-
-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.
diff --git a/vendor/github.com/dgryski/go-rendezvous/rdv.go b/vendor/github.com/dgryski/go-rendezvous/rdv.go
deleted file mode 100644
index 7a6f8203c67..00000000000
--- a/vendor/github.com/dgryski/go-rendezvous/rdv.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package rendezvous
-
-type Rendezvous struct {
- nodes map[string]int
- nstr []string
- nhash []uint64
- hash Hasher
-}
-
-type Hasher func(s string) uint64
-
-func New(nodes []string, hash Hasher) *Rendezvous {
- r := &Rendezvous{
- nodes: make(map[string]int, len(nodes)),
- nstr: make([]string, len(nodes)),
- nhash: make([]uint64, len(nodes)),
- hash: hash,
- }
-
- for i, n := range nodes {
- r.nodes[n] = i
- r.nstr[i] = n
- r.nhash[i] = hash(n)
- }
-
- return r
-}
-
-func (r *Rendezvous) Lookup(k string) string {
- // short-circuit if we're empty
- if len(r.nodes) == 0 {
- return ""
- }
-
- khash := r.hash(k)
-
- var midx int
- var mhash = xorshiftMult64(khash ^ r.nhash[0])
-
- for i, nhash := range r.nhash[1:] {
- if h := xorshiftMult64(khash ^ nhash); h > mhash {
- midx = i + 1
- mhash = h
- }
- }
-
- return r.nstr[midx]
-}
-
-func (r *Rendezvous) Add(node string) {
- r.nodes[node] = len(r.nstr)
- r.nstr = append(r.nstr, node)
- r.nhash = append(r.nhash, r.hash(node))
-}
-
-func (r *Rendezvous) Remove(node string) {
- // find index of node to remove
- nidx := r.nodes[node]
-
- // remove from the slices
- l := len(r.nstr)
- r.nstr[nidx] = r.nstr[l]
- r.nstr = r.nstr[:l]
-
- r.nhash[nidx] = r.nhash[l]
- r.nhash = r.nhash[:l]
-
- // update the map
- delete(r.nodes, node)
- moved := r.nstr[nidx]
- r.nodes[moved] = nidx
-}
-
-func xorshiftMult64(x uint64) uint64 {
- x ^= x >> 12 // a
- x ^= x << 25 // b
- x ^= x >> 27 // c
- return x * 2685821657736338717
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/.gitignore b/vendor/github.com/eclipse/paho.mqtt.golang/.gitignore
deleted file mode 100644
index 47bb0de48e9..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/.gitignore
+++ /dev/null
@@ -1,36 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-
-*.msg
-*.lok
-
-samples/trivial
-samples/trivial2
-samples/sample
-samples/reconnect
-samples/ssl
-samples/custom_store
-samples/simple
-samples/stdinpub
-samples/stdoutsub
-samples/routing
\ No newline at end of file
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/CONTRIBUTING.md b/vendor/github.com/eclipse/paho.mqtt.golang/CONTRIBUTING.md
deleted file mode 100644
index 9791dc60318..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/CONTRIBUTING.md
+++ /dev/null
@@ -1,56 +0,0 @@
-Contributing to Paho
-====================
-
-Thanks for your interest in this project.
-
-Project description:
---------------------
-
-The Paho project has been created to provide scalable open-source implementations of open and standard messaging protocols aimed at new, existing, and emerging applications for Machine-to-Machine (M2M) and Internet of Things (IoT).
-Paho reflects the inherent physical and cost constraints of device connectivity. Its objectives include effective levels of decoupling between devices and applications, designed to keep markets open and encourage the rapid growth of scalable Web and Enterprise middleware and applications. Paho is being kicked off with MQTT publish/subscribe client implementations for use on embedded platforms, along with corresponding server support as determined by the community.
-
-- https://projects.eclipse.org/projects/technology.paho
-
-Developer resources:
---------------------
-
-Information regarding source code management, builds, coding standards, and more.
-
-- https://projects.eclipse.org/projects/technology.paho/developer
-
-Contributor License Agreement:
-------------------------------
-
-Before your contribution can be accepted by the project, you need to create and electronically sign the Eclipse Foundation Contributor License Agreement (CLA).
-
-- http://www.eclipse.org/legal/CLA.php
-
-Contributing Code:
-------------------
-
-The Go client is developed in Github, see their documentation on the process of forking and pull requests; https://help.github.com/categories/collaborating-on-projects-using-pull-requests/
-
-Git commit messages should follow the style described here;
-
-http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
-
-Contact:
---------
-
-Contact the project developers via the project's "dev" list.
-
-- https://dev.eclipse.org/mailman/listinfo/paho-dev
-
-Search for bugs:
-----------------
-
-This project uses Github issues to track ongoing development and issues.
-
-- https://github.com/eclipse/paho.mqtt.golang/issues
-
-Create a new bug:
------------------
-
-Be sure to search for existing bugs before you create another one. Remember that contributions are always welcome!
-
-- https://github.com/eclipse/paho.mqtt.golang/issues
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/DISTRIBUTION b/vendor/github.com/eclipse/paho.mqtt.golang/DISTRIBUTION
deleted file mode 100644
index 34e49731daa..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/DISTRIBUTION
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-Eclipse Distribution License - v 1.0
-
-Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/LICENSE b/vendor/github.com/eclipse/paho.mqtt.golang/LICENSE
deleted file mode 100644
index aa7cc810fa1..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/LICENSE
+++ /dev/null
@@ -1,87 +0,0 @@
-Eclipse Public License - v 1.0
-
-THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
-
-1. DEFINITIONS
-
-"Contribution" means:
-
-a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
-
-b) in the case of each subsequent Contributor:
-
-i) changes to the Program, and
-
-ii) additions to the Program;
-
-where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
-
-"Contributor" means any person or entity that distributes the Program.
-
-"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
-
-"Program" means the Contributions distributed in accordance with this Agreement.
-
-"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
-
-2. GRANT OF RIGHTS
-
-a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
-
-b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
-
-c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
-
-d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
-
-3. REQUIREMENTS
-
-A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
-
-a) it complies with the terms and conditions of this Agreement; and
-
-b) its license agreement:
-
-i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
-
-ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
-
-iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
-
-iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
-
-When the Program is made available in source code form:
-
-a) it must be made available under this Agreement; and
-
-b) a copy of this Agreement must be included with each copy of the Program.
-
-Contributors may not remove or alter any copyright notices contained within the Program.
-
-Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
-
-4. COMMERCIAL DISTRIBUTION
-
-Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
-
-For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
-
-5. NO WARRANTY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
-
-6. DISCLAIMER OF LIABILITY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-7. GENERAL
-
-If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
-
-If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
-
-All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
-
-Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
-
-This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
\ No newline at end of file
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/README.md b/vendor/github.com/eclipse/paho.mqtt.golang/README.md
deleted file mode 100644
index 81c7148e093..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/README.md
+++ /dev/null
@@ -1,67 +0,0 @@
-
-[![GoDoc](https://godoc.org/github.com/eclipse/paho.mqtt.golang?status.svg)](https://godoc.org/github.com/eclipse/paho.mqtt.golang)
-[![Go Report Card](https://goreportcard.com/badge/github.com/eclipse/paho.mqtt.golang)](https://goreportcard.com/report/github.com/eclipse/paho.mqtt.golang)
-
-Eclipse Paho MQTT Go client
-===========================
-
-
-This repository contains the source code for the [Eclipse Paho](http://eclipse.org/paho) MQTT Go client library.
-
-This code builds a library which enable applications to connect to an [MQTT](http://mqtt.org) broker to publish messages, and to subscribe to topics and receive published messages.
-
-This library supports a fully asynchronous mode of operation.
-
-
-Installation and Build
-----------------------
-
-This client is designed to work with the standard Go tools, so installation is as easy as:
-
-```
-go get github.com/eclipse/paho.mqtt.golang
-```
-
-The client depends on Google's [websockets](https://godoc.org/golang.org/x/net/websocket) and [proxy](https://godoc.org/golang.org/x/net/proxy) package,
-also easily installed with the commands:
-
-```
-go get golang.org/x/net/websocket
-go get golang.org/x/net/proxy
-```
-
-
-Usage and API
--------------
-
-Detailed API documentation is available by using to godoc tool, or can be browsed online
-using the [godoc.org](http://godoc.org/github.com/eclipse/paho.mqtt.golang) service.
-
-Make use of the library by importing it in your Go client source code. For example,
-```
-import "github.com/eclipse/paho.mqtt.golang"
-```
-
-Samples are available in the `cmd` directory for reference.
-
-
-Runtime tracing
----------------
-
-Tracing is enabled by assigning logs (from the Go log package) to the logging endpoints, ERROR, CRITICAL, WARN and DEBUG
-
-
-Reporting bugs
---------------
-
-Please report bugs by raising issues for this project in github https://github.com/eclipse/paho.mqtt.golang/issues
-
-
-More information
-----------------
-
-Discussion of the Paho clients takes place on the [Eclipse paho-dev mailing list](https://dev.eclipse.org/mailman/listinfo/paho-dev).
-
-General questions about the MQTT protocol are discussed in the [MQTT Google Group](https://groups.google.com/forum/?hl=en-US&fromgroups#!forum/mqtt).
-
-There is much more information available via the [MQTT community site](http://mqtt.org).
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/about.html b/vendor/github.com/eclipse/paho.mqtt.golang/about.html
deleted file mode 100644
index b183f417abb..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/about.html
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-About
-
-
-About This Content
-
-December 9, 2013
-License
-
-The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
-indicated below, the Content is provided to you under the terms and conditions of the
-Eclipse Public License Version 1.0 ("EPL") and Eclipse Distribution License Version 1.0 ("EDL").
-A copy of the EPL is available at
-http://www.eclipse.org/legal/epl-v10.html
-and a copy of the EDL is available at
-http://www.eclipse.org/org/documents/edl-v10.php .
-For purposes of the EPL, "Program" will mean the Content.
-
-If you did not receive this Content directly from the Eclipse Foundation, the Content is
-being redistributed by another party ("Redistributor") and different terms and conditions may
-apply to your use of any object code in the Content. Check the Redistributor's license that was
-provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
-indicated below, the terms and conditions of the EPL still apply to any source code in the Content
-and such source code may be obtained at http://www.eclipse.org .
-
-
- Third Party Content
- The Content includes items that have been sourced from third parties as set out below. If you
- did not receive this Content directly from the Eclipse Foundation, the following is provided
- for informational purposes only, and you should look to the Redistributor's license for
- terms and conditions of use.
-
- None
-
-
-
-
-
-
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/client.go b/vendor/github.com/eclipse/paho.mqtt.golang/client.go
deleted file mode 100644
index 24d56c1f38b..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/client.go
+++ /dev/null
@@ -1,759 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-// Portions copyright © 2018 TIBCO Software Inc.
-
-// Package mqtt provides an MQTT v3.1.1 client library.
-package mqtt
-
-import (
- "errors"
- "fmt"
- "net"
- "strings"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/eclipse/paho.mqtt.golang/packets"
-)
-
-const (
- disconnected uint32 = iota
- connecting
- reconnecting
- connected
-)
-
-// Client is the interface definition for a Client as used by this
-// library, the interface is primarily to allow mocking tests.
-//
-// It is an MQTT v3.1.1 client for communicating
-// with an MQTT server using non-blocking methods that allow work
-// to be done in the background.
-// An application may connect to an MQTT server using:
-// A plain TCP socket
-// A secure SSL/TLS socket
-// A websocket
-// To enable ensured message delivery at Quality of Service (QoS) levels
-// described in the MQTT spec, a message persistence mechanism must be
-// used. This is done by providing a type which implements the Store
-// interface. For convenience, FileStore and MemoryStore are provided
-// implementations that should be sufficient for most use cases. More
-// information can be found in their respective documentation.
-// Numerous connection options may be specified by configuring a
-// and then supplying a ClientOptions type.
-type Client interface {
- // IsConnected returns a bool signifying whether
- // the client is connected or not.
- IsConnected() bool
- // IsConnectionOpen return a bool signifying wether the client has an active
- // connection to mqtt broker, i.e not in disconnected or reconnect mode
- IsConnectionOpen() bool
- // Connect will create a connection to the message broker, by default
- // it will attempt to connect at v3.1.1 and auto retry at v3.1 if that
- // fails
- Connect() Token
- // Disconnect will end the connection with the server, but not before waiting
- // the specified number of milliseconds to wait for existing work to be
- // completed.
- Disconnect(quiesce uint)
- // Publish will publish a message with the specified QoS and content
- // to the specified topic.
- // Returns a token to track delivery of the message to the broker
- Publish(topic string, qos byte, retained bool, payload interface{}) Token
- // Subscribe starts a new subscription. Provide a MessageHandler to be executed when
- // a message is published on the topic provided, or nil for the default handler
- Subscribe(topic string, qos byte, callback MessageHandler) Token
- // SubscribeMultiple starts a new subscription for multiple topics. Provide a MessageHandler to
- // be executed when a message is published on one of the topics provided, or nil for the
- // default handler
- SubscribeMultiple(filters map[string]byte, callback MessageHandler) Token
- // Unsubscribe will end the subscription from each of the topics provided.
- // Messages published to those topics from other clients will no longer be
- // received.
- Unsubscribe(topics ...string) Token
- // AddRoute allows you to add a handler for messages on a specific topic
- // without making a subscription. For example having a different handler
- // for parts of a wildcard subscription
- AddRoute(topic string, callback MessageHandler)
- // OptionsReader returns a ClientOptionsReader which is a copy of the clientoptions
- // in use by the client.
- OptionsReader() ClientOptionsReader
-}
-
-// client implements the Client interface
-type client struct {
- lastSent atomic.Value
- lastReceived atomic.Value
- pingOutstanding int32
- status uint32
- sync.RWMutex
- messageIds
- conn net.Conn
- ibound chan packets.ControlPacket
- obound chan *PacketAndToken
- oboundP chan *PacketAndToken
- msgRouter *router
- stopRouter chan bool
- incomingPubChan chan *packets.PublishPacket
- errors chan error
- stop chan struct{}
- persist Store
- options ClientOptions
- workers sync.WaitGroup
-}
-
-// NewClient will create an MQTT v3.1.1 client with all of the options specified
-// in the provided ClientOptions. The client must have the Connect method called
-// on it before it may be used. This is to make sure resources (such as a net
-// connection) are created before the application is actually ready.
-func NewClient(o *ClientOptions) Client {
- c := &client{}
- c.options = *o
-
- if c.options.Store == nil {
- c.options.Store = NewMemoryStore()
- }
- switch c.options.ProtocolVersion {
- case 3, 4:
- c.options.protocolVersionExplicit = true
- case 0x83, 0x84:
- c.options.protocolVersionExplicit = true
- default:
- c.options.ProtocolVersion = 4
- c.options.protocolVersionExplicit = false
- }
- c.persist = c.options.Store
- c.status = disconnected
- c.messageIds = messageIds{index: make(map[uint16]tokenCompletor)}
- c.msgRouter, c.stopRouter = newRouter()
- c.msgRouter.setDefaultHandler(c.options.DefaultPublishHandler)
- if !c.options.AutoReconnect {
- c.options.MessageChannelDepth = 0
- }
- return c
-}
-
-// AddRoute allows you to add a handler for messages on a specific topic
-// without making a subscription. For example having a different handler
-// for parts of a wildcard subscription
-func (c *client) AddRoute(topic string, callback MessageHandler) {
- if callback != nil {
- c.msgRouter.addRoute(topic, callback)
- }
-}
-
-// IsConnected returns a bool signifying whether
-// the client is connected or not.
-func (c *client) IsConnected() bool {
- c.RLock()
- defer c.RUnlock()
- status := atomic.LoadUint32(&c.status)
- switch {
- case status == connected:
- return true
- case c.options.AutoReconnect && status > connecting:
- return true
- default:
- return false
- }
-}
-
-// IsConnectionOpen return a bool signifying whether the client has an active
-// connection to mqtt broker, i.e not in disconnected or reconnect mode
-func (c *client) IsConnectionOpen() bool {
- c.RLock()
- defer c.RUnlock()
- status := atomic.LoadUint32(&c.status)
- switch {
- case status == connected:
- return true
- default:
- return false
- }
-}
-
-func (c *client) connectionStatus() uint32 {
- c.RLock()
- defer c.RUnlock()
- status := atomic.LoadUint32(&c.status)
- return status
-}
-
-func (c *client) setConnected(status uint32) {
- c.Lock()
- defer c.Unlock()
- atomic.StoreUint32(&c.status, uint32(status))
-}
-
-//ErrNotConnected is the error returned from function calls that are
-//made when the client is not connected to a broker
-var ErrNotConnected = errors.New("Not Connected")
-
-// Connect will create a connection to the message broker, by default
-// it will attempt to connect at v3.1.1 and auto retry at v3.1 if that
-// fails
-func (c *client) Connect() Token {
- var err error
- t := newToken(packets.Connect).(*ConnectToken)
- DEBUG.Println(CLI, "Connect()")
-
- c.obound = make(chan *PacketAndToken, c.options.MessageChannelDepth)
- c.oboundP = make(chan *PacketAndToken, c.options.MessageChannelDepth)
- c.ibound = make(chan packets.ControlPacket)
-
- go func() {
- c.persist.Open()
-
- c.setConnected(connecting)
- c.errors = make(chan error, 1)
- c.stop = make(chan struct{})
-
- var rc byte
- protocolVersion := c.options.ProtocolVersion
-
- if len(c.options.Servers) == 0 {
- t.setError(fmt.Errorf("No servers defined to connect to"))
- return
- }
-
- for _, broker := range c.options.Servers {
- cm := newConnectMsgFromOptions(&c.options, broker)
- c.options.ProtocolVersion = protocolVersion
- CONN:
- DEBUG.Println(CLI, "about to write new connect msg")
- c.conn, err = openConnection(broker, c.options.TLSConfig, c.options.ConnectTimeout, c.options.HTTPHeaders)
- if err == nil {
- DEBUG.Println(CLI, "socket connected to broker")
- switch c.options.ProtocolVersion {
- case 3:
- DEBUG.Println(CLI, "Using MQTT 3.1 protocol")
- cm.ProtocolName = "MQIsdp"
- cm.ProtocolVersion = 3
- case 0x83:
- DEBUG.Println(CLI, "Using MQTT 3.1b protocol")
- cm.ProtocolName = "MQIsdp"
- cm.ProtocolVersion = 0x83
- case 0x84:
- DEBUG.Println(CLI, "Using MQTT 3.1.1b protocol")
- cm.ProtocolName = "MQTT"
- cm.ProtocolVersion = 0x84
- default:
- DEBUG.Println(CLI, "Using MQTT 3.1.1 protocol")
- c.options.ProtocolVersion = 4
- cm.ProtocolName = "MQTT"
- cm.ProtocolVersion = 4
- }
- cm.Write(c.conn)
-
- rc, t.sessionPresent = c.connect()
- if rc != packets.Accepted {
- if c.conn != nil {
- c.conn.Close()
- c.conn = nil
- }
- //if the protocol version was explicitly set don't do any fallback
- if c.options.protocolVersionExplicit {
- ERROR.Println(CLI, "Connecting to", broker, "CONNACK was not CONN_ACCEPTED, but rather", packets.ConnackReturnCodes[rc])
- continue
- }
- if c.options.ProtocolVersion == 4 {
- DEBUG.Println(CLI, "Trying reconnect using MQTT 3.1 protocol")
- c.options.ProtocolVersion = 3
- goto CONN
- }
- }
- break
- } else {
- ERROR.Println(CLI, err.Error())
- WARN.Println(CLI, "failed to connect to broker, trying next")
- rc = packets.ErrNetworkError
- }
- }
-
- if c.conn == nil {
- ERROR.Println(CLI, "Failed to connect to a broker")
- c.setConnected(disconnected)
- c.persist.Close()
- t.returnCode = rc
- if rc != packets.ErrNetworkError {
- t.setError(packets.ConnErrors[rc])
- } else {
- t.setError(fmt.Errorf("%s : %s", packets.ConnErrors[rc], err))
- }
- return
- }
-
- c.options.protocolVersionExplicit = true
-
- if c.options.KeepAlive != 0 {
- atomic.StoreInt32(&c.pingOutstanding, 0)
- c.lastReceived.Store(time.Now())
- c.lastSent.Store(time.Now())
- c.workers.Add(1)
- go keepalive(c)
- }
-
- c.incomingPubChan = make(chan *packets.PublishPacket, c.options.MessageChannelDepth)
- c.msgRouter.matchAndDispatch(c.incomingPubChan, c.options.Order, c)
-
- c.setConnected(connected)
- DEBUG.Println(CLI, "client is connected")
- if c.options.OnConnect != nil {
- go c.options.OnConnect(c)
- }
-
- c.workers.Add(4)
- go errorWatch(c)
- go alllogic(c)
- go outgoing(c)
- go incoming(c)
-
- // Take care of any messages in the store
- if c.options.CleanSession == false {
- c.resume(c.options.ResumeSubs)
- } else {
- c.persist.Reset()
- }
-
- DEBUG.Println(CLI, "exit startClient")
- t.flowComplete()
- }()
- return t
-}
-
-// internal function used to reconnect the client when it loses its connection
-func (c *client) reconnect() {
- DEBUG.Println(CLI, "enter reconnect")
- var (
- err error
-
- rc = byte(1)
- sleep = time.Duration(1 * time.Second)
- )
-
- for rc != 0 && atomic.LoadUint32(&c.status) != disconnected {
- for _, broker := range c.options.Servers {
- cm := newConnectMsgFromOptions(&c.options, broker)
- DEBUG.Println(CLI, "about to write new connect msg")
- c.Lock()
- c.conn, err = openConnection(broker, c.options.TLSConfig, c.options.ConnectTimeout, c.options.HTTPHeaders)
- c.Unlock()
- if err == nil {
- DEBUG.Println(CLI, "socket connected to broker")
- switch c.options.ProtocolVersion {
- case 0x83:
- DEBUG.Println(CLI, "Using MQTT 3.1b protocol")
- cm.ProtocolName = "MQIsdp"
- cm.ProtocolVersion = 0x83
- case 0x84:
- DEBUG.Println(CLI, "Using MQTT 3.1.1b protocol")
- cm.ProtocolName = "MQTT"
- cm.ProtocolVersion = 0x84
- case 3:
- DEBUG.Println(CLI, "Using MQTT 3.1 protocol")
- cm.ProtocolName = "MQIsdp"
- cm.ProtocolVersion = 3
- default:
- DEBUG.Println(CLI, "Using MQTT 3.1.1 protocol")
- cm.ProtocolName = "MQTT"
- cm.ProtocolVersion = 4
- }
- cm.Write(c.conn)
-
- rc, _ = c.connect()
- if rc != packets.Accepted {
- c.conn.Close()
- c.conn = nil
- //if the protocol version was explicitly set don't do any fallback
- if c.options.protocolVersionExplicit {
- ERROR.Println(CLI, "Connecting to", broker, "CONNACK was not Accepted, but rather", packets.ConnackReturnCodes[rc])
- continue
- }
- }
- break
- } else {
- ERROR.Println(CLI, err.Error())
- WARN.Println(CLI, "failed to connect to broker, trying next")
- rc = packets.ErrNetworkError
- }
- }
- if rc != 0 {
- DEBUG.Println(CLI, "Reconnect failed, sleeping for", int(sleep.Seconds()), "seconds")
- time.Sleep(sleep)
- if sleep < c.options.MaxReconnectInterval {
- sleep *= 2
- }
-
- if sleep > c.options.MaxReconnectInterval {
- sleep = c.options.MaxReconnectInterval
- }
- }
- }
- // Disconnect() must have been called while we were trying to reconnect.
- if c.connectionStatus() == disconnected {
- DEBUG.Println(CLI, "Client moved to disconnected state while reconnecting, abandoning reconnect")
- return
- }
-
- c.stop = make(chan struct{})
-
- if c.options.KeepAlive != 0 {
- atomic.StoreInt32(&c.pingOutstanding, 0)
- c.lastReceived.Store(time.Now())
- c.lastSent.Store(time.Now())
- c.workers.Add(1)
- go keepalive(c)
- }
-
- c.setConnected(connected)
- DEBUG.Println(CLI, "client is reconnected")
- if c.options.OnConnect != nil {
- go c.options.OnConnect(c)
- }
-
- c.workers.Add(4)
- go errorWatch(c)
- go alllogic(c)
- go outgoing(c)
- go incoming(c)
-
- c.resume(false)
-}
-
-// This function is only used for receiving a connack
-// when the connection is first started.
-// This prevents receiving incoming data while resume
-// is in progress if clean session is false.
-func (c *client) connect() (byte, bool) {
- DEBUG.Println(NET, "connect started")
-
- ca, err := packets.ReadPacket(c.conn)
- if err != nil {
- ERROR.Println(NET, "connect got error", err)
- return packets.ErrNetworkError, false
- }
- if ca == nil {
- ERROR.Println(NET, "received nil packet")
- return packets.ErrNetworkError, false
- }
-
- msg, ok := ca.(*packets.ConnackPacket)
- if !ok {
- ERROR.Println(NET, "received msg that was not CONNACK")
- return packets.ErrNetworkError, false
- }
-
- DEBUG.Println(NET, "received connack")
- return msg.ReturnCode, msg.SessionPresent
-}
-
-// Disconnect will end the connection with the server, but not before waiting
-// the specified number of milliseconds to wait for existing work to be
-// completed.
-func (c *client) Disconnect(quiesce uint) {
- status := atomic.LoadUint32(&c.status)
- if status == connected {
- DEBUG.Println(CLI, "disconnecting")
- c.setConnected(disconnected)
-
- dm := packets.NewControlPacket(packets.Disconnect).(*packets.DisconnectPacket)
- dt := newToken(packets.Disconnect)
- c.oboundP <- &PacketAndToken{p: dm, t: dt}
-
- // wait for work to finish, or quiesce time consumed
- dt.WaitTimeout(time.Duration(quiesce) * time.Millisecond)
- } else {
- WARN.Println(CLI, "Disconnect() called but not connected (disconnected/reconnecting)")
- c.setConnected(disconnected)
- }
-
- c.disconnect()
-}
-
-// ForceDisconnect will end the connection with the mqtt broker immediately.
-func (c *client) forceDisconnect() {
- if !c.IsConnected() {
- WARN.Println(CLI, "already disconnected")
- return
- }
- c.setConnected(disconnected)
- c.conn.Close()
- DEBUG.Println(CLI, "forcefully disconnecting")
- c.disconnect()
-}
-
-func (c *client) internalConnLost(err error) {
- // Only do anything if this was called and we are still "connected"
- // forceDisconnect can cause incoming/outgoing/alllogic to end with
- // error from closing the socket but state will be "disconnected"
- if c.IsConnected() {
- c.closeStop()
- c.conn.Close()
- c.workers.Wait()
- if c.options.CleanSession && !c.options.AutoReconnect {
- c.messageIds.cleanUp()
- }
- if c.options.AutoReconnect {
- c.setConnected(reconnecting)
- go c.reconnect()
- } else {
- c.setConnected(disconnected)
- }
- if c.options.OnConnectionLost != nil {
- go c.options.OnConnectionLost(c, err)
- }
- }
-}
-
-func (c *client) closeStop() {
- c.Lock()
- defer c.Unlock()
- select {
- case <-c.stop:
- DEBUG.Println("In disconnect and stop channel is already closed")
- default:
- if c.stop != nil {
- close(c.stop)
- }
- }
-}
-
-func (c *client) closeStopRouter() {
- c.Lock()
- defer c.Unlock()
- select {
- case <-c.stopRouter:
- DEBUG.Println("In disconnect and stop channel is already closed")
- default:
- if c.stopRouter != nil {
- close(c.stopRouter)
- }
- }
-}
-
-func (c *client) closeConn() {
- c.Lock()
- defer c.Unlock()
- if c.conn != nil {
- c.conn.Close()
- }
-}
-
-func (c *client) disconnect() {
- c.closeStop()
- c.closeConn()
- c.workers.Wait()
- c.messageIds.cleanUp()
- c.closeStopRouter()
- DEBUG.Println(CLI, "disconnected")
- c.persist.Close()
-}
-
-// Publish will publish a message with the specified QoS and content
-// to the specified topic.
-// Returns a token to track delivery of the message to the broker
-func (c *client) Publish(topic string, qos byte, retained bool, payload interface{}) Token {
- token := newToken(packets.Publish).(*PublishToken)
- DEBUG.Println(CLI, "enter Publish")
- switch {
- case !c.IsConnected():
- token.setError(ErrNotConnected)
- return token
- case c.connectionStatus() == reconnecting && qos == 0:
- token.flowComplete()
- return token
- }
- pub := packets.NewControlPacket(packets.Publish).(*packets.PublishPacket)
- pub.Qos = qos
- pub.TopicName = topic
- pub.Retain = retained
- switch payload.(type) {
- case string:
- pub.Payload = []byte(payload.(string))
- case []byte:
- pub.Payload = payload.([]byte)
- default:
- token.setError(fmt.Errorf("Unknown payload type"))
- return token
- }
-
- if pub.Qos != 0 && pub.MessageID == 0 {
- pub.MessageID = c.getID(token)
- token.messageID = pub.MessageID
- }
- persistOutbound(c.persist, pub)
- if c.connectionStatus() == reconnecting {
- DEBUG.Println(CLI, "storing publish message (reconnecting), topic:", topic)
- } else {
- DEBUG.Println(CLI, "sending publish message, topic:", topic)
- c.obound <- &PacketAndToken{p: pub, t: token}
- }
- return token
-}
-
-// Subscribe starts a new subscription. Provide a MessageHandler to be executed when
-// a message is published on the topic provided.
-func (c *client) Subscribe(topic string, qos byte, callback MessageHandler) Token {
- token := newToken(packets.Subscribe).(*SubscribeToken)
- DEBUG.Println(CLI, "enter Subscribe")
- if !c.IsConnected() {
- token.setError(ErrNotConnected)
- return token
- }
- sub := packets.NewControlPacket(packets.Subscribe).(*packets.SubscribePacket)
- if err := validateTopicAndQos(topic, qos); err != nil {
- token.setError(err)
- return token
- }
- sub.Topics = append(sub.Topics, topic)
- sub.Qoss = append(sub.Qoss, qos)
- DEBUG.Println(CLI, sub.String())
-
- if strings.HasPrefix(topic, "$share") {
- topic = strings.Join(strings.Split(topic, "/")[2:], "/")
- }
-
- if callback != nil {
- c.msgRouter.addRoute(topic, callback)
- }
-
- token.subs = append(token.subs, topic)
- c.oboundP <- &PacketAndToken{p: sub, t: token}
- DEBUG.Println(CLI, "exit Subscribe")
- return token
-}
-
-// SubscribeMultiple starts a new subscription for multiple topics. Provide a MessageHandler to
-// be executed when a message is published on one of the topics provided.
-func (c *client) SubscribeMultiple(filters map[string]byte, callback MessageHandler) Token {
- var err error
- token := newToken(packets.Subscribe).(*SubscribeToken)
- DEBUG.Println(CLI, "enter SubscribeMultiple")
- if !c.IsConnected() {
- token.setError(ErrNotConnected)
- return token
- }
- sub := packets.NewControlPacket(packets.Subscribe).(*packets.SubscribePacket)
- if sub.Topics, sub.Qoss, err = validateSubscribeMap(filters); err != nil {
- token.setError(err)
- return token
- }
-
- if callback != nil {
- for topic := range filters {
- c.msgRouter.addRoute(topic, callback)
- }
- }
- token.subs = make([]string, len(sub.Topics))
- copy(token.subs, sub.Topics)
- c.oboundP <- &PacketAndToken{p: sub, t: token}
- DEBUG.Println(CLI, "exit SubscribeMultiple")
- return token
-}
-
-// Load all stored messages and resend them
-// Call this to ensure QOS > 1,2 even after an application crash
-func (c *client) resume(subscription bool) {
-
- storedKeys := c.persist.All()
- for _, key := range storedKeys {
- packet := c.persist.Get(key)
- if packet == nil {
- continue
- }
- details := packet.Details()
- if isKeyOutbound(key) {
- switch packet.(type) {
- case *packets.SubscribePacket:
- if subscription {
- DEBUG.Println(STR, fmt.Sprintf("loaded pending subscribe (%d)", details.MessageID))
- token := newToken(packets.Subscribe).(*SubscribeToken)
- c.oboundP <- &PacketAndToken{p: packet, t: token}
- }
- case *packets.UnsubscribePacket:
- if subscription {
- DEBUG.Println(STR, fmt.Sprintf("loaded pending unsubscribe (%d)", details.MessageID))
- token := newToken(packets.Unsubscribe).(*UnsubscribeToken)
- c.oboundP <- &PacketAndToken{p: packet, t: token}
- }
- case *packets.PubrelPacket:
- DEBUG.Println(STR, fmt.Sprintf("loaded pending pubrel (%d)", details.MessageID))
- select {
- case c.oboundP <- &PacketAndToken{p: packet, t: nil}:
- case <-c.stop:
- }
- case *packets.PublishPacket:
- token := newToken(packets.Publish).(*PublishToken)
- token.messageID = details.MessageID
- c.claimID(token, details.MessageID)
- DEBUG.Println(STR, fmt.Sprintf("loaded pending publish (%d)", details.MessageID))
- DEBUG.Println(STR, details)
- c.obound <- &PacketAndToken{p: packet, t: token}
- default:
- ERROR.Println(STR, "invalid message type in store (discarded)")
- c.persist.Del(key)
- }
- } else {
- switch packet.(type) {
- case *packets.PubrelPacket, *packets.PublishPacket:
- DEBUG.Println(STR, fmt.Sprintf("loaded pending incomming (%d)", details.MessageID))
- select {
- case c.ibound <- packet:
- case <-c.stop:
- }
- default:
- ERROR.Println(STR, "invalid message type in store (discarded)")
- c.persist.Del(key)
- }
- }
- }
-}
-
-// Unsubscribe will end the subscription from each of the topics provided.
-// Messages published to those topics from other clients will no longer be
-// received.
-func (c *client) Unsubscribe(topics ...string) Token {
- token := newToken(packets.Unsubscribe).(*UnsubscribeToken)
- DEBUG.Println(CLI, "enter Unsubscribe")
- if !c.IsConnected() {
- token.setError(ErrNotConnected)
- return token
- }
- unsub := packets.NewControlPacket(packets.Unsubscribe).(*packets.UnsubscribePacket)
- unsub.Topics = make([]string, len(topics))
- copy(unsub.Topics, topics)
-
- c.oboundP <- &PacketAndToken{p: unsub, t: token}
- for _, topic := range topics {
- c.msgRouter.deleteRoute(topic)
- }
-
- DEBUG.Println(CLI, "exit Unsubscribe")
- return token
-}
-
-// OptionsReader returns a ClientOptionsReader which is a copy of the clientoptions
-// in use by the client.
-func (c *client) OptionsReader() ClientOptionsReader {
- r := ClientOptionsReader{options: &c.options}
- return r
-}
-
-//DefaultConnectionLostHandler is a definition of a function that simply
-//reports to the DEBUG log the reason for the client losing a connection.
-func DefaultConnectionLostHandler(client Client, reason error) {
- DEBUG.Println("Connection lost:", reason.Error())
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/components.go b/vendor/github.com/eclipse/paho.mqtt.golang/components.go
deleted file mode 100644
index 01f5fafdf8f..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/components.go
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-type component string
-
-// Component names for debug output
-const (
- NET component = "[net] "
- PNG component = "[pinger] "
- CLI component = "[client] "
- DEC component = "[decode] "
- MES component = "[message] "
- STR component = "[store] "
- MID component = "[msgids] "
- TST component = "[test] "
- STA component = "[state] "
- ERR component = "[error] "
-)
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/edl-v10 b/vendor/github.com/eclipse/paho.mqtt.golang/edl-v10
deleted file mode 100644
index cf989f1456b..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/edl-v10
+++ /dev/null
@@ -1,15 +0,0 @@
-
-Eclipse Distribution License - v 1.0
-
-Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/epl-v10 b/vendor/github.com/eclipse/paho.mqtt.golang/epl-v10
deleted file mode 100644
index 79e486c3d2c..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/epl-v10
+++ /dev/null
@@ -1,70 +0,0 @@
-Eclipse Public License - v 1.0
-
-THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
-
-1. DEFINITIONS
-
-"Contribution" means:
-
-a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
-b) in the case of each subsequent Contributor:
-i) changes to the Program, and
-ii) additions to the Program;
-where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
-"Contributor" means any person or entity that distributes the Program.
-
-"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
-
-"Program" means the Contributions distributed in accordance with this Agreement.
-
-"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
-
-2. GRANT OF RIGHTS
-
-a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
-b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
-c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
-d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
-3. REQUIREMENTS
-
-A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
-
-a) it complies with the terms and conditions of this Agreement; and
-b) its license agreement:
-i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
-ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
-iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
-iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
-When the Program is made available in source code form:
-
-a) it must be made available under this Agreement; and
-b) a copy of this Agreement must be included with each copy of the Program.
-Contributors may not remove or alter any copyright notices contained within the Program.
-
-Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
-
-4. COMMERCIAL DISTRIBUTION
-
-Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
-
-For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
-
-5. NO WARRANTY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
-
-6. DISCLAIMER OF LIABILITY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-7. GENERAL
-
-If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
-
-If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
-
-All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
-
-Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
-
-This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/filestore.go b/vendor/github.com/eclipse/paho.mqtt.golang/filestore.go
deleted file mode 100644
index c4a0d36b534..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/filestore.go
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "io/ioutil"
- "os"
- "path"
- "sort"
- "sync"
-
- "github.com/eclipse/paho.mqtt.golang/packets"
-)
-
-const (
- msgExt = ".msg"
- tmpExt = ".tmp"
- corruptExt = ".CORRUPT"
-)
-
-// FileStore implements the store interface using the filesystem to provide
-// true persistence, even across client failure. This is designed to use a
-// single directory per running client. If you are running multiple clients
-// on the same filesystem, you will need to be careful to specify unique
-// store directories for each.
-type FileStore struct {
- sync.RWMutex
- directory string
- opened bool
-}
-
-// NewFileStore will create a new FileStore which stores its messages in the
-// directory provided.
-func NewFileStore(directory string) *FileStore {
- store := &FileStore{
- directory: directory,
- opened: false,
- }
- return store
-}
-
-// Open will allow the FileStore to be used.
-func (store *FileStore) Open() {
- store.Lock()
- defer store.Unlock()
- // if no store directory was specified in ClientOpts, by default use the
- // current working directory
- if store.directory == "" {
- store.directory, _ = os.Getwd()
- }
-
- // if store dir exists, great, otherwise, create it
- if !exists(store.directory) {
- perms := os.FileMode(0770)
- merr := os.MkdirAll(store.directory, perms)
- chkerr(merr)
- }
- store.opened = true
- DEBUG.Println(STR, "store is opened at", store.directory)
-}
-
-// Close will disallow the FileStore from being used.
-func (store *FileStore) Close() {
- store.Lock()
- defer store.Unlock()
- store.opened = false
- DEBUG.Println(STR, "store is closed")
-}
-
-// Put will put a message into the store, associated with the provided
-// key value.
-func (store *FileStore) Put(key string, m packets.ControlPacket) {
- store.Lock()
- defer store.Unlock()
- if !store.opened {
- ERROR.Println(STR, "Trying to use file store, but not open")
- return
- }
- full := fullpath(store.directory, key)
- write(store.directory, key, m)
- if !exists(full) {
- ERROR.Println(STR, "file not created:", full)
- }
-}
-
-// Get will retrieve a message from the store, the one associated with
-// the provided key value.
-func (store *FileStore) Get(key string) packets.ControlPacket {
- store.RLock()
- defer store.RUnlock()
- if !store.opened {
- ERROR.Println(STR, "Trying to use file store, but not open")
- return nil
- }
- filepath := fullpath(store.directory, key)
- if !exists(filepath) {
- return nil
- }
- mfile, oerr := os.Open(filepath)
- chkerr(oerr)
- msg, rerr := packets.ReadPacket(mfile)
- chkerr(mfile.Close())
-
- // Message was unreadable, return nil
- if rerr != nil {
- newpath := corruptpath(store.directory, key)
- WARN.Println(STR, "corrupted file detected:", rerr.Error(), "archived at:", newpath)
- os.Rename(filepath, newpath)
- return nil
- }
- return msg
-}
-
-// All will provide a list of all of the keys associated with messages
-// currenly residing in the FileStore.
-func (store *FileStore) All() []string {
- store.RLock()
- defer store.RUnlock()
- return store.all()
-}
-
-// Del will remove the persisted message associated with the provided
-// key from the FileStore.
-func (store *FileStore) Del(key string) {
- store.Lock()
- defer store.Unlock()
- store.del(key)
-}
-
-// Reset will remove all persisted messages from the FileStore.
-func (store *FileStore) Reset() {
- store.Lock()
- defer store.Unlock()
- WARN.Println(STR, "FileStore Reset")
- for _, key := range store.all() {
- store.del(key)
- }
-}
-
-// lockless
-func (store *FileStore) all() []string {
- var err error
- var keys []string
- var files fileInfos
-
- if !store.opened {
- ERROR.Println(STR, "Trying to use file store, but not open")
- return nil
- }
-
- files, err = ioutil.ReadDir(store.directory)
- chkerr(err)
- sort.Sort(files)
- for _, f := range files {
- DEBUG.Println(STR, "file in All():", f.Name())
- name := f.Name()
- if name[len(name)-4:len(name)] != msgExt {
- DEBUG.Println(STR, "skipping file, doesn't have right extension: ", name)
- continue
- }
- key := name[0 : len(name)-4] // remove file extension
- keys = append(keys, key)
- }
- return keys
-}
-
-// lockless
-func (store *FileStore) del(key string) {
- if !store.opened {
- ERROR.Println(STR, "Trying to use file store, but not open")
- return
- }
- DEBUG.Println(STR, "store del filepath:", store.directory)
- DEBUG.Println(STR, "store delete key:", key)
- filepath := fullpath(store.directory, key)
- DEBUG.Println(STR, "path of deletion:", filepath)
- if !exists(filepath) {
- WARN.Println(STR, "store could not delete key:", key)
- return
- }
- rerr := os.Remove(filepath)
- chkerr(rerr)
- DEBUG.Println(STR, "del msg:", key)
- if exists(filepath) {
- ERROR.Println(STR, "file not deleted:", filepath)
- }
-}
-
-func fullpath(store string, key string) string {
- p := path.Join(store, key+msgExt)
- return p
-}
-
-func tmppath(store string, key string) string {
- p := path.Join(store, key+tmpExt)
- return p
-}
-
-func corruptpath(store string, key string) string {
- p := path.Join(store, key+corruptExt)
- return p
-}
-
-// create file called "X.[messageid].tmp" located in the store
-// the contents of the file is the bytes of the message, then
-// rename it to "X.[messageid].msg", overwriting any existing
-// message with the same id
-// X will be 'i' for inbound messages, and O for outbound messages
-func write(store, key string, m packets.ControlPacket) {
- temppath := tmppath(store, key)
- f, err := os.Create(temppath)
- chkerr(err)
- werr := m.Write(f)
- chkerr(werr)
- cerr := f.Close()
- chkerr(cerr)
- rerr := os.Rename(temppath, fullpath(store, key))
- chkerr(rerr)
-}
-
-func exists(file string) bool {
- if _, err := os.Stat(file); err != nil {
- if os.IsNotExist(err) {
- return false
- }
- chkerr(err)
- }
- return true
-}
-
-type fileInfos []os.FileInfo
-
-func (f fileInfos) Len() int {
- return len(f)
-}
-
-func (f fileInfos) Swap(i, j int) {
- f[i], f[j] = f[j], f[i]
-}
-
-func (f fileInfos) Less(i, j int) bool {
- return f[i].ModTime().Before(f[j].ModTime())
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/memstore.go b/vendor/github.com/eclipse/paho.mqtt.golang/memstore.go
deleted file mode 100644
index 499c490bdbb..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/memstore.go
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "sync"
-
- "github.com/eclipse/paho.mqtt.golang/packets"
-)
-
-// MemoryStore implements the store interface to provide a "persistence"
-// mechanism wholly stored in memory. This is only useful for
-// as long as the client instance exists.
-type MemoryStore struct {
- sync.RWMutex
- messages map[string]packets.ControlPacket
- opened bool
-}
-
-// NewMemoryStore returns a pointer to a new instance of
-// MemoryStore, the instance is not initialized and ready to
-// use until Open() has been called on it.
-func NewMemoryStore() *MemoryStore {
- store := &MemoryStore{
- messages: make(map[string]packets.ControlPacket),
- opened: false,
- }
- return store
-}
-
-// Open initializes a MemoryStore instance.
-func (store *MemoryStore) Open() {
- store.Lock()
- defer store.Unlock()
- store.opened = true
- DEBUG.Println(STR, "memorystore initialized")
-}
-
-// Put takes a key and a pointer to a Message and stores the
-// message.
-func (store *MemoryStore) Put(key string, message packets.ControlPacket) {
- store.Lock()
- defer store.Unlock()
- if !store.opened {
- ERROR.Println(STR, "Trying to use memory store, but not open")
- return
- }
- store.messages[key] = message
-}
-
-// Get takes a key and looks in the store for a matching Message
-// returning either the Message pointer or nil.
-func (store *MemoryStore) Get(key string) packets.ControlPacket {
- store.RLock()
- defer store.RUnlock()
- if !store.opened {
- ERROR.Println(STR, "Trying to use memory store, but not open")
- return nil
- }
- mid := mIDFromKey(key)
- m := store.messages[key]
- if m == nil {
- CRITICAL.Println(STR, "memorystore get: message", mid, "not found")
- } else {
- DEBUG.Println(STR, "memorystore get: message", mid, "found")
- }
- return m
-}
-
-// All returns a slice of strings containing all the keys currently
-// in the MemoryStore.
-func (store *MemoryStore) All() []string {
- store.RLock()
- defer store.RUnlock()
- if !store.opened {
- ERROR.Println(STR, "Trying to use memory store, but not open")
- return nil
- }
- keys := []string{}
- for k := range store.messages {
- keys = append(keys, k)
- }
- return keys
-}
-
-// Del takes a key, searches the MemoryStore and if the key is found
-// deletes the Message pointer associated with it.
-func (store *MemoryStore) Del(key string) {
- store.Lock()
- defer store.Unlock()
- if !store.opened {
- ERROR.Println(STR, "Trying to use memory store, but not open")
- return
- }
- mid := mIDFromKey(key)
- m := store.messages[key]
- if m == nil {
- WARN.Println(STR, "memorystore del: message", mid, "not found")
- } else {
- delete(store.messages, key)
- DEBUG.Println(STR, "memorystore del: message", mid, "was deleted")
- }
-}
-
-// Close will disallow modifications to the state of the store.
-func (store *MemoryStore) Close() {
- store.Lock()
- defer store.Unlock()
- if !store.opened {
- ERROR.Println(STR, "Trying to close memory store, but not open")
- return
- }
- store.opened = false
- DEBUG.Println(STR, "memorystore closed")
-}
-
-// Reset eliminates all persisted message data in the store.
-func (store *MemoryStore) Reset() {
- store.Lock()
- defer store.Unlock()
- if !store.opened {
- ERROR.Println(STR, "Trying to reset memory store, but not open")
- }
- store.messages = make(map[string]packets.ControlPacket)
- WARN.Println(STR, "memorystore wiped")
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/message.go b/vendor/github.com/eclipse/paho.mqtt.golang/message.go
deleted file mode 100644
index 903e5dcf5e7..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/message.go
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "net/url"
-
- "github.com/eclipse/paho.mqtt.golang/packets"
- "sync"
-)
-
-// Message defines the externals that a message implementation must support
-// these are received messages that are passed to the callbacks, not internal
-// messages
-type Message interface {
- Duplicate() bool
- Qos() byte
- Retained() bool
- Topic() string
- MessageID() uint16
- Payload() []byte
- Ack()
-}
-
-type message struct {
- duplicate bool
- qos byte
- retained bool
- topic string
- messageID uint16
- payload []byte
- once sync.Once
- ack func()
-}
-
-func (m *message) Duplicate() bool {
- return m.duplicate
-}
-
-func (m *message) Qos() byte {
- return m.qos
-}
-
-func (m *message) Retained() bool {
- return m.retained
-}
-
-func (m *message) Topic() string {
- return m.topic
-}
-
-func (m *message) MessageID() uint16 {
- return m.messageID
-}
-
-func (m *message) Payload() []byte {
- return m.payload
-}
-
-func (m *message) Ack() {
- m.once.Do(m.ack)
-}
-
-func messageFromPublish(p *packets.PublishPacket, ack func()) Message {
- return &message{
- duplicate: p.Dup,
- qos: p.Qos,
- retained: p.Retain,
- topic: p.TopicName,
- messageID: p.MessageID,
- payload: p.Payload,
- ack: ack,
- }
-}
-
-func newConnectMsgFromOptions(options *ClientOptions, broker *url.URL) *packets.ConnectPacket {
- m := packets.NewControlPacket(packets.Connect).(*packets.ConnectPacket)
-
- m.CleanSession = options.CleanSession
- m.WillFlag = options.WillEnabled
- m.WillRetain = options.WillRetained
- m.ClientIdentifier = options.ClientID
-
- if options.WillEnabled {
- m.WillQos = options.WillQos
- m.WillTopic = options.WillTopic
- m.WillMessage = options.WillPayload
- }
-
- username := options.Username
- password := options.Password
- if broker.User != nil {
- username = broker.User.Username()
- if pwd, ok := broker.User.Password(); ok {
- password = pwd
- }
- }
- if options.CredentialsProvider != nil {
- username, password = options.CredentialsProvider()
- }
-
- if username != "" {
- m.UsernameFlag = true
- m.Username = username
- //mustn't have password without user as well
- if password != "" {
- m.PasswordFlag = true
- m.Password = []byte(password)
- }
- }
-
- m.Keepalive = uint16(options.KeepAlive)
-
- return m
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/messageids.go b/vendor/github.com/eclipse/paho.mqtt.golang/messageids.go
deleted file mode 100644
index 9a5fa9fd159..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/messageids.go
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "fmt"
- "sync"
- "time"
-)
-
-// MId is 16 bit message id as specified by the MQTT spec.
-// In general, these values should not be depended upon by
-// the client application.
-type MId uint16
-
-type messageIds struct {
- sync.RWMutex
- index map[uint16]tokenCompletor
-}
-
-const (
- midMin uint16 = 1
- midMax uint16 = 65535
-)
-
-func (mids *messageIds) cleanUp() {
- mids.Lock()
- for _, token := range mids.index {
- switch token.(type) {
- case *PublishToken:
- token.setError(fmt.Errorf("Connection lost before Publish completed"))
- case *SubscribeToken:
- token.setError(fmt.Errorf("Connection lost before Subscribe completed"))
- case *UnsubscribeToken:
- token.setError(fmt.Errorf("Connection lost before Unsubscribe completed"))
- case nil:
- continue
- }
- token.flowComplete()
- }
- mids.index = make(map[uint16]tokenCompletor)
- mids.Unlock()
- DEBUG.Println(MID, "cleaned up")
-}
-
-func (mids *messageIds) freeID(id uint16) {
- mids.Lock()
- delete(mids.index, id)
- mids.Unlock()
-}
-
-func (mids *messageIds) claimID(token tokenCompletor, id uint16) {
- mids.Lock()
- defer mids.Unlock()
- if _, ok := mids.index[id]; !ok {
- mids.index[id] = token
- } else {
- old := mids.index[id]
- old.flowComplete()
- mids.index[id] = token
- }
-}
-
-func (mids *messageIds) getID(t tokenCompletor) uint16 {
- mids.Lock()
- defer mids.Unlock()
- for i := midMin; i < midMax; i++ {
- if _, ok := mids.index[i]; !ok {
- mids.index[i] = t
- return i
- }
- }
- return 0
-}
-
-func (mids *messageIds) getToken(id uint16) tokenCompletor {
- mids.RLock()
- defer mids.RUnlock()
- if token, ok := mids.index[id]; ok {
- return token
- }
- return &DummyToken{id: id}
-}
-
-type DummyToken struct {
- id uint16
-}
-
-func (d *DummyToken) Wait() bool {
- return true
-}
-
-func (d *DummyToken) WaitTimeout(t time.Duration) bool {
- return true
-}
-
-func (d *DummyToken) flowComplete() {
- ERROR.Printf("A lookup for token %d returned nil\n", d.id)
-}
-
-func (d *DummyToken) Error() error {
- return nil
-}
-
-func (d *DummyToken) setError(e error) {}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/net.go b/vendor/github.com/eclipse/paho.mqtt.golang/net.go
deleted file mode 100644
index 3e6366be719..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/net.go
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "crypto/tls"
- "errors"
- "fmt"
- "net"
- "net/http"
- "net/url"
- "os"
- "reflect"
- "sync/atomic"
- "time"
-
- "github.com/eclipse/paho.mqtt.golang/packets"
- "golang.org/x/net/proxy"
- "golang.org/x/net/websocket"
-)
-
-func signalError(c chan<- error, err error) {
- select {
- case c <- err:
- default:
- }
-}
-
-func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration, headers http.Header) (net.Conn, error) {
- switch uri.Scheme {
- case "ws":
- config, _ := websocket.NewConfig(uri.String(), fmt.Sprintf("http://%s", uri.Host))
- config.Protocol = []string{"mqtt"}
- config.Header = headers
- config.Dialer = &net.Dialer{Timeout: timeout}
- conn, err := websocket.DialConfig(config)
- if err != nil {
- return nil, err
- }
- conn.PayloadType = websocket.BinaryFrame
- return conn, err
- case "wss":
- config, _ := websocket.NewConfig(uri.String(), fmt.Sprintf("https://%s", uri.Host))
- config.Protocol = []string{"mqtt"}
- config.TlsConfig = tlsc
- config.Header = headers
- config.Dialer = &net.Dialer{Timeout: timeout}
- conn, err := websocket.DialConfig(config)
- if err != nil {
- return nil, err
- }
- conn.PayloadType = websocket.BinaryFrame
- return conn, err
- case "tcp":
- allProxy := os.Getenv("all_proxy")
- if len(allProxy) == 0 {
- conn, err := net.DialTimeout("tcp", uri.Host, timeout)
- if err != nil {
- return nil, err
- }
- return conn, nil
- }
- proxyDialer := proxy.FromEnvironment()
-
- conn, err := proxyDialer.Dial("tcp", uri.Host)
- if err != nil {
- return nil, err
- }
- return conn, nil
- case "unix":
- conn, err := net.DialTimeout("unix", uri.Host, timeout)
- if err != nil {
- return nil, err
- }
- return conn, nil
- case "ssl":
- fallthrough
- case "tls":
- fallthrough
- case "tcps":
- allProxy := os.Getenv("all_proxy")
- if len(allProxy) == 0 {
- conn, err := tls.DialWithDialer(&net.Dialer{Timeout: timeout}, "tcp", uri.Host, tlsc)
- if err != nil {
- return nil, err
- }
- return conn, nil
- }
- proxyDialer := proxy.FromEnvironment()
-
- conn, err := proxyDialer.Dial("tcp", uri.Host)
- if err != nil {
- return nil, err
- }
-
- tlsConn := tls.Client(conn, tlsc)
-
- err = tlsConn.Handshake()
- if err != nil {
- conn.Close()
- return nil, err
- }
-
- return tlsConn, nil
- }
- return nil, errors.New("Unknown protocol")
-}
-
-// actually read incoming messages off the wire
-// send Message object into ibound channel
-func incoming(c *client) {
- var err error
- var cp packets.ControlPacket
-
- defer c.workers.Done()
-
- DEBUG.Println(NET, "incoming started")
-
- for {
- if cp, err = packets.ReadPacket(c.conn); err != nil {
- break
- }
- DEBUG.Println(NET, "Received Message")
- select {
- case c.ibound <- cp:
- // Notify keepalive logic that we recently received a packet
- if c.options.KeepAlive != 0 {
- c.lastReceived.Store(time.Now())
- }
- case <-c.stop:
- // This avoids a deadlock should a message arrive while shutting down.
- // In that case the "reader" of c.ibound might already be gone
- WARN.Println(NET, "incoming dropped a received message during shutdown")
- break
- }
- }
- // We received an error on read.
- // If disconnect is in progress, swallow error and return
- select {
- case <-c.stop:
- DEBUG.Println(NET, "incoming stopped")
- return
- // Not trying to disconnect, send the error to the errors channel
- default:
- ERROR.Println(NET, "incoming stopped with error", err)
- signalError(c.errors, err)
- return
- }
-}
-
-// receive a Message object on obound, and then
-// actually send outgoing message to the wire
-func outgoing(c *client) {
- defer c.workers.Done()
- DEBUG.Println(NET, "outgoing started")
-
- for {
- DEBUG.Println(NET, "outgoing waiting for an outbound message")
- select {
- case <-c.stop:
- DEBUG.Println(NET, "outgoing stopped")
- return
- case pub := <-c.obound:
- msg := pub.p.(*packets.PublishPacket)
-
- if c.options.WriteTimeout > 0 {
- c.conn.SetWriteDeadline(time.Now().Add(c.options.WriteTimeout))
- }
-
- if err := msg.Write(c.conn); err != nil {
- ERROR.Println(NET, "outgoing stopped with error", err)
- pub.t.setError(err)
- signalError(c.errors, err)
- return
- }
-
- if c.options.WriteTimeout > 0 {
- // If we successfully wrote, we don't want the timeout to happen during an idle period
- // so we reset it to infinite.
- c.conn.SetWriteDeadline(time.Time{})
- }
-
- if msg.Qos == 0 {
- pub.t.flowComplete()
- }
- DEBUG.Println(NET, "obound wrote msg, id:", msg.MessageID)
- case msg := <-c.oboundP:
- switch msg.p.(type) {
- case *packets.SubscribePacket:
- msg.p.(*packets.SubscribePacket).MessageID = c.getID(msg.t)
- case *packets.UnsubscribePacket:
- msg.p.(*packets.UnsubscribePacket).MessageID = c.getID(msg.t)
- }
- DEBUG.Println(NET, "obound priority msg to write, type", reflect.TypeOf(msg.p))
- if err := msg.p.Write(c.conn); err != nil {
- ERROR.Println(NET, "outgoing stopped with error", err)
- if msg.t != nil {
- msg.t.setError(err)
- }
- signalError(c.errors, err)
- return
- }
- switch msg.p.(type) {
- case *packets.DisconnectPacket:
- msg.t.(*DisconnectToken).flowComplete()
- DEBUG.Println(NET, "outbound wrote disconnect, stopping")
- return
- }
- }
- // Reset ping timer after sending control packet.
- if c.options.KeepAlive != 0 {
- c.lastSent.Store(time.Now())
- }
- }
-}
-
-// receive Message objects on ibound
-// store messages if necessary
-// send replies on obound
-// delete messages from store if necessary
-func alllogic(c *client) {
- defer c.workers.Done()
- DEBUG.Println(NET, "logic started")
-
- for {
- DEBUG.Println(NET, "logic waiting for msg on ibound")
-
- select {
- case msg := <-c.ibound:
- DEBUG.Println(NET, "logic got msg on ibound")
- persistInbound(c.persist, msg)
- switch m := msg.(type) {
- case *packets.PingrespPacket:
- DEBUG.Println(NET, "received pingresp")
- atomic.StoreInt32(&c.pingOutstanding, 0)
- case *packets.SubackPacket:
- DEBUG.Println(NET, "received suback, id:", m.MessageID)
- token := c.getToken(m.MessageID)
- switch t := token.(type) {
- case *SubscribeToken:
- DEBUG.Println(NET, "granted qoss", m.ReturnCodes)
- for i, qos := range m.ReturnCodes {
- t.subResult[t.subs[i]] = qos
- }
- }
- token.flowComplete()
- c.freeID(m.MessageID)
- case *packets.UnsubackPacket:
- DEBUG.Println(NET, "received unsuback, id:", m.MessageID)
- c.getToken(m.MessageID).flowComplete()
- c.freeID(m.MessageID)
- case *packets.PublishPacket:
- DEBUG.Println(NET, "received publish, msgId:", m.MessageID)
- DEBUG.Println(NET, "putting msg on onPubChan")
- switch m.Qos {
- case 2:
- c.incomingPubChan <- m
- DEBUG.Println(NET, "done putting msg on incomingPubChan")
- case 1:
- c.incomingPubChan <- m
- DEBUG.Println(NET, "done putting msg on incomingPubChan")
- case 0:
- select {
- case c.incomingPubChan <- m:
- case <-c.stop:
- }
- DEBUG.Println(NET, "done putting msg on incomingPubChan")
- }
- case *packets.PubackPacket:
- DEBUG.Println(NET, "received puback, id:", m.MessageID)
- // c.receipts.get(msg.MsgId()) <- Receipt{}
- // c.receipts.end(msg.MsgId())
- c.getToken(m.MessageID).flowComplete()
- c.freeID(m.MessageID)
- case *packets.PubrecPacket:
- DEBUG.Println(NET, "received pubrec, id:", m.MessageID)
- prel := packets.NewControlPacket(packets.Pubrel).(*packets.PubrelPacket)
- prel.MessageID = m.MessageID
- select {
- case c.oboundP <- &PacketAndToken{p: prel, t: nil}:
- case <-c.stop:
- }
- case *packets.PubrelPacket:
- DEBUG.Println(NET, "received pubrel, id:", m.MessageID)
- pc := packets.NewControlPacket(packets.Pubcomp).(*packets.PubcompPacket)
- pc.MessageID = m.MessageID
- persistOutbound(c.persist, pc)
- select {
- case c.oboundP <- &PacketAndToken{p: pc, t: nil}:
- case <-c.stop:
- }
- case *packets.PubcompPacket:
- DEBUG.Println(NET, "received pubcomp, id:", m.MessageID)
- c.getToken(m.MessageID).flowComplete()
- c.freeID(m.MessageID)
- }
- case <-c.stop:
- WARN.Println(NET, "logic stopped")
- return
- }
- }
-}
-
-func (c *client) ackFunc(packet *packets.PublishPacket) func() {
- return func() {
- switch packet.Qos {
- case 2:
- pr := packets.NewControlPacket(packets.Pubrec).(*packets.PubrecPacket)
- pr.MessageID = packet.MessageID
- DEBUG.Println(NET, "putting pubrec msg on obound")
- select {
- case c.oboundP <- &PacketAndToken{p: pr, t: nil}:
- case <-c.stop:
- }
- DEBUG.Println(NET, "done putting pubrec msg on obound")
- case 1:
- pa := packets.NewControlPacket(packets.Puback).(*packets.PubackPacket)
- pa.MessageID = packet.MessageID
- DEBUG.Println(NET, "putting puback msg on obound")
- persistOutbound(c.persist, pa)
- select {
- case c.oboundP <- &PacketAndToken{p: pa, t: nil}:
- case <-c.stop:
- }
- DEBUG.Println(NET, "done putting puback msg on obound")
- case 0:
- // do nothing, since there is no need to send an ack packet back
- }
- }
-}
-
-func errorWatch(c *client) {
- defer c.workers.Done()
- select {
- case <-c.stop:
- WARN.Println(NET, "errorWatch stopped")
- return
- case err := <-c.errors:
- ERROR.Println(NET, "error triggered, stopping")
- go c.internalConnLost(err)
- return
- }
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/notice.html b/vendor/github.com/eclipse/paho.mqtt.golang/notice.html
deleted file mode 100644
index f19c483b9c8..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/notice.html
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
-
-
-
-Eclipse Foundation Software User Agreement
-
-
-
-Eclipse Foundation Software User Agreement
-February 1, 2011
-
-Usage Of Content
-
-THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
- (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
- CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
- OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
- NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
- CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.
-
-Applicable Licenses
-
-Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
- ("EPL"). A copy of the EPL is provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html .
- For purposes of the EPL, "Program" will mean the Content.
-
-Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
- repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").
-
-
- Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").
- Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
- A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named "features". Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins
- and/or Fragments associated with that Feature.
- Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.
-
-
-The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and
-Included Features should be contained in files named "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module
-including, but not limited to the following locations:
-
-
- The top-level (root) directory
- Plug-in and Fragment directories
- Inside Plug-ins and Fragments packaged as JARs
- Sub-directories of the directory named "src" of certain Plug-ins
- Feature directories
-
-
-Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the
-installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
-inform you where you can locate them. Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature.
-Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
-that directory.
-
-THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
-OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):
-
-
-
-IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
-contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.
-
-
-Use of Provisioning Technology
-
-The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
- Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
- other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to
- install, extend and update Eclipse-based products. Information about packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html
- ("Specification").
-
-You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
- applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
- in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
- Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:
-
-
- A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology
- on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based
- product.
- During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
- accessed and copied to the Target Machine.
- Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
- Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target
- Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
- the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
- indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.
-
-
-Cryptography
-
-Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
- another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
- possession, or use, and re-export of encryption software, to see if this is permitted.
-
-Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.
-
-
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/oops.go b/vendor/github.com/eclipse/paho.mqtt.golang/oops.go
deleted file mode 100644
index 39630d7f28a..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/oops.go
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-func chkerr(e error) {
- if e != nil {
- panic(e)
- }
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/options.go b/vendor/github.com/eclipse/paho.mqtt.golang/options.go
deleted file mode 100644
index e96e9ed7c2b..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/options.go
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-// Portions copyright © 2018 TIBCO Software Inc.
-
-package mqtt
-
-import (
- "crypto/tls"
- "net/http"
- "net/url"
- "strings"
- "time"
-)
-
-// CredentialsProvider allows the username and password to be updated
-// before reconnecting. It should return the current username and password.
-type CredentialsProvider func() (username string, password string)
-
-// MessageHandler is a callback type which can be set to be
-// executed upon the arrival of messages published to topics
-// to which the client is subscribed.
-type MessageHandler func(Client, Message)
-
-// ConnectionLostHandler is a callback type which can be set to be
-// executed upon an unintended disconnection from the MQTT broker.
-// Disconnects caused by calling Disconnect or ForceDisconnect will
-// not cause an OnConnectionLost callback to execute.
-type ConnectionLostHandler func(Client, error)
-
-// OnConnectHandler is a callback that is called when the client
-// state changes from unconnected/disconnected to connected. Both
-// at initial connection and on reconnection
-type OnConnectHandler func(Client)
-
-// ClientOptions contains configurable options for an Client.
-type ClientOptions struct {
- Servers []*url.URL
- ClientID string
- Username string
- Password string
- CredentialsProvider CredentialsProvider
- CleanSession bool
- Order bool
- WillEnabled bool
- WillTopic string
- WillPayload []byte
- WillQos byte
- WillRetained bool
- ProtocolVersion uint
- protocolVersionExplicit bool
- TLSConfig *tls.Config
- KeepAlive int64
- PingTimeout time.Duration
- ConnectTimeout time.Duration
- MaxReconnectInterval time.Duration
- AutoReconnect bool
- Store Store
- DefaultPublishHandler MessageHandler
- OnConnect OnConnectHandler
- OnConnectionLost ConnectionLostHandler
- WriteTimeout time.Duration
- MessageChannelDepth uint
- ResumeSubs bool
- HTTPHeaders http.Header
-}
-
-// NewClientOptions will create a new ClientClientOptions type with some
-// default values.
-// Port: 1883
-// CleanSession: True
-// Order: True
-// KeepAlive: 30 (seconds)
-// ConnectTimeout: 30 (seconds)
-// MaxReconnectInterval 10 (minutes)
-// AutoReconnect: True
-func NewClientOptions() *ClientOptions {
- o := &ClientOptions{
- Servers: nil,
- ClientID: "",
- Username: "",
- Password: "",
- CleanSession: true,
- Order: true,
- WillEnabled: false,
- WillTopic: "",
- WillPayload: nil,
- WillQos: 0,
- WillRetained: false,
- ProtocolVersion: 0,
- protocolVersionExplicit: false,
- KeepAlive: 30,
- PingTimeout: 10 * time.Second,
- ConnectTimeout: 30 * time.Second,
- MaxReconnectInterval: 10 * time.Minute,
- AutoReconnect: true,
- Store: nil,
- OnConnect: nil,
- OnConnectionLost: DefaultConnectionLostHandler,
- WriteTimeout: 0, // 0 represents timeout disabled
- MessageChannelDepth: 100,
- ResumeSubs: false,
- HTTPHeaders: make(map[string][]string),
- }
- return o
-}
-
-// AddBroker adds a broker URI to the list of brokers to be used. The format should be
-// scheme://host:port
-// Where "scheme" is one of "tcp", "ssl", or "ws", "host" is the ip-address (or hostname)
-// and "port" is the port on which the broker is accepting connections.
-//
-// Default values for hostname is "127.0.0.1", for schema is "tcp://".
-//
-// An example broker URI would look like: tcp://foobar.com:1883
-func (o *ClientOptions) AddBroker(server string) *ClientOptions {
- if len(server) > 0 && server[0] == ':' {
- server = "127.0.0.1" + server
- }
- if !strings.Contains(server, "://") {
- server = "tcp://" + server
- }
- brokerURI, err := url.Parse(server)
- if err != nil {
- ERROR.Println(CLI, "Failed to parse %q broker address: %s", server, err)
- return o
- }
- o.Servers = append(o.Servers, brokerURI)
- return o
-}
-
-// SetResumeSubs will enable resuming of stored (un)subscribe messages when connecting
-// but not reconnecting if CleanSession is false. Otherwise these messages are discarded.
-func (o *ClientOptions) SetResumeSubs(resume bool) *ClientOptions {
- o.ResumeSubs = resume
- return o
-}
-
-// SetClientID will set the client id to be used by this client when
-// connecting to the MQTT broker. According to the MQTT v3.1 specification,
-// a client id mus be no longer than 23 characters.
-func (o *ClientOptions) SetClientID(id string) *ClientOptions {
- o.ClientID = id
- return o
-}
-
-// SetUsername will set the username to be used by this client when connecting
-// to the MQTT broker. Note: without the use of SSL/TLS, this information will
-// be sent in plaintext accross the wire.
-func (o *ClientOptions) SetUsername(u string) *ClientOptions {
- o.Username = u
- return o
-}
-
-// SetPassword will set the password to be used by this client when connecting
-// to the MQTT broker. Note: without the use of SSL/TLS, this information will
-// be sent in plaintext accross the wire.
-func (o *ClientOptions) SetPassword(p string) *ClientOptions {
- o.Password = p
- return o
-}
-
-// SetCredentialsProvider will set a method to be called by this client when
-// connecting to the MQTT broker that provide the current username and password.
-// Note: without the use of SSL/TLS, this information will be sent
-// in plaintext accross the wire.
-func (o *ClientOptions) SetCredentialsProvider(p CredentialsProvider) *ClientOptions {
- o.CredentialsProvider = p
- return o
-}
-
-// SetCleanSession will set the "clean session" flag in the connect message
-// when this client connects to an MQTT broker. By setting this flag, you are
-// indicating that no messages saved by the broker for this client should be
-// delivered. Any messages that were going to be sent by this client before
-// diconnecting previously but didn't will not be sent upon connecting to the
-// broker.
-func (o *ClientOptions) SetCleanSession(clean bool) *ClientOptions {
- o.CleanSession = clean
- return o
-}
-
-// SetOrderMatters will set the message routing to guarantee order within
-// each QoS level. By default, this value is true. If set to false,
-// this flag indicates that messages can be delivered asynchronously
-// from the client to the application and possibly arrive out of order.
-func (o *ClientOptions) SetOrderMatters(order bool) *ClientOptions {
- o.Order = order
- return o
-}
-
-// SetTLSConfig will set an SSL/TLS configuration to be used when connecting
-// to an MQTT broker. Please read the official Go documentation for more
-// information.
-func (o *ClientOptions) SetTLSConfig(t *tls.Config) *ClientOptions {
- o.TLSConfig = t
- return o
-}
-
-// SetStore will set the implementation of the Store interface
-// used to provide message persistence in cases where QoS levels
-// QoS_ONE or QoS_TWO are used. If no store is provided, then the
-// client will use MemoryStore by default.
-func (o *ClientOptions) SetStore(s Store) *ClientOptions {
- o.Store = s
- return o
-}
-
-// SetKeepAlive will set the amount of time (in seconds) that the client
-// should wait before sending a PING request to the broker. This will
-// allow the client to know that a connection has not been lost with the
-// server.
-func (o *ClientOptions) SetKeepAlive(k time.Duration) *ClientOptions {
- o.KeepAlive = int64(k / time.Second)
- return o
-}
-
-// SetPingTimeout will set the amount of time (in seconds) that the client
-// will wait after sending a PING request to the broker, before deciding
-// that the connection has been lost. Default is 10 seconds.
-func (o *ClientOptions) SetPingTimeout(k time.Duration) *ClientOptions {
- o.PingTimeout = k
- return o
-}
-
-// SetProtocolVersion sets the MQTT version to be used to connect to the
-// broker. Legitimate values are currently 3 - MQTT 3.1 or 4 - MQTT 3.1.1
-func (o *ClientOptions) SetProtocolVersion(pv uint) *ClientOptions {
- if (pv >= 3 && pv <= 4) || (pv > 0x80) {
- o.ProtocolVersion = pv
- o.protocolVersionExplicit = true
- }
- return o
-}
-
-// UnsetWill will cause any set will message to be disregarded.
-func (o *ClientOptions) UnsetWill() *ClientOptions {
- o.WillEnabled = false
- return o
-}
-
-// SetWill accepts a string will message to be set. When the client connects,
-// it will give this will message to the broker, which will then publish the
-// provided payload (the will) to any clients that are subscribed to the provided
-// topic.
-func (o *ClientOptions) SetWill(topic string, payload string, qos byte, retained bool) *ClientOptions {
- o.SetBinaryWill(topic, []byte(payload), qos, retained)
- return o
-}
-
-// SetBinaryWill accepts a []byte will message to be set. When the client connects,
-// it will give this will message to the broker, which will then publish the
-// provided payload (the will) to any clients that are subscribed to the provided
-// topic.
-func (o *ClientOptions) SetBinaryWill(topic string, payload []byte, qos byte, retained bool) *ClientOptions {
- o.WillEnabled = true
- o.WillTopic = topic
- o.WillPayload = payload
- o.WillQos = qos
- o.WillRetained = retained
- return o
-}
-
-// SetDefaultPublishHandler sets the MessageHandler that will be called when a message
-// is received that does not match any known subscriptions.
-func (o *ClientOptions) SetDefaultPublishHandler(defaultHandler MessageHandler) *ClientOptions {
- o.DefaultPublishHandler = defaultHandler
- return o
-}
-
-// SetOnConnectHandler sets the function to be called when the client is connected. Both
-// at initial connection time and upon automatic reconnect.
-func (o *ClientOptions) SetOnConnectHandler(onConn OnConnectHandler) *ClientOptions {
- o.OnConnect = onConn
- return o
-}
-
-// SetConnectionLostHandler will set the OnConnectionLost callback to be executed
-// in the case where the client unexpectedly loses connection with the MQTT broker.
-func (o *ClientOptions) SetConnectionLostHandler(onLost ConnectionLostHandler) *ClientOptions {
- o.OnConnectionLost = onLost
- return o
-}
-
-// SetWriteTimeout puts a limit on how long a mqtt publish should block until it unblocks with a
-// timeout error. A duration of 0 never times out. Default 30 seconds
-func (o *ClientOptions) SetWriteTimeout(t time.Duration) *ClientOptions {
- o.WriteTimeout = t
- return o
-}
-
-// SetConnectTimeout limits how long the client will wait when trying to open a connection
-// to an MQTT server before timeing out and erroring the attempt. A duration of 0 never times out.
-// Default 30 seconds. Currently only operational on TCP/TLS connections.
-func (o *ClientOptions) SetConnectTimeout(t time.Duration) *ClientOptions {
- o.ConnectTimeout = t
- return o
-}
-
-// SetMaxReconnectInterval sets the maximum time that will be waited between reconnection attempts
-// when connection is lost
-func (o *ClientOptions) SetMaxReconnectInterval(t time.Duration) *ClientOptions {
- o.MaxReconnectInterval = t
- return o
-}
-
-// SetAutoReconnect sets whether the automatic reconnection logic should be used
-// when the connection is lost, even if disabled the ConnectionLostHandler is still
-// called
-func (o *ClientOptions) SetAutoReconnect(a bool) *ClientOptions {
- o.AutoReconnect = a
- return o
-}
-
-// SetMessageChannelDepth sets the size of the internal queue that holds messages while the
-// client is temporairily offline, allowing the application to publish when the client is
-// reconnecting. This setting is only valid if AutoReconnect is set to true, it is otherwise
-// ignored.
-func (o *ClientOptions) SetMessageChannelDepth(s uint) *ClientOptions {
- o.MessageChannelDepth = s
- return o
-}
-
-// SetHTTPHeaders sets the additional HTTP headers that will be sent in the WebSocket
-// opening handshake.
-func (o *ClientOptions) SetHTTPHeaders(h http.Header) *ClientOptions {
- o.HTTPHeaders = h
- return o
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/options_reader.go b/vendor/github.com/eclipse/paho.mqtt.golang/options_reader.go
deleted file mode 100644
index 60144b93c86..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/options_reader.go
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "crypto/tls"
- "net/http"
- "net/url"
- "time"
-)
-
-// ClientOptionsReader provides an interface for reading ClientOptions after the client has been initialized.
-type ClientOptionsReader struct {
- options *ClientOptions
-}
-
-//Servers returns a slice of the servers defined in the clientoptions
-func (r *ClientOptionsReader) Servers() []*url.URL {
- s := make([]*url.URL, len(r.options.Servers))
-
- for i, u := range r.options.Servers {
- nu := *u
- s[i] = &nu
- }
-
- return s
-}
-
-//ResumeSubs returns true if resuming stored (un)sub is enabled
-func (r *ClientOptionsReader) ResumeSubs() bool {
- s := r.options.ResumeSubs
- return s
-}
-
-//ClientID returns the set client id
-func (r *ClientOptionsReader) ClientID() string {
- s := r.options.ClientID
- return s
-}
-
-//Username returns the set username
-func (r *ClientOptionsReader) Username() string {
- s := r.options.Username
- return s
-}
-
-//Password returns the set password
-func (r *ClientOptionsReader) Password() string {
- s := r.options.Password
- return s
-}
-
-//CleanSession returns whether Cleansession is set
-func (r *ClientOptionsReader) CleanSession() bool {
- s := r.options.CleanSession
- return s
-}
-
-func (r *ClientOptionsReader) Order() bool {
- s := r.options.Order
- return s
-}
-
-func (r *ClientOptionsReader) WillEnabled() bool {
- s := r.options.WillEnabled
- return s
-}
-
-func (r *ClientOptionsReader) WillTopic() string {
- s := r.options.WillTopic
- return s
-}
-
-func (r *ClientOptionsReader) WillPayload() []byte {
- s := r.options.WillPayload
- return s
-}
-
-func (r *ClientOptionsReader) WillQos() byte {
- s := r.options.WillQos
- return s
-}
-
-func (r *ClientOptionsReader) WillRetained() bool {
- s := r.options.WillRetained
- return s
-}
-
-func (r *ClientOptionsReader) ProtocolVersion() uint {
- s := r.options.ProtocolVersion
- return s
-}
-
-func (r *ClientOptionsReader) TLSConfig() *tls.Config {
- s := r.options.TLSConfig
- return s
-}
-
-func (r *ClientOptionsReader) KeepAlive() time.Duration {
- s := time.Duration(r.options.KeepAlive * int64(time.Second))
- return s
-}
-
-func (r *ClientOptionsReader) PingTimeout() time.Duration {
- s := r.options.PingTimeout
- return s
-}
-
-func (r *ClientOptionsReader) ConnectTimeout() time.Duration {
- s := r.options.ConnectTimeout
- return s
-}
-
-func (r *ClientOptionsReader) MaxReconnectInterval() time.Duration {
- s := r.options.MaxReconnectInterval
- return s
-}
-
-func (r *ClientOptionsReader) AutoReconnect() bool {
- s := r.options.AutoReconnect
- return s
-}
-
-func (r *ClientOptionsReader) WriteTimeout() time.Duration {
- s := r.options.WriteTimeout
- return s
-}
-
-func (r *ClientOptionsReader) MessageChannelDepth() uint {
- s := r.options.MessageChannelDepth
- return s
-}
-
-func (r *ClientOptionsReader) HTTPHeaders() http.Header {
- h := r.options.HTTPHeaders
- return h
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go
deleted file mode 100644
index 25cf30f63d6..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/connack.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package packets
-
-import (
- "bytes"
- "fmt"
- "io"
-)
-
-//ConnackPacket is an internal representation of the fields of the
-//Connack MQTT packet
-type ConnackPacket struct {
- FixedHeader
- SessionPresent bool
- ReturnCode byte
-}
-
-func (ca *ConnackPacket) String() string {
- str := fmt.Sprintf("%s", ca.FixedHeader)
- str += " "
- str += fmt.Sprintf("sessionpresent: %t returncode: %d", ca.SessionPresent, ca.ReturnCode)
- return str
-}
-
-func (ca *ConnackPacket) Write(w io.Writer) error {
- var body bytes.Buffer
- var err error
-
- body.WriteByte(boolToByte(ca.SessionPresent))
- body.WriteByte(ca.ReturnCode)
- ca.FixedHeader.RemainingLength = 2
- packet := ca.FixedHeader.pack()
- packet.Write(body.Bytes())
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (ca *ConnackPacket) Unpack(b io.Reader) error {
- flags, err := decodeByte(b)
- if err != nil {
- return err
- }
- ca.SessionPresent = 1&flags > 0
- ca.ReturnCode, err = decodeByte(b)
-
- return err
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (ca *ConnackPacket) Details() Details {
- return Details{Qos: 0, MessageID: 0}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go
deleted file mode 100644
index cb03ebc0730..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/connect.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package packets
-
-import (
- "bytes"
- "fmt"
- "io"
-)
-
-//ConnectPacket is an internal representation of the fields of the
-//Connect MQTT packet
-type ConnectPacket struct {
- FixedHeader
- ProtocolName string
- ProtocolVersion byte
- CleanSession bool
- WillFlag bool
- WillQos byte
- WillRetain bool
- UsernameFlag bool
- PasswordFlag bool
- ReservedBit byte
- Keepalive uint16
-
- ClientIdentifier string
- WillTopic string
- WillMessage []byte
- Username string
- Password []byte
-}
-
-func (c *ConnectPacket) String() string {
- str := fmt.Sprintf("%s", c.FixedHeader)
- str += " "
- str += fmt.Sprintf("protocolversion: %d protocolname: %s cleansession: %t willflag: %t WillQos: %d WillRetain: %t Usernameflag: %t Passwordflag: %t keepalive: %d clientId: %s willtopic: %s willmessage: %s Username: %s Password: %s", c.ProtocolVersion, c.ProtocolName, c.CleanSession, c.WillFlag, c.WillQos, c.WillRetain, c.UsernameFlag, c.PasswordFlag, c.Keepalive, c.ClientIdentifier, c.WillTopic, c.WillMessage, c.Username, c.Password)
- return str
-}
-
-func (c *ConnectPacket) Write(w io.Writer) error {
- var body bytes.Buffer
- var err error
-
- body.Write(encodeString(c.ProtocolName))
- body.WriteByte(c.ProtocolVersion)
- body.WriteByte(boolToByte(c.CleanSession)<<1 | boolToByte(c.WillFlag)<<2 | c.WillQos<<3 | boolToByte(c.WillRetain)<<5 | boolToByte(c.PasswordFlag)<<6 | boolToByte(c.UsernameFlag)<<7)
- body.Write(encodeUint16(c.Keepalive))
- body.Write(encodeString(c.ClientIdentifier))
- if c.WillFlag {
- body.Write(encodeString(c.WillTopic))
- body.Write(encodeBytes(c.WillMessage))
- }
- if c.UsernameFlag {
- body.Write(encodeString(c.Username))
- }
- if c.PasswordFlag {
- body.Write(encodeBytes(c.Password))
- }
- c.FixedHeader.RemainingLength = body.Len()
- packet := c.FixedHeader.pack()
- packet.Write(body.Bytes())
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (c *ConnectPacket) Unpack(b io.Reader) error {
- var err error
- c.ProtocolName, err = decodeString(b)
- if err != nil {
- return err
- }
- c.ProtocolVersion, err = decodeByte(b)
- if err != nil {
- return err
- }
- options, err := decodeByte(b)
- if err != nil {
- return err
- }
- c.ReservedBit = 1 & options
- c.CleanSession = 1&(options>>1) > 0
- c.WillFlag = 1&(options>>2) > 0
- c.WillQos = 3 & (options >> 3)
- c.WillRetain = 1&(options>>5) > 0
- c.PasswordFlag = 1&(options>>6) > 0
- c.UsernameFlag = 1&(options>>7) > 0
- c.Keepalive, err = decodeUint16(b)
- if err != nil {
- return err
- }
- c.ClientIdentifier, err = decodeString(b)
- if err != nil {
- return err
- }
- if c.WillFlag {
- c.WillTopic, err = decodeString(b)
- if err != nil {
- return err
- }
- c.WillMessage, err = decodeBytes(b)
- if err != nil {
- return err
- }
- }
- if c.UsernameFlag {
- c.Username, err = decodeString(b)
- if err != nil {
- return err
- }
- }
- if c.PasswordFlag {
- c.Password, err = decodeBytes(b)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
-//Validate performs validation of the fields of a Connect packet
-func (c *ConnectPacket) Validate() byte {
- if c.PasswordFlag && !c.UsernameFlag {
- return ErrRefusedBadUsernameOrPassword
- }
- if c.ReservedBit != 0 {
- //Bad reserved bit
- return ErrProtocolViolation
- }
- if (c.ProtocolName == "MQIsdp" && c.ProtocolVersion != 3) || (c.ProtocolName == "MQTT" && c.ProtocolVersion != 4) {
- //Mismatched or unsupported protocol version
- return ErrRefusedBadProtocolVersion
- }
- if c.ProtocolName != "MQIsdp" && c.ProtocolName != "MQTT" {
- //Bad protocol name
- return ErrProtocolViolation
- }
- if len(c.ClientIdentifier) > 65535 || len(c.Username) > 65535 || len(c.Password) > 65535 {
- //Bad size field
- return ErrProtocolViolation
- }
- if len(c.ClientIdentifier) == 0 && !c.CleanSession {
- //Bad client identifier
- return ErrRefusedIDRejected
- }
- return Accepted
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (c *ConnectPacket) Details() Details {
- return Details{Qos: 0, MessageID: 0}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go
deleted file mode 100644
index e5c1869207c..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/disconnect.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package packets
-
-import (
- "fmt"
- "io"
-)
-
-//DisconnectPacket is an internal representation of the fields of the
-//Disconnect MQTT packet
-type DisconnectPacket struct {
- FixedHeader
-}
-
-func (d *DisconnectPacket) String() string {
- str := fmt.Sprintf("%s", d.FixedHeader)
- return str
-}
-
-func (d *DisconnectPacket) Write(w io.Writer) error {
- packet := d.FixedHeader.pack()
- _, err := packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (d *DisconnectPacket) Unpack(b io.Reader) error {
- return nil
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (d *DisconnectPacket) Details() Details {
- return Details{Qos: 0, MessageID: 0}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go
deleted file mode 100644
index 42eeb46d39c..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/packets.go
+++ /dev/null
@@ -1,346 +0,0 @@
-package packets
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "io"
-)
-
-//ControlPacket defines the interface for structs intended to hold
-//decoded MQTT packets, either from being read or before being
-//written
-type ControlPacket interface {
- Write(io.Writer) error
- Unpack(io.Reader) error
- String() string
- Details() Details
-}
-
-//PacketNames maps the constants for each of the MQTT packet types
-//to a string representation of their name.
-var PacketNames = map[uint8]string{
- 1: "CONNECT",
- 2: "CONNACK",
- 3: "PUBLISH",
- 4: "PUBACK",
- 5: "PUBREC",
- 6: "PUBREL",
- 7: "PUBCOMP",
- 8: "SUBSCRIBE",
- 9: "SUBACK",
- 10: "UNSUBSCRIBE",
- 11: "UNSUBACK",
- 12: "PINGREQ",
- 13: "PINGRESP",
- 14: "DISCONNECT",
-}
-
-//Below are the constants assigned to each of the MQTT packet types
-const (
- 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
-)
-
-//Below are the const definitions for error codes returned by
-//Connect()
-const (
- Accepted = 0x00
- ErrRefusedBadProtocolVersion = 0x01
- ErrRefusedIDRejected = 0x02
- ErrRefusedServerUnavailable = 0x03
- ErrRefusedBadUsernameOrPassword = 0x04
- ErrRefusedNotAuthorised = 0x05
- ErrNetworkError = 0xFE
- ErrProtocolViolation = 0xFF
-)
-
-//ConnackReturnCodes is a map of the error codes constants for Connect()
-//to a string representation of the error
-var ConnackReturnCodes = map[uint8]string{
- 0: "Connection Accepted",
- 1: "Connection Refused: Bad Protocol Version",
- 2: "Connection Refused: Client Identifier Rejected",
- 3: "Connection Refused: Server Unavailable",
- 4: "Connection Refused: Username or Password in unknown format",
- 5: "Connection Refused: Not Authorised",
- 254: "Connection Error",
- 255: "Connection Refused: Protocol Violation",
-}
-
-//ConnErrors is a map of the errors codes constants for Connect()
-//to a Go error
-var ConnErrors = map[byte]error{
- Accepted: nil,
- ErrRefusedBadProtocolVersion: errors.New("Unnacceptable protocol version"),
- ErrRefusedIDRejected: errors.New("Identifier rejected"),
- ErrRefusedServerUnavailable: errors.New("Server Unavailable"),
- ErrRefusedBadUsernameOrPassword: errors.New("Bad user name or password"),
- ErrRefusedNotAuthorised: errors.New("Not Authorized"),
- ErrNetworkError: errors.New("Network Error"),
- ErrProtocolViolation: errors.New("Protocol Violation"),
-}
-
-//ReadPacket takes an instance of an io.Reader (such as net.Conn) and attempts
-//to read an MQTT packet from the stream. It returns a ControlPacket
-//representing the decoded MQTT packet and an error. One of these returns will
-//always be nil, a nil ControlPacket indicating an error occurred.
-func ReadPacket(r io.Reader) (ControlPacket, error) {
- var fh FixedHeader
- b := make([]byte, 1)
-
- _, err := io.ReadFull(r, b)
- if err != nil {
- return nil, err
- }
-
- err = fh.unpack(b[0], r)
- if err != nil {
- return nil, err
- }
-
- cp, err := NewControlPacketWithHeader(fh)
- if err != nil {
- return nil, err
- }
-
- packetBytes := make([]byte, fh.RemainingLength)
- n, err := io.ReadFull(r, packetBytes)
- if err != nil {
- return nil, err
- }
- if n != fh.RemainingLength {
- return nil, errors.New("Failed to read expected data")
- }
-
- err = cp.Unpack(bytes.NewBuffer(packetBytes))
- return cp, err
-}
-
-//NewControlPacket is used to create a new ControlPacket of the type specified
-//by packetType, this is usually done by reference to the packet type constants
-//defined in packets.go. The newly created ControlPacket is empty and a pointer
-//is returned.
-func NewControlPacket(packetType byte) ControlPacket {
- switch packetType {
- case Connect:
- return &ConnectPacket{FixedHeader: FixedHeader{MessageType: Connect}}
- case Connack:
- return &ConnackPacket{FixedHeader: FixedHeader{MessageType: Connack}}
- case Disconnect:
- return &DisconnectPacket{FixedHeader: FixedHeader{MessageType: Disconnect}}
- case Publish:
- return &PublishPacket{FixedHeader: FixedHeader{MessageType: Publish}}
- case Puback:
- return &PubackPacket{FixedHeader: FixedHeader{MessageType: Puback}}
- case Pubrec:
- return &PubrecPacket{FixedHeader: FixedHeader{MessageType: Pubrec}}
- case Pubrel:
- return &PubrelPacket{FixedHeader: FixedHeader{MessageType: Pubrel, Qos: 1}}
- case Pubcomp:
- return &PubcompPacket{FixedHeader: FixedHeader{MessageType: Pubcomp}}
- case Subscribe:
- return &SubscribePacket{FixedHeader: FixedHeader{MessageType: Subscribe, Qos: 1}}
- case Suback:
- return &SubackPacket{FixedHeader: FixedHeader{MessageType: Suback}}
- case Unsubscribe:
- return &UnsubscribePacket{FixedHeader: FixedHeader{MessageType: Unsubscribe, Qos: 1}}
- case Unsuback:
- return &UnsubackPacket{FixedHeader: FixedHeader{MessageType: Unsuback}}
- case Pingreq:
- return &PingreqPacket{FixedHeader: FixedHeader{MessageType: Pingreq}}
- case Pingresp:
- return &PingrespPacket{FixedHeader: FixedHeader{MessageType: Pingresp}}
- }
- return nil
-}
-
-//NewControlPacketWithHeader is used to create a new ControlPacket of the type
-//specified within the FixedHeader that is passed to the function.
-//The newly created ControlPacket is empty and a pointer is returned.
-func NewControlPacketWithHeader(fh FixedHeader) (ControlPacket, error) {
- switch fh.MessageType {
- case Connect:
- return &ConnectPacket{FixedHeader: fh}, nil
- case Connack:
- return &ConnackPacket{FixedHeader: fh}, nil
- case Disconnect:
- return &DisconnectPacket{FixedHeader: fh}, nil
- case Publish:
- return &PublishPacket{FixedHeader: fh}, nil
- case Puback:
- return &PubackPacket{FixedHeader: fh}, nil
- case Pubrec:
- return &PubrecPacket{FixedHeader: fh}, nil
- case Pubrel:
- return &PubrelPacket{FixedHeader: fh}, nil
- case Pubcomp:
- return &PubcompPacket{FixedHeader: fh}, nil
- case Subscribe:
- return &SubscribePacket{FixedHeader: fh}, nil
- case Suback:
- return &SubackPacket{FixedHeader: fh}, nil
- case Unsubscribe:
- return &UnsubscribePacket{FixedHeader: fh}, nil
- case Unsuback:
- return &UnsubackPacket{FixedHeader: fh}, nil
- case Pingreq:
- return &PingreqPacket{FixedHeader: fh}, nil
- case Pingresp:
- return &PingrespPacket{FixedHeader: fh}, nil
- }
- return nil, fmt.Errorf("unsupported packet type 0x%x", fh.MessageType)
-}
-
-//Details struct returned by the Details() function called on
-//ControlPackets to present details of the Qos and MessageID
-//of the ControlPacket
-type Details struct {
- Qos byte
- MessageID uint16
-}
-
-//FixedHeader is a struct to hold the decoded information from
-//the fixed header of an MQTT ControlPacket
-type FixedHeader struct {
- MessageType byte
- Dup bool
- Qos byte
- Retain bool
- RemainingLength int
-}
-
-func (fh FixedHeader) String() string {
- return fmt.Sprintf("%s: dup: %t qos: %d retain: %t rLength: %d", PacketNames[fh.MessageType], fh.Dup, fh.Qos, fh.Retain, fh.RemainingLength)
-}
-
-func boolToByte(b bool) byte {
- switch b {
- case true:
- return 1
- default:
- return 0
- }
-}
-
-func (fh *FixedHeader) pack() bytes.Buffer {
- var header bytes.Buffer
- header.WriteByte(fh.MessageType<<4 | boolToByte(fh.Dup)<<3 | fh.Qos<<1 | boolToByte(fh.Retain))
- header.Write(encodeLength(fh.RemainingLength))
- return header
-}
-
-func (fh *FixedHeader) unpack(typeAndFlags byte, r io.Reader) error {
- fh.MessageType = typeAndFlags >> 4
- fh.Dup = (typeAndFlags>>3)&0x01 > 0
- fh.Qos = (typeAndFlags >> 1) & 0x03
- fh.Retain = typeAndFlags&0x01 > 0
-
- var err error
- fh.RemainingLength, err = decodeLength(r)
- return err
-}
-
-func decodeByte(b io.Reader) (byte, error) {
- num := make([]byte, 1)
- _, err := b.Read(num)
- if err != nil {
- return 0, err
- }
-
- return num[0], nil
-}
-
-func decodeUint16(b io.Reader) (uint16, error) {
- num := make([]byte, 2)
- _, err := b.Read(num)
- if err != nil {
- return 0, err
- }
- return binary.BigEndian.Uint16(num), nil
-}
-
-func encodeUint16(num uint16) []byte {
- bytes := make([]byte, 2)
- binary.BigEndian.PutUint16(bytes, num)
- return bytes
-}
-
-func encodeString(field string) []byte {
- return encodeBytes([]byte(field))
-}
-
-func decodeString(b io.Reader) (string, error) {
- buf, err := decodeBytes(b)
- return string(buf), err
-}
-
-func decodeBytes(b io.Reader) ([]byte, error) {
- fieldLength, err := decodeUint16(b)
- if err != nil {
- return nil, err
- }
-
- field := make([]byte, fieldLength)
- _, err = b.Read(field)
- if err != nil {
- return nil, err
- }
-
- return field, nil
-}
-
-func encodeBytes(field []byte) []byte {
- fieldLength := make([]byte, 2)
- binary.BigEndian.PutUint16(fieldLength, uint16(len(field)))
- return append(fieldLength, field...)
-}
-
-func encodeLength(length int) []byte {
- var encLength []byte
- for {
- digit := byte(length % 128)
- length /= 128
- if length > 0 {
- digit |= 0x80
- }
- encLength = append(encLength, digit)
- if length == 0 {
- break
- }
- }
- return encLength
-}
-
-func decodeLength(r io.Reader) (int, error) {
- var rLength uint32
- var multiplier uint32
- b := make([]byte, 1)
- for multiplier < 27 { //fix: Infinite '(digit & 128) == 1' will cause the dead loop
- _, err := io.ReadFull(r, b)
- if err != nil {
- return 0, err
- }
-
- digit := b[0]
- rLength |= uint32(digit&127) << multiplier
- if (digit & 128) == 0 {
- break
- }
- multiplier += 7
- }
- return int(rLength), nil
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go
deleted file mode 100644
index 5c3e88f9408..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingreq.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package packets
-
-import (
- "fmt"
- "io"
-)
-
-//PingreqPacket is an internal representation of the fields of the
-//Pingreq MQTT packet
-type PingreqPacket struct {
- FixedHeader
-}
-
-func (pr *PingreqPacket) String() string {
- str := fmt.Sprintf("%s", pr.FixedHeader)
- return str
-}
-
-func (pr *PingreqPacket) Write(w io.Writer) error {
- packet := pr.FixedHeader.pack()
- _, err := packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pr *PingreqPacket) Unpack(b io.Reader) error {
- return nil
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pr *PingreqPacket) Details() Details {
- return Details{Qos: 0, MessageID: 0}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go
deleted file mode 100644
index 39ebc001e66..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pingresp.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package packets
-
-import (
- "fmt"
- "io"
-)
-
-//PingrespPacket is an internal representation of the fields of the
-//Pingresp MQTT packet
-type PingrespPacket struct {
- FixedHeader
-}
-
-func (pr *PingrespPacket) String() string {
- str := fmt.Sprintf("%s", pr.FixedHeader)
- return str
-}
-
-func (pr *PingrespPacket) Write(w io.Writer) error {
- packet := pr.FixedHeader.pack()
- _, err := packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pr *PingrespPacket) Unpack(b io.Reader) error {
- return nil
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pr *PingrespPacket) Details() Details {
- return Details{Qos: 0, MessageID: 0}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go
deleted file mode 100644
index 7c0cd7efdd1..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/puback.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package packets
-
-import (
- "fmt"
- "io"
-)
-
-//PubackPacket is an internal representation of the fields of the
-//Puback MQTT packet
-type PubackPacket struct {
- FixedHeader
- MessageID uint16
-}
-
-func (pa *PubackPacket) String() string {
- str := fmt.Sprintf("%s", pa.FixedHeader)
- str += " "
- str += fmt.Sprintf("MessageID: %d", pa.MessageID)
- return str
-}
-
-func (pa *PubackPacket) Write(w io.Writer) error {
- var err error
- pa.FixedHeader.RemainingLength = 2
- packet := pa.FixedHeader.pack()
- packet.Write(encodeUint16(pa.MessageID))
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pa *PubackPacket) Unpack(b io.Reader) error {
- var err error
- pa.MessageID, err = decodeUint16(b)
-
- return err
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pa *PubackPacket) Details() Details {
- return Details{Qos: pa.Qos, MessageID: pa.MessageID}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go
deleted file mode 100644
index 4f6f6e216e1..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubcomp.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package packets
-
-import (
- "fmt"
- "io"
-)
-
-//PubcompPacket is an internal representation of the fields of the
-//Pubcomp MQTT packet
-type PubcompPacket struct {
- FixedHeader
- MessageID uint16
-}
-
-func (pc *PubcompPacket) String() string {
- str := fmt.Sprintf("%s", pc.FixedHeader)
- str += " "
- str += fmt.Sprintf("MessageID: %d", pc.MessageID)
- return str
-}
-
-func (pc *PubcompPacket) Write(w io.Writer) error {
- var err error
- pc.FixedHeader.RemainingLength = 2
- packet := pc.FixedHeader.pack()
- packet.Write(encodeUint16(pc.MessageID))
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pc *PubcompPacket) Unpack(b io.Reader) error {
- var err error
- pc.MessageID, err = decodeUint16(b)
-
- return err
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pc *PubcompPacket) Details() Details {
- return Details{Qos: pc.Qos, MessageID: pc.MessageID}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go
deleted file mode 100644
index adc9adb9c0d..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/publish.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package packets
-
-import (
- "bytes"
- "fmt"
- "io"
-)
-
-//PublishPacket is an internal representation of the fields of the
-//Publish MQTT packet
-type PublishPacket struct {
- FixedHeader
- TopicName string
- MessageID uint16
- Payload []byte
-}
-
-func (p *PublishPacket) String() string {
- str := fmt.Sprintf("%s", p.FixedHeader)
- str += " "
- str += fmt.Sprintf("topicName: %s MessageID: %d", p.TopicName, p.MessageID)
- str += " "
- str += fmt.Sprintf("payload: %s", string(p.Payload))
- return str
-}
-
-func (p *PublishPacket) Write(w io.Writer) error {
- var body bytes.Buffer
- var err error
-
- body.Write(encodeString(p.TopicName))
- if p.Qos > 0 {
- body.Write(encodeUint16(p.MessageID))
- }
- p.FixedHeader.RemainingLength = body.Len() + len(p.Payload)
- packet := p.FixedHeader.pack()
- packet.Write(body.Bytes())
- packet.Write(p.Payload)
- _, err = w.Write(packet.Bytes())
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (p *PublishPacket) Unpack(b io.Reader) error {
- var payloadLength = p.FixedHeader.RemainingLength
- var err error
- p.TopicName, err = decodeString(b)
- if err != nil {
- return err
- }
-
- if p.Qos > 0 {
- p.MessageID, err = decodeUint16(b)
- if err != nil {
- return err
- }
- payloadLength -= len(p.TopicName) + 4
- } else {
- payloadLength -= len(p.TopicName) + 2
- }
- if payloadLength < 0 {
- return fmt.Errorf("Error unpacking publish, payload length < 0")
- }
- p.Payload = make([]byte, payloadLength)
- _, err = b.Read(p.Payload)
-
- return err
-}
-
-//Copy creates a new PublishPacket with the same topic and payload
-//but an empty fixed header, useful for when you want to deliver
-//a message with different properties such as Qos but the same
-//content
-func (p *PublishPacket) Copy() *PublishPacket {
- newP := NewControlPacket(Publish).(*PublishPacket)
- newP.TopicName = p.TopicName
- newP.Payload = p.Payload
-
- return newP
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (p *PublishPacket) Details() Details {
- return Details{Qos: p.Qos, MessageID: p.MessageID}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go
deleted file mode 100644
index 483372b0722..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrec.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package packets
-
-import (
- "fmt"
- "io"
-)
-
-//PubrecPacket is an internal representation of the fields of the
-//Pubrec MQTT packet
-type PubrecPacket struct {
- FixedHeader
- MessageID uint16
-}
-
-func (pr *PubrecPacket) String() string {
- str := fmt.Sprintf("%s", pr.FixedHeader)
- str += " "
- str += fmt.Sprintf("MessageID: %d", pr.MessageID)
- return str
-}
-
-func (pr *PubrecPacket) Write(w io.Writer) error {
- var err error
- pr.FixedHeader.RemainingLength = 2
- packet := pr.FixedHeader.pack()
- packet.Write(encodeUint16(pr.MessageID))
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pr *PubrecPacket) Unpack(b io.Reader) error {
- var err error
- pr.MessageID, err = decodeUint16(b)
-
- return err
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pr *PubrecPacket) Details() Details {
- return Details{Qos: pr.Qos, MessageID: pr.MessageID}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go
deleted file mode 100644
index 8590fd976ce..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/pubrel.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package packets
-
-import (
- "fmt"
- "io"
-)
-
-//PubrelPacket is an internal representation of the fields of the
-//Pubrel MQTT packet
-type PubrelPacket struct {
- FixedHeader
- MessageID uint16
-}
-
-func (pr *PubrelPacket) String() string {
- str := fmt.Sprintf("%s", pr.FixedHeader)
- str += " "
- str += fmt.Sprintf("MessageID: %d", pr.MessageID)
- return str
-}
-
-func (pr *PubrelPacket) Write(w io.Writer) error {
- var err error
- pr.FixedHeader.RemainingLength = 2
- packet := pr.FixedHeader.pack()
- packet.Write(encodeUint16(pr.MessageID))
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (pr *PubrelPacket) Unpack(b io.Reader) error {
- var err error
- pr.MessageID, err = decodeUint16(b)
-
- return err
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (pr *PubrelPacket) Details() Details {
- return Details{Qos: pr.Qos, MessageID: pr.MessageID}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go
deleted file mode 100644
index fc0572475ad..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/suback.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package packets
-
-import (
- "bytes"
- "fmt"
- "io"
-)
-
-//SubackPacket is an internal representation of the fields of the
-//Suback MQTT packet
-type SubackPacket struct {
- FixedHeader
- MessageID uint16
- ReturnCodes []byte
-}
-
-func (sa *SubackPacket) String() string {
- str := fmt.Sprintf("%s", sa.FixedHeader)
- str += " "
- str += fmt.Sprintf("MessageID: %d", sa.MessageID)
- return str
-}
-
-func (sa *SubackPacket) Write(w io.Writer) error {
- var body bytes.Buffer
- var err error
- body.Write(encodeUint16(sa.MessageID))
- body.Write(sa.ReturnCodes)
- sa.FixedHeader.RemainingLength = body.Len()
- packet := sa.FixedHeader.pack()
- packet.Write(body.Bytes())
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (sa *SubackPacket) Unpack(b io.Reader) error {
- var qosBuffer bytes.Buffer
- var err error
- sa.MessageID, err = decodeUint16(b)
- if err != nil {
- return err
- }
-
- _, err = qosBuffer.ReadFrom(b)
- if err != nil {
- return err
- }
- sa.ReturnCodes = qosBuffer.Bytes()
-
- return nil
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (sa *SubackPacket) Details() Details {
- return Details{Qos: 0, MessageID: sa.MessageID}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go
deleted file mode 100644
index 0787ce07c07..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/subscribe.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package packets
-
-import (
- "bytes"
- "fmt"
- "io"
-)
-
-//SubscribePacket is an internal representation of the fields of the
-//Subscribe MQTT packet
-type SubscribePacket struct {
- FixedHeader
- MessageID uint16
- Topics []string
- Qoss []byte
-}
-
-func (s *SubscribePacket) String() string {
- str := fmt.Sprintf("%s", s.FixedHeader)
- str += " "
- str += fmt.Sprintf("MessageID: %d topics: %s", s.MessageID, s.Topics)
- return str
-}
-
-func (s *SubscribePacket) Write(w io.Writer) error {
- var body bytes.Buffer
- var err error
-
- body.Write(encodeUint16(s.MessageID))
- for i, topic := range s.Topics {
- body.Write(encodeString(topic))
- body.WriteByte(s.Qoss[i])
- }
- s.FixedHeader.RemainingLength = body.Len()
- packet := s.FixedHeader.pack()
- packet.Write(body.Bytes())
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (s *SubscribePacket) Unpack(b io.Reader) error {
- var err error
- s.MessageID, err = decodeUint16(b)
- if err != nil {
- return err
- }
- payloadLength := s.FixedHeader.RemainingLength - 2
- for payloadLength > 0 {
- topic, err := decodeString(b)
- if err != nil {
- return err
- }
- s.Topics = append(s.Topics, topic)
- qos, err := decodeByte(b)
- if err != nil {
- return err
- }
- s.Qoss = append(s.Qoss, qos)
- payloadLength -= 2 + len(topic) + 1 //2 bytes of string length, plus string, plus 1 byte for Qos
- }
-
- return nil
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (s *SubscribePacket) Details() Details {
- return Details{Qos: 1, MessageID: s.MessageID}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go
deleted file mode 100644
index 4b40c273af0..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsuback.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package packets
-
-import (
- "fmt"
- "io"
-)
-
-//UnsubackPacket is an internal representation of the fields of the
-//Unsuback MQTT packet
-type UnsubackPacket struct {
- FixedHeader
- MessageID uint16
-}
-
-func (ua *UnsubackPacket) String() string {
- str := fmt.Sprintf("%s", ua.FixedHeader)
- str += " "
- str += fmt.Sprintf("MessageID: %d", ua.MessageID)
- return str
-}
-
-func (ua *UnsubackPacket) Write(w io.Writer) error {
- var err error
- ua.FixedHeader.RemainingLength = 2
- packet := ua.FixedHeader.pack()
- packet.Write(encodeUint16(ua.MessageID))
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (ua *UnsubackPacket) Unpack(b io.Reader) error {
- var err error
- ua.MessageID, err = decodeUint16(b)
-
- return err
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (ua *UnsubackPacket) Details() Details {
- return Details{Qos: 0, MessageID: ua.MessageID}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go b/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go
deleted file mode 100644
index 2012c310f83..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/packets/unsubscribe.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package packets
-
-import (
- "bytes"
- "fmt"
- "io"
-)
-
-//UnsubscribePacket is an internal representation of the fields of the
-//Unsubscribe MQTT packet
-type UnsubscribePacket struct {
- FixedHeader
- MessageID uint16
- Topics []string
-}
-
-func (u *UnsubscribePacket) String() string {
- str := fmt.Sprintf("%s", u.FixedHeader)
- str += " "
- str += fmt.Sprintf("MessageID: %d", u.MessageID)
- return str
-}
-
-func (u *UnsubscribePacket) Write(w io.Writer) error {
- var body bytes.Buffer
- var err error
- body.Write(encodeUint16(u.MessageID))
- for _, topic := range u.Topics {
- body.Write(encodeString(topic))
- }
- u.FixedHeader.RemainingLength = body.Len()
- packet := u.FixedHeader.pack()
- packet.Write(body.Bytes())
- _, err = packet.WriteTo(w)
-
- return err
-}
-
-//Unpack decodes the details of a ControlPacket after the fixed
-//header has been read
-func (u *UnsubscribePacket) Unpack(b io.Reader) error {
- var err error
- u.MessageID, err = decodeUint16(b)
- if err != nil {
- return err
- }
-
- for topic, err := decodeString(b); err == nil && topic != ""; topic, err = decodeString(b) {
- u.Topics = append(u.Topics, topic)
- }
-
- return err
-}
-
-//Details returns a Details struct containing the Qos and
-//MessageID of this ControlPacket
-func (u *UnsubscribePacket) Details() Details {
- return Details{Qos: 1, MessageID: u.MessageID}
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/ping.go b/vendor/github.com/eclipse/paho.mqtt.golang/ping.go
deleted file mode 100644
index dcbcb1dd226..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/ping.go
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "errors"
- "sync/atomic"
- "time"
-
- "github.com/eclipse/paho.mqtt.golang/packets"
-)
-
-func keepalive(c *client) {
- defer c.workers.Done()
- DEBUG.Println(PNG, "keepalive starting")
- var checkInterval int64
- var pingSent time.Time
-
- if c.options.KeepAlive > 10 {
- checkInterval = 5
- } else {
- checkInterval = c.options.KeepAlive / 2
- }
-
- intervalTicker := time.NewTicker(time.Duration(checkInterval * int64(time.Second)))
- defer intervalTicker.Stop()
-
- for {
- select {
- case <-c.stop:
- DEBUG.Println(PNG, "keepalive stopped")
- return
- case <-intervalTicker.C:
- lastSent := c.lastSent.Load().(time.Time)
- lastReceived := c.lastReceived.Load().(time.Time)
-
- DEBUG.Println(PNG, "ping check", time.Since(lastSent).Seconds())
- if time.Since(lastSent) >= time.Duration(c.options.KeepAlive*int64(time.Second)) || time.Since(lastReceived) >= time.Duration(c.options.KeepAlive*int64(time.Second)) {
- if atomic.LoadInt32(&c.pingOutstanding) == 0 {
- DEBUG.Println(PNG, "keepalive sending ping")
- ping := packets.NewControlPacket(packets.Pingreq).(*packets.PingreqPacket)
- //We don't want to wait behind large messages being sent, the Write call
- //will block until it it able to send the packet.
- atomic.StoreInt32(&c.pingOutstanding, 1)
- ping.Write(c.conn)
- c.lastSent.Store(time.Now())
- pingSent = time.Now()
- }
- }
- if atomic.LoadInt32(&c.pingOutstanding) > 0 && time.Now().Sub(pingSent) >= c.options.PingTimeout {
- CRITICAL.Println(PNG, "pingresp not received, disconnecting")
- c.errors <- errors.New("pingresp not received, disconnecting")
- return
- }
- }
- }
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/router.go b/vendor/github.com/eclipse/paho.mqtt.golang/router.go
deleted file mode 100644
index 7b4e8f8082f..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/router.go
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "container/list"
- "strings"
- "sync"
-
- "github.com/eclipse/paho.mqtt.golang/packets"
-)
-
-// route is a type which associates MQTT Topic strings with a
-// callback to be executed upon the arrival of a message associated
-// with a subscription to that topic.
-type route struct {
- topic string
- callback MessageHandler
-}
-
-// match takes a slice of strings which represent the route being tested having been split on '/'
-// separators, and a slice of strings representing the topic string in the published message, similarly
-// split.
-// The function determines if the topic string matches the route according to the MQTT topic rules
-// and returns a boolean of the outcome
-func match(route []string, topic []string) bool {
- if len(route) == 0 {
- if len(topic) == 0 {
- return true
- }
- return false
- }
-
- if len(topic) == 0 {
- if route[0] == "#" {
- return true
- }
- return false
- }
-
- if route[0] == "#" {
- return true
- }
-
- if (route[0] == "+") || (route[0] == topic[0]) {
- return match(route[1:], topic[1:])
- }
- return false
-}
-
-func routeIncludesTopic(route, topic string) bool {
- return match(routeSplit(route), strings.Split(topic, "/"))
-}
-
-// removes $share and sharename when splitting the route to allow
-// shared subscription routes to correctly match the topic
-func routeSplit(route string) []string {
- var result []string
- if strings.HasPrefix(route, "$share") {
- result = strings.Split(route, "/")[2:]
- } else {
- result = strings.Split(route, "/")
- }
- return result
-}
-
-// match takes the topic string of the published message and does a basic compare to the
-// string of the current Route, if they match it returns true
-func (r *route) match(topic string) bool {
- return r.topic == topic || routeIncludesTopic(r.topic, topic)
-}
-
-type router struct {
- sync.RWMutex
- routes *list.List
- defaultHandler MessageHandler
- messages chan *packets.PublishPacket
- stop chan bool
-}
-
-// newRouter returns a new instance of a Router and channel which can be used to tell the Router
-// to stop
-func newRouter() (*router, chan bool) {
- router := &router{routes: list.New(), messages: make(chan *packets.PublishPacket), stop: make(chan bool)}
- stop := router.stop
- return router, stop
-}
-
-// addRoute takes a topic string and MessageHandler callback. It looks in the current list of
-// routes to see if there is already a matching Route. If there is it replaces the current
-// callback with the new one. If not it add a new entry to the list of Routes.
-func (r *router) addRoute(topic string, callback MessageHandler) {
- r.Lock()
- defer r.Unlock()
- for e := r.routes.Front(); e != nil; e = e.Next() {
- if e.Value.(*route).match(topic) {
- r := e.Value.(*route)
- r.callback = callback
- return
- }
- }
- r.routes.PushBack(&route{topic: topic, callback: callback})
-}
-
-// deleteRoute takes a route string, looks for a matching Route in the list of Routes. If
-// found it removes the Route from the list.
-func (r *router) deleteRoute(topic string) {
- r.Lock()
- defer r.Unlock()
- for e := r.routes.Front(); e != nil; e = e.Next() {
- if e.Value.(*route).match(topic) {
- r.routes.Remove(e)
- return
- }
- }
-}
-
-// setDefaultHandler assigns a default callback that will be called if no matching Route
-// is found for an incoming Publish.
-func (r *router) setDefaultHandler(handler MessageHandler) {
- r.Lock()
- defer r.Unlock()
- r.defaultHandler = handler
-}
-
-// matchAndDispatch takes a channel of Message pointers as input and starts a go routine that
-// takes messages off the channel, matches them against the internal route list and calls the
-// associated callback (or the defaultHandler, if one exists and no other route matched). If
-// anything is sent down the stop channel the function will end.
-func (r *router) matchAndDispatch(messages <-chan *packets.PublishPacket, order bool, client *client) {
- go func() {
- for {
- select {
- case message := <-messages:
- sent := false
- r.RLock()
- m := messageFromPublish(message, client.ackFunc(message))
- handlers := []MessageHandler{}
- for e := r.routes.Front(); e != nil; e = e.Next() {
- if e.Value.(*route).match(message.TopicName) {
- if order {
- handlers = append(handlers, e.Value.(*route).callback)
- } else {
- hd := e.Value.(*route).callback
- go func() {
- hd(client, m)
- m.Ack()
- }()
- }
- sent = true
- }
- }
- if !sent && r.defaultHandler != nil {
- if order {
- handlers = append(handlers, r.defaultHandler)
- } else {
- go func() {
- r.defaultHandler(client, m)
- m.Ack()
- }()
- }
- }
- r.RUnlock()
- for _, handler := range handlers {
- func() {
- handler(client, m)
- m.Ack()
- }()
- }
- case <-r.stop:
- return
- }
- }
- }()
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/store.go b/vendor/github.com/eclipse/paho.mqtt.golang/store.go
deleted file mode 100644
index 24a76b7df3c..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/store.go
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "fmt"
- "strconv"
-
- "github.com/eclipse/paho.mqtt.golang/packets"
-)
-
-const (
- inboundPrefix = "i."
- outboundPrefix = "o."
-)
-
-// Store is an interface which can be used to provide implementations
-// for message persistence.
-// Because we may have to store distinct messages with the same
-// message ID, we need a unique key for each message. This is
-// possible by prepending "i." or "o." to each message id
-type Store interface {
- Open()
- Put(key string, message packets.ControlPacket)
- Get(key string) packets.ControlPacket
- All() []string
- Del(key string)
- Close()
- Reset()
-}
-
-// A key MUST have the form "X.[messageid]"
-// where X is 'i' or 'o'
-func mIDFromKey(key string) uint16 {
- s := key[2:]
- i, err := strconv.Atoi(s)
- chkerr(err)
- return uint16(i)
-}
-
-// Return true if key prefix is outbound
-func isKeyOutbound(key string) bool {
- return key[:2] == outboundPrefix
-}
-
-// Return true if key prefix is inbound
-func isKeyInbound(key string) bool {
- return key[:2] == inboundPrefix
-}
-
-// Return a string of the form "i.[id]"
-func inboundKeyFromMID(id uint16) string {
- return fmt.Sprintf("%s%d", inboundPrefix, id)
-}
-
-// Return a string of the form "o.[id]"
-func outboundKeyFromMID(id uint16) string {
- return fmt.Sprintf("%s%d", outboundPrefix, id)
-}
-
-// govern which outgoing messages are persisted
-func persistOutbound(s Store, m packets.ControlPacket) {
- switch m.Details().Qos {
- case 0:
- switch m.(type) {
- case *packets.PubackPacket, *packets.PubcompPacket:
- // Sending puback. delete matching publish
- // from ibound
- s.Del(inboundKeyFromMID(m.Details().MessageID))
- }
- case 1:
- switch m.(type) {
- case *packets.PublishPacket, *packets.PubrelPacket, *packets.SubscribePacket, *packets.UnsubscribePacket:
- // Sending publish. store in obound
- // until puback received
- s.Put(outboundKeyFromMID(m.Details().MessageID), m)
- default:
- ERROR.Println(STR, "Asked to persist an invalid message type")
- }
- case 2:
- switch m.(type) {
- case *packets.PublishPacket:
- // Sending publish. store in obound
- // until pubrel received
- s.Put(outboundKeyFromMID(m.Details().MessageID), m)
- default:
- ERROR.Println(STR, "Asked to persist an invalid message type")
- }
- }
-}
-
-// govern which incoming messages are persisted
-func persistInbound(s Store, m packets.ControlPacket) {
- switch m.Details().Qos {
- case 0:
- switch m.(type) {
- case *packets.PubackPacket, *packets.SubackPacket, *packets.UnsubackPacket, *packets.PubcompPacket:
- // Received a puback. delete matching publish
- // from obound
- s.Del(outboundKeyFromMID(m.Details().MessageID))
- case *packets.PublishPacket, *packets.PubrecPacket, *packets.PingrespPacket, *packets.ConnackPacket:
- default:
- ERROR.Println(STR, "Asked to persist an invalid messages type")
- }
- case 1:
- switch m.(type) {
- case *packets.PublishPacket, *packets.PubrelPacket:
- // Received a publish. store it in ibound
- // until puback sent
- s.Put(inboundKeyFromMID(m.Details().MessageID), m)
- default:
- ERROR.Println(STR, "Asked to persist an invalid messages type")
- }
- case 2:
- switch m.(type) {
- case *packets.PublishPacket:
- // Received a publish. store it in ibound
- // until pubrel received
- s.Put(inboundKeyFromMID(m.Details().MessageID), m)
- default:
- ERROR.Println(STR, "Asked to persist an invalid messages type")
- }
- }
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/token.go b/vendor/github.com/eclipse/paho.mqtt.golang/token.go
deleted file mode 100644
index 0818553332f..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/token.go
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Allan Stockdill-Mander
- */
-
-package mqtt
-
-import (
- "sync"
- "time"
-
- "github.com/eclipse/paho.mqtt.golang/packets"
-)
-
-// PacketAndToken is a struct that contains both a ControlPacket and a
-// Token. This struct is passed via channels between the client interface
-// code and the underlying code responsible for sending and receiving
-// MQTT messages.
-type PacketAndToken struct {
- p packets.ControlPacket
- t tokenCompletor
-}
-
-// Token defines the interface for the tokens used to indicate when
-// actions have completed.
-type Token interface {
- Wait() bool
- WaitTimeout(time.Duration) bool
- Error() error
-}
-
-type TokenErrorSetter interface {
- setError(error)
-}
-
-type tokenCompletor interface {
- Token
- TokenErrorSetter
- flowComplete()
-}
-
-type baseToken struct {
- m sync.RWMutex
- complete chan struct{}
- err error
-}
-
-// Wait will wait indefinitely for the Token to complete, ie the Publish
-// to be sent and confirmed receipt from the broker
-func (b *baseToken) Wait() bool {
- <-b.complete
- return true
-}
-
-// WaitTimeout takes a time.Duration to wait for the flow associated with the
-// Token to complete, returns true if it returned before the timeout or
-// returns false if the timeout occurred. In the case of a timeout the Token
-// does not have an error set in case the caller wishes to wait again
-func (b *baseToken) WaitTimeout(d time.Duration) bool {
- b.m.Lock()
- defer b.m.Unlock()
-
- timer := time.NewTimer(d)
- select {
- case <-b.complete:
- if !timer.Stop() {
- <-timer.C
- }
- return true
- case <-timer.C:
- }
-
- return false
-}
-
-func (b *baseToken) flowComplete() {
- select {
- case <-b.complete:
- default:
- close(b.complete)
- }
-}
-
-func (b *baseToken) Error() error {
- b.m.RLock()
- defer b.m.RUnlock()
- return b.err
-}
-
-func (b *baseToken) setError(e error) {
- b.m.Lock()
- b.err = e
- b.flowComplete()
- b.m.Unlock()
-}
-
-func newToken(tType byte) tokenCompletor {
- switch tType {
- case packets.Connect:
- return &ConnectToken{baseToken: baseToken{complete: make(chan struct{})}}
- case packets.Subscribe:
- return &SubscribeToken{baseToken: baseToken{complete: make(chan struct{})}, subResult: make(map[string]byte)}
- case packets.Publish:
- return &PublishToken{baseToken: baseToken{complete: make(chan struct{})}}
- case packets.Unsubscribe:
- return &UnsubscribeToken{baseToken: baseToken{complete: make(chan struct{})}}
- case packets.Disconnect:
- return &DisconnectToken{baseToken: baseToken{complete: make(chan struct{})}}
- }
- return nil
-}
-
-// ConnectToken is an extension of Token containing the extra fields
-// required to provide information about calls to Connect()
-type ConnectToken struct {
- baseToken
- returnCode byte
- sessionPresent bool
-}
-
-// ReturnCode returns the acknowlegement code in the connack sent
-// in response to a Connect()
-func (c *ConnectToken) ReturnCode() byte {
- c.m.RLock()
- defer c.m.RUnlock()
- return c.returnCode
-}
-
-// SessionPresent returns a bool representing the value of the
-// session present field in the connack sent in response to a Connect()
-func (c *ConnectToken) SessionPresent() bool {
- c.m.RLock()
- defer c.m.RUnlock()
- return c.sessionPresent
-}
-
-// PublishToken is an extension of Token containing the extra fields
-// required to provide information about calls to Publish()
-type PublishToken struct {
- baseToken
- messageID uint16
-}
-
-// MessageID returns the MQTT message ID that was assigned to the
-// Publish packet when it was sent to the broker
-func (p *PublishToken) MessageID() uint16 {
- return p.messageID
-}
-
-// SubscribeToken is an extension of Token containing the extra fields
-// required to provide information about calls to Subscribe()
-type SubscribeToken struct {
- baseToken
- subs []string
- subResult map[string]byte
-}
-
-// Result returns a map of topics that were subscribed to along with
-// the matching return code from the broker. This is either the Qos
-// value of the subscription or an error code.
-func (s *SubscribeToken) Result() map[string]byte {
- s.m.RLock()
- defer s.m.RUnlock()
- return s.subResult
-}
-
-// UnsubscribeToken is an extension of Token containing the extra fields
-// required to provide information about calls to Unsubscribe()
-type UnsubscribeToken struct {
- baseToken
-}
-
-// DisconnectToken is an extension of Token containing the extra fields
-// required to provide information about calls to Disconnect()
-type DisconnectToken struct {
- baseToken
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/topic.go b/vendor/github.com/eclipse/paho.mqtt.golang/topic.go
deleted file mode 100644
index 6fa3ad2ac5f..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/topic.go
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2014 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-import (
- "errors"
- "strings"
-)
-
-//ErrInvalidQos is the error returned when an packet is to be sent
-//with an invalid Qos value
-var ErrInvalidQos = errors.New("Invalid QoS")
-
-//ErrInvalidTopicEmptyString is the error returned when a topic string
-//is passed in that is 0 length
-var ErrInvalidTopicEmptyString = errors.New("Invalid Topic; empty string")
-
-//ErrInvalidTopicMultilevel is the error returned when a topic string
-//is passed in that has the multi level wildcard in any position but
-//the last
-var ErrInvalidTopicMultilevel = errors.New("Invalid Topic; multi-level wildcard must be last level")
-
-// Topic Names and Topic Filters
-// The MQTT v3.1.1 spec clarifies a number of ambiguities with regard
-// to the validity of Topic strings.
-// - A Topic must be between 1 and 65535 bytes.
-// - A Topic is case sensitive.
-// - A Topic may contain whitespace.
-// - A Topic containing a leading forward slash is different than a Topic without.
-// - A Topic may be "/" (two levels, both empty string).
-// - A Topic must be UTF-8 encoded.
-// - A Topic may contain any number of levels.
-// - A Topic may contain an empty level (two forward slashes in a row).
-// - A TopicName may not contain a wildcard.
-// - A TopicFilter may only have a # (multi-level) wildcard as the last level.
-// - A TopicFilter may contain any number of + (single-level) wildcards.
-// - A TopicFilter with a # will match the absense of a level
-// Example: a subscription to "foo/#" will match messages published to "foo".
-
-func validateSubscribeMap(subs map[string]byte) ([]string, []byte, error) {
- var topics []string
- var qoss []byte
- for topic, qos := range subs {
- if err := validateTopicAndQos(topic, qos); err != nil {
- return nil, nil, err
- }
- topics = append(topics, topic)
- qoss = append(qoss, qos)
- }
-
- return topics, qoss, nil
-}
-
-func validateTopicAndQos(topic string, qos byte) error {
- if len(topic) == 0 {
- return ErrInvalidTopicEmptyString
- }
-
- levels := strings.Split(topic, "/")
- for i, level := range levels {
- if level == "#" && i != len(levels)-1 {
- return ErrInvalidTopicMultilevel
- }
- }
-
- if qos < 0 || qos > 2 {
- return ErrInvalidQos
- }
- return nil
-}
diff --git a/vendor/github.com/eclipse/paho.mqtt.golang/trace.go b/vendor/github.com/eclipse/paho.mqtt.golang/trace.go
deleted file mode 100644
index 195c8173dcf..00000000000
--- a/vendor/github.com/eclipse/paho.mqtt.golang/trace.go
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2013 IBM Corp.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Seth Hoenig
- * Allan Stockdill-Mander
- * Mike Robertson
- */
-
-package mqtt
-
-type (
- // Logger interface allows implementations to provide to this package any
- // object that implements the methods defined in it.
- Logger interface {
- Println(v ...interface{})
- Printf(format string, v ...interface{})
- }
-
- // NOOPLogger implements the logger that does not perform any operation
- // by default. This allows us to efficiently discard the unwanted messages.
- NOOPLogger struct{}
-)
-
-func (NOOPLogger) Println(v ...interface{}) {}
-func (NOOPLogger) Printf(format string, v ...interface{}) {}
-
-// Internal levels of library output that are initialised to not print
-// anything but can be overridden by programmer
-var (
- ERROR Logger = NOOPLogger{}
- CRITICAL Logger = NOOPLogger{}
- WARN Logger = NOOPLogger{}
- DEBUG Logger = NOOPLogger{}
-)
diff --git a/vendor/github.com/evalphobia/logrus_sentry/.travis.yml b/vendor/github.com/evalphobia/logrus_sentry/.travis.yml
deleted file mode 100644
index 33edbc4c30f..00000000000
--- a/vendor/github.com/evalphobia/logrus_sentry/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-sudo: false
-language: go
-go:
- - 1.10.x
- - 1.x
- - tip
-matrix:
- allow_failures:
- - go: tip
-before_install:
- - go get github.com/axw/gocov/gocov
- - go get github.com/mattn/goveralls
- - go get golang.org/x/tools/cmd/cover
- - test -z "$(gofmt -s -l . | tee /dev/stderr)"
- - go tool vet -all -structtags -shadow .
-script:
- - $HOME/gopath/bin/goveralls -service=travis-ci
diff --git a/vendor/github.com/evalphobia/logrus_sentry/LICENSE b/vendor/github.com/evalphobia/logrus_sentry/LICENSE
deleted file mode 100644
index a2301f534a2..00000000000
--- a/vendor/github.com/evalphobia/logrus_sentry/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 logrus_sentry Authors
-
-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.
diff --git a/vendor/github.com/evalphobia/logrus_sentry/README.md b/vendor/github.com/evalphobia/logrus_sentry/README.md
deleted file mode 100644
index 9a65baafa65..00000000000
--- a/vendor/github.com/evalphobia/logrus_sentry/README.md
+++ /dev/null
@@ -1,163 +0,0 @@
-Sentry Hook for Logrus
-----
-
-[![GoDoc][1]][2] [![Release][5]][6] [![Build Status][7]][8] [![Coverage Status][9]][10] [![Go Report Card][13]][14] [![Code Climate][19]][20] [![BCH compliance][21]][22]
-
-[1]: https://godoc.org/github.com/evalphobia/logrus_sentry?status.svg
-[2]: https://godoc.org/github.com/evalphobia/logrus_sentry
-[4]: LICENSE.md
-[5]: https://img.shields.io/github/release/evalphobia/logrus_sentry.svg
-[6]: https://github.com/evalphobia/logrus_sentry/releases/latest
-[7]: https://travis-ci.org/evalphobia/logrus_sentry.svg?branch=master
-[8]: https://travis-ci.org/evalphobia/logrus_sentry
-[9]: https://coveralls.io/repos/evalphobia/logrus_sentry/badge.svg?branch=master&service=github
-[10]: https://coveralls.io/github/evalphobia/logrus_sentry?branch=master
-[11]: https://codecov.io/github/evalphobia/logrus_sentry/coverage.svg?branch=master
-[12]: https://codecov.io/github/evalphobia/logrus_sentry?branch=master
-[13]: https://goreportcard.com/badge/github.com/evalphobia/logrus_sentry
-[14]: https://goreportcard.com/report/github.com/evalphobia/logrus_sentry
-[15]: https://img.shields.io/github/downloads/evalphobia/logrus_sentry/total.svg?maxAge=1800
-[16]: https://github.com/evalphobia/logrus_sentry/releases
-[17]: https://img.shields.io/github/stars/evalphobia/logrus_sentry.svg
-[18]: https://github.com/evalphobia/logrus_sentry/stargazers
-[19]: https://codeclimate.com/github/evalphobia/logrus_sentry/badges/gpa.svg
-[20]: https://codeclimate.com/github/evalphobia/logrus_sentry
-[21]: https://bettercodehub.com/edge/badge/evalphobia/logrus_sentry?branch=master
-[22]: https://bettercodehub.com/
-
-
-[Sentry](https://getsentry.com) provides both self-hosted and hosted
-solutions for exception tracking.
-Both client and server are
-[open source](https://github.com/getsentry/sentry).
-
-## Usage
-
-Every sentry application defined on the server gets a different
-[DSN](https://www.getsentry.com/docs/). In the example below replace
-`YOUR_DSN` with the one created for your application.
-
-```go
-import (
- "github.com/sirupsen/logrus"
- "github.com/evalphobia/logrus_sentry"
-)
-
-func main() {
- log := logrus.New()
- hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{
- logrus.PanicLevel,
- logrus.FatalLevel,
- logrus.ErrorLevel,
- })
-
- if err == nil {
- log.Hooks.Add(hook)
- }
-}
-```
-
-If you wish to initialize a SentryHook with tags, you can use the `NewWithTagsSentryHook` constructor to provide default tags:
-
-```go
-tags := map[string]string{
- "site": "example.com",
-}
-levels := []logrus.Level{
- logrus.PanicLevel,
- logrus.FatalLevel,
- logrus.ErrorLevel,
-}
-hook, err := logrus_sentry.NewWithTagsSentryHook(YOUR_DSN, tags, levels)
-
-```
-
-If you wish to initialize a SentryHook with an already initialized raven client, you can use
-the `NewWithClientSentryHook` constructor:
-
-```go
-import (
- "github.com/sirupsen/logrus"
- "github.com/evalphobia/logrus_sentry"
- "github.com/getsentry/raven-go"
-)
-
-func main() {
- log := logrus.New()
-
- client, err := raven.New(YOUR_DSN)
- if err != nil {
- log.Fatal(err)
- }
-
- hook, err := logrus_sentry.NewWithClientSentryHook(client, []logrus.Level{
- logrus.PanicLevel,
- logrus.FatalLevel,
- logrus.ErrorLevel,
- })
-
- if err == nil {
- log.Hooks.Add(hook)
- }
-}
-
-hook, err := NewWithClientSentryHook(client, []logrus.Level{
- logrus.ErrorLevel,
-})
-```
-
-## Special fields
-
-Some logrus fields have a special meaning in this hook, and they will be especially processed by Sentry.
-
-
-| Field key | Description |
-| ------------- | ------------- |
-| `event_id` | Each logged event is identified by the `event_id`, which is hexadecimal string representing a UUID4 value. You can manually specify the identifier of a log event by supplying this field. The `event_id` string should be in one of the following UUID format: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` and `urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`)|
-| `user_name` | Name of the user who is in the context of the event |
-| `user_email` | Email of the user who is in the context of the event |
-| `user_id` | ID of the user who is in the context of the event |
-| `user_ip` | IP of the user who is in the context of the event |
-| `server_name` | Also known as hostname, it is the name of the server which is logging the event (hostname.example.com) |
-| `tags` | `tags` are `raven.Tags` struct from `github.com/getsentry/raven-go` and override default tags data |
-| `fingerprint` | `fingerprint` is an string array, that allows you to affect sentry's grouping of events as detailed in the [sentry documentation](https://docs.sentry.io/learn/rollups/#customize-grouping-with-fingerprints) |
-| `logger` | `logger` is the part of the application which is logging the event. In go this usually means setting it to the name of the package. |
-| `http_request` | `http_request` is the in-coming request(*http.Request). The detailed request data are sent to Sentry. |
-
-## Timeout
-
-`Timeout` is the time the sentry hook will wait for a response
-from the sentry server.
-
-If this time elapses with no response from
-the server an error will be returned.
-
-If `Timeout` is set to 0 the SentryHook will not wait for a reply
-and will assume a correct delivery.
-
-The SentryHook has a default timeout of `100 milliseconds` when created
-with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field:
-
-```go
-hook, _ := logrus_sentry.NewSentryHook(...)
-hook.Timeout = 20*time.Second
-```
-
-## Enabling Stacktraces
-
-By default the hook will not send any stacktraces. However, this can be enabled
-with:
-
-```go
-hook, _ := logrus_sentry.NewSentryHook(...)
-hook.StacktraceConfiguration.Enable = true
-```
-
-Subsequent calls to `logger.Error` and above will create a stacktrace.
-
-Other configuration options are:
-- `StacktraceConfiguration.Level` the logrus level at which to start capturing stacktraces.
-- `StacktraceConfiguration.Skip` how many stack frames to skip before stacktrace starts recording.
-- `StacktraceConfiguration.Context` the number of lines to include around a stack frame for context.
-- `StacktraceConfiguration.InAppPrefixes` the prefixes that will be matched against the stack frame to identify it as in_app
-- `StacktraceConfiguration.IncludeErrorBreadcrumb` whether to create a breadcrumb with the full text of error
diff --git a/vendor/github.com/evalphobia/logrus_sentry/data_field.go b/vendor/github.com/evalphobia/logrus_sentry/data_field.go
deleted file mode 100644
index 37c89fbb66f..00000000000
--- a/vendor/github.com/evalphobia/logrus_sentry/data_field.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package logrus_sentry
-
-import (
- "net/http"
-
- "github.com/getsentry/raven-go"
- "github.com/sirupsen/logrus"
-)
-
-const (
- fieldEventID = "event_id"
- fieldFingerprint = "fingerprint"
- fieldLogger = "logger"
- fieldServerName = "server_name"
- fieldTags = "tags"
- fieldHTTPRequest = "http_request"
- fieldUser = "user"
-)
-
-type dataField struct {
- data logrus.Fields
- omitList map[string]struct{}
-}
-
-func newDataField(data logrus.Fields) *dataField {
- return &dataField{
- data: data,
- omitList: make(map[string]struct{}),
- }
-}
-
-func (d *dataField) len() int {
- return len(d.data)
-}
-
-func (d *dataField) isOmit(key string) bool {
- _, ok := d.omitList[key]
- return ok
-}
-
-func (d *dataField) getLogger() (string, bool) {
- if logger, ok := d.data[fieldLogger].(string); ok {
- d.omitList[fieldLogger] = struct{}{}
- return logger, true
- }
- return "", false
-}
-
-func (d *dataField) getServerName() (string, bool) {
- if serverName, ok := d.data[fieldServerName].(string); ok {
- d.omitList[fieldServerName] = struct{}{}
- return serverName, true
- }
- return "", false
-}
-
-func (d *dataField) getTags() (raven.Tags, bool) {
- if tags, ok := d.data[fieldTags].(raven.Tags); ok {
- d.omitList[fieldTags] = struct{}{}
- return tags, true
- }
- return nil, false
-}
-
-func (d *dataField) getFingerprint() ([]string, bool) {
- if fingerprint, ok := d.data[fieldFingerprint].([]string); ok {
- d.omitList[fieldFingerprint] = struct{}{}
- return fingerprint, true
- }
- return nil, false
-}
-
-func (d *dataField) getError() (error, bool) {
- if err, ok := d.data[logrus.ErrorKey].(error); ok {
- d.omitList[logrus.ErrorKey] = struct{}{}
- return err, true
- }
- return nil, false
-}
-
-func (d *dataField) getHTTPRequest() (*raven.Http, bool) {
- if req, ok := d.data[fieldHTTPRequest].(*http.Request); ok {
- d.omitList[fieldHTTPRequest] = struct{}{}
- return raven.NewHttp(req), true
- }
- if req, ok := d.data[fieldHTTPRequest].(*raven.Http); ok {
- d.omitList[fieldHTTPRequest] = struct{}{}
- return req, true
- }
- return nil, false
-}
-
-func (d *dataField) getEventID() (string, bool) {
- eventID, ok := d.data[fieldEventID].(string)
- if !ok {
- return "", false
- }
-
- //verify eventID is 32 characters hexadecimal string (UUID4)
- uuid := parseUUID(eventID)
- if uuid == nil {
- return "", false
- }
-
- d.omitList[fieldEventID] = struct{}{}
- return uuid.noDashString(), true
-}
-
-func (d *dataField) getUser() (*raven.User, bool) {
- data := d.data
- if v, ok := data[fieldUser]; ok {
- switch val := v.(type) {
- case *raven.User:
- d.omitList[fieldUser] = struct{}{}
- return val, true
- case raven.User:
- d.omitList[fieldUser] = struct{}{}
- return &val, true
- }
- }
-
- username, _ := data["user_name"].(string)
- email, _ := data["user_email"].(string)
- id, _ := data["user_id"].(string)
- ip, _ := data["user_ip"].(string)
-
- if username == "" && email == "" && id == "" && ip == "" {
- return nil, false
- }
-
- return &raven.User{
- ID: id,
- Username: username,
- Email: email,
- IP: ip,
- }, true
-}
diff --git a/vendor/github.com/evalphobia/logrus_sentry/sentry.go b/vendor/github.com/evalphobia/logrus_sentry/sentry.go
deleted file mode 100644
index 5d314b97e6e..00000000000
--- a/vendor/github.com/evalphobia/logrus_sentry/sentry.go
+++ /dev/null
@@ -1,424 +0,0 @@
-package logrus_sentry
-
-import (
- "encoding/json"
- "fmt"
- "runtime"
- "sync"
- "time"
-
- raven "github.com/getsentry/raven-go"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-var (
- severityMap = map[logrus.Level]raven.Severity{
- logrus.TraceLevel: raven.DEBUG,
- logrus.DebugLevel: raven.DEBUG,
- logrus.InfoLevel: raven.INFO,
- logrus.WarnLevel: raven.WARNING,
- logrus.ErrorLevel: raven.ERROR,
- logrus.FatalLevel: raven.FATAL,
- logrus.PanicLevel: raven.FATAL,
- }
-)
-
-// SentryHook delivers logs to a sentry server.
-type SentryHook struct {
- // Timeout sets the time to wait for a delivery error from the sentry server.
- // If this is set to zero the server will not wait for any response and will
- // consider the message correctly sent.
- //
- // This is ignored for asynchronous hooks. If you want to set a timeout when
- // using an async hook (to bound the length of time that hook.Flush can take),
- // you probably want to create your own raven.Client and set
- // ravenClient.Transport.(*raven.HTTPTransport).Client.Timeout to set a
- // timeout on the underlying HTTP request instead.
- Timeout time.Duration
- StacktraceConfiguration StackTraceConfiguration
-
- client *raven.Client
- levels []logrus.Level
-
- serverName string
- ignoreFields map[string]struct{}
- extraFilters map[string]func(interface{}) interface{}
- errorHandlers []func(entry *logrus.Entry, err error)
-
- asynchronous bool
-
- mu sync.RWMutex
- wg sync.WaitGroup
-}
-
-// The Stacktracer interface allows an error type to return a raven.Stacktrace.
-type Stacktracer interface {
- GetStacktrace() *raven.Stacktrace
-}
-
-type causer interface {
- Cause() error
-}
-
-type pkgErrorStackTracer interface {
- StackTrace() errors.StackTrace
-}
-
-// StackTraceConfiguration allows for configuring stacktraces
-type StackTraceConfiguration struct {
- // whether stacktraces should be enabled
- Enable bool
- // the level at which to start capturing stacktraces
- Level logrus.Level
- // how many stack frames to skip before stacktrace starts recording
- Skip int
- // the number of lines to include around a stack frame for context
- Context int
- // the prefixes that will be matched against the stack frame.
- // if the stack frame's package matches one of these prefixes
- // sentry will identify the stack frame as "in_app"
- InAppPrefixes []string
- // whether sending exception type should be enabled.
- SendExceptionType bool
- // whether the exception type and message should be switched.
- SwitchExceptionTypeAndMessage bool
- // whether to include a breadcrumb with the full error stack
- IncludeErrorBreadcrumb bool
-}
-
-// NewSentryHook creates a hook to be added to an instance of logger
-// and initializes the raven client.
-// This method sets the timeout to 100 milliseconds.
-func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) {
- client, err := raven.New(DSN)
- if err != nil {
- return nil, err
- }
- return NewWithClientSentryHook(client, levels)
-}
-
-// NewWithTagsSentryHook creates a hook with tags to be added to an instance
-// of logger and initializes the raven client. This method sets the timeout to
-// 100 milliseconds.
-func NewWithTagsSentryHook(DSN string, tags map[string]string, levels []logrus.Level) (*SentryHook, error) {
- client, err := raven.NewWithTags(DSN, tags)
- if err != nil {
- return nil, err
- }
- return NewWithClientSentryHook(client, levels)
-}
-
-// NewWithClientSentryHook creates a hook using an initialized raven client.
-// This method sets the timeout to 100 milliseconds.
-func NewWithClientSentryHook(client *raven.Client, levels []logrus.Level) (*SentryHook, error) {
- return &SentryHook{
- Timeout: 100 * time.Millisecond,
- StacktraceConfiguration: StackTraceConfiguration{
- Enable: false,
- Level: logrus.ErrorLevel,
- Skip: 6,
- Context: 0,
- InAppPrefixes: nil,
- SendExceptionType: true,
- },
- client: client,
- levels: levels,
- ignoreFields: make(map[string]struct{}),
- extraFilters: make(map[string]func(interface{}) interface{}),
- }, nil
-}
-
-// NewAsyncSentryHook creates a hook same as NewSentryHook, but in asynchronous
-// mode.
-func NewAsyncSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) {
- hook, err := NewSentryHook(DSN, levels)
- return setAsync(hook), err
-}
-
-// NewAsyncWithTagsSentryHook creates a hook same as NewWithTagsSentryHook, but
-// in asynchronous mode.
-func NewAsyncWithTagsSentryHook(DSN string, tags map[string]string, levels []logrus.Level) (*SentryHook, error) {
- hook, err := NewWithTagsSentryHook(DSN, tags, levels)
- return setAsync(hook), err
-}
-
-// NewAsyncWithClientSentryHook creates a hook same as NewWithClientSentryHook,
-// but in asynchronous mode.
-func NewAsyncWithClientSentryHook(client *raven.Client, levels []logrus.Level) (*SentryHook, error) {
- hook, err := NewWithClientSentryHook(client, levels)
- return setAsync(hook), err
-}
-
-func setAsync(hook *SentryHook) *SentryHook {
- if hook == nil {
- return nil
- }
- hook.asynchronous = true
- return hook
-}
-
-// Fire is called when an event should be sent to sentry
-// Special fields that sentry uses to give more information to the server
-// are extracted from entry.Data (if they are found)
-// These fields are: error, logger, server_name, http_request, tags
-func (hook *SentryHook) Fire(entry *logrus.Entry) error {
- hook.mu.RLock() // Allow multiple go routines to log simultaneously
- defer hook.mu.RUnlock()
-
- df := newDataField(entry.Data)
-
- err, hasError := df.getError()
- var crumbs *Breadcrumbs
- if hasError && hook.StacktraceConfiguration.IncludeErrorBreadcrumb {
- crumbs = &Breadcrumbs{
- Values: []Value{{
- Timestamp: int64(time.Now().Unix()),
- Type: "error",
- Message: fmt.Sprintf("%+v", err),
- }},
- }
- }
-
- packet := raven.NewPacketWithExtra(entry.Message, nil, crumbs)
- packet.Timestamp = raven.Timestamp(entry.Time)
- packet.Level = severityMap[entry.Level]
- packet.Platform = "go"
-
- // set special fields
- if hook.serverName != "" {
- packet.ServerName = hook.serverName
- }
- if logger, ok := df.getLogger(); ok {
- packet.Logger = logger
- }
- if serverName, ok := df.getServerName(); ok {
- packet.ServerName = serverName
- }
- if eventID, ok := df.getEventID(); ok {
- packet.EventID = eventID
- }
- if tags, ok := df.getTags(); ok {
- packet.Tags = tags
- }
- if fingerprint, ok := df.getFingerprint(); ok {
- packet.Fingerprint = fingerprint
- }
- if req, ok := df.getHTTPRequest(); ok {
- packet.Interfaces = append(packet.Interfaces, req)
- }
- if user, ok := df.getUser(); ok {
- packet.Interfaces = append(packet.Interfaces, user)
- }
-
- // set stacktrace data
- stConfig := &hook.StacktraceConfiguration
- if stConfig.Enable && entry.Level <= stConfig.Level {
- if err, ok := df.getError(); ok {
- var currentStacktrace *raven.Stacktrace
- currentStacktrace = hook.findStacktrace(err)
- if currentStacktrace == nil {
- currentStacktrace = raven.NewStacktrace(stConfig.Skip, stConfig.Context, stConfig.InAppPrefixes)
- }
- cause := errors.Cause(err)
- if cause == nil {
- cause = err
- }
- exc := raven.NewException(cause, currentStacktrace)
- if !stConfig.SendExceptionType {
- exc.Type = ""
- }
- if stConfig.SwitchExceptionTypeAndMessage {
- packet.Interfaces = append(packet.Interfaces, currentStacktrace)
- packet.Culprit = exc.Type + ": " + currentStacktrace.Culprit()
- } else {
- packet.Interfaces = append(packet.Interfaces, exc)
- packet.Culprit = err.Error()
- }
- } else {
- currentStacktrace := raven.NewStacktrace(stConfig.Skip, stConfig.Context, stConfig.InAppPrefixes)
- if currentStacktrace != nil {
- packet.Interfaces = append(packet.Interfaces, currentStacktrace)
- }
- }
- } else {
- // set the culprit even when the stack trace is disabled, as long as we have an error
- if err, ok := df.getError(); ok {
- packet.Culprit = err.Error()
- }
- }
-
- // set other fields
- dataExtra := hook.formatExtraData(df)
- if packet.Extra == nil {
- packet.Extra = dataExtra
- } else {
- for k, v := range dataExtra {
- packet.Extra[k] = v
- }
- }
-
- _, errCh := hook.client.Capture(packet, nil)
-
- switch {
- case hook.asynchronous:
- // Our use of hook.mu guarantees that we are following the WaitGroup rule of
- // not calling Add in parallel with Wait.
- hook.wg.Add(1)
- go func() {
- if err := <-errCh; err != nil {
- for _, handlerFn := range hook.errorHandlers {
- handlerFn(entry, err)
- }
- }
- hook.wg.Done()
- }()
- return nil
- case hook.Timeout == 0:
- return nil
- default:
- timeout := hook.Timeout
- timeoutCh := time.After(timeout)
- select {
- case err := <-errCh:
- for _, handlerFn := range hook.errorHandlers {
- handlerFn(entry, err)
- }
- return err
- case <-timeoutCh:
- return fmt.Errorf("no response from sentry server in %s", timeout)
- }
- }
-}
-
-// Flush waits for the log queue to empty. This function only does anything in
-// asynchronous mode.
-func (hook *SentryHook) Flush() {
- if !hook.asynchronous {
- return
- }
- hook.mu.Lock() // Claim exclusive access; any logging goroutines will block until the flush completes
- defer hook.mu.Unlock()
-
- hook.wg.Wait()
-}
-
-func (hook *SentryHook) findStacktrace(err error) *raven.Stacktrace {
- var stacktrace *raven.Stacktrace
- var stackErr errors.StackTrace
- for err != nil {
- // Find the earliest *raven.Stacktrace, or error.StackTrace
- if tracer, ok := err.(Stacktracer); ok {
- stacktrace = tracer.GetStacktrace()
- stackErr = nil
- } else if tracer, ok := err.(pkgErrorStackTracer); ok {
- stacktrace = nil
- stackErr = tracer.StackTrace()
- }
- if cause, ok := err.(causer); ok {
- err = cause.Cause()
- } else {
- break
- }
- }
- if stackErr != nil {
- stacktrace = hook.convertStackTrace(stackErr)
- }
- return stacktrace
-}
-
-// convertStackTrace converts an errors.StackTrace into a natively consumable
-// *raven.Stacktrace
-func (hook *SentryHook) convertStackTrace(st errors.StackTrace) *raven.Stacktrace {
- stConfig := &hook.StacktraceConfiguration
- stFrames := []errors.Frame(st)
- frames := make([]*raven.StacktraceFrame, 0, len(stFrames))
- for i := range stFrames {
- pc := uintptr(stFrames[i])
- fn := runtime.FuncForPC(pc)
- file, line := fn.FileLine(pc)
- frame := raven.NewStacktraceFrame(pc, fn.Name(), file, line, stConfig.Context, stConfig.InAppPrefixes)
- if frame != nil {
- frames = append(frames, frame)
- }
- }
-
- // Sentry wants the frames with the oldest first, so reverse them
- for i, j := 0, len(frames)-1; i < j; i, j = i+1, j-1 {
- frames[i], frames[j] = frames[j], frames[i]
- }
- return &raven.Stacktrace{Frames: frames}
-}
-
-// Levels returns the available logging levels.
-func (hook *SentryHook) Levels() []logrus.Level {
- return hook.levels
-}
-
-// AddIgnore adds field name to ignore.
-func (hook *SentryHook) AddIgnore(name string) {
- hook.ignoreFields[name] = struct{}{}
-}
-
-// AddExtraFilter adds a custom filter function.
-func (hook *SentryHook) AddExtraFilter(name string, fn func(interface{}) interface{}) {
- hook.extraFilters[name] = fn
-}
-
-// AddErrorHandler adds a error handler function used when Sentry returns error.
-func (hook *SentryHook) AddErrorHandler(fn func(entry *logrus.Entry, err error)) {
- hook.errorHandlers = append(hook.errorHandlers, fn)
-}
-
-func (hook *SentryHook) formatExtraData(df *dataField) (result map[string]interface{}) {
- // create a map for passing to Sentry's extra data
- result = make(map[string]interface{}, df.len())
- for k, v := range df.data {
- if df.isOmit(k) {
- continue // skip already used special fields
- }
- if _, ok := hook.ignoreFields[k]; ok {
- continue
- }
-
- if fn, ok := hook.extraFilters[k]; ok {
- v = fn(v) // apply custom filter
- } else {
- v = formatData(v) // use default formatter
- }
- result[k] = v
- }
- return result
-}
-
-// formatData returns value as a suitable format.
-func formatData(value interface{}) (formatted interface{}) {
- switch value := value.(type) {
- case json.Marshaler:
- return value
- case error:
- return value.Error()
- case fmt.Stringer:
- return value.String()
- default:
- return value
- }
-}
-
-// utility classes for breadcrumb support
-type Breadcrumbs struct {
- Values []Value `json:"values"`
-}
-
-type Value struct {
- Timestamp int64 `json:"timestamp"`
- Type string `json:"type"`
- Message string `json:"message"`
- Category string `json:"category"`
- Level string `json:"string"`
- Data interface{} `json:"data"`
-}
-
-func (b *Breadcrumbs) Class() string {
- return "breadcrumbs"
-}
diff --git a/vendor/github.com/evalphobia/logrus_sentry/sentry_setter.go b/vendor/github.com/evalphobia/logrus_sentry/sentry_setter.go
deleted file mode 100644
index 1912e53f8a9..00000000000
--- a/vendor/github.com/evalphobia/logrus_sentry/sentry_setter.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package logrus_sentry
-
-import (
- "github.com/getsentry/raven-go"
-)
-
-// SetDefaultLoggerName sets default logger name tag.
-func (hook *SentryHook) SetDefaultLoggerName(name string) {
- hook.client.SetDefaultLoggerName(name)
-}
-
-// SetEnvironment sets environment tag.
-func (hook *SentryHook) SetEnvironment(environment string) {
- hook.client.SetEnvironment(environment)
-}
-
-// SetHttpContext sets http client.
-func (hook *SentryHook) SetHttpContext(h *raven.Http) {
- hook.client.SetHttpContext(h)
-}
-
-// SetIgnoreErrors sets ignoreErrorsRegexp.
-func (hook *SentryHook) SetIgnoreErrors(errs ...string) error {
- return hook.client.SetIgnoreErrors(errs)
-}
-
-// SetIncludePaths sets includePaths.
-func (hook *SentryHook) SetIncludePaths(p []string) {
- hook.client.SetIncludePaths(p)
-}
-
-// SetRelease sets release tag.
-func (hook *SentryHook) SetRelease(release string) {
- hook.client.SetRelease(release)
-}
-
-// SetSampleRate sets sampling rate.
-func (hook *SentryHook) SetSampleRate(rate float32) error {
- return hook.client.SetSampleRate(rate)
-}
-
-// SetTagsContext sets tags.
-func (hook *SentryHook) SetTagsContext(t map[string]string) {
- hook.client.SetTagsContext(t)
-}
-
-// SetUserContext sets user.
-func (hook *SentryHook) SetUserContext(u *raven.User) {
- hook.client.SetUserContext(u)
-}
-
-// SetServerName sets server_name tag.
-func (hook *SentryHook) SetServerName(serverName string) {
- hook.serverName = serverName
-}
diff --git a/vendor/github.com/evalphobia/logrus_sentry/utils.go b/vendor/github.com/evalphobia/logrus_sentry/utils.go
deleted file mode 100644
index 8b4a9095d3b..00000000000
--- a/vendor/github.com/evalphobia/logrus_sentry/utils.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package logrus_sentry
-
-import (
- "fmt"
- "strings"
-)
-
-/*
-Copyright (c) 2009,2014 Google Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
-// 4122.
-type uuid []byte
-
-// parseUUID decodes s into a UUID or returns nil. Both the UUID form of
-// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
-// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and
-// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
-func parseUUID(s string) uuid {
- //If it is in no dash format "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- if len(s) == 32 {
- uuid := make([]byte, 16)
- for i, x := range []int{
- 0, 2, 4, 6, 8, 10,
- 12, 14, 16, 18, 20,
- 22, 24, 26, 28, 30} {
- if v, ok := xtob(s[x:]); !ok {
- return nil
- } else {
- uuid[i] = v
- }
- }
- return uuid
- }
-
- if len(s) == 36+9 {
- if strings.ToLower(s[:9]) != "urn:uuid:" {
- return nil
- }
- s = s[9:]
- } else if len(s) != 36 {
- return nil
- }
- if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
- return nil
- }
- uuid := make([]byte, 16)
- for i, x := range []int{
- 0, 2, 4, 6,
- 9, 11,
- 14, 16,
- 19, 21,
- 24, 26, 28, 30, 32, 34} {
- if v, ok := xtob(s[x:]); !ok {
- return nil
- } else {
- uuid[i] = v
- }
- }
- return uuid
-}
-
-// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-// , or "" if uuid is invalid.
-func (uuid uuid) string() string {
- if uuid == nil || len(uuid) != 16 {
- return ""
- }
- b := []byte(uuid)
- return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
- b[:4], b[4:6], b[6:8], b[8:10], b[10:])
-}
-
-func (uuid uuid) noDashString() string {
- if uuid == nil || len(uuid) != 16 {
- return ""
- }
- b := []byte(uuid)
- return fmt.Sprintf("%08x%04x%04x%04x%012x",
- b[:4], b[4:6], b[6:8], b[8:10], b[10:])
-}
-
-// xvalues returns the value of a byte as a hexadecimal digit or 255.
-var xvalues = []byte{
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
- 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-}
-
-// xtob converts the the first two hex bytes of x into a byte.
-func xtob(x string) (byte, bool) {
- b1 := xvalues[x[0]]
- b2 := xvalues[x[1]]
- return (b1 << 4) | b2, b1 != 255 && b2 != 255
-}
diff --git a/vendor/github.com/facebookgo/clock/LICENSE b/vendor/github.com/facebookgo/clock/LICENSE
deleted file mode 100644
index ce212cb1cee..00000000000
--- a/vendor/github.com/facebookgo/clock/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Ben Johnson
-
-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.
diff --git a/vendor/github.com/facebookgo/clock/README.md b/vendor/github.com/facebookgo/clock/README.md
deleted file mode 100644
index 5d4f4fe72e7..00000000000
--- a/vendor/github.com/facebookgo/clock/README.md
+++ /dev/null
@@ -1,104 +0,0 @@
-clock [![Build Status](https://drone.io/github.com/benbjohnson/clock/status.png)](https://drone.io/github.com/benbjohnson/clock/latest) [![Coverage Status](https://coveralls.io/repos/benbjohnson/clock/badge.png?branch=master)](https://coveralls.io/r/benbjohnson/clock?branch=master) [![GoDoc](https://godoc.org/github.com/benbjohnson/clock?status.png)](https://godoc.org/github.com/benbjohnson/clock) ![Project status](http://img.shields.io/status/experimental.png?color=red)
-=====
-
-Clock is a small library for mocking time in Go. It provides an interface
-around the standard library's [`time`][time] package so that the application
-can use the realtime clock while tests can use the mock clock.
-
-[time]: http://golang.org/pkg/time/
-
-
-## Usage
-
-### Realtime Clock
-
-Your application can maintain a `Clock` variable that will allow realtime and
-mock clocks to be interchangable. For example, if you had an `Application` type:
-
-```go
-import "github.com/benbjohnson/clock"
-
-type Application struct {
- Clock clock.Clock
-}
-```
-
-You could initialize it to use the realtime clock like this:
-
-```go
-var app Application
-app.Clock = clock.New()
-...
-```
-
-Then all timers and time-related functionality should be performed from the
-`Clock` variable.
-
-
-### Mocking time
-
-In your tests, you will want to use a `Mock` clock:
-
-```go
-import (
- "testing"
-
- "github.com/benbjohnson/clock"
-)
-
-func TestApplication_DoSomething(t *testing.T) {
- mock := clock.NewMock()
- app := Application{Clock: mock}
- ...
-}
-```
-
-Now that you've initialized your application to use the mock clock, you can
-adjust the time programmatically. The mock clock always starts from the Unix
-epoch (midnight, Jan 1, 1970 UTC).
-
-
-### Controlling time
-
-The mock clock provides the same functions that the standard library's `time`
-package provides. For example, to find the current time, you use the `Now()`
-function:
-
-```go
-mock := clock.NewMock()
-
-// Find the current time.
-mock.Now().UTC() // 1970-01-01 00:00:00 +0000 UTC
-
-// Move the clock forward.
-mock.Add(2 * time.Hour)
-
-// Check the time again. It's 2 hours later!
-mock.Now().UTC() // 1970-01-01 02:00:00 +0000 UTC
-```
-
-Timers and Tickers are also controlled by this same mock clock. They will only
-execute when the clock is moved forward:
-
-```
-mock := clock.NewMock()
-count := 0
-
-// Kick off a timer to increment every 1 mock second.
-go func() {
- ticker := clock.Ticker(1 * time.Second)
- for {
- <-ticker.C
- count++
- }
-}()
-runtime.Gosched()
-
-// Move the clock forward 10 second.
-mock.Add(10 * time.Second)
-
-// This prints 10.
-fmt.Println(count)
-```
-
-
diff --git a/vendor/github.com/facebookgo/clock/clock.go b/vendor/github.com/facebookgo/clock/clock.go
deleted file mode 100644
index bca1a7ba8b3..00000000000
--- a/vendor/github.com/facebookgo/clock/clock.go
+++ /dev/null
@@ -1,363 +0,0 @@
-package clock
-
-import (
- "runtime"
- "sort"
- "sync"
- "time"
-)
-
-// Clock represents an interface to the functions in the standard library time
-// package. Two implementations are available in the clock package. The first
-// is a real-time clock which simply wraps the time package's functions. The
-// second is a mock clock which will only make forward progress when
-// programmatically adjusted.
-type Clock interface {
- After(d time.Duration) <-chan time.Time
- AfterFunc(d time.Duration, f func()) *Timer
- Now() time.Time
- Sleep(d time.Duration)
- Tick(d time.Duration) <-chan time.Time
- Ticker(d time.Duration) *Ticker
- Timer(d time.Duration) *Timer
-}
-
-// New returns an instance of a real-time clock.
-func New() Clock {
- return &clock{}
-}
-
-// clock implements a real-time clock by simply wrapping the time package functions.
-type clock struct{}
-
-func (c *clock) After(d time.Duration) <-chan time.Time { return time.After(d) }
-
-func (c *clock) AfterFunc(d time.Duration, f func()) *Timer {
- return &Timer{timer: time.AfterFunc(d, f)}
-}
-
-func (c *clock) Now() time.Time { return time.Now() }
-
-func (c *clock) Sleep(d time.Duration) { time.Sleep(d) }
-
-func (c *clock) Tick(d time.Duration) <-chan time.Time { return time.Tick(d) }
-
-func (c *clock) Ticker(d time.Duration) *Ticker {
- t := time.NewTicker(d)
- return &Ticker{C: t.C, ticker: t}
-}
-
-func (c *clock) Timer(d time.Duration) *Timer {
- t := time.NewTimer(d)
- return &Timer{C: t.C, timer: t}
-}
-
-// Mock represents a mock clock that only moves forward programmically.
-// It can be preferable to a real-time clock when testing time-based functionality.
-type Mock struct {
- mu sync.Mutex
- now time.Time // current time
- timers clockTimers // tickers & timers
-
- calls Calls
- waiting []waiting
- callsMutex sync.Mutex
-}
-
-// NewMock returns an instance of a mock clock.
-// The current time of the mock clock on initialization is the Unix epoch.
-func NewMock() *Mock {
- return &Mock{now: time.Unix(0, 0)}
-}
-
-// Add moves the current time of the mock clock forward by the duration.
-// This should only be called from a single goroutine at a time.
-func (m *Mock) Add(d time.Duration) {
- // Calculate the final current time.
- t := m.now.Add(d)
-
- // Continue to execute timers until there are no more before the new time.
- for {
- if !m.runNextTimer(t) {
- break
- }
- }
-
- // Ensure that we end with the new time.
- m.mu.Lock()
- m.now = t
- m.mu.Unlock()
-
- // Give a small buffer to make sure the other goroutines get handled.
- gosched()
-}
-
-// runNextTimer executes the next timer in chronological order and moves the
-// current time to the timer's next tick time. The next time is not executed if
-// it's next time if after the max time. Returns true if a timer is executed.
-func (m *Mock) runNextTimer(max time.Time) bool {
- m.mu.Lock()
-
- // Sort timers by time.
- sort.Sort(m.timers)
-
- // If we have no more timers then exit.
- if len(m.timers) == 0 {
- m.mu.Unlock()
- return false
- }
-
- // Retrieve next timer. Exit if next tick is after new time.
- t := m.timers[0]
- if t.Next().After(max) {
- m.mu.Unlock()
- return false
- }
-
- // Move "now" forward and unlock clock.
- m.now = t.Next()
- m.mu.Unlock()
-
- // Execute timer.
- t.Tick(m.now)
- return true
-}
-
-// After waits for the duration to elapse and then sends the current time on the returned channel.
-func (m *Mock) After(d time.Duration) <-chan time.Time {
- defer m.inc(&m.calls.After)
- return m.Timer(d).C
-}
-
-// AfterFunc waits for the duration to elapse and then executes a function.
-// A Timer is returned that can be stopped.
-func (m *Mock) AfterFunc(d time.Duration, f func()) *Timer {
- defer m.inc(&m.calls.AfterFunc)
- t := m.Timer(d)
- t.C = nil
- t.fn = f
- return t
-}
-
-// Now returns the current wall time on the mock clock.
-func (m *Mock) Now() time.Time {
- defer m.inc(&m.calls.Now)
- m.mu.Lock()
- defer m.mu.Unlock()
- return m.now
-}
-
-// Sleep pauses the goroutine for the given duration on the mock clock.
-// The clock must be moved forward in a separate goroutine.
-func (m *Mock) Sleep(d time.Duration) {
- defer m.inc(&m.calls.Sleep)
- <-m.After(d)
-}
-
-// Tick is a convenience function for Ticker().
-// It will return a ticker channel that cannot be stopped.
-func (m *Mock) Tick(d time.Duration) <-chan time.Time {
- defer m.inc(&m.calls.Tick)
- return m.Ticker(d).C
-}
-
-// Ticker creates a new instance of Ticker.
-func (m *Mock) Ticker(d time.Duration) *Ticker {
- defer m.inc(&m.calls.Ticker)
- m.mu.Lock()
- defer m.mu.Unlock()
- ch := make(chan time.Time)
- t := &Ticker{
- C: ch,
- c: ch,
- mock: m,
- d: d,
- next: m.now.Add(d),
- }
- m.timers = append(m.timers, (*internalTicker)(t))
- return t
-}
-
-// Timer creates a new instance of Timer.
-func (m *Mock) Timer(d time.Duration) *Timer {
- defer m.inc(&m.calls.Timer)
- m.mu.Lock()
- defer m.mu.Unlock()
- ch := make(chan time.Time)
- t := &Timer{
- C: ch,
- c: ch,
- mock: m,
- next: m.now.Add(d),
- }
- m.timers = append(m.timers, (*internalTimer)(t))
- return t
-}
-
-func (m *Mock) removeClockTimer(t clockTimer) {
- m.mu.Lock()
- defer m.mu.Unlock()
- for i, timer := range m.timers {
- if timer == t {
- copy(m.timers[i:], m.timers[i+1:])
- m.timers[len(m.timers)-1] = nil
- m.timers = m.timers[:len(m.timers)-1]
- break
- }
- }
- sort.Sort(m.timers)
-}
-
-func (m *Mock) inc(addr *uint32) {
- m.callsMutex.Lock()
- defer m.callsMutex.Unlock()
- *addr++
- var newWaiting []waiting
- for _, w := range m.waiting {
- if m.calls.atLeast(w.expected) {
- close(w.done)
- continue
- }
- newWaiting = append(newWaiting, w)
- }
- m.waiting = newWaiting
-}
-
-// Wait waits for at least the relevant calls before returning. The expected
-// Calls are always over the lifetime of the Mock. Values in the Calls struct
-// are used as the minimum number of calls, this allows you to wait for only
-// the calls you care about.
-func (m *Mock) Wait(s Calls) {
- m.callsMutex.Lock()
- if m.calls.atLeast(s) {
- m.callsMutex.Unlock()
- return
- }
- done := make(chan struct{})
- m.waiting = append(m.waiting, waiting{expected: s, done: done})
- m.callsMutex.Unlock()
- <-done
-}
-
-// clockTimer represents an object with an associated start time.
-type clockTimer interface {
- Next() time.Time
- Tick(time.Time)
-}
-
-// clockTimers represents a list of sortable timers.
-type clockTimers []clockTimer
-
-func (a clockTimers) Len() int { return len(a) }
-func (a clockTimers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-func (a clockTimers) Less(i, j int) bool { return a[i].Next().Before(a[j].Next()) }
-
-// Timer represents a single event.
-// The current time will be sent on C, unless the timer was created by AfterFunc.
-type Timer struct {
- C <-chan time.Time
- c chan time.Time
- timer *time.Timer // realtime impl, if set
- next time.Time // next tick time
- mock *Mock // mock clock, if set
- fn func() // AfterFunc function, if set
-}
-
-// Stop turns off the ticker.
-func (t *Timer) Stop() {
- if t.timer != nil {
- t.timer.Stop()
- } else {
- t.mock.removeClockTimer((*internalTimer)(t))
- }
-}
-
-type internalTimer Timer
-
-func (t *internalTimer) Next() time.Time { return t.next }
-func (t *internalTimer) Tick(now time.Time) {
- if t.fn != nil {
- t.fn()
- } else {
- t.c <- now
- }
- t.mock.removeClockTimer((*internalTimer)(t))
- gosched()
-}
-
-// Ticker holds a channel that receives "ticks" at regular intervals.
-type Ticker struct {
- C <-chan time.Time
- c chan time.Time
- ticker *time.Ticker // realtime impl, if set
- next time.Time // next tick time
- mock *Mock // mock clock, if set
- d time.Duration // time between ticks
-}
-
-// Stop turns off the ticker.
-func (t *Ticker) Stop() {
- if t.ticker != nil {
- t.ticker.Stop()
- } else {
- t.mock.removeClockTimer((*internalTicker)(t))
- }
-}
-
-type internalTicker Ticker
-
-func (t *internalTicker) Next() time.Time { return t.next }
-func (t *internalTicker) Tick(now time.Time) {
- select {
- case t.c <- now:
- case <-time.After(1 * time.Millisecond):
- }
- t.next = now.Add(t.d)
- gosched()
-}
-
-// Sleep momentarily so that other goroutines can process.
-func gosched() { runtime.Gosched() }
-
-// Calls keeps track of the count of calls for each of the methods on the Clock
-// interface.
-type Calls struct {
- After uint32
- AfterFunc uint32
- Now uint32
- Sleep uint32
- Tick uint32
- Ticker uint32
- Timer uint32
-}
-
-// atLeast returns true if at least the number of calls in o have been made.
-func (c Calls) atLeast(o Calls) bool {
- if c.After < o.After {
- return false
- }
- if c.AfterFunc < o.AfterFunc {
- return false
- }
- if c.Now < o.Now {
- return false
- }
- if c.Sleep < o.Sleep {
- return false
- }
- if c.Tick < o.Tick {
- return false
- }
- if c.Ticker < o.Ticker {
- return false
- }
- if c.Timer < o.Timer {
- return false
- }
- return true
-}
-
-type waiting struct {
- expected Calls
- done chan struct{}
-}
diff --git a/vendor/github.com/franela/goreq/.gitignore b/vendor/github.com/franela/goreq/.gitignore
deleted file mode 100644
index 131fc16fbbc..00000000000
--- a/vendor/github.com/franela/goreq/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-
-src
diff --git a/vendor/github.com/franela/goreq/.travis.yml b/vendor/github.com/franela/goreq/.travis.yml
deleted file mode 100644
index 916dd6889ef..00000000000
--- a/vendor/github.com/franela/goreq/.travis.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-language: go
-go:
- - 1.9.2
- - tip
-notifications:
- email:
- - ionathan@gmail.com
- - marcosnils@gmail.com
diff --git a/vendor/github.com/franela/goreq/LICENSE b/vendor/github.com/franela/goreq/LICENSE
deleted file mode 100644
index 068dee1edcc..00000000000
--- a/vendor/github.com/franela/goreq/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2013 Jonathan Leibiusky and Marcos Lilljedahl
-
-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.
diff --git a/vendor/github.com/franela/goreq/Makefile b/vendor/github.com/franela/goreq/Makefile
deleted file mode 100644
index 0f04d6572df..00000000000
--- a/vendor/github.com/franela/goreq/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-test:
- go get -v -d -t ./...
- go test -v
diff --git a/vendor/github.com/franela/goreq/README.md b/vendor/github.com/franela/goreq/README.md
deleted file mode 100644
index c202f32641b..00000000000
--- a/vendor/github.com/franela/goreq/README.md
+++ /dev/null
@@ -1,444 +0,0 @@
-[![Build Status](https://img.shields.io/travis/franela/goreq/master.svg)](https://travis-ci.org/franela/goreq)
-[![GoDoc](https://godoc.org/github.com/franela/goreq?status.svg)](https://godoc.org/github.com/franela/goreq)
-
-GoReq
-=======
-
-Simple and sane HTTP request library for Go language.
-
-
-
-**Table of Contents**
-
-- [Why GoReq?](#user-content-why-goreq)
-- [How do I install it?](#user-content-how-do-i-install-it)
-- [What can I do with it?](#user-content-what-can-i-do-with-it)
- - [Making requests with different methods](#user-content-making-requests-with-different-methods)
- - [GET](#user-content-get)
- - [Tags](#user-content-tags)
- - [POST](#user-content-post)
- - [Sending payloads in the Body](#user-content-sending-payloads-in-the-body)
- - [Specifiying request headers](#user-content-specifiying-request-headers)
- - [Sending Cookies](#cookie-support)
- - [Setting timeouts](#user-content-setting-timeouts)
- - [Using the Response and Error](#user-content-using-the-response-and-error)
- - [Receiving JSON](#user-content-receiving-json)
- - [Sending/Receiving Compressed Payloads](#user-content-sendingreceiving-compressed-payloads)
- - [Using gzip compression:](#user-content-using-gzip-compression)
- - [Using deflate compression:](#user-content-using-deflate-compression)
- - [Using compressed responses:](#user-content-using-compressed-responses)
- - [Proxy](#proxy)
- - [Debugging requests](#debug)
- - [Getting raw Request & Response](#getting-raw-request--response)
- - [TODO:](#user-content-todo)
-
-
-
-Why GoReq?
-==========
-
-Go has very nice native libraries that allows you to do lots of cool things. But sometimes those libraries are too low level, which means that to do a simple thing, like an HTTP Request, it takes some time. And if you want to do something as simple as adding a timeout to a request, you will end up writing several lines of code.
-
-This is why we think GoReq is useful. Because you can do all your HTTP requests in a very simple and comprehensive way, while enabling you to do more advanced stuff by giving you access to the native API.
-
-How do I install it?
-====================
-
-```bash
-go get github.com/franela/goreq
-```
-
-What can I do with it?
-======================
-
-## Making requests with different methods
-
-#### GET
-```go
-res, err := goreq.Request{ Uri: "http://www.google.com" }.Do()
-```
-
-GoReq default method is GET.
-
-You can also set value to GET method easily
-
-```go
-type Item struct {
- Limit int
- Skip int
- Fields string
-}
-
-item := Item {
- Limit: 3,
- Skip: 5,
- Fields: "Value",
-}
-
-res, err := goreq.Request{
- Uri: "http://localhost:3000/",
- QueryString: item,
-}.Do()
-```
-The sample above will send `http://localhost:3000/?limit=3&skip=5&fields=Value`
-
-Alternatively the `url` tag can be used in struct fields to customize encoding properties
-
-```go
-type Item struct {
- TheLimit int `url:"the_limit"`
- TheSkip string `url:"the_skip,omitempty"`
- TheFields string `url:"-"`
-}
-
-item := Item {
- TheLimit: 3,
- TheSkip: "",
- TheFields: "Value",
-}
-
-res, err := goreq.Request{
- Uri: "http://localhost:3000/",
- QueryString: item,
-}.Do()
-```
-The sample above will send `http://localhost:3000/?the_limit=3`
-
-
-QueryString also support url.Values
-
-```go
-item := url.Values{}
-item.Set("Limit", 3)
-item.Add("Field", "somefield")
-item.Add("Field", "someotherfield")
-
-res, err := goreq.Request{
- Uri: "http://localhost:3000/",
- QueryString: item,
-}.Do()
-```
-
-The sample above will send `http://localhost:3000/?limit=3&field=somefield&field=someotherfield`
-
-### Tags
-
-Struct field `url` tag is mainly used as the request parameter name.
-Tags can be comma separated multiple values, 1st value is for naming and rest has special meanings.
-
-- special tag for 1st value
- - `-`: value is ignored if set this
-
-- special tag for rest 2nd value
- - `omitempty`: zero-value is ignored if set this
- - `squash`: the fields of embedded struct is used for parameter
-
-#### Tag Examples
-
-```go
-type Place struct {
- Country string `url:"country"`
- City string `url:"city"`
- ZipCode string `url:"zipcode,omitempty"`
-}
-
-type Person struct {
- Place `url:",squash"`
-
- FirstName string `url:"first_name"`
- LastName string `url:"last_name"`
- Age string `url:"age,omitempty"`
- Password string `url:"-"`
-}
-
-johnbull := Person{
- Place: Place{ // squash the embedded struct value
- Country: "UK",
- City: "London",
- ZipCode: "SW1",
- },
- FirstName: "John",
- LastName: "Doe",
- Age: "35",
- Password: "my-secret", // ignored for parameter
-}
-
-goreq.Request{
- Uri: "http://localhost/",
- QueryString: johnbull,
-}.Do()
-// => `http://localhost/?first_name=John&last_name=Doe&age=35&country=UK&city=London&zip_code=SW1`
-
-
-// age and zipcode will be ignored because of `omitempty`
-// but firstname isn't.
-samurai := Person{
- Place: Place{ // squash the embedded struct value
- Country: "Japan",
- City: "Tokyo",
- },
- LastName: "Yagyu",
-}
-
-goreq.Request{
- Uri: "http://localhost/",
- QueryString: samurai,
-}.Do()
-// => `http://localhost/?first_name=&last_name=yagyu&country=Japan&city=Tokyo`
-```
-
-
-#### POST
-
-```go
-res, err := goreq.Request{ Method: "POST", Uri: "http://www.google.com" }.Do()
-```
-
-## Sending payloads in the Body
-
-You can send ```string```, ```Reader``` or ```interface{}``` in the body. The first two will be sent as text. The last one will be marshalled to JSON, if possible.
-
-```go
-type Item struct {
- Id int
- Name string
-}
-
-item := Item{ Id: 1111, Name: "foobar" }
-
-res, err := goreq.Request{
- Method: "POST",
- Uri: "http://www.google.com",
- Body: item,
-}.Do()
-```
-
-## Specifiying request headers
-
-We think that most of the times the request headers that you use are: ```Host```, ```Content-Type```, ```Accept``` and ```User-Agent```. This is why we decided to make it very easy to set these headers.
-
-```go
-res, err := goreq.Request{
- Uri: "http://www.google.com",
- Host: "foobar.com",
- Accept: "application/json",
- ContentType: "application/json",
- UserAgent: "goreq",
-}.Do()
-```
-
-But sometimes you need to set other headers. You can still do it.
-
-```go
-req := goreq.Request{ Uri: "http://www.google.com" }
-
-req.AddHeader("X-Custom", "somevalue")
-
-req.Do()
-```
-
-Alternatively you can use the `WithHeader` function to keep the syntax short
-
-```go
-res, err = goreq.Request{ Uri: "http://www.google.com" }.WithHeader("X-Custom", "somevalue").Do()
-```
-
-## Cookie support
-
-Cookies can be either set at the request level by sending a [CookieJar](http://golang.org/pkg/net/http/cookiejar/) in the `CookieJar` request field
-or you can use goreq's one-liner WithCookie method as shown below
-
-```go
-res, err := goreq.Request{
- Uri: "http://www.google.com",
-}.
-WithCookie(&http.Cookie{Name: "c1", Value: "v1"}).
-Do()
-```
-
-## Setting timeouts
-
-GoReq supports 2 kind of timeouts. A general connection timeout and a request specific one. By default the connection timeout is of 1 second. There is no default for request timeout, which means it will wait forever.
-
-You can change the connection timeout doing:
-
-```go
-goreq.SetConnectTimeout(100 * time.Millisecond)
-```
-
-And specify the request timeout doing:
-
-```go
-res, err := goreq.Request{
- Uri: "http://www.google.com",
- Timeout: 500 * time.Millisecond,
-}.Do()
-```
-
-## Using the Response and Error
-
-GoReq will always return 2 values: a ```Response``` and an ```Error```.
-If ```Error``` is not ```nil``` it means that an error happened while doing the request and you shouldn't use the ```Response``` in any way.
-You can check what happened by getting the error message:
-
-```go
-fmt.Println(err.Error())
-```
-And to make it easy to know if it was a timeout error, you can ask the error or return it:
-
-```go
-if serr, ok := err.(*goreq.Error); ok {
- if serr.Timeout() {
- ...
- }
-}
-return err
-```
-
-If you don't get an error, you can safely use the ```Response```.
-
-```go
-res.Uri // return final URL location of the response (fulfilled after redirect was made)
-res.StatusCode // return the status code of the response
-res.Body // gives you access to the body
-res.Body.ToString() // will return the body as a string
-res.Header.Get("Content-Type") // gives you access to all the response headers
-```
-Remember that you should **always** close `res.Body` if it's not `nil`
-
-## Receiving JSON
-
-GoReq will help you to receive and unmarshal JSON.
-
-```go
-type Item struct {
- Id int
- Name string
-}
-
-var item Item
-
-res.Body.FromJsonTo(&item)
-```
-
-## Sending/Receiving Compressed Payloads
-GoReq supports gzip, deflate and zlib compression of requests' body and transparent decompression of responses provided they have a correct `Content-Encoding` header.
-
-##### Using gzip compression:
-```go
-res, err := goreq.Request{
- Method: "POST",
- Uri: "http://www.google.com",
- Body: item,
- Compression: goreq.Gzip(),
-}.Do()
-```
-##### Using deflate/zlib compression:
-```go
-res, err := goreq.Request{
- Method: "POST",
- Uri: "http://www.google.com",
- Body: item,
- Compression: goreq.Deflate(),
-}.Do()
-```
-##### Using compressed responses:
-If servers replies a correct and matching `Content-Encoding` header (gzip requires `Content-Encoding: gzip` and deflate `Content-Encoding: deflate`) goreq transparently decompresses the response so the previous example should always work:
-```go
-type Item struct {
- Id int
- Name string
-}
-res, err := goreq.Request{
- Method: "POST",
- Uri: "http://www.google.com",
- Body: item,
- Compression: goreq.Gzip(),
-}.Do()
-var item Item
-res.Body.FromJsonTo(&item)
-```
-If no `Content-Encoding` header is replied by the server GoReq will return the crude response.
-
-## Proxy
-If you need to use a proxy for your requests GoReq supports the standard `http_proxy` env variable as well as manually setting the proxy for each request
-
-```go
-res, err := goreq.Request{
- Method: "GET",
- Proxy: "http://myproxy:myproxyport",
- Uri: "http://www.google.com",
-}.Do()
-```
-
-### Proxy basic auth is also supported
-
-```go
-res, err := goreq.Request{
- Method: "GET",
- Proxy: "http://user:pass@myproxy:myproxyport",
- Uri: "http://www.google.com",
-}.Do()
-```
-
-## Debug
-If you need to debug your http requests, it can print the http request detail.
-
-```go
-res, err := goreq.Request{
- Method: "GET",
- Uri: "http://www.google.com",
- Compression: goreq.Gzip(),
- ShowDebug: true,
-}.Do()
-fmt.Println(res, err)
-```
-
-and it will print the log:
-```
-GET / HTTP/1.1
-Host: www.google.com
-Accept:
-Accept-Encoding: gzip
-Content-Encoding: gzip
-Content-Type:
-```
-
-
-### Getting raw Request & Response
-
-To get the Request:
-
-```go
-req := goreq.Request{
- Host: "foobar.com",
-}
-
-//req.Request will return a new instance of an http.Request so you can safely use it for something else
-request, _ := req.NewRequest()
-
-```
-
-
-To get the Response:
-
-```go
-res, err := goreq.Request{
- Method: "GET",
- Uri: "http://www.google.com",
- Compression: goreq.Gzip(),
- ShowDebug: true,
-}.Do()
-
-// res.Response will contain the original http.Response structure
-fmt.Println(res.Response, err)
-```
-
-
-
-
-TODO:
------
-
-We do have a couple of [issues](https://github.com/franela/goreq/issues) pending we'll be addressing soon. But feel free to
-contribute and send us PRs (with tests please :smile:).
diff --git a/vendor/github.com/franela/goreq/goreq.go b/vendor/github.com/franela/goreq/goreq.go
deleted file mode 100644
index 801c7d307e5..00000000000
--- a/vendor/github.com/franela/goreq/goreq.go
+++ /dev/null
@@ -1,515 +0,0 @@
-package goreq
-
-import (
- "bufio"
- "bytes"
- "compress/gzip"
- "compress/zlib"
- "crypto/tls"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "net/http/httputil"
- "net/url"
- "reflect"
- "strings"
- "time"
-)
-
-type itimeout interface {
- Timeout() bool
-}
-type Request struct {
- headers []headerTuple
- cookies []*http.Cookie
- Method string
- Uri string
- Body interface{}
- QueryString interface{}
- Timeout time.Duration
- ContentType string
- Accept string
- Host string
- UserAgent string
- Insecure bool
- MaxRedirects int
- RedirectHeaders bool
- Proxy string
- proxyConnectHeaders []headerTuple
- Compression *compression
- BasicAuthUsername string
- BasicAuthPassword string
- CookieJar http.CookieJar
- ShowDebug bool
- OnBeforeRequest func(goreq *Request, httpreq *http.Request)
-}
-
-type compression struct {
- writer func(buffer io.Writer) (io.WriteCloser, error)
- reader func(buffer io.Reader) (io.ReadCloser, error)
- ContentEncoding string
-}
-
-type Response struct {
- *http.Response
- Uri string
- Body *Body
- req *http.Request
-}
-
-func (r Response) CancelRequest() {
- cancelRequest(DefaultTransport, r.req)
-
-}
-
-func cancelRequest(transport interface{}, r *http.Request) {
- if tp, ok := transport.(transportRequestCanceler); ok {
- tp.CancelRequest(r)
- }
-}
-
-type headerTuple struct {
- name string
- value string
-}
-
-type Body struct {
- reader io.ReadCloser
- compressedReader io.ReadCloser
-}
-
-type Error struct {
- timeout bool
- Err error
-}
-
-type transportRequestCanceler interface {
- CancelRequest(*http.Request)
-}
-
-func (e *Error) Timeout() bool {
- return e.timeout
-}
-
-func (e *Error) Error() string {
- return e.Err.Error()
-}
-
-func (b *Body) Read(p []byte) (int, error) {
- if b.compressedReader != nil {
- return b.compressedReader.Read(p)
- }
- return b.reader.Read(p)
-}
-
-func (b *Body) Close() error {
- err := b.reader.Close()
- if b.compressedReader != nil {
- return b.compressedReader.Close()
- }
- return err
-}
-
-func (b *Body) FromJsonTo(o interface{}) error {
- return json.NewDecoder(b).Decode(o)
-}
-
-func (b *Body) ToString() (string, error) {
- body, err := ioutil.ReadAll(b)
- if err != nil {
- return "", err
- }
- return string(body), nil
-}
-
-func Gzip() *compression {
- reader := func(buffer io.Reader) (io.ReadCloser, error) {
- return gzip.NewReader(buffer)
- }
- writer := func(buffer io.Writer) (io.WriteCloser, error) {
- return gzip.NewWriter(buffer), nil
- }
- return &compression{writer: writer, reader: reader, ContentEncoding: "gzip"}
-}
-
-func Deflate() *compression {
- reader := func(buffer io.Reader) (io.ReadCloser, error) {
- return zlib.NewReader(buffer)
- }
- writer := func(buffer io.Writer) (io.WriteCloser, error) {
- return zlib.NewWriter(buffer), nil
- }
- return &compression{writer: writer, reader: reader, ContentEncoding: "deflate"}
-}
-
-func Zlib() *compression {
- return Deflate()
-}
-
-func paramParse(query interface{}) (string, error) {
- switch query.(type) {
- case url.Values:
- return query.(url.Values).Encode(), nil
- case *url.Values:
- return query.(*url.Values).Encode(), nil
- default:
- var v = &url.Values{}
- err := paramParseStruct(v, query)
- return v.Encode(), err
- }
-}
-
-func paramParseStruct(v *url.Values, query interface{}) error {
- var (
- s = reflect.ValueOf(query)
- t = reflect.TypeOf(query)
- )
- for t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface {
- s = s.Elem()
- t = s.Type()
- }
-
- if t.Kind() != reflect.Struct {
- return errors.New("Can not parse QueryString.")
- }
-
- for i := 0; i < t.NumField(); i++ {
- var name string
-
- field := s.Field(i)
- typeField := t.Field(i)
-
- if !field.CanInterface() {
- continue
- }
-
- urlTag := typeField.Tag.Get("url")
- if urlTag == "-" {
- continue
- }
-
- name, opts := parseTag(urlTag)
-
- var omitEmpty, squash bool
- omitEmpty = opts.Contains("omitempty")
- squash = opts.Contains("squash")
-
- if squash {
- err := paramParseStruct(v, field.Interface())
- if err != nil {
- return err
- }
- continue
- }
-
- if urlTag == "" {
- name = strings.ToLower(typeField.Name)
- }
-
- if val := fmt.Sprintf("%v", field.Interface()); !(omitEmpty && len(val) == 0) {
- v.Add(name, val)
- }
- }
- return nil
-}
-
-func prepareRequestBody(b interface{}) (io.Reader, error) {
- switch b.(type) {
- case string:
- // treat is as text
- return strings.NewReader(b.(string)), nil
- case io.Reader:
- // treat is as text
- return b.(io.Reader), nil
- case []byte:
- //treat as byte array
- return bytes.NewReader(b.([]byte)), nil
- case nil:
- return nil, nil
- default:
- // try to jsonify it
- j, err := json.Marshal(b)
- if err == nil {
- return bytes.NewReader(j), nil
- }
- return nil, err
- }
-}
-
-var DefaultDialer = &net.Dialer{Timeout: 1000 * time.Millisecond}
-var DefaultTransport http.RoundTripper = &http.Transport{Dial: DefaultDialer.Dial, Proxy: http.ProxyFromEnvironment}
-var DefaultClient = &http.Client{Transport: DefaultTransport}
-
-var proxyTransport http.RoundTripper
-var proxyClient *http.Client
-
-func SetConnectTimeout(duration time.Duration) {
- DefaultDialer.Timeout = duration
-}
-
-func (r *Request) AddHeader(name string, value string) {
- if r.headers == nil {
- r.headers = []headerTuple{}
- }
- r.headers = append(r.headers, headerTuple{name: name, value: value})
-}
-
-func (r Request) WithHeader(name string, value string) Request {
- r.AddHeader(name, value)
- return r
-}
-
-func (r *Request) AddCookie(c *http.Cookie) {
- r.cookies = append(r.cookies, c)
-}
-
-func (r Request) WithCookie(c *http.Cookie) Request {
- r.AddCookie(c)
- return r
-}
-
-func (r *Request) AddProxyConnectHeader(name string, value string) {
- if r.proxyConnectHeaders == nil {
- r.proxyConnectHeaders = []headerTuple{}
- }
- r.proxyConnectHeaders = append(r.proxyConnectHeaders, headerTuple{name: name, value: value})
-}
-
-func (r Request) WithProxyConnectHeader(name string, value string) Request {
- r.AddProxyConnectHeader(name, value)
- return r
-}
-
-func (r Request) Do() (*Response, error) {
- var client = DefaultClient
- var transport = DefaultTransport
- var resUri string
- var redirectFailed bool
-
- r.Method = valueOrDefault(r.Method, "GET")
-
- // use a client with a cookie jar if necessary. We create a new client not
- // to modify the default one.
- if r.CookieJar != nil {
- client = &http.Client{
- Transport: transport,
- Jar: r.CookieJar,
- }
- }
-
- if r.Proxy != "" {
- proxyUrl, err := url.Parse(r.Proxy)
- if err != nil {
- // proxy address is in a wrong format
- return nil, &Error{Err: err}
- }
-
- proxyHeader := make(http.Header)
- if r.proxyConnectHeaders != nil {
- for _, header := range r.proxyConnectHeaders {
- proxyHeader.Add(header.name, header.value)
- }
- }
-
- //If jar is specified new client needs to be built
- if proxyTransport == nil || client.Jar != nil {
- proxyTransport = &http.Transport{
- Dial: DefaultDialer.Dial,
- Proxy: http.ProxyURL(proxyUrl),
- ProxyConnectHeader: proxyHeader,
- }
- proxyClient = &http.Client{Transport: proxyTransport, Jar: client.Jar}
- } else if proxyTransport, ok := proxyTransport.(*http.Transport); ok {
- proxyTransport.Proxy = http.ProxyURL(proxyUrl)
- proxyTransport.ProxyConnectHeader = proxyHeader
- }
- transport = proxyTransport
- client = proxyClient
- }
-
- client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
-
- if len(via) > r.MaxRedirects {
- redirectFailed = true
- return errors.New("Error redirecting. MaxRedirects reached")
- }
-
- resUri = req.URL.String()
-
- //By default Golang will not redirect request headers
- // https://code.google.com/p/go/issues/detail?id=4800&q=request%20header
- if r.RedirectHeaders {
- for key, val := range via[0].Header {
- req.Header[key] = val
- }
- }
- return nil
- }
-
- if transport, ok := transport.(*http.Transport); ok {
- if r.Insecure {
- if transport.TLSClientConfig != nil {
- transport.TLSClientConfig.InsecureSkipVerify = true
- } else {
- transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
- }
- } else if transport.TLSClientConfig != nil {
- // the default TLS client (when transport.TLSClientConfig==nil) is
- // already set to verify, so do nothing in that case
- transport.TLSClientConfig.InsecureSkipVerify = false
- }
- }
-
- req, err := r.NewRequest()
-
- if err != nil {
- // we couldn't parse the URL.
- return nil, &Error{Err: err}
- }
-
- timeout := false
- if r.Timeout > 0 {
- client.Timeout = r.Timeout
- }
-
- if r.ShowDebug {
- dump, err := httputil.DumpRequest(req, true)
- if err != nil {
- log.Println(err)
- }
- log.Println(string(dump))
- }
-
- if r.OnBeforeRequest != nil {
- r.OnBeforeRequest(&r, req)
- }
- res, err := client.Do(req)
-
- if err != nil {
- if !timeout {
- if t, ok := err.(itimeout); ok {
- timeout = t.Timeout()
- }
- if ue, ok := err.(*url.Error); ok {
- if t, ok := ue.Err.(itimeout); ok {
- timeout = t.Timeout()
- }
- }
- }
-
- var response *Response
- //If redirect fails we still want to return response data
- if redirectFailed {
- if res != nil {
- response = &Response{res, resUri, &Body{reader: res.Body}, req}
- } else {
- response = &Response{res, resUri, nil, req}
- }
- }
-
- //If redirect fails and we haven't set a redirect count we shouldn't return an error
- if redirectFailed && r.MaxRedirects == 0 {
- return response, nil
- }
-
- return response, &Error{timeout: timeout, Err: err}
- }
-
- if r.Compression != nil && strings.Contains(res.Header.Get("Content-Encoding"), r.Compression.ContentEncoding) {
- compressedReader, err := r.Compression.reader(res.Body)
- if err != nil {
- return nil, &Error{Err: err}
- }
- return &Response{res, resUri, &Body{reader: res.Body, compressedReader: compressedReader}, req}, nil
- }
-
- return &Response{res, resUri, &Body{reader: res.Body}, req}, nil
-}
-
-func (r Request) addHeaders(headersMap http.Header) {
- if len(r.UserAgent) > 0 {
- headersMap.Add("User-Agent", r.UserAgent)
- }
- if r.Accept != "" {
- headersMap.Add("Accept", r.Accept)
- }
- if r.ContentType != "" {
- headersMap.Add("Content-Type", r.ContentType)
- }
-}
-
-func (r Request) NewRequest() (*http.Request, error) {
-
- b, e := prepareRequestBody(r.Body)
- if e != nil {
- // there was a problem marshaling the body
- return nil, &Error{Err: e}
- }
-
- if r.QueryString != nil {
- param, e := paramParse(r.QueryString)
- if e != nil {
- return nil, &Error{Err: e}
- }
- r.Uri = r.Uri + "?" + param
- }
-
- var bodyReader io.Reader
- if b != nil && r.Compression != nil {
- buffer := bytes.NewBuffer([]byte{})
- readBuffer := bufio.NewReader(b)
- writer, err := r.Compression.writer(buffer)
- if err != nil {
- return nil, &Error{Err: err}
- }
- _, e = readBuffer.WriteTo(writer)
- writer.Close()
- if e != nil {
- return nil, &Error{Err: e}
- }
- bodyReader = buffer
- } else {
- bodyReader = b
- }
-
- req, err := http.NewRequest(r.Method, r.Uri, bodyReader)
- if err != nil {
- return nil, err
- }
- // add headers to the request
- req.Host = r.Host
-
- r.addHeaders(req.Header)
- if r.Compression != nil {
- req.Header.Add("Content-Encoding", r.Compression.ContentEncoding)
- req.Header.Add("Accept-Encoding", r.Compression.ContentEncoding)
- }
- if r.headers != nil {
- for _, header := range r.headers {
- req.Header.Add(header.name, header.value)
- }
- }
-
- //use basic auth if required
- if r.BasicAuthUsername != "" {
- req.SetBasicAuth(r.BasicAuthUsername, r.BasicAuthPassword)
- }
-
- for _, c := range r.cookies {
- req.AddCookie(c)
- }
- return req, nil
-}
-
-// Return value if nonempty, def otherwise.
-func valueOrDefault(value, def string) string {
- if value != "" {
- return value
- }
- return def
-}
diff --git a/vendor/github.com/franela/goreq/tags.go b/vendor/github.com/franela/goreq/tags.go
deleted file mode 100644
index f3c147e9a4b..00000000000
--- a/vendor/github.com/franela/goreq/tags.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found here: https://github.com/golang/go/blob/master/LICENSE
-
-package goreq
-
-import (
- "strings"
- "unicode"
-)
-
-// tagOptions is the string following a comma in a struct field's "json"
-// tag, or the empty string. It does not include the leading comma.
-type tagOptions string
-
-// parseTag splits a struct field's json tag into its name and
-// comma-separated options.
-func parseTag(tag string) (string, tagOptions) {
- if idx := strings.Index(tag, ","); idx != -1 {
- return tag[:idx], tagOptions(tag[idx+1:])
- }
- return tag, tagOptions("")
-}
-
-// Contains reports whether a comma-separated list of options
-// contains a particular substr flag. substr must be surrounded by a
-// string boundary or commas.
-func (o tagOptions) Contains(optionName string) bool {
- if len(o) == 0 {
- return false
- }
- s := string(o)
- for s != "" {
- var next string
- i := strings.Index(s, ",")
- if i >= 0 {
- s, next = s[:i], s[i+1:]
- }
- if s == optionName {
- return true
- }
- s = next
- }
- return false
-}
-
-func isValidTag(s string) bool {
- if s == "" {
- return false
- }
- for _, c := range s {
- switch {
- case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
- // Backslash and quote chars are reserved, but
- // otherwise any punctuation chars are allowed
- // in a tag name.
- default:
- if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
- return false
- }
- }
- }
- return true
-}
diff --git a/vendor/github.com/gemnasium/logrus-graylog-hook/.travis.yml b/vendor/github.com/gemnasium/logrus-graylog-hook/.travis.yml
deleted file mode 100644
index 9fe30e3cb9a..00000000000
--- a/vendor/github.com/gemnasium/logrus-graylog-hook/.travis.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-language: go
-go:
- - 1.4
- - 1.5
- - 1.6
- - 1.7
- - 1.8
- - 1.9
- - tip
-install:
- - mkdir -p $HOME/gopath/src/gopkg.in/gemnasium
- - mv $HOME/gopath/src/github.com/gemnasium/logrus-graylog-hook $HOME/gopath/src/gopkg.in/gemnasium/logrus-graylog-hook.v2
- - cd $HOME/gopath/src/gopkg.in/gemnasium/logrus-graylog-hook.v2
- - go get -t
diff --git a/vendor/github.com/gemnasium/logrus-graylog-hook/CHANGELOG.md b/vendor/github.com/gemnasium/logrus-graylog-hook/CHANGELOG.md
deleted file mode 100644
index fbe770db9c7..00000000000
--- a/vendor/github.com/gemnasium/logrus-graylog-hook/CHANGELOG.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Logrus Graylog hook
-
-## 2.0.7 - 2018-02-09
-
-* Fix reported levels to match syslog levels (@maxatome / #27)
-* Removed go 1.3 support
-
-## 2.0.6 - 2017-06-01
-
-* Update import logrus path. See https://github.com/sirupsen/logrus/pull/384
-
-## 2.0.5 - 2017-04-14
-
-* Support uncompressed messages (@yuancheng-p / #24)
-
-## 2.0.4 - 2017-02-19
-
-* Avoid panic if the hook can't dial Graylog (@chiffa-org / #21)
-
-## 2.0.3 - 2016-11-30
-
-* Add support for extracting stacktraces from errors (@flimzy / #19)
-* Allow specifying the host instead of taking `os.Hostname` by default (@mweibel / #18)
-
-## 2.0.2 - 2016-09-28
-
-* Get rid of github.com/SocialCodeInc/go-gelf/gelf (#14)
-
-## 2.0.1 - 2016-08-16
-
-* Fix an issue with entry constructor (#12)
-
-## 2.0.0 - 2016-07-02
-
-* Remove facility param in constructor, as it's an optional param in Graylog 2.0 (credits: @saward / #9)
-* Improve precision of TimeUnix (credits: @RaphYot / #2)
-* Expose Gelf Writer (we will make this an interface in later versions) (credits: @cha-won / #10)
-
-## 1.1.2 - 2016-06-03
-
-* Fix another race condition (credits: @dreyinger / #8)
-
-## 1.1.1 - 2016-05-10
-
-* Fix race condition (credits: @rschmukler / #6)
-
-## 1.1.0 - 2015-12-04
-
-* The default behavior is now to send the logs synchronously.
-* A new asynchronous hook is available through `NewAsyncGraylogHook`
-
-
diff --git a/vendor/github.com/gemnasium/logrus-graylog-hook/LICENSE b/vendor/github.com/gemnasium/logrus-graylog-hook/LICENSE
deleted file mode 100644
index a4282b2a1f2..00000000000
--- a/vendor/github.com/gemnasium/logrus-graylog-hook/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Gemnasium
-
-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.
diff --git a/vendor/github.com/gemnasium/logrus-graylog-hook/README.md b/vendor/github.com/gemnasium/logrus-graylog-hook/README.md
deleted file mode 100644
index 944cfd76623..00000000000
--- a/vendor/github.com/gemnasium/logrus-graylog-hook/README.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# Graylog Hook for [Logrus](https://github.com/sirupsen/logrus) [![Build Status](https://travis-ci.org/gemnasium/logrus-graylog-hook.svg?branch=master)](https://travis-ci.org/gemnasium/logrus-graylog-hook) [![godoc reference](https://godoc.org/github.com/gemnasium/logrus-graylog-hook?status.svg)](https://godoc.org/gopkg.in/gemnasium/logrus-graylog-hook.v2)
-
-Use this hook to send your logs to [Graylog](http://graylog2.org) server over UDP.
-The hook is non-blocking: even if UDP is used to send messages, the extra work
-should not block the logging function.
-
-All logrus fields will be sent as additional fields on Graylog.
-
-## Usage
-
-The hook must be configured with:
-
-* A Graylog GELF UDP address (a "ip:port" string).
-* an optional hash with extra global fields. These fields will be included in all messages sent to Graylog
-
-```go
-package main
-
-import (
- "log/syslog"
- log "github.com/sirupsen/logrus"
- "gopkg.in/gemnasium/logrus-graylog-hook.v2"
- )
-
-func main() {
- hook := graylog.NewGraylogHook(":", map[string]interface{}{"this": "is logged every time"})
- log.AddHook(hook)
- log.Info("some logging message")
-}
-```
-
-### Asynchronous logger
-
-```go
-package main
-
-import (
- "log/syslog"
- log "github.com/sirupsen/logrus"
- "gopkg.in/gemnasium/logrus-graylog-hook.v2"
- )
-
-func main() {
- hook := graylog.NewAsyncGraylogHook(":", map[string]interface{}{"this": "is logged every time"})
- defer hook.Flush()
- log.AddHook(hook)
- log.Info("some logging message")
-}
-```
-
-### Disable standard logging
-
-For some reason, you may want to disable logging on stdout, and keep only the messages in Graylog (ie: a webserver inside a docker container).
-You can redirect `stdout` to `/dev/null`, or just not log anything by creating a `NullFormatter` implementing `logrus.Formatter` interface:
-
-```go
-type NullFormatter struct {
-}
-
-// Don't spend time formatting logs
-func (NullFormatter) Format(e *log.Entry) ([]byte, error) {
- return []byte{}, nil
-}
-```
-
-And set this formatter as the new logging formatter:
-
-```go
-log.Infof("Log messages are now sent to Graylog (udp://%s)", graylogAddr) // Give a hint why logs are empty
-log.AddHook(graylog.NewGraylogHook(graylogAddr, "api", map[string]interface{}{})) // set graylogAddr accordingly
-log.SetFormatter(new(NullFormatter)) // Don't send logs to stdout
-```
diff --git a/vendor/github.com/gemnasium/logrus-graylog-hook/error.go b/vendor/github.com/gemnasium/logrus-graylog-hook/error.go
deleted file mode 100644
index 5d28124cd5b..00000000000
--- a/vendor/github.com/gemnasium/logrus-graylog-hook/error.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package graylog
-
-import (
- "encoding/json"
- "runtime"
-
- "github.com/pkg/errors"
-)
-
-// newMarshalableError builds an error which encodes its error message into JSON
-func newMarshalableError(err error) *marshalableError {
- return &marshalableError{err}
-}
-
-// a marshalableError is an error that can be encoded into JSON
-type marshalableError struct {
- err error
-}
-
-// MarshalJSON implements json.Marshaler for marshalableError
-func (m *marshalableError) MarshalJSON() ([]byte, error) {
- return json.Marshal(m.err.Error())
-}
-
-type causer interface {
- Cause() error
-}
-
-type stackTracer interface {
- StackTrace() errors.StackTrace
-}
-
-func extractStackTrace(err error) errors.StackTrace {
- var tracer stackTracer
- for {
- if st, ok := err.(stackTracer); ok {
- tracer = st
- }
- if cause, ok := err.(causer); ok {
- err = cause.Cause()
- continue
- }
- break
- }
- if tracer == nil {
- return nil
- }
- return tracer.StackTrace()
-}
-
-func extractFileAndLine(stacktrace errors.StackTrace) (string, int) {
- pc := uintptr(stacktrace[0])
- fn := runtime.FuncForPC(pc)
- return fn.FileLine(pc)
-}
diff --git a/vendor/github.com/gemnasium/logrus-graylog-hook/gelf_reader.go b/vendor/github.com/gemnasium/logrus-graylog-hook/gelf_reader.go
deleted file mode 100644
index 4b175f6911d..00000000000
--- a/vendor/github.com/gemnasium/logrus-graylog-hook/gelf_reader.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package graylog
-
-import (
- "bytes"
- "compress/gzip"
- "compress/zlib"
- "encoding/json"
- "fmt"
- "io"
- "net"
- "strings"
- "sync"
-)
-
-type Reader struct {
- mu sync.Mutex
- conn net.Conn
-}
-
-func NewReader(addr string) (*Reader, error) {
- var err error
- udpAddr, err := net.ResolveUDPAddr("udp", addr)
- if err != nil {
- return nil, fmt.Errorf("ResolveUDPAddr('%s'): %s", addr, err)
- }
-
- conn, err := net.ListenUDP("udp", udpAddr)
- if err != nil {
- return nil, fmt.Errorf("ListenUDP: %s", err)
- }
-
- r := new(Reader)
- r.conn = conn
- return r, nil
-}
-
-func (r *Reader) Addr() string {
- return r.conn.LocalAddr().String()
-}
-
-// FIXME: this will discard data if p isn't big enough to hold the
-// full message.
-func (r *Reader) Read(p []byte) (int, error) {
- msg, err := r.ReadMessage()
- if err != nil {
- return -1, err
- }
-
- var data string
-
- if msg.Full == "" {
- data = msg.Short
- } else {
- data = msg.Full
- }
-
- return strings.NewReader(data).Read(p)
-}
-
-func (r *Reader) ReadMessage() (*Message, error) {
- cBuf := make([]byte, ChunkSize)
- var (
- err error
- n, length int
- buf bytes.Buffer
- cid, ocid []byte
- seq, total uint8
- cHead []byte
- cReader io.Reader
- chunks [][]byte
- )
-
- for got := 0; got < 128 && (total == 0 || got < int(total)); got++ {
- if n, err = r.conn.Read(cBuf); err != nil {
- return nil, fmt.Errorf("Read: %s", err)
- }
- cHead, cBuf = cBuf[:2], cBuf[:n]
-
- if bytes.Equal(cHead, magicChunked) {
- //fmt.Printf("chunked %v\n", cBuf[:14])
- cid, seq, total = cBuf[2:2+8], cBuf[2+8], cBuf[2+8+1]
- if ocid != nil && !bytes.Equal(cid, ocid) {
- return nil, fmt.Errorf("out-of-band message %v (awaited %v)", cid, ocid)
- } else if ocid == nil {
- ocid = cid
- chunks = make([][]byte, total)
- }
- n = len(cBuf) - chunkedHeaderLen
- //fmt.Printf("setting chunks[%d]: %d\n", seq, n)
- chunks[seq] = append(make([]byte, 0, n), cBuf[chunkedHeaderLen:]...)
- length += n
- } else { //not chunked
- if total > 0 {
- return nil, fmt.Errorf("out-of-band message (not chunked)")
- }
- break
- }
- }
- //fmt.Printf("\nchunks: %v\n", chunks)
-
- if length > 0 {
- if cap(cBuf) < length {
- cBuf = append(cBuf, make([]byte, 0, length-cap(cBuf))...)
- }
- cBuf = cBuf[:0]
- for i := range chunks {
- //fmt.Printf("appending %d %v\n", i, chunks[i])
- cBuf = append(cBuf, chunks[i]...)
- }
- cHead = cBuf[:2]
- }
-
- // the data we get from the wire is compressed
- if bytes.Equal(cHead, magicGzip) {
- cReader, err = gzip.NewReader(bytes.NewReader(cBuf))
- } else if cHead[0] == magicZlib[0] &&
- (int(cHead[0])*256+int(cHead[1]))%31 == 0 {
- // zlib is slightly more complicated, but correct
- cReader, err = zlib.NewReader(bytes.NewReader(cBuf))
- } else {
- return nil, fmt.Errorf("unknown magic: %x %v", cHead, cHead)
- }
-
- if err != nil {
- return nil, fmt.Errorf("NewReader: %s", err)
- }
-
- if _, err = io.Copy(&buf, cReader); err != nil {
- return nil, fmt.Errorf("io.Copy: %s", err)
- }
-
- msg := new(Message)
- if err := json.Unmarshal(buf.Bytes(), &msg); err != nil {
- return nil, fmt.Errorf("json.Unmarshal: %s", err)
- }
-
- return msg, nil
-}
diff --git a/vendor/github.com/gemnasium/logrus-graylog-hook/gelf_writer.go b/vendor/github.com/gemnasium/logrus-graylog-hook/gelf_writer.go
deleted file mode 100644
index 3c3d3e21c53..00000000000
--- a/vendor/github.com/gemnasium/logrus-graylog-hook/gelf_writer.go
+++ /dev/null
@@ -1,339 +0,0 @@
-// Copyright 2012 SocialCode. All rights reserved.
-// Use of this source code is governed by the MIT
-// license that can be found in the LICENSE file.
-
-package graylog
-
-import (
- "bytes"
- "compress/flate"
- "compress/gzip"
- "compress/zlib"
- "crypto/rand"
- "encoding/json"
- "fmt"
- "io"
- "net"
- "os"
- "path"
- "sync"
- "time"
-)
-
-// Writer implements io.Writer and is used to send both discrete
-// messages to a graylog2 server, or data from a stream-oriented
-// interface (like the functions in log).
-type Writer struct {
- mu sync.Mutex
- conn net.Conn
- hostname string
- Facility string // defaults to current process name
- CompressionLevel int // one of the consts from compress/flate
- CompressionType CompressType
-}
-
-// What compression type the writer should use when sending messages
-// to the graylog2 server
-type CompressType int
-
-const (
- CompressGzip CompressType = iota
- CompressZlib
- NoCompress
-)
-
-// Message represents the contents of the GELF message. It is gzipped
-// before sending.
-type Message struct {
- Version string `json:"version"`
- Host string `json:"host"`
- Short string `json:"short_message"`
- Full string `json:"full_message"`
- TimeUnix float64 `json:"timestamp"`
- Level int32 `json:"level"`
- Facility string `json:"facility"`
- File string `json:"file"`
- Line int `json:"line"`
- Extra map[string]interface{} `json:"-"`
-}
-
-type innerMessage Message //against circular (Un)MarshalJSON
-
-// Used to control GELF chunking. Should be less than (MTU - len(UDP
-// header)).
-//
-// TODO: generate dynamically using Path MTU Discovery?
-const (
- ChunkSize = 1420
- chunkedHeaderLen = 12
- chunkedDataLen = ChunkSize - chunkedHeaderLen
-)
-
-var (
- magicChunked = []byte{0x1e, 0x0f}
- magicZlib = []byte{0x78}
- magicGzip = []byte{0x1f, 0x8b}
-)
-
-// numChunks returns the number of GELF chunks necessary to transmit
-// the given compressed buffer.
-func numChunks(b []byte) int {
- lenB := len(b)
- if lenB <= ChunkSize {
- return 1
- }
- return len(b)/chunkedDataLen + 1
-}
-
-// New returns a new GELF Writer. This writer can be used to send the
-// output of the standard Go log functions to a central GELF server by
-// passing it to log.SetOutput()
-func NewWriter(addr string) (*Writer, error) {
- var err error
- w := new(Writer)
- w.CompressionLevel = flate.BestSpeed
-
- if w.conn, err = net.Dial("udp", addr); err != nil {
- return nil, err
- }
- if w.hostname, err = os.Hostname(); err != nil {
- return nil, err
- }
-
- w.Facility = path.Base(os.Args[0])
-
- return w, nil
-}
-
-// writes the gzip compressed byte array to the connection as a series
-// of GELF chunked messages. The header format is documented at
-// https://github.com/Graylog2/graylog2-docs/wiki/GELF as:
-//
-// 2-byte magic (0x1e 0x0f), 8 byte id, 1 byte sequence id, 1 byte
-// total, chunk-data
-func (w *Writer) writeChunked(zBytes []byte) (err error) {
- b := make([]byte, 0, ChunkSize)
- buf := bytes.NewBuffer(b)
- nChunksI := numChunks(zBytes)
- if nChunksI > 255 {
- return fmt.Errorf("msg too large, would need %d chunks", nChunksI)
- }
- nChunks := uint8(nChunksI)
- // use urandom to get a unique message id
- msgId := make([]byte, 8)
- n, err := io.ReadFull(rand.Reader, msgId)
- if err != nil || n != 8 {
- return fmt.Errorf("rand.Reader: %d/%s", n, err)
- }
-
- bytesLeft := len(zBytes)
- for i := uint8(0); i < nChunks; i++ {
- buf.Reset()
- // manually write header. Don't care about
- // host/network byte order, because the spec only
- // deals in individual bytes.
- buf.Write(magicChunked) //magic
- buf.Write(msgId)
- buf.WriteByte(i)
- buf.WriteByte(nChunks)
- // slice out our chunk from zBytes
- chunkLen := chunkedDataLen
- if chunkLen > bytesLeft {
- chunkLen = bytesLeft
- }
- off := int(i) * chunkedDataLen
- chunk := zBytes[off : off+chunkLen]
- buf.Write(chunk)
-
- // write this chunk, and make sure the write was good
- n, err := w.conn.Write(buf.Bytes())
- if err != nil {
- return fmt.Errorf("Write (chunk %d/%d): %s", i,
- nChunks, err)
- }
- if n != len(buf.Bytes()) {
- return fmt.Errorf("Write len: (chunk %d/%d) (%d/%d)",
- i, nChunks, n, len(buf.Bytes()))
- }
-
- bytesLeft -= chunkLen
- }
-
- if bytesLeft != 0 {
- return fmt.Errorf("error: %d bytes left after sending", bytesLeft)
- }
- return nil
-}
-
-type bufferedWriter struct {
- buffer *bytes.Buffer
-}
-
-func (bw bufferedWriter) Write(p []byte) (n int, err error) {
- return bw.buffer.Write(p)
-}
-
-func (bw bufferedWriter) Close() error {
- return nil
-}
-
-// WriteMessage sends the specified message to the GELF server
-// specified in the call to New(). It assumes all the fields are
-// filled out appropriately. In general, clients will want to use
-// Write, rather than WriteMessage.
-func (w *Writer) WriteMessage(m *Message) (err error) {
- mBytes, err := json.Marshal(m)
- if err != nil {
- return
- }
-
- var zBuf bytes.Buffer
- var zw io.WriteCloser
- switch w.CompressionType {
- case CompressGzip:
- zw, err = gzip.NewWriterLevel(&zBuf, w.CompressionLevel)
- case CompressZlib:
- zw, err = zlib.NewWriterLevel(&zBuf, w.CompressionLevel)
- case NoCompress:
- zw = bufferedWriter{buffer: &zBuf}
- default:
- panic(fmt.Sprintf("unknown compression type %d",
- w.CompressionType))
- }
- if err != nil {
- return
- }
- if _, err = zw.Write(mBytes); err != nil {
- return
- }
- zw.Close()
-
- zBytes := zBuf.Bytes()
- if numChunks(zBytes) > 1 {
- return w.writeChunked(zBytes)
- }
-
- n, err := w.conn.Write(zBytes)
- if err != nil {
- return
- }
- if n != len(zBytes) {
- return fmt.Errorf("bad write (%d/%d)", n, len(zBytes))
- }
-
- return nil
-}
-
-/*
-func (w *Writer) Alert(m string) (err error)
-func (w *Writer) Close() error
-func (w *Writer) Crit(m string) (err error)
-func (w *Writer) Debug(m string) (err error)
-func (w *Writer) Emerg(m string) (err error)
-func (w *Writer) Err(m string) (err error)
-func (w *Writer) Info(m string) (err error)
-func (w *Writer) Notice(m string) (err error)
-func (w *Writer) Warning(m string) (err error)
-*/
-
-// Write encodes the given string in a GELF message and sends it to
-// the server specified in New().
-func (w *Writer) Write(p []byte) (n int, err error) {
-
- // 1 for the function that called us.
- file, line := getCallerIgnoringLogMulti(1)
-
- // remove trailing and leading whitespace
- p = bytes.TrimSpace(p)
-
- // If there are newlines in the message, use the first line
- // for the short message and set the full message to the
- // original input. If the input has no newlines, stick the
- // whole thing in Short.
- short := p
- full := []byte("")
- if i := bytes.IndexRune(p, '\n'); i > 0 {
- short = p[:i]
- full = p
- }
-
- m := Message{
- Version: "1.0",
- Host: w.hostname,
- Short: string(short),
- Full: string(full),
- TimeUnix: float64(time.Now().UnixNano()/1000000) / 1000.,
- Level: 6, // info
- Facility: w.Facility,
- File: file,
- Line: line,
- Extra: map[string]interface{}{},
- }
-
- if err = w.WriteMessage(&m); err != nil {
- return 0, err
- }
-
- return len(p), nil
-}
-
-func (m *Message) MarshalJSON() ([]byte, error) {
- var err error
- var b, eb []byte
-
- extra := m.Extra
- b, err = json.Marshal((*innerMessage)(m))
- m.Extra = extra
- if err != nil {
- return nil, err
- }
-
- if len(extra) == 0 {
- return b, nil
- }
-
- if eb, err = json.Marshal(extra); err != nil {
- return nil, err
- }
-
- // merge serialized message + serialized extra map
- b[len(b)-1] = ','
- return append(b, eb[1:len(eb)]...), nil
-}
-
-func (m *Message) UnmarshalJSON(data []byte) error {
- i := make(map[string]interface{}, 16)
- if err := json.Unmarshal(data, &i); err != nil {
- return err
- }
- for k, v := range i {
- if k[0] == '_' {
- if m.Extra == nil {
- m.Extra = make(map[string]interface{}, 1)
- }
- m.Extra[k] = v
- continue
- }
- switch k {
- case "version":
- m.Version = v.(string)
- case "host":
- m.Host = v.(string)
- case "short_message":
- m.Short = v.(string)
- case "full_message":
- m.Full = v.(string)
- case "timestamp":
- m.TimeUnix = v.(float64)
- case "level":
- m.Level = int32(v.(float64))
- case "facility":
- m.Facility = v.(string)
- case "file":
- m.File = v.(string)
- case "line":
- m.Line = int(v.(float64))
- }
- }
- return nil
-}
diff --git a/vendor/github.com/gemnasium/logrus-graylog-hook/graylog_hook.go b/vendor/github.com/gemnasium/logrus-graylog-hook/graylog_hook.go
deleted file mode 100644
index 8dcda5d5161..00000000000
--- a/vendor/github.com/gemnasium/logrus-graylog-hook/graylog_hook.go
+++ /dev/null
@@ -1,295 +0,0 @@
-package graylog
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "fmt"
- "os"
- "runtime"
- "strings"
- "sync"
- "time"
-
- "github.com/sirupsen/logrus"
-)
-
-const StackTraceKey = "_stacktrace"
-
-// Set graylog.BufSize = _before_ calling NewGraylogHook
-// Once the buffer is full, logging will start blocking, waiting for slots to
-// be available in the queue.
-var BufSize uint = 8192
-
-// GraylogHook to send logs to a logging service compatible with the Graylog API and the GELF format.
-type GraylogHook struct {
- Extra map[string]interface{}
- Host string
- Level logrus.Level
- gelfLogger *Writer
- buf chan graylogEntry
- wg sync.WaitGroup
- mu sync.RWMutex
- synchronous bool
- blacklist map[string]bool
-}
-
-// Graylog needs file and line params
-type graylogEntry struct {
- *logrus.Entry
- file string
- line int
-}
-
-// NewGraylogHook creates a hook to be added to an instance of logger.
-func NewGraylogHook(addr string, extra map[string]interface{}) *GraylogHook {
- g, err := NewWriter(addr)
- if err != nil {
- logrus.WithError(err).Error("Can't create Gelf logger")
- }
-
- host, err := os.Hostname()
- if err != nil {
- host = "localhost"
- }
-
- hook := &GraylogHook{
- Host: host,
- Extra: extra,
- Level: logrus.DebugLevel,
- gelfLogger: g,
- synchronous: true,
- }
- return hook
-}
-
-// NewAsyncGraylogHook creates a hook to be added to an instance of logger.
-// The hook created will be asynchronous, and it's the responsibility of the user to call the Flush method
-// before exiting to empty the log queue.
-func NewAsyncGraylogHook(addr string, extra map[string]interface{}) *GraylogHook {
- g, err := NewWriter(addr)
- if err != nil {
- logrus.WithError(err).Error("Can't create Gelf logger")
- }
-
- host, err := os.Hostname()
- if err != nil {
- host = "localhost"
- }
-
- hook := &GraylogHook{
- Host: host,
- Extra: extra,
- Level: logrus.DebugLevel,
- gelfLogger: g,
- buf: make(chan graylogEntry, BufSize),
- }
- go hook.fire() // Log in background
- return hook
-}
-
-// Fire is called when a log event is fired.
-// We assume the entry will be altered by another hook,
-// otherwise we might logging something wrong to Graylog
-func (hook *GraylogHook) Fire(entry *logrus.Entry) error {
- hook.mu.RLock() // Claim the mutex as a RLock - allowing multiple go routines to log simultaneously
- defer hook.mu.RUnlock()
-
- // get caller file and line here, it won't be available inside the goroutine
- // 1 for the function that called us.
- file, line := getCallerIgnoringLogMulti(1)
-
- newData := make(map[string]interface{})
- for k, v := range entry.Data {
- newData[k] = v
- }
-
- newEntry := &logrus.Entry{
- Logger: entry.Logger,
- Data: newData,
- Time: entry.Time,
- Level: entry.Level,
- Message: entry.Message,
- }
- gEntry := graylogEntry{newEntry, file, line}
-
- if hook.synchronous {
- hook.sendEntry(gEntry)
- } else {
- hook.wg.Add(1)
- hook.buf <- gEntry
- }
-
- return nil
-}
-
-// Flush waits for the log queue to be empty.
-// This func is meant to be used when the hook was created with NewAsyncGraylogHook.
-func (hook *GraylogHook) Flush() {
- hook.mu.Lock() // claim the mutex as a Lock - we want exclusive access to it
- defer hook.mu.Unlock()
-
- hook.wg.Wait()
-}
-
-// fire will loop on the 'buf' channel, and write entries to graylog
-func (hook *GraylogHook) fire() {
- for {
- entry := <-hook.buf // receive new entry on channel
- hook.sendEntry(entry)
- hook.wg.Done()
- }
-}
-
-func logrusLevelToSylog(level logrus.Level) int32 {
- // Till warn, logrus levels are lower than syslog by 1
- // (logrus has no equivalent of syslog LOG_NOTICE)
- if level <= logrus.WarnLevel {
- return int32(level) + 1
- }
- // From info, logrus levels are lower than syslog by 2
- return int32(level) + 2
-}
-
-// sendEntry sends an entry to graylog synchronously
-func (hook *GraylogHook) sendEntry(entry graylogEntry) {
- if hook.gelfLogger == nil {
- fmt.Println("Can't connect to Graylog")
- return
- }
- w := hook.gelfLogger
-
- // remove trailing and leading whitespace
- p := bytes.TrimSpace([]byte(entry.Message))
-
- // If there are newlines in the message, use the first line
- // for the short message and set the full message to the
- // original input. If the input has no newlines, stick the
- // whole thing in Short.
- short := p
- full := []byte("")
- if i := bytes.IndexRune(p, '\n'); i > 0 {
- short = p[:i]
- full = p
- }
-
- level := logrusLevelToSylog(entry.Level)
-
- // Don't modify entry.Data directly, as the entry will used after this hook was fired
- extra := map[string]interface{}{}
- // Merge extra fields
- for k, v := range hook.Extra {
- k = fmt.Sprintf("_%s", k) // "[...] every field you send and prefix with a _ (underscore) will be treated as an additional field."
- extra[k] = v
- }
- for k, v := range entry.Data {
- if !hook.blacklist[k] {
- extraK := fmt.Sprintf("_%s", k) // "[...] every field you send and prefix with a _ (underscore) will be treated as an additional field."
- if k == logrus.ErrorKey {
- asError, isError := v.(error)
- _, isMarshaler := v.(json.Marshaler)
- if isError && !isMarshaler {
- extra[extraK] = newMarshalableError(asError)
- } else {
- extra[extraK] = v
- }
- if stackTrace := extractStackTrace(asError); stackTrace != nil {
- extra[StackTraceKey] = fmt.Sprintf("%+v", stackTrace)
- file, line := extractFileAndLine(stackTrace)
- if file != "" && line != 0 {
- entry.file = file
- entry.line = line
- }
- }
- } else {
- extra[extraK] = v
- }
- }
- }
-
- m := Message{
- Version: "1.1",
- Host: hook.Host,
- Short: string(short),
- Full: string(full),
- TimeUnix: float64(time.Now().UnixNano()/1000000) / 1000.,
- Level: level,
- File: entry.file,
- Line: entry.line,
- Extra: extra,
- }
-
- if err := w.WriteMessage(&m); err != nil {
- fmt.Println(err)
- }
-}
-
-// Levels returns the available logging levels.
-func (hook *GraylogHook) Levels() []logrus.Level {
- levels := []logrus.Level{}
- for _, level := range logrus.AllLevels {
- if level <= hook.Level {
- levels = append(levels, level)
- }
- }
- return levels
-}
-
-// Blacklist create a blacklist map to filter some message keys.
-// This useful when you want your application to log extra fields locally
-// but don't want graylog to store them.
-func (hook *GraylogHook) Blacklist(b []string) {
- hook.blacklist = make(map[string]bool)
- for _, elem := range b {
- hook.blacklist[elem] = true
- }
-}
-
-// SetWriter sets the hook Gelf Writer
-func (hook *GraylogHook) SetWriter(w *Writer) error {
- if w == nil {
- return errors.New("writer can't be nil")
- }
- hook.gelfLogger = w
- return nil
-}
-
-// Writer returns the logger Gelf Writer
-func (hook *GraylogHook) Writer() *Writer {
- return hook.gelfLogger
-}
-
-// getCaller returns the filename and the line info of a function
-// further down in the call stack. Passing 0 in as callDepth would
-// return info on the function calling getCallerIgnoringLog, 1 the
-// parent function, and so on. Any suffixes passed to getCaller are
-// path fragments like "/pkg/log/log.go", and functions in the call
-// stack from that file are ignored.
-func getCaller(callDepth int, suffixesToIgnore ...string) (file string, line int) {
- // bump by 1 to ignore the getCaller (this) stackframe
- callDepth++
-outer:
- for {
- var ok bool
- _, file, line, ok = runtime.Caller(callDepth)
- if !ok {
- file = "???"
- line = 0
- break
- }
-
- for _, s := range suffixesToIgnore {
- if strings.HasSuffix(file, s) {
- callDepth++
- continue outer
- }
- }
- break
- }
- return
-}
-
-func getCallerIgnoringLogMulti(callDepth int) (string, int) {
- // the +1 is to ignore this (getCallerIgnoringLogMulti) frame
- return getCaller(callDepth+1, "logrus/hooks.go", "logrus/entry.go", "logrus/logger.go", "logrus/exported.go", "asm_amd64.s")
-}
diff --git a/vendor/github.com/getsentry/raven-go/.dockerignore b/vendor/github.com/getsentry/raven-go/.dockerignore
deleted file mode 100644
index 6b8710a711f..00000000000
--- a/vendor/github.com/getsentry/raven-go/.dockerignore
+++ /dev/null
@@ -1 +0,0 @@
-.git
diff --git a/vendor/github.com/getsentry/raven-go/.gitignore b/vendor/github.com/getsentry/raven-go/.gitignore
deleted file mode 100644
index 0f66ce75dc9..00000000000
--- a/vendor/github.com/getsentry/raven-go/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*.test
-*.out
-example/example
-/xunit.xml
-/coverage.xml
diff --git a/vendor/github.com/getsentry/raven-go/.gitmodules b/vendor/github.com/getsentry/raven-go/.gitmodules
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/vendor/github.com/getsentry/raven-go/.travis.yml b/vendor/github.com/getsentry/raven-go/.travis.yml
deleted file mode 100644
index 8ec4eca8109..00000000000
--- a/vendor/github.com/getsentry/raven-go/.travis.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-sudo: false
-language: go
-go:
- - 1.7.x
- - 1.8.x
- - 1.9.x
- - 1.10.x
- - 1.11.x
- - tip
-
-before_install:
- - go install -race std
- - go get golang.org/x/tools/cmd/cover
- - go get github.com/tebeka/go2xunit
- - go get github.com/t-yuki/gocover-cobertura
- - go get -v ./...
-
-script:
- - go test -v -race ./... | tee gotest.out
- - $GOPATH/bin/go2xunit -fail -input gotest.out -output xunit.xml
- - go test -v -coverprofile=coverage.txt -covermode count .
- - $GOPATH/bin/gocover-cobertura < coverage.txt > coverage.xml
-
-after_script:
- - npm install -g @zeus-ci/cli
- - zeus upload -t "application/x-cobertura+xml" coverage.xml
- - zeus upload -t "application/x-xunit+xml" xunit.xml
-
-matrix:
- allow_failures:
- - go: tip
-
-notifications:
- webhooks:
- urls:
- - https://zeus.ci/hooks/cd949996-d30a-11e8-ba53-0a580a28042d/public/provider/travis/webhook
- on_success: always
- on_failure: always
- on_start: always
- on_cancel: always
- on_error: always
diff --git a/vendor/github.com/getsentry/raven-go/LICENSE b/vendor/github.com/getsentry/raven-go/LICENSE
deleted file mode 100644
index b0301b57e8a..00000000000
--- a/vendor/github.com/getsentry/raven-go/LICENSE
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright (c) 2013 Apollic Software, LLC. All rights reserved.
-Copyright (c) 2015 Functional Software, Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Apollic Software, LLC nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/getsentry/raven-go/README.md b/vendor/github.com/getsentry/raven-go/README.md
deleted file mode 100644
index 16c9483e8a2..00000000000
--- a/vendor/github.com/getsentry/raven-go/README.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# raven
-
-[![Build Status](https://api.travis-ci.org/getsentry/raven-go.svg?branch=master)](https://travis-ci.org/getsentry/raven-go)
-[![Go Report Card](https://goreportcard.com/badge/github.com/getsentry/raven-go)](https://goreportcard.com/report/github.com/getsentry/raven-go)
-[![GoDoc](https://godoc.org/github.com/getsentry/raven-go?status.svg)](https://godoc.org/github.com/getsentry/raven-go)
-
-raven is the official Go SDK for the [Sentry](https://github.com/getsentry/sentry)
-event/error logging system.
-
-- [**API Documentation**](https://godoc.org/github.com/getsentry/raven-go)
-- [**Usage and Examples**](https://docs.sentry.io/clients/go/)
-
-## Installation
-
-```text
-go get github.com/getsentry/raven-go
-```
-
-Note: Go 1.7 and newer are supported.
diff --git a/vendor/github.com/getsentry/raven-go/client.go b/vendor/github.com/getsentry/raven-go/client.go
deleted file mode 100644
index a2c9a6c35d2..00000000000
--- a/vendor/github.com/getsentry/raven-go/client.go
+++ /dev/null
@@ -1,977 +0,0 @@
-// Package raven implements a client for the Sentry error logging service.
-package raven
-
-import (
- "bytes"
- "compress/zlib"
- "crypto/rand"
- "crypto/tls"
- "encoding/base64"
- "encoding/hex"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- mrand "math/rand"
- "net/http"
- "net/url"
- "os"
- "regexp"
- "runtime"
- "strings"
- "sync"
- "time"
-
- "github.com/certifi/gocertifi"
- pkgErrors "github.com/pkg/errors"
-)
-
-const (
- userAgent = "raven-go/1.0"
- timestampFormat = `"2006-01-02T15:04:05.00"`
-)
-
-var (
- ErrPacketDropped = errors.New("raven: packet dropped")
- ErrUnableToUnmarshalJSON = errors.New("raven: unable to unmarshal JSON")
- ErrMissingUser = errors.New("raven: dsn missing public key and/or password")
- ErrMissingProjectID = errors.New("raven: dsn missing project id")
- ErrInvalidSampleRate = errors.New("raven: sample rate should be between 0 and 1")
-)
-
-type Severity string
-
-// http://docs.python.org/2/howto/logging.html#logging-levels
-const (
- DEBUG = Severity("debug")
- INFO = Severity("info")
- WARNING = Severity("warning")
- ERROR = Severity("error")
- FATAL = Severity("fatal")
-)
-
-type Timestamp time.Time
-
-func (t Timestamp) MarshalJSON() ([]byte, error) {
- return []byte(time.Time(t).UTC().Format(timestampFormat)), nil
-}
-
-func (timestamp *Timestamp) UnmarshalJSON(data []byte) error {
- t, err := time.Parse(timestampFormat, string(data))
- if err != nil {
- return err
- }
-
- *timestamp = Timestamp(t)
- return nil
-}
-
-func (timestamp Timestamp) Format(format string) string {
- t := time.Time(timestamp)
- return t.Format(format)
-}
-
-// An Interface is a Sentry interface that will be serialized as JSON.
-// It must implement json.Marshaler or use json struct tags.
-type Interface interface {
- // The Sentry class name. Example: sentry.interfaces.Stacktrace
- Class() string
-}
-
-type Culpriter interface {
- Culprit() string
-}
-
-type Transport interface {
- Send(url, authHeader string, packet *Packet) error
-}
-
-type Extra map[string]interface{}
-
-type outgoingPacket struct {
- packet *Packet
- ch chan error
-}
-
-type Tag struct {
- Key string
- Value string
-}
-
-type Tags []Tag
-
-func (tag *Tag) MarshalJSON() ([]byte, error) {
- return json.Marshal([2]string{tag.Key, tag.Value})
-}
-
-func (t *Tag) UnmarshalJSON(data []byte) error {
- var tag [2]string
- if err := json.Unmarshal(data, &tag); err != nil {
- return err
- }
- *t = Tag{tag[0], tag[1]}
- return nil
-}
-
-func (t *Tags) UnmarshalJSON(data []byte) error {
- var tags []Tag
-
- switch data[0] {
- case '[':
- // Unmarshal into []Tag
- if err := json.Unmarshal(data, &tags); err != nil {
- return err
- }
- case '{':
- // Unmarshal into map[string]string
- tagMap := make(map[string]string)
- if err := json.Unmarshal(data, &tagMap); err != nil {
- return err
- }
-
- // Convert to []Tag
- for k, v := range tagMap {
- tags = append(tags, Tag{k, v})
- }
- default:
- return ErrUnableToUnmarshalJSON
- }
-
- *t = tags
- return nil
-}
-
-// https://docs.getsentry.com/hosted/clientdev/#building-the-json-packet
-type Packet struct {
- // Required
- Message string `json:"message"`
-
- // Required, set automatically by Client.Send/Report via Packet.Init if blank
- EventID string `json:"event_id"`
- Project string `json:"project"`
- Timestamp Timestamp `json:"timestamp"`
- Level Severity `json:"level"`
- Logger string `json:"logger"`
-
- // Optional
- Platform string `json:"platform,omitempty"`
- Culprit string `json:"culprit,omitempty"`
- ServerName string `json:"server_name,omitempty"`
- Release string `json:"release,omitempty"`
- Environment string `json:"environment,omitempty"`
- Tags Tags `json:"tags,omitempty"`
- Modules map[string]string `json:"modules,omitempty"`
- Fingerprint []string `json:"fingerprint,omitempty"`
- Extra Extra `json:"extra,omitempty"`
-
- Interfaces []Interface `json:"-"`
-}
-
-// NewPacket constructs a packet with the specified message and interfaces.
-func NewPacket(message string, interfaces ...Interface) *Packet {
- extra := Extra{}
- setExtraDefaults(extra)
- return &Packet{
- Message: message,
- Interfaces: interfaces,
- Extra: extra,
- }
-}
-
-// NewPacketWithExtra constructs a packet with the specified message, extra information, and interfaces.
-func NewPacketWithExtra(message string, extra Extra, interfaces ...Interface) *Packet {
- if extra == nil {
- extra = Extra{}
- }
- setExtraDefaults(extra)
-
- return &Packet{
- Message: message,
- Interfaces: interfaces,
- Extra: extra,
- }
-}
-
-func setExtraDefaults(extra Extra) Extra {
- extra["runtime.Version"] = runtime.Version()
- extra["runtime.NumCPU"] = runtime.NumCPU()
- extra["runtime.GOMAXPROCS"] = runtime.GOMAXPROCS(0) // 0 just returns the current value
- extra["runtime.NumGoroutine"] = runtime.NumGoroutine()
- return extra
-}
-
-// Init initializes required fields in a packet. It is typically called by
-// Client.Send/Report automatically.
-func (packet *Packet) Init(project string) error {
- if packet.Project == "" {
- packet.Project = project
- }
- if packet.EventID == "" {
- var err error
- packet.EventID, err = uuid()
- if err != nil {
- return err
- }
- }
- if time.Time(packet.Timestamp).IsZero() {
- packet.Timestamp = Timestamp(time.Now())
- }
- if packet.Level == "" {
- packet.Level = ERROR
- }
- if packet.Logger == "" {
- packet.Logger = "root"
- }
- if packet.ServerName == "" {
- packet.ServerName = hostname
- }
- if packet.Platform == "" {
- packet.Platform = "go"
- }
-
- if packet.Culprit == "" {
- for _, inter := range packet.Interfaces {
- if c, ok := inter.(Culpriter); ok {
- packet.Culprit = c.Culprit()
- if packet.Culprit != "" {
- break
- }
- }
- }
- }
-
- return nil
-}
-
-func (packet *Packet) AddTags(tags map[string]string) {
- for k, v := range tags {
- packet.Tags = append(packet.Tags, Tag{k, v})
- }
-}
-
-func uuid() (string, error) {
- id := make([]byte, 16)
- _, err := io.ReadFull(rand.Reader, id)
- if err != nil {
- return "", err
- }
- id[6] &= 0x0F // clear version
- id[6] |= 0x40 // set version to 4 (random uuid)
- id[8] &= 0x3F // clear variant
- id[8] |= 0x80 // set to IETF variant
- return hex.EncodeToString(id), nil
-}
-
-func (packet *Packet) JSON() ([]byte, error) {
- packetJSON, err := json.Marshal(packet)
- if err != nil {
- return nil, err
- }
-
- interfaces := make(map[string]Interface, len(packet.Interfaces))
- for _, inter := range packet.Interfaces {
- if inter != nil {
- interfaces[inter.Class()] = inter
- }
- }
-
- if len(interfaces) > 0 {
- interfaceJSON, err := json.Marshal(interfaces)
- if err != nil {
- return nil, err
- }
- packetJSON[len(packetJSON)-1] = ','
- packetJSON = append(packetJSON, interfaceJSON[1:]...)
- }
-
- return packetJSON, nil
-}
-
-type context struct {
- user *User
- http *Http
- tags map[string]string
-}
-
-func (c *context) setUser(u *User) { c.user = u }
-func (c *context) setHttp(h *Http) { c.http = h }
-func (c *context) setTags(t map[string]string) {
- if c.tags == nil {
- c.tags = make(map[string]string)
- }
- for k, v := range t {
- c.tags[k] = v
- }
-}
-func (c *context) clear() {
- c.user = nil
- c.http = nil
- c.tags = nil
-}
-
-// Return a list of interfaces to be used in appending with the rest
-func (c *context) interfaces() []Interface {
- len, i := 0, 0
- if c.user != nil {
- len++
- }
- if c.http != nil {
- len++
- }
- interfaces := make([]Interface, len)
- if c.user != nil {
- interfaces[i] = c.user
- i++
- }
- if c.http != nil {
- interfaces[i] = c.http
- i++
- }
- return interfaces
-}
-
-// The maximum number of packets that will be buffered waiting to be delivered.
-// Packets will be dropped if the buffer is full. Used by NewClient.
-var MaxQueueBuffer = 100
-
-func newTransport() Transport {
- t := &HTTPTransport{}
- rootCAs, err := gocertifi.CACerts()
- if err != nil {
- log.Println("raven: failed to load root TLS certificates:", err)
- } else {
- t.Client = &http.Client{
- Transport: &http.Transport{
- Proxy: http.ProxyFromEnvironment,
- TLSClientConfig: &tls.Config{RootCAs: rootCAs},
- },
- }
- }
- return t
-}
-
-func newClient(tags map[string]string) *Client {
- client := &Client{
- Transport: newTransport(),
- Tags: tags,
- context: &context{},
- sampleRate: 1.0,
- queue: make(chan *outgoingPacket, MaxQueueBuffer),
- }
- client.SetDSN(os.Getenv("SENTRY_DSN"))
- client.SetRelease(os.Getenv("SENTRY_RELEASE"))
- client.SetEnvironment(os.Getenv("SENTRY_ENVIRONMENT"))
- return client
-}
-
-// New constructs a new Sentry client instance
-func New(dsn string) (*Client, error) {
- client := newClient(nil)
- return client, client.SetDSN(dsn)
-}
-
-// NewWithTags constructs a new Sentry client instance with default tags.
-func NewWithTags(dsn string, tags map[string]string) (*Client, error) {
- client := newClient(tags)
- return client, client.SetDSN(dsn)
-}
-
-// NewClient constructs a Sentry client and spawns a background goroutine to
-// handle packets sent by Client.Report.
-//
-// Deprecated: use New and NewWithTags instead
-func NewClient(dsn string, tags map[string]string) (*Client, error) {
- client := newClient(tags)
- return client, client.SetDSN(dsn)
-}
-
-// Client encapsulates a connection to a Sentry server. It must be initialized
-// by calling NewClient. Modification of fields concurrently with Send or after
-// calling Report for the first time is not thread-safe.
-type Client struct {
- Tags map[string]string
-
- Transport Transport
-
- // DropHandler is called when a packet is dropped because the buffer is full.
- DropHandler func(*Packet)
-
- // Context that will get appending to all packets
- context *context
-
- mu sync.RWMutex
- url string
- projectID string
- authHeader string
- release string
- environment string
- sampleRate float32
-
- // default logger name (leave empty for 'root')
- defaultLoggerName string
-
- includePaths []string
- ignoreErrorsRegexp *regexp.Regexp
- queue chan *outgoingPacket
-
- // A WaitGroup to keep track of all currently in-progress captures
- // This is intended to be used with Client.Wait() to assure that
- // all messages have been transported before exiting the process.
- wg sync.WaitGroup
-
- // A Once to track only starting up the background worker once
- start sync.Once
-}
-
-// Initialize a default *Client instance
-var DefaultClient = newClient(nil)
-
-func (c *Client) SetIgnoreErrors(errs []string) error {
- joinedRegexp := strings.Join(errs, "|")
- r, err := regexp.Compile(joinedRegexp)
- if err != nil {
- return fmt.Errorf("failed to compile regexp %q for %q: %v", joinedRegexp, errs, err)
- }
-
- c.mu.Lock()
- c.ignoreErrorsRegexp = r
- c.mu.Unlock()
- return nil
-}
-
-func (c *Client) shouldExcludeErr(errStr string) bool {
- c.mu.RLock()
- defer c.mu.RUnlock()
- return c.ignoreErrorsRegexp != nil && c.ignoreErrorsRegexp.MatchString(errStr)
-}
-
-func SetIgnoreErrors(errs ...string) error {
- return DefaultClient.SetIgnoreErrors(errs)
-}
-
-// SetDSN updates a client with a new DSN. It safe to call after and
-// concurrently with calls to Report and Send.
-func (client *Client) SetDSN(dsn string) error {
- if dsn == "" {
- return nil
- }
-
- client.mu.Lock()
- defer client.mu.Unlock()
-
- uri, err := url.Parse(dsn)
- if err != nil {
- return err
- }
-
- if uri.User == nil {
- return ErrMissingUser
- }
- publicKey := uri.User.Username()
- secretKey, hasSecretKey := uri.User.Password()
- uri.User = nil
-
- if idx := strings.LastIndex(uri.Path, "/"); idx != -1 {
- client.projectID = uri.Path[idx+1:]
- uri.Path = uri.Path[:idx+1] + "api/" + client.projectID + "/store/"
- }
- if client.projectID == "" {
- return ErrMissingProjectID
- }
-
- client.url = uri.String()
-
- if hasSecretKey {
- client.authHeader = fmt.Sprintf("Sentry sentry_version=4, sentry_key=%s, sentry_secret=%s", publicKey, secretKey)
- } else {
- client.authHeader = fmt.Sprintf("Sentry sentry_version=4, sentry_key=%s", publicKey)
- }
-
- return nil
-}
-
-// Sets the DSN for the default *Client instance
-func SetDSN(dsn string) error { return DefaultClient.SetDSN(dsn) }
-
-// SetRelease sets the "release" tag.
-func (client *Client) SetRelease(release string) {
- client.mu.Lock()
- defer client.mu.Unlock()
- client.release = release
-}
-
-// SetEnvironment sets the "environment" tag.
-func (client *Client) SetEnvironment(environment string) {
- client.mu.Lock()
- defer client.mu.Unlock()
- client.environment = environment
-}
-
-// SetDefaultLoggerName sets the default logger name.
-func (client *Client) SetDefaultLoggerName(name string) {
- client.mu.Lock()
- defer client.mu.Unlock()
- client.defaultLoggerName = name
-}
-
-// SetSampleRate sets how much sampling we want on client side
-func (client *Client) SetSampleRate(rate float32) error {
- client.mu.Lock()
- defer client.mu.Unlock()
-
- if rate < 0 || rate > 1 {
- return ErrInvalidSampleRate
- }
- client.sampleRate = rate
- return nil
-}
-
-// SetRelease sets the "release" tag on the default *Client
-func SetRelease(release string) { DefaultClient.SetRelease(release) }
-
-// SetEnvironment sets the "environment" tag on the default *Client
-func SetEnvironment(environment string) { DefaultClient.SetEnvironment(environment) }
-
-// SetDefaultLoggerName sets the "defaultLoggerName" on the default *Client
-func SetDefaultLoggerName(name string) {
- DefaultClient.SetDefaultLoggerName(name)
-}
-
-// SetSampleRate sets the "sample rate" on the degault *Client
-func SetSampleRate(rate float32) error { return DefaultClient.SetSampleRate(rate) }
-
-func (client *Client) worker() {
- for outgoingPacket := range client.queue {
-
- client.mu.RLock()
- url, authHeader := client.url, client.authHeader
- client.mu.RUnlock()
-
- outgoingPacket.ch <- client.Transport.Send(url, authHeader, outgoingPacket.packet)
- client.wg.Done()
- }
-}
-
-// Capture asynchronously delivers a packet to the Sentry server. It is a no-op
-// when client is nil. A channel is provided if it is important to check for a
-// send's success.
-func (client *Client) Capture(packet *Packet, captureTags map[string]string) (eventID string, ch chan error) {
- ch = make(chan error, 1)
-
- if client == nil {
- // return a chan that always returns nil when the caller receives from it
- close(ch)
- return
- }
-
- if client.sampleRate < 1.0 && mrand.Float32() > client.sampleRate {
- return
- }
-
- if packet == nil {
- close(ch)
- return
- }
-
- if client.shouldExcludeErr(packet.Message) {
- return
- }
-
- // Keep track of all running Captures so that we can wait for them all to finish
- // *Must* call client.wg.Done() on any path that indicates that an event was
- // finished being acted upon, whether success or failure
- client.wg.Add(1)
-
- // Merge capture tags and client tags
- packet.AddTags(captureTags)
- packet.AddTags(client.Tags)
-
- // Initialize any required packet fields
- client.mu.RLock()
- packet.AddTags(client.context.tags)
- projectID := client.projectID
- release := client.release
- environment := client.environment
- defaultLoggerName := client.defaultLoggerName
- client.mu.RUnlock()
-
- // set the global logger name on the packet if we must
- if packet.Logger == "" && defaultLoggerName != "" {
- packet.Logger = defaultLoggerName
- }
-
- err := packet.Init(projectID)
- if err != nil {
- ch <- err
- client.wg.Done()
- return
- }
-
- if packet.Release == "" {
- packet.Release = release
- }
-
- if packet.Environment == "" {
- packet.Environment = environment
- }
-
- outgoingPacket := &outgoingPacket{packet, ch}
-
- // Lazily start background worker until we
- // do our first write into the queue.
- client.start.Do(func() {
- go client.worker()
- })
-
- select {
- case client.queue <- outgoingPacket:
- default:
- // Send would block, drop the packet
- if client.DropHandler != nil {
- client.DropHandler(packet)
- }
- ch <- ErrPacketDropped
- client.wg.Done()
- }
-
- return packet.EventID, ch
-}
-
-// Capture asynchronously delivers a packet to the Sentry server with the default *Client.
-// It is a no-op when client is nil. A channel is provided if it is important to check for a
-// send's success.
-func Capture(packet *Packet, captureTags map[string]string) (eventID string, ch chan error) {
- return DefaultClient.Capture(packet, captureTags)
-}
-
-// CaptureMessage formats and delivers a string message to the Sentry server.
-func (client *Client) CaptureMessage(message string, tags map[string]string, interfaces ...Interface) string {
- if client == nil {
- return ""
- }
-
- if client.shouldExcludeErr(message) {
- return ""
- }
-
- packet := NewPacket(message, append(append(interfaces, client.context.interfaces()...), &Message{message, nil})...)
- eventID, _ := client.Capture(packet, tags)
-
- return eventID
-}
-
-// CaptureMessage formats and delivers a string message to the Sentry server with the default *Client
-func CaptureMessage(message string, tags map[string]string, interfaces ...Interface) string {
- return DefaultClient.CaptureMessage(message, tags, interfaces...)
-}
-
-// CaptureMessageAndWait is identical to CaptureMessage except it blocks and waits for the message to be sent.
-func (client *Client) CaptureMessageAndWait(message string, tags map[string]string, interfaces ...Interface) string {
- if client == nil {
- return ""
- }
-
- if client.shouldExcludeErr(message) {
- return ""
- }
-
- packet := NewPacket(message, append(append(interfaces, client.context.interfaces()...), &Message{message, nil})...)
- eventID, ch := client.Capture(packet, tags)
- if eventID != "" {
- <-ch
- }
-
- return eventID
-}
-
-// CaptureMessageAndWait is identical to CaptureMessage except it blocks and waits for the message to be sent.
-func CaptureMessageAndWait(message string, tags map[string]string, interfaces ...Interface) string {
- return DefaultClient.CaptureMessageAndWait(message, tags, interfaces...)
-}
-
-// CaptureErrors formats and delivers an error to the Sentry server.
-// Adds a stacktrace to the packet, excluding the call to this method.
-func (client *Client) CaptureError(err error, tags map[string]string, interfaces ...Interface) string {
- if client == nil {
- return ""
- }
-
- if err == nil {
- return ""
- }
-
- if client.shouldExcludeErr(err.Error()) {
- return ""
- }
-
- extra := extractExtra(err)
- cause := pkgErrors.Cause(err)
-
- packet := NewPacketWithExtra(err.Error(), extra, append(append(interfaces, client.context.interfaces()...), NewException(cause, GetOrNewStacktrace(cause, 1, 3, client.includePaths)))...)
- eventID, _ := client.Capture(packet, tags)
-
- return eventID
-}
-
-// CaptureErrors formats and delivers an error to the Sentry server using the default *Client.
-// Adds a stacktrace to the packet, excluding the call to this method.
-func CaptureError(err error, tags map[string]string, interfaces ...Interface) string {
- return DefaultClient.CaptureError(err, tags, interfaces...)
-}
-
-// CaptureErrorAndWait is identical to CaptureError, except it blocks and assures that the event was sent
-func (client *Client) CaptureErrorAndWait(err error, tags map[string]string, interfaces ...Interface) string {
- if client == nil {
- return ""
- }
-
- if client.shouldExcludeErr(err.Error()) {
- return ""
- }
-
- extra := extractExtra(err)
- cause := pkgErrors.Cause(err)
-
- packet := NewPacketWithExtra(err.Error(), extra, append(append(interfaces, client.context.interfaces()...), NewException(cause, GetOrNewStacktrace(cause, 1, 3, client.includePaths)))...)
- eventID, ch := client.Capture(packet, tags)
- if eventID != "" {
- <-ch
- }
-
- return eventID
-}
-
-// CaptureErrorAndWait is identical to CaptureError, except it blocks and assures that the event was sent
-func CaptureErrorAndWait(err error, tags map[string]string, interfaces ...Interface) string {
- return DefaultClient.CaptureErrorAndWait(err, tags, interfaces...)
-}
-
-// CapturePanic calls f and then recovers and reports a panic to the Sentry server if it occurs.
-// If an error is captured, both the error and the reported Sentry error ID are returned.
-func (client *Client) CapturePanic(f func(), tags map[string]string, interfaces ...Interface) (err interface{}, errorID string) {
- // Note: This doesn't need to check for client, because we still want to go through the defer/recover path
- // Down the line, Capture will be noop'd, so while this does a _tiny_ bit of overhead constructing the
- // *Packet just to be thrown away, this should not be the normal case. Could be refactored to
- // be completely noop though if we cared.
- defer func() {
- var packet *Packet
- err = recover()
- switch rval := err.(type) {
- case nil:
- return
- case error:
- if client.shouldExcludeErr(rval.Error()) {
- return
- }
- packet = NewPacket(rval.Error(), append(append(interfaces, client.context.interfaces()...), NewException(rval, NewStacktrace(2, 3, client.includePaths)))...)
- default:
- rvalStr := fmt.Sprint(rval)
- if client.shouldExcludeErr(rvalStr) {
- return
- }
- packet = NewPacket(rvalStr, append(append(interfaces, client.context.interfaces()...), NewException(errors.New(rvalStr), NewStacktrace(2, 3, client.includePaths)))...)
- }
-
- errorID, _ = client.Capture(packet, tags)
- }()
-
- f()
- return
-}
-
-// CapturePanic calls f and then recovers and reports a panic to the Sentry server if it occurs.
-// If an error is captured, both the error and the reported Sentry error ID are returned.
-func CapturePanic(f func(), tags map[string]string, interfaces ...Interface) (interface{}, string) {
- return DefaultClient.CapturePanic(f, tags, interfaces...)
-}
-
-// CapturePanicAndWait is identical to CaptureError, except it blocks and assures that the event was sent
-func (client *Client) CapturePanicAndWait(f func(), tags map[string]string, interfaces ...Interface) (err interface{}, errorID string) {
- // Note: This doesn't need to check for client, because we still want to go through the defer/recover path
- // Down the line, Capture will be noop'd, so while this does a _tiny_ bit of overhead constructing the
- // *Packet just to be thrown away, this should not be the normal case. Could be refactored to
- // be completely noop though if we cared.
- defer func() {
- var packet *Packet
- err = recover()
- switch rval := err.(type) {
- case nil:
- return
- case error:
- if client.shouldExcludeErr(rval.Error()) {
- return
- }
- packet = NewPacket(rval.Error(), append(append(interfaces, client.context.interfaces()...), NewException(rval, NewStacktrace(2, 3, client.includePaths)))...)
- default:
- rvalStr := fmt.Sprint(rval)
- if client.shouldExcludeErr(rvalStr) {
- return
- }
- packet = NewPacket(rvalStr, append(append(interfaces, client.context.interfaces()...), NewException(errors.New(rvalStr), NewStacktrace(2, 3, client.includePaths)))...)
- }
-
- var ch chan error
- errorID, ch = client.Capture(packet, tags)
- if errorID != "" {
- <-ch
- }
- }()
-
- f()
- return
-}
-
-// CapturePanicAndWait is identical to CaptureError, except it blocks and assures that the event was sent
-func CapturePanicAndWait(f func(), tags map[string]string, interfaces ...Interface) (interface{}, string) {
- return DefaultClient.CapturePanicAndWait(f, tags, interfaces...)
-}
-
-func (client *Client) Close() {
- close(client.queue)
-}
-
-func Close() { DefaultClient.Close() }
-
-// Wait blocks and waits for all events to finish being sent to Sentry server
-func (client *Client) Wait() {
- client.wg.Wait()
-}
-
-// Wait blocks and waits for all events to finish being sent to Sentry server
-func Wait() { DefaultClient.Wait() }
-
-func (client *Client) URL() string {
- client.mu.RLock()
- defer client.mu.RUnlock()
-
- return client.url
-}
-
-func URL() string { return DefaultClient.URL() }
-
-func (client *Client) ProjectID() string {
- client.mu.RLock()
- defer client.mu.RUnlock()
-
- return client.projectID
-}
-
-func ProjectID() string { return DefaultClient.ProjectID() }
-
-func (client *Client) Release() string {
- client.mu.RLock()
- defer client.mu.RUnlock()
-
- return client.release
-}
-
-func Release() string { return DefaultClient.Release() }
-
-func IncludePaths() []string { return DefaultClient.IncludePaths() }
-
-func (client *Client) IncludePaths() []string {
- client.mu.RLock()
- defer client.mu.RUnlock()
-
- return client.includePaths
-}
-
-func SetIncludePaths(p []string) { DefaultClient.SetIncludePaths(p) }
-
-func (client *Client) SetIncludePaths(p []string) {
- client.mu.Lock()
- defer client.mu.Unlock()
-
- client.includePaths = p
-}
-
-func (c *Client) SetUserContext(u *User) {
- c.mu.Lock()
- defer c.mu.Unlock()
- c.context.setUser(u)
-}
-
-func (c *Client) SetHttpContext(h *Http) {
- c.mu.Lock()
- defer c.mu.Unlock()
- c.context.setHttp(h)
-}
-
-func (c *Client) SetTagsContext(t map[string]string) {
- c.mu.Lock()
- defer c.mu.Unlock()
- c.context.setTags(t)
-}
-
-func (c *Client) ClearContext() {
- c.mu.Lock()
- defer c.mu.Unlock()
- c.context.clear()
-}
-
-func SetUserContext(u *User) { DefaultClient.SetUserContext(u) }
-func SetHttpContext(h *Http) { DefaultClient.SetHttpContext(h) }
-func SetTagsContext(t map[string]string) { DefaultClient.SetTagsContext(t) }
-func ClearContext() { DefaultClient.ClearContext() }
-
-// HTTPTransport is the default transport, delivering packets to Sentry via the
-// HTTP API.
-type HTTPTransport struct {
- *http.Client
-}
-
-func (t *HTTPTransport) Send(url, authHeader string, packet *Packet) error {
- if url == "" {
- return nil
- }
-
- body, contentType, err := serializedPacket(packet)
- if err != nil {
- return fmt.Errorf("error serializing packet: %v", err)
- }
- req, err := http.NewRequest("POST", url, body)
- if err != nil {
- return fmt.Errorf("can't create new request: %v", err)
- }
- req.Header.Set("X-Sentry-Auth", authHeader)
- req.Header.Set("User-Agent", userAgent)
- req.Header.Set("Content-Type", contentType)
- res, err := t.Do(req)
- if err != nil {
- return err
- }
- io.Copy(ioutil.Discard, res.Body)
- res.Body.Close()
- if res.StatusCode != 200 {
- return fmt.Errorf("raven: got http status %d - x-sentry-error: %s", res.StatusCode, res.Header.Get("X-Sentry-Error"))
- }
- return nil
-}
-
-func serializedPacket(packet *Packet) (io.Reader, string, error) {
- packetJSON, err := packet.JSON()
- if err != nil {
- return nil, "", fmt.Errorf("error marshaling packet %+v to JSON: %v", packet, err)
- }
-
- // Only deflate/base64 the packet if it is bigger than 1KB, as there is
- // overhead.
- if len(packetJSON) > 1000 {
- buf := &bytes.Buffer{}
- b64 := base64.NewEncoder(base64.StdEncoding, buf)
- deflate, _ := zlib.NewWriterLevel(b64, zlib.BestCompression)
- deflate.Write(packetJSON)
- deflate.Close()
- b64.Close()
- return buf, "application/octet-stream", nil
- }
- return bytes.NewReader(packetJSON), "application/json", nil
-}
-
-var hostname string
-
-func init() {
- hostname, _ = os.Hostname()
-}
diff --git a/vendor/github.com/getsentry/raven-go/errors.go b/vendor/github.com/getsentry/raven-go/errors.go
deleted file mode 100644
index 5e57270436d..00000000000
--- a/vendor/github.com/getsentry/raven-go/errors.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package raven
-
-type causer interface {
- Cause() error
-}
-
-type errWrappedWithExtra struct {
- err error
- extraInfo map[string]interface{}
-}
-
-func (ewx *errWrappedWithExtra) Error() string {
- return ewx.err.Error()
-}
-
-func (ewx *errWrappedWithExtra) Cause() error {
- return ewx.err
-}
-
-func (ewx *errWrappedWithExtra) ExtraInfo() Extra {
- return ewx.extraInfo
-}
-
-// Adds extra data to an error before reporting to Sentry
-func WrapWithExtra(err error, extraInfo map[string]interface{}) error {
- return &errWrappedWithExtra{
- err: err,
- extraInfo: extraInfo,
- }
-}
-
-type ErrWithExtra interface {
- Error() string
- Cause() error
- ExtraInfo() Extra
-}
-
-// Iteratively fetches all the Extra data added to an error,
-// and it's underlying errors. Extra data defined first is
-// respected, and is not overridden when extracting.
-func extractExtra(err error) Extra {
- extra := Extra{}
-
- currentErr := err
- for currentErr != nil {
- if errWithExtra, ok := currentErr.(ErrWithExtra); ok {
- for k, v := range errWithExtra.ExtraInfo() {
- extra[k] = v
- }
- }
-
- if errWithCause, ok := currentErr.(causer); ok {
- currentErr = errWithCause.Cause()
- } else {
- currentErr = nil
- }
- }
-
- return extra
-}
diff --git a/vendor/github.com/getsentry/raven-go/exception.go b/vendor/github.com/getsentry/raven-go/exception.go
deleted file mode 100644
index 552eaad128c..00000000000
--- a/vendor/github.com/getsentry/raven-go/exception.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package raven
-
-import (
- "reflect"
- "regexp"
-)
-
-var errorMsgPattern = regexp.MustCompile(`\A(\w+): (.+)\z`)
-
-func NewException(err error, stacktrace *Stacktrace) *Exception {
- msg := err.Error()
- ex := &Exception{
- Stacktrace: stacktrace,
- Value: msg,
- Type: reflect.TypeOf(err).String(),
- }
- if m := errorMsgPattern.FindStringSubmatch(msg); m != nil {
- ex.Module, ex.Value = m[1], m[2]
- }
- return ex
-}
-
-// https://docs.getsentry.com/hosted/clientdev/interfaces/#failure-interfaces
-type Exception struct {
- // Required
- Value string `json:"value"`
-
- // Optional
- Type string `json:"type,omitempty"`
- Module string `json:"module,omitempty"`
- Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
-}
-
-func (e *Exception) Class() string { return "exception" }
-
-func (e *Exception) Culprit() string {
- if e.Stacktrace == nil {
- return ""
- }
- return e.Stacktrace.Culprit()
-}
-
-// Exceptions allows for chained errors
-// https://docs.sentry.io/clientdev/interfaces/exception/
-type Exceptions struct {
- // Required
- Values []*Exception `json:"values"`
-}
-
-func (es Exceptions) Class() string { return "exception" }
diff --git a/vendor/github.com/getsentry/raven-go/http.go b/vendor/github.com/getsentry/raven-go/http.go
deleted file mode 100644
index ae8f47234c1..00000000000
--- a/vendor/github.com/getsentry/raven-go/http.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package raven
-
-import (
- "errors"
- "fmt"
- "net"
- "net/http"
- "net/url"
- "runtime/debug"
- "strings"
-)
-
-func NewHttp(req *http.Request) *Http {
- proto := "http"
- if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
- proto = "https"
- }
- h := &Http{
- Method: req.Method,
- Cookies: req.Header.Get("Cookie"),
- Query: sanitizeQuery(req.URL.Query()).Encode(),
- URL: proto + "://" + req.Host + req.URL.Path,
- Headers: make(map[string]string, len(req.Header)),
- }
- if addr, port, err := net.SplitHostPort(req.RemoteAddr); err == nil {
- h.Env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port}
- }
- for k, v := range req.Header {
- h.Headers[k] = strings.Join(v, ",")
- }
- h.Headers["Host"] = req.Host
- return h
-}
-
-var querySecretFields = []string{"password", "passphrase", "passwd", "secret"}
-
-func sanitizeQuery(query url.Values) url.Values {
- for _, keyword := range querySecretFields {
- for field := range query {
- if strings.Contains(field, keyword) {
- query[field] = []string{"********"}
- }
- }
- }
- return query
-}
-
-// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
-type Http struct {
- // Required
- URL string `json:"url"`
- Method string `json:"method"`
- Query string `json:"query_string,omitempty"`
-
- // Optional
- Cookies string `json:"cookies,omitempty"`
- Headers map[string]string `json:"headers,omitempty"`
- Env map[string]string `json:"env,omitempty"`
-
- // Must be either a string or map[string]string
- Data interface{} `json:"data,omitempty"`
-}
-
-func (h *Http) Class() string { return "request" }
-
-// Recovery handler to wrap the stdlib net/http Mux.
-// Example:
-// http.HandleFunc("/", raven.RecoveryHandler(func(w http.ResponseWriter, r *http.Request) {
-// ...
-// }))
-func RecoveryHandler(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
- return Recoverer(http.HandlerFunc(handler)).ServeHTTP
-}
-
-// Recovery handler to wrap the stdlib net/http Mux.
-// Example:
-// mux := http.NewServeMux
-// ...
-// http.Handle("/", raven.Recoverer(mux))
-func Recoverer(handler http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- defer func() {
- if rval := recover(); rval != nil {
- debug.PrintStack()
- rvalStr := fmt.Sprint(rval)
- var packet *Packet
- if err, ok := rval.(error); ok {
- packet = NewPacket(rvalStr, NewException(errors.New(rvalStr), GetOrNewStacktrace(err, 2, 3, nil)), NewHttp(r))
- } else {
- packet = NewPacket(rvalStr, NewException(errors.New(rvalStr), NewStacktrace(2, 3, nil)), NewHttp(r))
- }
- Capture(packet, nil)
- w.WriteHeader(http.StatusInternalServerError)
- }
- }()
-
- handler.ServeHTTP(w, r)
- })
-}
diff --git a/vendor/github.com/getsentry/raven-go/interfaces.go b/vendor/github.com/getsentry/raven-go/interfaces.go
deleted file mode 100644
index a05dc3de472..00000000000
--- a/vendor/github.com/getsentry/raven-go/interfaces.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package raven
-
-// https://docs.getsentry.com/hosted/clientdev/interfaces/#message-interface
-type Message struct {
- // Required
- Message string `json:"message"`
-
- // Optional
- Params []interface{} `json:"params,omitempty"`
-}
-
-func (m *Message) Class() string { return "logentry" }
-
-// https://docs.getsentry.com/hosted/clientdev/interfaces/#template-interface
-type Template struct {
- // Required
- Filename string `json:"filename"`
- Lineno int `json:"lineno"`
- ContextLine string `json:"context_line"`
-
- // Optional
- PreContext []string `json:"pre_context,omitempty"`
- PostContext []string `json:"post_context,omitempty"`
- AbsolutePath string `json:"abs_path,omitempty"`
-}
-
-func (t *Template) Class() string { return "template" }
-
-// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
-type User struct {
- // All fields are optional
- ID string `json:"id,omitempty"`
- Username string `json:"username,omitempty"`
- Email string `json:"email,omitempty"`
- IP string `json:"ip_address,omitempty"`
-}
-
-func (h *User) Class() string { return "user" }
-
-// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
-type Query struct {
- // Required
- Query string `json:"query"`
-
- // Optional
- Engine string `json:"engine,omitempty"`
-}
-
-func (q *Query) Class() string { return "query" }
diff --git a/vendor/github.com/getsentry/raven-go/runtests.sh b/vendor/github.com/getsentry/raven-go/runtests.sh
deleted file mode 100644
index 9ed279c966e..00000000000
--- a/vendor/github.com/getsentry/raven-go/runtests.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-go test -race ./...
-go test -cover ./...
-go test -v ./...
diff --git a/vendor/github.com/getsentry/raven-go/stacktrace.go b/vendor/github.com/getsentry/raven-go/stacktrace.go
deleted file mode 100644
index bc302ba119f..00000000000
--- a/vendor/github.com/getsentry/raven-go/stacktrace.go
+++ /dev/null
@@ -1,277 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-// Some code from the runtime/debug package of the Go standard library.
-
-package raven
-
-import (
- "bytes"
- "go/build"
- "io/ioutil"
- "path/filepath"
- "runtime"
- "strings"
- "sync"
-
- "github.com/pkg/errors"
-)
-
-// https://docs.getsentry.com/hosted/clientdev/interfaces/#failure-interfaces
-type Stacktrace struct {
- // Required
- Frames []*StacktraceFrame `json:"frames"`
-}
-
-func (s *Stacktrace) Class() string { return "stacktrace" }
-
-func (s *Stacktrace) Culprit() string {
- for i := len(s.Frames) - 1; i >= 0; i-- {
- frame := s.Frames[i]
- if frame.InApp == true && frame.Module != "" && frame.Function != "" {
- return frame.Module + "." + frame.Function
- }
- }
- return ""
-}
-
-type StacktraceFrame struct {
- // At least one required
- Filename string `json:"filename,omitempty"`
- Function string `json:"function,omitempty"`
- Module string `json:"module,omitempty"`
-
- // Optional
- Lineno int `json:"lineno,omitempty"`
- Colno int `json:"colno,omitempty"`
- AbsolutePath string `json:"abs_path,omitempty"`
- ContextLine string `json:"context_line,omitempty"`
- PreContext []string `json:"pre_context,omitempty"`
- PostContext []string `json:"post_context,omitempty"`
- InApp bool `json:"in_app"`
-}
-
-// Try to get stacktrace from err as an interface of github.com/pkg/errors, or else NewStacktrace()
-func GetOrNewStacktrace(err error, skip int, context int, appPackagePrefixes []string) *Stacktrace {
- stacktracer, errHasStacktrace := err.(interface {
- StackTrace() errors.StackTrace
- })
- if errHasStacktrace {
- var frames []*StacktraceFrame
- for _, f := range stacktracer.StackTrace() {
- pc := uintptr(f) - 1
- fn := runtime.FuncForPC(pc)
- var fName string
- var file string
- var line int
- if fn != nil {
- file, line = fn.FileLine(pc)
- fName = fn.Name()
- } else {
- file = "unknown"
- fName = "unknown"
- }
- frame := NewStacktraceFrame(pc, fName, file, line, context, appPackagePrefixes)
- if frame != nil {
- frames = append([]*StacktraceFrame{frame}, frames...)
- }
- }
- return &Stacktrace{Frames: frames}
- } else {
- return NewStacktrace(skip+1, context, appPackagePrefixes)
- }
-}
-
-// Intialize and populate a new stacktrace, skipping skip frames.
-//
-// context is the number of surrounding lines that should be included for context.
-// Setting context to 3 would try to get seven lines. Setting context to -1 returns
-// one line with no surrounding context, and 0 returns no context.
-//
-// appPackagePrefixes is a list of prefixes used to check whether a package should
-// be considered "in app".
-func NewStacktrace(skip int, context int, appPackagePrefixes []string) *Stacktrace {
- var frames []*StacktraceFrame
-
- callerPcs := make([]uintptr, 100)
- numCallers := runtime.Callers(skip+2, callerPcs)
-
- // If there are no callers, the entire stacktrace is nil
- if numCallers == 0 {
- return nil
- }
-
- callersFrames := runtime.CallersFrames(callerPcs)
-
- for {
- fr, more := callersFrames.Next()
- if fr.Func != nil {
- frame := NewStacktraceFrame(fr.PC, fr.Function, fr.File, fr.Line, context, appPackagePrefixes)
- if frame != nil {
- frames = append(frames, frame)
- }
- }
- if !more {
- break
- }
- }
- // If there are no frames, the entire stacktrace is nil
- if len(frames) == 0 {
- return nil
- }
- // Optimize the path where there's only 1 frame
- if len(frames) == 1 {
- return &Stacktrace{frames}
- }
- // Sentry wants the frames with the oldest first, so reverse them
- for i, j := 0, len(frames)-1; i < j; i, j = i+1, j-1 {
- frames[i], frames[j] = frames[j], frames[i]
- }
- return &Stacktrace{frames}
-}
-
-// Build a single frame using data returned from runtime.Caller.
-//
-// context is the number of surrounding lines that should be included for context.
-// Setting context to 3 would try to get seven lines. Setting context to -1 returns
-// one line with no surrounding context, and 0 returns no context.
-//
-// appPackagePrefixes is a list of prefixes used to check whether a package should
-// be considered "in app".
-func NewStacktraceFrame(pc uintptr, fName, file string, line, context int, appPackagePrefixes []string) *StacktraceFrame {
- frame := &StacktraceFrame{AbsolutePath: file, Filename: trimPath(file), Lineno: line, InApp: false}
- frame.Module, frame.Function = functionName(fName)
-
- // `runtime.goexit` is effectively a placeholder that comes from
- // runtime/asm_amd64.s and is meaningless.
- if frame.Module == "runtime" && frame.Function == "goexit" {
- return nil
- }
-
- if frame.Module == "main" {
- frame.InApp = true
- } else {
- for _, prefix := range appPackagePrefixes {
- if strings.HasPrefix(frame.Module, prefix) && !strings.Contains(frame.Module, "vendor") && !strings.Contains(frame.Module, "third_party") {
- frame.InApp = true
- }
- }
- }
-
- if context > 0 {
- contextLines, lineIdx := sourceCodeLoader.Load(file, line, context)
- if len(contextLines) > 0 {
- for i, line := range contextLines {
- switch {
- case i < lineIdx:
- frame.PreContext = append(frame.PreContext, string(line))
- case i == lineIdx:
- frame.ContextLine = string(line)
- default:
- frame.PostContext = append(frame.PostContext, string(line))
- }
- }
- }
- } else if context == -1 {
- contextLine, _ := sourceCodeLoader.Load(file, line, 0)
- if len(contextLine) > 0 {
- frame.ContextLine = string(contextLine[0])
- }
- }
- return frame
-}
-
-// Retrieve the name of the package and function containing the PC.
-func functionName(fName string) (pack string, name string) {
- name = fName
- // We get this:
- // runtime/debug.*T·ptrmethod
- // and want this:
- // pack = runtime/debug
- // name = *T.ptrmethod
- if idx := strings.LastIndex(name, "."); idx != -1 {
- pack = name[:idx]
- name = name[idx+1:]
- }
- name = strings.Replace(name, "·", ".", -1)
- return
-}
-
-type SourceCodeLoader interface {
- Load(filename string, line, context int) ([][]byte, int)
-}
-
-var sourceCodeLoader SourceCodeLoader = &fsLoader{cache: make(map[string][][]byte)}
-
-func SetSourceCodeLoader(loader SourceCodeLoader) {
- sourceCodeLoader = loader
-}
-
-type fsLoader struct {
- mu sync.Mutex
- cache map[string][][]byte
-}
-
-func (fs *fsLoader) Load(filename string, line, context int) ([][]byte, int) {
- fs.mu.Lock()
- defer fs.mu.Unlock()
- lines, ok := fs.cache[filename]
- if !ok {
- data, err := ioutil.ReadFile(filename)
- if err != nil {
- // cache errors as nil slice: code below handles it correctly
- // otherwise when missing the source or running as a different user, we try
- // reading the file on each error which is unnecessary
- fs.cache[filename] = nil
- return nil, 0
- }
- lines = bytes.Split(data, []byte{'\n'})
- fs.cache[filename] = lines
- }
-
- if lines == nil {
- // cached error from ReadFile: return no lines
- return nil, 0
- }
-
- line-- // stack trace lines are 1-indexed
- start := line - context
- var idx int
- if start < 0 {
- start = 0
- idx = line
- } else {
- idx = context
- }
- end := line + context + 1
- if line >= len(lines) {
- return nil, 0
- }
- if end > len(lines) {
- end = len(lines)
- }
- return lines[start:end], idx
-}
-
-var trimPaths []string
-
-// Try to trim the GOROOT or GOPATH prefix off of a filename
-func trimPath(filename string) string {
- for _, prefix := range trimPaths {
- if trimmed := strings.TrimPrefix(filename, prefix); len(trimmed) < len(filename) {
- return trimmed
- }
- }
- return filename
-}
-
-func init() {
- // Collect all source directories, and make sure they
- // end in a trailing "separator"
- for _, prefix := range build.Default.SrcDirs() {
- if prefix[len(prefix)-1] != filepath.Separator {
- prefix += string(filepath.Separator)
- }
- trimPaths = append(trimPaths, prefix)
- }
-}
diff --git a/vendor/github.com/getsentry/raven-go/writer.go b/vendor/github.com/getsentry/raven-go/writer.go
deleted file mode 100644
index 61f7a91088e..00000000000
--- a/vendor/github.com/getsentry/raven-go/writer.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package raven
-
-type Writer struct {
- Client *Client
- Level Severity
- Logger string // Logger name reported to Sentry
-}
-
-// Write formats the byte slice p into a string, and sends a message to
-// Sentry at the severity level indicated by the Writer w.
-func (w *Writer) Write(p []byte) (int, error) {
- message := string(p)
-
- packet := NewPacket(message, &Message{message, nil})
- packet.Level = w.Level
- packet.Logger = w.Logger
- w.Client.Capture(packet, nil)
-
- return len(p), nil
-}
diff --git a/vendor/github.com/go-redis/redis/v8/.gitignore b/vendor/github.com/go-redis/redis/v8/.gitignore
deleted file mode 100644
index b975a7b4c32..00000000000
--- a/vendor/github.com/go-redis/redis/v8/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-*.rdb
-testdata/*/
-.idea/
diff --git a/vendor/github.com/go-redis/redis/v8/.golangci.yml b/vendor/github.com/go-redis/redis/v8/.golangci.yml
deleted file mode 100644
index 2132eee96f2..00000000000
--- a/vendor/github.com/go-redis/redis/v8/.golangci.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-run:
- concurrency: 8
- deadline: 5m
- tests: false
-linters:
- enable-all: true
- disable:
- - funlen
- - gochecknoglobals
- - gochecknoinits
- - gocognit
- - goconst
- - godox
- - gosec
- - maligned
- - wsl
- - gomnd
- - goerr113
- - exhaustive
- - gofumpt
- - nestif
diff --git a/vendor/github.com/go-redis/redis/v8/.prettierrc b/vendor/github.com/go-redis/redis/v8/.prettierrc
deleted file mode 100644
index 8b7f044ad1f..00000000000
--- a/vendor/github.com/go-redis/redis/v8/.prettierrc
+++ /dev/null
@@ -1,4 +0,0 @@
-semi: false
-singleQuote: true
-proseWrap: always
-printWidth: 100
diff --git a/vendor/github.com/go-redis/redis/v8/.travis.yml b/vendor/github.com/go-redis/redis/v8/.travis.yml
deleted file mode 100644
index adedd8df4e4..00000000000
--- a/vendor/github.com/go-redis/redis/v8/.travis.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-dist: xenial
-language: go
-
-services:
- - redis-server
-
-go:
- - 1.14.x
- - 1.15.x
- - tip
-
-matrix:
- allow_failures:
- - go: tip
-
-go_import_path: github.com/go-redis/redis
-
-before_install:
- - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s --
- -b $(go env GOPATH)/bin v1.28.3
diff --git a/vendor/github.com/go-redis/redis/v8/CHANGELOG.md b/vendor/github.com/go-redis/redis/v8/CHANGELOG.md
deleted file mode 100644
index d0c4c8c1cb3..00000000000
--- a/vendor/github.com/go-redis/redis/v8/CHANGELOG.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# Changelog
-
-> :heart: [**Uptrace.dev** - distributed traces, logs, and errors in one place](https://uptrace.dev)
-
-## v8
-
-- Documentation at https://redis.uptrace.dev/
-
-- All commands require `context.Context` as a first argument, e.g. `rdb.Ping(ctx)`. If you are not
- using `context.Context` yet, the simplest option is to define global package variable
- `var ctx = context.TODO()` and use it when `ctx` is required.
-
-- Full support for `context.Context` canceling.
-
-- Added `redis.NewFailoverClusterClient` that supports routing read-only commands to a slave node.
-
-- Added `redisext.OpenTemetryHook` that adds
- [Redis OpenTelemetry instrumentation](https://redis.uptrace.dev/tracing/).
-
-- Redis slow log support.
-
-- Ring uses Rendezvous Hashing by default which provides better distribution. You need to move
- existing keys to a new location or keys will be inaccessible / lost. To use old hashing scheme:
-
-```go
-import "github.com/golang/groupcache/consistenthash"
-
-ring := redis.NewRing(&redis.RingOptions{
- NewConsistentHash: func() {
- return consistenthash.New(100, crc32.ChecksumIEEE)
- },
-})
-```
-
-- `ClusterOptions.MaxRedirects` default value is changed from 8 to 3.
-- `Options.MaxRetries` default value is changed from 0 to 3.
-
-- `Cluster.ForEachNode` is renamed to `ForEachShard` for consistency with `Ring`.
-
-## v7.3
-
-- New option `Options.Username` which causes client to use `AuthACL`. Be aware if your connection
- URL contains username.
-
-## v7.2
-
-- Existing `HMSet` is renamed to `HSet` and old deprecated `HMSet` is restored for Redis 3 users.
-
-## v7.1
-
-- Existing `Cmd.String` is renamed to `Cmd.Text`. New `Cmd.String` implements `fmt.Stringer`
- interface.
-
-## v7
-
-- _Important_. Tx.Pipeline now returns a non-transactional pipeline. Use Tx.TxPipeline for a
- transactional pipeline.
-- WrapProcess is replaced with more convenient AddHook that has access to context.Context.
-- WithContext now can not be used to create a shallow copy of the client.
-- New methods ProcessContext, DoContext, and ExecContext.
-- Client respects Context.Deadline when setting net.Conn deadline.
-- Client listens on Context.Done while waiting for a connection from the pool and returns an error
- when context context is cancelled.
-- Add PubSub.ChannelWithSubscriptions that sends `*Subscription` in addition to `*Message` to allow
- detecting reconnections.
-- `time.Time` is now marshalled in RFC3339 format. `rdb.Get("foo").Time()` helper is added to parse
- the time.
-- `SetLimiter` is removed and added `Options.Limiter` instead.
-- `HMSet` is deprecated as of Redis v4.
-
-## v6.15
-
-- Cluster and Ring pipelines process commands for each node in its own goroutine.
-
-## 6.14
-
-- Added Options.MinIdleConns.
-- Added Options.MaxConnAge.
-- PoolStats.FreeConns is renamed to PoolStats.IdleConns.
-- Add Client.Do to simplify creating custom commands.
-- Add Cmd.String, Cmd.Int, Cmd.Int64, Cmd.Uint64, Cmd.Float64, and Cmd.Bool helpers.
-- Lower memory usage.
-
-## v6.13
-
-- Ring got new options called `HashReplicas` and `Hash`. It is recommended to set
- `HashReplicas = 1000` for better keys distribution between shards.
-- Cluster client was optimized to use much less memory when reloading cluster state.
-- PubSub.ReceiveMessage is re-worked to not use ReceiveTimeout so it does not lose data when timeout
- occurres. In most cases it is recommended to use PubSub.Channel instead.
-- Dialer.KeepAlive is set to 5 minutes by default.
-
-## v6.12
-
-- ClusterClient got new option called `ClusterSlots` which allows to build cluster of normal Redis
- Servers that don't have cluster mode enabled. See
- https://godoc.org/github.com/go-redis/redis#example-NewClusterClient--ManualSetup
diff --git a/vendor/github.com/go-redis/redis/v8/LICENSE b/vendor/github.com/go-redis/redis/v8/LICENSE
deleted file mode 100644
index 298bed9beaf..00000000000
--- a/vendor/github.com/go-redis/redis/v8/LICENSE
+++ /dev/null
@@ -1,25 +0,0 @@
-Copyright (c) 2013 The github.com/go-redis/redis Authors.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/go-redis/redis/v8/Makefile b/vendor/github.com/go-redis/redis/v8/Makefile
deleted file mode 100644
index 49e4c96f068..00000000000
--- a/vendor/github.com/go-redis/redis/v8/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-all: testdeps
- go test ./...
- go test ./... -short -race
- go test ./... -run=NONE -bench=. -benchmem
- env GOOS=linux GOARCH=386 go test ./...
- go vet
- golangci-lint run
-
-testdeps: testdata/redis/src/redis-server
-
-bench: testdeps
- go test ./... -test.run=NONE -test.bench=. -test.benchmem
-
-.PHONY: all test testdeps bench
-
-testdata/redis:
- mkdir -p $@
- wget -qO- http://download.redis.io/redis-stable.tar.gz | tar xvz --strip-components=1 -C $@
-
-testdata/redis/src/redis-server: testdata/redis
- cd $< && make all
diff --git a/vendor/github.com/go-redis/redis/v8/README.md b/vendor/github.com/go-redis/redis/v8/README.md
deleted file mode 100644
index 28c1f0b2de1..00000000000
--- a/vendor/github.com/go-redis/redis/v8/README.md
+++ /dev/null
@@ -1,138 +0,0 @@
-# Redis client for Golang
-
-[![Build Status](https://travis-ci.org/go-redis/redis.png?branch=master)](https://travis-ci.org/go-redis/redis)
-[![PkgGoDev](https://pkg.go.dev/badge/github.com/go-redis/redis/v8)](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc)
-[![Documentation](https://img.shields.io/badge/redis-documentation-informational)](https://redis.uptrace.dev/)
-[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj)
-
-> :heart: [**Uptrace.dev** - distributed traces, logs, and errors in one place](https://uptrace.dev)
-
-- Join [Discord](https://discord.gg/rWtp5Aj) to ask questions.
-- [Documentation](https://redis.uptrace.dev)
-- [Reference](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc)
-- [Examples](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#pkg-examples)
-- [RealWorld example app](https://github.com/uptrace/go-treemux-realworld-example-app)
-
-## Ecosystem
-
-- [redisext](https://github.com/go-redis/redisext) - tracing using OpenTelemetry and OpenCensus.
-- [Distributed Locks](https://github.com/bsm/redislock).
-- [Redis Cache](https://github.com/go-redis/cache).
-- [Rate limiting](https://github.com/go-redis/redis_rate).
-
-## Features
-
-- Redis 3 commands except QUIT, MONITOR, and SYNC.
-- Automatic connection pooling with
- [circuit breaker](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern) support.
-- [Pub/Sub](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#PubSub).
-- [Transactions](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-Client-TxPipeline).
-- [Pipeline](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-Client-Pipeline) and
- [TxPipeline](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-Client-TxPipeline).
-- [Scripting](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#Script).
-- [Timeouts](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#Options).
-- [Redis Sentinel](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewFailoverClient).
-- [Redis Cluster](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewClusterClient).
-- [Cluster of Redis Servers](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-NewClusterClient--ManualSetup)
- without using cluster mode and Redis Sentinel.
-- [Ring](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewRing).
-- [Instrumentation](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#ex-package--Instrumentation).
-
-## Installation
-
-go-redis supports 2 last Go versions and requires a Go version with
-[modules](https://github.com/golang/go/wiki/Modules) support. So make sure to initialize a Go
-module:
-
-```shell
-go mod init github.com/my/repo
-```
-
-And then install go-redis (note _v8_ in the import; omitting it is a popular mistake):
-
-```shell
-go get github.com/go-redis/redis/v8
-```
-
-## Quickstart
-
-```go
-import (
- "context"
- "github.com/go-redis/redis/v8"
-)
-
-var ctx = context.Background()
-
-func ExampleClient() {
- rdb := redis.NewClient(&redis.Options{
- Addr: "localhost:6379",
- Password: "", // no password set
- DB: 0, // use default DB
- })
-
- err := rdb.Set(ctx, "key", "value", 0).Err()
- if err != nil {
- panic(err)
- }
-
- val, err := rdb.Get(ctx, "key").Result()
- if err != nil {
- panic(err)
- }
- fmt.Println("key", val)
-
- val2, err := rdb.Get(ctx, "key2").Result()
- if err == redis.Nil {
- fmt.Println("key2 does not exist")
- } else if err != nil {
- panic(err)
- } else {
- fmt.Println("key2", val2)
- }
- // Output: key value
- // key2 does not exist
-}
-```
-
-## Look and feel
-
-Some corner cases:
-
-```go
-// SET key value EX 10 NX
-set, err := rdb.SetNX(ctx, "key", "value", 10*time.Second).Result()
-
-// SET key value keepttl NX
-set, err := rdb.SetNX(ctx, "key", "value", redis.KeepTTL).Result()
-
-// SORT list LIMIT 0 2 ASC
-vals, err := rdb.Sort(ctx, "list", &redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result()
-
-// ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2
-vals, err := rdb.ZRangeByScoreWithScores(ctx, "zset", &redis.ZRangeBy{
- Min: "-inf",
- Max: "+inf",
- Offset: 0,
- Count: 2,
-}).Result()
-
-// ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM
-vals, err := rdb.ZInterStore(ctx, "out", &redis.ZStore{
- Keys: []string{"zset1", "zset2"},
- Weights: []int64{2, 3}
-}).Result()
-
-// EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello"
-vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result()
-
-// custom command
-res, err := rdb.Do(ctx, "set", "key", "value").Result()
-```
-
-## See also
-
-- [Fast and flexible HTTP router](https://github.com/vmihailenco/treemux)
-- [Golang PostgreSQL ORM](https://github.com/go-pg/pg)
-- [Golang msgpack](https://github.com/vmihailenco/msgpack)
-- [Golang message task queue](https://github.com/vmihailenco/taskq)
diff --git a/vendor/github.com/go-redis/redis/v8/cluster.go b/vendor/github.com/go-redis/redis/v8/cluster.go
deleted file mode 100644
index a6ce5c58462..00000000000
--- a/vendor/github.com/go-redis/redis/v8/cluster.go
+++ /dev/null
@@ -1,1697 +0,0 @@
-package redis
-
-import (
- "context"
- "crypto/tls"
- "fmt"
- "math"
- "net"
- "runtime"
- "sort"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/go-redis/redis/v8/internal"
- "github.com/go-redis/redis/v8/internal/hashtag"
- "github.com/go-redis/redis/v8/internal/pool"
- "github.com/go-redis/redis/v8/internal/proto"
- "github.com/go-redis/redis/v8/internal/rand"
-)
-
-var errClusterNoNodes = fmt.Errorf("redis: cluster has no nodes")
-
-// ClusterOptions are used to configure a cluster client and should be
-// passed to NewClusterClient.
-type ClusterOptions struct {
- // A seed list of host:port addresses of cluster nodes.
- Addrs []string
-
- // NewClient creates a cluster node client with provided name and options.
- NewClient func(opt *Options) *Client
-
- // The maximum number of retries before giving up. Command is retried
- // on network errors and MOVED/ASK redirects.
- // Default is 3 retries.
- MaxRedirects int
-
- // Enables read-only commands on slave nodes.
- ReadOnly bool
- // Allows routing read-only commands to the closest master or slave node.
- // It automatically enables ReadOnly.
- RouteByLatency bool
- // Allows routing read-only commands to the random master or slave node.
- // It automatically enables ReadOnly.
- RouteRandomly bool
-
- // Optional function that returns cluster slots information.
- // It is useful to manually create cluster of standalone Redis servers
- // and load-balance read/write operations between master and slaves.
- // It can use service like ZooKeeper to maintain configuration information
- // and Cluster.ReloadState to manually trigger state reloading.
- ClusterSlots func(context.Context) ([]ClusterSlot, error)
-
- // Following options are copied from Options struct.
-
- Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
-
- OnConnect func(ctx context.Context, cn *Conn) error
-
- Username string
- Password string
-
- MaxRetries int
- MinRetryBackoff time.Duration
- MaxRetryBackoff time.Duration
-
- DialTimeout time.Duration
- ReadTimeout time.Duration
- WriteTimeout time.Duration
-
- // PoolSize applies per cluster node and not for the whole cluster.
- PoolSize int
- MinIdleConns int
- MaxConnAge time.Duration
- PoolTimeout time.Duration
- IdleTimeout time.Duration
- IdleCheckFrequency time.Duration
-
- TLSConfig *tls.Config
-}
-
-func (opt *ClusterOptions) init() {
- if opt.MaxRedirects == -1 {
- opt.MaxRedirects = 0
- } else if opt.MaxRedirects == 0 {
- opt.MaxRedirects = 3
- }
-
- if (opt.RouteByLatency || opt.RouteRandomly) && opt.ClusterSlots == nil {
- opt.ReadOnly = true
- }
-
- if opt.PoolSize == 0 {
- opt.PoolSize = 5 * runtime.NumCPU()
- }
-
- switch opt.ReadTimeout {
- case -1:
- opt.ReadTimeout = 0
- case 0:
- opt.ReadTimeout = 3 * time.Second
- }
- switch opt.WriteTimeout {
- case -1:
- opt.WriteTimeout = 0
- case 0:
- opt.WriteTimeout = opt.ReadTimeout
- }
-
- if opt.MaxRetries == 0 {
- opt.MaxRetries = -1
- }
- switch opt.MinRetryBackoff {
- case -1:
- opt.MinRetryBackoff = 0
- case 0:
- opt.MinRetryBackoff = 8 * time.Millisecond
- }
- switch opt.MaxRetryBackoff {
- case -1:
- opt.MaxRetryBackoff = 0
- case 0:
- opt.MaxRetryBackoff = 512 * time.Millisecond
- }
-
- if opt.NewClient == nil {
- opt.NewClient = NewClient
- }
-}
-
-func (opt *ClusterOptions) clientOptions() *Options {
- const disableIdleCheck = -1
-
- return &Options{
- Dialer: opt.Dialer,
- OnConnect: opt.OnConnect,
-
- Username: opt.Username,
- Password: opt.Password,
-
- MaxRetries: opt.MaxRetries,
- MinRetryBackoff: opt.MinRetryBackoff,
- MaxRetryBackoff: opt.MaxRetryBackoff,
-
- DialTimeout: opt.DialTimeout,
- ReadTimeout: opt.ReadTimeout,
- WriteTimeout: opt.WriteTimeout,
-
- PoolSize: opt.PoolSize,
- MinIdleConns: opt.MinIdleConns,
- MaxConnAge: opt.MaxConnAge,
- PoolTimeout: opt.PoolTimeout,
- IdleTimeout: opt.IdleTimeout,
- IdleCheckFrequency: disableIdleCheck,
-
- readOnly: opt.ReadOnly,
-
- TLSConfig: opt.TLSConfig,
- }
-}
-
-//------------------------------------------------------------------------------
-
-type clusterNode struct {
- Client *Client
-
- latency uint32 // atomic
- generation uint32 // atomic
- failing uint32 // atomic
-}
-
-func newClusterNode(clOpt *ClusterOptions, addr string) *clusterNode {
- opt := clOpt.clientOptions()
- opt.Addr = addr
- node := clusterNode{
- Client: clOpt.NewClient(opt),
- }
-
- node.latency = math.MaxUint32
- if clOpt.RouteByLatency {
- go node.updateLatency()
- }
-
- return &node
-}
-
-func (n *clusterNode) String() string {
- return n.Client.String()
-}
-
-func (n *clusterNode) Close() error {
- return n.Client.Close()
-}
-
-func (n *clusterNode) updateLatency() {
- const numProbe = 10
- var dur uint64
-
- for i := 0; i < numProbe; i++ {
- time.Sleep(time.Duration(10+rand.Intn(10)) * time.Millisecond)
-
- start := time.Now()
- n.Client.Ping(context.TODO())
- dur += uint64(time.Since(start) / time.Microsecond)
- }
-
- latency := float64(dur) / float64(numProbe)
- atomic.StoreUint32(&n.latency, uint32(latency+0.5))
-}
-
-func (n *clusterNode) Latency() time.Duration {
- latency := atomic.LoadUint32(&n.latency)
- return time.Duration(latency) * time.Microsecond
-}
-
-func (n *clusterNode) MarkAsFailing() {
- atomic.StoreUint32(&n.failing, uint32(time.Now().Unix()))
-}
-
-func (n *clusterNode) Failing() bool {
- const timeout = 15 // 15 seconds
-
- failing := atomic.LoadUint32(&n.failing)
- if failing == 0 {
- return false
- }
- if time.Now().Unix()-int64(failing) < timeout {
- return true
- }
- atomic.StoreUint32(&n.failing, 0)
- return false
-}
-
-func (n *clusterNode) Generation() uint32 {
- return atomic.LoadUint32(&n.generation)
-}
-
-func (n *clusterNode) SetGeneration(gen uint32) {
- for {
- v := atomic.LoadUint32(&n.generation)
- if gen < v || atomic.CompareAndSwapUint32(&n.generation, v, gen) {
- break
- }
- }
-}
-
-//------------------------------------------------------------------------------
-
-type clusterNodes struct {
- opt *ClusterOptions
-
- mu sync.RWMutex
- addrs []string
- nodes map[string]*clusterNode
- activeAddrs []string
- closed bool
-
- _generation uint32 // atomic
-}
-
-func newClusterNodes(opt *ClusterOptions) *clusterNodes {
- return &clusterNodes{
- opt: opt,
-
- addrs: opt.Addrs,
- nodes: make(map[string]*clusterNode),
- }
-}
-
-func (c *clusterNodes) Close() error {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if c.closed {
- return nil
- }
- c.closed = true
-
- var firstErr error
- for _, node := range c.nodes {
- if err := node.Client.Close(); err != nil && firstErr == nil {
- firstErr = err
- }
- }
-
- c.nodes = nil
- c.activeAddrs = nil
-
- return firstErr
-}
-
-func (c *clusterNodes) Addrs() ([]string, error) {
- var addrs []string
- c.mu.RLock()
- closed := c.closed
- if !closed {
- if len(c.activeAddrs) > 0 {
- addrs = c.activeAddrs
- } else {
- addrs = c.addrs
- }
- }
- c.mu.RUnlock()
-
- if closed {
- return nil, pool.ErrClosed
- }
- if len(addrs) == 0 {
- return nil, errClusterNoNodes
- }
- return addrs, nil
-}
-
-func (c *clusterNodes) NextGeneration() uint32 {
- return atomic.AddUint32(&c._generation, 1)
-}
-
-// GC removes unused nodes.
-func (c *clusterNodes) GC(generation uint32) {
- //nolint:prealloc
- var collected []*clusterNode
-
- c.mu.Lock()
-
- c.activeAddrs = c.activeAddrs[:0]
- for addr, node := range c.nodes {
- if node.Generation() >= generation {
- c.activeAddrs = append(c.activeAddrs, addr)
- if c.opt.RouteByLatency {
- go node.updateLatency()
- }
- continue
- }
-
- delete(c.nodes, addr)
- collected = append(collected, node)
- }
-
- c.mu.Unlock()
-
- for _, node := range collected {
- _ = node.Client.Close()
- }
-}
-
-func (c *clusterNodes) Get(addr string) (*clusterNode, error) {
- node, err := c.get(addr)
- if err != nil {
- return nil, err
- }
- if node != nil {
- return node, nil
- }
-
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if c.closed {
- return nil, pool.ErrClosed
- }
-
- node, ok := c.nodes[addr]
- if ok {
- return node, nil
- }
-
- node = newClusterNode(c.opt, addr)
-
- c.addrs = appendIfNotExists(c.addrs, addr)
- c.nodes[addr] = node
-
- return node, nil
-}
-
-func (c *clusterNodes) get(addr string) (*clusterNode, error) {
- var node *clusterNode
- var err error
- c.mu.RLock()
- if c.closed {
- err = pool.ErrClosed
- } else {
- node = c.nodes[addr]
- }
- c.mu.RUnlock()
- return node, err
-}
-
-func (c *clusterNodes) All() ([]*clusterNode, error) {
- c.mu.RLock()
- defer c.mu.RUnlock()
-
- if c.closed {
- return nil, pool.ErrClosed
- }
-
- cp := make([]*clusterNode, 0, len(c.nodes))
- for _, node := range c.nodes {
- cp = append(cp, node)
- }
- return cp, nil
-}
-
-func (c *clusterNodes) Random() (*clusterNode, error) {
- addrs, err := c.Addrs()
- if err != nil {
- return nil, err
- }
-
- n := rand.Intn(len(addrs))
- return c.Get(addrs[n])
-}
-
-//------------------------------------------------------------------------------
-
-type clusterSlot struct {
- start, end int
- nodes []*clusterNode
-}
-
-type clusterSlotSlice []*clusterSlot
-
-func (p clusterSlotSlice) Len() int {
- return len(p)
-}
-
-func (p clusterSlotSlice) Less(i, j int) bool {
- return p[i].start < p[j].start
-}
-
-func (p clusterSlotSlice) Swap(i, j int) {
- p[i], p[j] = p[j], p[i]
-}
-
-type clusterState struct {
- nodes *clusterNodes
- Masters []*clusterNode
- Slaves []*clusterNode
-
- slots []*clusterSlot
-
- generation uint32
- createdAt time.Time
-}
-
-func newClusterState(
- nodes *clusterNodes, slots []ClusterSlot, origin string,
-) (*clusterState, error) {
- c := clusterState{
- nodes: nodes,
-
- slots: make([]*clusterSlot, 0, len(slots)),
-
- generation: nodes.NextGeneration(),
- createdAt: time.Now(),
- }
-
- originHost, _, _ := net.SplitHostPort(origin)
- isLoopbackOrigin := isLoopback(originHost)
-
- for _, slot := range slots {
- var nodes []*clusterNode
- for i, slotNode := range slot.Nodes {
- addr := slotNode.Addr
- if !isLoopbackOrigin {
- addr = replaceLoopbackHost(addr, originHost)
- }
-
- node, err := c.nodes.Get(addr)
- if err != nil {
- return nil, err
- }
-
- node.SetGeneration(c.generation)
- nodes = append(nodes, node)
-
- if i == 0 {
- c.Masters = appendUniqueNode(c.Masters, node)
- } else {
- c.Slaves = appendUniqueNode(c.Slaves, node)
- }
- }
-
- c.slots = append(c.slots, &clusterSlot{
- start: slot.Start,
- end: slot.End,
- nodes: nodes,
- })
- }
-
- sort.Sort(clusterSlotSlice(c.slots))
-
- time.AfterFunc(time.Minute, func() {
- nodes.GC(c.generation)
- })
-
- return &c, nil
-}
-
-func replaceLoopbackHost(nodeAddr, originHost string) string {
- nodeHost, nodePort, err := net.SplitHostPort(nodeAddr)
- if err != nil {
- return nodeAddr
- }
-
- nodeIP := net.ParseIP(nodeHost)
- if nodeIP == nil {
- return nodeAddr
- }
-
- if !nodeIP.IsLoopback() {
- return nodeAddr
- }
-
- // Use origin host which is not loopback and node port.
- return net.JoinHostPort(originHost, nodePort)
-}
-
-func isLoopback(host string) bool {
- ip := net.ParseIP(host)
- if ip == nil {
- return true
- }
- return ip.IsLoopback()
-}
-
-func (c *clusterState) slotMasterNode(slot int) (*clusterNode, error) {
- nodes := c.slotNodes(slot)
- if len(nodes) > 0 {
- return nodes[0], nil
- }
- return c.nodes.Random()
-}
-
-func (c *clusterState) slotSlaveNode(slot int) (*clusterNode, error) {
- nodes := c.slotNodes(slot)
- switch len(nodes) {
- case 0:
- return c.nodes.Random()
- case 1:
- return nodes[0], nil
- case 2:
- if slave := nodes[1]; !slave.Failing() {
- return slave, nil
- }
- return nodes[0], nil
- default:
- var slave *clusterNode
- for i := 0; i < 10; i++ {
- n := rand.Intn(len(nodes)-1) + 1
- slave = nodes[n]
- if !slave.Failing() {
- return slave, nil
- }
- }
-
- // All slaves are loading - use master.
- return nodes[0], nil
- }
-}
-
-func (c *clusterState) slotClosestNode(slot int) (*clusterNode, error) {
- nodes := c.slotNodes(slot)
- if len(nodes) == 0 {
- return c.nodes.Random()
- }
-
- var node *clusterNode
- for _, n := range nodes {
- if n.Failing() {
- continue
- }
- if node == nil || n.Latency() < node.Latency() {
- node = n
- }
- }
- if node != nil {
- return node, nil
- }
-
- // If all nodes are failing - return random node
- return c.nodes.Random()
-}
-
-func (c *clusterState) slotRandomNode(slot int) (*clusterNode, error) {
- nodes := c.slotNodes(slot)
- if len(nodes) == 0 {
- return c.nodes.Random()
- }
- n := rand.Intn(len(nodes))
- return nodes[n], nil
-}
-
-func (c *clusterState) slotNodes(slot int) []*clusterNode {
- i := sort.Search(len(c.slots), func(i int) bool {
- return c.slots[i].end >= slot
- })
- if i >= len(c.slots) {
- return nil
- }
- x := c.slots[i]
- if slot >= x.start && slot <= x.end {
- return x.nodes
- }
- return nil
-}
-
-//------------------------------------------------------------------------------
-
-type clusterStateHolder struct {
- load func(ctx context.Context) (*clusterState, error)
-
- state atomic.Value
- reloading uint32 // atomic
-}
-
-func newClusterStateHolder(fn func(ctx context.Context) (*clusterState, error)) *clusterStateHolder {
- return &clusterStateHolder{
- load: fn,
- }
-}
-
-func (c *clusterStateHolder) Reload(ctx context.Context) (*clusterState, error) {
- state, err := c.load(ctx)
- if err != nil {
- return nil, err
- }
- c.state.Store(state)
- return state, nil
-}
-
-func (c *clusterStateHolder) LazyReload(ctx context.Context) {
- if !atomic.CompareAndSwapUint32(&c.reloading, 0, 1) {
- return
- }
- go func() {
- defer atomic.StoreUint32(&c.reloading, 0)
-
- _, err := c.Reload(ctx)
- if err != nil {
- return
- }
- time.Sleep(200 * time.Millisecond)
- }()
-}
-
-func (c *clusterStateHolder) Get(ctx context.Context) (*clusterState, error) {
- v := c.state.Load()
- if v != nil {
- state := v.(*clusterState)
- if time.Since(state.createdAt) > 10*time.Second {
- c.LazyReload(ctx)
- }
- return state, nil
- }
- return c.Reload(ctx)
-}
-
-func (c *clusterStateHolder) ReloadOrGet(ctx context.Context) (*clusterState, error) {
- state, err := c.Reload(ctx)
- if err == nil {
- return state, nil
- }
- return c.Get(ctx)
-}
-
-//------------------------------------------------------------------------------
-
-type clusterClient struct {
- opt *ClusterOptions
- nodes *clusterNodes
- state *clusterStateHolder //nolint:structcheck
- cmdsInfoCache *cmdsInfoCache //nolint:structcheck
-}
-
-// ClusterClient is a Redis Cluster client representing a pool of zero
-// or more underlying connections. It's safe for concurrent use by
-// multiple goroutines.
-type ClusterClient struct {
- *clusterClient
- cmdable
- hooks
- ctx context.Context
-}
-
-// NewClusterClient returns a Redis Cluster client as described in
-// http://redis.io/topics/cluster-spec.
-func NewClusterClient(opt *ClusterOptions) *ClusterClient {
- opt.init()
-
- c := &ClusterClient{
- clusterClient: &clusterClient{
- opt: opt,
- nodes: newClusterNodes(opt),
- },
- ctx: context.Background(),
- }
- c.state = newClusterStateHolder(c.loadState)
- c.cmdsInfoCache = newCmdsInfoCache(c.cmdsInfo)
- c.cmdable = c.Process
-
- if opt.IdleCheckFrequency > 0 {
- go c.reaper(opt.IdleCheckFrequency)
- }
-
- return c
-}
-
-func (c *ClusterClient) Context() context.Context {
- return c.ctx
-}
-
-func (c *ClusterClient) WithContext(ctx context.Context) *ClusterClient {
- if ctx == nil {
- panic("nil context")
- }
- clone := *c
- clone.cmdable = clone.Process
- clone.hooks.lock()
- clone.ctx = ctx
- return &clone
-}
-
-// Options returns read-only Options that were used to create the client.
-func (c *ClusterClient) Options() *ClusterOptions {
- return c.opt
-}
-
-// ReloadState reloads cluster state. If available it calls ClusterSlots func
-// to get cluster slots information.
-func (c *ClusterClient) ReloadState(ctx context.Context) {
- c.state.LazyReload(ctx)
-}
-
-// Close closes the cluster client, releasing any open resources.
-//
-// It is rare to Close a ClusterClient, as the ClusterClient is meant
-// to be long-lived and shared between many goroutines.
-func (c *ClusterClient) Close() error {
- return c.nodes.Close()
-}
-
-// Do creates a Cmd from the args and processes the cmd.
-func (c *ClusterClient) Do(ctx context.Context, args ...interface{}) *Cmd {
- cmd := NewCmd(ctx, args...)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-func (c *ClusterClient) Process(ctx context.Context, cmd Cmder) error {
- return c.hooks.process(ctx, cmd, c.process)
-}
-
-func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error {
- cmdInfo := c.cmdInfo(cmd.Name())
- slot := c.cmdSlot(cmd)
-
- var node *clusterNode
- var ask bool
- var lastErr error
- for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
- if attempt > 0 {
- if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
- return err
- }
- }
-
- if node == nil {
- var err error
- node, err = c.cmdNode(ctx, cmdInfo, slot)
- if err != nil {
- return err
- }
- }
-
- if ask {
- pipe := node.Client.Pipeline()
- _ = pipe.Process(ctx, NewCmd(ctx, "asking"))
- _ = pipe.Process(ctx, cmd)
- _, lastErr = pipe.Exec(ctx)
- _ = pipe.Close()
- ask = false
- } else {
- lastErr = node.Client.Process(ctx, cmd)
- }
-
- // If there is no error - we are done.
- if lastErr == nil {
- return nil
- }
- if isReadOnly := isReadOnlyError(lastErr); isReadOnly || lastErr == pool.ErrClosed {
- if isReadOnly {
- c.state.LazyReload(ctx)
- }
- node = nil
- continue
- }
-
- // If slave is loading - pick another node.
- if c.opt.ReadOnly && isLoadingError(lastErr) {
- node.MarkAsFailing()
- node = nil
- continue
- }
-
- var moved bool
- var addr string
- moved, ask, addr = isMovedError(lastErr)
- if moved || ask {
- var err error
- node, err = c.nodes.Get(addr)
- if err != nil {
- return err
- }
- continue
- }
-
- if shouldRetry(lastErr, cmd.readTimeout() == nil) {
- // First retry the same node.
- if attempt == 0 {
- continue
- }
-
- // Second try another node.
- node.MarkAsFailing()
- node = nil
- continue
- }
-
- return lastErr
- }
- return lastErr
-}
-
-// ForEachMaster concurrently calls the fn on each master node in the cluster.
-// It returns the first error if any.
-func (c *ClusterClient) ForEachMaster(
- ctx context.Context,
- fn func(ctx context.Context, client *Client) error,
-) error {
- state, err := c.state.ReloadOrGet(ctx)
- if err != nil {
- return err
- }
-
- var wg sync.WaitGroup
- errCh := make(chan error, 1)
-
- for _, master := range state.Masters {
- wg.Add(1)
- go func(node *clusterNode) {
- defer wg.Done()
- err := fn(ctx, node.Client)
- if err != nil {
- select {
- case errCh <- err:
- default:
- }
- }
- }(master)
- }
-
- wg.Wait()
-
- select {
- case err := <-errCh:
- return err
- default:
- return nil
- }
-}
-
-// ForEachSlave concurrently calls the fn on each slave node in the cluster.
-// It returns the first error if any.
-func (c *ClusterClient) ForEachSlave(
- ctx context.Context,
- fn func(ctx context.Context, client *Client) error,
-) error {
- state, err := c.state.ReloadOrGet(ctx)
- if err != nil {
- return err
- }
-
- var wg sync.WaitGroup
- errCh := make(chan error, 1)
-
- for _, slave := range state.Slaves {
- wg.Add(1)
- go func(node *clusterNode) {
- defer wg.Done()
- err := fn(ctx, node.Client)
- if err != nil {
- select {
- case errCh <- err:
- default:
- }
- }
- }(slave)
- }
-
- wg.Wait()
-
- select {
- case err := <-errCh:
- return err
- default:
- return nil
- }
-}
-
-// ForEachShard concurrently calls the fn on each known node in the cluster.
-// It returns the first error if any.
-func (c *ClusterClient) ForEachShard(
- ctx context.Context,
- fn func(ctx context.Context, client *Client) error,
-) error {
- state, err := c.state.ReloadOrGet(ctx)
- if err != nil {
- return err
- }
-
- var wg sync.WaitGroup
- errCh := make(chan error, 1)
-
- worker := func(node *clusterNode) {
- defer wg.Done()
- err := fn(ctx, node.Client)
- if err != nil {
- select {
- case errCh <- err:
- default:
- }
- }
- }
-
- for _, node := range state.Masters {
- wg.Add(1)
- go worker(node)
- }
- for _, node := range state.Slaves {
- wg.Add(1)
- go worker(node)
- }
-
- wg.Wait()
-
- select {
- case err := <-errCh:
- return err
- default:
- return nil
- }
-}
-
-// PoolStats returns accumulated connection pool stats.
-func (c *ClusterClient) PoolStats() *PoolStats {
- var acc PoolStats
-
- state, _ := c.state.Get(context.TODO())
- if state == nil {
- return &acc
- }
-
- for _, node := range state.Masters {
- s := node.Client.connPool.Stats()
- acc.Hits += s.Hits
- acc.Misses += s.Misses
- acc.Timeouts += s.Timeouts
-
- acc.TotalConns += s.TotalConns
- acc.IdleConns += s.IdleConns
- acc.StaleConns += s.StaleConns
- }
-
- for _, node := range state.Slaves {
- s := node.Client.connPool.Stats()
- acc.Hits += s.Hits
- acc.Misses += s.Misses
- acc.Timeouts += s.Timeouts
-
- acc.TotalConns += s.TotalConns
- acc.IdleConns += s.IdleConns
- acc.StaleConns += s.StaleConns
- }
-
- return &acc
-}
-
-func (c *ClusterClient) loadState(ctx context.Context) (*clusterState, error) {
- if c.opt.ClusterSlots != nil {
- slots, err := c.opt.ClusterSlots(ctx)
- if err != nil {
- return nil, err
- }
- return newClusterState(c.nodes, slots, "")
- }
-
- addrs, err := c.nodes.Addrs()
- if err != nil {
- return nil, err
- }
-
- var firstErr error
-
- for _, idx := range rand.Perm(len(addrs)) {
- addr := addrs[idx]
-
- node, err := c.nodes.Get(addr)
- if err != nil {
- if firstErr == nil {
- firstErr = err
- }
- continue
- }
-
- slots, err := node.Client.ClusterSlots(ctx).Result()
- if err != nil {
- if firstErr == nil {
- firstErr = err
- }
- continue
- }
-
- return newClusterState(c.nodes, slots, node.Client.opt.Addr)
- }
-
- /*
- * No node is connectable. It's possible that all nodes' IP has changed.
- * Clear activeAddrs to let client be able to re-connect using the initial
- * setting of the addresses (e.g. [redis-cluster-0:6379, redis-cluster-1:6379]),
- * which might have chance to resolve domain name and get updated IP address.
- */
- c.nodes.mu.Lock()
- c.nodes.activeAddrs = nil
- c.nodes.mu.Unlock()
-
- return nil, firstErr
-}
-
-// reaper closes idle connections to the cluster.
-func (c *ClusterClient) reaper(idleCheckFrequency time.Duration) {
- ticker := time.NewTicker(idleCheckFrequency)
- defer ticker.Stop()
-
- for range ticker.C {
- nodes, err := c.nodes.All()
- if err != nil {
- break
- }
-
- for _, node := range nodes {
- _, err := node.Client.connPool.(*pool.ConnPool).ReapStaleConns()
- if err != nil {
- internal.Logger.Printf(c.Context(), "ReapStaleConns failed: %s", err)
- }
- }
- }
-}
-
-func (c *ClusterClient) Pipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: c.processPipeline,
- }
- pipe.init()
- return &pipe
-}
-
-func (c *ClusterClient) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.Pipeline().Pipelined(ctx, fn)
-}
-
-func (c *ClusterClient) processPipeline(ctx context.Context, cmds []Cmder) error {
- return c.hooks.processPipeline(ctx, cmds, c._processPipeline)
-}
-
-func (c *ClusterClient) _processPipeline(ctx context.Context, cmds []Cmder) error {
- cmdsMap := newCmdsMap()
- err := c.mapCmdsByNode(ctx, cmdsMap, cmds)
- if err != nil {
- setCmdsErr(cmds, err)
- return err
- }
-
- for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
- if attempt > 0 {
- if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
- setCmdsErr(cmds, err)
- return err
- }
- }
-
- failedCmds := newCmdsMap()
- var wg sync.WaitGroup
-
- for node, cmds := range cmdsMap.m {
- wg.Add(1)
- go func(node *clusterNode, cmds []Cmder) {
- defer wg.Done()
-
- err := c._processPipelineNode(ctx, node, cmds, failedCmds)
- if err == nil {
- return
- }
- if attempt < c.opt.MaxRedirects {
- if err := c.mapCmdsByNode(ctx, failedCmds, cmds); err != nil {
- setCmdsErr(cmds, err)
- }
- } else {
- setCmdsErr(cmds, err)
- }
- }(node, cmds)
- }
-
- wg.Wait()
- if len(failedCmds.m) == 0 {
- break
- }
- cmdsMap = failedCmds
- }
-
- return cmdsFirstErr(cmds)
-}
-
-func (c *ClusterClient) mapCmdsByNode(ctx context.Context, cmdsMap *cmdsMap, cmds []Cmder) error {
- state, err := c.state.Get(ctx)
- if err != nil {
- return err
- }
-
- if c.opt.ReadOnly && c.cmdsAreReadOnly(cmds) {
- for _, cmd := range cmds {
- slot := c.cmdSlot(cmd)
- node, err := c.slotReadOnlyNode(state, slot)
- if err != nil {
- return err
- }
- cmdsMap.Add(node, cmd)
- }
- return nil
- }
-
- for _, cmd := range cmds {
- slot := c.cmdSlot(cmd)
- node, err := state.slotMasterNode(slot)
- if err != nil {
- return err
- }
- cmdsMap.Add(node, cmd)
- }
- return nil
-}
-
-func (c *ClusterClient) cmdsAreReadOnly(cmds []Cmder) bool {
- for _, cmd := range cmds {
- cmdInfo := c.cmdInfo(cmd.Name())
- if cmdInfo == nil || !cmdInfo.ReadOnly {
- return false
- }
- }
- return true
-}
-
-func (c *ClusterClient) _processPipelineNode(
- ctx context.Context, node *clusterNode, cmds []Cmder, failedCmds *cmdsMap,
-) error {
- return node.Client.hooks.processPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error {
- return node.Client.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error {
- err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
- return writeCmds(wr, cmds)
- })
- if err != nil {
- return err
- }
-
- return cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error {
- return c.pipelineReadCmds(ctx, node, rd, cmds, failedCmds)
- })
- })
- })
-}
-
-func (c *ClusterClient) pipelineReadCmds(
- ctx context.Context,
- node *clusterNode,
- rd *proto.Reader,
- cmds []Cmder,
- failedCmds *cmdsMap,
-) error {
- for _, cmd := range cmds {
- err := cmd.readReply(rd)
- cmd.SetErr(err)
-
- if err == nil {
- continue
- }
-
- if c.checkMovedErr(ctx, cmd, err, failedCmds) {
- continue
- }
-
- if c.opt.ReadOnly && isLoadingError(err) {
- node.MarkAsFailing()
- return err
- }
- if isRedisError(err) {
- continue
- }
- return err
- }
- return nil
-}
-
-func (c *ClusterClient) checkMovedErr(
- ctx context.Context, cmd Cmder, err error, failedCmds *cmdsMap,
-) bool {
- moved, ask, addr := isMovedError(err)
- if !moved && !ask {
- return false
- }
-
- node, err := c.nodes.Get(addr)
- if err != nil {
- return false
- }
-
- if moved {
- c.state.LazyReload(ctx)
- failedCmds.Add(node, cmd)
- return true
- }
-
- if ask {
- failedCmds.Add(node, NewCmd(ctx, "asking"), cmd)
- return true
- }
-
- panic("not reached")
-}
-
-// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
-func (c *ClusterClient) TxPipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: c.processTxPipeline,
- }
- pipe.init()
- return &pipe
-}
-
-func (c *ClusterClient) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.TxPipeline().Pipelined(ctx, fn)
-}
-
-func (c *ClusterClient) processTxPipeline(ctx context.Context, cmds []Cmder) error {
- return c.hooks.processPipeline(ctx, cmds, c._processTxPipeline)
-}
-
-func (c *ClusterClient) _processTxPipeline(ctx context.Context, cmds []Cmder) error {
- state, err := c.state.Get(ctx)
- if err != nil {
- setCmdsErr(cmds, err)
- return err
- }
-
- cmdsMap := c.mapCmdsBySlot(cmds)
- for slot, cmds := range cmdsMap {
- node, err := state.slotMasterNode(slot)
- if err != nil {
- setCmdsErr(cmds, err)
- continue
- }
-
- cmdsMap := map[*clusterNode][]Cmder{node: cmds}
- for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
- if attempt > 0 {
- if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
- setCmdsErr(cmds, err)
- return err
- }
- }
-
- failedCmds := newCmdsMap()
- var wg sync.WaitGroup
-
- for node, cmds := range cmdsMap {
- wg.Add(1)
- go func(node *clusterNode, cmds []Cmder) {
- defer wg.Done()
-
- err := c._processTxPipelineNode(ctx, node, cmds, failedCmds)
- if err == nil {
- return
- }
- if attempt < c.opt.MaxRedirects {
- if err := c.mapCmdsByNode(ctx, failedCmds, cmds); err != nil {
- setCmdsErr(cmds, err)
- }
- } else {
- setCmdsErr(cmds, err)
- }
- }(node, cmds)
- }
-
- wg.Wait()
- if len(failedCmds.m) == 0 {
- break
- }
- cmdsMap = failedCmds.m
- }
- }
-
- return cmdsFirstErr(cmds)
-}
-
-func (c *ClusterClient) mapCmdsBySlot(cmds []Cmder) map[int][]Cmder {
- cmdsMap := make(map[int][]Cmder)
- for _, cmd := range cmds {
- slot := c.cmdSlot(cmd)
- cmdsMap[slot] = append(cmdsMap[slot], cmd)
- }
- return cmdsMap
-}
-
-func (c *ClusterClient) _processTxPipelineNode(
- ctx context.Context, node *clusterNode, cmds []Cmder, failedCmds *cmdsMap,
-) error {
- return node.Client.hooks.processTxPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error {
- return node.Client.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error {
- err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
- return writeCmds(wr, cmds)
- })
- if err != nil {
- return err
- }
-
- return cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error {
- statusCmd := cmds[0].(*StatusCmd)
- // Trim multi and exec.
- cmds = cmds[1 : len(cmds)-1]
-
- err := c.txPipelineReadQueued(ctx, rd, statusCmd, cmds, failedCmds)
- if err != nil {
- moved, ask, addr := isMovedError(err)
- if moved || ask {
- return c.cmdsMoved(ctx, cmds, moved, ask, addr, failedCmds)
- }
- return err
- }
-
- return pipelineReadCmds(rd, cmds)
- })
- })
- })
-}
-
-func (c *ClusterClient) txPipelineReadQueued(
- ctx context.Context,
- rd *proto.Reader,
- statusCmd *StatusCmd,
- cmds []Cmder,
- failedCmds *cmdsMap,
-) error {
- // Parse queued replies.
- if err := statusCmd.readReply(rd); err != nil {
- return err
- }
-
- for _, cmd := range cmds {
- err := statusCmd.readReply(rd)
- if err == nil || c.checkMovedErr(ctx, cmd, err, failedCmds) || isRedisError(err) {
- continue
- }
- return err
- }
-
- // Parse number of replies.
- line, err := rd.ReadLine()
- if err != nil {
- if err == Nil {
- err = TxFailedErr
- }
- return err
- }
-
- switch line[0] {
- case proto.ErrorReply:
- return proto.ParseErrorReply(line)
- case proto.ArrayReply:
- // ok
- default:
- return fmt.Errorf("redis: expected '*', but got line %q", line)
- }
-
- return nil
-}
-
-func (c *ClusterClient) cmdsMoved(
- ctx context.Context, cmds []Cmder,
- moved, ask bool,
- addr string,
- failedCmds *cmdsMap,
-) error {
- node, err := c.nodes.Get(addr)
- if err != nil {
- return err
- }
-
- if moved {
- c.state.LazyReload(ctx)
- for _, cmd := range cmds {
- failedCmds.Add(node, cmd)
- }
- return nil
- }
-
- if ask {
- for _, cmd := range cmds {
- failedCmds.Add(node, NewCmd(ctx, "asking"), cmd)
- }
- return nil
- }
-
- return nil
-}
-
-func (c *ClusterClient) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error {
- if len(keys) == 0 {
- return fmt.Errorf("redis: Watch requires at least one key")
- }
-
- slot := hashtag.Slot(keys[0])
- for _, key := range keys[1:] {
- if hashtag.Slot(key) != slot {
- err := fmt.Errorf("redis: Watch requires all keys to be in the same slot")
- return err
- }
- }
-
- node, err := c.slotMasterNode(ctx, slot)
- if err != nil {
- return err
- }
-
- for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ {
- if attempt > 0 {
- if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
- return err
- }
- }
-
- err = node.Client.Watch(ctx, fn, keys...)
- if err == nil {
- break
- }
-
- moved, ask, addr := isMovedError(err)
- if moved || ask {
- node, err = c.nodes.Get(addr)
- if err != nil {
- return err
- }
- continue
- }
-
- if isReadOnly := isReadOnlyError(err); isReadOnly || err == pool.ErrClosed {
- if isReadOnly {
- c.state.LazyReload(ctx)
- }
- node, err = c.slotMasterNode(ctx, slot)
- if err != nil {
- return err
- }
- continue
- }
-
- if shouldRetry(err, true) {
- continue
- }
-
- return err
- }
-
- return err
-}
-
-func (c *ClusterClient) pubSub() *PubSub {
- var node *clusterNode
- pubsub := &PubSub{
- opt: c.opt.clientOptions(),
-
- newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) {
- if node != nil {
- panic("node != nil")
- }
-
- var err error
- if len(channels) > 0 {
- slot := hashtag.Slot(channels[0])
- node, err = c.slotMasterNode(ctx, slot)
- } else {
- node, err = c.nodes.Random()
- }
- if err != nil {
- return nil, err
- }
-
- cn, err := node.Client.newConn(context.TODO())
- if err != nil {
- node = nil
-
- return nil, err
- }
-
- return cn, nil
- },
- closeConn: func(cn *pool.Conn) error {
- err := node.Client.connPool.CloseConn(cn)
- node = nil
- return err
- },
- }
- pubsub.init()
-
- return pubsub
-}
-
-// Subscribe subscribes the client to the specified channels.
-// Channels can be omitted to create empty subscription.
-func (c *ClusterClient) Subscribe(ctx context.Context, channels ...string) *PubSub {
- pubsub := c.pubSub()
- if len(channels) > 0 {
- _ = pubsub.Subscribe(ctx, channels...)
- }
- return pubsub
-}
-
-// PSubscribe subscribes the client to the given patterns.
-// Patterns can be omitted to create empty subscription.
-func (c *ClusterClient) PSubscribe(ctx context.Context, channels ...string) *PubSub {
- pubsub := c.pubSub()
- if len(channels) > 0 {
- _ = pubsub.PSubscribe(ctx, channels...)
- }
- return pubsub
-}
-
-func (c *ClusterClient) retryBackoff(attempt int) time.Duration {
- return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff)
-}
-
-func (c *ClusterClient) cmdsInfo(ctx context.Context) (map[string]*CommandInfo, error) {
- // Try 3 random nodes.
- const nodeLimit = 3
-
- addrs, err := c.nodes.Addrs()
- if err != nil {
- return nil, err
- }
-
- var firstErr error
-
- perm := rand.Perm(len(addrs))
- if len(perm) > nodeLimit {
- perm = perm[:nodeLimit]
- }
-
- for _, idx := range perm {
- addr := addrs[idx]
-
- node, err := c.nodes.Get(addr)
- if err != nil {
- if firstErr == nil {
- firstErr = err
- }
- continue
- }
-
- info, err := node.Client.Command(ctx).Result()
- if err == nil {
- return info, nil
- }
- if firstErr == nil {
- firstErr = err
- }
- }
-
- if firstErr == nil {
- panic("not reached")
- }
- return nil, firstErr
-}
-
-func (c *ClusterClient) cmdInfo(name string) *CommandInfo {
- cmdsInfo, err := c.cmdsInfoCache.Get(c.ctx)
- if err != nil {
- return nil
- }
-
- info := cmdsInfo[name]
- if info == nil {
- internal.Logger.Printf(c.Context(), "info for cmd=%s not found", name)
- }
- return info
-}
-
-func (c *ClusterClient) cmdSlot(cmd Cmder) int {
- args := cmd.Args()
- if args[0] == "cluster" && args[1] == "getkeysinslot" {
- return args[2].(int)
- }
-
- cmdInfo := c.cmdInfo(cmd.Name())
- return cmdSlot(cmd, cmdFirstKeyPos(cmd, cmdInfo))
-}
-
-func cmdSlot(cmd Cmder, pos int) int {
- if pos == 0 {
- return hashtag.RandomSlot()
- }
- firstKey := cmd.stringArg(pos)
- return hashtag.Slot(firstKey)
-}
-
-func (c *ClusterClient) cmdNode(
- ctx context.Context,
- cmdInfo *CommandInfo,
- slot int,
-) (*clusterNode, error) {
- state, err := c.state.Get(ctx)
- if err != nil {
- return nil, err
- }
-
- if (c.opt.RouteByLatency || c.opt.RouteRandomly) && cmdInfo != nil && cmdInfo.ReadOnly {
- return c.slotReadOnlyNode(state, slot)
- }
- return state.slotMasterNode(slot)
-}
-
-func (c *clusterClient) slotReadOnlyNode(state *clusterState, slot int) (*clusterNode, error) {
- if c.opt.RouteByLatency {
- return state.slotClosestNode(slot)
- }
- if c.opt.RouteRandomly {
- return state.slotRandomNode(slot)
- }
- return state.slotSlaveNode(slot)
-}
-
-func (c *ClusterClient) slotMasterNode(ctx context.Context, slot int) (*clusterNode, error) {
- state, err := c.state.Get(ctx)
- if err != nil {
- return nil, err
- }
- return state.slotMasterNode(slot)
-}
-
-func appendUniqueNode(nodes []*clusterNode, node *clusterNode) []*clusterNode {
- for _, n := range nodes {
- if n == node {
- return nodes
- }
- }
- return append(nodes, node)
-}
-
-func appendIfNotExists(ss []string, es ...string) []string {
-loop:
- for _, e := range es {
- for _, s := range ss {
- if s == e {
- continue loop
- }
- }
- ss = append(ss, e)
- }
- return ss
-}
-
-//------------------------------------------------------------------------------
-
-type cmdsMap struct {
- mu sync.Mutex
- m map[*clusterNode][]Cmder
-}
-
-func newCmdsMap() *cmdsMap {
- return &cmdsMap{
- m: make(map[*clusterNode][]Cmder),
- }
-}
-
-func (m *cmdsMap) Add(node *clusterNode, cmds ...Cmder) {
- m.mu.Lock()
- m.m[node] = append(m.m[node], cmds...)
- m.mu.Unlock()
-}
diff --git a/vendor/github.com/go-redis/redis/v8/cluster_commands.go b/vendor/github.com/go-redis/redis/v8/cluster_commands.go
deleted file mode 100644
index 1f0bae067ae..00000000000
--- a/vendor/github.com/go-redis/redis/v8/cluster_commands.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package redis
-
-import (
- "context"
- "sync/atomic"
-)
-
-func (c *ClusterClient) DBSize(ctx context.Context) *IntCmd {
- cmd := NewIntCmd(ctx, "dbsize")
- var size int64
- err := c.ForEachMaster(ctx, func(ctx context.Context, master *Client) error {
- n, err := master.DBSize(ctx).Result()
- if err != nil {
- return err
- }
- atomic.AddInt64(&size, n)
- return nil
- })
- if err != nil {
- cmd.SetErr(err)
- return cmd
- }
- cmd.val = size
- return cmd
-}
diff --git a/vendor/github.com/go-redis/redis/v8/command.go b/vendor/github.com/go-redis/redis/v8/command.go
deleted file mode 100644
index 5dd55332503..00000000000
--- a/vendor/github.com/go-redis/redis/v8/command.go
+++ /dev/null
@@ -1,2396 +0,0 @@
-package redis
-
-import (
- "context"
- "fmt"
- "net"
- "strconv"
- "time"
-
- "github.com/go-redis/redis/v8/internal"
- "github.com/go-redis/redis/v8/internal/proto"
- "github.com/go-redis/redis/v8/internal/util"
-)
-
-type Cmder interface {
- Name() string
- FullName() string
- Args() []interface{}
- String() string
- stringArg(int) string
- firstKeyPos() int8
- setFirstKeyPos(int8)
-
- readTimeout() *time.Duration
- readReply(rd *proto.Reader) error
-
- SetErr(error)
- Err() error
-}
-
-func setCmdsErr(cmds []Cmder, e error) {
- for _, cmd := range cmds {
- if cmd.Err() == nil {
- cmd.SetErr(e)
- }
- }
-}
-
-func cmdsFirstErr(cmds []Cmder) error {
- for _, cmd := range cmds {
- if err := cmd.Err(); err != nil {
- return err
- }
- }
- return nil
-}
-
-func writeCmds(wr *proto.Writer, cmds []Cmder) error {
- for _, cmd := range cmds {
- if err := writeCmd(wr, cmd); err != nil {
- return err
- }
- }
- return nil
-}
-
-func writeCmd(wr *proto.Writer, cmd Cmder) error {
- return wr.WriteArgs(cmd.Args())
-}
-
-func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
- if pos := cmd.firstKeyPos(); pos != 0 {
- return int(pos)
- }
-
- switch cmd.Name() {
- case "eval", "evalsha":
- if cmd.stringArg(2) != "0" {
- return 3
- }
-
- return 0
- case "publish":
- return 1
- case "memory":
- // https://github.com/redis/redis/issues/7493
- if cmd.stringArg(1) == "usage" {
- return 2
- }
- }
-
- if info != nil {
- return int(info.FirstKeyPos)
- }
- return 0
-}
-
-func cmdString(cmd Cmder, val interface{}) string {
- b := make([]byte, 0, 64)
-
- for i, arg := range cmd.Args() {
- if i > 0 {
- b = append(b, ' ')
- }
- b = internal.AppendArg(b, arg)
- }
-
- if err := cmd.Err(); err != nil {
- b = append(b, ": "...)
- b = append(b, err.Error()...)
- } else if val != nil {
- b = append(b, ": "...)
- b = internal.AppendArg(b, val)
- }
-
- return internal.String(b)
-}
-
-//------------------------------------------------------------------------------
-
-type baseCmd struct {
- ctx context.Context
- args []interface{}
- err error
- keyPos int8
-
- _readTimeout *time.Duration
-}
-
-var _ Cmder = (*Cmd)(nil)
-
-func (cmd *baseCmd) Name() string {
- if len(cmd.args) == 0 {
- return ""
- }
- // Cmd name must be lower cased.
- return internal.ToLower(cmd.stringArg(0))
-}
-
-func (cmd *baseCmd) FullName() string {
- switch name := cmd.Name(); name {
- case "cluster", "command":
- if len(cmd.args) == 1 {
- return name
- }
- if s2, ok := cmd.args[1].(string); ok {
- return name + " " + s2
- }
- return name
- default:
- return name
- }
-}
-
-func (cmd *baseCmd) Args() []interface{} {
- return cmd.args
-}
-
-func (cmd *baseCmd) stringArg(pos int) string {
- if pos < 0 || pos >= len(cmd.args) {
- return ""
- }
- s, _ := cmd.args[pos].(string)
- return s
-}
-
-func (cmd *baseCmd) firstKeyPos() int8 {
- return cmd.keyPos
-}
-
-func (cmd *baseCmd) setFirstKeyPos(keyPos int8) {
- cmd.keyPos = keyPos
-}
-
-func (cmd *baseCmd) SetErr(e error) {
- cmd.err = e
-}
-
-func (cmd *baseCmd) Err() error {
- return cmd.err
-}
-
-func (cmd *baseCmd) readTimeout() *time.Duration {
- return cmd._readTimeout
-}
-
-func (cmd *baseCmd) setReadTimeout(d time.Duration) {
- cmd._readTimeout = &d
-}
-
-//------------------------------------------------------------------------------
-
-type Cmd struct {
- baseCmd
-
- val interface{}
-}
-
-func NewCmd(ctx context.Context, args ...interface{}) *Cmd {
- return &Cmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *Cmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *Cmd) Val() interface{} {
- return cmd.val
-}
-
-func (cmd *Cmd) Result() (interface{}, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *Cmd) Text() (string, error) {
- if cmd.err != nil {
- return "", cmd.err
- }
- switch val := cmd.val.(type) {
- case string:
- return val, nil
- default:
- err := fmt.Errorf("redis: unexpected type=%T for String", val)
- return "", err
- }
-}
-
-func (cmd *Cmd) Int() (int, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- switch val := cmd.val.(type) {
- case int64:
- return int(val), nil
- case string:
- return strconv.Atoi(val)
- default:
- err := fmt.Errorf("redis: unexpected type=%T for Int", val)
- return 0, err
- }
-}
-
-func (cmd *Cmd) Int64() (int64, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- switch val := cmd.val.(type) {
- case int64:
- return val, nil
- case string:
- return strconv.ParseInt(val, 10, 64)
- default:
- err := fmt.Errorf("redis: unexpected type=%T for Int64", val)
- return 0, err
- }
-}
-
-func (cmd *Cmd) Uint64() (uint64, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- switch val := cmd.val.(type) {
- case int64:
- return uint64(val), nil
- case string:
- return strconv.ParseUint(val, 10, 64)
- default:
- err := fmt.Errorf("redis: unexpected type=%T for Uint64", val)
- return 0, err
- }
-}
-
-func (cmd *Cmd) Float32() (float32, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- switch val := cmd.val.(type) {
- case int64:
- return float32(val), nil
- case string:
- f, err := strconv.ParseFloat(val, 32)
- if err != nil {
- return 0, err
- }
- return float32(f), nil
- default:
- err := fmt.Errorf("redis: unexpected type=%T for Float32", val)
- return 0, err
- }
-}
-
-func (cmd *Cmd) Float64() (float64, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- switch val := cmd.val.(type) {
- case int64:
- return float64(val), nil
- case string:
- return strconv.ParseFloat(val, 64)
- default:
- err := fmt.Errorf("redis: unexpected type=%T for Float64", val)
- return 0, err
- }
-}
-
-func (cmd *Cmd) Bool() (bool, error) {
- if cmd.err != nil {
- return false, cmd.err
- }
- switch val := cmd.val.(type) {
- case int64:
- return val != 0, nil
- case string:
- return strconv.ParseBool(val)
- default:
- err := fmt.Errorf("redis: unexpected type=%T for Bool", val)
- return false, err
- }
-}
-
-func (cmd *Cmd) readReply(rd *proto.Reader) (err error) {
- cmd.val, err = rd.ReadReply(sliceParser)
- return err
-}
-
-// sliceParser implements proto.MultiBulkParse.
-func sliceParser(rd *proto.Reader, n int64) (interface{}, error) {
- vals := make([]interface{}, n)
- for i := 0; i < len(vals); i++ {
- v, err := rd.ReadReply(sliceParser)
- if err != nil {
- if err == Nil {
- vals[i] = nil
- continue
- }
- if err, ok := err.(proto.RedisError); ok {
- vals[i] = err
- continue
- }
- return nil, err
- }
- vals[i] = v
- }
- return vals, nil
-}
-
-//------------------------------------------------------------------------------
-
-type SliceCmd struct {
- baseCmd
-
- val []interface{}
-}
-
-var _ Cmder = (*SliceCmd)(nil)
-
-func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd {
- return &SliceCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *SliceCmd) Val() []interface{} {
- return cmd.val
-}
-
-func (cmd *SliceCmd) Result() ([]interface{}, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *SliceCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *SliceCmd) readReply(rd *proto.Reader) error {
- v, err := rd.ReadArrayReply(sliceParser)
- if err != nil {
- return err
- }
- cmd.val = v.([]interface{})
- return nil
-}
-
-//------------------------------------------------------------------------------
-
-type StatusCmd struct {
- baseCmd
-
- val string
-}
-
-var _ Cmder = (*StatusCmd)(nil)
-
-func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd {
- return &StatusCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *StatusCmd) Val() string {
- return cmd.val
-}
-
-func (cmd *StatusCmd) Result() (string, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *StatusCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) {
- cmd.val, err = rd.ReadString()
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type IntCmd struct {
- baseCmd
-
- val int64
-}
-
-var _ Cmder = (*IntCmd)(nil)
-
-func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd {
- return &IntCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *IntCmd) Val() int64 {
- return cmd.val
-}
-
-func (cmd *IntCmd) Result() (int64, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *IntCmd) Uint64() (uint64, error) {
- return uint64(cmd.val), cmd.err
-}
-
-func (cmd *IntCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) {
- cmd.val, err = rd.ReadIntReply()
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type IntSliceCmd struct {
- baseCmd
-
- val []int64
-}
-
-var _ Cmder = (*IntSliceCmd)(nil)
-
-func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd {
- return &IntSliceCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *IntSliceCmd) Val() []int64 {
- return cmd.val
-}
-
-func (cmd *IntSliceCmd) Result() ([]int64, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *IntSliceCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make([]int64, n)
- for i := 0; i < len(cmd.val); i++ {
- num, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
- cmd.val[i] = num
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type DurationCmd struct {
- baseCmd
-
- val time.Duration
- precision time.Duration
-}
-
-var _ Cmder = (*DurationCmd)(nil)
-
-func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd {
- return &DurationCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- precision: precision,
- }
-}
-
-func (cmd *DurationCmd) Val() time.Duration {
- return cmd.val
-}
-
-func (cmd *DurationCmd) Result() (time.Duration, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *DurationCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *DurationCmd) readReply(rd *proto.Reader) error {
- n, err := rd.ReadIntReply()
- if err != nil {
- return err
- }
- switch n {
- // -2 if the key does not exist
- // -1 if the key exists but has no associated expire
- case -2, -1:
- cmd.val = time.Duration(n)
- default:
- cmd.val = time.Duration(n) * cmd.precision
- }
- return nil
-}
-
-//------------------------------------------------------------------------------
-
-type TimeCmd struct {
- baseCmd
-
- val time.Time
-}
-
-var _ Cmder = (*TimeCmd)(nil)
-
-func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd {
- return &TimeCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *TimeCmd) Val() time.Time {
- return cmd.val
-}
-
-func (cmd *TimeCmd) Result() (time.Time, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *TimeCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *TimeCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- if n != 2 {
- return nil, fmt.Errorf("got %d elements, expected 2", n)
- }
-
- sec, err := rd.ReadInt()
- if err != nil {
- return nil, err
- }
-
- microsec, err := rd.ReadInt()
- if err != nil {
- return nil, err
- }
-
- cmd.val = time.Unix(sec, microsec*1000)
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type BoolCmd struct {
- baseCmd
-
- val bool
-}
-
-var _ Cmder = (*BoolCmd)(nil)
-
-func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd {
- return &BoolCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *BoolCmd) Val() bool {
- return cmd.val
-}
-
-func (cmd *BoolCmd) Result() (bool, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *BoolCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *BoolCmd) readReply(rd *proto.Reader) error {
- v, err := rd.ReadReply(nil)
- // `SET key value NX` returns nil when key already exists. But
- // `SETNX key value` returns bool (0/1). So convert nil to bool.
- if err == Nil {
- cmd.val = false
- return nil
- }
- if err != nil {
- return err
- }
- switch v := v.(type) {
- case int64:
- cmd.val = v == 1
- return nil
- case string:
- cmd.val = v == "OK"
- return nil
- default:
- return fmt.Errorf("got %T, wanted int64 or string", v)
- }
-}
-
-//------------------------------------------------------------------------------
-
-type StringCmd struct {
- baseCmd
-
- val string
-}
-
-var _ Cmder = (*StringCmd)(nil)
-
-func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd {
- return &StringCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *StringCmd) Val() string {
- return cmd.val
-}
-
-func (cmd *StringCmd) Result() (string, error) {
- return cmd.Val(), cmd.err
-}
-
-func (cmd *StringCmd) Bytes() ([]byte, error) {
- return util.StringToBytes(cmd.val), cmd.err
-}
-
-func (cmd *StringCmd) Int() (int, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- return strconv.Atoi(cmd.Val())
-}
-
-func (cmd *StringCmd) Int64() (int64, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- return strconv.ParseInt(cmd.Val(), 10, 64)
-}
-
-func (cmd *StringCmd) Uint64() (uint64, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- return strconv.ParseUint(cmd.Val(), 10, 64)
-}
-
-func (cmd *StringCmd) Float32() (float32, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- f, err := strconv.ParseFloat(cmd.Val(), 32)
- if err != nil {
- return 0, err
- }
- return float32(f), nil
-}
-
-func (cmd *StringCmd) Float64() (float64, error) {
- if cmd.err != nil {
- return 0, cmd.err
- }
- return strconv.ParseFloat(cmd.Val(), 64)
-}
-
-func (cmd *StringCmd) Time() (time.Time, error) {
- if cmd.err != nil {
- return time.Time{}, cmd.err
- }
- return time.Parse(time.RFC3339Nano, cmd.Val())
-}
-
-func (cmd *StringCmd) Scan(val interface{}) error {
- if cmd.err != nil {
- return cmd.err
- }
- return proto.Scan([]byte(cmd.val), val)
-}
-
-func (cmd *StringCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) {
- cmd.val, err = rd.ReadString()
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type FloatCmd struct {
- baseCmd
-
- val float64
-}
-
-var _ Cmder = (*FloatCmd)(nil)
-
-func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd {
- return &FloatCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *FloatCmd) Val() float64 {
- return cmd.val
-}
-
-func (cmd *FloatCmd) Result() (float64, error) {
- return cmd.Val(), cmd.Err()
-}
-
-func (cmd *FloatCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) {
- cmd.val, err = rd.ReadFloatReply()
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type StringSliceCmd struct {
- baseCmd
-
- val []string
-}
-
-var _ Cmder = (*StringSliceCmd)(nil)
-
-func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd {
- return &StringSliceCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *StringSliceCmd) Val() []string {
- return cmd.val
-}
-
-func (cmd *StringSliceCmd) Result() ([]string, error) {
- return cmd.Val(), cmd.Err()
-}
-
-func (cmd *StringSliceCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *StringSliceCmd) ScanSlice(container interface{}) error {
- return proto.ScanSlice(cmd.Val(), container)
-}
-
-func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make([]string, n)
- for i := 0; i < len(cmd.val); i++ {
- switch s, err := rd.ReadString(); {
- case err == Nil:
- cmd.val[i] = ""
- case err != nil:
- return nil, err
- default:
- cmd.val[i] = s
- }
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type BoolSliceCmd struct {
- baseCmd
-
- val []bool
-}
-
-var _ Cmder = (*BoolSliceCmd)(nil)
-
-func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd {
- return &BoolSliceCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *BoolSliceCmd) Val() []bool {
- return cmd.val
-}
-
-func (cmd *BoolSliceCmd) Result() ([]bool, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *BoolSliceCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make([]bool, n)
- for i := 0; i < len(cmd.val); i++ {
- n, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
- cmd.val[i] = n == 1
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type StringStringMapCmd struct {
- baseCmd
-
- val map[string]string
-}
-
-var _ Cmder = (*StringStringMapCmd)(nil)
-
-func NewStringStringMapCmd(ctx context.Context, args ...interface{}) *StringStringMapCmd {
- return &StringStringMapCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *StringStringMapCmd) Val() map[string]string {
- return cmd.val
-}
-
-func (cmd *StringStringMapCmd) Result() (map[string]string, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *StringStringMapCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *StringStringMapCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make(map[string]string, n/2)
- for i := int64(0); i < n; i += 2 {
- key, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- value, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- cmd.val[key] = value
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type StringIntMapCmd struct {
- baseCmd
-
- val map[string]int64
-}
-
-var _ Cmder = (*StringIntMapCmd)(nil)
-
-func NewStringIntMapCmd(ctx context.Context, args ...interface{}) *StringIntMapCmd {
- return &StringIntMapCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *StringIntMapCmd) Val() map[string]int64 {
- return cmd.val
-}
-
-func (cmd *StringIntMapCmd) Result() (map[string]int64, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *StringIntMapCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *StringIntMapCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make(map[string]int64, n/2)
- for i := int64(0); i < n; i += 2 {
- key, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- n, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
-
- cmd.val[key] = n
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type StringStructMapCmd struct {
- baseCmd
-
- val map[string]struct{}
-}
-
-var _ Cmder = (*StringStructMapCmd)(nil)
-
-func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd {
- return &StringStructMapCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *StringStructMapCmd) Val() map[string]struct{} {
- return cmd.val
-}
-
-func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *StringStructMapCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make(map[string]struct{}, n)
- for i := int64(0); i < n; i++ {
- key, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
- cmd.val[key] = struct{}{}
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type XMessage struct {
- ID string
- Values map[string]interface{}
-}
-
-type XMessageSliceCmd struct {
- baseCmd
-
- val []XMessage
-}
-
-var _ Cmder = (*XMessageSliceCmd)(nil)
-
-func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd {
- return &XMessageSliceCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *XMessageSliceCmd) Val() []XMessage {
- return cmd.val
-}
-
-func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *XMessageSliceCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) error {
- var err error
- cmd.val, err = readXMessageSlice(rd)
- return err
-}
-
-func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) {
- n, err := rd.ReadArrayLen()
- if err != nil {
- return nil, err
- }
-
- msgs := make([]XMessage, n)
- for i := 0; i < n; i++ {
- var err error
- msgs[i], err = readXMessage(rd)
- if err != nil {
- return nil, err
- }
- }
- return msgs, nil
-}
-
-func readXMessage(rd *proto.Reader) (XMessage, error) {
- n, err := rd.ReadArrayLen()
- if err != nil {
- return XMessage{}, err
- }
- if n != 2 {
- return XMessage{}, fmt.Errorf("got %d, wanted 2", n)
- }
-
- id, err := rd.ReadString()
- if err != nil {
- return XMessage{}, err
- }
-
- var values map[string]interface{}
-
- v, err := rd.ReadArrayReply(stringInterfaceMapParser)
- if err != nil {
- if err != proto.Nil {
- return XMessage{}, err
- }
- } else {
- values = v.(map[string]interface{})
- }
-
- return XMessage{
- ID: id,
- Values: values,
- }, nil
-}
-
-// stringInterfaceMapParser implements proto.MultiBulkParse.
-func stringInterfaceMapParser(rd *proto.Reader, n int64) (interface{}, error) {
- m := make(map[string]interface{}, n/2)
- for i := int64(0); i < n; i += 2 {
- key, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- value, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- m[key] = value
- }
- return m, nil
-}
-
-//------------------------------------------------------------------------------
-
-type XStream struct {
- Stream string
- Messages []XMessage
-}
-
-type XStreamSliceCmd struct {
- baseCmd
-
- val []XStream
-}
-
-var _ Cmder = (*XStreamSliceCmd)(nil)
-
-func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd {
- return &XStreamSliceCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *XStreamSliceCmd) Val() []XStream {
- return cmd.val
-}
-
-func (cmd *XStreamSliceCmd) Result() ([]XStream, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *XStreamSliceCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make([]XStream, n)
- for i := 0; i < len(cmd.val); i++ {
- i := i
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- if n != 2 {
- return nil, fmt.Errorf("got %d, wanted 2", n)
- }
-
- stream, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- msgs, err := readXMessageSlice(rd)
- if err != nil {
- return nil, err
- }
-
- cmd.val[i] = XStream{
- Stream: stream,
- Messages: msgs,
- }
- return nil, nil
- })
- if err != nil {
- return nil, err
- }
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type XPending struct {
- Count int64
- Lower string
- Higher string
- Consumers map[string]int64
-}
-
-type XPendingCmd struct {
- baseCmd
- val *XPending
-}
-
-var _ Cmder = (*XPendingCmd)(nil)
-
-func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd {
- return &XPendingCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *XPendingCmd) Val() *XPending {
- return cmd.val
-}
-
-func (cmd *XPendingCmd) Result() (*XPending, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *XPendingCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *XPendingCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- if n != 4 {
- return nil, fmt.Errorf("got %d, wanted 4", n)
- }
-
- count, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
-
- lower, err := rd.ReadString()
- if err != nil && err != Nil {
- return nil, err
- }
-
- higher, err := rd.ReadString()
- if err != nil && err != Nil {
- return nil, err
- }
-
- cmd.val = &XPending{
- Count: count,
- Lower: lower,
- Higher: higher,
- }
- _, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- for i := int64(0); i < n; i++ {
- _, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- if n != 2 {
- return nil, fmt.Errorf("got %d, wanted 2", n)
- }
-
- consumerName, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- consumerPending, err := rd.ReadInt()
- if err != nil {
- return nil, err
- }
-
- if cmd.val.Consumers == nil {
- cmd.val.Consumers = make(map[string]int64)
- }
- cmd.val.Consumers[consumerName] = consumerPending
-
- return nil, nil
- })
- if err != nil {
- return nil, err
- }
- }
- return nil, nil
- })
- if err != nil && err != Nil {
- return nil, err
- }
-
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type XPendingExt struct {
- ID string
- Consumer string
- Idle time.Duration
- RetryCount int64
-}
-
-type XPendingExtCmd struct {
- baseCmd
- val []XPendingExt
-}
-
-var _ Cmder = (*XPendingExtCmd)(nil)
-
-func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd {
- return &XPendingExtCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *XPendingExtCmd) Val() []XPendingExt {
- return cmd.val
-}
-
-func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *XPendingExtCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make([]XPendingExt, 0, n)
- for i := int64(0); i < n; i++ {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- if n != 4 {
- return nil, fmt.Errorf("got %d, wanted 4", n)
- }
-
- id, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- consumer, err := rd.ReadString()
- if err != nil && err != Nil {
- return nil, err
- }
-
- idle, err := rd.ReadIntReply()
- if err != nil && err != Nil {
- return nil, err
- }
-
- retryCount, err := rd.ReadIntReply()
- if err != nil && err != Nil {
- return nil, err
- }
-
- cmd.val = append(cmd.val, XPendingExt{
- ID: id,
- Consumer: consumer,
- Idle: time.Duration(idle) * time.Millisecond,
- RetryCount: retryCount,
- })
- return nil, nil
- })
- if err != nil {
- return nil, err
- }
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type XInfoGroupsCmd struct {
- baseCmd
- val []XInfoGroup
-}
-
-type XInfoGroup struct {
- Name string
- Consumers int64
- Pending int64
- LastDeliveredID string
-}
-
-var _ Cmder = (*XInfoGroupsCmd)(nil)
-
-func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd {
- return &XInfoGroupsCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: []interface{}{"xinfo", "groups", stream},
- },
- }
-}
-
-func (cmd *XInfoGroupsCmd) Val() []XInfoGroup {
- return cmd.val
-}
-
-func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *XInfoGroupsCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error {
- n, err := rd.ReadArrayLen()
- if err != nil {
- return err
- }
-
- cmd.val = make([]XInfoGroup, n)
-
- for i := 0; i < n; i++ {
- cmd.val[i], err = readXGroupInfo(rd)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func readXGroupInfo(rd *proto.Reader) (XInfoGroup, error) {
- var group XInfoGroup
-
- n, err := rd.ReadArrayLen()
- if err != nil {
- return group, err
- }
- if n != 8 {
- return group, fmt.Errorf("redis: got %d elements in XINFO GROUPS reply, wanted 8", n)
- }
-
- for i := 0; i < 4; i++ {
- key, err := rd.ReadString()
- if err != nil {
- return group, err
- }
-
- val, err := rd.ReadString()
- if err != nil {
- return group, err
- }
-
- switch key {
- case "name":
- group.Name = val
- case "consumers":
- group.Consumers, err = strconv.ParseInt(val, 0, 64)
- if err != nil {
- return group, err
- }
- case "pending":
- group.Pending, err = strconv.ParseInt(val, 0, 64)
- if err != nil {
- return group, err
- }
- case "last-delivered-id":
- group.LastDeliveredID = val
- default:
- return group, fmt.Errorf("redis: unexpected content %s in XINFO GROUPS reply", key)
- }
- }
-
- return group, nil
-}
-
-//------------------------------------------------------------------------------
-
-type XInfoStreamCmd struct {
- baseCmd
- val *XInfoStream
-}
-
-type XInfoStream struct {
- Length int64
- RadixTreeKeys int64
- RadixTreeNodes int64
- Groups int64
- LastGeneratedID string
- FirstEntry XMessage
- LastEntry XMessage
-}
-
-var _ Cmder = (*XInfoStreamCmd)(nil)
-
-func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamCmd {
- return &XInfoStreamCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: []interface{}{"xinfo", "stream", stream},
- },
- }
-}
-
-func (cmd *XInfoStreamCmd) Val() *XInfoStream {
- return cmd.val
-}
-
-func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *XInfoStreamCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error {
- v, err := rd.ReadReply(xStreamInfoParser)
- if err != nil {
- return err
- }
- cmd.val = v.(*XInfoStream)
- return nil
-}
-
-func xStreamInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
- if n != 14 {
- return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM reply,"+
- "wanted 14", n)
- }
- var info XInfoStream
- for i := 0; i < 7; i++ {
- key, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
- switch key {
- case "length":
- info.Length, err = rd.ReadIntReply()
- case "radix-tree-keys":
- info.RadixTreeKeys, err = rd.ReadIntReply()
- case "radix-tree-nodes":
- info.RadixTreeNodes, err = rd.ReadIntReply()
- case "groups":
- info.Groups, err = rd.ReadIntReply()
- case "last-generated-id":
- info.LastGeneratedID, err = rd.ReadString()
- case "first-entry":
- info.FirstEntry, err = readXMessage(rd)
- case "last-entry":
- info.LastEntry, err = readXMessage(rd)
- default:
- return nil, fmt.Errorf("redis: unexpected content %s "+
- "in XINFO STREAM reply", key)
- }
- if err != nil {
- return nil, err
- }
- }
- return &info, nil
-}
-
-//------------------------------------------------------------------------------
-
-type ZSliceCmd struct {
- baseCmd
-
- val []Z
-}
-
-var _ Cmder = (*ZSliceCmd)(nil)
-
-func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd {
- return &ZSliceCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *ZSliceCmd) Val() []Z {
- return cmd.val
-}
-
-func (cmd *ZSliceCmd) Result() ([]Z, error) {
- return cmd.val, cmd.err
-}
-
-func (cmd *ZSliceCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make([]Z, n/2)
- for i := 0; i < len(cmd.val); i++ {
- member, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- score, err := rd.ReadFloatReply()
- if err != nil {
- return nil, err
- }
-
- cmd.val[i] = Z{
- Member: member,
- Score: score,
- }
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type ZWithKeyCmd struct {
- baseCmd
-
- val *ZWithKey
-}
-
-var _ Cmder = (*ZWithKeyCmd)(nil)
-
-func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd {
- return &ZWithKeyCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *ZWithKeyCmd) Val() *ZWithKey {
- return cmd.val
-}
-
-func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) {
- return cmd.Val(), cmd.Err()
-}
-
-func (cmd *ZWithKeyCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- if n != 3 {
- return nil, fmt.Errorf("got %d elements, expected 3", n)
- }
-
- cmd.val = &ZWithKey{}
- var err error
-
- cmd.val.Key, err = rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- cmd.val.Member, err = rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- cmd.val.Score, err = rd.ReadFloatReply()
- if err != nil {
- return nil, err
- }
-
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type ScanCmd struct {
- baseCmd
-
- page []string
- cursor uint64
-
- process cmdable
-}
-
-var _ Cmder = (*ScanCmd)(nil)
-
-func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd {
- return &ScanCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- process: process,
- }
-}
-
-func (cmd *ScanCmd) Val() (keys []string, cursor uint64) {
- return cmd.page, cmd.cursor
-}
-
-func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) {
- return cmd.page, cmd.cursor, cmd.err
-}
-
-func (cmd *ScanCmd) String() string {
- return cmdString(cmd, cmd.page)
-}
-
-func (cmd *ScanCmd) readReply(rd *proto.Reader) (err error) {
- cmd.page, cmd.cursor, err = rd.ReadScanReply()
- return err
-}
-
-// Iterator creates a new ScanIterator.
-func (cmd *ScanCmd) Iterator() *ScanIterator {
- return &ScanIterator{
- cmd: cmd,
- }
-}
-
-//------------------------------------------------------------------------------
-
-type ClusterNode struct {
- ID string
- Addr string
-}
-
-type ClusterSlot struct {
- Start int
- End int
- Nodes []ClusterNode
-}
-
-type ClusterSlotsCmd struct {
- baseCmd
-
- val []ClusterSlot
-}
-
-var _ Cmder = (*ClusterSlotsCmd)(nil)
-
-func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd {
- return &ClusterSlotsCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *ClusterSlotsCmd) Val() []ClusterSlot {
- return cmd.val
-}
-
-func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) {
- return cmd.Val(), cmd.Err()
-}
-
-func (cmd *ClusterSlotsCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make([]ClusterSlot, n)
- for i := 0; i < len(cmd.val); i++ {
- n, err := rd.ReadArrayLen()
- if err != nil {
- return nil, err
- }
- if n < 2 {
- err := fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n)
- return nil, err
- }
-
- start, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
-
- end, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
-
- nodes := make([]ClusterNode, n-2)
- for j := 0; j < len(nodes); j++ {
- n, err := rd.ReadArrayLen()
- if err != nil {
- return nil, err
- }
- if n != 2 && n != 3 {
- err := fmt.Errorf("got %d elements in cluster info address, expected 2 or 3", n)
- return nil, err
- }
-
- ip, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- port, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- nodes[j].Addr = net.JoinHostPort(ip, port)
-
- if n == 3 {
- id, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
- nodes[j].ID = id
- }
- }
-
- cmd.val[i] = ClusterSlot{
- Start: int(start),
- End: int(end),
- Nodes: nodes,
- }
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-// GeoLocation is used with GeoAdd to add geospatial location.
-type GeoLocation struct {
- Name string
- Longitude, Latitude, Dist float64
- GeoHash int64
-}
-
-// GeoRadiusQuery is used with GeoRadius to query geospatial index.
-type GeoRadiusQuery struct {
- Radius float64
- // Can be m, km, ft, or mi. Default is km.
- Unit string
- WithCoord bool
- WithDist bool
- WithGeoHash bool
- Count int
- // Can be ASC or DESC. Default is no sort order.
- Sort string
- Store string
- StoreDist string
-}
-
-type GeoLocationCmd struct {
- baseCmd
-
- q *GeoRadiusQuery
- locations []GeoLocation
-}
-
-var _ Cmder = (*GeoLocationCmd)(nil)
-
-func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd {
- return &GeoLocationCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: geoLocationArgs(q, args...),
- },
- q: q,
- }
-}
-
-func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface{} {
- args = append(args, q.Radius)
- if q.Unit != "" {
- args = append(args, q.Unit)
- } else {
- args = append(args, "km")
- }
- if q.WithCoord {
- args = append(args, "withcoord")
- }
- if q.WithDist {
- args = append(args, "withdist")
- }
- if q.WithGeoHash {
- args = append(args, "withhash")
- }
- if q.Count > 0 {
- args = append(args, "count", q.Count)
- }
- if q.Sort != "" {
- args = append(args, q.Sort)
- }
- if q.Store != "" {
- args = append(args, "store")
- args = append(args, q.Store)
- }
- if q.StoreDist != "" {
- args = append(args, "storedist")
- args = append(args, q.StoreDist)
- }
- return args
-}
-
-func (cmd *GeoLocationCmd) Val() []GeoLocation {
- return cmd.locations
-}
-
-func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) {
- return cmd.locations, cmd.err
-}
-
-func (cmd *GeoLocationCmd) String() string {
- return cmdString(cmd, cmd.locations)
-}
-
-func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error {
- v, err := rd.ReadArrayReply(newGeoLocationSliceParser(cmd.q))
- if err != nil {
- return err
- }
- cmd.locations = v.([]GeoLocation)
- return nil
-}
-
-func newGeoLocationSliceParser(q *GeoRadiusQuery) proto.MultiBulkParse {
- return func(rd *proto.Reader, n int64) (interface{}, error) {
- locs := make([]GeoLocation, 0, n)
- for i := int64(0); i < n; i++ {
- v, err := rd.ReadReply(newGeoLocationParser(q))
- if err != nil {
- return nil, err
- }
- switch vv := v.(type) {
- case string:
- locs = append(locs, GeoLocation{
- Name: vv,
- })
- case *GeoLocation:
- // TODO: avoid copying
- locs = append(locs, *vv)
- default:
- return nil, fmt.Errorf("got %T, expected string or *GeoLocation", v)
- }
- }
- return locs, nil
- }
-}
-
-func newGeoLocationParser(q *GeoRadiusQuery) proto.MultiBulkParse {
- return func(rd *proto.Reader, n int64) (interface{}, error) {
- var loc GeoLocation
- var err error
-
- loc.Name, err = rd.ReadString()
- if err != nil {
- return nil, err
- }
- if q.WithDist {
- loc.Dist, err = rd.ReadFloatReply()
- if err != nil {
- return nil, err
- }
- }
- if q.WithGeoHash {
- loc.GeoHash, err = rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
- }
- if q.WithCoord {
- n, err := rd.ReadArrayLen()
- if err != nil {
- return nil, err
- }
- if n != 2 {
- return nil, fmt.Errorf("got %d coordinates, expected 2", n)
- }
-
- loc.Longitude, err = rd.ReadFloatReply()
- if err != nil {
- return nil, err
- }
- loc.Latitude, err = rd.ReadFloatReply()
- if err != nil {
- return nil, err
- }
- }
-
- return &loc, nil
- }
-}
-
-//------------------------------------------------------------------------------
-
-type GeoPos struct {
- Longitude, Latitude float64
-}
-
-type GeoPosCmd struct {
- baseCmd
-
- val []*GeoPos
-}
-
-var _ Cmder = (*GeoPosCmd)(nil)
-
-func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd {
- return &GeoPosCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *GeoPosCmd) Val() []*GeoPos {
- return cmd.val
-}
-
-func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) {
- return cmd.Val(), cmd.Err()
-}
-
-func (cmd *GeoPosCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make([]*GeoPos, n)
- for i := 0; i < len(cmd.val); i++ {
- i := i
- _, err := rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- longitude, err := rd.ReadFloatReply()
- if err != nil {
- return nil, err
- }
-
- latitude, err := rd.ReadFloatReply()
- if err != nil {
- return nil, err
- }
-
- cmd.val[i] = &GeoPos{
- Longitude: longitude,
- Latitude: latitude,
- }
- return nil, nil
- })
- if err != nil {
- if err == Nil {
- cmd.val[i] = nil
- continue
- }
- return nil, err
- }
- }
- return nil, nil
- })
- return err
-}
-
-//------------------------------------------------------------------------------
-
-type CommandInfo struct {
- Name string
- Arity int8
- Flags []string
- ACLFlags []string
- FirstKeyPos int8
- LastKeyPos int8
- StepCount int8
- ReadOnly bool
-}
-
-type CommandsInfoCmd struct {
- baseCmd
-
- val map[string]*CommandInfo
-}
-
-var _ Cmder = (*CommandsInfoCmd)(nil)
-
-func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd {
- return &CommandsInfoCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo {
- return cmd.val
-}
-
-func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) {
- return cmd.Val(), cmd.Err()
-}
-
-func (cmd *CommandsInfoCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make(map[string]*CommandInfo, n)
- for i := int64(0); i < n; i++ {
- v, err := rd.ReadReply(commandInfoParser)
- if err != nil {
- return nil, err
- }
- vv := v.(*CommandInfo)
- cmd.val[vv.Name] = vv
- }
- return nil, nil
- })
- return err
-}
-
-func commandInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
- const numArgRedis5 = 6
- const numArgRedis6 = 7
-
- switch n {
- case numArgRedis5, numArgRedis6:
- // continue
- default:
- return nil, fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 7", n)
- }
-
- var cmd CommandInfo
- var err error
-
- cmd.Name, err = rd.ReadString()
- if err != nil {
- return nil, err
- }
-
- arity, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
- cmd.Arity = int8(arity)
-
- _, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.Flags = make([]string, n)
- for i := 0; i < len(cmd.Flags); i++ {
- switch s, err := rd.ReadString(); {
- case err == Nil:
- cmd.Flags[i] = ""
- case err != nil:
- return nil, err
- default:
- cmd.Flags[i] = s
- }
- }
- return nil, nil
- })
- if err != nil {
- return nil, err
- }
-
- firstKeyPos, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
- cmd.FirstKeyPos = int8(firstKeyPos)
-
- lastKeyPos, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
- cmd.LastKeyPos = int8(lastKeyPos)
-
- stepCount, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
- cmd.StepCount = int8(stepCount)
-
- for _, flag := range cmd.Flags {
- if flag == "readonly" {
- cmd.ReadOnly = true
- break
- }
- }
-
- if n == numArgRedis5 {
- return &cmd, nil
- }
-
- _, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.ACLFlags = make([]string, n)
- for i := 0; i < len(cmd.ACLFlags); i++ {
- switch s, err := rd.ReadString(); {
- case err == Nil:
- cmd.ACLFlags[i] = ""
- case err != nil:
- return nil, err
- default:
- cmd.ACLFlags[i] = s
- }
- }
- return nil, nil
- })
- if err != nil {
- return nil, err
- }
-
- return &cmd, nil
-}
-
-//------------------------------------------------------------------------------
-
-type cmdsInfoCache struct {
- fn func(ctx context.Context) (map[string]*CommandInfo, error)
-
- once internal.Once
- cmds map[string]*CommandInfo
-}
-
-func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandInfo, error)) *cmdsInfoCache {
- return &cmdsInfoCache{
- fn: fn,
- }
-}
-
-func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandInfo, error) {
- err := c.once.Do(func() error {
- cmds, err := c.fn(ctx)
- if err != nil {
- return err
- }
-
- // Extensions have cmd names in upper case. Convert them to lower case.
- for k, v := range cmds {
- lower := internal.ToLower(k)
- if lower != k {
- cmds[lower] = v
- }
- }
-
- c.cmds = cmds
- return nil
- })
- return c.cmds, err
-}
-
-//------------------------------------------------------------------------------
-
-type SlowLog struct {
- ID int64
- Time time.Time
- Duration time.Duration
- Args []string
- // These are also optional fields emitted only by Redis 4.0 or greater:
- // https://redis.io/commands/slowlog#output-format
- ClientAddr string
- ClientName string
-}
-
-type SlowLogCmd struct {
- baseCmd
-
- val []SlowLog
-}
-
-var _ Cmder = (*SlowLogCmd)(nil)
-
-func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd {
- return &SlowLogCmd{
- baseCmd: baseCmd{
- ctx: ctx,
- args: args,
- },
- }
-}
-
-func (cmd *SlowLogCmd) Val() []SlowLog {
- return cmd.val
-}
-
-func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
- return cmd.Val(), cmd.Err()
-}
-
-func (cmd *SlowLogCmd) String() string {
- return cmdString(cmd, cmd.val)
-}
-
-func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error {
- _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
- cmd.val = make([]SlowLog, n)
- for i := 0; i < len(cmd.val); i++ {
- n, err := rd.ReadArrayLen()
- if err != nil {
- return nil, err
- }
- if n < 4 {
- err := fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", n)
- return nil, err
- }
-
- id, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
-
- createdAt, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
- createdAtTime := time.Unix(createdAt, 0)
-
- costs, err := rd.ReadIntReply()
- if err != nil {
- return nil, err
- }
- costsDuration := time.Duration(costs) * time.Microsecond
-
- cmdLen, err := rd.ReadArrayLen()
- if err != nil {
- return nil, err
- }
- if cmdLen < 1 {
- err := fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen)
- return nil, err
- }
-
- cmdString := make([]string, cmdLen)
- for i := 0; i < cmdLen; i++ {
- cmdString[i], err = rd.ReadString()
- if err != nil {
- return nil, err
- }
- }
-
- var address, name string
- for i := 4; i < n; i++ {
- str, err := rd.ReadString()
- if err != nil {
- return nil, err
- }
- if i == 4 {
- address = str
- } else if i == 5 {
- name = str
- }
- }
-
- cmd.val[i] = SlowLog{
- ID: id,
- Time: createdAtTime,
- Duration: costsDuration,
- Args: cmdString,
- ClientAddr: address,
- ClientName: name,
- }
- }
- return nil, nil
- })
- return err
-}
diff --git a/vendor/github.com/go-redis/redis/v8/commands.go b/vendor/github.com/go-redis/redis/v8/commands.go
deleted file mode 100644
index f4e6afc1475..00000000000
--- a/vendor/github.com/go-redis/redis/v8/commands.go
+++ /dev/null
@@ -1,2732 +0,0 @@
-package redis
-
-import (
- "context"
- "errors"
- "io"
- "time"
-
- "github.com/go-redis/redis/v8/internal"
-)
-
-// KeepTTL is an option for Set command to keep key's existing TTL.
-// For example:
-//
-// rdb.Set(ctx, key, value, redis.KeepTTL)
-const KeepTTL = -1
-
-func usePrecise(dur time.Duration) bool {
- return dur < time.Second || dur%time.Second != 0
-}
-
-func formatMs(ctx context.Context, dur time.Duration) int64 {
- if dur > 0 && dur < time.Millisecond {
- internal.Logger.Printf(
- ctx,
- "specified duration is %s, but minimal supported value is %s - truncating to 1ms",
- dur, time.Millisecond,
- )
- return 1
- }
- return int64(dur / time.Millisecond)
-}
-
-func formatSec(ctx context.Context, dur time.Duration) int64 {
- if dur > 0 && dur < time.Second {
- internal.Logger.Printf(
- ctx,
- "specified duration is %s, but minimal supported value is %s - truncating to 1s",
- dur, time.Second,
- )
- return 1
- }
- return int64(dur / time.Second)
-}
-
-func appendArgs(dst, src []interface{}) []interface{} {
- if len(src) == 1 {
- return appendArg(dst, src[0])
- }
-
- dst = append(dst, src...)
- return dst
-}
-
-func appendArg(dst []interface{}, arg interface{}) []interface{} {
- switch arg := arg.(type) {
- case []string:
- for _, s := range arg {
- dst = append(dst, s)
- }
- return dst
- case []interface{}:
- dst = append(dst, arg...)
- return dst
- case map[string]interface{}:
- for k, v := range arg {
- dst = append(dst, k, v)
- }
- return dst
- default:
- return append(dst, arg)
- }
-}
-
-type Cmdable interface {
- Pipeline() Pipeliner
- Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
-
- TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
- TxPipeline() Pipeliner
-
- Command(ctx context.Context) *CommandsInfoCmd
- ClientGetName(ctx context.Context) *StringCmd
- Echo(ctx context.Context, message interface{}) *StringCmd
- Ping(ctx context.Context) *StatusCmd
- Quit(ctx context.Context) *StatusCmd
- Del(ctx context.Context, keys ...string) *IntCmd
- Unlink(ctx context.Context, keys ...string) *IntCmd
- Dump(ctx context.Context, key string) *StringCmd
- Exists(ctx context.Context, keys ...string) *IntCmd
- Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
- ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
- Keys(ctx context.Context, pattern string) *StringSliceCmd
- Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd
- Move(ctx context.Context, key string, db int) *BoolCmd
- ObjectRefCount(ctx context.Context, key string) *IntCmd
- ObjectEncoding(ctx context.Context, key string) *StringCmd
- ObjectIdleTime(ctx context.Context, key string) *DurationCmd
- Persist(ctx context.Context, key string) *BoolCmd
- PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
- PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
- PTTL(ctx context.Context, key string) *DurationCmd
- RandomKey(ctx context.Context) *StringCmd
- Rename(ctx context.Context, key, newkey string) *StatusCmd
- RenameNX(ctx context.Context, key, newkey string) *BoolCmd
- Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
- RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
- Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd
- SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd
- SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd
- Touch(ctx context.Context, keys ...string) *IntCmd
- TTL(ctx context.Context, key string) *DurationCmd
- Type(ctx context.Context, key string) *StatusCmd
- Append(ctx context.Context, key, value string) *IntCmd
- Decr(ctx context.Context, key string) *IntCmd
- DecrBy(ctx context.Context, key string, decrement int64) *IntCmd
- Get(ctx context.Context, key string) *StringCmd
- GetRange(ctx context.Context, key string, start, end int64) *StringCmd
- GetSet(ctx context.Context, key string, value interface{}) *StringCmd
- Incr(ctx context.Context, key string) *IntCmd
- IncrBy(ctx context.Context, key string, value int64) *IntCmd
- IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd
- MGet(ctx context.Context, keys ...string) *SliceCmd
- MSet(ctx context.Context, values ...interface{}) *StatusCmd
- MSetNX(ctx context.Context, values ...interface{}) *BoolCmd
- Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
- SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
- SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
- SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd
- StrLen(ctx context.Context, key string) *IntCmd
-
- GetBit(ctx context.Context, key string, offset int64) *IntCmd
- SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd
- BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd
- BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
- BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
- BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
- BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
- BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
- BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd
-
- Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd
- SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
- HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
- ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
-
- HDel(ctx context.Context, key string, fields ...string) *IntCmd
- HExists(ctx context.Context, key, field string) *BoolCmd
- HGet(ctx context.Context, key, field string) *StringCmd
- HGetAll(ctx context.Context, key string) *StringStringMapCmd
- HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd
- HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd
- HKeys(ctx context.Context, key string) *StringSliceCmd
- HLen(ctx context.Context, key string) *IntCmd
- HMGet(ctx context.Context, key string, fields ...string) *SliceCmd
- HSet(ctx context.Context, key string, values ...interface{}) *IntCmd
- HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd
- HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd
- HVals(ctx context.Context, key string) *StringSliceCmd
-
- BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
- BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
- BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd
- LIndex(ctx context.Context, key string, index int64) *StringCmd
- LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd
- LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd
- LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd
- LLen(ctx context.Context, key string) *IntCmd
- LPop(ctx context.Context, key string) *StringCmd
- LPush(ctx context.Context, key string, values ...interface{}) *IntCmd
- LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
- LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
- LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd
- LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd
- LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd
- RPop(ctx context.Context, key string) *StringCmd
- RPopLPush(ctx context.Context, source, destination string) *StringCmd
- RPush(ctx context.Context, key string, values ...interface{}) *IntCmd
- RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
-
- SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd
- SCard(ctx context.Context, key string) *IntCmd
- SDiff(ctx context.Context, keys ...string) *StringSliceCmd
- SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
- SInter(ctx context.Context, keys ...string) *StringSliceCmd
- SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd
- SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd
- SMembers(ctx context.Context, key string) *StringSliceCmd
- SMembersMap(ctx context.Context, key string) *StringStructMapCmd
- SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd
- SPop(ctx context.Context, key string) *StringCmd
- SPopN(ctx context.Context, key string, count int64) *StringSliceCmd
- SRandMember(ctx context.Context, key string) *StringCmd
- SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd
- SRem(ctx context.Context, key string, members ...interface{}) *IntCmd
- SUnion(ctx context.Context, keys ...string) *StringSliceCmd
- SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd
-
- XAdd(ctx context.Context, a *XAddArgs) *StringCmd
- XDel(ctx context.Context, stream string, ids ...string) *IntCmd
- XLen(ctx context.Context, stream string) *IntCmd
- XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd
- XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd
- XRevRange(ctx context.Context, stream string, start, stop string) *XMessageSliceCmd
- XRevRangeN(ctx context.Context, stream string, start, stop string, count int64) *XMessageSliceCmd
- XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd
- XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd
- XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd
- XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd
- XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd
- XGroupDestroy(ctx context.Context, stream, group string) *IntCmd
- XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
- XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd
- XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd
- XPending(ctx context.Context, stream, group string) *XPendingCmd
- XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd
- XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd
- XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd
- XTrim(ctx context.Context, key string, maxLen int64) *IntCmd
- XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd
- XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd
- XInfoStream(ctx context.Context, key string) *XInfoStreamCmd
-
- BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
- BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
- ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd
- ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd
- ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd
- ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd
- ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd
- ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd
- ZIncr(ctx context.Context, key string, member *Z) *FloatCmd
- ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd
- ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd
- ZCard(ctx context.Context, key string) *IntCmd
- ZCount(ctx context.Context, key, min, max string) *IntCmd
- ZLexCount(ctx context.Context, key, min, max string) *IntCmd
- ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd
- ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd
- ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd
- ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd
- ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
- ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
- ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
- ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
- ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
- ZRank(ctx context.Context, key, member string) *IntCmd
- ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd
- ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd
- ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd
- ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd
- ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
- ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
- ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
- ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
- ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
- ZRevRank(ctx context.Context, key, member string) *IntCmd
- ZScore(ctx context.Context, key, member string) *FloatCmd
- ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd
-
- PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd
- PFCount(ctx context.Context, keys ...string) *IntCmd
- PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd
-
- BgRewriteAOF(ctx context.Context) *StatusCmd
- BgSave(ctx context.Context) *StatusCmd
- ClientKill(ctx context.Context, ipPort string) *StatusCmd
- ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd
- ClientList(ctx context.Context) *StringCmd
- ClientPause(ctx context.Context, dur time.Duration) *BoolCmd
- ClientID(ctx context.Context) *IntCmd
- ConfigGet(ctx context.Context, parameter string) *SliceCmd
- ConfigResetStat(ctx context.Context) *StatusCmd
- ConfigSet(ctx context.Context, parameter, value string) *StatusCmd
- ConfigRewrite(ctx context.Context) *StatusCmd
- DBSize(ctx context.Context) *IntCmd
- FlushAll(ctx context.Context) *StatusCmd
- FlushAllAsync(ctx context.Context) *StatusCmd
- FlushDB(ctx context.Context) *StatusCmd
- FlushDBAsync(ctx context.Context) *StatusCmd
- Info(ctx context.Context, section ...string) *StringCmd
- LastSave(ctx context.Context) *IntCmd
- Save(ctx context.Context) *StatusCmd
- Shutdown(ctx context.Context) *StatusCmd
- ShutdownSave(ctx context.Context) *StatusCmd
- ShutdownNoSave(ctx context.Context) *StatusCmd
- SlaveOf(ctx context.Context, host, port string) *StatusCmd
- Time(ctx context.Context) *TimeCmd
- DebugObject(ctx context.Context, key string) *StringCmd
- ReadOnly(ctx context.Context) *StatusCmd
- ReadWrite(ctx context.Context) *StatusCmd
- MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd
-
- Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
- EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
- ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
- ScriptFlush(ctx context.Context) *StatusCmd
- ScriptKill(ctx context.Context) *StatusCmd
- ScriptLoad(ctx context.Context, script string) *StringCmd
-
- Publish(ctx context.Context, channel string, message interface{}) *IntCmd
- PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd
- PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd
- PubSubNumPat(ctx context.Context) *IntCmd
-
- ClusterSlots(ctx context.Context) *ClusterSlotsCmd
- ClusterNodes(ctx context.Context) *StringCmd
- ClusterMeet(ctx context.Context, host, port string) *StatusCmd
- ClusterForget(ctx context.Context, nodeID string) *StatusCmd
- ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd
- ClusterResetSoft(ctx context.Context) *StatusCmd
- ClusterResetHard(ctx context.Context) *StatusCmd
- ClusterInfo(ctx context.Context) *StringCmd
- ClusterKeySlot(ctx context.Context, key string) *IntCmd
- ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd
- ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd
- ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd
- ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd
- ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd
- ClusterSaveConfig(ctx context.Context) *StatusCmd
- ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd
- ClusterFailover(ctx context.Context) *StatusCmd
- ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd
- ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd
-
- GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd
- GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd
- GeoRadius(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd
- GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *IntCmd
- GeoRadiusByMember(ctx context.Context, key, member string, query *GeoRadiusQuery) *GeoLocationCmd
- GeoRadiusByMemberStore(ctx context.Context, key, member string, query *GeoRadiusQuery) *IntCmd
- GeoDist(ctx context.Context, key string, member1, member2, unit string) *FloatCmd
- GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd
-}
-
-type StatefulCmdable interface {
- Cmdable
- Auth(ctx context.Context, password string) *StatusCmd
- AuthACL(ctx context.Context, username, password string) *StatusCmd
- Select(ctx context.Context, index int) *StatusCmd
- SwapDB(ctx context.Context, index1, index2 int) *StatusCmd
- ClientSetName(ctx context.Context, name string) *BoolCmd
-}
-
-var (
- _ Cmdable = (*Client)(nil)
- _ Cmdable = (*Tx)(nil)
- _ Cmdable = (*Ring)(nil)
- _ Cmdable = (*ClusterClient)(nil)
-)
-
-type cmdable func(ctx context.Context, cmd Cmder) error
-
-type statefulCmdable func(ctx context.Context, cmd Cmder) error
-
-//------------------------------------------------------------------------------
-
-func (c statefulCmdable) Auth(ctx context.Context, password string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "auth", password)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Perform an AUTH command, using the given user and pass.
-// Should be used to authenticate the current connection with one of the connections defined in the ACL list
-// when connecting to a Redis 6.0 instance, or greater, that is using the Redis ACL system.
-func (c statefulCmdable) AuthACL(ctx context.Context, username, password string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "auth", username, password)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Wait(ctx context.Context, numSlaves int, timeout time.Duration) *IntCmd {
- cmd := NewIntCmd(ctx, "wait", numSlaves, int(timeout/time.Millisecond))
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c statefulCmdable) Select(ctx context.Context, index int) *StatusCmd {
- cmd := NewStatusCmd(ctx, "select", index)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c statefulCmdable) SwapDB(ctx context.Context, index1, index2 int) *StatusCmd {
- cmd := NewStatusCmd(ctx, "swapdb", index1, index2)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// ClientSetName assigns a name to the connection.
-func (c statefulCmdable) ClientSetName(ctx context.Context, name string) *BoolCmd {
- cmd := NewBoolCmd(ctx, "client", "setname", name)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) Command(ctx context.Context) *CommandsInfoCmd {
- cmd := NewCommandsInfoCmd(ctx, "command")
- _ = c(ctx, cmd)
- return cmd
-}
-
-// ClientGetName returns the name of the connection.
-func (c cmdable) ClientGetName(ctx context.Context) *StringCmd {
- cmd := NewStringCmd(ctx, "client", "getname")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Echo(ctx context.Context, message interface{}) *StringCmd {
- cmd := NewStringCmd(ctx, "echo", message)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Ping(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "ping")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Quit(ctx context.Context) *StatusCmd {
- panic("not implemented")
-}
-
-func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "del"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Unlink(ctx context.Context, keys ...string) *IntCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "unlink"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Dump(ctx context.Context, key string) *StringCmd {
- cmd := NewStringCmd(ctx, "dump", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "exists"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
- cmd := NewBoolCmd(ctx, "expire", key, formatSec(ctx, expiration))
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
- cmd := NewBoolCmd(ctx, "expireat", key, tm.Unix())
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "keys", pattern)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd {
- cmd := NewStatusCmd(
- ctx,
- "migrate",
- host,
- port,
- key,
- db,
- formatMs(ctx, timeout),
- )
- cmd.setReadTimeout(timeout)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Move(ctx context.Context, key string, db int) *BoolCmd {
- cmd := NewBoolCmd(ctx, "move", key, db)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ObjectRefCount(ctx context.Context, key string) *IntCmd {
- cmd := NewIntCmd(ctx, "object", "refcount", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ObjectEncoding(ctx context.Context, key string) *StringCmd {
- cmd := NewStringCmd(ctx, "object", "encoding", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ObjectIdleTime(ctx context.Context, key string) *DurationCmd {
- cmd := NewDurationCmd(ctx, time.Second, "object", "idletime", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Persist(ctx context.Context, key string) *BoolCmd {
- cmd := NewBoolCmd(ctx, "persist", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
- cmd := NewBoolCmd(ctx, "pexpire", key, formatMs(ctx, expiration))
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
- cmd := NewBoolCmd(
- ctx,
- "pexpireat",
- key,
- tm.UnixNano()/int64(time.Millisecond),
- )
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) PTTL(ctx context.Context, key string) *DurationCmd {
- cmd := NewDurationCmd(ctx, time.Millisecond, "pttl", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) RandomKey(ctx context.Context) *StringCmd {
- cmd := NewStringCmd(ctx, "randomkey")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Rename(ctx context.Context, key, newkey string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "rename", key, newkey)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) RenameNX(ctx context.Context, key, newkey string) *BoolCmd {
- cmd := NewBoolCmd(ctx, "renamenx", key, newkey)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
- cmd := NewStatusCmd(
- ctx,
- "restore",
- key,
- formatMs(ctx, ttl),
- value,
- )
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
- cmd := NewStatusCmd(
- ctx,
- "restore",
- key,
- formatMs(ctx, ttl),
- value,
- "replace",
- )
- _ = c(ctx, cmd)
- return cmd
-}
-
-type Sort struct {
- By string
- Offset, Count int64
- Get []string
- Order string
- Alpha bool
-}
-
-func (sort *Sort) args(key string) []interface{} {
- args := []interface{}{"sort", key}
- if sort.By != "" {
- args = append(args, "by", sort.By)
- }
- if sort.Offset != 0 || sort.Count != 0 {
- args = append(args, "limit", sort.Offset, sort.Count)
- }
- for _, get := range sort.Get {
- args = append(args, "get", get)
- }
- if sort.Order != "" {
- args = append(args, sort.Order)
- }
- if sort.Alpha {
- args = append(args, "alpha")
- }
- return args
-}
-
-func (c cmdable) Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, sort.args(key)...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd {
- args := sort.args(key)
- if store != "" {
- args = append(args, "store", store)
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd {
- cmd := NewSliceCmd(ctx, sort.args(key)...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Touch(ctx context.Context, keys ...string) *IntCmd {
- args := make([]interface{}, len(keys)+1)
- args[0] = "touch"
- for i, key := range keys {
- args[i+1] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) TTL(ctx context.Context, key string) *DurationCmd {
- cmd := NewDurationCmd(ctx, time.Second, "ttl", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Type(ctx context.Context, key string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "type", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd {
- cmd := NewIntCmd(ctx, "append", key, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Decr(ctx context.Context, key string) *IntCmd {
- cmd := NewIntCmd(ctx, "decr", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd {
- cmd := NewIntCmd(ctx, "decrby", key, decrement)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `GET key` command. It returns redis.Nil error when key does not exist.
-func (c cmdable) Get(ctx context.Context, key string) *StringCmd {
- cmd := NewStringCmd(ctx, "get", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd {
- cmd := NewStringCmd(ctx, "getrange", key, start, end)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd {
- cmd := NewStringCmd(ctx, "getset", key, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Incr(ctx context.Context, key string) *IntCmd {
- cmd := NewIntCmd(ctx, "incr", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd {
- cmd := NewIntCmd(ctx, "incrby", key, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd {
- cmd := NewFloatCmd(ctx, "incrbyfloat", key, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "mget"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// MSet is like Set but accepts multiple values:
-// - MSet("key1", "value1", "key2", "value2")
-// - MSet([]string{"key1", "value1", "key2", "value2"})
-// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})
-func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
- args := make([]interface{}, 1, 1+len(values))
- args[0] = "mset"
- args = appendArgs(args, values)
- cmd := NewStatusCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// MSetNX is like SetNX but accepts multiple values:
-// - MSetNX("key1", "value1", "key2", "value2")
-// - MSetNX([]string{"key1", "value1", "key2", "value2"})
-// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})
-func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd {
- args := make([]interface{}, 1, 1+len(values))
- args[0] = "msetnx"
- args = appendArgs(args, values)
- cmd := NewBoolCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `SET key value [expiration]` command.
-// Use expiration for `SETEX`-like behavior.
-//
-// Zero expiration means the key has no expiration time.
-// KeepTTL(-1) expiration is a Redis KEEPTTL option to keep existing TTL.
-func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
- args := make([]interface{}, 3, 5)
- args[0] = "set"
- args[1] = key
- args[2] = value
- if expiration > 0 {
- if usePrecise(expiration) {
- args = append(args, "px", formatMs(ctx, expiration))
- } else {
- args = append(args, "ex", formatSec(ctx, expiration))
- }
- } else if expiration == KeepTTL {
- args = append(args, "keepttl")
- }
-
- cmd := NewStatusCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `SET key value [expiration] NX` command.
-//
-// Zero expiration means the key has no expiration time.
-// KeepTTL(-1) expiration is a Redis KEEPTTL option to keep existing TTL.
-func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
- var cmd *BoolCmd
- switch expiration {
- case 0:
- // Use old `SETNX` to support old Redis versions.
- cmd = NewBoolCmd(ctx, "setnx", key, value)
- case KeepTTL:
- cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "nx")
- default:
- if usePrecise(expiration) {
- cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "nx")
- } else {
- cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx")
- }
- }
-
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `SET key value [expiration] XX` command.
-//
-// Zero expiration means the key has no expiration time.
-// KeepTTL(-1) expiration is a Redis KEEPTTL option to keep existing TTL.
-func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
- var cmd *BoolCmd
- switch expiration {
- case 0:
- cmd = NewBoolCmd(ctx, "set", key, value, "xx")
- case KeepTTL:
- cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "xx")
- default:
- if usePrecise(expiration) {
- cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "xx")
- } else {
- cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx")
- }
- }
-
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd {
- cmd := NewIntCmd(ctx, "setrange", key, offset, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd {
- cmd := NewIntCmd(ctx, "strlen", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd {
- cmd := NewIntCmd(ctx, "getbit", key, offset)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd {
- cmd := NewIntCmd(
- ctx,
- "setbit",
- key,
- offset,
- value,
- )
- _ = c(ctx, cmd)
- return cmd
-}
-
-type BitCount struct {
- Start, End int64
-}
-
-func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd {
- args := []interface{}{"bitcount", key}
- if bitCount != nil {
- args = append(
- args,
- bitCount.Start,
- bitCount.End,
- )
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd {
- args := make([]interface{}, 3+len(keys))
- args[0] = "bitop"
- args[1] = op
- args[2] = destKey
- for i, key := range keys {
- args[3+i] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
- return c.bitOp(ctx, "and", destKey, keys...)
-}
-
-func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
- return c.bitOp(ctx, "or", destKey, keys...)
-}
-
-func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
- return c.bitOp(ctx, "xor", destKey, keys...)
-}
-
-func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
- return c.bitOp(ctx, "not", destKey, key)
-}
-
-func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {
- args := make([]interface{}, 3+len(pos))
- args[0] = "bitpos"
- args[1] = key
- args[2] = bit
- switch len(pos) {
- case 0:
- case 1:
- args[3] = pos[0]
- case 2:
- args[3] = pos[0]
- args[4] = pos[1]
- default:
- panic("too many arguments")
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd {
- a := make([]interface{}, 0, 2+len(args))
- a = append(a, "bitfield")
- a = append(a, key)
- a = append(a, args...)
- cmd := NewIntSliceCmd(ctx, a...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd {
- args := []interface{}{"scan", cursor}
- if match != "" {
- args = append(args, "match", match)
- }
- if count > 0 {
- args = append(args, "count", count)
- }
- cmd := NewScanCmd(ctx, c, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
- args := []interface{}{"sscan", key, cursor}
- if match != "" {
- args = append(args, "match", match)
- }
- if count > 0 {
- args = append(args, "count", count)
- }
- cmd := NewScanCmd(ctx, c, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
- args := []interface{}{"hscan", key, cursor}
- if match != "" {
- args = append(args, "match", match)
- }
- if count > 0 {
- args = append(args, "count", count)
- }
- cmd := NewScanCmd(ctx, c, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
- args := []interface{}{"zscan", key, cursor}
- if match != "" {
- args = append(args, "match", match)
- }
- if count > 0 {
- args = append(args, "count", count)
- }
- cmd := NewScanCmd(ctx, c, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) HDel(ctx context.Context, key string, fields ...string) *IntCmd {
- args := make([]interface{}, 2+len(fields))
- args[0] = "hdel"
- args[1] = key
- for i, field := range fields {
- args[2+i] = field
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd {
- cmd := NewBoolCmd(ctx, "hexists", key, field)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd {
- cmd := NewStringCmd(ctx, "hget", key, field)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HGetAll(ctx context.Context, key string) *StringStringMapCmd {
- cmd := NewStringStringMapCmd(ctx, "hgetall", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd {
- cmd := NewIntCmd(ctx, "hincrby", key, field, incr)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd {
- cmd := NewFloatCmd(ctx, "hincrbyfloat", key, field, incr)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "hkeys", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HLen(ctx context.Context, key string) *IntCmd {
- cmd := NewIntCmd(ctx, "hlen", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// HMGet returns the values for the specified fields in the hash stored at key.
-// It returns an interface{} to distinguish between empty string and nil value.
-func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *SliceCmd {
- args := make([]interface{}, 2+len(fields))
- args[0] = "hmget"
- args[1] = key
- for i, field := range fields {
- args[2+i] = field
- }
- cmd := NewSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// HSet accepts values in following formats:
-// - HSet("myhash", "key1", "value1", "key2", "value2")
-// - HSet("myhash", []string{"key1", "value1", "key2", "value2"})
-// - HSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"})
-//
-// Note that it requires Redis v4 for multiple field/value pairs support.
-func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd {
- args := make([]interface{}, 2, 2+len(values))
- args[0] = "hset"
- args[1] = key
- args = appendArgs(args, values)
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// HMSet is a deprecated version of HSet left for compatibility with Redis 3.
-func (c cmdable) HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd {
- args := make([]interface{}, 2, 2+len(values))
- args[0] = "hmset"
- args[1] = key
- args = appendArgs(args, values)
- cmd := NewBoolCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd {
- cmd := NewBoolCmd(ctx, "hsetnx", key, field, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "hvals", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
- args := make([]interface{}, 1+len(keys)+1)
- args[0] = "blpop"
- for i, key := range keys {
- args[1+i] = key
- }
- args[len(args)-1] = formatSec(ctx, timeout)
- cmd := NewStringSliceCmd(ctx, args...)
- cmd.setReadTimeout(timeout)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
- args := make([]interface{}, 1+len(keys)+1)
- args[0] = "brpop"
- for i, key := range keys {
- args[1+i] = key
- }
- args[len(keys)+1] = formatSec(ctx, timeout)
- cmd := NewStringSliceCmd(ctx, args...)
- cmd.setReadTimeout(timeout)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd {
- cmd := NewStringCmd(
- ctx,
- "brpoplpush",
- source,
- destination,
- formatSec(ctx, timeout),
- )
- cmd.setReadTimeout(timeout)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LIndex(ctx context.Context, key string, index int64) *StringCmd {
- cmd := NewStringCmd(ctx, "lindex", key, index)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd {
- cmd := NewIntCmd(ctx, "linsert", key, op, pivot, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
- cmd := NewIntCmd(ctx, "linsert", key, "before", pivot, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
- cmd := NewIntCmd(ctx, "linsert", key, "after", pivot, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LLen(ctx context.Context, key string) *IntCmd {
- cmd := NewIntCmd(ctx, "llen", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LPop(ctx context.Context, key string) *StringCmd {
- cmd := NewStringCmd(ctx, "lpop", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
- args := make([]interface{}, 2, 2+len(values))
- args[0] = "lpush"
- args[1] = key
- args = appendArgs(args, values)
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
- args := make([]interface{}, 2, 2+len(values))
- args[0] = "lpushx"
- args[1] = key
- args = appendArgs(args, values)
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
- cmd := NewStringSliceCmd(
- ctx,
- "lrange",
- key,
- start,
- stop,
- )
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd {
- cmd := NewIntCmd(ctx, "lrem", key, count, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd {
- cmd := NewStatusCmd(ctx, "lset", key, index, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd {
- cmd := NewStatusCmd(
- ctx,
- "ltrim",
- key,
- start,
- stop,
- )
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) RPop(ctx context.Context, key string) *StringCmd {
- cmd := NewStringCmd(ctx, "rpop", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) RPopLPush(ctx context.Context, source, destination string) *StringCmd {
- cmd := NewStringCmd(ctx, "rpoplpush", source, destination)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) RPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
- args := make([]interface{}, 2, 2+len(values))
- args[0] = "rpush"
- args[1] = key
- args = appendArgs(args, values)
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
- args := make([]interface{}, 2, 2+len(values))
- args[0] = "rpushx"
- args[1] = key
- args = appendArgs(args, values)
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd {
- args := make([]interface{}, 2, 2+len(members))
- args[0] = "sadd"
- args[1] = key
- args = appendArgs(args, members)
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SCard(ctx context.Context, key string) *IntCmd {
- cmd := NewIntCmd(ctx, "scard", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "sdiff"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewStringSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
- args := make([]interface{}, 2+len(keys))
- args[0] = "sdiffstore"
- args[1] = destination
- for i, key := range keys {
- args[2+i] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "sinter"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewStringSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd {
- args := make([]interface{}, 2+len(keys))
- args[0] = "sinterstore"
- args[1] = destination
- for i, key := range keys {
- args[2+i] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd {
- cmd := NewBoolCmd(ctx, "sismember", key, member)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `SMEMBERS key` command output as a slice.
-func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "smembers", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `SMEMBERS key` command output as a map.
-func (c cmdable) SMembersMap(ctx context.Context, key string) *StringStructMapCmd {
- cmd := NewStringStructMapCmd(ctx, "smembers", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd {
- cmd := NewBoolCmd(ctx, "smove", source, destination, member)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `SPOP key` command.
-func (c cmdable) SPop(ctx context.Context, key string) *StringCmd {
- cmd := NewStringCmd(ctx, "spop", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `SPOP key count` command.
-func (c cmdable) SPopN(ctx context.Context, key string, count int64) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "spop", key, count)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `SRANDMEMBER key` command.
-func (c cmdable) SRandMember(ctx context.Context, key string) *StringCmd {
- cmd := NewStringCmd(ctx, "srandmember", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `SRANDMEMBER key count` command.
-func (c cmdable) SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "srandmember", key, count)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
- args := make([]interface{}, 2, 2+len(members))
- args[0] = "srem"
- args[1] = key
- args = appendArgs(args, members)
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "sunion"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewStringSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd {
- args := make([]interface{}, 2+len(keys))
- args[0] = "sunionstore"
- args[1] = destination
- for i, key := range keys {
- args[2+i] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-// XAddArgs accepts values in the following formats:
-// - XAddArgs.Values = []interface{}{"key1", "value1", "key2", "value2"}
-// - XAddArgs.Values = []string("key1", "value1", "key2", "value2")
-// - XAddArgs.Values = map[string]interface{}{"key1": "value1", "key2": "value2"}
-//
-// Note that map will not preserve the order of key-value pairs.
-type XAddArgs struct {
- Stream string
- MaxLen int64 // MAXLEN N
- MaxLenApprox int64 // MAXLEN ~ N
- ID string
- Values interface{}
-}
-
-func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd {
- args := make([]interface{}, 0, 8)
- args = append(args, "xadd")
- args = append(args, a.Stream)
- if a.MaxLen > 0 {
- args = append(args, "maxlen", a.MaxLen)
- } else if a.MaxLenApprox > 0 {
- args = append(args, "maxlen", "~", a.MaxLenApprox)
- }
- if a.ID != "" {
- args = append(args, a.ID)
- } else {
- args = append(args, "*")
- }
- args = appendArg(args, a.Values)
-
- cmd := NewStringCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd {
- args := []interface{}{"xdel", stream}
- for _, id := range ids {
- args = append(args, id)
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd {
- cmd := NewIntCmd(ctx, "xlen", stream)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
- cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
- cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop, "count", count)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XRevRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
- cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XRevRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
- cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop, "count", count)
- _ = c(ctx, cmd)
- return cmd
-}
-
-type XReadArgs struct {
- Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
- Count int64
- Block time.Duration
-}
-
-func (c cmdable) XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd {
- args := make([]interface{}, 0, 5+len(a.Streams))
- args = append(args, "xread")
-
- keyPos := int8(1)
- if a.Count > 0 {
- args = append(args, "count")
- args = append(args, a.Count)
- keyPos += 2
- }
- if a.Block >= 0 {
- args = append(args, "block")
- args = append(args, int64(a.Block/time.Millisecond))
- keyPos += 2
- }
- args = append(args, "streams")
- keyPos++
- for _, s := range a.Streams {
- args = append(args, s)
- }
-
- cmd := NewXStreamSliceCmd(ctx, args...)
- if a.Block >= 0 {
- cmd.setReadTimeout(a.Block)
- }
- cmd.setFirstKeyPos(keyPos)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd {
- return c.XRead(ctx, &XReadArgs{
- Streams: streams,
- Block: -1,
- })
-}
-
-func (c cmdable) XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start, "mkstream")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "xgroup", "setid", stream, group, start)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XGroupDestroy(ctx context.Context, stream, group string) *IntCmd {
- cmd := NewIntCmd(ctx, "xgroup", "destroy", stream, group)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
- cmd := NewIntCmd(ctx, "xgroup", "delconsumer", stream, group, consumer)
- _ = c(ctx, cmd)
- return cmd
-}
-
-type XReadGroupArgs struct {
- Group string
- Consumer string
- Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
- Count int64
- Block time.Duration
- NoAck bool
-}
-
-func (c cmdable) XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd {
- args := make([]interface{}, 0, 8+len(a.Streams))
- args = append(args, "xreadgroup", "group", a.Group, a.Consumer)
-
- keyPos := int8(1)
- if a.Count > 0 {
- args = append(args, "count", a.Count)
- keyPos += 2
- }
- if a.Block >= 0 {
- args = append(args, "block", int64(a.Block/time.Millisecond))
- keyPos += 2
- }
- if a.NoAck {
- args = append(args, "noack")
- keyPos++
- }
- args = append(args, "streams")
- keyPos++
- for _, s := range a.Streams {
- args = append(args, s)
- }
-
- cmd := NewXStreamSliceCmd(ctx, args...)
- if a.Block >= 0 {
- cmd.setReadTimeout(a.Block)
- }
- cmd.setFirstKeyPos(keyPos)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd {
- args := []interface{}{"xack", stream, group}
- for _, id := range ids {
- args = append(args, id)
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCmd {
- cmd := NewXPendingCmd(ctx, "xpending", stream, group)
- _ = c(ctx, cmd)
- return cmd
-}
-
-type XPendingExtArgs struct {
- Stream string
- Group string
- Start string
- End string
- Count int64
- Consumer string
-}
-
-func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd {
- args := make([]interface{}, 0, 7)
- args = append(args, "xpending", a.Stream, a.Group, a.Start, a.End, a.Count)
- if a.Consumer != "" {
- args = append(args, a.Consumer)
- }
- cmd := NewXPendingExtCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-type XClaimArgs struct {
- Stream string
- Group string
- Consumer string
- MinIdle time.Duration
- Messages []string
-}
-
-func (c cmdable) XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd {
- args := xClaimArgs(a)
- cmd := NewXMessageSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd {
- args := xClaimArgs(a)
- args = append(args, "justid")
- cmd := NewStringSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func xClaimArgs(a *XClaimArgs) []interface{} {
- args := make([]interface{}, 0, 4+len(a.Messages))
- args = append(args,
- "xclaim",
- a.Stream,
- a.Group, a.Consumer,
- int64(a.MinIdle/time.Millisecond))
- for _, id := range a.Messages {
- args = append(args, id)
- }
- return args
-}
-
-func (c cmdable) XTrim(ctx context.Context, key string, maxLen int64) *IntCmd {
- cmd := NewIntCmd(ctx, "xtrim", key, "maxlen", maxLen)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd {
- cmd := NewIntCmd(ctx, "xtrim", key, "maxlen", "~", maxLen)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd {
- cmd := NewXInfoGroupsCmd(ctx, key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) XInfoStream(ctx context.Context, key string) *XInfoStreamCmd {
- cmd := NewXInfoStreamCmd(ctx, key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-// Z represents sorted set member.
-type Z struct {
- Score float64
- Member interface{}
-}
-
-// ZWithKey represents sorted set member including the name of the key where it was popped.
-type ZWithKey struct {
- Z
- Key string
-}
-
-// ZStore is used as an arg to ZInterStore and ZUnionStore.
-type ZStore struct {
- Keys []string
- Weights []float64
- // Can be SUM, MIN or MAX.
- Aggregate string
-}
-
-// Redis `BZPOPMAX key [key ...] timeout` command.
-func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
- args := make([]interface{}, 1+len(keys)+1)
- args[0] = "bzpopmax"
- for i, key := range keys {
- args[1+i] = key
- }
- args[len(args)-1] = formatSec(ctx, timeout)
- cmd := NewZWithKeyCmd(ctx, args...)
- cmd.setReadTimeout(timeout)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `BZPOPMIN key [key ...] timeout` command.
-func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
- args := make([]interface{}, 1+len(keys)+1)
- args[0] = "bzpopmin"
- for i, key := range keys {
- args[1+i] = key
- }
- args[len(args)-1] = formatSec(ctx, timeout)
- cmd := NewZWithKeyCmd(ctx, args...)
- cmd.setReadTimeout(timeout)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) zAdd(ctx context.Context, a []interface{}, n int, members ...*Z) *IntCmd {
- for i, m := range members {
- a[n+2*i] = m.Score
- a[n+2*i+1] = m.Member
- }
- cmd := NewIntCmd(ctx, a...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `ZADD key score member [score member ...]` command.
-func (c cmdable) ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd {
- const n = 2
- a := make([]interface{}, n+2*len(members))
- a[0], a[1] = "zadd", key
- return c.zAdd(ctx, a, n, members...)
-}
-
-// Redis `ZADD key NX score member [score member ...]` command.
-func (c cmdable) ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd {
- const n = 3
- a := make([]interface{}, n+2*len(members))
- a[0], a[1], a[2] = "zadd", key, "nx"
- return c.zAdd(ctx, a, n, members...)
-}
-
-// Redis `ZADD key XX score member [score member ...]` command.
-func (c cmdable) ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd {
- const n = 3
- a := make([]interface{}, n+2*len(members))
- a[0], a[1], a[2] = "zadd", key, "xx"
- return c.zAdd(ctx, a, n, members...)
-}
-
-// Redis `ZADD key CH score member [score member ...]` command.
-func (c cmdable) ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd {
- const n = 3
- a := make([]interface{}, n+2*len(members))
- a[0], a[1], a[2] = "zadd", key, "ch"
- return c.zAdd(ctx, a, n, members...)
-}
-
-// Redis `ZADD key NX CH score member [score member ...]` command.
-func (c cmdable) ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
- const n = 4
- a := make([]interface{}, n+2*len(members))
- a[0], a[1], a[2], a[3] = "zadd", key, "nx", "ch"
- return c.zAdd(ctx, a, n, members...)
-}
-
-// Redis `ZADD key XX CH score member [score member ...]` command.
-func (c cmdable) ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
- const n = 4
- a := make([]interface{}, n+2*len(members))
- a[0], a[1], a[2], a[3] = "zadd", key, "xx", "ch"
- return c.zAdd(ctx, a, n, members...)
-}
-
-func (c cmdable) zIncr(ctx context.Context, a []interface{}, n int, members ...*Z) *FloatCmd {
- for i, m := range members {
- a[n+2*i] = m.Score
- a[n+2*i+1] = m.Member
- }
- cmd := NewFloatCmd(ctx, a...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// Redis `ZADD key INCR score member` command.
-func (c cmdable) ZIncr(ctx context.Context, key string, member *Z) *FloatCmd {
- const n = 3
- a := make([]interface{}, n+2)
- a[0], a[1], a[2] = "zadd", key, "incr"
- return c.zIncr(ctx, a, n, member)
-}
-
-// Redis `ZADD key NX INCR score member` command.
-func (c cmdable) ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd {
- const n = 4
- a := make([]interface{}, n+2)
- a[0], a[1], a[2], a[3] = "zadd", key, "incr", "nx"
- return c.zIncr(ctx, a, n, member)
-}
-
-// Redis `ZADD key XX INCR score member` command.
-func (c cmdable) ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd {
- const n = 4
- a := make([]interface{}, n+2)
- a[0], a[1], a[2], a[3] = "zadd", key, "incr", "xx"
- return c.zIncr(ctx, a, n, member)
-}
-
-func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd {
- cmd := NewIntCmd(ctx, "zcard", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd {
- cmd := NewIntCmd(ctx, "zcount", key, min, max)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd {
- cmd := NewIntCmd(ctx, "zlexcount", key, min, max)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd {
- cmd := NewFloatCmd(ctx, "zincrby", key, increment, member)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd {
- args := make([]interface{}, 3+len(store.Keys))
- args[0] = "zinterstore"
- args[1] = destination
- args[2] = len(store.Keys)
- for i, key := range store.Keys {
- args[3+i] = key
- }
- if len(store.Weights) > 0 {
- args = append(args, "weights")
- for _, weight := range store.Weights {
- args = append(args, weight)
- }
- }
- if store.Aggregate != "" {
- args = append(args, "aggregate", store.Aggregate)
- }
- cmd := NewIntCmd(ctx, args...)
- cmd.setFirstKeyPos(3)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd {
- args := []interface{}{
- "zpopmax",
- key,
- }
-
- switch len(count) {
- case 0:
- break
- case 1:
- args = append(args, count[0])
- default:
- panic("too many arguments")
- }
-
- cmd := NewZSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd {
- args := []interface{}{
- "zpopmin",
- key,
- }
-
- switch len(count) {
- case 0:
- break
- case 1:
- args = append(args, count[0])
- default:
- panic("too many arguments")
- }
-
- cmd := NewZSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) zRange(ctx context.Context, key string, start, stop int64, withScores bool) *StringSliceCmd {
- args := []interface{}{
- "zrange",
- key,
- start,
- stop,
- }
- if withScores {
- args = append(args, "withscores")
- }
- cmd := NewStringSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
- return c.zRange(ctx, key, start, stop, false)
-}
-
-func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
- cmd := NewZSliceCmd(ctx, "zrange", key, start, stop, "withscores")
- _ = c(ctx, cmd)
- return cmd
-}
-
-type ZRangeBy struct {
- Min, Max string
- Offset, Count int64
-}
-
-func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd {
- args := []interface{}{zcmd, key, opt.Min, opt.Max}
- if withScores {
- args = append(args, "withscores")
- }
- if opt.Offset != 0 || opt.Count != 0 {
- args = append(
- args,
- "limit",
- opt.Offset,
- opt.Count,
- )
- }
- cmd := NewStringSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
- return c.zRangeBy(ctx, "zrangebyscore", key, opt, false)
-}
-
-func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
- return c.zRangeBy(ctx, "zrangebylex", key, opt, false)
-}
-
-func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
- args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"}
- if opt.Offset != 0 || opt.Count != 0 {
- args = append(
- args,
- "limit",
- opt.Offset,
- opt.Count,
- )
- }
- cmd := NewZSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd {
- cmd := NewIntCmd(ctx, "zrank", key, member)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
- args := make([]interface{}, 2, 2+len(members))
- args[0] = "zrem"
- args[1] = key
- args = appendArgs(args, members)
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd {
- cmd := NewIntCmd(
- ctx,
- "zremrangebyrank",
- key,
- start,
- stop,
- )
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd {
- cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd {
- cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
- cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd {
- args := []interface{}{zcmd, key, opt.Max, opt.Min}
- if opt.Offset != 0 || opt.Count != 0 {
- args = append(
- args,
- "limit",
- opt.Offset,
- opt.Count,
- )
- }
- cmd := NewStringSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
- return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt)
-}
-
-func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
- return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt)
-}
-
-func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
- args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"}
- if opt.Offset != 0 || opt.Count != 0 {
- args = append(
- args,
- "limit",
- opt.Offset,
- opt.Count,
- )
- }
- cmd := NewZSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd {
- cmd := NewIntCmd(ctx, "zrevrank", key, member)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd {
- cmd := NewFloatCmd(ctx, "zscore", key, member)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd {
- args := make([]interface{}, 3+len(store.Keys))
- args[0] = "zunionstore"
- args[1] = dest
- args[2] = len(store.Keys)
- for i, key := range store.Keys {
- args[3+i] = key
- }
- if len(store.Weights) > 0 {
- args = append(args, "weights")
- for _, weight := range store.Weights {
- args = append(args, weight)
- }
- }
- if store.Aggregate != "" {
- args = append(args, "aggregate", store.Aggregate)
- }
-
- cmd := NewIntCmd(ctx, args...)
- cmd.setFirstKeyPos(3)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd {
- args := make([]interface{}, 2, 2+len(els))
- args[0] = "pfadd"
- args[1] = key
- args = appendArgs(args, els)
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) PFCount(ctx context.Context, keys ...string) *IntCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "pfcount"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd {
- args := make([]interface{}, 2+len(keys))
- args[0] = "pfmerge"
- args[1] = dest
- for i, key := range keys {
- args[2+i] = key
- }
- cmd := NewStatusCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) BgRewriteAOF(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "bgrewriteaof")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) BgSave(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "bgsave")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClientKill(ctx context.Context, ipPort string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "client", "kill", ipPort)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// ClientKillByFilter is new style syntax, while the ClientKill is old
-//
-// CLIENT KILL [value] ... [value]
-func (c cmdable) ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd {
- args := make([]interface{}, 2+len(keys))
- args[0] = "client"
- args[1] = "kill"
- for i, key := range keys {
- args[2+i] = key
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClientList(ctx context.Context) *StringCmd {
- cmd := NewStringCmd(ctx, "client", "list")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClientPause(ctx context.Context, dur time.Duration) *BoolCmd {
- cmd := NewBoolCmd(ctx, "client", "pause", formatMs(ctx, dur))
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClientID(ctx context.Context) *IntCmd {
- cmd := NewIntCmd(ctx, "client", "id")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClientUnblock(ctx context.Context, id int64) *IntCmd {
- cmd := NewIntCmd(ctx, "client", "unblock", id)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClientUnblockWithError(ctx context.Context, id int64) *IntCmd {
- cmd := NewIntCmd(ctx, "client", "unblock", id, "error")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ConfigGet(ctx context.Context, parameter string) *SliceCmd {
- cmd := NewSliceCmd(ctx, "config", "get", parameter)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ConfigResetStat(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "config", "resetstat")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ConfigSet(ctx context.Context, parameter, value string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "config", "set", parameter, value)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ConfigRewrite(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "config", "rewrite")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) DBSize(ctx context.Context) *IntCmd {
- cmd := NewIntCmd(ctx, "dbsize")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) FlushAll(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "flushall")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) FlushAllAsync(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "flushall", "async")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) FlushDB(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "flushdb")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) FlushDBAsync(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "flushdb", "async")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Info(ctx context.Context, section ...string) *StringCmd {
- args := []interface{}{"info"}
- if len(section) > 0 {
- args = append(args, section[0])
- }
- cmd := NewStringCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) LastSave(ctx context.Context) *IntCmd {
- cmd := NewIntCmd(ctx, "lastsave")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Save(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "save")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) shutdown(ctx context.Context, modifier string) *StatusCmd {
- var args []interface{}
- if modifier == "" {
- args = []interface{}{"shutdown"}
- } else {
- args = []interface{}{"shutdown", modifier}
- }
- cmd := NewStatusCmd(ctx, args...)
- _ = c(ctx, cmd)
- if err := cmd.Err(); err != nil {
- if err == io.EOF {
- // Server quit as expected.
- cmd.err = nil
- }
- } else {
- // Server did not quit. String reply contains the reason.
- cmd.err = errors.New(cmd.val)
- cmd.val = ""
- }
- return cmd
-}
-
-func (c cmdable) Shutdown(ctx context.Context) *StatusCmd {
- return c.shutdown(ctx, "")
-}
-
-func (c cmdable) ShutdownSave(ctx context.Context) *StatusCmd {
- return c.shutdown(ctx, "save")
-}
-
-func (c cmdable) ShutdownNoSave(ctx context.Context) *StatusCmd {
- return c.shutdown(ctx, "nosave")
-}
-
-func (c cmdable) SlaveOf(ctx context.Context, host, port string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "slaveof", host, port)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) SlowLogGet(ctx context.Context, num int64) *SlowLogCmd {
- cmd := NewSlowLogCmd(context.Background(), "slowlog", "get", num)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) Sync(ctx context.Context) {
- panic("not implemented")
-}
-
-func (c cmdable) Time(ctx context.Context) *TimeCmd {
- cmd := NewTimeCmd(ctx, "time")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) DebugObject(ctx context.Context, key string) *StringCmd {
- cmd := NewStringCmd(ctx, "debug", "object", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ReadOnly(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "readonly")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ReadWrite(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "readwrite")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd {
- args := []interface{}{"memory", "usage", key}
- if len(samples) > 0 {
- if len(samples) != 1 {
- panic("MemoryUsage expects single sample count")
- }
- args = append(args, "SAMPLES", samples[0])
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
- cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
- cmdArgs[0] = "eval"
- cmdArgs[1] = script
- cmdArgs[2] = len(keys)
- for i, key := range keys {
- cmdArgs[3+i] = key
- }
- cmdArgs = appendArgs(cmdArgs, args)
- cmd := NewCmd(ctx, cmdArgs...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {
- cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
- cmdArgs[0] = "evalsha"
- cmdArgs[1] = sha1
- cmdArgs[2] = len(keys)
- for i, key := range keys {
- cmdArgs[3+i] = key
- }
- cmdArgs = appendArgs(cmdArgs, args)
- cmd := NewCmd(ctx, cmdArgs...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd {
- args := make([]interface{}, 2+len(hashes))
- args[0] = "script"
- args[1] = "exists"
- for i, hash := range hashes {
- args[2+i] = hash
- }
- cmd := NewBoolSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ScriptFlush(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "script", "flush")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ScriptKill(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "script", "kill")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ScriptLoad(ctx context.Context, script string) *StringCmd {
- cmd := NewStringCmd(ctx, "script", "load", script)
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-// Publish posts the message to the channel.
-func (c cmdable) Publish(ctx context.Context, channel string, message interface{}) *IntCmd {
- cmd := NewIntCmd(ctx, "publish", channel, message)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd {
- args := []interface{}{"pubsub", "channels"}
- if pattern != "*" {
- args = append(args, pattern)
- }
- cmd := NewStringSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd {
- args := make([]interface{}, 2+len(channels))
- args[0] = "pubsub"
- args[1] = "numsub"
- for i, channel := range channels {
- args[2+i] = channel
- }
- cmd := NewStringIntMapCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) PubSubNumPat(ctx context.Context) *IntCmd {
- cmd := NewIntCmd(ctx, "pubsub", "numpat")
- _ = c(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
- cmd := NewClusterSlotsCmd(ctx, "cluster", "slots")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterNodes(ctx context.Context) *StringCmd {
- cmd := NewStringCmd(ctx, "cluster", "nodes")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterMeet(ctx context.Context, host, port string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "cluster", "meet", host, port)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterForget(ctx context.Context, nodeID string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "cluster", "forget", nodeID)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "cluster", "replicate", nodeID)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterResetSoft(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "cluster", "reset", "soft")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterResetHard(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "cluster", "reset", "hard")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterInfo(ctx context.Context) *StringCmd {
- cmd := NewStringCmd(ctx, "cluster", "info")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterKeySlot(ctx context.Context, key string) *IntCmd {
- cmd := NewIntCmd(ctx, "cluster", "keyslot", key)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "cluster", "getkeysinslot", slot, count)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd {
- cmd := NewIntCmd(ctx, "cluster", "count-failure-reports", nodeID)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd {
- cmd := NewIntCmd(ctx, "cluster", "countkeysinslot", slot)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd {
- args := make([]interface{}, 2+len(slots))
- args[0] = "cluster"
- args[1] = "delslots"
- for i, slot := range slots {
- args[2+i] = slot
- }
- cmd := NewStatusCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd {
- size := max - min + 1
- slots := make([]int, size)
- for i := 0; i < size; i++ {
- slots[i] = min + i
- }
- return c.ClusterDelSlots(ctx, slots...)
-}
-
-func (c cmdable) ClusterSaveConfig(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "cluster", "saveconfig")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "cluster", "slaves", nodeID)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterFailover(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "cluster", "failover")
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd {
- args := make([]interface{}, 2+len(slots))
- args[0] = "cluster"
- args[1] = "addslots"
- for i, num := range slots {
- args[2+i] = num
- }
- cmd := NewStatusCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd {
- size := max - min + 1
- slots := make([]int, size)
- for i := 0; i < size; i++ {
- slots[i] = min + i
- }
- return c.ClusterAddSlots(ctx, slots...)
-}
-
-//------------------------------------------------------------------------------
-
-func (c cmdable) GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd {
- args := make([]interface{}, 2+3*len(geoLocation))
- args[0] = "geoadd"
- args[1] = key
- for i, eachLoc := range geoLocation {
- args[2+3*i] = eachLoc.Longitude
- args[2+3*i+1] = eachLoc.Latitude
- args[2+3*i+2] = eachLoc.Name
- }
- cmd := NewIntCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-// GeoRadius is a read-only GEORADIUS_RO command.
-func (c cmdable) GeoRadius(
- ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
-) *GeoLocationCmd {
- cmd := NewGeoLocationCmd(ctx, query, "georadius_ro", key, longitude, latitude)
- if query.Store != "" || query.StoreDist != "" {
- cmd.SetErr(errors.New("GeoRadius does not support Store or StoreDist"))
- return cmd
- }
- _ = c(ctx, cmd)
- return cmd
-}
-
-// GeoRadiusStore is a writing GEORADIUS command.
-func (c cmdable) GeoRadiusStore(
- ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
-) *IntCmd {
- args := geoLocationArgs(query, "georadius", key, longitude, latitude)
- cmd := NewIntCmd(ctx, args...)
- if query.Store == "" && query.StoreDist == "" {
- cmd.SetErr(errors.New("GeoRadiusStore requires Store or StoreDist"))
- return cmd
- }
- _ = c(ctx, cmd)
- return cmd
-}
-
-// GeoRadius is a read-only GEORADIUSBYMEMBER_RO command.
-func (c cmdable) GeoRadiusByMember(
- ctx context.Context, key, member string, query *GeoRadiusQuery,
-) *GeoLocationCmd {
- cmd := NewGeoLocationCmd(ctx, query, "georadiusbymember_ro", key, member)
- if query.Store != "" || query.StoreDist != "" {
- cmd.SetErr(errors.New("GeoRadiusByMember does not support Store or StoreDist"))
- return cmd
- }
- _ = c(ctx, cmd)
- return cmd
-}
-
-// GeoRadiusByMemberStore is a writing GEORADIUSBYMEMBER command.
-func (c cmdable) GeoRadiusByMemberStore(
- ctx context.Context, key, member string, query *GeoRadiusQuery,
-) *IntCmd {
- args := geoLocationArgs(query, "georadiusbymember", key, member)
- cmd := NewIntCmd(ctx, args...)
- if query.Store == "" && query.StoreDist == "" {
- cmd.SetErr(errors.New("GeoRadiusByMemberStore requires Store or StoreDist"))
- return cmd
- }
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) GeoDist(
- ctx context.Context, key string, member1, member2, unit string,
-) *FloatCmd {
- if unit == "" {
- unit = "km"
- }
- cmd := NewFloatCmd(ctx, "geodist", key, member1, member2, unit)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd {
- args := make([]interface{}, 2+len(members))
- args[0] = "geohash"
- args[1] = key
- for i, member := range members {
- args[2+i] = member
- }
- cmd := NewStringSliceCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
-
-func (c cmdable) GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd {
- args := make([]interface{}, 2+len(members))
- args[0] = "geopos"
- args[1] = key
- for i, member := range members {
- args[2+i] = member
- }
- cmd := NewGeoPosCmd(ctx, args...)
- _ = c(ctx, cmd)
- return cmd
-}
diff --git a/vendor/github.com/go-redis/redis/v8/doc.go b/vendor/github.com/go-redis/redis/v8/doc.go
deleted file mode 100644
index 55262533a63..00000000000
--- a/vendor/github.com/go-redis/redis/v8/doc.go
+++ /dev/null
@@ -1,4 +0,0 @@
-/*
-Package redis implements a Redis client.
-*/
-package redis
diff --git a/vendor/github.com/go-redis/redis/v8/error.go b/vendor/github.com/go-redis/redis/v8/error.go
deleted file mode 100644
index d29c0c99fee..00000000000
--- a/vendor/github.com/go-redis/redis/v8/error.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package redis
-
-import (
- "context"
- "io"
- "net"
- "strings"
-
- "github.com/go-redis/redis/v8/internal/pool"
- "github.com/go-redis/redis/v8/internal/proto"
-)
-
-var ErrClosed = pool.ErrClosed
-
-type Error interface {
- error
-
- // RedisError is a no-op function but
- // serves to distinguish types that are Redis
- // errors from ordinary errors: a type is a
- // Redis error if it has a RedisError method.
- RedisError()
-}
-
-var _ Error = proto.RedisError("")
-
-func shouldRetry(err error, retryTimeout bool) bool {
- switch err {
- case io.EOF, io.ErrUnexpectedEOF:
- return true
- case nil, context.Canceled, context.DeadlineExceeded:
- return false
- }
-
- if v, ok := err.(timeoutError); ok {
- if v.Timeout() {
- return retryTimeout
- }
- return true
- }
-
- s := err.Error()
- if s == "ERR max number of clients reached" {
- return true
- }
- if strings.HasPrefix(s, "LOADING ") {
- return true
- }
- if strings.HasPrefix(s, "READONLY ") {
- return true
- }
- if strings.HasPrefix(s, "CLUSTERDOWN ") {
- return true
- }
-
- return false
-}
-
-func isRedisError(err error) bool {
- _, ok := err.(proto.RedisError)
- return ok
-}
-
-func isBadConn(err error, allowTimeout bool) bool {
- if err == nil {
- return false
- }
-
- if isRedisError(err) {
- // Close connections in read only state in case domain addr is used
- // and domain resolves to a different Redis Server. See #790.
- return isReadOnlyError(err)
- }
-
- if allowTimeout {
- if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
- return !netErr.Temporary()
- }
- }
-
- return true
-}
-
-func isMovedError(err error) (moved bool, ask bool, addr string) {
- if !isRedisError(err) {
- return
- }
-
- s := err.Error()
- switch {
- case strings.HasPrefix(s, "MOVED "):
- moved = true
- case strings.HasPrefix(s, "ASK "):
- ask = true
- default:
- return
- }
-
- ind := strings.LastIndex(s, " ")
- if ind == -1 {
- return false, false, ""
- }
- addr = s[ind+1:]
- return
-}
-
-func isLoadingError(err error) bool {
- return strings.HasPrefix(err.Error(), "LOADING ")
-}
-
-func isReadOnlyError(err error) bool {
- return strings.HasPrefix(err.Error(), "READONLY ")
-}
-
-//------------------------------------------------------------------------------
-
-type timeoutError interface {
- Timeout() bool
-}
diff --git a/vendor/github.com/go-redis/redis/v8/go.mod b/vendor/github.com/go-redis/redis/v8/go.mod
deleted file mode 100644
index 272478a9879..00000000000
--- a/vendor/github.com/go-redis/redis/v8/go.mod
+++ /dev/null
@@ -1,11 +0,0 @@
-module github.com/go-redis/redis/v8
-
-go 1.11
-
-require (
- github.com/cespare/xxhash/v2 v2.1.1
- github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f
- github.com/onsi/ginkgo v1.14.1
- github.com/onsi/gomega v1.10.2
- go.opentelemetry.io/otel v0.13.0
-)
diff --git a/vendor/github.com/go-redis/redis/v8/go.sum b/vendor/github.com/go-redis/redis/v8/go.sum
deleted file mode 100644
index 6f2355b79f7..00000000000
--- a/vendor/github.com/go-redis/redis/v8/go.sum
+++ /dev/null
@@ -1,76 +0,0 @@
-github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
-github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
-github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
-github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
-github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
-github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
-go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
-golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/github.com/go-redis/redis/v8/internal/arg.go b/vendor/github.com/go-redis/redis/v8/internal/arg.go
deleted file mode 100644
index b97fa0d6851..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/arg.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strconv"
- "time"
-)
-
-func AppendArg(b []byte, v interface{}) []byte {
- switch v := v.(type) {
- case nil:
- return append(b, ""...)
- case string:
- return appendUTF8String(b, Bytes(v))
- case []byte:
- return appendUTF8String(b, v)
- case int:
- return strconv.AppendInt(b, int64(v), 10)
- case int8:
- return strconv.AppendInt(b, int64(v), 10)
- case int16:
- return strconv.AppendInt(b, int64(v), 10)
- case int32:
- return strconv.AppendInt(b, int64(v), 10)
- case int64:
- return strconv.AppendInt(b, v, 10)
- case uint:
- return strconv.AppendUint(b, uint64(v), 10)
- case uint8:
- return strconv.AppendUint(b, uint64(v), 10)
- case uint16:
- return strconv.AppendUint(b, uint64(v), 10)
- case uint32:
- return strconv.AppendUint(b, uint64(v), 10)
- case uint64:
- return strconv.AppendUint(b, v, 10)
- case float32:
- return strconv.AppendFloat(b, float64(v), 'f', -1, 64)
- case float64:
- return strconv.AppendFloat(b, v, 'f', -1, 64)
- case bool:
- if v {
- return append(b, "true"...)
- }
- return append(b, "false"...)
- case time.Time:
- return v.AppendFormat(b, time.RFC3339Nano)
- default:
- return append(b, fmt.Sprint(v)...)
- }
-}
-
-func appendUTF8String(dst []byte, src []byte) []byte {
- dst = append(dst, src...)
- return dst
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go b/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go
deleted file mode 100644
index 2fc74ad1cd0..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/hashtag/hashtag.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package hashtag
-
-import (
- "strings"
-
- "github.com/go-redis/redis/v8/internal/rand"
-)
-
-const slotNumber = 16384
-
-// CRC16 implementation according to CCITT standards.
-// Copyright 2001-2010 Georges Menie (www.menie.org)
-// Copyright 2013 The Go Authors. All rights reserved.
-// http://redis.io/topics/cluster-spec#appendix-a-crc16-reference-implementation-in-ansi-c
-var crc16tab = [256]uint16{
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
- 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
- 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
- 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
- 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
- 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
- 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
- 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
- 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
- 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
- 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
- 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
- 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
- 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
- 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
-}
-
-func Key(key string) string {
- if s := strings.IndexByte(key, '{'); s > -1 {
- if e := strings.IndexByte(key[s+1:], '}'); e > 0 {
- return key[s+1 : s+e+1]
- }
- }
- return key
-}
-
-func RandomSlot() int {
- return rand.Intn(slotNumber)
-}
-
-// hashSlot returns a consistent slot number between 0 and 16383
-// for any given string key.
-func Slot(key string) int {
- if key == "" {
- return RandomSlot()
- }
- key = Key(key)
- return int(crc16sum(key)) % slotNumber
-}
-
-func crc16sum(key string) (crc uint16) {
- for i := 0; i < len(key); i++ {
- crc = (crc << 8) ^ crc16tab[(byte(crc>>8)^key[i])&0x00ff]
- }
- return
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/instruments.go b/vendor/github.com/go-redis/redis/v8/internal/instruments.go
deleted file mode 100644
index e837526d894..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/instruments.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package internal
-
-import (
- "context"
-
- "go.opentelemetry.io/otel/api/global"
- "go.opentelemetry.io/otel/api/metric"
-)
-
-var (
- // WritesCounter is a count of write commands performed.
- WritesCounter metric.Int64Counter
- // NewConnectionsCounter is a count of new connections.
- NewConnectionsCounter metric.Int64Counter
-)
-
-func init() {
- defer func() {
- if r := recover(); r != nil {
- Logger.Printf(context.Background(), "Error creating meter github.com/go-redis/redis for Instruments", r)
- }
- }()
-
- meter := metric.Must(global.Meter("github.com/go-redis/redis"))
-
- WritesCounter = meter.NewInt64Counter("redis.writes",
- metric.WithDescription("the number of writes initiated"),
- )
-
- NewConnectionsCounter = meter.NewInt64Counter("redis.new_connections",
- metric.WithDescription("the number of connections created"),
- )
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/internal.go b/vendor/github.com/go-redis/redis/v8/internal/internal.go
deleted file mode 100644
index 735d6affd8b..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/internal.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package internal
-
-import (
- "time"
-
- "github.com/go-redis/redis/v8/internal/rand"
-)
-
-func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration {
- if retry < 0 {
- panic("not reached")
- }
- if minBackoff == 0 {
- return 0
- }
-
- d := minBackoff << uint(retry)
- d = minBackoff + time.Duration(rand.Int63n(int64(d)))
-
- if d > maxBackoff || d < minBackoff {
- d = maxBackoff
- }
-
- return d
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/log.go b/vendor/github.com/go-redis/redis/v8/internal/log.go
deleted file mode 100644
index 3810f9e4e7a..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/log.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package internal
-
-import (
- "context"
- "fmt"
- "log"
- "os"
-)
-
-type Logging interface {
- Printf(ctx context.Context, format string, v ...interface{})
-}
-
-type logger struct {
- log *log.Logger
-}
-
-func (l *logger) Printf(ctx context.Context, format string, v ...interface{}) {
- _ = l.log.Output(2, fmt.Sprintf(format, v...))
-}
-
-var Logger Logging = &logger{
- log: log.New(os.Stderr, "redis: ", log.LstdFlags|log.Lshortfile),
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/once.go b/vendor/github.com/go-redis/redis/v8/internal/once.go
deleted file mode 100644
index 64f46272aed..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/once.go
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-Copyright 2014 The Camlistore Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package internal
-
-import (
- "sync"
- "sync/atomic"
-)
-
-// A Once will perform a successful action exactly once.
-//
-// Unlike a sync.Once, this Once's func returns an error
-// and is re-armed on failure.
-type Once struct {
- m sync.Mutex
- done uint32
-}
-
-// Do calls the function f if and only if Do has not been invoked
-// without error for this instance of Once. In other words, given
-// var once Once
-// if once.Do(f) is called multiple times, only the first call will
-// invoke f, even if f has a different value in each invocation unless
-// f returns an error. A new instance of Once is required for each
-// function to execute.
-//
-// Do is intended for initialization that must be run exactly once. Since f
-// is niladic, it may be necessary to use a function literal to capture the
-// arguments to a function to be invoked by Do:
-// err := config.once.Do(func() error { return config.init(filename) })
-func (o *Once) Do(f func() error) error {
- if atomic.LoadUint32(&o.done) == 1 {
- return nil
- }
- // Slow-path.
- o.m.Lock()
- defer o.m.Unlock()
- var err error
- if o.done == 0 {
- err = f()
- if err == nil {
- atomic.StoreUint32(&o.done, 1)
- }
- }
- return err
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go b/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go
deleted file mode 100644
index b930a908800..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/pool/conn.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package pool
-
-import (
- "bufio"
- "context"
- "net"
- "sync/atomic"
- "time"
-
- "github.com/go-redis/redis/v8/internal"
- "github.com/go-redis/redis/v8/internal/proto"
- "go.opentelemetry.io/otel/api/trace"
-)
-
-var noDeadline = time.Time{}
-
-type Conn struct {
- usedAt int64 // atomic
- netConn net.Conn
-
- rd *proto.Reader
- bw *bufio.Writer
- wr *proto.Writer
-
- Inited bool
- pooled bool
- createdAt time.Time
-}
-
-func NewConn(netConn net.Conn) *Conn {
- cn := &Conn{
- netConn: netConn,
- createdAt: time.Now(),
- }
- cn.rd = proto.NewReader(netConn)
- cn.bw = bufio.NewWriter(netConn)
- cn.wr = proto.NewWriter(cn.bw)
- cn.SetUsedAt(time.Now())
- return cn
-}
-
-func (cn *Conn) UsedAt() time.Time {
- unix := atomic.LoadInt64(&cn.usedAt)
- return time.Unix(unix, 0)
-}
-
-func (cn *Conn) SetUsedAt(tm time.Time) {
- atomic.StoreInt64(&cn.usedAt, tm.Unix())
-}
-
-func (cn *Conn) SetNetConn(netConn net.Conn) {
- cn.netConn = netConn
- cn.rd.Reset(netConn)
- cn.bw.Reset(netConn)
-}
-
-func (cn *Conn) Write(b []byte) (int, error) {
- return cn.netConn.Write(b)
-}
-
-func (cn *Conn) RemoteAddr() net.Addr {
- if cn.netConn != nil {
- return cn.netConn.RemoteAddr()
- }
- return nil
-}
-
-func (cn *Conn) WithReader(ctx context.Context, timeout time.Duration, fn func(rd *proto.Reader) error) error {
- return internal.WithSpan(ctx, "with_reader", func(ctx context.Context, span trace.Span) error {
- if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil {
- return internal.RecordError(ctx, err)
- }
- if err := fn(cn.rd); err != nil {
- return internal.RecordError(ctx, err)
- }
- return nil
- })
-}
-
-func (cn *Conn) WithWriter(
- ctx context.Context, timeout time.Duration, fn func(wr *proto.Writer) error,
-) error {
- return internal.WithSpan(ctx, "with_writer", func(ctx context.Context, span trace.Span) error {
- if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil {
- return internal.RecordError(ctx, err)
- }
-
- if cn.bw.Buffered() > 0 {
- cn.bw.Reset(cn.netConn)
- }
-
- if err := fn(cn.wr); err != nil {
- return internal.RecordError(ctx, err)
- }
-
- if err := cn.bw.Flush(); err != nil {
- return internal.RecordError(ctx, err)
- }
-
- internal.WritesCounter.Add(ctx, 1)
-
- return nil
- })
-}
-
-func (cn *Conn) Close() error {
- return cn.netConn.Close()
-}
-
-func (cn *Conn) deadline(ctx context.Context, timeout time.Duration) time.Time {
- tm := time.Now()
- cn.SetUsedAt(tm)
-
- if timeout > 0 {
- tm = tm.Add(timeout)
- }
-
- if ctx != nil {
- deadline, ok := ctx.Deadline()
- if ok {
- if timeout == 0 {
- return deadline
- }
- if deadline.Before(tm) {
- return deadline
- }
- return tm
- }
- }
-
- if timeout > 0 {
- return tm
- }
-
- return noDeadline
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go b/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go
deleted file mode 100644
index 355742bf358..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/pool/pool.go
+++ /dev/null
@@ -1,524 +0,0 @@
-package pool
-
-import (
- "context"
- "errors"
- "net"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/go-redis/redis/v8/internal"
-)
-
-var (
- ErrClosed = errors.New("redis: client is closed")
- ErrPoolTimeout = errors.New("redis: connection pool timeout")
-)
-
-var timers = sync.Pool{
- New: func() interface{} {
- t := time.NewTimer(time.Hour)
- t.Stop()
- return t
- },
-}
-
-// Stats contains pool state information and accumulated stats.
-type Stats struct {
- Hits uint32 // number of times free connection was found in the pool
- Misses uint32 // number of times free connection was NOT found in the pool
- Timeouts uint32 // number of times a wait timeout occurred
-
- TotalConns uint32 // number of total connections in the pool
- IdleConns uint32 // number of idle connections in the pool
- StaleConns uint32 // number of stale connections removed from the pool
-}
-
-type Pooler interface {
- NewConn(context.Context) (*Conn, error)
- CloseConn(*Conn) error
-
- Get(context.Context) (*Conn, error)
- Put(context.Context, *Conn)
- Remove(context.Context, *Conn, error)
-
- Len() int
- IdleLen() int
- Stats() *Stats
-
- Close() error
-}
-
-type Options struct {
- Dialer func(context.Context) (net.Conn, error)
- OnClose func(*Conn) error
-
- PoolSize int
- MinIdleConns int
- MaxConnAge time.Duration
- PoolTimeout time.Duration
- IdleTimeout time.Duration
- IdleCheckFrequency time.Duration
-}
-
-type lastDialErrorWrap struct {
- err error
-}
-
-type ConnPool struct {
- opt *Options
-
- dialErrorsNum uint32 // atomic
-
- lastDialError atomic.Value
-
- queue chan struct{}
-
- connsMu sync.Mutex
- conns []*Conn
- idleConns []*Conn
- poolSize int
- idleConnsLen int
-
- stats Stats
-
- _closed uint32 // atomic
- closedCh chan struct{}
-}
-
-var _ Pooler = (*ConnPool)(nil)
-
-func NewConnPool(opt *Options) *ConnPool {
- p := &ConnPool{
- opt: opt,
-
- queue: make(chan struct{}, opt.PoolSize),
- conns: make([]*Conn, 0, opt.PoolSize),
- idleConns: make([]*Conn, 0, opt.PoolSize),
- closedCh: make(chan struct{}),
- }
-
- p.connsMu.Lock()
- p.checkMinIdleConns()
- p.connsMu.Unlock()
-
- if opt.IdleTimeout > 0 && opt.IdleCheckFrequency > 0 {
- go p.reaper(opt.IdleCheckFrequency)
- }
-
- return p
-}
-
-func (p *ConnPool) checkMinIdleConns() {
- if p.opt.MinIdleConns == 0 {
- return
- }
- for p.poolSize < p.opt.PoolSize && p.idleConnsLen < p.opt.MinIdleConns {
- p.poolSize++
- p.idleConnsLen++
- go func() {
- err := p.addIdleConn()
- if err != nil {
- p.connsMu.Lock()
- p.poolSize--
- p.idleConnsLen--
- p.connsMu.Unlock()
- }
- }()
- }
-}
-
-func (p *ConnPool) addIdleConn() error {
- cn, err := p.dialConn(context.TODO(), true)
- if err != nil {
- return err
- }
-
- p.connsMu.Lock()
- p.conns = append(p.conns, cn)
- p.idleConns = append(p.idleConns, cn)
- p.connsMu.Unlock()
- return nil
-}
-
-func (p *ConnPool) NewConn(ctx context.Context) (*Conn, error) {
- return p.newConn(ctx, false)
-}
-
-func (p *ConnPool) newConn(ctx context.Context, pooled bool) (*Conn, error) {
- cn, err := p.dialConn(ctx, pooled)
- if err != nil {
- return nil, err
- }
-
- p.connsMu.Lock()
- p.conns = append(p.conns, cn)
- if pooled {
- // If pool is full remove the cn on next Put.
- if p.poolSize >= p.opt.PoolSize {
- cn.pooled = false
- } else {
- p.poolSize++
- }
- }
- p.connsMu.Unlock()
-
- return cn, nil
-}
-
-func (p *ConnPool) dialConn(ctx context.Context, pooled bool) (*Conn, error) {
- if p.closed() {
- return nil, ErrClosed
- }
-
- if atomic.LoadUint32(&p.dialErrorsNum) >= uint32(p.opt.PoolSize) {
- return nil, p.getLastDialError()
- }
-
- netConn, err := p.opt.Dialer(ctx)
- if err != nil {
- p.setLastDialError(err)
- if atomic.AddUint32(&p.dialErrorsNum, 1) == uint32(p.opt.PoolSize) {
- go p.tryDial()
- }
- return nil, err
- }
-
- internal.NewConnectionsCounter.Add(ctx, 1)
- cn := NewConn(netConn)
- cn.pooled = pooled
- return cn, nil
-}
-
-func (p *ConnPool) tryDial() {
- for {
- if p.closed() {
- return
- }
-
- conn, err := p.opt.Dialer(context.Background())
- if err != nil {
- p.setLastDialError(err)
- time.Sleep(time.Second)
- continue
- }
-
- atomic.StoreUint32(&p.dialErrorsNum, 0)
- _ = conn.Close()
- return
- }
-}
-
-func (p *ConnPool) setLastDialError(err error) {
- p.lastDialError.Store(&lastDialErrorWrap{err: err})
-}
-
-func (p *ConnPool) getLastDialError() error {
- err, _ := p.lastDialError.Load().(*lastDialErrorWrap)
- if err != nil {
- return err.err
- }
- return nil
-}
-
-// Get returns existed connection from the pool or creates a new one.
-func (p *ConnPool) Get(ctx context.Context) (*Conn, error) {
- if p.closed() {
- return nil, ErrClosed
- }
-
- err := p.waitTurn(ctx)
- if err != nil {
- return nil, err
- }
-
- for {
- p.connsMu.Lock()
- cn := p.popIdle()
- p.connsMu.Unlock()
-
- if cn == nil {
- break
- }
-
- if p.isStaleConn(cn) {
- _ = p.CloseConn(cn)
- continue
- }
-
- atomic.AddUint32(&p.stats.Hits, 1)
- return cn, nil
- }
-
- atomic.AddUint32(&p.stats.Misses, 1)
-
- newcn, err := p.newConn(ctx, true)
- if err != nil {
- p.freeTurn()
- return nil, err
- }
-
- return newcn, nil
-}
-
-func (p *ConnPool) getTurn() {
- p.queue <- struct{}{}
-}
-
-func (p *ConnPool) waitTurn(ctx context.Context) error {
- select {
- case <-ctx.Done():
- return ctx.Err()
- default:
- }
-
- select {
- case p.queue <- struct{}{}:
- return nil
- default:
- }
-
- timer := timers.Get().(*time.Timer)
- timer.Reset(p.opt.PoolTimeout)
-
- select {
- case <-ctx.Done():
- if !timer.Stop() {
- <-timer.C
- }
- timers.Put(timer)
- return ctx.Err()
- case p.queue <- struct{}{}:
- if !timer.Stop() {
- <-timer.C
- }
- timers.Put(timer)
- return nil
- case <-timer.C:
- timers.Put(timer)
- atomic.AddUint32(&p.stats.Timeouts, 1)
- return ErrPoolTimeout
- }
-}
-
-func (p *ConnPool) freeTurn() {
- <-p.queue
-}
-
-func (p *ConnPool) popIdle() *Conn {
- if len(p.idleConns) == 0 {
- return nil
- }
-
- idx := len(p.idleConns) - 1
- cn := p.idleConns[idx]
- p.idleConns = p.idleConns[:idx]
- p.idleConnsLen--
- p.checkMinIdleConns()
- return cn
-}
-
-func (p *ConnPool) Put(ctx context.Context, cn *Conn) {
- if cn.rd.Buffered() > 0 {
- internal.Logger.Printf(ctx, "Conn has unread data")
- p.Remove(ctx, cn, BadConnError{})
- return
- }
-
- if !cn.pooled {
- p.Remove(ctx, cn, nil)
- return
- }
-
- p.connsMu.Lock()
- p.idleConns = append(p.idleConns, cn)
- p.idleConnsLen++
- p.connsMu.Unlock()
- p.freeTurn()
-}
-
-func (p *ConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
- p.removeConnWithLock(cn)
- p.freeTurn()
- _ = p.closeConn(cn)
-}
-
-func (p *ConnPool) CloseConn(cn *Conn) error {
- p.removeConnWithLock(cn)
- return p.closeConn(cn)
-}
-
-func (p *ConnPool) removeConnWithLock(cn *Conn) {
- p.connsMu.Lock()
- p.removeConn(cn)
- p.connsMu.Unlock()
-}
-
-func (p *ConnPool) removeConn(cn *Conn) {
- for i, c := range p.conns {
- if c == cn {
- p.conns = append(p.conns[:i], p.conns[i+1:]...)
- if cn.pooled {
- p.poolSize--
- p.checkMinIdleConns()
- }
- return
- }
- }
-}
-
-func (p *ConnPool) closeConn(cn *Conn) error {
- if p.opt.OnClose != nil {
- _ = p.opt.OnClose(cn)
- }
- return cn.Close()
-}
-
-// Len returns total number of connections.
-func (p *ConnPool) Len() int {
- p.connsMu.Lock()
- n := len(p.conns)
- p.connsMu.Unlock()
- return n
-}
-
-// IdleLen returns number of idle connections.
-func (p *ConnPool) IdleLen() int {
- p.connsMu.Lock()
- n := p.idleConnsLen
- p.connsMu.Unlock()
- return n
-}
-
-func (p *ConnPool) Stats() *Stats {
- idleLen := p.IdleLen()
- return &Stats{
- Hits: atomic.LoadUint32(&p.stats.Hits),
- Misses: atomic.LoadUint32(&p.stats.Misses),
- Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
-
- TotalConns: uint32(p.Len()),
- IdleConns: uint32(idleLen),
- StaleConns: atomic.LoadUint32(&p.stats.StaleConns),
- }
-}
-
-func (p *ConnPool) closed() bool {
- return atomic.LoadUint32(&p._closed) == 1
-}
-
-func (p *ConnPool) Filter(fn func(*Conn) bool) error {
- p.connsMu.Lock()
- defer p.connsMu.Unlock()
-
- var firstErr error
- for _, cn := range p.conns {
- if fn(cn) {
- if err := p.closeConn(cn); err != nil && firstErr == nil {
- firstErr = err
- }
- }
- }
- return firstErr
-}
-
-func (p *ConnPool) Close() error {
- if !atomic.CompareAndSwapUint32(&p._closed, 0, 1) {
- return ErrClosed
- }
- close(p.closedCh)
-
- var firstErr error
- p.connsMu.Lock()
- for _, cn := range p.conns {
- if err := p.closeConn(cn); err != nil && firstErr == nil {
- firstErr = err
- }
- }
- p.conns = nil
- p.poolSize = 0
- p.idleConns = nil
- p.idleConnsLen = 0
- p.connsMu.Unlock()
-
- return firstErr
-}
-
-func (p *ConnPool) reaper(frequency time.Duration) {
- ticker := time.NewTicker(frequency)
- defer ticker.Stop()
-
- for {
- select {
- case <-ticker.C:
- // It is possible that ticker and closedCh arrive together,
- // and select pseudo-randomly pick ticker case, we double
- // check here to prevent being executed after closed.
- if p.closed() {
- return
- }
- _, err := p.ReapStaleConns()
- if err != nil {
- internal.Logger.Printf(context.Background(), "ReapStaleConns failed: %s", err)
- continue
- }
- case <-p.closedCh:
- return
- }
- }
-}
-
-func (p *ConnPool) ReapStaleConns() (int, error) {
- var n int
- for {
- p.getTurn()
-
- p.connsMu.Lock()
- cn := p.reapStaleConn()
- p.connsMu.Unlock()
- p.freeTurn()
-
- if cn != nil {
- _ = p.closeConn(cn)
- n++
- } else {
- break
- }
- }
- atomic.AddUint32(&p.stats.StaleConns, uint32(n))
- return n, nil
-}
-
-func (p *ConnPool) reapStaleConn() *Conn {
- if len(p.idleConns) == 0 {
- return nil
- }
-
- cn := p.idleConns[0]
- if !p.isStaleConn(cn) {
- return nil
- }
-
- p.idleConns = append(p.idleConns[:0], p.idleConns[1:]...)
- p.idleConnsLen--
- p.removeConn(cn)
-
- return cn
-}
-
-func (p *ConnPool) isStaleConn(cn *Conn) bool {
- if p.opt.IdleTimeout == 0 && p.opt.MaxConnAge == 0 {
- return false
- }
-
- now := time.Now()
- if p.opt.IdleTimeout > 0 && now.Sub(cn.UsedAt()) >= p.opt.IdleTimeout {
- return true
- }
- if p.opt.MaxConnAge > 0 && now.Sub(cn.createdAt) >= p.opt.MaxConnAge {
- return true
- }
-
- return false
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/pool/pool_single.go b/vendor/github.com/go-redis/redis/v8/internal/pool/pool_single.go
deleted file mode 100644
index 5a3fde191bb..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/pool/pool_single.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package pool
-
-import "context"
-
-type SingleConnPool struct {
- pool Pooler
- cn *Conn
- stickyErr error
-}
-
-var _ Pooler = (*SingleConnPool)(nil)
-
-func NewSingleConnPool(pool Pooler, cn *Conn) *SingleConnPool {
- return &SingleConnPool{
- pool: pool,
- cn: cn,
- }
-}
-
-func (p *SingleConnPool) NewConn(ctx context.Context) (*Conn, error) {
- return p.pool.NewConn(ctx)
-}
-
-func (p *SingleConnPool) CloseConn(cn *Conn) error {
- return p.pool.CloseConn(cn)
-}
-
-func (p *SingleConnPool) Get(ctx context.Context) (*Conn, error) {
- if p.stickyErr != nil {
- return nil, p.stickyErr
- }
- return p.cn, nil
-}
-
-func (p *SingleConnPool) Put(ctx context.Context, cn *Conn) {}
-
-func (p *SingleConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
- p.cn = nil
- p.stickyErr = reason
-}
-
-func (p *SingleConnPool) Close() error {
- p.cn = nil
- p.stickyErr = ErrClosed
- return nil
-}
-
-func (p *SingleConnPool) Len() int {
- return 0
-}
-
-func (p *SingleConnPool) IdleLen() int {
- return 0
-}
-
-func (p *SingleConnPool) Stats() *Stats {
- return &Stats{}
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go b/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go
deleted file mode 100644
index c3e7e7c0458..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/pool/pool_sticky.go
+++ /dev/null
@@ -1,202 +0,0 @@
-package pool
-
-import (
- "context"
- "errors"
- "fmt"
- "sync/atomic"
-)
-
-const (
- stateDefault = 0
- stateInited = 1
- stateClosed = 2
-)
-
-type BadConnError struct {
- wrapped error
-}
-
-var _ error = (*BadConnError)(nil)
-
-func (e BadConnError) Error() string {
- s := "redis: Conn is in a bad state"
- if e.wrapped != nil {
- s += ": " + e.wrapped.Error()
- }
- return s
-}
-
-func (e BadConnError) Unwrap() error {
- return e.wrapped
-}
-
-//------------------------------------------------------------------------------
-
-type StickyConnPool struct {
- pool Pooler
- shared int32 // atomic
-
- state uint32 // atomic
- ch chan *Conn
-
- _badConnError atomic.Value
-}
-
-var _ Pooler = (*StickyConnPool)(nil)
-
-func NewStickyConnPool(pool Pooler) *StickyConnPool {
- p, ok := pool.(*StickyConnPool)
- if !ok {
- p = &StickyConnPool{
- pool: pool,
- ch: make(chan *Conn, 1),
- }
- }
- atomic.AddInt32(&p.shared, 1)
- return p
-}
-
-func (p *StickyConnPool) NewConn(ctx context.Context) (*Conn, error) {
- return p.pool.NewConn(ctx)
-}
-
-func (p *StickyConnPool) CloseConn(cn *Conn) error {
- return p.pool.CloseConn(cn)
-}
-
-func (p *StickyConnPool) Get(ctx context.Context) (*Conn, error) {
- // In worst case this races with Close which is not a very common operation.
- for i := 0; i < 1000; i++ {
- switch atomic.LoadUint32(&p.state) {
- case stateDefault:
- cn, err := p.pool.Get(ctx)
- if err != nil {
- return nil, err
- }
- if atomic.CompareAndSwapUint32(&p.state, stateDefault, stateInited) {
- return cn, nil
- }
- p.pool.Remove(ctx, cn, ErrClosed)
- case stateInited:
- if err := p.badConnError(); err != nil {
- return nil, err
- }
- cn, ok := <-p.ch
- if !ok {
- return nil, ErrClosed
- }
- return cn, nil
- case stateClosed:
- return nil, ErrClosed
- default:
- panic("not reached")
- }
- }
- return nil, fmt.Errorf("redis: StickyConnPool.Get: infinite loop")
-}
-
-func (p *StickyConnPool) Put(ctx context.Context, cn *Conn) {
- defer func() {
- if recover() != nil {
- p.freeConn(ctx, cn)
- }
- }()
- p.ch <- cn
-}
-
-func (p *StickyConnPool) freeConn(ctx context.Context, cn *Conn) {
- if err := p.badConnError(); err != nil {
- p.pool.Remove(ctx, cn, err)
- } else {
- p.pool.Put(ctx, cn)
- }
-}
-
-func (p *StickyConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
- defer func() {
- if recover() != nil {
- p.pool.Remove(ctx, cn, ErrClosed)
- }
- }()
- p._badConnError.Store(BadConnError{wrapped: reason})
- p.ch <- cn
-}
-
-func (p *StickyConnPool) Close() error {
- if shared := atomic.AddInt32(&p.shared, -1); shared > 0 {
- return nil
- }
-
- for i := 0; i < 1000; i++ {
- state := atomic.LoadUint32(&p.state)
- if state == stateClosed {
- return ErrClosed
- }
- if atomic.CompareAndSwapUint32(&p.state, state, stateClosed) {
- close(p.ch)
- cn, ok := <-p.ch
- if ok {
- p.freeConn(context.TODO(), cn)
- }
- return nil
- }
- }
-
- return errors.New("redis: StickyConnPool.Close: infinite loop")
-}
-
-func (p *StickyConnPool) Reset(ctx context.Context) error {
- if p.badConnError() == nil {
- return nil
- }
-
- select {
- case cn, ok := <-p.ch:
- if !ok {
- return ErrClosed
- }
- p.pool.Remove(ctx, cn, ErrClosed)
- p._badConnError.Store(BadConnError{wrapped: nil})
- default:
- return errors.New("redis: StickyConnPool does not have a Conn")
- }
-
- if !atomic.CompareAndSwapUint32(&p.state, stateInited, stateDefault) {
- state := atomic.LoadUint32(&p.state)
- return fmt.Errorf("redis: invalid StickyConnPool state: %d", state)
- }
-
- return nil
-}
-
-func (p *StickyConnPool) badConnError() error {
- if v := p._badConnError.Load(); v != nil {
- err := v.(BadConnError)
- if err.wrapped != nil {
- return err
- }
- }
- return nil
-}
-
-func (p *StickyConnPool) Len() int {
- switch atomic.LoadUint32(&p.state) {
- case stateDefault:
- return 0
- case stateInited:
- return 1
- case stateClosed:
- return 0
- default:
- panic("not reached")
- }
-}
-
-func (p *StickyConnPool) IdleLen() int {
- return len(p.ch)
-}
-
-func (p *StickyConnPool) Stats() *Stats {
- return &Stats{}
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go b/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go
deleted file mode 100644
index 0fbc51e9ac3..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/proto/reader.go
+++ /dev/null
@@ -1,331 +0,0 @@
-package proto
-
-import (
- "bufio"
- "fmt"
- "io"
-
- "github.com/go-redis/redis/v8/internal/util"
-)
-
-const (
- ErrorReply = '-'
- StatusReply = '+'
- IntReply = ':'
- StringReply = '$'
- ArrayReply = '*'
-)
-
-//------------------------------------------------------------------------------
-
-const Nil = RedisError("redis: nil")
-
-type RedisError string
-
-func (e RedisError) Error() string { return string(e) }
-
-func (RedisError) RedisError() {}
-
-//------------------------------------------------------------------------------
-
-type MultiBulkParse func(*Reader, int64) (interface{}, error)
-
-type Reader struct {
- rd *bufio.Reader
- _buf []byte
-}
-
-func NewReader(rd io.Reader) *Reader {
- return &Reader{
- rd: bufio.NewReader(rd),
- _buf: make([]byte, 64),
- }
-}
-
-func (r *Reader) Buffered() int {
- return r.rd.Buffered()
-}
-
-func (r *Reader) Peek(n int) ([]byte, error) {
- return r.rd.Peek(n)
-}
-
-func (r *Reader) Reset(rd io.Reader) {
- r.rd.Reset(rd)
-}
-
-func (r *Reader) ReadLine() ([]byte, error) {
- line, err := r.readLine()
- if err != nil {
- return nil, err
- }
- if isNilReply(line) {
- return nil, Nil
- }
- return line, nil
-}
-
-// readLine that returns an error if:
-// - there is a pending read error;
-// - or line does not end with \r\n.
-func (r *Reader) readLine() ([]byte, error) {
- b, err := r.rd.ReadSlice('\n')
- if err != nil {
- if err != bufio.ErrBufferFull {
- return nil, err
- }
-
- full := make([]byte, len(b))
- copy(full, b)
-
- b, err = r.rd.ReadBytes('\n')
- if err != nil {
- return nil, err
- }
-
- full = append(full, b...)
- b = full
- }
- if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' {
- return nil, fmt.Errorf("redis: invalid reply: %q", b)
- }
- return b[:len(b)-2], nil
-}
-
-func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) {
- line, err := r.ReadLine()
- if err != nil {
- return nil, err
- }
-
- switch line[0] {
- case ErrorReply:
- return nil, ParseErrorReply(line)
- case StatusReply:
- return string(line[1:]), nil
- case IntReply:
- return util.ParseInt(line[1:], 10, 64)
- case StringReply:
- return r.readStringReply(line)
- case ArrayReply:
- n, err := parseArrayLen(line)
- if err != nil {
- return nil, err
- }
- if m == nil {
- err := fmt.Errorf("redis: got %.100q, but multi bulk parser is nil", line)
- return nil, err
- }
- return m(r, n)
- }
- return nil, fmt.Errorf("redis: can't parse %.100q", line)
-}
-
-func (r *Reader) ReadIntReply() (int64, error) {
- line, err := r.ReadLine()
- if err != nil {
- return 0, err
- }
- switch line[0] {
- case ErrorReply:
- return 0, ParseErrorReply(line)
- case IntReply:
- return util.ParseInt(line[1:], 10, 64)
- default:
- return 0, fmt.Errorf("redis: can't parse int reply: %.100q", line)
- }
-}
-
-func (r *Reader) ReadString() (string, error) {
- line, err := r.ReadLine()
- if err != nil {
- return "", err
- }
- switch line[0] {
- case ErrorReply:
- return "", ParseErrorReply(line)
- case StringReply:
- return r.readStringReply(line)
- case StatusReply:
- return string(line[1:]), nil
- case IntReply:
- return string(line[1:]), nil
- default:
- return "", fmt.Errorf("redis: can't parse reply=%.100q reading string", line)
- }
-}
-
-func (r *Reader) readStringReply(line []byte) (string, error) {
- if isNilReply(line) {
- return "", Nil
- }
-
- replyLen, err := util.Atoi(line[1:])
- if err != nil {
- return "", err
- }
-
- b := make([]byte, replyLen+2)
- _, err = io.ReadFull(r.rd, b)
- if err != nil {
- return "", err
- }
-
- return util.BytesToString(b[:replyLen]), nil
-}
-
-func (r *Reader) ReadArrayReply(m MultiBulkParse) (interface{}, error) {
- line, err := r.ReadLine()
- if err != nil {
- return nil, err
- }
- switch line[0] {
- case ErrorReply:
- return nil, ParseErrorReply(line)
- case ArrayReply:
- n, err := parseArrayLen(line)
- if err != nil {
- return nil, err
- }
- return m(r, n)
- default:
- return nil, fmt.Errorf("redis: can't parse array reply: %.100q", line)
- }
-}
-
-func (r *Reader) ReadArrayLen() (int, error) {
- line, err := r.ReadLine()
- if err != nil {
- return 0, err
- }
- switch line[0] {
- case ErrorReply:
- return 0, ParseErrorReply(line)
- case ArrayReply:
- n, err := parseArrayLen(line)
- if err != nil {
- return 0, err
- }
- return int(n), nil
- default:
- return 0, fmt.Errorf("redis: can't parse array reply: %.100q", line)
- }
-}
-
-func (r *Reader) ReadScanReply() ([]string, uint64, error) {
- n, err := r.ReadArrayLen()
- if err != nil {
- return nil, 0, err
- }
- if n != 2 {
- return nil, 0, fmt.Errorf("redis: got %d elements in scan reply, expected 2", n)
- }
-
- cursor, err := r.ReadUint()
- if err != nil {
- return nil, 0, err
- }
-
- n, err = r.ReadArrayLen()
- if err != nil {
- return nil, 0, err
- }
-
- keys := make([]string, n)
-
- for i := 0; i < n; i++ {
- key, err := r.ReadString()
- if err != nil {
- return nil, 0, err
- }
- keys[i] = key
- }
-
- return keys, cursor, err
-}
-
-func (r *Reader) ReadInt() (int64, error) {
- b, err := r.readTmpBytesReply()
- if err != nil {
- return 0, err
- }
- return util.ParseInt(b, 10, 64)
-}
-
-func (r *Reader) ReadUint() (uint64, error) {
- b, err := r.readTmpBytesReply()
- if err != nil {
- return 0, err
- }
- return util.ParseUint(b, 10, 64)
-}
-
-func (r *Reader) ReadFloatReply() (float64, error) {
- b, err := r.readTmpBytesReply()
- if err != nil {
- return 0, err
- }
- return util.ParseFloat(b, 64)
-}
-
-func (r *Reader) readTmpBytesReply() ([]byte, error) {
- line, err := r.ReadLine()
- if err != nil {
- return nil, err
- }
- switch line[0] {
- case ErrorReply:
- return nil, ParseErrorReply(line)
- case StringReply:
- return r._readTmpBytesReply(line)
- case StatusReply:
- return line[1:], nil
- default:
- return nil, fmt.Errorf("redis: can't parse string reply: %.100q", line)
- }
-}
-
-func (r *Reader) _readTmpBytesReply(line []byte) ([]byte, error) {
- if isNilReply(line) {
- return nil, Nil
- }
-
- replyLen, err := util.Atoi(line[1:])
- if err != nil {
- return nil, err
- }
-
- buf := r.buf(replyLen + 2)
- _, err = io.ReadFull(r.rd, buf)
- if err != nil {
- return nil, err
- }
-
- return buf[:replyLen], nil
-}
-
-func (r *Reader) buf(n int) []byte {
- if n <= cap(r._buf) {
- return r._buf[:n]
- }
- d := n - cap(r._buf)
- r._buf = append(r._buf, make([]byte, d)...)
- return r._buf
-}
-
-func isNilReply(b []byte) bool {
- return len(b) == 3 &&
- (b[0] == StringReply || b[0] == ArrayReply) &&
- b[1] == '-' && b[2] == '1'
-}
-
-func ParseErrorReply(line []byte) error {
- return RedisError(string(line[1:]))
-}
-
-func parseArrayLen(line []byte) (int64, error) {
- if isNilReply(line) {
- return 0, Nil
- }
- return util.ParseInt(line[1:], 10, 64)
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go b/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go
deleted file mode 100644
index 08d18d35e43..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/proto/scan.go
+++ /dev/null
@@ -1,173 +0,0 @@
-package proto
-
-import (
- "encoding"
- "fmt"
- "reflect"
- "time"
-
- "github.com/go-redis/redis/v8/internal/util"
-)
-
-// Scan parses bytes `b` to `v` with appropriate type.
-// nolint: gocyclo
-func Scan(b []byte, v interface{}) error {
- switch v := v.(type) {
- case nil:
- return fmt.Errorf("redis: Scan(nil)")
- case *string:
- *v = util.BytesToString(b)
- return nil
- case *[]byte:
- *v = b
- return nil
- case *int:
- var err error
- *v, err = util.Atoi(b)
- return err
- case *int8:
- n, err := util.ParseInt(b, 10, 8)
- if err != nil {
- return err
- }
- *v = int8(n)
- return nil
- case *int16:
- n, err := util.ParseInt(b, 10, 16)
- if err != nil {
- return err
- }
- *v = int16(n)
- return nil
- case *int32:
- n, err := util.ParseInt(b, 10, 32)
- if err != nil {
- return err
- }
- *v = int32(n)
- return nil
- case *int64:
- n, err := util.ParseInt(b, 10, 64)
- if err != nil {
- return err
- }
- *v = n
- return nil
- case *uint:
- n, err := util.ParseUint(b, 10, 64)
- if err != nil {
- return err
- }
- *v = uint(n)
- return nil
- case *uint8:
- n, err := util.ParseUint(b, 10, 8)
- if err != nil {
- return err
- }
- *v = uint8(n)
- return nil
- case *uint16:
- n, err := util.ParseUint(b, 10, 16)
- if err != nil {
- return err
- }
- *v = uint16(n)
- return nil
- case *uint32:
- n, err := util.ParseUint(b, 10, 32)
- if err != nil {
- return err
- }
- *v = uint32(n)
- return nil
- case *uint64:
- n, err := util.ParseUint(b, 10, 64)
- if err != nil {
- return err
- }
- *v = n
- return nil
- case *float32:
- n, err := util.ParseFloat(b, 32)
- if err != nil {
- return err
- }
- *v = float32(n)
- return err
- case *float64:
- var err error
- *v, err = util.ParseFloat(b, 64)
- return err
- case *bool:
- *v = len(b) == 1 && b[0] == '1'
- return nil
- case *time.Time:
- var err error
- *v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b))
- return err
- case encoding.BinaryUnmarshaler:
- return v.UnmarshalBinary(b)
- default:
- return fmt.Errorf(
- "redis: can't unmarshal %T (consider implementing BinaryUnmarshaler)", v)
- }
-}
-
-func ScanSlice(data []string, slice interface{}) error {
- v := reflect.ValueOf(slice)
- if !v.IsValid() {
- return fmt.Errorf("redis: ScanSlice(nil)")
- }
- if v.Kind() != reflect.Ptr {
- return fmt.Errorf("redis: ScanSlice(non-pointer %T)", slice)
- }
- v = v.Elem()
- if v.Kind() != reflect.Slice {
- return fmt.Errorf("redis: ScanSlice(non-slice %T)", slice)
- }
-
- next := makeSliceNextElemFunc(v)
- for i, s := range data {
- elem := next()
- if err := Scan([]byte(s), elem.Addr().Interface()); err != nil {
- err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %s", i, s, err)
- return err
- }
- }
-
- return nil
-}
-
-func makeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
- elemType := v.Type().Elem()
-
- if elemType.Kind() == reflect.Ptr {
- elemType = elemType.Elem()
- return func() reflect.Value {
- if v.Len() < v.Cap() {
- v.Set(v.Slice(0, v.Len()+1))
- elem := v.Index(v.Len() - 1)
- if elem.IsNil() {
- elem.Set(reflect.New(elemType))
- }
- return elem.Elem()
- }
-
- elem := reflect.New(elemType)
- v.Set(reflect.Append(v, elem))
- return elem.Elem()
- }
- }
-
- zero := reflect.Zero(elemType)
- return func() reflect.Value {
- if v.Len() < v.Cap() {
- v.Set(v.Slice(0, v.Len()+1))
- return v.Index(v.Len() - 1)
- }
-
- v.Set(reflect.Append(v, zero))
- return v.Index(v.Len() - 1)
- }
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/proto/writer.go b/vendor/github.com/go-redis/redis/v8/internal/proto/writer.go
deleted file mode 100644
index 81b09b8e4f7..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/proto/writer.go
+++ /dev/null
@@ -1,153 +0,0 @@
-package proto
-
-import (
- "encoding"
- "fmt"
- "io"
- "strconv"
- "time"
-
- "github.com/go-redis/redis/v8/internal/util"
-)
-
-type writer interface {
- io.Writer
- io.ByteWriter
- // io.StringWriter
- WriteString(s string) (n int, err error)
-}
-
-type Writer struct {
- writer
-
- lenBuf []byte
- numBuf []byte
-}
-
-func NewWriter(wr writer) *Writer {
- return &Writer{
- writer: wr,
-
- lenBuf: make([]byte, 64),
- numBuf: make([]byte, 64),
- }
-}
-
-func (w *Writer) WriteArgs(args []interface{}) error {
- if err := w.WriteByte(ArrayReply); err != nil {
- return err
- }
-
- if err := w.writeLen(len(args)); err != nil {
- return err
- }
-
- for _, arg := range args {
- if err := w.WriteArg(arg); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (w *Writer) writeLen(n int) error {
- w.lenBuf = strconv.AppendUint(w.lenBuf[:0], uint64(n), 10)
- w.lenBuf = append(w.lenBuf, '\r', '\n')
- _, err := w.Write(w.lenBuf)
- return err
-}
-
-func (w *Writer) WriteArg(v interface{}) error {
- switch v := v.(type) {
- case nil:
- return w.string("")
- case string:
- return w.string(v)
- case []byte:
- return w.bytes(v)
- case int:
- return w.int(int64(v))
- case int8:
- return w.int(int64(v))
- case int16:
- return w.int(int64(v))
- case int32:
- return w.int(int64(v))
- case int64:
- return w.int(v)
- case uint:
- return w.uint(uint64(v))
- case uint8:
- return w.uint(uint64(v))
- case uint16:
- return w.uint(uint64(v))
- case uint32:
- return w.uint(uint64(v))
- case uint64:
- return w.uint(v)
- case float32:
- return w.float(float64(v))
- case float64:
- return w.float(v)
- case bool:
- if v {
- return w.int(1)
- }
- return w.int(0)
- case time.Time:
- w.numBuf = v.AppendFormat(w.numBuf[:0], time.RFC3339Nano)
- return w.bytes(w.numBuf)
- case encoding.BinaryMarshaler:
- b, err := v.MarshalBinary()
- if err != nil {
- return err
- }
- return w.bytes(b)
- default:
- return fmt.Errorf(
- "redis: can't marshal %T (implement encoding.BinaryMarshaler)", v)
- }
-}
-
-func (w *Writer) bytes(b []byte) error {
- if err := w.WriteByte(StringReply); err != nil {
- return err
- }
-
- if err := w.writeLen(len(b)); err != nil {
- return err
- }
-
- if _, err := w.Write(b); err != nil {
- return err
- }
-
- return w.crlf()
-}
-
-func (w *Writer) string(s string) error {
- return w.bytes(util.StringToBytes(s))
-}
-
-func (w *Writer) uint(n uint64) error {
- w.numBuf = strconv.AppendUint(w.numBuf[:0], n, 10)
- return w.bytes(w.numBuf)
-}
-
-func (w *Writer) int(n int64) error {
- w.numBuf = strconv.AppendInt(w.numBuf[:0], n, 10)
- return w.bytes(w.numBuf)
-}
-
-func (w *Writer) float(f float64) error {
- w.numBuf = strconv.AppendFloat(w.numBuf[:0], f, 'f', -1, 64)
- return w.bytes(w.numBuf)
-}
-
-func (w *Writer) crlf() error {
- if err := w.WriteByte('\r'); err != nil {
- return err
- }
- return w.WriteByte('\n')
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go b/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go
deleted file mode 100644
index 40676f3cb66..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/rand/rand.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package rand
-
-import (
- "math/rand"
- "sync"
-)
-
-// Int returns a non-negative pseudo-random int.
-func Int() int { return pseudo.Int() }
-
-// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
-// It panics if n <= 0.
-func Intn(n int) int { return pseudo.Intn(n) }
-
-// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
-// It panics if n <= 0.
-func Int63n(n int64) int64 { return pseudo.Int63n(n) }
-
-// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
-func Perm(n int) []int { return pseudo.Perm(n) }
-
-// Seed uses the provided seed value to initialize the default Source to a
-// deterministic state. If Seed is not called, the generator behaves as if
-// seeded by Seed(1).
-func Seed(n int64) { pseudo.Seed(n) }
-
-var pseudo = rand.New(&source{src: rand.NewSource(1)})
-
-type source struct {
- src rand.Source
- mu sync.Mutex
-}
-
-func (s *source) Int63() int64 {
- s.mu.Lock()
- n := s.src.Int63()
- s.mu.Unlock()
- return n
-}
-
-func (s *source) Seed(seed int64) {
- s.mu.Lock()
- s.src.Seed(seed)
- s.mu.Unlock()
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/safe.go b/vendor/github.com/go-redis/redis/v8/internal/safe.go
deleted file mode 100644
index 862ff0eb3af..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/safe.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build appengine
-
-package internal
-
-func String(b []byte) string {
- return string(b)
-}
-
-func Bytes(s string) []byte {
- return []byte(s)
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/unsafe.go b/vendor/github.com/go-redis/redis/v8/internal/unsafe.go
deleted file mode 100644
index 4bc79701f49..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/unsafe.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// +build !appengine
-
-package internal
-
-import "unsafe"
-
-// String converts byte slice to string.
-func String(b []byte) string {
- return *(*string)(unsafe.Pointer(&b))
-}
-
-// Bytes converts string to byte slice.
-func Bytes(s string) []byte {
- return *(*[]byte)(unsafe.Pointer(
- &struct {
- string
- Cap int
- }{s, len(s)},
- ))
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/util.go b/vendor/github.com/go-redis/redis/v8/internal/util.go
deleted file mode 100644
index 9c861b0f419..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/util.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package internal
-
-import (
- "context"
- "time"
-
- "github.com/go-redis/redis/v8/internal/proto"
- "github.com/go-redis/redis/v8/internal/util"
- "go.opentelemetry.io/otel/api/global"
- "go.opentelemetry.io/otel/api/trace"
-)
-
-func Sleep(ctx context.Context, dur time.Duration) error {
- return WithSpan(ctx, "sleep", func(ctx context.Context, span trace.Span) error {
- t := time.NewTimer(dur)
- defer t.Stop()
-
- select {
- case <-t.C:
- return nil
- case <-ctx.Done():
- return ctx.Err()
- }
- })
-}
-
-func ToLower(s string) string {
- if isLower(s) {
- return s
- }
-
- b := make([]byte, len(s))
- for i := range b {
- c := s[i]
- if c >= 'A' && c <= 'Z' {
- c += 'a' - 'A'
- }
- b[i] = c
- }
- return util.BytesToString(b)
-}
-
-func isLower(s string) bool {
- for i := 0; i < len(s); i++ {
- c := s[i]
- if c >= 'A' && c <= 'Z' {
- return false
- }
- }
- return true
-}
-
-func Unwrap(err error) error {
- u, ok := err.(interface {
- Unwrap() error
- })
- if !ok {
- return nil
- }
- return u.Unwrap()
-}
-
-//------------------------------------------------------------------------------
-
-func WithSpan(ctx context.Context, name string, fn func(context.Context, trace.Span) error) error {
- if span := trace.SpanFromContext(ctx); !span.IsRecording() {
- return fn(ctx, span)
- }
-
- ctx, span := global.Tracer("github.com/go-redis/redis").Start(ctx, name)
- defer span.End()
-
- return fn(ctx, span)
-}
-
-func RecordError(ctx context.Context, err error) error {
- if err != proto.Nil {
- trace.SpanFromContext(ctx).RecordError(ctx, err)
- }
- return err
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/util/safe.go b/vendor/github.com/go-redis/redis/v8/internal/util/safe.go
deleted file mode 100644
index 1b3060ebc2f..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/util/safe.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build appengine
-
-package util
-
-func BytesToString(b []byte) string {
- return string(b)
-}
-
-func StringToBytes(s string) []byte {
- return []byte(s)
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/util/strconv.go b/vendor/github.com/go-redis/redis/v8/internal/util/strconv.go
deleted file mode 100644
index db5033802a9..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/util/strconv.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package util
-
-import "strconv"
-
-func Atoi(b []byte) (int, error) {
- return strconv.Atoi(BytesToString(b))
-}
-
-func ParseInt(b []byte, base int, bitSize int) (int64, error) {
- return strconv.ParseInt(BytesToString(b), base, bitSize)
-}
-
-func ParseUint(b []byte, base int, bitSize int) (uint64, error) {
- return strconv.ParseUint(BytesToString(b), base, bitSize)
-}
-
-func ParseFloat(b []byte, bitSize int) (float64, error) {
- return strconv.ParseFloat(BytesToString(b), bitSize)
-}
diff --git a/vendor/github.com/go-redis/redis/v8/internal/util/unsafe.go b/vendor/github.com/go-redis/redis/v8/internal/util/unsafe.go
deleted file mode 100644
index c9868aac2b4..00000000000
--- a/vendor/github.com/go-redis/redis/v8/internal/util/unsafe.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// +build !appengine
-
-package util
-
-import (
- "unsafe"
-)
-
-// BytesToString converts byte slice to string.
-func BytesToString(b []byte) string {
- return *(*string)(unsafe.Pointer(&b))
-}
-
-// StringToBytes converts string to byte slice.
-func StringToBytes(s string) []byte {
- return *(*[]byte)(unsafe.Pointer(
- &struct {
- string
- Cap int
- }{s, len(s)},
- ))
-}
diff --git a/vendor/github.com/go-redis/redis/v8/iterator.go b/vendor/github.com/go-redis/redis/v8/iterator.go
deleted file mode 100644
index 2f8bc2beda0..00000000000
--- a/vendor/github.com/go-redis/redis/v8/iterator.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package redis
-
-import (
- "context"
- "sync"
-)
-
-// ScanIterator is used to incrementally iterate over a collection of elements.
-// It's safe for concurrent use by multiple goroutines.
-type ScanIterator struct {
- mu sync.Mutex // protects Scanner and pos
- cmd *ScanCmd
- pos int
-}
-
-// Err returns the last iterator error, if any.
-func (it *ScanIterator) Err() error {
- it.mu.Lock()
- err := it.cmd.Err()
- it.mu.Unlock()
- return err
-}
-
-// Next advances the cursor and returns true if more values can be read.
-func (it *ScanIterator) Next(ctx context.Context) bool {
- it.mu.Lock()
- defer it.mu.Unlock()
-
- // Instantly return on errors.
- if it.cmd.Err() != nil {
- return false
- }
-
- // Advance cursor, check if we are still within range.
- if it.pos < len(it.cmd.page) {
- it.pos++
- return true
- }
-
- for {
- // Return if there is no more data to fetch.
- if it.cmd.cursor == 0 {
- return false
- }
-
- // Fetch next page.
- switch it.cmd.args[0] {
- case "scan", "qscan":
- it.cmd.args[1] = it.cmd.cursor
- default:
- it.cmd.args[2] = it.cmd.cursor
- }
-
- err := it.cmd.process(ctx, it.cmd)
- if err != nil {
- return false
- }
-
- it.pos = 1
-
- // Redis can occasionally return empty page.
- if len(it.cmd.page) > 0 {
- return true
- }
- }
-}
-
-// Val returns the key/field at the current cursor position.
-func (it *ScanIterator) Val() string {
- var v string
- it.mu.Lock()
- if it.cmd.Err() == nil && it.pos > 0 && it.pos <= len(it.cmd.page) {
- v = it.cmd.page[it.pos-1]
- }
- it.mu.Unlock()
- return v
-}
diff --git a/vendor/github.com/go-redis/redis/v8/options.go b/vendor/github.com/go-redis/redis/v8/options.go
deleted file mode 100644
index b3d3196a068..00000000000
--- a/vendor/github.com/go-redis/redis/v8/options.go
+++ /dev/null
@@ -1,317 +0,0 @@
-package redis
-
-import (
- "context"
- "crypto/tls"
- "errors"
- "fmt"
- "net"
- "net/url"
- "runtime"
- "strconv"
- "strings"
- "time"
-
- "github.com/go-redis/redis/v8/internal"
- "github.com/go-redis/redis/v8/internal/pool"
- "go.opentelemetry.io/otel/api/trace"
- "go.opentelemetry.io/otel/label"
-)
-
-// Limiter is the interface of a rate limiter or a circuit breaker.
-type Limiter interface {
- // Allow returns nil if operation is allowed or an error otherwise.
- // If operation is allowed client must ReportResult of the operation
- // whether it is a success or a failure.
- Allow() error
- // ReportResult reports the result of the previously allowed operation.
- // nil indicates a success, non-nil error usually indicates a failure.
- ReportResult(result error)
-}
-
-// Options keeps the settings to setup redis connection.
-type Options struct {
- // The network type, either tcp or unix.
- // Default is tcp.
- Network string
- // host:port address.
- Addr string
-
- // Dialer creates new network connection and has priority over
- // Network and Addr options.
- Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
-
- // Hook that is called when new connection is established.
- OnConnect func(ctx context.Context, cn *Conn) error
-
- // Use the specified Username to authenticate the current connection
- // with one of the connections defined in the ACL list when connecting
- // to a Redis 6.0 instance, or greater, that is using the Redis ACL system.
- Username string
- // Optional password. Must match the password specified in the
- // requirepass server configuration option (if connecting to a Redis 5.0 instance, or lower),
- // or the User Password when connecting to a Redis 6.0 instance, or greater,
- // that is using the Redis ACL system.
- Password string
-
- // Database to be selected after connecting to the server.
- DB int
-
- // Maximum number of retries before giving up.
- // Default is 3 retries.
- MaxRetries int
- // Minimum backoff between each retry.
- // Default is 8 milliseconds; -1 disables backoff.
- MinRetryBackoff time.Duration
- // Maximum backoff between each retry.
- // Default is 512 milliseconds; -1 disables backoff.
- MaxRetryBackoff time.Duration
-
- // Dial timeout for establishing new connections.
- // Default is 5 seconds.
- DialTimeout time.Duration
- // Timeout for socket reads. If reached, commands will fail
- // with a timeout instead of blocking. Use value -1 for no timeout and 0 for default.
- // Default is 3 seconds.
- ReadTimeout time.Duration
- // Timeout for socket writes. If reached, commands will fail
- // with a timeout instead of blocking.
- // Default is ReadTimeout.
- WriteTimeout time.Duration
-
- // Maximum number of socket connections.
- // Default is 10 connections per every CPU as reported by runtime.NumCPU.
- PoolSize int
- // Minimum number of idle connections which is useful when establishing
- // new connection is slow.
- MinIdleConns int
- // Connection age at which client retires (closes) the connection.
- // Default is to not close aged connections.
- MaxConnAge time.Duration
- // Amount of time client waits for connection if all connections
- // are busy before returning an error.
- // Default is ReadTimeout + 1 second.
- PoolTimeout time.Duration
- // Amount of time after which client closes idle connections.
- // Should be less than server's timeout.
- // Default is 5 minutes. -1 disables idle timeout check.
- IdleTimeout time.Duration
- // Frequency of idle checks made by idle connections reaper.
- // Default is 1 minute. -1 disables idle connections reaper,
- // but idle connections are still discarded by the client
- // if IdleTimeout is set.
- IdleCheckFrequency time.Duration
-
- // Enables read only queries on slave nodes.
- readOnly bool
-
- // TLS Config to use. When set TLS will be negotiated.
- TLSConfig *tls.Config
-
- // Limiter interface used to implemented circuit breaker or rate limiter.
- Limiter Limiter
-}
-
-func (opt *Options) init() {
- if opt.Addr == "" {
- opt.Addr = "localhost:6379"
- }
- if opt.Network == "" {
- if strings.HasPrefix(opt.Addr, "/") {
- opt.Network = "unix"
- } else {
- opt.Network = "tcp"
- }
- }
- if opt.DialTimeout == 0 {
- opt.DialTimeout = 5 * time.Second
- }
- if opt.Dialer == nil {
- opt.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) {
- netDialer := &net.Dialer{
- Timeout: opt.DialTimeout,
- KeepAlive: 5 * time.Minute,
- }
- if opt.TLSConfig == nil {
- return netDialer.DialContext(ctx, network, addr)
- }
- return tls.DialWithDialer(netDialer, network, addr, opt.TLSConfig)
- }
- }
- if opt.PoolSize == 0 {
- opt.PoolSize = 10 * runtime.NumCPU()
- }
- switch opt.ReadTimeout {
- case -1:
- opt.ReadTimeout = 0
- case 0:
- opt.ReadTimeout = 3 * time.Second
- }
- switch opt.WriteTimeout {
- case -1:
- opt.WriteTimeout = 0
- case 0:
- opt.WriteTimeout = opt.ReadTimeout
- }
- if opt.PoolTimeout == 0 {
- opt.PoolTimeout = opt.ReadTimeout + time.Second
- }
- if opt.IdleTimeout == 0 {
- opt.IdleTimeout = 5 * time.Minute
- }
- if opt.IdleCheckFrequency == 0 {
- opt.IdleCheckFrequency = time.Minute
- }
-
- if opt.MaxRetries == -1 {
- opt.MaxRetries = 0
- } else if opt.MaxRetries == 0 {
- opt.MaxRetries = 3
- }
- switch opt.MinRetryBackoff {
- case -1:
- opt.MinRetryBackoff = 0
- case 0:
- opt.MinRetryBackoff = 8 * time.Millisecond
- }
- switch opt.MaxRetryBackoff {
- case -1:
- opt.MaxRetryBackoff = 0
- case 0:
- opt.MaxRetryBackoff = 512 * time.Millisecond
- }
-}
-
-func (opt *Options) clone() *Options {
- clone := *opt
- return &clone
-}
-
-// ParseURL parses an URL into Options that can be used to connect to Redis.
-// Scheme is required.
-// There are two connection types: by tcp socket and by unix socket.
-// Tcp connection:
-// redis://:@:/
-// Unix connection:
-// unix://:@?db=
-func ParseURL(redisURL string) (*Options, error) {
- u, err := url.Parse(redisURL)
- if err != nil {
- return nil, err
- }
-
- switch u.Scheme {
- case "redis", "rediss":
- return setupTCPConn(u)
- case "unix":
- return setupUnixConn(u)
- default:
- return nil, fmt.Errorf("redis: invalid URL scheme: %s", u.Scheme)
- }
-}
-
-func setupTCPConn(u *url.URL) (*Options, error) {
- o := &Options{Network: "tcp"}
-
- o.Username, o.Password = getUserPassword(u)
-
- if len(u.Query()) > 0 {
- return nil, errors.New("redis: no options supported")
- }
-
- h, p, err := net.SplitHostPort(u.Host)
- if err != nil {
- h = u.Host
- }
- if h == "" {
- h = "localhost"
- }
- if p == "" {
- p = "6379"
- }
- o.Addr = net.JoinHostPort(h, p)
-
- f := strings.FieldsFunc(u.Path, func(r rune) bool {
- return r == '/'
- })
- switch len(f) {
- case 0:
- o.DB = 0
- case 1:
- if o.DB, err = strconv.Atoi(f[0]); err != nil {
- return nil, fmt.Errorf("redis: invalid database number: %q", f[0])
- }
- default:
- return nil, fmt.Errorf("redis: invalid URL path: %s", u.Path)
- }
-
- if u.Scheme == "rediss" {
- o.TLSConfig = &tls.Config{ServerName: h}
- }
-
- return o, nil
-}
-
-func setupUnixConn(u *url.URL) (*Options, error) {
- o := &Options{
- Network: "unix",
- }
-
- if strings.TrimSpace(u.Path) == "" { // path is required with unix connection
- return nil, errors.New("redis: empty unix socket path")
- }
- o.Addr = u.Path
-
- o.Username, o.Password = getUserPassword(u)
-
- dbStr := u.Query().Get("db")
- if dbStr == "" {
- return o, nil // if database is not set, connect to 0 db.
- }
-
- db, err := strconv.Atoi(dbStr)
- if err != nil {
- return nil, fmt.Errorf("redis: invalid database number: %s", err)
- }
- o.DB = db
-
- return o, nil
-}
-
-func getUserPassword(u *url.URL) (string, string) {
- var user, password string
- if u.User != nil {
- user = u.User.Username()
- if p, ok := u.User.Password(); ok {
- password = p
- }
- }
- return user, password
-}
-
-func newConnPool(opt *Options) *pool.ConnPool {
- return pool.NewConnPool(&pool.Options{
- Dialer: func(ctx context.Context) (net.Conn, error) {
- var conn net.Conn
- err := internal.WithSpan(ctx, "dialer", func(ctx context.Context, span trace.Span) error {
- var err error
- span.SetAttributes(
- label.String("redis.network", opt.Network),
- label.String("redis.addr", opt.Addr),
- )
- conn, err = opt.Dialer(ctx, opt.Network, opt.Addr)
- if err != nil {
- _ = internal.RecordError(ctx, err)
- }
- return err
- })
- return conn, err
- },
- PoolSize: opt.PoolSize,
- MinIdleConns: opt.MinIdleConns,
- MaxConnAge: opt.MaxConnAge,
- PoolTimeout: opt.PoolTimeout,
- IdleTimeout: opt.IdleTimeout,
- IdleCheckFrequency: opt.IdleCheckFrequency,
- })
-}
diff --git a/vendor/github.com/go-redis/redis/v8/pipeline.go b/vendor/github.com/go-redis/redis/v8/pipeline.go
deleted file mode 100644
index c6ec3409980..00000000000
--- a/vendor/github.com/go-redis/redis/v8/pipeline.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package redis
-
-import (
- "context"
- "sync"
-
- "github.com/go-redis/redis/v8/internal/pool"
-)
-
-type pipelineExecer func(context.Context, []Cmder) error
-
-// Pipeliner is an mechanism to realise Redis Pipeline technique.
-//
-// Pipelining is a technique to extremely speed up processing by packing
-// operations to batches, send them at once to Redis and read a replies in a
-// singe step.
-// See https://redis.io/topics/pipelining
-//
-// Pay attention, that Pipeline is not a transaction, so you can get unexpected
-// results in case of big pipelines and small read/write timeouts.
-// Redis client has retransmission logic in case of timeouts, pipeline
-// can be retransmitted and commands can be executed more then once.
-// To avoid this: it is good idea to use reasonable bigger read/write timeouts
-// depends of your batch size and/or use TxPipeline.
-type Pipeliner interface {
- StatefulCmdable
- Do(ctx context.Context, args ...interface{}) *Cmd
- Process(ctx context.Context, cmd Cmder) error
- Close() error
- Discard() error
- Exec(ctx context.Context) ([]Cmder, error)
-}
-
-var _ Pipeliner = (*Pipeline)(nil)
-
-// Pipeline implements pipelining as described in
-// http://redis.io/topics/pipelining. It's safe for concurrent use
-// by multiple goroutines.
-type Pipeline struct {
- cmdable
- statefulCmdable
-
- ctx context.Context
- exec pipelineExecer
-
- mu sync.Mutex
- cmds []Cmder
- closed bool
-}
-
-func (c *Pipeline) init() {
- c.cmdable = c.Process
- c.statefulCmdable = c.Process
-}
-
-func (c *Pipeline) Do(ctx context.Context, args ...interface{}) *Cmd {
- cmd := NewCmd(ctx, args...)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Process queues the cmd for later execution.
-func (c *Pipeline) Process(ctx context.Context, cmd Cmder) error {
- c.mu.Lock()
- c.cmds = append(c.cmds, cmd)
- c.mu.Unlock()
- return nil
-}
-
-// Close closes the pipeline, releasing any open resources.
-func (c *Pipeline) Close() error {
- c.mu.Lock()
- _ = c.discard()
- c.closed = true
- c.mu.Unlock()
- return nil
-}
-
-// Discard resets the pipeline and discards queued commands.
-func (c *Pipeline) Discard() error {
- c.mu.Lock()
- err := c.discard()
- c.mu.Unlock()
- return err
-}
-
-func (c *Pipeline) discard() error {
- if c.closed {
- return pool.ErrClosed
- }
- c.cmds = c.cmds[:0]
- return nil
-}
-
-// Exec executes all previously queued commands using one
-// client-server roundtrip.
-//
-// Exec always returns list of commands and error of the first failed
-// command if any.
-func (c *Pipeline) Exec(ctx context.Context) ([]Cmder, error) {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if c.closed {
- return nil, pool.ErrClosed
- }
-
- if len(c.cmds) == 0 {
- return nil, nil
- }
-
- cmds := c.cmds
- c.cmds = nil
-
- return cmds, c.exec(ctx, cmds)
-}
-
-func (c *Pipeline) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- if err := fn(c); err != nil {
- return nil, err
- }
- cmds, err := c.Exec(ctx)
- _ = c.Close()
- return cmds, err
-}
-
-func (c *Pipeline) Pipeline() Pipeliner {
- return c
-}
-
-func (c *Pipeline) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.Pipelined(ctx, fn)
-}
-
-func (c *Pipeline) TxPipeline() Pipeliner {
- return c
-}
diff --git a/vendor/github.com/go-redis/redis/v8/pubsub.go b/vendor/github.com/go-redis/redis/v8/pubsub.go
deleted file mode 100644
index c56270b443e..00000000000
--- a/vendor/github.com/go-redis/redis/v8/pubsub.go
+++ /dev/null
@@ -1,629 +0,0 @@
-package redis
-
-import (
- "context"
- "errors"
- "fmt"
- "strings"
- "sync"
- "time"
-
- "github.com/go-redis/redis/v8/internal"
- "github.com/go-redis/redis/v8/internal/pool"
- "github.com/go-redis/redis/v8/internal/proto"
-)
-
-const (
- pingTimeout = time.Second
- chanSendTimeout = time.Minute
-)
-
-var errPingTimeout = errors.New("redis: ping timeout")
-
-// PubSub implements Pub/Sub commands as described in
-// http://redis.io/topics/pubsub. Message receiving is NOT safe
-// for concurrent use by multiple goroutines.
-//
-// PubSub automatically reconnects to Redis Server and resubscribes
-// to the channels in case of network errors.
-type PubSub struct {
- opt *Options
-
- newConn func(ctx context.Context, channels []string) (*pool.Conn, error)
- closeConn func(*pool.Conn) error
-
- mu sync.Mutex
- cn *pool.Conn
- channels map[string]struct{}
- patterns map[string]struct{}
-
- closed bool
- exit chan struct{}
-
- cmd *Cmd
-
- chOnce sync.Once
- msgCh chan *Message
- allCh chan interface{}
- ping chan struct{}
-}
-
-func (c *PubSub) String() string {
- channels := mapKeys(c.channels)
- channels = append(channels, mapKeys(c.patterns)...)
- return fmt.Sprintf("PubSub(%s)", strings.Join(channels, ", "))
-}
-
-func (c *PubSub) init() {
- c.exit = make(chan struct{})
-}
-
-func (c *PubSub) connWithLock(ctx context.Context) (*pool.Conn, error) {
- c.mu.Lock()
- cn, err := c.conn(ctx, nil)
- c.mu.Unlock()
- return cn, err
-}
-
-func (c *PubSub) conn(ctx context.Context, newChannels []string) (*pool.Conn, error) {
- if c.closed {
- return nil, pool.ErrClosed
- }
- if c.cn != nil {
- return c.cn, nil
- }
-
- channels := mapKeys(c.channels)
- channels = append(channels, newChannels...)
-
- cn, err := c.newConn(ctx, channels)
- if err != nil {
- return nil, err
- }
-
- if err := c.resubscribe(ctx, cn); err != nil {
- _ = c.closeConn(cn)
- return nil, err
- }
-
- c.cn = cn
- return cn, nil
-}
-
-func (c *PubSub) writeCmd(ctx context.Context, cn *pool.Conn, cmd Cmder) error {
- return cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
- return writeCmd(wr, cmd)
- })
-}
-
-func (c *PubSub) resubscribe(ctx context.Context, cn *pool.Conn) error {
- var firstErr error
-
- if len(c.channels) > 0 {
- firstErr = c._subscribe(ctx, cn, "subscribe", mapKeys(c.channels))
- }
-
- if len(c.patterns) > 0 {
- err := c._subscribe(ctx, cn, "psubscribe", mapKeys(c.patterns))
- if err != nil && firstErr == nil {
- firstErr = err
- }
- }
-
- return firstErr
-}
-
-func mapKeys(m map[string]struct{}) []string {
- s := make([]string, len(m))
- i := 0
- for k := range m {
- s[i] = k
- i++
- }
- return s
-}
-
-func (c *PubSub) _subscribe(
- ctx context.Context, cn *pool.Conn, redisCmd string, channels []string,
-) error {
- args := make([]interface{}, 0, 1+len(channels))
- args = append(args, redisCmd)
- for _, channel := range channels {
- args = append(args, channel)
- }
- cmd := NewSliceCmd(ctx, args...)
- return c.writeCmd(ctx, cn, cmd)
-}
-
-func (c *PubSub) releaseConnWithLock(
- ctx context.Context,
- cn *pool.Conn,
- err error,
- allowTimeout bool,
-) {
- c.mu.Lock()
- c.releaseConn(ctx, cn, err, allowTimeout)
- c.mu.Unlock()
-}
-
-func (c *PubSub) releaseConn(ctx context.Context, cn *pool.Conn, err error, allowTimeout bool) {
- if c.cn != cn {
- return
- }
- if isBadConn(err, allowTimeout) {
- c.reconnect(ctx, err)
- }
-}
-
-func (c *PubSub) reconnect(ctx context.Context, reason error) {
- _ = c.closeTheCn(reason)
- _, _ = c.conn(ctx, nil)
-}
-
-func (c *PubSub) closeTheCn(reason error) error {
- if c.cn == nil {
- return nil
- }
- if !c.closed {
- internal.Logger.Printf(c.getContext(), "redis: discarding bad PubSub connection: %s", reason)
- }
- err := c.closeConn(c.cn)
- c.cn = nil
- return err
-}
-
-func (c *PubSub) Close() error {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if c.closed {
- return pool.ErrClosed
- }
- c.closed = true
- close(c.exit)
-
- return c.closeTheCn(pool.ErrClosed)
-}
-
-// Subscribe the client to the specified channels. It returns
-// empty subscription if there are no channels.
-func (c *PubSub) Subscribe(ctx context.Context, channels ...string) error {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- err := c.subscribe(ctx, "subscribe", channels...)
- if c.channels == nil {
- c.channels = make(map[string]struct{})
- }
- for _, s := range channels {
- c.channels[s] = struct{}{}
- }
- return err
-}
-
-// PSubscribe the client to the given patterns. It returns
-// empty subscription if there are no patterns.
-func (c *PubSub) PSubscribe(ctx context.Context, patterns ...string) error {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- err := c.subscribe(ctx, "psubscribe", patterns...)
- if c.patterns == nil {
- c.patterns = make(map[string]struct{})
- }
- for _, s := range patterns {
- c.patterns[s] = struct{}{}
- }
- return err
-}
-
-// Unsubscribe the client from the given channels, or from all of
-// them if none is given.
-func (c *PubSub) Unsubscribe(ctx context.Context, channels ...string) error {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- for _, channel := range channels {
- delete(c.channels, channel)
- }
- err := c.subscribe(ctx, "unsubscribe", channels...)
- return err
-}
-
-// PUnsubscribe the client from the given patterns, or from all of
-// them if none is given.
-func (c *PubSub) PUnsubscribe(ctx context.Context, patterns ...string) error {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- for _, pattern := range patterns {
- delete(c.patterns, pattern)
- }
- err := c.subscribe(ctx, "punsubscribe", patterns...)
- return err
-}
-
-func (c *PubSub) subscribe(ctx context.Context, redisCmd string, channels ...string) error {
- cn, err := c.conn(ctx, channels)
- if err != nil {
- return err
- }
-
- err = c._subscribe(ctx, cn, redisCmd, channels)
- c.releaseConn(ctx, cn, err, false)
- return err
-}
-
-func (c *PubSub) Ping(ctx context.Context, payload ...string) error {
- args := []interface{}{"ping"}
- if len(payload) == 1 {
- args = append(args, payload[0])
- }
- cmd := NewCmd(ctx, args...)
-
- cn, err := c.connWithLock(ctx)
- if err != nil {
- return err
- }
-
- err = c.writeCmd(ctx, cn, cmd)
- c.releaseConnWithLock(ctx, cn, err, false)
- return err
-}
-
-// Subscription received after a successful subscription to channel.
-type Subscription struct {
- // Can be "subscribe", "unsubscribe", "psubscribe" or "punsubscribe".
- Kind string
- // Channel name we have subscribed to.
- Channel string
- // Number of channels we are currently subscribed to.
- Count int
-}
-
-func (m *Subscription) String() string {
- return fmt.Sprintf("%s: %s", m.Kind, m.Channel)
-}
-
-// Message received as result of a PUBLISH command issued by another client.
-type Message struct {
- Channel string
- Pattern string
- Payload string
- PayloadSlice []string
-}
-
-func (m *Message) String() string {
- return fmt.Sprintf("Message<%s: %s>", m.Channel, m.Payload)
-}
-
-// Pong received as result of a PING command issued by another client.
-type Pong struct {
- Payload string
-}
-
-func (p *Pong) String() string {
- if p.Payload != "" {
- return fmt.Sprintf("Pong<%s>", p.Payload)
- }
- return "Pong"
-}
-
-func (c *PubSub) newMessage(reply interface{}) (interface{}, error) {
- switch reply := reply.(type) {
- case string:
- return &Pong{
- Payload: reply,
- }, nil
- case []interface{}:
- switch kind := reply[0].(string); kind {
- case "subscribe", "unsubscribe", "psubscribe", "punsubscribe":
- // Can be nil in case of "unsubscribe".
- channel, _ := reply[1].(string)
- return &Subscription{
- Kind: kind,
- Channel: channel,
- Count: int(reply[2].(int64)),
- }, nil
- case "message":
- switch payload := reply[2].(type) {
- case string:
- return &Message{
- Channel: reply[1].(string),
- Payload: payload,
- }, nil
- case []interface{}:
- ss := make([]string, len(payload))
- for i, s := range payload {
- ss[i] = s.(string)
- }
- return &Message{
- Channel: reply[1].(string),
- PayloadSlice: ss,
- }, nil
- default:
- return nil, fmt.Errorf("redis: unsupported pubsub message payload: %T", payload)
- }
- case "pmessage":
- return &Message{
- Pattern: reply[1].(string),
- Channel: reply[2].(string),
- Payload: reply[3].(string),
- }, nil
- case "pong":
- return &Pong{
- Payload: reply[1].(string),
- }, nil
- default:
- return nil, fmt.Errorf("redis: unsupported pubsub message: %q", kind)
- }
- default:
- return nil, fmt.Errorf("redis: unsupported pubsub message: %#v", reply)
- }
-}
-
-// ReceiveTimeout acts like Receive but returns an error if message
-// is not received in time. This is low-level API and in most cases
-// Channel should be used instead.
-func (c *PubSub) ReceiveTimeout(ctx context.Context, timeout time.Duration) (interface{}, error) {
- if c.cmd == nil {
- c.cmd = NewCmd(ctx)
- }
-
- cn, err := c.connWithLock(ctx)
- if err != nil {
- return nil, err
- }
-
- err = cn.WithReader(ctx, timeout, func(rd *proto.Reader) error {
- return c.cmd.readReply(rd)
- })
-
- c.releaseConnWithLock(ctx, cn, err, timeout > 0)
- if err != nil {
- return nil, err
- }
-
- return c.newMessage(c.cmd.Val())
-}
-
-// Receive returns a message as a Subscription, Message, Pong or error.
-// See PubSub example for details. This is low-level API and in most cases
-// Channel should be used instead.
-func (c *PubSub) Receive(ctx context.Context) (interface{}, error) {
- return c.ReceiveTimeout(ctx, 0)
-}
-
-// ReceiveMessage returns a Message or error ignoring Subscription and Pong
-// messages. This is low-level API and in most cases Channel should be used
-// instead.
-func (c *PubSub) ReceiveMessage(ctx context.Context) (*Message, error) {
- for {
- msg, err := c.Receive(ctx)
- if err != nil {
- return nil, err
- }
-
- switch msg := msg.(type) {
- case *Subscription:
- // Ignore.
- case *Pong:
- // Ignore.
- case *Message:
- return msg, nil
- default:
- err := fmt.Errorf("redis: unknown message: %T", msg)
- return nil, err
- }
- }
-}
-
-// Channel returns a Go channel for concurrently receiving messages.
-// The channel is closed together with the PubSub. If the Go channel
-// is blocked full for 30 seconds the message is dropped.
-// Receive* APIs can not be used after channel is created.
-//
-// go-redis periodically sends ping messages to test connection health
-// and re-subscribes if ping can not not received for 30 seconds.
-func (c *PubSub) Channel() <-chan *Message {
- return c.ChannelSize(100)
-}
-
-// ChannelSize is like Channel, but creates a Go channel
-// with specified buffer size.
-func (c *PubSub) ChannelSize(size int) <-chan *Message {
- c.chOnce.Do(func() {
- c.initPing()
- c.initMsgChan(size)
- })
- if c.msgCh == nil {
- err := fmt.Errorf("redis: Channel can't be called after ChannelWithSubscriptions")
- panic(err)
- }
- if cap(c.msgCh) != size {
- err := fmt.Errorf("redis: PubSub.Channel size can not be changed once created")
- panic(err)
- }
- return c.msgCh
-}
-
-// ChannelWithSubscriptions is like Channel, but message type can be either
-// *Subscription or *Message. Subscription messages can be used to detect
-// reconnections.
-//
-// ChannelWithSubscriptions can not be used together with Channel or ChannelSize.
-func (c *PubSub) ChannelWithSubscriptions(ctx context.Context, size int) <-chan interface{} {
- c.chOnce.Do(func() {
- c.initPing()
- c.initAllChan(size)
- })
- if c.allCh == nil {
- err := fmt.Errorf("redis: ChannelWithSubscriptions can't be called after Channel")
- panic(err)
- }
- if cap(c.allCh) != size {
- err := fmt.Errorf("redis: PubSub.Channel size can not be changed once created")
- panic(err)
- }
- return c.allCh
-}
-
-func (c *PubSub) getContext() context.Context {
- if c.cmd != nil {
- return c.cmd.ctx
- }
- return context.Background()
-}
-
-func (c *PubSub) initPing() {
- ctx := context.TODO()
- c.ping = make(chan struct{}, 1)
- go func() {
- timer := time.NewTimer(time.Minute)
- timer.Stop()
-
- healthy := true
- for {
- timer.Reset(pingTimeout)
- select {
- case <-c.ping:
- healthy = true
- if !timer.Stop() {
- <-timer.C
- }
- case <-timer.C:
- pingErr := c.Ping(ctx)
- if healthy {
- healthy = false
- } else {
- if pingErr == nil {
- pingErr = errPingTimeout
- }
- c.mu.Lock()
- c.reconnect(ctx, pingErr)
- healthy = true
- c.mu.Unlock()
- }
- case <-c.exit:
- return
- }
- }
- }()
-}
-
-// initMsgChan must be in sync with initAllChan.
-func (c *PubSub) initMsgChan(size int) {
- ctx := context.TODO()
- c.msgCh = make(chan *Message, size)
- go func() {
- timer := time.NewTimer(time.Minute)
- timer.Stop()
-
- var errCount int
- for {
- msg, err := c.Receive(ctx)
- if err != nil {
- if err == pool.ErrClosed {
- close(c.msgCh)
- return
- }
- if errCount > 0 {
- time.Sleep(100 * time.Millisecond)
- }
- errCount++
- continue
- }
-
- errCount = 0
-
- // Any message is as good as a ping.
- select {
- case c.ping <- struct{}{}:
- default:
- }
-
- switch msg := msg.(type) {
- case *Subscription:
- // Ignore.
- case *Pong:
- // Ignore.
- case *Message:
- timer.Reset(chanSendTimeout)
- select {
- case c.msgCh <- msg:
- if !timer.Stop() {
- <-timer.C
- }
- case <-timer.C:
- internal.Logger.Printf(
- c.getContext(),
- "redis: %s channel is full for %s (message is dropped)",
- c,
- chanSendTimeout,
- )
- }
- default:
- internal.Logger.Printf(c.getContext(), "redis: unknown message type: %T", msg)
- }
- }
- }()
-}
-
-// initAllChan must be in sync with initMsgChan.
-func (c *PubSub) initAllChan(size int) {
- ctx := context.TODO()
- c.allCh = make(chan interface{}, size)
- go func() {
- timer := time.NewTimer(pingTimeout)
- timer.Stop()
-
- var errCount int
- for {
- msg, err := c.Receive(ctx)
- if err != nil {
- if err == pool.ErrClosed {
- close(c.allCh)
- return
- }
- if errCount > 0 {
- time.Sleep(100 * time.Millisecond)
- }
- errCount++
- continue
- }
-
- errCount = 0
-
- // Any message is as good as a ping.
- select {
- case c.ping <- struct{}{}:
- default:
- }
-
- switch msg := msg.(type) {
- case *Subscription:
- c.sendMessage(msg, timer)
- case *Pong:
- // Ignore.
- case *Message:
- c.sendMessage(msg, timer)
- default:
- internal.Logger.Printf(c.getContext(), "redis: unknown message type: %T", msg)
- }
- }
- }()
-}
-
-func (c *PubSub) sendMessage(msg interface{}, timer *time.Timer) {
- timer.Reset(pingTimeout)
- select {
- case c.allCh <- msg:
- if !timer.Stop() {
- <-timer.C
- }
- case <-timer.C:
- internal.Logger.Printf(
- c.getContext(),
- "redis: %s channel is full for %s (message is dropped)", c, pingTimeout)
- }
-}
diff --git a/vendor/github.com/go-redis/redis/v8/redis.go b/vendor/github.com/go-redis/redis/v8/redis.go
deleted file mode 100644
index b70fef3191d..00000000000
--- a/vendor/github.com/go-redis/redis/v8/redis.go
+++ /dev/null
@@ -1,774 +0,0 @@
-package redis
-
-import (
- "context"
- "fmt"
- "time"
-
- "github.com/go-redis/redis/v8/internal"
- "github.com/go-redis/redis/v8/internal/pool"
- "github.com/go-redis/redis/v8/internal/proto"
- "go.opentelemetry.io/otel/api/trace"
- "go.opentelemetry.io/otel/label"
-)
-
-// Nil reply returned by Redis when key does not exist.
-const Nil = proto.Nil
-
-func SetLogger(logger internal.Logging) {
- internal.Logger = logger
-}
-
-//------------------------------------------------------------------------------
-
-type Hook interface {
- BeforeProcess(ctx context.Context, cmd Cmder) (context.Context, error)
- AfterProcess(ctx context.Context, cmd Cmder) error
-
- BeforeProcessPipeline(ctx context.Context, cmds []Cmder) (context.Context, error)
- AfterProcessPipeline(ctx context.Context, cmds []Cmder) error
-}
-
-type hooks struct {
- hooks []Hook
-}
-
-func (hs *hooks) lock() {
- hs.hooks = hs.hooks[:len(hs.hooks):len(hs.hooks)]
-}
-
-func (hs hooks) clone() hooks {
- clone := hs
- clone.lock()
- return clone
-}
-
-func (hs *hooks) AddHook(hook Hook) {
- hs.hooks = append(hs.hooks, hook)
-}
-
-func (hs hooks) process(
- ctx context.Context, cmd Cmder, fn func(context.Context, Cmder) error,
-) error {
- if len(hs.hooks) == 0 {
- err := hs.withContext(ctx, func() error {
- return fn(ctx, cmd)
- })
- cmd.SetErr(err)
- return err
- }
-
- var hookIndex int
- var retErr error
-
- for ; hookIndex < len(hs.hooks) && retErr == nil; hookIndex++ {
- ctx, retErr = hs.hooks[hookIndex].BeforeProcess(ctx, cmd)
- if retErr != nil {
- cmd.SetErr(retErr)
- }
- }
-
- if retErr == nil {
- retErr = hs.withContext(ctx, func() error {
- return fn(ctx, cmd)
- })
- cmd.SetErr(retErr)
- }
-
- for hookIndex--; hookIndex >= 0; hookIndex-- {
- if err := hs.hooks[hookIndex].AfterProcess(ctx, cmd); err != nil {
- retErr = err
- cmd.SetErr(retErr)
- }
- }
-
- return retErr
-}
-
-func (hs hooks) processPipeline(
- ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error,
-) error {
- if len(hs.hooks) == 0 {
- err := hs.withContext(ctx, func() error {
- return fn(ctx, cmds)
- })
- return err
- }
-
- var hookIndex int
- var retErr error
-
- for ; hookIndex < len(hs.hooks) && retErr == nil; hookIndex++ {
- ctx, retErr = hs.hooks[hookIndex].BeforeProcessPipeline(ctx, cmds)
- if retErr != nil {
- setCmdsErr(cmds, retErr)
- }
- }
-
- if retErr == nil {
- retErr = hs.withContext(ctx, func() error {
- return fn(ctx, cmds)
- })
- }
-
- for hookIndex--; hookIndex >= 0; hookIndex-- {
- if err := hs.hooks[hookIndex].AfterProcessPipeline(ctx, cmds); err != nil {
- retErr = err
- setCmdsErr(cmds, retErr)
- }
- }
-
- return retErr
-}
-
-func (hs hooks) processTxPipeline(
- ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error,
-) error {
- cmds = wrapMultiExec(ctx, cmds)
- return hs.processPipeline(ctx, cmds, fn)
-}
-
-func (hs hooks) withContext(ctx context.Context, fn func() error) error {
- done := ctx.Done()
- if done == nil {
- return fn()
- }
-
- errc := make(chan error, 1)
- go func() { errc <- fn() }()
-
- select {
- case <-done:
- return ctx.Err()
- case err := <-errc:
- return err
- }
-}
-
-//------------------------------------------------------------------------------
-
-type baseClient struct {
- opt *Options
- connPool pool.Pooler
-
- onClose func() error // hook called when client is closed
-}
-
-func newBaseClient(opt *Options, connPool pool.Pooler) *baseClient {
- return &baseClient{
- opt: opt,
- connPool: connPool,
- }
-}
-
-func (c *baseClient) clone() *baseClient {
- clone := *c
- return &clone
-}
-
-func (c *baseClient) withTimeout(timeout time.Duration) *baseClient {
- opt := c.opt.clone()
- opt.ReadTimeout = timeout
- opt.WriteTimeout = timeout
-
- clone := c.clone()
- clone.opt = opt
-
- return clone
-}
-
-func (c *baseClient) String() string {
- return fmt.Sprintf("Redis<%s db:%d>", c.getAddr(), c.opt.DB)
-}
-
-func (c *baseClient) newConn(ctx context.Context) (*pool.Conn, error) {
- cn, err := c.connPool.NewConn(ctx)
- if err != nil {
- return nil, err
- }
-
- err = c.initConn(ctx, cn)
- if err != nil {
- _ = c.connPool.CloseConn(cn)
- return nil, err
- }
-
- return cn, nil
-}
-
-func (c *baseClient) getConn(ctx context.Context) (*pool.Conn, error) {
- if c.opt.Limiter != nil {
- err := c.opt.Limiter.Allow()
- if err != nil {
- return nil, err
- }
- }
-
- cn, err := c._getConn(ctx)
- if err != nil {
- if c.opt.Limiter != nil {
- c.opt.Limiter.ReportResult(err)
- }
- return nil, err
- }
-
- return cn, nil
-}
-
-func (c *baseClient) _getConn(ctx context.Context) (*pool.Conn, error) {
- cn, err := c.connPool.Get(ctx)
- if err != nil {
- return nil, err
- }
-
- if cn.Inited {
- return cn, nil
- }
-
- err = internal.WithSpan(ctx, "init_conn", func(ctx context.Context, span trace.Span) error {
- return c.initConn(ctx, cn)
- })
- if err != nil {
- c.connPool.Remove(ctx, cn, err)
- if err := internal.Unwrap(err); err != nil {
- return nil, err
- }
- return nil, err
- }
-
- return cn, nil
-}
-
-func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error {
- if cn.Inited {
- return nil
- }
- cn.Inited = true
-
- if c.opt.Password == "" &&
- c.opt.DB == 0 &&
- !c.opt.readOnly &&
- c.opt.OnConnect == nil {
- return nil
- }
-
- connPool := pool.NewSingleConnPool(c.connPool, cn)
- conn := newConn(ctx, c.opt, connPool)
-
- _, err := conn.Pipelined(ctx, func(pipe Pipeliner) error {
- if c.opt.Password != "" {
- if c.opt.Username != "" {
- pipe.AuthACL(ctx, c.opt.Username, c.opt.Password)
- } else {
- pipe.Auth(ctx, c.opt.Password)
- }
- }
-
- if c.opt.DB > 0 {
- pipe.Select(ctx, c.opt.DB)
- }
-
- if c.opt.readOnly {
- pipe.ReadOnly(ctx)
- }
-
- return nil
- })
- if err != nil {
- return err
- }
-
- if c.opt.OnConnect != nil {
- return c.opt.OnConnect(ctx, conn)
- }
- return nil
-}
-
-func (c *baseClient) releaseConn(ctx context.Context, cn *pool.Conn, err error) {
- if c.opt.Limiter != nil {
- c.opt.Limiter.ReportResult(err)
- }
-
- if isBadConn(err, false) {
- c.connPool.Remove(ctx, cn, err)
- } else {
- c.connPool.Put(ctx, cn)
- }
-}
-
-func (c *baseClient) withConn(
- ctx context.Context, fn func(context.Context, *pool.Conn) error,
-) error {
- return internal.WithSpan(ctx, "with_conn", func(ctx context.Context, span trace.Span) error {
- cn, err := c.getConn(ctx)
- if err != nil {
- return err
- }
-
- if span.IsRecording() {
- if remoteAddr := cn.RemoteAddr(); remoteAddr != nil {
- span.SetAttributes(label.String("net.peer.ip", remoteAddr.String()))
- }
- }
-
- defer func() {
- c.releaseConn(ctx, cn, err)
- }()
-
- err = fn(ctx, cn)
- return err
- })
-}
-
-func (c *baseClient) process(ctx context.Context, cmd Cmder) error {
- var lastErr error
- for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
- attempt := attempt
-
- var retry bool
- err := internal.WithSpan(ctx, "process", func(ctx context.Context, span trace.Span) error {
- if attempt > 0 {
- if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
- return err
- }
- }
-
- retryTimeout := true
- err := c.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error {
- err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
- return writeCmd(wr, cmd)
- })
- if err != nil {
- return err
- }
-
- err = cn.WithReader(ctx, c.cmdTimeout(cmd), cmd.readReply)
- if err != nil {
- retryTimeout = cmd.readTimeout() == nil
- return err
- }
-
- return nil
- })
- if err == nil {
- return nil
- }
- retry = shouldRetry(err, retryTimeout)
- return err
- })
- if err == nil || !retry {
- return err
- }
- lastErr = err
- }
- return lastErr
-}
-
-func (c *baseClient) retryBackoff(attempt int) time.Duration {
- return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff)
-}
-
-func (c *baseClient) cmdTimeout(cmd Cmder) time.Duration {
- if timeout := cmd.readTimeout(); timeout != nil {
- t := *timeout
- if t == 0 {
- return 0
- }
- return t + 10*time.Second
- }
- return c.opt.ReadTimeout
-}
-
-// Close closes the client, releasing any open resources.
-//
-// It is rare to Close a Client, as the Client is meant to be
-// long-lived and shared between many goroutines.
-func (c *baseClient) Close() error {
- var firstErr error
- if c.onClose != nil {
- if err := c.onClose(); err != nil {
- firstErr = err
- }
- }
- if err := c.connPool.Close(); err != nil && firstErr == nil {
- firstErr = err
- }
- return firstErr
-}
-
-func (c *baseClient) getAddr() string {
- return c.opt.Addr
-}
-
-func (c *baseClient) processPipeline(ctx context.Context, cmds []Cmder) error {
- return c.generalProcessPipeline(ctx, cmds, c.pipelineProcessCmds)
-}
-
-func (c *baseClient) processTxPipeline(ctx context.Context, cmds []Cmder) error {
- return c.generalProcessPipeline(ctx, cmds, c.txPipelineProcessCmds)
-}
-
-type pipelineProcessor func(context.Context, *pool.Conn, []Cmder) (bool, error)
-
-func (c *baseClient) generalProcessPipeline(
- ctx context.Context, cmds []Cmder, p pipelineProcessor,
-) error {
- err := c._generalProcessPipeline(ctx, cmds, p)
- if err != nil {
- setCmdsErr(cmds, err)
- return err
- }
- return cmdsFirstErr(cmds)
-}
-
-func (c *baseClient) _generalProcessPipeline(
- ctx context.Context, cmds []Cmder, p pipelineProcessor,
-) error {
- var lastErr error
- for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
- if attempt > 0 {
- if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
- return err
- }
- }
-
- var canRetry bool
- lastErr = c.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error {
- var err error
- canRetry, err = p(ctx, cn, cmds)
- return err
- })
- if lastErr == nil || !canRetry || !shouldRetry(lastErr, true) {
- return lastErr
- }
- }
- return lastErr
-}
-
-func (c *baseClient) pipelineProcessCmds(
- ctx context.Context, cn *pool.Conn, cmds []Cmder,
-) (bool, error) {
- err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
- return writeCmds(wr, cmds)
- })
- if err != nil {
- return true, err
- }
-
- err = cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error {
- return pipelineReadCmds(rd, cmds)
- })
- return true, err
-}
-
-func pipelineReadCmds(rd *proto.Reader, cmds []Cmder) error {
- for _, cmd := range cmds {
- err := cmd.readReply(rd)
- cmd.SetErr(err)
- if err != nil && !isRedisError(err) {
- return err
- }
- }
- return nil
-}
-
-func (c *baseClient) txPipelineProcessCmds(
- ctx context.Context, cn *pool.Conn, cmds []Cmder,
-) (bool, error) {
- err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error {
- return writeCmds(wr, cmds)
- })
- if err != nil {
- return true, err
- }
-
- err = cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error {
- statusCmd := cmds[0].(*StatusCmd)
- // Trim multi and exec.
- cmds = cmds[1 : len(cmds)-1]
-
- err := txPipelineReadQueued(rd, statusCmd, cmds)
- if err != nil {
- return err
- }
-
- return pipelineReadCmds(rd, cmds)
- })
- return false, err
-}
-
-func wrapMultiExec(ctx context.Context, cmds []Cmder) []Cmder {
- if len(cmds) == 0 {
- panic("not reached")
- }
- cmdCopy := make([]Cmder, len(cmds)+2)
- cmdCopy[0] = NewStatusCmd(ctx, "multi")
- copy(cmdCopy[1:], cmds)
- cmdCopy[len(cmdCopy)-1] = NewSliceCmd(ctx, "exec")
- return cmdCopy
-}
-
-func txPipelineReadQueued(rd *proto.Reader, statusCmd *StatusCmd, cmds []Cmder) error {
- // Parse queued replies.
- if err := statusCmd.readReply(rd); err != nil {
- return err
- }
-
- for range cmds {
- if err := statusCmd.readReply(rd); err != nil && !isRedisError(err) {
- return err
- }
- }
-
- // Parse number of replies.
- line, err := rd.ReadLine()
- if err != nil {
- if err == Nil {
- err = TxFailedErr
- }
- return err
- }
-
- switch line[0] {
- case proto.ErrorReply:
- return proto.ParseErrorReply(line)
- case proto.ArrayReply:
- // ok
- default:
- err := fmt.Errorf("redis: expected '*', but got line %q", line)
- return err
- }
-
- return nil
-}
-
-//------------------------------------------------------------------------------
-
-// Client is a Redis client representing a pool of zero or more
-// underlying connections. It's safe for concurrent use by multiple
-// goroutines.
-type Client struct {
- *baseClient
- cmdable
- hooks
- ctx context.Context
-}
-
-// NewClient returns a client to the Redis Server specified by Options.
-func NewClient(opt *Options) *Client {
- opt.init()
-
- c := Client{
- baseClient: newBaseClient(opt, newConnPool(opt)),
- ctx: context.Background(),
- }
- c.cmdable = c.Process
-
- return &c
-}
-
-func (c *Client) clone() *Client {
- clone := *c
- clone.cmdable = clone.Process
- clone.hooks.lock()
- return &clone
-}
-
-func (c *Client) WithTimeout(timeout time.Duration) *Client {
- clone := c.clone()
- clone.baseClient = c.baseClient.withTimeout(timeout)
- return clone
-}
-
-func (c *Client) Context() context.Context {
- return c.ctx
-}
-
-func (c *Client) WithContext(ctx context.Context) *Client {
- if ctx == nil {
- panic("nil context")
- }
- clone := c.clone()
- clone.ctx = ctx
- return clone
-}
-
-func (c *Client) Conn(ctx context.Context) *Conn {
- return newConn(ctx, c.opt, pool.NewStickyConnPool(c.connPool))
-}
-
-// Do creates a Cmd from the args and processes the cmd.
-func (c *Client) Do(ctx context.Context, args ...interface{}) *Cmd {
- cmd := NewCmd(ctx, args...)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-func (c *Client) Process(ctx context.Context, cmd Cmder) error {
- return c.hooks.process(ctx, cmd, c.baseClient.process)
-}
-
-func (c *Client) processPipeline(ctx context.Context, cmds []Cmder) error {
- return c.hooks.processPipeline(ctx, cmds, c.baseClient.processPipeline)
-}
-
-func (c *Client) processTxPipeline(ctx context.Context, cmds []Cmder) error {
- return c.hooks.processTxPipeline(ctx, cmds, c.baseClient.processTxPipeline)
-}
-
-// Options returns read-only Options that were used to create the client.
-func (c *Client) Options() *Options {
- return c.opt
-}
-
-type PoolStats pool.Stats
-
-// PoolStats returns connection pool stats.
-func (c *Client) PoolStats() *PoolStats {
- stats := c.connPool.Stats()
- return (*PoolStats)(stats)
-}
-
-func (c *Client) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.Pipeline().Pipelined(ctx, fn)
-}
-
-func (c *Client) Pipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: c.processPipeline,
- }
- pipe.init()
- return &pipe
-}
-
-func (c *Client) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.TxPipeline().Pipelined(ctx, fn)
-}
-
-// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
-func (c *Client) TxPipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: c.processTxPipeline,
- }
- pipe.init()
- return &pipe
-}
-
-func (c *Client) pubSub() *PubSub {
- pubsub := &PubSub{
- opt: c.opt,
-
- newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) {
- return c.newConn(ctx)
- },
- closeConn: c.connPool.CloseConn,
- }
- pubsub.init()
- return pubsub
-}
-
-// Subscribe subscribes the client to the specified channels.
-// Channels can be omitted to create empty subscription.
-// Note that this method does not wait on a response from Redis, so the
-// subscription may not be active immediately. To force the connection to wait,
-// you may call the Receive() method on the returned *PubSub like so:
-//
-// sub := client.Subscribe(queryResp)
-// iface, err := sub.Receive()
-// if err != nil {
-// // handle error
-// }
-//
-// // Should be *Subscription, but others are possible if other actions have been
-// // taken on sub since it was created.
-// switch iface.(type) {
-// case *Subscription:
-// // subscribe succeeded
-// case *Message:
-// // received first message
-// case *Pong:
-// // pong received
-// default:
-// // handle error
-// }
-//
-// ch := sub.Channel()
-func (c *Client) Subscribe(ctx context.Context, channels ...string) *PubSub {
- pubsub := c.pubSub()
- if len(channels) > 0 {
- _ = pubsub.Subscribe(ctx, channels...)
- }
- return pubsub
-}
-
-// PSubscribe subscribes the client to the given patterns.
-// Patterns can be omitted to create empty subscription.
-func (c *Client) PSubscribe(ctx context.Context, channels ...string) *PubSub {
- pubsub := c.pubSub()
- if len(channels) > 0 {
- _ = pubsub.PSubscribe(ctx, channels...)
- }
- return pubsub
-}
-
-//------------------------------------------------------------------------------
-
-type conn struct {
- baseClient
- cmdable
- statefulCmdable
-}
-
-// Conn is like Client, but its pool contains single connection.
-type Conn struct {
- *conn
- ctx context.Context
-}
-
-func newConn(ctx context.Context, opt *Options, connPool pool.Pooler) *Conn {
- c := Conn{
- conn: &conn{
- baseClient: baseClient{
- opt: opt,
- connPool: connPool,
- },
- },
- ctx: ctx,
- }
- c.cmdable = c.Process
- c.statefulCmdable = c.Process
- return &c
-}
-
-func (c *Conn) Process(ctx context.Context, cmd Cmder) error {
- return c.baseClient.process(ctx, cmd)
-}
-
-func (c *Conn) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.Pipeline().Pipelined(ctx, fn)
-}
-
-func (c *Conn) Pipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: c.processPipeline,
- }
- pipe.init()
- return &pipe
-}
-
-func (c *Conn) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.TxPipeline().Pipelined(ctx, fn)
-}
-
-// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
-func (c *Conn) TxPipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: c.processTxPipeline,
- }
- pipe.init()
- return &pipe
-}
diff --git a/vendor/github.com/go-redis/redis/v8/renovate.json b/vendor/github.com/go-redis/redis/v8/renovate.json
deleted file mode 100644
index f45d8f110c3..00000000000
--- a/vendor/github.com/go-redis/redis/v8/renovate.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "extends": [
- "config:base"
- ]
-}
diff --git a/vendor/github.com/go-redis/redis/v8/result.go b/vendor/github.com/go-redis/redis/v8/result.go
deleted file mode 100644
index 24cfd499402..00000000000
--- a/vendor/github.com/go-redis/redis/v8/result.go
+++ /dev/null
@@ -1,180 +0,0 @@
-package redis
-
-import "time"
-
-// NewCmdResult returns a Cmd initialised with val and err for testing.
-func NewCmdResult(val interface{}, err error) *Cmd {
- var cmd Cmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewSliceResult returns a SliceCmd initialised with val and err for testing.
-func NewSliceResult(val []interface{}, err error) *SliceCmd {
- var cmd SliceCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewStatusResult returns a StatusCmd initialised with val and err for testing.
-func NewStatusResult(val string, err error) *StatusCmd {
- var cmd StatusCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewIntResult returns an IntCmd initialised with val and err for testing.
-func NewIntResult(val int64, err error) *IntCmd {
- var cmd IntCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewDurationResult returns a DurationCmd initialised with val and err for testing.
-func NewDurationResult(val time.Duration, err error) *DurationCmd {
- var cmd DurationCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewBoolResult returns a BoolCmd initialised with val and err for testing.
-func NewBoolResult(val bool, err error) *BoolCmd {
- var cmd BoolCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewStringResult returns a StringCmd initialised with val and err for testing.
-func NewStringResult(val string, err error) *StringCmd {
- var cmd StringCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewFloatResult returns a FloatCmd initialised with val and err for testing.
-func NewFloatResult(val float64, err error) *FloatCmd {
- var cmd FloatCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewStringSliceResult returns a StringSliceCmd initialised with val and err for testing.
-func NewStringSliceResult(val []string, err error) *StringSliceCmd {
- var cmd StringSliceCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewBoolSliceResult returns a BoolSliceCmd initialised with val and err for testing.
-func NewBoolSliceResult(val []bool, err error) *BoolSliceCmd {
- var cmd BoolSliceCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewStringStringMapResult returns a StringStringMapCmd initialised with val and err for testing.
-func NewStringStringMapResult(val map[string]string, err error) *StringStringMapCmd {
- var cmd StringStringMapCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewStringIntMapCmdResult returns a StringIntMapCmd initialised with val and err for testing.
-func NewStringIntMapCmdResult(val map[string]int64, err error) *StringIntMapCmd {
- var cmd StringIntMapCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewTimeCmdResult returns a TimeCmd initialised with val and err for testing.
-func NewTimeCmdResult(val time.Time, err error) *TimeCmd {
- var cmd TimeCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewZSliceCmdResult returns a ZSliceCmd initialised with val and err for testing.
-func NewZSliceCmdResult(val []Z, err error) *ZSliceCmd {
- var cmd ZSliceCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewZWithKeyCmdResult returns a NewZWithKeyCmd initialised with val and err for testing.
-func NewZWithKeyCmdResult(val *ZWithKey, err error) *ZWithKeyCmd {
- var cmd ZWithKeyCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewScanCmdResult returns a ScanCmd initialised with val and err for testing.
-func NewScanCmdResult(keys []string, cursor uint64, err error) *ScanCmd {
- var cmd ScanCmd
- cmd.page = keys
- cmd.cursor = cursor
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewClusterSlotsCmdResult returns a ClusterSlotsCmd initialised with val and err for testing.
-func NewClusterSlotsCmdResult(val []ClusterSlot, err error) *ClusterSlotsCmd {
- var cmd ClusterSlotsCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewGeoLocationCmdResult returns a GeoLocationCmd initialised with val and err for testing.
-func NewGeoLocationCmdResult(val []GeoLocation, err error) *GeoLocationCmd {
- var cmd GeoLocationCmd
- cmd.locations = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewGeoPosCmdResult returns a GeoPosCmd initialised with val and err for testing.
-func NewGeoPosCmdResult(val []*GeoPos, err error) *GeoPosCmd {
- var cmd GeoPosCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewCommandsInfoCmdResult returns a CommandsInfoCmd initialised with val and err for testing.
-func NewCommandsInfoCmdResult(val map[string]*CommandInfo, err error) *CommandsInfoCmd {
- var cmd CommandsInfoCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewXMessageSliceCmdResult returns a XMessageSliceCmd initialised with val and err for testing.
-func NewXMessageSliceCmdResult(val []XMessage, err error) *XMessageSliceCmd {
- var cmd XMessageSliceCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
-
-// NewXStreamSliceCmdResult returns a XStreamSliceCmd initialised with val and err for testing.
-func NewXStreamSliceCmdResult(val []XStream, err error) *XStreamSliceCmd {
- var cmd XStreamSliceCmd
- cmd.val = val
- cmd.SetErr(err)
- return &cmd
-}
diff --git a/vendor/github.com/go-redis/redis/v8/ring.go b/vendor/github.com/go-redis/redis/v8/ring.go
deleted file mode 100644
index 205b0249d78..00000000000
--- a/vendor/github.com/go-redis/redis/v8/ring.go
+++ /dev/null
@@ -1,732 +0,0 @@
-package redis
-
-import (
- "context"
- "crypto/tls"
- "errors"
- "fmt"
- "net"
- "strconv"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/cespare/xxhash/v2"
- "github.com/dgryski/go-rendezvous"
-
- "github.com/go-redis/redis/v8/internal"
- "github.com/go-redis/redis/v8/internal/hashtag"
- "github.com/go-redis/redis/v8/internal/pool"
- "github.com/go-redis/redis/v8/internal/rand"
-)
-
-var errRingShardsDown = errors.New("redis: all ring shards are down")
-
-//------------------------------------------------------------------------------
-
-type ConsistentHash interface {
- Get(string) string
-}
-
-type rendezvousWrapper struct {
- *rendezvous.Rendezvous
-}
-
-func (w rendezvousWrapper) Get(key string) string {
- return w.Lookup(key)
-}
-
-func newRendezvous(shards []string) ConsistentHash {
- return rendezvousWrapper{rendezvous.New(shards, xxhash.Sum64String)}
-}
-
-//------------------------------------------------------------------------------
-
-// RingOptions are used to configure a ring client and should be
-// passed to NewRing.
-type RingOptions struct {
- // Map of name => host:port addresses of ring shards.
- Addrs map[string]string
-
- // NewClient creates a shard client with provided name and options.
- NewClient func(name string, opt *Options) *Client
-
- // Frequency of PING commands sent to check shards availability.
- // Shard is considered down after 3 subsequent failed checks.
- HeartbeatFrequency time.Duration
-
- // NewConsistentHash returns a consistent hash that is used
- // to distribute keys across the shards.
- //
- // See https://medium.com/@dgryski/consistent-hashing-algorithmic-tradeoffs-ef6b8e2fcae8
- // for consistent hashing algorithmic tradeoffs.
- NewConsistentHash func(shards []string) ConsistentHash
-
- // Following options are copied from Options struct.
-
- Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
- OnConnect func(ctx context.Context, cn *Conn) error
-
- Username string
- Password string
- DB int
-
- MaxRetries int
- MinRetryBackoff time.Duration
- MaxRetryBackoff time.Duration
-
- DialTimeout time.Duration
- ReadTimeout time.Duration
- WriteTimeout time.Duration
-
- PoolSize int
- MinIdleConns int
- MaxConnAge time.Duration
- PoolTimeout time.Duration
- IdleTimeout time.Duration
- IdleCheckFrequency time.Duration
-
- TLSConfig *tls.Config
- Limiter Limiter
-}
-
-func (opt *RingOptions) init() {
- if opt.NewClient == nil {
- opt.NewClient = func(name string, opt *Options) *Client {
- return NewClient(opt)
- }
- }
-
- if opt.HeartbeatFrequency == 0 {
- opt.HeartbeatFrequency = 500 * time.Millisecond
- }
-
- if opt.NewConsistentHash == nil {
- opt.NewConsistentHash = newRendezvous
- }
-
- if opt.MaxRetries == -1 {
- opt.MaxRetries = 0
- } else if opt.MaxRetries == 0 {
- opt.MaxRetries = 3
- }
- switch opt.MinRetryBackoff {
- case -1:
- opt.MinRetryBackoff = 0
- case 0:
- opt.MinRetryBackoff = 8 * time.Millisecond
- }
- switch opt.MaxRetryBackoff {
- case -1:
- opt.MaxRetryBackoff = 0
- case 0:
- opt.MaxRetryBackoff = 512 * time.Millisecond
- }
-}
-
-func (opt *RingOptions) clientOptions() *Options {
- return &Options{
- Dialer: opt.Dialer,
- OnConnect: opt.OnConnect,
-
- Username: opt.Username,
- Password: opt.Password,
- DB: opt.DB,
-
- MaxRetries: -1,
-
- DialTimeout: opt.DialTimeout,
- ReadTimeout: opt.ReadTimeout,
- WriteTimeout: opt.WriteTimeout,
-
- PoolSize: opt.PoolSize,
- MinIdleConns: opt.MinIdleConns,
- MaxConnAge: opt.MaxConnAge,
- PoolTimeout: opt.PoolTimeout,
- IdleTimeout: opt.IdleTimeout,
- IdleCheckFrequency: opt.IdleCheckFrequency,
-
- TLSConfig: opt.TLSConfig,
- Limiter: opt.Limiter,
- }
-}
-
-//------------------------------------------------------------------------------
-
-type ringShard struct {
- Client *Client
- down int32
-}
-
-func newRingShard(opt *RingOptions, name, addr string) *ringShard {
- clopt := opt.clientOptions()
- clopt.Addr = addr
-
- return &ringShard{
- Client: opt.NewClient(name, clopt),
- }
-}
-
-func (shard *ringShard) String() string {
- var state string
- if shard.IsUp() {
- state = "up"
- } else {
- state = "down"
- }
- return fmt.Sprintf("%s is %s", shard.Client, state)
-}
-
-func (shard *ringShard) IsDown() bool {
- const threshold = 3
- return atomic.LoadInt32(&shard.down) >= threshold
-}
-
-func (shard *ringShard) IsUp() bool {
- return !shard.IsDown()
-}
-
-// Vote votes to set shard state and returns true if state was changed.
-func (shard *ringShard) Vote(up bool) bool {
- if up {
- changed := shard.IsDown()
- atomic.StoreInt32(&shard.down, 0)
- return changed
- }
-
- if shard.IsDown() {
- return false
- }
-
- atomic.AddInt32(&shard.down, 1)
- return shard.IsDown()
-}
-
-//------------------------------------------------------------------------------
-
-type ringShards struct {
- opt *RingOptions
-
- mu sync.RWMutex
- hash ConsistentHash
- shards map[string]*ringShard // read only
- list []*ringShard // read only
- numShard int
- closed bool
-}
-
-func newRingShards(opt *RingOptions) *ringShards {
- shards := make(map[string]*ringShard, len(opt.Addrs))
- list := make([]*ringShard, 0, len(shards))
-
- for name, addr := range opt.Addrs {
- shard := newRingShard(opt, name, addr)
- shards[name] = shard
-
- list = append(list, shard)
- }
-
- c := &ringShards{
- opt: opt,
-
- shards: shards,
- list: list,
- }
- c.rebalance()
-
- return c
-}
-
-func (c *ringShards) List() []*ringShard {
- var list []*ringShard
-
- c.mu.RLock()
- if !c.closed {
- list = c.list
- }
- c.mu.RUnlock()
-
- return list
-}
-
-func (c *ringShards) Hash(key string) string {
- key = hashtag.Key(key)
-
- var hash string
-
- c.mu.RLock()
- if c.numShard > 0 {
- hash = c.hash.Get(key)
- }
- c.mu.RUnlock()
-
- return hash
-}
-
-func (c *ringShards) GetByKey(key string) (*ringShard, error) {
- key = hashtag.Key(key)
-
- c.mu.RLock()
-
- if c.closed {
- c.mu.RUnlock()
- return nil, pool.ErrClosed
- }
-
- if c.numShard == 0 {
- c.mu.RUnlock()
- return nil, errRingShardsDown
- }
-
- hash := c.hash.Get(key)
- if hash == "" {
- c.mu.RUnlock()
- return nil, errRingShardsDown
- }
-
- shard := c.shards[hash]
- c.mu.RUnlock()
-
- return shard, nil
-}
-
-func (c *ringShards) GetByName(shardName string) (*ringShard, error) {
- if shardName == "" {
- return c.Random()
- }
-
- c.mu.RLock()
- shard := c.shards[shardName]
- c.mu.RUnlock()
- return shard, nil
-}
-
-func (c *ringShards) Random() (*ringShard, error) {
- return c.GetByKey(strconv.Itoa(rand.Int()))
-}
-
-// heartbeat monitors state of each shard in the ring.
-func (c *ringShards) Heartbeat(frequency time.Duration) {
- ticker := time.NewTicker(frequency)
- defer ticker.Stop()
-
- ctx := context.Background()
- for range ticker.C {
- var rebalance bool
-
- for _, shard := range c.List() {
- err := shard.Client.Ping(ctx).Err()
- isUp := err == nil || err == pool.ErrPoolTimeout
- if shard.Vote(isUp) {
- internal.Logger.Printf(context.Background(), "ring shard state changed: %s", shard)
- rebalance = true
- }
- }
-
- if rebalance {
- c.rebalance()
- }
- }
-}
-
-// rebalance removes dead shards from the Ring.
-func (c *ringShards) rebalance() {
- c.mu.RLock()
- shards := c.shards
- c.mu.RUnlock()
-
- liveShards := make([]string, 0, len(shards))
-
- for name, shard := range shards {
- if shard.IsUp() {
- liveShards = append(liveShards, name)
- }
- }
-
- hash := c.opt.NewConsistentHash(liveShards)
-
- c.mu.Lock()
- c.hash = hash
- c.numShard = len(liveShards)
- c.mu.Unlock()
-}
-
-func (c *ringShards) Len() int {
- c.mu.RLock()
- l := c.numShard
- c.mu.RUnlock()
- return l
-}
-
-func (c *ringShards) Close() error {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if c.closed {
- return nil
- }
- c.closed = true
-
- var firstErr error
- for _, shard := range c.shards {
- if err := shard.Client.Close(); err != nil && firstErr == nil {
- firstErr = err
- }
- }
- c.hash = nil
- c.shards = nil
- c.list = nil
-
- return firstErr
-}
-
-//------------------------------------------------------------------------------
-
-type ring struct {
- opt *RingOptions
- shards *ringShards
- cmdsInfoCache *cmdsInfoCache //nolint:structcheck
-}
-
-// Ring is a Redis client that uses consistent hashing to distribute
-// keys across multiple Redis servers (shards). It's safe for
-// concurrent use by multiple goroutines.
-//
-// Ring monitors the state of each shard and removes dead shards from
-// the ring. When a shard comes online it is added back to the ring. This
-// gives you maximum availability and partition tolerance, but no
-// consistency between different shards or even clients. Each client
-// uses shards that are available to the client and does not do any
-// coordination when shard state is changed.
-//
-// Ring should be used when you need multiple Redis servers for caching
-// and can tolerate losing data when one of the servers dies.
-// Otherwise you should use Redis Cluster.
-type Ring struct {
- *ring
- cmdable
- hooks
- ctx context.Context
-}
-
-func NewRing(opt *RingOptions) *Ring {
- opt.init()
-
- ring := Ring{
- ring: &ring{
- opt: opt,
- shards: newRingShards(opt),
- },
- ctx: context.Background(),
- }
-
- ring.cmdsInfoCache = newCmdsInfoCache(ring.cmdsInfo)
- ring.cmdable = ring.Process
-
- go ring.shards.Heartbeat(opt.HeartbeatFrequency)
-
- return &ring
-}
-
-func (c *Ring) Context() context.Context {
- return c.ctx
-}
-
-func (c *Ring) WithContext(ctx context.Context) *Ring {
- if ctx == nil {
- panic("nil context")
- }
- clone := *c
- clone.cmdable = clone.Process
- clone.hooks.lock()
- clone.ctx = ctx
- return &clone
-}
-
-// Do creates a Cmd from the args and processes the cmd.
-func (c *Ring) Do(ctx context.Context, args ...interface{}) *Cmd {
- cmd := NewCmd(ctx, args...)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-func (c *Ring) Process(ctx context.Context, cmd Cmder) error {
- return c.hooks.process(ctx, cmd, c.process)
-}
-
-// Options returns read-only Options that were used to create the client.
-func (c *Ring) Options() *RingOptions {
- return c.opt
-}
-
-func (c *Ring) retryBackoff(attempt int) time.Duration {
- return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff)
-}
-
-// PoolStats returns accumulated connection pool stats.
-func (c *Ring) PoolStats() *PoolStats {
- shards := c.shards.List()
- var acc PoolStats
- for _, shard := range shards {
- s := shard.Client.connPool.Stats()
- acc.Hits += s.Hits
- acc.Misses += s.Misses
- acc.Timeouts += s.Timeouts
- acc.TotalConns += s.TotalConns
- acc.IdleConns += s.IdleConns
- }
- return &acc
-}
-
-// Len returns the current number of shards in the ring.
-func (c *Ring) Len() int {
- return c.shards.Len()
-}
-
-// Subscribe subscribes the client to the specified channels.
-func (c *Ring) Subscribe(ctx context.Context, channels ...string) *PubSub {
- if len(channels) == 0 {
- panic("at least one channel is required")
- }
-
- shard, err := c.shards.GetByKey(channels[0])
- if err != nil {
- // TODO: return PubSub with sticky error
- panic(err)
- }
- return shard.Client.Subscribe(ctx, channels...)
-}
-
-// PSubscribe subscribes the client to the given patterns.
-func (c *Ring) PSubscribe(ctx context.Context, channels ...string) *PubSub {
- if len(channels) == 0 {
- panic("at least one channel is required")
- }
-
- shard, err := c.shards.GetByKey(channels[0])
- if err != nil {
- // TODO: return PubSub with sticky error
- panic(err)
- }
- return shard.Client.PSubscribe(ctx, channels...)
-}
-
-// ForEachShard concurrently calls the fn on each live shard in the ring.
-// It returns the first error if any.
-func (c *Ring) ForEachShard(
- ctx context.Context,
- fn func(ctx context.Context, client *Client) error,
-) error {
- shards := c.shards.List()
- var wg sync.WaitGroup
- errCh := make(chan error, 1)
- for _, shard := range shards {
- if shard.IsDown() {
- continue
- }
-
- wg.Add(1)
- go func(shard *ringShard) {
- defer wg.Done()
- err := fn(ctx, shard.Client)
- if err != nil {
- select {
- case errCh <- err:
- default:
- }
- }
- }(shard)
- }
- wg.Wait()
-
- select {
- case err := <-errCh:
- return err
- default:
- return nil
- }
-}
-
-func (c *Ring) cmdsInfo(ctx context.Context) (map[string]*CommandInfo, error) {
- shards := c.shards.List()
- var firstErr error
- for _, shard := range shards {
- cmdsInfo, err := shard.Client.Command(ctx).Result()
- if err == nil {
- return cmdsInfo, nil
- }
- if firstErr == nil {
- firstErr = err
- }
- }
- if firstErr == nil {
- return nil, errRingShardsDown
- }
- return nil, firstErr
-}
-
-func (c *Ring) cmdInfo(ctx context.Context, name string) *CommandInfo {
- cmdsInfo, err := c.cmdsInfoCache.Get(ctx)
- if err != nil {
- return nil
- }
- info := cmdsInfo[name]
- if info == nil {
- internal.Logger.Printf(c.Context(), "info for cmd=%s not found", name)
- }
- return info
-}
-
-func (c *Ring) cmdShard(ctx context.Context, cmd Cmder) (*ringShard, error) {
- cmdInfo := c.cmdInfo(ctx, cmd.Name())
- pos := cmdFirstKeyPos(cmd, cmdInfo)
- if pos == 0 {
- return c.shards.Random()
- }
- firstKey := cmd.stringArg(pos)
- return c.shards.GetByKey(firstKey)
-}
-
-func (c *Ring) process(ctx context.Context, cmd Cmder) error {
- var lastErr error
- for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
- if attempt > 0 {
- if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil {
- return err
- }
- }
-
- shard, err := c.cmdShard(ctx, cmd)
- if err != nil {
- return err
- }
-
- lastErr = shard.Client.Process(ctx, cmd)
- if lastErr == nil || !shouldRetry(lastErr, cmd.readTimeout() == nil) {
- return lastErr
- }
- }
- return lastErr
-}
-
-func (c *Ring) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.Pipeline().Pipelined(ctx, fn)
-}
-
-func (c *Ring) Pipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: c.processPipeline,
- }
- pipe.init()
- return &pipe
-}
-
-func (c *Ring) processPipeline(ctx context.Context, cmds []Cmder) error {
- return c.hooks.processPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error {
- return c.generalProcessPipeline(ctx, cmds, false)
- })
-}
-
-func (c *Ring) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.TxPipeline().Pipelined(ctx, fn)
-}
-
-func (c *Ring) TxPipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: c.processTxPipeline,
- }
- pipe.init()
- return &pipe
-}
-
-func (c *Ring) processTxPipeline(ctx context.Context, cmds []Cmder) error {
- return c.hooks.processPipeline(ctx, cmds, func(ctx context.Context, cmds []Cmder) error {
- return c.generalProcessPipeline(ctx, cmds, true)
- })
-}
-
-func (c *Ring) generalProcessPipeline(
- ctx context.Context, cmds []Cmder, tx bool,
-) error {
- cmdsMap := make(map[string][]Cmder)
- for _, cmd := range cmds {
- cmdInfo := c.cmdInfo(ctx, cmd.Name())
- hash := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo))
- if hash != "" {
- hash = c.shards.Hash(hash)
- }
- cmdsMap[hash] = append(cmdsMap[hash], cmd)
- }
-
- var wg sync.WaitGroup
- for hash, cmds := range cmdsMap {
- wg.Add(1)
- go func(hash string, cmds []Cmder) {
- defer wg.Done()
-
- _ = c.processShardPipeline(ctx, hash, cmds, tx)
- }(hash, cmds)
- }
-
- wg.Wait()
- return cmdsFirstErr(cmds)
-}
-
-func (c *Ring) processShardPipeline(
- ctx context.Context, hash string, cmds []Cmder, tx bool,
-) error {
- // TODO: retry?
- shard, err := c.shards.GetByName(hash)
- if err != nil {
- setCmdsErr(cmds, err)
- return err
- }
-
- if tx {
- return shard.Client.processTxPipeline(ctx, cmds)
- }
- return shard.Client.processPipeline(ctx, cmds)
-}
-
-func (c *Ring) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error {
- if len(keys) == 0 {
- return fmt.Errorf("redis: Watch requires at least one key")
- }
-
- var shards []*ringShard
- for _, key := range keys {
- if key != "" {
- shard, err := c.shards.GetByKey(hashtag.Key(key))
- if err != nil {
- return err
- }
-
- shards = append(shards, shard)
- }
- }
-
- if len(shards) == 0 {
- return fmt.Errorf("redis: Watch requires at least one shard")
- }
-
- if len(shards) > 1 {
- for _, shard := range shards[1:] {
- if shard.Client != shards[0].Client {
- err := fmt.Errorf("redis: Watch requires all keys to be in the same shard")
- return err
- }
- }
- }
-
- return shards[0].Client.Watch(ctx, fn, keys...)
-}
-
-// Close closes the ring client, releasing any open resources.
-//
-// It is rare to Close a Ring, as the Ring is meant to be long-lived
-// and shared between many goroutines.
-func (c *Ring) Close() error {
- return c.shards.Close()
-}
diff --git a/vendor/github.com/go-redis/redis/v8/script.go b/vendor/github.com/go-redis/redis/v8/script.go
deleted file mode 100644
index 07ed482c57c..00000000000
--- a/vendor/github.com/go-redis/redis/v8/script.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package redis
-
-import (
- "context"
- "crypto/sha1"
- "encoding/hex"
- "io"
- "strings"
-)
-
-type scripter interface {
- Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
- EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
- ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
- ScriptLoad(ctx context.Context, script string) *StringCmd
-}
-
-var (
- _ scripter = (*Client)(nil)
- _ scripter = (*Ring)(nil)
- _ scripter = (*ClusterClient)(nil)
-)
-
-type Script struct {
- src, hash string
-}
-
-func NewScript(src string) *Script {
- h := sha1.New()
- _, _ = io.WriteString(h, src)
- return &Script{
- src: src,
- hash: hex.EncodeToString(h.Sum(nil)),
- }
-}
-
-func (s *Script) Hash() string {
- return s.hash
-}
-
-func (s *Script) Load(ctx context.Context, c scripter) *StringCmd {
- return c.ScriptLoad(ctx, s.src)
-}
-
-func (s *Script) Exists(ctx context.Context, c scripter) *BoolSliceCmd {
- return c.ScriptExists(ctx, s.hash)
-}
-
-func (s *Script) Eval(ctx context.Context, c scripter, keys []string, args ...interface{}) *Cmd {
- return c.Eval(ctx, s.src, keys, args...)
-}
-
-func (s *Script) EvalSha(ctx context.Context, c scripter, keys []string, args ...interface{}) *Cmd {
- return c.EvalSha(ctx, s.hash, keys, args...)
-}
-
-// Run optimistically uses EVALSHA to run the script. If script does not exist
-// it is retried using EVAL.
-func (s *Script) Run(ctx context.Context, c scripter, keys []string, args ...interface{}) *Cmd {
- r := s.EvalSha(ctx, c, keys, args...)
- if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") {
- return s.Eval(ctx, c, keys, args...)
- }
- return r
-}
diff --git a/vendor/github.com/go-redis/redis/v8/sentinel.go b/vendor/github.com/go-redis/redis/v8/sentinel.go
deleted file mode 100644
index 7db984373f9..00000000000
--- a/vendor/github.com/go-redis/redis/v8/sentinel.go
+++ /dev/null
@@ -1,731 +0,0 @@
-package redis
-
-import (
- "context"
- "crypto/tls"
- "errors"
- "net"
- "strings"
- "sync"
- "time"
-
- "github.com/go-redis/redis/v8/internal"
- "github.com/go-redis/redis/v8/internal/pool"
- "github.com/go-redis/redis/v8/internal/rand"
-)
-
-//------------------------------------------------------------------------------
-
-// FailoverOptions are used to configure a failover client and should
-// be passed to NewFailoverClient.
-type FailoverOptions struct {
- // The master name.
- MasterName string
- // A seed list of host:port addresses of sentinel nodes.
- SentinelAddrs []string
- // Sentinel password from "requirepass " (if enabled) in Sentinel configuration
- SentinelPassword string
-
- // Allows routing read-only commands to the closest master or slave node.
- // This option only works with NewFailoverClusterClient.
- RouteByLatency bool
- // Allows routing read-only commands to the random master or slave node.
- // This option only works with NewFailoverClusterClient.
- RouteRandomly bool
-
- // Route all commands to slave read-only nodes.
- SlaveOnly bool
-
- // Following options are copied from Options struct.
-
- Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
- OnConnect func(ctx context.Context, cn *Conn) error
-
- Username string
- Password string
- DB int
-
- MaxRetries int
- MinRetryBackoff time.Duration
- MaxRetryBackoff time.Duration
-
- DialTimeout time.Duration
- ReadTimeout time.Duration
- WriteTimeout time.Duration
-
- PoolSize int
- MinIdleConns int
- MaxConnAge time.Duration
- PoolTimeout time.Duration
- IdleTimeout time.Duration
- IdleCheckFrequency time.Duration
-
- TLSConfig *tls.Config
-}
-
-func (opt *FailoverOptions) clientOptions() *Options {
- return &Options{
- Addr: "FailoverClient",
-
- Dialer: opt.Dialer,
- OnConnect: opt.OnConnect,
-
- DB: opt.DB,
- Username: opt.Username,
- Password: opt.Password,
-
- MaxRetries: opt.MaxRetries,
- MinRetryBackoff: opt.MinRetryBackoff,
- MaxRetryBackoff: opt.MaxRetryBackoff,
-
- DialTimeout: opt.DialTimeout,
- ReadTimeout: opt.ReadTimeout,
- WriteTimeout: opt.WriteTimeout,
-
- PoolSize: opt.PoolSize,
- PoolTimeout: opt.PoolTimeout,
- IdleTimeout: opt.IdleTimeout,
- IdleCheckFrequency: opt.IdleCheckFrequency,
- MinIdleConns: opt.MinIdleConns,
- MaxConnAge: opt.MaxConnAge,
-
- TLSConfig: opt.TLSConfig,
- }
-}
-
-func (opt *FailoverOptions) sentinelOptions(addr string) *Options {
- return &Options{
- Addr: addr,
-
- Dialer: opt.Dialer,
- OnConnect: opt.OnConnect,
-
- DB: 0,
- Password: opt.SentinelPassword,
-
- MaxRetries: opt.MaxRetries,
- MinRetryBackoff: opt.MinRetryBackoff,
- MaxRetryBackoff: opt.MaxRetryBackoff,
-
- DialTimeout: opt.DialTimeout,
- ReadTimeout: opt.ReadTimeout,
- WriteTimeout: opt.WriteTimeout,
-
- PoolSize: opt.PoolSize,
- PoolTimeout: opt.PoolTimeout,
- IdleTimeout: opt.IdleTimeout,
- IdleCheckFrequency: opt.IdleCheckFrequency,
- MinIdleConns: opt.MinIdleConns,
- MaxConnAge: opt.MaxConnAge,
-
- TLSConfig: opt.TLSConfig,
- }
-}
-
-func (opt *FailoverOptions) clusterOptions() *ClusterOptions {
- return &ClusterOptions{
- Dialer: opt.Dialer,
- OnConnect: opt.OnConnect,
-
- Username: opt.Username,
- Password: opt.Password,
-
- MaxRedirects: opt.MaxRetries,
-
- RouteByLatency: opt.RouteByLatency,
- RouteRandomly: opt.RouteRandomly,
-
- MinRetryBackoff: opt.MinRetryBackoff,
- MaxRetryBackoff: opt.MaxRetryBackoff,
-
- DialTimeout: opt.DialTimeout,
- ReadTimeout: opt.ReadTimeout,
- WriteTimeout: opt.WriteTimeout,
-
- PoolSize: opt.PoolSize,
- PoolTimeout: opt.PoolTimeout,
- IdleTimeout: opt.IdleTimeout,
- IdleCheckFrequency: opt.IdleCheckFrequency,
- MinIdleConns: opt.MinIdleConns,
- MaxConnAge: opt.MaxConnAge,
-
- TLSConfig: opt.TLSConfig,
- }
-}
-
-// NewFailoverClient returns a Redis client that uses Redis Sentinel
-// for automatic failover. It's safe for concurrent use by multiple
-// goroutines.
-func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
- if failoverOpt.RouteByLatency {
- panic("to route commands by latency, use NewFailoverClusterClient")
- }
- if failoverOpt.RouteRandomly {
- panic("to route commands randomly, use NewFailoverClusterClient")
- }
-
- sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs))
- copy(sentinelAddrs, failoverOpt.SentinelAddrs)
-
- failover := &sentinelFailover{
- opt: failoverOpt,
- sentinelAddrs: sentinelAddrs,
- }
-
- opt := failoverOpt.clientOptions()
- opt.Dialer = masterSlaveDialer(failover)
- opt.init()
-
- connPool := newConnPool(opt)
- failover.onFailover = func(ctx context.Context, addr string) {
- _ = connPool.Filter(func(cn *pool.Conn) bool {
- return cn.RemoteAddr().String() != addr
- })
- }
-
- c := Client{
- baseClient: newBaseClient(opt, connPool),
- ctx: context.Background(),
- }
- c.cmdable = c.Process
- c.onClose = failover.Close
-
- return &c
-}
-
-func masterSlaveDialer(
- failover *sentinelFailover,
-) func(ctx context.Context, network, addr string) (net.Conn, error) {
- return func(ctx context.Context, network, _ string) (net.Conn, error) {
- var addr string
- var err error
-
- if failover.opt.SlaveOnly {
- addr, err = failover.RandomSlaveAddr(ctx)
- } else {
- addr, err = failover.MasterAddr(ctx)
- if err == nil {
- failover.trySwitchMaster(ctx, addr)
- }
- }
-
- if err != nil {
- return nil, err
- }
- if failover.opt.Dialer != nil {
- return failover.opt.Dialer(ctx, network, addr)
- }
- return net.DialTimeout("tcp", addr, failover.opt.DialTimeout)
- }
-}
-
-//------------------------------------------------------------------------------
-
-// SentinelClient is a client for a Redis Sentinel.
-type SentinelClient struct {
- *baseClient
- hooks
- ctx context.Context
-}
-
-func NewSentinelClient(opt *Options) *SentinelClient {
- opt.init()
- c := &SentinelClient{
- baseClient: &baseClient{
- opt: opt,
- connPool: newConnPool(opt),
- },
- ctx: context.Background(),
- }
- return c
-}
-
-func (c *SentinelClient) Context() context.Context {
- return c.ctx
-}
-
-func (c *SentinelClient) WithContext(ctx context.Context) *SentinelClient {
- if ctx == nil {
- panic("nil context")
- }
- clone := *c
- clone.ctx = ctx
- return &clone
-}
-
-func (c *SentinelClient) Process(ctx context.Context, cmd Cmder) error {
- return c.hooks.process(ctx, cmd, c.baseClient.process)
-}
-
-func (c *SentinelClient) pubSub() *PubSub {
- pubsub := &PubSub{
- opt: c.opt,
-
- newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) {
- return c.newConn(ctx)
- },
- closeConn: c.connPool.CloseConn,
- }
- pubsub.init()
- return pubsub
-}
-
-// Ping is used to test if a connection is still alive, or to
-// measure latency.
-func (c *SentinelClient) Ping(ctx context.Context) *StringCmd {
- cmd := NewStringCmd(ctx, "ping")
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Subscribe subscribes the client to the specified channels.
-// Channels can be omitted to create empty subscription.
-func (c *SentinelClient) Subscribe(ctx context.Context, channels ...string) *PubSub {
- pubsub := c.pubSub()
- if len(channels) > 0 {
- _ = pubsub.Subscribe(ctx, channels...)
- }
- return pubsub
-}
-
-// PSubscribe subscribes the client to the given patterns.
-// Patterns can be omitted to create empty subscription.
-func (c *SentinelClient) PSubscribe(ctx context.Context, channels ...string) *PubSub {
- pubsub := c.pubSub()
- if len(channels) > 0 {
- _ = pubsub.PSubscribe(ctx, channels...)
- }
- return pubsub
-}
-
-func (c *SentinelClient) GetMasterAddrByName(ctx context.Context, name string) *StringSliceCmd {
- cmd := NewStringSliceCmd(ctx, "sentinel", "get-master-addr-by-name", name)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-func (c *SentinelClient) Sentinels(ctx context.Context, name string) *SliceCmd {
- cmd := NewSliceCmd(ctx, "sentinel", "sentinels", name)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Failover forces a failover as if the master was not reachable, and without
-// asking for agreement to other Sentinels.
-func (c *SentinelClient) Failover(ctx context.Context, name string) *StatusCmd {
- cmd := NewStatusCmd(ctx, "sentinel", "failover", name)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Reset resets all the masters with matching name. The pattern argument is a
-// glob-style pattern. The reset process clears any previous state in a master
-// (including a failover in progress), and removes every slave and sentinel
-// already discovered and associated with the master.
-func (c *SentinelClient) Reset(ctx context.Context, pattern string) *IntCmd {
- cmd := NewIntCmd(ctx, "sentinel", "reset", pattern)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// FlushConfig forces Sentinel to rewrite its configuration on disk, including
-// the current Sentinel state.
-func (c *SentinelClient) FlushConfig(ctx context.Context) *StatusCmd {
- cmd := NewStatusCmd(ctx, "sentinel", "flushconfig")
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Master shows the state and info of the specified master.
-func (c *SentinelClient) Master(ctx context.Context, name string) *StringStringMapCmd {
- cmd := NewStringStringMapCmd(ctx, "sentinel", "master", name)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Masters shows a list of monitored masters and their state.
-func (c *SentinelClient) Masters(ctx context.Context) *SliceCmd {
- cmd := NewSliceCmd(ctx, "sentinel", "masters")
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Slaves shows a list of slaves for the specified master and their state.
-func (c *SentinelClient) Slaves(ctx context.Context, name string) *SliceCmd {
- cmd := NewSliceCmd(ctx, "sentinel", "slaves", name)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// CkQuorum checks if the current Sentinel configuration is able to reach the
-// quorum needed to failover a master, and the majority needed to authorize the
-// failover. This command should be used in monitoring systems to check if a
-// Sentinel deployment is ok.
-func (c *SentinelClient) CkQuorum(ctx context.Context, name string) *StringCmd {
- cmd := NewStringCmd(ctx, "sentinel", "ckquorum", name)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Monitor tells the Sentinel to start monitoring a new master with the specified
-// name, ip, port, and quorum.
-func (c *SentinelClient) Monitor(ctx context.Context, name, ip, port, quorum string) *StringCmd {
- cmd := NewStringCmd(ctx, "sentinel", "monitor", name, ip, port, quorum)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Set is used in order to change configuration parameters of a specific master.
-func (c *SentinelClient) Set(ctx context.Context, name, option, value string) *StringCmd {
- cmd := NewStringCmd(ctx, "sentinel", "set", name, option, value)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Remove is used in order to remove the specified master: the master will no
-// longer be monitored, and will totally be removed from the internal state of
-// the Sentinel.
-func (c *SentinelClient) Remove(ctx context.Context, name string) *StringCmd {
- cmd := NewStringCmd(ctx, "sentinel", "remove", name)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-//------------------------------------------------------------------------------
-
-type sentinelFailover struct {
- opt *FailoverOptions
-
- sentinelAddrs []string
-
- onFailover func(ctx context.Context, addr string)
- onUpdate func(ctx context.Context)
-
- mu sync.RWMutex
- _masterAddr string
- sentinel *SentinelClient
- pubsub *PubSub
-}
-
-func (c *sentinelFailover) Close() error {
- c.mu.Lock()
- defer c.mu.Unlock()
- if c.sentinel != nil {
- return c.closeSentinel()
- }
- return nil
-}
-
-func (c *sentinelFailover) closeSentinel() error {
- firstErr := c.pubsub.Close()
- c.pubsub = nil
-
- err := c.sentinel.Close()
- if err != nil && firstErr == nil {
- firstErr = err
- }
- c.sentinel = nil
-
- return firstErr
-}
-
-func (c *sentinelFailover) RandomSlaveAddr(ctx context.Context) (string, error) {
- addresses, err := c.slaveAddrs(ctx)
- if err != nil {
- return "", err
- }
- if len(addresses) == 0 {
- return c.MasterAddr(ctx)
- }
- return addresses[rand.Intn(len(addresses))], nil
-}
-
-func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) {
- c.mu.RLock()
- sentinel := c.sentinel
- c.mu.RUnlock()
-
- if sentinel != nil {
- addr := c.getMasterAddr(ctx, sentinel)
- if addr != "" {
- return addr, nil
- }
- }
-
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if c.sentinel != nil {
- addr := c.getMasterAddr(ctx, c.sentinel)
- if addr != "" {
- return addr, nil
- }
- _ = c.closeSentinel()
- }
-
- for i, sentinelAddr := range c.sentinelAddrs {
- sentinel := NewSentinelClient(c.opt.sentinelOptions(sentinelAddr))
-
- masterAddr, err := sentinel.GetMasterAddrByName(ctx, c.opt.MasterName).Result()
- if err != nil {
- internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName master=%q failed: %s",
- c.opt.MasterName, err)
- _ = sentinel.Close()
- continue
- }
-
- // Push working sentinel to the top.
- c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0]
- c.setSentinel(ctx, sentinel)
-
- addr := net.JoinHostPort(masterAddr[0], masterAddr[1])
- return addr, nil
- }
-
- return "", errors.New("redis: all sentinels are unreachable")
-}
-
-func (c *sentinelFailover) slaveAddrs(ctx context.Context) ([]string, error) {
- c.mu.RLock()
- sentinel := c.sentinel
- c.mu.RUnlock()
-
- if sentinel != nil {
- addrs := c.getSlaveAddrs(ctx, sentinel)
- if len(addrs) > 0 {
- return addrs, nil
- }
- }
-
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if c.sentinel != nil {
- addrs := c.getSlaveAddrs(ctx, c.sentinel)
- if len(addrs) > 0 {
- return addrs, nil
- }
- _ = c.closeSentinel()
- }
-
- for i, sentinelAddr := range c.sentinelAddrs {
- sentinel := NewSentinelClient(c.opt.sentinelOptions(sentinelAddr))
-
- slaves, err := sentinel.Slaves(ctx, c.opt.MasterName).Result()
- if err != nil {
- internal.Logger.Printf(ctx, "sentinel: Slaves master=%q failed: %s",
- c.opt.MasterName, err)
- _ = sentinel.Close()
- continue
- }
-
- // Push working sentinel to the top.
- c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0]
- c.setSentinel(ctx, sentinel)
-
- addrs := parseSlaveAddrs(slaves)
- return addrs, nil
- }
-
- return []string{}, errors.New("redis: all sentinels are unreachable")
-}
-
-func (c *sentinelFailover) getMasterAddr(ctx context.Context, sentinel *SentinelClient) string {
- addr, err := sentinel.GetMasterAddrByName(ctx, c.opt.MasterName).Result()
- if err != nil {
- internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName name=%q failed: %s",
- c.opt.MasterName, err)
- return ""
- }
- return net.JoinHostPort(addr[0], addr[1])
-}
-
-func (c *sentinelFailover) getSlaveAddrs(ctx context.Context, sentinel *SentinelClient) []string {
- addrs, err := sentinel.Slaves(ctx, c.opt.MasterName).Result()
- if err != nil {
- internal.Logger.Printf(ctx, "sentinel: Slaves name=%q failed: %s",
- c.opt.MasterName, err)
- return []string{}
- }
- return parseSlaveAddrs(addrs)
-}
-
-func parseSlaveAddrs(addrs []interface{}) []string {
- nodes := make([]string, 0, len(addrs))
-
- for _, node := range addrs {
- ip := ""
- port := ""
- flags := []string{}
- lastkey := ""
- isDown := false
-
- for _, key := range node.([]interface{}) {
- switch lastkey {
- case "ip":
- ip = key.(string)
- case "port":
- port = key.(string)
- case "flags":
- flags = strings.Split(key.(string), ",")
- }
- lastkey = key.(string)
- }
-
- for _, flag := range flags {
- switch flag {
- case "s_down", "o_down", "disconnected":
- isDown = true
- }
- }
-
- if !isDown {
- nodes = append(nodes, net.JoinHostPort(ip, port))
- }
- }
-
- return nodes
-}
-
-func (c *sentinelFailover) trySwitchMaster(ctx context.Context, addr string) {
- c.mu.RLock()
- currentAddr := c._masterAddr
- c.mu.RUnlock()
-
- if addr == currentAddr {
- return
- }
-
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if addr == c._masterAddr {
- return
- }
- c._masterAddr = addr
-
- internal.Logger.Printf(ctx, "sentinel: new master=%q addr=%q",
- c.opt.MasterName, addr)
- if c.onFailover != nil {
- c.onFailover(ctx, addr)
- }
-}
-
-func (c *sentinelFailover) setSentinel(ctx context.Context, sentinel *SentinelClient) {
- if c.sentinel != nil {
- panic("not reached")
- }
- c.sentinel = sentinel
- c.discoverSentinels(ctx)
-
- c.pubsub = sentinel.Subscribe(ctx, "+switch-master", "+slave-reconf-done")
- go c.listen(c.pubsub)
-}
-
-func (c *sentinelFailover) discoverSentinels(ctx context.Context) {
- sentinels, err := c.sentinel.Sentinels(ctx, c.opt.MasterName).Result()
- if err != nil {
- internal.Logger.Printf(ctx, "sentinel: Sentinels master=%q failed: %s", c.opt.MasterName, err)
- return
- }
- for _, sentinel := range sentinels {
- vals := sentinel.([]interface{})
- for i := 0; i < len(vals); i += 2 {
- key := vals[i].(string)
- if key == "name" {
- sentinelAddr := vals[i+1].(string)
- if !contains(c.sentinelAddrs, sentinelAddr) {
- internal.Logger.Printf(ctx, "sentinel: discovered new sentinel=%q for master=%q",
- sentinelAddr, c.opt.MasterName)
- c.sentinelAddrs = append(c.sentinelAddrs, sentinelAddr)
- }
- }
- }
- }
-}
-
-func (c *sentinelFailover) listen(pubsub *PubSub) {
- ctx := context.TODO()
- if c.onUpdate != nil {
- c.onUpdate(ctx)
- }
-
- ch := pubsub.Channel()
- for msg := range ch {
- if msg.Channel == "+switch-master" {
- parts := strings.Split(msg.Payload, " ")
- if parts[0] != c.opt.MasterName {
- internal.Logger.Printf(pubsub.getContext(), "sentinel: ignore addr for master=%q", parts[0])
- continue
- }
- addr := net.JoinHostPort(parts[3], parts[4])
- c.trySwitchMaster(pubsub.getContext(), addr)
- }
-
- if c.onUpdate != nil {
- c.onUpdate(ctx)
- }
- }
-}
-
-func contains(slice []string, str string) bool {
- for _, s := range slice {
- if s == str {
- return true
- }
- }
- return false
-}
-
-//------------------------------------------------------------------------------
-
-// NewFailoverClusterClient returns a client that supports routing read-only commands
-// to a slave node.
-func NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient {
- sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs))
- copy(sentinelAddrs, failoverOpt.SentinelAddrs)
-
- failover := &sentinelFailover{
- opt: failoverOpt,
- sentinelAddrs: sentinelAddrs,
- }
-
- opt := failoverOpt.clusterOptions()
- opt.ClusterSlots = func(ctx context.Context) ([]ClusterSlot, error) {
- masterAddr, err := failover.MasterAddr(ctx)
- if err != nil {
- return nil, err
- }
-
- nodes := []ClusterNode{{
- Addr: masterAddr,
- }}
-
- slaveAddrs, err := failover.slaveAddrs(ctx)
- if err != nil {
- return nil, err
- }
-
- for _, slaveAddr := range slaveAddrs {
- nodes = append(nodes, ClusterNode{
- Addr: slaveAddr,
- })
- }
-
- slots := []ClusterSlot{
- {
- Start: 0,
- End: 16383,
- Nodes: nodes,
- },
- }
- return slots, nil
- }
-
- c := NewClusterClient(opt)
- failover.onUpdate = func(ctx context.Context) {
- c.ReloadState(ctx)
- }
-
- return c
-}
diff --git a/vendor/github.com/go-redis/redis/v8/tx.go b/vendor/github.com/go-redis/redis/v8/tx.go
deleted file mode 100644
index ad825c610ca..00000000000
--- a/vendor/github.com/go-redis/redis/v8/tx.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package redis
-
-import (
- "context"
-
- "github.com/go-redis/redis/v8/internal/pool"
- "github.com/go-redis/redis/v8/internal/proto"
-)
-
-// TxFailedErr transaction redis failed.
-const TxFailedErr = proto.RedisError("redis: transaction failed")
-
-// Tx implements Redis transactions as described in
-// http://redis.io/topics/transactions. It's NOT safe for concurrent use
-// by multiple goroutines, because Exec resets list of watched keys.
-// If you don't need WATCH it is better to use Pipeline.
-type Tx struct {
- baseClient
- cmdable
- statefulCmdable
- hooks
- ctx context.Context
-}
-
-func (c *Client) newTx(ctx context.Context) *Tx {
- tx := Tx{
- baseClient: baseClient{
- opt: c.opt,
- connPool: pool.NewStickyConnPool(c.connPool),
- },
- hooks: c.hooks.clone(),
- ctx: ctx,
- }
- tx.init()
- return &tx
-}
-
-func (c *Tx) init() {
- c.cmdable = c.Process
- c.statefulCmdable = c.Process
-}
-
-func (c *Tx) Context() context.Context {
- return c.ctx
-}
-
-func (c *Tx) WithContext(ctx context.Context) *Tx {
- if ctx == nil {
- panic("nil context")
- }
- clone := *c
- clone.init()
- clone.hooks.lock()
- clone.ctx = ctx
- return &clone
-}
-
-func (c *Tx) Process(ctx context.Context, cmd Cmder) error {
- return c.hooks.process(ctx, cmd, c.baseClient.process)
-}
-
-// Watch prepares a transaction and marks the keys to be watched
-// for conditional execution if there are any keys.
-//
-// The transaction is automatically closed when fn exits.
-func (c *Client) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error {
- tx := c.newTx(ctx)
- if len(keys) > 0 {
- if err := tx.Watch(ctx, keys...).Err(); err != nil {
- _ = tx.Close(ctx)
- return err
- }
- }
-
- err := fn(tx)
- _ = tx.Close(ctx)
- return err
-}
-
-// Close closes the transaction, releasing any open resources.
-func (c *Tx) Close(ctx context.Context) error {
- _ = c.Unwatch(ctx).Err()
- return c.baseClient.Close()
-}
-
-// Watch marks the keys to be watched for conditional execution
-// of a transaction.
-func (c *Tx) Watch(ctx context.Context, keys ...string) *StatusCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "watch"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewStatusCmd(ctx, args...)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Unwatch flushes all the previously watched keys for a transaction.
-func (c *Tx) Unwatch(ctx context.Context, keys ...string) *StatusCmd {
- args := make([]interface{}, 1+len(keys))
- args[0] = "unwatch"
- for i, key := range keys {
- args[1+i] = key
- }
- cmd := NewStatusCmd(ctx, args...)
- _ = c.Process(ctx, cmd)
- return cmd
-}
-
-// Pipeline creates a pipeline. Usually it is more convenient to use Pipelined.
-func (c *Tx) Pipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: func(ctx context.Context, cmds []Cmder) error {
- return c.hooks.processPipeline(ctx, cmds, c.baseClient.processPipeline)
- },
- }
- pipe.init()
- return &pipe
-}
-
-// Pipelined executes commands queued in the fn outside of the transaction.
-// Use TxPipelined if you need transactional behavior.
-func (c *Tx) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.Pipeline().Pipelined(ctx, fn)
-}
-
-// TxPipelined executes commands queued in the fn in the transaction.
-//
-// When using WATCH, EXEC will execute commands only if the watched keys
-// were not modified, allowing for a check-and-set mechanism.
-//
-// Exec always returns list of commands. If transaction fails
-// TxFailedErr is returned. Otherwise Exec returns an error of the first
-// failed command or nil.
-func (c *Tx) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) {
- return c.TxPipeline().Pipelined(ctx, fn)
-}
-
-// TxPipeline creates a pipeline. Usually it is more convenient to use TxPipelined.
-func (c *Tx) TxPipeline() Pipeliner {
- pipe := Pipeline{
- ctx: c.ctx,
- exec: func(ctx context.Context, cmds []Cmder) error {
- return c.hooks.processTxPipeline(ctx, cmds, c.baseClient.processTxPipeline)
- },
- }
- pipe.init()
- return &pipe
-}
diff --git a/vendor/github.com/go-redis/redis/v8/universal.go b/vendor/github.com/go-redis/redis/v8/universal.go
deleted file mode 100644
index 5f0e1e33a5e..00000000000
--- a/vendor/github.com/go-redis/redis/v8/universal.go
+++ /dev/null
@@ -1,206 +0,0 @@
-package redis
-
-import (
- "context"
- "crypto/tls"
- "net"
- "time"
-)
-
-// UniversalOptions information is required by UniversalClient to establish
-// connections.
-type UniversalOptions struct {
- // Either a single address or a seed list of host:port addresses
- // of cluster/sentinel nodes.
- Addrs []string
-
- // Database to be selected after connecting to the server.
- // Only single-node and failover clients.
- DB int
-
- // Common options.
-
- Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
- OnConnect func(ctx context.Context, cn *Conn) error
-
- Username string
- Password string
- SentinelPassword string
-
- MaxRetries int
- MinRetryBackoff time.Duration
- MaxRetryBackoff time.Duration
-
- DialTimeout time.Duration
- ReadTimeout time.Duration
- WriteTimeout time.Duration
-
- PoolSize int
- MinIdleConns int
- MaxConnAge time.Duration
- PoolTimeout time.Duration
- IdleTimeout time.Duration
- IdleCheckFrequency time.Duration
-
- TLSConfig *tls.Config
-
- // Only cluster clients.
-
- MaxRedirects int
- ReadOnly bool
- RouteByLatency bool
- RouteRandomly bool
-
- // The sentinel master name.
- // Only failover clients.
- MasterName string
-}
-
-// Cluster returns cluster options created from the universal options.
-func (o *UniversalOptions) Cluster() *ClusterOptions {
- if len(o.Addrs) == 0 {
- o.Addrs = []string{"127.0.0.1:6379"}
- }
-
- return &ClusterOptions{
- Addrs: o.Addrs,
- Dialer: o.Dialer,
- OnConnect: o.OnConnect,
-
- Username: o.Username,
- Password: o.Password,
-
- MaxRedirects: o.MaxRedirects,
- ReadOnly: o.ReadOnly,
- RouteByLatency: o.RouteByLatency,
- RouteRandomly: o.RouteRandomly,
-
- MaxRetries: o.MaxRetries,
- MinRetryBackoff: o.MinRetryBackoff,
- MaxRetryBackoff: o.MaxRetryBackoff,
-
- DialTimeout: o.DialTimeout,
- ReadTimeout: o.ReadTimeout,
- WriteTimeout: o.WriteTimeout,
- PoolSize: o.PoolSize,
- MinIdleConns: o.MinIdleConns,
- MaxConnAge: o.MaxConnAge,
- PoolTimeout: o.PoolTimeout,
- IdleTimeout: o.IdleTimeout,
- IdleCheckFrequency: o.IdleCheckFrequency,
-
- TLSConfig: o.TLSConfig,
- }
-}
-
-// Failover returns failover options created from the universal options.
-func (o *UniversalOptions) Failover() *FailoverOptions {
- if len(o.Addrs) == 0 {
- o.Addrs = []string{"127.0.0.1:26379"}
- }
-
- return &FailoverOptions{
- SentinelAddrs: o.Addrs,
- MasterName: o.MasterName,
-
- Dialer: o.Dialer,
- OnConnect: o.OnConnect,
-
- DB: o.DB,
- Username: o.Username,
- Password: o.Password,
- SentinelPassword: o.SentinelPassword,
-
- MaxRetries: o.MaxRetries,
- MinRetryBackoff: o.MinRetryBackoff,
- MaxRetryBackoff: o.MaxRetryBackoff,
-
- DialTimeout: o.DialTimeout,
- ReadTimeout: o.ReadTimeout,
- WriteTimeout: o.WriteTimeout,
-
- PoolSize: o.PoolSize,
- MinIdleConns: o.MinIdleConns,
- MaxConnAge: o.MaxConnAge,
- PoolTimeout: o.PoolTimeout,
- IdleTimeout: o.IdleTimeout,
- IdleCheckFrequency: o.IdleCheckFrequency,
-
- TLSConfig: o.TLSConfig,
- }
-}
-
-// Simple returns basic options created from the universal options.
-func (o *UniversalOptions) Simple() *Options {
- addr := "127.0.0.1:6379"
- if len(o.Addrs) > 0 {
- addr = o.Addrs[0]
- }
-
- return &Options{
- Addr: addr,
- Dialer: o.Dialer,
- OnConnect: o.OnConnect,
-
- DB: o.DB,
- Username: o.Username,
- Password: o.Password,
-
- MaxRetries: o.MaxRetries,
- MinRetryBackoff: o.MinRetryBackoff,
- MaxRetryBackoff: o.MaxRetryBackoff,
-
- DialTimeout: o.DialTimeout,
- ReadTimeout: o.ReadTimeout,
- WriteTimeout: o.WriteTimeout,
-
- PoolSize: o.PoolSize,
- MinIdleConns: o.MinIdleConns,
- MaxConnAge: o.MaxConnAge,
- PoolTimeout: o.PoolTimeout,
- IdleTimeout: o.IdleTimeout,
- IdleCheckFrequency: o.IdleCheckFrequency,
-
- TLSConfig: o.TLSConfig,
- }
-}
-
-// --------------------------------------------------------------------
-
-// UniversalClient is an abstract client which - based on the provided options -
-// can connect to either clusters, or sentinel-backed failover instances
-// or simple single-instance servers. This can be useful for testing
-// cluster-specific applications locally.
-type UniversalClient interface {
- Cmdable
- Context() context.Context
- AddHook(Hook)
- Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error
- Do(ctx context.Context, args ...interface{}) *Cmd
- Process(ctx context.Context, cmd Cmder) error
- Subscribe(ctx context.Context, channels ...string) *PubSub
- PSubscribe(ctx context.Context, channels ...string) *PubSub
- Close() error
- PoolStats() *PoolStats
-}
-
-var (
- _ UniversalClient = (*Client)(nil)
- _ UniversalClient = (*ClusterClient)(nil)
- _ UniversalClient = (*Ring)(nil)
-)
-
-// NewUniversalClient returns a new multi client. The type of client returned depends
-// on the following three conditions:
-//
-// 1. if a MasterName is passed a sentinel-backed FailoverClient will be returned
-// 2. if the number of Addrs is two or more, a ClusterClient will be returned
-// 3. otherwise, a single-node redis Client will be returned.
-func NewUniversalClient(opts *UniversalOptions) UniversalClient {
- if opts.MasterName != "" {
- return NewFailoverClient(opts.Failover())
- } else if len(opts.Addrs) > 1 {
- return NewClusterClient(opts.Cluster())
- }
- return NewClient(opts.Simple())
-}
diff --git a/vendor/github.com/gobuffalo/envy/.gitignore b/vendor/github.com/gobuffalo/envy/.gitignore
deleted file mode 100644
index 05bc384b5ed..00000000000
--- a/vendor/github.com/gobuffalo/envy/.gitignore
+++ /dev/null
@@ -1,30 +0,0 @@
-*.log
-.DS_Store
-doc
-tmp
-pkg
-*.gem
-*.pid
-coverage
-coverage.data
-build/*
-*.pbxuser
-*.mode1v3
-.svn
-profile
-.console_history
-.sass-cache/*
-.rake_tasks~
-*.log.lck
-solr/
-.jhw-cache/
-jhw.*
-*.sublime*
-node_modules/
-dist/
-generated/
-.vendor/
-bin/*
-gin-bin
-.idea/
-.env
diff --git a/vendor/github.com/gobuffalo/envy/.gometalinter.json b/vendor/github.com/gobuffalo/envy/.gometalinter.json
deleted file mode 100644
index e4f65a36e82..00000000000
--- a/vendor/github.com/gobuffalo/envy/.gometalinter.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"]
-}
diff --git a/vendor/github.com/gobuffalo/envy/LICENSE.txt b/vendor/github.com/gobuffalo/envy/LICENSE.txt
deleted file mode 100644
index 123ddc0d804..00000000000
--- a/vendor/github.com/gobuffalo/envy/LICENSE.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-The MIT License (MIT)
-Copyright (c) 2018 Mark Bates
-
-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.
diff --git a/vendor/github.com/gobuffalo/envy/Makefile b/vendor/github.com/gobuffalo/envy/Makefile
deleted file mode 100644
index 46aece8ff32..00000000000
--- a/vendor/github.com/gobuffalo/envy/Makefile
+++ /dev/null
@@ -1,46 +0,0 @@
-TAGS ?= "sqlite"
-GO_BIN ?= go
-
-install:
- packr2
- $(GO_BIN) install -v .
-
-deps:
- $(GO_BIN) get github.com/gobuffalo/release
- $(GO_BIN) get github.com/gobuffalo/packr/v2/packr2
- $(GO_BIN) get -tags ${TAGS} -t ./...
-ifeq ($(GO111MODULE),on)
- $(GO_BIN) mod tidy
-endif
-
-build:
- packr2
- $(GO_BIN) build -v .
-
-test:
- packr2
- $(GO_BIN) test -tags ${TAGS} ./...
-
-ci-test:
- $(GO_BIN) test -tags ${TAGS} -race ./...
-
-lint:
- gometalinter --vendor ./... --deadline=1m --skip=internal
-
-update:
- $(GO_BIN) get -u -tags ${TAGS}
-ifeq ($(GO111MODULE),on)
- $(GO_BIN) mod tidy
-endif
- packr2
- make test
- make install
-ifeq ($(GO111MODULE),on)
- $(GO_BIN) mod tidy
-endif
-
-release-test:
- $(GO_BIN) test -tags ${TAGS} -race ./...
-
-release:
- release -y -f version.go
diff --git a/vendor/github.com/gobuffalo/envy/README.md b/vendor/github.com/gobuffalo/envy/README.md
deleted file mode 100644
index f54462a7732..00000000000
--- a/vendor/github.com/gobuffalo/envy/README.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# envy
-[![Build Status](https://travis-ci.org/gobuffalo/envy.svg?branch=master)](https://travis-ci.org/gobuffalo/envy)
-
-Envy makes working with ENV variables in Go trivial.
-
-* Get ENV variables with default values.
-* Set ENV variables safely without affecting the underlying system.
-* Temporarily change ENV vars; useful for testing.
-* Map all of the key/values in the ENV.
-* Loads .env files (by using [godotenv](https://github.com/joho/godotenv/))
-* More!
-
-## Installation
-
-```text
-$ go get -u github.com/gobuffalo/envy
-```
-
-## Usage
-
-```go
-func Test_Get(t *testing.T) {
- r := require.New(t)
- r.NotZero(os.Getenv("GOPATH"))
- r.Equal(os.Getenv("GOPATH"), envy.Get("GOPATH", "foo"))
- r.Equal("bar", envy.Get("IDONTEXIST", "bar"))
-}
-
-func Test_MustGet(t *testing.T) {
- r := require.New(t)
- r.NotZero(os.Getenv("GOPATH"))
- v, err := envy.MustGet("GOPATH")
- r.NoError(err)
- r.Equal(os.Getenv("GOPATH"), v)
-
- _, err = envy.MustGet("IDONTEXIST")
- r.Error(err)
-}
-
-func Test_Set(t *testing.T) {
- r := require.New(t)
- _, err := envy.MustGet("FOO")
- r.Error(err)
-
- envy.Set("FOO", "foo")
- r.Equal("foo", envy.Get("FOO", "bar"))
-}
-
-func Test_Temp(t *testing.T) {
- r := require.New(t)
-
- _, err := envy.MustGet("BAR")
- r.Error(err)
-
- envy.Temp(func() {
- envy.Set("BAR", "foo")
- r.Equal("foo", envy.Get("BAR", "bar"))
- _, err = envy.MustGet("BAR")
- r.NoError(err)
- })
-
- _, err = envy.MustGet("BAR")
- r.Error(err)
-}
-```
-## .env files support
-
-Envy now supports loading `.env` files by using the [godotenv library](https://github.com/joho/godotenv/).
-That means one can use and define multiple `.env` files which will be loaded on-demand. By default, no env files will be loaded. To load one or more, you need to call the `envy.Load` function in one of the following ways:
-
-```go
-envy.Load() // 1
-
-envy.Load("MY_ENV_FILE") // 2
-
-envy.Load(".env", ".env.prod") // 3
-
-envy.Load(".env", "NON_EXISTING_FILE") // 4
-
-// 5
-envy.Load(".env")
-envy.Load("NON_EXISTING_FILE")
-
-// 6
-envy.Load(".env", "NON_EXISTING_FILE", ".env.prod")
-```
-
-1. Will load the default `.env` file
-2. Will load the file `MY_ENV_FILE`, **but not** `.env`
-3. Will load the file `.env`, and after that will load the `.env.prod` file. If any variable is redefined in `. env.prod` it will be overwritten (will contain the `env.prod` value)
-4. Will load the `.env` file and return an error as the second file does not exist. The values in `.env` will be loaded and available.
-5. Same as 4
-6. Will load the `.env` file and return an error as the second file does not exist. The values in `.env` will be loaded and available, **but the ones in** `.env.prod` **won't**.
diff --git a/vendor/github.com/gobuffalo/envy/SHOULDERS.md b/vendor/github.com/gobuffalo/envy/SHOULDERS.md
deleted file mode 100644
index 2384f72f4b0..00000000000
--- a/vendor/github.com/gobuffalo/envy/SHOULDERS.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# github.com/gobuffalo/envy Stands on the Shoulders of Giants
-
-github.com/gobuffalo/envy does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work.
-
-Thank you to the following **GIANTS**:
-
-
-* [github.com/davecgh/go-spew](https://godoc.org/github.com/davecgh/go-spew)
-
-* [github.com/joho/godotenv](https://godoc.org/github.com/joho/godotenv)
-
-* [github.com/rogpeppe/go-internal](https://godoc.org/github.com/rogpeppe/go-internal)
-
-* [github.com/stretchr/testify](https://godoc.org/github.com/stretchr/testify)
diff --git a/vendor/github.com/gobuffalo/envy/azure-pipelines.yml b/vendor/github.com/gobuffalo/envy/azure-pipelines.yml
deleted file mode 100644
index 144c4a2094a..00000000000
--- a/vendor/github.com/gobuffalo/envy/azure-pipelines.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-variables:
- GOBIN: "$(GOPATH)/bin" # Go binaries path
- GOPATH: "$(system.defaultWorkingDirectory)/gopath" # Go workspace path
- modulePath: "$(GOPATH)/src/github.com/$(build.repository.name)" # Path to the module"s code
-
-jobs:
-- job: Windows
- pool:
- vmImage: "vs2017-win2016"
- strategy:
- matrix:
- go 1.9:
- go_version: "1.9"
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
-
-- job: macOS
- pool:
- vmImage: "macOS-10.13"
- strategy:
- matrix:
- go 1.9:
- go_version: "1.9"
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
-
-- job: Linux
- pool:
- vmImage: "ubuntu-16.04"
- strategy:
- matrix:
- go 1.9:
- go_version: "1.9"
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
diff --git a/vendor/github.com/gobuffalo/envy/azure-tests.yml b/vendor/github.com/gobuffalo/envy/azure-tests.yml
deleted file mode 100644
index eea5822fad5..00000000000
--- a/vendor/github.com/gobuffalo/envy/azure-tests.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-steps:
- - task: GoTool@0
- inputs:
- version: $(go_version)
- - task: Bash@3
- inputs:
- targetType: inline
- script: |
- mkdir -p "$(GOBIN)"
- mkdir -p "$(GOPATH)/pkg"
- mkdir -p "$(modulePath)"
- shopt -s extglob
- mv !(gopath) "$(modulePath)"
- displayName: "Setup Go Workspace"
- - script: |
- go get -t -v ./...
- go test -race ./...
- workingDirectory: "$(modulePath)"
- displayName: "Tests"
diff --git a/vendor/github.com/gobuffalo/envy/azure.sh b/vendor/github.com/gobuffalo/envy/azure.sh
deleted file mode 100644
index f70949796f8..00000000000
--- a/vendor/github.com/gobuffalo/envy/azure.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-set -xe
-
-cat >> .env << EOF
-# This is a comment
-# We can use equal or colon notation
-DIR: root
-FLAVOUR: none
-INSIDE_FOLDER=false
-EOF
diff --git a/vendor/github.com/gobuffalo/envy/env b/vendor/github.com/gobuffalo/envy/env
deleted file mode 100644
index 33eeb3b13b9..00000000000
--- a/vendor/github.com/gobuffalo/envy/env
+++ /dev/null
@@ -1,5 +0,0 @@
-# This is a comment
-# We can use equal or colon notation
-DIR: root
-FLAVOUR: none
-INSIDE_FOLDER=false
\ No newline at end of file
diff --git a/vendor/github.com/gobuffalo/envy/envy.go b/vendor/github.com/gobuffalo/envy/envy.go
deleted file mode 100644
index dc31ba2c0ce..00000000000
--- a/vendor/github.com/gobuffalo/envy/envy.go
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
-package envy makes working with ENV variables in Go trivial.
-
-* Get ENV variables with default values.
-* Set ENV variables safely without affecting the underlying system.
-* Temporarily change ENV vars; useful for testing.
-* Map all of the key/values in the ENV.
-* Loads .env files (by using [godotenv](https://github.com/joho/godotenv/))
-* More!
-*/
-package envy
-
-import (
- "errors"
- "flag"
- "fmt"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
- "sync"
-
- "github.com/joho/godotenv"
- "github.com/rogpeppe/go-internal/modfile"
-)
-
-var gil = &sync.RWMutex{}
-var env = map[string]string{}
-
-// GO111MODULE is ENV for turning mods on/off
-const GO111MODULE = "GO111MODULE"
-
-func init() {
- Load()
- loadEnv()
-}
-
-// Load the ENV variables to the env map
-func loadEnv() {
- gil.Lock()
- defer gil.Unlock()
-
- if os.Getenv("GO_ENV") == "" {
- // if the flag "test.v" is *defined*, we're running as a unit test. Note that we don't care
- // about v.Value (verbose test mode); we just want to know if the test environment has defined
- // it. It's also possible that the flags are not yet fully parsed (i.e. flag.Parsed() == false),
- // so we could not depend on v.Value anyway.
- //
- if v := flag.Lookup("test.v"); v != nil {
- env["GO_ENV"] = "test"
- }
- }
-
- // set the GOPATH if using >= 1.8 and the GOPATH isn't set
- if os.Getenv("GOPATH") == "" {
- out, err := exec.Command("go", "env", "GOPATH").Output()
- if err == nil {
- gp := strings.TrimSpace(string(out))
- os.Setenv("GOPATH", gp)
- }
- }
-
- for _, e := range os.Environ() {
- pair := strings.Split(e, "=")
- env[pair[0]] = os.Getenv(pair[0])
- }
-}
-
-// Mods returns true if module support is enabled, false otherwise
-// See https://github.com/golang/go/wiki/Modules#how-to-install-and-activate-module-support for details
-func Mods() bool {
- go111 := Get(GO111MODULE, "")
-
- if !InGoPath() {
- return go111 != "off"
- }
-
- return go111 == "on"
-}
-
-// Reload the ENV variables. Useful if
-// an external ENV manager has been used
-func Reload() {
- env = map[string]string{}
- loadEnv()
-}
-
-// Load .env files. Files will be loaded in the same order that are received.
-// Redefined vars will override previously existing values.
-// IE: envy.Load(".env", "test_env/.env") will result in DIR=test_env
-// If no arg passed, it will try to load a .env file.
-func Load(files ...string) error {
-
- // If no files received, load the default one
- if len(files) == 0 {
- err := godotenv.Overload()
- if err == nil {
- Reload()
- }
- return err
- }
-
- // We received a list of files
- for _, file := range files {
-
- // Check if it exists or we can access
- if _, err := os.Stat(file); err != nil {
- // It does not exist or we can not access.
- // Return and stop loading
- return err
- }
-
- // It exists and we have permission. Load it
- if err := godotenv.Overload(file); err != nil {
- return err
- }
-
- // Reload the env so all new changes are noticed
- Reload()
-
- }
- return nil
-}
-
-// Get a value from the ENV. If it doesn't exist the
-// default value will be returned.
-func Get(key string, value string) string {
- gil.RLock()
- defer gil.RUnlock()
- if v, ok := env[key]; ok {
- return v
- }
- return value
-}
-
-// Get a value from the ENV. If it doesn't exist
-// an error will be returned
-func MustGet(key string) (string, error) {
- gil.RLock()
- defer gil.RUnlock()
- if v, ok := env[key]; ok {
- return v, nil
- }
- return "", fmt.Errorf("could not find ENV var with %s", key)
-}
-
-// Set a value into the ENV. This is NOT permanent. It will
-// only affect values accessed through envy.
-func Set(key string, value string) {
- gil.Lock()
- defer gil.Unlock()
- env[key] = value
-}
-
-// MustSet the value into the underlying ENV, as well as envy.
-// This may return an error if there is a problem setting the
-// underlying ENV value.
-func MustSet(key string, value string) error {
- gil.Lock()
- defer gil.Unlock()
- err := os.Setenv(key, value)
- if err != nil {
- return err
- }
- env[key] = value
- return nil
-}
-
-// Map all of the keys/values set in envy.
-func Map() map[string]string {
- gil.RLock()
- defer gil.RUnlock()
- cp := map[string]string{}
- for k, v := range env {
- cp[k] = v
- }
- return cp
-}
-
-// Temp makes a copy of the values and allows operation on
-// those values temporarily during the run of the function.
-// At the end of the function run the copy is discarded and
-// the original values are replaced. This is useful for testing.
-// Warning: This function is NOT safe to use from a goroutine or
-// from code which may access any Get or Set function from a goroutine
-func Temp(f func()) {
- oenv := env
- env = map[string]string{}
- for k, v := range oenv {
- env[k] = v
- }
- defer func() { env = oenv }()
- f()
-}
-
-func GoPath() string {
- return Get("GOPATH", "")
-}
-
-func GoBin() string {
- return Get("GO_BIN", "go")
-}
-
-func InGoPath() bool {
- pwd, _ := os.Getwd()
- for _, p := range GoPaths() {
- if strings.HasPrefix(pwd, p) {
- return true
- }
- }
- return false
-}
-
-// GoPaths returns all possible GOPATHS that are set.
-func GoPaths() []string {
- gp := Get("GOPATH", "")
- if runtime.GOOS == "windows" {
- return strings.Split(gp, ";") // Windows uses a different separator
- }
- return strings.Split(gp, ":")
-}
-
-func importPath(path string) string {
- path = strings.TrimPrefix(path, "/private")
- for _, gopath := range GoPaths() {
- srcpath := filepath.Join(gopath, "src")
- rel, err := filepath.Rel(srcpath, path)
- if err == nil {
- return filepath.ToSlash(rel)
- }
- }
-
- // fallback to trim
- rel := strings.TrimPrefix(path, filepath.Join(GoPath(), "src"))
- rel = strings.TrimPrefix(rel, string(filepath.Separator))
- return filepath.ToSlash(rel)
-}
-
-// CurrentModule will attempt to return the module name from `go.mod` if
-// modules are enabled.
-// If modules are not enabled it will fallback to using CurrentPackage instead.
-func CurrentModule() (string, error) {
- if !Mods() {
- return CurrentPackage(), nil
- }
- moddata, err := ioutil.ReadFile("go.mod")
- if err != nil {
- return "", errors.New("go.mod cannot be read or does not exist while go module is enabled")
- }
- packagePath := modfile.ModulePath(moddata)
- if packagePath == "" {
- return "", errors.New("go.mod is malformed")
- }
- return packagePath, nil
-}
-
-// CurrentPackage attempts to figure out the current package name from the PWD
-// Use CurrentModule for a more accurate package name.
-func CurrentPackage() string {
- if Mods() {
- }
- pwd, _ := os.Getwd()
- return importPath(pwd)
-}
-
-func Environ() []string {
- gil.RLock()
- defer gil.RUnlock()
- var e []string
- for k, v := range env {
- e = append(e, fmt.Sprintf("%s=%s", k, v))
- }
- return e
-}
diff --git a/vendor/github.com/gobuffalo/envy/go.mod b/vendor/github.com/gobuffalo/envy/go.mod
deleted file mode 100644
index d951b7ce1c2..00000000000
--- a/vendor/github.com/gobuffalo/envy/go.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-module github.com/gobuffalo/envy
-
-require (
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/joho/godotenv v1.3.0
- github.com/rogpeppe/go-internal v1.1.0
- github.com/stretchr/testify v1.3.0
-)
diff --git a/vendor/github.com/gobuffalo/envy/go.sum b/vendor/github.com/gobuffalo/envy/go.sum
deleted file mode 100644
index f11ef4ce58e..00000000000
--- a/vendor/github.com/gobuffalo/envy/go.sum
+++ /dev/null
@@ -1,17 +0,0 @@
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.1.0 h1:g0fH8RicVgNl+zVZDCDfbdWxAWoAEJyI7I3TZYXFiig=
-github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
diff --git a/vendor/github.com/gobuffalo/envy/version.go b/vendor/github.com/gobuffalo/envy/version.go
deleted file mode 100644
index b1623aef723..00000000000
--- a/vendor/github.com/gobuffalo/envy/version.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package envy
-
-const Version = "v1.7.0"
diff --git a/vendor/github.com/gobuffalo/packd/.gitignore b/vendor/github.com/gobuffalo/packd/.gitignore
deleted file mode 100644
index 3689718594c..00000000000
--- a/vendor/github.com/gobuffalo/packd/.gitignore
+++ /dev/null
@@ -1,29 +0,0 @@
-*.log
-.DS_Store
-doc
-tmp
-pkg
-*.gem
-*.pid
-coverage
-coverage.data
-build/*
-*.pbxuser
-*.mode1v3
-.svn
-profile
-.console_history
-.sass-cache/*
-.rake_tasks~
-*.log.lck
-solr/
-.jhw-cache/
-jhw.*
-*.sublime*
-node_modules/
-dist/
-generated/
-.vendor/
-bin/*
-gin-bin
-.idea/
diff --git a/vendor/github.com/gobuffalo/packd/.gometalinter.json b/vendor/github.com/gobuffalo/packd/.gometalinter.json
deleted file mode 100644
index e4f65a36e82..00000000000
--- a/vendor/github.com/gobuffalo/packd/.gometalinter.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"]
-}
diff --git a/vendor/github.com/gobuffalo/packd/LICENSE b/vendor/github.com/gobuffalo/packd/LICENSE
deleted file mode 100644
index 649efd43722..00000000000
--- a/vendor/github.com/gobuffalo/packd/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2019 Mark Bates
-
-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.
diff --git a/vendor/github.com/gobuffalo/packd/Makefile b/vendor/github.com/gobuffalo/packd/Makefile
deleted file mode 100644
index 0ac539f1c2e..00000000000
--- a/vendor/github.com/gobuffalo/packd/Makefile
+++ /dev/null
@@ -1,61 +0,0 @@
-TAGS ?= ""
-GO_BIN ?= "go"
-
-install:
- $(GO_BIN) install -tags ${TAGS} -v .
- make tidy
-
-tidy:
-ifeq ($(GO111MODULE),on)
- $(GO_BIN) mod tidy
-else
- echo skipping go mod tidy
-endif
-
-deps:
- $(GO_BIN) get -tags ${TAGS} -t ./...
- make tidy
-
-build:
- $(GO_BIN) build -v .
- make tidy
-
-test:
- $(GO_BIN) test -cover -tags ${TAGS} ./...
- make tidy
-
-ci-deps:
- $(GO_BIN) get -tags ${TAGS} -t ./...
-
-ci-test:
- $(GO_BIN) test -tags ${TAGS} -race ./...
-
-lint:
- go get github.com/golangci/golangci-lint/cmd/golangci-lint
- golangci-lint run --enable-all
- make tidy
-
-update:
-ifeq ($(GO111MODULE),on)
- rm go.*
- $(GO_BIN) mod init
- $(GO_BIN) mod tidy
-else
- $(GO_BIN) get -u -tags ${TAGS}
-endif
- make test
- make install
- make tidy
-
-release-test:
- $(GO_BIN) test -tags ${TAGS} -race ./...
- make tidy
-
-release:
- $(GO_BIN) get github.com/gobuffalo/release
- make tidy
- release -y -f version.go --skip-packr
- make tidy
-
-
-
diff --git a/vendor/github.com/gobuffalo/packd/README.md b/vendor/github.com/gobuffalo/packd/README.md
deleted file mode 100644
index 1c534cdd594..00000000000
--- a/vendor/github.com/gobuffalo/packd/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-# github.com/gobuffalo/packd
-
-This is a collection of interfaces designed to make using [github.com/gobuffalo/packr](https://github.com/gobuffalo/packr) easier, and to make the transition between v1 and v2 as seamless as possible.
-
-They can, and should, be used for testing, alternate Box implementations, etc...
-
-
-## Installation
-
-```bash
-$ go get -u -v github.com/gobuffalo/packd
-```
-
-## Memory Box
-
-The [`packd#MemoryBox`](https://godoc.org/github.com/gobuffalo/packd#MemoryBox) is a complete, thread-safe, implementation of [`packd#Box`](https://godoc.org/github.com/gobuffalo/packd#Box)
diff --git a/vendor/github.com/gobuffalo/packd/SHOULDERS.md b/vendor/github.com/gobuffalo/packd/SHOULDERS.md
deleted file mode 100644
index 076205ba101..00000000000
--- a/vendor/github.com/gobuffalo/packd/SHOULDERS.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# github.com/gobuffalo/packd Stands on the Shoulders of Giants
-
-github.com/gobuffalo/packd does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work.
-
-Thank you to the following **GIANTS**:
-
-
-* [github.com/davecgh/go-spew](https://godoc.org/github.com/davecgh/go-spew)
-
-* [github.com/stretchr/testify](https://godoc.org/github.com/stretchr/testify)
diff --git a/vendor/github.com/gobuffalo/packd/azure-pipelines.yml b/vendor/github.com/gobuffalo/packd/azure-pipelines.yml
deleted file mode 100644
index 417e2c57921..00000000000
--- a/vendor/github.com/gobuffalo/packd/azure-pipelines.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-variables:
- GOBIN: "$(GOPATH)/bin" # Go binaries path
- GOPATH: "$(system.defaultWorkingDirectory)/gopath" # Go workspace path
- modulePath: "$(GOPATH)/src/github.com/$(build.repository.name)" # Path to the module"s code
-
-jobs:
-- job: Windows
- pool:
- vmImage: "vs2017-win2016"
- strategy:
- matrix:
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11.5"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11.5"
- GO111MODULE: "off"
- go 1.12 (on):
- go_version: "1.12"
- GO111MODULE: "on"
- go 1.12 (off):
- go_version: "1.12"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
-
-- job: macOS
- pool:
- vmImage: "macOS-10.13"
- strategy:
- matrix:
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11.5"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11.5"
- GO111MODULE: "off"
- go 1.12 (on):
- go_version: "1.12"
- GO111MODULE: "on"
- go 1.12 (off):
- go_version: "1.12"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
-
-- job: Linux
- pool:
- vmImage: "ubuntu-16.04"
- strategy:
- matrix:
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11.5"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11.5"
- GO111MODULE: "off"
- go 1.12 (on):
- go_version: "1.12"
- GO111MODULE: "on"
- go 1.12 (off):
- go_version: "1.12"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
diff --git a/vendor/github.com/gobuffalo/packd/azure-tests.yml b/vendor/github.com/gobuffalo/packd/azure-tests.yml
deleted file mode 100644
index eea5822fad5..00000000000
--- a/vendor/github.com/gobuffalo/packd/azure-tests.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-steps:
- - task: GoTool@0
- inputs:
- version: $(go_version)
- - task: Bash@3
- inputs:
- targetType: inline
- script: |
- mkdir -p "$(GOBIN)"
- mkdir -p "$(GOPATH)/pkg"
- mkdir -p "$(modulePath)"
- shopt -s extglob
- mv !(gopath) "$(modulePath)"
- displayName: "Setup Go Workspace"
- - script: |
- go get -t -v ./...
- go test -race ./...
- workingDirectory: "$(modulePath)"
- displayName: "Tests"
diff --git a/vendor/github.com/gobuffalo/packd/file.go b/vendor/github.com/gobuffalo/packd/file.go
deleted file mode 100644
index 58fd86fea46..00000000000
--- a/vendor/github.com/gobuffalo/packd/file.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package packd
-
-import (
- "bytes"
- "fmt"
- "io"
- "os"
- "time"
-)
-
-var _ File = &virtualFile{}
-var _ io.Reader = &virtualFile{}
-var _ io.Writer = &virtualFile{}
-var _ fmt.Stringer = &virtualFile{}
-
-type virtualFile struct {
- io.Reader
- name string
- info fileInfo
- original []byte
-}
-
-func (f virtualFile) Name() string {
- return f.name
-}
-
-func (f *virtualFile) Seek(offset int64, whence int) (int64, error) {
- return f.Reader.(*bytes.Reader).Seek(offset, whence)
-}
-
-func (f virtualFile) FileInfo() (os.FileInfo, error) {
- return f.info, nil
-}
-
-func (f *virtualFile) Close() error {
- return nil
-}
-
-func (f virtualFile) Readdir(count int) ([]os.FileInfo, error) {
- return []os.FileInfo{f.info}, nil
-}
-
-func (f virtualFile) Stat() (os.FileInfo, error) {
- return f.info, nil
-}
-
-func (f virtualFile) String() string {
- return string(f.original)
-}
-
-// Read reads the next len(p) bytes from the virtualFile and
-// rewind read offset to 0 when it met EOF.
-func (f *virtualFile) Read(p []byte) (int, error) {
- i, err := f.Reader.Read(p)
-
- if i == 0 || err == io.EOF {
- f.Seek(0, io.SeekStart)
- }
- return i, err
-}
-
-// Write copies byte slice p to content of virtualFile.
-func (f *virtualFile) Write(p []byte) (int, error) {
- return f.write(p)
-}
-
-// write copies byte slice or data from io.Reader to content of the
-// virtualFile and update related information of the virtualFile.
-func (f *virtualFile) write(d interface{}) (c int, err error) {
- bb := &bytes.Buffer{}
- switch d.(type) {
- case []byte:
- c, err = bb.Write(d.([]byte))
- case io.Reader:
- if d != nil {
- i64, e := io.Copy(bb, d.(io.Reader))
- c = int(i64)
- err = e
- }
- default:
- err = fmt.Errorf("unknown type of argument")
- }
-
- if err != nil {
- return c, err
- }
-
- f.info.size = int64(c)
- f.info.modTime = time.Now()
- f.original = bb.Bytes()
- f.Reader = bytes.NewReader(f.original)
- return c, nil
-}
-
-// NewFile returns a new "virtual" file
-func NewFile(name string, r io.Reader) (File, error) {
- return buildFile(name, r)
-}
-
-// NewDir returns a new "virtual" directory
-func NewDir(name string) (File, error) {
- v, err := buildFile(name, nil)
- if err != nil {
- return v, err
- }
- v.info.isDir = true
- return v, nil
-}
-
-func buildFile(name string, r io.Reader) (*virtualFile, error) {
- vf := &virtualFile{
- name: name,
- info: fileInfo{
- Path: name,
- modTime: time.Now(),
- },
- }
-
- var err error
- if r != nil {
- _, err = vf.write(r)
- } else {
- _, err = vf.write([]byte{}) // for safety
- }
- return vf, err
-}
diff --git a/vendor/github.com/gobuffalo/packd/file_info.go b/vendor/github.com/gobuffalo/packd/file_info.go
deleted file mode 100644
index 8bed0b90374..00000000000
--- a/vendor/github.com/gobuffalo/packd/file_info.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package packd
-
-import (
- "os"
- "time"
-)
-
-var _ os.FileInfo = fileInfo{}
-
-type fileInfo struct {
- Path string
- size int64
- modTime time.Time
- isDir bool
-}
-
-func (f fileInfo) Name() string {
- return f.Path
-}
-
-func (f fileInfo) Size() int64 {
- return f.size
-}
-
-func (f fileInfo) Mode() os.FileMode {
- return 0444
-}
-
-func (f fileInfo) ModTime() time.Time {
- return f.modTime
-}
-
-func (f fileInfo) IsDir() bool {
- return f.isDir
-}
-
-func (f fileInfo) Sys() interface{} {
- return nil
-}
diff --git a/vendor/github.com/gobuffalo/packd/go.mod b/vendor/github.com/gobuffalo/packd/go.mod
deleted file mode 100644
index e61ff1ef099..00000000000
--- a/vendor/github.com/gobuffalo/packd/go.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-module github.com/gobuffalo/packd
-
-go 1.12
-
-require (
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/stretchr/testify v1.3.0
-)
diff --git a/vendor/github.com/gobuffalo/packd/go.sum b/vendor/github.com/gobuffalo/packd/go.sum
deleted file mode 100644
index 4f76e62c1f3..00000000000
--- a/vendor/github.com/gobuffalo/packd/go.sum
+++ /dev/null
@@ -1,9 +0,0 @@
-github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
diff --git a/vendor/github.com/gobuffalo/packd/interfaces.go b/vendor/github.com/gobuffalo/packd/interfaces.go
deleted file mode 100644
index e8475f0aa1a..00000000000
--- a/vendor/github.com/gobuffalo/packd/interfaces.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package packd
-
-import (
- "fmt"
- "io"
- "net/http"
- "os"
-)
-
-type WalkFunc func(string, File) error
-
-// Box represents the entirety of the necessary
-// interfaces to form a "full" box.
-// github.com/gobuffalo/packr#Box is an example of this interface.
-type Box interface {
- HTTPBox
- Lister
- Addable
- Finder
- Walkable
- Haser
-}
-
-type Haser interface {
- Has(string) bool
-}
-
-type Walker interface {
- Walk(wf WalkFunc) error
-}
-
-type Walkable interface {
- Walker
- WalkPrefix(prefix string, wf WalkFunc) error
-}
-
-type Finder interface {
- Find(string) ([]byte, error)
- FindString(name string) (string, error)
-}
-
-type HTTPBox interface {
- Open(name string) (http.File, error)
-}
-
-type Lister interface {
- List() []string
-}
-
-type Addable interface {
- AddString(path string, t string) error
- AddBytes(path string, t []byte) error
-}
-
-type SimpleFile interface {
- fmt.Stringer
- io.Reader
- io.Writer
- Name() string
-}
-
-type HTTPFile interface {
- SimpleFile
- io.Closer
- io.Seeker
- Readdir(count int) ([]os.FileInfo, error)
- Stat() (os.FileInfo, error)
-}
-
-type File interface {
- HTTPFile
- FileInfo() (os.FileInfo, error)
-}
-
-// LegacyBox represents deprecated methods
-// that older Box implementations might have had.
-// github.com/gobuffalo/packr v1 is an example of a LegacyBox.
-type LegacyBox interface {
- String(name string) string
- MustString(name string) (string, error)
- Bytes(name string) []byte
- MustBytes(name string) ([]byte, error)
-}
diff --git a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/.gitignore b/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/.gitignore
deleted file mode 100644
index 3689718594c..00000000000
--- a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/.gitignore
+++ /dev/null
@@ -1,29 +0,0 @@
-*.log
-.DS_Store
-doc
-tmp
-pkg
-*.gem
-*.pid
-coverage
-coverage.data
-build/*
-*.pbxuser
-*.mode1v3
-.svn
-profile
-.console_history
-.sass-cache/*
-.rake_tasks~
-*.log.lck
-solr/
-.jhw-cache/
-jhw.*
-*.sublime*
-node_modules/
-dist/
-generated/
-.vendor/
-bin/*
-gin-bin
-.idea/
diff --git a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/LICENSE b/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/LICENSE
deleted file mode 100644
index 649efd43722..00000000000
--- a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2019 Mark Bates
-
-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.
diff --git a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/Makefile b/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/Makefile
deleted file mode 100644
index 0ac539f1c2e..00000000000
--- a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/Makefile
+++ /dev/null
@@ -1,61 +0,0 @@
-TAGS ?= ""
-GO_BIN ?= "go"
-
-install:
- $(GO_BIN) install -tags ${TAGS} -v .
- make tidy
-
-tidy:
-ifeq ($(GO111MODULE),on)
- $(GO_BIN) mod tidy
-else
- echo skipping go mod tidy
-endif
-
-deps:
- $(GO_BIN) get -tags ${TAGS} -t ./...
- make tidy
-
-build:
- $(GO_BIN) build -v .
- make tidy
-
-test:
- $(GO_BIN) test -cover -tags ${TAGS} ./...
- make tidy
-
-ci-deps:
- $(GO_BIN) get -tags ${TAGS} -t ./...
-
-ci-test:
- $(GO_BIN) test -tags ${TAGS} -race ./...
-
-lint:
- go get github.com/golangci/golangci-lint/cmd/golangci-lint
- golangci-lint run --enable-all
- make tidy
-
-update:
-ifeq ($(GO111MODULE),on)
- rm go.*
- $(GO_BIN) mod init
- $(GO_BIN) mod tidy
-else
- $(GO_BIN) get -u -tags ${TAGS}
-endif
- make test
- make install
- make tidy
-
-release-test:
- $(GO_BIN) test -tags ${TAGS} -race ./...
- make tidy
-
-release:
- $(GO_BIN) get github.com/gobuffalo/release
- make tidy
- release -y -f version.go --skip-packr
- make tidy
-
-
-
diff --git a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/SHOULDERS.md b/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/SHOULDERS.md
deleted file mode 100644
index b19072e9f66..00000000000
--- a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/SHOULDERS.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# github.com/markbates/errx Stands on the Shoulders of Giants
-
-github.com/markbates/errx does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work.
-
-Thank you to the following **GIANTS**:
-
diff --git a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/azure-pipelines.yml b/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/azure-pipelines.yml
deleted file mode 100644
index 417e2c57921..00000000000
--- a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/azure-pipelines.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-variables:
- GOBIN: "$(GOPATH)/bin" # Go binaries path
- GOPATH: "$(system.defaultWorkingDirectory)/gopath" # Go workspace path
- modulePath: "$(GOPATH)/src/github.com/$(build.repository.name)" # Path to the module"s code
-
-jobs:
-- job: Windows
- pool:
- vmImage: "vs2017-win2016"
- strategy:
- matrix:
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11.5"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11.5"
- GO111MODULE: "off"
- go 1.12 (on):
- go_version: "1.12"
- GO111MODULE: "on"
- go 1.12 (off):
- go_version: "1.12"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
-
-- job: macOS
- pool:
- vmImage: "macOS-10.13"
- strategy:
- matrix:
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11.5"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11.5"
- GO111MODULE: "off"
- go 1.12 (on):
- go_version: "1.12"
- GO111MODULE: "on"
- go 1.12 (off):
- go_version: "1.12"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
-
-- job: Linux
- pool:
- vmImage: "ubuntu-16.04"
- strategy:
- matrix:
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11.5"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11.5"
- GO111MODULE: "off"
- go 1.12 (on):
- go_version: "1.12"
- GO111MODULE: "on"
- go 1.12 (off):
- go_version: "1.12"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
diff --git a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/azure-tests.yml b/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/azure-tests.yml
deleted file mode 100644
index eea5822fad5..00000000000
--- a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/azure-tests.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-steps:
- - task: GoTool@0
- inputs:
- version: $(go_version)
- - task: Bash@3
- inputs:
- targetType: inline
- script: |
- mkdir -p "$(GOBIN)"
- mkdir -p "$(GOPATH)/pkg"
- mkdir -p "$(modulePath)"
- shopt -s extglob
- mv !(gopath) "$(modulePath)"
- displayName: "Setup Go Workspace"
- - script: |
- go get -t -v ./...
- go test -race ./...
- workingDirectory: "$(modulePath)"
- displayName: "Tests"
diff --git a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/errx.go b/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/errx.go
deleted file mode 100644
index 5a6f6398c23..00000000000
--- a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/errx.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package errx
-
-// go2 errors
-type Wrapper interface {
- Unwrap() error
-}
-
-// pkg/errors
-type Causer interface {
- Cause() error
-}
-
-func Unwrap(err error) error {
- switch e := err.(type) {
- case Wrapper:
- return e.Unwrap()
- case Causer:
- return e.Cause()
- }
- return err
-}
-
-var Cause = Unwrap
diff --git a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/version.go b/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/version.go
deleted file mode 100644
index 82e25a1a957..00000000000
--- a/vendor/github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx/version.go
+++ /dev/null
@@ -1,4 +0,0 @@
-package errx
-
-// Version of errx
-const Version = "v1.0.0"
diff --git a/vendor/github.com/gobuffalo/packd/map.go b/vendor/github.com/gobuffalo/packd/map.go
deleted file mode 100644
index 906b49e3ea2..00000000000
--- a/vendor/github.com/gobuffalo/packd/map.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package packd
-
-import (
- "sort"
- "sync"
-)
-
-// ByteMap wraps sync.Map and uses the following types:
-// key: string
-// value: []byte
-type ByteMap struct {
- data sync.Map
-}
-
-// Delete the key from the map
-func (m *ByteMap) Delete(key string) {
- m.data.Delete(key)
-}
-
-// Load the key from the map.
-// Returns []byte or bool.
-// A false return indicates either the key was not found
-// or the value is not of type []byte
-func (m *ByteMap) Load(key string) ([]byte, bool) {
- i, ok := m.data.Load(key)
- if !ok {
- return []byte(``), false
- }
- s, ok := i.([]byte)
- return s, ok
-}
-
-// LoadOrStore will return an existing key or
-// store the value if not already in the map
-func (m *ByteMap) LoadOrStore(key string, value []byte) ([]byte, bool) {
- i, _ := m.data.LoadOrStore(key, value)
- s, ok := i.([]byte)
- return s, ok
-}
-
-// Range over the []byte values in the map
-func (m *ByteMap) Range(f func(key string, value []byte) bool) {
- m.data.Range(func(k, v interface{}) bool {
- key, ok := k.(string)
- if !ok {
- return false
- }
- value, ok := v.([]byte)
- if !ok {
- return false
- }
- return f(key, value)
- })
-}
-
-// Store a []byte in the map
-func (m *ByteMap) Store(key string, value []byte) {
- m.data.Store(key, value)
-}
-
-// Keys returns a list of keys in the map
-func (m *ByteMap) Keys() []string {
- var keys []string
- m.Range(func(key string, value []byte) bool {
- keys = append(keys, key)
- return true
- })
- sort.Strings(keys)
- return keys
-}
diff --git a/vendor/github.com/gobuffalo/packd/memory_box.go b/vendor/github.com/gobuffalo/packd/memory_box.go
deleted file mode 100644
index 7f3137cb44f..00000000000
--- a/vendor/github.com/gobuffalo/packd/memory_box.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package packd
-
-import (
- "bytes"
- "net/http"
- "os"
- "path/filepath"
- "sort"
- "strings"
-
- "github.com/gobuffalo/packd/internal/takeon/github.com/markbates/errx"
-)
-
-var _ Addable = NewMemoryBox()
-var _ Finder = NewMemoryBox()
-var _ Lister = NewMemoryBox()
-var _ HTTPBox = NewMemoryBox()
-var _ Haser = NewMemoryBox()
-var _ Walkable = NewMemoryBox()
-var _ Box = NewMemoryBox()
-
-// MemoryBox is a thread-safe, in-memory, implementation of the Box interface.
-type MemoryBox struct {
- files *ByteMap
-}
-
-func (m *MemoryBox) Has(path string) bool {
- _, ok := m.files.Load(path)
- return ok
-}
-
-func (m *MemoryBox) List() []string {
- var names []string
- m.files.Range(func(key string, value []byte) bool {
- names = append(names, key)
- return true
- })
-
- sort.Strings(names)
- return names
-}
-
-func (m *MemoryBox) Open(path string) (http.File, error) {
- cpath := strings.TrimPrefix(path, "/")
-
- if filepath.Ext(cpath) == "" {
- // it's a directory
- return NewDir(path)
- }
-
- if len(cpath) == 0 {
- cpath = "index.html"
- }
-
- b, err := m.Find(cpath)
- if err != nil {
- return nil, err
- }
-
- cpath = filepath.FromSlash(cpath)
-
- f, err := NewFile(cpath, bytes.NewReader(b))
- if err != nil {
- return nil, err
- }
- return f, nil
-}
-
-func (m *MemoryBox) FindString(path string) (string, error) {
- bb, err := m.Find(path)
- return string(bb), err
-}
-
-func (m *MemoryBox) Find(path string) (ret []byte, e error) {
- res, ok := m.files.Load(path)
- if !ok {
-
- var b []byte
- lpath := strings.ToLower(path)
- err := m.Walk(func(p string, file File) error {
- lp := strings.ToLower(p)
- if lp != lpath {
- return nil
- }
-
- res := file.String()
- b = []byte(res)
- return nil
- })
- if err != nil {
- return b, os.ErrNotExist
- }
- if len(b) == 0 {
- return b, os.ErrNotExist
- }
- return b, nil
- }
- return res, nil
-}
-
-func (m *MemoryBox) AddString(path string, t string) error {
- return m.AddBytes(path, []byte(t))
-}
-
-func (m *MemoryBox) AddBytes(path string, t []byte) error {
- m.files.Store(path, t)
- return nil
-}
-
-func (m *MemoryBox) Walk(wf WalkFunc) error {
- var err error
- m.files.Range(func(path string, b []byte) bool {
- var f File
- f, err = NewFile(path, bytes.NewReader(b))
- if err != nil {
- return false
- }
-
- err = wf(path, f)
- if err != nil {
- if errx.Unwrap(err) == filepath.SkipDir {
- err = nil
- return true
- }
- return false
- }
-
- return true
- })
-
- if errx.Unwrap(err) == filepath.SkipDir {
- return nil
- }
- return err
-}
-
-func (m *MemoryBox) WalkPrefix(pre string, wf WalkFunc) error {
- return m.Walk(func(path string, file File) error {
- if strings.HasPrefix(path, pre) {
- return wf(path, file)
- }
- return nil
- })
-}
-
-func (m *MemoryBox) Remove(path string) {
- m.files.Delete(path)
- m.files.Delete(strings.ToLower(path))
-}
-
-// NewMemoryBox returns a configured *MemoryBox
-func NewMemoryBox() *MemoryBox {
- return &MemoryBox{
- files: &ByteMap{},
- }
-}
diff --git a/vendor/github.com/gobuffalo/packd/skip_walker.go b/vendor/github.com/gobuffalo/packd/skip_walker.go
deleted file mode 100644
index 233c6dd6fb3..00000000000
--- a/vendor/github.com/gobuffalo/packd/skip_walker.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package packd
-
-import (
- "path/filepath"
- "strings"
-)
-
-var CommonSkipPrefixes = []string{".", "_", "node_modules", "vendor"}
-
-// SkipWalker will walk the Walker and call the WalkFunc for files who's directories
-// do no match any of the skipPrefixes. If no skipPrefixes are passed, then
-// CommonSkipPrefixes is used
-func SkipWalker(walker Walker, skipPrefixes []string, wf WalkFunc) error {
- if len(skipPrefixes) == 0 {
- skipPrefixes = append(skipPrefixes, CommonSkipPrefixes...)
- }
- return walker.Walk(func(path string, file File) error {
- fi, err := file.FileInfo()
- if err != nil {
- return err
- }
-
- path = strings.Replace(path, "\\", "/", -1)
-
- parts := strings.Split(path, "/")
- if !fi.IsDir() {
- parts = parts[:len(parts)-1]
- }
-
- for _, base := range parts {
- if base != "." {
- for _, skip := range skipPrefixes {
- skip = strings.ToLower(skip)
- lbase := strings.ToLower(base)
- if strings.HasPrefix(lbase, skip) {
- return filepath.SkipDir
- }
- }
- }
- }
- return wf(path, file)
- })
-}
diff --git a/vendor/github.com/gobuffalo/packd/version.go b/vendor/github.com/gobuffalo/packd/version.go
deleted file mode 100644
index 082aaef297b..00000000000
--- a/vendor/github.com/gobuffalo/packd/version.go
+++ /dev/null
@@ -1,4 +0,0 @@
-package packd
-
-// Version of packd
-const Version = "v0.3.0"
diff --git a/vendor/github.com/gobuffalo/packr/.codeclimate.yml b/vendor/github.com/gobuffalo/packr/.codeclimate.yml
deleted file mode 100644
index 8c914a509f0..00000000000
--- a/vendor/github.com/gobuffalo/packr/.codeclimate.yml
+++ /dev/null
@@ -1,20 +0,0 @@
----
-engines:
- golint:
- enabled: true
- checks:
- GoLint/Naming/MixedCaps:
- enabled: false
- govet:
- enabled: true
- gofmt:
- enabled: true
- fixme:
- enabled: true
-ratings:
- paths:
- - "**.go"
-exclude_paths:
- - "**/*_test.go"
- - "*_test.go"
- - "fixtures/"
diff --git a/vendor/github.com/gobuffalo/packr/.gitignore b/vendor/github.com/gobuffalo/packr/.gitignore
deleted file mode 100644
index 157ef96e308..00000000000
--- a/vendor/github.com/gobuffalo/packr/.gitignore
+++ /dev/null
@@ -1,36 +0,0 @@
-*.log
-./packr2
-.DS_Store
-doc
-tmp
-pkg
-*.gem
-*.pid
-coverage
-coverage.data
-build/*
-*.pbxuser
-*.mode1v3
-.svn
-profile
-.console_history
-.sass-cache/*
-.rake_tasks~
-*.log.lck
-solr/
-.jhw-cache/
-jhw.*
-*.sublime*
-node_modules/
-dist/
-generated/
-.vendor/
-bin/*
-gin-bin
-/packr_darwin_amd64
-/packr_linux_amd64
-.vscode/
-debug.test
-.grifter/
-*-packr.go
-
diff --git a/vendor/github.com/gobuffalo/packr/.gometalinter.json b/vendor/github.com/gobuffalo/packr/.gometalinter.json
deleted file mode 100644
index e4f65a36e82..00000000000
--- a/vendor/github.com/gobuffalo/packr/.gometalinter.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Enable": ["vet", "golint", "goimports", "deadcode", "gotype", "ineffassign", "misspell", "nakedret", "unconvert", "megacheck", "varcheck"]
-}
diff --git a/vendor/github.com/gobuffalo/packr/.goreleaser.yml b/vendor/github.com/gobuffalo/packr/.goreleaser.yml
deleted file mode 100644
index 288f4d5e4f7..00000000000
--- a/vendor/github.com/gobuffalo/packr/.goreleaser.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-# Code generated by github.com/gobuffalo/release. DO NOT EDIT.
-# Edit .goreleaser.yml.plush instead
-
-builds:
--
- goos:
- - darwin
- - linux
- - windows
- env:
- - CGO_ENABLED=0
- main: ./packr/main.go
- binary: packr
-
-checksum:
- name_template: 'checksums.txt'
-
-snapshot:
- name_template: "{{ .Tag }}-next"
-
-changelog:
- sort: asc
- filters:
- exclude:
- - '^docs:'
- - '^test:'
-
-brew:
- github:
- owner: gobuffalo
- name: homebrew-tap
-
diff --git a/vendor/github.com/gobuffalo/packr/.goreleaser.yml.plush b/vendor/github.com/gobuffalo/packr/.goreleaser.yml.plush
deleted file mode 100644
index 1d25c9a74aa..00000000000
--- a/vendor/github.com/gobuffalo/packr/.goreleaser.yml.plush
+++ /dev/null
@@ -1,29 +0,0 @@
-builds:
--
- goos:
- - darwin
- - linux
- - windows
- env:
- - CGO_ENABLED=0
- main: ./packr/main.go
- binary: packr
-
-checksum:
- name_template: 'checksums.txt'
-
-snapshot:
- name_template: "{{ .Tag }}-next"
-
-changelog:
- sort: asc
- filters:
- exclude:
- - '^docs:'
- - '^test:'
-<%= if (brew) { %>
-brew:
- github:
- owner: gobuffalo
- name: homebrew-tap
-<% } %>
diff --git a/vendor/github.com/gobuffalo/packr/LICENSE.txt b/vendor/github.com/gobuffalo/packr/LICENSE.txt
deleted file mode 100644
index 3ccb336a081..00000000000
--- a/vendor/github.com/gobuffalo/packr/LICENSE.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-The MIT License (MIT)
-Copyright (c) 2016 Mark Bates
-
-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.
diff --git a/vendor/github.com/gobuffalo/packr/Makefile b/vendor/github.com/gobuffalo/packr/Makefile
deleted file mode 100644
index b60c437dcf7..00000000000
--- a/vendor/github.com/gobuffalo/packr/Makefile
+++ /dev/null
@@ -1,64 +0,0 @@
-TAGS ?= "sqlite"
-GO_BIN ?= go
-
-install: deps
- echo "installing packr v1"
- packr
- $(GO_BIN) install -v ./packr
-
-tidy:
-ifeq ($(GO111MODULE),on)
- $(GO_BIN) mod tidy
-else
- echo skipping go mod tidy
-endif
-
-deps:
- rm -rf packrd
- rm -rf v2/packrd
- $(GO_BIN) get github.com/gobuffalo/release
- $(GO_BIN) get -tags ${TAGS} -t ./...
- $(GO_BIN) install -v ./packr
- packr clean
- make tidy
-
-build: deps
- packr
- $(GO_BIN) build -v .
- make tidy
-
-test:
- packr clean
- $(GO_BIN) test -tags ${TAGS} ./...
- packr clean
-
-ci-deps:
- rm -rf packrd
- rm -rf v2/packrd
- $(GO_BIN) get -tags ${TAGS} -t ./...
- $(GO_BIN) install -v ./packr
- packr clean
- make tidy
-
-ci-test:
- $(GO_BIN) test -v -tags ${TAGS} -race ./...
- make tidy
- cd ./v2 && make ci-test
-
-lint:
- gometalinter --vendor ./... --deadline=1m --skip=internal
-
-update:
- $(GO_BIN) get -u -tags ${TAGS}
- make tidy
- packr
- make test
- make install
- make tidy
-
-release-test:
- $(GO_BIN) test -tags ${TAGS} -race ./...
-
-release:
- release -y -f version.go
- make tidy
diff --git a/vendor/github.com/gobuffalo/packr/README.md b/vendor/github.com/gobuffalo/packr/README.md
deleted file mode 100644
index 89529f4de52..00000000000
--- a/vendor/github.com/gobuffalo/packr/README.md
+++ /dev/null
@@ -1,205 +0,0 @@
-# packr (v1)
-
-[![GoDoc](https://godoc.org/github.com/gobuffalo/packr?status.svg)](https://godoc.org/github.com/gobuffalo/packr)
-
-## Packr has been updated to `v2`! Please read the `./v2/README.md` file for more details.
-
----
-
-Packr is a simple solution for bundling static assets inside of Go binaries. Most importantly it does it in a way that is friendly to developers while they are developing.
-
-## Intro Video
-
-To get an idea of the what and why of packr, please enjoy this short video: [https://vimeo.com/219863271](https://vimeo.com/219863271).
-
-## Installation
-
-To install Packr utility
-
-```text
-$ go get -u github.com/gobuffalo/packr/packr
-```
-
-To get the dependency
-
-```text
-$ go get -u github.com/gobuffalo/packr
-```
-
-## Usage
-
-### In Code
-
-The first step in using Packr is to create a new box. A box represents a folder on disk. Once you have a box you can get `string` or `[]byte` representations of the file.
-
-```go
-// set up a new box by giving it a (relative) path to a folder on disk:
-box := packr.NewBox("./templates")
-
-// Get the string representation of a file, or an error if it doesn't exist:
-html, err := box.FindString("index.html")
-
-// Get the []byte representation of a file, or an error if it doesn't exist:
-html, err := box.FindBytes("index.html")
-```
-
-### What is a Box?
-
-A box represents a folder, and any sub-folders, on disk that you want to have access to in your binary. When compiling a binary using the `packr` CLI the contents of the folder will be converted into Go files that can be compiled inside of a "standard" go binary. Inside of the compiled binary the files will be read from memory. When working locally the files will be read directly off of disk. This is a seamless switch that doesn't require any special attention on your part.
-
-#### Example
-
-Assume the follow directory structure:
-
-```
-├── main.go
-└── templates
- ├── admin
- │  └── index.html
- └── index.html
-```
-
-The following program will read the `./templates/admin/index.html` file and print it out.
-
-```go
-package main
-
-import (
- "fmt"
-
- "github.com/gobuffalo/packr"
-)
-
-func main() {
- box := packr.NewBox("./templates")
-
- s, err := box.FindString("admin/index.html")
- if err != nil {
- log.Fatal(err)
- }
- fmt.Println(s)
-}
-```
-
-### Development Made Easy
-
-In order to get static files into a Go binary, those files must first be converted to Go code. To do that, Packr, ships with a few tools to help build binaries. See below.
-
-During development, however, it is painful to have to keep running a tool to compile those files.
-
-Packr uses the following resolution rules when looking for a file:
-
-1. Look for the file in-memory (inside a Go binary)
-1. Look for the file on disk (during development)
-
-Because Packr knows how to fall through to the file system, developers don't need to worry about constantly compiling their static files into a binary. They can work unimpeded.
-
-Packr takes file resolution a step further. When declaring a new box you use a relative path, `./templates`. When Packr receives this call it calculates out the absolute path to that directory. By doing this it means you can be guaranteed that Packr can find your files correctly, even if you're not running in the directory that the box was created in. This helps with the problem of testing, where Go changes the `pwd` for each package, making relative paths difficult to work with. This is not a problem when using Packr.
-
----
-
-## Usage with HTTP
-
-A box implements the [`http.FileSystem`](https://golang.org/pkg/net/http/#FileSystem) interface, meaning it can be used to serve static files.
-
-```go
-package main
-
-import (
- "net/http"
-
- "github.com/gobuffalo/packr"
-)
-
-func main() {
- box := packr.NewBox("./templates")
-
- http.Handle("/", http.FileServer(box))
- http.ListenAndServe(":3000", nil)
-}
-```
-
----
-
-## Building a Binary (the easy way)
-
-When it comes time to build, or install, your Go binary, simply use `packr build` or `packr install` just as you would `go build` or `go install`. All flags for the `go` tool are supported and everything works the way you expect, the only difference is your static assets are now bundled in the generated binary. If you want more control over how this happens, looking at the following section on building binaries (the hard way).
-
-## Building a Binary (the hard way)
-
-Before you build your Go binary, run the `packr` command first. It will look for all the boxes in your code and then generate `.go` files that pack the static files into bytes that can be bundled into the Go binary.
-
-```
-$ packr
-```
-
-Then run your `go build command` like normal.
-
-*NOTE*: It is not recommended to check-in these generated `-packr.go` files. They can be large, and can easily become out of date if not careful. It is recommended that you always run `packr clean` after running the `packr` tool.
-
-#### Cleaning Up
-
-When you're done it is recommended that you run the `packr clean` command. This will remove all of the generated files that Packr created for you.
-
-```
-$ packr clean
-```
-
-Why do you want to do this? Packr first looks to the information stored in these generated files, if the information isn't there it looks to disk. This makes it easy to work with in development.
-
----
-
-## Building/Moving a portable release
-
-When it comes to building multiple releases you typically want that release to be built in a specific directory.
-
-For example: `./releases`
-
-However, because passing a `.go` file requires absolute paths, we must compile the release in the appropriate absolute path.
-
-```bash
-GOOS=linux GOARCH=amd64 packr build
-```
-
-Now your `project_name` binary will be built at the root of your project dir. Great!
-
-All that is left to do is to move that binary to your release dir:
-
-Linux/macOS/Windows (bash)
-
-```bash
-mv ./project_name ./releases
-```
-
-Windows (cmd):
-
-```cmd
-move ./project_name ./releases
-```
-
-Powershell:
-
-```powershell
-Move-Item -Path .\project_name -Destination .\releases\
-```
-
-If you _target_ for Windows when building don't forget that it's `project_name.exe`
-
-Now you can make multiple releases and all of your needed static files will be available!
-
-#### Summing it up:
-
-Example Script for building to 3 common targets:
-
-```bash
-GOOS=darwin GOARCH=amd64 packr build && mv ./project_name ./releases/darwin-project_name \
- && GOOS=linux GOARCH=amd64 packr build && mv ./project_name ./releases/linux-project_name \
- && GOOS=windows GOARCH=386 packr build && mv ./project_name.exe ./releases/project_name.exe \
- && packr clean
-```
-
----
-
-## Debugging
-
-The `packr` command passes all arguments down to the underlying `go` command, this includes the `-v` flag to print out `go build` information. Packr looks for the `-v` flag, and will turn on its own verbose logging. This is very useful for trying to understand what the `packr` command is doing when it is run.
diff --git a/vendor/github.com/gobuffalo/packr/SHOULDERS.md b/vendor/github.com/gobuffalo/packr/SHOULDERS.md
deleted file mode 100644
index 26900074dde..00000000000
--- a/vendor/github.com/gobuffalo/packr/SHOULDERS.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# github.com/gobuffalo/packr Stands on the Shoulders of Giants
-
-github.com/gobuffalo/packr does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work.
-
-Thank you to the following **GIANTS**:
-
-
-* [github.com/gobuffalo/envy](https://godoc.org/github.com/gobuffalo/envy)
-
-* [github.com/gobuffalo/packd](https://godoc.org/github.com/gobuffalo/packd)
-
-* [github.com/gobuffalo/packr/v2](https://godoc.org/github.com/gobuffalo/packr/v2)
-
-* [github.com/spf13/cobra](https://godoc.org/github.com/spf13/cobra)
-
-* [github.com/stretchr/testify](https://godoc.org/github.com/stretchr/testify)
-
-* [golang.org/x/sync](https://godoc.org/golang.org/x/sync)
diff --git a/vendor/github.com/gobuffalo/packr/azure-pipelines.yml b/vendor/github.com/gobuffalo/packr/azure-pipelines.yml
deleted file mode 100644
index 417e2c57921..00000000000
--- a/vendor/github.com/gobuffalo/packr/azure-pipelines.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-variables:
- GOBIN: "$(GOPATH)/bin" # Go binaries path
- GOPATH: "$(system.defaultWorkingDirectory)/gopath" # Go workspace path
- modulePath: "$(GOPATH)/src/github.com/$(build.repository.name)" # Path to the module"s code
-
-jobs:
-- job: Windows
- pool:
- vmImage: "vs2017-win2016"
- strategy:
- matrix:
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11.5"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11.5"
- GO111MODULE: "off"
- go 1.12 (on):
- go_version: "1.12"
- GO111MODULE: "on"
- go 1.12 (off):
- go_version: "1.12"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
-
-- job: macOS
- pool:
- vmImage: "macOS-10.13"
- strategy:
- matrix:
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11.5"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11.5"
- GO111MODULE: "off"
- go 1.12 (on):
- go_version: "1.12"
- GO111MODULE: "on"
- go 1.12 (off):
- go_version: "1.12"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
-
-- job: Linux
- pool:
- vmImage: "ubuntu-16.04"
- strategy:
- matrix:
- go 1.10:
- go_version: "1.10"
- go 1.11 (on):
- go_version: "1.11.5"
- GO111MODULE: "on"
- go 1.11 (off):
- go_version: "1.11.5"
- GO111MODULE: "off"
- go 1.12 (on):
- go_version: "1.12"
- GO111MODULE: "on"
- go 1.12 (off):
- go_version: "1.12"
- GO111MODULE: "off"
- steps:
- - template: azure-tests.yml
diff --git a/vendor/github.com/gobuffalo/packr/azure-tests.yml b/vendor/github.com/gobuffalo/packr/azure-tests.yml
deleted file mode 100644
index 58300d13c38..00000000000
--- a/vendor/github.com/gobuffalo/packr/azure-tests.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-steps:
- - task: GoTool@0
- inputs:
- version: $(go_version)
- - task: Bash@3
- inputs:
- targetType: inline
- script: |
- mkdir -p "$(GOBIN)"
- mkdir -p "$(GOPATH)/pkg"
- mkdir -p "$(modulePath)"
- shopt -s extglob
- mv !(gopath) "$(modulePath)"
- displayName: "Setup Go Workspace"
- - script: |
- go get -t -v ./...
- go test -race ./...
- go install -v ./packr
- cd v2
- go get -t -v ./...
- go test -race ./...
- go install -v ./packr2
- workingDirectory: "$(modulePath)"
- displayName: "Tests"
diff --git a/vendor/github.com/gobuffalo/packr/box.go b/vendor/github.com/gobuffalo/packr/box.go
deleted file mode 100644
index 4922ebbe8b4..00000000000
--- a/vendor/github.com/gobuffalo/packr/box.go
+++ /dev/null
@@ -1,228 +0,0 @@
-package packr
-
-import (
- "bytes"
- "compress/gzip"
- "fmt"
- "io/ioutil"
- "net/http"
- "os"
- "path"
- "path/filepath"
- "runtime"
- "strings"
-
- "github.com/gobuffalo/packd"
-)
-
-var (
- // ErrResOutsideBox gets returned in case of the requested resources being outside the box
- ErrResOutsideBox = fmt.Errorf("Can't find a resource outside the box")
-)
-
-var _ packd.Box = Box{}
-var _ packd.HTTPBox = Box{}
-var _ packd.Lister = Box{}
-var _ packd.Addable = Box{}
-var _ packd.Walkable = Box{}
-var _ packd.Finder = Box{}
-var _ packd.LegacyBox = Box{}
-
-// NewBox returns a Box that can be used to
-// retrieve files from either disk or the embedded
-// binary.
-func NewBox(path string) Box {
- var cd string
- if !filepath.IsAbs(path) {
- _, filename, _, _ := runtime.Caller(1)
- cd = filepath.Dir(filename)
- }
-
- // this little hack courtesy of the `-cover` flag!!
- cov := filepath.Join("_test", "_obj_test")
- cd = strings.Replace(cd, string(filepath.Separator)+cov, "", 1)
- if !filepath.IsAbs(cd) && cd != "" {
- cd = filepath.Join(GoPath(), "src", cd)
- }
-
- return Box{
- Path: path,
- callingDir: cd,
- data: map[string][]byte{},
- }
-}
-
-// Box represent a folder on a disk you want to
-// have access to in the built Go binary.
-type Box struct {
- Path string
- callingDir string
- data map[string][]byte
- directories map[string]bool
-}
-
-// AddString converts t to a byteslice and delegates to AddBytes to add to b.data
-func (b Box) AddString(path string, t string) error {
- b.AddBytes(path, []byte(t))
- return nil
-}
-
-// AddBytes sets t in b.data by the given path
-func (b Box) AddBytes(path string, t []byte) error {
- b.data[path] = t
- return nil
-}
-
-// Deprecated: Use FindString instead.
-func (b Box) String(name string) string {
- bb, _ := b.FindString(name)
- return bb
-}
-
-// Deprecated: Use FindString instead.
-func (b Box) MustString(name string) (string, error) {
- return b.FindString(name)
-}
-
-// Deprecated: Use Find instead.
-func (b Box) Bytes(name string) []byte {
- bb, _ := b.Find(name)
- return bb
-}
-
-// Deprecated: Use Find instead.
-func (b Box) MustBytes(name string) ([]byte, error) {
- return b.Find(name)
-}
-
-// FindString returns either the string of the requested
-// file or an error if it can not be found.
-func (b Box) FindString(name string) (string, error) {
- bb, err := b.Find(name)
- return string(bb), err
-}
-
-// Find returns either the byte slice of the requested
-// file or an error if it can not be found.
-func (b Box) Find(name string) ([]byte, error) {
- f, err := b.find(name)
- if err == nil {
- bb := &bytes.Buffer{}
- bb.ReadFrom(f)
- return bb.Bytes(), err
- }
- return nil, err
-}
-
-// Has returns true if the resource exists in the box
-func (b Box) Has(name string) bool {
- _, err := b.find(name)
- if err != nil {
- return false
- }
- return true
-}
-
-func (b Box) decompress(bb []byte) []byte {
- reader, err := gzip.NewReader(bytes.NewReader(bb))
- if err != nil {
- return bb
- }
- defer reader.Close()
-
- data, err := ioutil.ReadAll(reader)
- if err != nil {
- return bb
- }
- return data
-}
-
-func (b Box) find(name string) (File, error) {
- if bb, ok := b.data[name]; ok {
- return packd.NewFile(name, bytes.NewReader(bb))
- }
-
- if b.directories == nil {
- b.indexDirectories()
- }
-
- cleanName := filepath.ToSlash(filepath.Clean(name))
- // Ensure name is not outside the box
- if strings.HasPrefix(cleanName, "../") {
- return nil, ErrResOutsideBox
- }
- // Absolute name is considered as relative to the box root
- cleanName = strings.TrimPrefix(cleanName, "/")
-
- if _, ok := data[b.Path]; ok {
- if bb, ok := data[b.Path][cleanName]; ok {
- bb = b.decompress(bb)
- return packd.NewFile(cleanName, bytes.NewReader(bb))
- }
- if _, ok := b.directories[cleanName]; ok {
- return packd.NewDir(cleanName)
- }
- if filepath.Ext(cleanName) != "" {
- // The Handler created by http.FileSystem checks for those errors and
- // returns http.StatusNotFound instead of http.StatusInternalServerError.
- return nil, os.ErrNotExist
- }
- return nil, os.ErrNotExist
- }
-
- // Not found in the box virtual fs, try to get it from the file system
- cleanName = filepath.FromSlash(cleanName)
- p := filepath.Join(b.callingDir, b.Path, cleanName)
- return fileFor(p, cleanName)
-}
-
-// Open returns a File using the http.File interface
-func (b Box) Open(name string) (http.File, error) {
- return b.find(name)
-}
-
-// List shows "What's in the box?"
-func (b Box) List() []string {
- var keys []string
-
- if b.data == nil || len(b.data) == 0 {
- b.Walk(func(path string, info File) error {
- finfo, _ := info.FileInfo()
- if !finfo.IsDir() {
- keys = append(keys, finfo.Name())
- }
- return nil
- })
- } else {
- for k := range b.data {
- keys = append(keys, k)
- }
- }
- return keys
-}
-
-func (b *Box) indexDirectories() {
- b.directories = map[string]bool{}
- if _, ok := data[b.Path]; ok {
- for name := range data[b.Path] {
- prefix, _ := path.Split(name)
- // Even on Windows the suffix appears to be a /
- prefix = strings.TrimSuffix(prefix, "/")
- b.directories[prefix] = true
- }
- }
-}
-
-func fileFor(p string, name string) (File, error) {
- fi, err := os.Stat(p)
- if err != nil {
- return nil, err
- }
- if fi.IsDir() {
- return packd.NewDir(p)
- }
- if bb, err := ioutil.ReadFile(p); err == nil {
- return packd.NewFile(name, bytes.NewReader(bb))
- }
- return nil, os.ErrNotExist
-}
diff --git a/vendor/github.com/gobuffalo/packr/env.go b/vendor/github.com/gobuffalo/packr/env.go
deleted file mode 100644
index 8ec70b56e07..00000000000
--- a/vendor/github.com/gobuffalo/packr/env.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package packr
-
-import (
- "github.com/gobuffalo/envy"
-)
-
-// GoPath returns the current GOPATH env var
-// or if it's missing, the default.
-var GoPath = envy.GoPath
-
-// GoBin returns the current GO_BIN env var
-// or if it's missing, a default of "go"
-var GoBin = envy.GoBin
diff --git a/vendor/github.com/gobuffalo/packr/file.go b/vendor/github.com/gobuffalo/packr/file.go
deleted file mode 100644
index 8d24b7303cb..00000000000
--- a/vendor/github.com/gobuffalo/packr/file.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package packr
-
-import "github.com/gobuffalo/packd"
-
-type File = packd.File
diff --git a/vendor/github.com/gobuffalo/packr/go.mod b/vendor/github.com/gobuffalo/packr/go.mod
deleted file mode 100644
index a8281f3a13d..00000000000
--- a/vendor/github.com/gobuffalo/packr/go.mod
+++ /dev/null
@@ -1,12 +0,0 @@
-module github.com/gobuffalo/packr
-
-go 1.12
-
-require (
- github.com/gobuffalo/envy v1.7.0
- github.com/gobuffalo/packd v0.3.0
- github.com/gobuffalo/packr/v2 v2.5.1
- github.com/spf13/cobra v0.0.5
- github.com/stretchr/testify v1.3.0
- golang.org/x/sync v0.0.0-20190423024810-112230192c58
-)
diff --git a/vendor/github.com/gobuffalo/packr/go.sum b/vendor/github.com/gobuffalo/packr/go.sum
deleted file mode 100644
index 162813101d6..00000000000
--- a/vendor/github.com/gobuffalo/packr/go.sum
+++ /dev/null
@@ -1,79 +0,0 @@
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
-github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
-github.com/gobuffalo/logger v1.0.0 h1:xw9Ko9EcC5iAFprrjJ6oZco9UpzS5MQ4jAwghsLHdy4=
-github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
-github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
-github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
-github.com/gobuffalo/packr/v2 v2.5.1 h1:TFOeY2VoGamPjQLiNDT3mn//ytzk236VMO2j7iHxJR4=
-github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
-github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU=
-github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
-golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190515120540-06a5c4944438 h1:khxRGsvPk4n2y8I/mLLjp7e5dMTJmH75wvqS6nMwUtY=
-golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c h1:KfpJVdWhuRqNk4XVXzjXf2KAV4TBEP77SYdFGjeGuIE=
-golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/github.com/gobuffalo/packr/packr.go b/vendor/github.com/gobuffalo/packr/packr.go
deleted file mode 100644
index 6ccc6c15ca5..00000000000
--- a/vendor/github.com/gobuffalo/packr/packr.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package packr
-
-import (
- "bytes"
- "compress/gzip"
- "encoding/json"
- "runtime"
- "strings"
- "sync"
-)
-
-var gil = &sync.Mutex{}
-var data = map[string]map[string][]byte{}
-
-// PackBytes packs bytes for a file into a box.
-func PackBytes(box string, name string, bb []byte) {
- gil.Lock()
- defer gil.Unlock()
- if _, ok := data[box]; !ok {
- data[box] = map[string][]byte{}
- }
- data[box][name] = bb
-}
-
-// PackBytesGzip packets the gzipped compressed bytes into a box.
-func PackBytesGzip(box string, name string, bb []byte) error {
- var buf bytes.Buffer
- w := gzip.NewWriter(&buf)
- _, err := w.Write(bb)
- if err != nil {
- return err
- }
- err = w.Close()
- if err != nil {
- return err
- }
- PackBytes(box, name, buf.Bytes())
- return nil
-}
-
-// PackJSONBytes packs JSON encoded bytes for a file into a box.
-func PackJSONBytes(box string, name string, jbb string) error {
- var bb []byte
- err := json.Unmarshal([]byte(jbb), &bb)
- if err != nil {
- return err
- }
- PackBytes(box, name, bb)
- return nil
-}
-
-// UnpackBytes unpacks bytes for specific box.
-func UnpackBytes(box string) {
- gil.Lock()
- defer gil.Unlock()
- delete(data, box)
-}
-
-func osPaths(paths ...string) []string {
- if runtime.GOOS == "windows" {
- for i, path := range paths {
- paths[i] = strings.Replace(path, "/", "\\", -1)
- }
- }
-
- return paths
-}
-
-func osPath(path string) string {
- if runtime.GOOS == "windows" {
- return strings.Replace(path, "/", "\\", -1)
- }
- return path
-}
diff --git a/vendor/github.com/gobuffalo/packr/version.go b/vendor/github.com/gobuffalo/packr/version.go
deleted file mode 100644
index bf736a7014f..00000000000
--- a/vendor/github.com/gobuffalo/packr/version.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package packr
-
-const Version = "v1.30.1"
diff --git a/vendor/github.com/gobuffalo/packr/walk.go b/vendor/github.com/gobuffalo/packr/walk.go
deleted file mode 100644
index f03f19626ff..00000000000
--- a/vendor/github.com/gobuffalo/packr/walk.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package packr
-
-import (
- "os"
- "path/filepath"
- "strings"
-
- "github.com/gobuffalo/packd"
-)
-
-type WalkFunc = packd.WalkFunc
-
-// Walk will traverse the box and call the WalkFunc for each file in the box/folder.
-func (b Box) Walk(wf WalkFunc) error {
- if data[b.Path] == nil {
- base, err := filepath.EvalSymlinks(filepath.Join(b.callingDir, b.Path))
- if err != nil {
- return err
- }
- return filepath.Walk(base, func(path string, info os.FileInfo, err error) error {
- cleanName, err := filepath.Rel(base, path)
- if err != nil {
- cleanName = strings.TrimPrefix(path, base)
- }
- cleanName = filepath.ToSlash(filepath.Clean(cleanName))
- cleanName = strings.TrimPrefix(cleanName, "/")
- cleanName = filepath.FromSlash(cleanName)
- if info == nil || info.IsDir() {
- return nil
- }
-
- file, err := fileFor(path, cleanName)
- if err != nil {
- return err
- }
- return wf(cleanName, file)
- })
- }
- for n := range data[b.Path] {
- f, err := b.find(n)
- if err != nil {
- return err
- }
- err = wf(n, f)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-// WalkPrefix will call box.Walk and call the WalkFunc when it finds paths that have a matching prefix
-func (b Box) WalkPrefix(prefix string, wf WalkFunc) error {
- opre := osPath(prefix)
- return b.Walk(func(path string, f File) error {
- if strings.HasPrefix(osPath(path), opre) {
- if err := wf(path, f); err != nil {
- return err
- }
- }
- return nil
- })
-}
diff --git a/vendor/github.com/gobwas/httphead/LICENSE b/vendor/github.com/gobwas/httphead/LICENSE
deleted file mode 100644
index 274431766fa..00000000000
--- a/vendor/github.com/gobwas/httphead/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2017 Sergey Kamardin
-
-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.
diff --git a/vendor/github.com/gobwas/httphead/README.md b/vendor/github.com/gobwas/httphead/README.md
deleted file mode 100644
index 67a97fdbe92..00000000000
--- a/vendor/github.com/gobwas/httphead/README.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# httphead.[go](https://golang.org)
-
-[![GoDoc][godoc-image]][godoc-url]
-
-> Tiny HTTP header value parsing library in go.
-
-## Overview
-
-This library contains low-level functions for scanning HTTP RFC2616 compatible header value grammars.
-
-## Install
-
-```shell
- go get github.com/gobwas/httphead
-```
-
-## Example
-
-The example below shows how multiple-choise HTTP header value could be parsed with this library:
-
-```go
- options, ok := httphead.ParseOptions([]byte(`foo;bar=1,baz`), nil)
- fmt.Println(options, ok)
- // Output: [{foo map[bar:1]} {baz map[]}] true
-```
-
-The low-level example below shows how to optimize keys skipping and selection
-of some key:
-
-```go
- // The right part of full header line like:
- // X-My-Header: key;foo=bar;baz,key;baz
- header := []byte(`foo;a=0,foo;a=1,foo;a=2,foo;a=3`)
-
- // We want to search key "foo" with an "a" parameter that equal to "2".
- var (
- foo = []byte(`foo`)
- a = []byte(`a`)
- v = []byte(`2`)
- )
- var found bool
- httphead.ScanOptions(header, func(i int, key, param, value []byte) Control {
- if !bytes.Equal(key, foo) {
- return ControlSkip
- }
- if !bytes.Equal(param, a) {
- if bytes.Equal(value, v) {
- // Found it!
- found = true
- return ControlBreak
- }
- return ControlSkip
- }
- return ControlContinue
- })
-```
-
-For more usage examples please see [docs][godoc-url] or package tests.
-
-[godoc-image]: https://godoc.org/github.com/gobwas/httphead?status.svg
-[godoc-url]: https://godoc.org/github.com/gobwas/httphead
-[travis-image]: https://travis-ci.org/gobwas/httphead.svg?branch=master
-[travis-url]: https://travis-ci.org/gobwas/httphead
diff --git a/vendor/github.com/gobwas/httphead/cookie.go b/vendor/github.com/gobwas/httphead/cookie.go
deleted file mode 100644
index 05c9a1fb6a1..00000000000
--- a/vendor/github.com/gobwas/httphead/cookie.go
+++ /dev/null
@@ -1,200 +0,0 @@
-package httphead
-
-import (
- "bytes"
-)
-
-// ScanCookie scans cookie pairs from data using DefaultCookieScanner.Scan()
-// method.
-func ScanCookie(data []byte, it func(key, value []byte) bool) bool {
- return DefaultCookieScanner.Scan(data, it)
-}
-
-// DefaultCookieScanner is a CookieScanner which is used by ScanCookie().
-// Note that it is intended to have the same behavior as http.Request.Cookies()
-// has.
-var DefaultCookieScanner = CookieScanner{}
-
-// CookieScanner contains options for scanning cookie pairs.
-// See https://tools.ietf.org/html/rfc6265#section-4.1.1
-type CookieScanner struct {
- // DisableNameValidation disables name validation of a cookie. If false,
- // only RFC2616 "tokens" are accepted.
- DisableNameValidation bool
-
- // DisableValueValidation disables value validation of a cookie. If false,
- // only RFC6265 "cookie-octet" characters are accepted.
- //
- // Note that Strict option also affects validation of a value.
- //
- // If Strict is false, then scanner begins to allow space and comma
- // characters inside the value for better compatibility with non standard
- // cookies implementations.
- DisableValueValidation bool
-
- // BreakOnPairError sets scanner to immediately return after first pair syntax
- // validation error.
- // If false, scanner will try to skip invalid pair bytes and go ahead.
- BreakOnPairError bool
-
- // Strict enables strict RFC6265 mode scanning. It affects name and value
- // validation, as also some other rules.
- // If false, it is intended to bring the same behavior as
- // http.Request.Cookies().
- Strict bool
-}
-
-// Scan maps data to name and value pairs. Usually data represents value of the
-// Cookie header.
-func (c CookieScanner) Scan(data []byte, it func(name, value []byte) bool) bool {
- lexer := &Scanner{data: data}
-
- const (
- statePair = iota
- stateBefore
- )
-
- state := statePair
-
- for lexer.Buffered() > 0 {
- switch state {
- case stateBefore:
- // Pairs separated by ";" and space, according to the RFC6265:
- // cookie-pair *( ";" SP cookie-pair )
- //
- // Cookie pairs MUST be separated by (";" SP). So our only option
- // here is to fail as syntax error.
- a, b := lexer.Peek2()
- if a != ';' {
- return false
- }
-
- state = statePair
-
- advance := 1
- if b == ' ' {
- advance++
- } else if c.Strict {
- return false
- }
-
- lexer.Advance(advance)
-
- case statePair:
- if !lexer.FetchUntil(';') {
- return false
- }
-
- var value []byte
- name := lexer.Bytes()
- if i := bytes.IndexByte(name, '='); i != -1 {
- value = name[i+1:]
- name = name[:i]
- } else if c.Strict {
- if !c.BreakOnPairError {
- goto nextPair
- }
- return false
- }
-
- if !c.Strict {
- trimLeft(name)
- }
- if !c.DisableNameValidation && !ValidCookieName(name) {
- if !c.BreakOnPairError {
- goto nextPair
- }
- return false
- }
-
- if !c.Strict {
- value = trimRight(value)
- }
- value = stripQuotes(value)
- if !c.DisableValueValidation && !ValidCookieValue(value, c.Strict) {
- if !c.BreakOnPairError {
- goto nextPair
- }
- return false
- }
-
- if !it(name, value) {
- return true
- }
-
- nextPair:
- state = stateBefore
- }
- }
-
- return true
-}
-
-// ValidCookieValue reports whether given value is a valid RFC6265
-// "cookie-octet" bytes.
-//
-// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
-// ; US-ASCII characters excluding CTLs,
-// ; whitespace DQUOTE, comma, semicolon,
-// ; and backslash
-//
-// Note that the false strict parameter disables errors on space 0x20 and comma
-// 0x2c. This could be useful to bring some compatibility with non-compliant
-// clients/servers in the real world.
-// It acts the same as standard library cookie parser if strict is false.
-func ValidCookieValue(value []byte, strict bool) bool {
- if len(value) == 0 {
- return true
- }
- for _, c := range value {
- switch c {
- case '"', ';', '\\':
- return false
- case ',', ' ':
- if strict {
- return false
- }
- default:
- if c <= 0x20 {
- return false
- }
- if c >= 0x7f {
- return false
- }
- }
- }
- return true
-}
-
-// ValidCookieName reports wheter given bytes is a valid RFC2616 "token" bytes.
-func ValidCookieName(name []byte) bool {
- for _, c := range name {
- if !OctetTypes[c].IsToken() {
- return false
- }
- }
- return true
-}
-
-func stripQuotes(bts []byte) []byte {
- if last := len(bts) - 1; last > 0 && bts[0] == '"' && bts[last] == '"' {
- return bts[1:last]
- }
- return bts
-}
-
-func trimLeft(p []byte) []byte {
- var i int
- for i < len(p) && OctetTypes[p[i]].IsSpace() {
- i++
- }
- return p[i:]
-}
-
-func trimRight(p []byte) []byte {
- j := len(p)
- for j > 0 && OctetTypes[p[j-1]].IsSpace() {
- j--
- }
- return p[:j]
-}
diff --git a/vendor/github.com/gobwas/httphead/head.go b/vendor/github.com/gobwas/httphead/head.go
deleted file mode 100644
index a50e907dd18..00000000000
--- a/vendor/github.com/gobwas/httphead/head.go
+++ /dev/null
@@ -1,275 +0,0 @@
-package httphead
-
-import (
- "bufio"
- "bytes"
-)
-
-// Version contains protocol major and minor version.
-type Version struct {
- Major int
- Minor int
-}
-
-// RequestLine contains parameters parsed from the first request line.
-type RequestLine struct {
- Method []byte
- URI []byte
- Version Version
-}
-
-// ResponseLine contains parameters parsed from the first response line.
-type ResponseLine struct {
- Version Version
- Status int
- Reason []byte
-}
-
-// SplitRequestLine splits given slice of bytes into three chunks without
-// parsing.
-func SplitRequestLine(line []byte) (method, uri, version []byte) {
- return split3(line, ' ')
-}
-
-// ParseRequestLine parses http request line like "GET / HTTP/1.0".
-func ParseRequestLine(line []byte) (r RequestLine, ok bool) {
- var i int
- for i = 0; i < len(line); i++ {
- c := line[i]
- if !OctetTypes[c].IsToken() {
- if i > 0 && c == ' ' {
- break
- }
- return
- }
- }
- if i == len(line) {
- return
- }
-
- var proto []byte
- r.Method = line[:i]
- r.URI, proto = split2(line[i+1:], ' ')
- if len(r.URI) == 0 {
- return
- }
- if major, minor, ok := ParseVersion(proto); ok {
- r.Version.Major = major
- r.Version.Minor = minor
- return r, true
- }
-
- return r, false
-}
-
-// SplitResponseLine splits given slice of bytes into three chunks without
-// parsing.
-func SplitResponseLine(line []byte) (version, status, reason []byte) {
- return split3(line, ' ')
-}
-
-// ParseResponseLine parses first response line into ResponseLine struct.
-func ParseResponseLine(line []byte) (r ResponseLine, ok bool) {
- var (
- proto []byte
- status []byte
- )
- proto, status, r.Reason = split3(line, ' ')
- if major, minor, ok := ParseVersion(proto); ok {
- r.Version.Major = major
- r.Version.Minor = minor
- } else {
- return r, false
- }
- if n, ok := IntFromASCII(status); ok {
- r.Status = n
- } else {
- return r, false
- }
- // TODO(gobwas): parse here r.Reason fot TEXT rule:
- // TEXT =
- return r, true
-}
-
-var (
- httpVersion10 = []byte("HTTP/1.0")
- httpVersion11 = []byte("HTTP/1.1")
- httpVersionPrefix = []byte("HTTP/")
-)
-
-// ParseVersion parses major and minor version of HTTP protocol.
-// It returns parsed values and true if parse is ok.
-func ParseVersion(bts []byte) (major, minor int, ok bool) {
- switch {
- case bytes.Equal(bts, httpVersion11):
- return 1, 1, true
- case bytes.Equal(bts, httpVersion10):
- return 1, 0, true
- case len(bts) < 8:
- return
- case !bytes.Equal(bts[:5], httpVersionPrefix):
- return
- }
-
- bts = bts[5:]
-
- dot := bytes.IndexByte(bts, '.')
- if dot == -1 {
- return
- }
- major, ok = IntFromASCII(bts[:dot])
- if !ok {
- return
- }
- minor, ok = IntFromASCII(bts[dot+1:])
- if !ok {
- return
- }
-
- return major, minor, true
-}
-
-// ReadLine reads line from br. It reads until '\n' and returns bytes without
-// '\n' or '\r\n' at the end.
-// It returns err if and only if line does not end in '\n'. Note that read
-// bytes returned in any case of error.
-//
-// It is much like the textproto/Reader.ReadLine() except the thing that it
-// returns raw bytes, instead of string. That is, it avoids copying bytes read
-// from br.
-//
-// textproto/Reader.ReadLineBytes() is also makes copy of resulting bytes to be
-// safe with future I/O operations on br.
-//
-// We could control I/O operations on br and do not need to make additional
-// copy for safety.
-func ReadLine(br *bufio.Reader) ([]byte, error) {
- var line []byte
- for {
- bts, err := br.ReadSlice('\n')
- if err == bufio.ErrBufferFull {
- // Copy bytes because next read will discard them.
- line = append(line, bts...)
- continue
- }
- // Avoid copy of single read.
- if line == nil {
- line = bts
- } else {
- line = append(line, bts...)
- }
- if err != nil {
- return line, err
- }
- // Size of line is at least 1.
- // In other case bufio.ReadSlice() returns error.
- n := len(line)
- // Cut '\n' or '\r\n'.
- if n > 1 && line[n-2] == '\r' {
- line = line[:n-2]
- } else {
- line = line[:n-1]
- }
- return line, nil
- }
-}
-
-// ParseHeaderLine parses HTTP header as key-value pair. It returns parsed
-// values and true if parse is ok.
-func ParseHeaderLine(line []byte) (k, v []byte, ok bool) {
- colon := bytes.IndexByte(line, ':')
- if colon == -1 {
- return
- }
- k = trim(line[:colon])
- for _, c := range k {
- if !OctetTypes[c].IsToken() {
- return nil, nil, false
- }
- }
- v = trim(line[colon+1:])
- return k, v, true
-}
-
-// IntFromASCII converts ascii encoded decimal numeric value from HTTP entities
-// to an integer.
-func IntFromASCII(bts []byte) (ret int, ok bool) {
- // ASCII numbers all start with the high-order bits 0011.
- // If you see that, and the next bits are 0-9 (0000 - 1001) you can grab those
- // bits and interpret them directly as an integer.
- var n int
- if n = len(bts); n < 1 {
- return 0, false
- }
- for i := 0; i < n; i++ {
- if bts[i]&0xf0 != 0x30 {
- return 0, false
- }
- ret += int(bts[i]&0xf) * pow(10, n-i-1)
- }
- return ret, true
-}
-
-const (
- toLower = 'a' - 'A' // for use with OR.
- toUpper = ^byte(toLower) // for use with AND.
-)
-
-// CanonicalizeHeaderKey is like standard textproto/CanonicalMIMEHeaderKey,
-// except that it operates with slice of bytes and modifies it inplace without
-// copying.
-func CanonicalizeHeaderKey(k []byte) {
- upper := true
- for i, c := range k {
- if upper && 'a' <= c && c <= 'z' {
- k[i] &= toUpper
- } else if !upper && 'A' <= c && c <= 'Z' {
- k[i] |= toLower
- }
- upper = c == '-'
- }
-}
-
-// pow for integers implementation.
-// See Donald Knuth, The Art of Computer Programming, Volume 2, Section 4.6.3
-func pow(a, b int) int {
- p := 1
- for b > 0 {
- if b&1 != 0 {
- p *= a
- }
- b >>= 1
- a *= a
- }
- return p
-}
-
-func split3(p []byte, sep byte) (p1, p2, p3 []byte) {
- a := bytes.IndexByte(p, sep)
- b := bytes.IndexByte(p[a+1:], sep)
- if a == -1 || b == -1 {
- return p, nil, nil
- }
- b += a + 1
- return p[:a], p[a+1 : b], p[b+1:]
-}
-
-func split2(p []byte, sep byte) (p1, p2 []byte) {
- i := bytes.IndexByte(p, sep)
- if i == -1 {
- return p, nil
- }
- return p[:i], p[i+1:]
-}
-
-func trim(p []byte) []byte {
- var i, j int
- for i = 0; i < len(p) && (p[i] == ' ' || p[i] == '\t'); {
- i++
- }
- for j = len(p); j > i && (p[j-1] == ' ' || p[j-1] == '\t'); {
- j--
- }
- return p[i:j]
-}
diff --git a/vendor/github.com/gobwas/httphead/httphead.go b/vendor/github.com/gobwas/httphead/httphead.go
deleted file mode 100644
index 2387e8033c9..00000000000
--- a/vendor/github.com/gobwas/httphead/httphead.go
+++ /dev/null
@@ -1,331 +0,0 @@
-// Package httphead contains utils for parsing HTTP and HTTP-grammar compatible
-// text protocols headers.
-//
-// That is, this package first aim is to bring ability to easily parse
-// constructions, described here https://tools.ietf.org/html/rfc2616#section-2
-package httphead
-
-import (
- "bytes"
- "strings"
-)
-
-// ScanTokens parses data in this form:
-//
-// list = 1#token
-//
-// It returns false if data is malformed.
-func ScanTokens(data []byte, it func([]byte) bool) bool {
- lexer := &Scanner{data: data}
-
- var ok bool
- for lexer.Next() {
- switch lexer.Type() {
- case ItemToken:
- ok = true
- if !it(lexer.Bytes()) {
- return true
- }
- case ItemSeparator:
- if !isComma(lexer.Bytes()) {
- return false
- }
- default:
- return false
- }
- }
-
- return ok && !lexer.err
-}
-
-// ParseOptions parses all header options and appends it to given slice of
-// Option. It returns flag of successful (wellformed input) parsing.
-//
-// Note that appended options are all consist of subslices of data. That is,
-// mutation of data will mutate appended options.
-func ParseOptions(data []byte, options []Option) ([]Option, bool) {
- var i int
- index := -1
- return options, ScanOptions(data, func(idx int, name, attr, val []byte) Control {
- if idx != index {
- index = idx
- i = len(options)
- options = append(options, Option{Name: name})
- }
- if attr != nil {
- options[i].Parameters.Set(attr, val)
- }
- return ControlContinue
- })
-}
-
-// SelectFlag encodes way of options selection.
-type SelectFlag byte
-
-// String represetns flag as string.
-func (f SelectFlag) String() string {
- var flags [2]string
- var n int
- if f&SelectCopy != 0 {
- flags[n] = "copy"
- n++
- }
- if f&SelectUnique != 0 {
- flags[n] = "unique"
- n++
- }
- return "[" + strings.Join(flags[:n], "|") + "]"
-}
-
-const (
- // SelectCopy causes selector to copy selected option before appending it
- // to resulting slice.
- // If SelectCopy flag is not passed to selector, then appended options will
- // contain sub-slices of the initial data.
- SelectCopy SelectFlag = 1 << iota
-
- // SelectUnique causes selector to append only not yet existing option to
- // resulting slice. Unique is checked by comparing option names.
- SelectUnique
-)
-
-// OptionSelector contains configuration for selecting Options from header value.
-type OptionSelector struct {
- // Check is a filter function that applied to every Option that possibly
- // could be selected.
- // If Check is nil all options will be selected.
- Check func(Option) bool
-
- // Flags contains flags for options selection.
- Flags SelectFlag
-
- // Alloc used to allocate slice of bytes when selector is configured with
- // SelectCopy flag. It will be called with number of bytes needed for copy
- // of single Option.
- // If Alloc is nil make is used.
- Alloc func(n int) []byte
-}
-
-// Select parses header data and appends it to given slice of Option.
-// It also returns flag of successful (wellformed input) parsing.
-func (s OptionSelector) Select(data []byte, options []Option) ([]Option, bool) {
- var current Option
- var has bool
- index := -1
-
- alloc := s.Alloc
- if alloc == nil {
- alloc = defaultAlloc
- }
- check := s.Check
- if check == nil {
- check = defaultCheck
- }
-
- ok := ScanOptions(data, func(idx int, name, attr, val []byte) Control {
- if idx != index {
- if has && check(current) {
- if s.Flags&SelectCopy != 0 {
- current = current.Copy(alloc(current.Size()))
- }
- options = append(options, current)
- has = false
- }
- if s.Flags&SelectUnique != 0 {
- for i := len(options) - 1; i >= 0; i-- {
- if bytes.Equal(options[i].Name, name) {
- return ControlSkip
- }
- }
- }
- index = idx
- current = Option{Name: name}
- has = true
- }
- if attr != nil {
- current.Parameters.Set(attr, val)
- }
-
- return ControlContinue
- })
- if has && check(current) {
- if s.Flags&SelectCopy != 0 {
- current = current.Copy(alloc(current.Size()))
- }
- options = append(options, current)
- }
-
- return options, ok
-}
-
-func defaultAlloc(n int) []byte { return make([]byte, n) }
-func defaultCheck(Option) bool { return true }
-
-// Control represents operation that scanner should perform.
-type Control byte
-
-const (
- // ControlContinue causes scanner to continue scan tokens.
- ControlContinue Control = iota
- // ControlBreak causes scanner to stop scan tokens.
- ControlBreak
- // ControlSkip causes scanner to skip current entity.
- ControlSkip
-)
-
-// ScanOptions parses data in this form:
-//
-// values = 1#value
-// value = token *( ";" param )
-// param = token [ "=" (token | quoted-string) ]
-//
-// It calls given callback with the index of the option, option itself and its
-// parameter (attribute and its value, both could be nil). Index is useful when
-// header contains multiple choises for the same named option.
-//
-// Given callback should return one of the defined Control* values.
-// ControlSkip means that passed key is not in caller's interest. That is, all
-// parameters of that key will be skipped.
-// ControlBreak means that no more keys and parameters should be parsed. That
-// is, it must break parsing immediately.
-// ControlContinue means that caller want to receive next parameter and its
-// value or the next key.
-//
-// It returns false if data is malformed.
-func ScanOptions(data []byte, it func(index int, option, attribute, value []byte) Control) bool {
- lexer := &Scanner{data: data}
-
- var ok bool
- var state int
- const (
- stateKey = iota
- stateParamBeforeName
- stateParamName
- stateParamBeforeValue
- stateParamValue
- )
-
- var (
- index int
- key, param, value []byte
- mustCall bool
- )
- for lexer.Next() {
- var (
- call bool
- growIndex int
- )
-
- t := lexer.Type()
- v := lexer.Bytes()
-
- switch t {
- case ItemToken:
- switch state {
- case stateKey, stateParamBeforeName:
- key = v
- state = stateParamBeforeName
- mustCall = true
- case stateParamName:
- param = v
- state = stateParamBeforeValue
- mustCall = true
- case stateParamValue:
- value = v
- state = stateParamBeforeName
- call = true
- default:
- return false
- }
-
- case ItemString:
- if state != stateParamValue {
- return false
- }
- value = v
- state = stateParamBeforeName
- call = true
-
- case ItemSeparator:
- switch {
- case isComma(v) && state == stateKey:
- // Nothing to do.
-
- case isComma(v) && state == stateParamBeforeName:
- state = stateKey
- // Make call only if we have not called this key yet.
- call = mustCall
- if !call {
- // If we have already called callback with the key
- // that just ended.
- index++
- } else {
- // Else grow the index after calling callback.
- growIndex = 1
- }
-
- case isComma(v) && state == stateParamBeforeValue:
- state = stateKey
- growIndex = 1
- call = true
-
- case isSemicolon(v) && state == stateParamBeforeName:
- state = stateParamName
-
- case isSemicolon(v) && state == stateParamBeforeValue:
- state = stateParamName
- call = true
-
- case isEquality(v) && state == stateParamBeforeValue:
- state = stateParamValue
-
- default:
- return false
- }
-
- default:
- return false
- }
-
- if call {
- switch it(index, key, param, value) {
- case ControlBreak:
- // User want to stop to parsing parameters.
- return true
-
- case ControlSkip:
- // User want to skip current param.
- state = stateKey
- lexer.SkipEscaped(',')
-
- case ControlContinue:
- // User is interested in rest of parameters.
- // Nothing to do.
-
- default:
- panic("unexpected control value")
- }
- ok = true
- param = nil
- value = nil
- mustCall = false
- index += growIndex
- }
- }
- if mustCall {
- ok = true
- it(index, key, param, value)
- }
-
- return ok && !lexer.err
-}
-
-func isComma(b []byte) bool {
- return len(b) == 1 && b[0] == ','
-}
-func isSemicolon(b []byte) bool {
- return len(b) == 1 && b[0] == ';'
-}
-func isEquality(b []byte) bool {
- return len(b) == 1 && b[0] == '='
-}
diff --git a/vendor/github.com/gobwas/httphead/lexer.go b/vendor/github.com/gobwas/httphead/lexer.go
deleted file mode 100644
index 729855ed0d3..00000000000
--- a/vendor/github.com/gobwas/httphead/lexer.go
+++ /dev/null
@@ -1,360 +0,0 @@
-package httphead
-
-import (
- "bytes"
-)
-
-// ItemType encodes type of the lexing token.
-type ItemType int
-
-const (
- // ItemUndef reports that token is undefined.
- ItemUndef ItemType = iota
- // ItemToken reports that token is RFC2616 token.
- ItemToken
- // ItemSeparator reports that token is RFC2616 separator.
- ItemSeparator
- // ItemString reports that token is RFC2616 quouted string.
- ItemString
- // ItemComment reports that token is RFC2616 comment.
- ItemComment
- // ItemOctet reports that token is octet slice.
- ItemOctet
-)
-
-// Scanner represents header tokens scanner.
-// See https://tools.ietf.org/html/rfc2616#section-2
-type Scanner struct {
- data []byte
- pos int
-
- itemType ItemType
- itemBytes []byte
-
- err bool
-}
-
-// NewScanner creates new RFC2616 data scanner.
-func NewScanner(data []byte) *Scanner {
- return &Scanner{data: data}
-}
-
-// Next scans for next token. It returns true on successful scanning, and false
-// on error or EOF.
-func (l *Scanner) Next() bool {
- c, ok := l.nextChar()
- if !ok {
- return false
- }
- switch c {
- case '"': // quoted-string;
- return l.fetchQuotedString()
-
- case '(': // comment;
- return l.fetchComment()
-
- case '\\', ')': // unexpected chars;
- l.err = true
- return false
-
- default:
- return l.fetchToken()
- }
-}
-
-// FetchUntil fetches ItemOctet from current scanner position to first
-// occurence of the c or to the end of the underlying data.
-func (l *Scanner) FetchUntil(c byte) bool {
- l.resetItem()
- if l.pos == len(l.data) {
- return false
- }
- return l.fetchOctet(c)
-}
-
-// Peek reads byte at current position without advancing it. On end of data it
-// returns 0.
-func (l *Scanner) Peek() byte {
- if l.pos == len(l.data) {
- return 0
- }
- return l.data[l.pos]
-}
-
-// Peek2 reads two first bytes at current position without advancing it.
-// If there not enough data it returs 0.
-func (l *Scanner) Peek2() (a, b byte) {
- if l.pos == len(l.data) {
- return 0, 0
- }
- if l.pos+1 == len(l.data) {
- return l.data[l.pos], 0
- }
- return l.data[l.pos], l.data[l.pos+1]
-}
-
-// Buffered reporst how many bytes there are left to scan.
-func (l *Scanner) Buffered() int {
- return len(l.data) - l.pos
-}
-
-// Advance moves current position index at n bytes. It returns true on
-// successful move.
-func (l *Scanner) Advance(n int) bool {
- l.pos += n
- if l.pos > len(l.data) {
- l.pos = len(l.data)
- return false
- }
- return true
-}
-
-// Skip skips all bytes until first occurence of c.
-func (l *Scanner) Skip(c byte) {
- if l.err {
- return
- }
- // Reset scanner state.
- l.resetItem()
-
- if i := bytes.IndexByte(l.data[l.pos:], c); i == -1 {
- // Reached the end of data.
- l.pos = len(l.data)
- } else {
- l.pos += i + 1
- }
-}
-
-// SkipEscaped skips all bytes until first occurence of non-escaped c.
-func (l *Scanner) SkipEscaped(c byte) {
- if l.err {
- return
- }
- // Reset scanner state.
- l.resetItem()
-
- if i := ScanUntil(l.data[l.pos:], c); i == -1 {
- // Reached the end of data.
- l.pos = len(l.data)
- } else {
- l.pos += i + 1
- }
-}
-
-// Type reports current token type.
-func (l *Scanner) Type() ItemType {
- return l.itemType
-}
-
-// Bytes returns current token bytes.
-func (l *Scanner) Bytes() []byte {
- return l.itemBytes
-}
-
-func (l *Scanner) nextChar() (byte, bool) {
- // Reset scanner state.
- l.resetItem()
-
- if l.err {
- return 0, false
- }
- l.pos += SkipSpace(l.data[l.pos:])
- if l.pos == len(l.data) {
- return 0, false
- }
- return l.data[l.pos], true
-}
-
-func (l *Scanner) resetItem() {
- l.itemType = ItemUndef
- l.itemBytes = nil
-}
-
-func (l *Scanner) fetchOctet(c byte) bool {
- i := l.pos
- if j := bytes.IndexByte(l.data[l.pos:], c); j == -1 {
- // Reached the end of data.
- l.pos = len(l.data)
- } else {
- l.pos += j
- }
-
- l.itemType = ItemOctet
- l.itemBytes = l.data[i:l.pos]
-
- return true
-}
-
-func (l *Scanner) fetchToken() bool {
- n, t := ScanToken(l.data[l.pos:])
- if n == -1 {
- l.err = true
- return false
- }
-
- l.itemType = t
- l.itemBytes = l.data[l.pos : l.pos+n]
- l.pos += n
-
- return true
-}
-
-func (l *Scanner) fetchQuotedString() (ok bool) {
- l.pos++
-
- n := ScanUntil(l.data[l.pos:], '"')
- if n == -1 {
- l.err = true
- return false
- }
-
- l.itemType = ItemString
- l.itemBytes = RemoveByte(l.data[l.pos:l.pos+n], '\\')
- l.pos += n + 1
-
- return true
-}
-
-func (l *Scanner) fetchComment() (ok bool) {
- l.pos++
-
- n := ScanPairGreedy(l.data[l.pos:], '(', ')')
- if n == -1 {
- l.err = true
- return false
- }
-
- l.itemType = ItemComment
- l.itemBytes = RemoveByte(l.data[l.pos:l.pos+n], '\\')
- l.pos += n + 1
-
- return true
-}
-
-// ScanUntil scans for first non-escaped character c in given data.
-// It returns index of matched c and -1 if c is not found.
-func ScanUntil(data []byte, c byte) (n int) {
- for {
- i := bytes.IndexByte(data[n:], c)
- if i == -1 {
- return -1
- }
- n += i
- if n == 0 || data[n-1] != '\\' {
- break
- }
- n++
- }
- return
-}
-
-// ScanPairGreedy scans for complete pair of opening and closing chars in greedy manner.
-// Note that first opening byte must not be present in data.
-func ScanPairGreedy(data []byte, open, close byte) (n int) {
- var m int
- opened := 1
- for {
- i := bytes.IndexByte(data[n:], close)
- if i == -1 {
- return -1
- }
- n += i
- // If found index is not escaped then it is the end.
- if n == 0 || data[n-1] != '\\' {
- opened--
- }
-
- for m < i {
- j := bytes.IndexByte(data[m:i], open)
- if j == -1 {
- break
- }
- m += j + 1
- opened++
- }
-
- if opened == 0 {
- break
- }
-
- n++
- m = n
- }
- return
-}
-
-// RemoveByte returns data without c. If c is not present in data it returns
-// the same slice. If not, it copies data without c.
-func RemoveByte(data []byte, c byte) []byte {
- j := bytes.IndexByte(data, c)
- if j == -1 {
- return data
- }
-
- n := len(data) - 1
-
- // If character is present, than allocate slice with n-1 capacity. That is,
- // resulting bytes could be at most n-1 length.
- result := make([]byte, n)
- k := copy(result, data[:j])
-
- for i := j + 1; i < n; {
- j = bytes.IndexByte(data[i:], c)
- if j != -1 {
- k += copy(result[k:], data[i:i+j])
- i = i + j + 1
- } else {
- k += copy(result[k:], data[i:])
- break
- }
- }
-
- return result[:k]
-}
-
-// SkipSpace skips spaces and lws-sequences from p.
-// It returns number ob bytes skipped.
-func SkipSpace(p []byte) (n int) {
- for len(p) > 0 {
- switch {
- case len(p) >= 3 &&
- p[0] == '\r' &&
- p[1] == '\n' &&
- OctetTypes[p[2]].IsSpace():
- p = p[3:]
- n += 3
- case OctetTypes[p[0]].IsSpace():
- p = p[1:]
- n++
- default:
- return
- }
- }
- return
-}
-
-// ScanToken scan for next token in p. It returns length of the token and its
-// type. It do not trim p.
-func ScanToken(p []byte) (n int, t ItemType) {
- if len(p) == 0 {
- return 0, ItemUndef
- }
-
- c := p[0]
- switch {
- case OctetTypes[c].IsSeparator():
- return 1, ItemSeparator
-
- case OctetTypes[c].IsToken():
- for n = 1; n < len(p); n++ {
- c := p[n]
- if !OctetTypes[c].IsToken() {
- break
- }
- }
- return n, ItemToken
-
- default:
- return -1, ItemUndef
- }
-}
diff --git a/vendor/github.com/gobwas/httphead/octet.go b/vendor/github.com/gobwas/httphead/octet.go
deleted file mode 100644
index 2a04cdd0909..00000000000
--- a/vendor/github.com/gobwas/httphead/octet.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package httphead
-
-// OctetType desribes character type.
-//
-// From the "Basic Rules" chapter of RFC2616
-// See https://tools.ietf.org/html/rfc2616#section-2.2
-//
-// OCTET =
-// CHAR =
-// UPALPHA =
-// LOALPHA =
-// ALPHA = UPALPHA | LOALPHA
-// DIGIT =
-// CTL =
-// CR =
-// LF =
-// SP =
-// HT =
-// <"> =
-// CRLF = CR LF
-// LWS = [CRLF] 1*( SP | HT )
-//
-// Many HTTP/1.1 header field values consist of words separated by LWS
-// or special characters. These special characters MUST be in a quoted
-// string to be used within a parameter value (as defined in section
-// 3.6).
-//
-// token = 1*
-// separators = "(" | ")" | "<" | ">" | "@"
-// | "," | ";" | ":" | "\" | <">
-// | "/" | "[" | "]" | "?" | "="
-// | "{" | "}" | SP | HT
-type OctetType byte
-
-// IsChar reports whether octet is CHAR.
-func (t OctetType) IsChar() bool { return t&octetChar != 0 }
-
-// IsControl reports whether octet is CTL.
-func (t OctetType) IsControl() bool { return t&octetControl != 0 }
-
-// IsSeparator reports whether octet is separator.
-func (t OctetType) IsSeparator() bool { return t&octetSeparator != 0 }
-
-// IsSpace reports whether octet is space (SP or HT).
-func (t OctetType) IsSpace() bool { return t&octetSpace != 0 }
-
-// IsToken reports whether octet is token.
-func (t OctetType) IsToken() bool { return t&octetToken != 0 }
-
-const (
- octetChar OctetType = 1 << iota
- octetControl
- octetSpace
- octetSeparator
- octetToken
-)
-
-// OctetTypes is a table of octets.
-var OctetTypes [256]OctetType
-
-func init() {
- for c := 32; c < 256; c++ {
- var t OctetType
- if c <= 127 {
- t |= octetChar
- }
- if 0 <= c && c <= 31 || c == 127 {
- t |= octetControl
- }
- switch c {
- case '(', ')', '<', '>', '@', ',', ';', ':', '"', '/', '[', ']', '?', '=', '{', '}', '\\':
- t |= octetSeparator
- case ' ', '\t':
- t |= octetSpace | octetSeparator
- }
-
- if t.IsChar() && !t.IsControl() && !t.IsSeparator() && !t.IsSpace() {
- t |= octetToken
- }
-
- OctetTypes[c] = t
- }
-}
diff --git a/vendor/github.com/gobwas/httphead/option.go b/vendor/github.com/gobwas/httphead/option.go
deleted file mode 100644
index 243be08c9a0..00000000000
--- a/vendor/github.com/gobwas/httphead/option.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package httphead
-
-import (
- "bytes"
- "sort"
-)
-
-// Option represents a header option.
-type Option struct {
- Name []byte
- Parameters Parameters
-}
-
-// Size returns number of bytes need to be allocated for use in opt.Copy.
-func (opt Option) Size() int {
- return len(opt.Name) + opt.Parameters.bytes
-}
-
-// Copy copies all underlying []byte slices into p and returns new Option.
-// Note that p must be at least of opt.Size() length.
-func (opt Option) Copy(p []byte) Option {
- n := copy(p, opt.Name)
- opt.Name = p[:n]
- opt.Parameters, p = opt.Parameters.Copy(p[n:])
- return opt
-}
-
-// String represents option as a string.
-func (opt Option) String() string {
- return "{" + string(opt.Name) + " " + opt.Parameters.String() + "}"
-}
-
-// NewOption creates named option with given parameters.
-func NewOption(name string, params map[string]string) Option {
- p := Parameters{}
- for k, v := range params {
- p.Set([]byte(k), []byte(v))
- }
- return Option{
- Name: []byte(name),
- Parameters: p,
- }
-}
-
-// Equal reports whether option is equal to b.
-func (opt Option) Equal(b Option) bool {
- if bytes.Equal(opt.Name, b.Name) {
- return opt.Parameters.Equal(b.Parameters)
- }
- return false
-}
-
-// Parameters represents option's parameters.
-type Parameters struct {
- pos int
- bytes int
- arr [8]pair
- dyn []pair
-}
-
-// Equal reports whether a equal to b.
-func (p Parameters) Equal(b Parameters) bool {
- switch {
- case p.dyn == nil && b.dyn == nil:
- case p.dyn != nil && b.dyn != nil:
- default:
- return false
- }
-
- ad, bd := p.data(), b.data()
- if len(ad) != len(bd) {
- return false
- }
-
- sort.Sort(pairs(ad))
- sort.Sort(pairs(bd))
-
- for i := 0; i < len(ad); i++ {
- av, bv := ad[i], bd[i]
- if !bytes.Equal(av.key, bv.key) || !bytes.Equal(av.value, bv.value) {
- return false
- }
- }
- return true
-}
-
-// Size returns number of bytes that needed to copy p.
-func (p *Parameters) Size() int {
- return p.bytes
-}
-
-// Copy copies all underlying []byte slices into dst and returns new
-// Parameters.
-// Note that dst must be at least of p.Size() length.
-func (p *Parameters) Copy(dst []byte) (Parameters, []byte) {
- ret := Parameters{
- pos: p.pos,
- bytes: p.bytes,
- }
- if p.dyn != nil {
- ret.dyn = make([]pair, len(p.dyn))
- for i, v := range p.dyn {
- ret.dyn[i], dst = v.copy(dst)
- }
- } else {
- for i, p := range p.arr {
- ret.arr[i], dst = p.copy(dst)
- }
- }
- return ret, dst
-}
-
-// Get returns value by key and flag about existence such value.
-func (p *Parameters) Get(key string) (value []byte, ok bool) {
- for _, v := range p.data() {
- if string(v.key) == key {
- return v.value, true
- }
- }
- return nil, false
-}
-
-// Set sets value by key.
-func (p *Parameters) Set(key, value []byte) {
- p.bytes += len(key) + len(value)
-
- if p.pos < len(p.arr) {
- p.arr[p.pos] = pair{key, value}
- p.pos++
- return
- }
-
- if p.dyn == nil {
- p.dyn = make([]pair, len(p.arr), len(p.arr)+1)
- copy(p.dyn, p.arr[:])
- }
- p.dyn = append(p.dyn, pair{key, value})
-}
-
-// ForEach iterates over parameters key-value pairs and calls cb for each one.
-func (p *Parameters) ForEach(cb func(k, v []byte) bool) {
- for _, v := range p.data() {
- if !cb(v.key, v.value) {
- break
- }
- }
-}
-
-// String represents parameters as a string.
-func (p *Parameters) String() (ret string) {
- ret = "["
- for i, v := range p.data() {
- if i > 0 {
- ret += " "
- }
- ret += string(v.key) + ":" + string(v.value)
- }
- return ret + "]"
-}
-
-func (p *Parameters) data() []pair {
- if p.dyn != nil {
- return p.dyn
- }
- return p.arr[:p.pos]
-}
-
-type pair struct {
- key, value []byte
-}
-
-func (p pair) copy(dst []byte) (pair, []byte) {
- n := copy(dst, p.key)
- p.key = dst[:n]
- m := n + copy(dst[n:], p.value)
- p.value = dst[n:m]
-
- dst = dst[m:]
-
- return p, dst
-}
-
-type pairs []pair
-
-func (p pairs) Len() int { return len(p) }
-func (p pairs) Less(a, b int) bool { return bytes.Compare(p[a].key, p[b].key) == -1 }
-func (p pairs) Swap(a, b int) { p[a], p[b] = p[b], p[a] }
diff --git a/vendor/github.com/gobwas/httphead/writer.go b/vendor/github.com/gobwas/httphead/writer.go
deleted file mode 100644
index e5df3ddf404..00000000000
--- a/vendor/github.com/gobwas/httphead/writer.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package httphead
-
-import "io"
-
-var (
- comma = []byte{','}
- equality = []byte{'='}
- semicolon = []byte{';'}
- quote = []byte{'"'}
- escape = []byte{'\\'}
-)
-
-// WriteOptions write options list to the dest.
-// It uses the same form as {Scan,Parse}Options functions:
-// values = 1#value
-// value = token *( ";" param )
-// param = token [ "=" (token | quoted-string) ]
-//
-// It wraps valuse into the quoted-string sequence if it contains any
-// non-token characters.
-func WriteOptions(dest io.Writer, options []Option) (n int, err error) {
- w := writer{w: dest}
- for i, opt := range options {
- if i > 0 {
- w.write(comma)
- }
-
- writeTokenSanitized(&w, opt.Name)
-
- for _, p := range opt.Parameters.data() {
- w.write(semicolon)
- writeTokenSanitized(&w, p.key)
- if len(p.value) != 0 {
- w.write(equality)
- writeTokenSanitized(&w, p.value)
- }
- }
- }
- return w.result()
-}
-
-// writeTokenSanitized writes token as is or as quouted string if it contains
-// non-token characters.
-//
-// Note that is is not expects LWS sequnces be in s, cause LWS is used only as
-// header field continuation:
-// "A CRLF is allowed in the definition of TEXT only as part of a header field
-// continuation. It is expected that the folding LWS will be replaced with a
-// single SP before interpretation of the TEXT value."
-// See https://tools.ietf.org/html/rfc2616#section-2
-//
-// That is we sanitizing s for writing, so there could not be any header field
-// continuation.
-// That is any CRLF will be escaped as any other control characters not allowd in TEXT.
-func writeTokenSanitized(bw *writer, bts []byte) {
- var qt bool
- var pos int
- for i := 0; i < len(bts); i++ {
- c := bts[i]
- if !OctetTypes[c].IsToken() && !qt {
- qt = true
- bw.write(quote)
- }
- if OctetTypes[c].IsControl() || c == '"' {
- if !qt {
- qt = true
- bw.write(quote)
- }
- bw.write(bts[pos:i])
- bw.write(escape)
- bw.write(bts[i : i+1])
- pos = i + 1
- }
- }
- if !qt {
- bw.write(bts)
- } else {
- bw.write(bts[pos:])
- bw.write(quote)
- }
-}
-
-type writer struct {
- w io.Writer
- n int
- err error
-}
-
-func (w *writer) write(p []byte) {
- if w.err != nil {
- return
- }
- var n int
- n, w.err = w.w.Write(p)
- w.n += n
- return
-}
-
-func (w *writer) result() (int, error) {
- return w.n, w.err
-}
diff --git a/vendor/github.com/gobwas/pool/README.md b/vendor/github.com/gobwas/pool/README.md
deleted file mode 100644
index 45685581dae..00000000000
--- a/vendor/github.com/gobwas/pool/README.md
+++ /dev/null
@@ -1,107 +0,0 @@
-# pool
-
-[![GoDoc][godoc-image]][godoc-url]
-
-> Tiny memory reuse helpers for Go.
-
-## generic
-
-Without use of subpackages, `pool` allows to reuse any struct distinguishable
-by size in generic way:
-
-```go
-package main
-
-import "github.com/gobwas/pool"
-
-func main() {
- x, n := pool.Get(100) // Returns object with size 128 or nil.
- if x == nil {
- // Create x somehow with knowledge that n is 128.
- }
- defer pool.Put(x, n)
-
- // Work with x.
-}
-```
-
-Pool allows you to pass specific options for constructing custom pool:
-
-```go
-package main
-
-import "github.com/gobwas/pool"
-
-func main() {
- p := pool.Custom(
- pool.WithLogSizeMapping(), // Will ceil size n passed to Get(n) to nearest power of two.
- pool.WithLogSizeRange(64, 512), // Will reuse objects in logarithmic range [64, 512].
- pool.WithSize(65536), // Will reuse object with size 65536.
- )
- x, n := p.Get(1000) // Returns nil and 1000 because mapped size 1000 => 1024 is not reusing by the pool.
- defer pool.Put(x, n) // Will not reuse x.
-
- // Work with x.
-}
-```
-
-Note that there are few non-generic pooling implementations inside subpackages.
-
-## pbytes
-
-Subpackage `pbytes` is intended for `[]byte` reuse.
-
-```go
-package main
-
-import "github.com/gobwas/pool/pbytes"
-
-func main() {
- bts := pbytes.GetCap(100) // Returns make([]byte, 0, 128).
- defer pbytes.Put(bts)
-
- // Work with bts.
-}
-```
-
-You can also create your own range for pooling:
-
-```go
-package main
-
-import "github.com/gobwas/pool/pbytes"
-
-func main() {
- // Reuse only slices whose capacity is 128, 256, 512 or 1024.
- pool := pbytes.New(128, 1024)
-
- bts := pool.GetCap(100) // Returns make([]byte, 0, 128).
- defer pool.Put(bts)
-
- // Work with bts.
-}
-```
-
-## pbufio
-
-Subpackage `pbufio` is intended for `*bufio.{Reader, Writer}` reuse.
-
-```go
-package main
-
-import "github.com/gobwas/pool/pbufio"
-
-func main() {
- bw := pbufio.GetWriter(os.Stdout, 100) // Returns bufio.NewWriterSize(128).
- defer pbufio.PutWriter(bw)
-
- // Work with bw.
-}
-```
-
-Like with `pbytes`, you can also create pool with custom reuse bounds.
-
-
-
-[godoc-image]: https://godoc.org/github.com/gobwas/pool?status.svg
-[godoc-url]: https://godoc.org/github.com/gobwas/pool
diff --git a/vendor/github.com/gobwas/pool/generic.go b/vendor/github.com/gobwas/pool/generic.go
deleted file mode 100644
index d40b362458b..00000000000
--- a/vendor/github.com/gobwas/pool/generic.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package pool
-
-import (
- "sync"
-
- "github.com/gobwas/pool/internal/pmath"
-)
-
-var DefaultPool = New(128, 65536)
-
-// Get pulls object whose generic size is at least of given size. It also
-// returns a real size of x for further pass to Put(). It returns -1 as real
-// size for nil x. Size >-1 does not mean that x is non-nil, so checks must be
-// done.
-//
-// Note that size could be ceiled to the next power of two.
-//
-// Get is a wrapper around DefaultPool.Get().
-func Get(size int) (interface{}, int) { return DefaultPool.Get(size) }
-
-// Put takes x and its size for future reuse.
-// Put is a wrapper around DefaultPool.Put().
-func Put(x interface{}, size int) { DefaultPool.Put(x, size) }
-
-// Pool contains logic of reusing objects distinguishable by size in generic
-// way.
-type Pool struct {
- pool map[int]*sync.Pool
- size func(int) int
-}
-
-// New creates new Pool that reuses objects which size is in logarithmic range
-// [min, max].
-//
-// Note that it is a shortcut for Custom() constructor with Options provided by
-// WithLogSizeMapping() and WithLogSizeRange(min, max) calls.
-func New(min, max int) *Pool {
- return Custom(
- WithLogSizeMapping(),
- WithLogSizeRange(min, max),
- )
-}
-
-// Custom creates new Pool with given options.
-func Custom(opts ...Option) *Pool {
- p := &Pool{
- pool: make(map[int]*sync.Pool),
- size: pmath.Identity,
- }
-
- c := (*poolConfig)(p)
- for _, opt := range opts {
- opt(c)
- }
-
- return p
-}
-
-// Get pulls object whose generic size is at least of given size.
-// It also returns a real size of x for further pass to Put() even if x is nil.
-// Note that size could be ceiled to the next power of two.
-func (p *Pool) Get(size int) (interface{}, int) {
- n := p.size(size)
- if pool := p.pool[n]; pool != nil {
- return pool.Get(), n
- }
- return nil, size
-}
-
-// Put takes x and its size for future reuse.
-func (p *Pool) Put(x interface{}, size int) {
- if pool := p.pool[size]; pool != nil {
- pool.Put(x)
- }
-}
-
-type poolConfig Pool
-
-// AddSize adds size n to the map.
-func (p *poolConfig) AddSize(n int) {
- p.pool[n] = new(sync.Pool)
-}
-
-// SetSizeMapping sets up incoming size mapping function.
-func (p *poolConfig) SetSizeMapping(size func(int) int) {
- p.size = size
-}
diff --git a/vendor/github.com/gobwas/pool/internal/pmath/pmath.go b/vendor/github.com/gobwas/pool/internal/pmath/pmath.go
deleted file mode 100644
index df152ed12a5..00000000000
--- a/vendor/github.com/gobwas/pool/internal/pmath/pmath.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package pmath
-
-const (
- bitsize = 32 << (^uint(0) >> 63)
- maxint = int(1<<(bitsize-1) - 1)
- maxintHeadBit = 1 << (bitsize - 2)
-)
-
-// LogarithmicRange iterates from ceiled to power of two min to max,
-// calling cb on each iteration.
-func LogarithmicRange(min, max int, cb func(int)) {
- if min == 0 {
- min = 1
- }
- for n := CeilToPowerOfTwo(min); n <= max; n <<= 1 {
- cb(n)
- }
-}
-
-// IsPowerOfTwo reports whether given integer is a power of two.
-func IsPowerOfTwo(n int) bool {
- return n&(n-1) == 0
-}
-
-// Identity is identity.
-func Identity(n int) int {
- return n
-}
-
-// CeilToPowerOfTwo returns the least power of two integer value greater than
-// or equal to n.
-func CeilToPowerOfTwo(n int) int {
- if n&maxintHeadBit != 0 && n > maxintHeadBit {
- panic("argument is too large")
- }
- if n <= 2 {
- return n
- }
- n--
- n = fillBits(n)
- n++
- return n
-}
-
-// FloorToPowerOfTwo returns the greatest power of two integer value less than
-// or equal to n.
-func FloorToPowerOfTwo(n int) int {
- if n <= 2 {
- return n
- }
- n = fillBits(n)
- n >>= 1
- n++
- return n
-}
-
-func fillBits(n int) int {
- n |= n >> 1
- n |= n >> 2
- n |= n >> 4
- n |= n >> 8
- n |= n >> 16
- n |= n >> 32
- return n
-}
diff --git a/vendor/github.com/gobwas/pool/option.go b/vendor/github.com/gobwas/pool/option.go
deleted file mode 100644
index d6e42b70055..00000000000
--- a/vendor/github.com/gobwas/pool/option.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package pool
-
-import "github.com/gobwas/pool/internal/pmath"
-
-// Option configures pool.
-type Option func(Config)
-
-// Config describes generic pool configuration.
-type Config interface {
- AddSize(n int)
- SetSizeMapping(func(int) int)
-}
-
-// WithSizeLogRange returns an Option that will add logarithmic range of
-// pooling sizes containing [min, max] values.
-func WithLogSizeRange(min, max int) Option {
- return func(c Config) {
- pmath.LogarithmicRange(min, max, func(n int) {
- c.AddSize(n)
- })
- }
-}
-
-// WithSize returns an Option that will add given pooling size to the pool.
-func WithSize(n int) Option {
- return func(c Config) {
- c.AddSize(n)
- }
-}
-
-func WithSizeMapping(sz func(int) int) Option {
- return func(c Config) {
- c.SetSizeMapping(sz)
- }
-}
-
-func WithLogSizeMapping() Option {
- return WithSizeMapping(pmath.CeilToPowerOfTwo)
-}
-
-func WithIdentitySizeMapping() Option {
- return WithSizeMapping(pmath.Identity)
-}
diff --git a/vendor/github.com/gobwas/pool/pbufio/pbufio.go b/vendor/github.com/gobwas/pool/pbufio/pbufio.go
deleted file mode 100644
index d526bd80da8..00000000000
--- a/vendor/github.com/gobwas/pool/pbufio/pbufio.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Package pbufio contains tools for pooling bufio.Reader and bufio.Writers.
-package pbufio
-
-import (
- "bufio"
- "io"
-
- "github.com/gobwas/pool"
-)
-
-var (
- DefaultWriterPool = NewWriterPool(256, 65536)
- DefaultReaderPool = NewReaderPool(256, 65536)
-)
-
-// GetWriter returns bufio.Writer whose buffer has at least size bytes.
-// Note that size could be ceiled to the next power of two.
-// GetWriter is a wrapper around DefaultWriterPool.Get().
-func GetWriter(w io.Writer, size int) *bufio.Writer { return DefaultWriterPool.Get(w, size) }
-
-// PutWriter takes bufio.Writer for future reuse.
-// It does not reuse bufio.Writer which underlying buffer size is not power of
-// PutWriter is a wrapper around DefaultWriterPool.Put().
-func PutWriter(bw *bufio.Writer) { DefaultWriterPool.Put(bw) }
-
-// GetReader returns bufio.Reader whose buffer has at least size bytes. It returns
-// its capacity for further pass to Put().
-// Note that size could be ceiled to the next power of two.
-// GetReader is a wrapper around DefaultReaderPool.Get().
-func GetReader(w io.Reader, size int) *bufio.Reader { return DefaultReaderPool.Get(w, size) }
-
-// PutReader takes bufio.Reader and its size for future reuse.
-// It does not reuse bufio.Reader if size is not power of two or is out of pool
-// min/max range.
-// PutReader is a wrapper around DefaultReaderPool.Put().
-func PutReader(bw *bufio.Reader) { DefaultReaderPool.Put(bw) }
-
-// WriterPool contains logic of *bufio.Writer reuse with various size.
-type WriterPool struct {
- pool *pool.Pool
-}
-
-// NewWriterPool creates new WriterPool that reuses writers which size is in
-// logarithmic range [min, max].
-func NewWriterPool(min, max int) *WriterPool {
- return &WriterPool{pool.New(min, max)}
-}
-
-// CustomWriterPool creates new WriterPool with given options.
-func CustomWriterPool(opts ...pool.Option) *WriterPool {
- return &WriterPool{pool.Custom(opts...)}
-}
-
-// Get returns bufio.Writer whose buffer has at least size bytes.
-func (wp *WriterPool) Get(w io.Writer, size int) *bufio.Writer {
- v, n := wp.pool.Get(size)
- if v != nil {
- bw := v.(*bufio.Writer)
- bw.Reset(w)
- return bw
- }
- return bufio.NewWriterSize(w, n)
-}
-
-// Put takes ownership of bufio.Writer for further reuse.
-func (wp *WriterPool) Put(bw *bufio.Writer) {
- // Should reset even if we do Reset() inside Get().
- // This is done to prevent locking underlying io.Writer from GC.
- bw.Reset(nil)
- wp.pool.Put(bw, writerSize(bw))
-}
-
-// ReaderPool contains logic of *bufio.Reader reuse with various size.
-type ReaderPool struct {
- pool *pool.Pool
-}
-
-// NewReaderPool creates new ReaderPool that reuses writers which size is in
-// logarithmic range [min, max].
-func NewReaderPool(min, max int) *ReaderPool {
- return &ReaderPool{pool.New(min, max)}
-}
-
-// CustomReaderPool creates new ReaderPool with given options.
-func CustomReaderPool(opts ...pool.Option) *ReaderPool {
- return &ReaderPool{pool.Custom(opts...)}
-}
-
-// Get returns bufio.Reader whose buffer has at least size bytes.
-func (rp *ReaderPool) Get(r io.Reader, size int) *bufio.Reader {
- v, n := rp.pool.Get(size)
- if v != nil {
- br := v.(*bufio.Reader)
- br.Reset(r)
- return br
- }
- return bufio.NewReaderSize(r, n)
-}
-
-// Put takes ownership of bufio.Reader for further reuse.
-func (rp *ReaderPool) Put(br *bufio.Reader) {
- // Should reset even if we do Reset() inside Get().
- // This is done to prevent locking underlying io.Reader from GC.
- br.Reset(nil)
- rp.pool.Put(br, readerSize(br))
-}
diff --git a/vendor/github.com/gobwas/pool/pbufio/pbufio_go110.go b/vendor/github.com/gobwas/pool/pbufio/pbufio_go110.go
deleted file mode 100644
index c736ae56e11..00000000000
--- a/vendor/github.com/gobwas/pool/pbufio/pbufio_go110.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// +build go1.10
-
-package pbufio
-
-import "bufio"
-
-func writerSize(bw *bufio.Writer) int {
- return bw.Size()
-}
-
-func readerSize(br *bufio.Reader) int {
- return br.Size()
-}
diff --git a/vendor/github.com/gobwas/pool/pbufio/pbufio_go19.go b/vendor/github.com/gobwas/pool/pbufio/pbufio_go19.go
deleted file mode 100644
index e71dd447d2a..00000000000
--- a/vendor/github.com/gobwas/pool/pbufio/pbufio_go19.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// +build !go1.10
-
-package pbufio
-
-import "bufio"
-
-func writerSize(bw *bufio.Writer) int {
- return bw.Available() + bw.Buffered()
-}
-
-// readerSize returns buffer size of the given buffered reader.
-// NOTE: current workaround implementation resets underlying io.Reader.
-func readerSize(br *bufio.Reader) int {
- br.Reset(sizeReader)
- br.ReadByte()
- n := br.Buffered() + 1
- br.Reset(nil)
- return n
-}
-
-var sizeReader optimisticReader
-
-type optimisticReader struct{}
-
-func (optimisticReader) Read(p []byte) (int, error) {
- return len(p), nil
-}
diff --git a/vendor/github.com/gobwas/pool/pbytes/pbytes.go b/vendor/github.com/gobwas/pool/pbytes/pbytes.go
deleted file mode 100644
index 919705b1093..00000000000
--- a/vendor/github.com/gobwas/pool/pbytes/pbytes.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Package pbytes contains tools for pooling byte pool.
-// Note that by default it reuse slices with capacity from 128 to 65536 bytes.
-package pbytes
-
-// DefaultPool is used by pacakge level functions.
-var DefaultPool = New(128, 65536)
-
-// Get returns probably reused slice of bytes with at least capacity of c and
-// exactly len of n.
-// Get is a wrapper around DefaultPool.Get().
-func Get(n, c int) []byte { return DefaultPool.Get(n, c) }
-
-// GetCap returns probably reused slice of bytes with at least capacity of n.
-// GetCap is a wrapper around DefaultPool.GetCap().
-func GetCap(c int) []byte { return DefaultPool.GetCap(c) }
-
-// GetLen returns probably reused slice of bytes with at least capacity of n
-// and exactly len of n.
-// GetLen is a wrapper around DefaultPool.GetLen().
-func GetLen(n int) []byte { return DefaultPool.GetLen(n) }
-
-// Put returns given slice to reuse pool.
-// Put is a wrapper around DefaultPool.Put().
-func Put(p []byte) { DefaultPool.Put(p) }
diff --git a/vendor/github.com/gobwas/pool/pbytes/pool.go b/vendor/github.com/gobwas/pool/pbytes/pool.go
deleted file mode 100644
index 1dde225f3ee..00000000000
--- a/vendor/github.com/gobwas/pool/pbytes/pool.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// +build !pool_sanitize
-
-package pbytes
-
-import "github.com/gobwas/pool"
-
-// Pool contains logic of reusing byte slices of various size.
-type Pool struct {
- pool *pool.Pool
-}
-
-// New creates new Pool that reuses slices which size is in logarithmic range
-// [min, max].
-//
-// Note that it is a shortcut for Custom() constructor with Options provided by
-// pool.WithLogSizeMapping() and pool.WithLogSizeRange(min, max) calls.
-func New(min, max int) *Pool {
- return &Pool{pool.New(min, max)}
-}
-
-// New creates new Pool with given options.
-func Custom(opts ...pool.Option) *Pool {
- return &Pool{pool.Custom(opts...)}
-}
-
-// Get returns probably reused slice of bytes with at least capacity of c and
-// exactly len of n.
-func (p *Pool) Get(n, c int) []byte {
- if n > c {
- panic("requested length is greater than capacity")
- }
-
- v, x := p.pool.Get(c)
- if v != nil {
- bts := v.([]byte)
- bts = bts[:n]
- return bts
- }
-
- return make([]byte, n, x)
-}
-
-// Put returns given slice to reuse pool.
-// It does not reuse bytes whose size is not power of two or is out of pool
-// min/max range.
-func (p *Pool) Put(bts []byte) {
- p.pool.Put(bts, cap(bts))
-}
-
-// GetCap returns probably reused slice of bytes with at least capacity of n.
-func (p *Pool) GetCap(c int) []byte {
- return p.Get(0, c)
-}
-
-// GetLen returns probably reused slice of bytes with at least capacity of n
-// and exactly len of n.
-func (p *Pool) GetLen(n int) []byte {
- return p.Get(n, n)
-}
diff --git a/vendor/github.com/gobwas/pool/pbytes/pool_sanitize.go b/vendor/github.com/gobwas/pool/pbytes/pool_sanitize.go
deleted file mode 100644
index fae9af49b12..00000000000
--- a/vendor/github.com/gobwas/pool/pbytes/pool_sanitize.go
+++ /dev/null
@@ -1,121 +0,0 @@
-// +build pool_sanitize
-
-package pbytes
-
-import (
- "reflect"
- "runtime"
- "sync/atomic"
- "syscall"
- "unsafe"
-
- "golang.org/x/sys/unix"
-)
-
-const magic = uint64(0x777742)
-
-type guard struct {
- magic uint64
- size int
- owners int32
-}
-
-const guardSize = int(unsafe.Sizeof(guard{}))
-
-type Pool struct {
- min, max int
-}
-
-func New(min, max int) *Pool {
- return &Pool{min, max}
-}
-
-// Get returns probably reused slice of bytes with at least capacity of c and
-// exactly len of n.
-func (p *Pool) Get(n, c int) []byte {
- if n > c {
- panic("requested length is greater than capacity")
- }
-
- pageSize := syscall.Getpagesize()
- pages := (c+guardSize)/pageSize + 1
- size := pages * pageSize
-
- bts := alloc(size)
-
- g := (*guard)(unsafe.Pointer(&bts[0]))
- *g = guard{
- magic: magic,
- size: size,
- owners: 1,
- }
-
- return bts[guardSize : guardSize+n]
-}
-
-func (p *Pool) GetCap(c int) []byte { return p.Get(0, c) }
-func (p *Pool) GetLen(n int) []byte { return Get(n, n) }
-
-// Put returns given slice to reuse pool.
-func (p *Pool) Put(bts []byte) {
- hdr := *(*reflect.SliceHeader)(unsafe.Pointer(&bts))
- ptr := hdr.Data - uintptr(guardSize)
-
- g := (*guard)(unsafe.Pointer(ptr))
- if g.magic != magic {
- panic("unknown slice returned to the pool")
- }
- if n := atomic.AddInt32(&g.owners, -1); n < 0 {
- panic("multiple Put() detected")
- }
-
- // Disable read and write on bytes memory pages. This will cause panic on
- // incorrect access to returned slice.
- mprotect(ptr, false, false, g.size)
-
- runtime.SetFinalizer(&bts, func(b *[]byte) {
- mprotect(ptr, true, true, g.size)
- free(*(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
- Data: ptr,
- Len: g.size,
- Cap: g.size,
- })))
- })
-}
-
-func alloc(n int) []byte {
- b, err := unix.Mmap(-1, 0, n, unix.PROT_READ|unix.PROT_WRITE|unix.PROT_EXEC, unix.MAP_SHARED|unix.MAP_ANONYMOUS)
- if err != nil {
- panic(err.Error())
- }
- return b
-}
-
-func free(b []byte) {
- if err := unix.Munmap(b); err != nil {
- panic(err.Error())
- }
-}
-
-func mprotect(ptr uintptr, r, w bool, size int) {
- // Need to avoid "EINVAL addr is not a valid pointer,
- // or not a multiple of PAGESIZE."
- start := ptr & ^(uintptr(syscall.Getpagesize() - 1))
-
- prot := uintptr(syscall.PROT_EXEC)
- switch {
- case r && w:
- prot |= syscall.PROT_READ | syscall.PROT_WRITE
- case r:
- prot |= syscall.PROT_READ
- case w:
- prot |= syscall.PROT_WRITE
- }
-
- _, _, err := syscall.Syscall(syscall.SYS_MPROTECT,
- start, uintptr(size), prot,
- )
- if err != 0 {
- panic(err.Error())
- }
-}
diff --git a/vendor/github.com/gobwas/pool/pool.go b/vendor/github.com/gobwas/pool/pool.go
deleted file mode 100644
index 1fe9e602fc5..00000000000
--- a/vendor/github.com/gobwas/pool/pool.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Package pool contains helpers for pooling structures distinguishable by
-// size.
-//
-// Quick example:
-//
-// import "github.com/gobwas/pool"
-//
-// func main() {
-// // Reuse objects in logarithmic range from 0 to 64 (0,1,2,4,6,8,16,32,64).
-// p := pool.New(0, 64)
-//
-// buf, n := p.Get(10) // Returns buffer with 16 capacity.
-// if buf == nil {
-// buf = bytes.NewBuffer(make([]byte, n))
-// }
-// defer p.Put(buf, n)
-//
-// // Work with buf.
-// }
-//
-// There are non-generic implementations for pooling:
-// - pool/pbytes for []byte reuse;
-// - pool/pbufio for *bufio.Reader and *bufio.Writer reuse;
-//
-package pool
diff --git a/vendor/github.com/gobwas/ws/.gitignore b/vendor/github.com/gobwas/ws/.gitignore
deleted file mode 100644
index e3e2b1080d0..00000000000
--- a/vendor/github.com/gobwas/ws/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-bin/
-reports/
-cpu.out
-mem.out
-ws.test
diff --git a/vendor/github.com/gobwas/ws/.travis.yml b/vendor/github.com/gobwas/ws/.travis.yml
deleted file mode 100644
index cf74f1bee3c..00000000000
--- a/vendor/github.com/gobwas/ws/.travis.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-sudo: required
-
-language: go
-
-services:
- - docker
-
-os:
- - linux
- - windows
-
-go:
- - 1.8.x
- - 1.9.x
- - 1.10.x
- - 1.11.x
- - 1.x
-
-install:
- - go get github.com/gobwas/pool
- - go get github.com/gobwas/httphead
-
-script:
- - if [ "$TRAVIS_OS_NAME" = "windows" ]; then go test ./...; fi
- - if [ "$TRAVIS_OS_NAME" = "linux" ]; then make test autobahn; fi
diff --git a/vendor/github.com/gobwas/ws/LICENSE b/vendor/github.com/gobwas/ws/LICENSE
deleted file mode 100644
index d2611fddf55..00000000000
--- a/vendor/github.com/gobwas/ws/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2017-2018 Sergey Kamardin
-
-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.
diff --git a/vendor/github.com/gobwas/ws/Makefile b/vendor/github.com/gobwas/ws/Makefile
deleted file mode 100644
index 075e83c74bc..00000000000
--- a/vendor/github.com/gobwas/ws/Makefile
+++ /dev/null
@@ -1,47 +0,0 @@
-BENCH ?=.
-BENCH_BASE?=master
-
-clean:
- rm -f bin/reporter
- rm -fr autobahn/report/*
-
-bin/reporter:
- go build -o bin/reporter ./autobahn
-
-bin/gocovmerge:
- go build -o bin/gocovmerge github.com/wadey/gocovmerge
-
-.PHONY: autobahn
-autobahn: clean bin/reporter
- ./autobahn/script/test.sh --build
- bin/reporter $(PWD)/autobahn/report/index.json
-
-test:
- go test -coverprofile=ws.coverage .
- go test -coverprofile=wsutil.coverage ./wsutil
-
-cover: bin/gocovmerge test autobahn
- bin/gocovmerge ws.coverage wsutil.coverage autobahn/report/server.coverage > total.coverage
-
-benchcmp: BENCH_BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
-benchcmp: BENCH_OLD:=$(shell mktemp -t old.XXXX)
-benchcmp: BENCH_NEW:=$(shell mktemp -t new.XXXX)
-benchcmp:
- if [ ! -z "$(shell git status -s)" ]; then\
- echo "could not compare with $(BENCH_BASE) – found unstaged changes";\
- exit 1;\
- fi;\
- if [ "$(BENCH_BRANCH)" == "$(BENCH_BASE)" ]; then\
- echo "comparing the same branches";\
- exit 1;\
- fi;\
- echo "benchmarking $(BENCH_BRANCH)...";\
- go test -run=none -bench=$(BENCH) -benchmem > $(BENCH_NEW);\
- echo "benchmarking $(BENCH_BASE)...";\
- git checkout -q $(BENCH_BASE);\
- go test -run=none -bench=$(BENCH) -benchmem > $(BENCH_OLD);\
- git checkout -q $(BENCH_BRANCH);\
- echo "\nresults:";\
- echo "========\n";\
- benchcmp $(BENCH_OLD) $(BENCH_NEW);\
-
diff --git a/vendor/github.com/gobwas/ws/README.md b/vendor/github.com/gobwas/ws/README.md
deleted file mode 100644
index 74acd78bd08..00000000000
--- a/vendor/github.com/gobwas/ws/README.md
+++ /dev/null
@@ -1,360 +0,0 @@
-# ws
-
-[![GoDoc][godoc-image]][godoc-url]
-[![Travis][travis-image]][travis-url]
-
-> [RFC6455][rfc-url] WebSocket implementation in Go.
-
-# Features
-
-- Zero-copy upgrade
-- No intermediate allocations during I/O
-- Low-level API which allows to build your own logic of packet handling and
- buffers reuse
-- High-level wrappers and helpers around API in `wsutil` package, which allow
- to start fast without digging the protocol internals
-
-# Documentation
-
-[GoDoc][godoc-url].
-
-# Why
-
-Existing WebSocket implementations do not allow users to reuse I/O buffers
-between connections in clear way. This library aims to export efficient
-low-level interface for working with the protocol without forcing only one way
-it could be used.
-
-By the way, if you want get the higher-level tools, you can use `wsutil`
-package.
-
-# Status
-
-Library is tagged as `v1*` so its API must not be broken during some
-improvements or refactoring.
-
-This implementation of RFC6455 passes [Autobahn Test
-Suite](https://github.com/crossbario/autobahn-testsuite) and currently has
-about 78% coverage.
-
-# Examples
-
-Example applications using `ws` are developed in separate repository
-[ws-examples](https://github.com/gobwas/ws-examples).
-
-# Usage
-
-The higher-level example of WebSocket echo server:
-
-```go
-package main
-
-import (
- "net/http"
-
- "github.com/gobwas/ws"
- "github.com/gobwas/ws/wsutil"
-)
-
-func main() {
- http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- conn, _, _, err := ws.UpgradeHTTP(r, w)
- if err != nil {
- // handle error
- }
- go func() {
- defer conn.Close()
-
- for {
- msg, op, err := wsutil.ReadClientData(conn)
- if err != nil {
- // handle error
- }
- err = wsutil.WriteServerMessage(conn, op, msg)
- if err != nil {
- // handle error
- }
- }
- }()
- }))
-}
-```
-
-Lower-level, but still high-level example:
-
-
-```go
-import (
- "net/http"
- "io"
-
- "github.com/gobwas/ws"
- "github.com/gobwas/ws/wsutil"
-)
-
-func main() {
- http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- conn, _, _, err := ws.UpgradeHTTP(r, w)
- if err != nil {
- // handle error
- }
- go func() {
- defer conn.Close()
-
- var (
- state = ws.StateServerSide
- reader = wsutil.NewReader(conn, state)
- writer = wsutil.NewWriter(conn, state, ws.OpText)
- )
- for {
- header, err := reader.NextFrame()
- if err != nil {
- // handle error
- }
-
- // Reset writer to write frame with right operation code.
- writer.Reset(conn, state, header.OpCode)
-
- if _, err = io.Copy(writer, reader); err != nil {
- // handle error
- }
- if err = writer.Flush(); err != nil {
- // handle error
- }
- }
- }()
- }))
-}
-```
-
-We can apply the same pattern to read and write structured responses through a JSON encoder and decoder.:
-
-```go
- ...
- var (
- r = wsutil.NewReader(conn, ws.StateServerSide)
- w = wsutil.NewWriter(conn, ws.StateServerSide, ws.OpText)
- decoder = json.NewDecoder(r)
- encoder = json.NewEncoder(w)
- )
- for {
- hdr, err = r.NextFrame()
- if err != nil {
- return err
- }
- if hdr.OpCode == ws.OpClose {
- return io.EOF
- }
- var req Request
- if err := decoder.Decode(&req); err != nil {
- return err
- }
- var resp Response
- if err := encoder.Encode(&resp); err != nil {
- return err
- }
- if err = w.Flush(); err != nil {
- return err
- }
- }
- ...
-```
-
-The lower-level example without `wsutil`:
-
-```go
-package main
-
-import (
- "net"
- "io"
-
- "github.com/gobwas/ws"
-)
-
-func main() {
- ln, err := net.Listen("tcp", "localhost:8080")
- if err != nil {
- log.Fatal(err)
- }
-
- for {
- conn, err := ln.Accept()
- if err != nil {
- // handle error
- }
- _, err = ws.Upgrade(conn)
- if err != nil {
- // handle error
- }
-
- go func() {
- defer conn.Close()
-
- for {
- header, err := ws.ReadHeader(conn)
- if err != nil {
- // handle error
- }
-
- payload := make([]byte, header.Length)
- _, err = io.ReadFull(conn, payload)
- if err != nil {
- // handle error
- }
- if header.Masked {
- ws.Cipher(payload, header.Mask, 0)
- }
-
- // Reset the Masked flag, server frames must not be masked as
- // RFC6455 says.
- header.Masked = false
-
- if err := ws.WriteHeader(conn, header); err != nil {
- // handle error
- }
- if _, err := conn.Write(payload); err != nil {
- // handle error
- }
-
- if header.OpCode == ws.OpClose {
- return
- }
- }
- }()
- }
-}
-```
-
-# Zero-copy upgrade
-
-Zero-copy upgrade helps to avoid unnecessary allocations and copying while
-handling HTTP Upgrade request.
-
-Processing of all non-websocket headers is made in place with use of registered
-user callbacks whose arguments are only valid until callback returns.
-
-The simple example looks like this:
-
-```go
-package main
-
-import (
- "net"
- "log"
-
- "github.com/gobwas/ws"
-)
-
-func main() {
- ln, err := net.Listen("tcp", "localhost:8080")
- if err != nil {
- log.Fatal(err)
- }
- u := ws.Upgrader{
- OnHeader: func(key, value []byte) (err error) {
- log.Printf("non-websocket header: %q=%q", key, value)
- return
- },
- }
- for {
- conn, err := ln.Accept()
- if err != nil {
- // handle error
- }
-
- _, err = u.Upgrade(conn)
- if err != nil {
- // handle error
- }
- }
-}
-```
-
-Usage of `ws.Upgrader` here brings ability to control incoming connections on
-tcp level and simply not to accept them by some logic.
-
-Zero-copy upgrade is for high-load services which have to control many
-resources such as connections buffers.
-
-The real life example could be like this:
-
-```go
-package main
-
-import (
- "fmt"
- "io"
- "log"
- "net"
- "net/http"
- "runtime"
-
- "github.com/gobwas/httphead"
- "github.com/gobwas/ws"
-)
-
-func main() {
- ln, err := net.Listen("tcp", "localhost:8080")
- if err != nil {
- // handle error
- }
-
- // Prepare handshake header writer from http.Header mapping.
- header := ws.HandshakeHeaderHTTP(http.Header{
- "X-Go-Version": []string{runtime.Version()},
- })
-
- u := ws.Upgrader{
- OnHost: func(host []byte) error {
- if string(host) == "github.com" {
- return nil
- }
- return ws.RejectConnectionError(
- ws.RejectionStatus(403),
- ws.RejectionHeader(ws.HandshakeHeaderString(
- "X-Want-Host: github.com\r\n",
- )),
- )
- },
- OnHeader: func(key, value []byte) error {
- if string(key) != "Cookie" {
- return nil
- }
- ok := httphead.ScanCookie(value, func(key, value []byte) bool {
- // Check session here or do some other stuff with cookies.
- // Maybe copy some values for future use.
- return true
- })
- if ok {
- return nil
- }
- return ws.RejectConnectionError(
- ws.RejectionReason("bad cookie"),
- ws.RejectionStatus(400),
- )
- },
- OnBeforeUpgrade: func() (ws.HandshakeHeader, error) {
- return header, nil
- },
- }
- for {
- conn, err := ln.Accept()
- if err != nil {
- log.Fatal(err)
- }
- _, err = u.Upgrade(conn)
- if err != nil {
- log.Printf("upgrade error: %s", err)
- }
- }
-}
-```
-
-
-
-[rfc-url]: https://tools.ietf.org/html/rfc6455
-[godoc-image]: https://godoc.org/github.com/gobwas/ws?status.svg
-[godoc-url]: https://godoc.org/github.com/gobwas/ws
-[travis-image]: https://travis-ci.org/gobwas/ws.svg?branch=master
-[travis-url]: https://travis-ci.org/gobwas/ws
diff --git a/vendor/github.com/gobwas/ws/check.go b/vendor/github.com/gobwas/ws/check.go
deleted file mode 100644
index 2288e6a2e28..00000000000
--- a/vendor/github.com/gobwas/ws/check.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package ws
-
-import "unicode/utf8"
-
-// State represents state of websocket endpoint.
-// It used by some functions to be more strict when checking compatibility with RFC6455.
-type State uint8
-
-const (
- // StateServerSide means that endpoint (caller) is a server.
- StateServerSide State = 0x1 << iota
- // StateClientSide means that endpoint (caller) is a client.
- StateClientSide
- // StateExtended means that extension was negotiated during handshake.
- StateExtended
- // StateFragmented means that endpoint (caller) has received fragmented
- // frame and waits for continuation parts.
- StateFragmented
-)
-
-// Is checks whether the s has v enabled.
-func (s State) Is(v State) bool {
- return uint8(s)&uint8(v) != 0
-}
-
-// Set enables v state on s.
-func (s State) Set(v State) State {
- return s | v
-}
-
-// Clear disables v state on s.
-func (s State) Clear(v State) State {
- return s & (^v)
-}
-
-// ServerSide reports whether states represents server side.
-func (s State) ServerSide() bool { return s.Is(StateServerSide) }
-
-// ClientSide reports whether state represents client side.
-func (s State) ClientSide() bool { return s.Is(StateClientSide) }
-
-// Extended reports whether state is extended.
-func (s State) Extended() bool { return s.Is(StateExtended) }
-
-// Fragmented reports whether state is fragmented.
-func (s State) Fragmented() bool { return s.Is(StateFragmented) }
-
-// ProtocolError describes error during checking/parsing websocket frames or
-// headers.
-type ProtocolError string
-
-// Error implements error interface.
-func (p ProtocolError) Error() string { return string(p) }
-
-// Errors used by the protocol checkers.
-var (
- ErrProtocolOpCodeReserved = ProtocolError("use of reserved op code")
- ErrProtocolControlPayloadOverflow = ProtocolError("control frame payload limit exceeded")
- ErrProtocolControlNotFinal = ProtocolError("control frame is not final")
- ErrProtocolNonZeroRsv = ProtocolError("non-zero rsv bits with no extension negotiated")
- ErrProtocolMaskRequired = ProtocolError("frames from client to server must be masked")
- ErrProtocolMaskUnexpected = ProtocolError("frames from server to client must be not masked")
- ErrProtocolContinuationExpected = ProtocolError("unexpected non-continuation data frame")
- ErrProtocolContinuationUnexpected = ProtocolError("unexpected continuation data frame")
- ErrProtocolStatusCodeNotInUse = ProtocolError("status code is not in use")
- ErrProtocolStatusCodeApplicationLevel = ProtocolError("status code is only application level")
- ErrProtocolStatusCodeNoMeaning = ProtocolError("status code has no meaning yet")
- ErrProtocolStatusCodeUnknown = ProtocolError("status code is not defined in spec")
- ErrProtocolInvalidUTF8 = ProtocolError("invalid utf8 sequence in close reason")
-)
-
-// CheckHeader checks h to contain valid header data for given state s.
-//
-// Note that zero state (0) means that state is clean,
-// neither server or client side, nor fragmented, nor extended.
-func CheckHeader(h Header, s State) error {
- if h.OpCode.IsReserved() {
- return ErrProtocolOpCodeReserved
- }
- if h.OpCode.IsControl() {
- if h.Length > MaxControlFramePayloadSize {
- return ErrProtocolControlPayloadOverflow
- }
- if !h.Fin {
- return ErrProtocolControlNotFinal
- }
- }
-
- switch {
- // [RFC6455]: MUST be 0 unless an extension is negotiated that defines meanings for
- // non-zero values. If a nonzero value is received and none of the
- // negotiated extensions defines the meaning of such a nonzero value, the
- // receiving endpoint MUST _Fail the WebSocket Connection_.
- case h.Rsv != 0 && !s.Extended():
- return ErrProtocolNonZeroRsv
-
- // [RFC6455]: The server MUST close the connection upon receiving a frame that is not masked.
- // In this case, a server MAY send a Close frame with a status code of 1002 (protocol error)
- // as defined in Section 7.4.1. A server MUST NOT mask any frames that it sends to the client.
- // A client MUST close a connection if it detects a masked frame. In this case, it MAY use the
- // status code 1002 (protocol error) as defined in Section 7.4.1.
- case s.ServerSide() && !h.Masked:
- return ErrProtocolMaskRequired
- case s.ClientSide() && h.Masked:
- return ErrProtocolMaskUnexpected
-
- // [RFC6455]: See detailed explanation in 5.4 section.
- case s.Fragmented() && !h.OpCode.IsControl() && h.OpCode != OpContinuation:
- return ErrProtocolContinuationExpected
- case !s.Fragmented() && h.OpCode == OpContinuation:
- return ErrProtocolContinuationUnexpected
- }
-
- return nil
-}
-
-// CheckCloseFrameData checks received close information
-// to be valid RFC6455 compatible close info.
-//
-// Note that code.Empty() or code.IsAppLevel() will raise error.
-//
-// If endpoint sends close frame without status code (with frame.Length = 0),
-// application should not check its payload.
-func CheckCloseFrameData(code StatusCode, reason string) error {
- switch {
- case code.IsNotUsed():
- return ErrProtocolStatusCodeNotInUse
-
- case code.IsProtocolReserved():
- return ErrProtocolStatusCodeApplicationLevel
-
- case code == StatusNoMeaningYet:
- return ErrProtocolStatusCodeNoMeaning
-
- case code.IsProtocolSpec() && !code.IsProtocolDefined():
- return ErrProtocolStatusCodeUnknown
-
- case !utf8.ValidString(reason):
- return ErrProtocolInvalidUTF8
-
- default:
- return nil
- }
-}
diff --git a/vendor/github.com/gobwas/ws/cipher.go b/vendor/github.com/gobwas/ws/cipher.go
deleted file mode 100644
index 7f2e1e2e956..00000000000
--- a/vendor/github.com/gobwas/ws/cipher.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package ws
-
-import (
- "unsafe"
-)
-
-// Cipher applies XOR cipher to the payload using mask.
-// Offset is used to cipher chunked data (e.g. in io.Reader implementations).
-//
-// To convert masked data into unmasked data, or vice versa, the following
-// algorithm is applied. The same algorithm applies regardless of the
-// direction of the translation, e.g., the same steps are applied to
-// mask the data as to unmask the data.
-func Cipher(payload []byte, mask [4]byte, offset int) {
- n := len(payload)
- if n < 8 {
- for i := 0; i < n; i++ {
- payload[i] ^= mask[(offset+i)%4]
- }
- return
- }
-
- // Calculate position in mask due to previously processed bytes number.
- mpos := offset % 4
- // Count number of bytes will processed one by one from the beginning of payload.
- ln := remain[mpos]
- // Count number of bytes will processed one by one from the end of payload.
- // This is done to process payload by 8 bytes in each iteration of main loop.
- rn := (n - ln) % 8
-
- for i := 0; i < ln; i++ {
- payload[i] ^= mask[(mpos+i)%4]
- }
- for i := n - rn; i < n; i++ {
- payload[i] ^= mask[(mpos+i)%4]
- }
-
- // We should cast mask to uint32 with unsafe instead of encoding.BigEndian
- // to avoid care of os dependent byte order. That is, on any endianess mask
- // and payload will be presented with the same order. In other words, we
- // could not use encoding.BigEndian on xoring payload as uint64.
- m := *(*uint32)(unsafe.Pointer(&mask))
- m2 := uint64(m)<<32 | uint64(m)
-
- // Skip already processed right part.
- // Get number of uint64 parts remaining to process.
- n = (n - ln - rn) >> 3
- for i := 0; i < n; i++ {
- v := (*uint64)(unsafe.Pointer(&payload[ln+(i<<3)]))
- *v = *v ^ m2
- }
-}
-
-// remain maps position in masking key [0,4) to number
-// of bytes that need to be processed manually inside Cipher().
-var remain = [4]int{0, 3, 2, 1}
diff --git a/vendor/github.com/gobwas/ws/dialer.go b/vendor/github.com/gobwas/ws/dialer.go
deleted file mode 100644
index b099a47670e..00000000000
--- a/vendor/github.com/gobwas/ws/dialer.go
+++ /dev/null
@@ -1,556 +0,0 @@
-package ws
-
-import (
- "bufio"
- "bytes"
- "context"
- "crypto/tls"
- "fmt"
- "io"
- "net"
- "net/url"
- "strconv"
- "strings"
- "time"
-
- "github.com/gobwas/httphead"
- "github.com/gobwas/pool/pbufio"
-)
-
-// Constants used by Dialer.
-const (
- DefaultClientReadBufferSize = 4096
- DefaultClientWriteBufferSize = 4096
-)
-
-// Handshake represents handshake result.
-type Handshake struct {
- // Protocol is the subprotocol selected during handshake.
- Protocol string
-
- // Extensions is the list of negotiated extensions.
- Extensions []httphead.Option
-}
-
-// Errors used by the websocket client.
-var (
- ErrHandshakeBadStatus = fmt.Errorf("unexpected http status")
- ErrHandshakeBadSubProtocol = fmt.Errorf("unexpected protocol in %q header", headerSecProtocol)
- ErrHandshakeBadExtensions = fmt.Errorf("unexpected extensions in %q header", headerSecProtocol)
-)
-
-// DefaultDialer is dialer that holds no options and is used by Dial function.
-var DefaultDialer Dialer
-
-// Dial is like Dialer{}.Dial().
-func Dial(ctx context.Context, urlstr string) (net.Conn, *bufio.Reader, Handshake, error) {
- return DefaultDialer.Dial(ctx, urlstr)
-}
-
-// Dialer contains options for establishing websocket connection to an url.
-type Dialer struct {
- // ReadBufferSize and WriteBufferSize is an I/O buffer sizes.
- // They used to read and write http data while upgrading to WebSocket.
- // Allocated buffers are pooled with sync.Pool to avoid extra allocations.
- //
- // If a size is zero then default value is used.
- ReadBufferSize, WriteBufferSize int
-
- // Timeout is the maximum amount of time a Dial() will wait for a connect
- // and an handshake to complete.
- //
- // The default is no timeout.
- Timeout time.Duration
-
- // Protocols is the list of subprotocols that the client wants to speak,
- // ordered by preference.
- //
- // See https://tools.ietf.org/html/rfc6455#section-4.1
- Protocols []string
-
- // Extensions is the list of extensions that client wants to speak.
- //
- // Note that if server decides to use some of this extensions, Dial() will
- // return Handshake struct containing a slice of items, which are the
- // shallow copies of the items from this list. That is, internals of
- // Extensions items are shared during Dial().
- //
- // See https://tools.ietf.org/html/rfc6455#section-4.1
- // See https://tools.ietf.org/html/rfc6455#section-9.1
- Extensions []httphead.Option
-
- // Header is an optional HandshakeHeader instance that could be used to
- // write additional headers to the handshake request.
- //
- // It used instead of any key-value mappings to avoid allocations in user
- // land.
- Header HandshakeHeader
-
- // OnStatusError is the callback that will be called after receiving non
- // "101 Continue" HTTP response status. It receives an io.Reader object
- // representing server response bytes. That is, it gives ability to parse
- // HTTP response somehow (probably with http.ReadResponse call) and make a
- // decision of further logic.
- //
- // The arguments are only valid until the callback returns.
- OnStatusError func(status int, reason []byte, resp io.Reader)
-
- // OnHeader is the callback that will be called after successful parsing of
- // header, that is not used during WebSocket handshake procedure. That is,
- // it will be called with non-websocket headers, which could be relevant
- // for application-level logic.
- //
- // The arguments are only valid until the callback returns.
- //
- // Returned value could be used to prevent processing response.
- OnHeader func(key, value []byte) (err error)
-
- // NetDial is the function that is used to get plain tcp connection.
- // If it is not nil, then it is used instead of net.Dialer.
- NetDial func(ctx context.Context, network, addr string) (net.Conn, error)
-
- // TLSClient is the callback that will be called after successful dial with
- // received connection and its remote host name. If it is nil, then the
- // default tls.Client() will be used.
- // If it is not nil, then TLSConfig field is ignored.
- TLSClient func(conn net.Conn, hostname string) net.Conn
-
- // TLSConfig is passed to tls.Client() to start TLS over established
- // connection. If TLSClient is not nil, then it is ignored. If TLSConfig is
- // non-nil and its ServerName is empty, then for every Dial() it will be
- // cloned and appropriate ServerName will be set.
- TLSConfig *tls.Config
-
- // WrapConn is the optional callback that will be called when connection is
- // ready for an i/o. That is, it will be called after successful dial and
- // TLS initialization (for "wss" schemes). It may be helpful for different
- // user land purposes such as end to end encryption.
- //
- // Note that for debugging purposes of an http handshake (e.g. sent request
- // and received response), there is an wsutil.DebugDialer struct.
- WrapConn func(conn net.Conn) net.Conn
-}
-
-// Dial connects to the url host and upgrades connection to WebSocket.
-//
-// If server has sent frames right after successful handshake then returned
-// buffer will be non-nil. In other cases buffer is always nil. For better
-// memory efficiency received non-nil bufio.Reader should be returned to the
-// inner pool with PutReader() function after use.
-//
-// Note that Dialer does not implement IDNA (RFC5895) logic as net/http does.
-// If you want to dial non-ascii host name, take care of its name serialization
-// avoiding bad request issues. For more info see net/http Request.Write()
-// implementation, especially cleanHost() function.
-func (d Dialer) Dial(ctx context.Context, urlstr string) (conn net.Conn, br *bufio.Reader, hs Handshake, err error) {
- u, err := url.ParseRequestURI(urlstr)
- if err != nil {
- return
- }
-
- // Prepare context to dial with. Initially it is the same as original, but
- // if d.Timeout is non-zero and points to time that is before ctx.Deadline,
- // we use more shorter context for dial.
- dialctx := ctx
-
- var deadline time.Time
- if t := d.Timeout; t != 0 {
- deadline = time.Now().Add(t)
- if d, ok := ctx.Deadline(); !ok || deadline.Before(d) {
- var cancel context.CancelFunc
- dialctx, cancel = context.WithDeadline(ctx, deadline)
- defer cancel()
- }
- }
- if conn, err = d.dial(dialctx, u); err != nil {
- return
- }
- defer func() {
- if err != nil {
- conn.Close()
- }
- }()
- if ctx == context.Background() {
- // No need to start I/O interrupter goroutine which is not zero-cost.
- conn.SetDeadline(deadline)
- defer conn.SetDeadline(noDeadline)
- } else {
- // Context could be canceled or its deadline could be exceeded.
- // Start the interrupter goroutine to handle context cancelation.
- done := setupContextDeadliner(ctx, conn)
- defer func() {
- // Map Upgrade() error to a possible context expiration error. That
- // is, even if Upgrade() err is nil, context could be already
- // expired and connection be "poisoned" by SetDeadline() call.
- // In that case we must not return ctx.Err() error.
- done(&err)
- }()
- }
-
- br, hs, err = d.Upgrade(conn, u)
-
- return
-}
-
-var (
- // netEmptyDialer is a net.Dialer without options, used in Dialer.dial() if
- // Dialer.NetDial is not provided.
- netEmptyDialer net.Dialer
- // tlsEmptyConfig is an empty tls.Config used as default one.
- tlsEmptyConfig tls.Config
-)
-
-func tlsDefaultConfig() *tls.Config {
- return &tlsEmptyConfig
-}
-
-func hostport(host string, defaultPort string) (hostname, addr string) {
- var (
- colon = strings.LastIndexByte(host, ':')
- bracket = strings.IndexByte(host, ']')
- )
- if colon > bracket {
- return host[:colon], host
- }
- return host, host + defaultPort
-}
-
-func (d Dialer) dial(ctx context.Context, u *url.URL) (conn net.Conn, err error) {
- dial := d.NetDial
- if dial == nil {
- dial = netEmptyDialer.DialContext
- }
- switch u.Scheme {
- case "ws":
- _, addr := hostport(u.Host, ":80")
- conn, err = dial(ctx, "tcp", addr)
- case "wss":
- hostname, addr := hostport(u.Host, ":443")
- conn, err = dial(ctx, "tcp", addr)
- if err != nil {
- return
- }
- tlsClient := d.TLSClient
- if tlsClient == nil {
- tlsClient = d.tlsClient
- }
- conn = tlsClient(conn, hostname)
- default:
- return nil, fmt.Errorf("unexpected websocket scheme: %q", u.Scheme)
- }
- if wrap := d.WrapConn; wrap != nil {
- conn = wrap(conn)
- }
- return
-}
-
-func (d Dialer) tlsClient(conn net.Conn, hostname string) net.Conn {
- config := d.TLSConfig
- if config == nil {
- config = tlsDefaultConfig()
- }
- if config.ServerName == "" {
- config = tlsCloneConfig(config)
- config.ServerName = hostname
- }
- // Do not make conn.Handshake() here because downstairs we will prepare
- // i/o on this conn with proper context's timeout handling.
- return tls.Client(conn, config)
-}
-
-var (
- // This variables are set like in net/net.go.
- // noDeadline is just zero value for readability.
- noDeadline = time.Time{}
- // aLongTimeAgo is a non-zero time, far in the past, used for immediate
- // cancelation of dials.
- aLongTimeAgo = time.Unix(42, 0)
-)
-
-// Upgrade writes an upgrade request to the given io.ReadWriter conn at given
-// url u and reads a response from it.
-//
-// It is a caller responsibility to manage I/O deadlines on conn.
-//
-// It returns handshake info and some bytes which could be written by the peer
-// right after response and be caught by us during buffered read.
-func (d Dialer) Upgrade(conn io.ReadWriter, u *url.URL) (br *bufio.Reader, hs Handshake, err error) {
- // headerSeen constants helps to report whether or not some header was seen
- // during reading request bytes.
- const (
- headerSeenUpgrade = 1 << iota
- headerSeenConnection
- headerSeenSecAccept
-
- // headerSeenAll is the value that we expect to receive at the end of
- // headers read/parse loop.
- headerSeenAll = 0 |
- headerSeenUpgrade |
- headerSeenConnection |
- headerSeenSecAccept
- )
-
- br = pbufio.GetReader(conn,
- nonZero(d.ReadBufferSize, DefaultClientReadBufferSize),
- )
- bw := pbufio.GetWriter(conn,
- nonZero(d.WriteBufferSize, DefaultClientWriteBufferSize),
- )
- defer func() {
- pbufio.PutWriter(bw)
- if br.Buffered() == 0 || err != nil {
- // Server does not wrote additional bytes to the connection or
- // error occurred. That is, no reason to return buffer.
- pbufio.PutReader(br)
- br = nil
- }
- }()
-
- nonce := make([]byte, nonceSize)
- initNonce(nonce)
-
- httpWriteUpgradeRequest(bw, u, nonce, d.Protocols, d.Extensions, d.Header)
- if err = bw.Flush(); err != nil {
- return
- }
-
- // Read HTTP status line like "HTTP/1.1 101 Switching Protocols".
- sl, err := readLine(br)
- if err != nil {
- return
- }
- // Begin validation of the response.
- // See https://tools.ietf.org/html/rfc6455#section-4.2.2
- // Parse request line data like HTTP version, uri and method.
- resp, err := httpParseResponseLine(sl)
- if err != nil {
- return
- }
- // Even if RFC says "1.1 or higher" without mentioning the part of the
- // version, we apply it only to minor part.
- if resp.major != 1 || resp.minor < 1 {
- err = ErrHandshakeBadProtocol
- return
- }
- if resp.status != 101 {
- err = StatusError(resp.status)
- if onStatusError := d.OnStatusError; onStatusError != nil {
- // Invoke callback with multireader of status-line bytes br.
- onStatusError(resp.status, resp.reason,
- io.MultiReader(
- bytes.NewReader(sl),
- strings.NewReader(crlf),
- br,
- ),
- )
- }
- return
- }
- // If response status is 101 then we expect all technical headers to be
- // valid. If not, then we stop processing response without giving user
- // ability to read non-technical headers. That is, we do not distinguish
- // technical errors (such as parsing error) and protocol errors.
- var headerSeen byte
- for {
- line, e := readLine(br)
- if e != nil {
- err = e
- return
- }
- if len(line) == 0 {
- // Blank line, no more lines to read.
- break
- }
-
- k, v, ok := httpParseHeaderLine(line)
- if !ok {
- err = ErrMalformedResponse
- return
- }
-
- switch btsToString(k) {
- case headerUpgradeCanonical:
- headerSeen |= headerSeenUpgrade
- if !bytes.Equal(v, specHeaderValueUpgrade) && !btsEqualFold(v, specHeaderValueUpgrade) {
- err = ErrHandshakeBadUpgrade
- return
- }
-
- case headerConnectionCanonical:
- headerSeen |= headerSeenConnection
- // Note that as RFC6455 says:
- // > A |Connection| header field with value "Upgrade".
- // That is, in server side, "Connection" header could contain
- // multiple token. But in response it must contains exactly one.
- if !bytes.Equal(v, specHeaderValueConnection) && !btsEqualFold(v, specHeaderValueConnection) {
- err = ErrHandshakeBadConnection
- return
- }
-
- case headerSecAcceptCanonical:
- headerSeen |= headerSeenSecAccept
- if !checkAcceptFromNonce(v, nonce) {
- err = ErrHandshakeBadSecAccept
- return
- }
-
- case headerSecProtocolCanonical:
- // RFC6455 1.3:
- // "The server selects one or none of the acceptable protocols
- // and echoes that value in its handshake to indicate that it has
- // selected that protocol."
- for _, want := range d.Protocols {
- if string(v) == want {
- hs.Protocol = want
- break
- }
- }
- if hs.Protocol == "" {
- // Server echoed subprotocol that is not present in client
- // requested protocols.
- err = ErrHandshakeBadSubProtocol
- return
- }
-
- case headerSecExtensionsCanonical:
- hs.Extensions, err = matchSelectedExtensions(v, d.Extensions, hs.Extensions)
- if err != nil {
- return
- }
-
- default:
- if onHeader := d.OnHeader; onHeader != nil {
- if e := onHeader(k, v); e != nil {
- err = e
- return
- }
- }
- }
- }
- if err == nil && headerSeen != headerSeenAll {
- switch {
- case headerSeen&headerSeenUpgrade == 0:
- err = ErrHandshakeBadUpgrade
- case headerSeen&headerSeenConnection == 0:
- err = ErrHandshakeBadConnection
- case headerSeen&headerSeenSecAccept == 0:
- err = ErrHandshakeBadSecAccept
- default:
- panic("unknown headers state")
- }
- }
- return
-}
-
-// PutReader returns bufio.Reader instance to the inner reuse pool.
-// It is useful in rare cases, when Dialer.Dial() returns non-nil buffer which
-// contains unprocessed buffered data, that was sent by the server quickly
-// right after handshake.
-func PutReader(br *bufio.Reader) {
- pbufio.PutReader(br)
-}
-
-// StatusError contains an unexpected status-line code from the server.
-type StatusError int
-
-func (s StatusError) Error() string {
- return "unexpected HTTP response status: " + strconv.Itoa(int(s))
-}
-
-func isTimeoutError(err error) bool {
- t, ok := err.(net.Error)
- return ok && t.Timeout()
-}
-
-func matchSelectedExtensions(selected []byte, wanted, received []httphead.Option) ([]httphead.Option, error) {
- if len(selected) == 0 {
- return received, nil
- }
- var (
- index int
- option httphead.Option
- err error
- )
- index = -1
- match := func() (ok bool) {
- for _, want := range wanted {
- if option.Equal(want) {
- // Check parsed extension to be present in client
- // requested extensions. We move matched extension
- // from client list to avoid allocation.
- received = append(received, want)
- return true
- }
- }
- return false
- }
- ok := httphead.ScanOptions(selected, func(i int, name, attr, val []byte) httphead.Control {
- if i != index {
- // Met next option.
- index = i
- if i != 0 && !match() {
- // Server returned non-requested extension.
- err = ErrHandshakeBadExtensions
- return httphead.ControlBreak
- }
- option = httphead.Option{Name: name}
- }
- if attr != nil {
- option.Parameters.Set(attr, val)
- }
- return httphead.ControlContinue
- })
- if !ok {
- err = ErrMalformedResponse
- return received, err
- }
- if !match() {
- return received, ErrHandshakeBadExtensions
- }
- return received, err
-}
-
-// setupContextDeadliner is a helper function that starts connection I/O
-// interrupter goroutine.
-//
-// Started goroutine calls SetDeadline() with long time ago value when context
-// become expired to make any I/O operations failed. It returns done function
-// that stops started goroutine and maps error received from conn I/O methods
-// to possible context expiration error.
-//
-// In concern with possible SetDeadline() call inside interrupter goroutine,
-// caller passes pointer to its I/O error (even if it is nil) to done(&err).
-// That is, even if I/O error is nil, context could be already expired and
-// connection "poisoned" by SetDeadline() call. In that case done(&err) will
-// store at *err ctx.Err() result. If err is caused not by timeout, it will
-// leaved untouched.
-func setupContextDeadliner(ctx context.Context, conn net.Conn) (done func(*error)) {
- var (
- quit = make(chan struct{})
- interrupt = make(chan error, 1)
- )
- go func() {
- select {
- case <-quit:
- interrupt <- nil
- case <-ctx.Done():
- // Cancel i/o immediately.
- conn.SetDeadline(aLongTimeAgo)
- interrupt <- ctx.Err()
- }
- }()
- return func(err *error) {
- close(quit)
- // If ctx.Err() is non-nil and the original err is net.Error with
- // Timeout() == true, then it means that I/O was canceled by us by
- // SetDeadline(aLongTimeAgo) call, or by somebody else previously
- // by conn.SetDeadline(x).
- //
- // Even on race condition when both deadlines are expired
- // (SetDeadline() made not by us and context's), we prefer ctx.Err() to
- // be returned.
- if ctxErr := <-interrupt; ctxErr != nil && (*err == nil || isTimeoutError(*err)) {
- *err = ctxErr
- }
- }
-}
diff --git a/vendor/github.com/gobwas/ws/dialer_tls_go17.go b/vendor/github.com/gobwas/ws/dialer_tls_go17.go
deleted file mode 100644
index b606e0ad909..00000000000
--- a/vendor/github.com/gobwas/ws/dialer_tls_go17.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// +build !go1.8
-
-package ws
-
-import "crypto/tls"
-
-func tlsCloneConfig(c *tls.Config) *tls.Config {
- // NOTE: we copying SessionTicketsDisabled and SessionTicketKey here
- // without calling inner c.initOnceServer somehow because we only could get
- // here from the ws.Dialer code, which is obviously a client and makes
- // tls.Client() when it gets new net.Conn.
- return &tls.Config{
- Rand: c.Rand,
- Time: c.Time,
- Certificates: c.Certificates,
- NameToCertificate: c.NameToCertificate,
- GetCertificate: c.GetCertificate,
- RootCAs: c.RootCAs,
- NextProtos: c.NextProtos,
- ServerName: c.ServerName,
- ClientAuth: c.ClientAuth,
- ClientCAs: c.ClientCAs,
- InsecureSkipVerify: c.InsecureSkipVerify,
- CipherSuites: c.CipherSuites,
- PreferServerCipherSuites: c.PreferServerCipherSuites,
- SessionTicketsDisabled: c.SessionTicketsDisabled,
- SessionTicketKey: c.SessionTicketKey,
- ClientSessionCache: c.ClientSessionCache,
- MinVersion: c.MinVersion,
- MaxVersion: c.MaxVersion,
- CurvePreferences: c.CurvePreferences,
- DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
- Renegotiation: c.Renegotiation,
- }
-}
diff --git a/vendor/github.com/gobwas/ws/dialer_tls_go18.go b/vendor/github.com/gobwas/ws/dialer_tls_go18.go
deleted file mode 100644
index a6704d5173a..00000000000
--- a/vendor/github.com/gobwas/ws/dialer_tls_go18.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// +build go1.8
-
-package ws
-
-import "crypto/tls"
-
-func tlsCloneConfig(c *tls.Config) *tls.Config {
- return c.Clone()
-}
diff --git a/vendor/github.com/gobwas/ws/errors.go b/vendor/github.com/gobwas/ws/errors.go
deleted file mode 100644
index 48fce3b72c1..00000000000
--- a/vendor/github.com/gobwas/ws/errors.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package ws
-
-// RejectOption represents an option used to control the way connection is
-// rejected.
-type RejectOption func(*rejectConnectionError)
-
-// RejectionReason returns an option that makes connection to be rejected with
-// given reason.
-func RejectionReason(reason string) RejectOption {
- return func(err *rejectConnectionError) {
- err.reason = reason
- }
-}
-
-// RejectionStatus returns an option that makes connection to be rejected with
-// given HTTP status code.
-func RejectionStatus(code int) RejectOption {
- return func(err *rejectConnectionError) {
- err.code = code
- }
-}
-
-// RejectionHeader returns an option that makes connection to be rejected with
-// given HTTP headers.
-func RejectionHeader(h HandshakeHeader) RejectOption {
- return func(err *rejectConnectionError) {
- err.header = h
- }
-}
-
-// RejectConnectionError constructs an error that could be used to control the way
-// handshake is rejected by Upgrader.
-func RejectConnectionError(options ...RejectOption) error {
- err := new(rejectConnectionError)
- for _, opt := range options {
- opt(err)
- }
- return err
-}
-
-// rejectConnectionError represents a rejection of upgrade error.
-//
-// It can be returned by Upgrader's On* hooks to control the way WebSocket
-// handshake is rejected.
-type rejectConnectionError struct {
- reason string
- code int
- header HandshakeHeader
-}
-
-// Error implements error interface.
-func (r *rejectConnectionError) Error() string {
- return r.reason
-}
diff --git a/vendor/github.com/gobwas/ws/frame.go b/vendor/github.com/gobwas/ws/frame.go
deleted file mode 100644
index d8bdcea99d4..00000000000
--- a/vendor/github.com/gobwas/ws/frame.go
+++ /dev/null
@@ -1,391 +0,0 @@
-package ws
-
-import (
- "bytes"
- "encoding/binary"
- "math/rand"
-)
-
-// Constants defined by specification.
-const (
- // All control frames MUST have a payload length of 125 bytes or less and MUST NOT be fragmented.
- MaxControlFramePayloadSize = 125
-)
-
-// OpCode represents operation code.
-type OpCode byte
-
-// Operation codes defined by specification.
-// See https://tools.ietf.org/html/rfc6455#section-5.2
-const (
- OpContinuation OpCode = 0x0
- OpText OpCode = 0x1
- OpBinary OpCode = 0x2
- OpClose OpCode = 0x8
- OpPing OpCode = 0x9
- OpPong OpCode = 0xa
-)
-
-// IsControl checks whether the c is control operation code.
-// See https://tools.ietf.org/html/rfc6455#section-5.5
-func (c OpCode) IsControl() bool {
- // RFC6455: Control frames are identified by opcodes where
- // the most significant bit of the opcode is 1.
- //
- // Note that OpCode is only 4 bit length.
- return c&0x8 != 0
-}
-
-// IsData checks whether the c is data operation code.
-// See https://tools.ietf.org/html/rfc6455#section-5.6
-func (c OpCode) IsData() bool {
- // RFC6455: Data frames (e.g., non-control frames) are identified by opcodes
- // where the most significant bit of the opcode is 0.
- //
- // Note that OpCode is only 4 bit length.
- return c&0x8 == 0
-}
-
-// IsReserved checks whether the c is reserved operation code.
-// See https://tools.ietf.org/html/rfc6455#section-5.2
-func (c OpCode) IsReserved() bool {
- // RFC6455:
- // %x3-7 are reserved for further non-control frames
- // %xB-F are reserved for further control frames
- return (0x3 <= c && c <= 0x7) || (0xb <= c && c <= 0xf)
-}
-
-// StatusCode represents the encoded reason for closure of websocket connection.
-//
-// There are few helper methods on StatusCode that helps to define a range in
-// which given code is lay in. accordingly to ranges defined in specification.
-//
-// See https://tools.ietf.org/html/rfc6455#section-7.4
-type StatusCode uint16
-
-// StatusCodeRange describes range of StatusCode values.
-type StatusCodeRange struct {
- Min, Max StatusCode
-}
-
-// Status code ranges defined by specification.
-// See https://tools.ietf.org/html/rfc6455#section-7.4.2
-var (
- StatusRangeNotInUse = StatusCodeRange{0, 999}
- StatusRangeProtocol = StatusCodeRange{1000, 2999}
- StatusRangeApplication = StatusCodeRange{3000, 3999}
- StatusRangePrivate = StatusCodeRange{4000, 4999}
-)
-
-// Status codes defined by specification.
-// See https://tools.ietf.org/html/rfc6455#section-7.4.1
-const (
- StatusNormalClosure StatusCode = 1000
- StatusGoingAway StatusCode = 1001
- StatusProtocolError StatusCode = 1002
- StatusUnsupportedData StatusCode = 1003
- StatusNoMeaningYet StatusCode = 1004
- StatusInvalidFramePayloadData StatusCode = 1007
- StatusPolicyViolation StatusCode = 1008
- StatusMessageTooBig StatusCode = 1009
- StatusMandatoryExt StatusCode = 1010
- StatusInternalServerError StatusCode = 1011
- StatusTLSHandshake StatusCode = 1015
-
- // StatusAbnormalClosure is a special code designated for use in
- // applications.
- StatusAbnormalClosure StatusCode = 1006
-
- // StatusNoStatusRcvd is a special code designated for use in applications.
- StatusNoStatusRcvd StatusCode = 1005
-)
-
-// In reports whether the code is defined in given range.
-func (s StatusCode) In(r StatusCodeRange) bool {
- return r.Min <= s && s <= r.Max
-}
-
-// Empty reports whether the code is empty.
-// Empty code has no any meaning neither app level codes nor other.
-// This method is useful just to check that code is golang default value 0.
-func (s StatusCode) Empty() bool {
- return s == 0
-}
-
-// IsNotUsed reports whether the code is predefined in not used range.
-func (s StatusCode) IsNotUsed() bool {
- return s.In(StatusRangeNotInUse)
-}
-
-// IsApplicationSpec reports whether the code should be defined by
-// application, framework or libraries specification.
-func (s StatusCode) IsApplicationSpec() bool {
- return s.In(StatusRangeApplication)
-}
-
-// IsPrivateSpec reports whether the code should be defined privately.
-func (s StatusCode) IsPrivateSpec() bool {
- return s.In(StatusRangePrivate)
-}
-
-// IsProtocolSpec reports whether the code should be defined by protocol specification.
-func (s StatusCode) IsProtocolSpec() bool {
- return s.In(StatusRangeProtocol)
-}
-
-// IsProtocolDefined reports whether the code is already defined by protocol specification.
-func (s StatusCode) IsProtocolDefined() bool {
- switch s {
- case StatusNormalClosure,
- StatusGoingAway,
- StatusProtocolError,
- StatusUnsupportedData,
- StatusInvalidFramePayloadData,
- StatusPolicyViolation,
- StatusMessageTooBig,
- StatusMandatoryExt,
- StatusInternalServerError,
- StatusNoStatusRcvd,
- StatusAbnormalClosure,
- StatusTLSHandshake:
- return true
- }
- return false
-}
-
-// IsProtocolReserved reports whether the code is defined by protocol specification
-// to be reserved only for application usage purpose.
-func (s StatusCode) IsProtocolReserved() bool {
- switch s {
- // [RFC6455]: {1005,1006,1015} is a reserved value and MUST NOT be set as a status code in a
- // Close control frame by an endpoint.
- case StatusNoStatusRcvd, StatusAbnormalClosure, StatusTLSHandshake:
- return true
- default:
- return false
- }
-}
-
-// Compiled control frames for common use cases.
-// For construct-serialize optimizations.
-var (
- CompiledPing = MustCompileFrame(NewPingFrame(nil))
- CompiledPong = MustCompileFrame(NewPongFrame(nil))
- CompiledClose = MustCompileFrame(NewCloseFrame(nil))
-
- CompiledCloseNormalClosure = MustCompileFrame(closeFrameNormalClosure)
- CompiledCloseGoingAway = MustCompileFrame(closeFrameGoingAway)
- CompiledCloseProtocolError = MustCompileFrame(closeFrameProtocolError)
- CompiledCloseUnsupportedData = MustCompileFrame(closeFrameUnsupportedData)
- CompiledCloseNoMeaningYet = MustCompileFrame(closeFrameNoMeaningYet)
- CompiledCloseInvalidFramePayloadData = MustCompileFrame(closeFrameInvalidFramePayloadData)
- CompiledClosePolicyViolation = MustCompileFrame(closeFramePolicyViolation)
- CompiledCloseMessageTooBig = MustCompileFrame(closeFrameMessageTooBig)
- CompiledCloseMandatoryExt = MustCompileFrame(closeFrameMandatoryExt)
- CompiledCloseInternalServerError = MustCompileFrame(closeFrameInternalServerError)
- CompiledCloseTLSHandshake = MustCompileFrame(closeFrameTLSHandshake)
-)
-
-// Header represents websocket frame header.
-// See https://tools.ietf.org/html/rfc6455#section-5.2
-type Header struct {
- Fin bool
- Rsv byte
- OpCode OpCode
- Masked bool
- Mask [4]byte
- Length int64
-}
-
-// Rsv1 reports whether the header has first rsv bit set.
-func (h Header) Rsv1() bool { return h.Rsv&bit5 != 0 }
-
-// Rsv2 reports whether the header has second rsv bit set.
-func (h Header) Rsv2() bool { return h.Rsv&bit6 != 0 }
-
-// Rsv3 reports whether the header has third rsv bit set.
-func (h Header) Rsv3() bool { return h.Rsv&bit7 != 0 }
-
-// Frame represents websocket frame.
-// See https://tools.ietf.org/html/rfc6455#section-5.2
-type Frame struct {
- Header Header
- Payload []byte
-}
-
-// NewFrame creates frame with given operation code,
-// flag of completeness and payload bytes.
-func NewFrame(op OpCode, fin bool, p []byte) Frame {
- return Frame{
- Header: Header{
- Fin: fin,
- OpCode: op,
- Length: int64(len(p)),
- },
- Payload: p,
- }
-}
-
-// NewTextFrame creates text frame with p as payload.
-// Note that p is not copied.
-func NewTextFrame(p []byte) Frame {
- return NewFrame(OpText, true, p)
-}
-
-// NewBinaryFrame creates binary frame with p as payload.
-// Note that p is not copied.
-func NewBinaryFrame(p []byte) Frame {
- return NewFrame(OpBinary, true, p)
-}
-
-// NewPingFrame creates ping frame with p as payload.
-// Note that p is not copied.
-// Note that p must have length of MaxControlFramePayloadSize bytes or less due
-// to RFC.
-func NewPingFrame(p []byte) Frame {
- return NewFrame(OpPing, true, p)
-}
-
-// NewPongFrame creates pong frame with p as payload.
-// Note that p is not copied.
-// Note that p must have length of MaxControlFramePayloadSize bytes or less due
-// to RFC.
-func NewPongFrame(p []byte) Frame {
- return NewFrame(OpPong, true, p)
-}
-
-// NewCloseFrame creates close frame with given close body.
-// Note that p is not copied.
-// Note that p must have length of MaxControlFramePayloadSize bytes or less due
-// to RFC.
-func NewCloseFrame(p []byte) Frame {
- return NewFrame(OpClose, true, p)
-}
-
-// NewCloseFrameBody encodes a closure code and a reason into a binary
-// representation.
-//
-// It returns slice which is at most MaxControlFramePayloadSize bytes length.
-// If the reason is too big it will be cropped to fit the limit defined by the
-// spec.
-//
-// See https://tools.ietf.org/html/rfc6455#section-5.5
-func NewCloseFrameBody(code StatusCode, reason string) []byte {
- n := min(2+len(reason), MaxControlFramePayloadSize)
- p := make([]byte, n)
-
- crop := min(MaxControlFramePayloadSize-2, len(reason))
- PutCloseFrameBody(p, code, reason[:crop])
-
- return p
-}
-
-// PutCloseFrameBody encodes code and reason into buf.
-//
-// It will panic if the buffer is too small to accommodate a code or a reason.
-//
-// PutCloseFrameBody does not check buffer to be RFC compliant, but note that
-// by RFC it must be at most MaxControlFramePayloadSize.
-func PutCloseFrameBody(p []byte, code StatusCode, reason string) {
- _ = p[1+len(reason)]
- binary.BigEndian.PutUint16(p, uint16(code))
- copy(p[2:], reason)
-}
-
-// MaskFrame masks frame and returns frame with masked payload and Mask header's field set.
-// Note that it copies f payload to prevent collisions.
-// For less allocations you could use MaskFrameInPlace or construct frame manually.
-func MaskFrame(f Frame) Frame {
- return MaskFrameWith(f, NewMask())
-}
-
-// MaskFrameWith masks frame with given mask and returns frame
-// with masked payload and Mask header's field set.
-// Note that it copies f payload to prevent collisions.
-// For less allocations you could use MaskFrameInPlaceWith or construct frame manually.
-func MaskFrameWith(f Frame, mask [4]byte) Frame {
- // TODO(gobwas): check CopyCipher ws copy() Cipher().
- p := make([]byte, len(f.Payload))
- copy(p, f.Payload)
- f.Payload = p
- return MaskFrameInPlaceWith(f, mask)
-}
-
-// MaskFrameInPlace masks frame and returns frame with masked payload and Mask
-// header's field set.
-// Note that it applies xor cipher to f.Payload without copying, that is, it
-// modifies f.Payload inplace.
-func MaskFrameInPlace(f Frame) Frame {
- return MaskFrameInPlaceWith(f, NewMask())
-}
-
-// MaskFrameInPlaceWith masks frame with given mask and returns frame
-// with masked payload and Mask header's field set.
-// Note that it applies xor cipher to f.Payload without copying, that is, it
-// modifies f.Payload inplace.
-func MaskFrameInPlaceWith(f Frame, m [4]byte) Frame {
- f.Header.Masked = true
- f.Header.Mask = m
- Cipher(f.Payload, m, 0)
- return f
-}
-
-// NewMask creates new random mask.
-func NewMask() (ret [4]byte) {
- binary.BigEndian.PutUint32(ret[:], rand.Uint32())
- return
-}
-
-// CompileFrame returns byte representation of given frame.
-// In terms of memory consumption it is useful to precompile static frames
-// which are often used.
-func CompileFrame(f Frame) (bts []byte, err error) {
- buf := bytes.NewBuffer(make([]byte, 0, 16))
- err = WriteFrame(buf, f)
- bts = buf.Bytes()
- return
-}
-
-// MustCompileFrame is like CompileFrame but panics if frame can not be
-// encoded.
-func MustCompileFrame(f Frame) []byte {
- bts, err := CompileFrame(f)
- if err != nil {
- panic(err)
- }
- return bts
-}
-
-// Rsv creates rsv byte representation.
-func Rsv(r1, r2, r3 bool) (rsv byte) {
- if r1 {
- rsv |= bit5
- }
- if r2 {
- rsv |= bit6
- }
- if r3 {
- rsv |= bit7
- }
- return rsv
-}
-
-func makeCloseFrame(code StatusCode, reason string) Frame {
- return NewCloseFrame(NewCloseFrameBody(
- code, reason,
- ))
-}
-
-var (
- closeFrameNormalClosure = makeCloseFrame(StatusNormalClosure, "")
- closeFrameGoingAway = makeCloseFrame(StatusGoingAway, "")
- closeFrameProtocolError = makeCloseFrame(StatusProtocolError, "")
- closeFrameUnsupportedData = makeCloseFrame(StatusUnsupportedData, "")
- closeFrameNoMeaningYet = makeCloseFrame(StatusNoMeaningYet, "")
- closeFrameInvalidFramePayloadData = makeCloseFrame(StatusInvalidFramePayloadData, "")
- closeFramePolicyViolation = makeCloseFrame(StatusPolicyViolation, "")
- closeFrameMessageTooBig = makeCloseFrame(StatusMessageTooBig, "")
- closeFrameMandatoryExt = makeCloseFrame(StatusMandatoryExt, "")
- closeFrameInternalServerError = makeCloseFrame(StatusInternalServerError, "")
- closeFrameTLSHandshake = makeCloseFrame(StatusTLSHandshake, "")
-)
diff --git a/vendor/github.com/gobwas/ws/http.go b/vendor/github.com/gobwas/ws/http.go
deleted file mode 100644
index e18df441b47..00000000000
--- a/vendor/github.com/gobwas/ws/http.go
+++ /dev/null
@@ -1,468 +0,0 @@
-package ws
-
-import (
- "bufio"
- "bytes"
- "io"
- "net/http"
- "net/textproto"
- "net/url"
- "strconv"
-
- "github.com/gobwas/httphead"
-)
-
-const (
- crlf = "\r\n"
- colonAndSpace = ": "
- commaAndSpace = ", "
-)
-
-const (
- textHeadUpgrade = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n"
-)
-
-var (
- textHeadBadRequest = statusText(http.StatusBadRequest)
- textHeadInternalServerError = statusText(http.StatusInternalServerError)
- textHeadUpgradeRequired = statusText(http.StatusUpgradeRequired)
-
- textTailErrHandshakeBadProtocol = errorText(ErrHandshakeBadProtocol)
- textTailErrHandshakeBadMethod = errorText(ErrHandshakeBadMethod)
- textTailErrHandshakeBadHost = errorText(ErrHandshakeBadHost)
- textTailErrHandshakeBadUpgrade = errorText(ErrHandshakeBadUpgrade)
- textTailErrHandshakeBadConnection = errorText(ErrHandshakeBadConnection)
- textTailErrHandshakeBadSecAccept = errorText(ErrHandshakeBadSecAccept)
- textTailErrHandshakeBadSecKey = errorText(ErrHandshakeBadSecKey)
- textTailErrHandshakeBadSecVersion = errorText(ErrHandshakeBadSecVersion)
- textTailErrUpgradeRequired = errorText(ErrHandshakeUpgradeRequired)
-)
-
-var (
- headerHost = "Host"
- headerUpgrade = "Upgrade"
- headerConnection = "Connection"
- headerSecVersion = "Sec-WebSocket-Version"
- headerSecProtocol = "Sec-WebSocket-Protocol"
- headerSecExtensions = "Sec-WebSocket-Extensions"
- headerSecKey = "Sec-WebSocket-Key"
- headerSecAccept = "Sec-WebSocket-Accept"
-
- headerHostCanonical = textproto.CanonicalMIMEHeaderKey(headerHost)
- headerUpgradeCanonical = textproto.CanonicalMIMEHeaderKey(headerUpgrade)
- headerConnectionCanonical = textproto.CanonicalMIMEHeaderKey(headerConnection)
- headerSecVersionCanonical = textproto.CanonicalMIMEHeaderKey(headerSecVersion)
- headerSecProtocolCanonical = textproto.CanonicalMIMEHeaderKey(headerSecProtocol)
- headerSecExtensionsCanonical = textproto.CanonicalMIMEHeaderKey(headerSecExtensions)
- headerSecKeyCanonical = textproto.CanonicalMIMEHeaderKey(headerSecKey)
- headerSecAcceptCanonical = textproto.CanonicalMIMEHeaderKey(headerSecAccept)
-)
-
-var (
- specHeaderValueUpgrade = []byte("websocket")
- specHeaderValueConnection = []byte("Upgrade")
- specHeaderValueConnectionLower = []byte("upgrade")
- specHeaderValueSecVersion = []byte("13")
-)
-
-var (
- httpVersion1_0 = []byte("HTTP/1.0")
- httpVersion1_1 = []byte("HTTP/1.1")
- httpVersionPrefix = []byte("HTTP/")
-)
-
-type httpRequestLine struct {
- method, uri []byte
- major, minor int
-}
-
-type httpResponseLine struct {
- major, minor int
- status int
- reason []byte
-}
-
-// httpParseRequestLine parses http request line like "GET / HTTP/1.0".
-func httpParseRequestLine(line []byte) (req httpRequestLine, err error) {
- var proto []byte
- req.method, req.uri, proto = bsplit3(line, ' ')
-
- var ok bool
- req.major, req.minor, ok = httpParseVersion(proto)
- if !ok {
- err = ErrMalformedRequest
- return
- }
-
- return
-}
-
-func httpParseResponseLine(line []byte) (resp httpResponseLine, err error) {
- var (
- proto []byte
- status []byte
- )
- proto, status, resp.reason = bsplit3(line, ' ')
-
- var ok bool
- resp.major, resp.minor, ok = httpParseVersion(proto)
- if !ok {
- return resp, ErrMalformedResponse
- }
-
- var convErr error
- resp.status, convErr = asciiToInt(status)
- if convErr != nil {
- return resp, ErrMalformedResponse
- }
-
- return resp, nil
-}
-
-// httpParseVersion parses major and minor version of HTTP protocol. It returns
-// parsed values and true if parse is ok.
-func httpParseVersion(bts []byte) (major, minor int, ok bool) {
- switch {
- case bytes.Equal(bts, httpVersion1_0):
- return 1, 0, true
- case bytes.Equal(bts, httpVersion1_1):
- return 1, 1, true
- case len(bts) < 8:
- return
- case !bytes.Equal(bts[:5], httpVersionPrefix):
- return
- }
-
- bts = bts[5:]
-
- dot := bytes.IndexByte(bts, '.')
- if dot == -1 {
- return
- }
- var err error
- major, err = asciiToInt(bts[:dot])
- if err != nil {
- return
- }
- minor, err = asciiToInt(bts[dot+1:])
- if err != nil {
- return
- }
-
- return major, minor, true
-}
-
-// httpParseHeaderLine parses HTTP header as key-value pair. It returns parsed
-// values and true if parse is ok.
-func httpParseHeaderLine(line []byte) (k, v []byte, ok bool) {
- colon := bytes.IndexByte(line, ':')
- if colon == -1 {
- return
- }
-
- k = btrim(line[:colon])
- // TODO(gobwas): maybe use just lower here?
- canonicalizeHeaderKey(k)
-
- v = btrim(line[colon+1:])
-
- return k, v, true
-}
-
-// httpGetHeader is the same as textproto.MIMEHeader.Get, except the thing,
-// that key is already canonical. This helps to increase performance.
-func httpGetHeader(h http.Header, key string) string {
- if h == nil {
- return ""
- }
- v := h[key]
- if len(v) == 0 {
- return ""
- }
- return v[0]
-}
-
-// The request MAY include a header field with the name
-// |Sec-WebSocket-Protocol|. If present, this value indicates one or more
-// comma-separated subprotocol the client wishes to speak, ordered by
-// preference. The elements that comprise this value MUST be non-empty strings
-// with characters in the range U+0021 to U+007E not including separator
-// characters as defined in [RFC2616] and MUST all be unique strings. The ABNF
-// for the value of this header field is 1#token, where the definitions of
-// constructs and rules are as given in [RFC2616].
-func strSelectProtocol(h string, check func(string) bool) (ret string, ok bool) {
- ok = httphead.ScanTokens(strToBytes(h), func(v []byte) bool {
- if check(btsToString(v)) {
- ret = string(v)
- return false
- }
- return true
- })
- return
-}
-func btsSelectProtocol(h []byte, check func([]byte) bool) (ret string, ok bool) {
- var selected []byte
- ok = httphead.ScanTokens(h, func(v []byte) bool {
- if check(v) {
- selected = v
- return false
- }
- return true
- })
- if ok && selected != nil {
- return string(selected), true
- }
- return
-}
-
-func strSelectExtensions(h string, selected []httphead.Option, check func(httphead.Option) bool) ([]httphead.Option, bool) {
- return btsSelectExtensions(strToBytes(h), selected, check)
-}
-
-func btsSelectExtensions(h []byte, selected []httphead.Option, check func(httphead.Option) bool) ([]httphead.Option, bool) {
- s := httphead.OptionSelector{
- Flags: httphead.SelectUnique | httphead.SelectCopy,
- Check: check,
- }
- return s.Select(h, selected)
-}
-
-func httpWriteHeader(bw *bufio.Writer, key, value string) {
- httpWriteHeaderKey(bw, key)
- bw.WriteString(value)
- bw.WriteString(crlf)
-}
-
-func httpWriteHeaderBts(bw *bufio.Writer, key string, value []byte) {
- httpWriteHeaderKey(bw, key)
- bw.Write(value)
- bw.WriteString(crlf)
-}
-
-func httpWriteHeaderKey(bw *bufio.Writer, key string) {
- bw.WriteString(key)
- bw.WriteString(colonAndSpace)
-}
-
-func httpWriteUpgradeRequest(
- bw *bufio.Writer,
- u *url.URL,
- nonce []byte,
- protocols []string,
- extensions []httphead.Option,
- header HandshakeHeader,
-) {
- bw.WriteString("GET ")
- bw.WriteString(u.RequestURI())
- bw.WriteString(" HTTP/1.1\r\n")
-
- httpWriteHeader(bw, headerHost, u.Host)
-
- httpWriteHeaderBts(bw, headerUpgrade, specHeaderValueUpgrade)
- httpWriteHeaderBts(bw, headerConnection, specHeaderValueConnection)
- httpWriteHeaderBts(bw, headerSecVersion, specHeaderValueSecVersion)
-
- // NOTE: write nonce bytes as a string to prevent heap allocation –
- // WriteString() copy given string into its inner buffer, unlike Write()
- // which may write p directly to the underlying io.Writer – which in turn
- // will lead to p escape.
- httpWriteHeader(bw, headerSecKey, btsToString(nonce))
-
- if len(protocols) > 0 {
- httpWriteHeaderKey(bw, headerSecProtocol)
- for i, p := range protocols {
- if i > 0 {
- bw.WriteString(commaAndSpace)
- }
- bw.WriteString(p)
- }
- bw.WriteString(crlf)
- }
-
- if len(extensions) > 0 {
- httpWriteHeaderKey(bw, headerSecExtensions)
- httphead.WriteOptions(bw, extensions)
- bw.WriteString(crlf)
- }
-
- if header != nil {
- header.WriteTo(bw)
- }
-
- bw.WriteString(crlf)
-}
-
-func httpWriteResponseUpgrade(bw *bufio.Writer, nonce []byte, hs Handshake, header HandshakeHeaderFunc) {
- bw.WriteString(textHeadUpgrade)
-
- httpWriteHeaderKey(bw, headerSecAccept)
- writeAccept(bw, nonce)
- bw.WriteString(crlf)
-
- if hs.Protocol != "" {
- httpWriteHeader(bw, headerSecProtocol, hs.Protocol)
- }
- if len(hs.Extensions) > 0 {
- httpWriteHeaderKey(bw, headerSecExtensions)
- httphead.WriteOptions(bw, hs.Extensions)
- bw.WriteString(crlf)
- }
- if header != nil {
- header(bw)
- }
-
- bw.WriteString(crlf)
-}
-
-func httpWriteResponseError(bw *bufio.Writer, err error, code int, header HandshakeHeaderFunc) {
- switch code {
- case http.StatusBadRequest:
- bw.WriteString(textHeadBadRequest)
- case http.StatusInternalServerError:
- bw.WriteString(textHeadInternalServerError)
- case http.StatusUpgradeRequired:
- bw.WriteString(textHeadUpgradeRequired)
- default:
- writeStatusText(bw, code)
- }
-
- // Write custom headers.
- if header != nil {
- header(bw)
- }
-
- switch err {
- case ErrHandshakeBadProtocol:
- bw.WriteString(textTailErrHandshakeBadProtocol)
- case ErrHandshakeBadMethod:
- bw.WriteString(textTailErrHandshakeBadMethod)
- case ErrHandshakeBadHost:
- bw.WriteString(textTailErrHandshakeBadHost)
- case ErrHandshakeBadUpgrade:
- bw.WriteString(textTailErrHandshakeBadUpgrade)
- case ErrHandshakeBadConnection:
- bw.WriteString(textTailErrHandshakeBadConnection)
- case ErrHandshakeBadSecAccept:
- bw.WriteString(textTailErrHandshakeBadSecAccept)
- case ErrHandshakeBadSecKey:
- bw.WriteString(textTailErrHandshakeBadSecKey)
- case ErrHandshakeBadSecVersion:
- bw.WriteString(textTailErrHandshakeBadSecVersion)
- case ErrHandshakeUpgradeRequired:
- bw.WriteString(textTailErrUpgradeRequired)
- case nil:
- bw.WriteString(crlf)
- default:
- writeErrorText(bw, err)
- }
-}
-
-func writeStatusText(bw *bufio.Writer, code int) {
- bw.WriteString("HTTP/1.1 ")
- bw.WriteString(strconv.Itoa(code))
- bw.WriteByte(' ')
- bw.WriteString(http.StatusText(code))
- bw.WriteString(crlf)
- bw.WriteString("Content-Type: text/plain; charset=utf-8")
- bw.WriteString(crlf)
-}
-
-func writeErrorText(bw *bufio.Writer, err error) {
- body := err.Error()
- bw.WriteString("Content-Length: ")
- bw.WriteString(strconv.Itoa(len(body)))
- bw.WriteString(crlf)
- bw.WriteString(crlf)
- bw.WriteString(body)
-}
-
-// httpError is like the http.Error with WebSocket context exception.
-func httpError(w http.ResponseWriter, body string, code int) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.Header().Set("Content-Length", strconv.Itoa(len(body)))
- w.WriteHeader(code)
- w.Write([]byte(body))
-}
-
-// statusText is a non-performant status text generator.
-// NOTE: Used only to generate constants.
-func statusText(code int) string {
- var buf bytes.Buffer
- bw := bufio.NewWriter(&buf)
- writeStatusText(bw, code)
- bw.Flush()
- return buf.String()
-}
-
-// errorText is a non-performant error text generator.
-// NOTE: Used only to generate constants.
-func errorText(err error) string {
- var buf bytes.Buffer
- bw := bufio.NewWriter(&buf)
- writeErrorText(bw, err)
- bw.Flush()
- return buf.String()
-}
-
-// HandshakeHeader is the interface that writes both upgrade request or
-// response headers into a given io.Writer.
-type HandshakeHeader interface {
- io.WriterTo
-}
-
-// HandshakeHeaderString is an adapter to allow the use of headers represented
-// by ordinary string as HandshakeHeader.
-type HandshakeHeaderString string
-
-// WriteTo implements HandshakeHeader (and io.WriterTo) interface.
-func (s HandshakeHeaderString) WriteTo(w io.Writer) (int64, error) {
- n, err := io.WriteString(w, string(s))
- return int64(n), err
-}
-
-// HandshakeHeaderBytes is an adapter to allow the use of headers represented
-// by ordinary slice of bytes as HandshakeHeader.
-type HandshakeHeaderBytes []byte
-
-// WriteTo implements HandshakeHeader (and io.WriterTo) interface.
-func (b HandshakeHeaderBytes) WriteTo(w io.Writer) (int64, error) {
- n, err := w.Write(b)
- return int64(n), err
-}
-
-// HandshakeHeaderFunc is an adapter to allow the use of headers represented by
-// ordinary function as HandshakeHeader.
-type HandshakeHeaderFunc func(io.Writer) (int64, error)
-
-// WriteTo implements HandshakeHeader (and io.WriterTo) interface.
-func (f HandshakeHeaderFunc) WriteTo(w io.Writer) (int64, error) {
- return f(w)
-}
-
-// HandshakeHeaderHTTP is an adapter to allow the use of http.Header as
-// HandshakeHeader.
-type HandshakeHeaderHTTP http.Header
-
-// WriteTo implements HandshakeHeader (and io.WriterTo) interface.
-func (h HandshakeHeaderHTTP) WriteTo(w io.Writer) (int64, error) {
- wr := writer{w: w}
- err := http.Header(h).Write(&wr)
- return wr.n, err
-}
-
-type writer struct {
- n int64
- w io.Writer
-}
-
-func (w *writer) WriteString(s string) (int, error) {
- n, err := io.WriteString(w.w, s)
- w.n += int64(n)
- return n, err
-}
-
-func (w *writer) Write(p []byte) (int, error) {
- n, err := w.w.Write(p)
- w.n += int64(n)
- return n, err
-}
diff --git a/vendor/github.com/gobwas/ws/nonce.go b/vendor/github.com/gobwas/ws/nonce.go
deleted file mode 100644
index e694da7c308..00000000000
--- a/vendor/github.com/gobwas/ws/nonce.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package ws
-
-import (
- "bufio"
- "bytes"
- "crypto/sha1"
- "encoding/base64"
- "fmt"
- "math/rand"
-)
-
-const (
- // RFC6455: The value of this header field MUST be a nonce consisting of a
- // randomly selected 16-byte value that has been base64-encoded (see
- // Section 4 of [RFC4648]). The nonce MUST be selected randomly for each
- // connection.
- nonceKeySize = 16
- nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize)
-
- // RFC6455: The value of this header field is constructed by concatenating
- // /key/, defined above in step 4 in Section 4.2.2, with the string
- // "258EAFA5- E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this
- // concatenated value to obtain a 20-byte value and base64- encoding (see
- // Section 4 of [RFC4648]) this 20-byte hash.
- acceptSize = 28 // base64.StdEncoding.EncodedLen(sha1.Size)
-)
-
-// initNonce fills given slice with random base64-encoded nonce bytes.
-func initNonce(dst []byte) {
- // NOTE: bts does not escape.
- bts := make([]byte, nonceKeySize)
- if _, err := rand.Read(bts); err != nil {
- panic(fmt.Sprintf("rand read error: %s", err))
- }
- base64.StdEncoding.Encode(dst, bts)
-}
-
-// checkAcceptFromNonce reports whether given accept bytes are valid for given
-// nonce bytes.
-func checkAcceptFromNonce(accept, nonce []byte) bool {
- if len(accept) != acceptSize {
- return false
- }
- // NOTE: expect does not escape.
- expect := make([]byte, acceptSize)
- initAcceptFromNonce(expect, nonce)
- return bytes.Equal(expect, accept)
-}
-
-// initAcceptFromNonce fills given slice with accept bytes generated from given
-// nonce bytes. Given buffer should be exactly acceptSize bytes.
-func initAcceptFromNonce(accept, nonce []byte) {
- const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
-
- if len(accept) != acceptSize {
- panic("accept buffer is invalid")
- }
- if len(nonce) != nonceSize {
- panic("nonce is invalid")
- }
-
- p := make([]byte, nonceSize+len(magic))
- copy(p[:nonceSize], nonce)
- copy(p[nonceSize:], magic)
-
- sum := sha1.Sum(p)
- base64.StdEncoding.Encode(accept, sum[:])
-
- return
-}
-
-func writeAccept(bw *bufio.Writer, nonce []byte) (int, error) {
- accept := make([]byte, acceptSize)
- initAcceptFromNonce(accept, nonce)
- // NOTE: write accept bytes as a string to prevent heap allocation –
- // WriteString() copy given string into its inner buffer, unlike Write()
- // which may write p directly to the underlying io.Writer – which in turn
- // will lead to p escape.
- return bw.WriteString(btsToString(accept))
-}
diff --git a/vendor/github.com/gobwas/ws/read.go b/vendor/github.com/gobwas/ws/read.go
deleted file mode 100644
index bc653e4690f..00000000000
--- a/vendor/github.com/gobwas/ws/read.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package ws
-
-import (
- "encoding/binary"
- "fmt"
- "io"
-)
-
-// Errors used by frame reader.
-var (
- ErrHeaderLengthMSB = fmt.Errorf("header error: the most significant bit must be 0")
- ErrHeaderLengthUnexpected = fmt.Errorf("header error: unexpected payload length bits")
-)
-
-// ReadHeader reads a frame header from r.
-func ReadHeader(r io.Reader) (h Header, err error) {
- // Make slice of bytes with capacity 12 that could hold any header.
- //
- // The maximum header size is 14, but due to the 2 hop reads,
- // after first hop that reads first 2 constant bytes, we could reuse 2 bytes.
- // So 14 - 2 = 12.
- bts := make([]byte, 2, MaxHeaderSize-2)
-
- // Prepare to hold first 2 bytes to choose size of next read.
- _, err = io.ReadFull(r, bts)
- if err != nil {
- return
- }
-
- h.Fin = bts[0]&bit0 != 0
- h.Rsv = (bts[0] & 0x70) >> 4
- h.OpCode = OpCode(bts[0] & 0x0f)
-
- var extra int
-
- if bts[1]&bit0 != 0 {
- h.Masked = true
- extra += 4
- }
-
- length := bts[1] & 0x7f
- switch {
- case length < 126:
- h.Length = int64(length)
-
- case length == 126:
- extra += 2
-
- case length == 127:
- extra += 8
-
- default:
- err = ErrHeaderLengthUnexpected
- return
- }
-
- if extra == 0 {
- return
- }
-
- // Increase len of bts to extra bytes need to read.
- // Overwrite first 2 bytes that was read before.
- bts = bts[:extra]
- _, err = io.ReadFull(r, bts)
- if err != nil {
- return
- }
-
- switch {
- case length == 126:
- h.Length = int64(binary.BigEndian.Uint16(bts[:2]))
- bts = bts[2:]
-
- case length == 127:
- if bts[0]&0x80 != 0 {
- err = ErrHeaderLengthMSB
- return
- }
- h.Length = int64(binary.BigEndian.Uint64(bts[:8]))
- bts = bts[8:]
- }
-
- if h.Masked {
- copy(h.Mask[:], bts)
- }
-
- return
-}
-
-// ReadFrame reads a frame from r.
-// It is not designed for high optimized use case cause it makes allocation
-// for frame.Header.Length size inside to read frame payload into.
-//
-// Note that ReadFrame does not unmask payload.
-func ReadFrame(r io.Reader) (f Frame, err error) {
- f.Header, err = ReadHeader(r)
- if err != nil {
- return
- }
-
- if f.Header.Length > 0 {
- // int(f.Header.Length) is safe here cause we have
- // checked it for overflow above in ReadHeader.
- f.Payload = make([]byte, int(f.Header.Length))
- _, err = io.ReadFull(r, f.Payload)
- }
-
- return
-}
-
-// MustReadFrame is like ReadFrame but panics if frame can not be read.
-func MustReadFrame(r io.Reader) Frame {
- f, err := ReadFrame(r)
- if err != nil {
- panic(err)
- }
- return f
-}
-
-// ParseCloseFrameData parses close frame status code and closure reason if any provided.
-// If there is no status code in the payload
-// the empty status code is returned (code.Empty()) with empty string as a reason.
-func ParseCloseFrameData(payload []byte) (code StatusCode, reason string) {
- if len(payload) < 2 {
- // We returning empty StatusCode here, preventing the situation
- // when endpoint really sent code 1005 and we should return ProtocolError on that.
- //
- // In other words, we ignoring this rule [RFC6455:7.1.5]:
- // If this Close control frame contains no status code, _The WebSocket
- // Connection Close Code_ is considered to be 1005.
- return
- }
- code = StatusCode(binary.BigEndian.Uint16(payload))
- reason = string(payload[2:])
- return
-}
-
-// ParseCloseFrameDataUnsafe is like ParseCloseFrameData except the thing
-// that it does not copies payload bytes into reason, but prepares unsafe cast.
-func ParseCloseFrameDataUnsafe(payload []byte) (code StatusCode, reason string) {
- if len(payload) < 2 {
- return
- }
- code = StatusCode(binary.BigEndian.Uint16(payload))
- reason = btsToString(payload[2:])
- return
-}
diff --git a/vendor/github.com/gobwas/ws/server.go b/vendor/github.com/gobwas/ws/server.go
deleted file mode 100644
index 7c7f63c4ecb..00000000000
--- a/vendor/github.com/gobwas/ws/server.go
+++ /dev/null
@@ -1,606 +0,0 @@
-package ws
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "net"
- "net/http"
- "time"
-
- "github.com/gobwas/httphead"
- "github.com/gobwas/pool/pbufio"
-)
-
-// Constants used by ConnUpgrader.
-const (
- DefaultServerReadBufferSize = 4096
- DefaultServerWriteBufferSize = 512
-)
-
-// Errors used by both client and server when preparing WebSocket handshake.
-var (
- ErrHandshakeBadProtocol = RejectConnectionError(
- RejectionStatus(http.StatusHTTPVersionNotSupported),
- RejectionReason(fmt.Sprintf("handshake error: bad HTTP protocol version")),
- )
- ErrHandshakeBadMethod = RejectConnectionError(
- RejectionStatus(http.StatusMethodNotAllowed),
- RejectionReason(fmt.Sprintf("handshake error: bad HTTP request method")),
- )
- ErrHandshakeBadHost = RejectConnectionError(
- RejectionStatus(http.StatusBadRequest),
- RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerHost)),
- )
- ErrHandshakeBadUpgrade = RejectConnectionError(
- RejectionStatus(http.StatusBadRequest),
- RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerUpgrade)),
- )
- ErrHandshakeBadConnection = RejectConnectionError(
- RejectionStatus(http.StatusBadRequest),
- RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerConnection)),
- )
- ErrHandshakeBadSecAccept = RejectConnectionError(
- RejectionStatus(http.StatusBadRequest),
- RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecAccept)),
- )
- ErrHandshakeBadSecKey = RejectConnectionError(
- RejectionStatus(http.StatusBadRequest),
- RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecKey)),
- )
- ErrHandshakeBadSecVersion = RejectConnectionError(
- RejectionStatus(http.StatusBadRequest),
- RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecVersion)),
- )
-)
-
-// ErrMalformedResponse is returned by Dialer to indicate that server response
-// can not be parsed.
-var ErrMalformedResponse = fmt.Errorf("malformed HTTP response")
-
-// ErrMalformedRequest is returned when HTTP request can not be parsed.
-var ErrMalformedRequest = RejectConnectionError(
- RejectionStatus(http.StatusBadRequest),
- RejectionReason("malformed HTTP request"),
-)
-
-// ErrHandshakeUpgradeRequired is returned by Upgrader to indicate that
-// connection is rejected because given WebSocket version is malformed.
-//
-// According to RFC6455:
-// If this version does not match a version understood by the server, the
-// server MUST abort the WebSocket handshake described in this section and
-// instead send an appropriate HTTP error code (such as 426 Upgrade Required)
-// and a |Sec-WebSocket-Version| header field indicating the version(s) the
-// server is capable of understanding.
-var ErrHandshakeUpgradeRequired = RejectConnectionError(
- RejectionStatus(http.StatusUpgradeRequired),
- RejectionHeader(HandshakeHeaderString(headerSecVersion+": 13\r\n")),
- RejectionReason(fmt.Sprintf("handshake error: bad %q header", headerSecVersion)),
-)
-
-// ErrNotHijacker is an error returned when http.ResponseWriter does not
-// implement http.Hijacker interface.
-var ErrNotHijacker = RejectConnectionError(
- RejectionStatus(http.StatusInternalServerError),
- RejectionReason("given http.ResponseWriter is not a http.Hijacker"),
-)
-
-// DefaultHTTPUpgrader is an HTTPUpgrader that holds no options and is used by
-// UpgradeHTTP function.
-var DefaultHTTPUpgrader HTTPUpgrader
-
-// UpgradeHTTP is like HTTPUpgrader{}.Upgrade().
-func UpgradeHTTP(r *http.Request, w http.ResponseWriter) (net.Conn, *bufio.ReadWriter, Handshake, error) {
- return DefaultHTTPUpgrader.Upgrade(r, w)
-}
-
-// DefaultUpgrader is an Upgrader that holds no options and is used by Upgrade
-// function.
-var DefaultUpgrader Upgrader
-
-// Upgrade is like Upgrader{}.Upgrade().
-func Upgrade(conn io.ReadWriter) (Handshake, error) {
- return DefaultUpgrader.Upgrade(conn)
-}
-
-// HTTPUpgrader contains options for upgrading connection to websocket from
-// net/http Handler arguments.
-type HTTPUpgrader struct {
- // Timeout is the maximum amount of time an Upgrade() will spent while
- // writing handshake response.
- //
- // The default is no timeout.
- Timeout time.Duration
-
- // Header is an optional http.Header mapping that could be used to
- // write additional headers to the handshake response.
- //
- // Note that if present, it will be written in any result of handshake.
- Header http.Header
-
- // Protocol is the select function that is used to select subprotocol from
- // list requested by client. If this field is set, then the first matched
- // protocol is sent to a client as negotiated.
- Protocol func(string) bool
-
- // Extension is the select function that is used to select extensions from
- // list requested by client. If this field is set, then the all matched
- // extensions are sent to a client as negotiated.
- Extension func(httphead.Option) bool
-}
-
-// Upgrade upgrades http connection to the websocket connection.
-//
-// It hijacks net.Conn from w and returns received net.Conn and
-// bufio.ReadWriter. On successful handshake it returns Handshake struct
-// describing handshake info.
-func (u HTTPUpgrader) Upgrade(r *http.Request, w http.ResponseWriter) (conn net.Conn, rw *bufio.ReadWriter, hs Handshake, err error) {
- // Hijack connection first to get the ability to write rejection errors the
- // same way as in Upgrader.
- hj, ok := w.(http.Hijacker)
- if ok {
- conn, rw, err = hj.Hijack()
- } else {
- err = ErrNotHijacker
- }
- if err != nil {
- httpError(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- // See https://tools.ietf.org/html/rfc6455#section-4.1
- // The method of the request MUST be GET, and the HTTP version MUST be at least 1.1.
- var nonce string
- if r.Method != http.MethodGet {
- err = ErrHandshakeBadMethod
- } else if r.ProtoMajor < 1 || (r.ProtoMajor == 1 && r.ProtoMinor < 1) {
- err = ErrHandshakeBadProtocol
- } else if r.Host == "" {
- err = ErrHandshakeBadHost
- } else if u := httpGetHeader(r.Header, headerUpgradeCanonical); u != "websocket" && !strEqualFold(u, "websocket") {
- err = ErrHandshakeBadUpgrade
- } else if c := httpGetHeader(r.Header, headerConnectionCanonical); c != "Upgrade" && !strHasToken(c, "upgrade") {
- err = ErrHandshakeBadConnection
- } else if nonce = httpGetHeader(r.Header, headerSecKeyCanonical); len(nonce) != nonceSize {
- err = ErrHandshakeBadSecKey
- } else if v := httpGetHeader(r.Header, headerSecVersionCanonical); v != "13" {
- // According to RFC6455:
- //
- // If this version does not match a version understood by the server,
- // the server MUST abort the WebSocket handshake described in this
- // section and instead send an appropriate HTTP error code (such as 426
- // Upgrade Required) and a |Sec-WebSocket-Version| header field
- // indicating the version(s) the server is capable of understanding.
- //
- // So we branching here cause empty or not present version does not
- // meet the ABNF rules of RFC6455:
- //
- // version = DIGIT | (NZDIGIT DIGIT) |
- // ("1" DIGIT DIGIT) | ("2" DIGIT DIGIT)
- // ; Limited to 0-255 range, with no leading zeros
- //
- // That is, if version is really invalid – we sent 426 status, if it
- // not present or empty – it is 400.
- if v != "" {
- err = ErrHandshakeUpgradeRequired
- } else {
- err = ErrHandshakeBadSecVersion
- }
- }
- if check := u.Protocol; err == nil && check != nil {
- ps := r.Header[headerSecProtocolCanonical]
- for i := 0; i < len(ps) && err == nil && hs.Protocol == ""; i++ {
- var ok bool
- hs.Protocol, ok = strSelectProtocol(ps[i], check)
- if !ok {
- err = ErrMalformedRequest
- }
- }
- }
- if check := u.Extension; err == nil && check != nil {
- xs := r.Header[headerSecExtensionsCanonical]
- for i := 0; i < len(xs) && err == nil; i++ {
- var ok bool
- hs.Extensions, ok = strSelectExtensions(xs[i], hs.Extensions, check)
- if !ok {
- err = ErrMalformedRequest
- }
- }
- }
-
- // Clear deadlines set by server.
- conn.SetDeadline(noDeadline)
- if t := u.Timeout; t != 0 {
- conn.SetWriteDeadline(time.Now().Add(t))
- defer conn.SetWriteDeadline(noDeadline)
- }
-
- var header handshakeHeader
- if h := u.Header; h != nil {
- header[0] = HandshakeHeaderHTTP(h)
- }
- if err == nil {
- httpWriteResponseUpgrade(rw.Writer, strToBytes(nonce), hs, header.WriteTo)
- err = rw.Writer.Flush()
- } else {
- var code int
- if rej, ok := err.(*rejectConnectionError); ok {
- code = rej.code
- header[1] = rej.header
- }
- if code == 0 {
- code = http.StatusInternalServerError
- }
- httpWriteResponseError(rw.Writer, err, code, header.WriteTo)
- // Do not store Flush() error to not override already existing one.
- rw.Writer.Flush()
- }
- return
-}
-
-// Upgrader contains options for upgrading connection to websocket.
-type Upgrader struct {
- // ReadBufferSize and WriteBufferSize is an I/O buffer sizes.
- // They used to read and write http data while upgrading to WebSocket.
- // Allocated buffers are pooled with sync.Pool to avoid extra allocations.
- //
- // If a size is zero then default value is used.
- //
- // Usually it is useful to set read buffer size bigger than write buffer
- // size because incoming request could contain long header values, such as
- // Cookie. Response, in other way, could be big only if user write multiple
- // custom headers. Usually response takes less than 256 bytes.
- ReadBufferSize, WriteBufferSize int
-
- // Protocol is a select function that is used to select subprotocol
- // from list requested by client. If this field is set, then the first matched
- // protocol is sent to a client as negotiated.
- //
- // The argument is only valid until the callback returns.
- Protocol func([]byte) bool
-
- // ProtocolCustrom allow user to parse Sec-WebSocket-Protocol header manually.
- // Note that returned bytes must be valid until Upgrade returns.
- // If ProtocolCustom is set, it used instead of Protocol function.
- ProtocolCustom func([]byte) (string, bool)
-
- // Extension is a select function that is used to select extensions
- // from list requested by client. If this field is set, then the all matched
- // extensions are sent to a client as negotiated.
- //
- // The argument is only valid until the callback returns.
- //
- // According to the RFC6455 order of extensions passed by a client is
- // significant. That is, returning true from this function means that no
- // other extension with the same name should be checked because server
- // accepted the most preferable extension right now:
- // "Note that the order of extensions is significant. Any interactions between
- // multiple extensions MAY be defined in the documents defining the extensions.
- // In the absence of such definitions, the interpretation is that the header
- // fields listed by the client in its request represent a preference of the
- // header fields it wishes to use, with the first options listed being most
- // preferable."
- Extension func(httphead.Option) bool
-
- // ExtensionCustorm allow user to parse Sec-WebSocket-Extensions header manually.
- // Note that returned options should be valid until Upgrade returns.
- // If ExtensionCustom is set, it used instead of Extension function.
- ExtensionCustom func([]byte, []httphead.Option) ([]httphead.Option, bool)
-
- // Header is an optional HandshakeHeader instance that could be used to
- // write additional headers to the handshake response.
- //
- // It used instead of any key-value mappings to avoid allocations in user
- // land.
- //
- // Note that if present, it will be written in any result of handshake.
- Header HandshakeHeader
-
- // OnRequest is a callback that will be called after request line
- // successful parsing.
- //
- // The arguments are only valid until the callback returns.
- //
- // If returned error is non-nil then connection is rejected and response is
- // sent with appropriate HTTP error code and body set to error message.
- //
- // RejectConnectionError could be used to get more control on response.
- OnRequest func(uri []byte) error
-
- // OnHost is a callback that will be called after "Host" header successful
- // parsing.
- //
- // It is separated from OnHeader callback because the Host header must be
- // present in each request since HTTP/1.1. Thus Host header is non-optional
- // and required for every WebSocket handshake.
- //
- // The arguments are only valid until the callback returns.
- //
- // If returned error is non-nil then connection is rejected and response is
- // sent with appropriate HTTP error code and body set to error message.
- //
- // RejectConnectionError could be used to get more control on response.
- OnHost func(host []byte) error
-
- // OnHeader is a callback that will be called after successful parsing of
- // header, that is not used during WebSocket handshake procedure. That is,
- // it will be called with non-websocket headers, which could be relevant
- // for application-level logic.
- //
- // The arguments are only valid until the callback returns.
- //
- // If returned error is non-nil then connection is rejected and response is
- // sent with appropriate HTTP error code and body set to error message.
- //
- // RejectConnectionError could be used to get more control on response.
- OnHeader func(key, value []byte) error
-
- // OnBeforeUpgrade is a callback that will be called before sending
- // successful upgrade response.
- //
- // Setting OnBeforeUpgrade allows user to make final application-level
- // checks and decide whether this connection is allowed to successfully
- // upgrade to WebSocket.
- //
- // It must return non-nil either HandshakeHeader or error and never both.
- //
- // If returned error is non-nil then connection is rejected and response is
- // sent with appropriate HTTP error code and body set to error message.
- //
- // RejectConnectionError could be used to get more control on response.
- OnBeforeUpgrade func() (header HandshakeHeader, err error)
-}
-
-// Upgrade zero-copy upgrades connection to WebSocket. It interprets given conn
-// as connection with incoming HTTP Upgrade request.
-//
-// It is a caller responsibility to manage i/o timeouts on conn.
-//
-// Non-nil error means that request for the WebSocket upgrade is invalid or
-// malformed and usually connection should be closed.
-// Even when error is non-nil Upgrade will write appropriate response into
-// connection in compliance with RFC.
-func (u Upgrader) Upgrade(conn io.ReadWriter) (hs Handshake, err error) {
- // headerSeen constants helps to report whether or not some header was seen
- // during reading request bytes.
- const (
- headerSeenHost = 1 << iota
- headerSeenUpgrade
- headerSeenConnection
- headerSeenSecVersion
- headerSeenSecKey
-
- // headerSeenAll is the value that we expect to receive at the end of
- // headers read/parse loop.
- headerSeenAll = 0 |
- headerSeenHost |
- headerSeenUpgrade |
- headerSeenConnection |
- headerSeenSecVersion |
- headerSeenSecKey
- )
-
- // Prepare I/O buffers.
- // TODO(gobwas): make it configurable.
- br := pbufio.GetReader(conn,
- nonZero(u.ReadBufferSize, DefaultServerReadBufferSize),
- )
- bw := pbufio.GetWriter(conn,
- nonZero(u.WriteBufferSize, DefaultServerWriteBufferSize),
- )
- defer func() {
- pbufio.PutReader(br)
- pbufio.PutWriter(bw)
- }()
-
- // Read HTTP request line like "GET /ws HTTP/1.1".
- rl, err := readLine(br)
- if err != nil {
- return
- }
- // Parse request line data like HTTP version, uri and method.
- req, err := httpParseRequestLine(rl)
- if err != nil {
- return
- }
-
- // Prepare stack-based handshake header list.
- header := handshakeHeader{
- 0: u.Header,
- }
-
- // Parse and check HTTP request.
- // As RFC6455 says:
- // The client's opening handshake consists of the following parts. If the
- // server, while reading the handshake, finds that the client did not
- // send a handshake that matches the description below (note that as per
- // [RFC2616], the order of the header fields is not important), including
- // but not limited to any violations of the ABNF grammar specified for
- // the components of the handshake, the server MUST stop processing the
- // client's handshake and return an HTTP response with an appropriate
- // error code (such as 400 Bad Request).
- //
- // See https://tools.ietf.org/html/rfc6455#section-4.2.1
-
- // An HTTP/1.1 or higher GET request, including a "Request-URI".
- //
- // Even if RFC says "1.1 or higher" without mentioning the part of the
- // version, we apply it only to minor part.
- switch {
- case req.major != 1 || req.minor < 1:
- // Abort processing the whole request because we do not even know how
- // to actually parse it.
- err = ErrHandshakeBadProtocol
-
- case btsToString(req.method) != http.MethodGet:
- err = ErrHandshakeBadMethod
-
- default:
- if onRequest := u.OnRequest; onRequest != nil {
- err = onRequest(req.uri)
- }
- }
- // Start headers read/parse loop.
- var (
- // headerSeen reports which header was seen by setting corresponding
- // bit on.
- headerSeen byte
-
- nonce = make([]byte, nonceSize)
- )
- for err == nil {
- line, e := readLine(br)
- if e != nil {
- return hs, e
- }
- if len(line) == 0 {
- // Blank line, no more lines to read.
- break
- }
-
- k, v, ok := httpParseHeaderLine(line)
- if !ok {
- err = ErrMalformedRequest
- break
- }
-
- switch btsToString(k) {
- case headerHostCanonical:
- headerSeen |= headerSeenHost
- if onHost := u.OnHost; onHost != nil {
- err = onHost(v)
- }
-
- case headerUpgradeCanonical:
- headerSeen |= headerSeenUpgrade
- if !bytes.Equal(v, specHeaderValueUpgrade) && !btsEqualFold(v, specHeaderValueUpgrade) {
- err = ErrHandshakeBadUpgrade
- }
-
- case headerConnectionCanonical:
- headerSeen |= headerSeenConnection
- if !bytes.Equal(v, specHeaderValueConnection) && !btsHasToken(v, specHeaderValueConnectionLower) {
- err = ErrHandshakeBadConnection
- }
-
- case headerSecVersionCanonical:
- headerSeen |= headerSeenSecVersion
- if !bytes.Equal(v, specHeaderValueSecVersion) {
- err = ErrHandshakeUpgradeRequired
- }
-
- case headerSecKeyCanonical:
- headerSeen |= headerSeenSecKey
- if len(v) != nonceSize {
- err = ErrHandshakeBadSecKey
- } else {
- copy(nonce[:], v)
- }
-
- case headerSecProtocolCanonical:
- if custom, check := u.ProtocolCustom, u.Protocol; hs.Protocol == "" && (custom != nil || check != nil) {
- var ok bool
- if custom != nil {
- hs.Protocol, ok = custom(v)
- } else {
- hs.Protocol, ok = btsSelectProtocol(v, check)
- }
- if !ok {
- err = ErrMalformedRequest
- }
- }
-
- case headerSecExtensionsCanonical:
- if custom, check := u.ExtensionCustom, u.Extension; custom != nil || check != nil {
- var ok bool
- if custom != nil {
- hs.Extensions, ok = custom(v, hs.Extensions)
- } else {
- hs.Extensions, ok = btsSelectExtensions(v, hs.Extensions, check)
- }
- if !ok {
- err = ErrMalformedRequest
- }
- }
-
- default:
- if onHeader := u.OnHeader; onHeader != nil {
- err = onHeader(k, v)
- }
- }
- }
- switch {
- case err == nil && headerSeen != headerSeenAll:
- switch {
- case headerSeen&headerSeenHost == 0:
- // As RFC2616 says:
- // A client MUST include a Host header field in all HTTP/1.1
- // request messages. If the requested URI does not include an
- // Internet host name for the service being requested, then the
- // Host header field MUST be given with an empty value. An
- // HTTP/1.1 proxy MUST ensure that any request message it
- // forwards does contain an appropriate Host header field that
- // identifies the service being requested by the proxy. All
- // Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad
- // Request) status code to any HTTP/1.1 request message which
- // lacks a Host header field.
- err = ErrHandshakeBadHost
- case headerSeen&headerSeenUpgrade == 0:
- err = ErrHandshakeBadUpgrade
- case headerSeen&headerSeenConnection == 0:
- err = ErrHandshakeBadConnection
- case headerSeen&headerSeenSecVersion == 0:
- // In case of empty or not present version we do not send 426 status,
- // because it does not meet the ABNF rules of RFC6455:
- //
- // version = DIGIT | (NZDIGIT DIGIT) |
- // ("1" DIGIT DIGIT) | ("2" DIGIT DIGIT)
- // ; Limited to 0-255 range, with no leading zeros
- //
- // That is, if version is really invalid – we sent 426 status as above, if it
- // not present – it is 400.
- err = ErrHandshakeBadSecVersion
- case headerSeen&headerSeenSecKey == 0:
- err = ErrHandshakeBadSecKey
- default:
- panic("unknown headers state")
- }
-
- case err == nil && u.OnBeforeUpgrade != nil:
- header[1], err = u.OnBeforeUpgrade()
- }
- if err != nil {
- var code int
- if rej, ok := err.(*rejectConnectionError); ok {
- code = rej.code
- header[1] = rej.header
- }
- if code == 0 {
- code = http.StatusInternalServerError
- }
- httpWriteResponseError(bw, err, code, header.WriteTo)
- // Do not store Flush() error to not override already existing one.
- bw.Flush()
- return
- }
-
- httpWriteResponseUpgrade(bw, nonce, hs, header.WriteTo)
- err = bw.Flush()
-
- return
-}
-
-type handshakeHeader [2]HandshakeHeader
-
-func (hs handshakeHeader) WriteTo(w io.Writer) (n int64, err error) {
- for i := 0; i < len(hs) && err == nil; i++ {
- if h := hs[i]; h != nil {
- var m int64
- m, err = h.WriteTo(w)
- n += m
- }
- }
- return n, err
-}
diff --git a/vendor/github.com/gobwas/ws/server_test.s b/vendor/github.com/gobwas/ws/server_test.s
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/vendor/github.com/gobwas/ws/util.go b/vendor/github.com/gobwas/ws/util.go
deleted file mode 100644
index de77007ad99..00000000000
--- a/vendor/github.com/gobwas/ws/util.go
+++ /dev/null
@@ -1,255 +0,0 @@
-package ws
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "reflect"
- "unsafe"
-
- "github.com/gobwas/httphead"
-)
-
-// SelectFromSlice creates accept function that could be used as Protocol/Extension
-// select during upgrade.
-func SelectFromSlice(accept []string) func(string) bool {
- if len(accept) > 16 {
- mp := make(map[string]struct{}, len(accept))
- for _, p := range accept {
- mp[p] = struct{}{}
- }
- return func(p string) bool {
- _, ok := mp[p]
- return ok
- }
- }
- return func(p string) bool {
- for _, ok := range accept {
- if p == ok {
- return true
- }
- }
- return false
- }
-}
-
-// SelectEqual creates accept function that could be used as Protocol/Extension
-// select during upgrade.
-func SelectEqual(v string) func(string) bool {
- return func(p string) bool {
- return v == p
- }
-}
-
-func strToBytes(str string) (bts []byte) {
- s := (*reflect.StringHeader)(unsafe.Pointer(&str))
- b := (*reflect.SliceHeader)(unsafe.Pointer(&bts))
- b.Data = s.Data
- b.Len = s.Len
- b.Cap = s.Len
- return
-}
-
-func btsToString(bts []byte) (str string) {
- return *(*string)(unsafe.Pointer(&bts))
-}
-
-// asciiToInt converts bytes to int.
-func asciiToInt(bts []byte) (ret int, err error) {
- // ASCII numbers all start with the high-order bits 0011.
- // If you see that, and the next bits are 0-9 (0000 - 1001) you can grab those
- // bits and interpret them directly as an integer.
- var n int
- if n = len(bts); n < 1 {
- return 0, fmt.Errorf("converting empty bytes to int")
- }
- for i := 0; i < n; i++ {
- if bts[i]&0xf0 != 0x30 {
- return 0, fmt.Errorf("%s is not a numeric character", string(bts[i]))
- }
- ret += int(bts[i]&0xf) * pow(10, n-i-1)
- }
- return ret, nil
-}
-
-// pow for integers implementation.
-// See Donald Knuth, The Art of Computer Programming, Volume 2, Section 4.6.3
-func pow(a, b int) int {
- p := 1
- for b > 0 {
- if b&1 != 0 {
- p *= a
- }
- b >>= 1
- a *= a
- }
- return p
-}
-
-func bsplit3(bts []byte, sep byte) (b1, b2, b3 []byte) {
- a := bytes.IndexByte(bts, sep)
- b := bytes.IndexByte(bts[a+1:], sep)
- if a == -1 || b == -1 {
- return bts, nil, nil
- }
- b += a + 1
- return bts[:a], bts[a+1 : b], bts[b+1:]
-}
-
-func btrim(bts []byte) []byte {
- var i, j int
- for i = 0; i < len(bts) && (bts[i] == ' ' || bts[i] == '\t'); {
- i++
- }
- for j = len(bts); j > i && (bts[j-1] == ' ' || bts[j-1] == '\t'); {
- j--
- }
- return bts[i:j]
-}
-
-func strHasToken(header, token string) (has bool) {
- return btsHasToken(strToBytes(header), strToBytes(token))
-}
-
-func btsHasToken(header, token []byte) (has bool) {
- httphead.ScanTokens(header, func(v []byte) bool {
- has = btsEqualFold(v, token)
- return !has
- })
- return
-}
-
-const (
- toLower = 'a' - 'A' // for use with OR.
- toUpper = ^byte(toLower) // for use with AND.
- toLower8 = uint64(toLower) |
- uint64(toLower)<<8 |
- uint64(toLower)<<16 |
- uint64(toLower)<<24 |
- uint64(toLower)<<32 |
- uint64(toLower)<<40 |
- uint64(toLower)<<48 |
- uint64(toLower)<<56
-)
-
-// Algorithm below is like standard textproto/CanonicalMIMEHeaderKey, except
-// that it operates with slice of bytes and modifies it inplace without copying.
-func canonicalizeHeaderKey(k []byte) {
- upper := true
- for i, c := range k {
- if upper && 'a' <= c && c <= 'z' {
- k[i] &= toUpper
- } else if !upper && 'A' <= c && c <= 'Z' {
- k[i] |= toLower
- }
- upper = c == '-'
- }
-}
-
-// readLine reads line from br. It reads until '\n' and returns bytes without
-// '\n' or '\r\n' at the end.
-// It returns err if and only if line does not end in '\n'. Note that read
-// bytes returned in any case of error.
-//
-// It is much like the textproto/Reader.ReadLine() except the thing that it
-// returns raw bytes, instead of string. That is, it avoids copying bytes read
-// from br.
-//
-// textproto/Reader.ReadLineBytes() is also makes copy of resulting bytes to be
-// safe with future I/O operations on br.
-//
-// We could control I/O operations on br and do not need to make additional
-// copy for safety.
-//
-// NOTE: it may return copied flag to notify that returned buffer is safe to
-// use.
-func readLine(br *bufio.Reader) ([]byte, error) {
- var line []byte
- for {
- bts, err := br.ReadSlice('\n')
- if err == bufio.ErrBufferFull {
- // Copy bytes because next read will discard them.
- line = append(line, bts...)
- continue
- }
-
- // Avoid copy of single read.
- if line == nil {
- line = bts
- } else {
- line = append(line, bts...)
- }
-
- if err != nil {
- return line, err
- }
-
- // Size of line is at least 1.
- // In other case bufio.ReadSlice() returns error.
- n := len(line)
-
- // Cut '\n' or '\r\n'.
- if n > 1 && line[n-2] == '\r' {
- line = line[:n-2]
- } else {
- line = line[:n-1]
- }
-
- return line, nil
- }
-}
-
-// strEqualFold checks s to be case insensitive equal to p.
-// Note that p must be only ascii letters. That is, every byte in p belongs to
-// range ['a','z'] or ['A','Z'].
-func strEqualFold(s, p string) bool {
- return btsEqualFold(strToBytes(s), strToBytes(p))
-}
-
-// btsEqualFold checks s to be case insensitive equal to p.
-// Note that p must be only ascii letters. That is, every byte in p belongs to
-// range ['a','z'] or ['A','Z'].
-func btsEqualFold(s, p []byte) bool {
- if len(s) != len(p) {
- return false
- }
- n := len(s)
- // Prepare manual conversion on bytes that not lay in uint64.
- m := n % 8
- for i := 0; i < m; i++ {
- if s[i]|toLower != p[i]|toLower {
- return false
- }
- }
- // Iterate over uint64 parts of s.
- n = (n - m) >> 3
- if n == 0 {
- // There are no more bytes to compare.
- return true
- }
-
- for i := 0; i < n; i++ {
- x := m + (i << 3)
- av := *(*uint64)(unsafe.Pointer(&s[x]))
- bv := *(*uint64)(unsafe.Pointer(&p[x]))
- if av|toLower8 != bv|toLower8 {
- return false
- }
- }
-
- return true
-}
-
-func min(a, b int) int {
- if a < b {
- return a
- }
- return b
-}
-
-func nonZero(a, b int) int {
- if a != 0 {
- return a
- }
- return b
-}
diff --git a/vendor/github.com/gobwas/ws/write.go b/vendor/github.com/gobwas/ws/write.go
deleted file mode 100644
index 94557c69639..00000000000
--- a/vendor/github.com/gobwas/ws/write.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package ws
-
-import (
- "encoding/binary"
- "io"
-)
-
-// Header size length bounds in bytes.
-const (
- MaxHeaderSize = 14
- MinHeaderSize = 2
-)
-
-const (
- bit0 = 0x80
- bit1 = 0x40
- bit2 = 0x20
- bit3 = 0x10
- bit4 = 0x08
- bit5 = 0x04
- bit6 = 0x02
- bit7 = 0x01
-
- len7 = int64(125)
- len16 = int64(^(uint16(0)))
- len64 = int64(^(uint64(0)) >> 1)
-)
-
-// HeaderSize returns number of bytes that are needed to encode given header.
-// It returns -1 if header is malformed.
-func HeaderSize(h Header) (n int) {
- switch {
- case h.Length < 126:
- n = 2
- case h.Length <= len16:
- n = 4
- case h.Length <= len64:
- n = 10
- default:
- return -1
- }
- if h.Masked {
- n += len(h.Mask)
- }
- return n
-}
-
-// WriteHeader writes header binary representation into w.
-func WriteHeader(w io.Writer, h Header) error {
- // Make slice of bytes with capacity 14 that could hold any header.
- bts := make([]byte, MaxHeaderSize)
-
- if h.Fin {
- bts[0] |= bit0
- }
- bts[0] |= h.Rsv << 4
- bts[0] |= byte(h.OpCode)
-
- var n int
- switch {
- case h.Length <= len7:
- bts[1] = byte(h.Length)
- n = 2
-
- case h.Length <= len16:
- bts[1] = 126
- binary.BigEndian.PutUint16(bts[2:4], uint16(h.Length))
- n = 4
-
- case h.Length <= len64:
- bts[1] = 127
- binary.BigEndian.PutUint64(bts[2:10], uint64(h.Length))
- n = 10
-
- default:
- return ErrHeaderLengthUnexpected
- }
-
- if h.Masked {
- bts[1] |= bit0
- n += copy(bts[n:], h.Mask[:])
- }
-
- _, err := w.Write(bts[:n])
-
- return err
-}
-
-// WriteFrame writes frame binary representation into w.
-func WriteFrame(w io.Writer, f Frame) error {
- err := WriteHeader(w, f.Header)
- if err != nil {
- return err
- }
- _, err = w.Write(f.Payload)
- return err
-}
-
-// MustWriteFrame is like WriteFrame but panics if frame can not be read.
-func MustWriteFrame(w io.Writer, f Frame) {
- if err := WriteFrame(w, f); err != nil {
- panic(err)
- }
-}
diff --git a/vendor/github.com/gobwas/ws/ws.go b/vendor/github.com/gobwas/ws/ws.go
deleted file mode 100644
index c9d5791570c..00000000000
--- a/vendor/github.com/gobwas/ws/ws.go
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-Package ws implements a client and server for the WebSocket protocol as
-specified in RFC 6455.
-
-The main purpose of this package is to provide simple low-level API for
-efficient work with protocol.
-
-Overview.
-
-Upgrade to WebSocket (or WebSocket handshake) can be done in two ways.
-
-The first way is to use `net/http` server:
-
- http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
- conn, _, _, err := ws.UpgradeHTTP(r, w)
- })
-
-The second and much more efficient way is so-called "zero-copy upgrade". It
-avoids redundant allocations and copying of not used headers or other request
-data. User decides by himself which data should be copied.
-
- ln, err := net.Listen("tcp", ":8080")
- if err != nil {
- // handle error
- }
-
- conn, err := ln.Accept()
- if err != nil {
- // handle error
- }
-
- handshake, err := ws.Upgrade(conn)
- if err != nil {
- // handle error
- }
-
-For customization details see `ws.Upgrader` documentation.
-
-After WebSocket handshake you can work with connection in multiple ways.
-That is, `ws` does not force the only one way of how to work with WebSocket:
-
- header, err := ws.ReadHeader(conn)
- if err != nil {
- // handle err
- }
-
- buf := make([]byte, header.Length)
- _, err := io.ReadFull(conn, buf)
- if err != nil {
- // handle err
- }
-
- resp := ws.NewBinaryFrame([]byte("hello, world!"))
- if err := ws.WriteFrame(conn, frame); err != nil {
- // handle err
- }
-
-As you can see, it stream friendly:
-
- const N = 42
-
- ws.WriteHeader(ws.Header{
- Fin: true,
- Length: N,
- OpCode: ws.OpBinary,
- })
-
- io.CopyN(conn, rand.Reader, N)
-
-Or:
-
- header, err := ws.ReadHeader(conn)
- if err != nil {
- // handle err
- }
-
- io.CopyN(ioutil.Discard, conn, header.Length)
-
-For more info see the documentation.
-*/
-package ws
diff --git a/vendor/github.com/gobwas/ws/wsutil/cipher.go b/vendor/github.com/gobwas/ws/wsutil/cipher.go
deleted file mode 100644
index f234be73226..00000000000
--- a/vendor/github.com/gobwas/ws/wsutil/cipher.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package wsutil
-
-import (
- "io"
-
- "github.com/gobwas/pool/pbytes"
- "github.com/gobwas/ws"
-)
-
-// CipherReader implements io.Reader that applies xor-cipher to the bytes read
-// from source.
-// It could help to unmask WebSocket frame payload on the fly.
-type CipherReader struct {
- r io.Reader
- mask [4]byte
- pos int
-}
-
-// NewCipherReader creates xor-cipher reader from r with given mask.
-func NewCipherReader(r io.Reader, mask [4]byte) *CipherReader {
- return &CipherReader{r, mask, 0}
-}
-
-// Reset resets CipherReader to read from r with given mask.
-func (c *CipherReader) Reset(r io.Reader, mask [4]byte) {
- c.r = r
- c.mask = mask
- c.pos = 0
-}
-
-// Read implements io.Reader interface. It applies mask given during
-// initialization to every read byte.
-func (c *CipherReader) Read(p []byte) (n int, err error) {
- n, err = c.r.Read(p)
- ws.Cipher(p[:n], c.mask, c.pos)
- c.pos += n
- return
-}
-
-// CipherWriter implements io.Writer that applies xor-cipher to the bytes
-// written to the destination writer. It does not modify the original bytes.
-type CipherWriter struct {
- w io.Writer
- mask [4]byte
- pos int
-}
-
-// NewCipherWriter creates xor-cipher writer to w with given mask.
-func NewCipherWriter(w io.Writer, mask [4]byte) *CipherWriter {
- return &CipherWriter{w, mask, 0}
-}
-
-// Reset reset CipherWriter to write to w with given mask.
-func (c *CipherWriter) Reset(w io.Writer, mask [4]byte) {
- c.w = w
- c.mask = mask
- c.pos = 0
-}
-
-// Write implements io.Writer interface. It applies masking during
-// initialization to every sent byte. It does not modify original slice.
-func (c *CipherWriter) Write(p []byte) (n int, err error) {
- cp := pbytes.GetLen(len(p))
- defer pbytes.Put(cp)
-
- copy(cp, p)
- ws.Cipher(cp, c.mask, c.pos)
- n, err = c.w.Write(cp)
- c.pos += n
-
- return
-}
diff --git a/vendor/github.com/gobwas/ws/wsutil/dialer.go b/vendor/github.com/gobwas/ws/wsutil/dialer.go
deleted file mode 100644
index 91c03d512b1..00000000000
--- a/vendor/github.com/gobwas/ws/wsutil/dialer.go
+++ /dev/null
@@ -1,146 +0,0 @@
-package wsutil
-
-import (
- "bufio"
- "bytes"
- "context"
- "io"
- "io/ioutil"
- "net"
- "net/http"
-
- "github.com/gobwas/ws"
-)
-
-// DebugDialer is a wrapper around ws.Dialer. It tracks i/o of WebSocket
-// handshake. That is, it gives ability to receive copied HTTP request and
-// response bytes that made inside Dialer.Dial().
-//
-// Note that it must not be used in production applications that requires
-// Dial() to be efficient.
-type DebugDialer struct {
- // Dialer contains WebSocket connection establishment options.
- Dialer ws.Dialer
-
- // OnRequest and OnResponse are the callbacks that will be called with the
- // HTTP request and response respectively.
- OnRequest, OnResponse func([]byte)
-}
-
-// Dial connects to the url host and upgrades connection to WebSocket. It makes
-// it by calling d.Dialer.Dial().
-func (d *DebugDialer) Dial(ctx context.Context, urlstr string) (conn net.Conn, br *bufio.Reader, hs ws.Handshake, err error) {
- // Need to copy Dialer to prevent original object mutation.
- dialer := d.Dialer
- var (
- reqBuf bytes.Buffer
- resBuf bytes.Buffer
-
- resContentLength int64
- )
- userWrap := dialer.WrapConn
- dialer.WrapConn = func(c net.Conn) net.Conn {
- if userWrap != nil {
- c = userWrap(c)
- }
-
- // Save the pointer to the raw connection.
- conn = c
-
- var (
- r io.Reader = conn
- w io.Writer = conn
- )
- if d.OnResponse != nil {
- r = &prefetchResponseReader{
- source: conn,
- buffer: &resBuf,
- contentLength: &resContentLength,
- }
- }
- if d.OnRequest != nil {
- w = io.MultiWriter(conn, &reqBuf)
- }
- return rwConn{conn, r, w}
- }
-
- _, br, hs, err = dialer.Dial(ctx, urlstr)
-
- if onRequest := d.OnRequest; onRequest != nil {
- onRequest(reqBuf.Bytes())
- }
- if onResponse := d.OnResponse; onResponse != nil {
- // We must split response inside buffered bytes from other received
- // bytes from server.
- p := resBuf.Bytes()
- n := bytes.Index(p, headEnd)
- h := n + len(headEnd) // Head end index.
- n = h + int(resContentLength) // Body end index.
-
- onResponse(p[:n])
-
- if br != nil {
- // If br is non-nil, then it mean two things. First is that
- // handshake is OK and server has sent additional bytes – probably
- // immediate sent frames (or weird but possible response body).
- // Second, the bad one, is that br buffer's source is now rwConn
- // instance from above WrapConn call. It is incorrect, so we must
- // fix it.
- var r io.Reader = conn
- if len(p) > h {
- // Buffer contains more than just HTTP headers bytes.
- r = io.MultiReader(
- bytes.NewReader(p[h:]),
- conn,
- )
- }
- br.Reset(r)
- // Must make br.Buffered() to be non-zero.
- br.Peek(len(p[h:]))
- }
- }
-
- return conn, br, hs, err
-}
-
-type rwConn struct {
- net.Conn
-
- r io.Reader
- w io.Writer
-}
-
-func (rwc rwConn) Read(p []byte) (int, error) {
- return rwc.r.Read(p)
-}
-func (rwc rwConn) Write(p []byte) (int, error) {
- return rwc.w.Write(p)
-}
-
-var headEnd = []byte("\r\n\r\n")
-
-type prefetchResponseReader struct {
- source io.Reader // Original connection source.
- reader io.Reader // Wrapped reader used to read from by clients.
- buffer *bytes.Buffer
-
- contentLength *int64
-}
-
-func (r *prefetchResponseReader) Read(p []byte) (int, error) {
- if r.reader == nil {
- resp, err := http.ReadResponse(bufio.NewReader(
- io.TeeReader(r.source, r.buffer),
- ), nil)
- if err == nil {
- *r.contentLength, _ = io.Copy(ioutil.Discard, resp.Body)
- resp.Body.Close()
- }
- bts := r.buffer.Bytes()
- r.reader = io.MultiReader(
- bytes.NewReader(bts),
- r.source,
- )
- }
- return r.reader.Read(p)
-}
diff --git a/vendor/github.com/gobwas/ws/wsutil/handler.go b/vendor/github.com/gobwas/ws/wsutil/handler.go
deleted file mode 100644
index a8f499fca32..00000000000
--- a/vendor/github.com/gobwas/ws/wsutil/handler.go
+++ /dev/null
@@ -1,219 +0,0 @@
-package wsutil
-
-import (
- "errors"
- "io"
- "io/ioutil"
- "strconv"
-
- "github.com/gobwas/pool/pbytes"
- "github.com/gobwas/ws"
-)
-
-// ClosedError returned when peer has closed the connection with appropriate
-// code and a textual reason.
-type ClosedError struct {
- Code ws.StatusCode
- Reason string
-}
-
-// Error implements error interface.
-func (err ClosedError) Error() string {
- return "ws closed: " + strconv.FormatUint(uint64(err.Code), 10) + " " + err.Reason
-}
-
-// ControlHandler contains logic of handling control frames.
-//
-// The intentional way to use it is to read the next frame header from the
-// connection, optionally check its validity via ws.CheckHeader() and if it is
-// not a ws.OpText of ws.OpBinary (or ws.OpContinuation) – pass it to Handle()
-// method.
-//
-// That is, passed header should be checked to get rid of unexpected errors.
-//
-// The Handle() method will read out all control frame payload (if any) and
-// write necessary bytes as a rfc compatible response.
-type ControlHandler struct {
- Src io.Reader
- Dst io.Writer
- State ws.State
-
- // DisableSrcCiphering disables unmasking payload data read from Src.
- // It is useful when wsutil.Reader is used or when frame payload already
- // pulled and ciphered out from the connection (and introduced by
- // bytes.Reader, for example).
- DisableSrcCiphering bool
-}
-
-// ErrNotControlFrame is returned by ControlHandler to indicate that given
-// header could not be handled.
-var ErrNotControlFrame = errors.New("not a control frame")
-
-// Handle handles control frames regarding to the c.State and writes responses
-// to the c.Dst when needed.
-//
-// It returns ErrNotControlFrame when given header is not of ws.OpClose,
-// ws.OpPing or ws.OpPong operation code.
-func (c ControlHandler) Handle(h ws.Header) error {
- switch h.OpCode {
- case ws.OpPing:
- return c.HandlePing(h)
- case ws.OpPong:
- return c.HandlePong(h)
- case ws.OpClose:
- return c.HandleClose(h)
- }
- return ErrNotControlFrame
-}
-
-// HandlePing handles ping frame and writes specification compatible response
-// to the c.Dst.
-func (c ControlHandler) HandlePing(h ws.Header) error {
- if h.Length == 0 {
- // The most common case when ping is empty.
- // Note that when sending masked frame the mask for empty payload is
- // just four zero bytes.
- return ws.WriteHeader(c.Dst, ws.Header{
- Fin: true,
- OpCode: ws.OpPong,
- Masked: c.State.ClientSide(),
- })
- }
-
- // In other way reply with Pong frame with copied payload.
- p := pbytes.GetLen(int(h.Length) + ws.HeaderSize(ws.Header{
- Length: h.Length,
- Masked: c.State.ClientSide(),
- }))
- defer pbytes.Put(p)
-
- // Deal with ciphering i/o:
- // Masking key is used to mask the "Payload data" defined in the same
- // section as frame-payload-data, which includes "Extension data" and
- // "Application data".
- //
- // See https://tools.ietf.org/html/rfc6455#section-5.3
- //
- // NOTE: We prefer ControlWriter with preallocated buffer to
- // ws.WriteHeader because it performs one syscall instead of two.
- w := NewControlWriterBuffer(c.Dst, c.State, ws.OpPong, p)
- r := c.Src
- if c.State.ServerSide() && !c.DisableSrcCiphering {
- r = NewCipherReader(r, h.Mask)
- }
-
- _, err := io.Copy(w, r)
- if err == nil {
- err = w.Flush()
- }
-
- return err
-}
-
-// HandlePong handles pong frame by discarding it.
-func (c ControlHandler) HandlePong(h ws.Header) error {
- if h.Length == 0 {
- return nil
- }
-
- buf := pbytes.GetLen(int(h.Length))
- defer pbytes.Put(buf)
-
- // Discard pong message according to the RFC6455:
- // A Pong frame MAY be sent unsolicited. This serves as a
- // unidirectional heartbeat. A response to an unsolicited Pong frame
- // is not expected.
- _, err := io.CopyBuffer(ioutil.Discard, c.Src, buf)
-
- return err
-}
-
-// HandleClose handles close frame, makes protocol validity checks and writes
-// specification compatible response to the c.Dst.
-func (c ControlHandler) HandleClose(h ws.Header) error {
- if h.Length == 0 {
- err := ws.WriteHeader(c.Dst, ws.Header{
- Fin: true,
- OpCode: ws.OpClose,
- Masked: c.State.ClientSide(),
- })
- if err != nil {
- return err
- }
-
- // Due to RFC, we should interpret the code as no status code
- // received:
- // If this Close control frame contains no status code, _The WebSocket
- // Connection Close Code_ is considered to be 1005.
- //
- // See https://tools.ietf.org/html/rfc6455#section-7.1.5
- return ClosedError{
- Code: ws.StatusNoStatusRcvd,
- }
- }
-
- // Prepare bytes both for reading reason and sending response.
- p := pbytes.GetLen(int(h.Length) + ws.HeaderSize(ws.Header{
- Length: h.Length,
- Masked: c.State.ClientSide(),
- }))
- defer pbytes.Put(p)
-
- // Get the subslice to read the frame payload out.
- subp := p[:h.Length]
-
- r := c.Src
- if c.State.ServerSide() && !c.DisableSrcCiphering {
- r = NewCipherReader(r, h.Mask)
- }
- if _, err := io.ReadFull(r, subp); err != nil {
- return err
- }
-
- code, reason := ws.ParseCloseFrameData(subp)
- if err := ws.CheckCloseFrameData(code, reason); err != nil {
- // Here we could not use the prepared bytes because there is no
- // guarantee that it may fit our protocol error closure code and a
- // reason.
- c.closeWithProtocolError(err)
- return err
- }
-
- // Deal with ciphering i/o:
- // Masking key is used to mask the "Payload data" defined in the same
- // section as frame-payload-data, which includes "Extension data" and
- // "Application data".
- //
- // See https://tools.ietf.org/html/rfc6455#section-5.3
- //
- // NOTE: We prefer ControlWriter with preallocated buffer to
- // ws.WriteHeader because it performs one syscall instead of two.
- w := NewControlWriterBuffer(c.Dst, c.State, ws.OpClose, p)
-
- // RFC6455#5.5.1:
- // If an endpoint receives a Close frame and did not previously
- // send a Close frame, the endpoint MUST send a Close frame in
- // response. (When sending a Close frame in response, the endpoint
- // typically echos the status code it received.)
- _, err := w.Write(p[:2])
- if err != nil {
- return err
- }
- if err = w.Flush(); err != nil {
- return err
- }
- return ClosedError{
- Code: code,
- Reason: reason,
- }
-}
-
-func (c ControlHandler) closeWithProtocolError(reason error) error {
- f := ws.NewCloseFrame(ws.NewCloseFrameBody(
- ws.StatusProtocolError, reason.Error(),
- ))
- if c.State.ClientSide() {
- ws.MaskFrameInPlace(f)
- }
- return ws.WriteFrame(c.Dst, f)
-}
diff --git a/vendor/github.com/gobwas/ws/wsutil/helper.go b/vendor/github.com/gobwas/ws/wsutil/helper.go
deleted file mode 100644
index 0a63def4ba7..00000000000
--- a/vendor/github.com/gobwas/ws/wsutil/helper.go
+++ /dev/null
@@ -1,279 +0,0 @@
-package wsutil
-
-import (
- "bytes"
- "io"
- "io/ioutil"
-
- "github.com/gobwas/ws"
-)
-
-// Message represents a message from peer, that could be presented in one or
-// more frames. That is, it contains payload of all message fragments and
-// operation code of initial frame for this message.
-type Message struct {
- OpCode ws.OpCode
- Payload []byte
-}
-
-// ReadMessage is a helper function that reads next message from r. It appends
-// received message(s) to the third argument and returns the result of it and
-// an error if some failure happened. That is, it probably could receive more
-// than one message when peer sending fragmented message in multiple frames and
-// want to send some control frame between fragments. Then returned slice will
-// contain those control frames at first, and then result of gluing fragments.
-//
-// TODO(gobwas): add DefaultReader with buffer size options.
-func ReadMessage(r io.Reader, s ws.State, m []Message) ([]Message, error) {
- rd := Reader{
- Source: r,
- State: s,
- CheckUTF8: true,
- OnIntermediate: func(hdr ws.Header, src io.Reader) error {
- bts, err := ioutil.ReadAll(src)
- if err != nil {
- return err
- }
- m = append(m, Message{hdr.OpCode, bts})
- return nil
- },
- }
- h, err := rd.NextFrame()
- if err != nil {
- return m, err
- }
- var p []byte
- if h.Fin {
- // No more frames will be read. Use fixed sized buffer to read payload.
- p = make([]byte, h.Length)
- // It is not possible to receive io.EOF here because Reader does not
- // return EOF if frame payload was successfully fetched.
- // Thus we consistent here with io.Reader behavior.
- _, err = io.ReadFull(&rd, p)
- } else {
- // Frame is fragmented, thus use ioutil.ReadAll behavior.
- var buf bytes.Buffer
- _, err = buf.ReadFrom(&rd)
- p = buf.Bytes()
- }
- if err != nil {
- return m, err
- }
- return append(m, Message{h.OpCode, p}), nil
-}
-
-// ReadClientMessage reads next message from r, considering that caller
-// represents server side.
-// It is a shortcut for ReadMessage(r, ws.StateServerSide, m)
-func ReadClientMessage(r io.Reader, m []Message) ([]Message, error) {
- return ReadMessage(r, ws.StateServerSide, m)
-}
-
-// ReadServerMessage reads next message from r, considering that caller
-// represents client side.
-// It is a shortcut for ReadMessage(r, ws.StateClientSide, m)
-func ReadServerMessage(r io.Reader, m []Message) ([]Message, error) {
- return ReadMessage(r, ws.StateClientSide, m)
-}
-
-// ReadData is a helper function that reads next data (non-control) message
-// from rw.
-// It takes care on handling all control frames. It will write response on
-// control frames to the write part of rw. It blocks until some data frame
-// will be received.
-//
-// Note this may handle and write control frames into the writer part of a
-// given io.ReadWriter.
-func ReadData(rw io.ReadWriter, s ws.State) ([]byte, ws.OpCode, error) {
- return readData(rw, s, ws.OpText|ws.OpBinary)
-}
-
-// ReadClientData reads next data message from rw, considering that caller
-// represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
-//
-// Note this may handle and write control frames into the writer part of a
-// given io.ReadWriter.
-func ReadClientData(rw io.ReadWriter) ([]byte, ws.OpCode, error) {
- return ReadData(rw, ws.StateServerSide)
-}
-
-// ReadClientText reads next text message from rw, considering that caller
-// represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
-// It discards received binary messages.
-//
-// Note this may handle and write control frames into the writer part of a
-// given io.ReadWriter.
-func ReadClientText(rw io.ReadWriter) ([]byte, error) {
- p, _, err := readData(rw, ws.StateServerSide, ws.OpText)
- return p, err
-}
-
-// ReadClientBinary reads next binary message from rw, considering that caller
-// represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
-// It discards received text messages.
-//
-// Note this may handle and write control frames into the writer part of a given
-// io.ReadWriter.
-func ReadClientBinary(rw io.ReadWriter) ([]byte, error) {
- p, _, err := readData(rw, ws.StateServerSide, ws.OpBinary)
- return p, err
-}
-
-// ReadServerData reads next data message from rw, considering that caller
-// represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
-//
-// Note this may handle and write control frames into the writer part of a
-// given io.ReadWriter.
-func ReadServerData(rw io.ReadWriter) ([]byte, ws.OpCode, error) {
- return ReadData(rw, ws.StateClientSide)
-}
-
-// ReadServerText reads next text message from rw, considering that caller
-// represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
-// It discards received binary messages.
-//
-// Note this may handle and write control frames into the writer part of a given
-// io.ReadWriter.
-func ReadServerText(rw io.ReadWriter) ([]byte, error) {
- p, _, err := readData(rw, ws.StateClientSide, ws.OpText)
- return p, err
-}
-
-// ReadServerBinary reads next binary message from rw, considering that caller
-// represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
-// It discards received text messages.
-//
-// Note this may handle and write control frames into the writer part of a
-// given io.ReadWriter.
-func ReadServerBinary(rw io.ReadWriter) ([]byte, error) {
- p, _, err := readData(rw, ws.StateClientSide, ws.OpBinary)
- return p, err
-}
-
-// WriteMessage is a helper function that writes message to the w. It
-// constructs single frame with given operation code and payload.
-// It uses given state to prepare side-dependtend things, like cipher
-// payload bytes from client to server. It will not mutate p bytes if
-// cipher must be made.
-//
-// If you want to write message in fragmented frames, use Writer instead.
-func WriteMessage(w io.Writer, s ws.State, op ws.OpCode, p []byte) error {
- return writeFrame(w, s, op, true, p)
-}
-
-// WriteServerMessage writes message to w, considering that caller
-// represents server side.
-func WriteServerMessage(w io.Writer, op ws.OpCode, p []byte) error {
- return WriteMessage(w, ws.StateServerSide, op, p)
-}
-
-// WriteServerText is the same as WriteServerMessage with
-// ws.OpText.
-func WriteServerText(w io.Writer, p []byte) error {
- return WriteServerMessage(w, ws.OpText, p)
-}
-
-// WriteServerBinary is the same as WriteServerMessage with
-// ws.OpBinary.
-func WriteServerBinary(w io.Writer, p []byte) error {
- return WriteServerMessage(w, ws.OpBinary, p)
-}
-
-// WriteClientMessage writes message to w, considering that caller
-// represents client side.
-func WriteClientMessage(w io.Writer, op ws.OpCode, p []byte) error {
- return WriteMessage(w, ws.StateClientSide, op, p)
-}
-
-// WriteClientText is the same as WriteClientMessage with
-// ws.OpText.
-func WriteClientText(w io.Writer, p []byte) error {
- return WriteClientMessage(w, ws.OpText, p)
-}
-
-// WriteClientBinary is the same as WriteClientMessage with
-// ws.OpBinary.
-func WriteClientBinary(w io.Writer, p []byte) error {
- return WriteClientMessage(w, ws.OpBinary, p)
-}
-
-// HandleClientControlMessage handles control frame from conn and writes
-// response when needed.
-//
-// It considers that caller represents server side.
-func HandleClientControlMessage(conn io.Writer, msg Message) error {
- return HandleControlMessage(conn, ws.StateServerSide, msg)
-}
-
-// HandleServerControlMessage handles control frame from conn and writes
-// response when needed.
-//
-// It considers that caller represents client side.
-func HandleServerControlMessage(conn io.Writer, msg Message) error {
- return HandleControlMessage(conn, ws.StateClientSide, msg)
-}
-
-// HandleControlMessage handles message which was read by ReadMessage()
-// functions.
-//
-// That is, it is expected, that payload is already unmasked and frame header
-// were checked by ws.CheckHeader() call.
-func HandleControlMessage(conn io.Writer, state ws.State, msg Message) error {
- return (ControlHandler{
- DisableSrcCiphering: true,
- Src: bytes.NewReader(msg.Payload),
- Dst: conn,
- State: state,
- }).Handle(ws.Header{
- Length: int64(len(msg.Payload)),
- OpCode: msg.OpCode,
- Fin: true,
- Masked: state.ServerSide(),
- })
-}
-
-// ControlFrameHandler returns FrameHandlerFunc for handling control frames.
-// For more info see ControlHandler docs.
-func ControlFrameHandler(w io.Writer, state ws.State) FrameHandlerFunc {
- return func(h ws.Header, r io.Reader) error {
- return (ControlHandler{
- DisableSrcCiphering: true,
- Src: r,
- Dst: w,
- State: state,
- }).Handle(h)
- }
-}
-
-func readData(rw io.ReadWriter, s ws.State, want ws.OpCode) ([]byte, ws.OpCode, error) {
- controlHandler := ControlFrameHandler(rw, s)
- rd := Reader{
- Source: rw,
- State: s,
- CheckUTF8: true,
- SkipHeaderCheck: false,
- OnIntermediate: controlHandler,
- }
- for {
- hdr, err := rd.NextFrame()
- if err != nil {
- return nil, 0, err
- }
- if hdr.OpCode.IsControl() {
- if err := controlHandler(hdr, &rd); err != nil {
- return nil, 0, err
- }
- continue
- }
- if hdr.OpCode&want == 0 {
- if err := rd.Discard(); err != nil {
- return nil, 0, err
- }
- continue
- }
-
- bts, err := ioutil.ReadAll(&rd)
-
- return bts, hdr.OpCode, err
- }
-}
diff --git a/vendor/github.com/gobwas/ws/wsutil/reader.go b/vendor/github.com/gobwas/ws/wsutil/reader.go
deleted file mode 100644
index f3f9c231817..00000000000
--- a/vendor/github.com/gobwas/ws/wsutil/reader.go
+++ /dev/null
@@ -1,257 +0,0 @@
-package wsutil
-
-import (
- "errors"
- "io"
- "io/ioutil"
-
- "github.com/gobwas/ws"
-)
-
-// ErrNoFrameAdvance means that Reader's Read() method was called without
-// preceding NextFrame() call.
-var ErrNoFrameAdvance = errors.New("no frame advance")
-
-// FrameHandlerFunc handles parsed frame header and its body represetned by
-// io.Reader.
-//
-// Note that reader represents already unmasked body.
-type FrameHandlerFunc func(ws.Header, io.Reader) error
-
-// Reader is a wrapper around source io.Reader which represents WebSocket
-// connection. It contains options for reading messages from source.
-//
-// Reader implements io.Reader, which Read() method reads payload of incoming
-// WebSocket frames. It also takes care on fragmented frames and possibly
-// intermediate control frames between them.
-//
-// Note that Reader's methods are not goroutine safe.
-type Reader struct {
- Source io.Reader
- State ws.State
-
- // SkipHeaderCheck disables checking header bits to be RFC6455 compliant.
- SkipHeaderCheck bool
-
- // CheckUTF8 enables UTF-8 checks for text frames payload. If incoming
- // bytes are not valid UTF-8 sequence, ErrInvalidUTF8 returned.
- CheckUTF8 bool
-
- // TODO(gobwas): add max frame size limit here.
-
- OnContinuation FrameHandlerFunc
- OnIntermediate FrameHandlerFunc
-
- opCode ws.OpCode // Used to store message op code on fragmentation.
- frame io.Reader // Used to as frame reader.
- raw io.LimitedReader // Used to discard frames without cipher.
- utf8 UTF8Reader // Used to check UTF8 sequences if CheckUTF8 is true.
-}
-
-// NewReader creates new frame reader that reads from r keeping given state to
-// make some protocol validity checks when it needed.
-func NewReader(r io.Reader, s ws.State) *Reader {
- return &Reader{
- Source: r,
- State: s,
- }
-}
-
-// NewClientSideReader is a helper function that calls NewReader with r and
-// ws.StateClientSide.
-func NewClientSideReader(r io.Reader) *Reader {
- return NewReader(r, ws.StateClientSide)
-}
-
-// NewServerSideReader is a helper function that calls NewReader with r and
-// ws.StateServerSide.
-func NewServerSideReader(r io.Reader) *Reader {
- return NewReader(r, ws.StateServerSide)
-}
-
-// Read implements io.Reader. It reads the next message payload into p.
-// It takes care on fragmented messages.
-//
-// The error is io.EOF only if all of message bytes were read.
-// If an io.EOF happens during reading some but not all the message bytes
-// Read() returns io.ErrUnexpectedEOF.
-//
-// The error is ErrNoFrameAdvance if no NextFrame() call was made before
-// reading next message bytes.
-func (r *Reader) Read(p []byte) (n int, err error) {
- if r.frame == nil {
- if !r.fragmented() {
- // Every new Read() must be preceded by NextFrame() call.
- return 0, ErrNoFrameAdvance
- }
- // Read next continuation or intermediate control frame.
- _, err := r.NextFrame()
- if err != nil {
- return 0, err
- }
- if r.frame == nil {
- // We handled intermediate control and now got nothing to read.
- return 0, nil
- }
- }
-
- n, err = r.frame.Read(p)
- if err != nil && err != io.EOF {
- return
- }
- if err == nil && r.raw.N != 0 {
- return
- }
-
- switch {
- case r.raw.N != 0:
- err = io.ErrUnexpectedEOF
-
- case r.fragmented():
- err = nil
- r.resetFragment()
-
- case r.CheckUTF8 && !r.utf8.Valid():
- n = r.utf8.Accepted()
- err = ErrInvalidUTF8
-
- default:
- r.reset()
- err = io.EOF
- }
-
- return
-}
-
-// Discard discards current message unread bytes.
-// It discards all frames of fragmented message.
-func (r *Reader) Discard() (err error) {
- for {
- _, err = io.Copy(ioutil.Discard, &r.raw)
- if err != nil {
- break
- }
- if !r.fragmented() {
- break
- }
- if _, err = r.NextFrame(); err != nil {
- break
- }
- }
- r.reset()
- return err
-}
-
-// NextFrame prepares r to read next message. It returns received frame header
-// and non-nil error on failure.
-//
-// Note that next NextFrame() call must be done after receiving or discarding
-// all current message bytes.
-func (r *Reader) NextFrame() (hdr ws.Header, err error) {
- hdr, err = ws.ReadHeader(r.Source)
- if err == io.EOF && r.fragmented() {
- // If we are in fragmented state EOF means that is was totally
- // unexpected.
- //
- // NOTE: This is necessary to prevent callers such that
- // ioutil.ReadAll to receive some amount of bytes without an error.
- // ReadAll() ignores an io.EOF error, thus caller may think that
- // whole message fetched, but actually only part of it.
- err = io.ErrUnexpectedEOF
- }
- if err == nil && !r.SkipHeaderCheck {
- err = ws.CheckHeader(hdr, r.State)
- }
- if err != nil {
- return hdr, err
- }
-
- // Save raw reader to use it on discarding frame without ciphering and
- // other streaming checks.
- r.raw = io.LimitedReader{r.Source, hdr.Length}
-
- frame := io.Reader(&r.raw)
- if hdr.Masked {
- frame = NewCipherReader(frame, hdr.Mask)
- }
- if r.fragmented() {
- if hdr.OpCode.IsControl() {
- if cb := r.OnIntermediate; cb != nil {
- err = cb(hdr, frame)
- }
- if err == nil {
- // Ensure that src is empty.
- _, err = io.Copy(ioutil.Discard, &r.raw)
- }
- return
- }
- } else {
- r.opCode = hdr.OpCode
- }
- if r.CheckUTF8 && (hdr.OpCode == ws.OpText || (r.fragmented() && r.opCode == ws.OpText)) {
- r.utf8.Source = frame
- frame = &r.utf8
- }
-
- // Save reader with ciphering and other streaming checks.
- r.frame = frame
-
- if hdr.OpCode == ws.OpContinuation {
- if cb := r.OnContinuation; cb != nil {
- err = cb(hdr, frame)
- }
- }
-
- if hdr.Fin {
- r.State = r.State.Clear(ws.StateFragmented)
- } else {
- r.State = r.State.Set(ws.StateFragmented)
- }
-
- return
-}
-
-func (r *Reader) fragmented() bool {
- return r.State.Fragmented()
-}
-
-func (r *Reader) resetFragment() {
- r.raw = io.LimitedReader{}
- r.frame = nil
- // Reset source of the UTF8Reader, but not the state.
- r.utf8.Source = nil
-}
-
-func (r *Reader) reset() {
- r.raw = io.LimitedReader{}
- r.frame = nil
- r.utf8 = UTF8Reader{}
- r.opCode = 0
-}
-
-// NextReader prepares next message read from r. It returns header that
-// describes the message and io.Reader to read message's payload. It returns
-// non-nil error when it is not possible to read message's initial frame.
-//
-// Note that next NextReader() on the same r should be done after reading all
-// bytes from previously returned io.Reader. For more performant way to discard
-// message use Reader and its Discard() method.
-//
-// Note that it will not handle any "intermediate" frames, that possibly could
-// be received between text/binary continuation frames. That is, if peer sent
-// text/binary frame with fin flag "false", then it could send ping frame, and
-// eventually remaining part of text/binary frame with fin "true" – with
-// NextReader() the ping frame will be dropped without any notice. To handle
-// this rare, but possible situation (and if you do not know exactly which
-// frames peer could send), you could use Reader with OnIntermediate field set.
-func NextReader(r io.Reader, s ws.State) (ws.Header, io.Reader, error) {
- rd := &Reader{
- Source: r,
- State: s,
- }
- header, err := rd.NextFrame()
- if err != nil {
- return header, nil, err
- }
- return header, rd, nil
-}
diff --git a/vendor/github.com/gobwas/ws/wsutil/upgrader.go b/vendor/github.com/gobwas/ws/wsutil/upgrader.go
deleted file mode 100644
index 2ed351e088e..00000000000
--- a/vendor/github.com/gobwas/ws/wsutil/upgrader.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package wsutil
-
-import (
- "bufio"
- "bytes"
- "io"
- "io/ioutil"
- "net/http"
-
- "github.com/gobwas/ws"
-)
-
-// DebugUpgrader is a wrapper around ws.Upgrader. It tracks I/O of a
-// WebSocket handshake.
-//
-// Note that it must not be used in production applications that requires
-// Upgrade() to be efficient.
-type DebugUpgrader struct {
- // Upgrader contains upgrade to WebSocket options.
- Upgrader ws.Upgrader
-
- // OnRequest and OnResponse are the callbacks that will be called with the
- // HTTP request and response respectively.
- OnRequest, OnResponse func([]byte)
-}
-
-// Upgrade calls Upgrade() on underlying ws.Upgrader and tracks I/O on conn.
-func (d *DebugUpgrader) Upgrade(conn io.ReadWriter) (hs ws.Handshake, err error) {
- var (
- // Take the Reader and Writer parts from conn to be probably replaced
- // below.
- r io.Reader = conn
- w io.Writer = conn
- )
- if onRequest := d.OnRequest; onRequest != nil {
- var buf bytes.Buffer
- // First, we must read the entire request.
- req, err := http.ReadRequest(bufio.NewReader(
- io.TeeReader(conn, &buf),
- ))
- if err == nil {
- // Fulfill the buffer with the response body.
- io.Copy(ioutil.Discard, req.Body)
- req.Body.Close()
- }
- onRequest(buf.Bytes())
-
- r = io.MultiReader(
- &buf, conn,
- )
- }
-
- if onResponse := d.OnResponse; onResponse != nil {
- var buf bytes.Buffer
- // Intercept the response stream written by the Upgrade().
- w = io.MultiWriter(
- conn, &buf,
- )
- defer func() {
- onResponse(buf.Bytes())
- }()
- }
-
- return d.Upgrader.Upgrade(struct {
- io.Reader
- io.Writer
- }{r, w})
-}
diff --git a/vendor/github.com/gobwas/ws/wsutil/utf8.go b/vendor/github.com/gobwas/ws/wsutil/utf8.go
deleted file mode 100644
index d877be0b1d1..00000000000
--- a/vendor/github.com/gobwas/ws/wsutil/utf8.go
+++ /dev/null
@@ -1,140 +0,0 @@
-package wsutil
-
-import (
- "fmt"
- "io"
-)
-
-// ErrInvalidUTF8 is returned by UTF8 reader on invalid utf8 sequence.
-var ErrInvalidUTF8 = fmt.Errorf("invalid utf8")
-
-// UTF8Reader implements io.Reader that calculates utf8 validity state after
-// every read byte from Source.
-//
-// Note that in some cases client must call r.Valid() after all bytes are read
-// to ensure that all of them are valid utf8 sequences. That is, some io helper
-// functions such io.ReadAtLeast or io.ReadFull could discard the error
-// information returned by the reader when they receive all of requested bytes.
-// For example, the last read sequence is invalid and UTF8Reader returns number
-// of bytes read and an error. But helper function decides to discard received
-// error due to all requested bytes are completely read from the source.
-//
-// Another possible case is when some valid sequence become split by the read
-// bound. Then UTF8Reader can not make decision about validity of the last
-// sequence cause it is not fully read yet. And if the read stops, Valid() will
-// return false, even if Read() by itself dit not.
-type UTF8Reader struct {
- Source io.Reader
-
- accepted int
-
- state uint32
- codep uint32
-}
-
-// NewUTF8Reader creates utf8 reader that reads from r.
-func NewUTF8Reader(r io.Reader) *UTF8Reader {
- return &UTF8Reader{
- Source: r,
- }
-}
-
-// Reset resets utf8 reader to read from r.
-func (u *UTF8Reader) Reset(r io.Reader) {
- u.Source = r
- u.state = 0
- u.codep = 0
-}
-
-// Read implements io.Reader.
-func (u *UTF8Reader) Read(p []byte) (n int, err error) {
- n, err = u.Source.Read(p)
-
- accepted := 0
- s, c := u.state, u.codep
- for i := 0; i < n; i++ {
- c, s = decode(s, c, p[i])
- if s == utf8Reject {
- u.state = s
- return accepted, ErrInvalidUTF8
- }
- if s == utf8Accept {
- accepted = i + 1
- }
- }
- u.state, u.codep = s, c
- u.accepted = accepted
-
- return
-}
-
-// Valid checks current reader state. It returns true if all read bytes are
-// valid UTF-8 sequences, and false if not.
-func (u *UTF8Reader) Valid() bool {
- return u.state == utf8Accept
-}
-
-// Accepted returns number of valid bytes in last Read().
-func (u *UTF8Reader) Accepted() int {
- return u.accepted
-}
-
-// Below is port of UTF-8 decoder from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
-//
-// Copyright (c) 2008-2009 Bjoern Hoehrmann
-//
-// 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.
-
-const (
- utf8Accept = 0
- utf8Reject = 12
-)
-
-var utf8d = [...]byte{
- // The first part of the table maps bytes to character classes that
- // to reduce the size of the transition table and create bitmasks.
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-
- // The second part is a transition table that maps a combination
- // of a state of the automaton and a character class to a state.
- 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12,
- 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-}
-
-func decode(state, codep uint32, b byte) (uint32, uint32) {
- t := uint32(utf8d[b])
-
- if state != utf8Accept {
- codep = (uint32(b) & 0x3f) | (codep << 6)
- } else {
- codep = (0xff >> t) & uint32(b)
- }
-
- return codep, uint32(utf8d[256+state+t])
-}
diff --git a/vendor/github.com/gobwas/ws/wsutil/writer.go b/vendor/github.com/gobwas/ws/wsutil/writer.go
deleted file mode 100644
index c76b0b4247a..00000000000
--- a/vendor/github.com/gobwas/ws/wsutil/writer.go
+++ /dev/null
@@ -1,450 +0,0 @@
-package wsutil
-
-import (
- "fmt"
- "io"
-
- "github.com/gobwas/pool"
- "github.com/gobwas/pool/pbytes"
- "github.com/gobwas/ws"
-)
-
-// DefaultWriteBuffer contains size of Writer's default buffer. It used by
-// Writer constructor functions.
-var DefaultWriteBuffer = 4096
-
-var (
- // ErrNotEmpty is returned by Writer.WriteThrough() to indicate that buffer is
- // not empty and write through could not be done. That is, caller should call
- // Writer.FlushFragment() to make buffer empty.
- ErrNotEmpty = fmt.Errorf("writer not empty")
-
- // ErrControlOverflow is returned by ControlWriter.Write() to indicate that
- // no more data could be written to the underlying io.Writer because
- // MaxControlFramePayloadSize limit is reached.
- ErrControlOverflow = fmt.Errorf("control frame payload overflow")
-)
-
-// Constants which are represent frame length ranges.
-const (
- len7 = int64(125) // 126 and 127 are reserved values
- len16 = int64(^uint16(0))
- len64 = int64((^uint64(0)) >> 1)
-)
-
-// ControlWriter is a wrapper around Writer that contains some guards for
-// buffered writes of control frames.
-type ControlWriter struct {
- w *Writer
- limit int
- n int
-}
-
-// NewControlWriter contains ControlWriter with Writer inside whose buffer size
-// is at most ws.MaxControlFramePayloadSize + ws.MaxHeaderSize.
-func NewControlWriter(dest io.Writer, state ws.State, op ws.OpCode) *ControlWriter {
- return &ControlWriter{
- w: NewWriterSize(dest, state, op, ws.MaxControlFramePayloadSize),
- limit: ws.MaxControlFramePayloadSize,
- }
-}
-
-// NewControlWriterBuffer returns a new ControlWriter with buf as a buffer.
-//
-// Note that it reserves x bytes of buf for header data, where x could be
-// ws.MinHeaderSize or ws.MinHeaderSize+4 (depending on state). At most
-// (ws.MaxControlFramePayloadSize + x) bytes of buf will be used.
-//
-// It panics if len(buf) <= ws.MinHeaderSize + x.
-func NewControlWriterBuffer(dest io.Writer, state ws.State, op ws.OpCode, buf []byte) *ControlWriter {
- max := ws.MaxControlFramePayloadSize + headerSize(state, ws.MaxControlFramePayloadSize)
- if len(buf) > max {
- buf = buf[:max]
- }
-
- w := NewWriterBuffer(dest, state, op, buf)
-
- return &ControlWriter{
- w: w,
- limit: len(w.buf),
- }
-}
-
-// Write implements io.Writer. It writes to the underlying Writer until it
-// returns error or until ControlWriter write limit will be exceeded.
-func (c *ControlWriter) Write(p []byte) (n int, err error) {
- if c.n+len(p) > c.limit {
- return 0, ErrControlOverflow
- }
- return c.w.Write(p)
-}
-
-// Flush flushes all buffered data to the underlying io.Writer.
-func (c *ControlWriter) Flush() error {
- return c.w.Flush()
-}
-
-// Writer contains logic of buffering output data into a WebSocket fragments.
-// It is much the same as bufio.Writer, except the thing that it works with
-// WebSocket frames, not the raw data.
-//
-// Writer writes frames with specified OpCode.
-// It uses ws.State to decide whether the output frames must be masked.
-//
-// Note that it does not check control frame size or other RFC rules.
-// That is, it must be used with special care to write control frames without
-// violation of RFC. You could use ControlWriter that wraps Writer and contains
-// some guards for writing control frames.
-//
-// If an error occurs writing to a Writer, no more data will be accepted and
-// all subsequent writes will return the error.
-// After all data has been written, the client should call the Flush() method
-// to guarantee all data has been forwarded to the underlying io.Writer.
-type Writer struct {
- dest io.Writer
-
- n int // Buffered bytes counter.
- raw []byte // Raw representation of buffer, including reserved header bytes.
- buf []byte // Writeable part of buffer, without reserved header bytes.
-
- op ws.OpCode
- state ws.State
-
- dirty bool
- fragmented bool
-
- err error
-}
-
-var writers = pool.New(128, 65536)
-
-// GetWriter tries to reuse Writer getting it from the pool.
-//
-// This function is intended for memory consumption optimizations, because
-// NewWriter*() functions make allocations for inner buffer.
-//
-// Note the it ceils n to the power of two.
-//
-// If you have your own bytes buffer pool you could use NewWriterBuffer to use
-// pooled bytes in writer.
-func GetWriter(dest io.Writer, state ws.State, op ws.OpCode, n int) *Writer {
- x, m := writers.Get(n)
- if x != nil {
- w := x.(*Writer)
- w.Reset(dest, state, op)
- return w
- }
- // NOTE: we use m instead of n, because m is an attempt to reuse w of such
- // size in the future.
- return NewWriterBufferSize(dest, state, op, m)
-}
-
-// PutWriter puts w for future reuse by GetWriter().
-func PutWriter(w *Writer) {
- w.Reset(nil, 0, 0)
- writers.Put(w, w.Size())
-}
-
-// NewWriter returns a new Writer whose buffer has the DefaultWriteBuffer size.
-func NewWriter(dest io.Writer, state ws.State, op ws.OpCode) *Writer {
- return NewWriterBufferSize(dest, state, op, 0)
-}
-
-// NewWriterSize returns a new Writer whose buffer size is at most n + ws.MaxHeaderSize.
-// That is, output frames payload length could be up to n, except the case when
-// Write() is called on empty Writer with len(p) > n.
-//
-// If n <= 0 then the default buffer size is used as Writer's buffer size.
-func NewWriterSize(dest io.Writer, state ws.State, op ws.OpCode, n int) *Writer {
- if n > 0 {
- n += headerSize(state, n)
- }
- return NewWriterBufferSize(dest, state, op, n)
-}
-
-// NewWriterBufferSize returns a new Writer whose buffer size is equal to n.
-// If n <= ws.MinHeaderSize then the default buffer size is used.
-//
-// Note that Writer will reserve x bytes for header data, where x is in range
-// [ws.MinHeaderSize,ws.MaxHeaderSize]. That is, frames flushed by Writer
-// will not have payload length equal to n, except the case when Write() is
-// called on empty Writer with len(p) > n.
-func NewWriterBufferSize(dest io.Writer, state ws.State, op ws.OpCode, n int) *Writer {
- if n <= ws.MinHeaderSize {
- n = DefaultWriteBuffer
- }
- return NewWriterBuffer(dest, state, op, make([]byte, n))
-}
-
-// NewWriterBuffer returns a new Writer with buf as a buffer.
-//
-// Note that it reserves x bytes of buf for header data, where x is in range
-// [ws.MinHeaderSize,ws.MaxHeaderSize] (depending on state and buf size).
-//
-// You could use ws.HeaderSize() to calculate number of bytes needed to store
-// header data.
-//
-// It panics if len(buf) is too small to fit header and payload data.
-func NewWriterBuffer(dest io.Writer, state ws.State, op ws.OpCode, buf []byte) *Writer {
- offset := reserve(state, len(buf))
- if len(buf) <= offset {
- panic("buffer too small")
- }
-
- return &Writer{
- dest: dest,
- raw: buf,
- buf: buf[offset:],
- state: state,
- op: op,
- }
-}
-
-func reserve(state ws.State, n int) (offset int) {
- var mask int
- if state.ClientSide() {
- mask = 4
- }
-
- switch {
- case n <= int(len7)+mask+2:
- return mask + 2
- case n <= int(len16)+mask+4:
- return mask + 4
- default:
- return mask + 10
- }
-}
-
-// headerSize returns number of bytes needed to encode header of a frame with
-// given state and length.
-func headerSize(s ws.State, n int) int {
- return ws.HeaderSize(ws.Header{
- Length: int64(n),
- Masked: s.ClientSide(),
- })
-}
-
-// Reset discards any buffered data, clears error, and resets w to have given
-// state and write frames with given OpCode to dest.
-func (w *Writer) Reset(dest io.Writer, state ws.State, op ws.OpCode) {
- w.n = 0
- w.dirty = false
- w.fragmented = false
- w.dest = dest
- w.state = state
- w.op = op
-}
-
-// Size returns the size of the underlying buffer in bytes.
-func (w *Writer) Size() int {
- return len(w.buf)
-}
-
-// Available returns how many bytes are unused in the buffer.
-func (w *Writer) Available() int {
- return len(w.buf) - w.n
-}
-
-// Buffered returns the number of bytes that have been written into the current
-// buffer.
-func (w *Writer) Buffered() int {
- return w.n
-}
-
-// Write implements io.Writer.
-//
-// Note that even if the Writer was created to have N-sized buffer, Write()
-// with payload of N bytes will not fit into that buffer. Writer reserves some
-// space to fit WebSocket header data.
-func (w *Writer) Write(p []byte) (n int, err error) {
- // Even empty p may make a sense.
- w.dirty = true
-
- var nn int
- for len(p) > w.Available() && w.err == nil {
- if w.Buffered() == 0 {
- // Large write, empty buffer. Write directly from p to avoid copy.
- // Trade off here is that we make additional Write() to underlying
- // io.Writer when writing frame header.
- //
- // On large buffers additional write is better than copying.
- nn, _ = w.WriteThrough(p)
- } else {
- nn = copy(w.buf[w.n:], p)
- w.n += nn
- w.FlushFragment()
- }
- n += nn
- p = p[nn:]
- }
- if w.err != nil {
- return n, w.err
- }
- nn = copy(w.buf[w.n:], p)
- w.n += nn
- n += nn
-
- // Even if w.Available() == 0 we will not flush buffer preventively because
- // this could bring unwanted fragmentation. That is, user could create
- // buffer with size that fits exactly all further Write() call, and then
- // call Flush(), excepting that single and not fragmented frame will be
- // sent. With preemptive flush this case will produce two frames – last one
- // will be empty and just to set fin = true.
-
- return n, w.err
-}
-
-// WriteThrough writes data bypassing the buffer.
-// Note that Writer's buffer must be empty before calling WriteThrough().
-func (w *Writer) WriteThrough(p []byte) (n int, err error) {
- if w.err != nil {
- return 0, w.err
- }
- if w.Buffered() != 0 {
- return 0, ErrNotEmpty
- }
-
- w.err = writeFrame(w.dest, w.state, w.opCode(), false, p)
- if w.err == nil {
- n = len(p)
- }
-
- w.dirty = true
- w.fragmented = true
-
- return n, w.err
-}
-
-// ReadFrom implements io.ReaderFrom.
-func (w *Writer) ReadFrom(src io.Reader) (n int64, err error) {
- var nn int
- for err == nil {
- if w.Available() == 0 {
- err = w.FlushFragment()
- continue
- }
-
- // We copy the behavior of bufio.Writer here.
- // Also, from the docs on io.ReaderFrom:
- // ReadFrom reads data from r until EOF or error.
- //
- // See https://codereview.appspot.com/76400048/#ps1
- const maxEmptyReads = 100
- var nr int
- for nr < maxEmptyReads {
- nn, err = src.Read(w.buf[w.n:])
- if nn != 0 || err != nil {
- break
- }
- nr++
- }
- if nr == maxEmptyReads {
- return n, io.ErrNoProgress
- }
-
- w.n += nn
- n += int64(nn)
- }
- if err == io.EOF {
- // NOTE: Do not flush preemptively.
- // See the Write() sources for more info.
- err = nil
- w.dirty = true
- }
- return n, err
-}
-
-// Flush writes any buffered data to the underlying io.Writer.
-// It sends the frame with "fin" flag set to true.
-//
-// If no Write() or ReadFrom() was made, then Flush() does nothing.
-func (w *Writer) Flush() error {
- if (!w.dirty && w.Buffered() == 0) || w.err != nil {
- return w.err
- }
-
- w.err = w.flushFragment(true)
- w.n = 0
- w.dirty = false
- w.fragmented = false
-
- return w.err
-}
-
-// FlushFragment writes any buffered data to the underlying io.Writer.
-// It sends the frame with "fin" flag set to false.
-func (w *Writer) FlushFragment() error {
- if w.Buffered() == 0 || w.err != nil {
- return w.err
- }
-
- w.err = w.flushFragment(false)
- w.n = 0
- w.fragmented = true
-
- return w.err
-}
-
-func (w *Writer) flushFragment(fin bool) error {
- frame := ws.NewFrame(w.opCode(), fin, w.buf[:w.n])
- if w.state.ClientSide() {
- frame = ws.MaskFrameInPlace(frame)
- }
-
- // Write header to the header segment of the raw buffer.
- head := len(w.raw) - len(w.buf)
- offset := head - ws.HeaderSize(frame.Header)
- buf := bytesWriter{
- buf: w.raw[offset:head],
- }
- if err := ws.WriteHeader(&buf, frame.Header); err != nil {
- // Must never be reached.
- panic("dump header error: " + err.Error())
- }
-
- _, err := w.dest.Write(w.raw[offset : head+w.n])
-
- return err
-}
-
-func (w *Writer) opCode() ws.OpCode {
- if w.fragmented {
- return ws.OpContinuation
- }
- return w.op
-}
-
-var errNoSpace = fmt.Errorf("not enough buffer space")
-
-type bytesWriter struct {
- buf []byte
- pos int
-}
-
-func (w *bytesWriter) Write(p []byte) (int, error) {
- n := copy(w.buf[w.pos:], p)
- w.pos += n
- if n != len(p) {
- return n, errNoSpace
- }
- return n, nil
-}
-
-func writeFrame(w io.Writer, s ws.State, op ws.OpCode, fin bool, p []byte) error {
- var frame ws.Frame
- if s.ClientSide() {
- // Should copy bytes to prevent corruption of caller data.
- payload := pbytes.GetLen(len(p))
- defer pbytes.Put(payload)
-
- copy(payload, p)
-
- frame = ws.NewFrame(op, fin, payload)
- frame = ws.MaskFrameInPlace(frame)
- } else {
- frame = ws.NewFrame(op, fin, p)
- }
-
- return ws.WriteFrame(w, frame)
-}
diff --git a/vendor/github.com/gobwas/ws/wsutil/wsutil.go b/vendor/github.com/gobwas/ws/wsutil/wsutil.go
deleted file mode 100644
index ffd43367dee..00000000000
--- a/vendor/github.com/gobwas/ws/wsutil/wsutil.go
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-Package wsutil provides utilities for working with WebSocket protocol.
-
-Overview:
-
- // Read masked text message from peer and check utf8 encoding.
- header, err := ws.ReadHeader(conn)
- if err != nil {
- // handle err
- }
-
- // Prepare to read payload.
- r := io.LimitReader(conn, header.Length)
- r = wsutil.NewCipherReader(r, header.Mask)
- r = wsutil.NewUTF8Reader(r)
-
- payload, err := ioutil.ReadAll(r)
- if err != nil {
- // handle err
- }
-
-You could get the same behavior using just `wsutil.Reader`:
-
- r := wsutil.Reader{
- Source: conn,
- CheckUTF8: true,
- }
-
- payload, err := ioutil.ReadAll(r)
- if err != nil {
- // handle err
- }
-
-Or even simplest:
-
- payload, err := wsutil.ReadClientText(conn)
- if err != nil {
- // handle err
- }
-
-Package is also exports tools for buffered writing:
-
- // Create buffered writer, that will buffer output bytes and send them as
- // 128-length fragments (with exception on large writes, see the doc).
- writer := wsutil.NewWriterSize(conn, ws.StateServerSide, ws.OpText, 128)
-
- _, err := io.CopyN(writer, rand.Reader, 100)
- if err == nil {
- err = writer.Flush()
- }
- if err != nil {
- // handle error
- }
-
-For more utils and helpers see the documentation.
-*/
-package wsutil
diff --git a/vendor/github.com/gocraft/health/LICENSE b/vendor/github.com/gocraft/health/LICENSE
deleted file mode 100644
index bc9d4641d60..00000000000
--- a/vendor/github.com/gocraft/health/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Jonathan Novak
-
-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.
diff --git a/vendor/github.com/gocraft/health/README.md b/vendor/github.com/gocraft/health/README.md
deleted file mode 100644
index a8f18f537ab..00000000000
--- a/vendor/github.com/gocraft/health/README.md
+++ /dev/null
@@ -1,409 +0,0 @@
-# gocraft/health [![GoDoc](https://godoc.org/github.com/gocraft/health?status.png)](https://godoc.org/github.com/gocraft/health)
-
-gocraft/health allows you to instrument your service for logging and metrics, and then send that instrumentation to log files, StatsD, Bugsnag, or to be polled and aggregated via a JSON API.
-
-gocraft/health also ships with a New Relic-like aggregator (called healthd) that shows you your slowest endpoints, top error producers, top throughput endpoints, and so on.
-
-## Instrumenting your service
-
-### Make a new stream with sinks
-
-First, you'll want to make a new Stream and attach your sinks to it. Streams are commonly saved in a global variable.
-
-```go
-import (
- "github.com/gocraft/health"
- "github.com/gocraft/health/sinks/bugsnag"
- "os"
-)
-
-// Save the stream as a global variable
-var stream = health.NewStream()
-
-// In your main func, initiailze the stream with your sinks.
-func main() {
- // Log to stdout! (can also use WriterSink to write to a log file, Syslog, etc)
- stream.AddSink(&health.WriterSink{os.Stdout})
-
- // Log to StatsD!
- statsdSink, err = health.NewStatsDSink("127.0.0.1:8125", "myapp")
- if err != nil {
- stream.EventErr("new_statsd_sink", err)
- return
- }
- stream.AddSink(statsdSink)
-
- // Expose instrumentation in this app on a JSON endpoint that healthd can poll!
- sink := health.NewJsonPollingSink(time.Minute, time.Minute*5)
- stream.AddSink(sink)
- sink.StartServer(addr)
-
- // Send errors to bugsnag!
- stream.AddSink(bugsnag.NewSink(&bugsnag.Config{APIKey: "myApiKey"}))
-
- // Now that your stream is setup, start a web server or something...
-}
-```
-
-### Jobs
-
-gocraft/health excels at instrumenting services that perform *jobs*. Examples of jobs: serving an HTTP request, serving an RPC request, or processing a message from a work queue. Jobs are encoded semantically into gocraft/health in order to provide out-of-the-box answers to questions like, "what is my slowest endpoint?"
-
-Jobs serve three functions:
-* Jobs record a timing (eg, it took 21ms to complete this job)
-* Jobs record a status (eg, did the job complete successfully or was there an error?)
-* Jobs group instrumentation inside that job together so that you can analyze it later.
-
-Let's say you're writing a web service that processes JSON requests/responses. You might write something like this:
-
-```go
-import (
- "github.com/gocraft/health"
- "net/http"
-)
-var stream = health.NewStream()
-func main() {
- // setup stream with sinks
- stream.AddSink(&health.WriterSink{os.Stdout})
- http.HandleFunc("/users", getUsers)
-}
-
-func getUsers(rw http.ResponseWriter, r *http.Request) {
- // All logging and instrumentation should be within the context of a job!
- job := stream.NewJob("get_users")
-
- err := fetchUsersFromDatabase(r)
- if err != nil {
- // When in your job's context, you can log errors, events, timings, etc.
- job.EventErr("fetch_user_from_database", err)
- }
-
- // When done with the job, call job.Complete with a completion status.
- if err == nil {
- job.Complete(health.Success)
- } else {
- job.Complete(health.Error)
- }
-}
-
-```
-
-(This example is just used for illustration -- in practice, you'll probably want to use middleware to create your job if you have more than a few endpoints.)
-
-There are five types of completion statuses:
-* **Success** - Your job completed successfully.
-* **Error** - Some library call resulted in an error that prevented you from successfully completing your job.
-* **Panic** - Some code paniced!
-* **ValidationError** - Your code was fine, but the user passed in bad inputs, and so the job wasn't completed successfully.
-* **Junk** - The job wasn't completed successfully, but not really because of an Error or ValidationError. For instance, maybe there's just a 404 (not found) or 401 (unauthorized) request to your app. This status code might not apply to all apps.
-
-### Events, Timings, Gauges, and Errors
-
-Within jobs, you can emit events, timings, gauges, and errors. The first argument of each of these methods is supposed to be a *key*. Camel case with dots is good because it works with other metrics stores like StatsD. Each method has a basic version as well as a version that accepts keys/values.
-
-#### Events
-
-```go
-// Events. Notice the camel case with dots.
-// (This is helpful when you want to use StatsD sinks)
-job.Event("starting_server")
-job.Event("proccess_user.by_email.gmail")
-
-// Event with keys and values:
-job.EventKv("failover.started", health.Kvs{"from_ip": fmt.Sprint(currentIP)})
-```
-
-* For the WriterSink, an event is just like logging to a file:
-```
-[2015-03-11T22:53:22.115855203Z]: job:/api/v2/user_stories event:starting_request kvs:[path:/api/v2/user_stories request-id:F8a8bQOWmRpO6ky]
-```
-
-* For the StatsD sink (and other metrics sinks), an event is like incrementing a counter.
-
-#### Timings
-
-```go
-// Timings:
-startTime := time.Now()
-// Do something...
-job.Timing("fetch_user", time.Since(startTime).Nanoseconds()) // NOTE: Nanoseconds!
-
-// Timings also support keys/values:
-job.TimingKv("fetch_user", time.Since(startTime).Nanoseconds(),
- health.Kvs{"user_email": userEmail})
-```
-
-* NOTE: All timing values are in nanoseconds.
-* For the WriterSink, a timing is just like logging to a file:
-```
-[2014-12-17T20:36:24.136663759Z]: job:/api/v2/user_stories event:dbr.select time:371 μs kvs:[request-id:F8a8bQOWmRpO6ky sql:SELECT COUNT(*) FROM user_stories WHERE (subdomain_id = 1221) AND (deleted_at IS NULL) AND (ticket_id IN (38327))]
-```
-
-* For the StatsD sink, we'll send it to StatsD as a timing.
-* The JSON polling sink will compute a summary of your timings: min, max, avg, stddev, count, sum.
-
-#### Gauges
-
-```go
-// Gauges:
-job.Gauge("num_goroutines", numRunningGoroutines())
-
-// Timings also support keys/values:
-job.GaugeKv("num_goroutines", numRunningGoroutines(),
- health.Kvs{"dispatcher": dispatcherStatus()})
-```
-
-* For the WriterSink, a timing is just like logging to a file:
-```
-[2014-12-17T20:36:24.136663759Z]: job:/api/v2/user_stories event:num_goroutines gauge:17 kvs:[request-id:F8a8bQOWmRpO6ky dispatcher:running]
-```
-
-* For the StatsD sink, we'll send it to StatsD as a gauge.
-
-#### Errors
-
-```go
-// Errors:
-err := someFunc(user.Email)
-if err != nil {
- return job.EventErr("some_func", err)
-}
-
-// And with keys/Values:
-job.EventErrKv("some_func", err, health.Kvs{"email": user.Email})
-```
-
-* For the WriterSink, and error will just log to the file with the error:
-```
-job:/api/v2/user_stories event:load_session.populate err:not_found kvs:[request-id:F8a8bQOWmRpO6ky]
-```
-
-* For metrics sinks, Errors are just like Events
-* The JSON polling sink and healthd will let you see which errors are trending.
-* For the Bugsnag sink, we'll push each error to bugsnag.
-
-Errors will capture a stacktrace by default so that you can diagnose it in things like Bugsnag. If an error is common or not worth sending to something like Bugsnag, you can mute it. This will cause health to not capture a stack trace or send it to bugsnag:
-
-```go
-i, err := strconv.ParseInt(userInput, 10, 0)
-if err != nil {
- // Mute this error! It's pretty common and
- // does not indicate a problem with our code!
- job.EventErr("myfunc.parse_int", health.Mute(err))
- i = 2 // We have a default anyway. No big deal.
-}
-```
-
-Since error handling is so prevalent in Go code, you'll have sitations where multiple functions have the option of loggin the same root error. The best practice that we've identified is to just not think about it and log it on every level of the call stack. Keep in mind that gocraft/health will handle this intelligently and only send one error to Bugsnag, have a correct root backtrace, and so on.
-
-```go
-func showUser(ctx *Context) error {
- user, err := ctx.getUser()
- if err != nil {
- // But we'll just log it here too!
- return ctx.EventErr("show_user.get_user", err)
- }
-}
-
-func getUser(ctx *Context) (*User, error) {
- var u User
- err := ctx.db.Select("SELECT * FROM users WHERE id = ?", ctx.userID).LoadStruct(&u)
- if err != nil {
- // Original error is here:
- return nil, ctx.EventErr("get_user.select", err)
- }
- return &u, nil
-}
-```
-
-### Keys and Values
-
-Most objects and methods in health work with key/value pairs. Key/value pairs are just maps of strings to strings. Keys and values are only relevant right now for logging sinks: The keys and values will be printed on each line written.
-
-You can add keys/values to a stream. This is useful for things like hostname or pid. They keys/values will show up on every future event/timing/error.
-```go
-stream := health.NewStream()
-stream.KeyValue("hostname", hostname)
-stream.KeyValue("pid", pid)
-```
-
-You can add keys/values to a job. This is useful for things like a request-id or the current user id:
-```go
-job.KeyValue("request_id", makeRequestID())
-if user != nil {
- job.KeyValue("user_id", fmt.Sprint(user.ID))
-}
-```
-
-And as previously discussed, each individual event/timing/error can have its own keys and values.
-
-### Writing your own Sink
-
-If you need a custom sink, you can just implement the Sink interface:
-
-```go
-type Sink interface {
- EmitEvent(job string, event string, kvs map[string]string)
- EmitEventErr(job string, event string, err error, kvs map[string]string)
- EmitTiming(job string, event string, nanoseconds int64, kvs map[string]string)
- EmitGauge(job string, event string, value float64, kvs map[string]string)
- EmitComplete(job string, status CompletionStatus, nanoseconds int64, kvs map[string]string)
-}
-```
-
-If you do implement a custom sink that you think would be valuable to other people, I'd be interested in including it in this package. Get in touch via an issue or send a pull requset.
-
-### Miscellaneous logging
-
-If you need to, you can log via a stream directly without creating a job. This will emit events under a job named 'general'. This is useful during application initialization:
-
-```go
-stream := NewStream()
-stream.EventKv("starting_app", health.Kvs{"listen_ip": listenIP})
-```
-
-## healthd and healthtop
-
-We've built a set of tools to give you New Relic-like application performance monitoring for your Go app. It can show you things like your slowest endpoints, top error producers, top throughput endpoints, and so on.
-
-These tools are completely optional -- health is super useful without them. But with them, it becomes even better.
-
-
-![Healthtop Screenshot](https://gocraft.github.io/health/images/healthtop.png)
-
-### Add a JsonPollingSink to your stream
-
-```go
-// Make sink and add it to stream:
-sink := health.NewJsonPollingSink(time.Minute, time.Minute*5)
-stream.AddSink(sink)
-
-// Start the HTTP server! This will expose metrics via a JSON API.
-// NOTE: this won't interfere with your main app (if it also serves HTTP),
-// since it starts a separate net/http server.
-// In prod, addr should be a private network interface and port, like "10.2.1.4:5020"
-// In local dev, it can be something like "127.0.0.1:5020"
-sink.StartServer(addr)
-```
-
-Once you start your app, you can browse to ```/health``` endpoint (eg, ```127.0.0.1:5020/health```) to see your metrics. Per the initialization options above, your metrics are aggregated in 1-minute chunks. We'll keep 5 minutes worth of data in memory. Nothing is ever persisted to disk.
-
-
-### Start healthd
-
-healthd will poll multiple services that are exposing a ```/health``` endpoint and aggregate that data. It will then expose that data via its own JSON API. You can query the healthd API to answer questions like 'what are my slowest endpoints'?
-
-Install the healthd binary:
-
-```bash
-go get github.com/gocraft/health/cmd/healthd
-```
-
-Now you can run it. It accepts two main inputs as environment variables:
-
-* **HEALTHD_MONITORED_HOSTPORTS**: comma separated list of hostports that represent your services running the JsonPollingSink. Example: ```HEALTHD_MONITORED_HOSTPORTS=10.18.23.130:5020,10.18.23.131:5020```
-* **HEALTHD_SERVER_HOSTPORT**: interface and port where you want to expose the healthd endpoints. Example: ```HEALTHD_SERVER_HOSTPORT=10.18.23.132:5032```
-
-Putting those together:
-```bash
-HEALTHD_MONITORED_HOSTPORTS=10.18.23.130:5020,10.18.23.131:5020 HEALTHD_SERVER_HOSTPORT=10.18.23.132:5030 healthd
-```
-
-Of course, in local development mode, you can do something like this:
-```bash
-HEALTHD_MONITORED_HOSTPORTS=:5020 HEALTHD_SERVER_HOSTPORT=:5032 healthd
-```
-
-Great! To get a sense of the type of data healthd serves, you can manually navigate to:
-
-* ```/jobs```: Lists top jobs
-* ```/aggregations```: Provides a time series of aggregations
-* ```/aggregations/overall```: Squishes all time series aggregations into one aggregation.
-* ```/hosts```: Lists all monitored hosts and their statuses.
-
-However, viewing raw JSON is just to give you a sense of the data. See the next section...
-
-### Use healthtop to query healthd
-
-healthtop is a command-line tool that repeatedly queries a healthd and displays the results.
-
-Install the healthtop binary:
-
-```bash
-go get github.com/gocraft/health/cmd/healthtop
-```
-
-See your top jobs:
-
-```bash
-healthtop jobs
-```
-
-![Healthtop Screenshot](https://gocraft.github.io/health/images/healthtop.png)
-
-(By default, healthop will query healthd on localhost:5032 -- if this is not the case, you can use the source option: ```healthtop --source=10.28.3.132:5032 jobs```)
-
-You can sort your top jobs by a variety of things:
-
-```bash
-$ healthtop jobs --sort
-Error: flag needs an argument: --sort
-Usage of jobs:
- -h, --help=false: help for jobs
- --name="": name is a partial match on the name
- --sort="name": sort ∈ {name, count, count_success, count_XXX, min, max, avg}
- --source="localhost:5032": source is the host:port of the healthd to query. ex: localhost:5031
-
-$ healthtop jobs --sort=count_error
-```
-
-
-See your hosts:
-
-```bash
-healthtop hosts
-```
-
-![Healthtop Screenshot](https://gocraft.github.io/health/images/healthtop_hosts.png)
-
-To get help:
-
-```bash
-healthtop help
-```
-
-## Current Status and Contributing
-
-Currently, the core instrumentation component is very solid. Healthd is good. healthtop is functional but could use some love.
-
-Request for contributions:
-
-health core:
-
-* A way to do fine-grained histograms with variable binning.
-
-healthd & healthtop
-
-* A web UI that is built into healthd
-* Keep track of multiple service types so that we can use one healthd to monitor multiple types of applications
-* Ability to drill into specific jobs to see top errors
-* tests
-* general love
-
-If anything here interests you, let me know by opening an issue and we can collaborate on it.
-
-## gocraft
-
-gocraft offers a toolkit for building web apps. Currently these packages are available:
-
-* [gocraft/web](https://github.com/gocraft/web) - Go Router + Middleware. Your Contexts.
-* [gocraft/dbr](https://github.com/gocraft/dbr) - Additions to Go's database/sql for super fast performance and convenience.
-* [gocraft/health](https://github.com/gocraft/health) - Instrument your web apps with logging and metrics.
-* [gocraft/work](https://github.com/gocraft/work) - Process background jobs in Go.
-
-These packages were developed by the [engineering team](https://eng.uservoice.com) at [UserVoice](https://www.uservoice.com) and currently power much of its infrastructure and tech stack.
-
-## Authors
-
-* Jonathan Novak -- [https://github.com/cypriss](https://github.com/cypriss)
-* Sponsored by [UserVoice](https://eng.uservoice.com)
diff --git a/vendor/github.com/gocraft/health/TODO b/vendor/github.com/gocraft/health/TODO
deleted file mode 100644
index 2a34fd8b229..00000000000
--- a/vendor/github.com/gocraft/health/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
- - make sure bugsnag works w/o Hostname and ReleaseStage (eg defaults work)
- - make sure healthtop default sort works or at least figure out what it is
- - in readme make sure I have the right syntax for http.Handle.
- - in readme make sure I get samples of how everything is logged.
- - screenshots for healthtop
- - remove self-logging in healthd
\ No newline at end of file
diff --git a/vendor/github.com/gocraft/health/aggregator.go b/vendor/github.com/gocraft/health/aggregator.go
deleted file mode 100644
index 951aacc6dd6..00000000000
--- a/vendor/github.com/gocraft/health/aggregator.go
+++ /dev/null
@@ -1,172 +0,0 @@
-package health
-
-import (
- "time"
-)
-
-type aggregator struct {
- // How long is each aggregation interval. Eg, 1 minute
- intervalDuration time.Duration
-
- // Retain controls how many metrics interval we keep. Eg, 5 minutes
- retain time.Duration
-
- // maxIntervals is the maximum length of intervals.
- // It is retain / interval.
- maxIntervals int
-
- // intervals is a slice of the retained intervals
- intervalAggregations []*IntervalAggregation
-}
-
-func startAggregator(intervalDuration time.Duration, retain time.Duration, sink *JsonPollingSink) {
- cmdChan := sink.cmdChan
- doneChan := sink.doneChan
- intervalsChanChan := sink.intervalsChanChan
- ticker := time.Tick(1 * time.Second)
-
- agg := newAggregator(intervalDuration, retain)
-
-AGGREGATE_LOOP:
- for {
- select {
- case <-doneChan:
- sink.doneDoneChan <- 1
- break AGGREGATE_LOOP
- case cmd := <-cmdChan:
- if cmd.Kind == cmdKindEvent {
- agg.EmitEvent(cmd.Job, cmd.Event)
- } else if cmd.Kind == cmdKindEventErr {
- agg.EmitEventErr(cmd.Job, cmd.Event, cmd.Err)
- } else if cmd.Kind == cmdKindTiming {
- agg.EmitTiming(cmd.Job, cmd.Event, cmd.Nanos)
- } else if cmd.Kind == cmdKindGauge {
- agg.EmitGauge(cmd.Job, cmd.Event, cmd.Value)
- } else if cmd.Kind == cmdKindComplete {
- agg.EmitComplete(cmd.Job, cmd.Status, cmd.Nanos)
- }
- case <-ticker:
- agg.getIntervalAggregation() // this has the side effect of sliding the interval window if necessary.
- case intervalsChan := <-intervalsChanChan:
- intervalsChan <- agg.memorySafeIntervals()
- }
- }
-}
-
-func newAggregator(intervalDuration time.Duration, retain time.Duration) *aggregator {
- maxIntervals := int(retain / intervalDuration)
- return &aggregator{
- intervalDuration: intervalDuration,
- retain: retain,
- maxIntervals: maxIntervals,
- intervalAggregations: make([]*IntervalAggregation, 0, maxIntervals),
- }
-}
-
-func (a *aggregator) memorySafeIntervals() []*IntervalAggregation {
- ret := make([]*IntervalAggregation, 0, len(a.intervalAggregations))
- curAgg := a.getIntervalAggregation()
-
- for _, intAgg := range a.intervalAggregations {
- if intAgg == curAgg {
- ret = append(ret, intAgg.Clone())
- } else {
- ret = append(ret, intAgg)
- }
- }
-
- return ret
-}
-
-func (a *aggregator) EmitEvent(job string, event string) {
- intAgg := a.getIntervalAggregation()
- intAgg.Events[event] = intAgg.Events[event] + 1
- jobAgg := intAgg.getJobAggregation(job)
- jobAgg.Events[event] = jobAgg.Events[event] + 1
- intAgg.SerialNumber++
-}
-
-func (a *aggregator) EmitEventErr(job string, event string, inputErr error) {
- intAgg := a.getIntervalAggregation()
- errc := intAgg.getCounterErrs(event)
- errc.incrementAndAddError(inputErr)
- jobAgg := intAgg.getJobAggregation(job)
- jerrc := jobAgg.getCounterErrs(event)
- jerrc.incrementAndAddError(inputErr)
- intAgg.SerialNumber++
-}
-
-func (a *aggregator) EmitTiming(job string, event string, nanos int64) {
- intAgg := a.getIntervalAggregation()
- t := intAgg.getTimers(event)
- t.ingest(nanos)
- jobAgg := intAgg.getJobAggregation(job)
- jt := jobAgg.getTimers(event)
- jt.ingest(nanos)
- intAgg.SerialNumber++
-}
-
-func (a *aggregator) EmitGauge(job string, event string, value float64) {
- intAgg := a.getIntervalAggregation()
- intAgg.Gauges[event] = value
- jobAgg := intAgg.getJobAggregation(job)
- jobAgg.Gauges[event] = value
- intAgg.SerialNumber++
-}
-
-func (a *aggregator) EmitComplete(job string, status CompletionStatus, nanos int64) {
- intAgg := a.getIntervalAggregation()
- jobAgg := intAgg.getJobAggregation(job)
- jobAgg.ingest(status, nanos)
- intAgg.SerialNumber++
-}
-
-func (a *aggregator) getIntervalAggregation() *IntervalAggregation {
- intervalStart := now().Truncate(a.intervalDuration)
-
- n := len(a.intervalAggregations)
- if n > 0 && a.intervalAggregations[n-1].IntervalStart == intervalStart {
- return a.intervalAggregations[n-1]
- }
-
- return a.createIntervalAggregation(intervalStart)
-}
-
-func (a *aggregator) createIntervalAggregation(interval time.Time) *IntervalAggregation {
- // Make new interval:
- current := NewIntervalAggregation(interval)
-
- // If we've reached our max intervals, and we're going to shift everything down, then set the last one
- n := len(a.intervalAggregations)
- if n == a.maxIntervals {
- for i := 1; i < n; i++ {
- a.intervalAggregations[i-1] = a.intervalAggregations[i]
- }
- a.intervalAggregations[n-1] = current
- } else {
- a.intervalAggregations = append(a.intervalAggregations, current)
- }
-
- return current
-}
-
-var nowMock time.Time
-
-func now() time.Time {
- if nowMock.IsZero() {
- return time.Now()
- }
- return nowMock
-}
-
-func setNowMock(t string) {
- var err error
- nowMock, err = time.Parse(time.RFC3339, t)
- if err != nil {
- panic(err)
- }
-}
-
-func resetNowMock() {
- nowMock = time.Time{}
-}
diff --git a/vendor/github.com/gocraft/health/error.go b/vendor/github.com/gocraft/health/error.go
deleted file mode 100644
index 712e1727091..00000000000
--- a/vendor/github.com/gocraft/health/error.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package health
-
-import (
- "github.com/gocraft/health/stack"
-)
-
-type MutedError struct {
- Err error
-}
-
-type UnmutedError struct {
- Err error
- Stack *stack.Trace
- Emitted bool
-}
-
-func (e *MutedError) Error() string {
- return e.Err.Error()
-}
-
-func (e *UnmutedError) Error() string {
- return e.Err.Error()
-}
-
-func Mute(err error) *MutedError {
- return &MutedError{Err: err}
-}
-
-func wrapErr(err error) error {
- switch err := err.(type) {
- case *MutedError, *UnmutedError:
- return err
- default:
- return &UnmutedError{Err: err, Stack: stack.NewTrace(2)}
- }
-}
diff --git a/vendor/github.com/gocraft/health/health.go b/vendor/github.com/gocraft/health/health.go
deleted file mode 100644
index 22ee16f7d92..00000000000
--- a/vendor/github.com/gocraft/health/health.go
+++ /dev/null
@@ -1,245 +0,0 @@
-package health
-
-import (
- "errors"
- "fmt"
- "runtime"
- "time"
-)
-
-// This is primarily used as syntactic sugar for libs outside this app for passing in maps easily.
-// We don't rely on it internally b/c I don't want to tie interfaces to the 'health' package.
-type Kvs map[string]string
-
-type EventReceiver interface {
- Event(eventName string)
- EventKv(eventName string, kvs map[string]string)
- EventErr(eventName string, err error) error
- EventErrKv(eventName string, err error, kvs map[string]string) error
- Timing(eventName string, nanoseconds int64)
- TimingKv(eventName string, nanoseconds int64, kvs map[string]string)
- Gauge(eventName string, value float64)
- GaugeKv(eventName string, value float64, kvs map[string]string)
-}
-
-type Stream struct {
- Sinks []Sink
- KeyValues map[string]string
- *Job
-}
-
-type Job struct {
- Stream *Stream
- JobName string
- KeyValues map[string]string
- Start time.Time
-}
-
-type CompletionStatus int
-
-const (
- Success CompletionStatus = iota
- ValidationError
- Panic
- Error
- Junk
-)
-
-var completionStatusToString = map[CompletionStatus]string{
- Success: "success",
- ValidationError: "validation_error",
- Panic: "panic",
- Error: "error",
- Junk: "junk",
-}
-
-func (cs CompletionStatus) String() string {
- return completionStatusToString[cs]
-}
-
-type Sink interface {
- EmitEvent(job string, event string, kvs map[string]string)
- EmitEventErr(job string, event string, err error, kvs map[string]string)
- EmitTiming(job string, event string, nanoseconds int64, kvs map[string]string)
- EmitComplete(job string, status CompletionStatus, nanoseconds int64, kvs map[string]string)
- EmitGauge(job string, event string, value float64, kvs map[string]string)
-}
-
-func NewStream() *Stream {
- s := &Stream{}
- s.Job = s.NewJob("general")
- return s
-}
-
-func (s *Stream) AddSink(sink Sink) *Stream {
- s.Sinks = append(s.Sinks, sink)
- return s
-}
-
-func (s *Stream) KeyValue(key string, value string) *Stream {
- if s.KeyValues == nil {
- s.KeyValues = make(map[string]string)
- }
- s.KeyValues[key] = value
- return s
-}
-
-func (s *Stream) NewJob(name string) *Job {
- return &Job{
- Stream: s,
- JobName: name,
- Start: time.Now(),
- }
-}
-
-func (j *Job) KeyValue(key string, value string) *Job {
- if j.KeyValues == nil {
- j.KeyValues = make(map[string]string)
- }
- j.KeyValues[key] = value
- return j
-}
-
-func (j *Job) Event(eventName string) {
- allKvs := j.mergedKeyValues(nil)
- for _, sink := range j.Stream.Sinks {
- sink.EmitEvent(j.JobName, eventName, allKvs)
- }
-}
-
-func (j *Job) EventKv(eventName string, kvs map[string]string) {
- allKvs := j.mergedKeyValues(kvs)
- for _, sink := range j.Stream.Sinks {
- sink.EmitEvent(j.JobName, eventName, allKvs)
- }
-}
-
-func (j *Job) EventErr(eventName string, err error) error {
- err = wrapErr(err)
- allKvs := j.mergedKeyValues(nil)
- for _, sink := range j.Stream.Sinks {
- sink.EmitEventErr(j.JobName, eventName, err, allKvs)
- }
- if err, ok := err.(*UnmutedError); ok {
- err.Emitted = true
- }
- return err
-}
-
-func (j *Job) EventErrKv(eventName string, err error, kvs map[string]string) error {
- err = wrapErr(err)
- allKvs := j.mergedKeyValues(kvs)
- for _, sink := range j.Stream.Sinks {
- sink.EmitEventErr(j.JobName, eventName, err, allKvs)
- }
- if err, ok := err.(*UnmutedError); ok {
- err.Emitted = true
- }
- return err
-}
-
-func (j *Job) Timing(eventName string, nanoseconds int64) {
- allKvs := j.mergedKeyValues(nil)
- for _, sink := range j.Stream.Sinks {
- sink.EmitTiming(j.JobName, eventName, nanoseconds, allKvs)
- }
-}
-
-func (j *Job) TimingKv(eventName string, nanoseconds int64, kvs map[string]string) {
- allKvs := j.mergedKeyValues(kvs)
- for _, sink := range j.Stream.Sinks {
- sink.EmitTiming(j.JobName, eventName, nanoseconds, allKvs)
- }
-}
-
-func (j *Job) Gauge(eventName string, value float64) {
- allKvs := j.mergedKeyValues(nil)
- for _, sink := range j.Stream.Sinks {
- sink.EmitGauge(j.JobName, eventName, value, allKvs)
- }
-}
-
-func (j *Job) GaugeKv(eventName string, value float64, kvs map[string]string) {
- allKvs := j.mergedKeyValues(kvs)
- for _, sink := range j.Stream.Sinks {
- sink.EmitGauge(j.JobName, eventName, value, allKvs)
- }
-}
-
-func (j *Job) Complete(status CompletionStatus) {
- allKvs := j.mergedKeyValues(nil)
- for _, sink := range j.Stream.Sinks {
- sink.EmitComplete(j.JobName, status, time.Since(j.Start).Nanoseconds(), allKvs)
- }
-}
-
-func (j *Job) CompleteKv(status CompletionStatus, kvs map[string]string) {
- allKvs := j.mergedKeyValues(kvs)
- for _, sink := range j.Stream.Sinks {
- sink.EmitComplete(j.JobName, status, time.Since(j.Start).Nanoseconds(), allKvs)
- }
-}
-
-func (j *Job) mergedKeyValues(instanceKvs map[string]string) map[string]string {
- var allKvs map[string]string
-
- // Count how many maps actually have contents in them. If it's 0 or 1, we won't allocate a new map.
- // Also, optimistically set allKvs. We might use it or we might overwrite the value with a newly made map.
- var kvCount = 0
- if len(j.KeyValues) > 0 {
- kvCount += 1
- allKvs = j.KeyValues
- }
- if len(j.Stream.KeyValues) > 0 {
- kvCount += 1
- allKvs = j.Stream.KeyValues
- }
- if len(instanceKvs) > 0 {
- kvCount += 1
- allKvs = instanceKvs
- }
-
- if kvCount > 1 {
- allKvs = make(map[string]string)
- for k, v := range j.Stream.KeyValues {
- allKvs[k] = v
- }
- for k, v := range j.KeyValues {
- allKvs[k] = v
- }
- for k, v := range instanceKvs {
- allKvs[k] = v
- }
- }
-
- return allKvs
-}
-
-func (s *Stream) Run(jobName string, f func() error) error {
- j := s.NewJob(jobName)
- return j.Run(f)
-}
-
-func (j *Job) Run(f func() error) (err error) {
- defer func() {
- if r := recover(); r != nil {
- stack := make([]byte, 4096)
- stack = stack[:runtime.Stack(stack, false)]
-
- // recovered value from panic() is an interface{}, and it might not be `error`
- // do not simply type-assert here
- err = errors.New(fmt.Sprint(r))
- j.EventErrKv("panic", err, Kvs{"stack": string(stack)})
- j.Complete(Panic)
- }
- }()
-
- err = f()
- if err != nil {
- j.Complete(Error)
- } else {
- j.Complete(Success)
- }
-
- return
-}
diff --git a/vendor/github.com/gocraft/health/identifier.go b/vendor/github.com/gocraft/health/identifier.go
deleted file mode 100644
index 6b36d6be47b..00000000000
--- a/vendor/github.com/gocraft/health/identifier.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package health
-
-import (
- "fmt"
- "os"
-)
-
-var Identifier = getIdentifier()
-
-func getIdentifier() string {
- pid := os.Getpid()
- host, err := os.Hostname()
- if err != nil {
- host = "hostname_errored"
- }
-
- return fmt.Sprintf("%s.%d", host, pid)
-}
diff --git a/vendor/github.com/gocraft/health/interval_aggregation.go b/vendor/github.com/gocraft/health/interval_aggregation.go
deleted file mode 100644
index 6c2b37c5b40..00000000000
--- a/vendor/github.com/gocraft/health/interval_aggregation.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package health
-
-import (
- "reflect"
- "time"
-)
-
-// IntervalAggregation will hold data for a given aggregation interval.
-type IntervalAggregation struct {
- // The start time of the interval
- IntervalStart time.Time `json:"interval_start"`
-
- // SerialNumber increments every time the aggregation changes. It does not increment if the aggregation does not change.
- SerialNumber int64 `json:"serial_number"`
-
- // Jobs hold a map of job name -> data about that job.
- // This includes both primary-job information (success vs error, et all) as well as
- // scoping timers/counters by the job.
- Jobs map[string]*JobAggregation `json:"jobs"`
-
- // aggregationMaps will hold event/timer information that is not nested per-job.
- aggregationMaps
-}
-
-type aggregationMaps struct {
- Timers map[string]*TimerAggregation `json:"timers"`
- Gauges map[string]float64 `json:"gauges"`
- Events map[string]int64 `json:"events"`
- EventErrs map[string]*ErrorCounter `json:"event_errs"`
-}
-
-type JobAggregation struct {
- aggregationMaps
- TimerAggregation
-
- CountSuccess int64 `json:"count_success"`
- CountValidationError int64 `json:"count_validation_error"`
- CountPanic int64 `json:"count_panic"`
- CountError int64 `json:"count_error"`
- CountJunk int64 `json:"count_junk"`
-}
-
-type TimerAggregation struct {
- Count int64 `json:"count"`
- NanosSum int64 `json:"nanos_sum"`
- NanosSumSquares float64 `json:"nanos_sum_squares"` // 3seconds^2 overflows an int64
- NanosMin int64 `json:"nanos_min"`
- NanosMax int64 `json:"nanos_max"`
-}
-
-type ErrorCounter struct {
- Count int64 `json:"count"`
-
- // Let's keep a ring buffer of some errors. I feel like this isn't the best data structure / plan of attack here but works for now.
- errorSamples [5]error
- errorSampleIndex int
-}
-
-func NewIntervalAggregation(intervalStart time.Time) *IntervalAggregation {
- intAgg := &IntervalAggregation{
- IntervalStart: intervalStart,
- Jobs: make(map[string]*JobAggregation),
- }
- intAgg.initAggregationMaps()
-
- return intAgg
-}
-
-func (am *aggregationMaps) initAggregationMaps() {
- am.Timers = make(map[string]*TimerAggregation)
- am.Gauges = make(map[string]float64)
- am.Events = make(map[string]int64)
- am.EventErrs = make(map[string]*ErrorCounter)
-}
-
-func (am *aggregationMaps) getCounterErrs(event string) *ErrorCounter {
- ce := am.EventErrs[event]
- if ce == nil {
- ce = &ErrorCounter{}
- am.EventErrs[event] = ce
- }
- return ce
-}
-
-func (am *aggregationMaps) getTimers(event string) *TimerAggregation {
- t := am.Timers[event]
- if t == nil {
- t = &TimerAggregation{}
- am.Timers[event] = t
- }
- return t
-}
-
-func (ec *ErrorCounter) incrementAndAddError(inputErr error) {
- ec.Count++
- ec.addError(inputErr)
-}
-
-func (ec *ErrorCounter) addError(inputErr error) {
- lastErr := ec.errorSamples[ec.errorSampleIndex]
- if lastErr == nil {
- ec.errorSamples[ec.errorSampleIndex] = inputErr
- } else if !reflect.DeepEqual(lastErr, inputErr) {
- n := len(ec.errorSamples)
- ec.errorSampleIndex = (ec.errorSampleIndex + 1) % n
- ec.errorSamples[ec.errorSampleIndex] = inputErr
- }
-}
-
-func (ec *ErrorCounter) getErrorSamples() []error {
- // Count how many non-nil errors are there so we can make a slice of the right size
- count := 0
- for _, e := range ec.errorSamples {
- if e != nil {
- count++
- }
- }
- ret := make([]error, 0, count)
-
- // Put non-nil errors in slice
- for _, e := range ec.errorSamples {
- if e != nil {
- ret = append(ret, e)
- }
- }
- return ret
-}
-
-func (ia *IntervalAggregation) getJobAggregation(job string) *JobAggregation {
- jobAgg := ia.Jobs[job]
- if jobAgg == nil {
- jobAgg = &JobAggregation{}
- jobAgg.initAggregationMaps()
- ia.Jobs[job] = jobAgg
- }
- return jobAgg
-}
-
-func (a *TimerAggregation) ingest(nanos int64) {
- a.Count++
- a.NanosSum += nanos
- floatNano := float64(nanos)
- a.NanosSumSquares += (floatNano * floatNano)
- if a.Count == 1 || nanos < a.NanosMin {
- a.NanosMin = nanos
- }
- if a.Count == 1 || nanos > a.NanosMax {
- a.NanosMax = nanos
- }
-}
-
-func (a *JobAggregation) ingest(status CompletionStatus, nanos int64) {
- a.TimerAggregation.ingest(nanos)
- if status == Success {
- a.CountSuccess++
- } else if status == ValidationError {
- a.CountValidationError++
- } else if status == Panic {
- a.CountPanic++
- } else if status == Error {
- a.CountError++
- } else if status == Junk {
- a.CountJunk++
- }
-}
diff --git a/vendor/github.com/gocraft/health/interval_aggregation_clone.go b/vendor/github.com/gocraft/health/interval_aggregation_clone.go
deleted file mode 100644
index 15356e9a091..00000000000
--- a/vendor/github.com/gocraft/health/interval_aggregation_clone.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package health
-
-// Clone does a deep clone of ia, duplicating all maps and whatnot.
-func (ia *IntervalAggregation) Clone() *IntervalAggregation {
- dup := &IntervalAggregation{}
- dup.IntervalStart = ia.IntervalStart
- dup.SerialNumber = ia.SerialNumber
- dup.aggregationMaps = *ia.aggregationMaps.Clone()
-
- dup.Jobs = make(map[string]*JobAggregation)
- for k, v := range ia.Jobs {
- dup.Jobs[k] = v.Clone()
- }
-
- return dup
-}
-
-func (am *aggregationMaps) Clone() *aggregationMaps {
- dup := &aggregationMaps{}
-
- dup.initAggregationMaps()
-
- for k, v := range am.Events {
- dup.Events[k] = v
- }
-
- for k, v := range am.Gauges {
- dup.Gauges[k] = v
- }
-
- for k, v := range am.Timers {
- dup.Timers[k] = v.Clone()
- }
-
- for k, v := range am.EventErrs {
- dup.EventErrs[k] = v.Clone()
- }
-
- return dup
-}
-
-func (ta *TimerAggregation) Clone() *TimerAggregation {
- var dup = *ta
- return &dup
-}
-
-func (ec *ErrorCounter) Clone() *ErrorCounter {
- var dup = *ec
- return &dup
-}
-
-func (ja *JobAggregation) Clone() *JobAggregation {
- dup := &JobAggregation{
- CountSuccess: ja.CountSuccess,
- CountValidationError: ja.CountValidationError,
- CountPanic: ja.CountPanic,
- CountError: ja.CountError,
- CountJunk: ja.CountJunk,
- }
-
- dup.aggregationMaps = *ja.aggregationMaps.Clone()
- dup.TimerAggregation = ja.TimerAggregation
-
- return dup
-}
diff --git a/vendor/github.com/gocraft/health/interval_aggregation_merge.go b/vendor/github.com/gocraft/health/interval_aggregation_merge.go
deleted file mode 100644
index eaa776ea272..00000000000
--- a/vendor/github.com/gocraft/health/interval_aggregation_merge.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package health
-
-// Merge merges intAgg into ia, mutating ia.
-// Requires that ia and intAgg are a fully valid with no nil maps.
-func (ia *IntervalAggregation) Merge(intAgg *IntervalAggregation) {
- ia.aggregationMaps.merge(&intAgg.aggregationMaps)
-
- for k, v := range intAgg.Jobs {
- if existingJob, ok := ia.Jobs[k]; ok {
- existingJob.merge(v)
- } else {
- ia.Jobs[k] = v.Clone()
- }
- }
-
- ia.SerialNumber++
-}
-
-func (intoJob *JobAggregation) merge(fromJob *JobAggregation) {
- intoJob.aggregationMaps.merge(&fromJob.aggregationMaps)
- intoJob.TimerAggregation.merge(&fromJob.TimerAggregation)
- intoJob.CountSuccess += fromJob.CountSuccess
- intoJob.CountValidationError += fromJob.CountValidationError
- intoJob.CountPanic += fromJob.CountPanic
- intoJob.CountError += fromJob.CountError
- intoJob.CountJunk += fromJob.CountJunk
-}
-
-func (intoTa *TimerAggregation) merge(fromTa *TimerAggregation) {
- intoTa.Count += fromTa.Count
- intoTa.NanosSum += fromTa.NanosSum
- intoTa.NanosSumSquares += fromTa.NanosSumSquares
- if fromTa.NanosMin < intoTa.NanosMin {
- intoTa.NanosMin = fromTa.NanosMin
- }
- if fromTa.NanosMax > intoTa.NanosMax {
- intoTa.NanosMax = fromTa.NanosMax
- }
-}
-
-func (intoAm *aggregationMaps) merge(fromAm *aggregationMaps) {
- for k, v := range fromAm.Events {
- intoAm.Events[k] += v
- }
-
- for k, v := range fromAm.Gauges {
- intoAm.Gauges[k] = v
- }
-
- for k, v := range fromAm.Timers {
- if existingTimer, ok := intoAm.Timers[k]; ok {
- existingTimer.merge(v)
- } else {
- intoAm.Timers[k] = v.Clone()
- }
- }
-
- for k, v := range fromAm.EventErrs {
- if existingErrCounter, ok := intoAm.EventErrs[k]; ok {
- existingErrCounter.Count += v.Count
-
- // merging two ring buffers given our shitty implementation is problematic.
- for _, err := range v.errorSamples {
- if err != nil {
- existingErrCounter.addError(err)
- }
- }
- } else {
- intoAm.EventErrs[k] = v.Clone()
- }
- }
-}
diff --git a/vendor/github.com/gocraft/health/json_polling_sink.go b/vendor/github.com/gocraft/health/json_polling_sink.go
deleted file mode 100644
index f0cc401f661..00000000000
--- a/vendor/github.com/gocraft/health/json_polling_sink.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package health
-
-import (
- "time"
-)
-
-type JsonPollingSink struct {
- intervalDuration time.Duration
- cmdChan chan *emitCmd
- doneChan chan int
- doneDoneChan chan int
- intervalsChanChan chan chan []*IntervalAggregation
-}
-
-type cmdKind int
-
-const (
- cmdKindEvent cmdKind = iota
- cmdKindEventErr
- cmdKindTiming
- cmdKindGauge
- cmdKindComplete
-)
-
-type emitCmd struct {
- Kind cmdKind
- Job string
- Event string
- Err error
- Nanos int64
- Value float64
- Status CompletionStatus
-}
-
-func NewJsonPollingSink(intervalDuration time.Duration, retain time.Duration) *JsonPollingSink {
- const buffSize = 4096 // random-ass-guess
-
- s := &JsonPollingSink{
- intervalDuration: intervalDuration,
- cmdChan: make(chan *emitCmd, buffSize),
- doneChan: make(chan int),
- doneDoneChan: make(chan int),
- intervalsChanChan: make(chan chan []*IntervalAggregation),
- }
-
- go startAggregator(intervalDuration, retain, s)
-
- return s
-}
-
-func (s *JsonPollingSink) ShutdownServer() {
- s.doneChan <- 1
- <-s.doneDoneChan
-}
-
-func (s *JsonPollingSink) EmitEvent(job string, event string, kvs map[string]string) {
- s.cmdChan <- &emitCmd{Kind: cmdKindEvent, Job: job, Event: event}
-}
-
-func (s *JsonPollingSink) EmitEventErr(job string, event string, inputErr error, kvs map[string]string) {
- s.cmdChan <- &emitCmd{Kind: cmdKindEventErr, Job: job, Event: event, Err: inputErr}
-}
-
-func (s *JsonPollingSink) EmitTiming(job string, event string, nanos int64, kvs map[string]string) {
- s.cmdChan <- &emitCmd{Kind: cmdKindTiming, Job: job, Event: event, Nanos: nanos}
-}
-
-func (s *JsonPollingSink) EmitGauge(job string, event string, value float64, kvs map[string]string) {
- s.cmdChan <- &emitCmd{Kind: cmdKindGauge, Job: job, Event: event, Value: value}
-}
-
-func (s *JsonPollingSink) EmitComplete(job string, status CompletionStatus, nanos int64, kvs map[string]string) {
- s.cmdChan <- &emitCmd{Kind: cmdKindComplete, Job: job, Status: status, Nanos: nanos}
-}
-
-func (s *JsonPollingSink) GetMetrics() []*IntervalAggregation {
- intervalsChan := make(chan []*IntervalAggregation)
- s.intervalsChanChan <- intervalsChan
- return <-intervalsChan
-}
diff --git a/vendor/github.com/gocraft/health/json_polling_sink_http.go b/vendor/github.com/gocraft/health/json_polling_sink_http.go
deleted file mode 100644
index 7bd4a0cfc4e..00000000000
--- a/vendor/github.com/gocraft/health/json_polling_sink_http.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package health
-
-import (
- "encoding/json"
- "fmt"
- "net/http"
- "time"
-)
-
-type HealthAggregationsResponse struct {
- InstanceId string `json:"instance_id"`
- IntervalDuration time.Duration `json:"interval_duration"`
- IntervalAggregations []*IntervalAggregation `json:"aggregations"`
-}
-
-func (s *JsonPollingSink) StartServer(addr string) {
- go http.ListenAndServe(addr, s)
-}
-
-func (s *JsonPollingSink) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
- rw.Header().Set("Content-Type", "application/json; charset=utf-8")
- if r.URL.Path == "/health" {
- metrics := s.GetMetrics()
- response := &HealthAggregationsResponse{
- InstanceId: Identifier,
- IntervalDuration: s.intervalDuration,
- IntervalAggregations: metrics,
- }
- jsonData, err := json.MarshalIndent(response, "", "\t")
- if err != nil {
- renderError(rw, err)
- return
- }
- fmt.Fprintf(rw, string(jsonData))
- } else {
- renderNotFound(rw)
- }
-}
-
-func renderNotFound(rw http.ResponseWriter) {
- rw.WriteHeader(404)
- fmt.Fprintf(rw, `{"error": "not_found"}`)
-}
-
-func renderError(rw http.ResponseWriter, err error) {
- rw.WriteHeader(500)
- fmt.Fprintf(rw, `{"error": "%s"}`, err.Error())
-}
diff --git a/vendor/github.com/gocraft/health/json_writer_sink.go b/vendor/github.com/gocraft/health/json_writer_sink.go
deleted file mode 100644
index b5ff73ef906..00000000000
--- a/vendor/github.com/gocraft/health/json_writer_sink.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package health
-
-import (
- "encoding/json"
- "fmt"
- "io"
-)
-
-type JsonWriterSink struct {
- io.Writer
-}
-
-func (j *JsonWriterSink) EmitEvent(job string, event string, kvs map[string]string) {
-
- b, err := json.Marshal(struct {
- Job string
- Event string
- Timestamp string
- Kvs map[string]string
- }{job, event, timestamp(), kvs})
-
- if err != nil {
- return
- }
- j.Write(b)
-}
-
-func (j *JsonWriterSink) EmitEventErr(job string, event string, err error, kvs map[string]string) {
-
- b, err := json.Marshal(struct {
- Job string
- Event string
- Timestamp string
- Err string
- Kvs map[string]string
- }{job, event, timestamp(), fmt.Sprint(err), kvs})
-
- if err != nil {
- return
- }
- j.Write(b)
-}
-
-func (j *JsonWriterSink) EmitTiming(job string, event string, nanoseconds int64, kvs map[string]string) {
-
- b, err := json.Marshal(struct {
- Job string
- Event string
- Timestamp string
- Nanoseconds int64
- Kvs map[string]string
- }{job, event, timestamp(), nanoseconds, kvs})
-
- if err != nil {
- return
- }
- j.Write(b)
-}
-
-func (j *JsonWriterSink) EmitGauge(job string, event string, value float64, kvs map[string]string) {
-
- b, err := json.Marshal(struct {
- Job string
- Event string
- Timestamp string
- Value float64
- Kvs map[string]string
- }{job, event, timestamp(), value, kvs})
-
- if err != nil {
- return
- }
- j.Write(b)
-}
-
-func (j *JsonWriterSink) EmitComplete(job string, status CompletionStatus, nanoseconds int64, kvs map[string]string) {
-
- b, err := json.Marshal(struct {
- Job string
- Status string
- Timestamp string
- Nanoseconds int64
- Kvs map[string]string
- }{job, status.String(), timestamp(), nanoseconds, kvs})
-
- if err != nil {
- return
- }
- j.Write(b)
-}
diff --git a/vendor/github.com/gocraft/health/stack/frame.go b/vendor/github.com/gocraft/health/stack/frame.go
deleted file mode 100644
index a8b042c3093..00000000000
--- a/vendor/github.com/gocraft/health/stack/frame.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package stack
-
-import (
- // "bytes"
- "fmt"
- // "io/ioutil"
- "runtime"
- "strings"
-)
-
-// Frame contains all necessary information about to generate a line in a callstack.
-type Frame struct {
- File string
- LineNumber int
- Name string
- Package string
- IsSystemPackage bool
- ProgramCounter uintptr
-}
-
-// NewFrame popoulates a stack frame object from the program counter.
-func NewFrame(pc uintptr) Frame {
- frame := Frame{ProgramCounter: pc}
- if frame.Func() == nil {
- return frame
- }
- frame.Package, frame.Name = packageAndName(frame.Func())
-
- // pc -1 because the program counters we use are usually return addresses,
- // and we want to show the line that corresponds to the function call
- frame.File, frame.LineNumber = frame.Func().FileLine(pc - 1)
- frame.IsSystemPackage = isSystemPackage(frame.File, frame.Package)
-
- return frame
-}
-
-// Func returns the function that this stackframe corresponds to
-func (frame *Frame) Func() *runtime.Func {
- if frame.ProgramCounter == 0 {
- return nil
- }
- return runtime.FuncForPC(frame.ProgramCounter)
-}
-
-func (frame *Frame) String() string {
- return fmt.Sprintf("%s:%d %s", frame.File, frame.LineNumber, frame.Name)
-}
-
-func packageAndName(fn *runtime.Func) (string, string) {
- name := fn.Name()
- pkg := ""
-
- // we first remove the path prefix if there is one.
- if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 {
- pkg += name[:lastslash] + "/"
- name = name[lastslash+1:]
- }
- if period := strings.Index(name, "."); period >= 0 {
- pkg += name[:period]
- name = name[period+1:]
- }
-
- return pkg, name
-}
-
-var goroot = runtime.GOROOT()
-
-// isSystemPackage returns true iff the package is a system package like 'runtime' or 'net/http'
-func isSystemPackage(file, pkg string) bool {
- return strings.HasPrefix(file, goroot)
-}
diff --git a/vendor/github.com/gocraft/health/stack/stack.go b/vendor/github.com/gocraft/health/stack/stack.go
deleted file mode 100644
index 5c7dc61caf2..00000000000
--- a/vendor/github.com/gocraft/health/stack/stack.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package stack
-
-import (
- "bytes"
- "runtime"
-)
-
-// MaxStackDepth is the maximum number of stackframes on any error.
-var MaxStackDepth = 50
-
-type Trace struct {
- stack []uintptr
- frames []Frame
-}
-
-func NewTrace(skip int) *Trace {
- stack := make([]uintptr, MaxStackDepth)
- length := runtime.Callers(2+skip, stack)
- return &Trace{
- stack: stack[:length],
- }
-}
-
-// StackFrames returns an array of frames containing information about the stack.
-func (t *Trace) Frames() []Frame {
- if t.frames == nil {
- t.frames = make([]Frame, len(t.stack))
-
- for i, pc := range t.stack {
- t.frames[i] = NewFrame(pc)
- }
- }
-
- return t.frames
-}
-
-// Stack returns a formatted callstack.
-func (t *Trace) Stack() []byte {
- buf := bytes.Buffer{}
-
- for _, frame := range t.Frames() {
- buf.WriteString(frame.String())
- buf.WriteRune('\n')
- }
-
- return buf.Bytes()
-}
diff --git a/vendor/github.com/gocraft/health/statsd_sink.go b/vendor/github.com/gocraft/health/statsd_sink.go
deleted file mode 100644
index a0b88682454..00000000000
--- a/vendor/github.com/gocraft/health/statsd_sink.go
+++ /dev/null
@@ -1,370 +0,0 @@
-package health
-
-import (
- "bytes"
- "net"
- "strconv"
- "time"
-)
-
-type StatsDSinkSanitizationFunc func(*bytes.Buffer, string)
-
-type eventKey struct {
- job string
- event string
- suffix string
-}
-
-type prefixBuffer struct {
- *bytes.Buffer
- prefixLen int
-}
-
-type StatsDSinkOptions struct {
- // Prefix is something like "metroid"
- // Events emitted to StatsD would be metroid.myevent.wat
- // Eg, don't include a trailing dot in the prefix.
- // It can be "", that's fine.
- Prefix string
-
- // SanitizationFunc sanitizes jobs and events before sending them to statsd
- SanitizationFunc StatsDSinkSanitizationFunc
-
- // SkipNestedEvents will skip {events,timers,gauges} from sending the job.event version
- // and will only send the event version.
- SkipNestedEvents bool
-
- // SkipTopLevelEvents will skip {events,timers,gauges} from sending the event version
- // and will only send the job.event version.
- SkipTopLevelEvents bool
-}
-
-var defaultStatsDOptions = StatsDSinkOptions{SanitizationFunc: sanitizeKey}
-
-type StatsDSink struct {
- options StatsDSinkOptions
-
- cmdChan chan statsdEmitCmd
- drainDoneChan chan struct{}
- stopDoneChan chan struct{}
-
- flushPeriod time.Duration
-
- udpBuf bytes.Buffer
- timingBuf []byte
-
- udpConn *net.UDPConn
- udpAddr *net.UDPAddr
-
- // map of {job,event,suffix} to a re-usable buffer prefixed with the key.
- // Since each timing/gauge has a unique component (the time), we'll truncate to the prefix, write the timing,
- // and write the statsD suffix (eg, "|ms\n"). Then copy that to the UDP buffer.
- prefixBuffers map[eventKey]prefixBuffer
-}
-
-type statsdCmdKind int
-
-const (
- statsdCmdKindEvent statsdCmdKind = iota
- statsdCmdKindEventErr
- statsdCmdKindTiming
- statsdCmdKindGauge
- statsdCmdKindComplete
- statsdCmdKindFlush
- statsdCmdKindDrain
- statsdCmdKindStop
-)
-
-type statsdEmitCmd struct {
- Kind statsdCmdKind
- Job string
- Event string
- Nanos int64
- Value float64
- Status CompletionStatus
-}
-
-const cmdChanBuffSize = 8192 // random-ass-guess
-const maxUdpBytes = 1440 // 1500(Ethernet MTU) - 60(Max UDP header size
-
-func NewStatsDSink(addr string, options *StatsDSinkOptions) (*StatsDSink, error) {
- c, err := net.ListenPacket("udp", ":0")
- if err != nil {
- return nil, err
- }
-
- ra, err := net.ResolveUDPAddr("udp", addr)
- if err != nil {
- return nil, err
- }
-
- s := &StatsDSink{
- udpConn: c.(*net.UDPConn),
- udpAddr: ra,
- cmdChan: make(chan statsdEmitCmd, cmdChanBuffSize),
- drainDoneChan: make(chan struct{}),
- stopDoneChan: make(chan struct{}),
- flushPeriod: 100 * time.Millisecond,
- prefixBuffers: make(map[eventKey]prefixBuffer),
- }
-
- if options != nil {
- s.options = *options
- if s.options.SanitizationFunc == nil {
- s.options.SanitizationFunc = sanitizeKey
- }
- } else {
- s.options = defaultStatsDOptions
- }
-
- go s.loop()
-
- return s, nil
-}
-
-func (s *StatsDSink) Stop() {
- s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindStop}
- <-s.stopDoneChan
-}
-
-func (s *StatsDSink) Drain() {
- s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindDrain}
- <-s.drainDoneChan
-}
-
-func (s *StatsDSink) EmitEvent(job string, event string, kvs map[string]string) {
- s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindEvent, Job: job, Event: event}
-}
-
-func (s *StatsDSink) EmitEventErr(job string, event string, inputErr error, kvs map[string]string) {
- s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindEventErr, Job: job, Event: event}
-}
-
-func (s *StatsDSink) EmitTiming(job string, event string, nanos int64, kvs map[string]string) {
- s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindTiming, Job: job, Event: event, Nanos: nanos}
-}
-
-func (s *StatsDSink) EmitGauge(job string, event string, value float64, kvs map[string]string) {
- s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindGauge, Job: job, Event: event, Value: value}
-}
-
-func (s *StatsDSink) EmitComplete(job string, status CompletionStatus, nanos int64, kvs map[string]string) {
- s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindComplete, Job: job, Status: status, Nanos: nanos}
-}
-
-func (s *StatsDSink) loop() {
- cmdChan := s.cmdChan
-
- ticker := time.NewTicker(s.flushPeriod)
- go func() {
- for _ = range ticker.C {
- cmdChan <- statsdEmitCmd{Kind: statsdCmdKindFlush}
- }
- }()
-
-LOOP:
- for cmd := range cmdChan {
- switch cmd.Kind {
- case statsdCmdKindDrain:
- DRAIN_LOOP:
- for {
- select {
- case cmd := <-cmdChan:
- s.processCmd(&cmd)
- default:
- s.flush()
- s.drainDoneChan <- struct{}{}
- break DRAIN_LOOP
- }
- }
- case statsdCmdKindStop:
- s.stopDoneChan <- struct{}{}
- break LOOP
- case statsdCmdKindFlush:
- s.flush()
- default:
- s.processCmd(&cmd)
- }
- }
-
- ticker.Stop()
-}
-
-func (s *StatsDSink) processCmd(cmd *statsdEmitCmd) {
- switch cmd.Kind {
- case statsdCmdKindEvent:
- s.processEvent(cmd.Job, cmd.Event)
- case statsdCmdKindEventErr:
- s.processEventErr(cmd.Job, cmd.Event)
- case statsdCmdKindTiming:
- s.processTiming(cmd.Job, cmd.Event, cmd.Nanos)
- case statsdCmdKindGauge:
- s.processGauge(cmd.Job, cmd.Event, cmd.Value)
- case statsdCmdKindComplete:
- s.processComplete(cmd.Job, cmd.Status, cmd.Nanos)
- }
-}
-
-func (s *StatsDSink) processEvent(job string, event string) {
- if !s.options.SkipTopLevelEvents {
- pb := s.getPrefixBuffer("", event, "")
- pb.WriteString("1|c\n")
- s.writeStatsDMetric(pb.Bytes())
- }
-
- if !s.options.SkipNestedEvents {
- pb := s.getPrefixBuffer(job, event, "")
- pb.WriteString("1|c\n")
- s.writeStatsDMetric(pb.Bytes())
- }
-}
-
-func (s *StatsDSink) processEventErr(job string, event string) {
- if !s.options.SkipTopLevelEvents {
- pb := s.getPrefixBuffer("", event, "error")
- pb.WriteString("1|c\n")
- s.writeStatsDMetric(pb.Bytes())
- }
-
- if !s.options.SkipNestedEvents {
- pb := s.getPrefixBuffer(job, event, "error")
- pb.WriteString("1|c\n")
- s.writeStatsDMetric(pb.Bytes())
- }
-}
-
-func (s *StatsDSink) processTiming(job string, event string, nanos int64) {
- s.writeNanosToTimingBuf(nanos)
-
- if !s.options.SkipTopLevelEvents {
- pb := s.getPrefixBuffer("", event, "")
- pb.Write(s.timingBuf)
- pb.WriteString("|ms\n")
- s.writeStatsDMetric(pb.Bytes())
- }
-
- if !s.options.SkipNestedEvents {
- pb := s.getPrefixBuffer(job, event, "")
- pb.Write(s.timingBuf)
- pb.WriteString("|ms\n")
- s.writeStatsDMetric(pb.Bytes())
- }
-}
-
-func (s *StatsDSink) processGauge(job string, event string, value float64) {
- s.timingBuf = s.timingBuf[0:0]
- prec := 2
- if (value < 0.1) && (value > -0.1) {
- prec = -1
- }
- s.timingBuf = strconv.AppendFloat(s.timingBuf, value, 'f', prec, 64)
-
- if !s.options.SkipTopLevelEvents {
- pb := s.getPrefixBuffer("", event, "")
- pb.Write(s.timingBuf)
- pb.WriteString("|g\n")
- s.writeStatsDMetric(pb.Bytes())
- }
-
- if !s.options.SkipNestedEvents {
- pb := s.getPrefixBuffer(job, event, "")
- pb.Write(s.timingBuf)
- pb.WriteString("|g\n")
- s.writeStatsDMetric(pb.Bytes())
- }
-}
-
-func (s *StatsDSink) processComplete(job string, status CompletionStatus, nanos int64) {
- s.writeNanosToTimingBuf(nanos)
- statusString := status.String()
-
- pb := s.getPrefixBuffer(job, "", statusString)
- pb.Write(s.timingBuf)
- pb.WriteString("|ms\n")
- s.writeStatsDMetric(pb.Bytes())
-}
-
-func (s *StatsDSink) flush() {
- if s.udpBuf.Len() > 0 {
- s.udpConn.WriteToUDP(s.udpBuf.Bytes(), s.udpAddr)
- s.udpBuf.Truncate(0)
- }
-}
-
-// assumes b is a well-formed statsd metric like "job.event:1|c\n" (including newline)
-func (s *StatsDSink) writeStatsDMetric(b []byte) {
- lenb := len(b)
-
- if lenb == 0 {
- return
- }
-
- // single metric exceeds limit. sad day.
- if lenb > maxUdpBytes {
- return
- }
-
- lenUdpBuf := s.udpBuf.Len()
-
- if (lenb + lenUdpBuf) > maxUdpBytes {
- s.udpConn.WriteToUDP(s.udpBuf.Bytes(), s.udpAddr)
- s.udpBuf.Truncate(0)
- }
-
- s.udpBuf.Write(b)
-}
-
-func (s *StatsDSink) getPrefixBuffer(job, event, suffix string) prefixBuffer {
- key := eventKey{job, event, suffix}
-
- b, ok := s.prefixBuffers[key]
- if !ok {
- b.Buffer = &bytes.Buffer{}
- s.writeSanitizedKeys(b.Buffer, s.options.Prefix, job, event, suffix)
- b.WriteByte(':')
- b.prefixLen = b.Len()
-
- // 123456789.99|ms\n 16 bytes. timing value represents 11 days max
- b.Grow(16)
- s.prefixBuffers[key] = b
- } else {
- b.Truncate(b.prefixLen)
- }
-
- return b
-}
-
-func (s *StatsDSink) writeSanitizedKeys(b *bytes.Buffer, keys ...string) {
- needDot := false
- for _, k := range keys {
- if k != "" {
- if needDot {
- b.WriteByte('.')
- }
- s.options.SanitizationFunc(b, k)
- needDot = true
- }
- }
-}
-
-func (s *StatsDSink) writeNanosToTimingBuf(nanos int64) {
- s.timingBuf = s.timingBuf[0:0]
- if nanos >= 10e6 {
- // More than 10 milliseconds. We'll just print as an integer
- s.timingBuf = strconv.AppendInt(s.timingBuf, nanos/1e6, 10)
- } else {
- s.timingBuf = strconv.AppendFloat(s.timingBuf, float64(nanos)/float64(time.Millisecond), 'f', 2, 64)
- }
-}
-
-func sanitizeKey(b *bytes.Buffer, s string) {
- b.Grow(len(s) + 1)
- for i := 0; i < len(s); i++ {
- si := s[i]
- if ('A' <= si && si <= 'Z') || ('a' <= si && si <= 'z') || ('0' <= si && s[i] <= '9') || si == '_' || si == '.' {
- b.WriteByte(si)
- } else {
- b.WriteByte('$')
- }
- }
-}
diff --git a/vendor/github.com/gocraft/health/writer_sink.go b/vendor/github.com/gocraft/health/writer_sink.go
deleted file mode 100644
index 84e01f9621e..00000000000
--- a/vendor/github.com/gocraft/health/writer_sink.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package health
-
-import (
- "bytes"
- "fmt"
- "io"
- "sort"
- "time"
-)
-
-// This sink writes bytes in a format that a human might like to read in a logfile
-// This can be used to log to Stdout:
-// .AddSink(&WriterSink{os.Stdout})
-// And to a file:
-// f, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
-// .AddSink(&WriterSink{f})
-// And to syslog:
-// w, err := syslog.New(LOG_INFO, "wat")
-// .AddSink(&WriterSink{w})
-type WriterSink struct {
- io.Writer
-}
-
-func (s *WriterSink) EmitEvent(job string, event string, kvs map[string]string) {
- var b bytes.Buffer
- b.WriteRune('[')
- b.WriteString(timestamp())
- b.WriteString("]: job:")
- b.WriteString(job)
- b.WriteString(" event:")
- b.WriteString(event)
- writeMapConsistently(&b, kvs)
- b.WriteRune('\n')
- s.Writer.Write(b.Bytes())
-}
-
-func (s *WriterSink) EmitEventErr(job string, event string, inputErr error, kvs map[string]string) {
- var b bytes.Buffer
- b.WriteRune('[')
- b.WriteString(timestamp())
- b.WriteString("]: job:")
- b.WriteString(job)
- b.WriteString(" event:")
- b.WriteString(event)
- b.WriteString(" err:")
- b.WriteString(inputErr.Error())
- writeMapConsistently(&b, kvs)
- b.WriteRune('\n')
- s.Writer.Write(b.Bytes())
-}
-
-func (s *WriterSink) EmitTiming(job string, event string, nanos int64, kvs map[string]string) {
- var b bytes.Buffer
- b.WriteRune('[')
- b.WriteString(timestamp())
- b.WriteString("]: job:")
- b.WriteString(job)
- b.WriteString(" event:")
- b.WriteString(event)
- b.WriteString(" time:")
- writeNanoseconds(&b, nanos)
- writeMapConsistently(&b, kvs)
- b.WriteRune('\n')
- s.Writer.Write(b.Bytes())
-}
-
-func (s *WriterSink) EmitGauge(job string, event string, value float64, kvs map[string]string) {
- var b bytes.Buffer
- b.WriteRune('[')
- b.WriteString(timestamp())
- b.WriteString("]: job:")
- b.WriteString(job)
- b.WriteString(" event:")
- b.WriteString(event)
- b.WriteString(" gauge:")
- fmt.Fprintf(&b, "%g", value)
- writeMapConsistently(&b, kvs)
- b.WriteRune('\n')
- s.Writer.Write(b.Bytes())
-}
-
-func (s *WriterSink) EmitComplete(job string, status CompletionStatus, nanos int64, kvs map[string]string) {
- var b bytes.Buffer
- b.WriteRune('[')
- b.WriteString(timestamp())
- b.WriteString("]: job:")
- b.WriteString(job)
- b.WriteString(" status:")
- b.WriteString(status.String())
- b.WriteString(" time:")
- writeNanoseconds(&b, nanos)
- writeMapConsistently(&b, kvs)
- b.WriteRune('\n')
- s.Writer.Write(b.Bytes())
-}
-
-func timestamp() string {
- return time.Now().UTC().Format(time.RFC3339Nano)
-}
-
-func writeMapConsistently(b *bytes.Buffer, kvs map[string]string) {
- if kvs == nil {
- return
- }
- keys := make([]string, 0, len(kvs))
- for k := range kvs {
- keys = append(keys, k)
- }
- sort.Strings(keys)
- keysLenMinusOne := len(keys) - 1
-
- b.WriteString(" kvs:[")
- for i, k := range keys {
- b.WriteString(k)
- b.WriteRune(':')
- b.WriteString(kvs[k])
-
- if i != keysLenMinusOne {
- b.WriteRune(' ')
- }
- }
- b.WriteRune(']')
-}
-
-func writeNanoseconds(b *bytes.Buffer, nanos int64) {
- switch {
- case nanos > 2000000:
- fmt.Fprintf(b, "%d ms", nanos/1000000)
- case nanos > 2000:
- fmt.Fprintf(b, "%d μs", nanos/1000)
- default:
- fmt.Fprintf(b, "%d ns", nanos)
- }
-}
diff --git a/vendor/github.com/golang/protobuf/AUTHORS b/vendor/github.com/golang/protobuf/AUTHORS
deleted file mode 100644
index 15167cd746c..00000000000
--- a/vendor/github.com/golang/protobuf/AUTHORS
+++ /dev/null
@@ -1,3 +0,0 @@
-# This source code refers to The Go Authors for copyright purposes.
-# The master list of authors is in the main Go distribution,
-# visible at http://tip.golang.org/AUTHORS.
diff --git a/vendor/github.com/golang/protobuf/CONTRIBUTORS b/vendor/github.com/golang/protobuf/CONTRIBUTORS
deleted file mode 100644
index 1c4577e9680..00000000000
--- a/vendor/github.com/golang/protobuf/CONTRIBUTORS
+++ /dev/null
@@ -1,3 +0,0 @@
-# This source code was written by the Go contributors.
-# The master list of contributors is in the main Go distribution,
-# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/vendor/github.com/golang/protobuf/LICENSE b/vendor/github.com/golang/protobuf/LICENSE
deleted file mode 100644
index 0f646931a46..00000000000
--- a/vendor/github.com/golang/protobuf/LICENSE
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright 2010 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/vendor/github.com/golang/protobuf/proto/buffer.go b/vendor/github.com/golang/protobuf/proto/buffer.go
deleted file mode 100644
index e810e6fea12..00000000000
--- a/vendor/github.com/golang/protobuf/proto/buffer.go
+++ /dev/null
@@ -1,324 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- "errors"
- "fmt"
-
- "google.golang.org/protobuf/encoding/prototext"
- "google.golang.org/protobuf/encoding/protowire"
- "google.golang.org/protobuf/runtime/protoimpl"
-)
-
-const (
- WireVarint = 0
- WireFixed32 = 5
- WireFixed64 = 1
- WireBytes = 2
- WireStartGroup = 3
- WireEndGroup = 4
-)
-
-// EncodeVarint returns the varint encoded bytes of v.
-func EncodeVarint(v uint64) []byte {
- return protowire.AppendVarint(nil, v)
-}
-
-// SizeVarint returns the length of the varint encoded bytes of v.
-// This is equal to len(EncodeVarint(v)).
-func SizeVarint(v uint64) int {
- return protowire.SizeVarint(v)
-}
-
-// DecodeVarint parses a varint encoded integer from b,
-// returning the integer value and the length of the varint.
-// It returns (0, 0) if there is a parse error.
-func DecodeVarint(b []byte) (uint64, int) {
- v, n := protowire.ConsumeVarint(b)
- if n < 0 {
- return 0, 0
- }
- return v, n
-}
-
-// Buffer is a buffer for encoding and decoding the protobuf wire format.
-// It may be reused between invocations to reduce memory usage.
-type Buffer struct {
- buf []byte
- idx int
- deterministic bool
-}
-
-// NewBuffer allocates a new Buffer initialized with buf,
-// where the contents of buf are considered the unread portion of the buffer.
-func NewBuffer(buf []byte) *Buffer {
- return &Buffer{buf: buf}
-}
-
-// SetDeterministic specifies whether to use deterministic serialization.
-//
-// Deterministic serialization guarantees that for a given binary, equal
-// messages will always be serialized to the same bytes. This implies:
-//
-// - Repeated serialization of a message will return the same bytes.
-// - Different processes of the same binary (which may be executing on
-// different machines) will serialize equal messages to the same bytes.
-//
-// Note that the deterministic serialization is NOT canonical across
-// languages. It is not guaranteed to remain stable over time. It is unstable
-// across different builds with schema changes due to unknown fields.
-// Users who need canonical serialization (e.g., persistent storage in a
-// canonical form, fingerprinting, etc.) should define their own
-// canonicalization specification and implement their own serializer rather
-// than relying on this API.
-//
-// If deterministic serialization is requested, map entries will be sorted
-// by keys in lexographical order. This is an implementation detail and
-// subject to change.
-func (b *Buffer) SetDeterministic(deterministic bool) {
- b.deterministic = deterministic
-}
-
-// SetBuf sets buf as the internal buffer,
-// where the contents of buf are considered the unread portion of the buffer.
-func (b *Buffer) SetBuf(buf []byte) {
- b.buf = buf
- b.idx = 0
-}
-
-// Reset clears the internal buffer of all written and unread data.
-func (b *Buffer) Reset() {
- b.buf = b.buf[:0]
- b.idx = 0
-}
-
-// Bytes returns the internal buffer.
-func (b *Buffer) Bytes() []byte {
- return b.buf
-}
-
-// Unread returns the unread portion of the buffer.
-func (b *Buffer) Unread() []byte {
- return b.buf[b.idx:]
-}
-
-// Marshal appends the wire-format encoding of m to the buffer.
-func (b *Buffer) Marshal(m Message) error {
- var err error
- b.buf, err = marshalAppend(b.buf, m, b.deterministic)
- return err
-}
-
-// Unmarshal parses the wire-format message in the buffer and
-// places the decoded results in m.
-// It does not reset m before unmarshaling.
-func (b *Buffer) Unmarshal(m Message) error {
- err := UnmarshalMerge(b.Unread(), m)
- b.idx = len(b.buf)
- return err
-}
-
-type unknownFields struct{ XXX_unrecognized protoimpl.UnknownFields }
-
-func (m *unknownFields) String() string { panic("not implemented") }
-func (m *unknownFields) Reset() { panic("not implemented") }
-func (m *unknownFields) ProtoMessage() { panic("not implemented") }
-
-// DebugPrint dumps the encoded bytes of b with a header and footer including s
-// to stdout. This is only intended for debugging.
-func (*Buffer) DebugPrint(s string, b []byte) {
- m := MessageReflect(new(unknownFields))
- m.SetUnknown(b)
- b, _ = prototext.MarshalOptions{AllowPartial: true, Indent: "\t"}.Marshal(m.Interface())
- fmt.Printf("==== %s ====\n%s==== %s ====\n", s, b, s)
-}
-
-// EncodeVarint appends an unsigned varint encoding to the buffer.
-func (b *Buffer) EncodeVarint(v uint64) error {
- b.buf = protowire.AppendVarint(b.buf, v)
- return nil
-}
-
-// EncodeZigzag32 appends a 32-bit zig-zag varint encoding to the buffer.
-func (b *Buffer) EncodeZigzag32(v uint64) error {
- return b.EncodeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31))))
-}
-
-// EncodeZigzag64 appends a 64-bit zig-zag varint encoding to the buffer.
-func (b *Buffer) EncodeZigzag64(v uint64) error {
- return b.EncodeVarint(uint64((uint64(v) << 1) ^ uint64((int64(v) >> 63))))
-}
-
-// EncodeFixed32 appends a 32-bit little-endian integer to the buffer.
-func (b *Buffer) EncodeFixed32(v uint64) error {
- b.buf = protowire.AppendFixed32(b.buf, uint32(v))
- return nil
-}
-
-// EncodeFixed64 appends a 64-bit little-endian integer to the buffer.
-func (b *Buffer) EncodeFixed64(v uint64) error {
- b.buf = protowire.AppendFixed64(b.buf, uint64(v))
- return nil
-}
-
-// EncodeRawBytes appends a length-prefixed raw bytes to the buffer.
-func (b *Buffer) EncodeRawBytes(v []byte) error {
- b.buf = protowire.AppendBytes(b.buf, v)
- return nil
-}
-
-// EncodeStringBytes appends a length-prefixed raw bytes to the buffer.
-// It does not validate whether v contains valid UTF-8.
-func (b *Buffer) EncodeStringBytes(v string) error {
- b.buf = protowire.AppendString(b.buf, v)
- return nil
-}
-
-// EncodeMessage appends a length-prefixed encoded message to the buffer.
-func (b *Buffer) EncodeMessage(m Message) error {
- var err error
- b.buf = protowire.AppendVarint(b.buf, uint64(Size(m)))
- b.buf, err = marshalAppend(b.buf, m, b.deterministic)
- return err
-}
-
-// DecodeVarint consumes an encoded unsigned varint from the buffer.
-func (b *Buffer) DecodeVarint() (uint64, error) {
- v, n := protowire.ConsumeVarint(b.buf[b.idx:])
- if n < 0 {
- return 0, protowire.ParseError(n)
- }
- b.idx += n
- return uint64(v), nil
-}
-
-// DecodeZigzag32 consumes an encoded 32-bit zig-zag varint from the buffer.
-func (b *Buffer) DecodeZigzag32() (uint64, error) {
- v, err := b.DecodeVarint()
- if err != nil {
- return 0, err
- }
- return uint64((uint32(v) >> 1) ^ uint32((int32(v&1)<<31)>>31)), nil
-}
-
-// DecodeZigzag64 consumes an encoded 64-bit zig-zag varint from the buffer.
-func (b *Buffer) DecodeZigzag64() (uint64, error) {
- v, err := b.DecodeVarint()
- if err != nil {
- return 0, err
- }
- return uint64((uint64(v) >> 1) ^ uint64((int64(v&1)<<63)>>63)), nil
-}
-
-// DecodeFixed32 consumes a 32-bit little-endian integer from the buffer.
-func (b *Buffer) DecodeFixed32() (uint64, error) {
- v, n := protowire.ConsumeFixed32(b.buf[b.idx:])
- if n < 0 {
- return 0, protowire.ParseError(n)
- }
- b.idx += n
- return uint64(v), nil
-}
-
-// DecodeFixed64 consumes a 64-bit little-endian integer from the buffer.
-func (b *Buffer) DecodeFixed64() (uint64, error) {
- v, n := protowire.ConsumeFixed64(b.buf[b.idx:])
- if n < 0 {
- return 0, protowire.ParseError(n)
- }
- b.idx += n
- return uint64(v), nil
-}
-
-// DecodeRawBytes consumes a length-prefixed raw bytes from the buffer.
-// If alloc is specified, it returns a copy the raw bytes
-// rather than a sub-slice of the buffer.
-func (b *Buffer) DecodeRawBytes(alloc bool) ([]byte, error) {
- v, n := protowire.ConsumeBytes(b.buf[b.idx:])
- if n < 0 {
- return nil, protowire.ParseError(n)
- }
- b.idx += n
- if alloc {
- v = append([]byte(nil), v...)
- }
- return v, nil
-}
-
-// DecodeStringBytes consumes a length-prefixed raw bytes from the buffer.
-// It does not validate whether the raw bytes contain valid UTF-8.
-func (b *Buffer) DecodeStringBytes() (string, error) {
- v, n := protowire.ConsumeString(b.buf[b.idx:])
- if n < 0 {
- return "", protowire.ParseError(n)
- }
- b.idx += n
- return v, nil
-}
-
-// DecodeMessage consumes a length-prefixed message from the buffer.
-// It does not reset m before unmarshaling.
-func (b *Buffer) DecodeMessage(m Message) error {
- v, err := b.DecodeRawBytes(false)
- if err != nil {
- return err
- }
- return UnmarshalMerge(v, m)
-}
-
-// DecodeGroup consumes a message group from the buffer.
-// It assumes that the start group marker has already been consumed and
-// consumes all bytes until (and including the end group marker).
-// It does not reset m before unmarshaling.
-func (b *Buffer) DecodeGroup(m Message) error {
- v, n, err := consumeGroup(b.buf[b.idx:])
- if err != nil {
- return err
- }
- b.idx += n
- return UnmarshalMerge(v, m)
-}
-
-// consumeGroup parses b until it finds an end group marker, returning
-// the raw bytes of the message (excluding the end group marker) and the
-// the total length of the message (including the end group marker).
-func consumeGroup(b []byte) ([]byte, int, error) {
- b0 := b
- depth := 1 // assume this follows a start group marker
- for {
- _, wtyp, tagLen := protowire.ConsumeTag(b)
- if tagLen < 0 {
- return nil, 0, protowire.ParseError(tagLen)
- }
- b = b[tagLen:]
-
- var valLen int
- switch wtyp {
- case protowire.VarintType:
- _, valLen = protowire.ConsumeVarint(b)
- case protowire.Fixed32Type:
- _, valLen = protowire.ConsumeFixed32(b)
- case protowire.Fixed64Type:
- _, valLen = protowire.ConsumeFixed64(b)
- case protowire.BytesType:
- _, valLen = protowire.ConsumeBytes(b)
- case protowire.StartGroupType:
- depth++
- case protowire.EndGroupType:
- depth--
- default:
- return nil, 0, errors.New("proto: cannot parse reserved wire type")
- }
- if valLen < 0 {
- return nil, 0, protowire.ParseError(valLen)
- }
- b = b[valLen:]
-
- if depth == 0 {
- return b0[:len(b0)-len(b)-tagLen], len(b0) - len(b), nil
- }
- }
-}
diff --git a/vendor/github.com/golang/protobuf/proto/defaults.go b/vendor/github.com/golang/protobuf/proto/defaults.go
deleted file mode 100644
index d399bf069c3..00000000000
--- a/vendor/github.com/golang/protobuf/proto/defaults.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- "google.golang.org/protobuf/reflect/protoreflect"
-)
-
-// SetDefaults sets unpopulated scalar fields to their default values.
-// Fields within a oneof are not set even if they have a default value.
-// SetDefaults is recursively called upon any populated message fields.
-func SetDefaults(m Message) {
- if m != nil {
- setDefaults(MessageReflect(m))
- }
-}
-
-func setDefaults(m protoreflect.Message) {
- fds := m.Descriptor().Fields()
- for i := 0; i < fds.Len(); i++ {
- fd := fds.Get(i)
- if !m.Has(fd) {
- if fd.HasDefault() && fd.ContainingOneof() == nil {
- v := fd.Default()
- if fd.Kind() == protoreflect.BytesKind {
- v = protoreflect.ValueOf(append([]byte(nil), v.Bytes()...)) // copy the default bytes
- }
- m.Set(fd, v)
- }
- continue
- }
- }
-
- m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- switch {
- // Handle singular message.
- case fd.Cardinality() != protoreflect.Repeated:
- if fd.Message() != nil {
- setDefaults(m.Get(fd).Message())
- }
- // Handle list of messages.
- case fd.IsList():
- if fd.Message() != nil {
- ls := m.Get(fd).List()
- for i := 0; i < ls.Len(); i++ {
- setDefaults(ls.Get(i).Message())
- }
- }
- // Handle map of messages.
- case fd.IsMap():
- if fd.MapValue().Message() != nil {
- ms := m.Get(fd).Map()
- ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
- setDefaults(v.Message())
- return true
- })
- }
- }
- return true
- })
-}
diff --git a/vendor/github.com/golang/protobuf/proto/deprecated.go b/vendor/github.com/golang/protobuf/proto/deprecated.go
deleted file mode 100644
index e8db57e097a..00000000000
--- a/vendor/github.com/golang/protobuf/proto/deprecated.go
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "strconv"
-
- protoV2 "google.golang.org/protobuf/proto"
-)
-
-var (
- // Deprecated: No longer returned.
- ErrNil = errors.New("proto: Marshal called with nil")
-
- // Deprecated: No longer returned.
- ErrTooLarge = errors.New("proto: message encodes to over 2 GB")
-
- // Deprecated: No longer returned.
- ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
-)
-
-// Deprecated: Do not use.
-type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
-
-// Deprecated: Do not use.
-func GetStats() Stats { return Stats{} }
-
-// Deprecated: Do not use.
-func MarshalMessageSet(interface{}) ([]byte, error) {
- return nil, errors.New("proto: not implemented")
-}
-
-// Deprecated: Do not use.
-func UnmarshalMessageSet([]byte, interface{}) error {
- return errors.New("proto: not implemented")
-}
-
-// Deprecated: Do not use.
-func MarshalMessageSetJSON(interface{}) ([]byte, error) {
- return nil, errors.New("proto: not implemented")
-}
-
-// Deprecated: Do not use.
-func UnmarshalMessageSetJSON([]byte, interface{}) error {
- return errors.New("proto: not implemented")
-}
-
-// Deprecated: Do not use.
-func RegisterMessageSetType(Message, int32, string) {}
-
-// Deprecated: Do not use.
-func EnumName(m map[int32]string, v int32) string {
- s, ok := m[v]
- if ok {
- return s
- }
- return strconv.Itoa(int(v))
-}
-
-// Deprecated: Do not use.
-func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
- if data[0] == '"' {
- // New style: enums are strings.
- var repr string
- if err := json.Unmarshal(data, &repr); err != nil {
- return -1, err
- }
- val, ok := m[repr]
- if !ok {
- return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
- }
- return val, nil
- }
- // Old style: enums are ints.
- var val int32
- if err := json.Unmarshal(data, &val); err != nil {
- return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
- }
- return val, nil
-}
-
-// Deprecated: Do not use; this type existed for intenal-use only.
-type InternalMessageInfo struct{}
-
-// Deprecated: Do not use; this method existed for intenal-use only.
-func (*InternalMessageInfo) DiscardUnknown(m Message) {
- DiscardUnknown(m)
-}
-
-// Deprecated: Do not use; this method existed for intenal-use only.
-func (*InternalMessageInfo) Marshal(b []byte, m Message, deterministic bool) ([]byte, error) {
- return protoV2.MarshalOptions{Deterministic: deterministic}.MarshalAppend(b, MessageV2(m))
-}
-
-// Deprecated: Do not use; this method existed for intenal-use only.
-func (*InternalMessageInfo) Merge(dst, src Message) {
- protoV2.Merge(MessageV2(dst), MessageV2(src))
-}
-
-// Deprecated: Do not use; this method existed for intenal-use only.
-func (*InternalMessageInfo) Size(m Message) int {
- return protoV2.Size(MessageV2(m))
-}
-
-// Deprecated: Do not use; this method existed for intenal-use only.
-func (*InternalMessageInfo) Unmarshal(m Message, b []byte) error {
- return protoV2.UnmarshalOptions{Merge: true}.Unmarshal(b, MessageV2(m))
-}
diff --git a/vendor/github.com/golang/protobuf/proto/discard.go b/vendor/github.com/golang/protobuf/proto/discard.go
deleted file mode 100644
index 2187e877fa4..00000000000
--- a/vendor/github.com/golang/protobuf/proto/discard.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- "google.golang.org/protobuf/reflect/protoreflect"
-)
-
-// DiscardUnknown recursively discards all unknown fields from this message
-// and all embedded messages.
-//
-// When unmarshaling a message with unrecognized fields, the tags and values
-// of such fields are preserved in the Message. This allows a later call to
-// marshal to be able to produce a message that continues to have those
-// unrecognized fields. To avoid this, DiscardUnknown is used to
-// explicitly clear the unknown fields after unmarshaling.
-func DiscardUnknown(m Message) {
- if m != nil {
- discardUnknown(MessageReflect(m))
- }
-}
-
-func discardUnknown(m protoreflect.Message) {
- m.Range(func(fd protoreflect.FieldDescriptor, val protoreflect.Value) bool {
- switch {
- // Handle singular message.
- case fd.Cardinality() != protoreflect.Repeated:
- if fd.Message() != nil {
- discardUnknown(m.Get(fd).Message())
- }
- // Handle list of messages.
- case fd.IsList():
- if fd.Message() != nil {
- ls := m.Get(fd).List()
- for i := 0; i < ls.Len(); i++ {
- discardUnknown(ls.Get(i).Message())
- }
- }
- // Handle map of messages.
- case fd.IsMap():
- if fd.MapValue().Message() != nil {
- ms := m.Get(fd).Map()
- ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
- discardUnknown(v.Message())
- return true
- })
- }
- }
- return true
- })
-
- // Discard unknown fields.
- if len(m.GetUnknown()) > 0 {
- m.SetUnknown(nil)
- }
-}
diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go
deleted file mode 100644
index 42fc120c972..00000000000
--- a/vendor/github.com/golang/protobuf/proto/extensions.go
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- "errors"
- "fmt"
- "reflect"
-
- "google.golang.org/protobuf/encoding/protowire"
- "google.golang.org/protobuf/proto"
- "google.golang.org/protobuf/reflect/protoreflect"
- "google.golang.org/protobuf/reflect/protoregistry"
- "google.golang.org/protobuf/runtime/protoiface"
- "google.golang.org/protobuf/runtime/protoimpl"
-)
-
-type (
- // ExtensionDesc represents an extension descriptor and
- // is used to interact with an extension field in a message.
- //
- // Variables of this type are generated in code by protoc-gen-go.
- ExtensionDesc = protoimpl.ExtensionInfo
-
- // ExtensionRange represents a range of message extensions.
- // Used in code generated by protoc-gen-go.
- ExtensionRange = protoiface.ExtensionRangeV1
-
- // Deprecated: Do not use; this is an internal type.
- Extension = protoimpl.ExtensionFieldV1
-
- // Deprecated: Do not use; this is an internal type.
- XXX_InternalExtensions = protoimpl.ExtensionFields
-)
-
-// ErrMissingExtension reports whether the extension was not present.
-var ErrMissingExtension = errors.New("proto: missing extension")
-
-var errNotExtendable = errors.New("proto: not an extendable proto.Message")
-
-// HasExtension reports whether the extension field is present in m
-// either as an explicitly populated field or as an unknown field.
-func HasExtension(m Message, xt *ExtensionDesc) (has bool) {
- mr := MessageReflect(m)
- if mr == nil || !mr.IsValid() {
- return false
- }
-
- // Check whether any populated known field matches the field number.
- xtd := xt.TypeDescriptor()
- if isValidExtension(mr.Descriptor(), xtd) {
- has = mr.Has(xtd)
- } else {
- mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
- has = int32(fd.Number()) == xt.Field
- return !has
- })
- }
-
- // Check whether any unknown field matches the field number.
- for b := mr.GetUnknown(); !has && len(b) > 0; {
- num, _, n := protowire.ConsumeField(b)
- has = int32(num) == xt.Field
- b = b[n:]
- }
- return has
-}
-
-// ClearExtension removes the extension field from m
-// either as an explicitly populated field or as an unknown field.
-func ClearExtension(m Message, xt *ExtensionDesc) {
- mr := MessageReflect(m)
- if mr == nil || !mr.IsValid() {
- return
- }
-
- xtd := xt.TypeDescriptor()
- if isValidExtension(mr.Descriptor(), xtd) {
- mr.Clear(xtd)
- } else {
- mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
- if int32(fd.Number()) == xt.Field {
- mr.Clear(fd)
- return false
- }
- return true
- })
- }
- clearUnknown(mr, fieldNum(xt.Field))
-}
-
-// ClearAllExtensions clears all extensions from m.
-// This includes populated fields and unknown fields in the extension range.
-func ClearAllExtensions(m Message) {
- mr := MessageReflect(m)
- if mr == nil || !mr.IsValid() {
- return
- }
-
- mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
- if fd.IsExtension() {
- mr.Clear(fd)
- }
- return true
- })
- clearUnknown(mr, mr.Descriptor().ExtensionRanges())
-}
-
-// GetExtension retrieves a proto2 extended field from m.
-//
-// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),
-// then GetExtension parses the encoded field and returns a Go value of the specified type.
-// If the field is not present, then the default value is returned (if one is specified),
-// otherwise ErrMissingExtension is reported.
-//
-// If the descriptor is type incomplete (i.e., ExtensionDesc.ExtensionType is nil),
-// then GetExtension returns the raw encoded bytes for the extension field.
-func GetExtension(m Message, xt *ExtensionDesc) (interface{}, error) {
- mr := MessageReflect(m)
- if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
- return nil, errNotExtendable
- }
-
- // Retrieve the unknown fields for this extension field.
- var bo protoreflect.RawFields
- for bi := mr.GetUnknown(); len(bi) > 0; {
- num, _, n := protowire.ConsumeField(bi)
- if int32(num) == xt.Field {
- bo = append(bo, bi[:n]...)
- }
- bi = bi[n:]
- }
-
- // For type incomplete descriptors, only retrieve the unknown fields.
- if xt.ExtensionType == nil {
- return []byte(bo), nil
- }
-
- // If the extension field only exists as unknown fields, unmarshal it.
- // This is rarely done since proto.Unmarshal eagerly unmarshals extensions.
- xtd := xt.TypeDescriptor()
- if !isValidExtension(mr.Descriptor(), xtd) {
- return nil, fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
- }
- if !mr.Has(xtd) && len(bo) > 0 {
- m2 := mr.New()
- if err := (proto.UnmarshalOptions{
- Resolver: extensionResolver{xt},
- }.Unmarshal(bo, m2.Interface())); err != nil {
- return nil, err
- }
- if m2.Has(xtd) {
- mr.Set(xtd, m2.Get(xtd))
- clearUnknown(mr, fieldNum(xt.Field))
- }
- }
-
- // Check whether the message has the extension field set or a default.
- var pv protoreflect.Value
- switch {
- case mr.Has(xtd):
- pv = mr.Get(xtd)
- case xtd.HasDefault():
- pv = xtd.Default()
- default:
- return nil, ErrMissingExtension
- }
-
- v := xt.InterfaceOf(pv)
- rv := reflect.ValueOf(v)
- if isScalarKind(rv.Kind()) {
- rv2 := reflect.New(rv.Type())
- rv2.Elem().Set(rv)
- v = rv2.Interface()
- }
- return v, nil
-}
-
-// extensionResolver is a custom extension resolver that stores a single
-// extension type that takes precedence over the global registry.
-type extensionResolver struct{ xt protoreflect.ExtensionType }
-
-func (r extensionResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
- if xtd := r.xt.TypeDescriptor(); xtd.FullName() == field {
- return r.xt, nil
- }
- return protoregistry.GlobalTypes.FindExtensionByName(field)
-}
-
-func (r extensionResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
- if xtd := r.xt.TypeDescriptor(); xtd.ContainingMessage().FullName() == message && xtd.Number() == field {
- return r.xt, nil
- }
- return protoregistry.GlobalTypes.FindExtensionByNumber(message, field)
-}
-
-// GetExtensions returns a list of the extensions values present in m,
-// corresponding with the provided list of extension descriptors, xts.
-// If an extension is missing in m, the corresponding value is nil.
-func GetExtensions(m Message, xts []*ExtensionDesc) ([]interface{}, error) {
- mr := MessageReflect(m)
- if mr == nil || !mr.IsValid() {
- return nil, errNotExtendable
- }
-
- vs := make([]interface{}, len(xts))
- for i, xt := range xts {
- v, err := GetExtension(m, xt)
- if err != nil {
- if err == ErrMissingExtension {
- continue
- }
- return vs, err
- }
- vs[i] = v
- }
- return vs, nil
-}
-
-// SetExtension sets an extension field in m to the provided value.
-func SetExtension(m Message, xt *ExtensionDesc, v interface{}) error {
- mr := MessageReflect(m)
- if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
- return errNotExtendable
- }
-
- rv := reflect.ValueOf(v)
- if reflect.TypeOf(v) != reflect.TypeOf(xt.ExtensionType) {
- return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", v, xt.ExtensionType)
- }
- if rv.Kind() == reflect.Ptr {
- if rv.IsNil() {
- return fmt.Errorf("proto: SetExtension called with nil value of type %T", v)
- }
- if isScalarKind(rv.Elem().Kind()) {
- v = rv.Elem().Interface()
- }
- }
-
- xtd := xt.TypeDescriptor()
- if !isValidExtension(mr.Descriptor(), xtd) {
- return fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
- }
- mr.Set(xtd, xt.ValueOf(v))
- clearUnknown(mr, fieldNum(xt.Field))
- return nil
-}
-
-// SetRawExtension inserts b into the unknown fields of m.
-//
-// Deprecated: Use Message.ProtoReflect.SetUnknown instead.
-func SetRawExtension(m Message, fnum int32, b []byte) {
- mr := MessageReflect(m)
- if mr == nil || !mr.IsValid() {
- return
- }
-
- // Verify that the raw field is valid.
- for b0 := b; len(b0) > 0; {
- num, _, n := protowire.ConsumeField(b0)
- if int32(num) != fnum {
- panic(fmt.Sprintf("mismatching field number: got %d, want %d", num, fnum))
- }
- b0 = b0[n:]
- }
-
- ClearExtension(m, &ExtensionDesc{Field: fnum})
- mr.SetUnknown(append(mr.GetUnknown(), b...))
-}
-
-// ExtensionDescs returns a list of extension descriptors found in m,
-// containing descriptors for both populated extension fields in m and
-// also unknown fields of m that are in the extension range.
-// For the later case, an type incomplete descriptor is provided where only
-// the ExtensionDesc.Field field is populated.
-// The order of the extension descriptors is undefined.
-func ExtensionDescs(m Message) ([]*ExtensionDesc, error) {
- mr := MessageReflect(m)
- if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
- return nil, errNotExtendable
- }
-
- // Collect a set of known extension descriptors.
- extDescs := make(map[protoreflect.FieldNumber]*ExtensionDesc)
- mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- if fd.IsExtension() {
- xt := fd.(protoreflect.ExtensionTypeDescriptor)
- if xd, ok := xt.Type().(*ExtensionDesc); ok {
- extDescs[fd.Number()] = xd
- }
- }
- return true
- })
-
- // Collect a set of unknown extension descriptors.
- extRanges := mr.Descriptor().ExtensionRanges()
- for b := mr.GetUnknown(); len(b) > 0; {
- num, _, n := protowire.ConsumeField(b)
- if extRanges.Has(num) && extDescs[num] == nil {
- extDescs[num] = nil
- }
- b = b[n:]
- }
-
- // Transpose the set of descriptors into a list.
- var xts []*ExtensionDesc
- for num, xt := range extDescs {
- if xt == nil {
- xt = &ExtensionDesc{Field: int32(num)}
- }
- xts = append(xts, xt)
- }
- return xts, nil
-}
-
-// isValidExtension reports whether xtd is a valid extension descriptor for md.
-func isValidExtension(md protoreflect.MessageDescriptor, xtd protoreflect.ExtensionTypeDescriptor) bool {
- return xtd.ContainingMessage() == md && md.ExtensionRanges().Has(xtd.Number())
-}
-
-// isScalarKind reports whether k is a protobuf scalar kind (except bytes).
-// This function exists for historical reasons since the representation of
-// scalars differs between v1 and v2, where v1 uses *T and v2 uses T.
-func isScalarKind(k reflect.Kind) bool {
- switch k {
- case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
- return true
- default:
- return false
- }
-}
-
-// clearUnknown removes unknown fields from m where remover.Has reports true.
-func clearUnknown(m protoreflect.Message, remover interface {
- Has(protoreflect.FieldNumber) bool
-}) {
- var bo protoreflect.RawFields
- for bi := m.GetUnknown(); len(bi) > 0; {
- num, _, n := protowire.ConsumeField(bi)
- if !remover.Has(num) {
- bo = append(bo, bi[:n]...)
- }
- bi = bi[n:]
- }
- if bi := m.GetUnknown(); len(bi) != len(bo) {
- m.SetUnknown(bo)
- }
-}
-
-type fieldNum protoreflect.FieldNumber
-
-func (n1 fieldNum) Has(n2 protoreflect.FieldNumber) bool {
- return protoreflect.FieldNumber(n1) == n2
-}
diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go
deleted file mode 100644
index dcdc2202fad..00000000000
--- a/vendor/github.com/golang/protobuf/proto/properties.go
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- "fmt"
- "reflect"
- "strconv"
- "strings"
- "sync"
-
- "google.golang.org/protobuf/reflect/protoreflect"
- "google.golang.org/protobuf/runtime/protoimpl"
-)
-
-// StructProperties represents protocol buffer type information for a
-// generated protobuf message in the open-struct API.
-//
-// Deprecated: Do not use.
-type StructProperties struct {
- // Prop are the properties for each field.
- //
- // Fields belonging to a oneof are stored in OneofTypes instead, with a
- // single Properties representing the parent oneof held here.
- //
- // The order of Prop matches the order of fields in the Go struct.
- // Struct fields that are not related to protobufs have a "XXX_" prefix
- // in the Properties.Name and must be ignored by the user.
- Prop []*Properties
-
- // OneofTypes contains information about the oneof fields in this message.
- // It is keyed by the protobuf field name.
- OneofTypes map[string]*OneofProperties
-}
-
-// Properties represents the type information for a protobuf message field.
-//
-// Deprecated: Do not use.
-type Properties struct {
- // Name is a placeholder name with little meaningful semantic value.
- // If the name has an "XXX_" prefix, the entire Properties must be ignored.
- Name string
- // OrigName is the protobuf field name or oneof name.
- OrigName string
- // JSONName is the JSON name for the protobuf field.
- JSONName string
- // Enum is a placeholder name for enums.
- // For historical reasons, this is neither the Go name for the enum,
- // nor the protobuf name for the enum.
- Enum string // Deprecated: Do not use.
- // Weak contains the full name of the weakly referenced message.
- Weak string
- // Wire is a string representation of the wire type.
- Wire string
- // WireType is the protobuf wire type for the field.
- WireType int
- // Tag is the protobuf field number.
- Tag int
- // Required reports whether this is a required field.
- Required bool
- // Optional reports whether this is a optional field.
- Optional bool
- // Repeated reports whether this is a repeated field.
- Repeated bool
- // Packed reports whether this is a packed repeated field of scalars.
- Packed bool
- // Proto3 reports whether this field operates under the proto3 syntax.
- Proto3 bool
- // Oneof reports whether this field belongs within a oneof.
- Oneof bool
-
- // Default is the default value in string form.
- Default string
- // HasDefault reports whether the field has a default value.
- HasDefault bool
-
- // MapKeyProp is the properties for the key field for a map field.
- MapKeyProp *Properties
- // MapValProp is the properties for the value field for a map field.
- MapValProp *Properties
-}
-
-// OneofProperties represents the type information for a protobuf oneof.
-//
-// Deprecated: Do not use.
-type OneofProperties struct {
- // Type is a pointer to the generated wrapper type for the field value.
- // This is nil for messages that are not in the open-struct API.
- Type reflect.Type
- // Field is the index into StructProperties.Prop for the containing oneof.
- Field int
- // Prop is the properties for the field.
- Prop *Properties
-}
-
-// String formats the properties in the protobuf struct field tag style.
-func (p *Properties) String() string {
- s := p.Wire
- s += "," + strconv.Itoa(p.Tag)
- if p.Required {
- s += ",req"
- }
- if p.Optional {
- s += ",opt"
- }
- if p.Repeated {
- s += ",rep"
- }
- if p.Packed {
- s += ",packed"
- }
- s += ",name=" + p.OrigName
- if p.JSONName != "" {
- s += ",json=" + p.JSONName
- }
- if len(p.Enum) > 0 {
- s += ",enum=" + p.Enum
- }
- if len(p.Weak) > 0 {
- s += ",weak=" + p.Weak
- }
- if p.Proto3 {
- s += ",proto3"
- }
- if p.Oneof {
- s += ",oneof"
- }
- if p.HasDefault {
- s += ",def=" + p.Default
- }
- return s
-}
-
-// Parse populates p by parsing a string in the protobuf struct field tag style.
-func (p *Properties) Parse(tag string) {
- // For example: "bytes,49,opt,name=foo,def=hello!"
- for len(tag) > 0 {
- i := strings.IndexByte(tag, ',')
- if i < 0 {
- i = len(tag)
- }
- switch s := tag[:i]; {
- case strings.HasPrefix(s, "name="):
- p.OrigName = s[len("name="):]
- case strings.HasPrefix(s, "json="):
- p.JSONName = s[len("json="):]
- case strings.HasPrefix(s, "enum="):
- p.Enum = s[len("enum="):]
- case strings.HasPrefix(s, "weak="):
- p.Weak = s[len("weak="):]
- case strings.Trim(s, "0123456789") == "":
- n, _ := strconv.ParseUint(s, 10, 32)
- p.Tag = int(n)
- case s == "opt":
- p.Optional = true
- case s == "req":
- p.Required = true
- case s == "rep":
- p.Repeated = true
- case s == "varint" || s == "zigzag32" || s == "zigzag64":
- p.Wire = s
- p.WireType = WireVarint
- case s == "fixed32":
- p.Wire = s
- p.WireType = WireFixed32
- case s == "fixed64":
- p.Wire = s
- p.WireType = WireFixed64
- case s == "bytes":
- p.Wire = s
- p.WireType = WireBytes
- case s == "group":
- p.Wire = s
- p.WireType = WireStartGroup
- case s == "packed":
- p.Packed = true
- case s == "proto3":
- p.Proto3 = true
- case s == "oneof":
- p.Oneof = true
- case strings.HasPrefix(s, "def="):
- // The default tag is special in that everything afterwards is the
- // default regardless of the presence of commas.
- p.HasDefault = true
- p.Default, i = tag[len("def="):], len(tag)
- }
- tag = strings.TrimPrefix(tag[i:], ",")
- }
-}
-
-// Init populates the properties from a protocol buffer struct tag.
-//
-// Deprecated: Do not use.
-func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
- p.Name = name
- p.OrigName = name
- if tag == "" {
- return
- }
- p.Parse(tag)
-
- if typ != nil && typ.Kind() == reflect.Map {
- p.MapKeyProp = new(Properties)
- p.MapKeyProp.Init(nil, "Key", f.Tag.Get("protobuf_key"), nil)
- p.MapValProp = new(Properties)
- p.MapValProp.Init(nil, "Value", f.Tag.Get("protobuf_val"), nil)
- }
-}
-
-var propertiesCache sync.Map // map[reflect.Type]*StructProperties
-
-// GetProperties returns the list of properties for the type represented by t,
-// which must be a generated protocol buffer message in the open-struct API,
-// where protobuf message fields are represented by exported Go struct fields.
-//
-// Deprecated: Use protobuf reflection instead.
-func GetProperties(t reflect.Type) *StructProperties {
- if p, ok := propertiesCache.Load(t); ok {
- return p.(*StructProperties)
- }
- p, _ := propertiesCache.LoadOrStore(t, newProperties(t))
- return p.(*StructProperties)
-}
-
-func newProperties(t reflect.Type) *StructProperties {
- if t.Kind() != reflect.Struct {
- panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
- }
-
- var hasOneof bool
- prop := new(StructProperties)
-
- // Construct a list of properties for each field in the struct.
- for i := 0; i < t.NumField(); i++ {
- p := new(Properties)
- f := t.Field(i)
- tagField := f.Tag.Get("protobuf")
- p.Init(f.Type, f.Name, tagField, &f)
-
- tagOneof := f.Tag.Get("protobuf_oneof")
- if tagOneof != "" {
- hasOneof = true
- p.OrigName = tagOneof
- }
-
- // Rename unrelated struct fields with the "XXX_" prefix since so much
- // user code simply checks for this to exclude special fields.
- if tagField == "" && tagOneof == "" && !strings.HasPrefix(p.Name, "XXX_") {
- p.Name = "XXX_" + p.Name
- p.OrigName = "XXX_" + p.OrigName
- } else if p.Weak != "" {
- p.Name = p.OrigName // avoid possible "XXX_" prefix on weak field
- }
-
- prop.Prop = append(prop.Prop, p)
- }
-
- // Construct a mapping of oneof field names to properties.
- if hasOneof {
- var oneofWrappers []interface{}
- if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
- oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
- }
- if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
- oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
- }
- if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(protoreflect.ProtoMessage); ok {
- if m, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok {
- oneofWrappers = m.ProtoMessageInfo().OneofWrappers
- }
- }
-
- prop.OneofTypes = make(map[string]*OneofProperties)
- for _, wrapper := range oneofWrappers {
- p := &OneofProperties{
- Type: reflect.ValueOf(wrapper).Type(), // *T
- Prop: new(Properties),
- }
- f := p.Type.Elem().Field(0)
- p.Prop.Name = f.Name
- p.Prop.Parse(f.Tag.Get("protobuf"))
-
- // Determine the struct field that contains this oneof.
- // Each wrapper is assignable to exactly one parent field.
- var foundOneof bool
- for i := 0; i < t.NumField() && !foundOneof; i++ {
- if p.Type.AssignableTo(t.Field(i).Type) {
- p.Field = i
- foundOneof = true
- }
- }
- if !foundOneof {
- panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
- }
- prop.OneofTypes[p.Prop.OrigName] = p
- }
- }
-
- return prop
-}
-
-func (sp *StructProperties) Len() int { return len(sp.Prop) }
-func (sp *StructProperties) Less(i, j int) bool { return false }
-func (sp *StructProperties) Swap(i, j int) { return }
diff --git a/vendor/github.com/golang/protobuf/proto/proto.go b/vendor/github.com/golang/protobuf/proto/proto.go
deleted file mode 100644
index 5aee89c323e..00000000000
--- a/vendor/github.com/golang/protobuf/proto/proto.go
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package proto provides functionality for handling protocol buffer messages.
-// In particular, it provides marshaling and unmarshaling between a protobuf
-// message and the binary wire format.
-//
-// See https://developers.google.com/protocol-buffers/docs/gotutorial for
-// more information.
-//
-// Deprecated: Use the "google.golang.org/protobuf/proto" package instead.
-package proto
-
-import (
- protoV2 "google.golang.org/protobuf/proto"
- "google.golang.org/protobuf/reflect/protoreflect"
- "google.golang.org/protobuf/runtime/protoiface"
- "google.golang.org/protobuf/runtime/protoimpl"
-)
-
-const (
- ProtoPackageIsVersion1 = true
- ProtoPackageIsVersion2 = true
- ProtoPackageIsVersion3 = true
- ProtoPackageIsVersion4 = true
-)
-
-// GeneratedEnum is any enum type generated by protoc-gen-go
-// which is a named int32 kind.
-// This type exists for documentation purposes.
-type GeneratedEnum interface{}
-
-// GeneratedMessage is any message type generated by protoc-gen-go
-// which is a pointer to a named struct kind.
-// This type exists for documentation purposes.
-type GeneratedMessage interface{}
-
-// Message is a protocol buffer message.
-//
-// This is the v1 version of the message interface and is marginally better
-// than an empty interface as it lacks any method to programatically interact
-// with the contents of the message.
-//
-// A v2 message is declared in "google.golang.org/protobuf/proto".Message and
-// exposes protobuf reflection as a first-class feature of the interface.
-//
-// To convert a v1 message to a v2 message, use the MessageV2 function.
-// To convert a v2 message to a v1 message, use the MessageV1 function.
-type Message = protoiface.MessageV1
-
-// MessageV1 converts either a v1 or v2 message to a v1 message.
-// It returns nil if m is nil.
-func MessageV1(m GeneratedMessage) protoiface.MessageV1 {
- return protoimpl.X.ProtoMessageV1Of(m)
-}
-
-// MessageV2 converts either a v1 or v2 message to a v2 message.
-// It returns nil if m is nil.
-func MessageV2(m GeneratedMessage) protoV2.Message {
- return protoimpl.X.ProtoMessageV2Of(m)
-}
-
-// MessageReflect returns a reflective view for a message.
-// It returns nil if m is nil.
-func MessageReflect(m Message) protoreflect.Message {
- return protoimpl.X.MessageOf(m)
-}
-
-// Marshaler is implemented by messages that can marshal themselves.
-// This interface is used by the following functions: Size, Marshal,
-// Buffer.Marshal, and Buffer.EncodeMessage.
-//
-// Deprecated: Do not implement.
-type Marshaler interface {
- // Marshal formats the encoded bytes of the message.
- // It should be deterministic and emit valid protobuf wire data.
- // The caller takes ownership of the returned buffer.
- Marshal() ([]byte, error)
-}
-
-// Unmarshaler is implemented by messages that can unmarshal themselves.
-// This interface is used by the following functions: Unmarshal, UnmarshalMerge,
-// Buffer.Unmarshal, Buffer.DecodeMessage, and Buffer.DecodeGroup.
-//
-// Deprecated: Do not implement.
-type Unmarshaler interface {
- // Unmarshal parses the encoded bytes of the protobuf wire input.
- // The provided buffer is only valid for during method call.
- // It should not reset the receiver message.
- Unmarshal([]byte) error
-}
-
-// Merger is implemented by messages that can merge themselves.
-// This interface is used by the following functions: Clone and Merge.
-//
-// Deprecated: Do not implement.
-type Merger interface {
- // Merge merges the contents of src into the receiver message.
- // It clones all data structures in src such that it aliases no mutable
- // memory referenced by src.
- Merge(src Message)
-}
-
-// RequiredNotSetError is an error type returned when
-// marshaling or unmarshaling a message with missing required fields.
-type RequiredNotSetError struct {
- err error
-}
-
-func (e *RequiredNotSetError) Error() string {
- if e.err != nil {
- return e.err.Error()
- }
- return "proto: required field not set"
-}
-func (e *RequiredNotSetError) RequiredNotSet() bool {
- return true
-}
-
-func checkRequiredNotSet(m protoV2.Message) error {
- if err := protoV2.CheckInitialized(m); err != nil {
- return &RequiredNotSetError{err: err}
- }
- return nil
-}
-
-// Clone returns a deep copy of src.
-func Clone(src Message) Message {
- return MessageV1(protoV2.Clone(MessageV2(src)))
-}
-
-// Merge merges src into dst, which must be messages of the same type.
-//
-// Populated scalar fields in src are copied to dst, while populated
-// singular messages in src are merged into dst by recursively calling Merge.
-// The elements of every list field in src is appended to the corresponded
-// list fields in dst. The entries of every map field in src is copied into
-// the corresponding map field in dst, possibly replacing existing entries.
-// The unknown fields of src are appended to the unknown fields of dst.
-func Merge(dst, src Message) {
- protoV2.Merge(MessageV2(dst), MessageV2(src))
-}
-
-// Equal reports whether two messages are equal.
-// If two messages marshal to the same bytes under deterministic serialization,
-// then Equal is guaranteed to report true.
-//
-// Two messages are equal if they are the same protobuf message type,
-// have the same set of populated known and extension field values,
-// and the same set of unknown fields values.
-//
-// Scalar values are compared with the equivalent of the == operator in Go,
-// except bytes values which are compared using bytes.Equal and
-// floating point values which specially treat NaNs as equal.
-// Message values are compared by recursively calling Equal.
-// Lists are equal if each element value is also equal.
-// Maps are equal if they have the same set of keys, where the pair of values
-// for each key is also equal.
-func Equal(x, y Message) bool {
- return protoV2.Equal(MessageV2(x), MessageV2(y))
-}
-
-func isMessageSet(md protoreflect.MessageDescriptor) bool {
- ms, ok := md.(interface{ IsMessageSet() bool })
- return ok && ms.IsMessageSet()
-}
diff --git a/vendor/github.com/golang/protobuf/proto/registry.go b/vendor/github.com/golang/protobuf/proto/registry.go
deleted file mode 100644
index 1e7ff642057..00000000000
--- a/vendor/github.com/golang/protobuf/proto/registry.go
+++ /dev/null
@@ -1,323 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- "bytes"
- "compress/gzip"
- "fmt"
- "io/ioutil"
- "reflect"
- "strings"
- "sync"
-
- "google.golang.org/protobuf/reflect/protoreflect"
- "google.golang.org/protobuf/reflect/protoregistry"
- "google.golang.org/protobuf/runtime/protoimpl"
-)
-
-// filePath is the path to the proto source file.
-type filePath = string // e.g., "google/protobuf/descriptor.proto"
-
-// fileDescGZIP is the compressed contents of the encoded FileDescriptorProto.
-type fileDescGZIP = []byte
-
-var fileCache sync.Map // map[filePath]fileDescGZIP
-
-// RegisterFile is called from generated code to register the compressed
-// FileDescriptorProto with the file path for a proto source file.
-//
-// Deprecated: Use protoregistry.GlobalFiles.RegisterFile instead.
-func RegisterFile(s filePath, d fileDescGZIP) {
- // Decompress the descriptor.
- zr, err := gzip.NewReader(bytes.NewReader(d))
- if err != nil {
- panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
- }
- b, err := ioutil.ReadAll(zr)
- if err != nil {
- panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
- }
-
- // Construct a protoreflect.FileDescriptor from the raw descriptor.
- // Note that DescBuilder.Build automatically registers the constructed
- // file descriptor with the v2 registry.
- protoimpl.DescBuilder{RawDescriptor: b}.Build()
-
- // Locally cache the raw descriptor form for the file.
- fileCache.Store(s, d)
-}
-
-// FileDescriptor returns the compressed FileDescriptorProto given the file path
-// for a proto source file. It returns nil if not found.
-//
-// Deprecated: Use protoregistry.GlobalFiles.FindFileByPath instead.
-func FileDescriptor(s filePath) fileDescGZIP {
- if v, ok := fileCache.Load(s); ok {
- return v.(fileDescGZIP)
- }
-
- // Find the descriptor in the v2 registry.
- var b []byte
- if fd, _ := protoregistry.GlobalFiles.FindFileByPath(s); fd != nil {
- if fd, ok := fd.(interface{ ProtoLegacyRawDesc() []byte }); ok {
- b = fd.ProtoLegacyRawDesc()
- } else {
- // TODO: Use protodesc.ToFileDescriptorProto to construct
- // a descriptorpb.FileDescriptorProto and marshal it.
- // However, doing so causes the proto package to have a dependency
- // on descriptorpb, leading to cyclic dependency issues.
- }
- }
-
- // Locally cache the raw descriptor form for the file.
- if len(b) > 0 {
- v, _ := fileCache.LoadOrStore(s, protoimpl.X.CompressGZIP(b))
- return v.(fileDescGZIP)
- }
- return nil
-}
-
-// enumName is the name of an enum. For historical reasons, the enum name is
-// neither the full Go name nor the full protobuf name of the enum.
-// The name is the dot-separated combination of just the proto package that the
-// enum is declared within followed by the Go type name of the generated enum.
-type enumName = string // e.g., "my.proto.package.GoMessage_GoEnum"
-
-// enumsByName maps enum values by name to their numeric counterpart.
-type enumsByName = map[string]int32
-
-// enumsByNumber maps enum values by number to their name counterpart.
-type enumsByNumber = map[int32]string
-
-var enumCache sync.Map // map[enumName]enumsByName
-var numFilesCache sync.Map // map[protoreflect.FullName]int
-
-// RegisterEnum is called from the generated code to register the mapping of
-// enum value names to enum numbers for the enum identified by s.
-//
-// Deprecated: Use protoregistry.GlobalTypes.RegisterEnum instead.
-func RegisterEnum(s enumName, _ enumsByNumber, m enumsByName) {
- if _, ok := enumCache.Load(s); ok {
- panic("proto: duplicate enum registered: " + s)
- }
- enumCache.Store(s, m)
-
- // This does not forward registration to the v2 registry since this API
- // lacks sufficient information to construct a complete v2 enum descriptor.
-}
-
-// EnumValueMap returns the mapping from enum value names to enum numbers for
-// the enum of the given name. It returns nil if not found.
-//
-// Deprecated: Use protoregistry.GlobalTypes.FindEnumByName instead.
-func EnumValueMap(s enumName) enumsByName {
- if v, ok := enumCache.Load(s); ok {
- return v.(enumsByName)
- }
-
- // Check whether the cache is stale. If the number of files in the current
- // package differs, then it means that some enums may have been recently
- // registered upstream that we do not know about.
- var protoPkg protoreflect.FullName
- if i := strings.LastIndexByte(s, '.'); i >= 0 {
- protoPkg = protoreflect.FullName(s[:i])
- }
- v, _ := numFilesCache.Load(protoPkg)
- numFiles, _ := v.(int)
- if protoregistry.GlobalFiles.NumFilesByPackage(protoPkg) == numFiles {
- return nil // cache is up-to-date; was not found earlier
- }
-
- // Update the enum cache for all enums declared in the given proto package.
- numFiles = 0
- protoregistry.GlobalFiles.RangeFilesByPackage(protoPkg, func(fd protoreflect.FileDescriptor) bool {
- walkEnums(fd, func(ed protoreflect.EnumDescriptor) {
- name := protoimpl.X.LegacyEnumName(ed)
- if _, ok := enumCache.Load(name); !ok {
- m := make(enumsByName)
- evs := ed.Values()
- for i := evs.Len() - 1; i >= 0; i-- {
- ev := evs.Get(i)
- m[string(ev.Name())] = int32(ev.Number())
- }
- enumCache.LoadOrStore(name, m)
- }
- })
- numFiles++
- return true
- })
- numFilesCache.Store(protoPkg, numFiles)
-
- // Check cache again for enum map.
- if v, ok := enumCache.Load(s); ok {
- return v.(enumsByName)
- }
- return nil
-}
-
-// walkEnums recursively walks all enums declared in d.
-func walkEnums(d interface {
- Enums() protoreflect.EnumDescriptors
- Messages() protoreflect.MessageDescriptors
-}, f func(protoreflect.EnumDescriptor)) {
- eds := d.Enums()
- for i := eds.Len() - 1; i >= 0; i-- {
- f(eds.Get(i))
- }
- mds := d.Messages()
- for i := mds.Len() - 1; i >= 0; i-- {
- walkEnums(mds.Get(i), f)
- }
-}
-
-// messageName is the full name of protobuf message.
-type messageName = string
-
-var messageTypeCache sync.Map // map[messageName]reflect.Type
-
-// RegisterType is called from generated code to register the message Go type
-// for a message of the given name.
-//
-// Deprecated: Use protoregistry.GlobalTypes.RegisterMessage instead.
-func RegisterType(m Message, s messageName) {
- mt := protoimpl.X.LegacyMessageTypeOf(m, protoreflect.FullName(s))
- if err := protoregistry.GlobalTypes.RegisterMessage(mt); err != nil {
- panic(err)
- }
- messageTypeCache.Store(s, reflect.TypeOf(m))
-}
-
-// RegisterMapType is called from generated code to register the Go map type
-// for a protobuf message representing a map entry.
-//
-// Deprecated: Do not use.
-func RegisterMapType(m interface{}, s messageName) {
- t := reflect.TypeOf(m)
- if t.Kind() != reflect.Map {
- panic(fmt.Sprintf("invalid map kind: %v", t))
- }
- if _, ok := messageTypeCache.Load(s); ok {
- panic(fmt.Errorf("proto: duplicate proto message registered: %s", s))
- }
- messageTypeCache.Store(s, t)
-}
-
-// MessageType returns the message type for a named message.
-// It returns nil if not found.
-//
-// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead.
-func MessageType(s messageName) reflect.Type {
- if v, ok := messageTypeCache.Load(s); ok {
- return v.(reflect.Type)
- }
-
- // Derive the message type from the v2 registry.
- var t reflect.Type
- if mt, _ := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(s)); mt != nil {
- t = messageGoType(mt)
- }
-
- // If we could not get a concrete type, it is possible that it is a
- // pseudo-message for a map entry.
- if t == nil {
- d, _ := protoregistry.GlobalFiles.FindDescriptorByName(protoreflect.FullName(s))
- if md, _ := d.(protoreflect.MessageDescriptor); md != nil && md.IsMapEntry() {
- kt := goTypeForField(md.Fields().ByNumber(1))
- vt := goTypeForField(md.Fields().ByNumber(2))
- t = reflect.MapOf(kt, vt)
- }
- }
-
- // Locally cache the message type for the given name.
- if t != nil {
- v, _ := messageTypeCache.LoadOrStore(s, t)
- return v.(reflect.Type)
- }
- return nil
-}
-
-func goTypeForField(fd protoreflect.FieldDescriptor) reflect.Type {
- switch k := fd.Kind(); k {
- case protoreflect.EnumKind:
- if et, _ := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName()); et != nil {
- return enumGoType(et)
- }
- return reflect.TypeOf(protoreflect.EnumNumber(0))
- case protoreflect.MessageKind, protoreflect.GroupKind:
- if mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName()); mt != nil {
- return messageGoType(mt)
- }
- return reflect.TypeOf((*protoreflect.Message)(nil)).Elem()
- default:
- return reflect.TypeOf(fd.Default().Interface())
- }
-}
-
-func enumGoType(et protoreflect.EnumType) reflect.Type {
- return reflect.TypeOf(et.New(0))
-}
-
-func messageGoType(mt protoreflect.MessageType) reflect.Type {
- return reflect.TypeOf(MessageV1(mt.Zero().Interface()))
-}
-
-// MessageName returns the full protobuf name for the given message type.
-//
-// Deprecated: Use protoreflect.MessageDescriptor.FullName instead.
-func MessageName(m Message) messageName {
- if m == nil {
- return ""
- }
- if m, ok := m.(interface{ XXX_MessageName() messageName }); ok {
- return m.XXX_MessageName()
- }
- return messageName(protoimpl.X.MessageDescriptorOf(m).FullName())
-}
-
-// RegisterExtension is called from the generated code to register
-// the extension descriptor.
-//
-// Deprecated: Use protoregistry.GlobalTypes.RegisterExtension instead.
-func RegisterExtension(d *ExtensionDesc) {
- if err := protoregistry.GlobalTypes.RegisterExtension(d); err != nil {
- panic(err)
- }
-}
-
-type extensionsByNumber = map[int32]*ExtensionDesc
-
-var extensionCache sync.Map // map[messageName]extensionsByNumber
-
-// RegisteredExtensions returns a map of the registered extensions for the
-// provided protobuf message, indexed by the extension field number.
-//
-// Deprecated: Use protoregistry.GlobalTypes.RangeExtensionsByMessage instead.
-func RegisteredExtensions(m Message) extensionsByNumber {
- // Check whether the cache is stale. If the number of extensions for
- // the given message differs, then it means that some extensions were
- // recently registered upstream that we do not know about.
- s := MessageName(m)
- v, _ := extensionCache.Load(s)
- xs, _ := v.(extensionsByNumber)
- if protoregistry.GlobalTypes.NumExtensionsByMessage(protoreflect.FullName(s)) == len(xs) {
- return xs // cache is up-to-date
- }
-
- // Cache is stale, re-compute the extensions map.
- xs = make(extensionsByNumber)
- protoregistry.GlobalTypes.RangeExtensionsByMessage(protoreflect.FullName(s), func(xt protoreflect.ExtensionType) bool {
- if xd, ok := xt.(*ExtensionDesc); ok {
- xs[int32(xt.TypeDescriptor().Number())] = xd
- } else {
- // TODO: This implies that the protoreflect.ExtensionType is a
- // custom type not generated by protoc-gen-go. We could try and
- // convert the type to an ExtensionDesc.
- }
- return true
- })
- extensionCache.Store(s, xs)
- return xs
-}
diff --git a/vendor/github.com/golang/protobuf/proto/text_decode.go b/vendor/github.com/golang/protobuf/proto/text_decode.go
deleted file mode 100644
index 4a593100987..00000000000
--- a/vendor/github.com/golang/protobuf/proto/text_decode.go
+++ /dev/null
@@ -1,801 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- "encoding"
- "errors"
- "fmt"
- "reflect"
- "strconv"
- "strings"
- "unicode/utf8"
-
- "google.golang.org/protobuf/encoding/prototext"
- protoV2 "google.golang.org/protobuf/proto"
- "google.golang.org/protobuf/reflect/protoreflect"
- "google.golang.org/protobuf/reflect/protoregistry"
-)
-
-const wrapTextUnmarshalV2 = false
-
-// ParseError is returned by UnmarshalText.
-type ParseError struct {
- Message string
-
- // Deprecated: Do not use.
- Line, Offset int
-}
-
-func (e *ParseError) Error() string {
- if wrapTextUnmarshalV2 {
- return e.Message
- }
- if e.Line == 1 {
- return fmt.Sprintf("line 1.%d: %v", e.Offset, e.Message)
- }
- return fmt.Sprintf("line %d: %v", e.Line, e.Message)
-}
-
-// UnmarshalText parses a proto text formatted string into m.
-func UnmarshalText(s string, m Message) error {
- if u, ok := m.(encoding.TextUnmarshaler); ok {
- return u.UnmarshalText([]byte(s))
- }
-
- m.Reset()
- mi := MessageV2(m)
-
- if wrapTextUnmarshalV2 {
- err := prototext.UnmarshalOptions{
- AllowPartial: true,
- }.Unmarshal([]byte(s), mi)
- if err != nil {
- return &ParseError{Message: err.Error()}
- }
- return checkRequiredNotSet(mi)
- } else {
- if err := newTextParser(s).unmarshalMessage(mi.ProtoReflect(), ""); err != nil {
- return err
- }
- return checkRequiredNotSet(mi)
- }
-}
-
-type textParser struct {
- s string // remaining input
- done bool // whether the parsing is finished (success or error)
- backed bool // whether back() was called
- offset, line int
- cur token
-}
-
-type token struct {
- value string
- err *ParseError
- line int // line number
- offset int // byte number from start of input, not start of line
- unquoted string // the unquoted version of value, if it was a quoted string
-}
-
-func newTextParser(s string) *textParser {
- p := new(textParser)
- p.s = s
- p.line = 1
- p.cur.line = 1
- return p
-}
-
-func (p *textParser) unmarshalMessage(m protoreflect.Message, terminator string) (err error) {
- md := m.Descriptor()
- fds := md.Fields()
-
- // A struct is a sequence of "name: value", terminated by one of
- // '>' or '}', or the end of the input. A name may also be
- // "[extension]" or "[type/url]".
- //
- // The whole struct can also be an expanded Any message, like:
- // [type/url] < ... struct contents ... >
- seen := make(map[protoreflect.FieldNumber]bool)
- for {
- tok := p.next()
- if tok.err != nil {
- return tok.err
- }
- if tok.value == terminator {
- break
- }
- if tok.value == "[" {
- if err := p.unmarshalExtensionOrAny(m, seen); err != nil {
- return err
- }
- continue
- }
-
- // This is a normal, non-extension field.
- name := protoreflect.Name(tok.value)
- fd := fds.ByName(name)
- switch {
- case fd == nil:
- gd := fds.ByName(protoreflect.Name(strings.ToLower(string(name))))
- if gd != nil && gd.Kind() == protoreflect.GroupKind && gd.Message().Name() == name {
- fd = gd
- }
- case fd.Kind() == protoreflect.GroupKind && fd.Message().Name() != name:
- fd = nil
- case fd.IsWeak() && fd.Message().IsPlaceholder():
- fd = nil
- }
- if fd == nil {
- typeName := string(md.FullName())
- if m, ok := m.Interface().(Message); ok {
- t := reflect.TypeOf(m)
- if t.Kind() == reflect.Ptr {
- typeName = t.Elem().String()
- }
- }
- return p.errorf("unknown field name %q in %v", name, typeName)
- }
- if od := fd.ContainingOneof(); od != nil && m.WhichOneof(od) != nil {
- return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, od.Name())
- }
- if fd.Cardinality() != protoreflect.Repeated && seen[fd.Number()] {
- return p.errorf("non-repeated field %q was repeated", fd.Name())
- }
- seen[fd.Number()] = true
-
- // Consume any colon.
- if err := p.checkForColon(fd); err != nil {
- return err
- }
-
- // Parse into the field.
- v := m.Get(fd)
- if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
- v = m.Mutable(fd)
- }
- if v, err = p.unmarshalValue(v, fd); err != nil {
- return err
- }
- m.Set(fd, v)
-
- if err := p.consumeOptionalSeparator(); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (p *textParser) unmarshalExtensionOrAny(m protoreflect.Message, seen map[protoreflect.FieldNumber]bool) error {
- name, err := p.consumeExtensionOrAnyName()
- if err != nil {
- return err
- }
-
- // If it contains a slash, it's an Any type URL.
- if slashIdx := strings.LastIndex(name, "/"); slashIdx >= 0 {
- tok := p.next()
- if tok.err != nil {
- return tok.err
- }
- // consume an optional colon
- if tok.value == ":" {
- tok = p.next()
- if tok.err != nil {
- return tok.err
- }
- }
-
- var terminator string
- switch tok.value {
- case "<":
- terminator = ">"
- case "{":
- terminator = "}"
- default:
- return p.errorf("expected '{' or '<', found %q", tok.value)
- }
-
- mt, err := protoregistry.GlobalTypes.FindMessageByURL(name)
- if err != nil {
- return p.errorf("unrecognized message %q in google.protobuf.Any", name[slashIdx+len("/"):])
- }
- m2 := mt.New()
- if err := p.unmarshalMessage(m2, terminator); err != nil {
- return err
- }
- b, err := protoV2.Marshal(m2.Interface())
- if err != nil {
- return p.errorf("failed to marshal message of type %q: %v", name[slashIdx+len("/"):], err)
- }
-
- urlFD := m.Descriptor().Fields().ByName("type_url")
- valFD := m.Descriptor().Fields().ByName("value")
- if seen[urlFD.Number()] {
- return p.errorf("Any message unpacked multiple times, or %q already set", urlFD.Name())
- }
- if seen[valFD.Number()] {
- return p.errorf("Any message unpacked multiple times, or %q already set", valFD.Name())
- }
- m.Set(urlFD, protoreflect.ValueOfString(name))
- m.Set(valFD, protoreflect.ValueOfBytes(b))
- seen[urlFD.Number()] = true
- seen[valFD.Number()] = true
- return nil
- }
-
- xname := protoreflect.FullName(name)
- xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname)
- if xt == nil && isMessageSet(m.Descriptor()) {
- xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension"))
- }
- if xt == nil {
- return p.errorf("unrecognized extension %q", name)
- }
- fd := xt.TypeDescriptor()
- if fd.ContainingMessage().FullName() != m.Descriptor().FullName() {
- return p.errorf("extension field %q does not extend message %q", name, m.Descriptor().FullName())
- }
-
- if err := p.checkForColon(fd); err != nil {
- return err
- }
-
- v := m.Get(fd)
- if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
- v = m.Mutable(fd)
- }
- v, err = p.unmarshalValue(v, fd)
- if err != nil {
- return err
- }
- m.Set(fd, v)
- return p.consumeOptionalSeparator()
-}
-
-func (p *textParser) unmarshalValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
- tok := p.next()
- if tok.err != nil {
- return v, tok.err
- }
- if tok.value == "" {
- return v, p.errorf("unexpected EOF")
- }
-
- switch {
- case fd.IsList():
- lv := v.List()
- var err error
- if tok.value == "[" {
- // Repeated field with list notation, like [1,2,3].
- for {
- vv := lv.NewElement()
- vv, err = p.unmarshalSingularValue(vv, fd)
- if err != nil {
- return v, err
- }
- lv.Append(vv)
-
- tok := p.next()
- if tok.err != nil {
- return v, tok.err
- }
- if tok.value == "]" {
- break
- }
- if tok.value != "," {
- return v, p.errorf("Expected ']' or ',' found %q", tok.value)
- }
- }
- return v, nil
- }
-
- // One value of the repeated field.
- p.back()
- vv := lv.NewElement()
- vv, err = p.unmarshalSingularValue(vv, fd)
- if err != nil {
- return v, err
- }
- lv.Append(vv)
- return v, nil
- case fd.IsMap():
- // The map entry should be this sequence of tokens:
- // < key : KEY value : VALUE >
- // However, implementations may omit key or value, and technically
- // we should support them in any order.
- var terminator string
- switch tok.value {
- case "<":
- terminator = ">"
- case "{":
- terminator = "}"
- default:
- return v, p.errorf("expected '{' or '<', found %q", tok.value)
- }
-
- keyFD := fd.MapKey()
- valFD := fd.MapValue()
-
- mv := v.Map()
- kv := keyFD.Default()
- vv := mv.NewValue()
- for {
- tok := p.next()
- if tok.err != nil {
- return v, tok.err
- }
- if tok.value == terminator {
- break
- }
- var err error
- switch tok.value {
- case "key":
- if err := p.consumeToken(":"); err != nil {
- return v, err
- }
- if kv, err = p.unmarshalSingularValue(kv, keyFD); err != nil {
- return v, err
- }
- if err := p.consumeOptionalSeparator(); err != nil {
- return v, err
- }
- case "value":
- if err := p.checkForColon(valFD); err != nil {
- return v, err
- }
- if vv, err = p.unmarshalSingularValue(vv, valFD); err != nil {
- return v, err
- }
- if err := p.consumeOptionalSeparator(); err != nil {
- return v, err
- }
- default:
- p.back()
- return v, p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value)
- }
- }
- mv.Set(kv.MapKey(), vv)
- return v, nil
- default:
- p.back()
- return p.unmarshalSingularValue(v, fd)
- }
-}
-
-func (p *textParser) unmarshalSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
- tok := p.next()
- if tok.err != nil {
- return v, tok.err
- }
- if tok.value == "" {
- return v, p.errorf("unexpected EOF")
- }
-
- switch fd.Kind() {
- case protoreflect.BoolKind:
- switch tok.value {
- case "true", "1", "t", "True":
- return protoreflect.ValueOfBool(true), nil
- case "false", "0", "f", "False":
- return protoreflect.ValueOfBool(false), nil
- }
- case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
- if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
- return protoreflect.ValueOfInt32(int32(x)), nil
- }
-
- // The C++ parser accepts large positive hex numbers that uses
- // two's complement arithmetic to represent negative numbers.
- // This feature is here for backwards compatibility with C++.
- if strings.HasPrefix(tok.value, "0x") {
- if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
- return protoreflect.ValueOfInt32(int32(-(int64(^x) + 1))), nil
- }
- }
- case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
- if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil {
- return protoreflect.ValueOfInt64(int64(x)), nil
- }
-
- // The C++ parser accepts large positive hex numbers that uses
- // two's complement arithmetic to represent negative numbers.
- // This feature is here for backwards compatibility with C++.
- if strings.HasPrefix(tok.value, "0x") {
- if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
- return protoreflect.ValueOfInt64(int64(-(int64(^x) + 1))), nil
- }
- }
- case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
- if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
- return protoreflect.ValueOfUint32(uint32(x)), nil
- }
- case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
- if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
- return protoreflect.ValueOfUint64(uint64(x)), nil
- }
- case protoreflect.FloatKind:
- // Ignore 'f' for compatibility with output generated by C++,
- // but don't remove 'f' when the value is "-inf" or "inf".
- v := tok.value
- if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
- v = v[:len(v)-len("f")]
- }
- if x, err := strconv.ParseFloat(v, 32); err == nil {
- return protoreflect.ValueOfFloat32(float32(x)), nil
- }
- case protoreflect.DoubleKind:
- // Ignore 'f' for compatibility with output generated by C++,
- // but don't remove 'f' when the value is "-inf" or "inf".
- v := tok.value
- if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
- v = v[:len(v)-len("f")]
- }
- if x, err := strconv.ParseFloat(v, 64); err == nil {
- return protoreflect.ValueOfFloat64(float64(x)), nil
- }
- case protoreflect.StringKind:
- if isQuote(tok.value[0]) {
- return protoreflect.ValueOfString(tok.unquoted), nil
- }
- case protoreflect.BytesKind:
- if isQuote(tok.value[0]) {
- return protoreflect.ValueOfBytes([]byte(tok.unquoted)), nil
- }
- case protoreflect.EnumKind:
- if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
- return protoreflect.ValueOfEnum(protoreflect.EnumNumber(x)), nil
- }
- vd := fd.Enum().Values().ByName(protoreflect.Name(tok.value))
- if vd != nil {
- return protoreflect.ValueOfEnum(vd.Number()), nil
- }
- case protoreflect.MessageKind, protoreflect.GroupKind:
- var terminator string
- switch tok.value {
- case "{":
- terminator = "}"
- case "<":
- terminator = ">"
- default:
- return v, p.errorf("expected '{' or '<', found %q", tok.value)
- }
- err := p.unmarshalMessage(v.Message(), terminator)
- return v, err
- default:
- panic(fmt.Sprintf("invalid kind %v", fd.Kind()))
- }
- return v, p.errorf("invalid %v: %v", fd.Kind(), tok.value)
-}
-
-// Consume a ':' from the input stream (if the next token is a colon),
-// returning an error if a colon is needed but not present.
-func (p *textParser) checkForColon(fd protoreflect.FieldDescriptor) *ParseError {
- tok := p.next()
- if tok.err != nil {
- return tok.err
- }
- if tok.value != ":" {
- if fd.Message() == nil {
- return p.errorf("expected ':', found %q", tok.value)
- }
- p.back()
- }
- return nil
-}
-
-// consumeExtensionOrAnyName consumes an extension name or an Any type URL and
-// the following ']'. It returns the name or URL consumed.
-func (p *textParser) consumeExtensionOrAnyName() (string, error) {
- tok := p.next()
- if tok.err != nil {
- return "", tok.err
- }
-
- // If extension name or type url is quoted, it's a single token.
- if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] {
- name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0]))
- if err != nil {
- return "", err
- }
- return name, p.consumeToken("]")
- }
-
- // Consume everything up to "]"
- var parts []string
- for tok.value != "]" {
- parts = append(parts, tok.value)
- tok = p.next()
- if tok.err != nil {
- return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
- }
- if p.done && tok.value != "]" {
- return "", p.errorf("unclosed type_url or extension name")
- }
- }
- return strings.Join(parts, ""), nil
-}
-
-// consumeOptionalSeparator consumes an optional semicolon or comma.
-// It is used in unmarshalMessage to provide backward compatibility.
-func (p *textParser) consumeOptionalSeparator() error {
- tok := p.next()
- if tok.err != nil {
- return tok.err
- }
- if tok.value != ";" && tok.value != "," {
- p.back()
- }
- return nil
-}
-
-func (p *textParser) errorf(format string, a ...interface{}) *ParseError {
- pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset}
- p.cur.err = pe
- p.done = true
- return pe
-}
-
-func (p *textParser) skipWhitespace() {
- i := 0
- for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
- if p.s[i] == '#' {
- // comment; skip to end of line or input
- for i < len(p.s) && p.s[i] != '\n' {
- i++
- }
- if i == len(p.s) {
- break
- }
- }
- if p.s[i] == '\n' {
- p.line++
- }
- i++
- }
- p.offset += i
- p.s = p.s[i:len(p.s)]
- if len(p.s) == 0 {
- p.done = true
- }
-}
-
-func (p *textParser) advance() {
- // Skip whitespace
- p.skipWhitespace()
- if p.done {
- return
- }
-
- // Start of non-whitespace
- p.cur.err = nil
- p.cur.offset, p.cur.line = p.offset, p.line
- p.cur.unquoted = ""
- switch p.s[0] {
- case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/':
- // Single symbol
- p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
- case '"', '\'':
- // Quoted string
- i := 1
- for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' {
- if p.s[i] == '\\' && i+1 < len(p.s) {
- // skip escaped char
- i++
- }
- i++
- }
- if i >= len(p.s) || p.s[i] != p.s[0] {
- p.errorf("unmatched quote")
- return
- }
- unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
- if err != nil {
- p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err)
- return
- }
- p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
- p.cur.unquoted = unq
- default:
- i := 0
- for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
- i++
- }
- if i == 0 {
- p.errorf("unexpected byte %#x", p.s[0])
- return
- }
- p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
- }
- p.offset += len(p.cur.value)
-}
-
-// Back off the parser by one token. Can only be done between calls to next().
-// It makes the next advance() a no-op.
-func (p *textParser) back() { p.backed = true }
-
-// Advances the parser and returns the new current token.
-func (p *textParser) next() *token {
- if p.backed || p.done {
- p.backed = false
- return &p.cur
- }
- p.advance()
- if p.done {
- p.cur.value = ""
- } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) {
- // Look for multiple quoted strings separated by whitespace,
- // and concatenate them.
- cat := p.cur
- for {
- p.skipWhitespace()
- if p.done || !isQuote(p.s[0]) {
- break
- }
- p.advance()
- if p.cur.err != nil {
- return &p.cur
- }
- cat.value += " " + p.cur.value
- cat.unquoted += p.cur.unquoted
- }
- p.done = false // parser may have seen EOF, but we want to return cat
- p.cur = cat
- }
- return &p.cur
-}
-
-func (p *textParser) consumeToken(s string) error {
- tok := p.next()
- if tok.err != nil {
- return tok.err
- }
- if tok.value != s {
- p.back()
- return p.errorf("expected %q, found %q", s, tok.value)
- }
- return nil
-}
-
-var errBadUTF8 = errors.New("proto: bad UTF-8")
-
-func unquoteC(s string, quote rune) (string, error) {
- // This is based on C++'s tokenizer.cc.
- // Despite its name, this is *not* parsing C syntax.
- // For instance, "\0" is an invalid quoted string.
-
- // Avoid allocation in trivial cases.
- simple := true
- for _, r := range s {
- if r == '\\' || r == quote {
- simple = false
- break
- }
- }
- if simple {
- return s, nil
- }
-
- buf := make([]byte, 0, 3*len(s)/2)
- for len(s) > 0 {
- r, n := utf8.DecodeRuneInString(s)
- if r == utf8.RuneError && n == 1 {
- return "", errBadUTF8
- }
- s = s[n:]
- if r != '\\' {
- if r < utf8.RuneSelf {
- buf = append(buf, byte(r))
- } else {
- buf = append(buf, string(r)...)
- }
- continue
- }
-
- ch, tail, err := unescape(s)
- if err != nil {
- return "", err
- }
- buf = append(buf, ch...)
- s = tail
- }
- return string(buf), nil
-}
-
-func unescape(s string) (ch string, tail string, err error) {
- r, n := utf8.DecodeRuneInString(s)
- if r == utf8.RuneError && n == 1 {
- return "", "", errBadUTF8
- }
- s = s[n:]
- switch r {
- case 'a':
- return "\a", s, nil
- case 'b':
- return "\b", s, nil
- case 'f':
- return "\f", s, nil
- case 'n':
- return "\n", s, nil
- case 'r':
- return "\r", s, nil
- case 't':
- return "\t", s, nil
- case 'v':
- return "\v", s, nil
- case '?':
- return "?", s, nil // trigraph workaround
- case '\'', '"', '\\':
- return string(r), s, nil
- case '0', '1', '2', '3', '4', '5', '6', '7':
- if len(s) < 2 {
- return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
- }
- ss := string(r) + s[:2]
- s = s[2:]
- i, err := strconv.ParseUint(ss, 8, 8)
- if err != nil {
- return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss)
- }
- return string([]byte{byte(i)}), s, nil
- case 'x', 'X', 'u', 'U':
- var n int
- switch r {
- case 'x', 'X':
- n = 2
- case 'u':
- n = 4
- case 'U':
- n = 8
- }
- if len(s) < n {
- return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n)
- }
- ss := s[:n]
- s = s[n:]
- i, err := strconv.ParseUint(ss, 16, 64)
- if err != nil {
- return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss)
- }
- if r == 'x' || r == 'X' {
- return string([]byte{byte(i)}), s, nil
- }
- if i > utf8.MaxRune {
- return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss)
- }
- return string(i), s, nil
- }
- return "", "", fmt.Errorf(`unknown escape \%c`, r)
-}
-
-func isIdentOrNumberChar(c byte) bool {
- switch {
- case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
- return true
- case '0' <= c && c <= '9':
- return true
- }
- switch c {
- case '-', '+', '.', '_':
- return true
- }
- return false
-}
-
-func isWhitespace(c byte) bool {
- switch c {
- case ' ', '\t', '\n', '\r':
- return true
- }
- return false
-}
-
-func isQuote(c byte) bool {
- switch c {
- case '"', '\'':
- return true
- }
- return false
-}
diff --git a/vendor/github.com/golang/protobuf/proto/text_encode.go b/vendor/github.com/golang/protobuf/proto/text_encode.go
deleted file mode 100644
index a31134eeb3b..00000000000
--- a/vendor/github.com/golang/protobuf/proto/text_encode.go
+++ /dev/null
@@ -1,560 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- "bytes"
- "encoding"
- "fmt"
- "io"
- "math"
- "sort"
- "strings"
-
- "google.golang.org/protobuf/encoding/prototext"
- "google.golang.org/protobuf/encoding/protowire"
- "google.golang.org/protobuf/proto"
- "google.golang.org/protobuf/reflect/protoreflect"
- "google.golang.org/protobuf/reflect/protoregistry"
-)
-
-const wrapTextMarshalV2 = false
-
-// TextMarshaler is a configurable text format marshaler.
-type TextMarshaler struct {
- Compact bool // use compact text format (one line)
- ExpandAny bool // expand google.protobuf.Any messages of known types
-}
-
-// Marshal writes the proto text format of m to w.
-func (tm *TextMarshaler) Marshal(w io.Writer, m Message) error {
- b, err := tm.marshal(m)
- if len(b) > 0 {
- if _, err := w.Write(b); err != nil {
- return err
- }
- }
- return err
-}
-
-// Text returns a proto text formatted string of m.
-func (tm *TextMarshaler) Text(m Message) string {
- b, _ := tm.marshal(m)
- return string(b)
-}
-
-func (tm *TextMarshaler) marshal(m Message) ([]byte, error) {
- mr := MessageReflect(m)
- if mr == nil || !mr.IsValid() {
- return []byte(""), nil
- }
-
- if wrapTextMarshalV2 {
- if m, ok := m.(encoding.TextMarshaler); ok {
- return m.MarshalText()
- }
-
- opts := prototext.MarshalOptions{
- AllowPartial: true,
- EmitUnknown: true,
- }
- if !tm.Compact {
- opts.Indent = " "
- }
- if !tm.ExpandAny {
- opts.Resolver = (*protoregistry.Types)(nil)
- }
- return opts.Marshal(mr.Interface())
- } else {
- w := &textWriter{
- compact: tm.Compact,
- expandAny: tm.ExpandAny,
- complete: true,
- }
-
- if m, ok := m.(encoding.TextMarshaler); ok {
- b, err := m.MarshalText()
- if err != nil {
- return nil, err
- }
- w.Write(b)
- return w.buf, nil
- }
-
- err := w.writeMessage(mr)
- return w.buf, err
- }
-}
-
-var (
- defaultTextMarshaler = TextMarshaler{}
- compactTextMarshaler = TextMarshaler{Compact: true}
-)
-
-// MarshalText writes the proto text format of m to w.
-func MarshalText(w io.Writer, m Message) error { return defaultTextMarshaler.Marshal(w, m) }
-
-// MarshalTextString returns a proto text formatted string of m.
-func MarshalTextString(m Message) string { return defaultTextMarshaler.Text(m) }
-
-// CompactText writes the compact proto text format of m to w.
-func CompactText(w io.Writer, m Message) error { return compactTextMarshaler.Marshal(w, m) }
-
-// CompactTextString returns a compact proto text formatted string of m.
-func CompactTextString(m Message) string { return compactTextMarshaler.Text(m) }
-
-var (
- newline = []byte("\n")
- endBraceNewline = []byte("}\n")
- posInf = []byte("inf")
- negInf = []byte("-inf")
- nan = []byte("nan")
-)
-
-// textWriter is an io.Writer that tracks its indentation level.
-type textWriter struct {
- compact bool // same as TextMarshaler.Compact
- expandAny bool // same as TextMarshaler.ExpandAny
- complete bool // whether the current position is a complete line
- indent int // indentation level; never negative
- buf []byte
-}
-
-func (w *textWriter) Write(p []byte) (n int, _ error) {
- newlines := bytes.Count(p, newline)
- if newlines == 0 {
- if !w.compact && w.complete {
- w.writeIndent()
- }
- w.buf = append(w.buf, p...)
- w.complete = false
- return len(p), nil
- }
-
- frags := bytes.SplitN(p, newline, newlines+1)
- if w.compact {
- for i, frag := range frags {
- if i > 0 {
- w.buf = append(w.buf, ' ')
- n++
- }
- w.buf = append(w.buf, frag...)
- n += len(frag)
- }
- return n, nil
- }
-
- for i, frag := range frags {
- if w.complete {
- w.writeIndent()
- }
- w.buf = append(w.buf, frag...)
- n += len(frag)
- if i+1 < len(frags) {
- w.buf = append(w.buf, '\n')
- n++
- }
- }
- w.complete = len(frags[len(frags)-1]) == 0
- return n, nil
-}
-
-func (w *textWriter) WriteByte(c byte) error {
- if w.compact && c == '\n' {
- c = ' '
- }
- if !w.compact && w.complete {
- w.writeIndent()
- }
- w.buf = append(w.buf, c)
- w.complete = c == '\n'
- return nil
-}
-
-func (w *textWriter) writeName(fd protoreflect.FieldDescriptor) {
- if !w.compact && w.complete {
- w.writeIndent()
- }
- w.complete = false
-
- if fd.Kind() != protoreflect.GroupKind {
- w.buf = append(w.buf, fd.Name()...)
- w.WriteByte(':')
- } else {
- // Use message type name for group field name.
- w.buf = append(w.buf, fd.Message().Name()...)
- }
-
- if !w.compact {
- w.WriteByte(' ')
- }
-}
-
-func requiresQuotes(u string) bool {
- // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
- for _, ch := range u {
- switch {
- case ch == '.' || ch == '/' || ch == '_':
- continue
- case '0' <= ch && ch <= '9':
- continue
- case 'A' <= ch && ch <= 'Z':
- continue
- case 'a' <= ch && ch <= 'z':
- continue
- default:
- return true
- }
- }
- return false
-}
-
-// writeProto3Any writes an expanded google.protobuf.Any message.
-//
-// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
-// required messages are not linked in).
-//
-// It returns (true, error) when sv was written in expanded format or an error
-// was encountered.
-func (w *textWriter) writeProto3Any(m protoreflect.Message) (bool, error) {
- md := m.Descriptor()
- fdURL := md.Fields().ByName("type_url")
- fdVal := md.Fields().ByName("value")
-
- url := m.Get(fdURL).String()
- mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
- if err != nil {
- return false, nil
- }
-
- b := m.Get(fdVal).Bytes()
- m2 := mt.New()
- if err := proto.Unmarshal(b, m2.Interface()); err != nil {
- return false, nil
- }
- w.Write([]byte("["))
- if requiresQuotes(url) {
- w.writeQuotedString(url)
- } else {
- w.Write([]byte(url))
- }
- if w.compact {
- w.Write([]byte("]:<"))
- } else {
- w.Write([]byte("]: <\n"))
- w.indent++
- }
- if err := w.writeMessage(m2); err != nil {
- return true, err
- }
- if w.compact {
- w.Write([]byte("> "))
- } else {
- w.indent--
- w.Write([]byte(">\n"))
- }
- return true, nil
-}
-
-func (w *textWriter) writeMessage(m protoreflect.Message) error {
- md := m.Descriptor()
- if w.expandAny && md.FullName() == "google.protobuf.Any" {
- if canExpand, err := w.writeProto3Any(m); canExpand {
- return err
- }
- }
-
- fds := md.Fields()
- for i := 0; i < fds.Len(); {
- fd := fds.Get(i)
- if od := fd.ContainingOneof(); od != nil {
- fd = m.WhichOneof(od)
- i += od.Fields().Len()
- } else {
- i++
- }
- if fd == nil || !m.Has(fd) {
- continue
- }
-
- switch {
- case fd.IsList():
- lv := m.Get(fd).List()
- for j := 0; j < lv.Len(); j++ {
- w.writeName(fd)
- v := lv.Get(j)
- if err := w.writeSingularValue(v, fd); err != nil {
- return err
- }
- w.WriteByte('\n')
- }
- case fd.IsMap():
- kfd := fd.MapKey()
- vfd := fd.MapValue()
- mv := m.Get(fd).Map()
-
- type entry struct{ key, val protoreflect.Value }
- var entries []entry
- mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
- entries = append(entries, entry{k.Value(), v})
- return true
- })
- sort.Slice(entries, func(i, j int) bool {
- switch kfd.Kind() {
- case protoreflect.BoolKind:
- return !entries[i].key.Bool() && entries[j].key.Bool()
- case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
- return entries[i].key.Int() < entries[j].key.Int()
- case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
- return entries[i].key.Uint() < entries[j].key.Uint()
- case protoreflect.StringKind:
- return entries[i].key.String() < entries[j].key.String()
- default:
- panic("invalid kind")
- }
- })
- for _, entry := range entries {
- w.writeName(fd)
- w.WriteByte('<')
- if !w.compact {
- w.WriteByte('\n')
- }
- w.indent++
- w.writeName(kfd)
- if err := w.writeSingularValue(entry.key, kfd); err != nil {
- return err
- }
- w.WriteByte('\n')
- w.writeName(vfd)
- if err := w.writeSingularValue(entry.val, vfd); err != nil {
- return err
- }
- w.WriteByte('\n')
- w.indent--
- w.WriteByte('>')
- w.WriteByte('\n')
- }
- default:
- w.writeName(fd)
- if err := w.writeSingularValue(m.Get(fd), fd); err != nil {
- return err
- }
- w.WriteByte('\n')
- }
- }
-
- if b := m.GetUnknown(); len(b) > 0 {
- w.writeUnknownFields(b)
- }
- return w.writeExtensions(m)
-}
-
-func (w *textWriter) writeSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
- switch fd.Kind() {
- case protoreflect.FloatKind, protoreflect.DoubleKind:
- switch vf := v.Float(); {
- case math.IsInf(vf, +1):
- w.Write(posInf)
- case math.IsInf(vf, -1):
- w.Write(negInf)
- case math.IsNaN(vf):
- w.Write(nan)
- default:
- fmt.Fprint(w, v.Interface())
- }
- case protoreflect.StringKind:
- // NOTE: This does not validate UTF-8 for historical reasons.
- w.writeQuotedString(string(v.String()))
- case protoreflect.BytesKind:
- w.writeQuotedString(string(v.Bytes()))
- case protoreflect.MessageKind, protoreflect.GroupKind:
- var bra, ket byte = '<', '>'
- if fd.Kind() == protoreflect.GroupKind {
- bra, ket = '{', '}'
- }
- w.WriteByte(bra)
- if !w.compact {
- w.WriteByte('\n')
- }
- w.indent++
- m := v.Message()
- if m2, ok := m.Interface().(encoding.TextMarshaler); ok {
- b, err := m2.MarshalText()
- if err != nil {
- return err
- }
- w.Write(b)
- } else {
- w.writeMessage(m)
- }
- w.indent--
- w.WriteByte(ket)
- case protoreflect.EnumKind:
- if ev := fd.Enum().Values().ByNumber(v.Enum()); ev != nil {
- fmt.Fprint(w, ev.Name())
- } else {
- fmt.Fprint(w, v.Enum())
- }
- default:
- fmt.Fprint(w, v.Interface())
- }
- return nil
-}
-
-// writeQuotedString writes a quoted string in the protocol buffer text format.
-func (w *textWriter) writeQuotedString(s string) {
- w.WriteByte('"')
- for i := 0; i < len(s); i++ {
- switch c := s[i]; c {
- case '\n':
- w.buf = append(w.buf, `\n`...)
- case '\r':
- w.buf = append(w.buf, `\r`...)
- case '\t':
- w.buf = append(w.buf, `\t`...)
- case '"':
- w.buf = append(w.buf, `\"`...)
- case '\\':
- w.buf = append(w.buf, `\\`...)
- default:
- if isPrint := c >= 0x20 && c < 0x7f; isPrint {
- w.buf = append(w.buf, c)
- } else {
- w.buf = append(w.buf, fmt.Sprintf(`\%03o`, c)...)
- }
- }
- }
- w.WriteByte('"')
-}
-
-func (w *textWriter) writeUnknownFields(b []byte) {
- if !w.compact {
- fmt.Fprintf(w, "/* %d unknown bytes */\n", len(b))
- }
-
- for len(b) > 0 {
- num, wtyp, n := protowire.ConsumeTag(b)
- if n < 0 {
- return
- }
- b = b[n:]
-
- if wtyp == protowire.EndGroupType {
- w.indent--
- w.Write(endBraceNewline)
- continue
- }
- fmt.Fprint(w, num)
- if wtyp != protowire.StartGroupType {
- w.WriteByte(':')
- }
- if !w.compact || wtyp == protowire.StartGroupType {
- w.WriteByte(' ')
- }
- switch wtyp {
- case protowire.VarintType:
- v, n := protowire.ConsumeVarint(b)
- if n < 0 {
- return
- }
- b = b[n:]
- fmt.Fprint(w, v)
- case protowire.Fixed32Type:
- v, n := protowire.ConsumeFixed32(b)
- if n < 0 {
- return
- }
- b = b[n:]
- fmt.Fprint(w, v)
- case protowire.Fixed64Type:
- v, n := protowire.ConsumeFixed64(b)
- if n < 0 {
- return
- }
- b = b[n:]
- fmt.Fprint(w, v)
- case protowire.BytesType:
- v, n := protowire.ConsumeBytes(b)
- if n < 0 {
- return
- }
- b = b[n:]
- fmt.Fprintf(w, "%q", v)
- case protowire.StartGroupType:
- w.WriteByte('{')
- w.indent++
- default:
- fmt.Fprintf(w, "/* unknown wire type %d */", wtyp)
- }
- w.WriteByte('\n')
- }
-}
-
-// writeExtensions writes all the extensions in m.
-func (w *textWriter) writeExtensions(m protoreflect.Message) error {
- md := m.Descriptor()
- if md.ExtensionRanges().Len() == 0 {
- return nil
- }
-
- type ext struct {
- desc protoreflect.FieldDescriptor
- val protoreflect.Value
- }
- var exts []ext
- m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- if fd.IsExtension() {
- exts = append(exts, ext{fd, v})
- }
- return true
- })
- sort.Slice(exts, func(i, j int) bool {
- return exts[i].desc.Number() < exts[j].desc.Number()
- })
-
- for _, ext := range exts {
- // For message set, use the name of the message as the extension name.
- name := string(ext.desc.FullName())
- if isMessageSet(ext.desc.ContainingMessage()) {
- name = strings.TrimSuffix(name, ".message_set_extension")
- }
-
- if !ext.desc.IsList() {
- if err := w.writeSingularExtension(name, ext.val, ext.desc); err != nil {
- return err
- }
- } else {
- lv := ext.val.List()
- for i := 0; i < lv.Len(); i++ {
- if err := w.writeSingularExtension(name, lv.Get(i), ext.desc); err != nil {
- return err
- }
- }
- }
- }
- return nil
-}
-
-func (w *textWriter) writeSingularExtension(name string, v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
- fmt.Fprintf(w, "[%s]:", name)
- if !w.compact {
- w.WriteByte(' ')
- }
- if err := w.writeSingularValue(v, fd); err != nil {
- return err
- }
- w.WriteByte('\n')
- return nil
-}
-
-func (w *textWriter) writeIndent() {
- if !w.complete {
- return
- }
- for i := 0; i < w.indent*2; i++ {
- w.buf = append(w.buf, ' ')
- }
- w.complete = false
-}
diff --git a/vendor/github.com/golang/protobuf/proto/wire.go b/vendor/github.com/golang/protobuf/proto/wire.go
deleted file mode 100644
index d7c28da5a75..00000000000
--- a/vendor/github.com/golang/protobuf/proto/wire.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-import (
- protoV2 "google.golang.org/protobuf/proto"
- "google.golang.org/protobuf/runtime/protoiface"
-)
-
-// Size returns the size in bytes of the wire-format encoding of m.
-func Size(m Message) int {
- if m == nil {
- return 0
- }
- mi := MessageV2(m)
- return protoV2.Size(mi)
-}
-
-// Marshal returns the wire-format encoding of m.
-func Marshal(m Message) ([]byte, error) {
- b, err := marshalAppend(nil, m, false)
- if b == nil {
- b = zeroBytes
- }
- return b, err
-}
-
-var zeroBytes = make([]byte, 0, 0)
-
-func marshalAppend(buf []byte, m Message, deterministic bool) ([]byte, error) {
- if m == nil {
- return nil, ErrNil
- }
- mi := MessageV2(m)
- nbuf, err := protoV2.MarshalOptions{
- Deterministic: deterministic,
- AllowPartial: true,
- }.MarshalAppend(buf, mi)
- if err != nil {
- return buf, err
- }
- if len(buf) == len(nbuf) {
- if !mi.ProtoReflect().IsValid() {
- return buf, ErrNil
- }
- }
- return nbuf, checkRequiredNotSet(mi)
-}
-
-// Unmarshal parses a wire-format message in b and places the decoded results in m.
-//
-// Unmarshal resets m before starting to unmarshal, so any existing data in m is always
-// removed. Use UnmarshalMerge to preserve and append to existing data.
-func Unmarshal(b []byte, m Message) error {
- m.Reset()
- return UnmarshalMerge(b, m)
-}
-
-// UnmarshalMerge parses a wire-format message in b and places the decoded results in m.
-func UnmarshalMerge(b []byte, m Message) error {
- mi := MessageV2(m)
- out, err := protoV2.UnmarshalOptions{
- AllowPartial: true,
- Merge: true,
- }.UnmarshalState(protoiface.UnmarshalInput{
- Buf: b,
- Message: mi.ProtoReflect(),
- })
- if err != nil {
- return err
- }
- if out.Flags&protoiface.UnmarshalInitialized > 0 {
- return nil
- }
- return checkRequiredNotSet(mi)
-}
diff --git a/vendor/github.com/golang/protobuf/proto/wrappers.go b/vendor/github.com/golang/protobuf/proto/wrappers.go
deleted file mode 100644
index 398e348599b..00000000000
--- a/vendor/github.com/golang/protobuf/proto/wrappers.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proto
-
-// Bool stores v in a new bool value and returns a pointer to it.
-func Bool(v bool) *bool { return &v }
-
-// Int stores v in a new int32 value and returns a pointer to it.
-//
-// Deprecated: Use Int32 instead.
-func Int(v int) *int32 { return Int32(int32(v)) }
-
-// Int32 stores v in a new int32 value and returns a pointer to it.
-func Int32(v int32) *int32 { return &v }
-
-// Int64 stores v in a new int64 value and returns a pointer to it.
-func Int64(v int64) *int64 { return &v }
-
-// Uint32 stores v in a new uint32 value and returns a pointer to it.
-func Uint32(v uint32) *uint32 { return &v }
-
-// Uint64 stores v in a new uint64 value and returns a pointer to it.
-func Uint64(v uint64) *uint64 { return &v }
-
-// Float32 stores v in a new float32 value and returns a pointer to it.
-func Float32(v float32) *float32 { return &v }
-
-// Float64 stores v in a new float64 value and returns a pointer to it.
-func Float64(v float64) *float64 { return &v }
-
-// String stores v in a new string value and returns a pointer to it.
-func String(v string) *string { return &v }
diff --git a/vendor/github.com/golang/protobuf/ptypes/any.go b/vendor/github.com/golang/protobuf/ptypes/any.go
deleted file mode 100644
index e729dcff13c..00000000000
--- a/vendor/github.com/golang/protobuf/ptypes/any.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ptypes
-
-import (
- "fmt"
- "strings"
-
- "github.com/golang/protobuf/proto"
- "google.golang.org/protobuf/reflect/protoreflect"
- "google.golang.org/protobuf/reflect/protoregistry"
-
- anypb "github.com/golang/protobuf/ptypes/any"
-)
-
-const urlPrefix = "type.googleapis.com/"
-
-// AnyMessageName returns the message name contained in an anypb.Any message.
-// Most type assertions should use the Is function instead.
-func AnyMessageName(any *anypb.Any) (string, error) {
- name, err := anyMessageName(any)
- return string(name), err
-}
-func anyMessageName(any *anypb.Any) (protoreflect.FullName, error) {
- if any == nil {
- return "", fmt.Errorf("message is nil")
- }
- name := protoreflect.FullName(any.TypeUrl)
- if i := strings.LastIndex(any.TypeUrl, "/"); i >= 0 {
- name = name[i+len("/"):]
- }
- if !name.IsValid() {
- return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl)
- }
- return name, nil
-}
-
-// MarshalAny marshals the given message m into an anypb.Any message.
-func MarshalAny(m proto.Message) (*anypb.Any, error) {
- switch dm := m.(type) {
- case DynamicAny:
- m = dm.Message
- case *DynamicAny:
- if dm == nil {
- return nil, proto.ErrNil
- }
- m = dm.Message
- }
- b, err := proto.Marshal(m)
- if err != nil {
- return nil, err
- }
- return &anypb.Any{TypeUrl: urlPrefix + proto.MessageName(m), Value: b}, nil
-}
-
-// Empty returns a new message of the type specified in an anypb.Any message.
-// It returns protoregistry.NotFound if the corresponding message type could not
-// be resolved in the global registry.
-func Empty(any *anypb.Any) (proto.Message, error) {
- name, err := anyMessageName(any)
- if err != nil {
- return nil, err
- }
- mt, err := protoregistry.GlobalTypes.FindMessageByName(name)
- if err != nil {
- return nil, err
- }
- return proto.MessageV1(mt.New().Interface()), nil
-}
-
-// UnmarshalAny unmarshals the encoded value contained in the anypb.Any message
-// into the provided message m. It returns an error if the target message
-// does not match the type in the Any message or if an unmarshal error occurs.
-//
-// The target message m may be a *DynamicAny message. If the underlying message
-// type could not be resolved, then this returns protoregistry.NotFound.
-func UnmarshalAny(any *anypb.Any, m proto.Message) error {
- if dm, ok := m.(*DynamicAny); ok {
- if dm.Message == nil {
- var err error
- dm.Message, err = Empty(any)
- if err != nil {
- return err
- }
- }
- m = dm.Message
- }
-
- anyName, err := AnyMessageName(any)
- if err != nil {
- return err
- }
- msgName := proto.MessageName(m)
- if anyName != msgName {
- return fmt.Errorf("mismatched message type: got %q want %q", anyName, msgName)
- }
- return proto.Unmarshal(any.Value, m)
-}
-
-// Is reports whether the Any message contains a message of the specified type.
-func Is(any *anypb.Any, m proto.Message) bool {
- if any == nil || m == nil {
- return false
- }
- name := proto.MessageName(m)
- if !strings.HasSuffix(any.TypeUrl, name) {
- return false
- }
- return len(any.TypeUrl) == len(name) || any.TypeUrl[len(any.TypeUrl)-len(name)-1] == '/'
-}
-
-// DynamicAny is a value that can be passed to UnmarshalAny to automatically
-// allocate a proto.Message for the type specified in an anypb.Any message.
-// The allocated message is stored in the embedded proto.Message.
-//
-// Example:
-// var x ptypes.DynamicAny
-// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
-// fmt.Printf("unmarshaled message: %v", x.Message)
-type DynamicAny struct{ proto.Message }
-
-func (m DynamicAny) String() string {
- if m.Message == nil {
- return ""
- }
- return m.Message.String()
-}
-func (m DynamicAny) Reset() {
- if m.Message == nil {
- return
- }
- m.Message.Reset()
-}
-func (m DynamicAny) ProtoMessage() {
- return
-}
-func (m DynamicAny) ProtoReflect() protoreflect.Message {
- if m.Message == nil {
- return nil
- }
- return dynamicAny{proto.MessageReflect(m.Message)}
-}
-
-type dynamicAny struct{ protoreflect.Message }
-
-func (m dynamicAny) Type() protoreflect.MessageType {
- return dynamicAnyType{m.Message.Type()}
-}
-func (m dynamicAny) New() protoreflect.Message {
- return dynamicAnyType{m.Message.Type()}.New()
-}
-func (m dynamicAny) Interface() protoreflect.ProtoMessage {
- return DynamicAny{proto.MessageV1(m.Message.Interface())}
-}
-
-type dynamicAnyType struct{ protoreflect.MessageType }
-
-func (t dynamicAnyType) New() protoreflect.Message {
- return dynamicAny{t.MessageType.New()}
-}
-func (t dynamicAnyType) Zero() protoreflect.Message {
- return dynamicAny{t.MessageType.Zero()}
-}
diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
deleted file mode 100644
index 0ef27d33deb..00000000000
--- a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: github.com/golang/protobuf/ptypes/any/any.proto
-
-package any
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- anypb "google.golang.org/protobuf/types/known/anypb"
- reflect "reflect"
-)
-
-// Symbols defined in public import of google/protobuf/any.proto.
-
-type Any = anypb.Any
-
-var File_github_com_golang_protobuf_ptypes_any_any_proto protoreflect.FileDescriptor
-
-var file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = []byte{
- 0x0a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
- 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
- 0x70, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
- 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2b, 0x5a, 0x29,
- 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
- 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65,
- 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x3b, 0x61, 0x6e, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x33,
-}
-
-var file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = []interface{}{}
-var file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = []int32{
- 0, // [0:0] is the sub-list for method output_type
- 0, // [0:0] is the sub-list for method input_type
- 0, // [0:0] is the sub-list for extension type_name
- 0, // [0:0] is the sub-list for extension extendee
- 0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_github_com_golang_protobuf_ptypes_any_any_proto_init() }
-func file_github_com_golang_protobuf_ptypes_any_any_proto_init() {
- if File_github_com_golang_protobuf_ptypes_any_any_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 0,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes,
- DependencyIndexes: file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs,
- }.Build()
- File_github_com_golang_protobuf_ptypes_any_any_proto = out.File
- file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = nil
- file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = nil
- file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = nil
-}
diff --git a/vendor/github.com/golang/protobuf/ptypes/doc.go b/vendor/github.com/golang/protobuf/ptypes/doc.go
deleted file mode 100644
index fb9edd5c627..00000000000
--- a/vendor/github.com/golang/protobuf/ptypes/doc.go
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package ptypes provides functionality for interacting with well-known types.
-package ptypes
diff --git a/vendor/github.com/golang/protobuf/ptypes/duration.go b/vendor/github.com/golang/protobuf/ptypes/duration.go
deleted file mode 100644
index 6110ae8a41d..00000000000
--- a/vendor/github.com/golang/protobuf/ptypes/duration.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ptypes
-
-import (
- "errors"
- "fmt"
- "time"
-
- durationpb "github.com/golang/protobuf/ptypes/duration"
-)
-
-// Range of google.protobuf.Duration as specified in duration.proto.
-// This is about 10,000 years in seconds.
-const (
- maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
- minSeconds = -maxSeconds
-)
-
-// Duration converts a durationpb.Duration to a time.Duration.
-// Duration returns an error if dur is invalid or overflows a time.Duration.
-func Duration(dur *durationpb.Duration) (time.Duration, error) {
- if err := validateDuration(dur); err != nil {
- return 0, err
- }
- d := time.Duration(dur.Seconds) * time.Second
- if int64(d/time.Second) != dur.Seconds {
- return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
- }
- if dur.Nanos != 0 {
- d += time.Duration(dur.Nanos) * time.Nanosecond
- if (d < 0) != (dur.Nanos < 0) {
- return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
- }
- }
- return d, nil
-}
-
-// DurationProto converts a time.Duration to a durationpb.Duration.
-func DurationProto(d time.Duration) *durationpb.Duration {
- nanos := d.Nanoseconds()
- secs := nanos / 1e9
- nanos -= secs * 1e9
- return &durationpb.Duration{
- Seconds: int64(secs),
- Nanos: int32(nanos),
- }
-}
-
-// validateDuration determines whether the durationpb.Duration is valid
-// according to the definition in google/protobuf/duration.proto.
-// A valid durpb.Duration may still be too large to fit into a time.Duration
-// Note that the range of durationpb.Duration is about 10,000 years,
-// while the range of time.Duration is about 290 years.
-func validateDuration(dur *durationpb.Duration) error {
- if dur == nil {
- return errors.New("duration: nil Duration")
- }
- if dur.Seconds < minSeconds || dur.Seconds > maxSeconds {
- return fmt.Errorf("duration: %v: seconds out of range", dur)
- }
- if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 {
- return fmt.Errorf("duration: %v: nanos out of range", dur)
- }
- // Seconds and Nanos must have the same sign, unless d.Nanos is zero.
- if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) {
- return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur)
- }
- return nil
-}
diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
deleted file mode 100644
index d0079ee3ef3..00000000000
--- a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: github.com/golang/protobuf/ptypes/duration/duration.proto
-
-package duration
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- durationpb "google.golang.org/protobuf/types/known/durationpb"
- reflect "reflect"
-)
-
-// Symbols defined in public import of google/protobuf/duration.proto.
-
-type Duration = durationpb.Duration
-
-var File_github_com_golang_protobuf_ptypes_duration_duration_proto protoreflect.FileDescriptor
-
-var file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = []byte{
- 0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
- 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
- 0x70, 0x65, 0x73, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x75, 0x72,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x35, 0x5a, 0x33, 0x67,
- 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67,
- 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73,
- 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
-}
-
-var file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = []interface{}{}
-var file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = []int32{
- 0, // [0:0] is the sub-list for method output_type
- 0, // [0:0] is the sub-list for method input_type
- 0, // [0:0] is the sub-list for extension type_name
- 0, // [0:0] is the sub-list for extension extendee
- 0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() }
-func file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() {
- if File_github_com_golang_protobuf_ptypes_duration_duration_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 0,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes,
- DependencyIndexes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs,
- }.Build()
- File_github_com_golang_protobuf_ptypes_duration_duration_proto = out.File
- file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = nil
- file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = nil
- file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = nil
-}
diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp.go b/vendor/github.com/golang/protobuf/ptypes/timestamp.go
deleted file mode 100644
index 026d0d49155..00000000000
--- a/vendor/github.com/golang/protobuf/ptypes/timestamp.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ptypes
-
-import (
- "errors"
- "fmt"
- "time"
-
- timestamppb "github.com/golang/protobuf/ptypes/timestamp"
-)
-
-// Range of google.protobuf.Duration as specified in timestamp.proto.
-const (
- // Seconds field of the earliest valid Timestamp.
- // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
- minValidSeconds = -62135596800
- // Seconds field just after the latest valid Timestamp.
- // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
- maxValidSeconds = 253402300800
-)
-
-// Timestamp converts a timestamppb.Timestamp to a time.Time.
-// It returns an error if the argument is invalid.
-//
-// Unlike most Go functions, if Timestamp returns an error, the first return
-// value is not the zero time.Time. Instead, it is the value obtained from the
-// time.Unix function when passed the contents of the Timestamp, in the UTC
-// locale. This may or may not be a meaningful time; many invalid Timestamps
-// do map to valid time.Times.
-//
-// A nil Timestamp returns an error. The first return value in that case is
-// undefined.
-func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) {
- // Don't return the zero value on error, because corresponds to a valid
- // timestamp. Instead return whatever time.Unix gives us.
- var t time.Time
- if ts == nil {
- t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
- } else {
- t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
- }
- return t, validateTimestamp(ts)
-}
-
-// TimestampNow returns a google.protobuf.Timestamp for the current time.
-func TimestampNow() *timestamppb.Timestamp {
- ts, err := TimestampProto(time.Now())
- if err != nil {
- panic("ptypes: time.Now() out of Timestamp range")
- }
- return ts
-}
-
-// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
-// It returns an error if the resulting Timestamp is invalid.
-func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) {
- ts := ×tamppb.Timestamp{
- Seconds: t.Unix(),
- Nanos: int32(t.Nanosecond()),
- }
- if err := validateTimestamp(ts); err != nil {
- return nil, err
- }
- return ts, nil
-}
-
-// TimestampString returns the RFC 3339 string for valid Timestamps.
-// For invalid Timestamps, it returns an error message in parentheses.
-func TimestampString(ts *timestamppb.Timestamp) string {
- t, err := Timestamp(ts)
- if err != nil {
- return fmt.Sprintf("(%v)", err)
- }
- return t.Format(time.RFC3339Nano)
-}
-
-// validateTimestamp determines whether a Timestamp is valid.
-// A valid timestamp represents a time in the range [0001-01-01, 10000-01-01)
-// and has a Nanos field in the range [0, 1e9).
-//
-// If the Timestamp is valid, validateTimestamp returns nil.
-// Otherwise, it returns an error that describes the problem.
-//
-// Every valid Timestamp can be represented by a time.Time,
-// but the converse is not true.
-func validateTimestamp(ts *timestamppb.Timestamp) error {
- if ts == nil {
- return errors.New("timestamp: nil Timestamp")
- }
- if ts.Seconds < minValidSeconds {
- return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
- }
- if ts.Seconds >= maxValidSeconds {
- return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
- }
- if ts.Nanos < 0 || ts.Nanos >= 1e9 {
- return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
- }
- return nil
-}
diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
deleted file mode 100644
index a76f8076009..00000000000
--- a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: github.com/golang/protobuf/ptypes/timestamp/timestamp.proto
-
-package timestamp
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- timestamppb "google.golang.org/protobuf/types/known/timestamppb"
- reflect "reflect"
-)
-
-// Symbols defined in public import of google/protobuf/timestamp.proto.
-
-type Timestamp = timestamppb.Timestamp
-
-var File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto protoreflect.FileDescriptor
-
-var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = []byte{
- 0x0a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
- 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
- 0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x74, 0x69,
- 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74,
- 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x37,
- 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
- 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
- 0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3b, 0x74, 0x69,
- 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x33,
-}
-
-var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = []interface{}{}
-var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = []int32{
- 0, // [0:0] is the sub-list for method output_type
- 0, // [0:0] is the sub-list for method input_type
- 0, // [0:0] is the sub-list for extension type_name
- 0, // [0:0] is the sub-list for extension extendee
- 0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() }
-func file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() {
- if File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc,
- NumEnums: 0,
- NumMessages: 0,
- NumExtensions: 0,
- NumServices: 0,
- },
- GoTypes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes,
- DependencyIndexes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs,
- }.Build()
- File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto = out.File
- file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = nil
- file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = nil
- file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = nil
-}
diff --git a/vendor/github.com/golang/snappy/.gitignore b/vendor/github.com/golang/snappy/.gitignore
deleted file mode 100644
index 042091d9b3b..00000000000
--- a/vendor/github.com/golang/snappy/.gitignore
+++ /dev/null
@@ -1,16 +0,0 @@
-cmd/snappytool/snappytool
-testdata/bench
-
-# These explicitly listed benchmark data files are for an obsolete version of
-# snappy_test.go.
-testdata/alice29.txt
-testdata/asyoulik.txt
-testdata/fireworks.jpeg
-testdata/geo.protodata
-testdata/html
-testdata/html_x_4
-testdata/kppkn.gtb
-testdata/lcet10.txt
-testdata/paper-100k.pdf
-testdata/plrabn12.txt
-testdata/urls.10K
diff --git a/vendor/github.com/golang/snappy/AUTHORS b/vendor/github.com/golang/snappy/AUTHORS
deleted file mode 100644
index bcfa19520af..00000000000
--- a/vendor/github.com/golang/snappy/AUTHORS
+++ /dev/null
@@ -1,15 +0,0 @@
-# This is the official list of Snappy-Go authors for copyright purposes.
-# This file is distinct from the CONTRIBUTORS files.
-# See the latter for an explanation.
-
-# Names should be added to this file as
-# Name or Organization
-# The email address is not required for organizations.
-
-# Please keep the list sorted.
-
-Damian Gryski
-Google Inc.
-Jan Mercl <0xjnml@gmail.com>
-Rodolfo Carvalho
-Sebastien Binet
diff --git a/vendor/github.com/golang/snappy/CONTRIBUTORS b/vendor/github.com/golang/snappy/CONTRIBUTORS
deleted file mode 100644
index 931ae31606f..00000000000
--- a/vendor/github.com/golang/snappy/CONTRIBUTORS
+++ /dev/null
@@ -1,37 +0,0 @@
-# This is the official list of people who can contribute
-# (and typically have contributed) code to the Snappy-Go repository.
-# The AUTHORS file lists the copyright holders; this file
-# lists people. For example, Google employees are listed here
-# but not in AUTHORS, because Google holds the copyright.
-#
-# The submission process automatically checks to make sure
-# that people submitting code are listed in this file (by email address).
-#
-# Names should be added to this file only after verifying that
-# the individual or the individual's organization has agreed to
-# the appropriate Contributor License Agreement, found here:
-#
-# http://code.google.com/legal/individual-cla-v1.0.html
-# http://code.google.com/legal/corporate-cla-v1.0.html
-#
-# The agreement for individuals can be filled out on the web.
-#
-# When adding J Random Contributor's name to this file,
-# either J's name or J's organization's name should be
-# added to the AUTHORS file, depending on whether the
-# individual or corporate CLA was used.
-
-# Names should be added to this file like so:
-# Name
-
-# Please keep the list sorted.
-
-Damian Gryski
-Jan Mercl <0xjnml@gmail.com>
-Kai Backman
-Marc-Antoine Ruel
-Nigel Tao
-Rob Pike
-Rodolfo Carvalho
-Russ Cox
-Sebastien Binet
diff --git a/vendor/github.com/golang/snappy/LICENSE b/vendor/github.com/golang/snappy/LICENSE
deleted file mode 100644
index 6050c10f4c8..00000000000
--- a/vendor/github.com/golang/snappy/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/golang/snappy/README b/vendor/github.com/golang/snappy/README
deleted file mode 100644
index cea12879a0e..00000000000
--- a/vendor/github.com/golang/snappy/README
+++ /dev/null
@@ -1,107 +0,0 @@
-The Snappy compression format in the Go programming language.
-
-To download and install from source:
-$ go get github.com/golang/snappy
-
-Unless otherwise noted, the Snappy-Go source files are distributed
-under the BSD-style license found in the LICENSE file.
-
-
-
-Benchmarks.
-
-The golang/snappy benchmarks include compressing (Z) and decompressing (U) ten
-or so files, the same set used by the C++ Snappy code (github.com/google/snappy
-and note the "google", not "golang"). On an "Intel(R) Core(TM) i7-3770 CPU @
-3.40GHz", Go's GOARCH=amd64 numbers as of 2016-05-29:
-
-"go test -test.bench=."
-
-_UFlat0-8 2.19GB/s ± 0% html
-_UFlat1-8 1.41GB/s ± 0% urls
-_UFlat2-8 23.5GB/s ± 2% jpg
-_UFlat3-8 1.91GB/s ± 0% jpg_200
-_UFlat4-8 14.0GB/s ± 1% pdf
-_UFlat5-8 1.97GB/s ± 0% html4
-_UFlat6-8 814MB/s ± 0% txt1
-_UFlat7-8 785MB/s ± 0% txt2
-_UFlat8-8 857MB/s ± 0% txt3
-_UFlat9-8 719MB/s ± 1% txt4
-_UFlat10-8 2.84GB/s ± 0% pb
-_UFlat11-8 1.05GB/s ± 0% gaviota
-
-_ZFlat0-8 1.04GB/s ± 0% html
-_ZFlat1-8 534MB/s ± 0% urls
-_ZFlat2-8 15.7GB/s ± 1% jpg
-_ZFlat3-8 740MB/s ± 3% jpg_200
-_ZFlat4-8 9.20GB/s ± 1% pdf
-_ZFlat5-8 991MB/s ± 0% html4
-_ZFlat6-8 379MB/s ± 0% txt1
-_ZFlat7-8 352MB/s ± 0% txt2
-_ZFlat8-8 396MB/s ± 1% txt3
-_ZFlat9-8 327MB/s ± 1% txt4
-_ZFlat10-8 1.33GB/s ± 1% pb
-_ZFlat11-8 605MB/s ± 1% gaviota
-
-
-
-"go test -test.bench=. -tags=noasm"
-
-_UFlat0-8 621MB/s ± 2% html
-_UFlat1-8 494MB/s ± 1% urls
-_UFlat2-8 23.2GB/s ± 1% jpg
-_UFlat3-8 1.12GB/s ± 1% jpg_200
-_UFlat4-8 4.35GB/s ± 1% pdf
-_UFlat5-8 609MB/s ± 0% html4
-_UFlat6-8 296MB/s ± 0% txt1
-_UFlat7-8 288MB/s ± 0% txt2
-_UFlat8-8 309MB/s ± 1% txt3
-_UFlat9-8 280MB/s ± 1% txt4
-_UFlat10-8 753MB/s ± 0% pb
-_UFlat11-8 400MB/s ± 0% gaviota
-
-_ZFlat0-8 409MB/s ± 1% html
-_ZFlat1-8 250MB/s ± 1% urls
-_ZFlat2-8 12.3GB/s ± 1% jpg
-_ZFlat3-8 132MB/s ± 0% jpg_200
-_ZFlat4-8 2.92GB/s ± 0% pdf
-_ZFlat5-8 405MB/s ± 1% html4
-_ZFlat6-8 179MB/s ± 1% txt1
-_ZFlat7-8 170MB/s ± 1% txt2
-_ZFlat8-8 189MB/s ± 1% txt3
-_ZFlat9-8 164MB/s ± 1% txt4
-_ZFlat10-8 479MB/s ± 1% pb
-_ZFlat11-8 270MB/s ± 1% gaviota
-
-
-
-For comparison (Go's encoded output is byte-for-byte identical to C++'s), here
-are the numbers from C++ Snappy's
-
-make CXXFLAGS="-O2 -DNDEBUG -g" clean snappy_unittest.log && cat snappy_unittest.log
-
-BM_UFlat/0 2.4GB/s html
-BM_UFlat/1 1.4GB/s urls
-BM_UFlat/2 21.8GB/s jpg
-BM_UFlat/3 1.5GB/s jpg_200
-BM_UFlat/4 13.3GB/s pdf
-BM_UFlat/5 2.1GB/s html4
-BM_UFlat/6 1.0GB/s txt1
-BM_UFlat/7 959.4MB/s txt2
-BM_UFlat/8 1.0GB/s txt3
-BM_UFlat/9 864.5MB/s txt4
-BM_UFlat/10 2.9GB/s pb
-BM_UFlat/11 1.2GB/s gaviota
-
-BM_ZFlat/0 944.3MB/s html (22.31 %)
-BM_ZFlat/1 501.6MB/s urls (47.78 %)
-BM_ZFlat/2 14.3GB/s jpg (99.95 %)
-BM_ZFlat/3 538.3MB/s jpg_200 (73.00 %)
-BM_ZFlat/4 8.3GB/s pdf (83.30 %)
-BM_ZFlat/5 903.5MB/s html4 (22.52 %)
-BM_ZFlat/6 336.0MB/s txt1 (57.88 %)
-BM_ZFlat/7 312.3MB/s txt2 (61.91 %)
-BM_ZFlat/8 353.1MB/s txt3 (54.99 %)
-BM_ZFlat/9 289.9MB/s txt4 (66.26 %)
-BM_ZFlat/10 1.2GB/s pb (19.68 %)
-BM_ZFlat/11 527.4MB/s gaviota (37.72 %)
diff --git a/vendor/github.com/golang/snappy/decode.go b/vendor/github.com/golang/snappy/decode.go
deleted file mode 100644
index 72efb0353dd..00000000000
--- a/vendor/github.com/golang/snappy/decode.go
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright 2011 The Snappy-Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package snappy
-
-import (
- "encoding/binary"
- "errors"
- "io"
-)
-
-var (
- // ErrCorrupt reports that the input is invalid.
- ErrCorrupt = errors.New("snappy: corrupt input")
- // ErrTooLarge reports that the uncompressed length is too large.
- ErrTooLarge = errors.New("snappy: decoded block is too large")
- // ErrUnsupported reports that the input isn't supported.
- ErrUnsupported = errors.New("snappy: unsupported input")
-
- errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
-)
-
-// DecodedLen returns the length of the decoded block.
-func DecodedLen(src []byte) (int, error) {
- v, _, err := decodedLen(src)
- return v, err
-}
-
-// decodedLen returns the length of the decoded block and the number of bytes
-// that the length header occupied.
-func decodedLen(src []byte) (blockLen, headerLen int, err error) {
- v, n := binary.Uvarint(src)
- if n <= 0 || v > 0xffffffff {
- return 0, 0, ErrCorrupt
- }
-
- const wordSize = 32 << (^uint(0) >> 32 & 1)
- if wordSize == 32 && v > 0x7fffffff {
- return 0, 0, ErrTooLarge
- }
- return int(v), n, nil
-}
-
-const (
- decodeErrCodeCorrupt = 1
- decodeErrCodeUnsupportedLiteralLength = 2
-)
-
-// Decode returns the decoded form of src. The returned slice may be a sub-
-// slice of dst if dst was large enough to hold the entire decoded block.
-// Otherwise, a newly allocated slice will be returned.
-//
-// The dst and src must not overlap. It is valid to pass a nil dst.
-func Decode(dst, src []byte) ([]byte, error) {
- dLen, s, err := decodedLen(src)
- if err != nil {
- return nil, err
- }
- if dLen <= len(dst) {
- dst = dst[:dLen]
- } else {
- dst = make([]byte, dLen)
- }
- switch decode(dst, src[s:]) {
- case 0:
- return dst, nil
- case decodeErrCodeUnsupportedLiteralLength:
- return nil, errUnsupportedLiteralLength
- }
- return nil, ErrCorrupt
-}
-
-// NewReader returns a new Reader that decompresses from r, using the framing
-// format described at
-// https://github.com/google/snappy/blob/master/framing_format.txt
-func NewReader(r io.Reader) *Reader {
- return &Reader{
- r: r,
- decoded: make([]byte, maxBlockSize),
- buf: make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize),
- }
-}
-
-// Reader is an io.Reader that can read Snappy-compressed bytes.
-type Reader struct {
- r io.Reader
- err error
- decoded []byte
- buf []byte
- // decoded[i:j] contains decoded bytes that have not yet been passed on.
- i, j int
- readHeader bool
-}
-
-// Reset discards any buffered data, resets all state, and switches the Snappy
-// reader to read from r. This permits reusing a Reader rather than allocating
-// a new one.
-func (r *Reader) Reset(reader io.Reader) {
- r.r = reader
- r.err = nil
- r.i = 0
- r.j = 0
- r.readHeader = false
-}
-
-func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) {
- if _, r.err = io.ReadFull(r.r, p); r.err != nil {
- if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
- r.err = ErrCorrupt
- }
- return false
- }
- return true
-}
-
-// Read satisfies the io.Reader interface.
-func (r *Reader) Read(p []byte) (int, error) {
- if r.err != nil {
- return 0, r.err
- }
- for {
- if r.i < r.j {
- n := copy(p, r.decoded[r.i:r.j])
- r.i += n
- return n, nil
- }
- if !r.readFull(r.buf[:4], true) {
- return 0, r.err
- }
- chunkType := r.buf[0]
- if !r.readHeader {
- if chunkType != chunkTypeStreamIdentifier {
- r.err = ErrCorrupt
- return 0, r.err
- }
- r.readHeader = true
- }
- chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
- if chunkLen > len(r.buf) {
- r.err = ErrUnsupported
- return 0, r.err
- }
-
- // The chunk types are specified at
- // https://github.com/google/snappy/blob/master/framing_format.txt
- switch chunkType {
- case chunkTypeCompressedData:
- // Section 4.2. Compressed data (chunk type 0x00).
- if chunkLen < checksumSize {
- r.err = ErrCorrupt
- return 0, r.err
- }
- buf := r.buf[:chunkLen]
- if !r.readFull(buf, false) {
- return 0, r.err
- }
- checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
- buf = buf[checksumSize:]
-
- n, err := DecodedLen(buf)
- if err != nil {
- r.err = err
- return 0, r.err
- }
- if n > len(r.decoded) {
- r.err = ErrCorrupt
- return 0, r.err
- }
- if _, err := Decode(r.decoded, buf); err != nil {
- r.err = err
- return 0, r.err
- }
- if crc(r.decoded[:n]) != checksum {
- r.err = ErrCorrupt
- return 0, r.err
- }
- r.i, r.j = 0, n
- continue
-
- case chunkTypeUncompressedData:
- // Section 4.3. Uncompressed data (chunk type 0x01).
- if chunkLen < checksumSize {
- r.err = ErrCorrupt
- return 0, r.err
- }
- buf := r.buf[:checksumSize]
- if !r.readFull(buf, false) {
- return 0, r.err
- }
- checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
- // Read directly into r.decoded instead of via r.buf.
- n := chunkLen - checksumSize
- if n > len(r.decoded) {
- r.err = ErrCorrupt
- return 0, r.err
- }
- if !r.readFull(r.decoded[:n], false) {
- return 0, r.err
- }
- if crc(r.decoded[:n]) != checksum {
- r.err = ErrCorrupt
- return 0, r.err
- }
- r.i, r.j = 0, n
- continue
-
- case chunkTypeStreamIdentifier:
- // Section 4.1. Stream identifier (chunk type 0xff).
- if chunkLen != len(magicBody) {
- r.err = ErrCorrupt
- return 0, r.err
- }
- if !r.readFull(r.buf[:len(magicBody)], false) {
- return 0, r.err
- }
- for i := 0; i < len(magicBody); i++ {
- if r.buf[i] != magicBody[i] {
- r.err = ErrCorrupt
- return 0, r.err
- }
- }
- continue
- }
-
- if chunkType <= 0x7f {
- // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
- r.err = ErrUnsupported
- return 0, r.err
- }
- // Section 4.4 Padding (chunk type 0xfe).
- // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
- if !r.readFull(r.buf[:chunkLen], false) {
- return 0, r.err
- }
- }
-}
diff --git a/vendor/github.com/golang/snappy/decode_amd64.go b/vendor/github.com/golang/snappy/decode_amd64.go
deleted file mode 100644
index fcd192b849e..00000000000
--- a/vendor/github.com/golang/snappy/decode_amd64.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2016 The Snappy-Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !appengine
-// +build gc
-// +build !noasm
-
-package snappy
-
-// decode has the same semantics as in decode_other.go.
-//
-//go:noescape
-func decode(dst, src []byte) int
diff --git a/vendor/github.com/golang/snappy/decode_amd64.s b/vendor/github.com/golang/snappy/decode_amd64.s
deleted file mode 100644
index e6179f65e35..00000000000
--- a/vendor/github.com/golang/snappy/decode_amd64.s
+++ /dev/null
@@ -1,490 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !appengine
-// +build gc
-// +build !noasm
-
-#include "textflag.h"
-
-// The asm code generally follows the pure Go code in decode_other.go, except
-// where marked with a "!!!".
-
-// func decode(dst, src []byte) int
-//
-// All local variables fit into registers. The non-zero stack size is only to
-// spill registers and push args when issuing a CALL. The register allocation:
-// - AX scratch
-// - BX scratch
-// - CX length or x
-// - DX offset
-// - SI &src[s]
-// - DI &dst[d]
-// + R8 dst_base
-// + R9 dst_len
-// + R10 dst_base + dst_len
-// + R11 src_base
-// + R12 src_len
-// + R13 src_base + src_len
-// - R14 used by doCopy
-// - R15 used by doCopy
-//
-// The registers R8-R13 (marked with a "+") are set at the start of the
-// function, and after a CALL returns, and are not otherwise modified.
-//
-// The d variable is implicitly DI - R8, and len(dst)-d is R10 - DI.
-// The s variable is implicitly SI - R11, and len(src)-s is R13 - SI.
-TEXT ·decode(SB), NOSPLIT, $48-56
- // Initialize SI, DI and R8-R13.
- MOVQ dst_base+0(FP), R8
- MOVQ dst_len+8(FP), R9
- MOVQ R8, DI
- MOVQ R8, R10
- ADDQ R9, R10
- MOVQ src_base+24(FP), R11
- MOVQ src_len+32(FP), R12
- MOVQ R11, SI
- MOVQ R11, R13
- ADDQ R12, R13
-
-loop:
- // for s < len(src)
- CMPQ SI, R13
- JEQ end
-
- // CX = uint32(src[s])
- //
- // switch src[s] & 0x03
- MOVBLZX (SI), CX
- MOVL CX, BX
- ANDL $3, BX
- CMPL BX, $1
- JAE tagCopy
-
- // ----------------------------------------
- // The code below handles literal tags.
-
- // case tagLiteral:
- // x := uint32(src[s] >> 2)
- // switch
- SHRL $2, CX
- CMPL CX, $60
- JAE tagLit60Plus
-
- // case x < 60:
- // s++
- INCQ SI
-
-doLit:
- // This is the end of the inner "switch", when we have a literal tag.
- //
- // We assume that CX == x and x fits in a uint32, where x is the variable
- // used in the pure Go decode_other.go code.
-
- // length = int(x) + 1
- //
- // Unlike the pure Go code, we don't need to check if length <= 0 because
- // CX can hold 64 bits, so the increment cannot overflow.
- INCQ CX
-
- // Prepare to check if copying length bytes will run past the end of dst or
- // src.
- //
- // AX = len(dst) - d
- // BX = len(src) - s
- MOVQ R10, AX
- SUBQ DI, AX
- MOVQ R13, BX
- SUBQ SI, BX
-
- // !!! Try a faster technique for short (16 or fewer bytes) copies.
- //
- // if length > 16 || len(dst)-d < 16 || len(src)-s < 16 {
- // goto callMemmove // Fall back on calling runtime·memmove.
- // }
- //
- // The C++ snappy code calls this TryFastAppend. It also checks len(src)-s
- // against 21 instead of 16, because it cannot assume that all of its input
- // is contiguous in memory and so it needs to leave enough source bytes to
- // read the next tag without refilling buffers, but Go's Decode assumes
- // contiguousness (the src argument is a []byte).
- CMPQ CX, $16
- JGT callMemmove
- CMPQ AX, $16
- JLT callMemmove
- CMPQ BX, $16
- JLT callMemmove
-
- // !!! Implement the copy from src to dst as a 16-byte load and store.
- // (Decode's documentation says that dst and src must not overlap.)
- //
- // This always copies 16 bytes, instead of only length bytes, but that's
- // OK. If the input is a valid Snappy encoding then subsequent iterations
- // will fix up the overrun. Otherwise, Decode returns a nil []byte (and a
- // non-nil error), so the overrun will be ignored.
- //
- // Note that on amd64, it is legal and cheap to issue unaligned 8-byte or
- // 16-byte loads and stores. This technique probably wouldn't be as
- // effective on architectures that are fussier about alignment.
- MOVOU 0(SI), X0
- MOVOU X0, 0(DI)
-
- // d += length
- // s += length
- ADDQ CX, DI
- ADDQ CX, SI
- JMP loop
-
-callMemmove:
- // if length > len(dst)-d || length > len(src)-s { etc }
- CMPQ CX, AX
- JGT errCorrupt
- CMPQ CX, BX
- JGT errCorrupt
-
- // copy(dst[d:], src[s:s+length])
- //
- // This means calling runtime·memmove(&dst[d], &src[s], length), so we push
- // DI, SI and CX as arguments. Coincidentally, we also need to spill those
- // three registers to the stack, to save local variables across the CALL.
- MOVQ DI, 0(SP)
- MOVQ SI, 8(SP)
- MOVQ CX, 16(SP)
- MOVQ DI, 24(SP)
- MOVQ SI, 32(SP)
- MOVQ CX, 40(SP)
- CALL runtime·memmove(SB)
-
- // Restore local variables: unspill registers from the stack and
- // re-calculate R8-R13.
- MOVQ 24(SP), DI
- MOVQ 32(SP), SI
- MOVQ 40(SP), CX
- MOVQ dst_base+0(FP), R8
- MOVQ dst_len+8(FP), R9
- MOVQ R8, R10
- ADDQ R9, R10
- MOVQ src_base+24(FP), R11
- MOVQ src_len+32(FP), R12
- MOVQ R11, R13
- ADDQ R12, R13
-
- // d += length
- // s += length
- ADDQ CX, DI
- ADDQ CX, SI
- JMP loop
-
-tagLit60Plus:
- // !!! This fragment does the
- //
- // s += x - 58; if uint(s) > uint(len(src)) { etc }
- //
- // checks. In the asm version, we code it once instead of once per switch case.
- ADDQ CX, SI
- SUBQ $58, SI
- MOVQ SI, BX
- SUBQ R11, BX
- CMPQ BX, R12
- JA errCorrupt
-
- // case x == 60:
- CMPL CX, $61
- JEQ tagLit61
- JA tagLit62Plus
-
- // x = uint32(src[s-1])
- MOVBLZX -1(SI), CX
- JMP doLit
-
-tagLit61:
- // case x == 61:
- // x = uint32(src[s-2]) | uint32(src[s-1])<<8
- MOVWLZX -2(SI), CX
- JMP doLit
-
-tagLit62Plus:
- CMPL CX, $62
- JA tagLit63
-
- // case x == 62:
- // x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
- MOVWLZX -3(SI), CX
- MOVBLZX -1(SI), BX
- SHLL $16, BX
- ORL BX, CX
- JMP doLit
-
-tagLit63:
- // case x == 63:
- // x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
- MOVL -4(SI), CX
- JMP doLit
-
-// The code above handles literal tags.
-// ----------------------------------------
-// The code below handles copy tags.
-
-tagCopy4:
- // case tagCopy4:
- // s += 5
- ADDQ $5, SI
-
- // if uint(s) > uint(len(src)) { etc }
- MOVQ SI, BX
- SUBQ R11, BX
- CMPQ BX, R12
- JA errCorrupt
-
- // length = 1 + int(src[s-5])>>2
- SHRQ $2, CX
- INCQ CX
-
- // offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
- MOVLQZX -4(SI), DX
- JMP doCopy
-
-tagCopy2:
- // case tagCopy2:
- // s += 3
- ADDQ $3, SI
-
- // if uint(s) > uint(len(src)) { etc }
- MOVQ SI, BX
- SUBQ R11, BX
- CMPQ BX, R12
- JA errCorrupt
-
- // length = 1 + int(src[s-3])>>2
- SHRQ $2, CX
- INCQ CX
-
- // offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
- MOVWQZX -2(SI), DX
- JMP doCopy
-
-tagCopy:
- // We have a copy tag. We assume that:
- // - BX == src[s] & 0x03
- // - CX == src[s]
- CMPQ BX, $2
- JEQ tagCopy2
- JA tagCopy4
-
- // case tagCopy1:
- // s += 2
- ADDQ $2, SI
-
- // if uint(s) > uint(len(src)) { etc }
- MOVQ SI, BX
- SUBQ R11, BX
- CMPQ BX, R12
- JA errCorrupt
-
- // offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
- MOVQ CX, DX
- ANDQ $0xe0, DX
- SHLQ $3, DX
- MOVBQZX -1(SI), BX
- ORQ BX, DX
-
- // length = 4 + int(src[s-2])>>2&0x7
- SHRQ $2, CX
- ANDQ $7, CX
- ADDQ $4, CX
-
-doCopy:
- // This is the end of the outer "switch", when we have a copy tag.
- //
- // We assume that:
- // - CX == length && CX > 0
- // - DX == offset
-
- // if offset <= 0 { etc }
- CMPQ DX, $0
- JLE errCorrupt
-
- // if d < offset { etc }
- MOVQ DI, BX
- SUBQ R8, BX
- CMPQ BX, DX
- JLT errCorrupt
-
- // if length > len(dst)-d { etc }
- MOVQ R10, BX
- SUBQ DI, BX
- CMPQ CX, BX
- JGT errCorrupt
-
- // forwardCopy(dst[d:d+length], dst[d-offset:]); d += length
- //
- // Set:
- // - R14 = len(dst)-d
- // - R15 = &dst[d-offset]
- MOVQ R10, R14
- SUBQ DI, R14
- MOVQ DI, R15
- SUBQ DX, R15
-
- // !!! Try a faster technique for short (16 or fewer bytes) forward copies.
- //
- // First, try using two 8-byte load/stores, similar to the doLit technique
- // above. Even if dst[d:d+length] and dst[d-offset:] can overlap, this is
- // still OK if offset >= 8. Note that this has to be two 8-byte load/stores
- // and not one 16-byte load/store, and the first store has to be before the
- // second load, due to the overlap if offset is in the range [8, 16).
- //
- // if length > 16 || offset < 8 || len(dst)-d < 16 {
- // goto slowForwardCopy
- // }
- // copy 16 bytes
- // d += length
- CMPQ CX, $16
- JGT slowForwardCopy
- CMPQ DX, $8
- JLT slowForwardCopy
- CMPQ R14, $16
- JLT slowForwardCopy
- MOVQ 0(R15), AX
- MOVQ AX, 0(DI)
- MOVQ 8(R15), BX
- MOVQ BX, 8(DI)
- ADDQ CX, DI
- JMP loop
-
-slowForwardCopy:
- // !!! If the forward copy is longer than 16 bytes, or if offset < 8, we
- // can still try 8-byte load stores, provided we can overrun up to 10 extra
- // bytes. As above, the overrun will be fixed up by subsequent iterations
- // of the outermost loop.
- //
- // The C++ snappy code calls this technique IncrementalCopyFastPath. Its
- // commentary says:
- //
- // ----
- //
- // The main part of this loop is a simple copy of eight bytes at a time
- // until we've copied (at least) the requested amount of bytes. However,
- // if d and d-offset are less than eight bytes apart (indicating a
- // repeating pattern of length < 8), we first need to expand the pattern in
- // order to get the correct results. For instance, if the buffer looks like
- // this, with the eight-byte and patterns marked as
- // intervals:
- //
- // abxxxxxxxxxxxx
- // [------] d-offset
- // [------] d
- //
- // a single eight-byte copy from to will repeat the pattern
- // once, after which we can move two bytes without moving :
- //
- // ababxxxxxxxxxx
- // [------] d-offset
- // [------] d
- //
- // and repeat the exercise until the two no longer overlap.
- //
- // This allows us to do very well in the special case of one single byte
- // repeated many times, without taking a big hit for more general cases.
- //
- // The worst case of extra writing past the end of the match occurs when
- // offset == 1 and length == 1; the last copy will read from byte positions
- // [0..7] and write to [4..11], whereas it was only supposed to write to
- // position 1. Thus, ten excess bytes.
- //
- // ----
- //
- // That "10 byte overrun" worst case is confirmed by Go's
- // TestSlowForwardCopyOverrun, which also tests the fixUpSlowForwardCopy
- // and finishSlowForwardCopy algorithm.
- //
- // if length > len(dst)-d-10 {
- // goto verySlowForwardCopy
- // }
- SUBQ $10, R14
- CMPQ CX, R14
- JGT verySlowForwardCopy
-
-makeOffsetAtLeast8:
- // !!! As above, expand the pattern so that offset >= 8 and we can use
- // 8-byte load/stores.
- //
- // for offset < 8 {
- // copy 8 bytes from dst[d-offset:] to dst[d:]
- // length -= offset
- // d += offset
- // offset += offset
- // // The two previous lines together means that d-offset, and therefore
- // // R15, is unchanged.
- // }
- CMPQ DX, $8
- JGE fixUpSlowForwardCopy
- MOVQ (R15), BX
- MOVQ BX, (DI)
- SUBQ DX, CX
- ADDQ DX, DI
- ADDQ DX, DX
- JMP makeOffsetAtLeast8
-
-fixUpSlowForwardCopy:
- // !!! Add length (which might be negative now) to d (implied by DI being
- // &dst[d]) so that d ends up at the right place when we jump back to the
- // top of the loop. Before we do that, though, we save DI to AX so that, if
- // length is positive, copying the remaining length bytes will write to the
- // right place.
- MOVQ DI, AX
- ADDQ CX, DI
-
-finishSlowForwardCopy:
- // !!! Repeat 8-byte load/stores until length <= 0. Ending with a negative
- // length means that we overrun, but as above, that will be fixed up by
- // subsequent iterations of the outermost loop.
- CMPQ CX, $0
- JLE loop
- MOVQ (R15), BX
- MOVQ BX, (AX)
- ADDQ $8, R15
- ADDQ $8, AX
- SUBQ $8, CX
- JMP finishSlowForwardCopy
-
-verySlowForwardCopy:
- // verySlowForwardCopy is a simple implementation of forward copy. In C
- // parlance, this is a do/while loop instead of a while loop, since we know
- // that length > 0. In Go syntax:
- //
- // for {
- // dst[d] = dst[d - offset]
- // d++
- // length--
- // if length == 0 {
- // break
- // }
- // }
- MOVB (R15), BX
- MOVB BX, (DI)
- INCQ R15
- INCQ DI
- DECQ CX
- JNZ verySlowForwardCopy
- JMP loop
-
-// The code above handles copy tags.
-// ----------------------------------------
-
-end:
- // This is the end of the "for s < len(src)".
- //
- // if d != len(dst) { etc }
- CMPQ DI, R10
- JNE errCorrupt
-
- // return 0
- MOVQ $0, ret+48(FP)
- RET
-
-errCorrupt:
- // return decodeErrCodeCorrupt
- MOVQ $1, ret+48(FP)
- RET
diff --git a/vendor/github.com/golang/snappy/decode_other.go b/vendor/github.com/golang/snappy/decode_other.go
deleted file mode 100644
index 8c9f2049bc7..00000000000
--- a/vendor/github.com/golang/snappy/decode_other.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2016 The Snappy-Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !amd64 appengine !gc noasm
-
-package snappy
-
-// decode writes the decoding of src to dst. It assumes that the varint-encoded
-// length of the decompressed bytes has already been read, and that len(dst)
-// equals that length.
-//
-// It returns 0 on success or a decodeErrCodeXxx error code on failure.
-func decode(dst, src []byte) int {
- var d, s, offset, length int
- for s < len(src) {
- switch src[s] & 0x03 {
- case tagLiteral:
- x := uint32(src[s] >> 2)
- switch {
- case x < 60:
- s++
- case x == 60:
- s += 2
- if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
- return decodeErrCodeCorrupt
- }
- x = uint32(src[s-1])
- case x == 61:
- s += 3
- if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
- return decodeErrCodeCorrupt
- }
- x = uint32(src[s-2]) | uint32(src[s-1])<<8
- case x == 62:
- s += 4
- if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
- return decodeErrCodeCorrupt
- }
- x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
- case x == 63:
- s += 5
- if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
- return decodeErrCodeCorrupt
- }
- x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
- }
- length = int(x) + 1
- if length <= 0 {
- return decodeErrCodeUnsupportedLiteralLength
- }
- if length > len(dst)-d || length > len(src)-s {
- return decodeErrCodeCorrupt
- }
- copy(dst[d:], src[s:s+length])
- d += length
- s += length
- continue
-
- case tagCopy1:
- s += 2
- if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
- return decodeErrCodeCorrupt
- }
- length = 4 + int(src[s-2])>>2&0x7
- offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
-
- case tagCopy2:
- s += 3
- if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
- return decodeErrCodeCorrupt
- }
- length = 1 + int(src[s-3])>>2
- offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
-
- case tagCopy4:
- s += 5
- if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
- return decodeErrCodeCorrupt
- }
- length = 1 + int(src[s-5])>>2
- offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
- }
-
- if offset <= 0 || d < offset || length > len(dst)-d {
- return decodeErrCodeCorrupt
- }
- // Copy from an earlier sub-slice of dst to a later sub-slice. Unlike
- // the built-in copy function, this byte-by-byte copy always runs
- // forwards, even if the slices overlap. Conceptually, this is:
- //
- // d += forwardCopy(dst[d:d+length], dst[d-offset:])
- for end := d + length; d != end; d++ {
- dst[d] = dst[d-offset]
- }
- }
- if d != len(dst) {
- return decodeErrCodeCorrupt
- }
- return 0
-}
diff --git a/vendor/github.com/golang/snappy/encode.go b/vendor/github.com/golang/snappy/encode.go
deleted file mode 100644
index 8d393e904bb..00000000000
--- a/vendor/github.com/golang/snappy/encode.go
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright 2011 The Snappy-Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package snappy
-
-import (
- "encoding/binary"
- "errors"
- "io"
-)
-
-// Encode returns the encoded form of src. The returned slice may be a sub-
-// slice of dst if dst was large enough to hold the entire encoded block.
-// Otherwise, a newly allocated slice will be returned.
-//
-// The dst and src must not overlap. It is valid to pass a nil dst.
-func Encode(dst, src []byte) []byte {
- if n := MaxEncodedLen(len(src)); n < 0 {
- panic(ErrTooLarge)
- } else if len(dst) < n {
- dst = make([]byte, n)
- }
-
- // The block starts with the varint-encoded length of the decompressed bytes.
- d := binary.PutUvarint(dst, uint64(len(src)))
-
- for len(src) > 0 {
- p := src
- src = nil
- if len(p) > maxBlockSize {
- p, src = p[:maxBlockSize], p[maxBlockSize:]
- }
- if len(p) < minNonLiteralBlockSize {
- d += emitLiteral(dst[d:], p)
- } else {
- d += encodeBlock(dst[d:], p)
- }
- }
- return dst[:d]
-}
-
-// inputMargin is the minimum number of extra input bytes to keep, inside
-// encodeBlock's inner loop. On some architectures, this margin lets us
-// implement a fast path for emitLiteral, where the copy of short (<= 16 byte)
-// literals can be implemented as a single load to and store from a 16-byte
-// register. That literal's actual length can be as short as 1 byte, so this
-// can copy up to 15 bytes too much, but that's OK as subsequent iterations of
-// the encoding loop will fix up the copy overrun, and this inputMargin ensures
-// that we don't overrun the dst and src buffers.
-const inputMargin = 16 - 1
-
-// minNonLiteralBlockSize is the minimum size of the input to encodeBlock that
-// could be encoded with a copy tag. This is the minimum with respect to the
-// algorithm used by encodeBlock, not a minimum enforced by the file format.
-//
-// The encoded output must start with at least a 1 byte literal, as there are
-// no previous bytes to copy. A minimal (1 byte) copy after that, generated
-// from an emitCopy call in encodeBlock's main loop, would require at least
-// another inputMargin bytes, for the reason above: we want any emitLiteral
-// calls inside encodeBlock's main loop to use the fast path if possible, which
-// requires being able to overrun by inputMargin bytes. Thus,
-// minNonLiteralBlockSize equals 1 + 1 + inputMargin.
-//
-// The C++ code doesn't use this exact threshold, but it could, as discussed at
-// https://groups.google.com/d/topic/snappy-compression/oGbhsdIJSJ8/discussion
-// The difference between Go (2+inputMargin) and C++ (inputMargin) is purely an
-// optimization. It should not affect the encoded form. This is tested by
-// TestSameEncodingAsCppShortCopies.
-const minNonLiteralBlockSize = 1 + 1 + inputMargin
-
-// MaxEncodedLen returns the maximum length of a snappy block, given its
-// uncompressed length.
-//
-// It will return a negative value if srcLen is too large to encode.
-func MaxEncodedLen(srcLen int) int {
- n := uint64(srcLen)
- if n > 0xffffffff {
- return -1
- }
- // Compressed data can be defined as:
- // compressed := item* literal*
- // item := literal* copy
- //
- // The trailing literal sequence has a space blowup of at most 62/60
- // since a literal of length 60 needs one tag byte + one extra byte
- // for length information.
- //
- // Item blowup is trickier to measure. Suppose the "copy" op copies
- // 4 bytes of data. Because of a special check in the encoding code,
- // we produce a 4-byte copy only if the offset is < 65536. Therefore
- // the copy op takes 3 bytes to encode, and this type of item leads
- // to at most the 62/60 blowup for representing literals.
- //
- // Suppose the "copy" op copies 5 bytes of data. If the offset is big
- // enough, it will take 5 bytes to encode the copy op. Therefore the
- // worst case here is a one-byte literal followed by a five-byte copy.
- // That is, 6 bytes of input turn into 7 bytes of "compressed" data.
- //
- // This last factor dominates the blowup, so the final estimate is:
- n = 32 + n + n/6
- if n > 0xffffffff {
- return -1
- }
- return int(n)
-}
-
-var errClosed = errors.New("snappy: Writer is closed")
-
-// NewWriter returns a new Writer that compresses to w.
-//
-// The Writer returned does not buffer writes. There is no need to Flush or
-// Close such a Writer.
-//
-// Deprecated: the Writer returned is not suitable for many small writes, only
-// for few large writes. Use NewBufferedWriter instead, which is efficient
-// regardless of the frequency and shape of the writes, and remember to Close
-// that Writer when done.
-func NewWriter(w io.Writer) *Writer {
- return &Writer{
- w: w,
- obuf: make([]byte, obufLen),
- }
-}
-
-// NewBufferedWriter returns a new Writer that compresses to w, using the
-// framing format described at
-// https://github.com/google/snappy/blob/master/framing_format.txt
-//
-// The Writer returned buffers writes. Users must call Close to guarantee all
-// data has been forwarded to the underlying io.Writer. They may also call
-// Flush zero or more times before calling Close.
-func NewBufferedWriter(w io.Writer) *Writer {
- return &Writer{
- w: w,
- ibuf: make([]byte, 0, maxBlockSize),
- obuf: make([]byte, obufLen),
- }
-}
-
-// Writer is an io.Writer that can write Snappy-compressed bytes.
-type Writer struct {
- w io.Writer
- err error
-
- // ibuf is a buffer for the incoming (uncompressed) bytes.
- //
- // Its use is optional. For backwards compatibility, Writers created by the
- // NewWriter function have ibuf == nil, do not buffer incoming bytes, and
- // therefore do not need to be Flush'ed or Close'd.
- ibuf []byte
-
- // obuf is a buffer for the outgoing (compressed) bytes.
- obuf []byte
-
- // wroteStreamHeader is whether we have written the stream header.
- wroteStreamHeader bool
-}
-
-// Reset discards the writer's state and switches the Snappy writer to write to
-// w. This permits reusing a Writer rather than allocating a new one.
-func (w *Writer) Reset(writer io.Writer) {
- w.w = writer
- w.err = nil
- if w.ibuf != nil {
- w.ibuf = w.ibuf[:0]
- }
- w.wroteStreamHeader = false
-}
-
-// Write satisfies the io.Writer interface.
-func (w *Writer) Write(p []byte) (nRet int, errRet error) {
- if w.ibuf == nil {
- // Do not buffer incoming bytes. This does not perform or compress well
- // if the caller of Writer.Write writes many small slices. This
- // behavior is therefore deprecated, but still supported for backwards
- // compatibility with code that doesn't explicitly Flush or Close.
- return w.write(p)
- }
-
- // The remainder of this method is based on bufio.Writer.Write from the
- // standard library.
-
- for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil {
- var n int
- if len(w.ibuf) == 0 {
- // Large write, empty buffer.
- // Write directly from p to avoid copy.
- n, _ = w.write(p)
- } else {
- n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
- w.ibuf = w.ibuf[:len(w.ibuf)+n]
- w.Flush()
- }
- nRet += n
- p = p[n:]
- }
- if w.err != nil {
- return nRet, w.err
- }
- n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
- w.ibuf = w.ibuf[:len(w.ibuf)+n]
- nRet += n
- return nRet, nil
-}
-
-func (w *Writer) write(p []byte) (nRet int, errRet error) {
- if w.err != nil {
- return 0, w.err
- }
- for len(p) > 0 {
- obufStart := len(magicChunk)
- if !w.wroteStreamHeader {
- w.wroteStreamHeader = true
- copy(w.obuf, magicChunk)
- obufStart = 0
- }
-
- var uncompressed []byte
- if len(p) > maxBlockSize {
- uncompressed, p = p[:maxBlockSize], p[maxBlockSize:]
- } else {
- uncompressed, p = p, nil
- }
- checksum := crc(uncompressed)
-
- // Compress the buffer, discarding the result if the improvement
- // isn't at least 12.5%.
- compressed := Encode(w.obuf[obufHeaderLen:], uncompressed)
- chunkType := uint8(chunkTypeCompressedData)
- chunkLen := 4 + len(compressed)
- obufEnd := obufHeaderLen + len(compressed)
- if len(compressed) >= len(uncompressed)-len(uncompressed)/8 {
- chunkType = chunkTypeUncompressedData
- chunkLen = 4 + len(uncompressed)
- obufEnd = obufHeaderLen
- }
-
- // Fill in the per-chunk header that comes before the body.
- w.obuf[len(magicChunk)+0] = chunkType
- w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0)
- w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8)
- w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16)
- w.obuf[len(magicChunk)+4] = uint8(checksum >> 0)
- w.obuf[len(magicChunk)+5] = uint8(checksum >> 8)
- w.obuf[len(magicChunk)+6] = uint8(checksum >> 16)
- w.obuf[len(magicChunk)+7] = uint8(checksum >> 24)
-
- if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil {
- w.err = err
- return nRet, err
- }
- if chunkType == chunkTypeUncompressedData {
- if _, err := w.w.Write(uncompressed); err != nil {
- w.err = err
- return nRet, err
- }
- }
- nRet += len(uncompressed)
- }
- return nRet, nil
-}
-
-// Flush flushes the Writer to its underlying io.Writer.
-func (w *Writer) Flush() error {
- if w.err != nil {
- return w.err
- }
- if len(w.ibuf) == 0 {
- return nil
- }
- w.write(w.ibuf)
- w.ibuf = w.ibuf[:0]
- return w.err
-}
-
-// Close calls Flush and then closes the Writer.
-func (w *Writer) Close() error {
- w.Flush()
- ret := w.err
- if w.err == nil {
- w.err = errClosed
- }
- return ret
-}
diff --git a/vendor/github.com/golang/snappy/encode_amd64.go b/vendor/github.com/golang/snappy/encode_amd64.go
deleted file mode 100644
index 150d91bc8be..00000000000
--- a/vendor/github.com/golang/snappy/encode_amd64.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Snappy-Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !appengine
-// +build gc
-// +build !noasm
-
-package snappy
-
-// emitLiteral has the same semantics as in encode_other.go.
-//
-//go:noescape
-func emitLiteral(dst, lit []byte) int
-
-// emitCopy has the same semantics as in encode_other.go.
-//
-//go:noescape
-func emitCopy(dst []byte, offset, length int) int
-
-// extendMatch has the same semantics as in encode_other.go.
-//
-//go:noescape
-func extendMatch(src []byte, i, j int) int
-
-// encodeBlock has the same semantics as in encode_other.go.
-//
-//go:noescape
-func encodeBlock(dst, src []byte) (d int)
diff --git a/vendor/github.com/golang/snappy/encode_amd64.s b/vendor/github.com/golang/snappy/encode_amd64.s
deleted file mode 100644
index adfd979fe27..00000000000
--- a/vendor/github.com/golang/snappy/encode_amd64.s
+++ /dev/null
@@ -1,730 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !appengine
-// +build gc
-// +build !noasm
-
-#include "textflag.h"
-
-// The XXX lines assemble on Go 1.4, 1.5 and 1.7, but not 1.6, due to a
-// Go toolchain regression. See https://github.com/golang/go/issues/15426 and
-// https://github.com/golang/snappy/issues/29
-//
-// As a workaround, the package was built with a known good assembler, and
-// those instructions were disassembled by "objdump -d" to yield the
-// 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15
-// style comments, in AT&T asm syntax. Note that rsp here is a physical
-// register, not Go/asm's SP pseudo-register (see https://golang.org/doc/asm).
-// The instructions were then encoded as "BYTE $0x.." sequences, which assemble
-// fine on Go 1.6.
-
-// The asm code generally follows the pure Go code in encode_other.go, except
-// where marked with a "!!!".
-
-// ----------------------------------------------------------------------------
-
-// func emitLiteral(dst, lit []byte) int
-//
-// All local variables fit into registers. The register allocation:
-// - AX len(lit)
-// - BX n
-// - DX return value
-// - DI &dst[i]
-// - R10 &lit[0]
-//
-// The 24 bytes of stack space is to call runtime·memmove.
-//
-// The unusual register allocation of local variables, such as R10 for the
-// source pointer, matches the allocation used at the call site in encodeBlock,
-// which makes it easier to manually inline this function.
-TEXT ·emitLiteral(SB), NOSPLIT, $24-56
- MOVQ dst_base+0(FP), DI
- MOVQ lit_base+24(FP), R10
- MOVQ lit_len+32(FP), AX
- MOVQ AX, DX
- MOVL AX, BX
- SUBL $1, BX
-
- CMPL BX, $60
- JLT oneByte
- CMPL BX, $256
- JLT twoBytes
-
-threeBytes:
- MOVB $0xf4, 0(DI)
- MOVW BX, 1(DI)
- ADDQ $3, DI
- ADDQ $3, DX
- JMP memmove
-
-twoBytes:
- MOVB $0xf0, 0(DI)
- MOVB BX, 1(DI)
- ADDQ $2, DI
- ADDQ $2, DX
- JMP memmove
-
-oneByte:
- SHLB $2, BX
- MOVB BX, 0(DI)
- ADDQ $1, DI
- ADDQ $1, DX
-
-memmove:
- MOVQ DX, ret+48(FP)
-
- // copy(dst[i:], lit)
- //
- // This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push
- // DI, R10 and AX as arguments.
- MOVQ DI, 0(SP)
- MOVQ R10, 8(SP)
- MOVQ AX, 16(SP)
- CALL runtime·memmove(SB)
- RET
-
-// ----------------------------------------------------------------------------
-
-// func emitCopy(dst []byte, offset, length int) int
-//
-// All local variables fit into registers. The register allocation:
-// - AX length
-// - SI &dst[0]
-// - DI &dst[i]
-// - R11 offset
-//
-// The unusual register allocation of local variables, such as R11 for the
-// offset, matches the allocation used at the call site in encodeBlock, which
-// makes it easier to manually inline this function.
-TEXT ·emitCopy(SB), NOSPLIT, $0-48
- MOVQ dst_base+0(FP), DI
- MOVQ DI, SI
- MOVQ offset+24(FP), R11
- MOVQ length+32(FP), AX
-
-loop0:
- // for length >= 68 { etc }
- CMPL AX, $68
- JLT step1
-
- // Emit a length 64 copy, encoded as 3 bytes.
- MOVB $0xfe, 0(DI)
- MOVW R11, 1(DI)
- ADDQ $3, DI
- SUBL $64, AX
- JMP loop0
-
-step1:
- // if length > 64 { etc }
- CMPL AX, $64
- JLE step2
-
- // Emit a length 60 copy, encoded as 3 bytes.
- MOVB $0xee, 0(DI)
- MOVW R11, 1(DI)
- ADDQ $3, DI
- SUBL $60, AX
-
-step2:
- // if length >= 12 || offset >= 2048 { goto step3 }
- CMPL AX, $12
- JGE step3
- CMPL R11, $2048
- JGE step3
-
- // Emit the remaining copy, encoded as 2 bytes.
- MOVB R11, 1(DI)
- SHRL $8, R11
- SHLB $5, R11
- SUBB $4, AX
- SHLB $2, AX
- ORB AX, R11
- ORB $1, R11
- MOVB R11, 0(DI)
- ADDQ $2, DI
-
- // Return the number of bytes written.
- SUBQ SI, DI
- MOVQ DI, ret+40(FP)
- RET
-
-step3:
- // Emit the remaining copy, encoded as 3 bytes.
- SUBL $1, AX
- SHLB $2, AX
- ORB $2, AX
- MOVB AX, 0(DI)
- MOVW R11, 1(DI)
- ADDQ $3, DI
-
- // Return the number of bytes written.
- SUBQ SI, DI
- MOVQ DI, ret+40(FP)
- RET
-
-// ----------------------------------------------------------------------------
-
-// func extendMatch(src []byte, i, j int) int
-//
-// All local variables fit into registers. The register allocation:
-// - DX &src[0]
-// - SI &src[j]
-// - R13 &src[len(src) - 8]
-// - R14 &src[len(src)]
-// - R15 &src[i]
-//
-// The unusual register allocation of local variables, such as R15 for a source
-// pointer, matches the allocation used at the call site in encodeBlock, which
-// makes it easier to manually inline this function.
-TEXT ·extendMatch(SB), NOSPLIT, $0-48
- MOVQ src_base+0(FP), DX
- MOVQ src_len+8(FP), R14
- MOVQ i+24(FP), R15
- MOVQ j+32(FP), SI
- ADDQ DX, R14
- ADDQ DX, R15
- ADDQ DX, SI
- MOVQ R14, R13
- SUBQ $8, R13
-
-cmp8:
- // As long as we are 8 or more bytes before the end of src, we can load and
- // compare 8 bytes at a time. If those 8 bytes are equal, repeat.
- CMPQ SI, R13
- JA cmp1
- MOVQ (R15), AX
- MOVQ (SI), BX
- CMPQ AX, BX
- JNE bsf
- ADDQ $8, R15
- ADDQ $8, SI
- JMP cmp8
-
-bsf:
- // If those 8 bytes were not equal, XOR the two 8 byte values, and return
- // the index of the first byte that differs. The BSF instruction finds the
- // least significant 1 bit, the amd64 architecture is little-endian, and
- // the shift by 3 converts a bit index to a byte index.
- XORQ AX, BX
- BSFQ BX, BX
- SHRQ $3, BX
- ADDQ BX, SI
-
- // Convert from &src[ret] to ret.
- SUBQ DX, SI
- MOVQ SI, ret+40(FP)
- RET
-
-cmp1:
- // In src's tail, compare 1 byte at a time.
- CMPQ SI, R14
- JAE extendMatchEnd
- MOVB (R15), AX
- MOVB (SI), BX
- CMPB AX, BX
- JNE extendMatchEnd
- ADDQ $1, R15
- ADDQ $1, SI
- JMP cmp1
-
-extendMatchEnd:
- // Convert from &src[ret] to ret.
- SUBQ DX, SI
- MOVQ SI, ret+40(FP)
- RET
-
-// ----------------------------------------------------------------------------
-
-// func encodeBlock(dst, src []byte) (d int)
-//
-// All local variables fit into registers, other than "var table". The register
-// allocation:
-// - AX . .
-// - BX . .
-// - CX 56 shift (note that amd64 shifts by non-immediates must use CX).
-// - DX 64 &src[0], tableSize
-// - SI 72 &src[s]
-// - DI 80 &dst[d]
-// - R9 88 sLimit
-// - R10 . &src[nextEmit]
-// - R11 96 prevHash, currHash, nextHash, offset
-// - R12 104 &src[base], skip
-// - R13 . &src[nextS], &src[len(src) - 8]
-// - R14 . len(src), bytesBetweenHashLookups, &src[len(src)], x
-// - R15 112 candidate
-//
-// The second column (56, 64, etc) is the stack offset to spill the registers
-// when calling other functions. We could pack this slightly tighter, but it's
-// simpler to have a dedicated spill map independent of the function called.
-//
-// "var table [maxTableSize]uint16" takes up 32768 bytes of stack space. An
-// extra 56 bytes, to call other functions, and an extra 64 bytes, to spill
-// local variables (registers) during calls gives 32768 + 56 + 64 = 32888.
-TEXT ·encodeBlock(SB), 0, $32888-56
- MOVQ dst_base+0(FP), DI
- MOVQ src_base+24(FP), SI
- MOVQ src_len+32(FP), R14
-
- // shift, tableSize := uint32(32-8), 1<<8
- MOVQ $24, CX
- MOVQ $256, DX
-
-calcShift:
- // for ; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 {
- // shift--
- // }
- CMPQ DX, $16384
- JGE varTable
- CMPQ DX, R14
- JGE varTable
- SUBQ $1, CX
- SHLQ $1, DX
- JMP calcShift
-
-varTable:
- // var table [maxTableSize]uint16
- //
- // In the asm code, unlike the Go code, we can zero-initialize only the
- // first tableSize elements. Each uint16 element is 2 bytes and each MOVOU
- // writes 16 bytes, so we can do only tableSize/8 writes instead of the
- // 2048 writes that would zero-initialize all of table's 32768 bytes.
- SHRQ $3, DX
- LEAQ table-32768(SP), BX
- PXOR X0, X0
-
-memclr:
- MOVOU X0, 0(BX)
- ADDQ $16, BX
- SUBQ $1, DX
- JNZ memclr
-
- // !!! DX = &src[0]
- MOVQ SI, DX
-
- // sLimit := len(src) - inputMargin
- MOVQ R14, R9
- SUBQ $15, R9
-
- // !!! Pre-emptively spill CX, DX and R9 to the stack. Their values don't
- // change for the rest of the function.
- MOVQ CX, 56(SP)
- MOVQ DX, 64(SP)
- MOVQ R9, 88(SP)
-
- // nextEmit := 0
- MOVQ DX, R10
-
- // s := 1
- ADDQ $1, SI
-
- // nextHash := hash(load32(src, s), shift)
- MOVL 0(SI), R11
- IMULL $0x1e35a7bd, R11
- SHRL CX, R11
-
-outer:
- // for { etc }
-
- // skip := 32
- MOVQ $32, R12
-
- // nextS := s
- MOVQ SI, R13
-
- // candidate := 0
- MOVQ $0, R15
-
-inner0:
- // for { etc }
-
- // s := nextS
- MOVQ R13, SI
-
- // bytesBetweenHashLookups := skip >> 5
- MOVQ R12, R14
- SHRQ $5, R14
-
- // nextS = s + bytesBetweenHashLookups
- ADDQ R14, R13
-
- // skip += bytesBetweenHashLookups
- ADDQ R14, R12
-
- // if nextS > sLimit { goto emitRemainder }
- MOVQ R13, AX
- SUBQ DX, AX
- CMPQ AX, R9
- JA emitRemainder
-
- // candidate = int(table[nextHash])
- // XXX: MOVWQZX table-32768(SP)(R11*2), R15
- // XXX: 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15
- BYTE $0x4e
- BYTE $0x0f
- BYTE $0xb7
- BYTE $0x7c
- BYTE $0x5c
- BYTE $0x78
-
- // table[nextHash] = uint16(s)
- MOVQ SI, AX
- SUBQ DX, AX
-
- // XXX: MOVW AX, table-32768(SP)(R11*2)
- // XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2)
- BYTE $0x66
- BYTE $0x42
- BYTE $0x89
- BYTE $0x44
- BYTE $0x5c
- BYTE $0x78
-
- // nextHash = hash(load32(src, nextS), shift)
- MOVL 0(R13), R11
- IMULL $0x1e35a7bd, R11
- SHRL CX, R11
-
- // if load32(src, s) != load32(src, candidate) { continue } break
- MOVL 0(SI), AX
- MOVL (DX)(R15*1), BX
- CMPL AX, BX
- JNE inner0
-
-fourByteMatch:
- // As per the encode_other.go code:
- //
- // A 4-byte match has been found. We'll later see etc.
-
- // !!! Jump to a fast path for short (<= 16 byte) literals. See the comment
- // on inputMargin in encode.go.
- MOVQ SI, AX
- SUBQ R10, AX
- CMPQ AX, $16
- JLE emitLiteralFastPath
-
- // ----------------------------------------
- // Begin inline of the emitLiteral call.
- //
- // d += emitLiteral(dst[d:], src[nextEmit:s])
-
- MOVL AX, BX
- SUBL $1, BX
-
- CMPL BX, $60
- JLT inlineEmitLiteralOneByte
- CMPL BX, $256
- JLT inlineEmitLiteralTwoBytes
-
-inlineEmitLiteralThreeBytes:
- MOVB $0xf4, 0(DI)
- MOVW BX, 1(DI)
- ADDQ $3, DI
- JMP inlineEmitLiteralMemmove
-
-inlineEmitLiteralTwoBytes:
- MOVB $0xf0, 0(DI)
- MOVB BX, 1(DI)
- ADDQ $2, DI
- JMP inlineEmitLiteralMemmove
-
-inlineEmitLiteralOneByte:
- SHLB $2, BX
- MOVB BX, 0(DI)
- ADDQ $1, DI
-
-inlineEmitLiteralMemmove:
- // Spill local variables (registers) onto the stack; call; unspill.
- //
- // copy(dst[i:], lit)
- //
- // This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push
- // DI, R10 and AX as arguments.
- MOVQ DI, 0(SP)
- MOVQ R10, 8(SP)
- MOVQ AX, 16(SP)
- ADDQ AX, DI // Finish the "d +=" part of "d += emitLiteral(etc)".
- MOVQ SI, 72(SP)
- MOVQ DI, 80(SP)
- MOVQ R15, 112(SP)
- CALL runtime·memmove(SB)
- MOVQ 56(SP), CX
- MOVQ 64(SP), DX
- MOVQ 72(SP), SI
- MOVQ 80(SP), DI
- MOVQ 88(SP), R9
- MOVQ 112(SP), R15
- JMP inner1
-
-inlineEmitLiteralEnd:
- // End inline of the emitLiteral call.
- // ----------------------------------------
-
-emitLiteralFastPath:
- // !!! Emit the 1-byte encoding "uint8(len(lit)-1)<<2".
- MOVB AX, BX
- SUBB $1, BX
- SHLB $2, BX
- MOVB BX, (DI)
- ADDQ $1, DI
-
- // !!! Implement the copy from lit to dst as a 16-byte load and store.
- // (Encode's documentation says that dst and src must not overlap.)
- //
- // This always copies 16 bytes, instead of only len(lit) bytes, but that's
- // OK. Subsequent iterations will fix up the overrun.
- //
- // Note that on amd64, it is legal and cheap to issue unaligned 8-byte or
- // 16-byte loads and stores. This technique probably wouldn't be as
- // effective on architectures that are fussier about alignment.
- MOVOU 0(R10), X0
- MOVOU X0, 0(DI)
- ADDQ AX, DI
-
-inner1:
- // for { etc }
-
- // base := s
- MOVQ SI, R12
-
- // !!! offset := base - candidate
- MOVQ R12, R11
- SUBQ R15, R11
- SUBQ DX, R11
-
- // ----------------------------------------
- // Begin inline of the extendMatch call.
- //
- // s = extendMatch(src, candidate+4, s+4)
-
- // !!! R14 = &src[len(src)]
- MOVQ src_len+32(FP), R14
- ADDQ DX, R14
-
- // !!! R13 = &src[len(src) - 8]
- MOVQ R14, R13
- SUBQ $8, R13
-
- // !!! R15 = &src[candidate + 4]
- ADDQ $4, R15
- ADDQ DX, R15
-
- // !!! s += 4
- ADDQ $4, SI
-
-inlineExtendMatchCmp8:
- // As long as we are 8 or more bytes before the end of src, we can load and
- // compare 8 bytes at a time. If those 8 bytes are equal, repeat.
- CMPQ SI, R13
- JA inlineExtendMatchCmp1
- MOVQ (R15), AX
- MOVQ (SI), BX
- CMPQ AX, BX
- JNE inlineExtendMatchBSF
- ADDQ $8, R15
- ADDQ $8, SI
- JMP inlineExtendMatchCmp8
-
-inlineExtendMatchBSF:
- // If those 8 bytes were not equal, XOR the two 8 byte values, and return
- // the index of the first byte that differs. The BSF instruction finds the
- // least significant 1 bit, the amd64 architecture is little-endian, and
- // the shift by 3 converts a bit index to a byte index.
- XORQ AX, BX
- BSFQ BX, BX
- SHRQ $3, BX
- ADDQ BX, SI
- JMP inlineExtendMatchEnd
-
-inlineExtendMatchCmp1:
- // In src's tail, compare 1 byte at a time.
- CMPQ SI, R14
- JAE inlineExtendMatchEnd
- MOVB (R15), AX
- MOVB (SI), BX
- CMPB AX, BX
- JNE inlineExtendMatchEnd
- ADDQ $1, R15
- ADDQ $1, SI
- JMP inlineExtendMatchCmp1
-
-inlineExtendMatchEnd:
- // End inline of the extendMatch call.
- // ----------------------------------------
-
- // ----------------------------------------
- // Begin inline of the emitCopy call.
- //
- // d += emitCopy(dst[d:], base-candidate, s-base)
-
- // !!! length := s - base
- MOVQ SI, AX
- SUBQ R12, AX
-
-inlineEmitCopyLoop0:
- // for length >= 68 { etc }
- CMPL AX, $68
- JLT inlineEmitCopyStep1
-
- // Emit a length 64 copy, encoded as 3 bytes.
- MOVB $0xfe, 0(DI)
- MOVW R11, 1(DI)
- ADDQ $3, DI
- SUBL $64, AX
- JMP inlineEmitCopyLoop0
-
-inlineEmitCopyStep1:
- // if length > 64 { etc }
- CMPL AX, $64
- JLE inlineEmitCopyStep2
-
- // Emit a length 60 copy, encoded as 3 bytes.
- MOVB $0xee, 0(DI)
- MOVW R11, 1(DI)
- ADDQ $3, DI
- SUBL $60, AX
-
-inlineEmitCopyStep2:
- // if length >= 12 || offset >= 2048 { goto inlineEmitCopyStep3 }
- CMPL AX, $12
- JGE inlineEmitCopyStep3
- CMPL R11, $2048
- JGE inlineEmitCopyStep3
-
- // Emit the remaining copy, encoded as 2 bytes.
- MOVB R11, 1(DI)
- SHRL $8, R11
- SHLB $5, R11
- SUBB $4, AX
- SHLB $2, AX
- ORB AX, R11
- ORB $1, R11
- MOVB R11, 0(DI)
- ADDQ $2, DI
- JMP inlineEmitCopyEnd
-
-inlineEmitCopyStep3:
- // Emit the remaining copy, encoded as 3 bytes.
- SUBL $1, AX
- SHLB $2, AX
- ORB $2, AX
- MOVB AX, 0(DI)
- MOVW R11, 1(DI)
- ADDQ $3, DI
-
-inlineEmitCopyEnd:
- // End inline of the emitCopy call.
- // ----------------------------------------
-
- // nextEmit = s
- MOVQ SI, R10
-
- // if s >= sLimit { goto emitRemainder }
- MOVQ SI, AX
- SUBQ DX, AX
- CMPQ AX, R9
- JAE emitRemainder
-
- // As per the encode_other.go code:
- //
- // We could immediately etc.
-
- // x := load64(src, s-1)
- MOVQ -1(SI), R14
-
- // prevHash := hash(uint32(x>>0), shift)
- MOVL R14, R11
- IMULL $0x1e35a7bd, R11
- SHRL CX, R11
-
- // table[prevHash] = uint16(s-1)
- MOVQ SI, AX
- SUBQ DX, AX
- SUBQ $1, AX
-
- // XXX: MOVW AX, table-32768(SP)(R11*2)
- // XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2)
- BYTE $0x66
- BYTE $0x42
- BYTE $0x89
- BYTE $0x44
- BYTE $0x5c
- BYTE $0x78
-
- // currHash := hash(uint32(x>>8), shift)
- SHRQ $8, R14
- MOVL R14, R11
- IMULL $0x1e35a7bd, R11
- SHRL CX, R11
-
- // candidate = int(table[currHash])
- // XXX: MOVWQZX table-32768(SP)(R11*2), R15
- // XXX: 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15
- BYTE $0x4e
- BYTE $0x0f
- BYTE $0xb7
- BYTE $0x7c
- BYTE $0x5c
- BYTE $0x78
-
- // table[currHash] = uint16(s)
- ADDQ $1, AX
-
- // XXX: MOVW AX, table-32768(SP)(R11*2)
- // XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2)
- BYTE $0x66
- BYTE $0x42
- BYTE $0x89
- BYTE $0x44
- BYTE $0x5c
- BYTE $0x78
-
- // if uint32(x>>8) == load32(src, candidate) { continue }
- MOVL (DX)(R15*1), BX
- CMPL R14, BX
- JEQ inner1
-
- // nextHash = hash(uint32(x>>16), shift)
- SHRQ $8, R14
- MOVL R14, R11
- IMULL $0x1e35a7bd, R11
- SHRL CX, R11
-
- // s++
- ADDQ $1, SI
-
- // break out of the inner1 for loop, i.e. continue the outer loop.
- JMP outer
-
-emitRemainder:
- // if nextEmit < len(src) { etc }
- MOVQ src_len+32(FP), AX
- ADDQ DX, AX
- CMPQ R10, AX
- JEQ encodeBlockEnd
-
- // d += emitLiteral(dst[d:], src[nextEmit:])
- //
- // Push args.
- MOVQ DI, 0(SP)
- MOVQ $0, 8(SP) // Unnecessary, as the callee ignores it, but conservative.
- MOVQ $0, 16(SP) // Unnecessary, as the callee ignores it, but conservative.
- MOVQ R10, 24(SP)
- SUBQ R10, AX
- MOVQ AX, 32(SP)
- MOVQ AX, 40(SP) // Unnecessary, as the callee ignores it, but conservative.
-
- // Spill local variables (registers) onto the stack; call; unspill.
- MOVQ DI, 80(SP)
- CALL ·emitLiteral(SB)
- MOVQ 80(SP), DI
-
- // Finish the "d +=" part of "d += emitLiteral(etc)".
- ADDQ 48(SP), DI
-
-encodeBlockEnd:
- MOVQ dst_base+0(FP), AX
- SUBQ AX, DI
- MOVQ DI, d+48(FP)
- RET
diff --git a/vendor/github.com/golang/snappy/encode_other.go b/vendor/github.com/golang/snappy/encode_other.go
deleted file mode 100644
index dbcae905e6e..00000000000
--- a/vendor/github.com/golang/snappy/encode_other.go
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2016 The Snappy-Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !amd64 appengine !gc noasm
-
-package snappy
-
-func load32(b []byte, i int) uint32 {
- b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line.
- return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
-}
-
-func load64(b []byte, i int) uint64 {
- b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line.
- return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
- uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
-}
-
-// emitLiteral writes a literal chunk and returns the number of bytes written.
-//
-// It assumes that:
-// dst is long enough to hold the encoded bytes
-// 1 <= len(lit) && len(lit) <= 65536
-func emitLiteral(dst, lit []byte) int {
- i, n := 0, uint(len(lit)-1)
- switch {
- case n < 60:
- dst[0] = uint8(n)<<2 | tagLiteral
- i = 1
- case n < 1<<8:
- dst[0] = 60<<2 | tagLiteral
- dst[1] = uint8(n)
- i = 2
- default:
- dst[0] = 61<<2 | tagLiteral
- dst[1] = uint8(n)
- dst[2] = uint8(n >> 8)
- i = 3
- }
- return i + copy(dst[i:], lit)
-}
-
-// emitCopy writes a copy chunk and returns the number of bytes written.
-//
-// It assumes that:
-// dst is long enough to hold the encoded bytes
-// 1 <= offset && offset <= 65535
-// 4 <= length && length <= 65535
-func emitCopy(dst []byte, offset, length int) int {
- i := 0
- // The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The
- // threshold for this loop is a little higher (at 68 = 64 + 4), and the
- // length emitted down below is is a little lower (at 60 = 64 - 4), because
- // it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed
- // by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as
- // a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as
- // 3+3 bytes). The magic 4 in the 64±4 is because the minimum length for a
- // tagCopy1 op is 4 bytes, which is why a length 3 copy has to be an
- // encodes-as-3-bytes tagCopy2 instead of an encodes-as-2-bytes tagCopy1.
- for length >= 68 {
- // Emit a length 64 copy, encoded as 3 bytes.
- dst[i+0] = 63<<2 | tagCopy2
- dst[i+1] = uint8(offset)
- dst[i+2] = uint8(offset >> 8)
- i += 3
- length -= 64
- }
- if length > 64 {
- // Emit a length 60 copy, encoded as 3 bytes.
- dst[i+0] = 59<<2 | tagCopy2
- dst[i+1] = uint8(offset)
- dst[i+2] = uint8(offset >> 8)
- i += 3
- length -= 60
- }
- if length >= 12 || offset >= 2048 {
- // Emit the remaining copy, encoded as 3 bytes.
- dst[i+0] = uint8(length-1)<<2 | tagCopy2
- dst[i+1] = uint8(offset)
- dst[i+2] = uint8(offset >> 8)
- return i + 3
- }
- // Emit the remaining copy, encoded as 2 bytes.
- dst[i+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
- dst[i+1] = uint8(offset)
- return i + 2
-}
-
-// extendMatch returns the largest k such that k <= len(src) and that
-// src[i:i+k-j] and src[j:k] have the same contents.
-//
-// It assumes that:
-// 0 <= i && i < j && j <= len(src)
-func extendMatch(src []byte, i, j int) int {
- for ; j < len(src) && src[i] == src[j]; i, j = i+1, j+1 {
- }
- return j
-}
-
-func hash(u, shift uint32) uint32 {
- return (u * 0x1e35a7bd) >> shift
-}
-
-// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It
-// assumes that the varint-encoded length of the decompressed bytes has already
-// been written.
-//
-// It also assumes that:
-// len(dst) >= MaxEncodedLen(len(src)) &&
-// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
-func encodeBlock(dst, src []byte) (d int) {
- // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive.
- // The table element type is uint16, as s < sLimit and sLimit < len(src)
- // and len(src) <= maxBlockSize and maxBlockSize == 65536.
- const (
- maxTableSize = 1 << 14
- // tableMask is redundant, but helps the compiler eliminate bounds
- // checks.
- tableMask = maxTableSize - 1
- )
- shift := uint32(32 - 8)
- for tableSize := 1 << 8; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 {
- shift--
- }
- // In Go, all array elements are zero-initialized, so there is no advantage
- // to a smaller tableSize per se. However, it matches the C++ algorithm,
- // and in the asm versions of this code, we can get away with zeroing only
- // the first tableSize elements.
- var table [maxTableSize]uint16
-
- // sLimit is when to stop looking for offset/length copies. The inputMargin
- // lets us use a fast path for emitLiteral in the main loop, while we are
- // looking for copies.
- sLimit := len(src) - inputMargin
-
- // nextEmit is where in src the next emitLiteral should start from.
- nextEmit := 0
-
- // The encoded form must start with a literal, as there are no previous
- // bytes to copy, so we start looking for hash matches at s == 1.
- s := 1
- nextHash := hash(load32(src, s), shift)
-
- for {
- // Copied from the C++ snappy implementation:
- //
- // Heuristic match skipping: If 32 bytes are scanned with no matches
- // found, start looking only at every other byte. If 32 more bytes are
- // scanned (or skipped), look at every third byte, etc.. When a match
- // is found, immediately go back to looking at every byte. This is a
- // small loss (~5% performance, ~0.1% density) for compressible data
- // due to more bookkeeping, but for non-compressible data (such as
- // JPEG) it's a huge win since the compressor quickly "realizes" the
- // data is incompressible and doesn't bother looking for matches
- // everywhere.
- //
- // The "skip" variable keeps track of how many bytes there are since
- // the last match; dividing it by 32 (ie. right-shifting by five) gives
- // the number of bytes to move ahead for each iteration.
- skip := 32
-
- nextS := s
- candidate := 0
- for {
- s = nextS
- bytesBetweenHashLookups := skip >> 5
- nextS = s + bytesBetweenHashLookups
- skip += bytesBetweenHashLookups
- if nextS > sLimit {
- goto emitRemainder
- }
- candidate = int(table[nextHash&tableMask])
- table[nextHash&tableMask] = uint16(s)
- nextHash = hash(load32(src, nextS), shift)
- if load32(src, s) == load32(src, candidate) {
- break
- }
- }
-
- // A 4-byte match has been found. We'll later see if more than 4 bytes
- // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
- // them as literal bytes.
- d += emitLiteral(dst[d:], src[nextEmit:s])
-
- // Call emitCopy, and then see if another emitCopy could be our next
- // move. Repeat until we find no match for the input immediately after
- // what was consumed by the last emitCopy call.
- //
- // If we exit this loop normally then we need to call emitLiteral next,
- // though we don't yet know how big the literal will be. We handle that
- // by proceeding to the next iteration of the main loop. We also can
- // exit this loop via goto if we get close to exhausting the input.
- for {
- // Invariant: we have a 4-byte match at s, and no need to emit any
- // literal bytes prior to s.
- base := s
-
- // Extend the 4-byte match as long as possible.
- //
- // This is an inlined version of:
- // s = extendMatch(src, candidate+4, s+4)
- s += 4
- for i := candidate + 4; s < len(src) && src[i] == src[s]; i, s = i+1, s+1 {
- }
-
- d += emitCopy(dst[d:], base-candidate, s-base)
- nextEmit = s
- if s >= sLimit {
- goto emitRemainder
- }
-
- // We could immediately start working at s now, but to improve
- // compression we first update the hash table at s-1 and at s. If
- // another emitCopy is not our next move, also calculate nextHash
- // at s+1. At least on GOARCH=amd64, these three hash calculations
- // are faster as one load64 call (with some shifts) instead of
- // three load32 calls.
- x := load64(src, s-1)
- prevHash := hash(uint32(x>>0), shift)
- table[prevHash&tableMask] = uint16(s - 1)
- currHash := hash(uint32(x>>8), shift)
- candidate = int(table[currHash&tableMask])
- table[currHash&tableMask] = uint16(s)
- if uint32(x>>8) != load32(src, candidate) {
- nextHash = hash(uint32(x>>16), shift)
- s++
- break
- }
- }
- }
-
-emitRemainder:
- if nextEmit < len(src) {
- d += emitLiteral(dst[d:], src[nextEmit:])
- }
- return d
-}
diff --git a/vendor/github.com/golang/snappy/go.mod b/vendor/github.com/golang/snappy/go.mod
deleted file mode 100644
index f6406bb2c76..00000000000
--- a/vendor/github.com/golang/snappy/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/golang/snappy
diff --git a/vendor/github.com/golang/snappy/snappy.go b/vendor/github.com/golang/snappy/snappy.go
deleted file mode 100644
index ece692ea461..00000000000
--- a/vendor/github.com/golang/snappy/snappy.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2011 The Snappy-Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package snappy implements the Snappy compression format. It aims for very
-// high speeds and reasonable compression.
-//
-// There are actually two Snappy formats: block and stream. They are related,
-// but different: trying to decompress block-compressed data as a Snappy stream
-// will fail, and vice versa. The block format is the Decode and Encode
-// functions and the stream format is the Reader and Writer types.
-//
-// The block format, the more common case, is used when the complete size (the
-// number of bytes) of the original data is known upfront, at the time
-// compression starts. The stream format, also known as the framing format, is
-// for when that isn't always true.
-//
-// The canonical, C++ implementation is at https://github.com/google/snappy and
-// it only implements the block format.
-package snappy // import "github.com/golang/snappy"
-
-import (
- "hash/crc32"
-)
-
-/*
-Each encoded block begins with the varint-encoded length of the decoded data,
-followed by a sequence of chunks. Chunks begin and end on byte boundaries. The
-first byte of each chunk is broken into its 2 least and 6 most significant bits
-called l and m: l ranges in [0, 4) and m ranges in [0, 64). l is the chunk tag.
-Zero means a literal tag. All other values mean a copy tag.
-
-For literal tags:
- - If m < 60, the next 1 + m bytes are literal bytes.
- - Otherwise, let n be the little-endian unsigned integer denoted by the next
- m - 59 bytes. The next 1 + n bytes after that are literal bytes.
-
-For copy tags, length bytes are copied from offset bytes ago, in the style of
-Lempel-Ziv compression algorithms. In particular:
- - For l == 1, the offset ranges in [0, 1<<11) and the length in [4, 12).
- The length is 4 + the low 3 bits of m. The high 3 bits of m form bits 8-10
- of the offset. The next byte is bits 0-7 of the offset.
- - For l == 2, the offset ranges in [0, 1<<16) and the length in [1, 65).
- The length is 1 + m. The offset is the little-endian unsigned integer
- denoted by the next 2 bytes.
- - For l == 3, this tag is a legacy format that is no longer issued by most
- encoders. Nonetheless, the offset ranges in [0, 1<<32) and the length in
- [1, 65). The length is 1 + m. The offset is the little-endian unsigned
- integer denoted by the next 4 bytes.
-*/
-const (
- tagLiteral = 0x00
- tagCopy1 = 0x01
- tagCopy2 = 0x02
- tagCopy4 = 0x03
-)
-
-const (
- checksumSize = 4
- chunkHeaderSize = 4
- magicChunk = "\xff\x06\x00\x00" + magicBody
- magicBody = "sNaPpY"
-
- // maxBlockSize is the maximum size of the input to encodeBlock. It is not
- // part of the wire format per se, but some parts of the encoder assume
- // that an offset fits into a uint16.
- //
- // Also, for the framing format (Writer type instead of Encode function),
- // https://github.com/google/snappy/blob/master/framing_format.txt says
- // that "the uncompressed data in a chunk must be no longer than 65536
- // bytes".
- maxBlockSize = 65536
-
- // maxEncodedLenOfMaxBlockSize equals MaxEncodedLen(maxBlockSize), but is
- // hard coded to be a const instead of a variable, so that obufLen can also
- // be a const. Their equivalence is confirmed by
- // TestMaxEncodedLenOfMaxBlockSize.
- maxEncodedLenOfMaxBlockSize = 76490
-
- obufHeaderLen = len(magicChunk) + checksumSize + chunkHeaderSize
- obufLen = obufHeaderLen + maxEncodedLenOfMaxBlockSize
-)
-
-const (
- chunkTypeCompressedData = 0x00
- chunkTypeUncompressedData = 0x01
- chunkTypePadding = 0xfe
- chunkTypeStreamIdentifier = 0xff
-)
-
-var crcTable = crc32.MakeTable(crc32.Castagnoli)
-
-// crc implements the checksum specified in section 3 of
-// https://github.com/google/snappy/blob/master/framing_format.txt
-func crc(b []byte) uint32 {
- c := crc32.Update(0, crcTable, b)
- return uint32(c>>15|c<<17) + 0xa282ead8
-}
diff --git a/vendor/github.com/google/uuid/.travis.yml b/vendor/github.com/google/uuid/.travis.yml
deleted file mode 100644
index d8156a60ba9..00000000000
--- a/vendor/github.com/google/uuid/.travis.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-language: go
-
-go:
- - 1.4.3
- - 1.5.3
- - tip
-
-script:
- - go test -v ./...
diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md
deleted file mode 100644
index 04fdf09f136..00000000000
--- a/vendor/github.com/google/uuid/CONTRIBUTING.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# How to contribute
-
-We definitely welcome patches and contribution to this project!
-
-### Legal requirements
-
-In order to protect both you and ourselves, you will need to sign the
-[Contributor License Agreement](https://cla.developers.google.com/clas).
-
-You may have already signed it for other Google projects.
diff --git a/vendor/github.com/google/uuid/CONTRIBUTORS b/vendor/github.com/google/uuid/CONTRIBUTORS
deleted file mode 100644
index b4bb97f6bcd..00000000000
--- a/vendor/github.com/google/uuid/CONTRIBUTORS
+++ /dev/null
@@ -1,9 +0,0 @@
-Paul Borman
-bmatsuo
-shawnps
-theory
-jboverfelt
-dsymonds
-cd1
-wallclockbuilder
-dansouza
diff --git a/vendor/github.com/google/uuid/LICENSE b/vendor/github.com/google/uuid/LICENSE
deleted file mode 100644
index 5dc68268d90..00000000000
--- a/vendor/github.com/google/uuid/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2009,2014 Google Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/google/uuid/README.md b/vendor/github.com/google/uuid/README.md
deleted file mode 100644
index 9d92c11f16f..00000000000
--- a/vendor/github.com/google/uuid/README.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master)
-The uuid package generates and inspects UUIDs based on
-[RFC 4122](http://tools.ietf.org/html/rfc4122)
-and DCE 1.1: Authentication and Security Services.
-
-This package is based on the github.com/pborman/uuid package (previously named
-code.google.com/p/go-uuid). It differs from these earlier packages in that
-a UUID is a 16 byte array rather than a byte slice. One loss due to this
-change is the ability to represent an invalid UUID (vs a NIL UUID).
-
-###### Install
-`go get github.com/google/uuid`
-
-###### Documentation
-[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid)
-
-Full `go doc` style documentation for the package can be viewed online without
-installing this package by using the GoDoc site here:
-http://godoc.org/github.com/google/uuid
diff --git a/vendor/github.com/google/uuid/dce.go b/vendor/github.com/google/uuid/dce.go
deleted file mode 100644
index fa820b9d309..00000000000
--- a/vendor/github.com/google/uuid/dce.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "encoding/binary"
- "fmt"
- "os"
-)
-
-// A Domain represents a Version 2 domain
-type Domain byte
-
-// Domain constants for DCE Security (Version 2) UUIDs.
-const (
- Person = Domain(0)
- Group = Domain(1)
- Org = Domain(2)
-)
-
-// NewDCESecurity returns a DCE Security (Version 2) UUID.
-//
-// The domain should be one of Person, Group or Org.
-// On a POSIX system the id should be the users UID for the Person
-// domain and the users GID for the Group. The meaning of id for
-// the domain Org or on non-POSIX systems is site defined.
-//
-// For a given domain/id pair the same token may be returned for up to
-// 7 minutes and 10 seconds.
-func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
- uuid, err := NewUUID()
- if err == nil {
- uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
- uuid[9] = byte(domain)
- binary.BigEndian.PutUint32(uuid[0:], id)
- }
- return uuid, err
-}
-
-// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
-// domain with the id returned by os.Getuid.
-//
-// NewDCESecurity(Person, uint32(os.Getuid()))
-func NewDCEPerson() (UUID, error) {
- return NewDCESecurity(Person, uint32(os.Getuid()))
-}
-
-// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
-// domain with the id returned by os.Getgid.
-//
-// NewDCESecurity(Group, uint32(os.Getgid()))
-func NewDCEGroup() (UUID, error) {
- return NewDCESecurity(Group, uint32(os.Getgid()))
-}
-
-// Domain returns the domain for a Version 2 UUID. Domains are only defined
-// for Version 2 UUIDs.
-func (uuid UUID) Domain() Domain {
- return Domain(uuid[9])
-}
-
-// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
-// UUIDs.
-func (uuid UUID) ID() uint32 {
- return binary.BigEndian.Uint32(uuid[0:4])
-}
-
-func (d Domain) String() string {
- switch d {
- case Person:
- return "Person"
- case Group:
- return "Group"
- case Org:
- return "Org"
- }
- return fmt.Sprintf("Domain%d", int(d))
-}
diff --git a/vendor/github.com/google/uuid/doc.go b/vendor/github.com/google/uuid/doc.go
deleted file mode 100644
index 5b8a4b9af8c..00000000000
--- a/vendor/github.com/google/uuid/doc.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package uuid generates and inspects UUIDs.
-//
-// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
-// Services.
-//
-// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
-// maps or compared directly.
-package uuid
diff --git a/vendor/github.com/google/uuid/go.mod b/vendor/github.com/google/uuid/go.mod
deleted file mode 100644
index fc84cd79d4c..00000000000
--- a/vendor/github.com/google/uuid/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/google/uuid
diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go
deleted file mode 100644
index b1746163151..00000000000
--- a/vendor/github.com/google/uuid/hash.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "crypto/md5"
- "crypto/sha1"
- "hash"
-)
-
-// Well known namespace IDs and UUIDs
-var (
- NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
- NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
- NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
- NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
- Nil UUID // empty UUID, all zeros
-)
-
-// NewHash returns a new UUID derived from the hash of space concatenated with
-// data generated by h. The hash should be at least 16 byte in length. The
-// first 16 bytes of the hash are used to form the UUID. The version of the
-// UUID will be the lower 4 bits of version. NewHash is used to implement
-// NewMD5 and NewSHA1.
-func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
- h.Reset()
- h.Write(space[:])
- h.Write(data)
- s := h.Sum(nil)
- var uuid UUID
- copy(uuid[:], s)
- uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
- uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
- return uuid
-}
-
-// NewMD5 returns a new MD5 (Version 3) UUID based on the
-// supplied name space and data. It is the same as calling:
-//
-// NewHash(md5.New(), space, data, 3)
-func NewMD5(space UUID, data []byte) UUID {
- return NewHash(md5.New(), space, data, 3)
-}
-
-// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
-// supplied name space and data. It is the same as calling:
-//
-// NewHash(sha1.New(), space, data, 5)
-func NewSHA1(space UUID, data []byte) UUID {
- return NewHash(sha1.New(), space, data, 5)
-}
diff --git a/vendor/github.com/google/uuid/marshal.go b/vendor/github.com/google/uuid/marshal.go
deleted file mode 100644
index 7f9e0c6c0e3..00000000000
--- a/vendor/github.com/google/uuid/marshal.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import "fmt"
-
-// MarshalText implements encoding.TextMarshaler.
-func (uuid UUID) MarshalText() ([]byte, error) {
- var js [36]byte
- encodeHex(js[:], uuid)
- return js[:], nil
-}
-
-// UnmarshalText implements encoding.TextUnmarshaler.
-func (uuid *UUID) UnmarshalText(data []byte) error {
- id, err := ParseBytes(data)
- if err == nil {
- *uuid = id
- }
- return err
-}
-
-// MarshalBinary implements encoding.BinaryMarshaler.
-func (uuid UUID) MarshalBinary() ([]byte, error) {
- return uuid[:], nil
-}
-
-// UnmarshalBinary implements encoding.BinaryUnmarshaler.
-func (uuid *UUID) UnmarshalBinary(data []byte) error {
- if len(data) != 16 {
- return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
- }
- copy(uuid[:], data)
- return nil
-}
diff --git a/vendor/github.com/google/uuid/node.go b/vendor/github.com/google/uuid/node.go
deleted file mode 100644
index d651a2b0619..00000000000
--- a/vendor/github.com/google/uuid/node.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "sync"
-)
-
-var (
- nodeMu sync.Mutex
- ifname string // name of interface being used
- nodeID [6]byte // hardware for version 1 UUIDs
- zeroID [6]byte // nodeID with only 0's
-)
-
-// NodeInterface returns the name of the interface from which the NodeID was
-// derived. The interface "user" is returned if the NodeID was set by
-// SetNodeID.
-func NodeInterface() string {
- defer nodeMu.Unlock()
- nodeMu.Lock()
- return ifname
-}
-
-// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
-// If name is "" then the first usable interface found will be used or a random
-// Node ID will be generated. If a named interface cannot be found then false
-// is returned.
-//
-// SetNodeInterface never fails when name is "".
-func SetNodeInterface(name string) bool {
- defer nodeMu.Unlock()
- nodeMu.Lock()
- return setNodeInterface(name)
-}
-
-func setNodeInterface(name string) bool {
- iname, addr := getHardwareInterface(name) // null implementation for js
- if iname != "" && addr != nil {
- ifname = iname
- copy(nodeID[:], addr)
- return true
- }
-
- // We found no interfaces with a valid hardware address. If name
- // does not specify a specific interface generate a random Node ID
- // (section 4.1.6)
- if name == "" {
- ifname = "random"
- randomBits(nodeID[:])
- return true
- }
- return false
-}
-
-// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
-// if not already set.
-func NodeID() []byte {
- defer nodeMu.Unlock()
- nodeMu.Lock()
- if nodeID == zeroID {
- setNodeInterface("")
- }
- nid := nodeID
- return nid[:]
-}
-
-// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
-// of id are used. If id is less than 6 bytes then false is returned and the
-// Node ID is not set.
-func SetNodeID(id []byte) bool {
- if len(id) < 6 {
- return false
- }
- defer nodeMu.Unlock()
- nodeMu.Lock()
- copy(nodeID[:], id)
- ifname = "user"
- return true
-}
-
-// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
-// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
-func (uuid UUID) NodeID() []byte {
- var node [6]byte
- copy(node[:], uuid[10:])
- return node[:]
-}
diff --git a/vendor/github.com/google/uuid/node_js.go b/vendor/github.com/google/uuid/node_js.go
deleted file mode 100644
index 24b78edc907..00000000000
--- a/vendor/github.com/google/uuid/node_js.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2017 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build js
-
-package uuid
-
-// getHardwareInterface returns nil values for the JS version of the code.
-// This remvoves the "net" dependency, because it is not used in the browser.
-// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
-func getHardwareInterface(name string) (string, []byte) { return "", nil }
diff --git a/vendor/github.com/google/uuid/node_net.go b/vendor/github.com/google/uuid/node_net.go
deleted file mode 100644
index 0cbbcddbd6e..00000000000
--- a/vendor/github.com/google/uuid/node_net.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2017 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !js
-
-package uuid
-
-import "net"
-
-var interfaces []net.Interface // cached list of interfaces
-
-// getHardwareInterface returns the name and hardware address of interface name.
-// If name is "" then the name and hardware address of one of the system's
-// interfaces is returned. If no interfaces are found (name does not exist or
-// there are no interfaces) then "", nil is returned.
-//
-// Only addresses of at least 6 bytes are returned.
-func getHardwareInterface(name string) (string, []byte) {
- if interfaces == nil {
- var err error
- interfaces, err = net.Interfaces()
- if err != nil {
- return "", nil
- }
- }
- for _, ifs := range interfaces {
- if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
- return ifs.Name, ifs.HardwareAddr
- }
- }
- return "", nil
-}
diff --git a/vendor/github.com/google/uuid/sql.go b/vendor/github.com/google/uuid/sql.go
deleted file mode 100644
index f326b54db37..00000000000
--- a/vendor/github.com/google/uuid/sql.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "database/sql/driver"
- "fmt"
-)
-
-// Scan implements sql.Scanner so UUIDs can be read from databases transparently
-// Currently, database types that map to string and []byte are supported. Please
-// consult database-specific driver documentation for matching types.
-func (uuid *UUID) Scan(src interface{}) error {
- switch src := src.(type) {
- case nil:
- return nil
-
- case string:
- // if an empty UUID comes from a table, we return a null UUID
- if src == "" {
- return nil
- }
-
- // see Parse for required string format
- u, err := Parse(src)
- if err != nil {
- return fmt.Errorf("Scan: %v", err)
- }
-
- *uuid = u
-
- case []byte:
- // if an empty UUID comes from a table, we return a null UUID
- if len(src) == 0 {
- return nil
- }
-
- // assumes a simple slice of bytes if 16 bytes
- // otherwise attempts to parse
- if len(src) != 16 {
- return uuid.Scan(string(src))
- }
- copy((*uuid)[:], src)
-
- default:
- return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
- }
-
- return nil
-}
-
-// Value implements sql.Valuer so that UUIDs can be written to databases
-// transparently. Currently, UUIDs map to strings. Please consult
-// database-specific driver documentation for matching types.
-func (uuid UUID) Value() (driver.Value, error) {
- return uuid.String(), nil
-}
diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go
deleted file mode 100644
index e6ef06cdc87..00000000000
--- a/vendor/github.com/google/uuid/time.go
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "encoding/binary"
- "sync"
- "time"
-)
-
-// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
-// 1582.
-type Time int64
-
-const (
- lillian = 2299160 // Julian day of 15 Oct 1582
- unix = 2440587 // Julian day of 1 Jan 1970
- epoch = unix - lillian // Days between epochs
- g1582 = epoch * 86400 // seconds between epochs
- g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
-)
-
-var (
- timeMu sync.Mutex
- lasttime uint64 // last time we returned
- clockSeq uint16 // clock sequence for this run
-
- timeNow = time.Now // for testing
-)
-
-// UnixTime converts t the number of seconds and nanoseconds using the Unix
-// epoch of 1 Jan 1970.
-func (t Time) UnixTime() (sec, nsec int64) {
- sec = int64(t - g1582ns100)
- nsec = (sec % 10000000) * 100
- sec /= 10000000
- return sec, nsec
-}
-
-// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
-// clock sequence as well as adjusting the clock sequence as needed. An error
-// is returned if the current time cannot be determined.
-func GetTime() (Time, uint16, error) {
- defer timeMu.Unlock()
- timeMu.Lock()
- return getTime()
-}
-
-func getTime() (Time, uint16, error) {
- t := timeNow()
-
- // If we don't have a clock sequence already, set one.
- if clockSeq == 0 {
- setClockSequence(-1)
- }
- now := uint64(t.UnixNano()/100) + g1582ns100
-
- // If time has gone backwards with this clock sequence then we
- // increment the clock sequence
- if now <= lasttime {
- clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
- }
- lasttime = now
- return Time(now), clockSeq, nil
-}
-
-// ClockSequence returns the current clock sequence, generating one if not
-// already set. The clock sequence is only used for Version 1 UUIDs.
-//
-// The uuid package does not use global static storage for the clock sequence or
-// the last time a UUID was generated. Unless SetClockSequence is used, a new
-// random clock sequence is generated the first time a clock sequence is
-// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
-func ClockSequence() int {
- defer timeMu.Unlock()
- timeMu.Lock()
- return clockSequence()
-}
-
-func clockSequence() int {
- if clockSeq == 0 {
- setClockSequence(-1)
- }
- return int(clockSeq & 0x3fff)
-}
-
-// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
-// -1 causes a new sequence to be generated.
-func SetClockSequence(seq int) {
- defer timeMu.Unlock()
- timeMu.Lock()
- setClockSequence(seq)
-}
-
-func setClockSequence(seq int) {
- if seq == -1 {
- var b [2]byte
- randomBits(b[:]) // clock sequence
- seq = int(b[0])<<8 | int(b[1])
- }
- oldSeq := clockSeq
- clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
- if oldSeq != clockSeq {
- lasttime = 0
- }
-}
-
-// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
-// uuid. The time is only defined for version 1 and 2 UUIDs.
-func (uuid UUID) Time() Time {
- time := int64(binary.BigEndian.Uint32(uuid[0:4]))
- time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
- time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
- return Time(time)
-}
-
-// ClockSequence returns the clock sequence encoded in uuid.
-// The clock sequence is only well defined for version 1 and 2 UUIDs.
-func (uuid UUID) ClockSequence() int {
- return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
-}
diff --git a/vendor/github.com/google/uuid/util.go b/vendor/github.com/google/uuid/util.go
deleted file mode 100644
index 5ea6c737806..00000000000
--- a/vendor/github.com/google/uuid/util.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "io"
-)
-
-// randomBits completely fills slice b with random data.
-func randomBits(b []byte) {
- if _, err := io.ReadFull(rander, b); err != nil {
- panic(err.Error()) // rand should never fail
- }
-}
-
-// xvalues returns the value of a byte as a hexadecimal digit or 255.
-var xvalues = [256]byte{
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
- 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-}
-
-// xtob converts hex characters x1 and x2 into a byte.
-func xtob(x1, x2 byte) (byte, bool) {
- b1 := xvalues[x1]
- b2 := xvalues[x2]
- return (b1 << 4) | b2, b1 != 255 && b2 != 255
-}
diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go
deleted file mode 100644
index 524404cc522..00000000000
--- a/vendor/github.com/google/uuid/uuid.go
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright 2018 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "bytes"
- "crypto/rand"
- "encoding/hex"
- "errors"
- "fmt"
- "io"
- "strings"
-)
-
-// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
-// 4122.
-type UUID [16]byte
-
-// A Version represents a UUID's version.
-type Version byte
-
-// A Variant represents a UUID's variant.
-type Variant byte
-
-// Constants returned by Variant.
-const (
- Invalid = Variant(iota) // Invalid UUID
- RFC4122 // The variant specified in RFC4122
- Reserved // Reserved, NCS backward compatibility.
- Microsoft // Reserved, Microsoft Corporation backward compatibility.
- Future // Reserved for future definition.
-)
-
-var rander = rand.Reader // random function
-
-// Parse decodes s into a UUID or returns an error. Both the standard UUID
-// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
-// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
-// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
-// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
-func Parse(s string) (UUID, error) {
- var uuid UUID
- switch len(s) {
- // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- case 36:
-
- // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- case 36 + 9:
- if strings.ToLower(s[:9]) != "urn:uuid:" {
- return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
- }
- s = s[9:]
-
- // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
- case 36 + 2:
- s = s[1:]
-
- // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- case 32:
- var ok bool
- for i := range uuid {
- uuid[i], ok = xtob(s[i*2], s[i*2+1])
- if !ok {
- return uuid, errors.New("invalid UUID format")
- }
- }
- return uuid, nil
- default:
- return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
- }
- // s is now at least 36 bytes long
- // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
- return uuid, errors.New("invalid UUID format")
- }
- for i, x := range [16]int{
- 0, 2, 4, 6,
- 9, 11,
- 14, 16,
- 19, 21,
- 24, 26, 28, 30, 32, 34} {
- v, ok := xtob(s[x], s[x+1])
- if !ok {
- return uuid, errors.New("invalid UUID format")
- }
- uuid[i] = v
- }
- return uuid, nil
-}
-
-// ParseBytes is like Parse, except it parses a byte slice instead of a string.
-func ParseBytes(b []byte) (UUID, error) {
- var uuid UUID
- switch len(b) {
- case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
- return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
- }
- b = b[9:]
- case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
- b = b[1:]
- case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- var ok bool
- for i := 0; i < 32; i += 2 {
- uuid[i/2], ok = xtob(b[i], b[i+1])
- if !ok {
- return uuid, errors.New("invalid UUID format")
- }
- }
- return uuid, nil
- default:
- return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
- }
- // s is now at least 36 bytes long
- // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
- return uuid, errors.New("invalid UUID format")
- }
- for i, x := range [16]int{
- 0, 2, 4, 6,
- 9, 11,
- 14, 16,
- 19, 21,
- 24, 26, 28, 30, 32, 34} {
- v, ok := xtob(b[x], b[x+1])
- if !ok {
- return uuid, errors.New("invalid UUID format")
- }
- uuid[i] = v
- }
- return uuid, nil
-}
-
-// MustParse is like Parse but panics if the string cannot be parsed.
-// It simplifies safe initialization of global variables holding compiled UUIDs.
-func MustParse(s string) UUID {
- uuid, err := Parse(s)
- if err != nil {
- panic(`uuid: Parse(` + s + `): ` + err.Error())
- }
- return uuid
-}
-
-// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
-// does not have a length of 16. The bytes are copied from the slice.
-func FromBytes(b []byte) (uuid UUID, err error) {
- err = uuid.UnmarshalBinary(b)
- return uuid, err
-}
-
-// Must returns uuid if err is nil and panics otherwise.
-func Must(uuid UUID, err error) UUID {
- if err != nil {
- panic(err)
- }
- return uuid
-}
-
-// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-// , or "" if uuid is invalid.
-func (uuid UUID) String() string {
- var buf [36]byte
- encodeHex(buf[:], uuid)
- return string(buf[:])
-}
-
-// URN returns the RFC 2141 URN form of uuid,
-// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
-func (uuid UUID) URN() string {
- var buf [36 + 9]byte
- copy(buf[:], "urn:uuid:")
- encodeHex(buf[9:], uuid)
- return string(buf[:])
-}
-
-func encodeHex(dst []byte, uuid UUID) {
- hex.Encode(dst, uuid[:4])
- dst[8] = '-'
- hex.Encode(dst[9:13], uuid[4:6])
- dst[13] = '-'
- hex.Encode(dst[14:18], uuid[6:8])
- dst[18] = '-'
- hex.Encode(dst[19:23], uuid[8:10])
- dst[23] = '-'
- hex.Encode(dst[24:], uuid[10:])
-}
-
-// Variant returns the variant encoded in uuid.
-func (uuid UUID) Variant() Variant {
- switch {
- case (uuid[8] & 0xc0) == 0x80:
- return RFC4122
- case (uuid[8] & 0xe0) == 0xc0:
- return Microsoft
- case (uuid[8] & 0xe0) == 0xe0:
- return Future
- default:
- return Reserved
- }
-}
-
-// Version returns the version of uuid.
-func (uuid UUID) Version() Version {
- return Version(uuid[6] >> 4)
-}
-
-func (v Version) String() string {
- if v > 15 {
- return fmt.Sprintf("BAD_VERSION_%d", v)
- }
- return fmt.Sprintf("VERSION_%d", v)
-}
-
-func (v Variant) String() string {
- switch v {
- case RFC4122:
- return "RFC4122"
- case Reserved:
- return "Reserved"
- case Microsoft:
- return "Microsoft"
- case Future:
- return "Future"
- case Invalid:
- return "Invalid"
- }
- return fmt.Sprintf("BadVariant%d", int(v))
-}
-
-// SetRand sets the random number generator to r, which implements io.Reader.
-// If r.Read returns an error when the package requests random data then
-// a panic will be issued.
-//
-// Calling SetRand with nil sets the random number generator to the default
-// generator.
-func SetRand(r io.Reader) {
- if r == nil {
- rander = rand.Reader
- return
- }
- rander = r
-}
diff --git a/vendor/github.com/google/uuid/version1.go b/vendor/github.com/google/uuid/version1.go
deleted file mode 100644
index 199a1ac6540..00000000000
--- a/vendor/github.com/google/uuid/version1.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "encoding/binary"
-)
-
-// NewUUID returns a Version 1 UUID based on the current NodeID and clock
-// sequence, and the current time. If the NodeID has not been set by SetNodeID
-// or SetNodeInterface then it will be set automatically. If the NodeID cannot
-// be set NewUUID returns nil. If clock sequence has not been set by
-// SetClockSequence then it will be set automatically. If GetTime fails to
-// return the current NewUUID returns nil and an error.
-//
-// In most cases, New should be used.
-func NewUUID() (UUID, error) {
- nodeMu.Lock()
- if nodeID == zeroID {
- setNodeInterface("")
- }
- nodeMu.Unlock()
-
- var uuid UUID
- now, seq, err := GetTime()
- if err != nil {
- return uuid, err
- }
-
- timeLow := uint32(now & 0xffffffff)
- timeMid := uint16((now >> 32) & 0xffff)
- timeHi := uint16((now >> 48) & 0x0fff)
- timeHi |= 0x1000 // Version 1
-
- binary.BigEndian.PutUint32(uuid[0:], timeLow)
- binary.BigEndian.PutUint16(uuid[4:], timeMid)
- binary.BigEndian.PutUint16(uuid[6:], timeHi)
- binary.BigEndian.PutUint16(uuid[8:], seq)
- copy(uuid[10:], nodeID[:])
-
- return uuid, nil
-}
diff --git a/vendor/github.com/google/uuid/version4.go b/vendor/github.com/google/uuid/version4.go
deleted file mode 100644
index 84af91c9f54..00000000000
--- a/vendor/github.com/google/uuid/version4.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import "io"
-
-// New creates a new random UUID or panics. New is equivalent to
-// the expression
-//
-// uuid.Must(uuid.NewRandom())
-func New() UUID {
- return Must(NewRandom())
-}
-
-// NewRandom returns a Random (Version 4) UUID.
-//
-// The strength of the UUIDs is based on the strength of the crypto/rand
-// package.
-//
-// A note about uniqueness derived from the UUID Wikipedia entry:
-//
-// Randomly generated UUIDs have 122 random bits. One's annual risk of being
-// hit by a meteorite is estimated to be one chance in 17 billion, that
-// means the probability is about 0.00000000006 (6 × 10−11),
-// equivalent to the odds of creating a few tens of trillions of UUIDs in a
-// year and having one duplicate.
-func NewRandom() (UUID, error) {
- var uuid UUID
- _, err := io.ReadFull(rander, uuid[:])
- if err != nil {
- return Nil, err
- }
- uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
- uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
- return uuid, nil
-}
diff --git a/vendor/github.com/gorilla/mux/AUTHORS b/vendor/github.com/gorilla/mux/AUTHORS
deleted file mode 100644
index b722392ee59..00000000000
--- a/vendor/github.com/gorilla/mux/AUTHORS
+++ /dev/null
@@ -1,8 +0,0 @@
-# This is the official list of gorilla/mux authors for copyright purposes.
-#
-# Please keep the list sorted.
-
-Google LLC (https://opensource.google.com/)
-Kamil Kisielk
-Matt Silverlock
-Rodrigo Moraes (https://github.com/moraes)
diff --git a/vendor/github.com/gorilla/mux/LICENSE b/vendor/github.com/gorilla/mux/LICENSE
deleted file mode 100644
index 6903df6386e..00000000000
--- a/vendor/github.com/gorilla/mux/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md
deleted file mode 100644
index 92e422eed7a..00000000000
--- a/vendor/github.com/gorilla/mux/README.md
+++ /dev/null
@@ -1,718 +0,0 @@
-# gorilla/mux
-
-[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
-[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
-[![CircleCI](https://circleci.com/gh/gorilla/mux.svg?style=svg)](https://circleci.com/gh/gorilla/mux)
-[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge)
-
-![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png)
-
-https://www.gorillatoolkit.org/pkg/mux
-
-Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to
-their respective handler.
-
-The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are:
-
-* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
-* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
-* URL hosts, paths and query values can have variables with an optional regular expression.
-* Registered URLs can be built, or "reversed", which helps maintaining references to resources.
-* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
-
----
-
-* [Install](#install)
-* [Examples](#examples)
-* [Matching Routes](#matching-routes)
-* [Static Files](#static-files)
-* [Registered URLs](#registered-urls)
-* [Walking Routes](#walking-routes)
-* [Graceful Shutdown](#graceful-shutdown)
-* [Middleware](#middleware)
-* [Handling CORS Requests](#handling-cors-requests)
-* [Testing Handlers](#testing-handlers)
-* [Full Example](#full-example)
-
----
-
-## Install
-
-With a [correctly configured](https://golang.org/doc/install#testing) Go toolchain:
-
-```sh
-go get -u github.com/gorilla/mux
-```
-
-## Examples
-
-Let's start registering a couple of URL paths and handlers:
-
-```go
-func main() {
- r := mux.NewRouter()
- r.HandleFunc("/", HomeHandler)
- r.HandleFunc("/products", ProductsHandler)
- r.HandleFunc("/articles", ArticlesHandler)
- http.Handle("/", r)
-}
-```
-
-Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters.
-
-Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example:
-
-```go
-r := mux.NewRouter()
-r.HandleFunc("/products/{key}", ProductHandler)
-r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
-r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
-```
-
-The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:
-
-```go
-func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
- vars := mux.Vars(r)
- w.WriteHeader(http.StatusOK)
- fmt.Fprintf(w, "Category: %v\n", vars["category"])
-}
-```
-
-And this is all you need to know about the basic usage. More advanced options are explained below.
-
-### Matching Routes
-
-Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:
-
-```go
-r := mux.NewRouter()
-// Only matches if domain is "www.example.com".
-r.Host("www.example.com")
-// Matches a dynamic subdomain.
-r.Host("{subdomain:[a-z]+}.example.com")
-```
-
-There are several other matchers that can be added. To match path prefixes:
-
-```go
-r.PathPrefix("/products/")
-```
-
-...or HTTP methods:
-
-```go
-r.Methods("GET", "POST")
-```
-
-...or URL schemes:
-
-```go
-r.Schemes("https")
-```
-
-...or header values:
-
-```go
-r.Headers("X-Requested-With", "XMLHttpRequest")
-```
-
-...or query values:
-
-```go
-r.Queries("key", "value")
-```
-
-...or to use a custom matcher function:
-
-```go
-r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
- return r.ProtoMajor == 0
-})
-```
-
-...and finally, it is possible to combine several matchers in a single route:
-
-```go
-r.HandleFunc("/products", ProductsHandler).
- Host("www.example.com").
- Methods("GET").
- Schemes("http")
-```
-
-Routes are tested in the order they were added to the router. If two routes match, the first one wins:
-
-```go
-r := mux.NewRouter()
-r.HandleFunc("/specific", specificHandler)
-r.PathPrefix("/").Handler(catchAllHandler)
-```
-
-Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
-
-For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:
-
-```go
-r := mux.NewRouter()
-s := r.Host("www.example.com").Subrouter()
-```
-
-Then register routes in the subrouter:
-
-```go
-s.HandleFunc("/products/", ProductsHandler)
-s.HandleFunc("/products/{key}", ProductHandler)
-s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
-```
-
-The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.
-
-Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter.
-
-There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths:
-
-```go
-r := mux.NewRouter()
-s := r.PathPrefix("/products").Subrouter()
-// "/products/"
-s.HandleFunc("/", ProductsHandler)
-// "/products/{key}/"
-s.HandleFunc("/{key}/", ProductHandler)
-// "/products/{key}/details"
-s.HandleFunc("/{key}/details", ProductDetailsHandler)
-```
-
-
-### Static Files
-
-Note that the path provided to `PathPrefix()` represents a "wildcard": calling
-`PathPrefix("/static/").Handler(...)` means that the handler will be passed any
-request that matches "/static/\*". This makes it easy to serve static files with mux:
-
-```go
-func main() {
- var dir string
-
- flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
- flag.Parse()
- r := mux.NewRouter()
-
- // This will serve files under http://localhost:8000/static/
- r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
-
- srv := &http.Server{
- Handler: r,
- Addr: "127.0.0.1:8000",
- // Good practice: enforce timeouts for servers you create!
- WriteTimeout: 15 * time.Second,
- ReadTimeout: 15 * time.Second,
- }
-
- log.Fatal(srv.ListenAndServe())
-}
-```
-
-### Registered URLs
-
-Now let's see how to build registered URLs.
-
-Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example:
-
-```go
-r := mux.NewRouter()
-r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
- Name("article")
-```
-
-To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do:
-
-```go
-url, err := r.Get("article").URL("category", "technology", "id", "42")
-```
-
-...and the result will be a `url.URL` with the following path:
-
-```
-"/articles/technology/42"
-```
-
-This also works for host and query value variables:
-
-```go
-r := mux.NewRouter()
-r.Host("{subdomain}.example.com").
- Path("/articles/{category}/{id:[0-9]+}").
- Queries("filter", "{filter}").
- HandlerFunc(ArticleHandler).
- Name("article")
-
-// url.String() will be "http://news.example.com/articles/technology/42?filter=gorilla"
-url, err := r.Get("article").URL("subdomain", "news",
- "category", "technology",
- "id", "42",
- "filter", "gorilla")
-```
-
-All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.
-
-Regex support also exists for matching Headers within a route. For example, we could do:
-
-```go
-r.HeadersRegexp("Content-Type", "application/(text|json)")
-```
-
-...and the route will match both requests with a Content-Type of `application/json` as well as `application/text`
-
-There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do:
-
-```go
-// "http://news.example.com/"
-host, err := r.Get("article").URLHost("subdomain", "news")
-
-// "/articles/technology/42"
-path, err := r.Get("article").URLPath("category", "technology", "id", "42")
-```
-
-And if you use subrouters, host and path defined separately can be built as well:
-
-```go
-r := mux.NewRouter()
-s := r.Host("{subdomain}.example.com").Subrouter()
-s.Path("/articles/{category}/{id:[0-9]+}").
- HandlerFunc(ArticleHandler).
- Name("article")
-
-// "http://news.example.com/articles/technology/42"
-url, err := r.Get("article").URL("subdomain", "news",
- "category", "technology",
- "id", "42")
-```
-
-### Walking Routes
-
-The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
-the following prints all of the registered routes:
-
-```go
-package main
-
-import (
- "fmt"
- "net/http"
- "strings"
-
- "github.com/gorilla/mux"
-)
-
-func handler(w http.ResponseWriter, r *http.Request) {
- return
-}
-
-func main() {
- r := mux.NewRouter()
- r.HandleFunc("/", handler)
- r.HandleFunc("/products", handler).Methods("POST")
- r.HandleFunc("/articles", handler).Methods("GET")
- r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
- r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
- err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
- pathTemplate, err := route.GetPathTemplate()
- if err == nil {
- fmt.Println("ROUTE:", pathTemplate)
- }
- pathRegexp, err := route.GetPathRegexp()
- if err == nil {
- fmt.Println("Path regexp:", pathRegexp)
- }
- queriesTemplates, err := route.GetQueriesTemplates()
- if err == nil {
- fmt.Println("Queries templates:", strings.Join(queriesTemplates, ","))
- }
- queriesRegexps, err := route.GetQueriesRegexp()
- if err == nil {
- fmt.Println("Queries regexps:", strings.Join(queriesRegexps, ","))
- }
- methods, err := route.GetMethods()
- if err == nil {
- fmt.Println("Methods:", strings.Join(methods, ","))
- }
- fmt.Println()
- return nil
- })
-
- if err != nil {
- fmt.Println(err)
- }
-
- http.Handle("/", r)
-}
-```
-
-### Graceful Shutdown
-
-Go 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`:
-
-```go
-package main
-
-import (
- "context"
- "flag"
- "log"
- "net/http"
- "os"
- "os/signal"
- "time"
-
- "github.com/gorilla/mux"
-)
-
-func main() {
- var wait time.Duration
- flag.DurationVar(&wait, "graceful-timeout", time.Second * 15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m")
- flag.Parse()
-
- r := mux.NewRouter()
- // Add your routes as needed
-
- srv := &http.Server{
- Addr: "0.0.0.0:8080",
- // Good practice to set timeouts to avoid Slowloris attacks.
- WriteTimeout: time.Second * 15,
- ReadTimeout: time.Second * 15,
- IdleTimeout: time.Second * 60,
- Handler: r, // Pass our instance of gorilla/mux in.
- }
-
- // Run our server in a goroutine so that it doesn't block.
- go func() {
- if err := srv.ListenAndServe(); err != nil {
- log.Println(err)
- }
- }()
-
- c := make(chan os.Signal, 1)
- // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
- // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
- signal.Notify(c, os.Interrupt)
-
- // Block until we receive our signal.
- <-c
-
- // Create a deadline to wait for.
- ctx, cancel := context.WithTimeout(context.Background(), wait)
- defer cancel()
- // Doesn't block if no connections, but will otherwise wait
- // until the timeout deadline.
- srv.Shutdown(ctx)
- // Optionally, you could run srv.Shutdown in a goroutine and block on
- // <-ctx.Done() if your application should wait for other services
- // to finalize based on context cancellation.
- log.Println("shutting down")
- os.Exit(0)
-}
-```
-
-### Middleware
-
-Mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed in the order they are added if a match is found, including its subrouters.
-Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or `ResponseWriter` hijacking.
-
-Mux middlewares are defined using the de facto standard type:
-
-```go
-type MiddlewareFunc func(http.Handler) http.Handler
-```
-
-Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers.
-
-A very basic middleware which logs the URI of the request being handled could be written as:
-
-```go
-func loggingMiddleware(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- // Do stuff here
- log.Println(r.RequestURI)
- // Call the next handler, which can be another middleware in the chain, or the final handler.
- next.ServeHTTP(w, r)
- })
-}
-```
-
-Middlewares can be added to a router using `Router.Use()`:
-
-```go
-r := mux.NewRouter()
-r.HandleFunc("/", handler)
-r.Use(loggingMiddleware)
-```
-
-A more complex authentication middleware, which maps session token to users, could be written as:
-
-```go
-// Define our struct
-type authenticationMiddleware struct {
- tokenUsers map[string]string
-}
-
-// Initialize it somewhere
-func (amw *authenticationMiddleware) Populate() {
- amw.tokenUsers["00000000"] = "user0"
- amw.tokenUsers["aaaaaaaa"] = "userA"
- amw.tokenUsers["05f717e5"] = "randomUser"
- amw.tokenUsers["deadbeef"] = "user0"
-}
-
-// Middleware function, which will be called for each request
-func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- token := r.Header.Get("X-Session-Token")
-
- if user, found := amw.tokenUsers[token]; found {
- // We found the token in our map
- log.Printf("Authenticated user %s\n", user)
- // Pass down the request to the next middleware (or final handler)
- next.ServeHTTP(w, r)
- } else {
- // Write an error and stop the handler chain
- http.Error(w, "Forbidden", http.StatusForbidden)
- }
- })
-}
-```
-
-```go
-r := mux.NewRouter()
-r.HandleFunc("/", handler)
-
-amw := authenticationMiddleware{}
-amw.Populate()
-
-r.Use(amw.Middleware)
-```
-
-Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it.
-
-### Handling CORS Requests
-
-[CORSMethodMiddleware](https://godoc.org/github.com/gorilla/mux#CORSMethodMiddleware) intends to make it easier to strictly set the `Access-Control-Allow-Methods` response header.
-
-* You will still need to use your own CORS handler to set the other CORS headers such as `Access-Control-Allow-Origin`
-* The middleware will set the `Access-Control-Allow-Methods` header to all the method matchers (e.g. `r.Methods(http.MethodGet, http.MethodPut, http.MethodOptions)` -> `Access-Control-Allow-Methods: GET,PUT,OPTIONS`) on a route
-* If you do not specify any methods, then:
-> _Important_: there must be an `OPTIONS` method matcher for the middleware to set the headers.
-
-Here is an example of using `CORSMethodMiddleware` along with a custom `OPTIONS` handler to set all the required CORS headers:
-
-```go
-package main
-
-import (
- "net/http"
- "github.com/gorilla/mux"
-)
-
-func main() {
- r := mux.NewRouter()
-
- // IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers
- r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions)
- r.Use(mux.CORSMethodMiddleware(r))
-
- http.ListenAndServe(":8080", r)
-}
-
-func fooHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Access-Control-Allow-Origin", "*")
- if r.Method == http.MethodOptions {
- return
- }
-
- w.Write([]byte("foo"))
-}
-```
-
-And an request to `/foo` using something like:
-
-```bash
-curl localhost:8080/foo -v
-```
-
-Would look like:
-
-```bash
-* Trying ::1...
-* TCP_NODELAY set
-* Connected to localhost (::1) port 8080 (#0)
-> GET /foo HTTP/1.1
-> Host: localhost:8080
-> User-Agent: curl/7.59.0
-> Accept: */*
->
-< HTTP/1.1 200 OK
-< Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS
-< Access-Control-Allow-Origin: *
-< Date: Fri, 28 Jun 2019 20:13:30 GMT
-< Content-Length: 3
-< Content-Type: text/plain; charset=utf-8
-<
-* Connection #0 to host localhost left intact
-foo
-```
-
-### Testing Handlers
-
-Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_.
-
-First, our simple HTTP handler:
-
-```go
-// endpoints.go
-package main
-
-func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
- // A very simple health check.
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
-
- // In the future we could report back on the status of our DB, or our cache
- // (e.g. Redis) by performing a simple PING, and include them in the response.
- io.WriteString(w, `{"alive": true}`)
-}
-
-func main() {
- r := mux.NewRouter()
- r.HandleFunc("/health", HealthCheckHandler)
-
- log.Fatal(http.ListenAndServe("localhost:8080", r))
-}
-```
-
-Our test code:
-
-```go
-// endpoints_test.go
-package main
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
-)
-
-func TestHealthCheckHandler(t *testing.T) {
- // Create a request to pass to our handler. We don't have any query parameters for now, so we'll
- // pass 'nil' as the third parameter.
- req, err := http.NewRequest("GET", "/health", nil)
- if err != nil {
- t.Fatal(err)
- }
-
- // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
- rr := httptest.NewRecorder()
- handler := http.HandlerFunc(HealthCheckHandler)
-
- // Our handlers satisfy http.Handler, so we can call their ServeHTTP method
- // directly and pass in our Request and ResponseRecorder.
- handler.ServeHTTP(rr, req)
-
- // Check the status code is what we expect.
- if status := rr.Code; status != http.StatusOK {
- t.Errorf("handler returned wrong status code: got %v want %v",
- status, http.StatusOK)
- }
-
- // Check the response body is what we expect.
- expected := `{"alive": true}`
- if rr.Body.String() != expected {
- t.Errorf("handler returned unexpected body: got %v want %v",
- rr.Body.String(), expected)
- }
-}
-```
-
-In the case that our routes have [variables](#examples), we can pass those in the request. We could write
-[table-driven tests](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) to test multiple
-possible route variables as needed.
-
-```go
-// endpoints.go
-func main() {
- r := mux.NewRouter()
- // A route with a route variable:
- r.HandleFunc("/metrics/{type}", MetricsHandler)
-
- log.Fatal(http.ListenAndServe("localhost:8080", r))
-}
-```
-
-Our test file, with a table-driven test of `routeVariables`:
-
-```go
-// endpoints_test.go
-func TestMetricsHandler(t *testing.T) {
- tt := []struct{
- routeVariable string
- shouldPass bool
- }{
- {"goroutines", true},
- {"heap", true},
- {"counters", true},
- {"queries", true},
- {"adhadaeqm3k", false},
- }
-
- for _, tc := range tt {
- path := fmt.Sprintf("/metrics/%s", tc.routeVariable)
- req, err := http.NewRequest("GET", path, nil)
- if err != nil {
- t.Fatal(err)
- }
-
- rr := httptest.NewRecorder()
-
- // Need to create a router that we can pass the request through so that the vars will be added to the context
- router := mux.NewRouter()
- router.HandleFunc("/metrics/{type}", MetricsHandler)
- router.ServeHTTP(rr, req)
-
- // In this case, our MetricsHandler returns a non-200 response
- // for a route variable it doesn't know about.
- if rr.Code == http.StatusOK && !tc.shouldPass {
- t.Errorf("handler should have failed on routeVariable %s: got %v want %v",
- tc.routeVariable, rr.Code, http.StatusOK)
- }
- }
-}
-```
-
-## Full Example
-
-Here's a complete, runnable example of a small `mux` based server:
-
-```go
-package main
-
-import (
- "net/http"
- "log"
- "github.com/gorilla/mux"
-)
-
-func YourHandler(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte("Gorilla!\n"))
-}
-
-func main() {
- r := mux.NewRouter()
- // Routes consist of a path and a handler function.
- r.HandleFunc("/", YourHandler)
-
- // Bind to a port and pass our router in
- log.Fatal(http.ListenAndServe(":8000", r))
-}
-```
-
-## License
-
-BSD licensed. See the LICENSE file for details.
diff --git a/vendor/github.com/gorilla/mux/context.go b/vendor/github.com/gorilla/mux/context.go
deleted file mode 100644
index 665940a2682..00000000000
--- a/vendor/github.com/gorilla/mux/context.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package mux
-
-import (
- "context"
- "net/http"
-)
-
-func contextGet(r *http.Request, key interface{}) interface{} {
- return r.Context().Value(key)
-}
-
-func contextSet(r *http.Request, key, val interface{}) *http.Request {
- if val == nil {
- return r
- }
-
- return r.WithContext(context.WithValue(r.Context(), key, val))
-}
diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go
deleted file mode 100644
index bd5a38b55d8..00000000000
--- a/vendor/github.com/gorilla/mux/doc.go
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package mux implements a request router and dispatcher.
-
-The name mux stands for "HTTP request multiplexer". Like the standard
-http.ServeMux, mux.Router matches incoming requests against a list of
-registered routes and calls a handler for the route that matches the URL
-or other conditions. The main features are:
-
- * Requests can be matched based on URL host, path, path prefix, schemes,
- header and query values, HTTP methods or using custom matchers.
- * URL hosts, paths and query values can have variables with an optional
- regular expression.
- * Registered URLs can be built, or "reversed", which helps maintaining
- references to resources.
- * Routes can be used as subrouters: nested routes are only tested if the
- parent route matches. This is useful to define groups of routes that
- share common conditions like a host, a path prefix or other repeated
- attributes. As a bonus, this optimizes request matching.
- * It implements the http.Handler interface so it is compatible with the
- standard http.ServeMux.
-
-Let's start registering a couple of URL paths and handlers:
-
- func main() {
- r := mux.NewRouter()
- r.HandleFunc("/", HomeHandler)
- r.HandleFunc("/products", ProductsHandler)
- r.HandleFunc("/articles", ArticlesHandler)
- http.Handle("/", r)
- }
-
-Here we register three routes mapping URL paths to handlers. This is
-equivalent to how http.HandleFunc() works: if an incoming request URL matches
-one of the paths, the corresponding handler is called passing
-(http.ResponseWriter, *http.Request) as parameters.
-
-Paths can have variables. They are defined using the format {name} or
-{name:pattern}. If a regular expression pattern is not defined, the matched
-variable will be anything until the next slash. For example:
-
- r := mux.NewRouter()
- r.HandleFunc("/products/{key}", ProductHandler)
- r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
- r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
-
-Groups can be used inside patterns, as long as they are non-capturing (?:re). For example:
-
- r.HandleFunc("/articles/{category}/{sort:(?:asc|desc|new)}", ArticlesCategoryHandler)
-
-The names are used to create a map of route variables which can be retrieved
-calling mux.Vars():
-
- vars := mux.Vars(request)
- category := vars["category"]
-
-Note that if any capturing groups are present, mux will panic() during parsing. To prevent
-this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to
-"/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably
-when capturing groups were present.
-
-And this is all you need to know about the basic usage. More advanced options
-are explained below.
-
-Routes can also be restricted to a domain or subdomain. Just define a host
-pattern to be matched. They can also have variables:
-
- r := mux.NewRouter()
- // Only matches if domain is "www.example.com".
- r.Host("www.example.com")
- // Matches a dynamic subdomain.
- r.Host("{subdomain:[a-z]+}.domain.com")
-
-There are several other matchers that can be added. To match path prefixes:
-
- r.PathPrefix("/products/")
-
-...or HTTP methods:
-
- r.Methods("GET", "POST")
-
-...or URL schemes:
-
- r.Schemes("https")
-
-...or header values:
-
- r.Headers("X-Requested-With", "XMLHttpRequest")
-
-...or query values:
-
- r.Queries("key", "value")
-
-...or to use a custom matcher function:
-
- r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
- return r.ProtoMajor == 0
- })
-
-...and finally, it is possible to combine several matchers in a single route:
-
- r.HandleFunc("/products", ProductsHandler).
- Host("www.example.com").
- Methods("GET").
- Schemes("http")
-
-Setting the same matching conditions again and again can be boring, so we have
-a way to group several routes that share the same requirements.
-We call it "subrouting".
-
-For example, let's say we have several URLs that should only match when the
-host is "www.example.com". Create a route for that host and get a "subrouter"
-from it:
-
- r := mux.NewRouter()
- s := r.Host("www.example.com").Subrouter()
-
-Then register routes in the subrouter:
-
- s.HandleFunc("/products/", ProductsHandler)
- s.HandleFunc("/products/{key}", ProductHandler)
- s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
-
-The three URL paths we registered above will only be tested if the domain is
-"www.example.com", because the subrouter is tested first. This is not
-only convenient, but also optimizes request matching. You can create
-subrouters combining any attribute matchers accepted by a route.
-
-Subrouters can be used to create domain or path "namespaces": you define
-subrouters in a central place and then parts of the app can register its
-paths relatively to a given subrouter.
-
-There's one more thing about subroutes. When a subrouter has a path prefix,
-the inner routes use it as base for their paths:
-
- r := mux.NewRouter()
- s := r.PathPrefix("/products").Subrouter()
- // "/products/"
- s.HandleFunc("/", ProductsHandler)
- // "/products/{key}/"
- s.HandleFunc("/{key}/", ProductHandler)
- // "/products/{key}/details"
- s.HandleFunc("/{key}/details", ProductDetailsHandler)
-
-Note that the path provided to PathPrefix() represents a "wildcard": calling
-PathPrefix("/static/").Handler(...) means that the handler will be passed any
-request that matches "/static/*". This makes it easy to serve static files with mux:
-
- func main() {
- var dir string
-
- flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
- flag.Parse()
- r := mux.NewRouter()
-
- // This will serve files under http://localhost:8000/static/
- r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
-
- srv := &http.Server{
- Handler: r,
- Addr: "127.0.0.1:8000",
- // Good practice: enforce timeouts for servers you create!
- WriteTimeout: 15 * time.Second,
- ReadTimeout: 15 * time.Second,
- }
-
- log.Fatal(srv.ListenAndServe())
- }
-
-Now let's see how to build registered URLs.
-
-Routes can be named. All routes that define a name can have their URLs built,
-or "reversed". We define a name calling Name() on a route. For example:
-
- r := mux.NewRouter()
- r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
- Name("article")
-
-To build a URL, get the route and call the URL() method, passing a sequence of
-key/value pairs for the route variables. For the previous route, we would do:
-
- url, err := r.Get("article").URL("category", "technology", "id", "42")
-
-...and the result will be a url.URL with the following path:
-
- "/articles/technology/42"
-
-This also works for host and query value variables:
-
- r := mux.NewRouter()
- r.Host("{subdomain}.domain.com").
- Path("/articles/{category}/{id:[0-9]+}").
- Queries("filter", "{filter}").
- HandlerFunc(ArticleHandler).
- Name("article")
-
- // url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
- url, err := r.Get("article").URL("subdomain", "news",
- "category", "technology",
- "id", "42",
- "filter", "gorilla")
-
-All variables defined in the route are required, and their values must
-conform to the corresponding patterns. These requirements guarantee that a
-generated URL will always match a registered route -- the only exception is
-for explicitly defined "build-only" routes which never match.
-
-Regex support also exists for matching Headers within a route. For example, we could do:
-
- r.HeadersRegexp("Content-Type", "application/(text|json)")
-
-...and the route will match both requests with a Content-Type of `application/json` as well as
-`application/text`
-
-There's also a way to build only the URL host or path for a route:
-use the methods URLHost() or URLPath() instead. For the previous route,
-we would do:
-
- // "http://news.domain.com/"
- host, err := r.Get("article").URLHost("subdomain", "news")
-
- // "/articles/technology/42"
- path, err := r.Get("article").URLPath("category", "technology", "id", "42")
-
-And if you use subrouters, host and path defined separately can be built
-as well:
-
- r := mux.NewRouter()
- s := r.Host("{subdomain}.domain.com").Subrouter()
- s.Path("/articles/{category}/{id:[0-9]+}").
- HandlerFunc(ArticleHandler).
- Name("article")
-
- // "http://news.domain.com/articles/technology/42"
- url, err := r.Get("article").URL("subdomain", "news",
- "category", "technology",
- "id", "42")
-
-Mux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters. Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or ResponseWriter hijacking.
-
- type MiddlewareFunc func(http.Handler) http.Handler
-
-Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created).
-
-A very basic middleware which logs the URI of the request being handled could be written as:
-
- func simpleMw(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- // Do stuff here
- log.Println(r.RequestURI)
- // Call the next handler, which can be another middleware in the chain, or the final handler.
- next.ServeHTTP(w, r)
- })
- }
-
-Middlewares can be added to a router using `Router.Use()`:
-
- r := mux.NewRouter()
- r.HandleFunc("/", handler)
- r.Use(simpleMw)
-
-A more complex authentication middleware, which maps session token to users, could be written as:
-
- // Define our struct
- type authenticationMiddleware struct {
- tokenUsers map[string]string
- }
-
- // Initialize it somewhere
- func (amw *authenticationMiddleware) Populate() {
- amw.tokenUsers["00000000"] = "user0"
- amw.tokenUsers["aaaaaaaa"] = "userA"
- amw.tokenUsers["05f717e5"] = "randomUser"
- amw.tokenUsers["deadbeef"] = "user0"
- }
-
- // Middleware function, which will be called for each request
- func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- token := r.Header.Get("X-Session-Token")
-
- if user, found := amw.tokenUsers[token]; found {
- // We found the token in our map
- log.Printf("Authenticated user %s\n", user)
- next.ServeHTTP(w, r)
- } else {
- http.Error(w, "Forbidden", http.StatusForbidden)
- }
- })
- }
-
- r := mux.NewRouter()
- r.HandleFunc("/", handler)
-
- amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
- amw.Populate()
-
- r.Use(amw.Middleware)
-
-Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to.
-
-*/
-package mux
diff --git a/vendor/github.com/gorilla/mux/go.mod b/vendor/github.com/gorilla/mux/go.mod
deleted file mode 100644
index cfc8ede5818..00000000000
--- a/vendor/github.com/gorilla/mux/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/gorilla/mux
diff --git a/vendor/github.com/gorilla/mux/middleware.go b/vendor/github.com/gorilla/mux/middleware.go
deleted file mode 100644
index cf2b26dc037..00000000000
--- a/vendor/github.com/gorilla/mux/middleware.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package mux
-
-import (
- "net/http"
- "strings"
-)
-
-// MiddlewareFunc is a function which receives an http.Handler and returns another http.Handler.
-// Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed
-// to it, and then calls the handler passed as parameter to the MiddlewareFunc.
-type MiddlewareFunc func(http.Handler) http.Handler
-
-// middleware interface is anything which implements a MiddlewareFunc named Middleware.
-type middleware interface {
- Middleware(handler http.Handler) http.Handler
-}
-
-// Middleware allows MiddlewareFunc to implement the middleware interface.
-func (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler {
- return mw(handler)
-}
-
-// Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
-func (r *Router) Use(mwf ...MiddlewareFunc) {
- for _, fn := range mwf {
- r.middlewares = append(r.middlewares, fn)
- }
-}
-
-// useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
-func (r *Router) useInterface(mw middleware) {
- r.middlewares = append(r.middlewares, mw)
-}
-
-// CORSMethodMiddleware automatically sets the Access-Control-Allow-Methods response header
-// on requests for routes that have an OPTIONS method matcher to all the method matchers on
-// the route. Routes that do not explicitly handle OPTIONS requests will not be processed
-// by the middleware. See examples for usage.
-func CORSMethodMiddleware(r *Router) MiddlewareFunc {
- return func(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- allMethods, err := getAllMethodsForRoute(r, req)
- if err == nil {
- for _, v := range allMethods {
- if v == http.MethodOptions {
- w.Header().Set("Access-Control-Allow-Methods", strings.Join(allMethods, ","))
- }
- }
- }
-
- next.ServeHTTP(w, req)
- })
- }
-}
-
-// getAllMethodsForRoute returns all the methods from method matchers matching a given
-// request.
-func getAllMethodsForRoute(r *Router, req *http.Request) ([]string, error) {
- var allMethods []string
-
- err := r.Walk(func(route *Route, _ *Router, _ []*Route) error {
- for _, m := range route.matchers {
- if _, ok := m.(*routeRegexp); ok {
- if m.Match(req, &RouteMatch{}) {
- methods, err := route.GetMethods()
- if err != nil {
- return err
- }
-
- allMethods = append(allMethods, methods...)
- }
- break
- }
- }
- return nil
- })
-
- return allMethods, err
-}
diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go
deleted file mode 100644
index a2cd193e487..00000000000
--- a/vendor/github.com/gorilla/mux/mux.go
+++ /dev/null
@@ -1,607 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import (
- "errors"
- "fmt"
- "net/http"
- "path"
- "regexp"
-)
-
-var (
- // ErrMethodMismatch is returned when the method in the request does not match
- // the method defined against the route.
- ErrMethodMismatch = errors.New("method is not allowed")
- // ErrNotFound is returned when no route match is found.
- ErrNotFound = errors.New("no matching route was found")
-)
-
-// NewRouter returns a new router instance.
-func NewRouter() *Router {
- return &Router{namedRoutes: make(map[string]*Route)}
-}
-
-// Router registers routes to be matched and dispatches a handler.
-//
-// It implements the http.Handler interface, so it can be registered to serve
-// requests:
-//
-// var router = mux.NewRouter()
-//
-// func main() {
-// http.Handle("/", router)
-// }
-//
-// Or, for Google App Engine, register it in a init() function:
-//
-// func init() {
-// http.Handle("/", router)
-// }
-//
-// This will send all incoming requests to the router.
-type Router struct {
- // Configurable Handler to be used when no route matches.
- NotFoundHandler http.Handler
-
- // Configurable Handler to be used when the request method does not match the route.
- MethodNotAllowedHandler http.Handler
-
- // Routes to be matched, in order.
- routes []*Route
-
- // Routes by name for URL building.
- namedRoutes map[string]*Route
-
- // If true, do not clear the request context after handling the request.
- //
- // Deprecated: No effect when go1.7+ is used, since the context is stored
- // on the request itself.
- KeepContext bool
-
- // Slice of middlewares to be called after a match is found
- middlewares []middleware
-
- // configuration shared with `Route`
- routeConf
-}
-
-// common route configuration shared between `Router` and `Route`
-type routeConf struct {
- // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
- useEncodedPath bool
-
- // If true, when the path pattern is "/path/", accessing "/path" will
- // redirect to the former and vice versa.
- strictSlash bool
-
- // If true, when the path pattern is "/path//to", accessing "/path//to"
- // will not redirect
- skipClean bool
-
- // Manager for the variables from host and path.
- regexp routeRegexpGroup
-
- // List of matchers.
- matchers []matcher
-
- // The scheme used when building URLs.
- buildScheme string
-
- buildVarsFunc BuildVarsFunc
-}
-
-// returns an effective deep copy of `routeConf`
-func copyRouteConf(r routeConf) routeConf {
- c := r
-
- if r.regexp.path != nil {
- c.regexp.path = copyRouteRegexp(r.regexp.path)
- }
-
- if r.regexp.host != nil {
- c.regexp.host = copyRouteRegexp(r.regexp.host)
- }
-
- c.regexp.queries = make([]*routeRegexp, 0, len(r.regexp.queries))
- for _, q := range r.regexp.queries {
- c.regexp.queries = append(c.regexp.queries, copyRouteRegexp(q))
- }
-
- c.matchers = make([]matcher, 0, len(r.matchers))
- for _, m := range r.matchers {
- c.matchers = append(c.matchers, m)
- }
-
- return c
-}
-
-func copyRouteRegexp(r *routeRegexp) *routeRegexp {
- c := *r
- return &c
-}
-
-// Match attempts to match the given request against the router's registered routes.
-//
-// If the request matches a route of this router or one of its subrouters the Route,
-// Handler, and Vars fields of the the match argument are filled and this function
-// returns true.
-//
-// If the request does not match any of this router's or its subrouters' routes
-// then this function returns false. If available, a reason for the match failure
-// will be filled in the match argument's MatchErr field. If the match failure type
-// (eg: not found) has a registered handler, the handler is assigned to the Handler
-// field of the match argument.
-func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
- for _, route := range r.routes {
- if route.Match(req, match) {
- // Build middleware chain if no error was found
- if match.MatchErr == nil {
- for i := len(r.middlewares) - 1; i >= 0; i-- {
- match.Handler = r.middlewares[i].Middleware(match.Handler)
- }
- }
- return true
- }
- }
-
- if match.MatchErr == ErrMethodMismatch {
- if r.MethodNotAllowedHandler != nil {
- match.Handler = r.MethodNotAllowedHandler
- return true
- }
-
- return false
- }
-
- // Closest match for a router (includes sub-routers)
- if r.NotFoundHandler != nil {
- match.Handler = r.NotFoundHandler
- match.MatchErr = ErrNotFound
- return true
- }
-
- match.MatchErr = ErrNotFound
- return false
-}
-
-// ServeHTTP dispatches the handler registered in the matched route.
-//
-// When there is a match, the route variables can be retrieved calling
-// mux.Vars(request).
-func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- if !r.skipClean {
- path := req.URL.Path
- if r.useEncodedPath {
- path = req.URL.EscapedPath()
- }
- // Clean path to canonical form and redirect.
- if p := cleanPath(path); p != path {
-
- // Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
- // This matches with fix in go 1.2 r.c. 4 for same problem. Go Issue:
- // http://code.google.com/p/go/issues/detail?id=5252
- url := *req.URL
- url.Path = p
- p = url.String()
-
- w.Header().Set("Location", p)
- w.WriteHeader(http.StatusMovedPermanently)
- return
- }
- }
- var match RouteMatch
- var handler http.Handler
- if r.Match(req, &match) {
- handler = match.Handler
- req = setVars(req, match.Vars)
- req = setCurrentRoute(req, match.Route)
- }
-
- if handler == nil && match.MatchErr == ErrMethodMismatch {
- handler = methodNotAllowedHandler()
- }
-
- if handler == nil {
- handler = http.NotFoundHandler()
- }
-
- handler.ServeHTTP(w, req)
-}
-
-// Get returns a route registered with the given name.
-func (r *Router) Get(name string) *Route {
- return r.namedRoutes[name]
-}
-
-// GetRoute returns a route registered with the given name. This method
-// was renamed to Get() and remains here for backwards compatibility.
-func (r *Router) GetRoute(name string) *Route {
- return r.namedRoutes[name]
-}
-
-// StrictSlash defines the trailing slash behavior for new routes. The initial
-// value is false.
-//
-// When true, if the route path is "/path/", accessing "/path" will perform a redirect
-// to the former and vice versa. In other words, your application will always
-// see the path as specified in the route.
-//
-// When false, if the route path is "/path", accessing "/path/" will not match
-// this route and vice versa.
-//
-// The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for
-// routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed
-// request will be made as a GET by most clients. Use middleware or client settings
-// to modify this behaviour as needed.
-//
-// Special case: when a route sets a path prefix using the PathPrefix() method,
-// strict slash is ignored for that route because the redirect behavior can't
-// be determined from a prefix alone. However, any subrouters created from that
-// route inherit the original StrictSlash setting.
-func (r *Router) StrictSlash(value bool) *Router {
- r.strictSlash = value
- return r
-}
-
-// SkipClean defines the path cleaning behaviour for new routes. The initial
-// value is false. Users should be careful about which routes are not cleaned
-//
-// When true, if the route path is "/path//to", it will remain with the double
-// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
-//
-// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will
-// become /fetch/http/xkcd.com/534
-func (r *Router) SkipClean(value bool) *Router {
- r.skipClean = value
- return r
-}
-
-// UseEncodedPath tells the router to match the encoded original path
-// to the routes.
-// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
-//
-// If not called, the router will match the unencoded path to the routes.
-// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
-func (r *Router) UseEncodedPath() *Router {
- r.useEncodedPath = true
- return r
-}
-
-// ----------------------------------------------------------------------------
-// Route factories
-// ----------------------------------------------------------------------------
-
-// NewRoute registers an empty route.
-func (r *Router) NewRoute() *Route {
- // initialize a route with a copy of the parent router's configuration
- route := &Route{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
- r.routes = append(r.routes, route)
- return route
-}
-
-// Name registers a new route with a name.
-// See Route.Name().
-func (r *Router) Name(name string) *Route {
- return r.NewRoute().Name(name)
-}
-
-// Handle registers a new route with a matcher for the URL path.
-// See Route.Path() and Route.Handler().
-func (r *Router) Handle(path string, handler http.Handler) *Route {
- return r.NewRoute().Path(path).Handler(handler)
-}
-
-// HandleFunc registers a new route with a matcher for the URL path.
-// See Route.Path() and Route.HandlerFunc().
-func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
- *http.Request)) *Route {
- return r.NewRoute().Path(path).HandlerFunc(f)
-}
-
-// Headers registers a new route with a matcher for request header values.
-// See Route.Headers().
-func (r *Router) Headers(pairs ...string) *Route {
- return r.NewRoute().Headers(pairs...)
-}
-
-// Host registers a new route with a matcher for the URL host.
-// See Route.Host().
-func (r *Router) Host(tpl string) *Route {
- return r.NewRoute().Host(tpl)
-}
-
-// MatcherFunc registers a new route with a custom matcher function.
-// See Route.MatcherFunc().
-func (r *Router) MatcherFunc(f MatcherFunc) *Route {
- return r.NewRoute().MatcherFunc(f)
-}
-
-// Methods registers a new route with a matcher for HTTP methods.
-// See Route.Methods().
-func (r *Router) Methods(methods ...string) *Route {
- return r.NewRoute().Methods(methods...)
-}
-
-// Path registers a new route with a matcher for the URL path.
-// See Route.Path().
-func (r *Router) Path(tpl string) *Route {
- return r.NewRoute().Path(tpl)
-}
-
-// PathPrefix registers a new route with a matcher for the URL path prefix.
-// See Route.PathPrefix().
-func (r *Router) PathPrefix(tpl string) *Route {
- return r.NewRoute().PathPrefix(tpl)
-}
-
-// Queries registers a new route with a matcher for URL query values.
-// See Route.Queries().
-func (r *Router) Queries(pairs ...string) *Route {
- return r.NewRoute().Queries(pairs...)
-}
-
-// Schemes registers a new route with a matcher for URL schemes.
-// See Route.Schemes().
-func (r *Router) Schemes(schemes ...string) *Route {
- return r.NewRoute().Schemes(schemes...)
-}
-
-// BuildVarsFunc registers a new route with a custom function for modifying
-// route variables before building a URL.
-func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
- return r.NewRoute().BuildVarsFunc(f)
-}
-
-// Walk walks the router and all its sub-routers, calling walkFn for each route
-// in the tree. The routes are walked in the order they were added. Sub-routers
-// are explored depth-first.
-func (r *Router) Walk(walkFn WalkFunc) error {
- return r.walk(walkFn, []*Route{})
-}
-
-// SkipRouter is used as a return value from WalkFuncs to indicate that the
-// router that walk is about to descend down to should be skipped.
-var SkipRouter = errors.New("skip this router")
-
-// WalkFunc is the type of the function called for each route visited by Walk.
-// At every invocation, it is given the current route, and the current router,
-// and a list of ancestor routes that lead to the current route.
-type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
-
-func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
- for _, t := range r.routes {
- err := walkFn(t, r, ancestors)
- if err == SkipRouter {
- continue
- }
- if err != nil {
- return err
- }
- for _, sr := range t.matchers {
- if h, ok := sr.(*Router); ok {
- ancestors = append(ancestors, t)
- err := h.walk(walkFn, ancestors)
- if err != nil {
- return err
- }
- ancestors = ancestors[:len(ancestors)-1]
- }
- }
- if h, ok := t.handler.(*Router); ok {
- ancestors = append(ancestors, t)
- err := h.walk(walkFn, ancestors)
- if err != nil {
- return err
- }
- ancestors = ancestors[:len(ancestors)-1]
- }
- }
- return nil
-}
-
-// ----------------------------------------------------------------------------
-// Context
-// ----------------------------------------------------------------------------
-
-// RouteMatch stores information about a matched route.
-type RouteMatch struct {
- Route *Route
- Handler http.Handler
- Vars map[string]string
-
- // MatchErr is set to appropriate matching error
- // It is set to ErrMethodMismatch if there is a mismatch in
- // the request method and route method
- MatchErr error
-}
-
-type contextKey int
-
-const (
- varsKey contextKey = iota
- routeKey
-)
-
-// Vars returns the route variables for the current request, if any.
-func Vars(r *http.Request) map[string]string {
- if rv := contextGet(r, varsKey); rv != nil {
- return rv.(map[string]string)
- }
- return nil
-}
-
-// CurrentRoute returns the matched route for the current request, if any.
-// This only works when called inside the handler of the matched route
-// because the matched route is stored in the request context which is cleared
-// after the handler returns, unless the KeepContext option is set on the
-// Router.
-func CurrentRoute(r *http.Request) *Route {
- if rv := contextGet(r, routeKey); rv != nil {
- return rv.(*Route)
- }
- return nil
-}
-
-func setVars(r *http.Request, val interface{}) *http.Request {
- return contextSet(r, varsKey, val)
-}
-
-func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
- return contextSet(r, routeKey, val)
-}
-
-// ----------------------------------------------------------------------------
-// Helpers
-// ----------------------------------------------------------------------------
-
-// cleanPath returns the canonical path for p, eliminating . and .. elements.
-// Borrowed from the net/http package.
-func cleanPath(p string) string {
- if p == "" {
- return "/"
- }
- if p[0] != '/' {
- p = "/" + p
- }
- np := path.Clean(p)
- // path.Clean removes trailing slash except for root;
- // put the trailing slash back if necessary.
- if p[len(p)-1] == '/' && np != "/" {
- np += "/"
- }
-
- return np
-}
-
-// uniqueVars returns an error if two slices contain duplicated strings.
-func uniqueVars(s1, s2 []string) error {
- for _, v1 := range s1 {
- for _, v2 := range s2 {
- if v1 == v2 {
- return fmt.Errorf("mux: duplicated route variable %q", v2)
- }
- }
- }
- return nil
-}
-
-// checkPairs returns the count of strings passed in, and an error if
-// the count is not an even number.
-func checkPairs(pairs ...string) (int, error) {
- length := len(pairs)
- if length%2 != 0 {
- return length, fmt.Errorf(
- "mux: number of parameters must be multiple of 2, got %v", pairs)
- }
- return length, nil
-}
-
-// mapFromPairsToString converts variadic string parameters to a
-// string to string map.
-func mapFromPairsToString(pairs ...string) (map[string]string, error) {
- length, err := checkPairs(pairs...)
- if err != nil {
- return nil, err
- }
- m := make(map[string]string, length/2)
- for i := 0; i < length; i += 2 {
- m[pairs[i]] = pairs[i+1]
- }
- return m, nil
-}
-
-// mapFromPairsToRegex converts variadic string parameters to a
-// string to regex map.
-func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
- length, err := checkPairs(pairs...)
- if err != nil {
- return nil, err
- }
- m := make(map[string]*regexp.Regexp, length/2)
- for i := 0; i < length; i += 2 {
- regex, err := regexp.Compile(pairs[i+1])
- if err != nil {
- return nil, err
- }
- m[pairs[i]] = regex
- }
- return m, nil
-}
-
-// matchInArray returns true if the given string value is in the array.
-func matchInArray(arr []string, value string) bool {
- for _, v := range arr {
- if v == value {
- return true
- }
- }
- return false
-}
-
-// matchMapWithString returns true if the given key/value pairs exist in a given map.
-func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
- for k, v := range toCheck {
- // Check if key exists.
- if canonicalKey {
- k = http.CanonicalHeaderKey(k)
- }
- if values := toMatch[k]; values == nil {
- return false
- } else if v != "" {
- // If value was defined as an empty string we only check that the
- // key exists. Otherwise we also check for equality.
- valueExists := false
- for _, value := range values {
- if v == value {
- valueExists = true
- break
- }
- }
- if !valueExists {
- return false
- }
- }
- }
- return true
-}
-
-// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
-// the given regex
-func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
- for k, v := range toCheck {
- // Check if key exists.
- if canonicalKey {
- k = http.CanonicalHeaderKey(k)
- }
- if values := toMatch[k]; values == nil {
- return false
- } else if v != nil {
- // If value was defined as an empty string we only check that the
- // key exists. Otherwise we also check for equality.
- valueExists := false
- for _, value := range values {
- if v.MatchString(value) {
- valueExists = true
- break
- }
- }
- if !valueExists {
- return false
- }
- }
- }
- return true
-}
-
-// methodNotAllowed replies to the request with an HTTP status code 405.
-func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(http.StatusMethodNotAllowed)
-}
-
-// methodNotAllowedHandler returns a simple request handler
-// that replies to each request with a status code 405.
-func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }
diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go
deleted file mode 100644
index ac1abcd473e..00000000000
--- a/vendor/github.com/gorilla/mux/regexp.go
+++ /dev/null
@@ -1,345 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import (
- "bytes"
- "fmt"
- "net/http"
- "net/url"
- "regexp"
- "strconv"
- "strings"
-)
-
-type routeRegexpOptions struct {
- strictSlash bool
- useEncodedPath bool
-}
-
-type regexpType int
-
-const (
- regexpTypePath regexpType = 0
- regexpTypeHost regexpType = 1
- regexpTypePrefix regexpType = 2
- regexpTypeQuery regexpType = 3
-)
-
-// newRouteRegexp parses a route template and returns a routeRegexp,
-// used to match a host, a path or a query string.
-//
-// It will extract named variables, assemble a regexp to be matched, create
-// a "reverse" template to build URLs and compile regexps to validate variable
-// values used in URL building.
-//
-// Previously we accepted only Python-like identifiers for variable
-// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
-// name and pattern can't be empty, and names can't contain a colon.
-func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*routeRegexp, error) {
- // Check if it is well-formed.
- idxs, errBraces := braceIndices(tpl)
- if errBraces != nil {
- return nil, errBraces
- }
- // Backup the original.
- template := tpl
- // Now let's parse it.
- defaultPattern := "[^/]+"
- if typ == regexpTypeQuery {
- defaultPattern = ".*"
- } else if typ == regexpTypeHost {
- defaultPattern = "[^.]+"
- }
- // Only match strict slash if not matching
- if typ != regexpTypePath {
- options.strictSlash = false
- }
- // Set a flag for strictSlash.
- endSlash := false
- if options.strictSlash && strings.HasSuffix(tpl, "/") {
- tpl = tpl[:len(tpl)-1]
- endSlash = true
- }
- varsN := make([]string, len(idxs)/2)
- varsR := make([]*regexp.Regexp, len(idxs)/2)
- pattern := bytes.NewBufferString("")
- pattern.WriteByte('^')
- reverse := bytes.NewBufferString("")
- var end int
- var err error
- for i := 0; i < len(idxs); i += 2 {
- // Set all values we are interested in.
- raw := tpl[end:idxs[i]]
- end = idxs[i+1]
- parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2)
- name := parts[0]
- patt := defaultPattern
- if len(parts) == 2 {
- patt = parts[1]
- }
- // Name or pattern can't be empty.
- if name == "" || patt == "" {
- return nil, fmt.Errorf("mux: missing name or pattern in %q",
- tpl[idxs[i]:end])
- }
- // Build the regexp pattern.
- fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt)
-
- // Build the reverse template.
- fmt.Fprintf(reverse, "%s%%s", raw)
-
- // Append variable name and compiled pattern.
- varsN[i/2] = name
- varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
- if err != nil {
- return nil, err
- }
- }
- // Add the remaining.
- raw := tpl[end:]
- pattern.WriteString(regexp.QuoteMeta(raw))
- if options.strictSlash {
- pattern.WriteString("[/]?")
- }
- if typ == regexpTypeQuery {
- // Add the default pattern if the query value is empty
- if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" {
- pattern.WriteString(defaultPattern)
- }
- }
- if typ != regexpTypePrefix {
- pattern.WriteByte('$')
- }
-
- var wildcardHostPort bool
- if typ == regexpTypeHost {
- if !strings.Contains(pattern.String(), ":") {
- wildcardHostPort = true
- }
- }
- reverse.WriteString(raw)
- if endSlash {
- reverse.WriteByte('/')
- }
- // Compile full regexp.
- reg, errCompile := regexp.Compile(pattern.String())
- if errCompile != nil {
- return nil, errCompile
- }
-
- // Check for capturing groups which used to work in older versions
- if reg.NumSubexp() != len(idxs)/2 {
- panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) +
- "Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)")
- }
-
- // Done!
- return &routeRegexp{
- template: template,
- regexpType: typ,
- options: options,
- regexp: reg,
- reverse: reverse.String(),
- varsN: varsN,
- varsR: varsR,
- wildcardHostPort: wildcardHostPort,
- }, nil
-}
-
-// routeRegexp stores a regexp to match a host or path and information to
-// collect and validate route variables.
-type routeRegexp struct {
- // The unmodified template.
- template string
- // The type of match
- regexpType regexpType
- // Options for matching
- options routeRegexpOptions
- // Expanded regexp.
- regexp *regexp.Regexp
- // Reverse template.
- reverse string
- // Variable names.
- varsN []string
- // Variable regexps (validators).
- varsR []*regexp.Regexp
- // Wildcard host-port (no strict port match in hostname)
- wildcardHostPort bool
-}
-
-// Match matches the regexp against the URL host or path.
-func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
- if r.regexpType == regexpTypeHost {
- host := getHost(req)
- if r.wildcardHostPort {
- // Don't be strict on the port match
- if i := strings.Index(host, ":"); i != -1 {
- host = host[:i]
- }
- }
- return r.regexp.MatchString(host)
- } else {
- if r.regexpType == regexpTypeQuery {
- return r.matchQueryString(req)
- }
- path := req.URL.Path
- if r.options.useEncodedPath {
- path = req.URL.EscapedPath()
- }
- return r.regexp.MatchString(path)
- }
-}
-
-// url builds a URL part using the given values.
-func (r *routeRegexp) url(values map[string]string) (string, error) {
- urlValues := make([]interface{}, len(r.varsN))
- for k, v := range r.varsN {
- value, ok := values[v]
- if !ok {
- return "", fmt.Errorf("mux: missing route variable %q", v)
- }
- if r.regexpType == regexpTypeQuery {
- value = url.QueryEscape(value)
- }
- urlValues[k] = value
- }
- rv := fmt.Sprintf(r.reverse, urlValues...)
- if !r.regexp.MatchString(rv) {
- // The URL is checked against the full regexp, instead of checking
- // individual variables. This is faster but to provide a good error
- // message, we check individual regexps if the URL doesn't match.
- for k, v := range r.varsN {
- if !r.varsR[k].MatchString(values[v]) {
- return "", fmt.Errorf(
- "mux: variable %q doesn't match, expected %q", values[v],
- r.varsR[k].String())
- }
- }
- }
- return rv, nil
-}
-
-// getURLQuery returns a single query parameter from a request URL.
-// For a URL with foo=bar&baz=ding, we return only the relevant key
-// value pair for the routeRegexp.
-func (r *routeRegexp) getURLQuery(req *http.Request) string {
- if r.regexpType != regexpTypeQuery {
- return ""
- }
- templateKey := strings.SplitN(r.template, "=", 2)[0]
- for key, vals := range req.URL.Query() {
- if key == templateKey && len(vals) > 0 {
- return key + "=" + vals[0]
- }
- }
- return ""
-}
-
-func (r *routeRegexp) matchQueryString(req *http.Request) bool {
- return r.regexp.MatchString(r.getURLQuery(req))
-}
-
-// braceIndices returns the first level curly brace indices from a string.
-// It returns an error in case of unbalanced braces.
-func braceIndices(s string) ([]int, error) {
- var level, idx int
- var idxs []int
- for i := 0; i < len(s); i++ {
- switch s[i] {
- case '{':
- if level++; level == 1 {
- idx = i
- }
- case '}':
- if level--; level == 0 {
- idxs = append(idxs, idx, i+1)
- } else if level < 0 {
- return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
- }
- }
- }
- if level != 0 {
- return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
- }
- return idxs, nil
-}
-
-// varGroupName builds a capturing group name for the indexed variable.
-func varGroupName(idx int) string {
- return "v" + strconv.Itoa(idx)
-}
-
-// ----------------------------------------------------------------------------
-// routeRegexpGroup
-// ----------------------------------------------------------------------------
-
-// routeRegexpGroup groups the route matchers that carry variables.
-type routeRegexpGroup struct {
- host *routeRegexp
- path *routeRegexp
- queries []*routeRegexp
-}
-
-// setMatch extracts the variables from the URL once a route matches.
-func (v routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
- // Store host variables.
- if v.host != nil {
- host := getHost(req)
- matches := v.host.regexp.FindStringSubmatchIndex(host)
- if len(matches) > 0 {
- extractVars(host, matches, v.host.varsN, m.Vars)
- }
- }
- path := req.URL.Path
- if r.useEncodedPath {
- path = req.URL.EscapedPath()
- }
- // Store path variables.
- if v.path != nil {
- matches := v.path.regexp.FindStringSubmatchIndex(path)
- if len(matches) > 0 {
- extractVars(path, matches, v.path.varsN, m.Vars)
- // Check if we should redirect.
- if v.path.options.strictSlash {
- p1 := strings.HasSuffix(path, "/")
- p2 := strings.HasSuffix(v.path.template, "/")
- if p1 != p2 {
- u, _ := url.Parse(req.URL.String())
- if p1 {
- u.Path = u.Path[:len(u.Path)-1]
- } else {
- u.Path += "/"
- }
- m.Handler = http.RedirectHandler(u.String(), http.StatusMovedPermanently)
- }
- }
- }
- }
- // Store query string variables.
- for _, q := range v.queries {
- queryURL := q.getURLQuery(req)
- matches := q.regexp.FindStringSubmatchIndex(queryURL)
- if len(matches) > 0 {
- extractVars(queryURL, matches, q.varsN, m.Vars)
- }
- }
-}
-
-// getHost tries its best to return the request host.
-// According to section 14.23 of RFC 2616 the Host header
-// can include the port number if the default value of 80 is not used.
-func getHost(r *http.Request) string {
- if r.URL.IsAbs() {
- return r.URL.Host
- }
- return r.Host
-}
-
-func extractVars(input string, matches []int, names []string, output map[string]string) {
- for i, name := range names {
- output[name] = input[matches[2*i+2]:matches[2*i+3]]
- }
-}
diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go
deleted file mode 100644
index 8479c68c1df..00000000000
--- a/vendor/github.com/gorilla/mux/route.go
+++ /dev/null
@@ -1,710 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import (
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "regexp"
- "strings"
-)
-
-// Route stores information to match a request and build URLs.
-type Route struct {
- // Request handler for the route.
- handler http.Handler
- // If true, this route never matches: it is only used to build URLs.
- buildOnly bool
- // The name used to build URLs.
- name string
- // Error resulted from building a route.
- err error
-
- // "global" reference to all named routes
- namedRoutes map[string]*Route
-
- // config possibly passed in from `Router`
- routeConf
-}
-
-// SkipClean reports whether path cleaning is enabled for this route via
-// Router.SkipClean.
-func (r *Route) SkipClean() bool {
- return r.skipClean
-}
-
-// Match matches the route against the request.
-func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
- if r.buildOnly || r.err != nil {
- return false
- }
-
- var matchErr error
-
- // Match everything.
- for _, m := range r.matchers {
- if matched := m.Match(req, match); !matched {
- if _, ok := m.(methodMatcher); ok {
- matchErr = ErrMethodMismatch
- continue
- }
-
- // Ignore ErrNotFound errors. These errors arise from match call
- // to Subrouters.
- //
- // This prevents subsequent matching subrouters from failing to
- // run middleware. If not ignored, the middleware would see a
- // non-nil MatchErr and be skipped, even when there was a
- // matching route.
- if match.MatchErr == ErrNotFound {
- match.MatchErr = nil
- }
-
- matchErr = nil
- return false
- }
- }
-
- if matchErr != nil {
- match.MatchErr = matchErr
- return false
- }
-
- if match.MatchErr == ErrMethodMismatch {
- // We found a route which matches request method, clear MatchErr
- match.MatchErr = nil
- // Then override the mis-matched handler
- match.Handler = r.handler
- }
-
- // Yay, we have a match. Let's collect some info about it.
- if match.Route == nil {
- match.Route = r
- }
- if match.Handler == nil {
- match.Handler = r.handler
- }
- if match.Vars == nil {
- match.Vars = make(map[string]string)
- }
-
- // Set variables.
- r.regexp.setMatch(req, match, r)
- return true
-}
-
-// ----------------------------------------------------------------------------
-// Route attributes
-// ----------------------------------------------------------------------------
-
-// GetError returns an error resulted from building the route, if any.
-func (r *Route) GetError() error {
- return r.err
-}
-
-// BuildOnly sets the route to never match: it is only used to build URLs.
-func (r *Route) BuildOnly() *Route {
- r.buildOnly = true
- return r
-}
-
-// Handler --------------------------------------------------------------------
-
-// Handler sets a handler for the route.
-func (r *Route) Handler(handler http.Handler) *Route {
- if r.err == nil {
- r.handler = handler
- }
- return r
-}
-
-// HandlerFunc sets a handler function for the route.
-func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route {
- return r.Handler(http.HandlerFunc(f))
-}
-
-// GetHandler returns the handler for the route, if any.
-func (r *Route) GetHandler() http.Handler {
- return r.handler
-}
-
-// Name -----------------------------------------------------------------------
-
-// Name sets the name for the route, used to build URLs.
-// It is an error to call Name more than once on a route.
-func (r *Route) Name(name string) *Route {
- if r.name != "" {
- r.err = fmt.Errorf("mux: route already has name %q, can't set %q",
- r.name, name)
- }
- if r.err == nil {
- r.name = name
- r.namedRoutes[name] = r
- }
- return r
-}
-
-// GetName returns the name for the route, if any.
-func (r *Route) GetName() string {
- return r.name
-}
-
-// ----------------------------------------------------------------------------
-// Matchers
-// ----------------------------------------------------------------------------
-
-// matcher types try to match a request.
-type matcher interface {
- Match(*http.Request, *RouteMatch) bool
-}
-
-// addMatcher adds a matcher to the route.
-func (r *Route) addMatcher(m matcher) *Route {
- if r.err == nil {
- r.matchers = append(r.matchers, m)
- }
- return r
-}
-
-// addRegexpMatcher adds a host or path matcher and builder to a route.
-func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error {
- if r.err != nil {
- return r.err
- }
- if typ == regexpTypePath || typ == regexpTypePrefix {
- if len(tpl) > 0 && tpl[0] != '/' {
- return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
- }
- if r.regexp.path != nil {
- tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
- }
- }
- rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{
- strictSlash: r.strictSlash,
- useEncodedPath: r.useEncodedPath,
- })
- if err != nil {
- return err
- }
- for _, q := range r.regexp.queries {
- if err = uniqueVars(rr.varsN, q.varsN); err != nil {
- return err
- }
- }
- if typ == regexpTypeHost {
- if r.regexp.path != nil {
- if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
- return err
- }
- }
- r.regexp.host = rr
- } else {
- if r.regexp.host != nil {
- if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil {
- return err
- }
- }
- if typ == regexpTypeQuery {
- r.regexp.queries = append(r.regexp.queries, rr)
- } else {
- r.regexp.path = rr
- }
- }
- r.addMatcher(rr)
- return nil
-}
-
-// Headers --------------------------------------------------------------------
-
-// headerMatcher matches the request against header values.
-type headerMatcher map[string]string
-
-func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
- return matchMapWithString(m, r.Header, true)
-}
-
-// Headers adds a matcher for request header values.
-// It accepts a sequence of key/value pairs to be matched. For example:
-//
-// r := mux.NewRouter()
-// r.Headers("Content-Type", "application/json",
-// "X-Requested-With", "XMLHttpRequest")
-//
-// The above route will only match if both request header values match.
-// If the value is an empty string, it will match any value if the key is set.
-func (r *Route) Headers(pairs ...string) *Route {
- if r.err == nil {
- var headers map[string]string
- headers, r.err = mapFromPairsToString(pairs...)
- return r.addMatcher(headerMatcher(headers))
- }
- return r
-}
-
-// headerRegexMatcher matches the request against the route given a regex for the header
-type headerRegexMatcher map[string]*regexp.Regexp
-
-func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
- return matchMapWithRegex(m, r.Header, true)
-}
-
-// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
-// support. For example:
-//
-// r := mux.NewRouter()
-// r.HeadersRegexp("Content-Type", "application/(text|json)",
-// "X-Requested-With", "XMLHttpRequest")
-//
-// The above route will only match if both the request header matches both regular expressions.
-// If the value is an empty string, it will match any value if the key is set.
-// Use the start and end of string anchors (^ and $) to match an exact value.
-func (r *Route) HeadersRegexp(pairs ...string) *Route {
- if r.err == nil {
- var headers map[string]*regexp.Regexp
- headers, r.err = mapFromPairsToRegex(pairs...)
- return r.addMatcher(headerRegexMatcher(headers))
- }
- return r
-}
-
-// Host -----------------------------------------------------------------------
-
-// Host adds a matcher for the URL host.
-// It accepts a template with zero or more URL variables enclosed by {}.
-// Variables can define an optional regexp pattern to be matched:
-//
-// - {name} matches anything until the next dot.
-//
-// - {name:pattern} matches the given regexp pattern.
-//
-// For example:
-//
-// r := mux.NewRouter()
-// r.Host("www.example.com")
-// r.Host("{subdomain}.domain.com")
-// r.Host("{subdomain:[a-z]+}.domain.com")
-//
-// Variable names must be unique in a given route. They can be retrieved
-// calling mux.Vars(request).
-func (r *Route) Host(tpl string) *Route {
- r.err = r.addRegexpMatcher(tpl, regexpTypeHost)
- return r
-}
-
-// MatcherFunc ----------------------------------------------------------------
-
-// MatcherFunc is the function signature used by custom matchers.
-type MatcherFunc func(*http.Request, *RouteMatch) bool
-
-// Match returns the match for a given request.
-func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
- return m(r, match)
-}
-
-// MatcherFunc adds a custom function to be used as request matcher.
-func (r *Route) MatcherFunc(f MatcherFunc) *Route {
- return r.addMatcher(f)
-}
-
-// Methods --------------------------------------------------------------------
-
-// methodMatcher matches the request against HTTP methods.
-type methodMatcher []string
-
-func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool {
- return matchInArray(m, r.Method)
-}
-
-// Methods adds a matcher for HTTP methods.
-// It accepts a sequence of one or more methods to be matched, e.g.:
-// "GET", "POST", "PUT".
-func (r *Route) Methods(methods ...string) *Route {
- for k, v := range methods {
- methods[k] = strings.ToUpper(v)
- }
- return r.addMatcher(methodMatcher(methods))
-}
-
-// Path -----------------------------------------------------------------------
-
-// Path adds a matcher for the URL path.
-// It accepts a template with zero or more URL variables enclosed by {}. The
-// template must start with a "/".
-// Variables can define an optional regexp pattern to be matched:
-//
-// - {name} matches anything until the next slash.
-//
-// - {name:pattern} matches the given regexp pattern.
-//
-// For example:
-//
-// r := mux.NewRouter()
-// r.Path("/products/").Handler(ProductsHandler)
-// r.Path("/products/{key}").Handler(ProductsHandler)
-// r.Path("/articles/{category}/{id:[0-9]+}").
-// Handler(ArticleHandler)
-//
-// Variable names must be unique in a given route. They can be retrieved
-// calling mux.Vars(request).
-func (r *Route) Path(tpl string) *Route {
- r.err = r.addRegexpMatcher(tpl, regexpTypePath)
- return r
-}
-
-// PathPrefix -----------------------------------------------------------------
-
-// PathPrefix adds a matcher for the URL path prefix. This matches if the given
-// template is a prefix of the full URL path. See Route.Path() for details on
-// the tpl argument.
-//
-// Note that it does not treat slashes specially ("/foobar/" will be matched by
-// the prefix "/foo") so you may want to use a trailing slash here.
-//
-// Also note that the setting of Router.StrictSlash() has no effect on routes
-// with a PathPrefix matcher.
-func (r *Route) PathPrefix(tpl string) *Route {
- r.err = r.addRegexpMatcher(tpl, regexpTypePrefix)
- return r
-}
-
-// Query ----------------------------------------------------------------------
-
-// Queries adds a matcher for URL query values.
-// It accepts a sequence of key/value pairs. Values may define variables.
-// For example:
-//
-// r := mux.NewRouter()
-// r.Queries("foo", "bar", "id", "{id:[0-9]+}")
-//
-// The above route will only match if the URL contains the defined queries
-// values, e.g.: ?foo=bar&id=42.
-//
-// If the value is an empty string, it will match any value if the key is set.
-//
-// Variables can define an optional regexp pattern to be matched:
-//
-// - {name} matches anything until the next slash.
-//
-// - {name:pattern} matches the given regexp pattern.
-func (r *Route) Queries(pairs ...string) *Route {
- length := len(pairs)
- if length%2 != 0 {
- r.err = fmt.Errorf(
- "mux: number of parameters must be multiple of 2, got %v", pairs)
- return nil
- }
- for i := 0; i < length; i += 2 {
- if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery); r.err != nil {
- return r
- }
- }
-
- return r
-}
-
-// Schemes --------------------------------------------------------------------
-
-// schemeMatcher matches the request against URL schemes.
-type schemeMatcher []string
-
-func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool {
- return matchInArray(m, r.URL.Scheme)
-}
-
-// Schemes adds a matcher for URL schemes.
-// It accepts a sequence of schemes to be matched, e.g.: "http", "https".
-func (r *Route) Schemes(schemes ...string) *Route {
- for k, v := range schemes {
- schemes[k] = strings.ToLower(v)
- }
- if len(schemes) > 0 {
- r.buildScheme = schemes[0]
- }
- return r.addMatcher(schemeMatcher(schemes))
-}
-
-// BuildVarsFunc --------------------------------------------------------------
-
-// BuildVarsFunc is the function signature used by custom build variable
-// functions (which can modify route variables before a route's URL is built).
-type BuildVarsFunc func(map[string]string) map[string]string
-
-// BuildVarsFunc adds a custom function to be used to modify build variables
-// before a route's URL is built.
-func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
- if r.buildVarsFunc != nil {
- // compose the old and new functions
- old := r.buildVarsFunc
- r.buildVarsFunc = func(m map[string]string) map[string]string {
- return f(old(m))
- }
- } else {
- r.buildVarsFunc = f
- }
- return r
-}
-
-// Subrouter ------------------------------------------------------------------
-
-// Subrouter creates a subrouter for the route.
-//
-// It will test the inner routes only if the parent route matched. For example:
-//
-// r := mux.NewRouter()
-// s := r.Host("www.example.com").Subrouter()
-// s.HandleFunc("/products/", ProductsHandler)
-// s.HandleFunc("/products/{key}", ProductHandler)
-// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
-//
-// Here, the routes registered in the subrouter won't be tested if the host
-// doesn't match.
-func (r *Route) Subrouter() *Router {
- // initialize a subrouter with a copy of the parent route's configuration
- router := &Router{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
- r.addMatcher(router)
- return router
-}
-
-// ----------------------------------------------------------------------------
-// URL building
-// ----------------------------------------------------------------------------
-
-// URL builds a URL for the route.
-//
-// It accepts a sequence of key/value pairs for the route variables. For
-// example, given this route:
-//
-// r := mux.NewRouter()
-// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
-// Name("article")
-//
-// ...a URL for it can be built using:
-//
-// url, err := r.Get("article").URL("category", "technology", "id", "42")
-//
-// ...which will return an url.URL with the following path:
-//
-// "/articles/technology/42"
-//
-// This also works for host variables:
-//
-// r := mux.NewRouter()
-// r.Host("{subdomain}.domain.com").
-// HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
-// Name("article")
-//
-// // url.String() will be "http://news.domain.com/articles/technology/42"
-// url, err := r.Get("article").URL("subdomain", "news",
-// "category", "technology",
-// "id", "42")
-//
-// All variables defined in the route are required, and their values must
-// conform to the corresponding patterns.
-func (r *Route) URL(pairs ...string) (*url.URL, error) {
- if r.err != nil {
- return nil, r.err
- }
- values, err := r.prepareVars(pairs...)
- if err != nil {
- return nil, err
- }
- var scheme, host, path string
- queries := make([]string, 0, len(r.regexp.queries))
- if r.regexp.host != nil {
- if host, err = r.regexp.host.url(values); err != nil {
- return nil, err
- }
- scheme = "http"
- if r.buildScheme != "" {
- scheme = r.buildScheme
- }
- }
- if r.regexp.path != nil {
- if path, err = r.regexp.path.url(values); err != nil {
- return nil, err
- }
- }
- for _, q := range r.regexp.queries {
- var query string
- if query, err = q.url(values); err != nil {
- return nil, err
- }
- queries = append(queries, query)
- }
- return &url.URL{
- Scheme: scheme,
- Host: host,
- Path: path,
- RawQuery: strings.Join(queries, "&"),
- }, nil
-}
-
-// URLHost builds the host part of the URL for a route. See Route.URL().
-//
-// The route must have a host defined.
-func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
- if r.err != nil {
- return nil, r.err
- }
- if r.regexp.host == nil {
- return nil, errors.New("mux: route doesn't have a host")
- }
- values, err := r.prepareVars(pairs...)
- if err != nil {
- return nil, err
- }
- host, err := r.regexp.host.url(values)
- if err != nil {
- return nil, err
- }
- u := &url.URL{
- Scheme: "http",
- Host: host,
- }
- if r.buildScheme != "" {
- u.Scheme = r.buildScheme
- }
- return u, nil
-}
-
-// URLPath builds the path part of the URL for a route. See Route.URL().
-//
-// The route must have a path defined.
-func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
- if r.err != nil {
- return nil, r.err
- }
- if r.regexp.path == nil {
- return nil, errors.New("mux: route doesn't have a path")
- }
- values, err := r.prepareVars(pairs...)
- if err != nil {
- return nil, err
- }
- path, err := r.regexp.path.url(values)
- if err != nil {
- return nil, err
- }
- return &url.URL{
- Path: path,
- }, nil
-}
-
-// GetPathTemplate returns the template used to build the
-// route match.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An error will be returned if the route does not define a path.
-func (r *Route) GetPathTemplate() (string, error) {
- if r.err != nil {
- return "", r.err
- }
- if r.regexp.path == nil {
- return "", errors.New("mux: route doesn't have a path")
- }
- return r.regexp.path.template, nil
-}
-
-// GetPathRegexp returns the expanded regular expression used to match route path.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An error will be returned if the route does not define a path.
-func (r *Route) GetPathRegexp() (string, error) {
- if r.err != nil {
- return "", r.err
- }
- if r.regexp.path == nil {
- return "", errors.New("mux: route does not have a path")
- }
- return r.regexp.path.regexp.String(), nil
-}
-
-// GetQueriesRegexp returns the expanded regular expressions used to match the
-// route queries.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An error will be returned if the route does not have queries.
-func (r *Route) GetQueriesRegexp() ([]string, error) {
- if r.err != nil {
- return nil, r.err
- }
- if r.regexp.queries == nil {
- return nil, errors.New("mux: route doesn't have queries")
- }
- var queries []string
- for _, query := range r.regexp.queries {
- queries = append(queries, query.regexp.String())
- }
- return queries, nil
-}
-
-// GetQueriesTemplates returns the templates used to build the
-// query matching.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An error will be returned if the route does not define queries.
-func (r *Route) GetQueriesTemplates() ([]string, error) {
- if r.err != nil {
- return nil, r.err
- }
- if r.regexp.queries == nil {
- return nil, errors.New("mux: route doesn't have queries")
- }
- var queries []string
- for _, query := range r.regexp.queries {
- queries = append(queries, query.template)
- }
- return queries, nil
-}
-
-// GetMethods returns the methods the route matches against
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An error will be returned if route does not have methods.
-func (r *Route) GetMethods() ([]string, error) {
- if r.err != nil {
- return nil, r.err
- }
- for _, m := range r.matchers {
- if methods, ok := m.(methodMatcher); ok {
- return []string(methods), nil
- }
- }
- return nil, errors.New("mux: route doesn't have methods")
-}
-
-// GetHostTemplate returns the template used to build the
-// route match.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An error will be returned if the route does not define a host.
-func (r *Route) GetHostTemplate() (string, error) {
- if r.err != nil {
- return "", r.err
- }
- if r.regexp.host == nil {
- return "", errors.New("mux: route doesn't have a host")
- }
- return r.regexp.host.template, nil
-}
-
-// prepareVars converts the route variable pairs into a map. If the route has a
-// BuildVarsFunc, it is invoked.
-func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
- m, err := mapFromPairsToString(pairs...)
- if err != nil {
- return nil, err
- }
- return r.buildVars(m), nil
-}
-
-func (r *Route) buildVars(m map[string]string) map[string]string {
- if r.buildVarsFunc != nil {
- m = r.buildVarsFunc(m)
- }
- return m
-}
diff --git a/vendor/github.com/gorilla/mux/test_helpers.go b/vendor/github.com/gorilla/mux/test_helpers.go
deleted file mode 100644
index 32ecffde489..00000000000
--- a/vendor/github.com/gorilla/mux/test_helpers.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import "net/http"
-
-// SetURLVars sets the URL variables for the given request, to be accessed via
-// mux.Vars for testing route behaviour. Arguments are not modified, a shallow
-// copy is returned.
-//
-// This API should only be used for testing purposes; it provides a way to
-// inject variables into the request context. Alternatively, URL variables
-// can be set by making a route that captures the required variables,
-// starting a server and sending the request to that server.
-func SetURLVars(r *http.Request, val map[string]string) *http.Request {
- return setVars(r, val)
-}
diff --git a/vendor/github.com/gorilla/websocket/.gitignore b/vendor/github.com/gorilla/websocket/.gitignore
deleted file mode 100644
index cd3fcd1ef72..00000000000
--- a/vendor/github.com/gorilla/websocket/.gitignore
+++ /dev/null
@@ -1,25 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-
-.idea/
-*.iml
diff --git a/vendor/github.com/gorilla/websocket/AUTHORS b/vendor/github.com/gorilla/websocket/AUTHORS
deleted file mode 100644
index 1931f400682..00000000000
--- a/vendor/github.com/gorilla/websocket/AUTHORS
+++ /dev/null
@@ -1,9 +0,0 @@
-# This is the official list of Gorilla WebSocket authors for copyright
-# purposes.
-#
-# Please keep the list sorted.
-
-Gary Burd
-Google LLC (https://opensource.google.com/)
-Joachim Bauch
-
diff --git a/vendor/github.com/gorilla/websocket/LICENSE b/vendor/github.com/gorilla/websocket/LICENSE
deleted file mode 100644
index 9171c972252..00000000000
--- a/vendor/github.com/gorilla/websocket/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
- Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md
deleted file mode 100644
index 19aa2e75c82..00000000000
--- a/vendor/github.com/gorilla/websocket/README.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# Gorilla WebSocket
-
-[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket)
-[![CircleCI](https://circleci.com/gh/gorilla/websocket.svg?style=svg)](https://circleci.com/gh/gorilla/websocket)
-
-Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
-[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
-
-### Documentation
-
-* [API Reference](https://pkg.go.dev/github.com/gorilla/websocket?tab=doc)
-* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat)
-* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command)
-* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo)
-* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch)
-
-### Status
-
-The Gorilla WebSocket package provides a complete and tested implementation of
-the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The
-package API is stable.
-
-### Installation
-
- go get github.com/gorilla/websocket
-
-### Protocol Compliance
-
-The Gorilla WebSocket package passes the server tests in the [Autobahn Test
-Suite](https://github.com/crossbario/autobahn-testsuite) using the application in the [examples/autobahn
-subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn).
-
-### Gorilla WebSocket compared with other packages
-
-
-
-Notes:
-
-1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html).
-2. The application can get the type of a received data message by implementing
- a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal)
- function.
-3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries.
- Read returns when the input buffer is full or a frame boundary is
- encountered. Each call to Write sends a single frame message. The Gorilla
- io.Reader and io.WriteCloser operate on a single WebSocket message.
-
diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go
deleted file mode 100644
index 962c06a391c..00000000000
--- a/vendor/github.com/gorilla/websocket/client.go
+++ /dev/null
@@ -1,395 +0,0 @@
-// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bytes"
- "context"
- "crypto/tls"
- "errors"
- "io"
- "io/ioutil"
- "net"
- "net/http"
- "net/http/httptrace"
- "net/url"
- "strings"
- "time"
-)
-
-// ErrBadHandshake is returned when the server response to opening handshake is
-// invalid.
-var ErrBadHandshake = errors.New("websocket: bad handshake")
-
-var errInvalidCompression = errors.New("websocket: invalid compression negotiation")
-
-// NewClient creates a new client connection using the given net connection.
-// The URL u specifies the host and request URI. Use requestHeader to specify
-// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
-// (Cookie). Use the response.Header to get the selected subprotocol
-// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
-//
-// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
-// non-nil *http.Response so that callers can handle redirects, authentication,
-// etc.
-//
-// Deprecated: Use Dialer instead.
-func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) {
- d := Dialer{
- ReadBufferSize: readBufSize,
- WriteBufferSize: writeBufSize,
- NetDial: func(net, addr string) (net.Conn, error) {
- return netConn, nil
- },
- }
- return d.Dial(u.String(), requestHeader)
-}
-
-// A Dialer contains options for connecting to WebSocket server.
-type Dialer struct {
- // NetDial specifies the dial function for creating TCP connections. If
- // NetDial is nil, net.Dial is used.
- NetDial func(network, addr string) (net.Conn, error)
-
- // NetDialContext specifies the dial function for creating TCP connections. If
- // NetDialContext is nil, net.DialContext is used.
- NetDialContext func(ctx context.Context, network, addr string) (net.Conn, error)
-
- // Proxy specifies a function to return a proxy for a given
- // Request. If the function returns a non-nil error, the
- // request is aborted with the provided error.
- // If Proxy is nil or returns a nil *URL, no proxy is used.
- Proxy func(*http.Request) (*url.URL, error)
-
- // TLSClientConfig specifies the TLS configuration to use with tls.Client.
- // If nil, the default configuration is used.
- TLSClientConfig *tls.Config
-
- // HandshakeTimeout specifies the duration for the handshake to complete.
- HandshakeTimeout time.Duration
-
- // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
- // size is zero, then a useful default size is used. The I/O buffer sizes
- // do not limit the size of the messages that can be sent or received.
- ReadBufferSize, WriteBufferSize int
-
- // WriteBufferPool is a pool of buffers for write operations. If the value
- // is not set, then write buffers are allocated to the connection for the
- // lifetime of the connection.
- //
- // A pool is most useful when the application has a modest volume of writes
- // across a large number of connections.
- //
- // Applications should use a single pool for each unique value of
- // WriteBufferSize.
- WriteBufferPool BufferPool
-
- // Subprotocols specifies the client's requested subprotocols.
- Subprotocols []string
-
- // EnableCompression specifies if the client should attempt to negotiate
- // per message compression (RFC 7692). Setting this value to true does not
- // guarantee that compression will be supported. Currently only "no context
- // takeover" modes are supported.
- EnableCompression bool
-
- // Jar specifies the cookie jar.
- // If Jar is nil, cookies are not sent in requests and ignored
- // in responses.
- Jar http.CookieJar
-}
-
-// Dial creates a new client connection by calling DialContext with a background context.
-func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
- return d.DialContext(context.Background(), urlStr, requestHeader)
-}
-
-var errMalformedURL = errors.New("malformed ws or wss URL")
-
-func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
- hostPort = u.Host
- hostNoPort = u.Host
- if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") {
- hostNoPort = hostNoPort[:i]
- } else {
- switch u.Scheme {
- case "wss":
- hostPort += ":443"
- case "https":
- hostPort += ":443"
- default:
- hostPort += ":80"
- }
- }
- return hostPort, hostNoPort
-}
-
-// DefaultDialer is a dialer with all fields set to the default values.
-var DefaultDialer = &Dialer{
- Proxy: http.ProxyFromEnvironment,
- HandshakeTimeout: 45 * time.Second,
-}
-
-// nilDialer is dialer to use when receiver is nil.
-var nilDialer = *DefaultDialer
-
-// DialContext creates a new client connection. Use requestHeader to specify the
-// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie).
-// Use the response.Header to get the selected subprotocol
-// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
-//
-// The context will be used in the request and in the Dialer.
-//
-// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
-// non-nil *http.Response so that callers can handle redirects, authentication,
-// etcetera. The response body may not contain the entire response and does not
-// need to be closed by the application.
-func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
- if d == nil {
- d = &nilDialer
- }
-
- challengeKey, err := generateChallengeKey()
- if err != nil {
- return nil, nil, err
- }
-
- u, err := url.Parse(urlStr)
- if err != nil {
- return nil, nil, err
- }
-
- switch u.Scheme {
- case "ws":
- u.Scheme = "http"
- case "wss":
- u.Scheme = "https"
- default:
- return nil, nil, errMalformedURL
- }
-
- if u.User != nil {
- // User name and password are not allowed in websocket URIs.
- return nil, nil, errMalformedURL
- }
-
- req := &http.Request{
- Method: "GET",
- URL: u,
- Proto: "HTTP/1.1",
- ProtoMajor: 1,
- ProtoMinor: 1,
- Header: make(http.Header),
- Host: u.Host,
- }
- req = req.WithContext(ctx)
-
- // Set the cookies present in the cookie jar of the dialer
- if d.Jar != nil {
- for _, cookie := range d.Jar.Cookies(u) {
- req.AddCookie(cookie)
- }
- }
-
- // Set the request headers using the capitalization for names and values in
- // RFC examples. Although the capitalization shouldn't matter, there are
- // servers that depend on it. The Header.Set method is not used because the
- // method canonicalizes the header names.
- req.Header["Upgrade"] = []string{"websocket"}
- req.Header["Connection"] = []string{"Upgrade"}
- req.Header["Sec-WebSocket-Key"] = []string{challengeKey}
- req.Header["Sec-WebSocket-Version"] = []string{"13"}
- if len(d.Subprotocols) > 0 {
- req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")}
- }
- for k, vs := range requestHeader {
- switch {
- case k == "Host":
- if len(vs) > 0 {
- req.Host = vs[0]
- }
- case k == "Upgrade" ||
- k == "Connection" ||
- k == "Sec-Websocket-Key" ||
- k == "Sec-Websocket-Version" ||
- k == "Sec-Websocket-Extensions" ||
- (k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
- return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
- case k == "Sec-Websocket-Protocol":
- req.Header["Sec-WebSocket-Protocol"] = vs
- default:
- req.Header[k] = vs
- }
- }
-
- if d.EnableCompression {
- req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"}
- }
-
- if d.HandshakeTimeout != 0 {
- var cancel func()
- ctx, cancel = context.WithTimeout(ctx, d.HandshakeTimeout)
- defer cancel()
- }
-
- // Get network dial function.
- var netDial func(network, add string) (net.Conn, error)
-
- if d.NetDialContext != nil {
- netDial = func(network, addr string) (net.Conn, error) {
- return d.NetDialContext(ctx, network, addr)
- }
- } else if d.NetDial != nil {
- netDial = d.NetDial
- } else {
- netDialer := &net.Dialer{}
- netDial = func(network, addr string) (net.Conn, error) {
- return netDialer.DialContext(ctx, network, addr)
- }
- }
-
- // If needed, wrap the dial function to set the connection deadline.
- if deadline, ok := ctx.Deadline(); ok {
- forwardDial := netDial
- netDial = func(network, addr string) (net.Conn, error) {
- c, err := forwardDial(network, addr)
- if err != nil {
- return nil, err
- }
- err = c.SetDeadline(deadline)
- if err != nil {
- c.Close()
- return nil, err
- }
- return c, nil
- }
- }
-
- // If needed, wrap the dial function to connect through a proxy.
- if d.Proxy != nil {
- proxyURL, err := d.Proxy(req)
- if err != nil {
- return nil, nil, err
- }
- if proxyURL != nil {
- dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial))
- if err != nil {
- return nil, nil, err
- }
- netDial = dialer.Dial
- }
- }
-
- hostPort, hostNoPort := hostPortNoPort(u)
- trace := httptrace.ContextClientTrace(ctx)
- if trace != nil && trace.GetConn != nil {
- trace.GetConn(hostPort)
- }
-
- netConn, err := netDial("tcp", hostPort)
- if trace != nil && trace.GotConn != nil {
- trace.GotConn(httptrace.GotConnInfo{
- Conn: netConn,
- })
- }
- if err != nil {
- return nil, nil, err
- }
-
- defer func() {
- if netConn != nil {
- netConn.Close()
- }
- }()
-
- if u.Scheme == "https" {
- cfg := cloneTLSConfig(d.TLSClientConfig)
- if cfg.ServerName == "" {
- cfg.ServerName = hostNoPort
- }
- tlsConn := tls.Client(netConn, cfg)
- netConn = tlsConn
-
- var err error
- if trace != nil {
- err = doHandshakeWithTrace(trace, tlsConn, cfg)
- } else {
- err = doHandshake(tlsConn, cfg)
- }
-
- if err != nil {
- return nil, nil, err
- }
- }
-
- conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize, d.WriteBufferPool, nil, nil)
-
- if err := req.Write(netConn); err != nil {
- return nil, nil, err
- }
-
- if trace != nil && trace.GotFirstResponseByte != nil {
- if peek, err := conn.br.Peek(1); err == nil && len(peek) == 1 {
- trace.GotFirstResponseByte()
- }
- }
-
- resp, err := http.ReadResponse(conn.br, req)
- if err != nil {
- return nil, nil, err
- }
-
- if d.Jar != nil {
- if rc := resp.Cookies(); len(rc) > 0 {
- d.Jar.SetCookies(u, rc)
- }
- }
-
- if resp.StatusCode != 101 ||
- !strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
- !strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
- resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) {
- // Before closing the network connection on return from this
- // function, slurp up some of the response to aid application
- // debugging.
- buf := make([]byte, 1024)
- n, _ := io.ReadFull(resp.Body, buf)
- resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n]))
- return nil, resp, ErrBadHandshake
- }
-
- for _, ext := range parseExtensions(resp.Header) {
- if ext[""] != "permessage-deflate" {
- continue
- }
- _, snct := ext["server_no_context_takeover"]
- _, cnct := ext["client_no_context_takeover"]
- if !snct || !cnct {
- return nil, resp, errInvalidCompression
- }
- conn.newCompressionWriter = compressNoContextTakeover
- conn.newDecompressionReader = decompressNoContextTakeover
- break
- }
-
- resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
- conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")
-
- netConn.SetDeadline(time.Time{})
- netConn = nil // to avoid close in defer.
- return conn, resp, nil
-}
-
-func doHandshake(tlsConn *tls.Conn, cfg *tls.Config) error {
- if err := tlsConn.Handshake(); err != nil {
- return err
- }
- if !cfg.InsecureSkipVerify {
- if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
- return err
- }
- }
- return nil
-}
diff --git a/vendor/github.com/gorilla/websocket/client_clone.go b/vendor/github.com/gorilla/websocket/client_clone.go
deleted file mode 100644
index 4f0d943723a..00000000000
--- a/vendor/github.com/gorilla/websocket/client_clone.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.8
-
-package websocket
-
-import "crypto/tls"
-
-func cloneTLSConfig(cfg *tls.Config) *tls.Config {
- if cfg == nil {
- return &tls.Config{}
- }
- return cfg.Clone()
-}
diff --git a/vendor/github.com/gorilla/websocket/client_clone_legacy.go b/vendor/github.com/gorilla/websocket/client_clone_legacy.go
deleted file mode 100644
index babb007fb41..00000000000
--- a/vendor/github.com/gorilla/websocket/client_clone_legacy.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !go1.8
-
-package websocket
-
-import "crypto/tls"
-
-// cloneTLSConfig clones all public fields except the fields
-// SessionTicketsDisabled and SessionTicketKey. This avoids copying the
-// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a
-// config in active use.
-func cloneTLSConfig(cfg *tls.Config) *tls.Config {
- if cfg == nil {
- return &tls.Config{}
- }
- return &tls.Config{
- Rand: cfg.Rand,
- Time: cfg.Time,
- Certificates: cfg.Certificates,
- NameToCertificate: cfg.NameToCertificate,
- GetCertificate: cfg.GetCertificate,
- RootCAs: cfg.RootCAs,
- NextProtos: cfg.NextProtos,
- ServerName: cfg.ServerName,
- ClientAuth: cfg.ClientAuth,
- ClientCAs: cfg.ClientCAs,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- CipherSuites: cfg.CipherSuites,
- PreferServerCipherSuites: cfg.PreferServerCipherSuites,
- ClientSessionCache: cfg.ClientSessionCache,
- MinVersion: cfg.MinVersion,
- MaxVersion: cfg.MaxVersion,
- CurvePreferences: cfg.CurvePreferences,
- }
-}
diff --git a/vendor/github.com/gorilla/websocket/compression.go b/vendor/github.com/gorilla/websocket/compression.go
deleted file mode 100644
index 813ffb1e843..00000000000
--- a/vendor/github.com/gorilla/websocket/compression.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "compress/flate"
- "errors"
- "io"
- "strings"
- "sync"
-)
-
-const (
- minCompressionLevel = -2 // flate.HuffmanOnly not defined in Go < 1.6
- maxCompressionLevel = flate.BestCompression
- defaultCompressionLevel = 1
-)
-
-var (
- flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool
- flateReaderPool = sync.Pool{New: func() interface{} {
- return flate.NewReader(nil)
- }}
-)
-
-func decompressNoContextTakeover(r io.Reader) io.ReadCloser {
- const tail =
- // Add four bytes as specified in RFC
- "\x00\x00\xff\xff" +
- // Add final block to squelch unexpected EOF error from flate reader.
- "\x01\x00\x00\xff\xff"
-
- fr, _ := flateReaderPool.Get().(io.ReadCloser)
- fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil)
- return &flateReadWrapper{fr}
-}
-
-func isValidCompressionLevel(level int) bool {
- return minCompressionLevel <= level && level <= maxCompressionLevel
-}
-
-func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser {
- p := &flateWriterPools[level-minCompressionLevel]
- tw := &truncWriter{w: w}
- fw, _ := p.Get().(*flate.Writer)
- if fw == nil {
- fw, _ = flate.NewWriter(tw, level)
- } else {
- fw.Reset(tw)
- }
- return &flateWriteWrapper{fw: fw, tw: tw, p: p}
-}
-
-// truncWriter is an io.Writer that writes all but the last four bytes of the
-// stream to another io.Writer.
-type truncWriter struct {
- w io.WriteCloser
- n int
- p [4]byte
-}
-
-func (w *truncWriter) Write(p []byte) (int, error) {
- n := 0
-
- // fill buffer first for simplicity.
- if w.n < len(w.p) {
- n = copy(w.p[w.n:], p)
- p = p[n:]
- w.n += n
- if len(p) == 0 {
- return n, nil
- }
- }
-
- m := len(p)
- if m > len(w.p) {
- m = len(w.p)
- }
-
- if nn, err := w.w.Write(w.p[:m]); err != nil {
- return n + nn, err
- }
-
- copy(w.p[:], w.p[m:])
- copy(w.p[len(w.p)-m:], p[len(p)-m:])
- nn, err := w.w.Write(p[:len(p)-m])
- return n + nn, err
-}
-
-type flateWriteWrapper struct {
- fw *flate.Writer
- tw *truncWriter
- p *sync.Pool
-}
-
-func (w *flateWriteWrapper) Write(p []byte) (int, error) {
- if w.fw == nil {
- return 0, errWriteClosed
- }
- return w.fw.Write(p)
-}
-
-func (w *flateWriteWrapper) Close() error {
- if w.fw == nil {
- return errWriteClosed
- }
- err1 := w.fw.Flush()
- w.p.Put(w.fw)
- w.fw = nil
- if w.tw.p != [4]byte{0, 0, 0xff, 0xff} {
- return errors.New("websocket: internal error, unexpected bytes at end of flate stream")
- }
- err2 := w.tw.w.Close()
- if err1 != nil {
- return err1
- }
- return err2
-}
-
-type flateReadWrapper struct {
- fr io.ReadCloser
-}
-
-func (r *flateReadWrapper) Read(p []byte) (int, error) {
- if r.fr == nil {
- return 0, io.ErrClosedPipe
- }
- n, err := r.fr.Read(p)
- if err == io.EOF {
- // Preemptively place the reader back in the pool. This helps with
- // scenarios where the application does not call NextReader() soon after
- // this final read.
- r.Close()
- }
- return n, err
-}
-
-func (r *flateReadWrapper) Close() error {
- if r.fr == nil {
- return io.ErrClosedPipe
- }
- err := r.fr.Close()
- flateReaderPool.Put(r.fr)
- r.fr = nil
- return err
-}
diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go
deleted file mode 100644
index ca46d2f793c..00000000000
--- a/vendor/github.com/gorilla/websocket/conn.go
+++ /dev/null
@@ -1,1201 +0,0 @@
-// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bufio"
- "encoding/binary"
- "errors"
- "io"
- "io/ioutil"
- "math/rand"
- "net"
- "strconv"
- "sync"
- "time"
- "unicode/utf8"
-)
-
-const (
- // Frame header byte 0 bits from Section 5.2 of RFC 6455
- finalBit = 1 << 7
- rsv1Bit = 1 << 6
- rsv2Bit = 1 << 5
- rsv3Bit = 1 << 4
-
- // Frame header byte 1 bits from Section 5.2 of RFC 6455
- maskBit = 1 << 7
-
- maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask
- maxControlFramePayloadSize = 125
-
- writeWait = time.Second
-
- defaultReadBufferSize = 4096
- defaultWriteBufferSize = 4096
-
- continuationFrame = 0
- noFrame = -1
-)
-
-// Close codes defined in RFC 6455, section 11.7.
-const (
- CloseNormalClosure = 1000
- CloseGoingAway = 1001
- CloseProtocolError = 1002
- CloseUnsupportedData = 1003
- CloseNoStatusReceived = 1005
- CloseAbnormalClosure = 1006
- CloseInvalidFramePayloadData = 1007
- ClosePolicyViolation = 1008
- CloseMessageTooBig = 1009
- CloseMandatoryExtension = 1010
- CloseInternalServerErr = 1011
- CloseServiceRestart = 1012
- CloseTryAgainLater = 1013
- CloseTLSHandshake = 1015
-)
-
-// The message types are defined in RFC 6455, section 11.8.
-const (
- // TextMessage denotes a text data message. The text message payload is
- // interpreted as UTF-8 encoded text data.
- TextMessage = 1
-
- // BinaryMessage denotes a binary data message.
- BinaryMessage = 2
-
- // CloseMessage denotes a close control message. The optional message
- // payload contains a numeric code and text. Use the FormatCloseMessage
- // function to format a close message payload.
- CloseMessage = 8
-
- // PingMessage denotes a ping control message. The optional message payload
- // is UTF-8 encoded text.
- PingMessage = 9
-
- // PongMessage denotes a pong control message. The optional message payload
- // is UTF-8 encoded text.
- PongMessage = 10
-)
-
-// ErrCloseSent is returned when the application writes a message to the
-// connection after sending a close message.
-var ErrCloseSent = errors.New("websocket: close sent")
-
-// ErrReadLimit is returned when reading a message that is larger than the
-// read limit set for the connection.
-var ErrReadLimit = errors.New("websocket: read limit exceeded")
-
-// netError satisfies the net Error interface.
-type netError struct {
- msg string
- temporary bool
- timeout bool
-}
-
-func (e *netError) Error() string { return e.msg }
-func (e *netError) Temporary() bool { return e.temporary }
-func (e *netError) Timeout() bool { return e.timeout }
-
-// CloseError represents a close message.
-type CloseError struct {
- // Code is defined in RFC 6455, section 11.7.
- Code int
-
- // Text is the optional text payload.
- Text string
-}
-
-func (e *CloseError) Error() string {
- s := []byte("websocket: close ")
- s = strconv.AppendInt(s, int64(e.Code), 10)
- switch e.Code {
- case CloseNormalClosure:
- s = append(s, " (normal)"...)
- case CloseGoingAway:
- s = append(s, " (going away)"...)
- case CloseProtocolError:
- s = append(s, " (protocol error)"...)
- case CloseUnsupportedData:
- s = append(s, " (unsupported data)"...)
- case CloseNoStatusReceived:
- s = append(s, " (no status)"...)
- case CloseAbnormalClosure:
- s = append(s, " (abnormal closure)"...)
- case CloseInvalidFramePayloadData:
- s = append(s, " (invalid payload data)"...)
- case ClosePolicyViolation:
- s = append(s, " (policy violation)"...)
- case CloseMessageTooBig:
- s = append(s, " (message too big)"...)
- case CloseMandatoryExtension:
- s = append(s, " (mandatory extension missing)"...)
- case CloseInternalServerErr:
- s = append(s, " (internal server error)"...)
- case CloseTLSHandshake:
- s = append(s, " (TLS handshake error)"...)
- }
- if e.Text != "" {
- s = append(s, ": "...)
- s = append(s, e.Text...)
- }
- return string(s)
-}
-
-// IsCloseError returns boolean indicating whether the error is a *CloseError
-// with one of the specified codes.
-func IsCloseError(err error, codes ...int) bool {
- if e, ok := err.(*CloseError); ok {
- for _, code := range codes {
- if e.Code == code {
- return true
- }
- }
- }
- return false
-}
-
-// IsUnexpectedCloseError returns boolean indicating whether the error is a
-// *CloseError with a code not in the list of expected codes.
-func IsUnexpectedCloseError(err error, expectedCodes ...int) bool {
- if e, ok := err.(*CloseError); ok {
- for _, code := range expectedCodes {
- if e.Code == code {
- return false
- }
- }
- return true
- }
- return false
-}
-
-var (
- errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true, temporary: true}
- errUnexpectedEOF = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()}
- errBadWriteOpCode = errors.New("websocket: bad write message type")
- errWriteClosed = errors.New("websocket: write closed")
- errInvalidControlFrame = errors.New("websocket: invalid control frame")
-)
-
-func newMaskKey() [4]byte {
- n := rand.Uint32()
- return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
-}
-
-func hideTempErr(err error) error {
- if e, ok := err.(net.Error); ok && e.Temporary() {
- err = &netError{msg: e.Error(), timeout: e.Timeout()}
- }
- return err
-}
-
-func isControl(frameType int) bool {
- return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage
-}
-
-func isData(frameType int) bool {
- return frameType == TextMessage || frameType == BinaryMessage
-}
-
-var validReceivedCloseCodes = map[int]bool{
- // see http://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number
-
- CloseNormalClosure: true,
- CloseGoingAway: true,
- CloseProtocolError: true,
- CloseUnsupportedData: true,
- CloseNoStatusReceived: false,
- CloseAbnormalClosure: false,
- CloseInvalidFramePayloadData: true,
- ClosePolicyViolation: true,
- CloseMessageTooBig: true,
- CloseMandatoryExtension: true,
- CloseInternalServerErr: true,
- CloseServiceRestart: true,
- CloseTryAgainLater: true,
- CloseTLSHandshake: false,
-}
-
-func isValidReceivedCloseCode(code int) bool {
- return validReceivedCloseCodes[code] || (code >= 3000 && code <= 4999)
-}
-
-// BufferPool represents a pool of buffers. The *sync.Pool type satisfies this
-// interface. The type of the value stored in a pool is not specified.
-type BufferPool interface {
- // Get gets a value from the pool or returns nil if the pool is empty.
- Get() interface{}
- // Put adds a value to the pool.
- Put(interface{})
-}
-
-// writePoolData is the type added to the write buffer pool. This wrapper is
-// used to prevent applications from peeking at and depending on the values
-// added to the pool.
-type writePoolData struct{ buf []byte }
-
-// The Conn type represents a WebSocket connection.
-type Conn struct {
- conn net.Conn
- isServer bool
- subprotocol string
-
- // Write fields
- mu chan struct{} // used as mutex to protect write to conn
- writeBuf []byte // frame is constructed in this buffer.
- writePool BufferPool
- writeBufSize int
- writeDeadline time.Time
- writer io.WriteCloser // the current writer returned to the application
- isWriting bool // for best-effort concurrent write detection
-
- writeErrMu sync.Mutex
- writeErr error
-
- enableWriteCompression bool
- compressionLevel int
- newCompressionWriter func(io.WriteCloser, int) io.WriteCloser
-
- // Read fields
- reader io.ReadCloser // the current reader returned to the application
- readErr error
- br *bufio.Reader
- // bytes remaining in current frame.
- // set setReadRemaining to safely update this value and prevent overflow
- readRemaining int64
- readFinal bool // true the current message has more frames.
- readLength int64 // Message size.
- readLimit int64 // Maximum message size.
- readMaskPos int
- readMaskKey [4]byte
- handlePong func(string) error
- handlePing func(string) error
- handleClose func(int, string) error
- readErrCount int
- messageReader *messageReader // the current low-level reader
-
- readDecompress bool // whether last read frame had RSV1 set
- newDecompressionReader func(io.Reader) io.ReadCloser
-}
-
-func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, writeBufferPool BufferPool, br *bufio.Reader, writeBuf []byte) *Conn {
-
- if br == nil {
- if readBufferSize == 0 {
- readBufferSize = defaultReadBufferSize
- } else if readBufferSize < maxControlFramePayloadSize {
- // must be large enough for control frame
- readBufferSize = maxControlFramePayloadSize
- }
- br = bufio.NewReaderSize(conn, readBufferSize)
- }
-
- if writeBufferSize <= 0 {
- writeBufferSize = defaultWriteBufferSize
- }
- writeBufferSize += maxFrameHeaderSize
-
- if writeBuf == nil && writeBufferPool == nil {
- writeBuf = make([]byte, writeBufferSize)
- }
-
- mu := make(chan struct{}, 1)
- mu <- struct{}{}
- c := &Conn{
- isServer: isServer,
- br: br,
- conn: conn,
- mu: mu,
- readFinal: true,
- writeBuf: writeBuf,
- writePool: writeBufferPool,
- writeBufSize: writeBufferSize,
- enableWriteCompression: true,
- compressionLevel: defaultCompressionLevel,
- }
- c.SetCloseHandler(nil)
- c.SetPingHandler(nil)
- c.SetPongHandler(nil)
- return c
-}
-
-// setReadRemaining tracks the number of bytes remaining on the connection. If n
-// overflows, an ErrReadLimit is returned.
-func (c *Conn) setReadRemaining(n int64) error {
- if n < 0 {
- return ErrReadLimit
- }
-
- c.readRemaining = n
- return nil
-}
-
-// Subprotocol returns the negotiated protocol for the connection.
-func (c *Conn) Subprotocol() string {
- return c.subprotocol
-}
-
-// Close closes the underlying network connection without sending or waiting
-// for a close message.
-func (c *Conn) Close() error {
- return c.conn.Close()
-}
-
-// LocalAddr returns the local network address.
-func (c *Conn) LocalAddr() net.Addr {
- return c.conn.LocalAddr()
-}
-
-// RemoteAddr returns the remote network address.
-func (c *Conn) RemoteAddr() net.Addr {
- return c.conn.RemoteAddr()
-}
-
-// Write methods
-
-func (c *Conn) writeFatal(err error) error {
- err = hideTempErr(err)
- c.writeErrMu.Lock()
- if c.writeErr == nil {
- c.writeErr = err
- }
- c.writeErrMu.Unlock()
- return err
-}
-
-func (c *Conn) read(n int) ([]byte, error) {
- p, err := c.br.Peek(n)
- if err == io.EOF {
- err = errUnexpectedEOF
- }
- c.br.Discard(len(p))
- return p, err
-}
-
-func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error {
- <-c.mu
- defer func() { c.mu <- struct{}{} }()
-
- c.writeErrMu.Lock()
- err := c.writeErr
- c.writeErrMu.Unlock()
- if err != nil {
- return err
- }
-
- c.conn.SetWriteDeadline(deadline)
- if len(buf1) == 0 {
- _, err = c.conn.Write(buf0)
- } else {
- err = c.writeBufs(buf0, buf1)
- }
- if err != nil {
- return c.writeFatal(err)
- }
- if frameType == CloseMessage {
- c.writeFatal(ErrCloseSent)
- }
- return nil
-}
-
-// WriteControl writes a control message with the given deadline. The allowed
-// message types are CloseMessage, PingMessage and PongMessage.
-func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error {
- if !isControl(messageType) {
- return errBadWriteOpCode
- }
- if len(data) > maxControlFramePayloadSize {
- return errInvalidControlFrame
- }
-
- b0 := byte(messageType) | finalBit
- b1 := byte(len(data))
- if !c.isServer {
- b1 |= maskBit
- }
-
- buf := make([]byte, 0, maxFrameHeaderSize+maxControlFramePayloadSize)
- buf = append(buf, b0, b1)
-
- if c.isServer {
- buf = append(buf, data...)
- } else {
- key := newMaskKey()
- buf = append(buf, key[:]...)
- buf = append(buf, data...)
- maskBytes(key, 0, buf[6:])
- }
-
- d := 1000 * time.Hour
- if !deadline.IsZero() {
- d = deadline.Sub(time.Now())
- if d < 0 {
- return errWriteTimeout
- }
- }
-
- timer := time.NewTimer(d)
- select {
- case <-c.mu:
- timer.Stop()
- case <-timer.C:
- return errWriteTimeout
- }
- defer func() { c.mu <- struct{}{} }()
-
- c.writeErrMu.Lock()
- err := c.writeErr
- c.writeErrMu.Unlock()
- if err != nil {
- return err
- }
-
- c.conn.SetWriteDeadline(deadline)
- _, err = c.conn.Write(buf)
- if err != nil {
- return c.writeFatal(err)
- }
- if messageType == CloseMessage {
- c.writeFatal(ErrCloseSent)
- }
- return err
-}
-
-// beginMessage prepares a connection and message writer for a new message.
-func (c *Conn) beginMessage(mw *messageWriter, messageType int) error {
- // Close previous writer if not already closed by the application. It's
- // probably better to return an error in this situation, but we cannot
- // change this without breaking existing applications.
- if c.writer != nil {
- c.writer.Close()
- c.writer = nil
- }
-
- if !isControl(messageType) && !isData(messageType) {
- return errBadWriteOpCode
- }
-
- c.writeErrMu.Lock()
- err := c.writeErr
- c.writeErrMu.Unlock()
- if err != nil {
- return err
- }
-
- mw.c = c
- mw.frameType = messageType
- mw.pos = maxFrameHeaderSize
-
- if c.writeBuf == nil {
- wpd, ok := c.writePool.Get().(writePoolData)
- if ok {
- c.writeBuf = wpd.buf
- } else {
- c.writeBuf = make([]byte, c.writeBufSize)
- }
- }
- return nil
-}
-
-// NextWriter returns a writer for the next message to send. The writer's Close
-// method flushes the complete message to the network.
-//
-// There can be at most one open writer on a connection. NextWriter closes the
-// previous writer if the application has not already done so.
-//
-// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and
-// PongMessage) are supported.
-func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
- var mw messageWriter
- if err := c.beginMessage(&mw, messageType); err != nil {
- return nil, err
- }
- c.writer = &mw
- if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) {
- w := c.newCompressionWriter(c.writer, c.compressionLevel)
- mw.compress = true
- c.writer = w
- }
- return c.writer, nil
-}
-
-type messageWriter struct {
- c *Conn
- compress bool // whether next call to flushFrame should set RSV1
- pos int // end of data in writeBuf.
- frameType int // type of the current frame.
- err error
-}
-
-func (w *messageWriter) endMessage(err error) error {
- if w.err != nil {
- return err
- }
- c := w.c
- w.err = err
- c.writer = nil
- if c.writePool != nil {
- c.writePool.Put(writePoolData{buf: c.writeBuf})
- c.writeBuf = nil
- }
- return err
-}
-
-// flushFrame writes buffered data and extra as a frame to the network. The
-// final argument indicates that this is the last frame in the message.
-func (w *messageWriter) flushFrame(final bool, extra []byte) error {
- c := w.c
- length := w.pos - maxFrameHeaderSize + len(extra)
-
- // Check for invalid control frames.
- if isControl(w.frameType) &&
- (!final || length > maxControlFramePayloadSize) {
- return w.endMessage(errInvalidControlFrame)
- }
-
- b0 := byte(w.frameType)
- if final {
- b0 |= finalBit
- }
- if w.compress {
- b0 |= rsv1Bit
- }
- w.compress = false
-
- b1 := byte(0)
- if !c.isServer {
- b1 |= maskBit
- }
-
- // Assume that the frame starts at beginning of c.writeBuf.
- framePos := 0
- if c.isServer {
- // Adjust up if mask not included in the header.
- framePos = 4
- }
-
- switch {
- case length >= 65536:
- c.writeBuf[framePos] = b0
- c.writeBuf[framePos+1] = b1 | 127
- binary.BigEndian.PutUint64(c.writeBuf[framePos+2:], uint64(length))
- case length > 125:
- framePos += 6
- c.writeBuf[framePos] = b0
- c.writeBuf[framePos+1] = b1 | 126
- binary.BigEndian.PutUint16(c.writeBuf[framePos+2:], uint16(length))
- default:
- framePos += 8
- c.writeBuf[framePos] = b0
- c.writeBuf[framePos+1] = b1 | byte(length)
- }
-
- if !c.isServer {
- key := newMaskKey()
- copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
- maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos])
- if len(extra) > 0 {
- return w.endMessage(c.writeFatal(errors.New("websocket: internal error, extra used in client mode")))
- }
- }
-
- // Write the buffers to the connection with best-effort detection of
- // concurrent writes. See the concurrency section in the package
- // documentation for more info.
-
- if c.isWriting {
- panic("concurrent write to websocket connection")
- }
- c.isWriting = true
-
- err := c.write(w.frameType, c.writeDeadline, c.writeBuf[framePos:w.pos], extra)
-
- if !c.isWriting {
- panic("concurrent write to websocket connection")
- }
- c.isWriting = false
-
- if err != nil {
- return w.endMessage(err)
- }
-
- if final {
- w.endMessage(errWriteClosed)
- return nil
- }
-
- // Setup for next frame.
- w.pos = maxFrameHeaderSize
- w.frameType = continuationFrame
- return nil
-}
-
-func (w *messageWriter) ncopy(max int) (int, error) {
- n := len(w.c.writeBuf) - w.pos
- if n <= 0 {
- if err := w.flushFrame(false, nil); err != nil {
- return 0, err
- }
- n = len(w.c.writeBuf) - w.pos
- }
- if n > max {
- n = max
- }
- return n, nil
-}
-
-func (w *messageWriter) Write(p []byte) (int, error) {
- if w.err != nil {
- return 0, w.err
- }
-
- if len(p) > 2*len(w.c.writeBuf) && w.c.isServer {
- // Don't buffer large messages.
- err := w.flushFrame(false, p)
- if err != nil {
- return 0, err
- }
- return len(p), nil
- }
-
- nn := len(p)
- for len(p) > 0 {
- n, err := w.ncopy(len(p))
- if err != nil {
- return 0, err
- }
- copy(w.c.writeBuf[w.pos:], p[:n])
- w.pos += n
- p = p[n:]
- }
- return nn, nil
-}
-
-func (w *messageWriter) WriteString(p string) (int, error) {
- if w.err != nil {
- return 0, w.err
- }
-
- nn := len(p)
- for len(p) > 0 {
- n, err := w.ncopy(len(p))
- if err != nil {
- return 0, err
- }
- copy(w.c.writeBuf[w.pos:], p[:n])
- w.pos += n
- p = p[n:]
- }
- return nn, nil
-}
-
-func (w *messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
- if w.err != nil {
- return 0, w.err
- }
- for {
- if w.pos == len(w.c.writeBuf) {
- err = w.flushFrame(false, nil)
- if err != nil {
- break
- }
- }
- var n int
- n, err = r.Read(w.c.writeBuf[w.pos:])
- w.pos += n
- nn += int64(n)
- if err != nil {
- if err == io.EOF {
- err = nil
- }
- break
- }
- }
- return nn, err
-}
-
-func (w *messageWriter) Close() error {
- if w.err != nil {
- return w.err
- }
- return w.flushFrame(true, nil)
-}
-
-// WritePreparedMessage writes prepared message into connection.
-func (c *Conn) WritePreparedMessage(pm *PreparedMessage) error {
- frameType, frameData, err := pm.frame(prepareKey{
- isServer: c.isServer,
- compress: c.newCompressionWriter != nil && c.enableWriteCompression && isData(pm.messageType),
- compressionLevel: c.compressionLevel,
- })
- if err != nil {
- return err
- }
- if c.isWriting {
- panic("concurrent write to websocket connection")
- }
- c.isWriting = true
- err = c.write(frameType, c.writeDeadline, frameData, nil)
- if !c.isWriting {
- panic("concurrent write to websocket connection")
- }
- c.isWriting = false
- return err
-}
-
-// WriteMessage is a helper method for getting a writer using NextWriter,
-// writing the message and closing the writer.
-func (c *Conn) WriteMessage(messageType int, data []byte) error {
-
- if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) {
- // Fast path with no allocations and single frame.
-
- var mw messageWriter
- if err := c.beginMessage(&mw, messageType); err != nil {
- return err
- }
- n := copy(c.writeBuf[mw.pos:], data)
- mw.pos += n
- data = data[n:]
- return mw.flushFrame(true, data)
- }
-
- w, err := c.NextWriter(messageType)
- if err != nil {
- return err
- }
- if _, err = w.Write(data); err != nil {
- return err
- }
- return w.Close()
-}
-
-// SetWriteDeadline sets the write deadline on the underlying network
-// connection. After a write has timed out, the websocket state is corrupt and
-// all future writes will return an error. A zero value for t means writes will
-// not time out.
-func (c *Conn) SetWriteDeadline(t time.Time) error {
- c.writeDeadline = t
- return nil
-}
-
-// Read methods
-
-func (c *Conn) advanceFrame() (int, error) {
- // 1. Skip remainder of previous frame.
-
- if c.readRemaining > 0 {
- if _, err := io.CopyN(ioutil.Discard, c.br, c.readRemaining); err != nil {
- return noFrame, err
- }
- }
-
- // 2. Read and parse first two bytes of frame header.
-
- p, err := c.read(2)
- if err != nil {
- return noFrame, err
- }
-
- final := p[0]&finalBit != 0
- frameType := int(p[0] & 0xf)
- mask := p[1]&maskBit != 0
- c.setReadRemaining(int64(p[1] & 0x7f))
-
- c.readDecompress = false
- if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 {
- c.readDecompress = true
- p[0] &^= rsv1Bit
- }
-
- if rsv := p[0] & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 {
- return noFrame, c.handleProtocolError("unexpected reserved bits 0x" + strconv.FormatInt(int64(rsv), 16))
- }
-
- switch frameType {
- case CloseMessage, PingMessage, PongMessage:
- if c.readRemaining > maxControlFramePayloadSize {
- return noFrame, c.handleProtocolError("control frame length > 125")
- }
- if !final {
- return noFrame, c.handleProtocolError("control frame not final")
- }
- case TextMessage, BinaryMessage:
- if !c.readFinal {
- return noFrame, c.handleProtocolError("message start before final message frame")
- }
- c.readFinal = final
- case continuationFrame:
- if c.readFinal {
- return noFrame, c.handleProtocolError("continuation after final message frame")
- }
- c.readFinal = final
- default:
- return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType))
- }
-
- // 3. Read and parse frame length as per
- // https://tools.ietf.org/html/rfc6455#section-5.2
- //
- // The length of the "Payload data", in bytes: if 0-125, that is the payload
- // length.
- // - If 126, the following 2 bytes interpreted as a 16-bit unsigned
- // integer are the payload length.
- // - If 127, the following 8 bytes interpreted as
- // a 64-bit unsigned integer (the most significant bit MUST be 0) are the
- // payload length. Multibyte length quantities are expressed in network byte
- // order.
-
- switch c.readRemaining {
- case 126:
- p, err := c.read(2)
- if err != nil {
- return noFrame, err
- }
-
- if err := c.setReadRemaining(int64(binary.BigEndian.Uint16(p))); err != nil {
- return noFrame, err
- }
- case 127:
- p, err := c.read(8)
- if err != nil {
- return noFrame, err
- }
-
- if err := c.setReadRemaining(int64(binary.BigEndian.Uint64(p))); err != nil {
- return noFrame, err
- }
- }
-
- // 4. Handle frame masking.
-
- if mask != c.isServer {
- return noFrame, c.handleProtocolError("incorrect mask flag")
- }
-
- if mask {
- c.readMaskPos = 0
- p, err := c.read(len(c.readMaskKey))
- if err != nil {
- return noFrame, err
- }
- copy(c.readMaskKey[:], p)
- }
-
- // 5. For text and binary messages, enforce read limit and return.
-
- if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage {
-
- c.readLength += c.readRemaining
- // Don't allow readLength to overflow in the presence of a large readRemaining
- // counter.
- if c.readLength < 0 {
- return noFrame, ErrReadLimit
- }
-
- if c.readLimit > 0 && c.readLength > c.readLimit {
- c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait))
- return noFrame, ErrReadLimit
- }
-
- return frameType, nil
- }
-
- // 6. Read control frame payload.
-
- var payload []byte
- if c.readRemaining > 0 {
- payload, err = c.read(int(c.readRemaining))
- c.setReadRemaining(0)
- if err != nil {
- return noFrame, err
- }
- if c.isServer {
- maskBytes(c.readMaskKey, 0, payload)
- }
- }
-
- // 7. Process control frame payload.
-
- switch frameType {
- case PongMessage:
- if err := c.handlePong(string(payload)); err != nil {
- return noFrame, err
- }
- case PingMessage:
- if err := c.handlePing(string(payload)); err != nil {
- return noFrame, err
- }
- case CloseMessage:
- closeCode := CloseNoStatusReceived
- closeText := ""
- if len(payload) >= 2 {
- closeCode = int(binary.BigEndian.Uint16(payload))
- if !isValidReceivedCloseCode(closeCode) {
- return noFrame, c.handleProtocolError("invalid close code")
- }
- closeText = string(payload[2:])
- if !utf8.ValidString(closeText) {
- return noFrame, c.handleProtocolError("invalid utf8 payload in close frame")
- }
- }
- if err := c.handleClose(closeCode, closeText); err != nil {
- return noFrame, err
- }
- return noFrame, &CloseError{Code: closeCode, Text: closeText}
- }
-
- return frameType, nil
-}
-
-func (c *Conn) handleProtocolError(message string) error {
- c.WriteControl(CloseMessage, FormatCloseMessage(CloseProtocolError, message), time.Now().Add(writeWait))
- return errors.New("websocket: " + message)
-}
-
-// NextReader returns the next data message received from the peer. The
-// returned messageType is either TextMessage or BinaryMessage.
-//
-// There can be at most one open reader on a connection. NextReader discards
-// the previous message if the application has not already consumed it.
-//
-// Applications must break out of the application's read loop when this method
-// returns a non-nil error value. Errors returned from this method are
-// permanent. Once this method returns a non-nil error, all subsequent calls to
-// this method return the same error.
-func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
- // Close previous reader, only relevant for decompression.
- if c.reader != nil {
- c.reader.Close()
- c.reader = nil
- }
-
- c.messageReader = nil
- c.readLength = 0
-
- for c.readErr == nil {
- frameType, err := c.advanceFrame()
- if err != nil {
- c.readErr = hideTempErr(err)
- break
- }
-
- if frameType == TextMessage || frameType == BinaryMessage {
- c.messageReader = &messageReader{c}
- c.reader = c.messageReader
- if c.readDecompress {
- c.reader = c.newDecompressionReader(c.reader)
- }
- return frameType, c.reader, nil
- }
- }
-
- // Applications that do handle the error returned from this method spin in
- // tight loop on connection failure. To help application developers detect
- // this error, panic on repeated reads to the failed connection.
- c.readErrCount++
- if c.readErrCount >= 1000 {
- panic("repeated read on failed websocket connection")
- }
-
- return noFrame, nil, c.readErr
-}
-
-type messageReader struct{ c *Conn }
-
-func (r *messageReader) Read(b []byte) (int, error) {
- c := r.c
- if c.messageReader != r {
- return 0, io.EOF
- }
-
- for c.readErr == nil {
-
- if c.readRemaining > 0 {
- if int64(len(b)) > c.readRemaining {
- b = b[:c.readRemaining]
- }
- n, err := c.br.Read(b)
- c.readErr = hideTempErr(err)
- if c.isServer {
- c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n])
- }
- rem := c.readRemaining
- rem -= int64(n)
- c.setReadRemaining(rem)
- if c.readRemaining > 0 && c.readErr == io.EOF {
- c.readErr = errUnexpectedEOF
- }
- return n, c.readErr
- }
-
- if c.readFinal {
- c.messageReader = nil
- return 0, io.EOF
- }
-
- frameType, err := c.advanceFrame()
- switch {
- case err != nil:
- c.readErr = hideTempErr(err)
- case frameType == TextMessage || frameType == BinaryMessage:
- c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader")
- }
- }
-
- err := c.readErr
- if err == io.EOF && c.messageReader == r {
- err = errUnexpectedEOF
- }
- return 0, err
-}
-
-func (r *messageReader) Close() error {
- return nil
-}
-
-// ReadMessage is a helper method for getting a reader using NextReader and
-// reading from that reader to a buffer.
-func (c *Conn) ReadMessage() (messageType int, p []byte, err error) {
- var r io.Reader
- messageType, r, err = c.NextReader()
- if err != nil {
- return messageType, nil, err
- }
- p, err = ioutil.ReadAll(r)
- return messageType, p, err
-}
-
-// SetReadDeadline sets the read deadline on the underlying network connection.
-// After a read has timed out, the websocket connection state is corrupt and
-// all future reads will return an error. A zero value for t means reads will
-// not time out.
-func (c *Conn) SetReadDeadline(t time.Time) error {
- return c.conn.SetReadDeadline(t)
-}
-
-// SetReadLimit sets the maximum size in bytes for a message read from the peer. If a
-// message exceeds the limit, the connection sends a close message to the peer
-// and returns ErrReadLimit to the application.
-func (c *Conn) SetReadLimit(limit int64) {
- c.readLimit = limit
-}
-
-// CloseHandler returns the current close handler
-func (c *Conn) CloseHandler() func(code int, text string) error {
- return c.handleClose
-}
-
-// SetCloseHandler sets the handler for close messages received from the peer.
-// The code argument to h is the received close code or CloseNoStatusReceived
-// if the close message is empty. The default close handler sends a close
-// message back to the peer.
-//
-// The handler function is called from the NextReader, ReadMessage and message
-// reader Read methods. The application must read the connection to process
-// close messages as described in the section on Control Messages above.
-//
-// The connection read methods return a CloseError when a close message is
-// received. Most applications should handle close messages as part of their
-// normal error handling. Applications should only set a close handler when the
-// application must perform some action before sending a close message back to
-// the peer.
-func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
- if h == nil {
- h = func(code int, text string) error {
- message := FormatCloseMessage(code, "")
- c.WriteControl(CloseMessage, message, time.Now().Add(writeWait))
- return nil
- }
- }
- c.handleClose = h
-}
-
-// PingHandler returns the current ping handler
-func (c *Conn) PingHandler() func(appData string) error {
- return c.handlePing
-}
-
-// SetPingHandler sets the handler for ping messages received from the peer.
-// The appData argument to h is the PING message application data. The default
-// ping handler sends a pong to the peer.
-//
-// The handler function is called from the NextReader, ReadMessage and message
-// reader Read methods. The application must read the connection to process
-// ping messages as described in the section on Control Messages above.
-func (c *Conn) SetPingHandler(h func(appData string) error) {
- if h == nil {
- h = func(message string) error {
- err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait))
- if err == ErrCloseSent {
- return nil
- } else if e, ok := err.(net.Error); ok && e.Temporary() {
- return nil
- }
- return err
- }
- }
- c.handlePing = h
-}
-
-// PongHandler returns the current pong handler
-func (c *Conn) PongHandler() func(appData string) error {
- return c.handlePong
-}
-
-// SetPongHandler sets the handler for pong messages received from the peer.
-// The appData argument to h is the PONG message application data. The default
-// pong handler does nothing.
-//
-// The handler function is called from the NextReader, ReadMessage and message
-// reader Read methods. The application must read the connection to process
-// pong messages as described in the section on Control Messages above.
-func (c *Conn) SetPongHandler(h func(appData string) error) {
- if h == nil {
- h = func(string) error { return nil }
- }
- c.handlePong = h
-}
-
-// UnderlyingConn returns the internal net.Conn. This can be used to further
-// modifications to connection specific flags.
-func (c *Conn) UnderlyingConn() net.Conn {
- return c.conn
-}
-
-// EnableWriteCompression enables and disables write compression of
-// subsequent text and binary messages. This function is a noop if
-// compression was not negotiated with the peer.
-func (c *Conn) EnableWriteCompression(enable bool) {
- c.enableWriteCompression = enable
-}
-
-// SetCompressionLevel sets the flate compression level for subsequent text and
-// binary messages. This function is a noop if compression was not negotiated
-// with the peer. See the compress/flate package for a description of
-// compression levels.
-func (c *Conn) SetCompressionLevel(level int) error {
- if !isValidCompressionLevel(level) {
- return errors.New("websocket: invalid compression level")
- }
- c.compressionLevel = level
- return nil
-}
-
-// FormatCloseMessage formats closeCode and text as a WebSocket close message.
-// An empty message is returned for code CloseNoStatusReceived.
-func FormatCloseMessage(closeCode int, text string) []byte {
- if closeCode == CloseNoStatusReceived {
- // Return empty message because it's illegal to send
- // CloseNoStatusReceived. Return non-nil value in case application
- // checks for nil.
- return []byte{}
- }
- buf := make([]byte, 2+len(text))
- binary.BigEndian.PutUint16(buf, uint16(closeCode))
- copy(buf[2:], text)
- return buf
-}
diff --git a/vendor/github.com/gorilla/websocket/conn_write.go b/vendor/github.com/gorilla/websocket/conn_write.go
deleted file mode 100644
index a509a21f87a..00000000000
--- a/vendor/github.com/gorilla/websocket/conn_write.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.8
-
-package websocket
-
-import "net"
-
-func (c *Conn) writeBufs(bufs ...[]byte) error {
- b := net.Buffers(bufs)
- _, err := b.WriteTo(c.conn)
- return err
-}
diff --git a/vendor/github.com/gorilla/websocket/conn_write_legacy.go b/vendor/github.com/gorilla/websocket/conn_write_legacy.go
deleted file mode 100644
index 37edaff5a57..00000000000
--- a/vendor/github.com/gorilla/websocket/conn_write_legacy.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !go1.8
-
-package websocket
-
-func (c *Conn) writeBufs(bufs ...[]byte) error {
- for _, buf := range bufs {
- if len(buf) > 0 {
- if _, err := c.conn.Write(buf); err != nil {
- return err
- }
- }
- }
- return nil
-}
diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go
deleted file mode 100644
index 8db0cef95a2..00000000000
--- a/vendor/github.com/gorilla/websocket/doc.go
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package websocket implements the WebSocket protocol defined in RFC 6455.
-//
-// Overview
-//
-// The Conn type represents a WebSocket connection. A server application calls
-// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn:
-//
-// var upgrader = websocket.Upgrader{
-// ReadBufferSize: 1024,
-// WriteBufferSize: 1024,
-// }
-//
-// func handler(w http.ResponseWriter, r *http.Request) {
-// conn, err := upgrader.Upgrade(w, r, nil)
-// if err != nil {
-// log.Println(err)
-// return
-// }
-// ... Use conn to send and receive messages.
-// }
-//
-// Call the connection's WriteMessage and ReadMessage methods to send and
-// receive messages as a slice of bytes. This snippet of code shows how to echo
-// messages using these methods:
-//
-// for {
-// messageType, p, err := conn.ReadMessage()
-// if err != nil {
-// log.Println(err)
-// return
-// }
-// if err := conn.WriteMessage(messageType, p); err != nil {
-// log.Println(err)
-// return
-// }
-// }
-//
-// In above snippet of code, p is a []byte and messageType is an int with value
-// websocket.BinaryMessage or websocket.TextMessage.
-//
-// An application can also send and receive messages using the io.WriteCloser
-// and io.Reader interfaces. To send a message, call the connection NextWriter
-// method to get an io.WriteCloser, write the message to the writer and close
-// the writer when done. To receive a message, call the connection NextReader
-// method to get an io.Reader and read until io.EOF is returned. This snippet
-// shows how to echo messages using the NextWriter and NextReader methods:
-//
-// for {
-// messageType, r, err := conn.NextReader()
-// if err != nil {
-// return
-// }
-// w, err := conn.NextWriter(messageType)
-// if err != nil {
-// return err
-// }
-// if _, err := io.Copy(w, r); err != nil {
-// return err
-// }
-// if err := w.Close(); err != nil {
-// return err
-// }
-// }
-//
-// Data Messages
-//
-// The WebSocket protocol distinguishes between text and binary data messages.
-// Text messages are interpreted as UTF-8 encoded text. The interpretation of
-// binary messages is left to the application.
-//
-// This package uses the TextMessage and BinaryMessage integer constants to
-// identify the two data message types. The ReadMessage and NextReader methods
-// return the type of the received message. The messageType argument to the
-// WriteMessage and NextWriter methods specifies the type of a sent message.
-//
-// It is the application's responsibility to ensure that text messages are
-// valid UTF-8 encoded text.
-//
-// Control Messages
-//
-// The WebSocket protocol defines three types of control messages: close, ping
-// and pong. Call the connection WriteControl, WriteMessage or NextWriter
-// methods to send a control message to the peer.
-//
-// Connections handle received close messages by calling the handler function
-// set with the SetCloseHandler method and by returning a *CloseError from the
-// NextReader, ReadMessage or the message Read method. The default close
-// handler sends a close message to the peer.
-//
-// Connections handle received ping messages by calling the handler function
-// set with the SetPingHandler method. The default ping handler sends a pong
-// message to the peer.
-//
-// Connections handle received pong messages by calling the handler function
-// set with the SetPongHandler method. The default pong handler does nothing.
-// If an application sends ping messages, then the application should set a
-// pong handler to receive the corresponding pong.
-//
-// The control message handler functions are called from the NextReader,
-// ReadMessage and message reader Read methods. The default close and ping
-// handlers can block these methods for a short time when the handler writes to
-// the connection.
-//
-// The application must read the connection to process close, ping and pong
-// messages sent from the peer. If the application is not otherwise interested
-// in messages from the peer, then the application should start a goroutine to
-// read and discard messages from the peer. A simple example is:
-//
-// func readLoop(c *websocket.Conn) {
-// for {
-// if _, _, err := c.NextReader(); err != nil {
-// c.Close()
-// break
-// }
-// }
-// }
-//
-// Concurrency
-//
-// Connections support one concurrent reader and one concurrent writer.
-//
-// Applications are responsible for ensuring that no more than one goroutine
-// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage,
-// WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and
-// that no more than one goroutine calls the read methods (NextReader,
-// SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler)
-// concurrently.
-//
-// The Close and WriteControl methods can be called concurrently with all other
-// methods.
-//
-// Origin Considerations
-//
-// Web browsers allow Javascript applications to open a WebSocket connection to
-// any host. It's up to the server to enforce an origin policy using the Origin
-// request header sent by the browser.
-//
-// The Upgrader calls the function specified in the CheckOrigin field to check
-// the origin. If the CheckOrigin function returns false, then the Upgrade
-// method fails the WebSocket handshake with HTTP status 403.
-//
-// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
-// the handshake if the Origin request header is present and the Origin host is
-// not equal to the Host request header.
-//
-// The deprecated package-level Upgrade function does not perform origin
-// checking. The application is responsible for checking the Origin header
-// before calling the Upgrade function.
-//
-// Buffers
-//
-// Connections buffer network input and output to reduce the number
-// of system calls when reading or writing messages.
-//
-// Write buffers are also used for constructing WebSocket frames. See RFC 6455,
-// Section 5 for a discussion of message framing. A WebSocket frame header is
-// written to the network each time a write buffer is flushed to the network.
-// Decreasing the size of the write buffer can increase the amount of framing
-// overhead on the connection.
-//
-// The buffer sizes in bytes are specified by the ReadBufferSize and
-// WriteBufferSize fields in the Dialer and Upgrader. The Dialer uses a default
-// size of 4096 when a buffer size field is set to zero. The Upgrader reuses
-// buffers created by the HTTP server when a buffer size field is set to zero.
-// The HTTP server buffers have a size of 4096 at the time of this writing.
-//
-// The buffer sizes do not limit the size of a message that can be read or
-// written by a connection.
-//
-// Buffers are held for the lifetime of the connection by default. If the
-// Dialer or Upgrader WriteBufferPool field is set, then a connection holds the
-// write buffer only when writing a message.
-//
-// Applications should tune the buffer sizes to balance memory use and
-// performance. Increasing the buffer size uses more memory, but can reduce the
-// number of system calls to read or write the network. In the case of writing,
-// increasing the buffer size can reduce the number of frame headers written to
-// the network.
-//
-// Some guidelines for setting buffer parameters are:
-//
-// Limit the buffer sizes to the maximum expected message size. Buffers larger
-// than the largest message do not provide any benefit.
-//
-// Depending on the distribution of message sizes, setting the buffer size to
-// a value less than the maximum expected message size can greatly reduce memory
-// use with a small impact on performance. Here's an example: If 99% of the
-// messages are smaller than 256 bytes and the maximum message size is 512
-// bytes, then a buffer size of 256 bytes will result in 1.01 more system calls
-// than a buffer size of 512 bytes. The memory savings is 50%.
-//
-// A write buffer pool is useful when the application has a modest number
-// writes over a large number of connections. when buffers are pooled, a larger
-// buffer size has a reduced impact on total memory use and has the benefit of
-// reducing system calls and frame overhead.
-//
-// Compression EXPERIMENTAL
-//
-// Per message compression extensions (RFC 7692) are experimentally supported
-// by this package in a limited capacity. Setting the EnableCompression option
-// to true in Dialer or Upgrader will attempt to negotiate per message deflate
-// support.
-//
-// var upgrader = websocket.Upgrader{
-// EnableCompression: true,
-// }
-//
-// If compression was successfully negotiated with the connection's peer, any
-// message received in compressed form will be automatically decompressed.
-// All Read methods will return uncompressed bytes.
-//
-// Per message compression of messages written to a connection can be enabled
-// or disabled by calling the corresponding Conn method:
-//
-// conn.EnableWriteCompression(false)
-//
-// Currently this package does not support compression with "context takeover".
-// This means that messages must be compressed and decompressed in isolation,
-// without retaining sliding window or dictionary state across messages. For
-// more details refer to RFC 7692.
-//
-// Use of compression is experimental and may result in decreased performance.
-package websocket
diff --git a/vendor/github.com/gorilla/websocket/go.mod b/vendor/github.com/gorilla/websocket/go.mod
deleted file mode 100644
index 1a7afd5028a..00000000000
--- a/vendor/github.com/gorilla/websocket/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/gorilla/websocket
-
-go 1.12
diff --git a/vendor/github.com/gorilla/websocket/go.sum b/vendor/github.com/gorilla/websocket/go.sum
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/vendor/github.com/gorilla/websocket/join.go b/vendor/github.com/gorilla/websocket/join.go
deleted file mode 100644
index c64f8c82901..00000000000
--- a/vendor/github.com/gorilla/websocket/join.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2019 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "io"
- "strings"
-)
-
-// JoinMessages concatenates received messages to create a single io.Reader.
-// The string term is appended to each message. The returned reader does not
-// support concurrent calls to the Read method.
-func JoinMessages(c *Conn, term string) io.Reader {
- return &joinReader{c: c, term: term}
-}
-
-type joinReader struct {
- c *Conn
- term string
- r io.Reader
-}
-
-func (r *joinReader) Read(p []byte) (int, error) {
- if r.r == nil {
- var err error
- _, r.r, err = r.c.NextReader()
- if err != nil {
- return 0, err
- }
- if r.term != "" {
- r.r = io.MultiReader(r.r, strings.NewReader(r.term))
- }
- }
- n, err := r.r.Read(p)
- if err == io.EOF {
- err = nil
- r.r = nil
- }
- return n, err
-}
diff --git a/vendor/github.com/gorilla/websocket/json.go b/vendor/github.com/gorilla/websocket/json.go
deleted file mode 100644
index dc2c1f6415f..00000000000
--- a/vendor/github.com/gorilla/websocket/json.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "encoding/json"
- "io"
-)
-
-// WriteJSON writes the JSON encoding of v as a message.
-//
-// Deprecated: Use c.WriteJSON instead.
-func WriteJSON(c *Conn, v interface{}) error {
- return c.WriteJSON(v)
-}
-
-// WriteJSON writes the JSON encoding of v as a message.
-//
-// See the documentation for encoding/json Marshal for details about the
-// conversion of Go values to JSON.
-func (c *Conn) WriteJSON(v interface{}) error {
- w, err := c.NextWriter(TextMessage)
- if err != nil {
- return err
- }
- err1 := json.NewEncoder(w).Encode(v)
- err2 := w.Close()
- if err1 != nil {
- return err1
- }
- return err2
-}
-
-// ReadJSON reads the next JSON-encoded message from the connection and stores
-// it in the value pointed to by v.
-//
-// Deprecated: Use c.ReadJSON instead.
-func ReadJSON(c *Conn, v interface{}) error {
- return c.ReadJSON(v)
-}
-
-// ReadJSON reads the next JSON-encoded message from the connection and stores
-// it in the value pointed to by v.
-//
-// See the documentation for the encoding/json Unmarshal function for details
-// about the conversion of JSON to a Go value.
-func (c *Conn) ReadJSON(v interface{}) error {
- _, r, err := c.NextReader()
- if err != nil {
- return err
- }
- err = json.NewDecoder(r).Decode(v)
- if err == io.EOF {
- // One value is expected in the message.
- err = io.ErrUnexpectedEOF
- }
- return err
-}
diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go
deleted file mode 100644
index 577fce9efd7..00000000000
--- a/vendor/github.com/gorilla/websocket/mask.go
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
-// this source code is governed by a BSD-style license that can be found in the
-// LICENSE file.
-
-// +build !appengine
-
-package websocket
-
-import "unsafe"
-
-const wordSize = int(unsafe.Sizeof(uintptr(0)))
-
-func maskBytes(key [4]byte, pos int, b []byte) int {
- // Mask one byte at a time for small buffers.
- if len(b) < 2*wordSize {
- for i := range b {
- b[i] ^= key[pos&3]
- pos++
- }
- return pos & 3
- }
-
- // Mask one byte at a time to word boundary.
- if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 {
- n = wordSize - n
- for i := range b[:n] {
- b[i] ^= key[pos&3]
- pos++
- }
- b = b[n:]
- }
-
- // Create aligned word size key.
- var k [wordSize]byte
- for i := range k {
- k[i] = key[(pos+i)&3]
- }
- kw := *(*uintptr)(unsafe.Pointer(&k))
-
- // Mask one word at a time.
- n := (len(b) / wordSize) * wordSize
- for i := 0; i < n; i += wordSize {
- *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw
- }
-
- // Mask one byte at a time for remaining bytes.
- b = b[n:]
- for i := range b {
- b[i] ^= key[pos&3]
- pos++
- }
-
- return pos & 3
-}
diff --git a/vendor/github.com/gorilla/websocket/mask_safe.go b/vendor/github.com/gorilla/websocket/mask_safe.go
deleted file mode 100644
index 2aac060e52e..00000000000
--- a/vendor/github.com/gorilla/websocket/mask_safe.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. Use of
-// this source code is governed by a BSD-style license that can be found in the
-// LICENSE file.
-
-// +build appengine
-
-package websocket
-
-func maskBytes(key [4]byte, pos int, b []byte) int {
- for i := range b {
- b[i] ^= key[pos&3]
- pos++
- }
- return pos & 3
-}
diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go
deleted file mode 100644
index c854225e967..00000000000
--- a/vendor/github.com/gorilla/websocket/prepared.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bytes"
- "net"
- "sync"
- "time"
-)
-
-// PreparedMessage caches on the wire representations of a message payload.
-// Use PreparedMessage to efficiently send a message payload to multiple
-// connections. PreparedMessage is especially useful when compression is used
-// because the CPU and memory expensive compression operation can be executed
-// once for a given set of compression options.
-type PreparedMessage struct {
- messageType int
- data []byte
- mu sync.Mutex
- frames map[prepareKey]*preparedFrame
-}
-
-// prepareKey defines a unique set of options to cache prepared frames in PreparedMessage.
-type prepareKey struct {
- isServer bool
- compress bool
- compressionLevel int
-}
-
-// preparedFrame contains data in wire representation.
-type preparedFrame struct {
- once sync.Once
- data []byte
-}
-
-// NewPreparedMessage returns an initialized PreparedMessage. You can then send
-// it to connection using WritePreparedMessage method. Valid wire
-// representation will be calculated lazily only once for a set of current
-// connection options.
-func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) {
- pm := &PreparedMessage{
- messageType: messageType,
- frames: make(map[prepareKey]*preparedFrame),
- data: data,
- }
-
- // Prepare a plain server frame.
- _, frameData, err := pm.frame(prepareKey{isServer: true, compress: false})
- if err != nil {
- return nil, err
- }
-
- // To protect against caller modifying the data argument, remember the data
- // copied to the plain server frame.
- pm.data = frameData[len(frameData)-len(data):]
- return pm, nil
-}
-
-func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) {
- pm.mu.Lock()
- frame, ok := pm.frames[key]
- if !ok {
- frame = &preparedFrame{}
- pm.frames[key] = frame
- }
- pm.mu.Unlock()
-
- var err error
- frame.once.Do(func() {
- // Prepare a frame using a 'fake' connection.
- // TODO: Refactor code in conn.go to allow more direct construction of
- // the frame.
- mu := make(chan struct{}, 1)
- mu <- struct{}{}
- var nc prepareConn
- c := &Conn{
- conn: &nc,
- mu: mu,
- isServer: key.isServer,
- compressionLevel: key.compressionLevel,
- enableWriteCompression: true,
- writeBuf: make([]byte, defaultWriteBufferSize+maxFrameHeaderSize),
- }
- if key.compress {
- c.newCompressionWriter = compressNoContextTakeover
- }
- err = c.WriteMessage(pm.messageType, pm.data)
- frame.data = nc.buf.Bytes()
- })
- return pm.messageType, frame.data, err
-}
-
-type prepareConn struct {
- buf bytes.Buffer
- net.Conn
-}
-
-func (pc *prepareConn) Write(p []byte) (int, error) { return pc.buf.Write(p) }
-func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil }
diff --git a/vendor/github.com/gorilla/websocket/proxy.go b/vendor/github.com/gorilla/websocket/proxy.go
deleted file mode 100644
index e87a8c9f0c9..00000000000
--- a/vendor/github.com/gorilla/websocket/proxy.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bufio"
- "encoding/base64"
- "errors"
- "net"
- "net/http"
- "net/url"
- "strings"
-)
-
-type netDialerFunc func(network, addr string) (net.Conn, error)
-
-func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
- return fn(network, addr)
-}
-
-func init() {
- proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) {
- return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil
- })
-}
-
-type httpProxyDialer struct {
- proxyURL *url.URL
- forwardDial func(network, addr string) (net.Conn, error)
-}
-
-func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
- hostPort, _ := hostPortNoPort(hpd.proxyURL)
- conn, err := hpd.forwardDial(network, hostPort)
- if err != nil {
- return nil, err
- }
-
- connectHeader := make(http.Header)
- if user := hpd.proxyURL.User; user != nil {
- proxyUser := user.Username()
- if proxyPassword, passwordSet := user.Password(); passwordSet {
- credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
- connectHeader.Set("Proxy-Authorization", "Basic "+credential)
- }
- }
-
- connectReq := &http.Request{
- Method: "CONNECT",
- URL: &url.URL{Opaque: addr},
- Host: addr,
- Header: connectHeader,
- }
-
- if err := connectReq.Write(conn); err != nil {
- conn.Close()
- return nil, err
- }
-
- // Read response. It's OK to use and discard buffered reader here becaue
- // the remote server does not speak until spoken to.
- br := bufio.NewReader(conn)
- resp, err := http.ReadResponse(br, connectReq)
- if err != nil {
- conn.Close()
- return nil, err
- }
-
- if resp.StatusCode != 200 {
- conn.Close()
- f := strings.SplitN(resp.Status, " ", 2)
- return nil, errors.New(f[1])
- }
- return conn, nil
-}
diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go
deleted file mode 100644
index 887d558918c..00000000000
--- a/vendor/github.com/gorilla/websocket/server.go
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bufio"
- "errors"
- "io"
- "net/http"
- "net/url"
- "strings"
- "time"
-)
-
-// HandshakeError describes an error with the handshake from the peer.
-type HandshakeError struct {
- message string
-}
-
-func (e HandshakeError) Error() string { return e.message }
-
-// Upgrader specifies parameters for upgrading an HTTP connection to a
-// WebSocket connection.
-type Upgrader struct {
- // HandshakeTimeout specifies the duration for the handshake to complete.
- HandshakeTimeout time.Duration
-
- // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer
- // size is zero, then buffers allocated by the HTTP server are used. The
- // I/O buffer sizes do not limit the size of the messages that can be sent
- // or received.
- ReadBufferSize, WriteBufferSize int
-
- // WriteBufferPool is a pool of buffers for write operations. If the value
- // is not set, then write buffers are allocated to the connection for the
- // lifetime of the connection.
- //
- // A pool is most useful when the application has a modest volume of writes
- // across a large number of connections.
- //
- // Applications should use a single pool for each unique value of
- // WriteBufferSize.
- WriteBufferPool BufferPool
-
- // Subprotocols specifies the server's supported protocols in order of
- // preference. If this field is not nil, then the Upgrade method negotiates a
- // subprotocol by selecting the first match in this list with a protocol
- // requested by the client. If there's no match, then no protocol is
- // negotiated (the Sec-Websocket-Protocol header is not included in the
- // handshake response).
- Subprotocols []string
-
- // Error specifies the function for generating HTTP error responses. If Error
- // is nil, then http.Error is used to generate the HTTP response.
- Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
-
- // CheckOrigin returns true if the request Origin header is acceptable. If
- // CheckOrigin is nil, then a safe default is used: return false if the
- // Origin request header is present and the origin host is not equal to
- // request Host header.
- //
- // A CheckOrigin function should carefully validate the request origin to
- // prevent cross-site request forgery.
- CheckOrigin func(r *http.Request) bool
-
- // EnableCompression specify if the server should attempt to negotiate per
- // message compression (RFC 7692). Setting this value to true does not
- // guarantee that compression will be supported. Currently only "no context
- // takeover" modes are supported.
- EnableCompression bool
-}
-
-func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
- err := HandshakeError{reason}
- if u.Error != nil {
- u.Error(w, r, status, err)
- } else {
- w.Header().Set("Sec-Websocket-Version", "13")
- http.Error(w, http.StatusText(status), status)
- }
- return nil, err
-}
-
-// checkSameOrigin returns true if the origin is not set or is equal to the request host.
-func checkSameOrigin(r *http.Request) bool {
- origin := r.Header["Origin"]
- if len(origin) == 0 {
- return true
- }
- u, err := url.Parse(origin[0])
- if err != nil {
- return false
- }
- return equalASCIIFold(u.Host, r.Host)
-}
-
-func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
- if u.Subprotocols != nil {
- clientProtocols := Subprotocols(r)
- for _, serverProtocol := range u.Subprotocols {
- for _, clientProtocol := range clientProtocols {
- if clientProtocol == serverProtocol {
- return clientProtocol
- }
- }
- }
- } else if responseHeader != nil {
- return responseHeader.Get("Sec-Websocket-Protocol")
- }
- return ""
-}
-
-// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
-//
-// The responseHeader is included in the response to the client's upgrade
-// request. Use the responseHeader to specify cookies (Set-Cookie) and the
-// application negotiated subprotocol (Sec-WebSocket-Protocol).
-//
-// If the upgrade fails, then Upgrade replies to the client with an HTTP error
-// response.
-func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
- const badHandshake = "websocket: the client is not using the websocket protocol: "
-
- if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
- return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header")
- }
-
- if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
- return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header")
- }
-
- if r.Method != "GET" {
- return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET")
- }
-
- if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
- }
-
- if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
- return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported")
- }
-
- checkOrigin := u.CheckOrigin
- if checkOrigin == nil {
- checkOrigin = checkSameOrigin
- }
- if !checkOrigin(r) {
- return u.returnError(w, r, http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin")
- }
-
- challengeKey := r.Header.Get("Sec-Websocket-Key")
- if challengeKey == "" {
- return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header is missing or blank")
- }
-
- subprotocol := u.selectSubprotocol(r, responseHeader)
-
- // Negotiate PMCE
- var compress bool
- if u.EnableCompression {
- for _, ext := range parseExtensions(r.Header) {
- if ext[""] != "permessage-deflate" {
- continue
- }
- compress = true
- break
- }
- }
-
- h, ok := w.(http.Hijacker)
- if !ok {
- return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
- }
- var brw *bufio.ReadWriter
- netConn, brw, err := h.Hijack()
- if err != nil {
- return u.returnError(w, r, http.StatusInternalServerError, err.Error())
- }
-
- if brw.Reader.Buffered() > 0 {
- netConn.Close()
- return nil, errors.New("websocket: client sent data before handshake is complete")
- }
-
- var br *bufio.Reader
- if u.ReadBufferSize == 0 && bufioReaderSize(netConn, brw.Reader) > 256 {
- // Reuse hijacked buffered reader as connection reader.
- br = brw.Reader
- }
-
- buf := bufioWriterBuffer(netConn, brw.Writer)
-
- var writeBuf []byte
- if u.WriteBufferPool == nil && u.WriteBufferSize == 0 && len(buf) >= maxFrameHeaderSize+256 {
- // Reuse hijacked write buffer as connection buffer.
- writeBuf = buf
- }
-
- c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf)
- c.subprotocol = subprotocol
-
- if compress {
- c.newCompressionWriter = compressNoContextTakeover
- c.newDecompressionReader = decompressNoContextTakeover
- }
-
- // Use larger of hijacked buffer and connection write buffer for header.
- p := buf
- if len(c.writeBuf) > len(p) {
- p = c.writeBuf
- }
- p = p[:0]
-
- p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
- p = append(p, computeAcceptKey(challengeKey)...)
- p = append(p, "\r\n"...)
- if c.subprotocol != "" {
- p = append(p, "Sec-WebSocket-Protocol: "...)
- p = append(p, c.subprotocol...)
- p = append(p, "\r\n"...)
- }
- if compress {
- p = append(p, "Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...)
- }
- for k, vs := range responseHeader {
- if k == "Sec-Websocket-Protocol" {
- continue
- }
- for _, v := range vs {
- p = append(p, k...)
- p = append(p, ": "...)
- for i := 0; i < len(v); i++ {
- b := v[i]
- if b <= 31 {
- // prevent response splitting.
- b = ' '
- }
- p = append(p, b)
- }
- p = append(p, "\r\n"...)
- }
- }
- p = append(p, "\r\n"...)
-
- // Clear deadlines set by HTTP server.
- netConn.SetDeadline(time.Time{})
-
- if u.HandshakeTimeout > 0 {
- netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
- }
- if _, err = netConn.Write(p); err != nil {
- netConn.Close()
- return nil, err
- }
- if u.HandshakeTimeout > 0 {
- netConn.SetWriteDeadline(time.Time{})
- }
-
- return c, nil
-}
-
-// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
-//
-// Deprecated: Use websocket.Upgrader instead.
-//
-// Upgrade does not perform origin checking. The application is responsible for
-// checking the Origin header before calling Upgrade. An example implementation
-// of the same origin policy check is:
-//
-// if req.Header.Get("Origin") != "http://"+req.Host {
-// http.Error(w, "Origin not allowed", http.StatusForbidden)
-// return
-// }
-//
-// If the endpoint supports subprotocols, then the application is responsible
-// for negotiating the protocol used on the connection. Use the Subprotocols()
-// function to get the subprotocols requested by the client. Use the
-// Sec-Websocket-Protocol response header to specify the subprotocol selected
-// by the application.
-//
-// The responseHeader is included in the response to the client's upgrade
-// request. Use the responseHeader to specify cookies (Set-Cookie) and the
-// negotiated subprotocol (Sec-Websocket-Protocol).
-//
-// The connection buffers IO to the underlying network connection. The
-// readBufSize and writeBufSize parameters specify the size of the buffers to
-// use. Messages can be larger than the buffers.
-//
-// If the request is not a valid WebSocket handshake, then Upgrade returns an
-// error of type HandshakeError. Applications should handle this error by
-// replying to the client with an HTTP error response.
-func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
- u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
- u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
- // don't return errors to maintain backwards compatibility
- }
- u.CheckOrigin = func(r *http.Request) bool {
- // allow all connections by default
- return true
- }
- return u.Upgrade(w, r, responseHeader)
-}
-
-// Subprotocols returns the subprotocols requested by the client in the
-// Sec-Websocket-Protocol header.
-func Subprotocols(r *http.Request) []string {
- h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
- if h == "" {
- return nil
- }
- protocols := strings.Split(h, ",")
- for i := range protocols {
- protocols[i] = strings.TrimSpace(protocols[i])
- }
- return protocols
-}
-
-// IsWebSocketUpgrade returns true if the client requested upgrade to the
-// WebSocket protocol.
-func IsWebSocketUpgrade(r *http.Request) bool {
- return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
- tokenListContainsValue(r.Header, "Upgrade", "websocket")
-}
-
-// bufioReaderSize size returns the size of a bufio.Reader.
-func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int {
- // This code assumes that peek on a reset reader returns
- // bufio.Reader.buf[:0].
- // TODO: Use bufio.Reader.Size() after Go 1.10
- br.Reset(originalReader)
- if p, err := br.Peek(0); err == nil {
- return cap(p)
- }
- return 0
-}
-
-// writeHook is an io.Writer that records the last slice passed to it vio
-// io.Writer.Write.
-type writeHook struct {
- p []byte
-}
-
-func (wh *writeHook) Write(p []byte) (int, error) {
- wh.p = p
- return len(p), nil
-}
-
-// bufioWriterBuffer grabs the buffer from a bufio.Writer.
-func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte {
- // This code assumes that bufio.Writer.buf[:1] is passed to the
- // bufio.Writer's underlying writer.
- var wh writeHook
- bw.Reset(&wh)
- bw.WriteByte(0)
- bw.Flush()
-
- bw.Reset(originalWriter)
-
- return wh.p[:cap(wh.p)]
-}
diff --git a/vendor/github.com/gorilla/websocket/trace.go b/vendor/github.com/gorilla/websocket/trace.go
deleted file mode 100644
index 834f122a00d..00000000000
--- a/vendor/github.com/gorilla/websocket/trace.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// +build go1.8
-
-package websocket
-
-import (
- "crypto/tls"
- "net/http/httptrace"
-)
-
-func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
- if trace.TLSHandshakeStart != nil {
- trace.TLSHandshakeStart()
- }
- err := doHandshake(tlsConn, cfg)
- if trace.TLSHandshakeDone != nil {
- trace.TLSHandshakeDone(tlsConn.ConnectionState(), err)
- }
- return err
-}
diff --git a/vendor/github.com/gorilla/websocket/trace_17.go b/vendor/github.com/gorilla/websocket/trace_17.go
deleted file mode 100644
index 77d05a0b574..00000000000
--- a/vendor/github.com/gorilla/websocket/trace_17.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build !go1.8
-
-package websocket
-
-import (
- "crypto/tls"
- "net/http/httptrace"
-)
-
-func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error {
- return doHandshake(tlsConn, cfg)
-}
diff --git a/vendor/github.com/gorilla/websocket/util.go b/vendor/github.com/gorilla/websocket/util.go
deleted file mode 100644
index 7bf2f66c674..00000000000
--- a/vendor/github.com/gorilla/websocket/util.go
+++ /dev/null
@@ -1,283 +0,0 @@
-// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "crypto/rand"
- "crypto/sha1"
- "encoding/base64"
- "io"
- "net/http"
- "strings"
- "unicode/utf8"
-)
-
-var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
-
-func computeAcceptKey(challengeKey string) string {
- h := sha1.New()
- h.Write([]byte(challengeKey))
- h.Write(keyGUID)
- return base64.StdEncoding.EncodeToString(h.Sum(nil))
-}
-
-func generateChallengeKey() (string, error) {
- p := make([]byte, 16)
- if _, err := io.ReadFull(rand.Reader, p); err != nil {
- return "", err
- }
- return base64.StdEncoding.EncodeToString(p), nil
-}
-
-// Token octets per RFC 2616.
-var isTokenOctet = [256]bool{
- '!': true,
- '#': true,
- '$': true,
- '%': true,
- '&': true,
- '\'': true,
- '*': true,
- '+': true,
- '-': true,
- '.': true,
- '0': true,
- '1': true,
- '2': true,
- '3': true,
- '4': true,
- '5': true,
- '6': true,
- '7': true,
- '8': true,
- '9': true,
- 'A': true,
- 'B': true,
- 'C': true,
- 'D': true,
- 'E': true,
- 'F': true,
- 'G': true,
- 'H': true,
- 'I': true,
- 'J': true,
- 'K': true,
- 'L': true,
- 'M': true,
- 'N': true,
- 'O': true,
- 'P': true,
- 'Q': true,
- 'R': true,
- 'S': true,
- 'T': true,
- 'U': true,
- 'W': true,
- 'V': true,
- 'X': true,
- 'Y': true,
- 'Z': true,
- '^': true,
- '_': true,
- '`': true,
- 'a': true,
- 'b': true,
- 'c': true,
- 'd': true,
- 'e': true,
- 'f': true,
- 'g': true,
- 'h': true,
- 'i': true,
- 'j': true,
- 'k': true,
- 'l': true,
- 'm': true,
- 'n': true,
- 'o': true,
- 'p': true,
- 'q': true,
- 'r': true,
- 's': true,
- 't': true,
- 'u': true,
- 'v': true,
- 'w': true,
- 'x': true,
- 'y': true,
- 'z': true,
- '|': true,
- '~': true,
-}
-
-// skipSpace returns a slice of the string s with all leading RFC 2616 linear
-// whitespace removed.
-func skipSpace(s string) (rest string) {
- i := 0
- for ; i < len(s); i++ {
- if b := s[i]; b != ' ' && b != '\t' {
- break
- }
- }
- return s[i:]
-}
-
-// nextToken returns the leading RFC 2616 token of s and the string following
-// the token.
-func nextToken(s string) (token, rest string) {
- i := 0
- for ; i < len(s); i++ {
- if !isTokenOctet[s[i]] {
- break
- }
- }
- return s[:i], s[i:]
-}
-
-// nextTokenOrQuoted returns the leading token or quoted string per RFC 2616
-// and the string following the token or quoted string.
-func nextTokenOrQuoted(s string) (value string, rest string) {
- if !strings.HasPrefix(s, "\"") {
- return nextToken(s)
- }
- s = s[1:]
- for i := 0; i < len(s); i++ {
- switch s[i] {
- case '"':
- return s[:i], s[i+1:]
- case '\\':
- p := make([]byte, len(s)-1)
- j := copy(p, s[:i])
- escape := true
- for i = i + 1; i < len(s); i++ {
- b := s[i]
- switch {
- case escape:
- escape = false
- p[j] = b
- j++
- case b == '\\':
- escape = true
- case b == '"':
- return string(p[:j]), s[i+1:]
- default:
- p[j] = b
- j++
- }
- }
- return "", ""
- }
- }
- return "", ""
-}
-
-// equalASCIIFold returns true if s is equal to t with ASCII case folding as
-// defined in RFC 4790.
-func equalASCIIFold(s, t string) bool {
- for s != "" && t != "" {
- sr, size := utf8.DecodeRuneInString(s)
- s = s[size:]
- tr, size := utf8.DecodeRuneInString(t)
- t = t[size:]
- if sr == tr {
- continue
- }
- if 'A' <= sr && sr <= 'Z' {
- sr = sr + 'a' - 'A'
- }
- if 'A' <= tr && tr <= 'Z' {
- tr = tr + 'a' - 'A'
- }
- if sr != tr {
- return false
- }
- }
- return s == t
-}
-
-// tokenListContainsValue returns true if the 1#token header with the given
-// name contains a token equal to value with ASCII case folding.
-func tokenListContainsValue(header http.Header, name string, value string) bool {
-headers:
- for _, s := range header[name] {
- for {
- var t string
- t, s = nextToken(skipSpace(s))
- if t == "" {
- continue headers
- }
- s = skipSpace(s)
- if s != "" && s[0] != ',' {
- continue headers
- }
- if equalASCIIFold(t, value) {
- return true
- }
- if s == "" {
- continue headers
- }
- s = s[1:]
- }
- }
- return false
-}
-
-// parseExtensions parses WebSocket extensions from a header.
-func parseExtensions(header http.Header) []map[string]string {
- // From RFC 6455:
- //
- // Sec-WebSocket-Extensions = extension-list
- // extension-list = 1#extension
- // extension = extension-token *( ";" extension-param )
- // extension-token = registered-token
- // registered-token = token
- // extension-param = token [ "=" (token | quoted-string) ]
- // ;When using the quoted-string syntax variant, the value
- // ;after quoted-string unescaping MUST conform to the
- // ;'token' ABNF.
-
- var result []map[string]string
-headers:
- for _, s := range header["Sec-Websocket-Extensions"] {
- for {
- var t string
- t, s = nextToken(skipSpace(s))
- if t == "" {
- continue headers
- }
- ext := map[string]string{"": t}
- for {
- s = skipSpace(s)
- if !strings.HasPrefix(s, ";") {
- break
- }
- var k string
- k, s = nextToken(skipSpace(s[1:]))
- if k == "" {
- continue headers
- }
- s = skipSpace(s)
- var v string
- if strings.HasPrefix(s, "=") {
- v, s = nextTokenOrQuoted(skipSpace(s[1:]))
- s = skipSpace(s)
- }
- if s != "" && s[0] != ',' && s[0] != ';' {
- continue headers
- }
- ext[k] = v
- }
- if s != "" && s[0] != ',' {
- continue headers
- }
- result = append(result, ext)
- if s == "" {
- continue headers
- }
- s = s[1:]
- }
- }
- return result
-}
diff --git a/vendor/github.com/gorilla/websocket/x_net_proxy.go b/vendor/github.com/gorilla/websocket/x_net_proxy.go
deleted file mode 100644
index 2e668f6b882..00000000000
--- a/vendor/github.com/gorilla/websocket/x_net_proxy.go
+++ /dev/null
@@ -1,473 +0,0 @@
-// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
-//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy
-
-// Package proxy provides support for a variety of protocols to proxy network
-// data.
-//
-
-package websocket
-
-import (
- "errors"
- "io"
- "net"
- "net/url"
- "os"
- "strconv"
- "strings"
- "sync"
-)
-
-type proxy_direct struct{}
-
-// Direct is a direct proxy: one that makes network connections directly.
-var proxy_Direct = proxy_direct{}
-
-func (proxy_direct) Dial(network, addr string) (net.Conn, error) {
- return net.Dial(network, addr)
-}
-
-// A PerHost directs connections to a default Dialer unless the host name
-// requested matches one of a number of exceptions.
-type proxy_PerHost struct {
- def, bypass proxy_Dialer
-
- bypassNetworks []*net.IPNet
- bypassIPs []net.IP
- bypassZones []string
- bypassHosts []string
-}
-
-// NewPerHost returns a PerHost Dialer that directs connections to either
-// defaultDialer or bypass, depending on whether the connection matches one of
-// the configured rules.
-func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost {
- return &proxy_PerHost{
- def: defaultDialer,
- bypass: bypass,
- }
-}
-
-// Dial connects to the address addr on the given network through either
-// defaultDialer or bypass.
-func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) {
- host, _, err := net.SplitHostPort(addr)
- if err != nil {
- return nil, err
- }
-
- return p.dialerForRequest(host).Dial(network, addr)
-}
-
-func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer {
- if ip := net.ParseIP(host); ip != nil {
- for _, net := range p.bypassNetworks {
- if net.Contains(ip) {
- return p.bypass
- }
- }
- for _, bypassIP := range p.bypassIPs {
- if bypassIP.Equal(ip) {
- return p.bypass
- }
- }
- return p.def
- }
-
- for _, zone := range p.bypassZones {
- if strings.HasSuffix(host, zone) {
- return p.bypass
- }
- if host == zone[1:] {
- // For a zone ".example.com", we match "example.com"
- // too.
- return p.bypass
- }
- }
- for _, bypassHost := range p.bypassHosts {
- if bypassHost == host {
- return p.bypass
- }
- }
- return p.def
-}
-
-// AddFromString parses a string that contains comma-separated values
-// specifying hosts that should use the bypass proxy. Each value is either an
-// IP address, a CIDR range, a zone (*.example.com) or a host name
-// (localhost). A best effort is made to parse the string and errors are
-// ignored.
-func (p *proxy_PerHost) AddFromString(s string) {
- hosts := strings.Split(s, ",")
- for _, host := range hosts {
- host = strings.TrimSpace(host)
- if len(host) == 0 {
- continue
- }
- if strings.Contains(host, "/") {
- // We assume that it's a CIDR address like 127.0.0.0/8
- if _, net, err := net.ParseCIDR(host); err == nil {
- p.AddNetwork(net)
- }
- continue
- }
- if ip := net.ParseIP(host); ip != nil {
- p.AddIP(ip)
- continue
- }
- if strings.HasPrefix(host, "*.") {
- p.AddZone(host[1:])
- continue
- }
- p.AddHost(host)
- }
-}
-
-// AddIP specifies an IP address that will use the bypass proxy. Note that
-// this will only take effect if a literal IP address is dialed. A connection
-// to a named host will never match an IP.
-func (p *proxy_PerHost) AddIP(ip net.IP) {
- p.bypassIPs = append(p.bypassIPs, ip)
-}
-
-// AddNetwork specifies an IP range that will use the bypass proxy. Note that
-// this will only take effect if a literal IP address is dialed. A connection
-// to a named host will never match.
-func (p *proxy_PerHost) AddNetwork(net *net.IPNet) {
- p.bypassNetworks = append(p.bypassNetworks, net)
-}
-
-// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
-// "example.com" matches "example.com" and all of its subdomains.
-func (p *proxy_PerHost) AddZone(zone string) {
- if strings.HasSuffix(zone, ".") {
- zone = zone[:len(zone)-1]
- }
- if !strings.HasPrefix(zone, ".") {
- zone = "." + zone
- }
- p.bypassZones = append(p.bypassZones, zone)
-}
-
-// AddHost specifies a host name that will use the bypass proxy.
-func (p *proxy_PerHost) AddHost(host string) {
- if strings.HasSuffix(host, ".") {
- host = host[:len(host)-1]
- }
- p.bypassHosts = append(p.bypassHosts, host)
-}
-
-// A Dialer is a means to establish a connection.
-type proxy_Dialer interface {
- // Dial connects to the given address via the proxy.
- Dial(network, addr string) (c net.Conn, err error)
-}
-
-// Auth contains authentication parameters that specific Dialers may require.
-type proxy_Auth struct {
- User, Password string
-}
-
-// FromEnvironment returns the dialer specified by the proxy related variables in
-// the environment.
-func proxy_FromEnvironment() proxy_Dialer {
- allProxy := proxy_allProxyEnv.Get()
- if len(allProxy) == 0 {
- return proxy_Direct
- }
-
- proxyURL, err := url.Parse(allProxy)
- if err != nil {
- return proxy_Direct
- }
- proxy, err := proxy_FromURL(proxyURL, proxy_Direct)
- if err != nil {
- return proxy_Direct
- }
-
- noProxy := proxy_noProxyEnv.Get()
- if len(noProxy) == 0 {
- return proxy
- }
-
- perHost := proxy_NewPerHost(proxy, proxy_Direct)
- perHost.AddFromString(noProxy)
- return perHost
-}
-
-// proxySchemes is a map from URL schemes to a function that creates a Dialer
-// from a URL with such a scheme.
-var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)
-
-// RegisterDialerType takes a URL scheme and a function to generate Dialers from
-// a URL with that scheme and a forwarding Dialer. Registered schemes are used
-// by FromURL.
-func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) {
- if proxy_proxySchemes == nil {
- proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error))
- }
- proxy_proxySchemes[scheme] = f
-}
-
-// FromURL returns a Dialer given a URL specification and an underlying
-// Dialer for it to make network requests.
-func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) {
- var auth *proxy_Auth
- if u.User != nil {
- auth = new(proxy_Auth)
- auth.User = u.User.Username()
- if p, ok := u.User.Password(); ok {
- auth.Password = p
- }
- }
-
- switch u.Scheme {
- case "socks5":
- return proxy_SOCKS5("tcp", u.Host, auth, forward)
- }
-
- // If the scheme doesn't match any of the built-in schemes, see if it
- // was registered by another package.
- if proxy_proxySchemes != nil {
- if f, ok := proxy_proxySchemes[u.Scheme]; ok {
- return f(u, forward)
- }
- }
-
- return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
-}
-
-var (
- proxy_allProxyEnv = &proxy_envOnce{
- names: []string{"ALL_PROXY", "all_proxy"},
- }
- proxy_noProxyEnv = &proxy_envOnce{
- names: []string{"NO_PROXY", "no_proxy"},
- }
-)
-
-// envOnce looks up an environment variable (optionally by multiple
-// names) once. It mitigates expensive lookups on some platforms
-// (e.g. Windows).
-// (Borrowed from net/http/transport.go)
-type proxy_envOnce struct {
- names []string
- once sync.Once
- val string
-}
-
-func (e *proxy_envOnce) Get() string {
- e.once.Do(e.init)
- return e.val
-}
-
-func (e *proxy_envOnce) init() {
- for _, n := range e.names {
- e.val = os.Getenv(n)
- if e.val != "" {
- return
- }
- }
-}
-
-// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
-// with an optional username and password. See RFC 1928 and RFC 1929.
-func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) {
- s := &proxy_socks5{
- network: network,
- addr: addr,
- forward: forward,
- }
- if auth != nil {
- s.user = auth.User
- s.password = auth.Password
- }
-
- return s, nil
-}
-
-type proxy_socks5 struct {
- user, password string
- network, addr string
- forward proxy_Dialer
-}
-
-const proxy_socks5Version = 5
-
-const (
- proxy_socks5AuthNone = 0
- proxy_socks5AuthPassword = 2
-)
-
-const proxy_socks5Connect = 1
-
-const (
- proxy_socks5IP4 = 1
- proxy_socks5Domain = 3
- proxy_socks5IP6 = 4
-)
-
-var proxy_socks5Errors = []string{
- "",
- "general failure",
- "connection forbidden",
- "network unreachable",
- "host unreachable",
- "connection refused",
- "TTL expired",
- "command not supported",
- "address type not supported",
-}
-
-// Dial connects to the address addr on the given network via the SOCKS5 proxy.
-func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) {
- switch network {
- case "tcp", "tcp6", "tcp4":
- default:
- return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
- }
-
- conn, err := s.forward.Dial(s.network, s.addr)
- if err != nil {
- return nil, err
- }
- if err := s.connect(conn, addr); err != nil {
- conn.Close()
- return nil, err
- }
- return conn, nil
-}
-
-// connect takes an existing connection to a socks5 proxy server,
-// and commands the server to extend that connection to target,
-// which must be a canonical address with a host and port.
-func (s *proxy_socks5) connect(conn net.Conn, target string) error {
- host, portStr, err := net.SplitHostPort(target)
- if err != nil {
- return err
- }
-
- port, err := strconv.Atoi(portStr)
- if err != nil {
- return errors.New("proxy: failed to parse port number: " + portStr)
- }
- if port < 1 || port > 0xffff {
- return errors.New("proxy: port number out of range: " + portStr)
- }
-
- // the size here is just an estimate
- buf := make([]byte, 0, 6+len(host))
-
- buf = append(buf, proxy_socks5Version)
- if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
- buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword)
- } else {
- buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone)
- }
-
- if _, err := conn.Write(buf); err != nil {
- return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if _, err := io.ReadFull(conn, buf[:2]); err != nil {
- return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
- if buf[0] != 5 {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
- }
- if buf[1] == 0xff {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
- }
-
- // See RFC 1929
- if buf[1] == proxy_socks5AuthPassword {
- buf = buf[:0]
- buf = append(buf, 1 /* password protocol version */)
- buf = append(buf, uint8(len(s.user)))
- buf = append(buf, s.user...)
- buf = append(buf, uint8(len(s.password)))
- buf = append(buf, s.password...)
-
- if _, err := conn.Write(buf); err != nil {
- return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if _, err := io.ReadFull(conn, buf[:2]); err != nil {
- return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if buf[1] != 0 {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
- }
- }
-
- buf = buf[:0]
- buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */)
-
- if ip := net.ParseIP(host); ip != nil {
- if ip4 := ip.To4(); ip4 != nil {
- buf = append(buf, proxy_socks5IP4)
- ip = ip4
- } else {
- buf = append(buf, proxy_socks5IP6)
- }
- buf = append(buf, ip...)
- } else {
- if len(host) > 255 {
- return errors.New("proxy: destination host name too long: " + host)
- }
- buf = append(buf, proxy_socks5Domain)
- buf = append(buf, byte(len(host)))
- buf = append(buf, host...)
- }
- buf = append(buf, byte(port>>8), byte(port))
-
- if _, err := conn.Write(buf); err != nil {
- return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if _, err := io.ReadFull(conn, buf[:4]); err != nil {
- return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- failure := "unknown error"
- if int(buf[1]) < len(proxy_socks5Errors) {
- failure = proxy_socks5Errors[buf[1]]
- }
-
- if len(failure) > 0 {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
- }
-
- bytesToDiscard := 0
- switch buf[3] {
- case proxy_socks5IP4:
- bytesToDiscard = net.IPv4len
- case proxy_socks5IP6:
- bytesToDiscard = net.IPv6len
- case proxy_socks5Domain:
- _, err := io.ReadFull(conn, buf[:1])
- if err != nil {
- return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
- bytesToDiscard = int(buf[0])
- default:
- return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
- }
-
- if cap(buf) < bytesToDiscard {
- buf = make([]byte, bytesToDiscard)
- } else {
- buf = buf[:bytesToDiscard]
- }
- if _, err := io.ReadFull(conn, buf); err != nil {
- return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- // Also need to discard the port number
- if _, err := io.ReadFull(conn, buf[:2]); err != nil {
- return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- return nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/LICENSE b/vendor/github.com/hashicorp/consul/api/LICENSE
deleted file mode 100644
index c33dcc7c928..00000000000
--- a/vendor/github.com/hashicorp/consul/api/LICENSE
+++ /dev/null
@@ -1,354 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. “Contributorâ€
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. “Contributor Versionâ€
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor’s Contribution.
-
-1.3. “Contributionâ€
-
- means Covered Software of a particular Contributor.
-
-1.4. “Covered Softwareâ€
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. “Incompatible With Secondary Licensesâ€
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of version
- 1.1 or earlier of the License, but not also under the terms of a
- Secondary License.
-
-1.6. “Executable Formâ€
-
- means any form of the work other than Source Code Form.
-
-1.7. “Larger Workâ€
-
- means a work that combines Covered Software with other material, in a separate
- file or files, that is not Covered Software.
-
-1.8. “Licenseâ€
-
- means this document.
-
-1.9. “Licensableâ€
-
- means having the right to grant, to the maximum extent possible, whether at the
- time of the initial grant or subsequently, any and all of the rights conveyed by
- this License.
-
-1.10. “Modificationsâ€
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to, deletion
- from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. “Patent Claims†of a Contributor
-
- means any patent claim(s), including without limitation, method, process,
- and apparatus claims, in any patent Licensable by such Contributor that
- would be infringed, but for the grant of the License, by the making,
- using, selling, offering for sale, having made, import, or transfer of
- either its Contributions or its Contributor Version.
-
-1.12. “Secondary Licenseâ€
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. “Source Code Formâ€
-
- means the form of the work preferred for making modifications.
-
-1.14. “You†(or “Yourâ€)
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, “You†includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, “control†means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or as
- part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its Contributions
- or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution become
- effective for each Contribution on the date the Contributor first distributes
- such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under this
- License. No additional rights or licenses will be implied from the distribution
- or licensing of Covered Software under this License. Notwithstanding Section
- 2.1(b) above, no patent license is granted by a Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party’s
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of its
- Contributions.
-
- This License does not grant any rights in the trademarks, service marks, or
- logos of any Contributor (except as may be necessary to comply with the
- notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this License
- (see Section 10.2) or under the terms of a Secondary License (if permitted
- under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its Contributions
- are its original creation(s) or it has sufficient rights to grant the
- rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under applicable
- copyright doctrines of fair use, fair dealing, or other equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under the
- terms of this License. You must inform recipients that the Source Code Form
- of the Covered Software is governed by the terms of this License, and how
- they can obtain a copy of this License. You may not attempt to alter or
- restrict the recipients’ rights in the Source Code Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this License,
- or sublicense it under different terms, provided that the license for
- the Executable Form does not attempt to limit or alter the recipients’
- rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for the
- Covered Software. If the Larger Work is a combination of Covered Software
- with a work governed by one or more Secondary Licenses, and the Covered
- Software is not Incompatible With Secondary Licenses, this License permits
- You to additionally distribute such Covered Software under the terms of
- such Secondary License(s), so that the recipient of the Larger Work may, at
- their option, further distribute the Covered Software under the terms of
- either this License or such Secondary License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices (including
- copyright notices, patent notices, disclaimers of warranty, or limitations
- of liability) contained within the Source Code Form of the Covered
- Software, except that You may alter any license notices to the extent
- required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on behalf
- of any Contributor. You must make it absolutely clear that any such
- warranty, support, indemnity, or liability obligation is offered by You
- alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute, judicial
- order, or regulation then You must: (a) comply with the terms of this License
- to the maximum extent possible; and (b) describe the limitations and the code
- they affect. Such description must be placed in a text file included with all
- distributions of the Covered Software under this License. Except to the
- extent prohibited by statute or regulation, such description must be
- sufficiently detailed for a recipient of ordinary skill to be able to
- understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing basis,
- if such Contributor fails to notify You of the non-compliance by some
- reasonable means prior to 60 days after You have come back into compliance.
- Moreover, Your grants from a particular Contributor are reinstated on an
- ongoing basis if such Contributor notifies You of the non-compliance by
- some reasonable means, this is the first time You have received notice of
- non-compliance with this License from such Contributor, and You become
- compliant prior to 30 days after Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions, counter-claims,
- and cross-claims) alleging that a Contributor Version directly or
- indirectly infringes any patent, then the rights granted to You by any and
- all Contributors for the Covered Software under Section 2.1 of this License
- shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an “as is†basis, without
- warranty of any kind, either expressed, implied, or statutory, including,
- without limitation, warranties that the Covered Software is free of defects,
- merchantable, fit for a particular purpose or non-infringing. The entire
- risk as to the quality and performance of the Covered Software is with You.
- Should any Covered Software prove defective in any respect, You (not any
- Contributor) assume the cost of any necessary servicing, repair, or
- correction. This disclaimer of warranty constitutes an essential part of this
- License. No use of any Covered Software is authorized under this License
- except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from such
- party’s negligence to the extent applicable law prohibits such limitation.
- Some jurisdictions do not allow the exclusion or limitation of incidental or
- consequential damages, so this exclusion and limitation may not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts of
- a jurisdiction where the defendant maintains its principal place of business
- and such litigation shall be governed by laws of that jurisdiction, without
- reference to its conflict-of-law provisions. Nothing in this Section shall
- prevent a party’s ability to bring cross-claims or counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject matter
- hereof. If any provision of this License is held to be unenforceable, such
- provision shall be reformed only to the extent necessary to make it
- enforceable. Any law or regulation which provides that the language of a
- contract shall be construed against the drafter shall not be used to construe
- this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version of
- the License under which You originally received the Covered Software, or
- under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a modified
- version of this License if you rename the license and remove any
- references to the name of the license steward (except to note that such
- modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
- If You choose to distribute Source Code Form that is Incompatible With
- Secondary Licenses under the terms of this version of the License, the
- notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file, then
-You may include the notice in a location (such as a LICENSE file in a relevant
-directory) where a recipient would be likely to look for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - “Incompatible With Secondary Licenses†Notice
-
- This Source Code Form is “Incompatible
- With Secondary Licensesâ€, as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/consul/api/README.md b/vendor/github.com/hashicorp/consul/api/README.md
deleted file mode 100644
index 3255cbb246a..00000000000
--- a/vendor/github.com/hashicorp/consul/api/README.md
+++ /dev/null
@@ -1,67 +0,0 @@
-Consul API client
-=================
-
-This package provides the `api` package which attempts to
-provide programmatic access to the full Consul API.
-
-Currently, all of the Consul APIs included in version 0.6.0 are supported.
-
-Documentation
-=============
-
-The full documentation is available on [Godoc](https://godoc.org/github.com/hashicorp/consul/api)
-
-Usage
-=====
-
-Below is an example of using the Consul client:
-
-```go
-package main
-
-import "github.com/hashicorp/consul/api"
-import "fmt"
-
-func main() {
- // Get a new client
- client, err := api.NewClient(api.DefaultConfig())
- if err != nil {
- panic(err)
- }
-
- // Get a handle to the KV API
- kv := client.KV()
-
- // PUT a new KV pair
- p := &api.KVPair{Key: "REDIS_MAXCLIENTS", Value: []byte("1000")}
- _, err = kv.Put(p, nil)
- if err != nil {
- panic(err)
- }
-
- // Lookup the pair
- pair, _, err := kv.Get("REDIS_MAXCLIENTS", nil)
- if err != nil {
- panic(err)
- }
- fmt.Printf("KV: %v %s\n", pair.Key, pair.Value)
-}
-```
-
-To run this example, start a Consul server:
-
-```bash
-consul agent -dev
-```
-
-Copy the code above into a file such as `main.go`.
-
-Install and run. You'll see a key (`REDIS_MAXCLIENTS`) and value (`1000`) printed.
-
-```bash
-$ go get
-$ go run main.go
-KV: REDIS_MAXCLIENTS 1000
-```
-
-After running the code, you can also view the values in the Consul UI on your local machine at http://localhost:8500/ui/dc1/kv
diff --git a/vendor/github.com/hashicorp/consul/api/acl.go b/vendor/github.com/hashicorp/consul/api/acl.go
deleted file mode 100644
index 124409ff2b7..00000000000
--- a/vendor/github.com/hashicorp/consul/api/acl.go
+++ /dev/null
@@ -1,1116 +0,0 @@
-package api
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "net/url"
- "time"
-
- "github.com/mitchellh/mapstructure"
-)
-
-const (
- // ACLClientType is the client type token
- ACLClientType = "client"
-
- // ACLManagementType is the management type token
- ACLManagementType = "management"
-)
-
-type ACLTokenPolicyLink struct {
- ID string
- Name string
-}
-type ACLTokenRoleLink struct {
- ID string
- Name string
-}
-
-// ACLToken represents an ACL Token
-type ACLToken struct {
- CreateIndex uint64
- ModifyIndex uint64
- AccessorID string
- SecretID string
- Description string
- Policies []*ACLTokenPolicyLink `json:",omitempty"`
- Roles []*ACLTokenRoleLink `json:",omitempty"`
- ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
- Local bool
- ExpirationTTL time.Duration `json:",omitempty"`
- ExpirationTime *time.Time `json:",omitempty"`
- CreateTime time.Time `json:",omitempty"`
- Hash []byte `json:",omitempty"`
-
- // DEPRECATED (ACL-Legacy-Compat)
- // Rules will only be present for legacy tokens returned via the new APIs
- Rules string `json:",omitempty"`
-}
-
-type ACLTokenListEntry struct {
- CreateIndex uint64
- ModifyIndex uint64
- AccessorID string
- Description string
- Policies []*ACLTokenPolicyLink `json:",omitempty"`
- Roles []*ACLTokenRoleLink `json:",omitempty"`
- ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
- Local bool
- ExpirationTime *time.Time `json:",omitempty"`
- CreateTime time.Time
- Hash []byte
- Legacy bool
-}
-
-// ACLEntry is used to represent a legacy ACL token
-// The legacy tokens are deprecated.
-type ACLEntry struct {
- CreateIndex uint64
- ModifyIndex uint64
- ID string
- Name string
- Type string
- Rules string
-}
-
-// ACLReplicationStatus is used to represent the status of ACL replication.
-type ACLReplicationStatus struct {
- Enabled bool
- Running bool
- SourceDatacenter string
- ReplicationType string
- ReplicatedIndex uint64
- ReplicatedRoleIndex uint64
- ReplicatedTokenIndex uint64
- LastSuccess time.Time
- LastError time.Time
-}
-
-// ACLServiceIdentity represents a high-level grant of all necessary privileges
-// to assume the identity of the named Service in the Catalog and within
-// Connect.
-type ACLServiceIdentity struct {
- ServiceName string
- Datacenters []string `json:",omitempty"`
-}
-
-// ACLPolicy represents an ACL Policy.
-type ACLPolicy struct {
- ID string
- Name string
- Description string
- Rules string
- Datacenters []string
- Hash []byte
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-type ACLPolicyListEntry struct {
- ID string
- Name string
- Description string
- Datacenters []string
- Hash []byte
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-type ACLRolePolicyLink struct {
- ID string
- Name string
-}
-
-// ACLRole represents an ACL Role.
-type ACLRole struct {
- ID string
- Name string
- Description string
- Policies []*ACLRolePolicyLink `json:",omitempty"`
- ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
- Hash []byte
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-// BindingRuleBindType is the type of binding rule mechanism used.
-type BindingRuleBindType string
-
-const (
- // BindingRuleBindTypeService binds to a service identity with the given name.
- BindingRuleBindTypeService BindingRuleBindType = "service"
-
- // BindingRuleBindTypeRole binds to pre-existing roles with the given name.
- BindingRuleBindTypeRole BindingRuleBindType = "role"
-)
-
-type ACLBindingRule struct {
- ID string
- Description string
- AuthMethod string
- Selector string
- BindType BindingRuleBindType
- BindName string
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-type ACLAuthMethod struct {
- Name string
- Type string
- Description string
-
- // Configuration is arbitrary configuration for the auth method. This
- // should only contain primitive values and containers (such as lists and
- // maps).
- Config map[string]interface{}
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-type ACLAuthMethodListEntry struct {
- Name string
- Type string
- Description string
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-// ParseKubernetesAuthMethodConfig takes a raw config map and returns a parsed
-// KubernetesAuthMethodConfig.
-func ParseKubernetesAuthMethodConfig(raw map[string]interface{}) (*KubernetesAuthMethodConfig, error) {
- var config KubernetesAuthMethodConfig
- decodeConf := &mapstructure.DecoderConfig{
- Result: &config,
- WeaklyTypedInput: true,
- }
-
- decoder, err := mapstructure.NewDecoder(decodeConf)
- if err != nil {
- return nil, err
- }
-
- if err := decoder.Decode(raw); err != nil {
- return nil, fmt.Errorf("error decoding config: %s", err)
- }
-
- return &config, nil
-}
-
-// KubernetesAuthMethodConfig is the config for the built-in Consul auth method
-// for Kubernetes.
-type KubernetesAuthMethodConfig struct {
- Host string `json:",omitempty"`
- CACert string `json:",omitempty"`
- ServiceAccountJWT string `json:",omitempty"`
-}
-
-// RenderToConfig converts this into a map[string]interface{} suitable for use
-// in the ACLAuthMethod.Config field.
-func (c *KubernetesAuthMethodConfig) RenderToConfig() map[string]interface{} {
- return map[string]interface{}{
- "Host": c.Host,
- "CACert": c.CACert,
- "ServiceAccountJWT": c.ServiceAccountJWT,
- }
-}
-
-type ACLLoginParams struct {
- AuthMethod string
- BearerToken string
- Meta map[string]string `json:",omitempty"`
-}
-
-// ACL can be used to query the ACL endpoints
-type ACL struct {
- c *Client
-}
-
-// ACL returns a handle to the ACL endpoints
-func (c *Client) ACL() *ACL {
- return &ACL{c}
-}
-
-// Bootstrap is used to perform a one-time ACL bootstrap operation on a cluster
-// to get the first management token.
-func (a *ACL) Bootstrap() (*ACLToken, *WriteMeta, error) {
- r := a.c.newRequest("PUT", "/v1/acl/bootstrap")
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLToken
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return &out, wm, nil
-}
-
-// Create is used to generate a new token with the given parameters
-//
-// Deprecated: Use TokenCreate instead.
-func (a *ACL) Create(acl *ACLEntry, q *WriteOptions) (string, *WriteMeta, error) {
- r := a.c.newRequest("PUT", "/v1/acl/create")
- r.setWriteOptions(q)
- r.obj = acl
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return "", nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out struct{ ID string }
- if err := decodeBody(resp, &out); err != nil {
- return "", nil, err
- }
- return out.ID, wm, nil
-}
-
-// Update is used to update the rules of an existing token
-//
-// Deprecated: Use TokenUpdate instead.
-func (a *ACL) Update(acl *ACLEntry, q *WriteOptions) (*WriteMeta, error) {
- r := a.c.newRequest("PUT", "/v1/acl/update")
- r.setWriteOptions(q)
- r.obj = acl
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- return wm, nil
-}
-
-// Destroy is used to destroy a given ACL token ID
-//
-// Deprecated: Use TokenDelete instead.
-func (a *ACL) Destroy(id string, q *WriteOptions) (*WriteMeta, error) {
- r := a.c.newRequest("PUT", "/v1/acl/destroy/"+id)
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- return wm, nil
-}
-
-// Clone is used to return a new token cloned from an existing one
-//
-// Deprecated: Use TokenClone instead.
-func (a *ACL) Clone(id string, q *WriteOptions) (string, *WriteMeta, error) {
- r := a.c.newRequest("PUT", "/v1/acl/clone/"+id)
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return "", nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out struct{ ID string }
- if err := decodeBody(resp, &out); err != nil {
- return "", nil, err
- }
- return out.ID, wm, nil
-}
-
-// Info is used to query for information about an ACL token
-//
-// Deprecated: Use TokenRead instead.
-func (a *ACL) Info(id string, q *QueryOptions) (*ACLEntry, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/info/"+id)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var entries []*ACLEntry
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- if len(entries) > 0 {
- return entries[0], qm, nil
- }
- return nil, qm, nil
-}
-
-// List is used to get all the ACL tokens
-//
-// Deprecated: Use TokenList instead.
-func (a *ACL) List(q *QueryOptions) ([]*ACLEntry, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/list")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var entries []*ACLEntry
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// Replication returns the status of the ACL replication process in the datacenter
-func (a *ACL) Replication(q *QueryOptions) (*ACLReplicationStatus, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/replication")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var entries *ACLReplicationStatus
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// TokenCreate creates a new ACL token. If either the AccessorID or SecretID fields
-// of the ACLToken structure are empty they will be filled in by Consul.
-func (a *ACL) TokenCreate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
- r := a.c.newRequest("PUT", "/v1/acl/token")
- r.setWriteOptions(q)
- r.obj = token
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLToken
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// TokenUpdate updates a token in place without modifying its AccessorID or SecretID. A valid
-// AccessorID must be set in the ACLToken structure passed to this function but the SecretID may
-// be omitted and will be filled in by Consul with its existing value.
-func (a *ACL) TokenUpdate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
- if token.AccessorID == "" {
- return nil, nil, fmt.Errorf("Must specify an AccessorID for Token Updating")
- }
- r := a.c.newRequest("PUT", "/v1/acl/token/"+token.AccessorID)
- r.setWriteOptions(q)
- r.obj = token
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLToken
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// TokenClone will create a new token with the same policies and locality as the original
-// token but will have its own auto-generated AccessorID and SecretID as well having the
-// description passed to this function. The tokenID parameter must be a valid Accessor ID
-// of an existing token.
-func (a *ACL) TokenClone(tokenID string, description string, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
- if tokenID == "" {
- return nil, nil, fmt.Errorf("Must specify a tokenID for Token Cloning")
- }
-
- r := a.c.newRequest("PUT", "/v1/acl/token/"+tokenID+"/clone")
- r.setWriteOptions(q)
- r.obj = struct{ Description string }{description}
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLToken
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// TokenDelete removes a single ACL token. The tokenID parameter must be a valid
-// Accessor ID of an existing token.
-func (a *ACL) TokenDelete(tokenID string, q *WriteOptions) (*WriteMeta, error) {
- r := a.c.newRequest("DELETE", "/v1/acl/token/"+tokenID)
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- return wm, nil
-}
-
-// TokenRead retrieves the full token details. The tokenID parameter must be a valid
-// Accessor ID of an existing token.
-func (a *ACL) TokenRead(tokenID string, q *QueryOptions) (*ACLToken, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/token/"+tokenID)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out ACLToken
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, qm, nil
-}
-
-// TokenReadSelf retrieves the full token details of the token currently
-// assigned to the API Client. In this manner its possible to read a token
-// by its Secret ID.
-func (a *ACL) TokenReadSelf(q *QueryOptions) (*ACLToken, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/token/self")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out ACLToken
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, qm, nil
-}
-
-// TokenList lists all tokens. The listing does not contain any SecretIDs as those
-// may only be retrieved by a call to TokenRead.
-func (a *ACL) TokenList(q *QueryOptions) ([]*ACLTokenListEntry, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/tokens")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var entries []*ACLTokenListEntry
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// PolicyCreate will create a new policy. It is not allowed for the policy parameters
-// ID field to be set as this will be generated by Consul while processing the request.
-func (a *ACL) PolicyCreate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) {
- if policy.ID != "" {
- return nil, nil, fmt.Errorf("Cannot specify an ID in Policy Creation")
- }
- r := a.c.newRequest("PUT", "/v1/acl/policy")
- r.setWriteOptions(q)
- r.obj = policy
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLPolicy
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// PolicyUpdate updates a policy. The ID field of the policy parameter must be set to an
-// existing policy ID
-func (a *ACL) PolicyUpdate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) {
- if policy.ID == "" {
- return nil, nil, fmt.Errorf("Must specify an ID in Policy Update")
- }
-
- r := a.c.newRequest("PUT", "/v1/acl/policy/"+policy.ID)
- r.setWriteOptions(q)
- r.obj = policy
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLPolicy
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// PolicyDelete deletes a policy given its ID.
-func (a *ACL) PolicyDelete(policyID string, q *WriteOptions) (*WriteMeta, error) {
- r := a.c.newRequest("DELETE", "/v1/acl/policy/"+policyID)
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- return wm, nil
-}
-
-// PolicyRead retrieves the policy details including the rule set.
-func (a *ACL) PolicyRead(policyID string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/policy/"+policyID)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out ACLPolicy
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, qm, nil
-}
-
-// PolicyList retrieves a listing of all policies. The listing does not include the
-// rules for any policy as those should be retrieved by subsequent calls to PolicyRead.
-func (a *ACL) PolicyList(q *QueryOptions) ([]*ACLPolicyListEntry, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/policies")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var entries []*ACLPolicyListEntry
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// RulesTranslate translates the legacy rule syntax into the current syntax.
-//
-// Deprecated: Support for the legacy syntax translation will be removed
-// when legacy ACL support is removed.
-func (a *ACL) RulesTranslate(rules io.Reader) (string, error) {
- r := a.c.newRequest("POST", "/v1/acl/rules/translate")
- r.body = rules
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return "", err
- }
- defer resp.Body.Close()
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- ruleBytes, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", fmt.Errorf("Failed to read translated rule body: %v", err)
- }
-
- return string(ruleBytes), nil
-}
-
-// RulesTranslateToken translates the rules associated with the legacy syntax
-// into the current syntax and returns the results.
-//
-// Deprecated: Support for the legacy syntax translation will be removed
-// when legacy ACL support is removed.
-func (a *ACL) RulesTranslateToken(tokenID string) (string, error) {
- r := a.c.newRequest("GET", "/v1/acl/rules/translate/"+tokenID)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return "", err
- }
- defer resp.Body.Close()
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- ruleBytes, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", fmt.Errorf("Failed to read translated rule body: %v", err)
- }
-
- return string(ruleBytes), nil
-}
-
-// RoleCreate will create a new role. It is not allowed for the role parameters
-// ID field to be set as this will be generated by Consul while processing the request.
-func (a *ACL) RoleCreate(role *ACLRole, q *WriteOptions) (*ACLRole, *WriteMeta, error) {
- if role.ID != "" {
- return nil, nil, fmt.Errorf("Cannot specify an ID in Role Creation")
- }
-
- r := a.c.newRequest("PUT", "/v1/acl/role")
- r.setWriteOptions(q)
- r.obj = role
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLRole
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// RoleUpdate updates a role. The ID field of the role parameter must be set to an
-// existing role ID
-func (a *ACL) RoleUpdate(role *ACLRole, q *WriteOptions) (*ACLRole, *WriteMeta, error) {
- if role.ID == "" {
- return nil, nil, fmt.Errorf("Must specify an ID in Role Update")
- }
-
- r := a.c.newRequest("PUT", "/v1/acl/role/"+role.ID)
- r.setWriteOptions(q)
- r.obj = role
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLRole
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// RoleDelete deletes a role given its ID.
-func (a *ACL) RoleDelete(roleID string, q *WriteOptions) (*WriteMeta, error) {
- r := a.c.newRequest("DELETE", "/v1/acl/role/"+roleID)
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- return wm, nil
-}
-
-// RoleRead retrieves the role details (by ID). Returns nil if not found.
-func (a *ACL) RoleRead(roleID string, q *QueryOptions) (*ACLRole, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/role/"+roleID)
- r.setQueryOptions(q)
- found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- if !found {
- return nil, qm, nil
- }
-
- var out ACLRole
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, qm, nil
-}
-
-// RoleReadByName retrieves the role details (by name). Returns nil if not found.
-func (a *ACL) RoleReadByName(roleName string, q *QueryOptions) (*ACLRole, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/role/name/"+url.QueryEscape(roleName))
- r.setQueryOptions(q)
- found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- if !found {
- return nil, qm, nil
- }
-
- var out ACLRole
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, qm, nil
-}
-
-// RoleList retrieves a listing of all roles. The listing does not include some
-// metadata for the role as those should be retrieved by subsequent calls to
-// RoleRead.
-func (a *ACL) RoleList(q *QueryOptions) ([]*ACLRole, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/roles")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var entries []*ACLRole
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// AuthMethodCreate will create a new auth method.
-func (a *ACL) AuthMethodCreate(method *ACLAuthMethod, q *WriteOptions) (*ACLAuthMethod, *WriteMeta, error) {
- if method.Name == "" {
- return nil, nil, fmt.Errorf("Must specify a Name in Auth Method Creation")
- }
-
- r := a.c.newRequest("PUT", "/v1/acl/auth-method")
- r.setWriteOptions(q)
- r.obj = method
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLAuthMethod
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// AuthMethodUpdate updates an auth method.
-func (a *ACL) AuthMethodUpdate(method *ACLAuthMethod, q *WriteOptions) (*ACLAuthMethod, *WriteMeta, error) {
- if method.Name == "" {
- return nil, nil, fmt.Errorf("Must specify a Name in Auth Method Update")
- }
-
- r := a.c.newRequest("PUT", "/v1/acl/auth-method/"+url.QueryEscape(method.Name))
- r.setWriteOptions(q)
- r.obj = method
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLAuthMethod
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// AuthMethodDelete deletes an auth method given its Name.
-func (a *ACL) AuthMethodDelete(methodName string, q *WriteOptions) (*WriteMeta, error) {
- if methodName == "" {
- return nil, fmt.Errorf("Must specify a Name in Auth Method Delete")
- }
-
- r := a.c.newRequest("DELETE", "/v1/acl/auth-method/"+url.QueryEscape(methodName))
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- return wm, nil
-}
-
-// AuthMethodRead retrieves the auth method. Returns nil if not found.
-func (a *ACL) AuthMethodRead(methodName string, q *QueryOptions) (*ACLAuthMethod, *QueryMeta, error) {
- if methodName == "" {
- return nil, nil, fmt.Errorf("Must specify a Name in Auth Method Read")
- }
-
- r := a.c.newRequest("GET", "/v1/acl/auth-method/"+url.QueryEscape(methodName))
- r.setQueryOptions(q)
- found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- if !found {
- return nil, qm, nil
- }
-
- var out ACLAuthMethod
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, qm, nil
-}
-
-// AuthMethodList retrieves a listing of all auth methods. The listing does not
-// include some metadata for the auth method as those should be retrieved by
-// subsequent calls to AuthMethodRead.
-func (a *ACL) AuthMethodList(q *QueryOptions) ([]*ACLAuthMethodListEntry, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/auth-methods")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var entries []*ACLAuthMethodListEntry
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// BindingRuleCreate will create a new binding rule. It is not allowed for the
-// binding rule parameter's ID field to be set as this will be generated by
-// Consul while processing the request.
-func (a *ACL) BindingRuleCreate(rule *ACLBindingRule, q *WriteOptions) (*ACLBindingRule, *WriteMeta, error) {
- if rule.ID != "" {
- return nil, nil, fmt.Errorf("Cannot specify an ID in Binding Rule Creation")
- }
-
- r := a.c.newRequest("PUT", "/v1/acl/binding-rule")
- r.setWriteOptions(q)
- r.obj = rule
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLBindingRule
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// BindingRuleUpdate updates a binding rule. The ID field of the role binding
-// rule parameter must be set to an existing binding rule ID.
-func (a *ACL) BindingRuleUpdate(rule *ACLBindingRule, q *WriteOptions) (*ACLBindingRule, *WriteMeta, error) {
- if rule.ID == "" {
- return nil, nil, fmt.Errorf("Must specify an ID in Binding Rule Update")
- }
-
- r := a.c.newRequest("PUT", "/v1/acl/binding-rule/"+rule.ID)
- r.setWriteOptions(q)
- r.obj = rule
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLBindingRule
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, wm, nil
-}
-
-// BindingRuleDelete deletes a binding rule given its ID.
-func (a *ACL) BindingRuleDelete(bindingRuleID string, q *WriteOptions) (*WriteMeta, error) {
- r := a.c.newRequest("DELETE", "/v1/acl/binding-rule/"+bindingRuleID)
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- return wm, nil
-}
-
-// BindingRuleRead retrieves the binding rule details. Returns nil if not found.
-func (a *ACL) BindingRuleRead(bindingRuleID string, q *QueryOptions) (*ACLBindingRule, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/binding-rule/"+bindingRuleID)
- r.setQueryOptions(q)
- found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- if !found {
- return nil, qm, nil
- }
-
- var out ACLBindingRule
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, qm, nil
-}
-
-// BindingRuleList retrieves a listing of all binding rules.
-func (a *ACL) BindingRuleList(methodName string, q *QueryOptions) ([]*ACLBindingRule, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/acl/binding-rules")
- if methodName != "" {
- r.params.Set("authmethod", methodName)
- }
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var entries []*ACLBindingRule
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// Login is used to exchange auth method credentials for a newly-minted Consul Token.
-func (a *ACL) Login(auth *ACLLoginParams, q *WriteOptions) (*ACLToken, *WriteMeta, error) {
- r := a.c.newRequest("POST", "/v1/acl/login")
- r.setWriteOptions(q)
- r.obj = auth
-
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out ACLToken
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return &out, wm, nil
-}
-
-// Logout is used to destroy a Consul Token created via Login().
-func (a *ACL) Logout(q *WriteOptions) (*WriteMeta, error) {
- r := a.c.newRequest("POST", "/v1/acl/logout")
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- return wm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/agent.go b/vendor/github.com/hashicorp/consul/api/agent.go
deleted file mode 100644
index 73c6e5881d9..00000000000
--- a/vendor/github.com/hashicorp/consul/api/agent.go
+++ /dev/null
@@ -1,999 +0,0 @@
-package api
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "net/http"
- "net/url"
-)
-
-// ServiceKind is the kind of service being registered.
-type ServiceKind string
-
-const (
- // ServiceKindTypical is a typical, classic Consul service. This is
- // represented by the absence of a value. This was chosen for ease of
- // backwards compatibility: existing services in the catalog would
- // default to the typical service.
- ServiceKindTypical ServiceKind = ""
-
- // ServiceKindConnectProxy is a proxy for the Connect feature. This
- // service proxies another service within Consul and speaks the connect
- // protocol.
- ServiceKindConnectProxy ServiceKind = "connect-proxy"
-
- // ServiceKindMeshGateway is a Mesh Gateway for the Connect feature. This
- // service will proxy connections based off the SNI header set by other
- // connect proxies
- ServiceKindMeshGateway ServiceKind = "mesh-gateway"
-)
-
-// UpstreamDestType is the type of upstream discovery mechanism.
-type UpstreamDestType string
-
-const (
- // UpstreamDestTypeService discovers instances via healthy service lookup.
- UpstreamDestTypeService UpstreamDestType = "service"
-
- // UpstreamDestTypePreparedQuery discovers instances via prepared query
- // execution.
- UpstreamDestTypePreparedQuery UpstreamDestType = "prepared_query"
-)
-
-// AgentCheck represents a check known to the agent
-type AgentCheck struct {
- Node string
- CheckID string
- Name string
- Status string
- Notes string
- Output string
- ServiceID string
- ServiceName string
- Type string
- Definition HealthCheckDefinition
-}
-
-// AgentWeights represent optional weights for a service
-type AgentWeights struct {
- Passing int
- Warning int
-}
-
-// AgentService represents a service known to the agent
-type AgentService struct {
- Kind ServiceKind `json:",omitempty"`
- ID string
- Service string
- Tags []string
- Meta map[string]string
- Port int
- Address string
- TaggedAddresses map[string]ServiceAddress `json:",omitempty"`
- Weights AgentWeights
- EnableTagOverride bool
- CreateIndex uint64 `json:",omitempty" bexpr:"-"`
- ModifyIndex uint64 `json:",omitempty" bexpr:"-"`
- ContentHash string `json:",omitempty" bexpr:"-"`
- Proxy *AgentServiceConnectProxyConfig `json:",omitempty"`
- Connect *AgentServiceConnect `json:",omitempty"`
-}
-
-// AgentServiceChecksInfo returns information about a Service and its checks
-type AgentServiceChecksInfo struct {
- AggregatedStatus string
- Service *AgentService
- Checks HealthChecks
-}
-
-// AgentServiceConnect represents the Connect configuration of a service.
-type AgentServiceConnect struct {
- Native bool `json:",omitempty"`
- SidecarService *AgentServiceRegistration `json:",omitempty" bexpr:"-"`
-}
-
-// AgentServiceConnectProxyConfig is the proxy configuration in a connect-proxy
-// ServiceDefinition or response.
-type AgentServiceConnectProxyConfig struct {
- DestinationServiceName string `json:",omitempty"`
- DestinationServiceID string `json:",omitempty"`
- LocalServiceAddress string `json:",omitempty"`
- LocalServicePort int `json:",omitempty"`
- Config map[string]interface{} `json:",omitempty" bexpr:"-"`
- Upstreams []Upstream `json:",omitempty"`
- MeshGateway MeshGatewayConfig `json:",omitempty"`
- Expose ExposeConfig `json:",omitempty"`
-}
-
-// AgentMember represents a cluster member known to the agent
-type AgentMember struct {
- Name string
- Addr string
- Port uint16
- Tags map[string]string
- Status int
- ProtocolMin uint8
- ProtocolMax uint8
- ProtocolCur uint8
- DelegateMin uint8
- DelegateMax uint8
- DelegateCur uint8
-}
-
-// AllSegments is used to select for all segments in MembersOpts.
-const AllSegments = "_all"
-
-// MembersOpts is used for querying member information.
-type MembersOpts struct {
- // WAN is whether to show members from the WAN.
- WAN bool
-
- // Segment is the LAN segment to show members for. Setting this to the
- // AllSegments value above will show members in all segments.
- Segment string
-}
-
-// AgentServiceRegistration is used to register a new service
-type AgentServiceRegistration struct {
- Kind ServiceKind `json:",omitempty"`
- ID string `json:",omitempty"`
- Name string `json:",omitempty"`
- Tags []string `json:",omitempty"`
- Port int `json:",omitempty"`
- Address string `json:",omitempty"`
- TaggedAddresses map[string]ServiceAddress `json:",omitempty"`
- EnableTagOverride bool `json:",omitempty"`
- Meta map[string]string `json:",omitempty"`
- Weights *AgentWeights `json:",omitempty"`
- Check *AgentServiceCheck
- Checks AgentServiceChecks
- Proxy *AgentServiceConnectProxyConfig `json:",omitempty"`
- Connect *AgentServiceConnect `json:",omitempty"`
-}
-
-// AgentCheckRegistration is used to register a new check
-type AgentCheckRegistration struct {
- ID string `json:",omitempty"`
- Name string `json:",omitempty"`
- Notes string `json:",omitempty"`
- ServiceID string `json:",omitempty"`
- AgentServiceCheck
-}
-
-// AgentServiceCheck is used to define a node or service level check
-type AgentServiceCheck struct {
- CheckID string `json:",omitempty"`
- Name string `json:",omitempty"`
- Args []string `json:"ScriptArgs,omitempty"`
- DockerContainerID string `json:",omitempty"`
- Shell string `json:",omitempty"` // Only supported for Docker.
- Interval string `json:",omitempty"`
- Timeout string `json:",omitempty"`
- TTL string `json:",omitempty"`
- HTTP string `json:",omitempty"`
- Header map[string][]string `json:",omitempty"`
- Method string `json:",omitempty"`
- TCP string `json:",omitempty"`
- Status string `json:",omitempty"`
- Notes string `json:",omitempty"`
- TLSSkipVerify bool `json:",omitempty"`
- GRPC string `json:",omitempty"`
- GRPCUseTLS bool `json:",omitempty"`
- AliasNode string `json:",omitempty"`
- AliasService string `json:",omitempty"`
-
- // In Consul 0.7 and later, checks that are associated with a service
- // may also contain this optional DeregisterCriticalServiceAfter field,
- // which is a timeout in the same Go time format as Interval and TTL. If
- // a check is in the critical state for more than this configured value,
- // then its associated service (and all of its associated checks) will
- // automatically be deregistered.
- DeregisterCriticalServiceAfter string `json:",omitempty"`
-}
-type AgentServiceChecks []*AgentServiceCheck
-
-// AgentToken is used when updating ACL tokens for an agent.
-type AgentToken struct {
- Token string
-}
-
-// Metrics info is used to store different types of metric values from the agent.
-type MetricsInfo struct {
- Timestamp string
- Gauges []GaugeValue
- Points []PointValue
- Counters []SampledValue
- Samples []SampledValue
-}
-
-// GaugeValue stores one value that is updated as time goes on, such as
-// the amount of memory allocated.
-type GaugeValue struct {
- Name string
- Value float32
- Labels map[string]string
-}
-
-// PointValue holds a series of points for a metric.
-type PointValue struct {
- Name string
- Points []float32
-}
-
-// SampledValue stores info about a metric that is incremented over time,
-// such as the number of requests to an HTTP endpoint.
-type SampledValue struct {
- Name string
- Count int
- Sum float64
- Min float64
- Max float64
- Mean float64
- Stddev float64
- Labels map[string]string
-}
-
-// AgentAuthorizeParams are the request parameters for authorizing a request.
-type AgentAuthorizeParams struct {
- Target string
- ClientCertURI string
- ClientCertSerial string
-}
-
-// AgentAuthorize is the response structure for Connect authorization.
-type AgentAuthorize struct {
- Authorized bool
- Reason string
-}
-
-// ConnectProxyConfig is the response structure for agent-local proxy
-// configuration.
-type ConnectProxyConfig struct {
- ProxyServiceID string
- TargetServiceID string
- TargetServiceName string
- ContentHash string
- Config map[string]interface{} `bexpr:"-"`
- Upstreams []Upstream
-}
-
-// Upstream is the response structure for a proxy upstream configuration.
-type Upstream struct {
- DestinationType UpstreamDestType `json:",omitempty"`
- DestinationNamespace string `json:",omitempty"`
- DestinationName string
- Datacenter string `json:",omitempty"`
- LocalBindAddress string `json:",omitempty"`
- LocalBindPort int `json:",omitempty"`
- Config map[string]interface{} `json:",omitempty" bexpr:"-"`
- MeshGateway MeshGatewayConfig `json:",omitempty"`
-}
-
-// Agent can be used to query the Agent endpoints
-type Agent struct {
- c *Client
-
- // cache the node name
- nodeName string
-}
-
-// Agent returns a handle to the agent endpoints
-func (c *Client) Agent() *Agent {
- return &Agent{c: c}
-}
-
-// Self is used to query the agent we are speaking to for
-// information about itself
-func (a *Agent) Self() (map[string]map[string]interface{}, error) {
- r := a.c.newRequest("GET", "/v1/agent/self")
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out map[string]map[string]interface{}
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// Host is used to retrieve information about the host the
-// agent is running on such as CPU, memory, and disk. Requires
-// a operator:read ACL token.
-func (a *Agent) Host() (map[string]interface{}, error) {
- r := a.c.newRequest("GET", "/v1/agent/host")
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out map[string]interface{}
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// Metrics is used to query the agent we are speaking to for
-// its current internal metric data
-func (a *Agent) Metrics() (*MetricsInfo, error) {
- r := a.c.newRequest("GET", "/v1/agent/metrics")
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out *MetricsInfo
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// Reload triggers a configuration reload for the agent we are connected to.
-func (a *Agent) Reload() error {
- r := a.c.newRequest("PUT", "/v1/agent/reload")
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// NodeName is used to get the node name of the agent
-func (a *Agent) NodeName() (string, error) {
- if a.nodeName != "" {
- return a.nodeName, nil
- }
- info, err := a.Self()
- if err != nil {
- return "", err
- }
- name := info["Config"]["NodeName"].(string)
- a.nodeName = name
- return name, nil
-}
-
-// Checks returns the locally registered checks
-func (a *Agent) Checks() (map[string]*AgentCheck, error) {
- return a.ChecksWithFilter("")
-}
-
-// ChecksWithFilter returns a subset of the locally registered checks that match
-// the given filter expression
-func (a *Agent) ChecksWithFilter(filter string) (map[string]*AgentCheck, error) {
- r := a.c.newRequest("GET", "/v1/agent/checks")
- r.filterQuery(filter)
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out map[string]*AgentCheck
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// Services returns the locally registered services
-func (a *Agent) Services() (map[string]*AgentService, error) {
- return a.ServicesWithFilter("")
-}
-
-// ServicesWithFilter returns a subset of the locally registered services that match
-// the given filter expression
-func (a *Agent) ServicesWithFilter(filter string) (map[string]*AgentService, error) {
- r := a.c.newRequest("GET", "/v1/agent/services")
- r.filterQuery(filter)
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out map[string]*AgentService
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
-
- return out, nil
-}
-
-// AgentHealthServiceByID returns for a given serviceID: the aggregated health status, the service definition or an error if any
-// - If the service is not found, will return status (critical, nil, nil)
-// - If the service is found, will return (critical|passing|warning), AgentServiceChecksInfo, nil)
-// - In all other cases, will return an error
-func (a *Agent) AgentHealthServiceByID(serviceID string) (string, *AgentServiceChecksInfo, error) {
- path := fmt.Sprintf("/v1/agent/health/service/id/%v", url.PathEscape(serviceID))
- r := a.c.newRequest("GET", path)
- r.params.Add("format", "json")
- r.header.Set("Accept", "application/json")
- _, resp, err := a.c.doRequest(r)
- if err != nil {
- return "", nil, err
- }
- defer resp.Body.Close()
- // Service not Found
- if resp.StatusCode == http.StatusNotFound {
- return HealthCritical, nil, nil
- }
- var out *AgentServiceChecksInfo
- if err := decodeBody(resp, &out); err != nil {
- return HealthCritical, out, err
- }
- switch resp.StatusCode {
- case http.StatusOK:
- return HealthPassing, out, nil
- case http.StatusTooManyRequests:
- return HealthWarning, out, nil
- case http.StatusServiceUnavailable:
- return HealthCritical, out, nil
- }
- return HealthCritical, out, fmt.Errorf("Unexpected Error Code %v for %s", resp.StatusCode, path)
-}
-
-// AgentHealthServiceByName returns for a given service name: the aggregated health status for all services
-// having the specified name.
-// - If no service is not found, will return status (critical, [], nil)
-// - If the service is found, will return (critical|passing|warning), []api.AgentServiceChecksInfo, nil)
-// - In all other cases, will return an error
-func (a *Agent) AgentHealthServiceByName(service string) (string, []AgentServiceChecksInfo, error) {
- path := fmt.Sprintf("/v1/agent/health/service/name/%v", url.PathEscape(service))
- r := a.c.newRequest("GET", path)
- r.params.Add("format", "json")
- r.header.Set("Accept", "application/json")
- _, resp, err := a.c.doRequest(r)
- if err != nil {
- return "", nil, err
- }
- defer resp.Body.Close()
- // Service not Found
- if resp.StatusCode == http.StatusNotFound {
- return HealthCritical, nil, nil
- }
- var out []AgentServiceChecksInfo
- if err := decodeBody(resp, &out); err != nil {
- return HealthCritical, out, err
- }
- switch resp.StatusCode {
- case http.StatusOK:
- return HealthPassing, out, nil
- case http.StatusTooManyRequests:
- return HealthWarning, out, nil
- case http.StatusServiceUnavailable:
- return HealthCritical, out, nil
- }
- return HealthCritical, out, fmt.Errorf("Unexpected Error Code %v for %s", resp.StatusCode, path)
-}
-
-// Service returns a locally registered service instance and allows for
-// hash-based blocking.
-//
-// Note that this uses an unconventional blocking mechanism since it's
-// agent-local state. That means there is no persistent raft index so we block
-// based on object hash instead.
-func (a *Agent) Service(serviceID string, q *QueryOptions) (*AgentService, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/agent/service/"+serviceID)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out *AgentService
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return out, qm, nil
-}
-
-// Members returns the known gossip members. The WAN
-// flag can be used to query a server for WAN members.
-func (a *Agent) Members(wan bool) ([]*AgentMember, error) {
- r := a.c.newRequest("GET", "/v1/agent/members")
- if wan {
- r.params.Set("wan", "1")
- }
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out []*AgentMember
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// MembersOpts returns the known gossip members and can be passed
-// additional options for WAN/segment filtering.
-func (a *Agent) MembersOpts(opts MembersOpts) ([]*AgentMember, error) {
- r := a.c.newRequest("GET", "/v1/agent/members")
- r.params.Set("segment", opts.Segment)
- if opts.WAN {
- r.params.Set("wan", "1")
- }
-
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out []*AgentMember
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// ServiceRegister is used to register a new service with
-// the local agent
-func (a *Agent) ServiceRegister(service *AgentServiceRegistration) error {
- r := a.c.newRequest("PUT", "/v1/agent/service/register")
- r.obj = service
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// ServiceDeregister is used to deregister a service with
-// the local agent
-func (a *Agent) ServiceDeregister(serviceID string) error {
- r := a.c.newRequest("PUT", "/v1/agent/service/deregister/"+serviceID)
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// PassTTL is used to set a TTL check to the passing state.
-//
-// DEPRECATION NOTICE: This interface is deprecated in favor of UpdateTTL().
-// The client interface will be removed in 0.8 or changed to use
-// UpdateTTL()'s endpoint and the server endpoints will be removed in 0.9.
-func (a *Agent) PassTTL(checkID, note string) error {
- return a.updateTTL(checkID, note, "pass")
-}
-
-// WarnTTL is used to set a TTL check to the warning state.
-//
-// DEPRECATION NOTICE: This interface is deprecated in favor of UpdateTTL().
-// The client interface will be removed in 0.8 or changed to use
-// UpdateTTL()'s endpoint and the server endpoints will be removed in 0.9.
-func (a *Agent) WarnTTL(checkID, note string) error {
- return a.updateTTL(checkID, note, "warn")
-}
-
-// FailTTL is used to set a TTL check to the failing state.
-//
-// DEPRECATION NOTICE: This interface is deprecated in favor of UpdateTTL().
-// The client interface will be removed in 0.8 or changed to use
-// UpdateTTL()'s endpoint and the server endpoints will be removed in 0.9.
-func (a *Agent) FailTTL(checkID, note string) error {
- return a.updateTTL(checkID, note, "fail")
-}
-
-// updateTTL is used to update the TTL of a check. This is the internal
-// method that uses the old API that's present in Consul versions prior to
-// 0.6.4. Since Consul didn't have an analogous "update" API before it seemed
-// ok to break this (former) UpdateTTL in favor of the new UpdateTTL below,
-// but keep the old Pass/Warn/Fail methods using the old API under the hood.
-//
-// DEPRECATION NOTICE: This interface is deprecated in favor of UpdateTTL().
-// The client interface will be removed in 0.8 and the server endpoints will
-// be removed in 0.9.
-func (a *Agent) updateTTL(checkID, note, status string) error {
- switch status {
- case "pass":
- case "warn":
- case "fail":
- default:
- return fmt.Errorf("Invalid status: %s", status)
- }
- endpoint := fmt.Sprintf("/v1/agent/check/%s/%s", status, checkID)
- r := a.c.newRequest("PUT", endpoint)
- r.params.Set("note", note)
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// checkUpdate is the payload for a PUT for a check update.
-type checkUpdate struct {
- // Status is one of the api.Health* states: HealthPassing
- // ("passing"), HealthWarning ("warning"), or HealthCritical
- // ("critical").
- Status string
-
- // Output is the information to post to the UI for operators as the
- // output of the process that decided to hit the TTL check. This is
- // different from the note field that's associated with the check
- // itself.
- Output string
-}
-
-// UpdateTTL is used to update the TTL of a check. This uses the newer API
-// that was introduced in Consul 0.6.4 and later. We translate the old status
-// strings for compatibility (though a newer version of Consul will still be
-// required to use this API).
-func (a *Agent) UpdateTTL(checkID, output, status string) error {
- switch status {
- case "pass", HealthPassing:
- status = HealthPassing
- case "warn", HealthWarning:
- status = HealthWarning
- case "fail", HealthCritical:
- status = HealthCritical
- default:
- return fmt.Errorf("Invalid status: %s", status)
- }
-
- endpoint := fmt.Sprintf("/v1/agent/check/update/%s", checkID)
- r := a.c.newRequest("PUT", endpoint)
- r.obj = &checkUpdate{
- Status: status,
- Output: output,
- }
-
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// CheckRegister is used to register a new check with
-// the local agent
-func (a *Agent) CheckRegister(check *AgentCheckRegistration) error {
- r := a.c.newRequest("PUT", "/v1/agent/check/register")
- r.obj = check
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// CheckDeregister is used to deregister a check with
-// the local agent
-func (a *Agent) CheckDeregister(checkID string) error {
- r := a.c.newRequest("PUT", "/v1/agent/check/deregister/"+checkID)
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// Join is used to instruct the agent to attempt a join to
-// another cluster member
-func (a *Agent) Join(addr string, wan bool) error {
- r := a.c.newRequest("PUT", "/v1/agent/join/"+addr)
- if wan {
- r.params.Set("wan", "1")
- }
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// Leave is used to have the agent gracefully leave the cluster and shutdown
-func (a *Agent) Leave() error {
- r := a.c.newRequest("PUT", "/v1/agent/leave")
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// ForceLeave is used to have the agent eject a failed node
-func (a *Agent) ForceLeave(node string) error {
- r := a.c.newRequest("PUT", "/v1/agent/force-leave/"+node)
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-//ForceLeavePrune is used to have an a failed agent removed
-//from the list of members
-func (a *Agent) ForceLeavePrune(node string) error {
- r := a.c.newRequest("PUT", "/v1/agent/force-leave/"+node)
- r.params.Set("prune", "1")
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// ConnectAuthorize is used to authorize an incoming connection
-// to a natively integrated Connect service.
-func (a *Agent) ConnectAuthorize(auth *AgentAuthorizeParams) (*AgentAuthorize, error) {
- r := a.c.newRequest("POST", "/v1/agent/connect/authorize")
- r.obj = auth
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out AgentAuthorize
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return &out, nil
-}
-
-// ConnectCARoots returns the list of roots.
-func (a *Agent) ConnectCARoots(q *QueryOptions) (*CARootList, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/agent/connect/ca/roots")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out CARootList
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return &out, qm, nil
-}
-
-// ConnectCALeaf gets the leaf certificate for the given service ID.
-func (a *Agent) ConnectCALeaf(serviceID string, q *QueryOptions) (*LeafCert, *QueryMeta, error) {
- r := a.c.newRequest("GET", "/v1/agent/connect/ca/leaf/"+serviceID)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out LeafCert
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return &out, qm, nil
-}
-
-// EnableServiceMaintenance toggles service maintenance mode on
-// for the given service ID.
-func (a *Agent) EnableServiceMaintenance(serviceID, reason string) error {
- r := a.c.newRequest("PUT", "/v1/agent/service/maintenance/"+serviceID)
- r.params.Set("enable", "true")
- r.params.Set("reason", reason)
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// DisableServiceMaintenance toggles service maintenance mode off
-// for the given service ID.
-func (a *Agent) DisableServiceMaintenance(serviceID string) error {
- r := a.c.newRequest("PUT", "/v1/agent/service/maintenance/"+serviceID)
- r.params.Set("enable", "false")
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// EnableNodeMaintenance toggles node maintenance mode on for the
-// agent we are connected to.
-func (a *Agent) EnableNodeMaintenance(reason string) error {
- r := a.c.newRequest("PUT", "/v1/agent/maintenance")
- r.params.Set("enable", "true")
- r.params.Set("reason", reason)
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// DisableNodeMaintenance toggles node maintenance mode off for the
-// agent we are connected to.
-func (a *Agent) DisableNodeMaintenance() error {
- r := a.c.newRequest("PUT", "/v1/agent/maintenance")
- r.params.Set("enable", "false")
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// Monitor returns a channel which will receive streaming logs from the agent
-// Providing a non-nil stopCh can be used to close the connection and stop the
-// log stream. An empty string will be sent down the given channel when there's
-// nothing left to stream, after which the caller should close the stopCh.
-func (a *Agent) Monitor(loglevel string, stopCh <-chan struct{}, q *QueryOptions) (chan string, error) {
- r := a.c.newRequest("GET", "/v1/agent/monitor")
- r.setQueryOptions(q)
- if loglevel != "" {
- r.params.Add("loglevel", loglevel)
- }
- _, resp, err := requireOK(a.c.doRequest(r))
- if err != nil {
- return nil, err
- }
-
- logCh := make(chan string, 64)
- go func() {
- defer resp.Body.Close()
-
- scanner := bufio.NewScanner(resp.Body)
- for {
- select {
- case <-stopCh:
- close(logCh)
- return
- default:
- }
- if scanner.Scan() {
- // An empty string signals to the caller that
- // the scan is done, so make sure we only emit
- // that when the scanner says it's done, not if
- // we happen to ingest an empty line.
- if text := scanner.Text(); text != "" {
- logCh <- text
- } else {
- logCh <- " "
- }
- } else {
- logCh <- ""
- }
- }
- }()
-
- return logCh, nil
-}
-
-// UpdateACLToken updates the agent's "acl_token". See updateToken for more
-// details.
-//
-// DEPRECATED (ACL-Legacy-Compat) - Prefer UpdateDefaultACLToken for v1.4.3 and above
-func (a *Agent) UpdateACLToken(token string, q *WriteOptions) (*WriteMeta, error) {
- return a.updateToken("acl_token", token, q)
-}
-
-// UpdateACLAgentToken updates the agent's "acl_agent_token". See updateToken
-// for more details.
-//
-// DEPRECATED (ACL-Legacy-Compat) - Prefer UpdateAgentACLToken for v1.4.3 and above
-func (a *Agent) UpdateACLAgentToken(token string, q *WriteOptions) (*WriteMeta, error) {
- return a.updateToken("acl_agent_token", token, q)
-}
-
-// UpdateACLAgentMasterToken updates the agent's "acl_agent_master_token". See
-// updateToken for more details.
-//
-// DEPRECATED (ACL-Legacy-Compat) - Prefer UpdateAgentMasterACLToken for v1.4.3 and above
-func (a *Agent) UpdateACLAgentMasterToken(token string, q *WriteOptions) (*WriteMeta, error) {
- return a.updateToken("acl_agent_master_token", token, q)
-}
-
-// UpdateACLReplicationToken updates the agent's "acl_replication_token". See
-// updateToken for more details.
-//
-// DEPRECATED (ACL-Legacy-Compat) - Prefer UpdateReplicationACLToken for v1.4.3 and above
-func (a *Agent) UpdateACLReplicationToken(token string, q *WriteOptions) (*WriteMeta, error) {
- return a.updateToken("acl_replication_token", token, q)
-}
-
-// UpdateDefaultACLToken updates the agent's "default" token. See updateToken
-// for more details
-func (a *Agent) UpdateDefaultACLToken(token string, q *WriteOptions) (*WriteMeta, error) {
- return a.updateTokenFallback("default", "acl_token", token, q)
-}
-
-// UpdateAgentACLToken updates the agent's "agent" token. See updateToken
-// for more details
-func (a *Agent) UpdateAgentACLToken(token string, q *WriteOptions) (*WriteMeta, error) {
- return a.updateTokenFallback("agent", "acl_agent_token", token, q)
-}
-
-// UpdateAgentMasterACLToken updates the agent's "agent_master" token. See updateToken
-// for more details
-func (a *Agent) UpdateAgentMasterACLToken(token string, q *WriteOptions) (*WriteMeta, error) {
- return a.updateTokenFallback("agent_master", "acl_agent_master_token", token, q)
-}
-
-// UpdateReplicationACLToken updates the agent's "replication" token. See updateToken
-// for more details
-func (a *Agent) UpdateReplicationACLToken(token string, q *WriteOptions) (*WriteMeta, error) {
- return a.updateTokenFallback("replication", "acl_replication_token", token, q)
-}
-
-// updateToken can be used to update one of an agent's ACL tokens after the agent has
-// started. The tokens are may not be persisted, so will need to be updated again if
-// the agent is restarted unless the agent is configured to persist them.
-func (a *Agent) updateToken(target, token string, q *WriteOptions) (*WriteMeta, error) {
- meta, _, err := a.updateTokenOnce(target, token, q)
- return meta, err
-}
-
-func (a *Agent) updateTokenFallback(target, fallback, token string, q *WriteOptions) (*WriteMeta, error) {
- meta, status, err := a.updateTokenOnce(target, token, q)
- if err != nil && status == 404 {
- meta, _, err = a.updateTokenOnce(fallback, token, q)
- }
- return meta, err
-}
-
-func (a *Agent) updateTokenOnce(target, token string, q *WriteOptions) (*WriteMeta, int, error) {
- r := a.c.newRequest("PUT", fmt.Sprintf("/v1/agent/token/%s", target))
- r.setWriteOptions(q)
- r.obj = &AgentToken{Token: token}
-
- rtt, resp, err := a.c.doRequest(r)
- if err != nil {
- return nil, 0, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
-
- if resp.StatusCode != 200 {
- var buf bytes.Buffer
- io.Copy(&buf, resp.Body)
- return wm, resp.StatusCode, fmt.Errorf("Unexpected response code: %d (%s)", resp.StatusCode, buf.Bytes())
- }
-
- return wm, resp.StatusCode, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/api.go b/vendor/github.com/hashicorp/consul/api/api.go
deleted file mode 100644
index 433d0f48261..00000000000
--- a/vendor/github.com/hashicorp/consul/api/api.go
+++ /dev/null
@@ -1,974 +0,0 @@
-package api
-
-import (
- "bytes"
- "context"
- "crypto/tls"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "net/url"
- "os"
- "strconv"
- "strings"
- "time"
-
- "github.com/hashicorp/go-cleanhttp"
- "github.com/hashicorp/go-rootcerts"
-)
-
-const (
- // HTTPAddrEnvName defines an environment variable name which sets
- // the HTTP address if there is no -http-addr specified.
- HTTPAddrEnvName = "CONSUL_HTTP_ADDR"
-
- // HTTPTokenEnvName defines an environment variable name which sets
- // the HTTP token.
- HTTPTokenEnvName = "CONSUL_HTTP_TOKEN"
-
- // HTTPTokenFileEnvName defines an environment variable name which sets
- // the HTTP token file.
- HTTPTokenFileEnvName = "CONSUL_HTTP_TOKEN_FILE"
-
- // HTTPAuthEnvName defines an environment variable name which sets
- // the HTTP authentication header.
- HTTPAuthEnvName = "CONSUL_HTTP_AUTH"
-
- // HTTPSSLEnvName defines an environment variable name which sets
- // whether or not to use HTTPS.
- HTTPSSLEnvName = "CONSUL_HTTP_SSL"
-
- // HTTPCAFile defines an environment variable name which sets the
- // CA file to use for talking to Consul over TLS.
- HTTPCAFile = "CONSUL_CACERT"
-
- // HTTPCAPath defines an environment variable name which sets the
- // path to a directory of CA certs to use for talking to Consul over TLS.
- HTTPCAPath = "CONSUL_CAPATH"
-
- // HTTPClientCert defines an environment variable name which sets the
- // client cert file to use for talking to Consul over TLS.
- HTTPClientCert = "CONSUL_CLIENT_CERT"
-
- // HTTPClientKey defines an environment variable name which sets the
- // client key file to use for talking to Consul over TLS.
- HTTPClientKey = "CONSUL_CLIENT_KEY"
-
- // HTTPTLSServerName defines an environment variable name which sets the
- // server name to use as the SNI host when connecting via TLS
- HTTPTLSServerName = "CONSUL_TLS_SERVER_NAME"
-
- // HTTPSSLVerifyEnvName defines an environment variable name which sets
- // whether or not to disable certificate checking.
- HTTPSSLVerifyEnvName = "CONSUL_HTTP_SSL_VERIFY"
-
- // GRPCAddrEnvName defines an environment variable name which sets the gRPC
- // address for consul connect envoy. Note this isn't actually used by the api
- // client in this package but is defined here for consistency with all the
- // other ENV names we use.
- GRPCAddrEnvName = "CONSUL_GRPC_ADDR"
-)
-
-// QueryOptions are used to parameterize a query
-type QueryOptions struct {
- // Providing a datacenter overwrites the DC provided
- // by the Config
- Datacenter string
-
- // AllowStale allows any Consul server (non-leader) to service
- // a read. This allows for lower latency and higher throughput
- AllowStale bool
-
- // RequireConsistent forces the read to be fully consistent.
- // This is more expensive but prevents ever performing a stale
- // read.
- RequireConsistent bool
-
- // UseCache requests that the agent cache results locally. See
- // https://www.consul.io/api/features/caching.html for more details on the
- // semantics.
- UseCache bool
-
- // MaxAge limits how old a cached value will be returned if UseCache is true.
- // If there is a cached response that is older than the MaxAge, it is treated
- // as a cache miss and a new fetch invoked. If the fetch fails, the error is
- // returned. Clients that wish to allow for stale results on error can set
- // StaleIfError to a longer duration to change this behavior. It is ignored
- // if the endpoint supports background refresh caching. See
- // https://www.consul.io/api/features/caching.html for more details.
- MaxAge time.Duration
-
- // StaleIfError specifies how stale the client will accept a cached response
- // if the servers are unavailable to fetch a fresh one. Only makes sense when
- // UseCache is true and MaxAge is set to a lower, non-zero value. It is
- // ignored if the endpoint supports background refresh caching. See
- // https://www.consul.io/api/features/caching.html for more details.
- StaleIfError time.Duration
-
- // WaitIndex is used to enable a blocking query. Waits
- // until the timeout or the next index is reached
- WaitIndex uint64
-
- // WaitHash is used by some endpoints instead of WaitIndex to perform blocking
- // on state based on a hash of the response rather than a monotonic index.
- // This is required when the state being blocked on is not stored in Raft, for
- // example agent-local proxy configuration.
- WaitHash string
-
- // WaitTime is used to bound the duration of a wait.
- // Defaults to that of the Config, but can be overridden.
- WaitTime time.Duration
-
- // Token is used to provide a per-request ACL token
- // which overrides the agent's default token.
- Token string
-
- // Near is used to provide a node name that will sort the results
- // in ascending order based on the estimated round trip time from
- // that node. Setting this to "_agent" will use the agent's node
- // for the sort.
- Near string
-
- // NodeMeta is used to filter results by nodes with the given
- // metadata key/value pairs. Currently, only one key/value pair can
- // be provided for filtering.
- NodeMeta map[string]string
-
- // RelayFactor is used in keyring operations to cause responses to be
- // relayed back to the sender through N other random nodes. Must be
- // a value from 0 to 5 (inclusive).
- RelayFactor uint8
-
- // LocalOnly is used in keyring list operation to force the keyring
- // query to only hit local servers (no WAN traffic).
- LocalOnly bool
-
- // Connect filters prepared query execution to only include Connect-capable
- // services. This currently affects prepared query execution.
- Connect bool
-
- // ctx is an optional context pass through to the underlying HTTP
- // request layer. Use Context() and WithContext() to manage this.
- ctx context.Context
-
- // Filter requests filtering data prior to it being returned. The string
- // is a go-bexpr compatible expression.
- Filter string
-}
-
-func (o *QueryOptions) Context() context.Context {
- if o != nil && o.ctx != nil {
- return o.ctx
- }
- return context.Background()
-}
-
-func (o *QueryOptions) WithContext(ctx context.Context) *QueryOptions {
- o2 := new(QueryOptions)
- if o != nil {
- *o2 = *o
- }
- o2.ctx = ctx
- return o2
-}
-
-// WriteOptions are used to parameterize a write
-type WriteOptions struct {
- // Providing a datacenter overwrites the DC provided
- // by the Config
- Datacenter string
-
- // Token is used to provide a per-request ACL token
- // which overrides the agent's default token.
- Token string
-
- // RelayFactor is used in keyring operations to cause responses to be
- // relayed back to the sender through N other random nodes. Must be
- // a value from 0 to 5 (inclusive).
- RelayFactor uint8
-
- // ctx is an optional context pass through to the underlying HTTP
- // request layer. Use Context() and WithContext() to manage this.
- ctx context.Context
-}
-
-func (o *WriteOptions) Context() context.Context {
- if o != nil && o.ctx != nil {
- return o.ctx
- }
- return context.Background()
-}
-
-func (o *WriteOptions) WithContext(ctx context.Context) *WriteOptions {
- o2 := new(WriteOptions)
- if o != nil {
- *o2 = *o
- }
- o2.ctx = ctx
- return o2
-}
-
-// QueryMeta is used to return meta data about a query
-type QueryMeta struct {
- // LastIndex. This can be used as a WaitIndex to perform
- // a blocking query
- LastIndex uint64
-
- // LastContentHash. This can be used as a WaitHash to perform a blocking query
- // for endpoints that support hash-based blocking. Endpoints that do not
- // support it will return an empty hash.
- LastContentHash string
-
- // Time of last contact from the leader for the
- // server servicing the request
- LastContact time.Duration
-
- // Is there a known leader
- KnownLeader bool
-
- // How long did the request take
- RequestTime time.Duration
-
- // Is address translation enabled for HTTP responses on this agent
- AddressTranslationEnabled bool
-
- // CacheHit is true if the result was served from agent-local cache.
- CacheHit bool
-
- // CacheAge is set if request was ?cached and indicates how stale the cached
- // response is.
- CacheAge time.Duration
-}
-
-// WriteMeta is used to return meta data about a write
-type WriteMeta struct {
- // How long did the request take
- RequestTime time.Duration
-}
-
-// HttpBasicAuth is used to authenticate http client with HTTP Basic Authentication
-type HttpBasicAuth struct {
- // Username to use for HTTP Basic Authentication
- Username string
-
- // Password to use for HTTP Basic Authentication
- Password string
-}
-
-// Config is used to configure the creation of a client
-type Config struct {
- // Address is the address of the Consul server
- Address string
-
- // Scheme is the URI scheme for the Consul server
- Scheme string
-
- // Datacenter to use. If not provided, the default agent datacenter is used.
- Datacenter string
-
- // Transport is the Transport to use for the http client.
- Transport *http.Transport
-
- // HttpClient is the client to use. Default will be
- // used if not provided.
- HttpClient *http.Client
-
- // HttpAuth is the auth info to use for http access.
- HttpAuth *HttpBasicAuth
-
- // WaitTime limits how long a Watch will block. If not provided,
- // the agent default values will be used.
- WaitTime time.Duration
-
- // Token is used to provide a per-request ACL token
- // which overrides the agent's default token.
- Token string
-
- // TokenFile is a file containing the current token to use for this client.
- // If provided it is read once at startup and never again.
- TokenFile string
-
- TLSConfig TLSConfig
-}
-
-// TLSConfig is used to generate a TLSClientConfig that's useful for talking to
-// Consul using TLS.
-type TLSConfig struct {
- // Address is the optional address of the Consul server. The port, if any
- // will be removed from here and this will be set to the ServerName of the
- // resulting config.
- Address string
-
- // CAFile is the optional path to the CA certificate used for Consul
- // communication, defaults to the system bundle if not specified.
- CAFile string
-
- // CAPath is the optional path to a directory of CA certificates to use for
- // Consul communication, defaults to the system bundle if not specified.
- CAPath string
-
- // CertFile is the optional path to the certificate for Consul
- // communication. If this is set then you need to also set KeyFile.
- CertFile string
-
- // KeyFile is the optional path to the private key for Consul communication.
- // If this is set then you need to also set CertFile.
- KeyFile string
-
- // InsecureSkipVerify if set to true will disable TLS host verification.
- InsecureSkipVerify bool
-}
-
-// DefaultConfig returns a default configuration for the client. By default this
-// will pool and reuse idle connections to Consul. If you have a long-lived
-// client object, this is the desired behavior and should make the most efficient
-// use of the connections to Consul. If you don't reuse a client object, which
-// is not recommended, then you may notice idle connections building up over
-// time. To avoid this, use the DefaultNonPooledConfig() instead.
-func DefaultConfig() *Config {
- return defaultConfig(cleanhttp.DefaultPooledTransport)
-}
-
-// DefaultNonPooledConfig returns a default configuration for the client which
-// does not pool connections. This isn't a recommended configuration because it
-// will reconnect to Consul on every request, but this is useful to avoid the
-// accumulation of idle connections if you make many client objects during the
-// lifetime of your application.
-func DefaultNonPooledConfig() *Config {
- return defaultConfig(cleanhttp.DefaultTransport)
-}
-
-// defaultConfig returns the default configuration for the client, using the
-// given function to make the transport.
-func defaultConfig(transportFn func() *http.Transport) *Config {
- config := &Config{
- Address: "127.0.0.1:8500",
- Scheme: "http",
- Transport: transportFn(),
- }
-
- if addr := os.Getenv(HTTPAddrEnvName); addr != "" {
- config.Address = addr
- }
-
- if tokenFile := os.Getenv(HTTPTokenFileEnvName); tokenFile != "" {
- config.TokenFile = tokenFile
- }
-
- if token := os.Getenv(HTTPTokenEnvName); token != "" {
- config.Token = token
- }
-
- if auth := os.Getenv(HTTPAuthEnvName); auth != "" {
- var username, password string
- if strings.Contains(auth, ":") {
- split := strings.SplitN(auth, ":", 2)
- username = split[0]
- password = split[1]
- } else {
- username = auth
- }
-
- config.HttpAuth = &HttpBasicAuth{
- Username: username,
- Password: password,
- }
- }
-
- if ssl := os.Getenv(HTTPSSLEnvName); ssl != "" {
- enabled, err := strconv.ParseBool(ssl)
- if err != nil {
- log.Printf("[WARN] client: could not parse %s: %s", HTTPSSLEnvName, err)
- }
-
- if enabled {
- config.Scheme = "https"
- }
- }
-
- if v := os.Getenv(HTTPTLSServerName); v != "" {
- config.TLSConfig.Address = v
- }
- if v := os.Getenv(HTTPCAFile); v != "" {
- config.TLSConfig.CAFile = v
- }
- if v := os.Getenv(HTTPCAPath); v != "" {
- config.TLSConfig.CAPath = v
- }
- if v := os.Getenv(HTTPClientCert); v != "" {
- config.TLSConfig.CertFile = v
- }
- if v := os.Getenv(HTTPClientKey); v != "" {
- config.TLSConfig.KeyFile = v
- }
- if v := os.Getenv(HTTPSSLVerifyEnvName); v != "" {
- doVerify, err := strconv.ParseBool(v)
- if err != nil {
- log.Printf("[WARN] client: could not parse %s: %s", HTTPSSLVerifyEnvName, err)
- }
- if !doVerify {
- config.TLSConfig.InsecureSkipVerify = true
- }
- }
-
- return config
-}
-
-// TLSConfig is used to generate a TLSClientConfig that's useful for talking to
-// Consul using TLS.
-func SetupTLSConfig(tlsConfig *TLSConfig) (*tls.Config, error) {
- tlsClientConfig := &tls.Config{
- InsecureSkipVerify: tlsConfig.InsecureSkipVerify,
- }
-
- if tlsConfig.Address != "" {
- server := tlsConfig.Address
- hasPort := strings.LastIndex(server, ":") > strings.LastIndex(server, "]")
- if hasPort {
- var err error
- server, _, err = net.SplitHostPort(server)
- if err != nil {
- return nil, err
- }
- }
- tlsClientConfig.ServerName = server
- }
-
- if tlsConfig.CertFile != "" && tlsConfig.KeyFile != "" {
- tlsCert, err := tls.LoadX509KeyPair(tlsConfig.CertFile, tlsConfig.KeyFile)
- if err != nil {
- return nil, err
- }
- tlsClientConfig.Certificates = []tls.Certificate{tlsCert}
- }
-
- if tlsConfig.CAFile != "" || tlsConfig.CAPath != "" {
- rootConfig := &rootcerts.Config{
- CAFile: tlsConfig.CAFile,
- CAPath: tlsConfig.CAPath,
- }
- if err := rootcerts.ConfigureTLS(tlsClientConfig, rootConfig); err != nil {
- return nil, err
- }
- }
-
- return tlsClientConfig, nil
-}
-
-func (c *Config) GenerateEnv() []string {
- env := make([]string, 0, 10)
-
- env = append(env,
- fmt.Sprintf("%s=%s", HTTPAddrEnvName, c.Address),
- fmt.Sprintf("%s=%s", HTTPTokenEnvName, c.Token),
- fmt.Sprintf("%s=%s", HTTPTokenFileEnvName, c.TokenFile),
- fmt.Sprintf("%s=%t", HTTPSSLEnvName, c.Scheme == "https"),
- fmt.Sprintf("%s=%s", HTTPCAFile, c.TLSConfig.CAFile),
- fmt.Sprintf("%s=%s", HTTPCAPath, c.TLSConfig.CAPath),
- fmt.Sprintf("%s=%s", HTTPClientCert, c.TLSConfig.CertFile),
- fmt.Sprintf("%s=%s", HTTPClientKey, c.TLSConfig.KeyFile),
- fmt.Sprintf("%s=%s", HTTPTLSServerName, c.TLSConfig.Address),
- fmt.Sprintf("%s=%t", HTTPSSLVerifyEnvName, !c.TLSConfig.InsecureSkipVerify))
-
- if c.HttpAuth != nil {
- env = append(env, fmt.Sprintf("%s=%s:%s", HTTPAuthEnvName, c.HttpAuth.Username, c.HttpAuth.Password))
- } else {
- env = append(env, fmt.Sprintf("%s=", HTTPAuthEnvName))
- }
-
- return env
-}
-
-// Client provides a client to the Consul API
-type Client struct {
- config Config
-}
-
-// NewClient returns a new client
-func NewClient(config *Config) (*Client, error) {
- // bootstrap the config
- defConfig := DefaultConfig()
-
- if len(config.Address) == 0 {
- config.Address = defConfig.Address
- }
-
- if len(config.Scheme) == 0 {
- config.Scheme = defConfig.Scheme
- }
-
- if config.Transport == nil {
- config.Transport = defConfig.Transport
- }
-
- if config.TLSConfig.Address == "" {
- config.TLSConfig.Address = defConfig.TLSConfig.Address
- }
-
- if config.TLSConfig.CAFile == "" {
- config.TLSConfig.CAFile = defConfig.TLSConfig.CAFile
- }
-
- if config.TLSConfig.CAPath == "" {
- config.TLSConfig.CAPath = defConfig.TLSConfig.CAPath
- }
-
- if config.TLSConfig.CertFile == "" {
- config.TLSConfig.CertFile = defConfig.TLSConfig.CertFile
- }
-
- if config.TLSConfig.KeyFile == "" {
- config.TLSConfig.KeyFile = defConfig.TLSConfig.KeyFile
- }
-
- if !config.TLSConfig.InsecureSkipVerify {
- config.TLSConfig.InsecureSkipVerify = defConfig.TLSConfig.InsecureSkipVerify
- }
-
- if config.HttpClient == nil {
- var err error
- config.HttpClient, err = NewHttpClient(config.Transport, config.TLSConfig)
- if err != nil {
- return nil, err
- }
- }
-
- parts := strings.SplitN(config.Address, "://", 2)
- if len(parts) == 2 {
- switch parts[0] {
- case "http":
- config.Scheme = "http"
- case "https":
- config.Scheme = "https"
- case "unix":
- trans := cleanhttp.DefaultTransport()
- trans.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) {
- return net.Dial("unix", parts[1])
- }
- config.HttpClient = &http.Client{
- Transport: trans,
- }
- default:
- return nil, fmt.Errorf("Unknown protocol scheme: %s", parts[0])
- }
- config.Address = parts[1]
- }
-
- // If the TokenFile is set, always use that, even if a Token is configured.
- // This is because when TokenFile is set it is read into the Token field.
- // We want any derived clients to have to re-read the token file.
- if config.TokenFile != "" {
- data, err := ioutil.ReadFile(config.TokenFile)
- if err != nil {
- return nil, fmt.Errorf("Error loading token file: %s", err)
- }
-
- if token := strings.TrimSpace(string(data)); token != "" {
- config.Token = token
- }
- }
- if config.Token == "" {
- config.Token = defConfig.Token
- }
-
- return &Client{config: *config}, nil
-}
-
-// NewHttpClient returns an http client configured with the given Transport and TLS
-// config.
-func NewHttpClient(transport *http.Transport, tlsConf TLSConfig) (*http.Client, error) {
- client := &http.Client{
- Transport: transport,
- }
-
- // TODO (slackpad) - Once we get some run time on the HTTP/2 support we
- // should turn it on by default if TLS is enabled. We would basically
- // just need to call http2.ConfigureTransport(transport) here. We also
- // don't want to introduce another external dependency on
- // golang.org/x/net/http2 at this time. For a complete recipe for how
- // to enable HTTP/2 support on a transport suitable for the API client
- // library see agent/http_test.go:TestHTTPServer_H2.
-
- if transport.TLSClientConfig == nil {
- tlsClientConfig, err := SetupTLSConfig(&tlsConf)
-
- if err != nil {
- return nil, err
- }
-
- transport.TLSClientConfig = tlsClientConfig
- }
-
- return client, nil
-}
-
-// request is used to help build up a request
-type request struct {
- config *Config
- method string
- url *url.URL
- params url.Values
- body io.Reader
- header http.Header
- obj interface{}
- ctx context.Context
-}
-
-// setQueryOptions is used to annotate the request with
-// additional query options
-func (r *request) setQueryOptions(q *QueryOptions) {
- if q == nil {
- return
- }
- if q.Datacenter != "" {
- r.params.Set("dc", q.Datacenter)
- }
- if q.AllowStale {
- r.params.Set("stale", "")
- }
- if q.RequireConsistent {
- r.params.Set("consistent", "")
- }
- if q.WaitIndex != 0 {
- r.params.Set("index", strconv.FormatUint(q.WaitIndex, 10))
- }
- if q.WaitTime != 0 {
- r.params.Set("wait", durToMsec(q.WaitTime))
- }
- if q.WaitHash != "" {
- r.params.Set("hash", q.WaitHash)
- }
- if q.Token != "" {
- r.header.Set("X-Consul-Token", q.Token)
- }
- if q.Near != "" {
- r.params.Set("near", q.Near)
- }
- if q.Filter != "" {
- r.params.Set("filter", q.Filter)
- }
- if len(q.NodeMeta) > 0 {
- for key, value := range q.NodeMeta {
- r.params.Add("node-meta", key+":"+value)
- }
- }
- if q.RelayFactor != 0 {
- r.params.Set("relay-factor", strconv.Itoa(int(q.RelayFactor)))
- }
- if q.LocalOnly {
- r.params.Set("local-only", fmt.Sprintf("%t", q.LocalOnly))
- }
- if q.Connect {
- r.params.Set("connect", "true")
- }
- if q.UseCache && !q.RequireConsistent {
- r.params.Set("cached", "")
-
- cc := []string{}
- if q.MaxAge > 0 {
- cc = append(cc, fmt.Sprintf("max-age=%.0f", q.MaxAge.Seconds()))
- }
- if q.StaleIfError > 0 {
- cc = append(cc, fmt.Sprintf("stale-if-error=%.0f", q.StaleIfError.Seconds()))
- }
- if len(cc) > 0 {
- r.header.Set("Cache-Control", strings.Join(cc, ", "))
- }
- }
-
- r.ctx = q.ctx
-}
-
-// durToMsec converts a duration to a millisecond specified string. If the
-// user selected a positive value that rounds to 0 ms, then we will use 1 ms
-// so they get a short delay, otherwise Consul will translate the 0 ms into
-// a huge default delay.
-func durToMsec(dur time.Duration) string {
- ms := dur / time.Millisecond
- if dur > 0 && ms == 0 {
- ms = 1
- }
- return fmt.Sprintf("%dms", ms)
-}
-
-// serverError is a string we look for to detect 500 errors.
-const serverError = "Unexpected response code: 500"
-
-// IsRetryableError returns true for 500 errors from the Consul servers, and
-// network connection errors. These are usually retryable at a later time.
-// This applies to reads but NOT to writes. This may return true for errors
-// on writes that may have still gone through, so do not use this to retry
-// any write operations.
-func IsRetryableError(err error) bool {
- if err == nil {
- return false
- }
-
- if _, ok := err.(net.Error); ok {
- return true
- }
-
- // TODO (slackpad) - Make a real error type here instead of using
- // a string check.
- return strings.Contains(err.Error(), serverError)
-}
-
-// setWriteOptions is used to annotate the request with
-// additional write options
-func (r *request) setWriteOptions(q *WriteOptions) {
- if q == nil {
- return
- }
- if q.Datacenter != "" {
- r.params.Set("dc", q.Datacenter)
- }
- if q.Token != "" {
- r.header.Set("X-Consul-Token", q.Token)
- }
- if q.RelayFactor != 0 {
- r.params.Set("relay-factor", strconv.Itoa(int(q.RelayFactor)))
- }
- r.ctx = q.ctx
-}
-
-// toHTTP converts the request to an HTTP request
-func (r *request) toHTTP() (*http.Request, error) {
- // Encode the query parameters
- r.url.RawQuery = r.params.Encode()
-
- // Check if we should encode the body
- if r.body == nil && r.obj != nil {
- b, err := encodeBody(r.obj)
- if err != nil {
- return nil, err
- }
- r.body = b
- }
-
- // Create the HTTP request
- req, err := http.NewRequest(r.method, r.url.RequestURI(), r.body)
- if err != nil {
- return nil, err
- }
-
- req.URL.Host = r.url.Host
- req.URL.Scheme = r.url.Scheme
- req.Host = r.url.Host
- req.Header = r.header
-
- // Setup auth
- if r.config.HttpAuth != nil {
- req.SetBasicAuth(r.config.HttpAuth.Username, r.config.HttpAuth.Password)
- }
- if r.ctx != nil {
- return req.WithContext(r.ctx), nil
- }
-
- return req, nil
-}
-
-// newRequest is used to create a new request
-func (c *Client) newRequest(method, path string) *request {
- r := &request{
- config: &c.config,
- method: method,
- url: &url.URL{
- Scheme: c.config.Scheme,
- Host: c.config.Address,
- Path: path,
- },
- params: make(map[string][]string),
- header: make(http.Header),
- }
- if c.config.Datacenter != "" {
- r.params.Set("dc", c.config.Datacenter)
- }
- if c.config.WaitTime != 0 {
- r.params.Set("wait", durToMsec(r.config.WaitTime))
- }
- if c.config.Token != "" {
- r.header.Set("X-Consul-Token", r.config.Token)
- }
- return r
-}
-
-// doRequest runs a request with our client
-func (c *Client) doRequest(r *request) (time.Duration, *http.Response, error) {
- req, err := r.toHTTP()
- if err != nil {
- return 0, nil, err
- }
- start := time.Now()
- resp, err := c.config.HttpClient.Do(req)
- diff := time.Since(start)
- return diff, resp, err
-}
-
-// Query is used to do a GET request against an endpoint
-// and deserialize the response into an interface using
-// standard Consul conventions.
-func (c *Client) query(endpoint string, out interface{}, q *QueryOptions) (*QueryMeta, error) {
- r := c.newRequest("GET", endpoint)
- r.setQueryOptions(q)
- rtt, resp, err := c.doRequest(r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- if err := decodeBody(resp, out); err != nil {
- return nil, err
- }
- return qm, nil
-}
-
-// write is used to do a PUT request against an endpoint
-// and serialize/deserialized using the standard Consul conventions.
-func (c *Client) write(endpoint string, in, out interface{}, q *WriteOptions) (*WriteMeta, error) {
- r := c.newRequest("PUT", endpoint)
- r.setWriteOptions(q)
- r.obj = in
- rtt, resp, err := requireOK(c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- if out != nil {
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- } else if _, err := ioutil.ReadAll(resp.Body); err != nil {
- return nil, err
- }
- return wm, nil
-}
-
-// parseQueryMeta is used to help parse query meta-data
-//
-// TODO(rb): bug? the error from this function is never handled
-func parseQueryMeta(resp *http.Response, q *QueryMeta) error {
- header := resp.Header
-
- // Parse the X-Consul-Index (if it's set - hash based blocking queries don't
- // set this)
- if indexStr := header.Get("X-Consul-Index"); indexStr != "" {
- index, err := strconv.ParseUint(indexStr, 10, 64)
- if err != nil {
- return fmt.Errorf("Failed to parse X-Consul-Index: %v", err)
- }
- q.LastIndex = index
- }
- q.LastContentHash = header.Get("X-Consul-ContentHash")
-
- // Parse the X-Consul-LastContact
- last, err := strconv.ParseUint(header.Get("X-Consul-LastContact"), 10, 64)
- if err != nil {
- return fmt.Errorf("Failed to parse X-Consul-LastContact: %v", err)
- }
- q.LastContact = time.Duration(last) * time.Millisecond
-
- // Parse the X-Consul-KnownLeader
- switch header.Get("X-Consul-KnownLeader") {
- case "true":
- q.KnownLeader = true
- default:
- q.KnownLeader = false
- }
-
- // Parse X-Consul-Translate-Addresses
- switch header.Get("X-Consul-Translate-Addresses") {
- case "true":
- q.AddressTranslationEnabled = true
- default:
- q.AddressTranslationEnabled = false
- }
-
- // Parse Cache info
- if cacheStr := header.Get("X-Cache"); cacheStr != "" {
- q.CacheHit = strings.EqualFold(cacheStr, "HIT")
- }
- if ageStr := header.Get("Age"); ageStr != "" {
- age, err := strconv.ParseUint(ageStr, 10, 64)
- if err != nil {
- return fmt.Errorf("Failed to parse Age Header: %v", err)
- }
- q.CacheAge = time.Duration(age) * time.Second
- }
-
- return nil
-}
-
-// decodeBody is used to JSON decode a body
-func decodeBody(resp *http.Response, out interface{}) error {
- dec := json.NewDecoder(resp.Body)
- return dec.Decode(out)
-}
-
-// encodeBody is used to encode a request body
-func encodeBody(obj interface{}) (io.Reader, error) {
- buf := bytes.NewBuffer(nil)
- enc := json.NewEncoder(buf)
- if err := enc.Encode(obj); err != nil {
- return nil, err
- }
- return buf, nil
-}
-
-// requireOK is used to wrap doRequest and check for a 200
-func requireOK(d time.Duration, resp *http.Response, e error) (time.Duration, *http.Response, error) {
- if e != nil {
- if resp != nil {
- resp.Body.Close()
- }
- return d, nil, e
- }
- if resp.StatusCode != 200 {
- return d, nil, generateUnexpectedResponseCodeError(resp)
- }
- return d, resp, nil
-}
-
-func (req *request) filterQuery(filter string) {
- if filter == "" {
- return
- }
-
- req.params.Set("filter", filter)
-}
-
-// generateUnexpectedResponseCodeError consumes the rest of the body, closes
-// the body stream and generates an error indicating the status code was
-// unexpected.
-func generateUnexpectedResponseCodeError(resp *http.Response) error {
- var buf bytes.Buffer
- io.Copy(&buf, resp.Body)
- resp.Body.Close()
- return fmt.Errorf("Unexpected response code: %d (%s)", resp.StatusCode, buf.Bytes())
-}
-
-func requireNotFoundOrOK(d time.Duration, resp *http.Response, e error) (bool, time.Duration, *http.Response, error) {
- if e != nil {
- if resp != nil {
- resp.Body.Close()
- }
- return false, d, nil, e
- }
- switch resp.StatusCode {
- case 200:
- return true, d, resp, nil
- case 404:
- return false, d, resp, nil
- default:
- return false, d, nil, generateUnexpectedResponseCodeError(resp)
- }
-}
diff --git a/vendor/github.com/hashicorp/consul/api/catalog.go b/vendor/github.com/hashicorp/consul/api/catalog.go
deleted file mode 100644
index 3fb055342c0..00000000000
--- a/vendor/github.com/hashicorp/consul/api/catalog.go
+++ /dev/null
@@ -1,262 +0,0 @@
-package api
-
-import (
- "net"
- "strconv"
-)
-
-type Weights struct {
- Passing int
- Warning int
-}
-
-type Node struct {
- ID string
- Node string
- Address string
- Datacenter string
- TaggedAddresses map[string]string
- Meta map[string]string
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-type ServiceAddress struct {
- Address string
- Port int
-}
-
-type CatalogService struct {
- ID string
- Node string
- Address string
- Datacenter string
- TaggedAddresses map[string]string
- NodeMeta map[string]string
- ServiceID string
- ServiceName string
- ServiceAddress string
- ServiceTaggedAddresses map[string]ServiceAddress
- ServiceTags []string
- ServiceMeta map[string]string
- ServicePort int
- ServiceWeights Weights
- ServiceEnableTagOverride bool
- ServiceProxy *AgentServiceConnectProxyConfig
- CreateIndex uint64
- Checks HealthChecks
- ModifyIndex uint64
-}
-
-type CatalogNode struct {
- Node *Node
- Services map[string]*AgentService
-}
-
-type CatalogRegistration struct {
- ID string
- Node string
- Address string
- TaggedAddresses map[string]string
- NodeMeta map[string]string
- Datacenter string
- Service *AgentService
- Check *AgentCheck
- Checks HealthChecks
- SkipNodeUpdate bool
-}
-
-type CatalogDeregistration struct {
- Node string
- Address string // Obsolete.
- Datacenter string
- ServiceID string
- CheckID string
-}
-
-// Catalog can be used to query the Catalog endpoints
-type Catalog struct {
- c *Client
-}
-
-// Catalog returns a handle to the catalog endpoints
-func (c *Client) Catalog() *Catalog {
- return &Catalog{c}
-}
-
-func (c *Catalog) Register(reg *CatalogRegistration, q *WriteOptions) (*WriteMeta, error) {
- r := c.c.newRequest("PUT", "/v1/catalog/register")
- r.setWriteOptions(q)
- r.obj = reg
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
-
- return wm, nil
-}
-
-func (c *Catalog) Deregister(dereg *CatalogDeregistration, q *WriteOptions) (*WriteMeta, error) {
- r := c.c.newRequest("PUT", "/v1/catalog/deregister")
- r.setWriteOptions(q)
- r.obj = dereg
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
-
- return wm, nil
-}
-
-// Datacenters is used to query for all the known datacenters
-func (c *Catalog) Datacenters() ([]string, error) {
- r := c.c.newRequest("GET", "/v1/catalog/datacenters")
- _, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out []string
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// Nodes is used to query all the known nodes
-func (c *Catalog) Nodes(q *QueryOptions) ([]*Node, *QueryMeta, error) {
- r := c.c.newRequest("GET", "/v1/catalog/nodes")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out []*Node
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// Services is used to query for all known services
-func (c *Catalog) Services(q *QueryOptions) (map[string][]string, *QueryMeta, error) {
- r := c.c.newRequest("GET", "/v1/catalog/services")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out map[string][]string
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// Service is used to query catalog entries for a given service
-func (c *Catalog) Service(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
- var tags []string
- if tag != "" {
- tags = []string{tag}
- }
- return c.service(service, tags, q, false)
-}
-
-// Supports multiple tags for filtering
-func (c *Catalog) ServiceMultipleTags(service string, tags []string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
- return c.service(service, tags, q, false)
-}
-
-// Connect is used to query catalog entries for a given Connect-enabled service
-func (c *Catalog) Connect(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
- var tags []string
- if tag != "" {
- tags = []string{tag}
- }
- return c.service(service, tags, q, true)
-}
-
-// Supports multiple tags for filtering
-func (c *Catalog) ConnectMultipleTags(service string, tags []string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
- return c.service(service, tags, q, true)
-}
-
-func (c *Catalog) service(service string, tags []string, q *QueryOptions, connect bool) ([]*CatalogService, *QueryMeta, error) {
- path := "/v1/catalog/service/" + service
- if connect {
- path = "/v1/catalog/connect/" + service
- }
- r := c.c.newRequest("GET", path)
- r.setQueryOptions(q)
- if len(tags) > 0 {
- for _, tag := range tags {
- r.params.Add("tag", tag)
- }
- }
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out []*CatalogService
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// Node is used to query for service information about a single node
-func (c *Catalog) Node(node string, q *QueryOptions) (*CatalogNode, *QueryMeta, error) {
- r := c.c.newRequest("GET", "/v1/catalog/node/"+node)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out *CatalogNode
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-func ParseServiceAddr(addrPort string) (ServiceAddress, error) {
- port := 0
- host, portStr, err := net.SplitHostPort(addrPort)
- if err == nil {
- port, err = strconv.Atoi(portStr)
- }
- return ServiceAddress{Address: host, Port: port}, err
-}
diff --git a/vendor/github.com/hashicorp/consul/api/config_entry.go b/vendor/github.com/hashicorp/consul/api/config_entry.go
deleted file mode 100644
index 5c05311be49..00000000000
--- a/vendor/github.com/hashicorp/consul/api/config_entry.go
+++ /dev/null
@@ -1,350 +0,0 @@
-package api
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "strconv"
- "strings"
-
- "github.com/mitchellh/mapstructure"
-)
-
-const (
- ServiceDefaults string = "service-defaults"
- ProxyDefaults string = "proxy-defaults"
- ServiceRouter string = "service-router"
- ServiceSplitter string = "service-splitter"
- ServiceResolver string = "service-resolver"
-
- ProxyConfigGlobal string = "global"
-)
-
-type ConfigEntry interface {
- GetKind() string
- GetName() string
- GetCreateIndex() uint64
- GetModifyIndex() uint64
-}
-
-type MeshGatewayMode string
-
-const (
- // MeshGatewayModeDefault represents no specific mode and should
- // be used to indicate that a different layer of the configuration
- // chain should take precedence
- MeshGatewayModeDefault MeshGatewayMode = ""
-
- // MeshGatewayModeNone represents that the Upstream Connect connections
- // should be direct and not flow through a mesh gateway.
- MeshGatewayModeNone MeshGatewayMode = "none"
-
- // MeshGatewayModeLocal represents that the Upstrea Connect connections
- // should be made to a mesh gateway in the local datacenter. This is
- MeshGatewayModeLocal MeshGatewayMode = "local"
-
- // MeshGatewayModeRemote represents that the Upstream Connect connections
- // should be made to a mesh gateway in a remote datacenter.
- MeshGatewayModeRemote MeshGatewayMode = "remote"
-)
-
-// MeshGatewayConfig controls how Mesh Gateways are used for upstream Connect
-// services
-type MeshGatewayConfig struct {
- // Mode is the mode that should be used for the upstream connection.
- Mode MeshGatewayMode `json:",omitempty"`
-}
-
-// ExposeConfig describes HTTP paths to expose through Envoy outside of Connect.
-// Users can expose individual paths and/or all HTTP/GRPC paths for checks.
-type ExposeConfig struct {
- // Checks defines whether paths associated with Consul checks will be exposed.
- // This flag triggers exposing all HTTP and GRPC check paths registered for the service.
- Checks bool `json:",omitempty"`
-
- // Paths is the list of paths exposed through the proxy.
- Paths []ExposePath `json:",omitempty"`
-}
-
-type ExposePath struct {
- // ListenerPort defines the port of the proxy's listener for exposed paths.
- ListenerPort int `json:",omitempty"`
-
- // Path is the path to expose through the proxy, ie. "/metrics."
- Path string `json:",omitempty"`
-
- // LocalPathPort is the port that the service is listening on for the given path.
- LocalPathPort int `json:",omitempty"`
-
- // Protocol describes the upstream's service protocol.
- // Valid values are "http" and "http2", defaults to "http"
- Protocol string `json:",omitempty"`
-
- // ParsedFromCheck is set if this path was parsed from a registered check
- ParsedFromCheck bool
-}
-
-type ServiceConfigEntry struct {
- Kind string
- Name string
- Protocol string `json:",omitempty"`
- MeshGateway MeshGatewayConfig `json:",omitempty"`
- Expose ExposeConfig `json:",omitempty"`
- ExternalSNI string `json:",omitempty"`
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-func (s *ServiceConfigEntry) GetKind() string {
- return s.Kind
-}
-
-func (s *ServiceConfigEntry) GetName() string {
- return s.Name
-}
-
-func (s *ServiceConfigEntry) GetCreateIndex() uint64 {
- return s.CreateIndex
-}
-
-func (s *ServiceConfigEntry) GetModifyIndex() uint64 {
- return s.ModifyIndex
-}
-
-type ProxyConfigEntry struct {
- Kind string
- Name string
- Config map[string]interface{} `json:",omitempty"`
- MeshGateway MeshGatewayConfig `json:",omitempty"`
- Expose ExposeConfig `json:",omitempty"`
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-func (p *ProxyConfigEntry) GetKind() string {
- return p.Kind
-}
-
-func (p *ProxyConfigEntry) GetName() string {
- return p.Name
-}
-
-func (p *ProxyConfigEntry) GetCreateIndex() uint64 {
- return p.CreateIndex
-}
-
-func (p *ProxyConfigEntry) GetModifyIndex() uint64 {
- return p.ModifyIndex
-}
-
-type rawEntryListResponse struct {
- kind string
- Entries []map[string]interface{}
-}
-
-func makeConfigEntry(kind, name string) (ConfigEntry, error) {
- switch kind {
- case ServiceDefaults:
- return &ServiceConfigEntry{Kind: kind, Name: name}, nil
- case ProxyDefaults:
- return &ProxyConfigEntry{Kind: kind, Name: name}, nil
- case ServiceRouter:
- return &ServiceRouterConfigEntry{Kind: kind, Name: name}, nil
- case ServiceSplitter:
- return &ServiceSplitterConfigEntry{Kind: kind, Name: name}, nil
- case ServiceResolver:
- return &ServiceResolverConfigEntry{Kind: kind, Name: name}, nil
- default:
- return nil, fmt.Errorf("invalid config entry kind: %s", kind)
- }
-}
-
-func MakeConfigEntry(kind, name string) (ConfigEntry, error) {
- return makeConfigEntry(kind, name)
-}
-
-// DecodeConfigEntry will decode the result of using json.Unmarshal of a config
-// entry into a map[string]interface{}.
-//
-// Important caveats:
-//
-// - This will NOT work if the map[string]interface{} was produced using HCL
-// decoding as that requires more extensive parsing to work around the issues
-// with map[string][]interface{} that arise.
-//
-// - This will only decode fields using their camel case json field
-// representations.
-func DecodeConfigEntry(raw map[string]interface{}) (ConfigEntry, error) {
- var entry ConfigEntry
-
- kindVal, ok := raw["Kind"]
- if !ok {
- kindVal, ok = raw["kind"]
- }
- if !ok {
- return nil, fmt.Errorf("Payload does not contain a kind/Kind key at the top level")
- }
-
- if kindStr, ok := kindVal.(string); ok {
- newEntry, err := makeConfigEntry(kindStr, "")
- if err != nil {
- return nil, err
- }
- entry = newEntry
- } else {
- return nil, fmt.Errorf("Kind value in payload is not a string")
- }
-
- decodeConf := &mapstructure.DecoderConfig{
- DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
- Result: &entry,
- WeaklyTypedInput: true,
- }
-
- decoder, err := mapstructure.NewDecoder(decodeConf)
- if err != nil {
- return nil, err
- }
-
- return entry, decoder.Decode(raw)
-}
-
-func DecodeConfigEntryFromJSON(data []byte) (ConfigEntry, error) {
- var raw map[string]interface{}
- if err := json.Unmarshal(data, &raw); err != nil {
- return nil, err
- }
-
- return DecodeConfigEntry(raw)
-}
-
-func decodeConfigEntrySlice(raw []map[string]interface{}) ([]ConfigEntry, error) {
- var entries []ConfigEntry
- for _, rawEntry := range raw {
- entry, err := DecodeConfigEntry(rawEntry)
- if err != nil {
- return nil, err
- }
- entries = append(entries, entry)
- }
- return entries, nil
-}
-
-// ConfigEntries can be used to query the Config endpoints
-type ConfigEntries struct {
- c *Client
-}
-
-// Config returns a handle to the Config endpoints
-func (c *Client) ConfigEntries() *ConfigEntries {
- return &ConfigEntries{c}
-}
-
-func (conf *ConfigEntries) Get(kind string, name string, q *QueryOptions) (ConfigEntry, *QueryMeta, error) {
- if kind == "" || name == "" {
- return nil, nil, fmt.Errorf("Both kind and name parameters must not be empty")
- }
-
- entry, err := makeConfigEntry(kind, name)
- if err != nil {
- return nil, nil, err
- }
-
- r := conf.c.newRequest("GET", fmt.Sprintf("/v1/config/%s/%s", kind, name))
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(conf.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
-
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- if err := decodeBody(resp, entry); err != nil {
- return nil, nil, err
- }
-
- return entry, qm, nil
-}
-
-func (conf *ConfigEntries) List(kind string, q *QueryOptions) ([]ConfigEntry, *QueryMeta, error) {
- if kind == "" {
- return nil, nil, fmt.Errorf("The kind parameter must not be empty")
- }
-
- r := conf.c.newRequest("GET", fmt.Sprintf("/v1/config/%s", kind))
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(conf.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
-
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var raw []map[string]interface{}
- if err := decodeBody(resp, &raw); err != nil {
- return nil, nil, err
- }
-
- entries, err := decodeConfigEntrySlice(raw)
- if err != nil {
- return nil, nil, err
- }
-
- return entries, qm, nil
-}
-
-func (conf *ConfigEntries) Set(entry ConfigEntry, w *WriteOptions) (bool, *WriteMeta, error) {
- return conf.set(entry, nil, w)
-}
-
-func (conf *ConfigEntries) CAS(entry ConfigEntry, index uint64, w *WriteOptions) (bool, *WriteMeta, error) {
- return conf.set(entry, map[string]string{"cas": strconv.FormatUint(index, 10)}, w)
-}
-
-func (conf *ConfigEntries) set(entry ConfigEntry, params map[string]string, w *WriteOptions) (bool, *WriteMeta, error) {
- r := conf.c.newRequest("PUT", "/v1/config")
- r.setWriteOptions(w)
- for param, value := range params {
- r.params.Set(param, value)
- }
- r.obj = entry
- rtt, resp, err := requireOK(conf.c.doRequest(r))
- if err != nil {
- return false, nil, err
- }
- defer resp.Body.Close()
-
- var buf bytes.Buffer
- if _, err := io.Copy(&buf, resp.Body); err != nil {
- return false, nil, fmt.Errorf("Failed to read response: %v", err)
- }
- res := strings.Contains(buf.String(), "true")
-
- wm := &WriteMeta{RequestTime: rtt}
- return res, wm, nil
-}
-
-func (conf *ConfigEntries) Delete(kind string, name string, w *WriteOptions) (*WriteMeta, error) {
- if kind == "" || name == "" {
- return nil, fmt.Errorf("Both kind and name parameters must not be empty")
- }
-
- r := conf.c.newRequest("DELETE", fmt.Sprintf("/v1/config/%s/%s", kind, name))
- r.setWriteOptions(w)
- rtt, resp, err := requireOK(conf.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- resp.Body.Close()
- wm := &WriteMeta{RequestTime: rtt}
- return wm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/config_entry_discoverychain.go b/vendor/github.com/hashicorp/consul/api/config_entry_discoverychain.go
deleted file mode 100644
index 77acfbddf1e..00000000000
--- a/vendor/github.com/hashicorp/consul/api/config_entry_discoverychain.go
+++ /dev/null
@@ -1,200 +0,0 @@
-package api
-
-import (
- "encoding/json"
- "time"
-)
-
-type ServiceRouterConfigEntry struct {
- Kind string
- Name string
-
- Routes []ServiceRoute `json:",omitempty"`
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-func (e *ServiceRouterConfigEntry) GetKind() string { return e.Kind }
-func (e *ServiceRouterConfigEntry) GetName() string { return e.Name }
-func (e *ServiceRouterConfigEntry) GetCreateIndex() uint64 { return e.CreateIndex }
-func (e *ServiceRouterConfigEntry) GetModifyIndex() uint64 { return e.ModifyIndex }
-
-type ServiceRoute struct {
- Match *ServiceRouteMatch `json:",omitempty"`
- Destination *ServiceRouteDestination `json:",omitempty"`
-}
-
-type ServiceRouteMatch struct {
- HTTP *ServiceRouteHTTPMatch `json:",omitempty"`
-}
-
-type ServiceRouteHTTPMatch struct {
- PathExact string `json:",omitempty"`
- PathPrefix string `json:",omitempty"`
- PathRegex string `json:",omitempty"`
-
- Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
- QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty"`
- Methods []string `json:",omitempty"`
-}
-
-type ServiceRouteHTTPMatchHeader struct {
- Name string
- Present bool `json:",omitempty"`
- Exact string `json:",omitempty"`
- Prefix string `json:",omitempty"`
- Suffix string `json:",omitempty"`
- Regex string `json:",omitempty"`
- Invert bool `json:",omitempty"`
-}
-
-type ServiceRouteHTTPMatchQueryParam struct {
- Name string
- Present bool `json:",omitempty"`
- Exact string `json:",omitempty"`
- Regex string `json:",omitempty"`
-}
-
-type ServiceRouteDestination struct {
- Service string `json:",omitempty"`
- ServiceSubset string `json:",omitempty"`
- Namespace string `json:",omitempty"`
- PrefixRewrite string `json:",omitempty"`
- RequestTimeout time.Duration `json:",omitempty"`
- NumRetries uint32 `json:",omitempty"`
- RetryOnConnectFailure bool `json:",omitempty"`
- RetryOnStatusCodes []uint32 `json:",omitempty"`
-}
-
-func (e *ServiceRouteDestination) MarshalJSON() ([]byte, error) {
- type Alias ServiceRouteDestination
- exported := &struct {
- RequestTimeout string `json:",omitempty"`
- *Alias
- }{
- RequestTimeout: e.RequestTimeout.String(),
- Alias: (*Alias)(e),
- }
- if e.RequestTimeout == 0 {
- exported.RequestTimeout = ""
- }
-
- return json.Marshal(exported)
-}
-
-func (e *ServiceRouteDestination) UnmarshalJSON(data []byte) error {
- type Alias ServiceRouteDestination
- aux := &struct {
- RequestTimeout string
- *Alias
- }{
- Alias: (*Alias)(e),
- }
- if err := json.Unmarshal(data, &aux); err != nil {
- return err
- }
- var err error
- if aux.RequestTimeout != "" {
- if e.RequestTimeout, err = time.ParseDuration(aux.RequestTimeout); err != nil {
- return err
- }
- }
- return nil
-}
-
-type ServiceSplitterConfigEntry struct {
- Kind string
- Name string
-
- Splits []ServiceSplit `json:",omitempty"`
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-func (e *ServiceSplitterConfigEntry) GetKind() string { return e.Kind }
-func (e *ServiceSplitterConfigEntry) GetName() string { return e.Name }
-func (e *ServiceSplitterConfigEntry) GetCreateIndex() uint64 { return e.CreateIndex }
-func (e *ServiceSplitterConfigEntry) GetModifyIndex() uint64 { return e.ModifyIndex }
-
-type ServiceSplit struct {
- Weight float32
- Service string `json:",omitempty"`
- ServiceSubset string `json:",omitempty"`
- Namespace string `json:",omitempty"`
-}
-
-type ServiceResolverConfigEntry struct {
- Kind string
- Name string
-
- DefaultSubset string `json:",omitempty"`
- Subsets map[string]ServiceResolverSubset `json:",omitempty"`
- Redirect *ServiceResolverRedirect `json:",omitempty"`
- Failover map[string]ServiceResolverFailover `json:",omitempty"`
- ConnectTimeout time.Duration `json:",omitempty"`
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-func (e *ServiceResolverConfigEntry) MarshalJSON() ([]byte, error) {
- type Alias ServiceResolverConfigEntry
- exported := &struct {
- ConnectTimeout string `json:",omitempty"`
- *Alias
- }{
- ConnectTimeout: e.ConnectTimeout.String(),
- Alias: (*Alias)(e),
- }
- if e.ConnectTimeout == 0 {
- exported.ConnectTimeout = ""
- }
-
- return json.Marshal(exported)
-}
-
-func (e *ServiceResolverConfigEntry) UnmarshalJSON(data []byte) error {
- type Alias ServiceResolverConfigEntry
- aux := &struct {
- ConnectTimeout string
- *Alias
- }{
- Alias: (*Alias)(e),
- }
- if err := json.Unmarshal(data, &aux); err != nil {
- return err
- }
- var err error
- if aux.ConnectTimeout != "" {
- if e.ConnectTimeout, err = time.ParseDuration(aux.ConnectTimeout); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (e *ServiceResolverConfigEntry) GetKind() string { return e.Kind }
-func (e *ServiceResolverConfigEntry) GetName() string { return e.Name }
-func (e *ServiceResolverConfigEntry) GetCreateIndex() uint64 { return e.CreateIndex }
-func (e *ServiceResolverConfigEntry) GetModifyIndex() uint64 { return e.ModifyIndex }
-
-type ServiceResolverSubset struct {
- Filter string `json:",omitempty"`
- OnlyPassing bool `json:",omitempty"`
-}
-
-type ServiceResolverRedirect struct {
- Service string `json:",omitempty"`
- ServiceSubset string `json:",omitempty"`
- Namespace string `json:",omitempty"`
- Datacenter string `json:",omitempty"`
-}
-
-type ServiceResolverFailover struct {
- Service string `json:",omitempty"`
- ServiceSubset string `json:",omitempty"`
- Namespace string `json:",omitempty"`
- Datacenters []string `json:",omitempty"`
-}
diff --git a/vendor/github.com/hashicorp/consul/api/connect.go b/vendor/github.com/hashicorp/consul/api/connect.go
deleted file mode 100644
index a40d1e2321a..00000000000
--- a/vendor/github.com/hashicorp/consul/api/connect.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package api
-
-// Connect can be used to work with endpoints related to Connect, the
-// feature for securely connecting services within Consul.
-type Connect struct {
- c *Client
-}
-
-// Connect returns a handle to the connect-related endpoints
-func (c *Client) Connect() *Connect {
- return &Connect{c}
-}
diff --git a/vendor/github.com/hashicorp/consul/api/connect_ca.go b/vendor/github.com/hashicorp/consul/api/connect_ca.go
deleted file mode 100644
index 600a3e0dbf6..00000000000
--- a/vendor/github.com/hashicorp/consul/api/connect_ca.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package api
-
-import (
- "fmt"
- "time"
-
- "github.com/mitchellh/mapstructure"
-)
-
-// CAConfig is the structure for the Connect CA configuration.
-type CAConfig struct {
- // Provider is the CA provider implementation to use.
- Provider string
-
- // Configuration is arbitrary configuration for the provider. This
- // should only contain primitive values and containers (such as lists
- // and maps).
- Config map[string]interface{}
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-// CommonCAProviderConfig is the common options available to all CA providers.
-type CommonCAProviderConfig struct {
- LeafCertTTL time.Duration
- SkipValidate bool
- CSRMaxPerSecond float32
- CSRMaxConcurrent int
-}
-
-// ConsulCAProviderConfig is the config for the built-in Consul CA provider.
-type ConsulCAProviderConfig struct {
- CommonCAProviderConfig `mapstructure:",squash"`
-
- PrivateKey string
- RootCert string
- RotationPeriod time.Duration
-}
-
-// ParseConsulCAConfig takes a raw config map and returns a parsed
-// ConsulCAProviderConfig.
-func ParseConsulCAConfig(raw map[string]interface{}) (*ConsulCAProviderConfig, error) {
- var config ConsulCAProviderConfig
- decodeConf := &mapstructure.DecoderConfig{
- DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
- Result: &config,
- WeaklyTypedInput: true,
- }
-
- decoder, err := mapstructure.NewDecoder(decodeConf)
- if err != nil {
- return nil, err
- }
-
- if err := decoder.Decode(raw); err != nil {
- return nil, fmt.Errorf("error decoding config: %s", err)
- }
-
- return &config, nil
-}
-
-// CARootList is the structure for the results of listing roots.
-type CARootList struct {
- ActiveRootID string
- TrustDomain string
- Roots []*CARoot
-}
-
-// CARoot represents a root CA certificate that is trusted.
-type CARoot struct {
- // ID is a globally unique ID (UUID) representing this CA root.
- ID string
-
- // Name is a human-friendly name for this CA root. This value is
- // opaque to Consul and is not used for anything internally.
- Name string
-
- // RootCertPEM is the PEM-encoded public certificate.
- RootCertPEM string `json:"RootCert"`
-
- // Active is true if this is the current active CA. This must only
- // be true for exactly one CA. For any method that modifies roots in the
- // state store, tests should be written to verify that multiple roots
- // cannot be active.
- Active bool
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-// LeafCert is a certificate that has been issued by a Connect CA.
-type LeafCert struct {
- // SerialNumber is the unique serial number for this certificate.
- // This is encoded in standard hex separated by :.
- SerialNumber string
-
- // CertPEM and PrivateKeyPEM are the PEM-encoded certificate and private
- // key for that cert, respectively. This should not be stored in the
- // state store, but is present in the sign API response.
- CertPEM string `json:",omitempty"`
- PrivateKeyPEM string `json:",omitempty"`
-
- // Service is the name of the service for which the cert was issued.
- // ServiceURI is the cert URI value.
- Service string
- ServiceURI string
-
- // ValidAfter and ValidBefore are the validity periods for the
- // certificate.
- ValidAfter time.Time
- ValidBefore time.Time
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-// CARoots queries the list of available roots.
-func (h *Connect) CARoots(q *QueryOptions) (*CARootList, *QueryMeta, error) {
- r := h.c.newRequest("GET", "/v1/connect/ca/roots")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out CARootList
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return &out, qm, nil
-}
-
-// CAGetConfig returns the current CA configuration.
-func (h *Connect) CAGetConfig(q *QueryOptions) (*CAConfig, *QueryMeta, error) {
- r := h.c.newRequest("GET", "/v1/connect/ca/configuration")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out CAConfig
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return &out, qm, nil
-}
-
-// CASetConfig sets the current CA configuration.
-func (h *Connect) CASetConfig(conf *CAConfig, q *WriteOptions) (*WriteMeta, error) {
- r := h.c.newRequest("PUT", "/v1/connect/ca/configuration")
- r.setWriteOptions(q)
- r.obj = conf
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
- return wm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/connect_intention.go b/vendor/github.com/hashicorp/consul/api/connect_intention.go
deleted file mode 100644
index d25cb844fb8..00000000000
--- a/vendor/github.com/hashicorp/consul/api/connect_intention.go
+++ /dev/null
@@ -1,309 +0,0 @@
-package api
-
-import (
- "bytes"
- "fmt"
- "io"
- "time"
-)
-
-// Intention defines an intention for the Connect Service Graph. This defines
-// the allowed or denied behavior of a connection between two services using
-// Connect.
-type Intention struct {
- // ID is the UUID-based ID for the intention, always generated by Consul.
- ID string
-
- // Description is a human-friendly description of this intention.
- // It is opaque to Consul and is only stored and transferred in API
- // requests.
- Description string
-
- // SourceNS, SourceName are the namespace and name, respectively, of
- // the source service. Either of these may be the wildcard "*", but only
- // the full value can be a wildcard. Partial wildcards are not allowed.
- // The source may also be a non-Consul service, as specified by SourceType.
- //
- // DestinationNS, DestinationName is the same, but for the destination
- // service. The same rules apply. The destination is always a Consul
- // service.
- SourceNS, SourceName string
- DestinationNS, DestinationName string
-
- // SourceType is the type of the value for the source.
- SourceType IntentionSourceType
-
- // Action is whether this is a whitelist or blacklist intention.
- Action IntentionAction
-
- // DefaultAddr, DefaultPort of the local listening proxy (if any) to
- // make this connection.
- DefaultAddr string
- DefaultPort int
-
- // Meta is arbitrary metadata associated with the intention. This is
- // opaque to Consul but is served in API responses.
- Meta map[string]string
-
- // Precedence is the order that the intention will be applied, with
- // larger numbers being applied first. This is a read-only field, on
- // any intention update it is updated.
- Precedence int
-
- // CreatedAt and UpdatedAt keep track of when this record was created
- // or modified.
- CreatedAt, UpdatedAt time.Time
-
- // Hash of the contents of the intention
- //
- // This is needed mainly for replication purposes. When replicating from
- // one DC to another keeping the content Hash will allow us to detect
- // content changes more efficiently than checking every single field
- Hash []byte
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-// String returns human-friendly output describing ths intention.
-func (i *Intention) String() string {
- return fmt.Sprintf("%s => %s (%s)",
- i.SourceString(),
- i.DestinationString(),
- i.Action)
-}
-
-// SourceString returns the namespace/name format for the source, or
-// just "name" if the namespace is the default namespace.
-func (i *Intention) SourceString() string {
- return i.partString(i.SourceNS, i.SourceName)
-}
-
-// DestinationString returns the namespace/name format for the source, or
-// just "name" if the namespace is the default namespace.
-func (i *Intention) DestinationString() string {
- return i.partString(i.DestinationNS, i.DestinationName)
-}
-
-func (i *Intention) partString(ns, n string) string {
- // For now we omit the default namespace from the output. In the future
- // we might want to look at this and show this in a multi-namespace world.
- if ns != "" && ns != IntentionDefaultNamespace {
- n = ns + "/" + n
- }
-
- return n
-}
-
-// IntentionDefaultNamespace is the default namespace value.
-const IntentionDefaultNamespace = "default"
-
-// IntentionAction is the action that the intention represents. This
-// can be "allow" or "deny" to whitelist or blacklist intentions.
-type IntentionAction string
-
-const (
- IntentionActionAllow IntentionAction = "allow"
- IntentionActionDeny IntentionAction = "deny"
-)
-
-// IntentionSourceType is the type of the source within an intention.
-type IntentionSourceType string
-
-const (
- // IntentionSourceConsul is a service within the Consul catalog.
- IntentionSourceConsul IntentionSourceType = "consul"
-)
-
-// IntentionMatch are the arguments for the intention match API.
-type IntentionMatch struct {
- By IntentionMatchType
- Names []string
-}
-
-// IntentionMatchType is the target for a match request. For example,
-// matching by source will look for all intentions that match the given
-// source value.
-type IntentionMatchType string
-
-const (
- IntentionMatchSource IntentionMatchType = "source"
- IntentionMatchDestination IntentionMatchType = "destination"
-)
-
-// IntentionCheck are the arguments for the intention check API. For
-// more documentation see the IntentionCheck function.
-type IntentionCheck struct {
- // Source and Destination are the source and destination values to
- // check. The destination is always a Consul service, but the source
- // may be other values as defined by the SourceType.
- Source, Destination string
-
- // SourceType is the type of the value for the source.
- SourceType IntentionSourceType
-}
-
-// Intentions returns the list of intentions.
-func (h *Connect) Intentions(q *QueryOptions) ([]*Intention, *QueryMeta, error) {
- r := h.c.newRequest("GET", "/v1/connect/intentions")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out []*Intention
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// IntentionGet retrieves a single intention.
-func (h *Connect) IntentionGet(id string, q *QueryOptions) (*Intention, *QueryMeta, error) {
- r := h.c.newRequest("GET", "/v1/connect/intentions/"+id)
- r.setQueryOptions(q)
- rtt, resp, err := h.c.doRequest(r)
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- if resp.StatusCode == 404 {
- return nil, qm, nil
- } else if resp.StatusCode != 200 {
- var buf bytes.Buffer
- io.Copy(&buf, resp.Body)
- return nil, nil, fmt.Errorf(
- "Unexpected response %d: %s", resp.StatusCode, buf.String())
- }
-
- var out Intention
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return &out, qm, nil
-}
-
-// IntentionDelete deletes a single intention.
-func (h *Connect) IntentionDelete(id string, q *WriteOptions) (*WriteMeta, error) {
- r := h.c.newRequest("DELETE", "/v1/connect/intentions/"+id)
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- qm := &WriteMeta{}
- qm.RequestTime = rtt
-
- return qm, nil
-}
-
-// IntentionMatch returns the list of intentions that match a given source
-// or destination. The returned intentions are ordered by precedence where
-// result[0] is the highest precedence (if that matches, then that rule overrides
-// all other rules).
-//
-// Matching can be done for multiple names at the same time. The resulting
-// map is keyed by the given names. Casing is preserved.
-func (h *Connect) IntentionMatch(args *IntentionMatch, q *QueryOptions) (map[string][]*Intention, *QueryMeta, error) {
- r := h.c.newRequest("GET", "/v1/connect/intentions/match")
- r.setQueryOptions(q)
- r.params.Set("by", string(args.By))
- for _, name := range args.Names {
- r.params.Add("name", name)
- }
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out map[string][]*Intention
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// IntentionCheck returns whether a given source/destination would be allowed
-// or not given the current set of intentions and the configuration of Consul.
-func (h *Connect) IntentionCheck(args *IntentionCheck, q *QueryOptions) (bool, *QueryMeta, error) {
- r := h.c.newRequest("GET", "/v1/connect/intentions/check")
- r.setQueryOptions(q)
- r.params.Set("source", args.Source)
- r.params.Set("destination", args.Destination)
- if args.SourceType != "" {
- r.params.Set("source-type", string(args.SourceType))
- }
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return false, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out struct{ Allowed bool }
- if err := decodeBody(resp, &out); err != nil {
- return false, nil, err
- }
- return out.Allowed, qm, nil
-}
-
-// IntentionCreate will create a new intention. The ID in the given
-// structure must be empty and a generate ID will be returned on
-// success.
-func (c *Connect) IntentionCreate(ixn *Intention, q *WriteOptions) (string, *WriteMeta, error) {
- r := c.c.newRequest("POST", "/v1/connect/intentions")
- r.setWriteOptions(q)
- r.obj = ixn
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return "", nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
-
- var out struct{ ID string }
- if err := decodeBody(resp, &out); err != nil {
- return "", nil, err
- }
- return out.ID, wm, nil
-}
-
-// IntentionUpdate will update an existing intention. The ID in the given
-// structure must be non-empty.
-func (c *Connect) IntentionUpdate(ixn *Intention, q *WriteOptions) (*WriteMeta, error) {
- r := c.c.newRequest("PUT", "/v1/connect/intentions/"+ixn.ID)
- r.setWriteOptions(q)
- r.obj = ixn
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
- return wm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/coordinate.go b/vendor/github.com/hashicorp/consul/api/coordinate.go
deleted file mode 100644
index 776630f67d7..00000000000
--- a/vendor/github.com/hashicorp/consul/api/coordinate.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package api
-
-import (
- "github.com/hashicorp/serf/coordinate"
-)
-
-// CoordinateEntry represents a node and its associated network coordinate.
-type CoordinateEntry struct {
- Node string
- Segment string
- Coord *coordinate.Coordinate
-}
-
-// CoordinateDatacenterMap has the coordinates for servers in a given datacenter
-// and area. Network coordinates are only compatible within the same area.
-type CoordinateDatacenterMap struct {
- Datacenter string
- AreaID string
- Coordinates []CoordinateEntry
-}
-
-// Coordinate can be used to query the coordinate endpoints
-type Coordinate struct {
- c *Client
-}
-
-// Coordinate returns a handle to the coordinate endpoints
-func (c *Client) Coordinate() *Coordinate {
- return &Coordinate{c}
-}
-
-// Datacenters is used to return the coordinates of all the servers in the WAN
-// pool.
-func (c *Coordinate) Datacenters() ([]*CoordinateDatacenterMap, error) {
- r := c.c.newRequest("GET", "/v1/coordinate/datacenters")
- _, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out []*CoordinateDatacenterMap
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// Nodes is used to return the coordinates of all the nodes in the LAN pool.
-func (c *Coordinate) Nodes(q *QueryOptions) ([]*CoordinateEntry, *QueryMeta, error) {
- r := c.c.newRequest("GET", "/v1/coordinate/nodes")
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out []*CoordinateEntry
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// Update inserts or updates the LAN coordinate of a node.
-func (c *Coordinate) Update(coord *CoordinateEntry, q *WriteOptions) (*WriteMeta, error) {
- r := c.c.newRequest("PUT", "/v1/coordinate/update")
- r.setWriteOptions(q)
- r.obj = coord
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
-
- return wm, nil
-}
-
-// Node is used to return the coordinates of a single node in the LAN pool.
-func (c *Coordinate) Node(node string, q *QueryOptions) ([]*CoordinateEntry, *QueryMeta, error) {
- r := c.c.newRequest("GET", "/v1/coordinate/node/"+node)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out []*CoordinateEntry
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/debug.go b/vendor/github.com/hashicorp/consul/api/debug.go
deleted file mode 100644
index 238046853a0..00000000000
--- a/vendor/github.com/hashicorp/consul/api/debug.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package api
-
-import (
- "fmt"
- "io/ioutil"
- "strconv"
-)
-
-// Debug can be used to query the /debug/pprof endpoints to gather
-// profiling information about the target agent.Debug
-//
-// The agent must have enable_debug set to true for profiling to be enabled
-// and for these endpoints to function.
-type Debug struct {
- c *Client
-}
-
-// Debug returns a handle that exposes the internal debug endpoints.
-func (c *Client) Debug() *Debug {
- return &Debug{c}
-}
-
-// Heap returns a pprof heap dump
-func (d *Debug) Heap() ([]byte, error) {
- r := d.c.newRequest("GET", "/debug/pprof/heap")
- _, resp, err := d.c.doRequest(r)
- if err != nil {
- return nil, fmt.Errorf("error making request: %s", err)
- }
- defer resp.Body.Close()
-
- // We return a raw response because we're just passing through a response
- // from the pprof handlers
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, fmt.Errorf("error decoding body: %s", err)
- }
-
- return body, nil
-}
-
-// Profile returns a pprof CPU profile for the specified number of seconds
-func (d *Debug) Profile(seconds int) ([]byte, error) {
- r := d.c.newRequest("GET", "/debug/pprof/profile")
-
- // Capture a profile for the specified number of seconds
- r.params.Set("seconds", strconv.Itoa(seconds))
-
- _, resp, err := d.c.doRequest(r)
- if err != nil {
- return nil, fmt.Errorf("error making request: %s", err)
- }
- defer resp.Body.Close()
-
- // We return a raw response because we're just passing through a response
- // from the pprof handlers
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, fmt.Errorf("error decoding body: %s", err)
- }
-
- return body, nil
-}
-
-// Trace returns an execution trace
-func (d *Debug) Trace(seconds int) ([]byte, error) {
- r := d.c.newRequest("GET", "/debug/pprof/trace")
-
- // Capture a trace for the specified number of seconds
- r.params.Set("seconds", strconv.Itoa(seconds))
-
- _, resp, err := d.c.doRequest(r)
- if err != nil {
- return nil, fmt.Errorf("error making request: %s", err)
- }
- defer resp.Body.Close()
-
- // We return a raw response because we're just passing through a response
- // from the pprof handlers
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, fmt.Errorf("error decoding body: %s", err)
- }
-
- return body, nil
-}
-
-// Goroutine returns a pprof goroutine profile
-func (d *Debug) Goroutine() ([]byte, error) {
- r := d.c.newRequest("GET", "/debug/pprof/goroutine")
-
- _, resp, err := d.c.doRequest(r)
- if err != nil {
- return nil, fmt.Errorf("error making request: %s", err)
- }
- defer resp.Body.Close()
-
- // We return a raw response because we're just passing through a response
- // from the pprof handlers
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, fmt.Errorf("error decoding body: %s", err)
- }
-
- return body, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/discovery_chain.go b/vendor/github.com/hashicorp/consul/api/discovery_chain.go
deleted file mode 100644
index 407a3b08e37..00000000000
--- a/vendor/github.com/hashicorp/consul/api/discovery_chain.go
+++ /dev/null
@@ -1,230 +0,0 @@
-package api
-
-import (
- "encoding/json"
- "fmt"
- "time"
-)
-
-// DiscoveryChain can be used to query the discovery-chain endpoints
-type DiscoveryChain struct {
- c *Client
-}
-
-// DiscoveryChain returns a handle to the discovery-chain endpoints
-func (c *Client) DiscoveryChain() *DiscoveryChain {
- return &DiscoveryChain{c}
-}
-
-func (d *DiscoveryChain) Get(name string, opts *DiscoveryChainOptions, q *QueryOptions) (*DiscoveryChainResponse, *QueryMeta, error) {
- if name == "" {
- return nil, nil, fmt.Errorf("Name parameter must not be empty")
- }
-
- method := "GET"
- if opts != nil && opts.requiresPOST() {
- method = "POST"
- }
-
- r := d.c.newRequest(method, fmt.Sprintf("/v1/discovery-chain/%s", name))
- r.setQueryOptions(q)
-
- if opts != nil {
- if opts.EvaluateInDatacenter != "" {
- r.params.Set("compile-dc", opts.EvaluateInDatacenter)
- }
- // TODO(namespaces): handle possible EvaluateInNamespace here
- }
-
- if method == "POST" {
- r.obj = opts
- }
-
- rtt, resp, err := requireOK(d.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out DiscoveryChainResponse
-
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
-
- return &out, qm, nil
-}
-
-type DiscoveryChainOptions struct {
- EvaluateInDatacenter string `json:"-"`
-
- // OverrideMeshGateway allows for the mesh gateway setting to be overridden
- // for any resolver in the compiled chain.
- OverrideMeshGateway MeshGatewayConfig `json:",omitempty"`
-
- // OverrideProtocol allows for the final protocol for the chain to be
- // altered.
- //
- // - If the chain ordinarily would be TCP and an L7 protocol is passed here
- // the chain will not include Routers or Splitters.
- //
- // - If the chain ordinarily would be L7 and TCP is passed here the chain
- // will not include Routers or Splitters.
- OverrideProtocol string `json:",omitempty"`
-
- // OverrideConnectTimeout allows for the ConnectTimeout setting to be
- // overridden for any resolver in the compiled chain.
- OverrideConnectTimeout time.Duration `json:",omitempty"`
-}
-
-func (o *DiscoveryChainOptions) requiresPOST() bool {
- if o == nil {
- return false
- }
- return o.OverrideMeshGateway.Mode != "" ||
- o.OverrideProtocol != "" ||
- o.OverrideConnectTimeout != 0
-}
-
-type DiscoveryChainResponse struct {
- Chain *CompiledDiscoveryChain
-}
-
-type CompiledDiscoveryChain struct {
- ServiceName string
- Namespace string
- Datacenter string
-
- // CustomizationHash is a unique hash of any data that affects the
- // compilation of the discovery chain other than config entries or the
- // name/namespace/datacenter evaluation criteria.
- //
- // If set, this value should be used to prefix/suffix any generated load
- // balancer data plane objects to avoid sharing customized and
- // non-customized versions.
- CustomizationHash string
-
- // Protocol is the overall protocol shared by everything in the chain.
- Protocol string
-
- // StartNode is the first key into the Nodes map that should be followed
- // when walking the discovery chain.
- StartNode string
-
- // Nodes contains all nodes available for traversal in the chain keyed by a
- // unique name. You can walk this by starting with StartNode.
- //
- // NOTE: The names should be treated as opaque values and are only
- // guaranteed to be consistent within a single compilation.
- Nodes map[string]*DiscoveryGraphNode
-
- // Targets is a list of all targets used in this chain.
- //
- // NOTE: The names should be treated as opaque values and are only
- // guaranteed to be consistent within a single compilation.
- Targets map[string]*DiscoveryTarget
-}
-
-const (
- DiscoveryGraphNodeTypeRouter = "router"
- DiscoveryGraphNodeTypeSplitter = "splitter"
- DiscoveryGraphNodeTypeResolver = "resolver"
-)
-
-// DiscoveryGraphNode is a single node in the compiled discovery chain.
-type DiscoveryGraphNode struct {
- Type string
- Name string // this is NOT necessarily a service
-
- // fields for Type==router
- Routes []*DiscoveryRoute
-
- // fields for Type==splitter
- Splits []*DiscoverySplit
-
- // fields for Type==resolver
- Resolver *DiscoveryResolver
-}
-
-// compiled form of ServiceRoute
-type DiscoveryRoute struct {
- Definition *ServiceRoute
- NextNode string
-}
-
-// compiled form of ServiceSplit
-type DiscoverySplit struct {
- Weight float32
- NextNode string
-}
-
-// compiled form of ServiceResolverConfigEntry
-type DiscoveryResolver struct {
- Default bool
- ConnectTimeout time.Duration
- Target string
- Failover *DiscoveryFailover
-}
-
-func (r *DiscoveryResolver) MarshalJSON() ([]byte, error) {
- type Alias DiscoveryResolver
- exported := &struct {
- ConnectTimeout string `json:",omitempty"`
- *Alias
- }{
- ConnectTimeout: r.ConnectTimeout.String(),
- Alias: (*Alias)(r),
- }
- if r.ConnectTimeout == 0 {
- exported.ConnectTimeout = ""
- }
-
- return json.Marshal(exported)
-}
-
-func (r *DiscoveryResolver) UnmarshalJSON(data []byte) error {
- type Alias DiscoveryResolver
- aux := &struct {
- ConnectTimeout string
- *Alias
- }{
- Alias: (*Alias)(r),
- }
- if err := json.Unmarshal(data, &aux); err != nil {
- return err
- }
- var err error
- if aux.ConnectTimeout != "" {
- if r.ConnectTimeout, err = time.ParseDuration(aux.ConnectTimeout); err != nil {
- return err
- }
- }
- return nil
-}
-
-// compiled form of ServiceResolverFailover
-type DiscoveryFailover struct {
- Targets []string
-}
-
-// DiscoveryTarget represents all of the inputs necessary to use a resolver
-// config entry to execute a catalog query to generate a list of service
-// instances during discovery.
-type DiscoveryTarget struct {
- ID string
-
- Service string
- ServiceSubset string
- Namespace string
- Datacenter string
-
- MeshGateway MeshGatewayConfig
- Subset ServiceResolverSubset
- External bool
- SNI string
- Name string
-}
diff --git a/vendor/github.com/hashicorp/consul/api/event.go b/vendor/github.com/hashicorp/consul/api/event.go
deleted file mode 100644
index 85b5b069b03..00000000000
--- a/vendor/github.com/hashicorp/consul/api/event.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package api
-
-import (
- "bytes"
- "strconv"
-)
-
-// Event can be used to query the Event endpoints
-type Event struct {
- c *Client
-}
-
-// UserEvent represents an event that was fired by the user
-type UserEvent struct {
- ID string
- Name string
- Payload []byte
- NodeFilter string
- ServiceFilter string
- TagFilter string
- Version int
- LTime uint64
-}
-
-// Event returns a handle to the event endpoints
-func (c *Client) Event() *Event {
- return &Event{c}
-}
-
-// Fire is used to fire a new user event. Only the Name, Payload and Filters
-// are respected. This returns the ID or an associated error. Cross DC requests
-// are supported.
-func (e *Event) Fire(params *UserEvent, q *WriteOptions) (string, *WriteMeta, error) {
- r := e.c.newRequest("PUT", "/v1/event/fire/"+params.Name)
- r.setWriteOptions(q)
- if params.NodeFilter != "" {
- r.params.Set("node", params.NodeFilter)
- }
- if params.ServiceFilter != "" {
- r.params.Set("service", params.ServiceFilter)
- }
- if params.TagFilter != "" {
- r.params.Set("tag", params.TagFilter)
- }
- if params.Payload != nil {
- r.body = bytes.NewReader(params.Payload)
- }
-
- rtt, resp, err := requireOK(e.c.doRequest(r))
- if err != nil {
- return "", nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
- var out UserEvent
- if err := decodeBody(resp, &out); err != nil {
- return "", nil, err
- }
- return out.ID, wm, nil
-}
-
-// List is used to get the most recent events an agent has received.
-// This list can be optionally filtered by the name. This endpoint supports
-// quasi-blocking queries. The index is not monotonic, nor does it provide provide
-// LastContact or KnownLeader.
-func (e *Event) List(name string, q *QueryOptions) ([]*UserEvent, *QueryMeta, error) {
- r := e.c.newRequest("GET", "/v1/event/list")
- r.setQueryOptions(q)
- if name != "" {
- r.params.Set("name", name)
- }
- rtt, resp, err := requireOK(e.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var entries []*UserEvent
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// IDToIndex is a bit of a hack. This simulates the index generation to
-// convert an event ID into a WaitIndex.
-func (e *Event) IDToIndex(uuid string) uint64 {
- lower := uuid[0:8] + uuid[9:13] + uuid[14:18]
- upper := uuid[19:23] + uuid[24:36]
- lowVal, err := strconv.ParseUint(lower, 16, 64)
- if err != nil {
- panic("Failed to convert " + lower)
- }
- highVal, err := strconv.ParseUint(upper, 16, 64)
- if err != nil {
- panic("Failed to convert " + upper)
- }
- return lowVal ^ highVal
-}
diff --git a/vendor/github.com/hashicorp/consul/api/go.mod b/vendor/github.com/hashicorp/consul/api/go.mod
deleted file mode 100644
index d02afa95a15..00000000000
--- a/vendor/github.com/hashicorp/consul/api/go.mod
+++ /dev/null
@@ -1,16 +0,0 @@
-module github.com/hashicorp/consul/api
-
-go 1.12
-
-replace github.com/hashicorp/consul/sdk => ../sdk
-
-require (
- github.com/hashicorp/consul/sdk v0.3.0
- github.com/hashicorp/go-cleanhttp v0.5.1
- github.com/hashicorp/go-rootcerts v1.0.0
- github.com/hashicorp/go-uuid v1.0.1
- github.com/hashicorp/serf v0.8.2
- github.com/mitchellh/mapstructure v1.1.2
- github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c
- github.com/stretchr/testify v1.3.0
-)
diff --git a/vendor/github.com/hashicorp/consul/api/go.sum b/vendor/github.com/hashicorp/consul/api/go.sum
deleted file mode 100644
index 72a87ea68db..00000000000
--- a/vendor/github.com/hashicorp/consul/api/go.sum
+++ /dev/null
@@ -1,78 +0,0 @@
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/hashicorp/consul/sdk v0.3.0 h1:UOxjlb4xVNF93jak1mzzoBatyFju9nrkxpVwIp/QqxQ=
-github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4=
-github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI=
-github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
-github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
-github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
-github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M=
-github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0=
-github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
-github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3 h1:KYQXGkl6vs02hK7pK4eIbw0NpNPedieTSTEiJ//bwGs=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=
-golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5 h1:x6r4Jo0KNzOOzYd8lbcRsqjuqEASK6ob3auvWYM4/8U=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
diff --git a/vendor/github.com/hashicorp/consul/api/health.go b/vendor/github.com/hashicorp/consul/api/health.go
deleted file mode 100644
index ce8e6975055..00000000000
--- a/vendor/github.com/hashicorp/consul/api/health.go
+++ /dev/null
@@ -1,354 +0,0 @@
-package api
-
-import (
- "encoding/json"
- "fmt"
- "strings"
- "time"
-)
-
-const (
- // HealthAny is special, and is used as a wild card,
- // not as a specific state.
- HealthAny = "any"
- HealthPassing = "passing"
- HealthWarning = "warning"
- HealthCritical = "critical"
- HealthMaint = "maintenance"
-)
-
-const (
- // NodeMaint is the special key set by a node in maintenance mode.
- NodeMaint = "_node_maintenance"
-
- // ServiceMaintPrefix is the prefix for a service in maintenance mode.
- ServiceMaintPrefix = "_service_maintenance:"
-)
-
-// HealthCheck is used to represent a single check
-type HealthCheck struct {
- Node string
- CheckID string
- Name string
- Status string
- Notes string
- Output string
- ServiceID string
- ServiceName string
- ServiceTags []string
- Type string
-
- Definition HealthCheckDefinition
-
- CreateIndex uint64
- ModifyIndex uint64
-}
-
-// HealthCheckDefinition is used to store the details about
-// a health check's execution.
-type HealthCheckDefinition struct {
- HTTP string
- Header map[string][]string
- Method string
- TLSSkipVerify bool
- TCP string
- IntervalDuration time.Duration `json:"-"`
- TimeoutDuration time.Duration `json:"-"`
- DeregisterCriticalServiceAfterDuration time.Duration `json:"-"`
-
- // DEPRECATED in Consul 1.4.1. Use the above time.Duration fields instead.
- Interval ReadableDuration
- Timeout ReadableDuration
- DeregisterCriticalServiceAfter ReadableDuration
-}
-
-func (d *HealthCheckDefinition) MarshalJSON() ([]byte, error) {
- type Alias HealthCheckDefinition
- out := &struct {
- Interval string
- Timeout string
- DeregisterCriticalServiceAfter string
- *Alias
- }{
- Interval: d.Interval.String(),
- Timeout: d.Timeout.String(),
- DeregisterCriticalServiceAfter: d.DeregisterCriticalServiceAfter.String(),
- Alias: (*Alias)(d),
- }
-
- if d.IntervalDuration != 0 {
- out.Interval = d.IntervalDuration.String()
- } else if d.Interval != 0 {
- out.Interval = d.Interval.String()
- }
- if d.TimeoutDuration != 0 {
- out.Timeout = d.TimeoutDuration.String()
- } else if d.Timeout != 0 {
- out.Timeout = d.Timeout.String()
- }
- if d.DeregisterCriticalServiceAfterDuration != 0 {
- out.DeregisterCriticalServiceAfter = d.DeregisterCriticalServiceAfterDuration.String()
- } else if d.DeregisterCriticalServiceAfter != 0 {
- out.DeregisterCriticalServiceAfter = d.DeregisterCriticalServiceAfter.String()
- }
-
- return json.Marshal(out)
-}
-
-func (t *HealthCheckDefinition) UnmarshalJSON(data []byte) (err error) {
- type Alias HealthCheckDefinition
- aux := &struct {
- IntervalDuration interface{}
- TimeoutDuration interface{}
- DeregisterCriticalServiceAfterDuration interface{}
- *Alias
- }{
- Alias: (*Alias)(t),
- }
- if err := json.Unmarshal(data, &aux); err != nil {
- return err
- }
-
- // Parse the values into both the time.Duration and old ReadableDuration fields.
-
- if aux.IntervalDuration == nil {
- t.IntervalDuration = time.Duration(t.Interval)
- } else {
- switch v := aux.IntervalDuration.(type) {
- case string:
- if t.IntervalDuration, err = time.ParseDuration(v); err != nil {
- return err
- }
- case float64:
- t.IntervalDuration = time.Duration(v)
- }
- t.Interval = ReadableDuration(t.IntervalDuration)
- }
-
- if aux.TimeoutDuration == nil {
- t.TimeoutDuration = time.Duration(t.Timeout)
- } else {
- switch v := aux.TimeoutDuration.(type) {
- case string:
- if t.TimeoutDuration, err = time.ParseDuration(v); err != nil {
- return err
- }
- case float64:
- t.TimeoutDuration = time.Duration(v)
- }
- t.Timeout = ReadableDuration(t.TimeoutDuration)
- }
- if aux.DeregisterCriticalServiceAfterDuration == nil {
- t.DeregisterCriticalServiceAfterDuration = time.Duration(t.DeregisterCriticalServiceAfter)
- } else {
- switch v := aux.DeregisterCriticalServiceAfterDuration.(type) {
- case string:
- if t.DeregisterCriticalServiceAfterDuration, err = time.ParseDuration(v); err != nil {
- return err
- }
- case float64:
- t.DeregisterCriticalServiceAfterDuration = time.Duration(v)
- }
- t.DeregisterCriticalServiceAfter = ReadableDuration(t.DeregisterCriticalServiceAfterDuration)
- }
-
- return nil
-}
-
-// HealthChecks is a collection of HealthCheck structs.
-type HealthChecks []*HealthCheck
-
-// AggregatedStatus returns the "best" status for the list of health checks.
-// Because a given entry may have many service and node-level health checks
-// attached, this function determines the best representative of the status as
-// as single string using the following heuristic:
-//
-// maintenance > critical > warning > passing
-//
-func (c HealthChecks) AggregatedStatus() string {
- var passing, warning, critical, maintenance bool
- for _, check := range c {
- id := string(check.CheckID)
- if id == NodeMaint || strings.HasPrefix(id, ServiceMaintPrefix) {
- maintenance = true
- continue
- }
-
- switch check.Status {
- case HealthPassing:
- passing = true
- case HealthWarning:
- warning = true
- case HealthCritical:
- critical = true
- default:
- return ""
- }
- }
-
- switch {
- case maintenance:
- return HealthMaint
- case critical:
- return HealthCritical
- case warning:
- return HealthWarning
- case passing:
- return HealthPassing
- default:
- return HealthPassing
- }
-}
-
-// ServiceEntry is used for the health service endpoint
-type ServiceEntry struct {
- Node *Node
- Service *AgentService
- Checks HealthChecks
-}
-
-// Health can be used to query the Health endpoints
-type Health struct {
- c *Client
-}
-
-// Health returns a handle to the health endpoints
-func (c *Client) Health() *Health {
- return &Health{c}
-}
-
-// Node is used to query for checks belonging to a given node
-func (h *Health) Node(node string, q *QueryOptions) (HealthChecks, *QueryMeta, error) {
- r := h.c.newRequest("GET", "/v1/health/node/"+node)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out HealthChecks
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// Checks is used to return the checks associated with a service
-func (h *Health) Checks(service string, q *QueryOptions) (HealthChecks, *QueryMeta, error) {
- r := h.c.newRequest("GET", "/v1/health/checks/"+service)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out HealthChecks
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// Service is used to query health information along with service info
-// for a given service. It can optionally do server-side filtering on a tag
-// or nodes with passing health checks only.
-func (h *Health) Service(service, tag string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
- var tags []string
- if tag != "" {
- tags = []string{tag}
- }
- return h.service(service, tags, passingOnly, q, false)
-}
-
-func (h *Health) ServiceMultipleTags(service string, tags []string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
- return h.service(service, tags, passingOnly, q, false)
-}
-
-// Connect is equivalent to Service except that it will only return services
-// which are Connect-enabled and will returns the connection address for Connect
-// client's to use which may be a proxy in front of the named service. If
-// passingOnly is true only instances where both the service and any proxy are
-// healthy will be returned.
-func (h *Health) Connect(service, tag string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
- var tags []string
- if tag != "" {
- tags = []string{tag}
- }
- return h.service(service, tags, passingOnly, q, true)
-}
-
-func (h *Health) ConnectMultipleTags(service string, tags []string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
- return h.service(service, tags, passingOnly, q, true)
-}
-
-func (h *Health) service(service string, tags []string, passingOnly bool, q *QueryOptions, connect bool) ([]*ServiceEntry, *QueryMeta, error) {
- path := "/v1/health/service/" + service
- if connect {
- path = "/v1/health/connect/" + service
- }
- r := h.c.newRequest("GET", path)
- r.setQueryOptions(q)
- if len(tags) > 0 {
- for _, tag := range tags {
- r.params.Add("tag", tag)
- }
- }
- if passingOnly {
- r.params.Set(HealthPassing, "1")
- }
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out []*ServiceEntry
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// State is used to retrieve all the checks in a given state.
-// The wildcard "any" state can also be used for all checks.
-func (h *Health) State(state string, q *QueryOptions) (HealthChecks, *QueryMeta, error) {
- switch state {
- case HealthAny:
- case HealthWarning:
- case HealthCritical:
- case HealthPassing:
- default:
- return nil, nil, fmt.Errorf("Unsupported state: %v", state)
- }
- r := h.c.newRequest("GET", "/v1/health/state/"+state)
- r.setQueryOptions(q)
- rtt, resp, err := requireOK(h.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- var out HealthChecks
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/kv.go b/vendor/github.com/hashicorp/consul/api/kv.go
deleted file mode 100644
index bd45a067c90..00000000000
--- a/vendor/github.com/hashicorp/consul/api/kv.go
+++ /dev/null
@@ -1,286 +0,0 @@
-package api
-
-import (
- "bytes"
- "fmt"
- "io"
- "net/http"
- "strconv"
- "strings"
-)
-
-// KVPair is used to represent a single K/V entry
-type KVPair struct {
- // Key is the name of the key. It is also part of the URL path when accessed
- // via the API.
- Key string
-
- // CreateIndex holds the index corresponding the creation of this KVPair. This
- // is a read-only field.
- CreateIndex uint64
-
- // ModifyIndex is used for the Check-And-Set operations and can also be fed
- // back into the WaitIndex of the QueryOptions in order to perform blocking
- // queries.
- ModifyIndex uint64
-
- // LockIndex holds the index corresponding to a lock on this key, if any. This
- // is a read-only field.
- LockIndex uint64
-
- // Flags are any user-defined flags on the key. It is up to the implementer
- // to check these values, since Consul does not treat them specially.
- Flags uint64
-
- // Value is the value for the key. This can be any value, but it will be
- // base64 encoded upon transport.
- Value []byte
-
- // Session is a string representing the ID of the session. Any other
- // interactions with this key over the same session must specify the same
- // session ID.
- Session string
-}
-
-// KVPairs is a list of KVPair objects
-type KVPairs []*KVPair
-
-// KV is used to manipulate the K/V API
-type KV struct {
- c *Client
-}
-
-// KV is used to return a handle to the K/V apis
-func (c *Client) KV() *KV {
- return &KV{c}
-}
-
-// Get is used to lookup a single key. The returned pointer
-// to the KVPair will be nil if the key does not exist.
-func (k *KV) Get(key string, q *QueryOptions) (*KVPair, *QueryMeta, error) {
- resp, qm, err := k.getInternal(key, nil, q)
- if err != nil {
- return nil, nil, err
- }
- if resp == nil {
- return nil, qm, nil
- }
- defer resp.Body.Close()
-
- var entries []*KVPair
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- if len(entries) > 0 {
- return entries[0], qm, nil
- }
- return nil, qm, nil
-}
-
-// List is used to lookup all keys under a prefix
-func (k *KV) List(prefix string, q *QueryOptions) (KVPairs, *QueryMeta, error) {
- resp, qm, err := k.getInternal(prefix, map[string]string{"recurse": ""}, q)
- if err != nil {
- return nil, nil, err
- }
- if resp == nil {
- return nil, qm, nil
- }
- defer resp.Body.Close()
-
- var entries []*KVPair
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// Keys is used to list all the keys under a prefix. Optionally,
-// a separator can be used to limit the responses.
-func (k *KV) Keys(prefix, separator string, q *QueryOptions) ([]string, *QueryMeta, error) {
- params := map[string]string{"keys": ""}
- if separator != "" {
- params["separator"] = separator
- }
- resp, qm, err := k.getInternal(prefix, params, q)
- if err != nil {
- return nil, nil, err
- }
- if resp == nil {
- return nil, qm, nil
- }
- defer resp.Body.Close()
-
- var entries []string
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-func (k *KV) getInternal(key string, params map[string]string, q *QueryOptions) (*http.Response, *QueryMeta, error) {
- r := k.c.newRequest("GET", "/v1/kv/"+strings.TrimPrefix(key, "/"))
- r.setQueryOptions(q)
- for param, val := range params {
- r.params.Set(param, val)
- }
- rtt, resp, err := k.c.doRequest(r)
- if err != nil {
- return nil, nil, err
- }
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- if resp.StatusCode == 404 {
- resp.Body.Close()
- return nil, qm, nil
- } else if resp.StatusCode != 200 {
- resp.Body.Close()
- return nil, nil, fmt.Errorf("Unexpected response code: %d", resp.StatusCode)
- }
- return resp, qm, nil
-}
-
-// Put is used to write a new value. Only the
-// Key, Flags and Value is respected.
-func (k *KV) Put(p *KVPair, q *WriteOptions) (*WriteMeta, error) {
- params := make(map[string]string, 1)
- if p.Flags != 0 {
- params["flags"] = strconv.FormatUint(p.Flags, 10)
- }
- _, wm, err := k.put(p.Key, params, p.Value, q)
- return wm, err
-}
-
-// CAS is used for a Check-And-Set operation. The Key,
-// ModifyIndex, Flags and Value are respected. Returns true
-// on success or false on failures.
-func (k *KV) CAS(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) {
- params := make(map[string]string, 2)
- if p.Flags != 0 {
- params["flags"] = strconv.FormatUint(p.Flags, 10)
- }
- params["cas"] = strconv.FormatUint(p.ModifyIndex, 10)
- return k.put(p.Key, params, p.Value, q)
-}
-
-// Acquire is used for a lock acquisition operation. The Key,
-// Flags, Value and Session are respected. Returns true
-// on success or false on failures.
-func (k *KV) Acquire(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) {
- params := make(map[string]string, 2)
- if p.Flags != 0 {
- params["flags"] = strconv.FormatUint(p.Flags, 10)
- }
- params["acquire"] = p.Session
- return k.put(p.Key, params, p.Value, q)
-}
-
-// Release is used for a lock release operation. The Key,
-// Flags, Value and Session are respected. Returns true
-// on success or false on failures.
-func (k *KV) Release(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) {
- params := make(map[string]string, 2)
- if p.Flags != 0 {
- params["flags"] = strconv.FormatUint(p.Flags, 10)
- }
- params["release"] = p.Session
- return k.put(p.Key, params, p.Value, q)
-}
-
-func (k *KV) put(key string, params map[string]string, body []byte, q *WriteOptions) (bool, *WriteMeta, error) {
- if len(key) > 0 && key[0] == '/' {
- return false, nil, fmt.Errorf("Invalid key. Key must not begin with a '/': %s", key)
- }
-
- r := k.c.newRequest("PUT", "/v1/kv/"+key)
- r.setWriteOptions(q)
- for param, val := range params {
- r.params.Set(param, val)
- }
- r.body = bytes.NewReader(body)
- rtt, resp, err := requireOK(k.c.doRequest(r))
- if err != nil {
- return false, nil, err
- }
- defer resp.Body.Close()
-
- qm := &WriteMeta{}
- qm.RequestTime = rtt
-
- var buf bytes.Buffer
- if _, err := io.Copy(&buf, resp.Body); err != nil {
- return false, nil, fmt.Errorf("Failed to read response: %v", err)
- }
- res := strings.Contains(buf.String(), "true")
- return res, qm, nil
-}
-
-// Delete is used to delete a single key
-func (k *KV) Delete(key string, w *WriteOptions) (*WriteMeta, error) {
- _, qm, err := k.deleteInternal(key, nil, w)
- return qm, err
-}
-
-// DeleteCAS is used for a Delete Check-And-Set operation. The Key
-// and ModifyIndex are respected. Returns true on success or false on failures.
-func (k *KV) DeleteCAS(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) {
- params := map[string]string{
- "cas": strconv.FormatUint(p.ModifyIndex, 10),
- }
- return k.deleteInternal(p.Key, params, q)
-}
-
-// DeleteTree is used to delete all keys under a prefix
-func (k *KV) DeleteTree(prefix string, w *WriteOptions) (*WriteMeta, error) {
- _, qm, err := k.deleteInternal(prefix, map[string]string{"recurse": ""}, w)
- return qm, err
-}
-
-func (k *KV) deleteInternal(key string, params map[string]string, q *WriteOptions) (bool, *WriteMeta, error) {
- r := k.c.newRequest("DELETE", "/v1/kv/"+strings.TrimPrefix(key, "/"))
- r.setWriteOptions(q)
- for param, val := range params {
- r.params.Set(param, val)
- }
- rtt, resp, err := requireOK(k.c.doRequest(r))
- if err != nil {
- return false, nil, err
- }
- defer resp.Body.Close()
-
- qm := &WriteMeta{}
- qm.RequestTime = rtt
-
- var buf bytes.Buffer
- if _, err := io.Copy(&buf, resp.Body); err != nil {
- return false, nil, fmt.Errorf("Failed to read response: %v", err)
- }
- res := strings.Contains(buf.String(), "true")
- return res, qm, nil
-}
-
-// The Txn function has been deprecated from the KV object; please see the Txn
-// object for more information about Transactions.
-func (k *KV) Txn(txn KVTxnOps, q *QueryOptions) (bool, *KVTxnResponse, *QueryMeta, error) {
- var ops TxnOps
- for _, op := range txn {
- ops = append(ops, &TxnOp{KV: op})
- }
-
- respOk, txnResp, qm, err := k.c.txn(ops, q)
- if err != nil {
- return false, nil, nil, err
- }
-
- // Convert from the internal format.
- kvResp := KVTxnResponse{
- Errors: txnResp.Errors,
- }
- for _, result := range txnResp.Results {
- kvResp.Results = append(kvResp.Results, result.KV)
- }
- return respOk, &kvResp, qm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/lock.go b/vendor/github.com/hashicorp/consul/api/lock.go
deleted file mode 100644
index 82339cb744a..00000000000
--- a/vendor/github.com/hashicorp/consul/api/lock.go
+++ /dev/null
@@ -1,386 +0,0 @@
-package api
-
-import (
- "fmt"
- "sync"
- "time"
-)
-
-const (
- // DefaultLockSessionName is the Session Name we assign if none is provided
- DefaultLockSessionName = "Consul API Lock"
-
- // DefaultLockSessionTTL is the default session TTL if no Session is provided
- // when creating a new Lock. This is used because we do not have another
- // other check to depend upon.
- DefaultLockSessionTTL = "15s"
-
- // DefaultLockWaitTime is how long we block for at a time to check if lock
- // acquisition is possible. This affects the minimum time it takes to cancel
- // a Lock acquisition.
- DefaultLockWaitTime = 15 * time.Second
-
- // DefaultLockRetryTime is how long we wait after a failed lock acquisition
- // before attempting to do the lock again. This is so that once a lock-delay
- // is in effect, we do not hot loop retrying the acquisition.
- DefaultLockRetryTime = 5 * time.Second
-
- // DefaultMonitorRetryTime is how long we wait after a failed monitor check
- // of a lock (500 response code). This allows the monitor to ride out brief
- // periods of unavailability, subject to the MonitorRetries setting in the
- // lock options which is by default set to 0, disabling this feature. This
- // affects locks and semaphores.
- DefaultMonitorRetryTime = 2 * time.Second
-
- // LockFlagValue is a magic flag we set to indicate a key
- // is being used for a lock. It is used to detect a potential
- // conflict with a semaphore.
- LockFlagValue = 0x2ddccbc058a50c18
-)
-
-var (
- // ErrLockHeld is returned if we attempt to double lock
- ErrLockHeld = fmt.Errorf("Lock already held")
-
- // ErrLockNotHeld is returned if we attempt to unlock a lock
- // that we do not hold.
- ErrLockNotHeld = fmt.Errorf("Lock not held")
-
- // ErrLockInUse is returned if we attempt to destroy a lock
- // that is in use.
- ErrLockInUse = fmt.Errorf("Lock in use")
-
- // ErrLockConflict is returned if the flags on a key
- // used for a lock do not match expectation
- ErrLockConflict = fmt.Errorf("Existing key does not match lock use")
-)
-
-// Lock is used to implement client-side leader election. It is follows the
-// algorithm as described here: https://www.consul.io/docs/guides/leader-election.html.
-type Lock struct {
- c *Client
- opts *LockOptions
-
- isHeld bool
- sessionRenew chan struct{}
- lockSession string
- l sync.Mutex
-}
-
-// LockOptions is used to parameterize the Lock behavior.
-type LockOptions struct {
- Key string // Must be set and have write permissions
- Value []byte // Optional, value to associate with the lock
- Session string // Optional, created if not specified
- SessionOpts *SessionEntry // Optional, options to use when creating a session
- SessionName string // Optional, defaults to DefaultLockSessionName (ignored if SessionOpts is given)
- SessionTTL string // Optional, defaults to DefaultLockSessionTTL (ignored if SessionOpts is given)
- MonitorRetries int // Optional, defaults to 0 which means no retries
- MonitorRetryTime time.Duration // Optional, defaults to DefaultMonitorRetryTime
- LockWaitTime time.Duration // Optional, defaults to DefaultLockWaitTime
- LockTryOnce bool // Optional, defaults to false which means try forever
-}
-
-// LockKey returns a handle to a lock struct which can be used
-// to acquire and release the mutex. The key used must have
-// write permissions.
-func (c *Client) LockKey(key string) (*Lock, error) {
- opts := &LockOptions{
- Key: key,
- }
- return c.LockOpts(opts)
-}
-
-// LockOpts returns a handle to a lock struct which can be used
-// to acquire and release the mutex. The key used must have
-// write permissions.
-func (c *Client) LockOpts(opts *LockOptions) (*Lock, error) {
- if opts.Key == "" {
- return nil, fmt.Errorf("missing key")
- }
- if opts.SessionName == "" {
- opts.SessionName = DefaultLockSessionName
- }
- if opts.SessionTTL == "" {
- opts.SessionTTL = DefaultLockSessionTTL
- } else {
- if _, err := time.ParseDuration(opts.SessionTTL); err != nil {
- return nil, fmt.Errorf("invalid SessionTTL: %v", err)
- }
- }
- if opts.MonitorRetryTime == 0 {
- opts.MonitorRetryTime = DefaultMonitorRetryTime
- }
- if opts.LockWaitTime == 0 {
- opts.LockWaitTime = DefaultLockWaitTime
- }
- l := &Lock{
- c: c,
- opts: opts,
- }
- return l, nil
-}
-
-// Lock attempts to acquire the lock and blocks while doing so.
-// Providing a non-nil stopCh can be used to abort the lock attempt.
-// Returns a channel that is closed if our lock is lost or an error.
-// This channel could be closed at any time due to session invalidation,
-// communication errors, operator intervention, etc. It is NOT safe to
-// assume that the lock is held until Unlock() unless the Session is specifically
-// created without any associated health checks. By default Consul sessions
-// prefer liveness over safety and an application must be able to handle
-// the lock being lost.
-func (l *Lock) Lock(stopCh <-chan struct{}) (<-chan struct{}, error) {
- // Hold the lock as we try to acquire
- l.l.Lock()
- defer l.l.Unlock()
-
- // Check if we already hold the lock
- if l.isHeld {
- return nil, ErrLockHeld
- }
-
- // Check if we need to create a session first
- l.lockSession = l.opts.Session
- if l.lockSession == "" {
- s, err := l.createSession()
- if err != nil {
- return nil, fmt.Errorf("failed to create session: %v", err)
- }
-
- l.sessionRenew = make(chan struct{})
- l.lockSession = s
- session := l.c.Session()
- go session.RenewPeriodic(l.opts.SessionTTL, s, nil, l.sessionRenew)
-
- // If we fail to acquire the lock, cleanup the session
- defer func() {
- if !l.isHeld {
- close(l.sessionRenew)
- l.sessionRenew = nil
- }
- }()
- }
-
- // Setup the query options
- kv := l.c.KV()
- qOpts := &QueryOptions{
- WaitTime: l.opts.LockWaitTime,
- }
-
- start := time.Now()
- attempts := 0
-WAIT:
- // Check if we should quit
- select {
- case <-stopCh:
- return nil, nil
- default:
- }
-
- // Handle the one-shot mode.
- if l.opts.LockTryOnce && attempts > 0 {
- elapsed := time.Since(start)
- if elapsed > l.opts.LockWaitTime {
- return nil, nil
- }
-
- // Query wait time should not exceed the lock wait time
- qOpts.WaitTime = l.opts.LockWaitTime - elapsed
- }
- attempts++
-
- // Look for an existing lock, blocking until not taken
- pair, meta, err := kv.Get(l.opts.Key, qOpts)
- if err != nil {
- return nil, fmt.Errorf("failed to read lock: %v", err)
- }
- if pair != nil && pair.Flags != LockFlagValue {
- return nil, ErrLockConflict
- }
- locked := false
- if pair != nil && pair.Session == l.lockSession {
- goto HELD
- }
- if pair != nil && pair.Session != "" {
- qOpts.WaitIndex = meta.LastIndex
- goto WAIT
- }
-
- // Try to acquire the lock
- pair = l.lockEntry(l.lockSession)
- locked, _, err = kv.Acquire(pair, nil)
- if err != nil {
- return nil, fmt.Errorf("failed to acquire lock: %v", err)
- }
-
- // Handle the case of not getting the lock
- if !locked {
- // Determine why the lock failed
- qOpts.WaitIndex = 0
- pair, meta, err = kv.Get(l.opts.Key, qOpts)
- if pair != nil && pair.Session != "" {
- //If the session is not null, this means that a wait can safely happen
- //using a long poll
- qOpts.WaitIndex = meta.LastIndex
- goto WAIT
- } else {
- // If the session is empty and the lock failed to acquire, then it means
- // a lock-delay is in effect and a timed wait must be used
- select {
- case <-time.After(DefaultLockRetryTime):
- goto WAIT
- case <-stopCh:
- return nil, nil
- }
- }
- }
-
-HELD:
- // Watch to ensure we maintain leadership
- leaderCh := make(chan struct{})
- go l.monitorLock(l.lockSession, leaderCh)
-
- // Set that we own the lock
- l.isHeld = true
-
- // Locked! All done
- return leaderCh, nil
-}
-
-// Unlock released the lock. It is an error to call this
-// if the lock is not currently held.
-func (l *Lock) Unlock() error {
- // Hold the lock as we try to release
- l.l.Lock()
- defer l.l.Unlock()
-
- // Ensure the lock is actually held
- if !l.isHeld {
- return ErrLockNotHeld
- }
-
- // Set that we no longer own the lock
- l.isHeld = false
-
- // Stop the session renew
- if l.sessionRenew != nil {
- defer func() {
- close(l.sessionRenew)
- l.sessionRenew = nil
- }()
- }
-
- // Get the lock entry, and clear the lock session
- lockEnt := l.lockEntry(l.lockSession)
- l.lockSession = ""
-
- // Release the lock explicitly
- kv := l.c.KV()
- _, _, err := kv.Release(lockEnt, nil)
- if err != nil {
- return fmt.Errorf("failed to release lock: %v", err)
- }
- return nil
-}
-
-// Destroy is used to cleanup the lock entry. It is not necessary
-// to invoke. It will fail if the lock is in use.
-func (l *Lock) Destroy() error {
- // Hold the lock as we try to release
- l.l.Lock()
- defer l.l.Unlock()
-
- // Check if we already hold the lock
- if l.isHeld {
- return ErrLockHeld
- }
-
- // Look for an existing lock
- kv := l.c.KV()
- pair, _, err := kv.Get(l.opts.Key, nil)
- if err != nil {
- return fmt.Errorf("failed to read lock: %v", err)
- }
-
- // Nothing to do if the lock does not exist
- if pair == nil {
- return nil
- }
-
- // Check for possible flag conflict
- if pair.Flags != LockFlagValue {
- return ErrLockConflict
- }
-
- // Check if it is in use
- if pair.Session != "" {
- return ErrLockInUse
- }
-
- // Attempt the delete
- didRemove, _, err := kv.DeleteCAS(pair, nil)
- if err != nil {
- return fmt.Errorf("failed to remove lock: %v", err)
- }
- if !didRemove {
- return ErrLockInUse
- }
- return nil
-}
-
-// createSession is used to create a new managed session
-func (l *Lock) createSession() (string, error) {
- session := l.c.Session()
- se := l.opts.SessionOpts
- if se == nil {
- se = &SessionEntry{
- Name: l.opts.SessionName,
- TTL: l.opts.SessionTTL,
- }
- }
- id, _, err := session.Create(se, nil)
- if err != nil {
- return "", err
- }
- return id, nil
-}
-
-// lockEntry returns a formatted KVPair for the lock
-func (l *Lock) lockEntry(session string) *KVPair {
- return &KVPair{
- Key: l.opts.Key,
- Value: l.opts.Value,
- Session: session,
- Flags: LockFlagValue,
- }
-}
-
-// monitorLock is a long running routine to monitor a lock ownership
-// It closes the stopCh if we lose our leadership.
-func (l *Lock) monitorLock(session string, stopCh chan struct{}) {
- defer close(stopCh)
- kv := l.c.KV()
- opts := &QueryOptions{RequireConsistent: true}
-WAIT:
- retries := l.opts.MonitorRetries
-RETRY:
- pair, meta, err := kv.Get(l.opts.Key, opts)
- if err != nil {
- // If configured we can try to ride out a brief Consul unavailability
- // by doing retries. Note that we have to attempt the retry in a non-
- // blocking fashion so that we have a clean place to reset the retry
- // counter if service is restored.
- if retries > 0 && IsRetryableError(err) {
- time.Sleep(l.opts.MonitorRetryTime)
- retries--
- opts.WaitIndex = 0
- goto RETRY
- }
- return
- }
- if pair != nil && pair.Session == session {
- opts.WaitIndex = meta.LastIndex
- goto WAIT
- }
-}
diff --git a/vendor/github.com/hashicorp/consul/api/operator.go b/vendor/github.com/hashicorp/consul/api/operator.go
deleted file mode 100644
index 079e2248663..00000000000
--- a/vendor/github.com/hashicorp/consul/api/operator.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package api
-
-// Operator can be used to perform low-level operator tasks for Consul.
-type Operator struct {
- c *Client
-}
-
-// Operator returns a handle to the operator endpoints.
-func (c *Client) Operator() *Operator {
- return &Operator{c}
-}
diff --git a/vendor/github.com/hashicorp/consul/api/operator_area.go b/vendor/github.com/hashicorp/consul/api/operator_area.go
deleted file mode 100644
index 5cf7e49730c..00000000000
--- a/vendor/github.com/hashicorp/consul/api/operator_area.go
+++ /dev/null
@@ -1,194 +0,0 @@
-package api
-
-// The /v1/operator/area endpoints are available only in Consul Enterprise and
-// interact with its network area subsystem. Network areas are used to link
-// together Consul servers in different Consul datacenters. With network areas,
-// Consul datacenters can be linked together in ways other than a fully-connected
-// mesh, as is required for Consul's WAN.
-
-import (
- "net"
- "time"
-)
-
-// Area defines a network area.
-type Area struct {
- // ID is this identifier for an area (a UUID). This must be left empty
- // when creating a new area.
- ID string
-
- // PeerDatacenter is the peer Consul datacenter that will make up the
- // other side of this network area. Network areas always involve a pair
- // of datacenters: the datacenter where the area was created, and the
- // peer datacenter. This is required.
- PeerDatacenter string
-
- // RetryJoin specifies the address of Consul servers to join to, such as
- // an IPs or hostnames with an optional port number. This is optional.
- RetryJoin []string
-
- // UseTLS specifies whether gossip over this area should be encrypted with TLS
- // if possible.
- UseTLS bool
-}
-
-// AreaJoinResponse is returned when a join occurs and gives the result for each
-// address.
-type AreaJoinResponse struct {
- // The address that was joined.
- Address string
-
- // Whether or not the join was a success.
- Joined bool
-
- // If we couldn't join, this is the message with information.
- Error string
-}
-
-// SerfMember is a generic structure for reporting information about members in
-// a Serf cluster. This is only used by the area endpoints right now, but this
-// could be expanded to other endpoints in the future.
-type SerfMember struct {
- // ID is the node identifier (a UUID).
- ID string
-
- // Name is the node name.
- Name string
-
- // Addr has the IP address.
- Addr net.IP
-
- // Port is the RPC port.
- Port uint16
-
- // Datacenter is the DC name.
- Datacenter string
-
- // Role is "client", "server", or "unknown".
- Role string
-
- // Build has the version of the Consul agent.
- Build string
-
- // Protocol is the protocol of the Consul agent.
- Protocol int
-
- // Status is the Serf health status "none", "alive", "leaving", "left",
- // or "failed".
- Status string
-
- // RTT is the estimated round trip time from the server handling the
- // request to the this member. This will be negative if no RTT estimate
- // is available.
- RTT time.Duration
-}
-
-// AreaCreate will create a new network area. The ID in the given structure must
-// be empty and a generated ID will be returned on success.
-func (op *Operator) AreaCreate(area *Area, q *WriteOptions) (string, *WriteMeta, error) {
- r := op.c.newRequest("POST", "/v1/operator/area")
- r.setWriteOptions(q)
- r.obj = area
- rtt, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return "", nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
-
- var out struct{ ID string }
- if err := decodeBody(resp, &out); err != nil {
- return "", nil, err
- }
- return out.ID, wm, nil
-}
-
-// AreaUpdate will update the configuration of the network area with the given ID.
-func (op *Operator) AreaUpdate(areaID string, area *Area, q *WriteOptions) (string, *WriteMeta, error) {
- r := op.c.newRequest("PUT", "/v1/operator/area/"+areaID)
- r.setWriteOptions(q)
- r.obj = area
- rtt, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return "", nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
-
- var out struct{ ID string }
- if err := decodeBody(resp, &out); err != nil {
- return "", nil, err
- }
- return out.ID, wm, nil
-}
-
-// AreaGet returns a single network area.
-func (op *Operator) AreaGet(areaID string, q *QueryOptions) ([]*Area, *QueryMeta, error) {
- var out []*Area
- qm, err := op.c.query("/v1/operator/area/"+areaID, &out, q)
- if err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// AreaList returns all the available network areas.
-func (op *Operator) AreaList(q *QueryOptions) ([]*Area, *QueryMeta, error) {
- var out []*Area
- qm, err := op.c.query("/v1/operator/area", &out, q)
- if err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// AreaDelete deletes the given network area.
-func (op *Operator) AreaDelete(areaID string, q *WriteOptions) (*WriteMeta, error) {
- r := op.c.newRequest("DELETE", "/v1/operator/area/"+areaID)
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
- return wm, nil
-}
-
-// AreaJoin attempts to join the given set of join addresses to the given
-// network area. See the Area structure for details about join addresses.
-func (op *Operator) AreaJoin(areaID string, addresses []string, q *WriteOptions) ([]*AreaJoinResponse, *WriteMeta, error) {
- r := op.c.newRequest("PUT", "/v1/operator/area/"+areaID+"/join")
- r.setWriteOptions(q)
- r.obj = addresses
- rtt, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
-
- var out []*AreaJoinResponse
- if err := decodeBody(resp, &out); err != nil {
- return nil, nil, err
- }
- return out, wm, nil
-}
-
-// AreaMembers lists the Serf information about the members in the given area.
-func (op *Operator) AreaMembers(areaID string, q *QueryOptions) ([]*SerfMember, *QueryMeta, error) {
- var out []*SerfMember
- qm, err := op.c.query("/v1/operator/area/"+areaID+"/members", &out, q)
- if err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/operator_autopilot.go b/vendor/github.com/hashicorp/consul/api/operator_autopilot.go
deleted file mode 100644
index 0e4ef24649f..00000000000
--- a/vendor/github.com/hashicorp/consul/api/operator_autopilot.go
+++ /dev/null
@@ -1,232 +0,0 @@
-package api
-
-import (
- "bytes"
- "fmt"
- "io"
- "strconv"
- "strings"
- "time"
-)
-
-// AutopilotConfiguration is used for querying/setting the Autopilot configuration.
-// Autopilot helps manage operator tasks related to Consul servers like removing
-// failed servers from the Raft quorum.
-type AutopilotConfiguration struct {
- // CleanupDeadServers controls whether to remove dead servers from the Raft
- // peer list when a new server joins
- CleanupDeadServers bool
-
- // LastContactThreshold is the limit on the amount of time a server can go
- // without leader contact before being considered unhealthy.
- LastContactThreshold *ReadableDuration
-
- // MaxTrailingLogs is the amount of entries in the Raft Log that a server can
- // be behind before being considered unhealthy.
- MaxTrailingLogs uint64
-
- // MinQuorum sets the minimum number of servers allowed in a cluster before
- // autopilot can prune dead servers.
- MinQuorum uint
-
- // ServerStabilizationTime is the minimum amount of time a server must be
- // in a stable, healthy state before it can be added to the cluster. Only
- // applicable with Raft protocol version 3 or higher.
- ServerStabilizationTime *ReadableDuration
-
- // (Enterprise-only) RedundancyZoneTag is the node tag to use for separating
- // servers into zones for redundancy. If left blank, this feature will be disabled.
- RedundancyZoneTag string
-
- // (Enterprise-only) DisableUpgradeMigration will disable Autopilot's upgrade migration
- // strategy of waiting until enough newer-versioned servers have been added to the
- // cluster before promoting them to voters.
- DisableUpgradeMigration bool
-
- // (Enterprise-only) UpgradeVersionTag is the node tag to use for version info when
- // performing upgrade migrations. If left blank, the Consul version will be used.
- UpgradeVersionTag string
-
- // CreateIndex holds the index corresponding the creation of this configuration.
- // This is a read-only field.
- CreateIndex uint64
-
- // ModifyIndex will be set to the index of the last update when retrieving the
- // Autopilot configuration. Resubmitting a configuration with
- // AutopilotCASConfiguration will perform a check-and-set operation which ensures
- // there hasn't been a subsequent update since the configuration was retrieved.
- ModifyIndex uint64
-}
-
-// ServerHealth is the health (from the leader's point of view) of a server.
-type ServerHealth struct {
- // ID is the raft ID of the server.
- ID string
-
- // Name is the node name of the server.
- Name string
-
- // Address is the address of the server.
- Address string
-
- // The status of the SerfHealth check for the server.
- SerfStatus string
-
- // Version is the Consul version of the server.
- Version string
-
- // Leader is whether this server is currently the leader.
- Leader bool
-
- // LastContact is the time since this node's last contact with the leader.
- LastContact *ReadableDuration
-
- // LastTerm is the highest leader term this server has a record of in its Raft log.
- LastTerm uint64
-
- // LastIndex is the last log index this server has a record of in its Raft log.
- LastIndex uint64
-
- // Healthy is whether or not the server is healthy according to the current
- // Autopilot config.
- Healthy bool
-
- // Voter is whether this is a voting server.
- Voter bool
-
- // StableSince is the last time this server's Healthy value changed.
- StableSince time.Time
-}
-
-// OperatorHealthReply is a representation of the overall health of the cluster
-type OperatorHealthReply struct {
- // Healthy is true if all the servers in the cluster are healthy.
- Healthy bool
-
- // FailureTolerance is the number of healthy servers that could be lost without
- // an outage occurring.
- FailureTolerance int
-
- // Servers holds the health of each server.
- Servers []ServerHealth
-}
-
-// ReadableDuration is a duration type that is serialized to JSON in human readable format.
-type ReadableDuration time.Duration
-
-func NewReadableDuration(dur time.Duration) *ReadableDuration {
- d := ReadableDuration(dur)
- return &d
-}
-
-func (d *ReadableDuration) String() string {
- return d.Duration().String()
-}
-
-func (d *ReadableDuration) Duration() time.Duration {
- if d == nil {
- return time.Duration(0)
- }
- return time.Duration(*d)
-}
-
-func (d *ReadableDuration) MarshalJSON() ([]byte, error) {
- return []byte(fmt.Sprintf(`"%s"`, d.Duration().String())), nil
-}
-
-func (d *ReadableDuration) UnmarshalJSON(raw []byte) (err error) {
- if d == nil {
- return fmt.Errorf("cannot unmarshal to nil pointer")
- }
-
- var dur time.Duration
- str := string(raw)
- if len(str) >= 2 && str[0] == '"' && str[len(str)-1] == '"' {
- // quoted string
- dur, err = time.ParseDuration(str[1 : len(str)-1])
- if err != nil {
- return err
- }
- } else {
- // no quotes, not a string
- v, err := strconv.ParseFloat(str, 64)
- if err != nil {
- return err
- }
- dur = time.Duration(v)
- }
-
- *d = ReadableDuration(dur)
- return nil
-}
-
-// AutopilotGetConfiguration is used to query the current Autopilot configuration.
-func (op *Operator) AutopilotGetConfiguration(q *QueryOptions) (*AutopilotConfiguration, error) {
- r := op.c.newRequest("GET", "/v1/operator/autopilot/configuration")
- r.setQueryOptions(q)
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out AutopilotConfiguration
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
-
- return &out, nil
-}
-
-// AutopilotSetConfiguration is used to set the current Autopilot configuration.
-func (op *Operator) AutopilotSetConfiguration(conf *AutopilotConfiguration, q *WriteOptions) error {
- r := op.c.newRequest("PUT", "/v1/operator/autopilot/configuration")
- r.setWriteOptions(q)
- r.obj = conf
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// AutopilotCASConfiguration is used to perform a Check-And-Set update on the
-// Autopilot configuration. The ModifyIndex value will be respected. Returns
-// true on success or false on failures.
-func (op *Operator) AutopilotCASConfiguration(conf *AutopilotConfiguration, q *WriteOptions) (bool, error) {
- r := op.c.newRequest("PUT", "/v1/operator/autopilot/configuration")
- r.setWriteOptions(q)
- r.params.Set("cas", strconv.FormatUint(conf.ModifyIndex, 10))
- r.obj = conf
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return false, err
- }
- defer resp.Body.Close()
-
- var buf bytes.Buffer
- if _, err := io.Copy(&buf, resp.Body); err != nil {
- return false, fmt.Errorf("Failed to read response: %v", err)
- }
- res := strings.Contains(buf.String(), "true")
-
- return res, nil
-}
-
-// AutopilotServerHealth
-func (op *Operator) AutopilotServerHealth(q *QueryOptions) (*OperatorHealthReply, error) {
- r := op.c.newRequest("GET", "/v1/operator/autopilot/health")
- r.setQueryOptions(q)
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out OperatorHealthReply
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return &out, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/operator_keyring.go b/vendor/github.com/hashicorp/consul/api/operator_keyring.go
deleted file mode 100644
index 038d5d5b02f..00000000000
--- a/vendor/github.com/hashicorp/consul/api/operator_keyring.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package api
-
-// keyringRequest is used for performing Keyring operations
-type keyringRequest struct {
- Key string
-}
-
-// KeyringResponse is returned when listing the gossip encryption keys
-type KeyringResponse struct {
- // Whether this response is for a WAN ring
- WAN bool
-
- // The datacenter name this request corresponds to
- Datacenter string
-
- // Segment has the network segment this request corresponds to.
- Segment string
-
- // Messages has information or errors from serf
- Messages map[string]string `json:",omitempty"`
-
- // A map of the encryption keys to the number of nodes they're installed on
- Keys map[string]int
-
- // The total number of nodes in this ring
- NumNodes int
-}
-
-// KeyringInstall is used to install a new gossip encryption key into the cluster
-func (op *Operator) KeyringInstall(key string, q *WriteOptions) error {
- r := op.c.newRequest("POST", "/v1/operator/keyring")
- r.setWriteOptions(q)
- r.obj = keyringRequest{
- Key: key,
- }
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// KeyringList is used to list the gossip keys installed in the cluster
-func (op *Operator) KeyringList(q *QueryOptions) ([]*KeyringResponse, error) {
- r := op.c.newRequest("GET", "/v1/operator/keyring")
- r.setQueryOptions(q)
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out []*KeyringResponse
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return out, nil
-}
-
-// KeyringRemove is used to remove a gossip encryption key from the cluster
-func (op *Operator) KeyringRemove(key string, q *WriteOptions) error {
- r := op.c.newRequest("DELETE", "/v1/operator/keyring")
- r.setWriteOptions(q)
- r.obj = keyringRequest{
- Key: key,
- }
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
-
-// KeyringUse is used to change the active gossip encryption key
-func (op *Operator) KeyringUse(key string, q *WriteOptions) error {
- r := op.c.newRequest("PUT", "/v1/operator/keyring")
- r.setWriteOptions(q)
- r.obj = keyringRequest{
- Key: key,
- }
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return err
- }
- resp.Body.Close()
- return nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/operator_license.go b/vendor/github.com/hashicorp/consul/api/operator_license.go
deleted file mode 100644
index 25aa702e8ad..00000000000
--- a/vendor/github.com/hashicorp/consul/api/operator_license.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package api
-
-import (
- "io/ioutil"
- "strings"
- "time"
-)
-
-type License struct {
- // The unique identifier of the license
- LicenseID string `json:"license_id"`
-
- // The customer ID associated with the license
- CustomerID string `json:"customer_id"`
-
- // If set, an identifier that should be used to lock the license to a
- // particular site, cluster, etc.
- InstallationID string `json:"installation_id"`
-
- // The time at which the license was issued
- IssueTime time.Time `json:"issue_time"`
-
- // The time at which the license starts being valid
- StartTime time.Time `json:"start_time"`
-
- // The time after which the license expires
- ExpirationTime time.Time `json:"expiration_time"`
-
- // The time at which the license ceases to function and can
- // no longer be used in any capacity
- TerminationTime time.Time `json:"termination_time"`
-
- // The product the license is valid for
- Product string `json:"product"`
-
- // License Specific Flags
- Flags map[string]interface{} `json:"flags"`
-
- // List of features enabled by the license
- Features []string `json:"features"`
-}
-
-type LicenseReply struct {
- Valid bool
- License *License
- Warnings []string
-}
-
-func (op *Operator) LicenseGet(q *QueryOptions) (*LicenseReply, error) {
- var reply LicenseReply
- if _, err := op.c.query("/v1/operator/license", &reply, q); err != nil {
- return nil, err
- } else {
- return &reply, nil
- }
-}
-
-func (op *Operator) LicenseGetSigned(q *QueryOptions) (string, error) {
- r := op.c.newRequest("GET", "/v1/operator/license")
- r.params.Set("signed", "1")
- r.setQueryOptions(q)
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return "", err
- }
- defer resp.Body.Close()
-
- data, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", err
- }
-
- return string(data), nil
-}
-
-// LicenseReset will reset the license to the builtin one if it is still valid.
-// If the builtin license is invalid, the current license stays active.
-func (op *Operator) LicenseReset(opts *WriteOptions) (*LicenseReply, error) {
- var reply LicenseReply
- r := op.c.newRequest("DELETE", "/v1/operator/license")
- r.setWriteOptions(opts)
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- if err := decodeBody(resp, &reply); err != nil {
- return nil, err
- }
-
- return &reply, nil
-}
-
-func (op *Operator) LicensePut(license string, opts *WriteOptions) (*LicenseReply, error) {
- var reply LicenseReply
- r := op.c.newRequest("PUT", "/v1/operator/license")
- r.setWriteOptions(opts)
- r.body = strings.NewReader(license)
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- if err := decodeBody(resp, &reply); err != nil {
- return nil, err
- }
-
- return &reply, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/operator_raft.go b/vendor/github.com/hashicorp/consul/api/operator_raft.go
deleted file mode 100644
index a9844df2dd3..00000000000
--- a/vendor/github.com/hashicorp/consul/api/operator_raft.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package api
-
-// RaftServer has information about a server in the Raft configuration.
-type RaftServer struct {
- // ID is the unique ID for the server. These are currently the same
- // as the address, but they will be changed to a real GUID in a future
- // release of Consul.
- ID string
-
- // Node is the node name of the server, as known by Consul, or this
- // will be set to "(unknown)" otherwise.
- Node string
-
- // Address is the IP:port of the server, used for Raft communications.
- Address string
-
- // Leader is true if this server is the current cluster leader.
- Leader bool
-
- // Protocol version is the raft protocol version used by the server
- ProtocolVersion string
-
- // Voter is true if this server has a vote in the cluster. This might
- // be false if the server is staging and still coming online, or if
- // it's a non-voting server, which will be added in a future release of
- // Consul.
- Voter bool
-}
-
-// RaftConfiguration is returned when querying for the current Raft configuration.
-type RaftConfiguration struct {
- // Servers has the list of servers in the Raft configuration.
- Servers []*RaftServer
-
- // Index has the Raft index of this configuration.
- Index uint64
-}
-
-// RaftGetConfiguration is used to query the current Raft peer set.
-func (op *Operator) RaftGetConfiguration(q *QueryOptions) (*RaftConfiguration, error) {
- r := op.c.newRequest("GET", "/v1/operator/raft/configuration")
- r.setQueryOptions(q)
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var out RaftConfiguration
- if err := decodeBody(resp, &out); err != nil {
- return nil, err
- }
- return &out, nil
-}
-
-// RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft
-// quorum but no longer known to Serf or the catalog) by address in the form of
-// "IP:port".
-func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) error {
- r := op.c.newRequest("DELETE", "/v1/operator/raft/peer")
- r.setWriteOptions(q)
-
- r.params.Set("address", string(address))
-
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return err
- }
-
- resp.Body.Close()
- return nil
-}
-
-// RaftRemovePeerByID is used to kick a stale peer (one that it in the Raft
-// quorum but no longer known to Serf or the catalog) by ID.
-func (op *Operator) RaftRemovePeerByID(id string, q *WriteOptions) error {
- r := op.c.newRequest("DELETE", "/v1/operator/raft/peer")
- r.setWriteOptions(q)
-
- r.params.Set("id", string(id))
-
- _, resp, err := requireOK(op.c.doRequest(r))
- if err != nil {
- return err
- }
-
- resp.Body.Close()
- return nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/operator_segment.go b/vendor/github.com/hashicorp/consul/api/operator_segment.go
deleted file mode 100644
index 92b05d3c03b..00000000000
--- a/vendor/github.com/hashicorp/consul/api/operator_segment.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package api
-
-// SegmentList returns all the available LAN segments.
-func (op *Operator) SegmentList(q *QueryOptions) ([]string, *QueryMeta, error) {
- var out []string
- qm, err := op.c.query("/v1/operator/segment", &out, q)
- if err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/prepared_query.go b/vendor/github.com/hashicorp/consul/api/prepared_query.go
deleted file mode 100644
index 02045811681..00000000000
--- a/vendor/github.com/hashicorp/consul/api/prepared_query.go
+++ /dev/null
@@ -1,217 +0,0 @@
-package api
-
-// QueryDatacenterOptions sets options about how we fail over if there are no
-// healthy nodes in the local datacenter.
-type QueryDatacenterOptions struct {
- // NearestN is set to the number of remote datacenters to try, based on
- // network coordinates.
- NearestN int
-
- // Datacenters is a fixed list of datacenters to try after NearestN. We
- // never try a datacenter multiple times, so those are subtracted from
- // this list before proceeding.
- Datacenters []string
-}
-
-// QueryDNSOptions controls settings when query results are served over DNS.
-type QueryDNSOptions struct {
- // TTL is the time to live for the served DNS results.
- TTL string
-}
-
-// ServiceQuery is used to query for a set of healthy nodes offering a specific
-// service.
-type ServiceQuery struct {
- // Service is the service to query.
- Service string
-
- // Near allows baking in the name of a node to automatically distance-
- // sort from. The magic "_agent" value is supported, which sorts near
- // the agent which initiated the request by default.
- Near string
-
- // Failover controls what we do if there are no healthy nodes in the
- // local datacenter.
- Failover QueryDatacenterOptions
-
- // IgnoreCheckIDs is an optional list of health check IDs to ignore when
- // considering which nodes are healthy. It is useful as an emergency measure
- // to temporarily override some health check that is producing false negatives
- // for example.
- IgnoreCheckIDs []string
-
- // If OnlyPassing is true then we will only include nodes with passing
- // health checks (critical AND warning checks will cause a node to be
- // discarded)
- OnlyPassing bool
-
- // Tags are a set of required and/or disallowed tags. If a tag is in
- // this list it must be present. If the tag is preceded with "!" then
- // it is disallowed.
- Tags []string
-
- // NodeMeta is a map of required node metadata fields. If a key/value
- // pair is in this map it must be present on the node in order for the
- // service entry to be returned.
- NodeMeta map[string]string
-
- // ServiceMeta is a map of required service metadata fields. If a key/value
- // pair is in this map it must be present on the node in order for the
- // service entry to be returned.
- ServiceMeta map[string]string
-
- // Connect if true will filter the prepared query results to only
- // include Connect-capable services. These include both native services
- // and proxies for matching services. Note that if a proxy matches,
- // the constraints in the query above (Near, OnlyPassing, etc.) apply
- // to the _proxy_ and not the service being proxied. In practice, proxies
- // should be directly next to their services so this isn't an issue.
- Connect bool
-}
-
-// QueryTemplate carries the arguments for creating a templated query.
-type QueryTemplate struct {
- // Type specifies the type of the query template. Currently only
- // "name_prefix_match" is supported. This field is required.
- Type string
-
- // Regexp allows specifying a regex pattern to match against the name
- // of the query being executed.
- Regexp string
-}
-
-// PreparedQueryDefinition defines a complete prepared query.
-type PreparedQueryDefinition struct {
- // ID is this UUID-based ID for the query, always generated by Consul.
- ID string
-
- // Name is an optional friendly name for the query supplied by the
- // user. NOTE - if this feature is used then it will reduce the security
- // of any read ACL associated with this query/service since this name
- // can be used to locate nodes with supplying any ACL.
- Name string
-
- // Session is an optional session to tie this query's lifetime to. If
- // this is omitted then the query will not expire.
- Session string
-
- // Token is the ACL token used when the query was created, and it is
- // used when a query is subsequently executed. This token, or a token
- // with management privileges, must be used to change the query later.
- Token string
-
- // Service defines a service query (leaving things open for other types
- // later).
- Service ServiceQuery
-
- // DNS has options that control how the results of this query are
- // served over DNS.
- DNS QueryDNSOptions
-
- // Template is used to pass through the arguments for creating a
- // prepared query with an attached template. If a template is given,
- // interpolations are possible in other struct fields.
- Template QueryTemplate
-}
-
-// PreparedQueryExecuteResponse has the results of executing a query.
-type PreparedQueryExecuteResponse struct {
- // Service is the service that was queried.
- Service string
-
- // Nodes has the nodes that were output by the query.
- Nodes []ServiceEntry
-
- // DNS has the options for serving these results over DNS.
- DNS QueryDNSOptions
-
- // Datacenter is the datacenter that these results came from.
- Datacenter string
-
- // Failovers is a count of how many times we had to query a remote
- // datacenter.
- Failovers int
-}
-
-// PreparedQuery can be used to query the prepared query endpoints.
-type PreparedQuery struct {
- c *Client
-}
-
-// PreparedQuery returns a handle to the prepared query endpoints.
-func (c *Client) PreparedQuery() *PreparedQuery {
- return &PreparedQuery{c}
-}
-
-// Create makes a new prepared query. The ID of the new query is returned.
-func (c *PreparedQuery) Create(query *PreparedQueryDefinition, q *WriteOptions) (string, *WriteMeta, error) {
- r := c.c.newRequest("POST", "/v1/query")
- r.setWriteOptions(q)
- r.obj = query
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return "", nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
-
- var out struct{ ID string }
- if err := decodeBody(resp, &out); err != nil {
- return "", nil, err
- }
- return out.ID, wm, nil
-}
-
-// Update makes updates to an existing prepared query.
-func (c *PreparedQuery) Update(query *PreparedQueryDefinition, q *WriteOptions) (*WriteMeta, error) {
- return c.c.write("/v1/query/"+query.ID, query, nil, q)
-}
-
-// List is used to fetch all the prepared queries (always requires a management
-// token).
-func (c *PreparedQuery) List(q *QueryOptions) ([]*PreparedQueryDefinition, *QueryMeta, error) {
- var out []*PreparedQueryDefinition
- qm, err := c.c.query("/v1/query", &out, q)
- if err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// Get is used to fetch a specific prepared query.
-func (c *PreparedQuery) Get(queryID string, q *QueryOptions) ([]*PreparedQueryDefinition, *QueryMeta, error) {
- var out []*PreparedQueryDefinition
- qm, err := c.c.query("/v1/query/"+queryID, &out, q)
- if err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
-
-// Delete is used to delete a specific prepared query.
-func (c *PreparedQuery) Delete(queryID string, q *WriteOptions) (*WriteMeta, error) {
- r := c.c.newRequest("DELETE", "/v1/query/"+queryID)
- r.setWriteOptions(q)
- rtt, resp, err := requireOK(c.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{}
- wm.RequestTime = rtt
- return wm, nil
-}
-
-// Execute is used to execute a specific prepared query. You can execute using
-// a query ID or name.
-func (c *PreparedQuery) Execute(queryIDOrName string, q *QueryOptions) (*PreparedQueryExecuteResponse, *QueryMeta, error) {
- var out *PreparedQueryExecuteResponse
- qm, err := c.c.query("/v1/query/"+queryIDOrName+"/execute", &out, q)
- if err != nil {
- return nil, nil, err
- }
- return out, qm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/raw.go b/vendor/github.com/hashicorp/consul/api/raw.go
deleted file mode 100644
index 745a208c99d..00000000000
--- a/vendor/github.com/hashicorp/consul/api/raw.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package api
-
-// Raw can be used to do raw queries against custom endpoints
-type Raw struct {
- c *Client
-}
-
-// Raw returns a handle to query endpoints
-func (c *Client) Raw() *Raw {
- return &Raw{c}
-}
-
-// Query is used to do a GET request against an endpoint
-// and deserialize the response into an interface using
-// standard Consul conventions.
-func (raw *Raw) Query(endpoint string, out interface{}, q *QueryOptions) (*QueryMeta, error) {
- return raw.c.query(endpoint, out, q)
-}
-
-// Write is used to do a PUT request against an endpoint
-// and serialize/deserialized using the standard Consul conventions.
-func (raw *Raw) Write(endpoint string, in, out interface{}, q *WriteOptions) (*WriteMeta, error) {
- return raw.c.write(endpoint, in, out, q)
-}
diff --git a/vendor/github.com/hashicorp/consul/api/semaphore.go b/vendor/github.com/hashicorp/consul/api/semaphore.go
deleted file mode 100644
index bc4f885fec0..00000000000
--- a/vendor/github.com/hashicorp/consul/api/semaphore.go
+++ /dev/null
@@ -1,514 +0,0 @@
-package api
-
-import (
- "encoding/json"
- "fmt"
- "path"
- "sync"
- "time"
-)
-
-const (
- // DefaultSemaphoreSessionName is the Session Name we assign if none is provided
- DefaultSemaphoreSessionName = "Consul API Semaphore"
-
- // DefaultSemaphoreSessionTTL is the default session TTL if no Session is provided
- // when creating a new Semaphore. This is used because we do not have another
- // other check to depend upon.
- DefaultSemaphoreSessionTTL = "15s"
-
- // DefaultSemaphoreWaitTime is how long we block for at a time to check if semaphore
- // acquisition is possible. This affects the minimum time it takes to cancel
- // a Semaphore acquisition.
- DefaultSemaphoreWaitTime = 15 * time.Second
-
- // DefaultSemaphoreKey is the key used within the prefix to
- // use for coordination between all the contenders.
- DefaultSemaphoreKey = ".lock"
-
- // SemaphoreFlagValue is a magic flag we set to indicate a key
- // is being used for a semaphore. It is used to detect a potential
- // conflict with a lock.
- SemaphoreFlagValue = 0xe0f69a2baa414de0
-)
-
-var (
- // ErrSemaphoreHeld is returned if we attempt to double lock
- ErrSemaphoreHeld = fmt.Errorf("Semaphore already held")
-
- // ErrSemaphoreNotHeld is returned if we attempt to unlock a semaphore
- // that we do not hold.
- ErrSemaphoreNotHeld = fmt.Errorf("Semaphore not held")
-
- // ErrSemaphoreInUse is returned if we attempt to destroy a semaphore
- // that is in use.
- ErrSemaphoreInUse = fmt.Errorf("Semaphore in use")
-
- // ErrSemaphoreConflict is returned if the flags on a key
- // used for a semaphore do not match expectation
- ErrSemaphoreConflict = fmt.Errorf("Existing key does not match semaphore use")
-)
-
-// Semaphore is used to implement a distributed semaphore
-// using the Consul KV primitives.
-type Semaphore struct {
- c *Client
- opts *SemaphoreOptions
-
- isHeld bool
- sessionRenew chan struct{}
- lockSession string
- l sync.Mutex
-}
-
-// SemaphoreOptions is used to parameterize the Semaphore
-type SemaphoreOptions struct {
- Prefix string // Must be set and have write permissions
- Limit int // Must be set, and be positive
- Value []byte // Optional, value to associate with the contender entry
- Session string // Optional, created if not specified
- SessionName string // Optional, defaults to DefaultLockSessionName
- SessionTTL string // Optional, defaults to DefaultLockSessionTTL
- MonitorRetries int // Optional, defaults to 0 which means no retries
- MonitorRetryTime time.Duration // Optional, defaults to DefaultMonitorRetryTime
- SemaphoreWaitTime time.Duration // Optional, defaults to DefaultSemaphoreWaitTime
- SemaphoreTryOnce bool // Optional, defaults to false which means try forever
-}
-
-// semaphoreLock is written under the DefaultSemaphoreKey and
-// is used to coordinate between all the contenders.
-type semaphoreLock struct {
- // Limit is the integer limit of holders. This is used to
- // verify that all the holders agree on the value.
- Limit int
-
- // Holders is a list of all the semaphore holders.
- // It maps the session ID to true. It is used as a set effectively.
- Holders map[string]bool
-}
-
-// SemaphorePrefix is used to created a Semaphore which will operate
-// at the given KV prefix and uses the given limit for the semaphore.
-// The prefix must have write privileges, and the limit must be agreed
-// upon by all contenders.
-func (c *Client) SemaphorePrefix(prefix string, limit int) (*Semaphore, error) {
- opts := &SemaphoreOptions{
- Prefix: prefix,
- Limit: limit,
- }
- return c.SemaphoreOpts(opts)
-}
-
-// SemaphoreOpts is used to create a Semaphore with the given options.
-// The prefix must have write privileges, and the limit must be agreed
-// upon by all contenders. If a Session is not provided, one will be created.
-func (c *Client) SemaphoreOpts(opts *SemaphoreOptions) (*Semaphore, error) {
- if opts.Prefix == "" {
- return nil, fmt.Errorf("missing prefix")
- }
- if opts.Limit <= 0 {
- return nil, fmt.Errorf("semaphore limit must be positive")
- }
- if opts.SessionName == "" {
- opts.SessionName = DefaultSemaphoreSessionName
- }
- if opts.SessionTTL == "" {
- opts.SessionTTL = DefaultSemaphoreSessionTTL
- } else {
- if _, err := time.ParseDuration(opts.SessionTTL); err != nil {
- return nil, fmt.Errorf("invalid SessionTTL: %v", err)
- }
- }
- if opts.MonitorRetryTime == 0 {
- opts.MonitorRetryTime = DefaultMonitorRetryTime
- }
- if opts.SemaphoreWaitTime == 0 {
- opts.SemaphoreWaitTime = DefaultSemaphoreWaitTime
- }
- s := &Semaphore{
- c: c,
- opts: opts,
- }
- return s, nil
-}
-
-// Acquire attempts to reserve a slot in the semaphore, blocking until
-// success, interrupted via the stopCh or an error is encountered.
-// Providing a non-nil stopCh can be used to abort the attempt.
-// On success, a channel is returned that represents our slot.
-// This channel could be closed at any time due to session invalidation,
-// communication errors, operator intervention, etc. It is NOT safe to
-// assume that the slot is held until Release() unless the Session is specifically
-// created without any associated health checks. By default Consul sessions
-// prefer liveness over safety and an application must be able to handle
-// the session being lost.
-func (s *Semaphore) Acquire(stopCh <-chan struct{}) (<-chan struct{}, error) {
- // Hold the lock as we try to acquire
- s.l.Lock()
- defer s.l.Unlock()
-
- // Check if we already hold the semaphore
- if s.isHeld {
- return nil, ErrSemaphoreHeld
- }
-
- // Check if we need to create a session first
- s.lockSession = s.opts.Session
- if s.lockSession == "" {
- sess, err := s.createSession()
- if err != nil {
- return nil, fmt.Errorf("failed to create session: %v", err)
- }
-
- s.sessionRenew = make(chan struct{})
- s.lockSession = sess
- session := s.c.Session()
- go session.RenewPeriodic(s.opts.SessionTTL, sess, nil, s.sessionRenew)
-
- // If we fail to acquire the lock, cleanup the session
- defer func() {
- if !s.isHeld {
- close(s.sessionRenew)
- s.sessionRenew = nil
- }
- }()
- }
-
- // Create the contender entry
- kv := s.c.KV()
- made, _, err := kv.Acquire(s.contenderEntry(s.lockSession), nil)
- if err != nil || !made {
- return nil, fmt.Errorf("failed to make contender entry: %v", err)
- }
-
- // Setup the query options
- qOpts := &QueryOptions{
- WaitTime: s.opts.SemaphoreWaitTime,
- }
-
- start := time.Now()
- attempts := 0
-WAIT:
- // Check if we should quit
- select {
- case <-stopCh:
- return nil, nil
- default:
- }
-
- // Handle the one-shot mode.
- if s.opts.SemaphoreTryOnce && attempts > 0 {
- elapsed := time.Since(start)
- if elapsed > s.opts.SemaphoreWaitTime {
- return nil, nil
- }
-
- // Query wait time should not exceed the semaphore wait time
- qOpts.WaitTime = s.opts.SemaphoreWaitTime - elapsed
- }
- attempts++
-
- // Read the prefix
- pairs, meta, err := kv.List(s.opts.Prefix, qOpts)
- if err != nil {
- return nil, fmt.Errorf("failed to read prefix: %v", err)
- }
-
- // Decode the lock
- lockPair := s.findLock(pairs)
- if lockPair.Flags != SemaphoreFlagValue {
- return nil, ErrSemaphoreConflict
- }
- lock, err := s.decodeLock(lockPair)
- if err != nil {
- return nil, err
- }
-
- // Verify we agree with the limit
- if lock.Limit != s.opts.Limit {
- return nil, fmt.Errorf("semaphore limit conflict (lock: %d, local: %d)",
- lock.Limit, s.opts.Limit)
- }
-
- // Prune the dead holders
- s.pruneDeadHolders(lock, pairs)
-
- // Check if the lock is held
- if len(lock.Holders) >= lock.Limit {
- qOpts.WaitIndex = meta.LastIndex
- goto WAIT
- }
-
- // Create a new lock with us as a holder
- lock.Holders[s.lockSession] = true
- newLock, err := s.encodeLock(lock, lockPair.ModifyIndex)
- if err != nil {
- return nil, err
- }
-
- // Attempt the acquisition
- didSet, _, err := kv.CAS(newLock, nil)
- if err != nil {
- return nil, fmt.Errorf("failed to update lock: %v", err)
- }
- if !didSet {
- // Update failed, could have been a race with another contender,
- // retry the operation
- goto WAIT
- }
-
- // Watch to ensure we maintain ownership of the slot
- lockCh := make(chan struct{})
- go s.monitorLock(s.lockSession, lockCh)
-
- // Set that we own the lock
- s.isHeld = true
-
- // Acquired! All done
- return lockCh, nil
-}
-
-// Release is used to voluntarily give up our semaphore slot. It is
-// an error to call this if the semaphore has not been acquired.
-func (s *Semaphore) Release() error {
- // Hold the lock as we try to release
- s.l.Lock()
- defer s.l.Unlock()
-
- // Ensure the lock is actually held
- if !s.isHeld {
- return ErrSemaphoreNotHeld
- }
-
- // Set that we no longer own the lock
- s.isHeld = false
-
- // Stop the session renew
- if s.sessionRenew != nil {
- defer func() {
- close(s.sessionRenew)
- s.sessionRenew = nil
- }()
- }
-
- // Get and clear the lock session
- lockSession := s.lockSession
- s.lockSession = ""
-
- // Remove ourselves as a lock holder
- kv := s.c.KV()
- key := path.Join(s.opts.Prefix, DefaultSemaphoreKey)
-READ:
- pair, _, err := kv.Get(key, nil)
- if err != nil {
- return err
- }
- if pair == nil {
- pair = &KVPair{}
- }
- lock, err := s.decodeLock(pair)
- if err != nil {
- return err
- }
-
- // Create a new lock without us as a holder
- if _, ok := lock.Holders[lockSession]; ok {
- delete(lock.Holders, lockSession)
- newLock, err := s.encodeLock(lock, pair.ModifyIndex)
- if err != nil {
- return err
- }
-
- // Swap the locks
- didSet, _, err := kv.CAS(newLock, nil)
- if err != nil {
- return fmt.Errorf("failed to update lock: %v", err)
- }
- if !didSet {
- goto READ
- }
- }
-
- // Destroy the contender entry
- contenderKey := path.Join(s.opts.Prefix, lockSession)
- if _, err := kv.Delete(contenderKey, nil); err != nil {
- return err
- }
- return nil
-}
-
-// Destroy is used to cleanup the semaphore entry. It is not necessary
-// to invoke. It will fail if the semaphore is in use.
-func (s *Semaphore) Destroy() error {
- // Hold the lock as we try to acquire
- s.l.Lock()
- defer s.l.Unlock()
-
- // Check if we already hold the semaphore
- if s.isHeld {
- return ErrSemaphoreHeld
- }
-
- // List for the semaphore
- kv := s.c.KV()
- pairs, _, err := kv.List(s.opts.Prefix, nil)
- if err != nil {
- return fmt.Errorf("failed to read prefix: %v", err)
- }
-
- // Find the lock pair, bail if it doesn't exist
- lockPair := s.findLock(pairs)
- if lockPair.ModifyIndex == 0 {
- return nil
- }
- if lockPair.Flags != SemaphoreFlagValue {
- return ErrSemaphoreConflict
- }
-
- // Decode the lock
- lock, err := s.decodeLock(lockPair)
- if err != nil {
- return err
- }
-
- // Prune the dead holders
- s.pruneDeadHolders(lock, pairs)
-
- // Check if there are any holders
- if len(lock.Holders) > 0 {
- return ErrSemaphoreInUse
- }
-
- // Attempt the delete
- didRemove, _, err := kv.DeleteCAS(lockPair, nil)
- if err != nil {
- return fmt.Errorf("failed to remove semaphore: %v", err)
- }
- if !didRemove {
- return ErrSemaphoreInUse
- }
- return nil
-}
-
-// createSession is used to create a new managed session
-func (s *Semaphore) createSession() (string, error) {
- session := s.c.Session()
- se := &SessionEntry{
- Name: s.opts.SessionName,
- TTL: s.opts.SessionTTL,
- Behavior: SessionBehaviorDelete,
- }
- id, _, err := session.Create(se, nil)
- if err != nil {
- return "", err
- }
- return id, nil
-}
-
-// contenderEntry returns a formatted KVPair for the contender
-func (s *Semaphore) contenderEntry(session string) *KVPair {
- return &KVPair{
- Key: path.Join(s.opts.Prefix, session),
- Value: s.opts.Value,
- Session: session,
- Flags: SemaphoreFlagValue,
- }
-}
-
-// findLock is used to find the KV Pair which is used for coordination
-func (s *Semaphore) findLock(pairs KVPairs) *KVPair {
- key := path.Join(s.opts.Prefix, DefaultSemaphoreKey)
- for _, pair := range pairs {
- if pair.Key == key {
- return pair
- }
- }
- return &KVPair{Flags: SemaphoreFlagValue}
-}
-
-// decodeLock is used to decode a semaphoreLock from an
-// entry in Consul
-func (s *Semaphore) decodeLock(pair *KVPair) (*semaphoreLock, error) {
- // Handle if there is no lock
- if pair == nil || pair.Value == nil {
- return &semaphoreLock{
- Limit: s.opts.Limit,
- Holders: make(map[string]bool),
- }, nil
- }
-
- l := &semaphoreLock{}
- if err := json.Unmarshal(pair.Value, l); err != nil {
- return nil, fmt.Errorf("lock decoding failed: %v", err)
- }
- return l, nil
-}
-
-// encodeLock is used to encode a semaphoreLock into a KVPair
-// that can be PUT
-func (s *Semaphore) encodeLock(l *semaphoreLock, oldIndex uint64) (*KVPair, error) {
- enc, err := json.Marshal(l)
- if err != nil {
- return nil, fmt.Errorf("lock encoding failed: %v", err)
- }
- pair := &KVPair{
- Key: path.Join(s.opts.Prefix, DefaultSemaphoreKey),
- Value: enc,
- Flags: SemaphoreFlagValue,
- ModifyIndex: oldIndex,
- }
- return pair, nil
-}
-
-// pruneDeadHolders is used to remove all the dead lock holders
-func (s *Semaphore) pruneDeadHolders(lock *semaphoreLock, pairs KVPairs) {
- // Gather all the live holders
- alive := make(map[string]struct{}, len(pairs))
- for _, pair := range pairs {
- if pair.Session != "" {
- alive[pair.Session] = struct{}{}
- }
- }
-
- // Remove any holders that are dead
- for holder := range lock.Holders {
- if _, ok := alive[holder]; !ok {
- delete(lock.Holders, holder)
- }
- }
-}
-
-// monitorLock is a long running routine to monitor a semaphore ownership
-// It closes the stopCh if we lose our slot.
-func (s *Semaphore) monitorLock(session string, stopCh chan struct{}) {
- defer close(stopCh)
- kv := s.c.KV()
- opts := &QueryOptions{RequireConsistent: true}
-WAIT:
- retries := s.opts.MonitorRetries
-RETRY:
- pairs, meta, err := kv.List(s.opts.Prefix, opts)
- if err != nil {
- // If configured we can try to ride out a brief Consul unavailability
- // by doing retries. Note that we have to attempt the retry in a non-
- // blocking fashion so that we have a clean place to reset the retry
- // counter if service is restored.
- if retries > 0 && IsRetryableError(err) {
- time.Sleep(s.opts.MonitorRetryTime)
- retries--
- opts.WaitIndex = 0
- goto RETRY
- }
- return
- }
- lockPair := s.findLock(pairs)
- lock, err := s.decodeLock(lockPair)
- if err != nil {
- return
- }
- s.pruneDeadHolders(lock, pairs)
- if _, ok := lock.Holders[session]; ok {
- opts.WaitIndex = meta.LastIndex
- goto WAIT
- }
-}
diff --git a/vendor/github.com/hashicorp/consul/api/session.go b/vendor/github.com/hashicorp/consul/api/session.go
deleted file mode 100644
index 1613f11a60c..00000000000
--- a/vendor/github.com/hashicorp/consul/api/session.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package api
-
-import (
- "errors"
- "fmt"
- "time"
-)
-
-const (
- // SessionBehaviorRelease is the default behavior and causes
- // all associated locks to be released on session invalidation.
- SessionBehaviorRelease = "release"
-
- // SessionBehaviorDelete is new in Consul 0.5 and changes the
- // behavior to delete all associated locks on session invalidation.
- // It can be used in a way similar to Ephemeral Nodes in ZooKeeper.
- SessionBehaviorDelete = "delete"
-)
-
-var ErrSessionExpired = errors.New("session expired")
-
-// SessionEntry represents a session in consul
-type SessionEntry struct {
- CreateIndex uint64
- ID string
- Name string
- Node string
- Checks []string
- LockDelay time.Duration
- Behavior string
- TTL string
-}
-
-// Session can be used to query the Session endpoints
-type Session struct {
- c *Client
-}
-
-// Session returns a handle to the session endpoints
-func (c *Client) Session() *Session {
- return &Session{c}
-}
-
-// CreateNoChecks is like Create but is used specifically to create
-// a session with no associated health checks.
-func (s *Session) CreateNoChecks(se *SessionEntry, q *WriteOptions) (string, *WriteMeta, error) {
- body := make(map[string]interface{})
- body["Checks"] = []string{}
- if se != nil {
- if se.Name != "" {
- body["Name"] = se.Name
- }
- if se.Node != "" {
- body["Node"] = se.Node
- }
- if se.LockDelay != 0 {
- body["LockDelay"] = durToMsec(se.LockDelay)
- }
- if se.Behavior != "" {
- body["Behavior"] = se.Behavior
- }
- if se.TTL != "" {
- body["TTL"] = se.TTL
- }
- }
- return s.create(body, q)
-
-}
-
-// Create makes a new session. Providing a session entry can
-// customize the session. It can also be nil to use defaults.
-func (s *Session) Create(se *SessionEntry, q *WriteOptions) (string, *WriteMeta, error) {
- var obj interface{}
- if se != nil {
- body := make(map[string]interface{})
- obj = body
- if se.Name != "" {
- body["Name"] = se.Name
- }
- if se.Node != "" {
- body["Node"] = se.Node
- }
- if se.LockDelay != 0 {
- body["LockDelay"] = durToMsec(se.LockDelay)
- }
- if len(se.Checks) > 0 {
- body["Checks"] = se.Checks
- }
- if se.Behavior != "" {
- body["Behavior"] = se.Behavior
- }
- if se.TTL != "" {
- body["TTL"] = se.TTL
- }
- }
- return s.create(obj, q)
-}
-
-func (s *Session) create(obj interface{}, q *WriteOptions) (string, *WriteMeta, error) {
- var out struct{ ID string }
- wm, err := s.c.write("/v1/session/create", obj, &out, q)
- if err != nil {
- return "", nil, err
- }
- return out.ID, wm, nil
-}
-
-// Destroy invalidates a given session
-func (s *Session) Destroy(id string, q *WriteOptions) (*WriteMeta, error) {
- wm, err := s.c.write("/v1/session/destroy/"+id, nil, nil, q)
- if err != nil {
- return nil, err
- }
- return wm, nil
-}
-
-// Renew renews the TTL on a given session
-func (s *Session) Renew(id string, q *WriteOptions) (*SessionEntry, *WriteMeta, error) {
- r := s.c.newRequest("PUT", "/v1/session/renew/"+id)
- r.setWriteOptions(q)
- rtt, resp, err := s.c.doRequest(r)
- if err != nil {
- return nil, nil, err
- }
- defer resp.Body.Close()
-
- wm := &WriteMeta{RequestTime: rtt}
-
- if resp.StatusCode == 404 {
- return nil, wm, nil
- } else if resp.StatusCode != 200 {
- return nil, nil, fmt.Errorf("Unexpected response code: %d", resp.StatusCode)
- }
-
- var entries []*SessionEntry
- if err := decodeBody(resp, &entries); err != nil {
- return nil, nil, fmt.Errorf("Failed to read response: %v", err)
- }
- if len(entries) > 0 {
- return entries[0], wm, nil
- }
- return nil, wm, nil
-}
-
-// RenewPeriodic is used to periodically invoke Session.Renew on a
-// session until a doneCh is closed. This is meant to be used in a long running
-// goroutine to ensure a session stays valid.
-func (s *Session) RenewPeriodic(initialTTL string, id string, q *WriteOptions, doneCh <-chan struct{}) error {
- ctx := q.Context()
-
- ttl, err := time.ParseDuration(initialTTL)
- if err != nil {
- return err
- }
-
- waitDur := ttl / 2
- lastRenewTime := time.Now()
- var lastErr error
- for {
- if time.Since(lastRenewTime) > ttl {
- return lastErr
- }
- select {
- case <-time.After(waitDur):
- entry, _, err := s.Renew(id, q)
- if err != nil {
- waitDur = time.Second
- lastErr = err
- continue
- }
- if entry == nil {
- return ErrSessionExpired
- }
-
- // Handle the server updating the TTL
- ttl, _ = time.ParseDuration(entry.TTL)
- waitDur = ttl / 2
- lastRenewTime = time.Now()
-
- case <-doneCh:
- // Attempt a session destroy
- s.Destroy(id, q)
- return nil
-
- case <-ctx.Done():
- // Bail immediately since attempting the destroy would
- // use the canceled context in q, which would just bail.
- return ctx.Err()
- }
- }
-}
-
-// Info looks up a single session
-func (s *Session) Info(id string, q *QueryOptions) (*SessionEntry, *QueryMeta, error) {
- var entries []*SessionEntry
- qm, err := s.c.query("/v1/session/info/"+id, &entries, q)
- if err != nil {
- return nil, nil, err
- }
- if len(entries) > 0 {
- return entries[0], qm, nil
- }
- return nil, qm, nil
-}
-
-// List gets sessions for a node
-func (s *Session) Node(node string, q *QueryOptions) ([]*SessionEntry, *QueryMeta, error) {
- var entries []*SessionEntry
- qm, err := s.c.query("/v1/session/node/"+node, &entries, q)
- if err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
-
-// List gets all active sessions
-func (s *Session) List(q *QueryOptions) ([]*SessionEntry, *QueryMeta, error) {
- var entries []*SessionEntry
- qm, err := s.c.query("/v1/session/list", &entries, q)
- if err != nil {
- return nil, nil, err
- }
- return entries, qm, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/snapshot.go b/vendor/github.com/hashicorp/consul/api/snapshot.go
deleted file mode 100644
index e902377dd5c..00000000000
--- a/vendor/github.com/hashicorp/consul/api/snapshot.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package api
-
-import (
- "io"
-)
-
-// Snapshot can be used to query the /v1/snapshot endpoint to take snapshots of
-// Consul's internal state and restore snapshots for disaster recovery.
-type Snapshot struct {
- c *Client
-}
-
-// Snapshot returns a handle that exposes the snapshot endpoints.
-func (c *Client) Snapshot() *Snapshot {
- return &Snapshot{c}
-}
-
-// Save requests a new snapshot and provides an io.ReadCloser with the snapshot
-// data to save. If this doesn't return an error, then it's the responsibility
-// of the caller to close it. Only a subset of the QueryOptions are supported:
-// Datacenter, AllowStale, and Token.
-func (s *Snapshot) Save(q *QueryOptions) (io.ReadCloser, *QueryMeta, error) {
- r := s.c.newRequest("GET", "/v1/snapshot")
- r.setQueryOptions(q)
-
- rtt, resp, err := requireOK(s.c.doRequest(r))
- if err != nil {
- return nil, nil, err
- }
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
- return resp.Body, qm, nil
-}
-
-// Restore streams in an existing snapshot and attempts to restore it.
-func (s *Snapshot) Restore(q *WriteOptions, in io.Reader) error {
- r := s.c.newRequest("PUT", "/v1/snapshot")
- r.body = in
- r.setWriteOptions(q)
- _, _, err := requireOK(s.c.doRequest(r))
- if err != nil {
- return err
- }
- return nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/status.go b/vendor/github.com/hashicorp/consul/api/status.go
deleted file mode 100644
index 74ef61a678f..00000000000
--- a/vendor/github.com/hashicorp/consul/api/status.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package api
-
-// Status can be used to query the Status endpoints
-type Status struct {
- c *Client
-}
-
-// Status returns a handle to the status endpoints
-func (c *Client) Status() *Status {
- return &Status{c}
-}
-
-// Leader is used to query for a known leader
-func (s *Status) Leader() (string, error) {
- r := s.c.newRequest("GET", "/v1/status/leader")
- _, resp, err := requireOK(s.c.doRequest(r))
- if err != nil {
- return "", err
- }
- defer resp.Body.Close()
-
- var leader string
- if err := decodeBody(resp, &leader); err != nil {
- return "", err
- }
- return leader, nil
-}
-
-// Peers is used to query for a known raft peers
-func (s *Status) Peers() ([]string, error) {
- r := s.c.newRequest("GET", "/v1/status/peers")
- _, resp, err := requireOK(s.c.doRequest(r))
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var peers []string
- if err := decodeBody(resp, &peers); err != nil {
- return nil, err
- }
- return peers, nil
-}
diff --git a/vendor/github.com/hashicorp/consul/api/txn.go b/vendor/github.com/hashicorp/consul/api/txn.go
deleted file mode 100644
index 65d7a16ea04..00000000000
--- a/vendor/github.com/hashicorp/consul/api/txn.go
+++ /dev/null
@@ -1,230 +0,0 @@
-package api
-
-import (
- "bytes"
- "fmt"
- "io"
- "net/http"
-)
-
-// Txn is used to manipulate the Txn API
-type Txn struct {
- c *Client
-}
-
-// Txn is used to return a handle to the K/V apis
-func (c *Client) Txn() *Txn {
- return &Txn{c}
-}
-
-// TxnOp is the internal format we send to Consul. Currently only K/V and
-// check operations are supported.
-type TxnOp struct {
- KV *KVTxnOp
- Node *NodeTxnOp
- Service *ServiceTxnOp
- Check *CheckTxnOp
-}
-
-// TxnOps is a list of transaction operations.
-type TxnOps []*TxnOp
-
-// TxnResult is the internal format we receive from Consul.
-type TxnResult struct {
- KV *KVPair
- Node *Node
- Service *CatalogService
- Check *HealthCheck
-}
-
-// TxnResults is a list of TxnResult objects.
-type TxnResults []*TxnResult
-
-// TxnError is used to return information about an operation in a transaction.
-type TxnError struct {
- OpIndex int
- What string
-}
-
-// TxnErrors is a list of TxnError objects.
-type TxnErrors []*TxnError
-
-// TxnResponse is the internal format we receive from Consul.
-type TxnResponse struct {
- Results TxnResults
- Errors TxnErrors
-}
-
-// KVOp constants give possible operations available in a transaction.
-type KVOp string
-
-const (
- KVSet KVOp = "set"
- KVDelete KVOp = "delete"
- KVDeleteCAS KVOp = "delete-cas"
- KVDeleteTree KVOp = "delete-tree"
- KVCAS KVOp = "cas"
- KVLock KVOp = "lock"
- KVUnlock KVOp = "unlock"
- KVGet KVOp = "get"
- KVGetTree KVOp = "get-tree"
- KVCheckSession KVOp = "check-session"
- KVCheckIndex KVOp = "check-index"
- KVCheckNotExists KVOp = "check-not-exists"
-)
-
-// KVTxnOp defines a single operation inside a transaction.
-type KVTxnOp struct {
- Verb KVOp
- Key string
- Value []byte
- Flags uint64
- Index uint64
- Session string
-}
-
-// KVTxnOps defines a set of operations to be performed inside a single
-// transaction.
-type KVTxnOps []*KVTxnOp
-
-// KVTxnResponse has the outcome of a transaction.
-type KVTxnResponse struct {
- Results []*KVPair
- Errors TxnErrors
-}
-
-// NodeOp constants give possible operations available in a transaction.
-type NodeOp string
-
-const (
- NodeGet NodeOp = "get"
- NodeSet NodeOp = "set"
- NodeCAS NodeOp = "cas"
- NodeDelete NodeOp = "delete"
- NodeDeleteCAS NodeOp = "delete-cas"
-)
-
-// NodeTxnOp defines a single operation inside a transaction.
-type NodeTxnOp struct {
- Verb NodeOp
- Node Node
-}
-
-// ServiceOp constants give possible operations available in a transaction.
-type ServiceOp string
-
-const (
- ServiceGet ServiceOp = "get"
- ServiceSet ServiceOp = "set"
- ServiceCAS ServiceOp = "cas"
- ServiceDelete ServiceOp = "delete"
- ServiceDeleteCAS ServiceOp = "delete-cas"
-)
-
-// ServiceTxnOp defines a single operation inside a transaction.
-type ServiceTxnOp struct {
- Verb ServiceOp
- Node string
- Service AgentService
-}
-
-// CheckOp constants give possible operations available in a transaction.
-type CheckOp string
-
-const (
- CheckGet CheckOp = "get"
- CheckSet CheckOp = "set"
- CheckCAS CheckOp = "cas"
- CheckDelete CheckOp = "delete"
- CheckDeleteCAS CheckOp = "delete-cas"
-)
-
-// CheckTxnOp defines a single operation inside a transaction.
-type CheckTxnOp struct {
- Verb CheckOp
- Check HealthCheck
-}
-
-// Txn is used to apply multiple Consul operations in a single, atomic transaction.
-//
-// Note that Go will perform the required base64 encoding on the values
-// automatically because the type is a byte slice. Transactions are defined as a
-// list of operations to perform, using the different fields in the TxnOp structure
-// to define operations. If any operation fails, none of the changes are applied
-// to the state store.
-//
-// Even though this is generally a write operation, we take a QueryOptions input
-// and return a QueryMeta output. If the transaction contains only read ops, then
-// Consul will fast-path it to a different endpoint internally which supports
-// consistency controls, but not blocking. If there are write operations then
-// the request will always be routed through raft and any consistency settings
-// will be ignored.
-//
-// Here's an example:
-//
-// ops := KVTxnOps{
-// &KVTxnOp{
-// Verb: KVLock,
-// Key: "test/lock",
-// Session: "adf4238a-882b-9ddc-4a9d-5b6758e4159e",
-// Value: []byte("hello"),
-// },
-// &KVTxnOp{
-// Verb: KVGet,
-// Key: "another/key",
-// },
-// &CheckTxnOp{
-// Verb: CheckSet,
-// HealthCheck: HealthCheck{
-// Node: "foo",
-// CheckID: "redis:a",
-// Name: "Redis Health Check",
-// Status: "passing",
-// },
-// }
-// }
-// ok, response, _, err := kv.Txn(&ops, nil)
-//
-// If there is a problem making the transaction request then an error will be
-// returned. Otherwise, the ok value will be true if the transaction succeeded
-// or false if it was rolled back. The response is a structured return value which
-// will have the outcome of the transaction. Its Results member will have entries
-// for each operation. For KV operations, Deleted keys will have a nil entry in the
-// results, and to save space, the Value of each key in the Results will be nil
-// unless the operation is a KVGet. If the transaction was rolled back, the Errors
-// member will have entries referencing the index of the operation that failed
-// along with an error message.
-func (t *Txn) Txn(txn TxnOps, q *QueryOptions) (bool, *TxnResponse, *QueryMeta, error) {
- return t.c.txn(txn, q)
-}
-
-func (c *Client) txn(txn TxnOps, q *QueryOptions) (bool, *TxnResponse, *QueryMeta, error) {
- r := c.newRequest("PUT", "/v1/txn")
- r.setQueryOptions(q)
-
- r.obj = txn
- rtt, resp, err := c.doRequest(r)
- if err != nil {
- return false, nil, nil, err
- }
- defer resp.Body.Close()
-
- qm := &QueryMeta{}
- parseQueryMeta(resp, qm)
- qm.RequestTime = rtt
-
- if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusConflict {
- var txnResp TxnResponse
- if err := decodeBody(resp, &txnResp); err != nil {
- return false, nil, nil, err
- }
-
- return resp.StatusCode == http.StatusOK, &txnResp, qm, nil
- }
-
- var buf bytes.Buffer
- if _, err := io.Copy(&buf, resp.Body); err != nil {
- return false, nil, nil, fmt.Errorf("Failed to read response: %v", err)
- }
- return false, nil, nil, fmt.Errorf("Failed request: %s", buf.String())
-}
diff --git a/vendor/github.com/hashicorp/errwrap/LICENSE b/vendor/github.com/hashicorp/errwrap/LICENSE
deleted file mode 100644
index c33dcc7c928..00000000000
--- a/vendor/github.com/hashicorp/errwrap/LICENSE
+++ /dev/null
@@ -1,354 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. “Contributorâ€
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. “Contributor Versionâ€
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor’s Contribution.
-
-1.3. “Contributionâ€
-
- means Covered Software of a particular Contributor.
-
-1.4. “Covered Softwareâ€
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. “Incompatible With Secondary Licensesâ€
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of version
- 1.1 or earlier of the License, but not also under the terms of a
- Secondary License.
-
-1.6. “Executable Formâ€
-
- means any form of the work other than Source Code Form.
-
-1.7. “Larger Workâ€
-
- means a work that combines Covered Software with other material, in a separate
- file or files, that is not Covered Software.
-
-1.8. “Licenseâ€
-
- means this document.
-
-1.9. “Licensableâ€
-
- means having the right to grant, to the maximum extent possible, whether at the
- time of the initial grant or subsequently, any and all of the rights conveyed by
- this License.
-
-1.10. “Modificationsâ€
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to, deletion
- from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. “Patent Claims†of a Contributor
-
- means any patent claim(s), including without limitation, method, process,
- and apparatus claims, in any patent Licensable by such Contributor that
- would be infringed, but for the grant of the License, by the making,
- using, selling, offering for sale, having made, import, or transfer of
- either its Contributions or its Contributor Version.
-
-1.12. “Secondary Licenseâ€
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. “Source Code Formâ€
-
- means the form of the work preferred for making modifications.
-
-1.14. “You†(or “Yourâ€)
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, “You†includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, “control†means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or as
- part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its Contributions
- or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution become
- effective for each Contribution on the date the Contributor first distributes
- such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under this
- License. No additional rights or licenses will be implied from the distribution
- or licensing of Covered Software under this License. Notwithstanding Section
- 2.1(b) above, no patent license is granted by a Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party’s
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of its
- Contributions.
-
- This License does not grant any rights in the trademarks, service marks, or
- logos of any Contributor (except as may be necessary to comply with the
- notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this License
- (see Section 10.2) or under the terms of a Secondary License (if permitted
- under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its Contributions
- are its original creation(s) or it has sufficient rights to grant the
- rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under applicable
- copyright doctrines of fair use, fair dealing, or other equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under the
- terms of this License. You must inform recipients that the Source Code Form
- of the Covered Software is governed by the terms of this License, and how
- they can obtain a copy of this License. You may not attempt to alter or
- restrict the recipients’ rights in the Source Code Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this License,
- or sublicense it under different terms, provided that the license for
- the Executable Form does not attempt to limit or alter the recipients’
- rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for the
- Covered Software. If the Larger Work is a combination of Covered Software
- with a work governed by one or more Secondary Licenses, and the Covered
- Software is not Incompatible With Secondary Licenses, this License permits
- You to additionally distribute such Covered Software under the terms of
- such Secondary License(s), so that the recipient of the Larger Work may, at
- their option, further distribute the Covered Software under the terms of
- either this License or such Secondary License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices (including
- copyright notices, patent notices, disclaimers of warranty, or limitations
- of liability) contained within the Source Code Form of the Covered
- Software, except that You may alter any license notices to the extent
- required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on behalf
- of any Contributor. You must make it absolutely clear that any such
- warranty, support, indemnity, or liability obligation is offered by You
- alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute, judicial
- order, or regulation then You must: (a) comply with the terms of this License
- to the maximum extent possible; and (b) describe the limitations and the code
- they affect. Such description must be placed in a text file included with all
- distributions of the Covered Software under this License. Except to the
- extent prohibited by statute or regulation, such description must be
- sufficiently detailed for a recipient of ordinary skill to be able to
- understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing basis,
- if such Contributor fails to notify You of the non-compliance by some
- reasonable means prior to 60 days after You have come back into compliance.
- Moreover, Your grants from a particular Contributor are reinstated on an
- ongoing basis if such Contributor notifies You of the non-compliance by
- some reasonable means, this is the first time You have received notice of
- non-compliance with this License from such Contributor, and You become
- compliant prior to 30 days after Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions, counter-claims,
- and cross-claims) alleging that a Contributor Version directly or
- indirectly infringes any patent, then the rights granted to You by any and
- all Contributors for the Covered Software under Section 2.1 of this License
- shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an “as is†basis, without
- warranty of any kind, either expressed, implied, or statutory, including,
- without limitation, warranties that the Covered Software is free of defects,
- merchantable, fit for a particular purpose or non-infringing. The entire
- risk as to the quality and performance of the Covered Software is with You.
- Should any Covered Software prove defective in any respect, You (not any
- Contributor) assume the cost of any necessary servicing, repair, or
- correction. This disclaimer of warranty constitutes an essential part of this
- License. No use of any Covered Software is authorized under this License
- except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from such
- party’s negligence to the extent applicable law prohibits such limitation.
- Some jurisdictions do not allow the exclusion or limitation of incidental or
- consequential damages, so this exclusion and limitation may not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts of
- a jurisdiction where the defendant maintains its principal place of business
- and such litigation shall be governed by laws of that jurisdiction, without
- reference to its conflict-of-law provisions. Nothing in this Section shall
- prevent a party’s ability to bring cross-claims or counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject matter
- hereof. If any provision of this License is held to be unenforceable, such
- provision shall be reformed only to the extent necessary to make it
- enforceable. Any law or regulation which provides that the language of a
- contract shall be construed against the drafter shall not be used to construe
- this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version of
- the License under which You originally received the Covered Software, or
- under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a modified
- version of this License if you rename the license and remove any
- references to the name of the license steward (except to note that such
- modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
- If You choose to distribute Source Code Form that is Incompatible With
- Secondary Licenses under the terms of this version of the License, the
- notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file, then
-You may include the notice in a location (such as a LICENSE file in a relevant
-directory) where a recipient would be likely to look for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - “Incompatible With Secondary Licenses†Notice
-
- This Source Code Form is “Incompatible
- With Secondary Licensesâ€, as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/errwrap/README.md b/vendor/github.com/hashicorp/errwrap/README.md
deleted file mode 100644
index 444df08f8e7..00000000000
--- a/vendor/github.com/hashicorp/errwrap/README.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# errwrap
-
-`errwrap` is a package for Go that formalizes the pattern of wrapping errors
-and checking if an error contains another error.
-
-There is a common pattern in Go of taking a returned `error` value and
-then wrapping it (such as with `fmt.Errorf`) before returning it. The problem
-with this pattern is that you completely lose the original `error` structure.
-
-Arguably the _correct_ approach is that you should make a custom structure
-implementing the `error` interface, and have the original error as a field
-on that structure, such [as this example](http://golang.org/pkg/os/#PathError).
-This is a good approach, but you have to know the entire chain of possible
-rewrapping that happens, when you might just care about one.
-
-`errwrap` formalizes this pattern (it doesn't matter what approach you use
-above) by giving a single interface for wrapping errors, checking if a specific
-error is wrapped, and extracting that error.
-
-## Installation and Docs
-
-Install using `go get github.com/hashicorp/errwrap`.
-
-Full documentation is available at
-http://godoc.org/github.com/hashicorp/errwrap
-
-## Usage
-
-#### Basic Usage
-
-Below is a very basic example of its usage:
-
-```go
-// A function that always returns an error, but wraps it, like a real
-// function might.
-func tryOpen() error {
- _, err := os.Open("/i/dont/exist")
- if err != nil {
- return errwrap.Wrapf("Doesn't exist: {{err}}", err)
- }
-
- return nil
-}
-
-func main() {
- err := tryOpen()
-
- // We can use the Contains helpers to check if an error contains
- // another error. It is safe to do this with a nil error, or with
- // an error that doesn't even use the errwrap package.
- if errwrap.Contains(err, "does not exist") {
- // Do something
- }
- if errwrap.ContainsType(err, new(os.PathError)) {
- // Do something
- }
-
- // Or we can use the associated `Get` functions to just extract
- // a specific error. This would return nil if that specific error doesn't
- // exist.
- perr := errwrap.GetType(err, new(os.PathError))
-}
-```
-
-#### Custom Types
-
-If you're already making custom types that properly wrap errors, then
-you can get all the functionality of `errwraps.Contains` and such by
-implementing the `Wrapper` interface with just one function. Example:
-
-```go
-type AppError {
- Code ErrorCode
- Err error
-}
-
-func (e *AppError) WrappedErrors() []error {
- return []error{e.Err}
-}
-```
-
-Now this works:
-
-```go
-err := &AppError{Err: fmt.Errorf("an error")}
-if errwrap.ContainsType(err, fmt.Errorf("")) {
- // This will work!
-}
-```
diff --git a/vendor/github.com/hashicorp/errwrap/errwrap.go b/vendor/github.com/hashicorp/errwrap/errwrap.go
deleted file mode 100644
index a733bef18c0..00000000000
--- a/vendor/github.com/hashicorp/errwrap/errwrap.go
+++ /dev/null
@@ -1,169 +0,0 @@
-// Package errwrap implements methods to formalize error wrapping in Go.
-//
-// All of the top-level functions that take an `error` are built to be able
-// to take any error, not just wrapped errors. This allows you to use errwrap
-// without having to type-check and type-cast everywhere.
-package errwrap
-
-import (
- "errors"
- "reflect"
- "strings"
-)
-
-// WalkFunc is the callback called for Walk.
-type WalkFunc func(error)
-
-// Wrapper is an interface that can be implemented by custom types to
-// have all the Contains, Get, etc. functions in errwrap work.
-//
-// When Walk reaches a Wrapper, it will call the callback for every
-// wrapped error in addition to the wrapper itself. Since all the top-level
-// functions in errwrap use Walk, this means that all those functions work
-// with your custom type.
-type Wrapper interface {
- WrappedErrors() []error
-}
-
-// Wrap defines that outer wraps inner, returning an error type that
-// can be cleanly used with the other methods in this package, such as
-// Contains, GetAll, etc.
-//
-// This function won't modify the error message at all (the outer message
-// will be used).
-func Wrap(outer, inner error) error {
- return &wrappedError{
- Outer: outer,
- Inner: inner,
- }
-}
-
-// Wrapf wraps an error with a formatting message. This is similar to using
-// `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap
-// errors, you should replace it with this.
-//
-// format is the format of the error message. The string '{{err}}' will
-// be replaced with the original error message.
-func Wrapf(format string, err error) error {
- outerMsg := ""
- if err != nil {
- outerMsg = err.Error()
- }
-
- outer := errors.New(strings.Replace(
- format, "{{err}}", outerMsg, -1))
-
- return Wrap(outer, err)
-}
-
-// Contains checks if the given error contains an error with the
-// message msg. If err is not a wrapped error, this will always return
-// false unless the error itself happens to match this msg.
-func Contains(err error, msg string) bool {
- return len(GetAll(err, msg)) > 0
-}
-
-// ContainsType checks if the given error contains an error with
-// the same concrete type as v. If err is not a wrapped error, this will
-// check the err itself.
-func ContainsType(err error, v interface{}) bool {
- return len(GetAllType(err, v)) > 0
-}
-
-// Get is the same as GetAll but returns the deepest matching error.
-func Get(err error, msg string) error {
- es := GetAll(err, msg)
- if len(es) > 0 {
- return es[len(es)-1]
- }
-
- return nil
-}
-
-// GetType is the same as GetAllType but returns the deepest matching error.
-func GetType(err error, v interface{}) error {
- es := GetAllType(err, v)
- if len(es) > 0 {
- return es[len(es)-1]
- }
-
- return nil
-}
-
-// GetAll gets all the errors that might be wrapped in err with the
-// given message. The order of the errors is such that the outermost
-// matching error (the most recent wrap) is index zero, and so on.
-func GetAll(err error, msg string) []error {
- var result []error
-
- Walk(err, func(err error) {
- if err.Error() == msg {
- result = append(result, err)
- }
- })
-
- return result
-}
-
-// GetAllType gets all the errors that are the same type as v.
-//
-// The order of the return value is the same as described in GetAll.
-func GetAllType(err error, v interface{}) []error {
- var result []error
-
- var search string
- if v != nil {
- search = reflect.TypeOf(v).String()
- }
- Walk(err, func(err error) {
- var needle string
- if err != nil {
- needle = reflect.TypeOf(err).String()
- }
-
- if needle == search {
- result = append(result, err)
- }
- })
-
- return result
-}
-
-// Walk walks all the wrapped errors in err and calls the callback. If
-// err isn't a wrapped error, this will be called once for err. If err
-// is a wrapped error, the callback will be called for both the wrapper
-// that implements error as well as the wrapped error itself.
-func Walk(err error, cb WalkFunc) {
- if err == nil {
- return
- }
-
- switch e := err.(type) {
- case *wrappedError:
- cb(e.Outer)
- Walk(e.Inner, cb)
- case Wrapper:
- cb(err)
-
- for _, err := range e.WrappedErrors() {
- Walk(err, cb)
- }
- default:
- cb(err)
- }
-}
-
-// wrappedError is an implementation of error that has both the
-// outer and inner errors.
-type wrappedError struct {
- Outer error
- Inner error
-}
-
-func (w *wrappedError) Error() string {
- return w.Outer.Error()
-}
-
-func (w *wrappedError) WrappedErrors() []error {
- return []error{w.Outer, w.Inner}
-}
diff --git a/vendor/github.com/hashicorp/errwrap/go.mod b/vendor/github.com/hashicorp/errwrap/go.mod
deleted file mode 100644
index c9b84022cf7..00000000000
--- a/vendor/github.com/hashicorp/errwrap/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/hashicorp/errwrap
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/LICENSE b/vendor/github.com/hashicorp/go-cleanhttp/LICENSE
deleted file mode 100644
index e87a115e462..00000000000
--- a/vendor/github.com/hashicorp/go-cleanhttp/LICENSE
+++ /dev/null
@@ -1,363 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. "Contributor"
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the terms of
- a Secondary License.
-
-1.6. "Executable Form"
-
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-
- means a work that combines Covered Software with other material, in a
- separate file or files, that is not Covered Software.
-
-1.8. "License"
-
- means this document.
-
-1.9. "Licensable"
-
- means having the right to grant, to the maximum extent possible, whether
- at the time of the initial grant or subsequently, any and all of the
- rights conveyed by this License.
-
-1.10. "Modifications"
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. "Patent Claims" of a Contributor
-
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the License,
- by the making, using, selling, offering for sale, having made, import,
- or transfer of either its Contributions or its Contributor Version.
-
-1.12. "Secondary License"
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. "Source Code Form"
-
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, "control" means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution
- become effective for each Contribution on the date the Contributor first
- distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under
- this License. No additional rights or licenses will be implied from the
- distribution or licensing of Covered Software under this License.
- Notwithstanding Section 2.1(b) above, no patent license is granted by a
- Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
- This License does not grant any rights in the trademarks, service marks,
- or logos of any Contributor (except as may be necessary to comply with
- the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this
- License (see Section 10.2) or under the terms of a Secondary License (if
- permitted under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its
- Contributions are its original creation(s) or it has sufficient rights to
- grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under
- applicable copyright doctrines of fair use, fair dealing, or other
- equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under
- the terms of this License. You must inform recipients that the Source
- Code Form of the Covered Software is governed by the terms of this
- License, and how they can obtain a copy of this License. You may not
- attempt to alter or restrict the recipients' rights in the Source Code
- Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter the
- recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for
- the Covered Software. If the Larger Work is a combination of Covered
- Software with a work governed by one or more Secondary Licenses, and the
- Covered Software is not Incompatible With Secondary Licenses, this
- License permits You to additionally distribute such Covered Software
- under the terms of such Secondary License(s), so that the recipient of
- the Larger Work may, at their option, further distribute the Covered
- Software under the terms of either this License or such Secondary
- License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices
- (including copyright notices, patent notices, disclaimers of warranty, or
- limitations of liability) contained within the Source Code Form of the
- Covered Software, except that You may alter any license notices to the
- extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on
- behalf of any Contributor. You must make it absolutely clear that any
- such warranty, support, indemnity, or liability obligation is offered by
- You alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute,
- judicial order, or regulation then You must: (a) comply with the terms of
- this License to the maximum extent possible; and (b) describe the
- limitations and the code they affect. Such description must be placed in a
- text file included with all distributions of the Covered Software under
- this License. Except to the extent prohibited by statute or regulation,
- such description must be sufficiently detailed for a recipient of ordinary
- skill to be able to understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing
- basis, if such Contributor fails to notify You of the non-compliance by
- some reasonable means prior to 60 days after You have come back into
- compliance. Moreover, Your grants from a particular Contributor are
- reinstated on an ongoing basis if such Contributor notifies You of the
- non-compliance by some reasonable means, this is the first time You have
- received notice of non-compliance with this License from such
- Contributor, and You become compliant prior to 30 days after Your receipt
- of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions,
- counter-claims, and cross-claims) alleging that a Contributor Version
- directly or indirectly infringes any patent, then the rights granted to
- You by any and all Contributors for the Covered Software under Section
- 2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an "as is" basis,
- without warranty of any kind, either expressed, implied, or statutory,
- including, without limitation, warranties that the Covered Software is free
- of defects, merchantable, fit for a particular purpose or non-infringing.
- The entire risk as to the quality and performance of the Covered Software
- is with You. Should any Covered Software prove defective in any respect,
- You (not any Contributor) assume the cost of any necessary servicing,
- repair, or correction. This disclaimer of warranty constitutes an essential
- part of this License. No use of any Covered Software is authorized under
- this License except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from
- such party's negligence to the extent applicable law prohibits such
- limitation. Some jurisdictions do not allow the exclusion or limitation of
- incidental or consequential damages, so this exclusion and limitation may
- not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts
- of a jurisdiction where the defendant maintains its principal place of
- business and such litigation shall be governed by laws of that
- jurisdiction, without reference to its conflict-of-law provisions. Nothing
- in this Section shall prevent a party's ability to bring cross-claims or
- counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. Any law or regulation which provides that
- the language of a contract shall be construed against the drafter shall not
- be used to construe this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version
- of the License under which You originally received the Covered Software,
- or under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a
- modified version of this License if you rename the license and remove
- any references to the name of the license steward (except to note that
- such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
- Licenses If You choose to distribute Source Code Form that is
- Incompatible With Secondary Licenses under the terms of this version of
- the License, the notice described in Exhibit B of this License must be
- attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file,
-then You may include the notice in a location (such as a LICENSE file in a
-relevant directory) where a recipient would be likely to look for such a
-notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
-
- This Source Code Form is "Incompatible
- With Secondary Licenses", as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/README.md b/vendor/github.com/hashicorp/go-cleanhttp/README.md
deleted file mode 100644
index 036e5313fc8..00000000000
--- a/vendor/github.com/hashicorp/go-cleanhttp/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# cleanhttp
-
-Functions for accessing "clean" Go http.Client values
-
--------------
-
-The Go standard library contains a default `http.Client` called
-`http.DefaultClient`. It is a common idiom in Go code to start with
-`http.DefaultClient` and tweak it as necessary, and in fact, this is
-encouraged; from the `http` package documentation:
-
-> The Client's Transport typically has internal state (cached TCP connections),
-so Clients should be reused instead of created as needed. Clients are safe for
-concurrent use by multiple goroutines.
-
-Unfortunately, this is a shared value, and it is not uncommon for libraries to
-assume that they are free to modify it at will. With enough dependencies, it
-can be very easy to encounter strange problems and race conditions due to
-manipulation of this shared value across libraries and goroutines (clients are
-safe for concurrent use, but writing values to the client struct itself is not
-protected).
-
-Making things worse is the fact that a bare `http.Client` will use a default
-`http.Transport` called `http.DefaultTransport`, which is another global value
-that behaves the same way. So it is not simply enough to replace
-`http.DefaultClient` with `&http.Client{}`.
-
-This repository provides some simple functions to get a "clean" `http.Client`
--- one that uses the same default values as the Go standard library, but
-returns a client that does not share any state with other clients.
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go b/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
deleted file mode 100644
index 8d306bf5134..00000000000
--- a/vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package cleanhttp
-
-import (
- "net"
- "net/http"
- "runtime"
- "time"
-)
-
-// DefaultTransport returns a new http.Transport with similar default values to
-// http.DefaultTransport, but with idle connections and keepalives disabled.
-func DefaultTransport() *http.Transport {
- transport := DefaultPooledTransport()
- transport.DisableKeepAlives = true
- transport.MaxIdleConnsPerHost = -1
- return transport
-}
-
-// DefaultPooledTransport returns a new http.Transport with similar default
-// values to http.DefaultTransport. Do not use this for transient transports as
-// it can leak file descriptors over time. Only use this for transports that
-// will be re-used for the same host(s).
-func DefaultPooledTransport() *http.Transport {
- transport := &http.Transport{
- Proxy: http.ProxyFromEnvironment,
- DialContext: (&net.Dialer{
- Timeout: 30 * time.Second,
- KeepAlive: 30 * time.Second,
- DualStack: true,
- }).DialContext,
- MaxIdleConns: 100,
- IdleConnTimeout: 90 * time.Second,
- TLSHandshakeTimeout: 10 * time.Second,
- ExpectContinueTimeout: 1 * time.Second,
- MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
- }
- return transport
-}
-
-// DefaultClient returns a new http.Client with similar default values to
-// http.Client, but with a non-shared Transport, idle connections disabled, and
-// keepalives disabled.
-func DefaultClient() *http.Client {
- return &http.Client{
- Transport: DefaultTransport(),
- }
-}
-
-// DefaultPooledClient returns a new http.Client with similar default values to
-// http.Client, but with a shared Transport. Do not use this function for
-// transient clients as it can leak file descriptors over time. Only use this
-// for clients that will be re-used for the same host(s).
-func DefaultPooledClient() *http.Client {
- return &http.Client{
- Transport: DefaultPooledTransport(),
- }
-}
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/doc.go b/vendor/github.com/hashicorp/go-cleanhttp/doc.go
deleted file mode 100644
index 05841092a7b..00000000000
--- a/vendor/github.com/hashicorp/go-cleanhttp/doc.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Package cleanhttp offers convenience utilities for acquiring "clean"
-// http.Transport and http.Client structs.
-//
-// Values set on http.DefaultClient and http.DefaultTransport affect all
-// callers. This can have detrimental effects, esepcially in TLS contexts,
-// where client or root certificates set to talk to multiple endpoints can end
-// up displacing each other, leading to hard-to-debug issues. This package
-// provides non-shared http.Client and http.Transport structs to ensure that
-// the configuration will not be overwritten by other parts of the application
-// or dependencies.
-//
-// The DefaultClient and DefaultTransport functions disable idle connections
-// and keepalives. Without ensuring that idle connections are closed before
-// garbage collection, short-term clients/transports can leak file descriptors,
-// eventually leading to "too many open files" errors. If you will be
-// connecting to the same hosts repeatedly from the same client, you can use
-// DefaultPooledClient to receive a client that has connection pooling
-// semantics similar to http.DefaultClient.
-//
-package cleanhttp
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/go.mod b/vendor/github.com/hashicorp/go-cleanhttp/go.mod
deleted file mode 100644
index 310f07569fc..00000000000
--- a/vendor/github.com/hashicorp/go-cleanhttp/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/hashicorp/go-cleanhttp
diff --git a/vendor/github.com/hashicorp/go-cleanhttp/handlers.go b/vendor/github.com/hashicorp/go-cleanhttp/handlers.go
deleted file mode 100644
index 3c845dc0dc6..00000000000
--- a/vendor/github.com/hashicorp/go-cleanhttp/handlers.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package cleanhttp
-
-import (
- "net/http"
- "strings"
- "unicode"
-)
-
-// HandlerInput provides input options to cleanhttp's handlers
-type HandlerInput struct {
- ErrStatus int
-}
-
-// PrintablePathCheckHandler is a middleware that ensures the request path
-// contains only printable runes.
-func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler {
- // Nil-check on input to make it optional
- if input == nil {
- input = &HandlerInput{
- ErrStatus: http.StatusBadRequest,
- }
- }
-
- // Default to http.StatusBadRequest on error
- if input.ErrStatus == 0 {
- input.ErrStatus = http.StatusBadRequest
- }
-
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r != nil {
- // Check URL path for non-printable characters
- idx := strings.IndexFunc(r.URL.Path, func(c rune) bool {
- return !unicode.IsPrint(c)
- })
-
- if idx != -1 {
- w.WriteHeader(input.ErrStatus)
- return
- }
-
- if next != nil {
- next.ServeHTTP(w, r)
- }
- }
-
- return
- })
-}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/.gitignore b/vendor/github.com/hashicorp/go-immutable-radix/.gitignore
deleted file mode 100644
index daf913b1b34..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-*.prof
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/.travis.yml b/vendor/github.com/hashicorp/go-immutable-radix/.travis.yml
deleted file mode 100644
index 1a0bbea6c77..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/.travis.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-language: go
-go:
- - tip
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/LICENSE b/vendor/github.com/hashicorp/go-immutable-radix/LICENSE
deleted file mode 100644
index e87a115e462..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/LICENSE
+++ /dev/null
@@ -1,363 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. "Contributor"
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the terms of
- a Secondary License.
-
-1.6. "Executable Form"
-
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-
- means a work that combines Covered Software with other material, in a
- separate file or files, that is not Covered Software.
-
-1.8. "License"
-
- means this document.
-
-1.9. "Licensable"
-
- means having the right to grant, to the maximum extent possible, whether
- at the time of the initial grant or subsequently, any and all of the
- rights conveyed by this License.
-
-1.10. "Modifications"
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. "Patent Claims" of a Contributor
-
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the License,
- by the making, using, selling, offering for sale, having made, import,
- or transfer of either its Contributions or its Contributor Version.
-
-1.12. "Secondary License"
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. "Source Code Form"
-
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, "control" means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution
- become effective for each Contribution on the date the Contributor first
- distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under
- this License. No additional rights or licenses will be implied from the
- distribution or licensing of Covered Software under this License.
- Notwithstanding Section 2.1(b) above, no patent license is granted by a
- Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
- This License does not grant any rights in the trademarks, service marks,
- or logos of any Contributor (except as may be necessary to comply with
- the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this
- License (see Section 10.2) or under the terms of a Secondary License (if
- permitted under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its
- Contributions are its original creation(s) or it has sufficient rights to
- grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under
- applicable copyright doctrines of fair use, fair dealing, or other
- equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under
- the terms of this License. You must inform recipients that the Source
- Code Form of the Covered Software is governed by the terms of this
- License, and how they can obtain a copy of this License. You may not
- attempt to alter or restrict the recipients' rights in the Source Code
- Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter the
- recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for
- the Covered Software. If the Larger Work is a combination of Covered
- Software with a work governed by one or more Secondary Licenses, and the
- Covered Software is not Incompatible With Secondary Licenses, this
- License permits You to additionally distribute such Covered Software
- under the terms of such Secondary License(s), so that the recipient of
- the Larger Work may, at their option, further distribute the Covered
- Software under the terms of either this License or such Secondary
- License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices
- (including copyright notices, patent notices, disclaimers of warranty, or
- limitations of liability) contained within the Source Code Form of the
- Covered Software, except that You may alter any license notices to the
- extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on
- behalf of any Contributor. You must make it absolutely clear that any
- such warranty, support, indemnity, or liability obligation is offered by
- You alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute,
- judicial order, or regulation then You must: (a) comply with the terms of
- this License to the maximum extent possible; and (b) describe the
- limitations and the code they affect. Such description must be placed in a
- text file included with all distributions of the Covered Software under
- this License. Except to the extent prohibited by statute or regulation,
- such description must be sufficiently detailed for a recipient of ordinary
- skill to be able to understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing
- basis, if such Contributor fails to notify You of the non-compliance by
- some reasonable means prior to 60 days after You have come back into
- compliance. Moreover, Your grants from a particular Contributor are
- reinstated on an ongoing basis if such Contributor notifies You of the
- non-compliance by some reasonable means, this is the first time You have
- received notice of non-compliance with this License from such
- Contributor, and You become compliant prior to 30 days after Your receipt
- of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions,
- counter-claims, and cross-claims) alleging that a Contributor Version
- directly or indirectly infringes any patent, then the rights granted to
- You by any and all Contributors for the Covered Software under Section
- 2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an "as is" basis,
- without warranty of any kind, either expressed, implied, or statutory,
- including, without limitation, warranties that the Covered Software is free
- of defects, merchantable, fit for a particular purpose or non-infringing.
- The entire risk as to the quality and performance of the Covered Software
- is with You. Should any Covered Software prove defective in any respect,
- You (not any Contributor) assume the cost of any necessary servicing,
- repair, or correction. This disclaimer of warranty constitutes an essential
- part of this License. No use of any Covered Software is authorized under
- this License except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from
- such party's negligence to the extent applicable law prohibits such
- limitation. Some jurisdictions do not allow the exclusion or limitation of
- incidental or consequential damages, so this exclusion and limitation may
- not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts
- of a jurisdiction where the defendant maintains its principal place of
- business and such litigation shall be governed by laws of that
- jurisdiction, without reference to its conflict-of-law provisions. Nothing
- in this Section shall prevent a party's ability to bring cross-claims or
- counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. Any law or regulation which provides that
- the language of a contract shall be construed against the drafter shall not
- be used to construe this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version
- of the License under which You originally received the Covered Software,
- or under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a
- modified version of this License if you rename the license and remove
- any references to the name of the license steward (except to note that
- such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
- Licenses If You choose to distribute Source Code Form that is
- Incompatible With Secondary Licenses under the terms of this version of
- the License, the notice described in Exhibit B of this License must be
- attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file,
-then You may include the notice in a location (such as a LICENSE file in a
-relevant directory) where a recipient would be likely to look for such a
-notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
-
- This Source Code Form is "Incompatible
- With Secondary Licenses", as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/README.md b/vendor/github.com/hashicorp/go-immutable-radix/README.md
deleted file mode 100644
index 8910fcc035a..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-go-immutable-radix [![Build Status](https://travis-ci.org/hashicorp/go-immutable-radix.png)](https://travis-ci.org/hashicorp/go-immutable-radix)
-=========
-
-Provides the `iradix` package that implements an immutable [radix tree](http://en.wikipedia.org/wiki/Radix_tree).
-The package only provides a single `Tree` implementation, optimized for sparse nodes.
-
-As a radix tree, it provides the following:
- * O(k) operations. In many cases, this can be faster than a hash table since
- the hash function is an O(k) operation, and hash tables have very poor cache locality.
- * Minimum / Maximum value lookups
- * Ordered iteration
-
-A tree supports using a transaction to batch multiple updates (insert, delete)
-in a more efficient manner than performing each operation one at a time.
-
-For a mutable variant, see [go-radix](https://github.com/armon/go-radix).
-
-Documentation
-=============
-
-The full documentation is available on [Godoc](http://godoc.org/github.com/hashicorp/go-immutable-radix).
-
-Example
-=======
-
-Below is a simple example of usage
-
-```go
-// Create a tree
-r := iradix.New()
-r, _, _ = r.Insert([]byte("foo"), 1)
-r, _, _ = r.Insert([]byte("bar"), 2)
-r, _, _ = r.Insert([]byte("foobar"), 2)
-
-// Find the longest prefix match
-m, _, _ := r.Root().LongestPrefix([]byte("foozip"))
-if string(m) != "foo" {
- panic("should be foo")
-}
-```
-
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/edges.go b/vendor/github.com/hashicorp/go-immutable-radix/edges.go
deleted file mode 100644
index a63674775f2..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/edges.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package iradix
-
-import "sort"
-
-type edges []edge
-
-func (e edges) Len() int {
- return len(e)
-}
-
-func (e edges) Less(i, j int) bool {
- return e[i].label < e[j].label
-}
-
-func (e edges) Swap(i, j int) {
- e[i], e[j] = e[j], e[i]
-}
-
-func (e edges) Sort() {
- sort.Sort(e)
-}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/go.mod b/vendor/github.com/hashicorp/go-immutable-radix/go.mod
deleted file mode 100644
index 27e7b7c9552..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/go.mod
+++ /dev/null
@@ -1,6 +0,0 @@
-module github.com/hashicorp/go-immutable-radix
-
-require (
- github.com/hashicorp/go-uuid v1.0.0
- github.com/hashicorp/golang-lru v0.5.0
-)
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/go.sum b/vendor/github.com/hashicorp/go-immutable-radix/go.sum
deleted file mode 100644
index 7de5dfc503e..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/go.sum
+++ /dev/null
@@ -1,4 +0,0 @@
-github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/iradix.go b/vendor/github.com/hashicorp/go-immutable-radix/iradix.go
deleted file mode 100644
index e5e6e57f262..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/iradix.go
+++ /dev/null
@@ -1,662 +0,0 @@
-package iradix
-
-import (
- "bytes"
- "strings"
-
- "github.com/hashicorp/golang-lru/simplelru"
-)
-
-const (
- // defaultModifiedCache is the default size of the modified node
- // cache used per transaction. This is used to cache the updates
- // to the nodes near the root, while the leaves do not need to be
- // cached. This is important for very large transactions to prevent
- // the modified cache from growing to be enormous. This is also used
- // to set the max size of the mutation notify maps since those should
- // also be bounded in a similar way.
- defaultModifiedCache = 8192
-)
-
-// Tree implements an immutable radix tree. This can be treated as a
-// Dictionary abstract data type. The main advantage over a standard
-// hash map is prefix-based lookups and ordered iteration. The immutability
-// means that it is safe to concurrently read from a Tree without any
-// coordination.
-type Tree struct {
- root *Node
- size int
-}
-
-// New returns an empty Tree
-func New() *Tree {
- t := &Tree{
- root: &Node{
- mutateCh: make(chan struct{}),
- },
- }
- return t
-}
-
-// Len is used to return the number of elements in the tree
-func (t *Tree) Len() int {
- return t.size
-}
-
-// Txn is a transaction on the tree. This transaction is applied
-// atomically and returns a new tree when committed. A transaction
-// is not thread safe, and should only be used by a single goroutine.
-type Txn struct {
- // root is the modified root for the transaction.
- root *Node
-
- // snap is a snapshot of the root node for use if we have to run the
- // slow notify algorithm.
- snap *Node
-
- // size tracks the size of the tree as it is modified during the
- // transaction.
- size int
-
- // writable is a cache of writable nodes that have been created during
- // the course of the transaction. This allows us to re-use the same
- // nodes for further writes and avoid unnecessary copies of nodes that
- // have never been exposed outside the transaction. This will only hold
- // up to defaultModifiedCache number of entries.
- writable *simplelru.LRU
-
- // trackChannels is used to hold channels that need to be notified to
- // signal mutation of the tree. This will only hold up to
- // defaultModifiedCache number of entries, after which we will set the
- // trackOverflow flag, which will cause us to use a more expensive
- // algorithm to perform the notifications. Mutation tracking is only
- // performed if trackMutate is true.
- trackChannels map[chan struct{}]struct{}
- trackOverflow bool
- trackMutate bool
-}
-
-// Txn starts a new transaction that can be used to mutate the tree
-func (t *Tree) Txn() *Txn {
- txn := &Txn{
- root: t.root,
- snap: t.root,
- size: t.size,
- }
- return txn
-}
-
-// TrackMutate can be used to toggle if mutations are tracked. If this is enabled
-// then notifications will be issued for affected internal nodes and leaves when
-// the transaction is committed.
-func (t *Txn) TrackMutate(track bool) {
- t.trackMutate = track
-}
-
-// trackChannel safely attempts to track the given mutation channel, setting the
-// overflow flag if we can no longer track any more. This limits the amount of
-// state that will accumulate during a transaction and we have a slower algorithm
-// to switch to if we overflow.
-func (t *Txn) trackChannel(ch chan struct{}) {
- // In overflow, make sure we don't store any more objects.
- if t.trackOverflow {
- return
- }
-
- // If this would overflow the state we reject it and set the flag (since
- // we aren't tracking everything that's required any longer).
- if len(t.trackChannels) >= defaultModifiedCache {
- // Mark that we are in the overflow state
- t.trackOverflow = true
-
- // Clear the map so that the channels can be garbage collected. It is
- // safe to do this since we have already overflowed and will be using
- // the slow notify algorithm.
- t.trackChannels = nil
- return
- }
-
- // Create the map on the fly when we need it.
- if t.trackChannels == nil {
- t.trackChannels = make(map[chan struct{}]struct{})
- }
-
- // Otherwise we are good to track it.
- t.trackChannels[ch] = struct{}{}
-}
-
-// writeNode returns a node to be modified, if the current node has already been
-// modified during the course of the transaction, it is used in-place. Set
-// forLeafUpdate to true if you are getting a write node to update the leaf,
-// which will set leaf mutation tracking appropriately as well.
-func (t *Txn) writeNode(n *Node, forLeafUpdate bool) *Node {
- // Ensure the writable set exists.
- if t.writable == nil {
- lru, err := simplelru.NewLRU(defaultModifiedCache, nil)
- if err != nil {
- panic(err)
- }
- t.writable = lru
- }
-
- // If this node has already been modified, we can continue to use it
- // during this transaction. We know that we don't need to track it for
- // a node update since the node is writable, but if this is for a leaf
- // update we track it, in case the initial write to this node didn't
- // update the leaf.
- if _, ok := t.writable.Get(n); ok {
- if t.trackMutate && forLeafUpdate && n.leaf != nil {
- t.trackChannel(n.leaf.mutateCh)
- }
- return n
- }
-
- // Mark this node as being mutated.
- if t.trackMutate {
- t.trackChannel(n.mutateCh)
- }
-
- // Mark its leaf as being mutated, if appropriate.
- if t.trackMutate && forLeafUpdate && n.leaf != nil {
- t.trackChannel(n.leaf.mutateCh)
- }
-
- // Copy the existing node. If you have set forLeafUpdate it will be
- // safe to replace this leaf with another after you get your node for
- // writing. You MUST replace it, because the channel associated with
- // this leaf will be closed when this transaction is committed.
- nc := &Node{
- mutateCh: make(chan struct{}),
- leaf: n.leaf,
- }
- if n.prefix != nil {
- nc.prefix = make([]byte, len(n.prefix))
- copy(nc.prefix, n.prefix)
- }
- if len(n.edges) != 0 {
- nc.edges = make([]edge, len(n.edges))
- copy(nc.edges, n.edges)
- }
-
- // Mark this node as writable.
- t.writable.Add(nc, nil)
- return nc
-}
-
-// Visit all the nodes in the tree under n, and add their mutateChannels to the transaction
-// Returns the size of the subtree visited
-func (t *Txn) trackChannelsAndCount(n *Node) int {
- // Count only leaf nodes
- leaves := 0
- if n.leaf != nil {
- leaves = 1
- }
- // Mark this node as being mutated.
- if t.trackMutate {
- t.trackChannel(n.mutateCh)
- }
-
- // Mark its leaf as being mutated, if appropriate.
- if t.trackMutate && n.leaf != nil {
- t.trackChannel(n.leaf.mutateCh)
- }
-
- // Recurse on the children
- for _, e := range n.edges {
- leaves += t.trackChannelsAndCount(e.node)
- }
- return leaves
-}
-
-// mergeChild is called to collapse the given node with its child. This is only
-// called when the given node is not a leaf and has a single edge.
-func (t *Txn) mergeChild(n *Node) {
- // Mark the child node as being mutated since we are about to abandon
- // it. We don't need to mark the leaf since we are retaining it if it
- // is there.
- e := n.edges[0]
- child := e.node
- if t.trackMutate {
- t.trackChannel(child.mutateCh)
- }
-
- // Merge the nodes.
- n.prefix = concat(n.prefix, child.prefix)
- n.leaf = child.leaf
- if len(child.edges) != 0 {
- n.edges = make([]edge, len(child.edges))
- copy(n.edges, child.edges)
- } else {
- n.edges = nil
- }
-}
-
-// insert does a recursive insertion
-func (t *Txn) insert(n *Node, k, search []byte, v interface{}) (*Node, interface{}, bool) {
- // Handle key exhaustion
- if len(search) == 0 {
- var oldVal interface{}
- didUpdate := false
- if n.isLeaf() {
- oldVal = n.leaf.val
- didUpdate = true
- }
-
- nc := t.writeNode(n, true)
- nc.leaf = &leafNode{
- mutateCh: make(chan struct{}),
- key: k,
- val: v,
- }
- return nc, oldVal, didUpdate
- }
-
- // Look for the edge
- idx, child := n.getEdge(search[0])
-
- // No edge, create one
- if child == nil {
- e := edge{
- label: search[0],
- node: &Node{
- mutateCh: make(chan struct{}),
- leaf: &leafNode{
- mutateCh: make(chan struct{}),
- key: k,
- val: v,
- },
- prefix: search,
- },
- }
- nc := t.writeNode(n, false)
- nc.addEdge(e)
- return nc, nil, false
- }
-
- // Determine longest prefix of the search key on match
- commonPrefix := longestPrefix(search, child.prefix)
- if commonPrefix == len(child.prefix) {
- search = search[commonPrefix:]
- newChild, oldVal, didUpdate := t.insert(child, k, search, v)
- if newChild != nil {
- nc := t.writeNode(n, false)
- nc.edges[idx].node = newChild
- return nc, oldVal, didUpdate
- }
- return nil, oldVal, didUpdate
- }
-
- // Split the node
- nc := t.writeNode(n, false)
- splitNode := &Node{
- mutateCh: make(chan struct{}),
- prefix: search[:commonPrefix],
- }
- nc.replaceEdge(edge{
- label: search[0],
- node: splitNode,
- })
-
- // Restore the existing child node
- modChild := t.writeNode(child, false)
- splitNode.addEdge(edge{
- label: modChild.prefix[commonPrefix],
- node: modChild,
- })
- modChild.prefix = modChild.prefix[commonPrefix:]
-
- // Create a new leaf node
- leaf := &leafNode{
- mutateCh: make(chan struct{}),
- key: k,
- val: v,
- }
-
- // If the new key is a subset, add to to this node
- search = search[commonPrefix:]
- if len(search) == 0 {
- splitNode.leaf = leaf
- return nc, nil, false
- }
-
- // Create a new edge for the node
- splitNode.addEdge(edge{
- label: search[0],
- node: &Node{
- mutateCh: make(chan struct{}),
- leaf: leaf,
- prefix: search,
- },
- })
- return nc, nil, false
-}
-
-// delete does a recursive deletion
-func (t *Txn) delete(parent, n *Node, search []byte) (*Node, *leafNode) {
- // Check for key exhaustion
- if len(search) == 0 {
- if !n.isLeaf() {
- return nil, nil
- }
- // Copy the pointer in case we are in a transaction that already
- // modified this node since the node will be reused. Any changes
- // made to the node will not affect returning the original leaf
- // value.
- oldLeaf := n.leaf
-
- // Remove the leaf node
- nc := t.writeNode(n, true)
- nc.leaf = nil
-
- // Check if this node should be merged
- if n != t.root && len(nc.edges) == 1 {
- t.mergeChild(nc)
- }
- return nc, oldLeaf
- }
-
- // Look for an edge
- label := search[0]
- idx, child := n.getEdge(label)
- if child == nil || !bytes.HasPrefix(search, child.prefix) {
- return nil, nil
- }
-
- // Consume the search prefix
- search = search[len(child.prefix):]
- newChild, leaf := t.delete(n, child, search)
- if newChild == nil {
- return nil, nil
- }
-
- // Copy this node. WATCH OUT - it's safe to pass "false" here because we
- // will only ADD a leaf via nc.mergeChild() if there isn't one due to
- // the !nc.isLeaf() check in the logic just below. This is pretty subtle,
- // so be careful if you change any of the logic here.
- nc := t.writeNode(n, false)
-
- // Delete the edge if the node has no edges
- if newChild.leaf == nil && len(newChild.edges) == 0 {
- nc.delEdge(label)
- if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() {
- t.mergeChild(nc)
- }
- } else {
- nc.edges[idx].node = newChild
- }
- return nc, leaf
-}
-
-// delete does a recursive deletion
-func (t *Txn) deletePrefix(parent, n *Node, search []byte) (*Node, int) {
- // Check for key exhaustion
- if len(search) == 0 {
- nc := t.writeNode(n, true)
- if n.isLeaf() {
- nc.leaf = nil
- }
- nc.edges = nil
- return nc, t.trackChannelsAndCount(n)
- }
-
- // Look for an edge
- label := search[0]
- idx, child := n.getEdge(label)
- // We make sure that either the child node's prefix starts with the search term, or the search term starts with the child node's prefix
- // Need to do both so that we can delete prefixes that don't correspond to any node in the tree
- if child == nil || (!bytes.HasPrefix(child.prefix, search) && !bytes.HasPrefix(search, child.prefix)) {
- return nil, 0
- }
-
- // Consume the search prefix
- if len(child.prefix) > len(search) {
- search = []byte("")
- } else {
- search = search[len(child.prefix):]
- }
- newChild, numDeletions := t.deletePrefix(n, child, search)
- if newChild == nil {
- return nil, 0
- }
- // Copy this node. WATCH OUT - it's safe to pass "false" here because we
- // will only ADD a leaf via nc.mergeChild() if there isn't one due to
- // the !nc.isLeaf() check in the logic just below. This is pretty subtle,
- // so be careful if you change any of the logic here.
-
- nc := t.writeNode(n, false)
-
- // Delete the edge if the node has no edges
- if newChild.leaf == nil && len(newChild.edges) == 0 {
- nc.delEdge(label)
- if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() {
- t.mergeChild(nc)
- }
- } else {
- nc.edges[idx].node = newChild
- }
- return nc, numDeletions
-}
-
-// Insert is used to add or update a given key. The return provides
-// the previous value and a bool indicating if any was set.
-func (t *Txn) Insert(k []byte, v interface{}) (interface{}, bool) {
- newRoot, oldVal, didUpdate := t.insert(t.root, k, k, v)
- if newRoot != nil {
- t.root = newRoot
- }
- if !didUpdate {
- t.size++
- }
- return oldVal, didUpdate
-}
-
-// Delete is used to delete a given key. Returns the old value if any,
-// and a bool indicating if the key was set.
-func (t *Txn) Delete(k []byte) (interface{}, bool) {
- newRoot, leaf := t.delete(nil, t.root, k)
- if newRoot != nil {
- t.root = newRoot
- }
- if leaf != nil {
- t.size--
- return leaf.val, true
- }
- return nil, false
-}
-
-// DeletePrefix is used to delete an entire subtree that matches the prefix
-// This will delete all nodes under that prefix
-func (t *Txn) DeletePrefix(prefix []byte) bool {
- newRoot, numDeletions := t.deletePrefix(nil, t.root, prefix)
- if newRoot != nil {
- t.root = newRoot
- t.size = t.size - numDeletions
- return true
- }
- return false
-
-}
-
-// Root returns the current root of the radix tree within this
-// transaction. The root is not safe across insert and delete operations,
-// but can be used to read the current state during a transaction.
-func (t *Txn) Root() *Node {
- return t.root
-}
-
-// Get is used to lookup a specific key, returning
-// the value and if it was found
-func (t *Txn) Get(k []byte) (interface{}, bool) {
- return t.root.Get(k)
-}
-
-// GetWatch is used to lookup a specific key, returning
-// the watch channel, value and if it was found
-func (t *Txn) GetWatch(k []byte) (<-chan struct{}, interface{}, bool) {
- return t.root.GetWatch(k)
-}
-
-// Commit is used to finalize the transaction and return a new tree. If mutation
-// tracking is turned on then notifications will also be issued.
-func (t *Txn) Commit() *Tree {
- nt := t.CommitOnly()
- if t.trackMutate {
- t.Notify()
- }
- return nt
-}
-
-// CommitOnly is used to finalize the transaction and return a new tree, but
-// does not issue any notifications until Notify is called.
-func (t *Txn) CommitOnly() *Tree {
- nt := &Tree{t.root, t.size}
- t.writable = nil
- return nt
-}
-
-// slowNotify does a complete comparison of the before and after trees in order
-// to trigger notifications. This doesn't require any additional state but it
-// is very expensive to compute.
-func (t *Txn) slowNotify() {
- snapIter := t.snap.rawIterator()
- rootIter := t.root.rawIterator()
- for snapIter.Front() != nil || rootIter.Front() != nil {
- // If we've exhausted the nodes in the old snapshot, we know
- // there's nothing remaining to notify.
- if snapIter.Front() == nil {
- return
- }
- snapElem := snapIter.Front()
-
- // If we've exhausted the nodes in the new root, we know we need
- // to invalidate everything that remains in the old snapshot. We
- // know from the loop condition there's something in the old
- // snapshot.
- if rootIter.Front() == nil {
- close(snapElem.mutateCh)
- if snapElem.isLeaf() {
- close(snapElem.leaf.mutateCh)
- }
- snapIter.Next()
- continue
- }
-
- // Do one string compare so we can check the various conditions
- // below without repeating the compare.
- cmp := strings.Compare(snapIter.Path(), rootIter.Path())
-
- // If the snapshot is behind the root, then we must have deleted
- // this node during the transaction.
- if cmp < 0 {
- close(snapElem.mutateCh)
- if snapElem.isLeaf() {
- close(snapElem.leaf.mutateCh)
- }
- snapIter.Next()
- continue
- }
-
- // If the snapshot is ahead of the root, then we must have added
- // this node during the transaction.
- if cmp > 0 {
- rootIter.Next()
- continue
- }
-
- // If we have the same path, then we need to see if we mutated a
- // node and possibly the leaf.
- rootElem := rootIter.Front()
- if snapElem != rootElem {
- close(snapElem.mutateCh)
- if snapElem.leaf != nil && (snapElem.leaf != rootElem.leaf) {
- close(snapElem.leaf.mutateCh)
- }
- }
- snapIter.Next()
- rootIter.Next()
- }
-}
-
-// Notify is used along with TrackMutate to trigger notifications. This must
-// only be done once a transaction is committed via CommitOnly, and it is called
-// automatically by Commit.
-func (t *Txn) Notify() {
- if !t.trackMutate {
- return
- }
-
- // If we've overflowed the tracking state we can't use it in any way and
- // need to do a full tree compare.
- if t.trackOverflow {
- t.slowNotify()
- } else {
- for ch := range t.trackChannels {
- close(ch)
- }
- }
-
- // Clean up the tracking state so that a re-notify is safe (will trigger
- // the else clause above which will be a no-op).
- t.trackChannels = nil
- t.trackOverflow = false
-}
-
-// Insert is used to add or update a given key. The return provides
-// the new tree, previous value and a bool indicating if any was set.
-func (t *Tree) Insert(k []byte, v interface{}) (*Tree, interface{}, bool) {
- txn := t.Txn()
- old, ok := txn.Insert(k, v)
- return txn.Commit(), old, ok
-}
-
-// Delete is used to delete a given key. Returns the new tree,
-// old value if any, and a bool indicating if the key was set.
-func (t *Tree) Delete(k []byte) (*Tree, interface{}, bool) {
- txn := t.Txn()
- old, ok := txn.Delete(k)
- return txn.Commit(), old, ok
-}
-
-// DeletePrefix is used to delete all nodes starting with a given prefix. Returns the new tree,
-// and a bool indicating if the prefix matched any nodes
-func (t *Tree) DeletePrefix(k []byte) (*Tree, bool) {
- txn := t.Txn()
- ok := txn.DeletePrefix(k)
- return txn.Commit(), ok
-}
-
-// Root returns the root node of the tree which can be used for richer
-// query operations.
-func (t *Tree) Root() *Node {
- return t.root
-}
-
-// Get is used to lookup a specific key, returning
-// the value and if it was found
-func (t *Tree) Get(k []byte) (interface{}, bool) {
- return t.root.Get(k)
-}
-
-// longestPrefix finds the length of the shared prefix
-// of two strings
-func longestPrefix(k1, k2 []byte) int {
- max := len(k1)
- if l := len(k2); l < max {
- max = l
- }
- var i int
- for i = 0; i < max; i++ {
- if k1[i] != k2[i] {
- break
- }
- }
- return i
-}
-
-// concat two byte slices, returning a third new copy
-func concat(a, b []byte) []byte {
- c := make([]byte, len(a)+len(b))
- copy(c, a)
- copy(c[len(a):], b)
- return c
-}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/iter.go b/vendor/github.com/hashicorp/go-immutable-radix/iter.go
deleted file mode 100644
index 9815e02538e..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/iter.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package iradix
-
-import "bytes"
-
-// Iterator is used to iterate over a set of nodes
-// in pre-order
-type Iterator struct {
- node *Node
- stack []edges
-}
-
-// SeekPrefixWatch is used to seek the iterator to a given prefix
-// and returns the watch channel of the finest granularity
-func (i *Iterator) SeekPrefixWatch(prefix []byte) (watch <-chan struct{}) {
- // Wipe the stack
- i.stack = nil
- n := i.node
- watch = n.mutateCh
- search := prefix
- for {
- // Check for key exhaution
- if len(search) == 0 {
- i.node = n
- return
- }
-
- // Look for an edge
- _, n = n.getEdge(search[0])
- if n == nil {
- i.node = nil
- return
- }
-
- // Update to the finest granularity as the search makes progress
- watch = n.mutateCh
-
- // Consume the search prefix
- if bytes.HasPrefix(search, n.prefix) {
- search = search[len(n.prefix):]
-
- } else if bytes.HasPrefix(n.prefix, search) {
- i.node = n
- return
- } else {
- i.node = nil
- return
- }
- }
-}
-
-// SeekPrefix is used to seek the iterator to a given prefix
-func (i *Iterator) SeekPrefix(prefix []byte) {
- i.SeekPrefixWatch(prefix)
-}
-
-// Next returns the next node in order
-func (i *Iterator) Next() ([]byte, interface{}, bool) {
- // Initialize our stack if needed
- if i.stack == nil && i.node != nil {
- i.stack = []edges{
- edges{
- edge{node: i.node},
- },
- }
- }
-
- for len(i.stack) > 0 {
- // Inspect the last element of the stack
- n := len(i.stack)
- last := i.stack[n-1]
- elem := last[0].node
-
- // Update the stack
- if len(last) > 1 {
- i.stack[n-1] = last[1:]
- } else {
- i.stack = i.stack[:n-1]
- }
-
- // Push the edges onto the frontier
- if len(elem.edges) > 0 {
- i.stack = append(i.stack, elem.edges)
- }
-
- // Return the leaf values if any
- if elem.leaf != nil {
- return elem.leaf.key, elem.leaf.val, true
- }
- }
- return nil, nil, false
-}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/node.go b/vendor/github.com/hashicorp/go-immutable-radix/node.go
deleted file mode 100644
index 7a065e7a09e..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/node.go
+++ /dev/null
@@ -1,292 +0,0 @@
-package iradix
-
-import (
- "bytes"
- "sort"
-)
-
-// WalkFn is used when walking the tree. Takes a
-// key and value, returning if iteration should
-// be terminated.
-type WalkFn func(k []byte, v interface{}) bool
-
-// leafNode is used to represent a value
-type leafNode struct {
- mutateCh chan struct{}
- key []byte
- val interface{}
-}
-
-// edge is used to represent an edge node
-type edge struct {
- label byte
- node *Node
-}
-
-// Node is an immutable node in the radix tree
-type Node struct {
- // mutateCh is closed if this node is modified
- mutateCh chan struct{}
-
- // leaf is used to store possible leaf
- leaf *leafNode
-
- // prefix is the common prefix we ignore
- prefix []byte
-
- // Edges should be stored in-order for iteration.
- // We avoid a fully materialized slice to save memory,
- // since in most cases we expect to be sparse
- edges edges
-}
-
-func (n *Node) isLeaf() bool {
- return n.leaf != nil
-}
-
-func (n *Node) addEdge(e edge) {
- num := len(n.edges)
- idx := sort.Search(num, func(i int) bool {
- return n.edges[i].label >= e.label
- })
- n.edges = append(n.edges, e)
- if idx != num {
- copy(n.edges[idx+1:], n.edges[idx:num])
- n.edges[idx] = e
- }
-}
-
-func (n *Node) replaceEdge(e edge) {
- num := len(n.edges)
- idx := sort.Search(num, func(i int) bool {
- return n.edges[i].label >= e.label
- })
- if idx < num && n.edges[idx].label == e.label {
- n.edges[idx].node = e.node
- return
- }
- panic("replacing missing edge")
-}
-
-func (n *Node) getEdge(label byte) (int, *Node) {
- num := len(n.edges)
- idx := sort.Search(num, func(i int) bool {
- return n.edges[i].label >= label
- })
- if idx < num && n.edges[idx].label == label {
- return idx, n.edges[idx].node
- }
- return -1, nil
-}
-
-func (n *Node) delEdge(label byte) {
- num := len(n.edges)
- idx := sort.Search(num, func(i int) bool {
- return n.edges[i].label >= label
- })
- if idx < num && n.edges[idx].label == label {
- copy(n.edges[idx:], n.edges[idx+1:])
- n.edges[len(n.edges)-1] = edge{}
- n.edges = n.edges[:len(n.edges)-1]
- }
-}
-
-func (n *Node) GetWatch(k []byte) (<-chan struct{}, interface{}, bool) {
- search := k
- watch := n.mutateCh
- for {
- // Check for key exhaustion
- if len(search) == 0 {
- if n.isLeaf() {
- return n.leaf.mutateCh, n.leaf.val, true
- }
- break
- }
-
- // Look for an edge
- _, n = n.getEdge(search[0])
- if n == nil {
- break
- }
-
- // Update to the finest granularity as the search makes progress
- watch = n.mutateCh
-
- // Consume the search prefix
- if bytes.HasPrefix(search, n.prefix) {
- search = search[len(n.prefix):]
- } else {
- break
- }
- }
- return watch, nil, false
-}
-
-func (n *Node) Get(k []byte) (interface{}, bool) {
- _, val, ok := n.GetWatch(k)
- return val, ok
-}
-
-// LongestPrefix is like Get, but instead of an
-// exact match, it will return the longest prefix match.
-func (n *Node) LongestPrefix(k []byte) ([]byte, interface{}, bool) {
- var last *leafNode
- search := k
- for {
- // Look for a leaf node
- if n.isLeaf() {
- last = n.leaf
- }
-
- // Check for key exhaution
- if len(search) == 0 {
- break
- }
-
- // Look for an edge
- _, n = n.getEdge(search[0])
- if n == nil {
- break
- }
-
- // Consume the search prefix
- if bytes.HasPrefix(search, n.prefix) {
- search = search[len(n.prefix):]
- } else {
- break
- }
- }
- if last != nil {
- return last.key, last.val, true
- }
- return nil, nil, false
-}
-
-// Minimum is used to return the minimum value in the tree
-func (n *Node) Minimum() ([]byte, interface{}, bool) {
- for {
- if n.isLeaf() {
- return n.leaf.key, n.leaf.val, true
- }
- if len(n.edges) > 0 {
- n = n.edges[0].node
- } else {
- break
- }
- }
- return nil, nil, false
-}
-
-// Maximum is used to return the maximum value in the tree
-func (n *Node) Maximum() ([]byte, interface{}, bool) {
- for {
- if num := len(n.edges); num > 0 {
- n = n.edges[num-1].node
- continue
- }
- if n.isLeaf() {
- return n.leaf.key, n.leaf.val, true
- } else {
- break
- }
- }
- return nil, nil, false
-}
-
-// Iterator is used to return an iterator at
-// the given node to walk the tree
-func (n *Node) Iterator() *Iterator {
- return &Iterator{node: n}
-}
-
-// rawIterator is used to return a raw iterator at the given node to walk the
-// tree.
-func (n *Node) rawIterator() *rawIterator {
- iter := &rawIterator{node: n}
- iter.Next()
- return iter
-}
-
-// Walk is used to walk the tree
-func (n *Node) Walk(fn WalkFn) {
- recursiveWalk(n, fn)
-}
-
-// WalkPrefix is used to walk the tree under a prefix
-func (n *Node) WalkPrefix(prefix []byte, fn WalkFn) {
- search := prefix
- for {
- // Check for key exhaution
- if len(search) == 0 {
- recursiveWalk(n, fn)
- return
- }
-
- // Look for an edge
- _, n = n.getEdge(search[0])
- if n == nil {
- break
- }
-
- // Consume the search prefix
- if bytes.HasPrefix(search, n.prefix) {
- search = search[len(n.prefix):]
-
- } else if bytes.HasPrefix(n.prefix, search) {
- // Child may be under our search prefix
- recursiveWalk(n, fn)
- return
- } else {
- break
- }
- }
-}
-
-// WalkPath is used to walk the tree, but only visiting nodes
-// from the root down to a given leaf. Where WalkPrefix walks
-// all the entries *under* the given prefix, this walks the
-// entries *above* the given prefix.
-func (n *Node) WalkPath(path []byte, fn WalkFn) {
- search := path
- for {
- // Visit the leaf values if any
- if n.leaf != nil && fn(n.leaf.key, n.leaf.val) {
- return
- }
-
- // Check for key exhaution
- if len(search) == 0 {
- return
- }
-
- // Look for an edge
- _, n = n.getEdge(search[0])
- if n == nil {
- return
- }
-
- // Consume the search prefix
- if bytes.HasPrefix(search, n.prefix) {
- search = search[len(n.prefix):]
- } else {
- break
- }
- }
-}
-
-// recursiveWalk is used to do a pre-order walk of a node
-// recursively. Returns true if the walk should be aborted
-func recursiveWalk(n *Node, fn WalkFn) bool {
- // Visit the leaf values if any
- if n.leaf != nil && fn(n.leaf.key, n.leaf.val) {
- return true
- }
-
- // Recurse on the children
- for _, e := range n.edges {
- if recursiveWalk(e.node, fn) {
- return true
- }
- }
- return false
-}
diff --git a/vendor/github.com/hashicorp/go-immutable-radix/raw_iter.go b/vendor/github.com/hashicorp/go-immutable-radix/raw_iter.go
deleted file mode 100644
index 04814c1323f..00000000000
--- a/vendor/github.com/hashicorp/go-immutable-radix/raw_iter.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package iradix
-
-// rawIterator visits each of the nodes in the tree, even the ones that are not
-// leaves. It keeps track of the effective path (what a leaf at a given node
-// would be called), which is useful for comparing trees.
-type rawIterator struct {
- // node is the starting node in the tree for the iterator.
- node *Node
-
- // stack keeps track of edges in the frontier.
- stack []rawStackEntry
-
- // pos is the current position of the iterator.
- pos *Node
-
- // path is the effective path of the current iterator position,
- // regardless of whether the current node is a leaf.
- path string
-}
-
-// rawStackEntry is used to keep track of the cumulative common path as well as
-// its associated edges in the frontier.
-type rawStackEntry struct {
- path string
- edges edges
-}
-
-// Front returns the current node that has been iterated to.
-func (i *rawIterator) Front() *Node {
- return i.pos
-}
-
-// Path returns the effective path of the current node, even if it's not actually
-// a leaf.
-func (i *rawIterator) Path() string {
- return i.path
-}
-
-// Next advances the iterator to the next node.
-func (i *rawIterator) Next() {
- // Initialize our stack if needed.
- if i.stack == nil && i.node != nil {
- i.stack = []rawStackEntry{
- rawStackEntry{
- edges: edges{
- edge{node: i.node},
- },
- },
- }
- }
-
- for len(i.stack) > 0 {
- // Inspect the last element of the stack.
- n := len(i.stack)
- last := i.stack[n-1]
- elem := last.edges[0].node
-
- // Update the stack.
- if len(last.edges) > 1 {
- i.stack[n-1].edges = last.edges[1:]
- } else {
- i.stack = i.stack[:n-1]
- }
-
- // Push the edges onto the frontier.
- if len(elem.edges) > 0 {
- path := last.path + string(elem.prefix)
- i.stack = append(i.stack, rawStackEntry{path, elem.edges})
- }
-
- i.pos = elem
- i.path = last.path + string(elem.prefix)
- return
- }
-
- i.pos = nil
- i.path = ""
-}
diff --git a/vendor/github.com/hashicorp/go-multierror/.travis.yml b/vendor/github.com/hashicorp/go-multierror/.travis.yml
deleted file mode 100644
index 304a8359558..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/.travis.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-sudo: false
-
-language: go
-
-go:
- - 1.x
-
-branches:
- only:
- - master
-
-script: make test testrace
diff --git a/vendor/github.com/hashicorp/go-multierror/LICENSE b/vendor/github.com/hashicorp/go-multierror/LICENSE
deleted file mode 100644
index 82b4de97c7e..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/LICENSE
+++ /dev/null
@@ -1,353 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. “Contributorâ€
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. “Contributor Versionâ€
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor’s Contribution.
-
-1.3. “Contributionâ€
-
- means Covered Software of a particular Contributor.
-
-1.4. “Covered Softwareâ€
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. “Incompatible With Secondary Licensesâ€
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of version
- 1.1 or earlier of the License, but not also under the terms of a
- Secondary License.
-
-1.6. “Executable Formâ€
-
- means any form of the work other than Source Code Form.
-
-1.7. “Larger Workâ€
-
- means a work that combines Covered Software with other material, in a separate
- file or files, that is not Covered Software.
-
-1.8. “Licenseâ€
-
- means this document.
-
-1.9. “Licensableâ€
-
- means having the right to grant, to the maximum extent possible, whether at the
- time of the initial grant or subsequently, any and all of the rights conveyed by
- this License.
-
-1.10. “Modificationsâ€
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to, deletion
- from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. “Patent Claims†of a Contributor
-
- means any patent claim(s), including without limitation, method, process,
- and apparatus claims, in any patent Licensable by such Contributor that
- would be infringed, but for the grant of the License, by the making,
- using, selling, offering for sale, having made, import, or transfer of
- either its Contributions or its Contributor Version.
-
-1.12. “Secondary Licenseâ€
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. “Source Code Formâ€
-
- means the form of the work preferred for making modifications.
-
-1.14. “You†(or “Yourâ€)
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, “You†includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, “control†means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or as
- part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its Contributions
- or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution become
- effective for each Contribution on the date the Contributor first distributes
- such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under this
- License. No additional rights or licenses will be implied from the distribution
- or licensing of Covered Software under this License. Notwithstanding Section
- 2.1(b) above, no patent license is granted by a Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party’s
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of its
- Contributions.
-
- This License does not grant any rights in the trademarks, service marks, or
- logos of any Contributor (except as may be necessary to comply with the
- notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this License
- (see Section 10.2) or under the terms of a Secondary License (if permitted
- under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its Contributions
- are its original creation(s) or it has sufficient rights to grant the
- rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under applicable
- copyright doctrines of fair use, fair dealing, or other equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under the
- terms of this License. You must inform recipients that the Source Code Form
- of the Covered Software is governed by the terms of this License, and how
- they can obtain a copy of this License. You may not attempt to alter or
- restrict the recipients’ rights in the Source Code Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this License,
- or sublicense it under different terms, provided that the license for
- the Executable Form does not attempt to limit or alter the recipients’
- rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for the
- Covered Software. If the Larger Work is a combination of Covered Software
- with a work governed by one or more Secondary Licenses, and the Covered
- Software is not Incompatible With Secondary Licenses, this License permits
- You to additionally distribute such Covered Software under the terms of
- such Secondary License(s), so that the recipient of the Larger Work may, at
- their option, further distribute the Covered Software under the terms of
- either this License or such Secondary License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices (including
- copyright notices, patent notices, disclaimers of warranty, or limitations
- of liability) contained within the Source Code Form of the Covered
- Software, except that You may alter any license notices to the extent
- required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on behalf
- of any Contributor. You must make it absolutely clear that any such
- warranty, support, indemnity, or liability obligation is offered by You
- alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute, judicial
- order, or regulation then You must: (a) comply with the terms of this License
- to the maximum extent possible; and (b) describe the limitations and the code
- they affect. Such description must be placed in a text file included with all
- distributions of the Covered Software under this License. Except to the
- extent prohibited by statute or regulation, such description must be
- sufficiently detailed for a recipient of ordinary skill to be able to
- understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing basis,
- if such Contributor fails to notify You of the non-compliance by some
- reasonable means prior to 60 days after You have come back into compliance.
- Moreover, Your grants from a particular Contributor are reinstated on an
- ongoing basis if such Contributor notifies You of the non-compliance by
- some reasonable means, this is the first time You have received notice of
- non-compliance with this License from such Contributor, and You become
- compliant prior to 30 days after Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions, counter-claims,
- and cross-claims) alleging that a Contributor Version directly or
- indirectly infringes any patent, then the rights granted to You by any and
- all Contributors for the Covered Software under Section 2.1 of this License
- shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an “as is†basis, without
- warranty of any kind, either expressed, implied, or statutory, including,
- without limitation, warranties that the Covered Software is free of defects,
- merchantable, fit for a particular purpose or non-infringing. The entire
- risk as to the quality and performance of the Covered Software is with You.
- Should any Covered Software prove defective in any respect, You (not any
- Contributor) assume the cost of any necessary servicing, repair, or
- correction. This disclaimer of warranty constitutes an essential part of this
- License. No use of any Covered Software is authorized under this License
- except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from such
- party’s negligence to the extent applicable law prohibits such limitation.
- Some jurisdictions do not allow the exclusion or limitation of incidental or
- consequential damages, so this exclusion and limitation may not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts of
- a jurisdiction where the defendant maintains its principal place of business
- and such litigation shall be governed by laws of that jurisdiction, without
- reference to its conflict-of-law provisions. Nothing in this Section shall
- prevent a party’s ability to bring cross-claims or counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject matter
- hereof. If any provision of this License is held to be unenforceable, such
- provision shall be reformed only to the extent necessary to make it
- enforceable. Any law or regulation which provides that the language of a
- contract shall be construed against the drafter shall not be used to construe
- this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version of
- the License under which You originally received the Covered Software, or
- under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a modified
- version of this License if you rename the license and remove any
- references to the name of the license steward (except to note that such
- modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
- If You choose to distribute Source Code Form that is Incompatible With
- Secondary Licenses under the terms of this version of the License, the
- notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file, then
-You may include the notice in a location (such as a LICENSE file in a relevant
-directory) where a recipient would be likely to look for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - “Incompatible With Secondary Licenses†Notice
-
- This Source Code Form is “Incompatible
- With Secondary Licensesâ€, as defined by
- the Mozilla Public License, v. 2.0.
diff --git a/vendor/github.com/hashicorp/go-multierror/Makefile b/vendor/github.com/hashicorp/go-multierror/Makefile
deleted file mode 100644
index b97cd6ed02b..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/Makefile
+++ /dev/null
@@ -1,31 +0,0 @@
-TEST?=./...
-
-default: test
-
-# test runs the test suite and vets the code.
-test: generate
- @echo "==> Running tests..."
- @go list $(TEST) \
- | grep -v "/vendor/" \
- | xargs -n1 go test -timeout=60s -parallel=10 ${TESTARGS}
-
-# testrace runs the race checker
-testrace: generate
- @echo "==> Running tests (race)..."
- @go list $(TEST) \
- | grep -v "/vendor/" \
- | xargs -n1 go test -timeout=60s -race ${TESTARGS}
-
-# updatedeps installs all the dependencies needed to run and build.
-updatedeps:
- @sh -c "'${CURDIR}/scripts/deps.sh' '${NAME}'"
-
-# generate runs `go generate` to build the dynamically generated source files.
-generate:
- @echo "==> Generating..."
- @find . -type f -name '.DS_Store' -delete
- @go list ./... \
- | grep -v "/vendor/" \
- | xargs -n1 go generate
-
-.PHONY: default test testrace updatedeps generate
diff --git a/vendor/github.com/hashicorp/go-multierror/README.md b/vendor/github.com/hashicorp/go-multierror/README.md
deleted file mode 100644
index ead5830f7b7..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/README.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# go-multierror
-
-[![Build Status](http://img.shields.io/travis/hashicorp/go-multierror.svg?style=flat-square)][travis]
-[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
-
-[travis]: https://travis-ci.org/hashicorp/go-multierror
-[godocs]: https://godoc.org/github.com/hashicorp/go-multierror
-
-`go-multierror` is a package for Go that provides a mechanism for
-representing a list of `error` values as a single `error`.
-
-This allows a function in Go to return an `error` that might actually
-be a list of errors. If the caller knows this, they can unwrap the
-list and access the errors. If the caller doesn't know, the error
-formats to a nice human-readable format.
-
-`go-multierror` implements the
-[errwrap](https://github.com/hashicorp/errwrap) interface so that it can
-be used with that library, as well.
-
-## Installation and Docs
-
-Install using `go get github.com/hashicorp/go-multierror`.
-
-Full documentation is available at
-http://godoc.org/github.com/hashicorp/go-multierror
-
-## Usage
-
-go-multierror is easy to use and purposely built to be unobtrusive in
-existing Go applications/libraries that may not be aware of it.
-
-**Building a list of errors**
-
-The `Append` function is used to create a list of errors. This function
-behaves a lot like the Go built-in `append` function: it doesn't matter
-if the first argument is nil, a `multierror.Error`, or any other `error`,
-the function behaves as you would expect.
-
-```go
-var result error
-
-if err := step1(); err != nil {
- result = multierror.Append(result, err)
-}
-if err := step2(); err != nil {
- result = multierror.Append(result, err)
-}
-
-return result
-```
-
-**Customizing the formatting of the errors**
-
-By specifying a custom `ErrorFormat`, you can customize the format
-of the `Error() string` function:
-
-```go
-var result *multierror.Error
-
-// ... accumulate errors here, maybe using Append
-
-if result != nil {
- result.ErrorFormat = func([]error) string {
- return "errors!"
- }
-}
-```
-
-**Accessing the list of errors**
-
-`multierror.Error` implements `error` so if the caller doesn't know about
-multierror, it will work just fine. But if you're aware a multierror might
-be returned, you can use type switches to access the list of errors:
-
-```go
-if err := something(); err != nil {
- if merr, ok := err.(*multierror.Error); ok {
- // Use merr.Errors
- }
-}
-```
-
-**Returning a multierror only if there are errors**
-
-If you build a `multierror.Error`, you can use the `ErrorOrNil` function
-to return an `error` implementation only if there are errors to return:
-
-```go
-var result *multierror.Error
-
-// ... accumulate errors here
-
-// Return the `error` only if errors were added to the multierror, otherwise
-// return nil since there are no errors.
-return result.ErrorOrNil()
-```
diff --git a/vendor/github.com/hashicorp/go-multierror/append.go b/vendor/github.com/hashicorp/go-multierror/append.go
deleted file mode 100644
index 775b6e753e7..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/append.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package multierror
-
-// Append is a helper function that will append more errors
-// onto an Error in order to create a larger multi-error.
-//
-// If err is not a multierror.Error, then it will be turned into
-// one. If any of the errs are multierr.Error, they will be flattened
-// one level into err.
-func Append(err error, errs ...error) *Error {
- switch err := err.(type) {
- case *Error:
- // Typed nils can reach here, so initialize if we are nil
- if err == nil {
- err = new(Error)
- }
-
- // Go through each error and flatten
- for _, e := range errs {
- switch e := e.(type) {
- case *Error:
- if e != nil {
- err.Errors = append(err.Errors, e.Errors...)
- }
- default:
- if e != nil {
- err.Errors = append(err.Errors, e)
- }
- }
- }
-
- return err
- default:
- newErrs := make([]error, 0, len(errs)+1)
- if err != nil {
- newErrs = append(newErrs, err)
- }
- newErrs = append(newErrs, errs...)
-
- return Append(&Error{}, newErrs...)
- }
-}
diff --git a/vendor/github.com/hashicorp/go-multierror/flatten.go b/vendor/github.com/hashicorp/go-multierror/flatten.go
deleted file mode 100644
index aab8e9abec9..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/flatten.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package multierror
-
-// Flatten flattens the given error, merging any *Errors together into
-// a single *Error.
-func Flatten(err error) error {
- // If it isn't an *Error, just return the error as-is
- if _, ok := err.(*Error); !ok {
- return err
- }
-
- // Otherwise, make the result and flatten away!
- flatErr := new(Error)
- flatten(err, flatErr)
- return flatErr
-}
-
-func flatten(err error, flatErr *Error) {
- switch err := err.(type) {
- case *Error:
- for _, e := range err.Errors {
- flatten(e, flatErr)
- }
- default:
- flatErr.Errors = append(flatErr.Errors, err)
- }
-}
diff --git a/vendor/github.com/hashicorp/go-multierror/format.go b/vendor/github.com/hashicorp/go-multierror/format.go
deleted file mode 100644
index 47f13c49a67..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/format.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package multierror
-
-import (
- "fmt"
- "strings"
-)
-
-// ErrorFormatFunc is a function callback that is called by Error to
-// turn the list of errors into a string.
-type ErrorFormatFunc func([]error) string
-
-// ListFormatFunc is a basic formatter that outputs the number of errors
-// that occurred along with a bullet point list of the errors.
-func ListFormatFunc(es []error) string {
- if len(es) == 1 {
- return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", es[0])
- }
-
- points := make([]string, len(es))
- for i, err := range es {
- points[i] = fmt.Sprintf("* %s", err)
- }
-
- return fmt.Sprintf(
- "%d errors occurred:\n\t%s\n\n",
- len(es), strings.Join(points, "\n\t"))
-}
diff --git a/vendor/github.com/hashicorp/go-multierror/go.mod b/vendor/github.com/hashicorp/go-multierror/go.mod
deleted file mode 100644
index 2534331d5f9..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/hashicorp/go-multierror
-
-require github.com/hashicorp/errwrap v1.0.0
diff --git a/vendor/github.com/hashicorp/go-multierror/go.sum b/vendor/github.com/hashicorp/go-multierror/go.sum
deleted file mode 100644
index 85b1f8ff333..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/go.sum
+++ /dev/null
@@ -1,4 +0,0 @@
-github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4=
-github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
diff --git a/vendor/github.com/hashicorp/go-multierror/multierror.go b/vendor/github.com/hashicorp/go-multierror/multierror.go
deleted file mode 100644
index 89b1422d1d1..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/multierror.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package multierror
-
-import (
- "fmt"
-)
-
-// Error is an error type to track multiple errors. This is used to
-// accumulate errors in cases and return them as a single "error".
-type Error struct {
- Errors []error
- ErrorFormat ErrorFormatFunc
-}
-
-func (e *Error) Error() string {
- fn := e.ErrorFormat
- if fn == nil {
- fn = ListFormatFunc
- }
-
- return fn(e.Errors)
-}
-
-// ErrorOrNil returns an error interface if this Error represents
-// a list of errors, or returns nil if the list of errors is empty. This
-// function is useful at the end of accumulation to make sure that the value
-// returned represents the existence of errors.
-func (e *Error) ErrorOrNil() error {
- if e == nil {
- return nil
- }
- if len(e.Errors) == 0 {
- return nil
- }
-
- return e
-}
-
-func (e *Error) GoString() string {
- return fmt.Sprintf("*%#v", *e)
-}
-
-// WrappedErrors returns the list of errors that this Error is wrapping.
-// It is an implementation of the errwrap.Wrapper interface so that
-// multierror.Error can be used with that library.
-//
-// This method is not safe to be called concurrently and is no different
-// than accessing the Errors field directly. It is implemented only to
-// satisfy the errwrap.Wrapper interface.
-func (e *Error) WrappedErrors() []error {
- return e.Errors
-}
diff --git a/vendor/github.com/hashicorp/go-multierror/prefix.go b/vendor/github.com/hashicorp/go-multierror/prefix.go
deleted file mode 100644
index 5c477abe44f..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/prefix.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package multierror
-
-import (
- "fmt"
-
- "github.com/hashicorp/errwrap"
-)
-
-// Prefix is a helper function that will prefix some text
-// to the given error. If the error is a multierror.Error, then
-// it will be prefixed to each wrapped error.
-//
-// This is useful to use when appending multiple multierrors
-// together in order to give better scoping.
-func Prefix(err error, prefix string) error {
- if err == nil {
- return nil
- }
-
- format := fmt.Sprintf("%s {{err}}", prefix)
- switch err := err.(type) {
- case *Error:
- // Typed nils can reach here, so initialize if we are nil
- if err == nil {
- err = new(Error)
- }
-
- // Wrap each of the errors
- for i, e := range err.Errors {
- err.Errors[i] = errwrap.Wrapf(format, e)
- }
-
- return err
- default:
- return errwrap.Wrapf(format, err)
- }
-}
diff --git a/vendor/github.com/hashicorp/go-multierror/sort.go b/vendor/github.com/hashicorp/go-multierror/sort.go
deleted file mode 100644
index fecb14e81c5..00000000000
--- a/vendor/github.com/hashicorp/go-multierror/sort.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package multierror
-
-// Len implements sort.Interface function for length
-func (err Error) Len() int {
- return len(err.Errors)
-}
-
-// Swap implements sort.Interface function for swapping elements
-func (err Error) Swap(i, j int) {
- err.Errors[i], err.Errors[j] = err.Errors[j], err.Errors[i]
-}
-
-// Less implements sort.Interface function for determining order
-func (err Error) Less(i, j int) bool {
- return err.Errors[i].Error() < err.Errors[j].Error()
-}
diff --git a/vendor/github.com/hashicorp/go-retryablehttp/.gitignore b/vendor/github.com/hashicorp/go-retryablehttp/.gitignore
deleted file mode 100644
index 4e309e0b326..00000000000
--- a/vendor/github.com/hashicorp/go-retryablehttp/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.idea/
-*.iml
-*.test
-.vscode/
\ No newline at end of file
diff --git a/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml b/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml
deleted file mode 100644
index c4fb6d6c8bb..00000000000
--- a/vendor/github.com/hashicorp/go-retryablehttp/.travis.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-sudo: false
-
-language: go
-
-go:
- - 1.12.4
-
-branches:
- only:
- - master
-
-script: make updatedeps test
diff --git a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE
deleted file mode 100644
index e87a115e462..00000000000
--- a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE
+++ /dev/null
@@ -1,363 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. "Contributor"
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the terms of
- a Secondary License.
-
-1.6. "Executable Form"
-
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-
- means a work that combines Covered Software with other material, in a
- separate file or files, that is not Covered Software.
-
-1.8. "License"
-
- means this document.
-
-1.9. "Licensable"
-
- means having the right to grant, to the maximum extent possible, whether
- at the time of the initial grant or subsequently, any and all of the
- rights conveyed by this License.
-
-1.10. "Modifications"
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. "Patent Claims" of a Contributor
-
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the License,
- by the making, using, selling, offering for sale, having made, import,
- or transfer of either its Contributions or its Contributor Version.
-
-1.12. "Secondary License"
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. "Source Code Form"
-
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, "control" means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution
- become effective for each Contribution on the date the Contributor first
- distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under
- this License. No additional rights or licenses will be implied from the
- distribution or licensing of Covered Software under this License.
- Notwithstanding Section 2.1(b) above, no patent license is granted by a
- Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
- This License does not grant any rights in the trademarks, service marks,
- or logos of any Contributor (except as may be necessary to comply with
- the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this
- License (see Section 10.2) or under the terms of a Secondary License (if
- permitted under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its
- Contributions are its original creation(s) or it has sufficient rights to
- grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under
- applicable copyright doctrines of fair use, fair dealing, or other
- equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under
- the terms of this License. You must inform recipients that the Source
- Code Form of the Covered Software is governed by the terms of this
- License, and how they can obtain a copy of this License. You may not
- attempt to alter or restrict the recipients' rights in the Source Code
- Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter the
- recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for
- the Covered Software. If the Larger Work is a combination of Covered
- Software with a work governed by one or more Secondary Licenses, and the
- Covered Software is not Incompatible With Secondary Licenses, this
- License permits You to additionally distribute such Covered Software
- under the terms of such Secondary License(s), so that the recipient of
- the Larger Work may, at their option, further distribute the Covered
- Software under the terms of either this License or such Secondary
- License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices
- (including copyright notices, patent notices, disclaimers of warranty, or
- limitations of liability) contained within the Source Code Form of the
- Covered Software, except that You may alter any license notices to the
- extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on
- behalf of any Contributor. You must make it absolutely clear that any
- such warranty, support, indemnity, or liability obligation is offered by
- You alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute,
- judicial order, or regulation then You must: (a) comply with the terms of
- this License to the maximum extent possible; and (b) describe the
- limitations and the code they affect. Such description must be placed in a
- text file included with all distributions of the Covered Software under
- this License. Except to the extent prohibited by statute or regulation,
- such description must be sufficiently detailed for a recipient of ordinary
- skill to be able to understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing
- basis, if such Contributor fails to notify You of the non-compliance by
- some reasonable means prior to 60 days after You have come back into
- compliance. Moreover, Your grants from a particular Contributor are
- reinstated on an ongoing basis if such Contributor notifies You of the
- non-compliance by some reasonable means, this is the first time You have
- received notice of non-compliance with this License from such
- Contributor, and You become compliant prior to 30 days after Your receipt
- of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions,
- counter-claims, and cross-claims) alleging that a Contributor Version
- directly or indirectly infringes any patent, then the rights granted to
- You by any and all Contributors for the Covered Software under Section
- 2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an "as is" basis,
- without warranty of any kind, either expressed, implied, or statutory,
- including, without limitation, warranties that the Covered Software is free
- of defects, merchantable, fit for a particular purpose or non-infringing.
- The entire risk as to the quality and performance of the Covered Software
- is with You. Should any Covered Software prove defective in any respect,
- You (not any Contributor) assume the cost of any necessary servicing,
- repair, or correction. This disclaimer of warranty constitutes an essential
- part of this License. No use of any Covered Software is authorized under
- this License except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from
- such party's negligence to the extent applicable law prohibits such
- limitation. Some jurisdictions do not allow the exclusion or limitation of
- incidental or consequential damages, so this exclusion and limitation may
- not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts
- of a jurisdiction where the defendant maintains its principal place of
- business and such litigation shall be governed by laws of that
- jurisdiction, without reference to its conflict-of-law provisions. Nothing
- in this Section shall prevent a party's ability to bring cross-claims or
- counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. Any law or regulation which provides that
- the language of a contract shall be construed against the drafter shall not
- be used to construe this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version
- of the License under which You originally received the Covered Software,
- or under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a
- modified version of this License if you rename the license and remove
- any references to the name of the license steward (except to note that
- such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
- Licenses If You choose to distribute Source Code Form that is
- Incompatible With Secondary Licenses under the terms of this version of
- the License, the notice described in Exhibit B of this License must be
- attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file,
-then You may include the notice in a location (such as a LICENSE file in a
-relevant directory) where a recipient would be likely to look for such a
-notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
-
- This Source Code Form is "Incompatible
- With Secondary Licenses", as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/go-retryablehttp/Makefile b/vendor/github.com/hashicorp/go-retryablehttp/Makefile
deleted file mode 100644
index da17640e644..00000000000
--- a/vendor/github.com/hashicorp/go-retryablehttp/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-default: test
-
-test:
- go vet ./...
- go test -race ./...
-
-updatedeps:
- go get -f -t -u ./...
- go get -f -u ./...
-
-.PHONY: default test updatedeps
diff --git a/vendor/github.com/hashicorp/go-retryablehttp/README.md b/vendor/github.com/hashicorp/go-retryablehttp/README.md
deleted file mode 100644
index ccdc7e87cad..00000000000
--- a/vendor/github.com/hashicorp/go-retryablehttp/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-go-retryablehttp
-================
-
-[![Build Status](http://img.shields.io/travis/hashicorp/go-retryablehttp.svg?style=flat-square)][travis]
-[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
-
-[travis]: http://travis-ci.org/hashicorp/go-retryablehttp
-[godocs]: http://godoc.org/github.com/hashicorp/go-retryablehttp
-
-The `retryablehttp` package provides a familiar HTTP client interface with
-automatic retries and exponential backoff. It is a thin wrapper over the
-standard `net/http` client library and exposes nearly the same public API. This
-makes `retryablehttp` very easy to drop into existing programs.
-
-`retryablehttp` performs automatic retries under certain conditions. Mainly, if
-an error is returned by the client (connection errors, etc.), or if a 500-range
-response code is received (except 501), then a retry is invoked after a wait
-period. Otherwise, the response is returned and left to the caller to
-interpret.
-
-The main difference from `net/http` is that requests which take a request body
-(POST/PUT et. al) can have the body provided in a number of ways (some more or
-less efficient) that allow "rewinding" the request body if the initial request
-fails so that the full request can be attempted again. See the
-[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp) for more
-details.
-
-Example Use
-===========
-
-Using this library should look almost identical to what you would do with
-`net/http`. The most simple example of a GET request is shown below:
-
-```go
-resp, err := retryablehttp.Get("/foo")
-if err != nil {
- panic(err)
-}
-```
-
-The returned response object is an `*http.Response`, the same thing you would
-usually get from `net/http`. Had the request failed one or more times, the above
-call would block and retry with exponential backoff.
-
-For more usage and examples see the
-[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp).
diff --git a/vendor/github.com/hashicorp/go-retryablehttp/client.go b/vendor/github.com/hashicorp/go-retryablehttp/client.go
deleted file mode 100644
index d5e250a5bfa..00000000000
--- a/vendor/github.com/hashicorp/go-retryablehttp/client.go
+++ /dev/null
@@ -1,549 +0,0 @@
-// The retryablehttp package provides a familiar HTTP client interface with
-// automatic retries and exponential backoff. It is a thin wrapper over the
-// standard net/http client library and exposes nearly the same public API.
-// This makes retryablehttp very easy to drop into existing programs.
-//
-// retryablehttp performs automatic retries under certain conditions. Mainly, if
-// an error is returned by the client (connection errors etc), or if a 500-range
-// response is received, then a retry is invoked. Otherwise, the response is
-// returned and left to the caller to interpret.
-//
-// Requests which take a request body should provide a non-nil function
-// parameter. The best choice is to provide either a function satisfying
-// ReaderFunc which provides multiple io.Readers in an efficient manner, a
-// *bytes.Buffer (the underlying raw byte slice will be used) or a raw byte
-// slice. As it is a reference type, and we will wrap it as needed by readers,
-// we can efficiently re-use the request body without needing to copy it. If an
-// io.Reader (such as a *bytes.Reader) is provided, the full body will be read
-// prior to the first request, and will be efficiently re-used for any retries.
-// ReadSeeker can be used, but some users have observed occasional data races
-// between the net/http library and the Seek functionality of some
-// implementations of ReadSeeker, so should be avoided if possible.
-package retryablehttp
-
-import (
- "bytes"
- "context"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "math"
- "math/rand"
- "net/http"
- "net/url"
- "os"
- "strings"
- "time"
-
- cleanhttp "github.com/hashicorp/go-cleanhttp"
-)
-
-var (
- // Default retry configuration
- defaultRetryWaitMin = 1 * time.Second
- defaultRetryWaitMax = 30 * time.Second
- defaultRetryMax = 4
-
- // defaultClient is used for performing requests without explicitly making
- // a new client. It is purposely private to avoid modifications.
- defaultClient = NewClient()
-
- // We need to consume response bodies to maintain http connections, but
- // limit the size we consume to respReadLimit.
- respReadLimit = int64(4096)
-)
-
-// ReaderFunc is the type of function that can be given natively to NewRequest
-type ReaderFunc func() (io.Reader, error)
-
-// LenReader is an interface implemented by many in-memory io.Reader's. Used
-// for automatically sending the right Content-Length header when possible.
-type LenReader interface {
- Len() int
-}
-
-// Request wraps the metadata needed to create HTTP requests.
-type Request struct {
- // body is a seekable reader over the request body payload. This is
- // used to rewind the request data in between retries.
- body ReaderFunc
-
- // Embed an HTTP request directly. This makes a *Request act exactly
- // like an *http.Request so that all meta methods are supported.
- *http.Request
-}
-
-// WithContext returns wrapped Request with a shallow copy of underlying *http.Request
-// with its context changed to ctx. The provided ctx must be non-nil.
-func (r *Request) WithContext(ctx context.Context) *Request {
- r.Request = r.Request.WithContext(ctx)
- return r
-}
-
-// BodyBytes allows accessing the request body. It is an analogue to
-// http.Request's Body variable, but it returns a copy of the underlying data
-// rather than consuming it.
-//
-// This function is not thread-safe; do not call it at the same time as another
-// call, or at the same time this request is being used with Client.Do.
-func (r *Request) BodyBytes() ([]byte, error) {
- if r.body == nil {
- return nil, nil
- }
- body, err := r.body()
- if err != nil {
- return nil, err
- }
- buf := new(bytes.Buffer)
- _, err = buf.ReadFrom(body)
- if err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
-}
-
-func getBodyReaderAndContentLength(rawBody interface{}) (ReaderFunc, int64, error) {
- var bodyReader ReaderFunc
- var contentLength int64
-
- if rawBody != nil {
- switch body := rawBody.(type) {
- // If they gave us a function already, great! Use it.
- case ReaderFunc:
- bodyReader = body
- tmp, err := body()
- if err != nil {
- return nil, 0, err
- }
- if lr, ok := tmp.(LenReader); ok {
- contentLength = int64(lr.Len())
- }
- if c, ok := tmp.(io.Closer); ok {
- c.Close()
- }
-
- case func() (io.Reader, error):
- bodyReader = body
- tmp, err := body()
- if err != nil {
- return nil, 0, err
- }
- if lr, ok := tmp.(LenReader); ok {
- contentLength = int64(lr.Len())
- }
- if c, ok := tmp.(io.Closer); ok {
- c.Close()
- }
-
- // If a regular byte slice, we can read it over and over via new
- // readers
- case []byte:
- buf := body
- bodyReader = func() (io.Reader, error) {
- return bytes.NewReader(buf), nil
- }
- contentLength = int64(len(buf))
-
- // If a bytes.Buffer we can read the underlying byte slice over and
- // over
- case *bytes.Buffer:
- buf := body
- bodyReader = func() (io.Reader, error) {
- return bytes.NewReader(buf.Bytes()), nil
- }
- contentLength = int64(buf.Len())
-
- // We prioritize *bytes.Reader here because we don't really want to
- // deal with it seeking so want it to match here instead of the
- // io.ReadSeeker case.
- case *bytes.Reader:
- buf, err := ioutil.ReadAll(body)
- if err != nil {
- return nil, 0, err
- }
- bodyReader = func() (io.Reader, error) {
- return bytes.NewReader(buf), nil
- }
- contentLength = int64(len(buf))
-
- // Compat case
- case io.ReadSeeker:
- raw := body
- bodyReader = func() (io.Reader, error) {
- _, err := raw.Seek(0, 0)
- return ioutil.NopCloser(raw), err
- }
- if lr, ok := raw.(LenReader); ok {
- contentLength = int64(lr.Len())
- }
-
- // Read all in so we can reset
- case io.Reader:
- buf, err := ioutil.ReadAll(body)
- if err != nil {
- return nil, 0, err
- }
- bodyReader = func() (io.Reader, error) {
- return bytes.NewReader(buf), nil
- }
- contentLength = int64(len(buf))
-
- default:
- return nil, 0, fmt.Errorf("cannot handle type %T", rawBody)
- }
- }
- return bodyReader, contentLength, nil
-}
-
-// FromRequest wraps an http.Request in a retryablehttp.Request
-func FromRequest(r *http.Request) (*Request, error) {
- bodyReader, _, err := getBodyReaderAndContentLength(r.Body)
- if err != nil {
- return nil, err
- }
- // Could assert contentLength == r.ContentLength
- return &Request{bodyReader, r}, nil
-}
-
-// NewRequest creates a new wrapped request.
-func NewRequest(method, url string, rawBody interface{}) (*Request, error) {
- bodyReader, contentLength, err := getBodyReaderAndContentLength(rawBody)
- if err != nil {
- return nil, err
- }
-
- httpReq, err := http.NewRequest(method, url, nil)
- if err != nil {
- return nil, err
- }
- httpReq.ContentLength = contentLength
-
- return &Request{bodyReader, httpReq}, nil
-}
-
-// Logger interface allows to use other loggers than
-// standard log.Logger.
-type Logger interface {
- Printf(string, ...interface{})
-}
-
-// RequestLogHook allows a function to run before each retry. The HTTP
-// request which will be made, and the retry number (0 for the initial
-// request) are available to users. The internal logger is exposed to
-// consumers.
-type RequestLogHook func(Logger, *http.Request, int)
-
-// ResponseLogHook is like RequestLogHook, but allows running a function
-// on each HTTP response. This function will be invoked at the end of
-// every HTTP request executed, regardless of whether a subsequent retry
-// needs to be performed or not. If the response body is read or closed
-// from this method, this will affect the response returned from Do().
-type ResponseLogHook func(Logger, *http.Response)
-
-// CheckRetry specifies a policy for handling retries. It is called
-// following each request with the response and error values returned by
-// the http.Client. If CheckRetry returns false, the Client stops retrying
-// and returns the response to the caller. If CheckRetry returns an error,
-// that error value is returned in lieu of the error from the request. The
-// Client will close any response body when retrying, but if the retry is
-// aborted it is up to the CheckResponse callback to properly close any
-// response body before returning.
-type CheckRetry func(ctx context.Context, resp *http.Response, err error) (bool, error)
-
-// Backoff specifies a policy for how long to wait between retries.
-// It is called after a failing request to determine the amount of time
-// that should pass before trying again.
-type Backoff func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration
-
-// ErrorHandler is called if retries are expired, containing the last status
-// from the http library. If not specified, default behavior for the library is
-// to close the body and return an error indicating how many tries were
-// attempted. If overriding this, be sure to close the body if needed.
-type ErrorHandler func(resp *http.Response, err error, numTries int) (*http.Response, error)
-
-// Client is used to make HTTP requests. It adds additional functionality
-// like automatic retries to tolerate minor outages.
-type Client struct {
- HTTPClient *http.Client // Internal HTTP client.
- Logger Logger // Customer logger instance.
-
- RetryWaitMin time.Duration // Minimum time to wait
- RetryWaitMax time.Duration // Maximum time to wait
- RetryMax int // Maximum number of retries
-
- // RequestLogHook allows a user-supplied function to be called
- // before each retry.
- RequestLogHook RequestLogHook
-
- // ResponseLogHook allows a user-supplied function to be called
- // with the response from each HTTP request executed.
- ResponseLogHook ResponseLogHook
-
- // CheckRetry specifies the policy for handling retries, and is called
- // after each request. The default policy is DefaultRetryPolicy.
- CheckRetry CheckRetry
-
- // Backoff specifies the policy for how long to wait between retries
- Backoff Backoff
-
- // ErrorHandler specifies the custom error handler to use, if any
- ErrorHandler ErrorHandler
-}
-
-// NewClient creates a new Client with default settings.
-func NewClient() *Client {
- return &Client{
- HTTPClient: cleanhttp.DefaultClient(),
- Logger: log.New(os.Stderr, "", log.LstdFlags),
- RetryWaitMin: defaultRetryWaitMin,
- RetryWaitMax: defaultRetryWaitMax,
- RetryMax: defaultRetryMax,
- CheckRetry: DefaultRetryPolicy,
- Backoff: DefaultBackoff,
- }
-}
-
-// DefaultRetryPolicy provides a default callback for Client.CheckRetry, which
-// will retry on connection errors and server errors.
-func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
- // do not retry on context.Canceled or context.DeadlineExceeded
- if ctx.Err() != nil {
- return false, ctx.Err()
- }
-
- if err != nil {
- return true, err
- }
- // Check the response code. We retry on 500-range responses to allow
- // the server time to recover, as 500's are typically not permanent
- // errors and may relate to outages on the server side. This will catch
- // invalid response codes as well, like 0 and 999.
- if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) {
- return true, nil
- }
-
- return false, nil
-}
-
-// DefaultBackoff provides a default callback for Client.Backoff which
-// will perform exponential backoff based on the attempt number and limited
-// by the provided minimum and maximum durations.
-func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
- mult := math.Pow(2, float64(attemptNum)) * float64(min)
- sleep := time.Duration(mult)
- if float64(sleep) != mult || sleep > max {
- sleep = max
- }
- return sleep
-}
-
-// LinearJitterBackoff provides a callback for Client.Backoff which will
-// perform linear backoff based on the attempt number and with jitter to
-// prevent a thundering herd.
-//
-// min and max here are *not* absolute values. The number to be multipled by
-// the attempt number will be chosen at random from between them, thus they are
-// bounding the jitter.
-//
-// For instance:
-// * To get strictly linear backoff of one second increasing each retry, set
-// both to one second (1s, 2s, 3s, 4s, ...)
-// * To get a small amount of jitter centered around one second increasing each
-// retry, set to around one second, such as a min of 800ms and max of 1200ms
-// (892ms, 2102ms, 2945ms, 4312ms, ...)
-// * To get extreme jitter, set to a very wide spread, such as a min of 100ms
-// and a max of 20s (15382ms, 292ms, 51321ms, 35234ms, ...)
-func LinearJitterBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
- // attemptNum always starts at zero but we want to start at 1 for multiplication
- attemptNum++
-
- if max <= min {
- // Unclear what to do here, or they are the same, so return min *
- // attemptNum
- return min * time.Duration(attemptNum)
- }
-
- // Seed rand; doing this every time is fine
- rand := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
-
- // Pick a random number that lies somewhere between the min and max and
- // multiply by the attemptNum. attemptNum starts at zero so we always
- // increment here. We first get a random percentage, then apply that to the
- // difference between min and max, and add to min.
- jitter := rand.Float64() * float64(max-min)
- jitterMin := int64(jitter) + int64(min)
- return time.Duration(jitterMin * int64(attemptNum))
-}
-
-// PassthroughErrorHandler is an ErrorHandler that directly passes through the
-// values from the net/http library for the final request. The body is not
-// closed.
-func PassthroughErrorHandler(resp *http.Response, err error, _ int) (*http.Response, error) {
- return resp, err
-}
-
-// Do wraps calling an HTTP method with retries.
-func (c *Client) Do(req *Request) (*http.Response, error) {
- if c.Logger != nil {
- c.Logger.Printf("[DEBUG] %s %s", req.Method, req.URL)
- }
-
- var resp *http.Response
- var err error
-
- for i := 0; ; i++ {
- var code int // HTTP response code
-
- // Always rewind the request body when non-nil.
- if req.body != nil {
- body, err := req.body()
- if err != nil {
- return resp, err
- }
- if c, ok := body.(io.ReadCloser); ok {
- req.Body = c
- } else {
- req.Body = ioutil.NopCloser(body)
- }
- }
-
- if c.RequestLogHook != nil {
- c.RequestLogHook(c.Logger, req.Request, i)
- }
-
- // Attempt the request
- resp, err = c.HTTPClient.Do(req.Request)
- if resp != nil {
- code = resp.StatusCode
- }
-
- // Check if we should continue with retries.
- checkOK, checkErr := c.CheckRetry(req.Context(), resp, err)
-
- if err != nil {
- if c.Logger != nil {
- c.Logger.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err)
- }
- } else {
- // Call this here to maintain the behavior of logging all requests,
- // even if CheckRetry signals to stop.
- if c.ResponseLogHook != nil {
- // Call the response logger function if provided.
- c.ResponseLogHook(c.Logger, resp)
- }
- }
-
- // Now decide if we should continue.
- if !checkOK {
- if checkErr != nil {
- err = checkErr
- }
- return resp, err
- }
-
- // We do this before drainBody beause there's no need for the I/O if
- // we're breaking out
- remain := c.RetryMax - i
- if remain <= 0 {
- break
- }
-
- // We're going to retry, consume any response to reuse the connection.
- if err == nil && resp != nil {
- c.drainBody(resp.Body)
- }
-
- wait := c.Backoff(c.RetryWaitMin, c.RetryWaitMax, i, resp)
- desc := fmt.Sprintf("%s %s", req.Method, req.URL)
- if code > 0 {
- desc = fmt.Sprintf("%s (status: %d)", desc, code)
- }
- if c.Logger != nil {
- c.Logger.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain)
- }
- select {
- case <-req.Context().Done():
- return nil, req.Context().Err()
- case <-time.After(wait):
- }
- }
-
- if c.ErrorHandler != nil {
- return c.ErrorHandler(resp, err, c.RetryMax+1)
- }
-
- // By default, we close the response body and return an error without
- // returning the response
- if resp != nil {
- resp.Body.Close()
- }
- return nil, fmt.Errorf("%s %s giving up after %d attempts",
- req.Method, req.URL, c.RetryMax+1)
-}
-
-// Try to read the response body so we can reuse this connection.
-func (c *Client) drainBody(body io.ReadCloser) {
- defer body.Close()
- _, err := io.Copy(ioutil.Discard, io.LimitReader(body, respReadLimit))
- if err != nil {
- if c.Logger != nil {
- c.Logger.Printf("[ERR] error reading response body: %v", err)
- }
- }
-}
-
-// Get is a shortcut for doing a GET request without making a new client.
-func Get(url string) (*http.Response, error) {
- return defaultClient.Get(url)
-}
-
-// Get is a convenience helper for doing simple GET requests.
-func (c *Client) Get(url string) (*http.Response, error) {
- req, err := NewRequest("GET", url, nil)
- if err != nil {
- return nil, err
- }
- return c.Do(req)
-}
-
-// Head is a shortcut for doing a HEAD request without making a new client.
-func Head(url string) (*http.Response, error) {
- return defaultClient.Head(url)
-}
-
-// Head is a convenience method for doing simple HEAD requests.
-func (c *Client) Head(url string) (*http.Response, error) {
- req, err := NewRequest("HEAD", url, nil)
- if err != nil {
- return nil, err
- }
- return c.Do(req)
-}
-
-// Post is a shortcut for doing a POST request without making a new client.
-func Post(url, bodyType string, body interface{}) (*http.Response, error) {
- return defaultClient.Post(url, bodyType, body)
-}
-
-// Post is a convenience method for doing simple POST requests.
-func (c *Client) Post(url, bodyType string, body interface{}) (*http.Response, error) {
- req, err := NewRequest("POST", url, body)
- if err != nil {
- return nil, err
- }
- req.Header.Set("Content-Type", bodyType)
- return c.Do(req)
-}
-
-// PostForm is a shortcut to perform a POST with form data without creating
-// a new client.
-func PostForm(url string, data url.Values) (*http.Response, error) {
- return defaultClient.PostForm(url, data)
-}
-
-// PostForm is a convenience method for doing simple POST operations using
-// pre-filled url.Values form data.
-func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) {
- return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
-}
diff --git a/vendor/github.com/hashicorp/go-retryablehttp/go.mod b/vendor/github.com/hashicorp/go-retryablehttp/go.mod
deleted file mode 100644
index d28c8c8eb6c..00000000000
--- a/vendor/github.com/hashicorp/go-retryablehttp/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/hashicorp/go-retryablehttp
-
-require github.com/hashicorp/go-cleanhttp v0.5.0
diff --git a/vendor/github.com/hashicorp/go-retryablehttp/go.sum b/vendor/github.com/hashicorp/go-retryablehttp/go.sum
deleted file mode 100644
index 3ed0fd98e92..00000000000
--- a/vendor/github.com/hashicorp/go-retryablehttp/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
-github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
diff --git a/vendor/github.com/hashicorp/go-rootcerts/.travis.yml b/vendor/github.com/hashicorp/go-rootcerts/.travis.yml
deleted file mode 100644
index 80e1de44e96..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/.travis.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-sudo: false
-
-language: go
-
-go:
- - 1.6
-
-branches:
- only:
- - master
-
-script: make test
diff --git a/vendor/github.com/hashicorp/go-rootcerts/LICENSE b/vendor/github.com/hashicorp/go-rootcerts/LICENSE
deleted file mode 100644
index e87a115e462..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/LICENSE
+++ /dev/null
@@ -1,363 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. "Contributor"
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the terms of
- a Secondary License.
-
-1.6. "Executable Form"
-
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-
- means a work that combines Covered Software with other material, in a
- separate file or files, that is not Covered Software.
-
-1.8. "License"
-
- means this document.
-
-1.9. "Licensable"
-
- means having the right to grant, to the maximum extent possible, whether
- at the time of the initial grant or subsequently, any and all of the
- rights conveyed by this License.
-
-1.10. "Modifications"
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. "Patent Claims" of a Contributor
-
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the License,
- by the making, using, selling, offering for sale, having made, import,
- or transfer of either its Contributions or its Contributor Version.
-
-1.12. "Secondary License"
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. "Source Code Form"
-
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, "control" means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution
- become effective for each Contribution on the date the Contributor first
- distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under
- this License. No additional rights or licenses will be implied from the
- distribution or licensing of Covered Software under this License.
- Notwithstanding Section 2.1(b) above, no patent license is granted by a
- Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
- This License does not grant any rights in the trademarks, service marks,
- or logos of any Contributor (except as may be necessary to comply with
- the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this
- License (see Section 10.2) or under the terms of a Secondary License (if
- permitted under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its
- Contributions are its original creation(s) or it has sufficient rights to
- grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under
- applicable copyright doctrines of fair use, fair dealing, or other
- equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under
- the terms of this License. You must inform recipients that the Source
- Code Form of the Covered Software is governed by the terms of this
- License, and how they can obtain a copy of this License. You may not
- attempt to alter or restrict the recipients' rights in the Source Code
- Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter the
- recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for
- the Covered Software. If the Larger Work is a combination of Covered
- Software with a work governed by one or more Secondary Licenses, and the
- Covered Software is not Incompatible With Secondary Licenses, this
- License permits You to additionally distribute such Covered Software
- under the terms of such Secondary License(s), so that the recipient of
- the Larger Work may, at their option, further distribute the Covered
- Software under the terms of either this License or such Secondary
- License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices
- (including copyright notices, patent notices, disclaimers of warranty, or
- limitations of liability) contained within the Source Code Form of the
- Covered Software, except that You may alter any license notices to the
- extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on
- behalf of any Contributor. You must make it absolutely clear that any
- such warranty, support, indemnity, or liability obligation is offered by
- You alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute,
- judicial order, or regulation then You must: (a) comply with the terms of
- this License to the maximum extent possible; and (b) describe the
- limitations and the code they affect. Such description must be placed in a
- text file included with all distributions of the Covered Software under
- this License. Except to the extent prohibited by statute or regulation,
- such description must be sufficiently detailed for a recipient of ordinary
- skill to be able to understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing
- basis, if such Contributor fails to notify You of the non-compliance by
- some reasonable means prior to 60 days after You have come back into
- compliance. Moreover, Your grants from a particular Contributor are
- reinstated on an ongoing basis if such Contributor notifies You of the
- non-compliance by some reasonable means, this is the first time You have
- received notice of non-compliance with this License from such
- Contributor, and You become compliant prior to 30 days after Your receipt
- of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions,
- counter-claims, and cross-claims) alleging that a Contributor Version
- directly or indirectly infringes any patent, then the rights granted to
- You by any and all Contributors for the Covered Software under Section
- 2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an "as is" basis,
- without warranty of any kind, either expressed, implied, or statutory,
- including, without limitation, warranties that the Covered Software is free
- of defects, merchantable, fit for a particular purpose or non-infringing.
- The entire risk as to the quality and performance of the Covered Software
- is with You. Should any Covered Software prove defective in any respect,
- You (not any Contributor) assume the cost of any necessary servicing,
- repair, or correction. This disclaimer of warranty constitutes an essential
- part of this License. No use of any Covered Software is authorized under
- this License except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from
- such party's negligence to the extent applicable law prohibits such
- limitation. Some jurisdictions do not allow the exclusion or limitation of
- incidental or consequential damages, so this exclusion and limitation may
- not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts
- of a jurisdiction where the defendant maintains its principal place of
- business and such litigation shall be governed by laws of that
- jurisdiction, without reference to its conflict-of-law provisions. Nothing
- in this Section shall prevent a party's ability to bring cross-claims or
- counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. Any law or regulation which provides that
- the language of a contract shall be construed against the drafter shall not
- be used to construe this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version
- of the License under which You originally received the Covered Software,
- or under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a
- modified version of this License if you rename the license and remove
- any references to the name of the license steward (except to note that
- such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
- Licenses If You choose to distribute Source Code Form that is
- Incompatible With Secondary Licenses under the terms of this version of
- the License, the notice described in Exhibit B of this License must be
- attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file,
-then You may include the notice in a location (such as a LICENSE file in a
-relevant directory) where a recipient would be likely to look for such a
-notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
-
- This Source Code Form is "Incompatible
- With Secondary Licenses", as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/go-rootcerts/Makefile b/vendor/github.com/hashicorp/go-rootcerts/Makefile
deleted file mode 100644
index c3989e789f6..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-TEST?=./...
-
-test:
- go test $(TEST) $(TESTARGS) -timeout=3s -parallel=4
- go vet $(TEST)
- go test $(TEST) -race
-
-.PHONY: test
diff --git a/vendor/github.com/hashicorp/go-rootcerts/README.md b/vendor/github.com/hashicorp/go-rootcerts/README.md
deleted file mode 100644
index f5abffc2934..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# rootcerts
-
-Functions for loading root certificates for TLS connections.
-
------
-
-Go's standard library `crypto/tls` provides a common mechanism for configuring
-TLS connections in `tls.Config`. The `RootCAs` field on this struct is a pool
-of certificates for the client to use as a trust store when verifying server
-certificates.
-
-This library contains utility functions for loading certificates destined for
-that field, as well as one other important thing:
-
-When the `RootCAs` field is `nil`, the standard library attempts to load the
-host's root CA set. This behavior is OS-specific, and the Darwin
-implementation contains [a bug that prevents trusted certificates from the
-System and Login keychains from being loaded][1]. This library contains
-Darwin-specific behavior that works around that bug.
-
-[1]: https://github.com/golang/go/issues/14514
-
-## Example Usage
-
-Here's a snippet demonstrating how this library is meant to be used:
-
-```go
-func httpClient() (*http.Client, error)
- tlsConfig := &tls.Config{}
- err := rootcerts.ConfigureTLS(tlsConfig, &rootcerts.Config{
- CAFile: os.Getenv("MYAPP_CAFILE"),
- CAPath: os.Getenv("MYAPP_CAPATH"),
- })
- if err != nil {
- return nil, err
- }
- c := cleanhttp.DefaultClient()
- t := cleanhttp.DefaultTransport()
- t.TLSClientConfig = tlsConfig
- c.Transport = t
- return c, nil
-}
-```
diff --git a/vendor/github.com/hashicorp/go-rootcerts/doc.go b/vendor/github.com/hashicorp/go-rootcerts/doc.go
deleted file mode 100644
index b55cc628485..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/doc.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Package rootcerts contains functions to aid in loading CA certificates for
-// TLS connections.
-//
-// In addition, its default behavior on Darwin works around an open issue [1]
-// in Go's crypto/x509 that prevents certicates from being loaded from the
-// System or Login keychains.
-//
-// [1] https://github.com/golang/go/issues/14514
-package rootcerts
diff --git a/vendor/github.com/hashicorp/go-rootcerts/go.mod b/vendor/github.com/hashicorp/go-rootcerts/go.mod
deleted file mode 100644
index e2dd0247022..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/go.mod
+++ /dev/null
@@ -1,5 +0,0 @@
-module github.com/hashicorp/go-rootcerts
-
-go 1.12
-
-require github.com/mitchellh/go-homedir v1.1.0
diff --git a/vendor/github.com/hashicorp/go-rootcerts/go.sum b/vendor/github.com/hashicorp/go-rootcerts/go.sum
deleted file mode 100644
index ae38d147b45..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
diff --git a/vendor/github.com/hashicorp/go-rootcerts/rootcerts.go b/vendor/github.com/hashicorp/go-rootcerts/rootcerts.go
deleted file mode 100644
index aeb30ece324..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/rootcerts.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package rootcerts
-
-import (
- "crypto/tls"
- "crypto/x509"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
-)
-
-// Config determines where LoadCACerts will load certificates from. When both
-// CAFile and CAPath are blank, this library's functions will either load
-// system roots explicitly and return them, or set the CertPool to nil to allow
-// Go's standard library to load system certs.
-type Config struct {
- // CAFile is a path to a PEM-encoded certificate file or bundle. Takes
- // precedence over CAPath.
- CAFile string
-
- // CAPath is a path to a directory populated with PEM-encoded certificates.
- CAPath string
-}
-
-// ConfigureTLS sets up the RootCAs on the provided tls.Config based on the
-// Config specified.
-func ConfigureTLS(t *tls.Config, c *Config) error {
- if t == nil {
- return nil
- }
- pool, err := LoadCACerts(c)
- if err != nil {
- return err
- }
- t.RootCAs = pool
- return nil
-}
-
-// LoadCACerts loads a CertPool based on the Config specified.
-func LoadCACerts(c *Config) (*x509.CertPool, error) {
- if c == nil {
- c = &Config{}
- }
- if c.CAFile != "" {
- return LoadCAFile(c.CAFile)
- }
- if c.CAPath != "" {
- return LoadCAPath(c.CAPath)
- }
-
- return LoadSystemCAs()
-}
-
-// LoadCAFile loads a single PEM-encoded file from the path specified.
-func LoadCAFile(caFile string) (*x509.CertPool, error) {
- pool := x509.NewCertPool()
-
- pem, err := ioutil.ReadFile(caFile)
- if err != nil {
- return nil, fmt.Errorf("Error loading CA File: %s", err)
- }
-
- ok := pool.AppendCertsFromPEM(pem)
- if !ok {
- return nil, fmt.Errorf("Error loading CA File: Couldn't parse PEM in: %s", caFile)
- }
-
- return pool, nil
-}
-
-// LoadCAPath walks the provided path and loads all certificates encounted into
-// a pool.
-func LoadCAPath(caPath string) (*x509.CertPool, error) {
- pool := x509.NewCertPool()
- walkFn := func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- if info.IsDir() {
- return nil
- }
-
- pem, err := ioutil.ReadFile(path)
- if err != nil {
- return fmt.Errorf("Error loading file from CAPath: %s", err)
- }
-
- ok := pool.AppendCertsFromPEM(pem)
- if !ok {
- return fmt.Errorf("Error loading CA Path: Couldn't parse PEM in: %s", path)
- }
-
- return nil
- }
-
- err := filepath.Walk(caPath, walkFn)
- if err != nil {
- return nil, err
- }
-
- return pool, nil
-}
diff --git a/vendor/github.com/hashicorp/go-rootcerts/rootcerts_base.go b/vendor/github.com/hashicorp/go-rootcerts/rootcerts_base.go
deleted file mode 100644
index 66b1472c4a0..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/rootcerts_base.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build !darwin
-
-package rootcerts
-
-import "crypto/x509"
-
-// LoadSystemCAs does nothing on non-Darwin systems. We return nil so that
-// default behavior of standard TLS config libraries is triggered, which is to
-// load system certs.
-func LoadSystemCAs() (*x509.CertPool, error) {
- return nil, nil
-}
diff --git a/vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin.go b/vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin.go
deleted file mode 100644
index a9a040657fe..00000000000
--- a/vendor/github.com/hashicorp/go-rootcerts/rootcerts_darwin.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package rootcerts
-
-import (
- "crypto/x509"
- "os/exec"
- "path"
-
- "github.com/mitchellh/go-homedir"
-)
-
-// LoadSystemCAs has special behavior on Darwin systems to work around
-func LoadSystemCAs() (*x509.CertPool, error) {
- pool := x509.NewCertPool()
-
- for _, keychain := range certKeychains() {
- err := addCertsFromKeychain(pool, keychain)
- if err != nil {
- return nil, err
- }
- }
-
- return pool, nil
-}
-
-func addCertsFromKeychain(pool *x509.CertPool, keychain string) error {
- cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", keychain)
- data, err := cmd.Output()
- if err != nil {
- return err
- }
-
- pool.AppendCertsFromPEM(data)
-
- return nil
-}
-
-func certKeychains() []string {
- keychains := []string{
- "/System/Library/Keychains/SystemRootCertificates.keychain",
- "/Library/Keychains/System.keychain",
- }
- home, err := homedir.Dir()
- if err == nil {
- loginKeychain := path.Join(home, "Library", "Keychains", "login.keychain")
- keychains = append(keychains, loginKeychain)
- }
- return keychains
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/.gitignore b/vendor/github.com/hashicorp/go-sockaddr/.gitignore
deleted file mode 100644
index 41720b86e3e..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/.gitignore
+++ /dev/null
@@ -1,26 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-*.prof
-.cover.out*
-coverage.html
diff --git a/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile b/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile
deleted file mode 100644
index 0f3ae1661e2..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile
+++ /dev/null
@@ -1,65 +0,0 @@
-TOOLS= golang.org/x/tools/cover
-GOCOVER_TMPFILE?= $(GOCOVER_FILE).tmp
-GOCOVER_FILE?= .cover.out
-GOCOVERHTML?= coverage.html
-FIND=`/usr/bin/which 2> /dev/null gfind find | /usr/bin/grep -v ^no | /usr/bin/head -n 1`
-XARGS=`/usr/bin/which 2> /dev/null gxargs xargs | /usr/bin/grep -v ^no | /usr/bin/head -n 1`
-
-test:: $(GOCOVER_FILE)
- @$(MAKE) -C cmd/sockaddr test
-
-cover:: coverage_report
-
-$(GOCOVER_FILE)::
- @${FIND} . -type d ! -path '*cmd*' ! -path '*.git*' -print0 | ${XARGS} -0 -I % sh -ec "cd % && rm -f $(GOCOVER_TMPFILE) && go test -coverprofile=$(GOCOVER_TMPFILE)"
-
- @echo 'mode: set' > $(GOCOVER_FILE)
- @${FIND} . -type f ! -path '*cmd*' ! -path '*.git*' -name "$(GOCOVER_TMPFILE)" -print0 | ${XARGS} -0 -n1 cat $(GOCOVER_TMPFILE) | grep -v '^mode: ' >> ${PWD}/$(GOCOVER_FILE)
-
-$(GOCOVERHTML): $(GOCOVER_FILE)
- go tool cover -html=$(GOCOVER_FILE) -o $(GOCOVERHTML)
-
-coverage_report:: $(GOCOVER_FILE)
- go tool cover -html=$(GOCOVER_FILE)
-
-audit_tools::
- @go get -u github.com/golang/lint/golint && echo "Installed golint:"
- @go get -u github.com/fzipp/gocyclo && echo "Installed gocyclo:"
- @go get -u github.com/remyoudompheng/go-misc/deadcode && echo "Installed deadcode:"
- @go get -u github.com/client9/misspell/cmd/misspell && echo "Installed misspell:"
- @go get -u github.com/gordonklaus/ineffassign && echo "Installed ineffassign:"
-
-audit::
- deadcode
- go tool vet -all *.go
- go tool vet -shadow=true *.go
- golint *.go
- ineffassign .
- gocyclo -over 65 *.go
- misspell *.go
-
-clean::
- rm -f $(GOCOVER_FILE) $(GOCOVERHTML)
-
-dev::
- @go build
- @$(MAKE) -B -C cmd/sockaddr sockaddr
-
-install::
- @go install
- @$(MAKE) -C cmd/sockaddr install
-
-doc::
- @echo Visit: http://127.0.0.1:6161/pkg/github.com/hashicorp/go-sockaddr/
- godoc -http=:6161 -goroot $GOROOT
-
-world::
- @set -e; \
- for os in solaris darwin freebsd linux windows android; do \
- for arch in amd64; do \
- printf "Building on %s-%s\n" "$${os}" "$${arch}" ; \
- env GOOS="$${os}" GOARCH="$${arch}" go build -o /dev/null; \
- done; \
- done
-
- $(MAKE) -C cmd/sockaddr world
diff --git a/vendor/github.com/hashicorp/go-sockaddr/LICENSE b/vendor/github.com/hashicorp/go-sockaddr/LICENSE
deleted file mode 100644
index a612ad9813b..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/LICENSE
+++ /dev/null
@@ -1,373 +0,0 @@
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
- means each individual or legal entity that creates, contributes to
- the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
- means the combination of the Contributions of others (if any) used
- by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
- means Source Code Form to which the initial Contributor has attached
- the notice in Exhibit A, the Executable Form of such Source Code
- Form, and Modifications of such Source Code Form, in each case
- including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- (a) that the initial Contributor has attached the notice described
- in Exhibit B to the Covered Software; or
-
- (b) that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the
- terms of a Secondary License.
-
-1.6. "Executable Form"
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
- means a work that combines Covered Software with other material, in
- a separate file or files, that is not Covered Software.
-
-1.8. "License"
- means this document.
-
-1.9. "Licensable"
- means having the right to grant, to the maximum extent possible,
- whether at the time of the initial grant or subsequently, any and
- all of the rights conveyed by this License.
-
-1.10. "Modifications"
- means any of the following:
-
- (a) any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered
- Software; or
-
- (b) any new file in Source Code Form that contains any Covered
- Software.
-
-1.11. "Patent Claims" of a Contributor
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the
- License, by the making, using, selling, offering for sale, having
- made, import, or transfer of either its Contributions or its
- Contributor Version.
-
-1.12. "Secondary License"
- means either the GNU General Public License, Version 2.0, the GNU
- Lesser General Public License, Version 2.1, the GNU Affero General
- Public License, Version 3.0, or any later versions of those
- licenses.
-
-1.13. "Source Code Form"
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that
- controls, is controlled by, or is under common control with You. For
- purposes of this definition, "control" means (a) the power, direct
- or indirect, to cause the direction or management of such entity,
- whether by contract or otherwise, or (b) ownership of more than
- fifty percent (50%) of the outstanding shares or beneficial
- ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
- for sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
- or
-
-(b) for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
- Form, as described in Section 3.1, and You must inform recipients of
- the Executable Form how they can obtain a copy of such Source Code
- Form by reasonable means in a timely manner, at a charge no more
- than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter
- the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-* *
-* 6. Disclaimer of Warranty *
-* ------------------------- *
-* *
-* Covered Software is provided under this License on an "as is" *
-* basis, without warranty of any kind, either expressed, implied, or *
-* statutory, including, without limitation, warranties that the *
-* Covered Software is free of defects, merchantable, fit for a *
-* particular purpose or non-infringing. The entire risk as to the *
-* quality and performance of the Covered Software is with You. *
-* Should any Covered Software prove defective in any respect, You *
-* (not any Contributor) assume the cost of any necessary servicing, *
-* repair, or correction. This disclaimer of warranty constitutes an *
-* essential part of this License. No use of any Covered Software is *
-* authorized under this License except under this disclaimer. *
-* *
-************************************************************************
-
-************************************************************************
-* *
-* 7. Limitation of Liability *
-* -------------------------- *
-* *
-* Under no circumstances and under no legal theory, whether tort *
-* (including negligence), contract, or otherwise, shall any *
-* Contributor, or anyone who distributes Covered Software as *
-* permitted above, be liable to You for any direct, indirect, *
-* special, incidental, or consequential damages of any character *
-* including, without limitation, damages for lost profits, loss of *
-* goodwill, work stoppage, computer failure or malfunction, or any *
-* and all other commercial damages or losses, even if such party *
-* shall have been informed of the possibility of such damages. This *
-* limitation of liability shall not apply to liability for death or *
-* personal injury resulting from such party's negligence to the *
-* extent applicable law prohibits such limitation. Some *
-* jurisdictions do not allow the exclusion or limitation of *
-* incidental or consequential damages, so this exclusion and *
-* limitation may not apply to You. *
-* *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
- This Source Code Form is "Incompatible With Secondary Licenses", as
- defined by the Mozilla Public License, v. 2.0.
diff --git a/vendor/github.com/hashicorp/go-sockaddr/README.md b/vendor/github.com/hashicorp/go-sockaddr/README.md
deleted file mode 100644
index a2e170ae09c..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/README.md
+++ /dev/null
@@ -1,118 +0,0 @@
-# go-sockaddr
-
-## `sockaddr` Library
-
-Socket address convenience functions for Go. `go-sockaddr` is a convenience
-library that makes doing the right thing with IP addresses easy. `go-sockaddr`
-is loosely modeled after the UNIX `sockaddr_t` and creates a union of the family
-of `sockaddr_t` types (see below for an ascii diagram). Library documentation
-is available
-at
-[https://godoc.org/github.com/hashicorp/go-sockaddr](https://godoc.org/github.com/hashicorp/go-sockaddr).
-The primary intent of the library was to make it possible to define heuristics
-for selecting the correct IP addresses when a configuration is evaluated at
-runtime. See
-the
-[docs](https://godoc.org/github.com/hashicorp/go-sockaddr),
-[`template` package](https://godoc.org/github.com/hashicorp/go-sockaddr/template),
-tests,
-and
-[CLI utility](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
-for details and hints as to how to use this library.
-
-For example, with this library it is possible to find an IP address that:
-
-* is attached to a default route
- ([`GetDefaultInterfaces()`](https://godoc.org/github.com/hashicorp/go-sockaddr#GetDefaultInterfaces))
-* is contained within a CIDR block ([`IfByNetwork()`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByNetwork))
-* is an RFC1918 address
- ([`IfByRFC("1918")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
-* is ordered
- ([`OrderedIfAddrBy(args)`](https://godoc.org/github.com/hashicorp/go-sockaddr#OrderedIfAddrBy) where
- `args` includes, but is not limited
- to,
- [`AscIfType`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscIfType),
- [`AscNetworkSize`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscNetworkSize))
-* excludes all IPv6 addresses
- ([`IfByType("^(IPv4)$")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByType))
-* is larger than a `/32`
- ([`IfByMaskSize(32)`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByMaskSize))
-* is not on a `down` interface
- ([`ExcludeIfs("flags", "down")`](https://godoc.org/github.com/hashicorp/go-sockaddr#ExcludeIfs))
-* preferences an IPv6 address over an IPv4 address
- ([`SortIfByType()`](https://godoc.org/github.com/hashicorp/go-sockaddr#SortIfByType) +
- [`ReverseIfAddrs()`](https://godoc.org/github.com/hashicorp/go-sockaddr#ReverseIfAddrs)); and
-* excludes any IP in RFC6890 address
- ([`IfByRFC("6890")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC))
-
-Or any combination or variation therein.
-
-There are also a few simple helper functions such as `GetPublicIP` and
-`GetPrivateIP` which both return strings and select the first public or private
-IP address on the default interface, respectively. Similarly, there is also a
-helper function called `GetInterfaceIP` which returns the first usable IP
-address on the named interface.
-
-## `sockaddr` CLI
-
-Given the possible complexity of the `sockaddr` library, there is a CLI utility
-that accompanies the library, also
-called
-[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr).
-The
-[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr)
-utility exposes nearly all of the functionality of the library and can be used
-either as an administrative tool or testing tool. To install
-the
-[`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr),
-run:
-
-```text
-$ go get -u github.com/hashicorp/go-sockaddr/cmd/sockaddr
-```
-
-If you're familiar with UNIX's `sockaddr` struct's, the following diagram
-mapping the C `sockaddr` (top) to `go-sockaddr` structs (bottom) and
-interfaces will be helpful:
-
-```
-+-------------------------------------------------------+
-| |
-| sockaddr |
-| SockAddr |
-| |
-| +--------------+ +----------------------------------+ |
-| | sockaddr_un | | | |
-| | SockAddrUnix | | sockaddr_in{,6} | |
-| +--------------+ | IPAddr | |
-| | | |
-| | +-------------+ +--------------+ | |
-| | | sockaddr_in | | sockaddr_in6 | | |
-| | | IPv4Addr | | IPv6Addr | | |
-| | +-------------+ +--------------+ | |
-| | | |
-| +----------------------------------+ |
-| |
-+-------------------------------------------------------+
-```
-
-## Inspiration and Design
-
-There were many subtle inspirations that led to this design, but the most direct
-inspiration for the filtering syntax was
-OpenBSD's
-[`pf.conf(5)`](https://www.freebsd.org/cgi/man.cgi?query=pf.conf&apropos=0&sektion=0&arch=default&format=html#PARAMETERS) firewall
-syntax that lets you select the first IP address on a given named interface.
-The original problem stemmed from:
-
-* needing to create immutable images using [Packer](https://www.packer.io) that
- ran the [Consul](https://www.consul.io) process (Consul can only use one IP
- address at a time);
-* images that may or may not have multiple interfaces or IP addresses at
- runtime; and
-* we didn't want to rely on configuration management to render out the correct
- IP address if the VM image was being used in an auto-scaling group.
-
-Instead we needed some way to codify a heuristic that would correctly select the
-right IP address but the input parameters were not known when the image was
-created.
diff --git a/vendor/github.com/hashicorp/go-sockaddr/doc.go b/vendor/github.com/hashicorp/go-sockaddr/doc.go
deleted file mode 100644
index 90671deb51d..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/doc.go
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
-Package sockaddr is a Go implementation of the UNIX socket family data types and
-related helper functions.
-*/
-package sockaddr
diff --git a/vendor/github.com/hashicorp/go-sockaddr/go.mod b/vendor/github.com/hashicorp/go-sockaddr/go.mod
deleted file mode 100644
index 21f8d8e8e75..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/go.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-module github.com/hashicorp/go-sockaddr
-
-require (
- github.com/hashicorp/errwrap v1.0.0
- github.com/mitchellh/cli v1.0.0
- github.com/mitchellh/go-wordwrap v1.0.0
- github.com/ryanuber/columnize v2.1.0+incompatible
-)
diff --git a/vendor/github.com/hashicorp/go-sockaddr/go.sum b/vendor/github.com/hashicorp/go-sockaddr/go.sum
deleted file mode 100644
index 1b2bdd48280..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/go.sum
+++ /dev/null
@@ -1,24 +0,0 @@
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
-github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
-github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc h1:MeuS1UDyZyFH++6vVy44PuufTeFF0d0nfI6XB87YGSk=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go
deleted file mode 100644
index 0811b275990..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go
+++ /dev/null
@@ -1,254 +0,0 @@
-package sockaddr
-
-import "strings"
-
-// ifAddrAttrMap is a map of the IfAddr type-specific attributes.
-var ifAddrAttrMap map[AttrName]func(IfAddr) string
-var ifAddrAttrs []AttrName
-
-func init() {
- ifAddrAttrInit()
-}
-
-// GetPrivateIP returns a string with a single IP address that is part of RFC
-// 6890 and has a default route. If the system can't determine its IP address
-// or find an RFC 6890 IP address, an empty string will be returned instead.
-// This function is the `eval` equivalent of:
-//
-// ```
-// $ sockaddr eval -r '{{GetPrivateInterfaces | attr "address"}}'
-/// ```
-func GetPrivateIP() (string, error) {
- privateIfs, err := GetPrivateInterfaces()
- if err != nil {
- return "", err
- }
- if len(privateIfs) < 1 {
- return "", nil
- }
-
- ifAddr := privateIfs[0]
- ip := *ToIPAddr(ifAddr.SockAddr)
- return ip.NetIP().String(), nil
-}
-
-// GetPrivateIPs returns a string with all IP addresses that are part of RFC
-// 6890 (regardless of whether or not there is a default route, unlike
-// GetPublicIP). If the system can't find any RFC 6890 IP addresses, an empty
-// string will be returned instead. This function is the `eval` equivalent of:
-//
-// ```
-// $ sockaddr eval -r '{{GetAllInterfaces | include "RFC" "6890" | join "address" " "}}'
-/// ```
-func GetPrivateIPs() (string, error) {
- ifAddrs, err := GetAllInterfaces()
- if err != nil {
- return "", err
- } else if len(ifAddrs) < 1 {
- return "", nil
- }
-
- ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP)
- if len(ifAddrs) == 0 {
- return "", nil
- }
-
- OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs)
-
- ifAddrs, _, err = IfByRFC("6890", ifAddrs)
- if err != nil {
- return "", err
- } else if len(ifAddrs) == 0 {
- return "", nil
- }
-
- _, ifAddrs, err = IfByRFC(ForwardingBlacklistRFC, ifAddrs)
- if err != nil {
- return "", err
- } else if len(ifAddrs) == 0 {
- return "", nil
- }
-
- ips := make([]string, 0, len(ifAddrs))
- for _, ifAddr := range ifAddrs {
- ip := *ToIPAddr(ifAddr.SockAddr)
- s := ip.NetIP().String()
- ips = append(ips, s)
- }
-
- return strings.Join(ips, " "), nil
-}
-
-// GetPublicIP returns a string with a single IP address that is NOT part of RFC
-// 6890 and has a default route. If the system can't determine its IP address
-// or find a non RFC 6890 IP address, an empty string will be returned instead.
-// This function is the `eval` equivalent of:
-//
-// ```
-// $ sockaddr eval -r '{{GetPublicInterfaces | attr "address"}}'
-/// ```
-func GetPublicIP() (string, error) {
- publicIfs, err := GetPublicInterfaces()
- if err != nil {
- return "", err
- } else if len(publicIfs) < 1 {
- return "", nil
- }
-
- ifAddr := publicIfs[0]
- ip := *ToIPAddr(ifAddr.SockAddr)
- return ip.NetIP().String(), nil
-}
-
-// GetPublicIPs returns a string with all IP addresses that are NOT part of RFC
-// 6890 (regardless of whether or not there is a default route, unlike
-// GetPublicIP). If the system can't find any non RFC 6890 IP addresses, an
-// empty string will be returned instead. This function is the `eval`
-// equivalent of:
-//
-// ```
-// $ sockaddr eval -r '{{GetAllInterfaces | exclude "RFC" "6890" | join "address" " "}}'
-/// ```
-func GetPublicIPs() (string, error) {
- ifAddrs, err := GetAllInterfaces()
- if err != nil {
- return "", err
- } else if len(ifAddrs) < 1 {
- return "", nil
- }
-
- ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP)
- if len(ifAddrs) == 0 {
- return "", nil
- }
-
- OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs)
-
- _, ifAddrs, err = IfByRFC("6890", ifAddrs)
- if err != nil {
- return "", err
- } else if len(ifAddrs) == 0 {
- return "", nil
- }
-
- ips := make([]string, 0, len(ifAddrs))
- for _, ifAddr := range ifAddrs {
- ip := *ToIPAddr(ifAddr.SockAddr)
- s := ip.NetIP().String()
- ips = append(ips, s)
- }
-
- return strings.Join(ips, " "), nil
-}
-
-// GetInterfaceIP returns a string with a single IP address sorted by the size
-// of the network (i.e. IP addresses with a smaller netmask, larger network
-// size, are sorted first). This function is the `eval` equivalent of:
-//
-// ```
-// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | include "flag" "forwardable" | attr "address" }}'
-/// ```
-func GetInterfaceIP(namedIfRE string) (string, error) {
- ifAddrs, err := GetAllInterfaces()
- if err != nil {
- return "", err
- }
-
- ifAddrs, _, err = IfByName(namedIfRE, ifAddrs)
- if err != nil {
- return "", err
- }
-
- ifAddrs, _, err = IfByFlag("forwardable", ifAddrs)
- if err != nil {
- return "", err
- }
-
- ifAddrs, err = SortIfBy("+type,+size", ifAddrs)
- if err != nil {
- return "", err
- }
-
- if len(ifAddrs) == 0 {
- return "", err
- }
-
- ip := ToIPAddr(ifAddrs[0].SockAddr)
- if ip == nil {
- return "", err
- }
-
- return IPAddrAttr(*ip, "address"), nil
-}
-
-// GetInterfaceIPs returns a string with all IPs, sorted by the size of the
-// network (i.e. IP addresses with a smaller netmask, larger network size, are
-// sorted first), on a named interface. This function is the `eval` equivalent
-// of:
-//
-// ```
-// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | join "address" " "}}'
-/// ```
-func GetInterfaceIPs(namedIfRE string) (string, error) {
- ifAddrs, err := GetAllInterfaces()
- if err != nil {
- return "", err
- }
-
- ifAddrs, _, err = IfByName(namedIfRE, ifAddrs)
- if err != nil {
- return "", err
- }
-
- ifAddrs, err = SortIfBy("+type,+size", ifAddrs)
- if err != nil {
- return "", err
- }
-
- if len(ifAddrs) == 0 {
- return "", err
- }
-
- ips := make([]string, 0, len(ifAddrs))
- for _, ifAddr := range ifAddrs {
- ip := *ToIPAddr(ifAddr.SockAddr)
- s := ip.NetIP().String()
- ips = append(ips, s)
- }
-
- return strings.Join(ips, " "), nil
-}
-
-// IfAddrAttrs returns a list of attributes supported by the IfAddr type
-func IfAddrAttrs() []AttrName {
- return ifAddrAttrs
-}
-
-// IfAddrAttr returns a string representation of an attribute for the given
-// IfAddr.
-func IfAddrAttr(ifAddr IfAddr, attrName AttrName) string {
- fn, found := ifAddrAttrMap[attrName]
- if !found {
- return ""
- }
-
- return fn(ifAddr)
-}
-
-// ifAddrAttrInit is called once at init()
-func ifAddrAttrInit() {
- // Sorted for human readability
- ifAddrAttrs = []AttrName{
- "flags",
- "name",
- }
-
- ifAddrAttrMap = map[AttrName]func(ifAddr IfAddr) string{
- "flags": func(ifAddr IfAddr) string {
- return ifAddr.Interface.Flags.String()
- },
- "name": func(ifAddr IfAddr) string {
- return ifAddr.Interface.Name
- },
- }
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
deleted file mode 100644
index 80f61bef680..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
+++ /dev/null
@@ -1,1304 +0,0 @@
-package sockaddr
-
-import (
- "encoding/binary"
- "errors"
- "fmt"
- "math/big"
- "net"
- "regexp"
- "sort"
- "strconv"
- "strings"
-)
-
-var (
- // Centralize all regexps and regexp.Copy() where necessary.
- signRE *regexp.Regexp = regexp.MustCompile(`^[\s]*[+-]`)
- whitespaceRE *regexp.Regexp = regexp.MustCompile(`[\s]+`)
- ifNameRE *regexp.Regexp = regexp.MustCompile(`^(?:Ethernet|Wireless LAN) adapter ([^:]+):`)
- ipAddrRE *regexp.Regexp = regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`)
-)
-
-// IfAddrs is a slice of IfAddr
-type IfAddrs []IfAddr
-
-func (ifs IfAddrs) Len() int { return len(ifs) }
-
-// CmpIfFunc is the function signature that must be met to be used in the
-// OrderedIfAddrBy multiIfAddrSorter
-type CmpIfAddrFunc func(p1, p2 *IfAddr) int
-
-// multiIfAddrSorter implements the Sort interface, sorting the IfAddrs within.
-type multiIfAddrSorter struct {
- ifAddrs IfAddrs
- cmp []CmpIfAddrFunc
-}
-
-// Sort sorts the argument slice according to the Cmp functions passed to
-// OrderedIfAddrBy.
-func (ms *multiIfAddrSorter) Sort(ifAddrs IfAddrs) {
- ms.ifAddrs = ifAddrs
- sort.Sort(ms)
-}
-
-// OrderedIfAddrBy sorts SockAddr by the list of sort function pointers.
-func OrderedIfAddrBy(cmpFuncs ...CmpIfAddrFunc) *multiIfAddrSorter {
- return &multiIfAddrSorter{
- cmp: cmpFuncs,
- }
-}
-
-// Len is part of sort.Interface.
-func (ms *multiIfAddrSorter) Len() int {
- return len(ms.ifAddrs)
-}
-
-// Less is part of sort.Interface. It is implemented by looping along the Cmp()
-// functions until it finds a comparison that is either less than or greater
-// than. A return value of 0 defers sorting to the next function in the
-// multisorter (which means the results of sorting may leave the resutls in a
-// non-deterministic order).
-func (ms *multiIfAddrSorter) Less(i, j int) bool {
- p, q := &ms.ifAddrs[i], &ms.ifAddrs[j]
- // Try all but the last comparison.
- var k int
- for k = 0; k < len(ms.cmp)-1; k++ {
- cmp := ms.cmp[k]
- x := cmp(p, q)
- switch x {
- case -1:
- // p < q, so we have a decision.
- return true
- case 1:
- // p > q, so we have a decision.
- return false
- }
- // p == q; try the next comparison.
- }
- // All comparisons to here said "equal", so just return whatever the
- // final comparison reports.
- switch ms.cmp[k](p, q) {
- case -1:
- return true
- case 1:
- return false
- default:
- // Still a tie! Now what?
- return false
- panic("undefined sort order for remaining items in the list")
- }
-}
-
-// Swap is part of sort.Interface.
-func (ms *multiIfAddrSorter) Swap(i, j int) {
- ms.ifAddrs[i], ms.ifAddrs[j] = ms.ifAddrs[j], ms.ifAddrs[i]
-}
-
-// AscIfAddress is a sorting function to sort IfAddrs by their respective
-// address type. Non-equal types are deferred in the sort.
-func AscIfAddress(p1Ptr, p2Ptr *IfAddr) int {
- return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// AscIfDefault is a sorting function to sort IfAddrs by whether or not they
-// have a default route or not. Non-equal types are deferred in the sort.
-//
-// FIXME: This is a particularly expensive sorting operation because of the
-// non-memoized calls to NewRouteInfo(). In an ideal world the routeInfo data
-// once at the start of the sort and pass it along as a context or by wrapping
-// the IfAddr type with this information (this would also solve the inability to
-// return errors and the possibility of failing silently). Fortunately,
-// N*log(N) where N = 3 is only ~6.2 invocations. Not ideal, but not worth
-// optimizing today. The common case is this gets called once or twice.
-// Patches welcome.
-func AscIfDefault(p1Ptr, p2Ptr *IfAddr) int {
- ri, err := NewRouteInfo()
- if err != nil {
- return sortDeferDecision
- }
-
- defaultIfName, err := ri.GetDefaultInterfaceName()
- if err != nil {
- return sortDeferDecision
- }
-
- switch {
- case p1Ptr.Interface.Name == defaultIfName && p2Ptr.Interface.Name == defaultIfName:
- return sortDeferDecision
- case p1Ptr.Interface.Name == defaultIfName:
- return sortReceiverBeforeArg
- case p2Ptr.Interface.Name == defaultIfName:
- return sortArgBeforeReceiver
- default:
- return sortDeferDecision
- }
-}
-
-// AscIfName is a sorting function to sort IfAddrs by their interface names.
-func AscIfName(p1Ptr, p2Ptr *IfAddr) int {
- return strings.Compare(p1Ptr.Name, p2Ptr.Name)
-}
-
-// AscIfNetworkSize is a sorting function to sort IfAddrs by their respective
-// network mask size.
-func AscIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int {
- return AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// AscIfPort is a sorting function to sort IfAddrs by their respective
-// port type. Non-equal types are deferred in the sort.
-func AscIfPort(p1Ptr, p2Ptr *IfAddr) int {
- return AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// AscIfPrivate is a sorting function to sort IfAddrs by "private" values before
-// "public" values. Both IPv4 and IPv6 are compared against RFC6890 (RFC6890
-// includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and IPv6
-// includes RFC4193).
-func AscIfPrivate(p1Ptr, p2Ptr *IfAddr) int {
- return AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// AscIfType is a sorting function to sort IfAddrs by their respective address
-// type. Non-equal types are deferred in the sort.
-func AscIfType(p1Ptr, p2Ptr *IfAddr) int {
- return AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// DescIfAddress is identical to AscIfAddress but reverse ordered.
-func DescIfAddress(p1Ptr, p2Ptr *IfAddr) int {
- return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// DescIfDefault is identical to AscIfDefault but reverse ordered.
-func DescIfDefault(p1Ptr, p2Ptr *IfAddr) int {
- return -1 * AscIfDefault(p1Ptr, p2Ptr)
-}
-
-// DescIfName is identical to AscIfName but reverse ordered.
-func DescIfName(p1Ptr, p2Ptr *IfAddr) int {
- return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name)
-}
-
-// DescIfNetworkSize is identical to AscIfNetworkSize but reverse ordered.
-func DescIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int {
- return -1 * AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// DescIfPort is identical to AscIfPort but reverse ordered.
-func DescIfPort(p1Ptr, p2Ptr *IfAddr) int {
- return -1 * AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// DescIfPrivate is identical to AscIfPrivate but reverse ordered.
-func DescIfPrivate(p1Ptr, p2Ptr *IfAddr) int {
- return -1 * AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// DescIfType is identical to AscIfType but reverse ordered.
-func DescIfType(p1Ptr, p2Ptr *IfAddr) int {
- return -1 * AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
-}
-
-// FilterIfByType filters IfAddrs and returns a list of the matching type
-func FilterIfByType(ifAddrs IfAddrs, type_ SockAddrType) (matchedIfs, excludedIfs IfAddrs) {
- excludedIfs = make(IfAddrs, 0, len(ifAddrs))
- matchedIfs = make(IfAddrs, 0, len(ifAddrs))
-
- for _, ifAddr := range ifAddrs {
- if ifAddr.SockAddr.Type()&type_ != 0 {
- matchedIfs = append(matchedIfs, ifAddr)
- } else {
- excludedIfs = append(excludedIfs, ifAddr)
- }
- }
- return matchedIfs, excludedIfs
-}
-
-// IfAttr forwards the selector to IfAttr.Attr() for resolution. If there is
-// more than one IfAddr, only the first IfAddr is used.
-func IfAttr(selectorName string, ifAddr IfAddr) (string, error) {
- attrName := AttrName(strings.ToLower(selectorName))
- attrVal, err := ifAddr.Attr(attrName)
- return attrVal, err
-}
-
-// IfAttrs forwards the selector to IfAttrs.Attr() for resolution. If there is
-// more than one IfAddr, only the first IfAddr is used.
-func IfAttrs(selectorName string, ifAddrs IfAddrs) (string, error) {
- if len(ifAddrs) == 0 {
- return "", nil
- }
-
- attrName := AttrName(strings.ToLower(selectorName))
- attrVal, err := ifAddrs[0].Attr(attrName)
- return attrVal, err
-}
-
-// GetAllInterfaces iterates over all available network interfaces and finds all
-// available IP addresses on each interface and converts them to
-// sockaddr.IPAddrs, and returning the result as an array of IfAddr.
-func GetAllInterfaces() (IfAddrs, error) {
- ifs, err := net.Interfaces()
- if err != nil {
- return nil, err
- }
-
- ifAddrs := make(IfAddrs, 0, len(ifs))
- for _, intf := range ifs {
- addrs, err := intf.Addrs()
- if err != nil {
- return nil, err
- }
-
- for _, addr := range addrs {
- var ipAddr IPAddr
- ipAddr, err = NewIPAddr(addr.String())
- if err != nil {
- return IfAddrs{}, fmt.Errorf("unable to create an IP address from %q", addr.String())
- }
-
- ifAddr := IfAddr{
- SockAddr: ipAddr,
- Interface: intf,
- }
- ifAddrs = append(ifAddrs, ifAddr)
- }
- }
-
- return ifAddrs, nil
-}
-
-// GetDefaultInterfaces returns IfAddrs of the addresses attached to the default
-// route.
-func GetDefaultInterfaces() (IfAddrs, error) {
- ri, err := NewRouteInfo()
- if err != nil {
- return nil, err
- }
-
- defaultIfName, err := ri.GetDefaultInterfaceName()
- if err != nil {
- return nil, err
- }
-
- var defaultIfs, ifAddrs IfAddrs
- ifAddrs, err = GetAllInterfaces()
- for _, ifAddr := range ifAddrs {
- if ifAddr.Name == defaultIfName {
- defaultIfs = append(defaultIfs, ifAddr)
- }
- }
-
- return defaultIfs, nil
-}
-
-// GetPrivateInterfaces returns an IfAddrs that are part of RFC 6890 and have a
-// default route. If the system can't determine its IP address or find an RFC
-// 6890 IP address, an empty IfAddrs will be returned instead. This function is
-// the `eval` equivalent of:
-//
-// ```
-// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | include "RFC" "6890" }}'
-/// ```
-func GetPrivateInterfaces() (IfAddrs, error) {
- privateIfs, err := GetAllInterfaces()
- if err != nil {
- return IfAddrs{}, err
- }
- if len(privateIfs) == 0 {
- return IfAddrs{}, nil
- }
-
- privateIfs, _ = FilterIfByType(privateIfs, TypeIP)
- if len(privateIfs) == 0 {
- return IfAddrs{}, nil
- }
-
- privateIfs, _, err = IfByFlag("forwardable", privateIfs)
- if err != nil {
- return IfAddrs{}, err
- }
-
- privateIfs, _, err = IfByFlag("up", privateIfs)
- if err != nil {
- return IfAddrs{}, err
- }
-
- if len(privateIfs) == 0 {
- return IfAddrs{}, nil
- }
-
- OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(privateIfs)
-
- privateIfs, _, err = IfByRFC("6890", privateIfs)
- if err != nil {
- return IfAddrs{}, err
- } else if len(privateIfs) == 0 {
- return IfAddrs{}, nil
- }
-
- return privateIfs, nil
-}
-
-// GetPublicInterfaces returns an IfAddrs that are NOT part of RFC 6890 and has a
-// default route. If the system can't determine its IP address or find a non
-// RFC 6890 IP address, an empty IfAddrs will be returned instead. This
-// function is the `eval` equivalent of:
-//
-// ```
-// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | exclude "RFC" "6890" }}'
-/// ```
-func GetPublicInterfaces() (IfAddrs, error) {
- publicIfs, err := GetAllInterfaces()
- if err != nil {
- return IfAddrs{}, err
- }
- if len(publicIfs) == 0 {
- return IfAddrs{}, nil
- }
-
- publicIfs, _ = FilterIfByType(publicIfs, TypeIP)
- if len(publicIfs) == 0 {
- return IfAddrs{}, nil
- }
-
- publicIfs, _, err = IfByFlag("forwardable", publicIfs)
- if err != nil {
- return IfAddrs{}, err
- }
-
- publicIfs, _, err = IfByFlag("up", publicIfs)
- if err != nil {
- return IfAddrs{}, err
- }
-
- if len(publicIfs) == 0 {
- return IfAddrs{}, nil
- }
-
- OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(publicIfs)
-
- _, publicIfs, err = IfByRFC("6890", publicIfs)
- if err != nil {
- return IfAddrs{}, err
- } else if len(publicIfs) == 0 {
- return IfAddrs{}, nil
- }
-
- return publicIfs, nil
-}
-
-// IfByAddress returns a list of matched and non-matched IfAddrs, or an error if
-// the regexp fails to compile.
-func IfByAddress(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
- re, err := regexp.Compile(inputRe)
- if err != nil {
- return nil, nil, fmt.Errorf("Unable to compile address regexp %+q: %v", inputRe, err)
- }
-
- matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
- excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
- for _, addr := range ifAddrs {
- if re.MatchString(addr.SockAddr.String()) {
- matchedAddrs = append(matchedAddrs, addr)
- } else {
- excludedAddrs = append(excludedAddrs, addr)
- }
- }
-
- return matchedAddrs, excludedAddrs, nil
-}
-
-// IfByName returns a list of matched and non-matched IfAddrs, or an error if
-// the regexp fails to compile.
-func IfByName(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
- re, err := regexp.Compile(inputRe)
- if err != nil {
- return nil, nil, fmt.Errorf("Unable to compile name regexp %+q: %v", inputRe, err)
- }
-
- matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
- excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
- for _, addr := range ifAddrs {
- if re.MatchString(addr.Name) {
- matchedAddrs = append(matchedAddrs, addr)
- } else {
- excludedAddrs = append(excludedAddrs, addr)
- }
- }
-
- return matchedAddrs, excludedAddrs, nil
-}
-
-// IfByPort returns a list of matched and non-matched IfAddrs, or an error if
-// the regexp fails to compile.
-func IfByPort(inputRe string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) {
- re, err := regexp.Compile(inputRe)
- if err != nil {
- return nil, nil, fmt.Errorf("Unable to compile port regexp %+q: %v", inputRe, err)
- }
-
- ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP)
- matchedIfs = make(IfAddrs, 0, len(ipIfs))
- excludedIfs = append(IfAddrs(nil), nonIfs...)
- for _, addr := range ipIfs {
- ipAddr := ToIPAddr(addr.SockAddr)
- if ipAddr == nil {
- continue
- }
-
- port := strconv.FormatInt(int64((*ipAddr).IPPort()), 10)
- if re.MatchString(port) {
- matchedIfs = append(matchedIfs, addr)
- } else {
- excludedIfs = append(excludedIfs, addr)
- }
- }
-
- return matchedIfs, excludedIfs, nil
-}
-
-// IfByRFC returns a list of matched and non-matched IfAddrs that contain the
-// relevant RFC-specified traits.
-func IfByRFC(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
- inputRFC, err := strconv.ParseUint(selectorParam, 10, 64)
- if err != nil {
- return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to parse RFC number %q: %v", selectorParam, err)
- }
-
- matchedIfAddrs := make(IfAddrs, 0, len(ifAddrs))
- remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
-
- rfcNetMap := KnownRFCs()
- rfcNets, ok := rfcNetMap[uint(inputRFC)]
- if !ok {
- return nil, nil, fmt.Errorf("unsupported RFC %d", inputRFC)
- }
-
- for _, ifAddr := range ifAddrs {
- var contained bool
- for _, rfcNet := range rfcNets {
- if rfcNet.Contains(ifAddr.SockAddr) {
- matchedIfAddrs = append(matchedIfAddrs, ifAddr)
- contained = true
- break
- }
- }
- if !contained {
- remainingIfAddrs = append(remainingIfAddrs, ifAddr)
- }
- }
-
- return matchedIfAddrs, remainingIfAddrs, nil
-}
-
-// IfByRFCs returns a list of matched and non-matched IfAddrs that contain the
-// relevant RFC-specified traits. Multiple RFCs can be specified and separated
-// by the `|` symbol. No protection is taken to ensure an IfAddr does not end
-// up in both the included and excluded list.
-func IfByRFCs(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
- var includedIfs, excludedIfs IfAddrs
- for _, rfcStr := range strings.Split(selectorParam, "|") {
- includedRFCIfs, excludedRFCIfs, err := IfByRFC(rfcStr, ifAddrs)
- if err != nil {
- return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to lookup RFC number %q: %v", rfcStr, err)
- }
- includedIfs = append(includedIfs, includedRFCIfs...)
- excludedIfs = append(excludedIfs, excludedRFCIfs...)
- }
-
- return includedIfs, excludedIfs, nil
-}
-
-// IfByMaskSize returns a list of matched and non-matched IfAddrs that have the
-// matching mask size.
-func IfByMaskSize(selectorParam string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) {
- maskSize, err := strconv.ParseUint(selectorParam, 10, 64)
- if err != nil {
- return IfAddrs{}, IfAddrs{}, fmt.Errorf("invalid exclude size argument (%q): %v", selectorParam, err)
- }
-
- ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP)
- matchedIfs = make(IfAddrs, 0, len(ipIfs))
- excludedIfs = append(IfAddrs(nil), nonIfs...)
- for _, addr := range ipIfs {
- ipAddr := ToIPAddr(addr.SockAddr)
- if ipAddr == nil {
- return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to filter mask sizes on non-IP type %s: %v", addr.SockAddr.Type().String(), addr.SockAddr.String())
- }
-
- switch {
- case (*ipAddr).Type()&TypeIPv4 != 0 && maskSize > 32:
- return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv4 address: %d", maskSize)
- case (*ipAddr).Type()&TypeIPv6 != 0 && maskSize > 128:
- return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv6 address: %d", maskSize)
- }
-
- if (*ipAddr).Maskbits() == int(maskSize) {
- matchedIfs = append(matchedIfs, addr)
- } else {
- excludedIfs = append(excludedIfs, addr)
- }
- }
-
- return matchedIfs, excludedIfs, nil
-}
-
-// IfByType returns a list of matching and non-matching IfAddr that match the
-// specified type. For instance:
-//
-// include "type" "IPv4,IPv6"
-//
-// will include any IfAddrs that is either an IPv4 or IPv6 address. Any
-// addresses on those interfaces that don't match will be included in the
-// remainder results.
-func IfByType(inputTypes string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
- matchingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
- remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs))
-
- ifTypes := strings.Split(strings.ToLower(inputTypes), "|")
- for _, ifType := range ifTypes {
- switch ifType {
- case "ip", "ipv4", "ipv6", "unix":
- // Valid types
- default:
- return nil, nil, fmt.Errorf("unsupported type %q %q", ifType, inputTypes)
- }
- }
-
- for _, ifAddr := range ifAddrs {
- for _, ifType := range ifTypes {
- var matched bool
- switch {
- case ifType == "ip" && ifAddr.SockAddr.Type()&TypeIP != 0:
- matched = true
- case ifType == "ipv4" && ifAddr.SockAddr.Type()&TypeIPv4 != 0:
- matched = true
- case ifType == "ipv6" && ifAddr.SockAddr.Type()&TypeIPv6 != 0:
- matched = true
- case ifType == "unix" && ifAddr.SockAddr.Type()&TypeUnix != 0:
- matched = true
- }
-
- if matched {
- matchingIfAddrs = append(matchingIfAddrs, ifAddr)
- } else {
- remainingIfAddrs = append(remainingIfAddrs, ifAddr)
- }
- }
- }
-
- return matchingIfAddrs, remainingIfAddrs, nil
-}
-
-// IfByFlag returns a list of matching and non-matching IfAddrs that match the
-// specified type. For instance:
-//
-// include "flag" "up,broadcast"
-//
-// will include any IfAddrs that have both the "up" and "broadcast" flags set.
-// Any addresses on those interfaces that don't match will be omitted from the
-// results.
-func IfByFlag(inputFlags string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) {
- matchedAddrs := make(IfAddrs, 0, len(ifAddrs))
- excludedAddrs := make(IfAddrs, 0, len(ifAddrs))
-
- var wantForwardable,
- wantGlobalUnicast,
- wantInterfaceLocalMulticast,
- wantLinkLocalMulticast,
- wantLinkLocalUnicast,
- wantLoopback,
- wantMulticast,
- wantUnspecified bool
- var ifFlags net.Flags
- var checkFlags, checkAttrs bool
- for _, flagName := range strings.Split(strings.ToLower(inputFlags), "|") {
- switch flagName {
- case "broadcast":
- checkFlags = true
- ifFlags = ifFlags | net.FlagBroadcast
- case "down":
- checkFlags = true
- ifFlags = (ifFlags &^ net.FlagUp)
- case "forwardable":
- checkAttrs = true
- wantForwardable = true
- case "global unicast":
- checkAttrs = true
- wantGlobalUnicast = true
- case "interface-local multicast":
- checkAttrs = true
- wantInterfaceLocalMulticast = true
- case "link-local multicast":
- checkAttrs = true
- wantLinkLocalMulticast = true
- case "link-local unicast":
- checkAttrs = true
- wantLinkLocalUnicast = true
- case "loopback":
- checkAttrs = true
- checkFlags = true
- ifFlags = ifFlags | net.FlagLoopback
- wantLoopback = true
- case "multicast":
- checkAttrs = true
- checkFlags = true
- ifFlags = ifFlags | net.FlagMulticast
- wantMulticast = true
- case "point-to-point":
- checkFlags = true
- ifFlags = ifFlags | net.FlagPointToPoint
- case "unspecified":
- checkAttrs = true
- wantUnspecified = true
- case "up":
- checkFlags = true
- ifFlags = ifFlags | net.FlagUp
- default:
- return nil, nil, fmt.Errorf("Unknown interface flag: %+q", flagName)
- }
- }
-
- for _, ifAddr := range ifAddrs {
- var matched bool
- if checkFlags && ifAddr.Interface.Flags&ifFlags == ifFlags {
- matched = true
- }
- if checkAttrs {
- if ip := ToIPAddr(ifAddr.SockAddr); ip != nil {
- netIP := (*ip).NetIP()
- switch {
- case wantGlobalUnicast && netIP.IsGlobalUnicast():
- matched = true
- case wantInterfaceLocalMulticast && netIP.IsInterfaceLocalMulticast():
- matched = true
- case wantLinkLocalMulticast && netIP.IsLinkLocalMulticast():
- matched = true
- case wantLinkLocalUnicast && netIP.IsLinkLocalUnicast():
- matched = true
- case wantLoopback && netIP.IsLoopback():
- matched = true
- case wantMulticast && netIP.IsMulticast():
- matched = true
- case wantUnspecified && netIP.IsUnspecified():
- matched = true
- case wantForwardable && !IsRFC(ForwardingBlacklist, ifAddr.SockAddr):
- matched = true
- }
- }
- }
- if matched {
- matchedAddrs = append(matchedAddrs, ifAddr)
- } else {
- excludedAddrs = append(excludedAddrs, ifAddr)
- }
- }
- return matchedAddrs, excludedAddrs, nil
-}
-
-// IfByNetwork returns an IfAddrs that are equal to or included within the
-// network passed in by selector.
-func IfByNetwork(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, IfAddrs, error) {
- var includedIfs, excludedIfs IfAddrs
- for _, netStr := range strings.Split(selectorParam, "|") {
- netAddr, err := NewIPAddr(netStr)
- if err != nil {
- return nil, nil, fmt.Errorf("unable to create an IP address from %+q: %v", netStr, err)
- }
-
- for _, ifAddr := range inputIfAddrs {
- if netAddr.Contains(ifAddr.SockAddr) {
- includedIfs = append(includedIfs, ifAddr)
- } else {
- excludedIfs = append(excludedIfs, ifAddr)
- }
- }
- }
-
- return includedIfs, excludedIfs, nil
-}
-
-// IfAddrMath will return a new IfAddr struct with a mutated value.
-func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) {
- // Regexp used to enforce the sign being a required part of the grammar for
- // some values.
- signRe := signRE.Copy()
-
- switch strings.ToLower(operation) {
- case "address":
- // "address" operates on the IP address and is allowed to overflow or
- // underflow networks, however it will wrap along the underlying address's
- // underlying type.
-
- if !signRe.MatchString(value) {
- return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
- }
-
- switch sockType := inputIfAddr.SockAddr.Type(); sockType {
- case TypeIPv4:
- // 33 == Accept any uint32 value
- // TODO(seanc@): Add the ability to parse hex
- i, err := strconv.ParseInt(value, 10, 33)
- if err != nil {
- return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
- }
-
- ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
- ipv4Uint32 := uint32(ipv4.Address)
- ipv4Uint32 += uint32(i)
- return IfAddr{
- SockAddr: IPv4Addr{
- Address: IPv4Address(ipv4Uint32),
- Mask: ipv4.Mask,
- },
- Interface: inputIfAddr.Interface,
- }, nil
- case TypeIPv6:
- // 64 == Accept any int32 value
- // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int.
- i, err := strconv.ParseInt(value, 10, 64)
- if err != nil {
- return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
- }
-
- ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
- ipv6BigIntA := new(big.Int)
- ipv6BigIntA.Set(ipv6.Address)
- ipv6BigIntB := big.NewInt(i)
-
- ipv6Addr := ipv6BigIntA.Add(ipv6BigIntA, ipv6BigIntB)
- ipv6Addr.And(ipv6Addr, ipv6HostMask)
-
- return IfAddr{
- SockAddr: IPv6Addr{
- Address: IPv6Address(ipv6Addr),
- Mask: ipv6.Mask,
- },
- Interface: inputIfAddr.Interface,
- }, nil
- default:
- return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
- }
- case "network":
- // "network" operates on the network address. Positive values start at the
- // network address and negative values wrap at the network address, which
- // means a "-1" value on a network will be the broadcast address after
- // wrapping is applied.
-
- if !signRe.MatchString(value) {
- return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
- }
-
- switch sockType := inputIfAddr.SockAddr.Type(); sockType {
- case TypeIPv4:
- // 33 == Accept any uint32 value
- // TODO(seanc@): Add the ability to parse hex
- i, err := strconv.ParseInt(value, 10, 33)
- if err != nil {
- return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
- }
-
- ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
- ipv4Uint32 := uint32(ipv4.NetworkAddress())
-
- // Wrap along network mask boundaries. EZ-mode wrapping made possible by
- // use of int64 vs a uint.
- var wrappedMask int64
- if i >= 0 {
- wrappedMask = i
- } else {
- wrappedMask = 1 + i + int64(^uint32(ipv4.Mask))
- }
-
- ipv4Uint32 = ipv4Uint32 + (uint32(wrappedMask) &^ uint32(ipv4.Mask))
-
- return IfAddr{
- SockAddr: IPv4Addr{
- Address: IPv4Address(ipv4Uint32),
- Mask: ipv4.Mask,
- },
- Interface: inputIfAddr.Interface,
- }, nil
- case TypeIPv6:
- // 64 == Accept any int32 value
- // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int.
- i, err := strconv.ParseInt(value, 10, 64)
- if err != nil {
- return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
- }
-
- ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
- ipv6BigInt := new(big.Int)
- ipv6BigInt.Set(ipv6.NetworkAddress())
-
- mask := new(big.Int)
- mask.Set(ipv6.Mask)
- if i > 0 {
- wrappedMask := new(big.Int)
- wrappedMask.SetInt64(i)
-
- wrappedMask.AndNot(wrappedMask, mask)
- ipv6BigInt.Add(ipv6BigInt, wrappedMask)
- } else {
- // Mask off any bits that exceed the network size. Subtract the
- // wrappedMask from the last usable - 1
- wrappedMask := new(big.Int)
- wrappedMask.SetInt64(-1 * i)
- wrappedMask.Sub(wrappedMask, big.NewInt(1))
-
- wrappedMask.AndNot(wrappedMask, mask)
-
- lastUsable := new(big.Int)
- lastUsable.Set(ipv6.LastUsable().(IPv6Addr).Address)
-
- ipv6BigInt = lastUsable.Sub(lastUsable, wrappedMask)
- }
-
- return IfAddr{
- SockAddr: IPv6Addr{
- Address: IPv6Address(ipv6BigInt),
- Mask: ipv6.Mask,
- },
- Interface: inputIfAddr.Interface,
- }, nil
- default:
- return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
- }
- case "mask":
- // "mask" operates on the IP address and returns the IP address on
- // which the given integer mask has been applied. If the applied mask
- // corresponds to a larger network than the mask of the IP address,
- // the latter will be replaced by the former.
- switch sockType := inputIfAddr.SockAddr.Type(); sockType {
- case TypeIPv4:
- i, err := strconv.ParseUint(value, 10, 32)
- if err != nil {
- return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
- }
-
- if i > 32 {
- return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation)
- }
-
- ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
-
- ipv4Mask := net.CIDRMask(int(i), 32)
- ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask)
-
- maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask)
- maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4)
-
- maskedIpv4MaskUint32 := uint32(ipv4.Mask)
-
- if ipv4MaskUint32 < maskedIpv4MaskUint32 {
- maskedIpv4MaskUint32 = ipv4MaskUint32
- }
-
- return IfAddr{
- SockAddr: IPv4Addr{
- Address: IPv4Address(maskedIpv4Uint32),
- Mask: IPv4Mask(maskedIpv4MaskUint32),
- },
- Interface: inputIfAddr.Interface,
- }, nil
- case TypeIPv6:
- i, err := strconv.ParseUint(value, 10, 32)
- if err != nil {
- return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
- }
-
- if i > 128 {
- return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation)
- }
-
- ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
-
- ipv6Mask := net.CIDRMask(int(i), 128)
- ipv6MaskBigInt := new(big.Int)
- ipv6MaskBigInt.SetBytes(ipv6Mask)
-
- maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask)
- maskedIpv6BigInt := new(big.Int)
- maskedIpv6BigInt.SetBytes(maskedIpv6)
-
- maskedIpv6MaskBigInt := new(big.Int)
- maskedIpv6MaskBigInt.Set(ipv6.Mask)
-
- if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 {
- maskedIpv6MaskBigInt = ipv6MaskBigInt
- }
-
- return IfAddr{
- SockAddr: IPv6Addr{
- Address: IPv6Address(maskedIpv6BigInt),
- Mask: IPv6Mask(maskedIpv6MaskBigInt),
- },
- Interface: inputIfAddr.Interface,
- }, nil
- default:
- return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
- }
- default:
- return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation)
- }
-}
-
-// IfAddrsMath will apply an IfAddrMath operation each IfAddr struct. Any
-// failure will result in zero results.
-func IfAddrsMath(operation, value string, inputIfAddrs IfAddrs) (IfAddrs, error) {
- outputAddrs := make(IfAddrs, 0, len(inputIfAddrs))
- for _, ifAddr := range inputIfAddrs {
- result, err := IfAddrMath(operation, value, ifAddr)
- if err != nil {
- return IfAddrs{}, fmt.Errorf("unable to perform an IPMath operation on %s: %v", ifAddr, err)
- }
- outputAddrs = append(outputAddrs, result)
- }
- return outputAddrs, nil
-}
-
-// IncludeIfs returns an IfAddrs based on the passed in selector.
-func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
- var includedIfs IfAddrs
- var err error
-
- switch strings.ToLower(selectorName) {
- case "address":
- includedIfs, _, err = IfByAddress(selectorParam, inputIfAddrs)
- case "flag", "flags":
- includedIfs, _, err = IfByFlag(selectorParam, inputIfAddrs)
- case "name":
- includedIfs, _, err = IfByName(selectorParam, inputIfAddrs)
- case "network":
- includedIfs, _, err = IfByNetwork(selectorParam, inputIfAddrs)
- case "port":
- includedIfs, _, err = IfByPort(selectorParam, inputIfAddrs)
- case "rfc", "rfcs":
- includedIfs, _, err = IfByRFCs(selectorParam, inputIfAddrs)
- case "size":
- includedIfs, _, err = IfByMaskSize(selectorParam, inputIfAddrs)
- case "type":
- includedIfs, _, err = IfByType(selectorParam, inputIfAddrs)
- default:
- return IfAddrs{}, fmt.Errorf("invalid include selector %q", selectorName)
- }
-
- if err != nil {
- return IfAddrs{}, err
- }
-
- return includedIfs, nil
-}
-
-// ExcludeIfs returns an IfAddrs based on the passed in selector.
-func ExcludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
- var excludedIfs IfAddrs
- var err error
-
- switch strings.ToLower(selectorName) {
- case "address":
- _, excludedIfs, err = IfByAddress(selectorParam, inputIfAddrs)
- case "flag", "flags":
- _, excludedIfs, err = IfByFlag(selectorParam, inputIfAddrs)
- case "name":
- _, excludedIfs, err = IfByName(selectorParam, inputIfAddrs)
- case "network":
- _, excludedIfs, err = IfByNetwork(selectorParam, inputIfAddrs)
- case "port":
- _, excludedIfs, err = IfByPort(selectorParam, inputIfAddrs)
- case "rfc", "rfcs":
- _, excludedIfs, err = IfByRFCs(selectorParam, inputIfAddrs)
- case "size":
- _, excludedIfs, err = IfByMaskSize(selectorParam, inputIfAddrs)
- case "type":
- _, excludedIfs, err = IfByType(selectorParam, inputIfAddrs)
- default:
- return IfAddrs{}, fmt.Errorf("invalid exclude selector %q", selectorName)
- }
-
- if err != nil {
- return IfAddrs{}, err
- }
-
- return excludedIfs, nil
-}
-
-// SortIfBy returns an IfAddrs sorted based on the passed in selector. Multiple
-// sort clauses can be passed in as a comma delimited list without whitespace.
-func SortIfBy(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
- sortedIfs := append(IfAddrs(nil), inputIfAddrs...)
-
- clauses := strings.Split(selectorParam, ",")
- sortFuncs := make([]CmpIfAddrFunc, len(clauses))
-
- for i, clause := range clauses {
- switch strings.TrimSpace(strings.ToLower(clause)) {
- case "+address", "address":
- // The "address" selector returns an array of IfAddrs
- // ordered by the network address. IfAddrs that are not
- // comparable will be at the end of the list and in a
- // non-deterministic order.
- sortFuncs[i] = AscIfAddress
- case "-address":
- sortFuncs[i] = DescIfAddress
- case "+default", "default":
- sortFuncs[i] = AscIfDefault
- case "-default":
- sortFuncs[i] = DescIfDefault
- case "+name", "name":
- // The "name" selector returns an array of IfAddrs
- // ordered by the interface name.
- sortFuncs[i] = AscIfName
- case "-name":
- sortFuncs[i] = DescIfName
- case "+port", "port":
- // The "port" selector returns an array of IfAddrs
- // ordered by the port, if included in the IfAddr.
- // IfAddrs that are not comparable will be at the end of
- // the list and in a non-deterministic order.
- sortFuncs[i] = AscIfPort
- case "-port":
- sortFuncs[i] = DescIfPort
- case "+private", "private":
- // The "private" selector returns an array of IfAddrs
- // ordered by private addresses first. IfAddrs that are
- // not comparable will be at the end of the list and in
- // a non-deterministic order.
- sortFuncs[i] = AscIfPrivate
- case "-private":
- sortFuncs[i] = DescIfPrivate
- case "+size", "size":
- // The "size" selector returns an array of IfAddrs
- // ordered by the size of the network mask, smaller mask
- // (larger number of hosts per network) to largest
- // (e.g. a /24 sorts before a /32).
- sortFuncs[i] = AscIfNetworkSize
- case "-size":
- sortFuncs[i] = DescIfNetworkSize
- case "+type", "type":
- // The "type" selector returns an array of IfAddrs
- // ordered by the type of the IfAddr. The sort order is
- // Unix, IPv4, then IPv6.
- sortFuncs[i] = AscIfType
- case "-type":
- sortFuncs[i] = DescIfType
- default:
- // Return an empty list for invalid sort types.
- return IfAddrs{}, fmt.Errorf("unknown sort type: %q", clause)
- }
- }
-
- OrderedIfAddrBy(sortFuncs...).Sort(sortedIfs)
-
- return sortedIfs, nil
-}
-
-// UniqueIfAddrsBy creates a unique set of IfAddrs based on the matching
-// selector. UniqueIfAddrsBy assumes the input has already been sorted.
-func UniqueIfAddrsBy(selectorName string, inputIfAddrs IfAddrs) (IfAddrs, error) {
- attrName := strings.ToLower(selectorName)
-
- ifs := make(IfAddrs, 0, len(inputIfAddrs))
- var lastMatch string
- for _, ifAddr := range inputIfAddrs {
- var out string
- switch attrName {
- case "address":
- out = ifAddr.SockAddr.String()
- case "name":
- out = ifAddr.Name
- default:
- return nil, fmt.Errorf("unsupported unique constraint %+q", selectorName)
- }
-
- switch {
- case lastMatch == "", lastMatch != out:
- lastMatch = out
- ifs = append(ifs, ifAddr)
- case lastMatch == out:
- continue
- }
- }
-
- return ifs, nil
-}
-
-// JoinIfAddrs joins an IfAddrs and returns a string
-func JoinIfAddrs(selectorName string, joinStr string, inputIfAddrs IfAddrs) (string, error) {
- outputs := make([]string, 0, len(inputIfAddrs))
- attrName := AttrName(strings.ToLower(selectorName))
-
- for _, ifAddr := range inputIfAddrs {
- var attrVal string
- var err error
- attrVal, err = ifAddr.Attr(attrName)
- if err != nil {
- return "", err
- }
- outputs = append(outputs, attrVal)
- }
- return strings.Join(outputs, joinStr), nil
-}
-
-// LimitIfAddrs returns a slice of IfAddrs based on the specified limit.
-func LimitIfAddrs(lim uint, in IfAddrs) (IfAddrs, error) {
- // Clamp the limit to the length of the array
- if int(lim) > len(in) {
- lim = uint(len(in))
- }
-
- return in[0:lim], nil
-}
-
-// OffsetIfAddrs returns a slice of IfAddrs based on the specified offset.
-func OffsetIfAddrs(off int, in IfAddrs) (IfAddrs, error) {
- var end bool
- if off < 0 {
- end = true
- off = off * -1
- }
-
- if off > len(in) {
- return IfAddrs{}, fmt.Errorf("unable to seek past the end of the interface array: offset (%d) exceeds the number of interfaces (%d)", off, len(in))
- }
-
- if end {
- return in[len(in)-off:], nil
- }
- return in[off:], nil
-}
-
-func (ifAddr IfAddr) String() string {
- return fmt.Sprintf("%s %v", ifAddr.SockAddr, ifAddr.Interface)
-}
-
-// parseDefaultIfNameFromRoute parses standard route(8)'s output for the *BSDs
-// and Solaris.
-func parseDefaultIfNameFromRoute(routeOut string) (string, error) {
- lines := strings.Split(routeOut, "\n")
- for _, line := range lines {
- kvs := strings.SplitN(line, ":", 2)
- if len(kvs) != 2 {
- continue
- }
-
- if strings.TrimSpace(kvs[0]) == "interface" {
- ifName := strings.TrimSpace(kvs[1])
- return ifName, nil
- }
- }
-
- return "", errors.New("No default interface found")
-}
-
-// parseDefaultIfNameFromIPCmd parses the default interface from ip(8) for
-// Linux.
-func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) {
- parsedLines := parseIfNameFromIPCmd(routeOut)
- for _, parsedLine := range parsedLines {
- if parsedLine[0] == "default" &&
- parsedLine[1] == "via" &&
- parsedLine[3] == "dev" {
- ifName := strings.TrimSpace(parsedLine[4])
- return ifName, nil
- }
- }
-
- return "", errors.New("No default interface found")
-}
-
-// parseDefaultIfNameFromIPCmdAndroid parses the default interface from ip(8) for
-// Android.
-func parseDefaultIfNameFromIPCmdAndroid(routeOut string) (string, error) {
- parsedLines := parseIfNameFromIPCmd(routeOut)
- if (len(parsedLines) > 0) {
- ifName := strings.TrimSpace(parsedLines[0][4])
- return ifName, nil
- }
-
- return "", errors.New("No default interface found")
-}
-
-
-// parseIfNameFromIPCmd parses interfaces from ip(8) for
-// Linux.
-func parseIfNameFromIPCmd(routeOut string) [][]string {
- lines := strings.Split(routeOut, "\n")
- re := whitespaceRE.Copy()
- parsedLines := make([][]string, 0, len(lines))
- for _, line := range lines {
- kvs := re.Split(line, -1)
- if len(kvs) < 5 {
- continue
- }
- parsedLines = append(parsedLines, kvs)
- }
- return parsedLines
-}
-
-// parseDefaultIfNameWindows parses the default interface from `netstat -rn` and
-// `ipconfig` on Windows.
-func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) {
- defaultIPAddr, err := parseDefaultIPAddrWindowsRoute(routeOut)
- if err != nil {
- return "", err
- }
-
- ifName, err := parseDefaultIfNameWindowsIPConfig(defaultIPAddr, ipconfigOut)
- if err != nil {
- return "", err
- }
-
- return ifName, nil
-}
-
-// parseDefaultIPAddrWindowsRoute parses the IP address on the default interface
-// `netstat -rn`.
-//
-// NOTES(sean): Only IPv4 addresses are parsed at this time. If you have an
-// IPv6 connected host, submit an issue on github.com/hashicorp/go-sockaddr with
-// the output from `netstat -rn`, `ipconfig`, and version of Windows to see IPv6
-// support added.
-func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) {
- lines := strings.Split(routeOut, "\n")
- re := whitespaceRE.Copy()
- for _, line := range lines {
- kvs := re.Split(strings.TrimSpace(line), -1)
- if len(kvs) < 3 {
- continue
- }
-
- if kvs[0] == "0.0.0.0" && kvs[1] == "0.0.0.0" {
- defaultIPAddr := strings.TrimSpace(kvs[3])
- return defaultIPAddr, nil
- }
- }
-
- return "", errors.New("No IP on default interface found")
-}
-
-// parseDefaultIfNameWindowsIPConfig parses the output of `ipconfig` to find the
-// interface name forwarding traffic to the default gateway.
-func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) {
- lines := strings.Split(routeOut, "\n")
- ifNameRe := ifNameRE.Copy()
- ipAddrRe := ipAddrRE.Copy()
- var ifName string
- for _, line := range lines {
- switch ifNameMatches := ifNameRe.FindStringSubmatch(line); {
- case len(ifNameMatches) > 1:
- ifName = ifNameMatches[1]
- continue
- }
-
- switch ipAddrMatches := ipAddrRe.FindStringSubmatch(line); {
- case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr:
- return ifName, nil
- }
- }
-
- return "", errors.New("No default interface found with matching IP")
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifattr.go b/vendor/github.com/hashicorp/go-sockaddr/ifattr.go
deleted file mode 100644
index 6984cb4a354..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/ifattr.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package sockaddr
-
-import (
- "fmt"
- "net"
-)
-
-// IfAddr is a union of a SockAddr and a net.Interface.
-type IfAddr struct {
- SockAddr
- net.Interface
-}
-
-// Attr returns the named attribute as a string
-func (ifAddr IfAddr) Attr(attrName AttrName) (string, error) {
- val := IfAddrAttr(ifAddr, attrName)
- if val != "" {
- return val, nil
- }
-
- return Attr(ifAddr.SockAddr, attrName)
-}
-
-// Attr returns the named attribute as a string
-func Attr(sa SockAddr, attrName AttrName) (string, error) {
- switch sockType := sa.Type(); {
- case sockType&TypeIP != 0:
- ip := *ToIPAddr(sa)
- attrVal := IPAddrAttr(ip, attrName)
- if attrVal != "" {
- return attrVal, nil
- }
-
- if sockType == TypeIPv4 {
- ipv4 := *ToIPv4Addr(sa)
- attrVal := IPv4AddrAttr(ipv4, attrName)
- if attrVal != "" {
- return attrVal, nil
- }
- } else if sockType == TypeIPv6 {
- ipv6 := *ToIPv6Addr(sa)
- attrVal := IPv6AddrAttr(ipv6, attrName)
- if attrVal != "" {
- return attrVal, nil
- }
- }
-
- case sockType == TypeUnix:
- us := *ToUnixSock(sa)
- attrVal := UnixSockAttr(us, attrName)
- if attrVal != "" {
- return attrVal, nil
- }
- }
-
- // Non type-specific attributes
- switch attrName {
- case "string":
- return sa.String(), nil
- case "type":
- return sa.Type().String(), nil
- }
-
- return "", fmt.Errorf("unsupported attribute name %q", attrName)
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipaddr.go b/vendor/github.com/hashicorp/go-sockaddr/ipaddr.go
deleted file mode 100644
index b47d15c2016..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/ipaddr.go
+++ /dev/null
@@ -1,169 +0,0 @@
-package sockaddr
-
-import (
- "fmt"
- "math/big"
- "net"
- "strings"
-)
-
-// Constants for the sizes of IPv3, IPv4, and IPv6 address types.
-const (
- IPv3len = 6
- IPv4len = 4
- IPv6len = 16
-)
-
-// IPAddr is a generic IP address interface for IPv4 and IPv6 addresses,
-// networks, and socket endpoints.
-type IPAddr interface {
- SockAddr
- AddressBinString() string
- AddressHexString() string
- Cmp(SockAddr) int
- CmpAddress(SockAddr) int
- CmpPort(SockAddr) int
- FirstUsable() IPAddr
- Host() IPAddr
- IPPort() IPPort
- LastUsable() IPAddr
- Maskbits() int
- NetIP() *net.IP
- NetIPMask() *net.IPMask
- NetIPNet() *net.IPNet
- Network() IPAddr
- Octets() []int
-}
-
-// IPPort is the type for an IP port number for the TCP and UDP IP transports.
-type IPPort uint16
-
-// IPPrefixLen is a typed integer representing the prefix length for a given
-// IPAddr.
-type IPPrefixLen byte
-
-// ipAddrAttrMap is a map of the IPAddr type-specific attributes.
-var ipAddrAttrMap map[AttrName]func(IPAddr) string
-var ipAddrAttrs []AttrName
-
-func init() {
- ipAddrInit()
-}
-
-// NewIPAddr creates a new IPAddr from a string. Returns nil if the string is
-// not an IPv4 or an IPv6 address.
-func NewIPAddr(addr string) (IPAddr, error) {
- ipv4Addr, err := NewIPv4Addr(addr)
- if err == nil {
- return ipv4Addr, nil
- }
-
- ipv6Addr, err := NewIPv6Addr(addr)
- if err == nil {
- return ipv6Addr, nil
- }
-
- return nil, fmt.Errorf("invalid IPAddr %v", addr)
-}
-
-// IPAddrAttr returns a string representation of an attribute for the given
-// IPAddr.
-func IPAddrAttr(ip IPAddr, selector AttrName) string {
- fn, found := ipAddrAttrMap[selector]
- if !found {
- return ""
- }
-
- return fn(ip)
-}
-
-// IPAttrs returns a list of attributes supported by the IPAddr type
-func IPAttrs() []AttrName {
- return ipAddrAttrs
-}
-
-// MustIPAddr is a helper method that must return an IPAddr or panic on invalid
-// input.
-func MustIPAddr(addr string) IPAddr {
- ip, err := NewIPAddr(addr)
- if err != nil {
- panic(fmt.Sprintf("Unable to create an IPAddr from %+q: %v", addr, err))
- }
- return ip
-}
-
-// ipAddrInit is called once at init()
-func ipAddrInit() {
- // Sorted for human readability
- ipAddrAttrs = []AttrName{
- "host",
- "address",
- "port",
- "netmask",
- "network",
- "mask_bits",
- "binary",
- "hex",
- "first_usable",
- "last_usable",
- "octets",
- }
-
- ipAddrAttrMap = map[AttrName]func(ip IPAddr) string{
- "address": func(ip IPAddr) string {
- return ip.NetIP().String()
- },
- "binary": func(ip IPAddr) string {
- return ip.AddressBinString()
- },
- "first_usable": func(ip IPAddr) string {
- return ip.FirstUsable().String()
- },
- "hex": func(ip IPAddr) string {
- return ip.AddressHexString()
- },
- "host": func(ip IPAddr) string {
- return ip.Host().String()
- },
- "last_usable": func(ip IPAddr) string {
- return ip.LastUsable().String()
- },
- "mask_bits": func(ip IPAddr) string {
- return fmt.Sprintf("%d", ip.Maskbits())
- },
- "netmask": func(ip IPAddr) string {
- switch v := ip.(type) {
- case IPv4Addr:
- ipv4Mask := IPv4Addr{
- Address: IPv4Address(v.Mask),
- Mask: IPv4HostMask,
- }
- return ipv4Mask.String()
- case IPv6Addr:
- ipv6Mask := new(big.Int)
- ipv6Mask.Set(v.Mask)
- ipv6MaskAddr := IPv6Addr{
- Address: IPv6Address(ipv6Mask),
- Mask: ipv6HostMask,
- }
- return ipv6MaskAddr.String()
- default:
- return fmt.Sprintf("", ip)
- }
- },
- "network": func(ip IPAddr) string {
- return ip.Network().NetIP().String()
- },
- "octets": func(ip IPAddr) string {
- octets := ip.Octets()
- octetStrs := make([]string, 0, len(octets))
- for _, octet := range octets {
- octetStrs = append(octetStrs, fmt.Sprintf("%d", octet))
- }
- return strings.Join(octetStrs, " ")
- },
- "port": func(ip IPAddr) string {
- return fmt.Sprintf("%d", ip.IPPort())
- },
- }
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go
deleted file mode 100644
index 6eeb7ddd2f1..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/ipaddrs.go
+++ /dev/null
@@ -1,98 +0,0 @@
-package sockaddr
-
-import "bytes"
-
-type IPAddrs []IPAddr
-
-func (s IPAddrs) Len() int { return len(s) }
-func (s IPAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
-// // SortIPAddrsByCmp is a type that satisfies sort.Interface and can be used
-// // by the routines in this package. The SortIPAddrsByCmp type is used to
-// // sort IPAddrs by Cmp()
-// type SortIPAddrsByCmp struct{ IPAddrs }
-
-// // Less reports whether the element with index i should sort before the
-// // element with index j.
-// func (s SortIPAddrsByCmp) Less(i, j int) bool {
-// // Sort by Type, then address, then port number.
-// return Less(s.IPAddrs[i], s.IPAddrs[j])
-// }
-
-// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
-// can be used by the routines in this package. The
-// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
-// network (most specific to largest network).
-type SortIPAddrsByNetworkSize struct{ IPAddrs }
-
-// Less reports whether the element with index i should sort before the
-// element with index j.
-func (s SortIPAddrsByNetworkSize) Less(i, j int) bool {
- // Sort masks with a larger binary value (i.e. fewer hosts per network
- // prefix) after masks with a smaller value (larger number of hosts per
- // prefix).
- switch bytes.Compare([]byte(*s.IPAddrs[i].NetIPMask()), []byte(*s.IPAddrs[j].NetIPMask())) {
- case 0:
- // Fall through to the second test if the net.IPMasks are the
- // same.
- break
- case 1:
- return true
- case -1:
- return false
- default:
- panic("bad, m'kay?")
- }
-
- // Sort IPs based on the length (i.e. prefer IPv4 over IPv6).
- iLen := len(*s.IPAddrs[i].NetIP())
- jLen := len(*s.IPAddrs[j].NetIP())
- if iLen != jLen {
- return iLen > jLen
- }
-
- // Sort IPs based on their network address from lowest to highest.
- switch bytes.Compare(s.IPAddrs[i].NetIPNet().IP, s.IPAddrs[j].NetIPNet().IP) {
- case 0:
- break
- case 1:
- return false
- case -1:
- return true
- default:
- panic("lol wut?")
- }
-
- // If a host does not have a port set, it always sorts after hosts
- // that have a port (e.g. a host with a /32 and port number is more
- // specific and should sort first over a host with a /32 but no port
- // set).
- if s.IPAddrs[i].IPPort() == 0 || s.IPAddrs[j].IPPort() == 0 {
- return false
- }
- return s.IPAddrs[i].IPPort() < s.IPAddrs[j].IPPort()
-}
-
-// SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and
-// can be used by the routines in this package. The
-// SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest
-// network (most specific to largest network).
-type SortIPAddrsBySpecificMaskLen struct{ IPAddrs }
-
-// Less reports whether the element with index i should sort before the
-// element with index j.
-func (s SortIPAddrsBySpecificMaskLen) Less(i, j int) bool {
- return s.IPAddrs[i].Maskbits() > s.IPAddrs[j].Maskbits()
-}
-
-// SortIPAddrsByBroadMaskLen is a type that satisfies sort.Interface and can
-// be used by the routines in this package. The SortIPAddrsByBroadMaskLen
-// type is used to sort IPAddrs by largest network (i.e. largest subnets
-// first).
-type SortIPAddrsByBroadMaskLen struct{ IPAddrs }
-
-// Less reports whether the element with index i should sort before the
-// element with index j.
-func (s SortIPAddrsByBroadMaskLen) Less(i, j int) bool {
- return s.IPAddrs[i].Maskbits() < s.IPAddrs[j].Maskbits()
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go
deleted file mode 100644
index 4d395dc954b..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go
+++ /dev/null
@@ -1,516 +0,0 @@
-package sockaddr
-
-import (
- "encoding/binary"
- "fmt"
- "net"
- "regexp"
- "strconv"
- "strings"
-)
-
-type (
- // IPv4Address is a named type representing an IPv4 address.
- IPv4Address uint32
-
- // IPv4Network is a named type representing an IPv4 network.
- IPv4Network uint32
-
- // IPv4Mask is a named type representing an IPv4 network mask.
- IPv4Mask uint32
-)
-
-// IPv4HostMask is a constant represents a /32 IPv4 Address
-// (i.e. 255.255.255.255).
-const IPv4HostMask = IPv4Mask(0xffffffff)
-
-// ipv4AddrAttrMap is a map of the IPv4Addr type-specific attributes.
-var ipv4AddrAttrMap map[AttrName]func(IPv4Addr) string
-var ipv4AddrAttrs []AttrName
-var trailingHexNetmaskRE *regexp.Regexp
-
-// IPv4Addr implements a convenience wrapper around the union of Go's
-// built-in net.IP and net.IPNet types. In UNIX-speak, IPv4Addr implements
-// `sockaddr` when the the address family is set to AF_INET
-// (i.e. `sockaddr_in`).
-type IPv4Addr struct {
- IPAddr
- Address IPv4Address
- Mask IPv4Mask
- Port IPPort
-}
-
-func init() {
- ipv4AddrInit()
- trailingHexNetmaskRE = regexp.MustCompile(`/([0f]{8})$`)
-}
-
-// NewIPv4Addr creates an IPv4Addr from a string. String can be in the form
-// of either an IPv4:port (e.g. `1.2.3.4:80`, in which case the mask is
-// assumed to be a `/32`), an IPv4 address (e.g. `1.2.3.4`, also with a `/32`
-// mask), or an IPv4 CIDR (e.g. `1.2.3.4/24`, which has its IP port
-// initialized to zero). ipv4Str can not be a hostname.
-//
-// NOTE: Many net.*() routines will initialize and return an IPv6 address.
-// To create uint32 values from net.IP, always test to make sure the address
-// returned can be converted to a 4 byte array using To4().
-func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) {
- // Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go. In
- // particular, clients with the Barracuda VPN client will see something like:
- // `192.168.3.51/00ffffff` as their IP address.
- trailingHexNetmaskRe := trailingHexNetmaskRE.Copy()
- if match := trailingHexNetmaskRe.FindStringIndex(ipv4Str); match != nil {
- ipv4Str = ipv4Str[:match[0]]
- }
-
- // Parse as an IPv4 CIDR
- ipAddr, network, err := net.ParseCIDR(ipv4Str)
- if err == nil {
- ipv4 := ipAddr.To4()
- if ipv4 == nil {
- return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address", ipv4Str)
- }
-
- // If we see an IPv6 netmask, convert it to an IPv4 mask.
- netmaskSepPos := strings.LastIndexByte(ipv4Str, '/')
- if netmaskSepPos != -1 && netmaskSepPos+1 < len(ipv4Str) {
- netMask, err := strconv.ParseUint(ipv4Str[netmaskSepPos+1:], 10, 8)
- if err != nil {
- return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: unable to parse CIDR netmask: %v", ipv4Str, err)
- } else if netMask > 128 {
- return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: invalid CIDR netmask", ipv4Str)
- }
-
- if netMask >= 96 {
- // Convert the IPv6 netmask to an IPv4 netmask
- network.Mask = net.CIDRMask(int(netMask-96), IPv4len*8)
- }
- }
- ipv4Addr := IPv4Addr{
- Address: IPv4Address(binary.BigEndian.Uint32(ipv4)),
- Mask: IPv4Mask(binary.BigEndian.Uint32(network.Mask)),
- }
- return ipv4Addr, nil
- }
-
- // Attempt to parse ipv4Str as a /32 host with a port number.
- tcpAddr, err := net.ResolveTCPAddr("tcp4", ipv4Str)
- if err == nil {
- ipv4 := tcpAddr.IP.To4()
- if ipv4 == nil {
- return IPv4Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv4 address", ipv4Str)
- }
-
- ipv4Uint32 := binary.BigEndian.Uint32(ipv4)
- ipv4Addr := IPv4Addr{
- Address: IPv4Address(ipv4Uint32),
- Mask: IPv4HostMask,
- Port: IPPort(tcpAddr.Port),
- }
-
- return ipv4Addr, nil
- }
-
- // Parse as a naked IPv4 address
- ip := net.ParseIP(ipv4Str)
- if ip != nil {
- ipv4 := ip.To4()
- if ipv4 == nil {
- return IPv4Addr{}, fmt.Errorf("Unable to string convert %+q to an IPv4 address", ipv4Str)
- }
-
- ipv4Uint32 := binary.BigEndian.Uint32(ipv4)
- ipv4Addr := IPv4Addr{
- Address: IPv4Address(ipv4Uint32),
- Mask: IPv4HostMask,
- }
- return ipv4Addr, nil
- }
-
- return IPv4Addr{}, fmt.Errorf("Unable to parse %+q to an IPv4 address: %v", ipv4Str, err)
-}
-
-// AddressBinString returns a string with the IPv4Addr's Address represented
-// as a sequence of '0' and '1' characters. This method is useful for
-// debugging or by operators who want to inspect an address.
-func (ipv4 IPv4Addr) AddressBinString() string {
- return fmt.Sprintf("%032s", strconv.FormatUint(uint64(ipv4.Address), 2))
-}
-
-// AddressHexString returns a string with the IPv4Addr address represented as
-// a sequence of hex characters. This method is useful for debugging or by
-// operators who want to inspect an address.
-func (ipv4 IPv4Addr) AddressHexString() string {
- return fmt.Sprintf("%08s", strconv.FormatUint(uint64(ipv4.Address), 16))
-}
-
-// Broadcast is an IPv4Addr-only method that returns the broadcast address of
-// the network.
-//
-// NOTE: IPv6 only supports multicast, so this method only exists for
-// IPv4Addr.
-func (ipv4 IPv4Addr) Broadcast() IPAddr {
- // Nothing should listen on a broadcast address.
- return IPv4Addr{
- Address: IPv4Address(ipv4.BroadcastAddress()),
- Mask: IPv4HostMask,
- }
-}
-
-// BroadcastAddress returns a IPv4Network of the IPv4Addr's broadcast
-// address.
-func (ipv4 IPv4Addr) BroadcastAddress() IPv4Network {
- return IPv4Network(uint32(ipv4.Address)&uint32(ipv4.Mask) | ^uint32(ipv4.Mask))
-}
-
-// CmpAddress follows the Cmp() standard protocol and returns:
-//
-// - -1 If the receiver should sort first because its address is lower than arg
-// - 0 if the SockAddr arg is equal to the receiving IPv4Addr or the argument is
-// of a different type.
-// - 1 If the argument should sort first.
-func (ipv4 IPv4Addr) CmpAddress(sa SockAddr) int {
- ipv4b, ok := sa.(IPv4Addr)
- if !ok {
- return sortDeferDecision
- }
-
- switch {
- case ipv4.Address == ipv4b.Address:
- return sortDeferDecision
- case ipv4.Address < ipv4b.Address:
- return sortReceiverBeforeArg
- default:
- return sortArgBeforeReceiver
- }
-}
-
-// CmpPort follows the Cmp() standard protocol and returns:
-//
-// - -1 If the receiver should sort first because its port is lower than arg
-// - 0 if the SockAddr arg's port number is equal to the receiving IPv4Addr,
-// regardless of type.
-// - 1 If the argument should sort first.
-func (ipv4 IPv4Addr) CmpPort(sa SockAddr) int {
- var saPort IPPort
- switch v := sa.(type) {
- case IPv4Addr:
- saPort = v.Port
- case IPv6Addr:
- saPort = v.Port
- default:
- return sortDeferDecision
- }
-
- switch {
- case ipv4.Port == saPort:
- return sortDeferDecision
- case ipv4.Port < saPort:
- return sortReceiverBeforeArg
- default:
- return sortArgBeforeReceiver
- }
-}
-
-// CmpRFC follows the Cmp() standard protocol and returns:
-//
-// - -1 If the receiver should sort first because it belongs to the RFC and its
-// arg does not
-// - 0 if the receiver and arg both belong to the same RFC or neither do.
-// - 1 If the arg belongs to the RFC but receiver does not.
-func (ipv4 IPv4Addr) CmpRFC(rfcNum uint, sa SockAddr) int {
- recvInRFC := IsRFC(rfcNum, ipv4)
- ipv4b, ok := sa.(IPv4Addr)
- if !ok {
- // If the receiver is part of the desired RFC and the SockAddr
- // argument is not, return -1 so that the receiver sorts before
- // the non-IPv4 SockAddr. Conversely, if the receiver is not
- // part of the RFC, punt on sorting and leave it for the next
- // sorter.
- if recvInRFC {
- return sortReceiverBeforeArg
- } else {
- return sortDeferDecision
- }
- }
-
- argInRFC := IsRFC(rfcNum, ipv4b)
- switch {
- case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC):
- // If a and b both belong to the RFC, or neither belong to
- // rfcNum, defer sorting to the next sorter.
- return sortDeferDecision
- case recvInRFC && !argInRFC:
- return sortReceiverBeforeArg
- default:
- return sortArgBeforeReceiver
- }
-}
-
-// Contains returns true if the SockAddr is contained within the receiver.
-func (ipv4 IPv4Addr) Contains(sa SockAddr) bool {
- ipv4b, ok := sa.(IPv4Addr)
- if !ok {
- return false
- }
-
- return ipv4.ContainsNetwork(ipv4b)
-}
-
-// ContainsAddress returns true if the IPv4Address is contained within the
-// receiver.
-func (ipv4 IPv4Addr) ContainsAddress(x IPv4Address) bool {
- return IPv4Address(ipv4.NetworkAddress()) <= x &&
- IPv4Address(ipv4.BroadcastAddress()) >= x
-}
-
-// ContainsNetwork returns true if the network from IPv4Addr is contained
-// within the receiver.
-func (ipv4 IPv4Addr) ContainsNetwork(x IPv4Addr) bool {
- return ipv4.NetworkAddress() <= x.NetworkAddress() &&
- ipv4.BroadcastAddress() >= x.BroadcastAddress()
-}
-
-// DialPacketArgs returns the arguments required to be passed to
-// net.DialUDP(). If the Mask of ipv4 is not a /32 or the Port is 0,
-// DialPacketArgs() will fail. See Host() to create an IPv4Addr with its
-// mask set to /32.
-func (ipv4 IPv4Addr) DialPacketArgs() (network, dialArgs string) {
- if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 {
- return "udp4", ""
- }
- return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
-}
-
-// DialStreamArgs returns the arguments required to be passed to
-// net.DialTCP(). If the Mask of ipv4 is not a /32 or the Port is 0,
-// DialStreamArgs() will fail. See Host() to create an IPv4Addr with its
-// mask set to /32.
-func (ipv4 IPv4Addr) DialStreamArgs() (network, dialArgs string) {
- if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 {
- return "tcp4", ""
- }
- return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
-}
-
-// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
-func (ipv4 IPv4Addr) Equal(sa SockAddr) bool {
- ipv4b, ok := sa.(IPv4Addr)
- if !ok {
- return false
- }
-
- if ipv4.Port != ipv4b.Port {
- return false
- }
-
- if ipv4.Address != ipv4b.Address {
- return false
- }
-
- if ipv4.NetIPNet().String() != ipv4b.NetIPNet().String() {
- return false
- }
-
- return true
-}
-
-// FirstUsable returns an IPv4Addr set to the first address following the
-// network prefix. The first usable address in a network is normally the
-// gateway and should not be used except by devices forwarding packets
-// between two administratively distinct networks (i.e. a router). This
-// function does not discriminate against first usable vs "first address that
-// should be used." For example, FirstUsable() on "192.168.1.10/24" would
-// return the address "192.168.1.1/24".
-func (ipv4 IPv4Addr) FirstUsable() IPAddr {
- addr := ipv4.NetworkAddress()
-
- // If /32, return the address itself. If /31 assume a point-to-point
- // link and return the lower address.
- if ipv4.Maskbits() < 31 {
- addr++
- }
-
- return IPv4Addr{
- Address: IPv4Address(addr),
- Mask: IPv4HostMask,
- }
-}
-
-// Host returns a copy of ipv4 with its mask set to /32 so that it can be
-// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
-// ListenStreamArgs().
-func (ipv4 IPv4Addr) Host() IPAddr {
- // Nothing should listen on a broadcast address.
- return IPv4Addr{
- Address: ipv4.Address,
- Mask: IPv4HostMask,
- Port: ipv4.Port,
- }
-}
-
-// IPPort returns the Port number attached to the IPv4Addr
-func (ipv4 IPv4Addr) IPPort() IPPort {
- return ipv4.Port
-}
-
-// LastUsable returns the last address before the broadcast address in a
-// given network.
-func (ipv4 IPv4Addr) LastUsable() IPAddr {
- addr := ipv4.BroadcastAddress()
-
- // If /32, return the address itself. If /31 assume a point-to-point
- // link and return the upper address.
- if ipv4.Maskbits() < 31 {
- addr--
- }
-
- return IPv4Addr{
- Address: IPv4Address(addr),
- Mask: IPv4HostMask,
- }
-}
-
-// ListenPacketArgs returns the arguments required to be passed to
-// net.ListenUDP(). If the Mask of ipv4 is not a /32, ListenPacketArgs()
-// will fail. See Host() to create an IPv4Addr with its mask set to /32.
-func (ipv4 IPv4Addr) ListenPacketArgs() (network, listenArgs string) {
- if ipv4.Mask != IPv4HostMask {
- return "udp4", ""
- }
- return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
-}
-
-// ListenStreamArgs returns the arguments required to be passed to
-// net.ListenTCP(). If the Mask of ipv4 is not a /32, ListenStreamArgs()
-// will fail. See Host() to create an IPv4Addr with its mask set to /32.
-func (ipv4 IPv4Addr) ListenStreamArgs() (network, listenArgs string) {
- if ipv4.Mask != IPv4HostMask {
- return "tcp4", ""
- }
- return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
-}
-
-// Maskbits returns the number of network mask bits in a given IPv4Addr. For
-// example, the Maskbits() of "192.168.1.1/24" would return 24.
-func (ipv4 IPv4Addr) Maskbits() int {
- mask := make(net.IPMask, IPv4len)
- binary.BigEndian.PutUint32(mask, uint32(ipv4.Mask))
- maskOnes, _ := mask.Size()
- return maskOnes
-}
-
-// MustIPv4Addr is a helper method that must return an IPv4Addr or panic on
-// invalid input.
-func MustIPv4Addr(addr string) IPv4Addr {
- ipv4, err := NewIPv4Addr(addr)
- if err != nil {
- panic(fmt.Sprintf("Unable to create an IPv4Addr from %+q: %v", addr, err))
- }
- return ipv4
-}
-
-// NetIP returns the address as a net.IP (address is always presized to
-// IPv4).
-func (ipv4 IPv4Addr) NetIP() *net.IP {
- x := make(net.IP, IPv4len)
- binary.BigEndian.PutUint32(x, uint32(ipv4.Address))
- return &x
-}
-
-// NetIPMask create a new net.IPMask from the IPv4Addr.
-func (ipv4 IPv4Addr) NetIPMask() *net.IPMask {
- ipv4Mask := net.IPMask{}
- ipv4Mask = make(net.IPMask, IPv4len)
- binary.BigEndian.PutUint32(ipv4Mask, uint32(ipv4.Mask))
- return &ipv4Mask
-}
-
-// NetIPNet create a new net.IPNet from the IPv4Addr.
-func (ipv4 IPv4Addr) NetIPNet() *net.IPNet {
- ipv4net := &net.IPNet{}
- ipv4net.IP = make(net.IP, IPv4len)
- binary.BigEndian.PutUint32(ipv4net.IP, uint32(ipv4.NetworkAddress()))
- ipv4net.Mask = *ipv4.NetIPMask()
- return ipv4net
-}
-
-// Network returns the network prefix or network address for a given network.
-func (ipv4 IPv4Addr) Network() IPAddr {
- return IPv4Addr{
- Address: IPv4Address(ipv4.NetworkAddress()),
- Mask: ipv4.Mask,
- }
-}
-
-// NetworkAddress returns an IPv4Network of the IPv4Addr's network address.
-func (ipv4 IPv4Addr) NetworkAddress() IPv4Network {
- return IPv4Network(uint32(ipv4.Address) & uint32(ipv4.Mask))
-}
-
-// Octets returns a slice of the four octets in an IPv4Addr's Address. The
-// order of the bytes is big endian.
-func (ipv4 IPv4Addr) Octets() []int {
- return []int{
- int(ipv4.Address >> 24),
- int((ipv4.Address >> 16) & 0xff),
- int((ipv4.Address >> 8) & 0xff),
- int(ipv4.Address & 0xff),
- }
-}
-
-// String returns a string representation of the IPv4Addr
-func (ipv4 IPv4Addr) String() string {
- if ipv4.Port != 0 {
- return fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port)
- }
-
- if ipv4.Maskbits() == 32 {
- return ipv4.NetIP().String()
- }
-
- return fmt.Sprintf("%s/%d", ipv4.NetIP().String(), ipv4.Maskbits())
-}
-
-// Type is used as a type switch and returns TypeIPv4
-func (IPv4Addr) Type() SockAddrType {
- return TypeIPv4
-}
-
-// IPv4AddrAttr returns a string representation of an attribute for the given
-// IPv4Addr.
-func IPv4AddrAttr(ipv4 IPv4Addr, selector AttrName) string {
- fn, found := ipv4AddrAttrMap[selector]
- if !found {
- return ""
- }
-
- return fn(ipv4)
-}
-
-// IPv4Attrs returns a list of attributes supported by the IPv4Addr type
-func IPv4Attrs() []AttrName {
- return ipv4AddrAttrs
-}
-
-// ipv4AddrInit is called once at init()
-func ipv4AddrInit() {
- // Sorted for human readability
- ipv4AddrAttrs = []AttrName{
- "size", // Same position as in IPv6 for output consistency
- "broadcast",
- "uint32",
- }
-
- ipv4AddrAttrMap = map[AttrName]func(ipv4 IPv4Addr) string{
- "broadcast": func(ipv4 IPv4Addr) string {
- return ipv4.Broadcast().String()
- },
- "size": func(ipv4 IPv4Addr) string {
- return fmt.Sprintf("%d", 1< 2 && ipv6Str[0] == '[' && ipv6Str[len(ipv6Str)-1] == ']' {
- ipv6Str = ipv6Str[1 : len(ipv6Str)-1]
- }
- ip := net.ParseIP(ipv6Str)
- if ip != nil {
- ipv6 := ip.To16()
- if ipv6 == nil {
- return IPv6Addr{}, fmt.Errorf("Unable to string convert %+q to a 16byte IPv6 address", ipv6Str)
- }
-
- ipv6BigIntAddr := new(big.Int)
- ipv6BigIntAddr.SetBytes(ipv6)
-
- ipv6BigIntMask := new(big.Int)
- ipv6BigIntMask.Set(ipv6HostMask)
-
- return IPv6Addr{
- Address: IPv6Address(ipv6BigIntAddr),
- Mask: IPv6Mask(ipv6BigIntMask),
- }, nil
- }
-
- // Parse as an IPv6 CIDR
- ipAddr, network, err := net.ParseCIDR(ipv6Str)
- if err == nil {
- ipv6 := ipAddr.To16()
- if ipv6 == nil {
- return IPv6Addr{}, fmt.Errorf("Unable to convert %+q to a 16byte IPv6 address", ipv6Str)
- }
-
- ipv6BigIntAddr := new(big.Int)
- ipv6BigIntAddr.SetBytes(ipv6)
-
- ipv6BigIntMask := new(big.Int)
- ipv6BigIntMask.SetBytes(network.Mask)
-
- ipv6Addr := IPv6Addr{
- Address: IPv6Address(ipv6BigIntAddr),
- Mask: IPv6Mask(ipv6BigIntMask),
- }
- return ipv6Addr, nil
- }
-
- return IPv6Addr{}, fmt.Errorf("Unable to parse %+q to an IPv6 address: %v", ipv6Str, err)
-}
-
-// AddressBinString returns a string with the IPv6Addr's Address represented
-// as a sequence of '0' and '1' characters. This method is useful for
-// debugging or by operators who want to inspect an address.
-func (ipv6 IPv6Addr) AddressBinString() string {
- bi := big.Int(*ipv6.Address)
- return fmt.Sprintf("%0128s", bi.Text(2))
-}
-
-// AddressHexString returns a string with the IPv6Addr address represented as
-// a sequence of hex characters. This method is useful for debugging or by
-// operators who want to inspect an address.
-func (ipv6 IPv6Addr) AddressHexString() string {
- bi := big.Int(*ipv6.Address)
- return fmt.Sprintf("%032s", bi.Text(16))
-}
-
-// CmpAddress follows the Cmp() standard protocol and returns:
-//
-// - -1 If the receiver should sort first because its address is lower than arg
-// - 0 if the SockAddr arg equal to the receiving IPv6Addr or the argument is of a
-// different type.
-// - 1 If the argument should sort first.
-func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int {
- ipv6b, ok := sa.(IPv6Addr)
- if !ok {
- return sortDeferDecision
- }
-
- ipv6aBigInt := new(big.Int)
- ipv6aBigInt.Set(ipv6.Address)
- ipv6bBigInt := new(big.Int)
- ipv6bBigInt.Set(ipv6b.Address)
-
- return ipv6aBigInt.Cmp(ipv6bBigInt)
-}
-
-// CmpPort follows the Cmp() standard protocol and returns:
-//
-// - -1 If the receiver should sort first because its port is lower than arg
-// - 0 if the SockAddr arg's port number is equal to the receiving IPv6Addr,
-// regardless of type.
-// - 1 If the argument should sort first.
-func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int {
- var saPort IPPort
- switch v := sa.(type) {
- case IPv4Addr:
- saPort = v.Port
- case IPv6Addr:
- saPort = v.Port
- default:
- return sortDeferDecision
- }
-
- switch {
- case ipv6.Port == saPort:
- return sortDeferDecision
- case ipv6.Port < saPort:
- return sortReceiverBeforeArg
- default:
- return sortArgBeforeReceiver
- }
-}
-
-// CmpRFC follows the Cmp() standard protocol and returns:
-//
-// - -1 If the receiver should sort first because it belongs to the RFC and its
-// arg does not
-// - 0 if the receiver and arg both belong to the same RFC or neither do.
-// - 1 If the arg belongs to the RFC but receiver does not.
-func (ipv6 IPv6Addr) CmpRFC(rfcNum uint, sa SockAddr) int {
- recvInRFC := IsRFC(rfcNum, ipv6)
- ipv6b, ok := sa.(IPv6Addr)
- if !ok {
- // If the receiver is part of the desired RFC and the SockAddr
- // argument is not, sort receiver before the non-IPv6 SockAddr.
- // Conversely, if the receiver is not part of the RFC, punt on
- // sorting and leave it for the next sorter.
- if recvInRFC {
- return sortReceiverBeforeArg
- } else {
- return sortDeferDecision
- }
- }
-
- argInRFC := IsRFC(rfcNum, ipv6b)
- switch {
- case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC):
- // If a and b both belong to the RFC, or neither belong to
- // rfcNum, defer sorting to the next sorter.
- return sortDeferDecision
- case recvInRFC && !argInRFC:
- return sortReceiverBeforeArg
- default:
- return sortArgBeforeReceiver
- }
-}
-
-// Contains returns true if the SockAddr is contained within the receiver.
-func (ipv6 IPv6Addr) Contains(sa SockAddr) bool {
- ipv6b, ok := sa.(IPv6Addr)
- if !ok {
- return false
- }
-
- return ipv6.ContainsNetwork(ipv6b)
-}
-
-// ContainsAddress returns true if the IPv6Address is contained within the
-// receiver.
-func (ipv6 IPv6Addr) ContainsAddress(x IPv6Address) bool {
- xAddr := IPv6Addr{
- Address: x,
- Mask: ipv6HostMask,
- }
-
- {
- xIPv6 := xAddr.FirstUsable().(IPv6Addr)
- yIPv6 := ipv6.FirstUsable().(IPv6Addr)
- if xIPv6.CmpAddress(yIPv6) >= 1 {
- return false
- }
- }
-
- {
- xIPv6 := xAddr.LastUsable().(IPv6Addr)
- yIPv6 := ipv6.LastUsable().(IPv6Addr)
- if xIPv6.CmpAddress(yIPv6) <= -1 {
- return false
- }
- }
- return true
-}
-
-// ContainsNetwork returns true if the network from IPv6Addr is contained within
-// the receiver.
-func (x IPv6Addr) ContainsNetwork(y IPv6Addr) bool {
- {
- xIPv6 := x.FirstUsable().(IPv6Addr)
- yIPv6 := y.FirstUsable().(IPv6Addr)
- if ret := xIPv6.CmpAddress(yIPv6); ret >= 1 {
- return false
- }
- }
-
- {
- xIPv6 := x.LastUsable().(IPv6Addr)
- yIPv6 := y.LastUsable().(IPv6Addr)
- if ret := xIPv6.CmpAddress(yIPv6); ret <= -1 {
- return false
- }
- }
- return true
-}
-
-// DialPacketArgs returns the arguments required to be passed to
-// net.DialUDP(). If the Mask of ipv6 is not a /128 or the Port is 0,
-// DialPacketArgs() will fail. See Host() to create an IPv6Addr with its
-// mask set to /128.
-func (ipv6 IPv6Addr) DialPacketArgs() (network, dialArgs string) {
- ipv6Mask := big.Int(*ipv6.Mask)
- if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
- return "udp6", ""
- }
- return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
-}
-
-// DialStreamArgs returns the arguments required to be passed to
-// net.DialTCP(). If the Mask of ipv6 is not a /128 or the Port is 0,
-// DialStreamArgs() will fail. See Host() to create an IPv6Addr with its
-// mask set to /128.
-func (ipv6 IPv6Addr) DialStreamArgs() (network, dialArgs string) {
- ipv6Mask := big.Int(*ipv6.Mask)
- if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
- return "tcp6", ""
- }
- return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
-}
-
-// Equal returns true if a SockAddr is equal to the receiving IPv4Addr.
-func (ipv6a IPv6Addr) Equal(sa SockAddr) bool {
- ipv6b, ok := sa.(IPv6Addr)
- if !ok {
- return false
- }
-
- if ipv6a.NetIP().String() != ipv6b.NetIP().String() {
- return false
- }
-
- if ipv6a.NetIPNet().String() != ipv6b.NetIPNet().String() {
- return false
- }
-
- if ipv6a.Port != ipv6b.Port {
- return false
- }
-
- return true
-}
-
-// FirstUsable returns an IPv6Addr set to the first address following the
-// network prefix. The first usable address in a network is normally the
-// gateway and should not be used except by devices forwarding packets
-// between two administratively distinct networks (i.e. a router). This
-// function does not discriminate against first usable vs "first address that
-// should be used." For example, FirstUsable() on "2001:0db8::0003/64" would
-// return "2001:0db8::00011".
-func (ipv6 IPv6Addr) FirstUsable() IPAddr {
- return IPv6Addr{
- Address: IPv6Address(ipv6.NetworkAddress()),
- Mask: ipv6HostMask,
- }
-}
-
-// Host returns a copy of ipv6 with its mask set to /128 so that it can be
-// used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or
-// ListenStreamArgs().
-func (ipv6 IPv6Addr) Host() IPAddr {
- // Nothing should listen on a broadcast address.
- return IPv6Addr{
- Address: ipv6.Address,
- Mask: ipv6HostMask,
- Port: ipv6.Port,
- }
-}
-
-// IPPort returns the Port number attached to the IPv6Addr
-func (ipv6 IPv6Addr) IPPort() IPPort {
- return ipv6.Port
-}
-
-// LastUsable returns the last address in a given network.
-func (ipv6 IPv6Addr) LastUsable() IPAddr {
- addr := new(big.Int)
- addr.Set(ipv6.Address)
-
- mask := new(big.Int)
- mask.Set(ipv6.Mask)
-
- negMask := new(big.Int)
- negMask.Xor(ipv6HostMask, mask)
-
- lastAddr := new(big.Int)
- lastAddr.And(addr, mask)
- lastAddr.Or(lastAddr, negMask)
-
- return IPv6Addr{
- Address: IPv6Address(lastAddr),
- Mask: ipv6HostMask,
- }
-}
-
-// ListenPacketArgs returns the arguments required to be passed to
-// net.ListenUDP(). If the Mask of ipv6 is not a /128, ListenPacketArgs()
-// will fail. See Host() to create an IPv6Addr with its mask set to /128.
-func (ipv6 IPv6Addr) ListenPacketArgs() (network, listenArgs string) {
- ipv6Mask := big.Int(*ipv6.Mask)
- if ipv6Mask.Cmp(ipv6HostMask) != 0 {
- return "udp6", ""
- }
- return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
-}
-
-// ListenStreamArgs returns the arguments required to be passed to
-// net.ListenTCP(). If the Mask of ipv6 is not a /128, ListenStreamArgs()
-// will fail. See Host() to create an IPv6Addr with its mask set to /128.
-func (ipv6 IPv6Addr) ListenStreamArgs() (network, listenArgs string) {
- ipv6Mask := big.Int(*ipv6.Mask)
- if ipv6Mask.Cmp(ipv6HostMask) != 0 {
- return "tcp6", ""
- }
- return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
-}
-
-// Maskbits returns the number of network mask bits in a given IPv6Addr. For
-// example, the Maskbits() of "2001:0db8::0003/64" would return 64.
-func (ipv6 IPv6Addr) Maskbits() int {
- maskOnes, _ := ipv6.NetIPNet().Mask.Size()
-
- return maskOnes
-}
-
-// MustIPv6Addr is a helper method that must return an IPv6Addr or panic on
-// invalid input.
-func MustIPv6Addr(addr string) IPv6Addr {
- ipv6, err := NewIPv6Addr(addr)
- if err != nil {
- panic(fmt.Sprintf("Unable to create an IPv6Addr from %+q: %v", addr, err))
- }
- return ipv6
-}
-
-// NetIP returns the address as a net.IP.
-func (ipv6 IPv6Addr) NetIP() *net.IP {
- return bigIntToNetIPv6(ipv6.Address)
-}
-
-// NetIPMask create a new net.IPMask from the IPv6Addr.
-func (ipv6 IPv6Addr) NetIPMask() *net.IPMask {
- ipv6Mask := make(net.IPMask, IPv6len)
- m := big.Int(*ipv6.Mask)
- copy(ipv6Mask, m.Bytes())
- return &ipv6Mask
-}
-
-// Network returns a pointer to the net.IPNet within IPv4Addr receiver.
-func (ipv6 IPv6Addr) NetIPNet() *net.IPNet {
- ipv6net := &net.IPNet{}
- ipv6net.IP = make(net.IP, IPv6len)
- copy(ipv6net.IP, *ipv6.NetIP())
- ipv6net.Mask = *ipv6.NetIPMask()
- return ipv6net
-}
-
-// Network returns the network prefix or network address for a given network.
-func (ipv6 IPv6Addr) Network() IPAddr {
- return IPv6Addr{
- Address: IPv6Address(ipv6.NetworkAddress()),
- Mask: ipv6.Mask,
- }
-}
-
-// NetworkAddress returns an IPv6Network of the IPv6Addr's network address.
-func (ipv6 IPv6Addr) NetworkAddress() IPv6Network {
- addr := new(big.Int)
- addr.SetBytes((*ipv6.Address).Bytes())
-
- mask := new(big.Int)
- mask.SetBytes(*ipv6.NetIPMask())
-
- netAddr := new(big.Int)
- netAddr.And(addr, mask)
-
- return IPv6Network(netAddr)
-}
-
-// Octets returns a slice of the 16 octets in an IPv6Addr's Address. The
-// order of the bytes is big endian.
-func (ipv6 IPv6Addr) Octets() []int {
- x := make([]int, IPv6len)
- for i, b := range *bigIntToNetIPv6(ipv6.Address) {
- x[i] = int(b)
- }
-
- return x
-}
-
-// String returns a string representation of the IPv6Addr
-func (ipv6 IPv6Addr) String() string {
- if ipv6.Port != 0 {
- return fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
- }
-
- if ipv6.Maskbits() == 128 {
- return ipv6.NetIP().String()
- }
-
- return fmt.Sprintf("%s/%d", ipv6.NetIP().String(), ipv6.Maskbits())
-}
-
-// Type is used as a type switch and returns TypeIPv6
-func (IPv6Addr) Type() SockAddrType {
- return TypeIPv6
-}
-
-// IPv6Attrs returns a list of attributes supported by the IPv6Addr type
-func IPv6Attrs() []AttrName {
- return ipv6AddrAttrs
-}
-
-// IPv6AddrAttr returns a string representation of an attribute for the given
-// IPv6Addr.
-func IPv6AddrAttr(ipv6 IPv6Addr, selector AttrName) string {
- fn, found := ipv6AddrAttrMap[selector]
- if !found {
- return ""
- }
-
- return fn(ipv6)
-}
-
-// ipv6AddrInit is called once at init()
-func ipv6AddrInit() {
- // Sorted for human readability
- ipv6AddrAttrs = []AttrName{
- "size", // Same position as in IPv6 for output consistency
- "uint128",
- }
-
- ipv6AddrAttrMap = map[AttrName]func(ipv6 IPv6Addr) string{
- "size": func(ipv6 IPv6Addr) string {
- netSize := big.NewInt(1)
- netSize = netSize.Lsh(netSize, uint(IPv6len*8-ipv6.Maskbits()))
- return netSize.Text(10)
- },
- "uint128": func(ipv6 IPv6Addr) string {
- b := big.Int(*ipv6.Address)
- return b.Text(10)
- },
- }
-}
-
-// bigIntToNetIPv6 is a helper function that correctly returns a net.IP with the
-// correctly padded values.
-func bigIntToNetIPv6(bi *big.Int) *net.IP {
- x := make(net.IP, IPv6len)
- ipv6Bytes := bi.Bytes()
-
- // It's possibe for ipv6Bytes to be less than IPv6len bytes in size. If
- // they are different sizes we to pad the size of response.
- if len(ipv6Bytes) < IPv6len {
- buf := new(bytes.Buffer)
- buf.Grow(IPv6len)
-
- for i := len(ipv6Bytes); i < IPv6len; i++ {
- if err := binary.Write(buf, binary.BigEndian, byte(0)); err != nil {
- panic(fmt.Sprintf("Unable to pad byte %d of input %v: %v", i, bi, err))
- }
- }
-
- for _, b := range ipv6Bytes {
- if err := binary.Write(buf, binary.BigEndian, b); err != nil {
- panic(fmt.Sprintf("Unable to preserve endianness of input %v: %v", bi, err))
- }
- }
-
- ipv6Bytes = buf.Bytes()
- }
- i := copy(x, ipv6Bytes)
- if i != IPv6len {
- panic("IPv6 wrong size")
- }
- return &x
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/rfc.go b/vendor/github.com/hashicorp/go-sockaddr/rfc.go
deleted file mode 100644
index 02e188f6fe6..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/rfc.go
+++ /dev/null
@@ -1,948 +0,0 @@
-package sockaddr
-
-// ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP
-// blocks.
-const ForwardingBlacklist = 4294967295
-const ForwardingBlacklistRFC = "4294967295"
-
-// IsRFC tests to see if an SockAddr matches the specified RFC
-func IsRFC(rfcNum uint, sa SockAddr) bool {
- rfcNetMap := KnownRFCs()
- rfcNets, ok := rfcNetMap[rfcNum]
- if !ok {
- return false
- }
-
- var contained bool
- for _, rfcNet := range rfcNets {
- if rfcNet.Contains(sa) {
- contained = true
- break
- }
- }
- return contained
-}
-
-// KnownRFCs returns an initial set of known RFCs.
-//
-// NOTE (sean@): As this list evolves over time, please submit patches to keep
-// this list current. If something isn't right, inquire, as it may just be a
-// bug on my part. Some of the inclusions were based on my judgement as to what
-// would be a useful value (e.g. RFC3330).
-//
-// Useful resources:
-//
-// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
-// * https://www.iana.org/assignments/ipv6-unicast-address-assignments/ipv6-unicast-address-assignments.xhtml
-// * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
-func KnownRFCs() map[uint]SockAddrs {
- // NOTE(sean@): Multiple SockAddrs per RFC lend themselves well to a
- // RADIX tree, but `ENOTIME`. Patches welcome.
- return map[uint]SockAddrs{
- 919: {
- // [RFC919] Broadcasting Internet Datagrams
- MustIPv4Addr("255.255.255.255/32"), // [RFC1122], §7 Broadcast IP Addressing - Proposed Standards
- },
- 1122: {
- // [RFC1122] Requirements for Internet Hosts -- Communication Layers
- MustIPv4Addr("0.0.0.0/8"), // [RFC1122], §3.2.1.3
- MustIPv4Addr("127.0.0.0/8"), // [RFC1122], §3.2.1.3
- },
- 1112: {
- // [RFC1112] Host Extensions for IP Multicasting
- MustIPv4Addr("224.0.0.0/4"), // [RFC1112], §4 Host Group Addresses
- },
- 1918: {
- // [RFC1918] Address Allocation for Private Internets
- MustIPv4Addr("10.0.0.0/8"),
- MustIPv4Addr("172.16.0.0/12"),
- MustIPv4Addr("192.168.0.0/16"),
- },
- 2544: {
- // [RFC2544] Benchmarking Methodology for Network
- // Interconnect Devices
- MustIPv4Addr("198.18.0.0/15"),
- },
- 2765: {
- // [RFC2765] Stateless IP/ICMP Translation Algorithm
- // (SIIT) (obsoleted by RFCs 6145, which itself was
- // later obsoleted by 7915).
-
- // [RFC2765], §2.1 Addresses
- MustIPv6Addr("0:0:0:0:0:ffff:0:0/96"),
- },
- 2928: {
- // [RFC2928] Initial IPv6 Sub-TLA ID Assignments
- MustIPv6Addr("2001::/16"), // Superblock
- //MustIPv6Addr("2001:0000::/23"), // IANA
- //MustIPv6Addr("2001:0200::/23"), // APNIC
- //MustIPv6Addr("2001:0400::/23"), // ARIN
- //MustIPv6Addr("2001:0600::/23"), // RIPE NCC
- //MustIPv6Addr("2001:0800::/23"), // (future assignment)
- // ...
- //MustIPv6Addr("2001:FE00::/23"), // (future assignment)
- },
- 3056: { // 6to4 address
- // [RFC3056] Connection of IPv6 Domains via IPv4 Clouds
-
- // [RFC3056], §2 IPv6 Prefix Allocation
- MustIPv6Addr("2002::/16"),
- },
- 3068: {
- // [RFC3068] An Anycast Prefix for 6to4 Relay Routers
- // (obsolete by RFC7526)
-
- // [RFC3068], § 6to4 Relay anycast address
- MustIPv4Addr("192.88.99.0/24"),
-
- // [RFC3068], §2.5 6to4 IPv6 relay anycast address
- //
- // NOTE: /120 == 128-(32-24)
- MustIPv6Addr("2002:c058:6301::/120"),
- },
- 3171: {
- // [RFC3171] IANA Guidelines for IPv4 Multicast Address Assignments
- MustIPv4Addr("224.0.0.0/4"),
- },
- 3330: {
- // [RFC3330] Special-Use IPv4 Addresses
-
- // Addresses in this block refer to source hosts on
- // "this" network. Address 0.0.0.0/32 may be used as a
- // source address for this host on this network; other
- // addresses within 0.0.0.0/8 may be used to refer to
- // specified hosts on this network [RFC1700, page 4].
- MustIPv4Addr("0.0.0.0/8"),
-
- // 10.0.0.0/8 - This block is set aside for use in
- // private networks. Its intended use is documented in
- // [RFC1918]. Addresses within this block should not
- // appear on the public Internet.
- MustIPv4Addr("10.0.0.0/8"),
-
- // 14.0.0.0/8 - This block is set aside for assignments
- // to the international system of Public Data Networks
- // [RFC1700, page 181]. The registry of assignments
- // within this block can be accessed from the "Public
- // Data Network Numbers" link on the web page at
- // http://www.iana.org/numbers.html. Addresses within
- // this block are assigned to users and should be
- // treated as such.
-
- // 24.0.0.0/8 - This block was allocated in early 1996
- // for use in provisioning IP service over cable
- // television systems. Although the IANA initially was
- // involved in making assignments to cable operators,
- // this responsibility was transferred to American
- // Registry for Internet Numbers (ARIN) in May 2001.
- // Addresses within this block are assigned in the
- // normal manner and should be treated as such.
-
- // 39.0.0.0/8 - This block was used in the "Class A
- // Subnet Experiment" that commenced in May 1995, as
- // documented in [RFC1797]. The experiment has been
- // completed and this block has been returned to the
- // pool of addresses reserved for future allocation or
- // assignment. This block therefore no longer has a
- // special use and is subject to allocation to a
- // Regional Internet Registry for assignment in the
- // normal manner.
-
- // 127.0.0.0/8 - This block is assigned for use as the Internet host
- // loopback address. A datagram sent by a higher level protocol to an
- // address anywhere within this block should loop back inside the host.
- // This is ordinarily implemented using only 127.0.0.1/32 for loopback,
- // but no addresses within this block should ever appear on any network
- // anywhere [RFC1700, page 5].
- MustIPv4Addr("127.0.0.0/8"),
-
- // 128.0.0.0/16 - This block, corresponding to the
- // numerically lowest of the former Class B addresses,
- // was initially and is still reserved by the IANA.
- // Given the present classless nature of the IP address
- // space, the basis for the reservation no longer
- // applies and addresses in this block are subject to
- // future allocation to a Regional Internet Registry for
- // assignment in the normal manner.
-
- // 169.254.0.0/16 - This is the "link local" block. It
- // is allocated for communication between hosts on a
- // single link. Hosts obtain these addresses by
- // auto-configuration, such as when a DHCP server may
- // not be found.
- MustIPv4Addr("169.254.0.0/16"),
-
- // 172.16.0.0/12 - This block is set aside for use in
- // private networks. Its intended use is documented in
- // [RFC1918]. Addresses within this block should not
- // appear on the public Internet.
- MustIPv4Addr("172.16.0.0/12"),
-
- // 191.255.0.0/16 - This block, corresponding to the numerically highest
- // to the former Class B addresses, was initially and is still reserved
- // by the IANA. Given the present classless nature of the IP address
- // space, the basis for the reservation no longer applies and addresses
- // in this block are subject to future allocation to a Regional Internet
- // Registry for assignment in the normal manner.
-
- // 192.0.0.0/24 - This block, corresponding to the
- // numerically lowest of the former Class C addresses,
- // was initially and is still reserved by the IANA.
- // Given the present classless nature of the IP address
- // space, the basis for the reservation no longer
- // applies and addresses in this block are subject to
- // future allocation to a Regional Internet Registry for
- // assignment in the normal manner.
-
- // 192.0.2.0/24 - This block is assigned as "TEST-NET" for use in
- // documentation and example code. It is often used in conjunction with
- // domain names example.com or example.net in vendor and protocol
- // documentation. Addresses within this block should not appear on the
- // public Internet.
- MustIPv4Addr("192.0.2.0/24"),
-
- // 192.88.99.0/24 - This block is allocated for use as 6to4 relay
- // anycast addresses, according to [RFC3068].
- MustIPv4Addr("192.88.99.0/24"),
-
- // 192.168.0.0/16 - This block is set aside for use in private networks.
- // Its intended use is documented in [RFC1918]. Addresses within this
- // block should not appear on the public Internet.
- MustIPv4Addr("192.168.0.0/16"),
-
- // 198.18.0.0/15 - This block has been allocated for use
- // in benchmark tests of network interconnect devices.
- // Its use is documented in [RFC2544].
- MustIPv4Addr("198.18.0.0/15"),
-
- // 223.255.255.0/24 - This block, corresponding to the
- // numerically highest of the former Class C addresses,
- // was initially and is still reserved by the IANA.
- // Given the present classless nature of the IP address
- // space, the basis for the reservation no longer
- // applies and addresses in this block are subject to
- // future allocation to a Regional Internet Registry for
- // assignment in the normal manner.
-
- // 224.0.0.0/4 - This block, formerly known as the Class
- // D address space, is allocated for use in IPv4
- // multicast address assignments. The IANA guidelines
- // for assignments from this space are described in
- // [RFC3171].
- MustIPv4Addr("224.0.0.0/4"),
-
- // 240.0.0.0/4 - This block, formerly known as the Class E address
- // space, is reserved. The "limited broadcast" destination address
- // 255.255.255.255 should never be forwarded outside the (sub-)net of
- // the source. The remainder of this space is reserved
- // for future use. [RFC1700, page 4]
- MustIPv4Addr("240.0.0.0/4"),
- },
- 3849: {
- // [RFC3849] IPv6 Address Prefix Reserved for Documentation
- MustIPv6Addr("2001:db8::/32"), // [RFC3849], §4 IANA Considerations
- },
- 3927: {
- // [RFC3927] Dynamic Configuration of IPv4 Link-Local Addresses
- MustIPv4Addr("169.254.0.0/16"), // [RFC3927], §2.1 Link-Local Address Selection
- },
- 4038: {
- // [RFC4038] Application Aspects of IPv6 Transition
-
- // [RFC4038], §4.2. IPv6 Applications in a Dual-Stack Node
- MustIPv6Addr("0:0:0:0:0:ffff::/96"),
- },
- 4193: {
- // [RFC4193] Unique Local IPv6 Unicast Addresses
- MustIPv6Addr("fc00::/7"),
- },
- 4291: {
- // [RFC4291] IP Version 6 Addressing Architecture
-
- // [RFC4291], §2.5.2 The Unspecified Address
- MustIPv6Addr("::/128"),
-
- // [RFC4291], §2.5.3 The Loopback Address
- MustIPv6Addr("::1/128"),
-
- // [RFC4291], §2.5.5.1. IPv4-Compatible IPv6 Address
- MustIPv6Addr("::/96"),
-
- // [RFC4291], §2.5.5.2. IPv4-Mapped IPv6 Address
- MustIPv6Addr("::ffff:0:0/96"),
-
- // [RFC4291], §2.5.6 Link-Local IPv6 Unicast Addresses
- MustIPv6Addr("fe80::/10"),
-
- // [RFC4291], §2.5.7 Site-Local IPv6 Unicast Addresses
- // (depreciated)
- MustIPv6Addr("fec0::/10"),
-
- // [RFC4291], §2.7 Multicast Addresses
- MustIPv6Addr("ff00::/8"),
-
- // IPv6 Multicast Information.
- //
- // In the following "table" below, `ff0x` is replaced
- // with the following values depending on the scope of
- // the query:
- //
- // IPv6 Multicast Scopes:
- // * ff00/9 // reserved
- // * ff01/9 // interface-local
- // * ff02/9 // link-local
- // * ff03/9 // realm-local
- // * ff04/9 // admin-local
- // * ff05/9 // site-local
- // * ff08/9 // organization-local
- // * ff0e/9 // global
- // * ff0f/9 // reserved
- //
- // IPv6 Multicast Addresses:
- // * ff0x::2 // All routers
- // * ff02::5 // OSPFIGP
- // * ff02::6 // OSPFIGP Designated Routers
- // * ff02::9 // RIP Routers
- // * ff02::a // EIGRP Routers
- // * ff02::d // All PIM Routers
- // * ff02::1a // All RPL Routers
- // * ff0x::fb // mDNSv6
- // * ff0x::101 // All Network Time Protocol (NTP) servers
- // * ff02::1:1 // Link Name
- // * ff02::1:2 // All-dhcp-agents
- // * ff02::1:3 // Link-local Multicast Name Resolution
- // * ff05::1:3 // All-dhcp-servers
- // * ff02::1:ff00:0/104 // Solicited-node multicast address.
- // * ff02::2:ff00:0/104 // Node Information Queries
- },
- 4380: {
- // [RFC4380] Teredo: Tunneling IPv6 over UDP through
- // Network Address Translations (NATs)
-
- // [RFC4380], §2.6 Global Teredo IPv6 Service Prefix
- MustIPv6Addr("2001:0000::/32"),
- },
- 4773: {
- // [RFC4773] Administration of the IANA Special Purpose IPv6 Address Block
- MustIPv6Addr("2001:0000::/23"), // IANA
- },
- 4843: {
- // [RFC4843] An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers (ORCHID)
- MustIPv6Addr("2001:10::/28"), // [RFC4843], §7 IANA Considerations
- },
- 5180: {
- // [RFC5180] IPv6 Benchmarking Methodology for Network Interconnect Devices
- MustIPv6Addr("2001:0200::/48"), // [RFC5180], §8 IANA Considerations
- },
- 5735: {
- // [RFC5735] Special Use IPv4 Addresses
- MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
- MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
- MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
- MustIPv4Addr("198.18.0.0/15"), // Benchmarks
- },
- 5737: {
- // [RFC5737] IPv4 Address Blocks Reserved for Documentation
- MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
- MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
- MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
- },
- 6052: {
- // [RFC6052] IPv6 Addressing of IPv4/IPv6 Translators
- MustIPv6Addr("64:ff9b::/96"), // [RFC6052], §2.1. Well-Known Prefix
- },
- 6333: {
- // [RFC6333] Dual-Stack Lite Broadband Deployments Following IPv4 Exhaustion
- MustIPv4Addr("192.0.0.0/29"), // [RFC6333], §5.7 Well-Known IPv4 Address
- },
- 6598: {
- // [RFC6598] IANA-Reserved IPv4 Prefix for Shared Address Space
- MustIPv4Addr("100.64.0.0/10"),
- },
- 6666: {
- // [RFC6666] A Discard Prefix for IPv6
- MustIPv6Addr("0100::/64"),
- },
- 6890: {
- // [RFC6890] Special-Purpose IP Address Registries
-
- // From "RFC6890 §2.2.1 Information Requirements":
- /*
- The IPv4 and IPv6 Special-Purpose Address Registries maintain the
- following information regarding each entry:
-
- o Address Block - A block of IPv4 or IPv6 addresses that has been
- registered for a special purpose.
-
- o Name - A descriptive name for the special-purpose address block.
-
- o RFC - The RFC through which the special-purpose address block was
- requested.
-
- o Allocation Date - The date upon which the special-purpose address
- block was allocated.
-
- o Termination Date - The date upon which the allocation is to be
- terminated. This field is applicable for limited-use allocations
- only.
-
- o Source - A boolean value indicating whether an address from the
- allocated special-purpose address block is valid when used as the
- source address of an IP datagram that transits two devices.
-
- o Destination - A boolean value indicating whether an address from
- the allocated special-purpose address block is valid when used as
- the destination address of an IP datagram that transits two
- devices.
-
- o Forwardable - A boolean value indicating whether a router may
- forward an IP datagram whose destination address is drawn from the
- allocated special-purpose address block between external
- interfaces.
-
- o Global - A boolean value indicating whether an IP datagram whose
- destination address is drawn from the allocated special-purpose
- address block is forwardable beyond a specified administrative
- domain.
-
- o Reserved-by-Protocol - A boolean value indicating whether the
- special-purpose address block is reserved by IP, itself. This
- value is "TRUE" if the RFC that created the special-purpose
- address block requires all compliant IP implementations to behave
- in a special way when processing packets either to or from
- addresses contained by the address block.
-
- If the value of "Destination" is FALSE, the values of "Forwardable"
- and "Global" must also be false.
- */
-
- /*+----------------------+----------------------------+
- * | Attribute | Value |
- * +----------------------+----------------------------+
- * | Address Block | 0.0.0.0/8 |
- * | Name | "This host on this network"|
- * | RFC | [RFC1122], Section 3.2.1.3 |
- * | Allocation Date | September 1981 |
- * | Termination Date | N/A |
- * | Source | True |
- * | Destination | False |
- * | Forwardable | False |
- * | Global | False |
- * | Reserved-by-Protocol | True |
- * +----------------------+----------------------------+*/
- MustIPv4Addr("0.0.0.0/8"),
-
- /*+----------------------+---------------+
- * | Attribute | Value |
- * +----------------------+---------------+
- * | Address Block | 10.0.0.0/8 |
- * | Name | Private-Use |
- * | RFC | [RFC1918] |
- * | Allocation Date | February 1996 |
- * | Termination Date | N/A |
- * | Source | True |
- * | Destination | True |
- * | Forwardable | True |
- * | Global | False |
- * | Reserved-by-Protocol | False |
- * +----------------------+---------------+ */
- MustIPv4Addr("10.0.0.0/8"),
-
- /*+----------------------+----------------------+
- | Attribute | Value |
- +----------------------+----------------------+
- | Address Block | 100.64.0.0/10 |
- | Name | Shared Address Space |
- | RFC | [RFC6598] |
- | Allocation Date | April 2012 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+----------------------+*/
- MustIPv4Addr("100.64.0.0/10"),
-
- /*+----------------------+----------------------------+
- | Attribute | Value |
- +----------------------+----------------------------+
- | Address Block | 127.0.0.0/8 |
- | Name | Loopback |
- | RFC | [RFC1122], Section 3.2.1.3 |
- | Allocation Date | September 1981 |
- | Termination Date | N/A |
- | Source | False [1] |
- | Destination | False [1] |
- | Forwardable | False [1] |
- | Global | False [1] |
- | Reserved-by-Protocol | True |
- +----------------------+----------------------------+*/
- // [1] Several protocols have been granted exceptions to
- // this rule. For examples, see [RFC4379] and
- // [RFC5884].
- MustIPv4Addr("127.0.0.0/8"),
-
- /*+----------------------+----------------+
- | Attribute | Value |
- +----------------------+----------------+
- | Address Block | 169.254.0.0/16 |
- | Name | Link Local |
- | RFC | [RFC3927] |
- | Allocation Date | May 2005 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | True |
- +----------------------+----------------+*/
- MustIPv4Addr("169.254.0.0/16"),
-
- /*+----------------------+---------------+
- | Attribute | Value |
- +----------------------+---------------+
- | Address Block | 172.16.0.0/12 |
- | Name | Private-Use |
- | RFC | [RFC1918] |
- | Allocation Date | February 1996 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+---------------+*/
- MustIPv4Addr("172.16.0.0/12"),
-
- /*+----------------------+---------------------------------+
- | Attribute | Value |
- +----------------------+---------------------------------+
- | Address Block | 192.0.0.0/24 [2] |
- | Name | IETF Protocol Assignments |
- | RFC | Section 2.1 of this document |
- | Allocation Date | January 2010 |
- | Termination Date | N/A |
- | Source | False |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+---------------------------------+*/
- // [2] Not usable unless by virtue of a more specific
- // reservation.
- MustIPv4Addr("192.0.0.0/24"),
-
- /*+----------------------+--------------------------------+
- | Attribute | Value |
- +----------------------+--------------------------------+
- | Address Block | 192.0.0.0/29 |
- | Name | IPv4 Service Continuity Prefix |
- | RFC | [RFC6333], [RFC7335] |
- | Allocation Date | June 2011 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+--------------------------------+*/
- MustIPv4Addr("192.0.0.0/29"),
-
- /*+----------------------+----------------------------+
- | Attribute | Value |
- +----------------------+----------------------------+
- | Address Block | 192.0.2.0/24 |
- | Name | Documentation (TEST-NET-1) |
- | RFC | [RFC5737] |
- | Allocation Date | January 2010 |
- | Termination Date | N/A |
- | Source | False |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+----------------------------+*/
- MustIPv4Addr("192.0.2.0/24"),
-
- /*+----------------------+--------------------+
- | Attribute | Value |
- +----------------------+--------------------+
- | Address Block | 192.88.99.0/24 |
- | Name | 6to4 Relay Anycast |
- | RFC | [RFC3068] |
- | Allocation Date | June 2001 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | True |
- | Reserved-by-Protocol | False |
- +----------------------+--------------------+*/
- MustIPv4Addr("192.88.99.0/24"),
-
- /*+----------------------+----------------+
- | Attribute | Value |
- +----------------------+----------------+
- | Address Block | 192.168.0.0/16 |
- | Name | Private-Use |
- | RFC | [RFC1918] |
- | Allocation Date | February 1996 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+----------------+*/
- MustIPv4Addr("192.168.0.0/16"),
-
- /*+----------------------+---------------+
- | Attribute | Value |
- +----------------------+---------------+
- | Address Block | 198.18.0.0/15 |
- | Name | Benchmarking |
- | RFC | [RFC2544] |
- | Allocation Date | March 1999 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+---------------+*/
- MustIPv4Addr("198.18.0.0/15"),
-
- /*+----------------------+----------------------------+
- | Attribute | Value |
- +----------------------+----------------------------+
- | Address Block | 198.51.100.0/24 |
- | Name | Documentation (TEST-NET-2) |
- | RFC | [RFC5737] |
- | Allocation Date | January 2010 |
- | Termination Date | N/A |
- | Source | False |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+----------------------------+*/
- MustIPv4Addr("198.51.100.0/24"),
-
- /*+----------------------+----------------------------+
- | Attribute | Value |
- +----------------------+----------------------------+
- | Address Block | 203.0.113.0/24 |
- | Name | Documentation (TEST-NET-3) |
- | RFC | [RFC5737] |
- | Allocation Date | January 2010 |
- | Termination Date | N/A |
- | Source | False |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+----------------------------+*/
- MustIPv4Addr("203.0.113.0/24"),
-
- /*+----------------------+----------------------+
- | Attribute | Value |
- +----------------------+----------------------+
- | Address Block | 240.0.0.0/4 |
- | Name | Reserved |
- | RFC | [RFC1112], Section 4 |
- | Allocation Date | August 1989 |
- | Termination Date | N/A |
- | Source | False |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | True |
- +----------------------+----------------------+*/
- MustIPv4Addr("240.0.0.0/4"),
-
- /*+----------------------+----------------------+
- | Attribute | Value |
- +----------------------+----------------------+
- | Address Block | 255.255.255.255/32 |
- | Name | Limited Broadcast |
- | RFC | [RFC0919], Section 7 |
- | Allocation Date | October 1984 |
- | Termination Date | N/A |
- | Source | False |
- | Destination | True |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+----------------------+*/
- MustIPv4Addr("255.255.255.255/32"),
-
- /*+----------------------+------------------+
- | Attribute | Value |
- +----------------------+------------------+
- | Address Block | ::1/128 |
- | Name | Loopback Address |
- | RFC | [RFC4291] |
- | Allocation Date | February 2006 |
- | Termination Date | N/A |
- | Source | False |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | True |
- +----------------------+------------------+*/
- MustIPv6Addr("::1/128"),
-
- /*+----------------------+---------------------+
- | Attribute | Value |
- +----------------------+---------------------+
- | Address Block | ::/128 |
- | Name | Unspecified Address |
- | RFC | [RFC4291] |
- | Allocation Date | February 2006 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | True |
- +----------------------+---------------------+*/
- MustIPv6Addr("::/128"),
-
- /*+----------------------+---------------------+
- | Attribute | Value |
- +----------------------+---------------------+
- | Address Block | 64:ff9b::/96 |
- | Name | IPv4-IPv6 Translat. |
- | RFC | [RFC6052] |
- | Allocation Date | October 2010 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | True |
- | Reserved-by-Protocol | False |
- +----------------------+---------------------+*/
- MustIPv6Addr("64:ff9b::/96"),
-
- /*+----------------------+---------------------+
- | Attribute | Value |
- +----------------------+---------------------+
- | Address Block | ::ffff:0:0/96 |
- | Name | IPv4-mapped Address |
- | RFC | [RFC4291] |
- | Allocation Date | February 2006 |
- | Termination Date | N/A |
- | Source | False |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | True |
- +----------------------+---------------------+*/
- MustIPv6Addr("::ffff:0:0/96"),
-
- /*+----------------------+----------------------------+
- | Attribute | Value |
- +----------------------+----------------------------+
- | Address Block | 100::/64 |
- | Name | Discard-Only Address Block |
- | RFC | [RFC6666] |
- | Allocation Date | June 2012 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+----------------------------+*/
- MustIPv6Addr("100::/64"),
-
- /*+----------------------+---------------------------+
- | Attribute | Value |
- +----------------------+---------------------------+
- | Address Block | 2001::/23 |
- | Name | IETF Protocol Assignments |
- | RFC | [RFC2928] |
- | Allocation Date | September 2000 |
- | Termination Date | N/A |
- | Source | False[1] |
- | Destination | False[1] |
- | Forwardable | False[1] |
- | Global | False[1] |
- | Reserved-by-Protocol | False |
- +----------------------+---------------------------+*/
- // [1] Unless allowed by a more specific allocation.
- MustIPv6Addr("2001::/16"),
-
- /*+----------------------+----------------+
- | Attribute | Value |
- +----------------------+----------------+
- | Address Block | 2001::/32 |
- | Name | TEREDO |
- | RFC | [RFC4380] |
- | Allocation Date | January 2006 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+----------------+*/
- // Covered by previous entry, included for completeness.
- //
- // MustIPv6Addr("2001::/16"),
-
- /*+----------------------+----------------+
- | Attribute | Value |
- +----------------------+----------------+
- | Address Block | 2001:2::/48 |
- | Name | Benchmarking |
- | RFC | [RFC5180] |
- | Allocation Date | April 2008 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+----------------+*/
- // Covered by previous entry, included for completeness.
- //
- // MustIPv6Addr("2001:2::/48"),
-
- /*+----------------------+---------------+
- | Attribute | Value |
- +----------------------+---------------+
- | Address Block | 2001:db8::/32 |
- | Name | Documentation |
- | RFC | [RFC3849] |
- | Allocation Date | July 2004 |
- | Termination Date | N/A |
- | Source | False |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+---------------+*/
- // Covered by previous entry, included for completeness.
- //
- // MustIPv6Addr("2001:db8::/32"),
-
- /*+----------------------+--------------+
- | Attribute | Value |
- +----------------------+--------------+
- | Address Block | 2001:10::/28 |
- | Name | ORCHID |
- | RFC | [RFC4843] |
- | Allocation Date | March 2007 |
- | Termination Date | March 2014 |
- | Source | False |
- | Destination | False |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+--------------+*/
- // Covered by previous entry, included for completeness.
- //
- // MustIPv6Addr("2001:10::/28"),
-
- /*+----------------------+---------------+
- | Attribute | Value |
- +----------------------+---------------+
- | Address Block | 2002::/16 [2] |
- | Name | 6to4 |
- | RFC | [RFC3056] |
- | Allocation Date | February 2001 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | N/A [2] |
- | Reserved-by-Protocol | False |
- +----------------------+---------------+*/
- // [2] See [RFC3056] for details.
- MustIPv6Addr("2002::/16"),
-
- /*+----------------------+--------------+
- | Attribute | Value |
- +----------------------+--------------+
- | Address Block | fc00::/7 |
- | Name | Unique-Local |
- | RFC | [RFC4193] |
- | Allocation Date | October 2005 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | True |
- | Global | False |
- | Reserved-by-Protocol | False |
- +----------------------+--------------+*/
- MustIPv6Addr("fc00::/7"),
-
- /*+----------------------+-----------------------+
- | Attribute | Value |
- +----------------------+-----------------------+
- | Address Block | fe80::/10 |
- | Name | Linked-Scoped Unicast |
- | RFC | [RFC4291] |
- | Allocation Date | February 2006 |
- | Termination Date | N/A |
- | Source | True |
- | Destination | True |
- | Forwardable | False |
- | Global | False |
- | Reserved-by-Protocol | True |
- +----------------------+-----------------------+*/
- MustIPv6Addr("fe80::/10"),
- },
- 7335: {
- // [RFC7335] IPv4 Service Continuity Prefix
- MustIPv4Addr("192.0.0.0/29"), // [RFC7335], §6 IANA Considerations
- },
- ForwardingBlacklist: { // Pseudo-RFC
- // Blacklist of non-forwardable IP blocks taken from RFC6890
- //
- // TODO: the attributes for forwardable should be
- // searcahble and embedded in the main list of RFCs
- // above.
- MustIPv4Addr("0.0.0.0/8"),
- MustIPv4Addr("127.0.0.0/8"),
- MustIPv4Addr("169.254.0.0/16"),
- MustIPv4Addr("192.0.0.0/24"),
- MustIPv4Addr("192.0.2.0/24"),
- MustIPv4Addr("198.51.100.0/24"),
- MustIPv4Addr("203.0.113.0/24"),
- MustIPv4Addr("240.0.0.0/4"),
- MustIPv4Addr("255.255.255.255/32"),
- MustIPv6Addr("::1/128"),
- MustIPv6Addr("::/128"),
- MustIPv6Addr("::ffff:0:0/96"),
-
- // There is no way of expressing a whitelist per RFC2928
- // atm without creating a negative mask, which I don't
- // want to do atm.
- //MustIPv6Addr("2001::/23"),
-
- MustIPv6Addr("2001:db8::/32"),
- MustIPv6Addr("2001:10::/28"),
- MustIPv6Addr("fe80::/10"),
- },
- }
-}
-
-// VisitAllRFCs iterates over all known RFCs and calls the visitor
-func VisitAllRFCs(fn func(rfcNum uint, sockaddrs SockAddrs)) {
- rfcNetMap := KnownRFCs()
-
- // Blacklist of faux-RFCs. Don't show the world that we're abusing the
- // RFC system in this library.
- rfcBlacklist := map[uint]struct{}{
- ForwardingBlacklist: {},
- }
-
- for rfcNum, sas := range rfcNetMap {
- if _, found := rfcBlacklist[rfcNum]; !found {
- fn(rfcNum, sas)
- }
- }
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info.go b/vendor/github.com/hashicorp/go-sockaddr/route_info.go
deleted file mode 100644
index 2a3ee1db9e8..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/route_info.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package sockaddr
-
-// RouteInterface specifies an interface for obtaining memoized route table and
-// network information from a given OS.
-type RouteInterface interface {
- // GetDefaultInterfaceName returns the name of the interface that has a
- // default route or an error and an empty string if a problem was
- // encountered.
- GetDefaultInterfaceName() (string, error)
-}
-
-// VisitCommands visits each command used by the platform-specific RouteInfo
-// implementation.
-func (ri routeInfo) VisitCommands(fn func(name string, cmd []string)) {
- for k, v := range ri.cmds {
- cmds := append([]string(nil), v...)
- fn(k, cmds)
- }
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_android.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_android.go
deleted file mode 100644
index 9885915a6ba..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/route_info_android.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package sockaddr
-
-import (
- "errors"
- "os/exec"
-)
-
-type routeInfo struct {
- cmds map[string][]string
-}
-
-// NewRouteInfo returns a Android-specific implementation of the RouteInfo
-// interface.
-func NewRouteInfo() (routeInfo, error) {
- return routeInfo{
- cmds: map[string][]string{"ip": {"/system/bin/ip", "route", "get", "8.8.8.8"}},
- }, nil
-}
-
-// GetDefaultInterfaceName returns the interface name attached to the default
-// route on the default interface.
-func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
- out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output()
- if err != nil {
- return "", err
- }
-
-
- var ifName string
- if ifName, err = parseDefaultIfNameFromIPCmdAndroid(string(out)); err != nil {
- return "", errors.New("No default interface found")
- }
- return ifName, nil
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go
deleted file mode 100644
index 705757abc7b..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/route_info_bsd.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// +build darwin dragonfly freebsd netbsd openbsd
-
-package sockaddr
-
-import "os/exec"
-
-var cmds map[string][]string = map[string][]string{
- "route": {"/sbin/route", "-n", "get", "default"},
-}
-
-type routeInfo struct {
- cmds map[string][]string
-}
-
-// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
-// interface.
-func NewRouteInfo() (routeInfo, error) {
- return routeInfo{
- cmds: cmds,
- }, nil
-}
-
-// GetDefaultInterfaceName returns the interface name attached to the default
-// route on the default interface.
-func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
- out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
- if err != nil {
- return "", err
- }
-
- var ifName string
- if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
- return "", err
- }
- return ifName, nil
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_default.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_default.go
deleted file mode 100644
index d1b009f6538..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/route_info_default.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// +build android nacl plan9
-
-package sockaddr
-
-import "errors"
-
-// getDefaultIfName is the default interface function for unsupported platforms.
-func getDefaultIfName() (string, error) {
- return "", errors.New("No default interface found (unsupported platform)")
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go
deleted file mode 100644
index b62ce6ecb21..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// +build !android
-
-package sockaddr
-
-import (
- "errors"
- "os/exec"
-)
-
-type routeInfo struct {
- cmds map[string][]string
-}
-
-// NewRouteInfo returns a Linux-specific implementation of the RouteInfo
-// interface.
-func NewRouteInfo() (routeInfo, error) {
- // CoreOS Container Linux moved ip to /usr/bin/ip, so look it up on
- // $PATH and fallback to /sbin/ip on error.
- path, _ := exec.LookPath("ip")
- if path == "" {
- path = "/sbin/ip"
- }
-
- return routeInfo{
- cmds: map[string][]string{"ip": {path, "route"}},
- }, nil
-}
-
-// GetDefaultInterfaceName returns the interface name attached to the default
-// route on the default interface.
-func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
- out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output()
- if err != nil {
- return "", err
- }
-
- var ifName string
- if ifName, err = parseDefaultIfNameFromIPCmd(string(out)); err != nil {
- return "", errors.New("No default interface found")
- }
- return ifName, nil
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go
deleted file mode 100644
index ee8e7984d79..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/route_info_solaris.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package sockaddr
-
-import (
- "errors"
- "os/exec"
-)
-
-var cmds map[string][]string = map[string][]string{
- "route": {"/usr/sbin/route", "-n", "get", "default"},
-}
-
-type routeInfo struct {
- cmds map[string][]string
-}
-
-// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
-// interface.
-func NewRouteInfo() (routeInfo, error) {
- return routeInfo{
- cmds: cmds,
- }, nil
-}
-
-// GetDefaultInterfaceName returns the interface name attached to the default
-// route on the default interface.
-func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
- out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
- if err != nil {
- return "", err
- }
-
- var ifName string
- if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
- return "", errors.New("No default interface found")
- }
- return ifName, nil
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go
deleted file mode 100644
index 3da972883e8..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/route_info_windows.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package sockaddr
-
-import "os/exec"
-
-var cmds map[string][]string = map[string][]string{
- "netstat": {"netstat", "-rn"},
- "ipconfig": {"ipconfig"},
-}
-
-type routeInfo struct {
- cmds map[string][]string
-}
-
-// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
-// interface.
-func NewRouteInfo() (routeInfo, error) {
- return routeInfo{
- cmds: cmds,
- }, nil
-}
-
-// GetDefaultInterfaceName returns the interface name attached to the default
-// route on the default interface.
-func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
- ifNameOut, err := exec.Command(cmds["netstat"][0], cmds["netstat"][1:]...).Output()
- if err != nil {
- return "", err
- }
-
- ipconfigOut, err := exec.Command(cmds["ipconfig"][0], cmds["ipconfig"][1:]...).Output()
- if err != nil {
- return "", err
- }
-
- ifName, err := parseDefaultIfNameWindows(string(ifNameOut), string(ipconfigOut))
- if err != nil {
- return "", err
- }
-
- return ifName, nil
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go b/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go
deleted file mode 100644
index 826c91c2e3d..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go
+++ /dev/null
@@ -1,206 +0,0 @@
-package sockaddr
-
-import (
- "encoding/json"
- "fmt"
- "strings"
-)
-
-type SockAddrType int
-type AttrName string
-
-const (
- TypeUnknown SockAddrType = 0x0
- TypeUnix = 0x1
- TypeIPv4 = 0x2
- TypeIPv6 = 0x4
-
- // TypeIP is the union of TypeIPv4 and TypeIPv6
- TypeIP = 0x6
-)
-
-type SockAddr interface {
- // CmpRFC returns 0 if SockAddr exactly matches one of the matched RFC
- // networks, -1 if the receiver is contained within the RFC network, or
- // 1 if the address is not contained within the RFC.
- CmpRFC(rfcNum uint, sa SockAddr) int
-
- // Contains returns true if the SockAddr arg is contained within the
- // receiver
- Contains(SockAddr) bool
-
- // Equal allows for the comparison of two SockAddrs
- Equal(SockAddr) bool
-
- DialPacketArgs() (string, string)
- DialStreamArgs() (string, string)
- ListenPacketArgs() (string, string)
- ListenStreamArgs() (string, string)
-
- // String returns the string representation of SockAddr
- String() string
-
- // Type returns the SockAddrType
- Type() SockAddrType
-}
-
-// sockAddrAttrMap is a map of the SockAddr type-specific attributes.
-var sockAddrAttrMap map[AttrName]func(SockAddr) string
-var sockAddrAttrs []AttrName
-
-func init() {
- sockAddrInit()
-}
-
-// New creates a new SockAddr from the string. The order in which New()
-// attempts to construct a SockAddr is: IPv4Addr, IPv6Addr, SockAddrUnix.
-//
-// NOTE: New() relies on the heuristic wherein if the path begins with either a
-// '.' or '/' character before creating a new UnixSock. For UNIX sockets that
-// are absolute paths or are nested within a sub-directory, this works as
-// expected, however if the UNIX socket is contained in the current working
-// directory, this will fail unless the path begins with "./"
-// (e.g. "./my-local-socket"). Calls directly to NewUnixSock() do not suffer
-// this limitation. Invalid IP addresses such as "256.0.0.0/-1" will run afoul
-// of this heuristic and be assumed to be a valid UNIX socket path (which they
-// are, but it is probably not what you want and you won't realize it until you
-// stat(2) the file system to discover it doesn't exist).
-func NewSockAddr(s string) (SockAddr, error) {
- ipv4Addr, err := NewIPv4Addr(s)
- if err == nil {
- return ipv4Addr, nil
- }
-
- ipv6Addr, err := NewIPv6Addr(s)
- if err == nil {
- return ipv6Addr, nil
- }
-
- // Check to make sure the string begins with either a '.' or '/', or
- // contains a '/'.
- if len(s) > 1 && (strings.IndexAny(s[0:1], "./") != -1 || strings.IndexByte(s, '/') != -1) {
- unixSock, err := NewUnixSock(s)
- if err == nil {
- return unixSock, nil
- }
- }
-
- return nil, fmt.Errorf("Unable to convert %q to an IPv4 or IPv6 address, or a UNIX Socket", s)
-}
-
-// ToIPAddr returns an IPAddr type or nil if the type conversion fails.
-func ToIPAddr(sa SockAddr) *IPAddr {
- ipa, ok := sa.(IPAddr)
- if !ok {
- return nil
- }
- return &ipa
-}
-
-// ToIPv4Addr returns an IPv4Addr type or nil if the type conversion fails.
-func ToIPv4Addr(sa SockAddr) *IPv4Addr {
- switch v := sa.(type) {
- case IPv4Addr:
- return &v
- default:
- return nil
- }
-}
-
-// ToIPv6Addr returns an IPv6Addr type or nil if the type conversion fails.
-func ToIPv6Addr(sa SockAddr) *IPv6Addr {
- switch v := sa.(type) {
- case IPv6Addr:
- return &v
- default:
- return nil
- }
-}
-
-// ToUnixSock returns a UnixSock type or nil if the type conversion fails.
-func ToUnixSock(sa SockAddr) *UnixSock {
- switch v := sa.(type) {
- case UnixSock:
- return &v
- default:
- return nil
- }
-}
-
-// SockAddrAttr returns a string representation of an attribute for the given
-// SockAddr.
-func SockAddrAttr(sa SockAddr, selector AttrName) string {
- fn, found := sockAddrAttrMap[selector]
- if !found {
- return ""
- }
-
- return fn(sa)
-}
-
-// String() for SockAddrType returns a string representation of the
-// SockAddrType (e.g. "IPv4", "IPv6", "UNIX", "IP", or "unknown").
-func (sat SockAddrType) String() string {
- switch sat {
- case TypeIPv4:
- return "IPv4"
- case TypeIPv6:
- return "IPv6"
- // There is no concrete "IP" type. Leaving here as a reminder.
- // case TypeIP:
- // return "IP"
- case TypeUnix:
- return "UNIX"
- default:
- panic("unsupported type")
- }
-}
-
-// sockAddrInit is called once at init()
-func sockAddrInit() {
- sockAddrAttrs = []AttrName{
- "type", // type should be first
- "string",
- }
-
- sockAddrAttrMap = map[AttrName]func(sa SockAddr) string{
- "string": func(sa SockAddr) string {
- return sa.String()
- },
- "type": func(sa SockAddr) string {
- return sa.Type().String()
- },
- }
-}
-
-// UnixSockAttrs returns a list of attributes supported by the UnixSock type
-func SockAddrAttrs() []AttrName {
- return sockAddrAttrs
-}
-
-// Although this is pretty trivial to do in a program, having the logic here is
-// useful all around. Note that this marshals into a *string* -- the underlying
-// string representation of the sockaddr. If you then unmarshal into this type
-// in Go, all will work as expected, but externally you can take what comes out
-// and use the string value directly.
-type SockAddrMarshaler struct {
- SockAddr
-}
-
-func (s *SockAddrMarshaler) MarshalJSON() ([]byte, error) {
- return json.Marshal(s.SockAddr.String())
-}
-
-func (s *SockAddrMarshaler) UnmarshalJSON(in []byte) error {
- var str string
- err := json.Unmarshal(in, &str)
- if err != nil {
- return err
- }
- sa, err := NewSockAddr(str)
- if err != nil {
- return err
- }
- s.SockAddr = sa
- return nil
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go
deleted file mode 100644
index 75fbffb1eab..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/sockaddrs.go
+++ /dev/null
@@ -1,193 +0,0 @@
-package sockaddr
-
-import (
- "bytes"
- "sort"
-)
-
-// SockAddrs is a slice of SockAddrs
-type SockAddrs []SockAddr
-
-func (s SockAddrs) Len() int { return len(s) }
-func (s SockAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
-// CmpAddrFunc is the function signature that must be met to be used in the
-// OrderedAddrBy multiAddrSorter
-type CmpAddrFunc func(p1, p2 *SockAddr) int
-
-// multiAddrSorter implements the Sort interface, sorting the SockAddrs within.
-type multiAddrSorter struct {
- addrs SockAddrs
- cmp []CmpAddrFunc
-}
-
-// Sort sorts the argument slice according to the Cmp functions passed to
-// OrderedAddrBy.
-func (ms *multiAddrSorter) Sort(sockAddrs SockAddrs) {
- ms.addrs = sockAddrs
- sort.Sort(ms)
-}
-
-// OrderedAddrBy sorts SockAddr by the list of sort function pointers.
-func OrderedAddrBy(cmpFuncs ...CmpAddrFunc) *multiAddrSorter {
- return &multiAddrSorter{
- cmp: cmpFuncs,
- }
-}
-
-// Len is part of sort.Interface.
-func (ms *multiAddrSorter) Len() int {
- return len(ms.addrs)
-}
-
-// Less is part of sort.Interface. It is implemented by looping along the
-// Cmp() functions until it finds a comparison that is either less than,
-// equal to, or greater than.
-func (ms *multiAddrSorter) Less(i, j int) bool {
- p, q := &ms.addrs[i], &ms.addrs[j]
- // Try all but the last comparison.
- var k int
- for k = 0; k < len(ms.cmp)-1; k++ {
- cmp := ms.cmp[k]
- x := cmp(p, q)
- switch x {
- case -1:
- // p < q, so we have a decision.
- return true
- case 1:
- // p > q, so we have a decision.
- return false
- }
- // p == q; try the next comparison.
- }
- // All comparisons to here said "equal", so just return whatever the
- // final comparison reports.
- switch ms.cmp[k](p, q) {
- case -1:
- return true
- case 1:
- return false
- default:
- // Still a tie! Now what?
- return false
- }
-}
-
-// Swap is part of sort.Interface.
-func (ms *multiAddrSorter) Swap(i, j int) {
- ms.addrs[i], ms.addrs[j] = ms.addrs[j], ms.addrs[i]
-}
-
-const (
- // NOTE (sean@): These constants are here for code readability only and
- // are sprucing up the code for readability purposes. Some of the
- // Cmp*() variants have confusing logic (especially when dealing with
- // mixed-type comparisons) and this, I think, has made it easier to grok
- // the code faster.
- sortReceiverBeforeArg = -1
- sortDeferDecision = 0
- sortArgBeforeReceiver = 1
-)
-
-// AscAddress is a sorting function to sort SockAddrs by their respective
-// address type. Non-equal types are deferred in the sort.
-func AscAddress(p1Ptr, p2Ptr *SockAddr) int {
- p1 := *p1Ptr
- p2 := *p2Ptr
-
- switch v := p1.(type) {
- case IPv4Addr:
- return v.CmpAddress(p2)
- case IPv6Addr:
- return v.CmpAddress(p2)
- case UnixSock:
- return v.CmpAddress(p2)
- default:
- return sortDeferDecision
- }
-}
-
-// AscPort is a sorting function to sort SockAddrs by their respective address
-// type. Non-equal types are deferred in the sort.
-func AscPort(p1Ptr, p2Ptr *SockAddr) int {
- p1 := *p1Ptr
- p2 := *p2Ptr
-
- switch v := p1.(type) {
- case IPv4Addr:
- return v.CmpPort(p2)
- case IPv6Addr:
- return v.CmpPort(p2)
- default:
- return sortDeferDecision
- }
-}
-
-// AscPrivate is a sorting function to sort "more secure" private values before
-// "more public" values. Both IPv4 and IPv6 are compared against RFC6890
-// (RFC6890 includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and
-// IPv6 includes RFC4193).
-func AscPrivate(p1Ptr, p2Ptr *SockAddr) int {
- p1 := *p1Ptr
- p2 := *p2Ptr
-
- switch v := p1.(type) {
- case IPv4Addr, IPv6Addr:
- return v.CmpRFC(6890, p2)
- default:
- return sortDeferDecision
- }
-}
-
-// AscNetworkSize is a sorting function to sort SockAddrs based on their network
-// size. Non-equal types are deferred in the sort.
-func AscNetworkSize(p1Ptr, p2Ptr *SockAddr) int {
- p1 := *p1Ptr
- p2 := *p2Ptr
- p1Type := p1.Type()
- p2Type := p2.Type()
-
- // Network size operations on non-IP types make no sense
- if p1Type != p2Type && p1Type != TypeIP {
- return sortDeferDecision
- }
-
- ipA := p1.(IPAddr)
- ipB := p2.(IPAddr)
-
- return bytes.Compare([]byte(*ipA.NetIPMask()), []byte(*ipB.NetIPMask()))
-}
-
-// AscType is a sorting function to sort "more secure" types before
-// "less-secure" types.
-func AscType(p1Ptr, p2Ptr *SockAddr) int {
- p1 := *p1Ptr
- p2 := *p2Ptr
- p1Type := p1.Type()
- p2Type := p2.Type()
- switch {
- case p1Type < p2Type:
- return sortReceiverBeforeArg
- case p1Type == p2Type:
- return sortDeferDecision
- case p1Type > p2Type:
- return sortArgBeforeReceiver
- default:
- return sortDeferDecision
- }
-}
-
-// FilterByType returns two lists: a list of matched and unmatched SockAddrs
-func (sas SockAddrs) FilterByType(type_ SockAddrType) (matched, excluded SockAddrs) {
- matched = make(SockAddrs, 0, len(sas))
- excluded = make(SockAddrs, 0, len(sas))
-
- for _, sa := range sas {
- if sa.Type()&type_ != 0 {
- matched = append(matched, sa)
- } else {
- excluded = append(excluded, sa)
- }
- }
- return matched, excluded
-}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/unixsock.go b/vendor/github.com/hashicorp/go-sockaddr/unixsock.go
deleted file mode 100644
index f3be3f67e77..00000000000
--- a/vendor/github.com/hashicorp/go-sockaddr/unixsock.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package sockaddr
-
-import (
- "fmt"
- "strings"
-)
-
-type UnixSock struct {
- SockAddr
- path string
-}
-type UnixSocks []*UnixSock
-
-// unixAttrMap is a map of the UnixSockAddr type-specific attributes.
-var unixAttrMap map[AttrName]func(UnixSock) string
-var unixAttrs []AttrName
-
-func init() {
- unixAttrInit()
-}
-
-// NewUnixSock creates an UnixSock from a string path. String can be in the
-// form of either URI-based string (e.g. `file:///etc/passwd`), an absolute
-// path (e.g. `/etc/passwd`), or a relative path (e.g. `./foo`).
-func NewUnixSock(s string) (ret UnixSock, err error) {
- ret.path = s
- return ret, nil
-}
-
-// CmpAddress follows the Cmp() standard protocol and returns:
-//
-// - -1 If the receiver should sort first because its name lexically sorts before arg
-// - 0 if the SockAddr arg is not a UnixSock, or is a UnixSock with the same path.
-// - 1 If the argument should sort first.
-func (us UnixSock) CmpAddress(sa SockAddr) int {
- usb, ok := sa.(UnixSock)
- if !ok {
- return sortDeferDecision
- }
-
- return strings.Compare(us.Path(), usb.Path())
-}
-
-// DialPacketArgs returns the arguments required to be passed to net.DialUnix()
-// with the `unixgram` network type.
-func (us UnixSock) DialPacketArgs() (network, dialArgs string) {
- return "unixgram", us.path
-}
-
-// DialStreamArgs returns the arguments required to be passed to net.DialUnix()
-// with the `unix` network type.
-func (us UnixSock) DialStreamArgs() (network, dialArgs string) {
- return "unix", us.path
-}
-
-// Equal returns true if a SockAddr is equal to the receiving UnixSock.
-func (us UnixSock) Equal(sa SockAddr) bool {
- usb, ok := sa.(UnixSock)
- if !ok {
- return false
- }
-
- if us.Path() != usb.Path() {
- return false
- }
-
- return true
-}
-
-// ListenPacketArgs returns the arguments required to be passed to
-// net.ListenUnixgram() with the `unixgram` network type.
-func (us UnixSock) ListenPacketArgs() (network, dialArgs string) {
- return "unixgram", us.path
-}
-
-// ListenStreamArgs returns the arguments required to be passed to
-// net.ListenUnix() with the `unix` network type.
-func (us UnixSock) ListenStreamArgs() (network, dialArgs string) {
- return "unix", us.path
-}
-
-// MustUnixSock is a helper method that must return an UnixSock or panic on
-// invalid input.
-func MustUnixSock(addr string) UnixSock {
- us, err := NewUnixSock(addr)
- if err != nil {
- panic(fmt.Sprintf("Unable to create a UnixSock from %+q: %v", addr, err))
- }
- return us
-}
-
-// Path returns the given path of the UnixSock
-func (us UnixSock) Path() string {
- return us.path
-}
-
-// String returns the path of the UnixSock
-func (us UnixSock) String() string {
- return fmt.Sprintf("%+q", us.path)
-}
-
-// Type is used as a type switch and returns TypeUnix
-func (UnixSock) Type() SockAddrType {
- return TypeUnix
-}
-
-// UnixSockAttrs returns a list of attributes supported by the UnixSockAddr type
-func UnixSockAttrs() []AttrName {
- return unixAttrs
-}
-
-// UnixSockAttr returns a string representation of an attribute for the given
-// UnixSock.
-func UnixSockAttr(us UnixSock, attrName AttrName) string {
- fn, found := unixAttrMap[attrName]
- if !found {
- return ""
- }
-
- return fn(us)
-}
-
-// unixAttrInit is called once at init()
-func unixAttrInit() {
- // Sorted for human readability
- unixAttrs = []AttrName{
- "path",
- }
-
- unixAttrMap = map[AttrName]func(us UnixSock) string{
- "path": func(us UnixSock) string {
- return us.Path()
- },
- }
-}
diff --git a/vendor/github.com/hashicorp/golang-lru/LICENSE b/vendor/github.com/hashicorp/golang-lru/LICENSE
deleted file mode 100644
index be2cc4dfb60..00000000000
--- a/vendor/github.com/hashicorp/golang-lru/LICENSE
+++ /dev/null
@@ -1,362 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. "Contributor"
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the terms of
- a Secondary License.
-
-1.6. "Executable Form"
-
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-
- means a work that combines Covered Software with other material, in a
- separate file or files, that is not Covered Software.
-
-1.8. "License"
-
- means this document.
-
-1.9. "Licensable"
-
- means having the right to grant, to the maximum extent possible, whether
- at the time of the initial grant or subsequently, any and all of the
- rights conveyed by this License.
-
-1.10. "Modifications"
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. "Patent Claims" of a Contributor
-
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the License,
- by the making, using, selling, offering for sale, having made, import,
- or transfer of either its Contributions or its Contributor Version.
-
-1.12. "Secondary License"
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. "Source Code Form"
-
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, "control" means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution
- become effective for each Contribution on the date the Contributor first
- distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under
- this License. No additional rights or licenses will be implied from the
- distribution or licensing of Covered Software under this License.
- Notwithstanding Section 2.1(b) above, no patent license is granted by a
- Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
- This License does not grant any rights in the trademarks, service marks,
- or logos of any Contributor (except as may be necessary to comply with
- the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this
- License (see Section 10.2) or under the terms of a Secondary License (if
- permitted under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its
- Contributions are its original creation(s) or it has sufficient rights to
- grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under
- applicable copyright doctrines of fair use, fair dealing, or other
- equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under
- the terms of this License. You must inform recipients that the Source
- Code Form of the Covered Software is governed by the terms of this
- License, and how they can obtain a copy of this License. You may not
- attempt to alter or restrict the recipients' rights in the Source Code
- Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter the
- recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for
- the Covered Software. If the Larger Work is a combination of Covered
- Software with a work governed by one or more Secondary Licenses, and the
- Covered Software is not Incompatible With Secondary Licenses, this
- License permits You to additionally distribute such Covered Software
- under the terms of such Secondary License(s), so that the recipient of
- the Larger Work may, at their option, further distribute the Covered
- Software under the terms of either this License or such Secondary
- License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices
- (including copyright notices, patent notices, disclaimers of warranty, or
- limitations of liability) contained within the Source Code Form of the
- Covered Software, except that You may alter any license notices to the
- extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on
- behalf of any Contributor. You must make it absolutely clear that any
- such warranty, support, indemnity, or liability obligation is offered by
- You alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute,
- judicial order, or regulation then You must: (a) comply with the terms of
- this License to the maximum extent possible; and (b) describe the
- limitations and the code they affect. Such description must be placed in a
- text file included with all distributions of the Covered Software under
- this License. Except to the extent prohibited by statute or regulation,
- such description must be sufficiently detailed for a recipient of ordinary
- skill to be able to understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing
- basis, if such Contributor fails to notify You of the non-compliance by
- some reasonable means prior to 60 days after You have come back into
- compliance. Moreover, Your grants from a particular Contributor are
- reinstated on an ongoing basis if such Contributor notifies You of the
- non-compliance by some reasonable means, this is the first time You have
- received notice of non-compliance with this License from such
- Contributor, and You become compliant prior to 30 days after Your receipt
- of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions,
- counter-claims, and cross-claims) alleging that a Contributor Version
- directly or indirectly infringes any patent, then the rights granted to
- You by any and all Contributors for the Covered Software under Section
- 2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an "as is" basis,
- without warranty of any kind, either expressed, implied, or statutory,
- including, without limitation, warranties that the Covered Software is free
- of defects, merchantable, fit for a particular purpose or non-infringing.
- The entire risk as to the quality and performance of the Covered Software
- is with You. Should any Covered Software prove defective in any respect,
- You (not any Contributor) assume the cost of any necessary servicing,
- repair, or correction. This disclaimer of warranty constitutes an essential
- part of this License. No use of any Covered Software is authorized under
- this License except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from
- such party's negligence to the extent applicable law prohibits such
- limitation. Some jurisdictions do not allow the exclusion or limitation of
- incidental or consequential damages, so this exclusion and limitation may
- not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts
- of a jurisdiction where the defendant maintains its principal place of
- business and such litigation shall be governed by laws of that
- jurisdiction, without reference to its conflict-of-law provisions. Nothing
- in this Section shall prevent a party's ability to bring cross-claims or
- counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. Any law or regulation which provides that
- the language of a contract shall be construed against the drafter shall not
- be used to construe this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version
- of the License under which You originally received the Covered Software,
- or under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a
- modified version of this License if you rename the license and remove
- any references to the name of the license steward (except to note that
- such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
- Licenses If You choose to distribute Source Code Form that is
- Incompatible With Secondary Licenses under the terms of this version of
- the License, the notice described in Exhibit B of this License must be
- attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file,
-then You may include the notice in a location (such as a LICENSE file in a
-relevant directory) where a recipient would be likely to look for such a
-notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
-
- This Source Code Form is "Incompatible
- With Secondary Licenses", as defined by
- the Mozilla Public License, v. 2.0.
diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go
deleted file mode 100644
index 5673773b22b..00000000000
--- a/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go
+++ /dev/null
@@ -1,161 +0,0 @@
-package simplelru
-
-import (
- "container/list"
- "errors"
-)
-
-// EvictCallback is used to get a callback when a cache entry is evicted
-type EvictCallback func(key interface{}, value interface{})
-
-// LRU implements a non-thread safe fixed size LRU cache
-type LRU struct {
- size int
- evictList *list.List
- items map[interface{}]*list.Element
- onEvict EvictCallback
-}
-
-// entry is used to hold a value in the evictList
-type entry struct {
- key interface{}
- value interface{}
-}
-
-// NewLRU constructs an LRU of the given size
-func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
- if size <= 0 {
- return nil, errors.New("Must provide a positive size")
- }
- c := &LRU{
- size: size,
- evictList: list.New(),
- items: make(map[interface{}]*list.Element),
- onEvict: onEvict,
- }
- return c, nil
-}
-
-// Purge is used to completely clear the cache.
-func (c *LRU) Purge() {
- for k, v := range c.items {
- if c.onEvict != nil {
- c.onEvict(k, v.Value.(*entry).value)
- }
- delete(c.items, k)
- }
- c.evictList.Init()
-}
-
-// Add adds a value to the cache. Returns true if an eviction occurred.
-func (c *LRU) Add(key, value interface{}) (evicted bool) {
- // Check for existing item
- if ent, ok := c.items[key]; ok {
- c.evictList.MoveToFront(ent)
- ent.Value.(*entry).value = value
- return false
- }
-
- // Add new item
- ent := &entry{key, value}
- entry := c.evictList.PushFront(ent)
- c.items[key] = entry
-
- evict := c.evictList.Len() > c.size
- // Verify size not exceeded
- if evict {
- c.removeOldest()
- }
- return evict
-}
-
-// Get looks up a key's value from the cache.
-func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
- if ent, ok := c.items[key]; ok {
- c.evictList.MoveToFront(ent)
- return ent.Value.(*entry).value, true
- }
- return
-}
-
-// Contains checks if a key is in the cache, without updating the recent-ness
-// or deleting it for being stale.
-func (c *LRU) Contains(key interface{}) (ok bool) {
- _, ok = c.items[key]
- return ok
-}
-
-// Peek returns the key value (or undefined if not found) without updating
-// the "recently used"-ness of the key.
-func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
- var ent *list.Element
- if ent, ok = c.items[key]; ok {
- return ent.Value.(*entry).value, true
- }
- return nil, ok
-}
-
-// Remove removes the provided key from the cache, returning if the
-// key was contained.
-func (c *LRU) Remove(key interface{}) (present bool) {
- if ent, ok := c.items[key]; ok {
- c.removeElement(ent)
- return true
- }
- return false
-}
-
-// RemoveOldest removes the oldest item from the cache.
-func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) {
- ent := c.evictList.Back()
- if ent != nil {
- c.removeElement(ent)
- kv := ent.Value.(*entry)
- return kv.key, kv.value, true
- }
- return nil, nil, false
-}
-
-// GetOldest returns the oldest entry
-func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) {
- ent := c.evictList.Back()
- if ent != nil {
- kv := ent.Value.(*entry)
- return kv.key, kv.value, true
- }
- return nil, nil, false
-}
-
-// Keys returns a slice of the keys in the cache, from oldest to newest.
-func (c *LRU) Keys() []interface{} {
- keys := make([]interface{}, len(c.items))
- i := 0
- for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
- keys[i] = ent.Value.(*entry).key
- i++
- }
- return keys
-}
-
-// Len returns the number of items in the cache.
-func (c *LRU) Len() int {
- return c.evictList.Len()
-}
-
-// removeOldest removes the oldest item from the cache.
-func (c *LRU) removeOldest() {
- ent := c.evictList.Back()
- if ent != nil {
- c.removeElement(ent)
- }
-}
-
-// removeElement is used to remove a given list element from the cache
-func (c *LRU) removeElement(e *list.Element) {
- c.evictList.Remove(e)
- kv := e.Value.(*entry)
- delete(c.items, kv.key)
- if c.onEvict != nil {
- c.onEvict(kv.key, kv.value)
- }
-}
diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go
deleted file mode 100644
index 74c7077440c..00000000000
--- a/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package simplelru
-
-// LRUCache is the interface for simple LRU cache.
-type LRUCache interface {
- // Adds a value to the cache, returns true if an eviction occurred and
- // updates the "recently used"-ness of the key.
- Add(key, value interface{}) bool
-
- // Returns key's value from the cache and
- // updates the "recently used"-ness of the key. #value, isFound
- Get(key interface{}) (value interface{}, ok bool)
-
- // Check if a key exsists in cache without updating the recent-ness.
- Contains(key interface{}) (ok bool)
-
- // Returns key's value without updating the "recently used"-ness of the key.
- Peek(key interface{}) (value interface{}, ok bool)
-
- // Removes a key from the cache.
- Remove(key interface{}) bool
-
- // Removes the oldest entry from cache.
- RemoveOldest() (interface{}, interface{}, bool)
-
- // Returns the oldest entry from the cache. #key, value, isFound
- GetOldest() (interface{}, interface{}, bool)
-
- // Returns a slice of the keys in the cache, from oldest to newest.
- Keys() []interface{}
-
- // Returns the number of items in the cache.
- Len() int
-
- // Clear all cache entries
- Purge()
-}
diff --git a/vendor/github.com/hashicorp/hcl/.gitignore b/vendor/github.com/hashicorp/hcl/.gitignore
deleted file mode 100644
index 15586a2b540..00000000000
--- a/vendor/github.com/hashicorp/hcl/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-y.output
-
-# ignore intellij files
-.idea
-*.iml
-*.ipr
-*.iws
-
-*.test
diff --git a/vendor/github.com/hashicorp/hcl/.travis.yml b/vendor/github.com/hashicorp/hcl/.travis.yml
deleted file mode 100644
index cb63a32161b..00000000000
--- a/vendor/github.com/hashicorp/hcl/.travis.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-sudo: false
-
-language: go
-
-go:
- - 1.x
- - tip
-
-branches:
- only:
- - master
-
-script: make test
diff --git a/vendor/github.com/hashicorp/hcl/LICENSE b/vendor/github.com/hashicorp/hcl/LICENSE
deleted file mode 100644
index c33dcc7c928..00000000000
--- a/vendor/github.com/hashicorp/hcl/LICENSE
+++ /dev/null
@@ -1,354 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. “Contributorâ€
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. “Contributor Versionâ€
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor’s Contribution.
-
-1.3. “Contributionâ€
-
- means Covered Software of a particular Contributor.
-
-1.4. “Covered Softwareâ€
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. “Incompatible With Secondary Licensesâ€
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of version
- 1.1 or earlier of the License, but not also under the terms of a
- Secondary License.
-
-1.6. “Executable Formâ€
-
- means any form of the work other than Source Code Form.
-
-1.7. “Larger Workâ€
-
- means a work that combines Covered Software with other material, in a separate
- file or files, that is not Covered Software.
-
-1.8. “Licenseâ€
-
- means this document.
-
-1.9. “Licensableâ€
-
- means having the right to grant, to the maximum extent possible, whether at the
- time of the initial grant or subsequently, any and all of the rights conveyed by
- this License.
-
-1.10. “Modificationsâ€
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to, deletion
- from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. “Patent Claims†of a Contributor
-
- means any patent claim(s), including without limitation, method, process,
- and apparatus claims, in any patent Licensable by such Contributor that
- would be infringed, but for the grant of the License, by the making,
- using, selling, offering for sale, having made, import, or transfer of
- either its Contributions or its Contributor Version.
-
-1.12. “Secondary Licenseâ€
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. “Source Code Formâ€
-
- means the form of the work preferred for making modifications.
-
-1.14. “You†(or “Yourâ€)
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, “You†includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, “control†means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or as
- part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its Contributions
- or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution become
- effective for each Contribution on the date the Contributor first distributes
- such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under this
- License. No additional rights or licenses will be implied from the distribution
- or licensing of Covered Software under this License. Notwithstanding Section
- 2.1(b) above, no patent license is granted by a Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party’s
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of its
- Contributions.
-
- This License does not grant any rights in the trademarks, service marks, or
- logos of any Contributor (except as may be necessary to comply with the
- notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this License
- (see Section 10.2) or under the terms of a Secondary License (if permitted
- under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its Contributions
- are its original creation(s) or it has sufficient rights to grant the
- rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under applicable
- copyright doctrines of fair use, fair dealing, or other equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under the
- terms of this License. You must inform recipients that the Source Code Form
- of the Covered Software is governed by the terms of this License, and how
- they can obtain a copy of this License. You may not attempt to alter or
- restrict the recipients’ rights in the Source Code Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this License,
- or sublicense it under different terms, provided that the license for
- the Executable Form does not attempt to limit or alter the recipients’
- rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for the
- Covered Software. If the Larger Work is a combination of Covered Software
- with a work governed by one or more Secondary Licenses, and the Covered
- Software is not Incompatible With Secondary Licenses, this License permits
- You to additionally distribute such Covered Software under the terms of
- such Secondary License(s), so that the recipient of the Larger Work may, at
- their option, further distribute the Covered Software under the terms of
- either this License or such Secondary License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices (including
- copyright notices, patent notices, disclaimers of warranty, or limitations
- of liability) contained within the Source Code Form of the Covered
- Software, except that You may alter any license notices to the extent
- required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on behalf
- of any Contributor. You must make it absolutely clear that any such
- warranty, support, indemnity, or liability obligation is offered by You
- alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute, judicial
- order, or regulation then You must: (a) comply with the terms of this License
- to the maximum extent possible; and (b) describe the limitations and the code
- they affect. Such description must be placed in a text file included with all
- distributions of the Covered Software under this License. Except to the
- extent prohibited by statute or regulation, such description must be
- sufficiently detailed for a recipient of ordinary skill to be able to
- understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing basis,
- if such Contributor fails to notify You of the non-compliance by some
- reasonable means prior to 60 days after You have come back into compliance.
- Moreover, Your grants from a particular Contributor are reinstated on an
- ongoing basis if such Contributor notifies You of the non-compliance by
- some reasonable means, this is the first time You have received notice of
- non-compliance with this License from such Contributor, and You become
- compliant prior to 30 days after Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions, counter-claims,
- and cross-claims) alleging that a Contributor Version directly or
- indirectly infringes any patent, then the rights granted to You by any and
- all Contributors for the Covered Software under Section 2.1 of this License
- shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an “as is†basis, without
- warranty of any kind, either expressed, implied, or statutory, including,
- without limitation, warranties that the Covered Software is free of defects,
- merchantable, fit for a particular purpose or non-infringing. The entire
- risk as to the quality and performance of the Covered Software is with You.
- Should any Covered Software prove defective in any respect, You (not any
- Contributor) assume the cost of any necessary servicing, repair, or
- correction. This disclaimer of warranty constitutes an essential part of this
- License. No use of any Covered Software is authorized under this License
- except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from such
- party’s negligence to the extent applicable law prohibits such limitation.
- Some jurisdictions do not allow the exclusion or limitation of incidental or
- consequential damages, so this exclusion and limitation may not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts of
- a jurisdiction where the defendant maintains its principal place of business
- and such litigation shall be governed by laws of that jurisdiction, without
- reference to its conflict-of-law provisions. Nothing in this Section shall
- prevent a party’s ability to bring cross-claims or counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject matter
- hereof. If any provision of this License is held to be unenforceable, such
- provision shall be reformed only to the extent necessary to make it
- enforceable. Any law or regulation which provides that the language of a
- contract shall be construed against the drafter shall not be used to construe
- this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version of
- the License under which You originally received the Covered Software, or
- under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a modified
- version of this License if you rename the license and remove any
- references to the name of the license steward (except to note that such
- modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
- If You choose to distribute Source Code Form that is Incompatible With
- Secondary Licenses under the terms of this version of the License, the
- notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file, then
-You may include the notice in a location (such as a LICENSE file in a relevant
-directory) where a recipient would be likely to look for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - “Incompatible With Secondary Licenses†Notice
-
- This Source Code Form is “Incompatible
- With Secondary Licensesâ€, as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/hcl/Makefile b/vendor/github.com/hashicorp/hcl/Makefile
deleted file mode 100644
index 84fd743f5cc..00000000000
--- a/vendor/github.com/hashicorp/hcl/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-TEST?=./...
-
-default: test
-
-fmt: generate
- go fmt ./...
-
-test: generate
- go get -t ./...
- go test $(TEST) $(TESTARGS)
-
-generate:
- go generate ./...
-
-updatedeps:
- go get -u golang.org/x/tools/cmd/stringer
-
-.PHONY: default generate test updatedeps
diff --git a/vendor/github.com/hashicorp/hcl/README.md b/vendor/github.com/hashicorp/hcl/README.md
deleted file mode 100644
index c8223326ddc..00000000000
--- a/vendor/github.com/hashicorp/hcl/README.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# HCL
-
-[![GoDoc](https://godoc.org/github.com/hashicorp/hcl?status.png)](https://godoc.org/github.com/hashicorp/hcl) [![Build Status](https://travis-ci.org/hashicorp/hcl.svg?branch=master)](https://travis-ci.org/hashicorp/hcl)
-
-HCL (HashiCorp Configuration Language) is a configuration language built
-by HashiCorp. The goal of HCL is to build a structured configuration language
-that is both human and machine friendly for use with command-line tools, but
-specifically targeted towards DevOps tools, servers, etc.
-
-HCL is also fully JSON compatible. That is, JSON can be used as completely
-valid input to a system expecting HCL. This helps makes systems
-interoperable with other systems.
-
-HCL is heavily inspired by
-[libucl](https://github.com/vstakhov/libucl),
-nginx configuration, and others similar.
-
-## Why?
-
-A common question when viewing HCL is to ask the question: why not
-JSON, YAML, etc.?
-
-Prior to HCL, the tools we built at [HashiCorp](http://www.hashicorp.com)
-used a variety of configuration languages from full programming languages
-such as Ruby to complete data structure languages such as JSON. What we
-learned is that some people wanted human-friendly configuration languages
-and some people wanted machine-friendly languages.
-
-JSON fits a nice balance in this, but is fairly verbose and most
-importantly doesn't support comments. With YAML, we found that beginners
-had a really hard time determining what the actual structure was, and
-ended up guessing more often than not whether to use a hyphen, colon, etc.
-in order to represent some configuration key.
-
-Full programming languages such as Ruby enable complex behavior
-a configuration language shouldn't usually allow, and also forces
-people to learn some set of Ruby.
-
-Because of this, we decided to create our own configuration language
-that is JSON-compatible. Our configuration language (HCL) is designed
-to be written and modified by humans. The API for HCL allows JSON
-as an input so that it is also machine-friendly (machines can generate
-JSON instead of trying to generate HCL).
-
-Our goal with HCL is not to alienate other configuration languages.
-It is instead to provide HCL as a specialized language for our tools,
-and JSON as the interoperability layer.
-
-## Syntax
-
-For a complete grammar, please see the parser itself. A high-level overview
-of the syntax and grammar is listed here.
-
- * Single line comments start with `#` or `//`
-
- * Multi-line comments are wrapped in `/*` and `*/`. Nested block comments
- are not allowed. A multi-line comment (also known as a block comment)
- terminates at the first `*/` found.
-
- * Values are assigned with the syntax `key = value` (whitespace doesn't
- matter). The value can be any primitive: a string, number, boolean,
- object, or list.
-
- * Strings are double-quoted and can contain any UTF-8 characters.
- Example: `"Hello, World"`
-
- * Multi-line strings start with `<-
- echo %Path%
-
- go version
-
- go env
-
- go get -t ./...
-
-build_script:
-- cmd: go test -v ./...
diff --git a/vendor/github.com/hashicorp/hcl/decoder.go b/vendor/github.com/hashicorp/hcl/decoder.go
deleted file mode 100644
index bed9ebbe141..00000000000
--- a/vendor/github.com/hashicorp/hcl/decoder.go
+++ /dev/null
@@ -1,729 +0,0 @@
-package hcl
-
-import (
- "errors"
- "fmt"
- "reflect"
- "sort"
- "strconv"
- "strings"
-
- "github.com/hashicorp/hcl/hcl/ast"
- "github.com/hashicorp/hcl/hcl/parser"
- "github.com/hashicorp/hcl/hcl/token"
-)
-
-// This is the tag to use with structures to have settings for HCL
-const tagName = "hcl"
-
-var (
- // nodeType holds a reference to the type of ast.Node
- nodeType reflect.Type = findNodeType()
-)
-
-// Unmarshal accepts a byte slice as input and writes the
-// data to the value pointed to by v.
-func Unmarshal(bs []byte, v interface{}) error {
- root, err := parse(bs)
- if err != nil {
- return err
- }
-
- return DecodeObject(v, root)
-}
-
-// Decode reads the given input and decodes it into the structure
-// given by `out`.
-func Decode(out interface{}, in string) error {
- obj, err := Parse(in)
- if err != nil {
- return err
- }
-
- return DecodeObject(out, obj)
-}
-
-// DecodeObject is a lower-level version of Decode. It decodes a
-// raw Object into the given output.
-func DecodeObject(out interface{}, n ast.Node) error {
- val := reflect.ValueOf(out)
- if val.Kind() != reflect.Ptr {
- return errors.New("result must be a pointer")
- }
-
- // If we have the file, we really decode the root node
- if f, ok := n.(*ast.File); ok {
- n = f.Node
- }
-
- var d decoder
- return d.decode("root", n, val.Elem())
-}
-
-type decoder struct {
- stack []reflect.Kind
-}
-
-func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error {
- k := result
-
- // If we have an interface with a valid value, we use that
- // for the check.
- if result.Kind() == reflect.Interface {
- elem := result.Elem()
- if elem.IsValid() {
- k = elem
- }
- }
-
- // Push current onto stack unless it is an interface.
- if k.Kind() != reflect.Interface {
- d.stack = append(d.stack, k.Kind())
-
- // Schedule a pop
- defer func() {
- d.stack = d.stack[:len(d.stack)-1]
- }()
- }
-
- switch k.Kind() {
- case reflect.Bool:
- return d.decodeBool(name, node, result)
- case reflect.Float32, reflect.Float64:
- return d.decodeFloat(name, node, result)
- case reflect.Int, reflect.Int32, reflect.Int64:
- return d.decodeInt(name, node, result)
- case reflect.Interface:
- // When we see an interface, we make our own thing
- return d.decodeInterface(name, node, result)
- case reflect.Map:
- return d.decodeMap(name, node, result)
- case reflect.Ptr:
- return d.decodePtr(name, node, result)
- case reflect.Slice:
- return d.decodeSlice(name, node, result)
- case reflect.String:
- return d.decodeString(name, node, result)
- case reflect.Struct:
- return d.decodeStruct(name, node, result)
- default:
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()),
- }
- }
-}
-
-func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error {
- switch n := node.(type) {
- case *ast.LiteralType:
- if n.Token.Type == token.BOOL {
- v, err := strconv.ParseBool(n.Token.Text)
- if err != nil {
- return err
- }
-
- result.Set(reflect.ValueOf(v))
- return nil
- }
- }
-
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: unknown type %T", name, node),
- }
-}
-
-func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error {
- switch n := node.(type) {
- case *ast.LiteralType:
- if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER {
- v, err := strconv.ParseFloat(n.Token.Text, 64)
- if err != nil {
- return err
- }
-
- result.Set(reflect.ValueOf(v).Convert(result.Type()))
- return nil
- }
- }
-
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: unknown type %T", name, node),
- }
-}
-
-func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error {
- switch n := node.(type) {
- case *ast.LiteralType:
- switch n.Token.Type {
- case token.NUMBER:
- v, err := strconv.ParseInt(n.Token.Text, 0, 0)
- if err != nil {
- return err
- }
-
- if result.Kind() == reflect.Interface {
- result.Set(reflect.ValueOf(int(v)))
- } else {
- result.SetInt(v)
- }
- return nil
- case token.STRING:
- v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0)
- if err != nil {
- return err
- }
-
- if result.Kind() == reflect.Interface {
- result.Set(reflect.ValueOf(int(v)))
- } else {
- result.SetInt(v)
- }
- return nil
- }
- }
-
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: unknown type %T", name, node),
- }
-}
-
-func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error {
- // When we see an ast.Node, we retain the value to enable deferred decoding.
- // Very useful in situations where we want to preserve ast.Node information
- // like Pos
- if result.Type() == nodeType && result.CanSet() {
- result.Set(reflect.ValueOf(node))
- return nil
- }
-
- var set reflect.Value
- redecode := true
-
- // For testing types, ObjectType should just be treated as a list. We
- // set this to a temporary var because we want to pass in the real node.
- testNode := node
- if ot, ok := node.(*ast.ObjectType); ok {
- testNode = ot.List
- }
-
- switch n := testNode.(type) {
- case *ast.ObjectList:
- // If we're at the root or we're directly within a slice, then we
- // decode objects into map[string]interface{}, otherwise we decode
- // them into lists.
- if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice {
- var temp map[string]interface{}
- tempVal := reflect.ValueOf(temp)
- result := reflect.MakeMap(
- reflect.MapOf(
- reflect.TypeOf(""),
- tempVal.Type().Elem()))
-
- set = result
- } else {
- var temp []map[string]interface{}
- tempVal := reflect.ValueOf(temp)
- result := reflect.MakeSlice(
- reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items))
- set = result
- }
- case *ast.ObjectType:
- // If we're at the root or we're directly within a slice, then we
- // decode objects into map[string]interface{}, otherwise we decode
- // them into lists.
- if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice {
- var temp map[string]interface{}
- tempVal := reflect.ValueOf(temp)
- result := reflect.MakeMap(
- reflect.MapOf(
- reflect.TypeOf(""),
- tempVal.Type().Elem()))
-
- set = result
- } else {
- var temp []map[string]interface{}
- tempVal := reflect.ValueOf(temp)
- result := reflect.MakeSlice(
- reflect.SliceOf(tempVal.Type().Elem()), 0, 1)
- set = result
- }
- case *ast.ListType:
- var temp []interface{}
- tempVal := reflect.ValueOf(temp)
- result := reflect.MakeSlice(
- reflect.SliceOf(tempVal.Type().Elem()), 0, 0)
- set = result
- case *ast.LiteralType:
- switch n.Token.Type {
- case token.BOOL:
- var result bool
- set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
- case token.FLOAT:
- var result float64
- set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
- case token.NUMBER:
- var result int
- set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
- case token.STRING, token.HEREDOC:
- set = reflect.Indirect(reflect.New(reflect.TypeOf("")))
- default:
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node),
- }
- }
- default:
- return fmt.Errorf(
- "%s: cannot decode into interface: %T",
- name, node)
- }
-
- // Set the result to what its supposed to be, then reset
- // result so we don't reflect into this method anymore.
- result.Set(set)
-
- if redecode {
- // Revisit the node so that we can use the newly instantiated
- // thing and populate it.
- if err := d.decode(name, node, result); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error {
- if item, ok := node.(*ast.ObjectItem); ok {
- node = &ast.ObjectList{Items: []*ast.ObjectItem{item}}
- }
-
- if ot, ok := node.(*ast.ObjectType); ok {
- node = ot.List
- }
-
- n, ok := node.(*ast.ObjectList)
- if !ok {
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: not an object type for map (%T)", name, node),
- }
- }
-
- // If we have an interface, then we can address the interface,
- // but not the slice itself, so get the element but set the interface
- set := result
- if result.Kind() == reflect.Interface {
- result = result.Elem()
- }
-
- resultType := result.Type()
- resultElemType := resultType.Elem()
- resultKeyType := resultType.Key()
- if resultKeyType.Kind() != reflect.String {
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: map must have string keys", name),
- }
- }
-
- // Make a map if it is nil
- resultMap := result
- if result.IsNil() {
- resultMap = reflect.MakeMap(
- reflect.MapOf(resultKeyType, resultElemType))
- }
-
- // Go through each element and decode it.
- done := make(map[string]struct{})
- for _, item := range n.Items {
- if item.Val == nil {
- continue
- }
-
- // github.com/hashicorp/terraform/issue/5740
- if len(item.Keys) == 0 {
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: map must have string keys", name),
- }
- }
-
- // Get the key we're dealing with, which is the first item
- keyStr := item.Keys[0].Token.Value().(string)
-
- // If we've already processed this key, then ignore it
- if _, ok := done[keyStr]; ok {
- continue
- }
-
- // Determine the value. If we have more than one key, then we
- // get the objectlist of only these keys.
- itemVal := item.Val
- if len(item.Keys) > 1 {
- itemVal = n.Filter(keyStr)
- done[keyStr] = struct{}{}
- }
-
- // Make the field name
- fieldName := fmt.Sprintf("%s.%s", name, keyStr)
-
- // Get the key/value as reflection values
- key := reflect.ValueOf(keyStr)
- val := reflect.Indirect(reflect.New(resultElemType))
-
- // If we have a pre-existing value in the map, use that
- oldVal := resultMap.MapIndex(key)
- if oldVal.IsValid() {
- val.Set(oldVal)
- }
-
- // Decode!
- if err := d.decode(fieldName, itemVal, val); err != nil {
- return err
- }
-
- // Set the value on the map
- resultMap.SetMapIndex(key, val)
- }
-
- // Set the final map if we can
- set.Set(resultMap)
- return nil
-}
-
-func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error {
- // Create an element of the concrete (non pointer) type and decode
- // into that. Then set the value of the pointer to this type.
- resultType := result.Type()
- resultElemType := resultType.Elem()
- val := reflect.New(resultElemType)
- if err := d.decode(name, node, reflect.Indirect(val)); err != nil {
- return err
- }
-
- result.Set(val)
- return nil
-}
-
-func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error {
- // If we have an interface, then we can address the interface,
- // but not the slice itself, so get the element but set the interface
- set := result
- if result.Kind() == reflect.Interface {
- result = result.Elem()
- }
- // Create the slice if it isn't nil
- resultType := result.Type()
- resultElemType := resultType.Elem()
- if result.IsNil() {
- resultSliceType := reflect.SliceOf(resultElemType)
- result = reflect.MakeSlice(
- resultSliceType, 0, 0)
- }
-
- // Figure out the items we'll be copying into the slice
- var items []ast.Node
- switch n := node.(type) {
- case *ast.ObjectList:
- items = make([]ast.Node, len(n.Items))
- for i, item := range n.Items {
- items[i] = item
- }
- case *ast.ObjectType:
- items = []ast.Node{n}
- case *ast.ListType:
- items = n.List
- default:
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("unknown slice type: %T", node),
- }
- }
-
- for i, item := range items {
- fieldName := fmt.Sprintf("%s[%d]", name, i)
-
- // Decode
- val := reflect.Indirect(reflect.New(resultElemType))
-
- // if item is an object that was decoded from ambiguous JSON and
- // flattened, make sure it's expanded if it needs to decode into a
- // defined structure.
- item := expandObject(item, val)
-
- if err := d.decode(fieldName, item, val); err != nil {
- return err
- }
-
- // Append it onto the slice
- result = reflect.Append(result, val)
- }
-
- set.Set(result)
- return nil
-}
-
-// expandObject detects if an ambiguous JSON object was flattened to a List which
-// should be decoded into a struct, and expands the ast to properly deocode.
-func expandObject(node ast.Node, result reflect.Value) ast.Node {
- item, ok := node.(*ast.ObjectItem)
- if !ok {
- return node
- }
-
- elemType := result.Type()
-
- // our target type must be a struct
- switch elemType.Kind() {
- case reflect.Ptr:
- switch elemType.Elem().Kind() {
- case reflect.Struct:
- //OK
- default:
- return node
- }
- case reflect.Struct:
- //OK
- default:
- return node
- }
-
- // A list value will have a key and field name. If it had more fields,
- // it wouldn't have been flattened.
- if len(item.Keys) != 2 {
- return node
- }
-
- keyToken := item.Keys[0].Token
- item.Keys = item.Keys[1:]
-
- // we need to un-flatten the ast enough to decode
- newNode := &ast.ObjectItem{
- Keys: []*ast.ObjectKey{
- &ast.ObjectKey{
- Token: keyToken,
- },
- },
- Val: &ast.ObjectType{
- List: &ast.ObjectList{
- Items: []*ast.ObjectItem{item},
- },
- },
- }
-
- return newNode
-}
-
-func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error {
- switch n := node.(type) {
- case *ast.LiteralType:
- switch n.Token.Type {
- case token.NUMBER:
- result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type()))
- return nil
- case token.STRING, token.HEREDOC:
- result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type()))
- return nil
- }
- }
-
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: unknown type for string %T", name, node),
- }
-}
-
-func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error {
- var item *ast.ObjectItem
- if it, ok := node.(*ast.ObjectItem); ok {
- item = it
- node = it.Val
- }
-
- if ot, ok := node.(*ast.ObjectType); ok {
- node = ot.List
- }
-
- // Handle the special case where the object itself is a literal. Previously
- // the yacc parser would always ensure top-level elements were arrays. The new
- // parser does not make the same guarantees, thus we need to convert any
- // top-level literal elements into a list.
- if _, ok := node.(*ast.LiteralType); ok && item != nil {
- node = &ast.ObjectList{Items: []*ast.ObjectItem{item}}
- }
-
- list, ok := node.(*ast.ObjectList)
- if !ok {
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node),
- }
- }
-
- // This slice will keep track of all the structs we'll be decoding.
- // There can be more than one struct if there are embedded structs
- // that are squashed.
- structs := make([]reflect.Value, 1, 5)
- structs[0] = result
-
- // Compile the list of all the fields that we're going to be decoding
- // from all the structs.
- type field struct {
- field reflect.StructField
- val reflect.Value
- }
- fields := []field{}
- for len(structs) > 0 {
- structVal := structs[0]
- structs = structs[1:]
-
- structType := structVal.Type()
- for i := 0; i < structType.NumField(); i++ {
- fieldType := structType.Field(i)
- tagParts := strings.Split(fieldType.Tag.Get(tagName), ",")
-
- // Ignore fields with tag name "-"
- if tagParts[0] == "-" {
- continue
- }
-
- if fieldType.Anonymous {
- fieldKind := fieldType.Type.Kind()
- if fieldKind != reflect.Struct {
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: unsupported type to struct: %s",
- fieldType.Name, fieldKind),
- }
- }
-
- // We have an embedded field. We "squash" the fields down
- // if specified in the tag.
- squash := false
- for _, tag := range tagParts[1:] {
- if tag == "squash" {
- squash = true
- break
- }
- }
-
- if squash {
- structs = append(
- structs, result.FieldByName(fieldType.Name))
- continue
- }
- }
-
- // Normal struct field, store it away
- fields = append(fields, field{fieldType, structVal.Field(i)})
- }
- }
-
- usedKeys := make(map[string]struct{})
- decodedFields := make([]string, 0, len(fields))
- decodedFieldsVal := make([]reflect.Value, 0)
- unusedKeysVal := make([]reflect.Value, 0)
- for _, f := range fields {
- field, fieldValue := f.field, f.val
- if !fieldValue.IsValid() {
- // This should never happen
- panic("field is not valid")
- }
-
- // If we can't set the field, then it is unexported or something,
- // and we just continue onwards.
- if !fieldValue.CanSet() {
- continue
- }
-
- fieldName := field.Name
-
- tagValue := field.Tag.Get(tagName)
- tagParts := strings.SplitN(tagValue, ",", 2)
- if len(tagParts) >= 2 {
- switch tagParts[1] {
- case "decodedFields":
- decodedFieldsVal = append(decodedFieldsVal, fieldValue)
- continue
- case "key":
- if item == nil {
- return &parser.PosError{
- Pos: node.Pos(),
- Err: fmt.Errorf("%s: %s asked for 'key', impossible",
- name, fieldName),
- }
- }
-
- fieldValue.SetString(item.Keys[0].Token.Value().(string))
- continue
- case "unusedKeys":
- unusedKeysVal = append(unusedKeysVal, fieldValue)
- continue
- }
- }
-
- if tagParts[0] != "" {
- fieldName = tagParts[0]
- }
-
- // Determine the element we'll use to decode. If it is a single
- // match (only object with the field), then we decode it exactly.
- // If it is a prefix match, then we decode the matches.
- filter := list.Filter(fieldName)
-
- prefixMatches := filter.Children()
- matches := filter.Elem()
- if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 {
- continue
- }
-
- // Track the used key
- usedKeys[fieldName] = struct{}{}
-
- // Create the field name and decode. We range over the elements
- // because we actually want the value.
- fieldName = fmt.Sprintf("%s.%s", name, fieldName)
- if len(prefixMatches.Items) > 0 {
- if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil {
- return err
- }
- }
- for _, match := range matches.Items {
- var decodeNode ast.Node = match.Val
- if ot, ok := decodeNode.(*ast.ObjectType); ok {
- decodeNode = &ast.ObjectList{Items: ot.List.Items}
- }
-
- if err := d.decode(fieldName, decodeNode, fieldValue); err != nil {
- return err
- }
- }
-
- decodedFields = append(decodedFields, field.Name)
- }
-
- if len(decodedFieldsVal) > 0 {
- // Sort it so that it is deterministic
- sort.Strings(decodedFields)
-
- for _, v := range decodedFieldsVal {
- v.Set(reflect.ValueOf(decodedFields))
- }
- }
-
- return nil
-}
-
-// findNodeType returns the type of ast.Node
-func findNodeType() reflect.Type {
- var nodeContainer struct {
- Node ast.Node
- }
- value := reflect.ValueOf(nodeContainer).FieldByName("Node")
- return value.Type()
-}
diff --git a/vendor/github.com/hashicorp/hcl/go.mod b/vendor/github.com/hashicorp/hcl/go.mod
deleted file mode 100644
index 4debbbe3580..00000000000
--- a/vendor/github.com/hashicorp/hcl/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/hashicorp/hcl
-
-require github.com/davecgh/go-spew v1.1.1
diff --git a/vendor/github.com/hashicorp/hcl/go.sum b/vendor/github.com/hashicorp/hcl/go.sum
deleted file mode 100644
index b5e2922e890..00000000000
--- a/vendor/github.com/hashicorp/hcl/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
diff --git a/vendor/github.com/hashicorp/hcl/hcl.go b/vendor/github.com/hashicorp/hcl/hcl.go
deleted file mode 100644
index 575a20b50b5..00000000000
--- a/vendor/github.com/hashicorp/hcl/hcl.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Package hcl decodes HCL into usable Go structures.
-//
-// hcl input can come in either pure HCL format or JSON format.
-// It can be parsed into an AST, and then decoded into a structure,
-// or it can be decoded directly from a string into a structure.
-//
-// If you choose to parse HCL into a raw AST, the benefit is that you
-// can write custom visitor implementations to implement custom
-// semantic checks. By default, HCL does not perform any semantic
-// checks.
-package hcl
diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go b/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go
deleted file mode 100644
index 6e5ef654bb8..00000000000
--- a/vendor/github.com/hashicorp/hcl/hcl/ast/ast.go
+++ /dev/null
@@ -1,219 +0,0 @@
-// Package ast declares the types used to represent syntax trees for HCL
-// (HashiCorp Configuration Language)
-package ast
-
-import (
- "fmt"
- "strings"
-
- "github.com/hashicorp/hcl/hcl/token"
-)
-
-// Node is an element in the abstract syntax tree.
-type Node interface {
- node()
- Pos() token.Pos
-}
-
-func (File) node() {}
-func (ObjectList) node() {}
-func (ObjectKey) node() {}
-func (ObjectItem) node() {}
-func (Comment) node() {}
-func (CommentGroup) node() {}
-func (ObjectType) node() {}
-func (LiteralType) node() {}
-func (ListType) node() {}
-
-// File represents a single HCL file
-type File struct {
- Node Node // usually a *ObjectList
- Comments []*CommentGroup // list of all comments in the source
-}
-
-func (f *File) Pos() token.Pos {
- return f.Node.Pos()
-}
-
-// ObjectList represents a list of ObjectItems. An HCL file itself is an
-// ObjectList.
-type ObjectList struct {
- Items []*ObjectItem
-}
-
-func (o *ObjectList) Add(item *ObjectItem) {
- o.Items = append(o.Items, item)
-}
-
-// Filter filters out the objects with the given key list as a prefix.
-//
-// The returned list of objects contain ObjectItems where the keys have
-// this prefix already stripped off. This might result in objects with
-// zero-length key lists if they have no children.
-//
-// If no matches are found, an empty ObjectList (non-nil) is returned.
-func (o *ObjectList) Filter(keys ...string) *ObjectList {
- var result ObjectList
- for _, item := range o.Items {
- // If there aren't enough keys, then ignore this
- if len(item.Keys) < len(keys) {
- continue
- }
-
- match := true
- for i, key := range item.Keys[:len(keys)] {
- key := key.Token.Value().(string)
- if key != keys[i] && !strings.EqualFold(key, keys[i]) {
- match = false
- break
- }
- }
- if !match {
- continue
- }
-
- // Strip off the prefix from the children
- newItem := *item
- newItem.Keys = newItem.Keys[len(keys):]
- result.Add(&newItem)
- }
-
- return &result
-}
-
-// Children returns further nested objects (key length > 0) within this
-// ObjectList. This should be used with Filter to get at child items.
-func (o *ObjectList) Children() *ObjectList {
- var result ObjectList
- for _, item := range o.Items {
- if len(item.Keys) > 0 {
- result.Add(item)
- }
- }
-
- return &result
-}
-
-// Elem returns items in the list that are direct element assignments
-// (key length == 0). This should be used with Filter to get at elements.
-func (o *ObjectList) Elem() *ObjectList {
- var result ObjectList
- for _, item := range o.Items {
- if len(item.Keys) == 0 {
- result.Add(item)
- }
- }
-
- return &result
-}
-
-func (o *ObjectList) Pos() token.Pos {
- // always returns the uninitiliazed position
- return o.Items[0].Pos()
-}
-
-// ObjectItem represents a HCL Object Item. An item is represented with a key
-// (or keys). It can be an assignment or an object (both normal and nested)
-type ObjectItem struct {
- // keys is only one length long if it's of type assignment. If it's a
- // nested object it can be larger than one. In that case "assign" is
- // invalid as there is no assignments for a nested object.
- Keys []*ObjectKey
-
- // assign contains the position of "=", if any
- Assign token.Pos
-
- // val is the item itself. It can be an object,list, number, bool or a
- // string. If key length is larger than one, val can be only of type
- // Object.
- Val Node
-
- LeadComment *CommentGroup // associated lead comment
- LineComment *CommentGroup // associated line comment
-}
-
-func (o *ObjectItem) Pos() token.Pos {
- // I'm not entirely sure what causes this, but removing this causes
- // a test failure. We should investigate at some point.
- if len(o.Keys) == 0 {
- return token.Pos{}
- }
-
- return o.Keys[0].Pos()
-}
-
-// ObjectKeys are either an identifier or of type string.
-type ObjectKey struct {
- Token token.Token
-}
-
-func (o *ObjectKey) Pos() token.Pos {
- return o.Token.Pos
-}
-
-// LiteralType represents a literal of basic type. Valid types are:
-// token.NUMBER, token.FLOAT, token.BOOL and token.STRING
-type LiteralType struct {
- Token token.Token
-
- // comment types, only used when in a list
- LeadComment *CommentGroup
- LineComment *CommentGroup
-}
-
-func (l *LiteralType) Pos() token.Pos {
- return l.Token.Pos
-}
-
-// ListStatement represents a HCL List type
-type ListType struct {
- Lbrack token.Pos // position of "["
- Rbrack token.Pos // position of "]"
- List []Node // the elements in lexical order
-}
-
-func (l *ListType) Pos() token.Pos {
- return l.Lbrack
-}
-
-func (l *ListType) Add(node Node) {
- l.List = append(l.List, node)
-}
-
-// ObjectType represents a HCL Object Type
-type ObjectType struct {
- Lbrace token.Pos // position of "{"
- Rbrace token.Pos // position of "}"
- List *ObjectList // the nodes in lexical order
-}
-
-func (o *ObjectType) Pos() token.Pos {
- return o.Lbrace
-}
-
-// Comment node represents a single //, # style or /*- style commment
-type Comment struct {
- Start token.Pos // position of / or #
- Text string
-}
-
-func (c *Comment) Pos() token.Pos {
- return c.Start
-}
-
-// CommentGroup node represents a sequence of comments with no other tokens and
-// no empty lines between.
-type CommentGroup struct {
- List []*Comment // len(List) > 0
-}
-
-func (c *CommentGroup) Pos() token.Pos {
- return c.List[0].Pos()
-}
-
-//-------------------------------------------------------------------
-// GoStringer
-//-------------------------------------------------------------------
-
-func (o *ObjectKey) GoString() string { return fmt.Sprintf("*%#v", *o) }
-func (o *ObjectList) GoString() string { return fmt.Sprintf("*%#v", *o) }
diff --git a/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go b/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go
deleted file mode 100644
index ba07ad42b02..00000000000
--- a/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package ast
-
-import "fmt"
-
-// WalkFunc describes a function to be called for each node during a Walk. The
-// returned node can be used to rewrite the AST. Walking stops the returned
-// bool is false.
-type WalkFunc func(Node) (Node, bool)
-
-// Walk traverses an AST in depth-first order: It starts by calling fn(node);
-// node must not be nil. If fn returns true, Walk invokes fn recursively for
-// each of the non-nil children of node, followed by a call of fn(nil). The
-// returned node of fn can be used to rewrite the passed node to fn.
-func Walk(node Node, fn WalkFunc) Node {
- rewritten, ok := fn(node)
- if !ok {
- return rewritten
- }
-
- switch n := node.(type) {
- case *File:
- n.Node = Walk(n.Node, fn)
- case *ObjectList:
- for i, item := range n.Items {
- n.Items[i] = Walk(item, fn).(*ObjectItem)
- }
- case *ObjectKey:
- // nothing to do
- case *ObjectItem:
- for i, k := range n.Keys {
- n.Keys[i] = Walk(k, fn).(*ObjectKey)
- }
-
- if n.Val != nil {
- n.Val = Walk(n.Val, fn)
- }
- case *LiteralType:
- // nothing to do
- case *ListType:
- for i, l := range n.List {
- n.List[i] = Walk(l, fn)
- }
- case *ObjectType:
- n.List = Walk(n.List, fn).(*ObjectList)
- default:
- // should we panic here?
- fmt.Printf("unknown type: %T\n", n)
- }
-
- fn(nil)
- return rewritten
-}
diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/error.go b/vendor/github.com/hashicorp/hcl/hcl/parser/error.go
deleted file mode 100644
index 5c99381dfbf..00000000000
--- a/vendor/github.com/hashicorp/hcl/hcl/parser/error.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package parser
-
-import (
- "fmt"
-
- "github.com/hashicorp/hcl/hcl/token"
-)
-
-// PosError is a parse error that contains a position.
-type PosError struct {
- Pos token.Pos
- Err error
-}
-
-func (e *PosError) Error() string {
- return fmt.Sprintf("At %s: %s", e.Pos, e.Err)
-}
diff --git a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go b/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go
deleted file mode 100644
index 64c83bcfb55..00000000000
--- a/vendor/github.com/hashicorp/hcl/hcl/parser/parser.go
+++ /dev/null
@@ -1,532 +0,0 @@
-// Package parser implements a parser for HCL (HashiCorp Configuration
-// Language)
-package parser
-
-import (
- "bytes"
- "errors"
- "fmt"
- "strings"
-
- "github.com/hashicorp/hcl/hcl/ast"
- "github.com/hashicorp/hcl/hcl/scanner"
- "github.com/hashicorp/hcl/hcl/token"
-)
-
-type Parser struct {
- sc *scanner.Scanner
-
- // Last read token
- tok token.Token
- commaPrev token.Token
-
- comments []*ast.CommentGroup
- leadComment *ast.CommentGroup // last lead comment
- lineComment *ast.CommentGroup // last line comment
-
- enableTrace bool
- indent int
- n int // buffer size (max = 1)
-}
-
-func newParser(src []byte) *Parser {
- return &Parser{
- sc: scanner.New(src),
- }
-}
-
-// Parse returns the fully parsed source and returns the abstract syntax tree.
-func Parse(src []byte) (*ast.File, error) {
- // normalize all line endings
- // since the scanner and output only work with "\n" line endings, we may
- // end up with dangling "\r" characters in the parsed data.
- src = bytes.Replace(src, []byte("\r\n"), []byte("\n"), -1)
-
- p := newParser(src)
- return p.Parse()
-}
-
-var errEofToken = errors.New("EOF token found")
-
-// Parse returns the fully parsed source and returns the abstract syntax tree.
-func (p *Parser) Parse() (*ast.File, error) {
- f := &ast.File{}
- var err, scerr error
- p.sc.Error = func(pos token.Pos, msg string) {
- scerr = &PosError{Pos: pos, Err: errors.New(msg)}
- }
-
- f.Node, err = p.objectList(false)
- if scerr != nil {
- return nil, scerr
- }
- if err != nil {
- return nil, err
- }
-
- f.Comments = p.comments
- return f, nil
-}
-
-// objectList parses a list of items within an object (generally k/v pairs).
-// The parameter" obj" tells this whether to we are within an object (braces:
-// '{', '}') or just at the top level. If we're within an object, we end
-// at an RBRACE.
-func (p *Parser) objectList(obj bool) (*ast.ObjectList, error) {
- defer un(trace(p, "ParseObjectList"))
- node := &ast.ObjectList{}
-
- for {
- if obj {
- tok := p.scan()
- p.unscan()
- if tok.Type == token.RBRACE {
- break
- }
- }
-
- n, err := p.objectItem()
- if err == errEofToken {
- break // we are finished
- }
-
- // we don't return a nil node, because might want to use already
- // collected items.
- if err != nil {
- return node, err
- }
-
- node.Add(n)
-
- // object lists can be optionally comma-delimited e.g. when a list of maps
- // is being expressed, so a comma is allowed here - it's simply consumed
- tok := p.scan()
- if tok.Type != token.COMMA {
- p.unscan()
- }
- }
- return node, nil
-}
-
-func (p *Parser) consumeComment() (comment *ast.Comment, endline int) {
- endline = p.tok.Pos.Line
-
- // count the endline if it's multiline comment, ie starting with /*
- if len(p.tok.Text) > 1 && p.tok.Text[1] == '*' {
- // don't use range here - no need to decode Unicode code points
- for i := 0; i < len(p.tok.Text); i++ {
- if p.tok.Text[i] == '\n' {
- endline++
- }
- }
- }
-
- comment = &ast.Comment{Start: p.tok.Pos, Text: p.tok.Text}
- p.tok = p.sc.Scan()
- return
-}
-
-func (p *Parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) {
- var list []*ast.Comment
- endline = p.tok.Pos.Line
-
- for p.tok.Type == token.COMMENT && p.tok.Pos.Line <= endline+n {
- var comment *ast.Comment
- comment, endline = p.consumeComment()
- list = append(list, comment)
- }
-
- // add comment group to the comments list
- comments = &ast.CommentGroup{List: list}
- p.comments = append(p.comments, comments)
-
- return
-}
-
-// objectItem parses a single object item
-func (p *Parser) objectItem() (*ast.ObjectItem, error) {
- defer un(trace(p, "ParseObjectItem"))
-
- keys, err := p.objectKey()
- if len(keys) > 0 && err == errEofToken {
- // We ignore eof token here since it is an error if we didn't
- // receive a value (but we did receive a key) for the item.
- err = nil
- }
- if len(keys) > 0 && err != nil && p.tok.Type == token.RBRACE {
- // This is a strange boolean statement, but what it means is:
- // We have keys with no value, and we're likely in an object
- // (since RBrace ends an object). For this, we set err to nil so
- // we continue and get the error below of having the wrong value
- // type.
- err = nil
-
- // Reset the token type so we don't think it completed fine. See
- // objectType which uses p.tok.Type to check if we're done with
- // the object.
- p.tok.Type = token.EOF
- }
- if err != nil {
- return nil, err
- }
-
- o := &ast.ObjectItem{
- Keys: keys,
- }
-
- if p.leadComment != nil {
- o.LeadComment = p.leadComment
- p.leadComment = nil
- }
-
- switch p.tok.Type {
- case token.ASSIGN:
- o.Assign = p.tok.Pos
- o.Val, err = p.object()
- if err != nil {
- return nil, err
- }
- case token.LBRACE:
- o.Val, err = p.objectType()
- if err != nil {
- return nil, err
- }
- default:
- keyStr := make([]string, 0, len(keys))
- for _, k := range keys {
- keyStr = append(keyStr, k.Token.Text)
- }
-
- return nil, &PosError{
- Pos: p.tok.Pos,
- Err: fmt.Errorf(
- "key '%s' expected start of object ('{') or assignment ('=')",
- strings.Join(keyStr, " ")),
- }
- }
-
- // key=#comment
- // val
- if p.lineComment != nil {
- o.LineComment, p.lineComment = p.lineComment, nil
- }
-
- // do a look-ahead for line comment
- p.scan()
- if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil {
- o.LineComment = p.lineComment
- p.lineComment = nil
- }
- p.unscan()
- return o, nil
-}
-
-// objectKey parses an object key and returns a ObjectKey AST
-func (p *Parser) objectKey() ([]*ast.ObjectKey, error) {
- keyCount := 0
- keys := make([]*ast.ObjectKey, 0)
-
- for {
- tok := p.scan()
- switch tok.Type {
- case token.EOF:
- // It is very important to also return the keys here as well as
- // the error. This is because we need to be able to tell if we
- // did parse keys prior to finding the EOF, or if we just found
- // a bare EOF.
- return keys, errEofToken
- case token.ASSIGN:
- // assignment or object only, but not nested objects. this is not
- // allowed: `foo bar = {}`
- if keyCount > 1 {
- return nil, &PosError{
- Pos: p.tok.Pos,
- Err: fmt.Errorf("nested object expected: LBRACE got: %s", p.tok.Type),
- }
- }
-
- if keyCount == 0 {
- return nil, &PosError{
- Pos: p.tok.Pos,
- Err: errors.New("no object keys found!"),
- }
- }
-
- return keys, nil
- case token.LBRACE:
- var err error
-
- // If we have no keys, then it is a syntax error. i.e. {{}} is not
- // allowed.
- if len(keys) == 0 {
- err = &PosError{
- Pos: p.tok.Pos,
- Err: fmt.Errorf("expected: IDENT | STRING got: %s", p.tok.Type),
- }
- }
-
- // object
- return keys, err
- case token.IDENT, token.STRING:
- keyCount++
- keys = append(keys, &ast.ObjectKey{Token: p.tok})
- case token.ILLEGAL:
- return keys, &PosError{
- Pos: p.tok.Pos,
- Err: fmt.Errorf("illegal character"),
- }
- default:
- return keys, &PosError{
- Pos: p.tok.Pos,
- Err: fmt.Errorf("expected: IDENT | STRING | ASSIGN | LBRACE got: %s", p.tok.Type),
- }
- }
- }
-}
-
-// object parses any type of object, such as number, bool, string, object or
-// list.
-func (p *Parser) object() (ast.Node, error) {
- defer un(trace(p, "ParseType"))
- tok := p.scan()
-
- switch tok.Type {
- case token.NUMBER, token.FLOAT, token.BOOL, token.STRING, token.HEREDOC:
- return p.literalType()
- case token.LBRACE:
- return p.objectType()
- case token.LBRACK:
- return p.listType()
- case token.COMMENT:
- // implement comment
- case token.EOF:
- return nil, errEofToken
- }
-
- return nil, &PosError{
- Pos: tok.Pos,
- Err: fmt.Errorf("Unknown token: %+v", tok),
- }
-}
-
-// objectType parses an object type and returns a ObjectType AST
-func (p *Parser) objectType() (*ast.ObjectType, error) {
- defer un(trace(p, "ParseObjectType"))
-
- // we assume that the currently scanned token is a LBRACE
- o := &ast.ObjectType{
- Lbrace: p.tok.Pos,
- }
-
- l, err := p.objectList(true)
-
- // if we hit RBRACE, we are good to go (means we parsed all Items), if it's
- // not a RBRACE, it's an syntax error and we just return it.
- if err != nil && p.tok.Type != token.RBRACE {
- return nil, err
- }
-
- // No error, scan and expect the ending to be a brace
- if tok := p.scan(); tok.Type != token.RBRACE {
- return nil, &PosError{
- Pos: tok.Pos,
- Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type),
- }
- }
-
- o.List = l
- o.Rbrace = p.tok.Pos // advanced via parseObjectList
- return o, nil
-}
-
-// listType parses a list type and returns a ListType AST
-func (p *Parser) listType() (*ast.ListType, error) {
- defer un(trace(p, "ParseListType"))
-
- // we assume that the currently scanned token is a LBRACK
- l := &ast.ListType{
- Lbrack: p.tok.Pos,
- }
-
- needComma := false
- for {
- tok := p.scan()
- if needComma {
- switch tok.Type {
- case token.COMMA, token.RBRACK:
- default:
- return nil, &PosError{
- Pos: tok.Pos,
- Err: fmt.Errorf(
- "error parsing list, expected comma or list end, got: %s",
- tok.Type),
- }
- }
- }
- switch tok.Type {
- case token.BOOL, token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC:
- node, err := p.literalType()
- if err != nil {
- return nil, err
- }
-
- // If there is a lead comment, apply it
- if p.leadComment != nil {
- node.LeadComment = p.leadComment
- p.leadComment = nil
- }
-
- l.Add(node)
- needComma = true
- case token.COMMA:
- // get next list item or we are at the end
- // do a look-ahead for line comment
- p.scan()
- if p.lineComment != nil && len(l.List) > 0 {
- lit, ok := l.List[len(l.List)-1].(*ast.LiteralType)
- if ok {
- lit.LineComment = p.lineComment
- l.List[len(l.List)-1] = lit
- p.lineComment = nil
- }
- }
- p.unscan()
-
- needComma = false
- continue
- case token.LBRACE:
- // Looks like a nested object, so parse it out
- node, err := p.objectType()
- if err != nil {
- return nil, &PosError{
- Pos: tok.Pos,
- Err: fmt.Errorf(
- "error while trying to parse object within list: %s", err),
- }
- }
- l.Add(node)
- needComma = true
- case token.LBRACK:
- node, err := p.listType()
- if err != nil {
- return nil, &PosError{
- Pos: tok.Pos,
- Err: fmt.Errorf(
- "error while trying to parse list within list: %s", err),
- }
- }
- l.Add(node)
- case token.RBRACK:
- // finished
- l.Rbrack = p.tok.Pos
- return l, nil
- default:
- return nil, &PosError{
- Pos: tok.Pos,
- Err: fmt.Errorf("unexpected token while parsing list: %s", tok.Type),
- }
- }
- }
-}
-
-// literalType parses a literal type and returns a LiteralType AST
-func (p *Parser) literalType() (*ast.LiteralType, error) {
- defer un(trace(p, "ParseLiteral"))
-
- return &ast.LiteralType{
- Token: p.tok,
- }, nil
-}
-
-// scan returns the next token from the underlying scanner. If a token has
-// been unscanned then read that instead. In the process, it collects any
-// comment groups encountered, and remembers the last lead and line comments.
-func (p *Parser) scan() token.Token {
- // If we have a token on the buffer, then return it.
- if p.n != 0 {
- p.n = 0
- return p.tok
- }
-
- // Otherwise read the next token from the scanner and Save it to the buffer
- // in case we unscan later.
- prev := p.tok
- p.tok = p.sc.Scan()
-
- if p.tok.Type == token.COMMENT {
- var comment *ast.CommentGroup
- var endline int
-
- // fmt.Printf("p.tok.Pos.Line = %+v prev: %d endline %d \n",
- // p.tok.Pos.Line, prev.Pos.Line, endline)
- if p.tok.Pos.Line == prev.Pos.Line {
- // The comment is on same line as the previous token; it
- // cannot be a lead comment but may be a line comment.
- comment, endline = p.consumeCommentGroup(0)
- if p.tok.Pos.Line != endline {
- // The next token is on a different line, thus
- // the last comment group is a line comment.
- p.lineComment = comment
- }
- }
-
- // consume successor comments, if any
- endline = -1
- for p.tok.Type == token.COMMENT {
- comment, endline = p.consumeCommentGroup(1)
- }
-
- if endline+1 == p.tok.Pos.Line && p.tok.Type != token.RBRACE {
- switch p.tok.Type {
- case token.RBRACE, token.RBRACK:
- // Do not count for these cases
- default:
- // The next token is following on the line immediately after the
- // comment group, thus the last comment group is a lead comment.
- p.leadComment = comment
- }
- }
-
- }
-
- return p.tok
-}
-
-// unscan pushes the previously read token back onto the buffer.
-func (p *Parser) unscan() {
- p.n = 1
-}
-
-// ----------------------------------------------------------------------------
-// Parsing support
-
-func (p *Parser) printTrace(a ...interface{}) {
- if !p.enableTrace {
- return
- }
-
- const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
- const n = len(dots)
- fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column)
-
- i := 2 * p.indent
- for i > n {
- fmt.Print(dots)
- i -= n
- }
- // i <= n
- fmt.Print(dots[0:i])
- fmt.Println(a...)
-}
-
-func trace(p *Parser, msg string) *Parser {
- p.printTrace(msg, "(")
- p.indent++
- return p
-}
-
-// Usage pattern: defer un(trace(p, "..."))
-func un(p *Parser) {
- p.indent--
- p.printTrace(")")
-}
diff --git a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
deleted file mode 100644
index 624a18fe3a7..00000000000
--- a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
+++ /dev/null
@@ -1,652 +0,0 @@
-// Package scanner implements a scanner for HCL (HashiCorp Configuration
-// Language) source text.
-package scanner
-
-import (
- "bytes"
- "fmt"
- "os"
- "regexp"
- "unicode"
- "unicode/utf8"
-
- "github.com/hashicorp/hcl/hcl/token"
-)
-
-// eof represents a marker rune for the end of the reader.
-const eof = rune(0)
-
-// Scanner defines a lexical scanner
-type Scanner struct {
- buf *bytes.Buffer // Source buffer for advancing and scanning
- src []byte // Source buffer for immutable access
-
- // Source Position
- srcPos token.Pos // current position
- prevPos token.Pos // previous position, used for peek() method
-
- lastCharLen int // length of last character in bytes
- lastLineLen int // length of last line in characters (for correct column reporting)
-
- tokStart int // token text start position
- tokEnd int // token text end position
-
- // Error is called for each error encountered. If no Error
- // function is set, the error is reported to os.Stderr.
- Error func(pos token.Pos, msg string)
-
- // ErrorCount is incremented by one for each error encountered.
- ErrorCount int
-
- // tokPos is the start position of most recently scanned token; set by
- // Scan. The Filename field is always left untouched by the Scanner. If
- // an error is reported (via Error) and Position is invalid, the scanner is
- // not inside a token.
- tokPos token.Pos
-}
-
-// New creates and initializes a new instance of Scanner using src as
-// its source content.
-func New(src []byte) *Scanner {
- // even though we accept a src, we read from a io.Reader compatible type
- // (*bytes.Buffer). So in the future we might easily change it to streaming
- // read.
- b := bytes.NewBuffer(src)
- s := &Scanner{
- buf: b,
- src: src,
- }
-
- // srcPosition always starts with 1
- s.srcPos.Line = 1
- return s
-}
-
-// next reads the next rune from the bufferred reader. Returns the rune(0) if
-// an error occurs (or io.EOF is returned).
-func (s *Scanner) next() rune {
- ch, size, err := s.buf.ReadRune()
- if err != nil {
- // advance for error reporting
- s.srcPos.Column++
- s.srcPos.Offset += size
- s.lastCharLen = size
- return eof
- }
-
- // remember last position
- s.prevPos = s.srcPos
-
- s.srcPos.Column++
- s.lastCharLen = size
- s.srcPos.Offset += size
-
- if ch == utf8.RuneError && size == 1 {
- s.err("illegal UTF-8 encoding")
- return ch
- }
-
- if ch == '\n' {
- s.srcPos.Line++
- s.lastLineLen = s.srcPos.Column
- s.srcPos.Column = 0
- }
-
- if ch == '\x00' {
- s.err("unexpected null character (0x00)")
- return eof
- }
-
- if ch == '\uE123' {
- s.err("unicode code point U+E123 reserved for internal use")
- return utf8.RuneError
- }
-
- // debug
- // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column)
- return ch
-}
-
-// unread unreads the previous read Rune and updates the source position
-func (s *Scanner) unread() {
- if err := s.buf.UnreadRune(); err != nil {
- panic(err) // this is user fault, we should catch it
- }
- s.srcPos = s.prevPos // put back last position
-}
-
-// peek returns the next rune without advancing the reader.
-func (s *Scanner) peek() rune {
- peek, _, err := s.buf.ReadRune()
- if err != nil {
- return eof
- }
-
- s.buf.UnreadRune()
- return peek
-}
-
-// Scan scans the next token and returns the token.
-func (s *Scanner) Scan() token.Token {
- ch := s.next()
-
- // skip white space
- for isWhitespace(ch) {
- ch = s.next()
- }
-
- var tok token.Type
-
- // token text markings
- s.tokStart = s.srcPos.Offset - s.lastCharLen
-
- // token position, initial next() is moving the offset by one(size of rune
- // actually), though we are interested with the starting point
- s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen
- if s.srcPos.Column > 0 {
- // common case: last character was not a '\n'
- s.tokPos.Line = s.srcPos.Line
- s.tokPos.Column = s.srcPos.Column
- } else {
- // last character was a '\n'
- // (we cannot be at the beginning of the source
- // since we have called next() at least once)
- s.tokPos.Line = s.srcPos.Line - 1
- s.tokPos.Column = s.lastLineLen
- }
-
- switch {
- case isLetter(ch):
- tok = token.IDENT
- lit := s.scanIdentifier()
- if lit == "true" || lit == "false" {
- tok = token.BOOL
- }
- case isDecimal(ch):
- tok = s.scanNumber(ch)
- default:
- switch ch {
- case eof:
- tok = token.EOF
- case '"':
- tok = token.STRING
- s.scanString()
- case '#', '/':
- tok = token.COMMENT
- s.scanComment(ch)
- case '.':
- tok = token.PERIOD
- ch = s.peek()
- if isDecimal(ch) {
- tok = token.FLOAT
- ch = s.scanMantissa(ch)
- ch = s.scanExponent(ch)
- }
- case '<':
- tok = token.HEREDOC
- s.scanHeredoc()
- case '[':
- tok = token.LBRACK
- case ']':
- tok = token.RBRACK
- case '{':
- tok = token.LBRACE
- case '}':
- tok = token.RBRACE
- case ',':
- tok = token.COMMA
- case '=':
- tok = token.ASSIGN
- case '+':
- tok = token.ADD
- case '-':
- if isDecimal(s.peek()) {
- ch := s.next()
- tok = s.scanNumber(ch)
- } else {
- tok = token.SUB
- }
- default:
- s.err("illegal char")
- }
- }
-
- // finish token ending
- s.tokEnd = s.srcPos.Offset
-
- // create token literal
- var tokenText string
- if s.tokStart >= 0 {
- tokenText = string(s.src[s.tokStart:s.tokEnd])
- }
- s.tokStart = s.tokEnd // ensure idempotency of tokenText() call
-
- return token.Token{
- Type: tok,
- Pos: s.tokPos,
- Text: tokenText,
- }
-}
-
-func (s *Scanner) scanComment(ch rune) {
- // single line comments
- if ch == '#' || (ch == '/' && s.peek() != '*') {
- if ch == '/' && s.peek() != '/' {
- s.err("expected '/' for comment")
- return
- }
-
- ch = s.next()
- for ch != '\n' && ch >= 0 && ch != eof {
- ch = s.next()
- }
- if ch != eof && ch >= 0 {
- s.unread()
- }
- return
- }
-
- // be sure we get the character after /* This allows us to find comment's
- // that are not erminated
- if ch == '/' {
- s.next()
- ch = s.next() // read character after "/*"
- }
-
- // look for /* - style comments
- for {
- if ch < 0 || ch == eof {
- s.err("comment not terminated")
- break
- }
-
- ch0 := ch
- ch = s.next()
- if ch0 == '*' && ch == '/' {
- break
- }
- }
-}
-
-// scanNumber scans a HCL number definition starting with the given rune
-func (s *Scanner) scanNumber(ch rune) token.Type {
- if ch == '0' {
- // check for hexadecimal, octal or float
- ch = s.next()
- if ch == 'x' || ch == 'X' {
- // hexadecimal
- ch = s.next()
- found := false
- for isHexadecimal(ch) {
- ch = s.next()
- found = true
- }
-
- if !found {
- s.err("illegal hexadecimal number")
- }
-
- if ch != eof {
- s.unread()
- }
-
- return token.NUMBER
- }
-
- // now it's either something like: 0421(octal) or 0.1231(float)
- illegalOctal := false
- for isDecimal(ch) {
- ch = s.next()
- if ch == '8' || ch == '9' {
- // this is just a possibility. For example 0159 is illegal, but
- // 0159.23 is valid. So we mark a possible illegal octal. If
- // the next character is not a period, we'll print the error.
- illegalOctal = true
- }
- }
-
- if ch == 'e' || ch == 'E' {
- ch = s.scanExponent(ch)
- return token.FLOAT
- }
-
- if ch == '.' {
- ch = s.scanFraction(ch)
-
- if ch == 'e' || ch == 'E' {
- ch = s.next()
- ch = s.scanExponent(ch)
- }
- return token.FLOAT
- }
-
- if illegalOctal {
- s.err("illegal octal number")
- }
-
- if ch != eof {
- s.unread()
- }
- return token.NUMBER
- }
-
- s.scanMantissa(ch)
- ch = s.next() // seek forward
- if ch == 'e' || ch == 'E' {
- ch = s.scanExponent(ch)
- return token.FLOAT
- }
-
- if ch == '.' {
- ch = s.scanFraction(ch)
- if ch == 'e' || ch == 'E' {
- ch = s.next()
- ch = s.scanExponent(ch)
- }
- return token.FLOAT
- }
-
- if ch != eof {
- s.unread()
- }
- return token.NUMBER
-}
-
-// scanMantissa scans the mantissa beginning from the rune. It returns the next
-// non decimal rune. It's used to determine wheter it's a fraction or exponent.
-func (s *Scanner) scanMantissa(ch rune) rune {
- scanned := false
- for isDecimal(ch) {
- ch = s.next()
- scanned = true
- }
-
- if scanned && ch != eof {
- s.unread()
- }
- return ch
-}
-
-// scanFraction scans the fraction after the '.' rune
-func (s *Scanner) scanFraction(ch rune) rune {
- if ch == '.' {
- ch = s.peek() // we peek just to see if we can move forward
- ch = s.scanMantissa(ch)
- }
- return ch
-}
-
-// scanExponent scans the remaining parts of an exponent after the 'e' or 'E'
-// rune.
-func (s *Scanner) scanExponent(ch rune) rune {
- if ch == 'e' || ch == 'E' {
- ch = s.next()
- if ch == '-' || ch == '+' {
- ch = s.next()
- }
- ch = s.scanMantissa(ch)
- }
- return ch
-}
-
-// scanHeredoc scans a heredoc string
-func (s *Scanner) scanHeredoc() {
- // Scan the second '<' in example: '<= len(identBytes) && identRegexp.Match(s.src[lineStart:s.srcPos.Offset-s.lastCharLen]) {
- break
- }
-
- // Not an anchor match, record the start of a new line
- lineStart = s.srcPos.Offset
- }
-
- if ch == eof {
- s.err("heredoc not terminated")
- return
- }
- }
-
- return
-}
-
-// scanString scans a quoted string
-func (s *Scanner) scanString() {
- braces := 0
- for {
- // '"' opening already consumed
- // read character after quote
- ch := s.next()
-
- if (ch == '\n' && braces == 0) || ch < 0 || ch == eof {
- s.err("literal not terminated")
- return
- }
-
- if ch == '"' && braces == 0 {
- break
- }
-
- // If we're going into a ${} then we can ignore quotes for awhile
- if braces == 0 && ch == '$' && s.peek() == '{' {
- braces++
- s.next()
- } else if braces > 0 && ch == '{' {
- braces++
- }
- if braces > 0 && ch == '}' {
- braces--
- }
-
- if ch == '\\' {
- s.scanEscape()
- }
- }
-
- return
-}
-
-// scanEscape scans an escape sequence
-func (s *Scanner) scanEscape() rune {
- // http://en.cppreference.com/w/cpp/language/escape
- ch := s.next() // read character after '/'
- switch ch {
- case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"':
- // nothing to do
- case '0', '1', '2', '3', '4', '5', '6', '7':
- // octal notation
- ch = s.scanDigits(ch, 8, 3)
- case 'x':
- // hexademical notation
- ch = s.scanDigits(s.next(), 16, 2)
- case 'u':
- // universal character name
- ch = s.scanDigits(s.next(), 16, 4)
- case 'U':
- // universal character name
- ch = s.scanDigits(s.next(), 16, 8)
- default:
- s.err("illegal char escape")
- }
- return ch
-}
-
-// scanDigits scans a rune with the given base for n times. For example an
-// octal notation \184 would yield in scanDigits(ch, 8, 3)
-func (s *Scanner) scanDigits(ch rune, base, n int) rune {
- start := n
- for n > 0 && digitVal(ch) < base {
- ch = s.next()
- if ch == eof {
- // If we see an EOF, we halt any more scanning of digits
- // immediately.
- break
- }
-
- n--
- }
- if n > 0 {
- s.err("illegal char escape")
- }
-
- if n != start && ch != eof {
- // we scanned all digits, put the last non digit char back,
- // only if we read anything at all
- s.unread()
- }
-
- return ch
-}
-
-// scanIdentifier scans an identifier and returns the literal string
-func (s *Scanner) scanIdentifier() string {
- offs := s.srcPos.Offset - s.lastCharLen
- ch := s.next()
- for isLetter(ch) || isDigit(ch) || ch == '-' || ch == '.' {
- ch = s.next()
- }
-
- if ch != eof {
- s.unread() // we got identifier, put back latest char
- }
-
- return string(s.src[offs:s.srcPos.Offset])
-}
-
-// recentPosition returns the position of the character immediately after the
-// character or token returned by the last call to Scan.
-func (s *Scanner) recentPosition() (pos token.Pos) {
- pos.Offset = s.srcPos.Offset - s.lastCharLen
- switch {
- case s.srcPos.Column > 0:
- // common case: last character was not a '\n'
- pos.Line = s.srcPos.Line
- pos.Column = s.srcPos.Column
- case s.lastLineLen > 0:
- // last character was a '\n'
- // (we cannot be at the beginning of the source
- // since we have called next() at least once)
- pos.Line = s.srcPos.Line - 1
- pos.Column = s.lastLineLen
- default:
- // at the beginning of the source
- pos.Line = 1
- pos.Column = 1
- }
- return
-}
-
-// err prints the error of any scanning to s.Error function. If the function is
-// not defined, by default it prints them to os.Stderr
-func (s *Scanner) err(msg string) {
- s.ErrorCount++
- pos := s.recentPosition()
-
- if s.Error != nil {
- s.Error(pos, msg)
- return
- }
-
- fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg)
-}
-
-// isHexadecimal returns true if the given rune is a letter
-func isLetter(ch rune) bool {
- return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
-}
-
-// isDigit returns true if the given rune is a decimal digit
-func isDigit(ch rune) bool {
- return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
-}
-
-// isDecimal returns true if the given rune is a decimal number
-func isDecimal(ch rune) bool {
- return '0' <= ch && ch <= '9'
-}
-
-// isHexadecimal returns true if the given rune is an hexadecimal number
-func isHexadecimal(ch rune) bool {
- return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F'
-}
-
-// isWhitespace returns true if the rune is a space, tab, newline or carriage return
-func isWhitespace(ch rune) bool {
- return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
-}
-
-// digitVal returns the integer value of a given octal,decimal or hexadecimal rune
-func digitVal(ch rune) int {
- switch {
- case '0' <= ch && ch <= '9':
- return int(ch - '0')
- case 'a' <= ch && ch <= 'f':
- return int(ch - 'a' + 10)
- case 'A' <= ch && ch <= 'F':
- return int(ch - 'A' + 10)
- }
- return 16 // larger than any legal digit val
-}
diff --git a/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go b/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go
deleted file mode 100644
index 5f981eaa2f0..00000000000
--- a/vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go
+++ /dev/null
@@ -1,241 +0,0 @@
-package strconv
-
-import (
- "errors"
- "unicode/utf8"
-)
-
-// ErrSyntax indicates that a value does not have the right syntax for the target type.
-var ErrSyntax = errors.New("invalid syntax")
-
-// Unquote interprets s as a single-quoted, double-quoted,
-// or backquoted Go string literal, returning the string value
-// that s quotes. (If s is single-quoted, it would be a Go
-// character literal; Unquote returns the corresponding
-// one-character string.)
-func Unquote(s string) (t string, err error) {
- n := len(s)
- if n < 2 {
- return "", ErrSyntax
- }
- quote := s[0]
- if quote != s[n-1] {
- return "", ErrSyntax
- }
- s = s[1 : n-1]
-
- if quote != '"' {
- return "", ErrSyntax
- }
- if !contains(s, '$') && !contains(s, '{') && contains(s, '\n') {
- return "", ErrSyntax
- }
-
- // Is it trivial? Avoid allocation.
- if !contains(s, '\\') && !contains(s, quote) && !contains(s, '$') {
- switch quote {
- case '"':
- return s, nil
- case '\'':
- r, size := utf8.DecodeRuneInString(s)
- if size == len(s) && (r != utf8.RuneError || size != 1) {
- return s, nil
- }
- }
- }
-
- var runeTmp [utf8.UTFMax]byte
- buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
- for len(s) > 0 {
- // If we're starting a '${}' then let it through un-unquoted.
- // Specifically: we don't unquote any characters within the `${}`
- // section.
- if s[0] == '$' && len(s) > 1 && s[1] == '{' {
- buf = append(buf, '$', '{')
- s = s[2:]
-
- // Continue reading until we find the closing brace, copying as-is
- braces := 1
- for len(s) > 0 && braces > 0 {
- r, size := utf8.DecodeRuneInString(s)
- if r == utf8.RuneError {
- return "", ErrSyntax
- }
-
- s = s[size:]
-
- n := utf8.EncodeRune(runeTmp[:], r)
- buf = append(buf, runeTmp[:n]...)
-
- switch r {
- case '{':
- braces++
- case '}':
- braces--
- }
- }
- if braces != 0 {
- return "", ErrSyntax
- }
- if len(s) == 0 {
- // If there's no string left, we're done!
- break
- } else {
- // If there's more left, we need to pop back up to the top of the loop
- // in case there's another interpolation in this string.
- continue
- }
- }
-
- if s[0] == '\n' {
- return "", ErrSyntax
- }
-
- c, multibyte, ss, err := unquoteChar(s, quote)
- if err != nil {
- return "", err
- }
- s = ss
- if c < utf8.RuneSelf || !multibyte {
- buf = append(buf, byte(c))
- } else {
- n := utf8.EncodeRune(runeTmp[:], c)
- buf = append(buf, runeTmp[:n]...)
- }
- if quote == '\'' && len(s) != 0 {
- // single-quoted must be single character
- return "", ErrSyntax
- }
- }
- return string(buf), nil
-}
-
-// contains reports whether the string contains the byte c.
-func contains(s string, c byte) bool {
- for i := 0; i < len(s); i++ {
- if s[i] == c {
- return true
- }
- }
- return false
-}
-
-func unhex(b byte) (v rune, ok bool) {
- c := rune(b)
- switch {
- case '0' <= c && c <= '9':
- return c - '0', true
- case 'a' <= c && c <= 'f':
- return c - 'a' + 10, true
- case 'A' <= c && c <= 'F':
- return c - 'A' + 10, true
- }
- return
-}
-
-func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) {
- // easy cases
- switch c := s[0]; {
- case c == quote && (quote == '\'' || quote == '"'):
- err = ErrSyntax
- return
- case c >= utf8.RuneSelf:
- r, size := utf8.DecodeRuneInString(s)
- return r, true, s[size:], nil
- case c != '\\':
- return rune(s[0]), false, s[1:], nil
- }
-
- // hard case: c is backslash
- if len(s) <= 1 {
- err = ErrSyntax
- return
- }
- c := s[1]
- s = s[2:]
-
- switch c {
- case 'a':
- value = '\a'
- case 'b':
- value = '\b'
- case 'f':
- value = '\f'
- case 'n':
- value = '\n'
- case 'r':
- value = '\r'
- case 't':
- value = '\t'
- case 'v':
- value = '\v'
- case 'x', 'u', 'U':
- n := 0
- switch c {
- case 'x':
- n = 2
- case 'u':
- n = 4
- case 'U':
- n = 8
- }
- var v rune
- if len(s) < n {
- err = ErrSyntax
- return
- }
- for j := 0; j < n; j++ {
- x, ok := unhex(s[j])
- if !ok {
- err = ErrSyntax
- return
- }
- v = v<<4 | x
- }
- s = s[n:]
- if c == 'x' {
- // single-byte string, possibly not UTF-8
- value = v
- break
- }
- if v > utf8.MaxRune {
- err = ErrSyntax
- return
- }
- value = v
- multibyte = true
- case '0', '1', '2', '3', '4', '5', '6', '7':
- v := rune(c) - '0'
- if len(s) < 2 {
- err = ErrSyntax
- return
- }
- for j := 0; j < 2; j++ { // one digit already; two more
- x := rune(s[j]) - '0'
- if x < 0 || x > 7 {
- err = ErrSyntax
- return
- }
- v = (v << 3) | x
- }
- s = s[2:]
- if v > 255 {
- err = ErrSyntax
- return
- }
- value = v
- case '\\':
- value = '\\'
- case '\'', '"':
- if c != quote {
- err = ErrSyntax
- return
- }
- value = rune(c)
- default:
- err = ErrSyntax
- return
- }
- tail = s
- return
-}
diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/position.go b/vendor/github.com/hashicorp/hcl/hcl/token/position.go
deleted file mode 100644
index 59c1bb72d4a..00000000000
--- a/vendor/github.com/hashicorp/hcl/hcl/token/position.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package token
-
-import "fmt"
-
-// Pos describes an arbitrary source position
-// including the file, line, and column location.
-// A Position is valid if the line number is > 0.
-type Pos struct {
- Filename string // filename, if any
- Offset int // offset, starting at 0
- Line int // line number, starting at 1
- Column int // column number, starting at 1 (character count)
-}
-
-// IsValid returns true if the position is valid.
-func (p *Pos) IsValid() bool { return p.Line > 0 }
-
-// String returns a string in one of several forms:
-//
-// file:line:column valid position with file name
-// line:column valid position without file name
-// file invalid position with file name
-// - invalid position without file name
-func (p Pos) String() string {
- s := p.Filename
- if p.IsValid() {
- if s != "" {
- s += ":"
- }
- s += fmt.Sprintf("%d:%d", p.Line, p.Column)
- }
- if s == "" {
- s = "-"
- }
- return s
-}
-
-// Before reports whether the position p is before u.
-func (p Pos) Before(u Pos) bool {
- return u.Offset > p.Offset || u.Line > p.Line
-}
-
-// After reports whether the position p is after u.
-func (p Pos) After(u Pos) bool {
- return u.Offset < p.Offset || u.Line < p.Line
-}
diff --git a/vendor/github.com/hashicorp/hcl/hcl/token/token.go b/vendor/github.com/hashicorp/hcl/hcl/token/token.go
deleted file mode 100644
index e37c0664ecd..00000000000
--- a/vendor/github.com/hashicorp/hcl/hcl/token/token.go
+++ /dev/null
@@ -1,219 +0,0 @@
-// Package token defines constants representing the lexical tokens for HCL
-// (HashiCorp Configuration Language)
-package token
-
-import (
- "fmt"
- "strconv"
- "strings"
-
- hclstrconv "github.com/hashicorp/hcl/hcl/strconv"
-)
-
-// Token defines a single HCL token which can be obtained via the Scanner
-type Token struct {
- Type Type
- Pos Pos
- Text string
- JSON bool
-}
-
-// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language)
-type Type int
-
-const (
- // Special tokens
- ILLEGAL Type = iota
- EOF
- COMMENT
-
- identifier_beg
- IDENT // literals
- literal_beg
- NUMBER // 12345
- FLOAT // 123.45
- BOOL // true,false
- STRING // "abc"
- HEREDOC // < 0 {
- // Pop the current item
- n := len(frontier)
- item := frontier[n-1]
- frontier = frontier[:n-1]
-
- switch v := item.Val.(type) {
- case *ast.ObjectType:
- items, frontier = flattenObjectType(v, item, items, frontier)
- case *ast.ListType:
- items, frontier = flattenListType(v, item, items, frontier)
- default:
- items = append(items, item)
- }
- }
-
- // Reverse the list since the frontier model runs things backwards
- for i := len(items)/2 - 1; i >= 0; i-- {
- opp := len(items) - 1 - i
- items[i], items[opp] = items[opp], items[i]
- }
-
- // Done! Set the original items
- list.Items = items
- return n, true
- })
-}
-
-func flattenListType(
- ot *ast.ListType,
- item *ast.ObjectItem,
- items []*ast.ObjectItem,
- frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
- // If the list is empty, keep the original list
- if len(ot.List) == 0 {
- items = append(items, item)
- return items, frontier
- }
-
- // All the elements of this object must also be objects!
- for _, subitem := range ot.List {
- if _, ok := subitem.(*ast.ObjectType); !ok {
- items = append(items, item)
- return items, frontier
- }
- }
-
- // Great! We have a match go through all the items and flatten
- for _, elem := range ot.List {
- // Add it to the frontier so that we can recurse
- frontier = append(frontier, &ast.ObjectItem{
- Keys: item.Keys,
- Assign: item.Assign,
- Val: elem,
- LeadComment: item.LeadComment,
- LineComment: item.LineComment,
- })
- }
-
- return items, frontier
-}
-
-func flattenObjectType(
- ot *ast.ObjectType,
- item *ast.ObjectItem,
- items []*ast.ObjectItem,
- frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
- // If the list has no items we do not have to flatten anything
- if ot.List.Items == nil {
- items = append(items, item)
- return items, frontier
- }
-
- // All the elements of this object must also be objects!
- for _, subitem := range ot.List.Items {
- if _, ok := subitem.Val.(*ast.ObjectType); !ok {
- items = append(items, item)
- return items, frontier
- }
- }
-
- // Great! We have a match go through all the items and flatten
- for _, subitem := range ot.List.Items {
- // Copy the new key
- keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys))
- copy(keys, item.Keys)
- copy(keys[len(item.Keys):], subitem.Keys)
-
- // Add it to the frontier so that we can recurse
- frontier = append(frontier, &ast.ObjectItem{
- Keys: keys,
- Assign: item.Assign,
- Val: subitem.Val,
- LeadComment: item.LeadComment,
- LineComment: item.LineComment,
- })
- }
-
- return items, frontier
-}
diff --git a/vendor/github.com/hashicorp/hcl/json/parser/parser.go b/vendor/github.com/hashicorp/hcl/json/parser/parser.go
deleted file mode 100644
index 125a5f07298..00000000000
--- a/vendor/github.com/hashicorp/hcl/json/parser/parser.go
+++ /dev/null
@@ -1,313 +0,0 @@
-package parser
-
-import (
- "errors"
- "fmt"
-
- "github.com/hashicorp/hcl/hcl/ast"
- hcltoken "github.com/hashicorp/hcl/hcl/token"
- "github.com/hashicorp/hcl/json/scanner"
- "github.com/hashicorp/hcl/json/token"
-)
-
-type Parser struct {
- sc *scanner.Scanner
-
- // Last read token
- tok token.Token
- commaPrev token.Token
-
- enableTrace bool
- indent int
- n int // buffer size (max = 1)
-}
-
-func newParser(src []byte) *Parser {
- return &Parser{
- sc: scanner.New(src),
- }
-}
-
-// Parse returns the fully parsed source and returns the abstract syntax tree.
-func Parse(src []byte) (*ast.File, error) {
- p := newParser(src)
- return p.Parse()
-}
-
-var errEofToken = errors.New("EOF token found")
-
-// Parse returns the fully parsed source and returns the abstract syntax tree.
-func (p *Parser) Parse() (*ast.File, error) {
- f := &ast.File{}
- var err, scerr error
- p.sc.Error = func(pos token.Pos, msg string) {
- scerr = fmt.Errorf("%s: %s", pos, msg)
- }
-
- // The root must be an object in JSON
- object, err := p.object()
- if scerr != nil {
- return nil, scerr
- }
- if err != nil {
- return nil, err
- }
-
- // We make our final node an object list so it is more HCL compatible
- f.Node = object.List
-
- // Flatten it, which finds patterns and turns them into more HCL-like
- // AST trees.
- flattenObjects(f.Node)
-
- return f, nil
-}
-
-func (p *Parser) objectList() (*ast.ObjectList, error) {
- defer un(trace(p, "ParseObjectList"))
- node := &ast.ObjectList{}
-
- for {
- n, err := p.objectItem()
- if err == errEofToken {
- break // we are finished
- }
-
- // we don't return a nil node, because might want to use already
- // collected items.
- if err != nil {
- return node, err
- }
-
- node.Add(n)
-
- // Check for a followup comma. If it isn't a comma, then we're done
- if tok := p.scan(); tok.Type != token.COMMA {
- break
- }
- }
-
- return node, nil
-}
-
-// objectItem parses a single object item
-func (p *Parser) objectItem() (*ast.ObjectItem, error) {
- defer un(trace(p, "ParseObjectItem"))
-
- keys, err := p.objectKey()
- if err != nil {
- return nil, err
- }
-
- o := &ast.ObjectItem{
- Keys: keys,
- }
-
- switch p.tok.Type {
- case token.COLON:
- pos := p.tok.Pos
- o.Assign = hcltoken.Pos{
- Filename: pos.Filename,
- Offset: pos.Offset,
- Line: pos.Line,
- Column: pos.Column,
- }
-
- o.Val, err = p.objectValue()
- if err != nil {
- return nil, err
- }
- }
-
- return o, nil
-}
-
-// objectKey parses an object key and returns a ObjectKey AST
-func (p *Parser) objectKey() ([]*ast.ObjectKey, error) {
- keyCount := 0
- keys := make([]*ast.ObjectKey, 0)
-
- for {
- tok := p.scan()
- switch tok.Type {
- case token.EOF:
- return nil, errEofToken
- case token.STRING:
- keyCount++
- keys = append(keys, &ast.ObjectKey{
- Token: p.tok.HCLToken(),
- })
- case token.COLON:
- // If we have a zero keycount it means that we never got
- // an object key, i.e. `{ :`. This is a syntax error.
- if keyCount == 0 {
- return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type)
- }
-
- // Done
- return keys, nil
- case token.ILLEGAL:
- return nil, errors.New("illegal")
- default:
- return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type)
- }
- }
-}
-
-// object parses any type of object, such as number, bool, string, object or
-// list.
-func (p *Parser) objectValue() (ast.Node, error) {
- defer un(trace(p, "ParseObjectValue"))
- tok := p.scan()
-
- switch tok.Type {
- case token.NUMBER, token.FLOAT, token.BOOL, token.NULL, token.STRING:
- return p.literalType()
- case token.LBRACE:
- return p.objectType()
- case token.LBRACK:
- return p.listType()
- case token.EOF:
- return nil, errEofToken
- }
-
- return nil, fmt.Errorf("Expected object value, got unknown token: %+v", tok)
-}
-
-// object parses any type of object, such as number, bool, string, object or
-// list.
-func (p *Parser) object() (*ast.ObjectType, error) {
- defer un(trace(p, "ParseType"))
- tok := p.scan()
-
- switch tok.Type {
- case token.LBRACE:
- return p.objectType()
- case token.EOF:
- return nil, errEofToken
- }
-
- return nil, fmt.Errorf("Expected object, got unknown token: %+v", tok)
-}
-
-// objectType parses an object type and returns a ObjectType AST
-func (p *Parser) objectType() (*ast.ObjectType, error) {
- defer un(trace(p, "ParseObjectType"))
-
- // we assume that the currently scanned token is a LBRACE
- o := &ast.ObjectType{}
-
- l, err := p.objectList()
-
- // if we hit RBRACE, we are good to go (means we parsed all Items), if it's
- // not a RBRACE, it's an syntax error and we just return it.
- if err != nil && p.tok.Type != token.RBRACE {
- return nil, err
- }
-
- o.List = l
- return o, nil
-}
-
-// listType parses a list type and returns a ListType AST
-func (p *Parser) listType() (*ast.ListType, error) {
- defer un(trace(p, "ParseListType"))
-
- // we assume that the currently scanned token is a LBRACK
- l := &ast.ListType{}
-
- for {
- tok := p.scan()
- switch tok.Type {
- case token.NUMBER, token.FLOAT, token.STRING:
- node, err := p.literalType()
- if err != nil {
- return nil, err
- }
-
- l.Add(node)
- case token.COMMA:
- continue
- case token.LBRACE:
- node, err := p.objectType()
- if err != nil {
- return nil, err
- }
-
- l.Add(node)
- case token.BOOL:
- // TODO(arslan) should we support? not supported by HCL yet
- case token.LBRACK:
- // TODO(arslan) should we support nested lists? Even though it's
- // written in README of HCL, it's not a part of the grammar
- // (not defined in parse.y)
- case token.RBRACK:
- // finished
- return l, nil
- default:
- return nil, fmt.Errorf("unexpected token while parsing list: %s", tok.Type)
- }
-
- }
-}
-
-// literalType parses a literal type and returns a LiteralType AST
-func (p *Parser) literalType() (*ast.LiteralType, error) {
- defer un(trace(p, "ParseLiteral"))
-
- return &ast.LiteralType{
- Token: p.tok.HCLToken(),
- }, nil
-}
-
-// scan returns the next token from the underlying scanner. If a token has
-// been unscanned then read that instead.
-func (p *Parser) scan() token.Token {
- // If we have a token on the buffer, then return it.
- if p.n != 0 {
- p.n = 0
- return p.tok
- }
-
- p.tok = p.sc.Scan()
- return p.tok
-}
-
-// unscan pushes the previously read token back onto the buffer.
-func (p *Parser) unscan() {
- p.n = 1
-}
-
-// ----------------------------------------------------------------------------
-// Parsing support
-
-func (p *Parser) printTrace(a ...interface{}) {
- if !p.enableTrace {
- return
- }
-
- const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
- const n = len(dots)
- fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column)
-
- i := 2 * p.indent
- for i > n {
- fmt.Print(dots)
- i -= n
- }
- // i <= n
- fmt.Print(dots[0:i])
- fmt.Println(a...)
-}
-
-func trace(p *Parser, msg string) *Parser {
- p.printTrace(msg, "(")
- p.indent++
- return p
-}
-
-// Usage pattern: defer un(trace(p, "..."))
-func un(p *Parser) {
- p.indent--
- p.printTrace(")")
-}
diff --git a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
deleted file mode 100644
index fe3f0f09502..00000000000
--- a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
+++ /dev/null
@@ -1,451 +0,0 @@
-package scanner
-
-import (
- "bytes"
- "fmt"
- "os"
- "unicode"
- "unicode/utf8"
-
- "github.com/hashicorp/hcl/json/token"
-)
-
-// eof represents a marker rune for the end of the reader.
-const eof = rune(0)
-
-// Scanner defines a lexical scanner
-type Scanner struct {
- buf *bytes.Buffer // Source buffer for advancing and scanning
- src []byte // Source buffer for immutable access
-
- // Source Position
- srcPos token.Pos // current position
- prevPos token.Pos // previous position, used for peek() method
-
- lastCharLen int // length of last character in bytes
- lastLineLen int // length of last line in characters (for correct column reporting)
-
- tokStart int // token text start position
- tokEnd int // token text end position
-
- // Error is called for each error encountered. If no Error
- // function is set, the error is reported to os.Stderr.
- Error func(pos token.Pos, msg string)
-
- // ErrorCount is incremented by one for each error encountered.
- ErrorCount int
-
- // tokPos is the start position of most recently scanned token; set by
- // Scan. The Filename field is always left untouched by the Scanner. If
- // an error is reported (via Error) and Position is invalid, the scanner is
- // not inside a token.
- tokPos token.Pos
-}
-
-// New creates and initializes a new instance of Scanner using src as
-// its source content.
-func New(src []byte) *Scanner {
- // even though we accept a src, we read from a io.Reader compatible type
- // (*bytes.Buffer). So in the future we might easily change it to streaming
- // read.
- b := bytes.NewBuffer(src)
- s := &Scanner{
- buf: b,
- src: src,
- }
-
- // srcPosition always starts with 1
- s.srcPos.Line = 1
- return s
-}
-
-// next reads the next rune from the bufferred reader. Returns the rune(0) if
-// an error occurs (or io.EOF is returned).
-func (s *Scanner) next() rune {
- ch, size, err := s.buf.ReadRune()
- if err != nil {
- // advance for error reporting
- s.srcPos.Column++
- s.srcPos.Offset += size
- s.lastCharLen = size
- return eof
- }
-
- if ch == utf8.RuneError && size == 1 {
- s.srcPos.Column++
- s.srcPos.Offset += size
- s.lastCharLen = size
- s.err("illegal UTF-8 encoding")
- return ch
- }
-
- // remember last position
- s.prevPos = s.srcPos
-
- s.srcPos.Column++
- s.lastCharLen = size
- s.srcPos.Offset += size
-
- if ch == '\n' {
- s.srcPos.Line++
- s.lastLineLen = s.srcPos.Column
- s.srcPos.Column = 0
- }
-
- // debug
- // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column)
- return ch
-}
-
-// unread unreads the previous read Rune and updates the source position
-func (s *Scanner) unread() {
- if err := s.buf.UnreadRune(); err != nil {
- panic(err) // this is user fault, we should catch it
- }
- s.srcPos = s.prevPos // put back last position
-}
-
-// peek returns the next rune without advancing the reader.
-func (s *Scanner) peek() rune {
- peek, _, err := s.buf.ReadRune()
- if err != nil {
- return eof
- }
-
- s.buf.UnreadRune()
- return peek
-}
-
-// Scan scans the next token and returns the token.
-func (s *Scanner) Scan() token.Token {
- ch := s.next()
-
- // skip white space
- for isWhitespace(ch) {
- ch = s.next()
- }
-
- var tok token.Type
-
- // token text markings
- s.tokStart = s.srcPos.Offset - s.lastCharLen
-
- // token position, initial next() is moving the offset by one(size of rune
- // actually), though we are interested with the starting point
- s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen
- if s.srcPos.Column > 0 {
- // common case: last character was not a '\n'
- s.tokPos.Line = s.srcPos.Line
- s.tokPos.Column = s.srcPos.Column
- } else {
- // last character was a '\n'
- // (we cannot be at the beginning of the source
- // since we have called next() at least once)
- s.tokPos.Line = s.srcPos.Line - 1
- s.tokPos.Column = s.lastLineLen
- }
-
- switch {
- case isLetter(ch):
- lit := s.scanIdentifier()
- if lit == "true" || lit == "false" {
- tok = token.BOOL
- } else if lit == "null" {
- tok = token.NULL
- } else {
- s.err("illegal char")
- }
- case isDecimal(ch):
- tok = s.scanNumber(ch)
- default:
- switch ch {
- case eof:
- tok = token.EOF
- case '"':
- tok = token.STRING
- s.scanString()
- case '.':
- tok = token.PERIOD
- ch = s.peek()
- if isDecimal(ch) {
- tok = token.FLOAT
- ch = s.scanMantissa(ch)
- ch = s.scanExponent(ch)
- }
- case '[':
- tok = token.LBRACK
- case ']':
- tok = token.RBRACK
- case '{':
- tok = token.LBRACE
- case '}':
- tok = token.RBRACE
- case ',':
- tok = token.COMMA
- case ':':
- tok = token.COLON
- case '-':
- if isDecimal(s.peek()) {
- ch := s.next()
- tok = s.scanNumber(ch)
- } else {
- s.err("illegal char")
- }
- default:
- s.err("illegal char: " + string(ch))
- }
- }
-
- // finish token ending
- s.tokEnd = s.srcPos.Offset
-
- // create token literal
- var tokenText string
- if s.tokStart >= 0 {
- tokenText = string(s.src[s.tokStart:s.tokEnd])
- }
- s.tokStart = s.tokEnd // ensure idempotency of tokenText() call
-
- return token.Token{
- Type: tok,
- Pos: s.tokPos,
- Text: tokenText,
- }
-}
-
-// scanNumber scans a HCL number definition starting with the given rune
-func (s *Scanner) scanNumber(ch rune) token.Type {
- zero := ch == '0'
- pos := s.srcPos
-
- s.scanMantissa(ch)
- ch = s.next() // seek forward
- if ch == 'e' || ch == 'E' {
- ch = s.scanExponent(ch)
- return token.FLOAT
- }
-
- if ch == '.' {
- ch = s.scanFraction(ch)
- if ch == 'e' || ch == 'E' {
- ch = s.next()
- ch = s.scanExponent(ch)
- }
- return token.FLOAT
- }
-
- if ch != eof {
- s.unread()
- }
-
- // If we have a larger number and this is zero, error
- if zero && pos != s.srcPos {
- s.err("numbers cannot start with 0")
- }
-
- return token.NUMBER
-}
-
-// scanMantissa scans the mantissa beginning from the rune. It returns the next
-// non decimal rune. It's used to determine wheter it's a fraction or exponent.
-func (s *Scanner) scanMantissa(ch rune) rune {
- scanned := false
- for isDecimal(ch) {
- ch = s.next()
- scanned = true
- }
-
- if scanned && ch != eof {
- s.unread()
- }
- return ch
-}
-
-// scanFraction scans the fraction after the '.' rune
-func (s *Scanner) scanFraction(ch rune) rune {
- if ch == '.' {
- ch = s.peek() // we peek just to see if we can move forward
- ch = s.scanMantissa(ch)
- }
- return ch
-}
-
-// scanExponent scans the remaining parts of an exponent after the 'e' or 'E'
-// rune.
-func (s *Scanner) scanExponent(ch rune) rune {
- if ch == 'e' || ch == 'E' {
- ch = s.next()
- if ch == '-' || ch == '+' {
- ch = s.next()
- }
- ch = s.scanMantissa(ch)
- }
- return ch
-}
-
-// scanString scans a quoted string
-func (s *Scanner) scanString() {
- braces := 0
- for {
- // '"' opening already consumed
- // read character after quote
- ch := s.next()
-
- if ch == '\n' || ch < 0 || ch == eof {
- s.err("literal not terminated")
- return
- }
-
- if ch == '"' {
- break
- }
-
- // If we're going into a ${} then we can ignore quotes for awhile
- if braces == 0 && ch == '$' && s.peek() == '{' {
- braces++
- s.next()
- } else if braces > 0 && ch == '{' {
- braces++
- }
- if braces > 0 && ch == '}' {
- braces--
- }
-
- if ch == '\\' {
- s.scanEscape()
- }
- }
-
- return
-}
-
-// scanEscape scans an escape sequence
-func (s *Scanner) scanEscape() rune {
- // http://en.cppreference.com/w/cpp/language/escape
- ch := s.next() // read character after '/'
- switch ch {
- case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"':
- // nothing to do
- case '0', '1', '2', '3', '4', '5', '6', '7':
- // octal notation
- ch = s.scanDigits(ch, 8, 3)
- case 'x':
- // hexademical notation
- ch = s.scanDigits(s.next(), 16, 2)
- case 'u':
- // universal character name
- ch = s.scanDigits(s.next(), 16, 4)
- case 'U':
- // universal character name
- ch = s.scanDigits(s.next(), 16, 8)
- default:
- s.err("illegal char escape")
- }
- return ch
-}
-
-// scanDigits scans a rune with the given base for n times. For example an
-// octal notation \184 would yield in scanDigits(ch, 8, 3)
-func (s *Scanner) scanDigits(ch rune, base, n int) rune {
- for n > 0 && digitVal(ch) < base {
- ch = s.next()
- n--
- }
- if n > 0 {
- s.err("illegal char escape")
- }
-
- // we scanned all digits, put the last non digit char back
- s.unread()
- return ch
-}
-
-// scanIdentifier scans an identifier and returns the literal string
-func (s *Scanner) scanIdentifier() string {
- offs := s.srcPos.Offset - s.lastCharLen
- ch := s.next()
- for isLetter(ch) || isDigit(ch) || ch == '-' {
- ch = s.next()
- }
-
- if ch != eof {
- s.unread() // we got identifier, put back latest char
- }
-
- return string(s.src[offs:s.srcPos.Offset])
-}
-
-// recentPosition returns the position of the character immediately after the
-// character or token returned by the last call to Scan.
-func (s *Scanner) recentPosition() (pos token.Pos) {
- pos.Offset = s.srcPos.Offset - s.lastCharLen
- switch {
- case s.srcPos.Column > 0:
- // common case: last character was not a '\n'
- pos.Line = s.srcPos.Line
- pos.Column = s.srcPos.Column
- case s.lastLineLen > 0:
- // last character was a '\n'
- // (we cannot be at the beginning of the source
- // since we have called next() at least once)
- pos.Line = s.srcPos.Line - 1
- pos.Column = s.lastLineLen
- default:
- // at the beginning of the source
- pos.Line = 1
- pos.Column = 1
- }
- return
-}
-
-// err prints the error of any scanning to s.Error function. If the function is
-// not defined, by default it prints them to os.Stderr
-func (s *Scanner) err(msg string) {
- s.ErrorCount++
- pos := s.recentPosition()
-
- if s.Error != nil {
- s.Error(pos, msg)
- return
- }
-
- fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg)
-}
-
-// isHexadecimal returns true if the given rune is a letter
-func isLetter(ch rune) bool {
- return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
-}
-
-// isHexadecimal returns true if the given rune is a decimal digit
-func isDigit(ch rune) bool {
- return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
-}
-
-// isHexadecimal returns true if the given rune is a decimal number
-func isDecimal(ch rune) bool {
- return '0' <= ch && ch <= '9'
-}
-
-// isHexadecimal returns true if the given rune is an hexadecimal number
-func isHexadecimal(ch rune) bool {
- return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F'
-}
-
-// isWhitespace returns true if the rune is a space, tab, newline or carriage return
-func isWhitespace(ch rune) bool {
- return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
-}
-
-// digitVal returns the integer value of a given octal,decimal or hexadecimal rune
-func digitVal(ch rune) int {
- switch {
- case '0' <= ch && ch <= '9':
- return int(ch - '0')
- case 'a' <= ch && ch <= 'f':
- return int(ch - 'a' + 10)
- case 'A' <= ch && ch <= 'F':
- return int(ch - 'A' + 10)
- }
- return 16 // larger than any legal digit val
-}
diff --git a/vendor/github.com/hashicorp/hcl/json/token/position.go b/vendor/github.com/hashicorp/hcl/json/token/position.go
deleted file mode 100644
index 59c1bb72d4a..00000000000
--- a/vendor/github.com/hashicorp/hcl/json/token/position.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package token
-
-import "fmt"
-
-// Pos describes an arbitrary source position
-// including the file, line, and column location.
-// A Position is valid if the line number is > 0.
-type Pos struct {
- Filename string // filename, if any
- Offset int // offset, starting at 0
- Line int // line number, starting at 1
- Column int // column number, starting at 1 (character count)
-}
-
-// IsValid returns true if the position is valid.
-func (p *Pos) IsValid() bool { return p.Line > 0 }
-
-// String returns a string in one of several forms:
-//
-// file:line:column valid position with file name
-// line:column valid position without file name
-// file invalid position with file name
-// - invalid position without file name
-func (p Pos) String() string {
- s := p.Filename
- if p.IsValid() {
- if s != "" {
- s += ":"
- }
- s += fmt.Sprintf("%d:%d", p.Line, p.Column)
- }
- if s == "" {
- s = "-"
- }
- return s
-}
-
-// Before reports whether the position p is before u.
-func (p Pos) Before(u Pos) bool {
- return u.Offset > p.Offset || u.Line > p.Line
-}
-
-// After reports whether the position p is after u.
-func (p Pos) After(u Pos) bool {
- return u.Offset < p.Offset || u.Line < p.Line
-}
diff --git a/vendor/github.com/hashicorp/hcl/json/token/token.go b/vendor/github.com/hashicorp/hcl/json/token/token.go
deleted file mode 100644
index 95a0c3eee65..00000000000
--- a/vendor/github.com/hashicorp/hcl/json/token/token.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package token
-
-import (
- "fmt"
- "strconv"
-
- hcltoken "github.com/hashicorp/hcl/hcl/token"
-)
-
-// Token defines a single HCL token which can be obtained via the Scanner
-type Token struct {
- Type Type
- Pos Pos
- Text string
-}
-
-// Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language)
-type Type int
-
-const (
- // Special tokens
- ILLEGAL Type = iota
- EOF
-
- identifier_beg
- literal_beg
- NUMBER // 12345
- FLOAT // 123.45
- BOOL // true,false
- STRING // "abc"
- NULL // null
- literal_end
- identifier_end
-
- operator_beg
- LBRACK // [
- LBRACE // {
- COMMA // ,
- PERIOD // .
- COLON // :
-
- RBRACK // ]
- RBRACE // }
-
- operator_end
-)
-
-var tokens = [...]string{
- ILLEGAL: "ILLEGAL",
-
- EOF: "EOF",
-
- NUMBER: "NUMBER",
- FLOAT: "FLOAT",
- BOOL: "BOOL",
- STRING: "STRING",
- NULL: "NULL",
-
- LBRACK: "LBRACK",
- LBRACE: "LBRACE",
- COMMA: "COMMA",
- PERIOD: "PERIOD",
- COLON: "COLON",
-
- RBRACK: "RBRACK",
- RBRACE: "RBRACE",
-}
-
-// String returns the string corresponding to the token tok.
-func (t Type) String() string {
- s := ""
- if 0 <= t && t < Type(len(tokens)) {
- s = tokens[t]
- }
- if s == "" {
- s = "token(" + strconv.Itoa(int(t)) + ")"
- }
- return s
-}
-
-// IsIdentifier returns true for tokens corresponding to identifiers and basic
-// type literals; it returns false otherwise.
-func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end }
-
-// IsLiteral returns true for tokens corresponding to basic type literals; it
-// returns false otherwise.
-func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end }
-
-// IsOperator returns true for tokens corresponding to operators and
-// delimiters; it returns false otherwise.
-func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end }
-
-// String returns the token's literal text. Note that this is only
-// applicable for certain token types, such as token.IDENT,
-// token.STRING, etc..
-func (t Token) String() string {
- return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text)
-}
-
-// HCLToken converts this token to an HCL token.
-//
-// The token type must be a literal type or this will panic.
-func (t Token) HCLToken() hcltoken.Token {
- switch t.Type {
- case BOOL:
- return hcltoken.Token{Type: hcltoken.BOOL, Text: t.Text}
- case FLOAT:
- return hcltoken.Token{Type: hcltoken.FLOAT, Text: t.Text}
- case NULL:
- return hcltoken.Token{Type: hcltoken.STRING, Text: ""}
- case NUMBER:
- return hcltoken.Token{Type: hcltoken.NUMBER, Text: t.Text}
- case STRING:
- return hcltoken.Token{Type: hcltoken.STRING, Text: t.Text, JSON: true}
- default:
- panic(fmt.Sprintf("unimplemented HCLToken for type: %s", t.Type))
- }
-}
diff --git a/vendor/github.com/hashicorp/hcl/lex.go b/vendor/github.com/hashicorp/hcl/lex.go
deleted file mode 100644
index d9993c2928a..00000000000
--- a/vendor/github.com/hashicorp/hcl/lex.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package hcl
-
-import (
- "unicode"
- "unicode/utf8"
-)
-
-type lexModeValue byte
-
-const (
- lexModeUnknown lexModeValue = iota
- lexModeHcl
- lexModeJson
-)
-
-// lexMode returns whether we're going to be parsing in JSON
-// mode or HCL mode.
-func lexMode(v []byte) lexModeValue {
- var (
- r rune
- w int
- offset int
- )
-
- for {
- r, w = utf8.DecodeRune(v[offset:])
- offset += w
- if unicode.IsSpace(r) {
- continue
- }
- if r == '{' {
- return lexModeJson
- }
- break
- }
-
- return lexModeHcl
-}
diff --git a/vendor/github.com/hashicorp/hcl/parse.go b/vendor/github.com/hashicorp/hcl/parse.go
deleted file mode 100644
index 1fca53c4cee..00000000000
--- a/vendor/github.com/hashicorp/hcl/parse.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package hcl
-
-import (
- "fmt"
-
- "github.com/hashicorp/hcl/hcl/ast"
- hclParser "github.com/hashicorp/hcl/hcl/parser"
- jsonParser "github.com/hashicorp/hcl/json/parser"
-)
-
-// ParseBytes accepts as input byte slice and returns ast tree.
-//
-// Input can be either JSON or HCL
-func ParseBytes(in []byte) (*ast.File, error) {
- return parse(in)
-}
-
-// ParseString accepts input as a string and returns ast tree.
-func ParseString(input string) (*ast.File, error) {
- return parse([]byte(input))
-}
-
-func parse(in []byte) (*ast.File, error) {
- switch lexMode(in) {
- case lexModeHcl:
- return hclParser.Parse(in)
- case lexModeJson:
- return jsonParser.Parse(in)
- }
-
- return nil, fmt.Errorf("unknown config format")
-}
-
-// Parse parses the given input and returns the root object.
-//
-// The input format can be either HCL or JSON.
-func Parse(input string) (*ast.File, error) {
- return parse([]byte(input))
-}
diff --git a/vendor/github.com/hashicorp/serf/LICENSE b/vendor/github.com/hashicorp/serf/LICENSE
deleted file mode 100644
index c33dcc7c928..00000000000
--- a/vendor/github.com/hashicorp/serf/LICENSE
+++ /dev/null
@@ -1,354 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. “Contributorâ€
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. “Contributor Versionâ€
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor’s Contribution.
-
-1.3. “Contributionâ€
-
- means Covered Software of a particular Contributor.
-
-1.4. “Covered Softwareâ€
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. “Incompatible With Secondary Licensesâ€
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of version
- 1.1 or earlier of the License, but not also under the terms of a
- Secondary License.
-
-1.6. “Executable Formâ€
-
- means any form of the work other than Source Code Form.
-
-1.7. “Larger Workâ€
-
- means a work that combines Covered Software with other material, in a separate
- file or files, that is not Covered Software.
-
-1.8. “Licenseâ€
-
- means this document.
-
-1.9. “Licensableâ€
-
- means having the right to grant, to the maximum extent possible, whether at the
- time of the initial grant or subsequently, any and all of the rights conveyed by
- this License.
-
-1.10. “Modificationsâ€
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to, deletion
- from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. “Patent Claims†of a Contributor
-
- means any patent claim(s), including without limitation, method, process,
- and apparatus claims, in any patent Licensable by such Contributor that
- would be infringed, but for the grant of the License, by the making,
- using, selling, offering for sale, having made, import, or transfer of
- either its Contributions or its Contributor Version.
-
-1.12. “Secondary Licenseâ€
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. “Source Code Formâ€
-
- means the form of the work preferred for making modifications.
-
-1.14. “You†(or “Yourâ€)
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, “You†includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, “control†means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or as
- part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its Contributions
- or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution become
- effective for each Contribution on the date the Contributor first distributes
- such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under this
- License. No additional rights or licenses will be implied from the distribution
- or licensing of Covered Software under this License. Notwithstanding Section
- 2.1(b) above, no patent license is granted by a Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party’s
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of its
- Contributions.
-
- This License does not grant any rights in the trademarks, service marks, or
- logos of any Contributor (except as may be necessary to comply with the
- notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this License
- (see Section 10.2) or under the terms of a Secondary License (if permitted
- under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its Contributions
- are its original creation(s) or it has sufficient rights to grant the
- rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under applicable
- copyright doctrines of fair use, fair dealing, or other equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under the
- terms of this License. You must inform recipients that the Source Code Form
- of the Covered Software is governed by the terms of this License, and how
- they can obtain a copy of this License. You may not attempt to alter or
- restrict the recipients’ rights in the Source Code Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this License,
- or sublicense it under different terms, provided that the license for
- the Executable Form does not attempt to limit or alter the recipients’
- rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for the
- Covered Software. If the Larger Work is a combination of Covered Software
- with a work governed by one or more Secondary Licenses, and the Covered
- Software is not Incompatible With Secondary Licenses, this License permits
- You to additionally distribute such Covered Software under the terms of
- such Secondary License(s), so that the recipient of the Larger Work may, at
- their option, further distribute the Covered Software under the terms of
- either this License or such Secondary License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices (including
- copyright notices, patent notices, disclaimers of warranty, or limitations
- of liability) contained within the Source Code Form of the Covered
- Software, except that You may alter any license notices to the extent
- required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on behalf
- of any Contributor. You must make it absolutely clear that any such
- warranty, support, indemnity, or liability obligation is offered by You
- alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute, judicial
- order, or regulation then You must: (a) comply with the terms of this License
- to the maximum extent possible; and (b) describe the limitations and the code
- they affect. Such description must be placed in a text file included with all
- distributions of the Covered Software under this License. Except to the
- extent prohibited by statute or regulation, such description must be
- sufficiently detailed for a recipient of ordinary skill to be able to
- understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing basis,
- if such Contributor fails to notify You of the non-compliance by some
- reasonable means prior to 60 days after You have come back into compliance.
- Moreover, Your grants from a particular Contributor are reinstated on an
- ongoing basis if such Contributor notifies You of the non-compliance by
- some reasonable means, this is the first time You have received notice of
- non-compliance with this License from such Contributor, and You become
- compliant prior to 30 days after Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions, counter-claims,
- and cross-claims) alleging that a Contributor Version directly or
- indirectly infringes any patent, then the rights granted to You by any and
- all Contributors for the Covered Software under Section 2.1 of this License
- shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an “as is†basis, without
- warranty of any kind, either expressed, implied, or statutory, including,
- without limitation, warranties that the Covered Software is free of defects,
- merchantable, fit for a particular purpose or non-infringing. The entire
- risk as to the quality and performance of the Covered Software is with You.
- Should any Covered Software prove defective in any respect, You (not any
- Contributor) assume the cost of any necessary servicing, repair, or
- correction. This disclaimer of warranty constitutes an essential part of this
- License. No use of any Covered Software is authorized under this License
- except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from such
- party’s negligence to the extent applicable law prohibits such limitation.
- Some jurisdictions do not allow the exclusion or limitation of incidental or
- consequential damages, so this exclusion and limitation may not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts of
- a jurisdiction where the defendant maintains its principal place of business
- and such litigation shall be governed by laws of that jurisdiction, without
- reference to its conflict-of-law provisions. Nothing in this Section shall
- prevent a party’s ability to bring cross-claims or counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject matter
- hereof. If any provision of this License is held to be unenforceable, such
- provision shall be reformed only to the extent necessary to make it
- enforceable. Any law or regulation which provides that the language of a
- contract shall be construed against the drafter shall not be used to construe
- this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version of
- the License under which You originally received the Covered Software, or
- under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a modified
- version of this License if you rename the license and remove any
- references to the name of the license steward (except to note that such
- modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
- If You choose to distribute Source Code Form that is Incompatible With
- Secondary Licenses under the terms of this version of the License, the
- notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file, then
-You may include the notice in a location (such as a LICENSE file in a relevant
-directory) where a recipient would be likely to look for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - “Incompatible With Secondary Licenses†Notice
-
- This Source Code Form is “Incompatible
- With Secondary Licensesâ€, as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/serf/coordinate/client.go b/vendor/github.com/hashicorp/serf/coordinate/client.go
deleted file mode 100644
index 3582ee4dae2..00000000000
--- a/vendor/github.com/hashicorp/serf/coordinate/client.go
+++ /dev/null
@@ -1,243 +0,0 @@
-package coordinate
-
-import (
- "fmt"
- "math"
- "sort"
- "sync"
- "time"
-
- "github.com/armon/go-metrics"
-)
-
-// Client manages the estimated network coordinate for a given node, and adjusts
-// it as the node observes round trip times and estimated coordinates from other
-// nodes. The core algorithm is based on Vivaldi, see the documentation for Config
-// for more details.
-type Client struct {
- // coord is the current estimate of the client's network coordinate.
- coord *Coordinate
-
- // origin is a coordinate sitting at the origin.
- origin *Coordinate
-
- // config contains the tuning parameters that govern the performance of
- // the algorithm.
- config *Config
-
- // adjustmentIndex is the current index into the adjustmentSamples slice.
- adjustmentIndex uint
-
- // adjustment is used to store samples for the adjustment calculation.
- adjustmentSamples []float64
-
- // latencyFilterSamples is used to store the last several RTT samples,
- // keyed by node name. We will use the config's LatencyFilterSamples
- // value to determine how many samples we keep, per node.
- latencyFilterSamples map[string][]float64
-
- // stats is used to record events that occur when updating coordinates.
- stats ClientStats
-
- // mutex enables safe concurrent access to the client.
- mutex sync.RWMutex
-}
-
-// ClientStats is used to record events that occur when updating coordinates.
-type ClientStats struct {
- // Resets is incremented any time we reset our local coordinate because
- // our calculations have resulted in an invalid state.
- Resets int
-}
-
-// NewClient creates a new Client and verifies the configuration is valid.
-func NewClient(config *Config) (*Client, error) {
- if !(config.Dimensionality > 0) {
- return nil, fmt.Errorf("dimensionality must be >0")
- }
-
- return &Client{
- coord: NewCoordinate(config),
- origin: NewCoordinate(config),
- config: config,
- adjustmentIndex: 0,
- adjustmentSamples: make([]float64, config.AdjustmentWindowSize),
- latencyFilterSamples: make(map[string][]float64),
- }, nil
-}
-
-// GetCoordinate returns a copy of the coordinate for this client.
-func (c *Client) GetCoordinate() *Coordinate {
- c.mutex.RLock()
- defer c.mutex.RUnlock()
-
- return c.coord.Clone()
-}
-
-// SetCoordinate forces the client's coordinate to a known state.
-func (c *Client) SetCoordinate(coord *Coordinate) error {
- c.mutex.Lock()
- defer c.mutex.Unlock()
-
- if err := c.checkCoordinate(coord); err != nil {
- return err
- }
-
- c.coord = coord.Clone()
- return nil
-}
-
-// ForgetNode removes any client state for the given node.
-func (c *Client) ForgetNode(node string) {
- c.mutex.Lock()
- defer c.mutex.Unlock()
-
- delete(c.latencyFilterSamples, node)
-}
-
-// Stats returns a copy of stats for the client.
-func (c *Client) Stats() ClientStats {
- c.mutex.Lock()
- defer c.mutex.Unlock()
-
- return c.stats
-}
-
-// checkCoordinate returns an error if the coordinate isn't compatible with
-// this client, or if the coordinate itself isn't valid. This assumes the mutex
-// has been locked already.
-func (c *Client) checkCoordinate(coord *Coordinate) error {
- if !c.coord.IsCompatibleWith(coord) {
- return fmt.Errorf("dimensions aren't compatible")
- }
-
- if !coord.IsValid() {
- return fmt.Errorf("coordinate is invalid")
- }
-
- return nil
-}
-
-// latencyFilter applies a simple moving median filter with a new sample for
-// a node. This assumes that the mutex has been locked already.
-func (c *Client) latencyFilter(node string, rttSeconds float64) float64 {
- samples, ok := c.latencyFilterSamples[node]
- if !ok {
- samples = make([]float64, 0, c.config.LatencyFilterSize)
- }
-
- // Add the new sample and trim the list, if needed.
- samples = append(samples, rttSeconds)
- if len(samples) > int(c.config.LatencyFilterSize) {
- samples = samples[1:]
- }
- c.latencyFilterSamples[node] = samples
-
- // Sort a copy of the samples and return the median.
- sorted := make([]float64, len(samples))
- copy(sorted, samples)
- sort.Float64s(sorted)
- return sorted[len(sorted)/2]
-}
-
-// updateVivialdi updates the Vivaldi portion of the client's coordinate. This
-// assumes that the mutex has been locked already.
-func (c *Client) updateVivaldi(other *Coordinate, rttSeconds float64) {
- const zeroThreshold = 1.0e-6
-
- dist := c.coord.DistanceTo(other).Seconds()
- if rttSeconds < zeroThreshold {
- rttSeconds = zeroThreshold
- }
- wrongness := math.Abs(dist-rttSeconds) / rttSeconds
-
- totalError := c.coord.Error + other.Error
- if totalError < zeroThreshold {
- totalError = zeroThreshold
- }
- weight := c.coord.Error / totalError
-
- c.coord.Error = c.config.VivaldiCE*weight*wrongness + c.coord.Error*(1.0-c.config.VivaldiCE*weight)
- if c.coord.Error > c.config.VivaldiErrorMax {
- c.coord.Error = c.config.VivaldiErrorMax
- }
-
- delta := c.config.VivaldiCC * weight
- force := delta * (rttSeconds - dist)
- c.coord = c.coord.ApplyForce(c.config, force, other)
-}
-
-// updateAdjustment updates the adjustment portion of the client's coordinate, if
-// the feature is enabled. This assumes that the mutex has been locked already.
-func (c *Client) updateAdjustment(other *Coordinate, rttSeconds float64) {
- if c.config.AdjustmentWindowSize == 0 {
- return
- }
-
- // Note that the existing adjustment factors don't figure in to this
- // calculation so we use the raw distance here.
- dist := c.coord.rawDistanceTo(other)
- c.adjustmentSamples[c.adjustmentIndex] = rttSeconds - dist
- c.adjustmentIndex = (c.adjustmentIndex + 1) % c.config.AdjustmentWindowSize
-
- sum := 0.0
- for _, sample := range c.adjustmentSamples {
- sum += sample
- }
- c.coord.Adjustment = sum / (2.0 * float64(c.config.AdjustmentWindowSize))
-}
-
-// updateGravity applies a small amount of gravity to pull coordinates towards
-// the center of the coordinate system to combat drift. This assumes that the
-// mutex is locked already.
-func (c *Client) updateGravity() {
- dist := c.origin.DistanceTo(c.coord).Seconds()
- force := -1.0 * math.Pow(dist/c.config.GravityRho, 2.0)
- c.coord = c.coord.ApplyForce(c.config, force, c.origin)
-}
-
-// Update takes other, a coordinate for another node, and rtt, a round trip
-// time observation for a ping to that node, and updates the estimated position of
-// the client's coordinate. Returns the updated coordinate.
-func (c *Client) Update(node string, other *Coordinate, rtt time.Duration) (*Coordinate, error) {
- c.mutex.Lock()
- defer c.mutex.Unlock()
-
- if err := c.checkCoordinate(other); err != nil {
- return nil, err
- }
-
- // The code down below can handle zero RTTs, which we have seen in
- // https://github.com/hashicorp/consul/issues/3789, presumably in
- // environments with coarse-grained monotonic clocks (we are still
- // trying to pin this down). In any event, this is ok from a code PoV
- // so we don't need to alert operators with spammy messages. We did
- // add a counter so this is still observable, though.
- const maxRTT = 10 * time.Second
- if rtt < 0 || rtt > maxRTT {
- return nil, fmt.Errorf("round trip time not in valid range, duration %v is not a positive value less than %v ", rtt, maxRTT)
- }
- if rtt == 0 {
- metrics.IncrCounter([]string{"serf", "coordinate", "zero-rtt"}, 1)
- }
-
- rttSeconds := c.latencyFilter(node, rtt.Seconds())
- c.updateVivaldi(other, rttSeconds)
- c.updateAdjustment(other, rttSeconds)
- c.updateGravity()
- if !c.coord.IsValid() {
- c.stats.Resets++
- c.coord = NewCoordinate(c.config)
- }
-
- return c.coord.Clone(), nil
-}
-
-// DistanceTo returns the estimated RTT from the client's coordinate to other, the
-// coordinate for another node.
-func (c *Client) DistanceTo(other *Coordinate) time.Duration {
- c.mutex.RLock()
- defer c.mutex.RUnlock()
-
- return c.coord.DistanceTo(other)
-}
diff --git a/vendor/github.com/hashicorp/serf/coordinate/config.go b/vendor/github.com/hashicorp/serf/coordinate/config.go
deleted file mode 100644
index b85a8ab7b00..00000000000
--- a/vendor/github.com/hashicorp/serf/coordinate/config.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package coordinate
-
-// Config is used to set the parameters of the Vivaldi-based coordinate mapping
-// algorithm.
-//
-// The following references are called out at various points in the documentation
-// here:
-//
-// [1] Dabek, Frank, et al. "Vivaldi: A decentralized network coordinate system."
-// ACM SIGCOMM Computer Communication Review. Vol. 34. No. 4. ACM, 2004.
-// [2] Ledlie, Jonathan, Paul Gardner, and Margo I. Seltzer. "Network Coordinates
-// in the Wild." NSDI. Vol. 7. 2007.
-// [3] Lee, Sanghwan, et al. "On suitability of Euclidean embedding for
-// host-based network coordinate systems." Networking, IEEE/ACM Transactions
-// on 18.1 (2010): 27-40.
-type Config struct {
- // The dimensionality of the coordinate system. As discussed in [2], more
- // dimensions improves the accuracy of the estimates up to a point. Per [2]
- // we chose 8 dimensions plus a non-Euclidean height.
- Dimensionality uint
-
- // VivaldiErrorMax is the default error value when a node hasn't yet made
- // any observations. It also serves as an upper limit on the error value in
- // case observations cause the error value to increase without bound.
- VivaldiErrorMax float64
-
- // VivaldiCE is a tuning factor that controls the maximum impact an
- // observation can have on a node's confidence. See [1] for more details.
- VivaldiCE float64
-
- // VivaldiCC is a tuning factor that controls the maximum impact an
- // observation can have on a node's coordinate. See [1] for more details.
- VivaldiCC float64
-
- // AdjustmentWindowSize is a tuning factor that determines how many samples
- // we retain to calculate the adjustment factor as discussed in [3]. Setting
- // this to zero disables this feature.
- AdjustmentWindowSize uint
-
- // HeightMin is the minimum value of the height parameter. Since this
- // always must be positive, it will introduce a small amount error, so
- // the chosen value should be relatively small compared to "normal"
- // coordinates.
- HeightMin float64
-
- // LatencyFilterSamples is the maximum number of samples that are retained
- // per node, in order to compute a median. The intent is to ride out blips
- // but still keep the delay low, since our time to probe any given node is
- // pretty infrequent. See [2] for more details.
- LatencyFilterSize uint
-
- // GravityRho is a tuning factor that sets how much gravity has an effect
- // to try to re-center coordinates. See [2] for more details.
- GravityRho float64
-}
-
-// DefaultConfig returns a Config that has some default values suitable for
-// basic testing of the algorithm, but not tuned to any particular type of cluster.
-func DefaultConfig() *Config {
- return &Config{
- Dimensionality: 8,
- VivaldiErrorMax: 1.5,
- VivaldiCE: 0.25,
- VivaldiCC: 0.25,
- AdjustmentWindowSize: 20,
- HeightMin: 10.0e-6,
- LatencyFilterSize: 3,
- GravityRho: 150.0,
- }
-}
diff --git a/vendor/github.com/hashicorp/serf/coordinate/coordinate.go b/vendor/github.com/hashicorp/serf/coordinate/coordinate.go
deleted file mode 100644
index fbe792c90d4..00000000000
--- a/vendor/github.com/hashicorp/serf/coordinate/coordinate.go
+++ /dev/null
@@ -1,203 +0,0 @@
-package coordinate
-
-import (
- "math"
- "math/rand"
- "time"
-)
-
-// Coordinate is a specialized structure for holding network coordinates for the
-// Vivaldi-based coordinate mapping algorithm. All of the fields should be public
-// to enable this to be serialized. All values in here are in units of seconds.
-type Coordinate struct {
- // Vec is the Euclidean portion of the coordinate. This is used along
- // with the other fields to provide an overall distance estimate. The
- // units here are seconds.
- Vec []float64
-
- // Err reflects the confidence in the given coordinate and is updated
- // dynamically by the Vivaldi Client. This is dimensionless.
- Error float64
-
- // Adjustment is a distance offset computed based on a calculation over
- // observations from all other nodes over a fixed window and is updated
- // dynamically by the Vivaldi Client. The units here are seconds.
- Adjustment float64
-
- // Height is a distance offset that accounts for non-Euclidean effects
- // which model the access links from nodes to the core Internet. The access
- // links are usually set by bandwidth and congestion, and the core links
- // usually follow distance based on geography.
- Height float64
-}
-
-const (
- // secondsToNanoseconds is used to convert float seconds to nanoseconds.
- secondsToNanoseconds = 1.0e9
-
- // zeroThreshold is used to decide if two coordinates are on top of each
- // other.
- zeroThreshold = 1.0e-6
-)
-
-// ErrDimensionalityConflict will be panic-d if you try to perform operations
-// with incompatible dimensions.
-type DimensionalityConflictError struct{}
-
-// Adds the error interface.
-func (e DimensionalityConflictError) Error() string {
- return "coordinate dimensionality does not match"
-}
-
-// NewCoordinate creates a new coordinate at the origin, using the given config
-// to supply key initial values.
-func NewCoordinate(config *Config) *Coordinate {
- return &Coordinate{
- Vec: make([]float64, config.Dimensionality),
- Error: config.VivaldiErrorMax,
- Adjustment: 0.0,
- Height: config.HeightMin,
- }
-}
-
-// Clone creates an independent copy of this coordinate.
-func (c *Coordinate) Clone() *Coordinate {
- vec := make([]float64, len(c.Vec))
- copy(vec, c.Vec)
- return &Coordinate{
- Vec: vec,
- Error: c.Error,
- Adjustment: c.Adjustment,
- Height: c.Height,
- }
-}
-
-// componentIsValid returns false if a floating point value is a NaN or an
-// infinity.
-func componentIsValid(f float64) bool {
- return !math.IsInf(f, 0) && !math.IsNaN(f)
-}
-
-// IsValid returns false if any component of a coordinate isn't valid, per the
-// componentIsValid() helper above.
-func (c *Coordinate) IsValid() bool {
- for i := range c.Vec {
- if !componentIsValid(c.Vec[i]) {
- return false
- }
- }
-
- return componentIsValid(c.Error) &&
- componentIsValid(c.Adjustment) &&
- componentIsValid(c.Height)
-}
-
-// IsCompatibleWith checks to see if the two coordinates are compatible
-// dimensionally. If this returns true then you are guaranteed to not get
-// any runtime errors operating on them.
-func (c *Coordinate) IsCompatibleWith(other *Coordinate) bool {
- return len(c.Vec) == len(other.Vec)
-}
-
-// ApplyForce returns the result of applying the force from the direction of the
-// other coordinate.
-func (c *Coordinate) ApplyForce(config *Config, force float64, other *Coordinate) *Coordinate {
- if !c.IsCompatibleWith(other) {
- panic(DimensionalityConflictError{})
- }
-
- ret := c.Clone()
- unit, mag := unitVectorAt(c.Vec, other.Vec)
- ret.Vec = add(ret.Vec, mul(unit, force))
- if mag > zeroThreshold {
- ret.Height = (ret.Height+other.Height)*force/mag + ret.Height
- ret.Height = math.Max(ret.Height, config.HeightMin)
- }
- return ret
-}
-
-// DistanceTo returns the distance between this coordinate and the other
-// coordinate, including adjustments.
-func (c *Coordinate) DistanceTo(other *Coordinate) time.Duration {
- if !c.IsCompatibleWith(other) {
- panic(DimensionalityConflictError{})
- }
-
- dist := c.rawDistanceTo(other)
- adjustedDist := dist + c.Adjustment + other.Adjustment
- if adjustedDist > 0.0 {
- dist = adjustedDist
- }
- return time.Duration(dist * secondsToNanoseconds)
-}
-
-// rawDistanceTo returns the Vivaldi distance between this coordinate and the
-// other coordinate in seconds, not including adjustments. This assumes the
-// dimensions have already been checked to be compatible.
-func (c *Coordinate) rawDistanceTo(other *Coordinate) float64 {
- return magnitude(diff(c.Vec, other.Vec)) + c.Height + other.Height
-}
-
-// add returns the sum of vec1 and vec2. This assumes the dimensions have
-// already been checked to be compatible.
-func add(vec1 []float64, vec2 []float64) []float64 {
- ret := make([]float64, len(vec1))
- for i := range ret {
- ret[i] = vec1[i] + vec2[i]
- }
- return ret
-}
-
-// diff returns the difference between the vec1 and vec2. This assumes the
-// dimensions have already been checked to be compatible.
-func diff(vec1 []float64, vec2 []float64) []float64 {
- ret := make([]float64, len(vec1))
- for i := range ret {
- ret[i] = vec1[i] - vec2[i]
- }
- return ret
-}
-
-// mul returns vec multiplied by a scalar factor.
-func mul(vec []float64, factor float64) []float64 {
- ret := make([]float64, len(vec))
- for i := range vec {
- ret[i] = vec[i] * factor
- }
- return ret
-}
-
-// magnitude computes the magnitude of the vec.
-func magnitude(vec []float64) float64 {
- sum := 0.0
- for i := range vec {
- sum += vec[i] * vec[i]
- }
- return math.Sqrt(sum)
-}
-
-// unitVectorAt returns a unit vector pointing at vec1 from vec2. If the two
-// positions are the same then a random unit vector is returned. We also return
-// the distance between the points for use in the later height calculation.
-func unitVectorAt(vec1 []float64, vec2 []float64) ([]float64, float64) {
- ret := diff(vec1, vec2)
-
- // If the coordinates aren't on top of each other we can normalize.
- if mag := magnitude(ret); mag > zeroThreshold {
- return mul(ret, 1.0/mag), mag
- }
-
- // Otherwise, just return a random unit vector.
- for i := range ret {
- ret[i] = rand.Float64() - 0.5
- }
- if mag := magnitude(ret); mag > zeroThreshold {
- return mul(ret, 1.0/mag), 0.0
- }
-
- // And finally just give up and make a unit vector along the first
- // dimension. This should be exceedingly rare.
- ret = make([]float64, len(ret))
- ret[0] = 1.0
- return ret, 0.0
-}
diff --git a/vendor/github.com/hashicorp/serf/coordinate/phantom.go b/vendor/github.com/hashicorp/serf/coordinate/phantom.go
deleted file mode 100644
index 6fb033c0cd3..00000000000
--- a/vendor/github.com/hashicorp/serf/coordinate/phantom.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package coordinate
-
-import (
- "fmt"
- "math"
- "math/rand"
- "time"
-)
-
-// GenerateClients returns a slice with nodes number of clients, all with the
-// given config.
-func GenerateClients(nodes int, config *Config) ([]*Client, error) {
- clients := make([]*Client, nodes)
- for i, _ := range clients {
- client, err := NewClient(config)
- if err != nil {
- return nil, err
- }
-
- clients[i] = client
- }
- return clients, nil
-}
-
-// GenerateLine returns a truth matrix as if all the nodes are in a straight linke
-// with the given spacing between them.
-func GenerateLine(nodes int, spacing time.Duration) [][]time.Duration {
- truth := make([][]time.Duration, nodes)
- for i := range truth {
- truth[i] = make([]time.Duration, nodes)
- }
-
- for i := 0; i < nodes; i++ {
- for j := i + 1; j < nodes; j++ {
- rtt := time.Duration(j-i) * spacing
- truth[i][j], truth[j][i] = rtt, rtt
- }
- }
- return truth
-}
-
-// GenerateGrid returns a truth matrix as if all the nodes are in a two dimensional
-// grid with the given spacing between them.
-func GenerateGrid(nodes int, spacing time.Duration) [][]time.Duration {
- truth := make([][]time.Duration, nodes)
- for i := range truth {
- truth[i] = make([]time.Duration, nodes)
- }
-
- n := int(math.Sqrt(float64(nodes)))
- for i := 0; i < nodes; i++ {
- for j := i + 1; j < nodes; j++ {
- x1, y1 := float64(i%n), float64(i/n)
- x2, y2 := float64(j%n), float64(j/n)
- dx, dy := x2-x1, y2-y1
- dist := math.Sqrt(dx*dx + dy*dy)
- rtt := time.Duration(dist * float64(spacing))
- truth[i][j], truth[j][i] = rtt, rtt
- }
- }
- return truth
-}
-
-// GenerateSplit returns a truth matrix as if half the nodes are close together in
-// one location and half the nodes are close together in another. The lan factor
-// is used to separate the nodes locally and the wan factor represents the split
-// between the two sides.
-func GenerateSplit(nodes int, lan time.Duration, wan time.Duration) [][]time.Duration {
- truth := make([][]time.Duration, nodes)
- for i := range truth {
- truth[i] = make([]time.Duration, nodes)
- }
-
- split := nodes / 2
- for i := 0; i < nodes; i++ {
- for j := i + 1; j < nodes; j++ {
- rtt := lan
- if (i <= split && j > split) || (i > split && j <= split) {
- rtt += wan
- }
- truth[i][j], truth[j][i] = rtt, rtt
- }
- }
- return truth
-}
-
-// GenerateCircle returns a truth matrix for a set of nodes, evenly distributed
-// around a circle with the given radius. The first node is at the "center" of the
-// circle because it's equidistant from all the other nodes, but we place it at
-// double the radius, so it should show up above all the other nodes in height.
-func GenerateCircle(nodes int, radius time.Duration) [][]time.Duration {
- truth := make([][]time.Duration, nodes)
- for i := range truth {
- truth[i] = make([]time.Duration, nodes)
- }
-
- for i := 0; i < nodes; i++ {
- for j := i + 1; j < nodes; j++ {
- var rtt time.Duration
- if i == 0 {
- rtt = 2 * radius
- } else {
- t1 := 2.0 * math.Pi * float64(i) / float64(nodes)
- x1, y1 := math.Cos(t1), math.Sin(t1)
- t2 := 2.0 * math.Pi * float64(j) / float64(nodes)
- x2, y2 := math.Cos(t2), math.Sin(t2)
- dx, dy := x2-x1, y2-y1
- dist := math.Sqrt(dx*dx + dy*dy)
- rtt = time.Duration(dist * float64(radius))
- }
- truth[i][j], truth[j][i] = rtt, rtt
- }
- }
- return truth
-}
-
-// GenerateRandom returns a truth matrix for a set of nodes with normally
-// distributed delays, with the given mean and deviation. The RNG is re-seeded
-// so you always get the same matrix for a given size.
-func GenerateRandom(nodes int, mean time.Duration, deviation time.Duration) [][]time.Duration {
- rand.Seed(1)
-
- truth := make([][]time.Duration, nodes)
- for i := range truth {
- truth[i] = make([]time.Duration, nodes)
- }
-
- for i := 0; i < nodes; i++ {
- for j := i + 1; j < nodes; j++ {
- rttSeconds := rand.NormFloat64()*deviation.Seconds() + mean.Seconds()
- rtt := time.Duration(rttSeconds * secondsToNanoseconds)
- truth[i][j], truth[j][i] = rtt, rtt
- }
- }
- return truth
-}
-
-// Simulate runs the given number of cycles using the given list of clients and
-// truth matrix. On each cycle, each client will pick a random node and observe
-// the truth RTT, updating its coordinate estimate. The RNG is re-seeded for
-// each simulation run to get deterministic results (for this algorithm and the
-// underlying algorithm which will use random numbers for position vectors when
-// starting out with everything at the origin).
-func Simulate(clients []*Client, truth [][]time.Duration, cycles int) {
- rand.Seed(1)
-
- nodes := len(clients)
- for cycle := 0; cycle < cycles; cycle++ {
- for i, _ := range clients {
- if j := rand.Intn(nodes); j != i {
- c := clients[j].GetCoordinate()
- rtt := truth[i][j]
- node := fmt.Sprintf("node_%d", j)
- clients[i].Update(node, c, rtt)
- }
- }
- }
-}
-
-// Stats is returned from the Evaluate function with a summary of the algorithm
-// performance.
-type Stats struct {
- ErrorMax float64
- ErrorAvg float64
-}
-
-// Evaluate uses the coordinates of the given clients to calculate estimated
-// distances and compares them with the given truth matrix, returning summary
-// stats.
-func Evaluate(clients []*Client, truth [][]time.Duration) (stats Stats) {
- nodes := len(clients)
- count := 0
- for i := 0; i < nodes; i++ {
- for j := i + 1; j < nodes; j++ {
- est := clients[i].DistanceTo(clients[j].GetCoordinate()).Seconds()
- actual := truth[i][j].Seconds()
- error := math.Abs(est-actual) / actual
- stats.ErrorMax = math.Max(stats.ErrorMax, error)
- stats.ErrorAvg += error
- count += 1
- }
- }
-
- stats.ErrorAvg /= float64(count)
- fmt.Printf("Error avg=%9.6f max=%9.6f\n", stats.ErrorAvg, stats.ErrorMax)
- return
-}
diff --git a/vendor/github.com/hashicorp/vault/api/LICENSE b/vendor/github.com/hashicorp/vault/api/LICENSE
deleted file mode 100644
index e87a115e462..00000000000
--- a/vendor/github.com/hashicorp/vault/api/LICENSE
+++ /dev/null
@@ -1,363 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. "Contributor"
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the terms of
- a Secondary License.
-
-1.6. "Executable Form"
-
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-
- means a work that combines Covered Software with other material, in a
- separate file or files, that is not Covered Software.
-
-1.8. "License"
-
- means this document.
-
-1.9. "Licensable"
-
- means having the right to grant, to the maximum extent possible, whether
- at the time of the initial grant or subsequently, any and all of the
- rights conveyed by this License.
-
-1.10. "Modifications"
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. "Patent Claims" of a Contributor
-
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the License,
- by the making, using, selling, offering for sale, having made, import,
- or transfer of either its Contributions or its Contributor Version.
-
-1.12. "Secondary License"
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. "Source Code Form"
-
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, "control" means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution
- become effective for each Contribution on the date the Contributor first
- distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under
- this License. No additional rights or licenses will be implied from the
- distribution or licensing of Covered Software under this License.
- Notwithstanding Section 2.1(b) above, no patent license is granted by a
- Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
- This License does not grant any rights in the trademarks, service marks,
- or logos of any Contributor (except as may be necessary to comply with
- the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this
- License (see Section 10.2) or under the terms of a Secondary License (if
- permitted under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its
- Contributions are its original creation(s) or it has sufficient rights to
- grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under
- applicable copyright doctrines of fair use, fair dealing, or other
- equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under
- the terms of this License. You must inform recipients that the Source
- Code Form of the Covered Software is governed by the terms of this
- License, and how they can obtain a copy of this License. You may not
- attempt to alter or restrict the recipients' rights in the Source Code
- Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter the
- recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for
- the Covered Software. If the Larger Work is a combination of Covered
- Software with a work governed by one or more Secondary Licenses, and the
- Covered Software is not Incompatible With Secondary Licenses, this
- License permits You to additionally distribute such Covered Software
- under the terms of such Secondary License(s), so that the recipient of
- the Larger Work may, at their option, further distribute the Covered
- Software under the terms of either this License or such Secondary
- License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices
- (including copyright notices, patent notices, disclaimers of warranty, or
- limitations of liability) contained within the Source Code Form of the
- Covered Software, except that You may alter any license notices to the
- extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on
- behalf of any Contributor. You must make it absolutely clear that any
- such warranty, support, indemnity, or liability obligation is offered by
- You alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute,
- judicial order, or regulation then You must: (a) comply with the terms of
- this License to the maximum extent possible; and (b) describe the
- limitations and the code they affect. Such description must be placed in a
- text file included with all distributions of the Covered Software under
- this License. Except to the extent prohibited by statute or regulation,
- such description must be sufficiently detailed for a recipient of ordinary
- skill to be able to understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing
- basis, if such Contributor fails to notify You of the non-compliance by
- some reasonable means prior to 60 days after You have come back into
- compliance. Moreover, Your grants from a particular Contributor are
- reinstated on an ongoing basis if such Contributor notifies You of the
- non-compliance by some reasonable means, this is the first time You have
- received notice of non-compliance with this License from such
- Contributor, and You become compliant prior to 30 days after Your receipt
- of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions,
- counter-claims, and cross-claims) alleging that a Contributor Version
- directly or indirectly infringes any patent, then the rights granted to
- You by any and all Contributors for the Covered Software under Section
- 2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an "as is" basis,
- without warranty of any kind, either expressed, implied, or statutory,
- including, without limitation, warranties that the Covered Software is free
- of defects, merchantable, fit for a particular purpose or non-infringing.
- The entire risk as to the quality and performance of the Covered Software
- is with You. Should any Covered Software prove defective in any respect,
- You (not any Contributor) assume the cost of any necessary servicing,
- repair, or correction. This disclaimer of warranty constitutes an essential
- part of this License. No use of any Covered Software is authorized under
- this License except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from
- such party's negligence to the extent applicable law prohibits such
- limitation. Some jurisdictions do not allow the exclusion or limitation of
- incidental or consequential damages, so this exclusion and limitation may
- not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts
- of a jurisdiction where the defendant maintains its principal place of
- business and such litigation shall be governed by laws of that
- jurisdiction, without reference to its conflict-of-law provisions. Nothing
- in this Section shall prevent a party's ability to bring cross-claims or
- counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. Any law or regulation which provides that
- the language of a contract shall be construed against the drafter shall not
- be used to construe this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version
- of the License under which You originally received the Covered Software,
- or under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a
- modified version of this License if you rename the license and remove
- any references to the name of the license steward (except to note that
- such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
- Licenses If You choose to distribute Source Code Form that is
- Incompatible With Secondary Licenses under the terms of this version of
- the License, the notice described in Exhibit B of this License must be
- attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file,
-then You may include the notice in a location (such as a LICENSE file in a
-relevant directory) where a recipient would be likely to look for such a
-notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
-
- This Source Code Form is "Incompatible
- With Secondary Licenses", as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/vault/api/auth.go b/vendor/github.com/hashicorp/vault/api/auth.go
deleted file mode 100644
index da870c111cc..00000000000
--- a/vendor/github.com/hashicorp/vault/api/auth.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package api
-
-// Auth is used to perform credential backend related operations.
-type Auth struct {
- c *Client
-}
-
-// Auth is used to return the client for credential-backend API calls.
-func (c *Client) Auth() *Auth {
- return &Auth{c: c}
-}
diff --git a/vendor/github.com/hashicorp/vault/api/auth_token.go b/vendor/github.com/hashicorp/vault/api/auth_token.go
deleted file mode 100644
index 6807c89c387..00000000000
--- a/vendor/github.com/hashicorp/vault/api/auth_token.go
+++ /dev/null
@@ -1,276 +0,0 @@
-package api
-
-import "context"
-
-// TokenAuth is used to perform token backend operations on Vault
-type TokenAuth struct {
- c *Client
-}
-
-// Token is used to return the client for token-backend API calls
-func (a *Auth) Token() *TokenAuth {
- return &TokenAuth{c: a.c}
-}
-
-func (c *TokenAuth) Create(opts *TokenCreateRequest) (*Secret, error) {
- r := c.c.NewRequest("POST", "/v1/auth/token/create")
- if err := r.SetJSONBody(opts); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-func (c *TokenAuth) CreateOrphan(opts *TokenCreateRequest) (*Secret, error) {
- r := c.c.NewRequest("POST", "/v1/auth/token/create-orphan")
- if err := r.SetJSONBody(opts); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-func (c *TokenAuth) CreateWithRole(opts *TokenCreateRequest, roleName string) (*Secret, error) {
- r := c.c.NewRequest("POST", "/v1/auth/token/create/"+roleName)
- if err := r.SetJSONBody(opts); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-func (c *TokenAuth) Lookup(token string) (*Secret, error) {
- r := c.c.NewRequest("POST", "/v1/auth/token/lookup")
- if err := r.SetJSONBody(map[string]interface{}{
- "token": token,
- }); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-func (c *TokenAuth) LookupAccessor(accessor string) (*Secret, error) {
- r := c.c.NewRequest("POST", "/v1/auth/token/lookup-accessor")
- if err := r.SetJSONBody(map[string]interface{}{
- "accessor": accessor,
- }); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-func (c *TokenAuth) LookupSelf() (*Secret, error) {
- r := c.c.NewRequest("GET", "/v1/auth/token/lookup-self")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-func (c *TokenAuth) Renew(token string, increment int) (*Secret, error) {
- r := c.c.NewRequest("PUT", "/v1/auth/token/renew")
- if err := r.SetJSONBody(map[string]interface{}{
- "token": token,
- "increment": increment,
- }); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-func (c *TokenAuth) RenewSelf(increment int) (*Secret, error) {
- r := c.c.NewRequest("PUT", "/v1/auth/token/renew-self")
-
- body := map[string]interface{}{"increment": increment}
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-// RenewTokenAsSelf behaves like renew-self, but authenticates using a provided
-// token instead of the token attached to the client.
-func (c *TokenAuth) RenewTokenAsSelf(token string, increment int) (*Secret, error) {
- r := c.c.NewRequest("PUT", "/v1/auth/token/renew-self")
- r.ClientToken = token
-
- body := map[string]interface{}{"increment": increment}
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-// RevokeAccessor revokes a token associated with the given accessor
-// along with all the child tokens.
-func (c *TokenAuth) RevokeAccessor(accessor string) error {
- r := c.c.NewRequest("POST", "/v1/auth/token/revoke-accessor")
- if err := r.SetJSONBody(map[string]interface{}{
- "accessor": accessor,
- }); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return nil
-}
-
-// RevokeOrphan revokes a token without revoking the tree underneath it (so
-// child tokens are orphaned rather than revoked)
-func (c *TokenAuth) RevokeOrphan(token string) error {
- r := c.c.NewRequest("PUT", "/v1/auth/token/revoke-orphan")
- if err := r.SetJSONBody(map[string]interface{}{
- "token": token,
- }); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return nil
-}
-
-// RevokeSelf revokes the token making the call. The `token` parameter is kept
-// for backwards compatibility but is ignored; only the client's set token has
-// an effect.
-func (c *TokenAuth) RevokeSelf(token string) error {
- r := c.c.NewRequest("PUT", "/v1/auth/token/revoke-self")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return nil
-}
-
-// RevokeTree is the "normal" revoke operation that revokes the given token and
-// the entire tree underneath -- all of its child tokens, their child tokens,
-// etc.
-func (c *TokenAuth) RevokeTree(token string) error {
- r := c.c.NewRequest("PUT", "/v1/auth/token/revoke")
- if err := r.SetJSONBody(map[string]interface{}{
- "token": token,
- }); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return nil
-}
-
-// TokenCreateRequest is the options structure for creating a token.
-type TokenCreateRequest struct {
- ID string `json:"id,omitempty"`
- Policies []string `json:"policies,omitempty"`
- Metadata map[string]string `json:"meta,omitempty"`
- Lease string `json:"lease,omitempty"`
- TTL string `json:"ttl,omitempty"`
- ExplicitMaxTTL string `json:"explicit_max_ttl,omitempty"`
- Period string `json:"period,omitempty"`
- NoParent bool `json:"no_parent,omitempty"`
- NoDefaultPolicy bool `json:"no_default_policy,omitempty"`
- DisplayName string `json:"display_name"`
- NumUses int `json:"num_uses"`
- Renewable *bool `json:"renewable,omitempty"`
- Type string `json:"type"`
- EntityAlias string `json:"entity_alias"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/client.go b/vendor/github.com/hashicorp/vault/api/client.go
deleted file mode 100644
index fb50f207398..00000000000
--- a/vendor/github.com/hashicorp/vault/api/client.go
+++ /dev/null
@@ -1,850 +0,0 @@
-package api
-
-import (
- "context"
- "crypto/tls"
- "fmt"
- "net"
- "net/http"
- "net/url"
- "os"
- "path"
- "strconv"
- "strings"
- "sync"
- "time"
- "unicode"
-
- "github.com/hashicorp/errwrap"
- cleanhttp "github.com/hashicorp/go-cleanhttp"
- retryablehttp "github.com/hashicorp/go-retryablehttp"
- rootcerts "github.com/hashicorp/go-rootcerts"
- "github.com/hashicorp/vault/sdk/helper/consts"
- "github.com/hashicorp/vault/sdk/helper/parseutil"
- "golang.org/x/net/http2"
- "golang.org/x/time/rate"
-)
-
-const EnvVaultAddress = "VAULT_ADDR"
-const EnvVaultAgentAddr = "VAULT_AGENT_ADDR"
-const EnvVaultCACert = "VAULT_CACERT"
-const EnvVaultCAPath = "VAULT_CAPATH"
-const EnvVaultClientCert = "VAULT_CLIENT_CERT"
-const EnvVaultClientKey = "VAULT_CLIENT_KEY"
-const EnvVaultClientTimeout = "VAULT_CLIENT_TIMEOUT"
-const EnvVaultSkipVerify = "VAULT_SKIP_VERIFY"
-const EnvVaultNamespace = "VAULT_NAMESPACE"
-const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
-const EnvVaultWrapTTL = "VAULT_WRAP_TTL"
-const EnvVaultMaxRetries = "VAULT_MAX_RETRIES"
-const EnvVaultToken = "VAULT_TOKEN"
-const EnvVaultMFA = "VAULT_MFA"
-const EnvRateLimit = "VAULT_RATE_LIMIT"
-
-// Deprecated values
-const EnvVaultAgentAddress = "VAULT_AGENT_ADDR"
-const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
-
-// WrappingLookupFunc is a function that, given an HTTP verb and a path,
-// returns an optional string duration to be used for response wrapping (e.g.
-// "15s", or simply "15"). The path will not begin with "/v1/" or "v1/" or "/",
-// however, end-of-path forward slashes are not trimmed, so must match your
-// called path precisely.
-type WrappingLookupFunc func(operation, path string) string
-
-// Config is used to configure the creation of the client.
-type Config struct {
- modifyLock sync.RWMutex
-
- // Address is the address of the Vault server. This should be a complete
- // URL such as "http://vault.example.com". If you need a custom SSL
- // cert or want to enable insecure mode, you need to specify a custom
- // HttpClient.
- Address string
-
- // AgentAddress is the address of the local Vault agent. This should be a
- // complete URL such as "http://vault.example.com".
- AgentAddress string
-
- // HttpClient is the HTTP client to use. Vault sets sane defaults for the
- // http.Client and its associated http.Transport created in DefaultConfig.
- // If you must modify Vault's defaults, it is suggested that you start with
- // that client and modify as needed rather than start with an empty client
- // (or http.DefaultClient).
- HttpClient *http.Client
-
- // MaxRetries controls the maximum number of times to retry when a 5xx
- // error occurs. Set to 0 to disable retrying. Defaults to 2 (for a total
- // of three tries).
- MaxRetries int
-
- // Timeout is for setting custom timeout parameter in the HttpClient
- Timeout time.Duration
-
- // If there is an error when creating the configuration, this will be the
- // error
- Error error
-
- // The Backoff function to use; a default is used if not provided
- Backoff retryablehttp.Backoff
-
- // Limiter is the rate limiter used by the client.
- // If this pointer is nil, then there will be no limit set.
- // In contrast, if this pointer is set, even to an empty struct,
- // then that limiter will be used. Note that an empty Limiter
- // is equivalent blocking all events.
- Limiter *rate.Limiter
-
- // OutputCurlString causes the actual request to return an error of type
- // *OutputStringError. Type asserting the error message will allow
- // fetching a cURL-compatible string for the operation.
- //
- // Note: It is not thread-safe to set this and make concurrent requests
- // with the same client. Cloning a client will not clone this value.
- OutputCurlString bool
-}
-
-// TLSConfig contains the parameters needed to configure TLS on the HTTP client
-// used to communicate with Vault.
-type TLSConfig struct {
- // CACert is the path to a PEM-encoded CA cert file to use to verify the
- // Vault server SSL certificate.
- CACert string
-
- // CAPath is the path to a directory of PEM-encoded CA cert files to verify
- // the Vault server SSL certificate.
- CAPath string
-
- // ClientCert is the path to the certificate for Vault communication
- ClientCert string
-
- // ClientKey is the path to the private key for Vault communication
- ClientKey string
-
- // TLSServerName, if set, is used to set the SNI host when connecting via
- // TLS.
- TLSServerName string
-
- // Insecure enables or disables SSL verification
- Insecure bool
-}
-
-// DefaultConfig returns a default configuration for the client. It is
-// safe to modify the return value of this function.
-//
-// The default Address is https://127.0.0.1:8200, but this can be overridden by
-// setting the `VAULT_ADDR` environment variable.
-//
-// If an error is encountered, this will return nil.
-func DefaultConfig() *Config {
- config := &Config{
- Address: "https://127.0.0.1:8200",
- HttpClient: cleanhttp.DefaultPooledClient(),
- }
- config.HttpClient.Timeout = time.Second * 60
-
- transport := config.HttpClient.Transport.(*http.Transport)
- transport.TLSHandshakeTimeout = 10 * time.Second
- transport.TLSClientConfig = &tls.Config{
- MinVersion: tls.VersionTLS12,
- }
- if err := http2.ConfigureTransport(transport); err != nil {
- config.Error = err
- return config
- }
-
- if err := config.ReadEnvironment(); err != nil {
- config.Error = err
- return config
- }
-
- // Ensure redirects are not automatically followed
- // Note that this is sane for the API client as it has its own
- // redirect handling logic (and thus also for command/meta),
- // but in e.g. http_test actual redirect handling is necessary
- config.HttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
- // Returning this value causes the Go net library to not close the
- // response body and to nil out the error. Otherwise retry clients may
- // try three times on every redirect because it sees an error from this
- // function (to prevent redirects) passing through to it.
- return http.ErrUseLastResponse
- }
-
- config.Backoff = retryablehttp.LinearJitterBackoff
- config.MaxRetries = 2
-
- return config
-}
-
-// ConfigureTLS takes a set of TLS configurations and applies those to the the
-// HTTP client.
-func (c *Config) ConfigureTLS(t *TLSConfig) error {
- if c.HttpClient == nil {
- c.HttpClient = DefaultConfig().HttpClient
- }
- clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
-
- var clientCert tls.Certificate
- foundClientCert := false
-
- switch {
- case t.ClientCert != "" && t.ClientKey != "":
- var err error
- clientCert, err = tls.LoadX509KeyPair(t.ClientCert, t.ClientKey)
- if err != nil {
- return err
- }
- foundClientCert = true
- case t.ClientCert != "" || t.ClientKey != "":
- return fmt.Errorf("both client cert and client key must be provided")
- }
-
- if t.CACert != "" || t.CAPath != "" {
- rootConfig := &rootcerts.Config{
- CAFile: t.CACert,
- CAPath: t.CAPath,
- }
- if err := rootcerts.ConfigureTLS(clientTLSConfig, rootConfig); err != nil {
- return err
- }
- }
-
- if t.Insecure {
- clientTLSConfig.InsecureSkipVerify = true
- }
-
- if foundClientCert {
- // We use this function to ignore the server's preferential list of
- // CAs, otherwise any CA used for the cert auth backend must be in the
- // server's CA pool
- clientTLSConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
- return &clientCert, nil
- }
- }
-
- if t.TLSServerName != "" {
- clientTLSConfig.ServerName = t.TLSServerName
- }
-
- return nil
-}
-
-// ReadEnvironment reads configuration information from the environment. If
-// there is an error, no configuration value is updated.
-func (c *Config) ReadEnvironment() error {
- var envAddress string
- var envAgentAddress string
- var envCACert string
- var envCAPath string
- var envClientCert string
- var envClientKey string
- var envClientTimeout time.Duration
- var envInsecure bool
- var envTLSServerName string
- var envMaxRetries *uint64
- var limit *rate.Limiter
-
- // Parse the environment variables
- if v := os.Getenv(EnvVaultAddress); v != "" {
- envAddress = v
- }
- if v := os.Getenv(EnvVaultAgentAddr); v != "" {
- envAgentAddress = v
- } else if v := os.Getenv(EnvVaultAgentAddress); v != "" {
- envAgentAddress = v
- }
- if v := os.Getenv(EnvVaultMaxRetries); v != "" {
- maxRetries, err := strconv.ParseUint(v, 10, 32)
- if err != nil {
- return err
- }
- envMaxRetries = &maxRetries
- }
- if v := os.Getenv(EnvVaultCACert); v != "" {
- envCACert = v
- }
- if v := os.Getenv(EnvVaultCAPath); v != "" {
- envCAPath = v
- }
- if v := os.Getenv(EnvVaultClientCert); v != "" {
- envClientCert = v
- }
- if v := os.Getenv(EnvVaultClientKey); v != "" {
- envClientKey = v
- }
- if v := os.Getenv(EnvRateLimit); v != "" {
- rateLimit, burstLimit, err := parseRateLimit(v)
- if err != nil {
- return err
- }
- limit = rate.NewLimiter(rate.Limit(rateLimit), burstLimit)
- }
- if t := os.Getenv(EnvVaultClientTimeout); t != "" {
- clientTimeout, err := parseutil.ParseDurationSecond(t)
- if err != nil {
- return fmt.Errorf("could not parse %q", EnvVaultClientTimeout)
- }
- envClientTimeout = clientTimeout
- }
- if v := os.Getenv(EnvVaultSkipVerify); v != "" {
- var err error
- envInsecure, err = strconv.ParseBool(v)
- if err != nil {
- return fmt.Errorf("could not parse VAULT_SKIP_VERIFY")
- }
- } else if v := os.Getenv(EnvVaultInsecure); v != "" {
- var err error
- envInsecure, err = strconv.ParseBool(v)
- if err != nil {
- return fmt.Errorf("could not parse VAULT_INSECURE")
- }
- }
-
- if v := os.Getenv(EnvVaultTLSServerName); v != "" {
- envTLSServerName = v
- }
-
- // Configure the HTTP clients TLS configuration.
- t := &TLSConfig{
- CACert: envCACert,
- CAPath: envCAPath,
- ClientCert: envClientCert,
- ClientKey: envClientKey,
- TLSServerName: envTLSServerName,
- Insecure: envInsecure,
- }
-
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
-
- c.Limiter = limit
-
- if err := c.ConfigureTLS(t); err != nil {
- return err
- }
-
- if envAddress != "" {
- c.Address = envAddress
- }
-
- if envAgentAddress != "" {
- c.AgentAddress = envAgentAddress
- }
-
- if envMaxRetries != nil {
- c.MaxRetries = int(*envMaxRetries)
- }
-
- if envClientTimeout != 0 {
- c.Timeout = envClientTimeout
- }
-
- return nil
-}
-
-func parseRateLimit(val string) (rate float64, burst int, err error) {
-
- _, err = fmt.Sscanf(val, "%f:%d", &rate, &burst)
- if err != nil {
- rate, err = strconv.ParseFloat(val, 64)
- if err != nil {
- err = fmt.Errorf("%v was provided but incorrectly formatted", EnvRateLimit)
- }
- burst = int(rate)
- }
-
- return rate, burst, err
-
-}
-
-// Client is the client to the Vault API. Create a client with NewClient.
-type Client struct {
- modifyLock sync.RWMutex
- addr *url.URL
- config *Config
- token string
- headers http.Header
- wrappingLookupFunc WrappingLookupFunc
- mfaCreds []string
- policyOverride bool
-}
-
-// NewClient returns a new client for the given configuration.
-//
-// If the configuration is nil, Vault will use configuration from
-// DefaultConfig(), which is the recommended starting configuration.
-//
-// If the environment variable `VAULT_TOKEN` is present, the token will be
-// automatically added to the client. Otherwise, you must manually call
-// `SetToken()`.
-func NewClient(c *Config) (*Client, error) {
- def := DefaultConfig()
- if def == nil {
- return nil, fmt.Errorf("could not create/read default configuration")
- }
- if def.Error != nil {
- return nil, errwrap.Wrapf("error encountered setting up default configuration: {{err}}", def.Error)
- }
-
- if c == nil {
- c = def
- }
-
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
-
- if c.HttpClient == nil {
- c.HttpClient = def.HttpClient
- }
- if c.HttpClient.Transport == nil {
- c.HttpClient.Transport = def.HttpClient.Transport
- }
-
- address := c.Address
- if c.AgentAddress != "" {
- address = c.AgentAddress
- }
-
- u, err := url.Parse(address)
- if err != nil {
- return nil, err
- }
-
- if strings.HasPrefix(address, "unix://") {
- socket := strings.TrimPrefix(address, "unix://")
- transport := c.HttpClient.Transport.(*http.Transport)
- transport.DialContext = func(context.Context, string, string) (net.Conn, error) {
- return net.Dial("unix", socket)
- }
-
- // Since the address points to a unix domain socket, the scheme in the
- // *URL would be set to `unix`. The *URL in the client is expected to
- // be pointing to the protocol used in the application layer and not to
- // the transport layer. Hence, setting the fields accordingly.
- u.Scheme = "http"
- u.Host = socket
- u.Path = ""
- }
-
- client := &Client{
- addr: u,
- config: c,
- }
-
- if token := os.Getenv(EnvVaultToken); token != "" {
- client.token = token
- }
-
- if namespace := os.Getenv(EnvVaultNamespace); namespace != "" {
- client.setNamespace(namespace)
- }
-
- return client, nil
-}
-
-// Sets the address of Vault in the client. The format of address should be
-// "://:". Setting this on a client will override the
-// value of VAULT_ADDR environment variable.
-func (c *Client) SetAddress(addr string) error {
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
-
- parsedAddr, err := url.Parse(addr)
- if err != nil {
- return errwrap.Wrapf("failed to set address: {{err}}", err)
- }
-
- c.addr = parsedAddr
- return nil
-}
-
-// Address returns the Vault URL the client is configured to connect to
-func (c *Client) Address() string {
- c.modifyLock.RLock()
- defer c.modifyLock.RUnlock()
-
- return c.addr.String()
-}
-
-// SetLimiter will set the rate limiter for this client.
-// This method is thread-safe.
-// rateLimit and burst are specified according to https://godoc.org/golang.org/x/time/rate#NewLimiter
-func (c *Client) SetLimiter(rateLimit float64, burst int) {
- c.modifyLock.RLock()
- c.config.modifyLock.Lock()
- defer c.config.modifyLock.Unlock()
- c.modifyLock.RUnlock()
-
- c.config.Limiter = rate.NewLimiter(rate.Limit(rateLimit), burst)
-}
-
-// SetMaxRetries sets the number of retries that will be used in the case of certain errors
-func (c *Client) SetMaxRetries(retries int) {
- c.modifyLock.RLock()
- c.config.modifyLock.Lock()
- defer c.config.modifyLock.Unlock()
- c.modifyLock.RUnlock()
-
- c.config.MaxRetries = retries
-}
-
-// SetClientTimeout sets the client request timeout
-func (c *Client) SetClientTimeout(timeout time.Duration) {
- c.modifyLock.RLock()
- c.config.modifyLock.Lock()
- defer c.config.modifyLock.Unlock()
- c.modifyLock.RUnlock()
-
- c.config.Timeout = timeout
-}
-
-func (c *Client) OutputCurlString() bool {
- c.modifyLock.RLock()
- c.config.modifyLock.RLock()
- defer c.config.modifyLock.RUnlock()
- c.modifyLock.RUnlock()
-
- return c.config.OutputCurlString
-}
-
-func (c *Client) SetOutputCurlString(curl bool) {
- c.modifyLock.RLock()
- c.config.modifyLock.Lock()
- defer c.config.modifyLock.Unlock()
- c.modifyLock.RUnlock()
-
- c.config.OutputCurlString = curl
-}
-
-// CurrentWrappingLookupFunc sets a lookup function that returns desired wrap TTLs
-// for a given operation and path
-func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc {
- c.modifyLock.RLock()
- defer c.modifyLock.RUnlock()
-
- return c.wrappingLookupFunc
-}
-
-// SetWrappingLookupFunc sets a lookup function that returns desired wrap TTLs
-// for a given operation and path
-func (c *Client) SetWrappingLookupFunc(lookupFunc WrappingLookupFunc) {
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
-
- c.wrappingLookupFunc = lookupFunc
-}
-
-// SetMFACreds sets the MFA credentials supplied either via the environment
-// variable or via the command line.
-func (c *Client) SetMFACreds(creds []string) {
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
-
- c.mfaCreds = creds
-}
-
-// SetNamespace sets the namespace supplied either via the environment
-// variable or via the command line.
-func (c *Client) SetNamespace(namespace string) {
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
- c.setNamespace(namespace)
-}
-
-func (c *Client) setNamespace(namespace string) {
- if c.headers == nil {
- c.headers = make(http.Header)
- }
-
- c.headers.Set(consts.NamespaceHeaderName, namespace)
-}
-
-// Token returns the access token being used by this client. It will
-// return the empty string if there is no token set.
-func (c *Client) Token() string {
- c.modifyLock.RLock()
- defer c.modifyLock.RUnlock()
-
- return c.token
-}
-
-// SetToken sets the token directly. This won't perform any auth
-// verification, it simply sets the token properly for future requests.
-func (c *Client) SetToken(v string) {
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
-
- c.token = v
-}
-
-// ClearToken deletes the token if it is set or does nothing otherwise.
-func (c *Client) ClearToken() {
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
-
- c.token = ""
-}
-
-// Headers gets the current set of headers used for requests. This returns a
-// copy; to modify it make modifications locally and use SetHeaders.
-func (c *Client) Headers() http.Header {
- c.modifyLock.RLock()
- defer c.modifyLock.RUnlock()
-
- if c.headers == nil {
- return nil
- }
-
- ret := make(http.Header)
- for k, v := range c.headers {
- for _, val := range v {
- ret[k] = append(ret[k], val)
- }
- }
-
- return ret
-}
-
-// SetHeaders sets the headers to be used for future requests.
-func (c *Client) SetHeaders(headers http.Header) {
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
-
- c.headers = headers
-}
-
-// SetBackoff sets the backoff function to be used for future requests.
-func (c *Client) SetBackoff(backoff retryablehttp.Backoff) {
- c.modifyLock.RLock()
- c.config.modifyLock.Lock()
- defer c.config.modifyLock.Unlock()
- c.modifyLock.RUnlock()
-
- c.config.Backoff = backoff
-}
-
-// Clone creates a new client with the same configuration. Note that the same
-// underlying http.Client is used; modifying the client from more than one
-// goroutine at once may not be safe, so modify the client as needed and then
-// clone.
-//
-// Also, only the client's config is currently copied; this means items not in
-// the api.Config struct, such as policy override and wrapping function
-// behavior, must currently then be set as desired on the new client.
-func (c *Client) Clone() (*Client, error) {
- c.modifyLock.RLock()
- c.config.modifyLock.RLock()
- config := c.config
- c.modifyLock.RUnlock()
-
- newConfig := &Config{
- Address: config.Address,
- HttpClient: config.HttpClient,
- MaxRetries: config.MaxRetries,
- Timeout: config.Timeout,
- Backoff: config.Backoff,
- Limiter: config.Limiter,
- }
- config.modifyLock.RUnlock()
-
- return NewClient(newConfig)
-}
-
-// SetPolicyOverride sets whether requests should be sent with the policy
-// override flag to request overriding soft-mandatory Sentinel policies (both
-// RGPs and EGPs)
-func (c *Client) SetPolicyOverride(override bool) {
- c.modifyLock.Lock()
- defer c.modifyLock.Unlock()
-
- c.policyOverride = override
-}
-
-// NewRequest creates a new raw request object to query the Vault server
-// configured for this client. This is an advanced method and generally
-// doesn't need to be called externally.
-func (c *Client) NewRequest(method, requestPath string) *Request {
- c.modifyLock.RLock()
- addr := c.addr
- token := c.token
- mfaCreds := c.mfaCreds
- wrappingLookupFunc := c.wrappingLookupFunc
- headers := c.headers
- policyOverride := c.policyOverride
- c.modifyLock.RUnlock()
-
- // if SRV records exist (see https://tools.ietf.org/html/draft-andrews-http-srv-02), lookup the SRV
- // record and take the highest match; this is not designed for high-availability, just discovery
- var host string = addr.Host
- if addr.Port() == "" {
- // Internet Draft specifies that the SRV record is ignored if a port is given
- _, addrs, err := net.LookupSRV("http", "tcp", addr.Hostname())
- if err == nil && len(addrs) > 0 {
- host = fmt.Sprintf("%s:%d", addrs[0].Target, addrs[0].Port)
- }
- }
-
- req := &Request{
- Method: method,
- URL: &url.URL{
- User: addr.User,
- Scheme: addr.Scheme,
- Host: host,
- Path: path.Join(addr.Path, requestPath),
- },
- ClientToken: token,
- Params: make(map[string][]string),
- }
-
- var lookupPath string
- switch {
- case strings.HasPrefix(requestPath, "/v1/"):
- lookupPath = strings.TrimPrefix(requestPath, "/v1/")
- case strings.HasPrefix(requestPath, "v1/"):
- lookupPath = strings.TrimPrefix(requestPath, "v1/")
- default:
- lookupPath = requestPath
- }
-
- req.MFAHeaderVals = mfaCreds
-
- if wrappingLookupFunc != nil {
- req.WrapTTL = wrappingLookupFunc(method, lookupPath)
- } else {
- req.WrapTTL = DefaultWrappingLookupFunc(method, lookupPath)
- }
-
- if headers != nil {
- req.Headers = headers
- }
-
- req.PolicyOverride = policyOverride
-
- return req
-}
-
-// RawRequest performs the raw request given. This request may be against
-// a Vault server not configured with this client. This is an advanced operation
-// that generally won't need to be called externally.
-func (c *Client) RawRequest(r *Request) (*Response, error) {
- return c.RawRequestWithContext(context.Background(), r)
-}
-
-// RawRequestWithContext performs the raw request given. This request may be against
-// a Vault server not configured with this client. This is an advanced operation
-// that generally won't need to be called externally.
-func (c *Client) RawRequestWithContext(ctx context.Context, r *Request) (*Response, error) {
- c.modifyLock.RLock()
- token := c.token
-
- c.config.modifyLock.RLock()
- limiter := c.config.Limiter
- maxRetries := c.config.MaxRetries
- backoff := c.config.Backoff
- httpClient := c.config.HttpClient
- timeout := c.config.Timeout
- outputCurlString := c.config.OutputCurlString
- c.config.modifyLock.RUnlock()
-
- c.modifyLock.RUnlock()
-
- if limiter != nil {
- limiter.Wait(ctx)
- }
-
- // Sanity check the token before potentially erroring from the API
- idx := strings.IndexFunc(token, func(c rune) bool {
- return !unicode.IsPrint(c)
- })
- if idx != -1 {
- return nil, fmt.Errorf("configured Vault token contains non-printable characters and cannot be used")
- }
-
- redirectCount := 0
-START:
- req, err := r.toRetryableHTTP()
- if err != nil {
- return nil, err
- }
- if req == nil {
- return nil, fmt.Errorf("nil request created")
- }
-
- if outputCurlString {
- LastOutputStringError = &OutputStringError{Request: req}
- return nil, LastOutputStringError
- }
-
- if timeout != 0 {
- ctx, _ = context.WithTimeout(ctx, timeout)
- }
- req.Request = req.Request.WithContext(ctx)
-
- if backoff == nil {
- backoff = retryablehttp.LinearJitterBackoff
- }
-
- client := &retryablehttp.Client{
- HTTPClient: httpClient,
- RetryWaitMin: 1000 * time.Millisecond,
- RetryWaitMax: 1500 * time.Millisecond,
- RetryMax: maxRetries,
- CheckRetry: retryablehttp.DefaultRetryPolicy,
- Backoff: backoff,
- ErrorHandler: retryablehttp.PassthroughErrorHandler,
- }
-
- var result *Response
- resp, err := client.Do(req)
- if resp != nil {
- result = &Response{Response: resp}
- }
- if err != nil {
- if strings.Contains(err.Error(), "tls: oversized") {
- err = errwrap.Wrapf(
- "{{err}}\n\n"+
- "This error usually means that the server is running with TLS disabled\n"+
- "but the client is configured to use TLS. Please either enable TLS\n"+
- "on the server or run the client with -address set to an address\n"+
- "that uses the http protocol:\n\n"+
- " vault -address http://\n\n"+
- "You can also set the VAULT_ADDR environment variable:\n\n\n"+
- " VAULT_ADDR=http:// vault \n\n"+
- "where is replaced by the actual address to the server.",
- err)
- }
- return result, err
- }
-
- // Check for a redirect, only allowing for a single redirect
- if (resp.StatusCode == 301 || resp.StatusCode == 302 || resp.StatusCode == 307) && redirectCount == 0 {
- // Parse the updated location
- respLoc, err := resp.Location()
- if err != nil {
- return result, err
- }
-
- // Ensure a protocol downgrade doesn't happen
- if req.URL.Scheme == "https" && respLoc.Scheme != "https" {
- return result, fmt.Errorf("redirect would cause protocol downgrade")
- }
-
- // Update the request
- r.URL = respLoc
-
- // Reset the request body if any
- if err := r.ResetJSONBody(); err != nil {
- return result, err
- }
-
- // Retry the request
- redirectCount++
- goto START
- }
-
- if err := result.Error(); err != nil {
- return result, err
- }
-
- return result, nil
-}
diff --git a/vendor/github.com/hashicorp/vault/api/go.mod b/vendor/github.com/hashicorp/vault/api/go.mod
deleted file mode 100644
index 94ca00bb513..00000000000
--- a/vendor/github.com/hashicorp/vault/api/go.mod
+++ /dev/null
@@ -1,19 +0,0 @@
-module github.com/hashicorp/vault/api
-
-go 1.12
-
-replace github.com/hashicorp/vault/sdk => ../sdk
-
-require (
- github.com/hashicorp/errwrap v1.0.0
- github.com/hashicorp/go-cleanhttp v0.5.1
- github.com/hashicorp/go-multierror v1.0.0
- github.com/hashicorp/go-retryablehttp v0.5.4
- github.com/hashicorp/go-rootcerts v1.0.1
- github.com/hashicorp/hcl v1.0.0
- github.com/hashicorp/vault/sdk v0.1.13
- github.com/mitchellh/mapstructure v1.1.2
- golang.org/x/net v0.0.0-20190620200207-3b0461eec859
- golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
- gopkg.in/square/go-jose.v2 v2.3.1
-)
diff --git a/vendor/github.com/hashicorp/vault/api/go.sum b/vendor/github.com/hashicorp/vault/api/go.sum
deleted file mode 100644
index 0f4df0aedef..00000000000
--- a/vendor/github.com/hashicorp/vault/api/go.sum
+++ /dev/null
@@ -1,118 +0,0 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
-github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
-github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
-github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE=
-github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
-github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8=
-github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
-github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
-github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
-github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
-github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
-github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
-github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
-github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU=
-golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
-gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
-gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/vendor/github.com/hashicorp/vault/api/help.go b/vendor/github.com/hashicorp/vault/api/help.go
deleted file mode 100644
index 321bd597c1a..00000000000
--- a/vendor/github.com/hashicorp/vault/api/help.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package api
-
-import (
- "context"
- "fmt"
-)
-
-// Help reads the help information for the given path.
-func (c *Client) Help(path string) (*Help, error) {
- r := c.NewRequest("GET", fmt.Sprintf("/v1/%s", path))
- r.Params.Add("help", "1")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result Help
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-type Help struct {
- Help string `json:"help"`
- SeeAlso []string `json:"see_also"`
- OpenAPI map[string]interface{} `json:"openapi"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/logical.go b/vendor/github.com/hashicorp/vault/api/logical.go
deleted file mode 100644
index d5f946446b6..00000000000
--- a/vendor/github.com/hashicorp/vault/api/logical.go
+++ /dev/null
@@ -1,285 +0,0 @@
-package api
-
-import (
- "bytes"
- "context"
- "fmt"
- "io"
- "net/url"
- "os"
-
- "github.com/hashicorp/errwrap"
- "github.com/hashicorp/vault/sdk/helper/jsonutil"
-)
-
-const (
- wrappedResponseLocation = "cubbyhole/response"
-)
-
-var (
- // The default TTL that will be used with `sys/wrapping/wrap`, can be
- // changed
- DefaultWrappingTTL = "5m"
-
- // The default function used if no other function is set, which honors the
- // env var and wraps `sys/wrapping/wrap`
- DefaultWrappingLookupFunc = func(operation, path string) string {
- if os.Getenv(EnvVaultWrapTTL) != "" {
- return os.Getenv(EnvVaultWrapTTL)
- }
-
- if (operation == "PUT" || operation == "POST") && path == "sys/wrapping/wrap" {
- return DefaultWrappingTTL
- }
-
- return ""
- }
-)
-
-// Logical is used to perform logical backend operations on Vault.
-type Logical struct {
- c *Client
-}
-
-// Logical is used to return the client for logical-backend API calls.
-func (c *Client) Logical() *Logical {
- return &Logical{c: c}
-}
-
-func (c *Logical) Read(path string) (*Secret, error) {
- return c.ReadWithData(path, nil)
-}
-
-func (c *Logical) ReadWithData(path string, data map[string][]string) (*Secret, error) {
- r := c.c.NewRequest("GET", "/v1/"+path)
-
- var values url.Values
- for k, v := range data {
- if values == nil {
- values = make(url.Values)
- }
- for _, val := range v {
- values.Add(k, val)
- }
- }
-
- if values != nil {
- r.Params = values
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if resp != nil {
- defer resp.Body.Close()
- }
- if resp != nil && resp.StatusCode == 404 {
- secret, parseErr := ParseSecret(resp.Body)
- switch parseErr {
- case nil:
- case io.EOF:
- return nil, nil
- default:
- return nil, err
- }
- if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
- return secret, nil
- }
- return nil, nil
- }
- if err != nil {
- return nil, err
- }
-
- return ParseSecret(resp.Body)
-}
-
-func (c *Logical) List(path string) (*Secret, error) {
- r := c.c.NewRequest("LIST", "/v1/"+path)
- // Set this for broader compatibility, but we use LIST above to be able to
- // handle the wrapping lookup function
- r.Method = "GET"
- r.Params.Set("list", "true")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if resp != nil {
- defer resp.Body.Close()
- }
- if resp != nil && resp.StatusCode == 404 {
- secret, parseErr := ParseSecret(resp.Body)
- switch parseErr {
- case nil:
- case io.EOF:
- return nil, nil
- default:
- return nil, err
- }
- if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
- return secret, nil
- }
- return nil, nil
- }
- if err != nil {
- return nil, err
- }
-
- return ParseSecret(resp.Body)
-}
-
-func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, error) {
- r := c.c.NewRequest("PUT", "/v1/"+path)
- if err := r.SetJSONBody(data); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if resp != nil {
- defer resp.Body.Close()
- }
- if resp != nil && resp.StatusCode == 404 {
- secret, parseErr := ParseSecret(resp.Body)
- switch parseErr {
- case nil:
- case io.EOF:
- return nil, nil
- default:
- return nil, err
- }
- if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
- return secret, err
- }
- }
- if err != nil {
- return nil, err
- }
-
- return ParseSecret(resp.Body)
-}
-
-func (c *Logical) Delete(path string) (*Secret, error) {
- return c.DeleteWithData(path, nil)
-}
-
-func (c *Logical) DeleteWithData(path string, data map[string][]string) (*Secret, error) {
- r := c.c.NewRequest("DELETE", "/v1/"+path)
-
- var values url.Values
- for k, v := range data {
- if values == nil {
- values = make(url.Values)
- }
- for _, val := range v {
- values.Add(k, val)
- }
- }
-
- if values != nil {
- r.Params = values
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if resp != nil {
- defer resp.Body.Close()
- }
- if resp != nil && resp.StatusCode == 404 {
- secret, parseErr := ParseSecret(resp.Body)
- switch parseErr {
- case nil:
- case io.EOF:
- return nil, nil
- default:
- return nil, err
- }
- if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
- return secret, err
- }
- }
- if err != nil {
- return nil, err
- }
-
- return ParseSecret(resp.Body)
-}
-
-func (c *Logical) Unwrap(wrappingToken string) (*Secret, error) {
- var data map[string]interface{}
- if wrappingToken != "" {
- if c.c.Token() == "" {
- c.c.SetToken(wrappingToken)
- } else if wrappingToken != c.c.Token() {
- data = map[string]interface{}{
- "token": wrappingToken,
- }
- }
- }
-
- r := c.c.NewRequest("PUT", "/v1/sys/wrapping/unwrap")
- if err := r.SetJSONBody(data); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if resp != nil {
- defer resp.Body.Close()
- }
- if resp == nil || resp.StatusCode != 404 {
- if err != nil {
- return nil, err
- }
- if resp == nil {
- return nil, nil
- }
- return ParseSecret(resp.Body)
- }
-
- // In the 404 case this may actually be a wrapped 404 error
- secret, parseErr := ParseSecret(resp.Body)
- switch parseErr {
- case nil:
- case io.EOF:
- return nil, nil
- default:
- return nil, err
- }
- if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
- return secret, nil
- }
-
- // Otherwise this might be an old-style wrapping token so attempt the old
- // method
- if wrappingToken != "" {
- origToken := c.c.Token()
- defer c.c.SetToken(origToken)
- c.c.SetToken(wrappingToken)
- }
-
- secret, err = c.Read(wrappedResponseLocation)
- if err != nil {
- return nil, errwrap.Wrapf(fmt.Sprintf("error reading %q: {{err}}", wrappedResponseLocation), err)
- }
- if secret == nil {
- return nil, fmt.Errorf("no value found at %q", wrappedResponseLocation)
- }
- if secret.Data == nil {
- return nil, fmt.Errorf("\"data\" not found in wrapping response")
- }
- if _, ok := secret.Data["response"]; !ok {
- return nil, fmt.Errorf("\"response\" not found in wrapping response \"data\" map")
- }
-
- wrappedSecret := new(Secret)
- buf := bytes.NewBufferString(secret.Data["response"].(string))
- if err := jsonutil.DecodeJSONFromReader(buf, wrappedSecret); err != nil {
- return nil, errwrap.Wrapf("error unmarshalling wrapped secret: {{err}}", err)
- }
-
- return wrappedSecret, nil
-}
diff --git a/vendor/github.com/hashicorp/vault/api/output_string.go b/vendor/github.com/hashicorp/vault/api/output_string.go
deleted file mode 100644
index b836b77a5af..00000000000
--- a/vendor/github.com/hashicorp/vault/api/output_string.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package api
-
-import (
- "fmt"
- "strings"
-
- retryablehttp "github.com/hashicorp/go-retryablehttp"
-)
-
-const (
- ErrOutputStringRequest = "output a string, please"
-)
-
-var (
- LastOutputStringError *OutputStringError
-)
-
-type OutputStringError struct {
- *retryablehttp.Request
- parsingError error
- parsedCurlString string
-}
-
-func (d *OutputStringError) Error() string {
- if d.parsedCurlString == "" {
- d.parseRequest()
- if d.parsingError != nil {
- return d.parsingError.Error()
- }
- }
-
- return ErrOutputStringRequest
-}
-
-func (d *OutputStringError) parseRequest() {
- body, err := d.Request.BodyBytes()
- if err != nil {
- d.parsingError = err
- return
- }
-
- // Build cURL string
- d.parsedCurlString = "curl "
- if d.Request.Method != "GET" {
- d.parsedCurlString = fmt.Sprintf("%s-X %s ", d.parsedCurlString, d.Request.Method)
- }
- for k, v := range d.Request.Header {
- for _, h := range v {
- if strings.ToLower(k) == "x-vault-token" {
- h = `$(vault print token)`
- }
- d.parsedCurlString = fmt.Sprintf("%s-H \"%s: %s\" ", d.parsedCurlString, k, h)
- }
- }
-
- if len(body) > 0 {
- // We need to escape single quotes since that's what we're using to
- // quote the body
- escapedBody := strings.Replace(string(body), "'", "'\"'\"'", -1)
- d.parsedCurlString = fmt.Sprintf("%s-d '%s' ", d.parsedCurlString, escapedBody)
- }
-
- d.parsedCurlString = fmt.Sprintf("%s%s", d.parsedCurlString, d.Request.URL.String())
-}
-
-func (d *OutputStringError) CurlString() string {
- if d.parsedCurlString == "" {
- d.parseRequest()
- }
- return d.parsedCurlString
-}
diff --git a/vendor/github.com/hashicorp/vault/api/plugin_helpers.go b/vendor/github.com/hashicorp/vault/api/plugin_helpers.go
deleted file mode 100644
index e664d5ebc49..00000000000
--- a/vendor/github.com/hashicorp/vault/api/plugin_helpers.go
+++ /dev/null
@@ -1,186 +0,0 @@
-package api
-
-import (
- "crypto/tls"
- "crypto/x509"
- "encoding/base64"
- "errors"
- "flag"
- "net/url"
- "os"
-
- squarejwt "gopkg.in/square/go-jose.v2/jwt"
-
- "github.com/hashicorp/errwrap"
-)
-
-var (
- // PluginMetadataModeEnv is an ENV name used to disable TLS communication
- // to bootstrap mounting plugins.
- PluginMetadataModeEnv = "VAULT_PLUGIN_METADATA_MODE"
-
- // PluginUnwrapTokenEnv is the ENV name used to pass unwrap tokens to the
- // plugin.
- PluginUnwrapTokenEnv = "VAULT_UNWRAP_TOKEN"
-)
-
-// PluginAPIClientMeta is a helper that plugins can use to configure TLS connections
-// back to Vault.
-type PluginAPIClientMeta struct {
- // These are set by the command line flags.
- flagCACert string
- flagCAPath string
- flagClientCert string
- flagClientKey string
- flagInsecure bool
-}
-
-// FlagSet returns the flag set for configuring the TLS connection
-func (f *PluginAPIClientMeta) FlagSet() *flag.FlagSet {
- fs := flag.NewFlagSet("vault plugin settings", flag.ContinueOnError)
-
- fs.StringVar(&f.flagCACert, "ca-cert", "", "")
- fs.StringVar(&f.flagCAPath, "ca-path", "", "")
- fs.StringVar(&f.flagClientCert, "client-cert", "", "")
- fs.StringVar(&f.flagClientKey, "client-key", "", "")
- fs.BoolVar(&f.flagInsecure, "tls-skip-verify", false, "")
-
- return fs
-}
-
-// GetTLSConfig will return a TLSConfig based off the values from the flags
-func (f *PluginAPIClientMeta) GetTLSConfig() *TLSConfig {
- // If we need custom TLS configuration, then set it
- if f.flagCACert != "" || f.flagCAPath != "" || f.flagClientCert != "" || f.flagClientKey != "" || f.flagInsecure {
- t := &TLSConfig{
- CACert: f.flagCACert,
- CAPath: f.flagCAPath,
- ClientCert: f.flagClientCert,
- ClientKey: f.flagClientKey,
- TLSServerName: "",
- Insecure: f.flagInsecure,
- }
-
- return t
- }
-
- return nil
-}
-
-// VaultPluginTLSProvider is run inside a plugin and retrieves the response
-// wrapped TLS certificate from vault. It returns a configured TLS Config.
-func VaultPluginTLSProvider(apiTLSConfig *TLSConfig) func() (*tls.Config, error) {
- if os.Getenv(PluginMetadataModeEnv) == "true" {
- return nil
- }
-
- return func() (*tls.Config, error) {
- unwrapToken := os.Getenv(PluginUnwrapTokenEnv)
-
- parsedJWT, err := squarejwt.ParseSigned(unwrapToken)
- if err != nil {
- return nil, errwrap.Wrapf("error parsing wrapping token: {{err}}", err)
- }
-
- var allClaims = make(map[string]interface{})
- if err = parsedJWT.UnsafeClaimsWithoutVerification(&allClaims); err != nil {
- return nil, errwrap.Wrapf("error parsing claims from wrapping token: {{err}}", err)
- }
-
- addrClaimRaw, ok := allClaims["addr"]
- if !ok {
- return nil, errors.New("could not validate addr claim")
- }
- vaultAddr, ok := addrClaimRaw.(string)
- if !ok {
- return nil, errors.New("could not parse addr claim")
- }
- if vaultAddr == "" {
- return nil, errors.New(`no vault api_addr found`)
- }
-
- // Sanity check the value
- if _, err := url.Parse(vaultAddr); err != nil {
- return nil, errwrap.Wrapf("error parsing the vault api_addr: {{err}}", err)
- }
-
- // Unwrap the token
- clientConf := DefaultConfig()
- clientConf.Address = vaultAddr
- if apiTLSConfig != nil {
- err := clientConf.ConfigureTLS(apiTLSConfig)
- if err != nil {
- return nil, errwrap.Wrapf("error configuring api client {{err}}", err)
- }
- }
- client, err := NewClient(clientConf)
- if err != nil {
- return nil, errwrap.Wrapf("error during api client creation: {{err}}", err)
- }
-
- secret, err := client.Logical().Unwrap(unwrapToken)
- if err != nil {
- return nil, errwrap.Wrapf("error during token unwrap request: {{err}}", err)
- }
- if secret == nil {
- return nil, errors.New("error during token unwrap request: secret is nil")
- }
-
- // Retrieve and parse the server's certificate
- serverCertBytesRaw, ok := secret.Data["ServerCert"].(string)
- if !ok {
- return nil, errors.New("error unmarshalling certificate")
- }
-
- serverCertBytes, err := base64.StdEncoding.DecodeString(serverCertBytesRaw)
- if err != nil {
- return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err)
- }
-
- serverCert, err := x509.ParseCertificate(serverCertBytes)
- if err != nil {
- return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err)
- }
-
- // Retrieve and parse the server's private key
- serverKeyB64, ok := secret.Data["ServerKey"].(string)
- if !ok {
- return nil, errors.New("error unmarshalling certificate")
- }
-
- serverKeyRaw, err := base64.StdEncoding.DecodeString(serverKeyB64)
- if err != nil {
- return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err)
- }
-
- serverKey, err := x509.ParseECPrivateKey(serverKeyRaw)
- if err != nil {
- return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err)
- }
-
- // Add CA cert to the cert pool
- caCertPool := x509.NewCertPool()
- caCertPool.AddCert(serverCert)
-
- // Build a certificate object out of the server's cert and private key.
- cert := tls.Certificate{
- Certificate: [][]byte{serverCertBytes},
- PrivateKey: serverKey,
- Leaf: serverCert,
- }
-
- // Setup TLS config
- tlsConfig := &tls.Config{
- ClientCAs: caCertPool,
- RootCAs: caCertPool,
- ClientAuth: tls.RequireAndVerifyClientCert,
- // TLS 1.2 minimum
- MinVersion: tls.VersionTLS12,
- Certificates: []tls.Certificate{cert},
- ServerName: serverCert.Subject.CommonName,
- }
- tlsConfig.BuildNameToCertificate()
-
- return tlsConfig, nil
- }
-}
diff --git a/vendor/github.com/hashicorp/vault/api/renewer.go b/vendor/github.com/hashicorp/vault/api/renewer.go
deleted file mode 100644
index 1d37a193821..00000000000
--- a/vendor/github.com/hashicorp/vault/api/renewer.go
+++ /dev/null
@@ -1,349 +0,0 @@
-package api
-
-import (
- "errors"
- "math/rand"
- "sync"
- "time"
-)
-
-var (
- ErrRenewerMissingInput = errors.New("missing input to renewer")
- ErrRenewerMissingSecret = errors.New("missing secret to renew")
- ErrRenewerNotRenewable = errors.New("secret is not renewable")
- ErrRenewerNoSecretData = errors.New("returned empty secret data")
-
- // DefaultRenewerRenewBuffer is the default size of the buffer for renew
- // messages on the channel.
- DefaultRenewerRenewBuffer = 5
-)
-
-// Renewer is a process for renewing a secret.
-//
-// renewer, err := client.NewRenewer(&RenewerInput{
-// Secret: mySecret,
-// })
-// go renewer.Renew()
-// defer renewer.Stop()
-//
-// for {
-// select {
-// case err := <-renewer.DoneCh():
-// if err != nil {
-// log.Fatal(err)
-// }
-//
-// // Renewal is now over
-// case renewal := <-renewer.RenewCh():
-// log.Printf("Successfully renewed: %#v", renewal)
-// }
-// }
-//
-//
-// The `DoneCh` will return if renewal fails or if the remaining lease duration
-// after a renewal is less than or equal to the grace (in number of seconds). In
-// both cases, the caller should attempt a re-read of the secret. Clients should
-// check the return value of the channel to see if renewal was successful.
-type Renewer struct {
- l sync.Mutex
-
- client *Client
- secret *Secret
- grace time.Duration
- random *rand.Rand
- increment int
- doneCh chan error
- renewCh chan *RenewOutput
-
- stopped bool
- stopCh chan struct{}
-}
-
-// RenewerInput is used as input to the renew function.
-type RenewerInput struct {
- // Secret is the secret to renew
- Secret *Secret
-
- // DEPRECATED: this does not do anything.
- Grace time.Duration
-
- // Rand is the randomizer to use for underlying randomization. If not
- // provided, one will be generated and seeded automatically. If provided, it
- // is assumed to have already been seeded.
- Rand *rand.Rand
-
- // RenewBuffer is the size of the buffered channel where renew messages are
- // dispatched.
- RenewBuffer int
-
- // The new TTL, in seconds, that should be set on the lease. The TTL set
- // here may or may not be honored by the vault server, based on Vault
- // configuration or any associated max TTL values.
- Increment int
-}
-
-// RenewOutput is the metadata returned to the client (if it's listening) to
-// renew messages.
-type RenewOutput struct {
- // RenewedAt is the timestamp when the renewal took place (UTC).
- RenewedAt time.Time
-
- // Secret is the underlying renewal data. It's the same struct as all data
- // that is returned from Vault, but since this is renewal data, it will not
- // usually include the secret itself.
- Secret *Secret
-}
-
-// NewRenewer creates a new renewer from the given input.
-func (c *Client) NewRenewer(i *RenewerInput) (*Renewer, error) {
- if i == nil {
- return nil, ErrRenewerMissingInput
- }
-
- secret := i.Secret
- if secret == nil {
- return nil, ErrRenewerMissingSecret
- }
-
- random := i.Rand
- if random == nil {
- random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
- }
-
- renewBuffer := i.RenewBuffer
- if renewBuffer == 0 {
- renewBuffer = DefaultRenewerRenewBuffer
- }
-
- return &Renewer{
- client: c,
- secret: secret,
- increment: i.Increment,
- random: random,
- doneCh: make(chan error, 1),
- renewCh: make(chan *RenewOutput, renewBuffer),
-
- stopped: false,
- stopCh: make(chan struct{}),
- }, nil
-}
-
-// DoneCh returns the channel where the renewer will publish when renewal stops.
-// If there is an error, this will be an error.
-func (r *Renewer) DoneCh() <-chan error {
- return r.doneCh
-}
-
-// RenewCh is a channel that receives a message when a successful renewal takes
-// place and includes metadata about the renewal.
-func (r *Renewer) RenewCh() <-chan *RenewOutput {
- return r.renewCh
-}
-
-// Stop stops the renewer.
-func (r *Renewer) Stop() {
- r.l.Lock()
- if !r.stopped {
- close(r.stopCh)
- r.stopped = true
- }
- r.l.Unlock()
-}
-
-// Renew starts a background process for renewing this secret. When the secret
-// has auth data, this attempts to renew the auth (token). When the secret has
-// a lease, this attempts to renew the lease.
-func (r *Renewer) Renew() {
- var result error
- if r.secret.Auth != nil {
- result = r.renewAuth()
- } else {
- result = r.renewLease()
- }
-
- r.doneCh <- result
-}
-
-// renewAuth is a helper for renewing authentication.
-func (r *Renewer) renewAuth() error {
- if !r.secret.Auth.Renewable || r.secret.Auth.ClientToken == "" {
- return ErrRenewerNotRenewable
- }
-
- priorDuration := time.Duration(r.secret.Auth.LeaseDuration) * time.Second
- r.calculateGrace(priorDuration)
-
- client, token := r.client, r.secret.Auth.ClientToken
-
- for {
- // Check if we are stopped.
- select {
- case <-r.stopCh:
- return nil
- default:
- }
-
- // Renew the auth.
- renewal, err := client.Auth().Token().RenewTokenAsSelf(token, r.increment)
- if err != nil {
- return err
- }
-
- // Push a message that a renewal took place.
- select {
- case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
- default:
- }
-
- // Somehow, sometimes, this happens.
- if renewal == nil || renewal.Auth == nil {
- return ErrRenewerNoSecretData
- }
-
- // Do nothing if we are not renewable
- if !renewal.Auth.Renewable {
- return ErrRenewerNotRenewable
- }
-
- // Grab the lease duration
- leaseDuration := time.Duration(renewal.Auth.LeaseDuration) * time.Second
-
- // We keep evaluating a new grace period so long as the lease is
- // extending. Once it stops extending, we've hit the max and need to
- // rely on the grace duration.
- if leaseDuration > priorDuration {
- r.calculateGrace(leaseDuration)
- }
- priorDuration = leaseDuration
-
- // The sleep duration is set to 2/3 of the current lease duration plus
- // 1/3 of the current grace period, which adds jitter.
- sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3)
-
- // If we are within grace, return now; or, if the amount of time we
- // would sleep would land us in the grace period. This helps with short
- // tokens; for example, you don't want a current lease duration of 4
- // seconds, a grace period of 3 seconds, and end up sleeping for more
- // than three of those seconds and having a very small budget of time
- // to renew.
- if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace {
- return nil
- }
-
- select {
- case <-r.stopCh:
- return nil
- case <-time.After(sleepDuration):
- continue
- }
- }
-}
-
-// renewLease is a helper for renewing a lease.
-func (r *Renewer) renewLease() error {
- if !r.secret.Renewable || r.secret.LeaseID == "" {
- return ErrRenewerNotRenewable
- }
-
- priorDuration := time.Duration(r.secret.LeaseDuration) * time.Second
- r.calculateGrace(priorDuration)
-
- client, leaseID := r.client, r.secret.LeaseID
-
- for {
- // Check if we are stopped.
- select {
- case <-r.stopCh:
- return nil
- default:
- }
-
- // Renew the lease.
- renewal, err := client.Sys().Renew(leaseID, r.increment)
- if err != nil {
- return err
- }
-
- // Push a message that a renewal took place.
- select {
- case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
- default:
- }
-
- // Somehow, sometimes, this happens.
- if renewal == nil {
- return ErrRenewerNoSecretData
- }
-
- // Do nothing if we are not renewable
- if !renewal.Renewable {
- return ErrRenewerNotRenewable
- }
-
- // Grab the lease duration
- leaseDuration := time.Duration(renewal.LeaseDuration) * time.Second
-
- // We keep evaluating a new grace period so long as the lease is
- // extending. Once it stops extending, we've hit the max and need to
- // rely on the grace duration.
- if leaseDuration > priorDuration {
- r.calculateGrace(leaseDuration)
- }
- priorDuration = leaseDuration
-
- // The sleep duration is set to 2/3 of the current lease duration plus
- // 1/3 of the current grace period, which adds jitter.
- sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3)
-
- // If we are within grace, return now; or, if the amount of time we
- // would sleep would land us in the grace period. This helps with short
- // tokens; for example, you don't want a current lease duration of 4
- // seconds, a grace period of 3 seconds, and end up sleeping for more
- // than three of those seconds and having a very small budget of time
- // to renew.
- if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace {
- return nil
- }
-
- select {
- case <-r.stopCh:
- return nil
- case <-time.After(sleepDuration):
- continue
- }
- }
-}
-
-// sleepDuration calculates the time to sleep given the base lease duration. The
-// base is the resulting lease duration. It will be reduced to 1/3 and
-// multiplied by a random float between 0.0 and 1.0. This extra randomness
-// prevents multiple clients from all trying to renew simultaneously.
-func (r *Renewer) sleepDuration(base time.Duration) time.Duration {
- sleep := float64(base)
-
- // Renew at 1/3 the remaining lease. This will give us an opportunity to retry
- // at least one more time should the first renewal fail.
- sleep = sleep / 3.0
-
- // Use a randomness so many clients do not hit Vault simultaneously.
- sleep = sleep * (r.random.Float64() + 1) / 2.0
-
- return time.Duration(sleep)
-}
-
-// calculateGrace calculates the grace period based on a reasonable set of
-// assumptions given the total lease time; it also adds some jitter to not have
-// clients be in sync.
-func (r *Renewer) calculateGrace(leaseDuration time.Duration) {
- if leaseDuration == 0 {
- r.grace = 0
- return
- }
-
- leaseNanos := float64(leaseDuration.Nanoseconds())
- jitterMax := 0.1 * leaseNanos
-
- // For a given lease duration, we want to allow 80-90% of that to elapse,
- // so the remaining amount is the grace period
- r.grace = time.Duration(jitterMax) + time.Duration(uint64(r.random.Int63())%uint64(jitterMax))
-}
diff --git a/vendor/github.com/hashicorp/vault/api/request.go b/vendor/github.com/hashicorp/vault/api/request.go
deleted file mode 100644
index 0ed04220e37..00000000000
--- a/vendor/github.com/hashicorp/vault/api/request.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package api
-
-import (
- "bytes"
- "encoding/json"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
-
- "github.com/hashicorp/vault/sdk/helper/consts"
-
- retryablehttp "github.com/hashicorp/go-retryablehttp"
-)
-
-// Request is a raw request configuration structure used to initiate
-// API requests to the Vault server.
-type Request struct {
- Method string
- URL *url.URL
- Params url.Values
- Headers http.Header
- ClientToken string
- MFAHeaderVals []string
- WrapTTL string
- Obj interface{}
-
- // When possible, use BodyBytes as it is more efficient due to how the
- // retry logic works
- BodyBytes []byte
-
- // Fallback
- Body io.Reader
- BodySize int64
-
- // Whether to request overriding soft-mandatory Sentinel policies (RGPs and
- // EGPs). If set, the override flag will take effect for all policies
- // evaluated during the request.
- PolicyOverride bool
-}
-
-// SetJSONBody is used to set a request body that is a JSON-encoded value.
-func (r *Request) SetJSONBody(val interface{}) error {
- buf, err := json.Marshal(val)
- if err != nil {
- return err
- }
-
- r.Obj = val
- r.BodyBytes = buf
- return nil
-}
-
-// ResetJSONBody is used to reset the body for a redirect
-func (r *Request) ResetJSONBody() error {
- if r.BodyBytes == nil {
- return nil
- }
- return r.SetJSONBody(r.Obj)
-}
-
-// DEPRECATED: ToHTTP turns this request into a valid *http.Request for use
-// with the net/http package.
-func (r *Request) ToHTTP() (*http.Request, error) {
- req, err := r.toRetryableHTTP()
- if err != nil {
- return nil, err
- }
-
- switch {
- case r.BodyBytes == nil && r.Body == nil:
- // No body
-
- case r.BodyBytes != nil:
- req.Request.Body = ioutil.NopCloser(bytes.NewReader(r.BodyBytes))
-
- default:
- if c, ok := r.Body.(io.ReadCloser); ok {
- req.Request.Body = c
- } else {
- req.Request.Body = ioutil.NopCloser(r.Body)
- }
- }
-
- return req.Request, nil
-}
-
-func (r *Request) toRetryableHTTP() (*retryablehttp.Request, error) {
- // Encode the query parameters
- r.URL.RawQuery = r.Params.Encode()
-
- // Create the HTTP request, defaulting to retryable
- var req *retryablehttp.Request
-
- var err error
- var body interface{}
-
- switch {
- case r.BodyBytes == nil && r.Body == nil:
- // No body
-
- case r.BodyBytes != nil:
- // Use bytes, it's more efficient
- body = r.BodyBytes
-
- default:
- body = r.Body
- }
-
- req, err = retryablehttp.NewRequest(r.Method, r.URL.RequestURI(), body)
- if err != nil {
- return nil, err
- }
-
- req.URL.User = r.URL.User
- req.URL.Scheme = r.URL.Scheme
- req.URL.Host = r.URL.Host
- req.Host = r.URL.Host
-
- if r.Headers != nil {
- for header, vals := range r.Headers {
- for _, val := range vals {
- req.Header.Add(header, val)
- }
- }
- }
-
- if len(r.ClientToken) != 0 {
- req.Header.Set(consts.AuthHeaderName, r.ClientToken)
- }
-
- if len(r.WrapTTL) != 0 {
- req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL)
- }
-
- if len(r.MFAHeaderVals) != 0 {
- for _, mfaHeaderVal := range r.MFAHeaderVals {
- req.Header.Add("X-Vault-MFA", mfaHeaderVal)
- }
- }
-
- if r.PolicyOverride {
- req.Header.Set("X-Vault-Policy-Override", "true")
- }
-
- return req, nil
-}
diff --git a/vendor/github.com/hashicorp/vault/api/response.go b/vendor/github.com/hashicorp/vault/api/response.go
deleted file mode 100644
index aed2a52e086..00000000000
--- a/vendor/github.com/hashicorp/vault/api/response.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package api
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
-
- "github.com/hashicorp/vault/sdk/helper/jsonutil"
-)
-
-// Response is a raw response that wraps an HTTP response.
-type Response struct {
- *http.Response
-}
-
-// DecodeJSON will decode the response body to a JSON structure. This
-// will consume the response body, but will not close it. Close must
-// still be called.
-func (r *Response) DecodeJSON(out interface{}) error {
- return jsonutil.DecodeJSONFromReader(r.Body, out)
-}
-
-// Error returns an error response if there is one. If there is an error,
-// this will fully consume the response body, but will not close it. The
-// body must still be closed manually.
-func (r *Response) Error() error {
- // 200 to 399 are okay status codes. 429 is the code for health status of
- // standby nodes.
- if (r.StatusCode >= 200 && r.StatusCode < 400) || r.StatusCode == 429 {
- return nil
- }
-
- // We have an error. Let's copy the body into our own buffer first,
- // so that if we can't decode JSON, we can at least copy it raw.
- bodyBuf := &bytes.Buffer{}
- if _, err := io.Copy(bodyBuf, r.Body); err != nil {
- return err
- }
-
- r.Body.Close()
- r.Body = ioutil.NopCloser(bodyBuf)
-
- // Build up the error object
- respErr := &ResponseError{
- HTTPMethod: r.Request.Method,
- URL: r.Request.URL.String(),
- StatusCode: r.StatusCode,
- }
-
- // Decode the error response if we can. Note that we wrap the bodyBuf
- // in a bytes.Reader here so that the JSON decoder doesn't move the
- // read pointer for the original buffer.
- var resp ErrorResponse
- if err := jsonutil.DecodeJSON(bodyBuf.Bytes(), &resp); err != nil {
- // Store the fact that we couldn't decode the errors
- respErr.RawError = true
- respErr.Errors = []string{bodyBuf.String()}
- } else {
- // Store the decoded errors
- respErr.Errors = resp.Errors
- }
-
- return respErr
-}
-
-// ErrorResponse is the raw structure of errors when they're returned by the
-// HTTP API.
-type ErrorResponse struct {
- Errors []string
-}
-
-// ResponseError is the error returned when Vault responds with an error or
-// non-success HTTP status code. If a request to Vault fails because of a
-// network error a different error message will be returned. ResponseError gives
-// access to the underlying errors and status code.
-type ResponseError struct {
- // HTTPMethod is the HTTP method for the request (PUT, GET, etc).
- HTTPMethod string
-
- // URL is the URL of the request.
- URL string
-
- // StatusCode is the HTTP status code.
- StatusCode int
-
- // RawError marks that the underlying error messages returned by Vault were
- // not parsable. The Errors slice will contain the raw response body as the
- // first and only error string if this value is set to true.
- RawError bool
-
- // Errors are the underlying errors returned by Vault.
- Errors []string
-}
-
-// Error returns a human-readable error string for the response error.
-func (r *ResponseError) Error() string {
- errString := "Errors"
- if r.RawError {
- errString = "Raw Message"
- }
-
- var errBody bytes.Buffer
- errBody.WriteString(fmt.Sprintf(
- "Error making API request.\n\n"+
- "URL: %s %s\n"+
- "Code: %d. %s:\n\n",
- r.HTTPMethod, r.URL, r.StatusCode, errString))
-
- if r.RawError && len(r.Errors) == 1 {
- errBody.WriteString(r.Errors[0])
- } else {
- for _, err := range r.Errors {
- errBody.WriteString(fmt.Sprintf("* %s", err))
- }
- }
-
- return errBody.String()
-}
diff --git a/vendor/github.com/hashicorp/vault/api/secret.go b/vendor/github.com/hashicorp/vault/api/secret.go
deleted file mode 100644
index d5b9ce9729e..00000000000
--- a/vendor/github.com/hashicorp/vault/api/secret.go
+++ /dev/null
@@ -1,322 +0,0 @@
-package api
-
-import (
- "bytes"
- "fmt"
- "io"
- "time"
-
- "github.com/hashicorp/errwrap"
- "github.com/hashicorp/vault/sdk/helper/jsonutil"
- "github.com/hashicorp/vault/sdk/helper/parseutil"
-)
-
-// Secret is the structure returned for every secret within Vault.
-type Secret struct {
- // The request ID that generated this response
- RequestID string `json:"request_id"`
-
- LeaseID string `json:"lease_id"`
- LeaseDuration int `json:"lease_duration"`
- Renewable bool `json:"renewable"`
-
- // Data is the actual contents of the secret. The format of the data
- // is arbitrary and up to the secret backend.
- Data map[string]interface{} `json:"data"`
-
- // Warnings contains any warnings related to the operation. These
- // are not issues that caused the command to fail, but that the
- // client should be aware of.
- Warnings []string `json:"warnings"`
-
- // Auth, if non-nil, means that there was authentication information
- // attached to this response.
- Auth *SecretAuth `json:"auth,omitempty"`
-
- // WrapInfo, if non-nil, means that the initial response was wrapped in the
- // cubbyhole of the given token (which has a TTL of the given number of
- // seconds)
- WrapInfo *SecretWrapInfo `json:"wrap_info,omitempty"`
-}
-
-// TokenID returns the standardized token ID (token) for the given secret.
-func (s *Secret) TokenID() (string, error) {
- if s == nil {
- return "", nil
- }
-
- if s.Auth != nil && len(s.Auth.ClientToken) > 0 {
- return s.Auth.ClientToken, nil
- }
-
- if s.Data == nil || s.Data["id"] == nil {
- return "", nil
- }
-
- id, ok := s.Data["id"].(string)
- if !ok {
- return "", fmt.Errorf("token found but in the wrong format")
- }
-
- return id, nil
-}
-
-// TokenAccessor returns the standardized token accessor for the given secret.
-// If the secret is nil or does not contain an accessor, this returns the empty
-// string.
-func (s *Secret) TokenAccessor() (string, error) {
- if s == nil {
- return "", nil
- }
-
- if s.Auth != nil && len(s.Auth.Accessor) > 0 {
- return s.Auth.Accessor, nil
- }
-
- if s.Data == nil || s.Data["accessor"] == nil {
- return "", nil
- }
-
- accessor, ok := s.Data["accessor"].(string)
- if !ok {
- return "", fmt.Errorf("token found but in the wrong format")
- }
-
- return accessor, nil
-}
-
-// TokenRemainingUses returns the standardized remaining uses for the given
-// secret. If the secret is nil or does not contain the "num_uses", this
-// returns -1. On error, this will return -1 and a non-nil error.
-func (s *Secret) TokenRemainingUses() (int, error) {
- if s == nil || s.Data == nil || s.Data["num_uses"] == nil {
- return -1, nil
- }
-
- uses, err := parseutil.ParseInt(s.Data["num_uses"])
- if err != nil {
- return 0, err
- }
-
- return int(uses), nil
-}
-
-// TokenPolicies returns the standardized list of policies for the given secret.
-// If the secret is nil or does not contain any policies, this returns nil. It
-// also populates the secret's Auth info with identity/token policy info.
-func (s *Secret) TokenPolicies() ([]string, error) {
- if s == nil {
- return nil, nil
- }
-
- if s.Auth != nil && len(s.Auth.Policies) > 0 {
- return s.Auth.Policies, nil
- }
-
- if s.Data == nil || s.Data["policies"] == nil {
- return nil, nil
- }
-
- var tokenPolicies []string
-
- // Token policies
- {
- _, ok := s.Data["policies"]
- if !ok {
- goto TOKEN_DONE
- }
-
- sList, ok := s.Data["policies"].([]string)
- if ok {
- tokenPolicies = sList
- goto TOKEN_DONE
- }
-
- list, ok := s.Data["policies"].([]interface{})
- if !ok {
- return nil, fmt.Errorf("unable to convert token policies to expected format")
- }
- for _, v := range list {
- p, ok := v.(string)
- if !ok {
- return nil, fmt.Errorf("unable to convert policy %v to string", v)
- }
- tokenPolicies = append(tokenPolicies, p)
- }
- }
-
-TOKEN_DONE:
- var identityPolicies []string
-
- // Identity policies
- {
- _, ok := s.Data["identity_policies"]
- if !ok {
- goto DONE
- }
-
- sList, ok := s.Data["identity_policies"].([]string)
- if ok {
- identityPolicies = sList
- goto DONE
- }
-
- list, ok := s.Data["identity_policies"].([]interface{})
- if !ok {
- return nil, fmt.Errorf("unable to convert identity policies to expected format")
- }
- for _, v := range list {
- p, ok := v.(string)
- if !ok {
- return nil, fmt.Errorf("unable to convert policy %v to string", v)
- }
- identityPolicies = append(identityPolicies, p)
- }
- }
-
-DONE:
-
- if s.Auth == nil {
- s.Auth = &SecretAuth{}
- }
-
- policies := append(tokenPolicies, identityPolicies...)
-
- s.Auth.TokenPolicies = tokenPolicies
- s.Auth.IdentityPolicies = identityPolicies
- s.Auth.Policies = policies
-
- return policies, nil
-}
-
-// TokenMetadata returns the map of metadata associated with this token, if any
-// exists. If the secret is nil or does not contain the "metadata" key, this
-// returns nil.
-func (s *Secret) TokenMetadata() (map[string]string, error) {
- if s == nil {
- return nil, nil
- }
-
- if s.Auth != nil && len(s.Auth.Metadata) > 0 {
- return s.Auth.Metadata, nil
- }
-
- if s.Data == nil || (s.Data["metadata"] == nil && s.Data["meta"] == nil) {
- return nil, nil
- }
-
- data, ok := s.Data["metadata"].(map[string]interface{})
- if !ok {
- data, ok = s.Data["meta"].(map[string]interface{})
- if !ok {
- return nil, fmt.Errorf("unable to convert metadata field to expected format")
- }
- }
-
- metadata := make(map[string]string, len(data))
- for k, v := range data {
- typed, ok := v.(string)
- if !ok {
- return nil, fmt.Errorf("unable to convert metadata value %v to string", v)
- }
- metadata[k] = typed
- }
-
- return metadata, nil
-}
-
-// TokenIsRenewable returns the standardized token renewability for the given
-// secret. If the secret is nil or does not contain the "renewable" key, this
-// returns false.
-func (s *Secret) TokenIsRenewable() (bool, error) {
- if s == nil {
- return false, nil
- }
-
- if s.Auth != nil && s.Auth.Renewable {
- return s.Auth.Renewable, nil
- }
-
- if s.Data == nil || s.Data["renewable"] == nil {
- return false, nil
- }
-
- renewable, err := parseutil.ParseBool(s.Data["renewable"])
- if err != nil {
- return false, errwrap.Wrapf("could not convert renewable value to a boolean: {{err}}", err)
- }
-
- return renewable, nil
-}
-
-// TokenTTL returns the standardized remaining token TTL for the given secret.
-// If the secret is nil or does not contain a TTL, this returns 0.
-func (s *Secret) TokenTTL() (time.Duration, error) {
- if s == nil {
- return 0, nil
- }
-
- if s.Auth != nil && s.Auth.LeaseDuration > 0 {
- return time.Duration(s.Auth.LeaseDuration) * time.Second, nil
- }
-
- if s.Data == nil || s.Data["ttl"] == nil {
- return 0, nil
- }
-
- ttl, err := parseutil.ParseDurationSecond(s.Data["ttl"])
- if err != nil {
- return 0, err
- }
-
- return ttl, nil
-}
-
-// SecretWrapInfo contains wrapping information if we have it. If what is
-// contained is an authentication token, the accessor for the token will be
-// available in WrappedAccessor.
-type SecretWrapInfo struct {
- Token string `json:"token"`
- Accessor string `json:"accessor"`
- TTL int `json:"ttl"`
- CreationTime time.Time `json:"creation_time"`
- CreationPath string `json:"creation_path"`
- WrappedAccessor string `json:"wrapped_accessor"`
-}
-
-// SecretAuth is the structure containing auth information if we have it.
-type SecretAuth struct {
- ClientToken string `json:"client_token"`
- Accessor string `json:"accessor"`
- Policies []string `json:"policies"`
- TokenPolicies []string `json:"token_policies"`
- IdentityPolicies []string `json:"identity_policies"`
- Metadata map[string]string `json:"metadata"`
- Orphan bool `json:"orphan"`
- EntityID string `json:"entity_id"`
-
- LeaseDuration int `json:"lease_duration"`
- Renewable bool `json:"renewable"`
-}
-
-// ParseSecret is used to parse a secret value from JSON from an io.Reader.
-func ParseSecret(r io.Reader) (*Secret, error) {
- // First read the data into a buffer. Not super efficient but we want to
- // know if we actually have a body or not.
- var buf bytes.Buffer
- _, err := buf.ReadFrom(r)
- if err != nil {
- return nil, err
- }
- if buf.Len() == 0 {
- return nil, nil
- }
-
- // First decode the JSON into a map[string]interface{}
- var secret Secret
- if err := jsonutil.DecodeJSONFromReader(&buf, &secret); err != nil {
- return nil, err
- }
-
- return &secret, nil
-}
diff --git a/vendor/github.com/hashicorp/vault/api/ssh.go b/vendor/github.com/hashicorp/vault/api/ssh.go
deleted file mode 100644
index 837eac4ff78..00000000000
--- a/vendor/github.com/hashicorp/vault/api/ssh.go
+++ /dev/null
@@ -1,62 +0,0 @@
-package api
-
-import (
- "context"
- "fmt"
-)
-
-// SSH is used to return a client to invoke operations on SSH backend.
-type SSH struct {
- c *Client
- MountPoint string
-}
-
-// SSH returns the client for logical-backend API calls.
-func (c *Client) SSH() *SSH {
- return c.SSHWithMountPoint(SSHHelperDefaultMountPoint)
-}
-
-// SSHWithMountPoint returns the client with specific SSH mount point.
-func (c *Client) SSHWithMountPoint(mountPoint string) *SSH {
- return &SSH{
- c: c,
- MountPoint: mountPoint,
- }
-}
-
-// Credential invokes the SSH backend API to create a credential to establish an SSH session.
-func (c *SSH) Credential(role string, data map[string]interface{}) (*Secret, error) {
- r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/%s/creds/%s", c.MountPoint, role))
- if err := r.SetJSONBody(data); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-// SignKey signs the given public key and returns a signed public key to pass
-// along with the SSH request.
-func (c *SSH) SignKey(role string, data map[string]interface{}) (*Secret, error) {
- r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/%s/sign/%s", c.MountPoint, role))
- if err := r.SetJSONBody(data); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
diff --git a/vendor/github.com/hashicorp/vault/api/ssh_agent.go b/vendor/github.com/hashicorp/vault/api/ssh_agent.go
deleted file mode 100644
index a4348ca2ed7..00000000000
--- a/vendor/github.com/hashicorp/vault/api/ssh_agent.go
+++ /dev/null
@@ -1,234 +0,0 @@
-package api
-
-import (
- "context"
- "crypto/tls"
- "crypto/x509"
- "fmt"
- "io/ioutil"
- "os"
-
- "github.com/hashicorp/errwrap"
- cleanhttp "github.com/hashicorp/go-cleanhttp"
- multierror "github.com/hashicorp/go-multierror"
- rootcerts "github.com/hashicorp/go-rootcerts"
- "github.com/hashicorp/hcl"
- "github.com/hashicorp/hcl/hcl/ast"
- "github.com/hashicorp/vault/sdk/helper/hclutil"
- "github.com/mitchellh/mapstructure"
-)
-
-const (
- // SSHHelperDefaultMountPoint is the default path at which SSH backend will be
- // mounted in the Vault server.
- SSHHelperDefaultMountPoint = "ssh"
-
- // VerifyEchoRequest is the echo request message sent as OTP by the helper.
- VerifyEchoRequest = "verify-echo-request"
-
- // VerifyEchoResponse is the echo response message sent as a response to OTP
- // matching echo request.
- VerifyEchoResponse = "verify-echo-response"
-)
-
-// SSHHelper is a structure representing a vault-ssh-helper which can talk to vault server
-// in order to verify the OTP entered by the user. It contains the path at which
-// SSH backend is mounted at the server.
-type SSHHelper struct {
- c *Client
- MountPoint string
-}
-
-// SSHVerifyResponse is a structure representing the fields in Vault server's
-// response.
-type SSHVerifyResponse struct {
- // Usually empty. If the request OTP is echo request message, this will
- // be set to the corresponding echo response message.
- Message string `json:"message" mapstructure:"message"`
-
- // Username associated with the OTP
- Username string `json:"username" mapstructure:"username"`
-
- // IP associated with the OTP
- IP string `json:"ip" mapstructure:"ip"`
-
- // Name of the role against which the OTP was issued
- RoleName string `json:"role_name" mapstructure:"role_name"`
-}
-
-// SSHHelperConfig is a structure which represents the entries from the vault-ssh-helper's configuration file.
-type SSHHelperConfig struct {
- VaultAddr string `hcl:"vault_addr"`
- SSHMountPoint string `hcl:"ssh_mount_point"`
- CACert string `hcl:"ca_cert"`
- CAPath string `hcl:"ca_path"`
- AllowedCidrList string `hcl:"allowed_cidr_list"`
- AllowedRoles string `hcl:"allowed_roles"`
- TLSSkipVerify bool `hcl:"tls_skip_verify"`
- TLSServerName string `hcl:"tls_server_name"`
-}
-
-// SetTLSParameters sets the TLS parameters for this SSH agent.
-func (c *SSHHelperConfig) SetTLSParameters(clientConfig *Config, certPool *x509.CertPool) {
- tlsConfig := &tls.Config{
- InsecureSkipVerify: c.TLSSkipVerify,
- MinVersion: tls.VersionTLS12,
- RootCAs: certPool,
- ServerName: c.TLSServerName,
- }
-
- transport := cleanhttp.DefaultTransport()
- transport.TLSClientConfig = tlsConfig
- clientConfig.HttpClient.Transport = transport
-}
-
-// Returns true if any of the following conditions are true:
-// * CA cert is configured
-// * CA path is configured
-// * configured to skip certificate verification
-// * TLS server name is configured
-//
-func (c *SSHHelperConfig) shouldSetTLSParameters() bool {
- return c.CACert != "" || c.CAPath != "" || c.TLSServerName != "" || c.TLSSkipVerify
-}
-
-// NewClient returns a new client for the configuration. This client will be used by the
-// vault-ssh-helper to communicate with Vault server and verify the OTP entered by user.
-// If the configuration supplies Vault SSL certificates, then the client will
-// have TLS configured in its transport.
-func (c *SSHHelperConfig) NewClient() (*Client, error) {
- // Creating a default client configuration for communicating with vault server.
- clientConfig := DefaultConfig()
-
- // Pointing the client to the actual address of vault server.
- clientConfig.Address = c.VaultAddr
-
- // Check if certificates are provided via config file.
- if c.shouldSetTLSParameters() {
- rootConfig := &rootcerts.Config{
- CAFile: c.CACert,
- CAPath: c.CAPath,
- }
- certPool, err := rootcerts.LoadCACerts(rootConfig)
- if err != nil {
- return nil, err
- }
- // Enable TLS on the HTTP client information
- c.SetTLSParameters(clientConfig, certPool)
- }
-
- // Creating the client object for the given configuration
- client, err := NewClient(clientConfig)
- if err != nil {
- return nil, err
- }
-
- return client, nil
-}
-
-// LoadSSHHelperConfig loads ssh-helper's configuration from the file and populates the corresponding
-// in-memory structure.
-//
-// Vault address is a required parameter.
-// Mount point defaults to "ssh".
-func LoadSSHHelperConfig(path string) (*SSHHelperConfig, error) {
- contents, err := ioutil.ReadFile(path)
- if err != nil && !os.IsNotExist(err) {
- return nil, multierror.Prefix(err, "ssh_helper:")
- }
- return ParseSSHHelperConfig(string(contents))
-}
-
-// ParseSSHHelperConfig parses the given contents as a string for the SSHHelper
-// configuration.
-func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) {
- root, err := hcl.Parse(string(contents))
- if err != nil {
- return nil, errwrap.Wrapf("error parsing config: {{err}}", err)
- }
-
- list, ok := root.Node.(*ast.ObjectList)
- if !ok {
- return nil, fmt.Errorf("error parsing config: file doesn't contain a root object")
- }
-
- valid := []string{
- "vault_addr",
- "ssh_mount_point",
- "ca_cert",
- "ca_path",
- "allowed_cidr_list",
- "allowed_roles",
- "tls_skip_verify",
- "tls_server_name",
- }
- if err := hclutil.CheckHCLKeys(list, valid); err != nil {
- return nil, multierror.Prefix(err, "ssh_helper:")
- }
-
- var c SSHHelperConfig
- c.SSHMountPoint = SSHHelperDefaultMountPoint
- if err := hcl.DecodeObject(&c, list); err != nil {
- return nil, multierror.Prefix(err, "ssh_helper:")
- }
-
- if c.VaultAddr == "" {
- return nil, fmt.Errorf(`missing config "vault_addr"`)
- }
- return &c, nil
-}
-
-// SSHHelper creates an SSHHelper object which can talk to Vault server with SSH backend
-// mounted at default path ("ssh").
-func (c *Client) SSHHelper() *SSHHelper {
- return c.SSHHelperWithMountPoint(SSHHelperDefaultMountPoint)
-}
-
-// SSHHelperWithMountPoint creates an SSHHelper object which can talk to Vault server with SSH backend
-// mounted at a specific mount point.
-func (c *Client) SSHHelperWithMountPoint(mountPoint string) *SSHHelper {
- return &SSHHelper{
- c: c,
- MountPoint: mountPoint,
- }
-}
-
-// Verify verifies if the key provided by user is present in Vault server. The response
-// will contain the IP address and username associated with the OTP. In case the
-// OTP matches the echo request message, instead of searching an entry for the OTP,
-// an echo response message is returned. This feature is used by ssh-helper to verify if
-// its configured correctly.
-func (c *SSHHelper) Verify(otp string) (*SSHVerifyResponse, error) {
- data := map[string]interface{}{
- "otp": otp,
- }
- verifyPath := fmt.Sprintf("/v1/%s/verify", c.MountPoint)
- r := c.c.NewRequest("PUT", verifyPath)
- if err := r.SetJSONBody(data); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
-
- if secret.Data == nil {
- return nil, nil
- }
-
- var verifyResp SSHVerifyResponse
- err = mapstructure.Decode(secret.Data, &verifyResp)
- if err != nil {
- return nil, err
- }
- return &verifyResp, nil
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys.go b/vendor/github.com/hashicorp/vault/api/sys.go
deleted file mode 100644
index 5fb111887c0..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package api
-
-// Sys is used to perform system-related operations on Vault.
-type Sys struct {
- c *Client
-}
-
-// Sys is used to return the client for sys-related API calls.
-func (c *Client) Sys() *Sys {
- return &Sys{c: c}
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_audit.go b/vendor/github.com/hashicorp/vault/api/sys_audit.go
deleted file mode 100644
index 2448c0367cb..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_audit.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package api
-
-import (
- "context"
- "errors"
- "fmt"
-
- "github.com/mitchellh/mapstructure"
-)
-
-func (c *Sys) AuditHash(path string, input string) (string, error) {
- body := map[string]interface{}{
- "input": input,
- }
-
- r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit-hash/%s", path))
- if err := r.SetJSONBody(body); err != nil {
- return "", err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return "", err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return "", err
- }
- if secret == nil || secret.Data == nil {
- return "", errors.New("data from server response is empty")
- }
-
- hash, ok := secret.Data["hash"]
- if !ok {
- return "", errors.New("hash not found in response data")
- }
- hashStr, ok := hash.(string)
- if !ok {
- return "", errors.New("could not parse hash in response data")
- }
-
- return hashStr, nil
-}
-
-func (c *Sys) ListAudit() (map[string]*Audit, error) {
- r := c.c.NewRequest("GET", "/v1/sys/audit")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
-
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- mounts := map[string]*Audit{}
- err = mapstructure.Decode(secret.Data, &mounts)
- if err != nil {
- return nil, err
- }
-
- return mounts, nil
-}
-
-// DEPRECATED: Use EnableAuditWithOptions instead
-func (c *Sys) EnableAudit(
- path string, auditType string, desc string, opts map[string]string) error {
- return c.EnableAuditWithOptions(path, &EnableAuditOptions{
- Type: auditType,
- Description: desc,
- Options: opts,
- })
-}
-
-func (c *Sys) EnableAuditWithOptions(path string, options *EnableAuditOptions) error {
- r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit/%s", path))
- if err := r.SetJSONBody(options); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
-
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return nil
-}
-
-func (c *Sys) DisableAudit(path string) error {
- r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/audit/%s", path))
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
-
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-// Structures for the requests/resposne are all down here. They aren't
-// individually documented because the map almost directly to the raw HTTP API
-// documentation. Please refer to that documentation for more details.
-
-type EnableAuditOptions struct {
- Type string `json:"type" mapstructure:"type"`
- Description string `json:"description" mapstructure:"description"`
- Options map[string]string `json:"options" mapstructure:"options"`
- Local bool `json:"local" mapstructure:"local"`
-}
-
-type Audit struct {
- Type string `json:"type" mapstructure:"type"`
- Description string `json:"description" mapstructure:"description"`
- Options map[string]string `json:"options" mapstructure:"options"`
- Local bool `json:"local" mapstructure:"local"`
- Path string `json:"path" mapstructure:"path"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_auth.go b/vendor/github.com/hashicorp/vault/api/sys_auth.go
deleted file mode 100644
index e7a9c222d8f..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_auth.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package api
-
-import (
- "context"
- "errors"
- "fmt"
-
- "github.com/mitchellh/mapstructure"
-)
-
-func (c *Sys) ListAuth() (map[string]*AuthMount, error) {
- r := c.c.NewRequest("GET", "/v1/sys/auth")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- mounts := map[string]*AuthMount{}
- err = mapstructure.Decode(secret.Data, &mounts)
- if err != nil {
- return nil, err
- }
-
- return mounts, nil
-}
-
-// DEPRECATED: Use EnableAuthWithOptions instead
-func (c *Sys) EnableAuth(path, authType, desc string) error {
- return c.EnableAuthWithOptions(path, &EnableAuthOptions{
- Type: authType,
- Description: desc,
- })
-}
-
-func (c *Sys) EnableAuthWithOptions(path string, options *EnableAuthOptions) error {
- r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/auth/%s", path))
- if err := r.SetJSONBody(options); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return nil
-}
-
-func (c *Sys) DisableAuth(path string) error {
- r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/auth/%s", path))
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-// Rather than duplicate, we can use modern Go's type aliasing
-type EnableAuthOptions = MountInput
-type AuthConfigInput = MountConfigInput
-type AuthMount = MountOutput
-type AuthConfigOutput = MountConfigOutput
diff --git a/vendor/github.com/hashicorp/vault/api/sys_capabilities.go b/vendor/github.com/hashicorp/vault/api/sys_capabilities.go
deleted file mode 100644
index 64b3951dd10..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_capabilities.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package api
-
-import (
- "context"
- "errors"
- "fmt"
-
- "github.com/mitchellh/mapstructure"
-)
-
-func (c *Sys) CapabilitiesSelf(path string) ([]string, error) {
- return c.Capabilities(c.c.Token(), path)
-}
-
-func (c *Sys) Capabilities(token, path string) ([]string, error) {
- body := map[string]string{
- "token": token,
- "path": path,
- }
-
- reqPath := "/v1/sys/capabilities"
- if token == c.c.Token() {
- reqPath = fmt.Sprintf("%s-self", reqPath)
- }
-
- r := c.c.NewRequest("POST", reqPath)
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- var res []string
- err = mapstructure.Decode(secret.Data[path], &res)
- if err != nil {
- return nil, err
- }
-
- if len(res) == 0 {
- _, ok := secret.Data["capabilities"]
- if ok {
- err = mapstructure.Decode(secret.Data["capabilities"], &res)
- if err != nil {
- return nil, err
- }
- }
- }
-
- return res, nil
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_config_cors.go b/vendor/github.com/hashicorp/vault/api/sys_config_cors.go
deleted file mode 100644
index d153a47c3a4..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_config_cors.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package api
-
-import (
- "context"
- "errors"
-
- "github.com/mitchellh/mapstructure"
-)
-
-func (c *Sys) CORSStatus() (*CORSResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/config/cors")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- var result CORSResponse
- err = mapstructure.Decode(secret.Data, &result)
- if err != nil {
- return nil, err
- }
-
- return &result, err
-}
-
-func (c *Sys) ConfigureCORS(req *CORSRequest) (*CORSResponse, error) {
- r := c.c.NewRequest("PUT", "/v1/sys/config/cors")
- if err := r.SetJSONBody(req); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- var result CORSResponse
- err = mapstructure.Decode(secret.Data, &result)
- if err != nil {
- return nil, err
- }
-
- return &result, err
-}
-
-func (c *Sys) DisableCORS() (*CORSResponse, error) {
- r := c.c.NewRequest("DELETE", "/v1/sys/config/cors")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- var result CORSResponse
- err = mapstructure.Decode(secret.Data, &result)
- if err != nil {
- return nil, err
- }
-
- return &result, err
-}
-
-type CORSRequest struct {
- AllowedOrigins string `json:"allowed_origins" mapstructure:"allowed_origins"`
- Enabled bool `json:"enabled" mapstructure:"enabled"`
-}
-
-type CORSResponse struct {
- AllowedOrigins string `json:"allowed_origins" mapstructure:"allowed_origins"`
- Enabled bool `json:"enabled" mapstructure:"enabled"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_generate_root.go b/vendor/github.com/hashicorp/vault/api/sys_generate_root.go
deleted file mode 100644
index 66f72dff69e..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_generate_root.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package api
-
-import "context"
-
-func (c *Sys) GenerateRootStatus() (*GenerateRootStatusResponse, error) {
- return c.generateRootStatusCommon("/v1/sys/generate-root/attempt")
-}
-
-func (c *Sys) GenerateDROperationTokenStatus() (*GenerateRootStatusResponse, error) {
- return c.generateRootStatusCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt")
-}
-
-func (c *Sys) generateRootStatusCommon(path string) (*GenerateRootStatusResponse, error) {
- r := c.c.NewRequest("GET", path)
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result GenerateRootStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) GenerateRootInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) {
- return c.generateRootInitCommon("/v1/sys/generate-root/attempt", otp, pgpKey)
-}
-
-func (c *Sys) GenerateDROperationTokenInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) {
- return c.generateRootInitCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt", otp, pgpKey)
-}
-
-func (c *Sys) generateRootInitCommon(path, otp, pgpKey string) (*GenerateRootStatusResponse, error) {
- body := map[string]interface{}{
- "otp": otp,
- "pgp_key": pgpKey,
- }
-
- r := c.c.NewRequest("PUT", path)
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result GenerateRootStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) GenerateRootCancel() error {
- return c.generateRootCancelCommon("/v1/sys/generate-root/attempt")
-}
-
-func (c *Sys) GenerateDROperationTokenCancel() error {
- return c.generateRootCancelCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt")
-}
-
-func (c *Sys) generateRootCancelCommon(path string) error {
- r := c.c.NewRequest("DELETE", path)
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) GenerateRootUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) {
- return c.generateRootUpdateCommon("/v1/sys/generate-root/update", shard, nonce)
-}
-
-func (c *Sys) GenerateDROperationTokenUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) {
- return c.generateRootUpdateCommon("/v1/sys/replication/dr/secondary/generate-operation-token/update", shard, nonce)
-}
-
-func (c *Sys) generateRootUpdateCommon(path, shard, nonce string) (*GenerateRootStatusResponse, error) {
- body := map[string]interface{}{
- "key": shard,
- "nonce": nonce,
- }
-
- r := c.c.NewRequest("PUT", path)
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result GenerateRootStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-type GenerateRootStatusResponse struct {
- Nonce string `json:"nonce"`
- Started bool `json:"started"`
- Progress int `json:"progress"`
- Required int `json:"required"`
- Complete bool `json:"complete"`
- EncodedToken string `json:"encoded_token"`
- EncodedRootToken string `json:"encoded_root_token"`
- PGPFingerprint string `json:"pgp_fingerprint"`
- OTP string `json:"otp"`
- OTPLength int `json:"otp_length"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_health.go b/vendor/github.com/hashicorp/vault/api/sys_health.go
deleted file mode 100644
index d5d7796008f..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_health.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package api
-
-import "context"
-
-func (c *Sys) Health() (*HealthResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/health")
- // If the code is 400 or above it will automatically turn into an error,
- // but the sys/health API defaults to returning 5xx when not sealed or
- // inited, so we force this code to be something else so we parse correctly
- r.Params.Add("uninitcode", "299")
- r.Params.Add("sealedcode", "299")
- r.Params.Add("standbycode", "299")
- r.Params.Add("drsecondarycode", "299")
- r.Params.Add("performancestandbycode", "299")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result HealthResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-type HealthResponse struct {
- Initialized bool `json:"initialized"`
- Sealed bool `json:"sealed"`
- Standby bool `json:"standby"`
- PerformanceStandby bool `json:"performance_standby"`
- ReplicationPerformanceMode string `json:"replication_performance_mode"`
- ReplicationDRMode string `json:"replication_dr_mode"`
- ServerTimeUTC int64 `json:"server_time_utc"`
- Version string `json:"version"`
- ClusterName string `json:"cluster_name,omitempty"`
- ClusterID string `json:"cluster_id,omitempty"`
- LastWAL uint64 `json:"last_wal,omitempty"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_init.go b/vendor/github.com/hashicorp/vault/api/sys_init.go
deleted file mode 100644
index 0e499c6e3c6..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_init.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package api
-
-import "context"
-
-func (c *Sys) InitStatus() (bool, error) {
- r := c.c.NewRequest("GET", "/v1/sys/init")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return false, err
- }
- defer resp.Body.Close()
-
- var result InitStatusResponse
- err = resp.DecodeJSON(&result)
- return result.Initialized, err
-}
-
-func (c *Sys) Init(opts *InitRequest) (*InitResponse, error) {
- r := c.c.NewRequest("PUT", "/v1/sys/init")
- if err := r.SetJSONBody(opts); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result InitResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-type InitRequest struct {
- SecretShares int `json:"secret_shares"`
- SecretThreshold int `json:"secret_threshold"`
- StoredShares int `json:"stored_shares"`
- PGPKeys []string `json:"pgp_keys"`
- RecoveryShares int `json:"recovery_shares"`
- RecoveryThreshold int `json:"recovery_threshold"`
- RecoveryPGPKeys []string `json:"recovery_pgp_keys"`
- RootTokenPGPKey string `json:"root_token_pgp_key"`
-}
-
-type InitStatusResponse struct {
- Initialized bool
-}
-
-type InitResponse struct {
- Keys []string `json:"keys"`
- KeysB64 []string `json:"keys_base64"`
- RecoveryKeys []string `json:"recovery_keys"`
- RecoveryKeysB64 []string `json:"recovery_keys_base64"`
- RootToken string `json:"root_token"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_leader.go b/vendor/github.com/hashicorp/vault/api/sys_leader.go
deleted file mode 100644
index 8846dcdfae9..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_leader.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package api
-
-import "context"
-
-func (c *Sys) Leader() (*LeaderResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/leader")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result LeaderResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-type LeaderResponse struct {
- HAEnabled bool `json:"ha_enabled"`
- IsSelf bool `json:"is_self"`
- LeaderAddress string `json:"leader_address"`
- LeaderClusterAddress string `json:"leader_cluster_address"`
- PerfStandby bool `json:"performance_standby"`
- PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"`
- LastWAL uint64 `json:"last_wal"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_leases.go b/vendor/github.com/hashicorp/vault/api/sys_leases.go
deleted file mode 100644
index 09c9642a95d..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_leases.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package api
-
-import (
- "context"
- "errors"
-)
-
-func (c *Sys) Renew(id string, increment int) (*Secret, error) {
- r := c.c.NewRequest("PUT", "/v1/sys/leases/renew")
-
- body := map[string]interface{}{
- "increment": increment,
- "lease_id": id,
- }
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- return ParseSecret(resp.Body)
-}
-
-func (c *Sys) Revoke(id string) error {
- r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke/"+id)
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) RevokePrefix(id string) error {
- r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke-prefix/"+id)
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) RevokeForce(id string) error {
- r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke-force/"+id)
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) RevokeWithOptions(opts *RevokeOptions) error {
- if opts == nil {
- return errors.New("nil options provided")
- }
-
- // Construct path
- path := "/v1/sys/leases/revoke/"
- switch {
- case opts.Force:
- path = "/v1/sys/leases/revoke-force/"
- case opts.Prefix:
- path = "/v1/sys/leases/revoke-prefix/"
- }
- path += opts.LeaseID
-
- r := c.c.NewRequest("PUT", path)
- if !opts.Force {
- body := map[string]interface{}{
- "sync": opts.Sync,
- }
- if err := r.SetJSONBody(body); err != nil {
- return err
- }
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-type RevokeOptions struct {
- LeaseID string
- Force bool
- Prefix bool
- Sync bool
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_mounts.go b/vendor/github.com/hashicorp/vault/api/sys_mounts.go
deleted file mode 100644
index 354b1ee9346..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_mounts.go
+++ /dev/null
@@ -1,185 +0,0 @@
-package api
-
-import (
- "context"
- "errors"
- "fmt"
-
- "github.com/mitchellh/mapstructure"
-)
-
-func (c *Sys) ListMounts() (map[string]*MountOutput, error) {
- r := c.c.NewRequest("GET", "/v1/sys/mounts")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- mounts := map[string]*MountOutput{}
- err = mapstructure.Decode(secret.Data, &mounts)
- if err != nil {
- return nil, err
- }
-
- return mounts, nil
-}
-
-func (c *Sys) Mount(path string, mountInfo *MountInput) error {
- r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/mounts/%s", path))
- if err := r.SetJSONBody(mountInfo); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return nil
-}
-
-func (c *Sys) Unmount(path string) error {
- r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/mounts/%s", path))
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) Remount(from, to string) error {
- body := map[string]interface{}{
- "from": from,
- "to": to,
- }
-
- r := c.c.NewRequest("POST", "/v1/sys/remount")
- if err := r.SetJSONBody(body); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) TuneMount(path string, config MountConfigInput) error {
- r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/mounts/%s/tune", path))
- if err := r.SetJSONBody(config); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) MountConfig(path string) (*MountConfigOutput, error) {
- r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/mounts/%s/tune", path))
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- var result MountConfigOutput
- err = mapstructure.Decode(secret.Data, &result)
- if err != nil {
- return nil, err
- }
-
- return &result, err
-}
-
-type MountInput struct {
- Type string `json:"type"`
- Description string `json:"description"`
- Config MountConfigInput `json:"config"`
- Local bool `json:"local"`
- SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
- Options map[string]string `json:"options"`
-
- // Deprecated: Newer server responses should be returning this information in the
- // Type field (json: "type") instead.
- PluginName string `json:"plugin_name,omitempty"`
-}
-
-type MountConfigInput struct {
- Options map[string]string `json:"options" mapstructure:"options"`
- DefaultLeaseTTL string `json:"default_lease_ttl" mapstructure:"default_lease_ttl"`
- Description *string `json:"description,omitempty" mapstructure:"description"`
- MaxLeaseTTL string `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
- ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"`
- AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"`
- AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"`
- ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"`
- PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"`
- AllowedResponseHeaders []string `json:"allowed_response_headers,omitempty" mapstructure:"allowed_response_headers"`
- TokenType string `json:"token_type,omitempty" mapstructure:"token_type"`
-
- // Deprecated: This field will always be blank for newer server responses.
- PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
-}
-
-type MountOutput struct {
- UUID string `json:"uuid"`
- Type string `json:"type"`
- Description string `json:"description"`
- Accessor string `json:"accessor"`
- Config MountConfigOutput `json:"config"`
- Options map[string]string `json:"options"`
- Local bool `json:"local"`
- SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
-}
-
-type MountConfigOutput struct {
- DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"`
- MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
- ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"`
- AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"`
- AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"`
- ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"`
- PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"`
- AllowedResponseHeaders []string `json:"allowed_response_headers,omitempty" mapstructure:"allowed_response_headers"`
- TokenType string `json:"token_type,omitempty" mapstructure:"token_type"`
-
- // Deprecated: This field will always be blank for newer server responses.
- PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_plugins.go b/vendor/github.com/hashicorp/vault/api/sys_plugins.go
deleted file mode 100644
index 0ab022ba094..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_plugins.go
+++ /dev/null
@@ -1,238 +0,0 @@
-package api
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
-
- "github.com/hashicorp/vault/sdk/helper/consts"
- "github.com/mitchellh/mapstructure"
-)
-
-// ListPluginsInput is used as input to the ListPlugins function.
-type ListPluginsInput struct {
- // Type of the plugin. Required.
- Type consts.PluginType `json:"type"`
-}
-
-// ListPluginsResponse is the response from the ListPlugins call.
-type ListPluginsResponse struct {
- // PluginsByType is the list of plugins by type.
- PluginsByType map[consts.PluginType][]string `json:"types"`
-
- // Names is the list of names of the plugins.
- //
- // Deprecated: Newer server responses should be returning PluginsByType (json:
- // "types") instead.
- Names []string `json:"names"`
-}
-
-// ListPlugins lists all plugins in the catalog and returns their names as a
-// list of strings.
-func (c *Sys) ListPlugins(i *ListPluginsInput) (*ListPluginsResponse, error) {
- path := ""
- method := ""
- if i.Type == consts.PluginTypeUnknown {
- path = "/v1/sys/plugins/catalog"
- method = "GET"
- } else {
- path = fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Type)
- method = "LIST"
- }
-
- req := c.c.NewRequest(method, path)
- if method == "LIST" {
- // Set this for broader compatibility, but we use LIST above to be able
- // to handle the wrapping lookup function
- req.Method = "GET"
- req.Params.Set("list", "true")
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, req)
- if err != nil && resp == nil {
- return nil, err
- }
- if resp == nil {
- return nil, nil
- }
- defer resp.Body.Close()
-
- // We received an Unsupported Operation response from Vault, indicating
- // Vault of an older version that doesn't support the GET method yet;
- // switch it to a LIST.
- if resp.StatusCode == 405 {
- req.Params.Set("list", "true")
- resp, err := c.c.RawRequestWithContext(ctx, req)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- var result struct {
- Data struct {
- Keys []string `json:"keys"`
- } `json:"data"`
- }
- if err := resp.DecodeJSON(&result); err != nil {
- return nil, err
- }
- return &ListPluginsResponse{Names: result.Data.Keys}, nil
- }
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- result := &ListPluginsResponse{
- PluginsByType: make(map[consts.PluginType][]string),
- }
- if i.Type == consts.PluginTypeUnknown {
- for pluginTypeStr, pluginsRaw := range secret.Data {
- pluginType, err := consts.ParsePluginType(pluginTypeStr)
- if err != nil {
- return nil, err
- }
-
- pluginsIfc, ok := pluginsRaw.([]interface{})
- if !ok {
- return nil, fmt.Errorf("unable to parse plugins for %q type", pluginTypeStr)
- }
-
- plugins := make([]string, len(pluginsIfc))
- for i, nameIfc := range pluginsIfc {
- name, ok := nameIfc.(string)
- if !ok {
-
- }
- plugins[i] = name
- }
- result.PluginsByType[pluginType] = plugins
- }
- } else {
- var respKeys []string
- if err := mapstructure.Decode(secret.Data["keys"], &respKeys); err != nil {
- return nil, err
- }
- result.PluginsByType[i.Type] = respKeys
- }
-
- return result, nil
-}
-
-// GetPluginInput is used as input to the GetPlugin function.
-type GetPluginInput struct {
- Name string `json:"-"`
-
- // Type of the plugin. Required.
- Type consts.PluginType `json:"type"`
-}
-
-// GetPluginResponse is the response from the GetPlugin call.
-type GetPluginResponse struct {
- Args []string `json:"args"`
- Builtin bool `json:"builtin"`
- Command string `json:"command"`
- Name string `json:"name"`
- SHA256 string `json:"sha256"`
-}
-
-// GetPlugin retrieves information about the plugin.
-func (c *Sys) GetPlugin(i *GetPluginInput) (*GetPluginResponse, error) {
- path := catalogPathByType(i.Type, i.Name)
- req := c.c.NewRequest(http.MethodGet, path)
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, req)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result struct {
- Data *GetPluginResponse
- }
- err = resp.DecodeJSON(&result)
- if err != nil {
- return nil, err
- }
- return result.Data, err
-}
-
-// RegisterPluginInput is used as input to the RegisterPlugin function.
-type RegisterPluginInput struct {
- // Name is the name of the plugin. Required.
- Name string `json:"-"`
-
- // Type of the plugin. Required.
- Type consts.PluginType `json:"type"`
-
- // Args is the list of args to spawn the process with.
- Args []string `json:"args,omitempty"`
-
- // Command is the command to run.
- Command string `json:"command,omitempty"`
-
- // SHA256 is the shasum of the plugin.
- SHA256 string `json:"sha256,omitempty"`
-}
-
-// RegisterPlugin registers the plugin with the given information.
-func (c *Sys) RegisterPlugin(i *RegisterPluginInput) error {
- path := catalogPathByType(i.Type, i.Name)
- req := c.c.NewRequest(http.MethodPut, path)
-
- if err := req.SetJSONBody(i); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, req)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-// DeregisterPluginInput is used as input to the DeregisterPlugin function.
-type DeregisterPluginInput struct {
- // Name is the name of the plugin. Required.
- Name string `json:"-"`
-
- // Type of the plugin. Required.
- Type consts.PluginType `json:"type"`
-}
-
-// DeregisterPlugin removes the plugin with the given name from the plugin
-// catalog.
-func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error {
- path := catalogPathByType(i.Type, i.Name)
- req := c.c.NewRequest(http.MethodDelete, path)
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, req)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-// catalogPathByType is a helper to construct the proper API path by plugin type
-func catalogPathByType(pluginType consts.PluginType, name string) string {
- path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", pluginType, name)
-
- // Backwards compat, if type is not provided then use old path
- if pluginType == consts.PluginTypeUnknown {
- path = fmt.Sprintf("/v1/sys/plugins/catalog/%s", name)
- }
-
- return path
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_policy.go b/vendor/github.com/hashicorp/vault/api/sys_policy.go
deleted file mode 100644
index c0c239f960c..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_policy.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package api
-
-import (
- "context"
- "errors"
- "fmt"
-
- "github.com/mitchellh/mapstructure"
-)
-
-func (c *Sys) ListPolicies() ([]string, error) {
- r := c.c.NewRequest("LIST", "/v1/sys/policies/acl")
- // Set this for broader compatibility, but we use LIST above to be able to
- // handle the wrapping lookup function
- r.Method = "GET"
- r.Params.Set("list", "true")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- var result []string
- err = mapstructure.Decode(secret.Data["keys"], &result)
- if err != nil {
- return nil, err
- }
-
- return result, err
-}
-
-func (c *Sys) GetPolicy(name string) (string, error) {
- r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/policies/acl/%s", name))
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if resp != nil {
- defer resp.Body.Close()
- if resp.StatusCode == 404 {
- return "", nil
- }
- }
- if err != nil {
- return "", err
- }
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return "", err
- }
- if secret == nil || secret.Data == nil {
- return "", errors.New("data from server response is empty")
- }
-
- if policyRaw, ok := secret.Data["policy"]; ok {
- return policyRaw.(string), nil
- }
-
- return "", fmt.Errorf("no policy found in response")
-}
-
-func (c *Sys) PutPolicy(name, rules string) error {
- body := map[string]string{
- "policy": rules,
- }
-
- r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/policies/acl/%s", name))
- if err := r.SetJSONBody(body); err != nil {
- return err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return nil
-}
-
-func (c *Sys) DeletePolicy(name string) error {
- r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/policies/acl/%s", name))
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-type getPoliciesResp struct {
- Rules string `json:"rules"`
-}
-
-type listPoliciesResp struct {
- Policies []string `json:"policies"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_raft.go b/vendor/github.com/hashicorp/vault/api/sys_raft.go
deleted file mode 100644
index 6897dc0a7eb..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_raft.go
+++ /dev/null
@@ -1,130 +0,0 @@
-package api
-
-import (
- "context"
- "io"
- "net/http"
-
- "github.com/hashicorp/vault/sdk/helper/consts"
-)
-
-// RaftJoinResponse represents the response of the raft join API
-type RaftJoinResponse struct {
- Joined bool `json:"joined"`
-}
-
-// RaftJoinRequest represents the parameters consumed by the raft join API
-type RaftJoinRequest struct {
- LeaderAPIAddr string `json:"leader_api_addr"`
- LeaderCACert string `json:"leader_ca_cert":`
- LeaderClientCert string `json:"leader_client_cert"`
- LeaderClientKey string `json:"leader_client_key"`
- Retry bool `json:"retry"`
-}
-
-// RaftJoin adds the node from which this call is invoked from to the raft
-// cluster represented by the leader address in the parameter.
-func (c *Sys) RaftJoin(opts *RaftJoinRequest) (*RaftJoinResponse, error) {
- r := c.c.NewRequest("POST", "/v1/sys/storage/raft/join")
-
- if err := r.SetJSONBody(opts); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RaftJoinResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-// RaftSnapshot invokes the API that takes the snapshot of the raft cluster and
-// writes it to the supplied io.Writer.
-func (c *Sys) RaftSnapshot(snapWriter io.Writer) error {
- r := c.c.NewRequest("GET", "/v1/sys/storage/raft/snapshot")
- r.URL.RawQuery = r.Params.Encode()
-
- req, err := http.NewRequest(http.MethodGet, r.URL.RequestURI(), nil)
- if err != nil {
- return err
- }
-
- req.URL.User = r.URL.User
- req.URL.Scheme = r.URL.Scheme
- req.URL.Host = r.URL.Host
- req.Host = r.URL.Host
-
- if r.Headers != nil {
- for header, vals := range r.Headers {
- for _, val := range vals {
- req.Header.Add(header, val)
- }
- }
- }
-
- if len(r.ClientToken) != 0 {
- req.Header.Set(consts.AuthHeaderName, r.ClientToken)
- }
-
- if len(r.WrapTTL) != 0 {
- req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL)
- }
-
- if len(r.MFAHeaderVals) != 0 {
- for _, mfaHeaderVal := range r.MFAHeaderVals {
- req.Header.Add("X-Vault-MFA", mfaHeaderVal)
- }
- }
-
- if r.PolicyOverride {
- req.Header.Set("X-Vault-Policy-Override", "true")
- }
-
- // Avoiding the use of RawRequestWithContext which reads the response body
- // to determine if the body contains error message.
- var result *Response
- resp, err := c.c.config.HttpClient.Do(req)
- if resp == nil {
- return nil
- }
-
- result = &Response{Response: resp}
- if err := result.Error(); err != nil {
- return err
- }
-
- _, err = io.Copy(snapWriter, resp.Body)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// RaftSnapshotRestore reads the snapshot from the io.Reader and installs that
-// snapshot, returning the cluster to the state defined by it.
-func (c *Sys) RaftSnapshotRestore(snapReader io.Reader, force bool) error {
- path := "/v1/sys/storage/raft/snapshot"
- if force {
- path = "/v1/sys/storage/raft/snapshot-force"
- }
- r := c.c.NewRequest("POST", path)
-
- r.Body = snapReader
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
-
- return nil
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_rekey.go b/vendor/github.com/hashicorp/vault/api/sys_rekey.go
deleted file mode 100644
index 153e486c6d6..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_rekey.go
+++ /dev/null
@@ -1,388 +0,0 @@
-package api
-
-import (
- "context"
- "errors"
-
- "github.com/mitchellh/mapstructure"
-)
-
-func (c *Sys) RekeyStatus() (*RekeyStatusResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/rekey/init")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) RekeyRecoveryKeyStatus() (*RekeyStatusResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/rekey-recovery-key/init")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) RekeyVerificationStatus() (*RekeyVerificationStatusResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/rekey/verify")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyVerificationStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) RekeyRecoveryKeyVerificationStatus() (*RekeyVerificationStatusResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/rekey-recovery-key/verify")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyVerificationStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) RekeyInit(config *RekeyInitRequest) (*RekeyStatusResponse, error) {
- r := c.c.NewRequest("PUT", "/v1/sys/rekey/init")
- if err := r.SetJSONBody(config); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) RekeyRecoveryKeyInit(config *RekeyInitRequest) (*RekeyStatusResponse, error) {
- r := c.c.NewRequest("PUT", "/v1/sys/rekey-recovery-key/init")
- if err := r.SetJSONBody(config); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) RekeyCancel() error {
- r := c.c.NewRequest("DELETE", "/v1/sys/rekey/init")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) RekeyRecoveryKeyCancel() error {
- r := c.c.NewRequest("DELETE", "/v1/sys/rekey-recovery-key/init")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) RekeyVerificationCancel() error {
- r := c.c.NewRequest("DELETE", "/v1/sys/rekey/verify")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) RekeyRecoveryKeyVerificationCancel() error {
- r := c.c.NewRequest("DELETE", "/v1/sys/rekey-recovery-key/verify")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) RekeyUpdate(shard, nonce string) (*RekeyUpdateResponse, error) {
- body := map[string]interface{}{
- "key": shard,
- "nonce": nonce,
- }
-
- r := c.c.NewRequest("PUT", "/v1/sys/rekey/update")
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyUpdateResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) RekeyRecoveryKeyUpdate(shard, nonce string) (*RekeyUpdateResponse, error) {
- body := map[string]interface{}{
- "key": shard,
- "nonce": nonce,
- }
-
- r := c.c.NewRequest("PUT", "/v1/sys/rekey-recovery-key/update")
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyUpdateResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) RekeyRetrieveBackup() (*RekeyRetrieveResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/rekey/backup")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- var result RekeyRetrieveResponse
- err = mapstructure.Decode(secret.Data, &result)
- if err != nil {
- return nil, err
- }
-
- return &result, err
-}
-
-func (c *Sys) RekeyRetrieveRecoveryBackup() (*RekeyRetrieveResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/rekey/recovery-key-backup")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- var result RekeyRetrieveResponse
- err = mapstructure.Decode(secret.Data, &result)
- if err != nil {
- return nil, err
- }
-
- return &result, err
-}
-
-func (c *Sys) RekeyDeleteBackup() error {
- r := c.c.NewRequest("DELETE", "/v1/sys/rekey/backup")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
-
- return err
-}
-
-func (c *Sys) RekeyDeleteRecoveryBackup() error {
- r := c.c.NewRequest("DELETE", "/v1/sys/rekey/recovery-key-backup")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
-
- return err
-}
-
-func (c *Sys) RekeyVerificationUpdate(shard, nonce string) (*RekeyVerificationUpdateResponse, error) {
- body := map[string]interface{}{
- "key": shard,
- "nonce": nonce,
- }
-
- r := c.c.NewRequest("PUT", "/v1/sys/rekey/verify")
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyVerificationUpdateResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-func (c *Sys) RekeyRecoveryKeyVerificationUpdate(shard, nonce string) (*RekeyVerificationUpdateResponse, error) {
- body := map[string]interface{}{
- "key": shard,
- "nonce": nonce,
- }
-
- r := c.c.NewRequest("PUT", "/v1/sys/rekey-recovery-key/verify")
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result RekeyVerificationUpdateResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-type RekeyInitRequest struct {
- SecretShares int `json:"secret_shares"`
- SecretThreshold int `json:"secret_threshold"`
- StoredShares int `json:"stored_shares"`
- PGPKeys []string `json:"pgp_keys"`
- Backup bool
- RequireVerification bool `json:"require_verification"`
-}
-
-type RekeyStatusResponse struct {
- Nonce string `json:"nonce"`
- Started bool `json:"started"`
- T int `json:"t"`
- N int `json:"n"`
- Progress int `json:"progress"`
- Required int `json:"required"`
- PGPFingerprints []string `json:"pgp_fingerprints"`
- Backup bool `json:"backup"`
- VerificationRequired bool `json:"verification_required"`
- VerificationNonce string `json:"verification_nonce"`
-}
-
-type RekeyUpdateResponse struct {
- Nonce string `json:"nonce"`
- Complete bool `json:"complete"`
- Keys []string `json:"keys"`
- KeysB64 []string `json:"keys_base64"`
- PGPFingerprints []string `json:"pgp_fingerprints"`
- Backup bool `json:"backup"`
- VerificationRequired bool `json:"verification_required"`
- VerificationNonce string `json:"verification_nonce,omitempty"`
-}
-
-type RekeyRetrieveResponse struct {
- Nonce string `json:"nonce" mapstructure:"nonce"`
- Keys map[string][]string `json:"keys" mapstructure:"keys"`
- KeysB64 map[string][]string `json:"keys_base64" mapstructure:"keys_base64"`
-}
-
-type RekeyVerificationStatusResponse struct {
- Nonce string `json:"nonce"`
- Started bool `json:"started"`
- T int `json:"t"`
- N int `json:"n"`
- Progress int `json:"progress"`
-}
-
-type RekeyVerificationUpdateResponse struct {
- Nonce string `json:"nonce"`
- Complete bool `json:"complete"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_rotate.go b/vendor/github.com/hashicorp/vault/api/sys_rotate.go
deleted file mode 100644
index c525feb00d3..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_rotate.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package api
-
-import (
- "context"
- "encoding/json"
- "errors"
- "time"
-)
-
-func (c *Sys) Rotate() error {
- r := c.c.NewRequest("POST", "/v1/sys/rotate")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) KeyStatus() (*KeyStatus, error) {
- r := c.c.NewRequest("GET", "/v1/sys/key-status")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- secret, err := ParseSecret(resp.Body)
- if err != nil {
- return nil, err
- }
- if secret == nil || secret.Data == nil {
- return nil, errors.New("data from server response is empty")
- }
-
- var result KeyStatus
-
- termRaw, ok := secret.Data["term"]
- if !ok {
- return nil, errors.New("term not found in response")
- }
- term, ok := termRaw.(json.Number)
- if !ok {
- return nil, errors.New("could not convert term to a number")
- }
- term64, err := term.Int64()
- if err != nil {
- return nil, err
- }
- result.Term = int(term64)
-
- installTimeRaw, ok := secret.Data["install_time"]
- if !ok {
- return nil, errors.New("install_time not found in response")
- }
- installTimeStr, ok := installTimeRaw.(string)
- if !ok {
- return nil, errors.New("could not convert install_time to a string")
- }
- installTime, err := time.Parse(time.RFC3339Nano, installTimeStr)
- if err != nil {
- return nil, err
- }
- result.InstallTime = installTime
-
- return &result, err
-}
-
-type KeyStatus struct {
- Term int `json:"term"`
- InstallTime time.Time `json:"install_time"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_seal.go b/vendor/github.com/hashicorp/vault/api/sys_seal.go
deleted file mode 100644
index 301d3f26a10..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_seal.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package api
-
-import "context"
-
-func (c *Sys) SealStatus() (*SealStatusResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/seal-status")
- return sealStatusRequest(c, r)
-}
-
-func (c *Sys) Seal() error {
- r := c.c.NewRequest("PUT", "/v1/sys/seal")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err == nil {
- defer resp.Body.Close()
- }
- return err
-}
-
-func (c *Sys) ResetUnsealProcess() (*SealStatusResponse, error) {
- body := map[string]interface{}{"reset": true}
-
- r := c.c.NewRequest("PUT", "/v1/sys/unseal")
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- return sealStatusRequest(c, r)
-}
-
-func (c *Sys) Unseal(shard string) (*SealStatusResponse, error) {
- body := map[string]interface{}{"key": shard}
-
- r := c.c.NewRequest("PUT", "/v1/sys/unseal")
- if err := r.SetJSONBody(body); err != nil {
- return nil, err
- }
-
- return sealStatusRequest(c, r)
-}
-
-func (c *Sys) UnsealWithOptions(opts *UnsealOpts) (*SealStatusResponse, error) {
- r := c.c.NewRequest("PUT", "/v1/sys/unseal")
- if err := r.SetJSONBody(opts); err != nil {
- return nil, err
- }
-
- return sealStatusRequest(c, r)
-}
-
-func sealStatusRequest(c *Sys, r *Request) (*SealStatusResponse, error) {
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- var result SealStatusResponse
- err = resp.DecodeJSON(&result)
- return &result, err
-}
-
-type SealStatusResponse struct {
- Type string `json:"type"`
- Initialized bool `json:"initialized"`
- Sealed bool `json:"sealed"`
- T int `json:"t"`
- N int `json:"n"`
- Progress int `json:"progress"`
- Nonce string `json:"nonce"`
- Version string `json:"version"`
- Migration bool `json:"migration"`
- ClusterName string `json:"cluster_name,omitempty"`
- ClusterID string `json:"cluster_id,omitempty"`
- RecoverySeal bool `json:"recovery_seal"`
-}
-
-type UnsealOpts struct {
- Key string `json:"key"`
- Reset bool `json:"reset"`
- Migrate bool `json:"migrate"`
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_stepdown.go b/vendor/github.com/hashicorp/vault/api/sys_stepdown.go
deleted file mode 100644
index 55dc6fbcb7b..00000000000
--- a/vendor/github.com/hashicorp/vault/api/sys_stepdown.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package api
-
-import "context"
-
-func (c *Sys) StepDown() error {
- r := c.c.NewRequest("PUT", "/v1/sys/step-down")
-
- ctx, cancelFunc := context.WithCancel(context.Background())
- defer cancelFunc()
- resp, err := c.c.RawRequestWithContext(ctx, r)
- if resp != nil && resp.Body != nil {
- resp.Body.Close()
- }
- return err
-}
diff --git a/vendor/github.com/hashicorp/vault/sdk/LICENSE b/vendor/github.com/hashicorp/vault/sdk/LICENSE
deleted file mode 100644
index e87a115e462..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/LICENSE
+++ /dev/null
@@ -1,363 +0,0 @@
-Mozilla Public License, version 2.0
-
-1. Definitions
-
-1.1. "Contributor"
-
- means each individual or legal entity that creates, contributes to the
- creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-
- means the combination of the Contributions of others (if any) used by a
- Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-
- means Source Code Form to which the initial Contributor has attached the
- notice in Exhibit A, the Executable Form of such Source Code Form, and
- Modifications of such Source Code Form, in each case including portions
- thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- a. that the initial Contributor has attached the notice described in
- Exhibit B to the Covered Software; or
-
- b. that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the terms of
- a Secondary License.
-
-1.6. "Executable Form"
-
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-
- means a work that combines Covered Software with other material, in a
- separate file or files, that is not Covered Software.
-
-1.8. "License"
-
- means this document.
-
-1.9. "Licensable"
-
- means having the right to grant, to the maximum extent possible, whether
- at the time of the initial grant or subsequently, any and all of the
- rights conveyed by this License.
-
-1.10. "Modifications"
-
- means any of the following:
-
- a. any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered Software; or
-
- b. any new file in Source Code Form that contains any Covered Software.
-
-1.11. "Patent Claims" of a Contributor
-
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the License,
- by the making, using, selling, offering for sale, having made, import,
- or transfer of either its Contributions or its Contributor Version.
-
-1.12. "Secondary License"
-
- means either the GNU General Public License, Version 2.0, the GNU Lesser
- General Public License, Version 2.1, the GNU Affero General Public
- License, Version 3.0, or any later versions of those licenses.
-
-1.13. "Source Code Form"
-
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that controls, is
- controlled by, or is under common control with You. For purposes of this
- definition, "control" means (a) the power, direct or indirect, to cause
- the direction or management of such entity, whether by contract or
- otherwise, or (b) ownership of more than fifty percent (50%) of the
- outstanding shares or beneficial ownership of such entity.
-
-
-2. License Grants and Conditions
-
-2.1. Grants
-
- Each Contributor hereby grants You a world-wide, royalty-free,
- non-exclusive license:
-
- a. under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
- b. under Patent Claims of such Contributor to make, use, sell, offer for
- sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
- The licenses granted in Section 2.1 with respect to any Contribution
- become effective for each Contribution on the date the Contributor first
- distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
- The licenses granted in this Section 2 are the only rights granted under
- this License. No additional rights or licenses will be implied from the
- distribution or licensing of Covered Software under this License.
- Notwithstanding Section 2.1(b) above, no patent license is granted by a
- Contributor:
-
- a. for any code that a Contributor has removed from Covered Software; or
-
- b. for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
- c. under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
- This License does not grant any rights in the trademarks, service marks,
- or logos of any Contributor (except as may be necessary to comply with
- the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
- No Contributor makes additional grants as a result of Your choice to
- distribute the Covered Software under a subsequent version of this
- License (see Section 10.2) or under the terms of a Secondary License (if
- permitted under the terms of Section 3.3).
-
-2.5. Representation
-
- Each Contributor represents that the Contributor believes its
- Contributions are its original creation(s) or it has sufficient rights to
- grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
- This License is not intended to limit any rights You have under
- applicable copyright doctrines of fair use, fair dealing, or other
- equivalents.
-
-2.7. Conditions
-
- Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
- Section 2.1.
-
-
-3. Responsibilities
-
-3.1. Distribution of Source Form
-
- All distribution of Covered Software in Source Code Form, including any
- Modifications that You create or to which You contribute, must be under
- the terms of this License. You must inform recipients that the Source
- Code Form of the Covered Software is governed by the terms of this
- License, and how they can obtain a copy of this License. You may not
- attempt to alter or restrict the recipients' rights in the Source Code
- Form.
-
-3.2. Distribution of Executable Form
-
- If You distribute Covered Software in Executable Form then:
-
- a. such Covered Software must also be made available in Source Code Form,
- as described in Section 3.1, and You must inform recipients of the
- Executable Form how they can obtain a copy of such Source Code Form by
- reasonable means in a timely manner, at a charge no more than the cost
- of distribution to the recipient; and
-
- b. You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter the
- recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
- You may create and distribute a Larger Work under terms of Your choice,
- provided that You also comply with the requirements of this License for
- the Covered Software. If the Larger Work is a combination of Covered
- Software with a work governed by one or more Secondary Licenses, and the
- Covered Software is not Incompatible With Secondary Licenses, this
- License permits You to additionally distribute such Covered Software
- under the terms of such Secondary License(s), so that the recipient of
- the Larger Work may, at their option, further distribute the Covered
- Software under the terms of either this License or such Secondary
- License(s).
-
-3.4. Notices
-
- You may not remove or alter the substance of any license notices
- (including copyright notices, patent notices, disclaimers of warranty, or
- limitations of liability) contained within the Source Code Form of the
- Covered Software, except that You may alter any license notices to the
- extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
- You may choose to offer, and to charge a fee for, warranty, support,
- indemnity or liability obligations to one or more recipients of Covered
- Software. However, You may do so only on Your own behalf, and not on
- behalf of any Contributor. You must make it absolutely clear that any
- such warranty, support, indemnity, or liability obligation is offered by
- You alone, and You hereby agree to indemnify every Contributor for any
- liability incurred by such Contributor as a result of warranty, support,
- indemnity or liability terms You offer. You may include additional
- disclaimers of warranty and limitations of liability specific to any
- jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
-
- If it is impossible for You to comply with any of the terms of this License
- with respect to some or all of the Covered Software due to statute,
- judicial order, or regulation then You must: (a) comply with the terms of
- this License to the maximum extent possible; and (b) describe the
- limitations and the code they affect. Such description must be placed in a
- text file included with all distributions of the Covered Software under
- this License. Except to the extent prohibited by statute or regulation,
- such description must be sufficiently detailed for a recipient of ordinary
- skill to be able to understand it.
-
-5. Termination
-
-5.1. The rights granted under this License will terminate automatically if You
- fail to comply with any of its terms. However, if You become compliant,
- then the rights granted under this License from a particular Contributor
- are reinstated (a) provisionally, unless and until such Contributor
- explicitly and finally terminates Your grants, and (b) on an ongoing
- basis, if such Contributor fails to notify You of the non-compliance by
- some reasonable means prior to 60 days after You have come back into
- compliance. Moreover, Your grants from a particular Contributor are
- reinstated on an ongoing basis if such Contributor notifies You of the
- non-compliance by some reasonable means, this is the first time You have
- received notice of non-compliance with this License from such
- Contributor, and You become compliant prior to 30 days after Your receipt
- of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
- infringement claim (excluding declaratory judgment actions,
- counter-claims, and cross-claims) alleging that a Contributor Version
- directly or indirectly infringes any patent, then the rights granted to
- You by any and all Contributors for the Covered Software under Section
- 2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
- license agreements (excluding distributors and resellers) which have been
- validly granted by You or Your distributors under this License prior to
- termination shall survive termination.
-
-6. Disclaimer of Warranty
-
- Covered Software is provided under this License on an "as is" basis,
- without warranty of any kind, either expressed, implied, or statutory,
- including, without limitation, warranties that the Covered Software is free
- of defects, merchantable, fit for a particular purpose or non-infringing.
- The entire risk as to the quality and performance of the Covered Software
- is with You. Should any Covered Software prove defective in any respect,
- You (not any Contributor) assume the cost of any necessary servicing,
- repair, or correction. This disclaimer of warranty constitutes an essential
- part of this License. No use of any Covered Software is authorized under
- this License except under this disclaimer.
-
-7. Limitation of Liability
-
- Under no circumstances and under no legal theory, whether tort (including
- negligence), contract, or otherwise, shall any Contributor, or anyone who
- distributes Covered Software as permitted above, be liable to You for any
- direct, indirect, special, incidental, or consequential damages of any
- character including, without limitation, damages for lost profits, loss of
- goodwill, work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses, even if such party shall have been
- informed of the possibility of such damages. This limitation of liability
- shall not apply to liability for death or personal injury resulting from
- such party's negligence to the extent applicable law prohibits such
- limitation. Some jurisdictions do not allow the exclusion or limitation of
- incidental or consequential damages, so this exclusion and limitation may
- not apply to You.
-
-8. Litigation
-
- Any litigation relating to this License may be brought only in the courts
- of a jurisdiction where the defendant maintains its principal place of
- business and such litigation shall be governed by laws of that
- jurisdiction, without reference to its conflict-of-law provisions. Nothing
- in this Section shall prevent a party's ability to bring cross-claims or
- counter-claims.
-
-9. Miscellaneous
-
- This License represents the complete agreement concerning the subject
- matter hereof. If any provision of this License is held to be
- unenforceable, such provision shall be reformed only to the extent
- necessary to make it enforceable. Any law or regulation which provides that
- the language of a contract shall be construed against the drafter shall not
- be used to construe this License against a Contributor.
-
-
-10. Versions of the License
-
-10.1. New Versions
-
- Mozilla Foundation is the license steward. Except as provided in Section
- 10.3, no one other than the license steward has the right to modify or
- publish new versions of this License. Each version will be given a
- distinguishing version number.
-
-10.2. Effect of New Versions
-
- You may distribute the Covered Software under the terms of the version
- of the License under which You originally received the Covered Software,
- or under the terms of any subsequent version published by the license
- steward.
-
-10.3. Modified Versions
-
- If you create software not governed by this License, and you want to
- create a new license for such software, you may create and use a
- modified version of this License if you rename the license and remove
- any references to the name of the license steward (except to note that
- such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
- Licenses If You choose to distribute Source Code Form that is
- Incompatible With Secondary Licenses under the terms of this version of
- the License, the notice described in Exhibit B of this License must be
- attached.
-
-Exhibit A - Source Code Form License Notice
-
- This Source Code Form is subject to the
- terms of the Mozilla Public License, v.
- 2.0. If a copy of the MPL was not
- distributed with this file, You can
- obtain one at
- http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular file,
-then You may include the notice in a location (such as a LICENSE file in a
-relevant directory) where a recipient would be likely to look for such a
-notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
-
- This Source Code Form is "Incompatible
- With Secondary Licenses", as defined by
- the Mozilla Public License, v. 2.0.
-
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/compressutil/compress.go b/vendor/github.com/hashicorp/vault/sdk/helper/compressutil/compress.go
deleted file mode 100644
index 356d4548fa4..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/compressutil/compress.go
+++ /dev/null
@@ -1,207 +0,0 @@
-package compressutil
-
-import (
- "bytes"
- "compress/gzip"
- "compress/lzw"
- "fmt"
- "io"
-
- "github.com/golang/snappy"
- "github.com/hashicorp/errwrap"
- "github.com/pierrec/lz4"
-)
-
-const (
- // A byte value used as a canary prefix for the compressed information
- // which is used to distinguish if a JSON input is compressed or not.
- // The value of this constant should not be a first character of any
- // valid JSON string.
-
- CompressionTypeGzip = "gzip"
- CompressionCanaryGzip byte = 'G'
-
- CompressionTypeLZW = "lzw"
- CompressionCanaryLZW byte = 'L'
-
- CompressionTypeSnappy = "snappy"
- CompressionCanarySnappy byte = 'S'
-
- CompressionTypeLZ4 = "lz4"
- CompressionCanaryLZ4 byte = '4'
-)
-
-// SnappyReadCloser embeds the snappy reader which implements the io.Reader
-// interface. The decompress procedure in this utility expects an
-// io.ReadCloser. This type implements the io.Closer interface to retain the
-// generic way of decompression.
-type CompressUtilReadCloser struct {
- io.Reader
-}
-
-// Close is a noop method implemented only to satisfy the io.Closer interface
-func (c *CompressUtilReadCloser) Close() error {
- return nil
-}
-
-// CompressionConfig is used to select a compression type to be performed by
-// Compress and Decompress utilities.
-// Supported types are:
-// * CompressionTypeLZW
-// * CompressionTypeGzip
-// * CompressionTypeSnappy
-// * CompressionTypeLZ4
-//
-// When using CompressionTypeGzip, the compression levels can also be chosen:
-// * gzip.DefaultCompression
-// * gzip.BestSpeed
-// * gzip.BestCompression
-type CompressionConfig struct {
- // Type of the compression algorithm to be used
- Type string
-
- // When using Gzip format, the compression level to employ
- GzipCompressionLevel int
-}
-
-// Compress places the canary byte in a buffer and uses the same buffer to fill
-// in the compressed information of the given input. The configuration supports
-// two type of compression: LZW and Gzip. When using Gzip compression format,
-// if GzipCompressionLevel is not specified, the 'gzip.DefaultCompression' will
-// be assumed.
-func Compress(data []byte, config *CompressionConfig) ([]byte, error) {
- var buf bytes.Buffer
- var writer io.WriteCloser
- var err error
-
- if config == nil {
- return nil, fmt.Errorf("config is nil")
- }
-
- // Write the canary into the buffer and create writer to compress the
- // input data based on the configured type
- switch config.Type {
- case CompressionTypeLZW:
- buf.Write([]byte{CompressionCanaryLZW})
- writer = lzw.NewWriter(&buf, lzw.LSB, 8)
-
- case CompressionTypeGzip:
- buf.Write([]byte{CompressionCanaryGzip})
-
- switch {
- case config.GzipCompressionLevel == gzip.BestCompression,
- config.GzipCompressionLevel == gzip.BestSpeed,
- config.GzipCompressionLevel == gzip.DefaultCompression:
- // These are valid compression levels
- default:
- // If compression level is set to NoCompression or to
- // any invalid value, fallback to Defaultcompression
- config.GzipCompressionLevel = gzip.DefaultCompression
- }
- writer, err = gzip.NewWriterLevel(&buf, config.GzipCompressionLevel)
-
- case CompressionTypeSnappy:
- buf.Write([]byte{CompressionCanarySnappy})
- writer = snappy.NewBufferedWriter(&buf)
-
- case CompressionTypeLZ4:
- buf.Write([]byte{CompressionCanaryLZ4})
- writer = lz4.NewWriter(&buf)
-
- default:
- return nil, fmt.Errorf("unsupported compression type")
- }
-
- if err != nil {
- return nil, errwrap.Wrapf("failed to create a compression writer: {{err}}", err)
- }
-
- if writer == nil {
- return nil, fmt.Errorf("failed to create a compression writer")
- }
-
- // Compress the input and place it in the same buffer containing the
- // canary byte.
- if _, err = writer.Write(data); err != nil {
- return nil, errwrap.Wrapf("failed to compress input data: err: {{err}}", err)
- }
-
- // Close the io.WriteCloser
- if err = writer.Close(); err != nil {
- return nil, err
- }
-
- // Return the compressed bytes with canary byte at the start
- return buf.Bytes(), nil
-}
-
-// Decompress checks if the first byte in the input matches the canary byte.
-// If the first byte is a canary byte, then the input past the canary byte
-// will be decompressed using the method specified in the given configuration.
-// If the first byte isn't a canary byte, then the utility returns a boolean
-// value indicating that the input was not compressed.
-func Decompress(data []byte) ([]byte, bool, error) {
- var err error
- var reader io.ReadCloser
- if data == nil || len(data) == 0 {
- return nil, false, fmt.Errorf("'data' being decompressed is empty")
- }
-
- canary := data[0]
- cData := data[1:]
-
- switch canary {
- // If the first byte matches the canary byte, remove the canary
- // byte and try to decompress the data that is after the canary.
- case CompressionCanaryGzip:
- if len(data) < 2 {
- return nil, false, fmt.Errorf("invalid 'data' after the canary")
- }
- reader, err = gzip.NewReader(bytes.NewReader(cData))
-
- case CompressionCanaryLZW:
- if len(data) < 2 {
- return nil, false, fmt.Errorf("invalid 'data' after the canary")
- }
- reader = lzw.NewReader(bytes.NewReader(cData), lzw.LSB, 8)
-
- case CompressionCanarySnappy:
- if len(data) < 2 {
- return nil, false, fmt.Errorf("invalid 'data' after the canary")
- }
- reader = &CompressUtilReadCloser{
- Reader: snappy.NewReader(bytes.NewReader(cData)),
- }
-
- case CompressionCanaryLZ4:
- if len(data) < 2 {
- return nil, false, fmt.Errorf("invalid 'data' after the canary")
- }
- reader = &CompressUtilReadCloser{
- Reader: lz4.NewReader(bytes.NewReader(cData)),
- }
-
- default:
- // If the first byte doesn't match the canary byte, it means
- // that the content was not compressed at all. Indicate the
- // caller that the input was not compressed.
- return nil, true, nil
- }
- if err != nil {
- return nil, false, errwrap.Wrapf("failed to create a compression reader: {{err}}", err)
- }
- if reader == nil {
- return nil, false, fmt.Errorf("failed to create a compression reader")
- }
-
- // Close the io.ReadCloser
- defer reader.Close()
-
- // Read all the compressed data into a buffer
- var buf bytes.Buffer
- if _, err = io.Copy(&buf, reader); err != nil {
- return nil, false, err
- }
-
- return buf.Bytes(), false, nil
-}
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/consts/agent.go b/vendor/github.com/hashicorp/vault/sdk/helper/consts/agent.go
deleted file mode 100644
index b62962e37e3..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/consts/agent.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package consts
-
-// AgentPathCacheClear is the path that the agent will use as its cache-clear
-// endpoint.
-const AgentPathCacheClear = "/agent/v1/cache-clear"
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/consts/consts.go b/vendor/github.com/hashicorp/vault/sdk/helper/consts/consts.go
deleted file mode 100644
index 769a7858369..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/consts/consts.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package consts
-
-const (
- // ExpirationRestoreWorkerCount specifies the number of workers to use while
- // restoring leases into the expiration manager
- ExpirationRestoreWorkerCount = 64
-
- // NamespaceHeaderName is the header set to specify which namespace the
- // request is indented for.
- NamespaceHeaderName = "X-Vault-Namespace"
-
- // AuthHeaderName is the name of the header containing the token.
- AuthHeaderName = "X-Vault-Token"
-
- // PerformanceReplicationALPN is the negotiated protocol used for
- // performance replication.
- PerformanceReplicationALPN = "replication_v1"
-
- // DRReplicationALPN is the negotiated protocol used for
- // dr replication.
- DRReplicationALPN = "replication_dr_v1"
-
- PerfStandbyALPN = "perf_standby_v1"
-
- RequestForwardingALPN = "req_fw_sb-act_v1"
-
- RaftStorageALPN = "raft_storage_v1"
-)
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/consts/error.go b/vendor/github.com/hashicorp/vault/sdk/helper/consts/error.go
deleted file mode 100644
index d4e60e54e34..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/consts/error.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package consts
-
-import "errors"
-
-var (
- // ErrSealed is returned if an operation is performed on a sealed barrier.
- // No operation is expected to succeed before unsealing
- ErrSealed = errors.New("Vault is sealed")
-
- // ErrStandby is returned if an operation is performed on a standby Vault.
- // No operation is expected to succeed until active.
- ErrStandby = errors.New("Vault is in standby mode")
-
- // ErrPathContainsParentReferences is returned when a path contains parent
- // references.
- ErrPathContainsParentReferences = errors.New("path cannot contain parent references")
-
- // ErrInvalidWrappingToken is returned when checking for the validity of
- // a wrapping token that turns out to be invalid.
- ErrInvalidWrappingToken = errors.New("wrapping token is not valid or does not exist")
-)
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/consts/plugin_types.go b/vendor/github.com/hashicorp/vault/sdk/helper/consts/plugin_types.go
deleted file mode 100644
index e0a00e4860c..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/consts/plugin_types.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package consts
-
-import "fmt"
-
-var PluginTypes = []PluginType{
- PluginTypeUnknown,
- PluginTypeCredential,
- PluginTypeDatabase,
- PluginTypeSecrets,
-}
-
-type PluginType uint32
-
-// This is a list of PluginTypes used by Vault.
-// If we need to add any in the future, it would
-// be best to add them to the _end_ of the list below
-// because they resolve to incrementing numbers,
-// which may be saved in state somewhere. Thus if
-// the name for one of those numbers changed because
-// a value were added to the middle, that could cause
-// the wrong plugin types to be read from storage
-// for a given underlying number. Example of the problem
-// here: https://play.golang.org/p/YAaPw5ww3er
-const (
- PluginTypeUnknown PluginType = iota
- PluginTypeCredential
- PluginTypeDatabase
- PluginTypeSecrets
-)
-
-func (p PluginType) String() string {
- switch p {
- case PluginTypeUnknown:
- return "unknown"
- case PluginTypeCredential:
- return "auth"
- case PluginTypeDatabase:
- return "database"
- case PluginTypeSecrets:
- return "secret"
- default:
- return "unsupported"
- }
-}
-
-func ParsePluginType(pluginType string) (PluginType, error) {
- switch pluginType {
- case "unknown":
- return PluginTypeUnknown, nil
- case "auth":
- return PluginTypeCredential, nil
- case "database":
- return PluginTypeDatabase, nil
- case "secret":
- return PluginTypeSecrets, nil
- default:
- return PluginTypeUnknown, fmt.Errorf("%q is not a supported plugin type", pluginType)
- }
-}
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/consts/replication.go b/vendor/github.com/hashicorp/vault/sdk/helper/consts/replication.go
deleted file mode 100644
index f3cafe75f2c..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/consts/replication.go
+++ /dev/null
@@ -1,150 +0,0 @@
-package consts
-
-import "time"
-
-const (
- //N.B. This needs to be excluded from replication despite the name; it's
- //merely saying that this is cluster information for the replicated
- //cluster.
- CoreReplicatedClusterPrefix = "core/cluster/replicated/"
- CoreReplicatedClusterPrefixDR = "core/cluster/replicated-dr/"
-
- CoreReplicatedClusterInfoPath = CoreReplicatedClusterPrefix + "info"
- CoreReplicatedClusterSecondariesPrefix = CoreReplicatedClusterPrefix + "secondaries/"
- CoreReplicatedClusterInfoPathDR = CoreReplicatedClusterPrefixDR + "info"
- CoreReplicatedClusterSecondariesPrefixDR = CoreReplicatedClusterPrefixDR + "secondaries/"
-
- // This is an identifier for the current secondary in the replicated paths
- // manager. It should contain a character that is not allowed in secondary
- // ids to ensure it doesn't collide.
- CurrentReplicatedSecondaryIdentifier = ".current"
-)
-
-type ReplicationState uint32
-
-var ReplicationStaleReadTimeout = 2 * time.Second
-
-const (
- _ ReplicationState = iota
- OldReplicationPrimary
- OldReplicationSecondary
- OldReplicationBootstrapping
- // Don't add anything here. Adding anything to this Old block would cause
- // the rest of the values to change below. This was done originally to
- // ensure no overlap between old and new values.
-
- ReplicationUnknown ReplicationState = 0
- ReplicationPerformancePrimary ReplicationState = 1 << iota // Note -- iota is 5 here!
- ReplicationPerformanceSecondary
- OldSplitReplicationBootstrapping
- ReplicationDRPrimary
- ReplicationDRSecondary
- ReplicationPerformanceBootstrapping
- ReplicationDRBootstrapping
- ReplicationPerformanceDisabled
- ReplicationDRDisabled
- ReplicationPerformanceStandby
-)
-
-// We verify no change to the above values are made
-func init() {
-
- if OldReplicationBootstrapping != 3 {
- panic("Replication Constants have changed")
- }
-
- if ReplicationPerformancePrimary != 1<<5 {
- panic("Replication Constants have changed")
- }
-}
-
-func (r ReplicationState) string() string {
- switch r {
- case ReplicationPerformanceSecondary:
- return "secondary"
- case ReplicationPerformancePrimary:
- return "primary"
- case ReplicationPerformanceBootstrapping:
- return "bootstrapping"
- case ReplicationPerformanceDisabled:
- return "disabled"
- case ReplicationDRPrimary:
- return "primary"
- case ReplicationDRSecondary:
- return "secondary"
- case ReplicationDRBootstrapping:
- return "bootstrapping"
- case ReplicationDRDisabled:
- return "disabled"
- }
-
- return "unknown"
-}
-
-func (r ReplicationState) StateStrings() []string {
- var ret []string
- if r.HasState(ReplicationPerformanceSecondary) {
- ret = append(ret, "perf-secondary")
- }
- if r.HasState(ReplicationPerformancePrimary) {
- ret = append(ret, "perf-primary")
- }
- if r.HasState(ReplicationPerformanceBootstrapping) {
- ret = append(ret, "perf-bootstrapping")
- }
- if r.HasState(ReplicationPerformanceDisabled) {
- ret = append(ret, "perf-disabled")
- }
- if r.HasState(ReplicationDRPrimary) {
- ret = append(ret, "dr-primary")
- }
- if r.HasState(ReplicationDRSecondary) {
- ret = append(ret, "dr-secondary")
- }
- if r.HasState(ReplicationDRBootstrapping) {
- ret = append(ret, "dr-bootstrapping")
- }
- if r.HasState(ReplicationDRDisabled) {
- ret = append(ret, "dr-disabled")
- }
- if r.HasState(ReplicationPerformanceStandby) {
- ret = append(ret, "perfstandby")
- }
-
- return ret
-}
-
-func (r ReplicationState) GetDRString() string {
- switch {
- case r.HasState(ReplicationDRBootstrapping):
- return ReplicationDRBootstrapping.string()
- case r.HasState(ReplicationDRPrimary):
- return ReplicationDRPrimary.string()
- case r.HasState(ReplicationDRSecondary):
- return ReplicationDRSecondary.string()
- case r.HasState(ReplicationDRDisabled):
- return ReplicationDRDisabled.string()
- default:
- return "unknown"
- }
-}
-
-func (r ReplicationState) GetPerformanceString() string {
- switch {
- case r.HasState(ReplicationPerformanceBootstrapping):
- return ReplicationPerformanceBootstrapping.string()
- case r.HasState(ReplicationPerformancePrimary):
- return ReplicationPerformancePrimary.string()
- case r.HasState(ReplicationPerformanceSecondary):
- return ReplicationPerformanceSecondary.string()
- case r.HasState(ReplicationPerformanceDisabled):
- return ReplicationPerformanceDisabled.string()
- default:
- return "unknown"
- }
-}
-
-func (r ReplicationState) HasState(flag ReplicationState) bool { return r&flag != 0 }
-func (r *ReplicationState) AddState(flag ReplicationState) { *r |= flag }
-func (r *ReplicationState) ClearState(flag ReplicationState) { *r &= ^flag }
-func (r *ReplicationState) ToggleState(flag ReplicationState) { *r ^= flag }
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/hclutil/hcl.go b/vendor/github.com/hashicorp/vault/sdk/helper/hclutil/hcl.go
deleted file mode 100644
index 0b120367d5a..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/hclutil/hcl.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package hclutil
-
-import (
- "fmt"
-
- multierror "github.com/hashicorp/go-multierror"
- "github.com/hashicorp/hcl/hcl/ast"
-)
-
-// CheckHCLKeys checks whether the keys in the AST list contains any of the valid keys provided.
-func CheckHCLKeys(node ast.Node, valid []string) error {
- var list *ast.ObjectList
- switch n := node.(type) {
- case *ast.ObjectList:
- list = n
- case *ast.ObjectType:
- list = n.List
- default:
- return fmt.Errorf("cannot check HCL keys of type %T", n)
- }
-
- validMap := make(map[string]struct{}, len(valid))
- for _, v := range valid {
- validMap[v] = struct{}{}
- }
-
- var result error
- for _, item := range list.Items {
- key := item.Keys[0].Token.Value().(string)
- if _, ok := validMap[key]; !ok {
- result = multierror.Append(result, fmt.Errorf("invalid key %q on line %d", key, item.Assign.Line))
- }
- }
-
- return result
-}
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/jsonutil/json.go b/vendor/github.com/hashicorp/vault/sdk/helper/jsonutil/json.go
deleted file mode 100644
index c03a4f8c8d1..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/jsonutil/json.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package jsonutil
-
-import (
- "bytes"
- "compress/gzip"
- "encoding/json"
- "fmt"
- "io"
-
- "github.com/hashicorp/errwrap"
- "github.com/hashicorp/vault/sdk/helper/compressutil"
-)
-
-// Encodes/Marshals the given object into JSON
-func EncodeJSON(in interface{}) ([]byte, error) {
- if in == nil {
- return nil, fmt.Errorf("input for encoding is nil")
- }
- var buf bytes.Buffer
- enc := json.NewEncoder(&buf)
- if err := enc.Encode(in); err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
-}
-
-// EncodeJSONAndCompress encodes the given input into JSON and compresses the
-// encoded value (using Gzip format BestCompression level, by default). A
-// canary byte is placed at the beginning of the returned bytes for the logic
-// in decompression method to identify compressed input.
-func EncodeJSONAndCompress(in interface{}, config *compressutil.CompressionConfig) ([]byte, error) {
- if in == nil {
- return nil, fmt.Errorf("input for encoding is nil")
- }
-
- // First JSON encode the given input
- encodedBytes, err := EncodeJSON(in)
- if err != nil {
- return nil, err
- }
-
- if config == nil {
- config = &compressutil.CompressionConfig{
- Type: compressutil.CompressionTypeGzip,
- GzipCompressionLevel: gzip.BestCompression,
- }
- }
-
- return compressutil.Compress(encodedBytes, config)
-}
-
-// DecodeJSON tries to decompress the given data. The call to decompress, fails
-// if the content was not compressed in the first place, which is identified by
-// a canary byte before the compressed data. If the data is not compressed, it
-// is JSON decoded directly. Otherwise the decompressed data will be JSON
-// decoded.
-func DecodeJSON(data []byte, out interface{}) error {
- if data == nil || len(data) == 0 {
- return fmt.Errorf("'data' being decoded is nil")
- }
- if out == nil {
- return fmt.Errorf("output parameter 'out' is nil")
- }
-
- // Decompress the data if it was compressed in the first place
- decompressedBytes, uncompressed, err := compressutil.Decompress(data)
- if err != nil {
- return errwrap.Wrapf("failed to decompress JSON: {{err}}", err)
- }
- if !uncompressed && (decompressedBytes == nil || len(decompressedBytes) == 0) {
- return fmt.Errorf("decompressed data being decoded is invalid")
- }
-
- // If the input supplied failed to contain the compression canary, it
- // will be notified by the compression utility. Decode the decompressed
- // input.
- if !uncompressed {
- data = decompressedBytes
- }
-
- return DecodeJSONFromReader(bytes.NewReader(data), out)
-}
-
-// Decodes/Unmarshals the given io.Reader pointing to a JSON, into a desired object
-func DecodeJSONFromReader(r io.Reader, out interface{}) error {
- if r == nil {
- return fmt.Errorf("'io.Reader' being decoded is nil")
- }
- if out == nil {
- return fmt.Errorf("output parameter 'out' is nil")
- }
-
- dec := json.NewDecoder(r)
-
- // While decoding JSON values, interpret the integer values as `json.Number`s instead of `float64`.
- dec.UseNumber()
-
- // Since 'out' is an interface representing a pointer, pass it to the decoder without an '&'
- return dec.Decode(out)
-}
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/parseutil/parseutil.go b/vendor/github.com/hashicorp/vault/sdk/helper/parseutil/parseutil.go
deleted file mode 100644
index ea8289b4361..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/parseutil/parseutil.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package parseutil
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "strconv"
- "strings"
- "time"
-
- "github.com/hashicorp/errwrap"
- sockaddr "github.com/hashicorp/go-sockaddr"
- "github.com/hashicorp/vault/sdk/helper/strutil"
- "github.com/mitchellh/mapstructure"
-)
-
-func ParseDurationSecond(in interface{}) (time.Duration, error) {
- var dur time.Duration
- jsonIn, ok := in.(json.Number)
- if ok {
- in = jsonIn.String()
- }
- switch inp := in.(type) {
- case nil:
- // return default of zero
- case string:
- if inp == "" {
- return dur, nil
- }
- var err error
- // Look for a suffix otherwise its a plain second value
- if strings.HasSuffix(inp, "s") || strings.HasSuffix(inp, "m") || strings.HasSuffix(inp, "h") || strings.HasSuffix(inp, "ms") {
- dur, err = time.ParseDuration(inp)
- if err != nil {
- return dur, err
- }
- } else {
- // Plain integer
- secs, err := strconv.ParseInt(inp, 10, 64)
- if err != nil {
- return dur, err
- }
- dur = time.Duration(secs) * time.Second
- }
- case int:
- dur = time.Duration(inp) * time.Second
- case int32:
- dur = time.Duration(inp) * time.Second
- case int64:
- dur = time.Duration(inp) * time.Second
- case uint:
- dur = time.Duration(inp) * time.Second
- case uint32:
- dur = time.Duration(inp) * time.Second
- case uint64:
- dur = time.Duration(inp) * time.Second
- case float32:
- dur = time.Duration(inp) * time.Second
- case float64:
- dur = time.Duration(inp) * time.Second
- case time.Duration:
- dur = inp
- default:
- return 0, errors.New("could not parse duration from input")
- }
-
- return dur, nil
-}
-
-func ParseInt(in interface{}) (int64, error) {
- var ret int64
- jsonIn, ok := in.(json.Number)
- if ok {
- in = jsonIn.String()
- }
- switch in.(type) {
- case string:
- inp := in.(string)
- if inp == "" {
- return 0, nil
- }
- var err error
- left, err := strconv.ParseInt(inp, 10, 64)
- if err != nil {
- return ret, err
- }
- ret = left
- case int:
- ret = int64(in.(int))
- case int32:
- ret = int64(in.(int32))
- case int64:
- ret = in.(int64)
- case uint:
- ret = int64(in.(uint))
- case uint32:
- ret = int64(in.(uint32))
- case uint64:
- ret = int64(in.(uint64))
- default:
- return 0, errors.New("could not parse value from input")
- }
-
- return ret, nil
-}
-
-func ParseBool(in interface{}) (bool, error) {
- var result bool
- if err := mapstructure.WeakDecode(in, &result); err != nil {
- return false, err
- }
- return result, nil
-}
-
-func ParseCommaStringSlice(in interface{}) ([]string, error) {
- rawString, ok := in.(string)
- if ok && rawString == "" {
- return []string{}, nil
- }
- var result []string
- config := &mapstructure.DecoderConfig{
- Result: &result,
- WeaklyTypedInput: true,
- DecodeHook: mapstructure.StringToSliceHookFunc(","),
- }
- decoder, err := mapstructure.NewDecoder(config)
- if err != nil {
- return nil, err
- }
- if err := decoder.Decode(in); err != nil {
- return nil, err
- }
- return strutil.TrimStrings(result), nil
-}
-
-func ParseAddrs(addrs interface{}) ([]*sockaddr.SockAddrMarshaler, error) {
- out := make([]*sockaddr.SockAddrMarshaler, 0)
- stringAddrs := make([]string, 0)
-
- switch addrs.(type) {
- case string:
- stringAddrs = strutil.ParseArbitraryStringSlice(addrs.(string), ",")
- if len(stringAddrs) == 0 {
- return nil, fmt.Errorf("unable to parse addresses from %v", addrs)
- }
-
- case []string:
- stringAddrs = addrs.([]string)
-
- case []interface{}:
- for _, v := range addrs.([]interface{}) {
- stringAddr, ok := v.(string)
- if !ok {
- return nil, fmt.Errorf("error parsing %v as string", v)
- }
- stringAddrs = append(stringAddrs, stringAddr)
- }
-
- default:
- return nil, fmt.Errorf("unknown address input type %T", addrs)
- }
-
- for _, addr := range stringAddrs {
- sa, err := sockaddr.NewSockAddr(addr)
- if err != nil {
- return nil, errwrap.Wrapf(fmt.Sprintf("error parsing address %q: {{err}}", addr), err)
- }
- out = append(out, &sockaddr.SockAddrMarshaler{
- SockAddr: sa,
- })
- }
-
- return out, nil
-}
diff --git a/vendor/github.com/hashicorp/vault/sdk/helper/strutil/strutil.go b/vendor/github.com/hashicorp/vault/sdk/helper/strutil/strutil.go
deleted file mode 100644
index 0069a1377b2..00000000000
--- a/vendor/github.com/hashicorp/vault/sdk/helper/strutil/strutil.go
+++ /dev/null
@@ -1,447 +0,0 @@
-package strutil
-
-import (
- "encoding/base64"
- "encoding/json"
- "fmt"
- "sort"
- "strings"
-
- "github.com/hashicorp/errwrap"
- glob "github.com/ryanuber/go-glob"
-)
-
-// StrListContainsGlob looks for a string in a list of strings and allows
-// globs.
-func StrListContainsGlob(haystack []string, needle string) bool {
- for _, item := range haystack {
- if glob.Glob(item, needle) {
- return true
- }
- }
- return false
-}
-
-// StrListContains looks for a string in a list of strings.
-func StrListContains(haystack []string, needle string) bool {
- for _, item := range haystack {
- if item == needle {
- return true
- }
- }
- return false
-}
-
-// StrListSubset checks if a given list is a subset
-// of another set
-func StrListSubset(super, sub []string) bool {
- for _, item := range sub {
- if !StrListContains(super, item) {
- return false
- }
- }
- return true
-}
-
-// ParseDedupAndSortStrings parses a comma separated list of strings
-// into a slice of strings. The return slice will be sorted and will
-// not contain duplicate or empty items.
-func ParseDedupAndSortStrings(input string, sep string) []string {
- input = strings.TrimSpace(input)
- parsed := []string{}
- if input == "" {
- // Don't return nil
- return parsed
- }
- return RemoveDuplicates(strings.Split(input, sep), false)
-}
-
-// ParseDedupLowercaseAndSortStrings parses a comma separated list of
-// strings into a slice of strings. The return slice will be sorted and
-// will not contain duplicate or empty items. The values will be converted
-// to lower case.
-func ParseDedupLowercaseAndSortStrings(input string, sep string) []string {
- input = strings.TrimSpace(input)
- parsed := []string{}
- if input == "" {
- // Don't return nil
- return parsed
- }
- return RemoveDuplicates(strings.Split(input, sep), true)
-}
-
-// ParseKeyValues parses a comma separated list of `=` tuples
-// into a map[string]string.
-func ParseKeyValues(input string, out map[string]string, sep string) error {
- if out == nil {
- return fmt.Errorf("'out is nil")
- }
-
- keyValues := ParseDedupLowercaseAndSortStrings(input, sep)
- if len(keyValues) == 0 {
- return nil
- }
-
- for _, keyValue := range keyValues {
- shards := strings.Split(keyValue, "=")
- if len(shards) != 2 {
- return fmt.Errorf("invalid format")
- }
-
- key := strings.TrimSpace(shards[0])
- value := strings.TrimSpace(shards[1])
- if key == "" || value == "" {
- return fmt.Errorf("invalid pair: key: %q value: %q", key, value)
- }
- out[key] = value
- }
- return nil
-}
-
-// ParseArbitraryKeyValues parses arbitrary tuples. The input
-// can be one of the following:
-// * JSON string
-// * Base64 encoded JSON string
-// * Comma separated list of `=` pairs
-// * Base64 encoded string containing comma separated list of
-// `=` pairs
-//
-// Input will be parsed into the output parameter, which should
-// be a non-nil map[string]string.
-func ParseArbitraryKeyValues(input string, out map[string]string, sep string) error {
- input = strings.TrimSpace(input)
- if input == "" {
- return nil
- }
- if out == nil {
- return fmt.Errorf("'out' is nil")
- }
-
- // Try to base64 decode the input. If successful, consider the decoded
- // value as input.
- inputBytes, err := base64.StdEncoding.DecodeString(input)
- if err == nil {
- input = string(inputBytes)
- }
-
- // Try to JSON unmarshal the input. If successful, consider that the
- // metadata was supplied as JSON input.
- err = json.Unmarshal([]byte(input), &out)
- if err != nil {
- // If JSON unmarshalling fails, consider that the input was
- // supplied as a comma separated string of 'key=value' pairs.
- if err = ParseKeyValues(input, out, sep); err != nil {
- return errwrap.Wrapf("failed to parse the input: {{err}}", err)
- }
- }
-
- // Validate the parsed input
- for key, value := range out {
- if key != "" && value == "" {
- return fmt.Errorf("invalid value for key %q", key)
- }
- }
-
- return nil
-}
-
-// ParseStringSlice parses a `sep`-separated list of strings into a
-// []string with surrounding whitespace removed.
-//
-// The output will always be a valid slice but may be of length zero.
-func ParseStringSlice(input string, sep string) []string {
- input = strings.TrimSpace(input)
- if input == "" {
- return []string{}
- }
-
- splitStr := strings.Split(input, sep)
- ret := make([]string, len(splitStr))
- for i, val := range splitStr {
- ret[i] = strings.TrimSpace(val)
- }
-
- return ret
-}
-
-// ParseArbitraryStringSlice parses arbitrary string slice. The input
-// can be one of the following:
-// * JSON string
-// * Base64 encoded JSON string
-// * `sep` separated list of values
-// * Base64-encoded string containing a `sep` separated list of values
-//
-// Note that the separator is ignored if the input is found to already be in a
-// structured format (e.g., JSON)
-//
-// The output will always be a valid slice but may be of length zero.
-func ParseArbitraryStringSlice(input string, sep string) []string {
- input = strings.TrimSpace(input)
- if input == "" {
- return []string{}
- }
-
- // Try to base64 decode the input. If successful, consider the decoded
- // value as input.
- inputBytes, err := base64.StdEncoding.DecodeString(input)
- if err == nil {
- input = string(inputBytes)
- }
-
- ret := []string{}
-
- // Try to JSON unmarshal the input. If successful, consider that the
- // metadata was supplied as JSON input.
- err = json.Unmarshal([]byte(input), &ret)
- if err != nil {
- // If JSON unmarshalling fails, consider that the input was
- // supplied as a separated string of values.
- return ParseStringSlice(input, sep)
- }
-
- if ret == nil {
- return []string{}
- }
-
- return ret
-}
-
-// TrimStrings takes a slice of strings and returns a slice of strings
-// with trimmed spaces
-func TrimStrings(items []string) []string {
- ret := make([]string, len(items))
- for i, item := range items {
- ret[i] = strings.TrimSpace(item)
- }
- return ret
-}
-
-// RemoveDuplicates removes duplicate and empty elements from a slice of
-// strings. This also may convert the items in the slice to lower case and
-// returns a sorted slice.
-func RemoveDuplicates(items []string, lowercase bool) []string {
- itemsMap := map[string]bool{}
- for _, item := range items {
- item = strings.TrimSpace(item)
- if lowercase {
- item = strings.ToLower(item)
- }
- if item == "" {
- continue
- }
- itemsMap[item] = true
- }
- items = make([]string, 0, len(itemsMap))
- for item := range itemsMap {
- items = append(items, item)
- }
- sort.Strings(items)
- return items
-}
-
-// RemoveDuplicatesStable removes duplicate and empty elements from a slice of
-// strings, preserving order (and case) of the original slice.
-// In all cases, strings are compared after trimming whitespace
-// If caseInsensitive, strings will be compared after ToLower()
-func RemoveDuplicatesStable(items []string, caseInsensitive bool) []string {
- itemsMap := make(map[string]bool, len(items))
- deduplicated := make([]string, 0, len(items))
-
- for _, item := range items {
- key := strings.TrimSpace(item)
- if caseInsensitive {
- key = strings.ToLower(key)
- }
- if key == "" || itemsMap[key] {
- continue
- }
- itemsMap[key] = true
- deduplicated = append(deduplicated, item)
- }
- return deduplicated
-}
-
-// RemoveEmpty removes empty elements from a slice of
-// strings
-func RemoveEmpty(items []string) []string {
- if len(items) == 0 {
- return items
- }
- itemsSlice := make([]string, 0, len(items))
- for _, item := range items {
- if item == "" {
- continue
- }
- itemsSlice = append(itemsSlice, item)
- }
- return itemsSlice
-}
-
-// EquivalentSlices checks whether the given string sets are equivalent, as in,
-// they contain the same values.
-func EquivalentSlices(a, b []string) bool {
- if a == nil && b == nil {
- return true
- }
-
- if a == nil || b == nil {
- return false
- }
-
- // First we'll build maps to ensure unique values
- mapA := map[string]bool{}
- mapB := map[string]bool{}
- for _, keyA := range a {
- mapA[keyA] = true
- }
- for _, keyB := range b {
- mapB[keyB] = true
- }
-
- // Now we'll build our checking slices
- var sortedA, sortedB []string
- for keyA := range mapA {
- sortedA = append(sortedA, keyA)
- }
- for keyB := range mapB {
- sortedB = append(sortedB, keyB)
- }
- sort.Strings(sortedA)
- sort.Strings(sortedB)
-
- // Finally, compare
- if len(sortedA) != len(sortedB) {
- return false
- }
-
- for i := range sortedA {
- if sortedA[i] != sortedB[i] {
- return false
- }
- }
-
- return true
-}
-
-// EqualStringMaps tests whether two map[string]string objects are equal.
-// Equal means both maps have the same sets of keys and values. This function
-// is 6-10x faster than a call to reflect.DeepEqual().
-func EqualStringMaps(a, b map[string]string) bool {
- if len(a) != len(b) {
- return false
- }
-
- for k := range a {
- v, ok := b[k]
- if !ok || a[k] != v {
- return false
- }
- }
-
- return true
-}
-
-// StrListDelete removes the first occurrence of the given item from the slice
-// of strings if the item exists.
-func StrListDelete(s []string, d string) []string {
- if s == nil {
- return s
- }
-
- for index, element := range s {
- if element == d {
- return append(s[:index], s[index+1:]...)
- }
- }
-
- return s
-}
-
-// GlobbedStringsMatch compares item to val with support for a leading and/or
-// trailing wildcard '*' in item.
-func GlobbedStringsMatch(item, val string) bool {
- if len(item) < 2 {
- return val == item
- }
-
- hasPrefix := strings.HasPrefix(item, "*")
- hasSuffix := strings.HasSuffix(item, "*")
-
- if hasPrefix && hasSuffix {
- return strings.Contains(val, item[1:len(item)-1])
- } else if hasPrefix {
- return strings.HasSuffix(val, item[1:])
- } else if hasSuffix {
- return strings.HasPrefix(val, item[:len(item)-1])
- }
-
- return val == item
-}
-
-// AppendIfMissing adds a string to a slice if the given string is not present
-func AppendIfMissing(slice []string, i string) []string {
- if StrListContains(slice, i) {
- return slice
- }
- return append(slice, i)
-}
-
-// MergeSlices adds an arbitrary number of slices together, uniquely
-func MergeSlices(args ...[]string) []string {
- all := map[string]struct{}{}
- for _, slice := range args {
- for _, v := range slice {
- all[v] = struct{}{}
- }
- }
-
- result := make([]string, 0, len(all))
- for k := range all {
- result = append(result, k)
- }
- sort.Strings(result)
- return result
-}
-
-// Difference returns the set difference (A - B) of the two given slices. The
-// result will also remove any duplicated values in set A regardless of whether
-// that matches any values in set B.
-func Difference(a, b []string, lowercase bool) []string {
- if len(a) == 0 {
- return a
- }
- if len(b) == 0 {
- if !lowercase {
- return a
- }
- newA := make([]string, len(a))
- for i, v := range a {
- newA[i] = strings.ToLower(v)
- }
- return newA
- }
-
- a = RemoveDuplicates(a, lowercase)
- b = RemoveDuplicates(b, lowercase)
-
- itemsMap := map[string]bool{}
- for _, aVal := range a {
- itemsMap[aVal] = true
- }
-
- // Perform difference calculation
- for _, bVal := range b {
- if _, ok := itemsMap[bVal]; ok {
- itemsMap[bVal] = false
- }
- }
-
- items := []string{}
- for item, exists := range itemsMap {
- if exists {
- items = append(items, item)
- }
- }
- sort.Strings(items)
- return items
-}
diff --git a/vendor/github.com/huandu/xstrings/.gitignore b/vendor/github.com/huandu/xstrings/.gitignore
deleted file mode 100644
index daf913b1b34..00000000000
--- a/vendor/github.com/huandu/xstrings/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-*.prof
diff --git a/vendor/github.com/huandu/xstrings/.travis.yml b/vendor/github.com/huandu/xstrings/.travis.yml
deleted file mode 100644
index d6460be411e..00000000000
--- a/vendor/github.com/huandu/xstrings/.travis.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-language: go
-install:
- - go get golang.org/x/tools/cmd/cover
- - go get github.com/mattn/goveralls
-script:
- - go test -v -covermode=count -coverprofile=coverage.out
- - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ ! -z "$COVERALLS_TOKEN" ]; then $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken $COVERALLS_TOKEN; fi'
diff --git a/vendor/github.com/huandu/xstrings/CONTRIBUTING.md b/vendor/github.com/huandu/xstrings/CONTRIBUTING.md
deleted file mode 100644
index d7b4b8d584b..00000000000
--- a/vendor/github.com/huandu/xstrings/CONTRIBUTING.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Contributing #
-
-Thanks for your contribution in advance. No matter what you will contribute to this project, pull request or bug report or feature discussion, it's always highly appreciated.
-
-## New API or feature ##
-
-I want to speak more about how to add new functions to this package.
-
-Package `xstring` is a collection of useful string functions which should be implemented in Go. It's a bit subject to say which function should be included and which should not. I set up following rules in order to make it clear and as objective as possible.
-
-* Rule 1: Only string algorithm, which takes string as input, can be included.
-* Rule 2: If a function has been implemented in package `string`, it must not be included.
-* Rule 3: If a function is not language neutral, it must not be included.
-* Rule 4: If a function is a part of standard library in other languages, it can be included.
-* Rule 5: If a function is quite useful in some famous framework or library, it can be included.
-
-New function must be discussed in project issues before submitting any code. If a pull request with new functions is sent without any ref issue, it will be rejected.
-
-## Pull request ##
-
-Pull request is always welcome. Just make sure you have run `go fmt` and all test cases passed before submit.
-
-If the pull request is to add a new API or feature, don't forget to update README.md and add new API in function list.
diff --git a/vendor/github.com/huandu/xstrings/LICENSE b/vendor/github.com/huandu/xstrings/LICENSE
deleted file mode 100644
index 27017725936..00000000000
--- a/vendor/github.com/huandu/xstrings/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Huan Du
-
-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.
-
diff --git a/vendor/github.com/huandu/xstrings/README.md b/vendor/github.com/huandu/xstrings/README.md
deleted file mode 100644
index 292bf2f39e1..00000000000
--- a/vendor/github.com/huandu/xstrings/README.md
+++ /dev/null
@@ -1,117 +0,0 @@
-# xstrings #
-
-[![Build Status](https://travis-ci.org/huandu/xstrings.svg?branch=master)](https://travis-ci.org/huandu/xstrings)
-[![GoDoc](https://godoc.org/github.com/huandu/xstrings?status.svg)](https://godoc.org/github.com/huandu/xstrings)
-[![Go Report](https://goreportcard.com/badge/github.com/huandu/xstrings)](https://goreportcard.com/report/github.com/huandu/xstrings)
-[![Coverage Status](https://coveralls.io/repos/github/huandu/xstrings/badge.svg?branch=master)](https://coveralls.io/github/huandu/xstrings?branch=master)
-
-Go package [xstrings](https://godoc.org/github.com/huandu/xstrings) is a collection of string functions, which are widely used in other languages but absent in Go package [strings](http://golang.org/pkg/strings).
-
-All functions are well tested and carefully tuned for performance.
-
-## Propose a new function ##
-
-Please review [contributing guideline](CONTRIBUTING.md) and [create new issue](https://github.com/huandu/xstrings/issues) to state why it should be included.
-
-## Install ##
-
-Use `go get` to install this library.
-
- go get github.com/huandu/xstrings
-
-## API document ##
-
-See [GoDoc](https://godoc.org/github.com/huandu/xstrings) for full document.
-
-## Function list ##
-
-Go functions have a unique naming style. One, who has experience in other language but new in Go, may have difficulties to find out right string function to use.
-
-Here is a list of functions in [strings](http://golang.org/pkg/strings) and [xstrings](https://godoc.org/github.com/huandu/xstrings) with enough extra information about how to map these functions to their friends in other languages. Hope this list could be helpful for fresh gophers.
-
-### Package `xstrings` functions ###
-
-*Keep this table sorted by Function in ascending order.*
-
-| Function | Friends | # |
-| -------- | ------- | --- |
-| [Center](https://godoc.org/github.com/huandu/xstrings#Center) | `str.center` in Python; `String#center` in Ruby | [#30](https://github.com/huandu/xstrings/issues/30) |
-| [Count](https://godoc.org/github.com/huandu/xstrings#Count) | `String#count` in Ruby | [#16](https://github.com/huandu/xstrings/issues/16) |
-| [Delete](https://godoc.org/github.com/huandu/xstrings#Delete) | `String#delete` in Ruby | [#17](https://github.com/huandu/xstrings/issues/17) |
-| [ExpandTabs](https://godoc.org/github.com/huandu/xstrings#ExpandTabs) | `str.expandtabs` in Python | [#27](https://github.com/huandu/xstrings/issues/27) |
-| [FirstRuneToLower](https://godoc.org/github.com/huandu/xstrings#FirstRuneToLower) | `lcfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) |
-| [FirstRuneToUpper](https://godoc.org/github.com/huandu/xstrings#FirstRuneToUpper) | `String#capitalize` in Ruby; `ucfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) |
-| [Insert](https://godoc.org/github.com/huandu/xstrings#Insert) | `String#insert` in Ruby | [#18](https://github.com/huandu/xstrings/issues/18) |
-| [LastPartition](https://godoc.org/github.com/huandu/xstrings#LastPartition) | `str.rpartition` in Python; `String#rpartition` in Ruby | [#19](https://github.com/huandu/xstrings/issues/19) |
-| [LeftJustify](https://godoc.org/github.com/huandu/xstrings#LeftJustify) | `str.ljust` in Python; `String#ljust` in Ruby | [#28](https://github.com/huandu/xstrings/issues/28) |
-| [Len](https://godoc.org/github.com/huandu/xstrings#Len) | `mb_strlen` in PHP | [#23](https://github.com/huandu/xstrings/issues/23) |
-| [Partition](https://godoc.org/github.com/huandu/xstrings#Partition) | `str.partition` in Python; `String#partition` in Ruby | [#10](https://github.com/huandu/xstrings/issues/10) |
-| [Reverse](https://godoc.org/github.com/huandu/xstrings#Reverse) | `String#reverse` in Ruby; `strrev` in PHP; `reverse` in Perl | [#7](https://github.com/huandu/xstrings/issues/7) |
-| [RightJustify](https://godoc.org/github.com/huandu/xstrings#RightJustify) | `str.rjust` in Python; `String#rjust` in Ruby | [#29](https://github.com/huandu/xstrings/issues/29) |
-| [RuneWidth](https://godoc.org/github.com/huandu/xstrings#RuneWidth) | - | [#27](https://github.com/huandu/xstrings/issues/27) |
-| [Scrub](https://godoc.org/github.com/huandu/xstrings#Scrub) | `String#scrub` in Ruby | [#20](https://github.com/huandu/xstrings/issues/20) |
-| [Shuffle](https://godoc.org/github.com/huandu/xstrings#Shuffle) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) |
-| [ShuffleSource](https://godoc.org/github.com/huandu/xstrings#ShuffleSource) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) |
-| [Slice](https://godoc.org/github.com/huandu/xstrings#Slice) | `mb_substr` in PHP | [#9](https://github.com/huandu/xstrings/issues/9) |
-| [Squeeze](https://godoc.org/github.com/huandu/xstrings#Squeeze) | `String#squeeze` in Ruby | [#11](https://github.com/huandu/xstrings/issues/11) |
-| [Successor](https://godoc.org/github.com/huandu/xstrings#Successor) | `String#succ` or `String#next` in Ruby | [#22](https://github.com/huandu/xstrings/issues/22) |
-| [SwapCase](https://godoc.org/github.com/huandu/xstrings#SwapCase) | `str.swapcase` in Python; `String#swapcase` in Ruby | [#12](https://github.com/huandu/xstrings/issues/12) |
-| [ToCamelCase](https://godoc.org/github.com/huandu/xstrings#ToCamelCase) | `String#camelize` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) |
-| [ToKebab](https://godoc.org/github.com/huandu/xstrings#ToKebabCase) | - | [#41](https://github.com/huandu/xstrings/issues/41) |
-| [ToSnakeCase](https://godoc.org/github.com/huandu/xstrings#ToSnakeCase) | `String#underscore` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) |
-| [Translate](https://godoc.org/github.com/huandu/xstrings#Translate) | `str.translate` in Python; `String#tr` in Ruby; `strtr` in PHP; `tr///` in Perl | [#21](https://github.com/huandu/xstrings/issues/21) |
-| [Width](https://godoc.org/github.com/huandu/xstrings#Width) | `mb_strwidth` in PHP | [#26](https://github.com/huandu/xstrings/issues/26) |
-| [WordCount](https://godoc.org/github.com/huandu/xstrings#WordCount) | `str_word_count` in PHP | [#14](https://github.com/huandu/xstrings/issues/14) |
-| [WordSplit](https://godoc.org/github.com/huandu/xstrings#WordSplit) | - | [#14](https://github.com/huandu/xstrings/issues/14) |
-
-### Package `strings` functions ###
-
-*Keep this table sorted by Function in ascending order.*
-
-| Function | Friends |
-| -------- | ------- |
-| [Contains](http://golang.org/pkg/strings/#Contains) | `String#include?` in Ruby |
-| [ContainsAny](http://golang.org/pkg/strings/#ContainsAny) | - |
-| [ContainsRune](http://golang.org/pkg/strings/#ContainsRune) | - |
-| [Count](http://golang.org/pkg/strings/#Count) | `str.count` in Python; `substr_count` in PHP |
-| [EqualFold](http://golang.org/pkg/strings/#EqualFold) | `stricmp` in PHP; `String#casecmp` in Ruby |
-| [Fields](http://golang.org/pkg/strings/#Fields) | `str.split` in Python; `split` in Perl; `String#split` in Ruby |
-| [FieldsFunc](http://golang.org/pkg/strings/#FieldsFunc) | - |
-| [HasPrefix](http://golang.org/pkg/strings/#HasPrefix) | `str.startswith` in Python; `String#start_with?` in Ruby |
-| [HasSuffix](http://golang.org/pkg/strings/#HasSuffix) | `str.endswith` in Python; `String#end_with?` in Ruby |
-| [Index](http://golang.org/pkg/strings/#Index) | `str.index` in Python; `String#index` in Ruby; `strpos` in PHP; `index` in Perl |
-| [IndexAny](http://golang.org/pkg/strings/#IndexAny) | - |
-| [IndexByte](http://golang.org/pkg/strings/#IndexByte) | - |
-| [IndexFunc](http://golang.org/pkg/strings/#IndexFunc) | - |
-| [IndexRune](http://golang.org/pkg/strings/#IndexRune) | - |
-| [Join](http://golang.org/pkg/strings/#Join) | `str.join` in Python; `Array#join` in Ruby; `implode` in PHP; `join` in Perl |
-| [LastIndex](http://golang.org/pkg/strings/#LastIndex) | `str.rindex` in Python; `String#rindex`; `strrpos` in PHP; `rindex` in Perl |
-| [LastIndexAny](http://golang.org/pkg/strings/#LastIndexAny) | - |
-| [LastIndexFunc](http://golang.org/pkg/strings/#LastIndexFunc) | - |
-| [Map](http://golang.org/pkg/strings/#Map) | `String#each_codepoint` in Ruby |
-| [Repeat](http://golang.org/pkg/strings/#Repeat) | operator `*` in Python and Ruby; `str_repeat` in PHP |
-| [Replace](http://golang.org/pkg/strings/#Replace) | `str.replace` in Python; `String#sub` in Ruby; `str_replace` in PHP |
-| [Split](http://golang.org/pkg/strings/#Split) | `str.split` in Python; `String#split` in Ruby; `explode` in PHP; `split` in Perl |
-| [SplitAfter](http://golang.org/pkg/strings/#SplitAfter) | - |
-| [SplitAfterN](http://golang.org/pkg/strings/#SplitAfterN) | - |
-| [SplitN](http://golang.org/pkg/strings/#SplitN) | `str.split` in Python; `String#split` in Ruby; `explode` in PHP; `split` in Perl |
-| [Title](http://golang.org/pkg/strings/#Title) | `str.title` in Python |
-| [ToLower](http://golang.org/pkg/strings/#ToLower) | `str.lower` in Python; `String#downcase` in Ruby; `strtolower` in PHP; `lc` in Perl |
-| [ToLowerSpecial](http://golang.org/pkg/strings/#ToLowerSpecial) | - |
-| [ToTitle](http://golang.org/pkg/strings/#ToTitle) | - |
-| [ToTitleSpecial](http://golang.org/pkg/strings/#ToTitleSpecial) | - |
-| [ToUpper](http://golang.org/pkg/strings/#ToUpper) | `str.upper` in Python; `String#upcase` in Ruby; `strtoupper` in PHP; `uc` in Perl |
-| [ToUpperSpecial](http://golang.org/pkg/strings/#ToUpperSpecial) | - |
-| [Trim](http://golang.org/pkg/strings/#Trim) | `str.strip` in Python; `String#strip` in Ruby; `trim` in PHP |
-| [TrimFunc](http://golang.org/pkg/strings/#TrimFunc) | - |
-| [TrimLeft](http://golang.org/pkg/strings/#TrimLeft) | `str.lstrip` in Python; `String#lstrip` in Ruby; `ltrim` in PHP |
-| [TrimLeftFunc](http://golang.org/pkg/strings/#TrimLeftFunc) | - |
-| [TrimPrefix](http://golang.org/pkg/strings/#TrimPrefix) | - |
-| [TrimRight](http://golang.org/pkg/strings/#TrimRight) | `str.rstrip` in Python; `String#rstrip` in Ruby; `rtrim` in PHP |
-| [TrimRightFunc](http://golang.org/pkg/strings/#TrimRightFunc) | - |
-| [TrimSpace](http://golang.org/pkg/strings/#TrimSpace) | `str.strip` in Python; `String#strip` in Ruby; `trim` in PHP |
-| [TrimSuffix](http://golang.org/pkg/strings/#TrimSuffix) | `String#chomp` in Ruby; `chomp` in Perl |
-
-## License ##
-
-This library is licensed under MIT license. See LICENSE for details.
diff --git a/vendor/github.com/huandu/xstrings/common.go b/vendor/github.com/huandu/xstrings/common.go
deleted file mode 100644
index 2aff57aab4d..00000000000
--- a/vendor/github.com/huandu/xstrings/common.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 Huan Du. All rights reserved.
-// Licensed under the MIT license that can be found in the LICENSE file.
-
-package xstrings
-
-import (
- "bytes"
-)
-
-const bufferMaxInitGrowSize = 2048
-
-// Lazy initialize a buffer.
-func allocBuffer(orig, cur string) *bytes.Buffer {
- output := &bytes.Buffer{}
- maxSize := len(orig) * 4
-
- // Avoid to reserve too much memory at once.
- if maxSize > bufferMaxInitGrowSize {
- maxSize = bufferMaxInitGrowSize
- }
-
- output.Grow(maxSize)
- output.WriteString(orig[:len(orig)-len(cur)])
- return output
-}
diff --git a/vendor/github.com/huandu/xstrings/convert.go b/vendor/github.com/huandu/xstrings/convert.go
deleted file mode 100644
index 3686780d23e..00000000000
--- a/vendor/github.com/huandu/xstrings/convert.go
+++ /dev/null
@@ -1,404 +0,0 @@
-// Copyright 2015 Huan Du. All rights reserved.
-// Licensed under the MIT license that can be found in the LICENSE file.
-
-package xstrings
-
-import (
- "bytes"
- "math/rand"
- "unicode"
- "unicode/utf8"
-)
-
-// ToCamelCase is to convert words separated by space, underscore and hyphen to camel case.
-//
-// Some samples.
-// "some_words" => "SomeWords"
-// "http_server" => "HttpServer"
-// "no_https" => "NoHttps"
-// "_complex__case_" => "_Complex_Case_"
-// "some words" => "SomeWords"
-func ToCamelCase(str string) string {
- if len(str) == 0 {
- return ""
- }
-
- buf := &bytes.Buffer{}
- var r0, r1 rune
- var size int
-
- // leading connector will appear in output.
- for len(str) > 0 {
- r0, size = utf8.DecodeRuneInString(str)
- str = str[size:]
-
- if !isConnector(r0) {
- r0 = unicode.ToUpper(r0)
- break
- }
-
- buf.WriteRune(r0)
- }
-
- if len(str) == 0 {
- // A special case for a string contains only 1 rune.
- if size != 0 {
- buf.WriteRune(r0)
- }
-
- return buf.String()
- }
-
- for len(str) > 0 {
- r1 = r0
- r0, size = utf8.DecodeRuneInString(str)
- str = str[size:]
-
- if isConnector(r0) && isConnector(r1) {
- buf.WriteRune(r1)
- continue
- }
-
- if isConnector(r1) {
- r0 = unicode.ToUpper(r0)
- } else {
- r0 = unicode.ToLower(r0)
- buf.WriteRune(r1)
- }
- }
-
- buf.WriteRune(r0)
- return buf.String()
-}
-
-// ToSnakeCase can convert all upper case characters in a string to
-// snake case format.
-//
-// Some samples.
-// "FirstName" => "first_name"
-// "HTTPServer" => "http_server"
-// "NoHTTPS" => "no_https"
-// "GO_PATH" => "go_path"
-// "GO PATH" => "go_path" // space is converted to underscore.
-// "GO-PATH" => "go_path" // hyphen is converted to underscore.
-// "HTTP2XX" => "http_2xx" // insert an underscore before a number and after an alphabet.
-// "http2xx" => "http_2xx"
-// "HTTP20xOK" => "http_20x_ok"
-func ToSnakeCase(str string) string {
- return camelCaseToLowerCase(str, '_')
-}
-
-// ToKebabCase can convert all upper case characters in a string to
-// kebab case format.
-//
-// Some samples.
-// "FirstName" => "first-name"
-// "HTTPServer" => "http-server"
-// "NoHTTPS" => "no-https"
-// "GO_PATH" => "go-path"
-// "GO PATH" => "go-path" // space is converted to '-'.
-// "GO-PATH" => "go-path" // hyphen is converted to '-'.
-// "HTTP2XX" => "http-2xx" // insert a '-' before a number and after an alphabet.
-// "http2xx" => "http-2xx"
-// "HTTP20xOK" => "http-20x-ok"
-func ToKebabCase(str string) string {
- return camelCaseToLowerCase(str, '-')
-}
-
-func camelCaseToLowerCase(str string, connector rune) string {
- if len(str) == 0 {
- return ""
- }
-
- buf := &bytes.Buffer{}
- var prev, r0, r1 rune
- var size int
-
- r0 = connector
-
- for len(str) > 0 {
- prev = r0
- r0, size = utf8.DecodeRuneInString(str)
- str = str[size:]
-
- switch {
- case r0 == utf8.RuneError:
- buf.WriteRune(r0)
-
- case unicode.IsUpper(r0):
- if prev != connector && !unicode.IsNumber(prev) {
- buf.WriteRune(connector)
- }
-
- buf.WriteRune(unicode.ToLower(r0))
-
- if len(str) == 0 {
- break
- }
-
- r0, size = utf8.DecodeRuneInString(str)
- str = str[size:]
-
- if !unicode.IsUpper(r0) {
- buf.WriteRune(r0)
- break
- }
-
- // find next non-upper-case character and insert connector properly.
- // it's designed to convert `HTTPServer` to `http_server`.
- // if there are more than 2 adjacent upper case characters in a word,
- // treat them as an abbreviation plus a normal word.
- for len(str) > 0 {
- r1 = r0
- r0, size = utf8.DecodeRuneInString(str)
- str = str[size:]
-
- if r0 == utf8.RuneError {
- buf.WriteRune(unicode.ToLower(r1))
- buf.WriteRune(r0)
- break
- }
-
- if !unicode.IsUpper(r0) {
- if isConnector(r0) {
- r0 = connector
-
- buf.WriteRune(unicode.ToLower(r1))
- } else if unicode.IsNumber(r0) {
- // treat a number as an upper case rune
- // so that both `http2xx` and `HTTP2XX` can be converted to `http_2xx`.
- buf.WriteRune(unicode.ToLower(r1))
- buf.WriteRune(connector)
- buf.WriteRune(r0)
- } else {
- buf.WriteRune(connector)
- buf.WriteRune(unicode.ToLower(r1))
- buf.WriteRune(r0)
- }
-
- break
- }
-
- buf.WriteRune(unicode.ToLower(r1))
- }
-
- if len(str) == 0 || r0 == connector {
- buf.WriteRune(unicode.ToLower(r0))
- }
-
- case unicode.IsNumber(r0):
- if prev != connector && !unicode.IsNumber(prev) {
- buf.WriteRune(connector)
- }
-
- buf.WriteRune(r0)
-
- default:
- if isConnector(r0) {
- r0 = connector
- }
-
- buf.WriteRune(r0)
- }
- }
-
- return buf.String()
-}
-
-func isConnector(r rune) bool {
- return r == '-' || r == '_' || unicode.IsSpace(r)
-}
-
-// SwapCase will swap characters case from upper to lower or lower to upper.
-func SwapCase(str string) string {
- var r rune
- var size int
-
- buf := &bytes.Buffer{}
-
- for len(str) > 0 {
- r, size = utf8.DecodeRuneInString(str)
-
- switch {
- case unicode.IsUpper(r):
- buf.WriteRune(unicode.ToLower(r))
-
- case unicode.IsLower(r):
- buf.WriteRune(unicode.ToUpper(r))
-
- default:
- buf.WriteRune(r)
- }
-
- str = str[size:]
- }
-
- return buf.String()
-}
-
-// FirstRuneToUpper converts first rune to upper case if necessary.
-func FirstRuneToUpper(str string) string {
- if str == "" {
- return str
- }
-
- r, size := utf8.DecodeRuneInString(str)
-
- if !unicode.IsLower(r) {
- return str
- }
-
- buf := &bytes.Buffer{}
- buf.WriteRune(unicode.ToUpper(r))
- buf.WriteString(str[size:])
- return buf.String()
-}
-
-// FirstRuneToLower converts first rune to lower case if necessary.
-func FirstRuneToLower(str string) string {
- if str == "" {
- return str
- }
-
- r, size := utf8.DecodeRuneInString(str)
-
- if !unicode.IsUpper(r) {
- return str
- }
-
- buf := &bytes.Buffer{}
- buf.WriteRune(unicode.ToLower(r))
- buf.WriteString(str[size:])
- return buf.String()
-}
-
-// Shuffle randomizes runes in a string and returns the result.
-// It uses default random source in `math/rand`.
-func Shuffle(str string) string {
- if str == "" {
- return str
- }
-
- runes := []rune(str)
- index := 0
-
- for i := len(runes) - 1; i > 0; i-- {
- index = rand.Intn(i + 1)
-
- if i != index {
- runes[i], runes[index] = runes[index], runes[i]
- }
- }
-
- return string(runes)
-}
-
-// ShuffleSource randomizes runes in a string with given random source.
-func ShuffleSource(str string, src rand.Source) string {
- if str == "" {
- return str
- }
-
- runes := []rune(str)
- index := 0
- r := rand.New(src)
-
- for i := len(runes) - 1; i > 0; i-- {
- index = r.Intn(i + 1)
-
- if i != index {
- runes[i], runes[index] = runes[index], runes[i]
- }
- }
-
- return string(runes)
-}
-
-// Successor returns the successor to string.
-//
-// If there is one alphanumeric rune is found in string, increase the rune by 1.
-// If increment generates a "carry", the rune to the left of it is incremented.
-// This process repeats until there is no carry, adding an additional rune if necessary.
-//
-// If there is no alphanumeric rune, the rightmost rune will be increased by 1
-// regardless whether the result is a valid rune or not.
-//
-// Only following characters are alphanumeric.
-// * a - z
-// * A - Z
-// * 0 - 9
-//
-// Samples (borrowed from ruby's String#succ document):
-// "abcd" => "abce"
-// "THX1138" => "THX1139"
-// "<>" => "<>"
-// "1999zzz" => "2000aaa"
-// "ZZZ9999" => "AAAA0000"
-// "***" => "**+"
-func Successor(str string) string {
- if str == "" {
- return str
- }
-
- var r rune
- var i int
- carry := ' '
- runes := []rune(str)
- l := len(runes)
- lastAlphanumeric := l
-
- for i = l - 1; i >= 0; i-- {
- r = runes[i]
-
- if ('a' <= r && r <= 'y') ||
- ('A' <= r && r <= 'Y') ||
- ('0' <= r && r <= '8') {
- runes[i]++
- carry = ' '
- lastAlphanumeric = i
- break
- }
-
- switch r {
- case 'z':
- runes[i] = 'a'
- carry = 'a'
- lastAlphanumeric = i
-
- case 'Z':
- runes[i] = 'A'
- carry = 'A'
- lastAlphanumeric = i
-
- case '9':
- runes[i] = '0'
- carry = '0'
- lastAlphanumeric = i
- }
- }
-
- // Needs to add one character for carry.
- if i < 0 && carry != ' ' {
- buf := &bytes.Buffer{}
- buf.Grow(l + 4) // Reserve enough space for write.
-
- if lastAlphanumeric != 0 {
- buf.WriteString(str[:lastAlphanumeric])
- }
-
- buf.WriteRune(carry)
-
- for _, r = range runes[lastAlphanumeric:] {
- buf.WriteRune(r)
- }
-
- return buf.String()
- }
-
- // No alphanumeric character. Simply increase last rune's value.
- if lastAlphanumeric == l {
- runes[l-1]++
- }
-
- return string(runes)
-}
diff --git a/vendor/github.com/huandu/xstrings/count.go b/vendor/github.com/huandu/xstrings/count.go
deleted file mode 100644
index f96e38703a3..00000000000
--- a/vendor/github.com/huandu/xstrings/count.go
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2015 Huan Du. All rights reserved.
-// Licensed under the MIT license that can be found in the LICENSE file.
-
-package xstrings
-
-import (
- "unicode"
- "unicode/utf8"
-)
-
-// Len returns str's utf8 rune length.
-func Len(str string) int {
- return utf8.RuneCountInString(str)
-}
-
-// WordCount returns number of words in a string.
-//
-// Word is defined as a locale dependent string containing alphabetic characters,
-// which may also contain but not start with `'` and `-` characters.
-func WordCount(str string) int {
- var r rune
- var size, n int
-
- inWord := false
-
- for len(str) > 0 {
- r, size = utf8.DecodeRuneInString(str)
-
- switch {
- case isAlphabet(r):
- if !inWord {
- inWord = true
- n++
- }
-
- case inWord && (r == '\'' || r == '-'):
- // Still in word.
-
- default:
- inWord = false
- }
-
- str = str[size:]
- }
-
- return n
-}
-
-const minCJKCharacter = '\u3400'
-
-// Checks r is a letter but not CJK character.
-func isAlphabet(r rune) bool {
- if !unicode.IsLetter(r) {
- return false
- }
-
- switch {
- // Quick check for non-CJK character.
- case r < minCJKCharacter:
- return true
-
- // Common CJK characters.
- case r >= '\u4E00' && r <= '\u9FCC':
- return false
-
- // Rare CJK characters.
- case r >= '\u3400' && r <= '\u4D85':
- return false
-
- // Rare and historic CJK characters.
- case r >= '\U00020000' && r <= '\U0002B81D':
- return false
- }
-
- return true
-}
-
-// Width returns string width in monotype font.
-// Multi-byte characters are usually twice the width of single byte characters.
-//
-// Algorithm comes from `mb_strwidth` in PHP.
-// http://php.net/manual/en/function.mb-strwidth.php
-func Width(str string) int {
- var r rune
- var size, n int
-
- for len(str) > 0 {
- r, size = utf8.DecodeRuneInString(str)
- n += RuneWidth(r)
- str = str[size:]
- }
-
- return n
-}
-
-// RuneWidth returns character width in monotype font.
-// Multi-byte characters are usually twice the width of single byte characters.
-//
-// Algorithm comes from `mb_strwidth` in PHP.
-// http://php.net/manual/en/function.mb-strwidth.php
-func RuneWidth(r rune) int {
- switch {
- case r == utf8.RuneError || r < '\x20':
- return 0
-
- case '\x20' <= r && r < '\u2000':
- return 1
-
- case '\u2000' <= r && r < '\uFF61':
- return 2
-
- case '\uFF61' <= r && r < '\uFFA0':
- return 1
-
- case '\uFFA0' <= r:
- return 2
- }
-
- return 0
-}
diff --git a/vendor/github.com/huandu/xstrings/doc.go b/vendor/github.com/huandu/xstrings/doc.go
deleted file mode 100644
index 1a6ef069f61..00000000000
--- a/vendor/github.com/huandu/xstrings/doc.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2015 Huan Du. All rights reserved.
-// Licensed under the MIT license that can be found in the LICENSE file.
-
-// Package xstrings is to provide string algorithms which are useful but not included in `strings` package.
-// See project home page for details. https://github.com/huandu/xstrings
-//
-// Package xstrings assumes all strings are encoded in utf8.
-package xstrings
diff --git a/vendor/github.com/huandu/xstrings/format.go b/vendor/github.com/huandu/xstrings/format.go
deleted file mode 100644
index 2d02df1c042..00000000000
--- a/vendor/github.com/huandu/xstrings/format.go
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright 2015 Huan Du. All rights reserved.
-// Licensed under the MIT license that can be found in the LICENSE file.
-
-package xstrings
-
-import (
- "bytes"
- "unicode/utf8"
-)
-
-// ExpandTabs can expand tabs ('\t') rune in str to one or more spaces dpending on
-// current column and tabSize.
-// The column number is reset to zero after each newline ('\n') occurring in the str.
-//
-// ExpandTabs uses RuneWidth to decide rune's width.
-// For example, CJK characters will be treated as two characters.
-//
-// If tabSize <= 0, ExpandTabs panics with error.
-//
-// Samples:
-// ExpandTabs("a\tbc\tdef\tghij\tk", 4) => "a bc def ghij k"
-// ExpandTabs("abcdefg\thij\nk\tl", 4) => "abcdefg hij\nk l"
-// ExpandTabs("zä¸\tæ–‡\tw", 4) => "zä¸ æ–‡ w"
-func ExpandTabs(str string, tabSize int) string {
- if tabSize <= 0 {
- panic("tab size must be positive")
- }
-
- var r rune
- var i, size, column, expand int
- var output *bytes.Buffer
-
- orig := str
-
- for len(str) > 0 {
- r, size = utf8.DecodeRuneInString(str)
-
- if r == '\t' {
- expand = tabSize - column%tabSize
-
- if output == nil {
- output = allocBuffer(orig, str)
- }
-
- for i = 0; i < expand; i++ {
- output.WriteByte(byte(' '))
- }
-
- column += expand
- } else {
- if r == '\n' {
- column = 0
- } else {
- column += RuneWidth(r)
- }
-
- if output != nil {
- output.WriteRune(r)
- }
- }
-
- str = str[size:]
- }
-
- if output == nil {
- return orig
- }
-
- return output.String()
-}
-
-// LeftJustify returns a string with pad string at right side if str's rune length is smaller than length.
-// If str's rune length is larger than length, str itself will be returned.
-//
-// If pad is an empty string, str will be returned.
-//
-// Samples:
-// LeftJustify("hello", 4, " ") => "hello"
-// LeftJustify("hello", 10, " ") => "hello "
-// LeftJustify("hello", 10, "123") => "hello12312"
-func LeftJustify(str string, length int, pad string) string {
- l := Len(str)
-
- if l >= length || pad == "" {
- return str
- }
-
- remains := length - l
- padLen := Len(pad)
-
- output := &bytes.Buffer{}
- output.Grow(len(str) + (remains/padLen+1)*len(pad))
- output.WriteString(str)
- writePadString(output, pad, padLen, remains)
- return output.String()
-}
-
-// RightJustify returns a string with pad string at left side if str's rune length is smaller than length.
-// If str's rune length is larger than length, str itself will be returned.
-//
-// If pad is an empty string, str will be returned.
-//
-// Samples:
-// RightJustify("hello", 4, " ") => "hello"
-// RightJustify("hello", 10, " ") => " hello"
-// RightJustify("hello", 10, "123") => "12312hello"
-func RightJustify(str string, length int, pad string) string {
- l := Len(str)
-
- if l >= length || pad == "" {
- return str
- }
-
- remains := length - l
- padLen := Len(pad)
-
- output := &bytes.Buffer{}
- output.Grow(len(str) + (remains/padLen+1)*len(pad))
- writePadString(output, pad, padLen, remains)
- output.WriteString(str)
- return output.String()
-}
-
-// Center returns a string with pad string at both side if str's rune length is smaller than length.
-// If str's rune length is larger than length, str itself will be returned.
-//
-// If pad is an empty string, str will be returned.
-//
-// Samples:
-// Center("hello", 4, " ") => "hello"
-// Center("hello", 10, " ") => " hello "
-// Center("hello", 10, "123") => "12hello123"
-func Center(str string, length int, pad string) string {
- l := Len(str)
-
- if l >= length || pad == "" {
- return str
- }
-
- remains := length - l
- padLen := Len(pad)
-
- output := &bytes.Buffer{}
- output.Grow(len(str) + (remains/padLen+1)*len(pad))
- writePadString(output, pad, padLen, remains/2)
- output.WriteString(str)
- writePadString(output, pad, padLen, (remains+1)/2)
- return output.String()
-}
-
-func writePadString(output *bytes.Buffer, pad string, padLen, remains int) {
- var r rune
- var size int
-
- repeats := remains / padLen
-
- for i := 0; i < repeats; i++ {
- output.WriteString(pad)
- }
-
- remains = remains % padLen
-
- if remains != 0 {
- for i := 0; i < remains; i++ {
- r, size = utf8.DecodeRuneInString(pad)
- output.WriteRune(r)
- pad = pad[size:]
- }
- }
-}
diff --git a/vendor/github.com/huandu/xstrings/go.mod b/vendor/github.com/huandu/xstrings/go.mod
deleted file mode 100644
index 3982c204ca4..00000000000
--- a/vendor/github.com/huandu/xstrings/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/huandu/xstrings
-
-go 1.12
diff --git a/vendor/github.com/huandu/xstrings/manipulate.go b/vendor/github.com/huandu/xstrings/manipulate.go
deleted file mode 100644
index 0eefb43ed71..00000000000
--- a/vendor/github.com/huandu/xstrings/manipulate.go
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright 2015 Huan Du. All rights reserved.
-// Licensed under the MIT license that can be found in the LICENSE file.
-
-package xstrings
-
-import (
- "bytes"
- "strings"
- "unicode/utf8"
-)
-
-// Reverse a utf8 encoded string.
-func Reverse(str string) string {
- var size int
-
- tail := len(str)
- buf := make([]byte, tail)
- s := buf
-
- for len(str) > 0 {
- _, size = utf8.DecodeRuneInString(str)
- tail -= size
- s = append(s[:tail], []byte(str[:size])...)
- str = str[size:]
- }
-
- return string(buf)
-}
-
-// Slice a string by rune.
-//
-// Start must satisfy 0 <= start <= rune length.
-//
-// End can be positive, zero or negative.
-// If end >= 0, start and end must satisfy start <= end <= rune length.
-// If end < 0, it means slice to the end of string.
-//
-// Otherwise, Slice will panic as out of range.
-func Slice(str string, start, end int) string {
- var size, startPos, endPos int
-
- origin := str
-
- if start < 0 || end > len(str) || (end >= 0 && start > end) {
- panic("out of range")
- }
-
- if end >= 0 {
- end -= start
- }
-
- for start > 0 && len(str) > 0 {
- _, size = utf8.DecodeRuneInString(str)
- start--
- startPos += size
- str = str[size:]
- }
-
- if end < 0 {
- return origin[startPos:]
- }
-
- endPos = startPos
-
- for end > 0 && len(str) > 0 {
- _, size = utf8.DecodeRuneInString(str)
- end--
- endPos += size
- str = str[size:]
- }
-
- if len(str) == 0 && (start > 0 || end > 0) {
- panic("out of range")
- }
-
- return origin[startPos:endPos]
-}
-
-// Partition splits a string by sep into three parts.
-// The return value is a slice of strings with head, match and tail.
-//
-// If str contains sep, for example "hello" and "l", Partition returns
-// "he", "l", "lo"
-//
-// If str doesn't contain sep, for example "hello" and "x", Partition returns
-// "hello", "", ""
-func Partition(str, sep string) (head, match, tail string) {
- index := strings.Index(str, sep)
-
- if index == -1 {
- head = str
- return
- }
-
- head = str[:index]
- match = str[index : index+len(sep)]
- tail = str[index+len(sep):]
- return
-}
-
-// LastPartition splits a string by last instance of sep into three parts.
-// The return value is a slice of strings with head, match and tail.
-//
-// If str contains sep, for example "hello" and "l", LastPartition returns
-// "hel", "l", "o"
-//
-// If str doesn't contain sep, for example "hello" and "x", LastPartition returns
-// "", "", "hello"
-func LastPartition(str, sep string) (head, match, tail string) {
- index := strings.LastIndex(str, sep)
-
- if index == -1 {
- tail = str
- return
- }
-
- head = str[:index]
- match = str[index : index+len(sep)]
- tail = str[index+len(sep):]
- return
-}
-
-// Insert src into dst at given rune index.
-// Index is counted by runes instead of bytes.
-//
-// If index is out of range of dst, panic with out of range.
-func Insert(dst, src string, index int) string {
- return Slice(dst, 0, index) + src + Slice(dst, index, -1)
-}
-
-// Scrub scrubs invalid utf8 bytes with repl string.
-// Adjacent invalid bytes are replaced only once.
-func Scrub(str, repl string) string {
- var buf *bytes.Buffer
- var r rune
- var size, pos int
- var hasError bool
-
- origin := str
-
- for len(str) > 0 {
- r, size = utf8.DecodeRuneInString(str)
-
- if r == utf8.RuneError {
- if !hasError {
- if buf == nil {
- buf = &bytes.Buffer{}
- }
-
- buf.WriteString(origin[:pos])
- hasError = true
- }
- } else if hasError {
- hasError = false
- buf.WriteString(repl)
-
- origin = origin[pos:]
- pos = 0
- }
-
- pos += size
- str = str[size:]
- }
-
- if buf != nil {
- buf.WriteString(origin)
- return buf.String()
- }
-
- // No invalid byte.
- return origin
-}
-
-// WordSplit splits a string into words. Returns a slice of words.
-// If there is no word in a string, return nil.
-//
-// Word is defined as a locale dependent string containing alphabetic characters,
-// which may also contain but not start with `'` and `-` characters.
-func WordSplit(str string) []string {
- var word string
- var words []string
- var r rune
- var size, pos int
-
- inWord := false
-
- for len(str) > 0 {
- r, size = utf8.DecodeRuneInString(str)
-
- switch {
- case isAlphabet(r):
- if !inWord {
- inWord = true
- word = str
- pos = 0
- }
-
- case inWord && (r == '\'' || r == '-'):
- // Still in word.
-
- default:
- if inWord {
- inWord = false
- words = append(words, word[:pos])
- }
- }
-
- pos += size
- str = str[size:]
- }
-
- if inWord {
- words = append(words, word[:pos])
- }
-
- return words
-}
diff --git a/vendor/github.com/huandu/xstrings/translate.go b/vendor/github.com/huandu/xstrings/translate.go
deleted file mode 100644
index 66e23f86d03..00000000000
--- a/vendor/github.com/huandu/xstrings/translate.go
+++ /dev/null
@@ -1,547 +0,0 @@
-// Copyright 2015 Huan Du. All rights reserved.
-// Licensed under the MIT license that can be found in the LICENSE file.
-
-package xstrings
-
-import (
- "bytes"
- "unicode"
- "unicode/utf8"
-)
-
-type runeRangeMap struct {
- FromLo rune // Lower bound of range map.
- FromHi rune // An inclusive higher bound of range map.
- ToLo rune
- ToHi rune
-}
-
-type runeDict struct {
- Dict [unicode.MaxASCII + 1]rune
-}
-
-type runeMap map[rune]rune
-
-// Translator can translate string with pre-compiled from and to patterns.
-// If a from/to pattern pair needs to be used more than once, it's recommended
-// to create a Translator and reuse it.
-type Translator struct {
- quickDict *runeDict // A quick dictionary to look up rune by index. Only available for latin runes.
- runeMap runeMap // Rune map for translation.
- ranges []*runeRangeMap // Ranges of runes.
- mappedRune rune // If mappedRune >= 0, all matched runes are translated to the mappedRune.
- reverted bool // If to pattern is empty, all matched characters will be deleted.
- hasPattern bool
-}
-
-// NewTranslator creates new Translator through a from/to pattern pair.
-func NewTranslator(from, to string) *Translator {
- tr := &Translator{}
-
- if from == "" {
- return tr
- }
-
- reverted := from[0] == '^'
- deletion := len(to) == 0
-
- if reverted {
- from = from[1:]
- }
-
- var fromStart, fromEnd, fromRangeStep rune
- var toStart, toEnd, toRangeStep rune
- var fromRangeSize, toRangeSize rune
- var singleRunes []rune
-
- // Update the to rune range.
- updateRange := func() {
- // No more rune to read in the to rune pattern.
- if toEnd == utf8.RuneError {
- return
- }
-
- if toRangeStep == 0 {
- to, toStart, toEnd, toRangeStep = nextRuneRange(to, toEnd)
- return
- }
-
- // Current range is not empty. Consume 1 rune from start.
- if toStart != toEnd {
- toStart += toRangeStep
- return
- }
-
- // No more rune. Repeat the last rune.
- if to == "" {
- toEnd = utf8.RuneError
- return
- }
-
- // Both start and end are used. Read two more runes from the to pattern.
- to, toStart, toEnd, toRangeStep = nextRuneRange(to, utf8.RuneError)
- }
-
- if deletion {
- toStart = utf8.RuneError
- toEnd = utf8.RuneError
- } else {
- // If from pattern is reverted, only the last rune in the to pattern will be used.
- if reverted {
- var size int
-
- for len(to) > 0 {
- toStart, size = utf8.DecodeRuneInString(to)
- to = to[size:]
- }
-
- toEnd = utf8.RuneError
- } else {
- to, toStart, toEnd, toRangeStep = nextRuneRange(to, utf8.RuneError)
- }
- }
-
- fromEnd = utf8.RuneError
-
- for len(from) > 0 {
- from, fromStart, fromEnd, fromRangeStep = nextRuneRange(from, fromEnd)
-
- // fromStart is a single character. Just map it with a rune in the to pattern.
- if fromRangeStep == 0 {
- singleRunes = tr.addRune(fromStart, toStart, singleRunes)
- updateRange()
- continue
- }
-
- for toEnd != utf8.RuneError && fromStart != fromEnd {
- // If mapped rune is a single character instead of a range, simply shift first
- // rune in the range.
- if toRangeStep == 0 {
- singleRunes = tr.addRune(fromStart, toStart, singleRunes)
- updateRange()
- fromStart += fromRangeStep
- continue
- }
-
- fromRangeSize = (fromEnd - fromStart) * fromRangeStep
- toRangeSize = (toEnd - toStart) * toRangeStep
-
- // Not enough runes in the to pattern. Need to read more.
- if fromRangeSize > toRangeSize {
- fromStart, toStart = tr.addRuneRange(fromStart, fromStart+toRangeSize*fromRangeStep, toStart, toEnd, singleRunes)
- fromStart += fromRangeStep
- updateRange()
-
- // Edge case: If fromRangeSize == toRangeSize + 1, the last fromStart value needs be considered
- // as a single rune.
- if fromStart == fromEnd {
- singleRunes = tr.addRune(fromStart, toStart, singleRunes)
- updateRange()
- }
-
- continue
- }
-
- fromStart, toStart = tr.addRuneRange(fromStart, fromEnd, toStart, toStart+fromRangeSize*toRangeStep, singleRunes)
- updateRange()
- break
- }
-
- if fromStart == fromEnd {
- fromEnd = utf8.RuneError
- continue
- }
-
- fromStart, toStart = tr.addRuneRange(fromStart, fromEnd, toStart, toStart, singleRunes)
- fromEnd = utf8.RuneError
- }
-
- if fromEnd != utf8.RuneError {
- singleRunes = tr.addRune(fromEnd, toStart, singleRunes)
- }
-
- tr.reverted = reverted
- tr.mappedRune = -1
- tr.hasPattern = true
-
- // Translate RuneError only if in deletion or reverted mode.
- if deletion || reverted {
- tr.mappedRune = toStart
- }
-
- return tr
-}
-
-func (tr *Translator) addRune(from, to rune, singleRunes []rune) []rune {
- if from <= unicode.MaxASCII {
- if tr.quickDict == nil {
- tr.quickDict = &runeDict{}
- }
-
- tr.quickDict.Dict[from] = to
- } else {
- if tr.runeMap == nil {
- tr.runeMap = make(runeMap)
- }
-
- tr.runeMap[from] = to
- }
-
- singleRunes = append(singleRunes, from)
- return singleRunes
-}
-
-func (tr *Translator) addRuneRange(fromLo, fromHi, toLo, toHi rune, singleRunes []rune) (rune, rune) {
- var r rune
- var rrm *runeRangeMap
-
- if fromLo < fromHi {
- rrm = &runeRangeMap{
- FromLo: fromLo,
- FromHi: fromHi,
- ToLo: toLo,
- ToHi: toHi,
- }
- } else {
- rrm = &runeRangeMap{
- FromLo: fromHi,
- FromHi: fromLo,
- ToLo: toHi,
- ToHi: toLo,
- }
- }
-
- // If there is any single rune conflicts with this rune range, clear single rune record.
- for _, r = range singleRunes {
- if rrm.FromLo <= r && r <= rrm.FromHi {
- if r <= unicode.MaxASCII {
- tr.quickDict.Dict[r] = 0
- } else {
- delete(tr.runeMap, r)
- }
- }
- }
-
- tr.ranges = append(tr.ranges, rrm)
- return fromHi, toHi
-}
-
-func nextRuneRange(str string, last rune) (remaining string, start, end rune, rangeStep rune) {
- var r rune
- var size int
-
- remaining = str
- escaping := false
- isRange := false
-
- for len(remaining) > 0 {
- r, size = utf8.DecodeRuneInString(remaining)
- remaining = remaining[size:]
-
- // Parse special characters.
- if !escaping {
- if r == '\\' {
- escaping = true
- continue
- }
-
- if r == '-' {
- // Ignore slash at beginning of string.
- if last == utf8.RuneError {
- continue
- }
-
- start = last
- isRange = true
- continue
- }
- }
-
- escaping = false
-
- if last != utf8.RuneError {
- // This is a range which start and end are the same.
- // Considier it as a normal character.
- if isRange && last == r {
- isRange = false
- continue
- }
-
- start = last
- end = r
-
- if isRange {
- if start < end {
- rangeStep = 1
- } else {
- rangeStep = -1
- }
- }
-
- return
- }
-
- last = r
- }
-
- start = last
- end = utf8.RuneError
- return
-}
-
-// Translate str with a from/to pattern pair.
-//
-// See comment in Translate function for usage and samples.
-func (tr *Translator) Translate(str string) string {
- if !tr.hasPattern || str == "" {
- return str
- }
-
- var r rune
- var size int
- var needTr bool
-
- orig := str
-
- var output *bytes.Buffer
-
- for len(str) > 0 {
- r, size = utf8.DecodeRuneInString(str)
- r, needTr = tr.TranslateRune(r)
-
- if needTr && output == nil {
- output = allocBuffer(orig, str)
- }
-
- if r != utf8.RuneError && output != nil {
- output.WriteRune(r)
- }
-
- str = str[size:]
- }
-
- // No character is translated.
- if output == nil {
- return orig
- }
-
- return output.String()
-}
-
-// TranslateRune return translated rune and true if r matches the from pattern.
-// If r doesn't match the pattern, original r is returned and translated is false.
-func (tr *Translator) TranslateRune(r rune) (result rune, translated bool) {
- switch {
- case tr.quickDict != nil:
- if r <= unicode.MaxASCII {
- result = tr.quickDict.Dict[r]
-
- if result != 0 {
- translated = true
-
- if tr.mappedRune >= 0 {
- result = tr.mappedRune
- }
-
- break
- }
- }
-
- fallthrough
-
- case tr.runeMap != nil:
- var ok bool
-
- if result, ok = tr.runeMap[r]; ok {
- translated = true
-
- if tr.mappedRune >= 0 {
- result = tr.mappedRune
- }
-
- break
- }
-
- fallthrough
-
- default:
- var rrm *runeRangeMap
- ranges := tr.ranges
-
- for i := len(ranges) - 1; i >= 0; i-- {
- rrm = ranges[i]
-
- if rrm.FromLo <= r && r <= rrm.FromHi {
- translated = true
-
- if tr.mappedRune >= 0 {
- result = tr.mappedRune
- break
- }
-
- if rrm.ToLo < rrm.ToHi {
- result = rrm.ToLo + r - rrm.FromLo
- } else if rrm.ToLo > rrm.ToHi {
- // ToHi can be smaller than ToLo if range is from higher to lower.
- result = rrm.ToLo - r + rrm.FromLo
- } else {
- result = rrm.ToLo
- }
-
- break
- }
- }
- }
-
- if tr.reverted {
- if !translated {
- result = tr.mappedRune
- }
-
- translated = !translated
- }
-
- if !translated {
- result = r
- }
-
- return
-}
-
-// HasPattern returns true if Translator has one pattern at least.
-func (tr *Translator) HasPattern() bool {
- return tr.hasPattern
-}
-
-// Translate str with the characters defined in from replaced by characters defined in to.
-//
-// From and to are patterns representing a set of characters. Pattern is defined as following.
-//
-// * Special characters
-// * '-' means a range of runes, e.g.
-// * "a-z" means all characters from 'a' to 'z' inclusive;
-// * "z-a" means all characters from 'z' to 'a' inclusive.
-// * '^' as first character means a set of all runes excepted listed, e.g.
-// * "^a-z" means all characters except 'a' to 'z' inclusive.
-// * '\' escapes special characters.
-// * Normal character represents itself, e.g. "abc" is a set including 'a', 'b' and 'c'.
-//
-// Translate will try to find a 1:1 mapping from from to to.
-// If to is smaller than from, last rune in to will be used to map "out of range" characters in from.
-//
-// Note that '^' only works in the from pattern. It will be considered as a normal character in the to pattern.
-//
-// If the to pattern is an empty string, Translate works exactly the same as Delete.
-//
-// Samples:
-// Translate("hello", "aeiou", "12345") => "h2ll4"
-// Translate("hello", "a-z", "A-Z") => "HELLO"
-// Translate("hello", "z-a", "a-z") => "svool"
-// Translate("hello", "aeiou", "*") => "h*ll*"
-// Translate("hello", "^l", "*") => "**ll*"
-// Translate("hello ^ world", `\^lo`, "*") => "he*** * w*r*d"
-func Translate(str, from, to string) string {
- tr := NewTranslator(from, to)
- return tr.Translate(str)
-}
-
-// Delete runes in str matching the pattern.
-// Pattern is defined in Translate function.
-//
-// Samples:
-// Delete("hello", "aeiou") => "hll"
-// Delete("hello", "a-k") => "llo"
-// Delete("hello", "^a-k") => "he"
-func Delete(str, pattern string) string {
- tr := NewTranslator(pattern, "")
- return tr.Translate(str)
-}
-
-// Count how many runes in str match the pattern.
-// Pattern is defined in Translate function.
-//
-// Samples:
-// Count("hello", "aeiou") => 3
-// Count("hello", "a-k") => 3
-// Count("hello", "^a-k") => 2
-func Count(str, pattern string) int {
- if pattern == "" || str == "" {
- return 0
- }
-
- var r rune
- var size int
- var matched bool
-
- tr := NewTranslator(pattern, "")
- cnt := 0
-
- for len(str) > 0 {
- r, size = utf8.DecodeRuneInString(str)
- str = str[size:]
-
- if _, matched = tr.TranslateRune(r); matched {
- cnt++
- }
- }
-
- return cnt
-}
-
-// Squeeze deletes adjacent repeated runes in str.
-// If pattern is not empty, only runes matching the pattern will be squeezed.
-//
-// Samples:
-// Squeeze("hello", "") => "helo"
-// Squeeze("hello", "m-z") => "hello"
-// Squeeze("hello world", " ") => "hello world"
-func Squeeze(str, pattern string) string {
- var last, r rune
- var size int
- var skipSqueeze, matched bool
- var tr *Translator
- var output *bytes.Buffer
-
- orig := str
- last = -1
-
- if len(pattern) > 0 {
- tr = NewTranslator(pattern, "")
- }
-
- for len(str) > 0 {
- r, size = utf8.DecodeRuneInString(str)
-
- // Need to squeeze the str.
- if last == r && !skipSqueeze {
- if tr != nil {
- if _, matched = tr.TranslateRune(r); !matched {
- skipSqueeze = true
- }
- }
-
- if output == nil {
- output = allocBuffer(orig, str)
- }
-
- if skipSqueeze {
- output.WriteRune(r)
- }
- } else {
- if output != nil {
- output.WriteRune(r)
- }
-
- last = r
- skipSqueeze = false
- }
-
- str = str[size:]
- }
-
- if output == nil {
- return orig
- }
-
- return output.String()
-}
diff --git a/vendor/github.com/imdario/mergo/.deepsource.toml b/vendor/github.com/imdario/mergo/.deepsource.toml
deleted file mode 100644
index 8a0681af855..00000000000
--- a/vendor/github.com/imdario/mergo/.deepsource.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-version = 1
-
-test_patterns = [
- "*_test.go"
-]
-
-[[analyzers]]
-name = "go"
-enabled = true
-
- [analyzers.meta]
- import_path = "github.com/imdario/mergo"
\ No newline at end of file
diff --git a/vendor/github.com/imdario/mergo/.gitignore b/vendor/github.com/imdario/mergo/.gitignore
deleted file mode 100644
index 529c3412ba9..00000000000
--- a/vendor/github.com/imdario/mergo/.gitignore
+++ /dev/null
@@ -1,33 +0,0 @@
-#### joe made this: http://goel.io/joe
-
-#### go ####
-# Binaries for programs and plugins
-*.exe
-*.dll
-*.so
-*.dylib
-
-# Test binary, build with `go test -c`
-*.test
-
-# Output of the go coverage tool, specifically when used with LiteIDE
-*.out
-
-# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
-.glide/
-
-#### vim ####
-# Swap
-[._]*.s[a-v][a-z]
-[._]*.sw[a-p]
-[._]s[a-v][a-z]
-[._]sw[a-p]
-
-# Session
-Session.vim
-
-# Temporary
-.netrwhist
-*~
-# Auto-generated tag files
-tags
diff --git a/vendor/github.com/imdario/mergo/.travis.yml b/vendor/github.com/imdario/mergo/.travis.yml
deleted file mode 100644
index dad29725f86..00000000000
--- a/vendor/github.com/imdario/mergo/.travis.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-language: go
-install:
- - go get -t
- - go get golang.org/x/tools/cmd/cover
- - go get github.com/mattn/goveralls
-script:
- - go test -race -v ./...
-after_script:
- - $HOME/gopath/bin/goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN
diff --git a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md
deleted file mode 100644
index 469b44907a0..00000000000
--- a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Contributor Covenant Code of Conduct
-
-## Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment include:
-
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
-
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/
diff --git a/vendor/github.com/imdario/mergo/LICENSE b/vendor/github.com/imdario/mergo/LICENSE
deleted file mode 100644
index 686680298da..00000000000
--- a/vendor/github.com/imdario/mergo/LICENSE
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright (c) 2013 Dario Castañé. All rights reserved.
-Copyright (c) 2012 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/imdario/mergo/README.md b/vendor/github.com/imdario/mergo/README.md
deleted file mode 100644
index 02fc81e0626..00000000000
--- a/vendor/github.com/imdario/mergo/README.md
+++ /dev/null
@@ -1,238 +0,0 @@
-# Mergo
-
-A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
-
-Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
-
-## Status
-
-It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
-
-[![GoDoc][3]][4]
-[![GoCard][5]][6]
-[![Build Status][1]][2]
-[![Coverage Status][7]][8]
-[![Sourcegraph][9]][10]
-[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield)
-
-[1]: https://travis-ci.org/imdario/mergo.png
-[2]: https://travis-ci.org/imdario/mergo
-[3]: https://godoc.org/github.com/imdario/mergo?status.svg
-[4]: https://godoc.org/github.com/imdario/mergo
-[5]: https://goreportcard.com/badge/imdario/mergo
-[6]: https://goreportcard.com/report/github.com/imdario/mergo
-[7]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
-[8]: https://coveralls.io/github/imdario/mergo?branch=master
-[9]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
-[10]: https://sourcegraph.com/github.com/imdario/mergo?badge
-
-### Latest release
-
-[Release v0.3.7](https://github.com/imdario/mergo/releases/tag/v0.3.7).
-
-### Important note
-
-Please keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2) Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). An optional/variadic argument has been added, so it won't break existing code.
-
-If you were using Mergo **before** April 6th 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause (I hope it won't!) in existing projects after the change (release 0.2.0).
-
-### Donations
-
-If Mergo is useful to you, consider buying me a coffee, a beer or making a monthly donation so I can keep building great free software. :heart_eyes:
-
-
-[![Beerpay](https://beerpay.io/imdario/mergo/badge.svg)](https://beerpay.io/imdario/mergo)
-[![Beerpay](https://beerpay.io/imdario/mergo/make-wish.svg)](https://beerpay.io/imdario/mergo)
-
-
-### Mergo in the wild
-
-- [moby/moby](https://github.com/moby/moby)
-- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
-- [vmware/dispatch](https://github.com/vmware/dispatch)
-- [Shopify/themekit](https://github.com/Shopify/themekit)
-- [imdario/zas](https://github.com/imdario/zas)
-- [matcornic/hermes](https://github.com/matcornic/hermes)
-- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go)
-- [kataras/iris](https://github.com/kataras/iris)
-- [michaelsauter/crane](https://github.com/michaelsauter/crane)
-- [go-task/task](https://github.com/go-task/task)
-- [sensu/uchiwa](https://github.com/sensu/uchiwa)
-- [ory/hydra](https://github.com/ory/hydra)
-- [sisatech/vcli](https://github.com/sisatech/vcli)
-- [dairycart/dairycart](https://github.com/dairycart/dairycart)
-- [projectcalico/felix](https://github.com/projectcalico/felix)
-- [resin-os/balena](https://github.com/resin-os/balena)
-- [go-kivik/kivik](https://github.com/go-kivik/kivik)
-- [Telefonica/govice](https://github.com/Telefonica/govice)
-- [supergiant/supergiant](supergiant/supergiant)
-- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce)
-- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy)
-- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel)
-- [EagerIO/Stout](https://github.com/EagerIO/Stout)
-- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api)
-- [russross/canvasassignments](https://github.com/russross/canvasassignments)
-- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api)
-- [casualjim/exeggutor](https://github.com/casualjim/exeggutor)
-- [divshot/gitling](https://github.com/divshot/gitling)
-- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl)
-- [andrerocker/deploy42](https://github.com/andrerocker/deploy42)
-- [elwinar/rambler](https://github.com/elwinar/rambler)
-- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman)
-- [jfbus/impressionist](https://github.com/jfbus/impressionist)
-- [Jmeyering/zealot](https://github.com/Jmeyering/zealot)
-- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host)
-- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go)
-- [thoas/picfit](https://github.com/thoas/picfit)
-- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
-- [jnuthong/item_search](https://github.com/jnuthong/item_search)
-- [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
-
-## Installation
-
- go get github.com/imdario/mergo
-
- // use in your .go code
- import (
- "github.com/imdario/mergo"
- )
-
-## Usage
-
-You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are not considered zero values](https://golang.org/ref/spec#The_zero_value) either. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
-
-```go
-if err := mergo.Merge(&dst, src); err != nil {
- // ...
-}
-```
-
-Also, you can merge overwriting values using the transformer `WithOverride`.
-
-```go
-if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
- // ...
-}
-```
-
-Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
-
-```go
-if err := mergo.Map(&dst, srcMap); err != nil {
- // ...
-}
-```
-
-Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values.
-
-More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo).
-
-### Nice example
-
-```go
-package main
-
-import (
- "fmt"
- "github.com/imdario/mergo"
-)
-
-type Foo struct {
- A string
- B int64
-}
-
-func main() {
- src := Foo{
- A: "one",
- B: 2,
- }
- dest := Foo{
- A: "two",
- }
- mergo.Merge(&dest, src)
- fmt.Println(dest)
- // Will print
- // {two 2}
-}
-```
-
-Note: if test are failing due missing package, please execute:
-
- go get gopkg.in/yaml.v2
-
-### Transformers
-
-Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`?
-
-```go
-package main
-
-import (
- "fmt"
- "github.com/imdario/mergo"
- "reflect"
- "time"
-)
-
-type timeTransfomer struct {
-}
-
-func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
- if typ == reflect.TypeOf(time.Time{}) {
- return func(dst, src reflect.Value) error {
- if dst.CanSet() {
- isZero := dst.MethodByName("IsZero")
- result := isZero.Call([]reflect.Value{})
- if result[0].Bool() {
- dst.Set(src)
- }
- }
- return nil
- }
- }
- return nil
-}
-
-type Snapshot struct {
- Time time.Time
- // ...
-}
-
-func main() {
- src := Snapshot{time.Now()}
- dest := Snapshot{}
- mergo.Merge(&dest, src, mergo.WithTransformers(timeTransfomer{}))
- fmt.Println(dest)
- // Will print
- // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
-}
-```
-
-
-## Contact me
-
-If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
-
-## About
-
-Written by [Dario Castañé](http://dario.im).
-
-## Top Contributors
-
-[![0](https://sourcerer.io/fame/imdario/imdario/mergo/images/0)](https://sourcerer.io/fame/imdario/imdario/mergo/links/0)
-[![1](https://sourcerer.io/fame/imdario/imdario/mergo/images/1)](https://sourcerer.io/fame/imdario/imdario/mergo/links/1)
-[![2](https://sourcerer.io/fame/imdario/imdario/mergo/images/2)](https://sourcerer.io/fame/imdario/imdario/mergo/links/2)
-[![3](https://sourcerer.io/fame/imdario/imdario/mergo/images/3)](https://sourcerer.io/fame/imdario/imdario/mergo/links/3)
-[![4](https://sourcerer.io/fame/imdario/imdario/mergo/images/4)](https://sourcerer.io/fame/imdario/imdario/mergo/links/4)
-[![5](https://sourcerer.io/fame/imdario/imdario/mergo/images/5)](https://sourcerer.io/fame/imdario/imdario/mergo/links/5)
-[![6](https://sourcerer.io/fame/imdario/imdario/mergo/images/6)](https://sourcerer.io/fame/imdario/imdario/mergo/links/6)
-[![7](https://sourcerer.io/fame/imdario/imdario/mergo/images/7)](https://sourcerer.io/fame/imdario/imdario/mergo/links/7)
-
-
-## License
-
-[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
-
-
-[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_large)
diff --git a/vendor/github.com/imdario/mergo/doc.go b/vendor/github.com/imdario/mergo/doc.go
deleted file mode 100644
index 6e9aa7baf35..00000000000
--- a/vendor/github.com/imdario/mergo/doc.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 Dario Castañé. All rights reserved.
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package mergo merges same-type structs and maps by setting default values in zero-value fields.
-
-Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
-
-Usage
-
-From my own work-in-progress project:
-
- type networkConfig struct {
- Protocol string
- Address string
- ServerType string `json: "server_type"`
- Port uint16
- }
-
- type FssnConfig struct {
- Network networkConfig
- }
-
- var fssnDefault = FssnConfig {
- networkConfig {
- "tcp",
- "127.0.0.1",
- "http",
- 31560,
- },
- }
-
- // Inside a function [...]
-
- if err := mergo.Merge(&config, fssnDefault); err != nil {
- log.Fatal(err)
- }
-
- // More code [...]
-
-*/
-package mergo
diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/github.com/imdario/mergo/map.go
deleted file mode 100644
index d83258b4dda..00000000000
--- a/vendor/github.com/imdario/mergo/map.go
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2014 Dario Castañé. All rights reserved.
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Based on src/pkg/reflect/deepequal.go from official
-// golang's stdlib.
-
-package mergo
-
-import (
- "fmt"
- "reflect"
- "unicode"
- "unicode/utf8"
-)
-
-func changeInitialCase(s string, mapper func(rune) rune) string {
- if s == "" {
- return s
- }
- r, n := utf8.DecodeRuneInString(s)
- return string(mapper(r)) + s[n:]
-}
-
-func isExported(field reflect.StructField) bool {
- r, _ := utf8.DecodeRuneInString(field.Name)
- return r >= 'A' && r <= 'Z'
-}
-
-// Traverses recursively both values, assigning src's fields values to dst.
-// The map argument tracks comparisons that have already been seen, which allows
-// short circuiting on recursive types.
-func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
- overwrite := config.Overwrite
- if dst.CanAddr() {
- addr := dst.UnsafeAddr()
- h := 17 * addr
- seen := visited[h]
- typ := dst.Type()
- for p := seen; p != nil; p = p.next {
- if p.ptr == addr && p.typ == typ {
- return nil
- }
- }
- // Remember, remember...
- visited[h] = &visit{addr, typ, seen}
- }
- zeroValue := reflect.Value{}
- switch dst.Kind() {
- case reflect.Map:
- dstMap := dst.Interface().(map[string]interface{})
- for i, n := 0, src.NumField(); i < n; i++ {
- srcType := src.Type()
- field := srcType.Field(i)
- if !isExported(field) {
- continue
- }
- fieldName := field.Name
- fieldName = changeInitialCase(fieldName, unicode.ToLower)
- if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v)) || overwrite) {
- dstMap[fieldName] = src.Field(i).Interface()
- }
- }
- case reflect.Ptr:
- if dst.IsNil() {
- v := reflect.New(dst.Type().Elem())
- dst.Set(v)
- }
- dst = dst.Elem()
- fallthrough
- case reflect.Struct:
- srcMap := src.Interface().(map[string]interface{})
- for key := range srcMap {
- config.overwriteWithEmptyValue = true
- srcValue := srcMap[key]
- fieldName := changeInitialCase(key, unicode.ToUpper)
- dstElement := dst.FieldByName(fieldName)
- if dstElement == zeroValue {
- // We discard it because the field doesn't exist.
- continue
- }
- srcElement := reflect.ValueOf(srcValue)
- dstKind := dstElement.Kind()
- srcKind := srcElement.Kind()
- if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
- srcElement = srcElement.Elem()
- srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
- } else if dstKind == reflect.Ptr {
- // Can this work? I guess it can't.
- if srcKind != reflect.Ptr && srcElement.CanAddr() {
- srcPtr := srcElement.Addr()
- srcElement = reflect.ValueOf(srcPtr)
- srcKind = reflect.Ptr
- }
- }
-
- if !srcElement.IsValid() {
- continue
- }
- if srcKind == dstKind {
- if _, err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
- return
- }
- } else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
- if _, err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
- return
- }
- } else if srcKind == reflect.Map {
- if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
- return
- }
- } else {
- return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
- }
- }
- }
- return
-}
-
-// Map sets fields' values in dst from src.
-// src can be a map with string keys or a struct. dst must be the opposite:
-// if src is a map, dst must be a valid pointer to struct. If src is a struct,
-// dst must be map[string]interface{}.
-// It won't merge unexported (private) fields and will do recursively
-// any exported field.
-// If dst is a map, keys will be src fields' names in lower camel case.
-// Missing key in src that doesn't match a field in dst will be skipped. This
-// doesn't apply if dst is a map.
-// This is separated method from Merge because it is cleaner and it keeps sane
-// semantics: merging equal types, mapping different (restricted) types.
-func Map(dst, src interface{}, opts ...func(*Config)) error {
- return _map(dst, src, opts...)
-}
-
-// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by
-// non-empty src attribute values.
-// Deprecated: Use Map(…) with WithOverride
-func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
- return _map(dst, src, append(opts, WithOverride)...)
-}
-
-func _map(dst, src interface{}, opts ...func(*Config)) error {
- var (
- vDst, vSrc reflect.Value
- err error
- )
- config := &Config{}
-
- for _, opt := range opts {
- opt(config)
- }
-
- if vDst, vSrc, err = resolveValues(dst, src); err != nil {
- return err
- }
- // To be friction-less, we redirect equal-type arguments
- // to deepMerge. Only because arguments can be anything.
- if vSrc.Kind() == vDst.Kind() {
- _, err := deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
- return err
- }
- switch vSrc.Kind() {
- case reflect.Struct:
- if vDst.Kind() != reflect.Map {
- return ErrExpectedMapAsDestination
- }
- case reflect.Map:
- if vDst.Kind() != reflect.Struct {
- return ErrExpectedStructAsDestination
- }
- default:
- return ErrNotSupported
- }
- return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
-}
diff --git a/vendor/github.com/imdario/mergo/merge.go b/vendor/github.com/imdario/mergo/merge.go
deleted file mode 100644
index 3332c9c2a7a..00000000000
--- a/vendor/github.com/imdario/mergo/merge.go
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright 2013 Dario Castañé. All rights reserved.
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Based on src/pkg/reflect/deepequal.go from official
-// golang's stdlib.
-
-package mergo
-
-import (
- "fmt"
- "reflect"
- "unsafe"
-)
-
-func hasExportedField(dst reflect.Value) (exported bool) {
- for i, n := 0, dst.NumField(); i < n; i++ {
- field := dst.Type().Field(i)
- if isExportedComponent(&field) {
- return true
- }
- }
- return
-}
-
-func isExportedComponent(field *reflect.StructField) bool {
- name := field.Name
- pkgPath := field.PkgPath
- if len(pkgPath) > 0 {
- return false
- }
- c := name[0]
- if 'a' <= c && c <= 'z' || c == '_' {
- return false
- }
- return true
-}
-
-type Config struct {
- Overwrite bool
- AppendSlice bool
- TypeCheck bool
- Transformers Transformers
- overwriteWithEmptyValue bool
- overwriteSliceWithEmptyValue bool
-}
-
-type Transformers interface {
- Transformer(reflect.Type) func(dst, src reflect.Value) error
-}
-
-// Traverses recursively both values, assigning src's fields values to dst.
-// The map argument tracks comparisons that have already been seen, which allows
-// short circuiting on recursive types.
-func deepMerge(dstIn, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (dst reflect.Value, err error) {
- dst = dstIn
- overwrite := config.Overwrite
- typeCheck := config.TypeCheck
- overwriteWithEmptySrc := config.overwriteWithEmptyValue
- overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
-
- if !src.IsValid() {
- return
- }
-
- if dst.CanAddr() {
- addr := dst.UnsafeAddr()
- h := 17 * addr
- seen := visited[h]
- typ := dst.Type()
- for p := seen; p != nil; p = p.next {
- if p.ptr == addr && p.typ == typ {
- return dst, nil
- }
- }
- // Remember, remember...
- visited[h] = &visit{addr, typ, seen}
- }
-
- if config.Transformers != nil && !isEmptyValue(dst) {
- if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
- err = fn(dst, src)
- return
- }
- }
-
- if dst.IsValid() && src.IsValid() && src.Type() != dst.Type() {
- err = fmt.Errorf("cannot append two different types (%s, %s)", src.Kind(), dst.Kind())
- return
- }
-
- switch dst.Kind() {
- case reflect.Struct:
- if hasExportedField(dst) {
- dstCp := reflect.New(dst.Type()).Elem()
- for i, n := 0, dst.NumField(); i < n; i++ {
- dstField := dst.Field(i)
- structField := dst.Type().Field(i)
- // copy un-exported struct fields
- if !isExportedComponent(&structField) {
- rf := dstCp.Field(i)
- rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem() //nolint:gosec
- dstRF := dst.Field(i)
- if !dst.Field(i).CanAddr() {
- continue
- }
-
- dstRF = reflect.NewAt(dstRF.Type(), unsafe.Pointer(dstRF.UnsafeAddr())).Elem() //nolint:gosec
- rf.Set(dstRF)
- continue
- }
- dstField, err = deepMerge(dstField, src.Field(i), visited, depth+1, config)
- if err != nil {
- return
- }
- dstCp.Field(i).Set(dstField)
- }
-
- if dst.CanSet() {
- dst.Set(dstCp)
- } else {
- dst = dstCp
- }
- return
- } else {
- if (isReflectNil(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc) {
- dst = src
- }
- }
-
- case reflect.Map:
- if dst.IsNil() && !src.IsNil() {
- if dst.CanSet() {
- dst.Set(reflect.MakeMap(dst.Type()))
- } else {
- dst = src
- return
- }
- }
- for _, key := range src.MapKeys() {
- srcElement := src.MapIndex(key)
- dstElement := dst.MapIndex(key)
- if !srcElement.IsValid() {
- continue
- }
- if dst.MapIndex(key).IsValid() {
- k := dstElement.Interface()
- dstElement = reflect.ValueOf(k)
- }
- if isReflectNil(srcElement) {
- if overwrite || isReflectNil(dstElement) {
- dst.SetMapIndex(key, srcElement)
- }
- continue
- }
- if !srcElement.CanInterface() {
- continue
- }
-
- if srcElement.CanInterface() {
- srcElement = reflect.ValueOf(srcElement.Interface())
- if dstElement.IsValid() {
- dstElement = reflect.ValueOf(dstElement.Interface())
- }
- }
- dstElement, err = deepMerge(dstElement, srcElement, visited, depth+1, config)
- if err != nil {
- return
- }
- dst.SetMapIndex(key, dstElement)
-
- }
- case reflect.Slice:
- newSlice := dst
- if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
- if typeCheck && src.Type() != dst.Type() {
- return dst, fmt.Errorf("cannot override two slices with different type (%s, %s)", src.Type(), dst.Type())
- }
- newSlice = src
- } else if config.AppendSlice {
- if typeCheck && src.Type() != dst.Type() {
- err = fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
- return
- }
- newSlice = reflect.AppendSlice(dst, src)
- }
- if dst.CanSet() {
- dst.Set(newSlice)
- } else {
- dst = newSlice
- }
- case reflect.Ptr, reflect.Interface:
- if isReflectNil(src) {
- break
- }
-
- if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
- if dst.IsNil() || overwrite {
- if overwrite || isEmptyValue(dst) {
- if dst.CanSet() {
- dst.Set(src)
- } else {
- dst = src
- }
- }
- }
- break
- }
-
- if src.Kind() != reflect.Interface {
- if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
- if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
- dst.Set(src)
- }
- } else if src.Kind() == reflect.Ptr {
- if dst, err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
- return
- }
- dst = dst.Addr()
- } else if dst.Elem().Type() == src.Type() {
- if dst, err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
- return
- }
- } else {
- return dst, ErrDifferentArgumentsTypes
- }
- break
- }
- if dst.IsNil() || overwrite {
- if (overwrite || isEmptyValue(dst)) && (overwriteWithEmptySrc || !isEmptyValue(src)) {
- if dst.CanSet() {
- dst.Set(src)
- } else {
- dst = src
- }
- }
- } else if _, err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
- return
- }
- default:
- overwriteFull := (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst))
- if overwriteFull {
- if dst.CanSet() {
- dst.Set(src)
- } else {
- dst = src
- }
- }
- }
-
- return
-}
-
-// Merge will fill any empty for value type attributes on the dst struct using corresponding
-// src attributes if they themselves are not empty. dst and src must be valid same-type structs
-// and dst must be a pointer to struct.
-// It won't merge unexported (private) fields and will do recursively any exported field.
-func Merge(dst, src interface{}, opts ...func(*Config)) error {
- return merge(dst, src, opts...)
-}
-
-// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
-// non-empty src attribute values.
-// Deprecated: use Merge(…) with WithOverride
-func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
- return merge(dst, src, append(opts, WithOverride)...)
-}
-
-// WithTransformers adds transformers to merge, allowing to customize the merging of some types.
-func WithTransformers(transformers Transformers) func(*Config) {
- return func(config *Config) {
- config.Transformers = transformers
- }
-}
-
-// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
-func WithOverride(config *Config) {
- config.Overwrite = true
-}
-
-// WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values.
-func WithOverwriteWithEmptyValue(config *Config) {
- config.overwriteWithEmptyValue = true
-}
-
-// WithOverrideEmptySlice will make merge override empty dst slice with empty src slice.
-func WithOverrideEmptySlice(config *Config) {
- config.overwriteSliceWithEmptyValue = true
-}
-
-// WithAppendSlice will make merge append slices instead of overwriting it.
-func WithAppendSlice(config *Config) {
- config.AppendSlice = true
-}
-
-// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
-func WithTypeCheck(config *Config) {
- config.TypeCheck = true
-}
-
-func merge(dst, src interface{}, opts ...func(*Config)) error {
- var (
- vDst, vSrc reflect.Value
- err error
- )
-
- config := &Config{}
-
- for _, opt := range opts {
- opt(config)
- }
-
- if vDst, vSrc, err = resolveValues(dst, src); err != nil {
- return err
- }
- if !vDst.CanSet() {
- return fmt.Errorf("cannot set dst, needs reference")
- }
- if vDst.Type() != vSrc.Type() {
- return ErrDifferentArgumentsTypes
- }
- _, err = deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
- return err
-}
-
-// IsReflectNil is the reflect value provided nil
-func isReflectNil(v reflect.Value) bool {
- k := v.Kind()
- switch k {
- case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr:
- // Both interface and slice are nil if first word is 0.
- // Both are always bigger than a word; assume flagIndir.
- return v.IsNil()
- default:
- return false
- }
-}
diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/github.com/imdario/mergo/mergo.go
deleted file mode 100644
index a82fea2fdcc..00000000000
--- a/vendor/github.com/imdario/mergo/mergo.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2013 Dario Castañé. All rights reserved.
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Based on src/pkg/reflect/deepequal.go from official
-// golang's stdlib.
-
-package mergo
-
-import (
- "errors"
- "reflect"
-)
-
-// Errors reported by Mergo when it finds invalid arguments.
-var (
- ErrNilArguments = errors.New("src and dst must not be nil")
- ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
- ErrNotSupported = errors.New("only structs and maps are supported")
- ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
- ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
-)
-
-// During deepMerge, must keep track of checks that are
-// in progress. The comparison algorithm assumes that all
-// checks in progress are true when it reencounters them.
-// Visited are stored in a map indexed by 17 * a1 + a2;
-type visit struct {
- ptr uintptr
- typ reflect.Type
- next *visit
-}
-
-// From src/pkg/encoding/json/encode.go.
-func isEmptyValue(v reflect.Value) bool {
- switch v.Kind() {
- case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
- return v.Len() == 0
- case reflect.Bool:
- return !v.Bool()
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return v.Int() == 0
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return v.Uint() == 0
- case reflect.Float32, reflect.Float64:
- return v.Float() == 0
- case reflect.Interface, reflect.Ptr:
- if v.IsNil() {
- return true
- }
- return isEmptyValue(v.Elem())
- case reflect.Func:
- return v.IsNil()
- case reflect.Invalid:
- return true
- }
- return false
-}
-
-func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
- if dst == nil || src == nil {
- err = ErrNilArguments
- return
- }
- vDst = reflect.ValueOf(dst).Elem()
- if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map {
- err = ErrNotSupported
- return
- }
- vSrc = reflect.ValueOf(src)
- // We check if vSrc is a pointer to dereference it.
- if vSrc.Kind() == reflect.Ptr {
- vSrc = vSrc.Elem()
- }
- return
-}
-
-// Traverses recursively both values, assigning src's fields values to dst.
-// The map argument tracks comparisons that have already been seen, which allows
-// short circuiting on recursive types.
-func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) {
- if dst.CanAddr() {
- addr := dst.UnsafeAddr()
- h := 17 * addr
- seen := visited[h]
- typ := dst.Type()
- for p := seen; p != nil; p = p.next {
- if p.ptr == addr && p.typ == typ {
- return nil
- }
- }
- // Remember, remember...
- visited[h] = &visit{addr, typ, seen}
- }
- return // TODO refactor
-}
diff --git a/vendor/github.com/jensneuse/abstractlogger/.gitignore b/vendor/github.com/jensneuse/abstractlogger/.gitignore
deleted file mode 100644
index ab9d06dfe41..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.idea
-
-abstractlogger.test
-mem.out
\ No newline at end of file
diff --git a/vendor/github.com/jensneuse/abstractlogger/README.md b/vendor/github.com/jensneuse/abstractlogger/README.md
deleted file mode 100644
index 33b0650f171..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/README.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# abstractlogger
-
-Abstractlogger is a logging frontend to abstract away logging from your frontend of choice.
-
-Abstractlogger enables you to use your logging backend of choice.
-Currently there's a zap and logrus implementation.
-Feel free to add additional logging backend implementations.
-
-You should consider using abstract logger in two situations:
-1. You're building a library and don't want to make the choice for your user on which logging backend to use.
-2. You're building an application and want logging in the hot path. You're unsure which logging library to use. In this case Abstractlogger helps you to keep your domain logic separated from a 3rd party logging library as you can change it every time without updating all of your code.
-
-If you feel an important logging method is missing please file an issue or create a PR.
-Tested code is welcomed.
-
-## Benchmarks
-
-```text
-BenchmarkNoopLogger/with_interface/log_level_invalid/noop-16 15396679 84.4 ns/op 448 B/op 2 allocs/op
-BenchmarkNoopLogger/with_interface/log_level_invalid/logrus-16 2463068 486 ns/op 1938 B/op 14 allocs/op
-BenchmarkNoopLogger/with_interface/log_level_invalid/zap-16 13834630 85.3 ns/op 352 B/op 2 allocs/op
-BenchmarkNoopLogger/with_interface/log_level_invalid/abstract_zap-16 50709734 24.4 ns/op 96 B/op 1 allocs/op
-BenchmarkNoopLogger/with_interface/log_level_invalid/abstract_logrus-16 48983234 23.2 ns/op 96 B/op 1 allocs/op
-BenchmarkNoopLogger/with_interface/log_level_valid/noop-16 14264962 81.6 ns/op 448 B/op 2 allocs/op
-BenchmarkNoopLogger/with_interface/log_level_valid/logrus-16 158092 6919 ns/op 3401 B/op 44 allocs/op
-BenchmarkNoopLogger/with_interface/log_level_valid/zap-16 4579869 277 ns/op 434 B/op 3 allocs/op
-BenchmarkNoopLogger/with_interface/log_level_valid/abstract_zap-16 3741235 325 ns/op 434 B/op 3 allocs/op
-BenchmarkNoopLogger/with_interface/log_level_valid/abstract_logrus-16 157494 6822 ns/op 2433 B/op 40 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_invalid/noop-16 18548176 62.5 ns/op 288 B/op 1 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_invalid/logrus-16 3592113 380 ns/op 1393 B/op 10 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_invalid/zap-16 23941255 48.3 ns/op 192 B/op 1 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_invalid/abstract_zap-16 250681747 5.14 ns/op 0 B/op 0 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_invalid/abstract_logrus-16 238591336 4.96 ns/op 0 B/op 0 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_valid/noop-16 16967037 67.3 ns/op 288 B/op 1 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_valid/logrus-16 180975 6104 ns/op 2742 B/op 38 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_valid/zap-16 10197316 126 ns/op 192 B/op 1 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_valid/abstract_zap-16 8566719 145 ns/op 192 B/op 1 allocs/op
-BenchmarkNoopLogger/without_interface/log_level_valid/abstract_logrus-16 178683 5900 ns/op 2224 B/op 37 allocs/op
-```
-
-The library improves the performance for non valid log levels by ~10x (zap) and ~76x (logrus).
-For valid log levels the overhead is minimal: No additional allocations, 13% increase (145ns vs. 126ns) for zap without using Any.
\ No newline at end of file
diff --git a/vendor/github.com/jensneuse/abstractlogger/doc.go b/vendor/github.com/jensneuse/abstractlogger/doc.go
deleted file mode 100644
index 3808baf77b0..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/doc.go
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-package abstractlogger solves the problem of abstracting away a logging frontend from a logging backend.
-
-Usually you would choose the best logger you can for your project.
-This can be determined by specific needs regarding the interface of the logger or just requirements regarding performance.
-
-But what if you want to change the logger easily?
-What if you're building a library and want your users to be able to use whatever logging library they want?
-
-This is exactly the problem abstractlogger tries to solve.
-This package acts as a "frontend" for logging that lets you or your users choose the backend.
-
-You're free to use one of the existing implementations, e.g. zap or logrus which are common across the community.
-If that doesn't satisfy your needs feel free to implement the interface yourself.
-You're invited to contribute back your additional implementations.
-
-If you think the Logger interface/frontend doesn't satisfy your needs feel free to add additional funcs via a PR.
-*/
-package abstractlogger
diff --git a/vendor/github.com/jensneuse/abstractlogger/field.go b/vendor/github.com/jensneuse/abstractlogger/field.go
deleted file mode 100644
index 513bc27e846..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/field.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package abstractlogger
-
-type Field struct {
- kind FieldKind
- key string
- stringValue string
- stringsValue []string
- intValue int64
- byteValue []byte
- interfaceValue interface{}
- errorValue error
-}
-
-type FieldKind int
-
-const (
- StringField FieldKind = iota + 1
- StringsField
- IntField
- BoolField
- ByteStringField
- InterfaceField
- ErrorField
- NamedErrorField
-)
-
-func Any(key string, value interface{}) Field {
- return Field{
- kind: InterfaceField,
- key: key,
- interfaceValue: value,
- }
-}
-
-func Error(err error) Field {
- return Field{
- kind: ErrorField,
- key: "error",
- errorValue: err,
- }
-}
-
-func NamedError(key string, err error) Field {
- return Field{
- kind: NamedErrorField,
- key: key,
- errorValue: err,
- }
-}
-
-func String(key, value string) Field {
- return Field{
- kind: StringField,
- key: key,
- stringValue: value,
- }
-}
-
-func Strings(key string, value []string) Field {
- return Field{
- key: key,
- kind: StringsField,
- stringsValue: value,
- }
-}
-
-func Int(key string, value int) Field {
- return Field{
- kind: IntField,
- key: key,
- intValue: int64(value),
- }
-}
-
-func Bool(key string, value bool) Field {
- var integer int64
- if value {
- integer = 1
- }
- return Field{
- kind: BoolField,
- key: key,
- intValue: integer,
- }
-}
-
-func ByteString(key string, value []byte) Field {
- return Field{
- kind: ByteStringField,
- key: key,
- byteValue: value,
- }
-}
diff --git a/vendor/github.com/jensneuse/abstractlogger/go.mod b/vendor/github.com/jensneuse/abstractlogger/go.mod
deleted file mode 100644
index 6f5082697d5..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/go.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-module github.com/jensneuse/abstractlogger
-
-go 1.13
-
-require (
- github.com/sirupsen/logrus v1.4.2
- go.uber.org/zap v1.13.0
-)
diff --git a/vendor/github.com/jensneuse/abstractlogger/go.sum b/vendor/github.com/jensneuse/abstractlogger/go.sum
deleted file mode 100644
index 683ba5de90c..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/go.sum
+++ /dev/null
@@ -1,69 +0,0 @@
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
-github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
-go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
-go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
-go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
-go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
-golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
-golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
diff --git a/vendor/github.com/jensneuse/abstractlogger/level.go b/vendor/github.com/jensneuse/abstractlogger/level.go
deleted file mode 100644
index 6740bd3b69d..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/level.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package abstractlogger
-
-// LevelCheck is a simple helper function to check the logging level before invoking the logging backend
-// This is a very helpful optimization because it can avoid calling into variadic functions of the logging backend of your choice.
-// In case of logrus this makes for a 300x improvement in performance (time/op) on a missed log level.
-// In case of zap this improves the performance (time/op) by at least 69x on a missed log level.
-type LevelCheck struct {
- level Level
-}
-
-func NewLevelCheck (level Level) LevelCheck {
- return LevelCheck{
- level:level,
- }
-}
-
-// Level are all possible logging levels in increasing order, starting with DebugLevel
-type Level int
-
-const (
- DebugLevel Level = iota - 1
- InfoLevel
- WarnLevel
- ErrorLevel
- PanicLevel
- FatalLevel
-)
-
-// Check returns true if the supplied logging level should be logged.
-// Because the logging levels are increasing this is a simple greater equals check.
-func (l LevelCheck) Check(level Level) bool {
- return level >= l.level
-}
\ No newline at end of file
diff --git a/vendor/github.com/jensneuse/abstractlogger/logger.go b/vendor/github.com/jensneuse/abstractlogger/logger.go
deleted file mode 100644
index 584dda6b326..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/logger.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package abstractlogger
-
-// Logger is the interface to abstract away a general purpose logger
-type Logger interface {
- DebugLogger
- InfoLogger
- WarnLogger
- ErrorLogger
- FatalLogger
- PanicLogger
- LevelLogger(level Level) LevelLogger
-}
-
-type LevelLogger interface {
- Println(v ...interface{})
- Printf(format string, v ...interface{})
-}
-
-// NoopLogger satisfies the Logger interface while doing nothing
-var NoopLogger Logger = Noop{}
-
-type DebugLogger interface {
- Debug(msg string,fields ...Field)
-}
-
-type ErrorLogger interface {
- Error(msg string,fields ...Field)
-}
-
-type FatalLogger interface {
- Fatal(msg string,fields ...Field)
-}
-
-type InfoLogger interface {
- Info(msg string,fields ...Field)
-}
-
-type PanicLogger interface {
- Panic(msg string,fields ...Field)
-}
-
-type WarnLogger interface {
- Warn(msg string,fields ...Field)
-}
-
-type LevelNoop struct {}
-
-func (_ LevelNoop) Println(v ...interface{}) {
-
-}
-
-func (_ LevelNoop) Printf(format string, v ...interface{}) {
-
-}
-
-type Noop struct {}
-
-func (_ Noop) LevelLogger(level Level) LevelLogger {
- return LevelNoop{}
-}
-
-func (_ Noop) Debug(msg string, fields ...Field) {
-
-}
-
-func (_ Noop) Info(msg string, fields ...Field) {
-
-}
-
-func (_ Noop) Warn(msg string, fields ...Field) {
-
-}
-
-func (_ Noop) Error(msg string, fields ...Field) {
-
-}
-
-func (_ Noop) Fatal(msg string, fields ...Field) {
-
-}
-
-func (_ Noop) Panic(msg string, fields ...Field) {
-
-}
-
diff --git a/vendor/github.com/jensneuse/abstractlogger/logrus.go b/vendor/github.com/jensneuse/abstractlogger/logrus.go
deleted file mode 100644
index a93d2b2bea4..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/logrus.go
+++ /dev/null
@@ -1,130 +0,0 @@
-package abstractlogger
-
-import (
- "github.com/sirupsen/logrus"
-)
-
-func NewLogrusLogger(l *logrus.Logger, level Level) *LogrusLogger {
- return &LogrusLogger{
- l: l,
- levelCheck: NewLevelCheck(level),
- }
-}
-
-// LogrusLogger implements the Logger frontend using the popular logrus library as a backend
-// It makes use of the LevelCheck helper to increase performance
-type LogrusLogger struct {
- l *logrus.Logger
- levelCheck LevelCheck
-}
-
-func (l *LogrusLogger) LevelLogger(level Level) LevelLogger {
- return &LogrusLevelLogger{
- l: l.l,
- level: level,
- }
-}
-
-func (l *LogrusLogger) fields(fields []Field) logrus.Fields {
- out := make(logrus.Fields, len(fields))
- for i := range fields {
- switch fields[i].kind {
- case StringField:
- out[fields[i].key] = fields[i].stringValue
- case ByteStringField:
- out[fields[i].key] = string(fields[i].byteValue)
- case IntField:
- out[fields[i].key] = fields[i].intValue
- case BoolField:
- out[fields[i].key] = fields[i].intValue != 0
- case ErrorField, NamedErrorField:
- out[fields[i].key] = fields[i].errorValue
- case StringsField:
- out[fields[i].key] = fields[i].stringsValue
- default:
- out[fields[i].key] = fields[i].interfaceValue
- }
- }
- return out
-}
-
-func (l *LogrusLogger) Debug(msg string, fields ...Field) {
- if !l.levelCheck.Check(DebugLevel) {
- return
- }
- l.l.WithFields(l.fields(fields)).Debug(msg)
-}
-
-func (l *LogrusLogger) Info(msg string, fields ...Field) {
- if !l.levelCheck.Check(InfoLevel) {
- return
- }
- l.l.WithFields(l.fields(fields)).Info(msg)
-}
-
-func (l *LogrusLogger) Warn(msg string, fields ...Field) {
- if !l.levelCheck.Check(WarnLevel) {
- return
- }
- l.l.WithFields(l.fields(fields)).Warn(msg)
-}
-
-func (l *LogrusLogger) Error(msg string, fields ...Field) {
- if !l.levelCheck.Check(ErrorLevel) {
- return
- }
- l.l.WithFields(l.fields(fields)).Error(msg)
-}
-
-func (l *LogrusLogger) Fatal(msg string, fields ...Field) {
- if !l.levelCheck.Check(FatalLevel) {
- return
- }
- l.l.WithFields(l.fields(fields)).Fatal(msg)
-}
-
-func (l *LogrusLogger) Panic(msg string, fields ...Field) {
- if !l.levelCheck.Check(PanicLevel) {
- return
- }
- l.l.WithFields(l.fields(fields)).Panic(msg)
-}
-
-type LogrusLevelLogger struct {
- l *logrus.Logger
- level Level
-}
-
-func (s *LogrusLevelLogger) Println(v ...interface{}) {
- switch s.level {
- case DebugLevel:
- s.l.Debug(v...)
- case InfoLevel:
- s.l.Info(v...)
- case WarnLevel:
- s.l.Warn(v...)
- case ErrorLevel:
- s.l.Error(v...)
- case FatalLevel:
- s.l.Fatal(v...)
- case PanicLevel:
- s.l.Panic(v...)
- }
-}
-
-func (s *LogrusLevelLogger) Printf(format string, v ...interface{}) {
- switch s.level {
- case DebugLevel:
- s.l.Debugf(format, v...)
- case InfoLevel:
- s.l.Infof(format, v...)
- case WarnLevel:
- s.l.Warnf(format, v...)
- case ErrorLevel:
- s.l.Errorf(format, v...)
- case FatalLevel:
- s.l.Fatalf(format, v...)
- case PanicLevel:
- s.l.Panicf(format, v...)
- }
-}
diff --git a/vendor/github.com/jensneuse/abstractlogger/zap.go b/vendor/github.com/jensneuse/abstractlogger/zap.go
deleted file mode 100644
index 8bb9ee89c0d..00000000000
--- a/vendor/github.com/jensneuse/abstractlogger/zap.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package abstractlogger
-
-import (
- "go.uber.org/zap"
-)
-
-func NewZapLogger(zapLogger *zap.Logger, level Level) *ZapLogger {
- return &ZapLogger{
- l: zapLogger,
- levelCheck: NewLevelCheck(level),
- }
-}
-
-// ZapLogger implements the Logging frontend using the popular logging backend zap
-// It uses the LevelCheck helper to increase performance.
-type ZapLogger struct {
- l *zap.Logger
- levelCheck LevelCheck
-}
-
-func (z *ZapLogger) LevelLogger(level Level) LevelLogger {
- return &ZapLevelLogger{
- l: z.l.Sugar(),
- level: level,
- }
-}
-
-func (z *ZapLogger) field(field Field) zap.Field {
- switch field.kind {
- case StringField:
- return zap.String(field.key, field.stringValue)
- case IntField:
- return zap.Int(field.key, int(field.intValue))
- case BoolField:
- return zap.Bool(field.key, field.intValue != 0)
- case ByteStringField:
- return zap.ByteString(field.key, field.byteValue)
- case ErrorField:
- return zap.Error(field.errorValue)
- case NamedErrorField:
- return zap.NamedError(field.key, field.errorValue)
- case StringsField:
- return zap.Strings(field.key, field.stringsValue)
- default:
- return zap.Any(field.key, field.interfaceValue)
- }
-}
-
-func (z *ZapLogger) fields(fields []Field) []zap.Field {
- out := make([]zap.Field, len(fields))
- for i := range fields {
- out[i] = z.field(fields[i])
- }
- return out
-}
-
-func (z *ZapLogger) Debug(msg string, fields ...Field) {
- if !z.levelCheck.Check(DebugLevel) {
- return
- }
- z.l.Debug(msg, z.fields(fields)...)
-}
-
-func (z *ZapLogger) Info(msg string, fields ...Field) {
- if !z.levelCheck.Check(InfoLevel) {
- return
- }
- z.l.Info(msg, z.fields(fields)...)
-}
-
-func (z *ZapLogger) Warn(msg string, fields ...Field) {
- if !z.levelCheck.Check(WarnLevel) {
- return
- }
- z.l.Warn(msg, z.fields(fields)...)
-}
-
-func (z *ZapLogger) Error(msg string, fields ...Field) {
- if !z.levelCheck.Check(ErrorLevel) {
- return
- }
- z.l.Error(msg, z.fields(fields)...)
-}
-
-func (z *ZapLogger) Fatal(msg string, fields ...Field) {
- if !z.levelCheck.Check(FatalLevel) {
- return
- }
- z.l.Fatal(msg, z.fields(fields)...)
-}
-
-func (z *ZapLogger) Panic(msg string, fields ...Field) {
- if !z.levelCheck.Check(PanicLevel) {
- return
- }
- z.l.Panic(msg, z.fields(fields)...)
-}
-
-type ZapLevelLogger struct {
- l *zap.SugaredLogger
- level Level
-}
-
-func (z *ZapLevelLogger) Println(v ...interface{}) {
- switch z.level {
- case DebugLevel:
- z.l.Debug(v...)
- case InfoLevel:
- z.l.Info(v...)
- case WarnLevel:
- z.l.Warn(v...)
- case ErrorLevel:
- z.l.Error(v...)
- case FatalLevel:
- z.l.Fatal(v...)
- case PanicLevel:
- z.l.Panic(v...)
- }
-}
-
-func (z *ZapLevelLogger) Printf(format string, v ...interface{}) {
- switch z.level {
- case DebugLevel:
- z.l.Debugf(format, v...)
- case InfoLevel:
- z.l.Infof(format, v...)
- case WarnLevel:
- z.l.Warnf(format, v...)
- case ErrorLevel:
- z.l.Errorf(format, v...)
- case FatalLevel:
- z.l.Fatalf(format, v...)
- case PanicLevel:
- z.l.Panicf(format, v...)
- }
-}
diff --git a/vendor/github.com/jensneuse/byte-template/.gitignore b/vendor/github.com/jensneuse/byte-template/.gitignore
deleted file mode 100644
index 485dee64bcf..00000000000
--- a/vendor/github.com/jensneuse/byte-template/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.idea
diff --git a/vendor/github.com/jensneuse/byte-template/README.md b/vendor/github.com/jensneuse/byte-template/README.md
deleted file mode 100644
index 7f0e72d7ec3..00000000000
--- a/vendor/github.com/jensneuse/byte-template/README.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# byte-template
-
-Byte Template is a templating engine for byte slices with custom directives.
-
-```go
-package main
-import (
- "bytes"
- "fmt"
- "github.com/jensneuse/byte-template"
- "io"
-)
-
-func main() {
- template := byte_template.New(byte_template.DirectiveDefinition{
- Name:[]byte("toLower"),
- Resolve:func(w io.Writer, arg []byte) (n int,err error) {
- return w.Write(bytes.ToLower(arg))
- },
- })
- buf := bytes.Buffer{}
- _,_ = template.Execute(&buf,[]byte("/api/user/{{ toLower .name }}"),func(w io.Writer, path []byte) (n int,err error) {
- if bytes.Equal(path,[]byte("name")){
- _,err = w.Write([]byte("Jens"))
- }
- return
- })
- fmt.Println(buf.String()) // Output: jens
-}
-```
-
-# Contributors
-
-- [Jens Neuse][jens-neuse-github] (Project Lead & Active Maintainer)
-- [Sergey Petrunin][sergey-petrunin-github] (Project Lead & Active Maintainer)
-
-[jens-neuse-github]: https://github.com/jensneuse
-[sergey-petrunin-github]: https://github.com/spetrunin
\ No newline at end of file
diff --git a/vendor/github.com/jensneuse/byte-template/go.mod b/vendor/github.com/jensneuse/byte-template/go.mod
deleted file mode 100644
index 543d54c7fd9..00000000000
--- a/vendor/github.com/jensneuse/byte-template/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/jensneuse/byte-template
-
-go 1.13
diff --git a/vendor/github.com/jensneuse/byte-template/templating.go b/vendor/github.com/jensneuse/byte-template/templating.go
deleted file mode 100644
index b9c49e62887..00000000000
--- a/vendor/github.com/jensneuse/byte-template/templating.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// byte_templating is intended to offer a simple templating engine for byte slices
-// it's different from other implementations in two ways
-// 1. you can define the "item" selector on your own, that is you don't have to supply a interface{} object, similar to https://github.com/valyala/fasttemplate
-// 2. in addition to fasttemplate you can also define custom directives like "toLower", "URLEncode" etc.
-// This library doesn't push any gc pressure to the user
-// This library is not thread safe, use it with a sync.Pool
-package byte_template
-
-import (
- "bytes"
- "io"
-)
-
-type Template struct {
- baseTemplate
- input []byte
- fetch Fetch
- directives []DirectiveDefinition
- buf bytes.Buffer
- instructions []instruction
-}
-
-type baseTemplate struct {
- startToken byte
- endToken byte
-}
-
-var defaultBaseTemplate = baseTemplate{
- startToken: '{',
- endToken: '}',
-}
-
-type Fetch func(w io.Writer, path []byte) (n int, err error)
-
-func New(directiveDefinitions ...DirectiveDefinition) *Template {
- return &Template{
- baseTemplate: defaultBaseTemplate,
- directives: directiveDefinitions,
- }
-}
-
-type instructionKind int
-
-const (
- write instructionKind = iota + 1
- template
-)
-
-type instruction struct {
- kind instructionKind
- start int
- end int
- directive arg
- item arg
-}
-
-type arg struct {
- defined bool
- start int
- end int
-}
-
-func (t *Template) Execute(w io.Writer, input []byte, fetch Fetch) (n int, err error) {
-
- t.input = input
- t.instructions = t.instructions[:0]
- t.fetch = fetch
-
- var (
- lastPosition int
- insideTemplate bool
- insideItem bool
- )
-
- length := len(t.input)
- for i := 1; i < length; i++ {
- switch t.input[i] {
- case t.startToken:
- if !insideTemplate && t.input[i-1] == t.startToken {
- insideTemplate = true
- t.instructions = append(t.instructions, instruction{
- kind: write,
- start: lastPosition,
- end: i - 1,
- }, instruction{
- kind: template,
- })
- i = i + 1
- }
- case t.endToken:
- if i+1 < length && t.input[i+1] == t.endToken {
- insideTemplate = false
- i = i + 2
- lastPosition = i
- }
- }
- if insideTemplate {
- switch {
- case !insideItem && !t.byteIsWhitespace(t.input[i]):
- lastPosition = i
- insideItem = true
- case len(t.instructions) != 0 && (insideItem && i+1 < length && t.byteIsWhitespace(t.input[i+1]) ||
- insideItem && i+2 < length && t.input[i+1] == t.endToken && t.input[i+2] == t.endToken):
- if t.input[lastPosition] == '.' {
- // item
- t.instructions[len(t.instructions)-1].item.start = lastPosition
- t.instructions[len(t.instructions)-1].item.end = i + 1
- t.instructions[len(t.instructions)-1].item.defined = true
- } else {
- // directive
- t.instructions[len(t.instructions)-1].directive.start = lastPosition
- t.instructions[len(t.instructions)-1].directive.end = i + 1
- t.instructions[len(t.instructions)-1].directive.defined = true
- }
- insideItem = false
- lastPosition = i + 1
- }
- }
- }
-
- if len(t.instructions) == 0 {
- return w.Write(t.input)
- } else {
- t.instructions = append(t.instructions, instruction{
- kind: write,
- start: lastPosition,
- end: length,
- })
- }
-
- return t.executeInstructions(w, t.instructions)
-}
-
-func (t *Template) executeInstructions(w io.Writer, instructions []instruction) (n int, err error) {
- for i := range instructions {
- switch instructions[i].kind {
- case write:
- n, err = w.Write(t.input[instructions[i].start:instructions[i].end])
- if err != nil {
- return
- }
- case template:
- itemPath := t.input[instructions[i].item.start:instructions[i].item.end]
- t.buf.Reset()
- n, err = t.fetch(&t.buf, itemPath)
- if err != nil {
- return
- }
-
- if instructions[i].directive.defined {
- directiveName := t.input[instructions[i].directive.start:instructions[i].directive.end]
- for k := range t.directives {
- if bytes.Equal(directiveName, t.directives[k].Name) {
- n, err = t.directives[k].Resolve(w, t.buf.Bytes())
- if err != nil {
- return
- }
- }
- }
- } else {
- _, err = t.buf.WriteTo(w)
- if err != nil {
- return
- }
- }
- }
- }
- return
-}
-
-func (t *Template) byteIsWhitespace(r byte) bool {
- switch r {
- case ' ', '\t', '\r', '\n':
- return true
- default:
- return false
- }
-}
-
-type DirectiveDefinition struct {
- Name []byte
- Resolve func(w io.Writer, arg []byte) (n int, err error)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/LICENSE b/vendor/github.com/jensneuse/graphql-go-tools/LICENSE
deleted file mode 100644
index efc56cd1fce..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2018 Jens Neuse
-
-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.
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/internal/pkg/quotes/quotes.go b/vendor/github.com/jensneuse/graphql-go-tools/internal/pkg/quotes/quotes.go
deleted file mode 100644
index 87f2e66de90..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/internal/pkg/quotes/quotes.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package quotes
-
-const (
- quoteStr = "\""
-)
-
-var (
- quoteBytes = []byte(quoteStr)
-)
-
-func WrapBytes(bytes []byte) []byte {
- cp := make([]byte, len(bytes))
- copy(cp, bytes)
- return append(quoteBytes, append(cp, quoteBytes...)...)
-}
-
-func WrapString(str string) string {
- return quoteStr + str + quoteStr
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes/unsafebytes.go b/vendor/github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes/unsafebytes.go
deleted file mode 100644
index 1a5d86c0f22..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes/unsafebytes.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package unsafebytes
-
-import (
- "reflect"
- "strconv"
- "unsafe"
-)
-
-func BytesToInt64(byteSlice []byte) int64 {
- out, _ := strconv.ParseInt(*(*string)(unsafe.Pointer(&byteSlice)), 10, 64)
- return out
-}
-
-func BytesToFloat32(byteSlice []byte) float32 {
- out, _ := strconv.ParseFloat(*(*string)(unsafe.Pointer(&byteSlice)), 64)
- return float32(out)
-}
-
-func BytesToString(bytes []byte) string {
- sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
- stringHeader := reflect.StringHeader{Data: sliceHeader.Data, Len: sliceHeader.Len}
- return *(*string)(unsafe.Pointer(&stringHeader))
-}
-
-func BytesToBool(byteSlice []byte) bool {
- out, _ := strconv.ParseBool(*(*string)(unsafe.Pointer(&byteSlice)))
- return out
-}
-
-func StringToBytes(str string) []byte {
- hdr := *(*reflect.StringHeader)(unsafe.Pointer(&str))
- return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
- Data: hdr.Data,
- Len: hdr.Len,
- Cap: hdr.Len,
- }))
-}
-
-func BytesIsValidFloat32(byteSlice []byte) bool {
- _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&byteSlice)), 64)
- return err == nil
-}
-
-func BytesIsValidInt64(byteSlice []byte) bool {
- _, err := strconv.ParseInt(*(*string)(unsafe.Pointer(&byteSlice)), 10, 64)
- return err == nil
-}
-
-func BytesIsValidBool(byteSlice []byte) bool {
- _, err := strconv.ParseBool(*(*string)(unsafe.Pointer(&byteSlice)))
- return err == nil
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast.go
deleted file mode 100644
index 6fa9b81a8be..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast.go
+++ /dev/null
@@ -1,250 +0,0 @@
-//go:generate stringer -type=OperationType,ValueKind,TypeKind,SelectionKind,NodeKind,PathKind -output ast_string.go
-
-// Package ast defines the GraphQL AST and offers helper methods to interact with the AST, mostly to get the necessary information from the ast.
-//
-// The document struct is designed in a way to enable performant parsing while keeping the ast easy to use with helper methods.
-package ast
-
-type Document struct {
- Input Input
- RootNodes []Node
- SchemaDefinitions []SchemaDefinition
- SchemaExtensions []SchemaExtension
- RootOperationTypeDefinitions []RootOperationTypeDefinition
- Directives []Directive
- Arguments []Argument
- ObjectTypeDefinitions []ObjectTypeDefinition
- ObjectTypeExtensions []ObjectTypeExtension
- FieldDefinitions []FieldDefinition
- Types []Type
- InputValueDefinitions []InputValueDefinition
- InputObjectTypeDefinitions []InputObjectTypeDefinition
- InputObjectTypeExtensions []InputObjectTypeExtension
- ScalarTypeDefinitions []ScalarTypeDefinition
- ScalarTypeExtensions []ScalarTypeExtension
- InterfaceTypeDefinitions []InterfaceTypeDefinition
- InterfaceTypeExtensions []InterfaceTypeExtension
- UnionTypeDefinitions []UnionTypeDefinition
- UnionTypeExtensions []UnionTypeExtension
- EnumTypeDefinitions []EnumTypeDefinition
- EnumTypeExtensions []EnumTypeExtension
- EnumValueDefinitions []EnumValueDefinition
- DirectiveDefinitions []DirectiveDefinition
- Values []Value
- ListValues []ListValue
- VariableValues []VariableValue
- StringValues []StringValue
- IntValues []IntValue
- FloatValues []FloatValue
- EnumValues []EnumValue
- ObjectFields []ObjectField
- ObjectValues []ObjectValue
- Selections []Selection
- SelectionSets []SelectionSet
- Fields []Field
- InlineFragments []InlineFragment
- FragmentSpreads []FragmentSpread
- OperationDefinitions []OperationDefinition
- VariableDefinitions []VariableDefinition
- FragmentDefinitions []FragmentDefinition
- BooleanValues [2]BooleanValue
- Refs [][8]int
- RefIndex int
- Index Index
-}
-
-func (d *Document) IndexOf(slice []int, ref int) (int, bool) {
- for i, j := range slice {
- if ref == j {
- return i, true
- }
- }
- return -1, false
-}
-
-func NewDocument() *Document {
- return &Document{
- RootNodes: make([]Node, 0, 48),
- RootOperationTypeDefinitions: make([]RootOperationTypeDefinition, 0, 3),
- SchemaDefinitions: make([]SchemaDefinition, 0, 2),
- SchemaExtensions: make([]SchemaExtension, 0, 2),
- Directives: make([]Directive, 0, 16),
- Arguments: make([]Argument, 0, 48),
- ObjectTypeDefinitions: make([]ObjectTypeDefinition, 0, 48),
- ObjectTypeExtensions: make([]ObjectTypeExtension, 0, 4),
- Types: make([]Type, 0, 48),
- FieldDefinitions: make([]FieldDefinition, 0, 128),
- InputValueDefinitions: make([]InputValueDefinition, 0, 128),
- InputObjectTypeDefinitions: make([]InputObjectTypeDefinition, 0, 16),
- InputObjectTypeExtensions: make([]InputObjectTypeExtension, 0, 4),
- ScalarTypeDefinitions: make([]ScalarTypeDefinition, 0, 16),
- ScalarTypeExtensions: make([]ScalarTypeExtension, 0, 4),
- InterfaceTypeDefinitions: make([]InterfaceTypeDefinition, 0, 16),
- InterfaceTypeExtensions: make([]InterfaceTypeExtension, 0, 4),
- UnionTypeDefinitions: make([]UnionTypeDefinition, 0, 8),
- UnionTypeExtensions: make([]UnionTypeExtension, 0, 4),
- EnumTypeDefinitions: make([]EnumTypeDefinition, 0, 8),
- EnumTypeExtensions: make([]EnumTypeExtension, 0, 4),
- EnumValueDefinitions: make([]EnumValueDefinition, 0, 48),
- DirectiveDefinitions: make([]DirectiveDefinition, 0, 8),
- VariableValues: make([]VariableValue, 0, 8),
- StringValues: make([]StringValue, 0, 24),
- EnumValues: make([]EnumValue, 0, 24),
- IntValues: make([]IntValue, 0, 128),
- FloatValues: make([]FloatValue, 0, 128),
- Values: make([]Value, 0, 64),
- ListValues: make([]ListValue, 0, 4),
- ObjectFields: make([]ObjectField, 0, 64),
- ObjectValues: make([]ObjectValue, 0, 16),
- Selections: make([]Selection, 0, 128),
- SelectionSets: make([]SelectionSet, 0, 48),
- Fields: make([]Field, 0, 128),
- InlineFragments: make([]InlineFragment, 0, 16),
- FragmentSpreads: make([]FragmentSpread, 0, 16),
- OperationDefinitions: make([]OperationDefinition, 0, 8),
- VariableDefinitions: make([]VariableDefinition, 0, 8),
- FragmentDefinitions: make([]FragmentDefinition, 0, 8),
- BooleanValues: [2]BooleanValue{false, true},
- Refs: make([][8]int, 48),
- RefIndex: -1,
- Index: Index{
- nodes: make(map[uint64][]Node, 48),
- },
- }
-}
-
-func (d *Document) Reset() {
- d.RootNodes = d.RootNodes[:0]
- d.SchemaDefinitions = d.SchemaDefinitions[:0]
- d.SchemaExtensions = d.SchemaExtensions[:0]
- d.RootOperationTypeDefinitions = d.RootOperationTypeDefinitions[:0]
- d.Directives = d.Directives[:0]
- d.Arguments = d.Arguments[:0]
- d.ObjectTypeDefinitions = d.ObjectTypeDefinitions[:0]
- d.ObjectTypeExtensions = d.ObjectTypeExtensions[:0]
- d.Types = d.Types[:0]
- d.FieldDefinitions = d.FieldDefinitions[:0]
- d.InputValueDefinitions = d.InputValueDefinitions[:0]
- d.InputObjectTypeDefinitions = d.InputObjectTypeDefinitions[:0]
- d.InputObjectTypeExtensions = d.InputObjectTypeExtensions[:0]
- d.ScalarTypeDefinitions = d.ScalarTypeDefinitions[:0]
- d.ScalarTypeExtensions = d.ScalarTypeExtensions[:0]
- d.InterfaceTypeDefinitions = d.InterfaceTypeDefinitions[:0]
- d.InterfaceTypeExtensions = d.InterfaceTypeExtensions[:0]
- d.UnionTypeDefinitions = d.UnionTypeDefinitions[:0]
- d.UnionTypeExtensions = d.UnionTypeExtensions[:0]
- d.EnumTypeDefinitions = d.EnumTypeDefinitions[:0]
- d.EnumTypeExtensions = d.EnumTypeExtensions[:0]
- d.EnumValueDefinitions = d.EnumValueDefinitions[:0]
- d.DirectiveDefinitions = d.DirectiveDefinitions[:0]
- d.VariableValues = d.VariableValues[:0]
- d.StringValues = d.StringValues[:0]
- d.EnumValues = d.EnumValues[:0]
- d.IntValues = d.IntValues[:0]
- d.FloatValues = d.FloatValues[:0]
- d.Values = d.Values[:0]
- d.ListValues = d.ListValues[:0]
- d.ObjectFields = d.ObjectFields[:0]
- d.ObjectValues = d.ObjectValues[:0]
- d.Selections = d.Selections[:0]
- d.SelectionSets = d.SelectionSets[:0]
- d.Fields = d.Fields[:0]
- d.InlineFragments = d.InlineFragments[:0]
- d.FragmentSpreads = d.FragmentSpreads[:0]
- d.OperationDefinitions = d.OperationDefinitions[:0]
- d.VariableDefinitions = d.VariableDefinitions[:0]
- d.FragmentDefinitions = d.FragmentDefinitions[:0]
-
- d.RefIndex = -1
- d.Index.Reset()
- d.Input.Reset()
-}
-
-func (d *Document) NextRefIndex() int {
- d.RefIndex++
- if d.RefIndex == len(d.Refs) {
- d.Refs = append(d.Refs, [8]int{})
- }
- return d.RefIndex
-}
-
-func (d *Document) AddRootNode(node Node) {
- d.RootNodes = append(d.RootNodes, node)
- d.Index.AddNodeStr(d.NodeNameString(node), node)
-}
-
-func (d *Document) ImportRootNode(ref int, kind NodeKind) {
- d.AddRootNode(Node{
- Kind: kind,
- Ref: ref,
- })
-}
-
-func (d *Document) DeleteRootNodes(nodes []Node) {
- for i := range nodes {
- d.DeleteRootNode(nodes[i])
- }
-}
-
-func (d *Document) DeleteRootNode(node Node) {
- for i := range d.RootNodes {
- if d.RootNodes[i].Kind == node.Kind && d.RootNodes[i].Ref == node.Ref {
- d.RootNodes = append(d.RootNodes[:i], d.RootNodes[i+1:]...)
- return
- }
- }
-}
-
-func (d *Document) RemoveMergedTypeExtensions() {
- for _, node := range d.Index.MergedTypeExtensions {
- d.RemoveRootNode(node)
- }
-}
-
-func (d *Document) RemoveRootNode(node Node) {
- for i := range d.RootNodes {
- if d.RootNodes[i] == node {
- d.RootNodes = append(d.RootNodes[:i], d.RootNodes[i+1:]...)
- return
- }
- }
-}
-
-func (d *Document) NodeByName(name ByteSlice) (Node, bool) {
- node, exists := d.Index.FirstNodeByNameBytes(name)
- return node, exists
-}
-
-func (d *Document) TypeDefinitionContainsImplementsInterface(typeName, interfaceName ByteSlice) bool {
- typeDefinition, exists := d.Index.FirstNodeByNameBytes(typeName)
- if !exists {
- return false
- }
- if typeDefinition.Kind != NodeKindObjectTypeDefinition {
- return false
- }
- return d.ObjectTypeDefinitionImplementsInterface(typeDefinition.Ref, interfaceName)
-}
-
-func FilterIntSliceByWhitelist(intSlice []int, whitelist []int) []int {
- if len(intSlice) == 0 || len(whitelist) == 0 {
- return []int{}
- }
- n := 0
- for i := 0; i < len(intSlice); i++ {
- if isWhitelisted(intSlice[i], whitelist) {
- intSlice[n] = intSlice[i]
- n++
- }
- }
- return intSlice[:n]
-}
-
-func isWhitelisted(value int, whitelisted []int) bool {
- for i := 0; i < len(whitelisted); i++ {
- if whitelisted[i] == value {
- return true
- }
- }
- return false
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_argument.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_argument.go
deleted file mode 100644
index 94afb38e154..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_argument.go
+++ /dev/null
@@ -1,159 +0,0 @@
-package ast
-
-import (
- "bytes"
- "io"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type ArgumentList struct {
- LPAREN position.Position
- Refs []int // Argument
- RPAREN position.Position
-}
-
-type Argument struct {
- Name ByteSliceReference // e.g. foo
- Colon position.Position // :
- Value Value // e.g. 100 or "Bar"
-}
-
-func (d *Document) PrintArgument(ref int, w io.Writer) error {
- _, err := w.Write(d.Input.ByteSlice(d.Arguments[ref].Name))
- if err != nil {
- return err
- }
- _, err = w.Write(literal.COLON)
- if err != nil {
- return err
- }
- _, err = w.Write(literal.SPACE)
- if err != nil {
- return err
- }
- return d.PrintValue(d.Arguments[ref].Value, w)
-}
-
-func (d *Document) PrintArguments(refs []int, w io.Writer) (err error) {
- _, err = w.Write(literal.LPAREN)
- if err != nil {
- return
- }
- for i, j := range refs {
- err = d.PrintArgument(j, w)
- if err != nil {
- return
- }
- if i != len(refs)-1 {
- _, err = w.Write(literal.COMMA)
- if err != nil {
- return
- }
- _, err = w.Write(literal.SPACE)
- if err != nil {
- return
- }
- }
- }
- _, err = w.Write(literal.RPAREN)
- return
-}
-
-func (d *Document) ArgumentNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.Arguments[ref].Name)
-}
-
-func (d *Document) ArgumentNameString(ref int) string {
- return unsafebytes.BytesToString(d.ArgumentNameBytes(ref))
-}
-
-func (d *Document) ArgumentValue(ref int) Value {
- return d.Arguments[ref].Value
-}
-
-func (d *Document) ArgumentsAreEqual(left, right int) bool {
- return bytes.Equal(d.ArgumentNameBytes(left), d.ArgumentNameBytes(right)) &&
- d.ValuesAreEqual(d.ArgumentValue(left), d.ArgumentValue(right))
-}
-
-func (d *Document) ArgumentSetsAreEquals(left, right []int) bool {
- if len(left) != len(right) {
- return false
- }
- for i := 0; i < len(left); i++ {
- leftArgument, rightArgument := left[i], right[i]
- if !d.ArgumentsAreEqual(leftArgument, rightArgument) {
- return false
- }
- }
- return true
-}
-
-func (d *Document) ArgumentsBefore(ancestor Node, argument int) []int {
- switch ancestor.Kind {
- case NodeKindField:
- for i, j := range d.Fields[ancestor.Ref].Arguments.Refs {
- if argument == j {
- return d.Fields[ancestor.Ref].Arguments.Refs[:i]
- }
- }
- case NodeKindDirective:
- for i, j := range d.Directives[ancestor.Ref].Arguments.Refs {
- if argument == j {
- return d.Directives[ancestor.Ref].Arguments.Refs[:i]
- }
- }
- }
- return nil
-}
-
-func (d *Document) ArgumentsAfter(ancestor Node, argument int) []int {
- switch ancestor.Kind {
- case NodeKindField:
- for i, j := range d.Fields[ancestor.Ref].Arguments.Refs {
- if argument == j {
- return d.Fields[ancestor.Ref].Arguments.Refs[i+1:]
- }
- }
- case NodeKindDirective:
- for i, j := range d.Directives[ancestor.Ref].Arguments.Refs {
- if argument == j {
- return d.Directives[ancestor.Ref].Arguments.Refs[i+1:]
- }
- }
- }
- return nil
-}
-
-func (d *Document) AddArgument(argument Argument) (ref int) {
- d.Arguments = append(d.Arguments, argument)
- return len(d.Arguments) - 1
-}
-
-func (d *Document) ImportArgument(name string, value Value) (ref int) {
- arg := Argument{
- Name: d.Input.AppendInputString(name),
- Value: value,
- }
-
- return d.AddArgument(arg)
-}
-
-func (d *Document) ImportVariableValueArgument(argName, variableName ByteSlice) (variableValueRef, argRef int) {
- variableValueRef = d.ImportVariableValue(variableName)
-
- arg := Argument{
- Name: d.Input.AppendInputBytes(argName),
- Value: Value{
- Kind: ValueKindVariable,
- Ref: variableValueRef,
- },
- }
-
- argRef = d.AddArgument(arg)
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_description.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_description.go
deleted file mode 100644
index 18611d8beb7..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_description.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package ast
-
-import (
- "io"
- "strings"
-
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/runes"
-)
-
-type Description struct {
- IsDefined bool
- IsBlockString bool // true if -> """content""" ; else "content"
- Content ByteSliceReference // literal
- Position position.Position
-}
-
-// nolint
-func (d *Document) PrintDescription(description Description, indent []byte, depth int, writer io.Writer) (err error) {
- for i := 0; i < depth; i++ {
- _, err = writer.Write(indent)
- }
- if description.IsBlockString {
- _, err = writer.Write(literal.QUOTE)
- _, err = writer.Write(literal.QUOTE)
- _, err = writer.Write(literal.QUOTE)
- _, err = writer.Write(literal.LINETERMINATOR)
- for i := 0; i < depth; i++ {
- _, err = writer.Write(indent)
- }
- } else {
- _, err = writer.Write(literal.QUOTE)
- }
-
- content := d.Input.ByteSlice(description.Content)
- skipWhitespace := false
- for i := range content {
- switch content[i] {
- case runes.LINETERMINATOR:
- skipWhitespace = true
- case runes.TAB, runes.SPACE:
- if skipWhitespace {
- continue
- }
- default:
- if skipWhitespace {
- for i := 0; i < depth; i++ {
- _, err = writer.Write(indent)
- }
- }
- skipWhitespace = false
- }
- _, err = writer.Write(content[i : i+1])
- }
- if description.IsBlockString {
- _, err = writer.Write(literal.LINETERMINATOR)
- for i := 0; i < depth; i++ {
- _, err = writer.Write(indent)
- }
- _, err = writer.Write(literal.QUOTE)
- _, err = writer.Write(literal.QUOTE)
- _, err = writer.Write(literal.QUOTE)
- } else {
- _, err = writer.Write(literal.QUOTE)
- }
- return nil
-}
-
-func (d *Document) ImportDescription(desc string) (description Description) {
- if desc == "" {
- return
- }
-
- return Description{
- IsDefined: true,
- IsBlockString: strings.Contains(desc, "\n"),
- Content: d.Input.AppendInputString(desc),
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_directive.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_directive.go
deleted file mode 100644
index 1c72149732b..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_directive.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package ast
-
-import (
- "bytes"
- "io"
-
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type DirectiveList struct {
- Refs []int
-}
-
-type Directive struct {
- At position.Position // @
- Name ByteSliceReference // e.g. include
- HasArguments bool
- Arguments ArgumentList // e.g. (if: true)
-}
-
-func (d *Document) PrintDirective(ref int, w io.Writer) error {
- _, err := w.Write(literal.AT)
- if err != nil {
- return err
- }
- _, err = w.Write(d.Input.ByteSlice(d.Directives[ref].Name))
- if err != nil {
- return err
- }
- if d.Directives[ref].HasArguments {
- err = d.PrintArguments(d.Directives[ref].Arguments.Refs, w)
- }
- return err
-}
-
-func (d *Document) DirectiveName(ref int) ByteSliceReference {
- return d.Directives[ref].Name
-}
-
-func (d *Document) DirectiveNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.Directives[ref].Name)
-}
-
-func (d *Document) DirectiveNameString(ref int) string {
- return d.Input.ByteSliceString(d.Directives[ref].Name)
-}
-
-func (d *Document) DirectiveIsFirst(directive int, ancestor Node) bool {
- directives := d.NodeDirectives(ancestor)
- return len(directives) != 0 && directives[0] == directive
-}
-
-func (d *Document) DirectiveIsLast(directive int, ancestor Node) bool {
- directives := d.NodeDirectives(ancestor)
- return len(directives) != 0 && directives[len(directives)-1] == directive
-}
-
-func (d *Document) DirectiveArgumentSet(ref int) []int {
- return d.Directives[ref].Arguments.Refs
-}
-
-func (d *Document) DirectiveArgumentValueByName(ref int, name ByteSlice) (Value, bool) {
- for i := 0; i < len(d.Directives[ref].Arguments.Refs); i++ {
- arg := d.Directives[ref].Arguments.Refs[i]
- if bytes.Equal(d.ArgumentNameBytes(arg), name) {
- return d.ArgumentValue(arg), true
- }
- }
- return Value{}, false
-}
-
-func (d *Document) DirectivesAreEqual(left, right int) bool {
- return d.Input.ByteSliceReferenceContentEquals(d.DirectiveName(left), d.DirectiveName(right)) &&
- d.ArgumentSetsAreEquals(d.DirectiveArgumentSet(left), d.DirectiveArgumentSet(right))
-}
-
-func (d *Document) DirectiveSetsAreEqual(left, right []int) bool {
- if len(left) != len(right) {
- return false
- }
- for i := 0; i < len(left); i++ {
- leftDirective, rightDirective := left[i], right[i]
- if !d.DirectivesAreEqual(leftDirective, rightDirective) {
- return false
- }
- }
- return true
-}
-
-func (d *Document) AddDirective(directive Directive) (ref int) {
- d.Directives = append(d.Directives, directive)
- return len(d.Directives) - 1
-}
-
-func (d *Document) ImportDirective(name string, argRefs []int) (ref int) {
- directive := Directive{
- Name: d.Input.AppendInputString(name),
- HasArguments: len(argRefs) > 0,
- Arguments: ArgumentList{
- Refs: argRefs,
- },
- }
-
- return d.AddDirective(directive)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_directive_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_directive_definition.go
deleted file mode 100644
index 388c6c1a8ae..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_directive_definition.go
+++ /dev/null
@@ -1,129 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// DirectiveDefinition
-// example:
-// directive @example on FIELD
-type DirectiveDefinition struct {
- Description Description // optional, describes the directive
- DirectiveLiteral position.Position // directive
- At position.Position // @
- Name ByteSliceReference // e.g. example
- HasArgumentsDefinitions bool
- ArgumentsDefinition InputValueDefinitionList // optional, e.g. (if: Boolean)
- On position.Position // on
- DirectiveLocations DirectiveLocations // e.g. FIELD
-}
-
-func (d *Document) DirectiveDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.DirectiveDefinitions[ref].Name)
-}
-
-func (d *Document) DirectiveDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.DirectiveDefinitions[ref].Name))
-}
-
-func (d *Document) DirectiveDefinitionDescriptionBytes(ref int) ByteSlice {
- if !d.DirectiveDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.DirectiveDefinitions[ref].Description.Content)
-}
-
-func (d *Document) DirectiveDefinitionDescriptionString(ref int) string {
- return unsafebytes.BytesToString(d.DirectiveDefinitionDescriptionBytes(ref))
-}
-
-func (d *Document) DirectiveArgumentInputValueDefinition(directiveName ByteSlice, argumentName ByteSlice) int {
- for i := range d.DirectiveDefinitions {
- if bytes.Equal(directiveName, d.Input.ByteSlice(d.DirectiveDefinitions[i].Name)) {
- for _, j := range d.DirectiveDefinitions[i].ArgumentsDefinition.Refs {
- if bytes.Equal(argumentName, d.Input.ByteSlice(d.InputValueDefinitions[j].Name)) {
- return j
- }
- }
- }
- }
- return -1
-}
-
-func (d *Document) DirectiveDefinitionArgumentDefaultValueString(directiveName, argumentName string) string {
- inputValueDefinition := d.DirectiveArgumentInputValueDefinition(unsafebytes.StringToBytes(directiveName), unsafebytes.StringToBytes(argumentName))
- if inputValueDefinition == -1 {
- return ""
- }
- defaultValue := d.InputValueDefinitionDefaultValue(inputValueDefinition)
- if defaultValue.Kind != ValueKindString {
- return ""
- }
- return d.StringValueContentString(defaultValue.Ref)
-}
-
-func (d *Document) DirectiveDefinitionArgumentDefaultValueBool(directiveName, argumentName string) bool {
- inputValueDefinition := d.DirectiveArgumentInputValueDefinition(unsafebytes.StringToBytes(directiveName), unsafebytes.StringToBytes(argumentName))
- if inputValueDefinition == -1 {
- return false
- }
- defaultValue := d.InputValueDefinitionDefaultValue(inputValueDefinition)
- if defaultValue.Kind != ValueKindBoolean {
- return false
- }
- return bool(d.BooleanValue(defaultValue.Ref))
-}
-
-func (d *Document) DirectiveDefinitionArgumentDefaultValueInt64(directiveName, argumentName string) int64 {
- inputValueDefinition := d.DirectiveArgumentInputValueDefinition(unsafebytes.StringToBytes(directiveName), unsafebytes.StringToBytes(argumentName))
- if inputValueDefinition == -1 {
- return -1
- }
- defaultValue := d.InputValueDefinitionDefaultValue(inputValueDefinition)
- if defaultValue.Kind != ValueKindInteger {
- return -1
- }
- return d.IntValueAsInt(defaultValue.Ref)
-}
-
-func (d *Document) DirectiveDefinitionArgumentDefaultValueFloat32(directiveName, argumentName string) float32 {
- inputValueDefinition := d.DirectiveArgumentInputValueDefinition(unsafebytes.StringToBytes(directiveName), unsafebytes.StringToBytes(argumentName))
- if inputValueDefinition == -1 {
- return -1
- }
- defaultValue := d.InputValueDefinitionDefaultValue(inputValueDefinition)
- if defaultValue.Kind != ValueKindFloat {
- return -1
- }
- return d.FloatValueAsFloat32(defaultValue.Ref)
-}
-
-func (d *Document) AddDirectiveDefinition(directiveDefinition DirectiveDefinition) (ref int) {
- d.DirectiveDefinitions = append(d.DirectiveDefinitions, directiveDefinition)
- return len(d.DirectiveDefinitions) - 1
-}
-
-func (d *Document) ImportDirectiveDefinition(name, description string, argsRefs []int, locations []string) (ref int) {
- directiveLocations := DirectiveLocations{}
- for _, location := range locations {
- _ = directiveLocations.SetFromRaw([]byte(location))
- }
-
- definition := DirectiveDefinition{
- Description: d.ImportDescription(description),
- Name: d.Input.AppendInputString(name),
- HasArgumentsDefinitions: len(argsRefs) > 0,
- ArgumentsDefinition: InputValueDefinitionList{
- Refs: argsRefs,
- },
- DirectiveLocations: directiveLocations,
- }
-
- ref = d.AddDirectiveDefinition(definition)
- d.ImportRootNode(ref, NodeKindDirectiveDefinition)
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_enum_type_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_enum_type_definition.go
deleted file mode 100644
index 7a2ab5cd830..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_enum_type_definition.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// EnumTypeDefinition
-// example:
-// enum Direction {
-// NORTH
-// EAST
-// SOUTH
-// WEST
-//}
-type EnumTypeDefinition struct {
- Description Description // optional, describes enum
- EnumLiteral position.Position // enum
- Name ByteSliceReference // e.g. Direction
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
- HasEnumValuesDefinition bool
- EnumValuesDefinition EnumValueDefinitionList // optional, e.g. { NORTH EAST }
-}
-
-func (d *Document) EnumTypeDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.EnumTypeDefinitions[ref].Name)
-}
-
-func (d *Document) EnumTypeDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.EnumTypeDefinitions[ref].Name))
-}
-
-func (d *Document) EnumTypeDefinitionDescriptionBytes(ref int) ByteSlice {
- if !d.EnumTypeDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.EnumTypeDefinitions[ref].Description.Content)
-}
-
-func (d *Document) EnumTypeDefinitionDescriptionString(ref int) string {
- return unsafebytes.BytesToString(d.EnumTypeDefinitionDescriptionBytes(ref))
-}
-
-func (d *Document) EnumTypeDefinitionHasDirectives(ref int) bool {
- return d.EnumTypeDefinitions[ref].HasDirectives
-}
-
-func (d *Document) EnumTypeDefinitionHasEnumValueDefinition(ref int) bool {
- return d.EnumTypeDefinitions[ref].HasEnumValuesDefinition
-}
-
-func (d *Document) EnumTypeDefinitionContainsEnumValue(enumTypeDef int, valueName ByteSlice) bool {
- for _, i := range d.EnumTypeDefinitions[enumTypeDef].EnumValuesDefinition.Refs {
- if bytes.Equal(valueName, d.EnumValueDefinitionNameBytes(i)) {
- return true
- }
- }
- return false
-}
-
-func (d *Document) AddEnumTypeDefinition(definition EnumTypeDefinition) (ref int) {
- d.EnumTypeDefinitions = append(d.EnumTypeDefinitions, definition)
- return len(d.EnumTypeDefinitions) - 1
-}
-
-func (d *Document) ImportEnumTypeDefinition(name, description string, valueRefs []int) (ref int) {
- definition := EnumTypeDefinition{
- Description: d.ImportDescription(description),
- Name: d.Input.AppendInputString(name),
- HasEnumValuesDefinition: len(valueRefs) > 0,
- EnumValuesDefinition: EnumValueDefinitionList{
- Refs: valueRefs,
- },
- }
-
- ref = d.AddEnumTypeDefinition(definition)
- d.ImportRootNode(ref, NodeKindEnumTypeDefinition)
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_enum_type_extension.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_enum_type_extension.go
deleted file mode 100644
index 3dc73abb5f7..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_enum_type_extension.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type EnumTypeExtension struct {
- ExtendLiteral position.Position
- EnumTypeDefinition
-}
-
-func (d *Document) EnumTypeExtensionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.EnumTypeExtensions[ref].Name)
-}
-
-func (d *Document) EnumTypeExtensionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.EnumTypeExtensions[ref].Name))
-}
-
-func (d *Document) EnumTypeExtensionHasDirectives(ref int) bool {
- return d.EnumTypeExtensions[ref].HasDirectives
-}
-
-func (d *Document) ExtendEnumTypeDefinitionByEnumTypeExtension(enumTypeDefinitionRef, enumTypeExtensionRef int) {
- if d.EnumTypeExtensionHasDirectives(enumTypeExtensionRef) {
- d.EnumTypeDefinitions[enumTypeDefinitionRef].Directives.Refs = append(d.EnumTypeDefinitions[enumTypeDefinitionRef].Directives.Refs, d.EnumTypeExtensions[enumTypeExtensionRef].Directives.Refs...)
- d.EnumTypeDefinitions[enumTypeDefinitionRef].HasDirectives = true
- }
-
- if d.EnumTypeDefinitionHasEnumValueDefinition(enumTypeExtensionRef) {
- d.EnumTypeDefinitions[enumTypeDefinitionRef].EnumValuesDefinition.Refs = append(d.EnumTypeDefinitions[enumTypeDefinitionRef].EnumValuesDefinition.Refs, d.EnumTypeExtensions[enumTypeExtensionRef].EnumValuesDefinition.Refs...)
- d.EnumTypeDefinitions[enumTypeDefinitionRef].HasEnumValuesDefinition = true
- }
-
- d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: enumTypeExtensionRef, Kind: NodeKindEnumTypeExtension})
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_enum_value_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_enum_value_definition.go
deleted file mode 100644
index 53ad2ea3d61..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_enum_value_definition.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type EnumValueDefinitionList struct {
- LBRACE position.Position // {
- Refs []int // EnumValueDefinition
- RBRACE position.Position // }
-}
-
-// EnumValueDefinition
-// example:
-// "NORTH enum value" NORTH @foo
-type EnumValueDefinition struct {
- Description Description // optional, describes enum value
- EnumValue ByteSliceReference // e.g. NORTH (Name but not true, false or null
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
-}
-
-func (d *Document) EnumValueDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.EnumValueDefinitions[ref].EnumValue)
-}
-
-func (d *Document) EnumValueDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.EnumValueDefinitions[ref].EnumValue))
-}
-
-func (d *Document) EnumValueDefinitionDescriptionBytes(ref int) ByteSlice {
- if !d.EnumValueDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.EnumValueDefinitions[ref].Description.Content)
-}
-
-func (d *Document) EnumValueDefinitionDescriptionString(ref int) string {
- return unsafebytes.BytesToString(d.EnumValueDefinitionDescriptionBytes(ref))
-}
-
-func (d *Document) EnumValueDefinitionHasDirectives(ref int) bool {
- return d.EnumValueDefinitions[ref].HasDirectives
-}
-
-func (d *Document) EnumValueDefinitionDirectives(ref int) (refs []int) {
- return d.EnumValueDefinitions[ref].Directives.Refs
-}
-
-func (d *Document) EnumValueDefinitionDirectiveByName(definitionRef int, directiveName ByteSlice) (ref int, exists bool) {
- for _, i := range d.EnumValueDefinitions[definitionRef].Directives.Refs {
- if bytes.Equal(directiveName, d.DirectiveNameBytes(i)) {
- return i, true
- }
- }
- return
-}
-
-func (d *Document) EnumValueDefinitionIsFirst(ref int, ancestor Node) bool {
- switch ancestor.Kind {
- case NodeKindEnumTypeDefinition:
- return d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs != nil &&
- d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs[0] == ref
- case NodeKindEnumTypeExtension:
- return d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs != nil &&
- d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs[0] == ref
- default:
- return false
- }
-}
-
-func (d *Document) EnumValueDefinitionIsLast(ref int, ancestor Node) bool {
- switch ancestor.Kind {
- case NodeKindEnumTypeDefinition:
- return d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs != nil &&
- d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs[len(d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs)-1] == ref
- case NodeKindEnumTypeExtension:
- return d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs != nil &&
- d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs[len(d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs)-1] == ref
- default:
- return false
- }
-}
-
-func (d *Document) AddEnumValueDefinition(inputValueDefinition EnumValueDefinition) (ref int) {
- d.EnumValueDefinitions = append(d.EnumValueDefinitions, inputValueDefinition)
- return len(d.EnumValueDefinitions) - 1
-}
-
-func (d *Document) ImportEnumValueDefinition(value, description string, directiveRefs []int) (ref int) {
- inputValueDef := EnumValueDefinition{
- Description: d.ImportDescription(description),
- EnumValue: d.Input.AppendInputString(value),
- HasDirectives: len(directiveRefs) > 0,
- Directives: DirectiveList{
- Refs: directiveRefs,
- },
- }
-
- return d.AddEnumValueDefinition(inputValueDef)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_field.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_field.go
deleted file mode 100644
index 7ecfa43bd44..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_field.go
+++ /dev/null
@@ -1,98 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
-)
-
-type Field struct {
- Alias Alias // optional, e.g. renamed:
- Name ByteSliceReference // field name, e.g. id
- HasArguments bool
- Arguments ArgumentList // optional
- HasDirectives bool
- Directives DirectiveList // optional
- SelectionSet int // optional
- HasSelections bool
-}
-
-func (d *Document) FieldNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.Fields[ref].Name)
-}
-
-func (d *Document) FieldNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.Fields[ref].Name))
-}
-
-func (d *Document) AddField(field Field) Node {
- d.Fields = append(d.Fields, field)
- return Node{
- Kind: NodeKindField,
- Ref: len(d.Fields) - 1,
- }
-}
-
-func (d *Document) AddArgumentToField(fieldRef, argRef int) {
- if !d.Fields[fieldRef].HasArguments {
- d.Fields[fieldRef].HasArguments = true
- d.Fields[fieldRef].Arguments.Refs = d.Refs[d.NextRefIndex()][:0]
- }
- d.Fields[fieldRef].Arguments.Refs = append(d.Fields[fieldRef].Arguments.Refs, argRef)
-}
-
-func (d *Document) FieldArguments(ref int) []int {
- return d.Fields[ref].Arguments.Refs
-}
-
-func (d *Document) FieldArgument(field int, name ByteSlice) (ref int, exists bool) {
- for _, i := range d.Fields[field].Arguments.Refs {
- if bytes.Equal(d.ArgumentNameBytes(i), name) {
- return i, true
- }
- }
- return -1, false
-}
-
-func (d *Document) FieldDirectives(ref int) []int {
- return d.Fields[ref].Directives.Refs
-}
-
-func (d *Document) FieldsHaveSameShape(left, right int) bool {
-
- leftAliasDefined := d.FieldAliasIsDefined(left)
- rightAliasDefined := d.FieldAliasIsDefined(right)
-
- switch {
- case !leftAliasDefined && !rightAliasDefined:
- return d.Input.ByteSliceReferenceContentEquals(d.Fields[left].Name, d.Fields[right].Name)
- case leftAliasDefined && rightAliasDefined:
- return d.Input.ByteSliceReferenceContentEquals(d.Fields[left].Alias.Name, d.Fields[right].Alias.Name)
- case leftAliasDefined && !rightAliasDefined:
- return d.Input.ByteSliceReferenceContentEquals(d.Fields[left].Alias.Name, d.Fields[right].Name)
- case !leftAliasDefined && rightAliasDefined:
- return d.Input.ByteSliceReferenceContentEquals(d.Fields[left].Name, d.Fields[right].Alias.Name)
- default:
- return false
- }
-}
-
-func (d *Document) FieldHasArguments(ref int) bool {
- return d.Fields[ref].HasArguments
-}
-
-func (d *Document) FieldHasSelections(ref int) bool {
- return d.Fields[ref].HasSelections
-}
-
-func (d *Document) FieldHasDirectives(ref int) bool {
- return d.Fields[ref].HasDirectives
-}
-
-func (d *Document) FieldsAreEqualFlat(left, right int) bool {
- return bytes.Equal(d.FieldNameBytes(left), d.FieldNameBytes(right)) && // name
- bytes.Equal(d.FieldAliasBytes(left), d.FieldAliasBytes(right)) && // alias
- !d.FieldHasSelections(left) && !d.FieldHasSelections(right) && // selections
- d.ArgumentSetsAreEquals(d.FieldArguments(left), d.FieldArguments(right)) && // arguments
- d.DirectiveSetsAreEqual(d.FieldDirectives(left), d.FieldDirectives(right)) // directives
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_field_alias.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_field_alias.go
deleted file mode 100644
index 3cbb5db61c8..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_field_alias.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type Alias struct {
- IsDefined bool
- Name ByteSliceReference // optional, e.g. renamedField
- Colon position.Position // :
-}
-
-func (d *Document) FieldAliasOrNameBytes(ref int) ByteSlice {
- if d.FieldAliasIsDefined(ref) {
- return d.FieldAliasBytes(ref)
- }
- return d.FieldNameBytes(ref)
-}
-
-func (d *Document) FieldAliasOrNameString(ref int) string {
- return unsafebytes.BytesToString(d.FieldAliasOrNameBytes(ref))
-}
-
-func (d *Document) FieldAliasBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.Fields[ref].Alias.Name)
-}
-
-func (d *Document) FieldAliasString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.Fields[ref].Alias.Name))
-}
-
-func (d *Document) FieldAliasIsDefined(ref int) bool {
- return d.Fields[ref].Alias.IsDefined
-}
-
-func (d *Document) RemoveFieldAlias(ref int) {
- d.Fields[ref].Alias.IsDefined = false
- d.Fields[ref].Alias.Name.Start = 0
- d.Fields[ref].Alias.Name.End = 0
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_field_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_field_definition.go
deleted file mode 100644
index b9c96e832eb..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_field_definition.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type FieldDefinitionList struct {
- LBRACE position.Position // {
- Refs []int // FieldDefinition
- RBRACE position.Position // }
-}
-
-type FieldDefinition struct {
- Description Description // optional e.g. "FieldDefinition is ..."
- Name ByteSliceReference // e.g. foo
- HasArgumentsDefinitions bool
- ArgumentsDefinition InputValueDefinitionList // optional
- Colon position.Position // :
- Type int // e.g. String
- HasDirectives bool
- Directives DirectiveList // e.g. @foo
-}
-
-func (d *Document) FieldDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.FieldDefinitions[ref].Name)
-}
-
-func (d *Document) FieldDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.FieldDefinitionNameBytes(ref))
-}
-
-func (d *Document) FieldDefinitionDescriptionBytes(ref int) ByteSlice {
- if !d.FieldDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.FieldDefinitions[ref].Description.Content)
-}
-
-func (d *Document) FieldDefinitionDescriptionString(ref int) string {
- return unsafebytes.BytesToString(d.FieldDefinitionDescriptionBytes(ref))
-}
-
-func (d *Document) FieldDefinitionIsFirst(field int, ancestor Node) bool {
- definitions := d.NodeFieldDefinitions(ancestor)
- return len(definitions) != 0 && definitions[0] == field
-}
-
-func (d *Document) FieldDefinitionIsLast(field int, ancestor Node) bool {
- definitions := d.NodeFieldDefinitions(ancestor)
- return len(definitions) != 0 && definitions[len(definitions)-1] == field
-}
-
-func (d *Document) FieldDefinitionHasDirectives(ref int) bool {
- return d.FieldDefinitions[ref].HasDirectives
-}
-
-func (d *Document) FieldDefinitionDirectives(fieldDefinition int) (refs []int) {
- return d.FieldDefinitions[fieldDefinition].Directives.Refs
-}
-
-func (d *Document) FieldDefinitionDirectiveByName(fieldDefinition int, directiveName ByteSlice) (ref int, exists bool) {
- for _, i := range d.FieldDefinitions[fieldDefinition].Directives.Refs {
- if bytes.Equal(directiveName, d.DirectiveNameBytes(i)) {
- return i, true
- }
- }
- return
-}
-
-func (d *Document) FieldDefinitionResolverTypeName(enclosingType Node) ByteSlice {
- switch enclosingType.Kind {
- case NodeKindObjectTypeDefinition:
- name := d.ObjectTypeDefinitionNameBytes(enclosingType.Ref)
- switch {
- case bytes.Equal(name, d.Index.QueryTypeName):
- return literal.QUERY
- case bytes.Equal(name, d.Index.MutationTypeName):
- return literal.MUTATION
- case bytes.Equal(name, d.Index.SubscriptionTypeName):
- return literal.SUBSCRIPTION
- }
- }
- return d.NodeNameBytes(enclosingType)
-}
-
-func (d *Document) AddFieldDefinition(fieldDefinition FieldDefinition) (ref int) {
- d.FieldDefinitions = append(d.FieldDefinitions, fieldDefinition)
- return len(d.FieldDefinitions) - 1
-}
-
-func (d *Document) ImportFieldDefinition(name, description string, typeRef int, argsRefs []int, directiveRefs []int) (ref int) {
- fieldDef := FieldDefinition{
- Name: d.Input.AppendInputString(name),
- Type: typeRef,
- Description: d.ImportDescription(description),
- ArgumentsDefinition: InputValueDefinitionList{
- Refs: argsRefs,
- },
- HasArgumentsDefinitions: len(argsRefs) > 0,
- Directives: DirectiveList{
- Refs: directiveRefs,
- },
- HasDirectives: len(directiveRefs) > 0,
- }
-
- return d.AddFieldDefinition(fieldDef)
-}
-
-func (d *Document) FieldDefinitionsContainField(definitions []int, field ByteSlice) bool {
- for _, i := range definitions {
- if bytes.Equal(field, d.FieldDefinitionNameBytes(i)) {
- return true
- }
- }
- return false
-}
-
-func (d *Document) FieldDefinitionHasArgumentsDefinitions(ref int) bool {
- return d.FieldDefinitions[ref].HasArgumentsDefinitions
-}
-
-func (d *Document) FieldDefinitionArgumentsDefinitions(ref int) []int {
- return d.FieldDefinitions[ref].ArgumentsDefinition.Refs
-}
-
-func (d *Document) FieldDefinitionType(ref int) int {
- return d.FieldDefinitions[ref].Type
-}
-
-func (d *Document) FieldDefinitionTypeNode(ref int) Node {
- typeName := d.ResolveTypeNameBytes(d.FieldDefinitions[ref].Type)
- node, _ := d.Index.FirstNodeByNameBytes(typeName)
- return node
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_fragment_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_fragment_definition.go
deleted file mode 100644
index bfc755ce66f..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_fragment_definition.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// TypeCondition
-// example:
-// on User
-type TypeCondition struct {
- On position.Position // on
- Type int // NamedType
-}
-
-// FragmentDefinition
-// example:
-// fragment friendFields on User {
-// id
-// name
-// profilePic(size: 50)
-//}
-type FragmentDefinition struct {
- FragmentLiteral position.Position // fragment
- Name ByteSliceReference // Name but not on, e.g. friendFields
- TypeCondition TypeCondition // e.g. on User
- Directives DirectiveList // optional, e.g. @foo
- SelectionSet int // e.g. { id }
- HasSelections bool
-}
-
-func (d *Document) FragmentDefinitionRef(byName ByteSlice) (ref int, exists bool) {
- for i := range d.FragmentDefinitions {
- if bytes.Equal(byName, d.Input.ByteSlice(d.FragmentDefinitions[i].Name)) {
- return i, true
- }
- }
- return -1, false
-}
-
-func (d *Document) FragmentDefinitionTypeName(ref int) ByteSlice {
- return d.ResolveTypeNameBytes(d.FragmentDefinitions[ref].TypeCondition.Type)
-}
-
-func (d *Document) FragmentDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.FragmentDefinitions[ref].Name)
-}
-
-func (d *Document) FragmentDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.FragmentDefinitions[ref].Name))
-}
-
-func (d *Document) FragmentDefinitionIsLastRootNode(ref int) bool {
- for i := range d.RootNodes {
- if d.RootNodes[i].Kind == NodeKindFragmentDefinition && d.RootNodes[i].Ref == ref {
- return len(d.RootNodes)-1 == i
- }
- }
- return false
-}
-
-func (d *Document) FragmentDefinitionIsUsed(name ByteSlice) bool {
- for _, i := range d.Index.ReplacedFragmentSpreads {
- if bytes.Equal(name, d.FragmentSpreadNameBytes(i)) {
- return true
- }
- }
- return false
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_fragment_spread.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_fragment_spread.go
deleted file mode 100644
index f09c091a047..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_fragment_spread.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// FragmentSpread
-// example:
-// ...MyFragment
-type FragmentSpread struct {
- Spread position.Position // ...
- FragmentName ByteSliceReference // Name but not on, e.g. MyFragment
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
-}
-
-func (d *Document) FragmentSpreadNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.FragmentSpreads[ref].FragmentName)
-}
-
-func (d *Document) FragmentSpreadNameString(ref int) string {
- return unsafebytes.BytesToString(d.FragmentSpreadNameBytes(ref))
-}
-
-// ReplaceFragmentSpread replaces a fragment spread with a given selection set
-// attention! this might lead to duplicate field problems because the same field with its unique field reference might be copied into the same selection set
-// possible problems: changing directives or sub selections will affect both fields with the same id
-// simple solution: run normalization deduplicate fields
-// as part of the normalization flow this problem will be handled automatically
-// just be careful in case you use this function outside of the normalization package
-func (d *Document) ReplaceFragmentSpread(selectionSet int, spreadRef int, replaceWithSelectionSet int) {
- for i, j := range d.SelectionSets[selectionSet].SelectionRefs {
- if d.Selections[j].Kind == SelectionKindFragmentSpread && d.Selections[j].Ref == spreadRef {
- d.SelectionSets[selectionSet].SelectionRefs = append(d.SelectionSets[selectionSet].SelectionRefs[:i], append(d.SelectionSets[replaceWithSelectionSet].SelectionRefs, d.SelectionSets[selectionSet].SelectionRefs[i+1:]...)...)
- d.Index.ReplacedFragmentSpreads = append(d.Index.ReplacedFragmentSpreads, spreadRef)
- return
- }
- }
-}
-
-// ReplaceFragmentSpreadWithInlineFragment replaces a given fragment spread with a inline fragment
-// attention! the same rules apply as for 'ReplaceFragmentSpread', look above!
-func (d *Document) ReplaceFragmentSpreadWithInlineFragment(selectionSet int, spreadRef int, replaceWithSelectionSet int, typeCondition TypeCondition) {
- d.InlineFragments = append(d.InlineFragments, InlineFragment{
- TypeCondition: typeCondition,
- SelectionSet: replaceWithSelectionSet,
- HasSelections: len(d.SelectionSets[replaceWithSelectionSet].SelectionRefs) != 0,
- })
- ref := len(d.InlineFragments) - 1
- d.Selections = append(d.Selections, Selection{
- Kind: SelectionKindInlineFragment,
- Ref: ref,
- })
- selectionRef := len(d.Selections) - 1
- for i, j := range d.SelectionSets[selectionSet].SelectionRefs {
- if d.Selections[j].Kind == SelectionKindFragmentSpread && d.Selections[j].Ref == spreadRef {
- d.SelectionSets[selectionSet].SelectionRefs = append(d.SelectionSets[selectionSet].SelectionRefs[:i], append([]int{selectionRef}, d.SelectionSets[selectionSet].SelectionRefs[i+1:]...)...)
- d.Index.ReplacedFragmentSpreads = append(d.Index.ReplacedFragmentSpreads, spreadRef)
- return
- }
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_inline_fragment.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_inline_fragment.go
deleted file mode 100644
index ddbcaa5f01a..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_inline_fragment.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// InlineFragment
-// example:
-// ... on User {
-// friends {
-// count
-// }
-// }
-type InlineFragment struct {
- Spread position.Position // ...
- TypeCondition TypeCondition // on NamedType, e.g. on User
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
- SelectionSet int // optional, e.g. { nextField }
- HasSelections bool
-}
-
-func (d *Document) InlineFragmentTypeConditionName(ref int) ByteSlice {
- if d.InlineFragments[ref].TypeCondition.Type == -1 {
- return nil
- }
- return d.Input.ByteSlice(d.Types[d.InlineFragments[ref].TypeCondition.Type].Name)
-}
-
-func (d *Document) InlineFragmentTypeConditionNameString(ref int) string {
- return unsafebytes.BytesToString(d.InlineFragmentTypeConditionName(ref))
-}
-
-func (d *Document) InlineFragmentHasTypeCondition(ref int) bool {
- return d.InlineFragments[ref].TypeCondition.Type != -1
-}
-
-func (d *Document) InlineFragmentHasDirectives(ref int) bool {
- return len(d.InlineFragments[ref].Directives.Refs) != 0
-}
-
-func (d *Document) InlineFragmentSelections(ref int) []int {
- if !d.InlineFragments[ref].HasSelections {
- return nil
- }
- return d.SelectionSets[d.InlineFragments[ref].SelectionSet].SelectionRefs
-}
-
-func (d *Document) AddInlineFragment(fragment InlineFragment) int {
- d.InlineFragments = append(d.InlineFragments, fragment)
- return len(d.InlineFragments) - 1
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_input_object_type_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_input_object_type_definition.go
deleted file mode 100644
index 70acc1d93f5..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_input_object_type_definition.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type InputObjectTypeDefinition struct {
- Description Description // optional, describes the input type
- InputLiteral position.Position // input
- Name ByteSliceReference // name of the input type
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
- HasInputFieldsDefinition bool
- InputFieldsDefinition InputValueDefinitionList // e.g. x:Float
-}
-
-func (d *Document) InputObjectTypeDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.InputObjectTypeDefinitions[ref].Name)
-}
-
-func (d *Document) InputObjectTypeDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.InputObjectTypeDefinitions[ref].Name))
-}
-
-func (d *Document) InputObjectTypeDefinitionDescriptionBytes(ref int) ByteSlice {
- if !d.InputObjectTypeDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.InputObjectTypeDefinitions[ref].Description.Content)
-}
-
-func (d *Document) InputObjectTypeDefinitionDescriptionString(ref int) string {
- return unsafebytes.BytesToString(d.InputObjectTypeDefinitionDescriptionBytes(ref))
-}
-
-func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValueString(inputObjectTypeDefinitionName, inputValueDefinitionName string) string {
- defaultValue := d.InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName)
- if defaultValue.Kind != ValueKindString {
- return ""
- }
- return d.StringValueContentString(defaultValue.Ref)
-}
-
-func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValueBool(inputObjectTypeDefinitionName, inputValueDefinitionName string) bool {
- defaultValue := d.InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName)
- if defaultValue.Kind != ValueKindBoolean {
- return false
- }
- return bool(d.BooleanValue(defaultValue.Ref))
-}
-
-func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValueInt64(inputObjectTypeDefinitionName, inputValueDefinitionName string) int64 {
- defaultValue := d.InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName)
- if defaultValue.Kind != ValueKindInteger {
- return -1
- }
- return d.IntValueAsInt(defaultValue.Ref)
-}
-
-func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValueFloat32(inputObjectTypeDefinitionName, inputValueDefinitionName string) float32 {
- defaultValue := d.InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName)
- if defaultValue.Kind != ValueKindFloat {
- return -1
- }
- return d.FloatValueAsFloat32(defaultValue.Ref)
-}
-
-func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName string) Value {
- inputObjectTypeDefinition, exists := d.Index.FirstNodeByNameStr(inputObjectTypeDefinitionName)
- if !exists {
- return Value{}
- }
- if inputObjectTypeDefinition.Kind != NodeKindInputObjectTypeDefinition {
- return Value{}
- }
- inputValueDefinition := d.InputObjectTypeDefinitionInputValueDefinitionByName(inputObjectTypeDefinition.Ref, unsafebytes.StringToBytes(inputValueDefinitionName))
- if inputValueDefinition == -1 {
- return Value{}
- }
- return d.InputValueDefinitionDefaultValue(inputValueDefinition)
-}
-
-func (d *Document) InputObjectTypeDefinitionInputValueDefinitionByName(definition int, inputValueDefinitionName ByteSlice) int {
- for _, i := range d.InputObjectTypeDefinitions[definition].InputFieldsDefinition.Refs {
- if bytes.Equal(inputValueDefinitionName, d.InputValueDefinitionNameBytes(i)) {
- return i
- }
- }
- return -1
-}
-
-func (d *Document) AddInputObjectTypeDefinition(definition InputObjectTypeDefinition) (ref int) {
- d.InputObjectTypeDefinitions = append(d.InputObjectTypeDefinitions, definition)
- return len(d.InputObjectTypeDefinitions) - 1
-}
-
-func (d *Document) ImportInputObjectTypeDefinition(name, description string, argsRefs []int) (ref int) {
- definition := InputObjectTypeDefinition{
- Description: d.ImportDescription(description),
- Name: d.Input.AppendInputString(name),
- HasInputFieldsDefinition: len(argsRefs) > 0,
- InputFieldsDefinition: InputValueDefinitionList{
- Refs: argsRefs,
- },
- }
-
- ref = d.AddInputObjectTypeDefinition(definition)
- d.ImportRootNode(ref, NodeKindInputObjectTypeDefinition)
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_input_object_type_extension.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_input_object_type_extension.go
deleted file mode 100644
index ba4ee396567..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_input_object_type_extension.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type InputObjectTypeExtension struct {
- ExtendLiteral position.Position
- InputObjectTypeDefinition
-}
-
-func (d *Document) InputObjectTypeExtensionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.InputObjectTypeExtensions[ref].Name)
-}
-
-func (d *Document) InputObjectTypeExtensionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.InputObjectTypeExtensions[ref].Name))
-}
-
-func (d *Document) InputObjectTypeExtensionHasInputFieldsDefinition(ref int) bool {
- return d.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition
-}
-
-func (d *Document) InputObjectTypeExtensionHasDirectives(ref int) bool {
- return d.InputObjectTypeExtensions[ref].HasDirectives
-}
-
-func (d *Document) ExtendInputObjectTypeDefinitionByInputObjectTypeExtension(inputObjectTypeDefinitionRef, inputObjectTypeExtensionRef int) {
- if d.InputObjectTypeExtensionHasDirectives(inputObjectTypeExtensionRef) {
- d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].Directives.Refs = append(d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].Directives.Refs, d.InputObjectTypeExtensions[inputObjectTypeExtensionRef].Directives.Refs...)
- d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].HasDirectives = true
- }
-
- if d.InputObjectTypeExtensionHasInputFieldsDefinition(inputObjectTypeExtensionRef) {
- d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].InputFieldsDefinition.Refs = append(d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].InputFieldsDefinition.Refs, d.InputObjectTypeExtensions[inputObjectTypeExtensionRef].InputFieldsDefinition.Refs...)
- d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].HasInputFieldsDefinition = true
- }
-
- d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: inputObjectTypeExtensionRef, Kind: NodeKindInputObjectTypeExtension})
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_input_value_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_input_value_definition.go
deleted file mode 100644
index 6b8d8f676a5..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_input_value_definition.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type InputValueDefinitionList struct {
- LPAREN position.Position // (
- Refs []int // InputValueDefinition
- RPAREN position.Position // )
-}
-
-type DefaultValue struct {
- IsDefined bool
- Equals position.Position // =
- Value Value // e.g. "Foo"
-}
-
-type InputValueDefinition struct {
- Description Description // optional, e.g. "input Foo is..."
- Name ByteSliceReference // e.g. Foo
- Colon position.Position // :
- Type int // e.g. String
- DefaultValue DefaultValue // e.g. = "Bar"
- HasDirectives bool
- Directives DirectiveList // e.g. @baz
-}
-
-func (d *Document) InputValueDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.InputValueDefinitions[ref].Name)
-}
-
-func (d *Document) InputValueDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.InputValueDefinitions[ref].Name))
-}
-
-func (d *Document) InputValueDefinitionDescriptionBytes(ref int) ByteSlice {
- if !d.InputValueDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.InputValueDefinitions[ref].Description.Content)
-}
-
-func (d *Document) InputValueDefinitionDescriptionString(ref int) string {
- return unsafebytes.BytesToString(d.InputValueDefinitionDescriptionBytes(ref))
-}
-
-func (d *Document) InputValueDefinitionType(ref int) int {
- return d.InputValueDefinitions[ref].Type
-}
-
-func (d *Document) InputValueDefinitionHasDefaultValue(ref int) bool {
- return d.InputValueDefinitions[ref].DefaultValue.IsDefined
-}
-
-func (d *Document) InputValueDefinitionDefaultValue(ref int) Value {
- return d.InputValueDefinitions[ref].DefaultValue.Value
-}
-
-func (d *Document) InputValueDefinitionArgumentIsOptional(ref int) bool {
- nonNull := d.Types[d.InputValueDefinitions[ref].Type].TypeKind == TypeKindNonNull
- hasDefault := d.InputValueDefinitions[ref].DefaultValue.IsDefined
- return !nonNull || hasDefault
-}
-
-func (d *Document) InputValueDefinitionHasDirective(ref int, directiveName ByteSlice) bool {
- if !d.InputValueDefinitions[ref].HasDirectives {
- return false
- }
- for _, i := range d.InputValueDefinitions[ref].Directives.Refs {
- if bytes.Equal(directiveName, d.DirectiveNameBytes(i)) {
- return true
- }
- }
- return false
-}
-
-func (d *Document) AddInputValueDefinition(inputValueDefinition InputValueDefinition) (ref int) {
- d.InputValueDefinitions = append(d.InputValueDefinitions, inputValueDefinition)
- return len(d.InputValueDefinitions) - 1
-}
-
-func (d *Document) ImportInputValueDefinition(name, description string, typeRef int, defaultValue DefaultValue) (ref int) {
- inputValueDef := InputValueDefinition{
- Description: d.ImportDescription(description),
- Name: d.Input.AppendInputString(name),
- Type: typeRef,
- DefaultValue: defaultValue,
- }
-
- return d.AddInputValueDefinition(inputValueDef)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_interface_type_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_interface_type_definition.go
deleted file mode 100644
index 69413c03243..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_interface_type_definition.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// InterfaceTypeDefinition
-// example:
-// interface NamedEntity {
-// name: String
-// }
-type InterfaceTypeDefinition struct {
- Description Description // optional, describes the interface
- InterfaceLiteral position.Position // interface
- Name ByteSliceReference // e.g. NamedEntity
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
- HasFieldDefinitions bool
- FieldsDefinition FieldDefinitionList // optional, e.g. { name: String }
-}
-
-func (d *Document) InterfaceTypeDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.InterfaceTypeDefinitions[ref].Name)
-}
-
-func (d *Document) InterfaceTypeDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.InterfaceTypeDefinitions[ref].Name))
-}
-
-func (d *Document) InterfaceTypeDefinitionDescriptionBytes(ref int) ByteSlice {
- if !d.InterfaceTypeDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.InterfaceTypeDefinitions[ref].Description.Content)
-}
-
-func (d *Document) InterfaceTypeDefinitionDescriptionString(ref int) string {
- return unsafebytes.BytesToString(d.InterfaceTypeDefinitionDescriptionBytes(ref))
-}
-
-func (d *Document) AddInterfaceTypeDefinition(definition InterfaceTypeDefinition) (ref int) {
- d.InterfaceTypeDefinitions = append(d.InterfaceTypeDefinitions, definition)
- return len(d.InterfaceTypeDefinitions) - 1
-}
-
-func (d *Document) ImportInterfaceTypeDefinition(name, description string, fieldRefs []int) (ref int) {
- definition := InterfaceTypeDefinition{
- Name: d.Input.AppendInputString(name),
- Description: d.ImportDescription(description),
- FieldsDefinition: FieldDefinitionList{
- Refs: fieldRefs,
- },
- HasFieldDefinitions: len(fieldRefs) > 0,
- }
-
- ref = d.AddInterfaceTypeDefinition(definition)
- d.ImportRootNode(ref, NodeKindInterfaceTypeDefinition)
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_interface_type_extension.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_interface_type_extension.go
deleted file mode 100644
index a9a5f8ff399..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_interface_type_extension.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type InterfaceTypeExtension struct {
- ExtendLiteral position.Position
- InterfaceTypeDefinition
-}
-
-func (d *Document) InterfaceTypeExtensionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.InterfaceTypeExtensions[ref].Name)
-}
-
-func (d *Document) InterfaceTypeExtensionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.InterfaceTypeExtensions[ref].Name))
-}
-
-func (d *Document) InterfaceTypeExtensionHasFieldDefinitions(ref int) bool {
- return d.InterfaceTypeExtensions[ref].HasFieldDefinitions
-}
-
-func (d *Document) InterfaceTypeExtensionHasDirectives(ref int) bool {
- return d.InterfaceTypeExtensions[ref].HasDirectives
-}
-
-func (d *Document) ExtendInterfaceTypeDefinitionByInterfaceTypeExtension(interfaceTypeDefinitionRef, interfaceTypeExtensionRef int) {
- if d.InterfaceTypeExtensionHasFieldDefinitions(interfaceTypeExtensionRef) {
- d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].FieldsDefinition.Refs = append(d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].FieldsDefinition.Refs, d.InterfaceTypeExtensions[interfaceTypeExtensionRef].FieldsDefinition.Refs...)
- d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].HasFieldDefinitions = true
- }
-
- if d.InterfaceTypeExtensionHasDirectives(interfaceTypeExtensionRef) {
- d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].Directives.Refs = append(d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].Directives.Refs, d.InterfaceTypeExtensions[interfaceTypeExtensionRef].Directives.Refs...)
- d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].HasDirectives = true
- }
-
- d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: interfaceTypeExtensionRef, Kind: NodeKindInterfaceTypeExtension})
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_node.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_node.go
deleted file mode 100644
index 161559d8d53..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_node.go
+++ /dev/null
@@ -1,429 +0,0 @@
-package ast
-
-import (
- "bytes"
- "fmt"
- "log"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
-)
-
-type Node struct {
- Kind NodeKind
- Ref int
-}
-
-func (d *Document) NodeNameBytes(node Node) ByteSlice {
-
- var ref ByteSliceReference
-
- switch node.Kind {
- case NodeKindObjectTypeDefinition:
- ref = d.ObjectTypeDefinitions[node.Ref].Name
- case NodeKindInterfaceTypeDefinition:
- ref = d.InterfaceTypeDefinitions[node.Ref].Name
- case NodeKindInputObjectTypeDefinition:
- ref = d.InputObjectTypeDefinitions[node.Ref].Name
- case NodeKindUnionTypeDefinition:
- ref = d.UnionTypeDefinitions[node.Ref].Name
- case NodeKindScalarTypeDefinition:
- ref = d.ScalarTypeDefinitions[node.Ref].Name
- case NodeKindDirectiveDefinition:
- ref = d.DirectiveDefinitions[node.Ref].Name
- case NodeKindField:
- ref = d.Fields[node.Ref].Name
- case NodeKindDirective:
- ref = d.Directives[node.Ref].Name
- }
-
- return d.Input.ByteSlice(ref)
-}
-
-func (n Node) NameBytes(definition *Document) []byte {
- return definition.NodeNameBytes(n)
-}
-
-func (n Node) NameString(definition *Document) string {
- return unsafebytes.BytesToString(definition.NodeNameBytes(n))
-}
-
-// TODO: we could use node name directly
-func (d *Document) NodeNameString(node Node) string {
- return unsafebytes.BytesToString(d.NodeNameBytes(node))
-}
-
-// Node directives
-
-func (d *Document) NodeDirectives(node Node) []int {
- switch node.Kind {
- case NodeKindField:
- return d.Fields[node.Ref].Directives.Refs
- case NodeKindInlineFragment:
- return d.InlineFragments[node.Ref].Directives.Refs
- case NodeKindFragmentSpread:
- return d.FragmentSpreads[node.Ref].Directives.Refs
- case NodeKindSchemaDefinition:
- return d.SchemaDefinitions[node.Ref].Directives.Refs
- case NodeKindSchemaExtension:
- return d.SchemaExtensions[node.Ref].Directives.Refs
- case NodeKindObjectTypeDefinition:
- return d.ObjectTypeDefinitions[node.Ref].Directives.Refs
- case NodeKindObjectTypeExtension:
- return d.ObjectTypeExtensions[node.Ref].Directives.Refs
- case NodeKindFieldDefinition:
- return d.FieldDefinitions[node.Ref].Directives.Refs
- case NodeKindInterfaceTypeDefinition:
- return d.InterfaceTypeDefinitions[node.Ref].Directives.Refs
- case NodeKindInterfaceTypeExtension:
- return d.InterfaceTypeExtensions[node.Ref].Directives.Refs
- case NodeKindInputObjectTypeDefinition:
- return d.InputObjectTypeDefinitions[node.Ref].Directives.Refs
- case NodeKindInputObjectTypeExtension:
- return d.InputObjectTypeExtensions[node.Ref].Directives.Refs
- case NodeKindScalarTypeDefinition:
- return d.ScalarTypeDefinitions[node.Ref].Directives.Refs
- case NodeKindScalarTypeExtension:
- return d.ScalarTypeExtensions[node.Ref].Directives.Refs
- case NodeKindUnionTypeDefinition:
- return d.UnionTypeDefinitions[node.Ref].Directives.Refs
- case NodeKindUnionTypeExtension:
- return d.UnionTypeExtensions[node.Ref].Directives.Refs
- case NodeKindEnumTypeDefinition:
- return d.EnumTypeDefinitions[node.Ref].Directives.Refs
- case NodeKindEnumTypeExtension:
- return d.EnumTypeExtensions[node.Ref].Directives.Refs
- case NodeKindFragmentDefinition:
- return d.FragmentDefinitions[node.Ref].Directives.Refs
- case NodeKindInputValueDefinition:
- return d.InputValueDefinitions[node.Ref].Directives.Refs
- case NodeKindEnumValueDefinition:
- return d.EnumValueDefinitions[node.Ref].Directives.Refs
- case NodeKindVariableDefinition:
- return d.VariableDefinitions[node.Ref].Directives.Refs
- case NodeKindOperationDefinition:
- return d.OperationDefinitions[node.Ref].Directives.Refs
- default:
- return nil
- }
-}
-
-func (d *Document) RemoveDirectiveFromNode(node Node, ref int) {
- switch node.Kind {
- case NodeKindFragmentSpread:
- if i, ok := d.IndexOf(d.FragmentSpreads[node.Ref].Directives.Refs, ref); ok {
- d.FragmentSpreads[node.Ref].Directives.Refs = append(d.FragmentSpreads[node.Ref].Directives.Refs[:i], d.FragmentSpreads[node.Ref].Directives.Refs[i+1:]...)
- d.FragmentSpreads[node.Ref].HasDirectives = len(d.FragmentSpreads[node.Ref].Directives.Refs) > 0
- }
- case NodeKindInlineFragment:
- if i, ok := d.IndexOf(d.InlineFragments[node.Ref].Directives.Refs, ref); ok {
- d.InlineFragments[node.Ref].Directives.Refs = append(d.InlineFragments[node.Ref].Directives.Refs[:i], d.InlineFragments[node.Ref].Directives.Refs[i+1:]...)
- d.InlineFragments[node.Ref].HasDirectives = len(d.InlineFragments[node.Ref].Directives.Refs) > 0
- }
- case NodeKindField:
- if i, ok := d.IndexOf(d.Fields[node.Ref].Directives.Refs, ref); ok {
- d.Fields[node.Ref].Directives.Refs = append(d.Fields[node.Ref].Directives.Refs[:i], d.Fields[node.Ref].Directives.Refs[i+1:]...)
- d.Fields[node.Ref].HasDirectives = len(d.Fields[node.Ref].Directives.Refs) > 0
- }
- default:
- log.Printf("RemoveDirectiveFromNode not implemented for node kind: %s", node.Kind)
- }
-}
-
-func (d *Document) NodeDirectiveLocation(node Node) (location DirectiveLocation, err error) {
- switch node.Kind {
- case NodeKindSchemaDefinition:
- location = TypeSystemDirectiveLocationSchema
- case NodeKindSchemaExtension:
- location = TypeSystemDirectiveLocationSchema
- case NodeKindObjectTypeDefinition:
- location = TypeSystemDirectiveLocationObject
- case NodeKindObjectTypeExtension:
- location = TypeSystemDirectiveLocationObject
- case NodeKindInterfaceTypeDefinition:
- location = TypeSystemDirectiveLocationInterface
- case NodeKindInterfaceTypeExtension:
- location = TypeSystemDirectiveLocationInterface
- case NodeKindUnionTypeDefinition:
- location = TypeSystemDirectiveLocationUnion
- case NodeKindUnionTypeExtension:
- location = TypeSystemDirectiveLocationUnion
- case NodeKindEnumTypeDefinition:
- location = TypeSystemDirectiveLocationEnum
- case NodeKindEnumTypeExtension:
- location = TypeSystemDirectiveLocationEnum
- case NodeKindInputObjectTypeDefinition:
- location = TypeSystemDirectiveLocationInputObject
- case NodeKindInputObjectTypeExtension:
- location = TypeSystemDirectiveLocationInputObject
- case NodeKindScalarTypeDefinition:
- location = TypeSystemDirectiveLocationScalar
- case NodeKindOperationDefinition:
- switch d.OperationDefinitions[node.Ref].OperationType {
- case OperationTypeQuery:
- location = ExecutableDirectiveLocationQuery
- case OperationTypeMutation:
- location = ExecutableDirectiveLocationMutation
- case OperationTypeSubscription:
- location = ExecutableDirectiveLocationSubscription
- }
- case NodeKindField:
- location = ExecutableDirectiveLocationField
- case NodeKindFragmentSpread:
- location = ExecutableDirectiveLocationFragmentSpread
- case NodeKindInlineFragment:
- location = ExecutableDirectiveLocationInlineFragment
- case NodeKindFragmentDefinition:
- location = ExecutableDirectiveLocationFragmentDefinition
- case NodeKindVariableDefinition:
- location = ExecutableDirectiveLocationVariableDefinition
- default:
- err = fmt.Errorf("node kind: %s is not allowed to have directives", node.Kind)
- }
- return
-}
-
-// Node resolvers
-
-// NodeResolverTypeNameBytes returns lowercase query/mutation/subscription for Query/Mutation/Subscription
-// for other type definitions it returns the default type name
-func (d *Document) NodeResolverTypeNameBytes(node Node, path Path) ByteSlice {
- if len(path) == 1 && path[0].Kind == FieldName {
- return path[0].FieldName
- }
- switch node.Kind {
- case NodeKindObjectTypeDefinition:
- return d.ObjectTypeDefinitionNameBytes(node.Ref)
- case NodeKindInterfaceTypeDefinition:
- return d.InterfaceTypeDefinitionNameBytes(node.Ref)
- case NodeKindUnionTypeDefinition:
- return d.UnionTypeDefinitionNameBytes(node.Ref)
- }
- return nil
-}
-
-func (d *Document) NodeResolverTypeNameString(node Node, path Path) string {
- return unsafebytes.BytesToString(d.NodeResolverTypeNameBytes(node, path))
-}
-
-// Node field definitions
-
-func (d *Document) NodeFieldDefinitions(node Node) []int {
- switch node.Kind {
- case NodeKindObjectTypeDefinition:
- return d.ObjectTypeDefinitions[node.Ref].FieldsDefinition.Refs
- case NodeKindObjectTypeExtension:
- return d.ObjectTypeExtensions[node.Ref].FieldsDefinition.Refs
- case NodeKindInterfaceTypeDefinition:
- return d.InterfaceTypeDefinitions[node.Ref].FieldsDefinition.Refs
- case NodeKindInterfaceTypeExtension:
- return d.InterfaceTypeExtensions[node.Ref].FieldsDefinition.Refs
- default:
- return nil
- }
-}
-
-func (d *Document) NodeFieldDefinitionByName(node Node, fieldName ByteSlice) (definition int, exists bool) {
- for _, i := range d.NodeFieldDefinitions(node) {
- if bytes.Equal(d.Input.ByteSlice(d.FieldDefinitions[i].Name), fieldName) {
- return i, true
- }
- }
- return
-}
-
-func (d *Document) NodeFieldDefinitionArgumentDefinitionByName(node Node, fieldName, argumentName ByteSlice) int {
- fieldDefinition, exists := d.NodeFieldDefinitionByName(node, fieldName)
- if !exists {
- return -1
- }
- argumentDefinitions := d.FieldDefinitionArgumentsDefinitions(fieldDefinition)
- for _, i := range argumentDefinitions {
- if bytes.Equal(argumentName, d.Input.ByteSlice(d.InputValueDefinitions[i].Name)) {
- return i
- }
- }
- return -1
-}
-
-func (d *Document) NodeFieldDefinitionArgumentsDefinitions(node Node, fieldName ByteSlice) []int {
- fieldDefinition, exists := d.NodeFieldDefinitionByName(node, fieldName)
- if !exists {
- return nil
- }
- return d.FieldDefinitionArgumentsDefinitions(fieldDefinition)
-}
-
-// Node input value definitions
-
-func (d *Document) NodeInputValueDefinitions(node Node) []int {
- switch node.Kind {
- case NodeKindInputObjectTypeDefinition:
- return d.InputObjectTypeDefinitions[node.Ref].InputFieldsDefinition.Refs
- case NodeKindInputObjectTypeExtension:
- return d.InputObjectTypeExtensions[node.Ref].InputFieldsDefinition.Refs
- case NodeKindFieldDefinition:
- return d.FieldDefinitions[node.Ref].ArgumentsDefinition.Refs
- case NodeKindDirectiveDefinition:
- return d.DirectiveDefinitions[node.Ref].ArgumentsDefinition.Refs
- default:
- return nil
- }
-}
-
-func (d *Document) InputValueDefinitionIsFirst(inputValue int, ancestor Node) bool {
- inputValues := d.NodeInputValueDefinitions(ancestor)
- return inputValues != nil && inputValues[0] == inputValue
-}
-
-func (d *Document) InputValueDefinitionIsLast(inputValue int, ancestor Node) bool {
- inputValues := d.NodeInputValueDefinitions(ancestor)
- return inputValues != nil && inputValues[len(inputValues)-1] == inputValue
-}
-
-// Node misc
-
-func (d *Document) NodeImplementsInterface(node Node, interfaceNode Node) bool {
-
- nodeFields := d.NodeFieldDefinitions(node)
- interfaceFields := d.NodeFieldDefinitions(interfaceNode)
-
- for _, i := range interfaceFields {
- interfaceFieldName := d.FieldDefinitionNameBytes(i)
- if !d.FieldDefinitionsContainField(nodeFields, interfaceFieldName) {
- return false
- }
- }
-
- return true
-}
-
-func (d *Document) NodeIsUnionMember(node Node, union Node) bool {
- nodeTypeName := d.NodeNameBytes(node)
- for _, i := range d.UnionTypeDefinitions[union.Ref].UnionMemberTypes.Refs {
- memberName := d.ResolveTypeNameBytes(i)
- if bytes.Equal(nodeTypeName, memberName) {
- return true
- }
- }
- return false
-}
-
-func (d *Document) NodeIsLastRootNode(node Node) bool {
- if len(d.RootNodes) == 0 {
- return false
- }
- for i := len(d.RootNodes) - 1; i >= 0; i-- {
- if d.RootNodes[i].Kind == NodeKindUnknown {
- continue
- }
- return d.RootNodes[i] == node
- }
- return false
-}
-
-func (d *Document) RemoveNodeFromNode(remove, from Node) {
- switch from.Kind {
- case NodeKindSelectionSet:
- d.RemoveNodeFromSelectionSet(from.Ref, remove)
- default:
- log.Printf("RemoveNodeFromNode not implemented for from: %s", from.Kind)
- }
-}
-
-func (d *Document) RemoveNodeFromSelectionSet(set int, node Node) {
-
- var selectionKind SelectionKind
-
- switch node.Kind {
- case NodeKindFragmentSpread:
- selectionKind = SelectionKindFragmentSpread
- case NodeKindInlineFragment:
- selectionKind = SelectionKindInlineFragment
- case NodeKindField:
- selectionKind = SelectionKindField
- default:
- log.Printf("RemoveNodeFromSelectionSet not implemented for node: %s", node.Kind)
- return
- }
-
- for i, j := range d.SelectionSets[set].SelectionRefs {
- if d.Selections[j].Kind == selectionKind && d.Selections[j].Ref == node.Ref {
- d.SelectionSets[set].SelectionRefs = append(d.SelectionSets[set].SelectionRefs[:i], d.SelectionSets[set].SelectionRefs[i+1:]...)
- return
- }
- }
-}
-
-// Node fragments
-
-func (d *Document) NodeFragmentIsAllowedOnNode(fragmentNode, onNode Node) bool {
- switch onNode.Kind {
- case NodeKindObjectTypeDefinition:
- return d.NodeFragmentIsAllowedOnObjectTypeDefinition(fragmentNode, onNode)
- case NodeKindInterfaceTypeDefinition:
- return d.NodeFragmentIsAllowedOnInterfaceTypeDefinition(fragmentNode, onNode)
- case NodeKindUnionTypeDefinition:
- return d.NodeFragmentIsAllowedOnUnionTypeDefinition(fragmentNode, onNode)
- default:
- return false
- }
-}
-
-func (d *Document) NodeFragmentIsAllowedOnInterfaceTypeDefinition(fragmentNode, interfaceTypeNode Node) bool {
-
- switch fragmentNode.Kind {
- case NodeKindObjectTypeDefinition:
- return d.NodeImplementsInterface(fragmentNode, interfaceTypeNode)
- case NodeKindInterfaceTypeDefinition:
- return bytes.Equal(d.InterfaceTypeDefinitionNameBytes(fragmentNode.Ref), d.InterfaceTypeDefinitionNameBytes(interfaceTypeNode.Ref))
- case NodeKindUnionTypeDefinition:
- return d.UnionNodeIntersectsInterfaceNode(fragmentNode, interfaceTypeNode)
- }
-
- return false
-}
-
-func (d *Document) NodeFragmentIsAllowedOnUnionTypeDefinition(fragmentNode, unionTypeNode Node) bool {
-
- switch fragmentNode.Kind {
- case NodeKindObjectTypeDefinition:
- return d.NodeIsUnionMember(fragmentNode, unionTypeNode)
- case NodeKindInterfaceTypeDefinition:
- return false
- case NodeKindUnionTypeDefinition:
- return bytes.Equal(d.UnionTypeDefinitionNameBytes(fragmentNode.Ref), d.UnionTypeDefinitionNameBytes(unionTypeNode.Ref))
- }
-
- return false
-}
-
-func (d *Document) NodeFragmentIsAllowedOnObjectTypeDefinition(fragmentNode, objectTypeNode Node) bool {
-
- switch fragmentNode.Kind {
- case NodeKindObjectTypeDefinition:
- return bytes.Equal(d.ObjectTypeDefinitionNameBytes(fragmentNode.Ref), d.ObjectTypeDefinitionNameBytes(objectTypeNode.Ref))
- case NodeKindInterfaceTypeDefinition:
- return d.NodeImplementsInterface(objectTypeNode, fragmentNode)
- case NodeKindUnionTypeDefinition:
- return d.NodeIsUnionMember(objectTypeNode, fragmentNode)
- }
-
- return false
-}
-
-func (d *Document) UnionNodeIntersectsInterfaceNode(unionNode, interfaceNode Node) bool {
- for _, i := range d.UnionTypeDefinitions[unionNode.Ref].UnionMemberTypes.Refs {
- memberName := d.ResolveTypeNameBytes(i)
- node, exists := d.Index.FirstNodeByNameBytes(memberName)
- if !exists {
- continue
- }
- if node.Kind != NodeKindObjectTypeDefinition {
- continue
- }
- if d.NodeImplementsInterface(node, interfaceNode) {
- return true
- }
- }
- return false
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_node_kind.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_node_kind.go
deleted file mode 100644
index 700dc36166a..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_node_kind.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type NodeKind int
-
-const (
- NodeKindUnknown NodeKind = 22 + iota
- NodeKindSchemaDefinition
- NodeKindSchemaExtension
- NodeKindObjectTypeDefinition
- NodeKindObjectTypeExtension
- NodeKindInterfaceTypeDefinition
- NodeKindInterfaceTypeExtension
- NodeKindUnionTypeDefinition
- NodeKindUnionTypeExtension
- NodeKindUnionMemberType
- NodeKindEnumTypeDefinition
- NodeKindEnumValueDefinition
- NodeKindEnumTypeExtension
- NodeKindInputObjectTypeDefinition
- NodeKindInputValueDefinition
- NodeKindInputObjectTypeExtension
- NodeKindScalarTypeDefinition
- NodeKindScalarTypeExtension
- NodeKindDirectiveDefinition
- NodeKindOperationDefinition
- NodeKindSelectionSet
- NodeKindField
- NodeKindFieldDefinition
- NodeKindFragmentSpread
- NodeKindInlineFragment
- NodeKindFragmentDefinition
- NodeKindArgument
- NodeKindDirective
- NodeKindVariableDefinition
-)
-
-func (d *Document) NodeKindNameBytes(node Node) ByteSlice {
- switch node.Kind {
- case NodeKindOperationDefinition:
- switch d.OperationDefinitions[node.Ref].OperationType {
- case OperationTypeQuery:
- return literal.LocationQuery
- case OperationTypeMutation:
- return literal.LocationMutation
- case OperationTypeSubscription:
- return literal.LocationSubscription
- }
- case NodeKindField:
- return literal.LocationField
- case NodeKindFragmentDefinition:
- return literal.LocationFragmentDefinition
- case NodeKindFragmentSpread:
- return literal.LocationFragmentSpread
- case NodeKindInlineFragment:
- return literal.LocationInlineFragment
- case NodeKindVariableDefinition:
- return literal.LocationVariableDefinition
- case NodeKindSchemaDefinition:
- return literal.LocationSchema
- case NodeKindScalarTypeDefinition:
- return literal.LocationScalar
- case NodeKindObjectTypeDefinition:
- return literal.LocationObject
- case NodeKindFieldDefinition:
- return literal.LocationFieldDefinition
- case NodeKindInterfaceTypeDefinition:
- return literal.LocationInterface
- case NodeKindUnionTypeDefinition:
- return literal.LocationUnion
- case NodeKindEnumTypeDefinition:
- return literal.LocationEnum
- case NodeKindEnumValueDefinition:
- return literal.LocationEnumValue
- case NodeKindInputObjectTypeDefinition:
- return literal.LocationInputObject
- case NodeKindInputValueDefinition:
- return literal.LocationInputFieldDefinition
- }
-
- return unsafebytes.StringToBytes(node.Kind.String())
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_object_field.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_object_field.go
deleted file mode 100644
index b6013765d5f..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_object_field.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// ObjectField
-// example:
-// lon: 12.43
-type ObjectField struct {
- Name ByteSliceReference // e.g. lon
- Colon position.Position // :
- Value Value // e.g. 12.43
-}
-
-func (d *Document) ObjectField(ref int) ObjectField {
- return d.ObjectFields[ref]
-}
-
-func (d *Document) ObjectFieldNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.ObjectFields[ref].Name)
-}
-
-func (d *Document) ObjectFieldNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.ObjectFields[ref].Name))
-}
-
-func (d *Document) ObjectFieldValue(ref int) Value {
- return d.ObjectFields[ref].Value
-}
-
-func (d *Document) ObjectFieldsAreEqual(left, right int) bool {
- return bytes.Equal(d.ObjectFieldNameBytes(left), d.ObjectFieldNameBytes(right)) &&
- d.ValuesAreEqual(d.ObjectFieldValue(left), d.ObjectFieldValue(right))
-}
-
-func (d *Document) ObjectValuesAreEqual(left, right int) bool {
- leftFields, rightFields := d.ObjectValues[left].Refs, d.ObjectValues[right].Refs
- if len(leftFields) != len(rightFields) {
- return false
- }
- for i := 0; i < len(leftFields); i++ {
- left, right = leftFields[i], rightFields[i]
- if !d.ObjectFieldsAreEqual(left, right) {
- return false
- }
- }
- return true
-}
-
-func (d *Document) AddObjectField(field ObjectField) (ref int) {
- d.ObjectFields = append(d.ObjectFields, field)
- return len(d.ObjectFields) - 1
-}
-
-func (d *Document) ImportObjectField(name ByteSlice, value Value) (ref int) {
- return d.AddObjectField(ObjectField{
- Name: d.Input.AppendInputBytes(name),
- Value: value,
- })
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_object_type_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_object_type_definition.go
deleted file mode 100644
index 59b50dde71d..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_object_type_definition.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type TypeList struct {
- Refs []int // Type
-}
-
-type ObjectTypeDefinition struct {
- Description Description // optional, e.g. "type Foo is ..."
- TypeLiteral position.Position // type
- Name ByteSliceReference // e.g. Foo
- ImplementsInterfaces TypeList // e.g implements Bar & Baz
- HasDirectives bool
- Directives DirectiveList // e.g. @foo
- HasFieldDefinitions bool
- FieldsDefinition FieldDefinitionList // { foo:Bar bar(baz:String) }
-}
-
-func (d *Document) ObjectTypeDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.ObjectTypeDefinitions[ref].Name)
-}
-
-func (d *Document) ObjectTypeDefinitionNameRef(ref int) ByteSliceReference {
- return d.ObjectTypeDefinitions[ref].Name
-}
-
-func (d *Document) ObjectTypeDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.ObjectTypeDefinitions[ref].Name))
-}
-
-func (d *Document) ObjectTypeDescriptionNameBytes(ref int) ByteSlice {
- if !d.ObjectTypeDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.ObjectTypeDefinitions[ref].Description.Content)
-}
-
-func (d *Document) ObjectTypeDescriptionNameString(ref int) string {
- return unsafebytes.BytesToString(d.ObjectTypeDescriptionNameBytes(ref))
-}
-
-func (d *Document) ObjectTypeDefinitionHasField(ref int, fieldName []byte) bool {
- for _, fieldDefinitionRef := range d.ObjectTypeDefinitions[ref].FieldsDefinition.Refs {
- currentFieldName := d.FieldDefinitionNameBytes(fieldDefinitionRef)
- if currentFieldName.Equals(fieldName) {
- return true
- }
- }
- return false
-}
-
-func (d *Document) ObjectTypeDefinitionImplementsInterface(definitionRef int, interfaceName ByteSlice) bool {
- for _, iRef := range d.ObjectTypeDefinitions[definitionRef].ImplementsInterfaces.Refs {
- implements := d.ResolveTypeNameBytes(iRef)
- if bytes.Equal(interfaceName, implements) {
- return true
- }
- }
- return false
-}
-
-func (d *Document) AddObjectTypeDefinition(definition ObjectTypeDefinition) (ref int) {
- d.ObjectTypeDefinitions = append(d.ObjectTypeDefinitions, definition)
- return len(d.ObjectTypeDefinitions) - 1
-}
-
-func (d *Document) ImportObjectTypeDefinition(name, description string, fieldRefs []int, iRefs []int) (ref int) {
- definition := ObjectTypeDefinition{
- Name: d.Input.AppendInputString(name),
- Description: d.ImportDescription(description),
- FieldsDefinition: FieldDefinitionList{
- Refs: fieldRefs,
- },
- HasFieldDefinitions: len(fieldRefs) > 0,
- ImplementsInterfaces: TypeList{
- Refs: iRefs,
- },
- }
-
- ref = d.AddObjectTypeDefinition(definition)
- d.ImportRootNode(ref, NodeKindObjectTypeDefinition)
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_object_type_extension.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_object_type_extension.go
deleted file mode 100644
index a49c76af1bc..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_object_type_extension.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type ObjectTypeExtension struct {
- ExtendLiteral position.Position
- ObjectTypeDefinition
-}
-
-func (d *Document) ObjectTypeExtensionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.ObjectTypeExtensions[ref].Name)
-}
-
-func (d *Document) ObjectTypeExtensionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.ObjectTypeExtensions[ref].Name))
-}
-
-func (d *Document) ObjectTypeExtensionHasFieldDefinitions(ref int) bool {
- return d.ObjectTypeExtensions[ref].HasFieldDefinitions
-}
-
-func (d *Document) ObjectTypeExtensionHasDirectives(ref int) bool {
- return d.ObjectTypeExtensions[ref].HasDirectives
-}
-
-func (d *Document) ExtendObjectTypeDefinitionByObjectTypeExtension(objectTypeDefinitionRef, objectTypeExtensionRef int) {
- if d.ObjectTypeExtensionHasFieldDefinitions(objectTypeExtensionRef) {
- d.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs = append(d.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs, d.ObjectTypeExtensions[objectTypeExtensionRef].FieldsDefinition.Refs...)
- d.ObjectTypeDefinitions[objectTypeDefinitionRef].HasFieldDefinitions = true
- }
-
- if d.ObjectTypeExtensionHasDirectives(objectTypeExtensionRef) {
- d.ObjectTypeDefinitions[objectTypeDefinitionRef].Directives.Refs = append(d.ObjectTypeDefinitions[objectTypeDefinitionRef].Directives.Refs, d.ObjectTypeExtensions[objectTypeExtensionRef].Directives.Refs...)
- d.ObjectTypeDefinitions[objectTypeDefinitionRef].HasDirectives = true
- }
-
- d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: objectTypeExtensionRef, Kind: NodeKindObjectTypeExtension})
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_operation_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_operation_definition.go
deleted file mode 100644
index 85552e6b100..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_operation_definition.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package ast
-
-import (
- "math"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type OperationType int
-
-const (
- OperationTypeUnknown OperationType = iota
- OperationTypeQuery
- OperationTypeMutation
- OperationTypeSubscription
-)
-
-type OperationDefinition struct {
- OperationType OperationType // one of query, mutation, subscription
- OperationTypeLiteral position.Position // position of the operation type literal, if present
- Name ByteSliceReference // optional, user defined name of the operation
- HasVariableDefinitions bool
- VariableDefinitions VariableDefinitionList // optional, e.g. ($devicePicSize: Int)
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
- SelectionSet int // e.g. {field}
- HasSelections bool
-}
-
-func (d *Document) OperationDefinitionHasVariableDefinition(ref int, variableName string) bool {
- for _, i := range d.OperationDefinitions[ref].VariableDefinitions.Refs {
- value := d.VariableDefinitions[i].VariableValue.Ref
- if variableName == d.VariableValueNameString(value) {
- return true
- }
- }
- return false
-}
-
-func (d *Document) OperationDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.OperationDefinitions[ref].Name)
-}
-
-func (d *Document) OperationDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.OperationDefinitions[ref].Name))
-}
-
-func (d *Document) AddOperationDefinitionToRootNodes(definition OperationDefinition) Node {
- d.OperationDefinitions = append(d.OperationDefinitions, definition)
- node := Node{Kind: NodeKindOperationDefinition, Ref: len(d.OperationDefinitions) - 1}
- d.RootNodes = append(d.RootNodes, node)
- return node
-}
-
-func (d *Document) AddVariableDefinitionToOperationDefinition(operationDefinitionRef, variableValueRef, typeRef int) {
- if !d.OperationDefinitions[operationDefinitionRef].HasVariableDefinitions {
- d.OperationDefinitions[operationDefinitionRef].HasVariableDefinitions = true
- d.OperationDefinitions[operationDefinitionRef].VariableDefinitions.Refs = d.Refs[d.NextRefIndex()][:0]
- }
- variableDefinition := VariableDefinition{
- VariableValue: Value{
- Kind: ValueKindVariable,
- Ref: variableValueRef,
- },
- Type: typeRef,
- }
- d.VariableDefinitions = append(d.VariableDefinitions, variableDefinition)
- ref := len(d.VariableDefinitions) - 1
- d.OperationDefinitions[operationDefinitionRef].VariableDefinitions.Refs =
- append(d.OperationDefinitions[operationDefinitionRef].VariableDefinitions.Refs, ref)
-}
-
-func (d *Document) AddImportedVariableDefinitionToOperationDefinition(operationDefinition, variableDefinition int) {
- if !d.OperationDefinitions[operationDefinition].HasVariableDefinitions {
- d.OperationDefinitions[operationDefinition].HasVariableDefinitions = true
- d.OperationDefinitions[operationDefinition].VariableDefinitions.Refs = d.Refs[d.NextRefIndex()][:0]
- }
- d.OperationDefinitions[operationDefinition].VariableDefinitions.Refs =
- append(d.OperationDefinitions[operationDefinition].VariableDefinitions.Refs, variableDefinition)
-}
-
-func (d *Document) OperationNameExists(operationName string) bool {
-
- for i := range d.RootNodes {
- if d.RootNodes[i].Kind != NodeKindOperationDefinition {
- continue
- }
- if d.OperationDefinitionNameString(i) == operationName {
- return true
- }
- }
-
- return false
-}
-
-func (d *Document) NumOfOperationDefinitions () (n int) {
- for i := range d.RootNodes {
- if d.RootNodes[i].Kind == NodeKindOperationDefinition {
- n++
- }
- }
- return
-}
-
-const (
- alphabet = `abcdefghijklmnopqrstuvwxyz`
-)
-
-func (d *Document) GenerateUnusedVariableDefinitionName(operationDefinition int) []byte {
- var i, k int64
-
- for i = 1; i < math.MaxInt64; i++ {
- out := make([]byte, i)
- for j := range alphabet {
- for k = 0; k < i; k++ {
- out[k] = alphabet[j]
- }
- _, exists := d.VariableDefinitionByNameAndOperation(operationDefinition, out)
- if !exists {
- return out
- }
- }
- }
-
- return nil
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_root_operation_type_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_root_operation_type_definition.go
deleted file mode 100644
index 3769e41e992..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_root_operation_type_definition.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package ast
-
-import "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-
-type RootOperationTypeDefinitionList struct {
- LBrace position.Position // {
- Refs []int // RootOperationTypeDefinition
- RBrace position.Position // }
-}
-
-type RootOperationTypeDefinition struct {
- OperationType OperationType // one of query, mutation, subscription
- Colon position.Position // :
- NamedType Type // e.g. Query
-}
-
-func (d *Document) RootOperationTypeDefinitionNameString(ref int) string {
- return d.RootOperationTypeDefinitions[ref].OperationType.String()
-}
-
-func (d *Document) RootOperationTypeDefinitionIsFirstInSchemaDefinition(ref int, ancestor Node) bool {
- switch ancestor.Kind {
- case NodeKindSchemaDefinition:
- if len(d.SchemaDefinitions[ancestor.Ref].RootOperationTypeDefinitions.Refs) == 0 {
- return false
- }
- return ref == d.SchemaDefinitions[ancestor.Ref].RootOperationTypeDefinitions.Refs[0]
- case NodeKindSchemaExtension:
- if len(d.SchemaExtensions[ancestor.Ref].RootOperationTypeDefinitions.Refs) == 0 {
- return false
- }
- return ref == d.SchemaExtensions[ancestor.Ref].RootOperationTypeDefinitions.Refs[0]
- default:
- return false
- }
-}
-
-func (d *Document) RootOperationTypeDefinitionIsLastInSchemaDefinition(ref int, ancestor Node) bool {
- switch ancestor.Kind {
- case NodeKindSchemaDefinition:
- return d.SchemaDefinitions[ancestor.Ref].RootOperationTypeDefinitions.Refs[len(d.SchemaDefinitions[ancestor.Ref].RootOperationTypeDefinitions.Refs)-1] == ref
- case NodeKindSchemaExtension:
- return d.SchemaExtensions[ancestor.Ref].RootOperationTypeDefinitions.Refs[len(d.SchemaExtensions[ancestor.Ref].RootOperationTypeDefinitions.Refs)-1] == ref
- default:
- return false
- }
-}
-
-func (d *Document) CreateRootOperationTypeDefinition(operationType OperationType, rootNodeIndex int) (ref int) {
- switch operationType {
- case OperationTypeQuery:
- d.Index.QueryTypeName = []byte("Query")
- case OperationTypeMutation:
- d.Index.MutationTypeName = []byte("Mutation")
- case OperationTypeSubscription:
- d.Index.SubscriptionTypeName = []byte("Subscription")
- default:
- return
- }
-
- nameRef := d.ObjectTypeDefinitionNameRef(d.RootNodes[rootNodeIndex].Ref)
- return d.AddRootOperationTypeDefinition(RootOperationTypeDefinition{
- OperationType: operationType,
- NamedType: Type{
- TypeKind: TypeKindNamed,
- Name: nameRef,
- },
- })
-}
-
-func (d *Document) AddRootOperationTypeDefinition(rootOperationTypeDefinition RootOperationTypeDefinition) (ref int) {
- d.RootOperationTypeDefinitions = append(d.RootOperationTypeDefinitions, rootOperationTypeDefinition)
- return len(d.RootOperationTypeDefinitions) - 1
-}
-
-func (d *Document) ImportRootOperationTypeDefinition(name string, operationType OperationType) (ref int) {
- operationTypeDefinition := RootOperationTypeDefinition{
- OperationType: operationType,
- NamedType: Type{
- Name: d.Input.AppendInputString(name),
- },
- }
-
- return d.AddRootOperationTypeDefinition(operationTypeDefinition)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_scalar_type_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_scalar_type_definition.go
deleted file mode 100644
index c9e8cceac39..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_scalar_type_definition.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// ScalarTypeDefinition
-// example:
-// scalar JSON
-type ScalarTypeDefinition struct {
- Description Description // optional, describes the scalar
- ScalarLiteral position.Position // scalar
- Name ByteSliceReference // e.g. JSON
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
-}
-
-func (d *Document) ScalarTypeDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.ScalarTypeDefinitions[ref].Name)
-}
-
-func (d *Document) ScalarTypeDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.ScalarTypeDefinitions[ref].Name))
-}
-
-func (d *Document) ScalarTypeDefinitionDescriptionBytes(ref int) ByteSlice {
- if !d.ScalarTypeDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.ScalarTypeDefinitions[ref].Description.Content)
-}
-
-func (d *Document) ScalarTypeDefinitionDescriptionString(ref int) string {
- return unsafebytes.BytesToString(d.ScalarTypeDefinitionDescriptionBytes(ref))
-}
-
-func (d *Document) ScalarTypeDefinitionHasDirectives(ref int) bool {
- return d.ScalarTypeDefinitions[ref].HasDirectives
-}
-
-func (d *Document) AddScalarTypeDefinition(definition ScalarTypeDefinition) (ref int) {
- d.ScalarTypeDefinitions = append(d.ScalarTypeDefinitions, definition)
- return len(d.ScalarTypeDefinitions) - 1
-}
-
-func (d *Document) ImportScalarTypeDefinition(name, description string) (ref int) {
- definition := ScalarTypeDefinition{
- Description: d.ImportDescription(description),
- Name: d.Input.AppendInputString(name),
- }
-
- ref = d.AddScalarTypeDefinition(definition)
- d.ImportRootNode(ref, NodeKindScalarTypeDefinition)
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_scalar_type_extension.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_scalar_type_extension.go
deleted file mode 100644
index 6158138f44f..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_scalar_type_extension.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type ScalarTypeExtension struct {
- ExtendLiteral position.Position
- ScalarTypeDefinition
-}
-
-func (d *Document) ScalarTypeExtensionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.ScalarTypeExtensions[ref].Name)
-}
-
-func (d *Document) ScalarTypeExtensionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.ScalarTypeExtensions[ref].Name))
-}
-
-func (d *Document) ScalarTypeExtensionHasDirectives(ref int) bool {
- return d.ScalarTypeExtensions[ref].HasDirectives
-}
-
-func (d *Document) ExtendScalarTypeDefinitionByScalarTypeExtension(scalarTypeDefinitionRef, scalarTypeExtensionRef int) {
- if d.ScalarTypeExtensionHasDirectives(scalarTypeExtensionRef) {
- d.ScalarTypeDefinitions[scalarTypeDefinitionRef].Directives.Refs = append(d.ScalarTypeDefinitions[scalarTypeDefinitionRef].Directives.Refs, d.ScalarTypeExtensions[scalarTypeExtensionRef].Directives.Refs...)
- d.ScalarTypeDefinitions[scalarTypeDefinitionRef].HasDirectives = true
- }
-
- d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: scalarTypeExtensionRef, Kind: NodeKindScalarTypeExtension})
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_schema_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_schema_definition.go
deleted file mode 100644
index c1f6054e3ed..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_schema_definition.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package ast
-
-import "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-
-type SchemaDefinition struct {
- SchemaLiteral position.Position // schema
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
- RootOperationTypeDefinitions RootOperationTypeDefinitionList // e.g. query: Query, mutation: Mutation, subscription: Subscription
-}
-
-func (s *SchemaDefinition) AddRootOperationTypeDefinitionRefs(refs ...int) {
- s.RootOperationTypeDefinitions.Refs = append(s.RootOperationTypeDefinitions.Refs, refs...)
-}
-
-func (d *Document) HasSchemaDefinition() bool {
- for i := range d.RootNodes {
- if d.RootNodes[i].Kind == NodeKindSchemaDefinition {
- return true
- }
- }
-
- return false
-}
-
-func (d *Document) AddSchemaDefinition(schemaDefinition SchemaDefinition) (ref int) {
- d.SchemaDefinitions = append(d.SchemaDefinitions, schemaDefinition)
- return len(d.SchemaDefinitions) - 1
-}
-
-func (d *Document) AddSchemaDefinitionRootNode(schemaDefinition SchemaDefinition) {
- ref := d.AddSchemaDefinition(schemaDefinition)
- schemaNode := Node{
- Kind: NodeKindSchemaDefinition,
- Ref: ref,
- }
- d.RootNodes = append([]Node{schemaNode}, d.RootNodes...)
-}
-
-func (d *Document) ImportSchemaDefinition(queryTypeName, mutationTypeName, subscriptionTypeName string) {
- var operationRefs []int
-
- if queryTypeName != "" {
- operationRefs = append(operationRefs, d.ImportRootOperationTypeDefinition(queryTypeName, OperationTypeQuery))
- }
- if mutationTypeName != "" {
- operationRefs = append(operationRefs, d.ImportRootOperationTypeDefinition(mutationTypeName, OperationTypeMutation))
- }
- if subscriptionTypeName != "" {
- operationRefs = append(operationRefs, d.ImportRootOperationTypeDefinition(subscriptionTypeName, OperationTypeSubscription))
- }
-
- schemaDefinition := SchemaDefinition{
- RootOperationTypeDefinitions: RootOperationTypeDefinitionList{
- Refs: operationRefs,
- },
- }
-
- d.AddSchemaDefinitionRootNode(schemaDefinition)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_schema_extension.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_schema_extension.go
deleted file mode 100644
index 69b3c3d5030..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_schema_extension.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package ast
-
-import "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-
-type SchemaExtension struct {
- ExtendLiteral position.Position
- SchemaDefinition
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_selection.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_selection.go
deleted file mode 100644
index 96e8b0bfe96..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_selection.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package ast
-
-import (
- "bytes"
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type SelectionKind int
-
-const (
- SelectionKindUnknown SelectionKind = 18 + iota
- SelectionKindField
- SelectionKindFragmentSpread
- SelectionKindInlineFragment
-)
-
-type SelectionSet struct {
- LBrace position.Position
- RBrace position.Position
- SelectionRefs []int
-}
-
-type Selection struct {
- Kind SelectionKind // one of Field, FragmentSpread, InlineFragment
- Ref int // reference to the actual selection
-}
-
-func (d *Document) PrintSelections(selections []int) (out string) {
- out += "["
- for i, ref := range selections {
- out += fmt.Sprintf("%+v", d.Selections[ref])
- if i != len(selections)-1 {
- out += ","
- }
- }
- out += "]"
- return
-}
-
-func (d *Document) SelectionsBeforeField(field int, selectionSet Node) bool {
- if selectionSet.Kind != NodeKindSelectionSet {
- return false
- }
-
- if len(d.SelectionSets[selectionSet.Ref].SelectionRefs) == 1 {
- return false
- }
-
- for i, j := range d.SelectionSets[selectionSet.Ref].SelectionRefs {
- if d.Selections[j].Kind == SelectionKindField && d.Selections[j].Ref == field {
- return i != 0
- }
- }
-
- return false
-}
-
-func (d *Document) SelectionsAfterField(field int, selectionSet Node) bool {
- if selectionSet.Kind != NodeKindSelectionSet {
- return false
- }
-
- if len(d.SelectionSets[selectionSet.Ref].SelectionRefs) == 1 {
- return false
- }
-
- for i, j := range d.SelectionSets[selectionSet.Ref].SelectionRefs {
- if d.Selections[j].Kind == SelectionKindField && d.Selections[j].Ref == field {
- return i != len(d.SelectionSets[selectionSet.Ref].SelectionRefs)-1
- }
- }
-
- return false
-}
-
-func (d *Document) SelectionsAfterInlineFragment(inlineFragment int, selectionSet Node) bool {
- if selectionSet.Kind != NodeKindSelectionSet {
- return false
- }
-
- if len(d.SelectionSets[selectionSet.Ref].SelectionRefs) == 1 {
- return false
- }
-
- for i, j := range d.SelectionSets[selectionSet.Ref].SelectionRefs {
- if d.Selections[j].Kind == SelectionKindInlineFragment && d.Selections[j].Ref == inlineFragment {
- return i != len(d.SelectionSets[selectionSet.Ref].SelectionRefs)-1
- }
- }
-
- return false
-}
-
-func (d *Document) AddSelectionSet() Node {
- d.SelectionSets = append(d.SelectionSets, SelectionSet{SelectionRefs: d.Refs[d.NextRefIndex()][:0]})
- return Node{
- Kind: NodeKindSelectionSet,
- Ref: len(d.SelectionSets) - 1,
- }
-}
-
-func (d *Document) AddSelection(set int, selection Selection) {
- d.Selections = append(d.Selections, selection)
- d.SelectionSets[set].SelectionRefs = append(d.SelectionSets[set].SelectionRefs, len(d.Selections)-1)
-}
-
-func (d *Document) EmptySelectionSet(ref int) {
- d.SelectionSets[ref].SelectionRefs = d.SelectionSets[ref].SelectionRefs[:0]
-}
-
-func (d *Document) AppendSelectionSet(ref int, appendRef int) {
- d.SelectionSets[ref].SelectionRefs = append(d.SelectionSets[ref].SelectionRefs, d.SelectionSets[appendRef].SelectionRefs...)
-}
-
-func (d *Document) ReplaceSelectionOnSelectionSet(ref, replace, with int) {
- d.SelectionSets[ref].SelectionRefs = append(d.SelectionSets[ref].SelectionRefs[:replace], append(d.SelectionSets[with].SelectionRefs, d.SelectionSets[ref].SelectionRefs[replace+1:]...)...)
-}
-
-func (d *Document) RemoveFromSelectionSet(ref int, index int) {
- d.SelectionSets[ref].SelectionRefs = append(d.SelectionSets[ref].SelectionRefs[:index], d.SelectionSets[ref].SelectionRefs[index+1:]...)
-}
-
-func (d *Document) SelectionSetHasFieldSelectionWithNameOrAliasBytes(set int, nameOrAlias []byte) bool {
- for _, i := range d.SelectionSets[set].SelectionRefs {
- if d.Selections[i].Kind != SelectionKindField {
- continue
- }
- field := d.Selections[i].Ref
- fieldName := d.FieldNameBytes(field)
- if bytes.Equal(fieldName, nameOrAlias) {
- return true
- }
- if !d.FieldAliasIsDefined(field) {
- continue
- }
- fieldAlias := d.FieldAliasBytes(field)
- if bytes.Equal(fieldAlias, nameOrAlias) {
- return true
- }
- }
- return false
-}
-
-func (d *Document) SelectionSetHasFieldSelectionWithNameOrAliasString(set int, nameOrAlias string) bool {
- return d.SelectionSetHasFieldSelectionWithNameOrAliasBytes(set, unsafebytes.StringToBytes(nameOrAlias))
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_string.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_string.go
deleted file mode 100644
index 74d7ec4d725..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_string.go
+++ /dev/null
@@ -1,160 +0,0 @@
-// Code generated by "stringer -type=OperationType,ValueKind,TypeKind,SelectionKind,NodeKind,PathKind -output ast_string.go"; DO NOT EDIT.
-
-package ast
-
-import "strconv"
-
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[OperationTypeUnknown-0]
- _ = x[OperationTypeQuery-1]
- _ = x[OperationTypeMutation-2]
- _ = x[OperationTypeSubscription-3]
-}
-
-const _OperationType_name = "OperationTypeUnknownOperationTypeQueryOperationTypeMutationOperationTypeSubscription"
-
-var _OperationType_index = [...]uint8{0, 20, 38, 59, 84}
-
-func (i OperationType) String() string {
- if i < 0 || i >= OperationType(len(_OperationType_index)-1) {
- return "OperationType(" + strconv.FormatInt(int64(i), 10) + ")"
- }
- return _OperationType_name[_OperationType_index[i]:_OperationType_index[i+1]]
-}
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[ValueKindUnknown-4]
- _ = x[ValueKindString-5]
- _ = x[ValueKindBoolean-6]
- _ = x[ValueKindInteger-7]
- _ = x[ValueKindFloat-8]
- _ = x[ValueKindVariable-9]
- _ = x[ValueKindNull-10]
- _ = x[ValueKindList-11]
- _ = x[ValueKindObject-12]
- _ = x[ValueKindEnum-13]
-}
-
-const _ValueKind_name = "ValueKindUnknownValueKindStringValueKindBooleanValueKindIntegerValueKindFloatValueKindVariableValueKindNullValueKindListValueKindObjectValueKindEnum"
-
-var _ValueKind_index = [...]uint8{0, 16, 31, 47, 63, 77, 94, 107, 120, 135, 148}
-
-func (i ValueKind) String() string {
- i -= 4
- if i < 0 || i >= ValueKind(len(_ValueKind_index)-1) {
- return "ValueKind(" + strconv.FormatInt(int64(i+4), 10) + ")"
- }
- return _ValueKind_name[_ValueKind_index[i]:_ValueKind_index[i+1]]
-}
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[TypeKindUnknown-14]
- _ = x[TypeKindNamed-15]
- _ = x[TypeKindList-16]
- _ = x[TypeKindNonNull-17]
-}
-
-const _TypeKind_name = "TypeKindUnknownTypeKindNamedTypeKindListTypeKindNonNull"
-
-var _TypeKind_index = [...]uint8{0, 15, 28, 40, 55}
-
-func (i TypeKind) String() string {
- i -= 14
- if i < 0 || i >= TypeKind(len(_TypeKind_index)-1) {
- return "TypeKind(" + strconv.FormatInt(int64(i+14), 10) + ")"
- }
- return _TypeKind_name[_TypeKind_index[i]:_TypeKind_index[i+1]]
-}
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[SelectionKindUnknown-18]
- _ = x[SelectionKindField-19]
- _ = x[SelectionKindFragmentSpread-20]
- _ = x[SelectionKindInlineFragment-21]
-}
-
-const _SelectionKind_name = "SelectionKindUnknownSelectionKindFieldSelectionKindFragmentSpreadSelectionKindInlineFragment"
-
-var _SelectionKind_index = [...]uint8{0, 20, 38, 65, 92}
-
-func (i SelectionKind) String() string {
- i -= 18
- if i < 0 || i >= SelectionKind(len(_SelectionKind_index)-1) {
- return "SelectionKind(" + strconv.FormatInt(int64(i+18), 10) + ")"
- }
- return _SelectionKind_name[_SelectionKind_index[i]:_SelectionKind_index[i+1]]
-}
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[NodeKindUnknown-22]
- _ = x[NodeKindSchemaDefinition-23]
- _ = x[NodeKindSchemaExtension-24]
- _ = x[NodeKindObjectTypeDefinition-25]
- _ = x[NodeKindObjectTypeExtension-26]
- _ = x[NodeKindInterfaceTypeDefinition-27]
- _ = x[NodeKindInterfaceTypeExtension-28]
- _ = x[NodeKindUnionTypeDefinition-29]
- _ = x[NodeKindUnionTypeExtension-30]
- _ = x[NodeKindUnionMemberType-31]
- _ = x[NodeKindEnumTypeDefinition-32]
- _ = x[NodeKindEnumValueDefinition-33]
- _ = x[NodeKindEnumTypeExtension-34]
- _ = x[NodeKindInputObjectTypeDefinition-35]
- _ = x[NodeKindInputValueDefinition-36]
- _ = x[NodeKindInputObjectTypeExtension-37]
- _ = x[NodeKindScalarTypeDefinition-38]
- _ = x[NodeKindScalarTypeExtension-39]
- _ = x[NodeKindDirectiveDefinition-40]
- _ = x[NodeKindOperationDefinition-41]
- _ = x[NodeKindSelectionSet-42]
- _ = x[NodeKindField-43]
- _ = x[NodeKindFieldDefinition-44]
- _ = x[NodeKindFragmentSpread-45]
- _ = x[NodeKindInlineFragment-46]
- _ = x[NodeKindFragmentDefinition-47]
- _ = x[NodeKindArgument-48]
- _ = x[NodeKindDirective-49]
- _ = x[NodeKindVariableDefinition-50]
-}
-
-const _NodeKind_name = "NodeKindUnknownNodeKindSchemaDefinitionNodeKindSchemaExtensionNodeKindObjectTypeDefinitionNodeKindObjectTypeExtensionNodeKindInterfaceTypeDefinitionNodeKindInterfaceTypeExtensionNodeKindUnionTypeDefinitionNodeKindUnionTypeExtensionNodeKindUnionMemberTypeNodeKindEnumTypeDefinitionNodeKindEnumValueDefinitionNodeKindEnumTypeExtensionNodeKindInputObjectTypeDefinitionNodeKindInputValueDefinitionNodeKindInputObjectTypeExtensionNodeKindScalarTypeDefinitionNodeKindScalarTypeExtensionNodeKindDirectiveDefinitionNodeKindOperationDefinitionNodeKindSelectionSetNodeKindFieldNodeKindFieldDefinitionNodeKindFragmentSpreadNodeKindInlineFragmentNodeKindFragmentDefinitionNodeKindArgumentNodeKindDirectiveNodeKindVariableDefinition"
-
-var _NodeKind_index = [...]uint16{0, 15, 39, 62, 90, 117, 148, 178, 205, 231, 254, 280, 307, 332, 365, 393, 425, 453, 480, 507, 534, 554, 567, 590, 612, 634, 660, 676, 693, 719}
-
-func (i NodeKind) String() string {
- i -= 22
- if i < 0 || i >= NodeKind(len(_NodeKind_index)-1) {
- return "NodeKind(" + strconv.FormatInt(int64(i+22), 10) + ")"
- }
- return _NodeKind_name[_NodeKind_index[i]:_NodeKind_index[i+1]]
-}
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[UnknownPathKind-0]
- _ = x[ArrayIndex-1]
- _ = x[FieldName-2]
-}
-
-const _PathKind_name = "UnknownPathKindArrayIndexFieldName"
-
-var _PathKind_index = [...]uint8{0, 15, 25, 34}
-
-func (i PathKind) String() string {
- if i < 0 || i >= PathKind(len(_PathKind_index)-1) {
- return "PathKind(" + strconv.FormatInt(int64(i), 10) + ")"
- }
- return _PathKind_name[_PathKind_index[i]:_PathKind_index[i+1]]
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_type.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_type.go
deleted file mode 100644
index 2b4c8ccdabd..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_type.go
+++ /dev/null
@@ -1,211 +0,0 @@
-package ast
-
-import (
- "bytes"
- "io"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type TypeKind int
-
-const (
- TypeKindUnknown TypeKind = 14 + iota
- TypeKindNamed
- TypeKindList
- TypeKindNonNull
-)
-
-type Type struct {
- TypeKind TypeKind // one of Named,List,NonNull
- Name ByteSliceReference // e.g. String (only on NamedType)
- Open position.Position // [ (only on ListType)
- Close position.Position // ] (only on ListType)
- Bang position.Position // ! (only on NonNullType)
- OfType int
-}
-
-func (d *Document) TypeNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.Types[ref].Name)
-}
-
-func (d *Document) TypeNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.Types[ref].Name))
-}
-
-func (d *Document) PrintType(ref int, w io.Writer) error {
- switch d.Types[ref].TypeKind {
- case TypeKindNonNull:
- err := d.PrintType(d.Types[ref].OfType, w)
- if err != nil {
- return err
- }
- _, err = w.Write(literal.BANG)
- return err
- case TypeKindNamed:
- _, err := w.Write(d.Input.ByteSlice(d.Types[ref].Name))
- return err
- case TypeKindList:
- _, err := w.Write(literal.LBRACK)
- if err != nil {
- return err
- }
- err = d.PrintType(d.Types[ref].OfType, w)
- if err != nil {
- return err
- }
- _, err = w.Write(literal.RBRACK)
- return err
- }
- return nil
-}
-
-func (d *Document) PrintTypeBytes(ref int, buf []byte) ([]byte, error) {
- if buf == nil {
- buf = make([]byte, 0, 24)
- }
- b := bytes.NewBuffer(buf)
- err := d.PrintType(ref, b)
- return b.Bytes(), err
-}
-
-func (d *Document) AddType(t Type) (ref int) {
- d.Types = append(d.Types, t)
- return len(d.Types) - 1
-}
-
-func (d *Document) AddNamedType(name []byte) (ref int) {
- nameRef := d.Input.AppendInputBytes(name)
- d.Types = append(d.Types, Type{
- TypeKind: TypeKindNamed,
- Name: nameRef,
- })
- return len(d.Types) - 1
-}
-
-func (d *Document) AddNonNullNamedType(name []byte) (ref int) {
- namedRef := d.AddNamedType(name)
- d.Types = append(d.Types, Type{
- TypeKind: TypeKindNonNull,
- OfType: namedRef,
- })
- return len(d.Types) - 1
-}
-
-func (d *Document) TypesAreEqualDeep(left int, right int) bool {
- for {
- if left == -1 || right == -1 {
- return false
- }
- if d.Types[left].TypeKind != d.Types[right].TypeKind {
- return false
- }
- if d.Types[left].TypeKind == TypeKindNamed {
- leftName := d.TypeNameBytes(left)
- rightName := d.TypeNameBytes(right)
- return bytes.Equal(leftName, rightName)
- }
- left = d.Types[left].OfType
- right = d.Types[right].OfType
- }
-}
-
-func (d *Document) TypeIsScalar(ref int, definition *Document) bool {
- switch d.Types[ref].TypeKind {
- case TypeKindNamed:
- typeName := d.TypeNameBytes(ref)
- node, _ := definition.Index.FirstNodeByNameBytes(typeName)
- return node.Kind == NodeKindScalarTypeDefinition
- case TypeKindNonNull:
- return d.TypeIsScalar(d.Types[ref].OfType, definition)
- }
- return false
-}
-
-func (d *Document) TypeIsNonNull(ref int) bool {
- return d.Types[ref].TypeKind == TypeKindNonNull
-}
-
-func (d *Document) TypeIsList(ref int) bool {
- switch d.Types[ref].TypeKind {
- case TypeKindList:
- return true
- case TypeKindNonNull:
- return d.TypeIsList(d.Types[ref].OfType)
- default:
- return false
- }
-}
-
-func (d *Document) TypesAreCompatibleDeep(left int, right int) bool {
- for {
- if left == -1 || right == -1 {
- return false
- }
- if d.Types[left].TypeKind != d.Types[right].TypeKind {
- return false
- }
- if d.Types[left].TypeKind == TypeKindNamed {
- leftName := d.TypeNameBytes(left)
- rightName := d.TypeNameBytes(right)
- if bytes.Equal(leftName, rightName) {
- return true
- }
- leftNode, _ := d.Index.FirstNodeByNameBytes(leftName)
- rightNode, _ := d.Index.FirstNodeByNameBytes(rightName)
- if leftNode.Kind == rightNode.Kind {
- return false
- }
- if leftNode.Kind == NodeKindInterfaceTypeDefinition && rightNode.Kind == NodeKindObjectTypeDefinition {
- return d.NodeImplementsInterface(rightNode, leftNode)
- }
- if leftNode.Kind == NodeKindObjectTypeDefinition && rightNode.Kind == NodeKindInterfaceTypeDefinition {
- return d.NodeImplementsInterface(leftNode, rightNode)
- }
- if leftNode.Kind == NodeKindUnionTypeDefinition && rightNode.Kind == NodeKindObjectTypeDefinition {
- return d.NodeIsUnionMember(rightNode, leftNode)
- }
- if leftNode.Kind == NodeKindObjectTypeDefinition && rightNode.Kind == NodeKindUnionTypeDefinition {
- return d.NodeIsUnionMember(leftNode, rightNode)
- }
- return false
- }
- left = d.Types[left].OfType
- right = d.Types[right].OfType
- }
-}
-
-func (d *Document) ResolveTypeNameBytes(ref int) ByteSlice {
- graphqlType := d.Types[ref]
- for graphqlType.TypeKind != TypeKindNamed {
- graphqlType = d.Types[graphqlType.OfType]
- }
- return d.Input.ByteSlice(graphqlType.Name)
-}
-
-func (d *Document) ResolveTypeNameString(ref int) string {
- return unsafebytes.BytesToString(d.ResolveTypeNameBytes(ref))
-}
-
-func (d *Document) TypeValueNeedsQuotes(ref int, definition *Document) bool {
- graphqlType := d.Types[ref]
- switch graphqlType.TypeKind {
- case TypeKindNonNull:
- return d.TypeValueNeedsQuotes(graphqlType.OfType, definition)
- case TypeKindList:
- return false
- case TypeKindNamed:
- typeName := d.Input.ByteSliceString(graphqlType.Name)
- switch typeName {
- case "String", "Date", "ID":
- return true
- default:
- node, _ := definition.Index.FirstNodeByNameStr(typeName)
- return node.Kind == NodeKindEnumTypeDefinition
- }
- default:
- return false
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_union_type_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_union_type_definition.go
deleted file mode 100644
index 692d73a45cc..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_union_type_definition.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// UnionTypeDefinition
-// example:
-// union SearchResult = Photo | Person
-type UnionTypeDefinition struct {
- Description Description // optional, describes union
- UnionLiteral position.Position // union
- Name ByteSliceReference // e.g. SearchResult
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
- Equals position.Position // =
- HasUnionMemberTypes bool
- UnionMemberTypes TypeList // optional, e.g. Photo | Person
-}
-
-func (d *Document) UnionTypeDefinitionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.UnionTypeDefinitions[ref].Name)
-}
-
-func (d *Document) UnionTypeDefinitionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.UnionTypeDefinitions[ref].Name))
-}
-
-func (d *Document) UnionTypeDefinitionDescriptionBytes(ref int) ByteSlice {
- if !d.UnionTypeDefinitions[ref].Description.IsDefined {
- return nil
- }
- return d.Input.ByteSlice(d.UnionTypeDefinitions[ref].Description.Content)
-}
-
-func (d *Document) UnionTypeDefinitionDescriptionString(ref int) string {
- return unsafebytes.BytesToString(d.UnionTypeDefinitionDescriptionBytes(ref))
-}
-
-func (d *Document) UnionMemberTypeIsFirst(ref int, ancestor Node) bool {
- switch ancestor.Kind {
- case NodeKindUnionTypeDefinition:
- return len(d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs) != 0 &&
- d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs[0] == ref
- case NodeKindUnionTypeExtension:
- return len(d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs) != 0 &&
- d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs[0] == ref
- default:
- return false
- }
-}
-
-func (d *Document) UnionMemberTypeIsLast(ref int, ancestor Node) bool {
- switch ancestor.Kind {
- case NodeKindUnionTypeDefinition:
- return len(d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs) != 0 &&
- d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs[len(d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs)-1] == ref
- case NodeKindUnionTypeExtension:
- return len(d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs) != 0 &&
- d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs[len(d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs)-1] == ref
- default:
- return false
- }
-}
-
-func (d *Document) UnionTypeDefinitionHasDirectives(ref int) bool {
- return d.UnionTypeDefinitions[ref].HasDirectives
-}
-
-func (d *Document) AddUnionTypeDefinition(definition UnionTypeDefinition) (ref int) {
- d.UnionTypeDefinitions = append(d.UnionTypeDefinitions, definition)
- return len(d.UnionTypeDefinitions) - 1
-}
-
-func (d *Document) ImportUnionTypeDefinition(name, description string, typeRefs []int) (ref int) {
- definition := UnionTypeDefinition{
- Name: d.Input.AppendInputString(name),
- Description: d.ImportDescription(description),
- HasUnionMemberTypes: len(typeRefs) > 0,
- UnionMemberTypes: TypeList{
- Refs: typeRefs,
- },
- }
-
- ref = d.AddUnionTypeDefinition(definition)
- d.ImportRootNode(ref, NodeKindUnionTypeDefinition)
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_union_type_extension.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_union_type_extension.go
deleted file mode 100644
index 4d2c356acbd..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_union_type_extension.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package ast
-
-import (
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type UnionTypeExtension struct {
- ExtendLiteral position.Position
- UnionTypeDefinition
-}
-
-func (d *Document) UnionTypeExtensionNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.UnionTypeExtensions[ref].Name)
-}
-
-func (d *Document) UnionTypeExtensionNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.UnionTypeExtensions[ref].Name))
-}
-
-func (d *Document) UnionTypeExtensionHasUnionMemberTypes(ref int) bool {
- return d.UnionTypeExtensions[ref].HasUnionMemberTypes
-}
-
-func (d *Document) UnionTypeExtensionHasDirectives(ref int) bool {
- return d.UnionTypeExtensions[ref].HasDirectives
-}
-
-func (d *Document) ExtendUnionTypeDefinitionByUnionTypeExtension(unionTypeDefinitionRef, unionTypeExtensionRef int) {
- if d.UnionTypeExtensionHasDirectives(unionTypeExtensionRef) {
- d.UnionTypeDefinitions[unionTypeDefinitionRef].Directives.Refs = append(d.UnionTypeDefinitions[unionTypeDefinitionRef].Directives.Refs, d.UnionTypeExtensions[unionTypeExtensionRef].Directives.Refs...)
- d.UnionTypeDefinitions[unionTypeDefinitionRef].HasDirectives = true
- }
-
- if d.UnionTypeExtensionHasUnionMemberTypes(unionTypeExtensionRef) {
- d.UnionTypeDefinitions[unionTypeDefinitionRef].UnionMemberTypes.Refs = append(d.UnionTypeDefinitions[unionTypeDefinitionRef].UnionMemberTypes.Refs, d.UnionTypeExtensions[unionTypeExtensionRef].UnionMemberTypes.Refs...)
- d.UnionTypeDefinitions[unionTypeDefinitionRef].HasUnionMemberTypes = true
- }
-
- d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: unionTypeExtensionRef, Kind: NodeKindUnionTypeExtension})
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_boolean_value.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_boolean_value.go
deleted file mode 100644
index f051a3f86bc..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_boolean_value.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package ast
-
-// BooleanValues
-// one of: true, false
-type BooleanValue bool
-
-func (d *Document) BooleanValue(ref int) BooleanValue {
- return d.BooleanValues[ref]
-}
-
-func (d *Document) BooleanValuesAreEqual(left, right int) bool {
- return d.BooleanValue(left) == d.BooleanValue(right)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_enum_value.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_enum_value.go
deleted file mode 100644
index 8940a4fae9f..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_enum_value.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package ast
-
-import "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
-
-// EnumValue
-// example:
-// Name but not true or false or null
-type EnumValue struct {
- Name ByteSliceReference // e.g. ORIGIN
-}
-
-func (d *Document) EnumValueName(ref int) ByteSliceReference {
- return d.EnumValues[ref].Name
-}
-
-func (d *Document) EnumValueNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.EnumValues[ref].Name)
-}
-
-func (d *Document) EnumValueNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.EnumValues[ref].Name))
-}
-
-func (d *Document) EnumValuesAreEqual(left, right int) bool {
- return d.Input.ByteSliceReferenceContentEquals(d.EnumValueName(left), d.EnumValueName(right))
-}
-
-func (d *Document) AddEnumValue(value EnumValue) (ref int) {
- d.EnumValues = append(d.EnumValues, value)
- return len(d.EnumValues) - 1
-}
-
-func (d *Document) ImportEnumValue(name ByteSlice) (ref int) {
- return d.AddEnumValue(EnumValue{
- Name: d.Input.AppendInputBytes(name),
- })
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_float_value.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_float_value.go
deleted file mode 100644
index 4c50f3d60da..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_float_value.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// FloatValue
-// example:
-// 13.37 / -13.37
-type FloatValue struct {
- Negative bool // indicates if the value is negative
- NegativeSign position.Position // optional -
- Raw ByteSliceReference // e.g. 13.37
-}
-
-func (d *Document) FloatValueAsFloat32(ref int) (out float32) {
- in := d.Input.ByteSlice(d.FloatValues[ref].Raw)
- out = unsafebytes.BytesToFloat32(in)
- if d.FloatValues[ref].Negative {
- out = -out
- }
- return
-}
-
-func (d *Document) FloatValueIsNegative(ref int) bool {
- return d.FloatValues[ref].Negative
-}
-
-func (d *Document) FloatValueRaw(ref int) ByteSlice {
- return d.Input.ByteSlice(d.FloatValues[ref].Raw)
-}
-
-func (d *Document) FloatValuesAreEqual(left, right int) bool {
- return d.FloatValueIsNegative(left) == d.FloatValueIsNegative(right) &&
- bytes.Equal(d.FloatValueRaw(left), d.FloatValueRaw(right))
-}
-
-func (d *Document) AddFloatValue(value FloatValue) (ref int) {
- d.FloatValues = append(d.FloatValues, value)
- return len(d.FloatValues) - 1
-}
-
-func (d *Document) ImportFloatValue(raw ByteSlice, isNegative bool) (ref int) {
- return d.AddFloatValue(FloatValue{
- Negative: isNegative,
- Raw: d.Input.AppendInputBytes(raw),
- })
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_int_value.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_int_value.go
deleted file mode 100644
index 6cf9e90b0c5..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_int_value.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// IntValue
-// example:
-// 123 / -123
-type IntValue struct {
- Negative bool // indicates if the value is negative
- NegativeSign position.Position // optional -
- Raw ByteSliceReference // e.g. 123
-}
-
-func (d *Document) IntValueAsInt(ref int) (out int64) {
- in := d.Input.ByteSlice(d.IntValues[ref].Raw)
- out = unsafebytes.BytesToInt64(in)
- if d.IntValues[ref].Negative {
- out = -out
- }
- return
-}
-
-func (d *Document) IntValue(ref int) IntValue {
- return d.IntValues[ref]
-}
-
-func (d *Document) IntValueIsNegative(ref int) bool {
- return d.IntValues[ref].Negative
-}
-
-func (d *Document) IntValueRaw(ref int) ByteSlice {
- return d.Input.ByteSlice(d.IntValues[ref].Raw)
-}
-
-func (d *Document) IntValuesAreEquals(left, right int) bool {
- return d.IntValueIsNegative(left) == d.IntValueIsNegative(right) &&
- bytes.Equal(d.IntValueRaw(left), d.IntValueRaw(right))
-}
-
-func (d *Document) AddIntValue(value IntValue) (ref int) {
- d.IntValues = append(d.IntValues, value)
- return len(d.IntValues) - 1
-}
-
-func (d *Document) ImportIntValue(raw ByteSlice, isNegative bool) (ref int) {
- return d.AddIntValue(IntValue{
- Negative: isNegative,
- Raw: d.Input.AppendInputBytes(raw),
- })
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_list_value.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_list_value.go
deleted file mode 100644
index 4d2aaba03d4..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_list_value.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package ast
-
-import "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-
-type ListValue struct {
- LBRACK position.Position // [
- Refs []int // Value
- RBRACK position.Position // ]
-}
-
-func (d *Document) ListValuesAreEqual(left, right int) bool {
- leftValues, rightValues := d.ListValues[left].Refs, d.ListValues[right].Refs
- if len(leftValues) != len(rightValues) {
- return false
- }
- for i := 0; i < len(leftValues); i++ {
- left, right = leftValues[i], rightValues[i]
- leftValue, rightValue := d.Value(left), d.Value(right)
- if !d.ValuesAreEqual(leftValue, rightValue) {
- return false
- }
- }
- return true
-}
-
-func (d *Document) AddListValue(value ListValue) (ref int) {
- d.ListValues = append(d.ListValues, value)
- return len(d.ListValues) - 1
-}
-
-func (d *Document) ImportListValue(valueRefs []int) (ref int) {
- return d.AddListValue(ListValue{
- Refs: valueRefs,
- })
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_object_value.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_object_value.go
deleted file mode 100644
index 2ddfb66662e..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_object_value.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package ast
-
-import "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-
-// ObjectValue
-// example:
-// { lon: 12.43, lat: -53.211 }
-type ObjectValue struct {
- LBRACE position.Position
- Refs []int // ObjectField
- RBRACE position.Position
-}
-
-func (d *Document) AddObjectValue(value ObjectValue) (ref int) {
- d.ObjectValues = append(d.ObjectValues, value)
- return len(d.ObjectValues) - 1
-}
-
-func (d *Document) ImportObjectValue(fieldRefs []int) (ref int) {
- return d.AddObjectValue(ObjectValue{
- Refs: fieldRefs,
- })
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_string_value.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_string_value.go
deleted file mode 100644
index 88b5a52568a..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_string_value.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
-)
-
-// StringValue
-// example:
-// "foo"
-type StringValue struct {
- BlockString bool // """foo""" = blockString, "foo" string
- Content ByteSliceReference // e.g. foo
-}
-
-func (d *Document) StringValue(ref int) StringValue {
- return d.StringValues[ref]
-}
-
-func (d *Document) StringValueContentBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.StringValues[ref].Content)
-}
-
-func (d *Document) StringValueContentString(ref int) string {
- return unsafebytes.BytesToString(d.StringValueContentBytes(ref))
-}
-
-func (d *Document) StringValueIsBlockString(ref int) bool {
- return d.StringValues[ref].BlockString
-}
-
-func (d *Document) StringValuesAreEquals(left, right int) bool {
- return d.StringValueIsBlockString(left) == d.StringValueIsBlockString(right) &&
- bytes.Equal(d.StringValueContentBytes(left), d.StringValueContentBytes(right))
-}
-
-func (d *Document) AddStringValue(value StringValue) (ref int) {
- d.StringValues = append(d.StringValues, value)
- return len(d.StringValues) - 1
-}
-
-func (d *Document) ImportStringValue(raw ByteSlice, isBlockString bool) (ref int) {
- return d.AddStringValue(StringValue{
- BlockString: isBlockString,
- Content: d.Input.AppendInputBytes(raw),
- })
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_variable_value.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_variable_value.go
deleted file mode 100644
index 4b2477a3d0b..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_val_variable_value.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// VariableValue
-// example:
-// $devicePicSize
-type VariableValue struct {
- Dollar position.Position // $
- Name ByteSliceReference // e.g. devicePicSize
-}
-
-func (d *Document) VariableValueNameBytes(ref int) ByteSlice {
- return d.Input.ByteSlice(d.VariableValues[ref].Name)
-}
-
-func (d *Document) VariableValueNameString(ref int) string {
- return unsafebytes.BytesToString(d.Input.ByteSlice(d.VariableValues[ref].Name))
-}
-
-func (d *Document) VariableValuesAreEqual(left, right int) bool {
- return bytes.Equal(d.VariableValueNameBytes(left), d.VariableValueNameBytes(right))
-}
-
-func (d *Document) AddVariableValue(value VariableValue) (ref int) {
- d.VariableValues = append(d.VariableValues, value)
- return len(d.VariableValues) - 1
-}
-
-func (d *Document) ImportVariableValue(name ByteSlice) (ref int) {
- return d.AddVariableValue(VariableValue{
- Name: d.Input.AppendInputBytes(name),
- })
-}
-
-func (d *Document) AddVariableValueArgument(argName, variableName []byte) (variableValueRef, argRef int) {
- variable := VariableValue{
- Name: d.Input.AppendInputBytes(variableName),
- }
- d.VariableValues = append(d.VariableValues, variable)
- variableValueRef = len(d.VariableValues) - 1
- arg := Argument{
- Name: d.Input.AppendInputBytes(argName),
- Value: Value{
- Kind: ValueKindVariable,
- Ref: variableValueRef,
- },
- }
- d.Arguments = append(d.Arguments, arg)
- argRef = len(d.Arguments) - 1
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_value.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_value.go
deleted file mode 100644
index 78e553b7ab1..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_value.go
+++ /dev/null
@@ -1,228 +0,0 @@
-package ast
-
-import (
- "bytes"
- "fmt"
- "io"
-
- "github.com/tidwall/sjson"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/quotes"
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type ValueKind int
-
-const (
- ValueKindUnknown ValueKind = 4 + iota
- ValueKindString
- ValueKindBoolean
- ValueKindInteger
- ValueKindFloat
- ValueKindVariable
- ValueKindNull
- ValueKindList
- ValueKindObject
- ValueKindEnum
-)
-
-type Value struct {
- Kind ValueKind // e.g. 100 or "Bar"
- Ref int
-}
-
-func (d *Document) ValueContentBytes(value Value) ByteSlice {
- switch value.Kind {
- case ValueKindEnum:
- return d.EnumValueNameBytes(value.Ref)
- case ValueKindString:
- return d.StringValueContentBytes(value.Ref)
- case ValueKindInteger:
- return d.IntValueRaw(value.Ref)
- case ValueKindFloat:
- return d.FloatValueRaw(value.Ref)
- }
- panic(fmt.Errorf("ValueContentBytes not implemented for ValueKind: %s", value.Kind))
-}
-
-func (d *Document) ValueContentString(value Value) string {
- return unsafebytes.BytesToString(d.ValueContentBytes(value))
-}
-
-func (d *Document) ValueToJSON(value Value) ([]byte, error) {
- switch value.Kind {
- case ValueKindNull:
- return literal.NULL, nil
- case ValueKindEnum:
- return quotes.WrapBytes(d.EnumValueNameBytes(value.Ref)), nil
- case ValueKindInteger:
- intValueBytes := d.IntValueRaw(value.Ref)
- if d.IntValueIsNegative(value.Ref) {
- return append(literal.SUB, intValueBytes...), nil
- }
- return intValueBytes, nil
- case ValueKindFloat:
- floatValueBytes := d.FloatValueRaw(value.Ref)
- if d.FloatValueIsNegative(value.Ref) {
- return append(literal.SUB, floatValueBytes...), nil
- }
- return floatValueBytes, nil
- case ValueKindBoolean:
- if value.Ref == 0 {
- return literal.FALSE, nil
- }
- return literal.TRUE, nil
- case ValueKindString:
- return quotes.WrapBytes(d.StringValueContentBytes(value.Ref)), nil
- case ValueKindList:
- out := []byte("[]")
- for _, i := range d.ListValues[value.Ref].Refs {
- item, err := d.ValueToJSON(d.Values[i])
- if err != nil {
- return nil, err
- }
- out, err = sjson.SetRawBytes(out, "-1", item)
- if err != nil {
- return nil, err
- }
- }
- return out, nil
- case ValueKindObject:
- out := []byte("{}")
- for i := len(d.ObjectValues[value.Ref].Refs) - 1; i >= 0; i-- {
- ref := d.ObjectValues[value.Ref].Refs[i]
- fieldNameString := d.ObjectFieldNameString(ref)
- fieldValueBytes, err := d.ValueToJSON(d.ObjectFieldValue(ref))
- if err != nil {
- return nil, err
- }
- out, err = sjson.SetRawBytes(out, fieldNameString, fieldValueBytes)
- if err != nil {
- return nil, err
- }
- }
- return out, nil
- default:
- return nil, fmt.Errorf("ValueToJSON: not implemented for kind: %s", value.Kind.String())
- }
-}
-
-// nolint
-func (d *Document) PrintValue(value Value, w io.Writer) (err error) {
- switch value.Kind {
- case ValueKindBoolean:
- if d.BooleanValues[value.Ref] {
- _, err = w.Write(literal.TRUE)
- } else {
- _, err = w.Write(literal.FALSE)
- }
- case ValueKindString:
- _, err = w.Write(literal.QUOTE)
- _, err = w.Write(d.Input.ByteSlice(d.StringValues[value.Ref].Content))
- _, err = w.Write(literal.QUOTE)
- case ValueKindInteger:
- if d.IntValues[value.Ref].Negative {
- _, err = w.Write(literal.SUB)
- }
- _, err = w.Write(d.Input.ByteSlice(d.IntValues[value.Ref].Raw))
- case ValueKindFloat:
- if d.FloatValues[value.Ref].Negative {
- _, err = w.Write(literal.SUB)
- }
- _, err = w.Write(d.Input.ByteSlice(d.FloatValues[value.Ref].Raw))
- case ValueKindVariable:
- _, err = w.Write(literal.DOLLAR)
- _, err = w.Write(d.Input.ByteSlice(d.VariableValues[value.Ref].Name))
- case ValueKindNull:
- _, err = w.Write(literal.NULL)
- case ValueKindList:
- _, err = w.Write(literal.LBRACK)
- for i, j := range d.ListValues[value.Ref].Refs {
- err = d.PrintValue(d.Value(j), w)
- if err != nil {
- return
- }
- if i != len(d.ListValues[value.Ref].Refs)-1 {
- _, err = w.Write(literal.COMMA)
- }
- }
- _, err = w.Write(literal.RBRACK)
- case ValueKindObject:
- _, err = w.Write(literal.LBRACE)
- for i, j := range d.ObjectValues[value.Ref].Refs {
- _, err = w.Write(d.ObjectFieldNameBytes(j))
- if err != nil {
- return
- }
- _, err = w.Write(literal.COLON)
- if err != nil {
- return
- }
- _, err = w.Write(literal.SPACE)
- if err != nil {
- return
- }
- err = d.PrintValue(d.ObjectFieldValue(j), w)
- if err != nil {
- return
- }
- if i != len(d.ObjectValues[value.Ref].Refs)-1 {
- _, err = w.Write(literal.COMMA)
- if err != nil {
- return
- }
- }
- }
- _, err = w.Write(literal.RBRACE)
- case ValueKindEnum:
- _, err = w.Write(d.Input.ByteSlice(d.EnumValues[value.Ref].Name))
- }
- return
-}
-
-func (d *Document) PrintValueBytes(value Value, buf []byte) ([]byte, error) {
- if buf == nil {
- buf = make([]byte, 0, 24)
- }
- b := bytes.NewBuffer(buf)
- err := d.PrintValue(value, b)
- return b.Bytes(), err
-}
-
-func (d *Document) Value(ref int) Value {
- return d.Values[ref]
-}
-
-func (d *Document) ValuesAreEqual(left, right Value) bool {
- if left.Kind != right.Kind {
- return false
- }
- switch left.Kind {
- case ValueKindString:
- return d.StringValuesAreEquals(left.Ref, right.Ref)
- case ValueKindBoolean:
- return d.BooleanValuesAreEqual(left.Ref, right.Ref)
- case ValueKindInteger:
- return d.IntValuesAreEquals(left.Ref, right.Ref)
- case ValueKindFloat:
- return d.FloatValuesAreEqual(left.Ref, right.Ref)
- case ValueKindVariable:
- return d.VariableValuesAreEqual(left.Ref, right.Ref)
- case ValueKindNull:
- return true
- case ValueKindList:
- return d.ListValuesAreEqual(left.Ref, right.Ref)
- case ValueKindObject:
- return d.ObjectValuesAreEqual(left.Ref, right.Ref)
- case ValueKindEnum:
- return d.EnumValuesAreEqual(left.Ref, right.Ref)
- default:
- return false
- }
-}
-
-func (d *Document) AddValue(value Value) (ref int) {
- d.Values = append(d.Values, value)
- return len(d.Values) - 1
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_variable_definition.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_variable_definition.go
deleted file mode 100644
index f71fd640fea..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/ast_variable_definition.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type VariableDefinitionList struct {
- LPAREN position.Position // (
- Refs []int // VariableDefinition
- RPAREN position.Position // )
-}
-
-// VariableDefinition
-// example:
-// $devicePicSize: Int = 100 @small
-type VariableDefinition struct {
- VariableValue Value // $ Name
- Colon position.Position // :
- Type int // e.g. String
- DefaultValue DefaultValue // optional, e.g. = "Default"
- HasDirectives bool
- Directives DirectiveList // optional, e.g. @foo
-}
-
-func (d *Document) VariableDefinitionNameBytes(ref int) ByteSlice {
- return d.VariableValueNameBytes(d.VariableDefinitions[ref].VariableValue.Ref)
-}
-
-func (d *Document) VariableDefinitionByNameAndOperation(operationDefinition int, name ByteSlice) (definition int, exists bool) {
- if !d.OperationDefinitions[operationDefinition].HasVariableDefinitions {
- return -1, false
- }
- for _, i := range d.OperationDefinitions[operationDefinition].VariableDefinitions.Refs {
- definitionName := d.VariableValueNameBytes(d.VariableDefinitions[i].VariableValue.Ref)
- if bytes.Equal(name, definitionName) {
- return i, true
- }
- }
- return -1, false
-}
-
-func (d *Document) VariableDefinitionsBefore(variableDefinition int) bool {
- for i := range d.OperationDefinitions {
- for j, k := range d.OperationDefinitions[i].VariableDefinitions.Refs {
- if k == variableDefinition {
- return j != 0
- }
- }
- }
- return false
-}
-
-func (d *Document) VariableDefinitionsAfter(variableDefinition int) bool {
- for i := range d.OperationDefinitions {
- for j, k := range d.OperationDefinitions[i].VariableDefinitions.Refs {
- if k == variableDefinition {
- return j != len(d.OperationDefinitions[i].VariableDefinitions.Refs)-1
- }
- }
- }
- return false
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/directive_location.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/directive_location.go
deleted file mode 100644
index 503c1122dc8..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/directive_location.go
+++ /dev/null
@@ -1,162 +0,0 @@
-//go:generate stringer -type=DirectiveLocation -output directive_location_string.go
-
-package ast
-
-import (
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type DirectiveLocation int
-
-const (
- DirectiveLocationUnknown DirectiveLocation = iota
- ExecutableDirectiveLocationQuery
- ExecutableDirectiveLocationMutation
- ExecutableDirectiveLocationSubscription
- ExecutableDirectiveLocationField
- ExecutableDirectiveLocationFragmentDefinition
- ExecutableDirectiveLocationFragmentSpread
- ExecutableDirectiveLocationInlineFragment
- ExecutableDirectiveLocationVariableDefinition
-
- TypeSystemDirectiveLocationSchema
- TypeSystemDirectiveLocationScalar
- TypeSystemDirectiveLocationObject
- TypeSystemDirectiveLocationFieldDefinition
- TypeSystemDirectiveLocationArgumentDefinition
- TypeSystemDirectiveLocationInterface
- TypeSystemDirectiveLocationUnion
- TypeSystemDirectiveLocationEnum
- TypeSystemDirectiveLocationEnumValue
- TypeSystemDirectiveLocationInputObject
- TypeSystemDirectiveLocationInputFieldDefinition
-)
-
-var (
- locations = map[string]DirectiveLocation{
- "QUERY": ExecutableDirectiveLocationQuery,
- "MUTATION": ExecutableDirectiveLocationMutation,
- "SUBSCRIPTION": ExecutableDirectiveLocationSubscription,
- "FIELD": ExecutableDirectiveLocationField,
- "FRAGMENT_DEFINITION": ExecutableDirectiveLocationFragmentDefinition,
- "FRAGMENT_SPREAD": ExecutableDirectiveLocationFragmentSpread,
- "INLINE_FRAGMENT": ExecutableDirectiveLocationInlineFragment,
- "VARIABLE_DEFINITION": ExecutableDirectiveLocationVariableDefinition,
- "SCHEMA": TypeSystemDirectiveLocationSchema,
- "SCALAR": TypeSystemDirectiveLocationScalar,
- "OBJECT": TypeSystemDirectiveLocationObject,
- "FIELD_DEFINITION": TypeSystemDirectiveLocationFieldDefinition,
- "ARGUMENT_DEFINITION": TypeSystemDirectiveLocationArgumentDefinition,
- "INTERFACE": TypeSystemDirectiveLocationInterface,
- "UNION": TypeSystemDirectiveLocationUnion,
- "ENUM": TypeSystemDirectiveLocationEnum,
- "ENUM_VALUE": TypeSystemDirectiveLocationEnumValue,
- "INPUT_OBJECT": TypeSystemDirectiveLocationInputObject,
- "INPUT_FIELD_DEFINITION": TypeSystemDirectiveLocationInputFieldDefinition,
- }
-)
-
-type DirectiveLocations struct {
- storage [20]bool
-}
-
-func (d *DirectiveLocations) Get(location DirectiveLocation) bool {
- return d.storage[location]
-}
-
-func (d *DirectiveLocations) Set(location DirectiveLocation) {
- d.storage[location] = true
-}
-
-func (d *DirectiveLocations) Unset(location DirectiveLocation) {
- d.storage[location] = false
-}
-
-func (d *DirectiveLocations) Iterable() DirectiveLocationIterable {
- return DirectiveLocationIterable{
- locations: *d,
- }
-}
-
-func (d *DirectiveLocations) SetFromRaw(bytes []byte) error {
-
- location, exists := locations[string(bytes)]
- if !exists {
- return fmt.Errorf("invalid directive location: %s", string(bytes))
- }
-
- d.Set(location)
-
- return nil
-}
-
-type DirectiveLocationIterable struct {
- locations DirectiveLocations
- current DirectiveLocation
-}
-
-func (d *DirectiveLocationIterable) Next() bool {
- for i := d.current + 1; i < 20; i++ {
- if d.locations.storage[i] {
- d.current = i
- return true
- }
- }
- return false
-}
-
-func (d *DirectiveLocationIterable) Value() DirectiveLocation {
- return d.current
-}
-
-func (d DirectiveLocation) LiteralBytes() ByteSlice {
- switch d {
- case ExecutableDirectiveLocationQuery:
- return literal.LocationQuery
- case ExecutableDirectiveLocationMutation:
- return literal.LocationMutation
- case ExecutableDirectiveLocationSubscription:
- return literal.LocationSubscription
- case ExecutableDirectiveLocationField:
- return literal.LocationField
- case ExecutableDirectiveLocationFragmentDefinition:
- return literal.LocationFragmentDefinition
- case ExecutableDirectiveLocationFragmentSpread:
- return literal.LocationFragmentSpread
- case ExecutableDirectiveLocationInlineFragment:
- return literal.LocationInlineFragment
- case ExecutableDirectiveLocationVariableDefinition:
- return literal.LocationVariableDefinition
- case TypeSystemDirectiveLocationSchema:
- return literal.LocationSchema
- case TypeSystemDirectiveLocationScalar:
- return literal.LocationScalar
- case TypeSystemDirectiveLocationObject:
- return literal.LocationObject
- case TypeSystemDirectiveLocationFieldDefinition:
- return literal.LocationFieldDefinition
- case TypeSystemDirectiveLocationArgumentDefinition:
- return literal.LocationArgumentDefinition
- case TypeSystemDirectiveLocationInterface:
- return literal.LocationInterface
- case TypeSystemDirectiveLocationUnion:
- return literal.LocationUnion
- case TypeSystemDirectiveLocationEnum:
- return literal.LocationEnum
- case TypeSystemDirectiveLocationEnumValue:
- return literal.LocationEnumValue
- case TypeSystemDirectiveLocationInputObject:
- return literal.LocationInputObject
- case TypeSystemDirectiveLocationInputFieldDefinition:
- return literal.LocationInputFieldDefinition
- default:
- return nil
- }
-}
-
-func (d DirectiveLocation) LiteralString() string {
- return unsafebytes.BytesToString(d.LiteralBytes())
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/directive_location_string.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/directive_location_string.go
deleted file mode 100644
index 505cb729df8..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/directive_location_string.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Code generated by "stringer -type=DirectiveLocation"; DO NOT EDIT.
-
-package ast
-
-import "strconv"
-
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[DirectiveLocationUnknown-0]
- _ = x[ExecutableDirectiveLocationQuery-1]
- _ = x[ExecutableDirectiveLocationMutation-2]
- _ = x[ExecutableDirectiveLocationSubscription-3]
- _ = x[ExecutableDirectiveLocationField-4]
- _ = x[ExecutableDirectiveLocationFragmentDefinition-5]
- _ = x[ExecutableDirectiveLocationFragmentSpread-6]
- _ = x[ExecutableDirectiveLocationInlineFragment-7]
- _ = x[ExecutableDirectiveLocationVariableDefinition-8]
- _ = x[TypeSystemDirectiveLocationSchema-9]
- _ = x[TypeSystemDirectiveLocationScalar-10]
- _ = x[TypeSystemDirectiveLocationObject-11]
- _ = x[TypeSystemDirectiveLocationFieldDefinition-12]
- _ = x[TypeSystemDirectiveLocationArgumentDefinition-13]
- _ = x[TypeSystemDirectiveLocationInterface-14]
- _ = x[TypeSystemDirectiveLocationUnion-15]
- _ = x[TypeSystemDirectiveLocationEnum-16]
- _ = x[TypeSystemDirectiveLocationEnumValue-17]
- _ = x[TypeSystemDirectiveLocationInputObject-18]
- _ = x[TypeSystemDirectiveLocationInputFieldDefinition-19]
-}
-
-const _DirectiveLocation_name = "DirectiveLocationUnknownExecutableDirectiveLocationQueryExecutableDirectiveLocationMutationExecutableDirectiveLocationSubscriptionExecutableDirectiveLocationFieldExecutableDirectiveLocationFragmentDefinitionExecutableDirectiveLocationFragmentSpreadExecutableDirectiveLocationInlineFragmentExecutableDirectiveLocationVariableDefinitionTypeSystemDirectiveLocationSchemaTypeSystemDirectiveLocationScalarTypeSystemDirectiveLocationObjectTypeSystemDirectiveLocationFieldDefinitionTypeSystemDirectiveLocationArgumentDefinitionTypeSystemDirectiveLocationInterfaceTypeSystemDirectiveLocationUnionTypeSystemDirectiveLocationEnumTypeSystemDirectiveLocationEnumValueTypeSystemDirectiveLocationInputObjectTypeSystemDirectiveLocationInputFieldDefinition"
-
-var _DirectiveLocation_index = [...]uint16{0, 24, 56, 91, 130, 162, 207, 248, 289, 334, 367, 400, 433, 475, 520, 556, 588, 619, 655, 693, 740}
-
-func (d DirectiveLocation) String() string {
- if d < 0 || d >= DirectiveLocation(len(_DirectiveLocation_index)-1) {
- return "DirectiveLocation(" + strconv.FormatInt(int64(d), 10) + ")"
- }
- return _DirectiveLocation_name[_DirectiveLocation_index[d]:_DirectiveLocation_index[d+1]]
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/index.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/index.go
deleted file mode 100644
index 1910b546514..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/index.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package ast
-
-import "github.com/cespare/xxhash"
-
-// Index is a struct to easily look up objects in a document, e.g. find Nodes (type/interface/union definitions) by name
-type Index struct {
- // QueryTypeName is the name of the query type on the schema Node
- // schema { query: Query }
- QueryTypeName ByteSlice
- // MutationTypeName is the name of the mutation type on the schema Node
- // schema { mutation: Mutation }
- MutationTypeName ByteSlice
- // SubscriptionTypeName is the name of the subscription type on the schema Node
- // schema { subscription: Subscription }
- SubscriptionTypeName ByteSlice
- // nodes is a list of all root nodes in a schema definition
- // The map key is the result of the xxhash algorithm from the Node name.
- nodes map[uint64][]Node
- // ReplacedFragmentSpreads is a list of references (slice indices) of all FragmentSpreads that got replaced during normalization.
- ReplacedFragmentSpreads []int
- // MergedTypeExtensions is a list of Nodes (Node kind + reference) that got merged during type extension merging.
- MergedTypeExtensions []Node
-}
-
-// Reset empties the Index
-func (i *Index) Reset() {
- i.QueryTypeName = i.QueryTypeName[:0]
- i.MutationTypeName = i.MutationTypeName[:0]
- i.SubscriptionTypeName = i.SubscriptionTypeName[:0]
- i.ReplacedFragmentSpreads = i.ReplacedFragmentSpreads[:0]
- i.MergedTypeExtensions = i.MergedTypeExtensions[:0]
- for j := range i.nodes {
- delete(i.nodes, j)
- }
-}
-
-func (i *Index) AddNodeStr(name string, node Node) {
- hash := xxhash.Sum64String(name)
- _, exists := i.nodes[hash]
- if !exists {
- i.nodes[hash] = []Node{node}
- return
- }
- i.nodes[hash] = append(i.nodes[hash], node)
-}
-
-func (i *Index) AddNodeBytes(name []byte, node Node) {
- hash := xxhash.Sum64(name)
- _, exists := i.nodes[hash]
- if !exists {
- i.nodes[hash] = []Node{node}
- return
- }
- i.nodes[hash] = append(i.nodes[hash], node)
-}
-
-func (i *Index) NodesByNameStr(name string) ([]Node, bool) {
- hash := xxhash.Sum64String(name)
- node, exists := i.nodes[hash]
- return node, exists
-}
-
-func (i *Index) FirstNodeByNameStr(name string) (Node, bool) {
- hash := xxhash.Sum64String(name)
- node, exists := i.nodes[hash]
- if !exists || len(node) == 0 {
- return Node{}, false
- }
- return node[0], true
-}
-
-func (i *Index) NodesByNameBytes(name []byte) ([]Node, bool) {
- hash := xxhash.Sum64(name)
- node, exists := i.nodes[hash]
- return node, exists
-}
-
-func (i *Index) FirstNodeByNameBytes(name []byte) (Node, bool) {
- hash := xxhash.Sum64(name)
- node, exists := i.nodes[hash]
- if !exists || len(node) == 0 {
- return Node{}, false
- }
- return node[0], true
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/input.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/input.go
deleted file mode 100644
index ca705f7fe67..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/input.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package ast
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-// Input is a raw graphql document containing the raw input + meta data
-type Input struct {
- // RawBytes is the raw byte input
- RawBytes []byte
- // Length of RawBytes
- Length int
- // InputPosition is the current position in the RawBytes
- InputPosition int
- // TextPosition is the current position within the text (line and character information about the current Tokens)
- TextPosition position.Position
- // Variables are the json encoded variables of the operation
- Variables []byte
-}
-
-// Reset empties the Input
-func (i *Input) Reset() {
- i.RawBytes = i.RawBytes[:0]
- i.Variables = i.Variables[:0]
- i.InputPosition = 0
- i.TextPosition.Reset()
-}
-
-// ResetInputBytes empties the input and sets it to bytes argument
-func (i *Input) ResetInputBytes(bytes []byte) {
- i.Reset()
- i.AppendInputBytes(bytes)
- i.Length = len(i.RawBytes)
-}
-
-// ResetInputString empties the input and sets it to input string.
-func (i *Input) ResetInputString(input string) {
- i.ResetInputBytes([]byte(input))
-}
-
-// AppendInputBytes appends a byte slice to the current input and returns the ByteSliceReference
-func (i *Input) AppendInputBytes(bytes []byte) (ref ByteSliceReference) {
- ref.Start = uint32(len(i.RawBytes))
- i.RawBytes = append(i.RawBytes, bytes...)
- i.Length = len(i.RawBytes)
- ref.End = uint32(len(i.RawBytes))
- return
-}
-
-// AppendInputString appends a string to the current input and returns the ByteSliceReference
-func (i *Input) AppendInputString(input string) ByteSliceReference {
- return i.AppendInputBytes([]byte(input))
-}
-
-// ByteSlice returns the byte slice for a given byte ByteSliceReference
-func (i *Input) ByteSlice(reference ByteSliceReference) ByteSlice {
- return i.RawBytes[reference.Start:reference.End]
-}
-
-// ByteSliceString returns a string for a given ByteSliceReference
-func (i *Input) ByteSliceString(reference ByteSliceReference) string {
- return unsafebytes.BytesToString(i.ByteSlice(reference))
-}
-
-// ByteSliceReferenceContentEquals compares the content of two byte slices and returns true if they are the same
-func (i *Input) ByteSliceReferenceContentEquals(left, right ByteSliceReference) bool {
- if left.Length() != right.Length() {
- return false
- }
- length := int(left.Length())
- for k := 0; k < length; k++ {
- if i.RawBytes[int(left.Start)+k] != i.RawBytes[int(right.Start)+k] {
- return false
- }
- }
- return true
-}
-
-// ByteSlice is an alias for []byte
-type ByteSlice []byte
-
-// Equals compares a ByteSlice to another
-func (b ByteSlice) Equals(another ByteSlice) bool {
- if len(b) != len(another) {
- return false
- }
- return bytes.Equal(b, another)
-}
-
-func (b ByteSlice) String() string {
- return unsafebytes.BytesToString(b)
-}
-
-func (b ByteSlice) MarshalJSON() ([]byte, error) {
- return append(append(literal.QUOTE, b...), literal.QUOTE...), nil
-}
-
-type ByteSlices []ByteSlice
-
-func (b ByteSlices) String() string {
- out := "["
- for i := range b {
- if i != 0 {
- out += ","
- }
- out += string(b[i])
- }
- out += "]"
- return out
-}
-
-type ByteSliceReference struct {
- Start uint32
- End uint32
-}
-
-func (b ByteSliceReference) Length() uint32 {
- return b.End - b.Start
-}
-
-// ByteSliceEquals compares two ByteSliceReferences from different Inputs
-func ByteSliceEquals(left ByteSliceReference, leftInput Input, right ByteSliceReference, rightInput Input) bool {
- if left.Length() != right.Length() {
- return false
- }
- length := int(left.Length())
- for i := 0; i < length; i++ {
- if leftInput.RawBytes[int(left.Start)+i] != rightInput.RawBytes[int(right.Start)+i] {
- return false
- }
- }
- return true
-}
-
-type ByteSliceReferences []ByteSliceReference
-
-func (b ByteSliceReferences) String(input *Input) string {
- out := "["
- for i := range b {
- if i != 0 {
- out += ","
- }
- if b[i].Length() == 0 {
- out += "query"
- } else {
- out += input.ByteSliceString(b[i])
- }
- }
- out += "]"
- return out
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/path.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/path.go
deleted file mode 100644
index 700060aee3b..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/ast/path.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package ast
-
-import (
- "bytes"
- "fmt"
- "strconv"
- "unsafe"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
-)
-
-type PathKind int
-
-const (
- UnknownPathKind PathKind = iota
- ArrayIndex
- FieldName
-)
-
-type PathItem struct {
- Kind PathKind
- ArrayIndex int
- FieldName ByteSlice
-}
-
-type Path []PathItem
-
-func (p Path) Equals(another Path) bool {
- if len(p) != len(another) {
- return false
- }
- for i := range p {
- if p[i].Kind != another[i].Kind {
- return false
- }
- if p[i].Kind == ArrayIndex && p[i].ArrayIndex != another[i].ArrayIndex {
- return false
- } else if !bytes.Equal(p[i].FieldName, another[i].FieldName) {
- return false
- }
- }
- return true
-}
-
-func (p Path) String() string {
- out := "["
- for i := range p {
- if i != 0 {
- out += ","
- }
- switch p[i].Kind {
- case ArrayIndex:
- out += strconv.Itoa(p[i].ArrayIndex)
- case FieldName:
- if len(p[i].FieldName) == 0 {
- out += "query"
- } else {
- out += unsafebytes.BytesToString(p[i].FieldName)
- }
- }
- }
- out += "]"
- return out
-}
-
-func (p Path) DotDelimitedString() string {
- out := ""
- for i := range p {
- if i != 0 {
- out += "."
- }
- switch p[i].Kind {
- case ArrayIndex:
- out += strconv.Itoa(p[i].ArrayIndex)
- case FieldName:
- if len(p[i].FieldName) == 0 {
- out += "query"
- } else {
- out += unsafebytes.BytesToString(p[i].FieldName)
- }
- }
- }
- return out
-}
-
-func (p *PathItem) UnmarshalJSON(data []byte) error {
- if data == nil {
- return fmt.Errorf("data must not be nil")
- }
- if data[0] == '"' && data[len(data)-1] == '"' {
- p.Kind = FieldName
- p.FieldName = data[1 : len(data)-1]
- return nil
- }
- out, err := strconv.ParseInt(*(*string)(unsafe.Pointer(&data)), 10, 64)
- if err != nil {
- return err
- }
- p.Kind = ArrayIndex
- p.ArrayIndex = int(out)
- return nil
-}
-
-func (p PathItem) MarshalJSON() ([]byte, error) {
- switch p.Kind {
- case ArrayIndex:
- return strconv.AppendInt(nil, int64(p.ArrayIndex), 10), nil
- case FieldName:
- return append([]byte("\""), append(p.FieldName, []byte("\"")...)...), nil
- default:
- return nil, fmt.Errorf("cannot marshal unknown PathKind")
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astimport/astimport.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astimport/astimport.go
deleted file mode 100644
index e45a9ad3c30..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astimport/astimport.go
+++ /dev/null
@@ -1,167 +0,0 @@
-// Package astimport can be used to import Nodes manually into an AST.
-//
-// This is useful when an AST should be created manually.
-package astimport
-
-import (
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
-)
-
-// Importer imports Nodes into an existing AST.
-// Always use NewImporter() to create a new Importer.
-type Importer struct {
-}
-
-func (i *Importer) ImportType(ref int, from, to *ast.Document) int {
-
- astType := ast.Type{
- TypeKind: from.Types[ref].TypeKind,
- OfType: -1,
- }
-
- if astType.TypeKind == ast.TypeKindNamed {
- astType.Name = to.Input.AppendInputBytes(from.TypeNameBytes(ref))
- }
-
- if from.Types[ref].OfType != -1 {
- astType.OfType = i.ImportType(from.Types[ref].OfType, from, to)
- }
-
- to.Types = append(to.Types, astType)
- return len(to.Types) - 1
-}
-
-func (i *Importer) ImportValue(fromValue ast.Value, from, to *ast.Document) (value ast.Value) {
- value.Kind = fromValue.Kind
-
- switch fromValue.Kind {
- case ast.ValueKindFloat:
- value.Ref = to.ImportFloatValue(
- from.FloatValueRaw(fromValue.Ref),
- from.FloatValueIsNegative(fromValue.Ref))
-
- case ast.ValueKindInteger:
- value.Ref = to.ImportIntValue(
- from.IntValueRaw(fromValue.Ref),
- from.IntValueIsNegative(fromValue.Ref))
-
- case ast.ValueKindBoolean:
- value.Ref = fromValue.Ref
-
- case ast.ValueKindString:
- value.Ref = to.ImportStringValue(
- from.StringValueContentBytes(fromValue.Ref),
- from.StringValueIsBlockString(fromValue.Ref))
-
- case ast.ValueKindNull:
- // empty case
-
- case ast.ValueKindEnum:
- value.Ref = to.ImportEnumValue(from.EnumValueNameBytes(fromValue.Ref))
-
- case ast.ValueKindVariable:
- value.Ref = to.ImportVariableValue(from.VariableValueNameBytes(fromValue.Ref))
-
- case ast.ValueKindList:
- value.Ref = to.ImportListValue(i.ImportListValues(fromValue.Ref, from, to))
-
- case ast.ValueKindObject:
- value.Ref = to.ImportObjectValue(i.ImportObjectFields(fromValue.Ref, from, to))
-
- default:
- value.Kind = ast.ValueKindUnknown
- fmt.Printf("astimport.Importer.ImportValue: not implemented for ValueKind: %s\n", fromValue.Kind)
- }
- return
-}
-
-func (i *Importer) ImportObjectFields(ref int, from, to *ast.Document) (refs []int) {
- objValue := from.ObjectValues[ref]
-
- for _, fieldRef := range objValue.Refs {
- objectField := from.ObjectFields[fieldRef]
-
- refs = append(refs, to.ImportObjectField(
- from.ObjectFieldNameBytes(fieldRef),
- i.ImportValue(objectField.Value, from, to)))
- }
- return
-}
-
-func (i *Importer) ImportListValues(ref int, from, to *ast.Document) (refs []int) {
- listValue := from.ListValues[ref]
-
- for _, valueRef := range listValue.Refs {
- value := i.ImportValue(from.Values[valueRef], from, to)
- refs = append(refs, to.AddValue(value))
- }
- return
-}
-
-func (i *Importer) ImportArgument(ref int, from, to *ast.Document) int {
- arg := ast.Argument{
- Name: to.Input.AppendInputBytes(from.ArgumentNameBytes(ref)),
- Value: i.ImportValue(from.ArgumentValue(ref), from, to),
- }
- to.Arguments = append(to.Arguments, arg)
- return len(to.Arguments) - 1
-}
-
-func (i *Importer) ImportArguments(refs []int, from, to *ast.Document) []int {
- args := make([]int, len(refs))
- for j, k := range refs {
- args[j] = i.ImportArgument(k, from, to)
- }
- return args
-}
-
-func (i *Importer) ImportVariableDefinition(ref int, from, to *ast.Document) int {
-
- variableDefinition := ast.VariableDefinition{
- VariableValue: i.ImportValue(from.VariableDefinitions[ref].VariableValue, from, to),
- Type: i.ImportType(from.VariableDefinitions[ref].Type, from, to),
- DefaultValue: ast.DefaultValue{
- IsDefined: from.VariableDefinitions[ref].DefaultValue.IsDefined,
- },
- // HasDirectives: false, //TODO: implement import directives
- // Directives: ast.DirectiveList{},
- }
-
- if from.VariableDefinitions[ref].DefaultValue.IsDefined {
- variableDefinition.DefaultValue.Value = i.ImportValue(from.VariableDefinitions[ref].DefaultValue.Value, from, to)
- }
-
- to.VariableDefinitions = append(to.VariableDefinitions, variableDefinition)
- return len(to.VariableDefinitions) - 1
-}
-
-func (i *Importer) ImportVariableDefinitions(refs []int, from, to *ast.Document) []int {
- definitions := make([]int, len(refs))
- for j, k := range refs {
- definitions[j] = i.ImportVariableDefinition(k, from, to)
- }
- return definitions
-}
-
-func (i *Importer) ImportField(ref int, from, to *ast.Document) int {
- field := ast.Field{
- Alias: ast.Alias{
- IsDefined: from.FieldAliasIsDefined(ref),
- },
- Name: to.Input.AppendInputBytes(from.FieldNameBytes(ref)),
- HasArguments: from.FieldHasArguments(ref),
- // HasDirectives: from.FieldHasDirectives(ref), // HasDirectives: false, //TODO: implement import directives
- SelectionSet: -1,
- HasSelections: false,
- }
- if field.Alias.IsDefined {
- field.Alias.Name = to.Input.AppendInputBytes(from.FieldAliasBytes(ref))
- }
- if field.HasArguments {
- field.Arguments.Refs = i.ImportArguments(from.FieldArguments(ref), from, to)
- }
- to.Fields = append(to.Fields, field)
- return len(to.Fields) - 1
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/astnormalization.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/astnormalization.go
deleted file mode 100644
index abd8d8b8598..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/astnormalization.go
+++ /dev/null
@@ -1,152 +0,0 @@
-/*Package astnormalization helps to transform parsed GraphQL AST's into a easier to use structure.
-
-Example
-
-This examples shows how the normalization package helps "simplifying" a GraphQL AST.
-
-Input:
-
- subscription sub {
- ... multipleSubscriptions
- ... on Subscription {
- newMessage {
- body
- sender
- }
- }
- }
- fragment newMessageFields on Message {
- body: body
- sender
- ... on Body {
- body
- }
- }
- fragment multipleSubscriptions on Subscription {
- newMessage {
- body
- sender
- }
- newMessage {
- ... newMessageFields
- }
- newMessage {
- body
- body
- sender
- }
- ... on Subscription {
- newMessage {
- body
- sender
- }
- }
- disallowedSecondRootField
- }
-
-Output:
-
- subscription sub {
- newMessage {
- body
- sender
- }
- disallowedSecondRootField
- }
- fragment newMessageFields on Message {
- body
- sender
- }
- fragment multipleSubscriptions on Subscription {
- newMessage {
- body
- sender
- }
- disallowedSecondRootField
- }
-*/
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-// NormalizeOperation creates a default Normalizer and applies all rules to a given AST
-// In case you're using OperationNormalizer in a hot path you shouldn't be using this function.
-// Create a new OperationNormalizer using NewNormalizer() instead and re-use it.
-func NormalizeOperation(operation, definition *ast.Document, report *operationreport.Report) {
- normalizer := NewNormalizer(false, false)
- normalizer.NormalizeOperation(operation, definition, report)
-}
-
-func NormalizeNamedOperation(operation, definition *ast.Document, operationName []byte, report *operationreport.Report) {
- normalizer := NewNormalizer(true, true)
- normalizer.NormalizeNamedOperation(operation, definition, operationName, report)
-}
-
-type registerNormalizeFunc func(walker *astvisitor.Walker)
-
-type registerNormalizeVariablesFunc func(walker *astvisitor.Walker) *variablesExtractionVisitor
-
-// OperationNormalizer walks a given AST and applies all registered rules
-type OperationNormalizer struct {
- walkers []*astvisitor.Walker
- removeFragmentDefinitions bool
- extractVariables bool
- variablesExtraction *variablesExtractionVisitor
-}
-
-// NewNormalizer creates a new OperationNormalizer and sets up all default rules
-func NewNormalizer(removeFragmentDefinitions, extractVariables bool) *OperationNormalizer {
- normalizer := &OperationNormalizer{
- removeFragmentDefinitions: removeFragmentDefinitions,
- extractVariables: extractVariables,
- }
- normalizer.setupWalkers()
- return normalizer
-}
-
-func (o *OperationNormalizer) setupWalkers() {
- fragmentInline := astvisitor.NewWalker(48)
- fragmentSpreadInline(&fragmentInline)
- directiveIncludeSkip(&fragmentInline)
-
- other := astvisitor.NewWalker(48)
- removeSelfAliasing(&other)
- mergeInlineFragments(&other)
- mergeFieldSelections(&other)
- deduplicateFields(&other)
- if o.extractVariables {
- o.variablesExtraction = extractVariables(&other)
- }
- if o.removeFragmentDefinitions {
- removeFragmentDefinitions(&other)
- }
-
- o.walkers = append(o.walkers, &fragmentInline, &other)
-}
-
-// NormalizeOperation applies all registered rules to the AST
-func (o *OperationNormalizer) NormalizeOperation(operation, definition *ast.Document, report *operationreport.Report) {
- for i := range o.walkers {
- o.walkers[i].Walk(operation, definition, report)
- if report.HasErrors() {
- return
- }
- }
-}
-
-// NormalizeNamedOperation applies all registered rules to one specific named operation in the AST
-func (o *OperationNormalizer) NormalizeNamedOperation(operation, definition *ast.Document, operationName []byte, report *operationreport.Report) {
- if o.variablesExtraction != nil {
- o.variablesExtraction.operationName = operationName
- }
- for i := range o.walkers {
- o.walkers[i].Walk(operation, definition, report)
- if report.HasErrors() {
- return
- }
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/directive_include_skip.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/directive_include_skip.go
deleted file mode 100644
index 104d9472d00..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/directive_include_skip.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package astnormalization
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-func directiveIncludeSkip(walker *astvisitor.Walker) {
- visitor := directiveIncludeSkipVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterDirectiveVisitor(&visitor)
-}
-
-type directiveIncludeSkipVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (d *directiveIncludeSkipVisitor) EnterDocument(operation, definition *ast.Document) {
- d.operation = operation
- d.definition = definition
-}
-
-func (d *directiveIncludeSkipVisitor) EnterDirective(ref int) {
-
- name := d.operation.DirectiveNameBytes(ref)
-
- switch {
- case bytes.Equal(name, literal.INCLUDE):
- d.handleInclude(ref)
- case bytes.Equal(name, literal.SKIP):
- d.handleSkip(ref)
- }
-}
-
-func (d *directiveIncludeSkipVisitor) handleSkip(ref int) {
- if len(d.operation.Directives[ref].Arguments.Refs) != 1 {
- return
- }
- arg := d.operation.Directives[ref].Arguments.Refs[0]
- if !bytes.Equal(d.operation.ArgumentNameBytes(arg), literal.IF) {
- return
- }
- value := d.operation.ArgumentValue(arg)
- if value.Kind != ast.ValueKindBoolean {
- return
- }
- include := d.operation.BooleanValue(value.Ref)
- switch include {
- case false:
- d.operation.RemoveDirectiveFromNode(d.Ancestors[len(d.Ancestors)-1], ref)
- case true:
- if len(d.Ancestors) < 2 {
- return
- }
- d.operation.RemoveNodeFromNode(d.Ancestors[len(d.Ancestors)-1], d.Ancestors[len(d.Ancestors)-2])
- }
-}
-
-func (d *directiveIncludeSkipVisitor) handleInclude(ref int) {
- if len(d.operation.Directives[ref].Arguments.Refs) != 1 {
- return
- }
- arg := d.operation.Directives[ref].Arguments.Refs[0]
- if !bytes.Equal(d.operation.ArgumentNameBytes(arg), literal.IF) {
- return
- }
- value := d.operation.ArgumentValue(arg)
- if value.Kind != ast.ValueKindBoolean {
- return
- }
- include := d.operation.BooleanValue(value.Ref)
- switch include {
- case true:
- d.operation.RemoveDirectiveFromNode(d.Ancestors[len(d.Ancestors)-1], ref)
- case false:
- if len(d.Ancestors) < 2 {
- return
- }
- d.operation.RemoveNodeFromNode(d.Ancestors[len(d.Ancestors)-1], d.Ancestors[len(d.Ancestors)-2])
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/enum_type_extending.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/enum_type_extending.go
deleted file mode 100644
index 84e456414a5..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/enum_type_extending.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func extendEnumTypeDefinition(walker *astvisitor.Walker) {
- visitor := extendEnumTypeDefinitionVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterEnumTypeExtensionVisitor(&visitor)
-}
-
-type extendEnumTypeDefinitionVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
-}
-
-func (e *extendEnumTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
- e.operation = operation
-}
-
-func (e *extendEnumTypeDefinitionVisitor) EnterEnumTypeExtension(ref int) {
-
- nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.EnumTypeExtensionNameBytes(ref))
- if !exists {
- return
- }
-
- for i := range nodes {
- if nodes[i].Kind != ast.NodeKindEnumTypeDefinition {
- continue
- }
- e.operation.ExtendEnumTypeDefinitionByEnumTypeExtension(nodes[i].Ref, ref)
- return
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/field_deduplication.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/field_deduplication.go
deleted file mode 100644
index 65eb486707d..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/field_deduplication.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func deduplicateFields(walker *astvisitor.Walker) {
- visitor := deduplicateFieldsVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterSelectionSetVisitor(&visitor)
-}
-
-type deduplicateFieldsVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
-}
-
-func (d *deduplicateFieldsVisitor) EnterDocument(operation, definition *ast.Document) {
- d.operation = operation
-}
-
-func (d *deduplicateFieldsVisitor) EnterSelectionSet(ref int) {
- if len(d.operation.SelectionSets[ref].SelectionRefs) < 2 {
- return
- }
-
- for a, i := range d.operation.SelectionSets[ref].SelectionRefs {
- if d.operation.Selections[i].Kind != ast.SelectionKindField {
- continue
- }
- left := d.operation.Selections[i].Ref
- if d.operation.Fields[left].HasSelections {
- continue
- }
- for b, j := range d.operation.SelectionSets[ref].SelectionRefs {
- if a == b {
- continue
- }
- if a > b {
- continue
- }
- if d.operation.Selections[j].Kind != ast.SelectionKindField {
- continue
- }
- right := d.operation.Selections[j].Ref
- if d.operation.Fields[right].HasSelections {
- continue
- }
- if d.operation.FieldsAreEqualFlat(left, right) {
- d.operation.RemoveFromSelectionSet(ref, b)
- d.RevisitNode()
- return
- }
- }
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/field_selection_merging.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/field_selection_merging.go
deleted file mode 100644
index cf8dcbcf7a8..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/field_selection_merging.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package astnormalization
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func mergeFieldSelections(walker *astvisitor.Walker) {
- visitor := fieldSelectionMergeVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterSelectionSetVisitor(&visitor)
-}
-
-type fieldSelectionMergeVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
-}
-
-func (f *fieldSelectionMergeVisitor) EnterDocument(operation, definition *ast.Document) {
- f.operation = operation
-}
-
-func (f *fieldSelectionMergeVisitor) fieldsCanMerge(left, right int) bool {
- leftName := f.operation.FieldNameBytes(left)
- rightName := f.operation.FieldNameBytes(right)
- leftAlias := f.operation.FieldAliasBytes(left)
- rightAlias := f.operation.FieldAliasBytes(right)
-
- if !bytes.Equal(leftName, rightName) || !bytes.Equal(leftAlias, rightAlias) {
- return false
- }
-
- leftDirectives := f.operation.FieldDirectives(left)
- rightDirectives := f.operation.FieldDirectives(right)
-
- return f.operation.DirectiveSetsAreEqual(leftDirectives, rightDirectives)
-}
-
-func (f *fieldSelectionMergeVisitor) isFieldSelection(ref int) bool {
- return f.operation.Selections[ref].Kind == ast.SelectionKindField
-}
-
-func (f *fieldSelectionMergeVisitor) fieldsHaveSelections(left, right int) bool {
- return f.operation.Fields[left].HasSelections && f.operation.Fields[right].HasSelections
-}
-
-func (f *fieldSelectionMergeVisitor) removeSelection(set, i int) {
- f.operation.SelectionSets[set].SelectionRefs = append(f.operation.SelectionSets[set].SelectionRefs[:i], f.operation.SelectionSets[set].SelectionRefs[i+1:]...)
-}
-
-func (f *fieldSelectionMergeVisitor) mergeFields(left, right int) {
- leftSet := f.operation.Fields[left].SelectionSet
- rightSet := f.operation.Fields[right].SelectionSet
- f.operation.SelectionSets[leftSet].SelectionRefs = append(f.operation.SelectionSets[leftSet].SelectionRefs, f.operation.SelectionSets[rightSet].SelectionRefs...)
- f.operation.Fields[left].Directives.Refs = append(f.operation.Fields[left].Directives.Refs, f.operation.Fields[right].Directives.Refs...)
-}
-
-func (f *fieldSelectionMergeVisitor) EnterSelectionSet(ref int) {
-
- if len(f.operation.SelectionSets[ref].SelectionRefs) < 2 {
- return
- }
-
- for _, leftSelection := range f.operation.SelectionSets[ref].SelectionRefs {
- if !f.isFieldSelection(leftSelection) {
- continue
- }
- leftField := f.operation.Selections[leftSelection].Ref
- for i, rightSelection := range f.operation.SelectionSets[ref].SelectionRefs {
- if !f.isFieldSelection(rightSelection) {
- continue
- }
- if leftSelection == rightSelection {
- continue
- }
- rightField := f.operation.Selections[rightSelection].Ref
- if !f.fieldsHaveSelections(leftField, rightField) {
- continue
- }
- if !f.fieldsCanMerge(leftField, rightField) {
- continue
- }
- f.removeSelection(ref, i)
- f.mergeFields(leftField, rightField)
- f.RevisitNode()
- return
- }
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/fragment_definition_removal.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/fragment_definition_removal.go
deleted file mode 100644
index 5606a52c172..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/fragment_definition_removal.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-type FragmentDefinitionRemoval struct {
-}
-
-func removeFragmentDefinitions(walker *astvisitor.Walker) {
- visitor := removeFragmentDefinitionsVisitor{}
- walker.RegisterLeaveDocumentVisitor(visitor)
-}
-
-type removeFragmentDefinitionsVisitor struct {
-}
-
-func (r removeFragmentDefinitionsVisitor) LeaveDocument(operation, definition *ast.Document) {
- for i := range operation.RootNodes {
- if operation.RootNodes[i].Kind == ast.NodeKindFragmentDefinition {
- operation.RootNodes[i].Kind = ast.NodeKindUnknown
- }
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/fragment_spread_inlining.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/fragment_spread_inlining.go
deleted file mode 100644
index 3a8e1a8991a..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/fragment_spread_inlining.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package astnormalization
-
-import (
- "bytes"
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/asttransform"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-func fragmentSpreadInline(walker *astvisitor.Walker) {
- visitor := fragmentSpreadInlineVisitor{
- Walker: walker,
- }
- walker.RegisterDocumentVisitor(&visitor)
- walker.RegisterEnterFragmentSpreadVisitor(&visitor)
-}
-
-type fragmentSpreadInlineVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
- transformer asttransform.Transformer
- fragmentSpreadDepth FragmentSpreadDepth
- depths Depths
-}
-
-func (f *fragmentSpreadInlineVisitor) EnterDocument(operation, definition *ast.Document) {
- f.transformer.Reset()
- f.depths = f.depths[:0]
- f.operation = operation
- f.definition = definition
-
- f.fragmentSpreadDepth.Get(operation, definition, f.Report, &f.depths)
- if f.Report.HasErrors() {
- f.Stop()
- }
-}
-
-func (f *fragmentSpreadInlineVisitor) LeaveDocument(operation, definition *ast.Document) {
- f.transformer.ApplyTransformations(operation)
-}
-
-func (f *fragmentSpreadInlineVisitor) EnterFragmentSpread(ref int) {
-
- parentTypeName := f.definition.NodeNameBytes(f.EnclosingTypeDefinition)
-
- fragmentDefinitionRef, exists := f.operation.FragmentDefinitionRef(f.operation.FragmentSpreadNameBytes(ref))
- if !exists {
- fragmentName := f.operation.FragmentSpreadNameBytes(ref)
- f.StopWithExternalErr(operationreport.ErrFragmentUndefined(fragmentName))
- return
- }
-
- fragmentTypeName := f.operation.FragmentDefinitionTypeName(fragmentDefinitionRef)
- fragmentNode, exists := f.definition.NodeByName(fragmentTypeName)
- if !exists {
- f.StopWithExternalErr(operationreport.ErrTypeUndefined(fragmentTypeName))
- return
- }
-
- fragmentTypeEqualsParentType := bytes.Equal(parentTypeName, fragmentTypeName)
- var enclosingTypeImplementsFragmentType bool
- var enclosingTypeIsMemberOfFragmentUnion bool
- var fragmentTypeImplementsEnclosingType bool
- var fragmentTypeIsMemberOfEnclosingUnionType bool
- var fragmentUnionIntersectsEnclosingInterface bool
-
- if fragmentNode.Kind == ast.NodeKindInterfaceTypeDefinition && f.EnclosingTypeDefinition.Kind == ast.NodeKindObjectTypeDefinition {
- enclosingTypeImplementsFragmentType = f.definition.NodeImplementsInterface(f.EnclosingTypeDefinition, fragmentNode)
- }
-
- if fragmentNode.Kind == ast.NodeKindUnionTypeDefinition {
- enclosingTypeIsMemberOfFragmentUnion = f.definition.NodeIsUnionMember(f.EnclosingTypeDefinition, fragmentNode)
- }
-
- if f.EnclosingTypeDefinition.Kind == ast.NodeKindInterfaceTypeDefinition {
- fragmentTypeImplementsEnclosingType = f.definition.NodeImplementsInterface(fragmentNode, f.EnclosingTypeDefinition)
- }
-
- if f.EnclosingTypeDefinition.Kind == ast.NodeKindInterfaceTypeDefinition && fragmentNode.Kind == ast.NodeKindUnionTypeDefinition {
- fragmentUnionIntersectsEnclosingInterface = f.definition.UnionNodeIntersectsInterfaceNode(fragmentNode, f.EnclosingTypeDefinition)
- }
-
- if f.EnclosingTypeDefinition.Kind == ast.NodeKindUnionTypeDefinition {
- fragmentTypeIsMemberOfEnclosingUnionType = f.definition.NodeIsUnionMember(fragmentNode, f.EnclosingTypeDefinition)
- }
-
- nestedDepth, ok := f.depths.ByRef(ref)
- if !ok {
- f.StopWithInternalErr(fmt.Errorf("nested depth missing on depths for FragmentSpread: %s", f.operation.FragmentSpreadNameString(ref)))
- return
- }
-
- precedence := asttransform.Precedence{
- Depth: nestedDepth,
- Order: 0,
- }
-
- selectionSet := f.Ancestors[len(f.Ancestors)-1].Ref
- replaceWith := f.operation.FragmentDefinitions[fragmentDefinitionRef].SelectionSet
- typeCondition := f.operation.FragmentDefinitions[fragmentDefinitionRef].TypeCondition
-
- switch {
- case fragmentTypeEqualsParentType || enclosingTypeImplementsFragmentType:
- f.transformer.ReplaceFragmentSpread(precedence, selectionSet, ref, replaceWith)
- case fragmentTypeImplementsEnclosingType || fragmentTypeIsMemberOfEnclosingUnionType || enclosingTypeIsMemberOfFragmentUnion || fragmentUnionIntersectsEnclosingInterface:
- f.transformer.ReplaceFragmentSpreadWithInlineFragment(precedence, selectionSet, ref, replaceWith, typeCondition)
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/fragmentspread_depth.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/fragmentspread_depth.go
deleted file mode 100644
index c180d70fd53..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/fragmentspread_depth.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package astnormalization
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-// FragmentSpreadDepth is a helper for nested Fragments to calculate the actual depth of a Fragment Node
-type FragmentSpreadDepth struct {
- walker astvisitor.Walker
- visitor fragmentSpreadDepthVisitor
- calc nestedDepthCalc
- visitorsRegistered bool
-}
-
-// Depth holds all necessary information to understand the Depth of a Fragment Node
-type Depth struct {
- SpreadRef int
- Depth int
- SpreadName ast.ByteSlice
- isNested bool
- parentFragmentName ast.ByteSlice
-}
-
-type Depths []Depth
-
-func (d Depths) ByRef(ref int) (int, bool) {
- for i := range d {
- if d[i].SpreadRef == ref {
- return d[i].Depth, true
- }
- }
- return -1, false
-}
-
-// Get returns all FragmentSpread Depths for a given AST
-func (r *FragmentSpreadDepth) Get(operation, definition *ast.Document, report *operationreport.Report, depths *Depths) {
-
- if !r.visitorsRegistered {
- r.walker.RegisterEnterFragmentSpreadVisitor(&r.visitor)
- r.visitorsRegistered = true
- }
-
- r.visitor.operation = operation
- r.visitor.definition = definition
- r.visitor.depths = depths
- r.visitor.Walker = &r.walker
-
- r.walker.Walk(operation, definition, report)
- r.calc.calculatedNestedDepths(depths)
-}
-
-type nestedDepthCalc struct {
- depths *Depths
-}
-
-func (n *nestedDepthCalc) calculatedNestedDepths(depths *Depths) {
- n.depths = depths
-
- for i := range *depths {
- (*depths)[i].Depth = n.calculateNestedDepth(i)
- }
-}
-
-func (n *nestedDepthCalc) calculateNestedDepth(i int) int {
- if !(*n.depths)[i].isNested {
- return (*n.depths)[i].Depth
- }
- return (*n.depths)[i].Depth + n.depthForFragment((*n.depths)[i].parentFragmentName)
-}
-
-func (n *nestedDepthCalc) depthForFragment(name ast.ByteSlice) int {
- for i := range *n.depths {
- if bytes.Equal(name, (*n.depths)[i].SpreadName) {
- return n.calculateNestedDepth(i)
- }
- }
- return 0
-}
-
-type fragmentSpreadDepthVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
- definition *ast.Document
- depths *Depths
-}
-
-func (r *fragmentSpreadDepthVisitor) EnterFragmentSpread(ref int) {
-
- depth := Depth{
- SpreadRef: ref,
- Depth: r.Depth,
- SpreadName: r.operation.FragmentSpreadNameBytes(ref),
- }
-
- if r.Ancestors[0].Kind == ast.NodeKindFragmentDefinition {
- depth.isNested = true
- depth.parentFragmentName = r.operation.FragmentDefinitionNameBytes(r.Ancestors[0].Ref)
- }
-
- *r.depths = append(*r.depths, depth)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/inline_fragment_merging.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/inline_fragment_merging.go
deleted file mode 100644
index 0e7270e6959..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/inline_fragment_merging.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package astnormalization
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func mergeInlineFragments(walker *astvisitor.Walker) {
- visitor := mergeInlineFragmentsVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterSelectionSetVisitor(&visitor)
-}
-
-type mergeInlineFragmentsVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (m *mergeInlineFragmentsVisitor) EnterDocument(operation, definition *ast.Document) {
- m.operation = operation
- m.definition = definition
-}
-
-func (m *mergeInlineFragmentsVisitor) couldInline(set, inlineFragment int) bool {
- if m.operation.InlineFragmentHasDirectives(inlineFragment) {
- return false
- }
- if !m.operation.InlineFragmentHasTypeCondition(inlineFragment) {
- return true
- }
- if bytes.Equal(m.operation.InlineFragmentTypeConditionName(inlineFragment), m.definition.NodeNameBytes(m.EnclosingTypeDefinition)) {
- return true
- }
-
- inlineFragmentTypeName := m.operation.InlineFragmentTypeConditionName(inlineFragment)
- enclosingTypeName := m.definition.NodeNameBytes(m.EnclosingTypeDefinition)
-
- return m.definition.TypeDefinitionContainsImplementsInterface(enclosingTypeName, inlineFragmentTypeName)
-}
-
-func (m *mergeInlineFragmentsVisitor) resolveInlineFragment(set, index, inlineFragment int) {
- m.operation.ReplaceSelectionOnSelectionSet(set, index, m.operation.InlineFragments[inlineFragment].SelectionSet)
-}
-
-func (m *mergeInlineFragmentsVisitor) EnterSelectionSet(ref int) {
-
- for index, selection := range m.operation.SelectionSets[ref].SelectionRefs {
- if m.operation.Selections[selection].Kind != ast.SelectionKindInlineFragment {
- continue
- }
- inlineFragment := m.operation.Selections[selection].Ref
- if !m.couldInline(ref, inlineFragment) {
- continue
- }
- m.resolveInlineFragment(ref, index, inlineFragment)
- m.RevisitNode()
- return
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/input_object_type_extending.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/input_object_type_extending.go
deleted file mode 100644
index 969b0d5d1b5..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/input_object_type_extending.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func extendInputObjectTypeDefinition(walker *astvisitor.Walker) {
- visitor := extendInputObjectTypeDefinitionVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterInputObjectTypeExtensionVisitor(&visitor)
-}
-
-type extendInputObjectTypeDefinitionVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
-}
-
-func (e *extendInputObjectTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
- e.operation = operation
-}
-
-func (e *extendInputObjectTypeDefinitionVisitor) EnterInputObjectTypeExtension(ref int) {
-
- nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.InputObjectTypeExtensionNameBytes(ref))
- if !exists {
- return
- }
-
- for i := range nodes {
- if nodes[i].Kind != ast.NodeKindInputObjectTypeDefinition {
- continue
- }
- e.operation.ExtendInputObjectTypeDefinitionByInputObjectTypeExtension(nodes[i].Ref, ref)
- return
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/interface_type_extending.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/interface_type_extending.go
deleted file mode 100644
index dc7af209a9e..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/interface_type_extending.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func extendInterfaceTypeDefinition(walker *astvisitor.Walker) {
- visitor := extendInterfaceTypeDefinitionVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterInterfaceTypeExtensionVisitor(&visitor)
-}
-
-type extendInterfaceTypeDefinitionVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
-}
-
-func (e *extendInterfaceTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
- e.operation = operation
-}
-
-func (e *extendInterfaceTypeDefinitionVisitor) EnterInterfaceTypeExtension(ref int) {
-
- nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.InterfaceTypeExtensionNameBytes(ref))
- if !exists {
- return
- }
-
- for i := range nodes {
- if nodes[i].Kind != ast.NodeKindInterfaceTypeDefinition {
- continue
- }
- e.operation.ExtendInterfaceTypeDefinitionByInterfaceTypeExtension(nodes[i].Ref, ref)
- return
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/object_type_extending.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/object_type_extending.go
deleted file mode 100644
index 029644b4b2d..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/object_type_extending.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func extendObjectTypeDefinition(walker *astvisitor.Walker) {
- visitor := extendObjectTypeDefinitionVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterObjectTypeExtensionVisitor(&visitor)
-}
-
-type extendObjectTypeDefinitionVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
-}
-
-func (e *extendObjectTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
- e.operation = operation
-}
-
-func (e *extendObjectTypeDefinitionVisitor) EnterObjectTypeExtension(ref int) {
-
- nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.ObjectTypeExtensionNameBytes(ref))
- if !exists {
- return
- }
-
- for i := range nodes {
- if nodes[i].Kind != ast.NodeKindObjectTypeDefinition {
- continue
- }
- e.operation.ExtendObjectTypeDefinitionByObjectTypeExtension(nodes[i].Ref, ref)
- return
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/remove_self_aliasing.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/remove_self_aliasing.go
deleted file mode 100644
index 700821428e3..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/remove_self_aliasing.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package astnormalization
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func removeSelfAliasing(walker *astvisitor.Walker) {
- visitor := removeSelfAliasingVisitor{}
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterFieldVisitor(&visitor)
-}
-
-type removeSelfAliasingVisitor struct {
- operation *ast.Document
-}
-
-func (r *removeSelfAliasingVisitor) EnterDocument(operation, definition *ast.Document) {
- r.operation = operation
-}
-
-func (r *removeSelfAliasingVisitor) EnterField(ref int) {
- if !r.operation.Fields[ref].Alias.IsDefined {
- return
- }
- if !bytes.Equal(r.operation.FieldNameBytes(ref), r.operation.FieldAliasBytes(ref)) {
- return
- }
- r.operation.RemoveFieldAlias(ref)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/remove_type_extensions.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/remove_type_extensions.go
deleted file mode 100644
index b420202667e..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/remove_type_extensions.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func removeMergedTypeExtensions(walker *astvisitor.Walker) {
- visitor := removeMergedTypeExtensionsVisitor{
- Walker: walker,
- }
- walker.RegisterLeaveDocumentVisitor(&visitor)
-}
-
-type removeMergedTypeExtensionsVisitor struct {
- *astvisitor.Walker
-}
-
-func (r *removeMergedTypeExtensionsVisitor) LeaveDocument(operation, definition *ast.Document) {
- operation.RemoveMergedTypeExtensions()
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/scalar_type_extending.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/scalar_type_extending.go
deleted file mode 100644
index d587c155bfb..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/scalar_type_extending.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func extendScalarTypeDefinition(walker *astvisitor.Walker) {
- visitor := extendScalarTypeDefinitionVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterScalarTypeExtensionVisitor(&visitor)
-}
-
-type extendScalarTypeDefinitionVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
-}
-
-func (e *extendScalarTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
- e.operation = operation
-}
-
-func (e *extendScalarTypeDefinitionVisitor) EnterScalarTypeExtension(ref int) {
-
- nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.ScalarTypeExtensionNameBytes(ref))
- if !exists {
- return
- }
-
- for i := range nodes {
- if nodes[i].Kind != ast.NodeKindScalarTypeDefinition {
- continue
- }
- e.operation.ExtendScalarTypeDefinitionByScalarTypeExtension(nodes[i].Ref, ref)
- return
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/union_type_extending.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/union_type_extending.go
deleted file mode 100644
index cdef8837533..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/union_type_extending.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package astnormalization
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func extendUnionTypeDefinition(walker *astvisitor.Walker) {
- visitor := extendUnionTypeDefinitionVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterUnionTypeExtensionVisitor(&visitor)
-}
-
-type extendUnionTypeDefinitionVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
-}
-
-func (e *extendUnionTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) {
- e.operation = operation
-}
-
-func (e *extendUnionTypeDefinitionVisitor) EnterUnionTypeExtension(ref int) {
-
- nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.UnionTypeExtensionNameBytes(ref))
- if !exists {
- return
- }
-
- for i := range nodes {
- if nodes[i].Kind != ast.NodeKindUnionTypeDefinition {
- continue
- }
- e.operation.ExtendUnionTypeDefinitionByUnionTypeExtension(nodes[i].Ref, ref)
- return
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/variables_extraction.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/variables_extraction.go
deleted file mode 100644
index 16685f5cbad..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astnormalization/variables_extraction.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package astnormalization
-
-import (
- "bytes"
-
- "github.com/tidwall/sjson"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astimport"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-func extractVariables(walker *astvisitor.Walker) *variablesExtractionVisitor {
- visitor := &variablesExtractionVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(visitor)
- walker.RegisterEnterArgumentVisitor(visitor)
- walker.RegisterEnterOperationVisitor(visitor)
- return visitor
-}
-
-type variablesExtractionVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
- importer astimport.Importer
- operationName []byte
- skip bool
-}
-
-func (v *variablesExtractionVisitor) EnterOperationDefinition(ref int) {
- if len(v.operationName) == 0 {
- v.skip = false
- return
- }
- operationName := v.operation.OperationDefinitionNameBytes(ref)
- v.skip = !bytes.Equal(operationName, v.operationName)
-}
-
-func (v *variablesExtractionVisitor) EnterArgument(ref int) {
- if v.skip {
- return
- }
- if v.operation.Arguments[ref].Value.Kind == ast.ValueKindVariable {
- return
- }
- if len(v.Ancestors) == 0 || v.Ancestors[0].Kind != ast.NodeKindOperationDefinition {
- return
- }
-
- for i := range v.Ancestors {
- if v.Ancestors[i].Kind == ast.NodeKindDirective {
- return // skip all directives in any case
- }
- }
-
- variableNameBytes := v.operation.GenerateUnusedVariableDefinitionName(v.Ancestors[0].Ref)
- valueBytes, err := v.operation.ValueToJSON(v.operation.Arguments[ref].Value)
- if err != nil {
- return
- }
- v.operation.Input.Variables, err = sjson.SetRawBytes(v.operation.Input.Variables, unsafebytes.BytesToString(variableNameBytes), valueBytes)
- if err != nil {
- v.StopWithInternalErr(err)
- return
- }
-
- variable := ast.VariableValue{
- Name: v.operation.Input.AppendInputBytes(variableNameBytes),
- }
-
- v.operation.VariableValues = append(v.operation.VariableValues, variable)
-
- varRef := len(v.operation.VariableValues) - 1
-
- v.operation.Arguments[ref].Value.Ref = varRef
- v.operation.Arguments[ref].Value.Kind = ast.ValueKindVariable
-
- defRef, ok := v.ArgumentInputValueDefinition(ref)
- if !ok {
- return
- }
-
- defType := v.definition.InputValueDefinitions[defRef].Type
-
- importedDefType := v.importer.ImportType(defType, v.definition, v.operation)
-
- v.operation.VariableDefinitions = append(v.operation.VariableDefinitions, ast.VariableDefinition{
- VariableValue: ast.Value{
- Kind: ast.ValueKindVariable,
- Ref: varRef,
- },
- Type: importedDefType,
- })
-
- newVariableRef := len(v.operation.VariableDefinitions) - 1
-
- v.operation.OperationDefinitions[v.Ancestors[0].Ref].VariableDefinitions.Refs =
- append(v.operation.OperationDefinitions[v.Ancestors[0].Ref].VariableDefinitions.Refs, newVariableRef)
- v.operation.OperationDefinitions[v.Ancestors[0].Ref].HasVariableDefinitions = true
-}
-
-func (v *variablesExtractionVisitor) EnterDocument(operation, definition *ast.Document) {
- v.operation, v.definition = operation, definition
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astparser/parser.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astparser/parser.go
deleted file mode 100644
index 50a3e18b3f8..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astparser/parser.go
+++ /dev/null
@@ -1,1934 +0,0 @@
-// Package astparser is used to turn raw GraphQL documents into an AST.
-package astparser
-
-import (
- "fmt"
- "runtime"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/identkeyword"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/keyword"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/token"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-// ParseGraphqlDocumentString takes a raw GraphQL document in string format and parses it into an AST.
-// This function creates a new parser as well as a new AST for every call.
-// Therefore you shouldn't use this function in a hot path.
-// Instead create a parser as well as AST objects and re-use them.
-func ParseGraphqlDocumentString(input string) (ast.Document, operationreport.Report) {
- return ParseGraphqlDocumentBytes([]byte(input))
-}
-
-// ParseGraphqlDocumentBytes takes a raw GraphQL document in byte slice format and parses it into an AST.
-// This function creates a new parser as well as a new AST for every call.
-// Therefore you shouldn't use this function in a hot path.
-// Instead create a parser as well as AST objects and re-use them.
-func ParseGraphqlDocumentBytes(input []byte) (ast.Document, operationreport.Report) {
- parser := NewParser()
- doc := *ast.NewDocument()
- doc.Input.ResetInputBytes(input)
- report := operationreport.Report{}
- parser.Parse(&doc, &report)
- return doc, report
-}
-
-type origin struct {
- file string
- line int
- funcName string
-}
-
-// ErrUnexpectedToken is a custom error object containing all necessary information to properly render an unexpected token error
-type ErrUnexpectedToken struct {
- keyword keyword.Keyword
- expected []keyword.Keyword
- position position.Position
- literal string
- origins []origin
-}
-
-func (e ErrUnexpectedToken) Error() string {
-
- origins := ""
- for _, origin := range e.origins {
- origins = origins + fmt.Sprintf("\n\t\t%s:%d\n\t\t%s", origin.file, origin.line, origin.funcName)
- }
-
- return fmt.Sprintf("unexpected token - keyword: '%s' literal: '%s' - expected: '%s' position: '%s'%s", e.keyword, e.literal, e.expected, e.position, origins)
-}
-
-// ErrUnexpectedIdentKey is a custom error object to properly render an unexpected ident key error
-type ErrUnexpectedIdentKey struct {
- keyword identkeyword.IdentKeyword
- expected []identkeyword.IdentKeyword
- position position.Position
- literal string
- origins []origin
-}
-
-func (e ErrUnexpectedIdentKey) Error() string {
-
- origins := ""
- for _, origin := range e.origins {
- origins = origins + fmt.Sprintf("\n\t\t%s:%d\n\t\t%s", origin.file, origin.line, origin.funcName)
- }
-
- return fmt.Sprintf("unexpected ident - keyword: '%s' literal: '%s' - expected: '%s' position: '%s'%s", e.keyword, e.literal, e.expected, e.position, origins)
-}
-
-// Parser takes a raw input and turns it into an AST
-// use NewParser() to create a parser
-// Don't create new parsers in the hot path, re-use them.
-type Parser struct {
- document *ast.Document
- report *operationreport.Report
- lexer *lexer.Lexer
- tokens []token.Token
- maxTokens int
- currentToken int
- shouldIndex bool
- reportInternalErrors bool
-}
-
-// NewParser returns a new parser with all values properly initialized
-func NewParser() *Parser {
- return &Parser{
- tokens: make([]token.Token, 256),
- lexer: &lexer.Lexer{},
- shouldIndex: true,
- reportInternalErrors: false,
- }
-}
-
-// PrepareImport prepares the Parser for importing new Nodes into an AST without directly parsing the content
-func (p *Parser) PrepareImport(document *ast.Document, report *operationreport.Report) {
- p.document = document
- p.report = report
- p.lexer.SetInput(&document.Input)
- p.tokenize()
-}
-
-// Parse parses all input in a Document.Input into the Document
-func (p *Parser) Parse(document *ast.Document, report *operationreport.Report) {
- p.document = document
- p.report = report
- p.lexer.SetInput(&document.Input)
- p.tokenize()
- p.parse()
-}
-
-func (p *Parser) tokenize() {
-
- p.tokens = p.tokens[:0]
-
- for {
- next := p.lexer.Read()
- if next.Keyword == keyword.EOF {
- p.maxTokens = len(p.tokens)
- p.currentToken = -1
- return
- }
- p.tokens = append(p.tokens, next)
- }
-}
-
-func (p *Parser) parse() {
- for {
- key, literalReference := p.peekLiteral()
-
- switch key {
- case keyword.EOF:
- p.read()
- return
- case keyword.LBRACE:
- p.parseOperationDefinition()
- case keyword.COMMENT:
- p.read()
- case keyword.STRING, keyword.BLOCKSTRING:
- p.parseRootDescription()
- case keyword.IDENT:
- keyIdent := p.identKeywordSliceRef(literalReference)
- switch keyIdent {
- case identkeyword.ENUM:
- p.parseEnumTypeDefinition(nil)
- case identkeyword.TYPE:
- p.parseObjectTypeDefinition(nil)
- case identkeyword.UNION:
- p.parseUnionTypeDefinition(nil)
- case identkeyword.QUERY, identkeyword.MUTATION, identkeyword.SUBSCRIPTION:
- p.parseOperationDefinition()
- case identkeyword.INPUT:
- p.parseInputObjectTypeDefinition(nil)
- case identkeyword.EXTEND:
- p.parseExtension()
- case identkeyword.SCHEMA:
- p.parseSchemaDefinition()
- case identkeyword.SCALAR:
- p.parseScalarTypeDefinition(nil)
- case identkeyword.FRAGMENT:
- p.parseFragmentDefinition()
- case identkeyword.INTERFACE:
- p.parseInterfaceTypeDefinition(nil)
- case identkeyword.DIRECTIVE:
- p.parseDirectiveDefinition(nil)
- default:
- p.errUnexpectedIdentKey(p.read(), keyIdent, identkeyword.ENUM, identkeyword.TYPE, identkeyword.UNION, identkeyword.QUERY, identkeyword.INPUT, identkeyword.EXTEND, identkeyword.SCHEMA, identkeyword.SCALAR, identkeyword.FRAGMENT, identkeyword.INTERFACE, identkeyword.DIRECTIVE)
- }
- default:
- p.errUnexpectedToken(p.read(), keyword.EOF, keyword.LBRACE, keyword.COMMENT, keyword.STRING, keyword.BLOCKSTRING, keyword.IDENT)
- }
-
- if p.report.HasErrors() {
- return
- }
- }
-}
-
-func (p *Parser) next() int {
- if p.currentToken != p.maxTokens-1 {
- p.currentToken++
- }
- return p.currentToken
-}
-
-func (p *Parser) read() token.Token {
- p.currentToken++
- if p.currentToken < p.maxTokens {
- return p.tokens[p.currentToken]
- }
-
- return token.Token{
- Keyword: keyword.EOF,
- }
-}
-
-func (p *Parser) identKeywordToken(token token.Token) identkeyword.IdentKeyword {
- return identkeyword.KeywordFromLiteral(p.document.Input.ByteSlice(token.Literal))
-}
-
-func (p *Parser) identKeywordSliceRef(ref ast.ByteSliceReference) identkeyword.IdentKeyword {
- return identkeyword.KeywordFromLiteral(p.document.Input.ByteSlice(ref))
-}
-
-func (p *Parser) readExpectLiteral(expect ...identkeyword.IdentKeyword) (token.Token, identkeyword.IdentKeyword) {
- p.currentToken++
- if p.currentToken < p.maxTokens {
- out := p.tokens[p.currentToken]
- identKey := p.identKeywordToken(out)
- for _, expectation := range expect {
- if identKey == expectation {
- return out, identKey
- }
- }
- p.errUnexpectedToken(out)
- return out, identKey
- }
-
- return token.Token{
- Keyword: keyword.EOF,
- }, identkeyword.UNDEFINED
-}
-
-func (p *Parser) peek() keyword.Keyword {
- nextIndex := p.currentToken + 1
- if nextIndex < p.maxTokens {
- return p.tokens[nextIndex].Keyword
- }
- return keyword.EOF
-}
-
-func (p *Parser) peekLiteral() (keyword.Keyword, ast.ByteSliceReference) {
- nextIndex := p.currentToken + 1
- if nextIndex < p.maxTokens {
- return p.tokens[nextIndex].Keyword, p.tokens[nextIndex].Literal
- }
- return keyword.EOF, ast.ByteSliceReference{}
-}
-
-func (p *Parser) peekEquals(key keyword.Keyword) bool {
- return p.peek() == key
-}
-
-func (p *Parser) peekEqualsIdentKey(identKey identkeyword.IdentKeyword) bool {
- key, literal := p.peekLiteral()
- if key != keyword.IDENT {
- return false
- }
- actualKey := p.identKeywordSliceRef(literal)
- return actualKey == identKey
-}
-
-func (p *Parser) errUnexpectedIdentKey(unexpected token.Token, unexpectedKey identkeyword.IdentKeyword, expectedKeywords ...identkeyword.IdentKeyword) {
-
- if p.report.HasErrors() {
- return
- }
-
- p.report.AddExternalError(operationreport.ExternalError{
- Message: fmt.Sprintf("unexpected literal - got: %s want one of: %v", unexpectedKey, expectedKeywords),
- Locations: []operationreport.Location{
- {
- Line: unexpected.TextPosition.LineStart,
- Column: unexpected.TextPosition.CharStart,
- },
- },
- })
-
- if !p.reportInternalErrors {
- return
- }
-
- origins := make([]origin, 3)
- for i := range origins {
- fpcs := make([]uintptr, 1)
- callers := runtime.Callers(2+i, fpcs)
-
- if callers == 0 {
- origins = origins[:i]
- break
- }
-
- fn := runtime.FuncForPC(fpcs[0])
- file, line := fn.FileLine(fpcs[0])
-
- origins[i].file = file
- origins[i].line = line
- origins[i].funcName = fn.Name()
- }
-
- p.report.AddInternalError(ErrUnexpectedIdentKey{
- keyword: unexpectedKey,
- position: unexpected.TextPosition,
- literal: p.document.Input.ByteSliceString(unexpected.Literal),
- origins: origins,
- expected: expectedKeywords,
- })
-}
-
-func (p *Parser) errUnexpectedToken(unexpected token.Token, expectedKeywords ...keyword.Keyword) {
-
- if p.report.HasErrors() {
- return
- }
-
- p.report.AddExternalError(operationreport.ExternalError{
- Message: fmt.Sprintf("unexpected token - got: %s want one of: %v", unexpected.Keyword, expectedKeywords),
- Locations: []operationreport.Location{
- {
- Line: unexpected.TextPosition.LineStart,
- Column: unexpected.TextPosition.CharStart,
- },
- },
- })
-
- if !p.reportInternalErrors {
- return
- }
-
- origins := make([]origin, 3)
- for i := range origins {
- fpcs := make([]uintptr, 1)
- callers := runtime.Callers(2+i, fpcs)
-
- if callers == 0 {
- origins = origins[:i]
- break
- }
-
- fn := runtime.FuncForPC(fpcs[0])
- file, line := fn.FileLine(fpcs[0])
-
- origins[i].file = file
- origins[i].line = line
- origins[i].funcName = fn.Name()
- }
-
- p.report.AddInternalError(ErrUnexpectedToken{
- keyword: unexpected.Keyword,
- position: unexpected.TextPosition,
- literal: p.document.Input.ByteSliceString(unexpected.Literal),
- origins: origins,
- expected: expectedKeywords,
- })
-}
-
-func (p *Parser) mustNext(key keyword.Keyword) int {
- current := p.currentToken
- if p.next() == current {
- p.errUnexpectedToken(p.tokens[p.currentToken], key)
- return p.currentToken
- }
- if p.tokens[p.currentToken].Keyword != key {
- p.errUnexpectedToken(p.tokens[p.currentToken], key)
- return p.currentToken
- }
- return p.currentToken
-}
-
-func (p *Parser) mustRead(key keyword.Keyword) (next token.Token) {
- next = p.read()
- if next.Keyword != key {
- p.errUnexpectedToken(next, key)
- }
- return
-}
-
-func (p *Parser) mustReadIdentKey(key identkeyword.IdentKeyword) (next token.Token) {
- next = p.read()
- if next.Keyword != keyword.IDENT {
- p.errUnexpectedToken(next, keyword.IDENT)
- }
- identKey := p.identKeywordToken(next)
- if identKey != key {
- p.errUnexpectedIdentKey(next, identKey, key)
- }
- return
-}
-
-func (p *Parser) mustReadExceptIdentKey(key identkeyword.IdentKeyword) (next token.Token) {
- next = p.read()
- if next.Keyword != keyword.IDENT {
- p.errUnexpectedToken(next, keyword.IDENT)
- }
- identKey := p.identKeywordToken(next)
- if identKey == key {
- p.errUnexpectedIdentKey(next, identKey, key)
- }
- return
-}
-
-func (p *Parser) parseSchemaDefinition() {
-
- schemaLiteral := p.read()
-
- schemaDefinition := ast.SchemaDefinition{
- SchemaLiteral: schemaLiteral.TextPosition,
- }
-
- if p.peekEquals(keyword.AT) {
- schemaDefinition.Directives = p.parseDirectiveList()
- schemaDefinition.HasDirectives = len(schemaDefinition.Directives.Refs) > 0
- }
-
- p.parseRootOperationTypeDefinitionList(&schemaDefinition.RootOperationTypeDefinitions)
-
- p.document.SchemaDefinitions = append(p.document.SchemaDefinitions, schemaDefinition)
-
- ref := len(p.document.SchemaDefinitions) - 1
- rootNode := ast.Node{
- Kind: ast.NodeKindSchemaDefinition,
- Ref: ref,
- }
- p.document.RootNodes = append(p.document.RootNodes, rootNode)
-}
-
-func (p *Parser) parseRootOperationTypeDefinitionList(list *ast.RootOperationTypeDefinitionList) {
-
- curlyBracketOpen := p.mustRead(keyword.LBRACE)
-
- for {
- next := p.peek()
- switch next {
- case keyword.RBRACE:
-
- curlyBracketClose := p.read()
- list.LBrace = curlyBracketOpen.TextPosition
- list.RBrace = curlyBracketClose.TextPosition
- return
- case keyword.IDENT:
-
- _, operationType := p.readExpectLiteral(identkeyword.QUERY, identkeyword.MUTATION, identkeyword.SUBSCRIPTION)
- colon := p.mustRead(keyword.COLON)
- namedType := p.mustRead(keyword.IDENT)
-
- rootOperationTypeDefinition := ast.RootOperationTypeDefinition{
- OperationType: p.operationTypeFromIdentKeyword(operationType),
- Colon: colon.TextPosition,
- NamedType: ast.Type{
- TypeKind: ast.TypeKindNamed,
- Name: namedType.Literal,
- },
- }
-
- p.document.RootOperationTypeDefinitions = append(p.document.RootOperationTypeDefinitions, rootOperationTypeDefinition)
- ref := len(p.document.RootOperationTypeDefinitions) - 1
-
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
-
- list.Refs = append(list.Refs, ref)
-
- if p.shouldIndex {
- p.indexRootOperationTypeDefinition(rootOperationTypeDefinition)
- }
-
- default:
- p.errUnexpectedToken(p.read())
- return
- }
-
- if p.report.HasErrors() {
- return
- }
- }
-}
-
-func (p *Parser) indexRootOperationTypeDefinition(definition ast.RootOperationTypeDefinition) {
- switch definition.OperationType {
- case ast.OperationTypeQuery:
- p.document.Index.QueryTypeName = p.document.Input.ByteSlice(definition.NamedType.Name)
- case ast.OperationTypeMutation:
- p.document.Index.MutationTypeName = p.document.Input.ByteSlice(definition.NamedType.Name)
- case ast.OperationTypeSubscription:
- p.document.Index.SubscriptionTypeName = p.document.Input.ByteSlice(definition.NamedType.Name)
- }
-}
-
-func (p *Parser) operationTypeFromIdentKeyword(key identkeyword.IdentKeyword) ast.OperationType {
- switch key {
- case identkeyword.QUERY:
- return ast.OperationTypeQuery
- case identkeyword.MUTATION:
- return ast.OperationTypeMutation
- case identkeyword.SUBSCRIPTION:
- return ast.OperationTypeSubscription
- default:
- return ast.OperationTypeUnknown
- }
-}
-
-func (p *Parser) parseDirectiveList() (list ast.DirectiveList) {
-
- for {
-
- if p.peek() != keyword.AT {
- break
- }
-
- at := p.read()
- name := p.mustRead(keyword.IDENT)
-
- directive := ast.Directive{
- At: at.TextPosition,
- Name: name.Literal,
- }
-
- if p.peekEquals(keyword.LPAREN) {
- directive.Arguments = p.parseArgumentList()
- directive.HasArguments = len(directive.Arguments.Refs) > 0
- }
-
- p.document.Directives = append(p.document.Directives, directive)
- ref := len(p.document.Directives) - 1
-
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
-
- list.Refs = append(list.Refs, ref)
-
- if p.report.HasErrors() {
- return
- }
- }
-
- return
-}
-
-func (p *Parser) parseArgumentList() (list ast.ArgumentList) {
-
- bracketOpen := p.next()
-
-Loop:
- for {
-
- next := p.peek()
- switch next {
- case keyword.IDENT:
- default:
- break Loop
- }
-
- name := p.next()
- colon := p.mustRead(keyword.COLON)
- value := p.ParseValue()
-
- argument := ast.Argument{
- Name: p.tokens[name].Literal,
- Colon: colon.TextPosition,
- Value: value,
- }
-
- p.document.Arguments = append(p.document.Arguments, argument)
- ref := len(p.document.Arguments) - 1
-
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
-
- list.Refs = append(list.Refs, ref)
-
- if p.report.HasErrors() {
- return
- }
- }
-
- bracketClose := p.mustRead(keyword.RPAREN)
-
- list.LPAREN = p.tokens[bracketOpen].TextPosition
- list.RPAREN = bracketClose.TextPosition
-
- return
-}
-
-func (p *Parser) ParseValue() (value ast.Value) {
-
- next, literal := p.peekLiteral()
-
- switch next {
- case keyword.STRING, keyword.BLOCKSTRING:
- value.Kind = ast.ValueKindString
- value.Ref = p.parseStringValue()
- case keyword.IDENT:
- key := p.identKeywordSliceRef(literal)
- switch key {
- case identkeyword.TRUE, identkeyword.FALSE:
- value.Kind = ast.ValueKindBoolean
- value.Ref = p.parseBooleanValue()
- case identkeyword.NULL:
- value.Kind = ast.ValueKindNull
- p.read()
- default:
- value.Kind = ast.ValueKindEnum
- value.Ref = p.parseEnumValue()
- }
- case keyword.DOLLAR:
- value.Kind = ast.ValueKindVariable
- value.Ref = p.parseVariableValue()
- case keyword.INTEGER:
- value.Kind = ast.ValueKindInteger
- value.Ref = p.parseIntegerValue(nil)
- case keyword.FLOAT:
- value.Kind = ast.ValueKindFloat
- value.Ref = p.parseFloatValue(nil)
- case keyword.SUB:
- value = p.parseNegativeNumberValue()
- case keyword.LBRACK:
- value.Kind = ast.ValueKindList
- value.Ref = p.parseValueList()
- case keyword.LBRACE:
- value.Kind = ast.ValueKindObject
- value.Ref = p.parseObjectValue()
- default:
- p.errUnexpectedToken(p.read())
- }
-
- return
-}
-
-func (p *Parser) parseObjectValue() int {
- var objectValue ast.ObjectValue
- objectValue.LBRACE = p.mustRead(keyword.LBRACE).TextPosition
-
- for {
- next := p.peek()
- switch next {
- case keyword.RBRACE:
- objectValue.RBRACE = p.read().TextPosition
- p.document.ObjectValues = append(p.document.ObjectValues, objectValue)
- return len(p.document.ObjectValues) - 1
- case keyword.IDENT:
- ref := p.parseObjectField()
- if cap(objectValue.Refs) == 0 {
- objectValue.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
- objectValue.Refs = append(objectValue.Refs, ref)
- default:
- p.errUnexpectedToken(p.read(), keyword.IDENT, keyword.RBRACE)
- return -1
- }
-
- if p.report.HasErrors() {
- return -1
- }
- }
-}
-
-func (p *Parser) parseObjectField() int {
- objectField := ast.ObjectField{
- Name: p.mustRead(keyword.IDENT).Literal,
- Colon: p.mustRead(keyword.COLON).TextPosition,
- Value: p.ParseValue(),
- }
- p.document.ObjectFields = append(p.document.ObjectFields, objectField)
- return len(p.document.ObjectFields) - 1
-}
-
-func (p *Parser) parseValueList() int {
- var list ast.ListValue
- list.LBRACK = p.mustRead(keyword.LBRACK).TextPosition
-
- for {
- next := p.peek()
- switch next {
- case keyword.RBRACK:
- list.RBRACK = p.read().TextPosition
- p.document.ListValues = append(p.document.ListValues, list)
- return len(p.document.ListValues) - 1
- default:
- value := p.ParseValue()
- p.document.Values = append(p.document.Values, value)
- ref := len(p.document.Values) - 1
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
- list.Refs = append(list.Refs, ref)
- }
-
- if p.report.HasErrors() {
- return -1
- }
- }
-}
-
-func (p *Parser) parseNegativeNumberValue() (value ast.Value) {
- negativeSign := p.mustRead(keyword.SUB).TextPosition
- switch p.peek() {
- case keyword.INTEGER:
- value.Kind = ast.ValueKindInteger
- value.Ref = p.parseIntegerValue(&negativeSign)
- case keyword.FLOAT:
- value.Kind = ast.ValueKindFloat
- value.Ref = p.parseFloatValue(&negativeSign)
- default:
- p.errUnexpectedToken(p.read(), keyword.INTEGER, keyword.FLOAT)
- }
-
- return
-}
-
-func (p *Parser) parseFloatValue(negativeSign *position.Position) int {
-
- value := p.mustRead(keyword.FLOAT)
-
- if negativeSign != nil && negativeSign.CharEnd != value.TextPosition.CharStart {
- p.errUnexpectedToken(value)
- return -1
- }
-
- floatValue := ast.FloatValue{
- Raw: value.Literal,
- }
- if negativeSign != nil {
- floatValue.Negative = true
- floatValue.NegativeSign = *negativeSign
- }
-
- p.document.FloatValues = append(p.document.FloatValues, floatValue)
- return len(p.document.FloatValues) - 1
-}
-
-func (p *Parser) parseIntegerValue(negativeSign *position.Position) int {
-
- value := p.mustRead(keyword.INTEGER)
-
- if negativeSign != nil && negativeSign.CharEnd != value.TextPosition.CharStart {
- p.errUnexpectedToken(value)
- return -1
- }
-
- intValue := ast.IntValue{
- Raw: value.Literal,
- }
- if negativeSign != nil {
- intValue.Negative = true
- intValue.NegativeSign = *negativeSign
- }
-
- p.document.IntValues = append(p.document.IntValues, intValue)
- return len(p.document.IntValues) - 1
-}
-
-func (p *Parser) parseVariableValue() int {
- dollar := p.mustRead(keyword.DOLLAR)
- var value token.Token
-
- next := p.peek()
- switch next {
- case keyword.IDENT:
- value = p.read()
- default:
- p.errUnexpectedToken(p.read(), keyword.IDENT)
- return -1
- }
-
- if dollar.TextPosition.CharEnd != value.TextPosition.CharStart {
- p.errUnexpectedToken(p.read(), keyword.IDENT)
- return -1
- }
-
- variable := ast.VariableValue{
- Dollar: dollar.TextPosition,
- Name: value.Literal,
- }
-
- p.document.VariableValues = append(p.document.VariableValues, variable)
- return len(p.document.VariableValues) - 1
-}
-
-func (p *Parser) parseBooleanValue() int {
- value := p.read()
- identKey := p.identKeywordToken(value)
- switch identKey {
- case identkeyword.FALSE:
- return 0
- case identkeyword.TRUE:
- return 1
- default:
- p.errUnexpectedIdentKey(value, identKey, identkeyword.TRUE, identkeyword.FALSE)
- return -1
- }
-}
-
-func (p *Parser) parseEnumValue() int {
- enum := ast.EnumValue{
- Name: p.mustRead(keyword.IDENT).Literal,
- }
- p.document.EnumValues = append(p.document.EnumValues, enum)
- return len(p.document.EnumValues) - 1
-}
-
-func (p *Parser) parseStringValue() int {
- value := p.read()
- if value.Keyword != keyword.STRING && value.Keyword != keyword.BLOCKSTRING {
- p.errUnexpectedToken(value, keyword.STRING, keyword.BLOCKSTRING)
- return -1
- }
- stringValue := ast.StringValue{
- Content: value.Literal,
- BlockString: value.Keyword == keyword.BLOCKSTRING,
- }
- p.document.StringValues = append(p.document.StringValues, stringValue)
- return len(p.document.StringValues) - 1
-}
-
-func (p *Parser) parseObjectTypeDefinition(description *ast.Description) {
- var objectTypeDefinition ast.ObjectTypeDefinition
- if description != nil {
- objectTypeDefinition.Description = *description
- }
- objectTypeDefinition.TypeLiteral = p.mustReadIdentKey(identkeyword.TYPE).TextPosition
- objectTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEqualsIdentKey(identkeyword.IMPLEMENTS) {
- objectTypeDefinition.ImplementsInterfaces = p.parseImplementsInterfaces()
- }
- if p.peekEquals(keyword.AT) {
- objectTypeDefinition.Directives = p.parseDirectiveList()
- objectTypeDefinition.HasDirectives = len(objectTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- objectTypeDefinition.FieldsDefinition = p.parseFieldDefinitionList()
- objectTypeDefinition.HasFieldDefinitions = len(objectTypeDefinition.FieldsDefinition.Refs) > 0
- }
- p.document.ObjectTypeDefinitions = append(p.document.ObjectTypeDefinitions, objectTypeDefinition)
- ref := len(p.document.ObjectTypeDefinitions) - 1
- node := ast.Node{
- Kind: ast.NodeKindObjectTypeDefinition,
- Ref: ref,
- }
- if p.shouldIndex {
- p.indexNode(objectTypeDefinition.Name, node)
- }
- p.document.RootNodes = append(p.document.RootNodes, node)
-}
-
-func (p *Parser) indexNode(key ast.ByteSliceReference, value ast.Node) {
- name := p.document.Input.ByteSlice(key)
- p.document.Index.AddNodeBytes(name, value)
-}
-
-func (p *Parser) parseRootDescription() {
-
- description := p.parseDescription()
-
- key, literal := p.peekLiteral()
- if key != keyword.IDENT {
- p.errUnexpectedToken(p.read(), keyword.IDENT)
- return
- }
-
- next := p.identKeywordSliceRef(literal)
-
- switch next {
- case identkeyword.TYPE:
- p.parseObjectTypeDefinition(&description)
- case identkeyword.INPUT:
- p.parseInputObjectTypeDefinition(&description)
- case identkeyword.SCALAR:
- p.parseScalarTypeDefinition(&description)
- case identkeyword.INTERFACE:
- p.parseInterfaceTypeDefinition(&description)
- case identkeyword.UNION:
- p.parseUnionTypeDefinition(&description)
- case identkeyword.ENUM:
- p.parseEnumTypeDefinition(&description)
- case identkeyword.DIRECTIVE:
- p.parseDirectiveDefinition(&description)
- default:
- p.errUnexpectedIdentKey(p.read(), next, identkeyword.TYPE, identkeyword.INPUT, identkeyword.SCALAR, identkeyword.INTERFACE, identkeyword.UNION, identkeyword.ENUM, identkeyword.DIRECTIVE)
- }
-}
-
-func (p *Parser) parseImplementsInterfaces() (list ast.TypeList) {
-
- p.read() // implements
-
- acceptIdent := true
- acceptAnd := true
-
- for {
- next := p.peek()
- switch next {
- case keyword.AND:
- if acceptAnd {
- acceptAnd = false
- acceptIdent = true
- p.read()
- } else {
- p.errUnexpectedToken(p.read())
- return
- }
- case keyword.IDENT:
- if acceptIdent {
- acceptIdent = false
- acceptAnd = true
- name := p.read()
- astType := ast.Type{
- TypeKind: ast.TypeKindNamed,
- Name: name.Literal,
- }
- p.document.Types = append(p.document.Types, astType)
- ref := len(p.document.Types) - 1
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
- list.Refs = append(list.Refs, ref)
- } else {
- p.errUnexpectedToken(p.read())
- return
- }
- default:
- if acceptIdent {
- p.errUnexpectedToken(p.read())
- }
- return
- }
-
- if p.report.HasErrors() {
- return
- }
- }
-}
-
-func (p *Parser) parseFieldDefinitionList() (list ast.FieldDefinitionList) {
-
- list.LBRACE = p.mustRead(keyword.LBRACE).TextPosition
-
- refsInitialized := false
-
- for {
-
- next := p.peek()
-
- switch next {
- case keyword.RBRACE:
- list.RBRACE = p.read().TextPosition
- return
- case keyword.STRING, keyword.BLOCKSTRING, keyword.IDENT:
- ref := p.parseFieldDefinition()
- if !refsInitialized {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- refsInitialized = true
- }
- list.Refs = append(list.Refs, ref)
- default:
- p.errUnexpectedToken(p.read())
- return
- }
-
- if p.report.HasErrors() {
- return
- }
- }
-}
-
-func (p *Parser) parseFieldDefinition() int {
-
- var fieldDefinition ast.FieldDefinition
-
- name := p.peek()
- switch name {
- case keyword.STRING, keyword.BLOCKSTRING:
- fieldDefinition.Description = p.parseDescription()
- case keyword.IDENT:
- break
- default:
- p.errUnexpectedToken(p.read())
- return -1
- }
-
- nameToken := p.read()
- if nameToken.Keyword != keyword.IDENT {
- p.errUnexpectedToken(nameToken, keyword.IDENT)
- return -1
- }
-
- fieldDefinition.Name = nameToken.Literal
- if p.peekEquals(keyword.LPAREN) {
- fieldDefinition.ArgumentsDefinition = p.parseInputValueDefinitionList(keyword.RPAREN)
- fieldDefinition.HasArgumentsDefinitions = len(fieldDefinition.ArgumentsDefinition.Refs) > 0
- }
- fieldDefinition.Colon = p.mustRead(keyword.COLON).TextPosition
- fieldDefinition.Type = p.ParseType()
- if p.peek() == keyword.AT {
- fieldDefinition.Directives = p.parseDirectiveList()
- fieldDefinition.HasDirectives = len(fieldDefinition.Directives.Refs) > 0
- }
-
- p.document.FieldDefinitions = append(p.document.FieldDefinitions, fieldDefinition)
- return len(p.document.FieldDefinitions) - 1
-}
-
-func (p *Parser) parseNamedType() (ref int) {
- ident := p.mustRead(keyword.IDENT)
- namedType := ast.Type{
- TypeKind: ast.TypeKindNamed,
- Name: ident.Literal,
- }
- p.document.Types = append(p.document.Types, namedType)
- return len(p.document.Types) - 1
-}
-
-func (p *Parser) ParseType() (ref int) {
-
- first := p.peek()
-
- if first == keyword.IDENT {
-
- namedType := ast.Type{
- TypeKind: ast.TypeKindNamed,
- Name: p.read().Literal,
- OfType: -1,
- }
-
- p.document.Types = append(p.document.Types, namedType)
- ref = len(p.document.Types) - 1
-
- } else if first == keyword.LBRACK {
-
- openList := p.read()
- ofType := p.ParseType()
- closeList := p.mustRead(keyword.RBRACK)
-
- listType := ast.Type{
- TypeKind: ast.TypeKindList,
- Open: openList.TextPosition,
- Close: closeList.TextPosition,
- OfType: ofType,
- }
-
- p.document.Types = append(p.document.Types, listType)
- ref = len(p.document.Types) - 1
-
- } else {
- p.errUnexpectedToken(p.read(), keyword.IDENT, keyword.LBRACK)
- return
- }
-
- next := p.peek()
- if next == keyword.BANG {
- nonNull := ast.Type{
- TypeKind: ast.TypeKindNonNull,
- Bang: p.read().TextPosition,
- OfType: ref,
- }
-
- if p.peek() == keyword.BANG {
- p.errUnexpectedToken(p.read())
- return
- }
-
- p.document.Types = append(p.document.Types, nonNull)
- ref = len(p.document.Types) - 1
- }
-
- return
-}
-
-func (p *Parser) parseDescription() ast.Description {
- tok := p.read()
- return ast.Description{
- IsDefined: true,
- Content: tok.Literal,
- Position: tok.TextPosition,
- IsBlockString: tok.Keyword == keyword.BLOCKSTRING,
- }
-}
-
-func (p *Parser) parseInputValueDefinitionList(closingKeyword keyword.Keyword) (list ast.InputValueDefinitionList) {
-
- list.LPAREN = p.read().TextPosition
-
- for {
- next := p.peek()
- switch next {
- case closingKeyword:
- list.RPAREN = p.read().TextPosition
- return
- case keyword.STRING, keyword.BLOCKSTRING, keyword.IDENT:
- ref := p.parseInputValueDefinition()
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
- list.Refs = append(list.Refs, ref)
- default:
- p.errUnexpectedToken(p.read())
- return
- }
-
- if p.report.HasErrors() {
- return
- }
- }
-}
-
-func (p *Parser) parseInputValueDefinition() int {
-
- var inputValueDefinition ast.InputValueDefinition
-
- name := p.peek()
- switch name {
- case keyword.STRING, keyword.BLOCKSTRING:
- inputValueDefinition.Description = p.parseDescription()
- case keyword.IDENT:
- break
- default:
- p.errUnexpectedToken(p.read())
- return -1
- }
-
- inputValueDefinition.Name = p.read().Literal
- inputValueDefinition.Colon = p.mustRead(keyword.COLON).TextPosition
- inputValueDefinition.Type = p.ParseType()
- if p.peekEquals(keyword.EQUALS) {
- equals := p.read()
- inputValueDefinition.DefaultValue.IsDefined = true
- inputValueDefinition.DefaultValue.Equals = equals.TextPosition
- inputValueDefinition.DefaultValue.Value = p.ParseValue()
- }
- if p.peekEquals(keyword.AT) {
- inputValueDefinition.Directives = p.parseDirectiveList()
- inputValueDefinition.HasDirectives = len(inputValueDefinition.Directives.Refs) > 0
- }
-
- p.document.InputValueDefinitions = append(p.document.InputValueDefinitions, inputValueDefinition)
- return len(p.document.InputValueDefinitions) - 1
-}
-
-func (p *Parser) parseInputObjectTypeDefinition(description *ast.Description) {
- var inputObjectTypeDefinition ast.InputObjectTypeDefinition
- if description != nil {
- inputObjectTypeDefinition.Description = *description
- }
- inputObjectTypeDefinition.InputLiteral = p.mustReadIdentKey(identkeyword.INPUT).TextPosition
- inputObjectTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- inputObjectTypeDefinition.Directives = p.parseDirectiveList()
- inputObjectTypeDefinition.HasDirectives = len(inputObjectTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- inputObjectTypeDefinition.InputFieldsDefinition = p.parseInputValueDefinitionList(keyword.RBRACE)
- inputObjectTypeDefinition.HasInputFieldsDefinition = len(inputObjectTypeDefinition.InputFieldsDefinition.Refs) > 0
- }
- p.document.InputObjectTypeDefinitions = append(p.document.InputObjectTypeDefinitions, inputObjectTypeDefinition)
- ref := len(p.document.InputObjectTypeDefinitions) - 1
- node := ast.Node{
- Kind: ast.NodeKindInputObjectTypeDefinition,
- Ref: ref,
- }
- if p.shouldIndex {
- p.indexNode(inputObjectTypeDefinition.Name, node)
- }
- p.document.RootNodes = append(p.document.RootNodes, node)
-}
-
-func (p *Parser) parseScalarTypeDefinition(description *ast.Description) {
- var scalarTypeDefinition ast.ScalarTypeDefinition
- if description != nil {
- scalarTypeDefinition.Description = *description
- }
- scalarTypeDefinition.ScalarLiteral = p.mustReadIdentKey(identkeyword.SCALAR).TextPosition
- scalarTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- scalarTypeDefinition.Directives = p.parseDirectiveList()
- scalarTypeDefinition.HasDirectives = len(scalarTypeDefinition.Directives.Refs) > 0
- }
- p.document.ScalarTypeDefinitions = append(p.document.ScalarTypeDefinitions, scalarTypeDefinition)
- ref := len(p.document.ScalarTypeDefinitions) - 1
- node := ast.Node{
- Kind: ast.NodeKindScalarTypeDefinition,
- Ref: ref,
- }
- if p.shouldIndex {
- p.indexNode(scalarTypeDefinition.Name, node)
- }
- p.document.RootNodes = append(p.document.RootNodes, node)
-}
-
-func (p *Parser) parseInterfaceTypeDefinition(description *ast.Description) {
- var interfaceTypeDefinition ast.InterfaceTypeDefinition
- if description != nil {
- interfaceTypeDefinition.Description = *description
- }
- interfaceTypeDefinition.InterfaceLiteral = p.mustReadIdentKey(identkeyword.INTERFACE).TextPosition
- interfaceTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- interfaceTypeDefinition.Directives = p.parseDirectiveList()
- interfaceTypeDefinition.HasDirectives = len(interfaceTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- interfaceTypeDefinition.FieldsDefinition = p.parseFieldDefinitionList()
- interfaceTypeDefinition.HasFieldDefinitions = len(interfaceTypeDefinition.FieldsDefinition.Refs) > 0
- }
- p.document.InterfaceTypeDefinitions = append(p.document.InterfaceTypeDefinitions, interfaceTypeDefinition)
- ref := len(p.document.InterfaceTypeDefinitions) - 1
- node := ast.Node{
- Kind: ast.NodeKindInterfaceTypeDefinition,
- Ref: ref,
- }
- if p.shouldIndex {
- p.indexNode(interfaceTypeDefinition.Name, node)
- }
- p.document.RootNodes = append(p.document.RootNodes, node)
-}
-
-func (p *Parser) parseUnionTypeDefinition(description *ast.Description) {
- var unionTypeDefinition ast.UnionTypeDefinition
- if description != nil {
- unionTypeDefinition.Description = *description
- }
- unionTypeDefinition.UnionLiteral = p.mustReadIdentKey(identkeyword.UNION).TextPosition
- unionTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- unionTypeDefinition.Directives = p.parseDirectiveList()
- unionTypeDefinition.HasDirectives = len(unionTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.EQUALS) {
- unionTypeDefinition.Equals = p.mustRead(keyword.EQUALS).TextPosition
- unionTypeDefinition.UnionMemberTypes = p.parseUnionMemberTypes()
- unionTypeDefinition.HasUnionMemberTypes = len(unionTypeDefinition.UnionMemberTypes.Refs) > 0
- }
- p.document.UnionTypeDefinitions = append(p.document.UnionTypeDefinitions, unionTypeDefinition)
- ref := len(p.document.UnionTypeDefinitions) - 1
- node := ast.Node{
- Kind: ast.NodeKindUnionTypeDefinition,
- Ref: ref,
- }
- if p.shouldIndex {
- p.indexNode(unionTypeDefinition.Name, node)
- }
- p.document.RootNodes = append(p.document.RootNodes, node)
-}
-
-func (p *Parser) parseUnionMemberTypes() (list ast.TypeList) {
-
- acceptPipe := true
- acceptIdent := true
- expectNext := true
-
- for {
- next := p.peek()
- switch next {
- case keyword.PIPE:
- if acceptPipe {
- acceptPipe = false
- acceptIdent = true
- expectNext = true
- p.read()
- } else {
- p.errUnexpectedToken(p.read())
- return
- }
- case keyword.IDENT:
- if acceptIdent {
- acceptPipe = true
- acceptIdent = false
- expectNext = false
-
- ident := p.read()
-
- namedType := ast.Type{
- TypeKind: ast.TypeKindNamed,
- Name: ident.Literal,
- }
-
- p.document.Types = append(p.document.Types, namedType)
- ref := len(p.document.Types) - 1
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
- list.Refs = append(list.Refs, ref)
- } else {
- return
- }
- default:
- if expectNext {
- p.errUnexpectedToken(p.read())
- }
- return
- }
-
- if p.report.HasErrors() {
- return
- }
- }
-}
-
-func (p *Parser) parseEnumTypeDefinition(description *ast.Description) {
- var enumTypeDefinition ast.EnumTypeDefinition
- if description != nil {
- enumTypeDefinition.Description = *description
- }
- enumTypeDefinition.EnumLiteral = p.mustReadIdentKey(identkeyword.ENUM).TextPosition
- enumTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- enumTypeDefinition.Directives = p.parseDirectiveList()
- enumTypeDefinition.HasDirectives = len(enumTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- enumTypeDefinition.EnumValuesDefinition = p.parseEnumValueDefinitionList()
- enumTypeDefinition.HasEnumValuesDefinition = len(enumTypeDefinition.EnumValuesDefinition.Refs) > 0
- }
- p.document.EnumTypeDefinitions = append(p.document.EnumTypeDefinitions, enumTypeDefinition)
- ref := len(p.document.EnumTypeDefinitions) - 1
- node := ast.Node{
- Kind: ast.NodeKindEnumTypeDefinition,
- Ref: ref,
- }
- if p.shouldIndex {
- p.indexNode(enumTypeDefinition.Name, node)
- }
- p.document.RootNodes = append(p.document.RootNodes, node)
-}
-
-func (p *Parser) parseEnumValueDefinitionList() (list ast.EnumValueDefinitionList) {
-
- list.LBRACE = p.mustRead(keyword.LBRACE).TextPosition
-
- for {
- next := p.peek()
- switch next {
- case keyword.STRING, keyword.BLOCKSTRING, keyword.IDENT:
- ref := p.parseEnumValueDefinition()
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
- list.Refs = append(list.Refs, ref)
- case keyword.RBRACE:
- list.RBRACE = p.read().TextPosition
- return
- default:
- p.errUnexpectedToken(p.read())
- return
- }
-
- if p.report.HasErrors() {
- return
- }
- }
-}
-
-func (p *Parser) parseEnumValueDefinition() int {
- var enumValueDefinition ast.EnumValueDefinition
- next := p.peek()
- switch next {
- case keyword.STRING, keyword.BLOCKSTRING:
- enumValueDefinition.Description = p.parseDescription()
- case keyword.IDENT:
- break
- default:
- p.errUnexpectedToken(p.read())
- return -1
- }
-
- enumValueDefinition.EnumValue = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- enumValueDefinition.Directives = p.parseDirectiveList()
- enumValueDefinition.HasDirectives = len(enumValueDefinition.Directives.Refs) > 0
- }
-
- p.document.EnumValueDefinitions = append(p.document.EnumValueDefinitions, enumValueDefinition)
- return len(p.document.EnumValueDefinitions) - 1
-}
-
-func (p *Parser) parseDirectiveDefinition(description *ast.Description) {
- var directiveDefinition ast.DirectiveDefinition
- if description != nil {
- directiveDefinition.Description = *description
- }
- directiveDefinition.DirectiveLiteral = p.mustReadIdentKey(identkeyword.DIRECTIVE).TextPosition
- directiveDefinition.At = p.mustRead(keyword.AT).TextPosition
- directiveDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.LPAREN) {
- directiveDefinition.ArgumentsDefinition = p.parseInputValueDefinitionList(keyword.RPAREN)
- directiveDefinition.HasArgumentsDefinitions = len(directiveDefinition.ArgumentsDefinition.Refs) > 0
- }
- directiveDefinition.On = p.mustReadIdentKey(identkeyword.ON).TextPosition
- p.parseDirectiveLocations(&directiveDefinition.DirectiveLocations)
- p.document.DirectiveDefinitions = append(p.document.DirectiveDefinitions, directiveDefinition)
- ref := len(p.document.DirectiveDefinitions) - 1
- node := ast.Node{
- Kind: ast.NodeKindDirectiveDefinition,
- Ref: ref,
- }
- if p.shouldIndex {
- p.indexNode(directiveDefinition.Name, node)
- }
- p.document.RootNodes = append(p.document.RootNodes, node)
-}
-
-func (p *Parser) parseDirectiveLocations(locations *ast.DirectiveLocations) {
- acceptPipe := true
- acceptIdent := true
- expectNext := true
- for {
- next := p.peek()
- switch next {
- case keyword.IDENT:
- if acceptIdent {
- acceptIdent = false
- acceptPipe = true
- expectNext = false
-
- ident := p.read()
- raw := p.document.Input.ByteSlice(ident.Literal)
- err := locations.SetFromRaw(raw)
- if err != nil {
- p.report.AddExternalError(operationreport.ExternalError{
- Message: fmt.Sprintf("invalid directive location: %s", unsafebytes.BytesToString(raw)),
- Locations: []operationreport.Location{
- {
- Line: ident.TextPosition.LineStart,
- Column: ident.TextPosition.CharStart,
- },
- },
- })
- if p.reportInternalErrors {
- p.report.AddInternalError(err)
- }
- return
- }
-
- } else {
- return
- }
- case keyword.PIPE:
- if acceptPipe {
- acceptPipe = false
- acceptIdent = true
- expectNext = true
- p.read()
- } else {
- p.errUnexpectedToken(p.read())
- return
- }
- default:
- if expectNext {
- p.errUnexpectedToken(p.read())
- }
- return
- }
-
- if p.report.HasErrors() {
- return
- }
- }
-}
-
-func (p *Parser) parseSelectionSet() (int, bool) {
-
- var set ast.SelectionSet
-
- set.SelectionRefs = p.document.Refs[p.document.NextRefIndex()][:0]
- set.LBrace = p.tokens[p.mustNext(keyword.LBRACE)].TextPosition
-
- for {
- switch p.peek() {
- case keyword.RBRACE:
- set.RBrace = p.tokens[p.next()].TextPosition
-
- if len(set.SelectionRefs) == 0 {
- return 0, false
- }
-
- p.document.SelectionSets = append(p.document.SelectionSets, set)
- return len(p.document.SelectionSets) - 1, true
-
- case keyword.IDENT, keyword.SPREAD:
- if cap(set.SelectionRefs) == 0 {
- set.SelectionRefs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
- ref := p.parseSelection()
- set.SelectionRefs = append(set.SelectionRefs, ref)
- default:
- p.errUnexpectedToken(p.read(), keyword.RBRACE, keyword.IDENT, keyword.SPREAD)
- }
-
- if p.report.HasErrors() {
- return -1, false
- }
- }
-}
-
-func (p *Parser) parseSelection() int {
- next := p.peek()
- switch next {
- case keyword.IDENT:
- p.document.Selections = append(p.document.Selections, ast.Selection{
- Kind: ast.SelectionKindField,
- Ref: p.parseField(),
- })
- return len(p.document.Selections) - 1
- case keyword.SPREAD:
- return p.parseFragmentSelection(p.tokens[p.next()].TextPosition)
- default:
- p.errUnexpectedToken(p.tokens[p.next()], keyword.IDENT, keyword.SPREAD)
- return -1
- }
-}
-
-func (p *Parser) parseFragmentSelection(spread position.Position) int {
-
- var selection ast.Selection
-
- next, literal := p.peekLiteral()
- switch next {
- case keyword.LBRACE, keyword.AT:
- selection.Kind = ast.SelectionKindInlineFragment
- selection.Ref = p.parseInlineFragment(spread)
- case keyword.IDENT:
- key := p.identKeywordSliceRef(literal)
- switch key {
- case identkeyword.ON:
- selection.Kind = ast.SelectionKindInlineFragment
- selection.Ref = p.parseInlineFragment(spread)
- default:
- selection.Kind = ast.SelectionKindFragmentSpread
- selection.Ref = p.parseFragmentSpread(spread)
- }
- default:
- p.errUnexpectedToken(p.tokens[p.next()], keyword.IDENT)
- }
-
- p.document.Selections = append(p.document.Selections, selection)
- return len(p.document.Selections) - 1
-}
-
-func (p *Parser) parseField() int {
-
- var field ast.Field
-
- firstIdent := p.next()
- if p.tokens[firstIdent].Keyword != keyword.IDENT {
- p.errUnexpectedToken(p.tokens[firstIdent], keyword.IDENT)
- }
-
- if p.peek() == keyword.COLON {
- field.Alias.IsDefined = true
- field.Alias.Name = p.tokens[firstIdent].Literal
- field.Alias.Colon = p.tokens[p.next()].TextPosition
- field.Name = p.tokens[p.mustNext(keyword.IDENT)].Literal
- } else {
- field.Name = p.tokens[firstIdent].Literal
- }
-
- if p.peekEquals(keyword.LPAREN) {
- field.Arguments = p.parseArgumentList()
- field.HasArguments = len(field.Arguments.Refs) > 0
- }
- if p.peekEquals(keyword.AT) {
- field.Directives = p.parseDirectiveList()
- field.HasDirectives = len(field.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- field.SelectionSet, field.HasSelections = p.parseSelectionSet()
- }
-
- p.document.Fields = append(p.document.Fields, field)
- return len(p.document.Fields) - 1
-}
-
-func (p *Parser) parseFragmentSpread(spread position.Position) int {
- var fragmentSpread ast.FragmentSpread
- fragmentSpread.Spread = spread
- fragmentSpread.FragmentName = p.mustReadExceptIdentKey(identkeyword.ON).Literal
- if p.peekEquals(keyword.AT) {
- fragmentSpread.Directives = p.parseDirectiveList()
- fragmentSpread.HasDirectives = len(fragmentSpread.Directives.Refs) > 0
- }
- p.document.FragmentSpreads = append(p.document.FragmentSpreads, fragmentSpread)
- return len(p.document.FragmentSpreads) - 1
-}
-
-func (p *Parser) parseInlineFragment(spread position.Position) int {
- fragment := ast.InlineFragment{
- TypeCondition: ast.TypeCondition{
- Type: -1,
- },
- }
- fragment.Spread = spread
- if p.peekEqualsIdentKey(identkeyword.ON) {
- fragment.TypeCondition = p.parseTypeCondition()
- }
- if p.peekEquals(keyword.AT) {
- fragment.Directives = p.parseDirectiveList()
- fragment.HasDirectives = len(fragment.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- fragment.SelectionSet, fragment.HasSelections = p.parseSelectionSet()
- }
- p.document.InlineFragments = append(p.document.InlineFragments, fragment)
- return len(p.document.InlineFragments) - 1
-}
-
-func (p *Parser) parseTypeCondition() (typeCondition ast.TypeCondition) {
- typeCondition.On = p.mustReadIdentKey(identkeyword.ON).TextPosition
- typeCondition.Type = p.parseNamedType()
- return
-}
-
-func (p *Parser) parseOperationDefinition() {
-
- var operationDefinition ast.OperationDefinition
-
- next, literal := p.peekLiteral()
- switch next {
- case keyword.IDENT:
- key := p.identKeywordSliceRef(literal)
- switch key {
- case identkeyword.QUERY:
- operationDefinition.OperationTypeLiteral = p.read().TextPosition
- operationDefinition.OperationType = ast.OperationTypeQuery
- case identkeyword.MUTATION:
- operationDefinition.OperationTypeLiteral = p.read().TextPosition
- operationDefinition.OperationType = ast.OperationTypeMutation
- case identkeyword.SUBSCRIPTION:
- operationDefinition.OperationTypeLiteral = p.read().TextPosition
- operationDefinition.OperationType = ast.OperationTypeSubscription
- default:
- p.errUnexpectedIdentKey(p.read(), key, identkeyword.QUERY, identkeyword.MUTATION, identkeyword.SUBSCRIPTION)
- return
- }
- case keyword.LBRACE:
- operationDefinition.OperationType = ast.OperationTypeQuery
- operationDefinition.SelectionSet, operationDefinition.HasSelections = p.parseSelectionSet()
- p.document.OperationDefinitions = append(p.document.OperationDefinitions, operationDefinition)
- ref := len(p.document.OperationDefinitions) - 1
- rootNode := ast.Node{
- Kind: ast.NodeKindOperationDefinition,
- Ref: ref,
- }
- p.document.RootNodes = append(p.document.RootNodes, rootNode)
- return
- default:
- p.errUnexpectedToken(p.read(), keyword.IDENT, keyword.LBRACE)
- return
- }
-
- if p.peekEquals(keyword.IDENT) {
- operationDefinition.Name = p.read().Literal
- }
- if p.peekEquals(keyword.LPAREN) {
- operationDefinition.VariableDefinitions = p.parseVariableDefinitionList()
- operationDefinition.HasVariableDefinitions = len(operationDefinition.VariableDefinitions.Refs) > 0
- }
- if p.peekEquals(keyword.AT) {
- operationDefinition.Directives = p.parseDirectiveList()
- operationDefinition.HasDirectives = len(operationDefinition.Directives.Refs) > 0
- }
-
- operationDefinition.SelectionSet, operationDefinition.HasSelections = p.parseSelectionSet()
-
- p.document.OperationDefinitions = append(p.document.OperationDefinitions, operationDefinition)
- ref := len(p.document.OperationDefinitions) - 1
- rootNode := ast.Node{
- Kind: ast.NodeKindOperationDefinition,
- Ref: ref,
- }
- p.document.RootNodes = append(p.document.RootNodes, rootNode)
-}
-
-func (p *Parser) parseVariableDefinitionList() (list ast.VariableDefinitionList) {
-
- list.LPAREN = p.mustRead(keyword.LPAREN).TextPosition
-
- for {
- next := p.peek()
- switch next {
- case keyword.RPAREN:
- list.RPAREN = p.read().TextPosition
- return
- case keyword.DOLLAR:
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
- ref := p.parseVariableDefinition()
- if cap(list.Refs) == 0 {
- list.Refs = p.document.Refs[p.document.NextRefIndex()][:0]
- }
- list.Refs = append(list.Refs, ref)
- default:
- p.errUnexpectedToken(p.read(), keyword.RPAREN, keyword.DOLLAR)
- return
- }
-
- if p.report.HasErrors() {
- return
- }
- }
-}
-
-func (p *Parser) parseVariableDefinition() int {
-
- var variableDefinition ast.VariableDefinition
-
- variableDefinition.VariableValue.Kind = ast.ValueKindVariable
- variableDefinition.VariableValue.Ref = p.parseVariableValue()
-
- variableDefinition.Colon = p.mustRead(keyword.COLON).TextPosition
- variableDefinition.Type = p.ParseType()
- if p.peekEquals(keyword.EQUALS) {
- variableDefinition.DefaultValue = p.parseDefaultValue()
- }
- if p.peekEquals(keyword.AT) {
- variableDefinition.Directives = p.parseDirectiveList()
- variableDefinition.HasDirectives = len(variableDefinition.Directives.Refs) > 0
- }
- p.document.VariableDefinitions = append(p.document.VariableDefinitions, variableDefinition)
- return len(p.document.VariableDefinitions) - 1
-}
-
-func (p *Parser) parseDefaultValue() ast.DefaultValue {
- equals := p.mustRead(keyword.EQUALS).TextPosition
- value := p.ParseValue()
- return ast.DefaultValue{
- IsDefined: true,
- Equals: equals,
- Value: value,
- }
-}
-
-func (p *Parser) parseFragmentDefinition() {
- var fragmentDefinition ast.FragmentDefinition
- fragmentDefinition.FragmentLiteral = p.mustReadIdentKey(identkeyword.FRAGMENT).TextPosition
- fragmentDefinition.Name = p.mustRead(keyword.IDENT).Literal
- fragmentDefinition.TypeCondition = p.parseTypeCondition()
- if p.peekEquals(keyword.AT) {
- fragmentDefinition.Directives = p.parseDirectiveList()
- }
- fragmentDefinition.SelectionSet, fragmentDefinition.HasSelections = p.parseSelectionSet()
- p.document.FragmentDefinitions = append(p.document.FragmentDefinitions, fragmentDefinition)
-
- ref := len(p.document.FragmentDefinitions) - 1
- p.document.RootNodes = append(p.document.RootNodes, ast.Node{
- Kind: ast.NodeKindFragmentDefinition,
- Ref: ref,
- })
-}
-
-func (p *Parser) parseExtension() {
- extend := p.mustReadIdentKey(identkeyword.EXTEND).TextPosition
- next, literal := p.peekLiteral()
-
- if next != keyword.IDENT {
- p.errUnexpectedToken(p.read(), keyword.IDENT)
- return
- }
-
- key := p.identKeywordSliceRef(literal)
-
- switch key {
- case identkeyword.SCHEMA:
- p.parseSchemaExtension(extend)
- case identkeyword.TYPE:
- p.parseObjectTypeExtension(extend)
- case identkeyword.INTERFACE:
- p.parseInterfaceTypeExtension(extend)
- case identkeyword.SCALAR:
- p.parseScalarTypeExtension(extend)
- case identkeyword.UNION:
- p.parseUnionTypeExtension(extend)
- case identkeyword.ENUM:
- p.parseEnumTypeExtension(extend)
- case identkeyword.INPUT:
- p.parseInputObjectTypeExtension(extend)
- default:
- p.errUnexpectedIdentKey(p.read(), key, identkeyword.SCHEMA, identkeyword.TYPE, identkeyword.INTERFACE, identkeyword.SCALAR, identkeyword.UNION, identkeyword.ENUM, identkeyword.INPUT)
- }
-}
-
-func (p *Parser) parseSchemaExtension(extend position.Position) {
- schemaLiteral := p.read()
- schemaDefinition := ast.SchemaDefinition{
- SchemaLiteral: schemaLiteral.TextPosition,
- }
- if p.peekEquals(keyword.AT) {
- schemaDefinition.Directives = p.parseDirectiveList()
- schemaDefinition.HasDirectives = len(schemaDefinition.Directives.Refs) > 0
- }
- p.parseRootOperationTypeDefinitionList(&schemaDefinition.RootOperationTypeDefinitions)
-
- schemaExtension := ast.SchemaExtension{
- ExtendLiteral: extend,
- SchemaDefinition: schemaDefinition,
- }
- p.document.SchemaExtensions = append(p.document.SchemaExtensions, schemaExtension)
- ref := len(p.document.SchemaExtensions) - 1
- p.document.RootNodes = append(p.document.RootNodes, ast.Node{Ref: ref, Kind: ast.NodeKindSchemaExtension})
-}
-
-func (p *Parser) parseObjectTypeExtension(extend position.Position) {
- var objectTypeDefinition ast.ObjectTypeDefinition
- objectTypeDefinition.TypeLiteral = p.mustReadIdentKey(identkeyword.TYPE).TextPosition
- objectTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEqualsIdentKey(identkeyword.IMPLEMENTS) {
- objectTypeDefinition.ImplementsInterfaces = p.parseImplementsInterfaces()
- }
- if p.peekEquals(keyword.AT) {
- objectTypeDefinition.Directives = p.parseDirectiveList()
- objectTypeDefinition.HasDirectives = len(objectTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- objectTypeDefinition.FieldsDefinition = p.parseFieldDefinitionList()
- objectTypeDefinition.HasFieldDefinitions = len(objectTypeDefinition.FieldsDefinition.Refs) > 0
- }
- objectTypeExtension := ast.ObjectTypeExtension{
- ExtendLiteral: extend,
- ObjectTypeDefinition: objectTypeDefinition,
- }
- p.document.ObjectTypeExtensions = append(p.document.ObjectTypeExtensions, objectTypeExtension)
- ref := len(p.document.ObjectTypeExtensions) - 1
- node := ast.Node{Ref: ref, Kind: ast.NodeKindObjectTypeExtension}
- p.document.RootNodes = append(p.document.RootNodes, node)
-
- if p.shouldIndex {
- p.indexNode(objectTypeDefinition.Name, node)
- }
-}
-
-func (p *Parser) parseInterfaceTypeExtension(extend position.Position) {
- var interfaceTypeDefinition ast.InterfaceTypeDefinition
- interfaceTypeDefinition.InterfaceLiteral = p.mustReadIdentKey(identkeyword.INTERFACE).TextPosition
- interfaceTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- interfaceTypeDefinition.Directives = p.parseDirectiveList()
- interfaceTypeDefinition.HasDirectives = len(interfaceTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- interfaceTypeDefinition.FieldsDefinition = p.parseFieldDefinitionList()
- interfaceTypeDefinition.HasFieldDefinitions = len(interfaceTypeDefinition.FieldsDefinition.Refs) > 0
- }
- interfaceTypeExtension := ast.InterfaceTypeExtension{
- ExtendLiteral: extend,
- InterfaceTypeDefinition: interfaceTypeDefinition,
- }
- p.document.InterfaceTypeExtensions = append(p.document.InterfaceTypeExtensions, interfaceTypeExtension)
- ref := len(p.document.InterfaceTypeExtensions) - 1
- p.document.RootNodes = append(p.document.RootNodes, ast.Node{Ref: ref, Kind: ast.NodeKindInterfaceTypeExtension})
-}
-
-func (p *Parser) parseScalarTypeExtension(extend position.Position) {
- var scalarTypeDefinition ast.ScalarTypeDefinition
- scalarTypeDefinition.ScalarLiteral = p.mustReadIdentKey(identkeyword.SCALAR).TextPosition
- scalarTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- scalarTypeDefinition.Directives = p.parseDirectiveList()
- scalarTypeDefinition.HasDirectives = len(scalarTypeDefinition.Directives.Refs) > 0
- }
- scalarTypeExtension := ast.ScalarTypeExtension{
- ExtendLiteral: extend,
- ScalarTypeDefinition: scalarTypeDefinition,
- }
- p.document.ScalarTypeExtensions = append(p.document.ScalarTypeExtensions, scalarTypeExtension)
- ref := len(p.document.ScalarTypeExtensions) - 1
- p.document.RootNodes = append(p.document.RootNodes, ast.Node{Ref: ref, Kind: ast.NodeKindScalarTypeExtension})
-}
-
-func (p *Parser) parseUnionTypeExtension(extend position.Position) {
- var unionTypeDefinition ast.UnionTypeDefinition
- unionTypeDefinition.UnionLiteral = p.mustReadIdentKey(identkeyword.UNION).TextPosition
- unionTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- unionTypeDefinition.Directives = p.parseDirectiveList()
- unionTypeDefinition.HasDirectives = len(unionTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.EQUALS) {
- unionTypeDefinition.Equals = p.mustRead(keyword.EQUALS).TextPosition
- unionTypeDefinition.UnionMemberTypes = p.parseUnionMemberTypes()
- unionTypeDefinition.HasUnionMemberTypes = len(unionTypeDefinition.UnionMemberTypes.Refs) > 0
- }
- unionTypeExtension := ast.UnionTypeExtension{
- ExtendLiteral: extend,
- UnionTypeDefinition: unionTypeDefinition,
- }
- p.document.UnionTypeExtensions = append(p.document.UnionTypeExtensions, unionTypeExtension)
- ref := len(p.document.UnionTypeExtensions) - 1
- p.document.RootNodes = append(p.document.RootNodes, ast.Node{Ref: ref, Kind: ast.NodeKindUnionTypeExtension})
-}
-
-func (p *Parser) parseEnumTypeExtension(extend position.Position) {
- var enumTypeDefinition ast.EnumTypeDefinition
- enumTypeDefinition.EnumLiteral = p.mustReadIdentKey(identkeyword.ENUM).TextPosition
- enumTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- enumTypeDefinition.Directives = p.parseDirectiveList()
- enumTypeDefinition.HasDirectives = len(enumTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- enumTypeDefinition.EnumValuesDefinition = p.parseEnumValueDefinitionList()
- enumTypeDefinition.HasEnumValuesDefinition = len(enumTypeDefinition.EnumValuesDefinition.Refs) > 0
- }
- enumTypeExtension := ast.EnumTypeExtension{
- ExtendLiteral: extend,
- EnumTypeDefinition: enumTypeDefinition,
- }
- p.document.EnumTypeExtensions = append(p.document.EnumTypeExtensions, enumTypeExtension)
- ref := len(p.document.EnumTypeExtensions) - 1
- p.document.RootNodes = append(p.document.RootNodes, ast.Node{Ref: ref, Kind: ast.NodeKindEnumTypeExtension})
-}
-
-func (p *Parser) parseInputObjectTypeExtension(extend position.Position) {
- var inputObjectTypeDefinition ast.InputObjectTypeDefinition
- inputObjectTypeDefinition.InputLiteral = p.mustReadIdentKey(identkeyword.INPUT).TextPosition
- inputObjectTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal
- if p.peekEquals(keyword.AT) {
- inputObjectTypeDefinition.Directives = p.parseDirectiveList()
- inputObjectTypeDefinition.HasDirectives = len(inputObjectTypeDefinition.Directives.Refs) > 0
- }
- if p.peekEquals(keyword.LBRACE) {
- inputObjectTypeDefinition.InputFieldsDefinition = p.parseInputValueDefinitionList(keyword.RBRACE)
- inputObjectTypeDefinition.HasInputFieldsDefinition = len(inputObjectTypeDefinition.InputFieldsDefinition.Refs) > 0
- }
- inputObjectTypeExtension := ast.InputObjectTypeExtension{
- ExtendLiteral: extend,
- InputObjectTypeDefinition: inputObjectTypeDefinition,
- }
- p.document.InputObjectTypeExtensions = append(p.document.InputObjectTypeExtensions, inputObjectTypeExtension)
- ref := len(p.document.InputObjectTypeExtensions) - 1
- p.document.RootNodes = append(p.document.RootNodes, ast.Node{Ref: ref, Kind: ast.NodeKindInputObjectTypeExtension})
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astprinter/astprinter.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astprinter/astprinter.go
deleted file mode 100644
index e397c6057e6..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astprinter/astprinter.go
+++ /dev/null
@@ -1,1018 +0,0 @@
-// Package astprinter takes a GraphQL document and prints it as a String with optional indentation.
-package astprinter
-
-import (
- "bytes"
- "io"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-// Print takes a document as well as a definition (optional) and prints it to the io.Writer.
-// The definition is only necessary in case a GraphQL Operation should be printed.
-func Print(document, definition *ast.Document, out io.Writer) error {
- printer := Printer{}
- return printer.Print(document, definition, out)
-}
-
-// PrintIndent is the same as Print but accepts an additional indent parameter to set indentation.
-func PrintIndent(document, definition *ast.Document, indent []byte, out io.Writer) error {
- printer := Printer{
- indent: indent,
- }
- return printer.Print(document, definition, out)
-}
-
-// PrintString is the same as Print but returns a string instead of writing to an io.Writer
-func PrintString(document, definition *ast.Document) (string, error) {
- buff := &bytes.Buffer{}
- err := Print(document, definition, buff)
- out := buff.String()
- return out, err
-}
-
-// PrintStringIndent is the same as PrintIndent but returns a string instead of writing to an io.Writer
-func PrintStringIndent(document, definition *ast.Document, indent string) (string, error) {
- buff := &bytes.Buffer{}
- err := PrintIndent(document, definition, []byte(indent), buff)
- out := buff.String()
- return out, err
-}
-
-// Printer walks a GraphQL document and prints it as a string
-type Printer struct {
- indent []byte
- visitor printVisitor
- walker astvisitor.SimpleWalker
- registered bool
-}
-
-// Print starts the actual AST printing
-// Keep a printer and re-use it in case you'd like to print ASTs in the hot path.
-func (p *Printer) Print(document, definition *ast.Document, out io.Writer) error {
- p.visitor.indent = p.indent
- p.visitor.err = nil
- p.visitor.document = document
- p.visitor.out = out
- p.visitor.SimpleWalker = &p.walker
- if !p.registered {
- p.walker.SetVisitor(&p.visitor)
- }
- return p.walker.Walk(p.visitor.document, definition)
-}
-
-type printVisitor struct {
- *astvisitor.SimpleWalker
- document *ast.Document
- out io.Writer
- err error
-
- indent []byte
- inputValueDefinitionOpener []byte
- inputValueDefinitionCloser []byte
- isFirstDirectiveLocation bool
-}
-
-func (p *printVisitor) write(data []byte) {
- if p.err != nil {
- return
- }
- _, p.err = p.out.Write(data)
-}
-
-func (p *printVisitor) indentationDepth() (depth int) {
-
- if len(p.Ancestors) == 0 {
- return 0
- }
-
- switch p.Ancestors[0].Kind {
- case ast.NodeKindOperationDefinition,
- ast.NodeKindFragmentDefinition:
- default:
- return 2
- }
-
- for i := range p.Ancestors {
- if p.Ancestors[i].Kind == ast.NodeKindSelectionSet {
- depth += 2
- }
- }
-
- return depth
-}
-
-func (p *printVisitor) writeIndented(data []byte) {
- if p.err != nil {
- return
- }
- depth := p.indentationDepth()
- for i := 0; i < depth; i++ {
- _, p.err = p.out.Write(p.indent)
- }
- _, p.err = p.out.Write(data)
-}
-
-func (p *printVisitor) must(err error) {
- if p.err != nil {
- return
- }
- p.err = err
-}
-
-func (p *printVisitor) EnterDirective(ref int) {
- if p.document.DirectiveIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) {
- switch p.Ancestors[len(p.Ancestors)-1].Kind {
- case ast.NodeKindFieldDefinition:
- p.writeFieldType(p.Ancestors[len(p.Ancestors)-1].Ref)
- p.write(literal.SPACE)
- case ast.NodeKindEnumValueDefinition,
- ast.NodeKindInputValueDefinition:
- p.write(literal.SPACE)
- }
- }
-
- p.write(literal.AT)
- p.write(p.document.DirectiveNameBytes(ref))
-}
-
-func (p *printVisitor) LeaveDirective(ref int) {
- if !p.document.DirectiveIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) {
- p.write(literal.SPACE)
- return
- }
-
- ancestor := p.Ancestors[len(p.Ancestors)-1]
- switch ancestor.Kind {
- case ast.NodeKindField:
- if p.document.FieldHasSelections(ancestor.Ref) {
- p.write(literal.SPACE)
- } else if len(p.SelectionsAfter) > 0 {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
- case ast.NodeKindVariableDefinition:
- if !p.document.VariableDefinitionsAfter(ancestor.Ref) {
- p.write(literal.SPACE)
- }
- case ast.NodeKindInlineFragment:
- if len(p.SelectionsAfter) > 0 {
- p.write(literal.SPACE)
- }
- case ast.NodeKindScalarTypeDefinition,
- ast.NodeKindScalarTypeExtension,
- ast.NodeKindUnionTypeDefinition,
- ast.NodeKindUnionTypeExtension,
- ast.NodeKindEnumTypeDefinition,
- ast.NodeKindEnumTypeExtension,
- ast.NodeKindEnumValueDefinition,
- ast.NodeKindFieldDefinition,
- ast.NodeKindInputValueDefinition:
- return
- default:
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) EnterVariableDefinition(ref int) {
- if !p.document.VariableDefinitionsBefore(ref) {
- p.write(literal.LPAREN)
- }
-
- p.must(p.document.PrintValue(p.document.VariableDefinitions[ref].VariableValue, p.out))
- p.write(literal.COLON)
- p.write(literal.SPACE)
-
- p.must(p.document.PrintType(p.document.VariableDefinitions[ref].Type, p.out))
-
- if p.document.VariableDefinitions[ref].DefaultValue.IsDefined {
- p.write(literal.SPACE)
- p.write(literal.EQUALS)
- p.write(literal.SPACE)
- p.must(p.document.PrintValue(p.document.VariableDefinitions[ref].DefaultValue.Value, p.out))
- }
-
- if p.document.VariableDefinitions[ref].HasDirectives {
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) LeaveVariableDefinition(ref int) {
- if !p.document.VariableDefinitionsAfter(ref) {
- p.write(literal.RPAREN)
- } else {
- p.write(literal.COMMA)
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) EnterArgument(ref int) {
- if len(p.document.ArgumentsBefore(p.Ancestors[len(p.Ancestors)-1], ref)) == 0 {
- p.write(literal.LPAREN)
- } else {
- p.write(literal.COMMA)
- p.write(literal.SPACE)
- }
- p.must(p.document.PrintArgument(ref, p.out))
-}
-
-func (p *printVisitor) LeaveArgument(ref int) {
- if len(p.document.ArgumentsAfter(p.Ancestors[len(p.Ancestors)-1], ref)) == 0 {
- p.write(literal.RPAREN)
- }
-}
-
-func (p *printVisitor) EnterOperationDefinition(ref int) {
-
- hasName := p.document.OperationDefinitions[ref].Name.Length() > 0
- hasVariables := p.document.OperationDefinitions[ref].HasVariableDefinitions
-
- switch p.document.OperationDefinitions[ref].OperationType {
- case ast.OperationTypeQuery:
- if hasName || hasVariables {
- p.write(literal.QUERY)
- }
- case ast.OperationTypeMutation:
- p.write(literal.MUTATION)
- case ast.OperationTypeSubscription:
- p.write(literal.SUBSCRIPTION)
- }
-
- if hasName {
- p.write(literal.SPACE)
- }
-
- if hasName {
- p.write(p.document.Input.ByteSlice(p.document.OperationDefinitions[ref].Name))
- if !p.document.OperationDefinitions[ref].HasVariableDefinitions {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) LeaveOperationDefinition(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindOperationDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterSelectionSet(ref int) {
- p.write(literal.LBRACE)
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
-}
-
-func (p *printVisitor) LeaveSelectionSet(ref int) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- p.writeIndented(literal.RBRACE)
-}
-
-func (p *printVisitor) EnterField(ref int) {
- if p.document.Fields[ref].Alias.IsDefined {
- p.writeIndented(p.document.Input.ByteSlice(p.document.Fields[ref].Alias.Name))
- p.write(literal.COLON)
- p.write(literal.SPACE)
- p.write(p.document.Input.ByteSlice(p.document.Fields[ref].Name))
- } else {
- p.writeIndented(p.document.Input.ByteSlice(p.document.Fields[ref].Name))
- }
- if !p.document.FieldHasArguments(ref) && (p.document.FieldHasSelections(ref) || p.document.FieldHasDirectives(ref)) {
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) LeaveField(ref int) {
- if !p.document.FieldHasDirectives(ref) && len(p.SelectionsAfter) != 0 {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterFragmentSpread(ref int) {
- p.writeIndented(literal.SPREAD)
- p.write(p.document.Input.ByteSlice(p.document.FragmentSpreads[ref].FragmentName))
-}
-
-func (p *printVisitor) LeaveFragmentSpread(ref int) {
-
-}
-
-func (p *printVisitor) EnterInlineFragment(ref int) {
- p.writeIndented(literal.SPREAD)
- if p.document.InlineFragments[ref].TypeCondition.Type != -1 {
- p.write(literal.SPACE)
- p.write(literal.ON)
- p.write(literal.SPACE)
- p.write(p.document.Input.ByteSlice(p.document.Types[p.document.InlineFragments[ref].TypeCondition.Type].Name))
- p.write(literal.SPACE)
- } else if p.document.InlineFragments[ref].HasDirectives {
- p.write(literal.SPACE)
- }
-
-}
-
-func (p *printVisitor) LeaveInlineFragment(ref int) {
- ancestor := p.Ancestors[len(p.Ancestors)-1]
- if p.document.SelectionsAfterInlineFragment(ref, ancestor) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterFragmentDefinition(ref int) {
- p.write(literal.FRAGMENT)
- p.write(literal.SPACE)
- p.write(p.document.Input.ByteSlice(p.document.FragmentDefinitions[ref].Name))
- p.write(literal.SPACE)
- p.write(literal.ON)
- p.write(literal.SPACE)
- p.write(p.document.Input.ByteSlice(p.document.Types[p.document.FragmentDefinitions[ref].TypeCondition.Type].Name))
- p.write(literal.SPACE)
-
-}
-
-func (p *printVisitor) LeaveFragmentDefinition(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindFragmentDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterObjectTypeDefinition(ref int) {
-
- if p.document.ObjectTypeDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.ObjectTypeDefinitions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.TYPE)
- p.write(literal.SPACE)
- p.write(p.document.ObjectTypeDefinitionNameBytes(ref))
- p.write(literal.SPACE)
-
- if len(p.document.ObjectTypeDefinitions[ref].ImplementsInterfaces.Refs) != 0 {
- p.write(literal.IMPLEMENTS)
- p.write(literal.SPACE)
- for i, j := range p.document.ObjectTypeDefinitions[ref].ImplementsInterfaces.Refs {
- if i != 0 {
- p.write(literal.SPACE)
- p.write(literal.AND)
- p.write(literal.SPACE)
- }
- p.must(p.document.PrintType(j, p.out))
- }
- p.write(literal.SPACE)
- }
-
- p.inputValueDefinitionOpener = literal.LPAREN
- p.inputValueDefinitionCloser = literal.RPAREN
-}
-
-func (p *printVisitor) LeaveObjectTypeDefinition(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindObjectTypeDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterObjectTypeExtension(ref int) {
-
- if p.document.ObjectTypeExtensions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.ObjectTypeExtensions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.EXTEND)
- p.write(literal.SPACE)
- p.write(literal.TYPE)
- p.write(literal.SPACE)
- p.write(p.document.ObjectTypeExtensionNameBytes(ref))
- p.write(literal.SPACE)
-
- p.inputValueDefinitionOpener = literal.LPAREN
- p.inputValueDefinitionCloser = literal.RPAREN
-}
-
-func (p *printVisitor) LeaveObjectTypeExtension(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindObjectTypeExtension, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterFieldDefinition(ref int) {
- if p.document.FieldDefinitionIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) {
- p.write(literal.LBRACE)
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- }
- if p.document.FieldDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.FieldDefinitions[ref].Description, p.indent, p.indentationDepth(), p.out))
- p.write(literal.LINETERMINATOR)
- }
- p.writeIndented(p.document.FieldDefinitionNameBytes(ref))
-}
-
-func (p *printVisitor) LeaveFieldDefinition(ref int) {
- if !p.document.FieldDefinitionHasDirectives(ref) {
- p.writeFieldType(ref)
- }
-
- if p.document.FieldDefinitionIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- p.write(literal.RBRACE)
- } else {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterInputValueDefinition(ref int) {
- if p.document.InputValueDefinitionIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) {
- p.write(p.inputValueDefinitionOpener)
- }
- if p.indent != nil {
- switch p.Ancestors[len(p.Ancestors)-1].Kind {
- case ast.NodeKindDirectiveDefinition, ast.NodeKindInputObjectTypeDefinition, ast.NodeKindInputObjectTypeExtension:
- p.write(literal.LINETERMINATOR)
- }
- }
- if p.document.InputValueDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.InputValueDefinitions[ref].Description, p.indent, p.indentationDepth(), p.out))
- p.write(literal.LINETERMINATOR)
- }
- switch p.Ancestors[len(p.Ancestors)-1].Kind {
- case ast.NodeKindDirectiveDefinition, ast.NodeKindInputObjectTypeDefinition, ast.NodeKindInputObjectTypeExtension:
- p.writeIndented(p.document.InputValueDefinitionNameBytes(ref))
- default:
- p.write(p.document.InputValueDefinitionNameBytes(ref))
- }
- p.write(literal.COLON)
- p.write(literal.SPACE)
- p.must(p.document.PrintType(p.document.InputValueDefinitionType(ref), p.out))
- if p.document.InputValueDefinitionHasDefaultValue(ref) {
- p.write(literal.SPACE)
- p.write(literal.EQUALS)
- p.write(literal.SPACE)
- p.must(p.document.PrintValue(p.document.InputValueDefinitionDefaultValue(ref), p.out))
- }
-}
-
-func (p *printVisitor) LeaveInputValueDefinition(ref int) {
- if p.document.InputValueDefinitionIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) {
- if p.indent != nil {
- switch p.Ancestors[len(p.Ancestors)-1].Kind {
- case ast.NodeKindDirectiveDefinition, ast.NodeKindInputObjectTypeDefinition, ast.NodeKindInputObjectTypeExtension:
- p.write(literal.LINETERMINATOR)
- }
- }
- p.write(p.inputValueDefinitionCloser)
- } else {
- if len(p.Ancestors) > 0 {
- // check enclosing type kind
- if p.Ancestors[len(p.Ancestors)-1].Kind == ast.NodeKindFieldDefinition {
- p.write(literal.COMMA)
- p.write(literal.SPACE)
- } else if len(p.indent) == 0 {
- // add space between arguments when printing without indents
- p.write(literal.SPACE)
- }
- }
- }
-}
-
-func (p *printVisitor) EnterInterfaceTypeDefinition(ref int) {
-
- if p.document.InterfaceTypeDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.InterfaceTypeDefinitions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.INTERFACE)
- p.write(literal.SPACE)
- p.write(p.document.InterfaceTypeDefinitionNameBytes(ref))
- p.write(literal.SPACE)
-
- p.inputValueDefinitionOpener = literal.LPAREN
- p.inputValueDefinitionCloser = literal.RPAREN
-}
-
-func (p *printVisitor) LeaveInterfaceTypeDefinition(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindInterfaceTypeDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterInterfaceTypeExtension(ref int) {
-
- if p.document.InterfaceTypeExtensions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.InterfaceTypeExtensions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.EXTEND)
- p.write(literal.SPACE)
- p.write(literal.INTERFACE)
- p.write(literal.SPACE)
- p.write(p.document.InterfaceTypeExtensionNameBytes(ref))
- p.write(literal.SPACE)
-
- p.inputValueDefinitionOpener = literal.LPAREN
- p.inputValueDefinitionCloser = literal.RPAREN
-}
-
-func (p *printVisitor) LeaveInterfaceTypeExtension(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindInterfaceTypeExtension, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterScalarTypeDefinition(ref int) {
-
- if p.document.ScalarTypeDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.ScalarTypeDefinitions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.SCALAR)
- p.write(literal.SPACE)
- p.write(p.document.ScalarTypeDefinitionNameBytes(ref))
- if p.document.ScalarTypeDefinitionHasDirectives(ref) {
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) LeaveScalarTypeDefinition(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindScalarTypeDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterScalarTypeExtension(ref int) {
-
- if p.document.ScalarTypeExtensions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.ScalarTypeExtensions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.EXTEND)
- p.write(literal.SPACE)
- p.write(literal.SCALAR)
- p.write(literal.SPACE)
- p.write(p.document.ScalarTypeExtensionNameBytes(ref))
- if p.document.ScalarTypeExtensionHasDirectives(ref) {
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) LeaveScalarTypeExtension(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindScalarTypeExtension, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterUnionTypeDefinition(ref int) {
-
- if p.document.UnionTypeDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.UnionTypeDefinitions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.UNION)
- p.write(literal.SPACE)
- p.write(p.document.UnionTypeDefinitionNameBytes(ref))
- if p.document.UnionTypeDefinitionHasDirectives(ref) {
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) LeaveUnionTypeDefinition(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindUnionTypeDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterUnionTypeExtension(ref int) {
-
- if p.document.UnionTypeExtensions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.UnionTypeExtensions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.EXTEND)
- p.write(literal.SPACE)
- p.write(literal.UNION)
- p.write(literal.SPACE)
- p.write(p.document.UnionTypeExtensionNameBytes(ref))
- if p.document.UnionTypeExtensionHasDirectives(ref) {
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) LeaveUnionTypeExtension(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindUnionTypeExtension, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterUnionMemberType(ref int) {
- if p.document.UnionMemberTypeIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) {
- p.write(literal.SPACE)
- p.write(literal.EQUALS)
- p.write(literal.SPACE)
- }
- p.write(p.document.TypeNameBytes(ref))
- if !p.document.UnionMemberTypeIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) {
- p.write(literal.SPACE)
- p.write(literal.PIPE)
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) LeaveUnionMemberType(ref int) {
-
-}
-
-func (p *printVisitor) EnterEnumTypeDefinition(ref int) {
-
- if p.document.EnumTypeDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.EnumTypeDefinitions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.ENUM)
- p.write(literal.SPACE)
- p.write(p.document.EnumTypeDefinitionNameBytes(ref))
- if p.document.EnumTypeDefinitionHasDirectives(ref) {
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) LeaveEnumTypeDefinition(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindEnumTypeDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterEnumTypeExtension(ref int) {
-
- if p.document.EnumTypeExtensions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.EnumTypeExtensions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.EXTEND)
- p.write(literal.SPACE)
- p.write(literal.ENUM)
- p.write(literal.SPACE)
- p.write(p.document.EnumTypeExtensionNameBytes(ref))
- if p.document.EnumTypeExtensionHasDirectives(ref) {
- p.write(literal.SPACE)
- }
-}
-
-func (p *printVisitor) LeaveEnumTypeExtension(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindEnumTypeExtension, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterEnumValueDefinition(ref int) {
- if p.document.EnumValueDefinitionIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) {
- p.write(literal.SPACE)
- p.write(literal.LBRACE)
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- }
- if p.document.EnumValueDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.EnumValueDefinitions[ref].Description, p.indent, p.indentationDepth(), p.out))
- p.write(literal.LINETERMINATOR)
- }
- p.writeIndented(p.document.EnumValueDefinitionNameBytes(ref))
-}
-
-func (p *printVisitor) LeaveEnumValueDefinition(ref int) {
- if p.document.EnumValueDefinitionIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- p.write(literal.RBRACE)
- } else {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterInputObjectTypeDefinition(ref int) {
-
- if p.document.InputObjectTypeDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.InputObjectTypeDefinitions[ref].Description, nil, 0, p.out))
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- }
-
- p.write(literal.INPUT)
- p.write(literal.SPACE)
- p.write(p.document.InputObjectTypeDefinitionNameBytes(ref))
- p.write(literal.SPACE)
-
- p.inputValueDefinitionOpener = literal.LBRACE
- p.inputValueDefinitionCloser = literal.RBRACE
-}
-
-func (p *printVisitor) LeaveInputObjectTypeDefinition(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindInputObjectTypeDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterInputObjectTypeExtension(ref int) {
-
- if p.document.InputObjectTypeExtensions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.InputObjectTypeExtensions[ref].Description, nil, 0, p.out))
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- }
-
- p.write(literal.EXTEND)
- p.write(literal.SPACE)
- p.write(literal.INPUT)
- p.write(literal.SPACE)
- p.write(p.document.InputObjectTypeExtensionNameBytes(ref))
- p.write(literal.SPACE)
-
- p.inputValueDefinitionOpener = literal.LBRACE
- p.inputValueDefinitionCloser = literal.RBRACE
-}
-
-func (p *printVisitor) LeaveInputObjectTypeExtension(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindInputObjectTypeExtension, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterDirectiveDefinition(ref int) {
-
- if p.document.DirectiveDefinitions[ref].Description.IsDefined {
- p.must(p.document.PrintDescription(p.document.DirectiveDefinitions[ref].Description, nil, 0, p.out))
- p.write(literal.LINETERMINATOR)
- }
-
- p.write(literal.DIRECTIVE)
- p.write(literal.SPACE)
- p.write(literal.AT)
- p.write(p.document.DirectiveDefinitionNameBytes(ref))
- p.isFirstDirectiveLocation = true
-
- p.inputValueDefinitionOpener = literal.LPAREN
- p.inputValueDefinitionCloser = literal.RPAREN
-}
-
-func (p *printVisitor) LeaveDirectiveDefinition(ref int) {
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindDirectiveDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterDirectiveLocation(location ast.DirectiveLocation) {
-
- if p.isFirstDirectiveLocation {
- p.isFirstDirectiveLocation = false
- p.write(literal.SPACE)
- p.write(literal.ON)
- p.write(literal.SPACE)
- } else {
- p.write(literal.SPACE)
- p.write(literal.PIPE)
- p.write(literal.SPACE)
- }
-
- switch location {
- case ast.ExecutableDirectiveLocationQuery:
- p.write(literal.LocationQuery)
- case ast.ExecutableDirectiveLocationMutation:
- p.write(literal.LocationMutation)
- case ast.ExecutableDirectiveLocationSubscription:
- p.write(literal.LocationSubscription)
- case ast.ExecutableDirectiveLocationField:
- p.write(literal.LocationField)
- case ast.ExecutableDirectiveLocationFragmentDefinition:
- p.write(literal.LocationFragmentDefinition)
- case ast.ExecutableDirectiveLocationFragmentSpread:
- p.write(literal.LocationFragmentSpread)
- case ast.ExecutableDirectiveLocationInlineFragment:
- p.write(literal.LocationInlineFragment)
- case ast.ExecutableDirectiveLocationVariableDefinition:
- p.write(literal.LocationVariableDefinition)
- case ast.TypeSystemDirectiveLocationSchema:
- p.write(literal.LocationSchema)
- case ast.TypeSystemDirectiveLocationScalar:
- p.write(literal.LocationScalar)
- case ast.TypeSystemDirectiveLocationObject:
- p.write(literal.LocationObject)
- case ast.TypeSystemDirectiveLocationFieldDefinition:
- p.write(literal.LocationFieldDefinition)
- case ast.TypeSystemDirectiveLocationArgumentDefinition:
- p.write(literal.LocationArgumentDefinition)
- case ast.TypeSystemDirectiveLocationInterface:
- p.write(literal.LocationInterface)
- case ast.TypeSystemDirectiveLocationUnion:
- p.write(literal.LocationUnion)
- case ast.TypeSystemDirectiveLocationEnum:
- p.write(literal.LocationEnum)
- case ast.TypeSystemDirectiveLocationEnumValue:
- p.write(literal.LocationEnumValue)
- case ast.TypeSystemDirectiveLocationInputObject:
- p.write(literal.LocationInputObject)
- case ast.TypeSystemDirectiveLocationInputFieldDefinition:
- p.write(literal.LocationInputFieldDefinition)
- }
-}
-
-func (p *printVisitor) LeaveDirectiveLocation(location ast.DirectiveLocation) {
-
-}
-
-func (p *printVisitor) EnterSchemaDefinition(ref int) {
- p.write(literal.SCHEMA)
- p.write(literal.SPACE)
-}
-
-func (p *printVisitor) LeaveSchemaDefinition(ref int) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- p.write(literal.RBRACE)
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindSchemaDefinition, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterSchemaExtension(ref int) {
- p.write(literal.EXTEND)
- p.write(literal.SPACE)
- p.write(literal.SCHEMA)
- p.write(literal.SPACE)
-}
-
-func (p *printVisitor) LeaveSchemaExtension(ref int) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- p.write(literal.RBRACE)
- if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindSchemaExtension, Ref: ref}) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterRootOperationTypeDefinition(ref int) {
- if p.document.RootOperationTypeDefinitionIsFirstInSchemaDefinition(ref, p.Ancestors[len(p.Ancestors)-1]) {
- p.write(literal.LBRACE)
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- }
- }
- switch p.document.RootOperationTypeDefinitions[ref].OperationType {
- case ast.OperationTypeQuery:
- p.writeIndented(literal.QUERY)
- case ast.OperationTypeMutation:
- p.writeIndented(literal.MUTATION)
- case ast.OperationTypeSubscription:
- p.writeIndented(literal.SUBSCRIPTION)
- }
- p.write(literal.COLON)
- p.write(literal.SPACE)
- p.write(p.document.Input.ByteSlice(p.document.RootOperationTypeDefinitions[ref].NamedType.Name))
-}
-
-func (p *printVisitor) LeaveRootOperationTypeDefinition(ref int) {
- if !p.document.RootOperationTypeDefinitionIsLastInSchemaDefinition(ref, p.Ancestors[len(p.Ancestors)-1]) {
- if p.indent != nil {
- p.write(literal.LINETERMINATOR)
- } else {
- p.write(literal.SPACE)
- }
- }
-}
-
-func (p *printVisitor) EnterDocument(operation, definition *ast.Document) {
-
-}
-
-func (p *printVisitor) LeaveDocument(operation, definition *ast.Document) {
-
-}
-
-func (p *printVisitor) writeFieldType(ref int) {
- p.write(literal.COLON)
- p.write(literal.SPACE)
- p.must(p.document.PrintType(p.document.FieldDefinitionType(ref), p.out))
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/asttransform/asttransform.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/asttransform/asttransform.go
deleted file mode 100644
index e1babddfb61..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/asttransform/asttransform.go
+++ /dev/null
@@ -1,168 +0,0 @@
-// Package asttransform contains a set of helper methods to make recursive ast transformations possible.
-//
-// This is especially useful for ast normalization for nested fragment inlining.
-//
-// This packages is necessary to make AST transformations possible while walking an AST recusively.
-// In order to resolve dependencies in a tree (inline fragments & fragment spreads) it's necessary to resolve them in a specific order.
-// The right order to not mess things up is from the deepest level up to the root.
-// Therefore this package is used to register transformations while walking an AST in order to bring all transformations in the right order.
-// Only then, when all transformations are in the right order according to depth, it's possible to safely apply them.
-//
-package asttransform
-
-import (
- "sort"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
-)
-
-type (
- // Transformable defines the interface which needs to be implemented in order to apply Transformations
- // This needs to be implemented by any AST in order to be transformable
- Transformable interface {
- // DeleteRootNode marks a Node for deletion
- DeleteRootNode(node ast.Node)
- // EmptySelectionSet marks a selectionset for emptying
- EmptySelectionSet(ref int)
- // AppendSelectionSet marks to append a reference to a selectionset
- AppendSelectionSet(ref int, appendRef int)
- // ReplaceFragmentSpread marks to replace a fragment spread with a selectionset
- ReplaceFragmentSpread(selectionSet int, spreadRef int, replaceWithSelectionSet int)
- // ReplaceFragmentSpreadWithInlineFragment marks a fragment spread to be replaces with an inline fragment
- ReplaceFragmentSpreadWithInlineFragment(selectionSet int, spreadRef int, replaceWithSelectionSet int, typeCondition ast.TypeCondition)
- }
- transformation interface {
- apply(transformable Transformable)
- }
- // Precedence defines Depth and Order of each transformation
- Precedence struct {
- Depth int
- Order int
- }
- action struct {
- precedence Precedence
- transformation transformation
- }
- // Transformer takes transformation registrations and applies them
- Transformer struct {
- actions []action
- }
-)
-
-// Reset empties all actions
-func (t *Transformer) Reset() {
- t.actions = t.actions[:0]
-}
-
-// ApplyTransformations applies all registered transformations to a transformable
-func (t *Transformer) ApplyTransformations(transformable Transformable) {
-
- sort.Slice(t.actions, func(i, j int) bool {
- if t.actions[i].precedence.Depth != t.actions[j].precedence.Depth {
- return t.actions[i].precedence.Depth > t.actions[j].precedence.Depth
- }
- return t.actions[i].precedence.Order < t.actions[j].precedence.Order
- })
-
- for i := range t.actions {
- t.actions[i].transformation.apply(transformable)
- }
-}
-
-// DeleteRootNode registers an action to delete a root node
-func (t *Transformer) DeleteRootNode(precedence Precedence, node ast.Node) {
- t.actions = append(t.actions, action{
- precedence: precedence,
- transformation: deleteRootNode{node: node},
- })
-}
-
-// EmptySelectionSet registers an actions to empty a selectionset
-func (t *Transformer) EmptySelectionSet(precedence Precedence, ref int) {
- t.actions = append(t.actions, action{
- precedence: precedence,
- transformation: emptySelectionSet{ref: ref},
- })
-}
-
-// AppendSelectionSet registers an action to append a selection to a selectionset
-func (t *Transformer) AppendSelectionSet(precedence Precedence, ref int, appendRef int) {
- t.actions = append(t.actions, action{
- precedence: precedence,
- transformation: appendSelectionSet{
- ref: ref,
- appendRef: appendRef,
- },
- })
-}
-
-// ReplaceFragmentSpread registers an action to replace a fragment spread with a selectionset
-func (t *Transformer) ReplaceFragmentSpread(precedence Precedence, selectionSet int, spreadRef int, replaceWithSelectionSet int) {
- t.actions = append(t.actions, action{
- precedence: precedence,
- transformation: replaceFragmentSpread{
- selectionSet: selectionSet,
- spreadRef: spreadRef,
- replaceWithSelectionSet: replaceWithSelectionSet,
- },
- })
-}
-
-// ReplaceFragmentSpreadWithInlineFragment registers an action to replace a fragment spread with an inline fragment
-func (t *Transformer) ReplaceFragmentSpreadWithInlineFragment(precedence Precedence, selectionSet int, spreadRef int, replaceWithSelectionSet int, typeCondition ast.TypeCondition) {
- t.actions = append(t.actions, action{
- precedence: precedence,
- transformation: replaceFragmentSpreadWithInlineFragment{
- selectionSet: selectionSet,
- spreadRef: spreadRef,
- replaceWithSelectionSet: replaceWithSelectionSet,
- typeCondition: typeCondition,
- },
- })
-}
-
-type replaceFragmentSpread struct {
- selectionSet int
- spreadRef int
- replaceWithSelectionSet int
-}
-
-func (r replaceFragmentSpread) apply(transformable Transformable) {
- transformable.ReplaceFragmentSpread(r.selectionSet, r.spreadRef, r.replaceWithSelectionSet)
-}
-
-type replaceFragmentSpreadWithInlineFragment struct {
- selectionSet int
- spreadRef int
- replaceWithSelectionSet int
- typeCondition ast.TypeCondition
-}
-
-func (r replaceFragmentSpreadWithInlineFragment) apply(transformable Transformable) {
- transformable.ReplaceFragmentSpreadWithInlineFragment(r.selectionSet, r.spreadRef, r.replaceWithSelectionSet, r.typeCondition)
-}
-
-type deleteRootNode struct {
- node ast.Node
-}
-
-func (d deleteRootNode) apply(transformable Transformable) {
- transformable.DeleteRootNode(d.node)
-}
-
-type emptySelectionSet struct {
- ref int
-}
-
-func (e emptySelectionSet) apply(transformable Transformable) {
- transformable.EmptySelectionSet(e.ref)
-}
-
-type appendSelectionSet struct {
- ref int
- appendRef int
-}
-
-func (a appendSelectionSet) apply(transformable Transformable) {
- transformable.AppendSelectionSet(a.ref, a.appendRef)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/asttransform/baseschema.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/asttransform/baseschema.go
deleted file mode 100644
index 6c8b8b9cf08..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/asttransform/baseschema.go
+++ /dev/null
@@ -1,305 +0,0 @@
-package asttransform
-
-import (
- "bytes"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astparser"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-func MergeDefinitionWithBaseSchema(definition *ast.Document) error {
- definition.Input.AppendInputBytes(baseSchema)
- parser := astparser.NewParser()
- report := operationreport.Report{}
- parser.Parse(definition, &report)
- if report.HasErrors() {
- return report
- }
- return handleSchema(definition)
-}
-
-func handleSchema(definition *ast.Document) error {
- if err := addSchemaDefinition(definition); err != nil {
- return err
- }
-
- queryNode, ok := findQueryNode(definition)
- if !ok {
- return nil
- }
-
- if err := addIntrospectionQueryFields(definition, queryNode.Ref); err != nil {
- return err
- }
-
- return nil
-}
-
-func addSchemaDefinition(definition *ast.Document) error {
- if definition.HasSchemaDefinition() {
- return nil
- }
-
- schemaDefinition := ast.SchemaDefinition{}
- var rootOperationTypeRefs []int
-
- for i := range definition.RootNodes {
- if definition.RootNodes[i].Kind == ast.NodeKindObjectTypeDefinition {
- typeName := definition.ObjectTypeDefinitionNameBytes(definition.RootNodes[i].Ref)
-
- switch {
- case bytes.Equal(typeName, []byte("Query")):
- ref := definition.CreateRootOperationTypeDefinition(ast.OperationTypeQuery, i)
- rootOperationTypeRefs = append(rootOperationTypeRefs, ref)
- case bytes.Equal(typeName, []byte("Mutation")):
- ref := definition.CreateRootOperationTypeDefinition(ast.OperationTypeMutation, i)
- rootOperationTypeRefs = append(rootOperationTypeRefs, ref)
- case bytes.Equal(typeName, []byte("Subscription")):
- ref := definition.CreateRootOperationTypeDefinition(ast.OperationTypeSubscription, i)
- rootOperationTypeRefs = append(rootOperationTypeRefs, ref)
- default:
- continue
- }
- }
- }
-
- schemaDefinition.AddRootOperationTypeDefinitionRefs(rootOperationTypeRefs...)
- definition.AddSchemaDefinitionRootNode(schemaDefinition)
- return nil
-}
-
-func addIntrospectionQueryFields(definition *ast.Document, objectTypeDefinitionRef int) error {
- var fieldRefs []int
- if !definition.ObjectTypeDefinitionHasField(objectTypeDefinitionRef, []byte("__schema")) {
- fieldRefs = append(fieldRefs, addSchemaField(definition))
- }
-
- if !definition.ObjectTypeDefinitionHasField(objectTypeDefinitionRef, []byte("__type")) {
- fieldRefs = append(fieldRefs, addTypeField(definition))
- }
-
- definition.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs = append(definition.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs, fieldRefs...)
- return nil
-}
-
-func addSchemaField(definition *ast.Document) (ref int) {
- fieldNameRef := definition.Input.AppendInputBytes([]byte("__schema"))
- fieldTypeRef := definition.AddNonNullNamedType([]byte("__Schema"))
-
- return definition.AddFieldDefinition(ast.FieldDefinition{
- Name: fieldNameRef,
- Type: fieldTypeRef,
- })
-}
-
-func addTypeField(definition *ast.Document) (ref int) {
- fieldNameRef := definition.Input.AppendInputBytes([]byte("__type"))
- fieldTypeRef := definition.AddNamedType([]byte("__Type"))
-
- argumentNameRef := definition.Input.AppendInputBytes([]byte("name"))
- argumentTypeRef := definition.AddNonNullNamedType([]byte("String"))
-
- argumentRef := definition.AddInputValueDefinition(ast.InputValueDefinition{
- Name: argumentNameRef,
- Type: argumentTypeRef,
- })
-
- return definition.AddFieldDefinition(ast.FieldDefinition{
- Name: fieldNameRef,
- Type: fieldTypeRef,
-
- HasArgumentsDefinitions: true,
- ArgumentsDefinition: ast.InputValueDefinitionList{
- Refs: []int{argumentRef},
- },
- })
-}
-
-func findQueryNode(definition *ast.Document) (queryNode ast.Node, ok bool) {
- queryNode, ok = definition.Index.FirstNodeByNameBytes(definition.Index.QueryTypeName)
- return queryNode, ok
-}
-
-var baseSchema = []byte(`"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1."
-scalar Int
-"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)."
-scalar Float
-"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text."
-scalar String
-"The 'Boolean' scalar type represents 'true' or 'false' ."
-scalar Boolean
-"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID."
-scalar ID
-"Directs the executor to include this field or fragment only when the argument is true."
-directive @include(
- " Included when true."
- if: Boolean!
-) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
-"Directs the executor to skip this field or fragment when the argument is true."
-directive @skip(
- "Skipped when true."
- if: Boolean!
-) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
-"Marks an element of a GraphQL schema as no longer supported."
-directive @deprecated(
- """
- Explains why this element was deprecated, usually also including a suggestion
- for how to access supported similar data. Formatted in
- [Markdown](https://daringfireball.net/projects/markdown/).
- """
- reason: String = "No longer supported"
-) on FIELD_DEFINITION | ENUM_VALUE
-
-"""
-A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
-In some cases, you need to provide options to alter GraphQL's execution behavior
-in ways field arguments will not suffice, such as conditionally including or
-skipping a field. Directives provide this by describing additional information
-to the executor.
-"""
-type __Directive {
- name: String!
- description: String
- locations: [__DirectiveLocation!]!
- args: [__InputValue!]!
-}
-
-"""
-A Directive can be adjacent to many parts of the GraphQL language, a
-__DirectiveLocation describes one such possible adjacencies.
-"""
-enum __DirectiveLocation {
- "Location adjacent to a query operation."
- QUERY
- "Location adjacent to a mutation operation."
- MUTATION
- "Location adjacent to a subscription operation."
- SUBSCRIPTION
- "Location adjacent to a field."
- FIELD
- "Location adjacent to a fragment definition."
- FRAGMENT_DEFINITION
- "Location adjacent to a fragment spread."
- FRAGMENT_SPREAD
- "Location adjacent to an inline fragment."
- INLINE_FRAGMENT
- "Location adjacent to a schema definition."
- SCHEMA
- "Location adjacent to a scalar definition."
- SCALAR
- "Location adjacent to an object type definition."
- OBJECT
- "Location adjacent to a field definition."
- FIELD_DEFINITION
- "Location adjacent to an argument definition."
- ARGUMENT_DEFINITION
- "Location adjacent to an interface definition."
- INTERFACE
- "Location adjacent to a union definition."
- UNION
- "Location adjacent to an enum definition."
- ENUM
- "Location adjacent to an enum value definition."
- ENUM_VALUE
- "Location adjacent to an input object type definition."
- INPUT_OBJECT
- "Location adjacent to an input object field definition."
- INPUT_FIELD_DEFINITION
-}
-"""
-One possible value for a given Enum. Enum values are unique values, not a
-placeholder for a string or numeric value. However an Enum value is returned in
-a JSON response as a string.
-"""
-type __EnumValue {
- name: String!
- description: String
- isDeprecated: Boolean!
- deprecationReason: String
-}
-
-"""
-Object and Interface types are described by a list of Fields, each of which has
-a name, potentially a list of arguments, and a return type.
-"""
-type __Field {
- name: String!
- description: String
- args: [__InputValue!]!
- type: __Type!
- isDeprecated: Boolean!
- deprecationReason: String
-}
-
-"""Arguments provided to Fields or Directives and the input fields of an
-InputObject are represented as Input Values which describe their type and
-optionally a default value.
-"""
-type __InputValue {
- name: String!
- description: String
- type: __Type!
- "A GraphQL-formatted string representing the default value for this input value."
- defaultValue: String
-}
-
-"""
-A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all
-available types and directives on the server, as well as the entry points for
-query, mutation, and subscription operations.
-"""
-type __Schema {
- "A list of all types supported by this server."
- types: [__Type!]!
- "The type that query operations will be rooted at."
- queryType: __Type!
- "If this server supports mutation, the type that mutation operations will be rooted at."
- mutationType: __Type
- "If this server support subscription, the type that subscription operations will be rooted at."
- subscriptionType: __Type
- "A list of all directives supported by this server."
- directives: [__Directive!]!
-}
-
-"""
-The fundamental unit of any GraphQL Schema is the type. There are many kinds of
-types in GraphQL as represented by the '__TypeKind' enum.
-
-Depending on the kind of a type, certain fields describe information about that
-type. Scalar types provide no information beyond a name and description, while
-Enum types provide their values. Object and Interface types provide the fields
-they describe. Abstract types, Union and Interface, provide the Object types
-possible at runtime. List and NonNull types compose other types.
-"""
-type __Type {
- kind: __TypeKind!
- name: String
- description: String
- fields(includeDeprecated: Boolean = false): [__Field!]
- interfaces: [__Type!]
- possibleTypes: [__Type!]
- enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
- inputFields: [__InputValue!]
- ofType: __Type
-}
-
-"An enum describing what kind of type a given '__Type' is."
-enum __TypeKind {
- "Indicates this type is a scalar."
- SCALAR
- "Indicates this type is an object. 'fields' and 'interfaces' are valid fields."
- OBJECT
- "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields."
- INTERFACE
- "Indicates this type is a union. 'possibleTypes' is a valid field."
- UNION
- "Indicates this type is an enum. 'enumValues' is a valid field."
- ENUM
- "Indicates this type is an input object. 'inputFields' is a valid field."
- INPUT_OBJECT
- "Indicates this type is a list. 'ofType' is a valid field."
- LIST
- "Indicates this type is a non-null. 'ofType' is a valid field."
- NON_NULL
-}`)
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/astvalidation.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/astvalidation.go
deleted file mode 100644
index 20a6b75b40f..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/astvalidation.go
+++ /dev/null
@@ -1,1440 +0,0 @@
-//go:generate stringer -type=ValidationState -output astvalidation_string.go
-
-// Package astvalidation implements the validation rules specified in the GraphQL specification.
-package astvalidation
-
-import (
- "bytes"
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astimport"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-// DefaultOperationValidator returns a fully initialized OperationValidator with all default rules registered
-func DefaultOperationValidator() *OperationValidator {
-
- validator := OperationValidator{
- walker: astvisitor.NewWalker(48),
- }
-
- validator.RegisterRule(DocumentContainsExecutableOperation())
- validator.RegisterRule(OperationNameUniqueness())
- validator.RegisterRule(LoneAnonymousOperation())
- validator.RegisterRule(SubscriptionSingleRootField())
- validator.RegisterRule(FieldSelections())
- validator.RegisterRule(FieldSelectionMerging())
- validator.RegisterRule(ValidArguments())
- validator.RegisterRule(Values())
- validator.RegisterRule(ArgumentUniqueness())
- validator.RegisterRule(RequiredArguments())
- validator.RegisterRule(Fragments())
- validator.RegisterRule(DirectivesAreDefined())
- validator.RegisterRule(DirectivesAreInValidLocations())
- validator.RegisterRule(VariableUniqueness())
- validator.RegisterRule(DirectivesAreUniquePerLocation())
- validator.RegisterRule(VariablesAreInputTypes())
- validator.RegisterRule(AllVariableUsesDefined())
- validator.RegisterRule(AllVariablesUsed())
-
- return &validator
-}
-
-// ValidationState is the outcome of a validation
-type ValidationState int
-
-const (
- UnknownState ValidationState = iota
- Valid
- Invalid
-)
-
-// Rule is hook to register callback functions on the Walker
-type Rule func(walker *astvisitor.Walker)
-
-// OperationValidator orchestrates the validation process of Operations
-type OperationValidator struct {
- walker astvisitor.Walker
-}
-
-// RegisterRule registers a rule to the OperationValidator
-func (o *OperationValidator) RegisterRule(rule Rule) {
- rule(&o.walker)
-}
-
-// Validate validates the operation against the definition using the registered ruleset.
-func (o *OperationValidator) Validate(operation, definition *ast.Document, report *operationreport.Report) ValidationState {
-
- if report == nil {
- report = &operationreport.Report{}
- }
-
- o.walker.Walk(operation, definition, report)
-
- if report.HasErrors() {
- return Invalid
- }
- return Valid
-}
-
-// DocumentContainsExecutableOperation validates if the document actually contains an executable Operation
-func DocumentContainsExecutableOperation() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := &documentContainsExecutableOperation{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(visitor)
- }
-}
-
-type documentContainsExecutableOperation struct {
- *astvisitor.Walker
-}
-
-func (d *documentContainsExecutableOperation) EnterDocument(operation, definition *ast.Document) {
- if len(operation.RootNodes) == 0 {
- d.StopWithExternalErr(operationreport.ErrDocumentDoesntContainExecutableOperation())
- return
- }
- for i := range operation.RootNodes {
- if operation.RootNodes[i].Kind == ast.NodeKindOperationDefinition {
- return
- }
- }
- d.StopWithExternalErr(operationreport.ErrDocumentDoesntContainExecutableOperation())
-}
-
-// OperationNameUniqueness validates if all operation names are unique
-func OperationNameUniqueness() Rule {
- return func(walker *astvisitor.Walker) {
- walker.RegisterEnterDocumentVisitor(&operationNameUniquenessVisitor{walker})
- }
-}
-
-type operationNameUniquenessVisitor struct {
- *astvisitor.Walker
-}
-
-func (o *operationNameUniquenessVisitor) EnterDocument(operation, definition *ast.Document) {
- if len(operation.OperationDefinitions) <= 1 {
- return
- }
-
- for i := range operation.OperationDefinitions {
- for k := range operation.OperationDefinitions {
- if i == k || i > k {
- continue
- }
-
- left := operation.OperationDefinitions[i].Name
- right := operation.OperationDefinitions[k].Name
-
- if ast.ByteSliceEquals(left, operation.Input, right, operation.Input) {
- operationName := operation.Input.ByteSlice(operation.OperationDefinitions[i].Name)
- o.StopWithExternalErr(operationreport.ErrOperationNameMustBeUnique(operationName))
- return
- }
- }
- }
-}
-
-// LoneAnonymousOperation validates if anonymous operations are alone in a given document.
-func LoneAnonymousOperation() Rule {
- return func(walker *astvisitor.Walker) {
- walker.RegisterEnterDocumentVisitor(&loneAnonymousOperationVisitor{walker})
- }
-}
-
-type loneAnonymousOperationVisitor struct {
- *astvisitor.Walker
-}
-
-func (l *loneAnonymousOperationVisitor) EnterDocument(operation, definition *ast.Document) {
- if len(operation.OperationDefinitions) <= 1 {
- return
- }
-
- for i := range operation.OperationDefinitions {
- if operation.OperationDefinitions[i].Name.Length() == 0 {
- l.StopWithExternalErr(operationreport.ErrAnonymousOperationMustBeTheOnlyOperationInDocument())
- return
- }
- }
-}
-
-// SubscriptionSingleRootField validates if subscriptions have a single root field
-func SubscriptionSingleRootField() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := subscriptionSingleRootFieldVisitor{walker}
- walker.RegisterEnterDocumentVisitor(&visitor)
- }
-}
-
-type subscriptionSingleRootFieldVisitor struct {
- *astvisitor.Walker
-}
-
-func (s *subscriptionSingleRootFieldVisitor) EnterDocument(operation, definition *ast.Document) {
- for i := range operation.OperationDefinitions {
- if operation.OperationDefinitions[i].OperationType == ast.OperationTypeSubscription {
- selections := len(operation.SelectionSets[operation.OperationDefinitions[i].SelectionSet].SelectionRefs)
- if selections > 1 {
- subscriptionName := operation.Input.ByteSlice(operation.OperationDefinitions[i].Name)
- s.StopWithExternalErr(operationreport.ErrSubscriptionMustOnlyHaveOneRootSelection(subscriptionName))
- return
- } else if selections == 1 {
- ref := operation.SelectionSets[operation.OperationDefinitions[i].SelectionSet].SelectionRefs[0]
- if operation.Selections[ref].Kind == ast.SelectionKindField {
- return
- }
- }
- }
- }
-}
-
-// FieldSelections validates if all FieldSelections are possible and valid
-func FieldSelections() Rule {
- return func(walker *astvisitor.Walker) {
- fieldDefined := fieldDefined{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&fieldDefined)
- walker.RegisterEnterFieldVisitor(&fieldDefined)
- }
-}
-
-type fieldDefined struct {
- *astvisitor.Walker
- operation *ast.Document
- definition *ast.Document
-}
-
-func (f *fieldDefined) EnterDocument(operation, definition *ast.Document) {
- f.operation = operation
- f.definition = definition
-}
-
-func (f *fieldDefined) ValidateUnionField(ref int, enclosingTypeDefinition ast.Node) {
- if bytes.Equal(f.operation.FieldNameBytes(ref), literal.TYPENAME) {
- return
- }
- fieldName := f.operation.FieldNameBytes(ref)
- unionName := f.definition.NodeNameBytes(enclosingTypeDefinition)
- f.StopWithExternalErr(operationreport.ErrFieldSelectionOnUnion(fieldName, unionName))
-}
-
-func (f *fieldDefined) ValidateInterfaceObjectTypeField(ref int, enclosingTypeDefinition ast.Node) {
- fieldName := f.operation.FieldNameBytes(ref)
- if bytes.Equal(fieldName, literal.TYPENAME) {
- return
- }
- typeName := f.definition.NodeNameBytes(enclosingTypeDefinition)
- hasSelections := f.operation.FieldHasSelections(ref)
- definitions := f.definition.NodeFieldDefinitions(enclosingTypeDefinition)
- for _, i := range definitions {
- definitionName := f.definition.FieldDefinitionNameBytes(i)
- if bytes.Equal(fieldName, definitionName) {
- // field is defined
- fieldDefinitionTypeKind := f.definition.FieldDefinitionTypeNode(i).Kind
- switch {
- case hasSelections && fieldDefinitionTypeKind == ast.NodeKindScalarTypeDefinition:
- f.StopWithExternalErr(operationreport.ErrFieldSelectionOnScalar(fieldName, definitionName))
- case !hasSelections && (fieldDefinitionTypeKind != ast.NodeKindScalarTypeDefinition && fieldDefinitionTypeKind != ast.NodeKindEnumTypeDefinition):
- f.StopWithExternalErr(operationreport.ErrMissingFieldSelectionOnNonScalar(fieldName, typeName))
- }
- return
- }
- }
-
- f.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, typeName))
-}
-
-func (f *fieldDefined) ValidateScalarField(ref int, enclosingTypeDefinition ast.Node) {
- fieldName := f.operation.FieldNameBytes(ref)
- scalarTypeName := f.operation.NodeNameBytes(enclosingTypeDefinition)
- f.StopWithExternalErr(operationreport.ErrFieldSelectionOnScalar(fieldName, scalarTypeName))
-}
-
-func (f *fieldDefined) EnterField(ref int) {
- switch f.EnclosingTypeDefinition.Kind {
- case ast.NodeKindUnionTypeDefinition:
- f.ValidateUnionField(ref, f.EnclosingTypeDefinition)
- case ast.NodeKindInterfaceTypeDefinition, ast.NodeKindObjectTypeDefinition:
- f.ValidateInterfaceObjectTypeField(ref, f.EnclosingTypeDefinition)
- case ast.NodeKindScalarTypeDefinition:
- f.ValidateScalarField(ref, f.EnclosingTypeDefinition)
- default:
- fieldName := f.operation.FieldNameBytes(ref)
- typeName := f.operation.NodeNameBytes(f.EnclosingTypeDefinition)
- f.StopWithInternalErr(fmt.Errorf("astvalidation/fieldDefined/EnterField: field: %s selection on type: %s unhandled", fieldName, typeName))
- }
-}
-
-// FieldSelectionMerging validates if field selections can be merged
-func FieldSelectionMerging() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := fieldSelectionMergingVisitor{Walker: walker}
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterSelectionSetVisitor(&visitor)
- walker.RegisterEnterFieldVisitor(&visitor)
- walker.RegisterEnterOperationVisitor(&visitor)
- walker.RegisterEnterFragmentDefinitionVisitor(&visitor)
- }
-}
-
-type fieldSelectionMergingVisitor struct {
- *astvisitor.Walker
- definition, operation *ast.Document
- scalarRequirements scalarRequirements
- nonScalarRequirements nonScalarRequirements
- refs []int
- pathCache [256][32]ast.PathItem
- pathCacheIndex int
-}
-type nonScalarRequirement struct {
- path ast.Path
- objectName ast.ByteSlice
- fieldTypeRef int
- fieldTypeDefinitionNode ast.Node
-}
-
-type nonScalarRequirements []nonScalarRequirement
-
-func (f *fieldSelectionMergingVisitor) NonScalarRequirementsByPathField(path ast.Path, objectName ast.ByteSlice) []int {
- f.refs = f.refs[:0]
- for i := range f.nonScalarRequirements {
- if f.nonScalarRequirements[i].path.Equals(path) && f.nonScalarRequirements[i].objectName.Equals(objectName) {
- f.refs = append(f.refs, i)
- }
- }
- return f.refs
-}
-
-type scalarRequirement struct {
- path ast.Path
- objectName ast.ByteSlice
- fieldRef int
- fieldType int
- enclosingTypeDefinition ast.Node
- fieldTypeDefinitionNode ast.Node
-}
-
-type scalarRequirements []scalarRequirement
-
-func (f *fieldSelectionMergingVisitor) ScalarRequirementsByPathField(path ast.Path, objectName ast.ByteSlice) []int {
- f.refs = f.refs[:0]
- for i := range f.scalarRequirements {
- if f.scalarRequirements[i].path.Equals(path) && f.scalarRequirements[i].objectName.Equals(objectName) {
- f.refs = append(f.refs, i)
- }
- }
- return f.refs
-}
-
-func (f *fieldSelectionMergingVisitor) resetRequirements() {
- f.scalarRequirements = f.scalarRequirements[:0]
- f.nonScalarRequirements = f.nonScalarRequirements[:0]
-}
-
-func (f *fieldSelectionMergingVisitor) EnterDocument(operation, definition *ast.Document) {
- f.operation = operation
- f.definition = definition
- f.pathCacheIndex = 0
-}
-
-func (f *fieldSelectionMergingVisitor) EnterFragmentDefinition(ref int) {
- f.resetRequirements()
-}
-
-func (f *fieldSelectionMergingVisitor) EnterOperationDefinition(ref int) {
- f.resetRequirements()
-}
-
-func (f *fieldSelectionMergingVisitor) EnterField(ref int) {
- fieldName := f.operation.FieldNameBytes(ref)
- if bytes.Equal(fieldName, literal.TYPENAME) {
- return
- }
- objectName := f.operation.FieldAliasOrNameBytes(ref)
- definition, ok := f.definition.NodeFieldDefinitionByName(f.EnclosingTypeDefinition, fieldName)
- if !ok {
- enclosingTypeName := f.definition.NodeNameBytes(f.EnclosingTypeDefinition)
- f.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, enclosingTypeName))
- return
- }
-
- fieldType := f.definition.FieldDefinitionType(definition)
- fieldDefinitionTypeNode := f.definition.FieldDefinitionTypeNode(definition)
- if fieldDefinitionTypeNode.Kind != ast.NodeKindScalarTypeDefinition {
-
- matchedRequirements := f.NonScalarRequirementsByPathField(f.Path, objectName)
- fieldDefinitionTypeKindPresentInRequirements := false
- for _, i := range matchedRequirements {
-
- if !f.potentiallySameObject(fieldDefinitionTypeNode, f.nonScalarRequirements[i].fieldTypeDefinitionNode) {
- if !objectName.Equals(f.nonScalarRequirements[i].objectName) {
- f.StopWithExternalErr(operationreport.ErrResponseOfDifferingTypesMustBeOfSameShape(objectName, f.nonScalarRequirements[i].objectName))
- return
- }
- } else if !f.definition.TypesAreCompatibleDeep(f.nonScalarRequirements[i].fieldTypeRef, fieldType) {
- left, err := f.definition.PrintTypeBytes(f.nonScalarRequirements[i].fieldTypeRef, nil)
- if err != nil {
- f.StopWithInternalErr(err)
- return
- }
- right, err := f.definition.PrintTypeBytes(fieldType, nil)
- if err != nil {
- f.StopWithInternalErr(err)
- return
- }
- f.StopWithExternalErr(operationreport.ErrTypesForFieldMismatch(objectName, left, right))
- return
- }
-
- if fieldDefinitionTypeNode.Kind != f.nonScalarRequirements[i].fieldTypeDefinitionNode.Kind {
- fieldDefinitionTypeKindPresentInRequirements = true
- }
- }
-
- if len(matchedRequirements) != 0 && fieldDefinitionTypeKindPresentInRequirements {
- return
- }
-
- var path ast.Path
- if f.pathCacheIndex != len(f.pathCache)-1 {
- path = f.pathCache[f.pathCacheIndex][:len(f.Path)]
- f.pathCacheIndex++
- for i := 0; i < len(f.Path); i++ {
- path[i] = f.Path[i]
- }
- } else {
- path = make(ast.Path, len(f.Path))
- copy(path, f.Path)
- }
-
- f.nonScalarRequirements = append(f.nonScalarRequirements, nonScalarRequirement{
- path: path,
- objectName: objectName,
- fieldTypeRef: fieldType,
- fieldTypeDefinitionNode: fieldDefinitionTypeNode,
- })
- return
- }
-
- matchedRequirements := f.ScalarRequirementsByPathField(f.Path, objectName)
- fieldDefinitionTypeKindPresentInRequirements := false
-
- for _, i := range matchedRequirements {
- if f.potentiallySameObject(f.scalarRequirements[i].enclosingTypeDefinition, f.EnclosingTypeDefinition) {
- if !f.operation.FieldsAreEqualFlat(f.scalarRequirements[i].fieldRef, ref) {
- f.StopWithExternalErr(operationreport.ErrDifferingFieldsOnPotentiallySameType(objectName))
- return
- }
- }
- if !f.definition.TypesAreCompatibleDeep(f.scalarRequirements[i].fieldType, fieldType) {
- left, err := f.definition.PrintTypeBytes(f.scalarRequirements[i].fieldType, nil)
- if err != nil {
- f.StopWithInternalErr(err)
- return
- }
- right, err := f.definition.PrintTypeBytes(fieldType, nil)
- if err != nil {
- f.StopWithInternalErr(err)
- return
- }
- f.StopWithExternalErr(operationreport.ErrFieldsConflict(objectName, left, right))
- return
- }
-
- if fieldDefinitionTypeNode.Kind != f.scalarRequirements[i].fieldTypeDefinitionNode.Kind {
- fieldDefinitionTypeKindPresentInRequirements = true
- }
- }
-
- if len(matchedRequirements) != 0 && fieldDefinitionTypeKindPresentInRequirements {
- return
- }
-
- var path ast.Path
- if f.pathCacheIndex != len(f.pathCache)-1 {
- path = f.pathCache[f.pathCacheIndex][:len(f.Path)]
- f.pathCacheIndex++
- for i := 0; i < len(f.Path); i++ {
- path[i] = f.Path[i]
- }
- } else {
- path = make(ast.Path, len(f.Path))
- copy(path, f.Path)
- }
-
- f.scalarRequirements = append(f.scalarRequirements, scalarRequirement{
- path: path,
- objectName: objectName,
- fieldRef: ref,
- fieldType: fieldType,
- enclosingTypeDefinition: f.EnclosingTypeDefinition,
- fieldTypeDefinitionNode: fieldDefinitionTypeNode,
- })
-}
-
-func (f *fieldSelectionMergingVisitor) potentiallySameObject(left, right ast.Node) bool {
- switch {
- case left.Kind == ast.NodeKindInterfaceTypeDefinition || right.Kind == ast.NodeKindInterfaceTypeDefinition:
- return true
- case left.Kind == ast.NodeKindObjectTypeDefinition && right.Kind == ast.NodeKindObjectTypeDefinition:
- return bytes.Equal(f.definition.ObjectTypeDefinitionNameBytes(left.Ref), f.definition.ObjectTypeDefinitionNameBytes(right.Ref))
- default:
- return false
- }
-}
-
-func (f *fieldSelectionMergingVisitor) EnterSelectionSet(ref int) {
-
-}
-
-// ValidArguments validates if arguments are valid
-func ValidArguments() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := validArgumentsVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterArgumentVisitor(&visitor)
- }
-}
-
-type validArgumentsVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (v *validArgumentsVisitor) EnterDocument(operation, definition *ast.Document) {
- v.operation = operation
- v.definition = definition
-}
-
-func (v *validArgumentsVisitor) EnterArgument(ref int) {
-
- definition, exists := v.ArgumentInputValueDefinition(ref)
-
- if !exists {
- argumentName := v.operation.ArgumentNameBytes(ref)
- ancestorName := v.AncestorNameBytes()
- v.StopWithExternalErr(operationreport.ErrArgumentNotDefinedOnNode(argumentName, ancestorName))
- return
- }
-
- value := v.operation.ArgumentValue(ref)
- v.validateIfValueSatisfiesInputFieldDefinition(value, definition)
-}
-
-func (v *validArgumentsVisitor) validateIfValueSatisfiesInputFieldDefinition(value ast.Value, inputValueDefinition int) {
-
- var satisfied bool
-
- switch value.Kind {
- case ast.ValueKindVariable:
- satisfied = v.variableValueSatisfiesInputValueDefinition(value.Ref, inputValueDefinition)
- case ast.ValueKindEnum:
- satisfied = v.enumValueSatisfiesInputValueDefinition(value.Ref, inputValueDefinition)
- case ast.ValueKindNull:
- satisfied = v.nullValueSatisfiesInputValueDefinition(inputValueDefinition)
- case ast.ValueKindBoolean:
- satisfied = v.booleanValueSatisfiesInputValueDefinition(inputValueDefinition)
- case ast.ValueKindInteger:
- satisfied = v.intValueSatisfiesInputValueDefinition(value, inputValueDefinition)
- case ast.ValueKindString:
- satisfied = v.stringValueSatisfiesInputValueDefinition(value, inputValueDefinition)
- case ast.ValueKindFloat:
- satisfied = v.floatValueSatisfiesInputValueDefinition(value, inputValueDefinition)
- case ast.ValueKindObject, ast.ValueKindList:
- // object- and list values are covered by Values() / valuesVisitor
- return
- default:
- v.StopWithInternalErr(fmt.Errorf("validateIfValueSatisfiesInputFieldDefinition: not implemented for value.Kind: %s", value.Kind))
- return
- }
-
- if satisfied {
- return
- }
-
- printedValue, err := v.operation.PrintValueBytes(value, nil)
- if v.HandleInternalErr(err) {
- return
- }
-
- typeRef := v.definition.InputValueDefinitionType(inputValueDefinition)
-
- printedType, err := v.definition.PrintTypeBytes(typeRef, nil)
- if v.HandleInternalErr(err) {
- return
- }
-
- v.StopWithExternalErr(operationreport.ErrValueDoesntSatisfyInputValueDefinition(printedValue, printedType))
-}
-
-func (v *validArgumentsVisitor) floatValueSatisfiesInputValueDefinition(value ast.Value, inputValueDefinition int) bool {
- inputType := v.definition.Types[v.definition.InputValueDefinitionType(inputValueDefinition)]
- if inputType.TypeKind == ast.TypeKindNonNull {
- inputType = v.definition.Types[inputType.OfType]
- }
- if inputType.TypeKind != ast.TypeKindNamed {
- return false
- }
- if !bytes.Equal(v.definition.Input.ByteSlice(inputType.Name), literal.FLOAT) {
- return false
- }
- return true
-}
-
-func (v *validArgumentsVisitor) stringValueSatisfiesInputValueDefinition(value ast.Value, inputValueDefinition int) bool {
- inputType := v.definition.Types[v.definition.InputValueDefinitionType(inputValueDefinition)]
- if inputType.TypeKind == ast.TypeKindNonNull {
- inputType = v.definition.Types[inputType.OfType]
- }
- if inputType.TypeKind != ast.TypeKindNamed {
- return false
- }
-
- inputTypeName := v.definition.Input.ByteSlice(inputType.Name)
- if !bytes.Equal(inputTypeName, literal.STRING) && !bytes.Equal(inputTypeName, literal.ID) {
- return false
- }
- return true
-}
-
-func (v *validArgumentsVisitor) intValueSatisfiesInputValueDefinition(value ast.Value, inputValueDefinition int) bool {
- inputType := v.definition.Types[v.definition.InputValueDefinitionType(inputValueDefinition)]
- if inputType.TypeKind == ast.TypeKindNonNull {
- inputType = v.definition.Types[inputType.OfType]
- }
- if inputType.TypeKind != ast.TypeKindNamed {
- return false
- }
- if !bytes.Equal(v.definition.Input.ByteSlice(inputType.Name), literal.INT) {
- return false
- }
- return true
-}
-
-func (v *validArgumentsVisitor) booleanValueSatisfiesInputValueDefinition(inputValueDefinition int) bool {
- inputType := v.definition.Types[v.definition.InputValueDefinitionType(inputValueDefinition)]
- if inputType.TypeKind == ast.TypeKindNonNull {
- inputType = v.definition.Types[inputType.OfType]
- }
- if inputType.TypeKind != ast.TypeKindNamed {
- return false
- }
- if !bytes.Equal(v.definition.Input.ByteSlice(inputType.Name), literal.BOOLEAN) {
- return false
- }
- return true
-}
-
-func (v *validArgumentsVisitor) nullValueSatisfiesInputValueDefinition(inputValueDefinition int) bool {
- inputType := v.definition.Types[v.definition.InputValueDefinitionType(inputValueDefinition)]
- return inputType.TypeKind != ast.TypeKindNonNull
-}
-
-func (v *validArgumentsVisitor) enumValueSatisfiesInputValueDefinition(enumValue, inputValueDefinition int) bool {
-
- definitionTypeName := v.definition.ResolveTypeNameBytes(v.definition.InputValueDefinitions[inputValueDefinition].Type)
- node, exists := v.definition.Index.FirstNodeByNameBytes(definitionTypeName)
- if !exists {
- return false
- }
-
- if node.Kind != ast.NodeKindEnumTypeDefinition {
- return false
- }
-
- enumValueName := v.operation.Input.ByteSlice(v.operation.EnumValueName(enumValue))
- return v.definition.EnumTypeDefinitionContainsEnumValue(node.Ref, enumValueName)
-}
-
-func (v *validArgumentsVisitor) variableValueSatisfiesInputValueDefinition(variableValue, inputValueDefinition int) bool {
- variableName := v.operation.VariableValueNameBytes(variableValue)
- variableDefinition, exists := v.operation.VariableDefinitionByNameAndOperation(v.Ancestors[0].Ref, variableName)
- if !exists {
- return false
- }
-
- operationType := v.operation.VariableDefinitions[variableDefinition].Type
- definitionType := v.definition.InputValueDefinitions[inputValueDefinition].Type
- hasDefaultValue := v.operation.VariableDefinitions[variableDefinition].DefaultValue.IsDefined ||
- v.definition.InputValueDefinitions[inputValueDefinition].DefaultValue.IsDefined
-
- return v.operationTypeSatisfiesDefinitionType(operationType, definitionType, hasDefaultValue)
-}
-
-func (v *validArgumentsVisitor) operationTypeSatisfiesDefinitionType(operationType int, definitionType int, hasDefaultValue bool) bool {
-
- if operationType == -1 || definitionType == -1 {
- return false
- }
-
- if v.operation.Types[operationType].TypeKind != ast.TypeKindNonNull &&
- v.definition.Types[definitionType].TypeKind == ast.TypeKindNonNull &&
- hasDefaultValue &&
- v.definition.Types[definitionType].OfType != -1 {
- definitionType = v.definition.Types[definitionType].OfType
- }
-
- if v.operation.Types[operationType].TypeKind == ast.TypeKindNonNull &&
- v.definition.Types[definitionType].TypeKind != ast.TypeKindNonNull &&
- v.operation.Types[operationType].OfType != -1 {
- operationType = v.operation.Types[operationType].OfType
- }
-
- for {
- if operationType == -1 || definitionType == -1 {
- return false
- }
- if v.operation.Types[operationType].TypeKind != v.definition.Types[definitionType].TypeKind {
- return false
- }
- if v.operation.Types[operationType].TypeKind == ast.TypeKindNamed {
- return bytes.Equal(v.operation.Input.ByteSlice(v.operation.Types[operationType].Name),
- v.definition.Input.ByteSlice(v.definition.Types[definitionType].Name))
- }
- operationType = v.operation.Types[operationType].OfType
- definitionType = v.definition.Types[definitionType].OfType
- }
-}
-
-// Values validates if values are used properly
-func Values() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := valuesVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterArgumentVisitor(&visitor)
- }
-}
-
-type valuesVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
- importer astimport.Importer
-}
-
-func (v *valuesVisitor) EnterDocument(operation, definition *ast.Document) {
- v.operation = operation
- v.definition = definition
-}
-
-func (v *valuesVisitor) EnterArgument(ref int) {
-
- definition, exists := v.ArgumentInputValueDefinition(ref)
-
- if !exists {
- argName := v.operation.ArgumentNameBytes(ref)
- nodeName := v.operation.NodeNameBytes(v.Ancestors[len(v.Ancestors)-1])
- v.StopWithExternalErr(operationreport.ErrArgumentNotDefinedOnNode(argName, nodeName))
- return
- }
-
- value := v.operation.ArgumentValue(ref)
- if value.Kind == ast.ValueKindVariable {
- variableName := v.operation.VariableValueNameBytes(value.Ref)
- variableDefinition, exists := v.operation.VariableDefinitionByNameAndOperation(v.Ancestors[0].Ref, variableName)
- if !exists {
- operationName := v.operation.NodeNameBytes(v.Ancestors[0])
- v.StopWithExternalErr(operationreport.ErrVariableNotDefinedOnOperation(variableName, operationName))
- return
- }
- if !v.operation.VariableDefinitions[variableDefinition].DefaultValue.IsDefined {
- return // variable has no default value, deep type check not required
- }
- value = v.operation.VariableDefinitions[variableDefinition].DefaultValue.Value
- }
-
- if !v.valueSatisfiesInputValueDefinitionType(value, v.definition.InputValueDefinitions[definition].Type) {
-
- printedValue, err := v.operation.PrintValueBytes(value, nil)
- if v.HandleInternalErr(err) {
- return
- }
-
- printedType, err := v.definition.PrintTypeBytes(v.definition.InputValueDefinitions[definition].Type, nil)
- if v.HandleInternalErr(err) {
- return
- }
-
- v.StopWithExternalErr(operationreport.ErrValueDoesntSatisfyInputValueDefinition(printedValue, printedType))
- return
- }
-}
-
-func (v *valuesVisitor) valueSatisfiesInputValueDefinitionType(value ast.Value, definitionTypeRef int) bool {
-
- switch v.definition.Types[definitionTypeRef].TypeKind {
- case ast.TypeKindNonNull:
- switch value.Kind {
- case ast.ValueKindNull:
- return false
- case ast.ValueKindVariable:
- variableName := v.operation.VariableValueNameBytes(value.Ref)
- variableDefinition, exists := v.operation.VariableDefinitionByNameAndOperation(v.Ancestors[0].Ref, variableName)
- if !exists {
- return false
- }
- variableTypeRef := v.operation.VariableDefinitions[variableDefinition].Type
- importedDefinitionType := v.importer.ImportType(definitionTypeRef, v.definition, v.operation)
- if !v.operation.TypesAreEqualDeep(importedDefinitionType, variableTypeRef) {
- return false
- }
- }
- return v.valueSatisfiesInputValueDefinitionType(value, v.definition.Types[definitionTypeRef].OfType)
- case ast.TypeKindNamed:
- node, exists := v.definition.Index.FirstNodeByNameBytes(v.definition.ResolveTypeNameBytes(definitionTypeRef))
- if !exists {
- return false
- }
- return v.valueSatisfiesTypeDefinitionNode(value, node)
- case ast.TypeKindList:
- return v.valueSatisfiesListType(value, v.definition.Types[definitionTypeRef].OfType)
- default:
- return false
- }
-}
-
-func (v *valuesVisitor) valueSatisfiesListType(value ast.Value, listType int) bool {
- if value.Kind != ast.ValueKindList {
- return false
- }
-
- if v.definition.Types[listType].TypeKind == ast.TypeKindNonNull {
- if len(v.operation.ListValues[value.Ref].Refs) == 0 {
- return false
- }
- listType = v.definition.Types[listType].OfType
- }
-
- for _, i := range v.operation.ListValues[value.Ref].Refs {
- listValue := v.operation.Value(i)
- if !v.valueSatisfiesInputValueDefinitionType(listValue, listType) {
- return false
- }
- }
-
- return true
-}
-
-func (v *valuesVisitor) valueSatisfiesTypeDefinitionNode(value ast.Value, node ast.Node) bool {
- switch node.Kind {
- case ast.NodeKindEnumTypeDefinition:
- return v.valueSatisfiesEnum(value, node)
- case ast.NodeKindScalarTypeDefinition:
- return v.valueSatisfiesScalar(value, node.Ref)
- case ast.NodeKindInputObjectTypeDefinition:
- return v.valueSatisfiesInputObjectTypeDefinition(value, node.Ref)
- default:
- return false
- }
-}
-
-func (v *valuesVisitor) valueSatisfiesEnum(value ast.Value, node ast.Node) bool {
- if value.Kind != ast.ValueKindEnum {
- return false
- }
- enumValue := v.operation.EnumValueNameBytes(value.Ref)
- return v.definition.EnumTypeDefinitionContainsEnumValue(node.Ref, enumValue)
-}
-
-func (v *valuesVisitor) valueSatisfiesInputObjectTypeDefinition(value ast.Value, inputObjectTypeDefinition int) bool {
- if value.Kind != ast.ValueKindObject {
- return false
- }
-
- for _, i := range v.definition.InputObjectTypeDefinitions[inputObjectTypeDefinition].InputFieldsDefinition.Refs {
- if !v.objectValueSatisfiesInputValueDefinition(value.Ref, i) {
- return false
- }
- }
-
- for _, i := range v.operation.ObjectValues[value.Ref].Refs {
- if !v.objectFieldDefined(i, inputObjectTypeDefinition) {
- objectFieldName := string(v.operation.ObjectFieldNameBytes(i))
- def := string(v.definition.Input.ByteSlice(v.definition.InputObjectTypeDefinitions[inputObjectTypeDefinition].Name))
- _, _ = objectFieldName, def
- return false
- }
- }
-
- return !v.objectValueHasDuplicateFields(value.Ref)
-}
-
-func (v *valuesVisitor) objectValueHasDuplicateFields(objectValue int) bool {
- for i, j := range v.operation.ObjectValues[objectValue].Refs {
- for k, l := range v.operation.ObjectValues[objectValue].Refs {
- if i == k || i > k {
- continue
- }
- if bytes.Equal(v.operation.ObjectFieldNameBytes(j), v.operation.ObjectFieldNameBytes(l)) {
- return true
- }
- }
- }
- return false
-}
-
-func (v *valuesVisitor) objectFieldDefined(objectField, inputObjectTypeDefinition int) bool {
- name := v.operation.ObjectFieldNameBytes(objectField)
- for _, i := range v.definition.InputObjectTypeDefinitions[inputObjectTypeDefinition].InputFieldsDefinition.Refs {
- if bytes.Equal(name, v.definition.InputValueDefinitionNameBytes(i)) {
- return true
- }
- }
- return false
-}
-
-func (v *valuesVisitor) objectValueSatisfiesInputValueDefinition(objectValue, inputValueDefinition int) bool {
-
- name := v.definition.InputValueDefinitionNameBytes(inputValueDefinition)
- definitionType := v.definition.InputValueDefinitionType(inputValueDefinition)
-
- for _, i := range v.operation.ObjectValues[objectValue].Refs {
- if bytes.Equal(name, v.operation.ObjectFieldNameBytes(i)) {
- value := v.operation.ObjectFieldValue(i)
- return v.valueSatisfiesInputValueDefinitionType(value, definitionType)
- }
- }
-
- // argument is not present on object value, if arg is optional it's still ok, otherwise not satisfied
- return v.definition.InputValueDefinitionArgumentIsOptional(inputValueDefinition)
-}
-
-func (v *valuesVisitor) valueSatisfiesScalar(value ast.Value, scalar int) bool {
- scalarName := v.definition.ScalarTypeDefinitionNameString(scalar)
- if value.Kind == ast.ValueKindVariable {
- variableName := v.operation.VariableValueNameBytes(value.Ref)
- variableDefinition, exists := v.operation.VariableDefinitionByNameAndOperation(v.Ancestors[0].Ref, variableName)
- if !exists {
- return false
- }
- variableTypeRef := v.operation.VariableDefinitions[variableDefinition].Type
- typeName := v.operation.ResolveTypeNameString(variableTypeRef)
- return scalarName == typeName
- }
- switch scalarName {
- case "Boolean":
- return value.Kind == ast.ValueKindBoolean
- case "Int":
- return value.Kind == ast.ValueKindInteger
- case "Float":
- return value.Kind == ast.ValueKindFloat || value.Kind == ast.ValueKindInteger
- default:
- return value.Kind == ast.ValueKindString
- }
-}
-
-// ArgumentUniqueness validates if arguments are unique
-func ArgumentUniqueness() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := argumentUniquenessVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterArgumentVisitor(&visitor)
- }
-}
-
-type argumentUniquenessVisitor struct {
- *astvisitor.Walker
- operation *ast.Document
-}
-
-func (a *argumentUniquenessVisitor) EnterDocument(operation, definition *ast.Document) {
- a.operation = operation
-}
-
-func (a *argumentUniquenessVisitor) EnterArgument(ref int) {
-
- argumentName := a.operation.ArgumentNameBytes(ref)
- argumentsAfter := a.operation.ArgumentsAfter(a.Ancestors[len(a.Ancestors)-1], ref)
-
- for _, i := range argumentsAfter {
- if bytes.Equal(argumentName, a.operation.ArgumentNameBytes(i)) {
- a.StopWithExternalErr(operationreport.ErrArgumentMustBeUnique(argumentName))
- return
- }
- }
-}
-
-// RequiredArguments validates if all required arguments are present
-func RequiredArguments() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := requiredArgumentsVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterFieldVisitor(&visitor)
- }
-}
-
-type requiredArgumentsVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (r *requiredArgumentsVisitor) EnterDocument(operation, definition *ast.Document) {
- r.operation = operation
- r.definition = definition
-}
-
-func (r *requiredArgumentsVisitor) EnterField(ref int) {
-
- fieldName := r.operation.FieldNameBytes(ref)
- inputValueDefinitions := r.definition.NodeFieldDefinitionArgumentsDefinitions(r.EnclosingTypeDefinition, fieldName)
-
- for _, i := range inputValueDefinitions {
- if r.definition.InputValueDefinitionArgumentIsOptional(i) {
- continue
- }
-
- name := r.definition.InputValueDefinitionNameBytes(i)
-
- argument, exists := r.operation.FieldArgument(ref, name)
- if !exists {
- r.StopWithExternalErr(operationreport.ErrArgumentRequiredOnField(name, fieldName))
- return
- }
-
- if r.operation.ArgumentValue(argument).Kind == ast.ValueKindNull {
- r.StopWithExternalErr(operationreport.ErrArgumentOnFieldMustNotBeNull(name, fieldName))
- return
- }
- }
-}
-
-// Fragments validates if the use of fragments in a given document is correct
-func Fragments() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := fragmentsVisitor{
- Walker: walker,
- fragmentDefinitionsVisited: make([]ast.ByteSlice, 0, 8),
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterLeaveDocumentVisitor(&visitor)
- walker.RegisterEnterFragmentDefinitionVisitor(&visitor)
- walker.RegisterEnterInlineFragmentVisitor(&visitor)
- walker.RegisterEnterFragmentSpreadVisitor(&visitor)
- }
-}
-
-type fragmentsVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
- fragmentDefinitionsVisited []ast.ByteSlice
-}
-
-func (f *fragmentsVisitor) EnterFragmentSpread(ref int) {
- if f.Ancestors[0].Kind == ast.NodeKindOperationDefinition {
- spreadName := f.operation.FragmentSpreadNameBytes(ref)
- f.StopWithExternalErr(operationreport.ErrFragmentSpreadFormsCycle(spreadName))
- }
-}
-
-func (f *fragmentsVisitor) LeaveDocument(operation, definition *ast.Document) {
- for i := range f.fragmentDefinitionsVisited {
- if !f.operation.FragmentDefinitionIsUsed(f.fragmentDefinitionsVisited[i]) {
- fragmentName := f.fragmentDefinitionsVisited[i]
- f.StopWithExternalErr(operationreport.ErrFragmentDefinedButNotUsed(fragmentName))
- return
- }
- }
-}
-
-func (f *fragmentsVisitor) fragmentOnNodeIsAllowed(node ast.Node) bool {
- switch node.Kind {
- case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition, ast.NodeKindUnionTypeDefinition:
- return true
- default:
- return false
- }
-}
-
-func (f *fragmentsVisitor) EnterInlineFragment(ref int) {
-
- if !f.operation.InlineFragmentHasTypeCondition(ref) {
- return
- }
-
- typeName := f.operation.InlineFragmentTypeConditionName(ref)
-
- node, exists := f.definition.Index.FirstNodeByNameBytes(typeName)
- if !exists {
- f.StopWithExternalErr(operationreport.ErrTypeUndefined(typeName))
- return
- }
-
- if !f.fragmentOnNodeIsAllowed(node) {
- f.StopWithExternalErr(operationreport.ErrInlineFragmentOnTypeDisallowed(typeName))
- return
- }
-
- if !f.definition.NodeFragmentIsAllowedOnNode(node, f.EnclosingTypeDefinition) {
- enclosingTypeName := f.definition.NodeNameBytes(f.EnclosingTypeDefinition)
- f.StopWithExternalErr(operationreport.ErrInlineFragmentOnTypeMismatchEnclosingType(typeName, enclosingTypeName))
- return
- }
-}
-
-func (f *fragmentsVisitor) EnterDocument(operation, definition *ast.Document) {
- f.operation = operation
- f.definition = definition
- f.fragmentDefinitionsVisited = f.fragmentDefinitionsVisited[:0]
-}
-
-func (f *fragmentsVisitor) EnterFragmentDefinition(ref int) {
-
- fragmentDefinitionName := f.operation.FragmentDefinitionNameBytes(ref)
- typeName := f.operation.FragmentDefinitionTypeName(ref)
-
- node, exists := f.definition.Index.FirstNodeByNameBytes(typeName)
- if !exists {
- f.StopWithExternalErr(operationreport.ErrTypeUndefined(typeName))
- return
- }
-
- if !f.fragmentOnNodeIsAllowed(node) {
- f.StopWithExternalErr(operationreport.ErrFragmentDefinitionOnTypeDisallowed(fragmentDefinitionName, typeName))
- return
- }
-
- for i := range f.fragmentDefinitionsVisited {
- if bytes.Equal(fragmentDefinitionName, f.fragmentDefinitionsVisited[i]) {
- f.StopWithExternalErr(operationreport.ErrFragmentDefinitionMustBeUnique(fragmentDefinitionName))
- return
- }
- }
-
- f.fragmentDefinitionsVisited = append(f.fragmentDefinitionsVisited, fragmentDefinitionName)
-}
-
-// DirectivesAreDefined validates if used directives are defined
-func DirectivesAreDefined() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := directivesAreDefinedVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterDirectiveVisitor(&visitor)
- }
-}
-
-type directivesAreDefinedVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (d *directivesAreDefinedVisitor) EnterDocument(operation, definition *ast.Document) {
- d.operation = operation
- d.definition = definition
-}
-
-func (d *directivesAreDefinedVisitor) EnterDirective(ref int) {
-
- directiveName := d.operation.DirectiveNameBytes(ref)
- definition, exists := d.definition.Index.FirstNodeByNameBytes(directiveName)
-
- if !exists || definition.Kind != ast.NodeKindDirectiveDefinition {
- d.StopWithExternalErr(operationreport.ErrDirectiveUndefined(directiveName))
- return
- }
-}
-
-// DirectivesAreInValidLocations validates if directives are used in the right place
-func DirectivesAreInValidLocations() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := directivesAreInValidLocationsVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterDirectiveVisitor(&visitor)
- }
-}
-
-type directivesAreInValidLocationsVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (d *directivesAreInValidLocationsVisitor) EnterDocument(operation, definition *ast.Document) {
- d.operation = operation
- d.definition = definition
-}
-
-func (d *directivesAreInValidLocationsVisitor) EnterDirective(ref int) {
-
- directiveName := d.operation.DirectiveNameBytes(ref)
- definition, exists := d.definition.Index.FirstNodeByNameBytes(directiveName)
-
- if !exists || definition.Kind != ast.NodeKindDirectiveDefinition {
- return // not defined, skip
- }
-
- ancestor := d.Ancestors[len(d.Ancestors)-1]
-
- if !d.directiveDefinitionContainsNodeLocation(definition.Ref, ancestor) {
- ancestorKindName := d.operation.NodeKindNameBytes(ancestor)
- d.StopWithExternalErr(operationreport.ErrDirectiveNotAllowedOnNode(directiveName, ancestorKindName))
- return
- }
-}
-
-func (d *directivesAreInValidLocationsVisitor) directiveDefinitionContainsNodeLocation(definition int, node ast.Node) bool {
-
- nodeDirectiveLocation, err := d.operation.NodeDirectiveLocation(node)
- if err != nil {
- return false
- }
-
- return d.definition.DirectiveDefinitions[definition].DirectiveLocations.Get(nodeDirectiveLocation)
-}
-
-// VariableUniqueness validates if variables are unique in a given document
-func VariableUniqueness() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := variableUniquenessVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterVariableDefinitionVisitor(&visitor)
- }
-}
-
-type variableUniquenessVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (v *variableUniquenessVisitor) EnterDocument(operation, definition *ast.Document) {
- v.operation = operation
- v.definition = definition
-}
-
-func (v *variableUniquenessVisitor) EnterVariableDefinition(ref int) {
-
- name := v.operation.VariableDefinitionNameBytes(ref)
-
- if v.Ancestors[0].Kind != ast.NodeKindOperationDefinition {
- return
- }
-
- variableDefinitions := v.operation.OperationDefinitions[v.Ancestors[0].Ref].VariableDefinitions.Refs
-
- for _, i := range variableDefinitions {
- if i == ref {
- continue
- }
- if bytes.Equal(name, v.operation.VariableDefinitionNameBytes(i)) {
- if v.Ancestors[0].Kind != ast.NodeKindOperationDefinition {
- v.StopWithInternalErr(fmt.Errorf("variable definition must have Operation ObjectDefinition as root ancestor, got: %s", v.Ancestors[0].Kind))
- return
- }
- operationName := v.operation.Input.ByteSlice(v.operation.OperationDefinitions[v.Ancestors[0].Ref].Name)
- v.StopWithExternalErr(operationreport.ErrVariableMustBeUnique(name, operationName))
- return
- }
- }
-}
-
-// DirectivesAreUniquePerLocation validates if directives are unique per location
-func DirectivesAreUniquePerLocation() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := directivesAreUniquePerLocationVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterDirectiveVisitor(&visitor)
- }
-}
-
-type directivesAreUniquePerLocationVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (d *directivesAreUniquePerLocationVisitor) EnterDocument(operation, definition *ast.Document) {
- d.operation = operation
- d.definition = definition
-}
-
-func (d *directivesAreUniquePerLocationVisitor) EnterDirective(ref int) {
-
- directiveName := d.operation.DirectiveNameBytes(ref)
- directives := d.operation.NodeDirectives(d.Ancestors[len(d.Ancestors)-1])
-
- for _, j := range directives {
- if j == ref {
- continue
- }
- if bytes.Equal(directiveName, d.operation.DirectiveNameBytes(j)) {
- d.StopWithExternalErr(operationreport.ErrDirectiveMustBeUniquePerLocation(directiveName))
- return
- }
- }
-}
-
-// VariablesAreInputTypes validates if variables are correct input types
-func VariablesAreInputTypes() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := variablesAreInputTypesVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterVariableDefinitionVisitor(&visitor)
- }
-}
-
-type variablesAreInputTypesVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (v *variablesAreInputTypesVisitor) EnterDocument(operation, definition *ast.Document) {
- v.operation = operation
- v.definition = definition
-}
-
-func (v *variablesAreInputTypesVisitor) EnterVariableDefinition(ref int) {
-
- typeName := v.operation.ResolveTypeNameBytes(v.operation.VariableDefinitions[ref].Type)
- typeDefinitionNode, _ := v.definition.Index.FirstNodeByNameBytes(typeName)
- switch typeDefinitionNode.Kind {
- case ast.NodeKindInputObjectTypeDefinition, ast.NodeKindScalarTypeDefinition, ast.NodeKindEnumTypeDefinition:
- return
- default:
- variableName := v.operation.VariableDefinitionNameBytes(ref)
- v.StopWithExternalErr(operationreport.ErrVariableOfTypeIsNoValidInputValue(variableName, typeName))
- return
- }
-}
-
-// AllVariableUsesDefined validates if used variables are defined within the operation
-func AllVariableUsesDefined() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := allVariableUsesDefinedVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterArgumentVisitor(&visitor)
- }
-}
-
-type allVariableUsesDefinedVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
-}
-
-func (a *allVariableUsesDefinedVisitor) EnterDocument(operation, definition *ast.Document) {
- a.operation = operation
- a.definition = definition
-}
-
-func (a *allVariableUsesDefinedVisitor) EnterArgument(ref int) {
-
- if a.operation.Arguments[ref].Value.Kind != ast.ValueKindVariable {
- return // skip because no variable
- }
-
- if a.Ancestors[0].Kind != ast.NodeKindOperationDefinition {
- // skip because variable is not used in operation which happens in case normalization did not merge the fragment definition
- // this happens when a fragment is defined but not used which will itself lead to another validation error
- // in which case we can safely skip here
- return
- }
-
- variableName := a.operation.VariableValueNameBytes(a.operation.Arguments[ref].Value.Ref)
-
- for _, i := range a.operation.OperationDefinitions[a.Ancestors[0].Ref].VariableDefinitions.Refs {
- if bytes.Equal(variableName, a.operation.VariableDefinitionNameBytes(i)) {
- return // return OK because variable is defined
- }
- }
-
- // at this point we're safe to say this variable was not defined on the root operation of this argument
- argumentName := a.operation.ArgumentNameBytes(ref)
- a.StopWithExternalErr(operationreport.ErrVariableNotDefinedOnArgument(variableName, argumentName))
-}
-
-// AllVariablesUsed validates if all defined variables are used
-func AllVariablesUsed() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := allVariablesUsedVisitor{
- Walker: walker,
- }
- walker.RegisterEnterDocumentVisitor(&visitor)
- walker.RegisterEnterOperationVisitor(&visitor)
- walker.RegisterLeaveOperationVisitor(&visitor)
- walker.RegisterEnterArgumentVisitor(&visitor)
- }
-}
-
-type allVariablesUsedVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
- variableDefinitions []int
-}
-
-func (a *allVariablesUsedVisitor) EnterDocument(operation, definition *ast.Document) {
- a.operation = operation
- a.definition = definition
- a.variableDefinitions = a.variableDefinitions[:0]
-}
-
-func (a *allVariablesUsedVisitor) EnterOperationDefinition(ref int) {
- a.variableDefinitions = append(a.variableDefinitions, a.operation.OperationDefinitions[ref].VariableDefinitions.Refs...)
-}
-
-func (a *allVariablesUsedVisitor) LeaveOperationDefinition(ref int) {
- if len(a.variableDefinitions) != 0 {
- operationName := a.operation.Input.ByteSlice(a.operation.OperationDefinitions[ref].Name)
- for _, i := range a.variableDefinitions {
- variableName := a.operation.VariableDefinitionNameBytes(i)
- a.Report.AddExternalError(operationreport.ErrVariableDefinedButNeverUsed(variableName, operationName))
- }
- a.Stop()
- }
-}
-
-func (a *allVariablesUsedVisitor) EnterArgument(ref int) {
-
- if len(a.variableDefinitions) == 0 {
- return // nothing to check, skip
- }
-
- a.verifyValue(a.operation.Arguments[ref].Value)
-}
-
-func (a *allVariablesUsedVisitor) verifyValue(value ast.Value) {
- switch value.Kind {
- case ast.ValueKindVariable: // don't skip
- case ast.ValueKindObject:
- for _, i := range a.operation.ObjectValues[value.Ref].Refs {
- a.verifyValue(a.operation.ObjectFields[i].Value)
- }
- return
- case ast.ValueKindList:
- for _, i := range a.operation.ListValues[value.Ref].Refs {
- a.verifyValue(a.operation.Values[i])
- }
- default:
- return // skip all others
- }
-
- variableName := a.operation.VariableValueNameBytes(value.Ref)
- for i, j := range a.variableDefinitions {
- if bytes.Equal(variableName, a.operation.VariableDefinitionNameBytes(j)) {
- a.variableDefinitions = append(a.variableDefinitions[:i], a.variableDefinitions[i+1:]...)
- return
- }
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/astvalidation_string.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/astvalidation_string.go
deleted file mode 100644
index 396508b13fb..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/astvalidation_string.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Code generated by "stringer -type=ValidationState -output astvalidation_string.go"; DO NOT EDIT.
-
-package astvalidation
-
-import "strconv"
-
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[UnknownState-0]
- _ = x[Valid-1]
- _ = x[Invalid-2]
-}
-
-const _ValidationState_name = "UnknownStateValidInvalid"
-
-var _ValidationState_index = [...]uint8{0, 12, 17, 24}
-
-func (i ValidationState) String() string {
- if i < 0 || i >= ValidationState(len(_ValidationState_index)-1) {
- return "ValidationState(" + strconv.FormatInt(int64(i), 10) + ")"
- }
- return _ValidationState_name[_ValidationState_index[i]:_ValidationState_index[i+1]]
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/definition_validation.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/definition_validation.go
deleted file mode 100644
index ff4da1b2f3b..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/definition_validation.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package astvalidation
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-func DefaultDefinitionValidator() *DefinitionValidator {
- validator := &DefinitionValidator{
- walker: astvisitor.NewWalker(48),
- }
-
- validator.RegisterRule(UniqueOperationTypes())
- validator.RegisterRule(UniqueTypeNames())
- validator.RegisterRule(UniqueFieldDefinitionNames())
- validator.RegisterRule(UniqueEnumValueNames())
- validator.RegisterRule(KnownTypeNames())
-
- return validator
-}
-
-type DefinitionValidator struct {
- walker astvisitor.Walker
-}
-
-func (d *DefinitionValidator) RegisterRule(rule Rule) {
- rule(&d.walker)
-}
-
-func (d *DefinitionValidator) Validate(definition *ast.Document, report *operationreport.Report) ValidationState {
- if report == nil {
- report = &operationreport.Report{}
- }
-
- d.walker.Walk(definition, nil, report)
-
- if report.HasErrors() {
- return Invalid
- }
- return Valid
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_known_type_names.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_known_type_names.go
deleted file mode 100644
index c49403801f8..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_known_type_names.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package astvalidation
-
-import (
- "github.com/cespare/xxhash"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-func KnownTypeNames() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := &knownTypeNamesVisitor{
- Walker: walker,
- }
-
- walker.RegisterDocumentVisitor(visitor)
- walker.RegisterEnterRootOperationTypeDefinitionVisitor(visitor)
- walker.RegisterEnterFieldDefinitionVisitor(visitor)
- walker.RegisterEnterUnionMemberTypeVisitor(visitor)
- walker.RegisterEnterInputValueDefinitionVisitor(visitor)
- walker.RegisterEnterObjectTypeDefinitionVisitor(visitor)
- walker.RegisterEnterInterfaceTypeDefinitionVisitor(visitor)
- walker.RegisterEnterScalarTypeDefinitionVisitor(visitor)
- walker.RegisterEnterUnionTypeDefinitionVisitor(visitor)
- walker.RegisterEnterInputObjectTypeDefinitionVisitor(visitor)
- walker.RegisterEnterEnumTypeDefinitionVisitor(visitor)
- }
-}
-
-type knownTypeNamesVisitor struct {
- *astvisitor.Walker
- definition *ast.Document
- definedTypeNameHashs map[uint64]bool
- referencedTypeNames map[uint64][]byte
-}
-
-func (u *knownTypeNamesVisitor) EnterDocument(operation, definition *ast.Document) {
- u.definition = operation
- u.definedTypeNameHashs = make(map[uint64]bool)
- u.referencedTypeNames = make(map[uint64][]byte)
-}
-
-func (u *knownTypeNamesVisitor) LeaveDocument(operation, definition *ast.Document) {
- for referencedTypeNameHash, referencedTypeName := range u.referencedTypeNames {
- if !u.definedTypeNameHashs[referencedTypeNameHash] {
- u.Report.AddExternalError(operationreport.ErrTypeUndefined(referencedTypeName))
- continue
- }
- }
-
-}
-
-func (u *knownTypeNamesVisitor) EnterRootOperationTypeDefinition(ref int) {
- referencedTypeName := u.definition.Input.ByteSlice(u.definition.RootOperationTypeDefinitions[ref].NamedType.Name)
- u.saveReferencedTypeName(referencedTypeName)
- u.saveReferencedTypeName(referencedTypeName)
-}
-
-func (u *knownTypeNamesVisitor) EnterFieldDefinition(ref int) {
- referencedTypeRef := u.definition.FieldDefinitions[ref].Type
- referencedTypeName := u.definition.TypeNameBytes(referencedTypeRef)
- u.saveReferencedTypeName(referencedTypeName)
-}
-
-func (u *knownTypeNamesVisitor) EnterUnionMemberType(ref int) {
- referencedTypeName := u.definition.TypeNameBytes(ref)
- u.saveReferencedTypeName(referencedTypeName)
-}
-
-func (u *knownTypeNamesVisitor) EnterInputValueDefinition(ref int) {
- referencedTypeRef := u.definition.InputValueDefinitions[ref].Type
- referencedTypeName := u.definition.TypeNameBytes(referencedTypeRef)
- u.saveReferencedTypeName(referencedTypeName)
-}
-
-func (u *knownTypeNamesVisitor) EnterObjectTypeDefinition(ref int) {
- typeName := u.definition.ObjectTypeDefinitionNameBytes(ref)
- u.saveTypeName(typeName)
-}
-
-func (u *knownTypeNamesVisitor) EnterInterfaceTypeDefinition(ref int) {
- typeName := u.definition.InterfaceTypeDefinitionNameBytes(ref)
- u.saveTypeName(typeName)
-}
-
-func (u *knownTypeNamesVisitor) EnterScalarTypeDefinition(ref int) {
- typeName := u.definition.ScalarTypeDefinitionNameBytes(ref)
- u.saveTypeName(typeName)
-}
-
-func (u *knownTypeNamesVisitor) EnterUnionTypeDefinition(ref int) {
- typeName := u.definition.UnionTypeDefinitionNameBytes(ref)
- u.saveTypeName(typeName)
-}
-
-func (u *knownTypeNamesVisitor) EnterInputObjectTypeDefinition(ref int) {
- typeName := u.definition.InputObjectTypeDefinitionNameBytes(ref)
- u.saveTypeName(typeName)
-}
-
-func (u *knownTypeNamesVisitor) EnterEnumTypeDefinition(ref int) {
- typeName := u.definition.EnumTypeDefinitionNameBytes(ref)
- u.saveTypeName(typeName)
-}
-
-func (u *knownTypeNamesVisitor) saveTypeName(typeName ast.ByteSlice) {
- u.definedTypeNameHashs[xxhash.Sum64(typeName)] = true
-}
-
-func (u *knownTypeNamesVisitor) saveReferencedTypeName(referencedTypeName ast.ByteSlice) {
- if len(referencedTypeName) == 0 {
- return
- }
- u.referencedTypeNames[xxhash.Sum64(referencedTypeName)] = referencedTypeName
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_enum_value_names.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_enum_value_names.go
deleted file mode 100644
index f2f0c36ac54..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_enum_value_names.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package astvalidation
-
-import (
- "github.com/cespare/xxhash"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type hashedEnumValueNames map[uint64]bool
-
-func UniqueEnumValueNames() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := &uniqueEnumValueNamesVisitor{
- Walker: walker,
- }
-
- walker.RegisterEnterDocumentVisitor(visitor)
- walker.RegisterEnterEnumValueDefinitionVisitor(visitor)
- walker.RegisterEnumTypeDefinitionVisitor(visitor)
- walker.RegisterEnumTypeExtensionVisitor(visitor)
- }
-}
-
-type uniqueEnumValueNamesVisitor struct {
- *astvisitor.Walker
- definition *ast.Document
- currentEnumName ast.ByteSlice
- currentEnumHash uint64
- usedEnumValues map[uint64]hashedEnumValueNames
-}
-
-func (u *uniqueEnumValueNamesVisitor) EnterDocument(operation, definition *ast.Document) {
- u.definition = operation
- u.currentEnumName = u.currentEnumName[:0]
- u.currentEnumHash = 0
- u.usedEnumValues = make(map[uint64]hashedEnumValueNames)
-}
-
-func (u *uniqueEnumValueNamesVisitor) EnterEnumValueDefinition(ref int) {
- enumValueName := u.definition.EnumValueDefinitionNameBytes(ref)
- u.checkEnumValueName(enumValueName)
-}
-
-func (u *uniqueEnumValueNamesVisitor) EnterEnumTypeDefinition(ref int) {
- enumName := u.definition.EnumTypeDefinitionNameBytes(ref)
- u.setCurrentEnum(enumName)
-}
-
-func (u *uniqueEnumValueNamesVisitor) LeaveEnumTypeDefinition(ref int) {
- u.unsetCurrentEnum()
-}
-
-func (u *uniqueEnumValueNamesVisitor) EnterEnumTypeExtension(ref int) {
- enumName := u.definition.EnumTypeExtensionNameBytes(ref)
- u.setCurrentEnum(enumName)
-}
-
-func (u *uniqueEnumValueNamesVisitor) LeaveEnumTypeExtension(ref int) {
- u.unsetCurrentEnum()
-}
-
-func (u *uniqueEnumValueNamesVisitor) setCurrentEnum(enumName ast.ByteSlice) {
- u.currentEnumName = enumName
- u.currentEnumHash = xxhash.Sum64(enumName)
-}
-
-func (u *uniqueEnumValueNamesVisitor) unsetCurrentEnum() {
- u.currentEnumName = u.currentEnumName[:0]
- u.currentEnumHash = 0
-}
-
-func (u *uniqueEnumValueNamesVisitor) checkEnumValueName(enumValueName ast.ByteSlice) {
- if len(u.currentEnumName) == 0 || u.currentEnumHash == 0 {
- return
- }
-
- enumValueNameHash := xxhash.Sum64(enumValueName)
- enumValueNames, ok := u.usedEnumValues[u.currentEnumHash]
- if !ok {
- enumValueNames = make(hashedEnumValueNames)
- }
-
- if enumValueNames[enumValueNameHash] {
- u.Report.AddExternalError(operationreport.ErrEnumValueNameMustBeUnique(u.currentEnumName, enumValueName))
- return
- }
-
- enumValueNames[enumValueNameHash] = true
- u.usedEnumValues[u.currentEnumHash] = enumValueNames
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_field_definition_names.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_field_definition_names.go
deleted file mode 100644
index 82eb5ee7a8b..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_field_definition_names.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package astvalidation
-
-import (
- "bytes"
-
- "github.com/cespare/xxhash"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type hashedFieldNames map[uint64]bool
-
-func UniqueFieldDefinitionNames() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := &uniqueFieldDefinitionNamesVisitor{
- Walker: walker,
- }
-
- walker.RegisterEnterDocumentVisitor(visitor)
- walker.RegisterEnterFieldDefinitionVisitor(visitor)
- walker.RegisterEnterInputValueDefinitionVisitor(visitor)
- walker.RegisterObjectTypeDefinitionVisitor(visitor)
- walker.RegisterObjectTypeExtensionVisitor(visitor)
- walker.RegisterInterfaceTypeDefinitionVisitor(visitor)
- walker.RegisterInterfaceTypeExtensionVisitor(visitor)
- walker.RegisterInputObjectTypeDefinitionVisitor(visitor)
- walker.RegisterInputObjectTypeExtensionVisitor(visitor)
- }
-}
-
-type uniqueFieldDefinitionNamesVisitor struct {
- *astvisitor.Walker
- definition *ast.Document
- currentTypeName ast.ByteSlice
- currentTypeNameHash uint64
- currentTypeKind ast.NodeKind
- usedFieldNames map[uint64]hashedFieldNames // map of hashed type names containing a map of hashed field names
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) EnterDocument(operation, definition *ast.Document) {
- u.definition = operation
- u.currentTypeName = u.currentTypeName[:0]
- u.currentTypeNameHash = 0
- u.currentTypeKind = ast.NodeKindUnknown
- u.usedFieldNames = make(map[uint64]hashedFieldNames)
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) EnterFieldDefinition(ref int) {
- fieldName := u.definition.FieldDefinitionNameBytes(ref)
- u.checkField(fieldName)
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) EnterInputValueDefinition(ref int) {
- if u.currentTypeKind != ast.NodeKindInputObjectTypeDefinition && u.currentTypeKind != ast.NodeKindInputObjectTypeExtension {
- return
- }
-
- name := u.definition.InputValueDefinitionNameBytes(ref)
- u.checkField(name)
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) EnterObjectTypeDefinition(ref int) {
- typeName := u.definition.ObjectTypeDefinitionNameBytes(ref)
- u.setCurrentTypeName(typeName, ast.NodeKindObjectTypeDefinition)
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) LeaveObjectTypeDefinition(ref int) {
- u.unsetCurrentTypeName()
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) EnterObjectTypeExtension(ref int) {
- typeName := u.definition.ObjectTypeExtensionNameBytes(ref)
- u.setCurrentTypeName(typeName, ast.NodeKindObjectTypeExtension)
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) LeaveObjectTypeExtension(ref int) {
- u.unsetCurrentTypeName()
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) EnterInterfaceTypeDefinition(ref int) {
- typeName := u.definition.InterfaceTypeDefinitionNameBytes(ref)
- u.setCurrentTypeName(typeName, ast.NodeKindInterfaceTypeDefinition)
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) LeaveInterfaceTypeDefinition(ref int) {
- u.unsetCurrentTypeName()
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) EnterInterfaceTypeExtension(ref int) {
- typeName := u.definition.InterfaceTypeExtensionNameBytes(ref)
- u.setCurrentTypeName(typeName, ast.NodeKindInterfaceTypeExtension)
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) LeaveInterfaceTypeExtension(ref int) {
- u.unsetCurrentTypeName()
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) EnterInputObjectTypeDefinition(ref int) {
- typeName := u.definition.InputObjectTypeDefinitionNameBytes(ref)
- u.setCurrentTypeName(typeName, ast.NodeKindObjectTypeDefinition)
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) LeaveInputObjectTypeDefinition(ref int) {
- u.unsetCurrentTypeName()
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) EnterInputObjectTypeExtension(ref int) {
- typeName := u.definition.InputObjectTypeExtensionNameBytes(ref)
- u.setCurrentTypeName(typeName, ast.NodeKindInputObjectTypeExtension)
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) LeaveInputObjectTypeExtension(ref int) {
- u.unsetCurrentTypeName()
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) setCurrentTypeName(typeName ast.ByteSlice, kind ast.NodeKind) {
- if bytes.HasPrefix(typeName, []byte("__")) { // ignore graphql reserved types
- return
- }
-
- u.currentTypeName = typeName
- u.currentTypeNameHash = xxhash.Sum64(typeName)
- u.currentTypeKind = kind
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) unsetCurrentTypeName() {
- u.currentTypeName = u.currentTypeName[:0]
- u.currentTypeNameHash = 0
- u.currentTypeKind = ast.NodeKindUnknown
-}
-
-func (u *uniqueFieldDefinitionNamesVisitor) checkField(fieldName ast.ByteSlice) {
- if bytes.HasPrefix(fieldName, []byte("__")) { // don't validate graphql reserved fields
- return
- }
-
- if len(u.currentTypeName) == 0 || u.currentTypeNameHash == 0 || u.currentTypeKind == ast.NodeKindUnknown {
- return
- }
-
- fieldNames, ok := u.usedFieldNames[u.currentTypeNameHash]
- if !ok {
- fieldNames = make(hashedFieldNames)
- }
-
- if fieldNames[xxhash.Sum64(fieldName)] {
- u.Report.AddExternalError(operationreport.ErrFieldNameMustBeUniqueOnType(fieldName, u.currentTypeName))
- return
- }
-
- fieldNames[xxhash.Sum64(fieldName)] = true
- u.usedFieldNames[u.currentTypeNameHash] = fieldNames
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_operation_types.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_operation_types.go
deleted file mode 100644
index 73b4abd733e..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_operation_types.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package astvalidation
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-func UniqueOperationTypes() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := &uniqueOperationTypesVisitor{
- Walker: walker,
- }
-
- walker.RegisterEnterDocumentVisitor(visitor)
- walker.RegisterEnterRootOperationTypeDefinitionVisitor(visitor)
- }
-}
-
-type uniqueOperationTypesVisitor struct {
- *astvisitor.Walker
- definition *ast.Document
- queryIsDefined bool
- mutationIsDefined bool
- subscriptionIsDefined bool
-}
-
-func (u *uniqueOperationTypesVisitor) EnterDocument(operation, definition *ast.Document) {
- u.definition = operation
- u.queryIsDefined = false
- u.mutationIsDefined = false
- u.subscriptionIsDefined = false
-}
-
-func (u *uniqueOperationTypesVisitor) EnterRootOperationTypeDefinition(ref int) {
- operationType := u.definition.RootOperationTypeDefinitions[ref].OperationType
- switch operationType {
- case ast.OperationTypeQuery:
- if u.queryIsDefined {
- u.Report.AddExternalError(operationreport.ErrOnlyOneQueryTypeAllowed())
- }
- u.queryIsDefined = true
- case ast.OperationTypeMutation:
- if u.mutationIsDefined {
- u.Report.AddExternalError(operationreport.ErrOnlyOneMutationTypeAllowed())
- }
- u.mutationIsDefined = true
- case ast.OperationTypeSubscription:
- if u.subscriptionIsDefined {
- u.Report.AddExternalError(operationreport.ErrOnlyOneSubscriptionTypeAllowed())
- }
- u.subscriptionIsDefined = true
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_type_names.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_type_names.go
deleted file mode 100644
index a8389522ea2..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvalidation/rule_unique_type_names.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package astvalidation
-
-import (
- "github.com/cespare/xxhash"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-func UniqueTypeNames() Rule {
- return func(walker *astvisitor.Walker) {
- visitor := &uniqueTypeNamesVisitor{
- Walker: walker,
- }
-
- walker.RegisterEnterDocumentVisitor(visitor)
- walker.RegisterEnterObjectTypeDefinitionVisitor(visitor)
- walker.RegisterEnterScalarTypeDefinitionVisitor(visitor)
- walker.RegisterEnterInterfaceTypeDefinitionVisitor(visitor)
- walker.RegisterEnterUnionTypeDefinitionVisitor(visitor)
- walker.RegisterEnterEnumTypeDefinitionVisitor(visitor)
- walker.RegisterEnterInputObjectTypeDefinitionVisitor(visitor)
- }
-}
-
-type uniqueTypeNamesVisitor struct {
- *astvisitor.Walker
- definition *ast.Document
- usedTypeNamesAsHash map[uint64]bool
-}
-
-func (u *uniqueTypeNamesVisitor) EnterDocument(operation, definition *ast.Document) {
- u.definition = operation
- u.usedTypeNamesAsHash = make(map[uint64]bool)
-}
-
-func (u *uniqueTypeNamesVisitor) EnterObjectTypeDefinition(ref int) {
- typeName := u.definition.ObjectTypeDefinitionNameBytes(ref)
- u.checkTypeName(typeName)
-}
-
-func (u *uniqueTypeNamesVisitor) EnterScalarTypeDefinition(ref int) {
- typeName := u.definition.ScalarTypeDefinitionNameBytes(ref)
- u.checkTypeName(typeName)
-}
-
-func (u *uniqueTypeNamesVisitor) EnterInterfaceTypeDefinition(ref int) {
- typeName := u.definition.InterfaceTypeDefinitionNameBytes(ref)
- u.checkTypeName(typeName)
-}
-
-func (u *uniqueTypeNamesVisitor) EnterUnionTypeDefinition(ref int) {
- typeName := u.definition.UnionTypeDefinitionNameBytes(ref)
- u.checkTypeName(typeName)
-}
-
-func (u *uniqueTypeNamesVisitor) EnterEnumTypeDefinition(ref int) {
- typeName := u.definition.EnumTypeDefinitionNameBytes(ref)
- u.checkTypeName(typeName)
-}
-
-func (u *uniqueTypeNamesVisitor) EnterInputObjectTypeDefinition(ref int) {
- typeName := u.definition.InputObjectTypeDefinitionNameBytes(ref)
- u.checkTypeName(typeName)
-}
-
-func (u *uniqueTypeNamesVisitor) checkTypeName(typeName ast.ByteSlice) {
- hashedTypeName := xxhash.Sum64(typeName)
- if u.usedTypeNamesAsHash[hashedTypeName] {
- u.Report.AddExternalError(operationreport.ErrTypeNameMustBeUnique(typeName))
- return
- }
- u.usedTypeNamesAsHash[hashedTypeName] = true
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvisitor/astvisitor.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvisitor/astvisitor.go
deleted file mode 100644
index 49c522c6173..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvisitor/astvisitor.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// Package astvisitor enables efficient and powerful traversal of GraphQL document AST's.
-//
-// Visitor has more options to configure the behaviour and offers more meta data than SimpleVisitor.
-// SimpleVisitor on the other hand is more performant.
-//
-// If all Nodes should be visited and not much meta data is needed, go with SimpleVisitor.
-// If you only need to visit a subset of Nodes or want specific meta data, e.g. TypeDefinitions you should go with Visitor.
-package astvisitor
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvisitor/simplevisitor.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvisitor/simplevisitor.go
deleted file mode 100644
index 051b59e950c..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvisitor/simplevisitor.go
+++ /dev/null
@@ -1,781 +0,0 @@
-package astvisitor
-
-import (
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
-)
-
-type SimpleWalker struct {
- err error
- document *ast.Document
- Depth int
- Ancestors []ast.Node
- visitor AllNodesVisitor
- SelectionsBefore []int
- SelectionsAfter []int
-}
-
-func NewSimpleWalker(ancestorSize int) SimpleWalker {
- return SimpleWalker{
- Ancestors: make([]ast.Node, 0, ancestorSize),
- }
-}
-
-func (w *SimpleWalker) SetVisitor(visitor AllNodesVisitor) {
- w.visitor = visitor
-}
-
-func (w *SimpleWalker) Walk(document, definition *ast.Document) error {
- return w.WalkDocument(document)
-}
-
-func (w *SimpleWalker) WalkDocument(document *ast.Document) error {
-
- if w.visitor == nil {
- return fmt.Errorf("visitor must not be nil, use SetVisitor()")
- }
-
- w.err = nil
- w.Ancestors = w.Ancestors[:0]
- w.document = document
- w.Depth = 0
- w.walk()
- return w.err
-}
-
-func (w *SimpleWalker) appendAncestor(ref int, kind ast.NodeKind) {
- w.Ancestors = append(w.Ancestors, ast.Node{
- Kind: kind,
- Ref: ref,
- })
-}
-
-func (w *SimpleWalker) removeLastAncestor() {
- w.Ancestors = w.Ancestors[:len(w.Ancestors)-1]
-}
-
-func (w *SimpleWalker) increaseDepth() {
- w.Depth++
-}
-
-func (w *SimpleWalker) decreaseDepth() {
- w.Depth--
-}
-
-func (w *SimpleWalker) walk() {
-
- if w.document == nil {
- w.err = fmt.Errorf("document must not be nil")
- return
- }
-
- w.visitor.EnterDocument(w.document, nil)
-
- for i := range w.document.RootNodes {
- isLast := i == len(w.document.RootNodes)-1
- switch w.document.RootNodes[i].Kind {
- case ast.NodeKindOperationDefinition:
- w.walkOperationDefinition(w.document.RootNodes[i].Ref, isLast)
- case ast.NodeKindFragmentDefinition:
- w.walkFragmentDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindSchemaDefinition:
- w.walkSchemaDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindSchemaExtension:
- w.walkSchemaExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindDirectiveDefinition:
- w.walkDirectiveDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindObjectTypeDefinition:
- w.walkObjectTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindObjectTypeExtension:
- w.walkObjectTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindInterfaceTypeDefinition:
- w.walkInterfaceTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindInterfaceTypeExtension:
- w.walkInterfaceTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindScalarTypeDefinition:
- w.walkScalarTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindScalarTypeExtension:
- w.walkScalarTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindUnionTypeDefinition:
- w.walkUnionTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindUnionTypeExtension:
- w.walkUnionTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindEnumTypeDefinition:
- w.walkEnumTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindEnumTypeExtension:
- w.walkEnumTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindInputObjectTypeDefinition:
- w.walkInputObjectTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindInputObjectTypeExtension:
- w.walkInputObjectTypeExtension(w.document.RootNodes[i].Ref)
- }
- }
-
- w.visitor.LeaveDocument(w.document, nil)
-}
-
-func (w *SimpleWalker) walkOperationDefinition(ref int, isLastRootNode bool) {
- w.increaseDepth()
-
- w.visitor.EnterOperationDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindOperationDefinition)
-
- if w.document.OperationDefinitions[ref].HasVariableDefinitions {
- for _, i := range w.document.OperationDefinitions[ref].VariableDefinitions.Refs {
- w.walkVariableDefinition(i)
- }
- }
-
- if w.document.OperationDefinitions[ref].HasDirectives {
- for _, i := range w.document.OperationDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.OperationDefinitions[ref].HasSelections {
- w.walkSelectionSet(w.document.OperationDefinitions[ref].SelectionSet)
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveOperationDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkVariableDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterVariableDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindVariableDefinition)
-
- if w.document.VariableDefinitions[ref].HasDirectives {
- for _, i := range w.document.VariableDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveVariableDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkSelectionSet(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterSelectionSet(ref)
-
- w.appendAncestor(ref, ast.NodeKindSelectionSet)
-
- for i, j := range w.document.SelectionSets[ref].SelectionRefs {
-
- w.SelectionsBefore = w.document.SelectionSets[ref].SelectionRefs[:i]
- w.SelectionsAfter = w.document.SelectionSets[ref].SelectionRefs[i+1:]
-
- switch w.document.Selections[j].Kind {
- case ast.SelectionKindField:
- w.walkField(w.document.Selections[j].Ref)
- case ast.SelectionKindFragmentSpread:
- w.walkFragmentSpread(w.document.Selections[j].Ref)
- case ast.SelectionKindInlineFragment:
- w.walkInlineFragment(w.document.Selections[j].Ref)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveSelectionSet(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkField(ref int) {
- w.increaseDepth()
-
- selectionsBefore := w.SelectionsBefore
- selectionsAfter := w.SelectionsAfter
- w.visitor.EnterField(ref)
-
- w.appendAncestor(ref, ast.NodeKindField)
-
- if len(w.document.Fields[ref].Arguments.Refs) != 0 {
- for _, i := range w.document.Fields[ref].Arguments.Refs {
- w.walkArgument(i)
- }
- }
-
- if w.document.Fields[ref].HasDirectives {
- for _, i := range w.document.Fields[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.Fields[ref].HasSelections {
- w.walkSelectionSet(w.document.Fields[ref].SelectionSet)
- }
-
- w.removeLastAncestor()
-
- w.SelectionsBefore = selectionsBefore
- w.SelectionsAfter = selectionsAfter
- w.visitor.LeaveField(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkDirective(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterDirective(ref)
-
- w.appendAncestor(ref, ast.NodeKindDirective)
-
- if w.document.Directives[ref].HasArguments {
- for _, i := range w.document.Directives[ref].Arguments.Refs {
- w.walkArgument(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveDirective(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkArgument(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterArgument(ref)
- w.visitor.LeaveArgument(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkFragmentSpread(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterFragmentSpread(ref)
- w.visitor.LeaveFragmentSpread(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkInlineFragment(ref int) {
- w.increaseDepth()
-
- selectionsBefore := w.SelectionsBefore
- selectionsAfter := w.SelectionsAfter
- w.visitor.EnterInlineFragment(ref)
-
- w.appendAncestor(ref, ast.NodeKindInlineFragment)
-
- if w.document.InlineFragments[ref].HasDirectives {
- for _, i := range w.document.InlineFragments[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.InlineFragments[ref].HasSelections {
- w.walkSelectionSet(w.document.InlineFragments[ref].SelectionSet)
- }
-
- w.removeLastAncestor()
-
- w.SelectionsBefore = selectionsBefore
- w.SelectionsAfter = selectionsAfter
- w.visitor.LeaveInlineFragment(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkFragmentDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterFragmentDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindFragmentDefinition)
-
- if w.document.FragmentDefinitions[ref].HasSelections {
- w.walkSelectionSet(w.document.FragmentDefinitions[ref].SelectionSet)
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveFragmentDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkObjectTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterObjectTypeDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindObjectTypeDefinition)
-
- if w.document.ObjectTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.ObjectTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.ObjectTypeDefinitions[ref].HasFieldDefinitions {
- for _, i := range w.document.ObjectTypeDefinitions[ref].FieldsDefinition.Refs {
- w.walkFieldDefinition(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveObjectTypeDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkObjectTypeExtension(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterObjectTypeExtension(ref)
- w.appendAncestor(ref, ast.NodeKindObjectTypeExtension)
-
- if w.document.ObjectTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.ObjectTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.ObjectTypeExtensions[ref].HasFieldDefinitions {
- for _, i := range w.document.ObjectTypeExtensions[ref].FieldsDefinition.Refs {
- w.walkFieldDefinition(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveObjectTypeExtension(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkFieldDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterFieldDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindFieldDefinition)
-
- if w.document.FieldDefinitions[ref].HasArgumentsDefinitions {
- for _, i := range w.document.FieldDefinitions[ref].ArgumentsDefinition.Refs {
- w.walkInputValueDefinition(i)
- }
- }
-
- if w.document.FieldDefinitions[ref].HasDirectives {
- for _, i := range w.document.FieldDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveFieldDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkInputValueDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterInputValueDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindInputValueDefinition)
-
- if w.document.InputValueDefinitions[ref].HasDirectives {
- for _, i := range w.document.InputValueDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveInputValueDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkInterfaceTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterInterfaceTypeDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindInterfaceTypeDefinition)
-
- if w.document.InterfaceTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.InterfaceTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.InterfaceTypeDefinitions[ref].HasFieldDefinitions {
- for _, i := range w.document.InterfaceTypeDefinitions[ref].FieldsDefinition.Refs {
- w.walkFieldDefinition(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveInterfaceTypeDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkInterfaceTypeExtension(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterInterfaceTypeExtension(ref)
-
- w.appendAncestor(ref, ast.NodeKindInterfaceTypeExtension)
-
- if w.document.InterfaceTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.InterfaceTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.InterfaceTypeExtensions[ref].HasFieldDefinitions {
- for _, i := range w.document.InterfaceTypeExtensions[ref].FieldsDefinition.Refs {
- w.walkFieldDefinition(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveInterfaceTypeExtension(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkScalarTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterScalarTypeDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindScalarTypeDefinition)
-
- if w.document.ScalarTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.ScalarTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveScalarTypeDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkScalarTypeExtension(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterScalarTypeExtension(ref)
-
- w.appendAncestor(ref, ast.NodeKindScalarTypeExtension)
-
- if w.document.ScalarTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.ScalarTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveScalarTypeExtension(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkUnionTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterUnionTypeDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindUnionTypeDefinition)
-
- if w.document.UnionTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.UnionTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.UnionTypeDefinitions[ref].HasUnionMemberTypes {
- for _, i := range w.document.UnionTypeDefinitions[ref].UnionMemberTypes.Refs {
- w.walkUnionMemberType(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveUnionTypeDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkUnionTypeExtension(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterUnionTypeExtension(ref)
-
- w.appendAncestor(ref, ast.NodeKindUnionTypeExtension)
-
- if w.document.UnionTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.UnionTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.UnionTypeExtensions[ref].HasUnionMemberTypes {
- for _, i := range w.document.UnionTypeExtensions[ref].UnionMemberTypes.Refs {
- w.walkUnionMemberType(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveUnionTypeExtension(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkUnionMemberType(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterUnionMemberType(ref)
-
- w.visitor.LeaveUnionMemberType(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkEnumTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterEnumTypeDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindEnumTypeDefinition)
-
- if w.document.EnumTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.EnumTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.EnumTypeDefinitions[ref].HasEnumValuesDefinition {
- for _, i := range w.document.EnumTypeDefinitions[ref].EnumValuesDefinition.Refs {
- w.walkEnumValueDefinition(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveEnumTypeDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkEnumTypeExtension(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterEnumTypeExtension(ref)
-
- w.appendAncestor(ref, ast.NodeKindEnumTypeExtension)
-
- if w.document.EnumTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.EnumTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.EnumTypeExtensions[ref].HasEnumValuesDefinition {
- for _, i := range w.document.EnumTypeExtensions[ref].EnumValuesDefinition.Refs {
- w.walkEnumValueDefinition(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveEnumTypeExtension(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkEnumValueDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterEnumValueDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindEnumValueDefinition)
-
- if w.document.EnumValueDefinitions[ref].HasDirectives {
- for _, i := range w.document.EnumValueDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveEnumValueDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkInputObjectTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterInputObjectTypeDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindInputObjectTypeDefinition)
-
- if w.document.InputObjectTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.InputObjectTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition {
- for _, i := range w.document.InputObjectTypeDefinitions[ref].InputFieldsDefinition.Refs {
- w.walkInputValueDefinition(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveInputObjectTypeDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkInputObjectTypeExtension(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterInputObjectTypeExtension(ref)
-
- w.appendAncestor(ref, ast.NodeKindInputObjectTypeExtension)
-
- if w.document.InputObjectTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.InputObjectTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.InputObjectTypeExtensions[ref].HasInputFieldsDefinition {
- for _, i := range w.document.InputObjectTypeExtensions[ref].InputFieldsDefinition.Refs {
- w.walkInputValueDefinition(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveInputObjectTypeExtension(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkDirectiveDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterDirectiveDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindDirectiveDefinition)
-
- if w.document.DirectiveDefinitions[ref].HasArgumentsDefinitions {
- for _, i := range w.document.DirectiveDefinitions[ref].ArgumentsDefinition.Refs {
- w.walkInputValueDefinition(i)
- }
- }
-
- iter := w.document.DirectiveDefinitions[ref].DirectiveLocations.Iterable()
- for iter.Next() {
- w.walkDirectiveLocation(iter.Value())
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveDirectiveDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkDirectiveLocation(location ast.DirectiveLocation) {
- w.increaseDepth()
-
- w.visitor.EnterDirectiveLocation(location)
-
- w.visitor.LeaveDirectiveLocation(location)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkSchemaDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterSchemaDefinition(ref)
-
- w.appendAncestor(ref, ast.NodeKindSchemaDefinition)
-
- if w.document.SchemaDefinitions[ref].HasDirectives {
- for _, i := range w.document.SchemaDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- for _, i := range w.document.SchemaDefinitions[ref].RootOperationTypeDefinitions.Refs {
- w.walkRootOperationTypeDefinition(i)
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveSchemaDefinition(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkSchemaExtension(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterSchemaExtension(ref)
-
- w.appendAncestor(ref, ast.NodeKindSchemaExtension)
-
- if w.document.SchemaExtensions[ref].HasDirectives {
- for _, i := range w.document.SchemaExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- for _, i := range w.document.SchemaExtensions[ref].RootOperationTypeDefinitions.Refs {
- w.walkRootOperationTypeDefinition(i)
- }
-
- w.removeLastAncestor()
-
- w.visitor.LeaveSchemaExtension(ref)
-
- w.decreaseDepth()
-}
-
-func (w *SimpleWalker) walkRootOperationTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.visitor.EnterRootOperationTypeDefinition(ref)
-
- w.visitor.LeaveRootOperationTypeDefinition(ref)
-
- w.decreaseDepth()
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvisitor/visitor.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvisitor/visitor.go
deleted file mode 100644
index ccb7ed524f6..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/astvisitor/visitor.go
+++ /dev/null
@@ -1,3626 +0,0 @@
-package astvisitor
-
-import (
- "bytes"
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-var (
- ErrDocumentMustNotBeNil = fmt.Errorf("document must not be nil")
- ErrDefinitionMustNotBeNil = fmt.Errorf("definition must not be nil when walking operations")
-)
-
-// Walker orchestrates the process of walking an AST and calling all registered callbacks
-// Always use NewWalker to instantiate a new Walker
-type Walker struct {
- // Ancestors is the slice of Nodes to the current Node in a callback
- // don't keep a reference to this slice, always copy it if you want to work with it after the callback returned
- Ancestors []ast.Node
- // Path is the slice of PathItems leading to the current Node
- // don't keep a reference to this slice, always copy it if you want to work with it after the callback returned
- Path ast.Path
- // EnclosingTypeDefinition is the TypeDefinition Node of the parent object of the current callback
- // e.g. if the current callback is a Field the EnclosingTypeDefinition will be the TypeDefinition of the parent object of such Field
- EnclosingTypeDefinition ast.Node
- // SelectionsBefore is the slice of references to selections before the current selection
- // This is only valid when inside a SelectionSet
- SelectionsBefore []int
- // SelectionsAfter is the slice of references to selections before the current selection
- // This is only valid when inside a SelectionSet
- SelectionsAfter []int
- // Report is the object to collect errors when walking the AST
- Report *operationreport.Report
- CurrentRef int
- CurrentKind ast.NodeKind
- document *ast.Document
- definition *ast.Document
- visitors visitors
- Depth int
- typeDefinitions []ast.Node
- stop bool
- skip bool
- revisit bool
- filter VisitorFilter
- deferred []func()
-}
-
-// NewWalker returns a fully initialized Walker
-func NewWalker(ancestorSize int) Walker {
- return Walker{
- Ancestors: make([]ast.Node, 0, ancestorSize),
- Path: make([]ast.PathItem, 0, ancestorSize),
- typeDefinitions: make([]ast.Node, 0, ancestorSize),
- deferred: make([]func(), 0, 8),
- }
-}
-
-type (
- // EnterOperationDefinitionVisitor is the callback when the walker enters an operation definition
- EnterOperationDefinitionVisitor interface {
- // EnterOperationDefinition gets called when the walker enters an operation definition
- // ref is the reference to the operation definition on the AST
- EnterOperationDefinition(ref int)
- }
- // LeaveOperationDefinitionVisitor is the callback when the walker leaves an operation definition
- LeaveOperationDefinitionVisitor interface {
- // LeaveOperationDefinition gets called when the walker leaves an operation definition
- // ref is the reference to the operation definition on the AST
- LeaveOperationDefinition(ref int)
- }
- // OperationDefinitionVisitor is the callback when the walker enters or leaves an operation
- OperationDefinitionVisitor interface {
- EnterOperationDefinitionVisitor
- LeaveOperationDefinitionVisitor
- }
- // EnterSelectionSetVisitor is the callback when the walker enters a selection set
- EnterSelectionSetVisitor interface {
- // EnterSelectionSet gets called when the walker enters a selection set
- // ref is the reference to the selection set on the AST
- EnterSelectionSet(ref int)
- }
- // LeaveSelectionSetVisitor is the callback when the walker leaves a selection set visitor
- LeaveSelectionSetVisitor interface {
- // LeaveSelectionSet gets called when the walker leaves a selection set
- // ref is the reference to the selection set on the AST
- LeaveSelectionSet(ref int)
- }
- // SelectionSetVisitor is the callback when the walker enters or leaves a selection set
- SelectionSetVisitor interface {
- EnterSelectionSetVisitor
- LeaveSelectionSetVisitor
- }
- // EnterFieldVisitor is the callback when the walker enters a field
- EnterFieldVisitor interface {
- // EnterField gets called when the walker enters a field
- // ref is the reference to the selection set on the AST
- EnterField(ref int)
- }
- // LeaveFieldVisitor is the callback when the walker leaves a field
- LeaveFieldVisitor interface {
- // LeaveField gets called when the walker leaves a field
- // ref is the reference to the selection set on the AST
- LeaveField(ref int)
- }
- // FieldVisitor is the callback when the walker enters or leaves a field
- FieldVisitor interface {
- EnterFieldVisitor
- LeaveFieldVisitor
- }
- // EnterArgumentVisitor is the callback when the walker enters an argument
- EnterArgumentVisitor interface {
- // EnterArgument gets called when the walker enters an argument
- // ref is the reference to the selection set on the AST
- EnterArgument(ref int)
- }
- // LeaveArgumentVisitor is the callback when the walker leaves an argument
- LeaveArgumentVisitor interface {
- // LeaveArgument gets called when the walker leaves an argument
- // ref is the reference to the selection set on the AST
- LeaveArgument(ref int)
- }
- // ArgumentVisitor is the callback when the walker enters or leaves an argument
- ArgumentVisitor interface {
- EnterArgumentVisitor
- LeaveArgumentVisitor
- }
- // EnterFragmentSpreadVisitor is the callback when the walker enters a fragment spread
- EnterFragmentSpreadVisitor interface {
- // EnterFragmentSpread gets called when the walker enters a fragment spread
- // ref is the reference to the selection set on the AST
- EnterFragmentSpread(ref int)
- }
- // LeaveFragmentSpreadVisitor is the callback when the walker leaves a fragment spread
- LeaveFragmentSpreadVisitor interface {
- // LeaveFragmentSpread gets called when the walker leaves a fragment spread
- // ref is the reference to the selection set on the AST
- LeaveFragmentSpread(ref int)
- }
- // FragmentSpreadVisitor is the callback when the walker enters or leaves a fragment spread
- FragmentSpreadVisitor interface {
- EnterFragmentSpreadVisitor
- LeaveFragmentSpreadVisitor
- }
- // EnterFragmentSpreadVisitor is the callback when the walker enters an inline framgnet
- EnterInlineFragmentVisitor interface {
- // EnterInlineFragment gets called when the walker enters an inline fragment
- // ref is the reference to the selection set on the AST
- EnterInlineFragment(ref int)
- }
- // LeaveInlineFragmentVisitor is the callback when the walker leaves an inline fragment
- LeaveInlineFragmentVisitor interface {
- // LeaveInlineFragment gets called when the walker leaves an inline fragment
- // ref is the reference to the selection set on the AST
- LeaveInlineFragment(ref int)
- }
- // InlineFragmentVisitor is the callback when the walker enters or leaves an inline fragment
- InlineFragmentVisitor interface {
- EnterInlineFragmentVisitor
- LeaveInlineFragmentVisitor
- }
- // EnterFragmentDefinitionVisitor is the callback when the walker enters a fragment definition
- EnterFragmentDefinitionVisitor interface {
- // EnterFragmentDefinition gets called when the walker enters a fragment definition
- // ref is the reference to the selection set on the AST
- EnterFragmentDefinition(ref int)
- }
- // LeaveFragmentDefinitionVisitor is the callback when the walker leaves a fragment definition
- LeaveFragmentDefinitionVisitor interface {
- // LeaveFragmentDefinition gets called when the walker leaves a fragment definition
- // ref is the reference to the selection set on the AST
- LeaveFragmentDefinition(ref int)
- }
- // FragmentDefinitionVisitor is the callback when the walker enters or leaves a fragment definition
- FragmentDefinitionVisitor interface {
- EnterFragmentDefinitionVisitor
- LeaveFragmentDefinitionVisitor
- }
- // EnterFragmentDefinitionVisitor is the callback when the walker enters a variable definition
- EnterVariableDefinitionVisitor interface {
- // EnterVariableDefinition gets called when the walker enters a variable definition
- // ref is the reference to the selection set on the AST
- EnterVariableDefinition(ref int)
- }
- // LeaveVariableDefinitionVisitor is the callback when the walker leaves a variable definition
- LeaveVariableDefinitionVisitor interface {
- // LeaveVariableDefinition gets called when the walker leaves a variable definition
- // ref is the reference to the selection set on the AST
- LeaveVariableDefinition(ref int)
- }
- // VariableDefinitionVisitor is the callback when the walker enters or leaves a variable definition
- VariableDefinitionVisitor interface {
- EnterVariableDefinitionVisitor
- LeaveVariableDefinitionVisitor
- }
- // EnterDirectiveVisitor is the callback when the walker enters a directive
- EnterDirectiveVisitor interface {
- // EnterDirective gets called when the walker enters a directive
- // ref is the reference to the selection set on the AST
- EnterDirective(ref int)
- }
- // LeaveDirectiveVisitor is the callback when the walker leaves a directive
- LeaveDirectiveVisitor interface {
- // LeaveDirective gets called when the walker leaves a directive
- // ref is the reference to the selection set on the AST
- LeaveDirective(ref int)
- }
- // DirectiveVisitor is the callback when the walker enters or leaves a directive
- DirectiveVisitor interface {
- EnterDirectiveVisitor
- LeaveDirectiveVisitor
- }
- // EnterObjectTypeDefinitionVisitor is the callback when the walker enters an object type definition
- EnterObjectTypeDefinitionVisitor interface {
- // EnterObjectTypeDefinition gets called when the walker enters an object type definition
- // ref is the reference to the selection set on the AST
- EnterObjectTypeDefinition(ref int)
- }
- // LeaveObjectTypeDefinitionVisitor is the callback when the walker leaves an object type definition
- LeaveObjectTypeDefinitionVisitor interface {
- // LeaveObjectTypeDefinition gets called when the walker leaves an object type definition
- // ref is the reference to the selection set on the AST
- LeaveObjectTypeDefinition(ref int)
- }
- // ObjectTypeDefinitionVisitor is the callback when the walker enters or leaves an object type definition
- ObjectTypeDefinitionVisitor interface {
- EnterObjectTypeDefinitionVisitor
- LeaveObjectTypeDefinitionVisitor
- }
- // EnterObjectTypeExtensionVisitor is the callback when the walker enters an object type extension
- EnterObjectTypeExtensionVisitor interface {
- // EnterObjectTypeExtension gets called when the walker enters an object type extension
- // ref is the reference to the selection set on the AST
- EnterObjectTypeExtension(ref int)
- }
- // LeaveObjectTypeExtensionVisitor is the callback when the walker leaves an object type extension
- LeaveObjectTypeExtensionVisitor interface {
- // LeaveObjectTypeExtension gets called when the walker leaves an object type extension
- // ref is the reference to the selection set on the AST
- LeaveObjectTypeExtension(ref int)
- }
- // ObjectTypeExtensionVisitor is the callback when the walker enters or leaves an object type extension
- ObjectTypeExtensionVisitor interface {
- EnterObjectTypeExtensionVisitor
- LeaveObjectTypeExtensionVisitor
- }
- // EnterFieldDefinitionVisitor is the callback when the walker enters a field definition
- EnterFieldDefinitionVisitor interface {
- // EnterFieldDefinition gets called when the walker enters a field definition
- // ref is the reference to the selection set on the AST
- EnterFieldDefinition(ref int)
- }
- // LeaveFieldDefinitionVisitor is the callback when the walker leaves a field definition
- LeaveFieldDefinitionVisitor interface {
- // LeaveFieldDefinition gets called when the walker leaves a field definition
- // ref is the reference to the selection set on the AST
- LeaveFieldDefinition(ref int)
- }
- // FieldDefinitionVisitor is the callback when the walker enters or leaves a field definition
- FieldDefinitionVisitor interface {
- EnterFieldDefinitionVisitor
- LeaveFieldDefinitionVisitor
- }
- // EnterInputValueDefinitionVisitor is the callback when the walker enters an input value definition
- EnterInputValueDefinitionVisitor interface {
- // EnterInputValueDefinition gets called when the walker enters an input value definition
- // ref is the reference to the selection set on the AST
- EnterInputValueDefinition(ref int)
- }
- // LeaveInputValueDefinitionVisitor is the callback when the walker leaves an input value definition
- LeaveInputValueDefinitionVisitor interface {
- // LeaveInputValueDefinition gets called when the walker leaves an input value definition
- // ref is the reference to the selection set on the AST
- LeaveInputValueDefinition(ref int)
- }
- // InputValueDefinitionVisitor is the callback when the walker enters or leaves an input value definition
- InputValueDefinitionVisitor interface {
- EnterInputValueDefinitionVisitor
- LeaveInputValueDefinitionVisitor
- }
- // EnterInterfaceTypeDefinitionVisitor is the callback when the walker enters an interface type definition
- EnterInterfaceTypeDefinitionVisitor interface {
- // EnterInterfaceTypeDefinition gets called when the walker enters an interface type definition
- // ref is the reference to the selection set on the AST
- EnterInterfaceTypeDefinition(ref int)
- }
- // LeaveInterfaceTypeDefinitionVisitor is the callback when the walker leaves an interface type definition
- LeaveInterfaceTypeDefinitionVisitor interface {
- // LeaveInterfaceTypeDefinition gets called when the walker leaves an interface type definition
- // ref is the reference to the selection set on the AST
- LeaveInterfaceTypeDefinition(ref int)
- }
- // InterfaceTypeDefinitionVisitor is the callback when the walker enters or leaves an interface type definition
- InterfaceTypeDefinitionVisitor interface {
- EnterInterfaceTypeDefinitionVisitor
- LeaveInterfaceTypeDefinitionVisitor
- }
- // EnterInterfaceTypeExtensionVisitor is the callback when the walker enters an interface type extension
- EnterInterfaceTypeExtensionVisitor interface {
- // EnterInterfaceTypeExtension gets called when the walker enters an interface type extension
- // ref is the reference to the selection set on the AST
- EnterInterfaceTypeExtension(ref int)
- }
- // LeaveInterfaceTypeExtensionVisitor is the callback when the walker leaves an interface type extension
- LeaveInterfaceTypeExtensionVisitor interface {
- // LeaveInterfaceTypeExtension gets called when the walker leaves an interface type extension
- // ref is the reference to the selection set on the AST
- LeaveInterfaceTypeExtension(ref int)
- }
- // InterfaceTypeExtensionVisitor is the callback when the walker enters or leaves an interface type extension
- InterfaceTypeExtensionVisitor interface {
- EnterInterfaceTypeExtensionVisitor
- LeaveInterfaceTypeExtensionVisitor
- }
- // EnterScalarTypeDefinitionVisitor is the callback when the walker enters a scalar type definition
- EnterScalarTypeDefinitionVisitor interface {
- // EnterScalarTypeDefinition gets called when the walker enters a scalar type definition
- // ref is the reference to the selection set on the AST
- EnterScalarTypeDefinition(ref int)
- }
- // LeaveScalarTypeDefinitionVisitor is the callback when the walker leaves a scalar type definition
- LeaveScalarTypeDefinitionVisitor interface {
- // LeaveScalarTypeDefinition gets called when the walker leaves a scalar type definition
- // ref is the reference to the selection set on the AST
- LeaveScalarTypeDefinition(ref int)
- }
- // ScalarTypeDefinitionVisitor is the callback when the walker enters or leaves a scalar type definition
- ScalarTypeDefinitionVisitor interface {
- EnterScalarTypeDefinitionVisitor
- LeaveScalarTypeDefinitionVisitor
- }
- // EnterScalarTypeExtensionVisitor is the callback when the walker enters a scalar type extension
- EnterScalarTypeExtensionVisitor interface {
- // EnterScalarTypeExtension gets called when the walker enters a scalar type extension
- // ref is the reference to the selection set on the AST
- EnterScalarTypeExtension(ref int)
- }
- // LeaveScalarTypeExtensionVisitor is the callback when the walker leaves a scalar type extension
- LeaveScalarTypeExtensionVisitor interface {
- // LeaveScalarTypeExtension gets called when the walker leaves a scalar type extension
- // ref is the reference to the selection set on the AST
- LeaveScalarTypeExtension(ref int)
- }
- // ScalarTypeExtensionVisitor is the callback when the walker enters or leaves a scalar type extension
- ScalarTypeExtensionVisitor interface {
- EnterScalarTypeExtensionVisitor
- LeaveScalarTypeExtensionVisitor
- }
- // EnterUnionTypeDefinitionVisitor is the callback when the walker enters a union type definition
- EnterUnionTypeDefinitionVisitor interface {
- // EnterUnionTypeDefinition gets called when the walker enters a union type definition
- // ref is the reference to the selection set on the AST
- EnterUnionTypeDefinition(ref int)
- }
- // LeaveUnionTypeDefinitionVisitor is the callback when the walker leaves a union type definition
- LeaveUnionTypeDefinitionVisitor interface {
- // LeaveUnionTypeDefinition gets called when the walker leaves a union type definition
- // ref is the reference to the selection set on the AST
- LeaveUnionTypeDefinition(ref int)
- }
- // UnionTypeDefinitionVisitor is the callback when the walker enters or leaves a union type definition
- UnionTypeDefinitionVisitor interface {
- EnterUnionTypeDefinitionVisitor
- LeaveUnionTypeDefinitionVisitor
- }
- // EnterUnionTypeExtensionVisitor is the callback when the walker enters a union type extension
- EnterUnionTypeExtensionVisitor interface {
- // EnterUnionTypeExtension gets called when the walker enters a union type extension
- // ref is the reference to the selection set on the AST
- EnterUnionTypeExtension(ref int)
- }
- // LeaveUnionTypeExtensionVisitor is the callback when the walker leaves a union type extension
- LeaveUnionTypeExtensionVisitor interface {
- // LeaveUnionTypeExtension gets called when the walker leaves a union type extension
- // ref is the reference to the selection set on the AST
- LeaveUnionTypeExtension(ref int)
- }
- // UnionTypeExtensionVisitor is the callback when the walker enters or leaves a union type extension
- UnionTypeExtensionVisitor interface {
- EnterUnionTypeExtensionVisitor
- LeaveUnionTypeExtensionVisitor
- }
- // EnterUnionMemberTypeVisitor is the callback when the walker enters a union member type
- EnterUnionMemberTypeVisitor interface {
- // EnterUnionMemberType gets called when the walker enters a union member type
- // ref is the reference to the selection set on the AST
- EnterUnionMemberType(ref int)
- }
- // LeaveUnionMemberTypeVisitor is the callback when the walker leaves a union member type
- LeaveUnionMemberTypeVisitor interface {
- // LeaveUnionMemberType gets called when the walker leaves a union member type
- // ref is the reference to the selection set on the AST
- LeaveUnionMemberType(ref int)
- }
- // UnionMemberTypeVisitor is the callback when the walker enters or leaves a union member type
- UnionMemberTypeVisitor interface {
- EnterUnionMemberTypeVisitor
- LeaveUnionMemberTypeVisitor
- }
- // EnterEnumTypeDefinitionVisitor is the callback when the walker enters an enum type definition
- EnterEnumTypeDefinitionVisitor interface {
- // EnterEnumTypeDefinition gets called when the walker enters an enum type definition
- // ref is the reference to the selection set on the AST
- EnterEnumTypeDefinition(ref int)
- }
- // LeaveEnumTypeDefinitionVisitor is the callback when the walker leaves an enum type definition
- LeaveEnumTypeDefinitionVisitor interface {
- // LeaveEnumTypeDefinition gets called when the walker leaves an enum type definition
- // ref is the reference to the selection set on the AST
- LeaveEnumTypeDefinition(ref int)
- }
- // EnumTypeDefinitionVisitor is the callback when the walker enters or leaves an enum type definition
- EnumTypeDefinitionVisitor interface {
- EnterEnumTypeDefinitionVisitor
- LeaveEnumTypeDefinitionVisitor
- }
- // EnterEnumTypeExtensionVisitor is the callback when the walker enters an enum type extension
- EnterEnumTypeExtensionVisitor interface {
- // EnterEnumTypeExtension gets called when the walker enters an enum type extension
- // ref is the reference to the selection set on the AST
- EnterEnumTypeExtension(ref int)
- }
- // LeaveEnumTypeExtensionVisitor is the callback when the walker leaves an enum type extension
- LeaveEnumTypeExtensionVisitor interface {
- // LeaveEnumTypeExtension gets called when the walker leaves an enum type extension
- // ref is the reference to the selection set on the AST
- LeaveEnumTypeExtension(ref int)
- }
- // EnumTypeExtensionVisitor is the callback when the walker enters or leaves an enum type extension
- EnumTypeExtensionVisitor interface {
- EnterEnumTypeExtensionVisitor
- LeaveEnumTypeExtensionVisitor
- }
- // EnterEnumValueDefinitionVisitor is the callback when the walker enters an enum value definition
- EnterEnumValueDefinitionVisitor interface {
- // EnterEnumValueDefinition gets called when the walker enters an enum value definition
- // ref is the reference to the selection set on the AST
- EnterEnumValueDefinition(ref int)
- }
- // LeaveEnumValueDefinitionVisitor is the callback when the walker leaves an enum value definition
- LeaveEnumValueDefinitionVisitor interface {
- // LeaveEnumValueDefinition gets called when the walker leaves an enum value definition
- // ref is the reference to the selection set on the AST
- LeaveEnumValueDefinition(ref int)
- }
- // EnumValueDefinitionVisitor is the callback when the walker enters or leaves an enum value definition
- EnumValueDefinitionVisitor interface {
- EnterEnumValueDefinitionVisitor
- LeaveEnumValueDefinitionVisitor
- }
- // EnterInputObjectTypeDefinitionVisitor is the callback when the walker enters an input object type definition
- EnterInputObjectTypeDefinitionVisitor interface {
- // EnterInputObjectTypeDefinition gets called when the walker enters an input object type definition
- // ref is the reference to the selection set on the AST
- EnterInputObjectTypeDefinition(ref int)
- }
- // LeaveInputObjectTypeDefinitionVisitor is the callback when the walker leaves an input object type definition
- LeaveInputObjectTypeDefinitionVisitor interface {
- // LeaveInputObjectTypeDefinition gets called when the walker leaves an input object type definition
- // ref is the reference to the selection set on the AST
- LeaveInputObjectTypeDefinition(ref int)
- }
- // InputObjectTypeDefinitionVisitor is the callback when the walker enters or leaves an input object type definition
- InputObjectTypeDefinitionVisitor interface {
- EnterInputObjectTypeDefinitionVisitor
- LeaveInputObjectTypeDefinitionVisitor
- }
- // EnterInputObjectTypeExtensionVisitor is the callback when the walker enters an input object type extension
- EnterInputObjectTypeExtensionVisitor interface {
- // EnterInputObjectTypeExtension gets called when the walker enters an input object type extension
- // ref is the reference to the selection set on the AST
- EnterInputObjectTypeExtension(ref int)
- }
- // LeaveInputObjectTypeExtensionVisitor is the callback when the walker leaves an input object type extension
- LeaveInputObjectTypeExtensionVisitor interface {
- // LeaveInputObjectTypeExtension gets called when the walker leaves an input object type extension
- // ref is the reference to the selection set on the AST
- LeaveInputObjectTypeExtension(ref int)
- }
- // InputObjectTypeExtensionVisitor is the callback when the walker enters or leaves an input object type extension
- InputObjectTypeExtensionVisitor interface {
- EnterInputObjectTypeExtensionVisitor
- LeaveInputObjectTypeExtensionVisitor
- }
- // EnterDirectiveDefinitionVisitor is the callback when the walker enters a directive definition
- EnterDirectiveDefinitionVisitor interface {
- // EnterDirectiveDefinition gets called when the walker enters a directive definition
- // ref is the reference to the selection set on the AST
- EnterDirectiveDefinition(ref int)
- }
- // LeaveDirectiveDefinitionVisitor is the callback when the walker leaves a directive definition
- LeaveDirectiveDefinitionVisitor interface {
- // LeaveDirectiveDefinition gets called when the walker leaves a directive definition
- // ref is the reference to the selection set on the AST
- LeaveDirectiveDefinition(ref int)
- }
- // DirectiveDefinitionVisitor is the callback when the walker enters or leaves a directive definition
- DirectiveDefinitionVisitor interface {
- EnterDirectiveDefinitionVisitor
- LeaveDirectiveDefinitionVisitor
- }
- // EnterDirectiveLocationVisitor is the callback when the walker enters a directive location
- EnterDirectiveLocationVisitor interface {
- // EnterDirectiveLocation gets called when the walker enters a directive location
- // ref is the reference to the selection set on the AST
- EnterDirectiveLocation(location ast.DirectiveLocation)
- }
- // LeaveDirectiveLocationVisitor is the callback when the walker leaves a directive location
- LeaveDirectiveLocationVisitor interface {
- // LeaveDirectiveLocation gets called when the walker leaves a directive location
- // ref is the reference to the selection set on the AST
- LeaveDirectiveLocation(location ast.DirectiveLocation)
- }
- // DirectiveLocationVisitor is the callback when the walker enters or leaves a directive location
- DirectiveLocationVisitor interface {
- EnterDirectiveLocationVisitor
- LeaveDirectiveLocationVisitor
- }
- // EnterSchemaDefinitionVisitor is the callback when the walker enters a schema definition
- EnterSchemaDefinitionVisitor interface {
- // EnterSchemaDefinition gets called when the walker enters a schema definition
- // ref is the reference to the selection set on the AST
- EnterSchemaDefinition(ref int)
- }
- // LeaveSchemaDefinitionVisitor is the callback when the walker leaves a schema definition
- LeaveSchemaDefinitionVisitor interface {
- // LeaveSchemaDefinition gets called when the walker leaves a schema definition
- // ref is the reference to the selection set on the AST
- LeaveSchemaDefinition(ref int)
- }
- // SchemaDefinitionVisitor is the callback when the walker enters or leaves a schema definition
- SchemaDefinitionVisitor interface {
- EnterSchemaDefinitionVisitor
- LeaveSchemaDefinitionVisitor
- }
- // EnterSchemaExtensionVisitor is the callback when the walker enters a schema extension
- EnterSchemaExtensionVisitor interface {
- // EnterSchemaExtension gets called when the walker enters a schema extension
- // ref is the reference to the selection set on the AST
- EnterSchemaExtension(ref int)
- }
- // LeaveSchemaExtensionVisitor is the callback when the walker leaves a schema extension
- LeaveSchemaExtensionVisitor interface {
- // LeaveSchemaExtension gets called when the walker leaves a schema extension
- // ref is the reference to the selection set on the AST
- LeaveSchemaExtension(ref int)
- }
- // SchemaExtensionVisitor is the callback when the walker enters or leaves a schema extension
- SchemaExtensionVisitor interface {
- EnterSchemaExtensionVisitor
- LeaveSchemaExtensionVisitor
- }
- // EnterRootOperationTypeDefinitionVisitor is the callback when the walker enters a root operation type definition
- EnterRootOperationTypeDefinitionVisitor interface {
- // EnterRootOperationTypeDefinition gets called when the walker enters a root operation type definition
- // ref is the reference to the selection set on the AST
- EnterRootOperationTypeDefinition(ref int)
- }
- // LeaveRootOperationTypeDefinitionVisitor is the callback when the walker leaves a root operation type definition
- LeaveRootOperationTypeDefinitionVisitor interface {
- // LeaveRootOperationTypeDefinition gets called when the walker leaves a root operation type definition
- // ref is the reference to the selection set on the AST
- LeaveRootOperationTypeDefinition(ref int)
- }
- // RootOperationTypeDefinitionVisitor is the callback when the walker enters or leaves a root operation type definition
- RootOperationTypeDefinitionVisitor interface {
- EnterRootOperationTypeDefinitionVisitor
- LeaveRootOperationTypeDefinitionVisitor
- }
- // TypeSystemVisitor is the callback when the walker enters or leaves any of the type definitions
- TypeSystemVisitor interface {
- ObjectTypeDefinitionVisitor
- ObjectTypeExtensionVisitor
- FieldDefinitionVisitor
- InputValueDefinitionVisitor
- InterfaceTypeDefinitionVisitor
- InterfaceTypeExtensionVisitor
- ScalarTypeDefinitionVisitor
- ScalarTypeExtensionVisitor
- UnionTypeDefinitionVisitor
- UnionTypeExtensionVisitor
- UnionMemberTypeVisitor
- EnumTypeDefinitionVisitor
- EnumTypeExtensionVisitor
- EnumValueDefinitionVisitor
- InputObjectTypeDefinitionVisitor
- InputObjectTypeExtensionVisitor
- DirectiveDefinitionVisitor
- DirectiveLocationVisitor
- SchemaDefinitionVisitor
- SchemaExtensionVisitor
- RootOperationTypeDefinitionVisitor
- }
- // ExecutableVisitor is the callback when the walker enters or leaves any of the executable definitions
- ExecutableVisitor interface {
- OperationDefinitionVisitor
- SelectionSetVisitor
- FieldVisitor
- ArgumentVisitor
- FragmentSpreadVisitor
- InlineFragmentVisitor
- FragmentDefinitionVisitor
- VariableDefinitionVisitor
- DirectiveVisitor
- }
- // EnterDocumentVisitor is the callback when the walker enters a document
- EnterDocumentVisitor interface {
- // EnterDocument gets called when the walker enters a document
- EnterDocument(operation, definition *ast.Document)
- }
- LeaveDocumentVisitor interface {
- // LeaveDocument gets called when the walker leaves a document
- LeaveDocument(operation, definition *ast.Document)
- }
- // DocumentVisitor is the callback when the walker enters or leaves a document
- DocumentVisitor interface {
- EnterDocumentVisitor
- LeaveDocumentVisitor
- }
- // AllNodesVisitor is the callback when the walker enters or leaves any Node
- AllNodesVisitor interface {
- DocumentVisitor
- TypeSystemVisitor
- ExecutableVisitor
- }
- // VisitorFilter can be defined to prevent specific visitors from getting invoked
- VisitorFilter interface {
- AllowVisitor(kind VisitorKind, ref int, visitor interface{}) bool
- }
-)
-
-type VisitorKind int
-
-const (
- EnterOperation VisitorKind = iota + 1
- LeaveOperation
- EnterSelectionSet
- LeaveSelectionSet
- EnterField
- LeaveField
- EnterArgument
- LeaveArgument
- EnterFragmentSpread
- LeaveFragmentSpread
- EnterInlineFragment
- LeaveInlineFragment
- EnterFragmentDefinition
- LeaveFragmentDefinition
- EnterDocument
- LeaveDocument
- EnterVariableDefinition
- LeaveVariableDefinition
- EnterDirective
- LeaveDirective
- EnterObjectTypeDefinition
- LeaveObjectTypeDefinition
- EnterFieldDefinition
- LeaveFieldDefinition
- EnterInputValueDefinition
- LeaveInputValueDefinition
- EnterInterfaceTypeDefinition
- LeaveInterfaceTypeDefinition
- EnterInterfaceTypeExtension
- LeaveInterfaceTypeExtension
- EnterObjectTypeExtension
- LeaveObjectTypeExtension
- EnterScalarTypeDefinition
- LeaveScalarTypeDefinition
- EnterScalarTypeExtension
- LeaveScalarTypeExtension
- EnterUnionTypeDefinition
- LeaveUnionTypeDefinition
- EnterUnionTypeExtension
- LeaveUnionTypeExtension
- EnterUnionMemberType
- LeaveUnionMemberType
- EnterEnumTypeDefinition
- LeaveEnumTypeDefinition
- EnterEnumTypeExtension
- LeaveEnumTypeExtension
- EnterEnumValueDefinition
- LeaveEnumValueDefinition
- EnterInputObjectTypeDefinition
- LeaveInputObjectTypeDefinition
- EnterInputObjectTypeExtension
- LeaveInputObjectTypeExtension
- EnterDirectiveDefinition
- LeaveDirectiveDefinition
- EnterDirectiveLocation
- LeaveDirectiveLocation
- EnterSchemaDefinition
- LeaveSchemaDefinition
- EnterSchemaExtension
- LeaveSchemaExtension
- EnterRootOperationTypeDefinition
- LeaveRootOperationTypeDefinition
-)
-
-type visitors struct {
- enterOperation []EnterOperationDefinitionVisitor
- leaveOperation []LeaveOperationDefinitionVisitor
- enterSelectionSet []EnterSelectionSetVisitor
- leaveSelectionSet []LeaveSelectionSetVisitor
- enterField []EnterFieldVisitor
- leaveField []LeaveFieldVisitor
- enterArgument []EnterArgumentVisitor
- leaveArgument []LeaveArgumentVisitor
- enterFragmentSpread []EnterFragmentSpreadVisitor
- leaveFragmentSpread []LeaveFragmentSpreadVisitor
- enterInlineFragment []EnterInlineFragmentVisitor
- leaveInlineFragment []LeaveInlineFragmentVisitor
- enterFragmentDefinition []EnterFragmentDefinitionVisitor
- leaveFragmentDefinition []LeaveFragmentDefinitionVisitor
- enterDocument []EnterDocumentVisitor
- leaveDocument []LeaveDocumentVisitor
- enterVariableDefinition []EnterVariableDefinitionVisitor
- leaveVariableDefinition []LeaveVariableDefinitionVisitor
- enterDirective []EnterDirectiveVisitor
- leaveDirective []LeaveDirectiveVisitor
- enterObjectTypeDefinition []EnterObjectTypeDefinitionVisitor
- leaveObjectTypeDefinition []LeaveObjectTypeDefinitionVisitor
- enterFieldDefinition []EnterFieldDefinitionVisitor
- leaveFieldDefinition []LeaveFieldDefinitionVisitor
- enterInputValueDefinition []EnterInputValueDefinitionVisitor
- leaveInputValueDefinition []LeaveInputValueDefinitionVisitor
- enterInterfaceTypeDefinition []EnterInterfaceTypeDefinitionVisitor
- leaveInterfaceTypeDefinition []LeaveInterfaceTypeDefinitionVisitor
- enterInterfaceTypeExtension []EnterInterfaceTypeExtensionVisitor
- leaveInterfaceTypeExtension []LeaveInterfaceTypeExtensionVisitor
- enterObjectTypeExtension []EnterObjectTypeExtensionVisitor
- leaveObjectTypeExtension []LeaveObjectTypeExtensionVisitor
- enterScalarTypeDefinition []EnterScalarTypeDefinitionVisitor
- leaveScalarTypeDefinition []LeaveScalarTypeDefinitionVisitor
- enterScalarTypeExtension []EnterScalarTypeExtensionVisitor
- leaveScalarTypeExtension []LeaveScalarTypeExtensionVisitor
- enterUnionTypeDefinition []EnterUnionTypeDefinitionVisitor
- leaveUnionTypeDefinition []LeaveUnionTypeDefinitionVisitor
- enterUnionTypeExtension []EnterUnionTypeExtensionVisitor
- leaveUnionTypeExtension []LeaveUnionTypeExtensionVisitor
- enterUnionMemberType []EnterUnionMemberTypeVisitor
- leaveUnionMemberType []LeaveUnionMemberTypeVisitor
- enterEnumTypeDefinition []EnterEnumTypeDefinitionVisitor
- leaveEnumTypeDefinition []LeaveEnumTypeDefinitionVisitor
- enterEnumTypeExtension []EnterEnumTypeExtensionVisitor
- leaveEnumTypeExtension []LeaveEnumTypeExtensionVisitor
- enterEnumValueDefinition []EnterEnumValueDefinitionVisitor
- leaveEnumValueDefinition []LeaveEnumValueDefinitionVisitor
- enterInputObjectTypeDefinition []EnterInputObjectTypeDefinitionVisitor
- leaveInputObjectTypeDefinition []LeaveInputObjectTypeDefinitionVisitor
- enterInputObjectTypeExtension []EnterInputObjectTypeExtensionVisitor
- leaveInputObjectTypeExtension []LeaveInputObjectTypeExtensionVisitor
- enterDirectiveDefinition []EnterDirectiveDefinitionVisitor
- leaveDirectiveDefinition []LeaveDirectiveDefinitionVisitor
- enterDirectiveLocation []EnterDirectiveLocationVisitor
- leaveDirectiveLocation []LeaveDirectiveLocationVisitor
- enterSchemaDefinition []EnterSchemaDefinitionVisitor
- leaveSchemaDefinition []LeaveSchemaDefinitionVisitor
- enterSchemaExtension []EnterSchemaExtensionVisitor
- leaveSchemaExtension []LeaveSchemaExtensionVisitor
- enterRootOperationTypeDefinition []EnterRootOperationTypeDefinitionVisitor
- leaveRootOperationTypeDefinition []LeaveRootOperationTypeDefinitionVisitor
-}
-
-// ResetVisitors empties all registered visitors / unregisters all callbacks
-func (w *Walker) ResetVisitors() {
- w.visitors.enterOperation = w.visitors.enterOperation[:0]
- w.visitors.leaveOperation = w.visitors.leaveOperation[:0]
- w.visitors.enterSelectionSet = w.visitors.enterSelectionSet[:0]
- w.visitors.leaveSelectionSet = w.visitors.leaveSelectionSet[:0]
- w.visitors.enterField = w.visitors.enterField[:0]
- w.visitors.leaveField = w.visitors.leaveField[:0]
- w.visitors.enterArgument = w.visitors.enterArgument[:0]
- w.visitors.leaveArgument = w.visitors.leaveArgument[:0]
- w.visitors.enterFragmentSpread = w.visitors.enterFragmentSpread[:0]
- w.visitors.leaveFragmentSpread = w.visitors.leaveFragmentSpread[:0]
- w.visitors.enterInlineFragment = w.visitors.enterInlineFragment[:0]
- w.visitors.leaveInlineFragment = w.visitors.leaveInlineFragment[:0]
- w.visitors.enterFragmentDefinition = w.visitors.enterFragmentDefinition[:0]
- w.visitors.leaveFragmentDefinition = w.visitors.leaveFragmentDefinition[:0]
- w.visitors.enterDocument = w.visitors.enterDocument[:0]
- w.visitors.leaveDocument = w.visitors.leaveDocument[:0]
- w.visitors.enterVariableDefinition = w.visitors.enterVariableDefinition[:0]
- w.visitors.leaveVariableDefinition = w.visitors.leaveVariableDefinition[:0]
- w.visitors.enterDirective = w.visitors.enterDirective[:0]
- w.visitors.leaveDirective = w.visitors.leaveDirective[:0]
- w.visitors.enterObjectTypeDefinition = w.visitors.enterObjectTypeDefinition[:0]
- w.visitors.leaveObjectTypeDefinition = w.visitors.leaveObjectTypeDefinition[:0]
- w.visitors.enterFieldDefinition = w.visitors.enterFieldDefinition[:0]
- w.visitors.leaveFieldDefinition = w.visitors.leaveFieldDefinition[:0]
- w.visitors.enterInputValueDefinition = w.visitors.enterInputValueDefinition[:0]
- w.visitors.leaveInputValueDefinition = w.visitors.leaveInputValueDefinition[:0]
- w.visitors.enterInterfaceTypeDefinition = w.visitors.enterInterfaceTypeDefinition[:0]
- w.visitors.leaveInterfaceTypeDefinition = w.visitors.leaveInterfaceTypeDefinition[:0]
- w.visitors.enterInterfaceTypeExtension = w.visitors.enterInterfaceTypeExtension[:0]
- w.visitors.leaveInterfaceTypeExtension = w.visitors.leaveInterfaceTypeExtension[:0]
- w.visitors.enterObjectTypeExtension = w.visitors.enterObjectTypeExtension[:0]
- w.visitors.leaveObjectTypeExtension = w.visitors.leaveObjectTypeExtension[:0]
- w.visitors.enterScalarTypeDefinition = w.visitors.enterScalarTypeDefinition[:0]
- w.visitors.leaveScalarTypeDefinition = w.visitors.leaveScalarTypeDefinition[:0]
- w.visitors.enterScalarTypeExtension = w.visitors.enterScalarTypeExtension[:0]
- w.visitors.leaveScalarTypeExtension = w.visitors.leaveScalarTypeExtension[:0]
- w.visitors.enterUnionTypeDefinition = w.visitors.enterUnionTypeDefinition[:0]
- w.visitors.leaveUnionTypeDefinition = w.visitors.leaveUnionTypeDefinition[:0]
- w.visitors.enterUnionTypeExtension = w.visitors.enterUnionTypeExtension[:0]
- w.visitors.leaveUnionTypeExtension = w.visitors.leaveUnionTypeExtension[:0]
- w.visitors.enterUnionMemberType = w.visitors.enterUnionMemberType[:0]
- w.visitors.leaveUnionMemberType = w.visitors.leaveUnionMemberType[:0]
- w.visitors.enterEnumTypeDefinition = w.visitors.enterEnumTypeDefinition[:0]
- w.visitors.leaveEnumTypeDefinition = w.visitors.leaveEnumTypeDefinition[:0]
- w.visitors.enterEnumTypeExtension = w.visitors.enterEnumTypeExtension[:0]
- w.visitors.leaveEnumTypeExtension = w.visitors.leaveEnumTypeExtension[:0]
- w.visitors.enterEnumValueDefinition = w.visitors.enterEnumValueDefinition[:0]
- w.visitors.leaveEnumValueDefinition = w.visitors.leaveEnumValueDefinition[:0]
- w.visitors.enterInputObjectTypeDefinition = w.visitors.enterInputObjectTypeDefinition[:0]
- w.visitors.leaveInputObjectTypeDefinition = w.visitors.leaveInputObjectTypeDefinition[:0]
- w.visitors.enterInputObjectTypeExtension = w.visitors.enterInputObjectTypeExtension[:0]
- w.visitors.leaveInputObjectTypeExtension = w.visitors.leaveInputObjectTypeExtension[:0]
- w.visitors.enterDirectiveDefinition = w.visitors.enterDirectiveDefinition[:0]
- w.visitors.leaveDirectiveDefinition = w.visitors.leaveDirectiveDefinition[:0]
- w.visitors.enterDirectiveLocation = w.visitors.enterDirectiveLocation[:0]
- w.visitors.leaveDirectiveLocation = w.visitors.leaveDirectiveLocation[:0]
- w.visitors.enterSchemaDefinition = w.visitors.enterSchemaDefinition[:0]
- w.visitors.leaveSchemaDefinition = w.visitors.leaveSchemaDefinition[:0]
- w.visitors.enterSchemaExtension = w.visitors.enterSchemaExtension[:0]
- w.visitors.leaveSchemaExtension = w.visitors.leaveSchemaExtension[:0]
- w.visitors.enterRootOperationTypeDefinition = w.visitors.enterRootOperationTypeDefinition[:0]
- w.visitors.leaveRootOperationTypeDefinition = w.visitors.leaveRootOperationTypeDefinition[:0]
- w.deferred = w.deferred[:0]
-}
-
-func (w *Walker) setCurrent(kind ast.NodeKind, ref int) {
- w.CurrentKind = kind
- w.CurrentRef = ref
-}
-
-func (w *Walker) RegisterExecutableVisitor(visitor ExecutableVisitor) {
- w.RegisterOperationDefinitionVisitor(visitor)
- w.RegisterSelectionSetVisitor(visitor)
- w.RegisterFieldVisitor(visitor)
- w.RegisterArgumentVisitor(visitor)
- w.RegisterFragmentSpreadVisitor(visitor)
- w.RegisterInlineFragmentVisitor(visitor)
- w.RegisterFragmentDefinitionVisitor(visitor)
- w.RegisterVariableDefinitionVisitor(visitor)
- w.RegisterDirectiveVisitor(visitor)
-}
-
-func (w *Walker) RegisterTypeSystemVisitor(visitor TypeSystemVisitor) {
- w.RegisterObjectTypeDefinitionVisitor(visitor)
- w.RegisterObjectTypeExtensionVisitor(visitor)
- w.RegisterFieldDefinitionVisitor(visitor)
- w.RegisterInputValueDefinitionVisitor(visitor)
- w.RegisterInterfaceTypeDefinitionVisitor(visitor)
- w.RegisterInterfaceTypeExtensionVisitor(visitor)
- w.RegisterScalarTypeDefinitionVisitor(visitor)
- w.RegisterScalarTypeExtensionVisitor(visitor)
- w.RegisterUnionTypeDefinitionVisitor(visitor)
- w.RegisterUnionTypeExtensionVisitor(visitor)
- w.RegisterUnionMemberTypeVisitor(visitor)
- w.RegisterEnumTypeDefinitionVisitor(visitor)
- w.RegisterEnumTypeExtensionVisitor(visitor)
- w.RegisterEnumValueDefinitionVisitor(visitor)
- w.RegisterInputObjectTypeDefinitionVisitor(visitor)
- w.RegisterInputObjectTypeExtensionVisitor(visitor)
- w.RegisterDirectiveDefinitionVisitor(visitor)
- w.RegisterDirectiveLocationVisitor(visitor)
- w.RegisterSchemaDefinitionVisitor(visitor)
- w.RegisterSchemaExtensionVisitor(visitor)
- w.RegisterRootOperationTypeDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterRootOperationTypeDefinitionVisitor(visitor EnterRootOperationTypeDefinitionVisitor) {
- w.visitors.enterRootOperationTypeDefinition = append(w.visitors.enterRootOperationTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveRootOperationTypeDefinitionVisitor(visitor LeaveRootOperationTypeDefinitionVisitor) {
- w.visitors.leaveRootOperationTypeDefinition = append(w.visitors.leaveRootOperationTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterRootOperationTypeDefinitionVisitor(visitor RootOperationTypeDefinitionVisitor) {
- w.RegisterEnterRootOperationTypeDefinitionVisitor(visitor)
- w.RegisterLeaveRootOperationTypeDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterSchemaDefinitionVisitor(visitor EnterSchemaDefinitionVisitor) {
- w.visitors.enterSchemaDefinition = append(w.visitors.enterSchemaDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveSchemaDefinitionVisitor(visitor LeaveSchemaDefinitionVisitor) {
- w.visitors.leaveSchemaDefinition = append(w.visitors.leaveSchemaDefinition, visitor)
-}
-
-func (w *Walker) RegisterSchemaDefinitionVisitor(visitor SchemaDefinitionVisitor) {
- w.RegisterEnterSchemaDefinitionVisitor(visitor)
- w.RegisterLeaveSchemaDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterSchemaExtensionVisitor(visitor EnterSchemaExtensionVisitor) {
- w.visitors.enterSchemaExtension = append(w.visitors.enterSchemaExtension, visitor)
-}
-
-func (w *Walker) RegisterLeaveSchemaExtensionVisitor(visitor LeaveSchemaExtensionVisitor) {
- w.visitors.leaveSchemaExtension = append(w.visitors.leaveSchemaExtension, visitor)
-}
-
-func (w *Walker) RegisterSchemaExtensionVisitor(visitor SchemaExtensionVisitor) {
- w.RegisterEnterSchemaExtensionVisitor(visitor)
- w.RegisterLeaveSchemaExtensionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterDirectiveLocationVisitor(visitor EnterDirectiveLocationVisitor) {
- w.visitors.enterDirectiveLocation = append(w.visitors.enterDirectiveLocation, visitor)
-}
-
-func (w *Walker) RegisterLeaveDirectiveLocationVisitor(visitor LeaveDirectiveLocationVisitor) {
- w.visitors.leaveDirectiveLocation = append(w.visitors.leaveDirectiveLocation, visitor)
-}
-
-func (w *Walker) RegisterDirectiveLocationVisitor(visitor DirectiveLocationVisitor) {
- w.RegisterEnterDirectiveLocationVisitor(visitor)
- w.RegisterLeaveDirectiveLocationVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterDirectiveDefinitionVisitor(visitor EnterDirectiveDefinitionVisitor) {
- w.visitors.enterDirectiveDefinition = append(w.visitors.enterDirectiveDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveDirectiveDefinitionVisitor(visitor LeaveDirectiveDefinitionVisitor) {
- w.visitors.leaveDirectiveDefinition = append(w.visitors.leaveDirectiveDefinition, visitor)
-}
-
-func (w *Walker) RegisterDirectiveDefinitionVisitor(visitor DirectiveDefinitionVisitor) {
- w.RegisterEnterDirectiveDefinitionVisitor(visitor)
- w.RegisterLeaveDirectiveDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterUnionMemberTypeVisitor(visitor EnterUnionMemberTypeVisitor) {
- w.visitors.enterUnionMemberType = append(w.visitors.enterUnionMemberType, visitor)
-}
-
-func (w *Walker) RegisterLeaveUnionMemberTypeVisitor(visitor LeaveUnionMemberTypeVisitor) {
- w.visitors.leaveUnionMemberType = append(w.visitors.leaveUnionMemberType, visitor)
-}
-
-func (w *Walker) RegisterUnionMemberTypeVisitor(visitor UnionMemberTypeVisitor) {
- w.RegisterEnterUnionMemberTypeVisitor(visitor)
- w.RegisterLeaveUnionMemberTypeVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterInputObjectTypeDefinitionVisitor(visitor EnterInputObjectTypeDefinitionVisitor) {
- w.visitors.enterInputObjectTypeDefinition = append(w.visitors.enterInputObjectTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveInputObjectTypeDefinitionVisitor(visitor LeaveInputObjectTypeDefinitionVisitor) {
- w.visitors.leaveInputObjectTypeDefinition = append(w.visitors.leaveInputObjectTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterInputObjectTypeDefinitionVisitor(visitor InputObjectTypeDefinitionVisitor) {
- w.RegisterEnterInputObjectTypeDefinitionVisitor(visitor)
- w.RegisterLeaveInputObjectTypeDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterInputObjectTypeExtensionVisitor(visitor EnterInputObjectTypeExtensionVisitor) {
- w.visitors.enterInputObjectTypeExtension = append(w.visitors.enterInputObjectTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterLeaveInputObjectTypeExtensionVisitor(visitor LeaveInputObjectTypeExtensionVisitor) {
- w.visitors.leaveInputObjectTypeExtension = append(w.visitors.leaveInputObjectTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterInputObjectTypeExtensionVisitor(visitor InputObjectTypeExtensionVisitor) {
- w.RegisterEnterInputObjectTypeExtensionVisitor(visitor)
- w.RegisterLeaveInputObjectTypeExtensionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterEnumTypeDefinitionVisitor(visitor EnterEnumTypeDefinitionVisitor) {
- w.visitors.enterEnumTypeDefinition = append(w.visitors.enterEnumTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveEnumTypeDefinitionVisitor(visitor LeaveEnumTypeDefinitionVisitor) {
- w.visitors.leaveEnumTypeDefinition = append(w.visitors.leaveEnumTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterEnumTypeDefinitionVisitor(visitor EnumTypeDefinitionVisitor) {
- w.RegisterEnterEnumTypeDefinitionVisitor(visitor)
- w.RegisterLeaveEnumTypeDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterEnumTypeExtensionVisitor(visitor EnterEnumTypeExtensionVisitor) {
- w.visitors.enterEnumTypeExtension = append(w.visitors.enterEnumTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterLeaveEnumTypeExtensionVisitor(visitor LeaveEnumTypeExtensionVisitor) {
- w.visitors.leaveEnumTypeExtension = append(w.visitors.leaveEnumTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterEnumTypeExtensionVisitor(visitor EnumTypeExtensionVisitor) {
- w.RegisterEnterEnumTypeExtensionVisitor(visitor)
- w.RegisterLeaveEnumTypeExtensionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterEnumValueDefinitionVisitor(visitor EnterEnumValueDefinitionVisitor) {
- w.visitors.enterEnumValueDefinition = append(w.visitors.enterEnumValueDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveEnumValueDefinitionVisitor(visitor LeaveEnumValueDefinitionVisitor) {
- w.visitors.leaveEnumValueDefinition = append(w.visitors.leaveEnumValueDefinition, visitor)
-}
-
-func (w *Walker) RegisterEnumValueDefinitionVisitor(visitor EnumValueDefinitionVisitor) {
- w.RegisterEnterEnumValueDefinitionVisitor(visitor)
- w.RegisterLeaveEnumValueDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterUnionTypeDefinitionVisitor(visitor EnterUnionTypeDefinitionVisitor) {
- w.visitors.enterUnionTypeDefinition = append(w.visitors.enterUnionTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveUnionTypeDefinitionVisitor(visitor LeaveUnionTypeDefinitionVisitor) {
- w.visitors.leaveUnionTypeDefinition = append(w.visitors.leaveUnionTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterUnionTypeDefinitionVisitor(visitor UnionTypeDefinitionVisitor) {
- w.RegisterEnterUnionTypeDefinitionVisitor(visitor)
- w.RegisterLeaveUnionTypeDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterUnionTypeExtensionVisitor(visitor EnterUnionTypeExtensionVisitor) {
- w.visitors.enterUnionTypeExtension = append(w.visitors.enterUnionTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterLeaveUnionTypeExtensionVisitor(visitor LeaveUnionTypeExtensionVisitor) {
- w.visitors.leaveUnionTypeExtension = append(w.visitors.leaveUnionTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterUnionTypeExtensionVisitor(visitor UnionTypeExtensionVisitor) {
- w.RegisterEnterUnionTypeExtensionVisitor(visitor)
- w.RegisterLeaveUnionTypeExtensionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterScalarTypeExtensionVisitor(visitor EnterScalarTypeExtensionVisitor) {
- w.visitors.enterScalarTypeExtension = append(w.visitors.enterScalarTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterLeaveScalarTypeExtensionVisitor(visitor LeaveScalarTypeExtensionVisitor) {
- w.visitors.leaveScalarTypeExtension = append(w.visitors.leaveScalarTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterScalarTypeExtensionVisitor(visitor ScalarTypeExtensionVisitor) {
- w.RegisterEnterScalarTypeExtensionVisitor(visitor)
- w.RegisterLeaveScalarTypeExtensionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterScalarTypeDefinitionVisitor(visitor EnterScalarTypeDefinitionVisitor) {
- w.visitors.enterScalarTypeDefinition = append(w.visitors.enterScalarTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveScalarTypeDefinitionVisitor(visitor LeaveScalarTypeDefinitionVisitor) {
- w.visitors.leaveScalarTypeDefinition = append(w.visitors.leaveScalarTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterScalarTypeDefinitionVisitor(visitor ScalarTypeDefinitionVisitor) {
- w.RegisterEnterScalarTypeDefinitionVisitor(visitor)
- w.RegisterLeaveScalarTypeDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterInterfaceTypeExtensionVisitor(visitor EnterInterfaceTypeExtensionVisitor) {
- w.visitors.enterInterfaceTypeExtension = append(w.visitors.enterInterfaceTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterLeaveInterfaceTypeExtensionVisitor(visitor LeaveInterfaceTypeExtensionVisitor) {
- w.visitors.leaveInterfaceTypeExtension = append(w.visitors.leaveInterfaceTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterInterfaceTypeExtensionVisitor(visitor InterfaceTypeExtensionVisitor) {
- w.RegisterEnterInterfaceTypeExtensionVisitor(visitor)
- w.RegisterLeaveInterfaceTypeExtensionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterInterfaceTypeDefinitionVisitor(visitor EnterInterfaceTypeDefinitionVisitor) {
- w.visitors.enterInterfaceTypeDefinition = append(w.visitors.enterInterfaceTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveInterfaceTypeDefinitionVisitor(visitor LeaveInterfaceTypeDefinitionVisitor) {
- w.visitors.leaveInterfaceTypeDefinition = append(w.visitors.leaveInterfaceTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterInterfaceTypeDefinitionVisitor(visitor InterfaceTypeDefinitionVisitor) {
- w.RegisterEnterInterfaceTypeDefinitionVisitor(visitor)
- w.RegisterLeaveInterfaceTypeDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterInputValueDefinitionVisitor(visitor EnterInputValueDefinitionVisitor) {
- w.visitors.enterInputValueDefinition = append(w.visitors.enterInputValueDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveInputValueDefinitionVisitor(visitor LeaveInputValueDefinitionVisitor) {
- w.visitors.leaveInputValueDefinition = append(w.visitors.leaveInputValueDefinition, visitor)
-}
-
-func (w *Walker) RegisterInputValueDefinitionVisitor(visitor InputValueDefinitionVisitor) {
- w.RegisterEnterInputValueDefinitionVisitor(visitor)
- w.RegisterLeaveInputValueDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterFieldDefinitionVisitor(visitor EnterFieldDefinitionVisitor) {
- w.visitors.enterFieldDefinition = append(w.visitors.enterFieldDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveFieldDefinitionVisitor(visitor LeaveFieldDefinitionVisitor) {
- w.visitors.leaveFieldDefinition = append(w.visitors.leaveFieldDefinition, visitor)
-}
-
-func (w *Walker) RegisterFieldDefinitionVisitor(visitor FieldDefinitionVisitor) {
- w.RegisterEnterFieldDefinitionVisitor(visitor)
- w.RegisterLeaveFieldDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterObjectTypeExtensionVisitor(visitor EnterObjectTypeExtensionVisitor) {
- w.visitors.enterObjectTypeExtension = append(w.visitors.enterObjectTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterLeaveObjectTypeExtensionVisitor(visitor LeaveObjectTypeExtensionVisitor) {
- w.visitors.leaveObjectTypeExtension = append(w.visitors.leaveObjectTypeExtension, visitor)
-}
-
-func (w *Walker) RegisterObjectTypeExtensionVisitor(visitor ObjectTypeExtensionVisitor) {
- w.RegisterEnterObjectTypeExtensionVisitor(visitor)
- w.RegisterLeaveObjectTypeExtensionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterObjectTypeDefinitionVisitor(visitor EnterObjectTypeDefinitionVisitor) {
- w.visitors.enterObjectTypeDefinition = append(w.visitors.enterObjectTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveObjectTypeDefinitionVisitor(visitor LeaveObjectTypeDefinitionVisitor) {
- w.visitors.leaveObjectTypeDefinition = append(w.visitors.leaveObjectTypeDefinition, visitor)
-}
-
-func (w *Walker) RegisterObjectTypeDefinitionVisitor(visitor ObjectTypeDefinitionVisitor) {
- w.RegisterEnterObjectTypeDefinitionVisitor(visitor)
- w.RegisterLeaveObjectTypeDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterFieldVisitor(visitor EnterFieldVisitor) {
- w.visitors.enterField = append(w.visitors.enterField, visitor)
-}
-
-func (w *Walker) RegisterLeaveFieldVisitor(visitor LeaveFieldVisitor) {
- w.visitors.leaveField = append(w.visitors.leaveField, visitor)
-}
-
-func (w *Walker) RegisterFieldVisitor(visitor FieldVisitor) {
- w.RegisterEnterFieldVisitor(visitor)
- w.RegisterLeaveFieldVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterSelectionSetVisitor(visitor EnterSelectionSetVisitor) {
- w.visitors.enterSelectionSet = append(w.visitors.enterSelectionSet, visitor)
-}
-
-func (w *Walker) RegisterLeaveSelectionSetVisitor(visitor LeaveSelectionSetVisitor) {
- w.visitors.leaveSelectionSet = append(w.visitors.leaveSelectionSet, visitor)
-}
-
-func (w *Walker) RegisterSelectionSetVisitor(visitor SelectionSetVisitor) {
- w.RegisterEnterSelectionSetVisitor(visitor)
- w.RegisterLeaveSelectionSetVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterArgumentVisitor(visitor EnterArgumentVisitor) {
- w.visitors.enterArgument = append(w.visitors.enterArgument, visitor)
-}
-
-func (w *Walker) RegisterLeaveArgumentVisitor(visitor LeaveArgumentVisitor) {
- w.visitors.leaveArgument = append(w.visitors.leaveArgument, visitor)
-}
-
-func (w *Walker) RegisterArgumentVisitor(visitor ArgumentVisitor) {
- w.RegisterEnterArgumentVisitor(visitor)
- w.RegisterLeaveArgumentVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterFragmentSpreadVisitor(visitor EnterFragmentSpreadVisitor) {
- w.visitors.enterFragmentSpread = append(w.visitors.enterFragmentSpread, visitor)
-}
-
-func (w *Walker) RegisterLeaveFragmentSpreadVisitor(visitor LeaveFragmentSpreadVisitor) {
- w.visitors.leaveFragmentSpread = append(w.visitors.leaveFragmentSpread, visitor)
-}
-
-func (w *Walker) RegisterFragmentSpreadVisitor(visitor FragmentSpreadVisitor) {
- w.RegisterEnterFragmentSpreadVisitor(visitor)
- w.RegisterLeaveFragmentSpreadVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterInlineFragmentVisitor(visitor EnterInlineFragmentVisitor) {
- w.visitors.enterInlineFragment = append(w.visitors.enterInlineFragment, visitor)
-}
-
-func (w *Walker) RegisterLeaveInlineFragmentVisitor(visitor LeaveInlineFragmentVisitor) {
- w.visitors.leaveInlineFragment = append(w.visitors.leaveInlineFragment, visitor)
-}
-
-func (w *Walker) RegisterInlineFragmentVisitor(visitor InlineFragmentVisitor) {
- w.RegisterEnterInlineFragmentVisitor(visitor)
- w.RegisterLeaveInlineFragmentVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterFragmentDefinitionVisitor(visitor EnterFragmentDefinitionVisitor) {
- w.visitors.enterFragmentDefinition = append(w.visitors.enterFragmentDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveFragmentDefinitionVisitor(visitor LeaveFragmentDefinitionVisitor) {
- w.visitors.leaveFragmentDefinition = append(w.visitors.leaveFragmentDefinition, visitor)
-}
-
-func (w *Walker) RegisterFragmentDefinitionVisitor(visitor FragmentDefinitionVisitor) {
- w.RegisterEnterFragmentDefinitionVisitor(visitor)
- w.RegisterLeaveFragmentDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterVariableDefinitionVisitor(visitor EnterVariableDefinitionVisitor) {
- w.visitors.enterVariableDefinition = append(w.visitors.enterVariableDefinition, visitor)
-}
-
-func (w *Walker) RegisterLeaveVariableDefinitionVisitor(visitor LeaveVariableDefinitionVisitor) {
- w.visitors.leaveVariableDefinition = append(w.visitors.leaveVariableDefinition, visitor)
-}
-
-func (w *Walker) RegisterVariableDefinitionVisitor(visitor VariableDefinitionVisitor) {
- w.RegisterEnterVariableDefinitionVisitor(visitor)
- w.RegisterLeaveVariableDefinitionVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterOperationVisitor(visitor EnterOperationDefinitionVisitor) {
- w.visitors.enterOperation = append(w.visitors.enterOperation, visitor)
-}
-
-func (w *Walker) RegisterLeaveOperationVisitor(visitor LeaveOperationDefinitionVisitor) {
- w.visitors.leaveOperation = append(w.visitors.leaveOperation, visitor)
-}
-
-func (w *Walker) RegisterOperationDefinitionVisitor(visitor OperationDefinitionVisitor) {
- w.RegisterEnterOperationVisitor(visitor)
- w.RegisterLeaveOperationVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterDirectiveVisitor(visitor EnterDirectiveVisitor) {
- w.visitors.enterDirective = append(w.visitors.enterDirective, visitor)
-}
-
-func (w *Walker) RegisterLeaveDirectiveVisitor(visitor LeaveDirectiveVisitor) {
- w.visitors.leaveDirective = append(w.visitors.leaveDirective, visitor)
-}
-
-func (w *Walker) RegisterDirectiveVisitor(visitor DirectiveVisitor) {
- w.RegisterEnterDirectiveVisitor(visitor)
- w.RegisterLeaveDirectiveVisitor(visitor)
-}
-
-func (w *Walker) RegisterAllNodesVisitor(visitor AllNodesVisitor) {
- w.RegisterDocumentVisitor(visitor)
- w.RegisterExecutableVisitor(visitor)
- w.RegisterTypeSystemVisitor(visitor)
-}
-
-func (w *Walker) RegisterEnterDocumentVisitor(visitor EnterDocumentVisitor) {
- w.visitors.enterDocument = append(w.visitors.enterDocument, visitor)
-}
-
-func (w *Walker) RegisterLeaveDocumentVisitor(visitor LeaveDocumentVisitor) {
- w.visitors.leaveDocument = append(w.visitors.leaveDocument, visitor)
-}
-
-func (w *Walker) RegisterDocumentVisitor(visitor DocumentVisitor) {
- w.RegisterEnterDocumentVisitor(visitor)
- w.RegisterLeaveDocumentVisitor(visitor)
-}
-
-func (w *Walker) SetVisitorFilter(filter VisitorFilter) {
- w.filter = filter
-}
-
-// Walk initiates the walker to start walking the AST from the top root Node
-func (w *Walker) Walk(document, definition *ast.Document, report *operationreport.Report) {
- if report == nil {
- w.Report = &operationreport.Report{}
- } else {
- w.Report = report
- }
- w.Ancestors = w.Ancestors[:0]
- w.Path = w.Path[:0]
- w.typeDefinitions = w.typeDefinitions[:0]
- w.document = document
- w.definition = definition
- w.Depth = 0
- w.stop = false
- w.walk()
-}
-
-// Defer runs the provided func() after the current batch of visitors
-// This gives you the possibility to execute some code that should e.g. run after all EnterField Visitors
-func (w *Walker) Defer(fn func()) {
- w.deferred = append(w.deferred, fn)
-}
-
-func (w *Walker) runDeferred() {
- if len(w.deferred) == 0 {
- return
- }
- for i := range w.deferred {
- w.deferred[i]()
- }
- w.deferred = w.deferred[:0]
-}
-
-func (w *Walker) appendAncestor(ref int, kind ast.NodeKind) {
-
- w.Ancestors = append(w.Ancestors, ast.Node{
- Kind: kind,
- Ref: ref,
- })
-
- var typeName ast.ByteSlice
-
- switch kind {
- case ast.NodeKindOperationDefinition:
- switch w.document.OperationDefinitions[ref].OperationType {
- case ast.OperationTypeQuery:
- typeName = w.definition.Index.QueryTypeName
- w.Path = append(w.Path, ast.PathItem{
- Kind: ast.FieldName,
- FieldName: literal.QUERY,
- })
- case ast.OperationTypeMutation:
- typeName = w.definition.Index.MutationTypeName
- w.Path = append(w.Path, ast.PathItem{
- Kind: ast.FieldName,
- FieldName: literal.MUTATION,
- })
- case ast.OperationTypeSubscription:
- typeName = w.definition.Index.SubscriptionTypeName
- w.Path = append(w.Path, ast.PathItem{
- Kind: ast.FieldName,
- FieldName: literal.SUBSCRIPTION,
- })
- default:
- return
- }
- case ast.NodeKindInlineFragment:
- if !w.document.InlineFragmentHasTypeCondition(ref) {
- return
- }
- typeName = w.document.InlineFragmentTypeConditionName(ref)
- case ast.NodeKindFragmentDefinition:
- typeName = w.document.FragmentDefinitionTypeName(ref)
- w.Path = append(w.Path, ast.PathItem{
- Kind: ast.FieldName,
- ArrayIndex: 0,
- FieldName: typeName,
- })
- case ast.NodeKindField:
- fieldName := w.document.FieldNameBytes(ref)
- w.Path = append(w.Path, ast.PathItem{
- Kind: ast.FieldName,
- ArrayIndex: 0,
- FieldName: w.document.FieldAliasOrNameBytes(ref),
- })
- if bytes.Equal(fieldName, literal.TYPENAME) {
- typeName = literal.STRING
- }
- fields := w.definition.NodeFieldDefinitions(w.typeDefinitions[len(w.typeDefinitions)-1])
- for _, i := range fields {
- if bytes.Equal(fieldName, w.definition.FieldDefinitionNameBytes(i)) {
- typeName = w.definition.ResolveTypeNameBytes(w.definition.FieldDefinitionType(i))
- break
- }
- }
- if typeName == nil {
- typeName := w.definition.NodeNameBytes(w.typeDefinitions[len(w.typeDefinitions)-1])
- w.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, typeName))
- return
- }
- case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition:
- w.EnclosingTypeDefinition = ast.Node{
- Kind: kind,
- Ref: ref,
- }
- return
- default:
- return
- }
-
- var exists bool
- w.EnclosingTypeDefinition, exists = w.definition.Index.FirstNodeByNameBytes(typeName)
- if !exists {
- w.StopWithExternalErr(operationreport.ErrTypeUndefined(typeName))
- return
- }
-
- w.typeDefinitions = append(w.typeDefinitions, w.EnclosingTypeDefinition)
-}
-
-func (w *Walker) removeLastAncestor() {
-
- ancestor := w.Ancestors[len(w.Ancestors)-1]
- w.Ancestors = w.Ancestors[:len(w.Ancestors)-1]
-
- switch ancestor.Kind {
- case ast.NodeKindOperationDefinition, ast.NodeKindFragmentDefinition:
- w.Path = w.Path[:len(w.Path)-1]
- w.typeDefinitions = w.typeDefinitions[:len(w.typeDefinitions)-1]
- w.EnclosingTypeDefinition.Kind = ast.NodeKindUnknown
- w.EnclosingTypeDefinition.Ref = -1
- case ast.NodeKindInlineFragment:
- if w.document.InlineFragmentHasTypeCondition(ancestor.Ref) {
- w.typeDefinitions = w.typeDefinitions[:len(w.typeDefinitions)-1]
- w.EnclosingTypeDefinition = w.typeDefinitions[len(w.typeDefinitions)-1]
- }
- case ast.NodeKindField:
- w.Path = w.Path[:len(w.Path)-1]
- w.typeDefinitions = w.typeDefinitions[:len(w.typeDefinitions)-1]
- w.EnclosingTypeDefinition = w.typeDefinitions[len(w.typeDefinitions)-1]
- case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition:
- w.EnclosingTypeDefinition.Ref = -1
- w.EnclosingTypeDefinition.Kind = ast.NodeKindUnknown
- default:
- return
- }
-}
-
-func (w *Walker) increaseDepth() {
- w.Depth++
-}
-
-func (w *Walker) decreaseDepth() {
- w.Depth--
-}
-
-func (w *Walker) walk() {
-
- if w.document == nil {
- w.Report.AddInternalError(ErrDocumentMustNotBeNil)
- return
- }
-
- for i := 0; i < len(w.visitors.enterDocument); {
- if w.filter == nil || w.filter.AllowVisitor(EnterDocument, 0, w.visitors.enterDocument[i]) {
- w.visitors.enterDocument[i].EnterDocument(w.document, w.definition)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- return
- }
- i++
- }
-
- for i := range w.document.RootNodes {
- switch w.document.RootNodes[i].Kind {
- case ast.NodeKindOperationDefinition:
- if w.definition == nil {
- w.Report.AddInternalError(ErrDefinitionMustNotBeNil)
- return
- }
- w.walkOperationDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindFragmentDefinition:
- if w.definition == nil {
- w.Report.AddInternalError(ErrDefinitionMustNotBeNil)
- return
- }
- w.walkFragmentDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindSchemaDefinition:
- w.walkSchemaDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindSchemaExtension:
- w.walkSchemaExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindDirectiveDefinition:
- w.walkDirectiveDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindObjectTypeDefinition:
- w.walkObjectTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindObjectTypeExtension:
- w.walkObjectTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindInterfaceTypeDefinition:
- w.walkInterfaceTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindInterfaceTypeExtension:
- w.walkInterfaceTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindScalarTypeDefinition:
- w.walkScalarTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindScalarTypeExtension:
- w.walkScalarTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindUnionTypeDefinition:
- w.walkUnionTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindUnionTypeExtension:
- w.walkUnionTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindEnumTypeDefinition:
- w.walkEnumTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindEnumTypeExtension:
- w.walkEnumTypeExtension(w.document.RootNodes[i].Ref)
- case ast.NodeKindInputObjectTypeDefinition:
- w.walkInputObjectTypeDefinition(w.document.RootNodes[i].Ref)
- case ast.NodeKindInputObjectTypeExtension:
- w.walkInputObjectTypeExtension(w.document.RootNodes[i].Ref)
- }
-
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- return
- }
- }
-
- for i := 0; i < len(w.visitors.leaveDocument); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveDocument, 0, w.visitors.leaveDocument[i]) {
- w.visitors.leaveDocument[i].LeaveDocument(w.document, w.definition)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- return
- }
- i++
- }
-}
-
-func (w *Walker) walkOperationDefinition(ref int) {
- w.increaseDepth()
-
- for i := 0; i < len(w.visitors.enterOperation); {
- if w.filter == nil || w.filter.AllowVisitor(EnterOperation, ref, w.visitors.enterOperation[i]) {
- w.visitors.enterOperation[i].EnterOperationDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindOperationDefinition)
- if w.stop {
- return
- }
-
- if w.document.OperationDefinitions[ref].HasVariableDefinitions {
- for _, i := range w.document.OperationDefinitions[ref].VariableDefinitions.Refs {
- w.walkVariableDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.OperationDefinitions[ref].HasDirectives {
- for _, i := range w.document.OperationDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.OperationDefinitions[ref].HasSelections {
- w.walkSelectionSet(w.document.OperationDefinitions[ref].SelectionSet)
- if w.stop {
- return
- }
- }
-
- w.removeLastAncestor()
-
- for i := 0; i < len(w.visitors.leaveOperation); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveOperation, ref, w.visitors.leaveOperation[i]) {
- w.visitors.leaveOperation[i].LeaveOperationDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkVariableDefinition(ref int) {
- w.increaseDepth()
-
- for i := 0; i < len(w.visitors.enterVariableDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterVariableDefinition, ref, w.visitors.enterVariableDefinition[i]) {
- w.visitors.enterVariableDefinition[i].EnterVariableDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindVariableDefinition)
- if w.stop {
- return
- }
-
- if w.document.VariableDefinitions[ref].HasDirectives {
- for _, i := range w.document.VariableDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- for i := 0; i < len(w.visitors.leaveVariableDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveVariableDefinition, ref, w.visitors.leaveVariableDefinition[i]) {
- w.visitors.leaveVariableDefinition[i].LeaveVariableDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkSelectionSet(ref int) {
- w.increaseDepth()
-
- for i := 0; i < len(w.visitors.enterSelectionSet); {
- if w.filter == nil || w.filter.AllowVisitor(EnterSelectionSet, ref, w.visitors.enterSelectionSet[i]) {
- w.visitors.enterSelectionSet[i].EnterSelectionSet(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindSelectionSet)
- if w.stop {
- return
- }
-
-RefsChanged:
- for {
- refs := w.document.SelectionSets[ref].SelectionRefs
- for i, j := range refs {
-
- w.SelectionsBefore = refs[:i]
- w.SelectionsAfter = refs[i+1:]
-
- switch w.document.Selections[j].Kind {
- case ast.SelectionKindField:
- w.walkField(w.document.Selections[j].Ref)
- case ast.SelectionKindFragmentSpread:
- w.walkFragmentSpread(w.document.Selections[j].Ref)
- case ast.SelectionKindInlineFragment:
- w.walkInlineFragment(w.document.Selections[j].Ref)
- }
-
- if w.stop {
- return
- }
- if !w.refsEqual(refs, w.document.SelectionSets[ref].SelectionRefs) {
- continue RefsChanged
- }
- }
- break
- }
-
- w.removeLastAncestor()
-
- for i := 0; i < len(w.visitors.leaveSelectionSet); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveSelectionSet, ref, w.visitors.leaveSelectionSet[i]) {
- w.visitors.leaveSelectionSet[i].LeaveSelectionSet(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkField(ref int) {
- w.increaseDepth()
-
- selectionsBefore := w.SelectionsBefore
- selectionsAfter := w.SelectionsAfter
-
- w.setCurrent(ast.NodeKindField, ref)
-
- for i := 0; i < len(w.visitors.enterField); {
- if w.filter == nil || w.filter.AllowVisitor(EnterField, ref, w.visitors.enterField[i]) {
- w.visitors.enterField[i].EnterField(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.runDeferred()
-
- w.appendAncestor(ref, ast.NodeKindField)
- if w.stop {
- return
- }
-
- if len(w.document.Fields[ref].Arguments.Refs) != 0 {
- for _, i := range w.document.Fields[ref].Arguments.Refs {
- w.walkArgument(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.Fields[ref].HasDirectives {
- for _, i := range w.document.Fields[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.Fields[ref].HasSelections {
- w.walkSelectionSet(w.document.Fields[ref].SelectionSet)
- }
-
- w.removeLastAncestor()
-
- w.SelectionsBefore = selectionsBefore
- w.SelectionsAfter = selectionsAfter
-
- w.setCurrent(ast.NodeKindField, ref)
-
- for i := 0; i < len(w.visitors.leaveField); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveField, ref, w.visitors.leaveField[i]) {
- w.visitors.leaveField[i].LeaveField(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkDirective(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindDirective, ref)
-
- for i := 0; i < len(w.visitors.enterDirective); {
- if w.filter == nil || w.filter.AllowVisitor(EnterDirective, ref, w.visitors.enterDirective[i]) {
- w.visitors.enterDirective[i].EnterDirective(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindDirective)
- if w.stop {
- return
- }
-
- if w.document.Directives[ref].HasArguments {
- for _, i := range w.document.Directives[ref].Arguments.Refs {
- w.walkArgument(i)
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindDirective, ref)
-
- for i := 0; i < len(w.visitors.leaveDirective); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveDirective, ref, w.visitors.leaveDirective[i]) {
- w.visitors.leaveDirective[i].LeaveDirective(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkArgument(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindArgument, ref)
-
- for i := 0; i < len(w.visitors.enterArgument); {
- if w.filter == nil || w.filter.AllowVisitor(EnterArgument, ref, w.visitors.enterArgument[i]) {
- w.visitors.enterArgument[i].EnterArgument(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- for i := 0; i < len(w.visitors.leaveArgument); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveArgument, ref, w.visitors.leaveArgument[i]) {
- w.visitors.leaveArgument[i].LeaveArgument(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkFragmentSpread(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindFragmentSpread, ref)
-
- for i := 0; i < len(w.visitors.enterFragmentSpread); {
- if w.filter == nil || w.filter.AllowVisitor(EnterFragmentSpread, ref, w.visitors.enterFragmentSpread[i]) {
- w.visitors.enterFragmentSpread[i].EnterFragmentSpread(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- for i := 0; i < len(w.visitors.leaveFragmentSpread); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveFragmentSpread, ref, w.visitors.leaveFragmentSpread[i]) {
- w.visitors.leaveFragmentSpread[i].LeaveFragmentSpread(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkInlineFragment(ref int) {
- w.increaseDepth()
-
- selectionsBefore := w.SelectionsBefore
- selectionsAfter := w.SelectionsAfter
-
- w.setCurrent(ast.NodeKindInlineFragment, ref)
-
- for i := 0; i < len(w.visitors.enterInlineFragment); {
- if w.filter == nil || w.filter.AllowVisitor(EnterInlineFragment, ref, w.visitors.enterInlineFragment[i]) {
- w.visitors.enterInlineFragment[i].EnterInlineFragment(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindInlineFragment)
- if w.stop {
- return
- }
-
- if w.document.InlineFragments[ref].HasDirectives {
- for _, i := range w.document.InlineFragments[ref].Directives.Refs {
- w.walkDirective(i)
- }
- }
-
- if w.document.InlineFragments[ref].HasSelections {
- w.walkSelectionSet(w.document.InlineFragments[ref].SelectionSet)
- if w.stop {
- return
- }
- }
-
- w.removeLastAncestor()
-
- w.SelectionsBefore = selectionsBefore
- w.SelectionsAfter = selectionsAfter
-
- w.setCurrent(ast.NodeKindInlineFragment, ref)
-
- for i := 0; i < len(w.visitors.leaveInlineFragment); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveInlineFragment, ref, w.visitors.leaveInlineFragment[i]) {
- w.visitors.leaveInlineFragment[i].LeaveInlineFragment(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkFragmentDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindFragmentDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterFragmentDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterFragmentDefinition, ref, w.visitors.enterFragmentDefinition[i]) {
- w.visitors.enterFragmentDefinition[i].EnterFragmentDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindFragmentDefinition)
- if w.stop {
- return
- }
-
- if w.document.FragmentDefinitions[ref].HasSelections {
- w.walkSelectionSet(w.document.FragmentDefinitions[ref].SelectionSet)
- if w.stop {
- return
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindFragmentDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveFragmentDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveFragmentDefinition, ref, w.visitors.leaveFragmentDefinition[i]) {
- w.visitors.leaveFragmentDefinition[i].LeaveFragmentDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkObjectTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindObjectTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterObjectTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterObjectTypeDefinition, ref, w.visitors.enterObjectTypeDefinition[i]) {
- w.visitors.enterObjectTypeDefinition[i].EnterObjectTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindObjectTypeDefinition)
- if w.stop {
- return
- }
-
- if w.document.ObjectTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.ObjectTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.ObjectTypeDefinitions[ref].HasFieldDefinitions {
- for _, i := range w.document.ObjectTypeDefinitions[ref].FieldsDefinition.Refs {
- w.walkFieldDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindObjectTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveObjectTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveObjectTypeDefinition, ref, w.visitors.leaveObjectTypeDefinition[i]) {
- w.visitors.leaveObjectTypeDefinition[i].LeaveObjectTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkObjectTypeExtension(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindObjectTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.enterObjectTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(EnterObjectTypeExtension, ref, w.visitors.enterObjectTypeExtension[i]) {
- w.visitors.enterObjectTypeExtension[i].EnterObjectTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindObjectTypeExtension)
- if w.stop {
- return
- }
-
- if w.document.ObjectTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.ObjectTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.ObjectTypeExtensions[ref].HasFieldDefinitions {
- for _, i := range w.document.ObjectTypeExtensions[ref].FieldsDefinition.Refs {
- w.walkFieldDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindObjectTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.leaveObjectTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveObjectTypeExtension, ref, w.visitors.leaveObjectTypeExtension[i]) {
- w.visitors.leaveObjectTypeExtension[i].LeaveObjectTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkFieldDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindFieldDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterFieldDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterFieldDefinition, ref, w.visitors.enterFieldDefinition[i]) {
- w.visitors.enterFieldDefinition[i].EnterFieldDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindFieldDefinition)
- if w.stop {
- return
- }
-
- if w.document.FieldDefinitions[ref].HasArgumentsDefinitions {
- for _, i := range w.document.FieldDefinitions[ref].ArgumentsDefinition.Refs {
- w.walkInputValueDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.FieldDefinitions[ref].HasDirectives {
- for _, i := range w.document.FieldDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindFieldDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveFieldDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveFieldDefinition, ref, w.visitors.leaveFieldDefinition[i]) {
- w.visitors.leaveFieldDefinition[i].LeaveFieldDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkInputValueDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindInputValueDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterInputValueDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterInputValueDefinition, ref, w.visitors.enterInputValueDefinition[i]) {
- w.visitors.enterInputValueDefinition[i].EnterInputValueDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindInputValueDefinition)
- if w.stop {
- return
- }
-
- if w.document.InputValueDefinitions[ref].HasDirectives {
- for _, i := range w.document.InputValueDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindInputValueDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveInputValueDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveInputValueDefinition, ref, w.visitors.leaveInputValueDefinition[i]) {
- w.visitors.leaveInputValueDefinition[i].LeaveInputValueDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkInterfaceTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindInterfaceTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterInterfaceTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterInterfaceTypeDefinition, ref, w.visitors.enterInterfaceTypeDefinition[i]) {
- w.visitors.enterInterfaceTypeDefinition[i].EnterInterfaceTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindInterfaceTypeDefinition)
- if w.stop {
- return
- }
-
- if w.document.InterfaceTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.InterfaceTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.InterfaceTypeDefinitions[ref].HasFieldDefinitions {
- for _, i := range w.document.InterfaceTypeDefinitions[ref].FieldsDefinition.Refs {
- w.walkFieldDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindInterfaceTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveInterfaceTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveInterfaceTypeDefinition, ref, w.visitors.leaveInterfaceTypeDefinition[i]) {
- w.visitors.leaveInterfaceTypeDefinition[i].LeaveInterfaceTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkInterfaceTypeExtension(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindInterfaceTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.enterInterfaceTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(EnterInterfaceTypeExtension, ref, w.visitors.enterInterfaceTypeExtension[i]) {
- w.visitors.enterInterfaceTypeExtension[i].EnterInterfaceTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindInterfaceTypeExtension)
- if w.stop {
- return
- }
-
- if w.document.InterfaceTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.InterfaceTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.InterfaceTypeExtensions[ref].HasFieldDefinitions {
- for _, i := range w.document.InterfaceTypeExtensions[ref].FieldsDefinition.Refs {
- w.walkFieldDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindInterfaceTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.leaveInterfaceTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveInterfaceTypeExtension, ref, w.visitors.leaveInterfaceTypeExtension[i]) {
- w.visitors.leaveInterfaceTypeExtension[i].LeaveInterfaceTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkScalarTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindScalarTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterScalarTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterScalarTypeDefinition, ref, w.visitors.enterScalarTypeDefinition[i]) {
- w.visitors.enterScalarTypeDefinition[i].EnterScalarTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindScalarTypeDefinition)
- if w.stop {
- return
- }
-
- if w.document.ScalarTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.ScalarTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindScalarTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveScalarTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveScalarTypeDefinition, ref, w.visitors.leaveScalarTypeDefinition[i]) {
- w.visitors.leaveScalarTypeDefinition[i].LeaveScalarTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkScalarTypeExtension(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindScalarTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.enterScalarTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(EnterScalarTypeExtension, ref, w.visitors.enterScalarTypeExtension[i]) {
- w.visitors.enterScalarTypeExtension[i].EnterScalarTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindScalarTypeExtension)
- if w.stop {
- return
- }
-
- if w.document.ScalarTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.ScalarTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindScalarTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.leaveScalarTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveScalarTypeExtension, ref, w.visitors.leaveScalarTypeExtension[i]) {
- w.visitors.leaveScalarTypeExtension[i].LeaveScalarTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkUnionTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindUnionTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterUnionTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterUnionTypeDefinition, ref, w.visitors.enterUnionTypeDefinition[i]) {
- w.visitors.enterUnionTypeDefinition[i].EnterUnionTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindUnionTypeDefinition)
- if w.stop {
- return
- }
-
- if w.document.UnionTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.UnionTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.UnionTypeDefinitions[ref].HasUnionMemberTypes {
- for _, i := range w.document.UnionTypeDefinitions[ref].UnionMemberTypes.Refs {
- w.walkUnionMemberType(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindUnionTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveUnionTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveUnionTypeDefinition, ref, w.visitors.leaveUnionTypeDefinition[i]) {
- w.visitors.leaveUnionTypeDefinition[i].LeaveUnionTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkUnionTypeExtension(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindUnionTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.enterUnionTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(EnterUnionTypeExtension, ref, w.visitors.enterUnionTypeExtension[i]) {
- w.visitors.enterUnionTypeExtension[i].EnterUnionTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindUnionTypeExtension)
- if w.stop {
- return
- }
-
- if w.document.UnionTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.UnionTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.UnionTypeExtensions[ref].HasUnionMemberTypes {
- for _, i := range w.document.UnionTypeExtensions[ref].UnionMemberTypes.Refs {
- w.walkUnionMemberType(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindUnionTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.leaveUnionTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveUnionTypeExtension, ref, w.visitors.leaveUnionTypeExtension[i]) {
- w.visitors.leaveUnionTypeExtension[i].LeaveUnionTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkUnionMemberType(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindUnionMemberType, ref)
-
- for i := 0; i < len(w.visitors.enterUnionMemberType); {
- if w.filter == nil || w.filter.AllowVisitor(EnterUnionMemberType, ref, w.visitors.enterUnionMemberType[i]) {
- w.visitors.enterUnionMemberType[i].EnterUnionMemberType(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- for i := 0; i < len(w.visitors.leaveUnionMemberType); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveUnionMemberType, ref, w.visitors.leaveUnionMemberType[i]) {
- w.visitors.leaveUnionMemberType[i].LeaveUnionMemberType(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkEnumTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindEnumTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterEnumTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterEnumTypeDefinition, ref, w.visitors.enterEnumTypeDefinition[i]) {
- w.visitors.enterEnumTypeDefinition[i].EnterEnumTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindEnumTypeDefinition)
- if w.stop {
- return
- }
-
- if w.document.EnumTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.EnumTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.EnumTypeDefinitions[ref].HasEnumValuesDefinition {
- for _, i := range w.document.EnumTypeDefinitions[ref].EnumValuesDefinition.Refs {
- w.walkEnumValueDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindEnumTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveEnumTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveEnumTypeDefinition, ref, w.visitors.leaveEnumTypeDefinition[i]) {
- w.visitors.leaveEnumTypeDefinition[i].LeaveEnumTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkEnumTypeExtension(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindEnumTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.enterEnumTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(EnterEnumTypeExtension, ref, w.visitors.enterEnumTypeExtension[i]) {
- w.visitors.enterEnumTypeExtension[i].EnterEnumTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindEnumTypeExtension)
- if w.stop {
- return
- }
-
- if w.document.EnumTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.EnumTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.EnumTypeExtensions[ref].HasEnumValuesDefinition {
- for _, i := range w.document.EnumTypeExtensions[ref].EnumValuesDefinition.Refs {
- w.walkEnumValueDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindEnumTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.leaveEnumTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveEnumTypeExtension, ref, w.visitors.leaveEnumTypeExtension[i]) {
- w.visitors.leaveEnumTypeExtension[i].LeaveEnumTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkEnumValueDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindEnumValueDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterEnumValueDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterEnumValueDefinition, ref, w.visitors.enterEnumValueDefinition[i]) {
- w.visitors.enterEnumValueDefinition[i].EnterEnumValueDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindEnumValueDefinition)
- if w.stop {
- return
- }
-
- if w.document.EnumValueDefinitions[ref].HasDirectives {
- for _, i := range w.document.EnumValueDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindEnumValueDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveEnumValueDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveEnumValueDefinition, ref, w.visitors.leaveEnumValueDefinition[i]) {
- w.visitors.leaveEnumValueDefinition[i].LeaveEnumValueDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkInputObjectTypeDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindInputObjectTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterInputObjectTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterInputObjectTypeDefinition, ref, w.visitors.enterInputObjectTypeDefinition[i]) {
- w.visitors.enterInputObjectTypeDefinition[i].EnterInputObjectTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindInputObjectTypeDefinition)
- if w.stop {
- return
- }
-
- if w.document.InputObjectTypeDefinitions[ref].HasDirectives {
- for _, i := range w.document.InputObjectTypeDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition {
- for _, i := range w.document.InputObjectTypeDefinitions[ref].InputFieldsDefinition.Refs {
- w.walkInputValueDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindInputObjectTypeDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveInputObjectTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveInputObjectTypeDefinition, ref, w.visitors.leaveInputObjectTypeDefinition[i]) {
- w.visitors.leaveInputObjectTypeDefinition[i].LeaveInputObjectTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkInputObjectTypeExtension(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindInputObjectTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.enterInputObjectTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(EnterInputObjectTypeExtension, ref, w.visitors.enterInputObjectTypeExtension[i]) {
- w.visitors.enterInputObjectTypeExtension[i].EnterInputObjectTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindInputObjectTypeExtension)
- if w.stop {
- return
- }
-
- if w.document.InputObjectTypeExtensions[ref].HasDirectives {
- for _, i := range w.document.InputObjectTypeExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- if w.document.InputObjectTypeExtensions[ref].HasInputFieldsDefinition {
- for _, i := range w.document.InputObjectTypeExtensions[ref].InputFieldsDefinition.Refs {
- w.walkInputValueDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindInputObjectTypeExtension, ref)
-
- for i := 0; i < len(w.visitors.leaveInputObjectTypeExtension); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveInputObjectTypeExtension, ref, w.visitors.leaveInputObjectTypeExtension[i]) {
- w.visitors.leaveInputObjectTypeExtension[i].LeaveInputObjectTypeExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkDirectiveDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindDirectiveDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterDirectiveDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterDirectiveDefinition, ref, w.visitors.enterDirectiveDefinition[i]) {
- w.visitors.enterDirectiveDefinition[i].EnterDirectiveDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindDirectiveDefinition)
- if w.stop {
- return
- }
-
- if w.document.DirectiveDefinitions[ref].HasArgumentsDefinitions {
- for _, i := range w.document.DirectiveDefinitions[ref].ArgumentsDefinition.Refs {
- w.walkInputValueDefinition(i)
- if w.stop {
- return
- }
- }
- }
-
- iter := w.document.DirectiveDefinitions[ref].DirectiveLocations.Iterable()
- for iter.Next() {
- w.walkDirectiveLocation(iter.Value())
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindDirectiveDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveDirectiveDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveDirectiveDefinition, ref, w.visitors.leaveDirectiveDefinition[i]) {
- w.visitors.leaveDirectiveDefinition[i].LeaveDirectiveDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkDirectiveLocation(location ast.DirectiveLocation) {
- w.increaseDepth()
-
- for i := 0; i < len(w.visitors.enterDirectiveLocation); {
- if w.filter == nil || w.filter.AllowVisitor(EnterDirectiveLocation, 0, w.visitors.enterDirectiveLocation[i]) {
- w.visitors.enterDirectiveLocation[i].EnterDirectiveLocation(location)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- for i := 0; i < len(w.visitors.leaveDirectiveLocation); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveDirectiveLocation, 0, w.visitors.leaveDirectiveLocation[i]) {
- w.visitors.leaveDirectiveLocation[i].LeaveDirectiveLocation(location)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkSchemaDefinition(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindSchemaDefinition, ref)
-
- for i := 0; i < len(w.visitors.enterSchemaDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterSchemaDefinition, ref, w.visitors.enterSchemaDefinition[i]) {
- w.visitors.enterSchemaDefinition[i].EnterSchemaDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindSchemaDefinition)
- if w.stop {
- return
- }
-
- if w.document.SchemaDefinitions[ref].HasDirectives {
- for _, i := range w.document.SchemaDefinitions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- for _, i := range w.document.SchemaDefinitions[ref].RootOperationTypeDefinitions.Refs {
- w.walkRootOperationTypeDefinition(i)
- if w.stop {
- return
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindSchemaDefinition, ref)
-
- for i := 0; i < len(w.visitors.leaveSchemaDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveSchemaDefinition, ref, w.visitors.leaveSchemaDefinition[i]) {
- w.visitors.leaveSchemaDefinition[i].LeaveSchemaDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkSchemaExtension(ref int) {
- w.increaseDepth()
-
- w.setCurrent(ast.NodeKindSchemaExtension, ref)
-
- for i := 0; i < len(w.visitors.enterSchemaExtension); {
- if w.filter == nil || w.filter.AllowVisitor(EnterSchemaExtension, ref, w.visitors.enterSchemaExtension[i]) {
- w.visitors.enterSchemaExtension[i].EnterSchemaExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.appendAncestor(ref, ast.NodeKindSchemaExtension)
- if w.stop {
- return
- }
-
- if w.document.SchemaExtensions[ref].HasDirectives {
- for _, i := range w.document.SchemaExtensions[ref].Directives.Refs {
- w.walkDirective(i)
- if w.stop {
- return
- }
- }
- }
-
- for _, i := range w.document.SchemaExtensions[ref].RootOperationTypeDefinitions.Refs {
- w.walkRootOperationTypeDefinition(i)
- if w.stop {
- return
- }
- }
-
- w.removeLastAncestor()
-
- w.setCurrent(ast.NodeKindSchemaExtension, ref)
-
- for i := 0; i < len(w.visitors.leaveSchemaExtension); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveSchemaExtension, ref, w.visitors.leaveSchemaExtension[i]) {
- w.visitors.leaveSchemaExtension[i].LeaveSchemaExtension(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) walkRootOperationTypeDefinition(ref int) {
- w.increaseDepth()
-
- for i := 0; i < len(w.visitors.enterRootOperationTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(EnterRootOperationTypeDefinition, ref, w.visitors.enterRootOperationTypeDefinition[i]) {
- w.visitors.enterRootOperationTypeDefinition[i].EnterRootOperationTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- for i := 0; i < len(w.visitors.leaveRootOperationTypeDefinition); {
- if w.filter == nil || w.filter.AllowVisitor(LeaveRootOperationTypeDefinition, ref, w.visitors.leaveRootOperationTypeDefinition[i]) {
- w.visitors.leaveRootOperationTypeDefinition[i].LeaveRootOperationTypeDefinition(ref)
- }
- if w.revisit {
- w.revisit = false
- continue
- }
- if w.stop {
- return
- }
- if w.skip {
- w.skip = false
- w.decreaseDepth()
- return
- }
- i++
- }
-
- w.decreaseDepth()
-}
-
-func (w *Walker) refsEqual(left, right []int) bool {
- if len(left) != len(right) {
- return false
- }
- for i := range left {
- if left[i] != right[i] {
- return false
- }
- }
- return true
-}
-
-func (w *Walker) SkipNode() {
- w.skip = true
-}
-
-func (w *Walker) Stop() {
- w.stop = true
-}
-
-func (w *Walker) RevisitNode() {
- w.revisit = true
-}
-
-func (w *Walker) StopWithInternalErr(err error) {
- w.stop = true
- w.Report.AddInternalError(err)
-}
-
-func (w *Walker) HandleInternalErr(err error) bool {
- if err != nil {
- w.StopWithInternalErr(err)
- return true
- }
- return false
-}
-
-func (w *Walker) StopWithExternalErr(err operationreport.ExternalError) {
- w.stop = true
- err.Path = w.Path
- w.Report.AddExternalError(err)
-}
-
-func (w *Walker) StopWithErr(internal error, external operationreport.ExternalError) {
- w.stop = true
- external.Path = w.Path
- w.Report.AddInternalError(internal)
- w.Report.AddExternalError(external)
-}
-
-func (w *Walker) ArgumentInputValueDefinition(argument int) (definition int, exits bool) {
- argumentName := w.document.ArgumentNameBytes(argument)
- ancestor := w.Ancestors[len(w.Ancestors)-1]
- switch ancestor.Kind {
- case ast.NodeKindField:
- fieldName := w.document.FieldNameBytes(ancestor.Ref)
- fieldTypeDef := w.typeDefinitions[len(w.typeDefinitions)-2]
- definition = w.definition.NodeFieldDefinitionArgumentDefinitionByName(fieldTypeDef, fieldName, argumentName)
- exits = definition != -1
- case ast.NodeKindDirective:
- directiveName := w.document.DirectiveNameBytes(ancestor.Ref)
- definition = w.definition.DirectiveArgumentInputValueDefinition(directiveName, argumentName)
- exits = definition != -1
- }
- return
-}
-
-func (w *Walker) FieldDefinition(field int) (definition int, exists bool) {
- definition, _ = w.definition.NodeFieldDefinitionByName(w.EnclosingTypeDefinition, w.document.FieldNameBytes(field))
- exists = definition != -1
- return
-}
-
-func (w *Walker) AncestorNameBytes() ast.ByteSlice {
- if len(w.Ancestors) == 0 {
- return nil
- }
- return w.document.NodeNameBytes(w.Ancestors[len(w.Ancestors)-1])
-}
-
-func (w *Walker) FieldDefinitionDirectiveArgumentValueByName(field int, directiveName, argumentName ast.ByteSlice) (ast.Value, bool) {
- definition, exists := w.FieldDefinition(field)
- if !exists {
- return ast.Value{}, false
- }
-
- directive, exists := w.definition.FieldDefinitionDirectiveByName(definition, directiveName)
- if !exists {
- return ast.Value{}, false
- }
-
- return w.definition.DirectiveArgumentValueByName(directive, argumentName)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/graphql_datasource/graphql_datasource.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
deleted file mode 100644
index e3478f560c9..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
+++ /dev/null
@@ -1,689 +0,0 @@
-package graphql_datasource
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "net/http"
- "strconv"
- "strings"
-
- "github.com/buger/jsonparser"
- "github.com/tidwall/sjson"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astnormalization"
- "github.com/jensneuse/graphql-go-tools/pkg/astparser"
- "github.com/jensneuse/graphql-go-tools/pkg/astprinter"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/plan"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/federation"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
- "github.com/jensneuse/graphql-go-tools/pkg/pool"
-)
-
-const (
- UniqueIdentifier = "graphql"
-)
-
-type Planner struct {
- visitor *plan.Visitor
- config Configuration
- id string
- upstreamOperation *ast.Document
- upstreamVariables []byte
- nodes []ast.Node
- variables resolve.Variables
- lastFieldEnclosingTypeName string
- disallowSingleFlight bool
- hasFederationRoot bool
- extractEntities bool
- client httpclient.Client
- isNested bool
-}
-
-type Configuration struct {
- Fetch FetchConfiguration
- Subscription SubscriptionConfiguration
- Federation FederationConfiguration
-}
-
-func ConfigJson(config Configuration) json.RawMessage {
- out, _ := json.Marshal(config)
- return out
-}
-
-type FederationConfiguration struct {
- Enabled bool
- ServiceSDL string
-}
-
-type SubscriptionConfiguration struct {
- URL string
-}
-
-type FetchConfiguration struct {
- URL string
- Method string
- Header http.Header
-}
-
-func (c *Configuration) ApplyDefaults() {
- if c.Fetch.Method == "" {
- c.Fetch.Method = "POST"
- }
-}
-
-func (p *Planner) Register(visitor *plan.Visitor, config json.RawMessage, isNested bool) error {
- p.visitor = visitor
- p.visitor.Walker.RegisterDocumentVisitor(p)
- p.visitor.Walker.RegisterFieldVisitor(p)
- p.visitor.Walker.RegisterOperationDefinitionVisitor(p)
- p.visitor.Walker.RegisterSelectionSetVisitor(p)
- p.visitor.Walker.RegisterEnterArgumentVisitor(p)
-
- err := json.Unmarshal(config, &p.config)
- if err != nil {
- return err
- }
-
- p.config.ApplyDefaults()
- p.isNested = isNested
-
- return nil
-}
-
-func (p *Planner) ConfigureFetch() plan.FetchConfiguration {
-
- var input []byte
- if p.extractEntities {
- input, _ = sjson.SetRawBytes(input, "extract_entities", []byte("true"))
- }
- input = httpclient.SetInputBodyWithPath(input, p.upstreamVariables, "variables")
- input = httpclient.SetInputBodyWithPath(input, p.printOperation(), "query")
-
- header, err := json.Marshal(p.config.Fetch.Header)
- if err == nil && len(header) != 0 && !bytes.Equal(header, literal.NULL) {
- input = httpclient.SetInputHeader(input, header)
- }
-
- input = httpclient.SetInputURL(input, []byte(p.config.Fetch.URL))
- input = httpclient.SetInputMethod(input, []byte(p.config.Fetch.Method))
-
- return plan.FetchConfiguration{
- Input: string(input),
- DataSource: &Source{
- client: p.client,
- },
- Variables: p.variables,
- DisallowSingleFlight: p.disallowSingleFlight,
- }
-}
-
-func (p *Planner) ConfigureSubscription() plan.SubscriptionConfiguration {
-
- input := httpclient.SetInputBodyWithPath(nil, p.upstreamVariables, "variables")
- input = httpclient.SetInputBodyWithPath(input, p.printOperation(), "query")
- input = httpclient.SetInputURL(input, []byte(p.config.Subscription.URL))
-
- header, err := json.Marshal(p.config.Fetch.Header)
- if err == nil && len(header) != 0 && !bytes.Equal(header, literal.NULL) {
- input = httpclient.SetInputHeader(input, header)
- }
-
- return plan.SubscriptionConfiguration{
- Input: string(input),
- SubscriptionManagerID: "graphql_websocket_subscription",
- }
-}
-
-func (p *Planner) EnterOperationDefinition(ref int) {
- operationType := p.visitor.Operation.OperationDefinitions[ref].OperationType
- if p.isNested {
- operationType = ast.OperationTypeQuery
- }
- definition := p.upstreamOperation.AddOperationDefinitionToRootNodes(ast.OperationDefinition{
- OperationType: operationType,
- })
- p.disallowSingleFlight = operationType == ast.OperationTypeMutation
- p.nodes = append(p.nodes, definition)
-}
-
-func (p *Planner) LeaveOperationDefinition(ref int) {
- p.nodes = p.nodes[:len(p.nodes)-1]
-}
-
-func (p *Planner) EnterSelectionSet(ref int) {
- parent := p.nodes[len(p.nodes)-1]
- set := p.upstreamOperation.AddSelectionSet()
- switch parent.Kind {
- case ast.NodeKindOperationDefinition:
- p.upstreamOperation.OperationDefinitions[parent.Ref].HasSelections = true
- p.upstreamOperation.OperationDefinitions[parent.Ref].SelectionSet = set.Ref
- case ast.NodeKindField:
- p.upstreamOperation.Fields[parent.Ref].HasSelections = true
- p.upstreamOperation.Fields[parent.Ref].SelectionSet = set.Ref
- case ast.NodeKindInlineFragment:
- p.upstreamOperation.InlineFragments[parent.Ref].HasSelections = true
- p.upstreamOperation.InlineFragments[parent.Ref].SelectionSet = set.Ref
- }
- p.nodes = append(p.nodes, set)
-}
-
-func (p *Planner) LeaveSelectionSet(ref int) {
- p.nodes = p.nodes[:len(p.nodes)-1]
-}
-
-func (p *Planner) EnterField(ref int) {
-
- p.lastFieldEnclosingTypeName = p.visitor.Walker.EnclosingTypeDefinition.NameString(p.visitor.Definition)
-
- p.handleFederation(ref)
-
- p.addField(ref)
-
- // fmt.Printf("Planner::%s::%s::EnterField::%s::%d\n", p.id, p.visitor.Walker.Path.DotDelimitedString(), p.visitor.Operation.FieldNameString(ref), ref)
-
- upstreamFieldRef := p.nodes[len(p.nodes)-1].Ref
- typeName := p.lastFieldEnclosingTypeName
- fieldName := p.visitor.Operation.FieldNameString(ref)
- fieldConfiguration := p.visitor.Config.Fields.ForTypeField(typeName, fieldName)
- if fieldConfiguration == nil {
- return
- }
- for i := range fieldConfiguration.Arguments {
- argumentConfiguration := fieldConfiguration.Arguments[i]
- p.configureArgument(upstreamFieldRef, ref, *fieldConfiguration, argumentConfiguration)
- }
-}
-
-func (p *Planner) LeaveField(ref int) {
- // fmt.Printf("Planner::%s::%s::LeaveField::%s::%d\n", p.id, p.visitor.Walker.Path.DotDelimitedString(), p.visitor.Operation.FieldNameString(ref), ref)
- p.nodes = p.nodes[:len(p.nodes)-1]
-}
-
-func (p *Planner) EnterArgument(ref int) {
-
-}
-
-func (p *Planner) EnterDocument(operation, definition *ast.Document) {
- if p.upstreamOperation == nil {
- p.upstreamOperation = ast.NewDocument()
- } else {
- p.upstreamOperation.Reset()
- }
- p.nodes = p.nodes[:0]
- p.upstreamVariables = nil
- p.variables = p.variables[:0]
- p.disallowSingleFlight = false
- p.hasFederationRoot = false
- p.extractEntities = false
-}
-
-func (p *Planner) LeaveDocument(operation, definition *ast.Document) {
-
-}
-
-func (p *Planner) handleFederation(fieldRef int) {
- if !p.config.Federation.Enabled || // federation must be enabled
- p.hasFederationRoot || // should not already have federation root field
- !p.isNestedRequest() { // must be nested, otherwise it's a regular query
- return
- }
- p.hasFederationRoot = true
- // query($representations: [_Any!]!){_entities(representations: $representations){... on Product
- p.addRepresentationsVariableDefinition() // $representations: [_Any!]!
- p.addEntitiesSelectionSet() // {_entities(representations: $representations)
- p.addOneTypeInlineFragment() // ... on Product
- p.addRepresentationsVariable() // "variables\":{\"representations\":[{\"upc\":\"$$0$$\",\"__typename\":\"Product\"}]}}
-}
-
-func (p *Planner) addRepresentationsVariable() {
- // "variables\":{\"representations\":[{\"upc\":\"$$0$$\",\"__typename\":\"Product\"}]}}
- parser := astparser.NewParser()
- doc := ast.NewDocument()
- doc.Input.ResetInputString(p.config.Federation.ServiceSDL)
- report := &operationreport.Report{}
- parser.Parse(doc, report)
- if report.HasErrors() {
- p.visitor.Walker.StopWithInternalErr(fmt.Errorf("GraphQL Planner: failed parsing Federation SDL"))
- return
- }
- directive := -1
- for i := range doc.ObjectTypeExtensions {
- if p.lastFieldEnclosingTypeName == doc.ObjectTypeExtensionNameString(i) {
- for _, j := range doc.ObjectTypeExtensions[i].Directives.Refs {
- if doc.DirectiveNameString(j) == "key" {
- directive = j
- break
- }
- }
- break
- }
- }
- for i := range doc.ObjectTypeDefinitions {
- if p.lastFieldEnclosingTypeName == doc.ObjectTypeDefinitionNameString(i) {
- for _, j := range doc.ObjectTypeDefinitions[i].Directives.Refs {
- if doc.DirectiveNameString(j) == "key" {
- directive = j
- break
- }
- }
- break
- }
- }
- if directive == -1 {
- return
- }
- value, exists := doc.DirectiveArgumentValueByName(directive, []byte("fields"))
- if !exists {
- return
- }
- if value.Kind != ast.ValueKindString {
- return
- }
- fieldsStr := doc.StringValueContentString(value.Ref)
- fields := strings.Split(fieldsStr, " ")
- representationsJson, _ := sjson.SetRawBytes(nil, "__typename", []byte("\""+p.lastFieldEnclosingTypeName+"\""))
- for i := range fields {
- variable, exists := p.variables.AddVariable(&resolve.ObjectVariable{
- Path: []string{fields[i]},
- }, true)
- if exists {
- continue
- }
- representationsJson, _ = sjson.SetRawBytes(representationsJson, fields[i], []byte(variable))
- }
- representationsJson = append([]byte("["), append(representationsJson, []byte("]")...)...)
- p.upstreamVariables, _ = sjson.SetRawBytes(p.upstreamVariables, "representations", representationsJson)
- p.extractEntities = true
-}
-
-func (p *Planner) addOneTypeInlineFragment() {
- selectionSet := p.upstreamOperation.AddSelectionSet()
- typeRef := p.upstreamOperation.AddNamedType([]byte(p.lastFieldEnclosingTypeName))
- inlineFragment := p.upstreamOperation.AddInlineFragment(ast.InlineFragment{
- HasSelections: true,
- SelectionSet: selectionSet.Ref,
- TypeCondition: ast.TypeCondition{
- Type: typeRef,
- },
- })
- p.upstreamOperation.AddSelection(p.nodes[len(p.nodes)-1].Ref, ast.Selection{
- Kind: ast.SelectionKindInlineFragment,
- Ref: inlineFragment,
- })
- p.nodes = append(p.nodes, selectionSet)
-}
-
-func (p *Planner) addEntitiesSelectionSet() {
-
- // $representations
- representationsLiteral := p.upstreamOperation.Input.AppendInputString("representations")
- representationsVariable := p.upstreamOperation.AddVariableValue(ast.VariableValue{
- Name: representationsLiteral,
- })
- representationsArgument := p.upstreamOperation.AddArgument(ast.Argument{
- Name: representationsLiteral,
- Value: ast.Value{
- Kind: ast.ValueKindVariable,
- Ref: representationsVariable,
- },
- })
-
- // _entities
- entitiesSelectionSet := p.upstreamOperation.AddSelectionSet()
- entitiesField := p.upstreamOperation.AddField(ast.Field{
- Name: p.upstreamOperation.Input.AppendInputString("_entities"),
- HasSelections: true,
- HasArguments: true,
- Arguments: ast.ArgumentList{
- Refs: []int{representationsArgument},
- },
- SelectionSet: entitiesSelectionSet.Ref,
- })
- p.upstreamOperation.AddSelection(p.nodes[len(p.nodes)-1].Ref, ast.Selection{
- Kind: ast.SelectionKindField,
- Ref: entitiesField.Ref,
- })
- p.nodes = append(p.nodes, entitiesField, entitiesSelectionSet)
-}
-
-func (p *Planner) addRepresentationsVariableDefinition() {
- anyType := p.upstreamOperation.AddNamedType([]byte("_Any"))
- nonNullAnyType := p.upstreamOperation.AddType(ast.Type{
- TypeKind: ast.TypeKindNonNull,
- OfType: anyType,
- })
- listOfNonNullAnyType := p.upstreamOperation.AddType(ast.Type{
- TypeKind: ast.TypeKindList,
- OfType: nonNullAnyType,
- })
- nonNullListOfNonNullAnyType := p.upstreamOperation.AddType(ast.Type{
- TypeKind: ast.TypeKindNonNull,
- OfType: listOfNonNullAnyType,
- })
- representationsVariable := p.upstreamOperation.AddVariableValue(ast.VariableValue{
- Name: p.upstreamOperation.Input.AppendInputBytes([]byte("representations")),
- })
- p.upstreamOperation.AddVariableDefinitionToOperationDefinition(p.nodes[0].Ref, representationsVariable, nonNullListOfNonNullAnyType)
-}
-
-func (p *Planner) isNestedRequest() bool {
- for i := range p.nodes {
- if p.nodes[i].Kind == ast.NodeKindField {
- return false
- }
- }
- selectionSetAncestors := 0
- for i := range p.visitor.Walker.Ancestors {
- if p.visitor.Walker.Ancestors[i].Kind == ast.NodeKindSelectionSet {
- selectionSetAncestors++
- if selectionSetAncestors == 2 {
- return true
- }
- }
- }
- return false
-}
-
-func (p *Planner) configureArgument(upstreamFieldRef, downstreamFieldRef int, fieldConfig plan.FieldConfiguration, argumentConfiguration plan.ArgumentConfiguration) {
- switch argumentConfiguration.SourceType {
- case plan.FieldArgumentSource:
- p.configureFieldArgumentSource(upstreamFieldRef, downstreamFieldRef, argumentConfiguration.Name, argumentConfiguration.SourcePath)
- case plan.ObjectFieldSource:
- p.configureObjectFieldSource(upstreamFieldRef, downstreamFieldRef, fieldConfig, argumentConfiguration)
- }
-}
-
-func (p *Planner) configureFieldArgumentSource(upstreamFieldRef, downstreamFieldRef int, argumentName string, sourcePath []string) {
- fieldArgument, ok := p.visitor.Operation.FieldArgument(downstreamFieldRef, []byte(argumentName))
- if !ok {
- return
- }
- value := p.visitor.Operation.ArgumentValue(fieldArgument)
- if value.Kind != ast.ValueKindVariable {
- p.applyInlineFieldArgument(upstreamFieldRef, downstreamFieldRef, argumentName, sourcePath)
- return
- }
- variableName := p.visitor.Operation.VariableValueNameBytes(value.Ref)
- variableNameStr := p.visitor.Operation.VariableValueNameString(value.Ref)
-
- variableDefinition, ok := p.visitor.Operation.VariableDefinitionByNameAndOperation(p.visitor.Walker.Ancestors[0].Ref, variableName)
- if !ok {
- return
- }
-
- variableDefinitionType := p.visitor.Operation.VariableDefinitions[variableDefinition].Type
- wrapValueInQuotes := p.visitor.Operation.TypeValueNeedsQuotes(variableDefinitionType, p.visitor.Definition)
-
- contextVariableName, exists := p.variables.AddVariable(&resolve.ContextVariable{Path: []string{variableNameStr}}, wrapValueInQuotes)
- variableValueRef, argRef := p.upstreamOperation.AddVariableValueArgument([]byte(argumentName), variableName) // add the argument to the field, but don't redefine it
- p.upstreamOperation.AddArgumentToField(upstreamFieldRef, argRef)
-
- if exists { // if the variable exists we don't have to put it onto the variables declaration again, skip
- return
- }
-
- for _, i := range p.visitor.Operation.OperationDefinitions[p.visitor.Walker.Ancestors[0].Ref].VariableDefinitions.Refs {
- ref := p.visitor.Operation.VariableDefinitions[i].VariableValue.Ref
- if !p.visitor.Operation.VariableValueNameBytes(ref).Equals(variableName) {
- continue
- }
- importedType := p.visitor.Importer.ImportType(p.visitor.Operation.VariableDefinitions[i].Type, p.visitor.Operation, p.upstreamOperation)
- p.upstreamOperation.AddVariableDefinitionToOperationDefinition(p.nodes[0].Ref, variableValueRef, importedType)
- }
-
- p.upstreamVariables, _ = sjson.SetRawBytes(p.upstreamVariables, variableNameStr, []byte(contextVariableName))
-}
-
-func (p *Planner) applyInlineFieldArgument(upstreamField, downstreamField int, argumentName string, sourcePath []string) {
- fieldArgument, ok := p.visitor.Operation.FieldArgument(downstreamField, []byte(argumentName))
- if !ok {
- return
- }
- value := p.visitor.Operation.ArgumentValue(fieldArgument)
- importedValue := p.visitor.Importer.ImportValue(value, p.visitor.Operation, p.upstreamOperation)
- argRef := p.upstreamOperation.AddArgument(ast.Argument{
- Name: p.upstreamOperation.Input.AppendInputString(argumentName),
- Value: importedValue,
- })
- p.upstreamOperation.AddArgumentToField(upstreamField, argRef)
- p.addVariableDefinitionsRecursively(value, argumentName, sourcePath)
-}
-
-func (p *Planner) addVariableDefinitionsRecursively(value ast.Value, argumentName string, sourcePath []string) {
- switch value.Kind {
- case ast.ValueKindObject:
- for _, i := range p.visitor.Operation.ObjectValues[value.Ref].Refs {
- p.addVariableDefinitionsRecursively(p.visitor.Operation.ObjectFields[i].Value, argumentName, sourcePath)
- }
- return
- case ast.ValueKindList:
- for _, i := range p.visitor.Operation.ListValues[value.Ref].Refs {
- p.addVariableDefinitionsRecursively(p.visitor.Operation.Values[i], argumentName, sourcePath)
- }
- return
- case ast.ValueKindVariable:
- // continue after switch
- default:
- return
- }
-
- variableName := p.visitor.Operation.VariableValueNameBytes(value.Ref)
- variableNameStr := p.visitor.Operation.VariableValueNameString(value.Ref)
- variableDefinition, exists := p.visitor.Operation.VariableDefinitionByNameAndOperation(p.visitor.Walker.Ancestors[0].Ref, variableName)
- if !exists {
- return
- }
- importedVariableDefinition := p.visitor.Importer.ImportVariableDefinition(variableDefinition, p.visitor.Operation, p.upstreamOperation)
- p.upstreamOperation.AddImportedVariableDefinitionToOperationDefinition(p.nodes[0].Ref, importedVariableDefinition)
-
- variableDefinitionType := p.visitor.Operation.VariableDefinitions[variableDefinition].Type
- wrapValueInQuotes := p.visitor.Operation.TypeValueNeedsQuotes(variableDefinitionType, p.visitor.Definition)
-
- contextVariableName, variableExists := p.variables.AddVariable(&resolve.ContextVariable{Path: append(sourcePath, variableNameStr)}, wrapValueInQuotes)
- if variableExists {
- return
- }
- p.upstreamVariables, _ = sjson.SetRawBytes(p.upstreamVariables, variableNameStr, []byte(contextVariableName))
-}
-
-func (p *Planner) configureObjectFieldSource(upstreamFieldRef, downstreamFieldRef int, fieldConfiguration plan.FieldConfiguration, argumentConfiguration plan.ArgumentConfiguration) {
- if len(argumentConfiguration.SourcePath) < 1 {
- return
- }
-
- fieldName := p.visitor.Operation.FieldNameString(downstreamFieldRef)
-
- if len(fieldConfiguration.Path) == 1 {
- fieldName = fieldConfiguration.Path[0]
- }
-
- queryTypeDefinition, exists := p.visitor.Definition.Index.FirstNodeByNameBytes(p.visitor.Definition.Index.QueryTypeName)
- if !exists {
- return
- }
- argumentDefinition := p.visitor.Definition.NodeFieldDefinitionArgumentDefinitionByName(queryTypeDefinition, []byte(fieldName), []byte(argumentConfiguration.Name))
- if argumentDefinition == -1 {
- return
- }
-
- argumentType := p.visitor.Definition.InputValueDefinitionType(argumentDefinition)
- variableName := p.upstreamOperation.GenerateUnusedVariableDefinitionName(p.nodes[0].Ref)
- variableValue, argument := p.upstreamOperation.AddVariableValueArgument([]byte(argumentConfiguration.Name), variableName)
- p.upstreamOperation.AddArgumentToField(upstreamFieldRef, argument)
- importedType := p.visitor.Importer.ImportType(argumentType, p.visitor.Definition, p.upstreamOperation)
- p.upstreamOperation.AddVariableDefinitionToOperationDefinition(p.nodes[0].Ref, variableValue, importedType)
- wrapVariableInQuotes := p.visitor.Definition.TypeValueNeedsQuotes(argumentType, p.visitor.Definition)
-
- objectVariableName, exists := p.variables.AddVariable(&resolve.ObjectVariable{Path: argumentConfiguration.SourcePath}, wrapVariableInQuotes)
- if !exists {
- p.upstreamVariables, _ = sjson.SetRawBytes(p.upstreamVariables, string(variableName), []byte(objectVariableName))
- }
-}
-
-func (p *Planner) printOperation() []byte {
-
- buf := &bytes.Buffer{}
-
- err := astprinter.Print(p.upstreamOperation, nil, buf)
- if err != nil {
- return nil
- }
-
- rawQuery := buf.Bytes()
-
- baseSchema, err := astprinter.PrintString(p.visitor.Definition, nil)
- if err != nil {
- return nil
- }
-
- federationSchema, err := federation.BuildFederationSchema(baseSchema, p.config.Federation.ServiceSDL)
- if err != nil {
- p.visitor.Walker.StopWithInternalErr(err)
- return nil
- }
-
- operation := ast.NewDocument()
- definition := ast.NewDocument()
- report := &operationreport.Report{}
- parser := astparser.NewParser()
-
- definition.Input.ResetInputString(federationSchema)
- operation.Input.ResetInputBytes(rawQuery)
-
- parser.Parse(operation, report)
- if report.HasErrors() {
- p.visitor.Walker.StopWithInternalErr(fmt.Errorf("printOperation: parse operation failed"))
- return nil
- }
-
- parser.Parse(definition, report)
- if report.HasErrors() {
- p.visitor.Walker.StopWithInternalErr(fmt.Errorf("printOperation: parse definition failed"))
- return nil
- }
-
- operationStr, _ := astprinter.PrintStringIndent(operation, definition, " ")
- schemaStr, _ := astprinter.PrintStringIndent(definition, nil, " ")
- _, _ = schemaStr, operationStr
-
- normalizer := astnormalization.NewNormalizer(true, true)
- normalizer.NormalizeOperation(operation, definition, report)
-
- if report.HasErrors() {
- p.visitor.Walker.StopWithInternalErr(fmt.Errorf("normalization failed"))
- return nil
- }
-
- buf.Reset()
-
- err = astprinter.Print(operation, p.visitor.Definition, buf)
- if err != nil {
- p.visitor.Walker.StopWithInternalErr(fmt.Errorf("normalization failed"))
- return nil
- }
- return buf.Bytes()
-}
-
-func (p *Planner) addField(ref int) {
-
- fieldName := p.visitor.Operation.FieldNameString(ref)
-
- alias := ast.Alias{
- IsDefined: p.visitor.Operation.FieldAliasIsDefined(ref),
- }
-
- if alias.IsDefined {
- aliasBytes := p.visitor.Operation.FieldAliasBytes(ref)
- alias.Name = p.upstreamOperation.Input.AppendInputBytes(aliasBytes)
- }
-
- typeName := p.visitor.Walker.EnclosingTypeDefinition.NameString(p.visitor.Definition)
- for i := range p.visitor.Config.Fields {
- if p.visitor.Config.Fields[i].TypeName == typeName &&
- p.visitor.Config.Fields[i].FieldName == fieldName &&
- len(p.visitor.Config.Fields[i].Path) == 1 {
- fieldName = p.visitor.Config.Fields[i].Path[0]
- break
- }
- }
-
- field := p.upstreamOperation.AddField(ast.Field{
- Name: p.upstreamOperation.Input.AppendInputString(fieldName),
- Alias: alias,
- })
-
- selection := ast.Selection{
- Kind: ast.SelectionKindField,
- Ref: field.Ref,
- }
-
- p.upstreamOperation.AddSelection(p.nodes[len(p.nodes)-1].Ref, selection)
- p.nodes = append(p.nodes, field)
-}
-
-type Factory struct {
- id int
- Client httpclient.Client
-}
-
-func (f *Factory) Planner() plan.DataSourcePlanner {
- f.id++
- return &Planner{
- id: strconv.Itoa(f.id),
- client: f.Client,
- }
-}
-
-var (
- responsePaths = [][]string{
- {"errors"},
- {"data"},
- }
- entitiesPath = []string{"_entities", "[0]"}
- uniqueIdentifier = []byte(UniqueIdentifier)
-)
-
-type Source struct {
- client httpclient.Client
-}
-
-func (s *Source) Load(ctx context.Context, input []byte, bufPair *resolve.BufPair) (err error) {
- buf := pool.BytesBuffer.Get()
- defer pool.BytesBuffer.Put(buf)
-
- err = s.client.Do(ctx, input, buf)
- if err != nil {
- return
- }
-
- responseData := buf.Bytes()
-
- extractEntitiesRaw, _, _, _ := jsonparser.Get(input, "extract_entities")
- extractEntities := bytes.Equal(extractEntitiesRaw, literal.TRUE)
-
- jsonparser.EachKey(responseData, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) {
- switch i {
- case 0:
- bufPair.Errors.WriteBytes(bytes)
- case 1:
- if extractEntities {
- data, _, _, _ := jsonparser.Get(bytes, entitiesPath...)
- bufPair.Data.WriteBytes(data)
- return
- }
- bufPair.Data.WriteBytes(bytes)
- }
- }, responsePaths...)
-
- return
-}
-
-func (s *Source) UniqueIdentifier() []byte {
- return uniqueIdentifier
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/compatibility_1.12.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/compatibility_1.12.go
deleted file mode 100644
index 959979b1342..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/compatibility_1.12.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package httpclient
-
-import (
- "bytes"
- "context"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- urlpkg "net/url"
- "strings"
-
- "golang.org/x/net/http/httpguts"
-)
-
-/*
-This package is a copy of the NewRequestWithContext function, which was introduced with go 1.13.
-When support for go 1.12 is dropped, this file can be safely removed an the usage of `NewRequestWithContext`
-should be then changed to `http.NewRequestWithContext`.
-*/
-
-func NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*http.Request, error) {
- if method == "" {
- // We document that "" means "GET" for Request.Method, and people have
- // relied on that from NewRequest, so keep that working.
- // We still enforce validMethod for non-empty methods.
- method = "GET"
- }
- if !validMethod(method) {
- return nil, fmt.Errorf("net/http: invalid method %q", method)
- }
- if ctx == nil {
- return nil, errors.New("net/http: nil Context")
- }
- u, err := urlpkg.Parse(url)
- if err != nil {
- return nil, err
- }
- rc, ok := body.(io.ReadCloser)
- if !ok && body != nil {
- rc = ioutil.NopCloser(body)
- }
- // The host's colon:port should be normalized. See Issue 14836.
- u.Host = removeEmptyPort(u.Host)
- req := &http.Request{
- Method: method,
- URL: u,
- Proto: "HTTP/1.1",
- ProtoMajor: 1,
- ProtoMinor: 1,
- Header: make(http.Header),
- Body: rc,
- Host: u.Host,
- }
-
- req = req.WithContext(ctx)
-
- if body != nil {
- switch v := body.(type) {
- case *bytes.Buffer:
- req.ContentLength = int64(v.Len())
- buf := v.Bytes()
- req.GetBody = func() (io.ReadCloser, error) {
- r := bytes.NewReader(buf)
- return ioutil.NopCloser(r), nil
- }
- case *bytes.Reader:
- req.ContentLength = int64(v.Len())
- snapshot := *v
- req.GetBody = func() (io.ReadCloser, error) {
- r := snapshot
- return ioutil.NopCloser(&r), nil
- }
- case *strings.Reader:
- req.ContentLength = int64(v.Len())
- snapshot := *v
- req.GetBody = func() (io.ReadCloser, error) {
- r := snapshot
- return ioutil.NopCloser(&r), nil
- }
- default:
- // This is where we'd set it to -1 (at least
- // if body != NoBody) to mean unknown, but
- // that broke people during the Go 1.8 testing
- // period. People depend on it being 0 I
- // guess. Maybe retry later. See Issue 18117.
- }
- // For client requests, Request.ContentLength of 0
- // means either actually 0, or unknown. The only way
- // to explicitly say that the ContentLength is zero is
- // to set the Body to nil. But turns out too much code
- // depends on NewRequest returning a non-nil Body,
- // so we use a well-known ReadCloser variable instead
- // and have the http package also treat that sentinel
- // variable to mean explicitly zero.
- if req.GetBody != nil && req.ContentLength == 0 {
- req.Body = http.NoBody
- req.GetBody = func() (io.ReadCloser, error) { return http.NoBody, nil }
- }
- }
-
- return req, nil
-}
-
-func validMethod(method string) bool {
- /*
- Method = "OPTIONS" ; Section 9.2
- | "GET" ; Section 9.3
- | "HEAD" ; Section 9.4
- | "POST" ; Section 9.5
- | "PUT" ; Section 9.6
- | "DELETE" ; Section 9.7
- | "TRACE" ; Section 9.8
- | "CONNECT" ; Section 9.9
- | extension-method
- extension-method = token
- token = 1*
- */
- return len(method) > 0 && strings.IndexFunc(method, isNotToken) == -1
-}
-
-// removeEmptyPort strips the empty port in ":port" to ""
-// as mandated by RFC 3986 Section 6.2.3.
-func removeEmptyPort(host string) string {
- if hasPort(host) {
- return strings.TrimSuffix(host, ":")
- }
- return host
-}
-
-func isNotToken(r rune) bool {
- return !httpguts.IsTokenRune(r)
-}
-
-// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
-// return true if the string includes a port.
-func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/fasthttpclient.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/fasthttpclient.go
deleted file mode 100644
index 8f5708371b9..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/fasthttpclient.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package httpclient
-
-import (
- "bytes"
- "context"
- "io"
- "time"
-
- "github.com/buger/jsonparser"
- "github.com/jensneuse/abstractlogger"
- "github.com/valyala/fasthttp"
-
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type FastHttpClient struct {
- client *fasthttp.Client
- log abstractlogger.Logger
-}
-
-type Option func(c *FastHttpClient)
-
-func WithLogger(logger abstractlogger.Logger) Option {
- return func(c *FastHttpClient) {
- c.log = logger
- }
-}
-
-func NewFastHttpClient(client *fasthttp.Client, options ...Option) *FastHttpClient {
- c := &FastHttpClient{
- client: client,
- }
- for i := range options {
- options[i](c)
- }
- return c
-}
-
-var (
- DefaultFastHttpClient = &fasthttp.Client{
- ReadTimeout: time.Second * 10,
- WriteTimeout: time.Second * 10,
- MaxIdleConnDuration: time.Minute,
- }
- queryParamsKeys = [][]string{
- {"name"},
- {"value"},
- }
- applicationJsonBytes = []byte("application/json")
- acceptBytes = []byte("accept")
- acceptEncodingBytes = []byte("Accept-Encoding")
- gzipEncodingBytes = []byte("gzip")
- userAgentBytes = []byte("graphql-go-client")
- contentEncoding = []byte("Content-Encoding")
-)
-
-func (f *FastHttpClient) Do(ctx context.Context, requestInput []byte, out io.Writer) (err error) {
-
- var (
- responseBody []byte
- )
-
- url, method, body, headers, queryParams := requestInputParams(requestInput)
-
- req, res := fasthttp.AcquireRequest(), fasthttp.AcquireResponse()
- defer func() {
- if f.log != nil {
- f.log.Debug("FastHttpClient.do",
- abstractlogger.ByteString("requestInput", requestInput),
- abstractlogger.ByteString("requestURI", req.RequestURI()),
- abstractlogger.ByteString("requestHeader", req.Header.Header()),
- abstractlogger.Int("responseCode", res.StatusCode()),
- abstractlogger.ByteString("responseHeader", res.Header.Header()),
- abstractlogger.ByteString("responseBody", responseBody),
- )
- }
- fasthttp.ReleaseRequest(req)
- fasthttp.ReleaseResponse(res)
- }()
-
- req.Header.SetUserAgentBytes(userAgentBytes)
- req.Header.SetMethodBytes(method)
- req.SetRequestURIBytes(url)
- req.SetBody(body)
-
- if headers != nil {
- err = jsonparser.ObjectEach(headers, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
- _, err := jsonparser.ArrayEach(value, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
- if err != nil {
- return
- }
- req.Header.AddBytesKV(key, value)
- })
- return err
- })
- if err != nil {
- return err
- }
- }
-
- if queryParams != nil {
- _, err = jsonparser.ArrayEach(queryParams, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
- var (
- parameterName, parameterValue []byte
- )
- jsonparser.EachKey(value, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) {
- switch i {
- case 0:
- parameterName = bytes
- case 1:
- parameterValue = bytes
- }
- }, queryParamsKeys...)
- if len(parameterName) != 0 && len(parameterValue) != 0 {
- if bytes.Equal(parameterValue[:1], literal.LBRACK) {
- _, _ = jsonparser.ArrayEach(parameterValue, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
- req.URI().QueryArgs().AddBytesKV(parameterName, value)
- })
- } else {
- req.URI().QueryArgs().AddBytesKV(parameterName, parameterValue)
- }
- }
- })
- if err != nil {
- return err
- }
- }
-
- req.Header.SetBytesKV(acceptBytes, applicationJsonBytes)
- req.Header.SetBytesKV(acceptEncodingBytes, gzipEncodingBytes)
- req.Header.SetContentTypeBytes(applicationJsonBytes)
-
- if deadline, ok := ctx.Deadline(); ok {
- err = f.client.DoDeadline(req, res, deadline)
- } else {
- err = f.client.Do(req, res)
- }
-
- if err != nil {
- return
- }
-
- if bytes.Equal(res.Header.PeekBytes(contentEncoding), gzipEncodingBytes) {
- responseBody, err = res.BodyGunzip()
- if err != nil {
- return err
- }
- } else {
- responseBody = res.Body()
- }
-
- _, err = out.Write(responseBody)
- return err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/httpclient.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/httpclient.go
deleted file mode 100644
index 70e565c7497..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/httpclient.go
+++ /dev/null
@@ -1,199 +0,0 @@
-package httpclient
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "io"
-
- "github.com/buger/jsonparser"
- byte_template "github.com/jensneuse/byte-template"
- "github.com/tidwall/gjson"
- "github.com/tidwall/sjson"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/quotes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-const (
- PATH = "path"
- URL = "url"
- BASEURL = "base_url"
- METHOD = "method"
- BODY = "body"
- HEADER = "header"
- QUERYPARAMS = "query_params"
-
- SCHEME = "scheme"
- HOST = "host"
-)
-
-var (
- inputPaths = [][]string{
- {URL},
- {METHOD},
- {BODY},
- {HEADER},
- {QUERYPARAMS},
- }
- subscriptionInputPaths = [][]string{
- {URL},
- {HEADER},
- {BODY},
- }
-)
-
-type Client interface {
- Do(ctx context.Context, requestInput []byte, out io.Writer) (err error)
-}
-
-func wrapQuotesIfString(b []byte) []byte {
-
- if bytes.HasPrefix(b, []byte("$$")) && bytes.HasSuffix(b, []byte("$$")) {
- return b
- }
-
- if bytes.HasPrefix(b, []byte("{{")) && bytes.HasSuffix(b, []byte("}}")) {
- return b
- }
-
- inType := gjson.ParseBytes(b).Type
- switch inType {
- case gjson.Number, gjson.String:
- return b
- case gjson.JSON:
- var value interface{}
- withoutTemplate := bytes.ReplaceAll(b, []byte("$$"), nil)
-
- buf := &bytes.Buffer{}
- tmpl := byte_template.New()
- _, _ = tmpl.Execute(buf, withoutTemplate, func(w io.Writer, path []byte) (n int, err error) {
- return w.Write([]byte("0"))
- })
-
- withoutTemplate = buf.Bytes()
-
- err := json.Unmarshal(withoutTemplate, &value)
- if err == nil {
- return b
- }
- case gjson.False:
- if bytes.Equal(b, literal.FALSE) {
- return b
- }
- case gjson.True:
- if bytes.Equal(b, literal.TRUE) {
- return b
- }
- case gjson.Null:
- if bytes.Equal(b, literal.NULL) {
- return b
- }
- }
- return quotes.WrapBytes(b)
-}
-
-func SetInputURL(input, url []byte) []byte {
- if len(url) == 0 {
- return input
- }
- out, _ := sjson.SetRawBytes(input, URL, wrapQuotesIfString(url))
- return out
-}
-
-func SetInputMethod(input, method []byte) []byte {
- if len(method) == 0 {
- return input
- }
- out, _ := sjson.SetRawBytes(input, METHOD, wrapQuotesIfString(method))
- return out
-}
-
-func SetInputBody(input, body []byte) []byte {
- return SetInputBodyWithPath(input, body, "")
-}
-
-func SetInputBodyWithPath(input, body []byte, path string) []byte {
- if len(body) == 0 {
- return input
- }
- if path != "" {
- path = BODY + "." + path
- } else {
- path = BODY
- }
- out, _ := sjson.SetRawBytes(input, path, wrapQuotesIfString(body))
- return out
-}
-
-func SetInputHeader(input, headers []byte) []byte {
- if len(headers) == 0 {
- return input
- }
- out, _ := sjson.SetRawBytes(input, HEADER, wrapQuotesIfString(headers))
- return out
-}
-
-func SetInputQueryParams(input, queryParams []byte) []byte {
- if len(queryParams) == 0 {
- return input
- }
- out, _ := sjson.SetRawBytes(input, QUERYPARAMS, wrapQuotesIfString(queryParams))
- return out
-}
-
-func SetInputScheme(input, scheme []byte) []byte {
- if len(scheme) == 0 {
- return input
- }
- out, _ := sjson.SetRawBytes(input, SCHEME, wrapQuotesIfString(scheme))
- return out
-}
-
-func SetInputHost(input, host []byte) []byte {
- if len(host) == 0 {
- return input
- }
- out, _ := sjson.SetRawBytes(input, HOST, wrapQuotesIfString(host))
- return out
-}
-
-func SetInputPath(input, path []byte) []byte {
- if len(path) == 0 {
- return input
- }
- out, _ := sjson.SetRawBytes(input, PATH, wrapQuotesIfString(path))
- return out
-}
-
-func requestInputParams(input []byte) (url, method, body, headers, queryParams []byte) {
- jsonparser.EachKey(input, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) {
- switch i {
- case 0:
- url = bytes
- case 1:
- method = bytes
- case 2:
- body = bytes
- case 3:
- headers = bytes
- case 4:
- queryParams = bytes
- }
- }, inputPaths...)
- return
-}
-
-func GetSubscriptionInput(input []byte) (url, header, body []byte) {
- jsonparser.EachKey(input, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) {
- switch i {
- case 0:
- url = bytes
- case 1:
- header = bytes
- case 2:
- body = bytes
- }
- }, subscriptionInputPaths...)
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/nethttpclient.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/nethttpclient.go
deleted file mode 100644
index 9e547201577..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient/nethttpclient.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package httpclient
-
-import (
- "bytes"
- "context"
- "io"
- "net/http"
- "time"
-
- "github.com/buger/jsonparser"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type NetHttpClient struct {
- client *http.Client
-}
-
-func NewNetHttpClient(client *http.Client) *NetHttpClient {
- return &NetHttpClient{
- client: client,
- }
-}
-
-var (
- DefaultNetHttpClient = &http.Client{
- Timeout: time.Second * 10,
- Transport: &http.Transport{
- MaxIdleConnsPerHost: 1024,
- TLSHandshakeTimeout: 0 * time.Second,
- },
- }
-)
-
-func (n *NetHttpClient) Do(ctx context.Context, requestInput []byte, out io.Writer) (err error) {
-
- url, method, body, headers, queryParams := requestInputParams(requestInput)
-
- // Change to `http.NewRequestWithContext` when support for go 1.12 is dropped
- request, err := NewRequestWithContext(ctx, unsafebytes.BytesToString(method), unsafebytes.BytesToString(url), bytes.NewReader(body))
- if err != nil {
- return err
- }
-
- if headers != nil {
- err = jsonparser.ObjectEach(headers, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
- _, err := jsonparser.ArrayEach(value, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
- if err != nil {
- return
- }
- request.Header.Add(unsafebytes.BytesToString(key), unsafebytes.BytesToString(value))
- })
- return err
- })
- if err != nil {
- return err
- }
- }
-
- if queryParams != nil {
- query := request.URL.Query()
- _, err = jsonparser.ArrayEach(queryParams, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
- var (
- parameterName, parameterValue []byte
- )
- jsonparser.EachKey(value, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) {
- switch i {
- case 0:
- parameterName = bytes
- case 1:
- parameterValue = bytes
- }
- }, queryParamsKeys...)
- if len(parameterName) != 0 && len(parameterValue) != 0 {
- if bytes.Equal(parameterValue[:1], literal.LBRACK) {
- _, _ = jsonparser.ArrayEach(parameterValue, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
- query.Add(string(parameterName), string(value))
- })
- } else {
- query.Add(string(parameterName), string(parameterValue))
- }
- }
- })
- if err != nil {
- return err
- }
- request.URL.RawQuery = query.Encode()
- }
-
- request.Header.Add("accept", "application/json")
- request.Header.Add("content-type", "application/json")
-
- response, err := n.client.Do(request)
- if err != nil {
- return err
- }
-
- defer response.Body.Close()
-
- _, err = io.Copy(out, response.Body)
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/rest_datasource/rest_datasource.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/rest_datasource/rest_datasource.go
deleted file mode 100644
index 23965ebc149..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/rest_datasource/rest_datasource.go
+++ /dev/null
@@ -1,185 +0,0 @@
-package rest_datasource
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "net/http"
- "regexp"
- "strings"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/plan"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/http_polling"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-const (
- UniqueIdentifier = "rest"
-)
-
-type Planner struct {
- client httpclient.Client
- v *plan.Visitor
- config Configuration
- rootField int
- operationDefinition int
-}
-
-func (p *Planner) EnterOperationDefinition(ref int) {
- p.operationDefinition = ref
-}
-
-type Factory struct {
- Client httpclient.Client
-}
-
-func (f *Factory) Planner() plan.DataSourcePlanner {
- return &Planner{
- client: f.Client,
- }
-}
-
-type Configuration struct {
- Fetch FetchConfiguration
- Subscription SubscriptionConfiguration
-}
-
-func ConfigJSON(config Configuration) json.RawMessage {
- out, _ := json.Marshal(config)
- return out
-}
-
-type SubscriptionConfiguration struct {
- PollingIntervalMillis int64
- SkipPublishSameResponse bool
-}
-
-type FetchConfiguration struct {
- URL string
- Method string
- Header http.Header
- Query []QueryConfiguration
- Body string
-}
-
-type QueryConfiguration struct {
- Name string `json:"name"`
- Value string `json:"value"`
-}
-
-func (p *Planner) Register(visitor *plan.Visitor, customConfiguration json.RawMessage, isNested bool) error {
- p.v = visitor
- visitor.Walker.RegisterEnterFieldVisitor(p)
- visitor.Walker.RegisterEnterOperationVisitor(p)
- return json.Unmarshal(customConfiguration, &p.config)
-}
-
-func (p *Planner) EnterField(ref int) {
- p.rootField = ref
-}
-
-func (p *Planner) configureInput() []byte {
-
- input := httpclient.SetInputURL(nil, []byte(p.config.Fetch.URL))
- input = httpclient.SetInputMethod(input, []byte(p.config.Fetch.Method))
- input = httpclient.SetInputBody(input, []byte(p.config.Fetch.Body))
-
- header, err := json.Marshal(p.config.Fetch.Header)
- if err == nil && len(header) != 0 && !bytes.Equal(header, literal.NULL) {
- input = httpclient.SetInputHeader(input, header)
- }
-
- preparedQuery := p.prepareQueryParams(p.rootField, p.config.Fetch.Query)
- query, err := json.Marshal(preparedQuery)
- if err == nil && len(preparedQuery) != 0 {
- input = httpclient.SetInputQueryParams(input, query)
- }
- return input
-}
-
-func (p *Planner) ConfigureFetch() plan.FetchConfiguration {
- input := p.configureInput()
- return plan.FetchConfiguration{
- Input: string(input),
- Variables: nil,
- DataSource: &Source{
- client: p.client,
- },
- DisallowSingleFlight: p.config.Fetch.Method != "GET",
- }
-}
-
-func (p *Planner) ConfigureSubscription() plan.SubscriptionConfiguration {
-
- input := p.configureInput()
-
- var httpPollingInput []byte
- httpPollingInput = http_polling.SetSkipPublishSameResponse(httpPollingInput, p.config.Subscription.SkipPublishSameResponse)
- httpPollingInput = http_polling.SetRequestInput(httpPollingInput, input)
- httpPollingInput = http_polling.SetInputIntervalMillis(httpPollingInput, p.config.Subscription.PollingIntervalMillis)
-
- return plan.SubscriptionConfiguration{
- Input: string(httpPollingInput),
- SubscriptionManagerID: "http_polling_stream",
- Variables: nil,
- }
-}
-
-var (
- selectorRegex = regexp.MustCompile(`{{\s(.*?)\s}}`)
-)
-
-func (p *Planner) prepareQueryParams(field int, query []QueryConfiguration) []QueryConfiguration {
- out := make([]QueryConfiguration, 0, len(query))
-Next:
- for i := range query {
- matches := selectorRegex.FindAllStringSubmatch(query[i].Value, -1)
- for j := range matches {
- if len(matches[j]) == 2 {
- path := matches[j][1]
- path = strings.TrimPrefix(path, ".")
- elements := strings.Split(path, ".")
- if len(elements) < 2 {
- continue
- }
- if elements[0] != "arguments" {
- continue
- }
- argumentName := elements[1]
- arg, ok := p.v.Operation.FieldArgument(field, []byte(argumentName))
- if !ok {
- continue Next
- }
- value := p.v.Operation.Arguments[arg].Value
- if value.Kind != ast.ValueKindVariable {
- continue Next
- }
- variableName := p.v.Operation.VariableValueNameString(value.Ref)
- if !p.v.Operation.OperationDefinitionHasVariableDefinition(p.operationDefinition, variableName) {
- continue Next
- }
- }
- }
- out = append(out, query[i])
- }
- return out
-}
-
-type Source struct {
- client httpclient.Client
-}
-
-var (
- uniqueIdentifier = []byte(UniqueIdentifier)
-)
-
-func (_ *Source) UniqueIdentifier() []byte {
- return uniqueIdentifier
-}
-
-func (s *Source) Load(ctx context.Context, input []byte, bufPair *resolve.BufPair) (err error) {
- return s.client.Do(ctx, input, bufPair.Data)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/plan/analyze_plan_kind.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/plan/analyze_plan_kind.go
deleted file mode 100644
index 6ce570c32d5..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/plan/analyze_plan_kind.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package plan
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-func AnalyzePlanKind(operation, definition *ast.Document, operationName string) (subscription, streaming bool, error error) {
- walker := astvisitor.NewWalker(48)
- visitor := &planKindVisitor{
- Walker: &walker,
- operationName: operationName,
- }
-
- walker.RegisterEnterDocumentVisitor(visitor)
- walker.RegisterEnterOperationVisitor(visitor)
- walker.RegisterEnterDirectiveVisitor(visitor)
-
- var report operationreport.Report
- walker.Walk(operation, definition, &report)
- if report.HasErrors() {
- return false, false, report
- }
- subscription = visitor.isSubscription
- streaming = visitor.hasDeferDirective || visitor.hasStreamDirective
- return
-}
-
-type planKindVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
- operationName string
- isSubscription, hasStreamDirective, hasDeferDirective bool
-}
-
-func (p *planKindVisitor) EnterDirective(ref int) {
- directiveName := p.operation.DirectiveNameString(ref)
- ancestor := p.Ancestors[len(p.Ancestors)-1]
- switch ancestor.Kind {
- case ast.NodeKindField:
- switch directiveName {
- case "defer":
- p.hasDeferDirective = true
- case "stream":
- p.hasStreamDirective = true
- }
- }
-}
-
-func (p *planKindVisitor) EnterOperationDefinition(ref int) {
- name := p.operation.OperationDefinitionNameString(ref)
- if p.operationName != name {
- p.SkipNode()
- return
- }
- switch p.operation.OperationDefinitions[ref].OperationType {
- case ast.OperationTypeSubscription:
- p.isSubscription = true
- }
-}
-
-func (p *planKindVisitor) EnterDocument(operation, definition *ast.Document) {
- p.operation, p.definition = operation, definition
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/plan/plan.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/plan/plan.go
deleted file mode 100644
index 6894e6c76c5..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/plan/plan.go
+++ /dev/null
@@ -1,1067 +0,0 @@
-package plan
-
-import (
- "encoding/json"
- "regexp"
- "strings"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astimport"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type Planner struct {
- config Configuration
- configurationWalker *astvisitor.Walker
- configurationVisitor *configurationVisitor
- planningWalker *astvisitor.Walker
- planningVisitor *Visitor
- requiredFieldsWalker *astvisitor.Walker
- requiredFieldsVisitor *requiredFieldsVisitor
-}
-
-type Configuration struct {
- DefaultFlushInterval int64
- DataSources []DataSourceConfiguration
- Fields FieldConfigurations
- Schema string
-}
-
-type FieldConfigurations []FieldConfiguration
-
-func (f FieldConfigurations) ForTypeField(typeName, fieldName string) *FieldConfiguration {
- for i := range f {
- if f[i].TypeName == typeName && f[i].FieldName == fieldName {
- return &f[i]
- }
- }
- return nil
-}
-
-type FieldConfiguration struct {
- TypeName string
- FieldName string
- DisableDefaultMapping bool
- Path []string
- RespectOverrideFieldPathFromAlias bool
- Arguments ArgumentsConfigurations
- RequiresFields []string
-}
-
-type ArgumentsConfigurations []ArgumentConfiguration
-
-func (a ArgumentsConfigurations) ForName(argName string) *ArgumentConfiguration {
- for i := range a {
- if a[i].Name == argName {
- return &a[i]
- }
- }
- return nil
-}
-
-type SourceType string
-
-const (
- ObjectFieldSource SourceType = "object_field"
- FieldArgumentSource SourceType = "field_argument"
-)
-
-type ArgumentConfiguration struct {
- Name string
- SourceType SourceType
- SourcePath []string
-}
-
-type DataSourceConfiguration struct {
- RootNodes []TypeField
- ChildNodes []TypeField
- Factory PlannerFactory
- OverrideFieldPathFromAlias bool
- Custom json.RawMessage
-}
-
-func (d *DataSourceConfiguration) HasRootNode(typeName, fieldName string) bool {
- for i := range d.RootNodes {
- if typeName != d.RootNodes[i].TypeName {
- continue
- }
- for j := range d.RootNodes[i].FieldNames {
- if fieldName == d.RootNodes[i].FieldNames[j] {
- return true
- }
- }
- }
- return false
-}
-
-type PlannerFactory interface {
- Planner() DataSourcePlanner
-}
-
-type TypeField struct {
- TypeName string
- FieldNames []string
-}
-
-type FieldMapping struct {
- TypeName string
- FieldName string
- DisableDefaultMapping bool
- Path []string
- RespectOverrideFieldPathFromAlias bool
-}
-
-func NewPlanner(config Configuration) *Planner {
-
- // required fields pre-processing
-
- requiredFieldsWalker := astvisitor.NewWalker(48)
- requiredFieldsV := &requiredFieldsVisitor{
- walker: &requiredFieldsWalker,
- }
-
- requiredFieldsWalker.RegisterEnterDocumentVisitor(requiredFieldsV)
- requiredFieldsWalker.RegisterEnterOperationVisitor(requiredFieldsV)
- requiredFieldsWalker.RegisterEnterFieldVisitor(requiredFieldsV)
-
- // configuration
-
- configurationWalker := astvisitor.NewWalker(48)
- configVisitor := &configurationVisitor{
- walker: &configurationWalker,
- }
-
- configurationWalker.RegisterEnterDocumentVisitor(configVisitor)
- configurationWalker.RegisterFieldVisitor(configVisitor)
- configurationWalker.RegisterEnterOperationVisitor(configVisitor)
-
- // planning
-
- planningWalker := astvisitor.NewWalker(48)
- planningVisitor := &Visitor{
- Walker: &planningWalker,
- }
-
- p := &Planner{
- config: config,
- configurationWalker: &configurationWalker,
- configurationVisitor: configVisitor,
- planningWalker: &planningWalker,
- planningVisitor: planningVisitor,
- requiredFieldsWalker: &requiredFieldsWalker,
- requiredFieldsVisitor: requiredFieldsV,
- }
-
- return p
-}
-
-func (p *Planner) SetConfig(config Configuration) {
- p.config = config
-}
-
-func (p *Planner) Plan(operation, definition *ast.Document, operationName string, report *operationreport.Report) (plan Plan) {
-
- // make a copy of the config as the pre-processor modifies it
-
- config := p.config
-
- // select operation
-
- p.selectOperation(operation, operationName, report)
- if report.HasErrors() {
- return
- }
-
- // pre-process required fields
-
- p.preProcessRequiredFields(&config, operation, definition, report)
-
- // find planning paths
-
- p.configurationVisitor.config = config
- p.configurationWalker.Walk(operation, definition, report)
-
- // configure planning visitor
-
- p.planningVisitor.planners = p.configurationVisitor.planners
- p.planningVisitor.Config = config
- p.planningVisitor.fetchConfigurations = p.configurationVisitor.fetches
- p.planningVisitor.fieldBuffers = p.configurationVisitor.fieldBuffers
- p.planningVisitor.skipFieldPaths = p.requiredFieldsVisitor.skipFieldPaths
-
- p.planningWalker.ResetVisitors()
- p.planningWalker.SetVisitorFilter(p.planningVisitor)
- p.planningWalker.RegisterDocumentVisitor(p.planningVisitor)
- p.planningWalker.RegisterEnterOperationVisitor(p.planningVisitor)
- p.planningWalker.RegisterFieldVisitor(p.planningVisitor)
- p.planningWalker.RegisterSelectionSetVisitor(p.planningVisitor)
- p.planningWalker.RegisterEnterDirectiveVisitor(p.planningVisitor)
-
- for key := range p.planningVisitor.planners {
- custom := p.planningVisitor.planners[key].dataSourceConfiguration.Custom
- isNested := p.planningVisitor.planners[key].isNestedPlanner()
- err := p.planningVisitor.planners[key].planner.Register(p.planningVisitor, custom, isNested)
- if err != nil {
- p.planningWalker.StopWithInternalErr(err)
- }
- }
-
- // process the plan
-
- p.planningWalker.Walk(operation, definition, report)
-
- return p.planningVisitor.plan
-}
-
-func (p *Planner) selectOperation(operation *ast.Document, operationName string, report *operationreport.Report) {
-
- numOfOperations := operation.NumOfOperationDefinitions()
- operationName = strings.TrimSpace(operationName)
- if len(operationName) == 0 && numOfOperations > 1 {
- report.AddExternalError(operationreport.ErrRequiredOperationNameIsMissing())
- return
- }
-
- if len(operationName) == 0 && numOfOperations == 1 {
- operationName = operation.OperationDefinitionNameString(0)
- }
-
- if !operation.OperationNameExists(operationName) {
- report.AddExternalError(operationreport.ErrOperationWithProvidedOperationNameNotFound(operationName))
- return
- }
-
- p.requiredFieldsVisitor.operationName = operationName
- p.configurationVisitor.operationName = operationName
- p.planningVisitor.OperationName = operationName
-}
-
-func (p *Planner) preProcessRequiredFields(config *Configuration, operation, definition *ast.Document, report *operationreport.Report) {
- if !p.hasRequiredFields(config) {
- return
- }
-
- p.requiredFieldsVisitor.config = config
- p.requiredFieldsVisitor.operation = operation
- p.requiredFieldsVisitor.definition = definition
- p.requiredFieldsWalker.Walk(operation, definition, report)
-}
-
-func (p *Planner) hasRequiredFields(config *Configuration) bool {
- for i := range config.Fields {
- if len(config.Fields[i].RequiresFields) != 0 {
- return true
- }
- }
- return false
-}
-
-type Visitor struct {
- Operation, Definition *ast.Document
- Walker *astvisitor.Walker
- Importer astimport.Importer
- Config Configuration
- plan Plan
- OperationName string
- operationDefinition int
- objects []*resolve.Object
- currentFields []objectFields
- currentField *resolve.Field
- planners []plannerConfiguration
- fetchConfigurations []objectFetchConfiguration
- fieldBuffers map[int]int
- skipFieldPaths []string
-}
-
-type objectFields struct {
- popOnField int
- fields *[]*resolve.Field
-}
-
-type objectFetchConfiguration struct {
- object *resolve.Object
- trigger *resolve.GraphQLSubscriptionTrigger
- planner DataSourcePlanner
- bufferID int
- isSubscription bool
- fieldRef int
-}
-
-func (v *Visitor) AllowVisitor(kind astvisitor.VisitorKind, ref int, visitor interface{}) bool {
- if visitor == v {
- return true
- }
- path := v.Walker.Path.DotDelimitedString()
- switch kind {
- case astvisitor.EnterField, astvisitor.LeaveField:
- fieldAliasOrName := v.Operation.FieldAliasOrNameString(ref)
- path = path + "." + fieldAliasOrName
- }
- if !strings.Contains(path, ".") {
- return true
- }
- for _, config := range v.planners {
- if config.planner == visitor && config.hasPath(path) {
- switch kind {
- case astvisitor.EnterSelectionSet, astvisitor.LeaveSelectionSet:
- return !config.isExitPath(path)
- default:
- return true
- }
- }
- }
- return false
-}
-
-func (v *Visitor) currentFullPath() string {
- path := v.Walker.Path.DotDelimitedString()
- if v.Walker.CurrentKind == ast.NodeKindField {
- fieldAliasOrName := v.Operation.FieldAliasOrNameString(v.Walker.CurrentRef)
- path = path + "." + fieldAliasOrName
- }
- return path
-}
-
-func (v *Visitor) currentPlannerConfiguration() plannerConfiguration {
- path := v.currentFullPath()
- for i := range v.planners {
- if v.planners[i].hasPath(path) {
- return v.planners[i]
- }
- }
- return plannerConfiguration{}
-}
-
-func (v *Visitor) EnterDirective(ref int) {
- directiveName := v.Operation.DirectiveNameString(ref)
- ancestor := v.Walker.Ancestors[len(v.Walker.Ancestors)-1]
- switch ancestor.Kind {
- case ast.NodeKindOperationDefinition:
- switch directiveName {
- case "flushInterval":
- if value, ok := v.Operation.DirectiveArgumentValueByName(ref, literal.MILLISECONDS); ok {
- if value.Kind == ast.ValueKindInteger {
- v.plan.SetFlushInterval(v.Operation.IntValueAsInt(value.Ref))
- }
- }
- }
- case ast.NodeKindField:
- switch directiveName {
- case "stream":
- initialBatchSize := 0
- if value, ok := v.Operation.DirectiveArgumentValueByName(ref, literal.INITIAL_BATCH_SIZE); ok {
- if value.Kind == ast.ValueKindInteger {
- initialBatchSize = int(v.Operation.IntValueAsInt(value.Ref))
- }
- }
- v.currentField.Stream = &resolve.StreamField{
- InitialBatchSize: initialBatchSize,
- }
- case "defer":
- v.currentField.Defer = &resolve.DeferField{}
- }
- }
-}
-
-func (v *Visitor) LeaveSelectionSet(ref int) {
-
-}
-
-func (v *Visitor) EnterSelectionSet(ref int) {
-
-}
-
-func (v *Visitor) EnterField(ref int) {
-
- if v.skipField(ref) {
- return
- }
-
- fieldName := v.Operation.FieldAliasOrNameBytes(ref)
- fieldDefinition, ok := v.Walker.FieldDefinition(ref)
- if !ok {
- return
- }
-
- var (
- hasFetchConfig bool
- i int
- )
- for i = range v.fetchConfigurations {
- if ref == v.fetchConfigurations[i].fieldRef {
- hasFetchConfig = true
- break
- }
- }
- if hasFetchConfig {
- if v.fetchConfigurations[i].isSubscription {
- plan, ok := v.plan.(*SubscriptionResponsePlan)
- if ok {
- v.fetchConfigurations[i].trigger = &plan.Response.Trigger
- }
- } else {
- v.fetchConfigurations[i].object = v.objects[len(v.objects)-1]
- }
- }
-
- path := v.resolveFieldPath(ref)
- fieldDefinitionType := v.Definition.FieldDefinitionType(fieldDefinition)
- bufferID, hasBuffer := v.fieldBuffers[ref]
- v.currentField = &resolve.Field{
- Name: fieldName,
- Value: v.resolveFieldValue(ref, fieldDefinitionType, true, path),
- HasBuffer: hasBuffer,
- BufferID: bufferID,
- }
-
- *v.currentFields[len(v.currentFields)-1].fields = append(*v.currentFields[len(v.currentFields)-1].fields, v.currentField)
-}
-
-func (v *Visitor) LeaveField(ref int) {
- if v.currentFields[len(v.currentFields)-1].popOnField == ref {
- v.currentFields = v.currentFields[:len(v.currentFields)-1]
- }
- fieldDefinition, ok := v.Walker.FieldDefinition(ref)
- if !ok {
- return
- }
- fieldDefinitionTypeNode := v.Definition.FieldDefinitionTypeNode(fieldDefinition)
- switch fieldDefinitionTypeNode.Kind {
- case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition:
- v.objects = v.objects[:len(v.objects)-1]
- }
-}
-
-func (v *Visitor) skipField(ref int) bool {
- fullPath := v.Walker.Path.DotDelimitedString() + "." + v.Operation.FieldAliasOrNameString(ref)
- for i := range v.skipFieldPaths {
- if v.skipFieldPaths[i] == fullPath {
- return true
- }
- }
- return false
-}
-
-func (v *Visitor) resolveFieldValue(fieldRef, typeRef int, nullable bool, path []string) resolve.Node {
- ofType := v.Definition.Types[typeRef].OfType
- switch v.Definition.Types[typeRef].TypeKind {
- case ast.TypeKindNonNull:
- return v.resolveFieldValue(fieldRef, ofType, false, path)
- case ast.TypeKindList:
- listItem := v.resolveFieldValue(fieldRef, ofType, true, nil)
- return &resolve.Array{
- Nullable: nullable,
- Path: path,
- Item: listItem,
- }
- case ast.TypeKindNamed:
- typeName := v.Definition.ResolveTypeNameString(typeRef)
- typeDefinitionNode, ok := v.Definition.Index.FirstNodeByNameStr(typeName)
- if !ok {
- return &resolve.Null{}
- }
- switch typeDefinitionNode.Kind {
- case ast.NodeKindScalarTypeDefinition:
- switch typeName {
- case "String":
- return &resolve.String{
- Path: path,
- Nullable: nullable,
- }
- case "Boolean":
- return &resolve.Boolean{
- Path: path,
- Nullable: nullable,
- }
- case "Int":
- return &resolve.Integer{
- Path: path,
- Nullable: nullable,
- }
- case "Float":
- return &resolve.Float{
- Path: path,
- Nullable: nullable,
- }
- default:
- return &resolve.String{
- Path: path,
- Nullable: nullable,
- }
- }
- case ast.NodeKindEnumTypeDefinition:
- return &resolve.String{
- Path: path,
- Nullable: nullable,
- }
- case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition:
- object := &resolve.Object{
- Nullable: nullable,
- Path: path,
- Fields: []*resolve.Field{},
- }
- v.objects = append(v.objects, object)
- v.Walker.Defer(func() {
- v.currentFields = append(v.currentFields, objectFields{
- popOnField: fieldRef,
- fields: &object.Fields,
- })
- })
- return object
- default:
- return &resolve.Null{}
- }
- default:
- return &resolve.Null{}
- }
-}
-
-func (v *Visitor) EnterOperationDefinition(ref int) {
- operationName := v.Operation.OperationDefinitionNameString(ref)
- if v.OperationName != operationName {
- v.Walker.SkipNode()
- return
- }
-
- v.operationDefinition = ref
-
- rootObject := &resolve.Object{
- Fields: []*resolve.Field{},
- }
-
- v.objects = append(v.objects, rootObject)
- v.currentFields = append(v.currentFields, objectFields{
- fields: &rootObject.Fields,
- popOnField: -1,
- })
-
- isSubscription, _, err := AnalyzePlanKind(v.Operation, v.Definition, v.OperationName)
- if err != nil {
- v.Walker.StopWithInternalErr(err)
- return
- }
-
- graphQLResponse := &resolve.GraphQLResponse{
- Data: rootObject,
- }
-
- if isSubscription {
- v.plan = &SubscriptionResponsePlan{
- FlushInterval: v.Config.DefaultFlushInterval,
- Response: resolve.GraphQLSubscription{
- Response: graphQLResponse,
- },
- }
- return
- }
-
- /*if isStreaming {
-
- }*/
-
- v.plan = &SynchronousResponsePlan{
- Response: graphQLResponse,
- }
-}
-
-func (v *Visitor) resolveFieldPath(ref int) []string {
- typeName := v.Walker.EnclosingTypeDefinition.NameString(v.Definition)
- fieldName := v.Operation.FieldNameString(ref)
-
- config := v.currentPlannerConfiguration()
- aliasOverride := config.dataSourceConfiguration.OverrideFieldPathFromAlias
-
- for i := range v.Config.Fields {
- if v.Config.Fields[i].TypeName == typeName && v.Config.Fields[i].FieldName == fieldName {
- if aliasOverride && v.Config.Fields[i].RespectOverrideFieldPathFromAlias {
- return []string{v.Operation.FieldAliasOrNameString(ref)}
- }
- if v.Config.Fields[i].DisableDefaultMapping {
- return nil
- }
- if v.Config.Fields[i].Path != nil {
- return v.Config.Fields[i].Path
- }
- return []string{fieldName}
- }
- }
-
- if aliasOverride {
- return []string{v.Operation.FieldAliasOrNameString(ref)}
- }
-
- return []string{fieldName}
-}
-
-func (v *Visitor) EnterDocument(operation, definition *ast.Document) {
- v.Operation, v.Definition = operation, definition
-}
-
-func (v *Visitor) LeaveDocument(operation, definition *ast.Document) {
- for _, config := range v.fetchConfigurations {
- if config.isSubscription {
- v.configureSubscription(config)
- } else {
- v.configureObjectFetch(config)
- }
- }
-}
-
-var (
- templateRegex = regexp.MustCompile(`{{.*?}}`)
- selectorRegex = regexp.MustCompile(`{{\s*(.*?)\s*}}`)
-)
-
-func (v *Visitor) resolveInputTemplates(config objectFetchConfiguration, input *string, variables *resolve.Variables) {
- *input = templateRegex.ReplaceAllStringFunc(*input, func(s string) string {
- selectors := selectorRegex.FindStringSubmatch(s)
- if len(selectors) != 2 {
- return s
- }
- selector := strings.TrimPrefix(selectors[1], ".")
- parts := strings.Split(selector, ".")
- if len(parts) < 2 {
- return s
- }
- path := parts[1:]
- var (
- variableName string
- )
- switch parts[0] {
- case "object":
- variableName, _ = variables.AddVariable(&resolve.ObjectVariable{
- Path: path,
- }, false)
- case "arguments":
- argumentName := path[0]
- arg, ok := v.Operation.FieldArgument(config.fieldRef, []byte(argumentName))
- if !ok {
- break
- }
- value := v.Operation.ArgumentValue(arg)
- if value.Kind != ast.ValueKindVariable {
- break
- }
- variableValue := v.Operation.VariableValueNameString(value.Ref)
- if !v.Operation.OperationDefinitionHasVariableDefinition(v.operationDefinition, variableValue) {
- break // omit optional argument when variable is not defined
- }
- variableName, _ = variables.AddVariable(&resolve.ContextVariable{
- Path: []string{variableValue},
- }, false)
- case "request":
- if len(path) != 2 {
- break
- }
- switch path[0] {
- case "header":
- key := path[1]
- variableName, _ = variables.AddVariable(&resolve.HeaderVariable{
- Path: []string{key},
- }, false)
- }
- }
- return variableName
- })
-}
-
-func (v *Visitor) configureSubscription(config objectFetchConfiguration) {
- subscription := config.planner.ConfigureSubscription()
- config.trigger.Input = subscription.Input
- config.trigger.ManagerID = []byte(subscription.SubscriptionManagerID)
- config.trigger.Variables = subscription.Variables
- v.resolveInputTemplates(config, &config.trigger.Input, &config.trigger.Variables)
-}
-
-func (v *Visitor) configureObjectFetch(config objectFetchConfiguration) {
- if config.object == nil {
- return
- }
- fetchConfig := config.planner.ConfigureFetch()
- fetch := v.configureSingleFetch(config, fetchConfig)
- v.resolveInputTemplates(config, &fetch.Input, &fetch.Variables)
- if config.object.Fetch == nil {
- config.object.Fetch = fetch
- return
- }
- switch existing := config.object.Fetch.(type) {
- case *resolve.SingleFetch:
- copyOfExisting := *existing
- parallel := &resolve.ParallelFetch{
- Fetches: []*resolve.SingleFetch{©OfExisting, fetch},
- }
- config.object.Fetch = parallel
- case *resolve.ParallelFetch:
- existing.Fetches = append(existing.Fetches, fetch)
- }
-}
-
-func (v *Visitor) configureSingleFetch(internal objectFetchConfiguration, external FetchConfiguration) *resolve.SingleFetch {
- return &resolve.SingleFetch{
- BufferId: internal.bufferID,
- Input: external.Input,
- DataSource: external.DataSource,
- Variables: external.Variables,
- DisallowSingleFlight: external.DisallowSingleFlight,
- }
-}
-
-type Kind int
-
-const (
- SynchronousResponseKind Kind = iota + 1
- StreamingResponseKind
- SubscriptionResponseKind
-)
-
-type Plan interface {
- PlanKind() Kind
- SetFlushInterval(interval int64)
-}
-
-type SynchronousResponsePlan struct {
- Response *resolve.GraphQLResponse
- FlushInterval int64
-}
-
-func (s *SynchronousResponsePlan) SetFlushInterval(interval int64) {
- s.FlushInterval = interval
-}
-
-func (_ *SynchronousResponsePlan) PlanKind() Kind {
- return SynchronousResponseKind
-}
-
-type StreamingResponsePlan struct {
- Response resolve.GraphQLStreamingResponse
- FlushInterval int64
-}
-
-func (s *StreamingResponsePlan) SetFlushInterval(interval int64) {
- s.FlushInterval = interval
-}
-
-func (_ *StreamingResponsePlan) PlanKind() Kind {
- return StreamingResponseKind
-}
-
-type SubscriptionResponsePlan struct {
- Response resolve.GraphQLSubscription
- FlushInterval int64
-}
-
-func (s *SubscriptionResponsePlan) SetFlushInterval(interval int64) {
- s.FlushInterval = interval
-}
-
-func (_ *SubscriptionResponsePlan) PlanKind() Kind {
- return SubscriptionResponseKind
-}
-
-type DataSourcePlanner interface {
- Register(visitor *Visitor, customConfiguration json.RawMessage, isNested bool) error
- ConfigureFetch() FetchConfiguration
- ConfigureSubscription() SubscriptionConfiguration
-}
-
-type SubscriptionConfiguration struct {
- Input string
- SubscriptionManagerID string
- Variables resolve.Variables
-}
-
-type FetchConfiguration struct {
- Input string
- Variables resolve.Variables
- DataSource resolve.DataSource
- DisallowSingleFlight bool
-}
-
-type configurationVisitor struct {
- operationName string
- operation, definition *ast.Document
- walker *astvisitor.Walker
- config Configuration
- planners []plannerConfiguration
- fetches []objectFetchConfiguration
- currentBufferId int
- fieldBuffers map[int]int
-}
-
-type plannerConfiguration struct {
- parentPath string
- planner DataSourcePlanner
- paths []pathConfiguration
- dataSourceConfiguration DataSourceConfiguration
- bufferID int
-}
-
-//isNestedPlanner returns true in case the planner is not directly attached to the Operation root
-// a nested planner should always build a Query
-func (p *plannerConfiguration) isNestedPlanner() bool {
- for i := range p.paths {
- pathElements := strings.Count(p.paths[i].path, ".") + 1
- if pathElements == 2 {
- return false
- }
- }
- return true
-}
-
-func (c *configurationVisitor) nextBufferID() int {
- c.currentBufferId++
- return c.currentBufferId
-}
-
-func (p *plannerConfiguration) hasPath(path string) bool {
- for i := range p.paths {
- if p.paths[i].path == path {
- return true
- }
- }
- return false
-}
-
-func (p *plannerConfiguration) isExitPath(path string) bool {
- for i := range p.paths {
- if p.paths[i].path == path {
- return p.paths[i].exitPlannerOnNode
- }
- }
- return false
-}
-
-func (p *plannerConfiguration) setPathExit(path string) {
- for i := range p.paths {
- if p.paths[i].path == path {
- p.paths[i].exitPlannerOnNode = true
- return
- }
- }
-}
-
-func (p *plannerConfiguration) hasPathPrefix(prefix string) bool {
- for i := range p.paths {
- if p.paths[i].path == prefix {
- continue
- }
- if strings.HasPrefix(p.paths[i].path, prefix) {
- return true
- }
- }
- return false
-}
-
-func (p *plannerConfiguration) hasParent(parent string) bool {
- return p.parentPath == parent
-}
-
-func (p *plannerConfiguration) hasChildNode(typeName, fieldName string) bool {
- for i := range p.dataSourceConfiguration.ChildNodes {
- if typeName != p.dataSourceConfiguration.ChildNodes[i].TypeName {
- continue
- }
- for j := range p.dataSourceConfiguration.ChildNodes[i].FieldNames {
- if fieldName == p.dataSourceConfiguration.ChildNodes[i].FieldNames[j] {
- return true
- }
- }
- }
- return false
-}
-
-func (p *plannerConfiguration) hasRootNode(typeName, fieldName string) bool {
- for i := range p.dataSourceConfiguration.RootNodes {
- if typeName != p.dataSourceConfiguration.RootNodes[i].TypeName {
- continue
- }
- for j := range p.dataSourceConfiguration.RootNodes[i].FieldNames {
- if fieldName == p.dataSourceConfiguration.RootNodes[i].FieldNames[j] {
- return true
- }
- }
- }
- return false
-}
-
-type pathConfiguration struct {
- path string
- exitPlannerOnNode bool
-}
-
-func (c *configurationVisitor) EnterOperationDefinition(ref int) {
- operationName := c.operation.OperationDefinitionNameString(ref)
- if c.operationName != operationName {
- c.walker.SkipNode()
- return
- }
-}
-
-func (c *configurationVisitor) EnterField(ref int) {
- fieldName := c.operation.FieldNameString(ref)
- fieldAliasOrName := c.operation.FieldAliasOrNameString(ref)
- typeName := c.walker.EnclosingTypeDefinition.NameString(c.definition)
- parent := c.walker.Path.DotDelimitedString()
- current := parent + "." + fieldAliasOrName
- root := c.walker.Ancestors[0]
- if root.Kind != ast.NodeKindOperationDefinition {
- return
- }
- isSubscription := c.isSubscription(root.Ref, current)
- for i, planner := range c.planners {
- if planner.hasParent(parent) && planner.hasRootNode(typeName, fieldName) {
- // same parent + root node = root sibling
- c.planners[i].paths = append(c.planners[i].paths, pathConfiguration{path: current})
- c.fieldBuffers[ref] = planner.bufferID
- return
- }
- if planner.hasPath(parent) && planner.hasChildNode(typeName, fieldName) {
- // has parent path + has child node = child
- c.planners[i].paths = append(c.planners[i].paths, pathConfiguration{path: current})
- return
- }
- }
- for i, config := range c.config.DataSources {
- if config.HasRootNode(typeName, fieldName) {
- var (
- bufferID int
- )
- if !isSubscription {
- bufferID = c.nextBufferID()
- c.fieldBuffers[ref] = bufferID
- }
- planner := c.config.DataSources[i].Factory.Planner()
- c.planners = append(c.planners, plannerConfiguration{
- bufferID: bufferID,
- parentPath: parent,
- planner: planner,
- paths: []pathConfiguration{
- {
- path: current,
- },
- },
- dataSourceConfiguration: config,
- })
- c.fetches = append(c.fetches, objectFetchConfiguration{
- bufferID: bufferID,
- planner: planner,
- isSubscription: isSubscription,
- fieldRef: ref,
- })
- return
- }
- }
-}
-
-func (c *configurationVisitor) LeaveField(ref int) {
- fieldAliasOrName := c.operation.FieldAliasOrNameString(ref)
- parent := c.walker.Path.DotDelimitedString()
- current := parent + "." + fieldAliasOrName
- for i, planner := range c.planners {
- if planner.hasPath(current) && !planner.hasPathPrefix(current) {
- c.planners[i].setPathExit(current)
- return
- }
- }
-}
-
-func (c *configurationVisitor) EnterDocument(operation, definition *ast.Document) {
- c.operation, c.definition = operation, definition
- c.currentBufferId = -1
- if c.planners == nil {
- c.planners = make([]plannerConfiguration, 0, 8)
- } else {
- c.planners = c.planners[:0]
- }
- if c.fetches == nil {
- c.fetches = []objectFetchConfiguration{}
- } else {
- c.fetches = c.fetches[:0]
- }
- if c.fieldBuffers == nil {
- c.fieldBuffers = map[int]int{}
- } else {
- for i := range c.fieldBuffers {
- delete(c.fieldBuffers, i)
- }
- }
-}
-
-func (c *configurationVisitor) isSubscription(root int, path string) bool {
- rootOperationType := c.operation.OperationDefinitions[root].OperationType
- if rootOperationType != ast.OperationTypeSubscription {
- return false
- }
- return strings.Count(path, ".") == 1
-}
-
-type requiredFieldsVisitor struct {
- operation, definition *ast.Document
- walker *astvisitor.Walker
- config *Configuration
- operationName string
- skipFieldPaths []string
-}
-
-func (r *requiredFieldsVisitor) EnterDocument(operation, definition *ast.Document) {
- r.skipFieldPaths = r.skipFieldPaths[:0]
-}
-
-func (r *requiredFieldsVisitor) EnterField(ref int) {
- typeName := r.walker.EnclosingTypeDefinition.NameString(r.definition)
- fieldName := r.operation.FieldNameString(ref)
- fieldConfig := r.config.Fields.ForTypeField(typeName, fieldName)
- if fieldConfig == nil {
- return
- }
- if len(fieldConfig.RequiresFields) == 0 {
- return
- }
- selectionSet := r.walker.Ancestors[len(r.walker.Ancestors)-1]
- if selectionSet.Kind != ast.NodeKindSelectionSet {
- return
- }
- for i := range fieldConfig.RequiresFields {
- r.handleRequiredField(selectionSet.Ref, fieldConfig.RequiresFields[i])
- }
-}
-
-func (r *requiredFieldsVisitor) handleRequiredField(selectionSet int, requiredFieldName string) {
- for _, ref := range r.operation.SelectionSets[selectionSet].SelectionRefs {
- selection := r.operation.Selections[ref]
- if selection.Kind != ast.SelectionKindField {
- continue
- }
- name := r.operation.FieldAliasOrNameString(selection.Ref)
- if name == requiredFieldName {
- // already exists
- return
- }
- }
- r.addRequiredField(requiredFieldName, selectionSet)
-}
-
-func (r *requiredFieldsVisitor) addRequiredField(fieldName string, selectionSet int) {
- field := ast.Field{
- Name: r.operation.Input.AppendInputString(fieldName),
- }
- addedField := r.operation.AddField(field)
- selection := ast.Selection{
- Kind: ast.SelectionKindField,
- Ref: addedField.Ref,
- }
- r.operation.AddSelection(selectionSet, selection)
- addedFieldPath := r.walker.Path.DotDelimitedString() + "." + fieldName
- r.skipFieldPaths = append(r.skipFieldPaths, addedFieldPath)
-}
-
-func (r *requiredFieldsVisitor) EnterOperationDefinition(ref int) {
- operationName := r.operation.OperationDefinitionNameString(ref)
- if r.operationName != operationName {
- r.walker.SkipNode()
- return
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/resolve/engine.md b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/resolve/engine.md
deleted file mode 100644
index 728968b6685..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/resolve/engine.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# this document outlines the architecture for the GraphQL Engine
-
-## requirements
-
-- have multiple data sources to resolve an object (e.g. pass an ID to two functions and merge the result, similar to map reduce)
-- resolves @defer: splits query into multiple serially executable statements, each emitting a response object to the client
-- resolves @stream: splits query at the @stream directive to stream a list of objects to the client
-- resolves __type & __schema queries
-- injects variables correctly into GraphQL sub queries in case multiple GraphQL queries will be assembled
-- can map from data source response objects to correct GraphQL object structure
-- can map between upstream GraphQL Enums and downstream GraphQL Enums
-- can filter results from upstream data source based on custom plugin/middleware or predefined rules
-- resolves child data sources inside an array concurrently
-- can pass custom configuration to individual data sources, e.g. setting Headers for HTTP based data sources
-- can pass request data from the downstream client to an upstream server (e.g. Headers)
-- can have static data sources
-- can have streaming data sources, e.g. RabbitMQ, Kafka, NATS
-- can have GraphQL and non GraphQL data sources nested into each other
-- can have multiple root level fields attached to the same data source
-- returns an internal error in case the error is not recoverable
-- returns an external error to tell the user about the error
-- might return both an internal as well as an external error
-- there should be triggers which are similar to data sources in that they trigger a subscription but don't resolve it themselves, instead they hand over the resolving to a data source (this is useful e.g. when you want to trigger a subscription from mutations but the mutations don't contain the data to resolve the subscription so from the trigger a query needs to be fired to resolve the subscription)
-- for subscriptions with a trigger there should be an idempotent mechanism (configurable) to ensure that each trigger only fires one event in case that's the desired behaviour (e.g. polling an upstream but only emit changes)
-- object path selector for arguments should make use of existing mappings (planning)
-- can skip data source invocation based on conditions (e.g. missing field on parent object)
-- return number of nodes in response
-
-## implemented in execution
-
-- resolves operations containing unions & interfaces
-- resolves flat queries/mutations
-- can define __typename for individual objects returned by data sources (users should be able to set the __typename using a middleware/plugin or predefined rules)
-
-## implemented in planning
-
-query:
-resolve() -> client
-
-subscription:
-for {
- resolve() -> client
-}
-
-stream:
-resolveUser() -> client
-for i := range user.friends {
- resolveFriend(i) -> client
- resolvePet(friend) -> client
-}
-
-
-```go
-package resolving
-type Resolver interface {
- Resolve(ctx context.Context,userID string, config, input []byte) (output []byte, err error)
-}
-```
-
-QueryPlan:
- ResolveOneUser()
- ResolveUserFriends()
- ResolveManyPets()
\ No newline at end of file
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/resolve/resolve.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/resolve/resolve.go
deleted file mode 100644
index 8a252d1962c..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/resolve/resolve.go
+++ /dev/null
@@ -1,1570 +0,0 @@
-//go:generate mockgen -self_package=github.com/jensneuse/go-data-resolver/pkg/resolve -destination=resolve_mock_test.go -package=resolve . DataSource,BeforeFetchHook,AfterFetchHook
-
-package resolve
-
-import (
- "bytes"
- "context"
- "fmt"
- "hash"
- "io"
- "net/http"
- "net/textproto"
- "strconv"
- "sync"
- "time"
- "unicode"
-
- "github.com/buger/jsonparser"
- "github.com/cespare/xxhash"
-
- errors "golang.org/x/xerrors"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/subscription"
- "github.com/jensneuse/graphql-go-tools/pkg/fastbuffer"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/pool"
-)
-
-var (
- lBrace = []byte("{")
- rBrace = []byte("}")
- lBrack = []byte("[")
- rBrack = []byte("]")
- comma = []byte(",")
- colon = []byte(":")
- quote = []byte("\"")
- null = []byte("null")
- literalData = []byte("data")
- literalErrors = []byte("Errors")
- literalMessage = []byte("message")
- literalLocations = []byte("locations")
- literalPath = []byte("path")
-)
-
-var errNonNullableFieldValueIsNull = errors.New("non Nullable field value is null")
-var errTypeNameSkipped = errors.New("skipped because of __typename condition")
-var errHeaderPathInvalid = errors.New("invalid header path: header variables must be of this format: .request.header.{{ key }} ")
-
-type Node interface {
- NodeKind() NodeKind
-}
-
-type NodeKind int
-type FetchKind int
-
-const (
- NodeKindObject NodeKind = iota + 1
- NodeKindEmptyObject
- NodeKindArray
- NodeKindEmptyArray
- NodeKindNull
- NodeKindString
- NodeKindBoolean
- NodeKindInteger
- NodeKindFloat
-
- FetchKindSingle FetchKind = iota + 1
- FetchKindParallel
-)
-
-type HookContext struct {
- CurrentPath []byte
-}
-
-type BeforeFetchHook interface {
- OnBeforeFetch(ctx HookContext, input []byte)
-}
-
-type AfterFetchHook interface {
- OnData(ctx HookContext, output []byte, singleFlight bool)
- OnError(ctx HookContext, output []byte, singleFlight bool)
-}
-
-type Context struct {
- context.Context
- Variables []byte
- Request Request
- pathElements [][]byte
- patches []patch
- usedBuffers []*bytes.Buffer
- currentPatch int
- maxPatch int
- pathPrefix []byte
- beforeFetchHook BeforeFetchHook
- afterFetchHook AfterFetchHook
-}
-
-type Request struct {
- Header http.Header
-}
-
-func NewContext(ctx context.Context) *Context {
- return &Context{
- Context: ctx,
- Variables: make([]byte, 0, 4096),
- pathPrefix: make([]byte, 0, 4096),
- pathElements: make([][]byte, 0, 16),
- patches: make([]patch, 0, 48),
- usedBuffers: make([]*bytes.Buffer, 0, 48),
- currentPatch: -1,
- maxPatch: -1,
- }
-}
-
-func (c *Context) Free() {
- c.Context = nil
- c.Variables = c.Variables[:0]
- c.pathPrefix = c.pathPrefix[:0]
- c.pathElements = c.pathElements[:0]
- c.patches = c.patches[:0]
- for i := range c.usedBuffers {
- pool.BytesBuffer.Put(c.usedBuffers[i])
- }
- c.usedBuffers = c.usedBuffers[:0]
- c.currentPatch = -1
- c.maxPatch = -1
- c.beforeFetchHook = nil
- c.afterFetchHook = nil
- c.Request.Header = nil
-}
-
-func (c *Context) SetBeforeFetchHook(hook BeforeFetchHook) {
- c.beforeFetchHook = hook
-}
-
-func (c *Context) SetAfterFetchHook(hook AfterFetchHook) {
- c.afterFetchHook = hook
-}
-
-func (c *Context) addPathElement(elem []byte) {
- c.pathElements = append(c.pathElements, elem)
-}
-
-func (c *Context) addIntegerPathElement(elem int) {
- b := unsafebytes.StringToBytes(strconv.Itoa(elem))
- c.pathElements = append(c.pathElements, b)
-}
-
-func (c *Context) removeLastPathElement() {
- c.pathElements = c.pathElements[:len(c.pathElements)-1]
-}
-
-func (c *Context) path() []byte {
- buf := pool.BytesBuffer.Get()
- c.usedBuffers = append(c.usedBuffers, buf)
- if len(c.pathPrefix) != 0 {
- buf.Write(c.pathPrefix)
- } else {
- buf.Write(literal.SLASH)
- buf.Write(literal.DATA)
- }
- for i := range c.pathElements {
- if i == 0 && bytes.Equal(literal.DATA, c.pathElements[0]) {
- continue
- }
- _, _ = buf.Write(literal.SLASH)
- _, _ = buf.Write(c.pathElements[i])
- }
- return buf.Bytes()
-}
-
-func (c *Context) addPatch(index int, path, extraPath, data []byte) {
- next := patch{path: path, extraPath: extraPath, data: data, index: index}
- c.patches = append(c.patches, next)
- c.maxPatch++
-}
-
-func (c *Context) popNextPatch() (patch patch, ok bool) {
- c.currentPatch++
- if c.currentPatch > c.maxPatch {
- return patch, false
- }
- return c.patches[c.currentPatch], true
-}
-
-type patch struct {
- path, extraPath, data []byte
- index int
-}
-
-type Fetch interface {
- FetchKind() FetchKind
-}
-
-type Fetches []Fetch
-
-type DataSource interface {
- Load(ctx context.Context, input []byte, bufPair *BufPair) (err error)
- UniqueIdentifier() []byte
-}
-
-type Resolver struct {
- EnableSingleFlightLoader bool
- resultSetPool sync.Pool
- byteSlicesPool sync.Pool
- waitGroupPool sync.Pool
- bufPairPool sync.Pool
- bufPairSlicePool sync.Pool
- errChanPool sync.Pool
- hash64Pool sync.Pool
- inflightFetchPool sync.Pool
- inflightFetchMu sync.Mutex
- inflightFetches map[uint64]*inflightFetch
- triggerManagers map[uint64]*subscription.Manager
-}
-
-func (r *Resolver) RegisterTriggerManager(m *subscription.Manager) {
- hash64 := r.getHash64()
- _, _ = hash64.Write(m.UniqueIdentifier())
- managerID := hash64.Sum64()
- r.putHash64(hash64)
- r.triggerManagers[managerID] = m
-}
-
-type inflightFetch struct {
- waitLoad sync.WaitGroup
- waitFree sync.WaitGroup
- err error
- bufPair BufPair
-}
-
-func New() *Resolver {
- return &Resolver{
- resultSetPool: sync.Pool{
- New: func() interface{} {
- return &resultSet{
- buffers: make(map[int]*BufPair, 8),
- }
- },
- },
- byteSlicesPool: sync.Pool{
- New: func() interface{} {
- slice := make([][]byte, 0, 24)
- return &slice
- },
- },
- waitGroupPool: sync.Pool{
- New: func() interface{} {
- return &sync.WaitGroup{}
- },
- },
- bufPairPool: sync.Pool{
- New: func() interface{} {
- pair := BufPair{
- Data: fastbuffer.New(),
- Errors: fastbuffer.New(),
- }
- return &pair
- },
- },
- bufPairSlicePool: sync.Pool{
- New: func() interface{} {
- slice := make([]*BufPair, 0, 24)
- return &slice
- },
- },
- errChanPool: sync.Pool{
- New: func() interface{} {
- return make(chan error, 1)
- },
- },
- hash64Pool: sync.Pool{
- New: func() interface{} {
- return xxhash.New()
- },
- },
- inflightFetchPool: sync.Pool{
- New: func() interface{} {
- return &inflightFetch{
- bufPair: BufPair{
- Data: fastbuffer.New(),
- Errors: fastbuffer.New(),
- },
- }
- },
- },
- inflightFetches: map[uint64]*inflightFetch{},
- triggerManagers: map[uint64]*subscription.Manager{},
- }
-}
-
-func (r *Resolver) writeSafe(err error, writer io.Writer, data []byte) error {
- if err != nil {
- return err
- }
- _, err = writer.Write(data)
- return err
-}
-
-func (r *Resolver) resolveNode(ctx *Context, node Node, data []byte, bufPair *BufPair) (err error) {
- switch n := node.(type) {
- case *Object:
- return r.resolveObject(ctx, n, data, bufPair)
- case *Array:
- return r.resolveArray(ctx, n, data, bufPair)
- case *Null:
- if n.Defer.Enabled {
- r.preparePatch(ctx, n.Defer.PatchIndex, nil, data)
- }
- r.resolveNull(bufPair.Data)
- return
- case *String:
- return r.resolveString(n, data, bufPair)
- case *Boolean:
- return r.resolveBoolean(n, data, bufPair)
- case *Integer:
- return r.resolveInteger(n, data, bufPair)
- case *Float:
- return r.resolveFloat(n, data, bufPair)
- case *EmptyObject:
- r.resolveEmptyObject(bufPair.Data)
- return
- case *EmptyArray:
- r.resolveEmptyArray(bufPair.Data)
- return
- default:
- return
- }
-}
-
-func (r *Resolver) validateContext(ctx *Context) (err error) {
- if ctx.maxPatch != -1 || ctx.currentPatch != -1 {
- return fmt.Errorf("Context must be resetted using Free() before re-using it")
- }
- return nil
-}
-
-func (r *Resolver) ResolveGraphQLResponse(ctx *Context, response *GraphQLResponse, data []byte, writer io.Writer) (err error) {
-
- buf := r.getBufPair()
- defer r.freeBufPair(buf)
-
- err = r.resolveNode(ctx, response.Data, data, buf)
- if err != nil {
- return
- }
-
- hasErrors := buf.Errors.Len() != 0
- hasData := buf.Data.Len() != 0
-
- err = r.writeSafe(err, writer, lBrace)
-
- if hasErrors {
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, literalErrors)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, colon)
- err = r.writeSafe(err, writer, lBrack)
- _, err = writer.Write(buf.Errors.Bytes())
- err = r.writeSafe(err, writer, rBrack)
- }
-
- if hasData {
- if hasErrors {
- err = r.writeSafe(err, writer, comma)
- }
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, literalData)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, colon)
- _, err = writer.Write(buf.Data.Bytes())
- }
-
- err = r.writeSafe(err, writer, rBrace)
-
- return
-}
-
-func (r *Resolver) ResolveGraphQLSubscription(ctx *Context, subscription *GraphQLSubscription, writer FlushWriter) (err error) {
- hash64 := r.getHash64()
- _, _ = hash64.Write(subscription.Trigger.ManagerID)
- managerID := hash64.Sum64()
- r.putHash64(hash64)
-
- manager, ok := r.triggerManagers[managerID]
- if !ok {
- return fmt.Errorf("trigger manager not found for id: %s", string(subscription.Trigger.ManagerID))
- }
-
- buf := r.getBufPair()
- err = subscription.Trigger.InputTemplate.Render(ctx, nil, buf.Data)
- if err != nil {
- return
- }
- rendered := buf.Data.Bytes()
- triggerInput := make([]byte, len(rendered))
- copy(triggerInput, rendered)
- r.freeBufPair(buf)
-
- trigger := manager.StartTrigger(triggerInput)
- defer manager.StopTrigger(trigger)
-
- for {
- data, ok := trigger.Next(ctx)
- if !ok {
- return nil
- }
- err = r.ResolveGraphQLResponse(ctx, subscription.Response, data, writer)
- if err != nil {
- return err
- }
- writer.Flush()
- }
-}
-
-func (r *Resolver) ResolveGraphQLStreamingResponse(ctx *Context, response *GraphQLStreamingResponse, data []byte, writer FlushWriter) (err error) {
-
- if err := r.validateContext(ctx); err != nil {
- return err
- }
-
- err = r.ResolveGraphQLResponse(ctx, response.InitialResponse, data, writer)
- if err != nil {
- return err
- }
- writer.Flush()
-
- nextFlush := time.Now().Add(time.Millisecond * time.Duration(response.FlushInterval))
-
- buf := pool.BytesBuffer.Get()
- defer pool.BytesBuffer.Put(buf)
-
- buf.Write(literal.LBRACK)
-
- done := ctx.Context.Done()
-
-Loop:
- for {
- select {
- case <-done:
- return
- default:
- patch, ok := ctx.popNextPatch()
- if !ok {
- break Loop
- }
-
- if patch.index > len(response.Patches)-1 {
- continue
- }
-
- if buf.Len() != 1 {
- buf.Write(literal.COMMA)
- }
-
- preparedPatch := response.Patches[patch.index]
- err = r.ResolveGraphQLResponsePatch(ctx, preparedPatch, patch.data, patch.path, patch.extraPath, buf)
- if err != nil {
- return err
- }
-
- now := time.Now()
- if now.After(nextFlush) {
- buf.Write(literal.RBRACK)
- _, err = writer.Write(buf.Bytes())
- if err != nil {
- return err
- }
- writer.Flush()
- buf.Reset()
- buf.Write(literal.LBRACK)
- nextFlush = time.Now().Add(time.Millisecond * time.Duration(response.FlushInterval))
- }
- }
- }
-
- if buf.Len() != 1 {
- buf.Write(literal.RBRACK)
- _, err = writer.Write(buf.Bytes())
- if err != nil {
- return err
- }
- writer.Flush()
- }
-
- return
-}
-
-func (r *Resolver) ResolveGraphQLResponsePatch(ctx *Context, patch *GraphQLResponsePatch, data, path, extraPath []byte, writer io.Writer) (err error) {
-
- buf := r.getBufPair()
- defer r.freeBufPair(buf)
-
- ctx.pathPrefix = append(path, extraPath...)
-
- if patch.Fetch != nil {
- set := r.getResultSet()
- defer r.freeResultSet(set)
- err = r.resolveFetch(ctx, patch.Fetch, data, set)
- if err != nil {
- return err
- }
- _, ok := set.buffers[0]
- if ok {
- r.MergeBufPairErrors(set.buffers[0], buf)
- data = set.buffers[0].Data.Bytes()
- }
- }
-
- err = r.resolveNode(ctx, patch.Value, data, buf)
- if err != nil {
- return
- }
-
- hasErrors := buf.Errors.Len() != 0
- hasData := buf.Data.Len() != 0
-
- if hasErrors {
- return
- }
-
- if hasData {
- if hasErrors {
- err = r.writeSafe(err, writer, comma)
- }
- err = r.writeSafe(err, writer, lBrace)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, literal.OP)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, colon)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, patch.Operation)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, comma)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, literal.PATH)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, colon)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, path)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, comma)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, literal.VALUE)
- err = r.writeSafe(err, writer, quote)
- err = r.writeSafe(err, writer, colon)
- _, err = writer.Write(buf.Data.Bytes())
- err = r.writeSafe(err, writer, rBrace)
- }
-
- return
-}
-
-func (r *Resolver) resolveEmptyArray(b *fastbuffer.FastBuffer) {
- b.WriteBytes(lBrack)
- b.WriteBytes(rBrack)
-}
-
-func (r *Resolver) resolveEmptyObject(b *fastbuffer.FastBuffer) {
- b.WriteBytes(lBrace)
- b.WriteBytes(rBrace)
-}
-
-func (r *Resolver) resolveArray(ctx *Context, array *Array, data []byte, arrayBuf *BufPair) (err error) {
-
- arrayItems := r.byteSlicesPool.Get().(*[][]byte)
- defer func() {
- *arrayItems = (*arrayItems)[:0]
- r.byteSlicesPool.Put(arrayItems)
- }()
-
- _, err = jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
- *arrayItems = append(*arrayItems, value)
- }, array.Path...)
-
- if len(*arrayItems) == 0 {
- if !array.Nullable {
- r.resolveEmptyArray(arrayBuf.Data)
- return nil
- }
- r.resolveNull(arrayBuf.Data)
- return nil
- }
-
- if array.ResolveAsynchronous && !array.Stream.Enabled {
- return r.resolveArrayAsynchronous(ctx, array, arrayItems, arrayBuf)
- }
- return r.resolveArraySynchronous(ctx, array, arrayItems, arrayBuf)
-}
-
-func (r *Resolver) resolveArraySynchronous(ctx *Context, array *Array, arrayItems *[][]byte, arrayBuf *BufPair) (err error) {
-
- itemBuf := r.getBufPair()
- defer r.freeBufPair(itemBuf)
-
- arrayBuf.Data.WriteBytes(lBrack)
- var (
- hasPreviousItem bool
- dataWritten int
- )
- for i := range *arrayItems {
-
- if array.Stream.Enabled {
- if i > array.Stream.InitialBatchSize-1 {
- ctx.addIntegerPathElement(i)
- r.preparePatch(ctx, array.Stream.PatchIndex, nil, (*arrayItems)[i])
- ctx.removeLastPathElement()
- continue
- }
- }
-
- ctx.addIntegerPathElement(i)
- err = r.resolveNode(ctx, array.Item, (*arrayItems)[i], itemBuf)
- ctx.removeLastPathElement()
- if err != nil {
- if errors.Is(err, errNonNullableFieldValueIsNull) && array.Nullable {
- arrayBuf.Data.Reset()
- r.resolveNull(arrayBuf.Data)
- return nil
- }
- if errors.Is(err, errTypeNameSkipped) {
- err = nil
- continue
- }
- return
- }
- dataWritten += itemBuf.Data.Len()
- r.MergeBufPairs(itemBuf, arrayBuf, hasPreviousItem)
- if !hasPreviousItem && dataWritten != 0 {
- hasPreviousItem = true
- }
- }
-
- arrayBuf.Data.WriteBytes(rBrack)
- return
-}
-
-func (r *Resolver) resolveArrayAsynchronous(ctx *Context, array *Array, arrayItems *[][]byte, arrayBuf *BufPair) (err error) {
-
- arrayBuf.Data.WriteBytes(lBrack)
-
- bufSlice := r.getBufPairSlice()
- defer r.freeBufPairSlice(bufSlice)
-
- wg := r.getWaitGroup()
- defer r.freeWaitGroup(wg)
-
- errCh := r.getErrChan()
- defer r.freeErrChan(errCh)
-
- wg.Add(len(*arrayItems))
-
- for i := range *arrayItems {
- itemBuf := r.getBufPair()
- *bufSlice = append(*bufSlice, itemBuf)
- itemData := (*arrayItems)[i]
- go func(ctx Context, i int) {
- ctx.addPathElement([]byte(strconv.Itoa(i)))
- if e := r.resolveNode(&ctx, array.Item, itemData, itemBuf); e != nil && !errors.Is(e, errTypeNameSkipped) {
- select {
- case errCh <- e:
- default:
- }
- }
- wg.Done()
- }(*ctx, i)
- }
-
- wg.Wait()
-
- select {
- case err = <-errCh:
- default:
- }
-
- if err != nil {
- if errors.Is(err, errNonNullableFieldValueIsNull) && array.Nullable {
- arrayBuf.Data.Reset()
- r.resolveNull(arrayBuf.Data)
- return nil
- }
- return
- }
-
- var (
- hasPreviousItem bool
- dataWritten int
- )
- for i := range *bufSlice {
- dataWritten += (*bufSlice)[i].Data.Len()
- r.MergeBufPairs((*bufSlice)[i], arrayBuf, hasPreviousItem)
- if !hasPreviousItem && dataWritten != 0 {
- hasPreviousItem = true
- }
- }
-
- arrayBuf.Data.WriteBytes(rBrack)
- return
-}
-
-func (r *Resolver) resolveInteger(integer *Integer, data []byte, integerBuf *BufPair) error {
- value, dataType, _, err := jsonparser.Get(data, integer.Path...)
- if err != nil || dataType != jsonparser.Number {
- if !integer.Nullable {
- return errNonNullableFieldValueIsNull
- }
- r.resolveNull(integerBuf.Data)
- return nil
- }
- integerBuf.Data.WriteBytes(value)
- return nil
-}
-
-func (r *Resolver) resolveFloat(floatValue *Float, data []byte, floatBuf *BufPair) error {
- value, dataType, _, err := jsonparser.Get(data, floatValue.Path...)
- if err != nil || dataType != jsonparser.Number {
- if !floatValue.Nullable {
- return errNonNullableFieldValueIsNull
- }
- r.resolveNull(floatBuf.Data)
- return nil
- }
- floatBuf.Data.WriteBytes(value)
- return nil
-}
-
-func (r *Resolver) resolveBoolean(boolean *Boolean, data []byte, booleanBuf *BufPair) error {
- value, valueType, _, err := jsonparser.Get(data, boolean.Path...)
- if err != nil || valueType != jsonparser.Boolean {
- if !boolean.Nullable {
- return errNonNullableFieldValueIsNull
- }
- r.resolveNull(booleanBuf.Data)
- return nil
- }
- booleanBuf.Data.WriteBytes(value)
- return nil
-}
-
-func (r *Resolver) resolveString(str *String, data []byte, stringBuf *BufPair) error {
- var (
- value []byte
- valueType jsonparser.ValueType
- err error
- )
- if len(data) != 0 && str.Path == nil {
- _, valueType, _, _ = jsonparser.Get(data)
- if valueType == jsonparser.String || unicode.IsLetter(rune(data[0])) {
- value = data
- } else if !str.Nullable {
- return errNonNullableFieldValueIsNull
- } else {
- r.resolveNull(stringBuf.Data)
- return nil
- }
- }
- if value == nil {
- value, valueType, _, err = jsonparser.Get(data, str.Path...)
- if err != nil || valueType != jsonparser.String {
- if !str.Nullable {
- return errNonNullableFieldValueIsNull
- }
- r.resolveNull(stringBuf.Data)
- return nil
- }
- }
- if value == nil && !str.Nullable {
- return errNonNullableFieldValueIsNull
- }
- stringBuf.Data.WriteBytes(quote)
- stringBuf.Data.WriteBytes(value)
- stringBuf.Data.WriteBytes(quote)
- return nil
-}
-
-func (r *Resolver) preparePatch(ctx *Context, patchIndex int, extraPath, data []byte) {
- buf := pool.BytesBuffer.Get()
- ctx.usedBuffers = append(ctx.usedBuffers, buf)
- _, _ = buf.Write(data)
- path, data := ctx.path(), buf.Bytes()
- ctx.addPatch(patchIndex, path, extraPath, data)
-}
-
-func (r *Resolver) resolveNull(b *fastbuffer.FastBuffer) {
- b.WriteBytes(null)
-}
-
-func (r *Resolver) resolveObject(ctx *Context, object *Object, data []byte, objectBuf *BufPair) (err error) {
-
- if len(object.Path) != 0 {
- data, _, _, _ = jsonparser.Get(data, object.Path...)
- }
-
- var set *resultSet
- if object.Fetch != nil {
- set = r.getResultSet()
- defer r.freeResultSet(set)
- err = r.resolveFetch(ctx, object.Fetch, data, set)
- if err != nil {
- return
- }
- for i := range set.buffers {
- r.MergeBufPairErrors(set.buffers[i], objectBuf)
- }
- }
-
- fieldBuf := r.getBufPair()
- defer r.freeBufPair(fieldBuf)
-
- typeNameSkip := false
- first := true
- for i := range object.Fields {
-
- var fieldData []byte
- if set != nil && object.Fields[i].HasBuffer {
- buffer, ok := set.buffers[object.Fields[i].BufferID]
- if ok {
- fieldData = buffer.Data.Bytes()
- }
- } else {
- fieldData = data
- }
-
- if object.Fields[i].OnTypeName != nil {
- typeName, _, _, _ := jsonparser.Get(fieldData, "__typename")
- if !bytes.Equal(typeName, object.Fields[i].OnTypeName) {
- typeNameSkip = true
- continue
- }
- }
-
- if first {
- objectBuf.Data.WriteBytes(lBrace)
- first = false
- } else {
- objectBuf.Data.WriteBytes(comma)
- }
- objectBuf.Data.WriteBytes(quote)
- objectBuf.Data.WriteBytes(object.Fields[i].Name)
- objectBuf.Data.WriteBytes(quote)
- objectBuf.Data.WriteBytes(colon)
- ctx.addPathElement(object.Fields[i].Name)
- err = r.resolveNode(ctx, object.Fields[i].Value, fieldData, fieldBuf)
- ctx.removeLastPathElement()
- if err != nil {
- if errors.Is(err, errNonNullableFieldValueIsNull) && object.Nullable {
- objectBuf.Data.Reset()
- r.resolveNull(objectBuf.Data)
- return nil
- }
- return
- }
- r.MergeBufPairs(fieldBuf, objectBuf, false)
- }
- if first {
- if !object.Nullable {
- if typeNameSkip {
- return errTypeNameSkipped
- }
- return errNonNullableFieldValueIsNull
- }
- r.resolveNull(objectBuf.Data)
- return
- }
- objectBuf.Data.WriteBytes(rBrace)
- return
-}
-
-func (r *Resolver) freeResultSet(set *resultSet) {
- for i := range set.buffers {
- set.buffers[i].Reset()
- r.bufPairPool.Put(set.buffers[i])
- delete(set.buffers, i)
- }
- r.resultSetPool.Put(set)
-}
-
-func (r *Resolver) resolveFetch(ctx *Context, fetch Fetch, data []byte, set *resultSet) (err error) {
- switch f := fetch.(type) {
- case *SingleFetch:
- preparedInput := r.getBufPair()
- defer r.freeBufPair(preparedInput)
- err = r.prepareSingleFetch(ctx, f, data, set, preparedInput.Data)
- if err != nil {
- return err
- }
- err = r.resolveSingleFetch(ctx, f, preparedInput.Data, set.buffers[f.BufferId])
- case *ParallelFetch:
- preparedInputs := r.getBufPairSlice()
- defer r.freeBufPairSlice(preparedInputs)
- for i := range f.Fetches {
- preparedInput := r.getBufPair()
- err = r.prepareSingleFetch(ctx, f.Fetches[i], data, set, preparedInput.Data)
- if err != nil {
- return err
- }
- *preparedInputs = append(*preparedInputs, preparedInput)
- }
- wg := r.getWaitGroup()
- defer r.freeWaitGroup(wg)
- for i := range f.Fetches {
- preparedInput := (*preparedInputs)[i]
- singleFetch := f.Fetches[i]
- buf := set.buffers[f.Fetches[i].BufferId]
- wg.Add(1)
- go func(s *SingleFetch, buf *BufPair) {
- _ = r.resolveSingleFetch(ctx, s, preparedInput.Data, buf)
- wg.Done()
- }(singleFetch, buf)
- }
- wg.Wait()
- }
- return
-}
-
-func (r *Resolver) prepareSingleFetch(ctx *Context, fetch *SingleFetch, data []byte, set *resultSet, preparedInput *fastbuffer.FastBuffer) (err error) {
- err = fetch.InputTemplate.Render(ctx, data, preparedInput)
- buf := r.getBufPair()
- set.buffers[fetch.BufferId] = buf
- return
-}
-
-func (r *Resolver) resolveSingleFetch(ctx *Context, fetch *SingleFetch, preparedInput *fastbuffer.FastBuffer, buf *BufPair) (err error) {
-
- if ctx.beforeFetchHook != nil {
- ctx.beforeFetchHook.OnBeforeFetch(r.hookCtx(ctx), preparedInput.Bytes())
- }
-
- if !r.EnableSingleFlightLoader || fetch.DisallowSingleFlight {
- err = fetch.DataSource.Load(ctx.Context, preparedInput.Bytes(), buf)
- if ctx.afterFetchHook != nil {
- if buf.HasData() {
- ctx.afterFetchHook.OnData(r.hookCtx(ctx), buf.Data.Bytes(), false)
- }
- if buf.HasErrors() {
- ctx.afterFetchHook.OnError(r.hookCtx(ctx), buf.Errors.Bytes(), false)
- }
- }
- return
- }
-
- hash64 := r.getHash64()
- _, _ = hash64.Write(fetch.DataSource.UniqueIdentifier())
- _, _ = hash64.Write(preparedInput.Bytes())
- fetchID := hash64.Sum64()
- r.putHash64(hash64)
-
- r.inflightFetchMu.Lock()
- inflight, ok := r.inflightFetches[fetchID]
- if ok {
- inflight.waitFree.Add(1)
- defer inflight.waitFree.Done()
- r.inflightFetchMu.Unlock()
- inflight.waitLoad.Wait()
- if inflight.bufPair.HasData() {
- if ctx.afterFetchHook != nil {
- ctx.afterFetchHook.OnData(r.hookCtx(ctx), inflight.bufPair.Data.Bytes(), true)
- }
- buf.Data.WriteBytes(inflight.bufPair.Data.Bytes())
- }
- if inflight.bufPair.HasErrors() {
- if ctx.afterFetchHook != nil {
- ctx.afterFetchHook.OnError(r.hookCtx(ctx), inflight.bufPair.Errors.Bytes(), true)
- }
- buf.Errors.WriteBytes(inflight.bufPair.Errors.Bytes())
- }
- return inflight.err
- }
-
- inflight = r.getInflightFetch()
- inflight.waitLoad.Add(1)
- r.inflightFetches[fetchID] = inflight
-
- r.inflightFetchMu.Unlock()
-
- err = fetch.DataSource.Load(ctx.Context, preparedInput.Bytes(), &inflight.bufPair)
- inflight.err = err
-
- if inflight.bufPair.HasData() {
- if ctx.afterFetchHook != nil {
- ctx.afterFetchHook.OnData(r.hookCtx(ctx), inflight.bufPair.Data.Bytes(), false)
- }
- buf.Data.WriteBytes(inflight.bufPair.Data.Bytes())
- }
-
- if inflight.bufPair.HasErrors() {
- if ctx.afterFetchHook != nil {
- ctx.afterFetchHook.OnError(r.hookCtx(ctx), inflight.bufPair.Errors.Bytes(), true)
- }
- buf.Errors.WriteBytes(inflight.bufPair.Errors.Bytes())
- }
-
- inflight.waitLoad.Done()
-
- r.inflightFetchMu.Lock()
- delete(r.inflightFetches, fetchID)
- r.inflightFetchMu.Unlock()
-
- go func() {
- inflight.waitFree.Wait()
- r.freeInflightFetch(inflight)
- }()
-
- return
-}
-
-func (r *Resolver) hookCtx(ctx *Context) HookContext {
- return HookContext{
- CurrentPath: ctx.path(),
- }
-}
-
-type Object struct {
- Nullable bool
- Path []string
- Fields []*Field
- Fetch Fetch
-}
-
-func (_ *Object) NodeKind() NodeKind {
- return NodeKindObject
-}
-
-type EmptyObject struct{}
-
-func (_ *EmptyObject) NodeKind() NodeKind {
- return NodeKindEmptyObject
-}
-
-type EmptyArray struct{}
-
-func (_ *EmptyArray) NodeKind() NodeKind {
- return NodeKindEmptyArray
-}
-
-type Field struct {
- Name []byte
- Value Node
- Defer *DeferField
- Stream *StreamField
- HasBuffer bool
- BufferID int
- OnTypeName []byte
-}
-
-type StreamField struct {
- InitialBatchSize int
-}
-
-type DeferField struct{}
-
-type Null struct {
- Defer Defer
-}
-
-type Defer struct {
- Enabled bool
- PatchIndex int
-}
-
-func (_ *Null) NodeKind() NodeKind {
- return NodeKindNull
-}
-
-type resultSet struct {
- buffers map[int]*BufPair
-}
-
-type SingleFetch struct {
- BufferId int
- Input string
- DataSource DataSource
- Variables Variables
- // DisallowSingleFlight is used for write operations like mutations, POST, DELETE etc. to disable singleFlight
- // By default SingleFlight for fetches is disabled and needs to be enabled on the Resolver first
- // If the resolver allows SingleFlight it's up the each individual DataSource Planner to decide whether an Operation
- // should be allowed to use SingleFlight
- DisallowSingleFlight bool
- InputTemplate InputTemplate
-}
-
-type InputTemplate struct {
- Segments []TemplateSegment
-}
-
-func (i *InputTemplate) Render(ctx *Context, data []byte, preparedInput *fastbuffer.FastBuffer) (err error) {
- for j := range i.Segments {
- switch i.Segments[j].SegmentType {
- case StaticSegmentType:
- preparedInput.WriteBytes(i.Segments[j].Data)
- case VariableSegmentType:
- switch i.Segments[j].VariableSource {
- case VariableSourceObject:
- err = i.renderObjectVariable(data, i.Segments[j].VariableSourcePath, preparedInput)
- case VariableSourceContext:
- err = i.renderContextVariable(ctx, i.Segments[j].VariableSourcePath, preparedInput)
- case VariableSourceRequestHeader:
- err = i.renderHeaderVariable(ctx, i.Segments[j].VariableSourcePath, preparedInput)
- default:
- err = fmt.Errorf("InputTemplate.Render: cannot resolve variable of kind: %d", i.Segments[j].VariableSource)
- }
- if err != nil {
- return err
- }
- }
- }
- return
-}
-
-func (i *InputTemplate) renderObjectVariable(data []byte, path []string, preparedInput *fastbuffer.FastBuffer) error {
- value, _, _, err := jsonparser.Get(data, path...)
- if err != nil {
- return err
- }
- preparedInput.WriteBytes(value)
- return nil
-}
-
-func (i *InputTemplate) renderContextVariable(ctx *Context, path []string, preparedInput *fastbuffer.FastBuffer) error {
- value, _, _, err := jsonparser.Get(ctx.Variables, path...)
- if err != nil {
- return err
- }
- preparedInput.WriteBytes(value)
- return nil
-}
-
-func (i *InputTemplate) renderHeaderVariable(ctx *Context, path []string, preparedInput *fastbuffer.FastBuffer) error {
- if len(path) != 1 {
- return errHeaderPathInvalid
- }
- // Header.Values is available from go 1.14
- // value := ctx.Request.Header.Values(path[0])
- // could be simplified once go 1.12 support will be dropped
- canonicalName := textproto.CanonicalMIMEHeaderKey(path[0])
- value := ctx.Request.Header[canonicalName]
- if len(value) == 0 {
- return nil
- }
- if len(value) == 1 {
- preparedInput.WriteString(value[0])
- return nil
- }
- for j := range value {
- if j != 0 {
- preparedInput.WriteBytes(literal.COMMA)
- }
- preparedInput.WriteString(value[j])
- }
- return nil
-}
-
-type SegmentType int
-type VariableSource int
-
-const (
- StaticSegmentType SegmentType = iota + 1
- VariableSegmentType
-
- VariableSourceObject VariableSource = iota + 1
- VariableSourceContext
- VariableSourceRequestHeader
-)
-
-type TemplateSegment struct {
- SegmentType SegmentType
- Data []byte
- VariableSource VariableSource
- VariableSourcePath []string
-}
-
-func (_ *SingleFetch) FetchKind() FetchKind {
- return FetchKindSingle
-}
-
-type ParallelFetch struct {
- Fetches []*SingleFetch
-}
-
-func (_ *ParallelFetch) FetchKind() FetchKind {
- return FetchKindParallel
-}
-
-type String struct {
- Path []string
- Nullable bool
-}
-
-func (_ *String) NodeKind() NodeKind {
- return NodeKindString
-}
-
-type Boolean struct {
- Path []string
- Nullable bool
-}
-
-func (_ *Boolean) NodeKind() NodeKind {
- return NodeKindBoolean
-}
-
-type Float struct {
- Path []string
- Nullable bool
-}
-
-func (_ *Float) NodeKind() NodeKind {
- return NodeKindFloat
-}
-
-type Integer struct {
- Path []string
- Nullable bool
-}
-
-func (_ *Integer) NodeKind() NodeKind {
- return NodeKindInteger
-}
-
-type Array struct {
- Path []string
- Nullable bool
- ResolveAsynchronous bool
- Item Node
- Stream Stream
-}
-
-type Stream struct {
- Enabled bool
- InitialBatchSize int
- PatchIndex int
-}
-
-func (_ *Array) NodeKind() NodeKind {
- return NodeKindArray
-}
-
-type Variable interface {
- VariableKind() VariableKind
- Equals(another Variable) bool
- TemplateSegment() TemplateSegment
-}
-
-type Variables []Variable
-
-func NewVariables(variables ...Variable) Variables {
- return variables
-}
-
-const (
- variablePrefixSuffix = "$$"
- quotes = "\""
-)
-
-func (v *Variables) AddVariable(variable Variable, quoteValue bool) (name string, exists bool) {
- index := -1
- for i := range *v {
- if (*v)[i].Equals(variable) {
- index = i
- exists = true
- break
- }
- }
- if index == -1 {
- *v = append(*v, variable)
- index = len(*v) - 1
- }
- i := strconv.Itoa(index)
- name = variablePrefixSuffix + i + variablePrefixSuffix
- if quoteValue {
- name = quotes + name + quotes
- }
- return
-}
-
-type VariableKind int
-
-const (
- VariableKindContext VariableKind = iota + 1
- VariableKindObject
- VariableKindHeader
-)
-
-type ContextVariable struct {
- Path []string
-}
-
-func (c *ContextVariable) TemplateSegment() TemplateSegment {
- return TemplateSegment{
- SegmentType: VariableSegmentType,
- VariableSource: VariableSourceContext,
- VariableSourcePath: c.Path,
- }
-}
-
-func (c *ContextVariable) Equals(another Variable) bool {
- if another == nil {
- return false
- }
- if another.VariableKind() != c.VariableKind() {
- return false
- }
- anotherContextVariable := another.(*ContextVariable)
- if len(c.Path) != len(anotherContextVariable.Path) {
- return false
- }
- for i := range c.Path {
- if c.Path[i] != anotherContextVariable.Path[i] {
- return false
- }
- }
- return true
-}
-
-func (_ *ContextVariable) VariableKind() VariableKind {
- return VariableKindContext
-}
-
-type ObjectVariable struct {
- Path []string
-}
-
-func (o *ObjectVariable) TemplateSegment() TemplateSegment {
- return TemplateSegment{
- SegmentType: VariableSegmentType,
- VariableSource: VariableSourceObject,
- VariableSourcePath: o.Path,
- }
-}
-
-func (o *ObjectVariable) Equals(another Variable) bool {
- if another == nil {
- return false
- }
- if another.VariableKind() != o.VariableKind() {
- return false
- }
- anotherObjectVariable := another.(*ObjectVariable)
- if len(o.Path) != len(anotherObjectVariable.Path) {
- return false
- }
- for i := range o.Path {
- if o.Path[i] != anotherObjectVariable.Path[i] {
- return false
- }
- }
- return true
-}
-
-func (o *ObjectVariable) VariableKind() VariableKind {
- return VariableKindObject
-}
-
-type HeaderVariable struct {
- Path []string
-}
-
-func (h *HeaderVariable) TemplateSegment() TemplateSegment {
- return TemplateSegment{
- SegmentType: VariableSegmentType,
- VariableSource: VariableSourceRequestHeader,
- VariableSourcePath: h.Path,
- }
-}
-
-func (h *HeaderVariable) VariableKind() VariableKind {
- return VariableKindHeader
-}
-
-func (h *HeaderVariable) Equals(another Variable) bool {
- if another == nil {
- return false
- }
- if another.VariableKind() != h.VariableKind() {
- return false
- }
- anotherHeaderVariable := another.(*HeaderVariable)
- if len(h.Path) != len(anotherHeaderVariable.Path) {
- return false
- }
- for i := range h.Path {
- if h.Path[i] != anotherHeaderVariable.Path[i] {
- return false
- }
- }
- return true
-}
-
-type GraphQLSubscription struct {
- Trigger GraphQLSubscriptionTrigger
- Response *GraphQLResponse
-}
-
-type GraphQLSubscriptionTrigger struct {
- ManagerID []byte
- Input string
- InputTemplate InputTemplate
- Variables Variables
-}
-
-type FlushWriter interface {
- io.Writer
- Flush()
-}
-
-type GraphQLResponse struct {
- Data Node
-}
-
-type GraphQLStreamingResponse struct {
- InitialResponse *GraphQLResponse
- Patches []*GraphQLResponsePatch
- FlushInterval int64
-}
-
-type GraphQLResponsePatch struct {
- Value Node
- Fetch Fetch
- Operation []byte
-}
-
-type BufPair struct {
- Data *fastbuffer.FastBuffer
- Errors *fastbuffer.FastBuffer
-}
-
-func NewBufPair() *BufPair {
- return &BufPair{
- Data: fastbuffer.New(),
- Errors: fastbuffer.New(),
- }
-}
-
-func (b *BufPair) HasData() bool {
- return b.Data.Len() != 0
-}
-
-func (b *BufPair) HasErrors() bool {
- return b.Errors.Len() != 0
-}
-
-func (b *BufPair) Reset() {
- b.Data.Reset()
- b.Errors.Reset()
-}
-
-func (b *BufPair) writeErrors(data []byte) {
- b.Errors.WriteBytes(data)
-}
-
-func (b *BufPair) WriteErr(message, locations, path []byte) {
- if b.HasErrors() {
- b.writeErrors(comma)
- }
- b.writeErrors(lBrace)
- b.writeErrors(quote)
- b.writeErrors(literalMessage)
- b.writeErrors(quote)
- b.writeErrors(colon)
- b.writeErrors(quote)
- b.writeErrors(message)
- b.writeErrors(quote)
- if locations != nil {
- b.writeErrors(comma)
- b.writeErrors(quote)
- b.writeErrors(literalLocations)
- b.writeErrors(quote)
- b.writeErrors(colon)
- b.writeErrors(locations)
- }
- if path != nil {
- b.writeErrors(comma)
- b.writeErrors(quote)
- b.writeErrors(literalPath)
- b.writeErrors(quote)
- b.writeErrors(colon)
- b.writeErrors(path)
- }
- b.writeErrors(rBrace)
-}
-
-func (r *Resolver) MergeBufPairs(from, to *BufPair, prefixDataWithComma bool) {
- r.MergeBufPairData(from, to, prefixDataWithComma)
- r.MergeBufPairErrors(from, to)
-}
-
-func (r *Resolver) MergeBufPairData(from, to *BufPair, prefixDataWithComma bool) {
- if !from.HasData() {
- return
- }
- if prefixDataWithComma {
- to.Data.WriteBytes(comma)
- }
- to.Data.WriteBytes(from.Data.Bytes())
- from.Data.Reset()
-}
-
-func (r *Resolver) MergeBufPairErrors(from, to *BufPair) {
- if !from.HasErrors() {
- return
- }
- if to.HasErrors() {
- to.Errors.WriteBytes(comma)
- }
- to.Errors.WriteBytes(from.Errors.Bytes())
- from.Errors.Reset()
-}
-
-func (r *Resolver) freeBufPair(pair *BufPair) {
- pair.Data.Reset()
- pair.Errors.Reset()
- r.bufPairPool.Put(pair)
-}
-
-func (r *Resolver) getResultSet() *resultSet {
- return r.resultSetPool.Get().(*resultSet)
-}
-
-func (r *Resolver) getBufPair() *BufPair {
- return r.bufPairPool.Get().(*BufPair)
-}
-
-func (r *Resolver) getBufPairSlice() *[]*BufPair {
- return r.bufPairSlicePool.Get().(*[]*BufPair)
-}
-
-func (r *Resolver) freeBufPairSlice(slice *[]*BufPair) {
- for i := range *slice {
- r.freeBufPair((*slice)[i])
- }
- *slice = (*slice)[:0]
- r.bufPairSlicePool.Put(slice)
-}
-
-func (r *Resolver) getErrChan() chan error {
- return r.errChanPool.Get().(chan error)
-}
-
-func (r *Resolver) freeErrChan(ch chan error) {
- r.errChanPool.Put(ch)
-}
-
-func (r *Resolver) getWaitGroup() *sync.WaitGroup {
- return &sync.WaitGroup{}
-}
-
-func (r *Resolver) freeWaitGroup(wg *sync.WaitGroup) {
- r.waitGroupPool.Put(wg)
-}
-
-func (r *Resolver) getInflightFetch() *inflightFetch {
- return r.inflightFetchPool.Get().(*inflightFetch)
-}
-
-func (r *Resolver) freeInflightFetch(f *inflightFetch) {
- f.bufPair.Data.Reset()
- f.bufPair.Errors.Reset()
- f.err = nil
- r.inflightFetchPool.Put(f)
-}
-
-func (r *Resolver) getHash64() hash.Hash64 {
- return r.hash64Pool.Get().(hash.Hash64)
-}
-
-func (r *Resolver) putHash64(h hash.Hash64) {
- h.Reset()
- r.hash64Pool.Put(h)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/http_polling/http_polling.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/http_polling/http_polling.go
deleted file mode 100644
index 10f8eb2ddff..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/http_polling/http_polling.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package http_polling
-
-import (
- "bytes"
- "context"
- "strconv"
- "time"
-
- "github.com/buger/jsonparser"
- "github.com/cespare/xxhash"
- "github.com/tidwall/sjson"
-
- "github.com/jensneuse/graphql-go-tools/pkg/engine/datasource/httpclient"
-)
-
-func SetInputIntervalMillis(input []byte, interval int64) []byte {
- out, _ := sjson.SetRawBytes(input, "interval", []byte(strconv.FormatInt(interval, 10)))
- return out
-}
-
-func SetRequestInput(input, requestInput []byte) []byte {
- out, _ := sjson.SetRawBytes(input, "request_input", requestInput)
- return out
-}
-
-func SetSkipPublishSameResponse(input []byte, skip bool) []byte {
- skipBytes := []byte("false")
- if skip {
- skipBytes = []byte("true")
- }
- out, _ := sjson.SetRawBytes(input, "skip_publish_same_response", skipBytes)
- return out
-}
-
-var (
- HttpPolling = []byte("http_polling_stream")
-)
-
-type HttpPollingStream struct {
- client httpclient.Client
-}
-
-func New(client httpclient.Client) *HttpPollingStream {
- return &HttpPollingStream{
- client: client,
- }
-}
-
-func (h *HttpPollingStream) Start(input []byte, next chan<- []byte, stop <-chan struct{}) {
- interval, err := jsonparser.GetInt(input, "interval")
- if err != nil {
- return
- }
- requestInput, _, _, err := jsonparser.Get(input, "request_input")
- if err != nil {
- return
- }
- skipSameResponse, err := jsonparser.GetBoolean(input, "skip_publish_same_response")
- if err != nil {
- skipSameResponse = false
- }
- buf := bytes.NewBuffer(make([]byte, 0, 4096))
- hash := xxhash.New()
- var (
- sum uint64
- )
- for {
- select {
- case <-time.After(time.Duration(interval) * time.Millisecond):
- buf.Reset()
- err := h.client.Do(context.Background(), requestInput, buf)
- if err != nil {
- continue
- }
- src := buf.Bytes()
- if len(src) == 0 {
- continue
- }
- if skipSameResponse {
- hash.Reset()
- _, err = hash.Write(src)
- if err != nil {
- continue
- }
- nextSum := hash.Sum64()
- if nextSum == sum {
- continue
- }
- sum = nextSum
- }
- dst := make([]byte, len(src))
- copy(dst, src)
- next <- dst
- case <-stop:
- return
- }
- }
-}
-
-func (h *HttpPollingStream) UniqueIdentifier() []byte {
- return HttpPolling
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/manager.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/manager.go
deleted file mode 100644
index 9b01c78f1a7..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/manager.go
+++ /dev/null
@@ -1,146 +0,0 @@
-package subscription
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/pool"
-)
-
-func NewManager(stream Stream) *Manager {
- return &Manager{
- stream: stream,
- subscribers: map[uint64]int64{},
- subscriptions: map[uint64]*subscription{},
- addTrigger: make(chan addTrigger),
- removeTrigger: make(chan Trigger),
- countSubscribers: make(chan chan int64),
- countSubscriptions: make(chan chan int64),
- }
-}
-
-type addTrigger struct {
- trigger Trigger
- input []byte
-}
-
-type Manager struct {
- stream Stream
- subscriptions map[uint64]*subscription
- subscribers map[uint64]int64
- addTrigger chan addTrigger
- removeTrigger chan Trigger
- countSubscriptions chan chan int64
- countSubscribers chan chan int64
-}
-
-func (m *Manager) TotalSubscriptions() int64 {
- out := make(chan int64)
- m.countSubscriptions <- out
- return <-out
-}
-
-func (m *Manager) TotalSubscribers() int64 {
- out := make(chan int64)
- m.countSubscribers <- out
- return <-out
-}
-
-func (m *Manager) Run(done <-chan struct{}) {
- go m.run(done)
-}
-
-func (m *Manager) run(done <-chan struct{}) {
- for {
- select {
- case <-done:
- return
- case addTrigger := <-m.addTrigger:
- sub, exists := m.subscriptions[addTrigger.trigger.subscriptionID]
- if !exists {
- sub = &subscription{
- triggers: map[Trigger]struct{}{
- addTrigger.trigger: {},
- },
- addTrigger: make(chan Trigger),
- removeTrigger: make(chan Trigger),
- stop: make(chan struct{}),
- results: make(chan []byte),
- }
- m.subscriptions[addTrigger.trigger.subscriptionID] = sub
- m.subscribers[addTrigger.trigger.subscriptionID] = 1
- go m.stream.Start(addTrigger.input, sub.results, sub.stop)
- go sub.run()
- continue
- }
- sub.addTrigger <- addTrigger.trigger
- m.subscribers[addTrigger.trigger.subscriptionID] += 1
- case trigger := <-m.removeTrigger:
- m.subscriptions[trigger.subscriptionID].removeTrigger <- trigger
- subscribers := m.subscribers[trigger.subscriptionID] - 1
- if subscribers == 0 {
- close(m.subscriptions[trigger.subscriptionID].stop)
- delete(m.subscriptions, trigger.subscriptionID)
- delete(m.subscribers, trigger.subscriptionID)
- continue
- }
- m.subscribers[trigger.subscriptionID] = subscribers
- case out := <-m.countSubscriptions:
- out <- int64(len(m.subscriptions))
- case out := <-m.countSubscribers:
- var subs int64
- for i := range m.subscribers {
- subs += m.subscribers[i]
- }
- out <- subs
- }
- }
-}
-
-type subscription struct {
- triggers map[Trigger]struct{}
- addTrigger chan Trigger
- removeTrigger chan Trigger
- stop chan struct{}
- results chan []byte
-}
-
-func (s *subscription) run() {
- for {
- select {
- case <-s.stop:
- return
- case trigger := <-s.addTrigger:
- s.triggers[trigger] = struct{}{}
- case trigger := <-s.removeTrigger:
- delete(s.triggers, trigger)
- case result := <-s.results:
- for trigger := range s.triggers {
- trigger.results <- result
- }
- }
- }
-}
-
-func (m *Manager) StartTrigger(input []byte) (trigger Trigger) {
- subscriptionID := m.subscriptionID(input)
- trigger = NewTrigger(subscriptionID)
- m.addTrigger <- addTrigger{
- trigger: trigger,
- input: input,
- }
- return
-}
-
-func (m *Manager) StopTrigger(trigger Trigger) {
- m.removeTrigger <- trigger
-}
-
-func (m *Manager) subscriptionID(input []byte) uint64 {
- hash64 := pool.Hash64.Get()
- _, _ = hash64.Write(input)
- subscriptionID := hash64.Sum64()
- pool.Hash64.Put(hash64)
- return subscriptionID
-}
-
-func (m *Manager) UniqueIdentifier() []byte {
- return m.stream.UniqueIdentifier()
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/stream.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/stream.go
deleted file mode 100644
index 8e59f5792d6..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/stream.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package subscription
-
-type Stream interface {
- Start(input []byte, next chan<- []byte, stop <-chan struct{})
- // UniqueIdentifier gives each stream a name, e.g. "kafka", "nats", "http-polling"
- // Don't give streams of the same type a different UID, e.g. don't use "kafka1", "kafka2"
- // This value should be static and the same for streams of the same kind
- UniqueIdentifier() []byte
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/trigger.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/trigger.go
deleted file mode 100644
index ceecafd002c..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/engine/subscription/trigger.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package subscription
-
-import (
- "context"
-)
-
-func NewTrigger(subscriptionID uint64) Trigger {
- return Trigger{
- subscriptionID: subscriptionID,
- results: make(chan []byte), // unbuffered channel
- }
-}
-
-type Trigger struct {
- subscriptionID uint64
- results chan []byte
-}
-
-func (h *Trigger) SubscriptionID() uint64 {
- return h.subscriptionID
-}
-
-func (h *Trigger) Next(ctx context.Context) (data []byte, ok bool) {
- done := ctx.Done()
- select {
- case <-done:
- return nil, false
- case result, ok := <-h.results:
- return result, ok
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource.go
deleted file mode 100644
index ed1eece103d..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource.go
+++ /dev/null
@@ -1,272 +0,0 @@
-package datasource
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "io"
- "net/http"
- "net/url"
- "strings"
- "time"
-
- "github.com/jensneuse/abstractlogger"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astparser"
- "github.com/jensneuse/graphql-go-tools/pkg/asttransform"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
-)
-
-var RootTypeName = []byte("root_type_name")
-var RootFieldName = []byte("root_field_name")
-
-var defaultHttpClient *http.Client
-
-func DefaultHttpClient() *http.Client {
- if defaultHttpClient == nil {
- defaultHttpClient = &http.Client{
- Timeout: time.Second * 10,
- Transport: &http.Transport{
- MaxIdleConnsPerHost: 1024,
- TLSHandshakeTimeout: 0 * time.Second,
- },
- }
- }
-
- return defaultHttpClient
-}
-
-type ResolverArgs interface {
- ByKey(key []byte) []byte
- Dump() []string
- Keys() [][]byte
-}
-
-type DataSource interface {
- Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error)
-}
-
-type Planner interface {
- CorePlanner
- PlannerVisitors
-}
-
-type CorePlanner interface {
- // Plan plan returns the pre configured DataSource as well as the Arguments
- // During runtime the arguments get resolved and passed to the DataSource
- Plan(args []Argument) (DataSource, []Argument)
- // Configure is the function to initialize all important values for the Planner to function correctly
- // You probably need access to the Walker, Operation and ObjectDefinition to use the Planner to its full power
- // Walker gives you useful information from within all visitor Callbacks, e.g. the Path & Ancestors
- // Operation is the AST of the GraphQL Operation
- // ObjectDefinition is the AST of the GraphQL schema ObjectDefinition
- // Args are the pre-calculated Arguments from the planner
- // resolverParameters are the parameters from the @directive params field
- Configure(operation, definition *ast.Document, walker *astvisitor.Walker)
-}
-
-type PlannerVisitors interface {
- astvisitor.EnterDocumentVisitor
- astvisitor.EnterInlineFragmentVisitor
- astvisitor.LeaveInlineFragmentVisitor
- astvisitor.EnterSelectionSetVisitor
- astvisitor.LeaveSelectionSetVisitor
- astvisitor.EnterFieldVisitor
- astvisitor.EnterArgumentVisitor
- astvisitor.LeaveFieldVisitor
-}
-
-type PlannerFactory interface {
- DataSourcePlanner() Planner
-}
-
-type PlannerFactoryFactory interface {
- Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error)
-}
-
-type BasePlanner struct {
- Log abstractlogger.Logger
- Walker *astvisitor.Walker // nolint
- Definition, Operation *ast.Document // nolint
- Args []Argument // nolint
- RootField rootField // nolint
- Config PlannerConfiguration // nolint
-}
-
-func NewBaseDataSourcePlanner(schema []byte, config PlannerConfiguration, logger abstractlogger.Logger) (*BasePlanner, error) {
- definition, report := astparser.ParseGraphqlDocumentBytes(schema)
- if report.HasErrors() {
- return nil, report
- }
-
- err := asttransform.MergeDefinitionWithBaseSchema(&definition)
- if err != nil {
- return nil, err
- }
-
- return &BasePlanner{
- Config: config,
- Log: logger,
- Definition: &definition,
- }, nil
-}
-
-func (b *BasePlanner) Configure(operation, definition *ast.Document, walker *astvisitor.Walker) {
- b.Operation, b.Definition, b.Walker = operation, definition, walker
-}
-
-func (b *BasePlanner) RegisterDataSourcePlannerFactory(dataSourceName string, factory PlannerFactoryFactory) (err error) {
- for i := range b.Config.TypeFieldConfigurations {
- if dataSourceName != b.Config.TypeFieldConfigurations[i].DataSource.Name {
- continue
- }
- configReader := bytes.NewReader(b.Config.TypeFieldConfigurations[i].DataSource.Config)
- b.Config.TypeFieldConfigurations[i].DataSourcePlannerFactory, err = factory.Initialize(*b, configReader)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-type PlannerConfiguration struct {
- TypeFieldConfigurations []TypeFieldConfiguration
-}
-
-type TypeFieldConfiguration struct {
- TypeName string `bson:"type_name" json:"type_name"`
- FieldName string `bson:"field_name" json:"field_name"`
- Mapping *MappingConfiguration `bson:"mapping" json:"mapping"`
- DataSource SourceConfig `bson:"data_source" json:"data_source"`
- DataSourcePlannerFactory PlannerFactory `bson:"-" json:"-"`
-}
-
-type SourceConfig struct {
- // Kind defines the unique identifier of the DataSource
- // Kind needs to match to the Planner "DataSourceName" name
- Name string `bson:"kind" json:"kind"`
- // Config is the DataSource specific configuration object
- // Each Planner needs to make sure to parse their Config Object correctly
- Config json.RawMessage `bson:"data_source_config" json:"data_source_config"`
-}
-
-type MappingConfiguration struct {
- Disabled bool `bson:"disabled" json:"disabled"`
- Path string `bson:"path" json:"path"`
-}
-
-func (p *PlannerConfiguration) DataSourcePlannerFactoryForTypeField(typeName, fieldName string) PlannerFactory {
- for i := range p.TypeFieldConfigurations {
- if strings.EqualFold(p.TypeFieldConfigurations[i].TypeName, typeName) && strings.EqualFold(p.TypeFieldConfigurations[i].FieldName, fieldName) {
- return p.TypeFieldConfigurations[i].DataSourcePlannerFactory
- }
- }
- return nil
-}
-
-func (p *PlannerConfiguration) MappingForTypeField(typeName, fieldName string) *MappingConfiguration {
- for i := range p.TypeFieldConfigurations {
- if strings.EqualFold(p.TypeFieldConfigurations[i].TypeName, typeName) && strings.EqualFold(p.TypeFieldConfigurations[i].FieldName, fieldName) {
- return p.TypeFieldConfigurations[i].Mapping
- }
- }
- return nil
-}
-
-type rootField struct {
- isDefined bool
- ref int
-}
-
-func (r *rootField) SetIfNotDefined(ref int) {
- if r.isDefined {
- return
- }
- r.isDefined = true
- r.ref = ref
-}
-
-func (r *rootField) IsDefinedAndEquals(ref int) bool {
- return r.isDefined && r.ref == ref
-}
-
-type visitingDataSourcePlanner struct {
- CorePlanner
-}
-
-func (_ visitingDataSourcePlanner) EnterDocument(operation, definition *ast.Document) {}
-func (_ visitingDataSourcePlanner) EnterInlineFragment(ref int) {}
-func (_ visitingDataSourcePlanner) LeaveInlineFragment(ref int) {}
-func (_ visitingDataSourcePlanner) EnterSelectionSet(ref int) {}
-func (_ visitingDataSourcePlanner) LeaveSelectionSet(ref int) {}
-func (_ visitingDataSourcePlanner) EnterField(ref int) {}
-func (_ visitingDataSourcePlanner) EnterArgument(ref int) {}
-func (_ visitingDataSourcePlanner) LeaveField(ref int) {}
-
-func SimpleDataSourcePlanner(core CorePlanner) Planner {
- return &visitingDataSourcePlanner{
- CorePlanner: core,
- }
-}
-
-type Argument interface {
- ArgName() []byte
-}
-
-type ContextVariableArgument struct {
- Name []byte
- VariableName []byte
-}
-
-func (c *ContextVariableArgument) ArgName() []byte {
- return c.Name
-}
-
-type PathSelector struct {
- Path string
-}
-
-type ObjectVariableArgument struct {
- Name []byte
- PathSelector PathSelector
-}
-
-func (o *ObjectVariableArgument) ArgName() []byte {
- return o.Name
-}
-
-type StaticVariableArgument struct {
- Name []byte
- Value []byte
-}
-
-func (s *StaticVariableArgument) ArgName() []byte {
- return s.Name
-}
-
-type ListArgument struct {
- Name []byte
- Arguments []Argument
-}
-
-func (l ListArgument) ArgName() []byte {
- return l.Name
-}
-
-func isWhitelistedScheme(scheme string, whitelistedSchemes []string, defaultSchemes []string) bool {
- schemes := append(whitelistedSchemes, defaultSchemes...)
- for _, whitelistedScheme := range schemes {
- if scheme == whitelistedScheme {
- return true
- }
- }
-
- return false
-}
-
-func parseURLBytes(urlArg []byte) (parsedURL *url.URL, rawURL string, err error) {
- rawURL = string(urlArg)
- parsedURL, err = url.Parse(rawURL)
- return parsedURL, rawURL, err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_graphql.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_graphql.go
deleted file mode 100644
index c432bc17cec..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_graphql.go
+++ /dev/null
@@ -1,471 +0,0 @@
-package datasource
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "io"
- "io/ioutil"
- "net/http"
-
- "github.com/buger/jsonparser"
- "github.com/cespare/xxhash"
- log "github.com/jensneuse/abstractlogger"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astimport"
- "github.com/jensneuse/graphql-go-tools/pkg/astprinter"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-var graphqlSchemes = []string{
- "https",
- "http",
-}
-
-type GraphqlRequest struct {
- OperationName string `json:"operationName"`
- Variables json.RawMessage `json:"variables"`
- Query string `json:"query"`
-}
-
-// GraphQLDataSourceConfig is the configuration for the GraphQL DataSource
-type GraphQLDataSourceConfig struct {
- // URL is the url of the upstream
- URL string `bson:"url" json:"url"`
- // Method is the http.Method of the upstream, defaults to POST (optional)
- Method *string `bson:"method" json:"method"`
-}
-
-type GraphQLDataSourcePlanner struct {
- BasePlanner
- importer *astimport.Importer
- nodes []ast.Node
- resolveDocument *ast.Document
- dataSourceConfiguration GraphQLDataSourceConfig
- client *http.Client
- whitelistedSchemes []string
- whitelistedVariableRefs []int
- whitelistedVariableNameHashs map[uint64]bool
- hooks Hooks
-}
-
-type GraphQLDataSourcePlannerFactoryFactory struct {
- Client *http.Client
- WhitelistedSchemes []string
- Hooks Hooks
-}
-
-func (g *GraphQLDataSourcePlannerFactoryFactory) httpClient() *http.Client {
- if g.Client != nil {
- return g.Client
- }
- return DefaultHttpClient()
-}
-
-func (g GraphQLDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) {
- factory := &GraphQLDataSourcePlannerFactory{
- base: base,
- client: g.httpClient(),
- whitelistedSchemes: g.WhitelistedSchemes,
- hooks: g.Hooks,
- }
- err := json.NewDecoder(configReader).Decode(&factory.config)
- return factory, err
-}
-
-type GraphQLDataSourcePlannerFactory struct {
- base BasePlanner
- config GraphQLDataSourceConfig
- client *http.Client
- whitelistedSchemes []string
- hooks Hooks
-}
-
-func (g *GraphQLDataSourcePlannerFactory) DataSourcePlanner() Planner {
- return &GraphQLDataSourcePlanner{
- BasePlanner: g.base,
- importer: &astimport.Importer{},
- dataSourceConfiguration: g.config,
- resolveDocument: &ast.Document{},
- client: g.client,
- whitelistedSchemes: g.whitelistedSchemes,
- whitelistedVariableRefs: []int{},
- whitelistedVariableNameHashs: map[uint64]bool{},
- hooks: g.hooks,
- }
-}
-
-func (g *GraphQLDataSourcePlanner) EnterDocument(operation, definition *ast.Document) {
- g.whitelistedVariableRefs = g.whitelistedVariableRefs[:0]
-}
-
-func (g *GraphQLDataSourcePlanner) EnterInlineFragment(ref int) {
- if len(g.nodes) == 0 {
- return
- }
- current := g.nodes[len(g.nodes)-1]
- if current.Kind != ast.NodeKindSelectionSet {
- return
- }
- inlineFragmentType := g.importer.ImportType(g.Operation.InlineFragments[ref].TypeCondition.Type, g.Operation, g.resolveDocument)
- g.resolveDocument.InlineFragments = append(g.resolveDocument.InlineFragments, ast.InlineFragment{
- TypeCondition: ast.TypeCondition{
- Type: inlineFragmentType,
- },
- SelectionSet: -1,
- })
- inlineFragmentRef := len(g.resolveDocument.InlineFragments) - 1
- g.resolveDocument.Selections = append(g.resolveDocument.Selections, ast.Selection{
- Kind: ast.SelectionKindInlineFragment,
- Ref: inlineFragmentRef,
- })
- selectionRef := len(g.resolveDocument.Selections) - 1
- g.resolveDocument.SelectionSets[current.Ref].SelectionRefs = append(g.resolveDocument.SelectionSets[current.Ref].SelectionRefs, selectionRef)
- g.nodes = append(g.nodes, ast.Node{
- Kind: ast.NodeKindInlineFragment,
- Ref: inlineFragmentRef,
- })
-}
-
-func (g *GraphQLDataSourcePlanner) LeaveInlineFragment(ref int) {
- g.nodes = g.nodes[:len(g.nodes)-1]
-}
-
-func (g *GraphQLDataSourcePlanner) EnterSelectionSet(ref int) {
-
- fieldOrInlineFragment := g.nodes[len(g.nodes)-1]
-
- set := ast.SelectionSet{}
- g.resolveDocument.SelectionSets = append(g.resolveDocument.SelectionSets, set)
- setRef := len(g.resolveDocument.SelectionSets) - 1
-
- switch fieldOrInlineFragment.Kind {
- case ast.NodeKindField:
- g.resolveDocument.Fields[fieldOrInlineFragment.Ref].HasSelections = true
- g.resolveDocument.Fields[fieldOrInlineFragment.Ref].SelectionSet = setRef
- case ast.NodeKindInlineFragment:
- g.resolveDocument.InlineFragments[fieldOrInlineFragment.Ref].HasSelections = true
- g.resolveDocument.InlineFragments[fieldOrInlineFragment.Ref].SelectionSet = setRef
- }
-
- g.nodes = append(g.nodes, ast.Node{
- Kind: ast.NodeKindSelectionSet,
- Ref: setRef,
- })
-}
-
-func (g *GraphQLDataSourcePlanner) LeaveSelectionSet(ref int) {
- g.nodes = g.nodes[:len(g.nodes)-1]
-}
-
-func (g *GraphQLDataSourcePlanner) EnterField(ref int) {
- if !g.RootField.isDefined {
- g.RootField.SetIfNotDefined(ref)
-
- typeName := g.Definition.NodeNameString(g.Walker.EnclosingTypeDefinition)
- fieldNameStr := g.Operation.FieldNameString(ref)
- fieldName := g.Operation.FieldNameBytes(ref)
-
- g.Args = append(g.Args, &StaticVariableArgument{
- Name: RootTypeName,
- Value: []byte(typeName),
- })
-
- g.Args = append(g.Args, &StaticVariableArgument{
- Name: RootFieldName,
- Value: fieldName,
- })
-
- mapping := g.Config.MappingForTypeField(typeName, fieldNameStr)
- if mapping != nil && !mapping.Disabled {
- fieldName = unsafebytes.StringToBytes(mapping.Path)
- }
-
- hasArguments := g.Operation.FieldHasArguments(ref)
- var argumentRefs []int
- if hasArguments {
- argumentRefs = g.importer.ImportArguments(g.Operation.FieldArguments(ref), g.Operation, g.resolveDocument)
- }
-
- field := ast.Field{
- Name: g.resolveDocument.Input.AppendInputBytes(fieldName),
- Arguments: ast.ArgumentList{
- Refs: argumentRefs,
- },
- HasArguments: hasArguments,
- }
- g.resolveDocument.Fields = append(g.resolveDocument.Fields, field)
- fieldRef := len(g.resolveDocument.Fields) - 1
- selection := ast.Selection{
- Kind: ast.SelectionKindField,
- Ref: fieldRef,
- }
- g.resolveDocument.Selections = append(g.resolveDocument.Selections, selection)
- selectionRef := len(g.resolveDocument.Selections) - 1
- set := ast.SelectionSet{
- SelectionRefs: []int{selectionRef},
- }
- g.resolveDocument.SelectionSets = append(g.resolveDocument.SelectionSets, set)
- setRef := len(g.resolveDocument.SelectionSets) - 1
- operationDefinition := ast.OperationDefinition{
- Name: g.resolveDocument.Input.AppendInputBytes([]byte("o")),
- OperationType: g.Operation.OperationDefinitions[g.Walker.Ancestors[0].Ref].OperationType,
- SelectionSet: setRef,
- HasSelections: true,
- }
- g.resolveDocument.OperationDefinitions = append(g.resolveDocument.OperationDefinitions, operationDefinition)
- operationDefinitionRef := len(g.resolveDocument.OperationDefinitions) - 1
- g.resolveDocument.RootNodes = append(g.resolveDocument.RootNodes, ast.Node{
- Kind: ast.NodeKindOperationDefinition,
- Ref: operationDefinitionRef,
- })
- g.nodes = append(g.nodes, ast.Node{
- Kind: ast.NodeKindOperationDefinition,
- Ref: operationDefinitionRef,
- })
- g.nodes = append(g.nodes, ast.Node{
- Kind: ast.NodeKindSelectionSet,
- Ref: setRef,
- })
- g.nodes = append(g.nodes, ast.Node{
- Kind: ast.NodeKindField,
- Ref: fieldRef,
- })
- } else {
- field := ast.Field{
- Name: g.resolveDocument.Input.AppendInputBytes(g.Operation.FieldNameBytes(ref)),
- }
- g.resolveDocument.Fields = append(g.resolveDocument.Fields, field)
- fieldRef := len(g.resolveDocument.Fields) - 1
- set := g.nodes[len(g.nodes)-1]
- selection := ast.Selection{
- Kind: ast.SelectionKindField,
- Ref: fieldRef,
- }
- g.resolveDocument.Selections = append(g.resolveDocument.Selections, selection)
- selectionRef := len(g.resolveDocument.Selections) - 1
- g.resolveDocument.SelectionSets[set.Ref].SelectionRefs = append(g.resolveDocument.SelectionSets[set.Ref].SelectionRefs, selectionRef)
- g.nodes = append(g.nodes, ast.Node{
- Kind: ast.NodeKindField,
- Ref: fieldRef,
- })
- }
-}
-
-func (g *GraphQLDataSourcePlanner) EnterArgument(ref int) {
- variableValue := g.Operation.ArgumentValue(ref)
- if variableValue.Kind != ast.ValueKindVariable {
- return
- }
-
- variableName := g.Operation.VariableValueNameBytes(variableValue.Ref)
- definitionRef, exists := g.Operation.VariableDefinitionByNameAndOperation(g.nodes[0].Ref, variableName)
- if !exists {
- return
- }
-
- g.whitelistedVariableRefs = append(g.whitelistedVariableRefs, definitionRef)
- g.whitelistedVariableNameHashs[xxhash.Sum64(variableName)] = true
-}
-
-func (g *GraphQLDataSourcePlanner) LeaveField(ref int) {
- defer func() {
- g.nodes = g.nodes[:len(g.nodes)-1]
- }()
- if g.RootField.ref != ref {
- return
- }
-
- hasVariableDefinitions := len(g.Operation.OperationDefinitions[g.Walker.Ancestors[0].Ref].VariableDefinitions.Refs) != 0
- var variableDefinitionsRefs []int
- if hasVariableDefinitions {
- operationVariableDefinitions := g.Operation.OperationDefinitions[g.Walker.Ancestors[0].Ref].VariableDefinitions.Refs
- definitions := make([]int, len(operationVariableDefinitions))
- copy(definitions, operationVariableDefinitions)
- definitions = ast.FilterIntSliceByWhitelist(definitions, g.whitelistedVariableRefs)
-
- variableDefinitionsRefs = g.importer.ImportVariableDefinitions(definitions, g.Operation, g.resolveDocument)
- g.resolveDocument.OperationDefinitions[0].HasVariableDefinitions = len(definitions) != 0
- g.resolveDocument.OperationDefinitions[0].VariableDefinitions.Refs = variableDefinitionsRefs
- }
-
- buff := bytes.Buffer{}
- err := astprinter.Print(g.resolveDocument, nil, &buff)
- if err != nil {
- g.Walker.StopWithInternalErr(err)
- return
- }
- g.Args = append(g.Args, &StaticVariableArgument{
- Name: literal.URL,
- Value: []byte(g.dataSourceConfiguration.URL),
- })
- g.Args = append(g.Args, &StaticVariableArgument{
- Name: literal.QUERY,
- Value: buff.Bytes(),
- })
- if g.dataSourceConfiguration.Method == nil {
- g.Args = append(g.Args, &StaticVariableArgument{
- Name: literal.METHOD,
- Value: literal.HTTP_METHOD_POST,
- })
- } else {
- g.Args = append(g.Args, &StaticVariableArgument{
- Name: literal.URL,
- Value: []byte(*g.dataSourceConfiguration.Method),
- })
- }
-}
-
-func (g *GraphQLDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) {
- for i := range args {
- if arg, ok := args[i].(*ContextVariableArgument); ok {
- if bytes.HasPrefix(arg.Name, literal.DOT_ARGUMENTS_DOT) {
- arg.Name = bytes.TrimPrefix(arg.Name, literal.DOT_ARGUMENTS_DOT)
-
- if g.whitelistedVariableNameHashs[xxhash.Sum64(arg.Name)] {
- g.Args = append(g.Args, arg)
- } else if g.whitelistedVariableNameHashs[xxhash.Sum64(arg.VariableName)] {
- arg.Name = arg.VariableName
- g.Args = append(g.Args, arg)
- }
- }
- }
- }
- return &GraphQLDataSource{
- Log: g.Log,
- Client: g.client,
- WhitelistedSchemes: g.whitelistedSchemes,
- Hooks: g.hooks,
- }, g.Args
-}
-
-type GraphQLDataSource struct {
- Log log.Logger
- Client *http.Client
- WhitelistedSchemes []string
- Hooks Hooks
-}
-
-func (g *GraphQLDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) {
- urlArg := args.ByKey(literal.URL)
- queryArg := args.ByKey(literal.QUERY)
- rootTypeName := args.ByKey(RootTypeName)
- rootFieldName := args.ByKey(RootFieldName)
- hookContext := HookContext{
- TypeName: string(rootTypeName),
- FieldName: string(rootFieldName),
- }
-
- g.Log.Debug("GraphQLDataSource.Resolve.Args",
- log.Strings("resolvedArgs", args.Dump()),
- )
-
- if urlArg == nil || queryArg == nil {
- g.Log.Error("GraphQLDataSource.Args invalid")
- return
- }
-
- parsedURL, rawURL, err := parseURLBytes(urlArg)
- if err != nil {
- g.Log.Error("GraphQLDataSource.RawURL could not be parsed", log.String("rawURL", rawURL))
- return
- }
-
- if len(parsedURL.Scheme) == 0 || !isWhitelistedScheme(parsedURL.Scheme, g.WhitelistedSchemes, graphqlSchemes) {
- parsedURL.Scheme = graphqlSchemes[0]
- }
-
- variables := map[string]interface{}{}
- keys := args.Keys()
- for i := 0; i < len(keys); i++ {
- switch {
- case bytes.Equal(keys[i], literal.URL):
- case bytes.Equal(keys[i], literal.QUERY):
- case bytes.Equal(keys[i], RootTypeName):
- case bytes.Equal(keys[i], RootFieldName):
- default:
- variables[string(keys[i])] = string(args.ByKey(keys[i]))
- }
- }
-
- variablesJson, err := json.Marshal(variables)
- if err != nil {
- g.Log.Error("GraphQLDataSource.json.Marshal(variables)",
- log.Error(err),
- )
- return n, err
- }
-
- gqlRequest := GraphqlRequest{
- OperationName: "o",
- Variables: variablesJson,
- Query: string(queryArg),
- }
-
- gqlRequestData, err := json.MarshalIndent(gqlRequest, "", " ")
- if err != nil {
- g.Log.Error("GraphQLDataSource.json.MarshalIndent",
- log.Error(err),
- )
- return n, err
- }
-
- g.Log.Debug("GraphQLDataSource.request",
- log.String("rawURL", rawURL),
- log.String("parsedURL", parsedURL.String()),
- log.ByteString("data", gqlRequestData),
- )
-
- request, err := http.NewRequest(http.MethodPost, parsedURL.String(), bytes.NewBuffer(gqlRequestData))
- if err != nil {
- g.Log.Error("GraphQLDataSource.http.NewRequest",
- log.Error(err),
- )
- return n, err
- }
-
- request.Header.Add("Content-Type", "application/json")
- request.Header.Add("Accept", "application/json")
-
- if g.Hooks.PreSendHttpHook != nil {
- g.Hooks.PreSendHttpHook.Execute(hookContext, request)
- }
-
- res, err := g.Client.Do(request)
- if err != nil {
- g.Log.Error("GraphQLDataSource.client.Do",
- log.Error(err),
- )
- return n, err
- }
- data, err := ioutil.ReadAll(res.Body)
- if err != nil {
- g.Log.Error("GraphQLDataSource.ioutil.ReadAll",
- log.Error(err),
- )
- return n, err
- }
-
- if g.Hooks.PostReceiveHttpHook != nil {
- g.Hooks.PostReceiveHttpHook.Execute(hookContext, res, data)
- }
-
- defer func() {
- err := res.Body.Close()
- if err != nil {
- g.Log.Error("GraphQLDataSource.Resolve.Response.Body.Close", log.Error(err))
- }
- }()
-
- data = bytes.ReplaceAll(data, literal.BACKSLASH, nil)
- data, _, _, err = jsonparser.Get(data, "data")
- if err != nil {
- g.Log.Error("GraphQLDataSource.jsonparser.Get",
- log.Error(err),
- )
- return n, err
- }
- return out.Write(data)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_http_json.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_http_json.go
deleted file mode 100644
index ed5a2c0a1b4..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_http_json.go
+++ /dev/null
@@ -1,401 +0,0 @@
-package datasource
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "strconv"
-
- "github.com/buger/jsonparser"
- log "github.com/jensneuse/abstractlogger"
- "github.com/tidwall/gjson"
- "github.com/tidwall/sjson"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-var httpJsonSchemes = []string{
- "https",
- "http",
-}
-
-// HttpJsonDataSourceConfig is the configuration object for the HttpJsonDataSource
-type HttpJsonDataSourceConfig struct {
- // URL is the url of the upstream
- URL string `bson:"url" json:"url"`
- // Method is the http.Method, e.g. GET, POST, UPDATE, DELETE
- // default is GET
- Method *string `bson:"method" json:"method"`
- // Body is the http body to send
- // default is null/nil (no body)
- Body *string `bson:"body" json:"body"`
- // Headers defines the header mappings
- Headers []HttpJsonDataSourceConfigHeader `bson:"headers" json:"headers"`
- // DefaultTypeName is the optional variable to define a default type name for the response object
- // This is useful in case the response might be a Union or Interface type which uses StatusCodeTypeNameMappings
- DefaultTypeName *string `bson:"default_type_name" json:"default_type_name"`
- // StatusCodeTypeNameMappings is a slice of mappings from http.StatusCode to GraphQL TypeName
- // This can be used when the TypeName depends on the http.StatusCode
- StatusCodeTypeNameMappings []StatusCodeTypeNameMapping `bson:"status_code_type_name_mappings" json:"status_code_type_name_mappings"`
-}
-
-type StatusCodeTypeNameMapping struct {
- StatusCode int `bson:"status_code" json:"status_code"`
- TypeName string `bson:"type_name" json:"type_name"`
-}
-
-type HttpJsonDataSourceConfigHeader struct {
- Key string `bson:"key" json:"key"`
- Value string `bson:"value" json:"value"`
-}
-
-type HttpJsonDataSourcePlannerFactoryFactory struct {
- Client *http.Client
- WhitelistedSchemes []string
- Hooks Hooks
-}
-
-func (h *HttpJsonDataSourcePlannerFactoryFactory) httpClient() *http.Client {
- if h.Client != nil {
- return h.Client
- }
- return DefaultHttpClient()
-}
-
-func (h *HttpJsonDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) {
- factory := &HttpJsonDataSourcePlannerFactory{
- base: base,
- client: h.httpClient(),
- whitelistedSchemes: h.WhitelistedSchemes,
- hooks: h.Hooks,
- }
- err := json.NewDecoder(configReader).Decode(&factory.config)
- return factory, err
-}
-
-type HttpJsonDataSourcePlannerFactory struct {
- base BasePlanner
- config HttpJsonDataSourceConfig
- client *http.Client
- whitelistedSchemes []string
- hooks Hooks
-}
-
-func (h *HttpJsonDataSourcePlannerFactory) DataSourcePlanner() Planner {
- return &HttpJsonDataSourcePlanner{
- BasePlanner: h.base,
- dataSourceConfig: h.config,
- client: h.client,
- whitelistedSchemes: h.whitelistedSchemes,
- hooks: h.hooks,
- }
-}
-
-type HttpJsonDataSourcePlanner struct {
- BasePlanner
- dataSourceConfig HttpJsonDataSourceConfig
- client *http.Client
- whitelistedSchemes []string
- hooks Hooks
-}
-
-func (h *HttpJsonDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) {
- return &HttpJsonDataSource{
- Log: h.Log,
- Client: h.client,
- WhitelistedSchemes: h.whitelistedSchemes,
- Hooks: h.hooks,
- }, append(h.Args, args...)
-}
-
-func (h *HttpJsonDataSourcePlanner) EnterDocument(operation, definition *ast.Document) {
-
-}
-
-func (h *HttpJsonDataSourcePlanner) EnterInlineFragment(ref int) {
-
-}
-
-func (h *HttpJsonDataSourcePlanner) LeaveInlineFragment(ref int) {
-
-}
-
-func (h *HttpJsonDataSourcePlanner) EnterSelectionSet(ref int) {
-
-}
-
-func (h *HttpJsonDataSourcePlanner) LeaveSelectionSet(ref int) {
-
-}
-
-func (h *HttpJsonDataSourcePlanner) EnterField(ref int) {
- if !h.RootField.isDefined {
- h.RootField.SetIfNotDefined(ref)
-
- typeName := h.Definition.NodeNameBytes(h.Walker.EnclosingTypeDefinition)
- fieldName := h.Operation.FieldNameBytes(ref)
-
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: RootTypeName,
- Value: typeName,
- })
-
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: RootFieldName,
- Value: fieldName,
- })
- }
-}
-
-func (h *HttpJsonDataSourcePlanner) EnterArgument(ref int) {}
-
-func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) {
- if !h.RootField.IsDefinedAndEquals(ref) {
- return
- }
- definition, exists := h.Walker.FieldDefinition(ref)
- if !exists {
- return
- }
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: literal.URL,
- Value: []byte(h.dataSourceConfig.URL),
- })
- if h.dataSourceConfig.Method == nil {
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: literal.METHOD,
- Value: literal.HTTP_METHOD_GET,
- })
- } else {
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: literal.METHOD,
- Value: []byte(*h.dataSourceConfig.Method),
- })
- }
- if h.dataSourceConfig.Body != nil {
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: literal.BODY,
- Value: []byte(*h.dataSourceConfig.Body),
- })
- }
-
- if len(h.dataSourceConfig.Headers) != 0 {
- listArg := &ListArgument{
- Name: literal.HEADERS,
- }
- for i := range h.dataSourceConfig.Headers {
- listArg.Arguments = append(listArg.Arguments, &StaticVariableArgument{
- Name: []byte(h.dataSourceConfig.Headers[i].Key),
- Value: []byte(h.dataSourceConfig.Headers[i].Value),
- })
- }
- h.Args = append(h.Args, listArg)
- }
-
- // __typename
- var typeNameValue []byte
- var err error
- fieldDefinitionTypeNode := h.Definition.FieldDefinitionTypeNode(definition)
- fieldDefinitionType := h.Definition.FieldDefinitionType(definition)
- fieldDefinitionTypeName := h.Definition.ResolveTypeNameBytes(fieldDefinitionType)
- quotedFieldDefinitionTypeName := append(literal.QUOTE, append(fieldDefinitionTypeName, literal.QUOTE...)...)
- switch fieldDefinitionTypeNode.Kind {
- case ast.NodeKindScalarTypeDefinition:
- return
- case ast.NodeKindUnionTypeDefinition, ast.NodeKindInterfaceTypeDefinition:
- if h.dataSourceConfig.DefaultTypeName != nil {
- typeNameValue, err = sjson.SetRawBytes(typeNameValue, "defaultTypeName", []byte("\""+*h.dataSourceConfig.DefaultTypeName+"\""))
- if err != nil {
- h.Log.Error("HttpJsonDataSourcePlanner set defaultTypeName (switch case union/interface)", log.Error(err))
- return
- }
- }
- for i := range h.dataSourceConfig.StatusCodeTypeNameMappings {
- typeNameValue, err = sjson.SetRawBytes(typeNameValue, strconv.Itoa(h.dataSourceConfig.StatusCodeTypeNameMappings[i].StatusCode), []byte("\""+h.dataSourceConfig.StatusCodeTypeNameMappings[i].TypeName+"\""))
- if err != nil {
- h.Log.Error("HttpJsonDataSourcePlanner set statusCodeTypeMapping", log.Error(err))
- return
- }
- }
- default:
- typeNameValue, err = sjson.SetRawBytes(typeNameValue, "defaultTypeName", quotedFieldDefinitionTypeName)
- if err != nil {
- h.Log.Error("HttpJsonDataSourcePlanner set defaultTypeName (switch case default)", log.Error(err))
- return
- }
- }
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: literal.TYPENAME,
- Value: typeNameValue,
- })
-}
-
-type HttpJsonDataSource struct {
- Log log.Logger
- Client *http.Client
- WhitelistedSchemes []string
- Hooks Hooks
-}
-
-func (r *HttpJsonDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) {
- urlArg := args.ByKey(literal.URL)
- methodArg := args.ByKey(literal.METHOD)
- bodyArg := args.ByKey(literal.BODY)
- headersArg := args.ByKey(literal.HEADERS)
- typeNameArg := args.ByKey(literal.TYPENAME)
- rootTypeName := args.ByKey(RootTypeName)
- rootFieldName := args.ByKey(RootFieldName)
- hookContext := HookContext{
- TypeName: string(rootTypeName),
- FieldName: string(rootFieldName),
- }
-
- r.Log.Debug("HttpJsonDataSource.Resolve.Args",
- log.Strings("resolvedArgs", args.Dump()),
- )
-
- switch {
- case urlArg == nil:
- r.Log.Error(fmt.Sprintf("arg '%s' must not be nil", string(literal.URL)))
- return
- case methodArg == nil:
- r.Log.Error(fmt.Sprintf("arg '%s' must not be nil", string(literal.METHOD)))
- return
- }
-
- httpMethod := http.MethodGet
- switch {
- case bytes.Equal(methodArg, literal.HTTP_METHOD_GET):
- httpMethod = http.MethodGet
- case bytes.Equal(methodArg, literal.HTTP_METHOD_POST):
- httpMethod = http.MethodPost
- case bytes.Equal(methodArg, literal.HTTP_METHOD_PUT):
- httpMethod = http.MethodPut
- case bytes.Equal(methodArg, literal.HTTP_METHOD_DELETE):
- httpMethod = http.MethodDelete
- case bytes.Equal(methodArg, literal.HTTP_METHOD_PATCH):
- httpMethod = http.MethodPatch
- }
-
- parsedURL, rawURL, err := parseURLBytes(urlArg)
- if err != nil {
- r.Log.Error("HttpJsonDataSource.RawURL could not be parsed", log.String("rawURL", rawURL))
- return
- }
-
- if len(parsedURL.Scheme) == 0 || !isWhitelistedScheme(parsedURL.Scheme, r.WhitelistedSchemes, httpJsonSchemes) {
- parsedURL.Scheme = httpJsonSchemes[0]
- }
-
- header := make(http.Header)
- if len(headersArg) != 0 {
- err := jsonparser.ObjectEach(headersArg, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
- header.Set(string(key), string(value))
- return nil
- })
- if err != nil {
- r.Log.Error("accessing headers", log.Error(err))
- }
- }
-
- r.Log.Debug("HttpJsonDataSource.Resolve",
- log.String("rawURL", rawURL),
- log.String("parsedURL", parsedURL.String()),
- )
-
- var bodyReader io.Reader
- if len(bodyArg) != 0 {
- bodyReader = bytes.NewReader(bodyArg)
- }
-
- request, err := http.NewRequest(httpMethod, parsedURL.String(), bodyReader)
- if err != nil {
- r.Log.Error("HttpJsonDataSource.Resolve.NewRequest",
- log.Error(err),
- )
- return
- }
-
- request.Header = header
-
- if r.Hooks.PreSendHttpHook != nil {
- r.Hooks.PreSendHttpHook.Execute(hookContext, request)
- }
-
- res, err := r.Client.Do(request)
- if err != nil {
- r.Log.Error("HttpJsonDataSource.Resolve.Client.Do",
- log.Error(err),
- )
- return
- }
-
- data, err := ioutil.ReadAll(res.Body)
- if err != nil {
- r.Log.Error("HttpJsonDataSource.Resolve.ioutil.ReadAll",
- log.Error(err),
- )
- return
- }
-
- if r.Hooks.PostReceiveHttpHook != nil {
- r.Hooks.PostReceiveHttpHook.Execute(hookContext, res, data)
- }
-
- defer func() {
- err := res.Body.Close()
- if err != nil {
- r.Log.Error("HttpJsonDataSource.Resolve.Response.Body.Close", log.Error(err))
- }
- }()
-
- statusCode := strconv.Itoa(res.StatusCode)
- statusCodeTypeName := gjson.GetBytes(typeNameArg, statusCode)
- defaultTypeName := gjson.GetBytes(typeNameArg, "defaultTypeName")
- var result *gjson.Result
- if statusCodeTypeName.Exists() {
- result = &statusCodeTypeName
- }
- if result == nil && defaultTypeName.Exists() {
- result = &defaultTypeName
- }
-
- if result != nil {
- parsed := gjson.ParseBytes(data)
- if parsed.IsArray() {
- arrayData := []byte(`[]`)
- items := parsed.Array()
- for i := range items {
- item, err := sjson.SetRaw(items[i].Raw, "__typename", result.Raw)
- if err != nil {
- r.Log.Error("HttpJsonDataSource.Resolve.array.setDefaultTypeName",
- log.Error(err),
- )
- }
- arrayData, err = sjson.SetRawBytes(arrayData, "-1", unsafebytes.StringToBytes(item))
- if err != nil {
- r.Log.Error("HttpJsonDataSource.Resolve.array.setArrayItem",
- log.Error(err),
- )
- }
- }
- data = arrayData
- } else {
- data, err = sjson.SetRawBytes(data, "__typename", []byte(result.Raw))
- if err != nil {
- r.Log.Error("HttpJsonDataSource.Resolve.setDefaultTypeName",
- log.Error(err),
- )
- return
- }
- }
- }
-
- return out.Write(data)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_http_polling_stream.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_http_polling_stream.go
deleted file mode 100644
index f7aa5360020..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_http_polling_stream.go
+++ /dev/null
@@ -1,252 +0,0 @@
-package datasource
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "io"
- "io/ioutil"
- "net/http"
- "strings"
- "sync"
- "text/template"
- "time"
-
- log "github.com/jensneuse/abstractlogger"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type HttpPollingStreamDataSourceConfiguration struct {
- Host string
- URL string
- DelaySeconds *int
-}
-
-type HttpPollingStreamDataSourcePlannerFactoryFactory struct {
-}
-
-func (h HttpPollingStreamDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) {
- factory := &HttpPollingStreamDataSourcePlannerFactory{
- base: base,
- }
- return factory, json.NewDecoder(configReader).Decode(&factory.config)
-}
-
-type HttpPollingStreamDataSourcePlannerFactory struct {
- base BasePlanner
- config HttpPollingStreamDataSourceConfiguration
-}
-
-func (h HttpPollingStreamDataSourcePlannerFactory) DataSourcePlanner() Planner {
- return &HttpPollingStreamDataSourcePlanner{
- BasePlanner: h.base,
- dataSourceConfig: h.config,
- }
-}
-
-type HttpPollingStreamDataSourcePlanner struct {
- BasePlanner
- dataSourceConfig HttpPollingStreamDataSourceConfiguration
- delay time.Duration
-}
-
-func (h *HttpPollingStreamDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) {
- return &HttpPollingStreamDataSource{
- Log: h.Log,
- Delay: h.delay,
- }, append(h.Args, args...)
-}
-
-func (h *HttpPollingStreamDataSourcePlanner) EnterDocument(operation, definition *ast.Document) {
-
-}
-
-func (h *HttpPollingStreamDataSourcePlanner) EnterInlineFragment(ref int) {
-
-}
-
-func (h *HttpPollingStreamDataSourcePlanner) LeaveInlineFragment(ref int) {
-
-}
-
-func (h *HttpPollingStreamDataSourcePlanner) EnterSelectionSet(ref int) {
-
-}
-
-func (h *HttpPollingStreamDataSourcePlanner) LeaveSelectionSet(ref int) {
-
-}
-
-func (h *HttpPollingStreamDataSourcePlanner) EnterField(ref int) {
- h.RootField.SetIfNotDefined(ref)
-}
-
-func (h *HttpPollingStreamDataSourcePlanner) EnterArgument(ref int) {
-
-}
-
-func (h *HttpPollingStreamDataSourcePlanner) LeaveField(ref int) {
- if !h.RootField.IsDefinedAndEquals(ref) {
- return
- }
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: literal.HOST,
- Value: []byte(h.dataSourceConfig.Host),
- })
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: literal.URL,
- Value: []byte(h.dataSourceConfig.URL),
- })
- if h.dataSourceConfig.DelaySeconds == nil {
- h.delay = time.Second * time.Duration(1)
- } else {
- h.delay = time.Second * time.Duration(*h.dataSourceConfig.DelaySeconds)
- }
-}
-
-type HttpPollingStreamDataSource struct {
- Log log.Logger
- once sync.Once
- ch chan []byte
- closed bool
- Delay time.Duration
- client *http.Client
- request *http.Request
- lastData []byte
-}
-
-func (h *HttpPollingStreamDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) {
- h.once.Do(func() {
- h.ch = make(chan []byte)
- h.request = h.generateRequest(args)
- h.client = &http.Client{
- Timeout: time.Second * 5,
- Transport: &http.Transport{
- MaxIdleConnsPerHost: 1024,
- TLSHandshakeTimeout: 0 * time.Second,
- },
- }
- go h.startPolling(ctx)
- })
- if h.closed {
- return
- }
- select {
- case data := <-h.ch:
- h.Log.Debug("HttpPollingStreamDataSource.Resolve.out.Write",
- log.ByteString("data", data),
- )
- _, err := out.Write(data)
- if err != nil {
- h.Log.Error("HttpPollingStreamDataSource.Resolve",
- log.Error(err),
- )
- }
- case <-ctx.Done():
- h.closed = true
- return
- }
- return
-}
-
-func (h *HttpPollingStreamDataSource) startPolling(ctx context.Context) {
- first := true
- for {
- if first {
- first = !first
- } else {
- time.Sleep(h.Delay)
- }
- var data []byte
- select {
- case <-ctx.Done():
- h.closed = true
- return
- default:
- response, err := h.client.Do(h.request)
- if err != nil {
- h.Log.Error("HttpPollingStreamDataSource.startPolling.client.Do",
- log.Error(err),
- )
- return
- }
- data, err = ioutil.ReadAll(response.Body)
- if err != nil {
- h.Log.Error("HttpPollingStreamDataSource.startPolling.ioutil.ReadAll",
- log.Error(err),
- )
- return
- }
- }
- if bytes.Equal(data, h.lastData) {
- continue
- }
- h.lastData = data
- select {
- case <-ctx.Done():
- h.closed = true
- return
- case h.ch <- data:
- continue
- }
- }
-}
-
-func (h *HttpPollingStreamDataSource) generateRequest(args ResolverArgs) *http.Request {
- hostArg := args.ByKey(literal.HOST)
- urlArg := args.ByKey(literal.URL)
-
- h.Log.Debug("HttpPollingStreamDataSource.generateRequest.Resolve.Args",
- log.Strings("resolvedArgs", args.Dump()),
- )
-
- if hostArg == nil || urlArg == nil {
- h.Log.Error("HttpPollingStreamDataSource.generateRequest.Args invalid")
- return nil
- }
-
- url := string(hostArg) + string(urlArg)
- if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
- url = "https://" + url
- }
-
- if strings.Contains(url, "{{") {
- tmpl, err := template.New("url").Parse(url)
- if err != nil {
- h.Log.Error("HttpPollingStreamDataSource.generateRequest.template.New",
- log.Error(err),
- )
- return nil
- }
- out := bytes.Buffer{}
- keys := args.Keys()
- data := make(map[string]string, len(keys))
- for i := 0; i < len(keys); i++ {
- data[string(keys[i])] = string(args.ByKey(keys[i]))
- }
- err = tmpl.Execute(&out, data)
- if err != nil {
- h.Log.Error("HttpPollingStreamDataSource.generateRequest.tmpl.Execute",
- log.Error(err),
- )
- return nil
- }
- url = out.String()
- }
-
- h.Log.Debug("HttpPollingStreamDataSource.generateRequest.Resolve",
- log.String("url", url),
- )
-
- request, err := http.NewRequest(http.MethodGet, url, nil)
- if err != nil {
- h.Log.Error("HttpPollingStreamDataSource.generateRequest.Resolve.NewRequest",
- log.Error(err),
- )
- return nil
- }
- request.Header.Add("Accept", "application/json")
- return request
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_mqtt.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_mqtt.go
deleted file mode 100644
index c60a26fec78..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_mqtt.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package datasource
-
-import (
- "context"
- "encoding/json"
- "io"
- "sync"
- "time"
-
- mqtt "github.com/eclipse/paho.mqtt.golang"
- log "github.com/jensneuse/abstractlogger"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type MQTTDataSourceConfig struct {
- BrokerAddr string
- ClientID string
- Topic string
-}
-
-type MQTTDataSourcePlannerFactoryFactory struct {
-}
-
-func (M MQTTDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) {
- factory := &MQTTDataSourcePlannerFactory{
- base: base,
- }
- return factory, json.NewDecoder(configReader).Decode(&factory.config)
-}
-
-type MQTTDataSourcePlannerFactory struct {
- base BasePlanner
- config MQTTDataSourceConfig
-}
-
-func (m MQTTDataSourcePlannerFactory) DataSourcePlanner() Planner {
- return &MQTTDataSourcePlanner{
- BasePlanner: m.base,
- dataSourceConfig: m.config,
- }
-}
-
-type MQTTDataSourcePlanner struct {
- BasePlanner
- dataSourceConfig MQTTDataSourceConfig
-}
-
-func (n *MQTTDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) {
- return &MQTTDataSource{
- log: n.Log,
- }, append(n.Args, args...)
-}
-
-func (n *MQTTDataSourcePlanner) EnterDocument(operation, definition *ast.Document) {
-
-}
-
-func (n *MQTTDataSourcePlanner) EnterInlineFragment(ref int) {
-
-}
-
-func (n *MQTTDataSourcePlanner) LeaveInlineFragment(ref int) {
-
-}
-
-func (n *MQTTDataSourcePlanner) EnterSelectionSet(ref int) {
-
-}
-
-func (n *MQTTDataSourcePlanner) LeaveSelectionSet(ref int) {
-
-}
-
-func (n *MQTTDataSourcePlanner) EnterField(ref int) {
- n.RootField.SetIfNotDefined(ref)
-}
-
-func (n *MQTTDataSourcePlanner) EnterArgument(ref int) {
-
-}
-
-func (n *MQTTDataSourcePlanner) LeaveField(ref int) {
- if !n.RootField.IsDefinedAndEquals(ref) {
- return
- }
- n.Args = append(n.Args, &StaticVariableArgument{
- Name: literal.BROKERADDR,
- Value: []byte(n.dataSourceConfig.BrokerAddr),
- })
- n.Args = append(n.Args, &StaticVariableArgument{
- Name: literal.CLIENTID,
- Value: []byte(n.dataSourceConfig.ClientID),
- })
- n.Args = append(n.Args, &StaticVariableArgument{
- Name: literal.TOPIC,
- Value: []byte(n.dataSourceConfig.Topic),
- })
-}
-
-type MQTTDataSource struct {
- log log.Logger
- once sync.Once
- ch chan mqtt.Message
- client mqtt.Client
-}
-
-func (m *MQTTDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) {
-
- defer func() {
- select {
- case <-ctx.Done():
- m.log.Debug("MQTTDataSource.Resolve.client.Disconnect")
- m.client.Disconnect(250)
- m.log.Debug("MQTTDataSource.Resolve.client.Disconnect.disconnected")
- default:
- return
- }
- }()
-
- m.once.Do(func() {
-
- brokerArg := args.ByKey(literal.BROKERADDR)
- clientIDArg := args.ByKey(literal.CLIENTID)
- topicArg := args.ByKey(literal.TOPIC)
-
- m.log.Debug("MQTTDataSource.Resolve.init",
- log.String("broker", string(brokerArg)),
- log.String("clientID", string(clientIDArg)),
- log.String("topic", string(topicArg)),
- )
-
- m.ch = make(chan mqtt.Message)
- m.start(string(brokerArg), string(clientIDArg), string(topicArg))
- })
-
- select {
- case <-ctx.Done():
- return
- case msg, ok := <-m.ch:
- if !ok {
- return
- }
- return out.Write(msg.Payload())
- }
-}
-
-func (m *MQTTDataSource) start(brokerAddr, clientID, topic string) {
- mqtt.ERROR = m.log.LevelLogger(log.ErrorLevel)
- mqtt.DEBUG = m.log.LevelLogger(log.DebugLevel)
- opts := mqtt.NewClientOptions().AddBroker(brokerAddr).SetClientID(clientID)
- opts.SetKeepAlive(5 * time.Second)
- opts.SetResumeSubs(true)
- opts.SetAutoReconnect(true)
- opts.SetDefaultPublishHandler(func(client mqtt.Client, msg mqtt.Message) {
- m.ch <- msg
- msg.Ack()
- })
- opts.SetPingTimeout(5 * time.Second)
-
- m.client = mqtt.NewClient(opts)
- if token := m.client.Connect(); token.Wait() && token.Error() != nil {
- m.log.Error("MQTTDataSource.start.Connect",
- log.Error(token.Error()),
- )
- close(m.ch)
- return
- }
-
- if token := m.client.Subscribe(topic, 0, nil); token.Wait() && token.Error() != nil {
- m.log.Error("MQTTDataSource.start.Subscribe",
- log.Error(token.Error()),
- )
- close(m.ch)
- return
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_nats.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_nats.go
deleted file mode 100644
index 28c455d9f09..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_nats.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package datasource
-
-import (
- "context"
- "encoding/json"
- "io"
- "sync"
- "time"
-
- log "github.com/jensneuse/abstractlogger"
- "github.com/nats-io/nats.go"
-
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type NatsDataSourceConfig struct {
- Addr string
- Topic string
-}
-
-type NatsDataSourcePlannerFactoryFactory struct {
-}
-
-func (n NatsDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) {
- factory := &NatsDataSourcePlannerFactory{
- base: base,
- }
- return factory, json.NewDecoder(configReader).Decode(&factory.config)
-}
-
-type NatsDataSourcePlannerFactory struct {
- base BasePlanner
- config NatsDataSourceConfig
-}
-
-func (n NatsDataSourcePlannerFactory) DataSourcePlanner() Planner {
- return SimpleDataSourcePlanner(&NatsDataSourcePlanner{
- BasePlanner: n.base,
- dataSourceConfig: n.config,
- })
-}
-
-type NatsDataSourcePlanner struct {
- BasePlanner
- dataSourceConfig NatsDataSourceConfig
-}
-
-func (n *NatsDataSourcePlanner) Plan([]Argument) (DataSource, []Argument) {
- n.Args = append(n.Args, &StaticVariableArgument{
- Name: literal.ADDR,
- Value: []byte(n.dataSourceConfig.Addr),
- })
- n.Args = append(n.Args, &StaticVariableArgument{
- Name: literal.TOPIC,
- Value: []byte(n.dataSourceConfig.Topic),
- })
- return &NatsDataSource{
- log: n.Log,
- }, n.Args
-}
-
-type NatsDataSource struct {
- log log.Logger
- conn *nats.Conn
- sub *nats.Subscription
- once sync.Once
-}
-
-func (d *NatsDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) {
- d.once.Do(func() {
-
- addrArg := args.ByKey(literal.ADDR)
- topicArg := args.ByKey(literal.TOPIC)
-
- addr := nats.DefaultURL
- topic := string(topicArg)
-
- if len(addrArg) != 0 {
- addr = string(addrArg)
- }
-
- go func() {
- <-ctx.Done()
- if d.sub != nil {
- d.log.Debug("NatsDataSource.unsubscribing",
- log.String("addr", addr),
- log.String("topic", topic),
- )
- err := d.sub.Unsubscribe()
- if err != nil {
- d.log.Error("Unsubscribe", log.Error(err))
- }
- }
- if d.conn != nil {
- d.log.Debug("NatsDataSource.closing",
- log.String("addr", addr),
- log.String("topic", topic),
- )
- d.conn.Close()
- }
- }()
-
- d.log.Debug("NatsDataSource.connecting",
- log.String("addr", addr),
- log.String("topic", topic),
- )
-
- d.conn, err = nats.Connect(addr)
- if err != nil {
- panic(err)
- }
-
- d.log.Debug("NatsDataSource.subscribing",
- log.String("addr", addr),
- log.String("topic", topic),
- )
-
- d.sub, err = d.conn.SubscribeSync(topic)
- if err != nil {
- panic(err)
- }
- })
-
- if err != nil {
- return n, err
- }
-
- message, err := d.sub.NextMsg(time.Minute)
- if err != nil {
- return n, err
- }
-
- return out.Write(message.Data)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_pipeline.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_pipeline.go
deleted file mode 100644
index fef4496016d..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_pipeline.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package datasource
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "io"
- "io/ioutil"
-
- log "github.com/jensneuse/abstractlogger"
- "github.com/jensneuse/pipeline/pkg/pipe"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type PipelineDataSourceConfig struct {
- /*
- ConfigFilePath is the path where the Pipeline configuration file can be found
- it needs to be in the json format according to the Pipeline json schema
- see this url for more info: https://github.com/jensneuse/pipeline
- */
- ConfigFilePath *string
- /*
- ConfigString is a string to configure the Pipeline
- it needs to be in the json format according to the Pipeline json schema
- see this url for more info: https://github.com/jensneuse/pipeline
- The PipelinDataSourcePlanner will always choose the configString over the configFilePath in case both are defined.
- */
- ConfigString *string
- // InputJSON is the template to define a JSON object based on the request, parameters etc. which gets passed to the first Pipeline step
- InputJSON string
-}
-
-type PipelineDataSourcePlannerFactoryFactory struct {
-}
-
-func (p PipelineDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) {
- factory := &PipelineDataSourcePlannerFactory{
- base: base,
- }
- return factory, json.NewDecoder(configReader).Decode(&factory.config)
-}
-
-type PipelineDataSourcePlannerFactory struct {
- base BasePlanner
- config PipelineDataSourceConfig
-}
-
-func (p PipelineDataSourcePlannerFactory) DataSourcePlanner() Planner {
- return &PipelineDataSourcePlanner{
- BasePlanner: p.base,
- dataSourceConfig: p.config,
- }
-}
-
-type PipelineDataSourcePlanner struct {
- BasePlanner
- dataSourceConfig PipelineDataSourceConfig
- rawPipelineConfig []byte
-}
-
-func (h *PipelineDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) {
-
- source := PipelineDataSource{
- Log: h.Log,
- }
-
- err := source.Pipeline.FromConfig(bytes.NewReader(h.rawPipelineConfig))
- if err != nil {
- h.Log.Error("PipelineDataSourcePlanner.pipe.FromConfig", log.Error(err))
- }
-
- return &source, append(h.Args, args...)
-}
-
-func (h *PipelineDataSourcePlanner) EnterDocument(operation, definition *ast.Document) {
-
-}
-
-func (h *PipelineDataSourcePlanner) EnterInlineFragment(ref int) {
-
-}
-
-func (h *PipelineDataSourcePlanner) LeaveInlineFragment(ref int) {
-
-}
-
-func (h *PipelineDataSourcePlanner) EnterSelectionSet(ref int) {
-
-}
-
-func (h *PipelineDataSourcePlanner) LeaveSelectionSet(ref int) {
-
-}
-
-func (h *PipelineDataSourcePlanner) EnterField(ref int) {
- h.RootField.SetIfNotDefined(ref)
-}
-
-func (h *PipelineDataSourcePlanner) EnterArgument(ref int) {
-
-}
-
-func (h *PipelineDataSourcePlanner) LeaveField(ref int) {
- if !h.RootField.IsDefinedAndEquals(ref) {
- return
- }
-
- if h.dataSourceConfig.ConfigString != nil {
- h.rawPipelineConfig = []byte(*h.dataSourceConfig.ConfigString)
- }
- if h.dataSourceConfig.ConfigFilePath != nil {
- var err error
- h.rawPipelineConfig, err = ioutil.ReadFile(*h.dataSourceConfig.ConfigFilePath)
- if err != nil {
- h.Log.Error("PipelineDataSourcePlanner.readConfigFile", log.Error(err))
- }
- }
-
- h.Args = append(h.Args, &StaticVariableArgument{
- Name: literal.INPUT_JSON,
- Value: []byte(h.dataSourceConfig.InputJSON),
- })
-}
-
-type PipelineDataSource struct {
- Log log.Logger
- Pipeline pipe.Pipeline
-}
-
-func (r *PipelineDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) {
-
- inputJSON := args.ByKey(literal.INPUT_JSON)
-
- err = r.Pipeline.Run(bytes.NewReader(inputJSON), out)
- if err != nil {
- r.Log.Error("PipelineDataSource.pipe.Run", log.Error(err))
- }
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_schema.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_schema.go
deleted file mode 100644
index ba28ab47708..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_schema.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package datasource
-
-import (
- "context"
- "encoding/json"
- "io"
-
- "github.com/jensneuse/graphql-go-tools/pkg/introspection"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type SchemaDataSourcePlannerConfig struct {
-}
-
-type SchemaDataSourcePlannerFactoryFactory struct {
-}
-
-func (s SchemaDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) {
- factory := &SchemaDataSourcePlannerFactory{
- base: base,
- }
- err := json.NewDecoder(configReader).Decode(&factory.config)
- if err != nil {
- return factory, err
- }
- gen := introspection.NewGenerator()
- var data introspection.Data
- var report operationreport.Report
- gen.Generate(base.Definition, &report, &data)
- factory.schemaBytes, err = json.Marshal(data)
- return factory, err
-}
-
-type SchemaDataSourcePlannerFactory struct {
- base BasePlanner
- config SchemaDataSourcePlannerConfig
- schemaBytes []byte
-}
-
-func (s SchemaDataSourcePlannerFactory) DataSourcePlanner() Planner {
- return SimpleDataSourcePlanner(&SchemaDataSourcePlanner{
- BasePlanner: s.base,
- dataSourceConfig: s.config,
- schemaBytes: s.schemaBytes,
- })
-}
-
-type SchemaDataSourcePlanner struct {
- BasePlanner
- dataSourceConfig SchemaDataSourcePlannerConfig
- schemaBytes []byte
-}
-
-func (s *SchemaDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) {
- return &SchemaDataSource{
- SchemaBytes: s.schemaBytes,
- }, append(s.Args, args...)
-}
-
-type SchemaDataSource struct {
- SchemaBytes []byte
-}
-
-func (s *SchemaDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) {
- return out.Write(s.SchemaBytes)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_static.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_static.go
deleted file mode 100644
index ef8f83420ae..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_static.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package datasource
-
-import (
- "context"
- "encoding/json"
- "io"
-)
-
-type StaticDataSourceConfig struct {
- Data string
-}
-
-type StaticDataSourcePlannerFactoryFactory struct {
-}
-
-func (s StaticDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) {
- factory := &StaticDataSourcePlannerFactory{
- base: base,
- }
- return factory, json.NewDecoder(configReader).Decode(&factory.config)
-}
-
-type StaticDataSourcePlannerFactory struct {
- base BasePlanner
- config StaticDataSourceConfig
-}
-
-func (s StaticDataSourcePlannerFactory) DataSourcePlanner() Planner {
- return SimpleDataSourcePlanner(&StaticDataSourcePlanner{
- BasePlanner: s.base,
- dataSourceConfig: s.config,
- })
-}
-
-type StaticDataSourcePlanner struct {
- BasePlanner
- dataSourceConfig StaticDataSourceConfig
-}
-
-func (s *StaticDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) {
- return &StaticDataSource{
- Data: []byte(s.dataSourceConfig.Data),
- }, append(s.Args, args...)
-}
-
-type StaticDataSource struct {
- Data []byte
-}
-
-func (s StaticDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) {
- return out.Write(s.Data)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_type.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_type.go
deleted file mode 100644
index 5e42207b241..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/datasource_type.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package datasource
-
-import (
- "context"
- "encoding/json"
- "io"
-)
-
-type TypeDataSourcePlannerConfig struct {
-}
-
-type TypeDataSourcePlannerFactoryFactory struct {
-}
-
-func (t TypeDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) {
- factory := TypeDataSourcePlannerFactory{
- base: base,
- }
- return factory, json.NewDecoder(configReader).Decode(&factory.config)
-}
-
-type TypeDataSourcePlannerFactory struct {
- base BasePlanner
- config TypeDataSourcePlannerConfig
-}
-
-func (t TypeDataSourcePlannerFactory) DataSourcePlanner() Planner {
- return SimpleDataSourcePlanner(&TypeDataSourcePlanner{
- BasePlanner: t.base,
- dataSourceConfig: t.config,
- })
-}
-
-type TypeDataSourcePlanner struct {
- BasePlanner
- dataSourceConfig TypeDataSourcePlannerConfig
-}
-
-func (t *TypeDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) {
- return &TypeDataSource{}, append(t.Args, args...)
-}
-
-type TypeDataSource struct {
-}
-
-func (t *TypeDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) {
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/hooks.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/hooks.go
deleted file mode 100644
index ccd397e3d64..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/datasource/hooks.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package datasource
-
-import (
- "net/http"
-)
-
-type HookContext struct {
- TypeName string
- FieldName string
-}
-
-type Hooks struct {
- PreSendHttpHook PreSendHttpHook
- PostReceiveHttpHook PostReceiveHttpHook
-}
-
-type PreSendHttpHook interface {
- Execute(ctx HookContext, req *http.Request)
-}
-
-type PostReceiveHttpHook interface {
- Execute(ctx HookContext, resp *http.Response, body []byte)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/execution.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/execution.go
deleted file mode 100644
index 6fa5dc9f722..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/execution.go
+++ /dev/null
@@ -1,613 +0,0 @@
-// Package execution is a complete GraphQL runtime.
-// It contains a Handler to orchestrate the execution, a Query Planner to generate a Query Plan from an AST as well as the Executor to execute a Query Plan.
-package execution
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "fmt"
- "io"
- "strconv"
- "strings"
- "sync"
- "unicode/utf8"
-
- "github.com/buger/jsonparser"
- "github.com/cespare/xxhash"
- byte_template "github.com/jensneuse/byte-template"
- "github.com/tidwall/gjson"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/execution/datasource"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/runes"
-)
-
-type Executor struct {
- context Context
- out io.Writer
- err error
- buffers LockableBufferMap
- escapeBuf [48]byte
- templateDirectives []byte_template.DirectiveDefinition
-}
-
-type LockableBufferMap struct {
- sync.Mutex
- Buffers map[uint64]*bytes.Buffer
-}
-
-func NewExecutor(templateDirectives []byte_template.DirectiveDefinition) *Executor {
- return &Executor{
- buffers: LockableBufferMap{
- Buffers: map[uint64]*bytes.Buffer{},
- },
- templateDirectives: templateDirectives,
- }
-}
-
-func (e *Executor) Execute(ctx Context, node RootNode, w io.Writer) error {
- e.context = ctx
- e.out = w
- e.err = nil
-
- var path string
- switch node.OperationType() {
- case ast.OperationTypeQuery:
- path = "query"
- case ast.OperationTypeMutation:
- path = "mutation"
- case ast.OperationTypeSubscription:
- path = "subscription"
- }
- e.resolveNode(node, nil, path, nil, true)
- return e.err
-}
-
-// write writes the data to the out io.Writer if there is no error previously captured
-func (e *Executor) write(data []byte) {
- if e.err != nil {
- return
- }
- _, e.err = e.out.Write(data)
-}
-
-// writeQuoted quotes and writes the data to the out io.Writer if there is no error previously captured
-func (e *Executor) writeQuoted(data []byte) {
- e.write(literal.QUOTE)
- e.write(data)
- e.write(literal.QUOTE)
-}
-
-func (e *Executor) resolveNode(node Node, data []byte, path string, prefetch *sync.WaitGroup, shouldFetch bool) {
-
- switch node := node.(type) {
- case *Object:
- if data != nil { // in case data is not nil apply any path selection/transformation and return early if there is no data
- data = e.resolveData(node.DataResolvingConfig, data)
- if data == nil || bytes.Equal(data, literal.NULL) {
- e.write(literal.NULL)
- return
- }
- }
- if shouldFetch && node.Fetch != nil { // execute the fetch on the object
- _, err := node.Fetch.Fetch(e.context, data, e, path, &e.buffers)
- if err != nil {
- e.err = err
- }
- if prefetch != nil { // in case this was a prefetch we can immediately return
- prefetch.Done()
- return
- }
- }
- e.write(literal.LBRACE) // start writing the object
- hasPreviousValue := false
- for i := 0; i < len(node.Fields); i++ {
- if node.Fields[i].Skip != nil {
- if node.Fields[i].Skip.Evaluate(e.context, data) {
- continue
- }
- }
- if hasPreviousValue { // separate all values with a comma in case we have at least one previous (unskipped field)
- e.write(literal.COMMA)
- }
- hasPreviousValue = true
- e.resolveNode(&node.Fields[i], data, path, nil, true) // recursively evaluate all fields
- }
- e.write(literal.RBRACE) // end writing the object
- case *Field:
- path = path + "." + unsafebytes.BytesToString(node.Name) // add the node name to the path using a "." as separator
- if node.HasResolvedData { // in case this field has associated resolved data we have to fetch it from the buffer
- if buf := e.buffers.Buffers[xxhash.Sum64String(path)]; buf != nil {
- data = buf.Bytes()
- }
- }
- e.writeQuoted(node.Name)
- e.write(literal.COLON)
- if data == nil && !node.Value.HasResolversRecursively() {
- e.write(literal.NULL)
- return
- }
- e.resolveNode(node.Value, data, path, nil, true)
- case *Value:
- data = e.resolveData(node.DataResolvingConfig, data)
- _, e.err = node.ValueType.writeValue(data, e.escapeBuf[:], e.out)
- return
- case *List:
- data = e.resolveData(node.DataResolvingConfig, data)
- if len(data) == 0 {
- e.write(literal.NULL)
- return
- }
- shouldPrefetch := false
- switch object := node.Value.(type) {
- case *Object:
- if object.Fetch != nil {
- shouldPrefetch = true
- }
- }
- result := gjson.ParseBytes(data).Array()
- listItems := make([][]byte, len(result))
- for i := range result {
- if result[i].Type == gjson.String {
- listItems[i] = unsafebytes.StringToBytes(result[i].Str)
- } else {
- listItems[i] = unsafebytes.StringToBytes(result[i].Raw)
- }
- }
- path = path + "."
- maxItems := len(listItems)
- if node.Filter != nil {
- switch filter := node.Filter.(type) {
- case *ListFilterFirstN:
- if maxItems > filter.FirstN {
- maxItems = filter.FirstN
- }
- }
- }
- if shouldPrefetch {
- wg := &sync.WaitGroup{}
- for i := 0; i < maxItems; i++ {
- wg.Add(1)
- go e.resolveNode(node.Value, listItems[i], path+strconv.Itoa(i), wg, true)
- }
- wg.Wait()
- }
- i := 0
- for i = 0; i < maxItems; i++ {
- if i == 0 {
- e.write(literal.LBRACK)
- } else {
- e.write(literal.COMMA)
- }
- e.resolveNode(node.Value, listItems[i], path+strconv.Itoa(i), nil, false)
- }
- if i == 0 || e.err == jsonparser.KeyPathNotFoundError {
- e.err = nil
- e.write(literal.LBRACK)
- }
- e.write(literal.RBRACK)
- }
-}
-
-func (e *Executor) resolveData(config DataResolvingConfig, data []byte) []byte {
- if len(data) == 0 {
- return nil
- }
- if config.PathSelector.Path == "" {
- return data
- }
- result := gjson.GetBytes(data, config.PathSelector.Path)
- if config.Transformation == nil && result.Type == gjson.String {
- data = unsafebytes.StringToBytes(result.Str)
- } else {
- data = unsafebytes.StringToBytes(result.Raw)
- }
- if config.Transformation == nil {
- return data
- }
- data, e.err = config.Transformation.Transform(data)
- return data
-}
-
-func (e *Executor) ResolveArgs(args []datasource.Argument, data []byte) ResolvedArgs {
-
- args = append(args, e.context.ExtraArguments...)
-
- resolved := make(ResolvedArgs, len(args))
- for i := 0; i < len(args); i++ {
- switch arg := args[i].(type) {
- case *datasource.StaticVariableArgument:
- resolved[i].Key = arg.Name
- resolved[i].Value = arg.Value
- case *datasource.ObjectVariableArgument:
- resolved[i].Key = arg.Name
- result := gjson.GetBytes(data, arg.PathSelector.Path)
- resolved[i].Value = unsafebytes.StringToBytes(result.Raw)
- case *datasource.ContextVariableArgument:
- resolved[i].Key = arg.Name
- resolved[i].Value = e.context.Variables[xxhash.Sum64(arg.VariableName)]
- case *datasource.ListArgument:
- resolved[i].Key = arg.Name
- listArgs := e.ResolveArgs(arg.Arguments, data)
- listValues := make(map[string]string, len(listArgs))
- for j := range listArgs {
- listValues[string(listArgs[j].Key)] = string(listArgs[j].Value)
- }
- resolved[i].Value, _ = json.Marshal(listValues)
- }
- }
-
- buf := bytes.Buffer{}
- tmpl := byte_template.New(e.templateDirectives...)
-
- for i := range resolved {
- if !bytes.Contains(resolved[i].Value, literal.DOUBLE_LBRACE) {
- continue
- }
- _, err := tmpl.Execute(&buf, resolved[i].Value, func(w io.Writer, path []byte) (n int, err error) {
- path = bytes.TrimFunc(path, func(r rune) bool {
- return r == runes.SPACE || r == runes.TAB || r == runes.LINETERMINATOR
- })
- if bytes.Count(path, literal.DOT) == 1 {
- path = bytes.TrimPrefix(path, literal.DOT)
- for j := range resolved {
- if bytes.Equal(resolved[j].Key, path) {
- return w.Write(resolved[j].Value)
- }
- }
- }
- if bytes.HasPrefix(path, literal.DOT_OBJECT_DOT) {
- path = bytes.TrimPrefix(path, literal.DOT_OBJECT_DOT)
- result := gjson.GetBytes(data, unsafebytes.BytesToString(path))
- if result.Type == gjson.String {
- return w.Write(unsafebytes.StringToBytes(result.Str))
- }
- return w.Write(unsafebytes.StringToBytes(result.Raw))
- }
- for j := range resolved {
- key := resolved[j].Key
- if bytes.HasPrefix(path, literal.DOT) && !bytes.HasPrefix(key, literal.DOT) {
- key = append(literal.DOT, key...)
- }
- if !bytes.HasPrefix(path, key) {
- continue
- }
- key = bytes.TrimPrefix(path, key)
- if len(key) == 0 {
- return w.Write(resolved[j].Value)
- }
- key = bytes.TrimPrefix(key, literal.DOT)
-
- result := gjson.GetBytes(resolved[j].Value, unsafebytes.BytesToString(key))
-
- if result.Type == gjson.String {
- resultBytes := unsafebytes.StringToBytes(strings.Trim(strconv.Quote(result.Str), `"`))
- return w.Write(resultBytes)
- }
-
- rawResultBytes := unsafebytes.StringToBytes(result.Raw)
- return w.Write(rawResultBytes)
- }
- _, _ = w.Write(literal.LBRACE)
- _, _ = w.Write(literal.LBRACE)
- _, _ = w.Write(literal.SPACE)
- _, _ = w.Write(path)
- _, _ = w.Write(literal.SPACE)
- _, _ = w.Write(literal.RBRACE)
- return w.Write(literal.RBRACE)
- })
- if err == nil {
- value := buf.Bytes()
- resolved[i].Value = make([]byte, len(value))
- copy(resolved[i].Value, value)
- buf.Reset()
- }
- }
-
- resolved.Filter(func(i int) (keep bool) {
- return !bytes.HasPrefix(resolved[i].Key, literal.DOT)
- })
-
- return resolved
-}
-
-const (
- ObjectKind NodeKind = iota + 1
- FieldKind
- ListKind
- ValueKind
-)
-
-type NodeKind int
-
-type Node interface {
- // Kind returns the NodeKind of each Node
- Kind() NodeKind
- // HasResolversRecursively returns true if this Node or any child Node has a resolver
- HasResolversRecursively() bool
-}
-
-type RootNode interface {
- Node
- OperationType() ast.OperationType
-}
-
-type Context struct {
- context.Context
- Variables Variables
- ExtraArguments []datasource.Argument
-}
-
-type Variables map[uint64][]byte
-
-type ResolvedArgument struct {
- Key []byte
- Value []byte
-}
-
-type ResolvedArgs []ResolvedArgument
-
-func (r ResolvedArgs) Keys() [][]byte {
- keys := make([][]byte, len(r))
- for i := range r {
- keys[i] = (r)[i].Key
- }
- return keys
-}
-
-func (r *ResolvedArgs) Filter(condition func(i int) (keep bool)) {
- n := 0
- for i := range *r {
- if condition(i) {
- (*r)[n] = (*r)[i]
- n++
- }
- }
- *r = (*r)[:n]
-}
-
-func (r ResolvedArgs) ByKey(key []byte) []byte {
- for i := 0; i < len(r); i++ {
- if bytes.Equal(r[i].Key, key) {
- return r[i].Value
- }
- }
- return nil
-}
-
-func (r ResolvedArgs) Dump() []string {
- out := make([]string, len(r))
- for i := range r {
- out[i] = string(r[i].Key) + "=" + string(r[i].Value)
- }
- return out
-}
-
-type DataResolvingConfig struct {
- PathSelector datasource.PathSelector
- Transformation Transformation
-}
-
-type Object struct {
- DataResolvingConfig DataResolvingConfig
- Fields []Field
- Fetch Fetch
- operationType ast.OperationType
-}
-
-func (o *Object) OperationType() ast.OperationType {
- return o.operationType
-}
-
-type ArgsResolver interface {
- ResolveArgs(args []datasource.Argument, data []byte) ResolvedArgs
-}
-
-type Fetch interface {
- Fetch(ctx Context, data []byte, argsResolver ArgsResolver, suffix string, buffers *LockableBufferMap) (n int, err error)
-}
-
-type SingleFetch struct {
- Source *DataSourceInvocation
- BufferName string
-}
-
-func (s *SingleFetch) Fetch(ctx Context, data []byte, argsResolver ArgsResolver, path string, buffers *LockableBufferMap) (int, error) {
- bufferName := path + "." + s.BufferName
- hash := xxhash.Sum64String(bufferName)
- buffers.Lock()
- buffer, exists := buffers.Buffers[hash]
- buffers.Unlock()
- if !exists {
- buffer = bytes.NewBuffer(make([]byte, 0, 1024))
- buffers.Lock()
- buffers.Buffers[hash] = buffer
- buffers.Unlock()
- } else {
- buffer.Reset()
- }
- return s.Source.DataSource.Resolve(ctx, argsResolver.ResolveArgs(s.Source.Args, data), buffer)
-}
-
-type SerialFetch struct {
- Fetches []Fetch
-}
-
-func (s *SerialFetch) Fetch(ctx Context, data []byte, argsResolver ArgsResolver, suffix string, buffers *LockableBufferMap) (n int, err error) {
- for i := 0; i < len(s.Fetches); i++ {
- nextN, nextErr := s.Fetches[i].Fetch(ctx, data, argsResolver, suffix, buffers)
- if nextErr != nil {
- return n, nextErr
- }
- n = n + nextN
- }
- return
-}
-
-type ParallelFetch struct {
- wg sync.WaitGroup
- Fetches []Fetch
-}
-
-func (p *ParallelFetch) Fetch(ctx Context, data []byte, argsResolver ArgsResolver, suffix string, buffers *LockableBufferMap) (n int, err error) {
- for i := 0; i < len(p.Fetches); i++ {
- p.wg.Add(1)
- go func(fetch Fetch, ctx Context, data []byte, argsResolver ArgsResolver) {
- _, _ = fetch.Fetch(ctx, data, argsResolver, suffix, buffers) // TODO: handle results
- p.wg.Done()
- }(p.Fetches[i], ctx, data, argsResolver)
- }
- p.wg.Wait()
- return
-}
-
-func (o *Object) HasResolversRecursively() bool {
- for i := 0; i < len(o.Fields); i++ {
- if o.Fields[i].HasResolversRecursively() {
- return true
- }
- }
- return false
-}
-
-func (*Object) Kind() NodeKind {
- return ObjectKind
-}
-
-type BooleanCondition interface {
- Evaluate(ctx Context, data []byte) bool
-}
-
-type Field struct {
- Name []byte
- Value Node
- Skip BooleanCondition
- HasResolvedData bool
-}
-
-func (f *Field) HasResolversRecursively() bool {
- return f.HasResolvedData || f.Value.HasResolversRecursively()
-}
-
-type IfEqual struct {
- Left, Right datasource.Argument
-}
-
-func (i *IfEqual) Evaluate(ctx Context, data []byte) bool {
- var left []byte
- var right []byte
-
- switch value := i.Left.(type) {
- case *datasource.ContextVariableArgument:
- left = ctx.Variables[xxhash.Sum64(value.VariableName)]
- case *datasource.ObjectVariableArgument:
- result := gjson.GetBytes(data, value.PathSelector.Path)
- if result.Type == gjson.String {
- left = unsafebytes.StringToBytes(result.Str)
- } else {
- left = unsafebytes.StringToBytes(result.Raw)
- }
- case *datasource.StaticVariableArgument:
- left = value.Value
- }
-
- switch value := i.Right.(type) {
- case *datasource.ContextVariableArgument:
- right = ctx.Variables[xxhash.Sum64(value.VariableName)]
- case *datasource.ObjectVariableArgument:
- result := gjson.GetBytes(data, value.PathSelector.Path)
- if result.Type == gjson.String {
- right = unsafebytes.StringToBytes(result.Str)
- } else {
- right = unsafebytes.StringToBytes(result.Raw)
- }
- case *datasource.StaticVariableArgument:
- right = value.Value
- }
-
- return bytes.Equal(left, right)
-}
-
-type IfNotEqual struct {
- Left, Right datasource.Argument
-}
-
-func (i *IfNotEqual) Evaluate(ctx Context, data []byte) bool {
- equal := IfEqual{
- Left: i.Left,
- Right: i.Right,
- }
- return !equal.Evaluate(ctx, data)
-}
-
-func (*Field) Kind() NodeKind {
- return FieldKind
-}
-
-type Value struct {
- DataResolvingConfig DataResolvingConfig
- ValueType JSONValueType
-}
-
-func (value *Value) HasResolversRecursively() bool {
- return false
-}
-
-func (*Value) Kind() NodeKind {
- return ValueKind
-}
-
-type List struct {
- DataResolvingConfig DataResolvingConfig
- Value Node
- Filter ListFilter
-}
-
-func (l *List) HasResolversRecursively() bool {
- return l.Value.HasResolversRecursively()
-}
-
-func (*List) Kind() NodeKind {
- return ListKind
-}
-
-type ListFilter interface {
- Kind() ListFilterKind
-}
-
-type ListFilterKind int
-
-const (
- ListFilterKindFirstN ListFilterKind = iota + 1
-)
-
-type ListFilterFirstN struct {
- FirstN int
-}
-
-func (_ ListFilterFirstN) Kind() ListFilterKind {
- return ListFilterKindFirstN
-}
-
-type DataSourceInvocation struct {
- Args []datasource.Argument
- DataSource datasource.DataSource
-}
-
-func isJSONObjectAsBytes(input []byte) bool {
- trimmedInput := bytes.Trim(input, " ")
- firstRune, _ := utf8.DecodeRune(trimmedInput)
- lastRune, _ := utf8.DecodeLastRune(trimmedInput)
- return fmt.Sprintf("%c", firstRune) == "{" && fmt.Sprintf("%c", lastRune) == "}"
-}
-
-func byteSliceContainsEscapedQuotes(input []byte) bool {
- return bytes.Contains(input, []byte(`\"`))
-}
-
-func byteSliceContainsQuotes(input []byte) bool {
- return bytes.Contains(input, []byte(`"`))
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/handler.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/handler.go
deleted file mode 100644
index 9f95796f886..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/handler.go
+++ /dev/null
@@ -1,110 +0,0 @@
-//go:generate packr
-//go:generate graphql-go-tools gen directiveUnmarshalCode -f ./graphql_definitions/**/*.graphql -p execution -o ./datasource_config.go -s Config
-package execution
-
-import (
- "encoding/json"
-
- "github.com/buger/jsonparser"
- "github.com/cespare/xxhash"
- byte_template "github.com/jensneuse/byte-template"
-
- "github.com/jensneuse/graphql-go-tools/pkg/astnormalization"
- "github.com/jensneuse/graphql-go-tools/pkg/astparser"
- "github.com/jensneuse/graphql-go-tools/pkg/astvalidation"
- "github.com/jensneuse/graphql-go-tools/pkg/execution/datasource"
-)
-
-type Handler struct {
- templateDirectives []byte_template.DirectiveDefinition
- base *datasource.BasePlanner
-}
-
-func NewHandler(base *datasource.BasePlanner, templateDirectives []byte_template.DirectiveDefinition) *Handler {
- return &Handler{
- templateDirectives: templateDirectives,
- base: base,
- }
-}
-
-type GraphqlRequest struct {
- OperationName string `json:"operationName"`
- Variables json.RawMessage `json:"variables"`
- Query string `json:"query"`
-}
-
-func (h *Handler) Handle(requestData, extraVariables []byte) (executor *Executor, node RootNode, ctx Context, err error) {
-
- var graphqlRequest GraphqlRequest
- err = json.Unmarshal(requestData, &graphqlRequest)
- if err != nil {
- return
- }
-
- operationDocument, report := astparser.ParseGraphqlDocumentString(graphqlRequest.Query)
- if report.HasErrors() {
- err = report
- return
- }
-
- variables, extraArguments := VariablesFromJson(graphqlRequest.Variables, extraVariables)
-
- planner := NewPlanner(h.base)
- if report.HasErrors() {
- err = report
- return
- }
-
- astnormalization.NormalizeOperation(&operationDocument, h.base.Definition, &report)
- if report.HasErrors() {
- err = report
- return
- }
-
- validator := astvalidation.DefaultOperationValidator()
- if report.HasErrors() {
- err = report
- return
- }
- validator.Validate(&operationDocument, h.base.Definition, &report)
- if report.HasErrors() {
- err = report
- return
- }
- normalizer := astnormalization.NewNormalizer(true, true)
- normalizer.NormalizeOperation(&operationDocument, h.base.Definition, &report)
- if report.HasErrors() {
- err = report
- return
- }
- plan := planner.Plan(&operationDocument, h.base.Definition, graphqlRequest.OperationName, &report)
- if report.HasErrors() {
- err = report
- return
- }
-
- executor = NewExecutor(h.templateDirectives)
- ctx = Context{
- Variables: variables,
- ExtraArguments: extraArguments,
- }
-
- return executor, plan, ctx, err
-}
-
-func VariablesFromJson(requestVariables, extraVariables []byte) (variables Variables, extraArguments []datasource.Argument) {
- variables = map[uint64][]byte{}
- _ = jsonparser.ObjectEach(requestVariables, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
- variables[xxhash.Sum64(key)] = value
- return nil
- })
- _ = jsonparser.ObjectEach(extraVariables, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
- variables[xxhash.Sum64(key)] = value
- extraArguments = append(extraArguments, &datasource.ContextVariableArgument{
- Name: key,
- VariableName: key,
- })
- return nil
- })
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/jsonvaluetype.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/jsonvaluetype.go
deleted file mode 100644
index 14a1b5caf06..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/jsonvaluetype.go
+++ /dev/null
@@ -1,84 +0,0 @@
-//go:generate stringer -type=JSONValueType
-package execution
-
-import (
- "bytes"
- "fmt"
- "io"
- "strconv"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type JSONValueType int
-
-const (
- UnknownValueType JSONValueType = iota
- StringValueType
- IntegerValueType
- FloatValueType
- BooleanValueType
-)
-
-type ErrJSONValueTypeValueIncompatible struct {
- value []byte
- valueType JSONValueType
-}
-
-func (e ErrJSONValueTypeValueIncompatible) Error() string {
- return fmt.Sprintf("JSONValueType.writeValue: cannot write %s as %s", unsafebytes.BytesToString(e.value), e.valueType)
-}
-
-func (i JSONValueType) writeValue(value, escapeBuf []byte, out io.Writer) (n int, err error) {
-
- if len(value) == 0 || bytes.Equal(value, literal.NULL) {
- return i.write(n, err, out, literal.NULL)
- }
-
- switch i {
- case StringValueType:
- return i.write(n, err, out, []byte(strconv.Quote(string(value))))
- case IntegerValueType:
- if !unsafebytes.BytesIsValidInt64(value) {
- return n, ErrJSONValueTypeValueIncompatible{
- value: value,
- valueType: i,
- }
- }
- return i.write(n, err, out, value)
- case FloatValueType:
- if !unsafebytes.BytesIsValidFloat32(value) {
- return n, ErrJSONValueTypeValueIncompatible{
- value: value,
- valueType: i,
- }
- }
- return i.write(n, err, out, value)
- case BooleanValueType:
- if !unsafebytes.BytesIsValidBool(value) {
- return n, ErrJSONValueTypeValueIncompatible{
- value: value,
- valueType: i,
- }
- }
- if unsafebytes.BytesToBool(value) {
- return i.write(n, err, out, literal.TRUE)
- } else {
- return i.write(n, err, out, literal.FALSE)
- }
- default:
- return n, ErrJSONValueTypeValueIncompatible{
- value: value,
- valueType: i,
- }
- }
-}
-
-func (i JSONValueType) write(n int, err error, out io.Writer, value []byte) (int, error) {
- if err != nil {
- return n, err
- }
- written, err := out.Write(value)
- return n + written, err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/jsonvaluetype_string.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/jsonvaluetype_string.go
deleted file mode 100644
index 885bb9805e6..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/jsonvaluetype_string.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Code generated by "stringer -type=JSONValueType"; DO NOT EDIT.
-
-package execution
-
-import "strconv"
-
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[UnknownValueType-0]
- _ = x[StringValueType-1]
- _ = x[IntegerValueType-2]
- _ = x[FloatValueType-3]
- _ = x[BooleanValueType-4]
-}
-
-const _JSONValueType_name = "UnknownValueTypeStringValueTypeIntegerValueTypeFloatValueTypeBooleanValueType"
-
-var _JSONValueType_index = [...]uint8{0, 16, 31, 47, 61, 77}
-
-func (i JSONValueType) String() string {
- if i < 0 || i >= JSONValueType(len(_JSONValueType_index)-1) {
- return "JSONValueType(" + strconv.FormatInt(int64(i), 10) + ")"
- }
- return _JSONValueType_name[_JSONValueType_index[i]:_JSONValueType_index[i+1]]
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/planning.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/planning.go
deleted file mode 100644
index 1e9b4b9b1d7..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/planning.go
+++ /dev/null
@@ -1,435 +0,0 @@
-package execution
-
-import (
- "bytes"
- "io"
- "os"
-
- "github.com/jensneuse/pipeline/pkg/pipe"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/execution/datasource"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type Planner struct {
- walker *astvisitor.Walker
- visitor *planningVisitor
-}
-
-type DataSourceDefinition struct {
- // the type name to which the data source is attached
- TypeName []byte
- // the field on the type to which the data source is attached
- FieldName []byte
- // a factory method to return a new planner
- DataSourcePlannerFactory func() datasource.Planner
-}
-
-func NewPlanner(base *datasource.BasePlanner) *Planner {
- walker := astvisitor.NewWalker(48)
- visitor := planningVisitor{
- Walker: &walker,
- base: base,
- }
-
- walker.RegisterDocumentVisitor(&visitor)
- walker.RegisterEnterFieldVisitor(&visitor)
- walker.RegisterEnterArgumentVisitor(&visitor)
- walker.RegisterLeaveFieldVisitor(&visitor)
- walker.RegisterEnterSelectionSetVisitor(&visitor)
- walker.RegisterLeaveSelectionSetVisitor(&visitor)
- walker.RegisterEnterInlineFragmentVisitor(&visitor)
- walker.RegisterLeaveInlineFragmentVisitor(&visitor)
- walker.RegisterEnterOperationVisitor(&visitor)
-
- return &Planner{
- walker: &walker,
- visitor: &visitor,
- }
-}
-
-func (p *Planner) Plan(operation, definition *ast.Document, operationName string, report *operationreport.Report) RootNode {
- p.visitor.operationName = operationName
- p.walker.Walk(operation, definition, report)
- return p.visitor.rootNode
-}
-
-type planningVisitor struct {
- *astvisitor.Walker
- base *datasource.BasePlanner
- operation, definition *ast.Document
- rootNode RootNode
- currentNode []Node
- planners []dataSourcePlannerRef
- operationName string
- foundOperation bool
- isSingleOperation bool
-}
-
-type dataSourcePlannerRef struct {
- path ast.Path
- fieldRef int
- planner datasource.Planner
-}
-
-func (p *planningVisitor) EnterDocument(operation, definition *ast.Document) {
- p.operation, p.definition, p.base.Definition = operation, definition, definition
- p.foundOperation = false
- p.isSingleOperation = p.countOperationDefinitionsInRootNodes() == 1
-
- if len(operation.OperationDefinitions) == 0 {
- p.Walker.StopWithExternalErr(operationreport.ErrDocumentDoesntContainExecutableOperation())
- return
- }
-
- p.currentNode = p.currentNode[:0]
- if len(p.planners) != 0 {
- p.planners[len(p.planners)-1].planner.EnterDocument(operation, definition)
- }
-}
-
-func (p *planningVisitor) LeaveDocument(operation, definition *ast.Document) {
- if !p.isSingleOperation && len(p.operationName) == 0 {
- p.Report.AddExternalError(operationreport.ErrRequiredOperationNameIsMissing())
- } else if !p.foundOperation {
- p.Report.AddExternalError(operationreport.ErrOperationWithProvidedOperationNameNotFound(p.operationName))
- }
-}
-
-func (p *planningVisitor) EnterOperationDefinition(ref int) {
- operationName := p.operation.OperationDefinitionNameString(ref)
- if !p.isSingleOperation && operationName != p.operationName {
- p.SkipNode()
- return
- }
-
- p.foundOperation = true
- obj := &Object{}
- p.rootNode = &Object{
- operationType: p.operation.OperationDefinitions[ref].OperationType,
- Fields: []Field{
- {
- Name: literal.DATA,
- Value: obj,
- },
- },
- }
- p.currentNode = append(p.currentNode, obj)
-}
-
-func (p *planningVisitor) EnterInlineFragment(ref int) {
- if len(p.planners) != 0 {
- p.planners[len(p.planners)-1].planner.EnterInlineFragment(ref)
- }
-}
-
-func (p *planningVisitor) LeaveInlineFragment(ref int) {
- if len(p.planners) != 0 {
- p.planners[len(p.planners)-1].planner.LeaveInlineFragment(ref)
- }
-}
-
-func (p *planningVisitor) EnterField(ref int) {
-
- definition, exists := p.FieldDefinition(ref)
- if !exists {
- return
- }
-
- typeName := p.definition.NodeResolverTypeNameString(p.EnclosingTypeDefinition, p.Path)
- fieldName := p.operation.FieldNameString(ref)
-
- plannerFactory := p.base.Config.DataSourcePlannerFactoryForTypeField(typeName, fieldName)
- if plannerFactory != nil {
- planner := plannerFactory.DataSourcePlanner()
- planner.Configure(p.operation, p.definition, p.Walker)
- p.planners = append(p.planners, dataSourcePlannerRef{
- path: p.Path,
- fieldRef: ref,
- planner: planner,
- })
- }
-
- if len(p.planners) != 0 {
- p.planners[len(p.planners)-1].planner.EnterField(ref)
- }
-
- switch parent := p.currentNode[len(p.currentNode)-1].(type) {
- case *Object:
-
- var skipCondition BooleanCondition
- ancestor := p.Ancestors[len(p.Ancestors)-2]
- if ancestor.Kind == ast.NodeKindInlineFragment {
- typeConditionName := p.operation.InlineFragmentTypeConditionName(ancestor.Ref)
- skipCondition = &IfNotEqual{
- Left: &datasource.ObjectVariableArgument{
- PathSelector: datasource.PathSelector{
- Path: "__typename",
- },
- },
- Right: &datasource.StaticVariableArgument{
- Value: typeConditionName,
- },
- }
- }
-
- dataResolvingConfig := p.fieldDataResolvingConfig(ref)
-
- var value Node
- fieldDefinitionType := p.definition.FieldDefinitionType(definition)
- if p.definition.TypeIsList(fieldDefinitionType) {
-
- if !p.operation.FieldHasSelections(ref) {
- value = &Value{
- ValueType: p.jsonValueType(fieldDefinitionType),
- }
- } else {
- value = &Object{}
- }
-
- list := &List{
- DataResolvingConfig: dataResolvingConfig,
- Value: value,
- }
-
- firstNValue, ok := p.FieldDefinitionDirectiveArgumentValueByName(ref, []byte("ListFilterFirstN"), []byte("n"))
- if ok {
- if firstNValue.Kind == ast.ValueKindInteger {
- firstN := p.definition.IntValueAsInt(firstNValue.Ref)
- list.Filter = &ListFilterFirstN{
- FirstN: int(firstN),
- }
- }
- }
-
- parent.Fields = append(parent.Fields, Field{
- Name: p.operation.FieldNameBytes(ref),
- Value: list,
- Skip: skipCondition,
- })
-
- p.currentNode = append(p.currentNode, value)
- return
- }
-
- if !p.operation.FieldHasSelections(ref) {
- value = &Value{
- DataResolvingConfig: dataResolvingConfig,
- ValueType: p.jsonValueType(fieldDefinitionType),
- }
- } else {
- value = &Object{
- DataResolvingConfig: dataResolvingConfig,
- }
- }
-
- parent.Fields = append(parent.Fields, Field{
- Name: p.operation.FieldAliasOrNameBytes(ref),
- Value: value,
- Skip: skipCondition,
- })
-
- p.currentNode = append(p.currentNode, value)
- }
-}
-
-func (p *planningVisitor) EnterArgument(ref int) {
- if len(p.planners) != 0 {
- p.planners[len(p.planners)-1].planner.EnterArgument(ref)
- }
-}
-
-func (p *planningVisitor) LeaveField(ref int) {
-
- var plannedDataSource datasource.DataSource
- var plannedArgs []datasource.Argument
-
- if len(p.planners) != 0 {
-
- p.planners[len(p.planners)-1].planner.LeaveField(ref)
-
- if p.planners[len(p.planners)-1].path.Equals(p.Path) && p.planners[len(p.planners)-1].fieldRef == ref {
- plannedDataSource, plannedArgs = p.planners[len(p.planners)-1].planner.Plan(p.fieldContextVariableArguments(ref))
- p.planners = p.planners[:len(p.planners)-1]
-
- if len(p.currentNode) >= 2 {
- switch parent := p.currentNode[len(p.currentNode)-2].(type) {
- case *Object:
- for i := 0; i < len(parent.Fields); i++ {
- if bytes.Equal(p.operation.FieldAliasOrNameBytes(ref), parent.Fields[i].Name) {
-
- pathName := p.operation.FieldAliasOrNameString(ref)
- parent.Fields[i].HasResolvedData = true
-
- singleFetch := &SingleFetch{
- Source: &DataSourceInvocation{
- Args: plannedArgs,
- DataSource: plannedDataSource,
- },
- BufferName: pathName,
- }
-
- if parent.Fetch == nil {
- parent.Fetch = singleFetch
- } else {
- switch fetch := parent.Fetch.(type) {
- case *ParallelFetch:
- fetch.Fetches = append(fetch.Fetches, singleFetch)
- case *SerialFetch:
- fetch.Fetches = append(fetch.Fetches, singleFetch)
- case *SingleFetch:
- first := *fetch
- parent.Fetch = &ParallelFetch{
- Fetches: []Fetch{
- &first,
- singleFetch,
- },
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- p.currentNode = p.currentNode[:len(p.currentNode)-1]
-}
-
-func (p *planningVisitor) fieldContextVariableArguments(ref int) []datasource.Argument {
- // args
- if p.operation.FieldHasArguments(ref) {
- refs := p.operation.FieldArguments(ref)
- out := make([]datasource.Argument, len(refs))
- for j, i := range refs {
- argName := p.operation.ArgumentNameBytes(i)
- value := p.operation.ArgumentValue(i)
- if value.Kind != ast.ValueKindVariable {
- continue
- }
- variableName := p.operation.VariableValueNameBytes(value.Ref)
- name := append([]byte(".arguments."), argName...)
- arg := &datasource.ContextVariableArgument{
- VariableName: variableName,
- Name: make([]byte, len(name)),
- }
- copy(arg.Name, name)
- out[j] = arg
- }
- return out
- }
- return nil
-}
-
-func (p *planningVisitor) EnterSelectionSet(ref int) {
- if len(p.planners) != 0 {
- p.planners[len(p.planners)-1].planner.EnterSelectionSet(ref)
- }
-}
-
-func (p *planningVisitor) LeaveSelectionSet(ref int) {
- if len(p.planners) != 0 {
- p.planners[len(p.planners)-1].planner.LeaveSelectionSet(ref)
- }
-}
-
-func (p *planningVisitor) jsonValueType(valueType int) JSONValueType {
- typeName := p.definition.ResolveTypeNameBytes(valueType)
- switch {
- case bytes.Equal(typeName, literal.INT):
- return IntegerValueType
- case bytes.Equal(typeName, literal.BOOLEAN):
- return BooleanValueType
- case bytes.Equal(typeName, literal.FLOAT):
- return FloatValueType
- default:
- return StringValueType
- }
-}
-
-func (p *planningVisitor) fieldDataResolvingConfig(ref int) DataResolvingConfig {
- return DataResolvingConfig{
- PathSelector: p.fieldPathSelector(ref),
- Transformation: p.fieldTransformation(ref),
- }
-}
-
-func (p *planningVisitor) fieldPathSelector(ref int) (selector datasource.PathSelector) {
- fieldName := p.operation.FieldNameString(ref)
- typeName := p.definition.NodeResolverTypeNameString(p.EnclosingTypeDefinition, p.Path)
- mapping := p.base.Config.MappingForTypeField(typeName, fieldName)
- if mapping == nil {
- selector.Path = fieldName
- return
- }
- if mapping.Disabled {
- return
- }
- selector.Path = mapping.Path
- return
-}
-
-func (p *planningVisitor) fieldTransformation(ref int) Transformation {
- definition, ok := p.FieldDefinition(ref)
- if !ok {
- return nil
- }
- transformationDirective, ok := p.definition.FieldDefinitionDirectiveByName(definition, literal.TRANSFORMATION)
- if !ok {
- return nil
- }
- modeValue, ok := p.definition.DirectiveArgumentValueByName(transformationDirective, literal.MODE)
- if !ok || modeValue.Kind != ast.ValueKindEnum {
- return nil
- }
- mode := unsafebytes.BytesToString(p.definition.EnumValueNameBytes(modeValue.Ref))
- switch mode {
- case "PIPELINE":
- return p.pipelineTransformation(transformationDirective)
- default:
- return nil
- }
-}
-
-func (p *planningVisitor) pipelineTransformation(directive int) *PipelineTransformation {
- var configReader io.Reader
- configFileStringValue, ok := p.definition.DirectiveArgumentValueByName(directive, literal.PIPELINE_CONFIG_FILE)
- if ok && configFileStringValue.Kind == ast.ValueKindString {
- reader, err := os.Open(p.definition.StringValueContentString(configFileStringValue.Ref))
- if err != nil {
- return nil
- }
- defer reader.Close()
- configReader = reader
- }
- configStringValue, ok := p.definition.DirectiveArgumentValueByName(directive, literal.PIPELINE_CONFIG_STRING)
- if ok && configStringValue.Kind == ast.ValueKindString {
- configReader = bytes.NewReader(p.definition.StringValueContentBytes(configStringValue.Ref))
- }
- if configReader == nil {
- return nil
- }
- var pipeline pipe.Pipeline
- err := pipeline.FromConfig(configReader)
- if err != nil {
- return nil
- }
- return &PipelineTransformation{
- pipeline: pipeline,
- }
-}
-
-func (p *planningVisitor) countOperationDefinitionsInRootNodes() (count int) {
- for i := range p.operation.RootNodes {
- if p.operation.RootNodes[i].Kind == ast.NodeKindOperationDefinition {
- count++
- }
- }
-
- return count
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/transformation.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/transformation.go
deleted file mode 100644
index d90cf7316dd..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/execution/transformation.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package execution
-
-import (
- "bytes"
-
- "github.com/jensneuse/pipeline/pkg/pipe"
-)
-
-type Transformation interface {
- Transform(input []byte) ([]byte, error)
-}
-
-type PipelineTransformation struct {
- pipeline pipe.Pipeline
- buf bytes.Buffer
-}
-
-func (p *PipelineTransformation) Transform(input []byte) ([]byte, error) {
- p.buf.Reset()
- err := p.pipeline.Run(bytes.NewReader(input), &p.buf)
- return p.buf.Bytes(), err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/fastbuffer/fastbuffer.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/fastbuffer/fastbuffer.go
deleted file mode 100644
index 85140f1e1fc..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/fastbuffer/fastbuffer.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package fastbuffer
-
-import (
- "reflect"
- "unsafe"
-)
-
-func New() *FastBuffer {
- return &FastBuffer{
- b: make([]byte, 0, 1024),
- }
-}
-
-type FastBuffer struct {
- b []byte
-}
-
-func (f *FastBuffer) Write(p []byte) (n int, err error) {
- f.b = append(f.b, p...)
- return len(p), nil
-}
-
-func (f *FastBuffer) Reset() {
- f.b = f.b[:0]
-}
-
-func (f *FastBuffer) WriteBytes(b []byte) {
- f.b = append(f.b, b...)
-}
-
-func (f *FastBuffer) WriteString(s string) {
- f.b = append(f.b, s...)
-}
-
-func (f *FastBuffer) Bytes() []byte {
- return f.b
-}
-
-func (f *FastBuffer) Len() int {
- return len(f.b)
-}
-
-func (f *FastBuffer) UnsafeString() string {
- sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&f.b))
- stringHeader := reflect.StringHeader{Data: sliceHeader.Data, Len: sliceHeader.Len}
- return *(*string)(unsafe.Pointer(&stringHeader))
-}
-
-func (f *FastBuffer) String() string {
- return string(f.b)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/federation/schema.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/federation/schema.go
deleted file mode 100644
index 131f67be270..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/federation/schema.go
+++ /dev/null
@@ -1,201 +0,0 @@
-package federation
-
-import (
- "fmt"
- "strings"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astparser"
- "github.com/jensneuse/graphql-go-tools/pkg/astprinter"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-func BuildFederationSchema(baseSchema, serviceSDL string) (string, error) {
- builder := schemaBuilder{}
- return builder.buildFederationSchema(baseSchema, serviceSDL)
-}
-
-// schemaBuilder makes GraphQL schemas compliant with the Apollo Federation Specification
-type schemaBuilder struct {
-}
-
-// BuildFederationSchema takes a baseSchema plus the service sdl and turns it into a fully compliant federation schema
-func (s *schemaBuilder) buildFederationSchema(baseSchema, serviceSDL string) (string, error) {
- unionTypes := s.entityUnionTypes(serviceSDL)
- if len(unionTypes) == 0 {
- return baseSchema, nil
- }
- allUnionTypes := strings.Join(unionTypes, " | ")
- federationExtension := fmt.Sprintf(federationTemplate, allUnionTypes)
-
- baseSchema = s.extendQueryTypeWithFederationFields(baseSchema)
-
- federatedSchema := baseSchema + federationExtension
- return federatedSchema, nil
-}
-
-func (s *schemaBuilder) extendQueryTypeWithFederationFields(schema string) string {
- doc := ast.NewDocument()
- doc.Input.ResetInputString(schema)
- parser := astparser.NewParser()
- report := &operationreport.Report{}
- parser.Parse(doc, report)
- if report.HasErrors() {
- return schema
- }
- queryTypeName := doc.Index.QueryTypeName.String()
- if queryTypeName == "" {
- return schema
- }
- for i := range doc.ObjectTypeDefinitions {
- name := doc.ObjectTypeDefinitionNameString(i)
- if name == queryTypeName {
- s.extendQueryType(doc, i)
- out, err := astprinter.PrintStringIndent(doc, nil, " ")
- if err != nil {
- return schema
- }
- return out
- }
- }
- return schema
-}
-
-func (s *schemaBuilder) extendQueryType(doc *ast.Document, ref int) {
- serviceType := doc.AddNonNullNamedType([]byte("_Service"))
- fieldDefinition := ast.FieldDefinition{
- Name: doc.Input.AppendInputString("_service"),
- Type: serviceType,
- }
- fdRef := doc.AddFieldDefinition(fieldDefinition)
- doc.ObjectTypeDefinitions[ref].HasFieldDefinitions = true
- doc.ObjectTypeDefinitions[ref].FieldsDefinition.Refs = append(doc.ObjectTypeDefinitions[ref].FieldsDefinition.Refs, fdRef)
-
- anyType := doc.AddNonNullNamedType([]byte("_Any"))
- entityType := doc.AddNamedType([]byte("_Entity"))
-
- doc.Types = append(doc.Types, ast.Type{
- TypeKind: ast.TypeKindList,
- OfType: anyType,
- })
-
- listOfAnyType := len(doc.Types) - 1
-
- doc.Types = append(doc.Types, ast.Type{
- TypeKind: ast.TypeKindNonNull,
- OfType: listOfAnyType,
- })
-
- nonNullListOfAnyType := len(doc.Types) - 1
-
- doc.Types = append(doc.Types, ast.Type{
- TypeKind: ast.TypeKindList,
- OfType: entityType,
- })
-
- listOfEntityType := len(doc.Types) - 1
-
- doc.Types = append(doc.Types, ast.Type{
- TypeKind: ast.TypeKindNonNull,
- OfType: listOfEntityType,
- })
-
- nonNullListOfEntityType := len(doc.Types) - 1
-
- doc.InputValueDefinitions = append(doc.InputValueDefinitions, ast.InputValueDefinition{
- Name: doc.Input.AppendInputString("representations"),
- Type: nonNullListOfAnyType,
- })
-
- representationsArg := len(doc.InputValueDefinitions) - 1
-
- entitiesFieldDefinition := ast.FieldDefinition{
- Name: doc.Input.AppendInputString("_entities"),
- HasArgumentsDefinitions: true,
- ArgumentsDefinition: ast.InputValueDefinitionList{
- Refs: []int{representationsArg},
- },
- Type: nonNullListOfEntityType,
- }
-
- entitiesFDRef := doc.AddFieldDefinition(entitiesFieldDefinition)
- doc.ObjectTypeDefinitions[ref].FieldsDefinition.Refs = append(doc.ObjectTypeDefinitions[ref].FieldsDefinition.Refs, entitiesFDRef)
-}
-
-// _entities(representations: [_Any!]!): [_Entity]!
-// _service: _Service!
-
-func (s *schemaBuilder) entityUnionTypes(serviceSDL string) []string {
- doc := ast.NewDocument()
- doc.Input.ResetInputString(serviceSDL)
- parser := astparser.NewParser()
- report := &operationreport.Report{}
- parser.Parse(doc, report)
- if report.HasErrors() {
- return nil
- }
-
- walker := astvisitor.NewWalker(4)
- visitor := &schemaBuilderVisitor{}
- walker.RegisterEnterDocumentVisitor(visitor)
- walker.RegisterEnterObjectTypeDefinitionVisitor(visitor)
- walker.RegisterEnterObjectTypeExtensionVisitor(visitor)
- walker.Walk(doc, nil, report)
- if report.HasErrors() {
- return nil
- }
- return visitor.entityUnionTypes
-}
-
-type schemaBuilderVisitor struct {
- definition *ast.Document
- entityUnionTypes []string
-}
-
-func (s *schemaBuilderVisitor) addEntity(entity string) {
- for i := range s.entityUnionTypes {
- if s.entityUnionTypes[i] == entity {
- return
- }
- }
- s.entityUnionTypes = append(s.entityUnionTypes, entity)
-}
-
-func (s *schemaBuilderVisitor) EnterDocument(operation, definition *ast.Document) {
- s.definition = operation
-}
-
-func (s *schemaBuilderVisitor) EnterObjectTypeExtension(ref int) {
- for _, i := range s.definition.ObjectTypeExtensions[ref].Directives.Refs {
- if s.definition.DirectiveNameString(i) == "key" {
- s.addEntity(s.definition.ObjectTypeExtensionNameString(ref))
- }
- }
-}
-
-func (s *schemaBuilderVisitor) EnterObjectTypeDefinition(ref int) {
- for _, i := range s.definition.ObjectTypeDefinitions[ref].Directives.Refs {
- if s.definition.DirectiveNameString(i) == "key" {
- s.addEntity(s.definition.ObjectTypeDefinitionNameString(ref))
- }
- }
-}
-
-const federationTemplate = `
-
-scalar _Any
-scalar _FieldSet
-
-union _Entity = %s
-
-type _Service {
- sdl: String
-}
-
-directive @external on FIELD_DEFINITION
-directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
-directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
-directive @key(fields: _FieldSet!) on OBJECT | INTERFACE
-directive @extends on OBJECT | INTERFACE
-`
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/complexity.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/complexity.go
deleted file mode 100644
index c658ee49511..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/complexity.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package graphql
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/middleware/operation_complexity"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-var DefaultComplexityCalculator = defaultComplexityCalculator{}
-
-type ComplexityCalculator interface {
- Calculate(operation, definition *ast.Document) (ComplexityResult, error)
-}
-
-type defaultComplexityCalculator struct {
-}
-
-func (d defaultComplexityCalculator) Calculate(operation, definition *ast.Document) (ComplexityResult, error) {
- report := operationreport.Report{}
- globalComplexityResult, fieldsComplexityResult := operation_complexity.CalculateOperationComplexity(operation, definition, &report)
-
- return complexityResult(globalComplexityResult, fieldsComplexityResult, report)
-}
-
-type ComplexityResult struct {
- NodeCount int
- Complexity int
- Depth int
- PerRootField []FieldComplexityResult
- Errors Errors
-}
-
-type FieldComplexityResult struct {
- TypeName string
- FieldName string
- Alias string
- NodeCount int
- Complexity int
- Depth int
-}
-
-func complexityResult(globalComplexityResult operation_complexity.OperationStats, fieldsComplexityResult []operation_complexity.RootFieldStats, report operationreport.Report) (ComplexityResult, error) {
- allFieldComplexityResults := make([]FieldComplexityResult, 0, len(fieldsComplexityResult))
- for _, fieldResult := range fieldsComplexityResult {
- allFieldComplexityResults = append(allFieldComplexityResults, FieldComplexityResult{
- TypeName: fieldResult.TypeName,
- FieldName: fieldResult.FieldName,
- Alias: fieldResult.Alias,
- NodeCount: fieldResult.Stats.NodeCount,
- Complexity: fieldResult.Stats.Complexity,
- Depth: fieldResult.Stats.Depth,
- })
- }
-
- result := ComplexityResult{
- NodeCount: globalComplexityResult.NodeCount,
- Complexity: globalComplexityResult.Complexity,
- Depth: globalComplexityResult.Depth,
- PerRootField: allFieldComplexityResults,
- Errors: nil,
- }
-
- if !report.HasErrors() {
- return result, nil
- }
-
- result.Errors = operationValidationErrorsFromOperationReport(report)
-
- var err error
- if len(report.InternalErrors) > 0 {
- err = report.InternalErrors[0]
- }
-
- return result, err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/errors.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/errors.go
deleted file mode 100644
index 8977cf34957..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/errors.go
+++ /dev/null
@@ -1,152 +0,0 @@
-package graphql
-
-import (
- "encoding/json"
- "fmt"
- "io"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type Errors interface {
- error
- WriteResponse(writer io.Writer) (n int, err error)
- Count() int
- ErrorByIndex(i int) error
-}
-
-type OperationValidationErrors []OperationValidationError
-
-func operationValidationErrorsFromOperationReport(report operationreport.Report) (errors OperationValidationErrors) {
- if len(report.ExternalErrors) == 0 {
- return nil
- }
-
- for _, externalError := range report.ExternalErrors {
- locations := make([]ErrorLocation, 0)
- for _, reportLocation := range externalError.Locations {
- loc := ErrorLocation{
- Line: reportLocation.Line,
- Column: reportLocation.Column,
- }
-
- locations = append(locations, loc)
- }
-
- validationError := OperationValidationError{
- Message: externalError.Message,
- Path: ErrorPath{astPath: externalError.Path},
- Locations: locations,
- }
-
- errors = append(errors, validationError)
- }
-
- return errors
-}
-
-func (o OperationValidationErrors) Error() string {
- if len(o) > 0 { // avoid panic ...
- return o.ErrorByIndex(0).Error()
- }
-
- return "no error" // ... so, this should never be returned
-}
-
-func (o OperationValidationErrors) WriteResponse(writer io.Writer) (n int, err error) {
- response := Response{
- Errors: o,
- }
-
- responseBytes, err := response.Marshal()
- if err != nil {
- return 0, err
- }
-
- return writer.Write(responseBytes)
-}
-
-func (o OperationValidationErrors) Count() int {
- return len(o)
-}
-
-func (o OperationValidationErrors) ErrorByIndex(i int) error {
- if i >= o.Count() {
- return nil
- }
-
- return o[i]
-}
-
-type OperationValidationError struct {
- Message string `json:"message"`
- Locations []ErrorLocation `json:"locations,omitempty"`
- Path ErrorPath `json:"path,omitempty"`
-}
-
-func (o OperationValidationError) Error() string {
- return fmt.Sprintf("%s, locations: %+v, path: %s", o.Message, o.Locations, o.Path.String())
-}
-
-type SchemaValidationErrors []SchemaValidationError
-
-func schemaValidationErrorsFromOperationReport(report operationreport.Report) (errors SchemaValidationErrors) {
- if len(report.ExternalErrors) == 0 {
- return nil
- }
-
- for _, externalError := range report.ExternalErrors {
- validationError := SchemaValidationError{
- Message: externalError.Message,
- }
-
- errors = append(errors, validationError)
- }
-
- return errors
-}
-
-func (s SchemaValidationErrors) Error() string {
- return fmt.Sprintf("schema contains %d error(s)", s.Count())
-}
-
-func (s SchemaValidationErrors) WriteResponse(writer io.Writer) (n int, err error) {
- return writer.Write(nil)
-}
-
-func (s SchemaValidationErrors) Count() int {
- return len(s)
-}
-
-func (s SchemaValidationErrors) ErrorByIndex(i int) error {
- if i >= s.Count() {
- return nil
- }
- return s[i]
-}
-
-type SchemaValidationError struct {
- Message string `json:"message"`
-}
-
-func (s SchemaValidationError) Error() string {
- return s.Message
-}
-
-type ErrorPath struct {
- astPath ast.Path
-}
-
-func (e *ErrorPath) String() string {
- return e.astPath.String()
-}
-
-func (e *ErrorPath) MarshalJSON() ([]byte, error) {
- return json.Marshal(e.astPath)
-}
-
-type ErrorLocation struct {
- Line uint32 `json:"line"`
- Column uint32 `json:"column"`
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/execution_engine.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/execution_engine.go
deleted file mode 100644
index f2b921f3679..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/execution_engine.go
+++ /dev/null
@@ -1,173 +0,0 @@
-package graphql
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "io"
- "io/ioutil"
- "net/http"
- "sync"
-
- "github.com/jensneuse/abstractlogger"
-
- "github.com/jensneuse/graphql-go-tools/pkg/execution"
- "github.com/jensneuse/graphql-go-tools/pkg/execution/datasource"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type DataSourceHttpJsonOptions struct {
- HttpClient *http.Client
- WhitelistedSchemes []string
- Hooks *datasource.Hooks
-}
-
-type DataSourceGraphqlOptions struct {
- HttpClient *http.Client
- WhitelistedSchemes []string
- Hooks *datasource.Hooks
-}
-
-type ExecutionOptions struct {
- ExtraArguments json.RawMessage
-}
-
-type ExecutionEngine struct {
- logger abstractlogger.Logger
- basePlanner *datasource.BasePlanner
- executorPool *sync.Pool
- schema *Schema
-}
-
-func NewExecutionEngine(logger abstractlogger.Logger, schema *Schema, plannerConfig datasource.PlannerConfiguration) (*ExecutionEngine, error) {
- executorPool := sync.Pool{
- New: func() interface{} {
- return execution.NewExecutor(nil)
- },
- }
-
- basePlanner, err := datasource.NewBaseDataSourcePlanner(schema.rawInput, plannerConfig, logger)
- if err != nil {
- return nil, err
- }
-
- return &ExecutionEngine{
- logger: logger,
- basePlanner: basePlanner,
- executorPool: &executorPool,
- schema: schema,
- }, nil
-}
-
-func (e *ExecutionEngine) AddHttpJsonDataSource(name string) error {
- return e.AddHttpJsonDataSourceWithOptions(name, DataSourceHttpJsonOptions{})
-}
-
-func (e *ExecutionEngine) AddHttpJsonDataSourceWithOptions(name string, options DataSourceHttpJsonOptions) error {
- httpJsonFactoryFactory := &datasource.HttpJsonDataSourcePlannerFactoryFactory{}
-
- if options.HttpClient != nil {
- httpJsonFactoryFactory.Client = options.HttpClient
- }
-
- if len(options.WhitelistedSchemes) > 0 {
- httpJsonFactoryFactory.WhitelistedSchemes = options.WhitelistedSchemes
- }
-
- if options.Hooks != nil {
- httpJsonFactoryFactory.Hooks = *options.Hooks
- }
-
- return e.AddDataSource(name, httpJsonFactoryFactory)
-}
-
-func (e *ExecutionEngine) AddGraphqlDataSource(name string) error {
- return e.AddGraphqlDataSourceWithOptions(name, DataSourceGraphqlOptions{})
-}
-
-func (e *ExecutionEngine) AddGraphqlDataSourceWithOptions(name string, options DataSourceGraphqlOptions) error {
- graphqlFactoryFactory := &datasource.GraphQLDataSourcePlannerFactoryFactory{}
-
- if options.HttpClient != nil {
- graphqlFactoryFactory.Client = options.HttpClient
- }
-
- if len(options.WhitelistedSchemes) > 0 {
- graphqlFactoryFactory.WhitelistedSchemes = options.WhitelistedSchemes
- }
-
- if options.Hooks != nil {
- graphqlFactoryFactory.Hooks = *options.Hooks
- }
-
- return e.AddDataSource(name, graphqlFactoryFactory)
-}
-
-func (e *ExecutionEngine) AddDataSource(name string, plannerFactoryFactory datasource.PlannerFactoryFactory) error {
- return e.basePlanner.RegisterDataSourcePlannerFactory(name, plannerFactoryFactory)
-}
-
-func (e *ExecutionEngine) ExecuteWithWriter(ctx context.Context, operation *Request, writer io.Writer, options ExecutionOptions) error {
- var report operationreport.Report
-
- if !operation.IsNormalized() {
- normalizationResult, err := operation.Normalize(e.schema)
- if err != nil {
- return err
- }
-
- if !normalizationResult.Successful {
- return normalizationResult.Errors
- }
- }
-
- planner := execution.NewPlanner(e.basePlanner)
- plan := planner.Plan(&operation.document, e.basePlanner.Definition, operation.OperationName, &report)
- if report.HasErrors() {
- return report
- }
-
- variables, extraArguments := execution.VariablesFromJson(operation.Variables, options.ExtraArguments)
- executionContext := execution.Context{
- Context: ctx,
- Variables: variables,
- ExtraArguments: extraArguments,
- }
-
- poolExecutor := e.executorPool.Get().(*execution.Executor)
- defer e.executorPool.Put(poolExecutor)
- return poolExecutor.Execute(executionContext, plan, writer)
-}
-
-func (e *ExecutionEngine) Execute(ctx context.Context, operation *Request, options ExecutionOptions) (*ExecutionResult, error) {
- var buf bytes.Buffer
- err := e.ExecuteWithWriter(ctx, operation, &buf, options)
- return &ExecutionResult{&buf}, err
-}
-
-func (e *ExecutionEngine) NewExecutionHandler() *execution.Handler {
- return execution.NewHandler(e.basePlanner, nil)
-}
-
-type ExecutionResult struct {
- buf *bytes.Buffer
-}
-
-func (r *ExecutionResult) Buffer() *bytes.Buffer {
- return r.buf
-}
-
-func (r *ExecutionResult) GetAsHTTPResponse() (res *http.Response) {
- if r.buf == nil {
- return
- }
-
- res = &http.Response{}
- res.Body = ioutil.NopCloser(r.buf)
- res.Header = make(http.Header)
- res.StatusCode = 200
-
- res.Header.Set("Content-Type", "application/json")
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/execution_engine_v2.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/execution_engine_v2.go
deleted file mode 100644
index 97cf9223ea0..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/execution_engine_v2.go
+++ /dev/null
@@ -1,223 +0,0 @@
-package graphql
-
-import (
- "bytes"
- "context"
- "errors"
- "io/ioutil"
- "net/http"
- "sync"
-
- "github.com/jensneuse/abstractlogger"
-
- "github.com/jensneuse/graphql-go-tools/pkg/engine/plan"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
- "github.com/jensneuse/graphql-go-tools/pkg/postprocess"
-)
-
-type EngineV2Configuration struct {
- schema *Schema
- plannerConfig plan.Configuration
-}
-
-func NewEngineV2Configuration(schema *Schema) EngineV2Configuration {
- return EngineV2Configuration{
- schema: schema,
- plannerConfig: plan.Configuration{
- DefaultFlushInterval: 0,
- DataSources: []plan.DataSourceConfiguration{},
- Fields: plan.FieldConfigurations{},
- Schema: string(schema.rawInput),
- },
- }
-}
-
-func (e *EngineV2Configuration) AddDataSource(dataSource plan.DataSourceConfiguration) {
- e.plannerConfig.DataSources = append(e.plannerConfig.DataSources, dataSource)
-}
-
-func (e *EngineV2Configuration) SetDataSources(dataSources []plan.DataSourceConfiguration) {
- e.plannerConfig.DataSources = dataSources
-}
-
-func (e *EngineV2Configuration) AddFieldConfiguration(fieldConfig plan.FieldConfiguration) {
- e.plannerConfig.Fields = append(e.plannerConfig.Fields, fieldConfig)
-}
-
-func (e *EngineV2Configuration) SetFieldConfigurations(fieldConfigs plan.FieldConfigurations) {
- e.plannerConfig.Fields = fieldConfigs
-}
-
-type EngineResultWriter struct {
- buf *bytes.Buffer
-}
-
-func NewEngineResultWriter() EngineResultWriter {
- return EngineResultWriter{
- buf: &bytes.Buffer{},
- }
-}
-
-func NewEngineResultWriterFromBuffer(buf *bytes.Buffer) EngineResultWriter {
- return EngineResultWriter{
- buf: buf,
- }
-}
-
-func (e *EngineResultWriter) Write(p []byte) (n int, err error) {
- return e.buf.Write(p)
-}
-
-func (e *EngineResultWriter) Read(p []byte) (n int, err error) {
- return e.buf.Read(p)
-}
-
-func (e *EngineResultWriter) Flush() {
- // Will be implemented with subscriptions
-}
-
-func (e *EngineResultWriter) Len() int {
- return e.buf.Len()
-}
-
-func (e *EngineResultWriter) Bytes() []byte {
- return e.buf.Bytes()
-}
-
-func (e *EngineResultWriter) String() string {
- return e.buf.String()
-}
-
-func (e *EngineResultWriter) Reset() {
- e.buf.Reset()
-}
-
-func (e *EngineResultWriter) AsHTTPResponse(status int, headers http.Header) *http.Response {
- res := &http.Response{}
- res.Body = ioutil.NopCloser(e.buf)
- res.Header = headers
- res.StatusCode = status
- return res
-}
-
-type internalExecutionContext struct {
- resolveContext *resolve.Context
- postProcessor *postprocess.Processor
-}
-
-func newInternalExecutionContext() *internalExecutionContext {
- return &internalExecutionContext{
- resolveContext: resolve.NewContext(context.Background()),
- postProcessor: postprocess.DefaultProcessor(),
- }
-}
-
-func (e *internalExecutionContext) prepare (ctx context.Context, variables []byte, request resolve.Request) {
- e.setContext(ctx)
- e.setVariables(variables)
- e.setRequest(request)
-}
-
-func (e *internalExecutionContext) setRequest(request resolve.Request){
- e.resolveContext.Request = request
-}
-
-func (e *internalExecutionContext) setContext(ctx context.Context) {
- e.resolveContext.Context = ctx
-}
-
-func (e *internalExecutionContext) setVariables(variables []byte) {
- e.resolveContext.Variables = variables
-}
-
-func (e *internalExecutionContext) reset() {
- e.resolveContext.Free()
-}
-
-type ExecutionEngineV2 struct {
- logger abstractlogger.Logger
- config EngineV2Configuration
- planner *plan.Planner
- resolver *resolve.Resolver
- internalExecutionContextPool sync.Pool
-}
-
-type ExecutionOptionsV2 func(ctx *internalExecutionContext)
-
-func WithBeforeFetchHook(hook resolve.BeforeFetchHook) ExecutionOptionsV2 {
- return func(ctx *internalExecutionContext) {
- ctx.resolveContext.SetBeforeFetchHook(hook)
- }
-}
-
-func WithAfterFetchHook(hook resolve.AfterFetchHook) ExecutionOptionsV2 {
- return func(ctx *internalExecutionContext) {
- ctx.resolveContext.SetAfterFetchHook(hook)
- }
-}
-
-func NewExecutionEngineV2(logger abstractlogger.Logger, engineConfig EngineV2Configuration) (*ExecutionEngineV2, error) {
- return &ExecutionEngineV2{
- logger: logger,
- config: engineConfig,
- planner: plan.NewPlanner(engineConfig.plannerConfig),
- resolver: resolve.New(),
- internalExecutionContextPool: sync.Pool{
- New: func() interface{} {
- return newInternalExecutionContext()
- },
- },
- }, nil
-}
-
-func (e *ExecutionEngineV2) Execute(ctx context.Context, operation *Request, writer resolve.FlushWriter, options ...ExecutionOptionsV2) error {
- if !operation.IsNormalized() {
- result, err := operation.Normalize(e.config.schema)
- if err != nil {
- return err
- }
-
- if !result.Successful {
- return result.Errors
- }
- }
-
- execContext := e.getExecutionCtx()
- defer e.putExecutionCtx(execContext)
-
- execContext.prepare(ctx,operation.Variables,operation.request)
-
- for i := range options {
- options[i](execContext)
- }
-
- // Optimization: Hashing the operation and caching the postprocessed plan for
- // this specific operation will improve perfomance significantly.
- var report operationreport.Report
- planResult := e.planner.Plan(&operation.document, &e.config.schema.document, operation.OperationName, &report)
- if report.HasErrors() {
- return errors.New(report.Error())
- }
-
- planResult = execContext.postProcessor.Process(planResult)
-
- var err error
- switch p := planResult.(type) {
- case *plan.SynchronousResponsePlan:
- err = e.resolver.ResolveGraphQLResponse(execContext.resolveContext, p.Response, nil, writer)
- default:
- return errors.New("execution of operation is not possible")
- }
-
- return err
-}
-
-func (e *ExecutionEngineV2) getExecutionCtx() *internalExecutionContext {
- return e.internalExecutionContextPool.Get().(*internalExecutionContext)
-}
-
-func (e *ExecutionEngineV2) putExecutionCtx(ctx *internalExecutionContext){
- ctx.reset()
- e.internalExecutionContextPool.Put(ctx)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/extractor.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/extractor.go
deleted file mode 100644
index ff2ad20d3f0..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/extractor.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package graphql
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type Extractor struct {
- walker *astvisitor.Walker
- visitor *requestVisitor
-}
-
-func NewExtractor() *Extractor {
- walker := astvisitor.NewWalker(48)
- visitor := requestVisitor{
- Walker: &walker,
- }
-
- walker.RegisterEnterFieldVisitor(&visitor)
-
- return &Extractor{
- walker: &walker,
- visitor: &visitor,
- }
-}
-
-func (e *Extractor) ExtractFieldsFromRequest(request *Request, schema *Schema, report *operationreport.Report, data RequestTypes) {
- if !request.IsNormalized() {
- result, err := request.Normalize(schema)
- if err != nil {
- report.AddInternalError(err)
- }
-
- if !result.Successful {
- report.AddInternalError(result.Errors)
- }
- }
-
- e.visitor.data = data
- e.visitor.operation = &request.document
- e.visitor.definition = &schema.document
- e.walker.Walk(&request.document, &schema.document, report)
-}
-
-type requestVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
- data RequestTypes
-}
-
-func (p *requestVisitor) EnterField(ref int) {
- fieldName := p.operation.FieldNameString(ref)
- parentTypeName := p.definition.NodeNameString(p.EnclosingTypeDefinition)
-
- t, ok := p.data[parentTypeName]
- if !ok {
- t = make(RequestFields)
- }
-
- if _, ok := t[fieldName]; !ok {
- t[fieldName] = struct{}{}
- }
-
- p.data[parentTypeName] = t
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/normalization.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/normalization.go
deleted file mode 100644
index 4b4edcb8aa3..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/normalization.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package graphql
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/astnormalization"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type NormalizationResult struct {
- Successful bool
- Errors Errors
-}
-
-func (r *Request) Normalize(schema *Schema) (result NormalizationResult, err error) {
- if schema == nil {
- return NormalizationResult{Successful: false, Errors: nil}, ErrNilSchema
- }
-
- report := r.parseQueryOnce()
- if report.HasErrors() {
- return normalizationResultFromReport(report)
- }
-
- r.document.Input.Variables = r.Variables
-
- normalizer := astnormalization.NewNormalizer(true, true)
- normalizer.NormalizeNamedOperation(&r.document, &schema.document, []byte(r.OperationName), &report)
- if report.HasErrors() {
- return normalizationResultFromReport(report)
- }
-
- r.isNormalized = true
-
- r.Variables = r.document.Input.Variables
-
- return NormalizationResult{Successful: true, Errors: nil}, nil
-}
-
-func normalizationResultFromReport(report operationreport.Report) (NormalizationResult, error) {
- result := NormalizationResult{
- Successful: false,
- Errors: nil,
- }
-
- if !report.HasErrors() {
- result.Successful = true
- return result, nil
- }
-
- result.Errors = operationValidationErrorsFromOperationReport(report)
-
- var err error
- if len(report.InternalErrors) > 0 {
- err = report.InternalErrors[0]
- }
-
- return result, err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/request.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/request.go
deleted file mode 100644
index 9646393228a..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/request.go
+++ /dev/null
@@ -1,169 +0,0 @@
-package graphql
-
-import (
- "encoding/json"
- "errors"
- "io"
- "io/ioutil"
- "net/http"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astparser"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/middleware/operation_complexity"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-const (
- defaultInrospectionQueryName = "IntrospectionQuery"
- schemaFieldName = "__schema"
-)
-
-type OperationType ast.OperationType
-
-const (
- OperationTypeUnknown OperationType = OperationType(ast.OperationTypeUnknown)
- OperationTypeQuery OperationType = OperationType(ast.OperationTypeQuery)
- OperationTypeMutation OperationType = OperationType(ast.OperationTypeMutation)
- OperationTypeSubscription OperationType = OperationType(ast.OperationTypeSubscription)
-)
-
-var (
- ErrEmptyRequest = errors.New("the provided request is empty")
- ErrNilSchema = errors.New("the provided schema is nil")
-)
-
-type Request struct {
- OperationName string `json:"operationName"`
- Variables json.RawMessage `json:"variables"`
- Query string `json:"query"`
-
- document ast.Document
- isParsed bool
- isNormalized bool
- request resolve.Request
-}
-
-func UnmarshalRequest(reader io.Reader, request *Request) error {
- requestBytes, err := ioutil.ReadAll(reader)
- if err != nil {
- return err
- }
-
- if len(requestBytes) == 0 {
- return ErrEmptyRequest
- }
-
- return json.Unmarshal(requestBytes, &request)
-}
-
-func UnmarshalHttpRequest(r *http.Request, request *Request) error {
- request.request.Header = r.Header
- return UnmarshalRequest(r.Body, request)
-}
-
-func (r *Request) SetHeader(header http.Header){
- r.request.Header = header
-}
-
-func (r *Request) CalculateComplexity(complexityCalculator ComplexityCalculator, schema *Schema) (ComplexityResult, error) {
- if schema == nil {
- return ComplexityResult{}, ErrNilSchema
- }
-
- report := r.parseQueryOnce()
- if report.HasErrors() {
- return complexityResult(
- operation_complexity.OperationStats{},
- []operation_complexity.RootFieldStats{},
- report,
- )
- }
-
- return complexityCalculator.Calculate(&r.document, &schema.document)
-}
-
-func (r Request) Print(writer io.Writer) (n int, err error) {
- report := r.parseQueryOnce()
- if report.HasErrors() {
- return 0, report
- }
-
- return writer.Write(r.document.Input.RawBytes)
-}
-
-func (r *Request) IsNormalized() bool {
- return r.isNormalized
-}
-
-func (r *Request) parseQueryOnce() (report operationreport.Report) {
- if r.isParsed {
- return report
- }
-
- r.isParsed = true
- r.document, report = astparser.ParseGraphqlDocumentString(r.Query)
- return report
-}
-
-func (r *Request) IsIntrospectionQuery() (result bool, err error) {
- report := r.parseQueryOnce()
- if report.HasErrors() {
- return false, report
- }
-
- if r.OperationName == defaultInrospectionQueryName {
- return true, nil
- }
-
- if len(r.document.RootNodes) == 0 {
- return
- }
-
- rootNode := r.document.RootNodes[0]
- if rootNode.Kind != ast.NodeKindOperationDefinition {
- return
- }
-
- operationDef := r.document.OperationDefinitions[rootNode.Ref]
- if operationDef.OperationType != ast.OperationTypeQuery {
- return
- }
- if !operationDef.HasSelections {
- return
- }
-
- selectionSet := r.document.SelectionSets[operationDef.SelectionSet]
- if len(selectionSet.SelectionRefs) == 0 {
- return
- }
-
- selection := r.document.Selections[selectionSet.SelectionRefs[0]]
- if selection.Kind != ast.SelectionKindField {
- return
- }
-
- return r.document.FieldNameString(selection.Ref) == schemaFieldName, nil
-}
-
-func (r *Request) OperationType() (OperationType, error) {
- report := r.parseQueryOnce()
- if report.HasErrors() {
- return OperationTypeUnknown, report
- }
-
- for _, rootNode := range r.document.RootNodes {
- if rootNode.Kind != ast.NodeKindOperationDefinition {
- continue
- }
-
- if r.document.OperationDefinitionNameString(rootNode.Ref) != r.OperationName {
- continue
- }
-
- opType := r.document.OperationDefinitions[rootNode.Ref].OperationType
- return OperationType(opType), nil
- }
-
- return OperationTypeUnknown, nil
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/request_fields_validator.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/request_fields_validator.go
deleted file mode 100644
index db0dd2883fb..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/request_fields_validator.go
+++ /dev/null
@@ -1,132 +0,0 @@
-package graphql
-
-import (
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type RequestFieldsValidator interface {
- Validate(request *Request, schema *Schema, restrictions []Type) (RequestFieldsValidationResult, error)
-}
-
-type FieldRestrictionValidator interface {
- ValidateByFieldList(request *Request, schema *Schema, restrictionList FieldRestrictionList) (RequestFieldsValidationResult, error)
-}
-
-type FieldRestrictionListKind int
-
-const (
- AllowList FieldRestrictionListKind = iota
- BlockList
-)
-
-type FieldRestrictionList struct {
- Kind FieldRestrictionListKind
- Types []Type
-}
-
-type DefaultFieldsValidator struct {
-}
-
-// Validate validates a request by checking if `restrictions` contains blocked fields.
-//
-// Deprecated: This function can only handle blocked fields. Use `ValidateByFieldList` if you
-// want to check for blocked or allowed fields instead.
-func (d DefaultFieldsValidator) Validate(request *Request, schema *Schema, restrictions []Type) (RequestFieldsValidationResult, error) {
- restrictionList := FieldRestrictionList{
- Kind: BlockList,
- Types: restrictions,
- }
-
- return d.ValidateByFieldList(request, schema, restrictionList)
-}
-
-// ValidateByFieldList will validate a request by using a list of allowed or blocked fields.
-func (d DefaultFieldsValidator) ValidateByFieldList(request *Request, schema *Schema, restrictionList FieldRestrictionList) (RequestFieldsValidationResult, error) {
- report := operationreport.Report{}
- if len(restrictionList.Types) == 0 {
- return fieldsValidationResult(report, true, "", "")
- }
-
- requestedTypes := make(RequestTypes)
- NewExtractor().ExtractFieldsFromRequest(request, schema, &report, requestedTypes)
-
- if restrictionList.Kind == BlockList {
- return d.checkForBlockedFields(restrictionList, requestedTypes, report)
- }
-
- return d.checkForAllowedFields(restrictionList, requestedTypes, report)
-}
-
-func (d DefaultFieldsValidator) checkForBlockedFields(restrictionList FieldRestrictionList, requestTypes RequestTypes, report operationreport.Report) (RequestFieldsValidationResult, error) {
- for _, typeFromList := range restrictionList.Types {
- requestedFields, hasRestrictedType := requestTypes[typeFromList.Name]
- if !hasRestrictedType {
- continue
- }
- for _, field := range typeFromList.Fields {
- _, requestHasField := requestedFields[field]
- if requestHasField {
- return fieldsValidationResult(report, false, typeFromList.Name, field)
- }
- }
- }
-
- return fieldsValidationResult(report, true, "", "")
-}
-
-func (d DefaultFieldsValidator) checkForAllowedFields(restrictionList FieldRestrictionList, requestTypes RequestTypes, report operationreport.Report) (RequestFieldsValidationResult, error) {
- allowedFieldsLookupMap := make(map[string]map[string]bool)
- for _, allowedType := range restrictionList.Types {
- allowedFieldsLookupMap[allowedType.Name] = make(map[string]bool)
- for _, allowedField := range allowedType.Fields {
- allowedFieldsLookupMap[allowedType.Name][allowedField] = true
- }
- }
-
- for requestType, requestFields := range requestTypes {
- for requestField := range requestFields {
- isAllowedField := allowedFieldsLookupMap[requestType][requestField]
- if !isAllowedField {
- return fieldsValidationResult(report, false, requestType, requestField)
- }
- }
- }
-
- return fieldsValidationResult(report, true, "", "")
-}
-
-type RequestFieldsValidationResult struct {
- Valid bool
- Errors Errors
-}
-
-func fieldsValidationResult(report operationreport.Report, valid bool, typeName, fieldName string) (RequestFieldsValidationResult, error) {
- result := RequestFieldsValidationResult{
- Valid: valid,
- Errors: nil,
- }
-
- var errors OperationValidationErrors
- if !result.Valid {
- errors = append(errors, OperationValidationError{
- Message: fmt.Sprintf("field: %s is restricted on type: %s", fieldName, typeName),
- })
- }
- result.Errors = errors
-
- if !report.HasErrors() {
- return result, nil
- }
-
- errors = append(errors, operationValidationErrorsFromOperationReport(report)...)
- result.Errors = errors
-
- var err error
- if len(report.InternalErrors) > 0 {
- err = report.InternalErrors[0]
- }
-
- return result, err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/response.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/response.go
deleted file mode 100644
index 1360341cf47..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/response.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package graphql
-
-import (
- "encoding/json"
-)
-
-type Response struct {
- Errors Errors `json:"errors,omitempty"`
- // TODO: Data
- // TODO: Extensions
-}
-
-func (r Response) Marshal() ([]byte, error) {
- return json.Marshal(r)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/schema.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/schema.go
deleted file mode 100644
index 61d54971cc9..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/schema.go
+++ /dev/null
@@ -1,143 +0,0 @@
-package graphql
-
-import (
- "bytes"
- "encoding/json"
- "io"
- "io/ioutil"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astparser"
- "github.com/jensneuse/graphql-go-tools/pkg/asttransform"
- "github.com/jensneuse/graphql-go-tools/pkg/astvalidation"
- "github.com/jensneuse/graphql-go-tools/pkg/introspection"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type Schema struct {
- rawInput []byte
- document ast.Document
-}
-
-func NewSchemaFromReader(reader io.Reader) (*Schema, error) {
- schemaContent, err := ioutil.ReadAll(reader)
- if err != nil {
- return nil, err
- }
-
- return createSchema(schemaContent)
-}
-
-func NewSchemaFromString(schema string) (*Schema, error) {
- schemaContent := []byte(schema)
-
- return createSchema(schemaContent)
-}
-
-func ValidateSchemaString(schema string) (result ValidationResult, err error) {
- parsedSchema, err := NewSchemaFromString(schema)
- if err != nil {
- return ValidationResult{
- Valid: false,
- Errors: SchemaValidationErrors{
- SchemaValidationError{Message: err.Error()},
- },
- }, nil
- }
-
- return parsedSchema.Validate()
-}
-
-func (s *Schema) Document() []byte {
- return s.rawInput
-}
-
-func (s *Schema) HasQueryType() bool {
- return len(s.document.Index.QueryTypeName) > 0
-}
-
-func (s *Schema) QueryTypeName() string {
- if !s.HasQueryType() {
- return ""
- }
-
- return string(s.document.Index.QueryTypeName)
-}
-
-func (s *Schema) HasMutationType() bool {
- return len(s.document.Index.MutationTypeName) > 0
-}
-
-func (s *Schema) MutationTypeName() string {
- if !s.HasMutationType() {
- return ""
- }
-
- return string(s.document.Index.MutationTypeName)
-}
-
-func (s *Schema) HasSubscriptionType() bool {
- return len(s.document.Index.SubscriptionTypeName) > 0
-}
-
-func (s *Schema) SubscriptionTypeName() string {
- if !s.HasSubscriptionType() {
- return ""
- }
-
- return string(s.document.Index.SubscriptionTypeName)
-}
-
-func (s *Schema) Validate() (result ValidationResult, err error) {
- var report operationreport.Report
- var isValid bool
-
- validator := astvalidation.DefaultDefinitionValidator()
- validationState := validator.Validate(&s.document, &report)
- if validationState == astvalidation.Valid {
- isValid = true
- }
-
- return ValidationResult{
- Valid: isValid,
- Errors: schemaValidationErrorsFromOperationReport(report),
- }, nil
-}
-
-func (s *Schema) IntrospectionResponse(out io.Writer) error {
- var (
- introspectionData = struct {
- Data introspection.Data `json:"data"`
- }{}
- report operationreport.Report
- )
- gen := introspection.NewGenerator()
- gen.Generate(&s.document, &report, &introspectionData.Data)
- if report.HasErrors() {
- return report
- }
- return json.NewEncoder(out).Encode(introspectionData)
-}
-
-func createSchema(schemaContent []byte) (*Schema, error) {
- document, report := astparser.ParseGraphqlDocumentBytes(schemaContent)
- if report.HasErrors() {
- return nil, report
- }
-
- err := asttransform.MergeDefinitionWithBaseSchema(&document)
- if err != nil {
- return nil, err
- }
-
- return &Schema{
- rawInput: schemaContent,
- document: document,
- }, nil
-}
-
-func SchemaIntrospection(schema *Schema) (*ExecutionResult, error) {
- var buf bytes.Buffer
- err := schema.IntrospectionResponse(&buf)
- return &ExecutionResult{&buf}, err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/types.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/types.go
deleted file mode 100644
index f9844bf95e4..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/types.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package graphql
-
-type (
- Type struct {
- Name string `json:"name"`
- Fields []string `json:"fields"`
- }
-
- RequestFields map[string]struct{}
- RequestTypes map[string]RequestFields
-)
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/validation.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/validation.go
deleted file mode 100644
index e98c1f2cdcd..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/graphql/validation.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package graphql
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/astvalidation"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type ValidationResult struct {
- Valid bool
- Errors Errors
-}
-
-func (r *Request) ValidateForSchema(schema *Schema) (result ValidationResult, err error) {
- if schema == nil {
- return ValidationResult{Valid: false, Errors: nil}, ErrNilSchema
- }
-
- report := r.parseQueryOnce()
- if report.HasErrors() {
- return operationValidationResultFromReport(report)
- }
-
- validator := astvalidation.DefaultOperationValidator()
- validator.Validate(&r.document, &schema.document, &report)
- return operationValidationResultFromReport(report)
-}
-
-// ValidateRestrictedFields validates a request by checking if `restrictedFields` contains blocked fields.
-//
-// Deprecated: This function can only handle blocked fields. Use `ValidateFieldRestrictions` if you
-// want to check for blocked or allowed fields instead.
-func (r *Request) ValidateRestrictedFields(schema *Schema, restrictedFields []Type) (RequestFieldsValidationResult, error) {
- if schema == nil {
- return RequestFieldsValidationResult{Valid: false}, ErrNilSchema
- }
-
- report := r.parseQueryOnce()
- if report.HasErrors() {
- return fieldsValidationResult(report, false, "", "")
- }
-
- var fieldsValidator RequestFieldsValidator = DefaultFieldsValidator{}
- return fieldsValidator.Validate(r, schema, restrictedFields)
-}
-
-// ValidateFieldRestrictions will validate a request by using a list of allowed or blocked fields.
-func (r *Request) ValidateFieldRestrictions(schema *Schema, restrictedFieldsList FieldRestrictionList, validator FieldRestrictionValidator) (RequestFieldsValidationResult, error) {
- if schema == nil {
- return RequestFieldsValidationResult{Valid: false}, ErrNilSchema
- }
-
- report := r.parseQueryOnce()
- if report.HasErrors() {
- return fieldsValidationResult(report, false, "", "")
- }
-
- return validator.ValidateByFieldList(r, schema, restrictedFieldsList)
-}
-
-func operationValidationResultFromReport(report operationreport.Report) (ValidationResult, error) {
- result := ValidationResult{
- Valid: false,
- Errors: nil,
- }
-
- if !report.HasErrors() {
- result.Valid = true
- return result, nil
- }
-
- result.Errors = operationValidationErrorsFromOperationReport(report)
-
- var err error
- if len(report.InternalErrors) > 0 {
- err = report.InternalErrors[0]
- }
-
- return result, err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/handler.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/handler.go
deleted file mode 100644
index 12195d6597d..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/handler.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package http
-
-import (
- "encoding/json"
- "io"
- "net/http"
-
- "github.com/gobwas/ws"
- log "github.com/jensneuse/abstractlogger"
-
- "github.com/jensneuse/graphql-go-tools/pkg/execution"
-)
-
-const (
- httpHeaderUpgrade string = "Upgrade"
-)
-
-func NewGraphqlHTTPHandlerFunc(executionHandler *execution.Handler, logger log.Logger, upgrader *ws.HTTPUpgrader) http.Handler {
- return &GraphQLHTTPRequestHandler{
- log: logger,
- executionHandler: executionHandler,
- wsUpgrader: upgrader,
- }
-}
-
-type GraphQLHTTPRequestHandler struct {
- log log.Logger
- executionHandler *execution.Handler
- wsUpgrader *ws.HTTPUpgrader
-}
-
-func (g *GraphQLHTTPRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- isUpgrade := g.isWebsocketUpgrade(r)
- if isUpgrade {
- err := g.upgradeWithNewGoroutine(w, r)
- if err != nil {
- g.log.Error("GraphQLHTTPRequestHandler.ServeHTTP",
- log.Error(err),
- )
- w.WriteHeader(http.StatusBadRequest)
- }
- return
- }
- g.handleHTTP(w, r)
-}
-
-func (g *GraphQLHTTPRequestHandler) upgradeWithNewGoroutine(w http.ResponseWriter, r *http.Request) error {
- conn, _, _, err := g.wsUpgrader.Upgrade(r, w)
- if err != nil {
- return err
- }
- g.handleWebsocket(conn)
- return nil
-}
-
-func (g *GraphQLHTTPRequestHandler) isWebsocketUpgrade(r *http.Request) bool {
- for _, header := range r.Header[httpHeaderUpgrade] {
- if header == "websocket" {
- return true
- }
- }
- return false
-}
-
-func (g *GraphQLHTTPRequestHandler) extraVariables(r *http.Request, out io.Writer) error {
- headers := map[string]string{}
- for key := range r.Header {
- headers[key] = r.Header.Get(key)
- }
-
- cookies := map[string]string{}
- for _, cookie := range r.Cookies() {
- cookies[cookie.Name] = cookie.Value
- }
-
- extra := map[string]interface{}{
- "request": map[string]interface{}{
- "uri": r.RequestURI,
- "method": r.Method,
- "host": r.Host,
- "headers": headers,
- "cookies": cookies,
- },
- }
-
- return json.NewEncoder(out).Encode(extra)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/http.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/http.go
deleted file mode 100644
index 2f2a8928882..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/http.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// Package http handles GraphQL HTTP Requests including WebSocket Upgrades.
-package http
-
-import (
- "bytes"
- "io/ioutil"
- "net/http"
-
- log "github.com/jensneuse/abstractlogger"
-)
-
-const (
- httpHeaderContentType string = "Content-Type"
-
- httpContentTypeApplicationJson string = "application/json"
-)
-
-func (g *GraphQLHTTPRequestHandler) handleHTTP(w http.ResponseWriter, r *http.Request) {
- data, err := ioutil.ReadAll(r.Body)
- if err != nil {
- g.log.Error("GraphQLHTTPRequestHandler.handleHTTP",
- log.Error(err),
- )
- w.WriteHeader(http.StatusBadRequest)
- return
- }
-
- extra := &bytes.Buffer{}
- err = g.extraVariables(r, extra)
- if err != nil {
- g.log.Error("executionHandler.Handle.json.Marshal(extra)",
- log.Error(err),
- )
- w.WriteHeader(http.StatusBadRequest)
- return
- }
-
- executor, rootNode, ctx, err := g.executionHandler.Handle(data, extra.Bytes())
- if err != nil {
- g.log.Error("executionHandler.Handle",
- log.Error(err),
- )
- w.WriteHeader(http.StatusBadRequest)
- return
- }
- ctx.Context = r.Context()
- buf := bytes.NewBuffer(make([]byte, 0, 4096))
- err = executor.Execute(ctx, rootNode, buf)
- if err != nil {
- g.log.Error("executor.Execute",
- log.Error(err),
- )
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- w.Header().Add(httpHeaderContentType, "application/json")
- w.WriteHeader(http.StatusOK)
- _, _ = buf.WriteTo(w)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/ws.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/ws.go
deleted file mode 100644
index 53e4820f444..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/ws.go
+++ /dev/null
@@ -1,160 +0,0 @@
-package http
-
-import (
- "context"
- "encoding/json"
- "net"
-
- "github.com/gobwas/ws"
- "github.com/gobwas/ws/wsutil"
- "github.com/jensneuse/abstractlogger"
-
- "github.com/jensneuse/graphql-go-tools/pkg/subscription"
-)
-
-// WebsocketSubscriptionClient is an actual implementation of the subscritpion client interface.
-type WebsocketSubscriptionClient struct {
- logger abstractlogger.Logger
- // clientConn holds the actual connection to the client.
- clientConn net.Conn
- // isClosedConnection indicates if the websocket connection is closed.
- isClosedConnection bool
-}
-
-// NewWebsocketSubscriptionClient will create a new websocket subscription client.
-func NewWebsocketSubscriptionClient(logger abstractlogger.Logger, clientConn net.Conn) *WebsocketSubscriptionClient {
- return &WebsocketSubscriptionClient{
- logger: logger,
- clientConn: clientConn,
- }
-}
-
-// ReadFromClient will read a subscription message from the websocket client.
-func (w *WebsocketSubscriptionClient) ReadFromClient() (message *subscription.Message, err error) {
- var data []byte
- var opCode ws.OpCode
-
- data, opCode, err = wsutil.ReadClientData(w.clientConn)
- if err != nil {
- if w.isClosedConnectionError(err) {
- return message, nil
- }
-
- w.logger.Error("http.WebsocketSubscriptionClient.ReadFromClient()",
- abstractlogger.Error(err),
- abstractlogger.ByteString("data", data),
- abstractlogger.Any("opCode", opCode),
- )
-
- w.isClosedConnectionError(err)
-
- return nil, err
- }
-
- err = json.Unmarshal(data, &message)
- if err != nil {
- w.logger.Error("http.WebsocketSubscriptionClient.ReadFromClient()",
- abstractlogger.Error(err),
- abstractlogger.ByteString("data", data),
- abstractlogger.Any("opCode", opCode),
- )
-
- return nil, err
- }
-
- return message, nil
-}
-
-// WriteToClient will write a subscription message to the websocket client.
-func (w *WebsocketSubscriptionClient) WriteToClient(message subscription.Message) error {
- if w.isClosedConnection {
- return nil
- }
-
- messageBytes, err := json.Marshal(message)
- if err != nil {
- w.logger.Error("http.WebsocketSubscriptionClient.WriteToClient()",
- abstractlogger.Error(err),
- abstractlogger.Any("message", message),
- )
-
- return err
- }
-
- err = wsutil.WriteServerMessage(w.clientConn, ws.OpText, messageBytes)
- if err != nil {
- w.logger.Error("http.WebsocketSubscriptionClient.WriteToClient()",
- abstractlogger.Error(err),
- abstractlogger.ByteString("messageBytes", messageBytes),
- )
-
- return err
- }
-
- return nil
-}
-
-// IsConnected will indicate if the websocket conenction is still established.
-func (w *WebsocketSubscriptionClient) IsConnected() bool {
- return !w.isClosedConnection
-}
-
-// Disconnect will close the websocket connection.
-func (w *WebsocketSubscriptionClient) Disconnect() error {
- w.logger.Debug("http.GraphQLHTTPRequestHandler.Disconnect()",
- abstractlogger.String("message", "disconnecting client"),
- )
- w.isClosedConnection = true
- return w.clientConn.Close()
-}
-
-// isClosedConnectionError will indicate if the given error is a conenction closed error.
-func (w *WebsocketSubscriptionClient) isClosedConnectionError(err error) bool {
- if _, ok := err.(wsutil.ClosedError); ok {
- w.isClosedConnection = true
- }
-
- return w.isClosedConnection
-}
-
-func HandleWebsocket(done chan bool, errChan chan error, conn net.Conn, executorPool subscription.ExecutorPool, logger abstractlogger.Logger) {
- defer func() {
- if err := conn.Close(); err != nil {
- logger.Error("http.HandleWebsocket()",
- abstractlogger.String("message", "could not close connection to client"),
- abstractlogger.Error(err),
- )
- }
- }()
-
- websocketClient := NewWebsocketSubscriptionClient(logger, conn)
- subscriptionHandler, err := subscription.NewHandler(logger, websocketClient, executorPool)
- if err != nil {
- logger.Error("http.HandleWebsocket()",
- abstractlogger.String("message", "could not create subscriptionHandler"),
- abstractlogger.Error(err),
- )
-
- errChan <- err
- return
- }
-
- close(done)
- subscriptionHandler.Handle(context.Background()) // Blocking
-}
-
-// handleWebsocket will handle the websocket connection.
-func (g *GraphQLHTTPRequestHandler) handleWebsocket(conn net.Conn) {
- done := make(chan bool)
- errChan := make(chan error)
-
- executorPool := subscription.NewExecutorV1Pool(g.executionHandler)
- go HandleWebsocket(done, errChan, conn, executorPool, g.log)
- select {
- case err := <-errChan:
- g.log.Error("http.GraphQLHTTPRequestHandler.handleWebsocket()",
- abstractlogger.Error(err),
- )
- case <-done:
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/ws_connection_init.json b/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/ws_connection_init.json
deleted file mode 100644
index b2ddf343c71..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/ws_connection_init.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "type": "connection_init",
- "payload": {}
-}
\ No newline at end of file
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/ws_start.json b/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/ws_start.json
deleted file mode 100644
index de8fc245618..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/http/ws_start.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "id": "1",
- "type": "start",
- "payload": {
- "variables": {},
- "extensions": {},
- "operationName": "stream",
- "query": "subscription stream {n stream {n datetimen timezonen abbreviationn }n}n"
- }
-}
\ No newline at end of file
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/converter.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/converter.go
deleted file mode 100644
index 111d7c2f87b..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/converter.go
+++ /dev/null
@@ -1,283 +0,0 @@
-package introspection
-
-import (
- "encoding/json"
- "fmt"
- "io"
- "strings"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astimport"
- "github.com/jensneuse/graphql-go-tools/pkg/astparser"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type JsonConverter struct {
- schema *Schema
- doc *ast.Document
- parser *astparser.Parser
-}
-
-func (j *JsonConverter) GraphQLDocument(introspectionJSON io.Reader) (*ast.Document, error) {
- var data Data
- if err := json.NewDecoder(introspectionJSON).Decode(&data); err != nil {
- return nil, fmt.Errorf("failed to parse inrospection json: %v", err)
- }
-
- j.schema = &data.Schema
- j.doc = ast.NewDocument()
- j.parser = astparser.NewParser()
-
- if err := j.importSchema(); err != nil {
- return nil, fmt.Errorf("failed to convert graphql schema: %v", err)
- }
-
- return j.doc, nil
-}
-
-func (j *JsonConverter) importSchema() error {
- j.doc.ImportSchemaDefinition(j.schema.TypeNames())
-
- for i := 0; i < len(j.schema.Types); i++ {
- if err := j.importFullType(j.schema.Types[i]); err != nil {
- return err
- }
- }
-
- for i := 0; i < len(j.schema.Directives); i++ {
- if err := j.importDirective(j.schema.Directives[i]); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (j *JsonConverter) importFullType(fullType FullType) (err error) {
- switch fullType.Kind {
- case SCALAR:
- j.doc.ImportScalarTypeDefinition(fullType.Name, fullType.Description)
- case OBJECT:
- err = j.importObject(fullType)
- case ENUM:
- j.importEnum(fullType)
- case INTERFACE:
- err = j.importInterface(fullType)
- case UNION:
- err = j.importUnion(fullType)
- case INPUTOBJECT:
- err = j.importInputObject(fullType)
- }
- return
-}
-
-func (j *JsonConverter) importObject(fullType FullType) error {
- fieldRefs, err := j.importFields(fullType.Fields)
- if err != nil {
- return err
- }
-
- iRefs := make([]int, len(fullType.Interfaces))
- for i := 0; i < len(iRefs); i++ {
- iRefs[i] = j.importType(fullType.Interfaces[i])
- }
-
- j.doc.ImportObjectTypeDefinition(
- fullType.Name,
- fullType.Description,
- fieldRefs,
- iRefs)
-
- return nil
-}
-
-func (j *JsonConverter) importInterface(fullType FullType) error {
- fieldRefs, err := j.importFields(fullType.Fields)
- if err != nil {
- return err
- }
-
- j.doc.ImportInterfaceTypeDefinition(
- fullType.Name,
- fullType.Description,
- fieldRefs)
-
- return nil
-}
-
-func (j *JsonConverter) importDirective(directive Directive) error {
- argRefs, err := j.importInputFields(directive.Args)
- if err != nil {
- return err
- }
-
- j.doc.ImportDirectiveDefinition(
- directive.Name,
- directive.Description,
- argRefs,
- directive.Locations)
-
- return nil
-}
-
-func (j *JsonConverter) importInputObject(fullType FullType) error {
- argRefs, err := j.importInputFields(fullType.InputFields)
- if err != nil {
- return err
- }
-
- j.doc.ImportInputObjectTypeDefinition(
- fullType.Name,
- fullType.Description,
- argRefs)
-
- return nil
-}
-
-func (j *JsonConverter) importEnum(fullType FullType) {
- valueRefs := make([]int, len(fullType.EnumValues))
- for i := 0; i < len(valueRefs); i++ {
- var directiveRefs []int
- if fullType.EnumValues[i].IsDeprecated {
- directiveRefs = append(directiveRefs, j.importDeprecatedDirective(fullType.EnumValues[i].DeprecationReason))
- }
-
- valueRefs[i] = j.doc.ImportEnumValueDefinition(
- fullType.EnumValues[i].Name,
- fullType.EnumValues[i].Description,
- directiveRefs,
- )
- }
-
- j.doc.ImportEnumTypeDefinition(
- fullType.Name,
- fullType.Description,
- valueRefs)
-}
-
-func (j *JsonConverter) importUnion(fullType FullType) error {
- typeRefs := make([]int, len(fullType.PossibleTypes))
- for i := 0; i < len(typeRefs); i++ {
- typeRefs[i] = j.importType(fullType.PossibleTypes[i])
- }
-
- j.doc.ImportUnionTypeDefinition(
- fullType.Name,
- fullType.Description,
- typeRefs)
-
- return nil
-}
-
-func (j *JsonConverter) importFields(fields []Field) (refs []int, err error) {
- refs = make([]int, len(fields))
- for i := 0; i < len(refs); i++ {
- fieldRef, err := j.importField(fields[i])
- if err != nil {
- return nil, err
- }
- refs[i] = fieldRef
- }
-
- return
-}
-
-func (j *JsonConverter) importField(field Field) (ref int, err error) {
- typeRef := j.importType(field.Type)
-
- argRefs, err := j.importInputFields(field.Args)
- if err != nil {
- return -1, err
- }
-
- var directiveRefs []int
- if field.IsDeprecated {
- directiveRefs = append(directiveRefs, j.importDeprecatedDirective(field.DeprecationReason))
- }
-
- return j.doc.ImportFieldDefinition(
- field.Name, field.Description, typeRef, argRefs, directiveRefs), nil
-}
-
-func (j *JsonConverter) importInputFields(fields []InputValue) (refs []int, err error) {
- refs = make([]int, len(fields))
- for i := 0; i < len(refs); i++ {
- argRef, err := j.importInputField(fields[i])
- if err != nil {
- return nil, err
- }
- refs[i] = argRef
- }
- return
-}
-
-func (j *JsonConverter) importInputField(field InputValue) (ref int, err error) {
- typeRef := j.importType(field.Type)
-
- defaultValue, err := j.importDefaultValue(field.DefaultValue)
- if err != nil {
- return -1, err
- }
-
- return j.doc.ImportInputValueDefinition(
- field.Name, field.Description, typeRef, defaultValue), nil
-}
-
-func (j *JsonConverter) importType(typeRef TypeRef) (ref int) {
- switch typeRef.Kind {
- case LIST:
- listType := ast.Type{
- TypeKind: ast.TypeKindList,
- OfType: j.importType(*typeRef.OfType),
- }
- return j.doc.AddType(listType)
- case NONNULL:
- nonNullType := ast.Type{
- TypeKind: ast.TypeKindNonNull,
- OfType: j.importType(*typeRef.OfType),
- }
- return j.doc.AddType(nonNullType)
- }
-
- return j.doc.AddNamedType([]byte(*typeRef.Name))
-}
-
-func (j *JsonConverter) importDefaultValue(defaultValue *string) (out ast.DefaultValue, err error) {
- if defaultValue == nil {
- return
- }
-
- from := ast.NewDocument()
- from.Input.AppendInputString(*defaultValue)
-
- report := &operationreport.Report{}
-
- j.parser.PrepareImport(from, report)
- value := j.parser.ParseValue()
-
- if report.HasErrors() {
- err = report
- return
- }
-
- importer := &astimport.Importer{}
- return ast.DefaultValue{
- IsDefined: true,
- Value: importer.ImportValue(value, from, j.doc),
- }, nil
-}
-
-func (j *JsonConverter) importDeprecatedDirective(reason *string) (ref int) {
- var args []int
- if reason != nil {
- valueRef := j.doc.ImportStringValue([]byte(*reason), strings.Contains(*reason, "\n"))
- value := ast.Value{
- Kind: ast.ValueKindString,
- Ref: valueRef,
- }
- j.doc.AddValue(value)
- args = append(args, j.doc.ImportArgument(DeprecationReasonArgName, value))
- }
-
- return j.doc.ImportDirective(DeprecatedDirectiveName, args)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/generator.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/generator.go
deleted file mode 100644
index 02ebb819fe2..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/generator.go
+++ /dev/null
@@ -1,479 +0,0 @@
-package introspection
-
-import (
- "strings"
-
- "github.com/jensneuse/graphql-go-tools/internal/pkg/unsafebytes"
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-const (
- DeprecatedDirectiveName = "deprecated"
- DeprecationReasonArgName = "reason"
-)
-
-type Generator struct {
- Data *Data
- walker *astvisitor.Walker
- visitor *introspectionVisitor
-}
-
-func NewGenerator() *Generator {
- walker := astvisitor.NewWalker(48)
- visitor := introspectionVisitor{
- Walker: &walker,
- }
-
- walker.RegisterAllNodesVisitor(&visitor)
-
- return &Generator{
- walker: &walker,
- visitor: &visitor,
- }
-}
-
-func (g *Generator) Generate(definition *ast.Document, report *operationreport.Report, data *Data) {
- g.visitor.data = data
- g.visitor.definition = definition
- g.walker.Walk(definition, nil, report)
-}
-
-type introspectionVisitor struct {
- *astvisitor.Walker
- definition *ast.Document
- data *Data
- currentType FullType
- currentField Field
- currentDirective Directive
-}
-
-func (i *introspectionVisitor) EnterDocument(operation, definition *ast.Document) {
- i.data.Schema = NewSchema()
-}
-
-func (i *introspectionVisitor) LeaveDocument(operation, definition *ast.Document) {
-
-}
-
-func (i *introspectionVisitor) EnterObjectTypeDefinition(ref int) {
- i.currentType = NewFullType()
- i.currentType.Name = i.definition.ObjectTypeDefinitionNameString(ref)
- i.currentType.Kind = OBJECT
- i.currentType.Description = i.definition.ObjectTypeDescriptionNameString(ref)
- for _, typeRef := range i.definition.ObjectTypeDefinitions[ref].ImplementsInterfaces.Refs {
- name := i.definition.TypeNameString(typeRef)
- i.currentType.Interfaces = append(i.currentType.Interfaces, TypeRef{
- Kind: INTERFACE,
- Name: &name,
- })
- }
-}
-
-func (i *introspectionVisitor) LeaveObjectTypeDefinition(ref int) {
- if strings.HasPrefix(i.currentType.Name, "__") {
- return
- }
- i.data.Schema.Types = append(i.data.Schema.Types, i.currentType)
-}
-
-func (i *introspectionVisitor) EnterObjectTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveObjectTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterFieldDefinition(ref int) {
- i.currentField = NewField()
- i.currentField.Name = i.definition.FieldDefinitionNameString(ref)
- i.currentField.Description = i.definition.FieldDefinitionDescriptionString(ref)
- i.currentField.Type = i.TypeRef(i.definition.FieldDefinitionType(ref))
-
- if i.definition.FieldDefinitionHasDirectives(ref) {
- directiveRef, exists := i.definition.FieldDefinitionDirectiveByName(ref, []byte(DeprecatedDirectiveName))
- if exists {
- i.currentField.IsDeprecated = true
- i.currentField.DeprecationReason = i.deprecationReason(directiveRef)
- }
- }
-}
-
-func (i *introspectionVisitor) LeaveFieldDefinition(ref int) {
- if strings.HasPrefix(i.currentField.Name, "__") {
- return
- }
- i.currentType.Fields = append(i.currentType.Fields, i.currentField)
-}
-
-func (i *introspectionVisitor) EnterInputValueDefinition(ref int) {
- var defaultValue *string
- if i.definition.InputValueDefinitionHasDefaultValue(ref) {
- value := i.definition.InputValueDefinitionDefaultValue(ref)
- printedValue, err := i.definition.PrintValueBytes(value, nil)
- if err != nil {
- i.StopWithInternalErr(err)
- return
- }
- printedStr := unsafebytes.BytesToString(printedValue)
- defaultValue = &printedStr
- }
-
- inputValue := InputValue{
- Name: i.definition.InputValueDefinitionNameString(ref),
- Description: i.definition.InputValueDefinitionDescriptionString(ref),
- Type: i.TypeRef(i.definition.InputValueDefinitionType(ref)),
- DefaultValue: defaultValue,
- }
-
- switch i.Ancestors[len(i.Ancestors)-1].Kind {
- case ast.NodeKindInputObjectTypeDefinition:
- i.currentType.InputFields = append(i.currentType.InputFields, inputValue)
- case ast.NodeKindFieldDefinition:
- i.currentField.Args = append(i.currentField.Args, inputValue)
- case ast.NodeKindDirectiveDefinition:
- i.currentDirective.Args = append(i.currentDirective.Args, inputValue)
- }
-}
-
-func (i *introspectionVisitor) LeaveInputValueDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterInterfaceTypeDefinition(ref int) {
- i.currentType = NewFullType()
- i.currentType.Kind = INTERFACE
- i.currentType.Name = i.definition.InterfaceTypeDefinitionNameString(ref)
- i.currentType.Description = i.definition.InterfaceTypeDefinitionDescriptionString(ref)
-
- interfaceNameBytes := i.definition.InterfaceTypeDefinitionNameBytes(ref)
- for objectTypeDefRef := range i.definition.ObjectTypeDefinitions {
- if i.definition.ObjectTypeDefinitionImplementsInterface(objectTypeDefRef, interfaceNameBytes) {
- objectName := i.definition.ObjectTypeDefinitionNameString(objectTypeDefRef)
- i.currentType.PossibleTypes = append(i.currentType.PossibleTypes, TypeRef{
- Kind: OBJECT,
- Name: &objectName,
- })
- }
- }
-}
-
-func (i *introspectionVisitor) LeaveInterfaceTypeDefinition(ref int) {
- if strings.HasPrefix(i.currentType.Name, "__") {
- return
- }
- i.data.Schema.Types = append(i.data.Schema.Types, i.currentType)
-}
-
-func (i *introspectionVisitor) EnterInterfaceTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveInterfaceTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterScalarTypeDefinition(ref int) {
- typeDefinition := NewFullType()
- typeDefinition.Kind = SCALAR
- typeDefinition.Name = i.definition.ScalarTypeDefinitionNameString(ref)
- typeDefinition.Description = i.definition.ScalarTypeDefinitionDescriptionString(ref)
- i.data.Schema.Types = append(i.data.Schema.Types, typeDefinition)
-}
-
-func (i *introspectionVisitor) LeaveScalarTypeDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterScalarTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveScalarTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterUnionTypeDefinition(ref int) {
- i.currentType = NewFullType()
- i.currentType.Kind = UNION
- i.currentType.Name = i.definition.UnionTypeDefinitionNameString(ref)
- i.currentType.Description = i.definition.UnionTypeDefinitionDescriptionString(ref)
-}
-
-func (i *introspectionVisitor) LeaveUnionTypeDefinition(ref int) {
- if strings.HasPrefix(i.currentType.Name, "__") {
- return
- }
- i.data.Schema.Types = append(i.data.Schema.Types, i.currentType)
-}
-
-func (i *introspectionVisitor) EnterUnionTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveUnionTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterUnionMemberType(ref int) {
- name := i.definition.TypeNameString(ref)
- i.currentType.PossibleTypes = append(i.currentType.PossibleTypes, TypeRef{
- Kind: OBJECT,
- Name: &name,
- })
-}
-
-func (i *introspectionVisitor) LeaveUnionMemberType(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterEnumTypeDefinition(ref int) {
- i.currentType = NewFullType()
- i.currentType.Kind = ENUM
- i.currentType.Name = i.definition.EnumTypeDefinitionNameString(ref)
- i.currentType.Description = i.definition.EnumTypeDefinitionDescriptionString(ref)
-}
-
-func (i *introspectionVisitor) LeaveEnumTypeDefinition(ref int) {
- if strings.HasPrefix(i.currentType.Name, "__") {
- return
- }
- i.data.Schema.Types = append(i.data.Schema.Types, i.currentType)
-}
-
-func (i *introspectionVisitor) EnterEnumTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveEnumTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterEnumValueDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveEnumValueDefinition(ref int) {
- enumValue := EnumValue{
- Name: i.definition.EnumValueDefinitionNameString(ref),
- Description: i.definition.EnumValueDefinitionDescriptionString(ref),
- }
-
- if i.definition.EnumValueDefinitionHasDirectives(ref) {
- directiveRef, exists := i.definition.EnumValueDefinitionDirectiveByName(ref, []byte(DeprecatedDirectiveName))
- if exists {
- enumValue.IsDeprecated = true
- enumValue.DeprecationReason = i.deprecationReason(directiveRef)
- }
- }
-
- i.currentType.EnumValues = append(i.currentType.EnumValues, enumValue)
-}
-
-func (i *introspectionVisitor) EnterInputObjectTypeDefinition(ref int) {
- i.currentType = NewFullType()
- i.currentType.Kind = INPUTOBJECT
- i.currentType.Name = i.definition.InputObjectTypeDefinitionNameString(ref)
- i.currentType.Description = i.definition.InputObjectTypeDefinitionDescriptionString(ref)
-}
-
-func (i *introspectionVisitor) LeaveInputObjectTypeDefinition(ref int) {
- i.data.Schema.Types = append(i.data.Schema.Types, i.currentType)
-}
-
-func (i *introspectionVisitor) EnterInputObjectTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveInputObjectTypeExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterDirectiveDefinition(ref int) {
- i.currentDirective = NewDirective()
- i.currentDirective.Name = i.definition.DirectiveDefinitionNameString(ref)
- i.currentDirective.Description = i.definition.DirectiveDefinitionDescriptionString(ref)
-}
-
-func (i *introspectionVisitor) LeaveDirectiveDefinition(ref int) {
- i.data.Schema.Directives = append(i.data.Schema.Directives, i.currentDirective)
-}
-
-func (i *introspectionVisitor) EnterDirectiveLocation(location ast.DirectiveLocation) {
- i.currentDirective.Locations = append(i.currentDirective.Locations, location.LiteralString())
-}
-
-func (i *introspectionVisitor) LeaveDirectiveLocation(location ast.DirectiveLocation) {
-
-}
-
-func (i *introspectionVisitor) EnterSchemaDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveSchemaDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterSchemaExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveSchemaExtension(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterRootOperationTypeDefinition(ref int) {
- switch i.definition.RootOperationTypeDefinitions[ref].OperationType {
- case ast.OperationTypeQuery:
- i.data.Schema.QueryType = &TypeName{
- Name: i.definition.Input.ByteSliceString(i.definition.RootOperationTypeDefinitions[ref].NamedType.Name),
- }
- case ast.OperationTypeMutation:
- i.data.Schema.MutationType = &TypeName{
- Name: i.definition.Input.ByteSliceString(i.definition.RootOperationTypeDefinitions[ref].NamedType.Name),
- }
- case ast.OperationTypeSubscription:
- i.data.Schema.SubscriptionType = &TypeName{
- Name: i.definition.Input.ByteSliceString(i.definition.RootOperationTypeDefinitions[ref].NamedType.Name),
- }
- }
-}
-
-func (i *introspectionVisitor) LeaveRootOperationTypeDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterOperationDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveOperationDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterSelectionSet(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveSelectionSet(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterField(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveField(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterArgument(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveArgument(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterFragmentSpread(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveFragmentSpread(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterInlineFragment(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveInlineFragment(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterFragmentDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveFragmentDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterVariableDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveVariableDefinition(ref int) {
-
-}
-
-func (i *introspectionVisitor) EnterDirective(ref int) {
-
-}
-
-func (i *introspectionVisitor) LeaveDirective(ref int) {
-
-}
-
-func (i *introspectionVisitor) TypeRef(typeRef int) TypeRef {
- switch i.definition.Types[typeRef].TypeKind {
- case ast.TypeKindNamed:
- name := i.definition.TypeNameBytes(typeRef)
- node, exists := i.definition.Index.FirstNodeByNameBytes(name)
- if !exists {
- return TypeRef{}
- }
- var typeKind __TypeKind
- switch node.Kind {
- case ast.NodeKindScalarTypeDefinition:
- typeKind = SCALAR
- case ast.NodeKindObjectTypeDefinition:
- typeKind = OBJECT
- case ast.NodeKindEnumTypeDefinition:
- typeKind = ENUM
- case ast.NodeKindInterfaceTypeDefinition:
- typeKind = INTERFACE
- case ast.NodeKindUnionTypeDefinition:
- typeKind = UNION
- case ast.NodeKindInputObjectTypeDefinition:
- typeKind = INPUTOBJECT
- }
- nameStr := unsafebytes.BytesToString(name)
- return TypeRef{
- Kind: typeKind,
- Name: &nameStr,
- }
- case ast.TypeKindNonNull:
- ofType := i.TypeRef(i.definition.Types[typeRef].OfType)
- return TypeRef{
- Kind: NONNULL,
- OfType: &ofType,
- }
- case ast.TypeKindList:
- ofType := i.TypeRef(i.definition.Types[typeRef].OfType)
- return TypeRef{
- Kind: LIST,
- OfType: &ofType,
- }
- default:
- return TypeRef{}
- }
-}
-
-func (i *introspectionVisitor) deprecationReason(directiveRef int) (reason *string) {
- argValue, exists := i.definition.DirectiveArgumentValueByName(directiveRef, []byte(DeprecationReasonArgName))
- if exists {
- reasonContent := i.definition.ValueContentString(argValue)
- return &reasonContent
- }
-
- defaultValue := i.definition.DirectiveDefinitionArgumentDefaultValueString(DeprecatedDirectiveName, DeprecationReasonArgName)
- if defaultValue != "" {
- return &defaultValue
- }
-
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/introspection.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/introspection.go
deleted file mode 100644
index 1b953fbd7f2..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/introspection.go
+++ /dev/null
@@ -1,154 +0,0 @@
-//go:generate go-enum -f=$GOFILE --noprefix --marshal
-
-// Package introspection takes a GraphQL Schema and provides the introspection JSON to fulfill introspection queries.
-package introspection
-
-import (
- "bytes"
-)
-
-type Data struct {
- Schema Schema `json:"__schema"`
-}
-
-type Schema struct {
- QueryType *TypeName `json:"queryType"`
- MutationType *TypeName `json:"mutationType"`
- SubscriptionType *TypeName `json:"subscriptionType"`
- Types []FullType `json:"types"`
- Directives []Directive `json:"directives"`
-}
-
-func (s *Schema) TypeNames() (query, mutation, subscription string) {
- if s.QueryType != nil {
- query = s.QueryType.Name
- }
- if s.MutationType != nil {
- mutation = s.MutationType.Name
- }
- if s.SubscriptionType != nil {
- subscription = s.SubscriptionType.Name
- }
- return
-}
-
-func NewSchema() Schema {
- return Schema{
- Types: make([]FullType, 0),
- Directives: make([]Directive, 0),
- }
-}
-
-type TypeName struct {
- Name string `json:"name"`
-}
-
-type FullType struct {
- Kind __TypeKind `json:"kind"`
- Name string `json:"name"`
- Description string `json:"description"`
- // not empty for __TypeKind OBJECT and INTERFACE only
- Fields []Field `json:"fields"`
- // not empty for __TypeKind INPUT_OBJECT only
- InputFields []InputValue `json:"inputFields"`
- // not empty for __TypeKind OBJECT only
- Interfaces []TypeRef `json:"interfaces"`
- // not empty for __TypeKind ENUM only
- EnumValues []EnumValue `json:"enumValues"`
- // not empty for __TypeKind INTERFACE and UNION only
- PossibleTypes []TypeRef `json:"possibleTypes"`
-}
-
-func NewFullType() FullType {
- return FullType{
- Fields: make([]Field, 0),
- InputFields: make([]InputValue, 0),
- Interfaces: make([]TypeRef, 0),
- EnumValues: make([]EnumValue, 0),
- PossibleTypes: make([]TypeRef, 0),
- }
-}
-
-/*
-ENUM(
-SCALAR
-LIST
-NON_NULL
-OBJECT
-ENUM
-INTERFACE
-UNION
-INPUT_OBJECT
-)
-*/
-type __TypeKind int
-
-func (x __TypeKind) MarshalJSON() ([]byte, error) {
-
- text, err := x.MarshalText()
- if err != nil {
- return nil, err
- }
-
- var buff bytes.Buffer
- _, err = buff.WriteRune('"')
- if err != nil {
- return nil, err
- }
- _, err = buff.Write(text)
- if err != nil {
- return nil, err
- }
- _, err = buff.WriteRune('"')
-
- return buff.Bytes(), err
-}
-
-type TypeRef struct {
- Kind __TypeKind `json:"kind"`
- Name *string `json:"name"`
- OfType *TypeRef `json:"ofType"`
-}
-
-type Field struct {
- Name string `json:"name"`
- Description string `json:"description"`
- Args []InputValue `json:"args"`
- Type TypeRef `json:"type"`
- IsDeprecated bool `json:"isDeprecated"`
- DeprecationReason *string `json:"deprecationReason"`
-}
-
-func NewField() Field {
- return Field{
- Args: make([]InputValue, 0),
- }
-}
-
-type EnumValue struct {
- Name string `json:"name"`
- Description string `json:"description"`
- IsDeprecated bool `json:"isDeprecated"`
- DeprecationReason *string `json:"deprecationReason"`
-}
-
-type InputValue struct {
- Name string `json:"name"`
- Description string `json:"description"`
- Type TypeRef `json:"type"`
- DefaultValue *string `json:"defaultValue"`
-}
-
-type Directive struct {
- Name string `json:"name"`
- Description string `json:"description"`
- Locations []string `json:"locations"`
- Args []InputValue `json:"args"`
-}
-
-func NewDirective() Directive {
- return Directive{
- Locations: make([]string, 0),
- Args: make([]InputValue, 0),
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/introspection_enum.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/introspection_enum.go
deleted file mode 100644
index f66b96bcc16..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/introspection/introspection_enum.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// Code generated by go-enum
-// DO NOT EDIT!
-
-package introspection
-
-import (
- "fmt"
-)
-
-const (
- // SCALAR is a __TypeKind of type SCALAR
- SCALAR __TypeKind = iota
- // LIST is a __TypeKind of type LIST
- LIST
- // NONNULL is a __TypeKind of type NON_NULL
- NONNULL
- // OBJECT is a __TypeKind of type OBJECT
- OBJECT
- // ENUM is a __TypeKind of type ENUM
- ENUM
- // INTERFACE is a __TypeKind of type INTERFACE
- INTERFACE
- // UNION is a __TypeKind of type UNION
- UNION
- // INPUTOBJECT is a __TypeKind of type INPUT_OBJECT
- INPUTOBJECT
-)
-
-const ___TypeKindName = "SCALARLISTNON_NULLOBJECTENUMINTERFACEUNIONINPUT_OBJECT"
-
-var ___TypeKindMap = map[__TypeKind]string{
- 0: ___TypeKindName[0:6],
- 1: ___TypeKindName[6:10],
- 2: ___TypeKindName[10:18],
- 3: ___TypeKindName[18:24],
- 4: ___TypeKindName[24:28],
- 5: ___TypeKindName[28:37],
- 6: ___TypeKindName[37:42],
- 7: ___TypeKindName[42:54],
-}
-
-// String implements the Stringer interface.
-func (x __TypeKind) String() string {
- if str, ok := ___TypeKindMap[x]; ok {
- return str
- }
- return fmt.Sprintf("__TypeKind(%d)", x)
-}
-
-var ___TypeKindValue = map[string]__TypeKind{
- ___TypeKindName[0:6]: 0,
- ___TypeKindName[6:10]: 1,
- ___TypeKindName[10:18]: 2,
- ___TypeKindName[18:24]: 3,
- ___TypeKindName[24:28]: 4,
- ___TypeKindName[28:37]: 5,
- ___TypeKindName[37:42]: 6,
- ___TypeKindName[42:54]: 7,
-}
-
-// Parse__TypeKind attempts to convert a string to a __TypeKind
-func Parse__TypeKind(name string) (__TypeKind, error) {
- if x, ok := ___TypeKindValue[name]; ok {
- return x, nil
- }
- return __TypeKind(0), fmt.Errorf("%s is not a valid __TypeKind", name)
-}
-
-// MarshalText implements the text marshaller method
-func (x *__TypeKind) MarshalText() ([]byte, error) {
- return []byte(x.String()), nil
-}
-
-// UnmarshalText implements the text unmarshaller method
-func (x *__TypeKind) UnmarshalText(text []byte) error {
- name := string(text)
- tmp, err := Parse__TypeKind(name)
- if err != nil {
- return err
- }
- *x = tmp
- return nil
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/identkeyword/identkeyword.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/identkeyword/identkeyword.go
deleted file mode 100644
index 57bdcf28c5e..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/identkeyword/identkeyword.go
+++ /dev/null
@@ -1,101 +0,0 @@
-//go:generate stringer -type=IdentKeyword
-
-// Package identkeyword contains all possible keywords for GraphQL identifiers
-package identkeyword
-
-type IdentKeyword int
-
-const (
- UNDEFINED IdentKeyword = iota
- ON
- TRUE
- FALSE
- NULL
- QUERY
- MUTATION
- SUBSCRIPTION
- FRAGMENT
- IMPLEMENTS
- SCHEMA
- SCALAR
- TYPE
- INTERFACE
- UNION
- ENUM
- INPUT
- DIRECTIVE
- EXTEND
-)
-
-func KeywordFromLiteral(literal []byte) IdentKeyword {
- switch len(literal) {
- case 2:
- if literal[0] == 'o' && literal[1] == 'n' {
- return ON
- }
- case 4:
- if literal[0] == 'n' && literal[1] == 'u' && literal[2] == 'l' && literal[3] == 'l' {
- return NULL
- }
- if literal[0] == 'e' && literal[1] == 'n' && literal[2] == 'u' && literal[3] == 'm' {
- return ENUM
- }
- if literal[0] == 't' {
- if literal[1] == 'r' && literal[2] == 'u' && literal[3] == 'e' {
- return TRUE
- }
- if literal[1] == 'y' && literal[2] == 'p' && literal[3] == 'e' {
- return TYPE
- }
- }
- case 5:
- if literal[0] == 'f' && literal[1] == 'a' && literal[2] == 'l' && literal[3] == 's' && literal[4] == 'e' {
- return FALSE
- }
- if literal[0] == 'u' && literal[1] == 'n' && literal[2] == 'i' && literal[3] == 'o' && literal[4] == 'n' {
- return UNION
- }
- if literal[0] == 'q' && literal[1] == 'u' && literal[2] == 'e' && literal[3] == 'r' && literal[4] == 'y' {
- return QUERY
- }
- if literal[0] == 'i' && literal[1] == 'n' && literal[2] == 'p' && literal[3] == 'u' && literal[4] == 't' {
- return INPUT
- }
- case 6:
- if literal[0] == 'e' && literal[1] == 'x' && literal[2] == 't' && literal[3] == 'e' && literal[4] == 'n' && literal[5] == 'd' {
- return EXTEND
- }
- if literal[0] == 's' {
- if literal[1] == 'c' && literal[2] == 'h' && literal[3] == 'e' && literal[4] == 'm' && literal[5] == 'a' {
- return SCHEMA
- }
- if literal[1] == 'c' && literal[2] == 'a' && literal[3] == 'l' && literal[4] == 'a' && literal[5] == 'r' {
- return SCALAR
- }
- }
- case 8:
- if literal[0] == 'm' && literal[1] == 'u' && literal[2] == 't' && literal[3] == 'a' && literal[4] == 't' && literal[5] == 'i' && literal[6] == 'o' && literal[7] == 'n' {
- return MUTATION
- }
- if literal[0] == 'f' && literal[1] == 'r' && literal[2] == 'a' && literal[3] == 'g' && literal[4] == 'm' && literal[5] == 'e' && literal[6] == 'n' && literal[7] == 't' {
- return FRAGMENT
- }
- case 9:
- if literal[0] == 'i' && literal[1] == 'n' && literal[2] == 't' && literal[3] == 'e' && literal[4] == 'r' && literal[5] == 'f' && literal[6] == 'a' && literal[7] == 'c' && literal[8] == 'e' {
- return INTERFACE
- }
- if literal[0] == 'd' && literal[1] == 'i' && literal[2] == 'r' && literal[3] == 'e' && literal[4] == 'c' && literal[5] == 't' && literal[6] == 'i' && literal[7] == 'v' && literal[8] == 'e' {
- return DIRECTIVE
- }
- case 10:
- if literal[0] == 'i' && literal[1] == 'm' && literal[2] == 'p' && literal[3] == 'l' && literal[4] == 'e' && literal[5] == 'm' && literal[6] == 'e' && literal[7] == 'n' && literal[8] == 't' && literal[9] == 's' {
- return IMPLEMENTS
- }
- case 12:
- if literal[0] == 's' && literal[1] == 'u' && literal[2] == 'b' && literal[3] == 's' && literal[4] == 'c' && literal[5] == 'r' && literal[6] == 'i' && literal[7] == 'p' && literal[8] == 't' && literal[9] == 'i' && literal[10] == 'o' && literal[11] == 'n' {
- return SUBSCRIPTION
- }
- }
-
- return UNDEFINED
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/identkeyword/identkeyword_string.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/identkeyword/identkeyword_string.go
deleted file mode 100644
index eda4494d70d..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/identkeyword/identkeyword_string.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Code generated by "stringer -type=IdentKeyword"; DO NOT EDIT.
-
-package identkeyword
-
-import "strconv"
-
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[UNDEFINED-0]
- _ = x[ON-1]
- _ = x[TRUE-2]
- _ = x[FALSE-3]
- _ = x[NULL-4]
- _ = x[QUERY-5]
- _ = x[MUTATION-6]
- _ = x[SUBSCRIPTION-7]
- _ = x[FRAGMENT-8]
- _ = x[IMPLEMENTS-9]
- _ = x[SCHEMA-10]
- _ = x[SCALAR-11]
- _ = x[TYPE-12]
- _ = x[INTERFACE-13]
- _ = x[UNION-14]
- _ = x[ENUM-15]
- _ = x[INPUT-16]
- _ = x[DIRECTIVE-17]
- _ = x[EXTEND-18]
-}
-
-const _IdentKeyword_name = "UNDEFINEDONTRUEFALSENULLQUERYMUTATIONSUBSCRIPTIONFRAGMENTIMPLEMENTSSCHEMASCALARTYPEINTERFACEUNIONENUMINPUTDIRECTIVEEXTEND"
-
-var _IdentKeyword_index = [...]uint8{0, 9, 11, 15, 20, 24, 29, 37, 49, 57, 67, 73, 79, 83, 92, 97, 101, 106, 115, 121}
-
-func (i IdentKeyword) String() string {
- if i < 0 || i >= IdentKeyword(len(_IdentKeyword_index)-1) {
- return "IdentKeyword(" + strconv.FormatInt(int64(i), 10) + ")"
- }
- return _IdentKeyword_name[_IdentKeyword_index[i]:_IdentKeyword_index[i+1]]
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/keyword/keyword.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/keyword/keyword.go
deleted file mode 100644
index bfaf5356af9..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/keyword/keyword.go
+++ /dev/null
@@ -1,42 +0,0 @@
-//go:generate stringer -type=Keyword
-
-// Package keyword contains all possible GraphQL keywords
-package keyword
-
-type Keyword int
-
-const (
- UNDEFINED Keyword = iota
- IDENT
- COMMENT
- EOF
-
- COLON
- BANG
- LT
- TAB
- SPACE
- COMMA
- AT
- DOT
- SPREAD
- PIPE
- SLASH
- EQUALS
- SUB
- AND
- QUOTE
-
- DOLLAR
- STRING
- BLOCKSTRING
- INTEGER
- FLOAT
-
- LPAREN
- RPAREN
- LBRACK
- RBRACK
- LBRACE
- RBRACE
-)
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/keyword/keyword_string.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/keyword/keyword_string.go
deleted file mode 100644
index f37f6a77650..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/keyword/keyword_string.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Code generated by "stringer -type=Keyword"; DO NOT EDIT.
-
-package keyword
-
-import "strconv"
-
-func _() {
- // An "invalid array index" compiler error signifies that the constant values have changed.
- // Re-run the stringer command to generate them again.
- var x [1]struct{}
- _ = x[UNDEFINED-0]
- _ = x[IDENT-1]
- _ = x[COMMENT-2]
- _ = x[EOF-3]
- _ = x[COLON-4]
- _ = x[BANG-5]
- _ = x[LT-6]
- _ = x[TAB-7]
- _ = x[SPACE-8]
- _ = x[COMMA-9]
- _ = x[AT-10]
- _ = x[DOT-11]
- _ = x[SPREAD-12]
- _ = x[PIPE-13]
- _ = x[SLASH-14]
- _ = x[EQUALS-15]
- _ = x[SUB-16]
- _ = x[AND-17]
- _ = x[QUOTE-18]
- _ = x[DOLLAR-19]
- _ = x[STRING-20]
- _ = x[BLOCKSTRING-21]
- _ = x[INTEGER-22]
- _ = x[FLOAT-23]
- _ = x[LPAREN-24]
- _ = x[RPAREN-25]
- _ = x[LBRACK-26]
- _ = x[RBRACK-27]
- _ = x[LBRACE-28]
- _ = x[RBRACE-29]
-}
-
-const _Keyword_name = "UNDEFINEDIDENTCOMMENTEOFCOLONBANGLTTABSPACECOMMAATDOTSPREADPIPESLASHEQUALSSUBANDQUOTEDOLLARSTRINGBLOCKSTRINGINTEGERFLOATLPARENRPARENLBRACKRBRACKLBRACERBRACE"
-
-var _Keyword_index = [...]uint8{0, 9, 14, 21, 24, 29, 33, 35, 38, 43, 48, 50, 53, 59, 63, 68, 74, 77, 80, 85, 91, 97, 108, 115, 120, 126, 132, 138, 144, 150, 156}
-
-func (i Keyword) String() string {
- if i < 0 || i >= Keyword(len(_Keyword_index)-1) {
- return "Keyword(" + strconv.FormatInt(int64(i), 10) + ")"
- }
- return _Keyword_name[_Keyword_index[i]:_Keyword_index[i+1]]
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/lexer.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/lexer.go
deleted file mode 100644
index 240dd08f9f0..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/lexer.go
+++ /dev/null
@@ -1,430 +0,0 @@
-// Package lexer contains the logic to turn an ast.Input into lexed tokens
-package lexer
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/keyword"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/runes"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/token"
-)
-
-// Lexer emits tokens from a input reader
-type Lexer struct {
- input *ast.Input
-}
-
-func (l *Lexer) SetInput(input *ast.Input) {
- l.input = input
-}
-
-// Read emits the next token
-func (l *Lexer) Read() (tok token.Token) {
-
- var next byte
-
- for {
- tok.SetStart(l.input.InputPosition, l.input.TextPosition)
- next = l.readRune()
- if !l.byteIsWhitespace(next) {
- break
- }
- }
-
- if l.matchSingleRuneToken(next, &tok) {
- return
- }
-
- switch next {
- case runes.HASHTAG:
- l.readComment(&tok)
- return
- case runes.QUOTE:
- l.readString(&tok)
- return
- case runes.DOT:
- l.readDotOrSpread(&tok)
- return
- }
-
- if runeIsDigit(next) {
- l.readDigit(&tok)
- return
- }
-
- l.readIdent()
- tok.Keyword = keyword.IDENT
- tok.SetEnd(l.input.InputPosition, l.input.TextPosition)
- return
-}
-
-func (l *Lexer) matchSingleRuneToken(r byte, tok *token.Token) bool {
-
- switch r {
- case runes.EOF:
- tok.Keyword = keyword.EOF
- case runes.PIPE:
- tok.Keyword = keyword.PIPE
- case runes.EQUALS:
- tok.Keyword = keyword.EQUALS
- case runes.AT:
- tok.Keyword = keyword.AT
- case runes.COLON:
- tok.Keyword = keyword.COLON
- case runes.BANG:
- tok.Keyword = keyword.BANG
- case runes.LPAREN:
- tok.Keyword = keyword.LPAREN
- case runes.RPAREN:
- tok.Keyword = keyword.RPAREN
- case runes.LBRACE:
- tok.Keyword = keyword.LBRACE
- case runes.RBRACE:
- tok.Keyword = keyword.RBRACE
- case runes.LBRACK:
- tok.Keyword = keyword.LBRACK
- case runes.RBRACK:
- tok.Keyword = keyword.RBRACK
- case runes.AND:
- tok.Keyword = keyword.AND
- case runes.SUB:
- tok.Keyword = keyword.SUB
- case runes.DOLLAR:
- tok.Keyword = keyword.DOLLAR
- default:
- return false
- }
-
- tok.SetEnd(l.input.InputPosition, l.input.TextPosition)
-
- return true
-}
-
-func (l *Lexer) readIdent() {
- for {
- if l.input.InputPosition < l.input.Length {
- if !l.runeIsIdent(l.input.RawBytes[l.input.InputPosition]) {
- return
- }
- l.input.TextPosition.CharStart++
- l.input.InputPosition++
- } else {
- return
- }
- }
-}
-
-func (l *Lexer) readDotOrSpread(tok *token.Token) {
-
- isSpread := l.peekEquals(false, runes.DOT, runes.DOT)
-
- if isSpread {
- l.swallowAmount(2)
- tok.Keyword = keyword.SPREAD
- } else {
- tok.Keyword = keyword.DOT
- }
-
- tok.SetEnd(l.input.InputPosition, l.input.TextPosition)
-}
-
-func (l *Lexer) readComment(tok *token.Token) {
-
- tok.Keyword = keyword.COMMENT
-
- for {
- next := l.readRune()
- switch next {
- case runes.EOF:
- return
- case runes.CARRIAGERETURN, runes.LINETERMINATOR:
- if l.peekRune(true) != runes.HASHTAG {
- return
- }
- default:
- tok.SetEnd(l.input.InputPosition, l.input.TextPosition)
- }
- }
-}
-
-func (l *Lexer) readString(tok *token.Token) {
-
- if l.peekEquals(false, runes.QUOTE, runes.QUOTE) {
- l.swallowAmount(2)
- l.readBlockString(tok)
- } else {
- l.readSingleLineString(tok)
- }
-}
-
-func (l *Lexer) swallowAmount(amount int) {
- for i := 0; i < amount; i++ {
- l.readRune()
- }
-}
-
-func (l *Lexer) peekEquals(ignoreWhitespace bool, equals ...byte) bool {
-
- var whitespaceOffset int
- if ignoreWhitespace {
- whitespaceOffset = l.peekWhitespaceLength()
- }
-
- start := l.input.InputPosition + whitespaceOffset
- end := l.input.InputPosition + len(equals) + whitespaceOffset
-
- if end > l.input.Length {
- return false
- }
-
- for i := 0; i < len(equals); i++ {
- if l.input.RawBytes[start+i] != equals[i] {
- return false
- }
- }
-
- return true
-}
-
-func (l *Lexer) peekWhitespaceLength() (amount int) {
- for i := l.input.InputPosition; i < l.input.Length; i++ {
- if l.byteIsWhitespace(l.input.RawBytes[i]) {
- amount++
- } else {
- break
- }
- }
-
- return amount
-}
-
-func (l *Lexer) readDigit(tok *token.Token) {
-
- var r byte
- for {
- r = l.peekRune(false)
- if !runeIsDigit(r) {
- break
- }
- l.readRune()
- }
-
- hasExponent := r == runes.EXPONENT_LOWER || r == runes.EXPONENT_UPPER
- isFloat := r == runes.DOT || hasExponent
-
- if isFloat {
- l.readRune()
- l.readFloat(hasExponent,tok)
- return
- }
-
- tok.Keyword = keyword.INTEGER
- tok.SetEnd(l.input.InputPosition, l.input.TextPosition)
-}
-
-func (l *Lexer) readFloat(hasReadExponentAlready bool,tok *token.Token) {
-
- var r byte
- for {
- r = l.peekRune(false)
- if !runeIsDigit(r) {
- break
- }
- l.readRune()
- }
-
- if hasReadExponentAlready {
- float := keyword.FLOAT
- tok.Keyword = float
- tok.SetEnd(l.input.InputPosition, l.input.TextPosition)
- return
- }
-
- optionalExponent := l.peekRune(false)
- if optionalExponent == runes.EXPONENT_LOWER || optionalExponent == runes.EXPONENT_UPPER {
- l.readRune()
- }
-
- optionalPlusMinus := l.peekRune(false)
- if optionalPlusMinus == runes.SUB || optionalPlusMinus == runes.ADD {
- l.readRune()
- }
-
- for {
- r = l.peekRune(false)
- if !runeIsDigit(r) {
- break
- }
- l.readRune()
- }
-
- float := keyword.FLOAT
- tok.Keyword = float
- tok.SetEnd(l.input.InputPosition, l.input.TextPosition)
-}
-
-func (l *Lexer) readRune() (r byte) {
-
- if l.input.InputPosition < l.input.Length {
- r = l.input.RawBytes[l.input.InputPosition]
-
- if r == runes.LINETERMINATOR {
- l.input.TextPosition.LineStart++
- l.input.TextPosition.CharStart = 1
- } else {
- l.input.TextPosition.CharStart++
- }
-
- l.input.InputPosition++
- } else {
- r = runes.EOF
- }
-
- return
-}
-
-func (l *Lexer) peekRune(ignoreWhitespace bool) (r byte) {
-
- for i := l.input.InputPosition; i < l.input.Length; i++ {
- r = l.input.RawBytes[i]
- if !ignoreWhitespace {
- return r
- } else if !l.byteIsWhitespace(r) {
- return r
- }
- }
-
- return runes.EOF
-}
-
-func (l *Lexer) runeIsIdent(r byte) bool {
-
- switch {
- case r >= 'a' && r <= 'z':
- return true
- case r >= 'A' && r <= 'Z':
- return true
- case r >= '0' && r <= '9':
- return true
- case r == runes.SUB:
- return true
- case r == runes.UNDERSCORE:
- return true
- default:
- return false
- }
-}
-
-func runeIsDigit(r byte) bool {
- switch {
- case r >= '0' && r <= '9':
- return true
- default:
- return false
- }
-}
-
-func (l *Lexer) byteIsWhitespace(r byte) bool {
- switch r {
- case runes.SPACE, runes.TAB, runes.CARRIAGERETURN, runes.LINETERMINATOR, runes.COMMA:
- return true
- default:
- return false
- }
-}
-
-func (l *Lexer) readBlockString(tok *token.Token) {
- tok.Keyword = keyword.BLOCKSTRING
-
- tok.SetStart(l.input.InputPosition, l.input.TextPosition)
- tok.TextPosition.CharStart -= 3
-
- escaped := false
- quoteCount := 0
- whitespaceCount := 0
- reachedFirstNonWhitespace := false
- leadingWhitespaceToken := 0
-
- for {
- next := l.readRune()
- switch next {
- case runes.SPACE, runes.TAB, runes.CARRIAGERETURN, runes.LINETERMINATOR:
- quoteCount = 0
- whitespaceCount++
- case runes.EOF:
- return
- case runes.QUOTE:
- if escaped {
- escaped = !escaped
- continue
- }
-
- quoteCount++
-
- if quoteCount == 3 {
- tok.SetEnd(l.input.InputPosition-3, l.input.TextPosition)
- tok.Literal.Start += uint32(leadingWhitespaceToken)
- tok.Literal.End -= uint32(whitespaceCount)
- return
- }
-
- case runes.BACKSLASH:
- escaped = !escaped
- quoteCount = 0
- whitespaceCount = 0
- default:
- if !reachedFirstNonWhitespace {
- reachedFirstNonWhitespace = true
- leadingWhitespaceToken = whitespaceCount
- }
- escaped = false
- quoteCount = 0
- whitespaceCount = 0
- }
- }
-}
-
-func (l *Lexer) readSingleLineString(tok *token.Token) {
-
- tok.Keyword = keyword.STRING
-
- tok.SetStart(l.input.InputPosition, l.input.TextPosition)
- tok.TextPosition.CharStart -= 1
-
- escaped := false
- whitespaceCount := 0
- reachedFirstNonWhitespace := false
- leadingWhitespaceToken := 0
-
- for {
- next := l.readRune()
- switch next {
- case runes.SPACE, runes.TAB:
- whitespaceCount++
- case runes.EOF:
- tok.SetEnd(l.input.InputPosition, l.input.TextPosition)
- tok.Literal.Start += uint32(leadingWhitespaceToken)
- tok.Literal.End -= uint32(whitespaceCount)
- return
- case runes.QUOTE, runes.CARRIAGERETURN, runes.LINETERMINATOR:
- if escaped {
- escaped = !escaped
- continue
- }
-
- tok.SetEnd(l.input.InputPosition-1, l.input.TextPosition)
- tok.Literal.Start += uint32(leadingWhitespaceToken)
- tok.Literal.End -= uint32(whitespaceCount)
- return
- case runes.BACKSLASH:
- escaped = !escaped
- whitespaceCount = 0
- default:
- if !reachedFirstNonWhitespace {
- reachedFirstNonWhitespace = true
- leadingWhitespaceToken = whitespaceCount
- }
- escaped = false
- whitespaceCount = 0
- }
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/literal/literal.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/literal/literal.go
deleted file mode 100644
index ef6a8573187..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/literal/literal.go
+++ /dev/null
@@ -1,145 +0,0 @@
-// Package literal contains a selection of frequently used literals with GraphQL APIs
-package literal
-
-import "bytes"
-
-var (
- COLON = []byte(":")
- BANG = []byte("!")
- LINETERMINATOR = []byte("\n")
- TAB = []byte(" ")
- SPACE = []byte(" ")
- QUOTE = []byte("\"")
- COMMA = []byte(",")
- AT = []byte("@")
- DOLLAR = []byte("$")
- DOT = []byte(".")
- SPREAD = []byte("...")
- PIPE = []byte("|")
- SLASH = []byte("/")
- BACKSLASH = []byte("\\")
- EQUALS = []byte("=")
- SUB = []byte("-")
- AND = []byte("&")
-
- LPAREN = []byte("(")
- RPAREN = []byte(")")
- LBRACK = []byte("[")
- RBRACK = []byte("]")
- LBRACE = []byte("{")
- DOUBLE_LBRACE = []byte("{{")
- DOUBLE_RBRACE = []byte("}}")
- RBRACE = []byte("}")
-
- GOBOOL = []byte("bool")
- GOINT32 = []byte("int32")
- GOFLOAT32 = []byte("float32")
- GOSTRING = []byte("string")
- GONIL = []byte("nil")
-
- EOF = []byte("eof")
- ID = []byte("ID")
- Date = []byte("Date")
- BOOLEAN = []byte("Boolean")
- STRING = []byte("String")
- INT = []byte("Int")
- FLOAT = []byte("Float")
- TYPE = []byte("type")
- UNDERSCORETYPE = []byte("__type")
- UNDERSCORESCHEMA = []byte("__schema")
- TYPENAME = []byte("__typename")
- GRAPHQLTYPE = []byte("graphqlType")
- INTERFACE = []byte("interface")
- INPUT = []byte("input")
- WASMFILE = []byte("wasmFile")
- INCLUDE = []byte("include")
- IF = []byte("if")
- SKIP = []byte("skip")
- SCHEMA = []byte("schema")
- EXTEND = []byte("extend")
- SCALAR = []byte("scalar")
- UNION = []byte("union")
- ENUM = []byte("enum")
- DIRECTIVE = []byte("directive")
- QUERY = []byte("query")
- MUTATION = []byte("mutation")
- SUBSCRIPTION = []byte("subscription")
- IMPLEMENTS = []byte("implements")
- ON = []byte("on")
- FRAGMENT = []byte("fragment")
- NULL = []byte("null")
- OBJECT = []byte("object")
- DATA = []byte("data")
- URL = []byte("url")
- CONFIG_FILE_PATH = []byte("configFilePath")
- CONFIG_STRING = []byte("configString")
- DELAY_SECONDS = []byte("delaySeconds")
- PIPELINE_CONFIG = []byte("pipelineConfig")
- PIPELINE_CONFIG_STRING = []byte("pipelineConfigString")
- PIPELINE_CONFIG_FILE = []byte("pipelineConfigFile")
- TRANSFORMATION = []byte("transformation")
- INPUT_JSON = []byte("inputJSON")
- DEFAULT_TYPENAME = []byte("defaultTypeName")
- STATUS_CODE_TYPENAME_MAPPINGS = []byte("statusCodeTypeNameMappings")
- DOT_OBJECT_DOT = []byte(".object.")
- DOT_ARGUMENTS_DOT = []byte(".arguments.")
- ADDR = []byte("addr")
- ADD = []byte("add")
- BROKERADDR = []byte("brokerAddr")
- CLIENTID = []byte("clientID")
- TOPIC = []byte("topic")
- HOST = []byte("host")
- PARAMS = []byte("params")
- FIELD = []byte("field")
- BODY = []byte("body")
- METHOD = []byte("method")
- MODE = []byte("mode")
- HEADERS = []byte("headers")
- KEY = []byte("key")
- OP = []byte("op")
- REPLACE = []byte("replace")
- INITIAL_BATCH_SIZE = []byte("initialBatchSize")
- MILLISECONDS = []byte("milliSeconds")
- PATH = []byte("path")
- VALUE = []byte("value")
- HTTP_METHOD_GET = []byte("GET")
- HTTP_METHOD_POST = []byte("POST")
- HTTP_METHOD_PUT = []byte("PUT")
- HTTP_METHOD_DELETE = []byte("DELETE")
- HTTP_METHOD_PATCH = []byte("PATCH")
-
- TRUE = []byte("true")
- FALSE = []byte("false")
-
- LocationQuery = []byte("QUERY")
- LocationMutation = []byte("MUTATION")
- LocationSubscription = []byte("SUBSCRIPTION")
- LocationField = []byte("FIELD")
- LocationFragmentDefinition = []byte("FRAGMENT_DEFINITION")
- LocationFragmentSpread = []byte("FRAGMENT_SPREAD")
- LocationInlineFragment = []byte("INLINE_FRAGMENT")
- LocationVariableDefinition = []byte("VARIABLE_DEFINITION")
-
- LocationSchema = []byte("SCHEMA")
- LocationScalar = []byte("SCALAR")
- LocationObject = []byte("OBJECT")
- LocationFieldDefinition = []byte("FIELD_DEFINITION")
- LocationArgumentDefinition = []byte("ARGUMENT_DEFINITION")
- LocationInterface = []byte("INTERFACE")
- LocationUnion = []byte("UNION")
- LocationEnum = []byte("ENUM")
- LocationEnumValue = []byte("ENUM_VALUE")
- LocationInputObject = []byte("INPUT_OBJECT")
- LocationInputFieldDefinition = []byte("INPUT_FIELD_DEFINITION")
-)
-
-const (
- DOUBLE_LBRACE_STR = "{{"
- DOUBLE_RBRACE_STR = "}}"
-)
-
-type Literal []byte
-
-func (l Literal) Equals(another Literal) bool {
- return bytes.Equal(l, another)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/position/position.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/position/position.go
deleted file mode 100644
index e21fdc8c831..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/position/position.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Package position contains the objects and logic to properly describe the position of a token in a GraphQL document
-package position
-
-import "fmt"
-
-type Position struct {
- LineStart uint32
- LineEnd uint32
- CharStart uint32
- CharEnd uint32
-}
-
-func (p Position) String() string {
- return fmt.Sprintf("%d:%d-%d:%d", p.LineStart, p.CharStart, p.LineEnd, p.CharEnd)
-}
-
-func (p *Position) Reset() {
- p.LineStart = 1
- p.LineEnd = 1
- p.CharStart = 1
- p.CharEnd = 1
-}
-
-func (p *Position) MergeStartIntoStart(position Position) {
- p.LineStart = position.LineStart
- p.CharStart = position.CharStart
-}
-
-func (p *Position) MergeStartIntoEnd(position Position) {
- p.LineEnd = position.LineStart
- p.CharEnd = position.CharStart
-}
-
-func (p *Position) MergeEndIntoEnd(position Position) {
- p.LineEnd = position.LineEnd
- p.CharEnd = position.CharEnd
-}
-
-func (p *Position) IsBefore(another Position) bool {
- return p.LineEnd < another.LineStart ||
- p.LineEnd == another.LineStart && p.CharEnd < another.CharStart
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/runes/runes.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/runes/runes.go
deleted file mode 100644
index af1fe2fe169..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/runes/runes.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Package runes contains all possible 'special' runes in a GraphQL document
-package runes
-
-const (
- EOF = 0
- COLON = ':'
- BANG = '!'
- CARRIAGERETURN = '\r'
- LINETERMINATOR = '\n'
- TAB = '\t'
- SPACE = ' '
- COMMA = ','
- HASHTAG = '#'
- QUOTE = '"'
- BACKSLASH = '\\'
- DOT = '.'
- EXPONENT_LOWER = 'e'
- EXPONENT_UPPER = 'E'
- AT = '@'
- DOLLAR = '$'
- PIPE = '|'
- SLASH = '/'
- EQUALS = '='
- SUB = '-'
- ADD = '+'
- AND = '&'
- UNDERSCORE = '_'
-
- LPAREN = '('
- RPAREN = ')'
- LBRACK = '['
- RBRACK = ']'
- LBRACE = '{'
- RBRACE = '}'
-)
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/token/token.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/token/token.go
deleted file mode 100644
index ff3b3952557..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/lexer/token/token.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Package token contains the object and logic needed to describe a lexed token in a GraphQL document
-package token
-
-import (
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/keyword"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/position"
-)
-
-type Token struct {
- Keyword keyword.Keyword
- Literal ast.ByteSliceReference
- TextPosition position.Position
-}
-
-func (t Token) String() string {
- return fmt.Sprintf("token:: Keyword: %s, Pos: %s", t.Keyword, t.TextPosition)
-}
-
-func (t *Token) SetStart(inputPosition int, textPosition position.Position) {
- t.Literal.Start = uint32(inputPosition)
- t.TextPosition.LineStart = textPosition.LineStart
- t.TextPosition.CharStart = textPosition.CharStart
-}
-
-func (t *Token) SetEnd(inputPosition int, textPosition position.Position) {
- t.Literal.End = uint32(inputPosition)
- t.TextPosition.LineEnd = textPosition.LineStart
- t.TextPosition.CharEnd = textPosition.CharStart
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/middleware/operation_complexity/operation_complexity.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/middleware/operation_complexity/operation_complexity.go
deleted file mode 100644
index d6b93059f91..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/middleware/operation_complexity/operation_complexity.go
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- package operation_complexity implements two common algorithms used by GitHub to calculate GraphQL query complexity
-
- 1. Node count, the maximum number of Nodes a query may return
- 2. Complexity, the maximum number of Node requests that might be needed to execute the query
-
- OperationComplexityEstimator takes a schema definition and a query and then walks recursively through the query to calculate both variables.
-
- The calculation can be influenced by integer arguments on fields that indicate the amount of Nodes returned by a field.
-
- To help the algorithm understand your schema you could make use of these two directives:
-
- - directive @nodeCountMultiply on ARGUMENT_DEFINITION
- - directive @nodeCountSkip on FIELD
-
- nodeCountMultiply:
- Indicates that the Int value the directive is applied on should be used as a Node multiplier
-
- nodeCountSkip:
- Indicates that the algorithm should skip this Node. This is useful to whitelist certain query paths, e.g. for introspection.
-*/
-package operation_complexity
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/astvisitor"
- "github.com/jensneuse/graphql-go-tools/pkg/operationreport"
-)
-
-type OperationStats struct {
- NodeCount int
- Complexity int
- Depth int
-}
-
-type RootFieldStats struct {
- TypeName string
- FieldName string
- Alias string
- Stats OperationStats
-}
-
-var (
- nodeCountMultiply = []byte("nodeCountMultiply")
- nodeCountSkip = []byte("nodeCountSkip")
-)
-
-type OperationComplexityEstimator struct {
- walker *astvisitor.Walker
- visitor *complexityVisitor
-}
-
-func NewOperationComplexityEstimator() *OperationComplexityEstimator {
-
- walker := astvisitor.NewWalker(48)
- visitor := &complexityVisitor{
- Walker: &walker,
- multipliers: make([]multiplier, 0, 16),
- }
-
- walker.RegisterEnterDocumentVisitor(visitor)
- walker.RegisterEnterArgumentVisitor(visitor)
- walker.RegisterLeaveFieldVisitor(visitor)
- walker.RegisterEnterFieldVisitor(visitor)
- walker.RegisterEnterSelectionSetVisitor(visitor)
- walker.RegisterEnterFragmentDefinitionVisitor(visitor)
-
- return &OperationComplexityEstimator{
- walker: &walker,
- visitor: visitor,
- }
-}
-
-func (n *OperationComplexityEstimator) Do(operation, definition *ast.Document, report *operationreport.Report) (OperationStats, []RootFieldStats) {
- n.visitor.count = 0
- n.visitor.complexity = 0
- n.visitor.maxFieldDepth = 0
- n.visitor.multipliers = n.visitor.multipliers[:0]
-
- n.visitor.maxSelectionSetFieldDepth = 0
- n.visitor.selectionSetDepth = 0
-
- if n.visitor.calculatedRootFieldStats == nil {
- n.visitor.calculatedRootFieldStats = make([]RootFieldStats, 0, len(definition.RootOperationTypeDefinitions))
- }
- n.visitor.calculatedRootFieldStats = n.visitor.calculatedRootFieldStats[:0]
-
- if n.visitor.rootOperationTypeNames == nil {
- n.visitor.rootOperationTypeNames = make(map[string]struct{}, len(definition.RootOperationTypeDefinitions))
- }
- for key := range n.visitor.rootOperationTypeNames {
- delete(n.visitor.rootOperationTypeNames, key)
- }
-
- n.walker.Walk(operation, definition, report)
-
- depth := n.visitor.maxFieldDepth - n.visitor.selectionSetDepth
- globalResult := OperationStats{
- NodeCount: n.visitor.count,
- Complexity: n.visitor.complexity,
- Depth: depth,
- }
-
- return globalResult, n.visitor.calculatedRootFieldStats
-}
-
-func CalculateOperationComplexity(operation, definition *ast.Document, report *operationreport.Report) (OperationStats, []RootFieldStats) {
- estimator := NewOperationComplexityEstimator()
- return estimator.Do(operation, definition, report)
-}
-
-type complexityVisitor struct {
- *astvisitor.Walker
- operation, definition *ast.Document
- count int
- complexity int
- maxFieldDepth int
- multipliers []multiplier
-
- maxSelectionSetFieldDepth int
- selectionSetDepth int
-
- rootOperationTypeNames map[string]struct{}
-
- currentRootFieldStats RootFieldStats
- currentRootFieldMaxDepth int
- currentRootFieldMaxSelectionSetDepth int
- currentRootFieldSelectionSetDepth int
-
- calculatedRootFieldStats []RootFieldStats
-}
-
-type multiplier struct {
- fieldRef int
- multi int
-}
-
-func (c *complexityVisitor) calculateMultiplied(i int) int {
- for _, j := range c.multipliers {
- i = i * j.multi
- }
- return i
-}
-
-func (c *complexityVisitor) EnterDocument(operation, definition *ast.Document) {
- c.operation = operation
- c.definition = definition
-
- for i := 0; i < len(c.definition.RootOperationTypeDefinitions); i++ {
- name := c.definition.Input.ByteSliceString(c.definition.RootOperationTypeDefinitions[i].NamedType.Name)
- c.rootOperationTypeNames[name] = struct{}{}
- }
-}
-
-func (c *complexityVisitor) EnterArgument(ref int) {
-
- if c.Ancestors[len(c.Ancestors)-1].Kind != ast.NodeKindField {
- return
- }
-
- definition, ok := c.ArgumentInputValueDefinition(ref)
- if !ok {
- return
- }
-
- if !c.definition.InputValueDefinitionHasDirective(definition, nodeCountMultiply) {
- return
- }
-
- value := c.operation.ArgumentValue(ref)
- if value.Kind == ast.ValueKindInteger {
- multi := c.operation.IntValueAsInt(value.Ref)
- c.multipliers = append(c.multipliers, multiplier{
- fieldRef: c.Ancestors[len(c.Ancestors)-1].Ref,
- multi: int(multi),
- })
- }
-}
-
-func (c *complexityVisitor) EnterField(ref int) {
- definition, exists := c.FieldDefinition(ref)
- if !exists {
- return
- }
-
- if _, exits := c.definition.FieldDefinitionDirectiveByName(definition, nodeCountSkip); exits {
- c.SkipNode()
- return
- }
-
- typeName, fieldName, alias := c.extractFieldRelatedNames(ref, definition)
- if c.isRootType(typeName) {
- c.resetCurrentRootFieldComplexity(typeName, fieldName, alias)
- }
-
- if !c.operation.FieldHasSelections(ref) {
- return
- }
-
- c.complexity = c.complexity + c.calculateMultiplied(1)
- if c.Depth > c.maxFieldDepth {
- c.maxFieldDepth = c.Depth
- }
-
- c.currentRootFieldStats.Stats.Complexity = c.currentRootFieldStats.Stats.Complexity + c.calculateMultiplied(1)
- if c.Depth > c.currentRootFieldMaxDepth {
- c.currentRootFieldMaxDepth = c.Depth
- }
-}
-
-func (c *complexityVisitor) LeaveField(ref int) {
- if c.isRootTypeField() {
- c.endRootFieldComplexityCalculation()
- }
-
- if len(c.multipliers) == 0 {
- return
- }
-
- if c.multipliers[len(c.multipliers)-1].fieldRef == ref {
- c.multipliers = c.multipliers[:len(c.multipliers)-1]
- }
-}
-
-func (c *complexityVisitor) EnterSelectionSet(ref int) {
-
- if c.Ancestors[len(c.Ancestors)-1].Kind != ast.NodeKindField {
- return
- }
-
- c.count = c.count + c.calculateMultiplied(1)
- if c.Depth > c.maxSelectionSetFieldDepth {
- c.maxSelectionSetFieldDepth = c.Depth
- c.selectionSetDepth++
- }
-
- c.currentRootFieldStats.Stats.NodeCount = c.currentRootFieldStats.Stats.NodeCount + c.calculateMultiplied(1)
- if c.Depth > c.currentRootFieldMaxSelectionSetDepth {
- c.currentRootFieldMaxSelectionSetDepth = c.Depth
- c.currentRootFieldSelectionSetDepth++
- }
-}
-
-func (c *complexityVisitor) EnterFragmentDefinition(ref int) {
- c.SkipNode()
-}
-
-func (c *complexityVisitor) resetCurrentRootFieldComplexity(typeName, fieldName, alias string) {
- c.currentRootFieldStats = RootFieldStats{
- TypeName: typeName,
- FieldName: fieldName,
- Alias: alias,
- Stats: OperationStats{
- NodeCount: 0,
- Complexity: 0,
- Depth: 0,
- },
- }
-}
-
-func (c *complexityVisitor) endRootFieldComplexityCalculation() {
- currentDepth := c.currentRootFieldMaxDepth - c.currentRootFieldSelectionSetDepth
- if currentDepth > 0 {
- currentDepth--
- }
- c.currentRootFieldStats.Stats.Depth = currentDepth
- c.calculatedRootFieldStats = append(c.calculatedRootFieldStats, c.currentRootFieldStats)
-
- c.currentRootFieldMaxDepth = 0
- c.currentRootFieldMaxSelectionSetDepth = 0
- c.currentRootFieldSelectionSetDepth = 0
-}
-
-func (c *complexityVisitor) extractFieldRelatedNames(ref, definitionRef int) (typeName, fieldName, alias string) {
- fieldName = c.definition.FieldDefinitionNameString(definitionRef)
- alias = c.operation.FieldAliasOrNameString(ref)
- if fieldName == alias {
- alias = ""
- }
-
- return c.EnclosingTypeDefinition.NameString(c.definition), fieldName, alias
-}
-
-func (c *complexityVisitor) isRootType(name string) bool {
- _, ok := c.rootOperationTypeNames[name]
- return ok
-}
-
-func (c *complexityVisitor) isRootTypeField() bool {
- enclosingTypeName := c.EnclosingTypeDefinition.NameString(c.definition)
- return c.isRootType(enclosingTypeName)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/operationreport/externalerror.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/operationreport/externalerror.go
deleted file mode 100644
index 51067452e54..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/operationreport/externalerror.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package operationreport
-
-import (
- "fmt"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
-)
-
-type ExternalError struct {
- Message string `json:"message"`
- Path ast.Path `json:"path"`
- Locations []Location `json:"locations"`
-}
-
-type Location struct {
- Line uint32 `json:"line"`
- Column uint32 `json:"column"`
-}
-
-func ErrDocumentDoesntContainExecutableOperation() (err ExternalError) {
- err.Message = "document doesn't contain any executable operation"
- return
-}
-
-func ErrFieldUndefinedOnType(fieldName, typeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("field: %s not defined on type: %s", fieldName, typeName)
- return err
-}
-
-func ErrFieldNameMustBeUniqueOnType(fieldName, typeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("field '%s.%s' can only be defined once", typeName, fieldName)
- return err
-}
-
-func ErrTypeUndefined(typeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("type not defined: %s", typeName)
- return err
-}
-
-func ErrTypeNameMustBeUnique(typeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("there can be only one type named '%s'", typeName)
- return err
-}
-
-func ErrOperationNameMustBeUnique(operationName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("operation name must be unique: %s", operationName)
- return err
-}
-
-func ErrAnonymousOperationMustBeTheOnlyOperationInDocument() (err ExternalError) {
- err.Message = "anonymous operation name the only operation in a graphql document"
- return err
-}
-
-func ErrRequiredOperationNameIsMissing() (err ExternalError) {
- err.Message = "operation name is required when providing multiple operations"
- return err
-}
-
-func ErrOperationWithProvidedOperationNameNotFound(operationName string) (err ExternalError) {
- err.Message = fmt.Sprintf("cannot find an operation with name: %s", operationName)
- return err
-}
-
-func ErrSubscriptionMustOnlyHaveOneRootSelection(subscriptionName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("subscription: %s must only have one root selection", subscriptionName)
- return err
-}
-
-func ErrFieldSelectionOnUnion(fieldName, unionName ast.ByteSlice) (err ExternalError) {
-
- err.Message = fmt.Sprintf("cannot select field: %s on union: %s", fieldName, unionName)
- return err
-}
-
-func ErrFieldsConflict(objectName, leftType, rightType ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("fields '%s' conflict because they return conflicting types '%s' and '%s'", objectName, leftType, rightType)
- return err
-}
-
-func ErrTypesForFieldMismatch(objectName, leftType, rightType ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("differing types '%s' and '%s' for objectName '%s'", leftType, rightType, objectName)
- return err
-}
-
-func ErrResponseOfDifferingTypesMustBeOfSameShape(leftObjectName, rightObjectName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("objects '%s' and '%s' on differing response types must be of same response shape", leftObjectName, rightObjectName)
- return err
-}
-
-func ErrDifferingFieldsOnPotentiallySameType(objectName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("differing fields for objectName '%s' on (potentially) same type", objectName)
- return err
-}
-
-func ErrFieldSelectionOnScalar(fieldName, scalarTypeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("cannot select field: %s on scalar %s", fieldName, scalarTypeName)
- return err
-}
-
-func ErrMissingFieldSelectionOnNonScalar(fieldName, enclosingTypeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("non scalar field: %s on type: %s must have selections", fieldName, enclosingTypeName)
- return err
-}
-
-func ErrArgumentNotDefinedOnNode(argName, node ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("argument: %s not defined on node: %s", argName, node)
- return err
-}
-
-func ErrValueDoesntSatisfyInputValueDefinition(value, inputType ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("value: %s doesn't satisfy inputType: %s", value, inputType)
- return err
-}
-
-func ErrVariableNotDefinedOnOperation(variableName, operationName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("variable: %s not defined on operation: %s", variableName, operationName)
- return err
-}
-
-func ErrVariableDefinedButNeverUsed(variableName, operationName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("variable: %s defined on operation: %s but never used", variableName, operationName)
- return err
-}
-
-func ErrVariableMustBeUnique(variableName, operationName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("variable: %s must be unique per operation: %s", variableName, operationName)
- return err
-}
-
-func ErrVariableNotDefinedOnArgument(variableName, argumentName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("variable: %s not defined on argument: %s", variableName, argumentName)
- return err
-}
-
-func ErrVariableOfTypeIsNoValidInputValue(variableName, ofTypeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("variable: %s of type: %s is no valid input value type", variableName, ofTypeName)
- return err
-}
-
-func ErrArgumentMustBeUnique(argName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("argument: %s must be unique", argName)
- return err
-}
-
-func ErrArgumentRequiredOnField(argName, fieldName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("argument: %s is required on field: %s but missing", argName, fieldName)
- return err
-}
-
-func ErrArgumentOnFieldMustNotBeNull(argName, fieldName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("argument: %s on field: %s must not be null", argName, fieldName)
- return err
-}
-
-func ErrFragmentSpreadFormsCycle(spreadName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("fragment spread: %s forms fragment cycle", spreadName)
- return err
-}
-
-func ErrFragmentDefinedButNotUsed(fragmentName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("fragment: %s defined but not used", fragmentName)
- return err
-}
-
-func ErrFragmentUndefined(fragmentName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("fragment: %s undefined", fragmentName)
- return err
-}
-
-func ErrInlineFragmentOnTypeDisallowed(onTypeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("inline fragment on type: %s disallowed", onTypeName)
- return err
-}
-
-func ErrInlineFragmentOnTypeMismatchEnclosingType(fragmentTypeName, enclosingTypeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("inline fragment on type: %s mismatches enclosing type: %s", fragmentTypeName, enclosingTypeName)
- return err
-}
-
-func ErrFragmentDefinitionOnTypeDisallowed(fragmentName, onTypeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("fragment: %s on type: %s disallowed", fragmentName, onTypeName)
- return err
-}
-
-func ErrFragmentDefinitionMustBeUnique(fragmentName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("fragment: %s must be unique per document", fragmentName)
- return err
-}
-
-func ErrDirectiveUndefined(directiveName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("directive: %s undefined", directiveName)
- return err
-}
-
-func ErrDirectiveNotAllowedOnNode(directiveName, nodeKindName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("directive: %s not allowed on node of kind: %s", directiveName, nodeKindName)
- return err
-}
-
-func ErrDirectiveMustBeUniquePerLocation(directiveName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("directive: %s must be unique per location", directiveName)
- return err
-}
-
-func ErrOnlyOneQueryTypeAllowed() (err ExternalError) {
- err.Message = "there can be only one query type in schema"
- return err
-}
-
-func ErrOnlyOneMutationTypeAllowed() (err ExternalError) {
- err.Message = "there can be only one mutation type in schema"
- return err
-}
-
-func ErrOnlyOneSubscriptionTypeAllowed() (err ExternalError) {
- err.Message = "there can be only one subscription type in schema"
- return err
-}
-
-func ErrEnumValueNameMustBeUnique(enumName, enumValueName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("enum value '%s.%s' can only be defined once", enumName, enumValueName)
- return err
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/operationreport/operationreport.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/operationreport/operationreport.go
deleted file mode 100644
index 1def29742a4..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/operationreport/operationreport.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// Package operationreport helps generating the errors object for a GraphQL Operation.
-package operationreport
-
-import "fmt"
-
-type Report struct {
- InternalErrors []error
- ExternalErrors []ExternalError
-}
-
-func (r Report) Error() string {
- out := ""
- for i := range r.InternalErrors {
- if i != 0 {
- out += "\n"
- }
- out += fmt.Sprintf("internal: %s", r.InternalErrors[i].Error())
- }
- for i := range r.ExternalErrors {
- if i != 0 {
- out += "\n"
- }
- out += fmt.Sprintf("external: %s, locations: %+v, path: %v", r.ExternalErrors[i].Message, r.ExternalErrors[i].Locations, r.ExternalErrors[i].Path)
- }
- return out
-}
-
-func (r *Report) HasErrors() bool {
- return len(r.InternalErrors) > 0 || len(r.ExternalErrors) > 0
-}
-
-func (r *Report) Reset() {
- r.InternalErrors = r.InternalErrors[:0]
- r.ExternalErrors = r.ExternalErrors[:0]
-}
-
-func (r *Report) AddInternalError(err error) {
- r.InternalErrors = append(r.InternalErrors, err)
-}
-
-func (r *Report) AddExternalError(gqlError ExternalError) {
- r.ExternalErrors = append(r.ExternalErrors, gqlError)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/playground/a_playground-packr.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/playground/a_playground-packr.go
deleted file mode 100644
index c4b7607fe72..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/playground/a_playground-packr.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Code generated by github.com/gobuffalo/packr. DO NOT EDIT.
-
-package playground
-
-import "github.com/gobuffalo/packr"
-
-// You can use the "packr clean" command to clean up this,
-// and any other packr generated files.
-func init() {
- _ = packr.PackJSONBytes("./files", "favicon.png", "\"iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAATiElEQVR42t2be4xc1X3Hz6x3jTEhEMIfKYQmRDTiGapAVNQqStOojcCoiioaJVVCqpSoQlFCotixsb3embvrdQwBY5MSMBCcQIDgACmPAqEmQPEj8TN+rPcxc8+d9/u9855Z9/s799x7Z3x35l6opUas/NWZe+d1P9/f75zzO+eOWZr9iJ1iB9nj7BuenezfhursPhxvZ1ewj7D3y9/lYCGmBtiIkVjBLNjZ59hl7Gw24jmXLRvC42Evu+nicXbzx8bYTaa8UmNG+551o/M5HEO24/eiDV1S2Ao6dzExnsvOGiJmYmdPwA2YNPQ99vkPz7ANL6jMWwwwbxrKSGX/BJQ7A8qCrUSMxErMgv137LvDp5Agf2CrVgWZckpjvsPQMY0px0lc1wmpqS6d7NK0pmvGkm9Was4QZz6/VECXoqI1xEl4r4bXkoK6FGpDUmFdSpijhSK6lKguHylGwmvieC0poUshxYgRrCvBLNjZs+y2EWnANjxZxJvfhvaTVF0HpA5KHerSYa7riNQfcSEQtd6jUsc4DMVrjyMCpBN4bGgKxySY6CNN4/VSvhmpWRyT5rg0URXyUhuQUnV5uSqMVCCfhveQgngMKSGO94BxAaxbwSzY2S/YrUvpYC/7ARlQwYt3Q4e4hOVCdlAVohbuHiXhC45pEAcoB6gGcUAKSVBuglqwOG+Cajpod9b46aJxXmYMpIMaGWOCqiQClRmDc1BPxkRwjlMGgPU+MAt2toN93TDg/m4D7PCWARa8IuGpVUSkBbiENyTgITu8z4x0L7wioq0BnpPs8JAiDDDguR3e6jI6PHUPGDBOBlAGELvNgCouao+Et0VfJVGKQxpkRP7Mwkvp4D3wXEae4NXF4dF6CRxSwpABH0ErDVAGGTAuDNCBFUi0JIInGfAAl5EHuHt4r4SX4IvDG1F3EXmfLfImvBwkNRNeidLrYYBjBuwl8NMjT+CnwR/rB0+DG3eGn9WGFJIA5xLeHnmv2effCzyX8GhjlC1uMmCv0dcteGvAQyv6u2PkAW2JwC14Hdw3q7L1MyTNA/ghxRZ5Ad4Lr3XDQ93wYQteRP10eMgXdDKghhft6xnsrAGvB57ET4cHuISH+sB7FB18aHQ2euUDWvTaB4N8qXdOZWvn8FygG149Q/Ac8GjjugHjzgYQsD3teyNvwdv7+2D4dTORa37C6wei1YXOgvhrzmQa8c8/FsFzc3xo3ADvA6+8a3gV8DgmA0JuMuD3EIGTFkv741pfeHvkuQlPBc3YbPC8SX9TzTVO4Y8MINHjdqHWDv/F1qDKRgN8yJzjbfCagPda8NZID9nTnlqCR5vAsaMBdTKAgBeBh7xGn+/p7/36PO8e8IaVuQBbM525/aWEgG+0F8w/PKZzhc3v5PxstZ8Pj/fCnzbN4XyfyAtwC15GXm+9ZEDYjQF/IHBb5K3qzk3a98zxZEBw2aTfz1ZN57yvp4QBrY7JT4/pXGnHgeIcW+nXlk1SP+9X3dki7wYebVLF+5zGgDqHAQRsVXcS3l2BY4dfosxBFP0ZPuKbKz95rCgMaHco/XW1dQOqb6gV7bxNGrJA5UOI/pLxQZEH+CLwkIC20j6htwoZEHHMAFoEua3uVAPeI6o6c7AjYZoD/DiN7jTVzaa//ny8FSs1RX/P17ryXx8DOkWcgxE0FmTueCWjDo9pAbaW4zNCmCJNeLQ6vAcC9AB4yILHuRSOXRlwgLuFH1Km+RIF4GMi8ogYwBUCn+We0ZkAWz0du+HRUH1fuCogy41O5tsvJ6uv++fpuMnzzSbPNcUwcCxRT33zN6lWvNyi5xonUo3EF59IInM01bM+pC2ZCGMWieCzKe2FtKHxKGYNSnlb5HvhfSQyIOpkQIMMgI47wnvGpwOe9VN+tmZKWz45y5eOA3jNSR38h9Ohi34cKP/yaAHhFVEu/+KPRe2c8UDsC4+ECXD+uakyjFMDbFQt3LM7T+dStz2bCrB1vLhlX3Gh3hKZUXlpphL55P0xmBning1hfEeYD/uiwXM2xfDaCBTlHkxxdvhkNzyyJU2Z4rQYggHegwNKWwuerZsKX7ktUPmv2VIrUW62wsVmcdu+bOjCuwK5dbtSiHabAGq7g5XY9dtDAJhVl476GyfTDTIkfMU2nFuvwgSuXTAZbCfKrQ7SP/hnm0J+tpITdOXFmYoxYxTu2VMMXrA5hs8uYBpt4fXt6pu8Hr1hexrXEsM1Idr2yGuAJ3HdgBgYnQ2ATtjW8mZ/p5QfPRm65J45o08bczmBoS8L8Fao0Ex95ddxqvDU4Q3+ALvTn131apqey29+m6a7AB+e0DDliUEv/e//KZ4r/sfviyq7M8hHxkIBtIm/fzzVOJFsyFqhYwyY5tgx3+hEPv1gGmbG0SVF5O3wShrKOBmwTRpwaFBpiwue9rMfThXu3p2hC0CqduRobs7npUcPFfjwGKDXYP6foLI2ELzoLq1TrLdhWks7f6NGkcfgaU5zMDVY3x+p0/uj1z0Qx3FIG5mIwIwQBtFw3vemPns02wvmDCK7SfmpY1U/uzOOMWhReA3CuQx44i4M8B0i4H5zPAa9GXzZFPpmSU5ntvk8/Z0XEgG2ahbzuQrDVBg2V9y+v6D38+dTFH1crFnX00gPUC3+hccSot+/NldF5tDoH9HOmogiE8LxG3ekbd8nM69+MNqEoQnAyv7uBbgJDwFeV8LJgCbt8w0qbQFEo/vJ0kMHcrJ/milJ0RGQX94ZD9DiZumEitYf/asHI2I82BuqUb9H5G3VHUygAS5YfvqomCGStzyVpgFPG9kYRQZEop95OLWAbzEMMLJBGPbyTB3jQAIzQl94tFmXBngP095dv+oOUw8taKaj1z2odWrNjoS3onEkXuPDCq3jA+iTZECguisgBrPY3z4awzHHhdoLHA/t220IhS/bEqNMas6km/wsmt+hISVGo33lpena6VlAx/EVv8zjcxMouAbAK5Av6caAI46l7ZAiCpzEiici3Qub2pu8EvrEvRoi5ucjExxTZCD51WdEWpefOFKiwQ6pbyttzQJneDyCKTSUV34nukt2zW8LeE8EnxVHise0D00m5neeqC609MijZminbn2uoBK8R8Ab4BDAe+Fz4HA2QG6ATPcrbTlJ7OaMi/I2eMFkgLpBbXeo6ke/V5dsCGCm0Je0yxXeDOSaNFjBmDAGNg3T1YDSVtb2H5iItoL5Fo3wwUvuxpS2IYasiasjvvgc+360/PMjorAKX35/Bt9JkU9T5A14K/KKCU8CWwp1wEADWrQUdrFra+7dBT8wqVJXqL3FK0hDRH6cI8qcBrrchl1ZutDc2K4cRR8zQsgOT7KWs6j4ojA2kvzazqw+oxycRybF8JkJfHYCj+Olhw9UhAGf2ArQDSlkpBl5AQ7xXnhSngwwtsUHGOCFAd4Zx11bDxkwBgM2wYBWp/a2VsVoLZayiJgauvTe0ALOo4s0+fJxcxNj8K6t3MTw6H2++hbXp8W/3p6BuXG+dGNSGPDIQZEBkUu3ZpFVMGDcgl888nkckwFpNwYcdbNrCwMCZIB2ziQXBrwlDAjgIjVcpFp+/HBJjOb/8kwK52lR47hry0XrRborcaruAC6mPjICswcyQBiQKD2sGxC+dBsZkEYGANq7aORViODxuAA2dwZQH18Mnnft2tL+HQamQK8B61Sa5mKfeyQml7dVzBgaXtsPfrHtKxKKmokEpX7pET3dk1/7dYGmOtQLyS4DcroBos8D2h55Ca8bAIOcDGirtArsc5tKwkOKGOjsBqzFuVFe2xOqidS94aEYGWAsZ512ba3VHORRADuaCF7y4xQNhi0t3w6evzGFWSKJLiAN2ArI9ZQBNnjIhFcBj7boygC6mWmO9ARuu0Uld249PjJAhQGaMOCdUG2W3eFPfet5kbal7ftLKJg4FThO8Lx3787cyEAWiJTPrn5NdKf8xJvzc+y7ifLPDtcsA0YzGAOsqU5IMeALhnCODMi6MeA4J2h72kOKeYsKBnAVrfbBHwVpPUDpjvTXaD3fKdU7oYvvEoUN0t/lrq0FL5XkxnL2LG+qOZ1uUeGjnT+ZwYJJHwQvux+QGzL4Dhl1yA5fJHicK/F3bQDAoZ7IEzQJKUoGcHX5GF9oYsp+8eR8du3rYurCqi+LVNUw7QHa7a6tBa92r+hQ3VG/T/7TU6I4Kv5kX7Ww5R0xLoQ+fjdlQBbrE7R2eJKEh3wlKOdogNz09NvSXkZeFS3gkQHU55O3PJNc6KB01fJNijx2dhp8qdyy9ujwUlFkghV52w6OFMCtRY1QmqY5jCVpqvmpDG5MpcSuUeb2l+cxBmRVj1fAq4tFHtIAD5VdGDDekctgK/JS3TcnIQ3pzks79KluoWOtBAv3vlOQ0Y90w/P3Co8CB5+VwXiSSn/7hbLcUTbXHpVX5pp8qZjj+8NDeEwG5J0yoEObIX1+kECiKk/M86lvPNe7vS0vqFNtdsKf3Baj5SwfGougj0JjERRHUamYrrE4WkMJXWNJtEmq7nSNpbhnLC1G+g9uzLbChba1GLL2H3Kjb1RxTXlcmwWPthfevQFTA29LL1GEAfM7j88bBlDbvTqj7Sra7KStq2agn7L95TfVxrFQK1psi8/HP2oNI+Qyu4WxoIBxqQeeS3hNh5+HCi4M8E0J8D4/SIABQRjAsSrrMaD7Vhf2B1uNw/FGK1hokWCEG7V7FIB4vo2ttXbjWLKFvcS2kfrSb8uAPaFWQBpAo30vPAR4lwaML9Cm58AfJGA5i9JWS9/6XNrcomoSNSQvCJFrJlY8maFFDUmO+Gbay3Q3lORm2o+R0rq8GdUzSqu9dPjj9+Wrr841zPRvQc221QXW76phl6qAmsOAL3fDk3BcocxwygAY4KU9AO70gwT0y2B5x+Fydyp2Ko0O9ucq7Wy1LUvhWuSan6aQMVHVM0Z7dtaA51GSOE5pJI+SNgY8HGdQ2pJ5ae3cyWzxvn1V0a0ylU5hy94atd3fiV1pDIK9aa/ZIk/w7g2YdronT+IeL5kQStz8ZLq4dV8pv+l/itFPP5TE/l849OdbEuWnj1WMCy3+dP988MLNeG41dm5R2AxvTOoD3ppkAKLI00hP8Bg801TdZb71YrmdqwpY1P714Ic35/HZufBl24q59W/UClv31ZP/vLOCO0iAH+sLr1nwVXCUnA0Qy2BFG/CDBKuuH1LEri2mPWh1GIbQej6G1I1S1GN/87NMfX9U39LOVjqZ77xSVIe9ZFIidOHmdOqWZ4qprz5bDH/03iyMSEHp+GcfK1Cfp/dgid2MXP1AEcZlkUF5lMYFGuxoxIcKqEOK3EPQdnhNwmsS3q0Bp2gp7OYHCVy0XgArUUSPRMtY6uvU0mpOLGlx9yie+tffFLAdLrpF/VCsmV35Wsk4Nvb2s99/dR53kurynkI7+aWnywDMod7IETi6DOC9+kA3PEEqdfd5Cd7b5yW8VA08ZRcGeGcAGvy//iBBX9IqCaS82MTQzt2Ywv3/+YVGy5o22x1dC2YNsZBb90ZFXerNYVDLYhssD8kix17aaqeN9La0tyJfw7FrA2adfpCgub8nD9FgN5HC/bzkHLsjnlv732U5exjg5nZ64b69VawoM3xEoXSXuzgDqzt75O1pXyV4qK7ieTddYO4M/SBB3pOXpe3IOO0MJXNrd/XUD8A3H2OdX6e0xy6wU11vjzzJFnmAm/K5M0CuBENn4gcJ3Xdq5IImFf+7nxcMA6TM+RxjxTxSPydLWpKttHWf9ha4VAPXWnEqhMgAf99dW3c/SEj2wEPmfr1HydCqDpE2b3BAclEz28Cq7rTI20pbGzxUcYSHcM40YM+gDJBL4PDAXVvnHyTY4EWr36DM4D5/Jn3bC/PV1/yN6i61mf3Bbyt8mQ/wXgGvkiz4vqUtwXOX8Byi5wcZsFUaEOAOu7Z94JP94Akcn2PerEAmZDEe0FY32nU5SnvsL/SB71/aau8CHu9pujTAFyDwQbu2OO4bec0OT3W9bdcW/TxnTHO4l1DoA+9U2lYH93kLXhpQczBAjAGqq11bQEv1uydvpjxayHHX1j7HI/IDStsBkVcM+KYFr7TIADddQKWUd9i1dQUP2SKvkhz27tyXtha8aoeXaS/hIXrejQHc7a6tak1zTrelIaddWwnvvrSFeiOvSniC7obXdPh2lwFbbAbskQbIlWDMnvaAllLt8Om+8BJcddiyHlDaVvqUtk7wLQkPAV5Xw2bA4/I/Te1jK41KUIWigIfQwgy0kJ4JUtIMrznqW/KmhSHSCLwvi9cbyknlpXoKHqmSVFlqvksVVVdVqiZVJxFgl5pSLcjKAKsQEuzsV+ybI3TwNvvenSF9EEzIzYmMJV9Wl0LKkYIAQJsP6irgmFTEOVJJSPZjqXnI7MtSVVIQkdQs1fEaSGl0qdmlllSbxPW2Q6LlvGbplNlaj1vECNY1YBbs7Hb2WQ9jbOkX2RUfO8rWvuJn3vIcG8tBeQcVjPb/WUWXKoBtnhiJlZgF+xLmYUPMM4z27PPY2R+6iV31l//Irrl+BbvqMyvY1Q66ypDzsaXrz5RuMltn3cyuvv5GduW1xEiskpmxf2CXM/q7hl00fC27+Gw8XIbTy9Ge836SZFr2KTASK2OSHU6wj7LzhQlXso94vsKuW/Il9qklyIL3lYiJ2IgRqMQs2P8Xy1UFKvk8fQAAAAAASUVORK5CYII=\"")
- _ = packr.PackJSONBytes("./files", "logo.png", "\"iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAB88klEQVR42uycXYhd13XHz4ykWDOSrI/KdkOp8xAnENIvpym4UKgbCoE+lD60JQ30paFQCEnTPiQxsax9tk0DhfShD8VN++SWQKCkgUBf0vYhLwVblq0PW5qvc86MNNFXIkuRHdfSzKhrnbPX/M9d65yz770j3euoZ8iftfc+utcT2b/1sfc+K+l/+p/+p//Zyc9Mr169pqNpAj/boF29evW637LsgcsJQK9g313Tnl69et1vgTlwaJ3BvYYf0AP2DwQ9VNNepblevXqNKcsTWAN/e5QzuDdOIAL+Q7PJzN79yUPzR5J9+36OdCSZ3086cLjU3IFDlR5m26tXr1EEdpglZupIpf0layRmjxlkFiOOYAfwW/D3ziQzcx9LHjvw8eSDB2l+gDRP2he0v6YDvXr12rHAFDhj5koGmUVmktm0jgBOYHz4kebPHU327f/F5NDBsJ58Mnn80F8kv/WhLye/+8RfJ5964q+S3/nIX5Z6+iNfJH0hefqjX0h+u1evXiOK2WGGmCVmitlixpg1Zo7ZC7zuZiaZTWYUGYFyAjuFn1OSJ5JHDvCz/06++PT55Ng/rSTuddIV0o+Drvfq1es+CZxdYfaYQWaRmWQ2mdGdOoGZBvjnqe7gL9739eT3D59Lnv1mnqSbRZLeJbvFtlevXpMU2GMWmUlmkxkNrM43OIGZUaL/HoF/X/IBjvoPP5N8+shScvz74R96h3Q7T/wG2a1KvlT4xWBlLMKfV5/x4Xl9zX6HlYfMP9fXxy2/i/19CvxZJVmPyUOR5xHZvyfzu1rl9b/H5ufqu2S9Jvz70M8if1d+TMX/rooxvgf/H6Bc2Tblzf8dq8+l+rut4v+9KBv9e94M7N1mFplJZpMZZVZLZuEE9gyXBdjUf25XMrP/g8nDR/hLFpJjL+YV/O8Vid+UXwbOYHQVyt5D3Xl/yo/1uUJZ/p5iGr/T9LXRIfx98bxD+K6faYmj32QmmU1mlFllZpldZliXAsNG/72kfY8nhw/x+AfJlz4V/oEb4R94l/QOabFI0tdJr1Vypc0H9XqeeFLaIX8qq8ZkK9GaGnuxSqnoNM1P5yS2PJc10hkak3yHUtFZEX1XqWJ7nIa5fwNKS6vX8kpv0jworcmVyiudYxXKKp2n7yL5oLQUr9PvSXKiBRY9W8C4slC6SN9BShczsjQPcnUtVUqDtaLPL2cktkXig2TuSGLdSpPkGf15Fs3TjL5jBUqD+M+4TERrwfI8ra/n+ba8qLbmcvp9CxaNyTqyKVuldFVEny+VBeGZWyOr5GDx/AKLvqNUAYV5SnIXyTbIbYt+z3UWfU7E82sCPjMpToFZZWYDu/t4HM0C4AAQ/WfJg3w4OXqUP/xm8uw/h9T/tsBfJP5VWvsfGr9MeqWugtYKzE90y5/IkvTVnJQlnqyM2bK8jE9mJJqT0po8VP4ZcTw+CHOMG53QtrLKnmKHVAQHxLYINodKh8NWJGtFJXl+ppIrJfNiUGfpGSltkWe9kVWOJViHMfRmRo6FbTlmiznJ89q5LPHnaB7kgoXEwZCFzJpnu1CQ2FZjx1Zr0cqVtkg8ied+qVJakyttAS3n4lxImLP1pG27UskH60qbsSVl1fMsEyfCCmPI0/M0Z4kjgRwsKzgTa32RkXhclA4FwtzVtTaotFSReJbML7BovsqOQphky4wyq8wsszursoBOB6Br/73JnofJHqGzxkeXk+OnggPYyMnyv/AAPzuBE1q5WABtBOgBs5WHBcgWcFgFtLKsALSRZBskCzFUDOpMkwTqvBqfhRxbCIC/0SwXrC9VwQwx2HYNEFt5sRZoqwUryS48WZbAyyC7oNRIAIZcsL5UXlmAzVBr0NkiWxCwa3MP4APEGeDGHDJAQ15sUSkVAW5oFXIylqwhwM6W4WWQ0yCHMXRBCRmDjAl6sgz+xeBEruWBTWaUWWVmmd3AsN4LmGmt/+WyD2k/3TQ6TPbwZ5JPfJSPHfjLUQaUkL0cgH8l6ITMOaoXAXCJ8mwxZwH+zDqIk2wD+AL/QKQP0GMM8HkMhwAHAfhVxOc1thlbwH2KlQcrawr+BoeQhnEK+CnqV0K0h61gh0NQmUCAn+FW0R9rBn44CMy9jAXwWuR3WKvDDyfBCuu+tBK9eVyUcmJpPawB/kXIyRrJy3hZOwi1DvgR+SXi09pA1M/qkZ+VMfzyHPCryO/zYDMFfy4C/DwG/Dbq85qX5yXcXEqEqC1akzHgdyw4BCkTyjHg5zW2efXsh2Q35WSOWWVmmd3A8H65JIQyIJL+kw7Qh4+wF/mz5KmPryTHr4sDCKnGa4Ae8IeUP8AP6EWZmgd4Swt5rAFmZAACtAJdrMoC6msAX2UBkvIj0sMRQAp+sRgL3DIG5CbyW/h15Af8Aj2tqdRewy8WcgI/C5F/YF/BAXyrhYwkNqPPV3Nfh78z8sM6Vhh7loyXSQI+MgAFf1AA3SHqG/hTAR6RH+ADfhP5fQ3+VIHeOl9l8ElksW8g8CN1J/AR+U30B+ROR/81BX+1jn2CC3nlADbCqc1dZpWZZXYDwwciZYBxAPPhKIHr/6N/mvzGLy1vOwC/7QByG/VpLvCTtbCfgANA1G+HP1XwA3i1BtBtXY/ID8hRw4fID+BHhh9i8AV+RH0Nv9T/DfA7AR/wA+43UNdjTUd9BX4dfgFcR3wb+bGGlB+RX8Fv0v6FNvhV1Bf4FeiuE/5Cpf0CP+AV0F2pbBD+vBl+RP4wLoLNVdqPNQYdzwR8seE5g89KFfwS+ePwBwvgZYzNQZq7AQfArDKzzG5gWMqAuAOQ+p90kD78CNlHPpt88lfaHEAu8JMAPK95Az/qfn8SY1P31+D3Bn41BvyI7GpsI38pnCAY+Nkq2TVb78sa4Af0gL818gN8thL5BXTU+jH4XUvND8gV/Oe64GdJ5C+BN/CncfihetRnIe034Fv4JZ0H+D44ArKA30T+OPwQ4Af4LIBv4c8N/B5pP0BXGhV+jzFODVodADPL7AaGD2IfoMUB6OM//tB89eFHP5P8+q8uN5QAsgfA8AvgqP2NEPmDtfIx+PUagC/lRSgLTJTnuYBv4UcUB/wKeAO/qvej8AvoGEP0XVLzC/gjRH7HUmtewU9S9b6t+W3kx05+FP6lzsgvYAP+OvhYU/DbqM/iOep9bPBFIr9K+zG28GOs4LcbfmGdLMMbj/wXLPxewd+a9gv8wVoHwMwyu4Hhg/Y4MO4ADtGHHyX72B8nn/g1mwFgD4ChV5CbsdrYYwF8rKua39T59ZMAm/bbDKAEX8PPc7lzUCj4AT6escaHH6qgR5QvVOQH/Cng5/HokV/qfR35Dfxdab865pPjOg3/QmPNb3f7O1L+tC3ysw2gO5XyC9w+HOkR9CTU/k3wOx35s9oY8ENI+zsjP+CXo7piqLTfqcjvm+APSqHwmS4HwMwyu4HhQ6M6gP2VA9jzGH/JHyVPsgN4q54B5CgBGoD3WKvBj+gP+HmM536YyA/QzfGe3elnK5K1jMVjBj6sA3Raw3k/wB8Kfh7bzT4NP9sgVe+j5h8NfkjV+6T2er+z5pc5jvp0zd++0w/w4/DDWvgBPs70FfzmuK8T/tTCD7hzG/Vd+4YfIn8B+OWYj8YCfjTyA35s9nlV7yv4MV/PORsIm4DhVuBdZpWZZXYDw4eY6VEdwOG56sM/T1/2pHYAAbQTRTf8MlY1v0fUj0R+RP3m3X4Lv2+HH9lCSPvFQrxGkvFO4Mc6oG+M/Krel2dj1Pxe1fxx+CGHMW4cCtzlenyzj+VaIz9L1ftKgB/pvivX5JKPPuZDyu/a4bfn+yrya/idhl+Al7FE/jAH/CryYw6ZtB/w280+lfYPwk/i9XzAAaTiAJ5kdgPDh8dyAPPBAfzhgAPgNEMcAOp+gB/mcAaI8JBaA+wY2zN+rCv4eR1pPuBXO/046jPwWwF+thDO+fUZv4x15EfN37bTz8JOP2kAfjgHAR9jaMSdfhbGUIadfpLAD/Cban5YIxP5Ffim5s/FIvJr+EkAXdJ+nlv4nY38eF40RP6uM34Zy4afgp+tj9X8ax2RHyk/sgBIwR9S/2D9JZ0BMLPM7vwYDmCu3QF4bAISZPVd/3rkz8gGnYRFyq8jP9Y1/ABe1f4461ebfRjDAcg7BIC/9ZiPZdJ+JQV/2gY/on0YY461Sh6XdjT8GCv4nan3WaPD7xT8foElKT+Aj6X9zuz2k7DhF4E/jxzztR31sc1a4GcLod63kZ/lWuFni3N+gR/A58HqyG/hd5HI7xXorjHyh2dkOQvwoziAuZEcwJxyAKYEAPhwBAH47sjv61d7AT7JjgG5VYq0v+GcHxd8UgO/cgDDbPid7oz8kIW/PfKXsOv7+/W1WNo/fuR3Bn62Fn7HEuDFmt1+yEdr/rbbfaWt4BcJ/ABf3d/ntcze7muJ/AA/Cj9bG/mx06/gj13tDc9iaX8X/OuVXB1+sp7m7Q5gbhwH0F0CpLYEQBYA+O3tPu0QVJQX6+W5QC/PI2m/b9vwK8fRM/74UV8pDXrHHPDbc34Fv4vAH7vg4wVy1phpvw/zUS74sFwX/PLMgG/TfoBfsMI5P4D2gL9uze0+13TMZy744Hw/HvkzFflxzj9c5Nc1v6xHjvks/DIG/GQjJcA9dgA4BkQGoM74fYDfN53xm8jfmvYj+mv462VBI/wS+UmI9nAC8TN+W++r+/vtkV8gj8AvsHPNj5S/E36nI79I7fa7kdL++jGfSvst/FZ6p78Fftd6zFev+aXGL1DvRyI/4IfV8vUz/pFr/kxHfoa7G36s2cgv4LPUOb+u9wE/nAKBL/DDEfBazQGkE3AAKgMQ4FmZgA7Zl3pgG3f7bYqfKvgBvIE/gJ9hjsg/OvyI/p3HfIBfZQBjXe2NR/5URX432tVe3O1HzR+P/Et1mcgPAfbOCz5sEfkhL/Ar0F2WdcFvj/n0Sz1su+HHM3PBR73NR2OAb+AHwF3w67S/ud7HszrwEvmn4QBQAqh7/axXx7ndhw1A+yYflGr45VnzSz2AfFz4TwN+W+9DiPbtab8fiPzVukR+NyT8qPchc9RnSgFd8wv4SPsjkd/U+67tjJ/n8ZofN/tQ76uXeooa/LmCP2uN/C6MPda0bL1vr/cCfJKseUT9QdC7zvhb4UeU95G0H5GfhcjvBf4f8nyCJYCvO4BTiOzmWE/UWPMrnex4kQcWY+z068hPUvU+rY8Lvx8q8uNiD9n4Sz1hTep9N+pLParGt5E/frVX5oj6O7va62WMqF9pqRV+jA38uYIfDgBrsciPcWvan+u0X0V+3OknyVt9YRy54APw1fVefa8fu/5N8GNNoF/PFfx8/l8MZAD+fmcAOAZkwAR6k/bT3N7u8+3wA3hzzKeen1I3/RD5WWqnfzz4vYLfibX1PqBXR30Mvzz35ZqO/FnsjN+m/ffgdp9H2h8gN5E/Dr9IR/5gHcaq5rcbfvaCjznjZw19wcdjbcSrvTbye9zuG4j8LhL5AT4rXu+7hprfkVDzwxr42U5tD4CAa3QAGKO2j6X9CnS10w/og4UDkMiv6/3xI7+93WfhB/jNd/vRvque9sc2+yJpfwf8kN3pdxjX3uhjC9Dd6PCj5gfwkZofqT+O+dpf500V+ENH/qIOv97th7DZVwnv8SP6V/BHX+qJH/N1wO+w1hL5sV9gIn9wAO7yVDIABj8T6G3aD/iRBZh7/UEYqzWT9mOMDj5BbTv9Efjbmni0vNEH2LGu4G9J+60DiMNvI38aj/y2fdf5EPkF/kUNP8/j8HvAr0CPw+/0vX7Aj2M+7PY3R/6s63YfWne1bvbZO/12ww83+lqbeLjV2GbfOPDblF8u+vAc8OcCPylL3HQygEz2AJp3+xtv97GwFoefZNJ+ffSX6UYeo8IP8FldNT/qfRv1Te8+QO7Yjg1//JgvDj+DH6Rq/hHgB/hDRn5EeXT21XU/W0Au8EfadzVHftT7UfjFyjhDBx8V+VXUHz7y162GX6Qjv476Aj+Jxkj3ZVwqo3mWuMnsAeAmIEoAW/OnAN2CH6v5WbFjPkR+AB+N/FiPRX7XCX/eccEHjTvtMV828uu8gH+kq732dd5y3Ni+K/5GX8cZfxx+jNG+K6T9qnefatoZad8FIe2PXO21kd/e6y90vz7IdfXuG+pqL+S6LvgAfqT8SPUBPskR/CRVAkw8A7BdezEG/FjToNvuPUj7Y8d8kZo/2r5Lw9++22/hh1wj/Kpr7ygv9bTCDwsNE/nVq7wG/vh7/L6pg08U/sGuvd507VVNPFaUA7in8EOAP2NJ7z51zm/q/fiG3xrGsLHbffqCD6sw8Ps6/ABf5sEBFJNwAKQWB4Bd/dgbfSoL0GtS43dFfkT5jnv9I97uizbu7Lzgg669wTq83DP8Sz3yvBX+WPuujq69gJ9sHH7bxQd2+MjP8/auvbZ3Xzf8tmvvaC/1YLOvo2uvQN8MP/YChrja6xX8XTv9PohTfraAny3kSGXaj/VpZgB9196+a2/ftXdn9/oR7RH5STbyh1JAxqRLnA1M/CZgnnjZAzjZd+3tu/b2XXsbu/ZCJvLb231qs09AV2m/WxfwQ+Qn63geSoDJvQwUHADq/r5rb9+1t+/aC/jJttf8+nIPj1XNj4hPGqz5L5VC5Kdn/srE3gbEHgBDifP+vmtv37W379qrdvot/IAd8JOQ8stYoj5qfoHfAf5Snh3A5Qm+DoxNQAa/79rbd+392e/am96Hrr32pZ68GmOzT0oAgZ/niPqq5leRH9p2AMVkMgCvHMCD0bW36Lv2/n/p2rs6ua69gL92u09v+OGMn4Wdfon8HfB7OICJvQ2oSgCG+kHq2ls84F17cwI/qJwL/EjbH+iuvauT7Nqr3+PH7T4W4McY8Ge8Hoe/lNoDmOC7AIj6D0TX3vwB7dqbM/hyvDfrl4rdz5NeoDGLxrteWC52k3Y9v1zMEMTsIB68rr1rE+7aa+EfHOOlHnW7rx1+PxD52bL4FGBCx4Aem4AEGTKAB6drb/6Ade1l8AnqJYK7dARZ8rWFleQr51eSL5P9KukZnpN4/gx953PsFMgZ+OXw+b5r78669rLkgg8JO/0tl3wAP68BfhHmBD4cwATfBYADwI2+vmvv+6trby6de0rwjy8S4Ofz3W5x/alvrv7oS/9x+eY/vHL91rfP3Hz7387evPXS6zfe+psf/OjKn3x7fe0XvpGzI8hIlC0sk7bT/L5r7xhdewV+OAKBXsO/Xj/qywC/jvoS+S/XHMCVSd8EvCMOgKHuu/ZOu2uvhb+K+n6Jo/3q0a8vX3/2P6++d/bKu1sbm5t36Wer/Lm7hTH90HDjrXc33v7uuZ9c+vRLFytHcGyZMoLSCfRde8fq2ov2XQK7SvtZAnzG8Ju0Hym/wC8ZQFZZ7AFMqB/AnYwglAjPtu/a+/7o2lul/H4pn3WLnN5f+9x3L925ePN2HXRyAltbd4Lq401xC9XPO987f2vtw3+XU6mwSJlEGfH7rr2jdO0F/EFNb/St1+Ena+DnsYr8JfxhLBnA5sRKAGQAcAB9197pd+2tIr8vU/587vjirX89dSOAHwDfFLjZ0oO7NeFHHAN/duPaO3cu/8G31peTr5ATeEGcQN+1d+iuvWnb1d7KYu2SWIEfawp+jIMDcNMrAfquvdPv2ovNvsrmB9LFn/5X9nYJ/52NKrLTMP6DUkAcgdirn/vOZSonloITWOm79g7Ztdem/GqzT6B3bfAr4KvUX1Q2A5m8A8AmYN+19/3RtVeO+HiX/+3vvPmTEv7bGyXBPAbbkR/1ZzkT4B/6rq1Lv/fSOpUV7AT6rr1DdO1lhec62q8z8Gq3X8HvW+GHnGQAV6eaAfRde6fbtZc+zzV6ueF3/dj3rw7ATxiXdtQf/iicQDm4s3bj9urjf5tnyXMr+Yznmn+l79rb2bWX180FH5Le7GuH39b8LKyRpAQoJuwAztC479o75a69OY9nOPIfW7z4y3+fb954d6NkvmR2HPhtNiClBNtbL712kzYFl/PZ59kB9F174117Ab/MEfE74QfoXkV9hzlposeAJOUA0lN9197pde2tR/9b//LaDcC6M/jhAdTP7c2t9adevEClBjkB33ftjXTtBfw448e6hd+m/N6k/Jgz+C44AL9B88lmAAB9nK69UN+1d7yuvTnZauPvucW1D30j4zP8rfqxvsJ/51nAZmlvvvjyjWXaEMx3lVlA37U33rVXxgK+gp9l4VfgwwJ+UpkBXJ1kRyDjANiO07WXbd+1d6yuvTj2283R/6vnr33+e5elXo/V/ePuB0hZcXvlx+8V888TtK7v2hvt2utU5Jex74A/jUR+dyWsBQfg2QFsTuZdAFwEOlvf9e+79k6+ay99hs/m2QEs3PrW6ZD+33MHgCyA/ydlwG/+I90U/NpKPlul+H3XXtO1V93rdwr+rrQ/7YQfGQDLwwFMIwMQB9B37Z1a196lbPa5xf89cfGnJaibOMK7Dw5g+4LQtT//9ytUBiznu6pMoO/a+3/sfQl0ZFd5Zpe626zDlkzChEwSEhICISEkmeRkmMkwk5WTjezbmRwmJCfrDGZgemi71Xr1pG7cNt43jAk2ENsYG4MbTOMF8MQGvLDYbtytpeq9V/u+qFSSqrT1/N999+ov3VuvnqoklRojHf/nvnpVqpbK+v7v3+53ddVeBrxDtgnw60Bn8DPbd4DfLnSPAOzhjAK7BFAId+yp9u6qaq+fBrzgWGzJq7WH4ADW6wDVI1+sCAdwYHxPtTdctdec6w9nfv2xBv7dcABmF+CpPdXe3VHtRfQgx35nEi+5JL6cnVveOQdgFgLrxx+pxvYdUg5gT7W3u2qvCf7w6T7F+uIes74Jfnw/runfG14NwNVqAAj591R7d0+1V0UAy4khRwCjX5IRwMSeam8P1d4Q5s+FMD+KfT3BD9utGsC3ZBdgT7V391R7YQTCsZnWU9nFoTgAVQP4+5PF2L73xuEA9lR7A1R7w8GPVTPLrPQHgx/AX3cALAo6PAcAwO+p9u6Saq+LxwcnYtiuO3fb07ND7QK8+YNpmj50UASkz3hPtTdEuw+rDn51zcwP43wfFgL+ouOnAKXhTwICbJL991R7h6vaKweAhIafM3JkOrbvPVOzNz1Z4zmAtR1wALxTcLXZXk3/5PWp2L7/ExNtwP0THnr1e6q9BvjNnJ9XrvDLjUAhBb+8CX6x4rnS8CYBuQsAIK4P+uyp9m6Hai/MCmR+V6w+8N3I0Rlo+ZHEV3LhS04TwNTC/x0pAionAJ2AyuGHyu4Lo5AQc2hvgEfOwHMY9HuqvTr4GeTBo71mn59Xjfmx4jnPjwBWhzoK7DMxa/fvqfYOrtrLq2Hrkt3rwB+JxgD85Ksucxof+lptrbXsS3zx9O+2RwD8fhwJqMftM8VW/g8+nocToMEgpASeG4nCEeyp9hpsHz7Xr4Mez2ngLyjww7zdcgAe1wD2VHsHVe01mV8L+23k+dDkEwaJL/f51kzl0APFlWJzWYX8MIlQU9tjG76M91TFxmXecTx//8x8+mduhHJQ3IkcdckRyBDf+s5V7YWFgx9gDi74meAvqiiAIwCrNExJMD0C2FPtHUC1V2d5NhsmN/rYMWj2O/uOCH2//NvuyLRPF7jaz8AXi2J/3MfzXLzbOvi19+R/boXlw1YXllZnr3u8nvjeS5LkCCgtIODvl4D/DlTtxRo02suA74f5GfieWC1hmgMYfgSwp9rbj2pvMPNLxhfMD+C7kbEZ6PWn33i9N/+56TmArhvAmZUZjGt6TjDAl/pWhXblCPR6AC46HcFybm65/M7PlZ0LjnrkuFyqDyRg33mqvZ3Mb4WDn80EvwC8LUN+SzgBXnchAgBApQPYU+3dtGovm878cBxycw+0+EWen/i3l8Rnr3msujq/tKqF+wxwFv1cf7zwQKzZejqvIgWuCQSkB9ptfr3wHz64SSp8bqWgpx14nt9LjxRa38i2cm/9WB5OgFqGHv1uCYpqku53iGpvn2G/WrsyP4NfMD9WdY37paEPAkkpraf3VHs3r9q70Zj5AXxxRNcIevoXTTsHj06X/+m+wnKmsdTJ7MzEWLCy2i9eR/sBlopvvyfvvigab0+WWroDWNMUgTfc02J7ffCnfOhU2XvFca/5yWfn1DSgD3Yt4uD0RF2T8zjTTL3+2jQ5NdeNWAlyBDzl99xX7YX1AL8dAH7B+Ax+DvkF8KWVpAMoswMYbgTwzJ5q7+ZUe2Ec8sNYzgtbep3I6DS29dKBHKnW1zMLzKjM7AxgLfdutFZqJx6pJF7xPmd63/+crF/xaEXXBuAQns8DkGxtng2gOwL8G/XWavL1lydp5iCe+5WP5BYfTy329TPOtVfrlz5a915+PAlHQFFOEiaKg89d1V6tx2+0+cIGfHDdGe5vAL8M/dkBDGs3IEcAPOizp9q7udFemCtXAJ8YcRrhfvq1V7vErg0FGAnOnuyKFd+T+vGrE+Q8ZqhYGEu/6fokwCY4nwuARsrQs8+/KrBv6AHSMWJzFKE48cgR1zkw6pb+9mSJhEI5SlnmKIVXLUpJ1JZKf31vydl/hGoCF3kU+ZAjiMIRJJ9rqr0m+GHmgA9fc29fOQLPBD+AD8O1dAC27gCGHwHsqfaGg5/eh8N9MgDfe+lErH7ikTJYPDjPN5kWUQJFCxkB/MhozDt43IFkd/PeMw3etWdO8JUvvK9YO/FotXny7NziI97C4leTCwsPxebnbj/dKP3dyeLcJ06L79eLiXAKuJF766056ve77sHxBCr9lBYk6pd/uY73xuuZ9Xv//PTvLubecgvOGvDo50/SjEOKphtTcATPFdVeWPCmHhb0MHr8Wtivg5+v7fPBAUSf66q9UwOp9prgJ+D74T60+zHCW/qrT+eW3FpbZ9BzGoN25tqoC6A+QHUC1AtQN4h7B48B/LH873wssybfC186g8/e+Hh9et+FM/GR92KmII5ZfpL4JruYWP1wfGbfe2KJH7o0sZJvLuuThcohLH4lsUjfR7k8WnxU2Y+MebQt2Em/4drM/MnJZj+dCvy+c7c/PZf64Ssz1O3wKBpK0ueTkvsBsG6jaq+9W6q9BXnfCPkN8JNxyK9Wi8EvjMF/XkQAzzXVXoecA4f5XOyT9wZR7eXjuSNHEe5PZn/pw8nFryTnNx7b1TuHRicAHQHqDDj0HtM0dhv3T+mxYY6zfyzeejK9oLO3OhWIHMdy4vtP0ITemOMenHB9KS9pkXEM7rje848nsMOvcvj+Mm8sWuuyE/DeEtgfDsB3BBOUghwRLb/8b96Wbz2Va3G6YqQFxu8GMdNq9Es178XjKYpoEhQdpWDSCfSl2itzd76WwGfAD0+1d5BKP4Nf9PcDmV+LAHavBgBQf7ur9jq4FyGw77enSOBiyo3YnaxPj8envAMTkN8WYBdRgcn65mEd6njuEUscz538oSscnNeHU3bCq+gMPswApH/6hmQMwI+MxRj40Tj9XA4Uesvvuq/IhT8TtOX//bmSkvByxBFerNqL1ZHyXeL+86PuOohXVEFA/lyIQqjb4H3v+5LkTIi1/UEf9Pk9MopKPPd5Y4nKu05VVvJzRtuwe31AjhXPlJeKf3Z3iSISeu8jiAbSVCQFkENVe11V7IvYGfpMMvS9CvQwXGfp58vSc1mXVnYAO6TaazJ/Xq4B23l7Mb8FM8APc/3rYXYBbCMF+HZV7QXwiQmnCBTE8mOTxH5nKJw9QznuWWLUSfcgsf/I2CT9UZ+Ni/uHzwL8whFEfEfQbbRXhfswVPbdF9sz1bEvllaqCyuB47t4Quuj03HerQJN/yG3J0D45/JFBPDJbHk6z1icmN3FCcD4pm5hO+kFLtLvY5zHxwo+DH7M8mOuP/8Ht+c7jwbTFYGo01D3o4CJDtXeqGjx0WeaQKU/8coTqdkbn5hdXVzm+gDsXMBYsXxMm5sWaJMT6gNJcngpOAKf0a2UPt0nC3YEeFuAn9ITtBsRSaRw7R6wMjBKdXDcOZ5L02eZJoefpd+VC347pNrLZob9Dg/4dIK/sAnmhxXZAexOBACQfVuq9jpy9YE/epb+kM8kvvuS6cKf35Wevf6JyvwDM43WN7ML7WcLi1Rsm58/Nd2oX/XVcuH3b095LzkGNqf3POo7Ao4GZjrDfeT55Dimin96V6Y9VeaQ2JikWzMm6TDnXzl0f4nm/sVef5zPD+OTeWFRgE+w/+wNj9Vkrq8V7nxPQrWBLHJ+xf69VHsdrCO2cALzp6aanaDnqUB66+bSavpnryPnNOqzP8DPCj4o6hF4j8IReJmfvTFLw0kLGuvrkQ9/BnjQWllr3Py1Bm16yghHMBJN03sKJ0DGrB8hdh8B8C9K0eedTv34tXmaQqw1PvpUc+Fhd7H9dK7dfibfXnjUW5y74/R85fCD9czPfaDgjIyigJqm96WIwFbafbltV+0Nnu5TqzB9wEcC3wC/Ar60snQClV1yAJznf7uo9jp4fQTgt6cA/NSPXhkjlqosF5pLQYdodtLVUrLeRtU+8e9OxJDPE/PIfH9jnp/5+ZsSC1+IN9fMCTl+P+OPfnkVO/wSr7rMJSdDeX40Ls/lj8vtwIr9sf0Wu+9imV+8MUVgWd3IqQza5skzc/IoL9fZrGS3cABH3PTP35AGe3fUJTa+92fONpH3o5UnQM+qvaK/70V8R0DO0CNwJgp/eGexfbbYDnSGWExnuELOsOa+wCKAH8bsQJoM4PfXiGD2VO7XPloiR72A/QidKsZBuoZUg2kV/+LuqrN/NEsRAdICMd/fN/jDVXthHPLro73BzC/u66wPY/Cj/y+uK7uRApzRcv7zXrXXBz+p8kYorI9cfJbYIK/ab5IxwU4KrNJ4UKYzvF7Ozy2V3vHpLIGLnABO5o3OiDz/+y6NNz74tepqSw97z4WFvU3s7Y+LPP9oDMD3AHawvg5+rBE4gIti8w9MB7I05gFSb7o2RWCGw9i0aq/Ywbffb/PVr/1qPSi6wOP87/5LgQDoidBf1+tXjmDETsFQ4KMpxWT14odqKxVOh8wpR1wY6VC78LbbSwA7OZQU8nysiVdekm1+4lvzGxSLls3/jzzstDGlWXwk0Ur95LVF+tkyFFHlHIB+G1V7zQEfxfww3tDDgOeQn4EPixrMzw4gWtmNvQBgaAl8rOe3aq8CP+WCk+5L7cn5z0zN+kA0wL1mfPF9A7iNm79ecyIXTVHha5qYqmDOy/MQfrdoYGm63Cr++d1ZAjPShhkB/IgPfOEAFPgZvAjlRduv8Ed35Hrm6Zc/WvULfxOu06dqL6r7KPIlvu+S5HKqvt4WPGfUFzIt0iRMMPhN1V6Zu4teP0U1cHJe8gcuzzRu/eYcF0SZ9QMcJfCNguhC+k035GP73p3M/MJNBWqj8uetdS3MPQ4btQ3V57Q621ot/Omd1ZhwAiIS2DbVXgZ/+GivHvIbToCZX60wTgGGuRsQTK2Ke1jPZ9VeFfaj0AfwLz6aaK4fob3aHfUbd8UF74fH9fxnpxo02DLfc5suVrP1VfZebMs8347D6Gdn4KtKv1g7D+K04u4Log7ltrK2wJX6dcfiVpe87znut/0i/av2dkQBbvl/fbZsdhhYIbjynlMVFP0I4AC7saFHra7cwYdeP0U5SUQE2Td/KE8DSYvcEg3fdoyhI3K8c8up2WUVnXQXLFnTRE2MMWeOCGgpvuOeGkcCEvhbV+1l8GMlMwd8mPk11jfCfqymA7B2JwJg5j//VXtR7Uc1v3nPs/V18PMfzeZ3zAZPt/Uz/DKbevUVMs+3ZLhv6eCPSfA7yhHQ5wT2F4W/ypEHe/fq//beIr1OqPY6A6r2KqOTh7yWmP1n5j+nzxj8+0sJ4EdF3h+m2iscQQRpwQTC+SQNRSWLf3lPeSleXTKGogK0DtjZap93/ypHHEG1V9ayv3xLmf5O0CHIIxLYsmpvOPhhPcBvsj+Ar8wVj63dSwHOd9VeAg2q/aLgV37PqZxkDI4psW5BKaPn+O6qMf66kH3Lh1PI8zG+q8J9BfzOkF+aAL8jri1i8igm9+LJH36/t1LoMa335cSCUOxlvf6BVHsdrPtFb9/N/dZH8z2nDD/w+CxCexkF9FTtxerC0MobGRdGzJv0XjKRrk38vzpCcvNzVX4gOFIYRPBA/+yWYpVl73veR+Afy7mRbVPtZfALszbJ/Ax8PfRnB2DRau1eCgDgD6La6wxLtTcSRatvMvnqy2dWigyaLZ+fzyxipgfmBpg2bYDJ0waYGUeM7453hPsWgM+9fQ38WGGC/UcE+8cat359lsFnzutnf+MW1BRU249FOgdS7cWQz0QC1f7mp55tdvt3FXtm/uMHcsToougnnEC4aq+c9pMtvggq/YeSqR+9Kjd35+kmQBk0MGVG+lsXPFX1iPo1X21SPUBGAYLlB1XtxX1tUw9X+jcB/rI0yfoMfnyvy05g+A7AAyOzA+hPtZfBv5OqvWB/MeSD4Z76lV8pKfYPAf9gwYC2m05ugV2pX/ZoxXvZsThYvzPPl0U+LeyPdhb82BGA/UdsUfXP/Neb0wh75ZfBxHMff6ZBbBon0LJevwF+C7Zp1V4vAjWf0UTqp67JrDbaQKLeFpRCJDML5OASCO/7UO3lIZ+I7wgoOkJEkMr98q3FxSfSLQ34Wtq2zZqHCHLqi6vJ11xJAB7NEYHkt6Lay+AX31vsg/kV4DXws7litbAOvw0IYA6s2qsBXwf/dqn2gv1R+PNednwa/fsNk3LbKpq7ZjBx81NnGqnXXYONMlOQ9pJtPQa8Yn4d/Mz6ccn8ZFE59XdxnNqF89q8P0t1VxdXkq+7KokNPtQm9AKYn+/1odqLNh8KfbVL/7XOoDdPDCr88Z1FihYSqPgj1+9XtVf19ylKEsM9tO04TbsUqyj4GdHbNn7pjpQmNxsUbWXdAyIKGFC11xzt5bHewcAvv19dV1z/ujrkQSB2AFtV7YXtlGovhn0wvpv/vduSPvh34tAMBoEKwUv/eDKPwzpo2gzAj+EQDwV4BX5Xy/m1Vh8zP157YNzBME/xL+/Om9V4BmN1QpzXF5cHdbibPpY7XLVXSnmNJbzvOpakPFkW6/x/H6ZCdBItbbsvsjvAb/et2uuuO4JxMeWHaMD7rons4mPJliZ0su3S58qRUaeoTRHANqn2mgM+EtzB4OdrBXYYXrsOflpheM3uOQAG+9ZUe7Fuu2rvARn+X/poSWetnTw7v/jXn8yJ1t4FE51gj4lVPpamwC+Bz6yPtTP/91427ixNlToOAJXkr4A3WWq7L1XAtwXYQ8DvmcxvqvbyaoHV0brzSu/4VKlXW7B69KEaRQvYF6B29A2m2ov7EUQDExmkBYuPJ1s7ff7hejRFhcjk919eFE4gEi0MqNorBDzNnN/uAf4o5/wMdqw6+EXoj+9xNQcwxBoAO4DzTbXX3+gzLiIACsdndebYyaOzG9c/WUWLzzswzvl+B/A9mOzzM9BtBr9cue13KFY79nCF235m6F3873cXsJVXsT/398OZ32HmD1HtFe077NRLLP6ruxi09XilOL+S/JHLCcBHKa/3T9oZWLVXbPAZSydf+f4ccnN9onInIjn1u2T/24crVHfJ0d8RV/fDVXvJLJ35+wn7+doEfwXg52tbXu+6A7CwnoeqvbboANCgSZP7vZz/74wDQCHu9CwiANXf7wz7AXSP8/0A5seq8v7RePL1VyWQ3xvjxACfGCOOz9O+AM77+8j5HY35eaLPUO1VY71JFPqyv/rPeW5DmsXIxke/Mefv7Z/Adt6BVXupAIkdfpn0G64rrLbEL7wjaVy3MWeaDqwRgeTICQvQ96naW+w114/HQdV+jf07wS/vAfjsAHY1AjhPVXvZAUSOTi4+lprf+aOzGZDNT55pyOk+LeTXRntlsc+RoMfK9ywxv4/cf+4TzzSC2m/oCGTecnOGHABeL9g/EPzsGIxjuT2s6oguPCeBr6v2urgeEcId3txtT80FtCPxiRCDfihPhUu8XjiBflV7sZIDyGL7Lo3/FlbbK3jbHXYAHFVRzaUeEw5gYlDVXoCfQc9WDGZ+s9gH05kf5oprdgCeMHt4XQAw//mq2gvnQYxI10cmsdGmM2eF7YAD4AjgtmcwFIMIYAPz83Qfg9/VwO8o8O+3XfTyc79xawbvGci0t3x91i/8GeB3pZkTfhzyK+Zn1u99LLef00ewjlK//orMSnk+ODJ52FkUwh4RkQIMoNobzcIBIAJIve5aigCWZQqwsw5AdRryf3hHDSmAHwFEB1HtlWt086O9bL2Zn/P/iiu7ALBhHg02ySH/+afaC6MiFKS2z9I+8LqeP++kA6hf9uVqTNYAdPC7GvjZAfA9aS7Cf0z1BeXamAZMvPr9aPu5lC5wb1+b7oMp5mezO/N9eS4/rsOO5UYq4Gv3odBXtb5Q61mbePsny5jyk3v5+1ftjWAdyyRefiJHv+/Kzkdy+DX8Qa7ML95UoZ2Ueb8GEO1ftdfM99l6hPxB4NdM3NsFB2BvcAAeg//8U+09MCHEO6qjXyjuqAMw/+jRBUALUIKfc36jxw/beM+l7oWLib/S391b7LkJ56IHysz+geD3ujO/rZ3Jb27lNcHfeS1bff9mPNV+Vu3xV5/vuc7djkvey4+Jtt7gqr22iAKoNdfa4UhO/txwrnMr3itOENOPURcAbN+Ham/YaG/wdB9fM/h11lfMj8dVzQGsDdUBnCeqvZOBqr0j9jTloJPZ//IhD6DR5v93pH2E6b/Ua67yiJVjbkRjfhizvMn6sAiYf8yheXSXtrpu6LfjP+Vk6OivFrT7eNRXNy72wSTrwzyYYnuxMtB7Mb8OfrGrD0M/hT/7RKnXfELt+MN1ihYQBbB2n6HaGw1U7SWHmIWUF0VWRi1kp+o485+dXKS6CoF/vOgMrtobDn5m+xIX/KwO8NsB4LcBfuUAakPfDASwMciHp9qrVo35JyXzG6q9MHe/NdV6KrtwbgeGgfS8l1RpmkKuOzLeOeRjjvaaYb/r5/5g/0Mx0tzj0Fo7pVfmp+JM/g72d3vN9MMcDve1Sr8e9luJTR/RFRlPo9BHZwssmD8vj9amfuLqHLG46Ou7EuxKtVeusO6qvSN2lsCYyfznm0udnRysO5XGlf7m3llqq+apALgV1V4N/Ax4fcAHxo/NYp8L4Ovg5wig5u1GBKCAj3XnVHvDwQ/gC9NO6lECnsQeZyvvPpU3ts9u8atbzksiHdDfQ/ivAK+xvsWV/g7wy3l/F+o9qZ+5LrXaxMx9dymu+fun53FCD/J+p8tefr3l56wzf1Rjfo31w5lfGkcBqPCj0Jf5Tzfl8fMF7lG46/Q8pUV4vXIACvwc9nMbUFPtVWnAkQzJrC3qjmY7JznxcMmpLtP4ODG/JcL9wVR7TfDzarb5GPQwLvipYR9pneCv8Bqt7UoK4GgOYLtVexnwgYd1SPBz2G8e1CHVe19kT7fPFFt6QW0b+/+oes/jeC6wvTSHjFl/Q6Wfi33+PeUADsdJa29O+yNnRqVKePoXbkhDs49eDwcQwvw2q/bKXH9zx3Jb4Wfy+wBOocCHEL/xwSfneoiTrtGpQgSmi/B6dgLM9ubJvL5lZBSQI6eXyf76LeWOmY4t1XT0z1b93OV33rfO/gj7B1ftNaf7TOY3B3wY/FiZ+TtCfjJ2BPQZ1Ya+G1Aq6z67zaq9ITm/1Y35AfrAk3llFDBDwJrK//a/pDYIQOB6q/vI8Vb0CLvk0v/hhiQcALGc1uOHWXEz72fwI/QH+EljL4e3Ddx3f91jdaPwx6Zv5eUdfYr5OfTX8/2QsN9O8jWvZFK7/2gq+YOXZZdzcyssH0ZXHQ4XQpyQ5wbwYYr5eWWdfkdeq/P5cA/CnVDsmb3h8Tm1fXfwdIDBL99LaTO2MP4L0LP1r9obzvxc6ddzfpfBL0wDvwr95Wrh3u45gG1U7e1nwEc9P20wP69TMBkBqLP4JqvHvqS2Bat2Wl/TgUGyYKV/uLfgV/4neLRXy/fB/Dr4sSpzDow5pLEXNGJ7jrT/lxOvOiHbfr129HVW+nmox2XVXjaT+budzKszv3qOt/LKKKBy6PO1nkpF/3CyilSAPifF+gLkbJZyAup+jg/olOsLrRyJq4hobpWA2/cWYWZ9XCnnigNPVpKvubxEn2+BnI0Y9Nmiaq/W4w9lfrPYZ4Df7gS/nwJwBLA6dAcA9t8u1d6gqr9DJlYu+MEJBIDfsBlXrtQVEJHA7LWPVQKUfLo6g27Pdwp+VEcfLDH47XXmh6nQ39F6/HrhD22/8rs/V+p5us+F96kjucD+WtivjfYy8ydhbkDBT5ku38VmJ3XwB831i3z+Aivd+ka2vf75ys9POVsC2TKUfF0APLIh19dZn5mfHYGU7z6aTbzqknyLNP8Ve6v8HV9BjqDbgauK+UnWbCX9xhvKVGwE+AXgt0G1t0fObwWG/a7G/P41s75DBuArJ+DskgOY2j7V3nDmd5j5GfwBYT9fa4dzdjiB6uhDxbWl1U7pKQ3hHO5vgP/yRnHK0t+fzAP82LQjJ/wCmJ/Znq8tDPCIth9p6iWgrRck89V6Ir1IpxRxyG/Kd5nMD+DDerX5wsGf6i7kYbEB/LQit4dsd/5tt0lH1j2NqV/55QbaepRjM+Blvq+A3+1Mfhg7gdEciZ7m50/NLHI0tuEIso1OgO/J18JpyM/2m7ml1GuvghbgetV/u1R7g+f6YXzN4T/n+zAvMOy3OqOAGj033EEgANPZJtXe3uC3JPNzj39jzh8NBb8ymTKgQi+O7Mr+0j8nW09mFs4FqALzaopQQZgj/dPXJ2Ma85Mx84eAH6+DZDdyepzc20N/fy332x/L+W0/gNwS4A8M+7nCz+DXrG/wY2Xwdx3tBauTgxVOYP6+yYXA8wrmxalChThV9dHi0w7nDAQ/DwXRvQgJdUTGcvGRI7nyhadm1ZSgIRa2JgcotKeUA6+deKRJZxXQzzK6zvzbrNrLYb+5j1+b6+ewX+7w08N+eY+BL6OBOtluOoDBVXtDR3u1nJ+uw8A/A+NrC9fS8L1iBWhj1L+epmO2Z6DLT33sJoZ4ejkAOttvuXlyspH/rduyTuTiGAp+AL9Z8AtnfgfryLho+5GWXhqaekEttOann8XOOmz28cHPob+xqYfz/BDmD1TtNcHP94PP5IcpNR+xeefnrs/jlJ7AVuZnzy7grD7hACTzS+D3BL/S6/edgJ2n789Dv4/OISxUj3yhQWnBkn74h75RCW0+kohrpl57TUlU+0co3I8w+LdRtVc+NnN+zve52s/5PqzzOrqB+R0wPux8cgCDqvYGMT/fU8wv2FsC3Qz5g5nfWge/XGNyOy4Kg1DrEbr89Mc4nfqxqz06BGOpY96cR1qTtaXkD17hItyP+8KeDoz7+TzWC3O7gt9yYX7ub2P7rtjwM//gTNNkS+4upN54DXrtSBe6Mb8BfjeI+flesGqvCX5h2tHcvbbzpnEyLw7orF+lTe5pw0zU8SjDCVD6hPBfY37jaG5lefmYZbuFeOdYLjbyXkRJucrhBxqcgoD7uY5CGo1NYvt8fORw3hGsT62+iM3g32bVXrB/IPMD/Ar4bMzyyrjaj3xfAV86AptWmx3AcGsA7AAGUe0NyflVvg/Twv7AM/mnTeY3wS/vQ6ZLrLRpR9xHNNCeKrW6OYD2VLHlHhyj143jSG5DuJPZPxj86rEK/dH2K/zxx1nmq8vpPrXLHqnRZCC9XrD/xtFebvNpc/3c5gth/lDVXqwG+LGa4OfjuCNYx9Io9i0n6stBbUE6eLXtHuQiH8Bvgh7PMfh5hYnvgWafEO/0nncMnZhc4e131XQHgM+Te/yH6LXHi4r1d0i111Dw0cEv1t49fpjq9Vc3sr7N1xscgD1kBzC4ai+H/Qx8jfltBW5xP7zYB7MCmR8mn4v5Fl03F4+fPx7DUV1dI4DpUoueD9Lu4wm/gLCfzRbm4PqFtts+nW/xiLJ2ug8dlOF99/GEfw5/sGqvvqnHHPAxc/5+VXuD9/LzPn413cdRwHvTpX/8TLXXhiY6qwFzDepILs0B6OCP9j6Zd78NVaRc8R2fqgc5gMq77veHfA74xb4dU+1lq/AqWZ7zfbpvgt/rwfyuBD8bnhuiA/A0B7Bl7T6+VgM+zPw8zIM1MOfn1TCT+Rn4ejQQc59nBzsAigzcCyTjM/i13Xw6+C1mfmG2Yn8Phb/K6IOVnj3zv/k02n7M/j1Ue2kFgMNy/qTO/P2o9oaDX13zdl4SZMmgZ8/Mr7UFs42VxA9cmkdrz410Zf68tJ5n8mNijz4n3wH81T314Ajg8w3fAYwPQ7VXAz9WdgQBo70w1d5TqUDNMcAfNRyANyQ9AMMBDKzay8wfON3HgA8L+znkZ+a3cQ3m7wn+DgcQD3EADHK90m+CX2d+8Rh5PwZ5SDMviaOvdTENVqX1FjryflgP1d7w0V6+bzB/mGpvKPhhuOezP4/2epTb48z+3Fs/UsLvGXyq0BNNPwqY4CO6N8/8rNorHMDh3g7gws9DrSlPad8QVHuxcqFPrIHMbw74yGsZ5pvg5zTA3r0iIEA/oGpvAPijGvgt2JQe9mssrwPfZH6xWt3AH4f14wD0fN8xp/t05oc5fuXfZ//GR77R63SfteyvfRiz7667n9k+ULWXgR/U5gub6x9MtRfAV+BnR8Cz/X7PPotUoHn36flAWTNqFmTefFMpLs/pB7iZ9TdzJr8lI4CJPh2AVdxJ1V4ys83XreBn5vs85NOd+asw9XiXUgCAdHDVXjZtR19fAz4wy2B9HfxBrN+nA2i7F+i9fl61Sr/O/BL84x60+0grL4P3Ddw5d8fTjRi3/Tw3RLU3nPlhVsho74CqvQz+LN03t/NGbF/S6w1XF1brLT5VSCt2UicE+++zor8vwa8cgeYAdOZnsc5NOICKcAD/VziAIaj2BoG/ugnwS3Cb4OfHAL6N18wOPQKAA9i6ai+M23wa85vgN00DP+f8WEOZn+8B1OEO4HnsALDq4MdqWOfhnBHfAWDXIIf7mh59ZWEl+dorUwQaej2DPki1N7zgZwXv5WcHMKBqL4Nf39SjDNN9aPNR1JOuve/hRs9Thf7kzip1RrIEZDB6UM4feFjHphzAO9kBMOh3VLV3w3SfB9MLftzj57CfR371sL/K4N99ByAAPqhqL70H5/zhzM9gN9t8yjTwa8DvCn4r3o8DgFa/zvxBIb/K+wFiFP6g209yYYWep/vYX6xy4S/q9avauwkhj8BWX7+qvdpGHmNTD1aHHUHWe8Wx3NJMeZk/X+1UoW8VltwXBzB/IPhtYR0pQL74PzblAMD6HPbvlGqvBn5xz2zzoeDnr5zzM+N3Az+vSAFmh98G9NmaHUCfqr0c9mvMHzrdZwX1+LXQ3lKrHvbHZdHPOKUnPAVgB2AyvyWvbbFqzkBs3fVePuHR+6vTfVTbjwFwpth2X+IDXxvtDVXtNYEfzPzM8hr4+1XtRdhvKvjAtE09FpR1xVbe4tvvqfZygJWjD0HlmKMAOSAUcjgnTKQAcd8BzIY4gAIcwLBUe82Qnzf1ODzdJ8N+7vGbOT8zv3QQWEUEMPQuAIDrMPOf7V+1l1l/4NFeM+fH8wbodeZ3/VU7lhsOYHwzDoDBHcT8ncDHtWD/Q3HSxqv2UtAt/MVdGGTB68HwA6v2ajP9atXn+rnq3w38fI9DfQ38MPk8s71vGY4AeCsv2nwo9FEK1ApUOi7N05bcK/hkXoP5zWO55YoIoBgPjwDm2AEMQbU3eLQXoDfAD0CH5Py4r67ZAezCbkCOAAZV7ZXgp7Vf8MOY+c1KP98zwc/Mr0l2bzIC0JjfBD9MMrfry3aNusmfuCq1Uus83efcRg39L4rTfdAmTHRIeG1JtRcWnu/zXH+Aam/alU4gQLVXD/kzvJVXG+2lCj8Kff+fvWsBkuwqy9uzeUBAKwUpU4gKhYJapQXGACUiRKBKq6SU0pIClAJLQSw0QZRk85jZ23dmE2DJgxiyeW1IEJQ8CEkIWUjCO7zCI2iAkOzuvbd7+v1+zfRMzyP+3+lz9u8+p2/fvj3dt3cxvflybt+e3sdMf//7fCfzuoOl7e1hpwo9uiLO558zTuZl8nMEoAxAQRmA4mgGIALVXib/gLFeP88fRH5FfIFul8CKzgB4pgEYX7WXC37hyc85f0Cbj8lvHssNg2AD4jly/JENgL/n9yRcVflHRZ808Zq+bTBo0L/mBghf4uvh5cOp9ga3+fzIz6O9/nr9gDACgeTvrwGw5yfwVt6lLH0/0nR02MqwU4VgJLrn8iG/B/ktRXgmvgAf0TXIADzlawCWolHtpfsD832+ZvIzfMmvGQCQv8YpwAwjgPFVe3nAJ5j8NpOfyT0a+UF840x+luzuMQDroxgABuf80msz+XfbHsQ7SQsvO/QcvZu+j7wXof/EVHvHIr95UMdg4U4fz8+El/fNDT1oC0LQI0vKO3mE+376B0gTKF1A2pDX8n2/8/mkAdgzQgSwhw3AdFV7jbBftfnguZn8QZX+uOb5mfy4jrYGwAbg8A5Ve8ORn4kvEEx+9vIeh/163o/VCWEAhIKPT9gP4usKvSL8Jy08XeaLR2FzzY3EC/cvd+f97cTEVHt51cmvMMDzM/mHqPZm5DWH/MoIMPE18gtkZBSQQ4EPhb7y/EP14acK3VXFaC8m/Jz+3D+nkV+sNHmoIoD6iAZguqq9Zr7PEQDAnt+X/Joh6IF1bI20Dej1GIDJqPYG7+gze/z24UDyG2E/F/vkqqv2jmgARKXfDPuZ/LLwt+ihnUcaeMWhp/vs+WIZ3p82z4DYk1bt1YnuM91nhPwhVXvZ8/O13Qttrl9u5X2WnV1/LN/pPVWIwPLcT5Y2qHUoUwBbD/v5fD4p3AkDAHKHMABRqPbyXD/3+EOQP64Tv9pD/no3ArAbEbYB42wAJqDaCwTs49fz/ZHJj9VVnl8QXcEc5nFCGQB/8gvEYAT2ut6ZlyVIA6+z7Xe6z4+ya+6plgr7gUmr9ga1+bjYp831h1XtVZ5fE/HQyB/PySgAXj2HoZ/8m28z24L04FOFvtYkA4kTekH2vrCfwOQHdtthDUBUqr1l7u3DGHDBL5j8tkZ+Wpn8BPs4MQDmdB9Wn+k+axTyswEwQ/5A8htn8vMpPYZe/zgRgA/50e+X3v98h7TvakNP9/nL/0LfGt4/6U5Htdcgv+/5fNpcf0+RL4RqbzD5sSpA0YcKn9mVBw63+wVReDIS48M0RlyEVLfcvw8oz993OGeICKBABiAK1V7c6x3w0av9AeQ3c34mvnjdJwKIOAVweNVVe3XPb0DL9wEV6gNG2M/EN8nfM+Sjhf0a+TXV3jFTAO38fYk528OhHaR5l9paGSKJdegJnO7jkqqQJPlUVXsDw353QNjPa7Bqry7fFUR+MRw01zUAqVddV9ruDD1VCPJhJN3FB3UIsHyXSgGKYQxAZKq90vOPSX4z7GfyzyAFMAyAJSIAH9XeEMKdhtcPvaNPvs5hP0E/nNPvfD4U90YzANzj7ye/Jbw/DADEO1v3PW7KfKnfcpVO93nFtdDO82AAIlDt1Ty/Od2nFfs0zz+6aq8p4mGSX73HkVt4EeKTKGpr+KlCt1a6qr2LpmrveAYgKtXeKlYnmPxVJj9X/znsNzw/wZ69AZiQaq9Ofp+5fmvwXL+W8zPxbc7/A1R7pQFwRzcATHxAhf4gf+5Nn8x1fw8fWeyrv1072i38RaraS9DIH+cev+752eOHVu3VtPsIxm4+HuqJIZxfyJEsegHa/NwWNE4VWidxkbzPsdx4XuwagAtDGIAoVHsBs81nkN+s9vcWAOscATD5j4sUYNKqvVhD9PiZ/Oz1ecAHz2W+H6TaG8oAMPnlynBOtjzSutMUcHjUdSNZ20g874PLpJmX8GJ2MjrVXsBisjP5CVzsk5Ck57n+sKq9+oYehqXWPK57o4DS++9vDFVIeu+9dfT5ieiGXj8MQjgDsBiFai9d+xX7mPy+YT97fp38CrIFOIsIACTjNt+EVXuZ6IE7+ni8Vwv5xesgf6Bq7ygGYL1rALwB5/G70vsn0PYr//uh0rAPcenc+0qa949KtVeN9HKxT6UAkvx9Yb9Z6Q+t2quulecHmPxxY7SXjGeejkbr+M5MJGqbJDRaJOOZ92Ks3ccpwFJIA2BFodobPNrL0ML++FDyq3sz6AKwAZimai8QQH59ug+rAlf6A1R7Q0QA2oGclsttvwWPtO2SpHHHKrj66T7fXW5TGMuV/tmo9uoFP+7xA/3DPJzz70C1V9vRJw0Ak9+RO/kw+pv9809WBO/9TxVawSgvvD3Cfo4A7BENwCGMArMBmLJqL6+Bo706FOF9yU9oSAPQjNwAEI5EqdprbudlJZ8ezw9wmy+Eai8bgOKoBgArnnvK+9evf6Q+tJD1Z5/I0Yfc83bLwt/MVHttY7RXJ7/j4/nHVu31386rjIA4mQeFvta9j/u0BUUBdTv1+x8jwl1S8ObsYncGgFaCNACFEAYgAtVe/7l+M+cHLPb8weRvSC2Aphf1bkCQjfN+64lpq/Zyb1+b7jPJj3uhVXvF15y6OJoBYPInqOqfwCae1B9el97uDDnd566ftLDVl6v+s1btjQ/c1OMAvuQfX7XXEPHgNSdXaQDm86mzrilRCxW0HSwfdt/P1shQ5L053tLrYpUGgLYDN0YwAOUIVHvD9fh5xLcuX2fy8/vV84ZDEK9zBBC9AWCyT1m1l8N+nzaf1uoLp9rLBuCJkSMAcUwX5vfRz1998PDKwLYffqv62lbqd68mUs3Lwp+VmL1qr+17NHffPn4mv8K4qr2G11fXPNqrdvRdkKtd/nBryKlC27m/+FTNoXCfSA/yA4UQBqAIAzBN1d7g0V7bKPaNHvbbyvPjuk5/76hTAFsYABH6R6Da6/rt5Zf3CI6m1R9atdfBOpoBEORXoT+8OmnZ5YeOs37o67LtB+9vJY4n1V6G6PHzdB+TX/f6QEjVXn/Pb2zqiRGoyJc487ICzusX3B80Rv2DTIeOIi/IFKAgU4BSCAMAApemrdrLxA8z3QfEdeKz55erJxBnAxBlCgCyIvSPQrXXFSsT3wNkn58JbTP5eR1JtReQBsAb1QAA4vpZtkdaduvGhhb1viPlTuK5+5Ldtl/8OFPtZQkvSXhdyMN/wCe8am8vNPLzpp6ekd5c8T331IdupPpAt6Ivo4DSSAbg3EOtrgFYgsePQLXXn/xy9SO/jgZWufOv4cnVFQbAitIAcBEQpJ+2aq87aK4/wPOHVe3lCMD2NQDrmgFQhb/K3oeGynwV//6zmE7z2PvvVLXXmqBqL0/3iWvu8wfN9QuSh1btNffy63P9eYJccW8+3/5mYl2RGUv/qULNzeSv7S+RcS1SahXCAOyBAYhAtTfA82vk13N+3esTGhz2Y2UDMJsIgIk/TdVeDvl9RnsdHu5h8odQ7aXVYwMQHAGg8Ie2H4laLA8TtWh/3W1TtRp5/3Gv2ivJq4f8fgM+oVV7TfLHpee3Jfl5tJeAnX1Fhwp92T+5pTrsVCHqvKyKKGBuqURGNowBiEC1N3DAB1BFP1/y8yrDfkV8rITZpQCRqvbagJru45aeRn4H5A+n2hvGACS47bfHbfzno42hp/u84WDWQdtvzob3P25Ve0O0+Yy5/hFVe3URD97LD+gn86rR3rnuZF/ztv9tD5FTw6lCVTK0Re+UfSEjgHgEqr0Mvhec85vFPhDd7vX6DcAVazz6OQBBzuhUe9nza+RnA6DdG0W1l1V8RjYAEO1E2y/z+oPZYcKWzU8+imKT3OxjnQCqvZY+2ReC/MGqvQxBeGUI+rfz8ik93dHeGKKA+cLyb19V3qq25alC5hHq1IFZd3ZdXPROhgHYE8YARKHaq2/qGT3n5/UY+T1Ffvb8eK0VkQGwDQMQgWqvNuCj9fhN8ruhVHt5H3+wATi1K9lF23291a+5q76n+5RWNpdffEWq2/Y7gVR7TfL75/w8Dhyo2mto92lhv05+dc2tvT356tJXWkNqLdv5t9xWJyOAtKE4zACU+g3AdFV7mfy6iIdf2M/FPh720ciP1WqC/GwAIp0EtH0MwDRVe80eP6ARf1TP7/WT3xrZAHin7RNtPzp6qjD0dB/rS9Wju85Xhb/IVHu9Han2muRnomvFPkV29vwjqfY6BFqNY7mZ/ACfz6cg0oHTl4qdnxU3um1BkWPhl7jGPerEbHin7yuhwk8/n2aAASiRAQDZI1Dt1Tb1MNG1nj+DyW8PI3/jODIAFtapqfYS9NFewPT8/FqAai+Tf/QIoLTunhxP0Acx0Tlc7vie7vOTwrr3bM75o1Dt9Sap2steP3C6L1SlHyvAOb5Gfksjv1j7B3zefmd9mOGt2l9eObzr3ELxXXf7G4DzvsAGYNqqvSb568MGfBzD88d9yG835Dp7AzBl1V5A8/pW4IBPgGqv6fljXSUf95lLvgYApIf3J4266tDTfd56W0G2/ZZhBE4c1V6T/Brxgzx/gGrvMM9vATr5+yW7Y4slzP/TASrrfqcKoU7gnbGvnH/bHY3hBuCiMhUMK5NQ7cV9uWrwV/AZRH6xmgU/kN4gPwHrzFOAI5gCjFC1lzBSpZ/hL9zJI70k4uHELKHge/SUi911vzmAx7Jry2ddncLpPr7FqIeOrFIOirYfyHuCqvbGgQDPb7HnZwSr9soCYIDn18lfEkM+c4sl5PiZc26s4mcCDGwLXvPt1dxbPlX3TwE+33py17lF56SFMu09qJDhFzm/M/Zorx2o2tur3qOI71ft9/Sw3yS/uhZwu9EAFwGjGgQShJVef+eqvVzp91PtlV/HYf9OyQ+PPxcXxHd/cSlBGvSF1t0/bW2tiU+Ksalns9beXKetwrInbbajOtSOevX1WfqQJqjtB+9/oqr2BuzoM9p8mtf3Ve1VbT5A7ePXyc/EZ5TUZh/0+lHlb3z8B4PbgrDbrfWt9ccLG+o2yN8rNU4/w43qZd9YTZ99XQ2RAEUVMARc7JuYam/waK8kPnv+/jYfMIz8yvPjujWDCIANwDiqvW4o1V5W8PEnP+f7weRfFAd2OCfPu6Xz7i91EtWOTmjxnFdW9FPXmshn/YZHcOosh/4npmpv8Fy/WekHOOQHTNVeJj97fvGa7vUB7ZQejgJiWBeKyRddXt4stLYM3QX50CO0QT9b7Nxcufdn66mXXVsjJ1B2dxOhY3bVmbxq79ABH/b84jn3+LWCn0n+2RsAx41KtZfJHxD2y04BE36gZDeO60q++MplGjMVnkTtMhNklnUlrHioldMBcd0/kpptbCRfuJ+IuZCktt+JrtpraveZIh5+Az6+qr2eAof8THwCGwP/Y7ml7p+o9FcufrDFBUE21ubPiQ2ASu0QOaiv2VrtbJX3PICDWSsUEVbYCOxUtTd4Nx/BGPDRcv6Gn+eXaLlYZ5ICgLgRqfZqxb4Azy+uddXePtHO9KtuSONILhVG4sNgegl+6K5f35RSveyrdITVv3neyUvL0Pf/+VDt5U09WIPJ7z/ay+Q3Q35AD/k14vcbALHuLbmn26WN5braLTjw8VT/D1GPEMTPTxUTG7f+aM3ZvYDcXxmBCan2hid/n9dn8utoSTTdWdUAuN03XdXeYPIzmPymXLcQ7jj72jTm92X47hMyGg8jGsDKQp/1jdRLr8l08/9FYQR+XlR76XkI8mOND1TtNYt9nPMD/p4fsLAWXaxzdpmMeLH24W+syHqMMMack0mYD9OgK+PRkdObn/jRWjcSsKuTU+01yc9tPm71aWE/e31ca2E/iK/WKFMAswjIXv/wtFV7h4X9fG2QXzuq69KE1PwzTut5aoxHb/sPW4K95yx18/+YIvuJr9oLEu+Q/MAQ8pveX/P8ajQYm33KmOIrvvuzzZ5OTZf2IX+EetqgjADt7lylfR5kBJYQBYRQ7Q3j+W3N80sDYOb7Bvn7DUCcU4BoNwOxAeDR3ump9hp7+c3pPm20l8Hef4/TuOUHhmbfU2Nyn70OrR3Zgrr2uw36cygKgCEQ3v9EUO0F/FR7g3N+g/yANaLnZ+L7h/6WLACiTbdQSv76FZXNPBcAlXLwWA9+L2/iWt+kbs4NDRr3rlKxmD39uKq95qYe5f21gp9BfgGD+Ex+eR2PMgVgAyAJfDgK1d6AAR9AH/CRUOS/yE2fc1NG/ZDxYAKP/eBJNPXAh+eVB7LUWkpSKgDPDUMApBgWP0elHsQHpDFwGSlNvYcr/5pqL5PXT7uP5/bVfUB5fGU8aKVrC8jjWiIPaANAivy4BrTtvOK6KKGihCKtCgW5lgC+b/M9eq9cgbI31/X+jYPfb8sqPpN/Zw9DwYnOKuw4MAC7FkHinaj2mj1+k/y9o71Dyc9rvBezigBEjn44ItVev9FeQCe/Wl21d59COqd5+2NNLfTHuuOHPojS+PgPm5SjJhOnXpoi2Sk/pE0sDUKmH4sZV8fuxayJJR05E4s68iaWdBR0eAKLOor9WBqE0mAs9qIMUHG1DEOw/BtXVbYaazynETaCC64LYKRbOInMHx9sUD0AUcDYqr1YNfJrIb9/wU/L9w3yq2v6+7Q8QpSKQNwG5Nx/yqq9JvkJno/nB5Ref0Lo9T//I8nNyqoxwTeZT07/OOpmrrXpPWcxdWTXBxJHYxcmyWtJXADgehmga6zDkPLDEb5OByAzCEcAvs4CR7EORw446o/8CCiMgKIO56SLizS9VyAJsJaRwk3iwZEETxQeeGQNtQAyhDX6jIZX7TX38vtV+nEdSH4mPcChvyT/CshPa8QRQHSqvVq+z57fKPjxvYQS7sj/7R3m7r0JPnpTCiy1Kx+uF/7uM6XiP32uXHzPvYNQGQ33VI9d/6NAtR/3jIKaWv1Q0K411AvvvqdeDEYj8HXgXVjvZqj7/HqzF/Q1Tfp7NQvvvLNBR651+rUX8b+JGnIe/f5pfpP0H6rO+Kq97PmZ/HqxDwhBfs77BfEJMvxfmUENwHIE8aNR7WU1H0nyQPJDsvskGACc0//t2oTDf7M9KP4bMEn49GNS3hmrUfafiiGHjWlvbC//5tUoBtYokhxftVdGAIE9/mDyK8h7gvwr8utWop4E3NQMgKHa605UtTduDviA9AIm+QE+tONCt3XXT82psUk/2ABguORpTANIs6bCfTzMCc/sn97SpAJyjeoAY6r2Mvl1zz86+QHbj/wERADCAGxHZgBo3eymABz6T1W1138770Dyq9dxaIcD9Z4vHT2m3jNtr9xbnDresC1h3A+DaP5eJjjFwi/9MfFCIJ7SeQ8tciA1SiWFpw9W7Y3rqr1Ymfw+m3qGe34mvyK+8vzurAyAywZAeH6s01btlfeCyI/X1PXTBuDnDLM3AOFVe7WwPyT52ev7hP2zNgDWsRRgWqq9/n1+i19jA8ApAK7nFiNLAYzDQDemEAJv/H+GlgJsR5ICtKgVqFKA4NHe4Ok+f/JzTUAv9rHn59dwTQDx8TxSAxCXBiAuagARqPYGkT8BKM/PsD3qnSdwJFf9qu/Up1kE9NtySv97ugg4KWL2RVfTKgLyb49TiJdf8lEi+DwVAdkA+Hl+LvaZ1X5J+iDyM/EBLd/n15j8szEA3AVw2fNPVbVXH+/Vye/1e36b0L1PgyWIADzSkouuDUhPa1c/3Mi/7fZy+V+/UC2dd6ha+pfP9+B+rIPxz4GoDUIRK6NeJJSGoDgEJUbDwHvHQrP03vsC8PmWH+jPbZXf94VW/u13NtsPJzq6HNiEOzncBvxxfpM0IGvYDzC2am948pvVfiY/VglbAa9jBmA1cj0AAhuAKav2MuIMzvkTgPT6gIoaxIk8ND+eSP7K5anNCkt5TccA8O7A9rcSa5k/uDF/eNf7Ekdi70+STBgP9wzFBYAx0HPERCYYFwDZIyMO+PgP+lwATGrIByiOgBLgkGLP0dgFJRL6LHpnXFppf3N6BsCUFvsuBoGqNO2I4t64qr1B23mZ/HwNDAv7mfwcBazOYi+AG6Vqr5nvW54ivoIj3++RIVBn7+NgDoh0tm5/rDXdNIDbgMoerBx6cpUUZ/IUhSx7u+00jQeLkV4X4NFeHdl+LA1CzsSijnw/lgahoIP+ToNQZCz5oWRicRDKjKXBOHVfhQ75qMAAeM+9rFL78MOrkPpSBrwn6pqwEedR4PRrbmxiBgD5//iqvf5CHrzqlX6A23wB5AfxxRrpdmC0ASVhp6HaG0h+veWHsL/HeOBeUq7Q5yMPfLGXOeemLG8GYhWAnYaNgJH7b7LQBD64tcu/2aAPcgZenmYTMvShUht8WLWXwfp9g8/tywEOriXo/UBOQ56v4wQba14ixxr9eM7yXr07+giDNvUQjE09QImv+Z58b0mizJt9bKxAuUfyq0w7KYn4F5edufly4R13NTtOZVNN/wG6FCM9m7j3X7n/iQ6Kf8j9x1btDSb/8B4/v9ZL/lYf+Qm4xhp1BLDpCVKykMdkVXsBa0TPL3L+Ps/vyrUL61gUQGKSDd5JNpntwMor8TWviDaUgCip12xgpNc5aT5NwyUpGAEYA6Xd50xOtReIVLUX23ZxjZWfW4C8B5JbZb62y2pVxKd6DSnxLJQR+mdefbDe/oandBpVBwBPWYhlk7d1TmI7sHIMJBG2nXrFAfL+86r6vyPVXi3fDyK/IjtHALS6kvxYCUx+rJwCbEenCKQiACb6UV21d9LkZzD5HUDl+9Lzy2tFfjyHTp84nz9x5qXLJAjSCRAECacFwPLh0utzRND7AVbP248sr2Vfd0sR0YATm0+7u8kQxODFT2jVXjYEDI38Vh/5XQFxpHeZ/v2C+MkXXFFt3vpoGwZai6QU0XtVnJQR4M4uEGr2n/2A+jPLFz3QFr3/OZH771i1lxGC/BzqS8IzmPTCOMzCANicAkjPD/JPRrUXsIZN97HX767q9aT0/Ex+BqIGIdUNzf70yw9kcXafDPlCSYLx17CHx32cFbC10tmSH1pdY1B6LU4LsDZve2xl+cVX5WmvAhkCC9t61Z78E1K1l9aRPD8gdf7LAJGt5D7LLpcveWiFdmxu9RGfyd2XVnXc6ibNdqwrI4DvrblFOLwkWOPmH67Lvn9jQqq9THwmP0Mjv9njZ89/LNTn3J8g1h4DYEeXAuA0XRB+gqq95nMz7FfEBzz29rYe9kuwIYAQByS76QOXyLz6xtxmrslGYEt688AHex68T4X2qd87kM+89ubC2qOZdS1E7f+8aR/kzfraVnXpq3XvF5eyqO7TBy8LOCeoai/A5LcM8vfk+dDjLxHZSvm/vr2xjjP/+PvGXl2vp6xtbNev+1478cv7q5Dyru1/uM1Kv/z9DngYoqCK/M7ueZBdFvziE1Ht1a4DPL/e41cTf0x+rB6Tv88AeFEYAI83A8kUYHzV3mDPz2G/M9Dzg/hAXCM/Vr6ndPmh1wcjgEhg+SVXpgfJgquQXh9BVR+y3nHi1S877eQLPoLDQJbpA51yTllIoV+/kWlsKE+mPphcwTbrA52j5Y3C2z9TcWKXZIgUVBugSn/MhiEAeU8U1V7N8xPktYsV3l+E+3tFiy999vW11QePrPP341jkJMCk7t5bfehoJ/3y6+tkKMtObC/26VfJmFeK/3B3iyIwETnoPyOVFvSueE2TBd8un//FNjy/M0fkj4H8tE5AtZfXQZ7f0shven6+Vp4/rvL+gQbAjdgAeMoA7FS1F/Af8DHDfgKH/f1E9yW/0uHD+6DZRxNeSeeU+SQdDFLpeNWOvh2UOwYq2cd/fE5g8d1U0NtNpN+1kKJQNg2gqEeeKZX4pQ9m6x/9TnNrldMCoz7AH1g2KF9z1zKvuqmIaMCJLQglH5AYacHxr9rLnl+R3z0W7hPx57p5fuJ5+yv1A99rw5vz90Yxnz2zIihFB5v5N9/ehFovteWEWKcbk6q90ggkX3RlvUGKvvL7zdTXH2yERdjfuvvxTuql1zbp+y3Cfib/ZFR7R9zU03s9qODHnp9JD6xQ3YhWIN7mGkB0KQAENyeh2qsjwavV2+MX9znPD/T8yxr5CTYbAZLvRl0Aaj3eLyyliu+4q9S688etjlvpbLXpE7gpzQGteN45Uu40P/1YK//WO0ruaTYGdPD+tBdbTPceykleLkMeKo2hntTLPpZfuf/JVRVE9H6w/dqG+GCSrNhK8lcvz2OYh7wSZL6EESCA6Mehaq+Z86PIx3n+RSX3GVa5/P5DrY18i40ih/tGeoR6QOWSL626z+6SnAhaBXpO7sE1inU1Mpb4mirt369X9n55lQxph+o8W1udLTbidI3fs/2tJI4Ga1PaJrb6UrW/Tr+H2so7cdXeHjQDyK+H/asC3OYz8n7iX1vea89CD8BzJqDay+/3I79tkN8d2fNbgvzmGX02q/buXoIopzAE0PLznrmUSv3Wf2Qz5xzM02aQQua1N+WXX3J11nvGUhoDPQS8F+/rle/O9B3SGbMzqO5TWoCWXzr3pv8u02hpxy9fHVToQqGyfOGDdfe0eI7+TLQMc4DDpD9uVHt7PT+39ZDnz5dA/twbP1Vf+5+s8e+nX0aBFOE59PmTL7yiRkaUwv04eXpIdAvSa2fyywM8Yovw4DX681AbqNBaS5zx4XrqrGsbmdff3My84eZW6uwDzcSZ+xtkLGrw+GrIh6DyfXj+aaj2MjTy+072YVU9fiY9oJOfYM/WAOxYtdds8+meX97nHj9P+lkjen6AT+ZVMt1sCEDoxRR5dBgD5PMEGt8l0IrnuE+vL6Xp6/RjuvhkXgKr9logrQAROO0+08qUz3+gJg8lUWQ3QlNVj2BpqkIn/1efrtDfJUthcFaIdcZQxTfInxtEfqxc5DNVe3GPFXnNHj9g9vg531fkd7uGQOb5lji+K/U711RbdP6e+LdpEdCgPB+z/pk/ghgn8vwFQXzzlB6Aj+gC8NzBGrOxdVfco9SMcAkR/WKJS+j5XjHPj/Fe7vHHI1Dt9RvwsQ0DwMM9AOf6HqDID+ITHCK+wxHA9kwNQEjVXp38CXPCz1bkT/SRXwv7+bmZ8/sfyw3wNYwACC7fkyIPRjk9QzzvP6JLJz/A5JcTfvKI7q5S75yF+kA68fz9ucaN329trxu97mH1ge2VLx5up846UMJ8P5EjB5VeGdpjZfiQXxgL1dqbI0Lvtnm8Fyq9c7TGBOmVQWCvz+Q3gFCf23q2kO5OnHFZuXb5t1Z7WqNGz76vCOpWNgvv/GyLqvAVIivCfe2gTj/y28Bg1d6YTYCHZ+Ce/HpTu0/AnrRqL8GSMNp85nSfTv6B1X72/FiFQYjaAHjKALDnd8Kq9hrEN6f7dPKDwEE5f3KY55fEBzgKYLBBkESHUdAID7A+PwHXxpn82mEduIcVEt1UH8igyJd+5Q3F1a84a9q0m9437DMQ0KmjTSqtxJkfKsAQUHQh5LsdrgMIomvkB/JETiHZDSNAXYsCRSV9m3ko0qHXFgowApDnprUkIwLD8xMk+S1BepCf3l90Tl4oFd/zuSbO7OMuiH+ev9WkNuilX1/1Tt9Xhdenfw/n+eOczGuq9irU5Rqpai8hgPxmpR+rp5HfAfllsQ9wFPlnGQE4XUI7O1HtHZTzO4r8tOqjvbrnN8lvBXh+u5foxuGc2kk9WJn00hD0nc8HmEdza6O9fFiHg+cxG4aAwvluy6/w1jsqdGa9lh9zWjCIOBvZ5iZ1L+rOqXtzlBrkiDQFwAH5e3v8kvgAEVQQ3TttXzH98usq+b+5XWz5LZ93qAk13uwbP1FdfsGVFHrPY0qR3ru3awh2KUPA030i3I8h3F+Uef6Fxezrb621H0mZeb7W1lOvt+78yRoV7XA0t2rrScIHk7/PABy/qr0m+c1JvxaTvrv6eX5Fftx3uisQfQTgaQZgfNVerKbn5w09TH6N+DqWAflacNhvkt88nJPJz8d0sSHwO5c/7fA9kJ3JD/D5fMI4EGFzALT5/4+9a4uR7Kqu3TNmbGOCjXkkliOSfEQIhAElUpRfJJCIiIT4sAhC+eIryR8CBQszc++1GbAtS4FgCfMBREmQeQgsDB/+MgQh8mESGUsWUaS61T2vflRVT7+mu7qrR5x16pxZ5b3r1Lm3u/re6p5rzdI+dfox8+G19z5777OOqXQv9ZKXNtDPDkzCmZVuke3+z9X+tb/5D1TAl0w1e/hwx3w2JD5gncKjyybiY1Cpt/Gt32ybdHvfkZOtTT/NvNk/MOfwfvezL5qC2ZM4xxvn4d7lR83ARX4Q35/zL/35V9fMVOMOi3js54/9N798Ze/ah/9tw/yb4TxA/HHv8vfk45yRN/lnWbVXkx+W5NeVfrc3Gvk92V0GMNYBtCutASBak/SlVXv9mkM+jPzs8xeN/LrVd9Q3+Znq83HOtie7SPsBT/iWu52HdeRZbmvR6zejwNfQ8jP97JXN/3xlG4ThWHG4PuDlq7Z+/NrOpff8K+oDS2bQZnn4Ok+2goh/+aGvd8215F1LQHL9dRJjVNzl3zFY2RqYd/O3WneeXzVERY3Avszrz/lmerG79vgvtg/Wd7XTIvGZtVzZGHT+8adbrXMXcM23N0z3SXxBftg4+Znez6pqbzDt55k/dN7Xkd+THoTnZ+cQqpUEowM4rGovU34R+UHuieTnnor8jPqAfJ03/DIv90FsH+kNSH7Ar8WZ/wrJ7yb04pd6sMchn/nUPs9l0m/7Qo+J1t2dXy/2xWUi4QhuqmvH5t78Vvv+iyD+Es74Rm1nwxTi2GpzkdhTXV5n5qQcI7bpm/cX/+xpXNHtmEnFTuvMo52Vv//RppleHIz83mA7E5N21//l1zsLb/+KO+enIL5L9RX5gaKRX5F/dlR7w+TPi4z2+iEfpvwAiM7oTwewa/Z2qzsCOAcA4h5JtVcP+MAGBnwE+UlgSX5YD5n2B8/7+syfAjzv65Sf1f7xd/ZJ/MCb/PJpbmQNhhw4Fiyj5WemDJdWP/38dTOluC+IFr12vPKpH15fu/iLLf4cpdBi/zHL4CUZFPUuP/TM2pW//MYajghjCpeAqmFs/+z/+pff/4zr51/oIt13Azw9A0b8MuTXZ36q9c6Yaq8mP8/5XKei4Afik/wgvFuT+MwGdl0hcLfCSUA6ABK+jGqv1u7jOZ8ZABHs8Uvyi6hv9yNpPyM/wMifibRfpfws9hmIZ7l11I9f6vF7VsQD1X0Akl3tt1xcWXvil5s4n08YKyYhSWOm9vhyQS1E5SjgPPDXrm4dDES6z+8W47uvLu8vfey7G8aR4dIPiN/L50H6hJEeNnzmZ4pPcE+f+WdVtVeTX0d+Od2H9a0JPxb8FHYBfG+FGUBGBzAka34E1d7R876b8IsP+JD4IvKrlD9j1X8c+bnHVF+QH3Bfl9He9vhFtf/I5AewdpeA7Iu8pj6whJbfpXd/rWOuwO74m4uBsWLsOeKPnsexOJzCsdY8CF/THaxsH3Q/9+J2fnfaQ5HPOLGeAYjfc5Gb0T5w5ue+7PEnMfLPomovya8EPPSFHh/5W0zv7ToU+WfAAbDqX061lw5AD/gkkcgvK/3h8374zJ8AlznY47MBkl/3+DngY+CKfcUiP0nOtJ8/E77UYx3BvC0UmvUXl1Htv/aRf+/t/ubqhLFi/4frQ//HrEHpJYwSH0NN6998eWfhQXtNt2OGnnqmaAjSI9Un+UluRf6CPX5PdpH2z6Zqr478erS37Sr9gIv2zgkAOu23IPl5BKjoOrDKADjVV1a1l9p90Us98TZfiPwA91TkBzLAOYEI+f1nRvwI+UPyXUBKwvM+v5zpB+ygj+/1o+9vKunLRkZ8w1w7HgSmCUXUn47uIXuSzDjMlei+GWpatyq+8+eR7nvSG9i0n8U+IjLaG4z84glu9vxnVLWXt/jcmp8Z+QFGe33m12k/1qlyAHl1DiBzNYAkP5Jqb1DEI4lEfnwuT35BfF/xxx4jP/YCkZ+EFz3+sIJPOe0+faEHcLf5sLa9ffTmVyDVba4dr65/7b+3UWkHGSXrj1P63Awv7a/83Q82W/Nf6JqBpq6N+PM23e/mrsjXEmk/rT7vC+Jr8odT/uszrdoLwgdv9CHqJz7aY0+RXxGfkR8WkBlAZYNAiyD9kVR7RdQvEflHrSS/h4z8Mupb8ueC/Kzaw1K1165JfEF+QJNfED8W+d0e9fs42muthZftsmO98+eHvf73PdPd+dWiVyM6tsdPfM3BdCYG7bde7CHqm3+HO+en3ddFfUb+KPmdFUi8FW0+rEn+E6Ta6z6z2MfID5sVIj+JT9TVBaADKKjaW260NyH5i432AoHpPpXy8zYfo73u8Q/hvj5N1d7kaKq9/mLPfLq6cO5LRkDkM0vXn/rltpvEY4XumJ7NwszBpXd91UT4Cyj0gew+8mONNl8h8ru1JL488/O8T/LD+vUsq/Zu66gPJCS+Qasc+b3dGXEA/TruAixOQbWXUT9e8FvkmjY23ScGfADsk/x6wOeKu9Aj5vpnTbWXcl35mfMrO//V7vP5M8vYY3k409calj/5vU0r6HnWOoCuI/0aC3+O+EHyh3v8QMHR3llX7Q1X+t3XWqXSfk1+NwjUr+MuwOIUVHs1+VkLKDDamwnyByr9+Czm+rGeMOAj5/r1dF/9qr3WWudw52OrRu6cwpqM/lN3AH5MufuZF7dxBMjv8NV+G/lVtb/8jb6k0HTfCVLtdSD5BfELn/lJ/sTv9Wt1ANNT7dX3+Ils8Yhz/Y7sOu2ntRBRHwjo9c+Mam+2iq8vvOnLnf3L64MqHcBa8vMbmPAzDsAV+5JeefKT+Crtj9/mOzGqvQDJ7yN/Vo78sCR/HxAOoMrLQNoBHE61N05+OdHHdUKoyK+n+0SxT0V+f973xFfTfeFLPXWp9tIB3HNxdX+xWgfQO//StncAtvAnyB8f7QV0pb8w+WdftZdpv2j1qZQ/nvYL8mf1ZQDaASQLsCVVe8uTHxZg1J945gc42Ye1iPyM+KLNFyO/nusHuetQ7QXsz74hXe2/urRXpQPAzT5c7oEDEOQPX+cl8QFx3k+Kkv+EqvZmTP0j5Aep9Wem/QbO1u4Akva0VXvD5E+L3Ogj2bEn2nywDj7q88zPmf4y5IcVSKpR7QWwN//YqunDr2z/5He7LALePLYioJ8DMIKpmPWHfJfo9Re8zqsj/3oB8p9A1V7KdkXID0vywwIs+PX5NazrcgC8DnwJ7b2pq/Zq8luIVl+Q/Gz1pd4ZULV3NO2XlX4R+YmMVpDfrxn5E7+uRLU3NxbPcEPBxwiKbPGF22NrA1ryQ3LbKOyiDdi7pdEfFe7UAz4GhdP+E6zaG73UQ0tgT6f9JH/9GYAhIId8jk+1F1aSH1aS3xOfpI+p9qaAOvML0uszPy0jPogvW31HUO31hI9Jdjsxzo65cbd65a+f7Umln2mSf/RBVSNA0rfRfx7pf5nRXqKEfNdJVu3FWkV+rgPFPoKEV+Tnnvl79lgErNIBVKDaS8S1+xzhi6v2hgt+sIr8bi8y2qv7/LRh8vvhnhJ6/Z1RQLXnxs9bnAUgcac9A3Bz6eHnNuEA3P3+Q6n2Yi9GftiTr9qbRckPEKmM/LAB8lu7Z/4f3qtoEjCjIIghqIv8i1Wp9sbJn5ZX7Y1H/iUgPNdPsmNPkZ49/oBqr7M+8jut/mLkT4dZwFlkAY+sLH/8u+sgKN/Gs8SdYvSHQtDCHkQ8p6Laq3v8p0u1N07+0HmfBT9YTXySnxlA9TWAU6ba68GoT9KXID+QBSK/Uu21eyR/KsgPhMg/uh4Kd0Kae+v513b9E2OwR3ECnvteQxC/6eqHvr3htPtB9Ea1N6LaW260N9ll5I+SH6Tfw/kftl1RBkAHANK6Xj9spaq9bPMdi2qvOO9jfzqRH1ZU+9uAOvNnE8if8qUeA8p0w57vLPzJk919c1mHUZtOoJwOAH/UO5O1x1+6MRT6wFNdaaPaW0C1V1b6I3P9fQB70chvLFJ/fG7DVn0ZCMQcifwL9aj2pseo2gvLyE8kIfIT+jqvHO2Vkb9M2s813+ZbzWHPZHigo3Plr55dG3RvHLhXcMe9ljuJ+Pz+EV3Aje/8764pNtqqf6PaW0a1l6QvQX7YEPa8BdrVO4CMRwDO+S+cUtXeSOSP3OXXc/2W8LmzBMivIv/K+LQ//Ca/dQJnh6/xmq7AdYwHu9YgpbzwJywH6q77vV5ybP0bL++0znzRjvo6Df9GtbeQai+JH5vuAyYW+xj5SX6VAWTVOQD3zPZCfaq9WZWqvZG0X5O/wGivTvuJlXDk1090AXyWG0XBx20msPjOp3rmTQB0Bqjp55wB1p71WANOx59vA/R2Dlb/4YWt4cBP6h/waFR7S6r2Rm70ifN+GiR/rslfnwMwACkXbjfVXt3miw/4AO3x5NfFPk1+7JP8xK3IT0eQmTUf60RNwBTsOsuf+P4mXuRxtQAKiDr4s77fxwtF68++7J7o/rwr+JH8J0W1F7ZW1V6d8hcl/2408sO6zMF9rvYIAGJy2u+2Uu3VAz5+zfaedwTizM+obzDuvE9MSPmD5CfcO/2PWaku3Ntv3XGhe/WD316//tSvbkDHDy/yIsLjZZ/B8taBeb9/f/O5V3c7//TC1uIfPw3imyzivCH/rbf5T5xqL1C/aq++0WcQSvuJOPl95Md6v4YjAEiZ3MaqvVTxUT1+lfanhaf7gAlv8nNN8hsLZLR40BN2WKnvtc96vT7o9/1zB1r97bu/1Ft8x1Nriw8+vbZw3xNr+R1WytuAxGfKf6JUe5n216/aC4RGe/uxAZ9R8rcV+T3xs/22QZWjwMwAGtVeQf40OODDVJ/kh42Tny/zsuCXjJA/G09+3shDNmCQDaW64QzmvIzXeQcM9qTDVP/sLeKfGtVe2FpUe+kEIuQn8T1asOHID2uJj71aHUCj2qsHfNjjD8/108YifwKMkh/7JD8J3skl+bHPtQW1+1DUAzKAZ/whTotqr7U1q/YWutSje/yM/Ejz3ZrkZ+Sv2wEklvCNau+kyJ8AYfITJL9u8wFdQBT8uuwUKPKT+FTtlY91AKdVtXe7dtVegiQXkV+SH2tG/bGRH8C6ZgfAtH+xUe2lam+ZyE+yB8jP837Xr0l+WEZ+mfIPkd72qr0i6lep2hsmv8YeIMhvrCY/13VkAJwEtBlAo9obUu1NAmd+FfU7tIE2nzjz5yS/hSB/z4Lkx16j2kuA+FWq9k7q8eu0n+f9UOSfrSNAo9obUO3V0326x499PeATifyi2KfIn0nyY33bq/ay1Vexai9tuODHyO+jPmx/lPzWkvwEnEUtDgAEdKRvVHtDqr0A5btgowM+LPYF0/5cRP7hmlHfRfsu0/+0Ue0F+atX7eU6PNo7mvYbcLovQv49WLtXmwNoVHsjqr10AoQa6w2c+QGumf7zvD9KfgdGfq4b1V72+OtQ7Y30+Bn5c0l+ElxHfrb/BsYOanMAjWpvXMEnPtqbiMjPSr+Hr/bn3GOUxxoQkR8Ebjk0qr2w1av2hsnPtS72ASS+jPye/I741lZfBAQhG9VeRv4g+XX018U+febneZ/Vfp73Lbhm9O/6lH8IRv1Gtbcy1d7y030gvE77BfkVBjU4AAqCDAt27PM3qr2R0d5g6p90gpEfhPbEJ0D0YNrvnuSWUt1rjWpvTaq98dFeTX5G+GDkD2cAaXUOICfxLzWqvWERj9iAD6M+IEZ7Iz1+h27LpfyALvaljWovyF+9aq8mP4t9kvzR874GiA+bDqpXBAJ5SfxLjWpvUMFHkF+h6y0jfaoGfNj/xzoY+Ul+olHtFaq9rYpVe2E1+VPZ44+Rf6AB4tuvVe8AcncEaFR7y5KfQh6yzQeCc81inyM9R3vVdF8qevxA2qj21q/aC+wVIP9eQfJzzer/SAaQVeUA8A+whL3UqPYWUu31CJAf5OaZH2hPHu2FLTLa26j21qjaS/LrHr9o9ZUlv7fCAVQrCHLVHwEa1d7xc/1EMiHy6zafA1t9+rwvhnwU+fG5Ue2tU7VXj/bqyE/HECU/ic89fK5vDgDkbFR7C6v2kvCFyN/L4+S3ZG+NIX+j2jtbqr280Xd48hMpsO8s9g5yoB4HQMI3qr0x1V6t3Uc7UuwLFfxAfHGjD8jHD/mcQNXexJP/dKn2AmZPFvxKkp8g+UF2A6xrcAAgrI/4jWpvXLU3GvlDIh68zDO0PPMz4gvyn0zV3uQUqvayzTedyE+A9G6/xgyAxL/cqPYWV+11Nkr+FjCM/BTxCPf4gUa1d7ZUeyPTfbrHHyj4AYz83D+o1wE0qr2HU+0tNtoL0mvyh6f7GtXemVPtLT/dJ8nviU+Q/HQANRUBvWJvo9p7WNVekn/MWG/RyN+o9s6waq9o85Uhvz7zcw9Et8iPswZw9wQHAPKB9I1q71FVe0F0fd7nmuQXaFR7Z1+1F1DkD6X8XGvy8+t2XdgB3H2Mz4Nf8y2+RrV3+qq96O+T/KrSf5pVe7fKqvay4Ddzqr2ByB8lPyzAVJ9r4piKgHcVugsAIrrI36j2Tlu1F5YKPo1q70TVXhb86lXtPSL5U33mJ8kHkviAI7wlfsFR4LtKOAAeAR4OOACX+jeqvY1q77RUe0l+2Ihqbz511d50eqq95Ud7ZcEvTH6ub4KP444AD/MIcGgHcJ/zHn9oftkHzC/tjV4HdhG6Ue1tVHuPR7UXtjLV3myaqr3lI78+7wNcEwMLkt9b6QB64Cy46zh8X1kHcM/QAZx7B37JJ+b+QjmAtiUqo3+j2nuSVXuzE6naC8y4au9embl+Ej6Nkt9acBFrOgCsrQMAZ8Fdx+H7wOmyDuBekz68Hb/kb+fe+17zS1fcEeAAAFkPodprbFS191qj2gtbpWpvun77qvZmx6raK9t8IuoDEfIr3PTWkn+8A1j5qOEsuOs4fG8RB3DG4A6DOw3eiB86N3f2bcY+8Kdz97/z/+cu/NY5gIEBbMfgMsmfWAgFH2tV5NcDPmHtPn3OD4p4wMrRXoCEJzzBPXJHfhI9rtoL5LRU7XXk5iy/REKLtF0LdxIc6iHpuZbEd9Dkd59vpfktMeBD4U6h3MM1oSb6dOTPqdrryS7WxEifP6zay7v8Mb1+Ej6s2ttXFmAdYKxwp18r1V5a7QDC531L/nxC2p+PO/PDkvg32QHgdWBwFZwFdx2H73WcvtNx/MwkB3DOffObzeZbH5h784NYvzL3yHfcEWDPwFuQ/HKLV3nhBES1H8gsmBmwADhcp4SW74JVjoKRn2g5J+HUe9yajoB3/OkkmPZbJ2DRhgWcc5BtPuf8/L19Anu6/eeQEq7Szws9QCYsvkYnwDWQEpb8zABadBLWyjpAi2taF/mHjiAxYD1AtAQt+WFzWK7tvmjzbeUWGaxyEm6oxxf6BOweVXuZEWg4h0BRT1UT8HuvywZaugsg0n5dDPRpf87qv7MaXrLbAJYY7vs2H9t4rqoPcOiH476W7Aq8CeiwD46Cq+AsuAsOY+04fa6oA0C/8A9QPXzb3D1/ZOz9P5z79EdHOgAHI06g64n6+3bOpqepIArDB/pFIbQUW0CohC8F3LtQMS5ETVy59ZcYE2No/4ULN/pH/ANujImJJlS3rFwbRee1Z3jJmcAN7S0Scm7yZGbuvbkzNHnOnJl7w36A9U6KSgsx9ZzWI3vHOcA55d/MzhLwnJIIC3rc7OMuPjEy4zpnddDTVL8Hjl8LooLeUdnRkgKrrAZd63Pm/9Gnq6jEgNdU3uPsEbTjrK7ENkCd1yGsikphMWPHtkntVfp0g491lR3i9/ryR7kjFBuwzXQfGMn3WYfIKrkF8jPV3z+iY8FaXomSE9L5CZLZHlBu801/isqbwn/kEUub9jMgqNwx7Y8k4pNfKOEqnFV3G+py9bQAIHqy0L+JbwLGZaw5I9U2HvhRXrz5HiIMfkwM3HRs6KI8C79ZnnzPSdj7LgrfWDd0c+6re5Gfc2gxvw3XsCgt5r4Rw3GMlC4YeixxLwBOwk04ClfhLNw1bwDKcFxd55FsBHIfoIaHlaWASLK0K5urn+Xle3TElEaFO8cfJKWb0R7qWWDgvwUlye7vDIKBHOTsgssXhMhlHBNRD+Ek3ISjcFWdnWX6D6fTDcDTlwGaBQSak1LGXsDiY9le+yDP3yJtQaeanvxxHOfcOYSDcBFOwk04qq5y9jfpf1YAsK8DaxpJ5iak2A6pxbVQb72WZ09Dp+++yKtPYdfxAF8ffXUcZ+SoawdwDw7CRTgJN+EoXOXsb1//pQEg3QdIs4B64Eo/CJSWajKBNGMB7TmZvnFfNm49kZu3H8n2nYeydXdXtnb6bO48kM17juMMBhyKPsEtOAbX4BzcU9kX4CTcRFtdrdvZ367/M7IA7gXYIBC42pDJ5aZMIeVYDaxouR7YEHLdcZyh2SBwjM7BQbgIJ638XPtnz/42CDALSIPAbKAVmA8sFmW8XZbickWKK4HVshTWAuuO4+TOGhyDa3AO7sFBdbGlblr5Oftny88s4JQgUAvMaGfNmIIgAulglpS24zg5Qa8W4VpcgquDs+pk7WT5OfsPEwSqgSkTCBqadjSVFgZmmHcc58xYj1rRM3WuYcSHm9Us+QcNAiV+JBQ6YUYwrQOoKzNKw3GcnKBXdaWm7sUZvyr82Kc0rPxpEEgDQcUEAzAVMwTHcXKGfk0a6StW/BzkZxDICASgImTCUHUcZzCsT8a1cob4lD+3IEAYDEjJcZyRUySUnmTIn3swIAXHcUbOOLHSn/8x5jjOf8IPP/zwY9DjL7+Syzb5TVU1AAAAAElFTkSuQmCC\"")
- _ = packr.PackJSONBytes("./files", "playground.css", "\"Ym9keXttYXJnaW46MDtwYWRkaW5nOjA7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjtvdmVyZmxvdzpoaWRkZW59I3Jvb3R7aGVpZ2h0OjEwMCV9Ym9keXtmb250LWZhbWlseTpPcGVuIFNhbnMsc2Fucy1zZXJpZjstd2Via2l0LWZvbnQtc21vb3RoaW5nOmFudGlhbGlhc2VkOy1tb3otb3N4LWZvbnQtc21vb3RoaW5nOmdyYXlzY2FsZTtjb2xvcjpyZ2JhKDAsMCwwLC44KTtsaW5lLWhlaWdodDoxLjU7aGVpZ2h0OjEwMHZoO2xldHRlci1zcGFjaW5nOi41M3B4O21hcmdpbi1yaWdodDotMXB4IWltcG9ydGFudH1hLGJvZHksY29kZSxoMSxoMixoMyxoNCxodG1sLHAscHJlLHVse21hcmdpbjowO3BhZGRpbmc6MDtjb2xvcjppbmhlcml0fWE6YWN0aXZlLGE6Zm9jdXMsYnV0dG9uOmZvY3VzLGlucHV0OmZvY3Vze291dGxpbmU6bm9uZX1idXR0b24saW5wdXQsc3VibWl0e2JvcmRlcjpub25lfWJ1dHRvbixpbnB1dCxwcmV7Zm9udC1mYW1pbHk6T3BlbiBTYW5zLHNhbnMtc2VyaWZ9Y29kZXtmb250LWZhbWlseTpDb25zb2xhcyxtb25vc3BhY2V9\"")
- _ = packr.PackJSONBytes("./files", "playground.html", "\"PCFET0NUWVBFIGh0bWw+CjxodG1sPgoKPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PXV0Zi04Lz4KICAgIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ1c2VyLXNjYWxhYmxlPW5vLCBpbml0aWFsLXNjYWxlPTEuMCwgbWluaW11bS1zY2FsZT0xLjAsIG1heGltdW0tc2NhbGU9MS4wLCBtaW5pbWFsLXVpIj4KICAgIDx0aXRsZT5HcmFwaFFMIFBsYXlncm91bmQ8L3RpdGxlPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJ7eyAuQ3NzVVJMIH19IiAvPgogICAgPGxpbmsgcmVsPSJzaG9ydGN1dCBpY29uIiBocmVmPSJ7eyAuRmF2SWNvblVSTCB9fSIgLz4KICAgIDxzY3JpcHQgc3JjPSJ7eyAuSnNVUkwgfX0iPjwvc2NyaXB0Pgo8L2hlYWQ+Cgo8Ym9keT4KPGRpdiBpZD0icm9vdCI+CiAgICA8c3R5bGU+CiAgICAgICAgYm9keSB7CiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHJnYigyMywgNDIsIDU4KTsKICAgICAgICAgICAgZm9udC1mYW1pbHk6IE9wZW4gU2Fucywgc2Fucy1zZXJpZjsKICAgICAgICAgICAgaGVpZ2h0OiA5MHZoOwogICAgICAgIH0KICAgICAgICAjcm9vdCB7CiAgICAgICAgICAgIGhlaWdodDogMTAwJTsKICAgICAgICAgICAgd2lkdGg6IDEwMCU7CiAgICAgICAgICAgIGRpc3BsYXk6IGZsZXg7CiAgICAgICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgICAgICAgICAgIGp1c3RpZnktY29udGVudDogY2VudGVyOwogICAgICAgIH0KICAgICAgICAubG9hZGluZyB7CiAgICAgICAgICAgIGZvbnQtc2l6ZTogMzJweDsKICAgICAgICAgICAgZm9udC13ZWlnaHQ6IDIwMDsKICAgICAgICAgICAgY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgLjYpOwogICAgICAgICAgICBtYXJnaW4tbGVmdDogMjBweDsKICAgICAgICB9CiAgICAgICAgaW1nIHsKICAgICAgICAgICAgd2lkdGg6IDc4cHg7CiAgICAgICAgICAgIGhlaWdodDogNzhweDsKICAgICAgICB9CiAgICAgICAgLnRpdGxlIHsKICAgICAgICAgICAgZm9udC13ZWlnaHQ6IDQwMDsKICAgICAgICB9CiAgICA8L3N0eWxlPgogICAgPGltZyBzcmM9J3t7IC5Mb2dvVVJMIH19JyBhbHQ9Jyc+CiAgICA8ZGl2IGNsYXNzPSJsb2FkaW5nIj4gTG9hZGluZwogICAgICAgIDxzcGFuIGNsYXNzPSJ0aXRsZSI+R3JhcGhRTCBQbGF5Z3JvdW5kPC9zcGFuPgogICAgPC9kaXY+CjwvZGl2Pgo8c2NyaXB0PndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgZnVuY3Rpb24gKGV2ZW50KSB7CiAgICAgICAgR3JhcGhRTFBsYXlncm91bmQuaW5pdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncm9vdCcpLCB7CiAgICAgICAgICAgIGVuZHBvaW50OiAie3sgLkVuZHBvaW50VVJMIH19IiwKICAgICAgICAgICAgc3Vic2NyaXB0aW9uRW5kcG9pbnQ6ICJ7eyAuU3Vic2NyaXB0aW9uRW5kcG9pbnRVUkwgfX0iCiAgICAgICAgfSkKICAgIH0pPC9zY3JpcHQ+CjwvYm9keT4KCjwvaHRtbD4=\"")
- _ = packr.PackJSONBytes("./files", "playground.js", "\"IWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQocil7aWYobltyXSlyZXR1cm4gbltyXS5leHBvcnRzO3ZhciBpPW5bcl09e2k6cixsOiExLGV4cG9ydHM6e319O3JldHVybiBlW3JdLmNhbGwoaS5leHBvcnRzLGksaS5leHBvcnRzLHQpLGkubD0hMCxpLmV4cG9ydHN9dmFyIG49e307dC5tPWUsdC5jPW4sdC5kPWZ1bmN0aW9uKGUsbixyKXt0Lm8oZSxuKXx8T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsbix7Y29uZmlndXJhYmxlOiExLGVudW1lcmFibGU6ITAsZ2V0OnJ9KX0sdC5uPWZ1bmN0aW9uKGUpe3ZhciBuPWUmJmUuX19lc01vZHVsZT9mdW5jdGlvbigpe3JldHVybiBlLmRlZmF1bHR9OmZ1bmN0aW9uKCl7cmV0dXJuIGV9O3JldHVybiB0LmQobiwiYSIsbiksbn0sdC5vPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLHQpfSx0LnA9Ii8iLHQodC5zPTc5NCl9KFtmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1uKDMxMyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLGZ1bmN0aW9uKGUpe2Zvcih2YXIgbiBpbiBlKXQuaGFzT3duUHJvcGVydHkobil8fCh0W25dPWVbbl0pfShuKDg3KSk7dmFyIHI9big4Nyk7dC5zdHlsZWQ9ci5kZWZhdWx0fSxmdW5jdGlvbihlLHQsbil7IWZ1bmN0aW9uKHQsbil7ZS5leHBvcnRzPW4oKX0oMCxmdW5jdGlvbigpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBlKGUpe3JldHVybiBuZXcgUmVnRXhwKCIoXnxcXHMpIitlKyIoPzokfFxccylcXHMqIil9ZnVuY3Rpb24gdChlKXtmb3IodmFyIHQ9ZS5jaGlsZE5vZGVzLmxlbmd0aDt0PjA7LS10KWUucmVtb3ZlQ2hpbGQoZS5maXJzdENoaWxkKTtyZXR1cm4gZX1mdW5jdGlvbiBuKGUsbil7cmV0dXJuIHQoZSkuYXBwZW5kQ2hpbGQobil9ZnVuY3Rpb24gcihlLHQsbixyKXt2YXIgaT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KGUpO2lmKG4mJihpLmNsYXNzTmFtZT1uKSxyJiYoaS5zdHlsZS5jc3NUZXh0PXIpLCJzdHJpbmciPT10eXBlb2YgdClpLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHQpKTtlbHNlIGlmKHQpZm9yKHZhciBvPTA7bzx0Lmxlbmd0aDsrK28paS5hcHBlbmRDaGlsZCh0W29dKTtyZXR1cm4gaX1mdW5jdGlvbiBpKGUsdCxuLGkpe3ZhciBvPXIoZSx0LG4saSk7cmV0dXJuIG8uc2V0QXR0cmlidXRlKCJyb2xlIiwicHJlc2VudGF0aW9uIiksb31mdW5jdGlvbiBvKGUsdCl7aWYoMz09dC5ub2RlVHlwZSYmKHQ9dC5wYXJlbnROb2RlKSxlLmNvbnRhaW5zKXJldHVybiBlLmNvbnRhaW5zKHQpO2Rve2lmKDExPT10Lm5vZGVUeXBlJiYodD10Lmhvc3QpLHQ9PWUpcmV0dXJuITB9d2hpbGUodD10LnBhcmVudE5vZGUpfWZ1bmN0aW9uIGEoKXt2YXIgZTt0cnl7ZT1kb2N1bWVudC5hY3RpdmVFbGVtZW50fWNhdGNoKHQpe2U9ZG9jdW1lbnQuYm9keXx8bnVsbH1mb3IoO2UmJmUuc2hhZG93Um9vdCYmZS5zaGFkb3dSb290LmFjdGl2ZUVsZW1lbnQ7KWU9ZS5zaGFkb3dSb290LmFjdGl2ZUVsZW1lbnQ7cmV0dXJuIGV9ZnVuY3Rpb24gcyh0LG4pe3ZhciByPXQuY2xhc3NOYW1lO2UobikudGVzdChyKXx8KHQuY2xhc3NOYW1lKz0ocj8iICI6IiIpK24pfWZ1bmN0aW9uIHUodCxuKXtmb3IodmFyIHI9dC5zcGxpdCgiICIpLGk9MDtpPHIubGVuZ3RoO2krKylyW2ldJiYhZShyW2ldKS50ZXN0KG4pJiYobis9IiAiK3JbaV0pO3JldHVybiBufWZ1bmN0aW9uIGMoZSl7dmFyIHQ9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLDEpO3JldHVybiBmdW5jdGlvbigpe3JldHVybiBlLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIGwoZSx0LG4pe3R8fCh0PXt9KTtmb3IodmFyIHIgaW4gZSkhZS5oYXNPd25Qcm9wZXJ0eShyKXx8ITE9PT1uJiZ0Lmhhc093blByb3BlcnR5KHIpfHwodFtyXT1lW3JdKTtyZXR1cm4gdH1mdW5jdGlvbiBwKGUsdCxuLHIsaSl7bnVsbD09dCYmLTE9PSh0PWUuc2VhcmNoKC9bXlxzXHUwMGEwXS8pKSYmKHQ9ZS5sZW5ndGgpO2Zvcih2YXIgbz1yfHwwLGE9aXx8MDs7KXt2YXIgcz1lLmluZGV4T2YoIlx0IixvKTtpZihzPDB8fHM+PXQpcmV0dXJuIGErKHQtbyk7YSs9cy1vLGErPW4tYSVuLG89cysxfX1mdW5jdGlvbiBmKGUsdCl7Zm9yKHZhciBuPTA7bjxlLmxlbmd0aDsrK24paWYoZVtuXT09dClyZXR1cm4gbjtyZXR1cm4tMX1mdW5jdGlvbiBkKGUsdCxuKXtmb3IodmFyIHI9MCxpPTA7Oyl7dmFyIG89ZS5pbmRleE9mKCJcdCIscik7LTE9PW8mJihvPWUubGVuZ3RoKTt2YXIgYT1vLXI7aWYobz09ZS5sZW5ndGh8fGkrYT49dClyZXR1cm4gcitNYXRoLm1pbihhLHQtaSk7aWYoaSs9by1yLGkrPW4taSVuLHI9bysxLGk+PXQpcmV0dXJuIHJ9fWZ1bmN0aW9uIGgoZSl7Zm9yKDtRYS5sZW5ndGg8PWU7KVFhLnB1c2gobShRYSkrIiAiKTtyZXR1cm4gUWFbZV19ZnVuY3Rpb24gbShlKXtyZXR1cm4gZVtlLmxlbmd0aC0xXX1mdW5jdGlvbiBnKGUsdCl7Zm9yKHZhciBuPVtdLHI9MDtyPGUubGVuZ3RoO3IrKyluW3JdPXQoZVtyXSxyKTtyZXR1cm4gbn1mdW5jdGlvbiB5KGUsdCxuKXtmb3IodmFyIHI9MCxpPW4odCk7cjxlLmxlbmd0aCYmbihlW3JdKTw9aTspcisrO2Uuc3BsaWNlKHIsMCx0KX1mdW5jdGlvbiB2KCl7fWZ1bmN0aW9uIGIoZSx0KXt2YXIgbjtyZXR1cm4gT2JqZWN0LmNyZWF0ZT9uPU9iamVjdC5jcmVhdGUoZSk6KHYucHJvdG90eXBlPWUsbj1uZXcgdiksdCYmbCh0LG4pLG59ZnVuY3Rpb24geChlKXtyZXR1cm4vXHcvLnRlc3QoZSl8fGU+Ilx4ODAiJiYoZS50b1VwcGVyQ2FzZSgpIT1lLnRvTG93ZXJDYXNlKCl8fEthLnRlc3QoZSkpfWZ1bmN0aW9uIEMoZSx0KXtyZXR1cm4gdD8hISh0LnNvdXJjZS5pbmRleE9mKCJcXHciKT4tMSYmeChlKSl8fHQudGVzdChlKTp4KGUpfWZ1bmN0aW9uIEUoZSl7Zm9yKHZhciB0IGluIGUpaWYoZS5oYXNPd25Qcm9wZXJ0eSh0KSYmZVt0XSlyZXR1cm4hMTtyZXR1cm4hMH1mdW5jdGlvbiBEKGUpe3JldHVybiBlLmNoYXJDb2RlQXQoMCk+PTc2OCYmSmEudGVzdChlKX1mdW5jdGlvbiB3KGUsdCxuKXtmb3IoOyhuPDA/dD4wOnQ8ZS5sZW5ndGgpJiZEKGUuY2hhckF0KHQpKTspdCs9bjtyZXR1cm4gdH1mdW5jdGlvbiBTKGUsdCxuKXtmb3IodmFyIHI9dD5uPy0xOjE7Oyl7aWYodD09bilyZXR1cm4gdDt2YXIgaT0odCtuKS8yLG89cjwwP01hdGguY2VpbChpKTpNYXRoLmZsb29yKGkpO2lmKG89PXQpcmV0dXJuIGUobyk/dDpuO2Uobyk/bj1vOnQ9bytyfX1mdW5jdGlvbiBrKGUsdCxuKXt2YXIgbz10aGlzO3RoaXMuaW5wdXQ9bixvLnNjcm9sbGJhckZpbGxlcj1yKCJkaXYiLG51bGwsIkNvZGVNaXJyb3Itc2Nyb2xsYmFyLWZpbGxlciIpLG8uc2Nyb2xsYmFyRmlsbGVyLnNldEF0dHJpYnV0ZSgiY20tbm90LWNvbnRlbnQiLCJ0cnVlIiksby5ndXR0ZXJGaWxsZXI9cigiZGl2IixudWxsLCJDb2RlTWlycm9yLWd1dHRlci1maWxsZXIiKSxvLmd1dHRlckZpbGxlci5zZXRBdHRyaWJ1dGUoImNtLW5vdC1jb250ZW50IiwidHJ1ZSIpLG8ubGluZURpdj1pKCJkaXYiLG51bGwsIkNvZGVNaXJyb3ItY29kZSIpLG8uc2VsZWN0aW9uRGl2PXIoImRpdiIsbnVsbCxudWxsLCJwb3NpdGlvbjogcmVsYXRpdmU7IHotaW5kZXg6IDEiKSxvLmN1cnNvckRpdj1yKCJkaXYiLG51bGwsIkNvZGVNaXJyb3ItY3Vyc29ycyIpLG8ubWVhc3VyZT1yKCJkaXYiLG51bGwsIkNvZGVNaXJyb3ItbWVhc3VyZSIpLG8ubGluZU1lYXN1cmU9cigiZGl2IixudWxsLCJDb2RlTWlycm9yLW1lYXN1cmUiKSxvLmxpbmVTcGFjZT1pKCJkaXYiLFtvLm1lYXN1cmUsby5saW5lTWVhc3VyZSxvLnNlbGVjdGlvbkRpdixvLmN1cnNvckRpdixvLmxpbmVEaXZdLG51bGwsInBvc2l0aW9uOiByZWxhdGl2ZTsgb3V0bGluZTogbm9uZSIpO3ZhciBhPWkoImRpdiIsW28ubGluZVNwYWNlXSwiQ29kZU1pcnJvci1saW5lcyIpO28ubW92ZXI9cigiZGl2IixbYV0sbnVsbCwicG9zaXRpb246IHJlbGF0aXZlIiksby5zaXplcj1yKCJkaXYiLFtvLm1vdmVyXSwiQ29kZU1pcnJvci1zaXplciIpLG8uc2l6ZXJXaWR0aD1udWxsLG8uaGVpZ2h0Rm9yY2VyPXIoImRpdiIsbnVsbCxudWxsLCJwb3NpdGlvbjogYWJzb2x1dGU7IGhlaWdodDogIitHYSsicHg7IHdpZHRoOiAxcHg7Iiksby5ndXR0ZXJzPXIoImRpdiIsbnVsbCwiQ29kZU1pcnJvci1ndXR0ZXJzIiksby5saW5lR3V0dGVyPW51bGwsby5zY3JvbGxlcj1yKCJkaXYiLFtvLnNpemVyLG8uaGVpZ2h0Rm9yY2VyLG8uZ3V0dGVyc10sIkNvZGVNaXJyb3Itc2Nyb2xsIiksby5zY3JvbGxlci5zZXRBdHRyaWJ1dGUoInRhYkluZGV4IiwiLTEiKSxvLndyYXBwZXI9cigiZGl2Iixbby5zY3JvbGxiYXJGaWxsZXIsby5ndXR0ZXJGaWxsZXIsby5zY3JvbGxlcl0sIkNvZGVNaXJyb3IiKSxiYSYmeGE8OCYmKG8uZ3V0dGVycy5zdHlsZS56SW5kZXg9LTEsby5zY3JvbGxlci5zdHlsZS5wYWRkaW5nUmlnaHQ9MCksQ2F8fG1hJiZPYXx8KG8uc2Nyb2xsZXIuZHJhZ2dhYmxlPSEwKSxlJiYoZS5hcHBlbmRDaGlsZD9lLmFwcGVuZENoaWxkKG8ud3JhcHBlcik6ZShvLndyYXBwZXIpKSxvLnZpZXdGcm9tPW8udmlld1RvPXQuZmlyc3Qsby5yZXBvcnRlZFZpZXdGcm9tPW8ucmVwb3J0ZWRWaWV3VG89dC5maXJzdCxvLnZpZXc9W10sby5yZW5kZXJlZFZpZXc9bnVsbCxvLmV4dGVybmFsTWVhc3VyZWQ9bnVsbCxvLnZpZXdPZmZzZXQ9MCxvLmxhc3RXcmFwSGVpZ2h0PW8ubGFzdFdyYXBXaWR0aD0wLG8udXBkYXRlTGluZU51bWJlcnM9bnVsbCxvLm5hdGl2ZUJhcldpZHRoPW8uYmFySGVpZ2h0PW8uYmFyV2lkdGg9MCxvLnNjcm9sbGJhcnNDbGlwcGVkPSExLG8ubGluZU51bVdpZHRoPW8ubGluZU51bUlubmVyV2lkdGg9by5saW5lTnVtQ2hhcnM9bnVsbCxvLmFsaWduV2lkZ2V0cz0hMSxvLmNhY2hlZENoYXJXaWR0aD1vLmNhY2hlZFRleHRIZWlnaHQ9by5jYWNoZWRQYWRkaW5nSD1udWxsLG8ubWF4TGluZT1udWxsLG8ubWF4TGluZUxlbmd0aD0wLG8ubWF4TGluZUNoYW5nZWQ9ITEsby53aGVlbERYPW8ud2hlZWxEWT1vLndoZWVsU3RhcnRYPW8ud2hlZWxTdGFydFk9bnVsbCxvLnNoaWZ0PSExLG8uc2VsRm9yQ29udGV4dE1lbnU9bnVsbCxvLmFjdGl2ZVRvdWNoPW51bGwsbi5pbml0KG8pfWZ1bmN0aW9uIEEoZSx0KXtpZigodC09ZS5maXJzdCk8MHx8dD49ZS5zaXplKXRocm93IG5ldyBFcnJvcigiVGhlcmUgaXMgbm8gbGluZSAiKyh0K2UuZmlyc3QpKyIgaW4gdGhlIGRvY3VtZW50LiIpO2Zvcih2YXIgbj1lOyFuLmxpbmVzOylmb3IodmFyIHI9MDs7KytyKXt2YXIgaT1uLmNoaWxkcmVuW3JdLG89aS5jaHVua1NpemUoKTtpZih0PG8pe249aTticmVha310LT1vfXJldHVybiBuLmxpbmVzW3RdfWZ1bmN0aW9uIF8oZSx0LG4pe3ZhciByPVtdLGk9dC5saW5lO3JldHVybiBlLml0ZXIodC5saW5lLG4ubGluZSsxLGZ1bmN0aW9uKGUpe3ZhciBvPWUudGV4dDtpPT1uLmxpbmUmJihvPW8uc2xpY2UoMCxuLmNoKSksaT09dC5saW5lJiYobz1vLnNsaWNlKHQuY2gpKSxyLnB1c2gobyksKytpfSkscn1mdW5jdGlvbiBUKGUsdCxuKXt2YXIgcj1bXTtyZXR1cm4gZS5pdGVyKHQsbixmdW5jdGlvbihlKXtyLnB1c2goZS50ZXh0KX0pLHJ9ZnVuY3Rpb24gTyhlLHQpe3ZhciBuPXQtZS5oZWlnaHQ7aWYobilmb3IodmFyIHI9ZTtyO3I9ci5wYXJlbnQpci5oZWlnaHQrPW59ZnVuY3Rpb24gRihlKXtpZihudWxsPT1lLnBhcmVudClyZXR1cm4gbnVsbDtmb3IodmFyIHQ9ZS5wYXJlbnQsbj1mKHQubGluZXMsZSkscj10LnBhcmVudDtyO3Q9cixyPXIucGFyZW50KWZvcih2YXIgaT0wO3IuY2hpbGRyZW5baV0hPXQ7KytpKW4rPXIuY2hpbGRyZW5baV0uY2h1bmtTaXplKCk7cmV0dXJuIG4rdC5maXJzdH1mdW5jdGlvbiBOKGUsdCl7dmFyIG49ZS5maXJzdDtlOmRve2Zvcih2YXIgcj0wO3I8ZS5jaGlsZHJlbi5sZW5ndGg7KytyKXt2YXIgaT1lLmNoaWxkcmVuW3JdLG89aS5oZWlnaHQ7aWYodDxvKXtlPWk7Y29udGludWUgZX10LT1vLG4rPWkuY2h1bmtTaXplKCl9cmV0dXJuIG59d2hpbGUoIWUubGluZXMpO2Zvcih2YXIgYT0wO2E8ZS5saW5lcy5sZW5ndGg7KythKXt2YXIgcz1lLmxpbmVzW2FdLHU9cy5oZWlnaHQ7aWYodDx1KWJyZWFrO3QtPXV9cmV0dXJuIG4rYX1mdW5jdGlvbiBJKGUsdCl7cmV0dXJuIHQ+PWUuZmlyc3QmJnQ8ZS5maXJzdCtlLnNpemV9ZnVuY3Rpb24gTChlLHQpe3JldHVybiBTdHJpbmcoZS5saW5lTnVtYmVyRm9ybWF0dGVyKHQrZS5maXJzdExpbmVOdW1iZXIpKX1mdW5jdGlvbiBQKGUsdCxuKXtpZih2b2lkIDA9PT1uJiYobj1udWxsKSwhKHRoaXMgaW5zdGFuY2VvZiBQKSlyZXR1cm4gbmV3IFAoZSx0LG4pO3RoaXMubGluZT1lLHRoaXMuY2g9dCx0aGlzLnN0aWNreT1ufWZ1bmN0aW9uIE0oZSx0KXtyZXR1cm4gZS5saW5lLXQubGluZXx8ZS5jaC10LmNofWZ1bmN0aW9uIGooZSx0KXtyZXR1cm4gZS5zdGlja3k9PXQuc3RpY2t5JiYwPT1NKGUsdCl9ZnVuY3Rpb24gUihlKXtyZXR1cm4gUChlLmxpbmUsZS5jaCl9ZnVuY3Rpb24gQihlLHQpe3JldHVybiBNKGUsdCk8MD90OmV9ZnVuY3Rpb24gJChlLHQpe3JldHVybiBNKGUsdCk8MD9lOnR9ZnVuY3Rpb24gVShlLHQpe3JldHVybiBNYXRoLm1heChlLmZpcnN0LE1hdGgubWluKHQsZS5maXJzdCtlLnNpemUtMSkpfWZ1bmN0aW9uIHooZSx0KXtpZih0LmxpbmU8ZS5maXJzdClyZXR1cm4gUChlLmZpcnN0LDApO3ZhciBuPWUuZmlyc3QrZS5zaXplLTE7cmV0dXJuIHQubGluZT5uP1AobixBKGUsbikudGV4dC5sZW5ndGgpOkcodCxBKGUsdC5saW5lKS50ZXh0Lmxlbmd0aCl9ZnVuY3Rpb24gRyhlLHQpe3ZhciBuPWUuY2g7cmV0dXJuIG51bGw9PW58fG4+dD9QKGUubGluZSx0KTpuPDA/UChlLmxpbmUsMCk6ZX1mdW5jdGlvbiBWKGUsdCl7Zm9yKHZhciBuPVtdLHI9MDtyPHQubGVuZ3RoO3IrKyluW3JdPXooZSx0W3JdKTtyZXR1cm4gbn1mdW5jdGlvbiBxKCl7WWE9ITB9ZnVuY3Rpb24gSCgpe1hhPSEwfWZ1bmN0aW9uIFcoZSx0LG4pe3RoaXMubWFya2VyPWUsdGhpcy5mcm9tPXQsdGhpcy50bz1ufWZ1bmN0aW9uIFEoZSx0KXtpZihlKWZvcih2YXIgbj0wO248ZS5sZW5ndGg7KytuKXt2YXIgcj1lW25dO2lmKHIubWFya2VyPT10KXJldHVybiByfX1mdW5jdGlvbiBLKGUsdCl7Zm9yKHZhciBuLHI9MDtyPGUubGVuZ3RoOysrcillW3JdIT10JiYobnx8KG49W10pKS5wdXNoKGVbcl0pO3JldHVybiBufWZ1bmN0aW9uIEooZSx0KXtlLm1hcmtlZFNwYW5zPWUubWFya2VkU3BhbnM/ZS5tYXJrZWRTcGFucy5jb25jYXQoW3RdKTpbdF0sdC5tYXJrZXIuYXR0YWNoTGluZShlKX1mdW5jdGlvbiBZKGUsdCxuKXt2YXIgcjtpZihlKWZvcih2YXIgaT0wO2k8ZS5sZW5ndGg7KytpKXt2YXIgbz1lW2ldLGE9by5tYXJrZXIscz1udWxsPT1vLmZyb218fChhLmluY2x1c2l2ZUxlZnQ/by5mcm9tPD10Om8uZnJvbTx0KTtpZihzfHxvLmZyb209PXQmJiJib29rbWFyayI9PWEudHlwZSYmKCFufHwhby5tYXJrZXIuaW5zZXJ0TGVmdCkpe3ZhciB1PW51bGw9PW8udG98fChhLmluY2x1c2l2ZVJpZ2h0P28udG8+PXQ6by50bz50KTsocnx8KHI9W10pKS5wdXNoKG5ldyBXKGEsby5mcm9tLHU/bnVsbDpvLnRvKSl9fXJldHVybiByfWZ1bmN0aW9uIFgoZSx0LG4pe3ZhciByO2lmKGUpZm9yKHZhciBpPTA7aTxlLmxlbmd0aDsrK2kpe3ZhciBvPWVbaV0sYT1vLm1hcmtlcixzPW51bGw9PW8udG98fChhLmluY2x1c2l2ZVJpZ2h0P28udG8+PXQ6by50bz50KTtpZihzfHxvLmZyb209PXQmJiJib29rbWFyayI9PWEudHlwZSYmKCFufHxvLm1hcmtlci5pbnNlcnRMZWZ0KSl7dmFyIHU9bnVsbD09by5mcm9tfHwoYS5pbmNsdXNpdmVMZWZ0P28uZnJvbTw9dDpvLmZyb208dCk7KHJ8fChyPVtdKSkucHVzaChuZXcgVyhhLHU/bnVsbDpvLmZyb20tdCxudWxsPT1vLnRvP251bGw6by50by10KSl9fXJldHVybiByfWZ1bmN0aW9uIFooZSx0KXtpZih0LmZ1bGwpcmV0dXJuIG51bGw7dmFyIG49SShlLHQuZnJvbS5saW5lKSYmQShlLHQuZnJvbS5saW5lKS5tYXJrZWRTcGFucyxyPUkoZSx0LnRvLmxpbmUpJiZBKGUsdC50by5saW5lKS5tYXJrZWRTcGFucztpZighbiYmIXIpcmV0dXJuIG51bGw7dmFyIGk9dC5mcm9tLmNoLG89dC50by5jaCxhPTA9PU0odC5mcm9tLHQudG8pLHM9WShuLGksYSksdT1YKHIsbyxhKSxjPTE9PXQudGV4dC5sZW5ndGgsbD1tKHQudGV4dCkubGVuZ3RoKyhjP2k6MCk7aWYocylmb3IodmFyIHA9MDtwPHMubGVuZ3RoOysrcCl7dmFyIGY9c1twXTtpZihudWxsPT1mLnRvKXt2YXIgZD1RKHUsZi5tYXJrZXIpO2Q/YyYmKGYudG89bnVsbD09ZC50bz9udWxsOmQudG8rbCk6Zi50bz1pfX1pZih1KWZvcih2YXIgaD0wO2g8dS5sZW5ndGg7KytoKXt2YXIgZz11W2hdO2lmKG51bGwhPWcudG8mJihnLnRvKz1sKSxudWxsPT1nLmZyb20pe3ZhciB5PVEocyxnLm1hcmtlcik7eXx8KGcuZnJvbT1sLGMmJihzfHwocz1bXSkpLnB1c2goZykpfWVsc2UgZy5mcm9tKz1sLGMmJihzfHwocz1bXSkpLnB1c2goZyl9cyYmKHM9ZWUocykpLHUmJnUhPXMmJih1PWVlKHUpKTt2YXIgdj1bc107aWYoIWMpe3ZhciBiLHg9dC50ZXh0Lmxlbmd0aC0yO2lmKHg+MCYmcylmb3IodmFyIEM9MDtDPHMubGVuZ3RoOysrQyludWxsPT1zW0NdLnRvJiYoYnx8KGI9W10pKS5wdXNoKG5ldyBXKHNbQ10ubWFya2VyLG51bGwsbnVsbCkpO2Zvcih2YXIgRT0wO0U8eDsrK0Updi5wdXNoKGIpO3YucHVzaCh1KX1yZXR1cm4gdn1mdW5jdGlvbiBlZShlKXtmb3IodmFyIHQ9MDt0PGUubGVuZ3RoOysrdCl7dmFyIG49ZVt0XTtudWxsIT1uLmZyb20mJm4uZnJvbT09bi50byYmITEhPT1uLm1hcmtlci5jbGVhcldoZW5FbXB0eSYmZS5zcGxpY2UodC0tLDEpfXJldHVybiBlLmxlbmd0aD9lOm51bGx9ZnVuY3Rpb24gdGUoZSx0LG4pe3ZhciByPW51bGw7aWYoZS5pdGVyKHQubGluZSxuLmxpbmUrMSxmdW5jdGlvbihlKXtpZihlLm1hcmtlZFNwYW5zKWZvcih2YXIgdD0wO3Q8ZS5tYXJrZWRTcGFucy5sZW5ndGg7Kyt0KXt2YXIgbj1lLm1hcmtlZFNwYW5zW3RdLm1hcmtlcjshbi5yZWFkT25seXx8ciYmLTEhPWYocixuKXx8KHJ8fChyPVtdKSkucHVzaChuKX19KSwhcilyZXR1cm4gbnVsbDtmb3IodmFyIGk9W3tmcm9tOnQsdG86bn1dLG89MDtvPHIubGVuZ3RoOysrbylmb3IodmFyIGE9cltvXSxzPWEuZmluZCgwKSx1PTA7dTxpLmxlbmd0aDsrK3Upe3ZhciBjPWlbdV07aWYoIShNKGMudG8scy5mcm9tKTwwfHxNKGMuZnJvbSxzLnRvKT4wKSl7dmFyIGw9W3UsMV0scD1NKGMuZnJvbSxzLmZyb20pLGQ9TShjLnRvLHMudG8pOyhwPDB8fCFhLmluY2x1c2l2ZUxlZnQmJiFwKSYmbC5wdXNoKHtmcm9tOmMuZnJvbSx0bzpzLmZyb219KSwoZD4wfHwhYS5pbmNsdXNpdmVSaWdodCYmIWQpJiZsLnB1c2goe2Zyb206cy50byx0bzpjLnRvfSksaS5zcGxpY2UuYXBwbHkoaSxsKSx1Kz1sLmxlbmd0aC0zfX1yZXR1cm4gaX1mdW5jdGlvbiBuZShlKXt2YXIgdD1lLm1hcmtlZFNwYW5zO2lmKHQpe2Zvcih2YXIgbj0wO248dC5sZW5ndGg7KytuKXRbbl0ubWFya2VyLmRldGFjaExpbmUoZSk7ZS5tYXJrZWRTcGFucz1udWxsfX1mdW5jdGlvbiByZShlLHQpe2lmKHQpe2Zvcih2YXIgbj0wO248dC5sZW5ndGg7KytuKXRbbl0ubWFya2VyLmF0dGFjaExpbmUoZSk7ZS5tYXJrZWRTcGFucz10fX1mdW5jdGlvbiBpZShlKXtyZXR1cm4gZS5pbmNsdXNpdmVMZWZ0Py0xOjB9ZnVuY3Rpb24gb2UoZSl7cmV0dXJuIGUuaW5jbHVzaXZlUmlnaHQ/MTowfWZ1bmN0aW9uIGFlKGUsdCl7dmFyIG49ZS5saW5lcy5sZW5ndGgtdC5saW5lcy5sZW5ndGg7aWYoMCE9bilyZXR1cm4gbjt2YXIgcj1lLmZpbmQoKSxpPXQuZmluZCgpLG89TShyLmZyb20saS5mcm9tKXx8aWUoZSktaWUodCk7aWYobylyZXR1cm4tbzt2YXIgYT1NKHIudG8saS50byl8fG9lKGUpLW9lKHQpO3JldHVybiBhfHx0LmlkLWUuaWR9ZnVuY3Rpb24gc2UoZSx0KXt2YXIgbixyPVhhJiZlLm1hcmtlZFNwYW5zO2lmKHIpZm9yKHZhciBpPXZvaWQgMCxvPTA7bzxyLmxlbmd0aDsrK28paT1yW29dLGkubWFya2VyLmNvbGxhcHNlZCYmbnVsbD09KHQ/aS5mcm9tOmkudG8pJiYoIW58fGFlKG4saS5tYXJrZXIpPDApJiYobj1pLm1hcmtlcik7cmV0dXJuIG59ZnVuY3Rpb24gdWUoZSl7cmV0dXJuIHNlKGUsITApfWZ1bmN0aW9uIGNlKGUpe3JldHVybiBzZShlLCExKX1mdW5jdGlvbiBsZShlLHQpe3ZhciBuLHI9WGEmJmUubWFya2VkU3BhbnM7aWYocilmb3IodmFyIGk9MDtpPHIubGVuZ3RoOysraSl7dmFyIG89cltpXTtvLm1hcmtlci5jb2xsYXBzZWQmJihudWxsPT1vLmZyb218fG8uZnJvbTx0KSYmKG51bGw9PW8udG98fG8udG8+dCkmJighbnx8YWUobixvLm1hcmtlcik8MCkmJihuPW8ubWFya2VyKX1yZXR1cm4gbn1mdW5jdGlvbiBwZShlLHQsbixyLGkpe3ZhciBvPUEoZSx0KSxhPVhhJiZvLm1hcmtlZFNwYW5zO2lmKGEpZm9yKHZhciBzPTA7czxhLmxlbmd0aDsrK3Mpe3ZhciB1PWFbc107aWYodS5tYXJrZXIuY29sbGFwc2VkKXt2YXIgYz11Lm1hcmtlci5maW5kKDApLGw9TShjLmZyb20sbil8fGllKHUubWFya2VyKS1pZShpKSxwPU0oYy50byxyKXx8b2UodS5tYXJrZXIpLW9lKGkpO2lmKCEobD49MCYmcDw9MHx8bDw9MCYmcD49MCkmJihsPD0wJiYodS5tYXJrZXIuaW5jbHVzaXZlUmlnaHQmJmkuaW5jbHVzaXZlTGVmdD9NKGMudG8sbik+PTA6TShjLnRvLG4pPjApfHxsPj0wJiYodS5tYXJrZXIuaW5jbHVzaXZlUmlnaHQmJmkuaW5jbHVzaXZlTGVmdD9NKGMuZnJvbSxyKTw9MDpNKGMuZnJvbSxyKTwwKSkpcmV0dXJuITB9fX1mdW5jdGlvbiBmZShlKXtmb3IodmFyIHQ7dD11ZShlKTspZT10LmZpbmQoLTEsITApLmxpbmU7cmV0dXJuIGV9ZnVuY3Rpb24gZGUoZSl7Zm9yKHZhciB0O3Q9Y2UoZSk7KWU9dC5maW5kKDEsITApLmxpbmU7cmV0dXJuIGV9ZnVuY3Rpb24gaGUoZSl7Zm9yKHZhciB0LG47dD1jZShlKTspZT10LmZpbmQoMSwhMCkubGluZSwobnx8KG49W10pKS5wdXNoKGUpO3JldHVybiBufWZ1bmN0aW9uIG1lKGUsdCl7dmFyIG49QShlLHQpLHI9ZmUobik7cmV0dXJuIG49PXI/dDpGKHIpfWZ1bmN0aW9uIGdlKGUsdCl7aWYodD5lLmxhc3RMaW5lKCkpcmV0dXJuIHQ7dmFyIG4scj1BKGUsdCk7aWYoIXllKGUscikpcmV0dXJuIHQ7Zm9yKDtuPWNlKHIpOylyPW4uZmluZCgxLCEwKS5saW5lO3JldHVybiBGKHIpKzF9ZnVuY3Rpb24geWUoZSx0KXt2YXIgbj1YYSYmdC5tYXJrZWRTcGFucztpZihuKWZvcih2YXIgcj12b2lkIDAsaT0wO2k8bi5sZW5ndGg7KytpKWlmKHI9bltpXSxyLm1hcmtlci5jb2xsYXBzZWQpe2lmKG51bGw9PXIuZnJvbSlyZXR1cm4hMDtpZighci5tYXJrZXIud2lkZ2V0Tm9kZSYmMD09ci5mcm9tJiZyLm1hcmtlci5pbmNsdXNpdmVMZWZ0JiZ2ZShlLHQscikpcmV0dXJuITB9fWZ1bmN0aW9uIHZlKGUsdCxuKXtpZihudWxsPT1uLnRvKXt2YXIgcj1uLm1hcmtlci5maW5kKDEsITApO3JldHVybiB2ZShlLHIubGluZSxRKHIubGluZS5tYXJrZWRTcGFucyxuLm1hcmtlcikpfWlmKG4ubWFya2VyLmluY2x1c2l2ZVJpZ2h0JiZuLnRvPT10LnRleHQubGVuZ3RoKXJldHVybiEwO2Zvcih2YXIgaT12b2lkIDAsbz0wO288dC5tYXJrZWRTcGFucy5sZW5ndGg7KytvKWlmKGk9dC5tYXJrZWRTcGFuc1tvXSxpLm1hcmtlci5jb2xsYXBzZWQmJiFpLm1hcmtlci53aWRnZXROb2RlJiZpLmZyb209PW4udG8mJihudWxsPT1pLnRvfHxpLnRvIT1uLmZyb20pJiYoaS5tYXJrZXIuaW5jbHVzaXZlTGVmdHx8bi5tYXJrZXIuaW5jbHVzaXZlUmlnaHQpJiZ2ZShlLHQsaSkpcmV0dXJuITB9ZnVuY3Rpb24gYmUoZSl7ZT1mZShlKTtmb3IodmFyIHQ9MCxuPWUucGFyZW50LHI9MDtyPG4ubGluZXMubGVuZ3RoOysrcil7dmFyIGk9bi5saW5lc1tyXTtpZihpPT1lKWJyZWFrO3QrPWkuaGVpZ2h0fWZvcih2YXIgbz1uLnBhcmVudDtvO249byxvPW4ucGFyZW50KWZvcih2YXIgYT0wO2E8by5jaGlsZHJlbi5sZW5ndGg7KythKXt2YXIgcz1vLmNoaWxkcmVuW2FdO2lmKHM9PW4pYnJlYWs7dCs9cy5oZWlnaHR9cmV0dXJuIHR9ZnVuY3Rpb24geGUoZSl7aWYoMD09ZS5oZWlnaHQpcmV0dXJuIDA7Zm9yKHZhciB0LG49ZS50ZXh0Lmxlbmd0aCxyPWU7dD11ZShyKTspe3ZhciBpPXQuZmluZCgwLCEwKTtyPWkuZnJvbS5saW5lLG4rPWkuZnJvbS5jaC1pLnRvLmNofWZvcihyPWU7dD1jZShyKTspe3ZhciBvPXQuZmluZCgwLCEwKTtuLT1yLnRleHQubGVuZ3RoLW8uZnJvbS5jaCxyPW8udG8ubGluZSxuKz1yLnRleHQubGVuZ3RoLW8udG8uY2h9cmV0dXJuIG59ZnVuY3Rpb24gQ2UoZSl7dmFyIHQ9ZS5kaXNwbGF5LG49ZS5kb2M7dC5tYXhMaW5lPUEobixuLmZpcnN0KSx0Lm1heExpbmVMZW5ndGg9eGUodC5tYXhMaW5lKSx0Lm1heExpbmVDaGFuZ2VkPSEwLG4uaXRlcihmdW5jdGlvbihlKXt2YXIgbj14ZShlKTtuPnQubWF4TGluZUxlbmd0aCYmKHQubWF4TGluZUxlbmd0aD1uLHQubWF4TGluZT1lKX0pfWZ1bmN0aW9uIEVlKGUsdCxuLHIpe2lmKCFlKXJldHVybiByKHQsbiwibHRyIiwwKTtmb3IodmFyIGk9ITEsbz0wO288ZS5sZW5ndGg7KytvKXt2YXIgYT1lW29dOyhhLmZyb208biYmYS50bz50fHx0PT1uJiZhLnRvPT10KSYmKHIoTWF0aC5tYXgoYS5mcm9tLHQpLE1hdGgubWluKGEudG8sbiksMT09YS5sZXZlbD8icnRsIjoibHRyIixvKSxpPSEwKX1pfHxyKHQsbiwibHRyIil9ZnVuY3Rpb24gRGUoZSx0LG4pe3ZhciByO1phPW51bGw7Zm9yKHZhciBpPTA7aTxlLmxlbmd0aDsrK2kpe3ZhciBvPWVbaV07aWYoby5mcm9tPHQmJm8udG8+dClyZXR1cm4gaTtvLnRvPT10JiYoby5mcm9tIT1vLnRvJiYiYmVmb3JlIj09bj9yPWk6WmE9aSksby5mcm9tPT10JiYoby5mcm9tIT1vLnRvJiYiYmVmb3JlIiE9bj9yPWk6WmE9aSl9cmV0dXJuIG51bGwhPXI/cjpaYX1mdW5jdGlvbiB3ZShlLHQpe3ZhciBuPWUub3JkZXI7cmV0dXJuIG51bGw9PW4mJihuPWUub3JkZXI9ZXMoZS50ZXh0LHQpKSxufWZ1bmN0aW9uIFNlKGUsdCl7cmV0dXJuIGUuX2hhbmRsZXJzJiZlLl9oYW5kbGVyc1t0XXx8dHN9ZnVuY3Rpb24ga2UoZSx0LG4pe2lmKGUucmVtb3ZlRXZlbnRMaXN0ZW5lcillLnJlbW92ZUV2ZW50TGlzdGVuZXIodCxuLCExKTtlbHNlIGlmKGUuZGV0YWNoRXZlbnQpZS5kZXRhY2hFdmVudCgib24iK3Qsbik7ZWxzZXt2YXIgcj1lLl9oYW5kbGVycyxpPXImJnJbdF07aWYoaSl7dmFyIG89ZihpLG4pO28+LTEmJihyW3RdPWkuc2xpY2UoMCxvKS5jb25jYXQoaS5zbGljZShvKzEpKSl9fX1mdW5jdGlvbiBBZShlLHQpe3ZhciBuPVNlKGUsdCk7aWYobi5sZW5ndGgpZm9yKHZhciByPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywyKSxpPTA7aTxuLmxlbmd0aDsrK2kpbltpXS5hcHBseShudWxsLHIpfWZ1bmN0aW9uIF9lKGUsdCxuKXtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIHQmJih0PXt0eXBlOnQscHJldmVudERlZmF1bHQ6ZnVuY3Rpb24oKXt0aGlzLmRlZmF1bHRQcmV2ZW50ZWQ9ITB9fSksQWUoZSxufHx0LnR5cGUsZSx0KSxMZSh0KXx8dC5jb2RlbWlycm9ySWdub3JlfWZ1bmN0aW9uIFRlKGUpe3ZhciB0PWUuX2hhbmRsZXJzJiZlLl9oYW5kbGVycy5jdXJzb3JBY3Rpdml0eTtpZih0KWZvcih2YXIgbj1lLmN1ck9wLmN1cnNvckFjdGl2aXR5SGFuZGxlcnN8fChlLmN1ck9wLmN1cnNvckFjdGl2aXR5SGFuZGxlcnM9W10pLHI9MDtyPHQubGVuZ3RoOysrciktMT09ZihuLHRbcl0pJiZuLnB1c2godFtyXSl9ZnVuY3Rpb24gT2UoZSx0KXtyZXR1cm4gU2UoZSx0KS5sZW5ndGg+MH1mdW5jdGlvbiBGZShlKXtlLnByb3RvdHlwZS5vbj1mdW5jdGlvbihlLHQpe25zKHRoaXMsZSx0KX0sZS5wcm90b3R5cGUub2ZmPWZ1bmN0aW9uKGUsdCl7a2UodGhpcyxlLHQpfX1mdW5jdGlvbiBOZShlKXtlLnByZXZlbnREZWZhdWx0P2UucHJldmVudERlZmF1bHQoKTplLnJldHVyblZhbHVlPSExfWZ1bmN0aW9uIEllKGUpe2Uuc3RvcFByb3BhZ2F0aW9uP2Uuc3RvcFByb3BhZ2F0aW9uKCk6ZS5jYW5jZWxCdWJibGU9ITB9ZnVuY3Rpb24gTGUoZSl7cmV0dXJuIG51bGwhPWUuZGVmYXVsdFByZXZlbnRlZD9lLmRlZmF1bHRQcmV2ZW50ZWQ6MD09ZS5yZXR1cm5WYWx1ZX1mdW5jdGlvbiBQZShlKXtOZShlKSxJZShlKX1mdW5jdGlvbiBNZShlKXtyZXR1cm4gZS50YXJnZXR8fGUuc3JjRWxlbWVudH1mdW5jdGlvbiBqZShlKXt2YXIgdD1lLndoaWNoO3JldHVybiBudWxsPT10JiYoMSZlLmJ1dHRvbj90PTE6MiZlLmJ1dHRvbj90PTM6NCZlLmJ1dHRvbiYmKHQ9MikpLEZhJiZlLmN0cmxLZXkmJjE9PXQmJih0PTMpLHR9ZnVuY3Rpb24gUmUoZSl7aWYobnVsbD09VWEpe3ZhciB0PXIoInNwYW4iLCJcdTIwMGIiKTtuKGUscigic3BhbiIsW3QsZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIngiKV0pKSwwIT1lLmZpcnN0Q2hpbGQub2Zmc2V0SGVpZ2h0JiYoVWE9dC5vZmZzZXRXaWR0aDw9MSYmdC5vZmZzZXRIZWlnaHQ+MiYmIShiYSYmeGE8OCkpfXZhciBpPVVhP3IoInNwYW4iLCJcdTIwMGIiKTpyKCJzcGFuIiwiXHhhMCIsbnVsbCwiZGlzcGxheTogaW5saW5lLWJsb2NrOyB3aWR0aDogMXB4OyBtYXJnaW4tcmlnaHQ6IC0xcHgiKTtyZXR1cm4gaS5zZXRBdHRyaWJ1dGUoImNtLXRleHQiLCIiKSxpfWZ1bmN0aW9uIEJlKGUpe2lmKG51bGwhPXphKXJldHVybiB6YTt2YXIgcj1uKGUsZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIkFcdTA2MmVBIikpLGk9UGEociwwLDEpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLG89UGEociwxLDIpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO3JldHVybiB0KGUpLCEoIWl8fGkubGVmdD09aS5yaWdodCkmJih6YT1vLnJpZ2h0LWkucmlnaHQ8Myl9ZnVuY3Rpb24gJGUoZSl7aWYobnVsbCE9c3MpcmV0dXJuIHNzO3ZhciB0PW4oZSxyKCJzcGFuIiwieCIpKSxpPXQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksbz1QYSh0LDAsMSkuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7cmV0dXJuIHNzPU1hdGguYWJzKGkubGVmdC1vLmxlZnQpPjF9ZnVuY3Rpb24gVWUoZSx0KXthcmd1bWVudHMubGVuZ3RoPjImJih0LmRlcGVuZGVuY2llcz1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMikpLHVzW2VdPXR9ZnVuY3Rpb24gemUoZSx0KXtjc1tlXT10fWZ1bmN0aW9uIEdlKGUpe2lmKCJzdHJpbmciPT10eXBlb2YgZSYmY3MuaGFzT3duUHJvcGVydHkoZSkpZT1jc1tlXTtlbHNlIGlmKGUmJiJzdHJpbmciPT10eXBlb2YgZS5uYW1lJiZjcy5oYXNPd25Qcm9wZXJ0eShlLm5hbWUpKXt2YXIgdD1jc1tlLm5hbWVdOyJzdHJpbmciPT10eXBlb2YgdCYmKHQ9e25hbWU6dH0pLGU9Yih0LGUpLGUubmFtZT10Lm5hbWV9ZWxzZXtpZigic3RyaW5nIj09dHlwZW9mIGUmJi9eW1x3XC1dK1wvW1x3XC1dK1wreG1sJC8udGVzdChlKSlyZXR1cm4gR2UoImFwcGxpY2F0aW9uL3htbCIpO2lmKCJzdHJpbmciPT10eXBlb2YgZSYmL15bXHdcLV0rXC9bXHdcLV0rXCtqc29uJC8udGVzdChlKSlyZXR1cm4gR2UoImFwcGxpY2F0aW9uL2pzb24iKX1yZXR1cm4ic3RyaW5nIj09dHlwZW9mIGU/e25hbWU6ZX06ZXx8e25hbWU6Im51bGwifX1mdW5jdGlvbiBWZShlLHQpe3Q9R2UodCk7dmFyIG49dXNbdC5uYW1lXTtpZighbilyZXR1cm4gVmUoZSwidGV4dC9wbGFpbiIpO3ZhciByPW4oZSx0KTtpZihscy5oYXNPd25Qcm9wZXJ0eSh0Lm5hbWUpKXt2YXIgaT1sc1t0Lm5hbWVdO2Zvcih2YXIgbyBpbiBpKWkuaGFzT3duUHJvcGVydHkobykmJihyLmhhc093blByb3BlcnR5KG8pJiYoclsiXyIrb109cltvXSkscltvXT1pW29dKX1pZihyLm5hbWU9dC5uYW1lLHQuaGVscGVyVHlwZSYmKHIuaGVscGVyVHlwZT10LmhlbHBlclR5cGUpLHQubW9kZVByb3BzKWZvcih2YXIgYSBpbiB0Lm1vZGVQcm9wcylyW2FdPXQubW9kZVByb3BzW2FdO3JldHVybiByfWZ1bmN0aW9uIHFlKGUsdCl7bCh0LGxzLmhhc093blByb3BlcnR5KGUpP2xzW2VdOmxzW2VdPXt9KX1mdW5jdGlvbiBIZShlLHQpe2lmKCEwPT09dClyZXR1cm4gdDtpZihlLmNvcHlTdGF0ZSlyZXR1cm4gZS5jb3B5U3RhdGUodCk7dmFyIG49e307Zm9yKHZhciByIGluIHQpe3ZhciBpPXRbcl07aSBpbnN0YW5jZW9mIEFycmF5JiYoaT1pLmNvbmNhdChbXSkpLG5bcl09aX1yZXR1cm4gbn1mdW5jdGlvbiBXZShlLHQpe2Zvcih2YXIgbjtlLmlubmVyTW9kZSYmKG49ZS5pbm5lck1vZGUodCkpJiZuLm1vZGUhPWU7KXQ9bi5zdGF0ZSxlPW4ubW9kZTtyZXR1cm4gbnx8e21vZGU6ZSxzdGF0ZTp0fX1mdW5jdGlvbiBRZShlLHQsbil7cmV0dXJuIWUuc3RhcnRTdGF0ZXx8ZS5zdGFydFN0YXRlKHQsbil9ZnVuY3Rpb24gS2UoZSx0LG4scil7dmFyIGk9W2Uuc3RhdGUubW9kZUdlbl0sbz17fTtydChlLHQudGV4dCxlLmRvYy5tb2RlLG4sZnVuY3Rpb24oZSx0KXtyZXR1cm4gaS5wdXNoKGUsdCl9LG8scik7Zm9yKHZhciBhPW4uc3RhdGUscz0wO3M8ZS5zdGF0ZS5vdmVybGF5cy5sZW5ndGg7KytzKSFmdW5jdGlvbihyKXtuLmJhc2VUb2tlbnM9aTt2YXIgcz1lLnN0YXRlLm92ZXJsYXlzW3JdLHU9MSxjPTA7bi5zdGF0ZT0hMCxydChlLHQudGV4dCxzLm1vZGUsbixmdW5jdGlvbihlLHQpe2Zvcih2YXIgbj11O2M8ZTspe3ZhciByPWlbdV07cj5lJiZpLnNwbGljZSh1LDEsZSxpW3UrMV0sciksdSs9MixjPU1hdGgubWluKGUscil9aWYodClpZihzLm9wYXF1ZSlpLnNwbGljZShuLHUtbixlLCJvdmVybGF5ICIrdCksdT1uKzI7ZWxzZSBmb3IoO248dTtuKz0yKXt2YXIgbz1pW24rMV07aVtuKzFdPShvP28rIiAiOiIiKSsib3ZlcmxheSAiK3R9fSxvKSxuLnN0YXRlPWEsbi5iYXNlVG9rZW5zPW51bGwsbi5iYXNlVG9rZW5Qb3M9MX0ocyk7cmV0dXJue3N0eWxlczppLGNsYXNzZXM6by5iZ0NsYXNzfHxvLnRleHRDbGFzcz9vOm51bGx9fWZ1bmN0aW9uIEplKGUsdCxuKXtpZighdC5zdHlsZXN8fHQuc3R5bGVzWzBdIT1lLnN0YXRlLm1vZGVHZW4pe3ZhciByPVllKGUsRih0KSksaT10LnRleHQubGVuZ3RoPmUub3B0aW9ucy5tYXhIaWdobGlnaHRMZW5ndGgmJkhlKGUuZG9jLm1vZGUsci5zdGF0ZSksbz1LZShlLHQscik7aSYmKHIuc3RhdGU9aSksdC5zdGF0ZUFmdGVyPXIuc2F2ZSghaSksdC5zdHlsZXM9by5zdHlsZXMsby5jbGFzc2VzP3Quc3R5bGVDbGFzc2VzPW8uY2xhc3Nlczp0LnN0eWxlQ2xhc3NlcyYmKHQuc3R5bGVDbGFzc2VzPW51bGwpLG49PT1lLmRvYy5oaWdobGlnaHRGcm9udGllciYmKGUuZG9jLm1vZGVGcm9udGllcj1NYXRoLm1heChlLmRvYy5tb2RlRnJvbnRpZXIsKytlLmRvYy5oaWdobGlnaHRGcm9udGllcikpfXJldHVybiB0LnN0eWxlc31mdW5jdGlvbiBZZShlLHQsbil7dmFyIHI9ZS5kb2MsaT1lLmRpc3BsYXk7aWYoIXIubW9kZS5zdGFydFN0YXRlKXJldHVybiBuZXcgZHMociwhMCx0KTt2YXIgbz1pdChlLHQsbiksYT1vPnIuZmlyc3QmJkEocixvLTEpLnN0YXRlQWZ0ZXIscz1hP2RzLmZyb21TYXZlZChyLGEsbyk6bmV3IGRzKHIsUWUoci5tb2RlKSxvKTtyZXR1cm4gci5pdGVyKG8sdCxmdW5jdGlvbihuKXtYZShlLG4udGV4dCxzKTt2YXIgcj1zLmxpbmU7bi5zdGF0ZUFmdGVyPXI9PXQtMXx8ciU1PT0wfHxyPj1pLnZpZXdGcm9tJiZyPGkudmlld1RvP3Muc2F2ZSgpOm51bGwscy5uZXh0TGluZSgpfSksbiYmKHIubW9kZUZyb250aWVyPXMubGluZSksc31mdW5jdGlvbiBYZShlLHQsbixyKXt2YXIgaT1lLmRvYy5tb2RlLG89bmV3IHBzKHQsZS5vcHRpb25zLnRhYlNpemUsbik7Zm9yKG8uc3RhcnQ9by5wb3M9cnx8MCwiIj09dCYmWmUoaSxuLnN0YXRlKTshby5lb2woKTspZXQoaSxvLG4uc3RhdGUpLG8uc3RhcnQ9by5wb3N9ZnVuY3Rpb24gWmUoZSx0KXtpZihlLmJsYW5rTGluZSlyZXR1cm4gZS5ibGFua0xpbmUodCk7aWYoZS5pbm5lck1vZGUpe3ZhciBuPVdlKGUsdCk7cmV0dXJuIG4ubW9kZS5ibGFua0xpbmU/bi5tb2RlLmJsYW5rTGluZShuLnN0YXRlKTp2b2lkIDB9fWZ1bmN0aW9uIGV0KGUsdCxuLHIpe2Zvcih2YXIgaT0wO2k8MTA7aSsrKXtyJiYoclswXT1XZShlLG4pLm1vZGUpO3ZhciBvPWUudG9rZW4odCxuKTtpZih0LnBvcz50LnN0YXJ0KXJldHVybiBvfXRocm93IG5ldyBFcnJvcigiTW9kZSAiK2UubmFtZSsiIGZhaWxlZCB0byBhZHZhbmNlIHN0cmVhbS4iKX1mdW5jdGlvbiB0dChlLHQsbixyKXt2YXIgaSxvPWUuZG9jLGE9by5tb2RlO3Q9eihvLHQpO3ZhciBzLHU9QShvLHQubGluZSksYz1ZZShlLHQubGluZSxuKSxsPW5ldyBwcyh1LnRleHQsZS5vcHRpb25zLnRhYlNpemUsYyk7Zm9yKHImJihzPVtdKTsocnx8bC5wb3M8dC5jaCkmJiFsLmVvbCgpOylsLnN0YXJ0PWwucG9zLGk9ZXQoYSxsLGMuc3RhdGUpLHImJnMucHVzaChuZXcgaHMobCxpLEhlKG8ubW9kZSxjLnN0YXRlKSkpO3JldHVybiByP3M6bmV3IGhzKGwsaSxjLnN0YXRlKX1mdW5jdGlvbiBudChlLHQpe2lmKGUpZm9yKDs7KXt2YXIgbj1lLm1hdGNoKC8oPzpefFxzKylsaW5lLShiYWNrZ3JvdW5kLSk/KFxTKykvKTtpZighbilicmVhaztlPWUuc2xpY2UoMCxuLmluZGV4KStlLnNsaWNlKG4uaW5kZXgrblswXS5sZW5ndGgpO3ZhciByPW5bMV0/ImJnQ2xhc3MiOiJ0ZXh0Q2xhc3MiO251bGw9PXRbcl0/dFtyXT1uWzJdOm5ldyBSZWdFeHAoIig/Ol58cykiK25bMl0rIig/OiR8cykiKS50ZXN0KHRbcl0pfHwodFtyXSs9IiAiK25bMl0pfXJldHVybiBlfWZ1bmN0aW9uIHJ0KGUsdCxuLHIsaSxvLGEpe3ZhciBzPW4uZmxhdHRlblNwYW5zO251bGw9PXMmJihzPWUub3B0aW9ucy5mbGF0dGVuU3BhbnMpO3ZhciB1LGM9MCxsPW51bGwscD1uZXcgcHModCxlLm9wdGlvbnMudGFiU2l6ZSxyKSxmPWUub3B0aW9ucy5hZGRNb2RlQ2xhc3MmJltudWxsXTtmb3IoIiI9PXQmJm50KFplKG4sci5zdGF0ZSksbyk7IXAuZW9sKCk7KXtpZihwLnBvcz5lLm9wdGlvbnMubWF4SGlnaGxpZ2h0TGVuZ3RoPyhzPSExLGEmJlhlKGUsdCxyLHAucG9zKSxwLnBvcz10Lmxlbmd0aCx1PW51bGwpOnU9bnQoZXQobixwLHIuc3RhdGUsZiksbyksZil7dmFyIGQ9ZlswXS5uYW1lO2QmJih1PSJtLSIrKHU/ZCsiICIrdTpkKSl9aWYoIXN8fGwhPXUpe2Zvcig7YzxwLnN0YXJ0OyljPU1hdGgubWluKHAuc3RhcnQsYys1ZTMpLGkoYyxsKTtsPXV9cC5zdGFydD1wLnBvc31mb3IoO2M8cC5wb3M7KXt2YXIgaD1NYXRoLm1pbihwLnBvcyxjKzVlMyk7aShoLGwpLGM9aH19ZnVuY3Rpb24gaXQoZSx0LG4pe2Zvcih2YXIgcixpLG89ZS5kb2MsYT1uPy0xOnQtKGUuZG9jLm1vZGUuaW5uZXJNb2RlPzFlMzoxMDApLHM9dDtzPmE7LS1zKXtpZihzPD1vLmZpcnN0KXJldHVybiBvLmZpcnN0O3ZhciB1PUEobyxzLTEpLGM9dS5zdGF0ZUFmdGVyO2lmKGMmJighbnx8cysoYyBpbnN0YW5jZW9mIGZzP2MubG9va0FoZWFkOjApPD1vLm1vZGVGcm9udGllcikpcmV0dXJuIHM7dmFyIGw9cCh1LnRleHQsbnVsbCxlLm9wdGlvbnMudGFiU2l6ZSk7KG51bGw9PWl8fHI+bCkmJihpPXMtMSxyPWwpfXJldHVybiBpfWZ1bmN0aW9uIG90KGUsdCl7aWYoZS5tb2RlRnJvbnRpZXI9TWF0aC5taW4oZS5tb2RlRnJvbnRpZXIsdCksIShlLmhpZ2hsaWdodEZyb250aWVyPHQtMTApKXtmb3IodmFyIG49ZS5maXJzdCxyPXQtMTtyPm47ci0tKXt2YXIgaT1BKGUscikuc3RhdGVBZnRlcjtpZihpJiYoIShpIGluc3RhbmNlb2YgZnMpfHxyK2kubG9va0FoZWFkPHQpKXtuPXIrMTticmVha319ZS5oaWdobGlnaHRGcm9udGllcj1NYXRoLm1pbihlLmhpZ2hsaWdodEZyb250aWVyLG4pfX1mdW5jdGlvbiBhdChlLHQsbixyKXtlLnRleHQ9dCxlLnN0YXRlQWZ0ZXImJihlLnN0YXRlQWZ0ZXI9bnVsbCksZS5zdHlsZXMmJihlLnN0eWxlcz1udWxsKSxudWxsIT1lLm9yZGVyJiYoZS5vcmRlcj1udWxsKSxuZShlKSxyZShlLG4pO3ZhciBpPXI/cihlKToxO2khPWUuaGVpZ2h0JiZPKGUsaSl9ZnVuY3Rpb24gc3QoZSl7ZS5wYXJlbnQ9bnVsbCxuZShlKX1mdW5jdGlvbiB1dChlLHQpe2lmKCFlfHwvXlxzKiQvLnRlc3QoZSkpcmV0dXJuIG51bGw7dmFyIG49dC5hZGRNb2RlQ2xhc3M/dnM6eXM7cmV0dXJuIG5bZV18fChuW2VdPWUucmVwbGFjZSgvXFMrL2csImNtLSQmIikpfWZ1bmN0aW9uIGN0KGUsdCl7dmFyIG49aSgic3BhbiIsbnVsbCxudWxsLENhPyJwYWRkaW5nLXJpZ2h0OiAuMXB4IjpudWxsKSxyPXtwcmU6aSgicHJlIixbbl0sIkNvZGVNaXJyb3ItbGluZSIpLGNvbnRlbnQ6bixjb2w6MCxwb3M6MCxjbTplLHRyYWlsaW5nU3BhY2U6ITEsc3BsaXRTcGFjZXM6KGJhfHxDYSkmJmUuZ2V0T3B0aW9uKCJsaW5lV3JhcHBpbmciKX07dC5tZWFzdXJlPXt9O2Zvcih2YXIgbz0wO288PSh0LnJlc3Q/dC5yZXN0Lmxlbmd0aDowKTtvKyspe3ZhciBhPW8/dC5yZXN0W28tMV06dC5saW5lLHM9dm9pZCAwO3IucG9zPTAsci5hZGRUb2tlbj1wdCxCZShlLmRpc3BsYXkubWVhc3VyZSkmJihzPXdlKGEsZS5kb2MuZGlyZWN0aW9uKSkmJihyLmFkZFRva2VuPWR0KHIuYWRkVG9rZW4scykpLHIubWFwPVtdO210KGEscixKZShlLGEsdCE9ZS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQmJkYoYSkpKSxhLnN0eWxlQ2xhc3NlcyYmKGEuc3R5bGVDbGFzc2VzLmJnQ2xhc3MmJihyLmJnQ2xhc3M9dShhLnN0eWxlQ2xhc3Nlcy5iZ0NsYXNzLHIuYmdDbGFzc3x8IiIpKSxhLnN0eWxlQ2xhc3Nlcy50ZXh0Q2xhc3MmJihyLnRleHRDbGFzcz11KGEuc3R5bGVDbGFzc2VzLnRleHRDbGFzcyxyLnRleHRDbGFzc3x8IiIpKSksMD09ci5tYXAubGVuZ3RoJiZyLm1hcC5wdXNoKDAsMCxyLmNvbnRlbnQuYXBwZW5kQ2hpbGQoUmUoZS5kaXNwbGF5Lm1lYXN1cmUpKSksMD09bz8odC5tZWFzdXJlLm1hcD1yLm1hcCx0Lm1lYXN1cmUuY2FjaGU9e30pOigodC5tZWFzdXJlLm1hcHN8fCh0Lm1lYXN1cmUubWFwcz1bXSkpLnB1c2goci5tYXApLCh0Lm1lYXN1cmUuY2FjaGVzfHwodC5tZWFzdXJlLmNhY2hlcz1bXSkpLnB1c2goe30pKX1pZihDYSl7dmFyIGM9ci5jb250ZW50Lmxhc3RDaGlsZDsoL1xiY20tdGFiXGIvLnRlc3QoYy5jbGFzc05hbWUpfHxjLnF1ZXJ5U2VsZWN0b3ImJmMucXVlcnlTZWxlY3RvcigiLmNtLXRhYiIpKSYmKHIuY29udGVudC5jbGFzc05hbWU9ImNtLXRhYi13cmFwLWhhY2siKX1yZXR1cm4gQWUoZSwicmVuZGVyTGluZSIsZSx0LmxpbmUsci5wcmUpLHIucHJlLmNsYXNzTmFtZSYmKHIudGV4dENsYXNzPXUoci5wcmUuY2xhc3NOYW1lLHIudGV4dENsYXNzfHwiIikpLHJ9ZnVuY3Rpb24gbHQoZSl7dmFyIHQ9cigic3BhbiIsIlx1MjAyMiIsImNtLWludmFsaWRjaGFyIik7cmV0dXJuIHQudGl0bGU9IlxcdSIrZS5jaGFyQ29kZUF0KDApLnRvU3RyaW5nKDE2KSx0LnNldEF0dHJpYnV0ZSgiYXJpYS1sYWJlbCIsdC50aXRsZSksdH1mdW5jdGlvbiBwdChlLHQsbixpLG8sYSxzKXtpZih0KXt2YXIgdSxjPWUuc3BsaXRTcGFjZXM/ZnQodCxlLnRyYWlsaW5nU3BhY2UpOnQsbD1lLmNtLnN0YXRlLnNwZWNpYWxDaGFycyxwPSExO2lmKGwudGVzdCh0KSl7dT1kb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7Zm9yKHZhciBmPTA7Oyl7bC5sYXN0SW5kZXg9Zjt2YXIgZD1sLmV4ZWModCksbT1kP2QuaW5kZXgtZjp0Lmxlbmd0aC1mO2lmKG0pe3ZhciBnPWRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGMuc2xpY2UoZixmK20pKTtiYSYmeGE8OT91LmFwcGVuZENoaWxkKHIoInNwYW4iLFtnXSkpOnUuYXBwZW5kQ2hpbGQoZyksZS5tYXAucHVzaChlLnBvcyxlLnBvcyttLGcpLGUuY29sKz1tLGUucG9zKz1tfWlmKCFkKWJyZWFrO2YrPW0rMTt2YXIgeT12b2lkIDA7aWYoIlx0Ij09ZFswXSl7dmFyIHY9ZS5jbS5vcHRpb25zLnRhYlNpemUsYj12LWUuY29sJXY7eT11LmFwcGVuZENoaWxkKHIoInNwYW4iLGgoYiksImNtLXRhYiIpKSx5LnNldEF0dHJpYnV0ZSgicm9sZSIsInByZXNlbnRhdGlvbiIpLHkuc2V0QXR0cmlidXRlKCJjbS10ZXh0IiwiXHQiKSxlLmNvbCs9Yn1lbHNlIlxyIj09ZFswXXx8IlxuIj09ZFswXT8oeT11LmFwcGVuZENoaWxkKHIoInNwYW4iLCJcciI9PWRbMF0/Ilx1MjQwZCI6Ilx1MjQyNCIsImNtLWludmFsaWRjaGFyIikpLHkuc2V0QXR0cmlidXRlKCJjbS10ZXh0IixkWzBdKSxlLmNvbCs9MSk6KHk9ZS5jbS5vcHRpb25zLnNwZWNpYWxDaGFyUGxhY2Vob2xkZXIoZFswXSkseS5zZXRBdHRyaWJ1dGUoImNtLXRleHQiLGRbMF0pLGJhJiZ4YTw5P3UuYXBwZW5kQ2hpbGQocigic3BhbiIsW3ldKSk6dS5hcHBlbmRDaGlsZCh5KSxlLmNvbCs9MSk7ZS5tYXAucHVzaChlLnBvcyxlLnBvcysxLHkpLGUucG9zKyt9fWVsc2UgZS5jb2wrPXQubGVuZ3RoLHU9ZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoYyksZS5tYXAucHVzaChlLnBvcyxlLnBvcyt0Lmxlbmd0aCx1KSxiYSYmeGE8OSYmKHA9ITApLGUucG9zKz10Lmxlbmd0aDtpZihlLnRyYWlsaW5nU3BhY2U9MzI9PWMuY2hhckNvZGVBdCh0Lmxlbmd0aC0xKSxufHxpfHxvfHxwfHxzKXt2YXIgeD1ufHwiIjtpJiYoeCs9aSksbyYmKHgrPW8pO3ZhciBDPXIoInNwYW4iLFt1XSx4LHMpO3JldHVybiBhJiYoQy50aXRsZT1hKSxlLmNvbnRlbnQuYXBwZW5kQ2hpbGQoQyl9ZS5jb250ZW50LmFwcGVuZENoaWxkKHUpfX1mdW5jdGlvbiBmdChlLHQpe2lmKGUubGVuZ3RoPjEmJiEvICAvLnRlc3QoZSkpcmV0dXJuIGU7Zm9yKHZhciBuPXQscj0iIixpPTA7aTxlLmxlbmd0aDtpKyspe3ZhciBvPWUuY2hhckF0KGkpOyIgIiE9b3x8IW58fGkhPWUubGVuZ3RoLTEmJjMyIT1lLmNoYXJDb2RlQXQoaSsxKXx8KG89Ilx4YTAiKSxyKz1vLG49IiAiPT1vfXJldHVybiByfWZ1bmN0aW9uIGR0KGUsdCl7cmV0dXJuIGZ1bmN0aW9uKG4scixpLG8sYSxzLHUpe2k9aT9pKyIgY20tZm9yY2UtYm9yZGVyIjoiY20tZm9yY2UtYm9yZGVyIjtmb3IodmFyIGM9bi5wb3MsbD1jK3IubGVuZ3RoOzspe2Zvcih2YXIgcD12b2lkIDAsZj0wO2Y8dC5sZW5ndGgmJihwPXRbZl0sIShwLnRvPmMmJnAuZnJvbTw9YykpO2YrKyk7aWYocC50bz49bClyZXR1cm4gZShuLHIsaSxvLGEscyx1KTtlKG4sci5zbGljZSgwLHAudG8tYyksaSxvLG51bGwscyx1KSxvPW51bGwscj1yLnNsaWNlKHAudG8tYyksYz1wLnRvfX19ZnVuY3Rpb24gaHQoZSx0LG4scil7dmFyIGk9IXImJm4ud2lkZ2V0Tm9kZTtpJiZlLm1hcC5wdXNoKGUucG9zLGUucG9zK3QsaSksIXImJmUuY20uZGlzcGxheS5pbnB1dC5uZWVkc0NvbnRlbnRBdHRyaWJ1dGUmJihpfHwoaT1lLmNvbnRlbnQuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic3BhbiIpKSksaS5zZXRBdHRyaWJ1dGUoImNtLW1hcmtlciIsbi5pZCkpLGkmJihlLmNtLmRpc3BsYXkuaW5wdXQuc2V0VW5lZGl0YWJsZShpKSxlLmNvbnRlbnQuYXBwZW5kQ2hpbGQoaSkpLGUucG9zKz10LGUudHJhaWxpbmdTcGFjZT0hMX1mdW5jdGlvbiBtdChlLHQsbil7dmFyIHI9ZS5tYXJrZWRTcGFucyxpPWUudGV4dCxvPTA7aWYocilmb3IodmFyIGEscyx1LGMsbCxwLGYsZD1pLmxlbmd0aCxoPTAsbT0xLGc9IiIseT0wOzspe2lmKHk9PWgpe3U9Yz1sPXA9cz0iIixmPW51bGwseT0xLzA7Zm9yKHZhciB2PVtdLGI9dm9pZCAwLHg9MDt4PHIubGVuZ3RoOysreCl7dmFyIEM9clt4XSxFPUMubWFya2VyOyJib29rbWFyayI9PUUudHlwZSYmQy5mcm9tPT1oJiZFLndpZGdldE5vZGU/di5wdXNoKEUpOkMuZnJvbTw9aCYmKG51bGw9PUMudG98fEMudG8+aHx8RS5jb2xsYXBzZWQmJkMudG89PWgmJkMuZnJvbT09aCk/KG51bGwhPUMudG8mJkMudG8hPWgmJnk+Qy50byYmKHk9Qy50byxjPSIiKSxFLmNsYXNzTmFtZSYmKHUrPSIgIitFLmNsYXNzTmFtZSksRS5jc3MmJihzPShzP3MrIjsiOiIiKStFLmNzcyksRS5zdGFydFN0eWxlJiZDLmZyb209PWgmJihsKz0iICIrRS5zdGFydFN0eWxlKSxFLmVuZFN0eWxlJiZDLnRvPT15JiYoYnx8KGI9W10pKS5wdXNoKEUuZW5kU3R5bGUsQy50byksRS50aXRsZSYmIXAmJihwPUUudGl0bGUpLEUuY29sbGFwc2VkJiYoIWZ8fGFlKGYubWFya2VyLEUpPDApJiYoZj1DKSk6Qy5mcm9tPmgmJnk+Qy5mcm9tJiYoeT1DLmZyb20pfWlmKGIpZm9yKHZhciBEPTA7RDxiLmxlbmd0aDtEKz0yKWJbRCsxXT09eSYmKGMrPSIgIitiW0RdKTtpZighZnx8Zi5mcm9tPT1oKWZvcih2YXIgdz0wO3c8di5sZW5ndGg7Kyt3KWh0KHQsMCx2W3ddKTtpZihmJiYoZi5mcm9tfHwwKT09aCl7aWYoaHQodCwobnVsbD09Zi50bz9kKzE6Zi50byktaCxmLm1hcmtlcixudWxsPT1mLmZyb20pLG51bGw9PWYudG8pcmV0dXJuO2YudG89PWgmJihmPSExKX19aWYoaD49ZClicmVhaztmb3IodmFyIFM9TWF0aC5taW4oZCx5KTs7KXtpZihnKXt2YXIgaz1oK2cubGVuZ3RoO2lmKCFmKXt2YXIgQT1rPlM/Zy5zbGljZSgwLFMtaCk6Zzt0LmFkZFRva2VuKHQsQSxhP2ErdTp1LGwsaCtBLmxlbmd0aD09eT9jOiIiLHAscyl9aWYoaz49Uyl7Zz1nLnNsaWNlKFMtaCksaD1TO2JyZWFrfWg9ayxsPSIifWc9aS5zbGljZShvLG89blttKytdKSxhPXV0KG5bbSsrXSx0LmNtLm9wdGlvbnMpfX1lbHNlIGZvcih2YXIgXz0xO188bi5sZW5ndGg7Xys9Mil0LmFkZFRva2VuKHQsaS5zbGljZShvLG89bltfXSksdXQobltfKzFdLHQuY20ub3B0aW9ucykpfWZ1bmN0aW9uIGd0KGUsdCxuKXt0aGlzLmxpbmU9dCx0aGlzLnJlc3Q9aGUodCksdGhpcy5zaXplPXRoaXMucmVzdD9GKG0odGhpcy5yZXN0KSktbisxOjEsdGhpcy5ub2RlPXRoaXMudGV4dD1udWxsLHRoaXMuaGlkZGVuPXllKGUsdCl9ZnVuY3Rpb24geXQoZSx0LG4pe2Zvcih2YXIgcixpPVtdLG89dDtvPG47bz1yKXt2YXIgYT1uZXcgZ3QoZS5kb2MsQShlLmRvYyxvKSxvKTtyPW8rYS5zaXplLGkucHVzaChhKX1yZXR1cm4gaX1mdW5jdGlvbiB2dChlKXticz9icy5vcHMucHVzaChlKTplLm93bnNHcm91cD1icz17b3BzOltlXSxkZWxheWVkQ2FsbGJhY2tzOltdfX1mdW5jdGlvbiBidChlKXt2YXIgdD1lLmRlbGF5ZWRDYWxsYmFja3Msbj0wO2Rve2Zvcig7bjx0Lmxlbmd0aDtuKyspdFtuXS5jYWxsKG51bGwpO2Zvcih2YXIgcj0wO3I8ZS5vcHMubGVuZ3RoO3IrKyl7dmFyIGk9ZS5vcHNbcl07aWYoaS5jdXJzb3JBY3Rpdml0eUhhbmRsZXJzKWZvcig7aS5jdXJzb3JBY3Rpdml0eUNhbGxlZDxpLmN1cnNvckFjdGl2aXR5SGFuZGxlcnMubGVuZ3RoOylpLmN1cnNvckFjdGl2aXR5SGFuZGxlcnNbaS5jdXJzb3JBY3Rpdml0eUNhbGxlZCsrXS5jYWxsKG51bGwsaS5jbSl9fXdoaWxlKG48dC5sZW5ndGgpfWZ1bmN0aW9uIHh0KGUsdCl7dmFyIG49ZS5vd25zR3JvdXA7aWYobil0cnl7YnQobil9ZmluYWxseXticz1udWxsLHQobil9fWZ1bmN0aW9uIEN0KGUsdCl7dmFyIG49U2UoZSx0KTtpZihuLmxlbmd0aCl7dmFyIHIsaT1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMik7YnM/cj1icy5kZWxheWVkQ2FsbGJhY2tzOnhzP3I9eHM6KHI9eHM9W10sc2V0VGltZW91dChFdCwwKSk7Zm9yKHZhciBvPTA7bzxuLmxlbmd0aDsrK28pIWZ1bmN0aW9uKGUpe3IucHVzaChmdW5jdGlvbigpe3JldHVybiBuW2VdLmFwcGx5KG51bGwsaSl9KX0obyl9fWZ1bmN0aW9uIEV0KCl7dmFyIGU9eHM7eHM9bnVsbDtmb3IodmFyIHQ9MDt0PGUubGVuZ3RoOysrdCllW3RdKCl9ZnVuY3Rpb24gRHQoZSx0LG4scil7Zm9yKHZhciBpPTA7aTx0LmNoYW5nZXMubGVuZ3RoO2krKyl7dmFyIG89dC5jaGFuZ2VzW2ldOyJ0ZXh0Ij09bz9BdChlLHQpOiJndXR0ZXIiPT1vP1R0KGUsdCxuLHIpOiJjbGFzcyI9PW8/X3QoZSx0KToid2lkZ2V0Ij09byYmT3QoZSx0LHIpfXQuY2hhbmdlcz1udWxsfWZ1bmN0aW9uIHd0KGUpe3JldHVybiBlLm5vZGU9PWUudGV4dCYmKGUubm9kZT1yKCJkaXYiLG51bGwsbnVsbCwicG9zaXRpb246IHJlbGF0aXZlIiksZS50ZXh0LnBhcmVudE5vZGUmJmUudGV4dC5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChlLm5vZGUsZS50ZXh0KSxlLm5vZGUuYXBwZW5kQ2hpbGQoZS50ZXh0KSxiYSYmeGE8OCYmKGUubm9kZS5zdHlsZS56SW5kZXg9MikpLGUubm9kZX1mdW5jdGlvbiBTdChlLHQpe3ZhciBuPXQuYmdDbGFzcz90LmJnQ2xhc3MrIiAiKyh0LmxpbmUuYmdDbGFzc3x8IiIpOnQubGluZS5iZ0NsYXNzO2lmKG4mJihuKz0iIENvZGVNaXJyb3ItbGluZWJhY2tncm91bmQiKSx0LmJhY2tncm91bmQpbj90LmJhY2tncm91bmQuY2xhc3NOYW1lPW46KHQuYmFja2dyb3VuZC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHQuYmFja2dyb3VuZCksdC5iYWNrZ3JvdW5kPW51bGwpO2Vsc2UgaWYobil7dmFyIGk9d3QodCk7dC5iYWNrZ3JvdW5kPWkuaW5zZXJ0QmVmb3JlKHIoImRpdiIsbnVsbCxuKSxpLmZpcnN0Q2hpbGQpLGUuZGlzcGxheS5pbnB1dC5zZXRVbmVkaXRhYmxlKHQuYmFja2dyb3VuZCl9fWZ1bmN0aW9uIGt0KGUsdCl7dmFyIG49ZS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQ7cmV0dXJuIG4mJm4ubGluZT09dC5saW5lPyhlLmRpc3BsYXkuZXh0ZXJuYWxNZWFzdXJlZD1udWxsLHQubWVhc3VyZT1uLm1lYXN1cmUsbi5idWlsdCk6Y3QoZSx0KX1mdW5jdGlvbiBBdChlLHQpe3ZhciBuPXQudGV4dC5jbGFzc05hbWUscj1rdChlLHQpO3QudGV4dD09dC5ub2RlJiYodC5ub2RlPXIucHJlKSx0LnRleHQucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQoci5wcmUsdC50ZXh0KSx0LnRleHQ9ci5wcmUsci5iZ0NsYXNzIT10LmJnQ2xhc3N8fHIudGV4dENsYXNzIT10LnRleHRDbGFzcz8odC5iZ0NsYXNzPXIuYmdDbGFzcyx0LnRleHRDbGFzcz1yLnRleHRDbGFzcyxfdChlLHQpKTpuJiYodC50ZXh0LmNsYXNzTmFtZT1uKX1mdW5jdGlvbiBfdChlLHQpe1N0KGUsdCksdC5saW5lLndyYXBDbGFzcz93dCh0KS5jbGFzc05hbWU9dC5saW5lLndyYXBDbGFzczp0Lm5vZGUhPXQudGV4dCYmKHQubm9kZS5jbGFzc05hbWU9IiIpO3ZhciBuPXQudGV4dENsYXNzP3QudGV4dENsYXNzKyIgIisodC5saW5lLnRleHRDbGFzc3x8IiIpOnQubGluZS50ZXh0Q2xhc3M7dC50ZXh0LmNsYXNzTmFtZT1ufHwiIn1mdW5jdGlvbiBUdChlLHQsbixpKXtpZih0Lmd1dHRlciYmKHQubm9kZS5yZW1vdmVDaGlsZCh0Lmd1dHRlciksdC5ndXR0ZXI9bnVsbCksdC5ndXR0ZXJCYWNrZ3JvdW5kJiYodC5ub2RlLnJlbW92ZUNoaWxkKHQuZ3V0dGVyQmFja2dyb3VuZCksdC5ndXR0ZXJCYWNrZ3JvdW5kPW51bGwpLHQubGluZS5ndXR0ZXJDbGFzcyl7dmFyIG89d3QodCk7dC5ndXR0ZXJCYWNrZ3JvdW5kPXIoImRpdiIsbnVsbCwiQ29kZU1pcnJvci1ndXR0ZXItYmFja2dyb3VuZCAiK3QubGluZS5ndXR0ZXJDbGFzcywibGVmdDogIisoZS5vcHRpb25zLmZpeGVkR3V0dGVyP2kuZml4ZWRQb3M6LWkuZ3V0dGVyVG90YWxXaWR0aCkrInB4OyB3aWR0aDogIitpLmd1dHRlclRvdGFsV2lkdGgrInB4IiksZS5kaXNwbGF5LmlucHV0LnNldFVuZWRpdGFibGUodC5ndXR0ZXJCYWNrZ3JvdW5kKSxvLmluc2VydEJlZm9yZSh0Lmd1dHRlckJhY2tncm91bmQsdC50ZXh0KX12YXIgYT10LmxpbmUuZ3V0dGVyTWFya2VycztpZihlLm9wdGlvbnMubGluZU51bWJlcnN8fGEpe3ZhciBzPXd0KHQpLHU9dC5ndXR0ZXI9cigiZGl2IixudWxsLCJDb2RlTWlycm9yLWd1dHRlci13cmFwcGVyIiwibGVmdDogIisoZS5vcHRpb25zLmZpeGVkR3V0dGVyP2kuZml4ZWRQb3M6LWkuZ3V0dGVyVG90YWxXaWR0aCkrInB4Iik7aWYoZS5kaXNwbGF5LmlucHV0LnNldFVuZWRpdGFibGUodSkscy5pbnNlcnRCZWZvcmUodSx0LnRleHQpLHQubGluZS5ndXR0ZXJDbGFzcyYmKHUuY2xhc3NOYW1lKz0iICIrdC5saW5lLmd1dHRlckNsYXNzKSwhZS5vcHRpb25zLmxpbmVOdW1iZXJzfHxhJiZhWyJDb2RlTWlycm9yLWxpbmVudW1iZXJzIl18fCh0LmxpbmVOdW1iZXI9dS5hcHBlbmRDaGlsZChyKCJkaXYiLEwoZS5vcHRpb25zLG4pLCJDb2RlTWlycm9yLWxpbmVudW1iZXIgQ29kZU1pcnJvci1ndXR0ZXItZWx0IiwibGVmdDogIitpLmd1dHRlckxlZnRbIkNvZGVNaXJyb3ItbGluZW51bWJlcnMiXSsicHg7IHdpZHRoOiAiK2UuZGlzcGxheS5saW5lTnVtSW5uZXJXaWR0aCsicHgiKSkpLGEpZm9yKHZhciBjPTA7YzxlLm9wdGlvbnMuZ3V0dGVycy5sZW5ndGg7KytjKXt2YXIgbD1lLm9wdGlvbnMuZ3V0dGVyc1tjXSxwPWEuaGFzT3duUHJvcGVydHkobCkmJmFbbF07cCYmdS5hcHBlbmRDaGlsZChyKCJkaXYiLFtwXSwiQ29kZU1pcnJvci1ndXR0ZXItZWx0IiwibGVmdDogIitpLmd1dHRlckxlZnRbbF0rInB4OyB3aWR0aDogIitpLmd1dHRlcldpZHRoW2xdKyJweCIpKX19fWZ1bmN0aW9uIE90KGUsdCxuKXt0LmFsaWduYWJsZSYmKHQuYWxpZ25hYmxlPW51bGwpO2Zvcih2YXIgcj10Lm5vZGUuZmlyc3RDaGlsZCxpPXZvaWQgMDtyO3I9aSlpPXIubmV4dFNpYmxpbmcsIkNvZGVNaXJyb3ItbGluZXdpZGdldCI9PXIuY2xhc3NOYW1lJiZ0Lm5vZGUucmVtb3ZlQ2hpbGQocik7TnQoZSx0LG4pfWZ1bmN0aW9uIEZ0KGUsdCxuLHIpe3ZhciBpPWt0KGUsdCk7cmV0dXJuIHQudGV4dD10Lm5vZGU9aS5wcmUsaS5iZ0NsYXNzJiYodC5iZ0NsYXNzPWkuYmdDbGFzcyksaS50ZXh0Q2xhc3MmJih0LnRleHRDbGFzcz1pLnRleHRDbGFzcyksX3QoZSx0KSxUdChlLHQsbixyKSxOdChlLHQsciksdC5ub2RlfWZ1bmN0aW9uIE50KGUsdCxuKXtpZihJdChlLHQubGluZSx0LG4sITApLHQucmVzdClmb3IodmFyIHI9MDtyPHQucmVzdC5sZW5ndGg7cisrKUl0KGUsdC5yZXN0W3JdLHQsbiwhMSl9ZnVuY3Rpb24gSXQoZSx0LG4saSxvKXtpZih0LndpZGdldHMpZm9yKHZhciBhPXd0KG4pLHM9MCx1PXQud2lkZ2V0cztzPHUubGVuZ3RoOysrcyl7dmFyIGM9dVtzXSxsPXIoImRpdiIsW2Mubm9kZV0sIkNvZGVNaXJyb3ItbGluZXdpZGdldCIpO2MuaGFuZGxlTW91c2VFdmVudHN8fGwuc2V0QXR0cmlidXRlKCJjbS1pZ25vcmUtZXZlbnRzIiwidHJ1ZSIpLEx0KGMsbCxuLGkpLGUuZGlzcGxheS5pbnB1dC5zZXRVbmVkaXRhYmxlKGwpLG8mJmMuYWJvdmU/YS5pbnNlcnRCZWZvcmUobCxuLmd1dHRlcnx8bi50ZXh0KTphLmFwcGVuZENoaWxkKGwpLEN0KGMsInJlZHJhdyIpfX1mdW5jdGlvbiBMdChlLHQsbixyKXtpZihlLm5vSFNjcm9sbCl7KG4uYWxpZ25hYmxlfHwobi5hbGlnbmFibGU9W10pKS5wdXNoKHQpO3ZhciBpPXIud3JhcHBlcldpZHRoO3Quc3R5bGUubGVmdD1yLmZpeGVkUG9zKyJweCIsZS5jb3Zlckd1dHRlcnx8KGktPXIuZ3V0dGVyVG90YWxXaWR0aCx0LnN0eWxlLnBhZGRpbmdMZWZ0PXIuZ3V0dGVyVG90YWxXaWR0aCsicHgiKSx0LnN0eWxlLndpZHRoPWkrInB4In1lLmNvdmVyR3V0dGVyJiYodC5zdHlsZS56SW5kZXg9NSx0LnN0eWxlLnBvc2l0aW9uPSJyZWxhdGl2ZSIsZS5ub0hTY3JvbGx8fCh0LnN0eWxlLm1hcmdpbkxlZnQ9LXIuZ3V0dGVyVG90YWxXaWR0aCsicHgiKSl9ZnVuY3Rpb24gUHQoZSl7aWYobnVsbCE9ZS5oZWlnaHQpcmV0dXJuIGUuaGVpZ2h0O3ZhciB0PWUuZG9jLmNtO2lmKCF0KXJldHVybiAwO2lmKCFvKGRvY3VtZW50LmJvZHksZS5ub2RlKSl7dmFyIGk9InBvc2l0aW9uOiByZWxhdGl2ZTsiO2UuY292ZXJHdXR0ZXImJihpKz0ibWFyZ2luLWxlZnQ6IC0iK3QuZGlzcGxheS5ndXR0ZXJzLm9mZnNldFdpZHRoKyJweDsiKSxlLm5vSFNjcm9sbCYmKGkrPSJ3aWR0aDogIit0LmRpc3BsYXkud3JhcHBlci5jbGllbnRXaWR0aCsicHg7Iiksbih0LmRpc3BsYXkubWVhc3VyZSxyKCJkaXYiLFtlLm5vZGVdLG51bGwsaSkpfXJldHVybiBlLmhlaWdodD1lLm5vZGUucGFyZW50Tm9kZS5vZmZzZXRIZWlnaHR9ZnVuY3Rpb24gTXQoZSx0KXtmb3IodmFyIG49TWUodCk7biE9ZS53cmFwcGVyO249bi5wYXJlbnROb2RlKWlmKCFufHwxPT1uLm5vZGVUeXBlJiYidHJ1ZSI9PW4uZ2V0QXR0cmlidXRlKCJjbS1pZ25vcmUtZXZlbnRzIil8fG4ucGFyZW50Tm9kZT09ZS5zaXplciYmbiE9ZS5tb3ZlcilyZXR1cm4hMH1mdW5jdGlvbiBqdChlKXtyZXR1cm4gZS5saW5lU3BhY2Uub2Zmc2V0VG9wfWZ1bmN0aW9uIFJ0KGUpe3JldHVybiBlLm1vdmVyLm9mZnNldEhlaWdodC1lLmxpbmVTcGFjZS5vZmZzZXRIZWlnaHR9ZnVuY3Rpb24gQnQoZSl7aWYoZS5jYWNoZWRQYWRkaW5nSClyZXR1cm4gZS5jYWNoZWRQYWRkaW5nSDt2YXIgdD1uKGUubWVhc3VyZSxyKCJwcmUiLCJ4IikpLGk9d2luZG93LmdldENvbXB1dGVkU3R5bGU/d2luZG93LmdldENvbXB1dGVkU3R5bGUodCk6dC5jdXJyZW50U3R5bGUsbz17bGVmdDpwYXJzZUludChpLnBhZGRpbmdMZWZ0KSxyaWdodDpwYXJzZUludChpLnBhZGRpbmdSaWdodCl9O3JldHVybiBpc05hTihvLmxlZnQpfHxpc05hTihvLnJpZ2h0KXx8KGUuY2FjaGVkUGFkZGluZ0g9byksb31mdW5jdGlvbiAkdChlKXtyZXR1cm4gR2EtZS5kaXNwbGF5Lm5hdGl2ZUJhcldpZHRofWZ1bmN0aW9uIFV0KGUpe3JldHVybiBlLmRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50V2lkdGgtJHQoZSktZS5kaXNwbGF5LmJhcldpZHRofWZ1bmN0aW9uIHp0KGUpe3JldHVybiBlLmRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50SGVpZ2h0LSR0KGUpLWUuZGlzcGxheS5iYXJIZWlnaHR9ZnVuY3Rpb24gR3QoZSx0LG4pe3ZhciByPWUub3B0aW9ucy5saW5lV3JhcHBpbmcsaT1yJiZVdChlKTtpZighdC5tZWFzdXJlLmhlaWdodHN8fHImJnQubWVhc3VyZS53aWR0aCE9aSl7dmFyIG89dC5tZWFzdXJlLmhlaWdodHM9W107aWYocil7dC5tZWFzdXJlLndpZHRoPWk7Zm9yKHZhciBhPXQudGV4dC5maXJzdENoaWxkLmdldENsaWVudFJlY3RzKCkscz0wO3M8YS5sZW5ndGgtMTtzKyspe3ZhciB1PWFbc10sYz1hW3MrMV07TWF0aC5hYnModS5ib3R0b20tYy5ib3R0b20pPjImJm8ucHVzaCgodS5ib3R0b20rYy50b3ApLzItbi50b3ApfX1vLnB1c2gobi5ib3R0b20tbi50b3ApfX1mdW5jdGlvbiBWdChlLHQsbil7aWYoZS5saW5lPT10KXJldHVybnttYXA6ZS5tZWFzdXJlLm1hcCxjYWNoZTplLm1lYXN1cmUuY2FjaGV9O2Zvcih2YXIgcj0wO3I8ZS5yZXN0Lmxlbmd0aDtyKyspaWYoZS5yZXN0W3JdPT10KXJldHVybnttYXA6ZS5tZWFzdXJlLm1hcHNbcl0sY2FjaGU6ZS5tZWFzdXJlLmNhY2hlc1tyXX07Zm9yKHZhciBpPTA7aTxlLnJlc3QubGVuZ3RoO2krKylpZihGKGUucmVzdFtpXSk+bilyZXR1cm57bWFwOmUubWVhc3VyZS5tYXBzW2ldLGNhY2hlOmUubWVhc3VyZS5jYWNoZXNbaV0sYmVmb3JlOiEwfX1mdW5jdGlvbiBxdChlLHQpe3Q9ZmUodCk7dmFyIHI9Rih0KSxpPWUuZGlzcGxheS5leHRlcm5hbE1lYXN1cmVkPW5ldyBndChlLmRvYyx0LHIpO2kubGluZU49cjt2YXIgbz1pLmJ1aWx0PWN0KGUsaSk7cmV0dXJuIGkudGV4dD1vLnByZSxuKGUuZGlzcGxheS5saW5lTWVhc3VyZSxvLnByZSksaX1mdW5jdGlvbiBIdChlLHQsbixyKXtyZXR1cm4gS3QoZSxRdChlLHQpLG4scil9ZnVuY3Rpb24gV3QoZSx0KXtpZih0Pj1lLmRpc3BsYXkudmlld0Zyb20mJnQ8ZS5kaXNwbGF5LnZpZXdUbylyZXR1cm4gZS5kaXNwbGF5LnZpZXdbQW4oZSx0KV07dmFyIG49ZS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQ7cmV0dXJuIG4mJnQ+PW4ubGluZU4mJnQ8bi5saW5lTituLnNpemU/bjp2b2lkIDB9ZnVuY3Rpb24gUXQoZSx0KXt2YXIgbj1GKHQpLHI9V3QoZSxuKTtyJiYhci50ZXh0P3I9bnVsbDpyJiZyLmNoYW5nZXMmJihEdChlLHIsbixFbihlKSksZS5jdXJPcC5mb3JjZVVwZGF0ZT0hMCkscnx8KHI9cXQoZSx0KSk7dmFyIGk9VnQocix0LG4pO3JldHVybntsaW5lOnQsdmlldzpyLHJlY3Q6bnVsbCxtYXA6aS5tYXAsY2FjaGU6aS5jYWNoZSxiZWZvcmU6aS5iZWZvcmUsaGFzSGVpZ2h0czohMX19ZnVuY3Rpb24gS3QoZSx0LG4scixpKXt0LmJlZm9yZSYmKG49LTEpO3ZhciBvLGE9bisocnx8IiIpO3JldHVybiB0LmNhY2hlLmhhc093blByb3BlcnR5KGEpP289dC5jYWNoZVthXToodC5yZWN0fHwodC5yZWN0PXQudmlldy50ZXh0LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpKSx0Lmhhc0hlaWdodHN8fChHdChlLHQudmlldyx0LnJlY3QpLHQuaGFzSGVpZ2h0cz0hMCksbz1YdChlLHQsbixyKSxvLmJvZ3VzfHwodC5jYWNoZVthXT1vKSkse2xlZnQ6by5sZWZ0LHJpZ2h0Om8ucmlnaHQsdG9wOmk/by5ydG9wOm8udG9wLGJvdHRvbTppP28ucmJvdHRvbTpvLmJvdHRvbX19ZnVuY3Rpb24gSnQoZSx0LG4pe2Zvcih2YXIgcixpLG8sYSxzLHUsYz0wO2M8ZS5sZW5ndGg7Yys9MylpZihzPWVbY10sdT1lW2MrMV0sdDxzPyhpPTAsbz0xLGE9ImxlZnQiKTp0PHU/KGk9dC1zLG89aSsxKTooYz09ZS5sZW5ndGgtM3x8dD09dSYmZVtjKzNdPnQpJiYobz11LXMsaT1vLTEsdD49dSYmKGE9InJpZ2h0IikpLG51bGwhPWkpe2lmKHI9ZVtjKzJdLHM9PXUmJm49PShyLmluc2VydExlZnQ/ImxlZnQiOiJyaWdodCIpJiYoYT1uKSwibGVmdCI9PW4mJjA9PWkpZm9yKDtjJiZlW2MtMl09PWVbYy0zXSYmZVtjLTFdLmluc2VydExlZnQ7KXI9ZVsyKyhjLT0zKV0sYT0ibGVmdCI7aWYoInJpZ2h0Ij09biYmaT09dS1zKWZvcig7YzxlLmxlbmd0aC0zJiZlW2MrM109PWVbYys0XSYmIWVbYys1XS5pbnNlcnRMZWZ0OylyPWVbKGMrPTMpKzJdLGE9InJpZ2h0IjticmVha31yZXR1cm57bm9kZTpyLHN0YXJ0OmksZW5kOm8sY29sbGFwc2U6YSxjb3ZlclN0YXJ0OnMsY292ZXJFbmQ6dX19ZnVuY3Rpb24gWXQoZSx0KXt2YXIgbj1DcztpZigibGVmdCI9PXQpZm9yKHZhciByPTA7cjxlLmxlbmd0aCYmKG49ZVtyXSkubGVmdD09bi5yaWdodDtyKyspO2Vsc2UgZm9yKHZhciBpPWUubGVuZ3RoLTE7aT49MCYmKG49ZVtpXSkubGVmdD09bi5yaWdodDtpLS0pO3JldHVybiBufWZ1bmN0aW9uIFh0KGUsdCxuLHIpe3ZhciBpLG89SnQodC5tYXAsbixyKSxhPW8ubm9kZSxzPW8uc3RhcnQsdT1vLmVuZCxjPW8uY29sbGFwc2U7aWYoMz09YS5ub2RlVHlwZSl7Zm9yKHZhciBsPTA7bDw0O2wrKyl7Zm9yKDtzJiZEKHQubGluZS50ZXh0LmNoYXJBdChvLmNvdmVyU3RhcnQrcykpOyktLXM7Zm9yKDtvLmNvdmVyU3RhcnQrdTxvLmNvdmVyRW5kJiZEKHQubGluZS50ZXh0LmNoYXJBdChvLmNvdmVyU3RhcnQrdSkpOykrK3U7aWYoaT1iYSYmeGE8OSYmMD09cyYmdT09by5jb3ZlckVuZC1vLmNvdmVyU3RhcnQ/YS5wYXJlbnROb2RlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOll0KFBhKGEscyx1KS5nZXRDbGllbnRSZWN0cygpLHIpLGkubGVmdHx8aS5yaWdodHx8MD09cylicmVhazt1PXMscy09MSxjPSJyaWdodCJ9YmEmJnhhPDExJiYoaT1adChlLmRpc3BsYXkubWVhc3VyZSxpKSl9ZWxzZXtzPjAmJihjPXI9InJpZ2h0Iik7dmFyIHA7aT1lLm9wdGlvbnMubGluZVdyYXBwaW5nJiYocD1hLmdldENsaWVudFJlY3RzKCkpLmxlbmd0aD4xP3BbInJpZ2h0Ij09cj9wLmxlbmd0aC0xOjBdOmEuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCl9aWYoYmEmJnhhPDkmJiFzJiYoIWl8fCFpLmxlZnQmJiFpLnJpZ2h0KSl7dmFyIGY9YS5wYXJlbnROb2RlLmdldENsaWVudFJlY3RzKClbMF07aT1mP3tsZWZ0OmYubGVmdCxyaWdodDpmLmxlZnQrQ24oZS5kaXNwbGF5KSx0b3A6Zi50b3AsYm90dG9tOmYuYm90dG9tfTpDc31mb3IodmFyIGQ9aS50b3AtdC5yZWN0LnRvcCxoPWkuYm90dG9tLXQucmVjdC50b3AsbT0oZCtoKS8yLGc9dC52aWV3Lm1lYXN1cmUuaGVpZ2h0cyx5PTA7eTxnLmxlbmd0aC0xJiYhKG08Z1t5XSk7eSsrKTt2YXIgdj15P2dbeS0xXTowLGI9Z1t5XSx4PXtsZWZ0OigicmlnaHQiPT1jP2kucmlnaHQ6aS5sZWZ0KS10LnJlY3QubGVmdCxyaWdodDooImxlZnQiPT1jP2kubGVmdDppLnJpZ2h0KS10LnJlY3QubGVmdCx0b3A6dixib3R0b206Yn07cmV0dXJuIGkubGVmdHx8aS5yaWdodHx8KHguYm9ndXM9ITApLGUub3B0aW9ucy5zaW5nbGVDdXJzb3JIZWlnaHRQZXJMaW5lfHwoeC5ydG9wPWQseC5yYm90dG9tPWgpLHh9ZnVuY3Rpb24gWnQoZSx0KXtpZighd2luZG93LnNjcmVlbnx8bnVsbD09c2NyZWVuLmxvZ2ljYWxYRFBJfHxzY3JlZW4ubG9naWNhbFhEUEk9PXNjcmVlbi5kZXZpY2VYRFBJfHwhJGUoZSkpcmV0dXJuIHQ7dmFyIG49c2NyZWVuLmxvZ2ljYWxYRFBJL3NjcmVlbi5kZXZpY2VYRFBJLHI9c2NyZWVuLmxvZ2ljYWxZRFBJL3NjcmVlbi5kZXZpY2VZRFBJO3JldHVybntsZWZ0OnQubGVmdCpuLHJpZ2h0OnQucmlnaHQqbix0b3A6dC50b3Aqcixib3R0b206dC5ib3R0b20qcn19ZnVuY3Rpb24gZW4oZSl7aWYoZS5tZWFzdXJlJiYoZS5tZWFzdXJlLmNhY2hlPXt9LGUubWVhc3VyZS5oZWlnaHRzPW51bGwsZS5yZXN0KSlmb3IodmFyIHQ9MDt0PGUucmVzdC5sZW5ndGg7dCsrKWUubWVhc3VyZS5jYWNoZXNbdF09e319ZnVuY3Rpb24gdG4oZSl7ZS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZT1udWxsLHQoZS5kaXNwbGF5LmxpbmVNZWFzdXJlKTtmb3IodmFyIG49MDtuPGUuZGlzcGxheS52aWV3Lmxlbmd0aDtuKyspZW4oZS5kaXNwbGF5LnZpZXdbbl0pfWZ1bmN0aW9uIG5uKGUpe3RuKGUpLGUuZGlzcGxheS5jYWNoZWRDaGFyV2lkdGg9ZS5kaXNwbGF5LmNhY2hlZFRleHRIZWlnaHQ9ZS5kaXNwbGF5LmNhY2hlZFBhZGRpbmdIPW51bGwsZS5vcHRpb25zLmxpbmVXcmFwcGluZ3x8KGUuZGlzcGxheS5tYXhMaW5lQ2hhbmdlZD0hMCksZS5kaXNwbGF5LmxpbmVOdW1DaGFycz1udWxsfWZ1bmN0aW9uIHJuKCl7cmV0dXJuIERhJiZUYT8tKGRvY3VtZW50LmJvZHkuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdC1wYXJzZUludChnZXRDb21wdXRlZFN0eWxlKGRvY3VtZW50LmJvZHkpLm1hcmdpbkxlZnQpKTp3aW5kb3cucGFnZVhPZmZzZXR8fChkb2N1bWVudC5kb2N1bWVudEVsZW1lbnR8fGRvY3VtZW50LmJvZHkpLnNjcm9sbExlZnR9ZnVuY3Rpb24gb24oKXtyZXR1cm4gRGEmJlRhPy0oZG9jdW1lbnQuYm9keS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3AtcGFyc2VJbnQoZ2V0Q29tcHV0ZWRTdHlsZShkb2N1bWVudC5ib2R5KS5tYXJnaW5Ub3ApKTp3aW5kb3cucGFnZVlPZmZzZXR8fChkb2N1bWVudC5kb2N1bWVudEVsZW1lbnR8fGRvY3VtZW50LmJvZHkpLnNjcm9sbFRvcH1mdW5jdGlvbiBhbihlKXt2YXIgdD0wO2lmKGUud2lkZ2V0cylmb3IodmFyIG49MDtuPGUud2lkZ2V0cy5sZW5ndGg7KytuKWUud2lkZ2V0c1tuXS5hYm92ZSYmKHQrPVB0KGUud2lkZ2V0c1tuXSkpO3JldHVybiB0fWZ1bmN0aW9uIHNuKGUsdCxuLHIsaSl7aWYoIWkpe3ZhciBvPWFuKHQpO24udG9wKz1vLG4uYm90dG9tKz1vfWlmKCJsaW5lIj09cilyZXR1cm4gbjtyfHwocj0ibG9jYWwiKTt2YXIgYT1iZSh0KTtpZigibG9jYWwiPT1yP2ErPWp0KGUuZGlzcGxheSk6YS09ZS5kaXNwbGF5LnZpZXdPZmZzZXQsInBhZ2UiPT1yfHwid2luZG93Ij09cil7dmFyIHM9ZS5kaXNwbGF5LmxpbmVTcGFjZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTthKz1zLnRvcCsoIndpbmRvdyI9PXI/MDpvbigpKTt2YXIgdT1zLmxlZnQrKCJ3aW5kb3ciPT1yPzA6cm4oKSk7bi5sZWZ0Kz11LG4ucmlnaHQrPXV9cmV0dXJuIG4udG9wKz1hLG4uYm90dG9tKz1hLG59ZnVuY3Rpb24gdW4oZSx0LG4pe2lmKCJkaXYiPT1uKXJldHVybiB0O3ZhciByPXQubGVmdCxpPXQudG9wO2lmKCJwYWdlIj09bilyLT1ybigpLGktPW9uKCk7ZWxzZSBpZigibG9jYWwiPT1ufHwhbil7dmFyIG89ZS5kaXNwbGF5LnNpemVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO3IrPW8ubGVmdCxpKz1vLnRvcH12YXIgYT1lLmRpc3BsYXkubGluZVNwYWNlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO3JldHVybntsZWZ0OnItYS5sZWZ0LHRvcDppLWEudG9wfX1mdW5jdGlvbiBjbihlLHQsbixyLGkpe3JldHVybiByfHwocj1BKGUuZG9jLHQubGluZSkpLHNuKGUscixIdChlLHIsdC5jaCxpKSxuKX1mdW5jdGlvbiBsbihlLHQsbixyLGksbyl7ZnVuY3Rpb24gYSh0LGEpe3ZhciBzPUt0KGUsaSx0LGE/InJpZ2h0IjoibGVmdCIsbyk7cmV0dXJuIGE/cy5sZWZ0PXMucmlnaHQ6cy5yaWdodD1zLmxlZnQsc24oZSxyLHMsbil9ZnVuY3Rpb24gcyhlLHQsbil7dmFyIHI9dVt0XSxpPTE9PXIubGV2ZWw7cmV0dXJuIGEobj9lLTE6ZSxpIT1uKX1yPXJ8fEEoZS5kb2MsdC5saW5lKSxpfHwoaT1RdChlLHIpKTt2YXIgdT13ZShyLGUuZG9jLmRpcmVjdGlvbiksYz10LmNoLGw9dC5zdGlja3k7aWYoYz49ci50ZXh0Lmxlbmd0aD8oYz1yLnRleHQubGVuZ3RoLGw9ImJlZm9yZSIpOmM8PTAmJihjPTAsbD0iYWZ0ZXIiKSwhdSlyZXR1cm4gYSgiYmVmb3JlIj09bD9jLTE6YywiYmVmb3JlIj09bCk7dmFyIHA9RGUodSxjLGwpLGY9WmEsZD1zKGMscCwiYmVmb3JlIj09bCk7cmV0dXJuIG51bGwhPWYmJihkLm90aGVyPXMoYyxmLCJiZWZvcmUiIT1sKSksZH1mdW5jdGlvbiBwbihlLHQpe3ZhciBuPTA7dD16KGUuZG9jLHQpLGUub3B0aW9ucy5saW5lV3JhcHBpbmd8fChuPUNuKGUuZGlzcGxheSkqdC5jaCk7dmFyIHI9QShlLmRvYyx0LmxpbmUpLGk9YmUocikranQoZS5kaXNwbGF5KTtyZXR1cm57bGVmdDpuLHJpZ2h0Om4sdG9wOmksYm90dG9tOmkrci5oZWlnaHR9fWZ1bmN0aW9uIGZuKGUsdCxuLHIsaSl7dmFyIG89UChlLHQsbik7cmV0dXJuIG8ueFJlbD1pLHImJihvLm91dHNpZGU9ITApLG99ZnVuY3Rpb24gZG4oZSx0LG4pe3ZhciByPWUuZG9jO2lmKChuKz1lLmRpc3BsYXkudmlld09mZnNldCk8MClyZXR1cm4gZm4oci5maXJzdCwwLG51bGwsITAsLTEpO3ZhciBpPU4ocixuKSxvPXIuZmlyc3Qrci5zaXplLTE7aWYoaT5vKXJldHVybiBmbihyLmZpcnN0K3Iuc2l6ZS0xLEEocixvKS50ZXh0Lmxlbmd0aCxudWxsLCEwLDEpO3Q8MCYmKHQ9MCk7Zm9yKHZhciBhPUEocixpKTs7KXt2YXIgcz15bihlLGEsaSx0LG4pLHU9bGUoYSxzLmNoKyhzLnhSZWw+MD8xOjApKTtpZighdSlyZXR1cm4gczt2YXIgYz11LmZpbmQoMSk7aWYoYy5saW5lPT1pKXJldHVybiBjO2E9QShyLGk9Yy5saW5lKX19ZnVuY3Rpb24gaG4oZSx0LG4scil7ci09YW4odCk7dmFyIGk9dC50ZXh0Lmxlbmd0aCxvPVMoZnVuY3Rpb24odCl7cmV0dXJuIEt0KGUsbix0LTEpLmJvdHRvbTw9cn0saSwwKTtyZXR1cm4gaT1TKGZ1bmN0aW9uKHQpe3JldHVybiBLdChlLG4sdCkudG9wPnJ9LG8saSkse2JlZ2luOm8sZW5kOml9fWZ1bmN0aW9uIG1uKGUsdCxuLHIpe3JldHVybiBufHwobj1RdChlLHQpKSxobihlLHQsbixzbihlLHQsS3QoZSxuLHIpLCJsaW5lIikudG9wKX1mdW5jdGlvbiBnbihlLHQsbixyKXtyZXR1cm4hKGUuYm90dG9tPD1uKSYmKGUudG9wPm58fChyP2UubGVmdDplLnJpZ2h0KT50KX1mdW5jdGlvbiB5bihlLHQsbixyLGkpe2ktPWJlKHQpO3ZhciBvPVF0KGUsdCksYT1hbih0KSxzPTAsdT10LnRleHQubGVuZ3RoLGM9ITAsbD13ZSh0LGUuZG9jLmRpcmVjdGlvbik7aWYobCl7dmFyIHA9KGUub3B0aW9ucy5saW5lV3JhcHBpbmc/Ym46dm4pKGUsdCxuLG8sbCxyLGkpO2M9MSE9cC5sZXZlbCxzPWM/cC5mcm9tOnAudG8tMSx1PWM/cC50bzpwLmZyb20tMX12YXIgZixkLGg9bnVsbCxtPW51bGwsZz1TKGZ1bmN0aW9uKHQpe3ZhciBuPUt0KGUsbyx0KTtyZXR1cm4gbi50b3ArPWEsbi5ib3R0b20rPWEsISFnbihuLHIsaSwhMSkmJihuLnRvcDw9aSYmbi5sZWZ0PD1yJiYoaD10LG09biksITApfSxzLHUpLHk9ITE7aWYobSl7dmFyIHY9ci1tLmxlZnQ8bS5yaWdodC1yLGI9dj09YztnPWgrKGI/MDoxKSxkPWI/ImFmdGVyIjoiYmVmb3JlIixmPXY/bS5sZWZ0Om0ucmlnaHR9ZWxzZXtjfHxnIT11JiZnIT1zfHxnKyssZD0wPT1nPyJhZnRlciI6Zz09dC50ZXh0Lmxlbmd0aD8iYmVmb3JlIjpLdChlLG8sZy0oYz8xOjApKS5ib3R0b20rYTw9aT09Yz8iYWZ0ZXIiOiJiZWZvcmUiO3ZhciB4PWxuKGUsUChuLGcsZCksImxpbmUiLHQsbyk7Zj14LmxlZnQseT1pPHgudG9wfHxpPj14LmJvdHRvbX1yZXR1cm4gZz13KHQudGV4dCxnLDEpLGZuKG4sZyxkLHksci1mKX1mdW5jdGlvbiB2bihlLHQsbixyLGksbyxhKXt2YXIgcz1TKGZ1bmN0aW9uKHMpe3ZhciB1PWlbc10sYz0xIT11LmxldmVsO3JldHVybiBnbihsbihlLFAobixjP3UudG86dS5mcm9tLGM/ImJlZm9yZSI6ImFmdGVyIiksImxpbmUiLHQsciksbyxhLCEwKX0sMCxpLmxlbmd0aC0xKSx1PWlbc107aWYocz4wKXt2YXIgYz0xIT11LmxldmVsLGw9bG4oZSxQKG4sYz91LmZyb206dS50byxjPyJhZnRlciI6ImJlZm9yZSIpLCJsaW5lIix0LHIpO2duKGwsbyxhLCEwKSYmbC50b3A+YSYmKHU9aVtzLTFdKX1yZXR1cm4gdX1mdW5jdGlvbiBibihlLHQsbixyLGksbyxhKXt2YXIgcz1obihlLHQscixhKSx1PXMuYmVnaW4sYz1zLmVuZDsvXHMvLnRlc3QodC50ZXh0LmNoYXJBdChjLTEpKSYmYy0tO2Zvcih2YXIgbD1udWxsLHA9bnVsbCxmPTA7ZjxpLmxlbmd0aDtmKyspe3ZhciBkPWlbZl07aWYoIShkLmZyb20+PWN8fGQudG88PXUpKXt2YXIgaD0xIT1kLmxldmVsLG09S3QoZSxyLGg/TWF0aC5taW4oYyxkLnRvKS0xOk1hdGgubWF4KHUsZC5mcm9tKSkucmlnaHQsZz1tPG8/by1tKzFlOTptLW87KCFsfHxwPmcpJiYobD1kLHA9Zyl9fXJldHVybiBsfHwobD1pW2kubGVuZ3RoLTFdKSxsLmZyb208dSYmKGw9e2Zyb206dSx0bzpsLnRvLGxldmVsOmwubGV2ZWx9KSxsLnRvPmMmJihsPXtmcm9tOmwuZnJvbSx0bzpjLGxldmVsOmwubGV2ZWx9KSxsfWZ1bmN0aW9uIHhuKGUpe2lmKG51bGwhPWUuY2FjaGVkVGV4dEhlaWdodClyZXR1cm4gZS5jYWNoZWRUZXh0SGVpZ2h0O2lmKG51bGw9PWdzKXtncz1yKCJwcmUiKTtmb3IodmFyIGk9MDtpPDQ5OysraSlncy5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgieCIpKSxncy5hcHBlbmRDaGlsZChyKCJiciIpKTtncy5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgieCIpKX1uKGUubWVhc3VyZSxncyk7dmFyIG89Z3Mub2Zmc2V0SGVpZ2h0LzUwO3JldHVybiBvPjMmJihlLmNhY2hlZFRleHRIZWlnaHQ9byksdChlLm1lYXN1cmUpLG98fDF9ZnVuY3Rpb24gQ24oZSl7aWYobnVsbCE9ZS5jYWNoZWRDaGFyV2lkdGgpcmV0dXJuIGUuY2FjaGVkQ2hhcldpZHRoO3ZhciB0PXIoInNwYW4iLCJ4eHh4eHh4eHh4IiksaT1yKCJwcmUiLFt0XSk7bihlLm1lYXN1cmUsaSk7dmFyIG89dC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSxhPShvLnJpZ2h0LW8ubGVmdCkvMTA7cmV0dXJuIGE+MiYmKGUuY2FjaGVkQ2hhcldpZHRoPWEpLGF8fDEwfWZ1bmN0aW9uIEVuKGUpe2Zvcih2YXIgdD1lLmRpc3BsYXksbj17fSxyPXt9LGk9dC5ndXR0ZXJzLmNsaWVudExlZnQsbz10Lmd1dHRlcnMuZmlyc3RDaGlsZCxhPTA7bztvPW8ubmV4dFNpYmxpbmcsKythKW5bZS5vcHRpb25zLmd1dHRlcnNbYV1dPW8ub2Zmc2V0TGVmdCtvLmNsaWVudExlZnQraSxyW2Uub3B0aW9ucy5ndXR0ZXJzW2FdXT1vLmNsaWVudFdpZHRoO3JldHVybntmaXhlZFBvczpEbih0KSxndXR0ZXJUb3RhbFdpZHRoOnQuZ3V0dGVycy5vZmZzZXRXaWR0aCxndXR0ZXJMZWZ0Om4sZ3V0dGVyV2lkdGg6cix3cmFwcGVyV2lkdGg6dC53cmFwcGVyLmNsaWVudFdpZHRofX1mdW5jdGlvbiBEbihlKXtyZXR1cm4gZS5zY3JvbGxlci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5sZWZ0LWUuc2l6ZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdH1mdW5jdGlvbiB3bihlKXt2YXIgdD14bihlLmRpc3BsYXkpLG49ZS5vcHRpb25zLmxpbmVXcmFwcGluZyxyPW4mJk1hdGgubWF4KDUsZS5kaXNwbGF5LnNjcm9sbGVyLmNsaWVudFdpZHRoL0NuKGUuZGlzcGxheSktMyk7cmV0dXJuIGZ1bmN0aW9uKGkpe2lmKHllKGUuZG9jLGkpKXJldHVybiAwO3ZhciBvPTA7aWYoaS53aWRnZXRzKWZvcih2YXIgYT0wO2E8aS53aWRnZXRzLmxlbmd0aDthKyspaS53aWRnZXRzW2FdLmhlaWdodCYmKG8rPWkud2lkZ2V0c1thXS5oZWlnaHQpO3JldHVybiBuP28rKE1hdGguY2VpbChpLnRleHQubGVuZ3RoL3IpfHwxKSp0Om8rdH19ZnVuY3Rpb24gU24oZSl7dmFyIHQ9ZS5kb2Msbj13bihlKTt0Lml0ZXIoZnVuY3Rpb24oZSl7dmFyIHQ9bihlKTt0IT1lLmhlaWdodCYmTyhlLHQpfSl9ZnVuY3Rpb24ga24oZSx0LG4scil7dmFyIGk9ZS5kaXNwbGF5O2lmKCFuJiYidHJ1ZSI9PU1lKHQpLmdldEF0dHJpYnV0ZSgiY20tbm90LWNvbnRlbnQiKSlyZXR1cm4gbnVsbDt2YXIgbyxhLHM9aS5saW5lU3BhY2UuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7dHJ5e289dC5jbGllbnRYLXMubGVmdCxhPXQuY2xpZW50WS1zLnRvcH1jYXRjaCh0KXtyZXR1cm4gbnVsbH12YXIgdSxjPWRuKGUsbyxhKTtpZihyJiYxPT1jLnhSZWwmJih1PUEoZS5kb2MsYy5saW5lKS50ZXh0KS5sZW5ndGg9PWMuY2gpe3ZhciBsPXAodSx1Lmxlbmd0aCxlLm9wdGlvbnMudGFiU2l6ZSktdS5sZW5ndGg7Yz1QKGMubGluZSxNYXRoLm1heCgwLE1hdGgucm91bmQoKG8tQnQoZS5kaXNwbGF5KS5sZWZ0KS9DbihlLmRpc3BsYXkpKS1sKSl9cmV0dXJuIGN9ZnVuY3Rpb24gQW4oZSx0KXtpZih0Pj1lLmRpc3BsYXkudmlld1RvKXJldHVybiBudWxsO2lmKCh0LT1lLmRpc3BsYXkudmlld0Zyb20pPDApcmV0dXJuIG51bGw7Zm9yKHZhciBuPWUuZGlzcGxheS52aWV3LHI9MDtyPG4ubGVuZ3RoO3IrKylpZigodC09bltyXS5zaXplKTwwKXJldHVybiByfWZ1bmN0aW9uIF9uKGUpe2UuZGlzcGxheS5pbnB1dC5zaG93U2VsZWN0aW9uKGUuZGlzcGxheS5pbnB1dC5wcmVwYXJlU2VsZWN0aW9uKCkpfWZ1bmN0aW9uIFRuKGUsdCl7dm9pZCAwPT09dCYmKHQ9ITApO2Zvcih2YXIgbj1lLmRvYyxyPXt9LGk9ci5jdXJzb3JzPWRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSxvPXIuc2VsZWN0aW9uPWRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSxhPTA7YTxuLnNlbC5yYW5nZXMubGVuZ3RoO2ErKylpZih0fHxhIT1uLnNlbC5wcmltSW5kZXgpe3ZhciBzPW4uc2VsLnJhbmdlc1thXTtpZighKHMuZnJvbSgpLmxpbmU+PWUuZGlzcGxheS52aWV3VG98fHMudG8oKS5saW5lPGUuZGlzcGxheS52aWV3RnJvbSkpe3ZhciB1PXMuZW1wdHkoKTsodXx8ZS5vcHRpb25zLnNob3dDdXJzb3JXaGVuU2VsZWN0aW5nKSYmT24oZSxzLmhlYWQsaSksdXx8Tm4oZSxzLG8pfX1yZXR1cm4gcn1mdW5jdGlvbiBPbihlLHQsbil7dmFyIGk9bG4oZSx0LCJkaXYiLG51bGwsbnVsbCwhZS5vcHRpb25zLnNpbmdsZUN1cnNvckhlaWdodFBlckxpbmUpLG89bi5hcHBlbmRDaGlsZChyKCJkaXYiLCJceGEwIiwiQ29kZU1pcnJvci1jdXJzb3IiKSk7aWYoby5zdHlsZS5sZWZ0PWkubGVmdCsicHgiLG8uc3R5bGUudG9wPWkudG9wKyJweCIsby5zdHlsZS5oZWlnaHQ9TWF0aC5tYXgoMCxpLmJvdHRvbS1pLnRvcCkqZS5vcHRpb25zLmN1cnNvckhlaWdodCsicHgiLGkub3RoZXIpe3ZhciBhPW4uYXBwZW5kQ2hpbGQocigiZGl2IiwiXHhhMCIsIkNvZGVNaXJyb3ItY3Vyc29yIENvZGVNaXJyb3Itc2Vjb25kYXJ5Y3Vyc29yIikpO2Euc3R5bGUuZGlzcGxheT0iIixhLnN0eWxlLmxlZnQ9aS5vdGhlci5sZWZ0KyJweCIsYS5zdHlsZS50b3A9aS5vdGhlci50b3ArInB4IixhLnN0eWxlLmhlaWdodD0uODUqKGkub3RoZXIuYm90dG9tLWkub3RoZXIudG9wKSsicHgifX1mdW5jdGlvbiBGbihlLHQpe3JldHVybiBlLnRvcC10LnRvcHx8ZS5sZWZ0LXQubGVmdH1mdW5jdGlvbiBObihlLHQsbil7ZnVuY3Rpb24gaShlLHQsbixpKXt0PDAmJih0PTApLHQ9TWF0aC5yb3VuZCh0KSxpPU1hdGgucm91bmQoaSksdS5hcHBlbmRDaGlsZChyKCJkaXYiLG51bGwsIkNvZGVNaXJyb3Itc2VsZWN0ZWQiLCJwb3NpdGlvbjogYWJzb2x1dGU7IGxlZnQ6ICIrZSsicHg7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvcDogIit0KyJweDsgd2lkdGg6ICIrKG51bGw9PW4/cC1lOm4pKyJweDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiAiKyhpLXQpKyJweCIpKX1mdW5jdGlvbiBvKHQsbixyKXtmdW5jdGlvbiBvKG4scil7cmV0dXJuIGNuKGUsUCh0LG4pLCJkaXYiLGQscil9ZnVuY3Rpb24gYSh0LG4scil7dmFyIGk9bW4oZSxkLG51bGwsdCksYT0ibHRyIj09bj09KCJhZnRlciI9PXIpPyJsZWZ0IjoicmlnaHQiO3JldHVybiBvKCJhZnRlciI9PXI/aS5iZWdpbjppLmVuZC0oL1xzLy50ZXN0KGQudGV4dC5jaGFyQXQoaS5lbmQtMSkpPzI6MSksYSlbYV19dmFyIHUsYyxkPUEocyx0KSxoPWQudGV4dC5sZW5ndGgsbT13ZShkLHMuZGlyZWN0aW9uKTtyZXR1cm4gRWUobSxufHwwLG51bGw9PXI/aDpyLGZ1bmN0aW9uKGUsdCxzLGQpe3ZhciBnPSJsdHIiPT1zLHk9byhlLGc/ImxlZnQiOiJyaWdodCIpLHY9byh0LTEsZz8icmlnaHQiOiJsZWZ0IiksYj1udWxsPT1uJiYwPT1lLHg9bnVsbD09ciYmdD09aCxDPTA9PWQsRT0hbXx8ZD09bS5sZW5ndGgtMTtpZih2LnRvcC15LnRvcDw9Myl7dmFyIEQ9KGY/Yjp4KSYmQyx3PShmP3g6YikmJkUsUz1EP2w6KGc/eTp2KS5sZWZ0LGs9dz9wOihnP3Y6eSkucmlnaHQ7aShTLHkudG9wLGstUyx5LmJvdHRvbSl9ZWxzZXt2YXIgQSxfLFQsTztnPyhBPWYmJmImJkM/bDp5LmxlZnQsXz1mP3A6YShlLHMsImJlZm9yZSIpLFQ9Zj9sOmEodCxzLCJhZnRlciIpLE89ZiYmeCYmRT9wOnYucmlnaHQpOihBPWY/YShlLHMsImJlZm9yZSIpOmwsXz0hZiYmYiYmQz9wOnkucmlnaHQsVD0hZiYmeCYmRT9sOnYubGVmdCxPPWY/YSh0LHMsImFmdGVyIik6cCksaShBLHkudG9wLF8tQSx5LmJvdHRvbSkseS5ib3R0b208di50b3AmJmkobCx5LmJvdHRvbSxudWxsLHYudG9wKSxpKFQsdi50b3AsTy1ULHYuYm90dG9tKX0oIXV8fEZuKHksdSk8MCkmJih1PXkpLEZuKHYsdSk8MCYmKHU9diksKCFjfHxGbih5LGMpPDApJiYoYz15KSxGbih2LGMpPDAmJihjPXYpfSkse3N0YXJ0OnUsZW5kOmN9fXZhciBhPWUuZGlzcGxheSxzPWUuZG9jLHU9ZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLGM9QnQoZS5kaXNwbGF5KSxsPWMubGVmdCxwPU1hdGgubWF4KGEuc2l6ZXJXaWR0aCxVdChlKS1hLnNpemVyLm9mZnNldExlZnQpLWMucmlnaHQsZj0ibHRyIj09cy5kaXJlY3Rpb24sZD10LmZyb20oKSxoPXQudG8oKTtpZihkLmxpbmU9PWgubGluZSlvKGQubGluZSxkLmNoLGguY2gpO2Vsc2V7dmFyIG09QShzLGQubGluZSksZz1BKHMsaC5saW5lKSx5PWZlKG0pPT1mZShnKSx2PW8oZC5saW5lLGQuY2gseT9tLnRleHQubGVuZ3RoKzE6bnVsbCkuZW5kLGI9byhoLmxpbmUseT8wOm51bGwsaC5jaCkuc3RhcnQ7eSYmKHYudG9wPGIudG9wLTI/KGkodi5yaWdodCx2LnRvcCxudWxsLHYuYm90dG9tKSxpKGwsYi50b3AsYi5sZWZ0LGIuYm90dG9tKSk6aSh2LnJpZ2h0LHYudG9wLGIubGVmdC12LnJpZ2h0LHYuYm90dG9tKSksdi5ib3R0b208Yi50b3AmJmkobCx2LmJvdHRvbSxudWxsLGIudG9wKX1uLmFwcGVuZENoaWxkKHUpfWZ1bmN0aW9uIEluKGUpe2lmKGUuc3RhdGUuZm9jdXNlZCl7dmFyIHQ9ZS5kaXNwbGF5O2NsZWFySW50ZXJ2YWwodC5ibGlua2VyKTt2YXIgbj0hMDt0LmN1cnNvckRpdi5zdHlsZS52aXNpYmlsaXR5PSIiLGUub3B0aW9ucy5jdXJzb3JCbGlua1JhdGU+MD90LmJsaW5rZXI9c2V0SW50ZXJ2YWwoZnVuY3Rpb24oKXtyZXR1cm4gdC5jdXJzb3JEaXYuc3R5bGUudmlzaWJpbGl0eT0obj0hbik/IiI6ImhpZGRlbiJ9LGUub3B0aW9ucy5jdXJzb3JCbGlua1JhdGUpOmUub3B0aW9ucy5jdXJzb3JCbGlua1JhdGU8MCYmKHQuY3Vyc29yRGl2LnN0eWxlLnZpc2liaWxpdHk9ImhpZGRlbiIpfX1mdW5jdGlvbiBMbihlKXtlLnN0YXRlLmZvY3VzZWR8fChlLmRpc3BsYXkuaW5wdXQuZm9jdXMoKSxNbihlKSl9ZnVuY3Rpb24gUG4oZSl7ZS5zdGF0ZS5kZWxheWluZ0JsdXJFdmVudD0hMCxzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7ZS5zdGF0ZS5kZWxheWluZ0JsdXJFdmVudCYmKGUuc3RhdGUuZGVsYXlpbmdCbHVyRXZlbnQ9ITEsam4oZSkpfSwxMDApfWZ1bmN0aW9uIE1uKGUsdCl7ZS5zdGF0ZS5kZWxheWluZ0JsdXJFdmVudCYmKGUuc3RhdGUuZGVsYXlpbmdCbHVyRXZlbnQ9ITEpLCJub2N1cnNvciIhPWUub3B0aW9ucy5yZWFkT25seSYmKGUuc3RhdGUuZm9jdXNlZHx8KEFlKGUsImZvY3VzIixlLHQpLGUuc3RhdGUuZm9jdXNlZD0hMCxzKGUuZGlzcGxheS53cmFwcGVyLCJDb2RlTWlycm9yLWZvY3VzZWQiKSxlLmN1ck9wfHxlLmRpc3BsYXkuc2VsRm9yQ29udGV4dE1lbnU9PWUuZG9jLnNlbHx8KGUuZGlzcGxheS5pbnB1dC5yZXNldCgpLENhJiZzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIGUuZGlzcGxheS5pbnB1dC5yZXNldCghMCl9LDIwKSksZS5kaXNwbGF5LmlucHV0LnJlY2VpdmVkRm9jdXMoKSksSW4oZSkpfWZ1bmN0aW9uIGpuKGUsdCl7ZS5zdGF0ZS5kZWxheWluZ0JsdXJFdmVudHx8KGUuc3RhdGUuZm9jdXNlZCYmKEFlKGUsImJsdXIiLGUsdCksZS5zdGF0ZS5mb2N1c2VkPSExLFJhKGUuZGlzcGxheS53cmFwcGVyLCJDb2RlTWlycm9yLWZvY3VzZWQiKSksY2xlYXJJbnRlcnZhbChlLmRpc3BsYXkuYmxpbmtlciksc2V0VGltZW91dChmdW5jdGlvbigpe2Uuc3RhdGUuZm9jdXNlZHx8KGUuZGlzcGxheS5zaGlmdD0hMSl9LDE1MCkpfWZ1bmN0aW9uIFJuKGUpe2Zvcih2YXIgdD1lLmRpc3BsYXksbj10LmxpbmVEaXYub2Zmc2V0VG9wLHI9MDtyPHQudmlldy5sZW5ndGg7cisrKXt2YXIgaT10LnZpZXdbcl0sbz12b2lkIDA7aWYoIWkuaGlkZGVuKXtpZihiYSYmeGE8OCl7dmFyIGE9aS5ub2RlLm9mZnNldFRvcCtpLm5vZGUub2Zmc2V0SGVpZ2h0O289YS1uLG49YX1lbHNle3ZhciBzPWkubm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtvPXMuYm90dG9tLXMudG9wfXZhciB1PWkubGluZS5oZWlnaHQtbztpZihvPDImJihvPXhuKHQpKSwodT4uMDA1fHx1PC0uMDA1KSYmKE8oaS5saW5lLG8pLEJuKGkubGluZSksaS5yZXN0KSlmb3IodmFyIGM9MDtjPGkucmVzdC5sZW5ndGg7YysrKUJuKGkucmVzdFtjXSl9fX1mdW5jdGlvbiBCbihlKXtpZihlLndpZGdldHMpZm9yKHZhciB0PTA7dDxlLndpZGdldHMubGVuZ3RoOysrdCl7dmFyIG49ZS53aWRnZXRzW3RdLHI9bi5ub2RlLnBhcmVudE5vZGU7ciYmKG4uaGVpZ2h0PXIub2Zmc2V0SGVpZ2h0KX19ZnVuY3Rpb24gJG4oZSx0LG4pe3ZhciByPW4mJm51bGwhPW4udG9wP01hdGgubWF4KDAsbi50b3ApOmUuc2Nyb2xsZXIuc2Nyb2xsVG9wO3I9TWF0aC5mbG9vcihyLWp0KGUpKTt2YXIgaT1uJiZudWxsIT1uLmJvdHRvbT9uLmJvdHRvbTpyK2Uud3JhcHBlci5jbGllbnRIZWlnaHQsbz1OKHQsciksYT1OKHQsaSk7aWYobiYmbi5lbnN1cmUpe3ZhciBzPW4uZW5zdXJlLmZyb20ubGluZSx1PW4uZW5zdXJlLnRvLmxpbmU7czxvPyhvPXMsYT1OKHQsYmUoQSh0LHMpKStlLndyYXBwZXIuY2xpZW50SGVpZ2h0KSk6TWF0aC5taW4odSx0Lmxhc3RMaW5lKCkpPj1hJiYobz1OKHQsYmUoQSh0LHUpKS1lLndyYXBwZXIuY2xpZW50SGVpZ2h0KSxhPXUpfXJldHVybntmcm9tOm8sdG86TWF0aC5tYXgoYSxvKzEpfX1mdW5jdGlvbiBVbihlKXt2YXIgdD1lLmRpc3BsYXksbj10LnZpZXc7aWYodC5hbGlnbldpZGdldHN8fHQuZ3V0dGVycy5maXJzdENoaWxkJiZlLm9wdGlvbnMuZml4ZWRHdXR0ZXIpe2Zvcih2YXIgcj1Ebih0KS10LnNjcm9sbGVyLnNjcm9sbExlZnQrZS5kb2Muc2Nyb2xsTGVmdCxpPXQuZ3V0dGVycy5vZmZzZXRXaWR0aCxvPXIrInB4IixhPTA7YTxuLmxlbmd0aDthKyspaWYoIW5bYV0uaGlkZGVuKXtlLm9wdGlvbnMuZml4ZWRHdXR0ZXImJihuW2FdLmd1dHRlciYmKG5bYV0uZ3V0dGVyLnN0eWxlLmxlZnQ9byksblthXS5ndXR0ZXJCYWNrZ3JvdW5kJiYoblthXS5ndXR0ZXJCYWNrZ3JvdW5kLnN0eWxlLmxlZnQ9bykpO3ZhciBzPW5bYV0uYWxpZ25hYmxlO2lmKHMpZm9yKHZhciB1PTA7dTxzLmxlbmd0aDt1Kyspc1t1XS5zdHlsZS5sZWZ0PW99ZS5vcHRpb25zLmZpeGVkR3V0dGVyJiYodC5ndXR0ZXJzLnN0eWxlLmxlZnQ9citpKyJweCIpfX1mdW5jdGlvbiB6bihlKXtpZighZS5vcHRpb25zLmxpbmVOdW1iZXJzKXJldHVybiExO3ZhciB0PWUuZG9jLG49TChlLm9wdGlvbnMsdC5maXJzdCt0LnNpemUtMSksaT1lLmRpc3BsYXk7aWYobi5sZW5ndGghPWkubGluZU51bUNoYXJzKXt2YXIgbz1pLm1lYXN1cmUuYXBwZW5kQ2hpbGQocigiZGl2IixbcigiZGl2IixuKV0sIkNvZGVNaXJyb3ItbGluZW51bWJlciBDb2RlTWlycm9yLWd1dHRlci1lbHQiKSksYT1vLmZpcnN0Q2hpbGQub2Zmc2V0V2lkdGgscz1vLm9mZnNldFdpZHRoLWE7cmV0dXJuIGkubGluZUd1dHRlci5zdHlsZS53aWR0aD0iIixpLmxpbmVOdW1Jbm5lcldpZHRoPU1hdGgubWF4KGEsaS5saW5lR3V0dGVyLm9mZnNldFdpZHRoLXMpKzEsaS5saW5lTnVtV2lkdGg9aS5saW5lTnVtSW5uZXJXaWR0aCtzLGkubGluZU51bUNoYXJzPWkubGluZU51bUlubmVyV2lkdGg/bi5sZW5ndGg6LTEsaS5saW5lR3V0dGVyLnN0eWxlLndpZHRoPWkubGluZU51bVdpZHRoKyJweCIsSXIoZSksITB9cmV0dXJuITF9ZnVuY3Rpb24gR24oZSx0KXtpZighX2UoZSwic2Nyb2xsQ3Vyc29ySW50b1ZpZXciKSl7dmFyIG49ZS5kaXNwbGF5LGk9bi5zaXplci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSxvPW51bGw7aWYodC50b3AraS50b3A8MD9vPSEwOnQuYm90dG9tK2kudG9wPih3aW5kb3cuaW5uZXJIZWlnaHR8fGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQpJiYobz0hMSksbnVsbCE9byYmIUFhKXt2YXIgYT1yKCJkaXYiLCJcdTIwMGIiLG51bGwsInBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICB0b3A6ICIrKHQudG9wLW4udmlld09mZnNldC1qdChlLmRpc3BsYXkpKSsicHg7XG4gICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiAiKyh0LmJvdHRvbS10LnRvcCskdChlKStuLmJhckhlaWdodCkrInB4O1xuICAgICAgICAgICAgICAgICAgICAgICAgIGxlZnQ6ICIrdC5sZWZ0KyJweDsgd2lkdGg6ICIrTWF0aC5tYXgoMix0LnJpZ2h0LXQubGVmdCkrInB4OyIpO2UuZGlzcGxheS5saW5lU3BhY2UuYXBwZW5kQ2hpbGQoYSksYS5zY3JvbGxJbnRvVmlldyhvKSxlLmRpc3BsYXkubGluZVNwYWNlLnJlbW92ZUNoaWxkKGEpfX19ZnVuY3Rpb24gVm4oZSx0LG4scil7bnVsbD09ciYmKHI9MCk7dmFyIGk7ZS5vcHRpb25zLmxpbmVXcmFwcGluZ3x8dCE9bnx8KHQ9dC5jaD9QKHQubGluZSwiYmVmb3JlIj09dC5zdGlja3k/dC5jaC0xOnQuY2gsImFmdGVyIik6dCxuPSJiZWZvcmUiPT10LnN0aWNreT9QKHQubGluZSx0LmNoKzEsImJlZm9yZSIpOnQpO2Zvcih2YXIgbz0wO288NTtvKyspe3ZhciBhPSExLHM9bG4oZSx0KSx1PW4mJm4hPXQ/bG4oZSxuKTpzO2k9e2xlZnQ6TWF0aC5taW4ocy5sZWZ0LHUubGVmdCksdG9wOk1hdGgubWluKHMudG9wLHUudG9wKS1yLHJpZ2h0Ok1hdGgubWF4KHMubGVmdCx1LmxlZnQpLGJvdHRvbTpNYXRoLm1heChzLmJvdHRvbSx1LmJvdHRvbSkrcn07dmFyIGM9SG4oZSxpKSxsPWUuZG9jLnNjcm9sbFRvcCxwPWUuZG9jLnNjcm9sbExlZnQ7aWYobnVsbCE9Yy5zY3JvbGxUb3AmJihabihlLGMuc2Nyb2xsVG9wKSxNYXRoLmFicyhlLmRvYy5zY3JvbGxUb3AtbCk+MSYmKGE9ITApKSxudWxsIT1jLnNjcm9sbExlZnQmJih0cihlLGMuc2Nyb2xsTGVmdCksTWF0aC5hYnMoZS5kb2Muc2Nyb2xsTGVmdC1wKT4xJiYoYT0hMCkpLCFhKWJyZWFrfXJldHVybiBpfWZ1bmN0aW9uIHFuKGUsdCl7dmFyIG49SG4oZSx0KTtudWxsIT1uLnNjcm9sbFRvcCYmWm4oZSxuLnNjcm9sbFRvcCksbnVsbCE9bi5zY3JvbGxMZWZ0JiZ0cihlLG4uc2Nyb2xsTGVmdCl9ZnVuY3Rpb24gSG4oZSx0KXt2YXIgbj1lLmRpc3BsYXkscj14bihlLmRpc3BsYXkpO3QudG9wPDAmJih0LnRvcD0wKTt2YXIgaT1lLmN1ck9wJiZudWxsIT1lLmN1ck9wLnNjcm9sbFRvcD9lLmN1ck9wLnNjcm9sbFRvcDpuLnNjcm9sbGVyLnNjcm9sbFRvcCxvPXp0KGUpLGE9e307dC5ib3R0b20tdC50b3A+byYmKHQuYm90dG9tPXQudG9wK28pO3ZhciBzPWUuZG9jLmhlaWdodCtSdChuKSx1PXQudG9wPHIsYz10LmJvdHRvbT5zLXI7aWYodC50b3A8aSlhLnNjcm9sbFRvcD11PzA6dC50b3A7ZWxzZSBpZih0LmJvdHRvbT5pK28pe3ZhciBsPU1hdGgubWluKHQudG9wLChjP3M6dC5ib3R0b20pLW8pO2whPWkmJihhLnNjcm9sbFRvcD1sKX12YXIgcD1lLmN1ck9wJiZudWxsIT1lLmN1ck9wLnNjcm9sbExlZnQ/ZS5jdXJPcC5zY3JvbGxMZWZ0Om4uc2Nyb2xsZXIuc2Nyb2xsTGVmdCxmPVV0KGUpLShlLm9wdGlvbnMuZml4ZWRHdXR0ZXI/bi5ndXR0ZXJzLm9mZnNldFdpZHRoOjApLGQ9dC5yaWdodC10LmxlZnQ+ZjtyZXR1cm4gZCYmKHQucmlnaHQ9dC5sZWZ0K2YpLHQubGVmdDwxMD9hLnNjcm9sbExlZnQ9MDp0LmxlZnQ8cD9hLnNjcm9sbExlZnQ9TWF0aC5tYXgoMCx0LmxlZnQtKGQ/MDoxMCkpOnQucmlnaHQ+ZitwLTMmJihhLnNjcm9sbExlZnQ9dC5yaWdodCsoZD8wOjEwKS1mKSxhfWZ1bmN0aW9uIFduKGUsdCl7bnVsbCE9dCYmKFluKGUpLGUuY3VyT3Auc2Nyb2xsVG9wPShudWxsPT1lLmN1ck9wLnNjcm9sbFRvcD9lLmRvYy5zY3JvbGxUb3A6ZS5jdXJPcC5zY3JvbGxUb3ApK3QpfWZ1bmN0aW9uIFFuKGUpe1luKGUpO3ZhciB0PWUuZ2V0Q3Vyc29yKCk7ZS5jdXJPcC5zY3JvbGxUb1Bvcz17ZnJvbTp0LHRvOnQsbWFyZ2luOmUub3B0aW9ucy5jdXJzb3JTY3JvbGxNYXJnaW59fWZ1bmN0aW9uIEtuKGUsdCxuKXtudWxsPT10JiZudWxsPT1ufHxZbihlKSxudWxsIT10JiYoZS5jdXJPcC5zY3JvbGxMZWZ0PXQpLG51bGwhPW4mJihlLmN1ck9wLnNjcm9sbFRvcD1uKX1mdW5jdGlvbiBKbihlLHQpe1luKGUpLGUuY3VyT3Auc2Nyb2xsVG9Qb3M9dH1mdW5jdGlvbiBZbihlKXt2YXIgdD1lLmN1ck9wLnNjcm9sbFRvUG9zO2lmKHQpe2UuY3VyT3Auc2Nyb2xsVG9Qb3M9bnVsbDtYbihlLHBuKGUsdC5mcm9tKSxwbihlLHQudG8pLHQubWFyZ2luKX19ZnVuY3Rpb24gWG4oZSx0LG4scil7dmFyIGk9SG4oZSx7bGVmdDpNYXRoLm1pbih0LmxlZnQsbi5sZWZ0KSx0b3A6TWF0aC5taW4odC50b3Asbi50b3ApLXIscmlnaHQ6TWF0aC5tYXgodC5yaWdodCxuLnJpZ2h0KSxib3R0b206TWF0aC5tYXgodC5ib3R0b20sbi5ib3R0b20pK3J9KTtLbihlLGkuc2Nyb2xsTGVmdCxpLnNjcm9sbFRvcCl9ZnVuY3Rpb24gWm4oZSx0KXtNYXRoLmFicyhlLmRvYy5zY3JvbGxUb3AtdCk8Mnx8KG1hfHxGcihlLHt0b3A6dH0pLGVyKGUsdCwhMCksbWEmJkZyKGUpLHdyKGUsMTAwKSl9ZnVuY3Rpb24gZXIoZSx0LG4pe3Q9TWF0aC5taW4oZS5kaXNwbGF5LnNjcm9sbGVyLnNjcm9sbEhlaWdodC1lLmRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50SGVpZ2h0LHQpLChlLmRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wIT10fHxuKSYmKGUuZG9jLnNjcm9sbFRvcD10LGUuZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbFRvcCh0KSxlLmRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wIT10JiYoZS5kaXNwbGF5LnNjcm9sbGVyLnNjcm9sbFRvcD10KSl9ZnVuY3Rpb24gdHIoZSx0LG4scil7dD1NYXRoLm1pbih0LGUuZGlzcGxheS5zY3JvbGxlci5zY3JvbGxXaWR0aC1lLmRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50V2lkdGgpLChuP3Q9PWUuZG9jLnNjcm9sbExlZnQ6TWF0aC5hYnMoZS5kb2Muc2Nyb2xsTGVmdC10KTwyKSYmIXJ8fChlLmRvYy5zY3JvbGxMZWZ0PXQsVW4oZSksZS5kaXNwbGF5LnNjcm9sbGVyLnNjcm9sbExlZnQhPXQmJihlLmRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsTGVmdD10KSxlLmRpc3BsYXkuc2Nyb2xsYmFycy5zZXRTY3JvbGxMZWZ0KHQpKX1mdW5jdGlvbiBucihlKXt2YXIgdD1lLmRpc3BsYXksbj10Lmd1dHRlcnMub2Zmc2V0V2lkdGgscj1NYXRoLnJvdW5kKGUuZG9jLmhlaWdodCtSdChlLmRpc3BsYXkpKTtyZXR1cm57Y2xpZW50SGVpZ2h0OnQuc2Nyb2xsZXIuY2xpZW50SGVpZ2h0LHZpZXdIZWlnaHQ6dC53cmFwcGVyLmNsaWVudEhlaWdodCxzY3JvbGxXaWR0aDp0LnNjcm9sbGVyLnNjcm9sbFdpZHRoLGNsaWVudFdpZHRoOnQuc2Nyb2xsZXIuY2xpZW50V2lkdGgsdmlld1dpZHRoOnQud3JhcHBlci5jbGllbnRXaWR0aCxiYXJMZWZ0OmUub3B0aW9ucy5maXhlZEd1dHRlcj9uOjAsZG9jSGVpZ2h0OnIsc2Nyb2xsSGVpZ2h0OnIrJHQoZSkrdC5iYXJIZWlnaHQsbmF0aXZlQmFyV2lkdGg6dC5uYXRpdmVCYXJXaWR0aCxndXR0ZXJXaWR0aDpufX1mdW5jdGlvbiBycihlLHQpe3R8fCh0PW5yKGUpKTt2YXIgbj1lLmRpc3BsYXkuYmFyV2lkdGgscj1lLmRpc3BsYXkuYmFySGVpZ2h0O2lyKGUsdCk7Zm9yKHZhciBpPTA7aTw0JiZuIT1lLmRpc3BsYXkuYmFyV2lkdGh8fHIhPWUuZGlzcGxheS5iYXJIZWlnaHQ7aSsrKW4hPWUuZGlzcGxheS5iYXJXaWR0aCYmZS5vcHRpb25zLmxpbmVXcmFwcGluZyYmUm4oZSksaXIoZSxucihlKSksbj1lLmRpc3BsYXkuYmFyV2lkdGgscj1lLmRpc3BsYXkuYmFySGVpZ2h0fWZ1bmN0aW9uIGlyKGUsdCl7dmFyIG49ZS5kaXNwbGF5LHI9bi5zY3JvbGxiYXJzLnVwZGF0ZSh0KTtuLnNpemVyLnN0eWxlLnBhZGRpbmdSaWdodD0obi5iYXJXaWR0aD1yLnJpZ2h0KSsicHgiLG4uc2l6ZXIuc3R5bGUucGFkZGluZ0JvdHRvbT0obi5iYXJIZWlnaHQ9ci5ib3R0b20pKyJweCIsbi5oZWlnaHRGb3JjZXIuc3R5bGUuYm9yZGVyQm90dG9tPXIuYm90dG9tKyJweCBzb2xpZCB0cmFuc3BhcmVudCIsci5yaWdodCYmci5ib3R0b20/KG4uc2Nyb2xsYmFyRmlsbGVyLnN0eWxlLmRpc3BsYXk9ImJsb2NrIixuLnNjcm9sbGJhckZpbGxlci5zdHlsZS5oZWlnaHQ9ci5ib3R0b20rInB4IixuLnNjcm9sbGJhckZpbGxlci5zdHlsZS53aWR0aD1yLnJpZ2h0KyJweCIpOm4uc2Nyb2xsYmFyRmlsbGVyLnN0eWxlLmRpc3BsYXk9IiIsci5ib3R0b20mJmUub3B0aW9ucy5jb3Zlckd1dHRlck5leHRUb1Njcm9sbGJhciYmZS5vcHRpb25zLmZpeGVkR3V0dGVyPyhuLmd1dHRlckZpbGxlci5zdHlsZS5kaXNwbGF5PSJibG9jayIsbi5ndXR0ZXJGaWxsZXIuc3R5bGUuaGVpZ2h0PXIuYm90dG9tKyJweCIsbi5ndXR0ZXJGaWxsZXIuc3R5bGUud2lkdGg9dC5ndXR0ZXJXaWR0aCsicHgiKTpuLmd1dHRlckZpbGxlci5zdHlsZS5kaXNwbGF5PSIifWZ1bmN0aW9uIG9yKGUpe2UuZGlzcGxheS5zY3JvbGxiYXJzJiYoZS5kaXNwbGF5LnNjcm9sbGJhcnMuY2xlYXIoKSxlLmRpc3BsYXkuc2Nyb2xsYmFycy5hZGRDbGFzcyYmUmEoZS5kaXNwbGF5LndyYXBwZXIsZS5kaXNwbGF5LnNjcm9sbGJhcnMuYWRkQ2xhc3MpKSxlLmRpc3BsYXkuc2Nyb2xsYmFycz1uZXcgd3NbZS5vcHRpb25zLnNjcm9sbGJhclN0eWxlXShmdW5jdGlvbih0KXtlLmRpc3BsYXkud3JhcHBlci5pbnNlcnRCZWZvcmUodCxlLmRpc3BsYXkuc2Nyb2xsYmFyRmlsbGVyKSxucyh0LCJtb3VzZWRvd24iLGZ1bmN0aW9uKCl7ZS5zdGF0ZS5mb2N1c2VkJiZzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIGUuZGlzcGxheS5pbnB1dC5mb2N1cygpfSwwKX0pLHQuc2V0QXR0cmlidXRlKCJjbS1ub3QtY29udGVudCIsInRydWUiKX0sZnVuY3Rpb24odCxuKXsiaG9yaXpvbnRhbCI9PW4/dHIoZSx0KTpabihlLHQpfSxlKSxlLmRpc3BsYXkuc2Nyb2xsYmFycy5hZGRDbGFzcyYmcyhlLmRpc3BsYXkud3JhcHBlcixlLmRpc3BsYXkuc2Nyb2xsYmFycy5hZGRDbGFzcyl9ZnVuY3Rpb24gYXIoZSl7ZS5jdXJPcD17Y206ZSx2aWV3Q2hhbmdlZDohMSxzdGFydEhlaWdodDplLmRvYy5oZWlnaHQsZm9yY2VVcGRhdGU6ITEsdXBkYXRlSW5wdXQ6bnVsbCx0eXBpbmc6ITEsY2hhbmdlT2JqczpudWxsLGN1cnNvckFjdGl2aXR5SGFuZGxlcnM6bnVsbCxjdXJzb3JBY3Rpdml0eUNhbGxlZDowLHNlbGVjdGlvbkNoYW5nZWQ6ITEsdXBkYXRlTWF4TGluZTohMSxzY3JvbGxMZWZ0Om51bGwsc2Nyb2xsVG9wOm51bGwsc2Nyb2xsVG9Qb3M6bnVsbCxmb2N1czohMSxpZDorK1NzfSx2dChlLmN1ck9wKX1mdW5jdGlvbiBzcihlKXt4dChlLmN1ck9wLGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0wO3Q8ZS5vcHMubGVuZ3RoO3QrKyllLm9wc1t0XS5jbS5jdXJPcD1udWxsO3VyKGUpfSl9ZnVuY3Rpb24gdXIoZSl7Zm9yKHZhciB0PWUub3BzLG49MDtuPHQubGVuZ3RoO24rKyljcih0W25dKTtmb3IodmFyIHI9MDtyPHQubGVuZ3RoO3IrKylscih0W3JdKTtmb3IodmFyIGk9MDtpPHQubGVuZ3RoO2krKylwcih0W2ldKTtmb3IodmFyIG89MDtvPHQubGVuZ3RoO28rKylmcih0W29dKTtmb3IodmFyIGE9MDthPHQubGVuZ3RoO2ErKylkcih0W2FdKX1mdW5jdGlvbiBjcihlKXt2YXIgdD1lLmNtLG49dC5kaXNwbGF5O2tyKHQpLGUudXBkYXRlTWF4TGluZSYmQ2UodCksZS5tdXN0VXBkYXRlPWUudmlld0NoYW5nZWR8fGUuZm9yY2VVcGRhdGV8fG51bGwhPWUuc2Nyb2xsVG9wfHxlLnNjcm9sbFRvUG9zJiYoZS5zY3JvbGxUb1Bvcy5mcm9tLmxpbmU8bi52aWV3RnJvbXx8ZS5zY3JvbGxUb1Bvcy50by5saW5lPj1uLnZpZXdUbyl8fG4ubWF4TGluZUNoYW5nZWQmJnQub3B0aW9ucy5saW5lV3JhcHBpbmcsZS51cGRhdGU9ZS5tdXN0VXBkYXRlJiZuZXcga3ModCxlLm11c3RVcGRhdGUmJnt0b3A6ZS5zY3JvbGxUb3AsZW5zdXJlOmUuc2Nyb2xsVG9Qb3N9LGUuZm9yY2VVcGRhdGUpfWZ1bmN0aW9uIGxyKGUpe2UudXBkYXRlZERpc3BsYXk9ZS5tdXN0VXBkYXRlJiZUcihlLmNtLGUudXBkYXRlKX1mdW5jdGlvbiBwcihlKXt2YXIgdD1lLmNtLG49dC5kaXNwbGF5O2UudXBkYXRlZERpc3BsYXkmJlJuKHQpLGUuYmFyTWVhc3VyZT1ucih0KSxuLm1heExpbmVDaGFuZ2VkJiYhdC5vcHRpb25zLmxpbmVXcmFwcGluZyYmKGUuYWRqdXN0V2lkdGhUbz1IdCh0LG4ubWF4TGluZSxuLm1heExpbmUudGV4dC5sZW5ndGgpLmxlZnQrMyx0LmRpc3BsYXkuc2l6ZXJXaWR0aD1lLmFkanVzdFdpZHRoVG8sZS5iYXJNZWFzdXJlLnNjcm9sbFdpZHRoPU1hdGgubWF4KG4uc2Nyb2xsZXIuY2xpZW50V2lkdGgsbi5zaXplci5vZmZzZXRMZWZ0K2UuYWRqdXN0V2lkdGhUbyskdCh0KSt0LmRpc3BsYXkuYmFyV2lkdGgpLGUubWF4U2Nyb2xsTGVmdD1NYXRoLm1heCgwLG4uc2l6ZXIub2Zmc2V0TGVmdCtlLmFkanVzdFdpZHRoVG8tVXQodCkpKSwoZS51cGRhdGVkRGlzcGxheXx8ZS5zZWxlY3Rpb25DaGFuZ2VkKSYmKGUucHJlcGFyZWRTZWxlY3Rpb249bi5pbnB1dC5wcmVwYXJlU2VsZWN0aW9uKCkpfWZ1bmN0aW9uIGZyKGUpe3ZhciB0PWUuY207bnVsbCE9ZS5hZGp1c3RXaWR0aFRvJiYodC5kaXNwbGF5LnNpemVyLnN0eWxlLm1pbldpZHRoPWUuYWRqdXN0V2lkdGhUbysicHgiLGUubWF4U2Nyb2xsTGVmdDx0LmRvYy5zY3JvbGxMZWZ0JiZ0cih0LE1hdGgubWluKHQuZGlzcGxheS5zY3JvbGxlci5zY3JvbGxMZWZ0LGUubWF4U2Nyb2xsTGVmdCksITApLHQuZGlzcGxheS5tYXhMaW5lQ2hhbmdlZD0hMSk7dmFyIG49ZS5mb2N1cyYmZS5mb2N1cz09YSgpO2UucHJlcGFyZWRTZWxlY3Rpb24mJnQuZGlzcGxheS5pbnB1dC5zaG93U2VsZWN0aW9uKGUucHJlcGFyZWRTZWxlY3Rpb24sbiksKGUudXBkYXRlZERpc3BsYXl8fGUuc3RhcnRIZWlnaHQhPXQuZG9jLmhlaWdodCkmJnJyKHQsZS5iYXJNZWFzdXJlKSxlLnVwZGF0ZWREaXNwbGF5JiZMcih0LGUuYmFyTWVhc3VyZSksZS5zZWxlY3Rpb25DaGFuZ2VkJiZJbih0KSx0LnN0YXRlLmZvY3VzZWQmJmUudXBkYXRlSW5wdXQmJnQuZGlzcGxheS5pbnB1dC5yZXNldChlLnR5cGluZyksbiYmTG4oZS5jbSl9ZnVuY3Rpb24gZHIoZSl7dmFyIHQ9ZS5jbSxuPXQuZGlzcGxheSxyPXQuZG9jO2lmKGUudXBkYXRlZERpc3BsYXkmJk9yKHQsZS51cGRhdGUpLG51bGw9PW4ud2hlZWxTdGFydFh8fG51bGw9PWUuc2Nyb2xsVG9wJiZudWxsPT1lLnNjcm9sbExlZnQmJiFlLnNjcm9sbFRvUG9zfHwobi53aGVlbFN0YXJ0WD1uLndoZWVsU3RhcnRZPW51bGwpLG51bGwhPWUuc2Nyb2xsVG9wJiZlcih0LGUuc2Nyb2xsVG9wLGUuZm9yY2VTY3JvbGwpLG51bGwhPWUuc2Nyb2xsTGVmdCYmdHIodCxlLnNjcm9sbExlZnQsITAsITApLGUuc2Nyb2xsVG9Qb3Mpe0duKHQsVm4odCx6KHIsZS5zY3JvbGxUb1Bvcy5mcm9tKSx6KHIsZS5zY3JvbGxUb1Bvcy50byksZS5zY3JvbGxUb1Bvcy5tYXJnaW4pKX12YXIgaT1lLm1heWJlSGlkZGVuTWFya2VycyxvPWUubWF5YmVVbmhpZGRlbk1hcmtlcnM7aWYoaSlmb3IodmFyIGE9MDthPGkubGVuZ3RoOysrYSlpW2FdLmxpbmVzLmxlbmd0aHx8QWUoaVthXSwiaGlkZSIpO2lmKG8pZm9yKHZhciBzPTA7czxvLmxlbmd0aDsrK3Mpb1tzXS5saW5lcy5sZW5ndGgmJkFlKG9bc10sInVuaGlkZSIpO24ud3JhcHBlci5vZmZzZXRIZWlnaHQmJihyLnNjcm9sbFRvcD10LmRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wKSxlLmNoYW5nZU9ianMmJkFlKHQsImNoYW5nZXMiLHQsZS5jaGFuZ2VPYmpzKSxlLnVwZGF0ZSYmZS51cGRhdGUuZmluaXNoKCl9ZnVuY3Rpb24gaHIoZSx0KXtpZihlLmN1ck9wKXJldHVybiB0KCk7YXIoZSk7dHJ5e3JldHVybiB0KCl9ZmluYWxseXtzcihlKX19ZnVuY3Rpb24gbXIoZSx0KXtyZXR1cm4gZnVuY3Rpb24oKXtpZihlLmN1ck9wKXJldHVybiB0LmFwcGx5KGUsYXJndW1lbnRzKTthcihlKTt0cnl7cmV0dXJuIHQuYXBwbHkoZSxhcmd1bWVudHMpfWZpbmFsbHl7c3IoZSl9fX1mdW5jdGlvbiBncihlKXtyZXR1cm4gZnVuY3Rpb24oKXtpZih0aGlzLmN1ck9wKXJldHVybiBlLmFwcGx5KHRoaXMsYXJndW1lbnRzKTthcih0aGlzKTt0cnl7cmV0dXJuIGUuYXBwbHkodGhpcyxhcmd1bWVudHMpfWZpbmFsbHl7c3IodGhpcyl9fX1mdW5jdGlvbiB5cihlKXtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgdD10aGlzLmNtO2lmKCF0fHx0LmN1ck9wKXJldHVybiBlLmFwcGx5KHRoaXMsYXJndW1lbnRzKTthcih0KTt0cnl7cmV0dXJuIGUuYXBwbHkodGhpcyxhcmd1bWVudHMpfWZpbmFsbHl7c3IodCl9fX1mdW5jdGlvbiB2cihlLHQsbixyKXtudWxsPT10JiYodD1lLmRvYy5maXJzdCksbnVsbD09biYmKG49ZS5kb2MuZmlyc3QrZS5kb2Muc2l6ZSkscnx8KHI9MCk7dmFyIGk9ZS5kaXNwbGF5O2lmKHImJm48aS52aWV3VG8mJihudWxsPT1pLnVwZGF0ZUxpbmVOdW1iZXJzfHxpLnVwZGF0ZUxpbmVOdW1iZXJzPnQpJiYoaS51cGRhdGVMaW5lTnVtYmVycz10KSxlLmN1ck9wLnZpZXdDaGFuZ2VkPSEwLHQ+PWkudmlld1RvKVhhJiZtZShlLmRvYyx0KTxpLnZpZXdUbyYmeHIoZSk7ZWxzZSBpZihuPD1pLnZpZXdGcm9tKVhhJiZnZShlLmRvYyxuK3IpPmkudmlld0Zyb20/eHIoZSk6KGkudmlld0Zyb20rPXIsaS52aWV3VG8rPXIpO2Vsc2UgaWYodDw9aS52aWV3RnJvbSYmbj49aS52aWV3VG8peHIoZSk7ZWxzZSBpZih0PD1pLnZpZXdGcm9tKXt2YXIgbz1DcihlLG4sbityLDEpO28/KGkudmlldz1pLnZpZXcuc2xpY2Uoby5pbmRleCksaS52aWV3RnJvbT1vLmxpbmVOLGkudmlld1RvKz1yKTp4cihlKX1lbHNlIGlmKG4+PWkudmlld1RvKXt2YXIgYT1DcihlLHQsdCwtMSk7YT8oaS52aWV3PWkudmlldy5zbGljZSgwLGEuaW5kZXgpLGkudmlld1RvPWEubGluZU4pOnhyKGUpfWVsc2V7dmFyIHM9Q3IoZSx0LHQsLTEpLHU9Q3IoZSxuLG4rciwxKTtzJiZ1PyhpLnZpZXc9aS52aWV3LnNsaWNlKDAscy5pbmRleCkuY29uY2F0KHl0KGUscy5saW5lTix1LmxpbmVOKSkuY29uY2F0KGkudmlldy5zbGljZSh1LmluZGV4KSksaS52aWV3VG8rPXIpOnhyKGUpfXZhciBjPWkuZXh0ZXJuYWxNZWFzdXJlZDtjJiYobjxjLmxpbmVOP2MubGluZU4rPXI6dDxjLmxpbmVOK2Muc2l6ZSYmKGkuZXh0ZXJuYWxNZWFzdXJlZD1udWxsKSl9ZnVuY3Rpb24gYnIoZSx0LG4pe2UuY3VyT3Audmlld0NoYW5nZWQ9ITA7dmFyIHI9ZS5kaXNwbGF5LGk9ZS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQ7aWYoaSYmdD49aS5saW5lTiYmdDxpLmxpbmVOK2kuc2l6ZSYmKHIuZXh0ZXJuYWxNZWFzdXJlZD1udWxsKSwhKHQ8ci52aWV3RnJvbXx8dD49ci52aWV3VG8pKXt2YXIgbz1yLnZpZXdbQW4oZSx0KV07aWYobnVsbCE9by5ub2RlKXt2YXIgYT1vLmNoYW5nZXN8fChvLmNoYW5nZXM9W10pOy0xPT1mKGEsbikmJmEucHVzaChuKX19fWZ1bmN0aW9uIHhyKGUpe2UuZGlzcGxheS52aWV3RnJvbT1lLmRpc3BsYXkudmlld1RvPWUuZG9jLmZpcnN0LGUuZGlzcGxheS52aWV3PVtdLGUuZGlzcGxheS52aWV3T2Zmc2V0PTB9ZnVuY3Rpb24gQ3IoZSx0LG4scil7dmFyIGksbz1BbihlLHQpLGE9ZS5kaXNwbGF5LnZpZXc7aWYoIVhhfHxuPT1lLmRvYy5maXJzdCtlLmRvYy5zaXplKXJldHVybntpbmRleDpvLGxpbmVOOm59O2Zvcih2YXIgcz1lLmRpc3BsYXkudmlld0Zyb20sdT0wO3U8bzt1Kyspcys9YVt1XS5zaXplO2lmKHMhPXQpe2lmKHI+MCl7aWYobz09YS5sZW5ndGgtMSlyZXR1cm4gbnVsbDtpPXMrYVtvXS5zaXplLXQsbysrfWVsc2UgaT1zLXQ7dCs9aSxuKz1pfWZvcig7bWUoZS5kb2MsbikhPW47KXtpZihvPT0ocjwwPzA6YS5sZW5ndGgtMSkpcmV0dXJuIG51bGw7bis9ciphW28tKHI8MD8xOjApXS5zaXplLG8rPXJ9cmV0dXJue2luZGV4Om8sbGluZU46bn19ZnVuY3Rpb24gRXIoZSx0LG4pe3ZhciByPWUuZGlzcGxheTswPT1yLnZpZXcubGVuZ3RofHx0Pj1yLnZpZXdUb3x8bjw9ci52aWV3RnJvbT8oci52aWV3PXl0KGUsdCxuKSxyLnZpZXdGcm9tPXQpOihyLnZpZXdGcm9tPnQ/ci52aWV3PXl0KGUsdCxyLnZpZXdGcm9tKS5jb25jYXQoci52aWV3KTpyLnZpZXdGcm9tPHQmJihyLnZpZXc9ci52aWV3LnNsaWNlKEFuKGUsdCkpKSxyLnZpZXdGcm9tPXQsci52aWV3VG88bj9yLnZpZXc9ci52aWV3LmNvbmNhdCh5dChlLHIudmlld1RvLG4pKTpyLnZpZXdUbz5uJiYoci52aWV3PXIudmlldy5zbGljZSgwLEFuKGUsbikpKSksci52aWV3VG89bn1mdW5jdGlvbiBEcihlKXtmb3IodmFyIHQ9ZS5kaXNwbGF5LnZpZXcsbj0wLHI9MDtyPHQubGVuZ3RoO3IrKyl7dmFyIGk9dFtyXTtpLmhpZGRlbnx8aS5ub2RlJiYhaS5jaGFuZ2VzfHwrK259cmV0dXJuIG59ZnVuY3Rpb24gd3IoZSx0KXtlLmRvYy5oaWdobGlnaHRGcm9udGllcjxlLmRpc3BsYXkudmlld1RvJiZlLnN0YXRlLmhpZ2hsaWdodC5zZXQodCxjKFNyLGUpKX1mdW5jdGlvbiBTcihlKXt2YXIgdD1lLmRvYztpZighKHQuaGlnaGxpZ2h0RnJvbnRpZXI+PWUuZGlzcGxheS52aWV3VG8pKXt2YXIgbj0rbmV3IERhdGUrZS5vcHRpb25zLndvcmtUaW1lLHI9WWUoZSx0LmhpZ2hsaWdodEZyb250aWVyKSxpPVtdO3QuaXRlcihyLmxpbmUsTWF0aC5taW4odC5maXJzdCt0LnNpemUsZS5kaXNwbGF5LnZpZXdUbys1MDApLGZ1bmN0aW9uKG8pe2lmKHIubGluZT49ZS5kaXNwbGF5LnZpZXdGcm9tKXt2YXIgYT1vLnN0eWxlcyxzPW8udGV4dC5sZW5ndGg+ZS5vcHRpb25zLm1heEhpZ2hsaWdodExlbmd0aD9IZSh0Lm1vZGUsci5zdGF0ZSk6bnVsbCx1PUtlKGUsbyxyLCEwKTtzJiYoci5zdGF0ZT1zKSxvLnN0eWxlcz11LnN0eWxlczt2YXIgYz1vLnN0eWxlQ2xhc3NlcyxsPXUuY2xhc3NlcztsP28uc3R5bGVDbGFzc2VzPWw6YyYmKG8uc3R5bGVDbGFzc2VzPW51bGwpO2Zvcih2YXIgcD0hYXx8YS5sZW5ndGghPW8uc3R5bGVzLmxlbmd0aHx8YyE9bCYmKCFjfHwhbHx8Yy5iZ0NsYXNzIT1sLmJnQ2xhc3N8fGMudGV4dENsYXNzIT1sLnRleHRDbGFzcyksZj0wOyFwJiZmPGEubGVuZ3RoOysrZilwPWFbZl0hPW8uc3R5bGVzW2ZdO3AmJmkucHVzaChyLmxpbmUpLG8uc3RhdGVBZnRlcj1yLnNhdmUoKSxyLm5leHRMaW5lKCl9ZWxzZSBvLnRleHQubGVuZ3RoPD1lLm9wdGlvbnMubWF4SGlnaGxpZ2h0TGVuZ3RoJiZYZShlLG8udGV4dCxyKSxvLnN0YXRlQWZ0ZXI9ci5saW5lJTU9PTA/ci5zYXZlKCk6bnVsbCxyLm5leHRMaW5lKCk7aWYoK25ldyBEYXRlPm4pcmV0dXJuIHdyKGUsZS5vcHRpb25zLndvcmtEZWxheSksITB9KSx0LmhpZ2hsaWdodEZyb250aWVyPXIubGluZSx0Lm1vZGVGcm9udGllcj1NYXRoLm1heCh0Lm1vZGVGcm9udGllcixyLmxpbmUpLGkubGVuZ3RoJiZocihlLGZ1bmN0aW9uKCl7Zm9yKHZhciB0PTA7dDxpLmxlbmd0aDt0KyspYnIoZSxpW3RdLCJ0ZXh0Iil9KX19ZnVuY3Rpb24ga3IoZSl7dmFyIHQ9ZS5kaXNwbGF5OyF0LnNjcm9sbGJhcnNDbGlwcGVkJiZ0LnNjcm9sbGVyLm9mZnNldFdpZHRoJiYodC5uYXRpdmVCYXJXaWR0aD10LnNjcm9sbGVyLm9mZnNldFdpZHRoLXQuc2Nyb2xsZXIuY2xpZW50V2lkdGgsdC5oZWlnaHRGb3JjZXIuc3R5bGUuaGVpZ2h0PSR0KGUpKyJweCIsdC5zaXplci5zdHlsZS5tYXJnaW5Cb3R0b209LXQubmF0aXZlQmFyV2lkdGgrInB4Iix0LnNpemVyLnN0eWxlLmJvcmRlclJpZ2h0V2lkdGg9JHQoZSkrInB4Iix0LnNjcm9sbGJhcnNDbGlwcGVkPSEwKX1mdW5jdGlvbiBBcihlKXtpZihlLmhhc0ZvY3VzKCkpcmV0dXJuIG51bGw7dmFyIHQ9YSgpO2lmKCF0fHwhbyhlLmRpc3BsYXkubGluZURpdix0KSlyZXR1cm4gbnVsbDt2YXIgbj17YWN0aXZlRWx0OnR9O2lmKHdpbmRvdy5nZXRTZWxlY3Rpb24pe3ZhciByPXdpbmRvdy5nZXRTZWxlY3Rpb24oKTtyLmFuY2hvck5vZGUmJnIuZXh0ZW5kJiZvKGUuZGlzcGxheS5saW5lRGl2LHIuYW5jaG9yTm9kZSkmJihuLmFuY2hvck5vZGU9ci5hbmNob3JOb2RlLG4uYW5jaG9yT2Zmc2V0PXIuYW5jaG9yT2Zmc2V0LG4uZm9jdXNOb2RlPXIuZm9jdXNOb2RlLG4uZm9jdXNPZmZzZXQ9ci5mb2N1c09mZnNldCl9cmV0dXJuIG59ZnVuY3Rpb24gX3IoZSl7aWYoZSYmZS5hY3RpdmVFbHQmJmUuYWN0aXZlRWx0IT1hKCkmJihlLmFjdGl2ZUVsdC5mb2N1cygpLGUuYW5jaG9yTm9kZSYmbyhkb2N1bWVudC5ib2R5LGUuYW5jaG9yTm9kZSkmJm8oZG9jdW1lbnQuYm9keSxlLmZvY3VzTm9kZSkpKXt2YXIgdD13aW5kb3cuZ2V0U2VsZWN0aW9uKCksbj1kb2N1bWVudC5jcmVhdGVSYW5nZSgpO24uc2V0RW5kKGUuYW5jaG9yTm9kZSxlLmFuY2hvck9mZnNldCksbi5jb2xsYXBzZSghMSksdC5yZW1vdmVBbGxSYW5nZXMoKSx0LmFkZFJhbmdlKG4pLHQuZXh0ZW5kKGUuZm9jdXNOb2RlLGUuZm9jdXNPZmZzZXQpfX1mdW5jdGlvbiBUcihlLG4pe3ZhciByPWUuZGlzcGxheSxpPWUuZG9jO2lmKG4uZWRpdG9ySXNIaWRkZW4pcmV0dXJuIHhyKGUpLCExO2lmKCFuLmZvcmNlJiZuLnZpc2libGUuZnJvbT49ci52aWV3RnJvbSYmbi52aXNpYmxlLnRvPD1yLnZpZXdUbyYmKG51bGw9PXIudXBkYXRlTGluZU51bWJlcnN8fHIudXBkYXRlTGluZU51bWJlcnM+PXIudmlld1RvKSYmci5yZW5kZXJlZFZpZXc9PXIudmlldyYmMD09RHIoZSkpcmV0dXJuITE7em4oZSkmJih4cihlKSxuLmRpbXM9RW4oZSkpO3ZhciBvPWkuZmlyc3QraS5zaXplLGE9TWF0aC5tYXgobi52aXNpYmxlLmZyb20tZS5vcHRpb25zLnZpZXdwb3J0TWFyZ2luLGkuZmlyc3QpLHM9TWF0aC5taW4obyxuLnZpc2libGUudG8rZS5vcHRpb25zLnZpZXdwb3J0TWFyZ2luKTtyLnZpZXdGcm9tPGEmJmEtci52aWV3RnJvbTwyMCYmKGE9TWF0aC5tYXgoaS5maXJzdCxyLnZpZXdGcm9tKSksci52aWV3VG8+cyYmci52aWV3VG8tczwyMCYmKHM9TWF0aC5taW4obyxyLnZpZXdUbykpLFhhJiYoYT1tZShlLmRvYyxhKSxzPWdlKGUuZG9jLHMpKTt2YXIgdT1hIT1yLnZpZXdGcm9tfHxzIT1yLnZpZXdUb3x8ci5sYXN0V3JhcEhlaWdodCE9bi53cmFwcGVySGVpZ2h0fHxyLmxhc3RXcmFwV2lkdGghPW4ud3JhcHBlcldpZHRoO0VyKGUsYSxzKSxyLnZpZXdPZmZzZXQ9YmUoQShlLmRvYyxyLnZpZXdGcm9tKSksZS5kaXNwbGF5Lm1vdmVyLnN0eWxlLnRvcD1yLnZpZXdPZmZzZXQrInB4Ijt2YXIgYz1EcihlKTtpZighdSYmMD09YyYmIW4uZm9yY2UmJnIucmVuZGVyZWRWaWV3PT1yLnZpZXcmJihudWxsPT1yLnVwZGF0ZUxpbmVOdW1iZXJzfHxyLnVwZGF0ZUxpbmVOdW1iZXJzPj1yLnZpZXdUbykpcmV0dXJuITE7dmFyIGw9QXIoZSk7cmV0dXJuIGM+NCYmKHIubGluZURpdi5zdHlsZS5kaXNwbGF5PSJub25lIiksTnIoZSxyLnVwZGF0ZUxpbmVOdW1iZXJzLG4uZGltcyksYz40JiYoci5saW5lRGl2LnN0eWxlLmRpc3BsYXk9IiIpLHIucmVuZGVyZWRWaWV3PXIudmlldyxfcihsKSx0KHIuY3Vyc29yRGl2KSx0KHIuc2VsZWN0aW9uRGl2KSxyLmd1dHRlcnMuc3R5bGUuaGVpZ2h0PXIuc2l6ZXIuc3R5bGUubWluSGVpZ2h0PTAsdSYmKHIubGFzdFdyYXBIZWlnaHQ9bi53cmFwcGVySGVpZ2h0LHIubGFzdFdyYXBXaWR0aD1uLndyYXBwZXJXaWR0aCx3cihlLDQwMCkpLHIudXBkYXRlTGluZU51bWJlcnM9bnVsbCwhMH1mdW5jdGlvbiBPcihlLHQpe2Zvcih2YXIgbj10LnZpZXdwb3J0LHI9ITA7KHImJmUub3B0aW9ucy5saW5lV3JhcHBpbmcmJnQub2xkRGlzcGxheVdpZHRoIT1VdChlKXx8KG4mJm51bGwhPW4udG9wJiYobj17dG9wOk1hdGgubWluKGUuZG9jLmhlaWdodCtSdChlLmRpc3BsYXkpLXp0KGUpLG4udG9wKX0pLHQudmlzaWJsZT0kbihlLmRpc3BsYXksZS5kb2MsbiksISh0LnZpc2libGUuZnJvbT49ZS5kaXNwbGF5LnZpZXdGcm9tJiZ0LnZpc2libGUudG88PWUuZGlzcGxheS52aWV3VG8pKSkmJlRyKGUsdCk7cj0hMSl7Um4oZSk7dmFyIGk9bnIoZSk7X24oZSkscnIoZSxpKSxMcihlLGkpLHQuZm9yY2U9ITF9dC5zaWduYWwoZSwidXBkYXRlIixlKSxlLmRpc3BsYXkudmlld0Zyb209PWUuZGlzcGxheS5yZXBvcnRlZFZpZXdGcm9tJiZlLmRpc3BsYXkudmlld1RvPT1lLmRpc3BsYXkucmVwb3J0ZWRWaWV3VG98fCh0LnNpZ25hbChlLCJ2aWV3cG9ydENoYW5nZSIsZSxlLmRpc3BsYXkudmlld0Zyb20sZS5kaXNwbGF5LnZpZXdUbyksZS5kaXNwbGF5LnJlcG9ydGVkVmlld0Zyb209ZS5kaXNwbGF5LnZpZXdGcm9tLGUuZGlzcGxheS5yZXBvcnRlZFZpZXdUbz1lLmRpc3BsYXkudmlld1RvKX1mdW5jdGlvbiBGcihlLHQpe3ZhciBuPW5ldyBrcyhlLHQpO2lmKFRyKGUsbikpe1JuKGUpLE9yKGUsbik7dmFyIHI9bnIoZSk7X24oZSkscnIoZSxyKSxMcihlLHIpLG4uZmluaXNoKCl9fWZ1bmN0aW9uIE5yKGUsbixyKXtmdW5jdGlvbiBpKHQpe3ZhciBuPXQubmV4dFNpYmxpbmc7cmV0dXJuIENhJiZGYSYmZS5kaXNwbGF5LmN1cnJlbnRXaGVlbFRhcmdldD09dD90LnN0eWxlLmRpc3BsYXk9Im5vbmUiOnQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0KSxufWZvcih2YXIgbz1lLmRpc3BsYXksYT1lLm9wdGlvbnMubGluZU51bWJlcnMscz1vLmxpbmVEaXYsdT1zLmZpcnN0Q2hpbGQsYz1vLnZpZXcsbD1vLnZpZXdGcm9tLHA9MDtwPGMubGVuZ3RoO3ArKyl7dmFyIGQ9Y1twXTtpZihkLmhpZGRlbik7ZWxzZSBpZihkLm5vZGUmJmQubm9kZS5wYXJlbnROb2RlPT1zKXtmb3IoO3UhPWQubm9kZTspdT1pKHUpO3ZhciBoPWEmJm51bGwhPW4mJm48PWwmJmQubGluZU51bWJlcjtkLmNoYW5nZXMmJihmKGQuY2hhbmdlcywiZ3V0dGVyIik+LTEmJihoPSExKSxEdChlLGQsbCxyKSksaCYmKHQoZC5saW5lTnVtYmVyKSxkLmxpbmVOdW1iZXIuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoTChlLm9wdGlvbnMsbCkpKSksdT1kLm5vZGUubmV4dFNpYmxpbmd9ZWxzZXt2YXIgbT1GdChlLGQsbCxyKTtzLmluc2VydEJlZm9yZShtLHUpfWwrPWQuc2l6ZX1mb3IoO3U7KXU9aSh1KX1mdW5jdGlvbiBJcihlKXt2YXIgdD1lLmRpc3BsYXkuZ3V0dGVycy5vZmZzZXRXaWR0aDtlLmRpc3BsYXkuc2l6ZXIuc3R5bGUubWFyZ2luTGVmdD10KyJweCJ9ZnVuY3Rpb24gTHIoZSx0KXtlLmRpc3BsYXkuc2l6ZXIuc3R5bGUubWluSGVpZ2h0PXQuZG9jSGVpZ2h0KyJweCIsZS5kaXNwbGF5LmhlaWdodEZvcmNlci5zdHlsZS50b3A9dC5kb2NIZWlnaHQrInB4IixlLmRpc3BsYXkuZ3V0dGVycy5zdHlsZS5oZWlnaHQ9dC5kb2NIZWlnaHQrZS5kaXNwbGF5LmJhckhlaWdodCskdChlKSsicHgifWZ1bmN0aW9uIFByKGUpe3ZhciBuPWUuZGlzcGxheS5ndXR0ZXJzLGk9ZS5vcHRpb25zLmd1dHRlcnM7dChuKTtmb3IodmFyIG89MDtvPGkubGVuZ3RoOysrbyl7dmFyIGE9aVtvXSxzPW4uYXBwZW5kQ2hpbGQocigiZGl2IixudWxsLCJDb2RlTWlycm9yLWd1dHRlciAiK2EpKTsiQ29kZU1pcnJvci1saW5lbnVtYmVycyI9PWEmJihlLmRpc3BsYXkubGluZUd1dHRlcj1zLHMuc3R5bGUud2lkdGg9KGUuZGlzcGxheS5saW5lTnVtV2lkdGh8fDEpKyJweCIpfW4uc3R5bGUuZGlzcGxheT1vPyIiOiJub25lIixJcihlKX1mdW5jdGlvbiBNcihlKXt2YXIgdD1mKGUuZ3V0dGVycywiQ29kZU1pcnJvci1saW5lbnVtYmVycyIpOy0xPT10JiZlLmxpbmVOdW1iZXJzP2UuZ3V0dGVycz1lLmd1dHRlcnMuY29uY2F0KFsiQ29kZU1pcnJvci1saW5lbnVtYmVycyJdKTp0Pi0xJiYhZS5saW5lTnVtYmVycyYmKGUuZ3V0dGVycz1lLmd1dHRlcnMuc2xpY2UoMCksZS5ndXR0ZXJzLnNwbGljZSh0LDEpKX1mdW5jdGlvbiBqcihlKXt2YXIgdD1lLndoZWVsRGVsdGFYLG49ZS53aGVlbERlbHRhWTtyZXR1cm4gbnVsbD09dCYmZS5kZXRhaWwmJmUuYXhpcz09ZS5IT1JJWk9OVEFMX0FYSVMmJih0PWUuZGV0YWlsKSxudWxsPT1uJiZlLmRldGFpbCYmZS5heGlzPT1lLlZFUlRJQ0FMX0FYSVM/bj1lLmRldGFpbDpudWxsPT1uJiYobj1lLndoZWVsRGVsdGEpLHt4OnQseTpufX1mdW5jdGlvbiBScihlKXt2YXIgdD1qcihlKTtyZXR1cm4gdC54Kj1fcyx0LnkqPV9zLHR9ZnVuY3Rpb24gQnIoZSx0KXt2YXIgbj1qcih0KSxyPW4ueCxpPW4ueSxvPWUuZGlzcGxheSxhPW8uc2Nyb2xsZXIscz1hLnNjcm9sbFdpZHRoPmEuY2xpZW50V2lkdGgsdT1hLnNjcm9sbEhlaWdodD5hLmNsaWVudEhlaWdodDtpZihyJiZzfHxpJiZ1KXtpZihpJiZGYSYmQ2EpZTpmb3IodmFyIGM9dC50YXJnZXQsbD1vLnZpZXc7YyE9YTtjPWMucGFyZW50Tm9kZSlmb3IodmFyIHA9MDtwPGwubGVuZ3RoO3ArKylpZihsW3BdLm5vZGU9PWMpe2UuZGlzcGxheS5jdXJyZW50V2hlZWxUYXJnZXQ9YzticmVhayBlfWlmKHImJiFtYSYmIXdhJiZudWxsIT1fcylyZXR1cm4gaSYmdSYmWm4oZSxNYXRoLm1heCgwLGEuc2Nyb2xsVG9wK2kqX3MpKSx0cihlLE1hdGgubWF4KDAsYS5zY3JvbGxMZWZ0K3IqX3MpKSwoIWl8fGkmJnUpJiZOZSh0KSx2b2lkKG8ud2hlZWxTdGFydFg9bnVsbCk7aWYoaSYmbnVsbCE9X3Mpe3ZhciBmPWkqX3MsZD1lLmRvYy5zY3JvbGxUb3AsaD1kK28ud3JhcHBlci5jbGllbnRIZWlnaHQ7ZjwwP2Q9TWF0aC5tYXgoMCxkK2YtNTApOmg9TWF0aC5taW4oZS5kb2MuaGVpZ2h0LGgrZis1MCksRnIoZSx7dG9wOmQsYm90dG9tOmh9KX1BczwyMCYmKG51bGw9PW8ud2hlZWxTdGFydFg/KG8ud2hlZWxTdGFydFg9YS5zY3JvbGxMZWZ0LG8ud2hlZWxTdGFydFk9YS5zY3JvbGxUb3Asby53aGVlbERYPXIsby53aGVlbERZPWksc2V0VGltZW91dChmdW5jdGlvbigpe2lmKG51bGwhPW8ud2hlZWxTdGFydFgpe3ZhciBlPWEuc2Nyb2xsTGVmdC1vLndoZWVsU3RhcnRYLHQ9YS5zY3JvbGxUb3Atby53aGVlbFN0YXJ0WSxuPXQmJm8ud2hlZWxEWSYmdC9vLndoZWVsRFl8fGUmJm8ud2hlZWxEWCYmZS9vLndoZWVsRFg7by53aGVlbFN0YXJ0WD1vLndoZWVsU3RhcnRZPW51bGwsbiYmKF9zPShfcypBcytuKS8oQXMrMSksKytBcyl9fSwyMDApKTooby53aGVlbERYKz1yLG8ud2hlZWxEWSs9aSkpfX1mdW5jdGlvbiAkcihlLHQpe3ZhciBuPWVbdF07ZS5zb3J0KGZ1bmN0aW9uKGUsdCl7cmV0dXJuIE0oZS5mcm9tKCksdC5mcm9tKCkpfSksdD1mKGUsbik7Zm9yKHZhciByPTE7cjxlLmxlbmd0aDtyKyspe3ZhciBpPWVbcl0sbz1lW3ItMV07aWYoTShvLnRvKCksaS5mcm9tKCkpPj0wKXt2YXIgYT0kKG8uZnJvbSgpLGkuZnJvbSgpKSxzPUIoby50bygpLGkudG8oKSksdT1vLmVtcHR5KCk/aS5mcm9tKCk9PWkuaGVhZDpvLmZyb20oKT09by5oZWFkO3I8PXQmJi0tdCxlLnNwbGljZSgtLXIsMixuZXcgT3ModT9zOmEsdT9hOnMpKX19cmV0dXJuIG5ldyBUcyhlLHQpfWZ1bmN0aW9uIFVyKGUsdCl7cmV0dXJuIG5ldyBUcyhbbmV3IE9zKGUsdHx8ZSldLDApfWZ1bmN0aW9uIHpyKGUpe3JldHVybiBlLnRleHQ/UChlLmZyb20ubGluZStlLnRleHQubGVuZ3RoLTEsbShlLnRleHQpLmxlbmd0aCsoMT09ZS50ZXh0Lmxlbmd0aD9lLmZyb20uY2g6MCkpOmUudG99ZnVuY3Rpb24gR3IoZSx0KXtpZihNKGUsdC5mcm9tKTwwKXJldHVybiBlO2lmKE0oZSx0LnRvKTw9MClyZXR1cm4genIodCk7dmFyIG49ZS5saW5lK3QudGV4dC5sZW5ndGgtKHQudG8ubGluZS10LmZyb20ubGluZSktMSxyPWUuY2g7cmV0dXJuIGUubGluZT09dC50by5saW5lJiYocis9enIodCkuY2gtdC50by5jaCksUChuLHIpfWZ1bmN0aW9uIFZyKGUsdCl7Zm9yKHZhciBuPVtdLHI9MDtyPGUuc2VsLnJhbmdlcy5sZW5ndGg7cisrKXt2YXIgaT1lLnNlbC5yYW5nZXNbcl07bi5wdXNoKG5ldyBPcyhHcihpLmFuY2hvcix0KSxHcihpLmhlYWQsdCkpKX1yZXR1cm4gJHIobixlLnNlbC5wcmltSW5kZXgpfWZ1bmN0aW9uIHFyKGUsdCxuKXtyZXR1cm4gZS5saW5lPT10LmxpbmU/UChuLmxpbmUsZS5jaC10LmNoK24uY2gpOlAobi5saW5lKyhlLmxpbmUtdC5saW5lKSxlLmNoKX1mdW5jdGlvbiBIcihlLHQsbil7Zm9yKHZhciByPVtdLGk9UChlLmZpcnN0LDApLG89aSxhPTA7YTx0Lmxlbmd0aDthKyspe3ZhciBzPXRbYV0sdT1xcihzLmZyb20saSxvKSxjPXFyKHpyKHMpLGksbyk7aWYoaT1zLnRvLG89YywiYXJvdW5kIj09bil7dmFyIGw9ZS5zZWwucmFuZ2VzW2FdLHA9TShsLmhlYWQsbC5hbmNob3IpPDA7clthXT1uZXcgT3MocD9jOnUscD91OmMpfWVsc2UgclthXT1uZXcgT3ModSx1KX1yZXR1cm4gbmV3IFRzKHIsZS5zZWwucHJpbUluZGV4KX1mdW5jdGlvbiBXcihlKXtlLmRvYy5tb2RlPVZlKGUub3B0aW9ucyxlLmRvYy5tb2RlT3B0aW9uKSxRcihlKX1mdW5jdGlvbiBRcihlKXtlLmRvYy5pdGVyKGZ1bmN0aW9uKGUpe2Uuc3RhdGVBZnRlciYmKGUuc3RhdGVBZnRlcj1udWxsKSxlLnN0eWxlcyYmKGUuc3R5bGVzPW51bGwpfSksZS5kb2MubW9kZUZyb250aWVyPWUuZG9jLmhpZ2hsaWdodEZyb250aWVyPWUuZG9jLmZpcnN0LHdyKGUsMTAwKSxlLnN0YXRlLm1vZGVHZW4rKyxlLmN1ck9wJiZ2cihlKX1mdW5jdGlvbiBLcihlLHQpe3JldHVybiAwPT10LmZyb20uY2gmJjA9PXQudG8uY2gmJiIiPT1tKHQudGV4dCkmJighZS5jbXx8ZS5jbS5vcHRpb25zLndob2xlTGluZVVwZGF0ZUJlZm9yZSl9ZnVuY3Rpb24gSnIoZSx0LG4scil7ZnVuY3Rpb24gaShlKXtyZXR1cm4gbj9uW2VdOm51bGx9ZnVuY3Rpb24gbyhlLG4saSl7YXQoZSxuLGksciksQ3QoZSwiY2hhbmdlIixlLHQpfWZ1bmN0aW9uIGEoZSx0KXtmb3IodmFyIG49W10sbz1lO288dDsrK28pbi5wdXNoKG5ldyBtcyhjW29dLGkobykscikpO3JldHVybiBufXZhciBzPXQuZnJvbSx1PXQudG8sYz10LnRleHQsbD1BKGUscy5saW5lKSxwPUEoZSx1LmxpbmUpLGY9bShjKSxkPWkoYy5sZW5ndGgtMSksaD11LmxpbmUtcy5saW5lO2lmKHQuZnVsbCllLmluc2VydCgwLGEoMCxjLmxlbmd0aCkpLGUucmVtb3ZlKGMubGVuZ3RoLGUuc2l6ZS1jLmxlbmd0aCk7ZWxzZSBpZihLcihlLHQpKXt2YXIgZz1hKDAsYy5sZW5ndGgtMSk7byhwLHAudGV4dCxkKSxoJiZlLnJlbW92ZShzLmxpbmUsaCksZy5sZW5ndGgmJmUuaW5zZXJ0KHMubGluZSxnKX1lbHNlIGlmKGw9PXApaWYoMT09Yy5sZW5ndGgpbyhsLGwudGV4dC5zbGljZSgwLHMuY2gpK2YrbC50ZXh0LnNsaWNlKHUuY2gpLGQpO2Vsc2V7dmFyIHk9YSgxLGMubGVuZ3RoLTEpO3kucHVzaChuZXcgbXMoZitsLnRleHQuc2xpY2UodS5jaCksZCxyKSksbyhsLGwudGV4dC5zbGljZSgwLHMuY2gpK2NbMF0saSgwKSksZS5pbnNlcnQocy5saW5lKzEseSl9ZWxzZSBpZigxPT1jLmxlbmd0aClvKGwsbC50ZXh0LnNsaWNlKDAscy5jaCkrY1swXStwLnRleHQuc2xpY2UodS5jaCksaSgwKSksZS5yZW1vdmUocy5saW5lKzEsaCk7ZWxzZXtvKGwsbC50ZXh0LnNsaWNlKDAscy5jaCkrY1swXSxpKDApKSxvKHAsZitwLnRleHQuc2xpY2UodS5jaCksZCk7dmFyIHY9YSgxLGMubGVuZ3RoLTEpO2g+MSYmZS5yZW1vdmUocy5saW5lKzEsaC0xKSxlLmluc2VydChzLmxpbmUrMSx2KX1DdChlLCJjaGFuZ2UiLGUsdCl9ZnVuY3Rpb24gWXIoZSx0LG4pe2Z1bmN0aW9uIHIoZSxpLG8pe2lmKGUubGlua2VkKWZvcih2YXIgYT0wO2E8ZS5saW5rZWQubGVuZ3RoOysrYSl7dmFyIHM9ZS5saW5rZWRbYV07aWYocy5kb2MhPWkpe3ZhciB1PW8mJnMuc2hhcmVkSGlzdDtuJiYhdXx8KHQocy5kb2MsdSkscihzLmRvYyxlLHUpKX19fXIoZSxudWxsLCEwKX1mdW5jdGlvbiBYcihlLHQpe2lmKHQuY20pdGhyb3cgbmV3IEVycm9yKCJUaGlzIGRvY3VtZW50IGlzIGFscmVhZHkgaW4gdXNlLiIpO2UuZG9jPXQsdC5jbT1lLFNuKGUpLFdyKGUpLFpyKGUpLGUub3B0aW9ucy5saW5lV3JhcHBpbmd8fENlKGUpLGUub3B0aW9ucy5tb2RlPXQubW9kZU9wdGlvbix2cihlKX1mdW5jdGlvbiBacihlKXsoInJ0bCI9PWUuZG9jLmRpcmVjdGlvbj9zOlJhKShlLmRpc3BsYXkubGluZURpdiwiQ29kZU1pcnJvci1ydGwiKX1mdW5jdGlvbiBlaShlKXtocihlLGZ1bmN0aW9uKCl7WnIoZSksdnIoZSl9KX1mdW5jdGlvbiB0aShlKXt0aGlzLmRvbmU9W10sdGhpcy51bmRvbmU9W10sdGhpcy51bmRvRGVwdGg9MS8wLHRoaXMubGFzdE1vZFRpbWU9dGhpcy5sYXN0U2VsVGltZT0wLHRoaXMubGFzdE9wPXRoaXMubGFzdFNlbE9wPW51bGwsdGhpcy5sYXN0T3JpZ2luPXRoaXMubGFzdFNlbE9yaWdpbj1udWxsLHRoaXMuZ2VuZXJhdGlvbj10aGlzLm1heEdlbmVyYXRpb249ZXx8MX1mdW5jdGlvbiBuaShlLHQpe3ZhciBuPXtmcm9tOlIodC5mcm9tKSx0bzp6cih0KSx0ZXh0Ol8oZSx0LmZyb20sdC50byl9O3JldHVybiBjaShlLG4sdC5mcm9tLmxpbmUsdC50by5saW5lKzEpLFlyKGUsZnVuY3Rpb24oZSl7cmV0dXJuIGNpKGUsbix0LmZyb20ubGluZSx0LnRvLmxpbmUrMSl9LCEwKSxufWZ1bmN0aW9uIHJpKGUpe2Zvcig7ZS5sZW5ndGg7KXtpZighbShlKS5yYW5nZXMpYnJlYWs7ZS5wb3AoKX19ZnVuY3Rpb24gaWkoZSx0KXtyZXR1cm4gdD8ocmkoZS5kb25lKSxtKGUuZG9uZSkpOmUuZG9uZS5sZW5ndGgmJiFtKGUuZG9uZSkucmFuZ2VzP20oZS5kb25lKTplLmRvbmUubGVuZ3RoPjEmJiFlLmRvbmVbZS5kb25lLmxlbmd0aC0yXS5yYW5nZXM/KGUuZG9uZS5wb3AoKSxtKGUuZG9uZSkpOnZvaWQgMH1mdW5jdGlvbiBvaShlLHQsbixyKXt2YXIgaT1lLmhpc3Rvcnk7aS51bmRvbmUubGVuZ3RoPTA7dmFyIG8sYSxzPStuZXcgRGF0ZTtpZigoaS5sYXN0T3A9PXJ8fGkubGFzdE9yaWdpbj09dC5vcmlnaW4mJnQub3JpZ2luJiYoIisiPT10Lm9yaWdpbi5jaGFyQXQoMCkmJmkubGFzdE1vZFRpbWU+cy0oZS5jbT9lLmNtLm9wdGlvbnMuaGlzdG9yeUV2ZW50RGVsYXk6NTAwKXx8IioiPT10Lm9yaWdpbi5jaGFyQXQoMCkpKSYmKG89aWkoaSxpLmxhc3RPcD09cikpKWE9bShvLmNoYW5nZXMpLDA9PU0odC5mcm9tLHQudG8pJiYwPT1NKHQuZnJvbSxhLnRvKT9hLnRvPXpyKHQpOm8uY2hhbmdlcy5wdXNoKG5pKGUsdCkpO2Vsc2V7dmFyIHU9bShpLmRvbmUpO2Zvcih1JiZ1LnJhbmdlc3x8dWkoZS5zZWwsaS5kb25lKSxvPXtjaGFuZ2VzOltuaShlLHQpXSxnZW5lcmF0aW9uOmkuZ2VuZXJhdGlvbn0saS5kb25lLnB1c2gobyk7aS5kb25lLmxlbmd0aD5pLnVuZG9EZXB0aDspaS5kb25lLnNoaWZ0KCksaS5kb25lWzBdLnJhbmdlc3x8aS5kb25lLnNoaWZ0KCl9aS5kb25lLnB1c2gobiksaS5nZW5lcmF0aW9uPSsraS5tYXhHZW5lcmF0aW9uLGkubGFzdE1vZFRpbWU9aS5sYXN0U2VsVGltZT1zLGkubGFzdE9wPWkubGFzdFNlbE9wPXIsaS5sYXN0T3JpZ2luPWkubGFzdFNlbE9yaWdpbj10Lm9yaWdpbixhfHxBZShlLCJoaXN0b3J5QWRkZWQiKX1mdW5jdGlvbiBhaShlLHQsbixyKXt2YXIgaT10LmNoYXJBdCgwKTtyZXR1cm4iKiI9PWl8fCIrIj09aSYmbi5yYW5nZXMubGVuZ3RoPT1yLnJhbmdlcy5sZW5ndGgmJm4uc29tZXRoaW5nU2VsZWN0ZWQoKT09ci5zb21ldGhpbmdTZWxlY3RlZCgpJiZuZXcgRGF0ZS1lLmhpc3RvcnkubGFzdFNlbFRpbWU8PShlLmNtP2UuY20ub3B0aW9ucy5oaXN0b3J5RXZlbnREZWxheTo1MDApfWZ1bmN0aW9uIHNpKGUsdCxuLHIpe3ZhciBpPWUuaGlzdG9yeSxvPXImJnIub3JpZ2luO249PWkubGFzdFNlbE9wfHxvJiZpLmxhc3RTZWxPcmlnaW49PW8mJihpLmxhc3RNb2RUaW1lPT1pLmxhc3RTZWxUaW1lJiZpLmxhc3RPcmlnaW49PW98fGFpKGUsbyxtKGkuZG9uZSksdCkpP2kuZG9uZVtpLmRvbmUubGVuZ3RoLTFdPXQ6dWkodCxpLmRvbmUpLGkubGFzdFNlbFRpbWU9K25ldyBEYXRlLGkubGFzdFNlbE9yaWdpbj1vLGkubGFzdFNlbE9wPW4sciYmITEhPT1yLmNsZWFyUmVkbyYmcmkoaS51bmRvbmUpfWZ1bmN0aW9uIHVpKGUsdCl7dmFyIG49bSh0KTtuJiZuLnJhbmdlcyYmbi5lcXVhbHMoZSl8fHQucHVzaChlKX1mdW5jdGlvbiBjaShlLHQsbixyKXt2YXIgaT10WyJzcGFuc18iK2UuaWRdLG89MDtlLml0ZXIoTWF0aC5tYXgoZS5maXJzdCxuKSxNYXRoLm1pbihlLmZpcnN0K2Uuc2l6ZSxyKSxmdW5jdGlvbihuKXtuLm1hcmtlZFNwYW5zJiYoKGl8fChpPXRbInNwYW5zXyIrZS5pZF09e30pKVtvXT1uLm1hcmtlZFNwYW5zKSwrK299KX1mdW5jdGlvbiBsaShlKXtpZighZSlyZXR1cm4gbnVsbDtmb3IodmFyIHQsbj0wO248ZS5sZW5ndGg7KytuKWVbbl0ubWFya2VyLmV4cGxpY2l0bHlDbGVhcmVkP3R8fCh0PWUuc2xpY2UoMCxuKSk6dCYmdC5wdXNoKGVbbl0pO3JldHVybiB0P3QubGVuZ3RoP3Q6bnVsbDplfWZ1bmN0aW9uIHBpKGUsdCl7dmFyIG49dFsic3BhbnNfIitlLmlkXTtpZighbilyZXR1cm4gbnVsbDtmb3IodmFyIHI9W10saT0wO2k8dC50ZXh0Lmxlbmd0aDsrK2kpci5wdXNoKGxpKG5baV0pKTtyZXR1cm4gcn1mdW5jdGlvbiBmaShlLHQpe3ZhciBuPXBpKGUsdCkscj1aKGUsdCk7aWYoIW4pcmV0dXJuIHI7aWYoIXIpcmV0dXJuIG47Zm9yKHZhciBpPTA7aTxuLmxlbmd0aDsrK2kpe3ZhciBvPW5baV0sYT1yW2ldO2lmKG8mJmEpZTpmb3IodmFyIHM9MDtzPGEubGVuZ3RoOysrcyl7Zm9yKHZhciB1PWFbc10sYz0wO2M8by5sZW5ndGg7KytjKWlmKG9bY10ubWFya2VyPT11Lm1hcmtlciljb250aW51ZSBlO28ucHVzaCh1KX1lbHNlIGEmJihuW2ldPWEpfXJldHVybiBufWZ1bmN0aW9uIGRpKGUsdCxuKXtmb3IodmFyIHI9W10saT0wO2k8ZS5sZW5ndGg7KytpKXt2YXIgbz1lW2ldO2lmKG8ucmFuZ2VzKXIucHVzaChuP1RzLnByb3RvdHlwZS5kZWVwQ29weS5jYWxsKG8pOm8pO2Vsc2V7dmFyIGE9by5jaGFuZ2VzLHM9W107ci5wdXNoKHtjaGFuZ2VzOnN9KTtmb3IodmFyIHU9MDt1PGEubGVuZ3RoOysrdSl7dmFyIGM9YVt1XSxsPXZvaWQgMDtpZihzLnB1c2goe2Zyb206Yy5mcm9tLHRvOmMudG8sdGV4dDpjLnRleHR9KSx0KWZvcih2YXIgcCBpbiBjKShsPXAubWF0Y2goL15zcGFuc18oXGQrKSQvKSkmJmYodCxOdW1iZXIobFsxXSkpPi0xJiYobShzKVtwXT1jW3BdLGRlbGV0ZSBjW3BdKX19fXJldHVybiByfWZ1bmN0aW9uIGhpKGUsdCxuLHIpe2lmKHIpe3ZhciBpPWUuYW5jaG9yO2lmKG4pe3ZhciBvPU0odCxpKTwwO28hPU0obixpKTwwPyhpPXQsdD1uKTpvIT1NKHQsbik8MCYmKHQ9bil9cmV0dXJuIG5ldyBPcyhpLHQpfXJldHVybiBuZXcgT3Mobnx8dCx0KX1mdW5jdGlvbiBtaShlLHQsbixyLGkpe251bGw9PWkmJihpPWUuY20mJihlLmNtLmRpc3BsYXkuc2hpZnR8fGUuZXh0ZW5kKSksQ2koZSxuZXcgVHMoW2hpKGUuc2VsLnByaW1hcnkoKSx0LG4saSldLDApLHIpfWZ1bmN0aW9uIGdpKGUsdCxuKXtmb3IodmFyIHI9W10saT1lLmNtJiYoZS5jbS5kaXNwbGF5LnNoaWZ0fHxlLmV4dGVuZCksbz0wO288ZS5zZWwucmFuZ2VzLmxlbmd0aDtvKyspcltvXT1oaShlLnNlbC5yYW5nZXNbb10sdFtvXSxudWxsLGkpO0NpKGUsJHIocixlLnNlbC5wcmltSW5kZXgpLG4pfWZ1bmN0aW9uIHlpKGUsdCxuLHIpe3ZhciBpPWUuc2VsLnJhbmdlcy5zbGljZSgwKTtpW3RdPW4sQ2koZSwkcihpLGUuc2VsLnByaW1JbmRleCkscil9ZnVuY3Rpb24gdmkoZSx0LG4scil7Q2koZSxVcih0LG4pLHIpfWZ1bmN0aW9uIGJpKGUsdCxuKXt2YXIgcj17cmFuZ2VzOnQucmFuZ2VzLHVwZGF0ZTpmdW5jdGlvbih0KXt2YXIgbj10aGlzO3RoaXMucmFuZ2VzPVtdO2Zvcih2YXIgcj0wO3I8dC5sZW5ndGg7cisrKW4ucmFuZ2VzW3JdPW5ldyBPcyh6KGUsdFtyXS5hbmNob3IpLHooZSx0W3JdLmhlYWQpKX0sb3JpZ2luOm4mJm4ub3JpZ2lufTtyZXR1cm4gQWUoZSwiYmVmb3JlU2VsZWN0aW9uQ2hhbmdlIixlLHIpLGUuY20mJkFlKGUuY20sImJlZm9yZVNlbGVjdGlvbkNoYW5nZSIsZS5jbSxyKSxyLnJhbmdlcyE9dC5yYW5nZXM/JHIoci5yYW5nZXMsci5yYW5nZXMubGVuZ3RoLTEpOnR9ZnVuY3Rpb24geGkoZSx0LG4pe3ZhciByPWUuaGlzdG9yeS5kb25lLGk9bShyKTtpJiZpLnJhbmdlcz8ocltyLmxlbmd0aC0xXT10LEVpKGUsdCxuKSk6Q2koZSx0LG4pfWZ1bmN0aW9uIENpKGUsdCxuKXtFaShlLHQsbiksc2koZSxlLnNlbCxlLmNtP2UuY20uY3VyT3AuaWQ6TmFOLG4pfWZ1bmN0aW9uIEVpKGUsdCxuKXsoT2UoZSwiYmVmb3JlU2VsZWN0aW9uQ2hhbmdlIil8fGUuY20mJk9lKGUuY20sImJlZm9yZVNlbGVjdGlvbkNoYW5nZSIpKSYmKHQ9YmkoZSx0LG4pKSxEaShlLFNpKGUsdCxuJiZuLmJpYXN8fChNKHQucHJpbWFyeSgpLmhlYWQsZS5zZWwucHJpbWFyeSgpLmhlYWQpPDA/LTE6MSksITApKSxuJiYhMT09PW4uc2Nyb2xsfHwhZS5jbXx8UW4oZS5jbSl9ZnVuY3Rpb24gRGkoZSx0KXt0LmVxdWFscyhlLnNlbCl8fChlLnNlbD10LGUuY20mJihlLmNtLmN1ck9wLnVwZGF0ZUlucHV0PWUuY20uY3VyT3Auc2VsZWN0aW9uQ2hhbmdlZD0hMCxUZShlLmNtKSksQ3QoZSwiY3Vyc29yQWN0aXZpdHkiLGUpKX1mdW5jdGlvbiB3aShlKXtEaShlLFNpKGUsZS5zZWwsbnVsbCwhMSkpfWZ1bmN0aW9uIFNpKGUsdCxuLHIpe2Zvcih2YXIgaSxvPTA7bzx0LnJhbmdlcy5sZW5ndGg7bysrKXt2YXIgYT10LnJhbmdlc1tvXSxzPXQucmFuZ2VzLmxlbmd0aD09ZS5zZWwucmFuZ2VzLmxlbmd0aCYmZS5zZWwucmFuZ2VzW29dLHU9QWkoZSxhLmFuY2hvcixzJiZzLmFuY2hvcixuLHIpLGM9QWkoZSxhLmhlYWQscyYmcy5oZWFkLG4scik7KGl8fHUhPWEuYW5jaG9yfHxjIT1hLmhlYWQpJiYoaXx8KGk9dC5yYW5nZXMuc2xpY2UoMCxvKSksaVtvXT1uZXcgT3ModSxjKSl9cmV0dXJuIGk/JHIoaSx0LnByaW1JbmRleCk6dH1mdW5jdGlvbiBraShlLHQsbixyLGkpe3ZhciBvPUEoZSx0LmxpbmUpO2lmKG8ubWFya2VkU3BhbnMpZm9yKHZhciBhPTA7YTxvLm1hcmtlZFNwYW5zLmxlbmd0aDsrK2Epe3ZhciBzPW8ubWFya2VkU3BhbnNbYV0sdT1zLm1hcmtlcjtpZigobnVsbD09cy5mcm9tfHwodS5pbmNsdXNpdmVMZWZ0P3MuZnJvbTw9dC5jaDpzLmZyb208dC5jaCkpJiYobnVsbD09cy50b3x8KHUuaW5jbHVzaXZlUmlnaHQ/cy50bz49dC5jaDpzLnRvPnQuY2gpKSl7aWYoaSYmKEFlKHUsImJlZm9yZUN1cnNvckVudGVyIiksdS5leHBsaWNpdGx5Q2xlYXJlZCkpe2lmKG8ubWFya2VkU3BhbnMpey0tYTtjb250aW51ZX1icmVha31pZighdS5hdG9taWMpY29udGludWU7aWYobil7dmFyIGM9dS5maW5kKHI8MD8xOi0xKSxsPXZvaWQgMDtpZigocjwwP3UuaW5jbHVzaXZlUmlnaHQ6dS5pbmNsdXNpdmVMZWZ0KSYmKGM9X2koZSxjLC1yLGMmJmMubGluZT09dC5saW5lP286bnVsbCkpLGMmJmMubGluZT09dC5saW5lJiYobD1NKGMsbikpJiYocjwwP2w8MDpsPjApKXJldHVybiBraShlLGMsdCxyLGkpfXZhciBwPXUuZmluZChyPDA/LTE6MSk7cmV0dXJuKHI8MD91LmluY2x1c2l2ZUxlZnQ6dS5pbmNsdXNpdmVSaWdodCkmJihwPV9pKGUscCxyLHAubGluZT09dC5saW5lP286bnVsbCkpLHA/a2koZSxwLHQscixpKTpudWxsfX1yZXR1cm4gdH1mdW5jdGlvbiBBaShlLHQsbixyLGkpe3ZhciBvPXJ8fDEsYT1raShlLHQsbixvLGkpfHwhaSYma2koZSx0LG4sbywhMCl8fGtpKGUsdCxuLC1vLGkpfHwhaSYma2koZSx0LG4sLW8sITApO3JldHVybiBhfHwoZS5jYW50RWRpdD0hMCxQKGUuZmlyc3QsMCkpfWZ1bmN0aW9uIF9pKGUsdCxuLHIpe3JldHVybiBuPDAmJjA9PXQuY2g/dC5saW5lPmUuZmlyc3Q/eihlLFAodC5saW5lLTEpKTpudWxsOm4+MCYmdC5jaD09KHJ8fEEoZSx0LmxpbmUpKS50ZXh0Lmxlbmd0aD90LmxpbmU8ZS5maXJzdCtlLnNpemUtMT9QKHQubGluZSsxLDApOm51bGw6bmV3IFAodC5saW5lLHQuY2grbil9ZnVuY3Rpb24gVGkoZSl7ZS5zZXRTZWxlY3Rpb24oUChlLmZpcnN0TGluZSgpLDApLFAoZS5sYXN0TGluZSgpKSxxYSl9ZnVuY3Rpb24gT2koZSx0LG4pe3ZhciByPXtjYW5jZWxlZDohMSxmcm9tOnQuZnJvbSx0bzp0LnRvLHRleHQ6dC50ZXh0LG9yaWdpbjp0Lm9yaWdpbixjYW5jZWw6ZnVuY3Rpb24oKXtyZXR1cm4gci5jYW5jZWxlZD0hMH19O3JldHVybiBuJiYoci51cGRhdGU9ZnVuY3Rpb24odCxuLGksbyl7dCYmKHIuZnJvbT16KGUsdCkpLG4mJihyLnRvPXooZSxuKSksaSYmKHIudGV4dD1pKSx2b2lkIDAhPT1vJiYoci5vcmlnaW49byl9KSxBZShlLCJiZWZvcmVDaGFuZ2UiLGUsciksZS5jbSYmQWUoZS5jbSwiYmVmb3JlQ2hhbmdlIixlLmNtLHIpLHIuY2FuY2VsZWQ/bnVsbDp7ZnJvbTpyLmZyb20sdG86ci50byx0ZXh0OnIudGV4dCxvcmlnaW46ci5vcmlnaW59fWZ1bmN0aW9uIEZpKGUsdCxuKXtpZihlLmNtKXtpZighZS5jbS5jdXJPcClyZXR1cm4gbXIoZS5jbSxGaSkoZSx0LG4pO2lmKGUuY20uc3RhdGUuc3VwcHJlc3NFZGl0cylyZXR1cm59aWYoIShPZShlLCJiZWZvcmVDaGFuZ2UiKXx8ZS5jbSYmT2UoZS5jbSwiYmVmb3JlQ2hhbmdlIikpfHwodD1PaShlLHQsITApKSl7dmFyIHI9WWEmJiFuJiZ0ZShlLHQuZnJvbSx0LnRvKTtpZihyKWZvcih2YXIgaT1yLmxlbmd0aC0xO2k+PTA7LS1pKU5pKGUse2Zyb206cltpXS5mcm9tLHRvOnJbaV0udG8sdGV4dDppP1siIl06dC50ZXh0LG9yaWdpbjp0Lm9yaWdpbn0pO2Vsc2UgTmkoZSx0KX19ZnVuY3Rpb24gTmkoZSx0KXtpZigxIT10LnRleHQubGVuZ3RofHwiIiE9dC50ZXh0WzBdfHwwIT1NKHQuZnJvbSx0LnRvKSl7dmFyIG49VnIoZSx0KTtvaShlLHQsbixlLmNtP2UuY20uY3VyT3AuaWQ6TmFOKSxQaShlLHQsbixaKGUsdCkpO3ZhciByPVtdO1lyKGUsZnVuY3Rpb24oZSxuKXtufHwtMSE9ZihyLGUuaGlzdG9yeSl8fCgkaShlLmhpc3RvcnksdCksci5wdXNoKGUuaGlzdG9yeSkpLFBpKGUsdCxudWxsLFooZSx0KSl9KX19ZnVuY3Rpb24gSWkoZSx0LG4pe3ZhciByPWUuY20mJmUuY20uc3RhdGUuc3VwcHJlc3NFZGl0cztpZighcnx8bil7Zm9yKHZhciBpLG89ZS5oaXN0b3J5LGE9ZS5zZWwscz0idW5kbyI9PXQ/by5kb25lOm8udW5kb25lLHU9InVuZG8iPT10P28udW5kb25lOm8uZG9uZSxjPTA7YzxzLmxlbmd0aCYmKGk9c1tjXSxuPyFpLnJhbmdlc3x8aS5lcXVhbHMoZS5zZWwpOmkucmFuZ2VzKTtjKyspO2lmKGMhPXMubGVuZ3RoKXtmb3Ioby5sYXN0T3JpZ2luPW8ubGFzdFNlbE9yaWdpbj1udWxsOzspe2lmKGk9cy5wb3AoKSwhaS5yYW5nZXMpe2lmKHIpcmV0dXJuIHZvaWQgcy5wdXNoKGkpO2JyZWFrfWlmKHVpKGksdSksbiYmIWkuZXF1YWxzKGUuc2VsKSlyZXR1cm4gdm9pZCBDaShlLGkse2NsZWFyUmVkbzohMX0pO2E9aX12YXIgbD1bXTt1aShhLHUpLHUucHVzaCh7Y2hhbmdlczpsLGdlbmVyYXRpb246by5nZW5lcmF0aW9ufSksby5nZW5lcmF0aW9uPWkuZ2VuZXJhdGlvbnx8KytvLm1heEdlbmVyYXRpb247Zm9yKHZhciBwPU9lKGUsImJlZm9yZUNoYW5nZSIpfHxlLmNtJiZPZShlLmNtLCJiZWZvcmVDaGFuZ2UiKSxkPWkuY2hhbmdlcy5sZW5ndGgtMTtkPj0wOy0tZCl7dmFyIGg9ZnVuY3Rpb24obil7dmFyIHI9aS5jaGFuZ2VzW25dO2lmKHIub3JpZ2luPXQscCYmIU9pKGUsciwhMSkpcmV0dXJuIHMubGVuZ3RoPTAse307bC5wdXNoKG5pKGUscikpO3ZhciBvPW4/VnIoZSxyKTptKHMpO1BpKGUscixvLGZpKGUscikpLCFuJiZlLmNtJiZlLmNtLnNjcm9sbEludG9WaWV3KHtmcm9tOnIuZnJvbSx0bzp6cihyKX0pO3ZhciBhPVtdO1lyKGUsZnVuY3Rpb24oZSx0KXt0fHwtMSE9ZihhLGUuaGlzdG9yeSl8fCgkaShlLmhpc3RvcnksciksYS5wdXNoKGUuaGlzdG9yeSkpLFBpKGUscixudWxsLGZpKGUscikpfSl9KGQpO2lmKGgpcmV0dXJuIGgudn19fX1mdW5jdGlvbiBMaShlLHQpe2lmKDAhPXQmJihlLmZpcnN0Kz10LGUuc2VsPW5ldyBUcyhnKGUuc2VsLnJhbmdlcyxmdW5jdGlvbihlKXtyZXR1cm4gbmV3IE9zKFAoZS5hbmNob3IubGluZSt0LGUuYW5jaG9yLmNoKSxQKGUuaGVhZC5saW5lK3QsZS5oZWFkLmNoKSl9KSxlLnNlbC5wcmltSW5kZXgpLGUuY20pKXt2cihlLmNtLGUuZmlyc3QsZS5maXJzdC10LHQpO2Zvcih2YXIgbj1lLmNtLmRpc3BsYXkscj1uLnZpZXdGcm9tO3I8bi52aWV3VG87cisrKWJyKGUuY20sciwiZ3V0dGVyIil9fWZ1bmN0aW9uIFBpKGUsdCxuLHIpe2lmKGUuY20mJiFlLmNtLmN1ck9wKXJldHVybiBtcihlLmNtLFBpKShlLHQsbixyKTtpZih0LnRvLmxpbmU8ZS5maXJzdClyZXR1cm4gdm9pZCBMaShlLHQudGV4dC5sZW5ndGgtMS0odC50by5saW5lLXQuZnJvbS5saW5lKSk7aWYoISh0LmZyb20ubGluZT5lLmxhc3RMaW5lKCkpKXtpZih0LmZyb20ubGluZTxlLmZpcnN0KXt2YXIgaT10LnRleHQubGVuZ3RoLTEtKGUuZmlyc3QtdC5mcm9tLmxpbmUpO0xpKGUsaSksdD17ZnJvbTpQKGUuZmlyc3QsMCksdG86UCh0LnRvLmxpbmUraSx0LnRvLmNoKSx0ZXh0OlttKHQudGV4dCldLG9yaWdpbjp0Lm9yaWdpbn19dmFyIG89ZS5sYXN0TGluZSgpO3QudG8ubGluZT5vJiYodD17ZnJvbTp0LmZyb20sdG86UChvLEEoZSxvKS50ZXh0Lmxlbmd0aCksdGV4dDpbdC50ZXh0WzBdXSxvcmlnaW46dC5vcmlnaW59KSx0LnJlbW92ZWQ9XyhlLHQuZnJvbSx0LnRvKSxufHwobj1WcihlLHQpKSxlLmNtP01pKGUuY20sdCxyKTpKcihlLHQsciksRWkoZSxuLHFhKX19ZnVuY3Rpb24gTWkoZSx0LG4pe3ZhciByPWUuZG9jLGk9ZS5kaXNwbGF5LG89dC5mcm9tLGE9dC50byxzPSExLHU9by5saW5lO2Uub3B0aW9ucy5saW5lV3JhcHBpbmd8fCh1PUYoZmUoQShyLG8ubGluZSkpKSxyLml0ZXIodSxhLmxpbmUrMSxmdW5jdGlvbihlKXtpZihlPT1pLm1heExpbmUpcmV0dXJuIHM9ITAsITB9KSksci5zZWwuY29udGFpbnModC5mcm9tLHQudG8pPi0xJiZUZShlKSxKcihyLHQsbix3bihlKSksZS5vcHRpb25zLmxpbmVXcmFwcGluZ3x8KHIuaXRlcih1LG8ubGluZSt0LnRleHQubGVuZ3RoLGZ1bmN0aW9uKGUpe3ZhciB0PXhlKGUpO3Q+aS5tYXhMaW5lTGVuZ3RoJiYoaS5tYXhMaW5lPWUsaS5tYXhMaW5lTGVuZ3RoPXQsaS5tYXhMaW5lQ2hhbmdlZD0hMCxzPSExKX0pLHMmJihlLmN1ck9wLnVwZGF0ZU1heExpbmU9ITApKSxvdChyLG8ubGluZSksd3IoZSw0MDApO3ZhciBjPXQudGV4dC5sZW5ndGgtKGEubGluZS1vLmxpbmUpLTE7dC5mdWxsP3ZyKGUpOm8ubGluZSE9YS5saW5lfHwxIT10LnRleHQubGVuZ3RofHxLcihlLmRvYyx0KT92cihlLG8ubGluZSxhLmxpbmUrMSxjKTpicihlLG8ubGluZSwidGV4dCIpO3ZhciBsPU9lKGUsImNoYW5nZXMiKSxwPU9lKGUsImNoYW5nZSIpO2lmKHB8fGwpe3ZhciBmPXtmcm9tOm8sdG86YSx0ZXh0OnQudGV4dCxyZW1vdmVkOnQucmVtb3ZlZCxvcmlnaW46dC5vcmlnaW59O3AmJkN0KGUsImNoYW5nZSIsZSxmKSxsJiYoZS5jdXJPcC5jaGFuZ2VPYmpzfHwoZS5jdXJPcC5jaGFuZ2VPYmpzPVtdKSkucHVzaChmKX1lLmRpc3BsYXkuc2VsRm9yQ29udGV4dE1lbnU9bnVsbH1mdW5jdGlvbiBqaShlLHQsbixyLGkpe2lmKHJ8fChyPW4pLE0ocixuKTwwKXt2YXIgbztvPVtyLG5dLG49b1swXSxyPW9bMV19InN0cmluZyI9PXR5cGVvZiB0JiYodD1lLnNwbGl0TGluZXModCkpLEZpKGUse2Zyb206bix0bzpyLHRleHQ6dCxvcmlnaW46aX0pfWZ1bmN0aW9uIFJpKGUsdCxuLHIpe248ZS5saW5lP2UubGluZSs9cjp0PGUubGluZSYmKGUubGluZT10LGUuY2g9MCl9ZnVuY3Rpb24gQmkoZSx0LG4scil7Zm9yKHZhciBpPTA7aTxlLmxlbmd0aDsrK2kpe3ZhciBvPWVbaV0sYT0hMDtpZihvLnJhbmdlcyl7by5jb3BpZWR8fChvPWVbaV09by5kZWVwQ29weSgpLG8uY29waWVkPSEwKTtmb3IodmFyIHM9MDtzPG8ucmFuZ2VzLmxlbmd0aDtzKyspUmkoby5yYW5nZXNbc10uYW5jaG9yLHQsbixyKSxSaShvLnJhbmdlc1tzXS5oZWFkLHQsbixyKX1lbHNle2Zvcih2YXIgdT0wO3U8by5jaGFuZ2VzLmxlbmd0aDsrK3Upe3ZhciBjPW8uY2hhbmdlc1t1XTtpZihuPGMuZnJvbS5saW5lKWMuZnJvbT1QKGMuZnJvbS5saW5lK3IsYy5mcm9tLmNoKSxjLnRvPVAoYy50by5saW5lK3IsYy50by5jaCk7ZWxzZSBpZih0PD1jLnRvLmxpbmUpe2E9ITE7YnJlYWt9fWF8fChlLnNwbGljZSgwLGkrMSksaT0wKX19fWZ1bmN0aW9uICRpKGUsdCl7dmFyIG49dC5mcm9tLmxpbmUscj10LnRvLmxpbmUsaT10LnRleHQubGVuZ3RoLShyLW4pLTE7QmkoZS5kb25lLG4scixpKSxCaShlLnVuZG9uZSxuLHIsaSl9ZnVuY3Rpb24gVWkoZSx0LG4scil7dmFyIGk9dCxvPXQ7cmV0dXJuIm51bWJlciI9PXR5cGVvZiB0P289QShlLFUoZSx0KSk6aT1GKHQpLG51bGw9PWk/bnVsbDoocihvLGkpJiZlLmNtJiZicihlLmNtLGksbiksbyl9ZnVuY3Rpb24gemkoZSl7dmFyIHQ9dGhpczt0aGlzLmxpbmVzPWUsdGhpcy5wYXJlbnQ9bnVsbDtmb3IodmFyIG49MCxyPTA7cjxlLmxlbmd0aDsrK3IpZVtyXS5wYXJlbnQ9dCxuKz1lW3JdLmhlaWdodDt0aGlzLmhlaWdodD1ufWZ1bmN0aW9uIEdpKGUpe3ZhciB0PXRoaXM7dGhpcy5jaGlsZHJlbj1lO2Zvcih2YXIgbj0wLHI9MCxpPTA7aTxlLmxlbmd0aDsrK2kpe3ZhciBvPWVbaV07bis9by5jaHVua1NpemUoKSxyKz1vLmhlaWdodCxvLnBhcmVudD10fXRoaXMuc2l6ZT1uLHRoaXMuaGVpZ2h0PXIsdGhpcy5wYXJlbnQ9bnVsbH1mdW5jdGlvbiBWaShlLHQsbil7YmUodCk8KGUuY3VyT3AmJmUuY3VyT3Auc2Nyb2xsVG9wfHxlLmRvYy5zY3JvbGxUb3ApJiZXbihlLG4pfWZ1bmN0aW9uIHFpKGUsdCxuLHIpe3ZhciBpPW5ldyBGcyhlLG4sciksbz1lLmNtO3JldHVybiBvJiZpLm5vSFNjcm9sbCYmKG8uZGlzcGxheS5hbGlnbldpZGdldHM9ITApLFVpKGUsdCwid2lkZ2V0IixmdW5jdGlvbih0KXt2YXIgbj10LndpZGdldHN8fCh0LndpZGdldHM9W10pO2lmKG51bGw9PWkuaW5zZXJ0QXQ/bi5wdXNoKGkpOm4uc3BsaWNlKE1hdGgubWluKG4ubGVuZ3RoLTEsTWF0aC5tYXgoMCxpLmluc2VydEF0KSksMCxpKSxpLmxpbmU9dCxvJiYheWUoZSx0KSl7dmFyIHI9YmUodCk8ZS5zY3JvbGxUb3A7Tyh0LHQuaGVpZ2h0K1B0KGkpKSxyJiZXbihvLGkuaGVpZ2h0KSxvLmN1ck9wLmZvcmNlVXBkYXRlPSEwfXJldHVybiEwfSksbyYmQ3QobywibGluZVdpZGdldEFkZGVkIixvLGksIm51bWJlciI9PXR5cGVvZiB0P3Q6Rih0KSksaX1mdW5jdGlvbiBIaShlLHQsbixyLG8pe2lmKHImJnIuc2hhcmVkKXJldHVybiBXaShlLHQsbixyLG8pO2lmKGUuY20mJiFlLmNtLmN1ck9wKXJldHVybiBtcihlLmNtLEhpKShlLHQsbixyLG8pO3ZhciBhPW5ldyBJcyhlLG8pLHM9TSh0LG4pO2lmKHImJmwocixhLCExKSxzPjB8fDA9PXMmJiExIT09YS5jbGVhcldoZW5FbXB0eSlyZXR1cm4gYTtpZihhLnJlcGxhY2VkV2l0aCYmKGEuY29sbGFwc2VkPSEwLGEud2lkZ2V0Tm9kZT1pKCJzcGFuIixbYS5yZXBsYWNlZFdpdGhdLCJDb2RlTWlycm9yLXdpZGdldCIpLHIuaGFuZGxlTW91c2VFdmVudHN8fGEud2lkZ2V0Tm9kZS5zZXRBdHRyaWJ1dGUoImNtLWlnbm9yZS1ldmVudHMiLCJ0cnVlIiksci5pbnNlcnRMZWZ0JiYoYS53aWRnZXROb2RlLmluc2VydExlZnQ9ITApKSxhLmNvbGxhcHNlZCl7aWYocGUoZSx0LmxpbmUsdCxuLGEpfHx0LmxpbmUhPW4ubGluZSYmcGUoZSxuLmxpbmUsdCxuLGEpKXRocm93IG5ldyBFcnJvcigiSW5zZXJ0aW5nIGNvbGxhcHNlZCBtYXJrZXIgcGFydGlhbGx5IG92ZXJsYXBwaW5nIGFuIGV4aXN0aW5nIG9uZSIpO0goKX1hLmFkZFRvSGlzdG9yeSYmb2koZSx7ZnJvbTp0LHRvOm4sb3JpZ2luOiJtYXJrVGV4dCJ9LGUuc2VsLE5hTik7dmFyIHUsYz10LmxpbmUscD1lLmNtO2lmKGUuaXRlcihjLG4ubGluZSsxLGZ1bmN0aW9uKGUpe3AmJmEuY29sbGFwc2VkJiYhcC5vcHRpb25zLmxpbmVXcmFwcGluZyYmZmUoZSk9PXAuZGlzcGxheS5tYXhMaW5lJiYodT0hMCksYS5jb2xsYXBzZWQmJmMhPXQubGluZSYmTyhlLDApLEooZSxuZXcgVyhhLGM9PXQubGluZT90LmNoOm51bGwsYz09bi5saW5lP24uY2g6bnVsbCkpLCsrY30pLGEuY29sbGFwc2VkJiZlLml0ZXIodC5saW5lLG4ubGluZSsxLGZ1bmN0aW9uKHQpe3llKGUsdCkmJk8odCwwKX0pLGEuY2xlYXJPbkVudGVyJiZucyhhLCJiZWZvcmVDdXJzb3JFbnRlciIsZnVuY3Rpb24oKXtyZXR1cm4gYS5jbGVhcigpfSksYS5yZWFkT25seSYmKHEoKSwoZS5oaXN0b3J5LmRvbmUubGVuZ3RofHxlLmhpc3RvcnkudW5kb25lLmxlbmd0aCkmJmUuY2xlYXJIaXN0b3J5KCkpLGEuY29sbGFwc2VkJiYoYS5pZD0rK05zLGEuYXRvbWljPSEwKSxwKXtpZih1JiYocC5jdXJPcC51cGRhdGVNYXhMaW5lPSEwKSxhLmNvbGxhcHNlZCl2cihwLHQubGluZSxuLmxpbmUrMSk7ZWxzZSBpZihhLmNsYXNzTmFtZXx8YS50aXRsZXx8YS5zdGFydFN0eWxlfHxhLmVuZFN0eWxlfHxhLmNzcylmb3IodmFyIGY9dC5saW5lO2Y8PW4ubGluZTtmKyspYnIocCxmLCJ0ZXh0Iik7YS5hdG9taWMmJndpKHAuZG9jKSxDdChwLCJtYXJrZXJBZGRlZCIscCxhKX1yZXR1cm4gYX1mdW5jdGlvbiBXaShlLHQsbixyLGkpe3I9bChyKSxyLnNoYXJlZD0hMTt2YXIgbz1bSGkoZSx0LG4scixpKV0sYT1vWzBdLHM9ci53aWRnZXROb2RlO3JldHVybiBZcihlLGZ1bmN0aW9uKGUpe3MmJihyLndpZGdldE5vZGU9cy5jbG9uZU5vZGUoITApKSxvLnB1c2goSGkoZSx6KGUsdCkseihlLG4pLHIsaSkpO2Zvcih2YXIgdT0wO3U8ZS5saW5rZWQubGVuZ3RoOysrdSlpZihlLmxpbmtlZFt1XS5pc1BhcmVudClyZXR1cm47YT1tKG8pfSksbmV3IExzKG8sYSl9ZnVuY3Rpb24gUWkoZSl7cmV0dXJuIGUuZmluZE1hcmtzKFAoZS5maXJzdCwwKSxlLmNsaXBQb3MoUChlLmxhc3RMaW5lKCkpKSxmdW5jdGlvbihlKXtyZXR1cm4gZS5wYXJlbnR9KX1mdW5jdGlvbiBLaShlLHQpe2Zvcih2YXIgbj0wO248dC5sZW5ndGg7bisrKXt2YXIgcj10W25dLGk9ci5maW5kKCksbz1lLmNsaXBQb3MoaS5mcm9tKSxhPWUuY2xpcFBvcyhpLnRvKTtpZihNKG8sYSkpe3ZhciBzPUhpKGUsbyxhLHIucHJpbWFyeSxyLnByaW1hcnkudHlwZSk7ci5tYXJrZXJzLnB1c2gocykscy5wYXJlbnQ9cn19fWZ1bmN0aW9uIEppKGUpe2Zvcih2YXIgdD0wO3Q8ZS5sZW5ndGg7dCsrKSFmdW5jdGlvbih0KXt2YXIgbj1lW3RdLHI9W24ucHJpbWFyeS5kb2NdO1lyKG4ucHJpbWFyeS5kb2MsZnVuY3Rpb24oZSl7cmV0dXJuIHIucHVzaChlKX0pO2Zvcih2YXIgaT0wO2k8bi5tYXJrZXJzLmxlbmd0aDtpKyspe3ZhciBvPW4ubWFya2Vyc1tpXTstMT09ZihyLG8uZG9jKSYmKG8ucGFyZW50PW51bGwsbi5tYXJrZXJzLnNwbGljZShpLS0sMSkpfX0odCl9ZnVuY3Rpb24gWWkoZSl7dmFyIHQ9dGhpcztpZihlbyh0KSwhX2UodCxlKSYmIU10KHQuZGlzcGxheSxlKSl7TmUoZSksYmEmJihqcz0rbmV3IERhdGUpO3ZhciBuPWtuKHQsZSwhMCkscj1lLmRhdGFUcmFuc2Zlci5maWxlcztpZihuJiYhdC5pc1JlYWRPbmx5KCkpaWYociYmci5sZW5ndGgmJndpbmRvdy5GaWxlUmVhZGVyJiZ3aW5kb3cuRmlsZSlmb3IodmFyIGk9ci5sZW5ndGgsbz1BcnJheShpKSxhPTAscz0wO3M8aTsrK3MpIWZ1bmN0aW9uKGUscil7aWYoIXQub3B0aW9ucy5hbGxvd0Ryb3BGaWxlVHlwZXN8fC0xIT1mKHQub3B0aW9ucy5hbGxvd0Ryb3BGaWxlVHlwZXMsZS50eXBlKSl7dmFyIHM9bmV3IEZpbGVSZWFkZXI7cy5vbmxvYWQ9bXIodCxmdW5jdGlvbigpe3ZhciBlPXMucmVzdWx0O2lmKC9bXHgwMC1ceDA4XHgwZS1ceDFmXXsyfS8udGVzdChlKSYmKGU9IiIpLG9bcl09ZSwrK2E9PWkpe249eih0LmRvYyxuKTt2YXIgdT17ZnJvbTpuLHRvOm4sdGV4dDp0LmRvYy5zcGxpdExpbmVzKG8uam9pbih0LmRvYy5saW5lU2VwYXJhdG9yKCkpKSxvcmlnaW46InBhc3RlIn07RmkodC5kb2MsdSkseGkodC5kb2MsVXIobix6cih1KSkpfX0pLHMucmVhZEFzVGV4dChlKX19KHJbc10scyk7ZWxzZXtpZih0LnN0YXRlLmRyYWdnaW5nVGV4dCYmdC5kb2Muc2VsLmNvbnRhaW5zKG4pPi0xKXJldHVybiB0LnN0YXRlLmRyYWdnaW5nVGV4dChlKSx2b2lkIHNldFRpbWVvdXQoZnVuY3Rpb24oKXtyZXR1cm4gdC5kaXNwbGF5LmlucHV0LmZvY3VzKCl9LDIwKTt0cnl7dmFyIHU9ZS5kYXRhVHJhbnNmZXIuZ2V0RGF0YSgiVGV4dCIpO2lmKHUpe3ZhciBjO2lmKHQuc3RhdGUuZHJhZ2dpbmdUZXh0JiYhdC5zdGF0ZS5kcmFnZ2luZ1RleHQuY29weSYmKGM9dC5saXN0U2VsZWN0aW9ucygpKSxFaSh0LmRvYyxVcihuLG4pKSxjKWZvcih2YXIgbD0wO2w8Yy5sZW5ndGg7KytsKWppKHQuZG9jLCIiLGNbbF0uYW5jaG9yLGNbbF0uaGVhZCwiZHJhZyIpO3QucmVwbGFjZVNlbGVjdGlvbih1LCJhcm91bmQiLCJwYXN0ZSIpLHQuZGlzcGxheS5pbnB1dC5mb2N1cygpfX1jYXRjaChlKXt9fX19ZnVuY3Rpb24gWGkoZSx0KXtpZihiYSYmKCFlLnN0YXRlLmRyYWdnaW5nVGV4dHx8K25ldyBEYXRlLWpzPDEwMCkpcmV0dXJuIHZvaWQgUGUodCk7aWYoIV9lKGUsdCkmJiFNdChlLmRpc3BsYXksdCkmJih0LmRhdGFUcmFuc2Zlci5zZXREYXRhKCJUZXh0IixlLmdldFNlbGVjdGlvbigpKSx0LmRhdGFUcmFuc2Zlci5lZmZlY3RBbGxvd2VkPSJjb3B5TW92ZSIsdC5kYXRhVHJhbnNmZXIuc2V0RHJhZ0ltYWdlJiYhU2EpKXt2YXIgbj1yKCJpbWciLG51bGwsbnVsbCwicG9zaXRpb246IGZpeGVkOyBsZWZ0OiAwOyB0b3A6IDA7Iik7bi5zcmM9ImRhdGE6aW1hZ2UvZ2lmO2Jhc2U2NCxSMGxHT0RsaEFRQUJBQUFBQUNINUJBRUtBQUVBTEFBQUFBQUJBQUVBQUFJQ1RBRUFPdz09Iix3YSYmKG4ud2lkdGg9bi5oZWlnaHQ9MSxlLmRpc3BsYXkud3JhcHBlci5hcHBlbmRDaGlsZChuKSxuLl90b3A9bi5vZmZzZXRUb3ApLHQuZGF0YVRyYW5zZmVyLnNldERyYWdJbWFnZShuLDAsMCksd2EmJm4ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChuKX19ZnVuY3Rpb24gWmkoZSx0KXt2YXIgaT1rbihlLHQpO2lmKGkpe3ZhciBvPWRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtPbihlLGksbyksZS5kaXNwbGF5LmRyYWdDdXJzb3J8fChlLmRpc3BsYXkuZHJhZ0N1cnNvcj1yKCJkaXYiLG51bGwsIkNvZGVNaXJyb3ItY3Vyc29ycyBDb2RlTWlycm9yLWRyYWdjdXJzb3JzIiksZS5kaXNwbGF5LmxpbmVTcGFjZS5pbnNlcnRCZWZvcmUoZS5kaXNwbGF5LmRyYWdDdXJzb3IsZS5kaXNwbGF5LmN1cnNvckRpdikpLG4oZS5kaXNwbGF5LmRyYWdDdXJzb3Isbyl9fWZ1bmN0aW9uIGVvKGUpe2UuZGlzcGxheS5kcmFnQ3Vyc29yJiYoZS5kaXNwbGF5LmxpbmVTcGFjZS5yZW1vdmVDaGlsZChlLmRpc3BsYXkuZHJhZ0N1cnNvciksZS5kaXNwbGF5LmRyYWdDdXJzb3I9bnVsbCl9ZnVuY3Rpb24gdG8oZSl7aWYoZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSlmb3IodmFyIHQ9ZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSgiQ29kZU1pcnJvciIpLG49MDtuPHQubGVuZ3RoO24rKyl7dmFyIHI9dFtuXS5Db2RlTWlycm9yO3ImJmUocil9fWZ1bmN0aW9uIG5vKCl7UnN8fChybygpLFJzPSEwKX1mdW5jdGlvbiBybygpe3ZhciBlO25zKHdpbmRvdywicmVzaXplIixmdW5jdGlvbigpe251bGw9PWUmJihlPXNldFRpbWVvdXQoZnVuY3Rpb24oKXtlPW51bGwsdG8oaW8pfSwxMDApKX0pLG5zKHdpbmRvdywiYmx1ciIsZnVuY3Rpb24oKXtyZXR1cm4gdG8oam4pfSl9ZnVuY3Rpb24gaW8oZSl7dmFyIHQ9ZS5kaXNwbGF5O3QubGFzdFdyYXBIZWlnaHQ9PXQud3JhcHBlci5jbGllbnRIZWlnaHQmJnQubGFzdFdyYXBXaWR0aD09dC53cmFwcGVyLmNsaWVudFdpZHRofHwodC5jYWNoZWRDaGFyV2lkdGg9dC5jYWNoZWRUZXh0SGVpZ2h0PXQuY2FjaGVkUGFkZGluZ0g9bnVsbCx0LnNjcm9sbGJhcnNDbGlwcGVkPSExLGUuc2V0U2l6ZSgpKX1mdW5jdGlvbiBvbyhlKXt2YXIgdD1lLnNwbGl0KC8tKD8hJCkvKTtlPXRbdC5sZW5ndGgtMV07Zm9yKHZhciBuLHIsaSxvLGE9MDthPHQubGVuZ3RoLTE7YSsrKXt2YXIgcz10W2FdO2lmKC9eKGNtZHxtZXRhfG0pJC9pLnRlc3Qocykpbz0hMDtlbHNlIGlmKC9eYShsdCk/JC9pLnRlc3Qocykpbj0hMDtlbHNlIGlmKC9eKGN8Y3RybHxjb250cm9sKSQvaS50ZXN0KHMpKXI9ITA7ZWxzZXtpZighL15zKGhpZnQpPyQvaS50ZXN0KHMpKXRocm93IG5ldyBFcnJvcigiVW5yZWNvZ25pemVkIG1vZGlmaWVyIG5hbWU6ICIrcyk7aT0hMH19cmV0dXJuIG4mJihlPSJBbHQtIitlKSxyJiYoZT0iQ3RybC0iK2UpLG8mJihlPSJDbWQtIitlKSxpJiYoZT0iU2hpZnQtIitlKSxlfWZ1bmN0aW9uIGFvKGUpe3ZhciB0PXt9O2Zvcih2YXIgbiBpbiBlKWlmKGUuaGFzT3duUHJvcGVydHkobikpe3ZhciByPWVbbl07aWYoL14obmFtZXxmYWxsdGhyb3VnaHwoZGV8YXQpdGFjaCkkLy50ZXN0KG4pKWNvbnRpbnVlO2lmKCIuLi4iPT1yKXtkZWxldGUgZVtuXTtjb250aW51ZX1mb3IodmFyIGk9ZyhuLnNwbGl0KCIgIiksb28pLG89MDtvPGkubGVuZ3RoO28rKyl7dmFyIGE9dm9pZCAwLHM9dm9pZCAwO289PWkubGVuZ3RoLTE/KHM9aS5qb2luKCIgIiksYT1yKToocz1pLnNsaWNlKDAsbysxKS5qb2luKCIgIiksYT0iLi4uIik7dmFyIHU9dFtzXTtpZih1KXtpZih1IT1hKXRocm93IG5ldyBFcnJvcigiSW5jb25zaXN0ZW50IGJpbmRpbmdzIGZvciAiK3MpfWVsc2UgdFtzXT1hfWRlbGV0ZSBlW25dfWZvcih2YXIgYyBpbiB0KWVbY109dFtjXTtyZXR1cm4gZX1mdW5jdGlvbiBzbyhlLHQsbixyKXt0PXBvKHQpO3ZhciBpPXQuY2FsbD90LmNhbGwoZSxyKTp0W2VdO2lmKCExPT09aSlyZXR1cm4ibm90aGluZyI7aWYoIi4uLiI9PT1pKXJldHVybiJtdWx0aSI7aWYobnVsbCE9aSYmbihpKSlyZXR1cm4iaGFuZGxlZCI7aWYodC5mYWxsdGhyb3VnaCl7aWYoIltvYmplY3QgQXJyYXldIiE9T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHQuZmFsbHRocm91Z2gpKXJldHVybiBzbyhlLHQuZmFsbHRocm91Z2gsbixyKTtmb3IodmFyIG89MDtvPHQuZmFsbHRocm91Z2gubGVuZ3RoO28rKyl7dmFyIGE9c28oZSx0LmZhbGx0aHJvdWdoW29dLG4scik7aWYoYSlyZXR1cm4gYX19fWZ1bmN0aW9uIHVvKGUpe3ZhciB0PSJzdHJpbmciPT10eXBlb2YgZT9lOkJzW2Uua2V5Q29kZV07cmV0dXJuIkN0cmwiPT10fHwiQWx0Ij09dHx8IlNoaWZ0Ij09dHx8Ik1vZCI9PXR9ZnVuY3Rpb24gY28oZSx0LG4pe3ZhciByPWU7cmV0dXJuIHQuYWx0S2V5JiYiQWx0IiE9ciYmKGU9IkFsdC0iK2UpLChNYT90Lm1ldGFLZXk6dC5jdHJsS2V5KSYmIkN0cmwiIT1yJiYoZT0iQ3RybC0iK2UpLChNYT90LmN0cmxLZXk6dC5tZXRhS2V5KSYmIkNtZCIhPXImJihlPSJDbWQtIitlKSwhbiYmdC5zaGlmdEtleSYmIlNoaWZ0IiE9ciYmKGU9IlNoaWZ0LSIrZSksZX1mdW5jdGlvbiBsbyhlLHQpe2lmKHdhJiYzND09ZS5rZXlDb2RlJiZlLmNoYXIpcmV0dXJuITE7dmFyIG49QnNbZS5rZXlDb2RlXTtyZXR1cm4gbnVsbCE9biYmIWUuYWx0R3JhcGhLZXkmJigzPT1lLmtleUNvZGUmJmUuY29kZSYmKG49ZS5jb2RlKSxjbyhuLGUsdCkpfWZ1bmN0aW9uIHBvKGUpe3JldHVybiJzdHJpbmciPT10eXBlb2YgZT9Hc1tlXTplfWZ1bmN0aW9uIGZvKGUsdCl7Zm9yKHZhciBuPWUuZG9jLnNlbC5yYW5nZXMscj1bXSxpPTA7aTxuLmxlbmd0aDtpKyspe2Zvcih2YXIgbz10KG5baV0pO3IubGVuZ3RoJiZNKG8uZnJvbSxtKHIpLnRvKTw9MDspe3ZhciBhPXIucG9wKCk7aWYoTShhLmZyb20sby5mcm9tKTwwKXtvLmZyb209YS5mcm9tO2JyZWFrfX1yLnB1c2gobyl9aHIoZSxmdW5jdGlvbigpe2Zvcih2YXIgdD1yLmxlbmd0aC0xO3Q+PTA7dC0tKWppKGUuZG9jLCIiLHJbdF0uZnJvbSxyW3RdLnRvLCIrZGVsZXRlIik7UW4oZSl9KX1mdW5jdGlvbiBobyhlLHQsbil7dmFyIHI9dyhlLnRleHQsdCtuLG4pO3JldHVybiByPDB8fHI+ZS50ZXh0Lmxlbmd0aD9udWxsOnJ9ZnVuY3Rpb24gbW8oZSx0LG4pe3ZhciByPWhvKGUsdC5jaCxuKTtyZXR1cm4gbnVsbD09cj9udWxsOm5ldyBQKHQubGluZSxyLG48MD8iYWZ0ZXIiOiJiZWZvcmUiKX1mdW5jdGlvbiBnbyhlLHQsbixyLGkpe2lmKGUpe3ZhciBvPXdlKG4sdC5kb2MuZGlyZWN0aW9uKTtpZihvKXt2YXIgYSxzPWk8MD9tKG8pOm9bMF0sdT1pPDA9PSgxPT1zLmxldmVsKSxjPXU/ImFmdGVyIjoiYmVmb3JlIjtpZihzLmxldmVsPjB8fCJydGwiPT10LmRvYy5kaXJlY3Rpb24pe3ZhciBsPVF0KHQsbik7YT1pPDA/bi50ZXh0Lmxlbmd0aC0xOjA7dmFyIHA9S3QodCxsLGEpLnRvcDthPVMoZnVuY3Rpb24oZSl7cmV0dXJuIEt0KHQsbCxlKS50b3A9PXB9LGk8MD09KDE9PXMubGV2ZWwpP3MuZnJvbTpzLnRvLTEsYSksImJlZm9yZSI9PWMmJihhPWhvKG4sYSwxKSl9ZWxzZSBhPWk8MD9zLnRvOnMuZnJvbTtyZXR1cm4gbmV3IFAocixhLGMpfX1yZXR1cm4gbmV3IFAocixpPDA/bi50ZXh0Lmxlbmd0aDowLGk8MD8iYmVmb3JlIjoiYWZ0ZXIiKX1mdW5jdGlvbiB5byhlLHQsbixyKXt2YXIgaT13ZSh0LGUuZG9jLmRpcmVjdGlvbik7aWYoIWkpcmV0dXJuIG1vKHQsbixyKTtuLmNoPj10LnRleHQubGVuZ3RoPyhuLmNoPXQudGV4dC5sZW5ndGgsbi5zdGlja3k9ImJlZm9yZSIpOm4uY2g8PTAmJihuLmNoPTAsbi5zdGlja3k9ImFmdGVyIik7dmFyIG89RGUoaSxuLmNoLG4uc3RpY2t5KSxhPWlbb107aWYoImx0ciI9PWUuZG9jLmRpcmVjdGlvbiYmYS5sZXZlbCUyPT0wJiYocj4wP2EudG8+bi5jaDphLmZyb208bi5jaCkpcmV0dXJuIG1vKHQsbixyKTt2YXIgcyx1PWZ1bmN0aW9uKGUsbil7cmV0dXJuIGhvKHQsZSBpbnN0YW5jZW9mIFA/ZS5jaDplLG4pfSxjPWZ1bmN0aW9uKG4pe3JldHVybiBlLm9wdGlvbnMubGluZVdyYXBwaW5nPyhzPXN8fFF0KGUsdCksbW4oZSx0LHMsbikpOntiZWdpbjowLGVuZDp0LnRleHQubGVuZ3RofX0sbD1jKCJiZWZvcmUiPT1uLnN0aWNreT91KG4sLTEpOm4uY2gpO2lmKCJydGwiPT1lLmRvYy5kaXJlY3Rpb258fDE9PWEubGV2ZWwpe3ZhciBwPTE9PWEubGV2ZWw9PXI8MCxmPXUobixwPzE6LTEpO2lmKG51bGwhPWYmJihwP2Y8PWEudG8mJmY8PWwuZW5kOmY+PWEuZnJvbSYmZj49bC5iZWdpbikpe3ZhciBkPXA/ImJlZm9yZSI6ImFmdGVyIjtyZXR1cm4gbmV3IFAobi5saW5lLGYsZCl9fXZhciBoPWZ1bmN0aW9uKGUsdCxyKXtmb3IodmFyIG89ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdD9uZXcgUChuLmxpbmUsdShlLDEpLCJiZWZvcmUiKTpuZXcgUChuLmxpbmUsZSwiYWZ0ZXIiKX07ZT49MCYmZTxpLmxlbmd0aDtlKz10KXt2YXIgYT1pW2VdLHM9dD4wPT0oMSE9YS5sZXZlbCksYz1zP3IuYmVnaW46dShyLmVuZCwtMSk7aWYoYS5mcm9tPD1jJiZjPGEudG8pcmV0dXJuIG8oYyxzKTtpZihjPXM/YS5mcm9tOnUoYS50bywtMSksci5iZWdpbjw9YyYmYzxyLmVuZClyZXR1cm4gbyhjLHMpfX0sbT1oKG8rcixyLGwpO2lmKG0pcmV0dXJuIG07dmFyIGc9cj4wP2wuZW5kOnUobC5iZWdpbiwtMSk7cmV0dXJuIG51bGw9PWd8fHI+MCYmZz09dC50ZXh0Lmxlbmd0aHx8IShtPWgocj4wPzA6aS5sZW5ndGgtMSxyLGMoZykpKT9udWxsOm19ZnVuY3Rpb24gdm8oZSx0KXt2YXIgbj1BKGUuZG9jLHQpLHI9ZmUobik7cmV0dXJuIHIhPW4mJih0PUYocikpLGdvKCEwLGUscix0LDEpfWZ1bmN0aW9uIGJvKGUsdCl7dmFyIG49QShlLmRvYyx0KSxyPWRlKG4pO3JldHVybiByIT1uJiYodD1GKHIpKSxnbyghMCxlLG4sdCwtMSl9ZnVuY3Rpb24geG8oZSx0KXt2YXIgbj12byhlLHQubGluZSkscj1BKGUuZG9jLG4ubGluZSksaT13ZShyLGUuZG9jLmRpcmVjdGlvbik7aWYoIWl8fDA9PWlbMF0ubGV2ZWwpe3ZhciBvPU1hdGgubWF4KDAsci50ZXh0LnNlYXJjaCgvXFMvKSksYT10LmxpbmU9PW4ubGluZSYmdC5jaDw9byYmdC5jaDtyZXR1cm4gUChuLmxpbmUsYT8wOm8sbi5zdGlja3kpfXJldHVybiBufWZ1bmN0aW9uIENvKGUsdCxuKXtpZigic3RyaW5nIj09dHlwZW9mIHQmJiEodD1Wc1t0XSkpcmV0dXJuITE7ZS5kaXNwbGF5LmlucHV0LmVuc3VyZVBvbGxlZCgpO3ZhciByPWUuZGlzcGxheS5zaGlmdCxpPSExO3RyeXtlLmlzUmVhZE9ubHkoKSYmKGUuc3RhdGUuc3VwcHJlc3NFZGl0cz0hMCksbiYmKGUuZGlzcGxheS5zaGlmdD0hMSksaT10KGUpIT1WYX1maW5hbGx5e2UuZGlzcGxheS5zaGlmdD1yLGUuc3RhdGUuc3VwcHJlc3NFZGl0cz0hMX1yZXR1cm4gaX1mdW5jdGlvbiBFbyhlLHQsbil7Zm9yKHZhciByPTA7cjxlLnN0YXRlLmtleU1hcHMubGVuZ3RoO3IrKyl7dmFyIGk9c28odCxlLnN0YXRlLmtleU1hcHNbcl0sbixlKTtpZihpKXJldHVybiBpfXJldHVybiBlLm9wdGlvbnMuZXh0cmFLZXlzJiZzbyh0LGUub3B0aW9ucy5leHRyYUtleXMsbixlKXx8c28odCxlLm9wdGlvbnMua2V5TWFwLG4sZSl9ZnVuY3Rpb24gRG8oZSx0LG4scil7dmFyIGk9ZS5zdGF0ZS5rZXlTZXE7aWYoaSl7aWYodW8odCkpcmV0dXJuImhhbmRsZWQiO2lmKC9cJyQvLnRlc3QodCk/ZS5zdGF0ZS5rZXlTZXE9bnVsbDpxcy5zZXQoNTAsZnVuY3Rpb24oKXtlLnN0YXRlLmtleVNlcT09aSYmKGUuc3RhdGUua2V5U2VxPW51bGwsZS5kaXNwbGF5LmlucHV0LnJlc2V0KCkpfSksd28oZSxpKyIgIit0LG4scikpcmV0dXJuITB9cmV0dXJuIHdvKGUsdCxuLHIpfWZ1bmN0aW9uIHdvKGUsdCxuLHIpe3ZhciBpPUVvKGUsdCxyKTtyZXR1cm4ibXVsdGkiPT1pJiYoZS5zdGF0ZS5rZXlTZXE9dCksImhhbmRsZWQiPT1pJiZDdChlLCJrZXlIYW5kbGVkIixlLHQsbiksImhhbmRsZWQiIT1pJiYibXVsdGkiIT1pfHwoTmUobiksSW4oZSkpLCEhaX1mdW5jdGlvbiBTbyhlLHQpe3ZhciBuPWxvKHQsITApO3JldHVybiEhbiYmKHQuc2hpZnRLZXkmJiFlLnN0YXRlLmtleVNlcT9EbyhlLCJTaGlmdC0iK24sdCxmdW5jdGlvbih0KXtyZXR1cm4gQ28oZSx0LCEwKX0pfHxEbyhlLG4sdCxmdW5jdGlvbih0KXtpZigic3RyaW5nIj09dHlwZW9mIHQ/L15nb1tBLVpdLy50ZXN0KHQpOnQubW90aW9uKXJldHVybiBDbyhlLHQpfSk6RG8oZSxuLHQsZnVuY3Rpb24odCl7cmV0dXJuIENvKGUsdCl9KSl9ZnVuY3Rpb24ga28oZSx0LG4pe3JldHVybiBEbyhlLCInIituKyInIix0LGZ1bmN0aW9uKHQpe3JldHVybiBDbyhlLHQsITApfSl9ZnVuY3Rpb24gQW8oZSl7dmFyIHQ9dGhpcztpZih0LmN1ck9wLmZvY3VzPWEoKSwhX2UodCxlKSl7YmEmJnhhPDExJiYyNz09ZS5rZXlDb2RlJiYoZS5yZXR1cm5WYWx1ZT0hMSk7dmFyIG49ZS5rZXlDb2RlO3QuZGlzcGxheS5zaGlmdD0xNj09bnx8ZS5zaGlmdEtleTt2YXIgcj1Tbyh0LGUpO3dhJiYoSHM9cj9uOm51bGwsIXImJjg4PT1uJiYhYXMmJihGYT9lLm1ldGFLZXk6ZS5jdHJsS2V5KSYmdC5yZXBsYWNlU2VsZWN0aW9uKCIiLG51bGwsImN1dCIpKSwxOCE9bnx8L1xiQ29kZU1pcnJvci1jcm9zc2hhaXJcYi8udGVzdCh0LmRpc3BsYXkubGluZURpdi5jbGFzc05hbWUpfHxfbyh0KX19ZnVuY3Rpb24gX28oZSl7ZnVuY3Rpb24gdChlKXsxOCE9ZS5rZXlDb2RlJiZlLmFsdEtleXx8KFJhKG4sIkNvZGVNaXJyb3ItY3Jvc3NoYWlyIiksa2UoZG9jdW1lbnQsImtleXVwIix0KSxrZShkb2N1bWVudCwibW91c2VvdmVyIix0KSl9dmFyIG49ZS5kaXNwbGF5LmxpbmVEaXY7cyhuLCJDb2RlTWlycm9yLWNyb3NzaGFpciIpLG5zKGRvY3VtZW50LCJrZXl1cCIsdCksbnMoZG9jdW1lbnQsIm1vdXNlb3ZlciIsdCl9ZnVuY3Rpb24gVG8oZSl7MTY9PWUua2V5Q29kZSYmKHRoaXMuZG9jLnNlbC5zaGlmdD0hMSksX2UodGhpcyxlKX1mdW5jdGlvbiBPbyhlKXt2YXIgdD10aGlzO2lmKCEoTXQodC5kaXNwbGF5LGUpfHxfZSh0LGUpfHxlLmN0cmxLZXkmJiFlLmFsdEtleXx8RmEmJmUubWV0YUtleSkpe3ZhciBuPWUua2V5Q29kZSxyPWUuY2hhckNvZGU7aWYod2EmJm49PUhzKXJldHVybiBIcz1udWxsLHZvaWQgTmUoZSk7aWYoIXdhfHxlLndoaWNoJiYhKGUud2hpY2g8MTApfHwhU28odCxlKSl7dmFyIGk9U3RyaW5nLmZyb21DaGFyQ29kZShudWxsPT1yP246cik7IlxiIiE9aSYmKGtvKHQsZSxpKXx8dC5kaXNwbGF5LmlucHV0Lm9uS2V5UHJlc3MoZSkpfX19ZnVuY3Rpb24gRm8oZSx0KXt2YXIgbj0rbmV3IERhdGU7cmV0dXJuIEtzJiZLcy5jb21wYXJlKG4sZSx0KT8oUXM9S3M9bnVsbCwidHJpcGxlIik6UXMmJlFzLmNvbXBhcmUobixlLHQpPyhLcz1uZXcgV3MobixlLHQpLFFzPW51bGwsImRvdWJsZSIpOihRcz1uZXcgV3MobixlLHQpLEtzPW51bGwsInNpbmdsZSIpfWZ1bmN0aW9uIE5vKGUpe3ZhciB0PXRoaXMsbj10LmRpc3BsYXk7aWYoIShfZSh0LGUpfHxuLmFjdGl2ZVRvdWNoJiZuLmlucHV0LnN1cHBvcnRzVG91Y2goKSkpe2lmKG4uaW5wdXQuZW5zdXJlUG9sbGVkKCksbi5zaGlmdD1lLnNoaWZ0S2V5LE10KG4sZSkpcmV0dXJuIHZvaWQoQ2F8fChuLnNjcm9sbGVyLmRyYWdnYWJsZT0hMSxzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIG4uc2Nyb2xsZXIuZHJhZ2dhYmxlPSEwfSwxMDApKSk7aWYoIVVvKHQsZSkpe3ZhciByPWtuKHQsZSksaT1qZShlKSxvPXI/Rm8ocixpKToic2luZ2xlIjt3aW5kb3cuZm9jdXMoKSwxPT1pJiZ0LnN0YXRlLnNlbGVjdGluZ1RleHQmJnQuc3RhdGUuc2VsZWN0aW5nVGV4dChlKSxyJiZJbyh0LGkscixvLGUpfHwoMT09aT9yP1BvKHQscixvLGUpOk1lKGUpPT1uLnNjcm9sbGVyJiZOZShlKToyPT1pPyhyJiZtaSh0LmRvYyxyKSxzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIG4uaW5wdXQuZm9jdXMoKX0sMjApKTozPT1pJiYoamE/em8odCxlKTpQbih0KSkpfX19ZnVuY3Rpb24gSW8oZSx0LG4scixpKXt2YXIgbz0iQ2xpY2siO3JldHVybiJkb3VibGUiPT1yP289IkRvdWJsZSIrbzoidHJpcGxlIj09ciYmKG89IlRyaXBsZSIrbyksbz0oMT09dD8iTGVmdCI6Mj09dD8iTWlkZGxlIjoiUmlnaHQiKStvLERvKGUsY28obyxpKSxpLGZ1bmN0aW9uKHQpe2lmKCJzdHJpbmciPT10eXBlb2YgdCYmKHQ9VnNbdF0pLCF0KXJldHVybiExO3ZhciByPSExO3RyeXtlLmlzUmVhZE9ubHkoKSYmKGUuc3RhdGUuc3VwcHJlc3NFZGl0cz0hMCkscj10KGUsbikhPVZhfWZpbmFsbHl7ZS5zdGF0ZS5zdXBwcmVzc0VkaXRzPSExfXJldHVybiByfSl9ZnVuY3Rpb24gTG8oZSx0LG4pe3ZhciByPWUuZ2V0T3B0aW9uKCJjb25maWd1cmVNb3VzZSIpLGk9cj9yKGUsdCxuKTp7fTtpZihudWxsPT1pLnVuaXQpe3ZhciBvPU5hP24uc2hpZnRLZXkmJm4ubWV0YUtleTpuLmFsdEtleTtpLnVuaXQ9bz8icmVjdGFuZ2xlIjoic2luZ2xlIj09dD8iY2hhciI6ImRvdWJsZSI9PXQ/IndvcmQiOiJsaW5lIn1yZXR1cm4obnVsbD09aS5leHRlbmR8fGUuZG9jLmV4dGVuZCkmJihpLmV4dGVuZD1lLmRvYy5leHRlbmR8fG4uc2hpZnRLZXkpLG51bGw9PWkuYWRkTmV3JiYoaS5hZGROZXc9RmE/bi5tZXRhS2V5Om4uY3RybEtleSksbnVsbD09aS5tb3ZlT25EcmFnJiYoaS5tb3ZlT25EcmFnPSEoRmE/bi5hbHRLZXk6bi5jdHJsS2V5KSksaX1mdW5jdGlvbiBQbyhlLHQsbixyKXtiYT9zZXRUaW1lb3V0KGMoTG4sZSksMCk6ZS5jdXJPcC5mb2N1cz1hKCk7dmFyIGksbz1MbyhlLG4scikscz1lLmRvYy5zZWw7ZS5vcHRpb25zLmRyYWdEcm9wJiZycyYmIWUuaXNSZWFkT25seSgpJiYic2luZ2xlIj09biYmKGk9cy5jb250YWlucyh0KSk+LTEmJihNKChpPXMucmFuZ2VzW2ldKS5mcm9tKCksdCk8MHx8dC54UmVsPjApJiYoTShpLnRvKCksdCk+MHx8dC54UmVsPDApP01vKGUscix0LG8pOlJvKGUscix0LG8pfWZ1bmN0aW9uIE1vKGUsdCxuLHIpe3ZhciBpPWUuZGlzcGxheSxvPSExLGE9bXIoZSxmdW5jdGlvbih0KXtDYSYmKGkuc2Nyb2xsZXIuZHJhZ2dhYmxlPSExKSxlLnN0YXRlLmRyYWdnaW5nVGV4dD0hMSxrZShpLndyYXBwZXIub3duZXJEb2N1bWVudCwibW91c2V1cCIsYSksa2UoaS53cmFwcGVyLm93bmVyRG9jdW1lbnQsIm1vdXNlbW92ZSIscyksa2UoaS5zY3JvbGxlciwiZHJhZ3N0YXJ0Iix1KSxrZShpLnNjcm9sbGVyLCJkcm9wIixhKSxvfHwoTmUodCksci5hZGROZXd8fG1pKGUuZG9jLG4sbnVsbCxudWxsLHIuZXh0ZW5kKSxDYXx8YmEmJjk9PXhhP3NldFRpbWVvdXQoZnVuY3Rpb24oKXtpLndyYXBwZXIub3duZXJEb2N1bWVudC5ib2R5LmZvY3VzKCksaS5pbnB1dC5mb2N1cygpfSwyMCk6aS5pbnB1dC5mb2N1cygpKX0pLHM9ZnVuY3Rpb24oZSl7bz1vfHxNYXRoLmFicyh0LmNsaWVudFgtZS5jbGllbnRYKStNYXRoLmFicyh0LmNsaWVudFktZS5jbGllbnRZKT49MTB9LHU9ZnVuY3Rpb24oKXtyZXR1cm4gbz0hMH07Q2EmJihpLnNjcm9sbGVyLmRyYWdnYWJsZT0hMCksZS5zdGF0ZS5kcmFnZ2luZ1RleHQ9YSxhLmNvcHk9IXIubW92ZU9uRHJhZyxpLnNjcm9sbGVyLmRyYWdEcm9wJiZpLnNjcm9sbGVyLmRyYWdEcm9wKCksbnMoaS53cmFwcGVyLm93bmVyRG9jdW1lbnQsIm1vdXNldXAiLGEpLG5zKGkud3JhcHBlci5vd25lckRvY3VtZW50LCJtb3VzZW1vdmUiLHMpLG5zKGkuc2Nyb2xsZXIsImRyYWdzdGFydCIsdSksbnMoaS5zY3JvbGxlciwiZHJvcCIsYSksUG4oZSksc2V0VGltZW91dChmdW5jdGlvbigpe3JldHVybiBpLmlucHV0LmZvY3VzKCl9LDIwKX1mdW5jdGlvbiBqbyhlLHQsbil7aWYoImNoYXIiPT1uKXJldHVybiBuZXcgT3ModCx0KTtpZigid29yZCI9PW4pcmV0dXJuIGUuZmluZFdvcmRBdCh0KTtpZigibGluZSI9PW4pcmV0dXJuIG5ldyBPcyhQKHQubGluZSwwKSx6KGUuZG9jLFAodC5saW5lKzEsMCkpKTt2YXIgcj1uKGUsdCk7cmV0dXJuIG5ldyBPcyhyLmZyb20sci50byl9ZnVuY3Rpb24gUm8oZSx0LG4scil7ZnVuY3Rpb24gaSh0KXtpZigwIT1NKHksdCkpaWYoeT10LCJyZWN0YW5nbGUiPT1yLnVuaXQpe2Zvcih2YXIgaT1bXSxvPWUub3B0aW9ucy50YWJTaXplLGE9cChBKGMsbi5saW5lKS50ZXh0LG4uY2gsbykscz1wKEEoYyx0LmxpbmUpLnRleHQsdC5jaCxvKSx1PU1hdGgubWluKGEscyksbT1NYXRoLm1heChhLHMpLGc9TWF0aC5taW4obi5saW5lLHQubGluZSksdj1NYXRoLm1pbihlLmxhc3RMaW5lKCksTWF0aC5tYXgobi5saW5lLHQubGluZSkpO2c8PXY7ZysrKXt2YXIgYj1BKGMsZykudGV4dCx4PWQoYix1LG8pO3U9PW0/aS5wdXNoKG5ldyBPcyhQKGcseCksUChnLHgpKSk6Yi5sZW5ndGg+eCYmaS5wdXNoKG5ldyBPcyhQKGcseCksUChnLGQoYixtLG8pKSkpfWkubGVuZ3RofHxpLnB1c2gobmV3IE9zKG4sbikpLENpKGMsJHIoaC5yYW5nZXMuc2xpY2UoMCxmKS5jb25jYXQoaSksZikse29yaWdpbjoiKm1vdXNlIixzY3JvbGw6ITF9KSxlLnNjcm9sbEludG9WaWV3KHQpfWVsc2V7dmFyIEMsRT1sLEQ9am8oZSx0LHIudW5pdCksdz1FLmFuY2hvcjtNKEQuYW5jaG9yLHcpPjA/KEM9RC5oZWFkLHc9JChFLmZyb20oKSxELmFuY2hvcikpOihDPUQuYW5jaG9yLHc9QihFLnRvKCksRC5oZWFkKSk7dmFyIFM9aC5yYW5nZXMuc2xpY2UoMCk7U1tmXT1CbyhlLG5ldyBPcyh6KGMsdyksQykpLENpKGMsJHIoUyxmKSxIYSl9fWZ1bmN0aW9uIG8odCl7dmFyIG49KytiLHM9a24oZSx0LCEwLCJyZWN0YW5nbGUiPT1yLnVuaXQpO2lmKHMpaWYoMCE9TShzLHkpKXtlLmN1ck9wLmZvY3VzPWEoKSxpKHMpO3ZhciBsPSRuKHUsYyk7KHMubGluZT49bC50b3x8cy5saW5lPGwuZnJvbSkmJnNldFRpbWVvdXQobXIoZSxmdW5jdGlvbigpe2I9PW4mJm8odCl9KSwxNTApfWVsc2V7dmFyIHA9dC5jbGllbnRZPHYudG9wPy0yMDp0LmNsaWVudFk+di5ib3R0b20/MjA6MDtwJiZzZXRUaW1lb3V0KG1yKGUsZnVuY3Rpb24oKXtiPT1uJiYodS5zY3JvbGxlci5zY3JvbGxUb3ArPXAsbyh0KSl9KSw1MCl9fWZ1bmN0aW9uIHModCl7ZS5zdGF0ZS5zZWxlY3RpbmdUZXh0PSExLGI9MS8wLE5lKHQpLHUuaW5wdXQuZm9jdXMoKSxrZSh1LndyYXBwZXIub3duZXJEb2N1bWVudCwibW91c2Vtb3ZlIix4KSxrZSh1LndyYXBwZXIub3duZXJEb2N1bWVudCwibW91c2V1cCIsQyksYy5oaXN0b3J5Lmxhc3RTZWxPcmlnaW49bnVsbH12YXIgdT1lLmRpc3BsYXksYz1lLmRvYztOZSh0KTt2YXIgbCxmLGg9Yy5zZWwsbT1oLnJhbmdlcztpZihyLmFkZE5ldyYmIXIuZXh0ZW5kPyhmPWMuc2VsLmNvbnRhaW5zKG4pLGw9Zj4tMT9tW2ZdOm5ldyBPcyhuLG4pKToobD1jLnNlbC5wcmltYXJ5KCksZj1jLnNlbC5wcmltSW5kZXgpLCJyZWN0YW5nbGUiPT1yLnVuaXQpci5hZGROZXd8fChsPW5ldyBPcyhuLG4pKSxuPWtuKGUsdCwhMCwhMCksZj0tMTtlbHNle3ZhciBnPWpvKGUsbixyLnVuaXQpO2w9ci5leHRlbmQ/aGkobCxnLmFuY2hvcixnLmhlYWQsci5leHRlbmQpOmd9ci5hZGROZXc/LTE9PWY/KGY9bS5sZW5ndGgsQ2koYywkcihtLmNvbmNhdChbbF0pLGYpLHtzY3JvbGw6ITEsb3JpZ2luOiIqbW91c2UifSkpOm0ubGVuZ3RoPjEmJm1bZl0uZW1wdHkoKSYmImNoYXIiPT1yLnVuaXQmJiFyLmV4dGVuZD8oQ2koYywkcihtLnNsaWNlKDAsZikuY29uY2F0KG0uc2xpY2UoZisxKSksMCkse3Njcm9sbDohMSxvcmlnaW46Iiptb3VzZSJ9KSxoPWMuc2VsKTp5aShjLGYsbCxIYSk6KGY9MCxDaShjLG5ldyBUcyhbbF0sMCksSGEpLGg9Yy5zZWwpO3ZhciB5PW4sdj11LndyYXBwZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksYj0wLHg9bXIoZSxmdW5jdGlvbihlKXswIT09ZS5idXR0b25zJiZqZShlKT9vKGUpOnMoZSl9KSxDPW1yKGUscyk7ZS5zdGF0ZS5zZWxlY3RpbmdUZXh0PUMsbnModS53cmFwcGVyLm93bmVyRG9jdW1lbnQsIm1vdXNlbW92ZSIseCksbnModS53cmFwcGVyLm93bmVyRG9jdW1lbnQsIm1vdXNldXAiLEMpfWZ1bmN0aW9uIEJvKGUsdCl7dmFyIG49dC5hbmNob3Iscj10LmhlYWQsaT1BKGUuZG9jLG4ubGluZSk7aWYoMD09TShuLHIpJiZuLnN0aWNreT09ci5zdGlja3kpcmV0dXJuIHQ7dmFyIG89d2UoaSk7aWYoIW8pcmV0dXJuIHQ7dmFyIGE9RGUobyxuLmNoLG4uc3RpY2t5KSxzPW9bYV07aWYocy5mcm9tIT1uLmNoJiZzLnRvIT1uLmNoKXJldHVybiB0O3ZhciB1PWErKHMuZnJvbT09bi5jaD09KDEhPXMubGV2ZWwpPzA6MSk7aWYoMD09dXx8dT09by5sZW5ndGgpcmV0dXJuIHQ7dmFyIGM7aWYoci5saW5lIT1uLmxpbmUpYz0oci5saW5lLW4ubGluZSkqKCJsdHIiPT1lLmRvYy5kaXJlY3Rpb24/MTotMSk+MDtlbHNle3ZhciBsPURlKG8sci5jaCxyLnN0aWNreSkscD1sLWF8fChyLmNoLW4uY2gpKigxPT1zLmxldmVsPy0xOjEpO2M9bD09dS0xfHxsPT11P3A8MDpwPjB9dmFyIGY9b1t1KyhjPy0xOjApXSxkPWM9PSgxPT1mLmxldmVsKSxoPWQ/Zi5mcm9tOmYudG8sbT1kPyJhZnRlciI6ImJlZm9yZSI7cmV0dXJuIG4uY2g9PWgmJm4uc3RpY2t5PT1tP3Q6bmV3IE9zKG5ldyBQKG4ubGluZSxoLG0pLHIpfWZ1bmN0aW9uICRvKGUsdCxuLHIpe3ZhciBpLG87aWYodC50b3VjaGVzKWk9dC50b3VjaGVzWzBdLmNsaWVudFgsbz10LnRvdWNoZXNbMF0uY2xpZW50WTtlbHNlIHRyeXtpPXQuY2xpZW50WCxvPXQuY2xpZW50WX1jYXRjaCh0KXtyZXR1cm4hMX1pZihpPj1NYXRoLmZsb29yKGUuZGlzcGxheS5ndXR0ZXJzLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnJpZ2h0KSlyZXR1cm4hMTtyJiZOZSh0KTt2YXIgYT1lLmRpc3BsYXkscz1hLmxpbmVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7aWYobz5zLmJvdHRvbXx8IU9lKGUsbikpcmV0dXJuIExlKHQpO28tPXMudG9wLWEudmlld09mZnNldDtmb3IodmFyIHU9MDt1PGUub3B0aW9ucy5ndXR0ZXJzLmxlbmd0aDsrK3Upe3ZhciBjPWEuZ3V0dGVycy5jaGlsZE5vZGVzW3VdO2lmKGMmJmMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkucmlnaHQ+PWkpe3JldHVybiBBZShlLG4sZSxOKGUuZG9jLG8pLGUub3B0aW9ucy5ndXR0ZXJzW3VdLHQpLExlKHQpfX19ZnVuY3Rpb24gVW8oZSx0KXtyZXR1cm4gJG8oZSx0LCJndXR0ZXJDbGljayIsITApfWZ1bmN0aW9uIHpvKGUsdCl7TXQoZS5kaXNwbGF5LHQpfHxHbyhlLHQpfHxfZShlLHQsImNvbnRleHRtZW51Iil8fGUuZGlzcGxheS5pbnB1dC5vbkNvbnRleHRNZW51KHQpfWZ1bmN0aW9uIEdvKGUsdCl7cmV0dXJuISFPZShlLCJndXR0ZXJDb250ZXh0TWVudSIpJiYkbyhlLHQsImd1dHRlckNvbnRleHRNZW51IiwhMSl9ZnVuY3Rpb24gVm8oZSl7ZS5kaXNwbGF5LndyYXBwZXIuY2xhc3NOYW1lPWUuZGlzcGxheS53cmFwcGVyLmNsYXNzTmFtZS5yZXBsYWNlKC9ccypjbS1zLVxTKy9nLCIiKStlLm9wdGlvbnMudGhlbWUucmVwbGFjZSgvKF58XHMpXHMqL2csIiBjbS1zLSIpLG5uKGUpfWZ1bmN0aW9uIHFvKGUpe1ByKGUpLHZyKGUpLFVuKGUpfWZ1bmN0aW9uIEhvKGUsdCxuKXtpZighdCE9IShuJiZuIT1Kcykpe3ZhciByPWUuZGlzcGxheS5kcmFnRnVuY3Rpb25zLGk9dD9uczprZTtpKGUuZGlzcGxheS5zY3JvbGxlciwiZHJhZ3N0YXJ0IixyLnN0YXJ0KSxpKGUuZGlzcGxheS5zY3JvbGxlciwiZHJhZ2VudGVyIixyLmVudGVyKSxpKGUuZGlzcGxheS5zY3JvbGxlciwiZHJhZ292ZXIiLHIub3ZlciksaShlLmRpc3BsYXkuc2Nyb2xsZXIsImRyYWdsZWF2ZSIsci5sZWF2ZSksaShlLmRpc3BsYXkuc2Nyb2xsZXIsImRyb3AiLHIuZHJvcCl9fWZ1bmN0aW9uIFdvKGUpe2Uub3B0aW9ucy5saW5lV3JhcHBpbmc/KHMoZS5kaXNwbGF5LndyYXBwZXIsIkNvZGVNaXJyb3Itd3JhcCIpLGUuZGlzcGxheS5zaXplci5zdHlsZS5taW5XaWR0aD0iIixlLmRpc3BsYXkuc2l6ZXJXaWR0aD1udWxsKTooUmEoZS5kaXNwbGF5LndyYXBwZXIsIkNvZGVNaXJyb3Itd3JhcCIpLENlKGUpKSxTbihlKSx2cihlKSxubihlKSxzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIHJyKGUpfSwxMDApfWZ1bmN0aW9uIFFvKGUsdCl7dmFyIG49dGhpcztpZighKHRoaXMgaW5zdGFuY2VvZiBRbykpcmV0dXJuIG5ldyBRbyhlLHQpO3RoaXMub3B0aW9ucz10PXQ/bCh0KTp7fSxsKFlzLHQsITEpLE1yKHQpO3ZhciByPXQudmFsdWU7InN0cmluZyI9PXR5cGVvZiByJiYocj1uZXcgTXMocix0Lm1vZGUsbnVsbCx0LmxpbmVTZXBhcmF0b3IsdC5kaXJlY3Rpb24pKSx0aGlzLmRvYz1yO3ZhciBpPW5ldyBRby5pbnB1dFN0eWxlc1t0LmlucHV0U3R5bGVdKHRoaXMpLG89dGhpcy5kaXNwbGF5PW5ldyBrKGUscixpKTtvLndyYXBwZXIuQ29kZU1pcnJvcj10aGlzLFByKHRoaXMpLFZvKHRoaXMpLHQubGluZVdyYXBwaW5nJiYodGhpcy5kaXNwbGF5LndyYXBwZXIuY2xhc3NOYW1lKz0iIENvZGVNaXJyb3Itd3JhcCIpLG9yKHRoaXMpLHRoaXMuc3RhdGU9e2tleU1hcHM6W10sb3ZlcmxheXM6W10sbW9kZUdlbjowLG92ZXJ3cml0ZTohMSxkZWxheWluZ0JsdXJFdmVudDohMSxmb2N1c2VkOiExLHN1cHByZXNzRWRpdHM6ITEscGFzdGVJbmNvbWluZzohMSxjdXRJbmNvbWluZzohMSxzZWxlY3RpbmdUZXh0OiExLGRyYWdnaW5nVGV4dDohMSxoaWdobGlnaHQ6bmV3ICRhLGtleVNlcTpudWxsLHNwZWNpYWxDaGFyczpudWxsfSx0LmF1dG9mb2N1cyYmIU9hJiZvLmlucHV0LmZvY3VzKCksYmEmJnhhPDExJiZzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIG4uZGlzcGxheS5pbnB1dC5yZXNldCghMCl9LDIwKSxLbyh0aGlzKSxubygpLGFyKHRoaXMpLHRoaXMuY3VyT3AuZm9yY2VVcGRhdGU9ITAsWHIodGhpcyxyKSx0LmF1dG9mb2N1cyYmIU9hfHx0aGlzLmhhc0ZvY3VzKCk/c2V0VGltZW91dChjKE1uLHRoaXMpLDIwKTpqbih0aGlzKTtmb3IodmFyIGEgaW4gWHMpWHMuaGFzT3duUHJvcGVydHkoYSkmJlhzW2FdKG4sdFthXSxKcyk7em4odGhpcyksdC5maW5pc2hJbml0JiZ0LmZpbmlzaEluaXQodGhpcyk7Zm9yKHZhciBzPTA7czxacy5sZW5ndGg7KytzKVpzW3NdKG4pO3NyKHRoaXMpLENhJiZ0LmxpbmVXcmFwcGluZyYmIm9wdGltaXplbGVnaWJpbGl0eSI9PWdldENvbXB1dGVkU3R5bGUoby5saW5lRGl2KS50ZXh0UmVuZGVyaW5nJiYoby5saW5lRGl2LnN0eWxlLnRleHRSZW5kZXJpbmc9ImF1dG8iKX1mdW5jdGlvbiBLbyhlKXtmdW5jdGlvbiB0KCl7aS5hY3RpdmVUb3VjaCYmKG89c2V0VGltZW91dChmdW5jdGlvbigpe3JldHVybiBpLmFjdGl2ZVRvdWNoPW51bGx9LDFlMyksYT1pLmFjdGl2ZVRvdWNoLGEuZW5kPStuZXcgRGF0ZSl9ZnVuY3Rpb24gbihlKXtpZigxIT1lLnRvdWNoZXMubGVuZ3RoKXJldHVybiExO3ZhciB0PWUudG91Y2hlc1swXTtyZXR1cm4gdC5yYWRpdXNYPD0xJiZ0LnJhZGl1c1k8PTF9ZnVuY3Rpb24gcihlLHQpe2lmKG51bGw9PXQubGVmdClyZXR1cm4hMDt2YXIgbj10LmxlZnQtZS5sZWZ0LHI9dC50b3AtZS50b3A7cmV0dXJuIG4qbityKnI+NDAwfXZhciBpPWUuZGlzcGxheTtucyhpLnNjcm9sbGVyLCJtb3VzZWRvd24iLG1yKGUsTm8pKSxiYSYmeGE8MTE/bnMoaS5zY3JvbGxlciwiZGJsY2xpY2siLG1yKGUsZnVuY3Rpb24odCl7aWYoIV9lKGUsdCkpe3ZhciBuPWtuKGUsdCk7aWYobiYmIVVvKGUsdCkmJiFNdChlLmRpc3BsYXksdCkpe05lKHQpO3ZhciByPWUuZmluZFdvcmRBdChuKTttaShlLmRvYyxyLmFuY2hvcixyLmhlYWQpfX19KSk6bnMoaS5zY3JvbGxlciwiZGJsY2xpY2siLGZ1bmN0aW9uKHQpe3JldHVybiBfZShlLHQpfHxOZSh0KX0pLGphfHxucyhpLnNjcm9sbGVyLCJjb250ZXh0bWVudSIsZnVuY3Rpb24odCl7cmV0dXJuIHpvKGUsdCl9KTt2YXIgbyxhPXtlbmQ6MH07bnMoaS5zY3JvbGxlciwidG91Y2hzdGFydCIsZnVuY3Rpb24odCl7aWYoIV9lKGUsdCkmJiFuKHQpJiYhVW8oZSx0KSl7aS5pbnB1dC5lbnN1cmVQb2xsZWQoKSxjbGVhclRpbWVvdXQobyk7dmFyIHI9K25ldyBEYXRlO2kuYWN0aXZlVG91Y2g9e3N0YXJ0OnIsbW92ZWQ6ITEscHJldjpyLWEuZW5kPD0zMDA/YTpudWxsfSwxPT10LnRvdWNoZXMubGVuZ3RoJiYoaS5hY3RpdmVUb3VjaC5sZWZ0PXQudG91Y2hlc1swXS5wYWdlWCxpLmFjdGl2ZVRvdWNoLnRvcD10LnRvdWNoZXNbMF0ucGFnZVkpfX0pLG5zKGkuc2Nyb2xsZXIsInRvdWNobW92ZSIsZnVuY3Rpb24oKXtpLmFjdGl2ZVRvdWNoJiYoaS5hY3RpdmVUb3VjaC5tb3ZlZD0hMCl9KSxucyhpLnNjcm9sbGVyLCJ0b3VjaGVuZCIsZnVuY3Rpb24obil7dmFyIG89aS5hY3RpdmVUb3VjaDtpZihvJiYhTXQoaSxuKSYmbnVsbCE9by5sZWZ0JiYhby5tb3ZlZCYmbmV3IERhdGUtby5zdGFydDwzMDApe3ZhciBhLHM9ZS5jb29yZHNDaGFyKGkuYWN0aXZlVG91Y2gsInBhZ2UiKTthPSFvLnByZXZ8fHIobyxvLnByZXYpP25ldyBPcyhzLHMpOiFvLnByZXYucHJldnx8cihvLG8ucHJldi5wcmV2KT9lLmZpbmRXb3JkQXQocyk6bmV3IE9zKFAocy5saW5lLDApLHooZS5kb2MsUChzLmxpbmUrMSwwKSkpLGUuc2V0U2VsZWN0aW9uKGEuYW5jaG9yLGEuaGVhZCksZS5mb2N1cygpLE5lKG4pfXQoKX0pLG5zKGkuc2Nyb2xsZXIsInRvdWNoY2FuY2VsIix0KSxucyhpLnNjcm9sbGVyLCJzY3JvbGwiLGZ1bmN0aW9uKCl7aS5zY3JvbGxlci5jbGllbnRIZWlnaHQmJihabihlLGkuc2Nyb2xsZXIuc2Nyb2xsVG9wKSx0cihlLGkuc2Nyb2xsZXIuc2Nyb2xsTGVmdCwhMCksQWUoZSwic2Nyb2xsIixlKSl9KSxucyhpLnNjcm9sbGVyLCJtb3VzZXdoZWVsIixmdW5jdGlvbih0KXtyZXR1cm4gQnIoZSx0KX0pLG5zKGkuc2Nyb2xsZXIsIkRPTU1vdXNlU2Nyb2xsIixmdW5jdGlvbih0KXtyZXR1cm4gQnIoZSx0KX0pLG5zKGkud3JhcHBlciwic2Nyb2xsIixmdW5jdGlvbigpe3JldHVybiBpLndyYXBwZXIuc2Nyb2xsVG9wPWkud3JhcHBlci5zY3JvbGxMZWZ0PTB9KSxpLmRyYWdGdW5jdGlvbnM9e2VudGVyOmZ1bmN0aW9uKHQpe19lKGUsdCl8fFBlKHQpfSxvdmVyOmZ1bmN0aW9uKHQpe19lKGUsdCl8fChaaShlLHQpLFBlKHQpKX0sc3RhcnQ6ZnVuY3Rpb24odCl7cmV0dXJuIFhpKGUsdCl9LGRyb3A6bXIoZSxZaSksbGVhdmU6ZnVuY3Rpb24odCl7X2UoZSx0KXx8ZW8oZSl9fTt2YXIgcz1pLmlucHV0LmdldEZpZWxkKCk7bnMocywia2V5dXAiLGZ1bmN0aW9uKHQpe3JldHVybiBUby5jYWxsKGUsdCl9KSxucyhzLCJrZXlkb3duIixtcihlLEFvKSksbnMocywia2V5cHJlc3MiLG1yKGUsT28pKSxucyhzLCJmb2N1cyIsZnVuY3Rpb24odCl7cmV0dXJuIE1uKGUsdCl9KSxucyhzLCJibHVyIixmdW5jdGlvbih0KXtyZXR1cm4gam4oZSx0KX0pfWZ1bmN0aW9uIEpvKGUsdCxuLHIpe3ZhciBpLG89ZS5kb2M7bnVsbD09biYmKG49ImFkZCIpLCJzbWFydCI9PW4mJihvLm1vZGUuaW5kZW50P2k9WWUoZSx0KS5zdGF0ZTpuPSJwcmV2Iik7dmFyIGE9ZS5vcHRpb25zLnRhYlNpemUscz1BKG8sdCksdT1wKHMudGV4dCxudWxsLGEpO3Muc3RhdGVBZnRlciYmKHMuc3RhdGVBZnRlcj1udWxsKTt2YXIgYyxsPXMudGV4dC5tYXRjaCgvXlxzKi8pWzBdO2lmKHJ8fC9cUy8udGVzdChzLnRleHQpKXtpZigic21hcnQiPT1uJiYoKGM9by5tb2RlLmluZGVudChpLHMudGV4dC5zbGljZShsLmxlbmd0aCkscy50ZXh0KSk9PVZhfHxjPjE1MCkpe2lmKCFyKXJldHVybjtuPSJwcmV2In19ZWxzZSBjPTAsbj0ibm90IjsicHJldiI9PW4/Yz10Pm8uZmlyc3Q/cChBKG8sdC0xKS50ZXh0LG51bGwsYSk6MDoiYWRkIj09bj9jPXUrZS5vcHRpb25zLmluZGVudFVuaXQ6InN1YnRyYWN0Ij09bj9jPXUtZS5vcHRpb25zLmluZGVudFVuaXQ6Im51bWJlciI9PXR5cGVvZiBuJiYoYz11K24pLGM9TWF0aC5tYXgoMCxjKTt2YXIgZj0iIixkPTA7aWYoZS5vcHRpb25zLmluZGVudFdpdGhUYWJzKWZvcih2YXIgbT1NYXRoLmZsb29yKGMvYSk7bTstLW0pZCs9YSxmKz0iXHQiO2lmKGQ8YyYmKGYrPWgoYy1kKSksZiE9bClyZXR1cm4gamkobyxmLFAodCwwKSxQKHQsbC5sZW5ndGgpLCIraW5wdXQiKSxzLnN0YXRlQWZ0ZXI9bnVsbCwhMDtmb3IodmFyIGc9MDtnPG8uc2VsLnJhbmdlcy5sZW5ndGg7ZysrKXt2YXIgeT1vLnNlbC5yYW5nZXNbZ107aWYoeS5oZWFkLmxpbmU9PXQmJnkuaGVhZC5jaDxsLmxlbmd0aCl7dmFyIHY9UCh0LGwubGVuZ3RoKTt5aShvLGcsbmV3IE9zKHYsdikpO2JyZWFrfX19ZnVuY3Rpb24gWW8oZSl7ZXU9ZX1mdW5jdGlvbiBYbyhlLHQsbixyLGkpe3ZhciBvPWUuZG9jO2UuZGlzcGxheS5zaGlmdD0hMSxyfHwocj1vLnNlbCk7dmFyIGE9ZS5zdGF0ZS5wYXN0ZUluY29taW5nfHwicGFzdGUiPT1pLHM9aXModCksdT1udWxsO2lmKGEmJnIucmFuZ2VzLmxlbmd0aD4xKWlmKGV1JiZldS50ZXh0LmpvaW4oIlxuIik9PXQpe2lmKHIucmFuZ2VzLmxlbmd0aCVldS50ZXh0Lmxlbmd0aD09MCl7dT1bXTtmb3IodmFyIGM9MDtjPGV1LnRleHQubGVuZ3RoO2MrKyl1LnB1c2goby5zcGxpdExpbmVzKGV1LnRleHRbY10pKX19ZWxzZSBzLmxlbmd0aD09ci5yYW5nZXMubGVuZ3RoJiZlLm9wdGlvbnMucGFzdGVMaW5lc1BlclNlbGVjdGlvbiYmKHU9ZyhzLGZ1bmN0aW9uKGUpe3JldHVybltlXX0pKTtmb3IodmFyIGwscD1yLnJhbmdlcy5sZW5ndGgtMTtwPj0wO3AtLSl7dmFyIGY9ci5yYW5nZXNbcF0sZD1mLmZyb20oKSxoPWYudG8oKTtmLmVtcHR5KCkmJihuJiZuPjA/ZD1QKGQubGluZSxkLmNoLW4pOmUuc3RhdGUub3ZlcndyaXRlJiYhYT9oPVAoaC5saW5lLE1hdGgubWluKEEobyxoLmxpbmUpLnRleHQubGVuZ3RoLGguY2grbShzKS5sZW5ndGgpKTpldSYmZXUubGluZVdpc2UmJmV1LnRleHQuam9pbigiXG4iKT09dCYmKGQ9aD1QKGQubGluZSwwKSkpLGw9ZS5jdXJPcC51cGRhdGVJbnB1dDt2YXIgeT17ZnJvbTpkLHRvOmgsdGV4dDp1P3VbcCV1Lmxlbmd0aF06cyxvcmlnaW46aXx8KGE/InBhc3RlIjplLnN0YXRlLmN1dEluY29taW5nPyJjdXQiOiIraW5wdXQiKX07RmkoZS5kb2MseSksQ3QoZSwiaW5wdXRSZWFkIixlLHkpfXQmJiFhJiZlYShlLHQpLFFuKGUpLGUuY3VyT3AudXBkYXRlSW5wdXQ9bCxlLmN1ck9wLnR5cGluZz0hMCxlLnN0YXRlLnBhc3RlSW5jb21pbmc9ZS5zdGF0ZS5jdXRJbmNvbWluZz0hMX1mdW5jdGlvbiBabyhlLHQpe3ZhciBuPWUuY2xpcGJvYXJkRGF0YSYmZS5jbGlwYm9hcmREYXRhLmdldERhdGEoIlRleHQiKTtpZihuKXJldHVybiBlLnByZXZlbnREZWZhdWx0KCksdC5pc1JlYWRPbmx5KCl8fHQub3B0aW9ucy5kaXNhYmxlSW5wdXR8fGhyKHQsZnVuY3Rpb24oKXtyZXR1cm4gWG8odCxuLDAsbnVsbCwicGFzdGUiKX0pLCEwfWZ1bmN0aW9uIGVhKGUsdCl7aWYoZS5vcHRpb25zLmVsZWN0cmljQ2hhcnMmJmUub3B0aW9ucy5zbWFydEluZGVudClmb3IodmFyIG49ZS5kb2Muc2VsLHI9bi5yYW5nZXMubGVuZ3RoLTE7cj49MDtyLS0pe3ZhciBpPW4ucmFuZ2VzW3JdO2lmKCEoaS5oZWFkLmNoPjEwMHx8ciYmbi5yYW5nZXNbci0xXS5oZWFkLmxpbmU9PWkuaGVhZC5saW5lKSl7dmFyIG89ZS5nZXRNb2RlQXQoaS5oZWFkKSxhPSExO2lmKG8uZWxlY3RyaWNDaGFycyl7Zm9yKHZhciBzPTA7czxvLmVsZWN0cmljQ2hhcnMubGVuZ3RoO3MrKylpZih0LmluZGV4T2Yoby5lbGVjdHJpY0NoYXJzLmNoYXJBdChzKSk+LTEpe2E9Sm8oZSxpLmhlYWQubGluZSwic21hcnQiKTticmVha319ZWxzZSBvLmVsZWN0cmljSW5wdXQmJm8uZWxlY3RyaWNJbnB1dC50ZXN0KEEoZS5kb2MsaS5oZWFkLmxpbmUpLnRleHQuc2xpY2UoMCxpLmhlYWQuY2gpKSYmKGE9Sm8oZSxpLmhlYWQubGluZSwic21hcnQiKSk7YSYmQ3QoZSwiZWxlY3RyaWNJbnB1dCIsZSxpLmhlYWQubGluZSl9fX1mdW5jdGlvbiB0YShlKXtmb3IodmFyIHQ9W10sbj1bXSxyPTA7cjxlLmRvYy5zZWwucmFuZ2VzLmxlbmd0aDtyKyspe3ZhciBpPWUuZG9jLnNlbC5yYW5nZXNbcl0uaGVhZC5saW5lLG89e2FuY2hvcjpQKGksMCksaGVhZDpQKGkrMSwwKX07bi5wdXNoKG8pLHQucHVzaChlLmdldFJhbmdlKG8uYW5jaG9yLG8uaGVhZCkpfXJldHVybnt0ZXh0OnQscmFuZ2VzOm59fWZ1bmN0aW9uIG5hKGUsdCl7ZS5zZXRBdHRyaWJ1dGUoImF1dG9jb3JyZWN0Iiwib2ZmIiksZS5zZXRBdHRyaWJ1dGUoImF1dG9jYXBpdGFsaXplIiwib2ZmIiksZS5zZXRBdHRyaWJ1dGUoInNwZWxsY2hlY2siLCEhdCl9ZnVuY3Rpb24gcmEoKXt2YXIgZT1yKCJ0ZXh0YXJlYSIsbnVsbCxudWxsLCJwb3NpdGlvbjogYWJzb2x1dGU7IGJvdHRvbTogLTFlbTsgcGFkZGluZzogMDsgd2lkdGg6IDFweDsgaGVpZ2h0OiAxZW07IG91dGxpbmU6IG5vbmUiKSx0PXIoImRpdiIsW2VdLG51bGwsIm92ZXJmbG93OiBoaWRkZW47IHBvc2l0aW9uOiByZWxhdGl2ZTsgd2lkdGg6IDNweDsgaGVpZ2h0OiAwcHg7Iik7cmV0dXJuIENhP2Uuc3R5bGUud2lkdGg9IjEwMDBweCI6ZS5zZXRBdHRyaWJ1dGUoIndyYXAiLCJvZmYiKSxfYSYmKGUuc3R5bGUuYm9yZGVyPSIxcHggc29saWQgYmxhY2siKSxuYShlKSx0fWZ1bmN0aW9uIGlhKGUsdCxuLHIsaSl7ZnVuY3Rpb24gbygpe3ZhciByPXQubGluZStuO3JldHVybiEocjxlLmZpcnN0fHxyPj1lLmZpcnN0K2Uuc2l6ZSkmJih0PW5ldyBQKHIsdC5jaCx0LnN0aWNreSksYz1BKGUscikpfWZ1bmN0aW9uIGEocil7dmFyIGE7aWYobnVsbD09KGE9aT95byhlLmNtLGMsdCxuKTptbyhjLHQsbikpKXtpZihyfHwhbygpKXJldHVybiExO3Q9Z28oaSxlLmNtLGMsdC5saW5lLG4pfWVsc2UgdD1hO3JldHVybiEwfXZhciBzPXQsdT1uLGM9QShlLHQubGluZSk7aWYoImNoYXIiPT1yKWEoKTtlbHNlIGlmKCJjb2x1bW4iPT1yKWEoITApO2Vsc2UgaWYoIndvcmQiPT1yfHwiZ3JvdXAiPT1yKWZvcih2YXIgbD1udWxsLHA9Imdyb3VwIj09cixmPWUuY20mJmUuY20uZ2V0SGVscGVyKHQsIndvcmRDaGFycyIpLGQ9ITA7IShuPDApfHxhKCFkKTtkPSExKXt2YXIgaD1jLnRleHQuY2hhckF0KHQuY2gpfHwiXG4iLG09QyhoLGYpPyJ3IjpwJiYiXG4iPT1oPyJuIjohcHx8L1xzLy50ZXN0KGgpP251bGw6InAiO2lmKCFwfHxkfHxtfHwobT0icyIpLGwmJmwhPW0pe248MCYmKG49MSxhKCksdC5zdGlja3k9ImFmdGVyIik7YnJlYWt9aWYobSYmKGw9bSksbj4wJiYhYSghZCkpYnJlYWt9dmFyIGc9QWkoZSx0LHMsdSwhMCk7cmV0dXJuIGoocyxnKSYmKGcuaGl0U2lkZT0hMCksZ31mdW5jdGlvbiBvYShlLHQsbixyKXt2YXIgaSxvPWUuZG9jLGE9dC5sZWZ0O2lmKCJwYWdlIj09cil7dmFyIHM9TWF0aC5taW4oZS5kaXNwbGF5LndyYXBwZXIuY2xpZW50SGVpZ2h0LHdpbmRvdy5pbm5lckhlaWdodHx8ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodCksdT1NYXRoLm1heChzLS41KnhuKGUuZGlzcGxheSksMyk7aT0obj4wP3QuYm90dG9tOnQudG9wKStuKnV9ZWxzZSJsaW5lIj09ciYmKGk9bj4wP3QuYm90dG9tKzM6dC50b3AtMyk7Zm9yKHZhciBjO2M9ZG4oZSxhLGkpLGMub3V0c2lkZTspe2lmKG48MD9pPD0wOmk+PW8uaGVpZ2h0KXtjLmhpdFNpZGU9ITA7YnJlYWt9aSs9NSpufXJldHVybiBjfWZ1bmN0aW9uIGFhKGUsdCl7dmFyIG49V3QoZSx0LmxpbmUpO2lmKCFufHxuLmhpZGRlbilyZXR1cm4gbnVsbDt2YXIgcj1BKGUuZG9jLHQubGluZSksaT1WdChuLHIsdC5saW5lKSxvPXdlKHIsZS5kb2MuZGlyZWN0aW9uKSxhPSJsZWZ0IjtpZihvKXthPURlKG8sdC5jaCklMj8icmlnaHQiOiJsZWZ0In12YXIgcz1KdChpLm1hcCx0LmNoLGEpO3JldHVybiBzLm9mZnNldD0icmlnaHQiPT1zLmNvbGxhcHNlP3MuZW5kOnMuc3RhcnQsc31mdW5jdGlvbiBzYShlKXtmb3IodmFyIHQ9ZTt0O3Q9dC5wYXJlbnROb2RlKWlmKC9Db2RlTWlycm9yLWd1dHRlci13cmFwcGVyLy50ZXN0KHQuY2xhc3NOYW1lKSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiB1YShlLHQpe3JldHVybiB0JiYoZS5iYWQ9ITApLGV9ZnVuY3Rpb24gY2EoZSx0LG4scixpKXtmdW5jdGlvbiBvKGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gdC5pZD09ZX19ZnVuY3Rpb24gYSgpe2wmJihjKz1wLGYmJihjKz1wKSxsPWY9ITEpfWZ1bmN0aW9uIHMoZSl7ZSYmKGEoKSxjKz1lKX1mdW5jdGlvbiB1KHQpe2lmKDE9PXQubm9kZVR5cGUpe3ZhciBuPXQuZ2V0QXR0cmlidXRlKCJjbS10ZXh0Iik7aWYobilyZXR1cm4gdm9pZCBzKG4pO3ZhciBjLGQ9dC5nZXRBdHRyaWJ1dGUoImNtLW1hcmtlciIpO2lmKGQpe3ZhciBoPWUuZmluZE1hcmtzKFAociwwKSxQKGkrMSwwKSxvKCtkKSk7cmV0dXJuIHZvaWQoaC5sZW5ndGgmJihjPWhbMF0uZmluZCgwKSkmJnMoXyhlLmRvYyxjLmZyb20sYy50bykuam9pbihwKSkpfWlmKCJmYWxzZSI9PXQuZ2V0QXR0cmlidXRlKCJjb250ZW50ZWRpdGFibGUiKSlyZXR1cm47dmFyIG09L14ocHJlfGRpdnxwfGxpfHRhYmxlfGJyKSQvaS50ZXN0KHQubm9kZU5hbWUpO2lmKCEvXmJyJC9pLnRlc3QodC5ub2RlTmFtZSkmJjA9PXQudGV4dENvbnRlbnQubGVuZ3RoKXJldHVybjttJiZhKCk7Zm9yKHZhciBnPTA7Zzx0LmNoaWxkTm9kZXMubGVuZ3RoO2crKyl1KHQuY2hpbGROb2Rlc1tnXSk7L14ocHJlfHApJC9pLnRlc3QodC5ub2RlTmFtZSkmJihmPSEwKSxtJiYobD0hMCl9ZWxzZSAzPT10Lm5vZGVUeXBlJiZzKHQubm9kZVZhbHVlLnJlcGxhY2UoL1x1MjAwYi9nLCIiKS5yZXBsYWNlKC9cdTAwYTAvZywiICIpKX1mb3IodmFyIGM9IiIsbD0hMSxwPWUuZG9jLmxpbmVTZXBhcmF0b3IoKSxmPSExO3UodCksdCE9bjspdD10Lm5leHRTaWJsaW5nLGY9ITE7cmV0dXJuIGN9ZnVuY3Rpb24gbGEoZSx0LG4pe3ZhciByO2lmKHQ9PWUuZGlzcGxheS5saW5lRGl2KXtpZighKHI9ZS5kaXNwbGF5LmxpbmVEaXYuY2hpbGROb2Rlc1tuXSkpcmV0dXJuIHVhKGUuY2xpcFBvcyhQKGUuZGlzcGxheS52aWV3VG8tMSkpLCEwKTt0PW51bGwsbj0wfWVsc2UgZm9yKHI9dDs7cj1yLnBhcmVudE5vZGUpe2lmKCFyfHxyPT1lLmRpc3BsYXkubGluZURpdilyZXR1cm4gbnVsbDtpZihyLnBhcmVudE5vZGUmJnIucGFyZW50Tm9kZT09ZS5kaXNwbGF5LmxpbmVEaXYpYnJlYWt9Zm9yKHZhciBpPTA7aTxlLmRpc3BsYXkudmlldy5sZW5ndGg7aSsrKXt2YXIgbz1lLmRpc3BsYXkudmlld1tpXTtpZihvLm5vZGU9PXIpcmV0dXJuIHBhKG8sdCxuKX19ZnVuY3Rpb24gcGEoZSx0LG4pe2Z1bmN0aW9uIHIodCxuLHIpe2Zvcih2YXIgaT0tMTtpPChwP3AubGVuZ3RoOjApO2krKylmb3IodmFyIG89aTwwP2wubWFwOnBbaV0sYT0wO2E8by5sZW5ndGg7YSs9Myl7dmFyIHM9b1thKzJdO2lmKHM9PXR8fHM9PW4pe3ZhciB1PUYoaTwwP2UubGluZTplLnJlc3RbaV0pLGM9b1thXStyO3JldHVybihyPDB8fHMhPXQpJiYoYz1vW2ErKHI/MTowKV0pLFAodSxjKX19fXZhciBpPWUudGV4dC5maXJzdENoaWxkLGE9ITE7aWYoIXR8fCFvKGksdCkpcmV0dXJuIHVhKFAoRihlLmxpbmUpLDApLCEwKTtpZih0PT1pJiYoYT0hMCx0PWkuY2hpbGROb2Rlc1tuXSxuPTAsIXQpKXt2YXIgcz1lLnJlc3Q/bShlLnJlc3QpOmUubGluZTtyZXR1cm4gdWEoUChGKHMpLHMudGV4dC5sZW5ndGgpLGEpfXZhciB1PTM9PXQubm9kZVR5cGU/dDpudWxsLGM9dDtmb3IodXx8MSE9dC5jaGlsZE5vZGVzLmxlbmd0aHx8MyE9dC5maXJzdENoaWxkLm5vZGVUeXBlfHwodT10LmZpcnN0Q2hpbGQsbiYmKG49dS5ub2RlVmFsdWUubGVuZ3RoKSk7Yy5wYXJlbnROb2RlIT1pOyljPWMucGFyZW50Tm9kZTt2YXIgbD1lLm1lYXN1cmUscD1sLm1hcHMsZj1yKHUsYyxuKTtpZihmKXJldHVybiB1YShmLGEpO2Zvcih2YXIgZD1jLm5leHRTaWJsaW5nLGg9dT91Lm5vZGVWYWx1ZS5sZW5ndGgtbjowO2Q7ZD1kLm5leHRTaWJsaW5nKXtpZihmPXIoZCxkLmZpcnN0Q2hpbGQsMCkpcmV0dXJuIHVhKFAoZi5saW5lLGYuY2gtaCksYSk7aCs9ZC50ZXh0Q29udGVudC5sZW5ndGh9Zm9yKHZhciBnPWMucHJldmlvdXNTaWJsaW5nLHk9bjtnO2c9Zy5wcmV2aW91c1NpYmxpbmcpe2lmKGY9cihnLGcuZmlyc3RDaGlsZCwtMSkpcmV0dXJuIHVhKFAoZi5saW5lLGYuY2greSksYSk7eSs9Zy50ZXh0Q29udGVudC5sZW5ndGh9fWZ1bmN0aW9uIGZhKGUsdCl7ZnVuY3Rpb24gbigpe2UudmFsdWU9dS5nZXRWYWx1ZSgpfWlmKHQ9dD9sKHQpOnt9LHQudmFsdWU9ZS52YWx1ZSwhdC50YWJpbmRleCYmZS50YWJJbmRleCYmKHQudGFiaW5kZXg9ZS50YWJJbmRleCksIXQucGxhY2Vob2xkZXImJmUucGxhY2Vob2xkZXImJih0LnBsYWNlaG9sZGVyPWUucGxhY2Vob2xkZXIpLG51bGw9PXQuYXV0b2ZvY3VzKXt2YXIgcj1hKCk7dC5hdXRvZm9jdXM9cj09ZXx8bnVsbCE9ZS5nZXRBdHRyaWJ1dGUoImF1dG9mb2N1cyIpJiZyPT1kb2N1bWVudC5ib2R5fXZhciBpO2lmKGUuZm9ybSYmKG5zKGUuZm9ybSwic3VibWl0IixuKSwhdC5sZWF2ZVN1Ym1pdE1ldGhvZEFsb25lKSl7dmFyIG89ZS5mb3JtO2k9by5zdWJtaXQ7dHJ5e3ZhciBzPW8uc3VibWl0PWZ1bmN0aW9uKCl7bigpLG8uc3VibWl0PWksby5zdWJtaXQoKSxvLnN1Ym1pdD1zfX1jYXRjaChlKXt9fXQuZmluaXNoSW5pdD1mdW5jdGlvbih0KXt0LnNhdmU9bix0LmdldFRleHRBcmVhPWZ1bmN0aW9uKCl7cmV0dXJuIGV9LHQudG9UZXh0QXJlYT1mdW5jdGlvbigpe3QudG9UZXh0QXJlYT1pc05hTixuKCksZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHQuZ2V0V3JhcHBlckVsZW1lbnQoKSksZS5zdHlsZS5kaXNwbGF5PSIiLGUuZm9ybSYmKGtlKGUuZm9ybSwic3VibWl0IixuKSwiZnVuY3Rpb24iPT10eXBlb2YgZS5mb3JtLnN1Ym1pdCYmKGUuZm9ybS5zdWJtaXQ9aSkpfX0sZS5zdHlsZS5kaXNwbGF5PSJub25lIjt2YXIgdT1RbyhmdW5jdGlvbih0KXtyZXR1cm4gZS5wYXJlbnROb2RlLmluc2VydEJlZm9yZSh0LGUubmV4dFNpYmxpbmcpfSx0KTtyZXR1cm4gdX12YXIgZGE9bmF2aWdhdG9yLnVzZXJBZ2VudCxoYT1uYXZpZ2F0b3IucGxhdGZvcm0sbWE9L2dlY2tvXC9cZC9pLnRlc3QoZGEpLGdhPS9NU0lFIFxkLy50ZXN0KGRhKSx5YT0vVHJpZGVudFwvKD86WzctOV18XGR7Mix9KVwuLipydjooXGQrKS8uZXhlYyhkYSksdmE9L0VkZ2VcLyhcZCspLy5leGVjKGRhKSxiYT1nYXx8eWF8fHZhLHhhPWJhJiYoZ2E/ZG9jdW1lbnQuZG9jdW1lbnRNb2RlfHw2OisodmF8fHlhKVsxXSksQ2E9IXZhJiYvV2ViS2l0XC8vLnRlc3QoZGEpLEVhPUNhJiYvUXRcL1xkK1wuXGQrLy50ZXN0KGRhKSxEYT0hdmEmJi9DaHJvbWVcLy8udGVzdChkYSksd2E9L09wZXJhXC8vLnRlc3QoZGEpLFNhPS9BcHBsZSBDb21wdXRlci8udGVzdChuYXZpZ2F0b3IudmVuZG9yKSxrYT0vTWFjIE9TIFggMVxkXEQoWzgtOV18XGRcZClcRC8udGVzdChkYSksQWE9L1BoYW50b21KUy8udGVzdChkYSksX2E9IXZhJiYvQXBwbGVXZWJLaXQvLnRlc3QoZGEpJiYvTW9iaWxlXC9cdysvLnRlc3QoZGEpLFRhPS9BbmRyb2lkLy50ZXN0KGRhKSxPYT1fYXx8VGF8fC93ZWJPU3xCbGFja0JlcnJ5fE9wZXJhIE1pbml8T3BlcmEgTW9iaXxJRU1vYmlsZS9pLnRlc3QoZGEpLEZhPV9hfHwvTWFjLy50ZXN0KGhhKSxOYT0vXGJDck9TXGIvLnRlc3QoZGEpLElhPS93aW4vaS50ZXN0KGhhKSxMYT13YSYmZGEubWF0Y2goL1ZlcnNpb25cLyhcZCpcLlxkKikvKTtMYSYmKExhPU51bWJlcihMYVsxXSkpLExhJiZMYT49MTUmJih3YT0hMSxDYT0hMCk7dmFyIFBhLE1hPUZhJiYoRWF8fHdhJiYobnVsbD09TGF8fExhPDEyLjExKSksamE9bWF8fGJhJiZ4YT49OSxSYT1mdW5jdGlvbih0LG4pe3ZhciByPXQuY2xhc3NOYW1lLGk9ZShuKS5leGVjKHIpO2lmKGkpe3ZhciBvPXIuc2xpY2UoaS5pbmRleCtpWzBdLmxlbmd0aCk7dC5jbGFzc05hbWU9ci5zbGljZSgwLGkuaW5kZXgpKyhvP2lbMV0rbzoiIil9fTtQYT1kb2N1bWVudC5jcmVhdGVSYW5nZT9mdW5jdGlvbihlLHQsbixyKXt2YXIgaT1kb2N1bWVudC5jcmVhdGVSYW5nZSgpO3JldHVybiBpLnNldEVuZChyfHxlLG4pLGkuc2V0U3RhcnQoZSx0KSxpfTpmdW5jdGlvbihlLHQsbil7dmFyIHI9ZG9jdW1lbnQuYm9keS5jcmVhdGVUZXh0UmFuZ2UoKTt0cnl7ci5tb3ZlVG9FbGVtZW50VGV4dChlLnBhcmVudE5vZGUpfWNhdGNoKGUpe3JldHVybiByfXJldHVybiByLmNvbGxhcHNlKCEwKSxyLm1vdmVFbmQoImNoYXJhY3RlciIsbiksci5tb3ZlU3RhcnQoImNoYXJhY3RlciIsdCkscn07dmFyIEJhPWZ1bmN0aW9uKGUpe2Uuc2VsZWN0KCl9O19hP0JhPWZ1bmN0aW9uKGUpe2Uuc2VsZWN0aW9uU3RhcnQ9MCxlLnNlbGVjdGlvbkVuZD1lLnZhbHVlLmxlbmd0aH06YmEmJihCYT1mdW5jdGlvbihlKXt0cnl7ZS5zZWxlY3QoKX1jYXRjaChlKXt9fSk7dmFyICRhPWZ1bmN0aW9uKCl7dGhpcy5pZD1udWxsfTskYS5wcm90b3R5cGUuc2V0PWZ1bmN0aW9uKGUsdCl7Y2xlYXJUaW1lb3V0KHRoaXMuaWQpLHRoaXMuaWQ9c2V0VGltZW91dCh0LGUpfTt2YXIgVWEsemEsR2E9MzAsVmE9e3RvU3RyaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIkNvZGVNaXJyb3IuUGFzcyJ9fSxxYT17c2Nyb2xsOiExfSxIYT17b3JpZ2luOiIqbW91c2UifSxXYT17b3JpZ2luOiIrbW92ZSJ9LFFhPVsiIl0sS2E9L1tcdTAwZGZcdTA1ODdcdTA1OTAtXHUwNWY0XHUwNjAwLVx1MDZmZlx1MzA0MC1cdTMwOWZcdTMwYTAtXHUzMGZmXHUzNDAwLVx1NGRiNVx1NGUwMC1cdTlmY2NcdWFjMDAtXHVkN2FmXS8sSmE9L1tcdTAzMDAtXHUwMzZmXHUwNDgzLVx1MDQ4OVx1MDU5MS1cdTA1YmRcdTA1YmZcdTA1YzFcdTA1YzJcdTA1YzRcdTA1YzVcdTA1YzdcdTA2MTAtXHUwNjFhXHUwNjRiLVx1MDY1ZVx1MDY3MFx1MDZkNi1cdTA2ZGNcdTA2ZGUtXHUwNmU0XHUwNmU3XHUwNmU4XHUwNmVhLVx1MDZlZFx1MDcxMVx1MDczMC1cdTA3NGFcdTA3YTYtXHUwN2IwXHUwN2ViLVx1MDdmM1x1MDgxNi1cdTA4MTlcdTA4MWItXHUwODIzXHUwODI1LVx1MDgyN1x1MDgyOS1cdTA4MmRcdTA5MDAtXHUwOTAyXHUwOTNjXHUwOTQxLVx1MDk0OFx1MDk0ZFx1MDk1MS1cdTA5NTVcdTA5NjJcdTA5NjNcdTA5ODFcdTA5YmNcdTA5YmVcdTA5YzEtXHUwOWM0XHUwOWNkXHUwOWQ3XHUwOWUyXHUwOWUzXHUwYTAxXHUwYTAyXHUwYTNjXHUwYTQxXHUwYTQyXHUwYTQ3XHUwYTQ4XHUwYTRiLVx1MGE0ZFx1MGE1MVx1MGE3MFx1MGE3MVx1MGE3NVx1MGE4MVx1MGE4Mlx1MGFiY1x1MGFjMS1cdTBhYzVcdTBhYzdcdTBhYzhcdTBhY2RcdTBhZTJcdTBhZTNcdTBiMDFcdTBiM2NcdTBiM2VcdTBiM2ZcdTBiNDEtXHUwYjQ0XHUwYjRkXHUwYjU2XHUwYjU3XHUwYjYyXHUwYjYzXHUwYjgyXHUwYmJlXHUwYmMwXHUwYmNkXHUwYmQ3XHUwYzNlLVx1MGM0MFx1MGM0Ni1cdTBjNDhcdTBjNGEtXHUwYzRkXHUwYzU1XHUwYzU2XHUwYzYyXHUwYzYzXHUwY2JjXHUwY2JmXHUwY2MyXHUwY2M2XHUwY2NjXHUwY2NkXHUwY2Q1XHUwY2Q2XHUwY2UyXHUwY2UzXHUwZDNlXHUwZDQxLVx1MGQ0NFx1MGQ0ZFx1MGQ1N1x1MGQ2Mlx1MGQ2M1x1MGRjYVx1MGRjZlx1MGRkMi1cdTBkZDRcdTBkZDZcdTBkZGZcdTBlMzFcdTBlMzQtXHUwZTNhXHUwZTQ3LVx1MGU0ZVx1MGViMVx1MGViNC1cdTBlYjlcdTBlYmJcdTBlYmNcdTBlYzgtXHUwZWNkXHUwZjE4XHUwZjE5XHUwZjM1XHUwZjM3XHUwZjM5XHUwZjcxLVx1MGY3ZVx1MGY4MC1cdTBmODRcdTBmODZcdTBmODdcdTBmOTAtXHUwZjk3XHUwZjk5LVx1MGZiY1x1MGZjNlx1MTAyZC1cdTEwMzBcdTEwMzItXHUxMDM3XHUxMDM5XHUxMDNhXHUxMDNkXHUxMDNlXHUxMDU4XHUxMDU5XHUxMDVlLVx1MTA2MFx1MTA3MS1cdTEwNzRcdTEwODJcdTEwODVcdTEwODZcdTEwOGRcdTEwOWRcdTEzNWZcdTE3MTItXHUxNzE0XHUxNzMyLVx1MTczNFx1MTc1Mlx1MTc1M1x1MTc3Mlx1MTc3M1x1MTdiNy1cdTE3YmRcdTE3YzZcdTE3YzktXHUxN2QzXHUxN2RkXHUxODBiLVx1MTgwZFx1MThhOVx1MTkyMC1cdTE5MjJcdTE5MjdcdTE5MjhcdTE5MzJcdTE5MzktXHUxOTNiXHUxYTE3XHUxYTE4XHUxYTU2XHUxYTU4LVx1MWE1ZVx1MWE2MFx1MWE2Mlx1MWE2NS1cdTFhNmNcdTFhNzMtXHUxYTdjXHUxYTdmXHUxYjAwLVx1MWIwM1x1MWIzNFx1MWIzNi1cdTFiM2FcdTFiM2NcdTFiNDJcdTFiNmItXHUxYjczXHUxYjgwXHUxYjgxXHUxYmEyLVx1MWJhNVx1MWJhOFx1MWJhOVx1MWMyYy1cdTFjMzNcdTFjMzZcdTFjMzdcdTFjZDAtXHUxY2QyXHUxY2Q0LVx1MWNlMFx1MWNlMi1cdTFjZThcdTFjZWRcdTFkYzAtXHUxZGU2XHUxZGZkLVx1MWRmZlx1MjAwY1x1MjAwZFx1MjBkMC1cdTIwZjBcdTJjZWYtXHUyY2YxXHUyZGUwLVx1MmRmZlx1MzAyYS1cdTMwMmZcdTMwOTlcdTMwOWFcdWE2NmYtXHVhNjcyXHVhNjdjXHVhNjdkXHVhNmYwXHVhNmYxXHVhODAyXHVhODA2XHVhODBiXHVhODI1XHVhODI2XHVhOGM0XHVhOGUwLVx1YThmMVx1YTkyNi1cdWE5MmRcdWE5NDctXHVhOTUxXHVhOTgwLVx1YTk4Mlx1YTliM1x1YTliNi1cdWE5YjlcdWE5YmNcdWFhMjktXHVhYTJlXHVhYTMxXHVhYTMyXHVhYTM1XHVhYTM2XHVhYTQzXHVhYTRjXHVhYWIwXHVhYWIyLVx1YWFiNFx1YWFiN1x1YWFiOFx1YWFiZVx1YWFiZlx1YWFjMVx1YWJlNVx1YWJlOFx1YWJlZFx1ZGMwMC1cdWRmZmZcdWZiMWVcdWZlMDAtXHVmZTBmXHVmZTIwLVx1ZmUyNlx1ZmY5ZVx1ZmY5Zl0vLFlhPSExLFhhPSExLFphPW51bGwsZXM9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3JldHVybiBlPD0yNDc/bi5jaGFyQXQoZSk6MTQyNDw9ZSYmZTw9MTUyND8iUiI6MTUzNjw9ZSYmZTw9MTc4NT9yLmNoYXJBdChlLTE1MzYpOjE3NzQ8PWUmJmU8PTIyMjA/InIiOjgxOTI8PWUmJmU8PTgyMDM/InciOjgyMDQ9PWU/ImIiOiJMIn1mdW5jdGlvbiB0KGUsdCxuKXt0aGlzLmxldmVsPWUsdGhpcy5mcm9tPXQsdGhpcy50bz1ufXZhciBuPSJiYmJiYmJiYmJ0c3R3c2JiYmJiYmJiYmJiYmJic3NzdHdOTiUlJU5OTk5OTixOLE4xMTExMTExMTExTk5OTk5OTkxMTExMTExMTExMTExMTExMTExMTExMTExMTk5OTk5OTExMTExMTExMTExMTExMTExMTExMTExMTExOTk5OYmJiYmJic2JiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiLE4lJSUlTk5OTkxOTk5OTiUlMTFOTE5OTjFMTk5OTk5MTExMTExMTExMTExMTExMTExMTExMTE5MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTiIscj0ibm5ubm5uTk5yJSVyLHJOTm1tbW1tbW1tbW1tcnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJybW1tbW1tbW1tbW1tbW1tbW1tbW1tbm5ubm5ubm5ubiVubnJycm1ycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycm1tbW1tbW1uTm1tbW1tbXJybW1ObW1tbXJyMTExMTExMTExMSIsaT0vW1x1MDU5MC1cdTA1ZjRcdTA2MDAtXHUwNmZmXHUwNzAwLVx1MDhhY10vLG89L1tzdHdOXS8sYT0vW0xScl0vLHM9L1tMYjFuXS8sdT0vWzFuXS87cmV0dXJuIGZ1bmN0aW9uKG4scil7dmFyIGM9Imx0ciI9PXI/IkwiOiJSIjtpZigwPT1uLmxlbmd0aHx8Imx0ciI9PXImJiFpLnRlc3QobikpcmV0dXJuITE7Zm9yKHZhciBsPW4ubGVuZ3RoLHA9W10sZj0wO2Y8bDsrK2YpcC5wdXNoKGUobi5jaGFyQ29kZUF0KGYpKSk7Zm9yKHZhciBkPTAsaD1jO2Q8bDsrK2Qpe3ZhciBnPXBbZF07Im0iPT1nP3BbZF09aDpoPWd9Zm9yKHZhciB5PTAsdj1jO3k8bDsrK3kpe3ZhciBiPXBbeV07IjEiPT1iJiYiciI9PXY/cFt5XT0ibiI6YS50ZXN0KGIpJiYodj1iLCJyIj09YiYmKHBbeV09IlIiKSl9Zm9yKHZhciB4PTEsQz1wWzBdO3g8bC0xOysreCl7dmFyIEU9cFt4XTsiKyI9PUUmJiIxIj09QyYmIjEiPT1wW3grMV0/cFt4XT0iMSI6IiwiIT1FfHxDIT1wW3grMV18fCIxIiE9QyYmIm4iIT1DfHwocFt4XT1DKSxDPUV9Zm9yKHZhciBEPTA7RDxsOysrRCl7dmFyIHc9cFtEXTtpZigiLCI9PXcpcFtEXT0iTiI7ZWxzZSBpZigiJSI9PXcpe3ZhciBTPXZvaWQgMDtmb3IoUz1EKzE7UzxsJiYiJSI9PXBbU107KytTKTtmb3IodmFyIGs9RCYmIiEiPT1wW0QtMV18fFM8bCYmIjEiPT1wW1NdPyIxIjoiTiIsQT1EO0E8UzsrK0EpcFtBXT1rO0Q9Uy0xfX1mb3IodmFyIF89MCxUPWM7XzxsOysrXyl7dmFyIE89cFtfXTsiTCI9PVQmJiIxIj09Tz9wW19dPSJMIjphLnRlc3QoTykmJihUPU8pfWZvcih2YXIgRj0wO0Y8bDsrK0YpaWYoby50ZXN0KHBbRl0pKXt2YXIgTj12b2lkIDA7Zm9yKE49RisxO048bCYmby50ZXN0KHBbTl0pOysrTik7Zm9yKHZhciBJPSJMIj09KEY/cFtGLTFdOmMpLEw9IkwiPT0oTjxsP3BbTl06YyksUD1JPT1MP0k/IkwiOiJSIjpjLE09RjtNPE47KytNKXBbTV09UDtGPU4tMX1mb3IodmFyIGosUj1bXSxCPTA7QjxsOylpZihzLnRlc3QocFtCXSkpe3ZhciAkPUI7Zm9yKCsrQjtCPGwmJnMudGVzdChwW0JdKTsrK0IpO1IucHVzaChuZXcgdCgwLCQsQikpfWVsc2V7dmFyIFU9Qix6PVIubGVuZ3RoO2ZvcigrK0I7QjxsJiYiTCIhPXBbQl07KytCKTtmb3IodmFyIEc9VTtHPEI7KWlmKHUudGVzdChwW0ddKSl7VTxHJiZSLnNwbGljZSh6LDAsbmV3IHQoMSxVLEcpKTt2YXIgVj1HO2ZvcigrK0c7RzxCJiZ1LnRlc3QocFtHXSk7KytHKTtSLnNwbGljZSh6LDAsbmV3IHQoMixWLEcpKSxVPUd9ZWxzZSsrRztVPEImJlIuc3BsaWNlKHosMCxuZXcgdCgxLFUsQikpfXJldHVybiJsdHIiPT1yJiYoMT09UlswXS5sZXZlbCYmKGo9bi5tYXRjaCgvXlxzKy8pKSYmKFJbMF0uZnJvbT1qWzBdLmxlbmd0aCxSLnVuc2hpZnQobmV3IHQoMCwwLGpbMF0ubGVuZ3RoKSkpLDE9PW0oUikubGV2ZWwmJihqPW4ubWF0Y2goL1xzKyQvKSkmJihtKFIpLnRvLT1qWzBdLmxlbmd0aCxSLnB1c2gobmV3IHQoMCxsLWpbMF0ubGVuZ3RoLGwpKSkpLCJydGwiPT1yP1IucmV2ZXJzZSgpOlJ9fSgpLHRzPVtdLG5zPWZ1bmN0aW9uKGUsdCxuKXtpZihlLmFkZEV2ZW50TGlzdGVuZXIpZS5hZGRFdmVudExpc3RlbmVyKHQsbiwhMSk7ZWxzZSBpZihlLmF0dGFjaEV2ZW50KWUuYXR0YWNoRXZlbnQoIm9uIit0LG4pO2Vsc2V7dmFyIHI9ZS5faGFuZGxlcnN8fChlLl9oYW5kbGVycz17fSk7clt0XT0oclt0XXx8dHMpLmNvbmNhdChuKX19LHJzPWZ1bmN0aW9uKCl7aWYoYmEmJnhhPDkpcmV0dXJuITE7dmFyIGU9cigiZGl2Iik7cmV0dXJuImRyYWdnYWJsZSJpbiBlfHwiZHJhZ0Ryb3AiaW4gZX0oKSxpcz0zIT0iXG5cbmIiLnNwbGl0KC9cbi8pLmxlbmd0aD9mdW5jdGlvbihlKXtmb3IodmFyIHQ9MCxuPVtdLHI9ZS5sZW5ndGg7dDw9cjspe3ZhciBpPWUuaW5kZXhPZigiXG4iLHQpOy0xPT1pJiYoaT1lLmxlbmd0aCk7dmFyIG89ZS5zbGljZSh0LCJcciI9PWUuY2hhckF0KGktMSk/aS0xOmkpLGE9by5pbmRleE9mKCJcciIpOy0xIT1hPyhuLnB1c2goby5zbGljZSgwLGEpKSx0Kz1hKzEpOihuLnB1c2gobyksdD1pKzEpfXJldHVybiBufTpmdW5jdGlvbihlKXtyZXR1cm4gZS5zcGxpdCgvXHJcbj98XG4vKX0sb3M9d2luZG93LmdldFNlbGVjdGlvbj9mdW5jdGlvbihlKXt0cnl7cmV0dXJuIGUuc2VsZWN0aW9uU3RhcnQhPWUuc2VsZWN0aW9uRW5kfWNhdGNoKGUpe3JldHVybiExfX06ZnVuY3Rpb24oZSl7dmFyIHQ7dHJ5e3Q9ZS5vd25lckRvY3VtZW50LnNlbGVjdGlvbi5jcmVhdGVSYW5nZSgpfWNhdGNoKGUpe31yZXR1cm4hKCF0fHx0LnBhcmVudEVsZW1lbnQoKSE9ZSkmJjAhPXQuY29tcGFyZUVuZFBvaW50cygiU3RhcnRUb0VuZCIsdCl9LGFzPWZ1bmN0aW9uKCl7dmFyIGU9cigiZGl2Iik7cmV0dXJuIm9uY29weSJpbiBlfHwoZS5zZXRBdHRyaWJ1dGUoIm9uY29weSIsInJldHVybjsiKSwiZnVuY3Rpb24iPT10eXBlb2YgZS5vbmNvcHkpfSgpLHNzPW51bGwsdXM9e30sY3M9e30sbHM9e30scHM9ZnVuY3Rpb24oZSx0LG4pe3RoaXMucG9zPXRoaXMuc3RhcnQ9MCx0aGlzLnN0cmluZz1lLHRoaXMudGFiU2l6ZT10fHw4LHRoaXMubGFzdENvbHVtblBvcz10aGlzLmxhc3RDb2x1bW5WYWx1ZT0wLHRoaXMubGluZVN0YXJ0PTAsdGhpcy5saW5lT3JhY2xlPW59O3BzLnByb3RvdHlwZS5lb2w9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5wb3M+PXRoaXMuc3RyaW5nLmxlbmd0aH0scHMucHJvdG90eXBlLnNvbD1mdW5jdGlvbigpe3JldHVybiB0aGlzLnBvcz09dGhpcy5saW5lU3RhcnR9LHBzLnByb3RvdHlwZS5wZWVrPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc3RyaW5nLmNoYXJBdCh0aGlzLnBvcyl8fHZvaWQgMH0scHMucHJvdG90eXBlLm5leHQ9ZnVuY3Rpb24oKXtpZih0aGlzLnBvczx0aGlzLnN0cmluZy5sZW5ndGgpcmV0dXJuIHRoaXMuc3RyaW5nLmNoYXJBdCh0aGlzLnBvcysrKX0scHMucHJvdG90eXBlLmVhdD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLnN0cmluZy5jaGFyQXQodGhpcy5wb3MpO2lmKCJzdHJpbmciPT10eXBlb2YgZT90PT1lOnQmJihlLnRlc3Q/ZS50ZXN0KHQpOmUodCkpKXJldHVybisrdGhpcy5wb3MsdH0scHMucHJvdG90eXBlLmVhdFdoaWxlPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD10aGlzLnBvczt0aGlzLmVhdChlKTspO3JldHVybiB0aGlzLnBvcz50fSxwcy5wcm90b3R5cGUuZWF0U3BhY2U9ZnVuY3Rpb24oKXtmb3IodmFyIGU9dGhpcyx0PXRoaXMucG9zOy9bXHNcdTAwYTBdLy50ZXN0KHRoaXMuc3RyaW5nLmNoYXJBdCh0aGlzLnBvcykpOykrK2UucG9zO3JldHVybiB0aGlzLnBvcz50fSxwcy5wcm90b3R5cGUuc2tpcFRvRW5kPWZ1bmN0aW9uKCl7dGhpcy5wb3M9dGhpcy5zdHJpbmcubGVuZ3RofSxwcy5wcm90b3R5cGUuc2tpcFRvPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuc3RyaW5nLmluZGV4T2YoZSx0aGlzLnBvcyk7aWYodD4tMSlyZXR1cm4gdGhpcy5wb3M9dCwhMH0scHMucHJvdG90eXBlLmJhY2tVcD1mdW5jdGlvbihlKXt0aGlzLnBvcy09ZX0scHMucHJvdG90eXBlLmNvbHVtbj1mdW5jdGlvbigpe3JldHVybiB0aGlzLmxhc3RDb2x1bW5Qb3M8dGhpcy5zdGFydCYmKHRoaXMubGFzdENvbHVtblZhbHVlPXAodGhpcy5zdHJpbmcsdGhpcy5zdGFydCx0aGlzLnRhYlNpemUsdGhpcy5sYXN0Q29sdW1uUG9zLHRoaXMubGFzdENvbHVtblZhbHVlKSx0aGlzLmxhc3RDb2x1bW5Qb3M9dGhpcy5zdGFydCksdGhpcy5sYXN0Q29sdW1uVmFsdWUtKHRoaXMubGluZVN0YXJ0P3AodGhpcy5zdHJpbmcsdGhpcy5saW5lU3RhcnQsdGhpcy50YWJTaXplKTowKX0scHMucHJvdG90eXBlLmluZGVudGF0aW9uPWZ1bmN0aW9uKCl7cmV0dXJuIHAodGhpcy5zdHJpbmcsbnVsbCx0aGlzLnRhYlNpemUpLSh0aGlzLmxpbmVTdGFydD9wKHRoaXMuc3RyaW5nLHRoaXMubGluZVN0YXJ0LHRoaXMudGFiU2l6ZSk6MCl9LHBzLnByb3RvdHlwZS5tYXRjaD1mdW5jdGlvbihlLHQsbil7aWYoInN0cmluZyIhPXR5cGVvZiBlKXt2YXIgcj10aGlzLnN0cmluZy5zbGljZSh0aGlzLnBvcykubWF0Y2goZSk7cmV0dXJuIHImJnIuaW5kZXg+MD9udWxsOihyJiYhMSE9PXQmJih0aGlzLnBvcys9clswXS5sZW5ndGgpLHIpfXZhciBpPWZ1bmN0aW9uKGUpe3JldHVybiBuP2UudG9Mb3dlckNhc2UoKTplfTtpZihpKHRoaXMuc3RyaW5nLnN1YnN0cih0aGlzLnBvcyxlLmxlbmd0aCkpPT1pKGUpKXJldHVybiExIT09dCYmKHRoaXMucG9zKz1lLmxlbmd0aCksITB9LHBzLnByb3RvdHlwZS5jdXJyZW50PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc3RyaW5nLnNsaWNlKHRoaXMuc3RhcnQsdGhpcy5wb3MpfSxwcy5wcm90b3R5cGUuaGlkZUZpcnN0Q2hhcnM9ZnVuY3Rpb24oZSx0KXt0aGlzLmxpbmVTdGFydCs9ZTt0cnl7cmV0dXJuIHQoKX1maW5hbGx5e3RoaXMubGluZVN0YXJ0LT1lfX0scHMucHJvdG90eXBlLmxvb2tBaGVhZD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLmxpbmVPcmFjbGU7cmV0dXJuIHQmJnQubG9va0FoZWFkKGUpfSxwcy5wcm90b3R5cGUuYmFzZVRva2VuPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5saW5lT3JhY2xlO3JldHVybiBlJiZlLmJhc2VUb2tlbih0aGlzLnBvcyl9O3ZhciBmcz1mdW5jdGlvbihlLHQpe3RoaXMuc3RhdGU9ZSx0aGlzLmxvb2tBaGVhZD10fSxkcz1mdW5jdGlvbihlLHQsbixyKXt0aGlzLnN0YXRlPXQsdGhpcy5kb2M9ZSx0aGlzLmxpbmU9bix0aGlzLm1heExvb2tBaGVhZD1yfHwwLHRoaXMuYmFzZVRva2Vucz1udWxsLHRoaXMuYmFzZVRva2VuUG9zPTF9O2RzLnByb3RvdHlwZS5sb29rQWhlYWQ9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5kb2MuZ2V0TGluZSh0aGlzLmxpbmUrZSk7cmV0dXJuIG51bGwhPXQmJmU+dGhpcy5tYXhMb29rQWhlYWQmJih0aGlzLm1heExvb2tBaGVhZD1lKSx0fSxkcy5wcm90b3R5cGUuYmFzZVRva2VuPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7aWYoIXRoaXMuYmFzZVRva2VucylyZXR1cm4gbnVsbDtmb3IoO3RoaXMuYmFzZVRva2Vuc1t0aGlzLmJhc2VUb2tlblBvc108PWU7KXQuYmFzZVRva2VuUG9zKz0yO3ZhciBuPXRoaXMuYmFzZVRva2Vuc1t0aGlzLmJhc2VUb2tlblBvcysxXTtyZXR1cm57dHlwZTpuJiZuLnJlcGxhY2UoLyggfF4pb3ZlcmxheSAuKi8sIiIpLHNpemU6dGhpcy5iYXNlVG9rZW5zW3RoaXMuYmFzZVRva2VuUG9zXS1lfX0sZHMucHJvdG90eXBlLm5leHRMaW5lPWZ1bmN0aW9uKCl7dGhpcy5saW5lKyssdGhpcy5tYXhMb29rQWhlYWQ+MCYmdGhpcy5tYXhMb29rQWhlYWQtLX0sZHMuZnJvbVNhdmVkPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gdCBpbnN0YW5jZW9mIGZzP25ldyBkcyhlLEhlKGUubW9kZSx0LnN0YXRlKSxuLHQubG9va0FoZWFkKTpuZXcgZHMoZSxIZShlLm1vZGUsdCksbil9LGRzLnByb3RvdHlwZS5zYXZlPWZ1bmN0aW9uKGUpe3ZhciB0PSExIT09ZT9IZSh0aGlzLmRvYy5tb2RlLHRoaXMuc3RhdGUpOnRoaXMuc3RhdGU7cmV0dXJuIHRoaXMubWF4TG9va0FoZWFkPjA/bmV3IGZzKHQsdGhpcy5tYXhMb29rQWhlYWQpOnR9O3ZhciBocz1mdW5jdGlvbihlLHQsbil7dGhpcy5zdGFydD1lLnN0YXJ0LHRoaXMuZW5kPWUucG9zLHRoaXMuc3RyaW5nPWUuY3VycmVudCgpLHRoaXMudHlwZT10fHxudWxsLHRoaXMuc3RhdGU9bn0sbXM9ZnVuY3Rpb24oZSx0LG4pe3RoaXMudGV4dD1lLHJlKHRoaXMsdCksdGhpcy5oZWlnaHQ9bj9uKHRoaXMpOjF9O21zLnByb3RvdHlwZS5saW5lTm89ZnVuY3Rpb24oKXtyZXR1cm4gRih0aGlzKX0sRmUobXMpO3ZhciBncyx5cz17fSx2cz17fSxicz1udWxsLHhzPW51bGwsQ3M9e2xlZnQ6MCxyaWdodDowLHRvcDowLGJvdHRvbTowfSxFcz1mdW5jdGlvbihlLHQsbil7dGhpcy5jbT1uO3ZhciBpPXRoaXMudmVydD1yKCJkaXYiLFtyKCJkaXYiLG51bGwsbnVsbCwibWluLXdpZHRoOiAxcHgiKV0sIkNvZGVNaXJyb3ItdnNjcm9sbGJhciIpLG89dGhpcy5ob3Jpej1yKCJkaXYiLFtyKCJkaXYiLG51bGwsbnVsbCwiaGVpZ2h0OiAxMDAlOyBtaW4taGVpZ2h0OiAxcHgiKV0sIkNvZGVNaXJyb3ItaHNjcm9sbGJhciIpO2kudGFiSW5kZXg9by50YWJJbmRleD0tMSxlKGkpLGUobyksbnMoaSwic2Nyb2xsIixmdW5jdGlvbigpe2kuY2xpZW50SGVpZ2h0JiZ0KGkuc2Nyb2xsVG9wLCJ2ZXJ0aWNhbCIpfSksbnMobywic2Nyb2xsIixmdW5jdGlvbigpe28uY2xpZW50V2lkdGgmJnQoby5zY3JvbGxMZWZ0LCJob3Jpem9udGFsIil9KSx0aGlzLmNoZWNrZWRaZXJvV2lkdGg9ITEsYmEmJnhhPDgmJih0aGlzLmhvcml6LnN0eWxlLm1pbkhlaWdodD10aGlzLnZlcnQuc3R5bGUubWluV2lkdGg9IjE4cHgiKX07RXMucHJvdG90eXBlLnVwZGF0ZT1mdW5jdGlvbihlKXt2YXIgdD1lLnNjcm9sbFdpZHRoPmUuY2xpZW50V2lkdGgrMSxuPWUuc2Nyb2xsSGVpZ2h0PmUuY2xpZW50SGVpZ2h0KzEscj1lLm5hdGl2ZUJhcldpZHRoO2lmKG4pe3RoaXMudmVydC5zdHlsZS5kaXNwbGF5PSJibG9jayIsdGhpcy52ZXJ0LnN0eWxlLmJvdHRvbT10P3IrInB4IjoiMCI7dmFyIGk9ZS52aWV3SGVpZ2h0LSh0P3I6MCk7dGhpcy52ZXJ0LmZpcnN0Q2hpbGQuc3R5bGUuaGVpZ2h0PU1hdGgubWF4KDAsZS5zY3JvbGxIZWlnaHQtZS5jbGllbnRIZWlnaHQraSkrInB4In1lbHNlIHRoaXMudmVydC5zdHlsZS5kaXNwbGF5PSIiLHRoaXMudmVydC5maXJzdENoaWxkLnN0eWxlLmhlaWdodD0iMCI7aWYodCl7dGhpcy5ob3Jpei5zdHlsZS5kaXNwbGF5PSJibG9jayIsdGhpcy5ob3Jpei5zdHlsZS5yaWdodD1uP3IrInB4IjoiMCIsdGhpcy5ob3Jpei5zdHlsZS5sZWZ0PWUuYmFyTGVmdCsicHgiO3ZhciBvPWUudmlld1dpZHRoLWUuYmFyTGVmdC0obj9yOjApO3RoaXMuaG9yaXouZmlyc3RDaGlsZC5zdHlsZS53aWR0aD1NYXRoLm1heCgwLGUuc2Nyb2xsV2lkdGgtZS5jbGllbnRXaWR0aCtvKSsicHgifWVsc2UgdGhpcy5ob3Jpei5zdHlsZS5kaXNwbGF5PSIiLHRoaXMuaG9yaXouZmlyc3RDaGlsZC5zdHlsZS53aWR0aD0iMCI7cmV0dXJuIXRoaXMuY2hlY2tlZFplcm9XaWR0aCYmZS5jbGllbnRIZWlnaHQ+MCYmKDA9PXImJnRoaXMuemVyb1dpZHRoSGFjaygpLHRoaXMuY2hlY2tlZFplcm9XaWR0aD0hMCkse3JpZ2h0Om4/cjowLGJvdHRvbTp0P3I6MH19LEVzLnByb3RvdHlwZS5zZXRTY3JvbGxMZWZ0PWZ1bmN0aW9uKGUpe3RoaXMuaG9yaXouc2Nyb2xsTGVmdCE9ZSYmKHRoaXMuaG9yaXouc2Nyb2xsTGVmdD1lKSx0aGlzLmRpc2FibGVIb3JpeiYmdGhpcy5lbmFibGVaZXJvV2lkdGhCYXIodGhpcy5ob3Jpeix0aGlzLmRpc2FibGVIb3JpeiwiaG9yaXoiKX0sRXMucHJvdG90eXBlLnNldFNjcm9sbFRvcD1mdW5jdGlvbihlKXt0aGlzLnZlcnQuc2Nyb2xsVG9wIT1lJiYodGhpcy52ZXJ0LnNjcm9sbFRvcD1lKSx0aGlzLmRpc2FibGVWZXJ0JiZ0aGlzLmVuYWJsZVplcm9XaWR0aEJhcih0aGlzLnZlcnQsdGhpcy5kaXNhYmxlVmVydCwidmVydCIpfSxFcy5wcm90b3R5cGUuemVyb1dpZHRoSGFjaz1mdW5jdGlvbigpe3ZhciBlPUZhJiYha2E/IjEycHgiOiIxOHB4Ijt0aGlzLmhvcml6LnN0eWxlLmhlaWdodD10aGlzLnZlcnQuc3R5bGUud2lkdGg9ZSx0aGlzLmhvcml6LnN0eWxlLnBvaW50ZXJFdmVudHM9dGhpcy52ZXJ0LnN0eWxlLnBvaW50ZXJFdmVudHM9Im5vbmUiLHRoaXMuZGlzYWJsZUhvcml6PW5ldyAkYSx0aGlzLmRpc2FibGVWZXJ0PW5ldyAkYX0sRXMucHJvdG90eXBlLmVuYWJsZVplcm9XaWR0aEJhcj1mdW5jdGlvbihlLHQsbil7ZnVuY3Rpb24gcigpe3ZhciBpPWUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7KCJ2ZXJ0Ij09bj9kb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KGkucmlnaHQtMSwoaS50b3AraS5ib3R0b20pLzIpOmRvY3VtZW50LmVsZW1lbnRGcm9tUG9pbnQoKGkucmlnaHQraS5sZWZ0KS8yLGkuYm90dG9tLTEpKSE9ZT9lLnN0eWxlLnBvaW50ZXJFdmVudHM9Im5vbmUiOnQuc2V0KDFlMyxyKX1lLnN0eWxlLnBvaW50ZXJFdmVudHM9ImF1dG8iLHQuc2V0KDFlMyxyKX0sRXMucHJvdG90eXBlLmNsZWFyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5ob3Jpei5wYXJlbnROb2RlO2UucmVtb3ZlQ2hpbGQodGhpcy5ob3JpeiksZS5yZW1vdmVDaGlsZCh0aGlzLnZlcnQpfTt2YXIgRHM9ZnVuY3Rpb24oKXt9O0RzLnByb3RvdHlwZS51cGRhdGU9ZnVuY3Rpb24oKXtyZXR1cm57Ym90dG9tOjAscmlnaHQ6MH19LERzLnByb3RvdHlwZS5zZXRTY3JvbGxMZWZ0PWZ1bmN0aW9uKCl7fSxEcy5wcm90b3R5cGUuc2V0U2Nyb2xsVG9wPWZ1bmN0aW9uKCl7fSxEcy5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXt9O3ZhciB3cz17bmF0aXZlOkVzLG51bGw6RHN9LFNzPTAsa3M9ZnVuY3Rpb24oZSx0LG4pe3ZhciByPWUuZGlzcGxheTt0aGlzLnZpZXdwb3J0PXQsdGhpcy52aXNpYmxlPSRuKHIsZS5kb2MsdCksdGhpcy5lZGl0b3JJc0hpZGRlbj0hci53cmFwcGVyLm9mZnNldFdpZHRoLHRoaXMud3JhcHBlckhlaWdodD1yLndyYXBwZXIuY2xpZW50SGVpZ2h0LHRoaXMud3JhcHBlcldpZHRoPXIud3JhcHBlci5jbGllbnRXaWR0aCx0aGlzLm9sZERpc3BsYXlXaWR0aD1VdChlKSx0aGlzLmZvcmNlPW4sdGhpcy5kaW1zPUVuKGUpLHRoaXMuZXZlbnRzPVtdfTtrcy5wcm90b3R5cGUuc2lnbmFsPWZ1bmN0aW9uKGUsdCl7T2UoZSx0KSYmdGhpcy5ldmVudHMucHVzaChhcmd1bWVudHMpfSxrcy5wcm90b3R5cGUuZmluaXNoPWZ1bmN0aW9uKCl7Zm9yKHZhciBlPXRoaXMsdD0wO3Q8dGhpcy5ldmVudHMubGVuZ3RoO3QrKylBZS5hcHBseShudWxsLGUuZXZlbnRzW3RdKX07dmFyIEFzPTAsX3M9bnVsbDtiYT9fcz0tLjUzOm1hP19zPTE1OkRhP19zPS0uNzpTYSYmKF9zPS0xLzMpO3ZhciBUcz1mdW5jdGlvbihlLHQpe3RoaXMucmFuZ2VzPWUsdGhpcy5wcmltSW5kZXg9dH07VHMucHJvdG90eXBlLnByaW1hcnk9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5yYW5nZXNbdGhpcy5wcmltSW5kZXhdfSxUcy5wcm90b3R5cGUuZXF1YWxzPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7aWYoZT09dGhpcylyZXR1cm4hMDtpZihlLnByaW1JbmRleCE9dGhpcy5wcmltSW5kZXh8fGUucmFuZ2VzLmxlbmd0aCE9dGhpcy5yYW5nZXMubGVuZ3RoKXJldHVybiExO2Zvcih2YXIgbj0wO248dGhpcy5yYW5nZXMubGVuZ3RoO24rKyl7dmFyIHI9dC5yYW5nZXNbbl0saT1lLnJhbmdlc1tuXTtpZighaihyLmFuY2hvcixpLmFuY2hvcil8fCFqKHIuaGVhZCxpLmhlYWQpKXJldHVybiExfXJldHVybiEwfSxUcy5wcm90b3R5cGUuZGVlcENvcHk9ZnVuY3Rpb24oKXtmb3IodmFyIGU9dGhpcyx0PVtdLG49MDtuPHRoaXMucmFuZ2VzLmxlbmd0aDtuKyspdFtuXT1uZXcgT3MoUihlLnJhbmdlc1tuXS5hbmNob3IpLFIoZS5yYW5nZXNbbl0uaGVhZCkpO3JldHVybiBuZXcgVHModCx0aGlzLnByaW1JbmRleCl9LFRzLnByb3RvdHlwZS5zb21ldGhpbmdTZWxlY3RlZD1mdW5jdGlvbigpe2Zvcih2YXIgZT10aGlzLHQ9MDt0PHRoaXMucmFuZ2VzLmxlbmd0aDt0KyspaWYoIWUucmFuZ2VzW3RdLmVtcHR5KCkpcmV0dXJuITA7cmV0dXJuITF9LFRzLnByb3RvdHlwZS5jb250YWlucz1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXM7dHx8KHQ9ZSk7Zm9yKHZhciByPTA7cjx0aGlzLnJhbmdlcy5sZW5ndGg7cisrKXt2YXIgaT1uLnJhbmdlc1tyXTtpZihNKHQsaS5mcm9tKCkpPj0wJiZNKGUsaS50bygpKTw9MClyZXR1cm4gcn1yZXR1cm4tMX07dmFyIE9zPWZ1bmN0aW9uKGUsdCl7dGhpcy5hbmNob3I9ZSx0aGlzLmhlYWQ9dH07T3MucHJvdG90eXBlLmZyb209ZnVuY3Rpb24oKXtyZXR1cm4gJCh0aGlzLmFuY2hvcix0aGlzLmhlYWQpfSxPcy5wcm90b3R5cGUudG89ZnVuY3Rpb24oKXtyZXR1cm4gQih0aGlzLmFuY2hvcix0aGlzLmhlYWQpfSxPcy5wcm90b3R5cGUuZW1wdHk9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5oZWFkLmxpbmU9PXRoaXMuYW5jaG9yLmxpbmUmJnRoaXMuaGVhZC5jaD09dGhpcy5hbmNob3IuY2h9LHppLnByb3RvdHlwZT17Y2h1bmtTaXplOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubGluZXMubGVuZ3RofSxyZW1vdmVJbm5lcjpmdW5jdGlvbihlLHQpe2Zvcih2YXIgbj10aGlzLHI9ZSxpPWUrdDtyPGk7KytyKXt2YXIgbz1uLmxpbmVzW3JdO24uaGVpZ2h0LT1vLmhlaWdodCxzdChvKSxDdChvLCJkZWxldGUiKX10aGlzLmxpbmVzLnNwbGljZShlLHQpfSxjb2xsYXBzZTpmdW5jdGlvbihlKXtlLnB1c2guYXBwbHkoZSx0aGlzLmxpbmVzKX0saW5zZXJ0SW5uZXI6ZnVuY3Rpb24oZSx0LG4pe3ZhciByPXRoaXM7dGhpcy5oZWlnaHQrPW4sdGhpcy5saW5lcz10aGlzLmxpbmVzLnNsaWNlKDAsZSkuY29uY2F0KHQpLmNvbmNhdCh0aGlzLmxpbmVzLnNsaWNlKGUpKTtmb3IodmFyIGk9MDtpPHQubGVuZ3RoOysraSl0W2ldLnBhcmVudD1yfSxpdGVyTjpmdW5jdGlvbihlLHQsbil7Zm9yKHZhciByPXRoaXMsaT1lK3Q7ZTxpOysrZSlpZihuKHIubGluZXNbZV0pKXJldHVybiEwfX0sR2kucHJvdG90eXBlPXtjaHVua1NpemU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5zaXplfSxyZW1vdmVJbm5lcjpmdW5jdGlvbihlLHQpe3ZhciBuPXRoaXM7dGhpcy5zaXplLT10O2Zvcih2YXIgcj0wO3I8dGhpcy5jaGlsZHJlbi5sZW5ndGg7KytyKXt2YXIgaT1uLmNoaWxkcmVuW3JdLG89aS5jaHVua1NpemUoKTtpZihlPG8pe3ZhciBhPU1hdGgubWluKHQsby1lKSxzPWkuaGVpZ2h0O2lmKGkucmVtb3ZlSW5uZXIoZSxhKSxuLmhlaWdodC09cy1pLmhlaWdodCxvPT1hJiYobi5jaGlsZHJlbi5zcGxpY2Uoci0tLDEpLGkucGFyZW50PW51bGwpLDA9PSh0LT1hKSlicmVhaztlPTB9ZWxzZSBlLT1vfWlmKHRoaXMuc2l6ZS10PDI1JiYodGhpcy5jaGlsZHJlbi5sZW5ndGg+MXx8ISh0aGlzLmNoaWxkcmVuWzBdaW5zdGFuY2VvZiB6aSkpKXt2YXIgdT1bXTt0aGlzLmNvbGxhcHNlKHUpLHRoaXMuY2hpbGRyZW49W25ldyB6aSh1KV0sdGhpcy5jaGlsZHJlblswXS5wYXJlbnQ9dGhpc319LGNvbGxhcHNlOmZ1bmN0aW9uKGUpe2Zvcih2YXIgdD10aGlzLG49MDtuPHRoaXMuY2hpbGRyZW4ubGVuZ3RoOysrbil0LmNoaWxkcmVuW25dLmNvbGxhcHNlKGUpfSxpbnNlcnRJbm5lcjpmdW5jdGlvbihlLHQsbil7dmFyIHI9dGhpczt0aGlzLnNpemUrPXQubGVuZ3RoLHRoaXMuaGVpZ2h0Kz1uO2Zvcih2YXIgaT0wO2k8dGhpcy5jaGlsZHJlbi5sZW5ndGg7KytpKXt2YXIgbz1yLmNoaWxkcmVuW2ldLGE9by5jaHVua1NpemUoKTtpZihlPD1hKXtpZihvLmluc2VydElubmVyKGUsdCxuKSxvLmxpbmVzJiZvLmxpbmVzLmxlbmd0aD41MCl7Zm9yKHZhciBzPW8ubGluZXMubGVuZ3RoJTI1KzI1LHU9czt1PG8ubGluZXMubGVuZ3RoOyl7dmFyIGM9bmV3IHppKG8ubGluZXMuc2xpY2UodSx1Kz0yNSkpO28uaGVpZ2h0LT1jLmhlaWdodCxyLmNoaWxkcmVuLnNwbGljZSgrK2ksMCxjKSxjLnBhcmVudD1yfW8ubGluZXM9by5saW5lcy5zbGljZSgwLHMpLHIubWF5YmVTcGlsbCgpfWJyZWFrfWUtPWF9fSxtYXliZVNwaWxsOmZ1bmN0aW9uKCl7aWYoISh0aGlzLmNoaWxkcmVuLmxlbmd0aDw9MTApKXt2YXIgZT10aGlzO2Rve3ZhciB0PWUuY2hpbGRyZW4uc3BsaWNlKGUuY2hpbGRyZW4ubGVuZ3RoLTUsNSksbj1uZXcgR2kodCk7aWYoZS5wYXJlbnQpe2Uuc2l6ZS09bi5zaXplLGUuaGVpZ2h0LT1uLmhlaWdodDt2YXIgcj1mKGUucGFyZW50LmNoaWxkcmVuLGUpO2UucGFyZW50LmNoaWxkcmVuLnNwbGljZShyKzEsMCxuKX1lbHNle3ZhciBpPW5ldyBHaShlLmNoaWxkcmVuKTtpLnBhcmVudD1lLGUuY2hpbGRyZW49W2ksbl0sZT1pfW4ucGFyZW50PWUucGFyZW50fXdoaWxlKGUuY2hpbGRyZW4ubGVuZ3RoPjEwKTtlLnBhcmVudC5tYXliZVNwaWxsKCl9fSxpdGVyTjpmdW5jdGlvbihlLHQsbil7Zm9yKHZhciByPXRoaXMsaT0wO2k8dGhpcy5jaGlsZHJlbi5sZW5ndGg7KytpKXt2YXIgbz1yLmNoaWxkcmVuW2ldLGE9by5jaHVua1NpemUoKTtpZihlPGEpe3ZhciBzPU1hdGgubWluKHQsYS1lKTtpZihvLml0ZXJOKGUscyxuKSlyZXR1cm4hMDtpZigwPT0odC09cykpYnJlYWs7ZT0wfWVsc2UgZS09YX19fTt2YXIgRnM9ZnVuY3Rpb24oZSx0LG4pe3ZhciByPXRoaXM7aWYobilmb3IodmFyIGkgaW4gbiluLmhhc093blByb3BlcnR5KGkpJiYocltpXT1uW2ldKTt0aGlzLmRvYz1lLHRoaXMubm9kZT10fTtGcy5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLHQ9dGhpcy5kb2MuY20sbj10aGlzLmxpbmUud2lkZ2V0cyxyPXRoaXMubGluZSxpPUYocik7aWYobnVsbCE9aSYmbil7Zm9yKHZhciBvPTA7bzxuLmxlbmd0aDsrK28pbltvXT09ZSYmbi5zcGxpY2Uoby0tLDEpO24ubGVuZ3RofHwoci53aWRnZXRzPW51bGwpO3ZhciBhPVB0KHRoaXMpO08ocixNYXRoLm1heCgwLHIuaGVpZ2h0LWEpKSx0JiYoaHIodCxmdW5jdGlvbigpe1ZpKHQsciwtYSksYnIodCxpLCJ3aWRnZXQiKX0pLEN0KHQsImxpbmVXaWRnZXRDbGVhcmVkIix0LHRoaXMsaSkpfX0sRnMucHJvdG90eXBlLmNoYW5nZWQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLHQ9dGhpcy5oZWlnaHQsbj10aGlzLmRvYy5jbSxyPXRoaXMubGluZTt0aGlzLmhlaWdodD1udWxsO3ZhciBpPVB0KHRoaXMpLXQ7aSYmKE8ocixyLmhlaWdodCtpKSxuJiZocihuLGZ1bmN0aW9uKCl7bi5jdXJPcC5mb3JjZVVwZGF0ZT0hMCxWaShuLHIsaSksQ3QobiwibGluZVdpZGdldENoYW5nZWQiLG4sZSxGKHIpKX0pKX0sRmUoRnMpO3ZhciBOcz0wLElzPWZ1bmN0aW9uKGUsdCl7dGhpcy5saW5lcz1bXSx0aGlzLnR5cGU9dCx0aGlzLmRvYz1lLHRoaXMuaWQ9KytOc307SXMucHJvdG90eXBlLmNsZWFyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcztpZighdGhpcy5leHBsaWNpdGx5Q2xlYXJlZCl7dmFyIHQ9dGhpcy5kb2MuY20sbj10JiYhdC5jdXJPcDtpZihuJiZhcih0KSxPZSh0aGlzLCJjbGVhciIpKXt2YXIgcj10aGlzLmZpbmQoKTtyJiZDdCh0aGlzLCJjbGVhciIsci5mcm9tLHIudG8pfWZvcih2YXIgaT1udWxsLG89bnVsbCxhPTA7YTx0aGlzLmxpbmVzLmxlbmd0aDsrK2Epe3ZhciBzPWUubGluZXNbYV0sdT1RKHMubWFya2VkU3BhbnMsZSk7dCYmIWUuY29sbGFwc2VkP2JyKHQsRihzKSwidGV4dCIpOnQmJihudWxsIT11LnRvJiYobz1GKHMpKSxudWxsIT11LmZyb20mJihpPUYocykpKSxzLm1hcmtlZFNwYW5zPUsocy5tYXJrZWRTcGFucyx1KSxudWxsPT11LmZyb20mJmUuY29sbGFwc2VkJiYheWUoZS5kb2MscykmJnQmJk8ocyx4bih0LmRpc3BsYXkpKX1pZih0JiZ0aGlzLmNvbGxhcHNlZCYmIXQub3B0aW9ucy5saW5lV3JhcHBpbmcpZm9yKHZhciBjPTA7Yzx0aGlzLmxpbmVzLmxlbmd0aDsrK2Mpe3ZhciBsPWZlKGUubGluZXNbY10pLHA9eGUobCk7cD50LmRpc3BsYXkubWF4TGluZUxlbmd0aCYmKHQuZGlzcGxheS5tYXhMaW5lPWwsdC5kaXNwbGF5Lm1heExpbmVMZW5ndGg9cCx0LmRpc3BsYXkubWF4TGluZUNoYW5nZWQ9ITApfW51bGwhPWkmJnQmJnRoaXMuY29sbGFwc2VkJiZ2cih0LGksbysxKSx0aGlzLmxpbmVzLmxlbmd0aD0wLHRoaXMuZXhwbGljaXRseUNsZWFyZWQ9ITAsdGhpcy5hdG9taWMmJnRoaXMuZG9jLmNhbnRFZGl0JiYodGhpcy5kb2MuY2FudEVkaXQ9ITEsdCYmd2kodC5kb2MpKSx0JiZDdCh0LCJtYXJrZXJDbGVhcmVkIix0LHRoaXMsaSxvKSxuJiZzcih0KSx0aGlzLnBhcmVudCYmdGhpcy5wYXJlbnQuY2xlYXIoKX19LElzLnByb3RvdHlwZS5maW5kPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcztudWxsPT1lJiYiYm9va21hcmsiPT10aGlzLnR5cGUmJihlPTEpO2Zvcih2YXIgcixpLG89MDtvPHRoaXMubGluZXMubGVuZ3RoOysrbyl7dmFyIGE9bi5saW5lc1tvXSxzPVEoYS5tYXJrZWRTcGFucyxuKTtpZihudWxsIT1zLmZyb20mJihyPVAodD9hOkYoYSkscy5mcm9tKSwtMT09ZSkpcmV0dXJuIHI7aWYobnVsbCE9cy50byYmKGk9UCh0P2E6RihhKSxzLnRvKSwxPT1lKSlyZXR1cm4gaX1yZXR1cm4gciYme2Zyb206cix0bzppfX0sSXMucHJvdG90eXBlLmNoYW5nZWQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLHQ9dGhpcy5maW5kKC0xLCEwKSxuPXRoaXMscj10aGlzLmRvYy5jbTt0JiZyJiZocihyLGZ1bmN0aW9uKCl7dmFyIGk9dC5saW5lLG89Rih0LmxpbmUpLGE9V3QocixvKTtpZihhJiYoZW4oYSksci5jdXJPcC5zZWxlY3Rpb25DaGFuZ2VkPXIuY3VyT3AuZm9yY2VVcGRhdGU9ITApLHIuY3VyT3AudXBkYXRlTWF4TGluZT0hMCwheWUobi5kb2MsaSkmJm51bGwhPW4uaGVpZ2h0KXt2YXIgcz1uLmhlaWdodDtuLmhlaWdodD1udWxsO3ZhciB1PVB0KG4pLXM7dSYmTyhpLGkuaGVpZ2h0K3UpfUN0KHIsIm1hcmtlckNoYW5nZWQiLHIsZSl9KX0sSXMucHJvdG90eXBlLmF0dGFjaExpbmU9ZnVuY3Rpb24oZSl7aWYoIXRoaXMubGluZXMubGVuZ3RoJiZ0aGlzLmRvYy5jbSl7dmFyIHQ9dGhpcy5kb2MuY20uY3VyT3A7dC5tYXliZUhpZGRlbk1hcmtlcnMmJi0xIT1mKHQubWF5YmVIaWRkZW5NYXJrZXJzLHRoaXMpfHwodC5tYXliZVVuaGlkZGVuTWFya2Vyc3x8KHQubWF5YmVVbmhpZGRlbk1hcmtlcnM9W10pKS5wdXNoKHRoaXMpfXRoaXMubGluZXMucHVzaChlKX0sSXMucHJvdG90eXBlLmRldGFjaExpbmU9ZnVuY3Rpb24oZSl7aWYodGhpcy5saW5lcy5zcGxpY2UoZih0aGlzLmxpbmVzLGUpLDEpLCF0aGlzLmxpbmVzLmxlbmd0aCYmdGhpcy5kb2MuY20pe3ZhciB0PXRoaXMuZG9jLmNtLmN1ck9wOyh0Lm1heWJlSGlkZGVuTWFya2Vyc3x8KHQubWF5YmVIaWRkZW5NYXJrZXJzPVtdKSkucHVzaCh0aGlzKX19LEZlKElzKTt2YXIgTHM9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzO3RoaXMubWFya2Vycz1lLHRoaXMucHJpbWFyeT10O2Zvcih2YXIgcj0wO3I8ZS5sZW5ndGg7KytyKWVbcl0ucGFyZW50PW59O0xzLnByb3RvdHlwZS5jbGVhcj1mdW5jdGlvbigpe3ZhciBlPXRoaXM7aWYoIXRoaXMuZXhwbGljaXRseUNsZWFyZWQpe3RoaXMuZXhwbGljaXRseUNsZWFyZWQ9ITA7Zm9yKHZhciB0PTA7dDx0aGlzLm1hcmtlcnMubGVuZ3RoOysrdCllLm1hcmtlcnNbdF0uY2xlYXIoKTtDdCh0aGlzLCJjbGVhciIpfX0sTHMucHJvdG90eXBlLmZpbmQ9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5wcmltYXJ5LmZpbmQoZSx0KX0sRmUoTHMpO3ZhciBQcz0wLE1zPWZ1bmN0aW9uKGUsdCxuLHIsaSl7aWYoISh0aGlzIGluc3RhbmNlb2YgTXMpKXJldHVybiBuZXcgTXMoZSx0LG4scixpKTtudWxsPT1uJiYobj0wKSxHaS5jYWxsKHRoaXMsW25ldyB6aShbbmV3IG1zKCIiLG51bGwpXSldKSx0aGlzLmZpcnN0PW4sdGhpcy5zY3JvbGxUb3A9dGhpcy5zY3JvbGxMZWZ0PTAsdGhpcy5jYW50RWRpdD0hMSx0aGlzLmNsZWFuR2VuZXJhdGlvbj0xLHRoaXMubW9kZUZyb250aWVyPXRoaXMuaGlnaGxpZ2h0RnJvbnRpZXI9bjt2YXIgbz1QKG4sMCk7dGhpcy5zZWw9VXIobyksdGhpcy5oaXN0b3J5PW5ldyB0aShudWxsKSx0aGlzLmlkPSsrUHMsdGhpcy5tb2RlT3B0aW9uPXQsdGhpcy5saW5lU2VwPXIsdGhpcy5kaXJlY3Rpb249InJ0bCI9PWk/InJ0bCI6Imx0ciIsdGhpcy5leHRlbmQ9ITEsInN0cmluZyI9PXR5cGVvZiBlJiYoZT10aGlzLnNwbGl0TGluZXMoZSkpLEpyKHRoaXMse2Zyb206byx0bzpvLHRleHQ6ZX0pLENpKHRoaXMsVXIobykscWEpfTtNcy5wcm90b3R5cGU9YihHaS5wcm90b3R5cGUse2NvbnN0cnVjdG9yOk1zLGl0ZXI6ZnVuY3Rpb24oZSx0LG4pe24/dGhpcy5pdGVyTihlLXRoaXMuZmlyc3QsdC1lLG4pOnRoaXMuaXRlck4odGhpcy5maXJzdCx0aGlzLmZpcnN0K3RoaXMuc2l6ZSxlKX0saW5zZXJ0OmZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPTAscj0wO3I8dC5sZW5ndGg7KytyKW4rPXRbcl0uaGVpZ2h0O3RoaXMuaW5zZXJ0SW5uZXIoZS10aGlzLmZpcnN0LHQsbil9LHJlbW92ZTpmdW5jdGlvbihlLHQpe3RoaXMucmVtb3ZlSW5uZXIoZS10aGlzLmZpcnN0LHQpfSxnZXRWYWx1ZTpmdW5jdGlvbihlKXt2YXIgdD1UKHRoaXMsdGhpcy5maXJzdCx0aGlzLmZpcnN0K3RoaXMuc2l6ZSk7cmV0dXJuITE9PT1lP3Q6dC5qb2luKGV8fHRoaXMubGluZVNlcGFyYXRvcigpKX0sc2V0VmFsdWU6eXIoZnVuY3Rpb24oZSl7dmFyIHQ9UCh0aGlzLmZpcnN0LDApLG49dGhpcy5maXJzdCt0aGlzLnNpemUtMTtGaSh0aGlzLHtmcm9tOnQsdG86UChuLEEodGhpcyxuKS50ZXh0Lmxlbmd0aCksdGV4dDp0aGlzLnNwbGl0TGluZXMoZSksb3JpZ2luOiJzZXRWYWx1ZSIsZnVsbDohMH0sITApLHRoaXMuY20mJktuKHRoaXMuY20sMCwwKSxDaSh0aGlzLFVyKHQpLHFhKX0pLHJlcGxhY2VSYW5nZTpmdW5jdGlvbihlLHQsbixyKXt0PXoodGhpcyx0KSxuPW4/eih0aGlzLG4pOnQsamkodGhpcyxlLHQsbixyKX0sZ2V0UmFuZ2U6ZnVuY3Rpb24oZSx0LG4pe3ZhciByPV8odGhpcyx6KHRoaXMsZSkseih0aGlzLHQpKTtyZXR1cm4hMT09PW4/cjpyLmpvaW4obnx8dGhpcy5saW5lU2VwYXJhdG9yKCkpfSxnZXRMaW5lOmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuZ2V0TGluZUhhbmRsZShlKTtyZXR1cm4gdCYmdC50ZXh0fSxnZXRMaW5lSGFuZGxlOmZ1bmN0aW9uKGUpe2lmKEkodGhpcyxlKSlyZXR1cm4gQSh0aGlzLGUpfSxnZXRMaW5lTnVtYmVyOmZ1bmN0aW9uKGUpe3JldHVybiBGKGUpfSxnZXRMaW5lSGFuZGxlVmlzdWFsU3RhcnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlJiYoZT1BKHRoaXMsZSkpLGZlKGUpfSxsaW5lQ291bnQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5zaXplfSxmaXJzdExpbmU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5maXJzdH0sbGFzdExpbmU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5maXJzdCt0aGlzLnNpemUtMX0sY2xpcFBvczpmdW5jdGlvbihlKXtyZXR1cm4geih0aGlzLGUpfSxnZXRDdXJzb3I6ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5zZWwucHJpbWFyeSgpO3JldHVybiBudWxsPT1lfHwiaGVhZCI9PWU/dC5oZWFkOiJhbmNob3IiPT1lP3QuYW5jaG9yOiJlbmQiPT1lfHwidG8iPT1lfHwhMT09PWU/dC50bygpOnQuZnJvbSgpfSxsaXN0U2VsZWN0aW9uczpmdW5jdGlvbigpe3JldHVybiB0aGlzLnNlbC5yYW5nZXN9LHNvbWV0aGluZ1NlbGVjdGVkOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc2VsLnNvbWV0aGluZ1NlbGVjdGVkKCl9LHNldEN1cnNvcjp5cihmdW5jdGlvbihlLHQsbil7dmkodGhpcyx6KHRoaXMsIm51bWJlciI9PXR5cGVvZiBlP1AoZSx0fHwwKTplKSxudWxsLG4pfSksc2V0U2VsZWN0aW9uOnlyKGZ1bmN0aW9uKGUsdCxuKXt2aSh0aGlzLHoodGhpcyxlKSx6KHRoaXMsdHx8ZSksbil9KSxleHRlbmRTZWxlY3Rpb246eXIoZnVuY3Rpb24oZSx0LG4pe21pKHRoaXMseih0aGlzLGUpLHQmJnoodGhpcyx0KSxuKX0pLGV4dGVuZFNlbGVjdGlvbnM6eXIoZnVuY3Rpb24oZSx0KXtnaSh0aGlzLFYodGhpcyxlKSx0KX0pLGV4dGVuZFNlbGVjdGlvbnNCeTp5cihmdW5jdGlvbihlLHQpe2dpKHRoaXMsVih0aGlzLGcodGhpcy5zZWwucmFuZ2VzLGUpKSx0KX0pLHNldFNlbGVjdGlvbnM6eXIoZnVuY3Rpb24oZSx0LG4pe3ZhciByPXRoaXM7aWYoZS5sZW5ndGgpe2Zvcih2YXIgaT1bXSxvPTA7bzxlLmxlbmd0aDtvKyspaVtvXT1uZXcgT3MoeihyLGVbb10uYW5jaG9yKSx6KHIsZVtvXS5oZWFkKSk7bnVsbD09dCYmKHQ9TWF0aC5taW4oZS5sZW5ndGgtMSx0aGlzLnNlbC5wcmltSW5kZXgpKSxDaSh0aGlzLCRyKGksdCksbil9fSksYWRkU2VsZWN0aW9uOnlyKGZ1bmN0aW9uKGUsdCxuKXt2YXIgcj10aGlzLnNlbC5yYW5nZXMuc2xpY2UoMCk7ci5wdXNoKG5ldyBPcyh6KHRoaXMsZSkseih0aGlzLHR8fGUpKSksQ2kodGhpcywkcihyLHIubGVuZ3RoLTEpLG4pfSksZ2V0U2VsZWN0aW9uOmZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPXRoaXMscj10aGlzLnNlbC5yYW5nZXMsaT0wO2k8ci5sZW5ndGg7aSsrKXt2YXIgbz1fKG4scltpXS5mcm9tKCkscltpXS50bygpKTt0PXQ/dC5jb25jYXQobyk6b31yZXR1cm4hMT09PWU/dDp0LmpvaW4oZXx8dGhpcy5saW5lU2VwYXJhdG9yKCkpfSxnZXRTZWxlY3Rpb25zOmZ1bmN0aW9uKGUpe2Zvcih2YXIgdD10aGlzLG49W10scj10aGlzLnNlbC5yYW5nZXMsaT0wO2k8ci5sZW5ndGg7aSsrKXt2YXIgbz1fKHQscltpXS5mcm9tKCkscltpXS50bygpKTshMSE9PWUmJihvPW8uam9pbihlfHx0LmxpbmVTZXBhcmF0b3IoKSkpLG5baV09b31yZXR1cm4gbn0scmVwbGFjZVNlbGVjdGlvbjpmdW5jdGlvbihlLHQsbil7Zm9yKHZhciByPVtdLGk9MDtpPHRoaXMuc2VsLnJhbmdlcy5sZW5ndGg7aSsrKXJbaV09ZTt0aGlzLnJlcGxhY2VTZWxlY3Rpb25zKHIsdCxufHwiK2lucHV0Iil9LHJlcGxhY2VTZWxlY3Rpb25zOnlyKGZ1bmN0aW9uKGUsdCxuKXtmb3IodmFyIHI9dGhpcyxpPVtdLG89dGhpcy5zZWwsYT0wO2E8by5yYW5nZXMubGVuZ3RoO2ErKyl7dmFyIHM9by5yYW5nZXNbYV07aVthXT17ZnJvbTpzLmZyb20oKSx0bzpzLnRvKCksdGV4dDpyLnNwbGl0TGluZXMoZVthXSksb3JpZ2luOm59fWZvcih2YXIgdT10JiYiZW5kIiE9dCYmSHIodGhpcyxpLHQpLGM9aS5sZW5ndGgtMTtjPj0wO2MtLSlGaShyLGlbY10pO3U/eGkodGhpcyx1KTp0aGlzLmNtJiZRbih0aGlzLmNtKX0pLHVuZG86eXIoZnVuY3Rpb24oKXtJaSh0aGlzLCJ1bmRvIil9KSxyZWRvOnlyKGZ1bmN0aW9uKCl7SWkodGhpcywicmVkbyIpfSksdW5kb1NlbGVjdGlvbjp5cihmdW5jdGlvbigpe0lpKHRoaXMsInVuZG8iLCEwKX0pLHJlZG9TZWxlY3Rpb246eXIoZnVuY3Rpb24oKXtJaSh0aGlzLCJyZWRvIiwhMCl9KSxzZXRFeHRlbmRpbmc6ZnVuY3Rpb24oZSl7dGhpcy5leHRlbmQ9ZX0sZ2V0RXh0ZW5kaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZXh0ZW5kfSxoaXN0b3J5U2l6ZTpmdW5jdGlvbigpe2Zvcih2YXIgZT10aGlzLmhpc3RvcnksdD0wLG49MCxyPTA7cjxlLmRvbmUubGVuZ3RoO3IrKyllLmRvbmVbcl0ucmFuZ2VzfHwrK3Q7Zm9yKHZhciBpPTA7aTxlLnVuZG9uZS5sZW5ndGg7aSsrKWUudW5kb25lW2ldLnJhbmdlc3x8KytuO3JldHVybnt1bmRvOnQscmVkbzpufX0sY2xlYXJIaXN0b3J5OmZ1bmN0aW9uKCl7dGhpcy5oaXN0b3J5PW5ldyB0aSh0aGlzLmhpc3RvcnkubWF4R2VuZXJhdGlvbil9LG1hcmtDbGVhbjpmdW5jdGlvbigpe3RoaXMuY2xlYW5HZW5lcmF0aW9uPXRoaXMuY2hhbmdlR2VuZXJhdGlvbighMCl9LGNoYW5nZUdlbmVyYXRpb246ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJih0aGlzLmhpc3RvcnkubGFzdE9wPXRoaXMuaGlzdG9yeS5sYXN0U2VsT3A9dGhpcy5oaXN0b3J5Lmxhc3RPcmlnaW49bnVsbCksdGhpcy5oaXN0b3J5LmdlbmVyYXRpb259LGlzQ2xlYW46ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuaGlzdG9yeS5nZW5lcmF0aW9uPT0oZXx8dGhpcy5jbGVhbkdlbmVyYXRpb24pfSxnZXRIaXN0b3J5OmZ1bmN0aW9uKCl7cmV0dXJue2RvbmU6ZGkodGhpcy5oaXN0b3J5LmRvbmUpLHVuZG9uZTpkaSh0aGlzLmhpc3RvcnkudW5kb25lKX19LHNldEhpc3Rvcnk6ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5oaXN0b3J5PW5ldyB0aSh0aGlzLmhpc3RvcnkubWF4R2VuZXJhdGlvbik7dC5kb25lPWRpKGUuZG9uZS5zbGljZSgwKSxudWxsLCEwKSx0LnVuZG9uZT1kaShlLnVuZG9uZS5zbGljZSgwKSxudWxsLCEwKX0sc2V0R3V0dGVyTWFya2VyOnlyKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gVWkodGhpcyxlLCJndXR0ZXIiLGZ1bmN0aW9uKGUpe3ZhciByPWUuZ3V0dGVyTWFya2Vyc3x8KGUuZ3V0dGVyTWFya2Vycz17fSk7cmV0dXJuIHJbdF09biwhbiYmRShyKSYmKGUuZ3V0dGVyTWFya2Vycz1udWxsKSwhMH0pfSksY2xlYXJHdXR0ZXI6eXIoZnVuY3Rpb24oZSl7dmFyIHQ9dGhpczt0aGlzLml0ZXIoZnVuY3Rpb24obil7bi5ndXR0ZXJNYXJrZXJzJiZuLmd1dHRlck1hcmtlcnNbZV0mJlVpKHQsbiwiZ3V0dGVyIixmdW5jdGlvbigpe3JldHVybiBuLmd1dHRlck1hcmtlcnNbZV09bnVsbCxFKG4uZ3V0dGVyTWFya2VycykmJihuLmd1dHRlck1hcmtlcnM9bnVsbCksITB9KX0pfSksbGluZUluZm86ZnVuY3Rpb24oZSl7dmFyIHQ7aWYoIm51bWJlciI9PXR5cGVvZiBlKXtpZighSSh0aGlzLGUpKXJldHVybiBudWxsO2lmKHQ9ZSwhKGU9QSh0aGlzLGUpKSlyZXR1cm4gbnVsbH1lbHNlIGlmKG51bGw9PSh0PUYoZSkpKXJldHVybiBudWxsO3JldHVybntsaW5lOnQsaGFuZGxlOmUsdGV4dDplLnRleHQsZ3V0dGVyTWFya2VyczplLmd1dHRlck1hcmtlcnMsdGV4dENsYXNzOmUudGV4dENsYXNzLGJnQ2xhc3M6ZS5iZ0NsYXNzLHdyYXBDbGFzczplLndyYXBDbGFzcyx3aWRnZXRzOmUud2lkZ2V0c319LGFkZExpbmVDbGFzczp5cihmdW5jdGlvbih0LG4scil7cmV0dXJuIFVpKHRoaXMsdCwiZ3V0dGVyIj09bj8iZ3V0dGVyIjoiY2xhc3MiLGZ1bmN0aW9uKHQpe3ZhciBpPSJ0ZXh0Ij09bj8idGV4dENsYXNzIjoiYmFja2dyb3VuZCI9PW4/ImJnQ2xhc3MiOiJndXR0ZXIiPT1uPyJndXR0ZXJDbGFzcyI6IndyYXBDbGFzcyI7aWYodFtpXSl7aWYoZShyKS50ZXN0KHRbaV0pKXJldHVybiExO3RbaV0rPSIgIityfWVsc2UgdFtpXT1yO3JldHVybiEwfSl9KSxyZW1vdmVMaW5lQ2xhc3M6eXIoZnVuY3Rpb24odCxuLHIpe3JldHVybiBVaSh0aGlzLHQsImd1dHRlciI9PW4/Imd1dHRlciI6ImNsYXNzIixmdW5jdGlvbih0KXt2YXIgaT0idGV4dCI9PW4/InRleHRDbGFzcyI6ImJhY2tncm91bmQiPT1uPyJiZ0NsYXNzIjoiZ3V0dGVyIj09bj8iZ3V0dGVyQ2xhc3MiOiJ3cmFwQ2xhc3MiLG89dFtpXTtpZighbylyZXR1cm4hMTtpZihudWxsPT1yKXRbaV09bnVsbDtlbHNle3ZhciBhPW8ubWF0Y2goZShyKSk7aWYoIWEpcmV0dXJuITE7dmFyIHM9YS5pbmRleCthWzBdLmxlbmd0aDt0W2ldPW8uc2xpY2UoMCxhLmluZGV4KSsoYS5pbmRleCYmcyE9by5sZW5ndGg/IiAiOiIiKStvLnNsaWNlKHMpfHxudWxsfXJldHVybiEwfSl9KSxhZGRMaW5lV2lkZ2V0OnlyKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gcWkodGhpcyxlLHQsbil9KSxyZW1vdmVMaW5lV2lkZ2V0OmZ1bmN0aW9uKGUpe2UuY2xlYXIoKX0sbWFya1RleHQ6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBIaSh0aGlzLHoodGhpcyxlKSx6KHRoaXMsdCksbixuJiZuLnR5cGV8fCJyYW5nZSIpfSxzZXRCb29rbWFyazpmdW5jdGlvbihlLHQpe3ZhciBuPXtyZXBsYWNlZFdpdGg6dCYmKG51bGw9PXQubm9kZVR5cGU/dC53aWRnZXQ6dCksaW5zZXJ0TGVmdDp0JiZ0Lmluc2VydExlZnQsY2xlYXJXaGVuRW1wdHk6ITEsc2hhcmVkOnQmJnQuc2hhcmVkLGhhbmRsZU1vdXNlRXZlbnRzOnQmJnQuaGFuZGxlTW91c2VFdmVudHN9O3JldHVybiBlPXoodGhpcyxlKSxIaSh0aGlzLGUsZSxuLCJib29rbWFyayIpfSxmaW5kTWFya3NBdDpmdW5jdGlvbihlKXtlPXoodGhpcyxlKTt2YXIgdD1bXSxuPUEodGhpcyxlLmxpbmUpLm1hcmtlZFNwYW5zO2lmKG4pZm9yKHZhciByPTA7cjxuLmxlbmd0aDsrK3Ipe3ZhciBpPW5bcl07KG51bGw9PWkuZnJvbXx8aS5mcm9tPD1lLmNoKSYmKG51bGw9PWkudG98fGkudG8+PWUuY2gpJiZ0LnB1c2goaS5tYXJrZXIucGFyZW50fHxpLm1hcmtlcil9cmV0dXJuIHR9LGZpbmRNYXJrczpmdW5jdGlvbihlLHQsbil7ZT16KHRoaXMsZSksdD16KHRoaXMsdCk7dmFyIHI9W10saT1lLmxpbmU7cmV0dXJuIHRoaXMuaXRlcihlLmxpbmUsdC5saW5lKzEsZnVuY3Rpb24obyl7dmFyIGE9by5tYXJrZWRTcGFucztpZihhKWZvcih2YXIgcz0wO3M8YS5sZW5ndGg7cysrKXt2YXIgdT1hW3NdO251bGwhPXUudG8mJmk9PWUubGluZSYmZS5jaD49dS50b3x8bnVsbD09dS5mcm9tJiZpIT1lLmxpbmV8fG51bGwhPXUuZnJvbSYmaT09dC5saW5lJiZ1LmZyb20+PXQuY2h8fG4mJiFuKHUubWFya2VyKXx8ci5wdXNoKHUubWFya2VyLnBhcmVudHx8dS5tYXJrZXIpfSsraX0pLHJ9LGdldEFsbE1hcmtzOmZ1bmN0aW9uKCl7dmFyIGU9W107cmV0dXJuIHRoaXMuaXRlcihmdW5jdGlvbih0KXt2YXIgbj10Lm1hcmtlZFNwYW5zO2lmKG4pZm9yKHZhciByPTA7cjxuLmxlbmd0aDsrK3IpbnVsbCE9bltyXS5mcm9tJiZlLnB1c2gobltyXS5tYXJrZXIpfSksZX0scG9zRnJvbUluZGV4OmZ1bmN0aW9uKGUpe3ZhciB0LG49dGhpcy5maXJzdCxyPXRoaXMubGluZVNlcGFyYXRvcigpLmxlbmd0aDtyZXR1cm4gdGhpcy5pdGVyKGZ1bmN0aW9uKGkpe3ZhciBvPWkudGV4dC5sZW5ndGgrcjtpZihvPmUpcmV0dXJuIHQ9ZSwhMDtlLT1vLCsrbn0pLHoodGhpcyxQKG4sdCkpfSxpbmRleEZyb21Qb3M6ZnVuY3Rpb24oZSl7ZT16KHRoaXMsZSk7dmFyIHQ9ZS5jaDtpZihlLmxpbmU8dGhpcy5maXJzdHx8ZS5jaDwwKXJldHVybiAwO3ZhciBuPXRoaXMubGluZVNlcGFyYXRvcigpLmxlbmd0aDtyZXR1cm4gdGhpcy5pdGVyKHRoaXMuZmlyc3QsZS5saW5lLGZ1bmN0aW9uKGUpe3QrPWUudGV4dC5sZW5ndGgrbn0pLHR9LGNvcHk6ZnVuY3Rpb24oZSl7dmFyIHQ9bmV3IE1zKFQodGhpcyx0aGlzLmZpcnN0LHRoaXMuZmlyc3QrdGhpcy5zaXplKSx0aGlzLm1vZGVPcHRpb24sdGhpcy5maXJzdCx0aGlzLmxpbmVTZXAsdGhpcy5kaXJlY3Rpb24pO3JldHVybiB0LnNjcm9sbFRvcD10aGlzLnNjcm9sbFRvcCx0LnNjcm9sbExlZnQ9dGhpcy5zY3JvbGxMZWZ0LHQuc2VsPXRoaXMuc2VsLHQuZXh0ZW5kPSExLGUmJih0Lmhpc3RvcnkudW5kb0RlcHRoPXRoaXMuaGlzdG9yeS51bmRvRGVwdGgsdC5zZXRIaXN0b3J5KHRoaXMuZ2V0SGlzdG9yeSgpKSksdH0sbGlua2VkRG9jOmZ1bmN0aW9uKGUpe2V8fChlPXt9KTt2YXIgdD10aGlzLmZpcnN0LG49dGhpcy5maXJzdCt0aGlzLnNpemU7bnVsbCE9ZS5mcm9tJiZlLmZyb20+dCYmKHQ9ZS5mcm9tKSxudWxsIT1lLnRvJiZlLnRvPG4mJihuPWUudG8pO3ZhciByPW5ldyBNcyhUKHRoaXMsdCxuKSxlLm1vZGV8fHRoaXMubW9kZU9wdGlvbix0LHRoaXMubGluZVNlcCx0aGlzLmRpcmVjdGlvbik7cmV0dXJuIGUuc2hhcmVkSGlzdCYmKHIuaGlzdG9yeT10aGlzLmhpc3RvcnkpLCh0aGlzLmxpbmtlZHx8KHRoaXMubGlua2VkPVtdKSkucHVzaCh7ZG9jOnIsc2hhcmVkSGlzdDplLnNoYXJlZEhpc3R9KSxyLmxpbmtlZD1be2RvYzp0aGlzLGlzUGFyZW50OiEwLHNoYXJlZEhpc3Q6ZS5zaGFyZWRIaXN0fV0sS2kocixRaSh0aGlzKSkscn0sdW5saW5rRG9jOmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7aWYoZSBpbnN0YW5jZW9mIFFvJiYoZT1lLmRvYyksdGhpcy5saW5rZWQpZm9yKHZhciBuPTA7bjx0aGlzLmxpbmtlZC5sZW5ndGg7KytuKXt2YXIgcj10LmxpbmtlZFtuXTtpZihyLmRvYz09ZSl7dC5saW5rZWQuc3BsaWNlKG4sMSksZS51bmxpbmtEb2ModCksSmkoUWkodCkpO2JyZWFrfX1pZihlLmhpc3Rvcnk9PXRoaXMuaGlzdG9yeSl7dmFyIGk9W2UuaWRdO1lyKGUsZnVuY3Rpb24oZSl7cmV0dXJuIGkucHVzaChlLmlkKX0sITApLGUuaGlzdG9yeT1uZXcgdGkobnVsbCksZS5oaXN0b3J5LmRvbmU9ZGkodGhpcy5oaXN0b3J5LmRvbmUsaSksZS5oaXN0b3J5LnVuZG9uZT1kaSh0aGlzLmhpc3RvcnkudW5kb25lLGkpfX0saXRlckxpbmtlZERvY3M6ZnVuY3Rpb24oZSl7WXIodGhpcyxlKX0sZ2V0TW9kZTpmdW5jdGlvbigpe3JldHVybiB0aGlzLm1vZGV9LGdldEVkaXRvcjpmdW5jdGlvbigpe3JldHVybiB0aGlzLmNtfSxzcGxpdExpbmVzOmZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLmxpbmVTZXA/ZS5zcGxpdCh0aGlzLmxpbmVTZXApOmlzKGUpfSxsaW5lU2VwYXJhdG9yOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubGluZVNlcHx8IlxuIn0sc2V0RGlyZWN0aW9uOnlyKGZ1bmN0aW9uKGUpeyJydGwiIT1lJiYoZT0ibHRyIiksZSE9dGhpcy5kaXJlY3Rpb24mJih0aGlzLmRpcmVjdGlvbj1lLHRoaXMuaXRlcihmdW5jdGlvbihlKXtyZXR1cm4gZS5vcmRlcj1udWxsfSksdGhpcy5jbSYmZWkodGhpcy5jbSkpfSl9KSxNcy5wcm90b3R5cGUuZWFjaExpbmU9TXMucHJvdG90eXBlLml0ZXI7Zm9yKHZhciBqcz0wLFJzPSExLEJzPXszOiJQYXVzZSIsODoiQmFja3NwYWNlIiw5OiJUYWIiLDEzOiJFbnRlciIsMTY6IlNoaWZ0IiwxNzoiQ3RybCIsMTg6IkFsdCIsMTk6IlBhdXNlIiwyMDoiQ2Fwc0xvY2siLDI3OiJFc2MiLDMyOiJTcGFjZSIsMzM6IlBhZ2VVcCIsMzQ6IlBhZ2VEb3duIiwzNToiRW5kIiwzNjoiSG9tZSIsMzc6IkxlZnQiLDM4OiJVcCIsMzk6IlJpZ2h0Iiw0MDoiRG93biIsNDQ6IlByaW50U2NybiIsNDU6Ikluc2VydCIsNDY6IkRlbGV0ZSIsNTk6IjsiLDYxOiI9Iiw5MToiTW9kIiw5MjoiTW9kIiw5MzoiTW9kIiwxMDY6IioiLDEwNzoiPSIsMTA5OiItIiwxMTA6Ii4iLDExMToiLyIsMTI3OiJEZWxldGUiLDE0NToiU2Nyb2xsTG9jayIsMTczOiItIiwxODY6IjsiLDE4NzoiPSIsMTg4OiIsIiwxODk6Ii0iLDE5MDoiLiIsMTkxOiIvIiwxOTI6ImAiLDIxOToiWyIsMjIwOiJcXCIsMjIxOiJdIiwyMjI6IiciLDYzMjMyOiJVcCIsNjMyMzM6IkRvd24iLDYzMjM0OiJMZWZ0Iiw2MzIzNToiUmlnaHQiLDYzMjcyOiJEZWxldGUiLDYzMjczOiJIb21lIiw2MzI3NToiRW5kIiw2MzI3NjoiUGFnZVVwIiw2MzI3NzoiUGFnZURvd24iLDYzMzAyOiJJbnNlcnQifSwkcz0wOyRzPDEwOyRzKyspQnNbJHMrNDhdPUJzWyRzKzk2XT1TdHJpbmcoJHMpO2Zvcih2YXIgVXM9NjU7VXM8PTkwO1VzKyspQnNbVXNdPVN0cmluZy5mcm9tQ2hhckNvZGUoVXMpO2Zvcih2YXIgenM9MTt6czw9MTI7enMrKylCc1t6cysxMTFdPUJzW3pzKzYzMjM1XT0iRiIrenM7dmFyIEdzPXt9O0dzLmJhc2ljPXtMZWZ0OiJnb0NoYXJMZWZ0IixSaWdodDoiZ29DaGFyUmlnaHQiLFVwOiJnb0xpbmVVcCIsRG93bjoiZ29MaW5lRG93biIsRW5kOiJnb0xpbmVFbmQiLEhvbWU6ImdvTGluZVN0YXJ0U21hcnQiLFBhZ2VVcDoiZ29QYWdlVXAiLFBhZ2VEb3duOiJnb1BhZ2VEb3duIixEZWxldGU6ImRlbENoYXJBZnRlciIsQmFja3NwYWNlOiJkZWxDaGFyQmVmb3JlIiwiU2hpZnQtQmFja3NwYWNlIjoiZGVsQ2hhckJlZm9yZSIsVGFiOiJkZWZhdWx0VGFiIiwiU2hpZnQtVGFiIjoiaW5kZW50QXV0byIsRW50ZXI6Im5ld2xpbmVBbmRJbmRlbnQiLEluc2VydDoidG9nZ2xlT3ZlcndyaXRlIixFc2M6InNpbmdsZVNlbGVjdGlvbiJ9LEdzLnBjRGVmYXVsdD17IkN0cmwtQSI6InNlbGVjdEFsbCIsIkN0cmwtRCI6ImRlbGV0ZUxpbmUiLCJDdHJsLVoiOiJ1bmRvIiwiU2hpZnQtQ3RybC1aIjoicmVkbyIsIkN0cmwtWSI6InJlZG8iLCJDdHJsLUhvbWUiOiJnb0RvY1N0YXJ0IiwiQ3RybC1FbmQiOiJnb0RvY0VuZCIsIkN0cmwtVXAiOiJnb0xpbmVVcCIsIkN0cmwtRG93biI6ImdvTGluZURvd24iLCJDdHJsLUxlZnQiOiJnb0dyb3VwTGVmdCIsIkN0cmwtUmlnaHQiOiJnb0dyb3VwUmlnaHQiLCJBbHQtTGVmdCI6ImdvTGluZVN0YXJ0IiwiQWx0LVJpZ2h0IjoiZ29MaW5lRW5kIiwiQ3RybC1CYWNrc3BhY2UiOiJkZWxHcm91cEJlZm9yZSIsIkN0cmwtRGVsZXRlIjoiZGVsR3JvdXBBZnRlciIsIkN0cmwtUyI6InNhdmUiLCJDdHJsLUYiOiJmaW5kIiwiQ3RybC1HIjoiZmluZE5leHQiLCJTaGlmdC1DdHJsLUciOiJmaW5kUHJldiIsIlNoaWZ0LUN0cmwtRiI6InJlcGxhY2UiLCJTaGlmdC1DdHJsLVIiOiJyZXBsYWNlQWxsIiwiQ3RybC1bIjoiaW5kZW50TGVzcyIsIkN0cmwtXSI6ImluZGVudE1vcmUiLCJDdHJsLVUiOiJ1bmRvU2VsZWN0aW9uIiwiU2hpZnQtQ3RybC1VIjoicmVkb1NlbGVjdGlvbiIsIkFsdC1VIjoicmVkb1NlbGVjdGlvbiIsZmFsbHRocm91Z2g6ImJhc2ljIn0sR3MuZW1hY3N5PXsiQ3RybC1GIjoiZ29DaGFyUmlnaHQiLCJDdHJsLUIiOiJnb0NoYXJMZWZ0IiwiQ3RybC1QIjoiZ29MaW5lVXAiLCJDdHJsLU4iOiJnb0xpbmVEb3duIiwiQWx0LUYiOiJnb1dvcmRSaWdodCIsIkFsdC1CIjoiZ29Xb3JkTGVmdCIsIkN0cmwtQSI6ImdvTGluZVN0YXJ0IiwiQ3RybC1FIjoiZ29MaW5lRW5kIiwiQ3RybC1WIjoiZ29QYWdlRG93biIsIlNoaWZ0LUN0cmwtViI6ImdvUGFnZVVwIiwiQ3RybC1EIjoiZGVsQ2hhckFmdGVyIiwiQ3RybC1IIjoiZGVsQ2hhckJlZm9yZSIsIkFsdC1EIjoiZGVsV29yZEFmdGVyIiwiQWx0LUJhY2tzcGFjZSI6ImRlbFdvcmRCZWZvcmUiLCJDdHJsLUsiOiJraWxsTGluZSIsIkN0cmwtVCI6InRyYW5zcG9zZUNoYXJzIiwiQ3RybC1PIjoib3BlbkxpbmUifSxHcy5tYWNEZWZhdWx0PXsiQ21kLUEiOiJzZWxlY3RBbGwiLCJDbWQtRCI6ImRlbGV0ZUxpbmUiLCJDbWQtWiI6InVuZG8iLCJTaGlmdC1DbWQtWiI6InJlZG8iLCJDbWQtWSI6InJlZG8iLCJDbWQtSG9tZSI6ImdvRG9jU3RhcnQiLCJDbWQtVXAiOiJnb0RvY1N0YXJ0IiwiQ21kLUVuZCI6ImdvRG9jRW5kIiwiQ21kLURvd24iOiJnb0RvY0VuZCIsIkFsdC1MZWZ0IjoiZ29Hcm91cExlZnQiLCJBbHQtUmlnaHQiOiJnb0dyb3VwUmlnaHQiLCJDbWQtTGVmdCI6ImdvTGluZUxlZnQiLCJDbWQtUmlnaHQiOiJnb0xpbmVSaWdodCIsIkFsdC1CYWNrc3BhY2UiOiJkZWxHcm91cEJlZm9yZSIsIkN0cmwtQWx0LUJhY2tzcGFjZSI6ImRlbEdyb3VwQWZ0ZXIiLCJBbHQtRGVsZXRlIjoiZGVsR3JvdXBBZnRlciIsIkNtZC1TIjoic2F2ZSIsIkNtZC1GIjoiZmluZCIsIkNtZC1HIjoiZmluZE5leHQiLCJTaGlmdC1DbWQtRyI6ImZpbmRQcmV2IiwiQ21kLUFsdC1GIjoicmVwbGFjZSIsIlNoaWZ0LUNtZC1BbHQtRiI6InJlcGxhY2VBbGwiLCJDbWQtWyI6ImluZGVudExlc3MiLCJDbWQtXSI6ImluZGVudE1vcmUiLCJDbWQtQmFja3NwYWNlIjoiZGVsV3JhcHBlZExpbmVMZWZ0IiwiQ21kLURlbGV0ZSI6ImRlbFdyYXBwZWRMaW5lUmlnaHQiLCJDbWQtVSI6InVuZG9TZWxlY3Rpb24iLCJTaGlmdC1DbWQtVSI6InJlZG9TZWxlY3Rpb24iLCJDdHJsLVVwIjoiZ29Eb2NTdGFydCIsIkN0cmwtRG93biI6ImdvRG9jRW5kIixmYWxsdGhyb3VnaDpbImJhc2ljIiwiZW1hY3N5Il19LEdzLmRlZmF1bHQ9RmE/R3MubWFjRGVmYXVsdDpHcy5wY0RlZmF1bHQ7dmFyIFZzPXtzZWxlY3RBbGw6VGksc2luZ2xlU2VsZWN0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiBlLnNldFNlbGVjdGlvbihlLmdldEN1cnNvcigiYW5jaG9yIiksZS5nZXRDdXJzb3IoImhlYWQiKSxxYSl9LGtpbGxMaW5lOmZ1bmN0aW9uKGUpe3JldHVybiBmbyhlLGZ1bmN0aW9uKHQpe2lmKHQuZW1wdHkoKSl7dmFyIG49QShlLmRvYyx0LmhlYWQubGluZSkudGV4dC5sZW5ndGg7cmV0dXJuIHQuaGVhZC5jaD09biYmdC5oZWFkLmxpbmU8ZS5sYXN0TGluZSgpP3tmcm9tOnQuaGVhZCx0bzpQKHQuaGVhZC5saW5lKzEsMCl9Ontmcm9tOnQuaGVhZCx0bzpQKHQuaGVhZC5saW5lLG4pfX1yZXR1cm57ZnJvbTp0LmZyb20oKSx0bzp0LnRvKCl9fSl9LGRlbGV0ZUxpbmU6ZnVuY3Rpb24oZSl7cmV0dXJuIGZvKGUsZnVuY3Rpb24odCl7cmV0dXJue2Zyb206UCh0LmZyb20oKS5saW5lLDApLHRvOnooZS5kb2MsUCh0LnRvKCkubGluZSsxLDApKX19KX0sZGVsTGluZUxlZnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGZvKGUsZnVuY3Rpb24oZSl7cmV0dXJue2Zyb206UChlLmZyb20oKS5saW5lLDApLHRvOmUuZnJvbSgpfX0pfSxkZWxXcmFwcGVkTGluZUxlZnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGZvKGUsZnVuY3Rpb24odCl7dmFyIG49ZS5jaGFyQ29vcmRzKHQuaGVhZCwiZGl2IikudG9wKzU7cmV0dXJue2Zyb206ZS5jb29yZHNDaGFyKHtsZWZ0OjAsdG9wOm59LCJkaXYiKSx0bzp0LmZyb20oKX19KX0sZGVsV3JhcHBlZExpbmVSaWdodDpmdW5jdGlvbihlKXtyZXR1cm4gZm8oZSxmdW5jdGlvbih0KXt2YXIgbj1lLmNoYXJDb29yZHModC5oZWFkLCJkaXYiKS50b3ArNSxyPWUuY29vcmRzQ2hhcih7bGVmdDplLmRpc3BsYXkubGluZURpdi5vZmZzZXRXaWR0aCsxMDAsdG9wOm59LCJkaXYiKTtyZXR1cm57ZnJvbTp0LmZyb20oKSx0bzpyfX0pfSx1bmRvOmZ1bmN0aW9uKGUpe3JldHVybiBlLnVuZG8oKX0scmVkbzpmdW5jdGlvbihlKXtyZXR1cm4gZS5yZWRvKCl9LHVuZG9TZWxlY3Rpb246ZnVuY3Rpb24oZSl7cmV0dXJuIGUudW5kb1NlbGVjdGlvbigpfSxyZWRvU2VsZWN0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiBlLnJlZG9TZWxlY3Rpb24oKX0sZ29Eb2NTdGFydDpmdW5jdGlvbihlKXtyZXR1cm4gZS5leHRlbmRTZWxlY3Rpb24oUChlLmZpcnN0TGluZSgpLDApKX0sZ29Eb2NFbmQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZXh0ZW5kU2VsZWN0aW9uKFAoZS5sYXN0TGluZSgpKSl9LGdvTGluZVN0YXJ0OmZ1bmN0aW9uKGUpe3JldHVybiBlLmV4dGVuZFNlbGVjdGlvbnNCeShmdW5jdGlvbih0KXtyZXR1cm4gdm8oZSx0LmhlYWQubGluZSl9LHtvcmlnaW46Iittb3ZlIixiaWFzOjF9KX0sZ29MaW5lU3RhcnRTbWFydDpmdW5jdGlvbihlKXtyZXR1cm4gZS5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24odCl7cmV0dXJuIHhvKGUsdC5oZWFkKX0se29yaWdpbjoiK21vdmUiLGJpYXM6MX0pfSxnb0xpbmVFbmQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uKHQpe3JldHVybiBibyhlLHQuaGVhZC5saW5lKX0se29yaWdpbjoiK21vdmUiLGJpYXM6LTF9KX0sZ29MaW5lUmlnaHQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uKHQpe3ZhciBuPWUuY3Vyc29yQ29vcmRzKHQuaGVhZCwiZGl2IikudG9wKzU7cmV0dXJuIGUuY29vcmRzQ2hhcih7bGVmdDplLmRpc3BsYXkubGluZURpdi5vZmZzZXRXaWR0aCsxMDAsdG9wOm59LCJkaXYiKX0sV2EpfSxnb0xpbmVMZWZ0OmZ1bmN0aW9uKGUpe3JldHVybiBlLmV4dGVuZFNlbGVjdGlvbnNCeShmdW5jdGlvbih0KXt2YXIgbj1lLmN1cnNvckNvb3Jkcyh0LmhlYWQsImRpdiIpLnRvcCs1O3JldHVybiBlLmNvb3Jkc0NoYXIoe2xlZnQ6MCx0b3A6bn0sImRpdiIpfSxXYSl9LGdvTGluZUxlZnRTbWFydDpmdW5jdGlvbihlKXtyZXR1cm4gZS5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24odCl7dmFyIG49ZS5jdXJzb3JDb29yZHModC5oZWFkLCJkaXYiKS50b3ArNSxyPWUuY29vcmRzQ2hhcih7bGVmdDowLHRvcDpufSwiZGl2Iik7cmV0dXJuIHIuY2g8ZS5nZXRMaW5lKHIubGluZSkuc2VhcmNoKC9cUy8pP3hvKGUsdC5oZWFkKTpyfSxXYSl9LGdvTGluZVVwOmZ1bmN0aW9uKGUpe3JldHVybiBlLm1vdmVWKC0xLCJsaW5lIil9LGdvTGluZURvd246ZnVuY3Rpb24oZSl7cmV0dXJuIGUubW92ZVYoMSwibGluZSIpfSxnb1BhZ2VVcDpmdW5jdGlvbihlKXtyZXR1cm4gZS5tb3ZlVigtMSwicGFnZSIpfSxnb1BhZ2VEb3duOmZ1bmN0aW9uKGUpe3JldHVybiBlLm1vdmVWKDEsInBhZ2UiKX0sZ29DaGFyTGVmdDpmdW5jdGlvbihlKXtyZXR1cm4gZS5tb3ZlSCgtMSwiY2hhciIpfSxnb0NoYXJSaWdodDpmdW5jdGlvbihlKXtyZXR1cm4gZS5tb3ZlSCgxLCJjaGFyIil9LGdvQ29sdW1uTGVmdDpmdW5jdGlvbihlKXtyZXR1cm4gZS5tb3ZlSCgtMSwiY29sdW1uIil9LGdvQ29sdW1uUmlnaHQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGUubW92ZUgoMSwiY29sdW1uIil9LGdvV29yZExlZnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGUubW92ZUgoLTEsIndvcmQiKX0sZ29Hcm91cFJpZ2h0OmZ1bmN0aW9uKGUpe3JldHVybiBlLm1vdmVIKDEsImdyb3VwIil9LGdvR3JvdXBMZWZ0OmZ1bmN0aW9uKGUpe3JldHVybiBlLm1vdmVIKC0xLCJncm91cCIpfSxnb1dvcmRSaWdodDpmdW5jdGlvbihlKXtyZXR1cm4gZS5tb3ZlSCgxLCJ3b3JkIil9LGRlbENoYXJCZWZvcmU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZGVsZXRlSCgtMSwiY2hhciIpfSxkZWxDaGFyQWZ0ZXI6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZGVsZXRlSCgxLCJjaGFyIil9LGRlbFdvcmRCZWZvcmU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZGVsZXRlSCgtMSwid29yZCIpfSxkZWxXb3JkQWZ0ZXI6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZGVsZXRlSCgxLCJ3b3JkIil9LGRlbEdyb3VwQmVmb3JlOmZ1bmN0aW9uKGUpe3JldHVybiBlLmRlbGV0ZUgoLTEsImdyb3VwIil9LGRlbEdyb3VwQWZ0ZXI6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZGVsZXRlSCgxLCJncm91cCIpfSxpbmRlbnRBdXRvOmZ1bmN0aW9uKGUpe3JldHVybiBlLmluZGVudFNlbGVjdGlvbigic21hcnQiKX0saW5kZW50TW9yZTpmdW5jdGlvbihlKXtyZXR1cm4gZS5pbmRlbnRTZWxlY3Rpb24oImFkZCIpfSxpbmRlbnRMZXNzOmZ1bmN0aW9uKGUpe3JldHVybiBlLmluZGVudFNlbGVjdGlvbigic3VidHJhY3QiKX0saW5zZXJ0VGFiOmZ1bmN0aW9uKGUpe3JldHVybiBlLnJlcGxhY2VTZWxlY3Rpb24oIlx0Iil9LGluc2VydFNvZnRUYWI6ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PVtdLG49ZS5saXN0U2VsZWN0aW9ucygpLHI9ZS5vcHRpb25zLnRhYlNpemUsaT0wO2k8bi5sZW5ndGg7aSsrKXt2YXIgbz1uW2ldLmZyb20oKSxhPXAoZS5nZXRMaW5lKG8ubGluZSksby5jaCxyKTt0LnB1c2goaChyLWElcikpfWUucmVwbGFjZVNlbGVjdGlvbnModCl9LGRlZmF1bHRUYWI6ZnVuY3Rpb24oZSl7ZS5zb21ldGhpbmdTZWxlY3RlZCgpP2UuaW5kZW50U2VsZWN0aW9uKCJhZGQiKTplLmV4ZWNDb21tYW5kKCJpbnNlcnRUYWIiKX0sdHJhbnNwb3NlQ2hhcnM6ZnVuY3Rpb24oZSl7cmV0dXJuIGhyKGUsZnVuY3Rpb24oKXtmb3IodmFyIHQ9ZS5saXN0U2VsZWN0aW9ucygpLG49W10scj0wO3I8dC5sZW5ndGg7cisrKWlmKHRbcl0uZW1wdHkoKSl7dmFyIGk9dFtyXS5oZWFkLG89QShlLmRvYyxpLmxpbmUpLnRleHQ7aWYobylpZihpLmNoPT1vLmxlbmd0aCYmKGk9bmV3IFAoaS5saW5lLGkuY2gtMSkpLGkuY2g+MClpPW5ldyBQKGkubGluZSxpLmNoKzEpLGUucmVwbGFjZVJhbmdlKG8uY2hhckF0KGkuY2gtMSkrby5jaGFyQXQoaS5jaC0yKSxQKGkubGluZSxpLmNoLTIpLGksIit0cmFuc3Bvc2UiKTtlbHNlIGlmKGkubGluZT5lLmRvYy5maXJzdCl7dmFyIGE9QShlLmRvYyxpLmxpbmUtMSkudGV4dDthJiYoaT1uZXcgUChpLmxpbmUsMSksZS5yZXBsYWNlUmFuZ2Uoby5jaGFyQXQoMCkrZS5kb2MubGluZVNlcGFyYXRvcigpK2EuY2hhckF0KGEubGVuZ3RoLTEpLFAoaS5saW5lLTEsYS5sZW5ndGgtMSksaSwiK3RyYW5zcG9zZSIpKX1uLnB1c2gobmV3IE9zKGksaSkpfWUuc2V0U2VsZWN0aW9ucyhuKX0pfSxuZXdsaW5lQW5kSW5kZW50OmZ1bmN0aW9uKGUpe3JldHVybiBocihlLGZ1bmN0aW9uKCl7Zm9yKHZhciB0PWUubGlzdFNlbGVjdGlvbnMoKSxuPXQubGVuZ3RoLTE7bj49MDtuLS0pZS5yZXBsYWNlUmFuZ2UoZS5kb2MubGluZVNlcGFyYXRvcigpLHRbbl0uYW5jaG9yLHRbbl0uaGVhZCwiK2lucHV0Iik7dD1lLmxpc3RTZWxlY3Rpb25zKCk7Zm9yKHZhciByPTA7cjx0Lmxlbmd0aDtyKyspZS5pbmRlbnRMaW5lKHRbcl0uZnJvbSgpLmxpbmUsbnVsbCwhMCk7UW4oZSl9KX0sb3BlbkxpbmU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUucmVwbGFjZVNlbGVjdGlvbigiXG4iLCJzdGFydCIpfSx0b2dnbGVPdmVyd3JpdGU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUudG9nZ2xlT3ZlcndyaXRlKCl9fSxxcz1uZXcgJGEsSHM9bnVsbCxXcz1mdW5jdGlvbihlLHQsbil7dGhpcy50aW1lPWUsdGhpcy5wb3M9dCx0aGlzLmJ1dHRvbj1ufTtXcy5wcm90b3R5cGUuY29tcGFyZT1mdW5jdGlvbihlLHQsbil7cmV0dXJuIHRoaXMudGltZSs0MDA+ZSYmMD09TSh0LHRoaXMucG9zKSYmbj09dGhpcy5idXR0b259O3ZhciBRcyxLcyxKcz17dG9TdHJpbmc6ZnVuY3Rpb24oKXtyZXR1cm4iQ29kZU1pcnJvci5Jbml0In19LFlzPXt9LFhzPXt9O1FvLmRlZmF1bHRzPVlzLFFvLm9wdGlvbkhhbmRsZXJzPVhzO3ZhciBacz1bXTtRby5kZWZpbmVJbml0SG9vaz1mdW5jdGlvbihlKXtyZXR1cm4gWnMucHVzaChlKX07dmFyIGV1PW51bGwsdHU9ZnVuY3Rpb24oZSl7dGhpcy5jbT1lLHRoaXMubGFzdEFuY2hvck5vZGU9dGhpcy5sYXN0QW5jaG9yT2Zmc2V0PXRoaXMubGFzdEZvY3VzTm9kZT10aGlzLmxhc3RGb2N1c09mZnNldD1udWxsLHRoaXMucG9sbGluZz1uZXcgJGEsdGhpcy5jb21wb3Npbmc9bnVsbCx0aGlzLmdyYWNlUGVyaW9kPSExLHRoaXMucmVhZERPTVRpbWVvdXQ9bnVsbH07dHUucHJvdG90eXBlLmluaXQ9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlKXtpZighX2UoaSxlKSl7aWYoaS5zb21ldGhpbmdTZWxlY3RlZCgpKVlvKHtsaW5lV2lzZTohMSx0ZXh0OmkuZ2V0U2VsZWN0aW9ucygpfSksImN1dCI9PWUudHlwZSYmaS5yZXBsYWNlU2VsZWN0aW9uKCIiLG51bGwsImN1dCIpO2Vsc2V7aWYoIWkub3B0aW9ucy5saW5lV2lzZUNvcHlDdXQpcmV0dXJuO3ZhciB0PXRhKGkpO1lvKHtsaW5lV2lzZTohMCx0ZXh0OnQudGV4dH0pLCJjdXQiPT1lLnR5cGUmJmkub3BlcmF0aW9uKGZ1bmN0aW9uKCl7aS5zZXRTZWxlY3Rpb25zKHQucmFuZ2VzLDAscWEpLGkucmVwbGFjZVNlbGVjdGlvbigiIixudWxsLCJjdXQiKX0pfWlmKGUuY2xpcGJvYXJkRGF0YSl7ZS5jbGlwYm9hcmREYXRhLmNsZWFyRGF0YSgpO3ZhciBuPWV1LnRleHQuam9pbigiXG4iKTtpZihlLmNsaXBib2FyZERhdGEuc2V0RGF0YSgiVGV4dCIsbiksZS5jbGlwYm9hcmREYXRhLmdldERhdGEoIlRleHQiKT09bilyZXR1cm4gdm9pZCBlLnByZXZlbnREZWZhdWx0KCl9dmFyIGE9cmEoKSxzPWEuZmlyc3RDaGlsZDtpLmRpc3BsYXkubGluZVNwYWNlLmluc2VydEJlZm9yZShhLGkuZGlzcGxheS5saW5lU3BhY2UuZmlyc3RDaGlsZCkscy52YWx1ZT1ldS50ZXh0LmpvaW4oIlxuIik7dmFyIHU9ZG9jdW1lbnQuYWN0aXZlRWxlbWVudDtCYShzKSxzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7aS5kaXNwbGF5LmxpbmVTcGFjZS5yZW1vdmVDaGlsZChhKSx1LmZvY3VzKCksdT09byYmci5zaG93UHJpbWFyeVNlbGVjdGlvbigpfSw1MCl9fXZhciBuPXRoaXMscj10aGlzLGk9ci5jbSxvPXIuZGl2PWUubGluZURpdjtuYShvLGkub3B0aW9ucy5zcGVsbGNoZWNrKSxucyhvLCJwYXN0ZSIsZnVuY3Rpb24oZSl7X2UoaSxlKXx8Wm8oZSxpKXx8eGE8PTExJiZzZXRUaW1lb3V0KG1yKGksZnVuY3Rpb24oKXtyZXR1cm4gbi51cGRhdGVGcm9tRE9NKCl9KSwyMCl9KSxucyhvLCJjb21wb3NpdGlvbnN0YXJ0IixmdW5jdGlvbihlKXtuLmNvbXBvc2luZz17ZGF0YTplLmRhdGEsZG9uZTohMX19KSxucyhvLCJjb21wb3NpdGlvbnVwZGF0ZSIsZnVuY3Rpb24oZSl7bi5jb21wb3Npbmd8fChuLmNvbXBvc2luZz17ZGF0YTplLmRhdGEsZG9uZTohMX0pfSksbnMobywiY29tcG9zaXRpb25lbmQiLGZ1bmN0aW9uKGUpe24uY29tcG9zaW5nJiYoZS5kYXRhIT1uLmNvbXBvc2luZy5kYXRhJiZuLnJlYWRGcm9tRE9NU29vbigpLG4uY29tcG9zaW5nLmRvbmU9ITApfSksbnMobywidG91Y2hzdGFydCIsZnVuY3Rpb24oKXtyZXR1cm4gci5mb3JjZUNvbXBvc2l0aW9uRW5kKCl9KSxucyhvLCJpbnB1dCIsZnVuY3Rpb24oKXtuLmNvbXBvc2luZ3x8bi5yZWFkRnJvbURPTVNvb24oKX0pLG5zKG8sImNvcHkiLHQpLG5zKG8sImN1dCIsdCl9LHR1LnByb3RvdHlwZS5wcmVwYXJlU2VsZWN0aW9uPWZ1bmN0aW9uKCl7dmFyIGU9VG4odGhpcy5jbSwhMSk7cmV0dXJuIGUuZm9jdXM9dGhpcy5jbS5zdGF0ZS5mb2N1c2VkLGV9LHR1LnByb3RvdHlwZS5zaG93U2VsZWN0aW9uPWZ1bmN0aW9uKGUsdCl7ZSYmdGhpcy5jbS5kaXNwbGF5LnZpZXcubGVuZ3RoJiYoKGUuZm9jdXN8fHQpJiZ0aGlzLnNob3dQcmltYXJ5U2VsZWN0aW9uKCksdGhpcy5zaG93TXVsdGlwbGVTZWxlY3Rpb25zKGUpKX0sdHUucHJvdG90eXBlLmdldFNlbGVjdGlvbj1mdW5jdGlvbigpe3JldHVybiB0aGlzLmNtLmRpc3BsYXkud3JhcHBlci5vd25lckRvY3VtZW50LmdldFNlbGVjdGlvbigpfSx0dS5wcm90b3R5cGUuc2hvd1ByaW1hcnlTZWxlY3Rpb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmdldFNlbGVjdGlvbigpLHQ9dGhpcy5jbSxuPXQuZG9jLnNlbC5wcmltYXJ5KCkscj1uLmZyb20oKSxpPW4udG8oKTtpZih0LmRpc3BsYXkudmlld1RvPT10LmRpc3BsYXkudmlld0Zyb218fHIubGluZT49dC5kaXNwbGF5LnZpZXdUb3x8aS5saW5lPHQuZGlzcGxheS52aWV3RnJvbSlyZXR1cm4gdm9pZCBlLnJlbW92ZUFsbFJhbmdlcygpO3ZhciBvPWxhKHQsZS5hbmNob3JOb2RlLGUuYW5jaG9yT2Zmc2V0KSxhPWxhKHQsZS5mb2N1c05vZGUsZS5mb2N1c09mZnNldCk7aWYoIW98fG8uYmFkfHwhYXx8YS5iYWR8fDAhPU0oJChvLGEpLHIpfHwwIT1NKEIobyxhKSxpKSl7dmFyIHM9dC5kaXNwbGF5LnZpZXcsdT1yLmxpbmU+PXQuZGlzcGxheS52aWV3RnJvbSYmYWEodCxyKXx8e25vZGU6c1swXS5tZWFzdXJlLm1hcFsyXSxvZmZzZXQ6MH0sYz1pLmxpbmU8dC5kaXNwbGF5LnZpZXdUbyYmYWEodCxpKTtpZighYyl7dmFyIGw9c1tzLmxlbmd0aC0xXS5tZWFzdXJlLHA9bC5tYXBzP2wubWFwc1tsLm1hcHMubGVuZ3RoLTFdOmwubWFwO2M9e25vZGU6cFtwLmxlbmd0aC0xXSxvZmZzZXQ6cFtwLmxlbmd0aC0yXS1wW3AubGVuZ3RoLTNdfX1pZighdXx8IWMpcmV0dXJuIHZvaWQgZS5yZW1vdmVBbGxSYW5nZXMoKTt2YXIgZixkPWUucmFuZ2VDb3VudCYmZS5nZXRSYW5nZUF0KDApO3RyeXtmPVBhKHUubm9kZSx1Lm9mZnNldCxjLm9mZnNldCxjLm5vZGUpfWNhdGNoKGUpe31mJiYoIW1hJiZ0LnN0YXRlLmZvY3VzZWQ/KGUuY29sbGFwc2UodS5ub2RlLHUub2Zmc2V0KSxmLmNvbGxhcHNlZHx8KGUucmVtb3ZlQWxsUmFuZ2VzKCksZS5hZGRSYW5nZShmKSkpOihlLnJlbW92ZUFsbFJhbmdlcygpLGUuYWRkUmFuZ2UoZikpLGQmJm51bGw9PWUuYW5jaG9yTm9kZT9lLmFkZFJhbmdlKGQpOm1hJiZ0aGlzLnN0YXJ0R3JhY2VQZXJpb2QoKSksdGhpcy5yZW1lbWJlclNlbGVjdGlvbigpfX0sdHUucHJvdG90eXBlLnN0YXJ0R3JhY2VQZXJpb2Q9ZnVuY3Rpb24oKXt2YXIgZT10aGlzO2NsZWFyVGltZW91dCh0aGlzLmdyYWNlUGVyaW9kKSx0aGlzLmdyYWNlUGVyaW9kPXNldFRpbWVvdXQoZnVuY3Rpb24oKXtlLmdyYWNlUGVyaW9kPSExLGUuc2VsZWN0aW9uQ2hhbmdlZCgpJiZlLmNtLm9wZXJhdGlvbihmdW5jdGlvbigpe3JldHVybiBlLmNtLmN1ck9wLnNlbGVjdGlvbkNoYW5nZWQ9ITB9KX0sMjApfSx0dS5wcm90b3R5cGUuc2hvd011bHRpcGxlU2VsZWN0aW9ucz1mdW5jdGlvbihlKXtuKHRoaXMuY20uZGlzcGxheS5jdXJzb3JEaXYsZS5jdXJzb3JzKSxuKHRoaXMuY20uZGlzcGxheS5zZWxlY3Rpb25EaXYsZS5zZWxlY3Rpb24pfSx0dS5wcm90b3R5cGUucmVtZW1iZXJTZWxlY3Rpb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmdldFNlbGVjdGlvbigpO3RoaXMubGFzdEFuY2hvck5vZGU9ZS5hbmNob3JOb2RlLHRoaXMubGFzdEFuY2hvck9mZnNldD1lLmFuY2hvck9mZnNldCx0aGlzLmxhc3RGb2N1c05vZGU9ZS5mb2N1c05vZGUsdGhpcy5sYXN0Rm9jdXNPZmZzZXQ9ZS5mb2N1c09mZnNldH0sdHUucHJvdG90eXBlLnNlbGVjdGlvbkluRWRpdG9yPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5nZXRTZWxlY3Rpb24oKTtpZighZS5yYW5nZUNvdW50KXJldHVybiExO3ZhciB0PWUuZ2V0UmFuZ2VBdCgwKS5jb21tb25BbmNlc3RvckNvbnRhaW5lcjtyZXR1cm4gbyh0aGlzLmRpdix0KX0sdHUucHJvdG90eXBlLmZvY3VzPWZ1bmN0aW9uKCl7Im5vY3Vyc29yIiE9dGhpcy5jbS5vcHRpb25zLnJlYWRPbmx5JiYodGhpcy5zZWxlY3Rpb25JbkVkaXRvcigpfHx0aGlzLnNob3dTZWxlY3Rpb24odGhpcy5wcmVwYXJlU2VsZWN0aW9uKCksITApLHRoaXMuZGl2LmZvY3VzKCkpfSx0dS5wcm90b3R5cGUuYmx1cj1mdW5jdGlvbigpe3RoaXMuZGl2LmJsdXIoKX0sdHUucHJvdG90eXBlLmdldEZpZWxkPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZGl2fSx0dS5wcm90b3R5cGUuc3VwcG9ydHNUb3VjaD1mdW5jdGlvbigpe3JldHVybiEwfSx0dS5wcm90b3R5cGUucmVjZWl2ZWRGb2N1cz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXt0LmNtLnN0YXRlLmZvY3VzZWQmJih0LnBvbGxTZWxlY3Rpb24oKSx0LnBvbGxpbmcuc2V0KHQuY20ub3B0aW9ucy5wb2xsSW50ZXJ2YWwsZSkpfXZhciB0PXRoaXM7dGhpcy5zZWxlY3Rpb25JbkVkaXRvcigpP3RoaXMucG9sbFNlbGVjdGlvbigpOmhyKHRoaXMuY20sZnVuY3Rpb24oKXtyZXR1cm4gdC5jbS5jdXJPcC5zZWxlY3Rpb25DaGFuZ2VkPSEwfSksdGhpcy5wb2xsaW5nLnNldCh0aGlzLmNtLm9wdGlvbnMucG9sbEludGVydmFsLGUpfSx0dS5wcm90b3R5cGUuc2VsZWN0aW9uQ2hhbmdlZD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuZ2V0U2VsZWN0aW9uKCk7cmV0dXJuIGUuYW5jaG9yTm9kZSE9dGhpcy5sYXN0QW5jaG9yTm9kZXx8ZS5hbmNob3JPZmZzZXQhPXRoaXMubGFzdEFuY2hvck9mZnNldHx8ZS5mb2N1c05vZGUhPXRoaXMubGFzdEZvY3VzTm9kZXx8ZS5mb2N1c09mZnNldCE9dGhpcy5sYXN0Rm9jdXNPZmZzZXR9LHR1LnByb3RvdHlwZS5wb2xsU2VsZWN0aW9uPWZ1bmN0aW9uKCl7aWYobnVsbD09dGhpcy5yZWFkRE9NVGltZW91dCYmIXRoaXMuZ3JhY2VQZXJpb2QmJnRoaXMuc2VsZWN0aW9uQ2hhbmdlZCgpKXt2YXIgZT10aGlzLmdldFNlbGVjdGlvbigpLHQ9dGhpcy5jbTtpZihUYSYmRGEmJnRoaXMuY20ub3B0aW9ucy5ndXR0ZXJzLmxlbmd0aCYmc2EoZS5hbmNob3JOb2RlKSlyZXR1cm4gdGhpcy5jbS50cmlnZ2VyT25LZXlEb3duKHt0eXBlOiJrZXlkb3duIixrZXlDb2RlOjgscHJldmVudERlZmF1bHQ6TWF0aC5hYnN9KSx0aGlzLmJsdXIoKSx2b2lkIHRoaXMuZm9jdXMoKTtpZighdGhpcy5jb21wb3Npbmcpe3RoaXMucmVtZW1iZXJTZWxlY3Rpb24oKTt2YXIgbj1sYSh0LGUuYW5jaG9yTm9kZSxlLmFuY2hvck9mZnNldCkscj1sYSh0LGUuZm9jdXNOb2RlLGUuZm9jdXNPZmZzZXQpO24mJnImJmhyKHQsZnVuY3Rpb24oKXtDaSh0LmRvYyxVcihuLHIpLHFhKSwobi5iYWR8fHIuYmFkKSYmKHQuY3VyT3Auc2VsZWN0aW9uQ2hhbmdlZD0hMCl9KX19fSx0dS5wcm90b3R5cGUucG9sbENvbnRlbnQ9ZnVuY3Rpb24oKXtudWxsIT10aGlzLnJlYWRET01UaW1lb3V0JiYoY2xlYXJUaW1lb3V0KHRoaXMucmVhZERPTVRpbWVvdXQpLHRoaXMucmVhZERPTVRpbWVvdXQ9bnVsbCk7dmFyIGU9dGhpcy5jbSx0PWUuZGlzcGxheSxuPWUuZG9jLnNlbC5wcmltYXJ5KCkscj1uLmZyb20oKSxpPW4udG8oKTtpZigwPT1yLmNoJiZyLmxpbmU+ZS5maXJzdExpbmUoKSYmKHI9UChyLmxpbmUtMSxBKGUuZG9jLHIubGluZS0xKS5sZW5ndGgpKSxpLmNoPT1BKGUuZG9jLGkubGluZSkudGV4dC5sZW5ndGgmJmkubGluZTxlLmxhc3RMaW5lKCkmJihpPVAoaS5saW5lKzEsMCkpLHIubGluZTx0LnZpZXdGcm9tfHxpLmxpbmU+dC52aWV3VG8tMSlyZXR1cm4hMTt2YXIgbyxhLHM7ci5saW5lPT10LnZpZXdGcm9tfHwwPT0obz1BbihlLHIubGluZSkpPyhhPUYodC52aWV3WzBdLmxpbmUpLHM9dC52aWV3WzBdLm5vZGUpOihhPUYodC52aWV3W29dLmxpbmUpLHM9dC52aWV3W28tMV0ubm9kZS5uZXh0U2libGluZyk7dmFyIHUsYyxsPUFuKGUsaS5saW5lKTtpZihsPT10LnZpZXcubGVuZ3RoLTE/KHU9dC52aWV3VG8tMSxjPXQubGluZURpdi5sYXN0Q2hpbGQpOih1PUYodC52aWV3W2wrMV0ubGluZSktMSxjPXQudmlld1tsKzFdLm5vZGUucHJldmlvdXNTaWJsaW5nKSwhcylyZXR1cm4hMTtmb3IodmFyIHA9ZS5kb2Muc3BsaXRMaW5lcyhjYShlLHMsYyxhLHUpKSxmPV8oZS5kb2MsUChhLDApLFAodSxBKGUuZG9jLHUpLnRleHQubGVuZ3RoKSk7cC5sZW5ndGg+MSYmZi5sZW5ndGg+MTspaWYobShwKT09bShmKSlwLnBvcCgpLGYucG9wKCksdS0tO2Vsc2V7aWYocFswXSE9ZlswXSlicmVhaztwLnNoaWZ0KCksZi5zaGlmdCgpLGErK31mb3IodmFyIGQ9MCxoPTAsZz1wWzBdLHk9ZlswXSx2PU1hdGgubWluKGcubGVuZ3RoLHkubGVuZ3RoKTtkPHYmJmcuY2hhckNvZGVBdChkKT09eS5jaGFyQ29kZUF0KGQpOykrK2Q7Zm9yKHZhciBiPW0ocCkseD1tKGYpLEM9TWF0aC5taW4oYi5sZW5ndGgtKDE9PXAubGVuZ3RoP2Q6MCkseC5sZW5ndGgtKDE9PWYubGVuZ3RoP2Q6MCkpO2g8QyYmYi5jaGFyQ29kZUF0KGIubGVuZ3RoLWgtMSk9PXguY2hhckNvZGVBdCh4Lmxlbmd0aC1oLTEpOykrK2g7aWYoMT09cC5sZW5ndGgmJjE9PWYubGVuZ3RoJiZhPT1yLmxpbmUpZm9yKDtkJiZkPnIuY2gmJmIuY2hhckNvZGVBdChiLmxlbmd0aC1oLTEpPT14LmNoYXJDb2RlQXQoeC5sZW5ndGgtaC0xKTspZC0tLGgrKztwW3AubGVuZ3RoLTFdPWIuc2xpY2UoMCxiLmxlbmd0aC1oKS5yZXBsYWNlKC9eXHUyMDBiKy8sIiIpLHBbMF09cFswXS5zbGljZShkKS5yZXBsYWNlKC9cdTIwMGIrJC8sIiIpO3ZhciBFPVAoYSxkKSxEPVAodSxmLmxlbmd0aD9tKGYpLmxlbmd0aC1oOjApO3JldHVybiBwLmxlbmd0aD4xfHxwWzBdfHxNKEUsRCk/KGppKGUuZG9jLHAsRSxELCIraW5wdXQiKSwhMCk6dm9pZCAwfSx0dS5wcm90b3R5cGUuZW5zdXJlUG9sbGVkPWZ1bmN0aW9uKCl7dGhpcy5mb3JjZUNvbXBvc2l0aW9uRW5kKCl9LHR1LnByb3RvdHlwZS5yZXNldD1mdW5jdGlvbigpe3RoaXMuZm9yY2VDb21wb3NpdGlvbkVuZCgpfSx0dS5wcm90b3R5cGUuZm9yY2VDb21wb3NpdGlvbkVuZD1mdW5jdGlvbigpe3RoaXMuY29tcG9zaW5nJiYoY2xlYXJUaW1lb3V0KHRoaXMucmVhZERPTVRpbWVvdXQpLHRoaXMuY29tcG9zaW5nPW51bGwsdGhpcy51cGRhdGVGcm9tRE9NKCksdGhpcy5kaXYuYmx1cigpLHRoaXMuZGl2LmZvY3VzKCkpfSx0dS5wcm90b3R5cGUucmVhZEZyb21ET01Tb29uPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcztudWxsPT10aGlzLnJlYWRET01UaW1lb3V0JiYodGhpcy5yZWFkRE9NVGltZW91dD1zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7aWYoZS5yZWFkRE9NVGltZW91dD1udWxsLGUuY29tcG9zaW5nKXtpZighZS5jb21wb3NpbmcuZG9uZSlyZXR1cm47ZS5jb21wb3Npbmc9bnVsbH1lLnVwZGF0ZUZyb21ET00oKX0sODApKX0sdHUucHJvdG90eXBlLnVwZGF0ZUZyb21ET009ZnVuY3Rpb24oKXt2YXIgZT10aGlzOyF0aGlzLmNtLmlzUmVhZE9ubHkoKSYmdGhpcy5wb2xsQ29udGVudCgpfHxocih0aGlzLmNtLGZ1bmN0aW9uKCl7cmV0dXJuIHZyKGUuY20pfSl9LHR1LnByb3RvdHlwZS5zZXRVbmVkaXRhYmxlPWZ1bmN0aW9uKGUpe2UuY29udGVudEVkaXRhYmxlPSJmYWxzZSJ9LHR1LnByb3RvdHlwZS5vbktleVByZXNzPWZ1bmN0aW9uKGUpezA9PWUuY2hhckNvZGV8fHRoaXMuY29tcG9zaW5nfHwoZS5wcmV2ZW50RGVmYXVsdCgpLHRoaXMuY20uaXNSZWFkT25seSgpfHxtcih0aGlzLmNtLFhvKSh0aGlzLmNtLFN0cmluZy5mcm9tQ2hhckNvZGUobnVsbD09ZS5jaGFyQ29kZT9lLmtleUNvZGU6ZS5jaGFyQ29kZSksMCkpfSx0dS5wcm90b3R5cGUucmVhZE9ubHlDaGFuZ2VkPWZ1bmN0aW9uKGUpe3RoaXMuZGl2LmNvbnRlbnRFZGl0YWJsZT1TdHJpbmcoIm5vY3Vyc29yIiE9ZSl9LHR1LnByb3RvdHlwZS5vbkNvbnRleHRNZW51PWZ1bmN0aW9uKCl7fSx0dS5wcm90b3R5cGUucmVzZXRQb3NpdGlvbj1mdW5jdGlvbigpe30sdHUucHJvdG90eXBlLm5lZWRzQ29udGVudEF0dHJpYnV0ZT0hMDt2YXIgbnU9ZnVuY3Rpb24oZSl7dGhpcy5jbT1lLHRoaXMucHJldklucHV0PSIiLHRoaXMucG9sbGluZ0Zhc3Q9ITEsdGhpcy5wb2xsaW5nPW5ldyAkYSx0aGlzLmhhc1NlbGVjdGlvbj0hMSx0aGlzLmNvbXBvc2luZz1udWxsfTtudS5wcm90b3R5cGUuaW5pdD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUpe2lmKCFfZShpLGUpKXtpZihpLnNvbWV0aGluZ1NlbGVjdGVkKCkpWW8oe2xpbmVXaXNlOiExLHRleHQ6aS5nZXRTZWxlY3Rpb25zKCl9KTtlbHNle2lmKCFpLm9wdGlvbnMubGluZVdpc2VDb3B5Q3V0KXJldHVybjt2YXIgdD10YShpKTtZbyh7bGluZVdpc2U6ITAsdGV4dDp0LnRleHR9KSwiY3V0Ij09ZS50eXBlP2kuc2V0U2VsZWN0aW9ucyh0LnJhbmdlcyxudWxsLHFhKTooci5wcmV2SW5wdXQ9IiIsby52YWx1ZT10LnRleHQuam9pbigiXG4iKSxCYShvKSl9ImN1dCI9PWUudHlwZSYmKGkuc3RhdGUuY3V0SW5jb21pbmc9ITApfX12YXIgbj10aGlzLHI9dGhpcyxpPXRoaXMuY207dGhpcy5jcmVhdGVGaWVsZChlKTt2YXIgbz10aGlzLnRleHRhcmVhO2Uud3JhcHBlci5pbnNlcnRCZWZvcmUodGhpcy53cmFwcGVyLGUud3JhcHBlci5maXJzdENoaWxkKSxfYSYmKG8uc3R5bGUud2lkdGg9IjBweCIpLG5zKG8sImlucHV0IixmdW5jdGlvbigpe2JhJiZ4YT49OSYmbi5oYXNTZWxlY3Rpb24mJihuLmhhc1NlbGVjdGlvbj1udWxsKSxyLnBvbGwoKX0pLG5zKG8sInBhc3RlIixmdW5jdGlvbihlKXtfZShpLGUpfHxabyhlLGkpfHwoaS5zdGF0ZS5wYXN0ZUluY29taW5nPSEwLHIuZmFzdFBvbGwoKSl9KSxucyhvLCJjdXQiLHQpLG5zKG8sImNvcHkiLHQpLG5zKGUuc2Nyb2xsZXIsInBhc3RlIixmdW5jdGlvbih0KXtNdChlLHQpfHxfZShpLHQpfHwoaS5zdGF0ZS5wYXN0ZUluY29taW5nPSEwLHIuZm9jdXMoKSl9KSxucyhlLmxpbmVTcGFjZSwic2VsZWN0c3RhcnQiLGZ1bmN0aW9uKHQpe010KGUsdCl8fE5lKHQpfSksbnMobywiY29tcG9zaXRpb25zdGFydCIsZnVuY3Rpb24oKXt2YXIgZT1pLmdldEN1cnNvcigiZnJvbSIpO3IuY29tcG9zaW5nJiZyLmNvbXBvc2luZy5yYW5nZS5jbGVhcigpLHIuY29tcG9zaW5nPXtzdGFydDplLHJhbmdlOmkubWFya1RleHQoZSxpLmdldEN1cnNvcigidG8iKSx7Y2xhc3NOYW1lOiJDb2RlTWlycm9yLWNvbXBvc2luZyJ9KX19KSxucyhvLCJjb21wb3NpdGlvbmVuZCIsZnVuY3Rpb24oKXtyLmNvbXBvc2luZyYmKHIucG9sbCgpLHIuY29tcG9zaW5nLnJhbmdlLmNsZWFyKCksci5jb21wb3Npbmc9bnVsbCl9KX0sbnUucHJvdG90eXBlLmNyZWF0ZUZpZWxkPWZ1bmN0aW9uKGUpe3RoaXMud3JhcHBlcj1yYSgpLHRoaXMudGV4dGFyZWE9dGhpcy53cmFwcGVyLmZpcnN0Q2hpbGR9LG51LnByb3RvdHlwZS5wcmVwYXJlU2VsZWN0aW9uPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jbSx0PWUuZGlzcGxheSxuPWUuZG9jLHI9VG4oZSk7aWYoZS5vcHRpb25zLm1vdmVJbnB1dFdpdGhDdXJzb3Ipe3ZhciBpPWxuKGUsbi5zZWwucHJpbWFyeSgpLmhlYWQsImRpdiIpLG89dC53cmFwcGVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLGE9dC5saW5lRGl2LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO3IudGVUb3A9TWF0aC5tYXgoMCxNYXRoLm1pbih0LndyYXBwZXIuY2xpZW50SGVpZ2h0LTEwLGkudG9wK2EudG9wLW8udG9wKSksci50ZUxlZnQ9TWF0aC5tYXgoMCxNYXRoLm1pbih0LndyYXBwZXIuY2xpZW50V2lkdGgtMTAsaS5sZWZ0K2EubGVmdC1vLmxlZnQpKX1yZXR1cm4gcn0sbnUucHJvdG90eXBlLnNob3dTZWxlY3Rpb249ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5jbSxyPXQuZGlzcGxheTtuKHIuY3Vyc29yRGl2LGUuY3Vyc29ycyksbihyLnNlbGVjdGlvbkRpdixlLnNlbGVjdGlvbiksbnVsbCE9ZS50ZVRvcCYmKHRoaXMud3JhcHBlci5zdHlsZS50b3A9ZS50ZVRvcCsicHgiLHRoaXMud3JhcHBlci5zdHlsZS5sZWZ0PWUudGVMZWZ0KyJweCIpfSxudS5wcm90b3R5cGUucmVzZXQ9ZnVuY3Rpb24oZSl7aWYoIXRoaXMuY29udGV4dE1lbnVQZW5kaW5nJiYhdGhpcy5jb21wb3Npbmcpe3ZhciB0PXRoaXMuY207aWYodC5zb21ldGhpbmdTZWxlY3RlZCgpKXt0aGlzLnByZXZJbnB1dD0iIjt2YXIgbj10LmdldFNlbGVjdGlvbigpO3RoaXMudGV4dGFyZWEudmFsdWU9bix0LnN0YXRlLmZvY3VzZWQmJkJhKHRoaXMudGV4dGFyZWEpLGJhJiZ4YT49OSYmKHRoaXMuaGFzU2VsZWN0aW9uPW4pfWVsc2UgZXx8KHRoaXMucHJldklucHV0PXRoaXMudGV4dGFyZWEudmFsdWU9IiIsYmEmJnhhPj05JiYodGhpcy5oYXNTZWxlY3Rpb249bnVsbCkpfX0sbnUucHJvdG90eXBlLmdldEZpZWxkPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudGV4dGFyZWF9LG51LnByb3RvdHlwZS5zdXBwb3J0c1RvdWNoPWZ1bmN0aW9uKCl7cmV0dXJuITF9LG51LnByb3RvdHlwZS5mb2N1cz1mdW5jdGlvbigpe2lmKCJub2N1cnNvciIhPXRoaXMuY20ub3B0aW9ucy5yZWFkT25seSYmKCFPYXx8YSgpIT10aGlzLnRleHRhcmVhKSl0cnl7dGhpcy50ZXh0YXJlYS5mb2N1cygpfWNhdGNoKGUpe319LG51LnByb3RvdHlwZS5ibHVyPWZ1bmN0aW9uKCl7dGhpcy50ZXh0YXJlYS5ibHVyKCl9LG51LnByb3RvdHlwZS5yZXNldFBvc2l0aW9uPWZ1bmN0aW9uKCl7dGhpcy53cmFwcGVyLnN0eWxlLnRvcD10aGlzLndyYXBwZXIuc3R5bGUubGVmdD0wfSxudS5wcm90b3R5cGUucmVjZWl2ZWRGb2N1cz1mdW5jdGlvbigpe3RoaXMuc2xvd1BvbGwoKX0sbnUucHJvdG90eXBlLnNsb3dQb2xsPWZ1bmN0aW9uKCl7dmFyIGU9dGhpczt0aGlzLnBvbGxpbmdGYXN0fHx0aGlzLnBvbGxpbmcuc2V0KHRoaXMuY20ub3B0aW9ucy5wb2xsSW50ZXJ2YWwsZnVuY3Rpb24oKXtlLnBvbGwoKSxlLmNtLnN0YXRlLmZvY3VzZWQmJmUuc2xvd1BvbGwoKX0pfSxudS5wcm90b3R5cGUuZmFzdFBvbGw9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7bi5wb2xsKCl8fHQ/KG4ucG9sbGluZ0Zhc3Q9ITEsbi5zbG93UG9sbCgpKToodD0hMCxuLnBvbGxpbmcuc2V0KDYwLGUpKX12YXIgdD0hMSxuPXRoaXM7bi5wb2xsaW5nRmFzdD0hMCxuLnBvbGxpbmcuc2V0KDIwLGUpfSxudS5wcm90b3R5cGUucG9sbD1mdW5jdGlvbigpe3ZhciBlPXRoaXMsdD10aGlzLmNtLG49dGhpcy50ZXh0YXJlYSxyPXRoaXMucHJldklucHV0O2lmKHRoaXMuY29udGV4dE1lbnVQZW5kaW5nfHwhdC5zdGF0ZS5mb2N1c2VkfHxvcyhuKSYmIXImJiF0aGlzLmNvbXBvc2luZ3x8dC5pc1JlYWRPbmx5KCl8fHQub3B0aW9ucy5kaXNhYmxlSW5wdXR8fHQuc3RhdGUua2V5U2VxKXJldHVybiExO3ZhciBpPW4udmFsdWU7aWYoaT09ciYmIXQuc29tZXRoaW5nU2VsZWN0ZWQoKSlyZXR1cm4hMTtpZihiYSYmeGE+PTkmJnRoaXMuaGFzU2VsZWN0aW9uPT09aXx8RmEmJi9bXHVmNzAwLVx1ZjdmZl0vLnRlc3QoaSkpcmV0dXJuIHQuZGlzcGxheS5pbnB1dC5yZXNldCgpLCExO2lmKHQuZG9jLnNlbD09dC5kaXNwbGF5LnNlbEZvckNvbnRleHRNZW51KXt2YXIgbz1pLmNoYXJDb2RlQXQoMCk7aWYoODIwMyE9b3x8cnx8KHI9Ilx1MjAwYiIpLDg2NjY9PW8pcmV0dXJuIHRoaXMucmVzZXQoKSx0aGlzLmNtLmV4ZWNDb21tYW5kKCJ1bmRvIil9Zm9yKHZhciBhPTAscz1NYXRoLm1pbihyLmxlbmd0aCxpLmxlbmd0aCk7YTxzJiZyLmNoYXJDb2RlQXQoYSk9PWkuY2hhckNvZGVBdChhKTspKythO3JldHVybiBocih0LGZ1bmN0aW9uKCl7WG8odCxpLnNsaWNlKGEpLHIubGVuZ3RoLWEsbnVsbCxlLmNvbXBvc2luZz8iKmNvbXBvc2UiOm51bGwpLGkubGVuZ3RoPjFlM3x8aS5pbmRleE9mKCJcbiIpPi0xP24udmFsdWU9ZS5wcmV2SW5wdXQ9IiI6ZS5wcmV2SW5wdXQ9aSxlLmNvbXBvc2luZyYmKGUuY29tcG9zaW5nLnJhbmdlLmNsZWFyKCksZS5jb21wb3NpbmcucmFuZ2U9dC5tYXJrVGV4dChlLmNvbXBvc2luZy5zdGFydCx0LmdldEN1cnNvcigidG8iKSx7Y2xhc3NOYW1lOiJDb2RlTWlycm9yLWNvbXBvc2luZyJ9KSl9KSwhMH0sbnUucHJvdG90eXBlLmVuc3VyZVBvbGxlZD1mdW5jdGlvbigpe3RoaXMucG9sbGluZ0Zhc3QmJnRoaXMucG9sbCgpJiYodGhpcy5wb2xsaW5nRmFzdD0hMSl9LG51LnByb3RvdHlwZS5vbktleVByZXNzPWZ1bmN0aW9uKCl7YmEmJnhhPj05JiYodGhpcy5oYXNTZWxlY3Rpb249bnVsbCksdGhpcy5mYXN0UG9sbCgpfSxudS5wcm90b3R5cGUub25Db250ZXh0TWVudT1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7aWYobnVsbCE9YS5zZWxlY3Rpb25TdGFydCl7dmFyIGU9aS5zb21ldGhpbmdTZWxlY3RlZCgpLHQ9Ilx1MjAwYiIrKGU/YS52YWx1ZToiIik7YS52YWx1ZT0iXHUyMWRhIixhLnZhbHVlPXQsci5wcmV2SW5wdXQ9ZT8iIjoiXHUyMDBiIixhLnNlbGVjdGlvblN0YXJ0PTEsYS5zZWxlY3Rpb25FbmQ9dC5sZW5ndGgsby5zZWxGb3JDb250ZXh0TWVudT1pLmRvYy5zZWx9fWZ1bmN0aW9uIG4oKXtpZihyLmNvbnRleHRNZW51UGVuZGluZz0hMSxyLndyYXBwZXIuc3R5bGUuY3NzVGV4dD1sLGEuc3R5bGUuY3NzVGV4dD1jLGJhJiZ4YTw5JiZvLnNjcm9sbGJhcnMuc2V0U2Nyb2xsVG9wKG8uc2Nyb2xsZXIuc2Nyb2xsVG9wPXUpLG51bGwhPWEuc2VsZWN0aW9uU3RhcnQpeyghYmF8fGJhJiZ4YTw5KSYmdCgpO3ZhciBlPTAsbj1mdW5jdGlvbigpe28uc2VsRm9yQ29udGV4dE1lbnU9PWkuZG9jLnNlbCYmMD09YS5zZWxlY3Rpb25TdGFydCYmYS5zZWxlY3Rpb25FbmQ+MCYmIlx1MjAwYiI9PXIucHJldklucHV0P21yKGksVGkpKGkpOmUrKzwxMD9vLmRldGVjdGluZ1NlbGVjdEFsbD1zZXRUaW1lb3V0KG4sNTAwKTooby5zZWxGb3JDb250ZXh0TWVudT1udWxsLG8uaW5wdXQucmVzZXQoKSl9O28uZGV0ZWN0aW5nU2VsZWN0QWxsPXNldFRpbWVvdXQobiwyMDApfX12YXIgcj10aGlzLGk9ci5jbSxvPWkuZGlzcGxheSxhPXIudGV4dGFyZWEscz1rbihpLGUpLHU9by5zY3JvbGxlci5zY3JvbGxUb3A7aWYocyYmIXdhKXtpLm9wdGlvbnMucmVzZXRTZWxlY3Rpb25PbkNvbnRleHRNZW51JiYtMT09aS5kb2Muc2VsLmNvbnRhaW5zKHMpJiZtcihpLENpKShpLmRvYyxVcihzKSxxYSk7dmFyIGM9YS5zdHlsZS5jc3NUZXh0LGw9ci53cmFwcGVyLnN0eWxlLmNzc1RleHQ7ci53cmFwcGVyLnN0eWxlLmNzc1RleHQ9InBvc2l0aW9uOiBhYnNvbHV0ZSI7dmFyIHA9ci53cmFwcGVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO2Euc3R5bGUuY3NzVGV4dD0icG9zaXRpb246IGFic29sdXRlOyB3aWR0aDogMzBweDsgaGVpZ2h0OiAzMHB4O1xuICAgICAgdG9wOiAiKyhlLmNsaWVudFktcC50b3AtNSkrInB4OyBsZWZ0OiAiKyhlLmNsaWVudFgtcC5sZWZ0LTUpKyJweDtcbiAgICAgIHotaW5kZXg6IDEwMDA7IGJhY2tncm91bmQ6ICIrKGJhPyJyZ2JhKDI1NSwgMjU1LCAyNTUsIC4wNSkiOiJ0cmFuc3BhcmVudCIpKyI7XG4gICAgICBvdXRsaW5lOiBub25lOyBib3JkZXItd2lkdGg6IDA7IG91dGxpbmU6IG5vbmU7IG92ZXJmbG93OiBoaWRkZW47IG9wYWNpdHk6IC4wNTsgZmlsdGVyOiBhbHBoYShvcGFjaXR5PTUpOyI7dmFyIGY7aWYoQ2EmJihmPXdpbmRvdy5zY3JvbGxZKSxvLmlucHV0LmZvY3VzKCksQ2EmJndpbmRvdy5zY3JvbGxUbyhudWxsLGYpLG8uaW5wdXQucmVzZXQoKSxpLnNvbWV0aGluZ1NlbGVjdGVkKCl8fChhLnZhbHVlPXIucHJldklucHV0PSIgIiksci5jb250ZXh0TWVudVBlbmRpbmc9ITAsby5zZWxGb3JDb250ZXh0TWVudT1pLmRvYy5zZWwsY2xlYXJUaW1lb3V0KG8uZGV0ZWN0aW5nU2VsZWN0QWxsKSxiYSYmeGE+PTkmJnQoKSxqYSl7UGUoZSk7dmFyIGQ9ZnVuY3Rpb24oKXtrZSh3aW5kb3csIm1vdXNldXAiLGQpLHNldFRpbWVvdXQobiwyMCl9O25zKHdpbmRvdywibW91c2V1cCIsZCl9ZWxzZSBzZXRUaW1lb3V0KG4sNTApfX0sbnUucHJvdG90eXBlLnJlYWRPbmx5Q2hhbmdlZD1mdW5jdGlvbihlKXtlfHx0aGlzLnJlc2V0KCksdGhpcy50ZXh0YXJlYS5kaXNhYmxlZD0ibm9jdXJzb3IiPT1lfSxudS5wcm90b3R5cGUuc2V0VW5lZGl0YWJsZT1mdW5jdGlvbigpe30sbnUucHJvdG90eXBlLm5lZWRzQ29udGVudEF0dHJpYnV0ZT0hMSxmdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQscixpLG8pe2UuZGVmYXVsdHNbdF09cixpJiYoblt0XT1vP2Z1bmN0aW9uKGUsdCxuKXtuIT1KcyYmaShlLHQsbil9OmkpfXZhciBuPWUub3B0aW9uSGFuZGxlcnM7ZS5kZWZpbmVPcHRpb249dCxlLkluaXQ9SnMsdCgidmFsdWUiLCIiLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuc2V0VmFsdWUodCl9LCEwKSx0KCJtb2RlIixudWxsLGZ1bmN0aW9uKGUsdCl7ZS5kb2MubW9kZU9wdGlvbj10LFdyKGUpfSwhMCksdCgiaW5kZW50VW5pdCIsMixXciwhMCksdCgiaW5kZW50V2l0aFRhYnMiLCExKSx0KCJzbWFydEluZGVudCIsITApLHQoInRhYlNpemUiLDQsZnVuY3Rpb24oZSl7UXIoZSksbm4oZSksdnIoZSl9LCEwKSx0KCJsaW5lU2VwYXJhdG9yIixudWxsLGZ1bmN0aW9uKGUsdCl7aWYoZS5kb2MubGluZVNlcD10LHQpe3ZhciBuPVtdLHI9ZS5kb2MuZmlyc3Q7ZS5kb2MuaXRlcihmdW5jdGlvbihlKXtmb3IodmFyIGk9MDs7KXt2YXIgbz1lLnRleHQuaW5kZXhPZih0LGkpO2lmKC0xPT1vKWJyZWFrO2k9byt0Lmxlbmd0aCxuLnB1c2goUChyLG8pKX1yKyt9KTtmb3IodmFyIGk9bi5sZW5ndGgtMTtpPj0wO2ktLSlqaShlLmRvYyx0LG5baV0sUChuW2ldLmxpbmUsbltpXS5jaCt0Lmxlbmd0aCkpfX0pLHQoInNwZWNpYWxDaGFycyIsL1tcdTAwMDAtXHUwMDFmXHUwMDdmLVx1MDA5Zlx1MDBhZFx1MDYxY1x1MjAwYi1cdTIwMGZcdTIwMjhcdTIwMjlcdWZlZmZdL2csZnVuY3Rpb24oZSx0LG4pe2Uuc3RhdGUuc3BlY2lhbENoYXJzPW5ldyBSZWdFeHAodC5zb3VyY2UrKHQudGVzdCgiXHQiKT8iIjoifFx0IiksImciKSxuIT1KcyYmZS5yZWZyZXNoKCl9KSx0KCJzcGVjaWFsQ2hhclBsYWNlaG9sZGVyIixsdCxmdW5jdGlvbihlKXtyZXR1cm4gZS5yZWZyZXNoKCl9LCEwKSx0KCJlbGVjdHJpY0NoYXJzIiwhMCksdCgiaW5wdXRTdHlsZSIsT2E/ImNvbnRlbnRlZGl0YWJsZSI6InRleHRhcmVhIixmdW5jdGlvbigpe3Rocm93IG5ldyBFcnJvcigiaW5wdXRTdHlsZSBjYW4gbm90ICh5ZXQpIGJlIGNoYW5nZWQgaW4gYSBydW5uaW5nIGVkaXRvciIpfSwhMCksdCgic3BlbGxjaGVjayIsITEsZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5nZXRJbnB1dEZpZWxkKCkuc3BlbGxjaGVjaz10fSwhMCksdCgicnRsTW92ZVZpc3VhbGx5IiwhSWEpLHQoIndob2xlTGluZVVwZGF0ZUJlZm9yZSIsITApLHQoInRoZW1lIiwiZGVmYXVsdCIsZnVuY3Rpb24oZSl7Vm8oZSkscW8oZSl9LCEwKSx0KCJrZXlNYXAiLCJkZWZhdWx0IixmdW5jdGlvbihlLHQsbil7dmFyIHI9cG8odCksaT1uIT1KcyYmcG8obik7aSYmaS5kZXRhY2gmJmkuZGV0YWNoKGUsciksci5hdHRhY2gmJnIuYXR0YWNoKGUsaXx8bnVsbCl9KSx0KCJleHRyYUtleXMiLG51bGwpLHQoImNvbmZpZ3VyZU1vdXNlIixudWxsKSx0KCJsaW5lV3JhcHBpbmciLCExLFdvLCEwKSx0KCJndXR0ZXJzIixbXSxmdW5jdGlvbihlKXtNcihlLm9wdGlvbnMpLHFvKGUpfSwhMCksdCgiZml4ZWRHdXR0ZXIiLCEwLGZ1bmN0aW9uKGUsdCl7ZS5kaXNwbGF5Lmd1dHRlcnMuc3R5bGUubGVmdD10P0RuKGUuZGlzcGxheSkrInB4IjoiMCIsZS5yZWZyZXNoKCl9LCEwKSx0KCJjb3Zlckd1dHRlck5leHRUb1Njcm9sbGJhciIsITEsZnVuY3Rpb24oZSl7cmV0dXJuIHJyKGUpfSwhMCksdCgic2Nyb2xsYmFyU3R5bGUiLCJuYXRpdmUiLGZ1bmN0aW9uKGUpe29yKGUpLHJyKGUpLGUuZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbFRvcChlLmRvYy5zY3JvbGxUb3ApLGUuZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbExlZnQoZS5kb2Muc2Nyb2xsTGVmdCl9LCEwKSx0KCJsaW5lTnVtYmVycyIsITEsZnVuY3Rpb24oZSl7TXIoZS5vcHRpb25zKSxxbyhlKX0sITApLHQoImZpcnN0TGluZU51bWJlciIsMSxxbywhMCksdCgibGluZU51bWJlckZvcm1hdHRlciIsZnVuY3Rpb24oZSl7cmV0dXJuIGV9LHFvLCEwKSx0KCJzaG93Q3Vyc29yV2hlblNlbGVjdGluZyIsITEsX24sITApLHQoInJlc2V0U2VsZWN0aW9uT25Db250ZXh0TWVudSIsITApLHQoImxpbmVXaXNlQ29weUN1dCIsITApLHQoInBhc3RlTGluZXNQZXJTZWxlY3Rpb24iLCEwKSx0KCJyZWFkT25seSIsITEsZnVuY3Rpb24oZSx0KXsibm9jdXJzb3IiPT10JiYoam4oZSksZS5kaXNwbGF5LmlucHV0LmJsdXIoKSksZS5kaXNwbGF5LmlucHV0LnJlYWRPbmx5Q2hhbmdlZCh0KX0pLHQoImRpc2FibGVJbnB1dCIsITEsZnVuY3Rpb24oZSx0KXt0fHxlLmRpc3BsYXkuaW5wdXQucmVzZXQoKX0sITApLHQoImRyYWdEcm9wIiwhMCxIbyksdCgiYWxsb3dEcm9wRmlsZVR5cGVzIixudWxsKSx0KCJjdXJzb3JCbGlua1JhdGUiLDUzMCksdCgiY3Vyc29yU2Nyb2xsTWFyZ2luIiwwKSx0KCJjdXJzb3JIZWlnaHQiLDEsX24sITApLHQoInNpbmdsZUN1cnNvckhlaWdodFBlckxpbmUiLCEwLF9uLCEwKSx0KCJ3b3JrVGltZSIsMTAwKSx0KCJ3b3JrRGVsYXkiLDEwMCksdCgiZmxhdHRlblNwYW5zIiwhMCxRciwhMCksdCgiYWRkTW9kZUNsYXNzIiwhMSxRciwhMCksdCgicG9sbEludGVydmFsIiwxMDApLHQoInVuZG9EZXB0aCIsMjAwLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuZG9jLmhpc3RvcnkudW5kb0RlcHRoPXR9KSx0KCJoaXN0b3J5RXZlbnREZWxheSIsMTI1MCksdCgidmlld3BvcnRNYXJnaW4iLDEwLGZ1bmN0aW9uKGUpe3JldHVybiBlLnJlZnJlc2goKX0sITApLHQoIm1heEhpZ2hsaWdodExlbmd0aCIsMWU0LFFyLCEwKSx0KCJtb3ZlSW5wdXRXaXRoQ3Vyc29yIiwhMCxmdW5jdGlvbihlLHQpe3R8fGUuZGlzcGxheS5pbnB1dC5yZXNldFBvc2l0aW9uKCl9KSx0KCJ0YWJpbmRleCIsbnVsbCxmdW5jdGlvbihlLHQpe3JldHVybiBlLmRpc3BsYXkuaW5wdXQuZ2V0RmllbGQoKS50YWJJbmRleD10fHwiIn0pLHQoImF1dG9mb2N1cyIsbnVsbCksdCgiZGlyZWN0aW9uIiwibHRyIixmdW5jdGlvbihlLHQpe3JldHVybiBlLmRvYy5zZXREaXJlY3Rpb24odCl9LCEwKX0oUW8pLGZ1bmN0aW9uKGUpe3ZhciB0PWUub3B0aW9uSGFuZGxlcnMsbj1lLmhlbHBlcnM9e307ZS5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOmUsZm9jdXM6ZnVuY3Rpb24oKXt3aW5kb3cuZm9jdXMoKSx0aGlzLmRpc3BsYXkuaW5wdXQuZm9jdXMoKX0sc2V0T3B0aW9uOmZ1bmN0aW9uKGUsbil7dmFyIHI9dGhpcy5vcHRpb25zLGk9cltlXTtyW2VdPT1uJiYibW9kZSIhPWV8fChyW2VdPW4sdC5oYXNPd25Qcm9wZXJ0eShlKSYmbXIodGhpcyx0W2VdKSh0aGlzLG4saSksQWUodGhpcywib3B0aW9uQ2hhbmdlIix0aGlzLGUpKX0sZ2V0T3B0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLm9wdGlvbnNbZV19LGdldERvYzpmdW5jdGlvbigpe3JldHVybiB0aGlzLmRvY30sYWRkS2V5TWFwOmZ1bmN0aW9uKGUsdCl7dGhpcy5zdGF0ZS5rZXlNYXBzW3Q/InB1c2giOiJ1bnNoaWZ0Il0ocG8oZSkpfSxyZW1vdmVLZXlNYXA6ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PXRoaXMuc3RhdGUua2V5TWFwcyxuPTA7bjx0Lmxlbmd0aDsrK24paWYodFtuXT09ZXx8dFtuXS5uYW1lPT1lKXJldHVybiB0LnNwbGljZShuLDEpLCEwfSxhZGRPdmVybGF5OmdyKGZ1bmN0aW9uKHQsbil7dmFyIHI9dC50b2tlbj90OmUuZ2V0TW9kZSh0aGlzLm9wdGlvbnMsdCk7aWYoci5zdGFydFN0YXRlKXRocm93IG5ldyBFcnJvcigiT3ZlcmxheXMgbWF5IG5vdCBiZSBzdGF0ZWZ1bC4iKTt5KHRoaXMuc3RhdGUub3ZlcmxheXMse21vZGU6cixtb2RlU3BlYzp0LG9wYXF1ZTpuJiZuLm9wYXF1ZSxwcmlvcml0eTpuJiZuLnByaW9yaXR5fHwwfSxmdW5jdGlvbihlKXtyZXR1cm4gZS5wcmlvcml0eX0pLHRoaXMuc3RhdGUubW9kZUdlbisrLHZyKHRoaXMpfSkscmVtb3ZlT3ZlcmxheTpncihmdW5jdGlvbihlKXtmb3IodmFyIHQ9dGhpcyxuPXRoaXMuc3RhdGUub3ZlcmxheXMscj0wO3I8bi5sZW5ndGg7KytyKXt2YXIgaT1uW3JdLm1vZGVTcGVjO2lmKGk9PWV8fCJzdHJpbmciPT10eXBlb2YgZSYmaS5uYW1lPT1lKXJldHVybiBuLnNwbGljZShyLDEpLHQuc3RhdGUubW9kZUdlbisrLHZvaWQgdnIodCl9fSksaW5kZW50TGluZTpncihmdW5jdGlvbihlLHQsbil7InN0cmluZyIhPXR5cGVvZiB0JiYibnVtYmVyIiE9dHlwZW9mIHQmJih0PW51bGw9PXQ/dGhpcy5vcHRpb25zLnNtYXJ0SW5kZW50PyJzbWFydCI6InByZXYiOnQ/ImFkZCI6InN1YnRyYWN0IiksSSh0aGlzLmRvYyxlKSYmSm8odGhpcyxlLHQsbil9KSxpbmRlbnRTZWxlY3Rpb246Z3IoZnVuY3Rpb24oZSl7Zm9yKHZhciB0PXRoaXMsbj10aGlzLmRvYy5zZWwucmFuZ2VzLHI9LTEsaT0wO2k8bi5sZW5ndGg7aSsrKXt2YXIgbz1uW2ldO2lmKG8uZW1wdHkoKSlvLmhlYWQubGluZT5yJiYoSm8odCxvLmhlYWQubGluZSxlLCEwKSxyPW8uaGVhZC5saW5lLGk9PXQuZG9jLnNlbC5wcmltSW5kZXgmJlFuKHQpKTtlbHNle3ZhciBhPW8uZnJvbSgpLHM9by50bygpLHU9TWF0aC5tYXgocixhLmxpbmUpO3I9TWF0aC5taW4odC5sYXN0TGluZSgpLHMubGluZS0ocy5jaD8wOjEpKSsxO2Zvcih2YXIgYz11O2M8cjsrK2MpSm8odCxjLGUpO3ZhciBsPXQuZG9jLnNlbC5yYW5nZXM7MD09YS5jaCYmbi5sZW5ndGg9PWwubGVuZ3RoJiZsW2ldLmZyb20oKS5jaD4wJiZ5aSh0LmRvYyxpLG5ldyBPcyhhLGxbaV0udG8oKSkscWEpfX19KSxnZXRUb2tlbkF0OmZ1bmN0aW9uKGUsdCl7cmV0dXJuIHR0KHRoaXMsZSx0KX0sZ2V0TGluZVRva2VuczpmdW5jdGlvbihlLHQpe3JldHVybiB0dCh0aGlzLFAoZSksdCwhMCl9LGdldFRva2VuVHlwZUF0OmZ1bmN0aW9uKGUpe2U9eih0aGlzLmRvYyxlKTt2YXIgdCxuPUplKHRoaXMsQSh0aGlzLmRvYyxlLmxpbmUpKSxyPTAsaT0obi5sZW5ndGgtMSkvMixvPWUuY2g7aWYoMD09byl0PW5bMl07ZWxzZSBmb3IoOzspe3ZhciBhPXIraT4+MTtpZigoYT9uWzIqYS0xXTowKT49bylpPWE7ZWxzZXtpZighKG5bMiphKzFdPG8pKXt0PW5bMiphKzJdO2JyZWFrfXI9YSsxfX12YXIgcz10P3QuaW5kZXhPZigib3ZlcmxheSAiKTotMTtyZXR1cm4gczwwP3Q6MD09cz9udWxsOnQuc2xpY2UoMCxzLTEpfSxnZXRNb2RlQXQ6ZnVuY3Rpb24odCl7dmFyIG49dGhpcy5kb2MubW9kZTtyZXR1cm4gbi5pbm5lck1vZGU/ZS5pbm5lck1vZGUobix0aGlzLmdldFRva2VuQXQodCkuc3RhdGUpLm1vZGU6bn0sZ2V0SGVscGVyOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuZ2V0SGVscGVycyhlLHQpWzBdfSxnZXRIZWxwZXJzOmZ1bmN0aW9uKGUsdCl7dmFyIHI9dGhpcyxpPVtdO2lmKCFuLmhhc093blByb3BlcnR5KHQpKXJldHVybiBpO3ZhciBvPW5bdF0sYT10aGlzLmdldE1vZGVBdChlKTtpZigic3RyaW5nIj09dHlwZW9mIGFbdF0pb1thW3RdXSYmaS5wdXNoKG9bYVt0XV0pO2Vsc2UgaWYoYVt0XSlmb3IodmFyIHM9MDtzPGFbdF0ubGVuZ3RoO3MrKyl7dmFyIHU9b1thW3RdW3NdXTt1JiZpLnB1c2godSl9ZWxzZSBhLmhlbHBlclR5cGUmJm9bYS5oZWxwZXJUeXBlXT9pLnB1c2gob1thLmhlbHBlclR5cGVdKTpvW2EubmFtZV0mJmkucHVzaChvW2EubmFtZV0pO2Zvcih2YXIgYz0wO2M8by5fZ2xvYmFsLmxlbmd0aDtjKyspe3ZhciBsPW8uX2dsb2JhbFtjXTtsLnByZWQoYSxyKSYmLTE9PWYoaSxsLnZhbCkmJmkucHVzaChsLnZhbCl9cmV0dXJuIGl9LGdldFN0YXRlQWZ0ZXI6ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLmRvYztyZXR1cm4gZT1VKG4sbnVsbD09ZT9uLmZpcnN0K24uc2l6ZS0xOmUpLFllKHRoaXMsZSsxLHQpLnN0YXRlfSxjdXJzb3JDb29yZHM6ZnVuY3Rpb24oZSx0KXt2YXIgbixyPXRoaXMuZG9jLnNlbC5wcmltYXJ5KCk7cmV0dXJuIG49bnVsbD09ZT9yLmhlYWQ6Im9iamVjdCI9PXR5cGVvZiBlP3oodGhpcy5kb2MsZSk6ZT9yLmZyb20oKTpyLnRvKCksbG4odGhpcyxuLHR8fCJwYWdlIil9LGNoYXJDb29yZHM6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gY24odGhpcyx6KHRoaXMuZG9jLGUpLHR8fCJwYWdlIil9LGNvb3Jkc0NoYXI6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZT11bih0aGlzLGUsdHx8InBhZ2UiKSxkbih0aGlzLGUubGVmdCxlLnRvcCl9LGxpbmVBdEhlaWdodDpmdW5jdGlvbihlLHQpe3JldHVybiBlPXVuKHRoaXMse3RvcDplLGxlZnQ6MH0sdHx8InBhZ2UiKS50b3AsTih0aGlzLmRvYyxlK3RoaXMuZGlzcGxheS52aWV3T2Zmc2V0KX0saGVpZ2h0QXRMaW5lOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpPSExO2lmKCJudW1iZXIiPT10eXBlb2YgZSl7dmFyIG89dGhpcy5kb2MuZmlyc3QrdGhpcy5kb2Muc2l6ZS0xO2U8dGhpcy5kb2MuZmlyc3Q/ZT10aGlzLmRvYy5maXJzdDplPm8mJihlPW8saT0hMCkscj1BKHRoaXMuZG9jLGUpfWVsc2Ugcj1lO3JldHVybiBzbih0aGlzLHIse3RvcDowLGxlZnQ6MH0sdHx8InBhZ2UiLG58fGkpLnRvcCsoaT90aGlzLmRvYy5oZWlnaHQtYmUocik6MCl9LGRlZmF1bHRUZXh0SGVpZ2h0OmZ1bmN0aW9uKCl7cmV0dXJuIHhuKHRoaXMuZGlzcGxheSl9LGRlZmF1bHRDaGFyV2lkdGg6ZnVuY3Rpb24oKXtyZXR1cm4gQ24odGhpcy5kaXNwbGF5KX0sZ2V0Vmlld3BvcnQ6ZnVuY3Rpb24oKXtyZXR1cm57ZnJvbTp0aGlzLmRpc3BsYXkudmlld0Zyb20sdG86dGhpcy5kaXNwbGF5LnZpZXdUb319LGFkZFdpZGdldDpmdW5jdGlvbihlLHQsbixyLGkpe3ZhciBvPXRoaXMuZGlzcGxheTtlPWxuKHRoaXMseih0aGlzLmRvYyxlKSk7dmFyIGE9ZS5ib3R0b20scz1lLmxlZnQ7aWYodC5zdHlsZS5wb3NpdGlvbj0iYWJzb2x1dGUiLHQuc2V0QXR0cmlidXRlKCJjbS1pZ25vcmUtZXZlbnRzIiwidHJ1ZSIpLHRoaXMuZGlzcGxheS5pbnB1dC5zZXRVbmVkaXRhYmxlKHQpLG8uc2l6ZXIuYXBwZW5kQ2hpbGQodCksIm92ZXIiPT1yKWE9ZS50b3A7ZWxzZSBpZigiYWJvdmUiPT1yfHwibmVhciI9PXIpe3ZhciB1PU1hdGgubWF4KG8ud3JhcHBlci5jbGllbnRIZWlnaHQsdGhpcy5kb2MuaGVpZ2h0KSxjPU1hdGgubWF4KG8uc2l6ZXIuY2xpZW50V2lkdGgsby5saW5lU3BhY2UuY2xpZW50V2lkdGgpOygiYWJvdmUiPT1yfHxlLmJvdHRvbSt0Lm9mZnNldEhlaWdodD51KSYmZS50b3A+dC5vZmZzZXRIZWlnaHQ/YT1lLnRvcC10Lm9mZnNldEhlaWdodDplLmJvdHRvbSt0Lm9mZnNldEhlaWdodDw9dSYmKGE9ZS5ib3R0b20pLHMrdC5vZmZzZXRXaWR0aD5jJiYocz1jLXQub2Zmc2V0V2lkdGgpfXQuc3R5bGUudG9wPWErInB4Iix0LnN0eWxlLmxlZnQ9dC5zdHlsZS5yaWdodD0iIiwicmlnaHQiPT1pPyhzPW8uc2l6ZXIuY2xpZW50V2lkdGgtdC5vZmZzZXRXaWR0aCx0LnN0eWxlLnJpZ2h0PSIwcHgiKTooImxlZnQiPT1pP3M9MDoibWlkZGxlIj09aSYmKHM9KG8uc2l6ZXIuY2xpZW50V2lkdGgtdC5vZmZzZXRXaWR0aCkvMiksdC5zdHlsZS5sZWZ0PXMrInB4IiksbiYmcW4odGhpcyx7bGVmdDpzLHRvcDphLHJpZ2h0OnMrdC5vZmZzZXRXaWR0aCxib3R0b206YSt0Lm9mZnNldEhlaWdodH0pfSx0cmlnZ2VyT25LZXlEb3duOmdyKEFvKSx0cmlnZ2VyT25LZXlQcmVzczpncihPbyksdHJpZ2dlck9uS2V5VXA6VG8sdHJpZ2dlck9uTW91c2VEb3duOmdyKE5vKSxleGVjQ29tbWFuZDpmdW5jdGlvbihlKXtpZihWcy5oYXNPd25Qcm9wZXJ0eShlKSlyZXR1cm4gVnNbZV0uY2FsbChudWxsLHRoaXMpfSx0cmlnZ2VyRWxlY3RyaWM6Z3IoZnVuY3Rpb24oZSl7ZWEodGhpcyxlKX0pLGZpbmRQb3NIOmZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpPXRoaXMsbz0xO3Q8MCYmKG89LTEsdD0tdCk7Zm9yKHZhciBhPXoodGhpcy5kb2MsZSkscz0wO3M8dCYmKGE9aWEoaS5kb2MsYSxvLG4sciksIWEuaGl0U2lkZSk7KytzKTtyZXR1cm4gYX0sbW92ZUg6Z3IoZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzO3RoaXMuZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uKHIpe3JldHVybiBuLmRpc3BsYXkuc2hpZnR8fG4uZG9jLmV4dGVuZHx8ci5lbXB0eSgpP2lhKG4uZG9jLHIuaGVhZCxlLHQsbi5vcHRpb25zLnJ0bE1vdmVWaXN1YWxseSk6ZTwwP3IuZnJvbSgpOnIudG8oKX0sV2EpfSksZGVsZXRlSDpncihmdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMuZG9jLnNlbCxyPXRoaXMuZG9jO24uc29tZXRoaW5nU2VsZWN0ZWQoKT9yLnJlcGxhY2VTZWxlY3Rpb24oIiIsbnVsbCwiK2RlbGV0ZSIpOmZvKHRoaXMsZnVuY3Rpb24obil7dmFyIGk9aWEocixuLmhlYWQsZSx0LCExKTtyZXR1cm4gZTwwP3tmcm9tOmksdG86bi5oZWFkfTp7ZnJvbTpuLmhlYWQsdG86aX19KX0pLGZpbmRQb3NWOmZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpPXRoaXMsbz0xLGE9cjt0PDAmJihvPS0xLHQ9LXQpO2Zvcih2YXIgcz16KHRoaXMuZG9jLGUpLHU9MDt1PHQ7Kyt1KXt2YXIgYz1sbihpLHMsImRpdiIpO2lmKG51bGw9PWE/YT1jLmxlZnQ6Yy5sZWZ0PWEscz1vYShpLGMsbyxuKSxzLmhpdFNpZGUpYnJlYWt9cmV0dXJuIHN9LG1vdmVWOmdyKGZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcyxyPXRoaXMuZG9jLGk9W10sbz0hdGhpcy5kaXNwbGF5LnNoaWZ0JiYhci5leHRlbmQmJnIuc2VsLnNvbWV0aGluZ1NlbGVjdGVkKCk7aWYoci5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24oYSl7aWYobylyZXR1cm4gZTwwP2EuZnJvbSgpOmEudG8oKTt2YXIgcz1sbihuLGEuaGVhZCwiZGl2Iik7bnVsbCE9YS5nb2FsQ29sdW1uJiYocy5sZWZ0PWEuZ29hbENvbHVtbiksaS5wdXNoKHMubGVmdCk7dmFyIHU9b2EobixzLGUsdCk7cmV0dXJuInBhZ2UiPT10JiZhPT1yLnNlbC5wcmltYXJ5KCkmJlduKG4sY24obix1LCJkaXYiKS50b3Atcy50b3ApLHV9LFdhKSxpLmxlbmd0aClmb3IodmFyIGE9MDthPHIuc2VsLnJhbmdlcy5sZW5ndGg7YSsrKXIuc2VsLnJhbmdlc1thXS5nb2FsQ29sdW1uPWlbYV19KSxmaW5kV29yZEF0OmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuZG9jLG49QSh0LGUubGluZSkudGV4dCxyPWUuY2gsaT1lLmNoO2lmKG4pe3ZhciBvPXRoaXMuZ2V0SGVscGVyKGUsIndvcmRDaGFycyIpOyJiZWZvcmUiIT1lLnN0aWNreSYmaSE9bi5sZW5ndGh8fCFyPysraTotLXI7Zm9yKHZhciBhPW4uY2hhckF0KHIpLHM9QyhhLG8pP2Z1bmN0aW9uKGUpe3JldHVybiBDKGUsbyl9Oi9ccy8udGVzdChhKT9mdW5jdGlvbihlKXtyZXR1cm4vXHMvLnRlc3QoZSl9OmZ1bmN0aW9uKGUpe3JldHVybiEvXHMvLnRlc3QoZSkmJiFDKGUpfTtyPjAmJnMobi5jaGFyQXQoci0xKSk7KS0tcjtmb3IoO2k8bi5sZW5ndGgmJnMobi5jaGFyQXQoaSkpOykrK2l9cmV0dXJuIG5ldyBPcyhQKGUubGluZSxyKSxQKGUubGluZSxpKSl9LHRvZ2dsZU92ZXJ3cml0ZTpmdW5jdGlvbihlKXtudWxsIT1lJiZlPT10aGlzLnN0YXRlLm92ZXJ3cml0ZXx8KCh0aGlzLnN0YXRlLm92ZXJ3cml0ZT0hdGhpcy5zdGF0ZS5vdmVyd3JpdGUpP3ModGhpcy5kaXNwbGF5LmN1cnNvckRpdiwiQ29kZU1pcnJvci1vdmVyd3JpdGUiKTpSYSh0aGlzLmRpc3BsYXkuY3Vyc29yRGl2LCJDb2RlTWlycm9yLW92ZXJ3cml0ZSIpLEFlKHRoaXMsIm92ZXJ3cml0ZVRvZ2dsZSIsdGhpcyx0aGlzLnN0YXRlLm92ZXJ3cml0ZSkpfSxoYXNGb2N1czpmdW5jdGlvbigpe3JldHVybiB0aGlzLmRpc3BsYXkuaW5wdXQuZ2V0RmllbGQoKT09YSgpfSxpc1JlYWRPbmx5OmZ1bmN0aW9uKCl7cmV0dXJuISghdGhpcy5vcHRpb25zLnJlYWRPbmx5JiYhdGhpcy5kb2MuY2FudEVkaXQpfSxzY3JvbGxUbzpncihmdW5jdGlvbihlLHQpe0tuKHRoaXMsZSx0KX0pLGdldFNjcm9sbEluZm86ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmRpc3BsYXkuc2Nyb2xsZXI7cmV0dXJue2xlZnQ6ZS5zY3JvbGxMZWZ0LHRvcDplLnNjcm9sbFRvcCxoZWlnaHQ6ZS5zY3JvbGxIZWlnaHQtJHQodGhpcyktdGhpcy5kaXNwbGF5LmJhckhlaWdodCx3aWR0aDplLnNjcm9sbFdpZHRoLSR0KHRoaXMpLXRoaXMuZGlzcGxheS5iYXJXaWR0aCxjbGllbnRIZWlnaHQ6enQodGhpcyksY2xpZW50V2lkdGg6VXQodGhpcyl9fSxzY3JvbGxJbnRvVmlldzpncihmdW5jdGlvbihlLHQpe251bGw9PWU/KGU9e2Zyb206dGhpcy5kb2Muc2VsLnByaW1hcnkoKS5oZWFkLHRvOm51bGx9LG51bGw9PXQmJih0PXRoaXMub3B0aW9ucy5jdXJzb3JTY3JvbGxNYXJnaW4pKToibnVtYmVyIj09dHlwZW9mIGU/ZT17ZnJvbTpQKGUsMCksdG86bnVsbH06bnVsbD09ZS5mcm9tJiYoZT17ZnJvbTplLHRvOm51bGx9KSxlLnRvfHwoZS50bz1lLmZyb20pLGUubWFyZ2luPXR8fDAsbnVsbCE9ZS5mcm9tLmxpbmU/Sm4odGhpcyxlKTpYbih0aGlzLGUuZnJvbSxlLnRvLGUubWFyZ2luKX0pLHNldFNpemU6Z3IoZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLHI9ZnVuY3Rpb24oZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlfHwvXlxkKyQvLnRlc3QoU3RyaW5nKGUpKT9lKyJweCI6ZX07bnVsbCE9ZSYmKHRoaXMuZGlzcGxheS53cmFwcGVyLnN0eWxlLndpZHRoPXIoZSkpLG51bGwhPXQmJih0aGlzLmRpc3BsYXkud3JhcHBlci5zdHlsZS5oZWlnaHQ9cih0KSksdGhpcy5vcHRpb25zLmxpbmVXcmFwcGluZyYmdG4odGhpcyk7dmFyIGk9dGhpcy5kaXNwbGF5LnZpZXdGcm9tO3RoaXMuZG9jLml0ZXIoaSx0aGlzLmRpc3BsYXkudmlld1RvLGZ1bmN0aW9uKGUpe2lmKGUud2lkZ2V0cylmb3IodmFyIHQ9MDt0PGUud2lkZ2V0cy5sZW5ndGg7dCsrKWlmKGUud2lkZ2V0c1t0XS5ub0hTY3JvbGwpe2JyKG4saSwid2lkZ2V0Iik7YnJlYWt9KytpfSksdGhpcy5jdXJPcC5mb3JjZVVwZGF0ZT0hMCxBZSh0aGlzLCJyZWZyZXNoIix0aGlzKX0pLG9wZXJhdGlvbjpmdW5jdGlvbihlKXtyZXR1cm4gaHIodGhpcyxlKX0sc3RhcnRPcGVyYXRpb246ZnVuY3Rpb24oKXtyZXR1cm4gYXIodGhpcyl9LGVuZE9wZXJhdGlvbjpmdW5jdGlvbigpe3JldHVybiBzcih0aGlzKX0scmVmcmVzaDpncihmdW5jdGlvbigpe3ZhciBlPXRoaXMuZGlzcGxheS5jYWNoZWRUZXh0SGVpZ2h0O3ZyKHRoaXMpLHRoaXMuY3VyT3AuZm9yY2VVcGRhdGU9ITAsbm4odGhpcyksS24odGhpcyx0aGlzLmRvYy5zY3JvbGxMZWZ0LHRoaXMuZG9jLnNjcm9sbFRvcCksSXIodGhpcyksKG51bGw9PWV8fE1hdGguYWJzKGUteG4odGhpcy5kaXNwbGF5KSk+LjUpJiZTbih0aGlzKSxBZSh0aGlzLCJyZWZyZXNoIix0aGlzKX0pLHN3YXBEb2M6Z3IoZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5kb2M7cmV0dXJuIHQuY209bnVsbCxYcih0aGlzLGUpLG5uKHRoaXMpLHRoaXMuZGlzcGxheS5pbnB1dC5yZXNldCgpLEtuKHRoaXMsZS5zY3JvbGxMZWZ0LGUuc2Nyb2xsVG9wKSx0aGlzLmN1ck9wLmZvcmNlU2Nyb2xsPSEwLEN0KHRoaXMsInN3YXBEb2MiLHRoaXMsdCksdH0pLGdldElucHV0RmllbGQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kaXNwbGF5LmlucHV0LmdldEZpZWxkKCl9LGdldFdyYXBwZXJFbGVtZW50OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZGlzcGxheS53cmFwcGVyfSxnZXRTY3JvbGxlckVsZW1lbnQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kaXNwbGF5LnNjcm9sbGVyfSxnZXRHdXR0ZXJFbGVtZW50OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZGlzcGxheS5ndXR0ZXJzfX0sRmUoZSksZS5yZWdpc3RlckhlbHBlcj1mdW5jdGlvbih0LHIsaSl7bi5oYXNPd25Qcm9wZXJ0eSh0KXx8KG5bdF09ZVt0XT17X2dsb2JhbDpbXX0pLG5bdF1bcl09aX0sZS5yZWdpc3Rlckdsb2JhbEhlbHBlcj1mdW5jdGlvbih0LHIsaSxvKXtlLnJlZ2lzdGVySGVscGVyKHQscixvKSxuW3RdLl9nbG9iYWwucHVzaCh7cHJlZDppLHZhbDpvfSl9fShRbyk7dmFyIHJ1PSJpdGVyIGluc2VydCByZW1vdmUgY29weSBnZXRFZGl0b3IgY29uc3RydWN0b3IiLnNwbGl0KCIgIik7Zm9yKHZhciBpdSBpbiBNcy5wcm90b3R5cGUpTXMucHJvdG90eXBlLmhhc093blByb3BlcnR5KGl1KSYmZihydSxpdSk8MCYmKFFvLnByb3RvdHlwZVtpdV09ZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGUuYXBwbHkodGhpcy5kb2MsYXJndW1lbnRzKX19KE1zLnByb3RvdHlwZVtpdV0pKTtyZXR1cm4gRmUoTXMpLFFvLmlucHV0U3R5bGVzPXt0ZXh0YXJlYTpudSxjb250ZW50ZWRpdGFibGU6dHV9LFFvLmRlZmluZU1vZGU9ZnVuY3Rpb24oZSl7UW8uZGVmYXVsdHMubW9kZXx8Im51bGwiPT1lfHwoUW8uZGVmYXVsdHMubW9kZT1lKSxVZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl9LFFvLmRlZmluZU1JTUU9emUsUW8uZGVmaW5lTW9kZSgibnVsbCIsZnVuY3Rpb24oKXtyZXR1cm57dG9rZW46ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc2tpcFRvRW5kKCl9fX0pLFFvLmRlZmluZU1JTUUoInRleHQvcGxhaW4iLCJudWxsIiksUW8uZGVmaW5lRXh0ZW5zaW9uPWZ1bmN0aW9uKGUsdCl7UW8ucHJvdG90eXBlW2VdPXR9LFFvLmRlZmluZURvY0V4dGVuc2lvbj1mdW5jdGlvbihlLHQpe01zLnByb3RvdHlwZVtlXT10fSxRby5mcm9tVGV4dEFyZWE9ZmEsZnVuY3Rpb24oZSl7ZS5vZmY9a2UsZS5vbj1ucyxlLndoZWVsRXZlbnRQaXhlbHM9UnIsZS5Eb2M9TXMsZS5zcGxpdExpbmVzPWlzLGUuY291bnRDb2x1bW49cCxlLmZpbmRDb2x1bW49ZCxlLmlzV29yZENoYXI9eCxlLlBhc3M9VmEsZS5zaWduYWw9QWUsZS5MaW5lPW1zLGUuY2hhbmdlRW5kPXpyLGUuc2Nyb2xsYmFyTW9kZWw9d3MsZS5Qb3M9UCxlLmNtcFBvcz1NLGUubW9kZXM9dXMsZS5taW1lTW9kZXM9Y3MsZS5yZXNvbHZlTW9kZT1HZSxlLmdldE1vZGU9VmUsZS5tb2RlRXh0ZW5zaW9ucz1scyxlLmV4dGVuZE1vZGU9cWUsZS5jb3B5U3RhdGU9SGUsZS5zdGFydFN0YXRlPVFlLGUuaW5uZXJNb2RlPVdlLGUuY29tbWFuZHM9VnMsZS5rZXlNYXA9R3MsZS5rZXlOYW1lPWxvLGUuaXNNb2RpZmllcktleT11byxlLmxvb2t1cEtleT1zbyxlLm5vcm1hbGl6ZUtleU1hcD1hbyxlLlN0cmluZ1N0cmVhbT1wcyxlLlNoYXJlZFRleHRNYXJrZXI9THMsZS5UZXh0TWFya2VyPUlzLGUuTGluZVdpZGdldD1GcyxlLmVfcHJldmVudERlZmF1bHQ9TmUsZS5lX3N0b3BQcm9wYWdhdGlvbj1JZSxlLmVfc3RvcD1QZSxlLmFkZENsYXNzPXMsZS5jb250YWlucz1vLGUucm1DbGFzcz1SYSxlLmtleU5hbWVzPUJzfShRbyksUW8udmVyc2lvbj0iNS4zOC4wIixRb30pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDQzKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiR3JhcGhRTEVycm9yIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gci5HcmFwaFFMRXJyb3J9fSk7dmFyIGk9bigzOTEpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJzeW50YXhFcnJvciIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuc3ludGF4RXJyb3J9fSk7dmFyIG89bigxODApO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJsb2NhdGVkRXJyb3IiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLmxvY2F0ZWRFcnJvcn19KTt2YXIgYT1uKDM5Mik7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImZvcm1hdEVycm9yIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS5mb3JtYXRFcnJvcn19KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZSl9ZnVuY3Rpb24gaShlKXtyZXR1cm4iW29iamVjdCBTdHJpbmddIj09PXIoZSl9ZnVuY3Rpb24gbyhlLHQpe3JldHVybiBDLmNhbGwoZSx0KX1mdW5jdGlvbiBhKGUpe3JldHVybiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMSkuZm9yRWFjaChmdW5jdGlvbih0KXtpZih0KXtpZigib2JqZWN0IiE9PXR5cGVvZiB0KXRocm93IG5ldyBUeXBlRXJyb3IodCsibXVzdCBiZSBvYmplY3QiKTtPYmplY3Qua2V5cyh0KS5mb3JFYWNoKGZ1bmN0aW9uKG4pe2Vbbl09dFtuXX0pfX0pLGV9ZnVuY3Rpb24gcyhlLHQsbil7cmV0dXJuW10uY29uY2F0KGUuc2xpY2UoMCx0KSxuLGUuc2xpY2UodCsxKSl9ZnVuY3Rpb24gdShlKXtyZXR1cm4hKGU+PTU1Mjk2JiZlPD01NzM0MykmJighKGU+PTY0OTc2JiZlPD02NTAwNykmJig2NTUzNSE9PSg2NTUzNSZlKSYmNjU1MzQhPT0oNjU1MzUmZSkmJighKGU+PTAmJmU8PTgpJiYoMTEhPT1lJiYoIShlPj0xNCYmZTw9MzEpJiYoIShlPj0xMjcmJmU8PTE1OSkmJiEoZT4xMTE0MTExKSkpKSkpKX1mdW5jdGlvbiBjKGUpe2lmKGU+NjU1MzUpe2UtPTY1NTM2O3ZhciB0PTU1Mjk2KyhlPj4xMCksbj01NjMyMCsoMTAyMyZlKTtyZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZSh0LG4pfXJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKGUpfWZ1bmN0aW9uIGwoZSx0KXt2YXIgbj0wO3JldHVybiBvKGssdCk/a1t0XTozNT09PXQuY2hhckNvZGVBdCgwKSYmUy50ZXN0KHQpJiYobj0ieCI9PT10WzFdLnRvTG93ZXJDYXNlKCk/cGFyc2VJbnQodC5zbGljZSgyKSwxNik6cGFyc2VJbnQodC5zbGljZSgxKSwxMCksdShuKSk/YyhuKTplfWZ1bmN0aW9uIHAoZSl7cmV0dXJuIGUuaW5kZXhPZigiXFwiKTwwP2U6ZS5yZXBsYWNlKEUsIiQxIil9ZnVuY3Rpb24gZihlKXtyZXR1cm4gZS5pbmRleE9mKCJcXCIpPDAmJmUuaW5kZXhPZigiJiIpPDA/ZTplLnJlcGxhY2UodyxmdW5jdGlvbihlLHQsbil7cmV0dXJuIHR8fGwoZSxuKX0pfWZ1bmN0aW9uIGQoZSl7cmV0dXJuIFRbZV19ZnVuY3Rpb24gaChlKXtyZXR1cm4gQS50ZXN0KGUpP2UucmVwbGFjZShfLGQpOmV9ZnVuY3Rpb24gbShlKXtyZXR1cm4gZS5yZXBsYWNlKE8sIlxcJCYiKX1mdW5jdGlvbiBnKGUpe3N3aXRjaChlKXtjYXNlIDk6Y2FzZSAzMjpyZXR1cm4hMH1yZXR1cm4hMX1mdW5jdGlvbiB5KGUpe2lmKGU+PTgxOTImJmU8PTgyMDIpcmV0dXJuITA7c3dpdGNoKGUpe2Nhc2UgOTpjYXNlIDEwOmNhc2UgMTE6Y2FzZSAxMjpjYXNlIDEzOmNhc2UgMzI6Y2FzZSAxNjA6Y2FzZSA1NzYwOmNhc2UgODIzOTpjYXNlIDgyODc6Y2FzZSAxMjI4ODpyZXR1cm4hMH1yZXR1cm4hMX1mdW5jdGlvbiB2KGUpe3JldHVybiBGLnRlc3QoZSl9ZnVuY3Rpb24gYihlKXtzd2l0Y2goZSl7Y2FzZSAzMzpjYXNlIDM0OmNhc2UgMzU6Y2FzZSAzNjpjYXNlIDM3OmNhc2UgMzg6Y2FzZSAzOTpjYXNlIDQwOmNhc2UgNDE6Y2FzZSA0MjpjYXNlIDQzOmNhc2UgNDQ6Y2FzZSA0NTpjYXNlIDQ2OmNhc2UgNDc6Y2FzZSA1ODpjYXNlIDU5OmNhc2UgNjA6Y2FzZSA2MTpjYXNlIDYyOmNhc2UgNjM6Y2FzZSA2NDpjYXNlIDkxOmNhc2UgOTI6Y2FzZSA5MzpjYXNlIDk0OmNhc2UgOTU6Y2FzZSA5NjpjYXNlIDEyMzpjYXNlIDEyNDpjYXNlIDEyNTpjYXNlIDEyNjpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiExfX1mdW5jdGlvbiB4KGUpe3JldHVybiBlLnRyaW0oKS5yZXBsYWNlKC9ccysvZywiICIpLnRvVXBwZXJDYXNlKCl9dmFyIEM9T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eSxFPS9cXChbISIjJCUmJygpKissXC0uXC86Ozw9Pj9AW1xcXF1eX2B7fH1+XSkvZyxEPS8mKFthLXojXVthLXowLTldezEsMzF9KTsvZ2ksdz1uZXcgUmVnRXhwKEUuc291cmNlKyJ8IitELnNvdXJjZSwiZ2kiKSxTPS9eIygoPzp4W2EtZjAtOV17MSw4fXxbMC05XXsxLDh9KSkvaSxrPW4oMjYxKSxBPS9bJjw+Il0vLF89L1smPD4iXS9nLFQ9eyImIjoiJmFtcDsiLCI8IjoiJmx0OyIsIj4iOiImZ3Q7IiwnIic6IiZxdW90OyJ9LE89L1suPyorXiRbXF1cXCgpe318LV0vZyxGPW4oMjYzKTt0LmxpYj17fSx0LmxpYi5tZHVybD1uKDg4KSx0LmxpYi51Y21pY3JvPW4oNTQzKSx0LmFzc2lnbj1hLHQuaXNTdHJpbmc9aSx0Lmhhcz1vLHQudW5lc2NhcGVNZD1wLHQudW5lc2NhcGVBbGw9Zix0LmlzVmFsaWRFbnRpdHlDb2RlPXUsdC5mcm9tQ29kZVBvaW50PWMsdC5lc2NhcGVIdG1sPWgsdC5hcnJheVJlcGxhY2VBdD1zLHQuaXNTcGFjZT1nLHQuaXNXaGl0ZVNwYWNlPXksdC5pc01kQXNjaWlQdW5jdD1iLHQuaXNQdW5jdENoYXI9dix0LmVzY2FwZVJFPW0sdC5ub3JtYWxpemVSZWZlcmVuY2U9eH0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZSl9ZnVuY3Rpb24gaShlKXtyZXR1cm4iW29iamVjdCBTdHJpbmddIj09PXIoZSl9ZnVuY3Rpb24gbyhlLHQpe3JldHVybiBDLmNhbGwoZSx0KX1mdW5jdGlvbiBhKGUpe3JldHVybiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMSkuZm9yRWFjaChmdW5jdGlvbih0KXtpZih0KXtpZigib2JqZWN0IiE9PXR5cGVvZiB0KXRocm93IG5ldyBUeXBlRXJyb3IodCsibXVzdCBiZSBvYmplY3QiKTtPYmplY3Qua2V5cyh0KS5mb3JFYWNoKGZ1bmN0aW9uKG4pe2Vbbl09dFtuXX0pfX0pLGV9ZnVuY3Rpb24gcyhlLHQsbil7cmV0dXJuW10uY29uY2F0KGUuc2xpY2UoMCx0KSxuLGUuc2xpY2UodCsxKSl9ZnVuY3Rpb24gdShlKXtyZXR1cm4hKGU+PTU1Mjk2JiZlPD01NzM0MykmJighKGU+PTY0OTc2JiZlPD02NTAwNykmJig2NTUzNSE9PSg2NTUzNSZlKSYmNjU1MzQhPT0oNjU1MzUmZSkmJighKGU+PTAmJmU8PTgpJiYoMTEhPT1lJiYoIShlPj0xNCYmZTw9MzEpJiYoIShlPj0xMjcmJmU8PTE1OSkmJiEoZT4xMTE0MTExKSkpKSkpKX1mdW5jdGlvbiBjKGUpe2lmKGU+NjU1MzUpe2UtPTY1NTM2O3ZhciB0PTU1Mjk2KyhlPj4xMCksbj01NjMyMCsoMTAyMyZlKTtyZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZSh0LG4pfXJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKGUpfWZ1bmN0aW9uIGwoZSx0KXt2YXIgbj0wO3JldHVybiBvKGssdCk/a1t0XTozNT09PXQuY2hhckNvZGVBdCgwKSYmUy50ZXN0KHQpJiYobj0ieCI9PT10WzFdLnRvTG93ZXJDYXNlKCk/cGFyc2VJbnQodC5zbGljZSgyKSwxNik6cGFyc2VJbnQodC5zbGljZSgxKSwxMCksdShuKSk/YyhuKTplfWZ1bmN0aW9uIHAoZSl7cmV0dXJuIGUuaW5kZXhPZigiXFwiKTwwP2U6ZS5yZXBsYWNlKEUsIiQxIil9ZnVuY3Rpb24gZihlKXtyZXR1cm4gZS5pbmRleE9mKCJcXCIpPDAmJmUuaW5kZXhPZigiJiIpPDA/ZTplLnJlcGxhY2UodyxmdW5jdGlvbihlLHQsbil7cmV0dXJuIHR8fGwoZSxuKX0pfWZ1bmN0aW9uIGQoZSl7cmV0dXJuIFRbZV19ZnVuY3Rpb24gaChlKXtyZXR1cm4gQS50ZXN0KGUpP2UucmVwbGFjZShfLGQpOmV9ZnVuY3Rpb24gbShlKXtyZXR1cm4gZS5yZXBsYWNlKE8sIlxcJCYiKX1mdW5jdGlvbiBnKGUpe3N3aXRjaChlKXtjYXNlIDk6Y2FzZSAzMjpyZXR1cm4hMH1yZXR1cm4hMX1mdW5jdGlvbiB5KGUpe2lmKGU+PTgxOTImJmU8PTgyMDIpcmV0dXJuITA7c3dpdGNoKGUpe2Nhc2UgOTpjYXNlIDEwOmNhc2UgMTE6Y2FzZSAxMjpjYXNlIDEzOmNhc2UgMzI6Y2FzZSAxNjA6Y2FzZSA1NzYwOmNhc2UgODIzOTpjYXNlIDgyODc6Y2FzZSAxMjI4ODpyZXR1cm4hMH1yZXR1cm4hMX1mdW5jdGlvbiB2KGUpe3JldHVybiBGLnRlc3QoZSl9ZnVuY3Rpb24gYihlKXtzd2l0Y2goZSl7Y2FzZSAzMzpjYXNlIDM0OmNhc2UgMzU6Y2FzZSAzNjpjYXNlIDM3OmNhc2UgMzg6Y2FzZSAzOTpjYXNlIDQwOmNhc2UgNDE6Y2FzZSA0MjpjYXNlIDQzOmNhc2UgNDQ6Y2FzZSA0NTpjYXNlIDQ2OmNhc2UgNDc6Y2FzZSA1ODpjYXNlIDU5OmNhc2UgNjA6Y2FzZSA2MTpjYXNlIDYyOmNhc2UgNjM6Y2FzZSA2NDpjYXNlIDkxOmNhc2UgOTI6Y2FzZSA5MzpjYXNlIDk0OmNhc2UgOTU6Y2FzZSA5NjpjYXNlIDEyMzpjYXNlIDEyNDpjYXNlIDEyNTpjYXNlIDEyNjpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiExfX1mdW5jdGlvbiB4KGUpe3JldHVybiBlLnRyaW0oKS5yZXBsYWNlKC9ccysvZywiICIpLnRvVXBwZXJDYXNlKCl9dmFyIEM9T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eSxFPS9cXChbISIjJCUmJygpKissXC0uXC86Ozw9Pj9AW1xcXF1eX2B7fH1+XSkvZyxEPS8mKFthLXojXVthLXowLTldezEsMzF9KTsvZ2ksdz1uZXcgUmVnRXhwKEUuc291cmNlKyJ8IitELnNvdXJjZSwiZ2kiKSxTPS9eIygoPzp4W2EtZjAtOV17MSw4fXxbMC05XXsxLDh9KSkvaSxrPW4oMjk0KSxBPS9bJjw+Il0vLF89L1smPD4iXS9nLFQ9eyImIjoiJmFtcDsiLCI8IjoiJmx0OyIsIj4iOiImZ3Q7IiwnIic6IiZxdW90OyJ9LE89L1suPyorXiRbXF1cXCgpe318LV0vZyxGPW4oMTM2KTt0LmxpYj17fSx0LmxpYi5tZHVybD1uKDg4KSx0LmxpYi51Y21pY3JvPW4oNjQ3KSx0LmFzc2lnbj1hLHQuaXNTdHJpbmc9aSx0Lmhhcz1vLHQudW5lc2NhcGVNZD1wLHQudW5lc2NhcGVBbGw9Zix0LmlzVmFsaWRFbnRpdHlDb2RlPXUsdC5mcm9tQ29kZVBvaW50PWMsdC5lc2NhcGVIdG1sPWgsdC5hcnJheVJlcGxhY2VBdD1zLHQuaXNTcGFjZT1nLHQuaXNXaGl0ZVNwYWNlPXksdC5pc01kQXNjaWlQdW5jdD1iLHQuaXNQdW5jdENoYXI9dix0LmVzY2FwZVJFPW0sdC5ub3JtYWxpemVSZWZlcmVuY2U9eH0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1mdW5jdGlvbiBpKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9ZnVuY3Rpb24gbyhlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIGp8fGUgaW5zdGFuY2VvZiBSfHxlIGluc3RhbmNlb2YgQnx8ZSBpbnN0YW5jZW9mICR8fGUgaW5zdGFuY2VvZiBVfHxlIGluc3RhbmNlb2Ygenx8ZSBpbnN0YW5jZW9mIEd8fGUgaW5zdGFuY2VvZiBWfWZ1bmN0aW9uIGEoZSl7cmV0dXJuIG8oZSl8fCgwLEYuZGVmYXVsdCkoMCwiRXhwZWN0ZWQgIitTdHJpbmcoZSkrIiB0byBiZSBhIEdyYXBoUUwgdHlwZS4iKSxlfWZ1bmN0aW9uIHMoZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiBqfHxlIGluc3RhbmNlb2YgVXx8ZSBpbnN0YW5jZW9mIHp8fGUgaW5zdGFuY2VvZiBWJiZzKGUub2ZUeXBlKXx8ZSBpbnN0YW5jZW9mIEcmJnMoZS5vZlR5cGUpfWZ1bmN0aW9uIHUoZSl7cmV0dXJuIHMoZSl8fCgwLEYuZGVmYXVsdCkoMCwiRXhwZWN0ZWQgIitTdHJpbmcoZSkrIiB0byBiZSBhIEdyYXBoUUwgaW5wdXQgdHlwZS4iKSxlfWZ1bmN0aW9uIGMoZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiBqfHxlIGluc3RhbmNlb2YgUnx8ZSBpbnN0YW5jZW9mIEJ8fGUgaW5zdGFuY2VvZiAkfHxlIGluc3RhbmNlb2YgVXx8ZSBpbnN0YW5jZW9mIFYmJmMoZS5vZlR5cGUpfHxlIGluc3RhbmNlb2YgRyYmYyhlLm9mVHlwZSl9ZnVuY3Rpb24gbChlKXtyZXR1cm4gYyhlKXx8KDAsRi5kZWZhdWx0KSgwLCJFeHBlY3RlZCAiK1N0cmluZyhlKSsiIHRvIGJlIGEgR3JhcGhRTCBvdXRwdXQgdHlwZS4iKSxlfWZ1bmN0aW9uIHAoZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiBqfHxlIGluc3RhbmNlb2YgVX1mdW5jdGlvbiBmKGUpe3JldHVybiBwKGUpfHwoMCxGLmRlZmF1bHQpKDAsIkV4cGVjdGVkICIrU3RyaW5nKGUpKyIgdG8gYmUgYSBHcmFwaFFMIGxlYWYgdHlwZS4iKSxlfWZ1bmN0aW9uIGQoZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiBSfHxlIGluc3RhbmNlb2YgQnx8ZSBpbnN0YW5jZW9mICR9ZnVuY3Rpb24gaChlKXtyZXR1cm4gZChlKXx8KDAsRi5kZWZhdWx0KSgwLCJFeHBlY3RlZCAiK1N0cmluZyhlKSsiIHRvIGJlIGEgR3JhcGhRTCBjb21wb3NpdGUgdHlwZS4iKSxlfWZ1bmN0aW9uIG0oZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiBCfHxlIGluc3RhbmNlb2YgJH1mdW5jdGlvbiBnKGUpe3JldHVybiBtKGUpfHwoMCxGLmRlZmF1bHQpKDAsIkV4cGVjdGVkICIrU3RyaW5nKGUpKyIgdG8gYmUgYSBHcmFwaFFMIGFic3RyYWN0IHR5cGUuIiksZX1mdW5jdGlvbiB5KGUpe3JldHVybiBlIGluc3RhbmNlb2YgVj9lLm9mVHlwZTplfWZ1bmN0aW9uIHYoZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiBqfHxlIGluc3RhbmNlb2YgUnx8ZSBpbnN0YW5jZW9mIEJ8fGUgaW5zdGFuY2VvZiAkfHxlIGluc3RhbmNlb2YgVXx8ZSBpbnN0YW5jZW9mIHp9ZnVuY3Rpb24gYihlKXtyZXR1cm4gdihlKXx8KDAsRi5kZWZhdWx0KSgwLCJFeHBlY3RlZCAiK1N0cmluZyhlKSsiIHRvIGJlIGEgR3JhcGhRTCBuYW1lZCB0eXBlLiIpLGV9ZnVuY3Rpb24geChlKXtpZihlKXtmb3IodmFyIHQ9ZTt0IGluc3RhbmNlb2YgR3x8dCBpbnN0YW5jZW9mIFY7KXQ9dC5vZlR5cGU7cmV0dXJuIHR9fWZ1bmN0aW9uIEMoZSl7cmV0dXJuImZ1bmN0aW9uIj09PXR5cGVvZiBlP2UoKTplfWZ1bmN0aW9uIEUoZSx0KXt2YXIgbj1DKHQpO2lmKCFuKXJldHVybltdO0FycmF5LmlzQXJyYXkobil8fCgwLEYuZGVmYXVsdCkoMCxlLm5hbWUrIiBpbnRlcmZhY2VzIG11c3QgYmUgYW4gQXJyYXkgb3IgYSBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFuIEFycmF5LiIpO3ZhciByPU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIG4uZm9yRWFjaChmdW5jdGlvbih0KXt0IGluc3RhbmNlb2YgQnx8KDAsRi5kZWZhdWx0KSgwLGUubmFtZSsiIG1heSBvbmx5IGltcGxlbWVudCBJbnRlcmZhY2UgdHlwZXMsIGl0IGNhbm5vdCBpbXBsZW1lbnQ6ICIrU3RyaW5nKHQpKyIuIiksclt0Lm5hbWVdJiYoMCxGLmRlZmF1bHQpKDAsZS5uYW1lKyIgbWF5IGRlY2xhcmUgaXQgaW1wbGVtZW50cyAiK3QubmFtZSsiIG9ubHkgb25jZS4iKSxyW3QubmFtZV09ITAsImZ1bmN0aW9uIiE9PXR5cGVvZiB0LnJlc29sdmVUeXBlJiYiZnVuY3Rpb24iIT09dHlwZW9mIGUuaXNUeXBlT2YmJigwLEYuZGVmYXVsdCkoMCwiSW50ZXJmYWNlIFR5cGUgIit0Lm5hbWUrJyBkb2VzIG5vdCBwcm92aWRlIGEgInJlc29sdmVUeXBlIiBmdW5jdGlvbiBhbmQgaW1wbGVtZW50aW5nIFR5cGUgJytlLm5hbWUrJyBkb2VzIG5vdCBwcm92aWRlIGEgImlzVHlwZU9mIiBmdW5jdGlvbi4gVGhlcmUgaXMgbm8gd2F5IHRvIHJlc29sdmUgdGhpcyBpbXBsZW1lbnRpbmcgdHlwZSBkdXJpbmcgZXhlY3V0aW9uLicpfSksbn1mdW5jdGlvbiBEKGUsdCl7dmFyIG49Qyh0KTt3KG4pfHwoMCxGLmRlZmF1bHQpKDAsZS5uYW1lKyIgZmllbGRzIG11c3QgYmUgYW4gb2JqZWN0IHdpdGggZmllbGQgbmFtZXMgYXMga2V5cyBvciBhIGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgc3VjaCBhbiBvYmplY3QuIik7dmFyIHI9T2JqZWN0LmtleXMobik7ci5sZW5ndGg+MHx8KDAsRi5kZWZhdWx0KSgwLGUubmFtZSsiIGZpZWxkcyBtdXN0IGJlIGFuIG9iamVjdCB3aXRoIGZpZWxkIG5hbWVzIGFzIGtleXMgb3IgYSBmdW5jdGlvbiB3aGljaCByZXR1cm5zIHN1Y2ggYW4gb2JqZWN0LiIpO3ZhciBpPU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIHIuZm9yRWFjaChmdW5jdGlvbih0KXsoMCxNLmFzc2VydFZhbGlkTmFtZSkodCk7dmFyIHI9blt0XTt3KHIpfHwoMCxGLmRlZmF1bHQpKDAsZS5uYW1lKyIuIit0KyIgZmllbGQgY29uZmlnIG11c3QgYmUgYW4gb2JqZWN0Iiksci5oYXNPd25Qcm9wZXJ0eSgiaXNEZXByZWNhdGVkIikmJigwLEYuZGVmYXVsdCkoMCxlLm5hbWUrIi4iK3QrJyBzaG91bGQgcHJvdmlkZSAiZGVwcmVjYXRpb25SZWFzb24iIGluc3RlYWQgb2YgImlzRGVwcmVjYXRlZCIuJyk7dmFyIG89VCh7fSxyLHtpc0RlcHJlY2F0ZWQ6Qm9vbGVhbihyLmRlcHJlY2F0aW9uUmVhc29uKSxuYW1lOnR9KTtjKG8udHlwZSl8fCgwLEYuZGVmYXVsdCkoMCxlLm5hbWUrIi4iK3QrIiBmaWVsZCB0eXBlIG11c3QgYmUgT3V0cHV0IFR5cGUgYnV0IGdvdDogIitTdHJpbmcoby50eXBlKSsiLiIpLFMoby5yZXNvbHZlKXx8KDAsRi5kZWZhdWx0KSgwLGUubmFtZSsiLiIrdCsiIGZpZWxkIHJlc29sdmVyIG11c3QgYmUgYSBmdW5jdGlvbiBpZiBwcm92aWRlZCwgYnV0IGdvdDogIitTdHJpbmcoby5yZXNvbHZlKSsiLiIpO3ZhciBhPXIuYXJnczthPyh3KGEpfHwoMCxGLmRlZmF1bHQpKDAsZS5uYW1lKyIuIit0KyIgYXJncyBtdXN0IGJlIGFuIG9iamVjdCB3aXRoIGFyZ3VtZW50IG5hbWVzIGFzIGtleXMuIiksby5hcmdzPU9iamVjdC5rZXlzKGEpLm1hcChmdW5jdGlvbihuKXsoMCxNLmFzc2VydFZhbGlkTmFtZSkobik7dmFyIHI9YVtuXTtyZXR1cm4gcyhyLnR5cGUpfHwoMCxGLmRlZmF1bHQpKDAsZS5uYW1lKyIuIit0KyIoIituKyI6KSBhcmd1bWVudCB0eXBlIG11c3QgYmUgSW5wdXQgVHlwZSBidXQgZ290OiAiK1N0cmluZyhyLnR5cGUpKyIuIikse25hbWU6bixkZXNjcmlwdGlvbjp2b2lkIDA9PT1yLmRlc2NyaXB0aW9uP251bGw6ci5kZXNjcmlwdGlvbix0eXBlOnIudHlwZSxkZWZhdWx0VmFsdWU6ci5kZWZhdWx0VmFsdWUsYXN0Tm9kZTpyLmFzdE5vZGV9fSkpOm8uYXJncz1bXSxpW3RdPW99KSxpfWZ1bmN0aW9uIHcoZSl7cmV0dXJuIGUmJiJvYmplY3QiPT09KCJ1bmRlZmluZWQiPT09dHlwZW9mIGU/InVuZGVmaW5lZCI6XyhlKSkmJiFBcnJheS5pc0FycmF5KGUpfWZ1bmN0aW9uIFMoZSl7cmV0dXJuIG51bGw9PWV8fCJmdW5jdGlvbiI9PT10eXBlb2YgZX1mdW5jdGlvbiBrKGUsdCl7dmFyIG49Qyh0KTtBcnJheS5pc0FycmF5KG4pJiZuLmxlbmd0aD4wfHwoMCxGLmRlZmF1bHQpKDAsIk11c3QgcHJvdmlkZSBBcnJheSBvZiB0eXBlcyBvciBhIGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgc3VjaCBhbiBhcnJheSBmb3IgVW5pb24gIitlLm5hbWUrIi4iKTt2YXIgcj1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybiBuLmZvckVhY2goZnVuY3Rpb24odCl7dCBpbnN0YW5jZW9mIFJ8fCgwLEYuZGVmYXVsdCkoMCxlLm5hbWUrIiBtYXkgb25seSBjb250YWluIE9iamVjdCB0eXBlcywgaXQgY2Fubm90IGNvbnRhaW46ICIrU3RyaW5nKHQpKyIuIiksclt0Lm5hbWVdJiYoMCxGLmRlZmF1bHQpKDAsZS5uYW1lKyIgY2FuIGluY2x1ZGUgIit0Lm5hbWUrIiB0eXBlIG9ubHkgb25jZS4iKSxyW3QubmFtZV09ITAsImZ1bmN0aW9uIiE9PXR5cGVvZiBlLnJlc29sdmVUeXBlJiYiZnVuY3Rpb24iIT09dHlwZW9mIHQuaXNUeXBlT2YmJigwLEYuZGVmYXVsdCkoMCwnVW5pb24gdHlwZSAiJytlLm5hbWUrJyIgZG9lcyBub3QgcHJvdmlkZSBhICJyZXNvbHZlVHlwZSIgZnVuY3Rpb24gYW5kIHBvc3NpYmxlIHR5cGUgIicrdC5uYW1lKyciIGRvZXMgbm90IHByb3ZpZGUgYW4gImlzVHlwZU9mIiBmdW5jdGlvbi4gVGhlcmUgaXMgbm8gd2F5IHRvIHJlc29sdmUgdGhpcyBwb3NzaWJsZSB0eXBlIGR1cmluZyBleGVjdXRpb24uJyl9KSxufWZ1bmN0aW9uIEEoZSx0KXt3KHQpfHwoMCxGLmRlZmF1bHQpKDAsZS5uYW1lKyIgdmFsdWVzIG11c3QgYmUgYW4gb2JqZWN0IHdpdGggdmFsdWUgbmFtZXMgYXMga2V5cy4iKTt2YXIgbj1PYmplY3Qua2V5cyh0KTtyZXR1cm4gbi5sZW5ndGg+MHx8KDAsRi5kZWZhdWx0KSgwLGUubmFtZSsiIHZhbHVlcyBtdXN0IGJlIGFuIG9iamVjdCB3aXRoIHZhbHVlIG5hbWVzIGFzIGtleXMuIiksbi5tYXAoZnVuY3Rpb24obil7KDAsTS5hc3NlcnRWYWxpZE5hbWUpKG4pLC0xIT09WyJ0cnVlIiwiZmFsc2UiLCJudWxsIl0uaW5kZXhPZihuKSYmKDAsRi5kZWZhdWx0KSgwLCdOYW1lICInK24rJyIgY2FuIG5vdCBiZSB1c2VkIGFzIGFuIEVudW0gdmFsdWUuJyk7dmFyIHI9dFtuXTtyZXR1cm4gdyhyKXx8KDAsRi5kZWZhdWx0KSgwLGUubmFtZSsiLiIrbisnIG11c3QgcmVmZXIgdG8gYW4gb2JqZWN0IHdpdGggYSAidmFsdWUiIGtleSByZXByZXNlbnRpbmcgYW4gaW50ZXJuYWwgdmFsdWUgYnV0IGdvdDogJytTdHJpbmcocikrIi4iKSxyLmhhc093blByb3BlcnR5KCJpc0RlcHJlY2F0ZWQiKSYmKDAsRi5kZWZhdWx0KSgwLGUubmFtZSsiLiIrbisnIHNob3VsZCBwcm92aWRlICJkZXByZWNhdGlvblJlYXNvbiIgaW5zdGVhZCBvZiAiaXNEZXByZWNhdGVkIi4nKSx7bmFtZTpuLGRlc2NyaXB0aW9uOnIuZGVzY3JpcHRpb24saXNEZXByZWNhdGVkOkJvb2xlYW4oci5kZXByZWNhdGlvblJlYXNvbiksZGVwcmVjYXRpb25SZWFzb246ci5kZXByZWNhdGlvblJlYXNvbixhc3ROb2RlOnIuYXN0Tm9kZSx2YWx1ZTpyLmhhc093blByb3BlcnR5KCJ2YWx1ZSIpP3IudmFsdWU6bn19KX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5HcmFwaFFMTm9uTnVsbD10LkdyYXBoUUxMaXN0PXQuR3JhcGhRTElucHV0T2JqZWN0VHlwZT10LkdyYXBoUUxFbnVtVHlwZT10LkdyYXBoUUxVbmlvblR5cGU9dC5HcmFwaFFMSW50ZXJmYWNlVHlwZT10LkdyYXBoUUxPYmplY3RUeXBlPXQuR3JhcGhRTFNjYWxhclR5cGU9dm9pZCAwO3ZhciBfPSJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiYic3ltYm9sIj09PXR5cGVvZiBTeW1ib2wuaXRlcmF0b3I/ZnVuY3Rpb24oZSl7cmV0dXJuIHR5cGVvZiBlfTpmdW5jdGlvbihlKXtyZXR1cm4gZSYmImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfSxUPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspe3ZhciBuPWFyZ3VtZW50c1t0XTtmb3IodmFyIHIgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmKGVbcl09bltyXSl9cmV0dXJuIGV9O3QuaXNUeXBlPW8sdC5hc3NlcnRUeXBlPWEsdC5pc0lucHV0VHlwZT1zLHQuYXNzZXJ0SW5wdXRUeXBlPXUsdC5pc091dHB1dFR5cGU9Yyx0LmFzc2VydE91dHB1dFR5cGU9bCx0LmlzTGVhZlR5cGU9cCx0LmFzc2VydExlYWZUeXBlPWYsdC5pc0NvbXBvc2l0ZVR5cGU9ZCx0LmFzc2VydENvbXBvc2l0ZVR5cGU9aCx0LmlzQWJzdHJhY3RUeXBlPW0sdC5hc3NlcnRBYnN0cmFjdFR5cGU9Zyx0LmdldE51bGxhYmxlVHlwZT15LHQuaXNOYW1lZFR5cGU9dix0LmFzc2VydE5hbWVkVHlwZT1iLHQuZ2V0TmFtZWRUeXBlPXg7dmFyIE89bigxMyksRj1yKE8pLE49bigzNSksST1yKE4pLEw9bigxMCksUD1mdW5jdGlvbihlKXtpZihlJiZlLl9fZXNNb2R1bGUpcmV0dXJuIGU7dmFyIHQ9e307aWYobnVsbCE9ZSlmb3IodmFyIG4gaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxuKSYmKHRbbl09ZVtuXSk7cmV0dXJuIHQuZGVmYXVsdD1lLHR9KEwpLE09bigxMTEpLGo9dC5HcmFwaFFMU2NhbGFyVHlwZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7aSh0aGlzLGUpLCgwLE0uYXNzZXJ0VmFsaWROYW1lKSh0Lm5hbWUpLHRoaXMubmFtZT10Lm5hbWUsdGhpcy5kZXNjcmlwdGlvbj10LmRlc2NyaXB0aW9uLHRoaXMuYXN0Tm9kZT10LmFzdE5vZGUsImZ1bmN0aW9uIiE9PXR5cGVvZiB0LnNlcmlhbGl6ZSYmKDAsRi5kZWZhdWx0KSgwLHRoaXMubmFtZSsnIG11c3QgcHJvdmlkZSAic2VyaWFsaXplIiBmdW5jdGlvbi4gSWYgdGhpcyBjdXN0b20gU2NhbGFyIGlzIGFsc28gdXNlZCBhcyBhbiBpbnB1dCB0eXBlLCBlbnN1cmUgInBhcnNlVmFsdWUiIGFuZCAicGFyc2VMaXRlcmFsIiBmdW5jdGlvbnMgYXJlIGFsc28gcHJvdmlkZWQuJyksKHQucGFyc2VWYWx1ZXx8dC5wYXJzZUxpdGVyYWwpJiYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0LnBhcnNlVmFsdWV8fCJmdW5jdGlvbiIhPT10eXBlb2YgdC5wYXJzZUxpdGVyYWwpJiYoMCxGLmRlZmF1bHQpKDAsdGhpcy5uYW1lKycgbXVzdCBwcm92aWRlIGJvdGggInBhcnNlVmFsdWUiIGFuZCAicGFyc2VMaXRlcmFsIiBmdW5jdGlvbnMuJyksdGhpcy5fc2NhbGFyQ29uZmlnPXR9cmV0dXJuIGUucHJvdG90eXBlLnNlcmlhbGl6ZT1mdW5jdGlvbihlKXtyZXR1cm4oMCx0aGlzLl9zY2FsYXJDb25maWcuc2VyaWFsaXplKShlKX0sZS5wcm90b3R5cGUuaXNWYWxpZFZhbHVlPWZ1bmN0aW9uKGUpe3JldHVybiEoMCxJLmRlZmF1bHQpKHRoaXMucGFyc2VWYWx1ZShlKSl9LGUucHJvdG90eXBlLnBhcnNlVmFsdWU9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fc2NhbGFyQ29uZmlnLnBhcnNlVmFsdWU7cmV0dXJuIHQmJiEoMCxJLmRlZmF1bHQpKGUpP3QoZSk6dm9pZCAwfSxlLnByb3RvdHlwZS5pc1ZhbGlkTGl0ZXJhbD1mdW5jdGlvbihlKXtyZXR1cm4hKDAsSS5kZWZhdWx0KSh0aGlzLnBhcnNlTGl0ZXJhbChlKSl9LGUucHJvdG90eXBlLnBhcnNlTGl0ZXJhbD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9zY2FsYXJDb25maWcucGFyc2VMaXRlcmFsO3JldHVybiB0P3QoZSk6dm9pZCAwfSxlLnByb3RvdHlwZS50b1N0cmluZz1mdW5jdGlvbigpe3JldHVybiB0aGlzLm5hbWV9LGV9KCk7ai5wcm90b3R5cGUudG9KU09OPWoucHJvdG90eXBlLmluc3BlY3Q9ai5wcm90b3R5cGUudG9TdHJpbmc7dmFyIFI9dC5HcmFwaFFMT2JqZWN0VHlwZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7aSh0aGlzLGUpLCgwLE0uYXNzZXJ0VmFsaWROYW1lKSh0Lm5hbWUsdC5pc0ludHJvc3BlY3Rpb24pLHRoaXMubmFtZT10Lm5hbWUsdGhpcy5kZXNjcmlwdGlvbj10LmRlc2NyaXB0aW9uLHRoaXMuYXN0Tm9kZT10LmFzdE5vZGUsdGhpcy5leHRlbnNpb25BU1ROb2Rlcz10LmV4dGVuc2lvbkFTVE5vZGVzfHxbXSx0LmlzVHlwZU9mJiYiZnVuY3Rpb24iIT09dHlwZW9mIHQuaXNUeXBlT2YmJigwLEYuZGVmYXVsdCkoMCx0aGlzLm5hbWUrJyBtdXN0IHByb3ZpZGUgImlzVHlwZU9mIiBhcyBhIGZ1bmN0aW9uLicpLHRoaXMuaXNUeXBlT2Y9dC5pc1R5cGVPZix0aGlzLl90eXBlQ29uZmlnPXR9cmV0dXJuIGUucHJvdG90eXBlLmdldEZpZWxkcz1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9maWVsZHN8fCh0aGlzLl9maWVsZHM9RCh0aGlzLHRoaXMuX3R5cGVDb25maWcuZmllbGRzKSl9LGUucHJvdG90eXBlLmdldEludGVyZmFjZXM9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5faW50ZXJmYWNlc3x8KHRoaXMuX2ludGVyZmFjZXM9RSh0aGlzLHRoaXMuX3R5cGVDb25maWcuaW50ZXJmYWNlcykpfSxlLnByb3RvdHlwZS50b1N0cmluZz1mdW5jdGlvbigpe3JldHVybiB0aGlzLm5hbWV9LGV9KCk7Ui5wcm90b3R5cGUudG9KU09OPVIucHJvdG90eXBlLmluc3BlY3Q9Ui5wcm90b3R5cGUudG9TdHJpbmc7dmFyIEI9dC5HcmFwaFFMSW50ZXJmYWNlVHlwZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7aSh0aGlzLGUpLCgwLE0uYXNzZXJ0VmFsaWROYW1lKSh0Lm5hbWUpLHRoaXMubmFtZT10Lm5hbWUsdGhpcy5kZXNjcmlwdGlvbj10LmRlc2NyaXB0aW9uLHRoaXMuYXN0Tm9kZT10LmFzdE5vZGUsdC5yZXNvbHZlVHlwZSYmImZ1bmN0aW9uIiE9PXR5cGVvZiB0LnJlc29sdmVUeXBlJiYoMCxGLmRlZmF1bHQpKDAsdGhpcy5uYW1lKycgbXVzdCBwcm92aWRlICJyZXNvbHZlVHlwZSIgYXMgYSBmdW5jdGlvbi4nKSx0aGlzLnJlc29sdmVUeXBlPXQucmVzb2x2ZVR5cGUsdGhpcy5fdHlwZUNvbmZpZz10fXJldHVybiBlLnByb3RvdHlwZS5nZXRGaWVsZHM9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fZmllbGRzfHwodGhpcy5fZmllbGRzPUQodGhpcyx0aGlzLl90eXBlQ29uZmlnLmZpZWxkcykpfSxlLnByb3RvdHlwZS50b1N0cmluZz1mdW5jdGlvbigpe3JldHVybiB0aGlzLm5hbWV9LGV9KCk7Qi5wcm90b3R5cGUudG9KU09OPUIucHJvdG90eXBlLmluc3BlY3Q9Qi5wcm90b3R5cGUudG9TdHJpbmc7dmFyICQ9dC5HcmFwaFFMVW5pb25UeXBlPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0KXtpKHRoaXMsZSksKDAsTS5hc3NlcnRWYWxpZE5hbWUpKHQubmFtZSksdGhpcy5uYW1lPXQubmFtZSx0aGlzLmRlc2NyaXB0aW9uPXQuZGVzY3JpcHRpb24sdGhpcy5hc3ROb2RlPXQuYXN0Tm9kZSx0LnJlc29sdmVUeXBlJiYiZnVuY3Rpb24iIT09dHlwZW9mIHQucmVzb2x2ZVR5cGUmJigwLEYuZGVmYXVsdCkoMCx0aGlzLm5hbWUrJyBtdXN0IHByb3ZpZGUgInJlc29sdmVUeXBlIiBhcyBhIGZ1bmN0aW9uLicpLHRoaXMucmVzb2x2ZVR5cGU9dC5yZXNvbHZlVHlwZSx0aGlzLl90eXBlQ29uZmlnPXR9cmV0dXJuIGUucHJvdG90eXBlLmdldFR5cGVzPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3R5cGVzfHwodGhpcy5fdHlwZXM9ayh0aGlzLHRoaXMuX3R5cGVDb25maWcudHlwZXMpKX0sZS5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5uYW1lfSxlfSgpOyQucHJvdG90eXBlLnRvSlNPTj0kLnByb3RvdHlwZS5pbnNwZWN0PSQucHJvdG90eXBlLnRvU3RyaW5nO3ZhciBVPXQuR3JhcGhRTEVudW1UeXBlPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0KXtpKHRoaXMsZSksdGhpcy5uYW1lPXQubmFtZSwoMCxNLmFzc2VydFZhbGlkTmFtZSkodC5uYW1lLHQuaXNJbnRyb3NwZWN0aW9uKSx0aGlzLmRlc2NyaXB0aW9uPXQuZGVzY3JpcHRpb24sdGhpcy5hc3ROb2RlPXQuYXN0Tm9kZSx0aGlzLl92YWx1ZXM9QSh0aGlzLHQudmFsdWVzKSx0aGlzLl9lbnVtQ29uZmlnPXR9cmV0dXJuIGUucHJvdG90eXBlLmdldFZhbHVlcz1mdW5jdGlvbigpe3JldHVybiB0aGlzLl92YWx1ZXN9LGUucHJvdG90eXBlLmdldFZhbHVlPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9nZXROYW1lTG9va3VwKClbZV19LGUucHJvdG90eXBlLnNlcmlhbGl6ZT1mdW5jdGlvbihlKXt2YXIgdD10aGlzLl9nZXRWYWx1ZUxvb2t1cCgpLmdldChlKTtyZXR1cm4gdD90Lm5hbWU6bnVsbH0sZS5wcm90b3R5cGUuaXNWYWxpZFZhbHVlPWZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciPT09dHlwZW9mIGUmJnZvaWQgMCE9PXRoaXMuX2dldE5hbWVMb29rdXAoKVtlXX0sZS5wcm90b3R5cGUucGFyc2VWYWx1ZT1mdW5jdGlvbihlKXtpZigic3RyaW5nIj09PXR5cGVvZiBlKXt2YXIgdD10aGlzLl9nZXROYW1lTG9va3VwKClbZV07aWYodClyZXR1cm4gdC52YWx1ZX19LGUucHJvdG90eXBlLmlzVmFsaWRMaXRlcmFsPWZ1bmN0aW9uKGUpe3JldHVybiBlLmtpbmQ9PT1QLkVOVU0mJnZvaWQgMCE9PXRoaXMuX2dldE5hbWVMb29rdXAoKVtlLnZhbHVlXX0sZS5wcm90b3R5cGUucGFyc2VMaXRlcmFsPWZ1bmN0aW9uKGUpe2lmKGUua2luZD09PVAuRU5VTSl7dmFyIHQ9dGhpcy5fZ2V0TmFtZUxvb2t1cCgpW2UudmFsdWVdO2lmKHQpcmV0dXJuIHQudmFsdWV9fSxlLnByb3RvdHlwZS5fZ2V0VmFsdWVMb29rdXA9ZnVuY3Rpb24oKXtpZighdGhpcy5fdmFsdWVMb29rdXApe3ZhciBlPW5ldyBNYXA7dGhpcy5nZXRWYWx1ZXMoKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe2Uuc2V0KHQudmFsdWUsdCl9KSx0aGlzLl92YWx1ZUxvb2t1cD1lfXJldHVybiB0aGlzLl92YWx1ZUxvb2t1cH0sZS5wcm90b3R5cGUuX2dldE5hbWVMb29rdXA9ZnVuY3Rpb24oKXtpZighdGhpcy5fbmFtZUxvb2t1cCl7dmFyIGU9T2JqZWN0LmNyZWF0ZShudWxsKTt0aGlzLmdldFZhbHVlcygpLmZvckVhY2goZnVuY3Rpb24odCl7ZVt0Lm5hbWVdPXR9KSx0aGlzLl9uYW1lTG9va3VwPWV9cmV0dXJuIHRoaXMuX25hbWVMb29rdXB9LGUucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubmFtZX0sZX0oKTtVLnByb3RvdHlwZS50b0pTT049VS5wcm90b3R5cGUuaW5zcGVjdD1VLnByb3RvdHlwZS50b1N0cmluZzt2YXIgej10LkdyYXBoUUxJbnB1dE9iamVjdFR5cGU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQpe2kodGhpcyxlKSwoMCxNLmFzc2VydFZhbGlkTmFtZSkodC5uYW1lKSx0aGlzLm5hbWU9dC5uYW1lLHRoaXMuZGVzY3JpcHRpb249dC5kZXNjcmlwdGlvbix0aGlzLmFzdE5vZGU9dC5hc3ROb2RlLHRoaXMuX3R5cGVDb25maWc9dH1yZXR1cm4gZS5wcm90b3R5cGUuZ2V0RmllbGRzPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2ZpZWxkc3x8KHRoaXMuX2ZpZWxkcz10aGlzLl9kZWZpbmVGaWVsZE1hcCgpKX0sZS5wcm90b3R5cGUuX2RlZmluZUZpZWxkTWFwPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcyx0PUModGhpcy5fdHlwZUNvbmZpZy5maWVsZHMpO3codCl8fCgwLEYuZGVmYXVsdCkoMCx0aGlzLm5hbWUrIiBmaWVsZHMgbXVzdCBiZSBhbiBvYmplY3Qgd2l0aCBmaWVsZCBuYW1lcyBhcyBrZXlzIG9yIGEgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBzdWNoIGFuIG9iamVjdC4iKTt2YXIgbj1PYmplY3Qua2V5cyh0KTtuLmxlbmd0aD4wfHwoMCxGLmRlZmF1bHQpKDAsdGhpcy5uYW1lKyIgZmllbGRzIG11c3QgYmUgYW4gb2JqZWN0IHdpdGggZmllbGQgbmFtZXMgYXMga2V5cyBvciBhIGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgc3VjaCBhbiBvYmplY3QuIik7dmFyIHI9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gbi5mb3JFYWNoKGZ1bmN0aW9uKG4peygwLE0uYXNzZXJ0VmFsaWROYW1lKShuKTt2YXIgaT1UKHt9LHRbbl0se25hbWU6bn0pO3MoaS50eXBlKXx8KDAsRi5kZWZhdWx0KSgwLGUubmFtZSsiLiIrbisiIGZpZWxkIHR5cGUgbXVzdCBiZSBJbnB1dCBUeXBlIGJ1dCBnb3Q6ICIrU3RyaW5nKGkudHlwZSkrIi4iKSxudWxsIT1pLnJlc29sdmUmJigwLEYuZGVmYXVsdCkoMCxlLm5hbWUrIi4iK24rIiBmaWVsZCB0eXBlIGhhcyBhIHJlc29sdmUgcHJvcGVydHksIGJ1dCBJbnB1dCBUeXBlcyBjYW5ub3QgZGVmaW5lIHJlc29sdmVycy4iKSxyW25dPWl9KSxyfSxlLnByb3RvdHlwZS50b1N0cmluZz1mdW5jdGlvbigpe3JldHVybiB0aGlzLm5hbWV9LGV9KCk7ei5wcm90b3R5cGUudG9KU09OPXoucHJvdG90eXBlLmluc3BlY3Q9ei5wcm90b3R5cGUudG9TdHJpbmc7dmFyIEc9dC5HcmFwaFFMTGlzdD1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7aSh0aGlzLGUpLG8odCl8fCgwLEYuZGVmYXVsdCkoMCwiQ2FuIG9ubHkgY3JlYXRlIExpc3Qgb2YgYSBHcmFwaFFMVHlwZSBidXQgZ290OiAiK1N0cmluZyh0KSsiLiIpLHRoaXMub2ZUeXBlPXR9cmV0dXJuIGUucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIlsiK1N0cmluZyh0aGlzLm9mVHlwZSkrIl0ifSxlfSgpO0cucHJvdG90eXBlLnRvSlNPTj1HLnByb3RvdHlwZS5pbnNwZWN0PUcucHJvdG90eXBlLnRvU3RyaW5nO3ZhciBWPXQuR3JhcGhRTE5vbk51bGw9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQpe2kodGhpcyxlKSwoIW8odCl8fHQgaW5zdGFuY2VvZiBlKSYmKDAsRi5kZWZhdWx0KSgwLCJDYW4gb25seSBjcmVhdGUgTm9uTnVsbCBvZiBhIE51bGxhYmxlIEdyYXBoUUxUeXBlIGJ1dCBnb3Q6ICIrU3RyaW5nKHQpKyIuIiksdGhpcy5vZlR5cGU9dH1yZXR1cm4gZS5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5vZlR5cGUudG9TdHJpbmcoKSsiISJ9LGV9KCk7Vi5wcm90b3R5cGUudG9KU09OPVYucHJvdG90eXBlLmluc3BlY3Q9Vi5wcm90b3R5cGUudG9TdHJpbmd9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oMzkwKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ3JhcGhxbCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIuZ3JhcGhxbH19KTt2YXIgaT1uKDM5Myk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxTY2hlbWEiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLkdyYXBoUUxTY2hlbWF9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxTY2FsYXJUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5HcmFwaFFMU2NhbGFyVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiR3JhcGhRTE9iamVjdFR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLkdyYXBoUUxPYmplY3RUeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMSW50ZXJmYWNlVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTEludGVyZmFjZVR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxVbmlvblR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLkdyYXBoUUxVbmlvblR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxFbnVtVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTEVudW1UeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMSW5wdXRPYmplY3RUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5HcmFwaFFMSW5wdXRPYmplY3RUeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMTGlzdCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTExpc3R9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxOb25OdWxsIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5HcmFwaFFMTm9uTnVsbH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiR3JhcGhRTERpcmVjdGl2ZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTERpcmVjdGl2ZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiVHlwZUtpbmQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLlR5cGVLaW5kfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJEaXJlY3RpdmVMb2NhdGlvbiIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuRGlyZWN0aXZlTG9jYXRpb259fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxJbnQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLkdyYXBoUUxJbnR9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxGbG9hdCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTEZsb2F0fX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMU3RyaW5nIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5HcmFwaFFMU3RyaW5nfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMQm9vbGVhbiIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTEJvb2xlYW59fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxJRCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTElEfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJzcGVjaWZpZWREaXJlY3RpdmVzIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5zcGVjaWZpZWREaXJlY3RpdmVzfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMSW5jbHVkZURpcmVjdGl2ZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTEluY2x1ZGVEaXJlY3RpdmV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxTa2lwRGlyZWN0aXZlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5HcmFwaFFMU2tpcERpcmVjdGl2ZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiR3JhcGhRTERlcHJlY2F0ZWREaXJlY3RpdmUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLkdyYXBoUUxEZXByZWNhdGVkRGlyZWN0aXZlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJERUZBVUxUX0RFUFJFQ0FUSU9OX1JFQVNPTiIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuREVGQVVMVF9ERVBSRUNBVElPTl9SRUFTT059fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlNjaGVtYU1ldGFGaWVsZERlZiIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuU2NoZW1hTWV0YUZpZWxkRGVmfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJUeXBlTWV0YUZpZWxkRGVmIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5UeXBlTWV0YUZpZWxkRGVmfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJUeXBlTmFtZU1ldGFGaWVsZERlZiIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuVHlwZU5hbWVNZXRhRmllbGREZWZ9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fU2NoZW1hIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5fX1NjaGVtYX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19EaXJlY3RpdmUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLl9fRGlyZWN0aXZlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX0RpcmVjdGl2ZUxvY2F0aW9uIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5fX0RpcmVjdGl2ZUxvY2F0aW9ufX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX1R5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLl9fVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19GaWVsZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuX19GaWVsZH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19JbnB1dFZhbHVlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5fX0lucHV0VmFsdWV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fRW51bVZhbHVlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5fX0VudW1WYWx1ZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19UeXBlS2luZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuX19UeXBlS2luZH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiaXNUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5pc1R5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzSW5wdXRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5pc0lucHV0VHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiaXNPdXRwdXRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5pc091dHB1dFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzTGVhZlR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLmlzTGVhZlR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzQ29tcG9zaXRlVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuaXNDb21wb3NpdGVUeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJpc0Fic3RyYWN0VHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuaXNBYnN0cmFjdFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzTmFtZWRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5pc05hbWVkVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXNzZXJ0VHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuYXNzZXJ0VHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXNzZXJ0SW5wdXRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5hc3NlcnRJbnB1dFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImFzc2VydE91dHB1dFR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLmFzc2VydE91dHB1dFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImFzc2VydExlYWZUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5hc3NlcnRMZWFmVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXNzZXJ0Q29tcG9zaXRlVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuYXNzZXJ0Q29tcG9zaXRlVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXNzZXJ0QWJzdHJhY3RUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5hc3NlcnRBYnN0cmFjdFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImFzc2VydE5hbWVkVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuYXNzZXJ0TmFtZWRUeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJnZXROdWxsYWJsZVR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLmdldE51bGxhYmxlVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0TmFtZWRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5nZXROYW1lZFR5cGV9fSk7dmFyIG89bigzOTQpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJTb3VyY2UiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLlNvdXJjZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0TG9jYXRpb24iLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLmdldExvY2F0aW9ufX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwYXJzZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8ucGFyc2V9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInBhcnNlVmFsdWUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLnBhcnNlVmFsdWV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInBhcnNlVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8ucGFyc2VUeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwcmludCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8ucHJpbnR9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInZpc2l0Iix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby52aXNpdH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidmlzaXRJblBhcmFsbGVsIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby52aXNpdEluUGFyYWxsZWx9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInZpc2l0V2l0aFR5cGVJbmZvIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby52aXNpdFdpdGhUeXBlSW5mb319KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0VmlzaXRGbiIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8uZ2V0VmlzaXRGbn19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiS2luZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8uS2luZH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiVG9rZW5LaW5kIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby5Ub2tlbktpbmR9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkJSRUFLIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby5CUkVBS319KTt2YXIgYT1uKDM5NSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImV4ZWN1dGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBhLmV4ZWN1dGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImRlZmF1bHRGaWVsZFJlc29sdmVyIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS5kZWZhdWx0RmllbGRSZXNvbHZlcn19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwicmVzcG9uc2VQYXRoQXNBcnJheSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGEucmVzcG9uc2VQYXRoQXNBcnJheX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0RGlyZWN0aXZlVmFsdWVzIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS5nZXREaXJlY3RpdmVWYWx1ZXN9fSk7dmFyIHM9bigzOTYpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJzdWJzY3JpYmUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBzLnN1YnNjcmliZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiY3JlYXRlU291cmNlRXZlbnRTdHJlYW0iLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBzLmNyZWF0ZVNvdXJjZUV2ZW50U3RyZWFtfX0pO3ZhciB1PW4oMzk5KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidmFsaWRhdGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LnZhbGlkYXRlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJWYWxpZGF0aW9uQ29udGV4dCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuVmFsaWRhdGlvbkNvbnRleHR9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInNwZWNpZmllZFJ1bGVzIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5zcGVjaWZpZWRSdWxlc319KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiQXJndW1lbnRzT2ZDb3JyZWN0VHlwZVJ1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LkFyZ3VtZW50c09mQ29ycmVjdFR5cGVSdWxlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJEZWZhdWx0VmFsdWVzT2ZDb3JyZWN0VHlwZVJ1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LkRlZmF1bHRWYWx1ZXNPZkNvcnJlY3RUeXBlUnVsZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiRmllbGRzT25Db3JyZWN0VHlwZVJ1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LkZpZWxkc09uQ29ycmVjdFR5cGVSdWxlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJGcmFnbWVudHNPbkNvbXBvc2l0ZVR5cGVzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuRnJhZ21lbnRzT25Db21wb3NpdGVUeXBlc1J1bGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIktub3duQXJndW1lbnROYW1lc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1Lktub3duQXJndW1lbnROYW1lc1J1bGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIktub3duRGlyZWN0aXZlc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1Lktub3duRGlyZWN0aXZlc1J1bGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIktub3duRnJhZ21lbnROYW1lc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1Lktub3duRnJhZ21lbnROYW1lc1J1bGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIktub3duVHlwZU5hbWVzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuS25vd25UeXBlTmFtZXNSdWxlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJMb25lQW5vbnltb3VzT3BlcmF0aW9uUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuTG9uZUFub255bW91c09wZXJhdGlvblJ1bGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIk5vRnJhZ21lbnRDeWNsZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5Ob0ZyYWdtZW50Q3ljbGVzUnVsZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiTm9VbmRlZmluZWRWYXJpYWJsZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5Ob1VuZGVmaW5lZFZhcmlhYmxlc1J1bGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIk5vVW51c2VkRnJhZ21lbnRzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuTm9VbnVzZWRGcmFnbWVudHNSdWxlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJOb1VudXNlZFZhcmlhYmxlc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1Lk5vVW51c2VkVmFyaWFibGVzUnVsZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiT3ZlcmxhcHBpbmdGaWVsZHNDYW5CZU1lcmdlZFJ1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1Lk92ZXJsYXBwaW5nRmllbGRzQ2FuQmVNZXJnZWRSdWxlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJQb3NzaWJsZUZyYWdtZW50U3ByZWFkc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LlBvc3NpYmxlRnJhZ21lbnRTcHJlYWRzUnVsZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiUHJvdmlkZWROb25OdWxsQXJndW1lbnRzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuUHJvdmlkZWROb25OdWxsQXJndW1lbnRzUnVsZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiU2NhbGFyTGVhZnNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5TY2FsYXJMZWFmc1J1bGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlNpbmdsZUZpZWxkU3Vic2NyaXB0aW9uc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LlNpbmdsZUZpZWxkU3Vic2NyaXB0aW9uc1J1bGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlVuaXF1ZUFyZ3VtZW50TmFtZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5VbmlxdWVBcmd1bWVudE5hbWVzUnVsZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiVW5pcXVlRGlyZWN0aXZlc1BlckxvY2F0aW9uUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuVW5pcXVlRGlyZWN0aXZlc1BlckxvY2F0aW9uUnVsZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiVW5pcXVlRnJhZ21lbnROYW1lc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LlVuaXF1ZUZyYWdtZW50TmFtZXNSdWxlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJVbmlxdWVJbnB1dEZpZWxkTmFtZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5VbmlxdWVJbnB1dEZpZWxkTmFtZXNSdWxlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJVbmlxdWVPcGVyYXRpb25OYW1lc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LlVuaXF1ZU9wZXJhdGlvbk5hbWVzUnVsZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiVW5pcXVlVmFyaWFibGVOYW1lc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LlVuaXF1ZVZhcmlhYmxlTmFtZXNSdWxlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJWYXJpYWJsZXNBcmVJbnB1dFR5cGVzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuVmFyaWFibGVzQXJlSW5wdXRUeXBlc1J1bGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlZhcmlhYmxlc0luQWxsb3dlZFBvc2l0aW9uUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuVmFyaWFibGVzSW5BbGxvd2VkUG9zaXRpb25SdWxlfX0pO3ZhciBjPW4oMyk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxFcnJvciIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGMuR3JhcGhRTEVycm9yfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJmb3JtYXRFcnJvciIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGMuZm9ybWF0RXJyb3J9fSk7dmFyIGw9big0MDApO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJpbnRyb3NwZWN0aW9uUXVlcnkiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBsLmludHJvc3BlY3Rpb25RdWVyeX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0T3BlcmF0aW9uQVNUIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5nZXRPcGVyYXRpb25BU1R9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImJ1aWxkQ2xpZW50U2NoZW1hIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5idWlsZENsaWVudFNjaGVtYX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYnVpbGRBU1RTY2hlbWEiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBsLmJ1aWxkQVNUU2NoZW1hfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJidWlsZFNjaGVtYSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGwuYnVpbGRTY2hlbWF9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImV4dGVuZFNjaGVtYSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGwuZXh0ZW5kU2NoZW1hfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwcmludFNjaGVtYSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGwucHJpbnRTY2hlbWF9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInByaW50SW50cm9zcGVjdGlvblNjaGVtYSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGwucHJpbnRJbnRyb3NwZWN0aW9uU2NoZW1hfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwcmludFR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBsLnByaW50VHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidHlwZUZyb21BU1QiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBsLnR5cGVGcm9tQVNUfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJ2YWx1ZUZyb21BU1QiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBsLnZhbHVlRnJvbUFTVH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXN0RnJvbVZhbHVlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5hc3RGcm9tVmFsdWV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlR5cGVJbmZvIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5UeXBlSW5mb319KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiaXNWYWxpZEpTVmFsdWUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBsLmlzVmFsaWRKU1ZhbHVlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJpc1ZhbGlkTGl0ZXJhbFZhbHVlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5pc1ZhbGlkTGl0ZXJhbFZhbHVlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJjb25jYXRBU1QiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBsLmNvbmNhdEFTVH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwic2VwYXJhdGVPcGVyYXRpb25zIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5zZXBhcmF0ZU9wZXJhdGlvbnN9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzRXF1YWxUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5pc0VxdWFsVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiaXNUeXBlU3ViVHlwZU9mIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5pc1R5cGVTdWJUeXBlT2Z9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImRvVHlwZXNPdmVybGFwIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5kb1R5cGVzT3ZlcmxhcH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXNzZXJ0VmFsaWROYW1lIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5hc3NlcnRWYWxpZE5hbWV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImZpbmRCcmVha2luZ0NoYW5nZXMiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBsLmZpbmRCcmVha2luZ0NoYW5nZXN9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImZpbmREYW5nZXJvdXNDaGFuZ2VzIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5maW5kRGFuZ2Vyb3VzQ2hhbmdlc319KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiQnJlYWtpbmdDaGFuZ2VUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5CcmVha2luZ0NoYW5nZVR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkRhbmdlcm91c0NoYW5nZVR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBsLkRhbmdlcm91c0NoYW5nZVR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImZpbmREZXByZWNhdGVkVXNhZ2VzIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5maW5kRGVwcmVjYXRlZFVzYWdlc319KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7cmV0dXJuIGU9PT10fWZ1bmN0aW9uIGkoZSx0LG4pe2lmKG51bGw9PT10fHxudWxsPT09bnx8dC5sZW5ndGghPT1uLmxlbmd0aClyZXR1cm4hMTtmb3IodmFyIHI9dC5sZW5ndGgsaT0wO2k8cjtpKyspaWYoIWUodFtpXSxuW2ldKSlyZXR1cm4hMTtyZXR1cm4hMH1mdW5jdGlvbiBvKGUpe3ZhciB0PWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTpyLG49bnVsbCxvPW51bGw7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGkodCxuLGFyZ3VtZW50cyl8fChvPWUuYXBwbHkobnVsbCxhcmd1bWVudHMpKSxuPWFyZ3VtZW50cyxvfX1mdW5jdGlvbiBhKGUpe3ZhciB0PUFycmF5LmlzQXJyYXkoZVswXSk/ZVswXTplO2lmKCF0LmV2ZXJ5KGZ1bmN0aW9uKGUpe3JldHVybiJmdW5jdGlvbiI9PT10eXBlb2YgZX0pKXt2YXIgbj10Lm1hcChmdW5jdGlvbihlKXtyZXR1cm4gdHlwZW9mIGV9KS5qb2luKCIsICIpO3Rocm93IG5ldyBFcnJvcigiU2VsZWN0b3IgY3JlYXRvcnMgZXhwZWN0IGFsbCBpbnB1dC1zZWxlY3RvcnMgdG8gYmUgZnVuY3Rpb25zLCBpbnN0ZWFkIHJlY2VpdmVkIHRoZSBmb2xsb3dpbmcgdHlwZXM6IFsiK24rIl0iKX1yZXR1cm4gdH1mdW5jdGlvbiBzKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49QXJyYXkodD4xP3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBmdW5jdGlvbigpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLHI9QXJyYXkodCksaT0wO2k8dDtpKyspcltpXT1hcmd1bWVudHNbaV07dmFyIHM9MCx1PXIucG9wKCksYz1hKHIpLGw9ZS5hcHBseSh2b2lkIDAsW2Z1bmN0aW9uKCl7cmV0dXJuIHMrKyx1LmFwcGx5KG51bGwsYXJndW1lbnRzKX1dLmNvbmNhdChuKSkscD1vKGZ1bmN0aW9uKCl7Zm9yKHZhciBlPVtdLHQ9Yy5sZW5ndGgsbj0wO248dDtuKyspZS5wdXNoKGNbbl0uYXBwbHkobnVsbCxhcmd1bWVudHMpKTtyZXR1cm4gbC5hcHBseShudWxsLGUpfSk7cmV0dXJuIHAucmVzdWx0RnVuYz11LHAucmVjb21wdXRhdGlvbnM9ZnVuY3Rpb24oKXtyZXR1cm4gc30scC5yZXNldFJlY29tcHV0YXRpb25zPWZ1bmN0aW9uKCl7cmV0dXJuIHM9MH0scH19ZnVuY3Rpb24gdShlKXt2YXIgdD1hcmd1bWVudHMubGVuZ3RoPjEmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXT9hcmd1bWVudHNbMV06YztpZigib2JqZWN0IiE9PXR5cGVvZiBlKXRocm93IG5ldyBFcnJvcigiY3JlYXRlU3RydWN0dXJlZFNlbGVjdG9yIGV4cGVjdHMgZmlyc3QgYXJndW1lbnQgdG8gYmUgYW4gb2JqZWN0IHdoZXJlIGVhY2ggcHJvcGVydHkgaXMgYSBzZWxlY3RvciwgaW5zdGVhZCByZWNlaXZlZCBhICIrdHlwZW9mIGUpO3ZhciBuPU9iamVjdC5rZXlzKGUpO3JldHVybiB0KG4ubWFwKGZ1bmN0aW9uKHQpe3JldHVybiBlW3RdfSksZnVuY3Rpb24oKXtmb3IodmFyIGU9YXJndW1lbnRzLmxlbmd0aCx0PUFycmF5KGUpLHI9MDtyPGU7cisrKXRbcl09YXJndW1lbnRzW3JdO3JldHVybiB0LnJlZHVjZShmdW5jdGlvbihlLHQscil7cmV0dXJuIGVbbltyXV09dCxlfSx7fSl9KX10Ll9fZXNNb2R1bGU9ITAsdC5kZWZhdWx0TWVtb2l6ZT1vLHQuY3JlYXRlU2VsZWN0b3JDcmVhdG9yPXMsdC5jcmVhdGVTdHJ1Y3R1cmVkU2VsZWN0b3I9dTt2YXIgYz10LmNyZWF0ZVNlbGVjdG9yPXMobyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oMzI5KSxpPW4oMTU2KSxvPW4oMzMyKTtuLmQodCwiUHJvdmlkZXIiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuYn0pLG4uZCh0LCJjcmVhdGVQcm92aWRlciIsZnVuY3Rpb24oKXtyZXR1cm4gci5hfSksbi5kKHQsImNvbm5lY3RBZHZhbmNlZCIsZnVuY3Rpb24oKXtyZXR1cm4gaS5hfSksbi5kKHQsImNvbm5lY3QiLGZ1bmN0aW9uKCl7cmV0dXJuIG8uYX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt0Lk5BTUU9Ik5hbWUiLHQuRE9DVU1FTlQ9IkRvY3VtZW50Iix0Lk9QRVJBVElPTl9ERUZJTklUSU9OPSJPcGVyYXRpb25EZWZpbml0aW9uIix0LlZBUklBQkxFX0RFRklOSVRJT049IlZhcmlhYmxlRGVmaW5pdGlvbiIsdC5WQVJJQUJMRT0iVmFyaWFibGUiLHQuU0VMRUNUSU9OX1NFVD0iU2VsZWN0aW9uU2V0Iix0LkZJRUxEPSJGaWVsZCIsdC5BUkdVTUVOVD0iQXJndW1lbnQiLHQuRlJBR01FTlRfU1BSRUFEPSJGcmFnbWVudFNwcmVhZCIsdC5JTkxJTkVfRlJBR01FTlQ9IklubGluZUZyYWdtZW50Iix0LkZSQUdNRU5UX0RFRklOSVRJT049IkZyYWdtZW50RGVmaW5pdGlvbiIsdC5JTlQ9IkludFZhbHVlIix0LkZMT0FUPSJGbG9hdFZhbHVlIix0LlNUUklORz0iU3RyaW5nVmFsdWUiLHQuQk9PTEVBTj0iQm9vbGVhblZhbHVlIix0Lk5VTEw9Ik51bGxWYWx1ZSIsdC5FTlVNPSJFbnVtVmFsdWUiLHQuTElTVD0iTGlzdFZhbHVlIix0Lk9CSkVDVD0iT2JqZWN0VmFsdWUiLHQuT0JKRUNUX0ZJRUxEPSJPYmplY3RGaWVsZCIsdC5ESVJFQ1RJVkU9IkRpcmVjdGl2ZSIsdC5OQU1FRF9UWVBFPSJOYW1lZFR5cGUiLHQuTElTVF9UWVBFPSJMaXN0VHlwZSIsdC5OT05fTlVMTF9UWVBFPSJOb25OdWxsVHlwZSIsdC5TQ0hFTUFfREVGSU5JVElPTj0iU2NoZW1hRGVmaW5pdGlvbiIsdC5PUEVSQVRJT05fVFlQRV9ERUZJTklUSU9OPSJPcGVyYXRpb25UeXBlRGVmaW5pdGlvbiIsdC5TQ0FMQVJfVFlQRV9ERUZJTklUSU9OPSJTY2FsYXJUeXBlRGVmaW5pdGlvbiIsdC5PQkpFQ1RfVFlQRV9ERUZJTklUSU9OPSJPYmplY3RUeXBlRGVmaW5pdGlvbiIsdC5GSUVMRF9ERUZJTklUSU9OPSJGaWVsZERlZmluaXRpb24iLHQuSU5QVVRfVkFMVUVfREVGSU5JVElPTj0iSW5wdXRWYWx1ZURlZmluaXRpb24iLHQuSU5URVJGQUNFX1RZUEVfREVGSU5JVElPTj0iSW50ZXJmYWNlVHlwZURlZmluaXRpb24iLHQuVU5JT05fVFlQRV9ERUZJTklUSU9OPSJVbmlvblR5cGVEZWZpbml0aW9uIix0LkVOVU1fVFlQRV9ERUZJTklUSU9OPSJFbnVtVHlwZURlZmluaXRpb24iLHQuRU5VTV9WQUxVRV9ERUZJTklUSU9OPSJFbnVtVmFsdWVEZWZpbml0aW9uIix0LklOUFVUX09CSkVDVF9UWVBFX0RFRklOSVRJT049IklucHV0T2JqZWN0VHlwZURlZmluaXRpb24iLHQuVFlQRV9FWFRFTlNJT05fREVGSU5JVElPTj0iVHlwZUV4dGVuc2lvbkRlZmluaXRpb24iLHQuRElSRUNUSVZFX0RFRklOSVRJT049IkRpcmVjdGl2ZURlZmluaXRpb24ifSxmdW5jdGlvbihlLHQpe3ZhciBuO249ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30oKTt0cnl7bj1ufHxGdW5jdGlvbigicmV0dXJuIHRoaXMiKSgpfHwoMCxldmFsKSgidGhpcyIpfWNhdGNoKGUpeyJvYmplY3QiPT09dHlwZW9mIHdpbmRvdyYmKG49d2luZG93KX1lLmV4cG9ydHM9bn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlLmdldCgic2VsZWN0ZWRXb3Jrc3BhY2UiKX1mdW5jdGlvbiBpKGUpe3JldHVybiBlLmdldEluKFsid29ya3NwYWNlcyIscihlKV0pfHxjLm1ha2VXb3Jrc3BhY2UoIiIpfWZ1bmN0aW9uIG8oZSl7cmV0dXJuIGUuZ2V0SW4oWyJzZXR0aW5nc1N0cmluZyJdKX1mdW5jdGlvbiBhKGUpe3RyeXtyZXR1cm4gSlNPTi5wYXJzZShlKX1jYXRjaChlKXt9cmV0dXJue319ZnVuY3Rpb24gcyhlKXt2YXIgdD1lLnZhcmlhYmxlczt0cnl7cmV0dXJuIEpTT04ucGFyc2UodCl9Y2F0Y2goZSl7fXJldHVybnt9fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgdT1uKDgpLGM9bigxNyk7dC5nZXRTZXNzaW9uc1N0YXRlPXUuY3JlYXRlU2VsZWN0b3IoW2ldLGZ1bmN0aW9uKGUpe3JldHVybiBlLmdldCgic2Vzc2lvbnMiKX0pLHQuZ2V0U2VsZWN0ZWRTZXNzaW9uPXUuY3JlYXRlU2VsZWN0b3IoW3QuZ2V0U2Vzc2lvbnNTdGF0ZV0sZnVuY3Rpb24oZSl7dmFyIG49dC5nZXRTZWxlY3RlZFNlc3Npb25JZChlKTtyZXR1cm4gZS5nZXRJbihbInNlc3Npb25zIixuXSl9KSx0LmdldFNlbGVjdGVkU2Vzc2lvbklkPWZ1bmN0aW9uKGUpe3JldHVybiBlLnNlbGVjdGVkU2Vzc2lvbklkJiYiIiE9PWUuc2VsZWN0ZWRTZXNzaW9uSWQ/ZS5zZWxlY3RlZFNlc3Npb25JZDplLnNlc3Npb25zLmZpcnN0KCkuaWR9LHQuZ2V0U2VsZWN0ZWRTZXNzaW9uSWRGcm9tUm9vdD11LmNyZWF0ZVNlbGVjdG9yKFt0LmdldFNlbGVjdGVkU2Vzc2lvbl0sZnVuY3Rpb24oZSl7cmV0dXJuIGUuZ2V0KCJpZCIpfSk7dmFyIGw9ZnVuY3Rpb24oZSl7cmV0dXJuIHUuY3JlYXRlU2VsZWN0b3IoW3QuZ2V0U2VsZWN0ZWRTZXNzaW9uXSxmdW5jdGlvbih0KXtyZXR1cm4gdC5nZXQoZSl9KX07dC5nZXRTY3JvbGxUb3A9bCgic2Nyb2xsVG9wIiksdC5nZXRFbmRwb2ludD1sKCJlbmRwb2ludCIpLHQuZ2V0UXVlcnk9bCgicXVlcnkiKSx0LmdldEZpbGU9bCgiZmlsZSIpLHQuZ2V0VmFyaWFibGVzPWwoInZhcmlhYmxlcyIpLHQuZ2V0UmVzcG9uc2VzPWwoInJlc3BvbnNlcyIpLHQuZ2V0T3BlcmF0aW9uTmFtZT1sKCJvcGVyYXRpb25OYW1lIiksdC5nZXRRdWVyeVJ1bm5pbmc9bCgicXVlcnlSdW5uaW5nIiksdC5nZXRTdWJzY3JpcHRpb25BY3RpdmU9bCgic3Vic2NyaXB0aW9uQWN0aXZlIiksdC5nZXRPcGVyYXRpb25zPWwoIm9wZXJhdGlvbnMiKSx0LmdldFZhcmlhYmxlVG9UeXBlPWwoInZhcmlhYmxlVG9UeXBlIiksdC5nZXRRdWVyeVR5cGVzPWwoInF1ZXJ5VHlwZXMiKSx0LmdldERhdGU9bCgiZGF0ZSIpLHQuZ2V0SGFzTXV0YXRpb249bCgiaGFzTXV0YXRpb24iKSx0LmdldEhhc1N1YnNjcmlwdGlvbj1sKCJoYXNTdWJzY3JpcHRpb24iKSx0LmdldEhhc1F1ZXJ5PWwoImhhc1F1ZXJ5IiksdC5nZXRJc0ZpbGU9bCgiaXNGaWxlIiksdC5nZXRTdGFycmVkPWwoInN0YXJyZWQiKSx0LmdldE5hbWU9bCgibmFtZSIpLHQuZ2V0RmlsZVBhdGg9bCgiZmlsZVBhdGgiKSx0LmdldFNlbGVjdGVkVXNlclRva2VuPWwoInNlbGVjdGVkVXNlclRva2VuIiksdC5nZXRIZWFkZXJzPWwoImhlYWRlcnMiKSx0LmdldEhhc0NoYW5nZWQ9bCgiaGFzQ2hhbmdlZCIpLHQuZ2V0QWJzb2x1dGVQYXRoPWwoImFic29sdXRlUGF0aCIpLHQuZ2V0SXNTZXR0aW5nc1RhYj1sKCJpc1NldHRpbmdzVGFiIiksdC5nZXRJc0NvbmZpZ1RhYj1sKCJpc0NvbmZpZ1RhYiIpLHQuZ2V0Q3VycmVudFF1ZXJ5U3RhcnRUaW1lPWwoImN1cnJlbnRRdWVyeVN0YXJ0VGltZSIpLHQuZ2V0Q3VycmVudFF1ZXJ5RW5kVGltZT1sKCJjdXJyZW50UXVlcnlFbmRUaW1lIiksdC5nZXRJc1JlbG9hZGluZ1NjaGVtYT1sKCJpc1JlbG9hZGluZ1NjaGVtYSIpLHQuZ2V0SXNQb2xsaW5nU2NoZW1hPXUuY3JlYXRlU2VsZWN0b3IoW3QuZ2V0RW5kcG9pbnQsb10sZnVuY3Rpb24oZSx0KXt2YXIgbj1KU09OLnBhcnNlKHQpO3RyeXtyZXR1cm4gblsic2NoZW1hLnBvbGxpbmcuZW5hYmxlIl0mJmUubWF0Y2goIi8iK25bInNjaGVtYS5wb2xsaW5nLmVuZHBvaW50RmlsdGVyIl0pJiYhMH1jYXRjaChlKXtyZXR1cm4hMX19KSx0LmdldFJlc3BvbnNlRXh0ZW5zaW9ucz1sKCJyZXNwb25zZUV4dGVuc2lvbnMiKSx0LmdldFF1ZXJ5VmFyaWFibGVzQWN0aXZlPWwoInF1ZXJ5VmFyaWFibGVzQWN0aXZlIiksdC5nZXRFbmRwb2ludFVucmVhY2hhYmxlPWwoImVuZHBvaW50VW5yZWFjaGFibGUiKSx0LmdldEVkaXRvckZsZXg9bCgiZWRpdG9yRmxleCIpLHQuZ2V0VmFyaWFibGVFZGl0b3JPcGVuPWwoInZhcmlhYmxlRWRpdG9yT3BlbiIpLHQuZ2V0VmFyaWFibGVFZGl0b3JIZWlnaHQ9bCgidmFyaWFibGVFZGl0b3JIZWlnaHQiKSx0LmdldFJlc3BvbnNlVHJhY2luZ09wZW49bCgicmVzcG9uc2VUcmFjaW5nT3BlbiIpLHQuZ2V0UmVzcG9uc2VUcmFjaW5nSGVpZ2h0PWwoInJlc3BvbnNlVHJhY2luZ0hlaWdodCIpLHQuZ2V0RG9jRXhwbG9yZXJXaWR0aD1sKCJkb2NFeHBsb3JlcldpZHRoIiksdC5nZXROZXh0UXVlcnlTdGFydFRpbWU9bCgibmV4dFF1ZXJ5U3RhcnRUaW1lIiksdC5nZXRUcmFjaW5nU3VwcG9ydGVkPWwoInRyYWNpbmdTdXBwb3J0ZWQiKSx0LmdldFRhYldpZHRoPXUuY3JlYXRlU2VsZWN0b3IoW29dLGZ1bmN0aW9uKGUpe3RyeXtyZXR1cm4gSlNPTi5wYXJzZShlKVsicHJldHRpZXIudGFiV2lkdGgiXXx8Mn1jYXRjaChlKXt9cmV0dXJuIDJ9KSx0LmdldFVzZVRhYnM9dS5jcmVhdGVTZWxlY3Rvcihbb10sZnVuY3Rpb24oZSl7dHJ5e3JldHVybiBKU09OLnBhcnNlKGUpWyJwcmV0dGllci51c2VUYWJzIl18fCExfWNhdGNoKGUpe31yZXR1cm4hMX0pLHQuZ2V0SGVhZGVyc0NvdW50PXUuY3JlYXRlU2VsZWN0b3IoW3QuZ2V0SGVhZGVyc10sZnVuY3Rpb24oZSl7dHJ5e3ZhciB0PUpTT04ucGFyc2UoZSk7cmV0dXJuIE9iamVjdC5rZXlzKHQpLmxlbmd0aH1jYXRjaChlKXt9cmV0dXJuIDB9KSx0LmdldFBhcnNlZEhlYWRlcnM9dS5jcmVhdGVTZWxlY3RvcihbdC5nZXRTZWxlY3RlZFNlc3Npb25dLGEpLHQuZ2V0UGFyc2VkSGVhZGVyc0Zyb21TZXNzaW9uPWEsdC5nZXRQYXJzZWRWYXJpYWJsZXM9dS5jcmVhdGVTZWxlY3RvcihbdC5nZXRTZWxlY3RlZFNlc3Npb25dLHMpLHQuZ2V0UGFyc2VkVmFyaWFibGVzRnJvbVNlc3Npb249cyx0LmdldFRyYWNpbmc9dS5jcmVhdGVTZWxlY3RvcihbdC5nZXRSZXNwb25zZUV4dGVuc2lvbnNdLGZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLnRyYWNpbmd9KSx0LmdldFNlc3Npb25zQXJyYXk9dS5jcmVhdGVTZWxlY3RvcihbdC5nZXRTZXNzaW9uc1N0YXRlXSxmdW5jdGlvbihlKXtyZXR1cm4gZS5nZXQoInNlc3Npb25zIikudG9BcnJheSgpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZVsxXX0pfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2lmKCFlKXRocm93IG5ldyBFcnJvcih0KX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZS52YWx1ZT0hMSxlfWZ1bmN0aW9uIGkoZSl7ZSYmKGUudmFsdWU9ITApfWZ1bmN0aW9uIG8oKXt9ZnVuY3Rpb24gYShlKXtyZXR1cm4gdm9pZCAwPT09ZS5zaXplJiYoZS5zaXplPWUuX19pdGVyYXRlKHUpKSxlLnNpemV9ZnVuY3Rpb24gcyhlLHQpe2lmKCJudW1iZXIiIT09dHlwZW9mIHQpe3ZhciBuPXQ+Pj4wO2lmKCIiK24hPT10fHw0Mjk0OTY3Mjk1PT09bilyZXR1cm4gTmFOO3Q9bn1yZXR1cm4gdDwwP2EoZSkrdDp0fWZ1bmN0aW9uIHUoKXtyZXR1cm4hMH1mdW5jdGlvbiBjKGUsdCxuKXtyZXR1cm4oMD09PWUmJiFkKGUpfHx2b2lkIDAhPT1uJiZlPD0tbikmJih2b2lkIDA9PT10fHx2b2lkIDAhPT1uJiZ0Pj1uKX1mdW5jdGlvbiBsKGUsdCl7cmV0dXJuIGYoZSx0LDApfWZ1bmN0aW9uIHAoZSx0KXtyZXR1cm4gZihlLHQsdCl9ZnVuY3Rpb24gZihlLHQsbil7cmV0dXJuIHZvaWQgMD09PWU/bjpkKGUpP3Q9PT0xLzA/dDowfE1hdGgubWF4KDAsdCtlKTp2b2lkIDA9PT10fHx0PT09ZT9lOjB8TWF0aC5taW4odCxlKX1mdW5jdGlvbiBkKGUpe3JldHVybiBlPDB8fDA9PT1lJiYxL2U9PT0tMS8wfWZ1bmN0aW9uIGgoZSl7cmV0dXJuIG0oZSl8fHgoZSl9ZnVuY3Rpb24gbShlKXtyZXR1cm4hKCFlfHwhZVtobl0pfWZ1bmN0aW9uIGcoZSl7cmV0dXJuISghZXx8IWVbbW5dKX1mdW5jdGlvbiB5KGUpe3JldHVybiEoIWV8fCFlW2duXSl9ZnVuY3Rpb24gdihlKXtyZXR1cm4gZyhlKXx8eShlKX1mdW5jdGlvbiBiKGUpe3JldHVybiEoIWV8fCFlW3luXSl9ZnVuY3Rpb24geChlKXtyZXR1cm4hKCFlfHwhZVt2bl0pfWZ1bmN0aW9uIEMoZSl7cmV0dXJuISghZXx8ImZ1bmN0aW9uIiE9PXR5cGVvZiBlLmVxdWFsc3x8ImZ1bmN0aW9uIiE9PXR5cGVvZiBlLmhhc2hDb2RlKX1mdW5jdGlvbiBFKGUsdCxuLHIpe3ZhciBpPTA9PT1lP3Q6MT09PWU/bjpbdCxuXTtyZXR1cm4gcj9yLnZhbHVlPWk6cj17dmFsdWU6aSxkb25lOiExfSxyfWZ1bmN0aW9uIEQoKXtyZXR1cm57dmFsdWU6dm9pZCAwLGRvbmU6ITB9fWZ1bmN0aW9uIHcoZSl7cmV0dXJuISFBKGUpfWZ1bmN0aW9uIFMoZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PT10eXBlb2YgZS5uZXh0fWZ1bmN0aW9uIGsoZSl7dmFyIHQ9QShlKTtyZXR1cm4gdCYmdC5jYWxsKGUpfWZ1bmN0aW9uIEEoZSl7dmFyIHQ9ZSYmKGtuJiZlW2tuXXx8ZVtBbl0pO2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgdClyZXR1cm4gdH1mdW5jdGlvbiBfKGUpe3JldHVybiBlJiYibnVtYmVyIj09PXR5cGVvZiBlLmxlbmd0aH1mdW5jdGlvbiBUKGUpe3JldHVybiEoIWV8fCFlW1BuXSl9ZnVuY3Rpb24gTygpe3JldHVybiBSbnx8KFJuPW5ldyBNbihbXSkpfWZ1bmN0aW9uIEYoZSl7dmFyIHQ9QXJyYXkuaXNBcnJheShlKT9uZXcgTW4oZSk6UyhlKT9uZXcgVW4oZSk6dyhlKT9uZXcgJG4oZSk6dm9pZCAwO2lmKHQpcmV0dXJuIHQuZnJvbUVudHJ5U2VxKCk7aWYoIm9iamVjdCI9PT10eXBlb2YgZSlyZXR1cm4gbmV3IGpuKGUpO3Rocm93IG5ldyBUeXBlRXJyb3IoIkV4cGVjdGVkIEFycmF5IG9yIGNvbGxlY3Rpb24gb2JqZWN0IG9mIFtrLCB2XSBlbnRyaWVzLCBvciBrZXllZCBvYmplY3Q6ICIrZSl9ZnVuY3Rpb24gTihlKXt2YXIgdD1MKGUpO2lmKHQpcmV0dXJuIHQ7dGhyb3cgbmV3IFR5cGVFcnJvcigiRXhwZWN0ZWQgQXJyYXkgb3IgY29sbGVjdGlvbiBvYmplY3Qgb2YgdmFsdWVzOiAiK2UpfWZ1bmN0aW9uIEkoZSl7dmFyIHQ9TChlKTtpZih0KXJldHVybiB0O2lmKCJvYmplY3QiPT09dHlwZW9mIGUpcmV0dXJuIG5ldyBqbihlKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJFeHBlY3RlZCBBcnJheSBvciBjb2xsZWN0aW9uIG9iamVjdCBvZiB2YWx1ZXMsIG9yIGtleWVkIG9iamVjdDogIitlKX1mdW5jdGlvbiBMKGUpe3JldHVybiBfKGUpP25ldyBNbihlKTpTKGUpP25ldyBVbihlKTp3KGUpP25ldyAkbihlKTp2b2lkIDB9ZnVuY3Rpb24gUChlLHQpe2lmKGU9PT10fHxlIT09ZSYmdCE9PXQpcmV0dXJuITA7aWYoIWV8fCF0KXJldHVybiExO2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgZS52YWx1ZU9mJiYiZnVuY3Rpb24iPT09dHlwZW9mIHQudmFsdWVPZil7aWYoZT1lLnZhbHVlT2YoKSx0PXQudmFsdWVPZigpLGU9PT10fHxlIT09ZSYmdCE9PXQpcmV0dXJuITA7aWYoIWV8fCF0KXJldHVybiExfXJldHVybiEhKEMoZSkmJkModCkmJmUuZXF1YWxzKHQpKX1mdW5jdGlvbiBNKGUpe3JldHVybiBlPj4+MSYxMDczNzQxODI0fDMyMjEyMjU0NzEmZX1mdW5jdGlvbiBqKGUpe2lmKCExPT09ZXx8bnVsbD09PWV8fHZvaWQgMD09PWUpcmV0dXJuIDA7aWYoImZ1bmN0aW9uIj09PXR5cGVvZiBlLnZhbHVlT2YmJighMT09PShlPWUudmFsdWVPZigpKXx8bnVsbD09PWV8fHZvaWQgMD09PWUpKXJldHVybiAwO2lmKCEwPT09ZSlyZXR1cm4gMTt2YXIgdD10eXBlb2YgZTtpZigibnVtYmVyIj09PXQpe2lmKGUhPT1lfHxlPT09MS8wKXJldHVybiAwO3ZhciBuPTB8ZTtmb3IobiE9PWUmJihuXj00Mjk0OTY3Mjk1KmUpO2U+NDI5NDk2NzI5NTspZS89NDI5NDk2NzI5NSxuXj1lO3JldHVybiBNKG4pfWlmKCJzdHJpbmciPT09dClyZXR1cm4gZS5sZW5ndGg+UW4/UihlKTpCKGUpO2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgZS5oYXNoQ29kZSlyZXR1cm4gTShlLmhhc2hDb2RlKCkpO2lmKCJvYmplY3QiPT09dClyZXR1cm4gJChlKTtpZigiZnVuY3Rpb24iPT09dHlwZW9mIGUudG9TdHJpbmcpcmV0dXJuIEIoZS50b1N0cmluZygpKTt0aHJvdyBuZXcgRXJyb3IoIlZhbHVlIHR5cGUgIit0KyIgY2Fubm90IGJlIGhhc2hlZC4iKX1mdW5jdGlvbiBSKGUpe3ZhciB0PVluW2VdO3JldHVybiB2b2lkIDA9PT10JiYodD1CKGUpLEpuPT09S24mJihKbj0wLFluPXt9KSxKbisrLFluW2VdPXQpLHR9ZnVuY3Rpb24gQihlKXtmb3IodmFyIHQ9MCxuPTA7bjxlLmxlbmd0aDtuKyspdD0zMSp0K2UuY2hhckNvZGVBdChuKXwwO3JldHVybiBNKHQpfWZ1bmN0aW9uICQoZSl7dmFyIHQ7aWYocW4mJnZvaWQgMCE9PSh0PUJuLmdldChlKSkpcmV0dXJuIHQ7aWYodm9pZCAwIT09KHQ9ZVtXbl0pKXJldHVybiB0O2lmKCFWbil7aWYodm9pZCAwIT09KHQ9ZS5wcm9wZXJ0eUlzRW51bWVyYWJsZSYmZS5wcm9wZXJ0eUlzRW51bWVyYWJsZVtXbl0pKXJldHVybiB0O2lmKHZvaWQgMCE9PSh0PVUoZSkpKXJldHVybiB0fWlmKHQ9KytIbiwxMDczNzQxODI0JkhuJiYoSG49MCkscW4pQm4uc2V0KGUsdCk7ZWxzZXtpZih2b2lkIDAhPT1HbiYmITE9PT1HbihlKSl0aHJvdyBuZXcgRXJyb3IoIk5vbi1leHRlbnNpYmxlIG9iamVjdHMgYXJlIG5vdCBhbGxvd2VkIGFzIGtleXMuIik7aWYoVm4pT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsV24se2VudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiExLHdyaXRhYmxlOiExLHZhbHVlOnR9KTtlbHNlIGlmKHZvaWQgMCE9PWUucHJvcGVydHlJc0VudW1lcmFibGUmJmUucHJvcGVydHlJc0VudW1lcmFibGU9PT1lLmNvbnN0cnVjdG9yLnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZSllLnByb3BlcnR5SXNFbnVtZXJhYmxlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IucHJvdG90eXBlLnByb3BlcnR5SXNFbnVtZXJhYmxlLmFwcGx5KHRoaXMsYXJndW1lbnRzKX0sZS5wcm9wZXJ0eUlzRW51bWVyYWJsZVtXbl09dDtlbHNle2lmKHZvaWQgMD09PWUubm9kZVR5cGUpdGhyb3cgbmV3IEVycm9yKCJVbmFibGUgdG8gc2V0IGEgbm9uLWVudW1lcmFibGUgcHJvcGVydHkgb24gb2JqZWN0LiIpO2VbV25dPXR9fXJldHVybiB0fWZ1bmN0aW9uIFUoZSl7aWYoZSYmZS5ub2RlVHlwZT4wKXN3aXRjaChlLm5vZGVUeXBlKXtjYXNlIDE6cmV0dXJuIGUudW5pcXVlSUQ7Y2FzZSA5OnJldHVybiBlLmRvY3VtZW50RWxlbWVudCYmZS5kb2N1bWVudEVsZW1lbnQudW5pcXVlSUR9fWZ1bmN0aW9uIHooZSl7dmFyIHQ9dWUoZSk7cmV0dXJuIHQuX2l0ZXI9ZSx0LnNpemU9ZS5zaXplLHQuZmxpcD1mdW5jdGlvbigpe3JldHVybiBlfSx0LnJldmVyc2U9ZnVuY3Rpb24oKXt2YXIgdD1lLnJldmVyc2UuYXBwbHkodGhpcyk7cmV0dXJuIHQuZmxpcD1mdW5jdGlvbigpe3JldHVybiBlLnJldmVyc2UoKX0sdH0sdC5oYXM9ZnVuY3Rpb24odCl7cmV0dXJuIGUuaW5jbHVkZXModCl9LHQuaW5jbHVkZXM9ZnVuY3Rpb24odCl7cmV0dXJuIGUuaGFzKHQpfSx0LmNhY2hlUmVzdWx0PWNlLHQuX19pdGVyYXRlVW5jYWNoZWQ9ZnVuY3Rpb24odCxuKXt2YXIgcj10aGlzO3JldHVybiBlLl9faXRlcmF0ZShmdW5jdGlvbihlLG4pe3JldHVybiExIT09dChuLGUscil9LG4pfSx0Ll9faXRlcmF0b3JVbmNhY2hlZD1mdW5jdGlvbih0LG4pe2lmKHQ9PT1Tbil7dmFyIHI9ZS5fX2l0ZXJhdG9yKHQsbik7cmV0dXJuIG5ldyBUbihmdW5jdGlvbigpe3ZhciBlPXIubmV4dCgpO2lmKCFlLmRvbmUpe3ZhciB0PWUudmFsdWVbMF07ZS52YWx1ZVswXT1lLnZhbHVlWzFdLGUudmFsdWVbMV09dH1yZXR1cm4gZX0pfXJldHVybiBlLl9faXRlcmF0b3IodD09PXduP0RuOnduLG4pfSx0fWZ1bmN0aW9uIEcoZSx0LG4pe3ZhciByPXVlKGUpO3JldHVybiByLnNpemU9ZS5zaXplLHIuaGFzPWZ1bmN0aW9uKHQpe3JldHVybiBlLmhhcyh0KX0sci5nZXQ9ZnVuY3Rpb24ocixpKXt2YXIgbz1lLmdldChyLHBuKTtyZXR1cm4gbz09PXBuP2k6dC5jYWxsKG4sbyxyLGUpfSxyLl9faXRlcmF0ZVVuY2FjaGVkPWZ1bmN0aW9uKHIsaSl7dmFyIG89dGhpcztyZXR1cm4gZS5fX2l0ZXJhdGUoZnVuY3Rpb24oZSxpLGEpe3JldHVybiExIT09cih0LmNhbGwobixlLGksYSksaSxvKX0saSl9LHIuX19pdGVyYXRvclVuY2FjaGVkPWZ1bmN0aW9uKHIsaSl7dmFyIG89ZS5fX2l0ZXJhdG9yKFNuLGkpO3JldHVybiBuZXcgVG4oZnVuY3Rpb24oKXt2YXIgaT1vLm5leHQoKTtpZihpLmRvbmUpcmV0dXJuIGk7dmFyIGE9aS52YWx1ZSxzPWFbMF07cmV0dXJuIEUocixzLHQuY2FsbChuLGFbMV0scyxlKSxpKX0pfSxyfWZ1bmN0aW9uIFYoZSx0KXt2YXIgbj10aGlzLHI9dWUoZSk7cmV0dXJuIHIuX2l0ZXI9ZSxyLnNpemU9ZS5zaXplLHIucmV2ZXJzZT1mdW5jdGlvbigpe3JldHVybiBlfSxlLmZsaXAmJihyLmZsaXA9ZnVuY3Rpb24oKXt2YXIgdD16KGUpO3JldHVybiB0LnJldmVyc2U9ZnVuY3Rpb24oKXtyZXR1cm4gZS5mbGlwKCl9LHR9KSxyLmdldD1mdW5jdGlvbihuLHIpe3JldHVybiBlLmdldCh0P246LTEtbixyKX0sci5oYXM9ZnVuY3Rpb24obil7cmV0dXJuIGUuaGFzKHQ/bjotMS1uKX0sci5pbmNsdWRlcz1mdW5jdGlvbih0KXtyZXR1cm4gZS5pbmNsdWRlcyh0KX0sci5jYWNoZVJlc3VsdD1jZSxyLl9faXRlcmF0ZT1mdW5jdGlvbihuLHIpe3ZhciBpPXRoaXMsbz0wO3JldHVybiByJiZhKGUpLGUuX19pdGVyYXRlKGZ1bmN0aW9uKGUsYSl7cmV0dXJuIG4oZSx0P2E6cj9pLnNpemUtKytvOm8rKyxpKX0sIXIpfSxyLl9faXRlcmF0b3I9ZnVuY3Rpb24ocixpKXt2YXIgbz0wO2kmJmEoZSk7dmFyIHM9ZS5fX2l0ZXJhdG9yKFNuLCFpKTtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7dmFyIGU9cy5uZXh0KCk7aWYoZS5kb25lKXJldHVybiBlO3ZhciBhPWUudmFsdWU7cmV0dXJuIEUocix0P2FbMF06aT9uLnNpemUtKytvOm8rKyxhWzFdLGUpfSl9LHJ9ZnVuY3Rpb24gcShlLHQsbixyKXt2YXIgaT11ZShlKTtyZXR1cm4gciYmKGkuaGFzPWZ1bmN0aW9uKHIpe3ZhciBpPWUuZ2V0KHIscG4pO3JldHVybiBpIT09cG4mJiEhdC5jYWxsKG4saSxyLGUpfSxpLmdldD1mdW5jdGlvbihyLGkpe3ZhciBvPWUuZ2V0KHIscG4pO3JldHVybiBvIT09cG4mJnQuY2FsbChuLG8scixlKT9vOml9KSxpLl9faXRlcmF0ZVVuY2FjaGVkPWZ1bmN0aW9uKGksbyl7dmFyIGE9dGhpcyxzPTA7cmV0dXJuIGUuX19pdGVyYXRlKGZ1bmN0aW9uKGUsbyx1KXtpZih0LmNhbGwobixlLG8sdSkpcmV0dXJuIHMrKyxpKGUscj9vOnMtMSxhKX0sbyksc30saS5fX2l0ZXJhdG9yVW5jYWNoZWQ9ZnVuY3Rpb24oaSxvKXt2YXIgYT1lLl9faXRlcmF0b3IoU24sbykscz0wO3JldHVybiBuZXcgVG4oZnVuY3Rpb24oKXtmb3IoOzspe3ZhciBvPWEubmV4dCgpO2lmKG8uZG9uZSlyZXR1cm4gbzt2YXIgdT1vLnZhbHVlLGM9dVswXSxsPXVbMV07aWYodC5jYWxsKG4sbCxjLGUpKXJldHVybiBFKGkscj9jOnMrKyxsLG8pfX0pfSxpfWZ1bmN0aW9uIEgoZSx0LG4pe3ZhciByPW5yKCkuYXNNdXRhYmxlKCk7cmV0dXJuIGUuX19pdGVyYXRlKGZ1bmN0aW9uKGksbyl7ci51cGRhdGUodC5jYWxsKG4saSxvLGUpLDAsZnVuY3Rpb24oZSl7cmV0dXJuIGUrMX0pfSksci5hc0ltbXV0YWJsZSgpfWZ1bmN0aW9uIFcoZSx0LG4pe3ZhciByPWcoZSksaT0oYihlKT9DcigpOm5yKCkpLmFzTXV0YWJsZSgpO2UuX19pdGVyYXRlKGZ1bmN0aW9uKG8sYSl7aS51cGRhdGUodC5jYWxsKG4sbyxhLGUpLGZ1bmN0aW9uKGUpe3JldHVybiBlPWV8fFtdLGUucHVzaChyP1thLG9dOm8pLGV9KX0pO3ZhciBvPXNlKGUpO3JldHVybiBpLm1hcChmdW5jdGlvbih0KXtyZXR1cm4gb2UoZSxvKHQpKX0pfWZ1bmN0aW9uIFEoZSx0LG4scil7dmFyIGk9ZS5zaXplO2lmKGModCxuLGkpKXJldHVybiBlO3ZhciBvPWwodCxpKSxhPXAobixpKTtpZihvIT09b3x8YSE9PWEpcmV0dXJuIFEoZS50b1NlcSgpLmNhY2hlUmVzdWx0KCksdCxuLHIpO3ZhciB1LGY9YS1vO2Y9PT1mJiYodT1mPDA/MDpmKTt2YXIgZD11ZShlKTtyZXR1cm4gZC5zaXplPTA9PT11P3U6ZS5zaXplJiZ1fHx2b2lkIDAsIXImJlQoZSkmJnU+PTAmJihkLmdldD1mdW5jdGlvbih0LG4pe3JldHVybiB0PXModGhpcyx0KSx0Pj0wJiZ0PHU/ZS5nZXQodCtvLG4pOm59KSxkLl9faXRlcmF0ZVVuY2FjaGVkPWZ1bmN0aW9uKHQsbil7dmFyIGk9dGhpcztpZigwPT09dSlyZXR1cm4gMDtpZihuKXJldHVybiB0aGlzLmNhY2hlUmVzdWx0KCkuX19pdGVyYXRlKHQsbik7dmFyIGE9MCxzPSEwLGM9MDtyZXR1cm4gZS5fX2l0ZXJhdGUoZnVuY3Rpb24oZSxuKXtpZighc3x8IShzPWErKzxvKSlyZXR1cm4gYysrLCExIT09dChlLHI/bjpjLTEsaSkmJmMhPT11fSksY30sZC5fX2l0ZXJhdG9yVW5jYWNoZWQ9ZnVuY3Rpb24odCxuKXtpZigwIT09dSYmbilyZXR1cm4gdGhpcy5jYWNoZVJlc3VsdCgpLl9faXRlcmF0b3IodCxuKTtpZigwPT09dSlyZXR1cm4gbmV3IFRuKEQpO3ZhciBpPWUuX19pdGVyYXRvcih0LG4pLGE9MCxzPTA7cmV0dXJuIG5ldyBUbihmdW5jdGlvbigpe2Zvcig7YSsrPG87KWkubmV4dCgpO2lmKCsrcz51KXJldHVybiBEKCk7dmFyIGU9aS5uZXh0KCk7cmV0dXJuIHJ8fHQ9PT13bnx8ZS5kb25lP2U6dD09PURuP0UodCxzLTEsdm9pZCAwLGUpOkUodCxzLTEsZS52YWx1ZVsxXSxlKX0pfSxkfWZ1bmN0aW9uIEsoZSx0LG4pe3ZhciByPXVlKGUpO3JldHVybiByLl9faXRlcmF0ZVVuY2FjaGVkPWZ1bmN0aW9uKHIsaSl7dmFyIG89dGhpcztpZihpKXJldHVybiB0aGlzLmNhY2hlUmVzdWx0KCkuX19pdGVyYXRlKHIsaSk7dmFyIGE9MDtyZXR1cm4gZS5fX2l0ZXJhdGUoZnVuY3Rpb24oZSxpLHMpe3JldHVybiB0LmNhbGwobixlLGkscykmJisrYSYmcihlLGksbyl9KSxhfSxyLl9faXRlcmF0b3JVbmNhY2hlZD1mdW5jdGlvbihyLGkpe3ZhciBvPXRoaXM7aWYoaSlyZXR1cm4gdGhpcy5jYWNoZVJlc3VsdCgpLl9faXRlcmF0b3IocixpKTt2YXIgYT1lLl9faXRlcmF0b3IoU24saSkscz0hMDtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7aWYoIXMpcmV0dXJuIEQoKTt2YXIgZT1hLm5leHQoKTtpZihlLmRvbmUpcmV0dXJuIGU7dmFyIGk9ZS52YWx1ZSx1PWlbMF0sYz1pWzFdO3JldHVybiB0LmNhbGwobixjLHUsbyk/cj09PVNuP2U6RShyLHUsYyxlKToocz0hMSxEKCkpfSl9LHJ9ZnVuY3Rpb24gSihlLHQsbixyKXt2YXIgaT11ZShlKTtyZXR1cm4gaS5fX2l0ZXJhdGVVbmNhY2hlZD1mdW5jdGlvbihpLG8pe3ZhciBhPXRoaXM7aWYobylyZXR1cm4gdGhpcy5jYWNoZVJlc3VsdCgpLl9faXRlcmF0ZShpLG8pO3ZhciBzPSEwLHU9MDtyZXR1cm4gZS5fX2l0ZXJhdGUoZnVuY3Rpb24oZSxvLGMpe2lmKCFzfHwhKHM9dC5jYWxsKG4sZSxvLGMpKSlyZXR1cm4gdSsrLGkoZSxyP286dS0xLGEpfSksdX0saS5fX2l0ZXJhdG9yVW5jYWNoZWQ9ZnVuY3Rpb24oaSxvKXt2YXIgYT10aGlzO2lmKG8pcmV0dXJuIHRoaXMuY2FjaGVSZXN1bHQoKS5fX2l0ZXJhdG9yKGksbyk7dmFyIHM9ZS5fX2l0ZXJhdG9yKFNuLG8pLHU9ITAsYz0wO3JldHVybiBuZXcgVG4oZnVuY3Rpb24oKXt2YXIgZSxvLGw7ZG97aWYoZT1zLm5leHQoKSxlLmRvbmUpcmV0dXJuIHJ8fGk9PT13bj9lOmk9PT1Ebj9FKGksYysrLHZvaWQgMCxlKTpFKGksYysrLGUudmFsdWVbMV0sZSk7dmFyIHA9ZS52YWx1ZTtvPXBbMF0sbD1wWzFdLHUmJih1PXQuY2FsbChuLGwsbyxhKSl9d2hpbGUodSk7cmV0dXJuIGk9PT1Tbj9lOkUoaSxvLGwsZSl9KX0saX1mdW5jdGlvbiBZKGUsdCl7dmFyIG49ZyhlKSxyPVtlXS5jb25jYXQodCkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBtKGUpP24mJihlPXhuKGUpKTplPW4/RihlKTpOKEFycmF5LmlzQXJyYXkoZSk/ZTpbZV0pLGV9KS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIDAhPT1lLnNpemV9KTtpZigwPT09ci5sZW5ndGgpcmV0dXJuIGU7aWYoMT09PXIubGVuZ3RoKXt2YXIgaT1yWzBdO2lmKGk9PT1lfHxuJiZnKGkpfHx5KGUpJiZ5KGkpKXJldHVybiBpfXZhciBvPW5ldyBNbihyKTtyZXR1cm4gbj9vPW8udG9LZXllZFNlcSgpOnkoZSl8fChvPW8udG9TZXRTZXEoKSksbz1vLmZsYXR0ZW4oITApLG8uc2l6ZT1yLnJlZHVjZShmdW5jdGlvbihlLHQpe2lmKHZvaWQgMCE9PWUpe3ZhciBuPXQuc2l6ZTtpZih2b2lkIDAhPT1uKXJldHVybiBlK259fSwwKSxvfWZ1bmN0aW9uIFgoZSx0LG4pe3ZhciByPXVlKGUpO3JldHVybiByLl9faXRlcmF0ZVVuY2FjaGVkPWZ1bmN0aW9uKGksbyl7ZnVuY3Rpb24gYShlLGMpe2UuX19pdGVyYXRlKGZ1bmN0aW9uKGUsbyl7cmV0dXJuKCF0fHxjPHQpJiZtKGUpP2EoZSxjKzEpOihzKyssITE9PT1pKGUsbj9vOnMtMSxyKSYmKHU9ITApKSwhdX0sbyl9aWYobylyZXR1cm4gdGhpcy5jYWNoZVJlc3VsdCgpLl9faXRlcmF0ZShpLG8pO3ZhciBzPTAsdT0hMTtyZXR1cm4gYShlLDApLHN9LHIuX19pdGVyYXRvclVuY2FjaGVkPWZ1bmN0aW9uKHIsaSl7aWYoaSlyZXR1cm4gdGhpcy5jYWNoZVJlc3VsdCgpLl9faXRlcmF0b3IocixpKTt2YXIgbz1lLl9faXRlcmF0b3IocixpKSxhPVtdLHM9MDtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7Zm9yKDtvOyl7dmFyIGU9by5uZXh0KCk7aWYoITE9PT1lLmRvbmUpe3ZhciB1PWUudmFsdWU7aWYocj09PVNuJiYodT11WzFdKSx0JiYhKGEubGVuZ3RoPHQpfHwhbSh1KSlyZXR1cm4gbj9lOkUocixzKyssdSxlKTthLnB1c2gobyksbz11Ll9faXRlcmF0b3IocixpKX1lbHNlIG89YS5wb3AoKX1yZXR1cm4gRCgpfSl9LHJ9ZnVuY3Rpb24gWihlLHQsbil7dmFyIHI9c2UoZSk7cmV0dXJuIGUudG9TZXEoKS5tYXAoZnVuY3Rpb24oaSxvKXtyZXR1cm4gcih0LmNhbGwobixpLG8sZSkpfSkuZmxhdHRlbighMCl9ZnVuY3Rpb24gZWUoZSx0KXt2YXIgbj11ZShlKTtyZXR1cm4gbi5zaXplPWUuc2l6ZSYmMiplLnNpemUtMSxuLl9faXRlcmF0ZVVuY2FjaGVkPWZ1bmN0aW9uKG4scil7dmFyIGk9dGhpcyxvPTA7cmV0dXJuIGUuX19pdGVyYXRlKGZ1bmN0aW9uKGUpe3JldHVybighb3x8ITEhPT1uKHQsbysrLGkpKSYmITEhPT1uKGUsbysrLGkpfSxyKSxvfSxuLl9faXRlcmF0b3JVbmNhY2hlZD1mdW5jdGlvbihuLHIpe3ZhciBpLG89ZS5fX2l0ZXJhdG9yKHduLHIpLGE9MDtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7cmV0dXJuKCFpfHxhJTIpJiYoaT1vLm5leHQoKSxpLmRvbmUpP2k6YSUyP0UobixhKyssdCk6RShuLGErKyxpLnZhbHVlLGkpfSl9LG59ZnVuY3Rpb24gdGUoZSx0LG4pe3R8fCh0PWxlKTt2YXIgcj1nKGUpLGk9MCxvPWUudG9TZXEoKS5tYXAoZnVuY3Rpb24odCxyKXtyZXR1cm5bcix0LGkrKyxuP24odCxyLGUpOnRdfSkudmFsdWVTZXEoKS50b0FycmF5KCk7cmV0dXJuIG8uc29ydChmdW5jdGlvbihlLG4pe3JldHVybiB0KGVbM10sblszXSl8fGVbMl0tblsyXX0pLmZvckVhY2gocj9mdW5jdGlvbihlLHQpe29bdF0ubGVuZ3RoPTJ9OmZ1bmN0aW9uKGUsdCl7b1t0XT1lWzFdfSkscj9ObihvKTp5KGUpP0luKG8pOkxuKG8pfWZ1bmN0aW9uIG5lKGUsdCxuKXtpZih0fHwodD1sZSksbil7dmFyIHI9ZS50b1NlcSgpLm1hcChmdW5jdGlvbih0LHIpe3JldHVyblt0LG4odCxyLGUpXX0pLnJlZHVjZShmdW5jdGlvbihlLG4pe3JldHVybiByZSh0LGVbMV0sblsxXSk/bjplfSk7cmV0dXJuIHImJnJbMF19cmV0dXJuIGUucmVkdWNlKGZ1bmN0aW9uKGUsbil7cmV0dXJuIHJlKHQsZSxuKT9uOmV9KX1mdW5jdGlvbiByZShlLHQsbil7dmFyIHI9ZShuLHQpO3JldHVybiAwPT09ciYmbiE9PXQmJih2b2lkIDA9PT1ufHxudWxsPT09bnx8biE9PW4pfHxyPjB9ZnVuY3Rpb24gaWUoZSx0LG4scil7dmFyIGk9dWUoZSksbz1uZXcgTW4obikubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnNpemV9KTtyZXR1cm4gaS5zaXplPXI/by5tYXgoKTpvLm1pbigpLGkuX19pdGVyYXRlPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuLHI9dGhpcyxpPXRoaXMuX19pdGVyYXRvcih3bix0KSxvPTA7IShuPWkubmV4dCgpKS5kb25lJiYhMSE9PWUobi52YWx1ZSxvKysscik7KTtyZXR1cm4gb30saS5fX2l0ZXJhdG9yVW5jYWNoZWQ9ZnVuY3Rpb24oZSxpKXt2YXIgbz1uLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZT1ibihlKSxrKGk/ZS5yZXZlcnNlKCk6ZSl9KSxhPTAscz0hMTtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7dmFyIG47cmV0dXJuIHN8fChuPW8ubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLm5leHQoKX0pLHM9cj9uLmV2ZXJ5KGZ1bmN0aW9uKGUpe3JldHVybiBlLmRvbmV9KTpuLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGUuZG9uZX0pKSxzP0QoKTpFKGUsYSsrLHQuYXBwbHkobnVsbCxuLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS52YWx1ZX0pKSl9KX0saX1mdW5jdGlvbiBvZShlLHQpe3JldHVybiBlPT09dD9lOlQoZSk/dDplLmNvbnN0cnVjdG9yKHQpfWZ1bmN0aW9uIGFlKGUpe2lmKGUhPT1PYmplY3QoZSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiRXhwZWN0ZWQgW0ssIFZdIHR1cGxlOiAiK2UpfWZ1bmN0aW9uIHNlKGUpe3JldHVybiBnKGUpP3huOnkoZSk/Q246RW59ZnVuY3Rpb24gdWUoZSl7cmV0dXJuIE9iamVjdC5jcmVhdGUoKGcoZSk/Tm46eShlKT9JbjpMbikucHJvdG90eXBlKX1mdW5jdGlvbiBjZSgpe3JldHVybiB0aGlzLl9pdGVyLmNhY2hlUmVzdWx0Pyh0aGlzLl9pdGVyLmNhY2hlUmVzdWx0KCksdGhpcy5zaXplPXRoaXMuX2l0ZXIuc2l6ZSx0aGlzKTpGbi5wcm90b3R5cGUuY2FjaGVSZXN1bHQuY2FsbCh0aGlzKX1mdW5jdGlvbiBsZShlLHQpe3JldHVybiB2b2lkIDA9PT1lJiZ2b2lkIDA9PT10PzA6dm9pZCAwPT09ZT8xOnZvaWQgMD09PXQ/LTE6ZT50PzE6ZTx0Py0xOjB9ZnVuY3Rpb24gcGUoZSx0KXt0PXR8fDA7Zm9yKHZhciBuPU1hdGgubWF4KDAsZS5sZW5ndGgtdCkscj1uZXcgQXJyYXkobiksaT0wO2k8bjtpKyspcltpXT1lW2krdF07cmV0dXJuIHJ9ZnVuY3Rpb24gZmUoZSx0KXtpZighZSl0aHJvdyBuZXcgRXJyb3IodCl9ZnVuY3Rpb24gZGUoZSl7ZmUoZSE9PTEvMCwiQ2Fubm90IHBlcmZvcm0gdGhpcyBhY3Rpb24gd2l0aCBhbiBpbmZpbml0ZSBzaXplLiIpfWZ1bmN0aW9uIGhlKGUpe2lmKF8oZSkmJiJzdHJpbmciIT09dHlwZW9mIGUpcmV0dXJuIGU7aWYoYihlKSlyZXR1cm4gZS50b0FycmF5KCk7dGhyb3cgbmV3IFR5cGVFcnJvcigiSW52YWxpZCBrZXlQYXRoOiBleHBlY3RlZCBPcmRlcmVkIENvbGxlY3Rpb24gb3IgQXJyYXk6ICIrZSl9ZnVuY3Rpb24gbWUoZSl7cmV0dXJuIGUmJihlLmNvbnN0cnVjdG9yPT09T2JqZWN0fHx2b2lkIDA9PT1lLmNvbnN0cnVjdG9yKX1mdW5jdGlvbiBnZShlKXtyZXR1cm4gaChlKXx8QXJyYXkuaXNBcnJheShlKXx8bWUoZSl9ZnVuY3Rpb24geWUoZSl7dHJ5e3JldHVybiJzdHJpbmciPT09dHlwZW9mIGU/SlNPTi5zdHJpbmdpZnkoZSk6U3RyaW5nKGUpfWNhdGNoKHQpe3JldHVybiBKU09OLnN0cmluZ2lmeShlKX19ZnVuY3Rpb24gdmUoZSx0KXtyZXR1cm4gaChlKT9lLmhhcyh0KTpnZShlKSYmT24uY2FsbChlLHQpfWZ1bmN0aW9uIGJlKGUsdCxuKXtyZXR1cm4gaChlKT9lLmdldCh0LG4pOnZlKGUsdCk/ImZ1bmN0aW9uIj09PXR5cGVvZiBlLmdldD9lLmdldCh0KTplW3RdOm59ZnVuY3Rpb24geGUoZSl7aWYoQXJyYXkuaXNBcnJheShlKSlyZXR1cm4gcGUoZSk7dmFyIHQ9e307Zm9yKHZhciBuIGluIGUpT24uY2FsbChlLG4pJiYodFtuXT1lW25dKTtyZXR1cm4gdH1mdW5jdGlvbiBDZShlLHQpe2lmKCFnZShlKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgdXBkYXRlIG5vbi1kYXRhLXN0cnVjdHVyZSB2YWx1ZTogIitlKTtpZihoKGUpKXtpZighZS5yZW1vdmUpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IHVwZGF0ZSBpbW11dGFibGUgdmFsdWUgd2l0aG91dCAucmVtb3ZlKCkgbWV0aG9kOiAiK2UpO3JldHVybiBlLnJlbW92ZSh0KX1pZighT24uY2FsbChlLHQpKXJldHVybiBlO3ZhciBuPXhlKGUpO3JldHVybiBBcnJheS5pc0FycmF5KG4pP24uc3BsaWNlKHQsMSk6ZGVsZXRlIG5bdF0sbn1mdW5jdGlvbiBFZShlLHQsbil7aWYoIWdlKGUpKXRocm93IG5ldyBUeXBlRXJyb3IoIkNhbm5vdCB1cGRhdGUgbm9uLWRhdGEtc3RydWN0dXJlIHZhbHVlOiAiK2UpO2lmKGgoZSkpe2lmKCFlLnNldCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgdXBkYXRlIGltbXV0YWJsZSB2YWx1ZSB3aXRob3V0IC5zZXQoKSBtZXRob2Q6ICIrZSk7cmV0dXJuIGUuc2V0KHQsbil9aWYoT24uY2FsbChlLHQpJiZuPT09ZVt0XSlyZXR1cm4gZTt2YXIgcj14ZShlKTtyZXR1cm4gclt0XT1uLHJ9ZnVuY3Rpb24gRGUoZSx0LG4scil7cnx8KHI9bixuPXZvaWQgMCk7dmFyIGk9d2UoaChlKSxlLGhlKHQpLDAsbixyKTtyZXR1cm4gaT09PXBuP246aX1mdW5jdGlvbiB3ZShlLHQsbixyLGksbyl7dmFyIGE9dD09PXBuO2lmKHI9PT1uLmxlbmd0aCl7dmFyIHM9YT9pOnQsdT1vKHMpO3JldHVybiB1PT09cz90OnV9aWYoIWEmJiFnZSh0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgdXBkYXRlIHdpdGhpbiBub24tZGF0YS1zdHJ1Y3R1cmUgdmFsdWUgaW4gcGF0aCBbIituLnNsaWNlKDAscikubWFwKHllKSsiXTogIit0KTt2YXIgYz1uW3JdLGw9YT9wbjpiZSh0LGMscG4pLHA9d2UobD09PXBuP2U6aChsKSxsLG4scisxLGksbyk7cmV0dXJuIHA9PT1sP3Q6cD09PXBuP0NlKHQsYyk6RWUoYT9lP2V0KCk6e306dCxjLHApfWZ1bmN0aW9uIFNlKGUsdCxuKXtyZXR1cm4gRGUoZSx0LHBuLGZ1bmN0aW9uKCl7cmV0dXJuIG59KX1mdW5jdGlvbiBrZShlLHQpe3JldHVybiBTZSh0aGlzLGUsdCl9ZnVuY3Rpb24gQWUoZSx0KXtyZXR1cm4gRGUoZSx0LGZ1bmN0aW9uKCl7cmV0dXJuIHBufSl9ZnVuY3Rpb24gX2UoZSl7cmV0dXJuIEFlKHRoaXMsZSl9ZnVuY3Rpb24gVGUoZSx0LG4scil7cmV0dXJuIERlKGUsW3RdLG4scil9ZnVuY3Rpb24gT2UoZSx0LG4pe3JldHVybiAxPT09YXJndW1lbnRzLmxlbmd0aD9lKHRoaXMpOlRlKHRoaXMsZSx0LG4pfWZ1bmN0aW9uIEZlKGUsdCxuKXtyZXR1cm4gRGUodGhpcyxlLHQsbil9ZnVuY3Rpb24gTmUoKXtmb3IodmFyIGU9W10sdD1hcmd1bWVudHMubGVuZ3RoO3QtLTspZVt0XT1hcmd1bWVudHNbdF07cmV0dXJuIExlKHRoaXMsZSl9ZnVuY3Rpb24gSWUoZSl7Zm9yKHZhciB0PVtdLG49YXJndW1lbnRzLmxlbmd0aC0xO24tLSA+MDspdFtuXT1hcmd1bWVudHNbbisxXTtyZXR1cm4gTGUodGhpcyx0LGUpfWZ1bmN0aW9uIExlKGUsdCxuKXtmb3IodmFyIHI9W10saT0wO2k8dC5sZW5ndGg7aSsrKXt2YXIgbz14bih0W2ldKTswIT09by5zaXplJiZyLnB1c2gobyl9cmV0dXJuIDA9PT1yLmxlbmd0aD9lOjAhPT1lLnNpemV8fGUuX19vd25lcklEfHwxIT09ci5sZW5ndGg/ZS53aXRoTXV0YXRpb25zKGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1uP2Z1bmN0aW9uKHQscil7VGUoZSxyLHBuLGZ1bmN0aW9uKGUpe3JldHVybiBlPT09cG4/dDpuKGUsdCxyKX0pfTpmdW5jdGlvbih0LG4pe2Uuc2V0KG4sdCl9LGk9MDtpPHIubGVuZ3RoO2krKylyW2ldLmZvckVhY2godCl9KTplLmNvbnN0cnVjdG9yKHJbMF0pfWZ1bmN0aW9uIFBlKGUpe2Zvcih2YXIgdD1bXSxuPWFyZ3VtZW50cy5sZW5ndGgtMTtuLS0gPjA7KXRbbl09YXJndW1lbnRzW24rMV07cmV0dXJuICRlKGUsdCl9ZnVuY3Rpb24gTWUoZSx0KXtmb3IodmFyIG49W10scj1hcmd1bWVudHMubGVuZ3RoLTI7ci0tID4wOyluW3JdPWFyZ3VtZW50c1tyKzJdO3JldHVybiAkZSh0LG4sZSl9ZnVuY3Rpb24gamUoZSl7Zm9yKHZhciB0PVtdLG49YXJndW1lbnRzLmxlbmd0aC0xO24tLSA+MDspdFtuXT1hcmd1bWVudHNbbisxXTtyZXR1cm4gQmUoZSx0KX1mdW5jdGlvbiBSZShlLHQpe2Zvcih2YXIgbj1bXSxyPWFyZ3VtZW50cy5sZW5ndGgtMjtyLS0gPjA7KW5bcl09YXJndW1lbnRzW3IrMl07cmV0dXJuIEJlKHQsbixlKX1mdW5jdGlvbiBCZShlLHQsbil7cmV0dXJuICRlKGUsdCxVZShuKSl9ZnVuY3Rpb24gJGUoZSx0LG4pe2lmKCFnZShlKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgbWVyZ2UgaW50byBub24tZGF0YS1zdHJ1Y3R1cmUgdmFsdWU6ICIrZSk7aWYoaChlKSlyZXR1cm4gZS5tZXJnZVdpdGg/ZS5tZXJnZVdpdGguYXBwbHkoZSxbbl0uY29uY2F0KHQpKTplLmNvbmNhdC5hcHBseShlLHQpO2Zvcih2YXIgcj1BcnJheS5pc0FycmF5KGUpLGk9ZSxvPXI/Q246eG4sYT1yP2Z1bmN0aW9uKHQpe2k9PT1lJiYoaT14ZShpKSksaS5wdXNoKHQpfTpmdW5jdGlvbih0LHIpe3ZhciBvPU9uLmNhbGwoaSxyKSxhPW8mJm4/bihpW3JdLHQscik6dDtvJiZhPT09aVtyXXx8KGk9PT1lJiYoaT14ZShpKSksaVtyXT1hKX0scz0wO3M8dC5sZW5ndGg7cysrKW8odFtzXSkuZm9yRWFjaChhKTtyZXR1cm4gaX1mdW5jdGlvbiBVZShlKXtmdW5jdGlvbiB0KG4scixpKXtyZXR1cm4gZ2UobikmJmdlKHIpPyRlKG4sW3JdLHQpOmU/ZShuLHIsaSk6cn1yZXR1cm4gdH1mdW5jdGlvbiB6ZSgpe2Zvcih2YXIgZT1bXSx0PWFyZ3VtZW50cy5sZW5ndGg7dC0tOyllW3RdPWFyZ3VtZW50c1t0XTtyZXR1cm4gQmUodGhpcyxlKX1mdW5jdGlvbiBHZShlKXtmb3IodmFyIHQ9W10sbj1hcmd1bWVudHMubGVuZ3RoLTE7bi0tID4wOyl0W25dPWFyZ3VtZW50c1tuKzFdO3JldHVybiBCZSh0aGlzLHQsZSl9ZnVuY3Rpb24gVmUoZSl7Zm9yKHZhciB0PVtdLG49YXJndW1lbnRzLmxlbmd0aC0xO24tLSA+MDspdFtuXT1hcmd1bWVudHNbbisxXTtyZXR1cm4gRGUodGhpcyxlLGV0KCksZnVuY3Rpb24oZSl7cmV0dXJuICRlKGUsdCl9KX1mdW5jdGlvbiBxZShlKXtmb3IodmFyIHQ9W10sbj1hcmd1bWVudHMubGVuZ3RoLTE7bi0tID4wOyl0W25dPWFyZ3VtZW50c1tuKzFdO3JldHVybiBEZSh0aGlzLGUsZXQoKSxmdW5jdGlvbihlKXtyZXR1cm4gQmUoZSx0KX0pfWZ1bmN0aW9uIEhlKGUpe3ZhciB0PXRoaXMuYXNNdXRhYmxlKCk7cmV0dXJuIGUodCksdC53YXNBbHRlcmVkKCk/dC5fX2Vuc3VyZU93bmVyKHRoaXMuX19vd25lcklEKTp0aGlzfWZ1bmN0aW9uIFdlKCl7cmV0dXJuIHRoaXMuX19vd25lcklEP3RoaXM6dGhpcy5fX2Vuc3VyZU93bmVyKG5ldyBvKX1mdW5jdGlvbiBRZSgpe3JldHVybiB0aGlzLl9fZW5zdXJlT3duZXIoKX1mdW5jdGlvbiBLZSgpe3JldHVybiB0aGlzLl9fYWx0ZXJlZH1mdW5jdGlvbiBKZShlKXtyZXR1cm4hKCFlfHwhZVtycl0pfWZ1bmN0aW9uIFllKGUsdCl7cmV0dXJuIEUoZSx0WzBdLHRbMV0pfWZ1bmN0aW9uIFhlKGUsdCl7cmV0dXJue25vZGU6ZSxpbmRleDowLF9fcHJldjp0fX1mdW5jdGlvbiBaZShlLHQsbixyKXt2YXIgaT1PYmplY3QuY3JlYXRlKGlyKTtyZXR1cm4gaS5zaXplPWUsaS5fcm9vdD10LGkuX19vd25lcklEPW4saS5fX2hhc2g9cixpLl9fYWx0ZXJlZD0hMSxpfWZ1bmN0aW9uIGV0KCl7cmV0dXJuIGxyfHwobHI9WmUoMCkpfWZ1bmN0aW9uIHR0KGUsdCxuKXt2YXIgaSxvO2lmKGUuX3Jvb3Qpe3ZhciBhPXIoZm4pLHM9cihkbik7aWYoaT1udChlLl9yb290LGUuX19vd25lcklELDAsdm9pZCAwLHQsbixhLHMpLCFzLnZhbHVlKXJldHVybiBlO289ZS5zaXplKyhhLnZhbHVlP249PT1wbj8tMToxOjApfWVsc2V7aWYobj09PXBuKXJldHVybiBlO289MSxpPW5ldyBvcihlLl9fb3duZXJJRCxbW3Qsbl1dKX1yZXR1cm4gZS5fX293bmVySUQ/KGUuc2l6ZT1vLGUuX3Jvb3Q9aSxlLl9faGFzaD12b2lkIDAsZS5fX2FsdGVyZWQ9ITAsZSk6aT9aZShvLGkpOmV0KCl9ZnVuY3Rpb24gbnQoZSx0LG4scixvLGEscyx1KXtyZXR1cm4gZT9lLnVwZGF0ZSh0LG4scixvLGEscyx1KTphPT09cG4/ZTooaSh1KSxpKHMpLG5ldyBjcih0LHIsW28sYV0pKX1mdW5jdGlvbiBydChlKXtyZXR1cm4gZS5jb25zdHJ1Y3Rvcj09PWNyfHxlLmNvbnN0cnVjdG9yPT09dXJ9ZnVuY3Rpb24gaXQoZSx0LG4scixpKXtpZihlLmtleUhhc2g9PT1yKXJldHVybiBuZXcgdXIodCxyLFtlLmVudHJ5LGldKTt2YXIgbyxhPSgwPT09bj9lLmtleUhhc2g6ZS5rZXlIYXNoPj4+bikmbG4scz0oMD09PW4/cjpyPj4+bikmbG4sdT1hPT09cz9baXQoZSx0LG4rdW4scixpKV06KG89bmV3IGNyKHQscixpKSxhPHM/W2Usb106W28sZV0pO3JldHVybiBuZXcgYXIodCwxPDxhfDE8PHMsdSl9ZnVuY3Rpb24gb3QoZSx0LG4scil7ZXx8KGU9bmV3IG8pO2Zvcih2YXIgaT1uZXcgY3IoZSxqKG4pLFtuLHJdKSxhPTA7YTx0Lmxlbmd0aDthKyspe3ZhciBzPXRbYV07aT1pLnVwZGF0ZShlLDAsdm9pZCAwLHNbMF0sc1sxXSl9cmV0dXJuIGl9ZnVuY3Rpb24gYXQoZSx0LG4scil7Zm9yKHZhciBpPTAsbz0wLGE9bmV3IEFycmF5KG4pLHM9MCx1PTEsYz10Lmxlbmd0aDtzPGM7cysrLHU8PD0xKXt2YXIgbD10W3NdO3ZvaWQgMCE9PWwmJnMhPT1yJiYoaXw9dSxhW28rK109bCl9cmV0dXJuIG5ldyBhcihlLGksYSl9ZnVuY3Rpb24gc3QoZSx0LG4scixpKXtmb3IodmFyIG89MCxhPW5ldyBBcnJheShjbikscz0wOzAhPT1uO3MrKyxuPj4+PTEpYVtzXT0xJm4/dFtvKytdOnZvaWQgMDtyZXR1cm4gYVtyXT1pLG5ldyBzcihlLG8rMSxhKX1mdW5jdGlvbiB1dChlKXtyZXR1cm4gZS09ZT4+MSYxNDMxNjU1NzY1LGU9KDg1ODk5MzQ1OSZlKSsoZT4+MiY4NTg5OTM0NTkpLGU9ZSsoZT4+NCkmMjUyNjQ1MTM1LGUrPWU+PjgsMTI3JihlKz1lPj4xNil9ZnVuY3Rpb24gY3QoZSx0LG4scil7dmFyIGk9cj9lOnBlKGUpO3JldHVybiBpW3RdPW4saX1mdW5jdGlvbiBsdChlLHQsbixyKXt2YXIgaT1lLmxlbmd0aCsxO2lmKHImJnQrMT09PWkpcmV0dXJuIGVbdF09bixlO2Zvcih2YXIgbz1uZXcgQXJyYXkoaSksYT0wLHM9MDtzPGk7cysrKXM9PT10PyhvW3NdPW4sYT0tMSk6b1tzXT1lW3MrYV07cmV0dXJuIG99ZnVuY3Rpb24gcHQoZSx0LG4pe3ZhciByPWUubGVuZ3RoLTE7aWYobiYmdD09PXIpcmV0dXJuIGUucG9wKCksZTtmb3IodmFyIGk9bmV3IEFycmF5KHIpLG89MCxhPTA7YTxyO2ErKylhPT09dCYmKG89MSksaVthXT1lW2Erb107cmV0dXJuIGl9ZnVuY3Rpb24gZnQoZSl7cmV0dXJuISghZXx8IWVbZ3JdKX1mdW5jdGlvbiBkdChlLHQpe2Z1bmN0aW9uIG4oZSx0LG4pe3JldHVybiAwPT09dD9yKGUsbik6aShlLHQsbil9ZnVuY3Rpb24gcihlLG4pe3ZhciByPW49PT1zP3UmJnUuYXJyYXk6ZSYmZS5hcnJheSxpPW4+bz8wOm8tbixjPWEtbjtyZXR1cm4gYz5jbiYmKGM9Y24pLGZ1bmN0aW9uKCl7aWYoaT09PWMpcmV0dXJuIHhyO3ZhciBlPXQ/LS1jOmkrKztyZXR1cm4gciYmcltlXX19ZnVuY3Rpb24gaShlLHIsaSl7dmFyIHMsdT1lJiZlLmFycmF5LGM9aT5vPzA6by1pPj5yLGw9MSsoYS1pPj5yKTtyZXR1cm4gbD5jbiYmKGw9Y24pLGZ1bmN0aW9uKCl7Zm9yKDs7KXtpZihzKXt2YXIgZT1zKCk7aWYoZSE9PXhyKXJldHVybiBlO3M9bnVsbH1pZihjPT09bClyZXR1cm4geHI7dmFyIG89dD8tLWw6YysrO3M9bih1JiZ1W29dLHItdW4saSsobzw8cikpfX19dmFyIG89ZS5fb3JpZ2luLGE9ZS5fY2FwYWNpdHkscz1DdChhKSx1PWUuX3RhaWw7cmV0dXJuIG4oZS5fcm9vdCxlLl9sZXZlbCwwKX1mdW5jdGlvbiBodChlLHQsbixyLGksbyxhKXt2YXIgcz1PYmplY3QuY3JlYXRlKHlyKTtyZXR1cm4gcy5zaXplPXQtZSxzLl9vcmlnaW49ZSxzLl9jYXBhY2l0eT10LHMuX2xldmVsPW4scy5fcm9vdD1yLHMuX3RhaWw9aSxzLl9fb3duZXJJRD1vLHMuX19oYXNoPWEscy5fX2FsdGVyZWQ9ITEsc31mdW5jdGlvbiBtdCgpe3JldHVybiBicnx8KGJyPWh0KDAsMCx1bikpfWZ1bmN0aW9uIGd0KGUsdCxuKXtpZigodD1zKGUsdCkpIT09dClyZXR1cm4gZTtpZih0Pj1lLnNpemV8fHQ8MClyZXR1cm4gZS53aXRoTXV0YXRpb25zKGZ1bmN0aW9uKGUpe3Q8MD94dChlLHQpLnNldCgwLG4pOnh0KGUsMCx0KzEpLnNldCh0LG4pfSk7dCs9ZS5fb3JpZ2luO3ZhciBpPWUuX3RhaWwsbz1lLl9yb290LGE9cihkbik7cmV0dXJuIHQ+PUN0KGUuX2NhcGFjaXR5KT9pPXl0KGksZS5fX293bmVySUQsMCx0LG4sYSk6bz15dChvLGUuX19vd25lcklELGUuX2xldmVsLHQsbixhKSxhLnZhbHVlP2UuX19vd25lcklEPyhlLl9yb290PW8sZS5fdGFpbD1pLGUuX19oYXNoPXZvaWQgMCxlLl9fYWx0ZXJlZD0hMCxlKTpodChlLl9vcmlnaW4sZS5fY2FwYWNpdHksZS5fbGV2ZWwsbyxpKTplfWZ1bmN0aW9uIHl0KGUsdCxuLHIsbyxhKXt2YXIgcz1yPj4+biZsbix1PWUmJnM8ZS5hcnJheS5sZW5ndGg7aWYoIXUmJnZvaWQgMD09PW8pcmV0dXJuIGU7dmFyIGM7aWYobj4wKXt2YXIgbD1lJiZlLmFycmF5W3NdLHA9eXQobCx0LG4tdW4scixvLGEpO3JldHVybiBwPT09bD9lOihjPXZ0KGUsdCksYy5hcnJheVtzXT1wLGMpfXJldHVybiB1JiZlLmFycmF5W3NdPT09bz9lOihpKGEpLGM9dnQoZSx0KSx2b2lkIDA9PT1vJiZzPT09Yy5hcnJheS5sZW5ndGgtMT9jLmFycmF5LnBvcCgpOmMuYXJyYXlbc109byxjKX1mdW5jdGlvbiB2dChlLHQpe3JldHVybiB0JiZlJiZ0PT09ZS5vd25lcklEP2U6bmV3IHZyKGU/ZS5hcnJheS5zbGljZSgpOltdLHQpfWZ1bmN0aW9uIGJ0KGUsdCl7aWYodD49Q3QoZS5fY2FwYWNpdHkpKXJldHVybiBlLl90YWlsO2lmKHQ8MTw8ZS5fbGV2ZWwrdW4pe2Zvcih2YXIgbj1lLl9yb290LHI9ZS5fbGV2ZWw7biYmcj4wOyluPW4uYXJyYXlbdD4+PnImbG5dLHItPXVuO3JldHVybiBufX1mdW5jdGlvbiB4dChlLHQsbil7dm9pZCAwIT09dCYmKHR8PTApLHZvaWQgMCE9PW4mJihufD0wKTt2YXIgcj1lLl9fb3duZXJJRHx8bmV3IG8saT1lLl9vcmlnaW4sYT1lLl9jYXBhY2l0eSxzPWkrdCx1PXZvaWQgMD09PW4/YTpuPDA/YStuOmkrbjtpZihzPT09aSYmdT09PWEpcmV0dXJuIGU7aWYocz49dSlyZXR1cm4gZS5jbGVhcigpO2Zvcih2YXIgYz1lLl9sZXZlbCxsPWUuX3Jvb3QscD0wO3MrcDwwOylsPW5ldyB2cihsJiZsLmFycmF5Lmxlbmd0aD9bdm9pZCAwLGxdOltdLHIpLGMrPXVuLHArPTE8PGM7cCYmKHMrPXAsaSs9cCx1Kz1wLGErPXApO2Zvcih2YXIgZj1DdChhKSxkPUN0KHUpO2Q+PTE8PGMrdW47KWw9bmV3IHZyKGwmJmwuYXJyYXkubGVuZ3RoP1tsXTpbXSxyKSxjKz11bjt2YXIgaD1lLl90YWlsLG09ZDxmP2J0KGUsdS0xKTpkPmY/bmV3IHZyKFtdLHIpOmg7aWYoaCYmZD5mJiZzPGEmJmguYXJyYXkubGVuZ3RoKXtsPXZ0KGwscik7Zm9yKHZhciBnPWwseT1jO3k+dW47eS09dW4pe3ZhciB2PWY+Pj55JmxuO2c9Zy5hcnJheVt2XT12dChnLmFycmF5W3ZdLHIpfWcuYXJyYXlbZj4+PnVuJmxuXT1ofWlmKHU8YSYmKG09bSYmbS5yZW1vdmVBZnRlcihyLDAsdSkpLHM+PWQpcy09ZCx1LT1kLGM9dW4sbD1udWxsLG09bSYmbS5yZW1vdmVCZWZvcmUociwwLHMpO2Vsc2UgaWYocz5pfHxkPGYpe2ZvcihwPTA7bDspe3ZhciBiPXM+Pj5jJmxuO2lmKGIhPT1kPj4+YyZsbilicmVhaztiJiYocCs9KDE8PGMpKmIpLGMtPXVuLGw9bC5hcnJheVtiXX1sJiZzPmkmJihsPWwucmVtb3ZlQmVmb3JlKHIsYyxzLXApKSxsJiZkPGYmJihsPWwucmVtb3ZlQWZ0ZXIocixjLGQtcCkpLHAmJihzLT1wLHUtPXApfXJldHVybiBlLl9fb3duZXJJRD8oZS5zaXplPXUtcyxlLl9vcmlnaW49cyxlLl9jYXBhY2l0eT11LGUuX2xldmVsPWMsZS5fcm9vdD1sLGUuX3RhaWw9bSxlLl9faGFzaD12b2lkIDAsZS5fX2FsdGVyZWQ9ITAsZSk6aHQocyx1LGMsbCxtKX1mdW5jdGlvbiBDdChlKXtyZXR1cm4gZTxjbj8wOmUtMT4+PnVuPDx1bn1mdW5jdGlvbiBFdChlKXtyZXR1cm4gSmUoZSkmJmIoZSl9ZnVuY3Rpb24gRHQoZSx0LG4scil7dmFyIGk9T2JqZWN0LmNyZWF0ZShDci5wcm90b3R5cGUpO3JldHVybiBpLnNpemU9ZT9lLnNpemU6MCxpLl9tYXA9ZSxpLl9saXN0PXQsaS5fX293bmVySUQ9bixpLl9faGFzaD1yLGl9ZnVuY3Rpb24gd3QoKXtyZXR1cm4gRXJ8fChFcj1EdChldCgpLG10KCkpKX1mdW5jdGlvbiBTdChlLHQsbil7dmFyIHIsaSxvPWUuX21hcCxhPWUuX2xpc3Qscz1vLmdldCh0KSx1PXZvaWQgMCE9PXM7aWYobj09PXBuKXtpZighdSlyZXR1cm4gZTthLnNpemU+PWNuJiZhLnNpemU+PTIqby5zaXplPyhpPWEuZmlsdGVyKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHZvaWQgMCE9PWUmJnMhPT10fSkscj1pLnRvS2V5ZWRTZXEoKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGVbMF19KS5mbGlwKCkudG9NYXAoKSxlLl9fb3duZXJJRCYmKHIuX19vd25lcklEPWkuX19vd25lcklEPWUuX19vd25lcklEKSk6KHI9by5yZW1vdmUodCksaT1zPT09YS5zaXplLTE/YS5wb3AoKTphLnNldChzLHZvaWQgMCkpfWVsc2UgaWYodSl7aWYobj09PWEuZ2V0KHMpWzFdKXJldHVybiBlO3I9byxpPWEuc2V0KHMsW3Qsbl0pfWVsc2Ugcj1vLnNldCh0LGEuc2l6ZSksaT1hLnNldChhLnNpemUsW3Qsbl0pO3JldHVybiBlLl9fb3duZXJJRD8oZS5zaXplPXIuc2l6ZSxlLl9tYXA9cixlLl9saXN0PWksZS5fX2hhc2g9dm9pZCAwLGUpOkR0KHIsaSl9ZnVuY3Rpb24ga3QoZSl7cmV0dXJuISghZXx8IWVbd3JdKX1mdW5jdGlvbiBBdChlLHQsbixyKXt2YXIgaT1PYmplY3QuY3JlYXRlKFNyKTtyZXR1cm4gaS5zaXplPWUsaS5faGVhZD10LGkuX19vd25lcklEPW4saS5fX2hhc2g9cixpLl9fYWx0ZXJlZD0hMSxpfWZ1bmN0aW9uIF90KCl7cmV0dXJuIGtyfHwoa3I9QXQoMCkpfWZ1bmN0aW9uIFR0KGUsdCl7aWYoZT09PXQpcmV0dXJuITA7aWYoIW0odCl8fHZvaWQgMCE9PWUuc2l6ZSYmdm9pZCAwIT09dC5zaXplJiZlLnNpemUhPT10LnNpemV8fHZvaWQgMCE9PWUuX19oYXNoJiZ2b2lkIDAhPT10Ll9faGFzaCYmZS5fX2hhc2ghPT10Ll9faGFzaHx8ZyhlKSE9PWcodCl8fHkoZSkhPT15KHQpfHxiKGUpIT09Yih0KSlyZXR1cm4hMTtpZigwPT09ZS5zaXplJiYwPT09dC5zaXplKXJldHVybiEwO3ZhciBuPSF2KGUpO2lmKGIoZSkpe3ZhciByPWUuZW50cmllcygpO3JldHVybiB0LmV2ZXJ5KGZ1bmN0aW9uKGUsdCl7dmFyIGk9ci5uZXh0KCkudmFsdWU7cmV0dXJuIGkmJlAoaVsxXSxlKSYmKG58fFAoaVswXSx0KSl9KSYmci5uZXh0KCkuZG9uZX12YXIgaT0hMTtpZih2b2lkIDA9PT1lLnNpemUpaWYodm9pZCAwPT09dC5zaXplKSJmdW5jdGlvbiI9PT10eXBlb2YgZS5jYWNoZVJlc3VsdCYmZS5jYWNoZVJlc3VsdCgpO2Vsc2V7aT0hMDt2YXIgbz1lO2U9dCx0PW99dmFyIGE9ITAscz10Ll9faXRlcmF0ZShmdW5jdGlvbih0LHIpe2lmKG4/IWUuaGFzKHQpOmk/IVAodCxlLmdldChyLHBuKSk6IVAoZS5nZXQocixwbiksdCkpcmV0dXJuIGE9ITEsITF9KTtyZXR1cm4gYSYmZS5zaXplPT09c31mdW5jdGlvbiBPdChlLHQpe3ZhciBuPWZ1bmN0aW9uKG4pe2UucHJvdG90eXBlW25dPXRbbl19O3JldHVybiBPYmplY3Qua2V5cyh0KS5mb3JFYWNoKG4pLE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMmJk9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHModCkuZm9yRWFjaChuKSxlfWZ1bmN0aW9uIEZ0KGUpe3JldHVybiBnZShlKT9GbihlKS5tYXAoRnQpLnRvSlNPTigpOmV9ZnVuY3Rpb24gTnQoZSl7cmV0dXJuISghZXx8IWVbX3JdKX1mdW5jdGlvbiBJdChlLHQpe3JldHVybiBlLl9fb3duZXJJRD8oZS5zaXplPXQuc2l6ZSxlLl9tYXA9dCxlKTp0PT09ZS5fbWFwP2U6MD09PXQuc2l6ZT9lLl9fZW1wdHkoKTplLl9fbWFrZSh0KX1mdW5jdGlvbiBMdChlLHQpe3ZhciBuPU9iamVjdC5jcmVhdGUoVHIpO3JldHVybiBuLnNpemU9ZT9lLnNpemU6MCxuLl9tYXA9ZSxuLl9fb3duZXJJRD10LG59ZnVuY3Rpb24gUHQoKXtyZXR1cm4gT3J8fChPcj1MdChldCgpKSl9ZnVuY3Rpb24gTXQoZSx0LG4pe2Zvcih2YXIgcj1oZSh0KSxpPTA7aSE9PXIubGVuZ3RoOylpZigoZT1iZShlLHJbaSsrXSxwbikpPT09cG4pcmV0dXJuIG47cmV0dXJuIGV9ZnVuY3Rpb24ganQoZSx0KXtyZXR1cm4gTXQodGhpcyxlLHQpfWZ1bmN0aW9uIFJ0KGUsdCl7cmV0dXJuIE10KGUsdCxwbikhPT1wbn1mdW5jdGlvbiBCdChlKXtyZXR1cm4gUnQodGhpcyxlKX1mdW5jdGlvbiAkdCgpe2RlKHRoaXMuc2l6ZSk7dmFyIGU9e307cmV0dXJuIHRoaXMuX19pdGVyYXRlKGZ1bmN0aW9uKHQsbil7ZVtuXT10fSksZX1mdW5jdGlvbiBVdChlLHQsbixyLGksbyl7cmV0dXJuIGRlKGUuc2l6ZSksZS5fX2l0ZXJhdGUoZnVuY3Rpb24oZSxvLGEpe2k/KGk9ITEsbj1lKTpuPXQuY2FsbChyLG4sZSxvLGEpfSxvKSxufWZ1bmN0aW9uIHp0KGUsdCl7cmV0dXJuIHR9ZnVuY3Rpb24gR3QoZSx0KXtyZXR1cm5bdCxlXX1mdW5jdGlvbiBWdChlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4hZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl9fWZ1bmN0aW9uIHF0KGUpe3JldHVybiBmdW5jdGlvbigpe3JldHVybi1lLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19ZnVuY3Rpb24gSHQoKXtyZXR1cm4gcGUoYXJndW1lbnRzKX1mdW5jdGlvbiBXdChlLHQpe3JldHVybiBlPHQ/MTplPnQ/LTE6MH1mdW5jdGlvbiBRdChlKXtpZihlLnNpemU9PT0xLzApcmV0dXJuIDA7dmFyIHQ9YihlKSxuPWcoZSkscj10PzE6MDtyZXR1cm4gS3QoZS5fX2l0ZXJhdGUobj90P2Z1bmN0aW9uKGUsdCl7cj0zMSpyK0p0KGooZSksaih0KSl8MH06ZnVuY3Rpb24oZSx0KXtyPXIrSnQoaihlKSxqKHQpKXwwfTp0P2Z1bmN0aW9uKGUpe3I9MzEqcitqKGUpfDB9OmZ1bmN0aW9uKGUpe3I9citqKGUpfDB9KSxyKX1mdW5jdGlvbiBLdChlLHQpe3JldHVybiB0PXpuKHQsMzQzMjkxODM1MyksdD16bih0PDwxNXx0Pj4+LTE1LDQ2MTg0NTkwNyksdD16bih0PDwxM3x0Pj4+LTEzLDUpLHQ9KHQrMzg2NDI5MjE5NnwwKV5lLHQ9em4odF50Pj4+MTYsMjI0NjgyMjUwNyksdD16bih0XnQ+Pj4xMywzMjY2NDg5OTA5KSx0PU0odF50Pj4+MTYpfWZ1bmN0aW9uIEp0KGUsdCl7cmV0dXJuIGVedCsyNjU0NDM1NzY5KyhlPDw2KSsoZT4+Mil8MH1mdW5jdGlvbiBZdChlKXtyZXR1cm4gTnQoZSkmJmIoZSl9ZnVuY3Rpb24gWHQoZSx0KXt2YXIgbj1PYmplY3QuY3JlYXRlKGpyKTtyZXR1cm4gbi5zaXplPWU/ZS5zaXplOjAsbi5fbWFwPWUsbi5fX293bmVySUQ9dCxufWZ1bmN0aW9uIFp0KCl7cmV0dXJuIFJyfHwoUnI9WHQod3QoKSkpfWZ1bmN0aW9uIGVuKGUsdCxuKXt2YXIgcj1PYmplY3QuY3JlYXRlKE9iamVjdC5nZXRQcm90b3R5cGVPZihlKSk7cmV0dXJuIHIuX3ZhbHVlcz10LHIuX19vd25lcklEPW4scn1mdW5jdGlvbiB0bihlKXtyZXR1cm4gZS5fbmFtZXx8ZS5jb25zdHJ1Y3Rvci5uYW1lfHwiUmVjb3JkIn1mdW5jdGlvbiBubihlKXtyZXR1cm4gRihlLl9rZXlzLm1hcChmdW5jdGlvbih0KXtyZXR1cm5bdCxlLmdldCh0KV19KSl9ZnVuY3Rpb24gcm4oZSx0KXt0cnl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsdCx7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZ2V0KHQpfSxzZXQ6ZnVuY3Rpb24oZSl7ZmUodGhpcy5fX293bmVySUQsIkNhbm5vdCBzZXQgb24gYW4gaW1tdXRhYmxlIHJlY29yZC4iKSx0aGlzLnNldCh0LGUpfX0pfWNhdGNoKGUpe319ZnVuY3Rpb24gb24oZSx0KXtyZXR1cm4gYW4oW10sdHx8c24sZSwiIix0JiZ0Lmxlbmd0aD4yP1tdOnZvaWQgMCx7IiI6ZX0pfWZ1bmN0aW9uIGFuKGUsdCxuLHIsaSxvKXt2YXIgYT1BcnJheS5pc0FycmF5KG4pP0luOm1lKG4pP05uOm51bGw7aWYoYSl7aWYofmUuaW5kZXhPZihuKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY29udmVydCBjaXJjdWxhciBzdHJ1Y3R1cmUgdG8gSW1tdXRhYmxlIik7ZS5wdXNoKG4pLGkmJiIiIT09ciYmaS5wdXNoKHIpO3ZhciBzPXQuY2FsbChvLHIsYShuKS5tYXAoZnVuY3Rpb24ocixvKXtyZXR1cm4gYW4oZSx0LHIsbyxpLG4pfSksaSYmaS5zbGljZSgpKTtyZXR1cm4gZS5wb3AoKSxpJiZpLnBvcCgpLHN9cmV0dXJuIG59ZnVuY3Rpb24gc24oZSx0KXtyZXR1cm4gZyh0KT90LnRvTWFwKCk6dC50b0xpc3QoKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksbi5kKHQsInZlcnNpb24iLGZ1bmN0aW9uKCl7cmV0dXJuIEdyfSksbi5kKHQsIkNvbGxlY3Rpb24iLGZ1bmN0aW9uKCl7cmV0dXJuIGJufSksbi5kKHQsIkl0ZXJhYmxlIixmdW5jdGlvbigpe3JldHVybiBxcn0pLG4uZCh0LCJTZXEiLGZ1bmN0aW9uKCl7cmV0dXJuIEZufSksbi5kKHQsIk1hcCIsZnVuY3Rpb24oKXtyZXR1cm4gbnJ9KSxuLmQodCwiT3JkZXJlZE1hcCIsZnVuY3Rpb24oKXtyZXR1cm4gQ3J9KSxuLmQodCwiTGlzdCIsZnVuY3Rpb24oKXtyZXR1cm4gbXJ9KSxuLmQodCwiU3RhY2siLGZ1bmN0aW9uKCl7cmV0dXJuIERyfSksbi5kKHQsIlNldCIsZnVuY3Rpb24oKXtyZXR1cm4gQXJ9KSxuLmQodCwiT3JkZXJlZFNldCIsZnVuY3Rpb24oKXtyZXR1cm4gTXJ9KSxuLmQodCwiUmVjb3JkIixmdW5jdGlvbigpe3JldHVybiBCcn0pLG4uZCh0LCJSYW5nZSIsZnVuY3Rpb24oKXtyZXR1cm4gTnJ9KSxuLmQodCwiUmVwZWF0IixmdW5jdGlvbigpe3JldHVybiB6cn0pLG4uZCh0LCJpcyIsZnVuY3Rpb24oKXtyZXR1cm4gUH0pLG4uZCh0LCJmcm9tSlMiLGZ1bmN0aW9uKCl7cmV0dXJuIG9ufSksbi5kKHQsImhhc2giLGZ1bmN0aW9uKCl7cmV0dXJuIGp9KSxuLmQodCwiaXNJbW11dGFibGUiLGZ1bmN0aW9uKCl7cmV0dXJuIGh9KSxuLmQodCwiaXNDb2xsZWN0aW9uIixmdW5jdGlvbigpe3JldHVybiBtfSksbi5kKHQsImlzS2V5ZWQiLGZ1bmN0aW9uKCl7cmV0dXJuIGd9KSxuLmQodCwiaXNJbmRleGVkIixmdW5jdGlvbigpe3JldHVybiB5fSksbi5kKHQsImlzQXNzb2NpYXRpdmUiLGZ1bmN0aW9uKCl7cmV0dXJuIHZ9KSxuLmQodCwiaXNPcmRlcmVkIixmdW5jdGlvbigpe3JldHVybiBifSksbi5kKHQsImlzVmFsdWVPYmplY3QiLGZ1bmN0aW9uKCl7cmV0dXJuIEN9KSxuLmQodCwiZ2V0IixmdW5jdGlvbigpe3JldHVybiBiZX0pLG4uZCh0LCJnZXRJbiIsZnVuY3Rpb24oKXtyZXR1cm4gTXR9KSxuLmQodCwiaGFzIixmdW5jdGlvbigpe3JldHVybiB2ZX0pLG4uZCh0LCJoYXNJbiIsZnVuY3Rpb24oKXtyZXR1cm4gUnR9KSxuLmQodCwibWVyZ2UiLGZ1bmN0aW9uKCl7cmV0dXJuIFBlfSksbi5kKHQsIm1lcmdlRGVlcCIsZnVuY3Rpb24oKXtyZXR1cm4gamV9KSxuLmQodCwibWVyZ2VXaXRoIixmdW5jdGlvbigpe3JldHVybiBNZX0pLG4uZCh0LCJtZXJnZURlZXBXaXRoIixmdW5jdGlvbigpe3JldHVybiBSZX0pLG4uZCh0LCJyZW1vdmUiLGZ1bmN0aW9uKCl7cmV0dXJuIENlfSksbi5kKHQsInJlbW92ZUluIixmdW5jdGlvbigpe3JldHVybiBBZX0pLG4uZCh0LCJzZXQiLGZ1bmN0aW9uKCl7cmV0dXJuIEVlfSksbi5kKHQsInNldEluIixmdW5jdGlvbigpe3JldHVybiBTZX0pLG4uZCh0LCJ1cGRhdGUiLGZ1bmN0aW9uKCl7cmV0dXJuIFRlfSksbi5kKHQsInVwZGF0ZUluIixmdW5jdGlvbigpe3JldHVybiBEZX0pO3ZhciB1bj01LGNuPTE8PHVuLGxuPWNuLTEscG49e30sZm49e3ZhbHVlOiExfSxkbj17dmFsdWU6ITF9LGhuPSJAQF9fSU1NVVRBQkxFX0lURVJBQkxFX19AQCIsbW49IkBAX19JTU1VVEFCTEVfS0VZRURfX0BAIixnbj0iQEBfX0lNTVVUQUJMRV9JTkRFWEVEX19AQCIseW49IkBAX19JTU1VVEFCTEVfT1JERVJFRF9fQEAiLHZuPSJAQF9fSU1NVVRBQkxFX1JFQ09SRF9fQEAiLGJuPWZ1bmN0aW9uKGUpe3JldHVybiBtKGUpP2U6Rm4oZSl9LHhuPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7cmV0dXJuIGcoZSk/ZTpObihlKX1yZXR1cm4gZSYmKHQuX19wcm90b19fPWUpLHQucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZSYmZS5wcm90b3R5cGUpLHQucHJvdG90eXBlLmNvbnN0cnVjdG9yPXQsdH0oYm4pLENuPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7cmV0dXJuIHkoZSk/ZTpJbihlKX1yZXR1cm4gZSYmKHQuX19wcm90b19fPWUpLHQucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZSYmZS5wcm90b3R5cGUpLHQucHJvdG90eXBlLmNvbnN0cnVjdG9yPXQsdH0oYm4pLEVuPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7cmV0dXJuIG0oZSkmJiF2KGUpP2U6TG4oZSl9cmV0dXJuIGUmJih0Ll9fcHJvdG9fXz1lKSx0LnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUmJmUucHJvdG90eXBlKSx0LnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj10LHR9KGJuKTtibi5LZXllZD14bixibi5JbmRleGVkPUNuLGJuLlNldD1Fbjt2YXIgRG49MCx3bj0xLFNuPTIsa249ImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJlN5bWJvbC5pdGVyYXRvcixBbj0iQEBpdGVyYXRvciIsX249a258fEFuLFRuPWZ1bmN0aW9uKGUpe3RoaXMubmV4dD1lfTtUbi5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4iW0l0ZXJhdG9yXSJ9LFRuLktFWVM9RG4sVG4uVkFMVUVTPXduLFRuLkVOVFJJRVM9U24sVG4ucHJvdG90eXBlLmluc3BlY3Q9VG4ucHJvdG90eXBlLnRvU291cmNlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudG9TdHJpbmcoKX0sVG4ucHJvdG90eXBlW19uXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfTt2YXIgT249T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eSxGbj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUpe3JldHVybiBudWxsPT09ZXx8dm9pZCAwPT09ZT9PKCk6aChlKT9lLnRvU2VxKCk6SShlKX1yZXR1cm4gZSYmKHQuX19wcm90b19fPWUpLHQucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZSYmZS5wcm90b3R5cGUpLHQucHJvdG90eXBlLmNvbnN0cnVjdG9yPXQsdC5wcm90b3R5cGUudG9TZXE9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sdC5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fX3RvU3RyaW5nKCJTZXEgeyIsIn0iKX0sdC5wcm90b3R5cGUuY2FjaGVSZXN1bHQ9ZnVuY3Rpb24oKXtyZXR1cm4hdGhpcy5fY2FjaGUmJnRoaXMuX19pdGVyYXRlVW5jYWNoZWQmJih0aGlzLl9jYWNoZT10aGlzLmVudHJ5U2VxKCkudG9BcnJheSgpLHRoaXMuc2l6ZT10aGlzLl9jYWNoZS5sZW5ndGgpLHRoaXN9LHQucHJvdG90eXBlLl9faXRlcmF0ZT1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMscj10aGlzLl9jYWNoZTtpZihyKXtmb3IodmFyIGk9ci5sZW5ndGgsbz0wO28hPT1pOyl7dmFyIGE9clt0P2ktKytvOm8rK107aWYoITE9PT1lKGFbMV0sYVswXSxuKSlicmVha31yZXR1cm4gb31yZXR1cm4gdGhpcy5fX2l0ZXJhdGVVbmNhY2hlZChlLHQpfSx0LnByb3RvdHlwZS5fX2l0ZXJhdG9yPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5fY2FjaGU7aWYobil7dmFyIHI9bi5sZW5ndGgsaT0wO3JldHVybiBuZXcgVG4oZnVuY3Rpb24oKXtpZihpPT09cilyZXR1cm4gRCgpO3ZhciBvPW5bdD9yLSsraTppKytdO3JldHVybiBFKGUsb1swXSxvWzFdKX0pfXJldHVybiB0aGlzLl9faXRlcmF0b3JVbmNhY2hlZChlLHQpfSx0fShibiksTm49ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlKXtyZXR1cm4gbnVsbD09PWV8fHZvaWQgMD09PWU/TygpLnRvS2V5ZWRTZXEoKTptKGUpP2coZSk/ZS50b1NlcSgpOmUuZnJvbUVudHJ5U2VxKCk6eChlKT9lLnRvU2VxKCk6RihlKX1yZXR1cm4gZSYmKHQuX19wcm90b19fPWUpLHQucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZSYmZS5wcm90b3R5cGUpLHQucHJvdG90eXBlLmNvbnN0cnVjdG9yPXQsdC5wcm90b3R5cGUudG9LZXllZFNlcT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx0fShGbiksSW49ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlKXtyZXR1cm4gbnVsbD09PWV8fHZvaWQgMD09PWU/TygpOm0oZSk/ZyhlKT9lLmVudHJ5U2VxKCk6ZS50b0luZGV4ZWRTZXEoKTp4KGUpP2UudG9TZXEoKS5lbnRyeVNlcSgpOk4oZSl9cmV0dXJuIGUmJih0Ll9fcHJvdG9fXz1lKSx0LnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUmJmUucHJvdG90eXBlKSx0LnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj10LHQub2Y9ZnVuY3Rpb24oKXtyZXR1cm4gdChhcmd1bWVudHMpfSx0LnByb3RvdHlwZS50b0luZGV4ZWRTZXE9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sdC5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fX3RvU3RyaW5nKCJTZXEgWyIsIl0iKX0sdH0oRm4pLExuPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7cmV0dXJuKG0oZSkmJiF2KGUpP2U6SW4oZSkpLnRvU2V0U2VxKCl9cmV0dXJuIGUmJih0Ll9fcHJvdG9fXz1lKSx0LnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUmJmUucHJvdG90eXBlKSx0LnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj10LHQub2Y9ZnVuY3Rpb24oKXtyZXR1cm4gdChhcmd1bWVudHMpfSx0LnByb3RvdHlwZS50b1NldFNlcT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx0fShGbik7Rm4uaXNTZXE9VCxGbi5LZXllZD1ObixGbi5TZXQ9TG4sRm4uSW5kZXhlZD1Jbjt2YXIgUG49IkBAX19JTU1VVEFCTEVfU0VRX19AQCI7Rm4ucHJvdG90eXBlW1BuXT0hMDt2YXIgTW49ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlKXt0aGlzLl9hcnJheT1lLHRoaXMuc2l6ZT1lLmxlbmd0aH1yZXR1cm4gZSYmKHQuX19wcm90b19fPWUpLHQucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZSYmZS5wcm90b3R5cGUpLHQucHJvdG90eXBlLmNvbnN0cnVjdG9yPXQsdC5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuaGFzKGUpP3RoaXMuX2FycmF5W3ModGhpcyxlKV06dH0sdC5wcm90b3R5cGUuX19pdGVyYXRlPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPXRoaXMscj10aGlzLl9hcnJheSxpPXIubGVuZ3RoLG89MDtvIT09aTspe3ZhciBhPXQ/aS0rK286bysrO2lmKCExPT09ZShyW2FdLGEsbikpYnJlYWt9cmV0dXJuIG99LHQucHJvdG90eXBlLl9faXRlcmF0b3I9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLl9hcnJheSxyPW4ubGVuZ3RoLGk9MDtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7aWYoaT09PXIpcmV0dXJuIEQoKTt2YXIgbz10P3ItKytpOmkrKztyZXR1cm4gRShlLG8sbltvXSl9KX0sdH0oSW4pLGpuPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7dmFyIHQ9T2JqZWN0LmtleXMoZSk7dGhpcy5fb2JqZWN0PWUsdGhpcy5fa2V5cz10LHRoaXMuc2l6ZT10Lmxlbmd0aH1yZXR1cm4gZSYmKHQuX19wcm90b19fPWUpLHQucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZSYmZS5wcm90b3R5cGUpLHQucHJvdG90eXBlLmNvbnN0cnVjdG9yPXQsdC5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHZvaWQgMD09PXR8fHRoaXMuaGFzKGUpP3RoaXMuX29iamVjdFtlXTp0fSx0LnByb3RvdHlwZS5oYXM9ZnVuY3Rpb24oZSl7cmV0dXJuIE9uLmNhbGwodGhpcy5fb2JqZWN0LGUpfSx0LnByb3RvdHlwZS5fX2l0ZXJhdGU9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG49dGhpcyxyPXRoaXMuX29iamVjdCxpPXRoaXMuX2tleXMsbz1pLmxlbmd0aCxhPTA7YSE9PW87KXt2YXIgcz1pW3Q/by0rK2E6YSsrXTtpZighMT09PWUocltzXSxzLG4pKWJyZWFrfXJldHVybiBhfSx0LnByb3RvdHlwZS5fX2l0ZXJhdG9yPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5fb2JqZWN0LHI9dGhpcy5fa2V5cyxpPXIubGVuZ3RoLG89MDtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7aWYobz09PWkpcmV0dXJuIEQoKTt2YXIgYT1yW3Q/aS0rK286bysrXTtyZXR1cm4gRShlLGEsblthXSl9KX0sdH0oTm4pO2puLnByb3RvdHlwZVt5bl09ITA7dmFyIFJuLEJuLCRuPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7dGhpcy5fY29sbGVjdGlvbj1lLHRoaXMuc2l6ZT1lLmxlbmd0aHx8ZS5zaXplfXJldHVybiBlJiYodC5fX3Byb3RvX189ZSksdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlJiZlLnByb3RvdHlwZSksdC5wcm90b3R5cGUuY29uc3RydWN0b3I9dCx0LnByb3RvdHlwZS5fX2l0ZXJhdGVVbmNhY2hlZD1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXM7aWYodClyZXR1cm4gdGhpcy5jYWNoZVJlc3VsdCgpLl9faXRlcmF0ZShlLHQpO3ZhciByPXRoaXMuX2NvbGxlY3Rpb24saT1rKHIpLG89MDtpZihTKGkpKWZvcih2YXIgYTshKGE9aS5uZXh0KCkpLmRvbmUmJiExIT09ZShhLnZhbHVlLG8rKyxuKTspO3JldHVybiBvfSx0LnByb3RvdHlwZS5fX2l0ZXJhdG9yVW5jYWNoZWQ9ZnVuY3Rpb24oZSx0KXtpZih0KXJldHVybiB0aGlzLmNhY2hlUmVzdWx0KCkuX19pdGVyYXRvcihlLHQpO3ZhciBuPXRoaXMuX2NvbGxlY3Rpb24scj1rKG4pO2lmKCFTKHIpKXJldHVybiBuZXcgVG4oRCk7dmFyIGk9MDtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7dmFyIHQ9ci5uZXh0KCk7cmV0dXJuIHQuZG9uZT90OkUoZSxpKyssdC52YWx1ZSl9KX0sdH0oSW4pLFVuPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7dGhpcy5faXRlcmF0b3I9ZSx0aGlzLl9pdGVyYXRvckNhY2hlPVtdfXJldHVybiBlJiYodC5fX3Byb3RvX189ZSksdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlJiZlLnByb3RvdHlwZSksdC5wcm90b3R5cGUuY29uc3RydWN0b3I9dCx0LnByb3RvdHlwZS5fX2l0ZXJhdGVVbmNhY2hlZD1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXM7aWYodClyZXR1cm4gdGhpcy5jYWNoZVJlc3VsdCgpLl9faXRlcmF0ZShlLHQpO2Zvcih2YXIgcj10aGlzLl9pdGVyYXRvcixpPXRoaXMuX2l0ZXJhdG9yQ2FjaGUsbz0wO288aS5sZW5ndGg7KWlmKCExPT09ZShpW29dLG8rKyxuKSlyZXR1cm4gbztmb3IodmFyIGE7IShhPXIubmV4dCgpKS5kb25lOyl7dmFyIHM9YS52YWx1ZTtpZihpW29dPXMsITE9PT1lKHMsbysrLG4pKWJyZWFrfXJldHVybiBvfSx0LnByb3RvdHlwZS5fX2l0ZXJhdG9yVW5jYWNoZWQ9ZnVuY3Rpb24oZSx0KXtpZih0KXJldHVybiB0aGlzLmNhY2hlUmVzdWx0KCkuX19pdGVyYXRvcihlLHQpO3ZhciBuPXRoaXMuX2l0ZXJhdG9yLHI9dGhpcy5faXRlcmF0b3JDYWNoZSxpPTA7cmV0dXJuIG5ldyBUbihmdW5jdGlvbigpe2lmKGk+PXIubGVuZ3RoKXt2YXIgdD1uLm5leHQoKTtpZih0LmRvbmUpcmV0dXJuIHQ7cltpXT10LnZhbHVlfXJldHVybiBFKGUsaSxyW2krK10pfSl9LHR9KEluKSx6bj0iZnVuY3Rpb24iPT09dHlwZW9mIE1hdGguaW11bCYmLTI9PT1NYXRoLmltdWwoNDI5NDk2NzI5NSwyKT9NYXRoLmltdWw6ZnVuY3Rpb24oZSx0KXtlfD0wLHR8PTA7dmFyIG49NjU1MzUmZSxyPTY1NTM1JnQ7cmV0dXJuIG4qcisoKGU+Pj4xNikqcituKih0Pj4+MTYpPDwxNj4+PjApfDB9LEduPU9iamVjdC5pc0V4dGVuc2libGUsVm49ZnVuY3Rpb24oKXt0cnl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh7fSwiQCIse30pLCEwfWNhdGNoKGUpe3JldHVybiExfX0oKSxxbj0iZnVuY3Rpb24iPT09dHlwZW9mIFdlYWtNYXA7cW4mJihCbj1uZXcgV2Vha01hcCk7dmFyIEhuPTAsV249Il9faW1tdXRhYmxlaGFzaF9fIjsiZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmKFduPVN5bWJvbChXbikpO3ZhciBRbj0xNixLbj0yNTUsSm49MCxZbj17fSxYbj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUsdCl7dGhpcy5faXRlcj1lLHRoaXMuX3VzZUtleXM9dCx0aGlzLnNpemU9ZS5zaXplfXJldHVybiBlJiYodC5fX3Byb3RvX189ZSksdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlJiZlLnByb3RvdHlwZSksdC5wcm90b3R5cGUuY29uc3RydWN0b3I9dCx0LnByb3RvdHlwZS5nZXQ9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5faXRlci5nZXQoZSx0KX0sdC5wcm90b3R5cGUuaGFzPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9pdGVyLmhhcyhlKX0sdC5wcm90b3R5cGUudmFsdWVTZXE9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5faXRlci52YWx1ZVNlcSgpfSx0LnByb3RvdHlwZS5yZXZlcnNlPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcyx0PVYodGhpcywhMCk7cmV0dXJuIHRoaXMuX3VzZUtleXN8fCh0LnZhbHVlU2VxPWZ1bmN0aW9uKCl7cmV0dXJuIGUuX2l0ZXIudG9TZXEoKS5yZXZlcnNlKCl9KSx0fSx0LnByb3RvdHlwZS5tYXA9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLHI9Ryh0aGlzLGUsdCk7cmV0dXJuIHRoaXMuX3VzZUtleXN8fChyLnZhbHVlU2VxPWZ1bmN0aW9uKCl7cmV0dXJuIG4uX2l0ZXIudG9TZXEoKS5tYXAoZSx0KX0pLHJ9LHQucHJvdG90eXBlLl9faXRlcmF0ZT1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXM7cmV0dXJuIHRoaXMuX2l0ZXIuX19pdGVyYXRlKGZ1bmN0aW9uKHQscil7cmV0dXJuIGUodCxyLG4pfSx0KX0sdC5wcm90b3R5cGUuX19pdGVyYXRvcj1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLl9pdGVyLl9faXRlcmF0b3IoZSx0KX0sdH0oTm4pO1huLnByb3RvdHlwZVt5bl09ITA7dmFyIFpuPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7dGhpcy5faXRlcj1lLHRoaXMuc2l6ZT1lLnNpemV9cmV0dXJuIGUmJih0Ll9fcHJvdG9fXz1lKSx0LnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUmJmUucHJvdG90eXBlKSx0LnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj10LHQucHJvdG90eXBlLmluY2x1ZGVzPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9pdGVyLmluY2x1ZGVzKGUpfSx0LnByb3RvdHlwZS5fX2l0ZXJhdGU9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLHI9MDtyZXR1cm4gdCYmYSh0aGlzKSx0aGlzLl9pdGVyLl9faXRlcmF0ZShmdW5jdGlvbihpKXtyZXR1cm4gZShpLHQ/bi5zaXplLSsrcjpyKyssbil9LHQpfSx0LnByb3RvdHlwZS5fX2l0ZXJhdG9yPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcyxyPXRoaXMuX2l0ZXIuX19pdGVyYXRvcih3bix0KSxpPTA7cmV0dXJuIHQmJmEodGhpcyksbmV3IFRuKGZ1bmN0aW9uKCl7dmFyIG89ci5uZXh0KCk7cmV0dXJuIG8uZG9uZT9vOkUoZSx0P24uc2l6ZS0rK2k6aSsrLG8udmFsdWUsbyl9KX0sdH0oSW4pLGVyPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7dGhpcy5faXRlcj1lLHRoaXMuc2l6ZT1lLnNpemV9cmV0dXJuIGUmJih0Ll9fcHJvdG9fXz1lKSx0LnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUmJmUucHJvdG90eXBlKSx0LnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj10LHQucHJvdG90eXBlLmhhcz1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5faXRlci5pbmNsdWRlcyhlKX0sdC5wcm90b3R5cGUuX19pdGVyYXRlPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcztyZXR1cm4gdGhpcy5faXRlci5fX2l0ZXJhdGUoZnVuY3Rpb24odCl7cmV0dXJuIGUodCx0LG4pfSx0KX0sdC5wcm90b3R5cGUuX19pdGVyYXRvcj1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMuX2l0ZXIuX19pdGVyYXRvcih3bix0KTtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7dmFyIHQ9bi5uZXh0KCk7cmV0dXJuIHQuZG9uZT90OkUoZSx0LnZhbHVlLHQudmFsdWUsdCl9KX0sdH0oTG4pLHRyPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7dGhpcy5faXRlcj1lLHRoaXMuc2l6ZT1lLnNpemV9cmV0dXJuIGUmJih0Ll9fcHJvdG9fXz1lKSx0LnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUmJmUucHJvdG90eXBlKSx0LnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj10LHQucHJvdG90eXBlLmVudHJ5U2VxPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2l0ZXIudG9TZXEoKX0sdC5wcm90b3R5cGUuX19pdGVyYXRlPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcztyZXR1cm4gdGhpcy5faXRlci5fX2l0ZXJhdGUoZnVuY3Rpb24odCl7aWYodCl7YWUodCk7dmFyIHI9bSh0KTtyZXR1cm4gZShyP3QuZ2V0KDEpOnRbMV0scj90LmdldCgwKTp0WzBdLG4pfX0sdCl9LHQucHJvdG90eXBlLl9faXRlcmF0b3I9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLl9pdGVyLl9faXRlcmF0b3Iod24sdCk7cmV0dXJuIG5ldyBUbihmdW5jdGlvbigpe2Zvcig7Oyl7dmFyIHQ9bi5uZXh0KCk7aWYodC5kb25lKXJldHVybiB0O3ZhciByPXQudmFsdWU7aWYocil7YWUocik7dmFyIGk9bShyKTtyZXR1cm4gRShlLGk/ci5nZXQoMCk6clswXSxpP3IuZ2V0KDEpOnJbMV0sdCl9fX0pfSx0fShObik7Wm4ucHJvdG90eXBlLmNhY2hlUmVzdWx0PVhuLnByb3RvdHlwZS5jYWNoZVJlc3VsdD1lci5wcm90b3R5cGUuY2FjaGVSZXN1bHQ9dHIucHJvdG90eXBlLmNhY2hlUmVzdWx0PWNlO3ZhciBucj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe3JldHVybiBudWxsPT09dHx8dm9pZCAwPT09dD9ldCgpOkplKHQpJiYhYih0KT90OmV0KCkud2l0aE11dGF0aW9ucyhmdW5jdGlvbihuKXt2YXIgcj1lKHQpO2RlKHIuc2l6ZSksci5mb3JFYWNoKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG4uc2V0KHQsZSl9KX0pfXJldHVybiBlJiYodC5fX3Byb3RvX189ZSksdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlJiZlLnByb3RvdHlwZSksdC5wcm90b3R5cGUuY29uc3RydWN0b3I9dCx0Lm9mPWZ1bmN0aW9uKCl7Zm9yKHZhciBlPVtdLHQ9YXJndW1lbnRzLmxlbmd0aDt0LS07KWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBldCgpLndpdGhNdXRhdGlvbnMoZnVuY3Rpb24odCl7Zm9yKHZhciBuPTA7bjxlLmxlbmd0aDtuKz0yKXtpZihuKzE+PWUubGVuZ3RoKXRocm93IG5ldyBFcnJvcigiTWlzc2luZyB2YWx1ZSBmb3Iga2V5OiAiK2Vbbl0pO3Quc2V0KGVbbl0sZVtuKzFdKX19KX0sdC5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fX3RvU3RyaW5nKCJNYXAgeyIsIn0iKX0sdC5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuX3Jvb3Q/dGhpcy5fcm9vdC5nZXQoMCx2b2lkIDAsZSx0KTp0fSx0LnByb3RvdHlwZS5zZXQ9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdHQodGhpcyxlLHQpfSx0LnByb3RvdHlwZS5yZW1vdmU9ZnVuY3Rpb24oZSl7cmV0dXJuIHR0KHRoaXMsZSxwbil9LHQucHJvdG90eXBlLmRlbGV0ZUFsbD1mdW5jdGlvbihlKXt2YXIgdD1ibihlKTtyZXR1cm4gMD09PXQuc2l6ZT90aGlzOnRoaXMud2l0aE11dGF0aW9ucyhmdW5jdGlvbihlKXt0LmZvckVhY2goZnVuY3Rpb24odCl7cmV0dXJuIGUucmVtb3ZlKHQpfSl9KX0sdC5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXtyZXR1cm4gMD09PXRoaXMuc2l6ZT90aGlzOnRoaXMuX19vd25lcklEPyh0aGlzLnNpemU9MCx0aGlzLl9yb290PW51bGwsdGhpcy5fX2hhc2g9dm9pZCAwLHRoaXMuX19hbHRlcmVkPSEwLHRoaXMpOmV0KCl9LHQucHJvdG90eXBlLnNvcnQ9ZnVuY3Rpb24oZSl7cmV0dXJuIENyKHRlKHRoaXMsZSkpfSx0LnByb3RvdHlwZS5zb3J0Qnk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gQ3IodGUodGhpcyx0LGUpKX0sdC5wcm90b3R5cGUuX19pdGVyYXRvcj1mdW5jdGlvbihlLHQpe3JldHVybiBuZXcgcHIodGhpcyxlLHQpfSx0LnByb3RvdHlwZS5fX2l0ZXJhdGU9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLHI9MDtyZXR1cm4gdGhpcy5fcm9vdCYmdGhpcy5fcm9vdC5pdGVyYXRlKGZ1bmN0aW9uKHQpe3JldHVybiByKyssZSh0WzFdLHRbMF0sbil9LHQpLHJ9LHQucHJvdG90eXBlLl9fZW5zdXJlT3duZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIGU9PT10aGlzLl9fb3duZXJJRD90aGlzOmU/WmUodGhpcy5zaXplLHRoaXMuX3Jvb3QsZSx0aGlzLl9faGFzaCk6MD09PXRoaXMuc2l6ZT9ldCgpOih0aGlzLl9fb3duZXJJRD1lLHRoaXMuX19hbHRlcmVkPSExLHRoaXMpfSx0fSh4bik7bnIuaXNNYXA9SmU7dmFyIHJyPSJAQF9fSU1NVVRBQkxFX01BUF9fQEAiLGlyPW5yLnByb3RvdHlwZTtpcltycl09ITAsaXIuZGVsZXRlPWlyLnJlbW92ZSxpci5yZW1vdmVBbGw9aXIuZGVsZXRlQWxsLGlyLmNvbmNhdD1pci5tZXJnZSxpci5zZXRJbj1rZSxpci5yZW1vdmVJbj1pci5kZWxldGVJbj1fZSxpci51cGRhdGU9T2UsaXIudXBkYXRlSW49RmUsaXIubWVyZ2U9TmUsaXIubWVyZ2VXaXRoPUllLGlyLm1lcmdlRGVlcD16ZSxpci5tZXJnZURlZXBXaXRoPUdlLGlyLm1lcmdlSW49VmUsaXIubWVyZ2VEZWVwSW49cWUsaXIud2l0aE11dGF0aW9ucz1IZSxpci53YXNBbHRlcmVkPUtlLGlyLmFzSW1tdXRhYmxlPVFlLGlyWyJAQHRyYW5zZHVjZXIvaW5pdCJdPWlyLmFzTXV0YWJsZT1XZSxpclsiQEB0cmFuc2R1Y2VyL3N0ZXAiXT1mdW5jdGlvbihlLHQpe3JldHVybiBlLnNldCh0WzBdLHRbMV0pfSxpclsiQEB0cmFuc2R1Y2VyL3Jlc3VsdCJdPWZ1bmN0aW9uKGUpe3JldHVybiBlLmFzSW1tdXRhYmxlKCl9O3ZhciBvcj1mdW5jdGlvbihlLHQpe3RoaXMub3duZXJJRD1lLHRoaXMuZW50cmllcz10fTtvci5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUsdCxuLHIpe2Zvcih2YXIgaT10aGlzLmVudHJpZXMsbz0wLGE9aS5sZW5ndGg7bzxhO28rKylpZihQKG4saVtvXVswXSkpcmV0dXJuIGlbb11bMV07cmV0dXJuIHJ9LG9yLnByb3RvdHlwZS51cGRhdGU9ZnVuY3Rpb24oZSx0LG4scixvLGEscyl7Zm9yKHZhciB1PW89PT1wbixjPXRoaXMuZW50cmllcyxsPTAscD1jLmxlbmd0aDtsPHAmJiFQKHIsY1tsXVswXSk7bCsrKTt2YXIgZj1sPHA7aWYoZj9jW2xdWzFdPT09bzp1KXJldHVybiB0aGlzO2lmKGkocyksKHV8fCFmKSYmaShhKSwhdXx8MSE9PWMubGVuZ3RoKXtpZighZiYmIXUmJmMubGVuZ3RoPj1mcilyZXR1cm4gb3QoZSxjLHIsbyk7dmFyIGQ9ZSYmZT09PXRoaXMub3duZXJJRCxoPWQ/YzpwZShjKTtyZXR1cm4gZj91P2w9PT1wLTE/aC5wb3AoKTpoW2xdPWgucG9wKCk6aFtsXT1bcixvXTpoLnB1c2goW3Isb10pLGQ/KHRoaXMuZW50cmllcz1oLHRoaXMpOm5ldyBvcihlLGgpfX07dmFyIGFyPWZ1bmN0aW9uKGUsdCxuKXt0aGlzLm93bmVySUQ9ZSx0aGlzLmJpdG1hcD10LHRoaXMubm9kZXM9bn07YXIucHJvdG90eXBlLmdldD1mdW5jdGlvbihlLHQsbixyKXt2b2lkIDA9PT10JiYodD1qKG4pKTt2YXIgaT0xPDwoKDA9PT1lP3Q6dD4+PmUpJmxuKSxvPXRoaXMuYml0bWFwO3JldHVybiAwPT09KG8maSk/cjp0aGlzLm5vZGVzW3V0KG8maS0xKV0uZ2V0KGUrdW4sdCxuLHIpfSxhci5wcm90b3R5cGUudXBkYXRlPWZ1bmN0aW9uKGUsdCxuLHIsaSxvLGEpe3ZvaWQgMD09PW4mJihuPWoocikpO3ZhciBzPSgwPT09dD9uOm4+Pj50KSZsbix1PTE8PHMsYz10aGlzLmJpdG1hcCxsPTAhPT0oYyZ1KTtpZighbCYmaT09PXBuKXJldHVybiB0aGlzO3ZhciBwPXV0KGMmdS0xKSxmPXRoaXMubm9kZXMsZD1sP2ZbcF06dm9pZCAwLGg9bnQoZCxlLHQrdW4sbixyLGksbyxhKTtpZihoPT09ZClyZXR1cm4gdGhpcztpZighbCYmaCYmZi5sZW5ndGg+PWRyKXJldHVybiBzdChlLGYsYyxzLGgpO2lmKGwmJiFoJiYyPT09Zi5sZW5ndGgmJnJ0KGZbMV5wXSkpcmV0dXJuIGZbMV5wXTtpZihsJiZoJiYxPT09Zi5sZW5ndGgmJnJ0KGgpKXJldHVybiBoO3ZhciBtPWUmJmU9PT10aGlzLm93bmVySUQsZz1sP2g/YzpjXnU6Y3x1LHk9bD9oP2N0KGYscCxoLG0pOnB0KGYscCxtKTpsdChmLHAsaCxtKTtyZXR1cm4gbT8odGhpcy5iaXRtYXA9Zyx0aGlzLm5vZGVzPXksdGhpcyk6bmV3IGFyKGUsZyx5KX07dmFyIHNyPWZ1bmN0aW9uKGUsdCxuKXt0aGlzLm93bmVySUQ9ZSx0aGlzLmNvdW50PXQsdGhpcy5ub2Rlcz1ufTtzci5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUsdCxuLHIpe3ZvaWQgMD09PXQmJih0PWoobikpO3ZhciBpPSgwPT09ZT90OnQ+Pj5lKSZsbixvPXRoaXMubm9kZXNbaV07cmV0dXJuIG8/by5nZXQoZSt1bix0LG4scik6cn0sc3IucHJvdG90eXBlLnVwZGF0ZT1mdW5jdGlvbihlLHQsbixyLGksbyxhKXt2b2lkIDA9PT1uJiYobj1qKHIpKTt2YXIgcz0oMD09PXQ/bjpuPj4+dCkmbG4sdT1pPT09cG4sYz10aGlzLm5vZGVzLGw9Y1tzXTtpZih1JiYhbClyZXR1cm4gdGhpczt2YXIgcD1udChsLGUsdCt1bixuLHIsaSxvLGEpO2lmKHA9PT1sKXJldHVybiB0aGlzO3ZhciBmPXRoaXMuY291bnQ7aWYobCl7aWYoIXAmJi0tZjxocilyZXR1cm4gYXQoZSxjLGYscyl9ZWxzZSBmKys7dmFyIGQ9ZSYmZT09PXRoaXMub3duZXJJRCxoPWN0KGMscyxwLGQpO3JldHVybiBkPyh0aGlzLmNvdW50PWYsdGhpcy5ub2Rlcz1oLHRoaXMpOm5ldyBzcihlLGYsaCl9O3ZhciB1cj1mdW5jdGlvbihlLHQsbil7dGhpcy5vd25lcklEPWUsdGhpcy5rZXlIYXNoPXQsdGhpcy5lbnRyaWVzPW59O3VyLnByb3RvdHlwZS5nZXQ9ZnVuY3Rpb24oZSx0LG4scil7Zm9yKHZhciBpPXRoaXMuZW50cmllcyxvPTAsYT1pLmxlbmd0aDtvPGE7bysrKWlmKFAobixpW29dWzBdKSlyZXR1cm4gaVtvXVsxXTtyZXR1cm4gcn0sdXIucHJvdG90eXBlLnVwZGF0ZT1mdW5jdGlvbihlLHQsbixyLG8sYSxzKXt2b2lkIDA9PT1uJiYobj1qKHIpKTt2YXIgdT1vPT09cG47aWYobiE9PXRoaXMua2V5SGFzaClyZXR1cm4gdT90aGlzOihpKHMpLGkoYSksaXQodGhpcyxlLHQsbixbcixvXSkpO2Zvcih2YXIgYz10aGlzLmVudHJpZXMsbD0wLHA9Yy5sZW5ndGg7bDxwJiYhUChyLGNbbF1bMF0pO2wrKyk7dmFyIGY9bDxwO2lmKGY/Y1tsXVsxXT09PW86dSlyZXR1cm4gdGhpcztpZihpKHMpLCh1fHwhZikmJmkoYSksdSYmMj09PXApcmV0dXJuIG5ldyBjcihlLHRoaXMua2V5SGFzaCxjWzFebF0pO3ZhciBkPWUmJmU9PT10aGlzLm93bmVySUQsaD1kP2M6cGUoYyk7cmV0dXJuIGY/dT9sPT09cC0xP2gucG9wKCk6aFtsXT1oLnBvcCgpOmhbbF09W3Isb106aC5wdXNoKFtyLG9dKSxkPyh0aGlzLmVudHJpZXM9aCx0aGlzKTpuZXcgdXIoZSx0aGlzLmtleUhhc2gsaCl9O3ZhciBjcj1mdW5jdGlvbihlLHQsbil7dGhpcy5vd25lcklEPWUsdGhpcy5rZXlIYXNoPXQsdGhpcy5lbnRyeT1ufTtjci5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUsdCxuLHIpe3JldHVybiBQKG4sdGhpcy5lbnRyeVswXSk/dGhpcy5lbnRyeVsxXTpyfSxjci5wcm90b3R5cGUudXBkYXRlPWZ1bmN0aW9uKGUsdCxuLHIsbyxhLHMpe3ZhciB1PW89PT1wbixjPVAocix0aGlzLmVudHJ5WzBdKTtyZXR1cm4oYz9vPT09dGhpcy5lbnRyeVsxXTp1KT90aGlzOihpKHMpLHU/dm9pZCBpKGEpOmM/ZSYmZT09PXRoaXMub3duZXJJRD8odGhpcy5lbnRyeVsxXT1vLHRoaXMpOm5ldyBjcihlLHRoaXMua2V5SGFzaCxbcixvXSk6KGkoYSksaXQodGhpcyxlLHQsaihyKSxbcixvXSkpKX0sb3IucHJvdG90eXBlLml0ZXJhdGU9dXIucHJvdG90eXBlLml0ZXJhdGU9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG49dGhpcy5lbnRyaWVzLHI9MCxpPW4ubGVuZ3RoLTE7cjw9aTtyKyspaWYoITE9PT1lKG5bdD9pLXI6cl0pKXJldHVybiExfSxhci5wcm90b3R5cGUuaXRlcmF0ZT1zci5wcm90b3R5cGUuaXRlcmF0ZT1mdW5jdGlvbihlLHQpe2Zvcih2YXIgbj10aGlzLm5vZGVzLHI9MCxpPW4ubGVuZ3RoLTE7cjw9aTtyKyspe3ZhciBvPW5bdD9pLXI6cl07aWYobyYmITE9PT1vLml0ZXJhdGUoZSx0KSlyZXR1cm4hMX19LGNyLnByb3RvdHlwZS5pdGVyYXRlPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUodGhpcy5lbnRyeSl9O3ZhciBscixwcj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUsdCxuKXt0aGlzLl90eXBlPXQsdGhpcy5fcmV2ZXJzZT1uLHRoaXMuX3N0YWNrPWUuX3Jvb3QmJlhlKGUuX3Jvb3QpfXJldHVybiBlJiYodC5fX3Byb3RvX189ZSksdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlJiZlLnByb3RvdHlwZSksdC5wcm90b3R5cGUuY29uc3RydWN0b3I9dCx0LnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKCl7Zm9yKHZhciBlPXRoaXMsdD10aGlzLl90eXBlLG49dGhpcy5fc3RhY2s7bjspe3ZhciByPW4ubm9kZSxpPW4uaW5kZXgrKyxvPXZvaWQgMDtpZihyLmVudHJ5KXtpZigwPT09aSlyZXR1cm4gWWUodCxyLmVudHJ5KX1lbHNlIGlmKHIuZW50cmllcyl7aWYobz1yLmVudHJpZXMubGVuZ3RoLTEsaTw9bylyZXR1cm4gWWUodCxyLmVudHJpZXNbZS5fcmV2ZXJzZT9vLWk6aV0pfWVsc2UgaWYobz1yLm5vZGVzLmxlbmd0aC0xLGk8PW8pe3ZhciBhPXIubm9kZXNbZS5fcmV2ZXJzZT9vLWk6aV07aWYoYSl7aWYoYS5lbnRyeSlyZXR1cm4gWWUodCxhLmVudHJ5KTtuPWUuX3N0YWNrPVhlKGEsbil9Y29udGludWV9bj1lLl9zdGFjaz1lLl9zdGFjay5fX3ByZXZ9cmV0dXJuIEQoKX0sdH0oVG4pLGZyPWNuLzQsZHI9Y24vMixocj1jbi80LG1yPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIG49bXQoKTtpZihudWxsPT09dHx8dm9pZCAwPT09dClyZXR1cm4gbjtpZihmdCh0KSlyZXR1cm4gdDt2YXIgcj1lKHQpLGk9ci5zaXplO3JldHVybiAwPT09aT9uOihkZShpKSxpPjAmJmk8Y24/aHQoMCxpLHVuLG51bGwsbmV3IHZyKHIudG9BcnJheSgpKSk6bi53aXRoTXV0YXRpb25zKGZ1bmN0aW9uKGUpe2Uuc2V0U2l6ZShpKSxyLmZvckVhY2goZnVuY3Rpb24odCxuKXtyZXR1cm4gZS5zZXQobix0KX0pfSkpfXJldHVybiBlJiYodC5fX3Byb3RvX189ZSksdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlJiZlLnByb3RvdHlwZSksdC5wcm90b3R5cGUuY29uc3RydWN0b3I9dCx0Lm9mPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMoYXJndW1lbnRzKX0sdC5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fX3RvU3RyaW5nKCJMaXN0IFsiLCJdIil9LHQucHJvdG90eXBlLmdldD1mdW5jdGlvbihlLHQpe2lmKChlPXModGhpcyxlKSk+PTAmJmU8dGhpcy5zaXplKXtlKz10aGlzLl9vcmlnaW47dmFyIG49YnQodGhpcyxlKTtyZXR1cm4gbiYmbi5hcnJheVtlJmxuXX1yZXR1cm4gdH0sdC5wcm90b3R5cGUuc2V0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGd0KHRoaXMsZSx0KX0sdC5wcm90b3R5cGUucmVtb3ZlPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLmhhcyhlKT8wPT09ZT90aGlzLnNoaWZ0KCk6ZT09PXRoaXMuc2l6ZS0xP3RoaXMucG9wKCk6dGhpcy5zcGxpY2UoZSwxKTp0aGlzfSx0LnByb3RvdHlwZS5pbnNlcnQ9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5zcGxpY2UoZSwwLHQpfSx0LnByb3RvdHlwZS5jbGVhcj1mdW5jdGlvbigpe3JldHVybiAwPT09dGhpcy5zaXplP3RoaXM6dGhpcy5fX293bmVySUQ/KHRoaXMuc2l6ZT10aGlzLl9vcmlnaW49dGhpcy5fY2FwYWNpdHk9MCx0aGlzLl9sZXZlbD11bix0aGlzLl9yb290PXRoaXMuX3RhaWw9bnVsbCx0aGlzLl9faGFzaD12b2lkIDAsdGhpcy5fX2FsdGVyZWQ9ITAsdGhpcyk6bXQoKX0sdC5wcm90b3R5cGUucHVzaD1mdW5jdGlvbigpe3ZhciBlPWFyZ3VtZW50cyx0PXRoaXMuc2l6ZTtyZXR1cm4gdGhpcy53aXRoTXV0YXRpb25zKGZ1bmN0aW9uKG4pe3h0KG4sMCx0K2UubGVuZ3RoKTtmb3IodmFyIHI9MDtyPGUubGVuZ3RoO3IrKyluLnNldCh0K3IsZVtyXSl9KX0sdC5wcm90b3R5cGUucG9wPWZ1bmN0aW9uKCl7cmV0dXJuIHh0KHRoaXMsMCwtMSl9LHQucHJvdG90eXBlLnVuc2hpZnQ9ZnVuY3Rpb24oKXt2YXIgZT1hcmd1bWVudHM7cmV0dXJuIHRoaXMud2l0aE11dGF0aW9ucyhmdW5jdGlvbih0KXt4dCh0LC1lLmxlbmd0aCk7Zm9yKHZhciBuPTA7bjxlLmxlbmd0aDtuKyspdC5zZXQobixlW25dKX0pfSx0LnByb3RvdHlwZS5zaGlmdD1mdW5jdGlvbigpe3JldHVybiB4dCh0aGlzLDEpfSx0LnByb3RvdHlwZS5jb25jYXQ9ZnVuY3Rpb24oKXtmb3IodmFyIHQ9YXJndW1lbnRzLG49W10scj0wO3I8YXJndW1lbnRzLmxlbmd0aDtyKyspe3ZhciBpPXRbcl0sbz1lKCJzdHJpbmciIT09dHlwZW9mIGkmJncoaSk/aTpbaV0pOzAhPT1vLnNpemUmJm4ucHVzaChvKX1yZXR1cm4gMD09PW4ubGVuZ3RoP3RoaXM6MCE9PXRoaXMuc2l6ZXx8dGhpcy5fX293bmVySUR8fDEhPT1uLmxlbmd0aD90aGlzLndpdGhNdXRhdGlvbnMoZnVuY3Rpb24oZSl7bi5mb3JFYWNoKGZ1bmN0aW9uKHQpe3JldHVybiB0LmZvckVhY2goZnVuY3Rpb24odCl7cmV0dXJuIGUucHVzaCh0KX0pfSl9KTp0aGlzLmNvbnN0cnVjdG9yKG5bMF0pfSx0LnByb3RvdHlwZS5zZXRTaXplPWZ1bmN0aW9uKGUpe3JldHVybiB4dCh0aGlzLDAsZSl9LHQucHJvdG90eXBlLnNsaWNlPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5zaXplO3JldHVybiBjKGUsdCxuKT90aGlzOnh0KHRoaXMsbChlLG4pLHAodCxuKSl9LHQucHJvdG90eXBlLl9faXRlcmF0b3I9ZnVuY3Rpb24oZSx0KXt2YXIgbj10P3RoaXMuc2l6ZTowLHI9ZHQodGhpcyx0KTtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7dmFyIGk9cigpO3JldHVybiBpPT09eHI/RCgpOkUoZSx0Py0tbjpuKyssaSl9KX0sdC5wcm90b3R5cGUuX19pdGVyYXRlPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuLHI9dGhpcyxpPXQ/dGhpcy5zaXplOjAsbz1kdCh0aGlzLHQpOyhuPW8oKSkhPT14ciYmITEhPT1lKG4sdD8tLWk6aSsrLHIpOyk7cmV0dXJuIGl9LHQucHJvdG90eXBlLl9fZW5zdXJlT3duZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIGU9PT10aGlzLl9fb3duZXJJRD90aGlzOmU/aHQodGhpcy5fb3JpZ2luLHRoaXMuX2NhcGFjaXR5LHRoaXMuX2xldmVsLHRoaXMuX3Jvb3QsdGhpcy5fdGFpbCxlLHRoaXMuX19oYXNoKTowPT09dGhpcy5zaXplP210KCk6KHRoaXMuX19vd25lcklEPWUsdGhpcy5fX2FsdGVyZWQ9ITEsdGhpcyl9LHR9KENuKTttci5pc0xpc3Q9ZnQ7dmFyIGdyPSJAQF9fSU1NVVRBQkxFX0xJU1RfX0BAIix5cj1tci5wcm90b3R5cGU7eXJbZ3JdPSEwLHlyLmRlbGV0ZT15ci5yZW1vdmUseXIubWVyZ2U9eXIuY29uY2F0LHlyLnNldEluPWtlLHlyLmRlbGV0ZUluPXlyLnJlbW92ZUluPV9lLHlyLnVwZGF0ZT1PZSx5ci51cGRhdGVJbj1GZSx5ci5tZXJnZUluPVZlLHlyLm1lcmdlRGVlcEluPXFlLHlyLndpdGhNdXRhdGlvbnM9SGUseXIud2FzQWx0ZXJlZD1LZSx5ci5hc0ltbXV0YWJsZT1RZSx5clsiQEB0cmFuc2R1Y2VyL2luaXQiXT15ci5hc011dGFibGU9V2UseXJbIkBAdHJhbnNkdWNlci9zdGVwIl09ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5wdXNoKHQpfSx5clsiQEB0cmFuc2R1Y2VyL3Jlc3VsdCJdPWZ1bmN0aW9uKGUpe3JldHVybiBlLmFzSW1tdXRhYmxlKCl9O3ZhciB2cj1mdW5jdGlvbihlLHQpe3RoaXMuYXJyYXk9ZSx0aGlzLm93bmVySUQ9dH07dnIucHJvdG90eXBlLnJlbW92ZUJlZm9yZT1mdW5jdGlvbihlLHQsbil7aWYobj09PXQ/MTw8dDowPT09dGhpcy5hcnJheS5sZW5ndGgpcmV0dXJuIHRoaXM7dmFyIHI9bj4+PnQmbG47aWYocj49dGhpcy5hcnJheS5sZW5ndGgpcmV0dXJuIG5ldyB2cihbXSxlKTt2YXIgaSxvPTA9PT1yO2lmKHQ+MCl7dmFyIGE9dGhpcy5hcnJheVtyXTtpZigoaT1hJiZhLnJlbW92ZUJlZm9yZShlLHQtdW4sbikpPT09YSYmbylyZXR1cm4gdGhpc31pZihvJiYhaSlyZXR1cm4gdGhpczt2YXIgcz12dCh0aGlzLGUpO2lmKCFvKWZvcih2YXIgdT0wO3U8cjt1Kyspcy5hcnJheVt1XT12b2lkIDA7cmV0dXJuIGkmJihzLmFycmF5W3JdPWkpLHN9LHZyLnByb3RvdHlwZS5yZW1vdmVBZnRlcj1mdW5jdGlvbihlLHQsbil7aWYobj09PSh0PzE8PHQ6MCl8fDA9PT10aGlzLmFycmF5Lmxlbmd0aClyZXR1cm4gdGhpczt2YXIgcj1uLTE+Pj50JmxuO2lmKHI+PXRoaXMuYXJyYXkubGVuZ3RoKXJldHVybiB0aGlzO3ZhciBpO2lmKHQ+MCl7dmFyIG89dGhpcy5hcnJheVtyXTtpZigoaT1vJiZvLnJlbW92ZUFmdGVyKGUsdC11bixuKSk9PT1vJiZyPT09dGhpcy5hcnJheS5sZW5ndGgtMSlyZXR1cm4gdGhpc312YXIgYT12dCh0aGlzLGUpO3JldHVybiBhLmFycmF5LnNwbGljZShyKzEpLGkmJihhLmFycmF5W3JdPWkpLGF9O3ZhciBicix4cj17fSxDcj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUpe3JldHVybiBudWxsPT09ZXx8dm9pZCAwPT09ZT93dCgpOkV0KGUpP2U6d3QoKS53aXRoTXV0YXRpb25zKGZ1bmN0aW9uKHQpe3ZhciBuPXhuKGUpO2RlKG4uc2l6ZSksbi5mb3JFYWNoKGZ1bmN0aW9uKGUsbil7cmV0dXJuIHQuc2V0KG4sZSl9KX0pfXJldHVybiBlJiYodC5fX3Byb3RvX189ZSksdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlJiZlLnByb3RvdHlwZSksdC5wcm90b3R5cGUuY29uc3RydWN0b3I9dCx0Lm9mPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMoYXJndW1lbnRzKX0sdC5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fX3RvU3RyaW5nKCJPcmRlcmVkTWFwIHsiLCJ9Iil9LHQucHJvdG90eXBlLmdldD1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMuX21hcC5nZXQoZSk7cmV0dXJuIHZvaWQgMCE9PW4/dGhpcy5fbGlzdC5nZXQobilbMV06dH0sdC5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXtyZXR1cm4gMD09PXRoaXMuc2l6ZT90aGlzOnRoaXMuX19vd25lcklEPyh0aGlzLnNpemU9MCx0aGlzLl9tYXAuY2xlYXIoKSx0aGlzLl9saXN0LmNsZWFyKCksdGhpcyk6d3QoKX0sdC5wcm90b3R5cGUuc2V0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIFN0KHRoaXMsZSx0KX0sdC5wcm90b3R5cGUucmVtb3ZlPWZ1bmN0aW9uKGUpe3JldHVybiBTdCh0aGlzLGUscG4pfSx0LnByb3RvdHlwZS53YXNBbHRlcmVkPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX21hcC53YXNBbHRlcmVkKCl8fHRoaXMuX2xpc3Qud2FzQWx0ZXJlZCgpfSx0LnByb3RvdHlwZS5fX2l0ZXJhdGU9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzO3JldHVybiB0aGlzLl9saXN0Ll9faXRlcmF0ZShmdW5jdGlvbih0KXtyZXR1cm4gdCYmZSh0WzFdLHRbMF0sbil9LHQpfSx0LnByb3RvdHlwZS5fX2l0ZXJhdG9yPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuX2xpc3QuZnJvbUVudHJ5U2VxKCkuX19pdGVyYXRvcihlLHQpfSx0LnByb3RvdHlwZS5fX2Vuc3VyZU93bmVyPWZ1bmN0aW9uKGUpe2lmKGU9PT10aGlzLl9fb3duZXJJRClyZXR1cm4gdGhpczt2YXIgdD10aGlzLl9tYXAuX19lbnN1cmVPd25lcihlKSxuPXRoaXMuX2xpc3QuX19lbnN1cmVPd25lcihlKTtyZXR1cm4gZT9EdCh0LG4sZSx0aGlzLl9faGFzaCk6MD09PXRoaXMuc2l6ZT93dCgpOih0aGlzLl9fb3duZXJJRD1lLHRoaXMuX21hcD10LHRoaXMuX2xpc3Q9bix0aGlzKX0sdH0obnIpO0NyLmlzT3JkZXJlZE1hcD1FdCxDci5wcm90b3R5cGVbeW5dPSEwLENyLnByb3RvdHlwZS5kZWxldGU9Q3IucHJvdG90eXBlLnJlbW92ZTt2YXIgRXIsRHI9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlKXtyZXR1cm4gbnVsbD09PWV8fHZvaWQgMD09PWU/X3QoKTprdChlKT9lOl90KCkucHVzaEFsbChlKX1yZXR1cm4gZSYmKHQuX19wcm90b19fPWUpLHQucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZSYmZS5wcm90b3R5cGUpLHQucHJvdG90eXBlLmNvbnN0cnVjdG9yPXQsdC5vZj1mdW5jdGlvbigpe3JldHVybiB0aGlzKGFyZ3VtZW50cyl9LHQucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX190b1N0cmluZygiU3RhY2sgWyIsIl0iKX0sdC5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5faGVhZDtmb3IoZT1zKHRoaXMsZSk7biYmZS0tOyluPW4ubmV4dDtyZXR1cm4gbj9uLnZhbHVlOnR9LHQucHJvdG90eXBlLnBlZWs9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5faGVhZCYmdGhpcy5faGVhZC52YWx1ZX0sdC5wcm90b3R5cGUucHVzaD1mdW5jdGlvbigpe3ZhciBlPWFyZ3VtZW50cztpZigwPT09YXJndW1lbnRzLmxlbmd0aClyZXR1cm4gdGhpcztmb3IodmFyIHQ9dGhpcy5zaXplK2FyZ3VtZW50cy5sZW5ndGgsbj10aGlzLl9oZWFkLHI9YXJndW1lbnRzLmxlbmd0aC0xO3I+PTA7ci0tKW49e3ZhbHVlOmVbcl0sbmV4dDpufTtyZXR1cm4gdGhpcy5fX293bmVySUQ/KHRoaXMuc2l6ZT10LHRoaXMuX2hlYWQ9bix0aGlzLl9faGFzaD12b2lkIDAsdGhpcy5fX2FsdGVyZWQ9ITAsdGhpcyk6QXQodCxuKX0sdC5wcm90b3R5cGUucHVzaEFsbD1mdW5jdGlvbih0KXtpZih0PWUodCksMD09PXQuc2l6ZSlyZXR1cm4gdGhpcztpZigwPT09dGhpcy5zaXplJiZrdCh0KSlyZXR1cm4gdDtkZSh0LnNpemUpO3ZhciBuPXRoaXMuc2l6ZSxyPXRoaXMuX2hlYWQ7cmV0dXJuIHQuX19pdGVyYXRlKGZ1bmN0aW9uKGUpe24rKyxyPXt2YWx1ZTplLG5leHQ6cn19LCEwKSx0aGlzLl9fb3duZXJJRD8odGhpcy5zaXplPW4sdGhpcy5faGVhZD1yLHRoaXMuX19oYXNoPXZvaWQgMCx0aGlzLl9fYWx0ZXJlZD0hMCx0aGlzKTpBdChuLHIpfSx0LnByb3RvdHlwZS5wb3A9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5zbGljZSgxKX0sdC5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXtyZXR1cm4gMD09PXRoaXMuc2l6ZT90aGlzOnRoaXMuX19vd25lcklEPyh0aGlzLnNpemU9MCx0aGlzLl9oZWFkPXZvaWQgMCx0aGlzLl9faGFzaD12b2lkIDAsdGhpcy5fX2FsdGVyZWQ9ITAsdGhpcyk6X3QoKX0sdC5wcm90b3R5cGUuc2xpY2U9ZnVuY3Rpb24odCxuKXtpZihjKHQsbix0aGlzLnNpemUpKXJldHVybiB0aGlzO3ZhciByPWwodCx0aGlzLnNpemUpO2lmKHAobix0aGlzLnNpemUpIT09dGhpcy5zaXplKXJldHVybiBlLnByb3RvdHlwZS5zbGljZS5jYWxsKHRoaXMsdCxuKTtmb3IodmFyIGk9dGhpcy5zaXplLXIsbz10aGlzLl9oZWFkO3ItLTspbz1vLm5leHQ7cmV0dXJuIHRoaXMuX19vd25lcklEPyh0aGlzLnNpemU9aSx0aGlzLl9oZWFkPW8sdGhpcy5fX2hhc2g9dm9pZCAwLHRoaXMuX19hbHRlcmVkPSEwLHRoaXMpOkF0KGksbyl9LHQucHJvdG90eXBlLl9fZW5zdXJlT3duZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIGU9PT10aGlzLl9fb3duZXJJRD90aGlzOmU/QXQodGhpcy5zaXplLHRoaXMuX2hlYWQsZSx0aGlzLl9faGFzaCk6MD09PXRoaXMuc2l6ZT9fdCgpOih0aGlzLl9fb3duZXJJRD1lLHRoaXMuX19hbHRlcmVkPSExLHRoaXMpfSx0LnByb3RvdHlwZS5fX2l0ZXJhdGU9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzO2lmKHQpcmV0dXJuIG5ldyBNbih0aGlzLnRvQXJyYXkoKSkuX19pdGVyYXRlKGZ1bmN0aW9uKHQscil7cmV0dXJuIGUodCxyLG4pfSx0KTtmb3IodmFyIHI9MCxpPXRoaXMuX2hlYWQ7aSYmITEhPT1lKGkudmFsdWUscisrLG4pOylpPWkubmV4dDtyZXR1cm4gcn0sdC5wcm90b3R5cGUuX19pdGVyYXRvcj1mdW5jdGlvbihlLHQpe2lmKHQpcmV0dXJuIG5ldyBNbih0aGlzLnRvQXJyYXkoKSkuX19pdGVyYXRvcihlLHQpO3ZhciBuPTAscj10aGlzLl9oZWFkO3JldHVybiBuZXcgVG4oZnVuY3Rpb24oKXtpZihyKXt2YXIgdD1yLnZhbHVlO3JldHVybiByPXIubmV4dCxFKGUsbisrLHQpfXJldHVybiBEKCl9KX0sdH0oQ24pO0RyLmlzU3RhY2s9a3Q7dmFyIHdyPSJAQF9fSU1NVVRBQkxFX1NUQUNLX19AQCIsU3I9RHIucHJvdG90eXBlO1NyW3dyXT0hMCxTci5zaGlmdD1Tci5wb3AsU3IudW5zaGlmdD1Tci5wdXNoLFNyLnVuc2hpZnRBbGw9U3IucHVzaEFsbCxTci53aXRoTXV0YXRpb25zPUhlLFNyLndhc0FsdGVyZWQ9S2UsU3IuYXNJbW11dGFibGU9UWUsU3JbIkBAdHJhbnNkdWNlci9pbml0Il09U3IuYXNNdXRhYmxlPVdlLFNyWyJAQHRyYW5zZHVjZXIvc3RlcCJdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUudW5zaGlmdCh0KX0sU3JbIkBAdHJhbnNkdWNlci9yZXN1bHQiXT1mdW5jdGlvbihlKXtyZXR1cm4gZS5hc0ltbXV0YWJsZSgpfTt2YXIga3IsQXI9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0KXtyZXR1cm4gbnVsbD09PXR8fHZvaWQgMD09PXQ/UHQoKTpOdCh0KSYmIWIodCk/dDpQdCgpLndpdGhNdXRhdGlvbnMoZnVuY3Rpb24obil7dmFyIHI9ZSh0KTtkZShyLnNpemUpLHIuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gbi5hZGQoZSl9KX0pfXJldHVybiBlJiYodC5fX3Byb3RvX189ZSksdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlJiZlLnByb3RvdHlwZSksdC5wcm90b3R5cGUuY29uc3RydWN0b3I9dCx0Lm9mPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMoYXJndW1lbnRzKX0sdC5mcm9tS2V5cz1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcyh4bihlKS5rZXlTZXEoKSl9LHQuaW50ZXJzZWN0PWZ1bmN0aW9uKGUpe3JldHVybiBlPWJuKGUpLnRvQXJyYXkoKSxlLmxlbmd0aD9Uci5pbnRlcnNlY3QuYXBwbHkodChlLnBvcCgpKSxlKTpQdCgpfSx0LnVuaW9uPWZ1bmN0aW9uKGUpe3JldHVybiBlPWJuKGUpLnRvQXJyYXkoKSxlLmxlbmd0aD9Uci51bmlvbi5hcHBseSh0KGUucG9wKCkpLGUpOlB0KCl9LHQucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX190b1N0cmluZygiU2V0IHsiLCJ9Iil9LHQucHJvdG90eXBlLmhhcz1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5fbWFwLmhhcyhlKX0sdC5wcm90b3R5cGUuYWRkPWZ1bmN0aW9uKGUpe3JldHVybiBJdCh0aGlzLHRoaXMuX21hcC5zZXQoZSxlKSl9LHQucHJvdG90eXBlLnJlbW92ZT1mdW5jdGlvbihlKXtyZXR1cm4gSXQodGhpcyx0aGlzLl9tYXAucmVtb3ZlKGUpKX0sdC5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXtyZXR1cm4gSXQodGhpcyx0aGlzLl9tYXAuY2xlYXIoKSl9LHQucHJvdG90eXBlLnVuaW9uPWZ1bmN0aW9uKCl7Zm9yKHZhciB0PVtdLG49YXJndW1lbnRzLmxlbmd0aDtuLS07KXRbbl09YXJndW1lbnRzW25dO3JldHVybiB0PXQuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiAwIT09ZS5zaXplfSksMD09PXQubGVuZ3RoP3RoaXM6MCE9PXRoaXMuc2l6ZXx8dGhpcy5fX293bmVySUR8fDEhPT10Lmxlbmd0aD90aGlzLndpdGhNdXRhdGlvbnMoZnVuY3Rpb24obil7Zm9yKHZhciByPTA7cjx0Lmxlbmd0aDtyKyspZSh0W3JdKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBuLmFkZChlKX0pfSk6dGhpcy5jb25zdHJ1Y3Rvcih0WzBdKX0sdC5wcm90b3R5cGUuaW50ZXJzZWN0PWZ1bmN0aW9uKCl7Zm9yKHZhciB0PVtdLG49YXJndW1lbnRzLmxlbmd0aDtuLS07KXRbbl09YXJndW1lbnRzW25dO2lmKDA9PT10Lmxlbmd0aClyZXR1cm4gdGhpczt0PXQubWFwKGZ1bmN0aW9uKHQpe3JldHVybiBlKHQpfSk7dmFyIHI9W107cmV0dXJuIHRoaXMuZm9yRWFjaChmdW5jdGlvbihlKXt0LmV2ZXJ5KGZ1bmN0aW9uKHQpe3JldHVybiB0LmluY2x1ZGVzKGUpfSl8fHIucHVzaChlKX0pLHRoaXMud2l0aE11dGF0aW9ucyhmdW5jdGlvbihlKXtyLmZvckVhY2goZnVuY3Rpb24odCl7ZS5yZW1vdmUodCl9KX0pfSx0LnByb3RvdHlwZS5zdWJ0cmFjdD1mdW5jdGlvbigpe2Zvcih2YXIgdD1bXSxuPWFyZ3VtZW50cy5sZW5ndGg7bi0tOyl0W25dPWFyZ3VtZW50c1tuXTtpZigwPT09dC5sZW5ndGgpcmV0dXJuIHRoaXM7dD10Lm1hcChmdW5jdGlvbih0KXtyZXR1cm4gZSh0KX0pO3ZhciByPVtdO3JldHVybiB0aGlzLmZvckVhY2goZnVuY3Rpb24oZSl7dC5zb21lKGZ1bmN0aW9uKHQpe3JldHVybiB0LmluY2x1ZGVzKGUpfSkmJnIucHVzaChlKX0pLHRoaXMud2l0aE11dGF0aW9ucyhmdW5jdGlvbihlKXtyLmZvckVhY2goZnVuY3Rpb24odCl7ZS5yZW1vdmUodCl9KX0pfSx0LnByb3RvdHlwZS5zb3J0PWZ1bmN0aW9uKGUpe3JldHVybiBNcih0ZSh0aGlzLGUpKX0sdC5wcm90b3R5cGUuc29ydEJ5PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE1yKHRlKHRoaXMsdCxlKSl9LHQucHJvdG90eXBlLndhc0FsdGVyZWQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fbWFwLndhc0FsdGVyZWQoKX0sdC5wcm90b3R5cGUuX19pdGVyYXRlPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcztyZXR1cm4gdGhpcy5fbWFwLl9faXRlcmF0ZShmdW5jdGlvbih0KXtyZXR1cm4gZSh0LHQsbil9LHQpfSx0LnByb3RvdHlwZS5fX2l0ZXJhdG9yPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuX21hcC5fX2l0ZXJhdG9yKGUsdCl9LHQucHJvdG90eXBlLl9fZW5zdXJlT3duZXI9ZnVuY3Rpb24oZSl7aWYoZT09PXRoaXMuX19vd25lcklEKXJldHVybiB0aGlzO3ZhciB0PXRoaXMuX21hcC5fX2Vuc3VyZU93bmVyKGUpO3JldHVybiBlP3RoaXMuX19tYWtlKHQsZSk6MD09PXRoaXMuc2l6ZT90aGlzLl9fZW1wdHkoKToodGhpcy5fX293bmVySUQ9ZSx0aGlzLl9tYXA9dCx0aGlzKX0sdH0oRW4pO0FyLmlzU2V0PU50O3ZhciBfcj0iQEBfX0lNTVVUQUJMRV9TRVRfX0BAIixUcj1Bci5wcm90b3R5cGU7VHJbX3JdPSEwLFRyLmRlbGV0ZT1Uci5yZW1vdmUsVHIubWVyZ2U9VHIuY29uY2F0PVRyLnVuaW9uLFRyLndpdGhNdXRhdGlvbnM9SGUsVHIuYXNJbW11dGFibGU9UWUsVHJbIkBAdHJhbnNkdWNlci9pbml0Il09VHIuYXNNdXRhYmxlPVdlLFRyWyJAQHRyYW5zZHVjZXIvc3RlcCJdPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuYWRkKHQpfSxUclsiQEB0cmFuc2R1Y2VyL3Jlc3VsdCJdPWZ1bmN0aW9uKGUpe3JldHVybiBlLmFzSW1tdXRhYmxlKCl9LFRyLl9fZW1wdHk9UHQsVHIuX19tYWtlPUx0O3ZhciBPcixGcixOcj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUsbixyKXtpZighKHRoaXMgaW5zdGFuY2VvZiB0KSlyZXR1cm4gbmV3IHQoZSxuLHIpO2lmKGZlKDAhPT1yLCJDYW5ub3Qgc3RlcCBhIFJhbmdlIGJ5IDAiKSxlPWV8fDAsdm9pZCAwPT09biYmKG49MS8wKSxyPXZvaWQgMD09PXI/MTpNYXRoLmFicyhyKSxuPGUmJihyPS1yKSx0aGlzLl9zdGFydD1lLHRoaXMuX2VuZD1uLHRoaXMuX3N0ZXA9cix0aGlzLnNpemU9TWF0aC5tYXgoMCxNYXRoLmNlaWwoKG4tZSkvci0xKSsxKSwwPT09dGhpcy5zaXplKXtpZihGcilyZXR1cm4gRnI7RnI9dGhpc319cmV0dXJuIGUmJih0Ll9fcHJvdG9fXz1lKSx0LnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUmJmUucHJvdG90eXBlKSx0LnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj10LHQucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIDA9PT10aGlzLnNpemU/IlJhbmdlIFtdIjoiUmFuZ2UgWyAiK3RoaXMuX3N0YXJ0KyIuLi4iK3RoaXMuX2VuZCsoMSE9PXRoaXMuX3N0ZXA/IiBieSAiK3RoaXMuX3N0ZXA6IiIpKyIgXSJ9LHQucHJvdG90eXBlLmdldD1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLmhhcyhlKT90aGlzLl9zdGFydCtzKHRoaXMsZSkqdGhpcy5fc3RlcDp0fSx0LnByb3RvdHlwZS5pbmNsdWRlcz1mdW5jdGlvbihlKXt2YXIgdD0oZS10aGlzLl9zdGFydCkvdGhpcy5fc3RlcDtyZXR1cm4gdD49MCYmdDx0aGlzLnNpemUmJnQ9PT1NYXRoLmZsb29yKHQpfSx0LnByb3RvdHlwZS5zbGljZT1mdW5jdGlvbihlLG4pe3JldHVybiBjKGUsbix0aGlzLnNpemUpP3RoaXM6KGU9bChlLHRoaXMuc2l6ZSksbj1wKG4sdGhpcy5zaXplKSxuPD1lP25ldyB0KDAsMCk6bmV3IHQodGhpcy5nZXQoZSx0aGlzLl9lbmQpLHRoaXMuZ2V0KG4sdGhpcy5fZW5kKSx0aGlzLl9zdGVwKSl9LHQucHJvdG90eXBlLmluZGV4T2Y9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS10aGlzLl9zdGFydDtpZih0JXRoaXMuX3N0ZXA9PT0wKXt2YXIgbj10L3RoaXMuX3N0ZXA7aWYobj49MCYmbjx0aGlzLnNpemUpcmV0dXJuIG59cmV0dXJuLTF9LHQucHJvdG90eXBlLmxhc3RJbmRleE9mPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLmluZGV4T2YoZSl9LHQucHJvdG90eXBlLl9faXRlcmF0ZT1mdW5jdGlvbihlLHQpe2Zvcih2YXIgbj10aGlzLHI9dGhpcy5zaXplLGk9dGhpcy5fc3RlcCxvPXQ/dGhpcy5fc3RhcnQrKHItMSkqaTp0aGlzLl9zdGFydCxhPTA7YSE9PXImJiExIT09ZShvLHQ/ci0rK2E6YSsrLG4pOylvKz10Py1pOmk7cmV0dXJuIGF9LHQucHJvdG90eXBlLl9faXRlcmF0b3I9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLnNpemUscj10aGlzLl9zdGVwLGk9dD90aGlzLl9zdGFydCsobi0xKSpyOnRoaXMuX3N0YXJ0LG89MDtyZXR1cm4gbmV3IFRuKGZ1bmN0aW9uKCl7aWYobz09PW4pcmV0dXJuIEQoKTt2YXIgYT1pO3JldHVybiBpKz10Py1yOnIsRShlLHQ/bi0rK286bysrLGEpfSl9LHQucHJvdG90eXBlLmVxdWFscz1mdW5jdGlvbihlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIHQ/dGhpcy5fc3RhcnQ9PT1lLl9zdGFydCYmdGhpcy5fZW5kPT09ZS5fZW5kJiZ0aGlzLl9zdGVwPT09ZS5fc3RlcDpUdCh0aGlzLGUpfSx0fShJbik7Ym4uaXNJdGVyYWJsZT1tLGJuLmlzS2V5ZWQ9Zyxibi5pc0luZGV4ZWQ9eSxibi5pc0Fzc29jaWF0aXZlPXYsYm4uaXNPcmRlcmVkPWIsYm4uSXRlcmF0b3I9VG4sT3QoYm4se3RvQXJyYXk6ZnVuY3Rpb24oKXtkZSh0aGlzLnNpemUpO3ZhciBlPW5ldyBBcnJheSh0aGlzLnNpemV8fDApLHQ9Zyh0aGlzKSxuPTA7cmV0dXJuIHRoaXMuX19pdGVyYXRlKGZ1bmN0aW9uKHIsaSl7ZVtuKytdPXQ/W2kscl06cn0pLGV9LHRvSW5kZXhlZFNlcTpmdW5jdGlvbigpe3JldHVybiBuZXcgWm4odGhpcyl9LHRvSlM6ZnVuY3Rpb24oKXtyZXR1cm4gRnQodGhpcyl9LHRvS2V5ZWRTZXE6ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IFhuKHRoaXMsITApfSx0b01hcDpmdW5jdGlvbigpe3JldHVybiBucih0aGlzLnRvS2V5ZWRTZXEoKSl9LHRvT2JqZWN0OiR0LHRvT3JkZXJlZE1hcDpmdW5jdGlvbigpe3JldHVybiBDcih0aGlzLnRvS2V5ZWRTZXEoKSl9LHRvT3JkZXJlZFNldDpmdW5jdGlvbigpe3JldHVybiBNcihnKHRoaXMpP3RoaXMudmFsdWVTZXEoKTp0aGlzKX0sdG9TZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gQXIoZyh0aGlzKT90aGlzLnZhbHVlU2VxKCk6dGhpcyl9LHRvU2V0U2VxOmZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBlcih0aGlzKX0sdG9TZXE6ZnVuY3Rpb24oKXtyZXR1cm4geSh0aGlzKT90aGlzLnRvSW5kZXhlZFNlcSgpOmcodGhpcyk/dGhpcy50b0tleWVkU2VxKCk6dGhpcy50b1NldFNlcSgpfSx0b1N0YWNrOmZ1bmN0aW9uKCl7cmV0dXJuIERyKGcodGhpcyk/dGhpcy52YWx1ZVNlcSgpOnRoaXMpfSx0b0xpc3Q6ZnVuY3Rpb24oKXtyZXR1cm4gbXIoZyh0aGlzKT90aGlzLnZhbHVlU2VxKCk6dGhpcyl9LHRvU3RyaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIltDb2xsZWN0aW9uXSJ9LF9fdG9TdHJpbmc6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gMD09PXRoaXMuc2l6ZT9lK3Q6ZSsiICIrdGhpcy50b1NlcSgpLm1hcCh0aGlzLl9fdG9TdHJpbmdNYXBwZXIpLmpvaW4oIiwgIikrIiAiK3R9LGNvbmNhdDpmdW5jdGlvbigpe2Zvcih2YXIgZT1bXSx0PWFyZ3VtZW50cy5sZW5ndGg7dC0tOyllW3RdPWFyZ3VtZW50c1t0XTtyZXR1cm4gb2UodGhpcyxZKHRoaXMsZSkpfSxpbmNsdWRlczpmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5zb21lKGZ1bmN0aW9uKHQpe3JldHVybiBQKHQsZSl9KX0sZW50cmllczpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9faXRlcmF0b3IoU24pfSxldmVyeTpmdW5jdGlvbihlLHQpe2RlKHRoaXMuc2l6ZSk7dmFyIG49ITA7cmV0dXJuIHRoaXMuX19pdGVyYXRlKGZ1bmN0aW9uKHIsaSxvKXtpZighZS5jYWxsKHQscixpLG8pKXJldHVybiBuPSExLCExfSksbn0sZmlsdGVyOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIG9lKHRoaXMscSh0aGlzLGUsdCwhMCkpfSxmaW5kOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj10aGlzLmZpbmRFbnRyeShlLHQpO3JldHVybiByP3JbMV06bn0sZm9yRWFjaDpmdW5jdGlvbihlLHQpe3JldHVybiBkZSh0aGlzLnNpemUpLHRoaXMuX19pdGVyYXRlKHQ/ZS5iaW5kKHQpOmUpfSxqb2luOmZ1bmN0aW9uKGUpe2RlKHRoaXMuc2l6ZSksZT12b2lkIDAhPT1lPyIiK2U6IiwiO3ZhciB0PSIiLG49ITA7cmV0dXJuIHRoaXMuX19pdGVyYXRlKGZ1bmN0aW9uKHIpe24/bj0hMTp0Kz1lLHQrPW51bGwhPT1yJiZ2b2lkIDAhPT1yP3IudG9TdHJpbmcoKToiIn0pLHR9LGtleXM6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fX2l0ZXJhdG9yKERuKX0sbWFwOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIG9lKHRoaXMsRyh0aGlzLGUsdCkpfSxyZWR1Y2U6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBVdCh0aGlzLGUsdCxuLGFyZ3VtZW50cy5sZW5ndGg8MiwhMSl9LHJlZHVjZVJpZ2h0OmZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gVXQodGhpcyxlLHQsbixhcmd1bWVudHMubGVuZ3RoPDIsITApfSxyZXZlcnNlOmZ1bmN0aW9uKCl7cmV0dXJuIG9lKHRoaXMsVih0aGlzLCEwKSl9LHNsaWNlOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIG9lKHRoaXMsUSh0aGlzLGUsdCwhMCkpfSxzb21lOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIXRoaXMuZXZlcnkoVnQoZSksdCl9LHNvcnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIG9lKHRoaXMsdGUodGhpcyxlKSl9LHZhbHVlczpmdW5jdGlvbigpe3JldHVybiB0aGlzLl9faXRlcmF0b3Iod24pfSxidXRMYXN0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc2xpY2UoMCwtMSl9LGlzRW1wdHk6ZnVuY3Rpb24oKXtyZXR1cm4gdm9pZCAwIT09dGhpcy5zaXplPzA9PT10aGlzLnNpemU6IXRoaXMuc29tZShmdW5jdGlvbigpe3JldHVybiEwfSl9LGNvdW50OmZ1bmN0aW9uKGUsdCl7cmV0dXJuIGEoZT90aGlzLnRvU2VxKCkuZmlsdGVyKGUsdCk6dGhpcyl9LGNvdW50Qnk6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gSCh0aGlzLGUsdCl9LGVxdWFsczpmdW5jdGlvbihlKXtyZXR1cm4gVHQodGhpcyxlKX0sZW50cnlTZXE6ZnVuY3Rpb24oKXt2YXIgZT10aGlzO2lmKGUuX2NhY2hlKXJldHVybiBuZXcgTW4oZS5fY2FjaGUpO3ZhciB0PWUudG9TZXEoKS5tYXAoR3QpLnRvSW5kZXhlZFNlcSgpO3JldHVybiB0LmZyb21FbnRyeVNlcT1mdW5jdGlvbigpe3JldHVybiBlLnRvU2VxKCl9LHR9LGZpbHRlck5vdDpmdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLmZpbHRlcihWdChlKSx0KX0sZmluZEVudHJ5OmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1uO3JldHVybiB0aGlzLl9faXRlcmF0ZShmdW5jdGlvbihuLGksbyl7aWYoZS5jYWxsKHQsbixpLG8pKXJldHVybiByPVtpLG5dLCExfSkscn0sZmluZEtleTpmdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMuZmluZEVudHJ5KGUsdCk7cmV0dXJuIG4mJm5bMF19LGZpbmRMYXN0OmZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gdGhpcy50b0tleWVkU2VxKCkucmV2ZXJzZSgpLmZpbmQoZSx0LG4pfSxmaW5kTGFzdEVudHJ5OmZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gdGhpcy50b0tleWVkU2VxKCkucmV2ZXJzZSgpLmZpbmRFbnRyeShlLHQsbil9LGZpbmRMYXN0S2V5OmZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMudG9LZXllZFNlcSgpLnJldmVyc2UoKS5maW5kS2V5KGUsdCl9LGZpcnN0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZmluZCh1KX0sZmxhdE1hcDpmdW5jdGlvbihlLHQpe3JldHVybiBvZSh0aGlzLFoodGhpcyxlLHQpKX0sZmxhdHRlbjpmdW5jdGlvbihlKXtyZXR1cm4gb2UodGhpcyxYKHRoaXMsZSwhMCkpfSxmcm9tRW50cnlTZXE6ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IHRyKHRoaXMpfSxnZXQ6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5maW5kKGZ1bmN0aW9uKHQsbil7cmV0dXJuIFAobixlKX0sdm9pZCAwLHQpfSxnZXRJbjpqdCxncm91cEJ5OmZ1bmN0aW9uKGUsdCl7cmV0dXJuIFcodGhpcyxlLHQpfSxoYXM6ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuZ2V0KGUscG4pIT09cG59LGhhc0luOkJ0LGlzU3Vic2V0OmZ1bmN0aW9uKGUpe3JldHVybiBlPSJmdW5jdGlvbiI9PT10eXBlb2YgZS5pbmNsdWRlcz9lOmJuKGUpLHRoaXMuZXZlcnkoZnVuY3Rpb24odCl7cmV0dXJuIGUuaW5jbHVkZXModCl9KX0saXNTdXBlcnNldDpmdW5jdGlvbihlKXtyZXR1cm4gZT0iZnVuY3Rpb24iPT09dHlwZW9mIGUuaXNTdWJzZXQ/ZTpibihlKSxlLmlzU3Vic2V0KHRoaXMpfSxrZXlPZjpmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5maW5kS2V5KGZ1bmN0aW9uKHQpe3JldHVybiBQKHQsZSl9KX0sa2V5U2VxOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudG9TZXEoKS5tYXAoenQpLnRvSW5kZXhlZFNlcSgpfSxsYXN0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudG9TZXEoKS5yZXZlcnNlKCkuZmlyc3QoKX0sbGFzdEtleU9mOmZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLnRvS2V5ZWRTZXEoKS5yZXZlcnNlKCkua2V5T2YoZSl9LG1heDpmdW5jdGlvbihlKXtyZXR1cm4gbmUodGhpcyxlKX0sbWF4Qnk6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gbmUodGhpcyx0LGUpfSxtaW46ZnVuY3Rpb24oZSl7cmV0dXJuIG5lKHRoaXMsZT9xdChlKTpXdCl9LG1pbkJ5OmZ1bmN0aW9uKGUsdCl7cmV0dXJuIG5lKHRoaXMsdD9xdCh0KTpXdCxlKX0scmVzdDpmdW5jdGlvbigpe3JldHVybiB0aGlzLnNsaWNlKDEpfSxza2lwOmZ1bmN0aW9uKGUpe3JldHVybiAwPT09ZT90aGlzOnRoaXMuc2xpY2UoTWF0aC5tYXgoMCxlKSl9LHNraXBMYXN0OmZ1bmN0aW9uKGUpe3JldHVybiAwPT09ZT90aGlzOnRoaXMuc2xpY2UoMCwtTWF0aC5tYXgoMCxlKSl9LHNraXBXaGlsZTpmdW5jdGlvbihlLHQpe3JldHVybiBvZSh0aGlzLEoodGhpcyxlLHQsITApKX0sc2tpcFVudGlsOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuc2tpcFdoaWxlKFZ0KGUpLHQpfSxzb3J0Qnk6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gb2UodGhpcyx0ZSh0aGlzLHQsZSkpfSx0YWtlOmZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLnNsaWNlKDAsTWF0aC5tYXgoMCxlKSl9LHRha2VMYXN0OmZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLnNsaWNlKC1NYXRoLm1heCgwLGUpKX0sdGFrZVdoaWxlOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIG9lKHRoaXMsSyh0aGlzLGUsdCkpfSx0YWtlVW50aWw6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy50YWtlV2hpbGUoVnQoZSksdCl9LHVwZGF0ZTpmdW5jdGlvbihlKXtyZXR1cm4gZSh0aGlzKX0sdmFsdWVTZXE6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy50b0luZGV4ZWRTZXEoKX0saGFzaENvZGU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fX2hhc2h8fCh0aGlzLl9faGFzaD1RdCh0aGlzKSl9fSk7dmFyIElyPWJuLnByb3RvdHlwZTtJcltobl09ITAsSXJbX25dPUlyLnZhbHVlcyxJci50b0pTT049SXIudG9BcnJheSxJci5fX3RvU3RyaW5nTWFwcGVyPXllLElyLmluc3BlY3Q9SXIudG9Tb3VyY2U9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy50b1N0cmluZygpfSxJci5jaGFpbj1Jci5mbGF0TWFwLElyLmNvbnRhaW5zPUlyLmluY2x1ZGVzLE90KHhuLHtmbGlwOmZ1bmN0aW9uKCl7cmV0dXJuIG9lKHRoaXMseih0aGlzKSl9LG1hcEVudHJpZXM6ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLHI9MDtyZXR1cm4gb2UodGhpcyx0aGlzLnRvU2VxKCkubWFwKGZ1bmN0aW9uKGksbyl7cmV0dXJuIGUuY2FsbCh0LFtvLGldLHIrKyxuKX0pLmZyb21FbnRyeVNlcSgpKX0sbWFwS2V5czpmdW5jdGlvbihlLHQpe3ZhciBuPXRoaXM7cmV0dXJuIG9lKHRoaXMsdGhpcy50b1NlcSgpLmZsaXAoKS5tYXAoZnVuY3Rpb24ocixpKXtyZXR1cm4gZS5jYWxsKHQscixpLG4pfSkuZmxpcCgpKX19KTt2YXIgTHI9eG4ucHJvdG90eXBlO0xyW21uXT0hMCxMcltfbl09SXIuZW50cmllcyxMci50b0pTT049JHQsTHIuX190b1N0cmluZ01hcHBlcj1mdW5jdGlvbihlLHQpe3JldHVybiB5ZSh0KSsiOiAiK3llKGUpfSxPdChDbix7dG9LZXllZFNlcTpmdW5jdGlvbigpe3JldHVybiBuZXcgWG4odGhpcywhMSl9LGZpbHRlcjpmdW5jdGlvbihlLHQpe3JldHVybiBvZSh0aGlzLHEodGhpcyxlLHQsITEpKX0sZmluZEluZGV4OmZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5maW5kRW50cnkoZSx0KTtyZXR1cm4gbj9uWzBdOi0xfSxpbmRleE9mOmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMua2V5T2YoZSk7cmV0dXJuIHZvaWQgMD09PXQ/LTE6dH0sbGFzdEluZGV4T2Y6ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5sYXN0S2V5T2YoZSk7cmV0dXJuIHZvaWQgMD09PXQ/LTE6dH0scmV2ZXJzZTpmdW5jdGlvbigpe3JldHVybiBvZSh0aGlzLFYodGhpcywhMSkpfSxzbGljZTpmdW5jdGlvbihlLHQpe3JldHVybiBvZSh0aGlzLFEodGhpcyxlLHQsITEpKX0sc3BsaWNlOmZ1bmN0aW9uKGUsdCl7dmFyIG49YXJndW1lbnRzLmxlbmd0aDtpZih0PU1hdGgubWF4KHR8fDAsMCksMD09PW58fDI9PT1uJiYhdClyZXR1cm4gdGhpcztlPWwoZSxlPDA/dGhpcy5jb3VudCgpOnRoaXMuc2l6ZSk7dmFyIHI9dGhpcy5zbGljZSgwLGUpO3JldHVybiBvZSh0aGlzLDE9PT1uP3I6ci5jb25jYXQocGUoYXJndW1lbnRzLDIpLHRoaXMuc2xpY2UoZSt0KSkpfSxmaW5kTGFzdEluZGV4OmZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5maW5kTGFzdEVudHJ5KGUsdCk7cmV0dXJuIG4/blswXTotMX0sZmlyc3Q6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5nZXQoMCl9LGZsYXR0ZW46ZnVuY3Rpb24oZSl7cmV0dXJuIG9lKHRoaXMsWCh0aGlzLGUsITEpKX0sZ2V0OmZ1bmN0aW9uKGUsdCl7cmV0dXJuIGU9cyh0aGlzLGUpLGU8MHx8dGhpcy5zaXplPT09MS8wfHx2b2lkIDAhPT10aGlzLnNpemUmJmU+dGhpcy5zaXplP3Q6dGhpcy5maW5kKGZ1bmN0aW9uKHQsbil7cmV0dXJuIG49PT1lfSx2b2lkIDAsdCl9LGhhczpmdW5jdGlvbihlKXtyZXR1cm4oZT1zKHRoaXMsZSkpPj0wJiYodm9pZCAwIT09dGhpcy5zaXplP3RoaXMuc2l6ZT09PTEvMHx8ZTx0aGlzLnNpemU6LTEhPT10aGlzLmluZGV4T2YoZSkpfSxpbnRlcnBvc2U6ZnVuY3Rpb24oZSl7cmV0dXJuIG9lKHRoaXMsZWUodGhpcyxlKSl9LGludGVybGVhdmU6ZnVuY3Rpb24oKXt2YXIgZT1bdGhpc10uY29uY2F0KHBlKGFyZ3VtZW50cykpLHQ9aWUodGhpcy50b1NlcSgpLEluLm9mLGUpLG49dC5mbGF0dGVuKCEwKTtyZXR1cm4gdC5zaXplJiYobi5zaXplPXQuc2l6ZSplLmxlbmd0aCksb2UodGhpcyxuKX0sa2V5U2VxOmZ1bmN0aW9uKCl7cmV0dXJuIE5yKDAsdGhpcy5zaXplKX0sbGFzdDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmdldCgtMSl9LHNraXBXaGlsZTpmdW5jdGlvbihlLHQpe3JldHVybiBvZSh0aGlzLEoodGhpcyxlLHQsITEpKX0semlwOmZ1bmN0aW9uKCl7cmV0dXJuIG9lKHRoaXMsaWUodGhpcyxIdCxbdGhpc10uY29uY2F0KHBlKGFyZ3VtZW50cykpKSl9LHppcEFsbDpmdW5jdGlvbigpe3JldHVybiBvZSh0aGlzLGllKHRoaXMsSHQsW3RoaXNdLmNvbmNhdChwZShhcmd1bWVudHMpKSwhMCkpfSx6aXBXaXRoOmZ1bmN0aW9uKGUpe3ZhciB0PXBlKGFyZ3VtZW50cyk7cmV0dXJuIHRbMF09dGhpcyxvZSh0aGlzLGllKHRoaXMsZSx0KSl9fSk7dmFyIFByPUNuLnByb3RvdHlwZTtQcltnbl09ITAsUHJbeW5dPSEwLE90KEVuLHtnZXQ6ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5oYXMoZSk/ZTp0fSxpbmNsdWRlczpmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5oYXMoZSl9LGtleVNlcTpmdW5jdGlvbigpe3JldHVybiB0aGlzLnZhbHVlU2VxKCl9fSksRW4ucHJvdG90eXBlLmhhcz1Jci5pbmNsdWRlcyxFbi5wcm90b3R5cGUuY29udGFpbnM9RW4ucHJvdG90eXBlLmluY2x1ZGVzLE90KE5uLHhuLnByb3RvdHlwZSksT3QoSW4sQ24ucHJvdG90eXBlKSxPdChMbixFbi5wcm90b3R5cGUpO3ZhciBNcj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUpe3JldHVybiBudWxsPT09ZXx8dm9pZCAwPT09ZT9adCgpOll0KGUpP2U6WnQoKS53aXRoTXV0YXRpb25zKGZ1bmN0aW9uKHQpe3ZhciBuPUVuKGUpO2RlKG4uc2l6ZSksbi5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiB0LmFkZChlKX0pfSl9cmV0dXJuIGUmJih0Ll9fcHJvdG9fXz1lKSx0LnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUmJmUucHJvdG90eXBlKSx0LnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj10LHQub2Y9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcyhhcmd1bWVudHMpfSx0LmZyb21LZXlzPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzKHhuKGUpLmtleVNlcSgpKX0sdC5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fX3RvU3RyaW5nKCJPcmRlcmVkU2V0IHsiLCJ9Iil9LHR9KEFyKTtNci5pc09yZGVyZWRTZXQ9WXQ7dmFyIGpyPU1yLnByb3RvdHlwZTtqclt5bl09ITAsanIuemlwPVByLnppcCxqci56aXBXaXRoPVByLnppcFdpdGgsanIuX19lbXB0eT1adCxqci5fX21ha2U9WHQ7dmFyIFJyLEJyPWZ1bmN0aW9uKGUsdCl7dmFyIG4scj1mdW5jdGlvbihvKXt2YXIgYT10aGlzO2lmKG8gaW5zdGFuY2VvZiByKXJldHVybiBvO2lmKCEodGhpcyBpbnN0YW5jZW9mIHIpKXJldHVybiBuZXcgcihvKTtpZighbil7bj0hMDt2YXIgcz1PYmplY3Qua2V5cyhlKSx1PWkuX2luZGljZXM9e307aS5fbmFtZT10LGkuX2tleXM9cyxpLl9kZWZhdWx0VmFsdWVzPWU7Zm9yKHZhciBjPTA7YzxzLmxlbmd0aDtjKyspe3ZhciBsPXNbY107dVtsXT1jLGlbbF0/Im9iamVjdCI9PT10eXBlb2YgY29uc29sZSYmY29uc29sZS53YXJuJiZjb25zb2xlLndhcm4oIkNhbm5vdCBkZWZpbmUgIit0bihhKSsnIHdpdGggcHJvcGVydHkgIicrbCsnIiBzaW5jZSB0aGF0IHByb3BlcnR5IG5hbWUgaXMgcGFydCBvZiB0aGUgUmVjb3JkIEFQSS4nKTpybihpLGwpfX10aGlzLl9fb3duZXJJRD12b2lkIDAsdGhpcy5fdmFsdWVzPW1yKCkud2l0aE11dGF0aW9ucyhmdW5jdGlvbihlKXtlLnNldFNpemUoYS5fa2V5cy5sZW5ndGgpLHhuKG8pLmZvckVhY2goZnVuY3Rpb24odCxuKXtlLnNldChhLl9pbmRpY2VzW25dLHQ9PT1hLl9kZWZhdWx0VmFsdWVzW25dP3ZvaWQgMDp0KX0pfSl9LGk9ci5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZSgkcik7cmV0dXJuIGkuY29uc3RydWN0b3I9cixyfTtCci5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtmb3IodmFyIGUsdD10aGlzLG49dG4odGhpcykrIiB7ICIscj10aGlzLl9rZXlzLGk9MCxvPXIubGVuZ3RoO2khPT1vO2krKyllPXJbaV0sbis9KGk/IiwgIjoiIikrZSsiOiAiK3llKHQuZ2V0KGUpKTtyZXR1cm4gbisiIH0ifSxCci5wcm90b3R5cGUuZXF1YWxzPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzPT09ZXx8ZSYmdGhpcy5fa2V5cz09PWUuX2tleXMmJm5uKHRoaXMpLmVxdWFscyhubihlKSl9LEJyLnByb3RvdHlwZS5oYXNoQ29kZT1mdW5jdGlvbigpe3JldHVybiBubih0aGlzKS5oYXNoQ29kZSgpfSxCci5wcm90b3R5cGUuaGFzPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9pbmRpY2VzLmhhc093blByb3BlcnR5KGUpfSxCci5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUsdCl7aWYoIXRoaXMuaGFzKGUpKXJldHVybiB0O3ZhciBuPXRoaXMuX2luZGljZXNbZV0scj10aGlzLl92YWx1ZXMuZ2V0KG4pO3JldHVybiB2b2lkIDA9PT1yP3RoaXMuX2RlZmF1bHRWYWx1ZXNbZV06cn0sQnIucHJvdG90eXBlLnNldD1mdW5jdGlvbihlLHQpe2lmKHRoaXMuaGFzKGUpKXt2YXIgbj10aGlzLl92YWx1ZXMuc2V0KHRoaXMuX2luZGljZXNbZV0sdD09PXRoaXMuX2RlZmF1bHRWYWx1ZXNbZV0/dm9pZCAwOnQpO2lmKG4hPT10aGlzLl92YWx1ZXMmJiF0aGlzLl9fb3duZXJJRClyZXR1cm4gZW4odGhpcyxuKX1yZXR1cm4gdGhpc30sQnIucHJvdG90eXBlLnJlbW92ZT1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5zZXQoZSl9LEJyLnByb3RvdHlwZS5jbGVhcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMuX3ZhbHVlcy5jbGVhcigpLnNldFNpemUodGhpcy5fa2V5cy5sZW5ndGgpO3JldHVybiB0aGlzLl9fb3duZXJJRD90aGlzOmVuKHRoaXMsZSl9LEJyLnByb3RvdHlwZS53YXNBbHRlcmVkPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3ZhbHVlcy53YXNBbHRlcmVkKCl9LEJyLnByb3RvdHlwZS50b1NlcT1mdW5jdGlvbigpe3JldHVybiBubih0aGlzKX0sQnIucHJvdG90eXBlLnRvSlM9ZnVuY3Rpb24oKXtyZXR1cm4gRnQodGhpcyl9LEJyLnByb3RvdHlwZS5lbnRyaWVzPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX19pdGVyYXRvcihTbil9LEJyLnByb3RvdHlwZS5fX2l0ZXJhdG9yPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIG5uKHRoaXMpLl9faXRlcmF0b3IoZSx0KX0sQnIucHJvdG90eXBlLl9faXRlcmF0ZT1mdW5jdGlvbihlLHQpe3JldHVybiBubih0aGlzKS5fX2l0ZXJhdGUoZSx0KX0sQnIucHJvdG90eXBlLl9fZW5zdXJlT3duZXI9ZnVuY3Rpb24oZSl7aWYoZT09PXRoaXMuX19vd25lcklEKXJldHVybiB0aGlzO3ZhciB0PXRoaXMuX3ZhbHVlcy5fX2Vuc3VyZU93bmVyKGUpO3JldHVybiBlP2VuKHRoaXMsdCxlKToodGhpcy5fX293bmVySUQ9ZSx0aGlzLl92YWx1ZXM9dCx0aGlzKX0sQnIuaXNSZWNvcmQ9eCxCci5nZXREZXNjcmlwdGl2ZU5hbWU9dG47dmFyICRyPUJyLnByb3RvdHlwZTskclt2bl09ITAsJHIuZGVsZXRlPSRyLnJlbW92ZSwkci5kZWxldGVJbj0kci5yZW1vdmVJbj1fZSwkci5nZXRJbj1qdCwkci5oYXNJbj1Jci5oYXNJbiwkci5tZXJnZT1OZSwkci5tZXJnZVdpdGg9SWUsJHIubWVyZ2VJbj1WZSwkci5tZXJnZURlZXA9emUsJHIubWVyZ2VEZWVwV2l0aD1HZSwkci5tZXJnZURlZXBJbj1xZSwkci5zZXRJbj1rZSwkci51cGRhdGU9T2UsJHIudXBkYXRlSW49RmUsJHIud2l0aE11dGF0aW9ucz1IZSwkci5hc011dGFibGU9V2UsJHIuYXNJbW11dGFibGU9UWUsJHJbX25dPSRyLmVudHJpZXMsJHIudG9KU09OPSRyLnRvT2JqZWN0PUlyLnRvT2JqZWN0LCRyLmluc3BlY3Q9JHIudG9Tb3VyY2U9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy50b1N0cmluZygpfTt2YXIgVXIsenI9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlLG4pe2lmKCEodGhpcyBpbnN0YW5jZW9mIHQpKXJldHVybiBuZXcgdChlLG4pO2lmKHRoaXMuX3ZhbHVlPWUsdGhpcy5zaXplPXZvaWQgMD09PW4/MS8wOk1hdGgubWF4KDAsbiksMD09PXRoaXMuc2l6ZSl7aWYoVXIpcmV0dXJuIFVyO1VyPXRoaXN9fXJldHVybiBlJiYodC5fX3Byb3RvX189ZSksdC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlJiZlLnByb3RvdHlwZSksdC5wcm90b3R5cGUuY29uc3RydWN0b3I9dCx0LnByb3RvdHlwZS50b1N0cmluZz1mdW5jdGlvbigpe3JldHVybiAwPT09dGhpcy5zaXplPyJSZXBlYXQgW10iOiJSZXBlYXQgWyAiK3RoaXMuX3ZhbHVlKyIgIit0aGlzLnNpemUrIiB0aW1lcyBdIn0sdC5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuaGFzKGUpP3RoaXMuX3ZhbHVlOnR9LHQucHJvdG90eXBlLmluY2x1ZGVzPWZ1bmN0aW9uKGUpe3JldHVybiBQKHRoaXMuX3ZhbHVlLGUpfSx0LnByb3RvdHlwZS5zbGljZT1mdW5jdGlvbihlLG4pe3ZhciByPXRoaXMuc2l6ZTtyZXR1cm4gYyhlLG4scik/dGhpczpuZXcgdCh0aGlzLl92YWx1ZSxwKG4sciktbChlLHIpKX0sdC5wcm90b3R5cGUucmV2ZXJzZT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx0LnByb3RvdHlwZS5pbmRleE9mPWZ1bmN0aW9uKGUpe3JldHVybiBQKHRoaXMuX3ZhbHVlLGUpPzA6LTF9LHQucHJvdG90eXBlLmxhc3RJbmRleE9mPWZ1bmN0aW9uKGUpe3JldHVybiBQKHRoaXMuX3ZhbHVlLGUpP3RoaXMuc2l6ZTotMX0sdC5wcm90b3R5cGUuX19pdGVyYXRlPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPXRoaXMscj10aGlzLnNpemUsaT0wO2khPT1yJiYhMSE9PWUobi5fdmFsdWUsdD9yLSsraTppKyssbik7KTtyZXR1cm4gaX0sdC5wcm90b3R5cGUuX19pdGVyYXRvcj1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMscj10aGlzLnNpemUsaT0wO3JldHVybiBuZXcgVG4oZnVuY3Rpb24oKXtyZXR1cm4gaT09PXI/RCgpOkUoZSx0P3ItKytpOmkrKyxuLl92YWx1ZSl9KX0sdC5wcm90b3R5cGUuZXF1YWxzPWZ1bmN0aW9uKGUpe3JldHVybiBlIGluc3RhbmNlb2YgdD9QKHRoaXMuX3ZhbHVlLGUuX3ZhbHVlKTpUdChlKX0sdH0oSW4pLEdyPSI0LjAuMC1yYy45IixWcj17dmVyc2lvbjpHcixDb2xsZWN0aW9uOmJuLEl0ZXJhYmxlOmJuLFNlcTpGbixNYXA6bnIsT3JkZXJlZE1hcDpDcixMaXN0Om1yLFN0YWNrOkRyLFNldDpBcixPcmRlcmVkU2V0Ok1yLFJlY29yZDpCcixSYW5nZTpOcixSZXBlYXQ6enIsaXM6UCxmcm9tSlM6b24saGFzaDpqLGlzSW1tdXRhYmxlOmgsaXNDb2xsZWN0aW9uOm0saXNLZXllZDpnLGlzSW5kZXhlZDp5LGlzQXNzb2NpYXRpdmU6dixpc09yZGVyZWQ6Yixpc1ZhbHVlT2JqZWN0OkMsZ2V0OmJlLGdldEluOk10LGhhczp2ZSxoYXNJbjpSdCxtZXJnZTpQZSxtZXJnZURlZXA6amUsbWVyZ2VXaXRoOk1lLG1lcmdlRGVlcFdpdGg6UmUscmVtb3ZlOkNlLHJlbW92ZUluOkFlLHNldDpFZSxzZXRJbjpTZSx1cGRhdGU6VGUsdXBkYXRlSW46RGV9LHFyPWJuO3QuZGVmYXVsdD1Wcn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PXt9O3JldHVybiBudWxsIT09ZSYmT2JqZWN0LmtleXMoZSkuZm9yRWFjaChmdW5jdGlvbihuKXtlW25dLmZvckVhY2goZnVuY3Rpb24oZSl7dFtTdHJpbmcoZSldPW59KX0pLHR9ZnVuY3Rpb24gaShlLHQpe2lmKHQ9dHx8e30sT2JqZWN0LmtleXModCkuZm9yRWFjaChmdW5jdGlvbih0KXtpZigtMT09PWEuaW5kZXhPZih0KSl0aHJvdyBuZXcgbygnVW5rbm93biBvcHRpb24gIicrdCsnIiBpcyBtZXQgaW4gZGVmaW5pdGlvbiBvZiAiJytlKyciIFlBTUwgdHlwZS4nKX0pLHRoaXMudGFnPWUsdGhpcy5raW5kPXQua2luZHx8bnVsbCx0aGlzLnJlc29sdmU9dC5yZXNvbHZlfHxmdW5jdGlvbigpe3JldHVybiEwfSx0aGlzLmNvbnN0cnVjdD10LmNvbnN0cnVjdHx8ZnVuY3Rpb24oZSl7cmV0dXJuIGV9LHRoaXMuaW5zdGFuY2VPZj10Lmluc3RhbmNlT2Z8fG51bGwsdGhpcy5wcmVkaWNhdGU9dC5wcmVkaWNhdGV8fG51bGwsdGhpcy5yZXByZXNlbnQ9dC5yZXByZXNlbnR8fG51bGwsdGhpcy5kZWZhdWx0U3R5bGU9dC5kZWZhdWx0U3R5bGV8fG51bGwsdGhpcy5zdHlsZUFsaWFzZXM9cih0LnN0eWxlQWxpYXNlc3x8bnVsbCksLTE9PT1zLmluZGV4T2YodGhpcy5raW5kKSl0aHJvdyBuZXcgbygnVW5rbm93biBraW5kICInK3RoaXMua2luZCsnIiBpcyBzcGVjaWZpZWQgZm9yICInK2UrJyIgWUFNTCB0eXBlLicpfXZhciBvPW4oNzIpLGE9WyJraW5kIiwicmVzb2x2ZSIsImNvbnN0cnVjdCIsImluc3RhbmNlT2YiLCJwcmVkaWNhdGUiLCJyZXByZXNlbnQiLCJkZWZhdWx0U3R5bGUiLCJzdHlsZUFsaWFzZXMiXSxzPVsic2NhbGFyIiwic2VxdWVuY2UiLCJtYXBwaW5nIl07ZS5leHBvcnRzPWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybiBmdW5jdGlvbihuKXt2YXIgcjtyZXR1cm4gcj17fSxyW2VdPW58fHQscn19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpLG89bigyMyk7dC5lZGl0UXVlcnk9KGk9by5jcmVhdGVBY3Rpb25zKHtFRElUX1FVRVJZOmZ1bmN0aW9uKGUpe3JldHVybntxdWVyeTplfX0sRURJVF9IRUFERVJTOnIoImhlYWRlcnMiKSxFRElUX0VORFBPSU5UOnIoImVuZHBvaW50IiksRURJVF9WQVJJQUJMRVM6cigidmFyaWFibGVzIiksU0VUX09QRVJBVElPTl9OQU1FOnIoIm9wZXJhdGlvbk5hbWUiKSxTRVRfVkFSSUFCTEVfVE9fVFlQRTpyKCJ2YXJpYWJsZVRvVHlwZSIpLFNFVF9PUEVSQVRJT05TOnIoIm9wZXJhdGlvbnMiKSxTRVRfRURJVE9SX0ZMRVg6cigiZWRpdG9yRmxleCIpLEVESVRfTkFNRTpyKCJuYW1lIiksT1BFTl9RVUVSWV9WQVJJQUJMRVM6ZnVuY3Rpb24oKXtyZXR1cm57cXVlcnlWYXJpYWJsZXNBY3RpdmU6ITB9fSxDTE9TRV9RVUVSWV9WQVJJQUJMRVM6ZnVuY3Rpb24oKXtyZXR1cm57cXVlcnlWYXJpYWJsZXNBY3RpdmU6ITF9fSxTRVRfVkFSSUFCTEVfRURJVE9SX0hFSUdIVDpyKCJ2YXJpYWJsZUVkaXRvckhlaWdodCIpLFNFVF9SRVNQT05TRV9UUkFDSU5HX0hFSUdIVDpyKCJyZXNwb25jZVRyYWNpbmdIZWlnaHQiKSxTRVRfVFJBQ0lOR19TVVBQT1JURUQ6cigidHJhY2luZ1N1cHBvcnRlZCIpLFNFVF9TVUJTQ1JJUFRJT05fQUNUSVZFOnIoInN1YnNjcmlwdGlvbkFjdGl2ZSIpLFNFVF9RVUVSWV9UWVBFUzpyKCJxdWVyeVR5cGVzIiksU0VUX1JFU1BPTlNFX0VYVEVOU0lPTlM6cigicmVzcG9uc2VFeHRlbnNpb25zIiksU0VUX0NVUlJFTlRfUVVFUllfU1RBUlRfVElNRTpyKCJjdXJyZW50UXVlcnlTdGFydFRpbWUiKSxTRVRfQ1VSUkVOVF9RVUVSWV9FTkRfVElNRTpyKCJjdXJyZW50UXVlcnlFbmRUaW1lIiksVVBEQVRFX1FVRVJZX0ZBQ1RTOnIoKSxQUkVUVElGWV9RVUVSWTpyKCksSU5KRUNUX0hFQURFUlM6ZnVuY3Rpb24oZSx0KXtyZXR1cm57aGVhZGVyczplLGVuZHBvaW50OnR9fSxDTE9TRV9UUkFDSU5HOnIoInJlc3BvbnNlVHJhY2luZ0hlaWdodCIpLE9QRU5fVFJBQ0lORzpyKCJyZXNwb25zZVRyYWNpbmdIZWlnaHQiKSxUT0dHTEVfVFJBQ0lORzpyKCksQ0xPU0VfVkFSSUFCTEVTOnIoInZhcmlhYmxlRWRpdG9ySGVpZ2h0IiksT1BFTl9WQVJJQUJMRVM6cigidmFyaWFibGVFZGl0b3JIZWlnaHQiKSxUT0dHTEVfVkFSSUFCTEVTOnIoKSxBRERfUkVTUE9OU0U6ZnVuY3Rpb24oZSx0LG4pe3JldHVybnt3b3Jrc3BhY2VJZDplLHNlc3Npb25JZDp0LHJlc3BvbnNlOm59fSxTRVRfUkVTUE9OU0U6ZnVuY3Rpb24oZSx0LG4pe3JldHVybnt3b3Jrc3BhY2VJZDplLHNlc3Npb25JZDp0LHJlc3BvbnNlOm59fSxDTEVBUl9SRVNQT05TRVM6cigpLEZFVENIX1NDSEVNQTpyKCksUkVGRVRDSF9TQ0hFTUE6cigpLFNFVF9FTkRQT0lOVF9VTlJFQUNIQUJMRTpyKCJlbmRwb2ludCIpLFNFVF9TQ1JPTExfVE9QOmZ1bmN0aW9uKGUsdCl7cmV0dXJue3Nlc3Npb25JZDplLHNjcm9sbFRvcDp0fX0sU0NIRU1BX0ZFVENISU5HX1NVQ0NFU1M6ZnVuY3Rpb24oZSx0LG4pe3JldHVybntlbmRwb2ludDplLHRyYWNpbmdTdXBwb3J0ZWQ6dCxpc1BvbGxpbmdTY2hlbWE6bn19LFNDSEVNQV9GRVRDSElOR19FUlJPUjpmdW5jdGlvbihlLHQpe3JldHVybntlbmRwb2ludDplLGVycm9yOnR9fSxSRU5FV19TVEFDS1M6cigpLFJVTl9RVUVSWTpmdW5jdGlvbihlKXtyZXR1cm57b3BlcmF0aW9uTmFtZTplfX0sUVVFUllfU1VDQ0VTUzpyKCksUVVFUllfRVJST1I6cigpLFJVTl9RVUVSWV9BVF9QT1NJVElPTjpmdW5jdGlvbihlKXtyZXR1cm57cG9zaXRpb246ZX19LFNUQVJUX1FVRVJZOnIoInF1ZXJ5UnVubmluZyIsITApLFNUT1BfUVVFUlk6ZnVuY3Rpb24oZSx0KXtyZXR1cm57d29ya3NwYWNlSWQ6dCxzZXNzaW9uSWQ6ZX19LE9QRU5fU0VUVElOR1NfVEFCOmZ1bmN0aW9uKCl7cmV0dXJue319LE9QRU5fQ09ORklHX1RBQjpmdW5jdGlvbigpe3JldHVybnt9fSxORVdfU0VTU0lPTjpmdW5jdGlvbihlLHQpe3JldHVybntlbmRwb2ludDplLHJldXNlSGVhZGVyczp0fX0sTkVXX1NFU1NJT05fRlJPTV9RVUVSWTpmdW5jdGlvbihlKXtyZXR1cm57cXVlcnk6ZX19LE5FV19GSUxFX1RBQjpmdW5jdGlvbihlLHQsbil7cmV0dXJue2ZpbGVOYW1lOmUsZmlsZVBhdGg6dCxmaWxlOm59fSxEVVBMSUNBVEVfU0VTU0lPTjpyKCJzZXNzaW9uIiksQ0xPU0VfU0VMRUNURURfVEFCOmZ1bmN0aW9uKCl7cmV0dXJue319LFNFTEVDVF9ORVhUX1RBQjpmdW5jdGlvbigpe3JldHVybnt9fSxTRUxFQ1RfUFJFVl9UQUI6ZnVuY3Rpb24oKXtyZXR1cm57fX0sU0VMRUNUX1RBQjpyKCJzZXNzaW9uSWQiKSxTRUxFQ1RfVEFCX0lOREVYOnIoImluZGV4IiksQ0xPU0VfVEFCOnIoInNlc3Npb25JZCIpLFJFT1JERVJfVEFCUzpmdW5jdGlvbihlLHQpe3JldHVybntzcmM6ZSxkZXN0OnR9fSxFRElUX1NFVFRJTkdTOnIoKSxTQVZFX1NFVFRJTkdTOnIoKSxFRElUX0NPTkZJRzpyKCksU0FWRV9DT05GSUc6cigpLEVESVRfRklMRTpyKCksU0FWRV9GSUxFOnIoKX0pLGkuZWRpdFF1ZXJ5KSx0LmVkaXRWYXJpYWJsZXM9aS5lZGl0VmFyaWFibGVzLHQuc2V0T3BlcmF0aW9uTmFtZT1pLnNldE9wZXJhdGlvbk5hbWUsdC5lZGl0SGVhZGVycz1pLmVkaXRIZWFkZXJzLHQuZWRpdEVuZHBvaW50PWkuZWRpdEVuZHBvaW50LHQuc2V0VmFyaWFibGVUb1R5cGU9aS5zZXRWYXJpYWJsZVRvVHlwZSx0LnNldE9wZXJhdGlvbnM9aS5zZXRPcGVyYXRpb25zLHQuc3RhcnRRdWVyeT1pLnN0YXJ0UXVlcnksdC5zdG9wUXVlcnk9aS5zdG9wUXVlcnksdC5zZXRFZGl0b3JGbGV4PWkuc2V0RWRpdG9yRmxleCx0Lm9wZW5RdWVyeVZhcmlhYmxlcz1pLm9wZW5RdWVyeVZhcmlhYmxlcyx0LmNsb3NlUXVlcnlWYXJpYWJsZXM9aS5jbG9zZVF1ZXJ5VmFyaWFibGVzLHQuc2V0VmFyaWFibGVFZGl0b3JIZWlnaHQ9aS5zZXRWYXJpYWJsZUVkaXRvckhlaWdodCx0LnNldFJlc3BvbnNlVHJhY2luZ0hlaWdodD1pLnNldFJlc3BvbnNlVHJhY2luZ0hlaWdodCx0LnNldFRyYWNpbmdTdXBwb3J0ZWQ9aS5zZXRUcmFjaW5nU3VwcG9ydGVkLHQuY2xvc2VUcmFjaW5nPWkuY2xvc2VUcmFjaW5nLHQub3BlblRyYWNpbmc9aS5vcGVuVHJhY2luZyx0LmNsb3NlVmFyaWFibGVzPWkuY2xvc2VWYXJpYWJsZXMsdC5vcGVuVmFyaWFibGVzPWkub3BlblZhcmlhYmxlcyx0LmFkZFJlc3BvbnNlPWkuYWRkUmVzcG9uc2UsdC5zZXRSZXNwb25zZT1pLnNldFJlc3BvbnNlLHQuY2xlYXJSZXNwb25zZXM9aS5jbGVhclJlc3BvbnNlcyx0Lm9wZW5TZXR0aW5nc1RhYj1pLm9wZW5TZXR0aW5nc1RhYix0LnNjaGVtYUZldGNoaW5nU3VjY2Vzcz1pLnNjaGVtYUZldGNoaW5nU3VjY2Vzcyx0LnNjaGVtYUZldGNoaW5nRXJyb3I9aS5zY2hlbWFGZXRjaGluZ0Vycm9yLHQuc2V0RW5kcG9pbnRVbnJlYWNoYWJsZT1pLnNldEVuZHBvaW50VW5yZWFjaGFibGUsdC5yZW5ld1N0YWNrcz1pLnJlbmV3U3RhY2tzLHQucnVuUXVlcnk9aS5ydW5RdWVyeSx0LnByZXR0aWZ5UXVlcnk9aS5wcmV0dGlmeVF1ZXJ5LHQuZmV0Y2hTY2hlbWE9aS5mZXRjaFNjaGVtYSx0LnVwZGF0ZVF1ZXJ5RmFjdHM9aS51cGRhdGVRdWVyeUZhY3RzLHQucnVuUXVlcnlBdFBvc2l0aW9uPWkucnVuUXVlcnlBdFBvc2l0aW9uLHQudG9nZ2xlVHJhY2luZz1pLnRvZ2dsZVRyYWNpbmcsdC50b2dnbGVWYXJpYWJsZXM9aS50b2dnbGVWYXJpYWJsZXMsdC5uZXdTZXNzaW9uPWkubmV3U2Vzc2lvbix0Lm5ld1Nlc3Npb25Gcm9tUXVlcnk9aS5uZXdTZXNzaW9uRnJvbVF1ZXJ5LHQubmV3RmlsZVRhYj1pLm5ld0ZpbGVUYWIsdC5jbG9zZVRhYj1pLmNsb3NlVGFiLHQuY2xvc2VTZWxlY3RlZFRhYj1pLmNsb3NlU2VsZWN0ZWRUYWIsdC5lZGl0U2V0dGluZ3M9aS5lZGl0U2V0dGluZ3MsdC5zYXZlU2V0dGluZ3M9aS5zYXZlU2V0dGluZ3MsdC5lZGl0Q29uZmlnPWkuZWRpdENvbmZpZyx0LnNhdmVDb25maWc9aS5zYXZlQ29uZmlnLHQuZWRpdEZpbGU9aS5lZGl0RmlsZSx0LnNhdmVGaWxlPWkuc2F2ZUZpbGUsdC5zZWxlY3RUYWI9aS5zZWxlY3RUYWIsdC5zZWxlY3RUYWJJbmRleD1pLnNlbGVjdFRhYkluZGV4LHQuc2VsZWN0TmV4dFRhYj1pLnNlbGVjdE5leHRUYWIsdC5zZWxlY3RQcmV2VGFiPWkuc2VsZWN0UHJldlRhYix0LmR1cGxpY2F0ZVNlc3Npb249aS5kdXBsaWNhdGVTZXNzaW9uLHQucXVlcnlTdWNjZXNzPWkucXVlcnlTdWNjZXNzLHQucXVlcnlFcnJvcj1pLnF1ZXJ5RXJyb3IsdC5zZXRTdWJzY3JpcHRpb25BY3RpdmU9aS5zZXRTdWJzY3JpcHRpb25BY3RpdmUsdC5zZXRRdWVyeVR5cGVzPWkuc2V0UXVlcnlUeXBlcyx0LmluamVjdEhlYWRlcnM9aS5pbmplY3RIZWFkZXJzLHQub3BlbkNvbmZpZ1RhYj1pLm9wZW5Db25maWdUYWIsdC5lZGl0TmFtZT1pLmVkaXROYW1lLHQuc2V0UmVzcG9uc2VFeHRlbnNpb25zPWkuc2V0UmVzcG9uc2VFeHRlbnNpb25zLHQuc2V0Q3VycmVudFF1ZXJ5U3RhcnRUaW1lPWkuc2V0Q3VycmVudFF1ZXJ5U3RhcnRUaW1lLHQuc2V0Q3VycmVudFF1ZXJ5RW5kVGltZT1pLnNldEN1cnJlbnRRdWVyeUVuZFRpbWUsdC5yZWZldGNoU2NoZW1hPWkucmVmZXRjaFNjaGVtYSx0LnNldFNjcm9sbFRvcD1pLnNldFNjcm9sbFRvcCx0LnJlb3JkZXJUYWJzPWkucmVvcmRlclRhYnN9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZS5nZXQoInNlbGVjdGVkV29ya3NwYWNlIil9ZnVuY3Rpb24gaShlKXtyZXR1cm4gZS5nZXRJbihbIndvcmtzcGFjZXMiLHIoZSldKX1mdW5jdGlvbiBvKGUpe3ZhciB0PWVbMF0uZW5kcG9pbnQsbj15Lk9yZGVyZWRNYXAoZS5tYXAoaC5zZXNzaW9uRnJvbVRhYikucmVkdWNlKGZ1bmN0aW9uKGUsdCl7dmFyIG47cmV0dXJuIHAoe30sZSwobj17fSxuW3QuaWRdPXQsbikpfSx7fSkpLHI9bi5maXJzdCgpLmlkLGk9YSh0KS5zZXRJbihbInNlc3Npb25zIiwic2Vzc2lvbnMiXSxuKS5zZXRJbihbInNlc3Npb25zIiwic2VsZWN0ZWRTZXNzaW9uSWQiXSxyKTtyZXR1cm4obmV3IHcpLnNldEluKFsid29ya3NwYWNlcyIsdF0saSkuc2V0KCJzZWxlY3RlZFdvcmtzcGFjZSIsdCl9ZnVuY3Rpb24gYShlKXt2YXIgdCxuPWgubWFrZVNlc3Npb25TdGF0ZShlKTtyZXR1cm4gbmV3IEQoe2RvY3M6eS5NYXAoKHQ9e30sdFtuLnNlbGVjdGVkU2Vzc2lvbklkXT1uZXcgZC5Eb2NzU2Vzc2lvbix0KSksc2Vzc2lvbnM6bixzaGFyaW5nOm5ldyBtLlNoYXJpbmdTdGF0ZSxoaXN0b3J5OnkuT3JkZXJlZE1hcCgpfSl9ZnVuY3Rpb24gcyhlKXt2YXIgbj1lWyJlZGl0b3IudGhlbWUiXTtyZXR1cm4iZGFyayIhPT1uJiYibGlnaHQiIT09biYmKGVbImVkaXRvci50aGVtZSJdPSJkYXJrIikscCh7fSx0LmRlZmF1bHRTZXR0aW5ncyxlKX1mdW5jdGlvbiB1KGUpe3RyeXtyZXR1cm4gcyhKU09OLnBhcnNlKGUpKX1jYXRjaChlKXtyZXR1cm4gdC5kZWZhdWx0U2V0dGluZ3N9fWZ1bmN0aW9uIGMoZSl7cmV0dXJuIEpTT04uc3RyaW5naWZ5KHUoZSksbnVsbCwyKX12YXIgbD1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLHA9ZnVuY3Rpb24oKXtyZXR1cm4gcD1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQsbj0xLHI9YXJndW1lbnRzLmxlbmd0aDtuPHI7bisrKXt0PWFyZ3VtZW50c1tuXTtmb3IodmFyIGkgaW4gdClPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxpKSYmKGVbaV09dFtpXSl9cmV0dXJuIGV9LHAuYXBwbHkodGhpcyxhcmd1bWVudHMpfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGY9big0ODgpLGQ9bigxMzApLGg9big4NSksbT1uKDI0OCksZz1uKDQ5OSkseT1uKDE0KSx2PW4oMjQ5KSxiPW4oNTAwKSx4PW4oOCksQz1uKDI1MCksRT1uKDI1MSk7dC5nZXRTZWxlY3RlZFdvcmtzcGFjZUlkPXIsdC5nZXRTZWxlY3RlZFdvcmtzcGFjZT1pO3ZhciBEPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gbnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzfXJldHVybiBsKHQsZSksdH0oeS5SZWNvcmQoe2RvY3M6eS5NYXAoe30pLHNlc3Npb25zOmgubWFrZVNlc3Npb25TdGF0ZSgiIiksc2hhcmluZzpuZXcgbS5TaGFyaW5nU3RhdGUsaGlzdG9yeTp5Lk9yZGVyZWRNYXAoKX0pKTt0LldvcmtzcGFjZT1ELHQuZGVmYXVsdFNldHRpbmdzPXsiZWRpdG9yLmN1cnNvclNoYXBlIjoibGluZSIsImVkaXRvci5mb250RmFtaWx5IjoiJ1NvdXJjZSBDb2RlIFBybycsICdDb25zb2xhcycsICdJbmNvbnNvbGF0YScsICdEcm9pZCBTYW5zIE1vbm8nLCAnTW9uYWNvJywgbW9ub3NwYWNlIiwiZWRpdG9yLmZvbnRTaXplIjoxNCwiZWRpdG9yLnJldXNlSGVhZGVycyI6ITAsImVkaXRvci50aGVtZSI6ImRhcmsiLCJnZW5lcmFsLmJldGFVcGRhdGVzIjohMSwicHJldHRpZXIucHJpbnRXaWR0aCI6ODAsInByZXR0aWVyLnRhYldpZHRoIjoyLCJwcmV0dGllci51c2VUYWJzIjohMSwicmVxdWVzdC5jcmVkZW50aWFscyI6Im9taXQiLCJzY2hlbWEuZGlzYWJsZUNvbW1lbnRzIjohMCwic2NoZW1hLnBvbGxpbmcuZW5hYmxlIjohMCwic2NoZW1hLnBvbGxpbmcuZW5kcG9pbnRGaWx0ZXIiOiIqbG9jYWxob3N0KiIsInNjaGVtYS5wb2xsaW5nLmludGVydmFsIjoyZTMsInRyYWNpbmcuaGlkZVRyYWNpbmdSZXNwb25zZSI6ITB9O3ZhciB3PWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gbnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzfXJldHVybiBsKHQsZSksdH0oeS5SZWNvcmQoe3dvcmtzcGFjZXM6eS5NYXAoeyIiOmEoIiIpfSksc2VsZWN0ZWRXb3Jrc3BhY2U6IiIsc2V0dGluZ3NTdHJpbmc6SlNPTi5zdHJpbmdpZnkodC5kZWZhdWx0U2V0dGluZ3MsbnVsbCwyKSxzdGF0ZUluamVjdGVkOiExLGFwcEhpc3Rvcnk6bmV3IEUuQXBwSGlzdG9yeSxnZW5lcmFsOm5ldyB2LkdlbmVyYWxTdGF0ZX0pKTt0LlJvb3RTdGF0ZT13O3ZhciBTPWYuY29tYmluZVJlZHVjZXJzKHtkb2NzOmQuZGVmYXVsdCxzZXNzaW9uczpoLmRlZmF1bHQsc2hhcmluZzptLmRlZmF1bHQsaGlzdG9yeTpnLmRlZmF1bHQsZ2VuZXJhbDp2LmRlZmF1bHQsYXBwSGlzdG9yeTpFLmRlZmF1bHR9KTt0LnJvb3RSZWR1Y2VyPWZ1bmN0aW9uKGUsdCl7aWYodm9pZCAwPT09ZSYmKGU9bmV3IHcpLCJTRUxFQ1RfV09SS1NQQUNFIj09PXQudHlwZSlyZXR1cm4gZS5zZXQoInNlbGVjdGVkV29ya3NwYWNlIix0LnBheWxvYWQud29ya3NwYWNlKTtpZigiU0VUX1NFVFRJTkdTX1NUUklORyI9PT10LnR5cGUpcmV0dXJuIGUuc2V0KCJzZXR0aW5nc1N0cmluZyIsdC5wYXlsb2FkLnNldHRpbmdzU3RyaW5nKTtpZigiSU5JVF9TVEFURSI9PT10LnR5cGUmJiFlLnN0YXRlSW5qZWN0ZWQpe3ZhciBuPXQucGF5bG9hZCxpPW4ud29ya3NwYWNlSWQscz1uLmVuZHBvaW50O2lmKCFlLndvcmtzcGFjZXMuZ2V0KGkpKXtyZXR1cm4gZS5zZXRJbihbIndvcmtzcGFjZXMiLGldLGEocykpLnNldCgic2VsZWN0ZWRXb3Jrc3BhY2UiLGkpfXJldHVybiBlLnNldCgic2VsZWN0ZWRXb3Jrc3BhY2UiLGkpfWlmKCJJTkpFQ1RfU1RBVEUiPT09dC50eXBlKXJldHVybiBDLmRlc2VyaWFsaXplUGVyc2lzdGVkU3RhdGUodC5wYXlsb2FkLnN0YXRlKS5zZXQoInN0YXRlSW5qZWN0ZWQiLCEwKTtpZigiSU5KRUNUX1RBQlMiPT09dC50eXBlKXJldHVybiBvKHQucGF5bG9hZC50YWJzKTtpZigiU0VMRUNUX0FQUF9ISVNUT1JZX0lURU0iPT09dC50eXBlKXJldHVybiBlLnNldCgiYXBwSGlzdG9yeSIsRS5kZWZhdWx0KGUuYXBwSGlzdG9yeSx0KSk7aWYoe09QRU5fSElTVE9SWTohMCxDTE9TRV9ISVNUT1JZOiEwLFNFVF9FTkRQT0lOVF9ESVNBQkxFRDohMCxTRVRfQ09ORklHX1NUUklORzohMH1bdC50eXBlXSlyZXR1cm4gZS5zZXQoImdlbmVyYWwiLHYuZGVmYXVsdChlLmdlbmVyYWwsdCkpO3ZhciB1PXQucGF5bG9hZCYmdC5wYXlsb2FkLndvcmtzcGFjZUlkP3QucGF5bG9hZC53b3Jrc3BhY2VJZDpyKGUpLGM9WyJ3b3Jrc3BhY2VzIix1XTtyZXR1cm4gZS5zZXRJbihjLFMoZS5nZXRJbihjKSx0KSl9LHQubWFrZVdvcmtzcGFjZT1hLHQuZGVmYXVsdD10LnJvb3RSZWR1Y2VyLHQuZ2V0U2Vzc2lvbkNvdW50cz1iLmltbXV0YWJsZU1lbW9pemUoZnVuY3Rpb24oZSl7cmV0dXJuIGUud29ya3NwYWNlcy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUuc2Vzc2lvbnMuc2Vzc2lvbkNvdW50fSl9KSx0LmdldFNldHRpbmdzU3RyaW5nPWZ1bmN0aW9uKGUpe3JldHVybiBlLnNldHRpbmdzU3RyaW5nfSx0LmdldFNldHRpbmdzPXguY3JlYXRlU2VsZWN0b3IoW3QuZ2V0U2V0dGluZ3NTdHJpbmddLHUpLHQubm9ybWFsaXplU2V0dGluZ3NTdHJpbmc9Yyx0LmdldFRoZW1lPWZ1bmN0aW9uKGUsbil7cmV0dXJuKG58fHQuZ2V0U2V0dGluZ3MoZSkpWyJlZGl0b3IudGhlbWUiXXx8ImRhcmsifX0sZnVuY3Rpb24oZSx0LG4pe2UuZXhwb3J0cz1uKDMyMSkoKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybigwLHUudmlzaXQpKGUse2xlYXZlOmN9KX1mdW5jdGlvbiBpKGUsdCl7cmV0dXJuIGU/ZS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIGV9KS5qb2luKHR8fCIiKToiIn1mdW5jdGlvbiBvKGUpe3JldHVybiBlJiYwIT09ZS5sZW5ndGg/cygie1xuIitpKGUsIlxuIikpKyJcbn0iOiJ7fSJ9ZnVuY3Rpb24gYShlLHQsbil7cmV0dXJuIHQ/ZSt0KyhufHwiIik6IiJ9ZnVuY3Rpb24gcyhlKXtyZXR1cm4gZSYmZS5yZXBsYWNlKC9cbi9nLCJcbiAgIil9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQucHJpbnQ9cjt2YXIgdT1uKDU3KSxjPXtOYW1lOmZ1bmN0aW9uKGUpe3JldHVybiBlLnZhbHVlfSxWYXJpYWJsZTpmdW5jdGlvbihlKXtyZXR1cm4iJCIrZS5uYW1lfSxEb2N1bWVudDpmdW5jdGlvbihlKXtyZXR1cm4gaShlLmRlZmluaXRpb25zLCJcblxuIikrIlxuIn0sT3BlcmF0aW9uRGVmaW5pdGlvbjpmdW5jdGlvbihlKXt2YXIgdD1lLm9wZXJhdGlvbixuPWUubmFtZSxyPWEoIigiLGkoZS52YXJpYWJsZURlZmluaXRpb25zLCIsICIpLCIpIiksbz1pKGUuZGlyZWN0aXZlcywiICIpLHM9ZS5zZWxlY3Rpb25TZXQ7cmV0dXJuIG58fG98fHJ8fCJxdWVyeSIhPT10P2koW3QsaShbbixyXSksbyxzXSwiICIpOnN9LFZhcmlhYmxlRGVmaW5pdGlvbjpmdW5jdGlvbihlKXtyZXR1cm4gZS52YXJpYWJsZSsiOiAiK2UudHlwZSthKCIgPSAiLGUuZGVmYXVsdFZhbHVlKX0sU2VsZWN0aW9uU2V0OmZ1bmN0aW9uKGUpe3JldHVybiBvKGUuc2VsZWN0aW9ucyl9LEZpZWxkOmZ1bmN0aW9uKGUpe3ZhciB0PWUuYWxpYXMsbj1lLm5hbWUscj1lLmFyZ3VtZW50cyxvPWUuZGlyZWN0aXZlcyxzPWUuc2VsZWN0aW9uU2V0O3JldHVybiBpKFthKCIiLHQsIjogIikrbithKCIoIixpKHIsIiwgIiksIikiKSxpKG8sIiAiKSxzXSwiICIpfSxBcmd1bWVudDpmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lKyI6ICIrZS52YWx1ZX0sRnJhZ21lbnRTcHJlYWQ6ZnVuY3Rpb24oZSl7cmV0dXJuIi4uLiIrZS5uYW1lK2EoIiAiLGkoZS5kaXJlY3RpdmVzLCIgIikpfSxJbmxpbmVGcmFnbWVudDpmdW5jdGlvbihlKXt2YXIgdD1lLnR5cGVDb25kaXRpb24sbj1lLmRpcmVjdGl2ZXMscj1lLnNlbGVjdGlvblNldDtyZXR1cm4gaShbIi4uLiIsYSgib24gIix0KSxpKG4sIiAiKSxyXSwiICIpfSxGcmFnbWVudERlZmluaXRpb246ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5uYW1lLG49ZS50eXBlQ29uZGl0aW9uLHI9ZS5kaXJlY3RpdmVzLG89ZS5zZWxlY3Rpb25TZXQ7cmV0dXJuImZyYWdtZW50ICIrdCsiIG9uICIrbisiICIrYSgiIixpKHIsIiAiKSwiICIpK299LEludFZhbHVlOmZ1bmN0aW9uKGUpe3JldHVybiBlLnZhbHVlfSxGbG9hdFZhbHVlOmZ1bmN0aW9uKGUpe3JldHVybiBlLnZhbHVlfSxTdHJpbmdWYWx1ZTpmdW5jdGlvbihlKXt2YXIgdD1lLnZhbHVlO3JldHVybiBKU09OLnN0cmluZ2lmeSh0KX0sQm9vbGVhblZhbHVlOmZ1bmN0aW9uKGUpe3ZhciB0PWUudmFsdWU7cmV0dXJuIEpTT04uc3RyaW5naWZ5KHQpfSxOdWxsVmFsdWU6ZnVuY3Rpb24oKXtyZXR1cm4ibnVsbCJ9LEVudW1WYWx1ZTpmdW5jdGlvbihlKXtyZXR1cm4gZS52YWx1ZX0sTGlzdFZhbHVlOmZ1bmN0aW9uKGUpe3JldHVybiJbIitpKGUudmFsdWVzLCIsICIpKyJdIn0sT2JqZWN0VmFsdWU6ZnVuY3Rpb24oZSl7cmV0dXJuInsiK2koZS5maWVsZHMsIiwgIikrIn0ifSxPYmplY3RGaWVsZDpmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lKyI6ICIrZS52YWx1ZX0sRGlyZWN0aXZlOmZ1bmN0aW9uKGUpe3JldHVybiJAIitlLm5hbWUrYSgiKCIsaShlLmFyZ3VtZW50cywiLCAiKSwiKSIpfSxOYW1lZFR5cGU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZX0sTGlzdFR5cGU6ZnVuY3Rpb24oZSl7cmV0dXJuIlsiK2UudHlwZSsiXSJ9LE5vbk51bGxUeXBlOmZ1bmN0aW9uKGUpe3JldHVybiBlLnR5cGUrIiEifSxTY2hlbWFEZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3ZhciB0PWUuZGlyZWN0aXZlcyxuPWUub3BlcmF0aW9uVHlwZXM7cmV0dXJuIGkoWyJzY2hlbWEiLGkodCwiICIpLG8obildLCIgIil9LE9wZXJhdGlvblR5cGVEZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiBlLm9wZXJhdGlvbisiOiAiK2UudHlwZX0sU2NhbGFyVHlwZURlZmluaXRpb246ZnVuY3Rpb24oZSl7cmV0dXJuIGkoWyJzY2FsYXIiLGUubmFtZSxpKGUuZGlyZWN0aXZlcywiICIpXSwiICIpfSxPYmplY3RUeXBlRGVmaW5pdGlvbjpmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLmludGVyZmFjZXMscj1lLmRpcmVjdGl2ZXMscz1lLmZpZWxkcztyZXR1cm4gaShbInR5cGUiLHQsYSgiaW1wbGVtZW50cyAiLGkobiwiLCAiKSksaShyLCIgIiksbyhzKV0sIiAiKX0sRmllbGREZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3ZhciB0PWUubmFtZSxuPWUuYXJndW1lbnRzLHI9ZS50eXBlLG89ZS5kaXJlY3RpdmVzO3JldHVybiB0K2EoIigiLGkobiwiLCAiKSwiKSIpKyI6ICIrcithKCIgIixpKG8sIiAiKSl9LElucHV0VmFsdWVEZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3ZhciB0PWUubmFtZSxuPWUudHlwZSxyPWUuZGVmYXVsdFZhbHVlLG89ZS5kaXJlY3RpdmVzO3JldHVybiBpKFt0KyI6ICIrbixhKCI9ICIsciksaShvLCIgIildLCIgIil9LEludGVyZmFjZVR5cGVEZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3ZhciB0PWUubmFtZSxuPWUuZGlyZWN0aXZlcyxyPWUuZmllbGRzO3JldHVybiBpKFsiaW50ZXJmYWNlIix0LGkobiwiICIpLG8ocildLCIgIil9LFVuaW9uVHlwZURlZmluaXRpb246ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5uYW1lLG49ZS5kaXJlY3RpdmVzLHI9ZS50eXBlcztyZXR1cm4gaShbInVuaW9uIix0LGkobiwiICIpLCI9ICIraShyLCIgfCAiKV0sIiAiKX0sRW51bVR5cGVEZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3ZhciB0PWUubmFtZSxuPWUuZGlyZWN0aXZlcyxyPWUudmFsdWVzO3JldHVybiBpKFsiZW51bSIsdCxpKG4sIiAiKSxvKHIpXSwiICIpfSxFbnVtVmFsdWVEZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiBpKFtlLm5hbWUsaShlLmRpcmVjdGl2ZXMsIiAiKV0sIiAiKX0sSW5wdXRPYmplY3RUeXBlRGVmaW5pdGlvbjpmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLmRpcmVjdGl2ZXMscj1lLmZpZWxkcztyZXR1cm4gaShbImlucHV0Iix0LGkobiwiICIpLG8ocildLCIgIil9LFR5cGVFeHRlbnNpb25EZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiJleHRlbmQgIitlLmRlZmluaXRpb259LERpcmVjdGl2ZURlZmluaXRpb246ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5uYW1lLG49ZS5hcmd1bWVudHMscj1lLmxvY2F0aW9ucztyZXR1cm4iZGlyZWN0aXZlIEAiK3QrYSgiKCIsaShuLCIsICIpLCIpIikrIiBvbiAiK2kociwiIHwgIil9fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbihlLHQsbixyLGksbyxhLHMpe2lmKCFlKXt2YXIgdTtpZih2b2lkIDA9PT10KXU9bmV3IEVycm9yKCJNaW5pZmllZCBleGNlcHRpb24gb2NjdXJyZWQ7IHVzZSB0aGUgbm9uLW1pbmlmaWVkIGRldiBlbnZpcm9ubWVudCBmb3IgdGhlIGZ1bGwgZXJyb3IgbWVzc2FnZSBhbmQgYWRkaXRpb25hbCBoZWxwZnVsIHdhcm5pbmdzLiIpO2Vsc2V7dmFyIGM9W24scixpLG8sYSxzXSxsPTA7dT1uZXcgRXJyb3IodC5yZXBsYWNlKC8lcy9nLGZ1bmN0aW9uKCl7cmV0dXJuIGNbbCsrXX0pKSx1Lm5hbWU9IkludmFyaWFudCBWaW9sYXRpb24ifXRocm93IHUuZnJhbWVzVG9Qb3A9MSx1fX07ZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9bigxNjQpLGk9Im9iamVjdCI9PXR5cGVvZiBzZWxmJiZzZWxmJiZzZWxmLk9iamVjdD09PU9iamVjdCYmc2VsZixvPXIuYXx8aXx8RnVuY3Rpb24oInJldHVybiB0aGlzIikoKTt0LmE9b30sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXtpZighdChlKSl0aHJvdyBwKCJlcnJvciIsInVuY2F1Z2h0IGF0IGNoZWNrIixuKSxuZXcgRXJyb3Iobil9ZnVuY3Rpb24gaShlLHQpe3JldHVybiBBLm5vdFVuZGVmKGUpJiZrLmNhbGwoZSx0KX1mdW5jdGlvbiBvKGUsdCl7dmFyIG49ZS5pbmRleE9mKHQpO24+PTAmJmUuc3BsaWNlKG4sMSl9ZnVuY3Rpb24gYSgpe3ZhciBlPWFyZ3VtZW50cy5sZW5ndGg+MCYmdm9pZCAwIT09YXJndW1lbnRzWzBdP2FyZ3VtZW50c1swXTp7fSx0PWQoe30sZSksbj1uZXcgUHJvbWlzZShmdW5jdGlvbihlLG4pe3QucmVzb2x2ZT1lLHQucmVqZWN0PW59KTtyZXR1cm4gdC5wcm9taXNlPW4sdH1mdW5jdGlvbiBzKGUpe2Zvcih2YXIgdD1bXSxuPTA7bjxlO24rKyl0LnB1c2goYSgpKTtyZXR1cm4gdH1mdW5jdGlvbiB1KGUpe3ZhciB0PSEoYXJndW1lbnRzLmxlbmd0aD4xJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0pfHxhcmd1bWVudHNbMV0sbj12b2lkIDAscj1uZXcgUHJvbWlzZShmdW5jdGlvbihyKXtuPXNldFRpbWVvdXQoZnVuY3Rpb24oKXtyZXR1cm4gcih0KX0sZSl9KTtyZXR1cm4gcltiXT1mdW5jdGlvbigpe3JldHVybiBjbGVhclRpbWVvdXQobil9LHJ9ZnVuY3Rpb24gYygpe3ZhciBlLHQ9ITAsbj12b2lkIDAscj12b2lkIDA7cmV0dXJuIGU9e30sZVtnXT0hMCxlLmlzUnVubmluZz1mdW5jdGlvbigpe3JldHVybiB0fSxlLnJlc3VsdD1mdW5jdGlvbigpe3JldHVybiBufSxlLmVycm9yPWZ1bmN0aW9uKCl7cmV0dXJuIHJ9LGUuc2V0UnVubmluZz1mdW5jdGlvbihlKXtyZXR1cm4gdD1lfSxlLnNldFJlc3VsdD1mdW5jdGlvbihlKXtyZXR1cm4gbj1lfSxlLnNldEVycm9yPWZ1bmN0aW9uKGUpe3JldHVybiByPWV9LGV9ZnVuY3Rpb24gbChlKXt2YXIgdD1hcmd1bWVudHMubGVuZ3RoPjEmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXT9hcmd1bWVudHNbMV06RixuPWFyZ3VtZW50cy5sZW5ndGg+MiYmdm9pZCAwIT09YXJndW1lbnRzWzJdP2FyZ3VtZW50c1syXToiIixyPWFyZ3VtZW50c1szXSxpPXtuYW1lOm4sbmV4dDplLHRocm93OnQscmV0dXJuOk59O3JldHVybiByJiYoaVt5XT0hMCksInVuZGVmaW5lZCIhPT10eXBlb2YgU3ltYm9sJiYoaVtTeW1ib2wuaXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIGl9KSxpfWZ1bmN0aW9uIHAoZSx0KXt2YXIgbj1hcmd1bWVudHMubGVuZ3RoPjImJnZvaWQgMCE9PWFyZ3VtZW50c1syXT9hcmd1bWVudHNbMl06IiI7InVuZGVmaW5lZCI9PT10eXBlb2Ygd2luZG93P2NvbnNvbGUubG9nKCJyZWR1eC1zYWdhICIrZSsiOiAiK3QrIlxuIisobiYmbi5zdGFja3x8bikpOmNvbnNvbGVbZV0odCxuKX1mdW5jdGlvbiBmKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGUuYXBwbHkodm9pZCAwLGFyZ3VtZW50cyl9fW4uZCh0LCJ4IixmdW5jdGlvbigpe3JldHVybiBtfSksbi5kKHQsImUiLGZ1bmN0aW9uKCl7cmV0dXJuIGd9KSxuLmQodCwiYiIsZnVuY3Rpb24oKXtyZXR1cm4gdn0pLG4uZCh0LCJhIixmdW5jdGlvbigpe3JldHVybiBifSksbi5kKHQsImMiLGZ1bmN0aW9uKCl7cmV0dXJuIHh9KSxuLmQodCwiZCIsZnVuY3Rpb24oKXtyZXR1cm4gQ30pLG4uZCh0LCJyIixmdW5jdGlvbigpe3JldHVybiBEfSksbi5kKHQsInUiLGZ1bmN0aW9uKCl7cmV0dXJuIHd9KSxuLmQodCwibyIsZnVuY3Rpb24oKXtyZXR1cm4gU30pLHQuaD1yLG4uZCh0LCJxIixmdW5jdGlvbigpe3JldHVybiBBfSksbi5kKHQsInYiLGZ1bmN0aW9uKCl7cmV0dXJuIF99KSx0Lnc9byxuLmQodCwiZiIsZnVuY3Rpb24oKXtyZXR1cm4gVH0pLHQubD1hLHQuZz1zLHQubT11LHQuaj1jLG4uZCh0LCJ5IixmdW5jdGlvbigpe3JldHVybiBPfSksdC50PWwsdC5zPXAsdC5uPWYsbi5kKHQsInoiLGZ1bmN0aW9uKCl7cmV0dXJuIEl9KSxuLmQodCwicCIsZnVuY3Rpb24oKXtyZXR1cm4gTH0pLG4uZCh0LCJrIixmdW5jdGlvbigpe3JldHVybiBQfSksbi5kKHQsIkEiLGZ1bmN0aW9uKCl7cmV0dXJuIE19KSxuLmQodCwiaSIsZnVuY3Rpb24oKXtyZXR1cm4gan0pO3ZhciBkPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspe3ZhciBuPWFyZ3VtZW50c1t0XTtmb3IodmFyIHIgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmKGVbcl09bltyXSl9cmV0dXJuIGV9LGg9ImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJiJzeW1ib2wiPT09dHlwZW9mIFN5bWJvbC5pdGVyYXRvcj9mdW5jdGlvbihlKXtyZXR1cm4gdHlwZW9mIGV9OmZ1bmN0aW9uKGUpe3JldHVybiBlJiYiZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmZS5jb25zdHJ1Y3Rvcj09PVN5bWJvbCYmZSE9PVN5bWJvbC5wcm90b3R5cGU/InN5bWJvbCI6dHlwZW9mIGV9LG09ZnVuY3Rpb24oZSl7cmV0dXJuIkBAcmVkdXgtc2FnYS8iK2V9LGc9bSgiVEFTSyIpLHk9bSgiSEVMUEVSIiksdj1tKCJNQVRDSCIpLGI9bSgiQ0FOQ0VMX1BST01JU0UiKSx4PW0oIlNBR0FfQUNUSU9OIiksQz1tKCJTRUxGX0NBTkNFTExBVElPTiIpLEU9ZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGV9fSxEPUUoITApLHc9ZnVuY3Rpb24oKXt9LFM9ZnVuY3Rpb24oZSl7cmV0dXJuIGV9LGs9T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eSxBPXt1bmRlZjpmdW5jdGlvbihlKXtyZXR1cm4gbnVsbD09PWV8fHZvaWQgMD09PWV9LG5vdFVuZGVmOmZ1bmN0aW9uKGUpe3JldHVybiBudWxsIT09ZSYmdm9pZCAwIT09ZX0sZnVuYzpmdW5jdGlvbihlKXtyZXR1cm4iZnVuY3Rpb24iPT09dHlwZW9mIGV9LG51bWJlcjpmdW5jdGlvbihlKXtyZXR1cm4ibnVtYmVyIj09PXR5cGVvZiBlfSxzdHJpbmc6ZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyI9PT10eXBlb2YgZX0sYXJyYXk6QXJyYXkuaXNBcnJheSxvYmplY3Q6ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiFBLmFycmF5KGUpJiYib2JqZWN0Ij09PSgidW5kZWZpbmVkIj09PXR5cGVvZiBlPyJ1bmRlZmluZWQiOmgoZSkpfSxwcm9taXNlOmZ1bmN0aW9uKGUpe3JldHVybiBlJiZBLmZ1bmMoZS50aGVuKX0saXRlcmF0b3I6ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJkEuZnVuYyhlLm5leHQpJiZBLmZ1bmMoZS50aHJvdyl9LGl0ZXJhYmxlOmZ1bmN0aW9uKGUpe3JldHVybiBlJiZBLmZ1bmMoU3ltYm9sKT9BLmZ1bmMoZVtTeW1ib2wuaXRlcmF0b3JdKTpBLmFycmF5KGUpfSx0YXNrOmZ1bmN0aW9uKGUpe3JldHVybiBlJiZlW2ddfSxvYnNlcnZhYmxlOmZ1bmN0aW9uKGUpe3JldHVybiBlJiZBLmZ1bmMoZS5zdWJzY3JpYmUpfSxidWZmZXI6ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJkEuZnVuYyhlLmlzRW1wdHkpJiZBLmZ1bmMoZS50YWtlKSYmQS5mdW5jKGUucHV0KX0scGF0dGVybjpmdW5jdGlvbihlKXtyZXR1cm4gZSYmKEEuc3RyaW5nKGUpfHwic3ltYm9sIj09PSgidW5kZWZpbmVkIj09PXR5cGVvZiBlPyJ1bmRlZmluZWQiOmgoZSkpfHxBLmZ1bmMoZSl8fEEuYXJyYXkoZSkpfSxjaGFubmVsOmZ1bmN0aW9uKGUpe3JldHVybiBlJiZBLmZ1bmMoZS50YWtlKSYmQS5mdW5jKGUuY2xvc2UpfSxoZWxwZXI6ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmVbeV19LHN0cmluZ2FibGVGdW5jOmZ1bmN0aW9uKGUpe3JldHVybiBBLmZ1bmMoZSkmJmkoZSwidG9TdHJpbmciKX19LF89e2Fzc2lnbjpmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KWkodCxuKSYmKGVbbl09dFtuXSl9fSxUPXtmcm9tOmZ1bmN0aW9uKGUpe3ZhciB0PUFycmF5KGUubGVuZ3RoKTtmb3IodmFyIG4gaW4gZSlpKGUsbikmJih0W25dPWVbbl0pO3JldHVybiB0fX0sTz1mdW5jdGlvbigpe3ZhciBlPWFyZ3VtZW50cy5sZW5ndGg+MCYmdm9pZCAwIT09YXJndW1lbnRzWzBdP2FyZ3VtZW50c1swXTowO3JldHVybiBmdW5jdGlvbigpe3JldHVybisrZX19KCksRj1mdW5jdGlvbihlKXt0aHJvdyBlfSxOPWZ1bmN0aW9uKGUpe3JldHVybnt2YWx1ZTplLGRvbmU6ITB9fSxJPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUrIiBoYXMgYmVlbiBkZXByZWNhdGVkIGluIGZhdm9yIG9mICIrdCsiLCBwbGVhc2UgdXBkYXRlIHlvdXIgY29kZSJ9LEw9ZnVuY3Rpb24oZSl7cmV0dXJuIG5ldyBFcnJvcigiXG4gIHJlZHV4LXNhZ2E6IEVycm9yIGNoZWNraW5nIGhvb2tzIGRldGVjdGVkIGFuIGluY29uc2lzdGVudCBzdGF0ZS4gVGhpcyBpcyBsaWtlbHkgYSBidWdcbiAgaW4gcmVkdXgtc2FnYSBjb2RlIGFuZCBub3QgeW91cnMuIFRoYW5rcyBmb3IgcmVwb3J0aW5nIHRoaXMgaW4gdGhlIHByb2plY3QncyBnaXRodWIgcmVwby5cbiAgRXJyb3I6ICIrZSsiXG4iKX0sUD1mdW5jdGlvbihlLHQpe3JldHVybihlP2UrIi4iOiIiKSsic2V0Q29udGV4dChwcm9wcyk6IGFyZ3VtZW50ICIrdCsiIGlzIG5vdCBhIHBsYWluIG9iamVjdCJ9LE09ZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBlKE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LHgse3ZhbHVlOiEwfSkpfX0saj1mdW5jdGlvbiBlKHQpe3JldHVybiBmdW5jdGlvbigpe2Zvcih2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHI9QXJyYXkobiksaT0wO2k8bjtpKyspcltpXT1hcmd1bWVudHNbaV07dmFyIG89W10sYT10LmFwcGx5KHZvaWQgMCxyKTtyZXR1cm57bmV4dDpmdW5jdGlvbihlKXtyZXR1cm4gby5wdXNoKGUpLGEubmV4dChlKX0sY2xvbmU6ZnVuY3Rpb24oKXt2YXIgbj1lKHQpLmFwcGx5KHZvaWQgMCxyKTtyZXR1cm4gby5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBuLm5leHQoZSl9KSxufSxyZXR1cm46ZnVuY3Rpb24oZSl7cmV0dXJuIGEucmV0dXJuKGUpfSx0aHJvdzpmdW5jdGlvbihlKXtyZXR1cm4gYS50aHJvdyhlKX19fX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oNDA5KSxpPW4oMTI0KSxvPW4oNDI0KSxhPW4oNDQ4KSxzPW4oMjQzKSx1PW4oNDg0KTtuLmQodCwiY29tYmluZUFjdGlvbnMiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuYX0pLG4uZCh0LCJjcmVhdGVBY3Rpb24iLGZ1bmN0aW9uKCl7cmV0dXJuIGkuYX0pLG4uZCh0LCJjcmVhdGVBY3Rpb25zIixmdW5jdGlvbigpe3JldHVybiBvLmF9KSxuLmQodCwiY3JlYXRlQ3VycmllZEFjdGlvbiIsZnVuY3Rpb24oKXtyZXR1cm4gYS5hfSksbi5kKHQsImhhbmRsZUFjdGlvbiIsZnVuY3Rpb24oKXtyZXR1cm4gcy5hfSksbi5kKHQsImhhbmRsZUFjdGlvbnMiLGZ1bmN0aW9uKCl7cmV0dXJuIHUuYX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspe3ZhciBuPWFyZ3VtZW50c1t0XTtmb3IodmFyIHIgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmKGVbcl09bltyXSl9cmV0dXJuIGV9LGk9ZnVuY3Rpb24oZSx0KXt2YXIgbj17fTtmb3IodmFyIHIgaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxyKSYmdC5pbmRleE9mKHIpPDAmJihuW3JdPWVbcl0pO2lmKG51bGwhPWUmJiJmdW5jdGlvbiI9PT10eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scylmb3IodmFyIGk9MCxyPU9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMoZSk7aTxyLmxlbmd0aDtpKyspdC5pbmRleE9mKHJbaV0pPDAmJihuW3JbaV1dPWVbcltpXV0pO3JldHVybiBufTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPWZ1bmN0aW9uKGUpe3ZhciB0PWUudGl0bGUsbj1lLmNoaWxkcmVuLHI9aShlLFsidGl0bGUiLCJjaGlsZHJlbiJdKTtyZXR1cm4gby5jcmVhdGVFbGVtZW50KCJzdmciLHIsdD9vLmNyZWF0ZUVsZW1lbnQoInRpdGxlIixudWxsLHQpOnZvaWQgMCxuKX07dC5BZGRJY29uPWZ1bmN0aW9uKGUpe3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoYSxyKHt9LGUse3ZpZXdCb3g6IjAgMCA1MCA1MCJ9KSxvLmNyZWF0ZUVsZW1lbnQoImxpbmUiLHt4MToiMjUiLHkxOiIxMy4xIix4MjoiMjUiLHkyOiIzNi45In0pLG8uY3JlYXRlRWxlbWVudCgibGluZSIse3gxOiIzNi45Iix5MToiMjUiLHgyOiIxMy4xIix5MjoiMjUifSkpfSx0LkFkZEZ1bGxJY29uPWZ1bmN0aW9uKGUpe3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoYSxyKHt4OiIwcHgiLHk6IjBweCIsdmlld0JveDoiLTEgMyA1MCA1MCJ9LGUpLG8uY3JlYXRlRWxlbWVudCgibGluZSIse3gxOiIyNCIseTE6IjcuMjciLHgyOiIyNCIseTI6IjQ4LjczIn0pLG8uY3JlYXRlRWxlbWVudCgibGluZSIse3gxOiI0NC43MyIseTE6IjI4Iix4MjoiMy4yNyIseTI6IjI4In0pKX0sdC5GdWxsQXJyb3dSaWdodEljb249ZnVuY3Rpb24oZSl7cmV0dXJuIG8uY3JlYXRlRWxlbWVudChhLHIoe30sZSx7dmlld0JveDoiMCAwIDE0IDExIn0pLG8uY3JlYXRlRWxlbWVudCgicGF0aCIse2Q6Ik0xMy4zMiw0Ljk3TDguOTksMC42NGMtMC4yOS0wLjI5LTAuNzctMC4yOS0xLjA2LDBzLTAuMjksMC43NywwLDEuMDZsMi45NywyLjk3SDEuMjEgQzAuOCw0LjY3LDAuNDYsNSwwLjQ2LDUuNDJTMC44LDYuMTcsMS4yMSw2LjE3aDkuODVMNy45Myw5LjNjLTAuMjksMC4yOS0wLjI5LDAuNzcsMCwxLjA2YzAuMTUsMC4xNSwwLjM0LDAuMjIsMC41MywwLjIyIHMwLjM4LTAuMDcsMC41My0wLjIybDQuMzMtNC4zM0MxMy42MSw1Ljc0LDEzLjYxLDUuMjYsMTMuMzIsNC45N3oifSkpfSx0LlNldHRpbmdzSWNvbj1mdW5jdGlvbihlKXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGEscih7fSxlLHt2aWV3Qm94OiIwIDAgNTAgNTAifSksby5jcmVhdGVFbGVtZW50KCJwYXRoIix7ZDoiTTQ4LDIxaC01LjcxYy0wLjQtMS41OC0wLjkxLTMuMzMtMS41Ni00LjY2bDQuMDYtNC4wNmMwLjE5LTAuMTksMC4yOS0wLjQ0LDAuMjktMC43MSBjMC0wLjI3LTAuMTEtMC41Mi0wLjI5LTAuNzFMMzkuMTQsNS4yYy0wLjM5LTAuMzktMS4wMi0wLjM5LTEuNDEsMGwtNC4wNiw0LjA2QzMyLjMzLDguNjIsMzAuNTgsOC4xMSwyOSw3LjcxVjJjMC0wLjU1LTAuNDUtMS0xLTEgaC02Yy0wLjU1LDAtMSwwLjQ1LTEsMXY1LjcxYy0xLjU4LDAuNC0zLjMzLDAuOTEtNC42NiwxLjU1TDEyLjI3LDUuMmMtMC4zOS0wLjM5LTEuMDItMC4zOS0xLjQxLDBMNS4yLDEwLjg2IGMtMC4zOSwwLjM5LTAuMzksMS4wMiwwLDEuNDFsNC4wNyw0LjA3QzguNjIsMTcuNjYsOC4xMSwxOS40Miw3LjcxLDIxSDJjLTAuNTUsMC0xLDAuNDUtMSwxdjZjMCwwLjU1LDAuNDUsMSwxLDFoNS43MSBjMC40LDEuNTgsMC45MSwzLjM0LDEuNTYsNC42Nkw1LjIsMzcuNzNjLTAuMTksMC4xOS0wLjI5LDAuNDQtMC4yOSwwLjcxczAuMTEsMC41MiwwLjI5LDAuNzFsNS42Niw1LjY2YzAuMzgsMC4zOCwxLjA0LDAuMzgsMS40MSwwIGw0LjA3LTQuMDZjMS4zMiwwLjY1LDMuMDgsMS4xNSw0LjY2LDEuNTZWNDhjMCwwLjU1LDAuNDUsMSwxLDFoNmMwLjU1LDAsMS0wLjQ1LDEtMXYtNS43MWMxLjU4LTAuNCwzLjM0LTAuOTEsNC42Ni0xLjU2bDQuMDcsNC4wNiBjMC4zOSwwLjM5LDEuMDIsMC4zOSwxLjQxLDBsNS42Ni01LjY2YzAuMzktMC4zOSwwLjM5LTEuMDIsMC0xLjQxbC00LjA2LTQuMDdjMC42NS0xLjMzLDEuMTYtMy4wOCwxLjU2LTQuNjZINDhjMC41NSwwLDEtMC40NSwxLTEgdi02QzQ5LDIxLjQ1LDQ4LjU1LDIxLDQ4LDIxIE0yNSwzM2MtNC40MSwwLTgtMy41OS04LThzMy41OS04LDgtOHM4LDMuNTksOCw4UzI5LjQxLDMzLDI1LDMzIn0pKX0sdC5Dcm9zc0ljb249ZnVuY3Rpb24oZSl7cmV0dXJuIG8uY3JlYXRlRWxlbWVudChhLHIoe30sZSx7dmlld0JveDoiMCAwIDUwIDUwIn0pLG8uY3JlYXRlRWxlbWVudCgibGluZSIse3gxOiI0Iix5MToiNCIseDI6IjQ2Iix5MjoiNDYifSksby5jcmVhdGVFbGVtZW50KCJsaW5lIix7eDE6IjQ2Iix5MToiNCIseDI6IjQiLHkyOiI0NiJ9KSl9LHQuQXJyb3dSaWdodD1mdW5jdGlvbihlKXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGEscih7d2lkdGg6MTQsaGVpZ2h0OjExfSxlLHt2aWV3Qm94OiItMSAtMSAxNCAxMSJ9KSxvLmNyZWF0ZUVsZW1lbnQoInBhdGgiLHtkOiJNNSw4Ljc5ODI1NTc5IEw1LC0xLjc5NDAyMDg5IixpZDoiU3Ryb2tlLTMiLHN0cm9rZToiI0ZGRkZGRiIsc3Ryb2tlV2lkdGg6IjEuNSIsc3Ryb2tlTGluZWNhcDoicm91bmQiLHN0cm9rZUxpbmVqb2luOiJyb3VuZCIsZmlsbDoibm9uZSIsdHJhbnNmb3JtOiJ0cmFuc2xhdGUoNS43NTAwMDAsIDMuNTAyMTE3KSByb3RhdGUoLTkwLjAwMDAwMCkgdHJhbnNsYXRlKC01Ljc1MDAwMCwgLTMuNTAyMTE3KSAifSksby5jcmVhdGVFbGVtZW50KCJwb2x5bGluZSIse2lkOiJTdHJva2UtNSIsc3Ryb2tlOiIjRkZGRkZGIixzdHJva2VXaWR0aDoiMS41IixzdHJva2VMaW5lY2FwOiJyb3VuZCIsc3Ryb2tlTGluZWpvaW46InJvdW5kIixmaWxsOiJub25lIix0cmFuc2Zvcm06InRyYW5zbGF0ZSg5Ljg2ODI5NSwgNC4zMzM5OTIpIHJvdGF0ZSgtOTAuMDAwMDAwKSB0cmFuc2xhdGUoLTkuODY4Mjk1LCAtNC4zMzM5OTIpICIscG9pbnRzOiIxNC4yMDIyODY4IDIuMTY2OTk2MDUgOS44NjgyOTQ3NSA2LjUwMDk4ODE0IDUuNTM0MzAyNjUgMi4xNjY5OTYwNSJ9KSl9LHQuSGlzdG9yeT1mdW5jdGlvbihlKXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGEscih7fSxlLHt2aWV3Qm94OiIwIDAgNTAgNTAiLGZpbGw6Im5vbmUifSksby5jcmVhdGVFbGVtZW50KCJwb2x5bGluZSIse3BvaW50czoiNC4zMywxOS42NCA5LjcsMjcuNjkgMTUuOTUsMjAuNTQgIn0pLG8uY3JlYXRlRWxlbWVudCgicGF0aCIse2Q6Ik05LjcxLDI3LjY5QzguMzYsMTYuODEsMTYuNjgsOC4zOCwyNi4wNiw4LjAzYzkuMzctMC4zNSwxNy4yNSw2Ljk3LDE3LjYsMTYuMzUgYzAuMzUsOS4zOC02Ljk3LDE3LjI2LTE2LjM1LDE3LjYifSksby5jcmVhdGVFbGVtZW50KCJwb2x5bGluZSIse3BvaW50czoiMjYuNjgsMTYuMDYgMjYuNjgsMjUuODkgMzUuNjIsMjUuODkgIn0pKX0sdC5TdGFyPWZ1bmN0aW9uKGUpe3ZhciB0PWUuaGVpZ2h0LG49ZS53aWR0aCxzPWUuc3Ryb2tlLHU9ZS5maWxsLGM9ZS5zdHJva2VXaWR0aCxsPWUub25DbGljayxwPWkoZSxbImhlaWdodCIsIndpZHRoIiwic3Ryb2tlIiwiZmlsbCIsInN0cm9rZVdpZHRoIiwib25DbGljayJdKTtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGEscih7d2lkdGg6bixoZWlnaHQ6dCxmaWxsOnV8fCJub25lIixzdHJva2U6c3x8Im5vbmUiLHN0cm9rZVdpZHRoOmMsdmlld0JveDoiMTE4IDEyIDE2IDE2IixvbkNsaWNrOmx9LHApLG8uY3JlYXRlRWxlbWVudCgicG9seWdvbiIse3BvaW50czoiMTI2IDI0IDEyMS4yOTc3MTggMjYuNDcyMTM2IDEyMi4xOTU3NzQgMjEuMjM2MDY4IDExOC4zOTE1NDggMTcuNTI3ODY0IDEyMy42NDg4NTkgMTYuNzYzOTMyIDEyNiAxMiAxMjguMzUxMTQxIDE2Ljc2MzkzMiAxMzMuNjA4NDUyIDE3LjUyNzg2NCAxMjkuODA0MjI2IDIxLjIzNjA2OCAxMzAuNzAyMjgyIDI2LjQ3MjEzNiJ9KSl9LHQuU2VhcmNoPWZ1bmN0aW9uKGUpe3ZhciB0PWUuaGVpZ2h0LG49ZS53aWR0aCxzPWUuc3Ryb2tlV2lkdGgsdT1lLmNvbG9yLGM9aShlLFsiaGVpZ2h0Iiwid2lkdGgiLCJzdHJva2VXaWR0aCIsImNvbG9yIl0pO3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoYSxyKHt3aWR0aDpuLGhlaWdodDp0LHZpZXdCb3g6IjAgMCA1MCA1MCIsc3Ryb2tlV2lkdGg6cyxzdHJva2U6dSxmaWxsOiJub25lIn0sYyksby5jcmVhdGVFbGVtZW50KCJjaXJjbGUiLHtjeDoiMTcuODIiLGN5OiIxOC4xMSIscjoiMTYuMjEifSksby5jcmVhdGVFbGVtZW50KCJsaW5lIix7eDE6IjI5LjI4Iix5MToiMjkuNTciLHgyOiI0OC4yMSIseTI6IjQ4LjUifSkpfSx0LlNoYXJlSWNvbj1mdW5jdGlvbihlKXt2YXIgdD1lLndpZHRoLG49ZS5oZWlnaHQscz1lLmNvbG9yLHU9aShlLFsid2lkdGgiLCJoZWlnaHQiLCJjb2xvciJdKTtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGEscih7d2lkdGg6dCxoZWlnaHQ6bix2aWV3Qm94OiIwIDAgNTAgNTAiLHN0cm9rZTpzfSx1KSxvLmNyZWF0ZUVsZW1lbnQoInBhdGgiLHtkOiJNMTYuNDcgMTUuNTZjLS4zNiAwLS42NS4zLS42NS42N3YyMC4yMmMwIC4zNy4yOS42Ny42NS42N2g5LjA2Yy4zNiAwIC42NS0uMy42NS0uNjdzLS4yOS0uNjctLjY1LS42N2gtOC40MVYxNi45MWgxLjI5di42N2MwIC4zNy4yOS42Ny42NS42N2gxMC4zNWMuMzYgMCAuNjUtLjMuNjUtLjY3di0uNjdoMS4yOXY2LjA3YzAgLjM3LjI5LjY3LjY1LjY3LjM2IDAgLjY1LS4zLjY1LS42N3YtNi43NGEuNjYuNjYgMCAwIDAtLjY1LS42N2gtMS45NHYtMS4zNWgzLjg4djguNzZjMCAuMzcuMjkuNjcuNjUuNjcuMzYgMCAuNjUtLjMuNjUtLjY3di05LjQ0YS42Ni42NiAwIDAgMC0uNjUtLjY3aC00LjUzdi0uNjdhLjY2LjY2IDAgMCAwLS42NS0uNjdIMjcuNGMtLjMtMS41NC0xLjYxLTIuNy0zLjE3LTIuNy0xLjU2IDAtMi44NyAxLjE2LTMuMTcgMi43aC0yLjAxYy0uMzYgMC0uNjUuMy0uNjUuNjd2LjY3aC00LjUzYy0uMzYgMC0uNjUuMy0uNjUuNjdWNDAuNWMwIC4zNy4yOS42Ny42NS42N2gxMS42NWMuMzYgMCAuNjUtLjMuNjUtLjY3cy0uMjktLjY3LS42NS0uNjdoLTExVjE0LjIyaDMuODh2MS4zNWgtMS45M3ptMy4yNC0yLjY5aDEuOTRjLjM2IDAgLjY1LS4zLjY1LS42NyAwLTEuMTEuODctMi4wMiAxLjk0LTIuMDIgMS4wNyAwIDEuOTQuOTEgMS45NCAyLjAyIDAgLjM3LjI5LjY3LjY1LjY3aDEuOTR2NC4wNGgtOS4wNnYtNC4wNHoifSksby5jcmVhdGVFbGVtZW50KCJwYXRoIix7ZDoiTTI4LjcxIDIwLjk2aC05LjA2Yy0uMzYgMC0uNjUuMy0uNjUuNjcgMCAuMzcuMjkuNjcuNjUuNjdoOS4wNmMuMzYgMCAuNjUtLjMuNjUtLjY3YS42Ni42NiAwIDAgMC0uNjUtLjY3TTI4LjcxIDIzLjY1aC05LjA2Yy0uMzYgMC0uNjUuMy0uNjUuNjdzLjMuNjguNjYuNjhoOS4wNmMuMzYgMCAuNjUtLjMuNjUtLjY3cy0uMy0uNjgtLjY2LS42OE0yOC43MSAyNi4zNWgtOS4wNmMtLjM2IDAtLjY1LjMtLjY1LjY3cy4yOS42Ny42NS42N2g5LjA2Yy4zNiAwIC42NS0uMy42NS0uNjdzLS4yOS0uNjctLjY1LS42N00yNi4xMyAyOS4wNGgtNi40N2MtLjM2IDAtLjY1LjMtLjY1LjY3IDAgLjM3LjI5LjY3LjY1LjY3aDYuNDdjLjM2IDAgLjY1LS4zLjY1LS42Ny0uMDEtLjM2LS4zLS42Ny0uNjUtLjY3TTM3Ljc3IDMzLjIxaC02LjEzbDEuNDMtMS4zOGMuMjYtLjI1LjI4LS42OC4wMy0uOTVhLjYyLjYyIDAgMCAwLS45MS0uMDRsLTIuNjMgMi41NGMtLjEzLjEzLS4yMS4zLS4yMS40OXYuMDJjMCAuMi4wOS4zOC4yMy41bDIuNiAyLjU2Yy4xMi4xMi4yOC4xOC40NC4xOC4xNyAwIC4zNC0uMDcuNDctLjIxLjI1LS4yNy4yMy0uNy0uMDMtLjk1bC0xLjQzLTEuNDFoNi4xM2MuMzYgMCAuNjUtLjMuNjUtLjY3cy0uMjgtLjY4LS42NC0uNjgifSkpfSx0LlRyaWFuZ2xlPWZ1bmN0aW9uKGUpe3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoYSxyKHt3aWR0aDo2LGhlaWdodDo3LHZpZXdCb3g6IjQwIDAgNiA3In0sZSksby5jcmVhdGVFbGVtZW50KCJwb2x5Z29uIix7c3Ryb2tlOiJub25lIixmaWxsOiJyZ2JhKDAsIDAsIDAsIC4yKSIsZmlsbFJ1bGU6ImV2ZW5vZGQiLHBvaW50czoiNDAgNyA0MCAwIDQ2IDMuNSJ9KSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7fTtlLmV4cG9ydHM9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1mdW5jdGlvbiBpKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9ZnVuY3Rpb24gbyhlLHQpe2lmKCF0KXJldHVybiBlO2lmKHQgaW5zdGFuY2VvZiB1LkdyYXBoUUxMaXN0fHx0IGluc3RhbmNlb2YgdS5HcmFwaFFMTm9uTnVsbClyZXR1cm4gbyhlLHQub2ZUeXBlKTtpZihlW3QubmFtZV0pcmV0dXJuIGVbdC5uYW1lXSE9PXQmJigwLGguZGVmYXVsdCkoMCwnU2NoZW1hIG11c3QgY29udGFpbiB1bmlxdWUgbmFtZWQgdHlwZXMgYnV0IGNvbnRhaW5zIG11bHRpcGxlIHR5cGVzIG5hbWVkICInK3QubmFtZSsnIi4nKSxlO2VbdC5uYW1lXT10O3ZhciBuPWU7aWYodCBpbnN0YW5jZW9mIHUuR3JhcGhRTFVuaW9uVHlwZSYmKG49dC5nZXRUeXBlcygpLnJlZHVjZShvLG4pKSx0IGluc3RhbmNlb2YgdS5HcmFwaFFMT2JqZWN0VHlwZSYmKG49dC5nZXRJbnRlcmZhY2VzKCkucmVkdWNlKG8sbikpLHQgaW5zdGFuY2VvZiB1LkdyYXBoUUxPYmplY3RUeXBlfHx0IGluc3RhbmNlb2YgdS5HcmFwaFFMSW50ZXJmYWNlVHlwZSl7dmFyIHI9dC5nZXRGaWVsZHMoKTtPYmplY3Qua2V5cyhyKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PXJbZV07aWYodC5hcmdzKXt2YXIgaT10LmFyZ3MubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnR5cGV9KTtuPWkucmVkdWNlKG8sbil9bj1vKG4sdC50eXBlKX0pfWlmKHQgaW5zdGFuY2VvZiB1LkdyYXBoUUxJbnB1dE9iamVjdFR5cGUpe3ZhciBpPXQuZ2V0RmllbGRzKCk7T2JqZWN0LmtleXMoaSkuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1pW2VdO249byhuLHQudHlwZSl9KX1yZXR1cm4gbn1mdW5jdGlvbiBhKGUsdCxuKXt2YXIgcj10LmdldEZpZWxkcygpLGk9bi5nZXRGaWVsZHMoKTtPYmplY3Qua2V5cyhpKS5mb3JFYWNoKGZ1bmN0aW9uKG8pe3ZhciBhPXJbb10scz1pW29dO2F8fCgwLGguZGVmYXVsdCkoMCwnIicrbi5uYW1lKyciIGV4cGVjdHMgZmllbGQgIicrbysnIiBidXQgIicrdC5uYW1lKyciIGRvZXMgbm90IHByb3ZpZGUgaXQuJyksKDAsbS5pc1R5cGVTdWJUeXBlT2YpKGUsYS50eXBlLHMudHlwZSl8fCgwLGguZGVmYXVsdCkoMCxuLm5hbWUrIi4iK28rJyBleHBlY3RzIHR5cGUgIicrU3RyaW5nKHMudHlwZSkrJyIgYnV0ICcrdC5uYW1lKyIuIitvKycgcHJvdmlkZXMgdHlwZSAiJytTdHJpbmcoYS50eXBlKSsnIi4nKSxzLmFyZ3MuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgcj1lLm5hbWUsaT0oMCxmLmRlZmF1bHQpKGEuYXJncyxmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lPT09cn0pO2l8fCgwLGguZGVmYXVsdCkoMCxuLm5hbWUrIi4iK28rJyBleHBlY3RzIGFyZ3VtZW50ICInK3IrJyIgYnV0ICcrdC5uYW1lKyIuIitvKyIgZG9lcyBub3QgcHJvdmlkZSBpdC4iKSwoMCxtLmlzRXF1YWxUeXBlKShlLnR5cGUsaS50eXBlKXx8KDAsaC5kZWZhdWx0KSgwLG4ubmFtZSsiLiIrbysiKCIrcisnOikgZXhwZWN0cyB0eXBlICInK1N0cmluZyhlLnR5cGUpKyciIGJ1dCAnK3QubmFtZSsiLiIrbysiKCIrcisnOikgcHJvdmlkZXMgdHlwZSAiJytTdHJpbmcoaS50eXBlKSsnIi4nKX0pLGEuYXJncy5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciByPWUubmFtZTsoMCxmLmRlZmF1bHQpKHMuYXJncyxmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lPT09cn0pfHxlLnR5cGUgaW5zdGFuY2VvZiB1LkdyYXBoUUxOb25OdWxsJiYoMCxoLmRlZmF1bHQpKDAsdC5uYW1lKyIuIitvKyIoIityKyc6KSBpcyBvZiByZXF1aXJlZCB0eXBlICInK1N0cmluZyhlLnR5cGUpKyciIGJ1dCBpcyBub3QgYWxzbyBwcm92aWRlZCBieSB0aGUgaW50ZXJmYWNlICcrbi5uYW1lKyIuIitvKyIuIil9KX0pfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkdyYXBoUUxTY2hlbWE9dm9pZCAwO3ZhciBzPSJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiYic3ltYm9sIj09PXR5cGVvZiBTeW1ib2wuaXRlcmF0b3I/ZnVuY3Rpb24oZSl7cmV0dXJuIHR5cGVvZiBlfTpmdW5jdGlvbihlKXtyZXR1cm4gZSYmImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfSx1PW4oNiksYz1uKDI3KSxsPW4oMjgpLHA9big0NSksZj1yKHApLGQ9bigxMyksaD1yKGQpLG09big4MSk7dC5HcmFwaFFMU2NoZW1hPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0KXt2YXIgbj10aGlzO2kodGhpcyxlKSwib2JqZWN0IiE9PSgidW5kZWZpbmVkIj09PXR5cGVvZiB0PyJ1bmRlZmluZWQiOnModCkpJiYoMCxoLmRlZmF1bHQpKDAsIk11c3QgcHJvdmlkZSBjb25maWd1cmF0aW9uIG9iamVjdC4iKSx0LnF1ZXJ5IGluc3RhbmNlb2YgdS5HcmFwaFFMT2JqZWN0VHlwZXx8KDAsaC5kZWZhdWx0KSgwLCJTY2hlbWEgcXVlcnkgbXVzdCBiZSBPYmplY3QgVHlwZSBidXQgZ290OiAiK1N0cmluZyh0LnF1ZXJ5KSsiLiIpLHRoaXMuX3F1ZXJ5VHlwZT10LnF1ZXJ5LCF0Lm11dGF0aW9ufHx0Lm11dGF0aW9uIGluc3RhbmNlb2YgdS5HcmFwaFFMT2JqZWN0VHlwZXx8KDAsaC5kZWZhdWx0KSgwLCJTY2hlbWEgbXV0YXRpb24gbXVzdCBiZSBPYmplY3QgVHlwZSBpZiBwcm92aWRlZCBidXQgZ290OiAiK1N0cmluZyh0Lm11dGF0aW9uKSsiLiIpLHRoaXMuX211dGF0aW9uVHlwZT10Lm11dGF0aW9uLCF0LnN1YnNjcmlwdGlvbnx8dC5zdWJzY3JpcHRpb24gaW5zdGFuY2VvZiB1LkdyYXBoUUxPYmplY3RUeXBlfHwoMCxoLmRlZmF1bHQpKDAsIlNjaGVtYSBzdWJzY3JpcHRpb24gbXVzdCBiZSBPYmplY3QgVHlwZSBpZiBwcm92aWRlZCBidXQgZ290OiAiK1N0cmluZyh0LnN1YnNjcmlwdGlvbikrIi4iKSx0aGlzLl9zdWJzY3JpcHRpb25UeXBlPXQuc3Vic2NyaXB0aW9uLHQudHlwZXMmJiFBcnJheS5pc0FycmF5KHQudHlwZXMpJiYoMCxoLmRlZmF1bHQpKDAsIlNjaGVtYSB0eXBlcyBtdXN0IGJlIEFycmF5IGlmIHByb3ZpZGVkIGJ1dCBnb3Q6ICIrU3RyaW5nKHQudHlwZXMpKyIuIiksIXQuZGlyZWN0aXZlc3x8QXJyYXkuaXNBcnJheSh0LmRpcmVjdGl2ZXMpJiZ0LmRpcmVjdGl2ZXMuZXZlcnkoZnVuY3Rpb24oZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiBjLkdyYXBoUUxEaXJlY3RpdmV9KXx8KDAsaC5kZWZhdWx0KSgwLCJTY2hlbWEgZGlyZWN0aXZlcyBtdXN0IGJlIEFycmF5PEdyYXBoUUxEaXJlY3RpdmU+IGlmIHByb3ZpZGVkIGJ1dCBnb3Q6ICIrU3RyaW5nKHQuZGlyZWN0aXZlcykrIi4iKSx0aGlzLl9kaXJlY3RpdmVzPXQuZGlyZWN0aXZlc3x8Yy5zcGVjaWZpZWREaXJlY3RpdmVzLHRoaXMuYXN0Tm9kZT10LmFzdE5vZGV8fG51bGw7dmFyIHI9W3RoaXMuZ2V0UXVlcnlUeXBlKCksdGhpcy5nZXRNdXRhdGlvblR5cGUoKSx0aGlzLmdldFN1YnNjcmlwdGlvblR5cGUoKSxsLl9fU2NoZW1hXSxwPXQudHlwZXM7cCYmKHI9ci5jb25jYXQocCkpLHRoaXMuX3R5cGVNYXA9ci5yZWR1Y2UobyxPYmplY3QuY3JlYXRlKG51bGwpKSx0aGlzLl9pbXBsZW1lbnRhdGlvbnM9T2JqZWN0LmNyZWF0ZShudWxsKSxPYmplY3Qua2V5cyh0aGlzLl90eXBlTWFwKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PW4uX3R5cGVNYXBbZV07dCBpbnN0YW5jZW9mIHUuR3JhcGhRTE9iamVjdFR5cGUmJnQuZ2V0SW50ZXJmYWNlcygpLmZvckVhY2goZnVuY3Rpb24oZSl7dmFyIHI9bi5faW1wbGVtZW50YXRpb25zW2UubmFtZV07cj9yLnB1c2godCk6bi5faW1wbGVtZW50YXRpb25zW2UubmFtZV09W3RdfSl9KSxPYmplY3Qua2V5cyh0aGlzLl90eXBlTWFwKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PW4uX3R5cGVNYXBbZV07dCBpbnN0YW5jZW9mIHUuR3JhcGhRTE9iamVjdFR5cGUmJnQuZ2V0SW50ZXJmYWNlcygpLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGEobix0LGUpfSl9KX1yZXR1cm4gZS5wcm90b3R5cGUuZ2V0UXVlcnlUeXBlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3F1ZXJ5VHlwZX0sZS5wcm90b3R5cGUuZ2V0TXV0YXRpb25UeXBlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX211dGF0aW9uVHlwZX0sZS5wcm90b3R5cGUuZ2V0U3Vic2NyaXB0aW9uVHlwZT1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9zdWJzY3JpcHRpb25UeXBlfSxlLnByb3RvdHlwZS5nZXRUeXBlTWFwPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3R5cGVNYXB9LGUucHJvdG90eXBlLmdldFR5cGU9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuZ2V0VHlwZU1hcCgpW2VdfSxlLnByb3RvdHlwZS5nZXRQb3NzaWJsZVR5cGVzPWZ1bmN0aW9uKGUpe3JldHVybiBlIGluc3RhbmNlb2YgdS5HcmFwaFFMVW5pb25UeXBlP2UuZ2V0VHlwZXMoKTooZSBpbnN0YW5jZW9mIHUuR3JhcGhRTEludGVyZmFjZVR5cGV8fCgwLGguZGVmYXVsdCkoMCksdGhpcy5faW1wbGVtZW50YXRpb25zW2UubmFtZV0pfSxlLnByb3RvdHlwZS5pc1Bvc3NpYmxlVHlwZT1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMuX3Bvc3NpYmxlVHlwZU1hcDtpZihufHwodGhpcy5fcG9zc2libGVUeXBlTWFwPW49T2JqZWN0LmNyZWF0ZShudWxsKSksIW5bZS5uYW1lXSl7dmFyIHI9dGhpcy5nZXRQb3NzaWJsZVR5cGVzKGUpO0FycmF5LmlzQXJyYXkocil8fCgwLGguZGVmYXVsdCkoMCwiQ291bGQgbm90IGZpbmQgcG9zc2libGUgaW1wbGVtZW50aW5nIHR5cGVzIGZvciAiK2UubmFtZSsiIGluIHNjaGVtYS4gQ2hlY2sgdGhhdCBzY2hlbWEudHlwZXMgaXMgZGVmaW5lZCBhbmQgaXMgYW4gYXJyYXkgb2YgYWxsIHBvc3NpYmxlIHR5cGVzIGluIHRoZSBzY2hlbWEuIiksbltlLm5hbWVdPXIucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGVbdC5uYW1lXT0hMCxlfSxPYmplY3QuY3JlYXRlKG51bGwpKX1yZXR1cm4gQm9vbGVhbihuW2UubmFtZV1bdC5uYW1lXSl9LGUucHJvdG90eXBlLmdldERpcmVjdGl2ZXM9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fZGlyZWN0aXZlc30sZS5wcm90b3R5cGUuZ2V0RGlyZWN0aXZlPWZ1bmN0aW9uKGUpe3JldHVybigwLGYuZGVmYXVsdCkodGhpcy5nZXREaXJlY3RpdmVzKCksZnVuY3Rpb24odCl7cmV0dXJuIHQubmFtZT09PWV9KX0sZX0oKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuc3BlY2lmaWVkRGlyZWN0aXZlcz10LkdyYXBoUUxEZXByZWNhdGVkRGlyZWN0aXZlPXQuREVGQVVMVF9ERVBSRUNBVElPTl9SRUFTT049dC5HcmFwaFFMU2tpcERpcmVjdGl2ZT10LkdyYXBoUUxJbmNsdWRlRGlyZWN0aXZlPXQuR3JhcGhRTERpcmVjdGl2ZT10LkRpcmVjdGl2ZUxvY2F0aW9uPXZvaWQgMDt2YXIgaT1uKDYpLG89bigzMiksYT1uKDEzKSxzPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0oYSksdT1uKDExMSksYz10LkRpcmVjdGl2ZUxvY2F0aW9uPXtRVUVSWToiUVVFUlkiLE1VVEFUSU9OOiJNVVRBVElPTiIsU1VCU0NSSVBUSU9OOiJTVUJTQ1JJUFRJT04iLEZJRUxEOiJGSUVMRCIsRlJBR01FTlRfREVGSU5JVElPTjoiRlJBR01FTlRfREVGSU5JVElPTiIsRlJBR01FTlRfU1BSRUFEOiJGUkFHTUVOVF9TUFJFQUQiLElOTElORV9GUkFHTUVOVDoiSU5MSU5FX0ZSQUdNRU5UIixTQ0hFTUE6IlNDSEVNQSIsU0NBTEFSOiJTQ0FMQVIiLE9CSkVDVDoiT0JKRUNUIixGSUVMRF9ERUZJTklUSU9OOiJGSUVMRF9ERUZJTklUSU9OIixBUkdVTUVOVF9ERUZJTklUSU9OOiJBUkdVTUVOVF9ERUZJTklUSU9OIixJTlRFUkZBQ0U6IklOVEVSRkFDRSIsVU5JT046IlVOSU9OIixFTlVNOiJFTlVNIixFTlVNX1ZBTFVFOiJFTlVNX1ZBTFVFIixJTlBVVF9PQkpFQ1Q6IklOUFVUX09CSkVDVCIsSU5QVVRfRklFTERfREVGSU5JVElPTjoiSU5QVVRfRklFTERfREVGSU5JVElPTiJ9LGw9dC5HcmFwaFFMRGlyZWN0aXZlPWZ1bmN0aW9uIGUodCl7cih0aGlzLGUpLHQubmFtZXx8KDAscy5kZWZhdWx0KSgwLCJEaXJlY3RpdmUgbXVzdCBiZSBuYW1lZC4iKSwoMCx1LmFzc2VydFZhbGlkTmFtZSkodC5uYW1lKSxBcnJheS5pc0FycmF5KHQubG9jYXRpb25zKXx8KDAscy5kZWZhdWx0KSgwLCJNdXN0IHByb3ZpZGUgbG9jYXRpb25zIGZvciBkaXJlY3RpdmUuIiksdGhpcy5uYW1lPXQubmFtZSx0aGlzLmRlc2NyaXB0aW9uPXQuZGVzY3JpcHRpb24sdGhpcy5sb2NhdGlvbnM9dC5sb2NhdGlvbnMsdGhpcy5hc3ROb2RlPXQuYXN0Tm9kZTt2YXIgbj10LmFyZ3M7bj8oQXJyYXkuaXNBcnJheShuKSYmKDAscy5kZWZhdWx0KSgwLCJAIit0Lm5hbWUrIiBhcmdzIG11c3QgYmUgYW4gb2JqZWN0IHdpdGggYXJndW1lbnQgbmFtZXMgYXMga2V5cy4iKSx0aGlzLmFyZ3M9T2JqZWN0LmtleXMobikubWFwKGZ1bmN0aW9uKGUpeygwLHUuYXNzZXJ0VmFsaWROYW1lKShlKTt2YXIgcj1uW2VdO3JldHVybigwLGkuaXNJbnB1dFR5cGUpKHIudHlwZSl8fCgwLHMuZGVmYXVsdCkoMCwiQCIrdC5uYW1lKyIoIitlKyI6KSBhcmd1bWVudCB0eXBlIG11c3QgYmUgSW5wdXQgVHlwZSBidXQgZ290OiAiK1N0cmluZyhyLnR5cGUpKyIuIikse25hbWU6ZSxkZXNjcmlwdGlvbjp2b2lkIDA9PT1yLmRlc2NyaXB0aW9uP251bGw6ci5kZXNjcmlwdGlvbix0eXBlOnIudHlwZSxkZWZhdWx0VmFsdWU6ci5kZWZhdWx0VmFsdWUsYXN0Tm9kZTpyLmFzdE5vZGV9fSkpOnRoaXMuYXJncz1bXX0scD10LkdyYXBoUUxJbmNsdWRlRGlyZWN0aXZlPW5ldyBsKHtuYW1lOiJpbmNsdWRlIixkZXNjcmlwdGlvbjoiRGlyZWN0cyB0aGUgZXhlY3V0b3IgdG8gaW5jbHVkZSB0aGlzIGZpZWxkIG9yIGZyYWdtZW50IG9ubHkgd2hlbiB0aGUgYGlmYCBhcmd1bWVudCBpcyB0cnVlLiIsbG9jYXRpb25zOltjLkZJRUxELGMuRlJBR01FTlRfU1BSRUFELGMuSU5MSU5FX0ZSQUdNRU5UXSxhcmdzOntpZjp7dHlwZTpuZXcgaS5HcmFwaFFMTm9uTnVsbChvLkdyYXBoUUxCb29sZWFuKSxkZXNjcmlwdGlvbjoiSW5jbHVkZWQgd2hlbiB0cnVlLiJ9fX0pLGY9dC5HcmFwaFFMU2tpcERpcmVjdGl2ZT1uZXcgbCh7bmFtZToic2tpcCIsZGVzY3JpcHRpb246IkRpcmVjdHMgdGhlIGV4ZWN1dG9yIHRvIHNraXAgdGhpcyBmaWVsZCBvciBmcmFnbWVudCB3aGVuIHRoZSBgaWZgIGFyZ3VtZW50IGlzIHRydWUuIixsb2NhdGlvbnM6W2MuRklFTEQsYy5GUkFHTUVOVF9TUFJFQUQsYy5JTkxJTkVfRlJBR01FTlRdLGFyZ3M6e2lmOnt0eXBlOm5ldyBpLkdyYXBoUUxOb25OdWxsKG8uR3JhcGhRTEJvb2xlYW4pLGRlc2NyaXB0aW9uOiJTa2lwcGVkIHdoZW4gdHJ1ZS4ifX19KSxkPXQuREVGQVVMVF9ERVBSRUNBVElPTl9SRUFTT049Ik5vIGxvbmdlciBzdXBwb3J0ZWQiLGg9dC5HcmFwaFFMRGVwcmVjYXRlZERpcmVjdGl2ZT1uZXcgbCh7bmFtZToiZGVwcmVjYXRlZCIsZGVzY3JpcHRpb246Ik1hcmtzIGFuIGVsZW1lbnQgb2YgYSBHcmFwaFFMIHNjaGVtYSBhcyBubyBsb25nZXIgc3VwcG9ydGVkLiIsbG9jYXRpb25zOltjLkZJRUxEX0RFRklOSVRJT04sYy5FTlVNX1ZBTFVFXSxhcmdzOntyZWFzb246e3R5cGU6by5HcmFwaFFMU3RyaW5nLGRlc2NyaXB0aW9uOiJFeHBsYWlucyB3aHkgdGhpcyBlbGVtZW50IHdhcyBkZXByZWNhdGVkLCB1c3VhbGx5IGFsc28gaW5jbHVkaW5nIGEgc3VnZ2VzdGlvbiBmb3IgaG93IHRvIGFjY2VzcyBzdXBwb3J0ZWQgc2ltaWxhciBkYXRhLiBGb3JtYXR0ZWQgaW4gW01hcmtkb3duXShodHRwczovL2RhcmluZ2ZpcmViYWxsLm5ldC9wcm9qZWN0cy9tYXJrZG93bi8pLiIsZGVmYXVsdFZhbHVlOmR9fX0pO3Quc3BlY2lmaWVkRGlyZWN0aXZlcz1bcCxmLGhdfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlR5cGVOYW1lTWV0YUZpZWxkRGVmPXQuVHlwZU1ldGFGaWVsZERlZj10LlNjaGVtYU1ldGFGaWVsZERlZj10Ll9fVHlwZUtpbmQ9dC5UeXBlS2luZD10Ll9fRW51bVZhbHVlPXQuX19JbnB1dFZhbHVlPXQuX19GaWVsZD10Ll9fVHlwZT10Ll9fRGlyZWN0aXZlTG9jYXRpb249dC5fX0RpcmVjdGl2ZT10Ll9fU2NoZW1hPXZvaWQgMDt2YXIgcj1uKDU4KSxpPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0ociksbz1uKDExMiksYT1uKDE5KSxzPW4oNiksdT1uKDMyKSxjPW4oMjcpLGw9dC5fX1NjaGVtYT1uZXcgcy5HcmFwaFFMT2JqZWN0VHlwZSh7bmFtZToiX19TY2hlbWEiLGlzSW50cm9zcGVjdGlvbjohMCxkZXNjcmlwdGlvbjoiQSBHcmFwaFFMIFNjaGVtYSBkZWZpbmVzIHRoZSBjYXBhYmlsaXRpZXMgb2YgYSBHcmFwaFFMIHNlcnZlci4gSXQgZXhwb3NlcyBhbGwgYXZhaWxhYmxlIHR5cGVzIGFuZCBkaXJlY3RpdmVzIG9uIHRoZSBzZXJ2ZXIsIGFzIHdlbGwgYXMgdGhlIGVudHJ5IHBvaW50cyBmb3IgcXVlcnksIG11dGF0aW9uLCBhbmQgc3Vic2NyaXB0aW9uIG9wZXJhdGlvbnMuIixmaWVsZHM6ZnVuY3Rpb24oKXtyZXR1cm57dHlwZXM6e2Rlc2NyaXB0aW9uOiJBIGxpc3Qgb2YgYWxsIHR5cGVzIHN1cHBvcnRlZCBieSB0aGlzIHNlcnZlci4iLHR5cGU6bmV3IHMuR3JhcGhRTE5vbk51bGwobmV3IHMuR3JhcGhRTExpc3QobmV3IHMuR3JhcGhRTE5vbk51bGwoZCkpKSxyZXNvbHZlOmZ1bmN0aW9uKGUpe3ZhciB0PWUuZ2V0VHlwZU1hcCgpO3JldHVybiBPYmplY3Qua2V5cyh0KS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIHRbZV19KX19LHF1ZXJ5VHlwZTp7ZGVzY3JpcHRpb246IlRoZSB0eXBlIHRoYXQgcXVlcnkgb3BlcmF0aW9ucyB3aWxsIGJlIHJvb3RlZCBhdC4iLHR5cGU6bmV3IHMuR3JhcGhRTE5vbk51bGwoZCkscmVzb2x2ZTpmdW5jdGlvbihlKXtyZXR1cm4gZS5nZXRRdWVyeVR5cGUoKX19LG11dGF0aW9uVHlwZTp7ZGVzY3JpcHRpb246IklmIHRoaXMgc2VydmVyIHN1cHBvcnRzIG11dGF0aW9uLCB0aGUgdHlwZSB0aGF0IG11dGF0aW9uIG9wZXJhdGlvbnMgd2lsbCBiZSByb290ZWQgYXQuIix0eXBlOmQscmVzb2x2ZTpmdW5jdGlvbihlKXtyZXR1cm4gZS5nZXRNdXRhdGlvblR5cGUoKX19LHN1YnNjcmlwdGlvblR5cGU6e2Rlc2NyaXB0aW9uOiJJZiB0aGlzIHNlcnZlciBzdXBwb3J0IHN1YnNjcmlwdGlvbiwgdGhlIHR5cGUgdGhhdCBzdWJzY3JpcHRpb24gb3BlcmF0aW9ucyB3aWxsIGJlIHJvb3RlZCBhdC4iLHR5cGU6ZCxyZXNvbHZlOmZ1bmN0aW9uKGUpe3JldHVybiBlLmdldFN1YnNjcmlwdGlvblR5cGUoKX19LGRpcmVjdGl2ZXM6e2Rlc2NyaXB0aW9uOiJBIGxpc3Qgb2YgYWxsIGRpcmVjdGl2ZXMgc3VwcG9ydGVkIGJ5IHRoaXMgc2VydmVyLiIsdHlwZTpuZXcgcy5HcmFwaFFMTm9uTnVsbChuZXcgcy5HcmFwaFFMTGlzdChuZXcgcy5HcmFwaFFMTm9uTnVsbChwKSkpLHJlc29sdmU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZ2V0RGlyZWN0aXZlcygpfX19fX0pLHA9dC5fX0RpcmVjdGl2ZT1uZXcgcy5HcmFwaFFMT2JqZWN0VHlwZSh7bmFtZToiX19EaXJlY3RpdmUiLGlzSW50cm9zcGVjdGlvbjohMCxkZXNjcmlwdGlvbjoiQSBEaXJlY3RpdmUgcHJvdmlkZXMgYSB3YXkgdG8gZGVzY3JpYmUgYWx0ZXJuYXRlIHJ1bnRpbWUgZXhlY3V0aW9uIGFuZCB0eXBlIHZhbGlkYXRpb24gYmVoYXZpb3IgaW4gYSBHcmFwaFFMIGRvY3VtZW50LlxuXG5JbiBzb21lIGNhc2VzLCB5b3UgbmVlZCB0byBwcm92aWRlIG9wdGlvbnMgdG8gYWx0ZXIgR3JhcGhRTCdzIGV4ZWN1dGlvbiBiZWhhdmlvciBpbiB3YXlzIGZpZWxkIGFyZ3VtZW50cyB3aWxsIG5vdCBzdWZmaWNlLCBzdWNoIGFzIGNvbmRpdGlvbmFsbHkgaW5jbHVkaW5nIG9yIHNraXBwaW5nIGEgZmllbGQuIERpcmVjdGl2ZXMgcHJvdmlkZSB0aGlzIGJ5IGRlc2NyaWJpbmcgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiB0byB0aGUgZXhlY3V0b3IuIixmaWVsZHM6ZnVuY3Rpb24oKXtyZXR1cm57bmFtZTp7dHlwZTpuZXcgcy5HcmFwaFFMTm9uTnVsbCh1LkdyYXBoUUxTdHJpbmcpfSxkZXNjcmlwdGlvbjp7dHlwZTp1LkdyYXBoUUxTdHJpbmd9LGxvY2F0aW9uczp7dHlwZTpuZXcgcy5HcmFwaFFMTm9uTnVsbChuZXcgcy5HcmFwaFFMTGlzdChuZXcgcy5HcmFwaFFMTm9uTnVsbChmKSkpfSxhcmdzOnt0eXBlOm5ldyBzLkdyYXBoUUxOb25OdWxsKG5ldyBzLkdyYXBoUUxMaXN0KG5ldyBzLkdyYXBoUUxOb25OdWxsKG0pKSkscmVzb2x2ZTpmdW5jdGlvbihlKXtyZXR1cm4gZS5hcmdzfHxbXX19LG9uT3BlcmF0aW9uOntkZXByZWNhdGlvblJlYXNvbjoiVXNlIGBsb2NhdGlvbnNgLiIsdHlwZTpuZXcgcy5HcmFwaFFMTm9uTnVsbCh1LkdyYXBoUUxCb29sZWFuKSxyZXNvbHZlOmZ1bmN0aW9uKGUpe3JldHVybi0xIT09ZS5sb2NhdGlvbnMuaW5kZXhPZihjLkRpcmVjdGl2ZUxvY2F0aW9uLlFVRVJZKXx8LTEhPT1lLmxvY2F0aW9ucy5pbmRleE9mKGMuRGlyZWN0aXZlTG9jYXRpb24uTVVUQVRJT04pfHwtMSE9PWUubG9jYXRpb25zLmluZGV4T2YoYy5EaXJlY3RpdmVMb2NhdGlvbi5TVUJTQ1JJUFRJT04pfX0sb25GcmFnbWVudDp7ZGVwcmVjYXRpb25SZWFzb246IlVzZSBgbG9jYXRpb25zYC4iLHR5cGU6bmV3IHMuR3JhcGhRTE5vbk51bGwodS5HcmFwaFFMQm9vbGVhbikscmVzb2x2ZTpmdW5jdGlvbihlKXtyZXR1cm4tMSE9PWUubG9jYXRpb25zLmluZGV4T2YoYy5EaXJlY3RpdmVMb2NhdGlvbi5GUkFHTUVOVF9TUFJFQUQpfHwtMSE9PWUubG9jYXRpb25zLmluZGV4T2YoYy5EaXJlY3RpdmVMb2NhdGlvbi5JTkxJTkVfRlJBR01FTlQpfHwtMSE9PWUubG9jYXRpb25zLmluZGV4T2YoYy5EaXJlY3RpdmVMb2NhdGlvbi5GUkFHTUVOVF9ERUZJTklUSU9OKX19LG9uRmllbGQ6e2RlcHJlY2F0aW9uUmVhc29uOiJVc2UgYGxvY2F0aW9uc2AuIix0eXBlOm5ldyBzLkdyYXBoUUxOb25OdWxsKHUuR3JhcGhRTEJvb2xlYW4pLHJlc29sdmU6ZnVuY3Rpb24oZSl7cmV0dXJuLTEhPT1lLmxvY2F0aW9ucy5pbmRleE9mKGMuRGlyZWN0aXZlTG9jYXRpb24uRklFTEQpfX19fX0pLGY9dC5fX0RpcmVjdGl2ZUxvY2F0aW9uPW5ldyBzLkdyYXBoUUxFbnVtVHlwZSh7bmFtZToiX19EaXJlY3RpdmVMb2NhdGlvbiIsaXNJbnRyb3NwZWN0aW9uOiEwLGRlc2NyaXB0aW9uOiJBIERpcmVjdGl2ZSBjYW4gYmUgYWRqYWNlbnQgdG8gbWFueSBwYXJ0cyBvZiB0aGUgR3JhcGhRTCBsYW5ndWFnZSwgYSBfX0RpcmVjdGl2ZUxvY2F0aW9uIGRlc2NyaWJlcyBvbmUgc3VjaCBwb3NzaWJsZSBhZGphY2VuY2llcy4iLHZhbHVlczp7UVVFUlk6e3ZhbHVlOmMuRGlyZWN0aXZlTG9jYXRpb24uUVVFUlksZGVzY3JpcHRpb246IkxvY2F0aW9uIGFkamFjZW50IHRvIGEgcXVlcnkgb3BlcmF0aW9uLiJ9LE1VVEFUSU9OOnt2YWx1ZTpjLkRpcmVjdGl2ZUxvY2F0aW9uLk1VVEFUSU9OLGRlc2NyaXB0aW9uOiJMb2NhdGlvbiBhZGphY2VudCB0byBhIG11dGF0aW9uIG9wZXJhdGlvbi4ifSxTVUJTQ1JJUFRJT046e3ZhbHVlOmMuRGlyZWN0aXZlTG9jYXRpb24uU1VCU0NSSVBUSU9OLGRlc2NyaXB0aW9uOiJMb2NhdGlvbiBhZGphY2VudCB0byBhIHN1YnNjcmlwdGlvbiBvcGVyYXRpb24uIn0sRklFTEQ6e3ZhbHVlOmMuRGlyZWN0aXZlTG9jYXRpb24uRklFTEQsZGVzY3JpcHRpb246IkxvY2F0aW9uIGFkamFjZW50IHRvIGEgZmllbGQuIn0sRlJBR01FTlRfREVGSU5JVElPTjp7dmFsdWU6Yy5EaXJlY3RpdmVMb2NhdGlvbi5GUkFHTUVOVF9ERUZJTklUSU9OLGRlc2NyaXB0aW9uOiJMb2NhdGlvbiBhZGphY2VudCB0byBhIGZyYWdtZW50IGRlZmluaXRpb24uIn0sRlJBR01FTlRfU1BSRUFEOnt2YWx1ZTpjLkRpcmVjdGl2ZUxvY2F0aW9uLkZSQUdNRU5UX1NQUkVBRCxkZXNjcmlwdGlvbjoiTG9jYXRpb24gYWRqYWNlbnQgdG8gYSBmcmFnbWVudCBzcHJlYWQuIn0sSU5MSU5FX0ZSQUdNRU5UOnt2YWx1ZTpjLkRpcmVjdGl2ZUxvY2F0aW9uLklOTElORV9GUkFHTUVOVCxkZXNjcmlwdGlvbjoiTG9jYXRpb24gYWRqYWNlbnQgdG8gYW4gaW5saW5lIGZyYWdtZW50LiJ9LFNDSEVNQTp7dmFsdWU6Yy5EaXJlY3RpdmVMb2NhdGlvbi5TQ0hFTUEsZGVzY3JpcHRpb246IkxvY2F0aW9uIGFkamFjZW50IHRvIGEgc2NoZW1hIGRlZmluaXRpb24uIn0sU0NBTEFSOnt2YWx1ZTpjLkRpcmVjdGl2ZUxvY2F0aW9uLlNDQUxBUixkZXNjcmlwdGlvbjoiTG9jYXRpb24gYWRqYWNlbnQgdG8gYSBzY2FsYXIgZGVmaW5pdGlvbi4ifSxPQkpFQ1Q6e3ZhbHVlOmMuRGlyZWN0aXZlTG9jYXRpb24uT0JKRUNULGRlc2NyaXB0aW9uOiJMb2NhdGlvbiBhZGphY2VudCB0byBhbiBvYmplY3QgdHlwZSBkZWZpbml0aW9uLiJ9LEZJRUxEX0RFRklOSVRJT046e3ZhbHVlOmMuRGlyZWN0aXZlTG9jYXRpb24uRklFTERfREVGSU5JVElPTixkZXNjcmlwdGlvbjoiTG9jYXRpb24gYWRqYWNlbnQgdG8gYSBmaWVsZCBkZWZpbml0aW9uLiJ9LEFSR1VNRU5UX0RFRklOSVRJT046e3ZhbHVlOmMuRGlyZWN0aXZlTG9jYXRpb24uQVJHVU1FTlRfREVGSU5JVElPTixkZXNjcmlwdGlvbjoiTG9jYXRpb24gYWRqYWNlbnQgdG8gYW4gYXJndW1lbnQgZGVmaW5pdGlvbi4ifSxJTlRFUkZBQ0U6e3ZhbHVlOmMuRGlyZWN0aXZlTG9jYXRpb24uSU5URVJGQUNFLGRlc2NyaXB0aW9uOiJMb2NhdGlvbiBhZGphY2VudCB0byBhbiBpbnRlcmZhY2UgZGVmaW5pdGlvbi4ifSxVTklPTjp7dmFsdWU6Yy5EaXJlY3RpdmVMb2NhdGlvbi5VTklPTixkZXNjcmlwdGlvbjoiTG9jYXRpb24gYWRqYWNlbnQgdG8gYSB1bmlvbiBkZWZpbml0aW9uLiJ9LEVOVU06e3ZhbHVlOmMuRGlyZWN0aXZlTG9jYXRpb24uRU5VTSxkZXNjcmlwdGlvbjoiTG9jYXRpb24gYWRqYWNlbnQgdG8gYW4gZW51bSBkZWZpbml0aW9uLiJ9LEVOVU1fVkFMVUU6e3ZhbHVlOmMuRGlyZWN0aXZlTG9jYXRpb24uRU5VTV9WQUxVRSxkZXNjcmlwdGlvbjoiTG9jYXRpb24gYWRqYWNlbnQgdG8gYW4gZW51bSB2YWx1ZSBkZWZpbml0aW9uLiJ9LElOUFVUX09CSkVDVDp7dmFsdWU6Yy5EaXJlY3RpdmVMb2NhdGlvbi5JTlBVVF9PQkpFQ1QsZGVzY3JpcHRpb246IkxvY2F0aW9uIGFkamFjZW50IHRvIGFuIGlucHV0IG9iamVjdCB0eXBlIGRlZmluaXRpb24uIn0sSU5QVVRfRklFTERfREVGSU5JVElPTjp7dmFsdWU6Yy5EaXJlY3RpdmVMb2NhdGlvbi5JTlBVVF9GSUVMRF9ERUZJTklUSU9OLGRlc2NyaXB0aW9uOiJMb2NhdGlvbiBhZGphY2VudCB0byBhbiBpbnB1dCBvYmplY3QgZmllbGQgZGVmaW5pdGlvbi4ifX19KSxkPXQuX19UeXBlPW5ldyBzLkdyYXBoUUxPYmplY3RUeXBlKHtuYW1lOiJfX1R5cGUiLGlzSW50cm9zcGVjdGlvbjohMCxkZXNjcmlwdGlvbjoiVGhlIGZ1bmRhbWVudGFsIHVuaXQgb2YgYW55IEdyYXBoUUwgU2NoZW1hIGlzIHRoZSB0eXBlLiBUaGVyZSBhcmUgbWFueSBraW5kcyBvZiB0eXBlcyBpbiBHcmFwaFFMIGFzIHJlcHJlc2VudGVkIGJ5IHRoZSBgX19UeXBlS2luZGAgZW51bS5cblxuRGVwZW5kaW5nIG9uIHRoZSBraW5kIG9mIGEgdHlwZSwgY2VydGFpbiBmaWVsZHMgZGVzY3JpYmUgaW5mb3JtYXRpb24gYWJvdXQgdGhhdCB0eXBlLiBTY2FsYXIgdHlwZXMgcHJvdmlkZSBubyBpbmZvcm1hdGlvbiBiZXlvbmQgYSBuYW1lIGFuZCBkZXNjcmlwdGlvbiwgd2hpbGUgRW51bSB0eXBlcyBwcm92aWRlIHRoZWlyIHZhbHVlcy4gT2JqZWN0IGFuZCBJbnRlcmZhY2UgdHlwZXMgcHJvdmlkZSB0aGUgZmllbGRzIHRoZXkgZGVzY3JpYmUuIEFic3RyYWN0IHR5cGVzLCBVbmlvbiBhbmQgSW50ZXJmYWNlLCBwcm92aWRlIHRoZSBPYmplY3QgdHlwZXMgcG9zc2libGUgYXQgcnVudGltZS4gTGlzdCBhbmQgTm9uTnVsbCB0eXBlcyBjb21wb3NlIG90aGVyIHR5cGVzLiIsZmllbGRzOmZ1bmN0aW9uKCl7cmV0dXJue2tpbmQ6e3R5cGU6bmV3IHMuR3JhcGhRTE5vbk51bGwodikscmVzb2x2ZTpmdW5jdGlvbihlKXtpZihlIGluc3RhbmNlb2Ygcy5HcmFwaFFMU2NhbGFyVHlwZSlyZXR1cm4geS5TQ0FMQVI7aWYoZSBpbnN0YW5jZW9mIHMuR3JhcGhRTE9iamVjdFR5cGUpcmV0dXJuIHkuT0JKRUNUO2lmKGUgaW5zdGFuY2VvZiBzLkdyYXBoUUxJbnRlcmZhY2VUeXBlKXJldHVybiB5LklOVEVSRkFDRTtpZihlIGluc3RhbmNlb2Ygcy5HcmFwaFFMVW5pb25UeXBlKXJldHVybiB5LlVOSU9OO2lmKGUgaW5zdGFuY2VvZiBzLkdyYXBoUUxFbnVtVHlwZSlyZXR1cm4geS5FTlVNO2lmKGUgaW5zdGFuY2VvZiBzLkdyYXBoUUxJbnB1dE9iamVjdFR5cGUpcmV0dXJuIHkuSU5QVVRfT0JKRUNUO2lmKGUgaW5zdGFuY2VvZiBzLkdyYXBoUUxMaXN0KXJldHVybiB5LkxJU1Q7aWYoZSBpbnN0YW5jZW9mIHMuR3JhcGhRTE5vbk51bGwpcmV0dXJuIHkuTk9OX05VTEw7dGhyb3cgbmV3IEVycm9yKCJVbmtub3duIGtpbmQgb2YgdHlwZTogIitlKX19LG5hbWU6e3R5cGU6dS5HcmFwaFFMU3RyaW5nfSxkZXNjcmlwdGlvbjp7dHlwZTp1LkdyYXBoUUxTdHJpbmd9LGZpZWxkczp7dHlwZTpuZXcgcy5HcmFwaFFMTGlzdChuZXcgcy5HcmFwaFFMTm9uTnVsbChoKSksYXJnczp7aW5jbHVkZURlcHJlY2F0ZWQ6e3R5cGU6dS5HcmFwaFFMQm9vbGVhbixkZWZhdWx0VmFsdWU6ITF9fSxyZXNvbHZlOmZ1bmN0aW9uKGUsdCl7dmFyIG49dC5pbmNsdWRlRGVwcmVjYXRlZDtpZihlIGluc3RhbmNlb2Ygcy5HcmFwaFFMT2JqZWN0VHlwZXx8ZSBpbnN0YW5jZW9mIHMuR3JhcGhRTEludGVyZmFjZVR5cGUpe3ZhciByPWUuZ2V0RmllbGRzKCksaT1PYmplY3Qua2V5cyhyKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIHJbZV19KTtyZXR1cm4gbnx8KGk9aS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIWUuZGVwcmVjYXRpb25SZWFzb259KSksaX1yZXR1cm4gbnVsbH19LGludGVyZmFjZXM6e3R5cGU6bmV3IHMuR3JhcGhRTExpc3QobmV3IHMuR3JhcGhRTE5vbk51bGwoZCkpLHJlc29sdmU6ZnVuY3Rpb24oZSl7aWYoZSBpbnN0YW5jZW9mIHMuR3JhcGhRTE9iamVjdFR5cGUpcmV0dXJuIGUuZ2V0SW50ZXJmYWNlcygpfX0scG9zc2libGVUeXBlczp7dHlwZTpuZXcgcy5HcmFwaFFMTGlzdChuZXcgcy5HcmFwaFFMTm9uTnVsbChkKSkscmVzb2x2ZTpmdW5jdGlvbihlLHQsbixyKXt2YXIgaT1yLnNjaGVtYTtpZigoMCxzLmlzQWJzdHJhY3RUeXBlKShlKSlyZXR1cm4gaS5nZXRQb3NzaWJsZVR5cGVzKGUpfX0sZW51bVZhbHVlczp7dHlwZTpuZXcgcy5HcmFwaFFMTGlzdChuZXcgcy5HcmFwaFFMTm9uTnVsbChnKSksYXJnczp7aW5jbHVkZURlcHJlY2F0ZWQ6e3R5cGU6dS5HcmFwaFFMQm9vbGVhbixkZWZhdWx0VmFsdWU6ITF9fSxyZXNvbHZlOmZ1bmN0aW9uKGUsdCl7dmFyIG49dC5pbmNsdWRlRGVwcmVjYXRlZDtpZihlIGluc3RhbmNlb2Ygcy5HcmFwaFFMRW51bVR5cGUpe3ZhciByPWUuZ2V0VmFsdWVzKCk7cmV0dXJuIG58fChyPXIuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiFlLmRlcHJlY2F0aW9uUmVhc29ufSkpLHJ9fX0saW5wdXRGaWVsZHM6e3R5cGU6bmV3IHMuR3JhcGhRTExpc3QobmV3IHMuR3JhcGhRTE5vbk51bGwobSkpLHJlc29sdmU6ZnVuY3Rpb24oZSl7aWYoZSBpbnN0YW5jZW9mIHMuR3JhcGhRTElucHV0T2JqZWN0VHlwZSl7dmFyIHQ9ZS5nZXRGaWVsZHMoKTtyZXR1cm4gT2JqZWN0LmtleXModCkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiB0W2VdfSl9fX0sb2ZUeXBlOnt0eXBlOmR9fX19KSxoPXQuX19GaWVsZD1uZXcgcy5HcmFwaFFMT2JqZWN0VHlwZSh7bmFtZToiX19GaWVsZCIsaXNJbnRyb3NwZWN0aW9uOiEwLGRlc2NyaXB0aW9uOiJPYmplY3QgYW5kIEludGVyZmFjZSB0eXBlcyBhcmUgZGVzY3JpYmVkIGJ5IGEgbGlzdCBvZiBGaWVsZHMsIGVhY2ggb2Ygd2hpY2ggaGFzIGEgbmFtZSwgcG90ZW50aWFsbHkgYSBsaXN0IG9mIGFyZ3VtZW50cywgYW5kIGEgcmV0dXJuIHR5cGUuIixmaWVsZHM6ZnVuY3Rpb24oKXtyZXR1cm57bmFtZTp7dHlwZTpuZXcgcy5HcmFwaFFMTm9uTnVsbCh1LkdyYXBoUUxTdHJpbmcpfSxkZXNjcmlwdGlvbjp7dHlwZTp1LkdyYXBoUUxTdHJpbmd9LGFyZ3M6e3R5cGU6bmV3IHMuR3JhcGhRTE5vbk51bGwobmV3IHMuR3JhcGhRTExpc3QobmV3IHMuR3JhcGhRTE5vbk51bGwobSkpKSxyZXNvbHZlOmZ1bmN0aW9uKGUpe3JldHVybiBlLmFyZ3N8fFtdfX0sdHlwZTp7dHlwZTpuZXcgcy5HcmFwaFFMTm9uTnVsbChkKX0saXNEZXByZWNhdGVkOnt0eXBlOm5ldyBzLkdyYXBoUUxOb25OdWxsKHUuR3JhcGhRTEJvb2xlYW4pfSxkZXByZWNhdGlvblJlYXNvbjp7dHlwZTp1LkdyYXBoUUxTdHJpbmd9fX19KSxtPXQuX19JbnB1dFZhbHVlPW5ldyBzLkdyYXBoUUxPYmplY3RUeXBlKHtuYW1lOiJfX0lucHV0VmFsdWUiLGlzSW50cm9zcGVjdGlvbjohMCxkZXNjcmlwdGlvbjoiQXJndW1lbnRzIHByb3ZpZGVkIHRvIEZpZWxkcyBvciBEaXJlY3RpdmVzIGFuZCB0aGUgaW5wdXQgZmllbGRzIG9mIGFuIElucHV0T2JqZWN0IGFyZSByZXByZXNlbnRlZCBhcyBJbnB1dCBWYWx1ZXMgd2hpY2ggZGVzY3JpYmUgdGhlaXIgdHlwZSBhbmQgb3B0aW9uYWxseSBhIGRlZmF1bHQgdmFsdWUuIixmaWVsZHM6ZnVuY3Rpb24oKXtyZXR1cm57bmFtZTp7dHlwZTpuZXcgcy5HcmFwaFFMTm9uTnVsbCh1LkdyYXBoUUxTdHJpbmcpfSxkZXNjcmlwdGlvbjp7dHlwZTp1LkdyYXBoUUxTdHJpbmd9LHR5cGU6e3R5cGU6bmV3IHMuR3JhcGhRTE5vbk51bGwoZCl9LGRlZmF1bHRWYWx1ZTp7dHlwZTp1LkdyYXBoUUxTdHJpbmcsZGVzY3JpcHRpb246IkEgR3JhcGhRTC1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgZGVmYXVsdCB2YWx1ZSBmb3IgdGhpcyBpbnB1dCB2YWx1ZS4iLHJlc29sdmU6ZnVuY3Rpb24oZSl7cmV0dXJuKDAsaS5kZWZhdWx0KShlLmRlZmF1bHRWYWx1ZSk/bnVsbDooMCxhLnByaW50KSgoMCxvLmFzdEZyb21WYWx1ZSkoZS5kZWZhdWx0VmFsdWUsZS50eXBlKSl9fX19fSksZz10Ll9fRW51bVZhbHVlPW5ldyBzLkdyYXBoUUxPYmplY3RUeXBlKHtuYW1lOiJfX0VudW1WYWx1ZSIsaXNJbnRyb3NwZWN0aW9uOiEwLGRlc2NyaXB0aW9uOiJPbmUgcG9zc2libGUgdmFsdWUgZm9yIGEgZ2l2ZW4gRW51bS4gRW51bSB2YWx1ZXMgYXJlIHVuaXF1ZSB2YWx1ZXMsIG5vdCBhIHBsYWNlaG9sZGVyIGZvciBhIHN0cmluZyBvciBudW1lcmljIHZhbHVlLiBIb3dldmVyIGFuIEVudW0gdmFsdWUgaXMgcmV0dXJuZWQgaW4gYSBKU09OIHJlc3BvbnNlIGFzIGEgc3RyaW5nLiIsZmllbGRzOmZ1bmN0aW9uKCl7cmV0dXJue25hbWU6e3R5cGU6bmV3IHMuR3JhcGhRTE5vbk51bGwodS5HcmFwaFFMU3RyaW5nKX0sZGVzY3JpcHRpb246e3R5cGU6dS5HcmFwaFFMU3RyaW5nfSxpc0RlcHJlY2F0ZWQ6e3R5cGU6bmV3IHMuR3JhcGhRTE5vbk51bGwodS5HcmFwaFFMQm9vbGVhbil9LGRlcHJlY2F0aW9uUmVhc29uOnt0eXBlOnUuR3JhcGhRTFN0cmluZ319fX0pLHk9dC5UeXBlS2luZD17U0NBTEFSOiJTQ0FMQVIiLE9CSkVDVDoiT0JKRUNUIixJTlRFUkZBQ0U6IklOVEVSRkFDRSIsVU5JT046IlVOSU9OIixFTlVNOiJFTlVNIixJTlBVVF9PQkpFQ1Q6IklOUFVUX09CSkVDVCIsTElTVDoiTElTVCIsTk9OX05VTEw6Ik5PTl9OVUxMIn0sdj10Ll9fVHlwZUtpbmQ9bmV3IHMuR3JhcGhRTEVudW1UeXBlKHtuYW1lOiJfX1R5cGVLaW5kIixpc0ludHJvc3BlY3Rpb246ITAsZGVzY3JpcHRpb246IkFuIGVudW0gZGVzY3JpYmluZyB3aGF0IGtpbmQgb2YgdHlwZSBhIGdpdmVuIGBfX1R5cGVgIGlzLiIsdmFsdWVzOntTQ0FMQVI6e3ZhbHVlOnkuU0NBTEFSLGRlc2NyaXB0aW9uOiJJbmRpY2F0ZXMgdGhpcyB0eXBlIGlzIGEgc2NhbGFyLiJ9LE9CSkVDVDp7dmFsdWU6eS5PQkpFQ1QsZGVzY3JpcHRpb246IkluZGljYXRlcyB0aGlzIHR5cGUgaXMgYW4gb2JqZWN0LiBgZmllbGRzYCBhbmQgYGludGVyZmFjZXNgIGFyZSB2YWxpZCBmaWVsZHMuIn0sSU5URVJGQUNFOnt2YWx1ZTp5LklOVEVSRkFDRSxkZXNjcmlwdGlvbjoiSW5kaWNhdGVzIHRoaXMgdHlwZSBpcyBhbiBpbnRlcmZhY2UuIGBmaWVsZHNgIGFuZCBgcG9zc2libGVUeXBlc2AgYXJlIHZhbGlkIGZpZWxkcy4ifSxVTklPTjp7dmFsdWU6eS5VTklPTixkZXNjcmlwdGlvbjoiSW5kaWNhdGVzIHRoaXMgdHlwZSBpcyBhIHVuaW9uLiBgcG9zc2libGVUeXBlc2AgaXMgYSB2YWxpZCBmaWVsZC4ifSxFTlVNOnt2YWx1ZTp5LkVOVU0sZGVzY3JpcHRpb246IkluZGljYXRlcyB0aGlzIHR5cGUgaXMgYW4gZW51bS4gYGVudW1WYWx1ZXNgIGlzIGEgdmFsaWQgZmllbGQuIn0sSU5QVVRfT0JKRUNUOnt2YWx1ZTp5LklOUFVUX09CSkVDVCxkZXNjcmlwdGlvbjoiSW5kaWNhdGVzIHRoaXMgdHlwZSBpcyBhbiBpbnB1dCBvYmplY3QuIGBpbnB1dEZpZWxkc2AgaXMgYSB2YWxpZCBmaWVsZC4ifSxMSVNUOnt2YWx1ZTp5LkxJU1QsZGVzY3JpcHRpb246IkluZGljYXRlcyB0aGlzIHR5cGUgaXMgYSBsaXN0LiBgb2ZUeXBlYCBpcyBhIHZhbGlkIGZpZWxkLiJ9LE5PTl9OVUxMOnt2YWx1ZTp5Lk5PTl9OVUxMLGRlc2NyaXB0aW9uOiJJbmRpY2F0ZXMgdGhpcyB0eXBlIGlzIGEgbm9uLW51bGwuIGBvZlR5cGVgIGlzIGEgdmFsaWQgZmllbGQuIn19fSk7dC5TY2hlbWFNZXRhRmllbGREZWY9e25hbWU6Il9fc2NoZW1hIix0eXBlOm5ldyBzLkdyYXBoUUxOb25OdWxsKGwpLGRlc2NyaXB0aW9uOiJBY2Nlc3MgdGhlIGN1cnJlbnQgdHlwZSBzY2hlbWEgb2YgdGhpcyBzZXJ2ZXIuIixhcmdzOltdLHJlc29sdmU6ZnVuY3Rpb24oZSx0LG4scil7cmV0dXJuIHIuc2NoZW1hfX0sdC5UeXBlTWV0YUZpZWxkRGVmPXtuYW1lOiJfX3R5cGUiLHR5cGU6ZCxkZXNjcmlwdGlvbjoiUmVxdWVzdCB0aGUgdHlwZSBpbmZvcm1hdGlvbiBvZiBhIHNpbmdsZSB0eXBlLiIsYXJnczpbe25hbWU6Im5hbWUiLHR5cGU6bmV3IHMuR3JhcGhRTE5vbk51bGwodS5HcmFwaFFMU3RyaW5nKX1dLHJlc29sdmU6ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9dC5uYW1lO3JldHVybiByLnNjaGVtYS5nZXRUeXBlKGkpfX0sdC5UeXBlTmFtZU1ldGFGaWVsZERlZj17bmFtZToiX190eXBlbmFtZSIsdHlwZTpuZXcgcy5HcmFwaFFMTm9uTnVsbCh1LkdyYXBoUUxTdHJpbmcpLGRlc2NyaXB0aW9uOiJUaGUgbmFtZSBvZiB0aGUgY3VycmVudCBPYmplY3QgdHlwZSBhdCBydW50aW1lLiIsYXJnczpbXSxyZXNvbHZlOmZ1bmN0aW9uKGUsdCxuLHIpe3JldHVybiByLnBhcmVudFR5cGUubmFtZX19fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2YXIgbj12b2lkIDA7cmV0dXJuIHQua2luZD09PXMuTElTVF9UWVBFPyhuPWMoZSx0LnR5cGUpKSYmbmV3IHUuR3JhcGhRTExpc3Qobik6dC5raW5kPT09cy5OT05fTlVMTF9UWVBFPyhuPWMoZSx0LnR5cGUpKSYmbmV3IHUuR3JhcGhRTE5vbk51bGwobik6KHQua2luZCE9PXMuTkFNRURfVFlQRSYmKDAsby5kZWZhdWx0KSgwLCJNdXN0IGJlIGEgbmFtZWQgdHlwZS4iKSxlLmdldFR5cGUodC5uYW1lLnZhbHVlKSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQudHlwZUZyb21BU1Q9dm9pZCAwO3ZhciBpPW4oMTMpLG89ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShpKSxhPW4oMTApLHM9ZnVuY3Rpb24oZSl7aWYoZSYmZS5fX2VzTW9kdWxlKXJldHVybiBlO3ZhciB0PXt9O2lmKG51bGwhPWUpZm9yKHZhciBuIGluIGUpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUsbikmJih0W25dPWVbbl0pO3JldHVybiB0LmRlZmF1bHQ9ZSx0fShhKSx1PW4oNiksYz10LnR5cGVGcm9tQVNUPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe2lmKCJ1bmRlZmluZWQiIT09dHlwZW9mIF9fUkVBQ1RfREVWVE9PTFNfR0xPQkFMX0hPT0tfXyYmImZ1bmN0aW9uIj09PXR5cGVvZiBfX1JFQUNUX0RFVlRPT0xTX0dMT0JBTF9IT09LX18uY2hlY2tEQ0UpdHJ5e19fUkVBQ1RfREVWVE9PTFNfR0xPQkFMX0hPT0tfXy5jaGVja0RDRShyKX1jYXRjaChlKXtjb25zb2xlLmVycm9yKGUpfX1yKCksZS5leHBvcnRzPW4oMzE0KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBudWxsIT1lJiYib2JqZWN0Ij09dHlwZW9mIGV9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZigiIj09PWUpdGhyb3cgbmV3IFR5cGVFcnJvcigiSW50IGNhbm5vdCByZXByZXNlbnQgbm9uIDMyLWJpdCBzaWduZWQgaW50ZWdlciB2YWx1ZTogKGVtcHR5IHN0cmluZykiKTt2YXIgdD1OdW1iZXIoZSk7aWYodCE9PXR8fHQ+Y3x8dDxsKXRocm93IG5ldyBUeXBlRXJyb3IoIkludCBjYW5ub3QgcmVwcmVzZW50IG5vbiAzMi1iaXQgc2lnbmVkIGludGVnZXIgdmFsdWU6ICIrU3RyaW5nKGUpKTt2YXIgbj1NYXRoLmZsb29yKHQpO2lmKG4hPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIkludCBjYW5ub3QgcmVwcmVzZW50IG5vbi1pbnRlZ2VyIHZhbHVlOiAiK1N0cmluZyhlKSk7cmV0dXJuIG59ZnVuY3Rpb24gaShlKXtpZigiIj09PWUpdGhyb3cgbmV3IFR5cGVFcnJvcigiRmxvYXQgY2Fubm90IHJlcHJlc2VudCBub24gbnVtZXJpYyB2YWx1ZTogKGVtcHR5IHN0cmluZykiKTt2YXIgdD1OdW1iZXIoZSk7aWYodD09PXQpcmV0dXJuIHQ7dGhyb3cgbmV3IFR5cGVFcnJvcigiRmxvYXQgY2Fubm90IHJlcHJlc2VudCBub24gbnVtZXJpYyB2YWx1ZTogIitTdHJpbmcoZSkpfWZ1bmN0aW9uIG8oZSl7aWYoQXJyYXkuaXNBcnJheShlKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJTdHJpbmcgY2Fubm90IHJlcHJlc2VudCBhbiBhcnJheSB2YWx1ZTogWyIrU3RyaW5nKGUpKyJdIik7cmV0dXJuIFN0cmluZyhlKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5HcmFwaFFMSUQ9dC5HcmFwaFFMQm9vbGVhbj10LkdyYXBoUUxTdHJpbmc9dC5HcmFwaFFMRmxvYXQ9dC5HcmFwaFFMSW50PXZvaWQgMDt2YXIgYT1uKDYpLHM9bigxMCksdT1mdW5jdGlvbihlKXtpZihlJiZlLl9fZXNNb2R1bGUpcmV0dXJuIGU7dmFyIHQ9e307aWYobnVsbCE9ZSlmb3IodmFyIG4gaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxuKSYmKHRbbl09ZVtuXSk7cmV0dXJuIHQuZGVmYXVsdD1lLHR9KHMpLGM9MjE0NzQ4MzY0NyxsPS0yMTQ3NDgzNjQ4O3QuR3JhcGhRTEludD1uZXcgYS5HcmFwaFFMU2NhbGFyVHlwZSh7bmFtZToiSW50IixkZXNjcmlwdGlvbjoiVGhlIGBJbnRgIHNjYWxhciB0eXBlIHJlcHJlc2VudHMgbm9uLWZyYWN0aW9uYWwgc2lnbmVkIHdob2xlIG51bWVyaWMgdmFsdWVzLiBJbnQgY2FuIHJlcHJlc2VudCB2YWx1ZXMgYmV0d2VlbiAtKDJeMzEpIGFuZCAyXjMxIC0gMS4gIixzZXJpYWxpemU6cixwYXJzZVZhbHVlOnIscGFyc2VMaXRlcmFsOmZ1bmN0aW9uKGUpe2lmKGUua2luZD09PXUuSU5UKXt2YXIgdD1wYXJzZUludChlLnZhbHVlLDEwKTtpZih0PD1jJiZ0Pj1sKXJldHVybiB0fXJldHVybiBudWxsfX0pLHQuR3JhcGhRTEZsb2F0PW5ldyBhLkdyYXBoUUxTY2FsYXJUeXBlKHtuYW1lOiJGbG9hdCIsZGVzY3JpcHRpb246IlRoZSBgRmxvYXRgIHNjYWxhciB0eXBlIHJlcHJlc2VudHMgc2lnbmVkIGRvdWJsZS1wcmVjaXNpb24gZnJhY3Rpb25hbCB2YWx1ZXMgYXMgc3BlY2lmaWVkIGJ5IFtJRUVFIDc1NF0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JRUVFX2Zsb2F0aW5nX3BvaW50KS4gIixzZXJpYWxpemU6aSxwYXJzZVZhbHVlOmkscGFyc2VMaXRlcmFsOmZ1bmN0aW9uKGUpe3JldHVybiBlLmtpbmQ9PT11LkZMT0FUfHxlLmtpbmQ9PT11LklOVD9wYXJzZUZsb2F0KGUudmFsdWUpOm51bGx9fSksdC5HcmFwaFFMU3RyaW5nPW5ldyBhLkdyYXBoUUxTY2FsYXJUeXBlKHtuYW1lOiJTdHJpbmciLGRlc2NyaXB0aW9uOiJUaGUgYFN0cmluZ2Agc2NhbGFyIHR5cGUgcmVwcmVzZW50cyB0ZXh0dWFsIGRhdGEsIHJlcHJlc2VudGVkIGFzIFVURi04IGNoYXJhY3RlciBzZXF1ZW5jZXMuIFRoZSBTdHJpbmcgdHlwZSBpcyBtb3N0IG9mdGVuIHVzZWQgYnkgR3JhcGhRTCB0byByZXByZXNlbnQgZnJlZS1mb3JtIGh1bWFuLXJlYWRhYmxlIHRleHQuIixzZXJpYWxpemU6byxwYXJzZVZhbHVlOm8scGFyc2VMaXRlcmFsOmZ1bmN0aW9uKGUpe3JldHVybiBlLmtpbmQ9PT11LlNUUklORz9lLnZhbHVlOm51bGx9fSksdC5HcmFwaFFMQm9vbGVhbj1uZXcgYS5HcmFwaFFMU2NhbGFyVHlwZSh7bmFtZToiQm9vbGVhbiIsZGVzY3JpcHRpb246IlRoZSBgQm9vbGVhbmAgc2NhbGFyIHR5cGUgcmVwcmVzZW50cyBgdHJ1ZWAgb3IgYGZhbHNlYC4iLHNlcmlhbGl6ZTpCb29sZWFuLHBhcnNlVmFsdWU6Qm9vbGVhbixwYXJzZUxpdGVyYWw6ZnVuY3Rpb24oZSl7cmV0dXJuIGUua2luZD09PXUuQk9PTEVBTj9lLnZhbHVlOm51bGx9fSksdC5HcmFwaFFMSUQ9bmV3IGEuR3JhcGhRTFNjYWxhclR5cGUoe25hbWU6IklEIixkZXNjcmlwdGlvbjonVGhlIGBJRGAgc2NhbGFyIHR5cGUgcmVwcmVzZW50cyBhIHVuaXF1ZSBpZGVudGlmaWVyLCBvZnRlbiB1c2VkIHRvIHJlZmV0Y2ggYW4gb2JqZWN0IG9yIGFzIGtleSBmb3IgYSBjYWNoZS4gVGhlIElEIHR5cGUgYXBwZWFycyBpbiBhIEpTT04gcmVzcG9uc2UgYXMgYSBTdHJpbmc7IGhvd2V2ZXIsIGl0IGlzIG5vdCBpbnRlbmRlZCB0byBiZSBodW1hbi1yZWFkYWJsZS4gV2hlbiBleHBlY3RlZCBhcyBhbiBpbnB1dCB0eXBlLCBhbnkgc3RyaW5nIChzdWNoIGFzIGAiNCJgKSBvciBpbnRlZ2VyIChzdWNoIGFzIGA0YCkgaW5wdXQgdmFsdWUgd2lsbCBiZSBhY2NlcHRlZCBhcyBhbiBJRC4nLHNlcmlhbGl6ZTpTdHJpbmcscGFyc2VWYWx1ZTpTdHJpbmcscGFyc2VMaXRlcmFsOmZ1bmN0aW9uKGUpe3JldHVybiBlLmtpbmQ9PT11LlNUUklOR3x8ZS5raW5kPT09dS5JTlQ/ZS52YWx1ZTpudWxsfX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG51bGw9PWU/dm9pZCAwPT09ZT91OnM6YyYmYyBpbiBPYmplY3QoZSk/T2JqZWN0KG8uYSkoZSk6T2JqZWN0KGEuYSkoZSl9dmFyIGk9bigxMDMpLG89bigzNDkpLGE9bigzNTApLHM9IltvYmplY3QgTnVsbF0iLHU9IltvYmplY3QgVW5kZWZpbmVkXSIsYz1pLmE/aS5hLnRvU3RyaW5nVGFnOnZvaWQgMDt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKCl7dmFyIGU9YXJndW1lbnRzLmxlbmd0aD4wJiZ2b2lkIDAhPT1hcmd1bWVudHNbMF0/YXJndW1lbnRzWzBdOiIqIjtpZihhcmd1bWVudHMubGVuZ3RoJiZPYmplY3Qody5oKShhcmd1bWVudHNbMF0sdy5xLm5vdFVuZGVmLCJ0YWtlKHBhdHRlcm5PckNoYW5uZWwpOiBwYXR0ZXJuT3JDaGFubmVsIGlzIHVuZGVmaW5lZCIpLHcucS5wYXR0ZXJuKGUpKXJldHVybiBHKEEse3BhdHRlcm46ZX0pO2lmKHcucS5jaGFubmVsKGUpKXJldHVybiBHKEEse2NoYW5uZWw6ZX0pO3Rocm93IG5ldyBFcnJvcigidGFrZShwYXR0ZXJuT3JDaGFubmVsKTogYXJndW1lbnQgIitTdHJpbmcoZSkrIiBpcyBub3QgdmFsaWQgY2hhbm5lbCBvciBhIHZhbGlkIHBhdHRlcm4iKX1mdW5jdGlvbiBpKGUsdCl7cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGg+MT8oT2JqZWN0KHcuaCkoZSx3LnEubm90VW5kZWYsInB1dChjaGFubmVsLCBhY3Rpb24pOiBhcmd1bWVudCBjaGFubmVsIGlzIHVuZGVmaW5lZCIpLE9iamVjdCh3LmgpKGUsdy5xLmNoYW5uZWwsInB1dChjaGFubmVsLCBhY3Rpb24pOiBhcmd1bWVudCAiK2UrIiBpcyBub3QgYSB2YWxpZCBjaGFubmVsIiksT2JqZWN0KHcuaCkodCx3LnEubm90VW5kZWYsInB1dChjaGFubmVsLCBhY3Rpb24pOiBhcmd1bWVudCBhY3Rpb24gaXMgdW5kZWZpbmVkIikpOihPYmplY3Qody5oKShlLHcucS5ub3RVbmRlZiwicHV0KGFjdGlvbik6IGFyZ3VtZW50IGFjdGlvbiBpcyB1bmRlZmluZWQiKSx0PWUsZT1udWxsKSxHKF8se2NoYW5uZWw6ZSxhY3Rpb246dH0pfWZ1bmN0aW9uIG8oZSl7cmV0dXJuIEcoVCxlKX1mdW5jdGlvbiBhKGUpe3JldHVybiBHKE8sZSl9ZnVuY3Rpb24gcyhlLHQsbil7T2JqZWN0KHcuaCkodCx3LnEubm90VW5kZWYsZSsiOiBhcmd1bWVudCBmbiBpcyB1bmRlZmluZWQiKTt2YXIgcj1udWxsO2lmKHcucS5hcnJheSh0KSl7dmFyIGk9dDtyPWlbMF0sdD1pWzFdfWVsc2UgaWYodC5mbil7dmFyIG89dDtyPW8uY29udGV4dCx0PW8uZm59cmV0dXJuIHImJncucS5zdHJpbmcodCkmJncucS5mdW5jKHJbdF0pJiYodD1yW3RdKSxPYmplY3Qody5oKSh0LHcucS5mdW5jLGUrIjogYXJndW1lbnQgIit0KyIgaXMgbm90IGEgZnVuY3Rpb24iKSx7Y29udGV4dDpyLGZuOnQsYXJnczpufX1mdW5jdGlvbiB1KGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49QXJyYXkodD4xP3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBHKEYscygiY2FsbCIsZSxuKSl9ZnVuY3Rpb24gYyhlLHQpe3ZhciBuPWFyZ3VtZW50cy5sZW5ndGg+MiYmdm9pZCAwIT09YXJndW1lbnRzWzJdP2FyZ3VtZW50c1syXTpbXTtyZXR1cm4gRyhGLHMoImFwcGx5Iix7Y29udGV4dDplLGZuOnR9LG4pKX1mdW5jdGlvbiBsKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49QXJyYXkodD4xP3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBHKE4scygiY3BzIixlLG4pKX1mdW5jdGlvbiBwKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49QXJyYXkodD4xP3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBHKEkscygiZm9yayIsZSxuKSl9ZnVuY3Rpb24gZihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPUFycmF5KHQ+MT90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTtyZXR1cm4gVihwLmFwcGx5KHZvaWQgMCxbZV0uY29uY2F0KG4pKSl9ZnVuY3Rpb24gZCgpe2Zvcih2YXIgZT1hcmd1bWVudHMubGVuZ3RoLHQ9QXJyYXkoZSksbj0wO248ZTtuKyspdFtuXT1hcmd1bWVudHNbbl07aWYodC5sZW5ndGg+MSlyZXR1cm4gbyh0Lm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZChlKX0pKTt2YXIgcj10WzBdO3JldHVybiBPYmplY3Qody5oKShyLHcucS5ub3RVbmRlZiwiam9pbih0YXNrKTogYXJndW1lbnQgdGFzayBpcyB1bmRlZmluZWQiKSxPYmplY3Qody5oKShyLHcucS50YXNrLCJqb2luKHRhc2spOiBhcmd1bWVudCAiK3IrIiBpcyBub3QgYSB2YWxpZCBUYXNrIG9iamVjdCAiK3opLEcoTCxyKX1mdW5jdGlvbiBoKCl7Zm9yKHZhciBlPWFyZ3VtZW50cy5sZW5ndGgsdD1BcnJheShlKSxuPTA7bjxlO24rKyl0W25dPWFyZ3VtZW50c1tuXTtpZih0Lmxlbmd0aD4xKXJldHVybiBvKHQubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBoKGUpfSkpO3ZhciByPXRbMF07cmV0dXJuIDE9PT10Lmxlbmd0aCYmKE9iamVjdCh3LmgpKHIsdy5xLm5vdFVuZGVmLCJjYW5jZWwodGFzayk6IGFyZ3VtZW50IHRhc2sgaXMgdW5kZWZpbmVkIiksT2JqZWN0KHcuaCkocix3LnEudGFzaywiY2FuY2VsKHRhc2spOiBhcmd1bWVudCAiK3IrIiBpcyBub3QgYSB2YWxpZCBUYXNrIG9iamVjdCAiK3opKSxHKFAscnx8dy5kKX1mdW5jdGlvbiBtKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49QXJyYXkodD4xP3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiAwPT09YXJndW1lbnRzLmxlbmd0aD9lPXcubzooT2JqZWN0KHcuaCkoZSx3LnEubm90VW5kZWYsInNlbGVjdChzZWxlY3RvcixbLi4uXSk6IGFyZ3VtZW50IHNlbGVjdG9yIGlzIHVuZGVmaW5lZCIpLE9iamVjdCh3LmgpKGUsdy5xLmZ1bmMsInNlbGVjdChzZWxlY3RvcixbLi4uXSk6IGFyZ3VtZW50ICIrZSsiIGlzIG5vdCBhIGZ1bmN0aW9uIikpLEcoTSx7c2VsZWN0b3I6ZSxhcmdzOm59KX1mdW5jdGlvbiBnKGUsdCl7cmV0dXJuIE9iamVjdCh3LmgpKGUsdy5xLm5vdFVuZGVmLCJhY3Rpb25DaGFubmVsKHBhdHRlcm4sLi4uKTogYXJndW1lbnQgcGF0dGVybiBpcyB1bmRlZmluZWQiKSxhcmd1bWVudHMubGVuZ3RoPjEmJihPYmplY3Qody5oKSh0LHcucS5ub3RVbmRlZiwiYWN0aW9uQ2hhbm5lbChwYXR0ZXJuLCBidWZmZXIpOiBhcmd1bWVudCBidWZmZXIgaXMgdW5kZWZpbmVkIiksT2JqZWN0KHcuaCkodCx3LnEuYnVmZmVyLCJhY3Rpb25DaGFubmVsKHBhdHRlcm4sIGJ1ZmZlcik6IGFyZ3VtZW50ICIrdCsiIGlzIG5vdCBhIHZhbGlkIGJ1ZmZlciIpKSxHKGose3BhdHRlcm46ZSxidWZmZXI6dH0pfWZ1bmN0aW9uIHkoKXtyZXR1cm4gRyhSLHt9KX1mdW5jdGlvbiB2KGUpe3JldHVybiBPYmplY3Qody5oKShlLHcucS5jaGFubmVsLCJmbHVzaChjaGFubmVsKTogYXJndW1lbnQgIitlKyIgaXMgbm90IHZhbGlkIGNoYW5uZWwiKSxHKEIsZSl9ZnVuY3Rpb24gYihlKXtyZXR1cm4gT2JqZWN0KHcuaCkoZSx3LnEuc3RyaW5nLCJnZXRDb250ZXh0KHByb3ApOiBhcmd1bWVudCAiK2UrIiBpcyBub3QgYSBzdHJpbmciKSxHKCQsZSl9ZnVuY3Rpb24geChlKXtyZXR1cm4gT2JqZWN0KHcuaCkoZSx3LnEub2JqZWN0LE9iamVjdCh3LmspKG51bGwsZSkpLEcoVSxlKX1mdW5jdGlvbiBDKGUsdCl7Zm9yKHZhciBuPWFyZ3VtZW50cy5sZW5ndGgscj1BcnJheShuPjI/bi0yOjApLGk9MjtpPG47aSsrKXJbaS0yXT1hcmd1bWVudHNbaV07cmV0dXJuIHAuYXBwbHkodm9pZCAwLFtTLmIsZSx0XS5jb25jYXQocikpfWZ1bmN0aW9uIEUoZSx0KXtmb3IodmFyIG49YXJndW1lbnRzLmxlbmd0aCxyPUFycmF5KG4+Mj9uLTI6MCksaT0yO2k8bjtpKyspcltpLTJdPWFyZ3VtZW50c1tpXTtyZXR1cm4gcC5hcHBseSh2b2lkIDAsW1MuZCxlLHRdLmNvbmNhdChyKSl9ZnVuY3Rpb24gRChlLHQsbil7Zm9yKHZhciByPWFyZ3VtZW50cy5sZW5ndGgsaT1BcnJheShyPjM/ci0zOjApLG89MztvPHI7bysrKWlbby0zXT1hcmd1bWVudHNbb107cmV0dXJuIHAuYXBwbHkodm9pZCAwLFtTLmYsZSx0LG5dLmNvbmNhdChpKSl9bi5kKHQsImkiLGZ1bmN0aW9uKCl7cmV0dXJuIFZ9KSx0LnM9cixuLmQodCwidiIsZnVuY3Rpb24oKXtyZXR1cm4gcX0pLHQubj1pLHQuYj1vLHQubz1hLHQuZT11LHQuYz1jLHQuaD1sLHQuaz1wLHQucj1mLHQubT1kLHQuZj1oLHQucD1tLHQuYT1nLHQuZz15LHQuaj12LHQubD1iLHQucT14LHQudD1DLHQudT1FLHQudz1ELG4uZCh0LCJkIixmdW5jdGlvbigpe3JldHVybiBXfSk7dmFyIHc9bigyMiksUz1uKDE2OSksaz1PYmplY3Qody54KSgiSU8iKSxBPSJUQUtFIixfPSJQVVQiLFQ9IkFMTCIsTz0iUkFDRSIsRj0iQ0FMTCIsTj0iQ1BTIixJPSJGT1JLIixMPSJKT0lOIixQPSJDQU5DRUwiLE09IlNFTEVDVCIsaj0iQUNUSU9OX0NIQU5ORUwiLFI9IkNBTkNFTExFRCIsQj0iRkxVU0giLCQ9IkdFVF9DT05URVhUIixVPSJTRVRfQ09OVEVYVCIsej0iXG4oSElOVDogaWYgeW91IGFyZSBnZXR0aW5nIHRoaXMgZXJyb3JzIGluIHRlc3RzLCBjb25zaWRlciB1c2luZyBjcmVhdGVNb2NrVGFzayBmcm9tIHJlZHV4LXNhZ2EvdXRpbHMpIixHPWZ1bmN0aW9uKGUsdCl7dmFyIG47cmV0dXJuIG49e30sbltrXT0hMCxuW2VdPXQsbn0sVj1mdW5jdGlvbihlKXtyZXR1cm4gT2JqZWN0KHcuaCkoVy5mb3JrKGUpLHcucS5vYmplY3QsImRldGFjaChlZmYpOiBhcmd1bWVudCBtdXN0IGJlIGEgZm9yayBlZmZlY3QiKSxlW0ldLmRldGFjaGVkPSEwLGV9O3IubWF5YmU9ZnVuY3Rpb24oKXt2YXIgZT1yLmFwcGx5KHZvaWQgMCxhcmd1bWVudHMpO3JldHVybiBlW0FdLm1heWJlPSEwLGV9O3ZhciBxPU9iamVjdCh3Lm4pKHIubWF5YmUsT2JqZWN0KHcueikoInRha2VtIiwidGFrZS5tYXliZSIpKTtpLnJlc29sdmU9ZnVuY3Rpb24oKXt2YXIgZT1pLmFwcGx5KHZvaWQgMCxhcmd1bWVudHMpO3JldHVybiBlW19dLnJlc29sdmU9ITAsZX0saS5zeW5jPU9iamVjdCh3Lm4pKGkucmVzb2x2ZSxPYmplY3Qody56KSgicHV0LnN5bmMiLCJwdXQucmVzb2x2ZSIpKTt2YXIgSD1mdW5jdGlvbihlKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIHQmJnRba10mJnRbZV19fSxXPXt0YWtlOkgoQSkscHV0OkgoXyksYWxsOkgoVCkscmFjZTpIKE8pLGNhbGw6SChGKSxjcHM6SChOKSxmb3JrOkgoSSksam9pbjpIKEwpLGNhbmNlbDpIKFApLHNlbGVjdDpIKE0pLGFjdGlvbkNoYW5uZWw6SChqKSxjYW5jZWxsZWQ6SChSKSxmbHVzaDpIKEIpLGdldENvbnRleHQ6SCgkKSxzZXRDb250ZXh0OkgoVSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG51bGw9PT1lfHx2b2lkIDA9PT1lfHxlIT09ZX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm57aWQ6aSgpLHF1ZXJ5OnQuZGVmYXVsdFF1ZXJ5LHZhcmlhYmxlczoiIixyZXNwb25zZXM6YS5MaXN0KFtdKSxlbmRwb2ludDplLG9wZXJhdGlvbk5hbWU6dm9pZCAwLGhhc011dGF0aW9uOiExLGhhc1N1YnNjcmlwdGlvbjohMSxoYXNRdWVyeTohMSxxdWVyeVR5cGVzOm8uZ2V0UXVlcnlUeXBlcyh0LmRlZmF1bHRRdWVyeSksc3Vic2NyaXB0aW9uQWN0aXZlOiExLGRhdGU6bmV3IERhdGUsc3RhcnJlZDohMSxxdWVyeVJ1bm5pbmc6ITEsb3BlcmF0aW9uczphLkxpc3QoW10pLGlzUmVsb2FkaW5nU2NoZW1hOiExLGlzU2NoZW1hUGVuZGluZ1VwZGF0ZTohMSxyZXNwb25zZUV4dGVuc2lvbnM6e30scXVlcnlWYXJpYWJsZXNBY3RpdmU6ITEsZW5kcG9pbnRVbnJlYWNoYWJsZTohMSxlZGl0b3JGbGV4OjEsdmFyaWFibGVFZGl0b3JPcGVuOiExLHZhcmlhYmxlRWRpdG9ySGVpZ2h0OjIwMCxyZXNwb25zZVRyYWNpbmdPcGVuOiExLHJlc3BvbnNlVHJhY2luZ0hlaWdodDozMDAsZG9jRXhwbG9yZXJXaWR0aDozNTAsdmFyaWFibGVUb1R5cGU6YS5NYXAoe30pLGhlYWRlcnM6IiIsZmlsZTp2b2lkIDAsaXNGaWxlOiExLG5hbWU6dm9pZCAwLGZpbGVQYXRoOnZvaWQgMCxzZWxlY3RlZFVzZXJUb2tlbjp2b2lkIDAsaGFzQ2hhbmdlZDp2b2lkIDAsYWJzb2x1dGVQYXRoOnZvaWQgMCxpc1NldHRpbmdzVGFiOnZvaWQgMCxpc0NvbmZpZ1RhYjp2b2lkIDAsY3VycmVudFF1ZXJ5U3RhcnRUaW1lOnZvaWQgMCxjdXJyZW50UXVlcnlFbmRUaW1lOnZvaWQgMCxuZXh0UXVlcnlTdGFydFRpbWU6dm9pZCAwLHRyYWNpbmdTdXBwb3J0ZWQ6dm9pZCAwLGNoYW5nZWQ6dm9pZCAwLHNjcm9sbFRvcDp2b2lkIDB9fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDY0KSxvPW4oMjQ1KSxhPW4oMTQpO3QuY29sdW1uV2lkdGg9MzAwLHQuaW50cm9zcGVjdGlvblF1ZXJ5PSJcbiAgcXVlcnkgSW50cm9zcGVjdGlvblF1ZXJ5IHtcbiAgICBfX3NjaGVtYSB7XG4gICAgICBxdWVyeVR5cGUgeyBuYW1lIH1cbiAgICAgIG11dGF0aW9uVHlwZSB7IG5hbWUgfVxuICAgICAgc3Vic2NyaXB0aW9uVHlwZSB7IG5hbWUgfVxuICAgICAgdHlwZXMge1xuICAgICAgICAuLi5GdWxsVHlwZVxuICAgICAgfVxuICAgICAgZGlyZWN0aXZlcyB7XG4gICAgICAgIG5hbWVcbiAgICAgICAgZGVzY3JpcHRpb25cbiAgICAgICAgbG9jYXRpb25zXG4gICAgICAgIGFyZ3Mge1xuICAgICAgICAgIC4uLklucHV0VmFsdWVcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGZyYWdtZW50IEZ1bGxUeXBlIG9uIF9fVHlwZSB7XG4gICAga2luZFxuICAgIG5hbWVcbiAgICBkZXNjcmlwdGlvblxuICAgIGZpZWxkcyhpbmNsdWRlRGVwcmVjYXRlZDogdHJ1ZSkge1xuICAgICAgbmFtZVxuICAgICAgZGVzY3JpcHRpb25cbiAgICAgIGFyZ3Mge1xuICAgICAgICAuLi5JbnB1dFZhbHVlXG4gICAgICB9XG4gICAgICB0eXBlIHtcbiAgICAgICAgLi4uVHlwZVJlZlxuICAgICAgfVxuICAgICAgaXNEZXByZWNhdGVkXG4gICAgICBkZXByZWNhdGlvblJlYXNvblxuICAgIH1cbiAgICBpbnB1dEZpZWxkcyB7XG4gICAgICAuLi5JbnB1dFZhbHVlXG4gICAgfVxuICAgIGludGVyZmFjZXMge1xuICAgICAgLi4uVHlwZVJlZlxuICAgIH1cbiAgICBlbnVtVmFsdWVzKGluY2x1ZGVEZXByZWNhdGVkOiB0cnVlKSB7XG4gICAgICBuYW1lXG4gICAgICBkZXNjcmlwdGlvblxuICAgICAgaXNEZXByZWNhdGVkXG4gICAgICBkZXByZWNhdGlvblJlYXNvblxuICAgIH1cbiAgICBwb3NzaWJsZVR5cGVzIHtcbiAgICAgIC4uLlR5cGVSZWZcbiAgICB9XG4gIH1cblxuICBmcmFnbWVudCBJbnB1dFZhbHVlIG9uIF9fSW5wdXRWYWx1ZSB7XG4gICAgbmFtZVxuICAgIGRlc2NyaXB0aW9uXG4gICAgdHlwZSB7IC4uLlR5cGVSZWYgfVxuICAgIGRlZmF1bHRWYWx1ZVxuICB9XG5cbiAgZnJhZ21lbnQgVHlwZVJlZiBvbiBfX1R5cGUge1xuICAgIGtpbmRcbiAgICBuYW1lXG4gICAgb2ZUeXBlIHtcbiAgICAgIGtpbmRcbiAgICAgIG5hbWVcbiAgICAgIG9mVHlwZSB7XG4gICAgICAgIGtpbmRcbiAgICAgICAgbmFtZVxuICAgICAgICBvZlR5cGUge1xuICAgICAgICAgIGtpbmRcbiAgICAgICAgICBuYW1lXG4gICAgICAgICAgb2ZUeXBlIHtcbiAgICAgICAgICAgIGtpbmRcbiAgICAgICAgICAgIG5hbWVcbiAgICAgICAgICAgIG9mVHlwZSB7XG4gICAgICAgICAgICAgIGtpbmRcbiAgICAgICAgICAgICAgbmFtZVxuICAgICAgICAgICAgICBvZlR5cGUge1xuICAgICAgICAgICAgICAgIGtpbmRcbiAgICAgICAgICAgICAgICBuYW1lXG4gICAgICAgICAgICAgICAgb2ZUeXBlIHtcbiAgICAgICAgICAgICAgICAgIGtpbmRcbiAgICAgICAgICAgICAgICAgIG5hbWVcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiIsdC5kZWZhdWx0UXVlcnk9IiMgV3JpdGUgeW91ciBxdWVyeSBvciBtdXRhdGlvbiBoZXJlXG4iLHQubW9kYWxTdHlsZT17b3ZlcmxheTp7ekluZGV4Ojk5OTk5LGJhY2tncm91bmRDb2xvcjoicmdiYSgxNSwzMiw0NiwuOSkiLGRpc3BsYXk6ImZsZXgiLGFsaWduSXRlbXM6ImNlbnRlciIsanVzdGlmeUNvbnRlbnQ6ImNlbnRlciJ9LGNvbnRlbnQ6e3Bvc2l0aW9uOiJyZWxhdGl2ZSIsd2lkdGg6OTc2LGhlaWdodDoiYXV0byIsdG9wOiJpbml0aWFsIixsZWZ0OiJpbml0aWFsIixyaWdodDoiaW5pdGlhbCIsYm90dG9tOiJpbml0aWFsIixib3JkZXJSYWRpdXM6MixwYWRkaW5nOjAsYm9yZGVyOiJub25lIixiYWNrZ3JvdW5kOiJub25lIixib3hTaGFkb3c6IjAgMXB4IDdweCByZ2JhKDAsMCwwLC4yKSJ9fSx0LmdldERlZmF1bHRTZXNzaW9uPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigwKSxvPW4oMSksYT1vLnN0eWxlZC5kaXYobHx8KGw9cihbIlxuICAvKiBDb21tZW50ICovXG4gIC5jbS1jb21tZW50IHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogUHVuY3R1YXRpb24gKi9cbiAgLmNtLXB1bmN0dWF0aW9uIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogUHJvcHBlcnkgKi9cbiAgLmNtLXByb3BlcnR5IHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogS2V5d29yZCAqL1xuICAuY20ta2V5d29yZCB7XG4gICAgY29sb3I6ICIsIjtcbiAgfVxuXG4gIC8qIE9wZXJhdGlvbk5hbWUsIEZyYWdtZW50TmFtZSAqL1xuICAuY20tZGVmIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogRmllbGRBbGlhcyAqL1xuICAuY20tcXVhbGlmaWVyIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogQXJndW1lbnROYW1lIGFuZCBPYmplY3RGaWVsZE5hbWUgKi9cbiAgLmNtLWF0dHJpYnV0ZSB7XG4gICAgY29sb3I6ICIsIjtcbiAgfVxuXG4gIC8qIE51bWJlciAqL1xuICAuY20tbnVtYmVyIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogU3RyaW5nICovXG4gIC5jbS1zdHJpbmcge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBCb29sZWFuICovXG4gIC5jbS1idWlsdGluIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogRW51bVZhbHVlICovXG4gIC5jbS1zdHJpbmctMiB7XG4gICAgY29sb3I6ICIsIjtcbiAgfVxuXG4gIC8qIFZhcmlhYmxlICovXG4gIC5jbS12YXJpYWJsZSB7XG4gICAgY29sb3I6ICIsIjtcbiAgfVxuXG4gIC8qIERpcmVjdGl2ZSAqL1xuICAuY20tbWV0YSB7XG4gICAgY29sb3I6ICIsIjtcbiAgfVxuXG4gIC8qIFR5cGUgKi9cbiAgLmNtLWF0b20ge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBDb21tYSAqL1xuICAuY20td3Mge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4OiAxIDEgMCU7XG4gIGZsZXgtZmxvdzogY29sdW1uO1xuXG4gIC5Db2RlTWlycm9yIHtcbiAgICBjb2xvcjogcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjMpO1xuICAgIGZvbnQtZmFtaWx5OiAiLCI7XG4gICAgZm9udC1zaXplOiAiLCI7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIGxlZnQ6IDA7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHRvcDogMDtcbiAgICB3aWR0aDogMTAwJTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbmVzIHtcbiAgICBwYWRkaW5nOiAyMHB4IDA7XG4gIH1cblxuICAuQ29kZU1pcnJvci1ndXR0ZXJzIHtcbiAgICBib3JkZXItcmlnaHQ6IG5vbmU7XG4gIH1cblxuICAuQ29kZU1pcnJvciBzcGFuW3JvbGU9J3ByZXNlbnRhdGlvbiddIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogQ1VSU09SICovXG5cbiAgLkNvZGVNaXJyb3IgZGl2LkNvZGVNaXJyb3ItY3Vyc29yIHtcbiAgICBiYWNrZ3JvdW5kOiAiLCI7XG4gICAgYm9yZGVyLWxlZnQ6ICIsIjtcbiAgICBib3JkZXItYm90dG9tOiAiLCI7XG4gIH1cbiAgLyogU2hvd24gd2hlbiBtb3ZpbmcgaW4gYmktZGlyZWN0aW9uYWwgdGV4dCAqL1xuICAuQ29kZU1pcnJvciBkaXYuQ29kZU1pcnJvci1zZWNvbmRhcnljdXJzb3Ige1xuICAgIGJvcmRlci1sZWZ0OiAxcHggc29saWQgc2lsdmVyO1xuICB9XG4gIC5Db2RlTWlycm9yLmNtLWZhdC1jdXJzb3IgZGl2LkNvZGVNaXJyb3ItY3Vyc29yIHtcbiAgICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDAuNik7XG4gICAgY29sb3I6IHdoaXRlO1xuICAgIGJvcmRlcjogMDtcbiAgICB3aWR0aDogYXV0bztcbiAgfVxuICAuQ29kZU1pcnJvci5jbS1mYXQtY3Vyc29yIGRpdi5Db2RlTWlycm9yLWN1cnNvcnMge1xuICAgIHotaW5kZXg6IDE7XG4gIH1cblxuICAuY20tYW5pbWF0ZS1mYXQtY3Vyc29yIHtcbiAgICAtd2Via2l0LWFuaW1hdGlvbjogYmxpbmsgMS4wNnMgc3RlcHMoMSkgaW5maW5pdGU7XG4gICAgYW5pbWF0aW9uOiBibGluayAxLjA2cyBzdGVwcygxKSBpbmZpbml0ZTtcbiAgICBib3JkZXI6IDA7XG4gICAgd2lkdGg6IGF1dG87XG4gIH1cbiAgQC13ZWJraXQta2V5ZnJhbWVzIGJsaW5rIHtcbiAgICAwJSB7XG4gICAgICBiYWNrZ3JvdW5kOiAjN2U3O1xuICAgIH1cbiAgICA1MCUge1xuICAgICAgYmFja2dyb3VuZDogbm9uZTtcbiAgICB9XG4gICAgMTAwJSB7XG4gICAgICBiYWNrZ3JvdW5kOiAjN2U3O1xuICAgIH1cbiAgfVxuICBAa2V5ZnJhbWVzIGJsaW5rIHtcbiAgICAwJSB7XG4gICAgICBiYWNrZ3JvdW5kOiAjN2U3O1xuICAgIH1cbiAgICA1MCUge1xuICAgICAgYmFja2dyb3VuZDogbm9uZTtcbiAgICB9XG4gICAgMTAwJSB7XG4gICAgICBiYWNrZ3JvdW5kOiAjN2U3O1xuICAgIH1cbiAgfVxuXG4gIC5Db2RlTWlycm9yLWZvbGRtYXJrZXIge1xuICAgIGJvcmRlci1yYWRpdXM6IDRweDtcbiAgICBiYWNrZ3JvdW5kOiAjMDhmO1xuICAgIGJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCgjNDNhOGZmLCAjMGY4M2U4KTtcbiAgICBib3gtc2hhZG93OiAwIDFweCAxcHggcmdiYSgwLCAwLCAwLCAwLjIpLCBpbnNldCAwIDAgMCAxcHggcmdiYSgwLCAwLCAwLCAwLjEpO1xuICAgIGNvbG9yOiB3aGl0ZTtcbiAgICBmb250LWZhbWlseTogYXJpYWw7XG4gICAgZm9udC1zaXplOiAxMnB4O1xuICAgIGxpbmUtaGVpZ2h0OiAwO1xuICAgIG1hcmdpbjogMCAzcHg7XG4gICAgcGFkZGluZzogMHB4IDRweCAxcHg7XG4gICAgdGV4dC1zaGFkb3c6IDAgLTFweCByZ2JhKDAsIDAsIDAsIDAuMSk7XG4gIH1cblxuICBkaXYuQ29kZU1pcnJvciBzcGFuLkNvZGVNaXJyb3ItbWF0Y2hpbmdicmFja2V0IHtcbiAgICAvKiBjb2xvcjogcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjQpOyAqL1xuICAgIHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lO1xuICB9XG5cbiAgZGl2LkNvZGVNaXJyb3Igc3Bhbi5Db2RlTWlycm9yLW5vbm1hdGNoaW5nYnJhY2tldCB7XG4gICAgY29sb3I6IHJnYigyNDIsIDkyLCA4NCk7XG4gIH1cblxuICAudG9vbGJhci1idXR0b24ge1xuICAgIGJhY2tncm91bmQ6ICNmZGZkZmQ7XG4gICAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KCNmYmZiZmIsICNmOGY4ZjgpO1xuICAgIGJvcmRlci1jb2xvcjogI2QzZDNkMyAjZDBkMGQwICNiYWJhYmE7XG4gICAgYm9yZGVyLXJhZGl1czogNHB4O1xuICAgIGJvcmRlci1zdHlsZTogc29saWQ7XG4gICAgYm9yZGVyLXdpZHRoOiAwLjVweDtcbiAgICBib3gtc2hhZG93OiAwIDFweCAxcHggLTFweCByZ2JhKDAsIDAsIDAsIDAuMTMpLCBpbnNldCAwIDFweCAjZmZmO1xuICAgIGNvbG9yOiAjNDQ0O1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgbWFyZ2luOiAwIDVweCAwO1xuICAgIHBhZGRpbmc6IDJweCA4cHggNHB4O1xuICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTtcbiAgfVxuICAudG9vbGJhci1idXR0b246YWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQoI2VjZWNlYywgI2Q4ZDhkOCk7XG4gICAgYm9yZGVyLWNvbG9yOiAjY2FjYWNhICNjOWM5YzkgI2IwYjBiMDtcbiAgICBib3gtc2hhZG93OiAwIDFweCAwICNmZmYsIGluc2V0IDAgMXB4IHJnYmEoMjU1LCAyNTUsIDI1NSwgMC4yKSxcbiAgICAgIGluc2V0IDAgMXB4IDFweCByZ2JhKDAsIDAsIDAsIDAuMDgpO1xuICB9XG4gIC50b29sYmFyLWJ1dHRvbi5lcnJvciB7XG4gICAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KCNmZGYzZjMsICNlNmQ2ZDcpO1xuICAgIGNvbG9yOiAjYjAwO1xuICB9XG5cbiAgLmF1dG9JbnNlcnRlZExlYWYuY20tcHJvcGVydHkge1xuICAgIC13ZWJraXQtYW5pbWF0aW9uLWR1cmF0aW9uOiA2cztcbiAgICBhbmltYXRpb24tZHVyYXRpb246IDZzO1xuICAgIC13ZWJraXQtYW5pbWF0aW9uLW5hbWU6IGluc2VydGlvbkZhZGU7XG4gICAgYW5pbWF0aW9uLW5hbWU6IGluc2VydGlvbkZhZGU7XG4gICAgYm9yZGVyLWJvdHRvbTogMnB4IHNvbGlkIHJnYmEoMjU1LCAyNTUsIDI1NSwgMCk7XG4gICAgYm9yZGVyLXJhZGl1czogMnB4O1xuICAgIG1hcmdpbjogLTJweCAtNHB4IC0xcHg7XG4gICAgcGFkZGluZzogMnB4IDRweCAxcHg7XG4gIH1cblxuICBALXdlYmtpdC1rZXlmcmFtZXMgaW5zZXJ0aW9uRmFkZSB7XG4gICAgZnJvbSxcbiAgICB0byB7XG4gICAgICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDApO1xuICAgICAgYm9yZGVyLWNvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDApO1xuICAgIH1cblxuICAgIDE1JSxcbiAgICA4NSUge1xuICAgICAgYmFja2dyb3VuZDogI2ZiZmZjOTtcbiAgICAgIGJvcmRlci1jb2xvcjogI2YwZjNjMDtcbiAgICB9XG4gIH1cblxuICBAa2V5ZnJhbWVzIGluc2VydGlvbkZhZGUge1xuICAgIGZyb20sXG4gICAgdG8ge1xuICAgICAgYmFja2dyb3VuZDogcmdiYSgyNTUsIDI1NSwgMjU1LCAwKTtcbiAgICAgIGJvcmRlci1jb2xvcjogcmdiYSgyNTUsIDI1NSwgMjU1LCAwKTtcbiAgICB9XG5cbiAgICAxNSUsXG4gICAgODUlIHtcbiAgICAgIGJhY2tncm91bmQ6ICNmYmZmYzk7XG4gICAgICBib3JkZXItY29sb3I6ICNmMGYzYzA7XG4gICAgfVxuICB9XG5cbiAgLkNvZGVNaXJyb3IgcHJlIHtcbiAgICBwYWRkaW5nOiAwIDRweDsgLyogSG9yaXpvbnRhbCBwYWRkaW5nIG9mIGNvbnRlbnQgKi9cbiAgfVxuXG4gIC5Db2RlTWlycm9yLXNjcm9sbGJhci1maWxsZXIsXG4gIC5Db2RlTWlycm9yLWd1dHRlci1maWxsZXIge1xuICAgIGJhY2tncm91bmQtY29sb3I6IHdoaXRlOyAvKiBUaGUgbGl0dGxlIHNxdWFyZSBiZXR3ZWVuIEggYW5kIFYgc2Nyb2xsYmFycyAqL1xuICB9XG5cbiAgLyogR1VUVEVSICovXG5cbiAgLkNvZGVNaXJyb3ItZ3V0dGVycyB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgYm9yZGVyOiBub25lO1xuICAgIHdoaXRlLXNwYWNlOiBub3dyYXA7XG4gIH1cbiAgLkNvZGVNaXJyb3ItbGluZW51bWJlcnMge1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgfVxuICAuQ29kZU1pcnJvci1saW5lbnVtYmVyIHtcbiAgICBmb250LWZhbWlseTogT3BlbiBTYW5zLCBzYW5zLXNlcmlmO1xuICAgIGZvbnQtd2VpZ2h0OiA2MDA7XG4gICAgZm9udC1zaXplOiAiLCI7XG4gICAgY29sb3I6ICIsIjtcbiAgICBtaW4td2lkdGg6IDIwcHg7XG4gICAgcGFkZGluZzogMCAzcHggMCA1cHg7XG4gICAgdGV4dC1hbGlnbjogcmlnaHQ7XG4gICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWd1dHRlcm1hcmtlciB7XG4gICAgY29sb3I6IGJsYWNrO1xuICB9XG4gIC5Db2RlTWlycm9yLWd1dHRlcm1hcmtlci1zdWJ0bGUge1xuICAgIGNvbG9yOiAjOTk5O1xuICB9XG5cbiAgLmNtLXRhYiB7XG4gICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICAgIHRleHQtZGVjb3JhdGlvbjogaW5oZXJpdDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLXJ1bGVyIHtcbiAgICBib3JkZXItbGVmdDogMXB4IHNvbGlkICNjY2M7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICB9XG4gIC5jbS1uZWdhdGl2ZSB7XG4gICAgY29sb3I6ICNkNDQ7XG4gIH1cbiAgLmNtLXBvc2l0aXZlIHtcbiAgICBjb2xvcjogIzI5MjtcbiAgfVxuICAuY20taGVhZGVyLFxuICAuY20tc3Ryb25nIHtcbiAgICBmb250LXdlaWdodDogYm9sZDtcbiAgfVxuICAuY20tZW0ge1xuICAgIGZvbnQtc3R5bGU6IGl0YWxpYztcbiAgfVxuICAuY20tbGluayB7XG4gICAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7XG4gIH1cbiAgLmNtLXN0cmlrZXRocm91Z2gge1xuICAgIHRleHQtZGVjb3JhdGlvbjogbGluZS10aHJvdWdoO1xuICB9XG5cbiAgLmNtLXMtZGVmYXVsdCAuY20tZXJyb3Ige1xuICAgIGNvbG9yOiAjZjAwO1xuICB9XG4gIC5jbS1pbnZhbGlkY2hhciB7XG4gICAgY29sb3I6ICNmMDA7XG4gIH1cblxuICAuQ29kZU1pcnJvci1jb21wb3Npbmcge1xuICAgIGJvcmRlci1ib3R0b206IDJweCBzb2xpZDtcbiAgfVxuICAuQ29kZU1pcnJvci1tYXRjaGluZ3RhZyB7XG4gICAgYmFja2dyb3VuZDogcmdiYSgyNTUsIDE1MCwgMCwgMC4zKTtcbiAgfVxuICAuQ29kZU1pcnJvci1hY3RpdmVsaW5lLWJhY2tncm91bmQge1xuICAgIGJhY2tncm91bmQ6ICNlOGYyZmY7XG4gIH1cblxuICAvKiBUaGUgcmVzdCBvZiB0aGlzIGZpbGUgY29udGFpbnMgc3R5bGVzIHJlbGF0ZWQgdG8gdGhlIG1lY2hhbmljcyBvZlxuICAgdGhlIGVkaXRvci4gWW91IHByb2JhYmx5IHNob3VsZG4ndCB0b3VjaCB0aGVtLiAqL1xuXG4gIC5Db2RlTWlycm9yIHtcbiAgICBiYWNrZ3JvdW5kOiB3aGl0ZTtcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIGxpbmUtaGVpZ2h0OiAxLjY7XG4gIH1cblxuICAuQ29kZU1pcnJvci1zY3JvbGwge1xuICAgIGhlaWdodDogMTAwJTtcbiAgICAvKiAzMHB4IGlzIHRoZSBtYWdpYyBtYXJnaW4gdXNlZCB0byBoaWRlIHRoZSBlbGVtZW50J3MgcmVhbCBzY3JvbGxiYXJzICovXG4gICAgLyogU2VlIG92ZXJmbG93OiBoaWRkZW4gaW4gLkNvZGVNaXJyb3IgKi9cbiAgICAvKiBtYXJnaW4tYm90dG9tOiAtMzBweDtcbiAgICBtYXJnaW4tcmlnaHQ6IC0zMHB4OyAqL1xuICAgIG91dGxpbmU6IG5vbmU7IC8qIFByZXZlbnQgZHJhZ2dpbmcgZnJvbSBoaWdobGlnaHRpbmcgdGhlIGVsZW1lbnQgKi9cbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIC8qIHBhZGRpbmctYm90dG9tOiAzMHB4OyAqL1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICAmOmhvdmVyIHtcbiAgICAgIG92ZXJmbG93OiBzY3JvbGwgIWltcG9ydGFudDtcbiAgICB9XG4gIH1cbiAgLkNvZGVNaXJyb3Itc2l6ZXIge1xuICAgIGJvcmRlci1yaWdodDogMzBweCBzb2xpZCB0cmFuc3BhcmVudDtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIH1cblxuICAvKiBUaGUgZmFrZSwgdmlzaWJsZSBzY3JvbGxiYXJzLiBVc2VkIHRvIGZvcmNlIHJlZHJhdyBkdXJpbmcgc2Nyb2xsaW5nXG4gICBiZWZvcmUgYWN0dWFsIHNjcm9sbGluZyBoYXBwZW5zLCB0aHVzIHByZXZlbnRpbmcgc2hha2luZyBhbmRcbiAgIGZsaWNrZXJpbmcgYXJ0aWZhY3RzLiAqL1xuICAuQ29kZU1pcnJvci12c2Nyb2xsYmFyLFxuICAuQ29kZU1pcnJvci1oc2Nyb2xsYmFyLFxuICAuQ29kZU1pcnJvci1zY3JvbGxiYXItZmlsbGVyLFxuICAuQ29kZU1pcnJvci1ndXR0ZXItZmlsbGVyIHtcbiAgICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHotaW5kZXg6IDY7XG4gIH1cbiAgLkNvZGVNaXJyb3ItdnNjcm9sbGJhciB7XG4gICAgb3ZlcmZsb3cteDogaGlkZGVuO1xuICAgIG92ZXJmbG93LXk6IHNjcm9sbDtcbiAgICByaWdodDogMDtcbiAgICB0b3A6IDA7XG4gIH1cbiAgLkNvZGVNaXJyb3ItaHNjcm9sbGJhciB7XG4gICAgYm90dG9tOiAwO1xuICAgIGxlZnQ6IDA7XG4gICAgb3ZlcmZsb3cteDogc2Nyb2xsO1xuICAgIG92ZXJmbG93LXk6IGhpZGRlbjtcbiAgfVxuICAuQ29kZU1pcnJvci1zY3JvbGxiYXItZmlsbGVyIHtcbiAgICByaWdodDogMDtcbiAgICBib3R0b206IDA7XG4gIH1cbiAgLkNvZGVNaXJyb3ItZ3V0dGVyLWZpbGxlciB7XG4gICAgbGVmdDogMDtcbiAgICBib3R0b206IDA7XG4gIH1cblxuICAuQ29kZU1pcnJvci1ndXR0ZXJzIHtcbiAgICBtaW4taGVpZ2h0OiAxMDAlO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICBsZWZ0OiAwO1xuICAgIHRvcDogMDtcbiAgICB6LWluZGV4OiAzO1xuICAgIG1hcmdpbi1sZWZ0OiAzcHg7XG4gIH1cbiAgLkNvZGVNaXJyb3ItZ3V0dGVyIHtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIG1hcmdpbi1ib3R0b206IC0zMHB4O1xuICAgIHZlcnRpY2FsLWFsaWduOiB0b3A7XG4gICAgd2hpdGUtc3BhY2U6IG5vcm1hbDtcbiAgICAvKiBIYWNrIHRvIG1ha2UgSUU3IGJlaGF2ZSAqL1xuICAgICp6b29tOiAxO1xuICAgICpkaXNwbGF5OiBpbmxpbmU7XG4gIH1cbiAgLkNvZGVNaXJyb3ItZ3V0dGVyLXdyYXBwZXIge1xuICAgIGJhY2tncm91bmQ6IG5vbmUgIWltcG9ydGFudDtcbiAgICBib3JkZXI6IG5vbmUgIWltcG9ydGFudDtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgei1pbmRleDogNDtcbiAgfVxuICAuQ29kZU1pcnJvci1ndXR0ZXItYmFja2dyb3VuZCB7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHRvcDogMDtcbiAgICBib3R0b206IDA7XG4gICAgei1pbmRleDogNDtcbiAgfVxuICAuQ29kZU1pcnJvci1ndXR0ZXItZWx0IHtcbiAgICBjdXJzb3I6IGRlZmF1bHQ7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHotaW5kZXg6IDQ7XG4gIH1cbiAgLkNvZGVNaXJyb3ItZ3V0dGVyLXdyYXBwZXIge1xuICAgIC13ZWJraXQtdXNlci1zZWxlY3Q6IG5vbmU7XG4gICAgLW1vei11c2VyLXNlbGVjdDogbm9uZTtcbiAgICAtbXMtdXNlci1zZWxlY3Q6IG5vbmU7XG4gICAgdXNlci1zZWxlY3Q6IG5vbmU7XG4gIH1cblxuICAuQ29kZU1pcnJvci1saW5lcyB7XG4gICAgY3Vyc29yOiB0ZXh0O1xuICAgIG1pbi1oZWlnaHQ6IDFweDsgLyogcHJldmVudHMgY29sbGFwc2luZyBiZWZvcmUgZmlyc3QgZHJhdyAqL1xuICB9XG4gIC5Db2RlTWlycm9yIHByZSB7XG4gICAgLXdlYmtpdC10YXAtaGlnaGxpZ2h0LWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICAvKiBSZXNldCBzb21lIHN0eWxlcyB0aGF0IHRoZSByZXN0IG9mIHRoZSBwYWdlIG1pZ2h0IGhhdmUgc2V0ICovXG4gICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XG4gICAgYm9yZGVyLXJhZGl1czogMDtcbiAgICBib3JkZXItd2lkdGg6IDA7XG4gICAgY29sb3I6IGluaGVyaXQ7XG4gICAgZm9udC1mYW1pbHk6IGluaGVyaXQ7XG4gICAgZm9udC1zaXplOiBpbmhlcml0O1xuICAgIC13ZWJraXQtZm9udC12YXJpYW50LWxpZ2F0dXJlczogbm9uZTtcbiAgICBmb250LXZhcmlhbnQtbGlnYXR1cmVzOiBub25lO1xuICAgIGxpbmUtaGVpZ2h0OiBpbmhlcml0O1xuICAgIG1hcmdpbjogMDtcbiAgICBvdmVyZmxvdzogdmlzaWJsZTtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgd2hpdGUtc3BhY2U6IHByZTtcbiAgICB3b3JkLXdyYXA6IG5vcm1hbDtcbiAgICB6LWluZGV4OiAyO1xuICB9XG4gIC5Db2RlTWlycm9yLXdyYXAgcHJlIHtcbiAgICB3b3JkLXdyYXA6IGJyZWFrLXdvcmQ7XG4gICAgd2hpdGUtc3BhY2U6IHByZS13cmFwO1xuICAgIHdvcmQtYnJlYWs6IG5vcm1hbDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbmViYWNrZ3JvdW5kIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgbGVmdDogMDtcbiAgICByaWdodDogMDtcbiAgICB0b3A6IDA7XG4gICAgYm90dG9tOiAwO1xuICAgIHotaW5kZXg6IDA7XG4gIH1cblxuICAuQ29kZU1pcnJvci1saW5ld2lkZ2V0IHtcbiAgICBvdmVyZmxvdzogYXV0bztcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgei1pbmRleDogMjtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLXdpZGdldCB7XG4gIH1cblxuICAuQ29kZU1pcnJvci1jb2RlIHtcbiAgICBvdXRsaW5lOiBub25lO1xuICB9XG5cbiAgLyogRm9yY2UgY29udGVudC1ib3ggc2l6aW5nIGZvciB0aGUgZWxlbWVudHMgd2hlcmUgd2UgZXhwZWN0IGl0ICovXG4gIC5Db2RlTWlycm9yLXNjcm9sbCxcbiAgLkNvZGVNaXJyb3Itc2l6ZXIsXG4gIC5Db2RlTWlycm9yLWd1dHRlcixcbiAgLkNvZGVNaXJyb3ItZ3V0dGVycyxcbiAgLkNvZGVNaXJyb3ItbGluZW51bWJlciB7XG4gICAgYm94LXNpemluZzogY29udGVudC1ib3g7XG4gIH1cblxuICAuQ29kZU1pcnJvci1tZWFzdXJlIHtcbiAgICBoZWlnaHQ6IDA7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgdmlzaWJpbGl0eTogaGlkZGVuO1xuICAgIHdpZHRoOiAxMDAlO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItY3Vyc29yIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIH1cbiAgLkNvZGVNaXJyb3ItbWVhc3VyZSBwcmUge1xuICAgIHBvc2l0aW9uOiBzdGF0aWM7XG4gIH1cblxuICBkaXYuQ29kZU1pcnJvci1jdXJzb3JzIHtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgdmlzaWJpbGl0eTogaGlkZGVuO1xuICAgIHotaW5kZXg6IDM7XG4gIH1cbiAgZGl2LkNvZGVNaXJyb3ItZHJhZ2N1cnNvcnMge1xuICAgIHZpc2liaWxpdHk6IHZpc2libGU7XG4gIH1cblxuICAuQ29kZU1pcnJvci1mb2N1c2VkIGRpdi5Db2RlTWlycm9yLWN1cnNvcnMge1xuICAgIHZpc2liaWxpdHk6IHZpc2libGU7XG4gIH1cblxuICAuQ29kZU1pcnJvci1zZWxlY3RlZCB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4gIC5Db2RlTWlycm9yLWZvY3VzZWQgLkNvZGVNaXJyb3Itc2VsZWN0ZWQge1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgfVxuICAuQ29kZU1pcnJvci1jcm9zc2hhaXIge1xuICAgIGN1cnNvcjogY3Jvc3NoYWlyO1xuICB9XG4gIC5Db2RlTWlycm9yLWxpbmU6Oi1tb3otc2VsZWN0aW9uLFxuICAuQ29kZU1pcnJvci1saW5lID4gc3Bhbjo6LW1vei1zZWxlY3Rpb24sXG4gIC5Db2RlTWlycm9yLWxpbmUgPiBzcGFuID4gc3Bhbjo6LW1vei1zZWxlY3Rpb24ge1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgfVxuICAuQ29kZU1pcnJvci1saW5lOjpzZWxlY3Rpb24sXG4gIC5Db2RlTWlycm9yLWxpbmUgPiBzcGFuOjpzZWxlY3Rpb24sXG4gIC5Db2RlTWlycm9yLWxpbmUgPiBzcGFuID4gc3Bhbjo6c2VsZWN0aW9uIHtcbiAgICBiYWNrZ3JvdW5kOiAiLCI7XG4gIH1cbiAgLkNvZGVNaXJyb3ItbGluZTo6LW1vei1zZWxlY3Rpb24sXG4gIC5Db2RlTWlycm9yLWxpbmUgPiBzcGFuOjotbW96LXNlbGVjdGlvbixcbiAgLkNvZGVNaXJyb3ItbGluZSA+IHNwYW4gPiBzcGFuOjotbW96LXNlbGVjdGlvbiB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG5cbiAgLmNtLXNlYXJjaGluZyB7XG4gICAgYmFja2dyb3VuZDogI2ZmYTtcbiAgICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwgMjU1LCAwLCAwLjQpO1xuICB9XG5cbiAgLyogSUU3IGhhY2sgdG8gcHJldmVudCBpdCBmcm9tIHJldHVybmluZyBmdW5ueSBvZmZzZXRUb3BzIG9uIHRoZSBzcGFucyAqL1xuICAuQ29kZU1pcnJvciBzcGFuIHtcbiAgICAqdmVydGljYWwtYWxpZ246IHRleHQtYm90dG9tO1xuICB9XG5cbiAgLyogVXNlZCB0byBmb3JjZSBhIGJvcmRlciBtb2RlbCBmb3IgYSBub2RlICovXG4gIC5jbS1mb3JjZS1ib3JkZXIge1xuICAgIHBhZGRpbmctcmlnaHQ6IDAuMXB4O1xuICB9XG5cbiAgQG1lZGlhIHByaW50IHtcbiAgICAvKiBIaWRlIHRoZSBjdXJzb3Igd2hlbiBwcmludGluZyAqL1xuICAgIC5Db2RlTWlycm9yIGRpdi5Db2RlTWlycm9yLWN1cnNvcnMge1xuICAgICAgdmlzaWJpbGl0eTogaGlkZGVuO1xuICAgIH1cbiAgfVxuXG4gIC8qIFNlZSBpc3N1ZSAjMjkwMSAqL1xuICAuY20tdGFiLXdyYXAtaGFjazphZnRlciB7XG4gICAgY29udGVudDogJyc7XG4gIH1cblxuICAvKiBIZWxwIHVzZXJzIHVzZSBtYXJrc2VsZWN0aW9uIHRvIHNhZmVseSBzdHlsZSB0ZXh0IGJhY2tncm91bmQgKi9cbiAgc3Bhbi5Db2RlTWlycm9yLXNlbGVjdGVkdGV4dCB7XG4gICAgYmFja2dyb3VuZDogbm9uZTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWRpYWxvZyB7XG4gICAgYmFja2dyb3VuZDogaW5oZXJpdDtcbiAgICBjb2xvcjogaW5oZXJpdDtcbiAgICBsZWZ0OiAwO1xuICAgIHJpZ2h0OiAwO1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgcGFkZGluZzogMC4xZW0gMC44ZW07XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHotaW5kZXg6IDE1O1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItZGlhbG9nLXRvcCB7XG4gICAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNlZWU7XG4gICAgdG9wOiAwO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItZGlhbG9nLWJvdHRvbSB7XG4gICAgYm9yZGVyLXRvcDogMXB4IHNvbGlkICNlZWU7XG4gICAgYm90dG9tOiAwO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItZGlhbG9nIGlucHV0IHtcbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgICBib3JkZXI6IDFweCBzb2xpZCAjZDNkNmRiO1xuICAgIGNvbG9yOiBpbmhlcml0O1xuICAgIGZvbnQtZmFtaWx5OiBtb25vc3BhY2U7XG4gICAgb3V0bGluZTogbm9uZTtcbiAgICB3aWR0aDogMjBlbTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWRpYWxvZyBidXR0b24ge1xuICAgIGZvbnQtc2l6ZTogNzAlO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItZm9sZGd1dHRlciB7XG4gICAgd2lkdGg6IDAuN2VtO1xuICB9XG4gIC5Db2RlTWlycm9yLWZvbGRndXR0ZXItb3BlbixcbiAgLkNvZGVNaXJyb3ItZm9sZGd1dHRlci1mb2xkZWQge1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgfVxuICAuQ29kZU1pcnJvci1mb2xkZ3V0dGVyLW9wZW46YWZ0ZXIge1xuICAgIGNvbnRlbnQ6ICdcdTI1YmUnO1xuICB9XG4gIC5Db2RlTWlycm9yLWZvbGRndXR0ZXItZm9sZGVkOmFmdGVyIHtcbiAgICBjb250ZW50OiAnXHUyNWI4JztcbiAgfVxuICAvKiBUaGUgbGludCBtYXJrZXIgZ3V0dGVyICovXG4gIC5Db2RlTWlycm9yLWxpbnQtbWFya2VycyB7XG4gICAgd2lkdGg6IDE2cHg7XG4gIH1cblxuICAuQ29kZU1pcnJvci1qdW1wLXRva2VuIHtcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7XG4gIH1cbiJdLFsiXG4gIC8qIENvbW1lbnQgKi9cbiAgLmNtLWNvbW1lbnQge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBQdW5jdHVhdGlvbiAqL1xuICAuY20tcHVuY3R1YXRpb24ge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBQcm9wcGVyeSAqL1xuICAuY20tcHJvcGVydHkge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBLZXl3b3JkICovXG4gIC5jbS1rZXl3b3JkIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogT3BlcmF0aW9uTmFtZSwgRnJhZ21lbnROYW1lICovXG4gIC5jbS1kZWYge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBGaWVsZEFsaWFzICovXG4gIC5jbS1xdWFsaWZpZXIge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBBcmd1bWVudE5hbWUgYW5kIE9iamVjdEZpZWxkTmFtZSAqL1xuICAuY20tYXR0cmlidXRlIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogTnVtYmVyICovXG4gIC5jbS1udW1iZXIge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBTdHJpbmcgKi9cbiAgLmNtLXN0cmluZyB7XG4gICAgY29sb3I6ICIsIjtcbiAgfVxuXG4gIC8qIEJvb2xlYW4gKi9cbiAgLmNtLWJ1aWx0aW4ge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBFbnVtVmFsdWUgKi9cbiAgLmNtLXN0cmluZy0yIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogVmFyaWFibGUgKi9cbiAgLmNtLXZhcmlhYmxlIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogRGlyZWN0aXZlICovXG4gIC5jbS1tZXRhIHtcbiAgICBjb2xvcjogIiwiO1xuICB9XG5cbiAgLyogVHlwZSAqL1xuICAuY20tYXRvbSB7XG4gICAgY29sb3I6ICIsIjtcbiAgfVxuXG4gIC8qIENvbW1hICovXG4gIC5jbS13cyB7XG4gICAgY29sb3I6ICIsIjtcbiAgfVxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXg6IDEgMSAwJTtcbiAgZmxleC1mbG93OiBjb2x1bW47XG5cbiAgLkNvZGVNaXJyb3Ige1xuICAgIGNvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDAuMyk7XG4gICAgZm9udC1mYW1pbHk6ICIsIjtcbiAgICBmb250LXNpemU6ICIsIjtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgbGVmdDogMDtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgdG9wOiAwO1xuICAgIHdpZHRoOiAxMDAlO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGluZXMge1xuICAgIHBhZGRpbmc6IDIwcHggMDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWd1dHRlcnMge1xuICAgIGJvcmRlci1yaWdodDogbm9uZTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yIHNwYW5bcm9sZT0ncHJlc2VudGF0aW9uJ10ge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cblxuICAvKiBDVVJTT1IgKi9cblxuICAuQ29kZU1pcnJvciBkaXYuQ29kZU1pcnJvci1jdXJzb3Ige1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgICBib3JkZXItbGVmdDogIiwiO1xuICAgIGJvcmRlci1ib3R0b206ICIsIjtcbiAgfVxuICAvKiBTaG93biB3aGVuIG1vdmluZyBpbiBiaS1kaXJlY3Rpb25hbCB0ZXh0ICovXG4gIC5Db2RlTWlycm9yIGRpdi5Db2RlTWlycm9yLXNlY29uZGFyeWN1cnNvciB7XG4gICAgYm9yZGVyLWxlZnQ6IDFweCBzb2xpZCBzaWx2ZXI7XG4gIH1cbiAgLkNvZGVNaXJyb3IuY20tZmF0LWN1cnNvciBkaXYuQ29kZU1pcnJvci1jdXJzb3Ige1xuICAgIGJhY2tncm91bmQ6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMC42KTtcbiAgICBjb2xvcjogd2hpdGU7XG4gICAgYm9yZGVyOiAwO1xuICAgIHdpZHRoOiBhdXRvO1xuICB9XG4gIC5Db2RlTWlycm9yLmNtLWZhdC1jdXJzb3IgZGl2LkNvZGVNaXJyb3ItY3Vyc29ycyB7XG4gICAgei1pbmRleDogMTtcbiAgfVxuXG4gIC5jbS1hbmltYXRlLWZhdC1jdXJzb3Ige1xuICAgIC13ZWJraXQtYW5pbWF0aW9uOiBibGluayAxLjA2cyBzdGVwcygxKSBpbmZpbml0ZTtcbiAgICBhbmltYXRpb246IGJsaW5rIDEuMDZzIHN0ZXBzKDEpIGluZmluaXRlO1xuICAgIGJvcmRlcjogMDtcbiAgICB3aWR0aDogYXV0bztcbiAgfVxuICBALXdlYmtpdC1rZXlmcmFtZXMgYmxpbmsge1xuICAgIDAlIHtcbiAgICAgIGJhY2tncm91bmQ6ICM3ZTc7XG4gICAgfVxuICAgIDUwJSB7XG4gICAgICBiYWNrZ3JvdW5kOiBub25lO1xuICAgIH1cbiAgICAxMDAlIHtcbiAgICAgIGJhY2tncm91bmQ6ICM3ZTc7XG4gICAgfVxuICB9XG4gIEBrZXlmcmFtZXMgYmxpbmsge1xuICAgIDAlIHtcbiAgICAgIGJhY2tncm91bmQ6ICM3ZTc7XG4gICAgfVxuICAgIDUwJSB7XG4gICAgICBiYWNrZ3JvdW5kOiBub25lO1xuICAgIH1cbiAgICAxMDAlIHtcbiAgICAgIGJhY2tncm91bmQ6ICM3ZTc7XG4gICAgfVxuICB9XG5cbiAgLkNvZGVNaXJyb3ItZm9sZG1hcmtlciB7XG4gICAgYm9yZGVyLXJhZGl1czogNHB4O1xuICAgIGJhY2tncm91bmQ6ICMwOGY7XG4gICAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KCM0M2E4ZmYsICMwZjgzZTgpO1xuICAgIGJveC1zaGFkb3c6IDAgMXB4IDFweCByZ2JhKDAsIDAsIDAsIDAuMiksIGluc2V0IDAgMCAwIDFweCByZ2JhKDAsIDAsIDAsIDAuMSk7XG4gICAgY29sb3I6IHdoaXRlO1xuICAgIGZvbnQtZmFtaWx5OiBhcmlhbDtcbiAgICBmb250LXNpemU6IDEycHg7XG4gICAgbGluZS1oZWlnaHQ6IDA7XG4gICAgbWFyZ2luOiAwIDNweDtcbiAgICBwYWRkaW5nOiAwcHggNHB4IDFweDtcbiAgICB0ZXh0LXNoYWRvdzogMCAtMXB4IHJnYmEoMCwgMCwgMCwgMC4xKTtcbiAgfVxuXG4gIGRpdi5Db2RlTWlycm9yIHNwYW4uQ29kZU1pcnJvci1tYXRjaGluZ2JyYWNrZXQge1xuICAgIC8qIGNvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDAuNCk7ICovXG4gICAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7XG4gIH1cblxuICBkaXYuQ29kZU1pcnJvciBzcGFuLkNvZGVNaXJyb3Itbm9ubWF0Y2hpbmdicmFja2V0IHtcbiAgICBjb2xvcjogcmdiKDI0MiwgOTIsIDg0KTtcbiAgfVxuXG4gIC50b29sYmFyLWJ1dHRvbiB7XG4gICAgYmFja2dyb3VuZDogI2ZkZmRmZDtcbiAgICBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQoI2ZiZmJmYiwgI2Y4ZjhmOCk7XG4gICAgYm9yZGVyLWNvbG9yOiAjZDNkM2QzICNkMGQwZDAgI2JhYmFiYTtcbiAgICBib3JkZXItcmFkaXVzOiA0cHg7XG4gICAgYm9yZGVyLXN0eWxlOiBzb2xpZDtcbiAgICBib3JkZXItd2lkdGg6IDAuNXB4O1xuICAgIGJveC1zaGFkb3c6IDAgMXB4IDFweCAtMXB4IHJnYmEoMCwgMCwgMCwgMC4xMyksIGluc2V0IDAgMXB4ICNmZmY7XG4gICAgY29sb3I6ICM0NDQ7XG4gICAgY3Vyc29yOiBwb2ludGVyO1xuICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICBtYXJnaW46IDAgNXB4IDA7XG4gICAgcGFkZGluZzogMnB4IDhweCA0cHg7XG4gICAgdGV4dC1kZWNvcmF0aW9uOiBub25lO1xuICB9XG4gIC50b29sYmFyLWJ1dHRvbjphY3RpdmUge1xuICAgIGJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCgjZWNlY2VjLCAjZDhkOGQ4KTtcbiAgICBib3JkZXItY29sb3I6ICNjYWNhY2EgI2M5YzljOSAjYjBiMGIwO1xuICAgIGJveC1zaGFkb3c6IDAgMXB4IDAgI2ZmZiwgaW5zZXQgMCAxcHggcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjIpLFxuICAgICAgaW5zZXQgMCAxcHggMXB4IHJnYmEoMCwgMCwgMCwgMC4wOCk7XG4gIH1cbiAgLnRvb2xiYXItYnV0dG9uLmVycm9yIHtcbiAgICBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQoI2ZkZjNmMywgI2U2ZDZkNyk7XG4gICAgY29sb3I6ICNiMDA7XG4gIH1cblxuICAuYXV0b0luc2VydGVkTGVhZi5jbS1wcm9wZXJ0eSB7XG4gICAgLXdlYmtpdC1hbmltYXRpb24tZHVyYXRpb246IDZzO1xuICAgIGFuaW1hdGlvbi1kdXJhdGlvbjogNnM7XG4gICAgLXdlYmtpdC1hbmltYXRpb24tbmFtZTogaW5zZXJ0aW9uRmFkZTtcbiAgICBhbmltYXRpb24tbmFtZTogaW5zZXJ0aW9uRmFkZTtcbiAgICBib3JkZXItYm90dG9tOiAycHggc29saWQgcmdiYSgyNTUsIDI1NSwgMjU1LCAwKTtcbiAgICBib3JkZXItcmFkaXVzOiAycHg7XG4gICAgbWFyZ2luOiAtMnB4IC00cHggLTFweDtcbiAgICBwYWRkaW5nOiAycHggNHB4IDFweDtcbiAgfVxuXG4gIEAtd2Via2l0LWtleWZyYW1lcyBpbnNlcnRpb25GYWRlIHtcbiAgICBmcm9tLFxuICAgIHRvIHtcbiAgICAgIGJhY2tncm91bmQ6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMCk7XG4gICAgICBib3JkZXItY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMCk7XG4gICAgfVxuXG4gICAgMTUlLFxuICAgIDg1JSB7XG4gICAgICBiYWNrZ3JvdW5kOiAjZmJmZmM5O1xuICAgICAgYm9yZGVyLWNvbG9yOiAjZjBmM2MwO1xuICAgIH1cbiAgfVxuXG4gIEBrZXlmcmFtZXMgaW5zZXJ0aW9uRmFkZSB7XG4gICAgZnJvbSxcbiAgICB0byB7XG4gICAgICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDApO1xuICAgICAgYm9yZGVyLWNvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDApO1xuICAgIH1cblxuICAgIDE1JSxcbiAgICA4NSUge1xuICAgICAgYmFja2dyb3VuZDogI2ZiZmZjOTtcbiAgICAgIGJvcmRlci1jb2xvcjogI2YwZjNjMDtcbiAgICB9XG4gIH1cblxuICAuQ29kZU1pcnJvciBwcmUge1xuICAgIHBhZGRpbmc6IDAgNHB4OyAvKiBIb3Jpem9udGFsIHBhZGRpbmcgb2YgY29udGVudCAqL1xuICB9XG5cbiAgLkNvZGVNaXJyb3Itc2Nyb2xsYmFyLWZpbGxlcixcbiAgLkNvZGVNaXJyb3ItZ3V0dGVyLWZpbGxlciB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogd2hpdGU7IC8qIFRoZSBsaXR0bGUgc3F1YXJlIGJldHdlZW4gSCBhbmQgViBzY3JvbGxiYXJzICovXG4gIH1cblxuICAvKiBHVVRURVIgKi9cblxuICAuQ29kZU1pcnJvci1ndXR0ZXJzIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICBib3JkZXI6IG5vbmU7XG4gICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgfVxuICAuQ29kZU1pcnJvci1saW5lbnVtYmVycyB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4gIC5Db2RlTWlycm9yLWxpbmVudW1iZXIge1xuICAgIGZvbnQtZmFtaWx5OiBPcGVuIFNhbnMsIHNhbnMtc2VyaWY7XG4gICAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgICBmb250LXNpemU6ICIsIjtcbiAgICBjb2xvcjogIiwiO1xuICAgIG1pbi13aWR0aDogMjBweDtcbiAgICBwYWRkaW5nOiAwIDNweCAwIDVweDtcbiAgICB0ZXh0LWFsaWduOiByaWdodDtcbiAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItZ3V0dGVybWFya2VyIHtcbiAgICBjb2xvcjogYmxhY2s7XG4gIH1cbiAgLkNvZGVNaXJyb3ItZ3V0dGVybWFya2VyLXN1YnRsZSB7XG4gICAgY29sb3I6ICM5OTk7XG4gIH1cblxuICAuY20tdGFiIHtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgdGV4dC1kZWNvcmF0aW9uOiBpbmhlcml0O1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItcnVsZXIge1xuICAgIGJvcmRlci1sZWZ0OiAxcHggc29saWQgI2NjYztcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIH1cbiAgLmNtLW5lZ2F0aXZlIHtcbiAgICBjb2xvcjogI2Q0NDtcbiAgfVxuICAuY20tcG9zaXRpdmUge1xuICAgIGNvbG9yOiAjMjkyO1xuICB9XG4gIC5jbS1oZWFkZXIsXG4gIC5jbS1zdHJvbmcge1xuICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xuICB9XG4gIC5jbS1lbSB7XG4gICAgZm9udC1zdHlsZTogaXRhbGljO1xuICB9XG4gIC5jbS1saW5rIHtcbiAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTtcbiAgfVxuICAuY20tc3RyaWtldGhyb3VnaCB7XG4gICAgdGV4dC1kZWNvcmF0aW9uOiBsaW5lLXRocm91Z2g7XG4gIH1cblxuICAuY20tcy1kZWZhdWx0IC5jbS1lcnJvciB7XG4gICAgY29sb3I6ICNmMDA7XG4gIH1cbiAgLmNtLWludmFsaWRjaGFyIHtcbiAgICBjb2xvcjogI2YwMDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWNvbXBvc2luZyB7XG4gICAgYm9yZGVyLWJvdHRvbTogMnB4IHNvbGlkO1xuICB9XG4gIC5Db2RlTWlycm9yLW1hdGNoaW5ndGFnIHtcbiAgICBiYWNrZ3JvdW5kOiByZ2JhKDI1NSwgMTUwLCAwLCAwLjMpO1xuICB9XG4gIC5Db2RlTWlycm9yLWFjdGl2ZWxpbmUtYmFja2dyb3VuZCB7XG4gICAgYmFja2dyb3VuZDogI2U4ZjJmZjtcbiAgfVxuXG4gIC8qIFRoZSByZXN0IG9mIHRoaXMgZmlsZSBjb250YWlucyBzdHlsZXMgcmVsYXRlZCB0byB0aGUgbWVjaGFuaWNzIG9mXG4gICB0aGUgZWRpdG9yLiBZb3UgcHJvYmFibHkgc2hvdWxkbid0IHRvdWNoIHRoZW0uICovXG5cbiAgLkNvZGVNaXJyb3Ige1xuICAgIGJhY2tncm91bmQ6IHdoaXRlO1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgbGluZS1oZWlnaHQ6IDEuNjtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLXNjcm9sbCB7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIC8qIDMwcHggaXMgdGhlIG1hZ2ljIG1hcmdpbiB1c2VkIHRvIGhpZGUgdGhlIGVsZW1lbnQncyByZWFsIHNjcm9sbGJhcnMgKi9cbiAgICAvKiBTZWUgb3ZlcmZsb3c6IGhpZGRlbiBpbiAuQ29kZU1pcnJvciAqL1xuICAgIC8qIG1hcmdpbi1ib3R0b206IC0zMHB4O1xuICAgIG1hcmdpbi1yaWdodDogLTMwcHg7ICovXG4gICAgb3V0bGluZTogbm9uZTsgLyogUHJldmVudCBkcmFnZ2luZyBmcm9tIGhpZ2hsaWdodGluZyB0aGUgZWxlbWVudCAqL1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgLyogcGFkZGluZy1ib3R0b206IDMwcHg7ICovXG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICY6aG92ZXIge1xuICAgICAgb3ZlcmZsb3c6IHNjcm9sbCAhaW1wb3J0YW50O1xuICAgIH1cbiAgfVxuICAuQ29kZU1pcnJvci1zaXplciB7XG4gICAgYm9yZGVyLXJpZ2h0OiAzMHB4IHNvbGlkIHRyYW5zcGFyZW50O1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgfVxuXG4gIC8qIFRoZSBmYWtlLCB2aXNpYmxlIHNjcm9sbGJhcnMuIFVzZWQgdG8gZm9yY2UgcmVkcmF3IGR1cmluZyBzY3JvbGxpbmdcbiAgIGJlZm9yZSBhY3R1YWwgc2Nyb2xsaW5nIGhhcHBlbnMsIHRodXMgcHJldmVudGluZyBzaGFraW5nIGFuZFxuICAgZmxpY2tlcmluZyBhcnRpZmFjdHMuICovXG4gIC5Db2RlTWlycm9yLXZzY3JvbGxiYXIsXG4gIC5Db2RlTWlycm9yLWhzY3JvbGxiYXIsXG4gIC5Db2RlTWlycm9yLXNjcm9sbGJhci1maWxsZXIsXG4gIC5Db2RlTWlycm9yLWd1dHRlci1maWxsZXIge1xuICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgei1pbmRleDogNjtcbiAgfVxuICAuQ29kZU1pcnJvci12c2Nyb2xsYmFyIHtcbiAgICBvdmVyZmxvdy14OiBoaWRkZW47XG4gICAgb3ZlcmZsb3cteTogc2Nyb2xsO1xuICAgIHJpZ2h0OiAwO1xuICAgIHRvcDogMDtcbiAgfVxuICAuQ29kZU1pcnJvci1oc2Nyb2xsYmFyIHtcbiAgICBib3R0b206IDA7XG4gICAgbGVmdDogMDtcbiAgICBvdmVyZmxvdy14OiBzY3JvbGw7XG4gICAgb3ZlcmZsb3cteTogaGlkZGVuO1xuICB9XG4gIC5Db2RlTWlycm9yLXNjcm9sbGJhci1maWxsZXIge1xuICAgIHJpZ2h0OiAwO1xuICAgIGJvdHRvbTogMDtcbiAgfVxuICAuQ29kZU1pcnJvci1ndXR0ZXItZmlsbGVyIHtcbiAgICBsZWZ0OiAwO1xuICAgIGJvdHRvbTogMDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWd1dHRlcnMge1xuICAgIG1pbi1oZWlnaHQ6IDEwMCU7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIGxlZnQ6IDA7XG4gICAgdG9wOiAwO1xuICAgIHotaW5kZXg6IDM7XG4gICAgbWFyZ2luLWxlZnQ6IDNweDtcbiAgfVxuICAuQ29kZU1pcnJvci1ndXR0ZXIge1xuICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgbWFyZ2luLWJvdHRvbTogLTMwcHg7XG4gICAgdmVydGljYWwtYWxpZ246IHRvcDtcbiAgICB3aGl0ZS1zcGFjZTogbm9ybWFsO1xuICAgIC8qIEhhY2sgdG8gbWFrZSBJRTcgYmVoYXZlICovXG4gICAgKnpvb206IDE7XG4gICAgKmRpc3BsYXk6IGlubGluZTtcbiAgfVxuICAuQ29kZU1pcnJvci1ndXR0ZXItd3JhcHBlciB7XG4gICAgYmFja2dyb3VuZDogbm9uZSAhaW1wb3J0YW50O1xuICAgIGJvcmRlcjogbm9uZSAhaW1wb3J0YW50O1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB6LWluZGV4OiA0O1xuICB9XG4gIC5Db2RlTWlycm9yLWd1dHRlci1iYWNrZ3JvdW5kIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgdG9wOiAwO1xuICAgIGJvdHRvbTogMDtcbiAgICB6LWluZGV4OiA0O1xuICB9XG4gIC5Db2RlTWlycm9yLWd1dHRlci1lbHQge1xuICAgIGN1cnNvcjogZGVmYXVsdDtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgei1pbmRleDogNDtcbiAgfVxuICAuQ29kZU1pcnJvci1ndXR0ZXItd3JhcHBlciB7XG4gICAgLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTtcbiAgICAtbW96LXVzZXItc2VsZWN0OiBub25lO1xuICAgIC1tcy11c2VyLXNlbGVjdDogbm9uZTtcbiAgICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbmVzIHtcbiAgICBjdXJzb3I6IHRleHQ7XG4gICAgbWluLWhlaWdodDogMXB4OyAvKiBwcmV2ZW50cyBjb2xsYXBzaW5nIGJlZm9yZSBmaXJzdCBkcmF3ICovXG4gIH1cbiAgLkNvZGVNaXJyb3IgcHJlIHtcbiAgICAtd2Via2l0LXRhcC1oaWdobGlnaHQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIC8qIFJlc2V0IHNvbWUgc3R5bGVzIHRoYXQgdGhlIHJlc3Qgb2YgdGhlIHBhZ2UgbWlnaHQgaGF2ZSBzZXQgKi9cbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgICBib3JkZXItcmFkaXVzOiAwO1xuICAgIGJvcmRlci13aWR0aDogMDtcbiAgICBjb2xvcjogaW5oZXJpdDtcbiAgICBmb250LWZhbWlseTogaW5oZXJpdDtcbiAgICBmb250LXNpemU6IGluaGVyaXQ7XG4gICAgLXdlYmtpdC1mb250LXZhcmlhbnQtbGlnYXR1cmVzOiBub25lO1xuICAgIGZvbnQtdmFyaWFudC1saWdhdHVyZXM6IG5vbmU7XG4gICAgbGluZS1oZWlnaHQ6IGluaGVyaXQ7XG4gICAgbWFyZ2luOiAwO1xuICAgIG92ZXJmbG93OiB2aXNpYmxlO1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICB3aGl0ZS1zcGFjZTogcHJlO1xuICAgIHdvcmQtd3JhcDogbm9ybWFsO1xuICAgIHotaW5kZXg6IDI7XG4gIH1cbiAgLkNvZGVNaXJyb3Itd3JhcCBwcmUge1xuICAgIHdvcmQtd3JhcDogYnJlYWstd29yZDtcbiAgICB3aGl0ZS1zcGFjZTogcHJlLXdyYXA7XG4gICAgd29yZC1icmVhazogbm9ybWFsO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGluZWJhY2tncm91bmQge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICBsZWZ0OiAwO1xuICAgIHJpZ2h0OiAwO1xuICAgIHRvcDogMDtcbiAgICBib3R0b206IDA7XG4gICAgei1pbmRleDogMDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbmV3aWRnZXQge1xuICAgIG92ZXJmbG93OiBhdXRvO1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICB6LWluZGV4OiAyO1xuICB9XG5cbiAgLkNvZGVNaXJyb3Itd2lkZ2V0IHtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWNvZGUge1xuICAgIG91dGxpbmU6IG5vbmU7XG4gIH1cblxuICAvKiBGb3JjZSBjb250ZW50LWJveCBzaXppbmcgZm9yIHRoZSBlbGVtZW50cyB3aGVyZSB3ZSBleHBlY3QgaXQgKi9cbiAgLkNvZGVNaXJyb3Itc2Nyb2xsLFxuICAuQ29kZU1pcnJvci1zaXplcixcbiAgLkNvZGVNaXJyb3ItZ3V0dGVyLFxuICAuQ29kZU1pcnJvci1ndXR0ZXJzLFxuICAuQ29kZU1pcnJvci1saW5lbnVtYmVyIHtcbiAgICBib3gtc2l6aW5nOiBjb250ZW50LWJveDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLW1lYXN1cmUge1xuICAgIGhlaWdodDogMDtcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB2aXNpYmlsaXR5OiBoaWRkZW47XG4gICAgd2lkdGg6IDEwMCU7XG4gIH1cblxuICAuQ29kZU1pcnJvci1jdXJzb3Ige1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgfVxuICAuQ29kZU1pcnJvci1tZWFzdXJlIHByZSB7XG4gICAgcG9zaXRpb246IHN0YXRpYztcbiAgfVxuXG4gIGRpdi5Db2RlTWlycm9yLWN1cnNvcnMge1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICB2aXNpYmlsaXR5OiBoaWRkZW47XG4gICAgei1pbmRleDogMztcbiAgfVxuICBkaXYuQ29kZU1pcnJvci1kcmFnY3Vyc29ycyB7XG4gICAgdmlzaWJpbGl0eTogdmlzaWJsZTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWZvY3VzZWQgZGl2LkNvZGVNaXJyb3ItY3Vyc29ycyB7XG4gICAgdmlzaWJpbGl0eTogdmlzaWJsZTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLXNlbGVjdGVkIHtcbiAgICBiYWNrZ3JvdW5kOiAiLCI7XG4gIH1cbiAgLkNvZGVNaXJyb3ItZm9jdXNlZCAuQ29kZU1pcnJvci1zZWxlY3RlZCB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4gIC5Db2RlTWlycm9yLWNyb3NzaGFpciB7XG4gICAgY3Vyc29yOiBjcm9zc2hhaXI7XG4gIH1cbiAgLkNvZGVNaXJyb3ItbGluZTo6LW1vei1zZWxlY3Rpb24sXG4gIC5Db2RlTWlycm9yLWxpbmUgPiBzcGFuOjotbW96LXNlbGVjdGlvbixcbiAgLkNvZGVNaXJyb3ItbGluZSA+IHNwYW4gPiBzcGFuOjotbW96LXNlbGVjdGlvbiB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4gIC5Db2RlTWlycm9yLWxpbmU6OnNlbGVjdGlvbixcbiAgLkNvZGVNaXJyb3ItbGluZSA+IHNwYW46OnNlbGVjdGlvbixcbiAgLkNvZGVNaXJyb3ItbGluZSA+IHNwYW4gPiBzcGFuOjpzZWxlY3Rpb24ge1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgfVxuICAuQ29kZU1pcnJvci1saW5lOjotbW96LXNlbGVjdGlvbixcbiAgLkNvZGVNaXJyb3ItbGluZSA+IHNwYW46Oi1tb3otc2VsZWN0aW9uLFxuICAuQ29kZU1pcnJvci1saW5lID4gc3BhbiA+IHNwYW46Oi1tb3otc2VsZWN0aW9uIHtcbiAgICBiYWNrZ3JvdW5kOiAiLCI7XG4gIH1cblxuICAuY20tc2VhcmNoaW5nIHtcbiAgICBiYWNrZ3JvdW5kOiAjZmZhO1xuICAgIGJhY2tncm91bmQ6IHJnYmEoMjU1LCAyNTUsIDAsIDAuNCk7XG4gIH1cblxuICAvKiBJRTcgaGFjayB0byBwcmV2ZW50IGl0IGZyb20gcmV0dXJuaW5nIGZ1bm55IG9mZnNldFRvcHMgb24gdGhlIHNwYW5zICovXG4gIC5Db2RlTWlycm9yIHNwYW4ge1xuICAgICp2ZXJ0aWNhbC1hbGlnbjogdGV4dC1ib3R0b207XG4gIH1cblxuICAvKiBVc2VkIHRvIGZvcmNlIGEgYm9yZGVyIG1vZGVsIGZvciBhIG5vZGUgKi9cbiAgLmNtLWZvcmNlLWJvcmRlciB7XG4gICAgcGFkZGluZy1yaWdodDogMC4xcHg7XG4gIH1cblxuICBAbWVkaWEgcHJpbnQge1xuICAgIC8qIEhpZGUgdGhlIGN1cnNvciB3aGVuIHByaW50aW5nICovXG4gICAgLkNvZGVNaXJyb3IgZGl2LkNvZGVNaXJyb3ItY3Vyc29ycyB7XG4gICAgICB2aXNpYmlsaXR5OiBoaWRkZW47XG4gICAgfVxuICB9XG5cbiAgLyogU2VlIGlzc3VlICMyOTAxICovXG4gIC5jbS10YWItd3JhcC1oYWNrOmFmdGVyIHtcbiAgICBjb250ZW50OiAnJztcbiAgfVxuXG4gIC8qIEhlbHAgdXNlcnMgdXNlIG1hcmtzZWxlY3Rpb24gdG8gc2FmZWx5IHN0eWxlIHRleHQgYmFja2dyb3VuZCAqL1xuICBzcGFuLkNvZGVNaXJyb3Itc2VsZWN0ZWR0ZXh0IHtcbiAgICBiYWNrZ3JvdW5kOiBub25lO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItZGlhbG9nIHtcbiAgICBiYWNrZ3JvdW5kOiBpbmhlcml0O1xuICAgIGNvbG9yOiBpbmhlcml0O1xuICAgIGxlZnQ6IDA7XG4gICAgcmlnaHQ6IDA7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICBwYWRkaW5nOiAwLjFlbSAwLjhlbTtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgei1pbmRleDogMTU7XG4gIH1cblxuICAuQ29kZU1pcnJvci1kaWFsb2ctdG9wIHtcbiAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgI2VlZTtcbiAgICB0b3A6IDA7XG4gIH1cblxuICAuQ29kZU1pcnJvci1kaWFsb2ctYm90dG9tIHtcbiAgICBib3JkZXItdG9wOiAxcHggc29saWQgI2VlZTtcbiAgICBib3R0b206IDA7XG4gIH1cblxuICAuQ29kZU1pcnJvci1kaWFsb2cgaW5wdXQge1xuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNkM2Q2ZGI7XG4gICAgY29sb3I6IGluaGVyaXQ7XG4gICAgZm9udC1mYW1pbHk6IG1vbm9zcGFjZTtcbiAgICBvdXRsaW5lOiBub25lO1xuICAgIHdpZHRoOiAyMGVtO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItZGlhbG9nIGJ1dHRvbiB7XG4gICAgZm9udC1zaXplOiA3MCU7XG4gIH1cblxuICAuQ29kZU1pcnJvci1mb2xkZ3V0dGVyIHtcbiAgICB3aWR0aDogMC43ZW07XG4gIH1cbiAgLkNvZGVNaXJyb3ItZm9sZGd1dHRlci1vcGVuLFxuICAuQ29kZU1pcnJvci1mb2xkZ3V0dGVyLWZvbGRlZCB7XG4gICAgY3Vyc29yOiBwb2ludGVyO1xuICB9XG4gIC5Db2RlTWlycm9yLWZvbGRndXR0ZXItb3BlbjphZnRlciB7XG4gICAgY29udGVudDogJ1x1MjViZSc7XG4gIH1cbiAgLkNvZGVNaXJyb3ItZm9sZGd1dHRlci1mb2xkZWQ6YWZ0ZXIge1xuICAgIGNvbnRlbnQ6ICdcdTI1YjgnO1xuICB9XG4gIC8qIFRoZSBsaW50IG1hcmtlciBndXR0ZXIgKi9cbiAgLkNvZGVNaXJyb3ItbGludC1tYXJrZXJzIHtcbiAgICB3aWR0aDogMTZweDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWp1bXAtdG9rZW4ge1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmNvbW1lbnR9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMucHVuY3R1YXRpb259LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMucHJvcGVydHl9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMua2V5d29yZH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5kZWZ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuZGVmfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmF0dHJpYnV0ZX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5udW1iZXJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuc3RyaW5nfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmJ1aWx0aW59LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuc3RyaW5nMn0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy52YXJpYWJsZX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5tZXRhfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmF0b219LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMud3N9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNldHRpbmdzWyJlZGl0b3IuZm9udEZhbWlseSJdfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zZXR0aW5nc1siZWRpdG9yLmZvbnRTaXplIl0rInB4In0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy50ZXh0fSxmdW5jdGlvbihlKXtyZXR1cm4iYmxvY2siPT09ZS50aGVtZS5zZXR0aW5nc1siZWRpdG9yLmN1cnNvclNoYXBlIl0/ZS50aGVtZS5lZGl0b3JDb2xvdXJzLmN1cnNvckNvbG9yOiJ0cmFuc3BhcmVudCJ9LGZ1bmN0aW9uKGUpe3JldHVybiJsaW5lIj09PWUudGhlbWUuc2V0dGluZ3NbImVkaXRvci5jdXJzb3JTaGFwZSJdPyIxcHggc29saWQgIitlLnRoZW1lLmVkaXRvckNvbG91cnMuY3Vyc29yQ29sb3I6MH0sZnVuY3Rpb24oZSl7cmV0dXJuInVuZGVybGluZSI9PT1lLnRoZW1lLnNldHRpbmdzWyJlZGl0b3IuY3Vyc29yU2hhcGUiXT8iMXB4IHNvbGlkICIrZS50aGVtZS5lZGl0b3JDb2xvdXJzLmN1cnNvckNvbG9yOjB9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuZWRpdG9yQmFja2dyb3VuZH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuc2V0dGluZ3NbImVkaXRvci5mb250U2l6ZSJdLTIrInB4In0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy50ZXh0SW5hY3RpdmV9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuc2VsZWN0aW9ufSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnNlbGVjdGlvbn0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5zZWxlY3Rpb259LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuc2VsZWN0aW9ufSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnNlbGVjdGlvbn0pLHM9by5jcmVhdGVHbG9iYWxTdHlsZShwfHwocD1yKFsnXG4gICo6Oi13ZWJraXQtc2Nyb2xsYmFyIHtcbiAgICAtd2Via2l0LWFwcGVhcmFuY2U6IG5vbmU7XG4gICAgd2lkdGg6IDdweDtcbiAgICBoZWlnaHQ6IDdweDtcbiAgfVxuICAqOjotd2Via2l0LXNjcm9sbGJhci10cmFjay1waWVjZSB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgyNTUsIDI1NSwgMjU1LCAwKTtcbiAgfVxuICAqOjotd2Via2l0LXNjcm9sbGJhci10cmFjayB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogaW5oZXJpdDtcbiAgfVxuICAqOjotd2Via2l0LXNjcm9sbGJhci10aHVtYiB7XG4gICAgbWF4LWhlaWdodDogMTAwcHg7XG4gICAgYm9yZGVyLXJhZGl1czogM3B4O1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMSwgMSwgMSwgMC4yMyk7XG4gIH1cbiAgKjo6LXdlYmtpdC1zY3JvbGxiYXItdGh1bWI6aG92ZXIge1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMSwgMSwgMSwgMC4zNSk7XG4gIH1cbiAgKjo6LXdlYmtpdC1zY3JvbGxiYXItdGh1bWI6YWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDEsIDEsIDEsIDAuNDgpO1xuICB9XG4gICo6Oi13ZWJraXQtc2Nyb2xsYmFyLWNvcm5lciB7XG4gICAgYmFja2dyb3VuZDogcmdiYSgwLDAsMCwwKTtcbiAgfVxuXG5cbiAgLkNvZGVNaXJyb3ItbGludC10b29sdGlwLCAuQ29kZU1pcnJvci1pbmZvIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTtcbiAgICBib3JkZXItcmFkaXVzOiA0cHggNHB4IDRweCA0cHg7XG4gICAgYm9yZGVyOiAxcHggc29saWQgYmxhY2s7XG4gICAgY29sb3I6ICMwOTE0MUM7XG4gICAgZm9udC1mYW1pbHk6IE9wZW4gU2FucywgbW9ub3NwYWNlO1xuICAgIGZvbnQtc2l6ZTogMTRweDtcbiAgICBtYXgtd2lkdGg6IDYwMHB4O1xuICAgIG9wYWNpdHk6IDA7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICBwYWRkaW5nOiAxMnB4IDE0cHg7XG4gICAgcG9zaXRpb246IGZpeGVkO1xuICAgIC13ZWJraXQtdHJhbnNpdGlvbjogb3BhY2l0eSAwLjRzO1xuICAgIHRyYW5zaXRpb246IG9wYWNpdHkgMC40cztcbiAgICB6LWluZGV4OiAxMDA7XG4gIH1cblxuICAuQ29kZU1pcnJvci1saW50LW1lc3NhZ2UtZXJyb3IsXG4gIC5Db2RlTWlycm9yLWxpbnQtbWVzc2FnZS13YXJuaW5nIHtcbiAgICBwYWRkaW5nLWxlZnQ6IDE4cHg7XG4gIH1cblxuICAuQ29kZU1pcnJvci1saW50LW1hcmstZXJyb3IsXG4gIC5Db2RlTWlycm9yLWxpbnQtbWFyay13YXJuaW5nIHtcbiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiBsZWZ0IGJvdHRvbTtcbiAgICBiYWNrZ3JvdW5kLXJlcGVhdDogcmVwZWF0LXg7XG4gIH1cblxuICAuQ29kZU1pcnJvci1saW50LW1hcmstZXJyb3Ige1xuICAgIGJhY2tncm91bmQtaW1hZ2U6IHVybChcJ2RhdGE6aW1hZ2Uvc3ZnK3htbDt1dGY4LDxzdmcgd2lkdGg9IjUiIGhlaWdodD0iNCIgdmlld0JveD0iMCAwIDUgNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj5cbiAgICA8cGF0aCBkPSJNNSAxLjAwOTU0QzQuODcxOTEgMS4wMzQ3NCA0Ljc1MjE5IDEuMTA5ODkgNC42NzQgMS4yMzVMMy44NyAyLjUyMTQxQzMuMjgyNDkgMy40NjE0MSAxLjkxMzUgMy40NjE0MSAxLjMyNiAyLjUyMTQxTDAuNTIxOTk4IDEuMjM1QzAuNDA0MzU2IDEuMDQ2NzcgMC4xOTI3MSAwLjk3MTYxOSAwIDEuMDA5NTRWMC4wMDMxNDgyMUMwLjAzMjU4NTUgMC4wMDEwNTIwOSAwLjA2NTIyOTEgMi42ODUwM2UtMDYgMC4wOTc4NzI4IDUuMTQ1OTJlLTA5QzAuMDk3Nzg5MiAtMS43MTUzMWUtMDkgMC4wOTc5NTY0IC0xLjcxNTMxZS0wOSAwLjA5Nzg3MjggNS4xNDU5MmUtMDlDMC41ODY5NTQgNC4wMTU2M2UtMDUgMS4wNzYyNyAwLjIzNTA0MSAxLjM3IDAuNzA1MDAyTDIuMTc0IDEuOTkxNDFDMi4zNjk4MyAyLjMwNDc0IDIuODI2MTYgMi4zMDQ3NCAzLjAyMiAxLjk5MTQxTDMuODI2IDAuNzA1MDAyQzQuMTAwMTIgMC4yNjY0MDggNC41NDQzOCAwLjAzMjQ1NjkgNSAwLjAwMzE0ODE4VjEuMDA5NTRaIiBmaWxsPSIjRkY0RjU2Ii8+XG4gICAgPC9zdmc+XG4gICAgXCcpO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGludC1tYXJrLXdhcm5pbmcge1xuICAgIGJhY2tncm91bmQtaW1hZ2U6IHVybChcJ2RhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQVFBQUFBRENBWUFBQUMwOUs3R0FBQUFBWE5TUjBJQXJzNGM2UUFBQUFaaVMwZEVBUDhBL3dEL29MMm5rd0FBQUFsd1NGbHpBQUFMRXdBQUN4TUJBSnFjR0FBQUFBZDBTVTFGQjlzSkZoUVhFYmhUZzdZQUFBQVpkRVZZZEVOdmJXMWxiblFBUTNKbFlYUmxaQ0IzYVhSb0lFZEpUVkJYZ1E0WEFBQUFNa2xFUVZRSTEyTmtnSUl2SjNRWE1qQXdkRE4rT2FFYnlzREE0TVBBd05ETndNQ3dpT0hMQ2QxelgwN282a0JWR1FFQUtCQU50b2Jza05NQUFBQUFTVVZPUks1Q1lJST1cJyk7XG4gIH1cblxuICAuQ29kZU1pcnJvci1saW50LW1hcmtlci1lcnJvcixcbiAgLkNvZGVNaXJyb3ItbGludC1tYXJrZXItd2FybmluZyB7XG4gICAgYmFja2dyb3VuZC1wb3NpdGlvbjogY2VudGVyIGNlbnRlcjtcbiAgICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0O1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgaGVpZ2h0OiAxNnB4O1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO1xuICAgIHdpZHRoOiAxNnB4O1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGludC1tZXNzYWdlLWVycm9yLFxuICAuQ29kZU1pcnJvci1saW50LW1lc3NhZ2Utd2FybmluZyB7XG4gICAgYmFja2dyb3VuZC1wb3NpdGlvbjogdG9wIGxlZnQ7XG4gICAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgICBwYWRkaW5nLWxlZnQ6IDIycHg7XG4gIH1cblxuICAuQ29kZU1pcnJvci1saW50LW1hcmtlci1lcnJvcixcbiAgLkNvZGVNaXJyb3ItbGludC1tZXNzYWdlLWVycm9yIHtcbiAgICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoXCdkYXRhOmltYWdlL3N2Zyt4bWw7dXRmOCw8c3ZnIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPlxuICAgIDxjaXJjbGUgY3g9IjgiIGN5PSI4IiByPSI4IiBmaWxsPSIjRkY0RjU2Ii8+XG4gICAgPHBhdGggZD0iTTQuMjkyOSAxMC4yOTI4QzMuOTAyMzcgMTAuNjgzMyAzLjkwMjM3IDExLjMxNjQgNC4yOTI4OSAxMS43MDdDNC42ODM0MSAxMi4wOTc1IDUuMzE2NTcgMTIuMDk3NSA1LjcwNzEgMTEuNzA3TDQuMjkyOSAxMC4yOTI4Wk0xMS43MDcxIDUuNzA3MTFDMTIuMDk3NiA1LjMxNjU5IDEyLjA5NzYgNC42ODM0MyAxMS43MDcxIDQuMjkyOUMxMS4zMTY2IDMuOTAyMzcgMTAuNjgzNCAzLjkwMjM3IDEwLjI5MjkgNC4yOTI4OUwxMS43MDcxIDUuNzA3MTFaTTUuNzA3MSA0LjI5MzAxQzUuMzE2NTcgMy45MDI0OSA0LjY4MzQxIDMuOTAyNSA0LjI5Mjg5IDQuMjkzMDJDMy45MDIzNyA0LjY4MzU1IDMuOTAyMzcgNS4zMTY3MiA0LjI5MjkgNS43MDcyNEw1LjcwNzEgNC4yOTMwMVpNMTAuMjkyOSAxMS43MDcxQzEwLjY4MzQgMTIuMDk3NiAxMS4zMTY2IDEyLjA5NzYgMTEuNzA3MSAxMS43MDcxQzEyLjA5NzYgMTEuMzE2NiAxMi4wOTc2IDEwLjY4MzQgMTEuNzA3MSAxMC4yOTI5TDEwLjI5MjkgMTEuNzA3MVpNNS43MDcxIDExLjcwN0wxMS43MDcxIDUuNzA3MTFMMTAuMjkyOSA0LjI5Mjg5TDQuMjkyOSAxMC4yOTI4TDUuNzA3MSAxMS43MDdaTTQuMjkyOSA1LjcwNzI0TDEwLjI5MjkgMTEuNzA3MUwxMS43MDcxIDEwLjI5MjlMNS43MDcxIDQuMjkzMDFMNC4yOTI5IDUuNzA3MjRaIiBmaWxsPSJ3aGl0ZSIvPlxuICAgIDwvc3ZnPlxuICAgIFwnKTtcbiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiAwIDUwJTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbnQtbWFya2VyLXdhcm5pbmcsXG4gIC5Db2RlTWlycm9yLWxpbnQtbWVzc2FnZS13YXJuaW5nIHtcbiAgICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoXCdkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUJBQUFBQVFDQU1BQUFBb0xROVRBQUFBTmxCTVZFWC91d0R2cndEL3V3RC91d0QvdXdEL3V3RC91d0QvdXdEL3V3RDZ0d0QvdXdBQUFBRHVyd0QydFFEN3VBRCt1Z0FBQUFEL3V3RGhtZVRSQUFBQURIUlNUbE1KOG1OMUVZY2JtaWl4Z0FDbTdXYnVBQUFBVmtsRVFWUjQybjNQVVFxQUlCQkZVVTFMTGMzdS9qZGJPSm9XMVAwOERBOUdiYTgrWVdKNmdOSm9OWUlCekFBMmNoQnRoNWtMbUc5WVVvRzBOSEFVd0ZYd085THVCUUwxZ2lDUWI4Z0M5T3JvMnZwNXJuY0NJWThMOHVFeDVaa0FBQUFBU1VWT1JLNUNZSUk9XCcpO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGludC1tYXJrZXItbXVsdGlwbGUge1xuICAgIGJhY2tncm91bmQtaW1hZ2U6IHVybChcJ2RhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQWNBQUFBSENBTUFBQUR6aktmaEFBQUFDVkJNVkVVQUFBQUFBQUMvdjc5MTRreUhBQUFBQVhSU1RsTUFRT2JZWmdBQUFDTkpSRUZVZU5vMWlvRUpBQUFJd216L0g5MGlGRlNHSmdGTWUzZ2FMWjBvZCs5L0FRWjBBRG9zYllyYUFBQUFBRWxGVGtTdVFtQ0NcJyk7XG4gICAgYmFja2dyb3VuZC1wb3NpdGlvbjogcmlnaHQgYm90dG9tO1xuICAgIGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGludC1tYXJrLWVycm9yIHtcbiAgICAmOmJlZm9yZSB7XG4gICAgICBjb250ZW50OiBcJ1wnO1xuICAgICAgd2lkdGg6IDUwcHg7XG4gICAgICBoZWlnaHQ6IDE0cHg7XG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgICBiYWNrZ3JvdW5kOiAjRkY0RjU2O1xuICAgICAgbGVmdDogLTgwcHg7XG4gICAgICB0b3A6IDUwJTtcbiAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtNTAlKTtcbiAgICAgIHotaW5kZXg6IDEwO1xuICAgIH1cbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbnQtbWVzc2FnZS1lcnJvciBzcGFuIHtcbiAgICBjb2xvcjogd2hpdGU7XG4gICAgYmFja2dyb3VuZDogI0ZGNEY1NjtcbiAgICBmb250LWZhbWlseTogXCdTb3VyY2UgQ29kZSBQcm9cJywgbW9ub3NwYWNlO1xuICAgIGZvbnQtd2VpZ2h0OiA2MDA7XG4gICAgYm9yZGVyLXJhZGl1czogMnB4O1xuICAgIHBhZGRpbmc6IDAgNHB4O1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludHMge1xuICAgIGJhY2tncm91bmQ6IHdoaXRlO1xuICAgIGJveC1zaGFkb3c6IDAgMXB4IDRweCByZ2JhKDAsIDAsIDAsIDAuMTUpO1xuICAgIGZvbnQtc2l6ZTogMTRweDtcbiAgICBsaXN0LXN0eWxlOiBub25lO1xuICAgIG1hcmdpbi1sZWZ0OiAtNnB4O1xuICAgIG1hcmdpbjogMDtcbiAgICBtYXgtaGVpZ2h0OiAyMGVtO1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgcGFkZGluZzogMDtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgei1pbmRleDogMTA7XG4gICAgYm9yZGVyLXJhZGl1czogMnB4O1xuICAgIHRvcDogMDtcbiAgICBsZWZ0OiAwO1xuICAgICY6aG92ZXIge1xuICAgICAgb3ZlcmZsb3cteTogb3ZlcmxheTtcbiAgICB9XG4gIH1cblxuICAuQ29kZU1pcnJvci1oaW50cy13cmFwcGVyIHtcbiAgICBmb250LWZhbWlseTogXCdPcGVuIFNhbnNcJywgc2Fucy1zZXJpZjtcbiAgICBiYWNrZ3JvdW5kOiB3aGl0ZTtcbiAgICBib3gtc2hhZG93OiAwIDFweCAzcHggcmdiYSgwLCAwLCAwLCAwLjQ1KTtcbiAgICBtYXJnaW4tbGVmdDogLTZweDtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgei1pbmRleDogMTA7XG4gIH1cblxuICAuQ29kZU1pcnJvci1oaW50cy13cmFwcGVyIC5Db2RlTWlycm9yLWhpbnRzIHtcbiAgICBib3gtc2hhZG93OiBub25lO1xuICAgIG1hcmdpbi1sZWZ0OiAwO1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICB6LWluZGV4OiAwO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludCB7XG4gICAgY29sb3I6IHJnYmEoMTUsIDMyLCA0NSwgMC42KTtcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgbWFyZ2luOiAwO1xuICAgIG1heC13aWR0aDogMzAwcHg7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICBwYWRkaW5nOiA2cHggMTJweDtcbiAgICB3aGl0ZS1zcGFjZTogcHJlO1xuICB9XG5cbiAgbGkuQ29kZU1pcnJvci1oaW50LWFjdGl2ZSB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogIzJhN2VkMztcbiAgICBib3JkZXItdG9wLWNvbG9yOiB3aGl0ZTtcbiAgICBjb2xvcjogd2hpdGU7XG4gIH1cblxuICAuQ29kZU1pcnJvci1oaW50LWluZm9ybWF0aW9uIHtcbiAgICBib3JkZXItdG9wOiBzb2xpZCAxcHggcmdiYSgwLCAwLCAwLCAwLjEpO1xuICAgIG1heC13aWR0aDogMzAwcHg7XG4gICAgcGFkZGluZzogMTBweCAxMnB4O1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICB6LWluZGV4OiAxO1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMTUsIDMyLCA0NSwgMC4wMyk7XG4gICAgZm9udC1zaXplOiAxNHB4O1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludC1pbmZvcm1hdGlvbjpmaXJzdC1jaGlsZCB7XG4gICAgYm9yZGVyLWJvdHRvbTogc29saWQgMXB4ICNjMGMwYzA7XG4gICAgYm9yZGVyLXRvcDogbm9uZTtcbiAgICBtYXJnaW4tYm90dG9tOiAtMXB4O1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludC1pbmZvcm1hdGlvbiAuY29udGVudCB7XG4gICAgY29sb3I6IHJnYmEoMTUsIDMyLCA0NSwgMC42KTtcbiAgICBib3gtb3JpZW50OiB2ZXJ0aWNhbDtcbiAgICBkaXNwbGF5OiAtd2Via2l0LWJveDtcbiAgICBkaXNwbGF5OiAtbXMtZmxleGJveDtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGxpbmUtY2xhbXA6IDM7XG4gICAgbGluZS1oZWlnaHQ6IDEuMzY7XG4gICAgbWF4LWhlaWdodDogNTlweDtcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIHRleHQtb3ZlcmZsb3c6IC1vLWVsbGlwc2lzLWxhc3RsaW5lO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludC1pbmZvcm1hdGlvbiAuY29udGVudCBwOmZpcnN0LWNoaWxkIHtcbiAgICBtYXJnaW4tdG9wOiAwO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludC1pbmZvcm1hdGlvbiAuY29udGVudCBwOmxhc3QtY2hpbGQge1xuICAgIG1hcmdpbi1ib3R0b206IDA7XG4gIH1cblxuICAuQ29kZU1pcnJvci1oaW50LWluZm9ybWF0aW9uIC5pbmZvVHlwZSB7XG4gICAgY29sb3I6IHJnYigyNDEsIDE0MywgMSk7XG4gICAgY3Vyc29yOiBwb2ludGVyO1xuICAgIGRpc3BsYXk6IGlubGluZTtcbiAgICBtYXJnaW4tcmlnaHQ6IDAuNWVtO1xuICB9XG4nXSxbJ1xuICAqOjotd2Via2l0LXNjcm9sbGJhciB7XG4gICAgLXdlYmtpdC1hcHBlYXJhbmNlOiBub25lO1xuICAgIHdpZHRoOiA3cHg7XG4gICAgaGVpZ2h0OiA3cHg7XG4gIH1cbiAgKjo6LXdlYmtpdC1zY3JvbGxiYXItdHJhY2stcGllY2Uge1xuICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMCk7XG4gIH1cbiAgKjo6LXdlYmtpdC1zY3JvbGxiYXItdHJhY2sge1xuICAgIGJhY2tncm91bmQtY29sb3I6IGluaGVyaXQ7XG4gIH1cbiAgKjo6LXdlYmtpdC1zY3JvbGxiYXItdGh1bWIge1xuICAgIG1heC1oZWlnaHQ6IDEwMHB4O1xuICAgIGJvcmRlci1yYWRpdXM6IDNweDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDEsIDEsIDEsIDAuMjMpO1xuICB9XG4gICo6Oi13ZWJraXQtc2Nyb2xsYmFyLXRodW1iOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDEsIDEsIDEsIDAuMzUpO1xuICB9XG4gICo6Oi13ZWJraXQtc2Nyb2xsYmFyLXRodW1iOmFjdGl2ZSB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgxLCAxLCAxLCAwLjQ4KTtcbiAgfVxuICAqOjotd2Via2l0LXNjcm9sbGJhci1jb3JuZXIge1xuICAgIGJhY2tncm91bmQ6IHJnYmEoMCwwLDAsMCk7XG4gIH1cblxuXG4gIC5Db2RlTWlycm9yLWxpbnQtdG9vbHRpcCwgLkNvZGVNaXJyb3ItaW5mbyB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogd2hpdGU7XG4gICAgYm9yZGVyLXJhZGl1czogNHB4IDRweCA0cHggNHB4O1xuICAgIGJvcmRlcjogMXB4IHNvbGlkIGJsYWNrO1xuICAgIGNvbG9yOiAjMDkxNDFDO1xuICAgIGZvbnQtZmFtaWx5OiBPcGVuIFNhbnMsIG1vbm9zcGFjZTtcbiAgICBmb250LXNpemU6IDE0cHg7XG4gICAgbWF4LXdpZHRoOiA2MDBweDtcbiAgICBvcGFjaXR5OiAwO1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgcGFkZGluZzogMTJweCAxNHB4O1xuICAgIHBvc2l0aW9uOiBmaXhlZDtcbiAgICAtd2Via2l0LXRyYW5zaXRpb246IG9wYWNpdHkgMC40cztcbiAgICB0cmFuc2l0aW9uOiBvcGFjaXR5IDAuNHM7XG4gICAgei1pbmRleDogMTAwO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGludC1tZXNzYWdlLWVycm9yLFxuICAuQ29kZU1pcnJvci1saW50LW1lc3NhZ2Utd2FybmluZyB7XG4gICAgcGFkZGluZy1sZWZ0OiAxOHB4O1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGludC1tYXJrLWVycm9yLFxuICAuQ29kZU1pcnJvci1saW50LW1hcmstd2FybmluZyB7XG4gICAgYmFja2dyb3VuZC1wb3NpdGlvbjogbGVmdCBib3R0b207XG4gICAgYmFja2dyb3VuZC1yZXBlYXQ6IHJlcGVhdC14O1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGludC1tYXJrLWVycm9yIHtcbiAgICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoXCdkYXRhOmltYWdlL3N2Zyt4bWw7dXRmOCw8c3ZnIHdpZHRoPSI1IiBoZWlnaHQ9IjQiIHZpZXdCb3g9IjAgMCA1IDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+XG4gICAgPHBhdGggZD0iTTUgMS4wMDk1NEM0Ljg3MTkxIDEuMDM0NzQgNC43NTIxOSAxLjEwOTg5IDQuNjc0IDEuMjM1TDMuODcgMi41MjE0MUMzLjI4MjQ5IDMuNDYxNDEgMS45MTM1IDMuNDYxNDEgMS4zMjYgMi41MjE0MUwwLjUyMTk5OCAxLjIzNUMwLjQwNDM1NiAxLjA0Njc3IDAuMTkyNzEgMC45NzE2MTkgMCAxLjAwOTU0VjAuMDAzMTQ4MjFDMC4wMzI1ODU1IDAuMDAxMDUyMDkgMC4wNjUyMjkxIDIuNjg1MDNlLTA2IDAuMDk3ODcyOCA1LjE0NTkyZS0wOUMwLjA5Nzc4OTIgLTEuNzE1MzFlLTA5IDAuMDk3OTU2NCAtMS43MTUzMWUtMDkgMC4wOTc4NzI4IDUuMTQ1OTJlLTA5QzAuNTg2OTU0IDQuMDE1NjNlLTA1IDEuMDc2MjcgMC4yMzUwNDEgMS4zNyAwLjcwNTAwMkwyLjE3NCAxLjk5MTQxQzIuMzY5ODMgMi4zMDQ3NCAyLjgyNjE2IDIuMzA0NzQgMy4wMjIgMS45OTE0MUwzLjgyNiAwLjcwNTAwMkM0LjEwMDEyIDAuMjY2NDA4IDQuNTQ0MzggMC4wMzI0NTY5IDUgMC4wMDMxNDgxOFYxLjAwOTU0WiIgZmlsbD0iI0ZGNEY1NiIvPlxuICAgIDwvc3ZnPlxuICAgIFwnKTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbnQtbWFyay13YXJuaW5nIHtcbiAgICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoXCdkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUFRQUFBQURDQVlBQUFDMDlLN0dBQUFBQVhOU1IwSUFyczRjNlFBQUFBWmlTMGRFQVA4QS93RC9vTDJua3dBQUFBbHdTRmx6QUFBTEV3QUFDeE1CQUpxY0dBQUFBQWQwU1UxRkI5c0pGaFFYRWJoVGc3WUFBQUFaZEVWWWRFTnZiVzFsYm5RQVEzSmxZWFJsWkNCM2FYUm9JRWRKVFZCWGdRNFhBQUFBTWtsRVFWUUkxMk5rZ0lJdkozUVhNakF3ZEROK09hRWJ5c0RBNE1QQXdORE53TUN3aU9ITENkMXpYMDdvNmtCVkdRRUFLQkFOdG9ic2tOTUFBQUFBU1VWT1JLNUNZSUk9XCcpO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGludC1tYXJrZXItZXJyb3IsXG4gIC5Db2RlTWlycm9yLWxpbnQtbWFya2VyLXdhcm5pbmcge1xuICAgIGJhY2tncm91bmQtcG9zaXRpb246IGNlbnRlciBjZW50ZXI7XG4gICAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICAgIGhlaWdodDogMTZweDtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcbiAgICB3aWR0aDogMTZweDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbnQtbWVzc2FnZS1lcnJvcixcbiAgLkNvZGVNaXJyb3ItbGludC1tZXNzYWdlLXdhcm5pbmcge1xuICAgIGJhY2tncm91bmQtcG9zaXRpb246IHRvcCBsZWZ0O1xuICAgIGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7XG4gICAgcGFkZGluZy1sZWZ0OiAyMnB4O1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItbGludC1tYXJrZXItZXJyb3IsXG4gIC5Db2RlTWlycm9yLWxpbnQtbWVzc2FnZS1lcnJvciB7XG4gICAgYmFja2dyb3VuZC1pbWFnZTogdXJsKFwnZGF0YTppbWFnZS9zdmcreG1sO3V0ZjgsPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj5cbiAgICA8Y2lyY2xlIGN4PSI4IiBjeT0iOCIgcj0iOCIgZmlsbD0iI0ZGNEY1NiIvPlxuICAgIDxwYXRoIGQ9Ik00LjI5MjkgMTAuMjkyOEMzLjkwMjM3IDEwLjY4MzMgMy45MDIzNyAxMS4zMTY0IDQuMjkyODkgMTEuNzA3QzQuNjgzNDEgMTIuMDk3NSA1LjMxNjU3IDEyLjA5NzUgNS43MDcxIDExLjcwN0w0LjI5MjkgMTAuMjkyOFpNMTEuNzA3MSA1LjcwNzExQzEyLjA5NzYgNS4zMTY1OSAxMi4wOTc2IDQuNjgzNDMgMTEuNzA3MSA0LjI5MjlDMTEuMzE2NiAzLjkwMjM3IDEwLjY4MzQgMy45MDIzNyAxMC4yOTI5IDQuMjkyODlMMTEuNzA3MSA1LjcwNzExWk01LjcwNzEgNC4yOTMwMUM1LjMxNjU3IDMuOTAyNDkgNC42ODM0MSAzLjkwMjUgNC4yOTI4OSA0LjI5MzAyQzMuOTAyMzcgNC42ODM1NSAzLjkwMjM3IDUuMzE2NzIgNC4yOTI5IDUuNzA3MjRMNS43MDcxIDQuMjkzMDFaTTEwLjI5MjkgMTEuNzA3MUMxMC42ODM0IDEyLjA5NzYgMTEuMzE2NiAxMi4wOTc2IDExLjcwNzEgMTEuNzA3MUMxMi4wOTc2IDExLjMxNjYgMTIuMDk3NiAxMC42ODM0IDExLjcwNzEgMTAuMjkyOUwxMC4yOTI5IDExLjcwNzFaTTUuNzA3MSAxMS43MDdMMTEuNzA3MSA1LjcwNzExTDEwLjI5MjkgNC4yOTI4OUw0LjI5MjkgMTAuMjkyOEw1LjcwNzEgMTEuNzA3Wk00LjI5MjkgNS43MDcyNEwxMC4yOTI5IDExLjcwNzFMMTEuNzA3MSAxMC4yOTI5TDUuNzA3MSA0LjI5MzAxTDQuMjkyOSA1LjcwNzI0WiIgZmlsbD0id2hpdGUiLz5cbiAgICA8L3N2Zz5cbiAgICBcJyk7XG4gICAgYmFja2dyb3VuZC1wb3NpdGlvbjogMCA1MCU7XG4gIH1cblxuICAuQ29kZU1pcnJvci1saW50LW1hcmtlci13YXJuaW5nLFxuICAuQ29kZU1pcnJvci1saW50LW1lc3NhZ2Utd2FybmluZyB7XG4gICAgYmFja2dyb3VuZC1pbWFnZTogdXJsKFwnZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFCQUFBQUFRQ0FNQUFBQW9MUTlUQUFBQU5sQk1WRVgvdXdEdnJ3RC91d0QvdXdEL3V3RC91d0QvdXdEL3V3RC91d0Q2dHdEL3V3QUFBQUR1cndEMnRRRDd1QUQrdWdBQUFBRC91d0RobWVUUkFBQUFESFJTVGxNSjhtTjFFWWNibWlpeGdBQ203V2J1QUFBQVZrbEVRVlI0Mm4zUFVRcUFJQkJGVVUxTExjM3UvamRiT0pvVzFQMDhEQTlHYmE4K1lXSjZnTkpvTllJQnpBQTJjaEJ0aDVrTG1HOVlVb0cwTkhBVXdGWHdPOUx1QlFMMWdpQ1FiOGdDOU9ybzJ2cDVybmNDSVk4TDh1RXg1WmtBQUFBQVNVVk9SSzVDWUlJPVwnKTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbnQtbWFya2VyLW11bHRpcGxlIHtcbiAgICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoXCdkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUFjQUFBQUhDQU1BQUFEempLZmhBQUFBQ1ZCTVZFVUFBQUFBQUFDL3Y3OTE0a3lIQUFBQUFYUlNUbE1BUU9iWVpnQUFBQ05KUkVGVWVObzFpb0VKQUFBSXdtei9IOTBpRkZTR0pnRk1lM2dhTFowb2QrOS9BUVowQURvc2JZcmFBQUFBQUVsRlRrU3VRbUNDXCcpO1xuICAgIGJhY2tncm91bmQtcG9zaXRpb246IHJpZ2h0IGJvdHRvbTtcbiAgICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0O1xuICAgIHdpZHRoOiAxMDAlO1xuICAgIGhlaWdodDogMTAwJTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWxpbnQtbWFyay1lcnJvciB7XG4gICAgJjpiZWZvcmUge1xuICAgICAgY29udGVudDogXCdcJztcbiAgICAgIHdpZHRoOiA1MHB4O1xuICAgICAgaGVpZ2h0OiAxNHB4O1xuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgYmFja2dyb3VuZDogI0ZGNEY1NjtcbiAgICAgIGxlZnQ6IC04MHB4O1xuICAgICAgdG9wOiA1MCU7XG4gICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVkoLTUwJSk7XG4gICAgICB6LWluZGV4OiAxMDtcbiAgICB9XG4gIH1cblxuICAuQ29kZU1pcnJvci1saW50LW1lc3NhZ2UtZXJyb3Igc3BhbiB7XG4gICAgY29sb3I6IHdoaXRlO1xuICAgIGJhY2tncm91bmQ6ICNGRjRGNTY7XG4gICAgZm9udC1mYW1pbHk6IFwnU291cmNlIENvZGUgUHJvXCcsIG1vbm9zcGFjZTtcbiAgICBmb250LXdlaWdodDogNjAwO1xuICAgIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgICBwYWRkaW5nOiAwIDRweDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWhpbnRzIHtcbiAgICBiYWNrZ3JvdW5kOiB3aGl0ZTtcbiAgICBib3gtc2hhZG93OiAwIDFweCA0cHggcmdiYSgwLCAwLCAwLCAwLjE1KTtcbiAgICBmb250LXNpemU6IDE0cHg7XG4gICAgbGlzdC1zdHlsZTogbm9uZTtcbiAgICBtYXJnaW4tbGVmdDogLTZweDtcbiAgICBtYXJnaW46IDA7XG4gICAgbWF4LWhlaWdodDogMjBlbTtcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIHBhZGRpbmc6IDA7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHotaW5kZXg6IDEwO1xuICAgIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgICB0b3A6IDA7XG4gICAgbGVmdDogMDtcbiAgICAmOmhvdmVyIHtcbiAgICAgIG92ZXJmbG93LXk6IG92ZXJsYXk7XG4gICAgfVxuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludHMtd3JhcHBlciB7XG4gICAgZm9udC1mYW1pbHk6IFwnT3BlbiBTYW5zXCcsIHNhbnMtc2VyaWY7XG4gICAgYmFja2dyb3VuZDogd2hpdGU7XG4gICAgYm94LXNoYWRvdzogMCAxcHggM3B4IHJnYmEoMCwgMCwgMCwgMC40NSk7XG4gICAgbWFyZ2luLWxlZnQ6IC02cHg7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHotaW5kZXg6IDEwO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludHMtd3JhcHBlciAuQ29kZU1pcnJvci1oaW50cyB7XG4gICAgYm94LXNoYWRvdzogbm9uZTtcbiAgICBtYXJnaW4tbGVmdDogMDtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgei1pbmRleDogMDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWhpbnQge1xuICAgIGNvbG9yOiByZ2JhKDE1LCAzMiwgNDUsIDAuNik7XG4gICAgY3Vyc29yOiBwb2ludGVyO1xuICAgIG1hcmdpbjogMDtcbiAgICBtYXgtd2lkdGg6IDMwMHB4O1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgcGFkZGluZzogNnB4IDEycHg7XG4gICAgd2hpdGUtc3BhY2U6IHByZTtcbiAgfVxuXG4gIGxpLkNvZGVNaXJyb3ItaGludC1hY3RpdmUge1xuICAgIGJhY2tncm91bmQtY29sb3I6ICMyYTdlZDM7XG4gICAgYm9yZGVyLXRvcC1jb2xvcjogd2hpdGU7XG4gICAgY29sb3I6IHdoaXRlO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludC1pbmZvcm1hdGlvbiB7XG4gICAgYm9yZGVyLXRvcDogc29saWQgMXB4IHJnYmEoMCwgMCwgMCwgMC4xKTtcbiAgICBtYXgtd2lkdGg6IDMwMHB4O1xuICAgIHBhZGRpbmc6IDEwcHggMTJweDtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgei1pbmRleDogMTtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDE1LCAzMiwgNDUsIDAuMDMpO1xuICAgIGZvbnQtc2l6ZTogMTRweDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWhpbnQtaW5mb3JtYXRpb246Zmlyc3QtY2hpbGQge1xuICAgIGJvcmRlci1ib3R0b206IHNvbGlkIDFweCAjYzBjMGMwO1xuICAgIGJvcmRlci10b3A6IG5vbmU7XG4gICAgbWFyZ2luLWJvdHRvbTogLTFweDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWhpbnQtaW5mb3JtYXRpb24gLmNvbnRlbnQge1xuICAgIGNvbG9yOiByZ2JhKDE1LCAzMiwgNDUsIDAuNik7XG4gICAgYm94LW9yaWVudDogdmVydGljYWw7XG4gICAgZGlzcGxheTogLXdlYmtpdC1ib3g7XG4gICAgZGlzcGxheTogLW1zLWZsZXhib3g7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBsaW5lLWNsYW1wOiAzO1xuICAgIGxpbmUtaGVpZ2h0OiAxLjM2O1xuICAgIG1heC1oZWlnaHQ6IDU5cHg7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICB0ZXh0LW92ZXJmbG93OiAtby1lbGxpcHNpcy1sYXN0bGluZTtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWhpbnQtaW5mb3JtYXRpb24gLmNvbnRlbnQgcDpmaXJzdC1jaGlsZCB7XG4gICAgbWFyZ2luLXRvcDogMDtcbiAgfVxuXG4gIC5Db2RlTWlycm9yLWhpbnQtaW5mb3JtYXRpb24gLmNvbnRlbnQgcDpsYXN0LWNoaWxkIHtcbiAgICBtYXJnaW4tYm90dG9tOiAwO1xuICB9XG5cbiAgLkNvZGVNaXJyb3ItaGludC1pbmZvcm1hdGlvbiAuaW5mb1R5cGUge1xuICAgIGNvbG9yOiByZ2IoMjQxLCAxNDMsIDEpO1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICBkaXNwbGF5OiBpbmxpbmU7XG4gICAgbWFyZ2luLXJpZ2h0OiAwLjVlbTtcbiAgfVxuJ10pKSksdT1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUpe2lmKGUudGFyZ2V0LmNsYXNzTGlzdC5jb250YWlucygiQ29kZU1pcnJvci1saW50LW1hcmstZXJyb3IiKSlmb3IodmFyIHQ9ZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSgiQ29kZU1pcnJvci1saW50LW1lc3NhZ2UtZXJyb3IiKSxuPTAscj1BcnJheS5mcm9tKHQpO248ci5sZW5ndGg7bisrKXt2YXIgaT1yW25dO2kuaW5uZXJIVE1MPWkuaW5uZXJIVE1MLnJlcGxhY2UoLyIoLio/KSIvZywiPHNwYW4+JDE8L3NwYW4+Iil9fXZhciBuPWUuY2hpbGRyZW47cmV0dXJuIGkuY3JlYXRlRWxlbWVudChhLHtvbk1vdXNlTW92ZTp0fSxuLGkuY3JlYXRlRWxlbWVudChzLG51bGwpKX0sYz1vLnN0eWxlZC5kaXYoZnx8KGY9cihbIlxuICBjb2xvcjogIzE0MTgyMztcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IHJvdztcbiAgZm9udC1mYW1pbHk6IHN5c3RlbSwgLWFwcGxlLXN5c3RlbSwgJ1NhbiBGcmFuY2lzY28nLCAnLlNGTlNEaXNwbGF5LVJlZ3VsYXInLFxuICAgICdTZWdvZSBVSScsIFNlZ29lLCAnU2Vnb2UgV1AnLCAnSGVsdmV0aWNhIE5ldWUnLCBoZWx2ZXRpY2EsICdMdWNpZGEgR3JhbmRlJyxcbiAgICBhcmlhbCwgc2Fucy1zZXJpZjtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBoZWlnaHQ6IDEwMCU7XG4gIG1hcmdpbjogMDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgd2lkdGg6IDEwMCU7XG4iXSxbIlxuICBjb2xvcjogIzE0MTgyMztcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IHJvdztcbiAgZm9udC1mYW1pbHk6IHN5c3RlbSwgLWFwcGxlLXN5c3RlbSwgJ1NhbiBGcmFuY2lzY28nLCAnLlNGTlNEaXNwbGF5LVJlZ3VsYXInLFxuICAgICdTZWdvZSBVSScsIFNlZ29lLCAnU2Vnb2UgV1AnLCAnSGVsdmV0aWNhIE5ldWUnLCBoZWx2ZXRpY2EsICdMdWNpZGEgR3JhbmRlJyxcbiAgICBhcmlhbCwgc2Fucy1zZXJpZjtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBoZWlnaHQ6IDEwMCU7XG4gIG1hcmdpbjogMDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgd2lkdGg6IDEwMCU7XG4iXSkpKTt0LkNvbnRhaW5lcj1mdW5jdGlvbihlKXt2YXIgdD1lLmNoaWxkcmVuLG49ZS5zZXRSZWY7cmV0dXJuIGkuY3JlYXRlRWxlbWVudChjLHtyZWY6bn0sdCl9LHQuZGVmYXVsdD11O3ZhciBsLHAsZn0sZnVuY3Rpb24oZSx0LG4peyFmdW5jdGlvbihlKXtlKG4oMikpfShmdW5jdGlvbihlKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gdChlKXt2YXIgdD1lLmZsYWdzO3JldHVybiBudWxsIT10P3Q6KGUuaWdub3JlQ2FzZT8iaSI6IiIpKyhlLmdsb2JhbD8iZyI6IiIpKyhlLm11bHRpbGluZT8ibSI6IiIpfWZ1bmN0aW9uIG4oZSxuKXtmb3IodmFyIHI9dChlKSxpPXIsbz0wO288bi5sZW5ndGg7bysrKS0xPT1pLmluZGV4T2Yobi5jaGFyQXQobykpJiYoaSs9bi5jaGFyQXQobykpO3JldHVybiByPT1pP2U6bmV3IFJlZ0V4cChlLnNvdXJjZSxpKX1mdW5jdGlvbiByKGUpe3JldHVybi9cXHN8XFxufFxufFxcV3xcXER8XFtcXi8udGVzdChlLnNvdXJjZSl9ZnVuY3Rpb24gaShlLHQscil7dD1uKHQsImciKTtmb3IodmFyIGk9ci5saW5lLG89ci5jaCxhPWUubGFzdExpbmUoKTtpPD1hO2krKyxvPTApe3QubGFzdEluZGV4PW87dmFyIHM9ZS5nZXRMaW5lKGkpLHU9dC5leGVjKHMpO2lmKHUpcmV0dXJue2Zyb206bShpLHUuaW5kZXgpLHRvOm0oaSx1LmluZGV4K3VbMF0ubGVuZ3RoKSxtYXRjaDp1fX19ZnVuY3Rpb24gbyhlLHQsbyl7aWYoIXIodCkpcmV0dXJuIGkoZSx0LG8pO3Q9bih0LCJnbSIpO2Zvcih2YXIgYSxzPTEsdT1vLmxpbmUsYz1lLmxhc3RMaW5lKCk7dTw9Yzspe2Zvcih2YXIgbD0wO2w8cyYmISh1PmMpO2wrKyl7dmFyIHA9ZS5nZXRMaW5lKHUrKyk7YT1udWxsPT1hP3A6YSsiXG4iK3B9cyo9Mix0Lmxhc3RJbmRleD1vLmNoO3ZhciBmPXQuZXhlYyhhKTtpZihmKXt2YXIgZD1hLnNsaWNlKDAsZi5pbmRleCkuc3BsaXQoIlxuIiksaD1mWzBdLnNwbGl0KCJcbiIpLGc9by5saW5lK2QubGVuZ3RoLTEseT1kW2QubGVuZ3RoLTFdLmxlbmd0aDtyZXR1cm57ZnJvbTptKGcseSksdG86bShnK2gubGVuZ3RoLTEsMT09aC5sZW5ndGg/eStoWzBdLmxlbmd0aDpoW2gubGVuZ3RoLTFdLmxlbmd0aCksbWF0Y2g6Zn19fX1mdW5jdGlvbiBhKGUsdCl7Zm9yKHZhciBuLHI9MDs7KXt0Lmxhc3RJbmRleD1yO3ZhciBpPXQuZXhlYyhlKTtpZighaSlyZXR1cm4gbjtpZihuPWksKHI9bi5pbmRleCsoblswXS5sZW5ndGh8fDEpKT09ZS5sZW5ndGgpcmV0dXJuIG59fWZ1bmN0aW9uIHMoZSx0LHIpe3Q9bih0LCJnIik7Zm9yKHZhciBpPXIubGluZSxvPXIuY2gscz1lLmZpcnN0TGluZSgpO2k+PXM7aS0tLG89LTEpe3ZhciB1PWUuZ2V0TGluZShpKTtvPi0xJiYodT11LnNsaWNlKDAsbykpO3ZhciBjPWEodSx0KTtpZihjKXJldHVybntmcm9tOm0oaSxjLmluZGV4KSx0bzptKGksYy5pbmRleCtjWzBdLmxlbmd0aCksbWF0Y2g6Y319fWZ1bmN0aW9uIHUoZSx0LHIpe3Q9bih0LCJnbSIpO2Zvcih2YXIgaSxvPTEscz1yLmxpbmUsdT1lLmZpcnN0TGluZSgpO3M+PXU7KXtmb3IodmFyIGM9MDtjPG87YysrKXt2YXIgbD1lLmdldExpbmUocy0tKTtpPW51bGw9PWk/bC5zbGljZSgwLHIuY2gpOmwrIlxuIitpfW8qPTI7dmFyIHA9YShpLHQpO2lmKHApe3ZhciBmPWkuc2xpY2UoMCxwLmluZGV4KS5zcGxpdCgiXG4iKSxkPXBbMF0uc3BsaXQoIlxuIiksaD1zK2YubGVuZ3RoLGc9ZltmLmxlbmd0aC0xXS5sZW5ndGg7cmV0dXJue2Zyb206bShoLGcpLHRvOm0oaCtkLmxlbmd0aC0xLDE9PWQubGVuZ3RoP2crZFswXS5sZW5ndGg6ZFtkLmxlbmd0aC0xXS5sZW5ndGgpLG1hdGNoOnB9fX19ZnVuY3Rpb24gYyhlLHQsbixyKXtpZihlLmxlbmd0aD09dC5sZW5ndGgpcmV0dXJuIG47Zm9yKHZhciBpPTAsbz1uK01hdGgubWF4KDAsZS5sZW5ndGgtdC5sZW5ndGgpOzspe2lmKGk9PW8pcmV0dXJuIGk7dmFyIGE9aStvPj4xLHM9cihlLnNsaWNlKDAsYSkpLmxlbmd0aDtpZihzPT1uKXJldHVybiBhO3M+bj9vPWE6aT1hKzF9fWZ1bmN0aW9uIGwoZSx0LG4scil7aWYoIXQubGVuZ3RoKXJldHVybiBudWxsO3ZhciBpPXI/ZDpoLG89aSh0KS5zcGxpdCgvXHJ8XG5ccj8vKTtlOmZvcih2YXIgYT1uLmxpbmUscz1uLmNoLHU9ZS5sYXN0TGluZSgpKzEtby5sZW5ndGg7YTw9dTthKysscz0wKXt2YXIgbD1lLmdldExpbmUoYSkuc2xpY2UocykscD1pKGwpO2lmKDE9PW8ubGVuZ3RoKXt2YXIgZj1wLmluZGV4T2Yob1swXSk7aWYoLTE9PWYpY29udGludWUgZTt2YXIgbj1jKGwscCxmLGkpK3M7cmV0dXJue2Zyb206bShhLGMobCxwLGYsaSkrcyksdG86bShhLGMobCxwLGYrb1swXS5sZW5ndGgsaSkrcyl9fXZhciBnPXAubGVuZ3RoLW9bMF0ubGVuZ3RoO2lmKHAuc2xpY2UoZyk9PW9bMF0pe2Zvcih2YXIgeT0xO3k8by5sZW5ndGgtMTt5KyspaWYoaShlLmdldExpbmUoYSt5KSkhPW9beV0pY29udGludWUgZTt2YXIgdj1lLmdldExpbmUoYStvLmxlbmd0aC0xKSxiPWkodikseD1vW28ubGVuZ3RoLTFdO2lmKGIuc2xpY2UoMCx4Lmxlbmd0aCk9PXgpcmV0dXJue2Zyb206bShhLGMobCxwLGcsaSkrcyksdG86bShhK28ubGVuZ3RoLTEsYyh2LGIseC5sZW5ndGgsaSkpfX19fWZ1bmN0aW9uIHAoZSx0LG4scil7aWYoIXQubGVuZ3RoKXJldHVybiBudWxsO3ZhciBpPXI/ZDpoLG89aSh0KS5zcGxpdCgvXHJ8XG5ccj8vKTtlOmZvcih2YXIgYT1uLmxpbmUscz1uLmNoLHU9ZS5maXJzdExpbmUoKS0xK28ubGVuZ3RoO2E+PXU7YS0tLHM9LTEpe3ZhciBsPWUuZ2V0TGluZShhKTtzPi0xJiYobD1sLnNsaWNlKDAscykpO3ZhciBwPWkobCk7aWYoMT09by5sZW5ndGgpe3ZhciBmPXAubGFzdEluZGV4T2Yob1swXSk7aWYoLTE9PWYpY29udGludWUgZTtyZXR1cm57ZnJvbTptKGEsYyhsLHAsZixpKSksdG86bShhLGMobCxwLGYrb1swXS5sZW5ndGgsaSkpfX12YXIgZz1vW28ubGVuZ3RoLTFdO2lmKHAuc2xpY2UoMCxnLmxlbmd0aCk9PWcpe2Zvcih2YXIgeT0xLG49YS1vLmxlbmd0aCsxO3k8by5sZW5ndGgtMTt5KyspaWYoaShlLmdldExpbmUobit5KSkhPW9beV0pY29udGludWUgZTt2YXIgdj1lLmdldExpbmUoYSsxLW8ubGVuZ3RoKSxiPWkodik7aWYoYi5zbGljZShiLmxlbmd0aC1vWzBdLmxlbmd0aCk9PW9bMF0pcmV0dXJue2Zyb206bShhKzEtby5sZW5ndGgsYyh2LGIsdi5sZW5ndGgtb1swXS5sZW5ndGgsaSkpLHRvOm0oYSxjKGwscCxnLmxlbmd0aCxpKSl9fX19ZnVuY3Rpb24gZihlLHQscixhKXt0aGlzLmF0T2NjdXJyZW5jZT0hMSx0aGlzLmRvYz1lLHI9cj9lLmNsaXBQb3Mocik6bSgwLDApLHRoaXMucG9zPXtmcm9tOnIsdG86cn07dmFyIGM7Im9iamVjdCI9PXR5cGVvZiBhP2M9YS5jYXNlRm9sZDooYz1hLGE9bnVsbCksInN0cmluZyI9PXR5cGVvZiB0PyhudWxsPT1jJiYoYz0hMSksdGhpcy5tYXRjaGVzPWZ1bmN0aW9uKG4scil7cmV0dXJuKG4/cDpsKShlLHQscixjKX0pOih0PW4odCwiZ20iKSxhJiYhMT09PWEubXVsdGlsaW5lP3RoaXMubWF0Y2hlcz1mdW5jdGlvbihuLHIpe3JldHVybihuP3M6aSkoZSx0LHIpfTp0aGlzLm1hdGNoZXM9ZnVuY3Rpb24obixyKXtyZXR1cm4obj91Om8pKGUsdCxyKX0pfXZhciBkLGgsbT1lLlBvcztTdHJpbmcucHJvdG90eXBlLm5vcm1hbGl6ZT8oZD1mdW5jdGlvbihlKXtyZXR1cm4gZS5ub3JtYWxpemUoIk5GRCIpLnRvTG93ZXJDYXNlKCl9LGg9ZnVuY3Rpb24oZSl7cmV0dXJuIGUubm9ybWFsaXplKCJORkQiKX0pOihkPWZ1bmN0aW9uKGUpe3JldHVybiBlLnRvTG93ZXJDYXNlKCl9LGg9ZnVuY3Rpb24oZSl7cmV0dXJuIGV9KSxmLnByb3RvdHlwZT17ZmluZE5leHQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5maW5kKCExKX0sZmluZFByZXZpb3VzOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZmluZCghMCl9LGZpbmQ6ZnVuY3Rpb24odCl7Zm9yKHZhciBuPXRoaXMubWF0Y2hlcyh0LHRoaXMuZG9jLmNsaXBQb3ModD90aGlzLnBvcy5mcm9tOnRoaXMucG9zLnRvKSk7biYmMD09ZS5jbXBQb3Mobi5mcm9tLG4udG8pOyl0P24uZnJvbS5jaD9uLmZyb209bShuLmZyb20ubGluZSxuLmZyb20uY2gtMSk6bj1uLmZyb20ubGluZT09dGhpcy5kb2MuZmlyc3RMaW5lKCk/bnVsbDp0aGlzLm1hdGNoZXModCx0aGlzLmRvYy5jbGlwUG9zKG0obi5mcm9tLmxpbmUtMSkpKTpuLnRvLmNoPHRoaXMuZG9jLmdldExpbmUobi50by5saW5lKS5sZW5ndGg/bi50bz1tKG4udG8ubGluZSxuLnRvLmNoKzEpOm49bi50by5saW5lPT10aGlzLmRvYy5sYXN0TGluZSgpP251bGw6dGhpcy5tYXRjaGVzKHQsbShuLnRvLmxpbmUrMSwwKSk7aWYobilyZXR1cm4gdGhpcy5wb3M9bix0aGlzLmF0T2NjdXJyZW5jZT0hMCx0aGlzLnBvcy5tYXRjaHx8ITA7dmFyIHI9bSh0P3RoaXMuZG9jLmZpcnN0TGluZSgpOnRoaXMuZG9jLmxhc3RMaW5lKCkrMSwwKTtyZXR1cm4gdGhpcy5wb3M9e2Zyb206cix0bzpyfSx0aGlzLmF0T2NjdXJyZW5jZT0hMX0sZnJvbTpmdW5jdGlvbigpe2lmKHRoaXMuYXRPY2N1cnJlbmNlKXJldHVybiB0aGlzLnBvcy5mcm9tfSx0bzpmdW5jdGlvbigpe2lmKHRoaXMuYXRPY2N1cnJlbmNlKXJldHVybiB0aGlzLnBvcy50b30scmVwbGFjZTpmdW5jdGlvbih0LG4pe2lmKHRoaXMuYXRPY2N1cnJlbmNlKXt2YXIgcj1lLnNwbGl0TGluZXModCk7dGhpcy5kb2MucmVwbGFjZVJhbmdlKHIsdGhpcy5wb3MuZnJvbSx0aGlzLnBvcy50byxuKSx0aGlzLnBvcy50bz1tKHRoaXMucG9zLmZyb20ubGluZStyLmxlbmd0aC0xLHJbci5sZW5ndGgtMV0ubGVuZ3RoKygxPT1yLmxlbmd0aD90aGlzLnBvcy5mcm9tLmNoOjApKX19fSxlLmRlZmluZUV4dGVuc2lvbigiZ2V0U2VhcmNoQ3Vyc29yIixmdW5jdGlvbihlLHQsbil7cmV0dXJuIG5ldyBmKHRoaXMuZG9jLGUsdCxuKX0pLGUuZGVmaW5lRG9jRXh0ZW5zaW9uKCJnZXRTZWFyY2hDdXJzb3IiLGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gbmV3IGYodGhpcyxlLHQsbil9KSxlLmRlZmluZUV4dGVuc2lvbigic2VsZWN0TWF0Y2hlcyIsZnVuY3Rpb24odCxuKXtmb3IodmFyIHI9W10saT10aGlzLmdldFNlYXJjaEN1cnNvcih0LHRoaXMuZ2V0Q3Vyc29yKCJmcm9tIiksbik7aS5maW5kTmV4dCgpJiYhKGUuY21wUG9zKGkudG8oKSx0aGlzLmdldEN1cnNvcigidG8iKSk+MCk7KXIucHVzaCh7YW5jaG9yOmkuZnJvbSgpLGhlYWQ6aS50bygpfSk7ci5sZW5ndGgmJnRoaXMuc2V0U2VsZWN0aW9ucyhyLDApfSl9KX0sZnVuY3Rpb24oZSx0LG4peyFmdW5jdGlvbihlKXtlKG4oMikpfShmdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQsbixyKXt2YXIgaSxvPXQuZ2V0V3JhcHBlckVsZW1lbnQoKTtyZXR1cm4gaT1vLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpKSxpLmNsYXNzTmFtZT1yPyJDb2RlTWlycm9yLWRpYWxvZyBDb2RlTWlycm9yLWRpYWxvZy1ib3R0b20iOiJDb2RlTWlycm9yLWRpYWxvZyBDb2RlTWlycm9yLWRpYWxvZy10b3AiLCJzdHJpbmciPT10eXBlb2Ygbj9pLmlubmVySFRNTD1uOmkuYXBwZW5kQ2hpbGQobiksZS5hZGRDbGFzcyhvLCJkaWFsb2ctb3BlbmVkIiksaX1mdW5jdGlvbiBuKGUsdCl7ZS5zdGF0ZS5jdXJyZW50Tm90aWZpY2F0aW9uQ2xvc2UmJmUuc3RhdGUuY3VycmVudE5vdGlmaWNhdGlvbkNsb3NlKCksZS5zdGF0ZS5jdXJyZW50Tm90aWZpY2F0aW9uQ2xvc2U9dH1lLmRlZmluZUV4dGVuc2lvbigib3BlbkRpYWxvZyIsZnVuY3Rpb24ocixpLG8pe2Z1bmN0aW9uIGEodCl7aWYoInN0cmluZyI9PXR5cGVvZiB0KXAudmFsdWU9dDtlbHNle2lmKGMpcmV0dXJuO2M9ITAsZS5ybUNsYXNzKHUucGFyZW50Tm9kZSwiZGlhbG9nLW9wZW5lZCIpLHUucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh1KSxsLmZvY3VzKCksby5vbkNsb3NlJiZvLm9uQ2xvc2UodSl9fW98fChvPXt9KSxuKHRoaXMsbnVsbCk7dmFyIHMsdT10KHRoaXMscixvLmJvdHRvbSksYz0hMSxsPXRoaXMscD11LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJpbnB1dCIpWzBdO3JldHVybiBwPyhwLmZvY3VzKCksby52YWx1ZSYmKHAudmFsdWU9by52YWx1ZSwhMSE9PW8uc2VsZWN0VmFsdWVPbk9wZW4mJnAuc2VsZWN0KCkpLG8ub25JbnB1dCYmZS5vbihwLCJpbnB1dCIsZnVuY3Rpb24oZSl7by5vbklucHV0KGUscC52YWx1ZSxhKX0pLG8ub25LZXlVcCYmZS5vbihwLCJrZXl1cCIsZnVuY3Rpb24oZSl7by5vbktleVVwKGUscC52YWx1ZSxhKX0pLGUub24ocCwia2V5ZG93biIsZnVuY3Rpb24odCl7byYmby5vbktleURvd24mJm8ub25LZXlEb3duKHQscC52YWx1ZSxhKXx8KCgyNz09dC5rZXlDb2RlfHwhMSE9PW8uY2xvc2VPbkVudGVyJiYxMz09dC5rZXlDb2RlKSYmKHAuYmx1cigpLGUuZV9zdG9wKHQpLGEoKSksMTM9PXQua2V5Q29kZSYmaShwLnZhbHVlLHQpKX0pLCExIT09by5jbG9zZU9uQmx1ciYmZS5vbihwLCJibHVyIixhKSk6KHM9dS5nZXRFbGVtZW50c0J5VGFnTmFtZSgiYnV0dG9uIilbMF0pJiYoZS5vbihzLCJjbGljayIsZnVuY3Rpb24oKXthKCksbC5mb2N1cygpfSksITEhPT1vLmNsb3NlT25CbHVyJiZlLm9uKHMsImJsdXIiLGEpLHMuZm9jdXMoKSksYX0pLGUuZGVmaW5lRXh0ZW5zaW9uKCJvcGVuQ29uZmlybSIsZnVuY3Rpb24ocixpLG8pe2Z1bmN0aW9uIGEoKXtjfHwoYz0hMCxlLnJtQ2xhc3Mocy5wYXJlbnROb2RlLCJkaWFsb2ctb3BlbmVkIikscy5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHMpLGwuZm9jdXMoKSl9bih0aGlzLG51bGwpO3ZhciBzPXQodGhpcyxyLG8mJm8uYm90dG9tKSx1PXMuZ2V0RWxlbWVudHNCeVRhZ05hbWUoImJ1dHRvbiIpLGM9ITEsbD10aGlzLHA9MTt1WzBdLmZvY3VzKCk7Zm9yKHZhciBmPTA7Zjx1Lmxlbmd0aDsrK2Ype3ZhciBkPXVbZl07IWZ1bmN0aW9uKHQpe2Uub24oZCwiY2xpY2siLGZ1bmN0aW9uKG4pe2UuZV9wcmV2ZW50RGVmYXVsdChuKSxhKCksdCYmdChsKX0pfShpW2ZdKSxlLm9uKGQsImJsdXIiLGZ1bmN0aW9uKCl7LS1wLHNldFRpbWVvdXQoZnVuY3Rpb24oKXtwPD0wJiZhKCl9LDIwMCl9KSxlLm9uKGQsImZvY3VzIixmdW5jdGlvbigpeysrcH0pfX0pLGUuZGVmaW5lRXh0ZW5zaW9uKCJvcGVuTm90aWZpY2F0aW9uIixmdW5jdGlvbihyLGkpe2Z1bmN0aW9uIG8oKXt1fHwodT0hMCxjbGVhclRpbWVvdXQoYSksZS5ybUNsYXNzKHMucGFyZW50Tm9kZSwiZGlhbG9nLW9wZW5lZCIpLHMucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChzKSl9bih0aGlzLG8pO3ZhciBhLHM9dCh0aGlzLHIsaSYmaS5ib3R0b20pLHU9ITEsYz1pJiYidW5kZWZpbmVkIiE9PXR5cGVvZiBpLmR1cmF0aW9uP2kuZHVyYXRpb246NWUzO3JldHVybiBlLm9uKHMsImNsaWNrIixmdW5jdGlvbih0KXtlLmVfcHJldmVudERlZmF1bHQodCksbygpfSksYyYmKGE9c2V0VGltZW91dChvLGMpKSxvfSl9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9bigxNTcpLGk9bigzNDYpLG89bigzNDcpLGE9bigzNDgpLHM9bigxNjEpO24oMTYwKTtuLmQodCwiY3JlYXRlU3RvcmUiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuYn0pLG4uZCh0LCJjb21iaW5lUmVkdWNlcnMiLGZ1bmN0aW9uKCl7cmV0dXJuIGkuYX0pLG4uZCh0LCJiaW5kQWN0aW9uQ3JlYXRvcnMiLGZ1bmN0aW9uKCl7cmV0dXJuIG8uYX0pLG4uZCh0LCJhcHBseU1pZGRsZXdhcmUiLGZ1bmN0aW9uKCl7cmV0dXJuIGEuYX0pLG4uZCh0LCJjb21wb3NlIixmdW5jdGlvbigpe3JldHVybiBzLmF9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe2lmKCFPYmplY3QoYS5hKShlKXx8T2JqZWN0KGkuYSkoZSkhPXMpcmV0dXJuITE7dmFyIHQ9T2JqZWN0KG8uYSkoZSk7aWYobnVsbD09PXQpcmV0dXJuITA7dmFyIG49cC5jYWxsKHQsImNvbnN0cnVjdG9yIikmJnQuY29uc3RydWN0b3I7cmV0dXJuImZ1bmN0aW9uIj09dHlwZW9mIG4mJm4gaW5zdGFuY2VvZiBuJiZsLmNhbGwobik9PWZ9dmFyIGk9bigzMyksbz1uKDM1MSksYT1uKDMxKSxzPSJbb2JqZWN0IE9iamVjdF0iLHU9RnVuY3Rpb24ucHJvdG90eXBlLGM9T2JqZWN0LnByb3RvdHlwZSxsPXUudG9TdHJpbmcscD1jLmhhc093blByb3BlcnR5LGY9bC5jYWxsKE9iamVjdCk7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe2Z1bmN0aW9uIGUoZSl7cmV0dXJuIG4ucHVzaChlKSxmdW5jdGlvbigpe3JldHVybiBPYmplY3Qocy53KShuLGUpfX1mdW5jdGlvbiB0KGUpe2Zvcih2YXIgdD1uLnNsaWNlKCkscj0wLGk9dC5sZW5ndGg7cjxpO3IrKyl0W3JdKGUpfXZhciBuPVtdO3JldHVybntzdWJzY3JpYmU6ZSxlbWl0OnR9fWZ1bmN0aW9uIGkoKXtmdW5jdGlvbiBlKCl7aWYoYSYmYy5sZW5ndGgpdGhyb3cgT2JqZWN0KHMucCkoIkNhbm5vdCBoYXZlIGEgY2xvc2VkIGNoYW5uZWwgd2l0aCBwZW5kaW5nIHRha2VycyIpO2lmKGMubGVuZ3RoJiYhby5pc0VtcHR5KCkpdGhyb3cgT2JqZWN0KHMucCkoIkNhbm5vdCBoYXZlIHBlbmRpbmcgdGFrZXJzIHdpdGggbm9uIGVtcHR5IGJ1ZmZlciIpfWZ1bmN0aW9uIHQodCl7aWYoZSgpLE9iamVjdChzLmgpKHQscy5xLm5vdFVuZGVmLGgpLCFhKXtpZighYy5sZW5ndGgpcmV0dXJuIG8ucHV0KHQpO2Zvcih2YXIgbj0wO248Yy5sZW5ndGg7bisrKXt2YXIgcj1jW25dO2lmKCFyW3MuYl18fHJbcy5iXSh0KSlyZXR1cm4gYy5zcGxpY2UobiwxKSxyKHQpfX19ZnVuY3Rpb24gbih0KXtlKCksT2JqZWN0KHMuaCkodCxzLnEuZnVuYywiY2hhbm5lbC50YWtlJ3MgY2FsbGJhY2sgbXVzdCBiZSBhIGZ1bmN0aW9uIiksYSYmby5pc0VtcHR5KCk/dChwKTpvLmlzRW1wdHkoKT8oYy5wdXNoKHQpLHQuY2FuY2VsPWZ1bmN0aW9uKCl7cmV0dXJuIE9iamVjdChzLncpKGMsdCl9KTp0KG8udGFrZSgpKX1mdW5jdGlvbiByKHQpe2lmKGUoKSxPYmplY3Qocy5oKSh0LHMucS5mdW5jLCJjaGFubmVsLmZsdXNoJyBjYWxsYmFjayBtdXN0IGJlIGEgZnVuY3Rpb24iKSxhJiZvLmlzRW1wdHkoKSlyZXR1cm4gdm9pZCB0KHApO3Qoby5mbHVzaCgpKX1mdW5jdGlvbiBpKCl7aWYoZSgpLCFhJiYoYT0hMCxjLmxlbmd0aCkpe3ZhciB0PWM7Yz1bXTtmb3IodmFyIG49MCxyPXQubGVuZ3RoO248cjtuKyspdFtuXShwKX19dmFyIG89YXJndW1lbnRzLmxlbmd0aD4wJiZ2b2lkIDAhPT1hcmd1bWVudHNbMF0/YXJndW1lbnRzWzBdOnUuYS5maXhlZCgpLGE9ITEsYz1bXTtyZXR1cm4gT2JqZWN0KHMuaCkobyxzLnEuYnVmZmVyLGQpLHt0YWtlOm4scHV0OnQsZmx1c2g6cixjbG9zZTppLGdldCBfX3Rha2Vyc19fKCl7cmV0dXJuIGN9LGdldCBfX2Nsb3NlZF9fKCl7cmV0dXJuIGF9fX1mdW5jdGlvbiBvKGUpe3ZhciB0PWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp1LmEubm9uZSgpLG49YXJndW1lbnRzWzJdO2FyZ3VtZW50cy5sZW5ndGg+MiYmT2JqZWN0KHMuaCkobixzLnEuZnVuYywiSW52YWxpZCBtYXRjaCBmdW5jdGlvbiBwYXNzZWQgdG8gZXZlbnRDaGFubmVsIik7dmFyIHI9aSh0KSxvPWZ1bmN0aW9uKCl7ci5fX2Nsb3NlZF9ffHwoYSYmYSgpLHIuY2xvc2UoKSl9LGE9ZShmdW5jdGlvbihlKXtpZihmKGUpKXJldHVybiB2b2lkIG8oKTtuJiYhbihlKXx8ci5wdXQoZSl9KTtpZihyLl9fY2xvc2VkX18mJmEoKSwhcy5xLmZ1bmMoYSkpdGhyb3cgbmV3IEVycm9yKCJpbiBldmVudENoYW5uZWw6IHN1YnNjcmliZSBzaG91bGQgcmV0dXJuIGEgZnVuY3Rpb24gdG8gdW5zdWJzY3JpYmUiKTtyZXR1cm57dGFrZTpyLnRha2UsZmx1c2g6ci5mbHVzaCxjbG9zZTpvfX1mdW5jdGlvbiBhKGUpe3ZhciB0PW8oZnVuY3Rpb24odCl7cmV0dXJuIGUoZnVuY3Rpb24oZSl7aWYoZVtzLmNdKXJldHVybiB2b2lkIHQoZSk7T2JqZWN0KGMuYSkoZnVuY3Rpb24oKXtyZXR1cm4gdChlKX0pfSl9KTtyZXR1cm4gbCh7fSx0LHt0YWtlOmZ1bmN0aW9uKGUsbil7YXJndW1lbnRzLmxlbmd0aD4xJiYoT2JqZWN0KHMuaCkobixzLnEuZnVuYywiY2hhbm5lbC50YWtlJ3MgbWF0Y2hlciBhcmd1bWVudCBtdXN0IGJlIGEgZnVuY3Rpb24iKSxlW3MuYl09biksdC50YWtlKGUpfX0pfW4uZCh0LCJhIixmdW5jdGlvbigpe3JldHVybiBwfSksbi5kKHQsImUiLGZ1bmN0aW9uKCl7cmV0dXJuIGZ9KSx0LmM9cix0LmI9aSx0LmQ9byx0LmY9YTt2YXIgcz1uKDIyKSx1PW4oNzYpLGM9bigxNjYpLGw9T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTE7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyl7dmFyIG49YXJndW1lbnRzW3RdO2Zvcih2YXIgciBpbiBuKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChuLHIpJiYoZVtyXT1uW3JdKX1yZXR1cm4gZX0scD17dHlwZToiQEByZWR1eC1zYWdhL0NIQU5ORUxfRU5EIn0sZj1mdW5jdGlvbihlKXtyZXR1cm4gZSYmIkBAcmVkdXgtc2FnYS9DSEFOTkVMX0VORCI9PT1lLnR5cGV9LGQ9ImludmFsaWQgYnVmZmVyIHBhc3NlZCB0byBjaGFubmVsIGZhY3RvcnkgZnVuY3Rpb24iLGg9IlNhZ2Egd2FzIHByb3ZpZGVkIHdpdGggYW4gdW5kZWZpbmVkIGFjdGlvbiJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbixvLGEscyl7dmFyIHU9bjtpZighdSYmdCYmdC5sZW5ndGg+MCl7dmFyIGM9dFswXTt1PWMmJmMubG9jJiZjLmxvYy5zb3VyY2V9dmFyIGw9bzshbCYmdCYmKGw9dC5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIEJvb2xlYW4oZS5sb2MpfSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLmxvYy5zdGFydH0pKSxsJiYwPT09bC5sZW5ndGgmJihsPXZvaWQgMCk7dmFyIHA9dm9pZCAwLGY9dTtmJiZsJiYocD1sLm1hcChmdW5jdGlvbihlKXtyZXR1cm4oMCxpLmdldExvY2F0aW9uKShmLGUpfSkpLE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMse21lc3NhZ2U6e3ZhbHVlOmUsZW51bWVyYWJsZTohMCx3cml0YWJsZTohMH0sbG9jYXRpb25zOnt2YWx1ZTpwfHx2b2lkIDAsZW51bWVyYWJsZTohMH0scGF0aDp7dmFsdWU6YXx8dm9pZCAwLGVudW1lcmFibGU6ITB9LG5vZGVzOnt2YWx1ZTp0fHx2b2lkIDB9LHNvdXJjZTp7dmFsdWU6dXx8dm9pZCAwfSxwb3NpdGlvbnM6e3ZhbHVlOmx8fHZvaWQgMH0sb3JpZ2luYWxFcnJvcjp7dmFsdWU6c319KSxzJiZzLnN0YWNrP09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCJzdGFjayIse3ZhbHVlOnMuc3RhY2ssd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfSk6RXJyb3IuY2FwdHVyZVN0YWNrVHJhY2U/RXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UodGhpcyxyKTpPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywic3RhY2siLHt2YWx1ZTpFcnJvcigpLnN0YWNrLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkdyYXBoUUxFcnJvcj1yO3ZhciBpPW4oMTA5KTtyLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKEVycm9yLnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOnJ9LG5hbWU6e3ZhbHVlOiJHcmFwaFFMRXJyb3IifX0pfSxmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7cmV0dXJuISFhKGUpfWZ1bmN0aW9uIHIoZSl7dmFyIHQ9bnVsbCE9ZSYmZS5sZW5ndGg7cmV0dXJuIm51bWJlciI9PT10eXBlb2YgdCYmdD49MCYmdCUxPT09MH1mdW5jdGlvbiBpKGUpe3JldHVybiBPYmplY3QoZSk9PT1lJiYocihlKXx8bihlKSl9ZnVuY3Rpb24gbyhlKXt2YXIgdD1hKGUpO2lmKHQpcmV0dXJuIHQuY2FsbChlKX1mdW5jdGlvbiBhKGUpe2lmKG51bGwhPWUpe3ZhciB0PWcmJmVbZ118fGVbIkBAaXRlcmF0b3IiXTtpZigiZnVuY3Rpb24iPT09dHlwZW9mIHQpcmV0dXJuIHR9fWZ1bmN0aW9uIHMoZSl7aWYobnVsbCE9ZSl7dmFyIHQ9byhlKTtpZih0KXJldHVybiB0O2lmKHIoZSkpcmV0dXJuIG5ldyB1KGUpfX1mdW5jdGlvbiB1KGUpe3RoaXMuX289ZSx0aGlzLl9pPTB9ZnVuY3Rpb24gYyhlLHQsbil7aWYobnVsbCE9ZSl7aWYoImZ1bmN0aW9uIj09PXR5cGVvZiBlLmZvckVhY2gpcmV0dXJuIGUuZm9yRWFjaCh0LG4pO3ZhciBpPTAsYT1vKGUpO2lmKGEpe2Zvcih2YXIgczshKHM9YS5uZXh0KCkpLmRvbmU7KWlmKHQuY2FsbChuLHMudmFsdWUsaSsrLGUpLGk+OTk5OTk5OSl0aHJvdyBuZXcgVHlwZUVycm9yKCJOZWFyLWluZmluaXRlIGl0ZXJhdGlvbi4iKX1lbHNlIGlmKHIoZSkpZm9yKDtpPGUubGVuZ3RoO2krKyllLmhhc093blByb3BlcnR5KGkpJiZ0LmNhbGwobixlW2ldLGksZSl9fWZ1bmN0aW9uIGwoZSl7cmV0dXJuISFmKGUpfWZ1bmN0aW9uIHAoZSl7dmFyIHQ9ZihlKTtpZih0KXJldHVybiB0LmNhbGwoZSl9ZnVuY3Rpb24gZihlKXtpZihudWxsIT1lKXt2YXIgdD12JiZlW3ZdfHxlWyJAQGFzeW5jSXRlcmF0b3IiXTtpZigiZnVuY3Rpb24iPT09dHlwZW9mIHQpcmV0dXJuIHR9fWZ1bmN0aW9uIGQoZSl7aWYobnVsbCE9ZSl7dmFyIHQ9cChlKTtpZih0KXJldHVybiB0O3ZhciBuPXMoZSk7aWYobilyZXR1cm4gbmV3IGgobil9fWZ1bmN0aW9uIGgoZSl7dGhpcy5faT1lfWZ1bmN0aW9uIG0oZSx0LG4pe3ZhciByPWQoZSk7aWYocil7dmFyIGk9MDtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24obyxhKXtmdW5jdGlvbiBzKCl7cmV0dXJuIHIubmV4dCgpLnRoZW4oZnVuY3Rpb24ocil7ci5kb25lP28oKTpQcm9taXNlLnJlc29sdmUodC5jYWxsKG4sci52YWx1ZSxpKyssZSkpLnRoZW4ocykuY2F0Y2goYSl9KS5jYXRjaChhKX1zKCl9KX19dmFyIGc9ImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJlN5bWJvbC5pdGVyYXRvcix5PWd8fCJAQGl0ZXJhdG9yIjt0LiQkaXRlcmF0b3I9eSx0LmlzSXRlcmFibGU9bix0LmlzQXJyYXlMaWtlPXIsdC5pc0NvbGxlY3Rpb249aSx0LmdldEl0ZXJhdG9yPW8sdC5nZXRJdGVyYXRvck1ldGhvZD1hLHQuY3JlYXRlSXRlcmF0b3I9cyx1LnByb3RvdHlwZVt5XT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx1LnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKCl7cmV0dXJuIHZvaWQgMD09PXRoaXMuX298fHRoaXMuX2k+PXRoaXMuX28ubGVuZ3RoPyh0aGlzLl9vPXZvaWQgMCx7dmFsdWU6dm9pZCAwLGRvbmU6ITB9KTp7dmFsdWU6dGhpcy5fb1t0aGlzLl9pKytdLGRvbmU6ITF9fSx0LmZvckVhY2g9Yzt2YXIgdj0iZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmU3ltYm9sLmFzeW5jSXRlcmF0b3IsYj12fHwiQEBhc3luY0l0ZXJhdG9yIjt0LiQkYXN5bmNJdGVyYXRvcj1iLHQuaXNBc3luY0l0ZXJhYmxlPWwsdC5nZXRBc3luY0l0ZXJhdG9yPXAsdC5nZXRBc3luY0l0ZXJhdG9yTWV0aG9kPWYsdC5jcmVhdGVBc3luY0l0ZXJhdG9yPWQsaC5wcm90b3R5cGVbYl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30saC5wcm90b3R5cGUubmV4dD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuX2kubmV4dCgpO3JldHVybiBQcm9taXNlLnJlc29sdmUoZS52YWx1ZSkudGhlbihmdW5jdGlvbih0KXtyZXR1cm57dmFsdWU6dCxkb25lOmUuZG9uZX19KX0sdC5mb3JBd2FpdEVhY2g9bX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuPTA7bjxlLmxlbmd0aDtuKyspaWYodChlW25dKSlyZXR1cm4gZVtuXX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybiBlLnJlZHVjZShmdW5jdGlvbihlLG4pe3JldHVybiBlW3QobildPW4sZX0sT2JqZWN0LmNyZWF0ZShudWxsKSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZGVmYXVsdD1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPUFycmF5LmlzQXJyYXk7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZighT2JqZWN0KG8uYSkoZSkpcmV0dXJuITE7dmFyIHQ9T2JqZWN0KGkuYSkoZSk7cmV0dXJuIHQ9PXN8fHQ9PXV8fHQ9PWF8fHQ9PWN9dmFyIGk9bigzMyksbz1uKDYwKSxhPSJbb2JqZWN0IEFzeW5jRnVuY3Rpb25dIixzPSJbb2JqZWN0IEZ1bmN0aW9uXSIsdT0iW29iamVjdCBHZW5lcmF0b3JGdW5jdGlvbl0iLGM9IltvYmplY3QgUHJveHldIjt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dmFyIG49T2JqZWN0KG8uYSkoZSx0KTtyZXR1cm4gT2JqZWN0KGkuYSkobik/bjp2b2lkIDB9dmFyIGk9big0MTIpLG89big0MTUpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDkyKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0RGVmaW5pdGlvblN0YXRlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gci5nZXREZWZpbml0aW9uU3RhdGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImdldEZpZWxkRGVmIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gci5nZXRGaWVsZERlZn19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZm9yRWFjaFN0YXRlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gci5mb3JFYWNoU3RhdGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIm9iamVjdFZhbHVlcyIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIub2JqZWN0VmFsdWVzfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJoaW50TGlzdCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIuaGludExpc3R9fSk7dmFyIGk9big5Myk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImdldEF1dG9jb21wbGV0ZVN1Z2dlc3Rpb25zIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5nZXRBdXRvY29tcGxldGVTdWdnZXN0aW9uc319KTt2YXIgbz1uKDk0KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiTEFOR1VBR0UiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLkxBTkdVQUdFfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJnZXREZWZpbml0aW9uUXVlcnlSZXN1bHRGb3JGcmFnbWVudFNwcmVhZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8uZ2V0RGVmaW5pdGlvblF1ZXJ5UmVzdWx0Rm9yRnJhZ21lbnRTcHJlYWR9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImdldERlZmluaXRpb25RdWVyeVJlc3VsdEZvckRlZmluaXRpb25Ob2RlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby5nZXREZWZpbml0aW9uUXVlcnlSZXN1bHRGb3JEZWZpbml0aW9uTm9kZX19KTt2YXIgYT1uKDk2KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0RGlhZ25vc3RpY3MiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBhLmdldERpYWdub3N0aWNzfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJ2YWxpZGF0ZVF1ZXJ5Iix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS52YWxpZGF0ZVF1ZXJ5fX0pO3ZhciBzPW4oMTQwKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0T3V0bGluZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHMuZ2V0T3V0bGluZX19KTt2YXIgdT1uKDE0MSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxMYW5ndWFnZVNlcnZpY2UiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LkdyYXBoUUxMYW5ndWFnZVNlcnZpY2V9fSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIGMuR3JhcGhRTE5vbk51bGw/YS5jcmVhdGVFbGVtZW50KCJzcGFuIixudWxsLHIoZS5vZlR5cGUpLCIhIik6ZSBpbnN0YW5jZW9mIGMuR3JhcGhRTExpc3Q/YS5jcmVhdGVFbGVtZW50KCJzcGFuIixudWxsLCJbIixyKGUub2ZUeXBlKSwiXSIpOmEuY3JlYXRlRWxlbWVudCgic3BhbiIsbnVsbCxlLm5hbWUpfXZhciBpPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksbz1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgYT1uKDApLHM9big0MCksdT1uKDkpLGM9big3KSxsPW4oNjQzKSxwPW4oMjQpLGY9bigyNjApLGQ9big2NyksaD1uKDY4KSxtPW4oMTIpLGc9big4KSx5PW4oMSksdj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe3ZhciBuPWUuY2FsbCh0aGlzLHQpfHx0aGlzO3JldHVybiBuLm9uQ2xpY2s9ZnVuY3Rpb24oKXtuLnByb3BzLmNsaWNrYWJsZSYmbi5wcm9wcy5hZGRTdGFjayhuLnByb3BzLnNlc3Npb25JZCxuLnByb3BzLnR5cGUsbi5wcm9wcy54LG4ucHJvcHMueSl9LG4uc2V0UmVmPWZ1bmN0aW9uKGUpe24ucmVmPWV9LG4uc3RhdGU9e2NvbGxhcHNlZDohMX0sbn1yZXR1cm4gaSh0LGUpLHQucHJvdG90eXBlLnNob3VsZENvbXBvbmVudFVwZGF0ZT1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLnByb3BzLnR5cGUhPT1lLnR5cGV8fHRoaXMucHJvcHMua2V5TW92ZSE9PWUua2V5TW92ZXx8dGhpcy5wcm9wcy5pc0FjdGl2ZSE9PWUuaXNBY3RpdmV8fHRoaXMuc3RhdGUuY29sbGFwc2VkIT09dC5jb2xsYXBzZWR9LHQucHJvdG90eXBlLmNvbXBvbmVudERpZE1vdW50PWZ1bmN0aW9uKCl7dGhpcy51cGRhdGVTaXplKCl9LHQucHJvdG90eXBlLmNvbXBvbmVudERpZFVwZGF0ZT1mdW5jdGlvbigpe3RoaXMudXBkYXRlU2l6ZSgpfSx0LnByb3RvdHlwZS51cGRhdGVTaXplPWZ1bmN0aW9uKCl7aWYodGhpcy5yZWYpeyJmdW5jdGlvbiI9PT10eXBlb2YgdGhpcy5wcm9wcy5vblNldFdpZHRoJiZ0aGlzLnByb3BzLm9uU2V0V2lkdGgodGhpcy5yZWYuc2Nyb2xsV2lkdGgpO3RoaXMucmVmLnNjcm9sbEhlaWdodD4zMSYmIXRoaXMuc3RhdGUuY29sbGFwc2VkJiZ0aGlzLnByb3BzLmNvbGxhcHNhYmxlJiZ0aGlzLnNldFN0YXRlKHtjb2xsYXBzZWQ6ITB9KX19LHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMsdD1lLnR5cGUsbj1lLmNsaWNrYWJsZSxpPWUuY2xhc3NOYW1lLG89ZS5iZWZvcmVOb2RlLHM9ZS5hZnRlck5vZGUsdT1lLnNob3dQYXJlbnROYW1lLGY9ZS5pc0FjdGl2ZSxkPWMuaXNUeXBlKHQpLGg9dSYmdC5wYXJlbnQ/YS5jcmVhdGVFbGVtZW50KCJzcGFuIixudWxsLHQucGFyZW50Lm5hbWUsIi4iLGEuY3JlYXRlRWxlbWVudCgiYiIsbnVsbCx0Lm5hbWUpKTp0Lm5hbWU7cmV0dXJuIGEuY3JlYXRlRWxlbWVudChrLHthY3RpdmU6ZixjbGlja2FibGU6bixjbGFzc05hbWU6ImRvYy1jYXRlZ29yeS1pdGVtIisoaXx8IiIpLG9uQ2xpY2s6dGhpcy5vbkNsaWNrLHJlZjp0aGlzLnNldFJlZn0sbyxvJiYiICIsIWQmJmEuY3JlYXRlRWxlbWVudCgic3BhbiIsbnVsbCxhLmNyZWF0ZUVsZW1lbnQoInNwYW4iLHtjbGFzc05hbWU6ImZpZWxkLW5hbWUifSxoKSx0LmFyZ3MmJnQuYXJncy5sZW5ndGg+MCYmWyIoIixhLmNyZWF0ZUVsZW1lbnQoInNwYW4iLHtrZXk6ImFyZ3MifSx0aGlzLnN0YXRlLmNvbGxhcHNlZD9hLmNyZWF0ZUVsZW1lbnQoQSxudWxsLCIuLi4iKTp0LmFyZ3MubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBhLmNyZWF0ZUVsZW1lbnQobC5kZWZhdWx0LHtrZXk6ZS5uYW1lLGFyZzplfSl9KSksIikiXSwiOiAiKSxhLmNyZWF0ZUVsZW1lbnQoInNwYW4iLHtjbGFzc05hbWU6InR5cGUtbmFtZSJ9LHIodC50eXBlfHx0KSksdm9pZCAwIT09dC5kZWZhdWx0VmFsdWU/YS5jcmVhdGVFbGVtZW50KFQsbnVsbCwiICIsIj0gIixhLmNyZWF0ZUVsZW1lbnQoInNwYW4iLG51bGwsIiIrSlNPTi5zdHJpbmdpZnkodC5kZWZhdWx0VmFsdWUsbnVsbCwyKSkpOnZvaWQgMCxuJiZhLmNyZWF0ZUVsZW1lbnQoXyxudWxsLGEuY3JlYXRlRWxlbWVudChwLlRyaWFuZ2xlLG51bGwpKSxzJiYiICIscyl9LHQuZGVmYXVsdFByb3BzPXtjbGlja2FibGU6ITAsY29sbGFwc2FibGU6ITF9LHR9KGEuQ29tcG9uZW50KSxiPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC54LHI9dC55LGk9aC5nZXRTZXNzaW9uRG9jc1N0YXRlKGUpLG89bS5nZXRTZWxlY3RlZFNlc3Npb25JZEZyb21Sb290KGUpO2lmKGkpe3ZhciBhPWkubmF2U3RhY2suZ2V0KG4pO2lmKGEpe3ZhciBzPWEuZ2V0KCJ4Iik9PT1uJiZhLmdldCgieSIpPT09cjtyZXR1cm57aXNBY3RpdmU6cyxrZXlNb3ZlOmkua2V5TW92ZSxsYXN0QWN0aXZlOnMmJm49PT1pLm5hdlN0YWNrLmxlbmd0aC0xLHNlc3Npb25JZDpvfX19cmV0dXJue2lzQWN0aXZlOiExLGtleU1vdmU6ITEsbGFzdEFjdGl2ZTohMSxzZXNzaW9uSWQ6b319LHg9Zy5jcmVhdGVTZWxlY3RvcihbYl0sZnVuY3Rpb24oZSl7cmV0dXJuIGV9KSxDPWZ1bmN0aW9uKGUpe3JldHVybiBzLmJpbmRBY3Rpb25DcmVhdG9ycyh7YWRkU3RhY2s6ZC5hZGRTdGFja30sZSl9O3QuZGVmYXVsdD11LmNvbm5lY3QoeCxDKShmLnRvSlModikpO3ZhciBFLEQsdyxTLGs9eS5zdHlsZWQoImRpdiIpKEV8fChFPW8oWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBwYWRkaW5nOiA2cHggMTZweDtcbiAgb3ZlcmZsb3c6IGF1dG87XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgdHJhbnNpdGlvbjogMC4xcyBiYWNrZ3JvdW5kLWNvbG9yO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG5cbiAgY3Vyc29yOiAiLCI7XG5cbiAgJjpob3ZlciB7XG4gICAgY29sb3I6ICIsIjtcbiAgICBiYWNrZ3JvdW5kOiAjMmE3ZWQzO1xuICAgIC5maWVsZC1uYW1lLFxuICAgIC50eXBlLW5hbWUsXG4gICAgLmFyZy1uYW1lLFxuICAgIHNwYW4ge1xuICAgICAgY29sb3I6ICIsIiAhaW1wb3J0YW50O1xuICAgIH1cbiAgfVxuICBiIHtcbiAgICBmb250LXdlaWdodDogNjAwO1xuICB9XG4iXSxbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIHBhZGRpbmc6IDZweCAxNnB4O1xuICBvdmVyZmxvdzogYXV0bztcbiAgZm9udC1zaXplOiAxNHB4O1xuICB0cmFuc2l0aW9uOiAwLjFzIGJhY2tncm91bmQtY29sb3I7XG4gIGJhY2tncm91bmQ6ICIsIjtcblxuICBjdXJzb3I6ICIsIjtcblxuICAmOmhvdmVyIHtcbiAgICBjb2xvcjogIiwiO1xuICAgIGJhY2tncm91bmQ6ICMyYTdlZDM7XG4gICAgLmZpZWxkLW5hbWUsXG4gICAgLnR5cGUtbmFtZSxcbiAgICAuYXJnLW5hbWUsXG4gICAgc3BhbiB7XG4gICAgICBjb2xvcjogIiwiICFpbXBvcnRhbnQ7XG4gICAgfVxuICB9XG4gIGIge1xuICAgIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUuYWN0aXZlP2UudGhlbWUuY29sb3Vycy5ibGFjazA3OmUudGhlbWUuY29sb3Vycy53aGl0ZX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUuY2xpY2thYmxlPyJwb2ludGVyIjoic2VsZWN0In0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy53aGl0ZX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy53aGl0ZX0pLEE9eS5zdHlsZWQuc3BhbihEfHwoRD1vKFsiXG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4iXSxbIlxuICBmb250LXdlaWdodDogNjAwO1xuIl0pKSksXz15LnN0eWxlZC5kaXYod3x8KHc9byhbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHJpZ2h0OiAxMHB4O1xuICB0b3A6IDUwJTtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKC01MCUpO1xuIl0sWyJcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICByaWdodDogMTBweDtcbiAgdG9wOiA1MCU7XG4gIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtNTAlKTtcbiJdKSkpLFQ9eS5zdHlsZWQuc3BhbihTfHwoUz1vKFsiXG4gIGNvbG9yOiAiLCI7XG4gIHNwYW4ge1xuICAgIGNvbG9yOiAjMWY2MWE5O1xuICB9XG4iXSxbIlxuICBjb2xvcjogIiwiO1xuICBzcGFuIHtcbiAgICBjb2xvcjogIzFmNjFhOTtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5jb2xvdXJzLmJsYWNrMzB9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiJ1bmRlZmluZWQiPT09dHlwZW9mIGV8fG51bGw9PT1lfWZ1bmN0aW9uIGkoZSl7cmV0dXJuIm9iamVjdCI9PT10eXBlb2YgZSYmbnVsbCE9PWV9ZnVuY3Rpb24gbyhlKXtyZXR1cm4gQXJyYXkuaXNBcnJheShlKT9lOnIoZSk/W106W2VdfWZ1bmN0aW9uIGEoZSx0KXt2YXIgbixyLGksbztpZih0KWZvcihvPU9iamVjdC5rZXlzKHQpLG49MCxyPW8ubGVuZ3RoO248cjtuKz0xKWk9b1tuXSxlW2ldPXRbaV07cmV0dXJuIGV9ZnVuY3Rpb24gcyhlLHQpe3ZhciBuLHI9IiI7Zm9yKG49MDtuPHQ7bis9MSlyKz1lO3JldHVybiByfWZ1bmN0aW9uIHUoZSl7cmV0dXJuIDA9PT1lJiZOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk9PT0xL2V9ZS5leHBvcnRzLmlzTm90aGluZz1yLGUuZXhwb3J0cy5pc09iamVjdD1pLGUuZXhwb3J0cy50b0FycmF5PW8sZS5leHBvcnRzLnJlcGVhdD1zLGUuZXhwb3J0cy5pc05lZ2F0aXZlWmVybz11LGUuZXhwb3J0cy5leHRlbmQ9YX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXt2YXIgaT1bXTtyZXR1cm4gZS5pbmNsdWRlLmZvckVhY2goZnVuY3Rpb24oZSl7bj1yKGUsdCxuKX0pLGVbdF0uZm9yRWFjaChmdW5jdGlvbihlKXtuLmZvckVhY2goZnVuY3Rpb24odCxuKXt0LnRhZz09PWUudGFnJiZ0LmtpbmQ9PT1lLmtpbmQmJmkucHVzaChuKX0pLG4ucHVzaChlKX0pLG4uZmlsdGVyKGZ1bmN0aW9uKGUsdCl7cmV0dXJuLTE9PT1pLmluZGV4T2YodCl9KX1mdW5jdGlvbiBpKCl7ZnVuY3Rpb24gZShlKXtyW2Uua2luZF1bZS50YWddPXIuZmFsbGJhY2tbZS50YWddPWV9dmFyIHQsbixyPXtzY2FsYXI6e30sc2VxdWVuY2U6e30sbWFwcGluZzp7fSxmYWxsYmFjazp7fX07Zm9yKHQ9MCxuPWFyZ3VtZW50cy5sZW5ndGg7dDxuO3QrPTEpYXJndW1lbnRzW3RdLmZvckVhY2goZSk7cmV0dXJuIHJ9ZnVuY3Rpb24gbyhlKXt0aGlzLmluY2x1ZGU9ZS5pbmNsdWRlfHxbXSx0aGlzLmltcGxpY2l0PWUuaW1wbGljaXR8fFtdLHRoaXMuZXhwbGljaXQ9ZS5leHBsaWNpdHx8W10sdGhpcy5pbXBsaWNpdC5mb3JFYWNoKGZ1bmN0aW9uKGUpe2lmKGUubG9hZEtpbmQmJiJzY2FsYXIiIT09ZS5sb2FkS2luZCl0aHJvdyBuZXcgcygiVGhlcmUgaXMgYSBub24tc2NhbGFyIHR5cGUgaW4gdGhlIGltcGxpY2l0IGxpc3Qgb2YgYSBzY2hlbWEuIEltcGxpY2l0IHJlc29sdmluZyBvZiBzdWNoIHR5cGVzIGlzIG5vdCBzdXBwb3J0ZWQuIil9KSx0aGlzLmNvbXBpbGVkSW1wbGljaXQ9cih0aGlzLCJpbXBsaWNpdCIsW10pLHRoaXMuY29tcGlsZWRFeHBsaWNpdD1yKHRoaXMsImV4cGxpY2l0IixbXSksdGhpcy5jb21waWxlZFR5cGVNYXA9aSh0aGlzLmNvbXBpbGVkSW1wbGljaXQsdGhpcy5jb21waWxlZEV4cGxpY2l0KX12YXIgYT1uKDUyKSxzPW4oNzIpLHU9bigxNSk7by5ERUZBVUxUPW51bGwsby5jcmVhdGU9ZnVuY3Rpb24oKXt2YXIgZSx0O3N3aXRjaChhcmd1bWVudHMubGVuZ3RoKXtjYXNlIDE6ZT1vLkRFRkFVTFQsdD1hcmd1bWVudHNbMF07YnJlYWs7Y2FzZSAyOmU9YXJndW1lbnRzWzBdLHQ9YXJndW1lbnRzWzFdO2JyZWFrO2RlZmF1bHQ6dGhyb3cgbmV3IHMoIldyb25nIG51bWJlciBvZiBhcmd1bWVudHMgZm9yIFNjaGVtYS5jcmVhdGUgZnVuY3Rpb24iKX1pZihlPWEudG9BcnJheShlKSx0PWEudG9BcnJheSh0KSwhZS5ldmVyeShmdW5jdGlvbihlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIG99KSl0aHJvdyBuZXcgcygiU3BlY2lmaWVkIGxpc3Qgb2Ygc3VwZXIgc2NoZW1hcyAob3IgYSBzaW5nbGUgU2NoZW1hIG9iamVjdCkgY29udGFpbnMgYSBub24tU2NoZW1hIG9iamVjdC4iKTtpZighdC5ldmVyeShmdW5jdGlvbihlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIHV9KSl0aHJvdyBuZXcgcygiU3BlY2lmaWVkIGxpc3Qgb2YgWUFNTCB0eXBlcyAob3IgYSBzaW5nbGUgVHlwZSBvYmplY3QpIGNvbnRhaW5zIGEgbm9uLVR5cGUgb2JqZWN0LiIpO3JldHVybiBuZXcgbyh7aW5jbHVkZTplLGV4cGxpY2l0OnR9KX0sZS5leHBvcnRzPW99LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZihudWxsPT09ZXx8dm9pZCAwPT09ZSl0aHJvdyBuZXcgVHlwZUVycm9yKCJPYmplY3QuYXNzaWduIGNhbm5vdCBiZSBjYWxsZWQgd2l0aCBudWxsIG9yIHVuZGVmaW5lZCIpO3JldHVybiBPYmplY3QoZSl9dmFyIGk9T2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyxvPU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHksYT1PYmplY3QucHJvdG90eXBlLnByb3BlcnR5SXNFbnVtZXJhYmxlO2UuZXhwb3J0cz1mdW5jdGlvbigpe3RyeXtpZighT2JqZWN0LmFzc2lnbilyZXR1cm4hMTt2YXIgZT1uZXcgU3RyaW5nKCJhYmMiKTtpZihlWzVdPSJkZSIsIjUiPT09T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoZSlbMF0pcmV0dXJuITE7Zm9yKHZhciB0PXt9LG49MDtuPDEwO24rKyl0WyJfIitTdHJpbmcuZnJvbUNoYXJDb2RlKG4pXT1uO2lmKCIwMTIzNDU2Nzg5IiE9PU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHQpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gdFtlXX0pLmpvaW4oIiIpKXJldHVybiExO3ZhciByPXt9O3JldHVybiJhYmNkZWZnaGlqa2xtbm9wcXJzdCIuc3BsaXQoIiIpLmZvckVhY2goZnVuY3Rpb24oZSl7cltlXT1lfSksImFiY2RlZmdoaWprbG1ub3BxcnN0Ij09PU9iamVjdC5rZXlzKE9iamVjdC5hc3NpZ24oe30scikpLmpvaW4oIiIpfWNhdGNoKGUpe3JldHVybiExfX0oKT9PYmplY3QuYXNzaWduOmZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuLHMsdT1yKGUpLGM9MTtjPGFyZ3VtZW50cy5sZW5ndGg7YysrKXtuPU9iamVjdChhcmd1bWVudHNbY10pO2Zvcih2YXIgbCBpbiBuKW8uY2FsbChuLGwpJiYodVtsXT1uW2xdKTtpZihpKXtzPWkobik7Zm9yKHZhciBwPTA7cDxzLmxlbmd0aDtwKyspYS5jYWxsKG4sc1twXSkmJih1W3NbcF1dPW5bc1twXV0pfX1yZXR1cm4gdX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oMzQpO24uZCh0LCJ0YWtlIixmdW5jdGlvbigpe3JldHVybiByLnN9KSxuLmQodCwidGFrZW0iLGZ1bmN0aW9uKCl7cmV0dXJuIHIudn0pLG4uZCh0LCJwdXQiLGZ1bmN0aW9uKCl7cmV0dXJuIHIubn0pLG4uZCh0LCJhbGwiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuYn0pLG4uZCh0LCJyYWNlIixmdW5jdGlvbigpe3JldHVybiByLm99KSxuLmQodCwiY2FsbCIsZnVuY3Rpb24oKXtyZXR1cm4gci5lfSksbi5kKHQsImFwcGx5IixmdW5jdGlvbigpe3JldHVybiByLmN9KSxuLmQodCwiY3BzIixmdW5jdGlvbigpe3JldHVybiByLmh9KSxuLmQodCwiZm9yayIsZnVuY3Rpb24oKXtyZXR1cm4gci5rfSksbi5kKHQsInNwYXduIixmdW5jdGlvbigpe3JldHVybiByLnJ9KSxuLmQodCwiam9pbiIsZnVuY3Rpb24oKXtyZXR1cm4gci5tfSksbi5kKHQsImNhbmNlbCIsZnVuY3Rpb24oKXtyZXR1cm4gci5mfSksbi5kKHQsInNlbGVjdCIsZnVuY3Rpb24oKXtyZXR1cm4gci5wfSksbi5kKHQsImFjdGlvbkNoYW5uZWwiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuYX0pLG4uZCh0LCJjYW5jZWxsZWQiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuZ30pLG4uZCh0LCJmbHVzaCIsZnVuY3Rpb24oKXtyZXR1cm4gci5qfSksbi5kKHQsImdldENvbnRleHQiLGZ1bmN0aW9uKCl7cmV0dXJuIHIubH0pLG4uZCh0LCJzZXRDb250ZXh0IixmdW5jdGlvbigpe3JldHVybiByLnF9KSxuLmQodCwidGFrZUV2ZXJ5IixmdW5jdGlvbigpe3JldHVybiByLnR9KSxuLmQodCwidGFrZUxhdGVzdCIsZnVuY3Rpb24oKXtyZXR1cm4gci51fSksbi5kKHQsInRocm90dGxlIixmdW5jdGlvbigpe3JldHVybiByLnd9KX0sZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKCl7dGhyb3cgbmV3IEVycm9yKCJzZXRUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkIil9ZnVuY3Rpb24gcigpe3Rocm93IG5ldyBFcnJvcigiY2xlYXJUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkIil9ZnVuY3Rpb24gaShlKXtpZihsPT09c2V0VGltZW91dClyZXR1cm4gc2V0VGltZW91dChlLDApO2lmKChsPT09bnx8IWwpJiZzZXRUaW1lb3V0KXJldHVybiBsPXNldFRpbWVvdXQsc2V0VGltZW91dChlLDApO3RyeXtyZXR1cm4gbChlLDApfWNhdGNoKHQpe3RyeXtyZXR1cm4gbC5jYWxsKG51bGwsZSwwKX1jYXRjaCh0KXtyZXR1cm4gbC5jYWxsKHRoaXMsZSwwKX19fWZ1bmN0aW9uIG8oZSl7aWYocD09PWNsZWFyVGltZW91dClyZXR1cm4gY2xlYXJUaW1lb3V0KGUpO2lmKChwPT09cnx8IXApJiZjbGVhclRpbWVvdXQpcmV0dXJuIHA9Y2xlYXJUaW1lb3V0LGNsZWFyVGltZW91dChlKTt0cnl7cmV0dXJuIHAoZSl9Y2F0Y2godCl7dHJ5e3JldHVybiBwLmNhbGwobnVsbCxlKX1jYXRjaCh0KXtyZXR1cm4gcC5jYWxsKHRoaXMsZSl9fX1mdW5jdGlvbiBhKCl7bSYmZCYmKG09ITEsZC5sZW5ndGg/aD1kLmNvbmNhdChoKTpnPS0xLGgubGVuZ3RoJiZzKCkpfWZ1bmN0aW9uIHMoKXtpZighbSl7dmFyIGU9aShhKTttPSEwO2Zvcih2YXIgdD1oLmxlbmd0aDt0Oyl7Zm9yKGQ9aCxoPVtdOysrZzx0OylkJiZkW2ddLnJ1bigpO2c9LTEsdD1oLmxlbmd0aH1kPW51bGwsbT0hMSxvKGUpfX1mdW5jdGlvbiB1KGUsdCl7dGhpcy5mdW49ZSx0aGlzLmFycmF5PXR9ZnVuY3Rpb24gYygpe312YXIgbCxwLGY9ZS5leHBvcnRzPXt9OyFmdW5jdGlvbigpe3RyeXtsPSJmdW5jdGlvbiI9PT10eXBlb2Ygc2V0VGltZW91dD9zZXRUaW1lb3V0Om59Y2F0Y2goZSl7bD1ufXRyeXtwPSJmdW5jdGlvbiI9PT10eXBlb2YgY2xlYXJUaW1lb3V0P2NsZWFyVGltZW91dDpyfWNhdGNoKGUpe3A9cn19KCk7dmFyIGQsaD1bXSxtPSExLGc9LTE7Zi5uZXh0VGljaz1mdW5jdGlvbihlKXt2YXIgdD1uZXcgQXJyYXkoYXJndW1lbnRzLmxlbmd0aC0xKTtpZihhcmd1bWVudHMubGVuZ3RoPjEpZm9yKHZhciBuPTE7bjxhcmd1bWVudHMubGVuZ3RoO24rKyl0W24tMV09YXJndW1lbnRzW25dO2gucHVzaChuZXcgdShlLHQpKSwxIT09aC5sZW5ndGh8fG18fGkocyl9LHUucHJvdG90eXBlLnJ1bj1mdW5jdGlvbigpe3RoaXMuZnVuLmFwcGx5KG51bGwsdGhpcy5hcnJheSl9LGYudGl0bGU9ImJyb3dzZXIiLGYuYnJvd3Nlcj0hMCxmLmVudj17fSxmLmFyZ3Y9W10sZi52ZXJzaW9uPSIiLGYudmVyc2lvbnM9e30sZi5vbj1jLGYuYWRkTGlzdGVuZXI9YyxmLm9uY2U9YyxmLm9mZj1jLGYucmVtb3ZlTGlzdGVuZXI9YyxmLnJlbW92ZUFsbExpc3RlbmVycz1jLGYuZW1pdD1jLGYucHJlcGVuZExpc3RlbmVyPWMsZi5wcmVwZW5kT25jZUxpc3RlbmVyPWMsZi5saXN0ZW5lcnM9ZnVuY3Rpb24oZSl7cmV0dXJuW119LGYuYmluZGluZz1mdW5jdGlvbihlKXt0aHJvdyBuZXcgRXJyb3IoInByb2Nlc3MuYmluZGluZyBpcyBub3Qgc3VwcG9ydGVkIil9LGYuY3dkPWZ1bmN0aW9uKCl7cmV0dXJuIi8ifSxmLmNoZGlyPWZ1bmN0aW9uKGUpe3Rocm93IG5ldyBFcnJvcigicHJvY2Vzcy5jaGRpciBpcyBub3Qgc3VwcG9ydGVkIil9LGYudW1hc2s9ZnVuY3Rpb24oKXtyZXR1cm4gMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7dmFyIHI9bnx8dSxvPXZvaWQgMCxhPUFycmF5LmlzQXJyYXkoZSksbD1bZV0scD0tMSxmPVtdLGQ9dm9pZCAwLGg9W10sbT1bXSxnPWU7ZG97cCsrO3ZhciB5PXA9PT1sLmxlbmd0aCx2PXZvaWQgMCxiPXZvaWQgMCx4PXkmJjAhPT1mLmxlbmd0aDtpZih5KXtpZih2PTA9PT1tLmxlbmd0aD92b2lkIDA6aC5wb3AoKSxiPWQsZD1tLnBvcCgpLHgpe2lmKGEpYj1iLnNsaWNlKCk7ZWxzZXt2YXIgQz17fTtmb3IodmFyIEUgaW4gYiliLmhhc093blByb3BlcnR5KEUpJiYoQ1tFXT1iW0VdKTtiPUN9Zm9yKHZhciBEPTAsdz0wO3c8Zi5sZW5ndGg7dysrKXt2YXIgUz1mW3ddWzBdLGs9Zlt3XVsxXTthJiYoUy09RCksYSYmbnVsbD09PWs/KGIuc3BsaWNlKFMsMSksRCsrKTpiW1NdPWt9fXA9by5pbmRleCxsPW8ua2V5cyxmPW8uZWRpdHMsYT1vLmluQXJyYXksbz1vLnByZXZ9ZWxzZXtpZih2PWQ/YT9wOmxbcF06dm9pZCAwLG51bGw9PT0oYj1kP2Rbdl06Zyl8fHZvaWQgMD09PWIpY29udGludWU7ZCYmaC5wdXNoKHYpfXZhciBBPXZvaWQgMDtpZighQXJyYXkuaXNBcnJheShiKSl7aWYoIWkoYikpdGhyb3cgbmV3IEVycm9yKCJJbnZhbGlkIEFTVCBOb2RlOiAiK0pTT04uc3RyaW5naWZ5KGIpKTt2YXIgXz1zKHQsYi5raW5kLHkpO2lmKF8pe2lmKChBPV8uY2FsbCh0LGIsdixkLGgsbSkpPT09YylicmVhaztpZighMT09PUEpe2lmKCF5KXtoLnBvcCgpO2NvbnRpbnVlfX1lbHNlIGlmKHZvaWQgMCE9PUEmJihmLnB1c2goW3YsQV0pLCF5KSl7aWYoIWkoQSkpe2gucG9wKCk7Y29udGludWV9Yj1BfX19dm9pZCAwPT09QSYmeCYmZi5wdXNoKFt2LGJdKSx5fHwobz17aW5BcnJheTphLGluZGV4OnAsa2V5czpsLGVkaXRzOmYscHJldjpvfSxhPUFycmF5LmlzQXJyYXkoYiksbD1hP2I6cltiLmtpbmRdfHxbXSxwPS0xLGY9W10sZCYmbS5wdXNoKGQpLGQ9Yil9d2hpbGUodm9pZCAwIT09byk7cmV0dXJuIDAhPT1mLmxlbmd0aCYmKGc9ZltmLmxlbmd0aC0xXVsxXSksZ31mdW5jdGlvbiBpKGUpe3JldHVybiBlJiYic3RyaW5nIj09PXR5cGVvZiBlLmtpbmR9ZnVuY3Rpb24gbyhlKXt2YXIgdD1uZXcgQXJyYXkoZS5sZW5ndGgpO3JldHVybntlbnRlcjpmdW5jdGlvbihuKXtmb3IodmFyIHI9MDtyPGUubGVuZ3RoO3IrKylpZighdFtyXSl7dmFyIGk9cyhlW3JdLG4ua2luZCwhMSk7aWYoaSl7dmFyIG89aS5hcHBseShlW3JdLGFyZ3VtZW50cyk7aWYoITE9PT1vKXRbcl09bjtlbHNlIGlmKG89PT1jKXRbcl09YztlbHNlIGlmKHZvaWQgMCE9PW8pcmV0dXJuIG99fX0sbGVhdmU6ZnVuY3Rpb24obil7Zm9yKHZhciByPTA7cjxlLmxlbmd0aDtyKyspaWYodFtyXSl0W3JdPT09biYmKHRbcl09bnVsbCk7ZWxzZXt2YXIgaT1zKGVbcl0sbi5raW5kLCEwKTtpZihpKXt2YXIgbz1pLmFwcGx5KGVbcl0sYXJndW1lbnRzKTtpZihvPT09Yyl0W3JdPWM7ZWxzZSBpZih2b2lkIDAhPT1vJiYhMSE9PW8pcmV0dXJuIG99fX19fWZ1bmN0aW9uIGEoZSx0KXtyZXR1cm57ZW50ZXI6ZnVuY3Rpb24obil7ZS5lbnRlcihuKTt2YXIgcj1zKHQsbi5raW5kLCExKTtpZihyKXt2YXIgbz1yLmFwcGx5KHQsYXJndW1lbnRzKTtyZXR1cm4gdm9pZCAwIT09byYmKGUubGVhdmUobiksaShvKSYmZS5lbnRlcihvKSksb319LGxlYXZlOmZ1bmN0aW9uKG4pe3ZhciByPXModCxuLmtpbmQsITApLGk9dm9pZCAwO3JldHVybiByJiYoaT1yLmFwcGx5KHQsYXJndW1lbnRzKSksZS5sZWF2ZShuKSxpfX19ZnVuY3Rpb24gcyhlLHQsbil7dmFyIHI9ZVt0XTtpZihyKXtpZighbiYmImZ1bmN0aW9uIj09PXR5cGVvZiByKXJldHVybiByO3ZhciBpPW4/ci5sZWF2ZTpyLmVudGVyO2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgaSlyZXR1cm4gaX1lbHNle3ZhciBvPW4/ZS5sZWF2ZTplLmVudGVyO2lmKG8pe2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgbylyZXR1cm4gbzt2YXIgYT1vW3RdO2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgYSlyZXR1cm4gYX19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnZpc2l0PXIsdC52aXNpdEluUGFyYWxsZWw9byx0LnZpc2l0V2l0aFR5cGVJbmZvPWEsdC5nZXRWaXNpdEZuPXM7dmFyIHU9dC5RdWVyeURvY3VtZW50S2V5cz17TmFtZTpbXSxEb2N1bWVudDpbImRlZmluaXRpb25zIl0sT3BlcmF0aW9uRGVmaW5pdGlvbjpbIm5hbWUiLCJ2YXJpYWJsZURlZmluaXRpb25zIiwiZGlyZWN0aXZlcyIsInNlbGVjdGlvblNldCJdLFZhcmlhYmxlRGVmaW5pdGlvbjpbInZhcmlhYmxlIiwidHlwZSIsImRlZmF1bHRWYWx1ZSJdLFZhcmlhYmxlOlsibmFtZSJdLFNlbGVjdGlvblNldDpbInNlbGVjdGlvbnMiXSxGaWVsZDpbImFsaWFzIiwibmFtZSIsImFyZ3VtZW50cyIsImRpcmVjdGl2ZXMiLCJzZWxlY3Rpb25TZXQiXSxBcmd1bWVudDpbIm5hbWUiLCJ2YWx1ZSJdLEZyYWdtZW50U3ByZWFkOlsibmFtZSIsImRpcmVjdGl2ZXMiXSxJbmxpbmVGcmFnbWVudDpbInR5cGVDb25kaXRpb24iLCJkaXJlY3RpdmVzIiwic2VsZWN0aW9uU2V0Il0sRnJhZ21lbnREZWZpbml0aW9uOlsibmFtZSIsInR5cGVDb25kaXRpb24iLCJkaXJlY3RpdmVzIiwic2VsZWN0aW9uU2V0Il0sSW50VmFsdWU6W10sRmxvYXRWYWx1ZTpbXSxTdHJpbmdWYWx1ZTpbXSxCb29sZWFuVmFsdWU6W10sTnVsbFZhbHVlOltdLEVudW1WYWx1ZTpbXSxMaXN0VmFsdWU6WyJ2YWx1ZXMiXSxPYmplY3RWYWx1ZTpbImZpZWxkcyJdLE9iamVjdEZpZWxkOlsibmFtZSIsInZhbHVlIl0sRGlyZWN0aXZlOlsibmFtZSIsImFyZ3VtZW50cyJdLE5hbWVkVHlwZTpbIm5hbWUiXSxMaXN0VHlwZTpbInR5cGUiXSxOb25OdWxsVHlwZTpbInR5cGUiXSxTY2hlbWFEZWZpbml0aW9uOlsiZGlyZWN0aXZlcyIsIm9wZXJhdGlvblR5cGVzIl0sT3BlcmF0aW9uVHlwZURlZmluaXRpb246WyJ0eXBlIl0sU2NhbGFyVHlwZURlZmluaXRpb246WyJuYW1lIiwiZGlyZWN0aXZlcyJdLE9iamVjdFR5cGVEZWZpbml0aW9uOlsibmFtZSIsImludGVyZmFjZXMiLCJkaXJlY3RpdmVzIiwiZmllbGRzIl0sRmllbGREZWZpbml0aW9uOlsibmFtZSIsImFyZ3VtZW50cyIsInR5cGUiLCJkaXJlY3RpdmVzIl0sSW5wdXRWYWx1ZURlZmluaXRpb246WyJuYW1lIiwidHlwZSIsImRlZmF1bHRWYWx1ZSIsImRpcmVjdGl2ZXMiXSxJbnRlcmZhY2VUeXBlRGVmaW5pdGlvbjpbIm5hbWUiLCJkaXJlY3RpdmVzIiwiZmllbGRzIl0sVW5pb25UeXBlRGVmaW5pdGlvbjpbIm5hbWUiLCJkaXJlY3RpdmVzIiwidHlwZXMiXSxFbnVtVHlwZURlZmluaXRpb246WyJuYW1lIiwiZGlyZWN0aXZlcyIsInZhbHVlcyJdLEVudW1WYWx1ZURlZmluaXRpb246WyJuYW1lIiwiZGlyZWN0aXZlcyJdLElucHV0T2JqZWN0VHlwZURlZmluaXRpb246WyJuYW1lIiwiZGlyZWN0aXZlcyIsImZpZWxkcyJdLFR5cGVFeHRlbnNpb25EZWZpbml0aW9uOlsiZGVmaW5pdGlvbiJdLERpcmVjdGl2ZURlZmluaXRpb246WyJuYW1lIiwiYXJndW1lbnRzIiwibG9jYXRpb25zIl19LGM9dC5CUkVBSz17fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiB2b2lkIDA9PT1lfHxlIT09ZX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gaShlLHQsbil7aWYoZSl7aWYodCBpbnN0YW5jZW9mIGcuR3JhcGhRTE5vbk51bGwpe2lmKGUua2luZD09PW0uTlVMTClyZXR1cm47cmV0dXJuIGkoZSx0Lm9mVHlwZSxuKX1pZihlLmtpbmQ9PT1tLk5VTEwpcmV0dXJuIG51bGw7aWYoZS5raW5kPT09bS5WQVJJQUJMRSl7dmFyIHI9ZS5uYW1lLnZhbHVlO2lmKCFufHwoMCxkLmRlZmF1bHQpKG5bcl0pKXJldHVybjtyZXR1cm4gbltyXX1pZih0IGluc3RhbmNlb2YgZy5HcmFwaFFMTGlzdCl7dmFyIGE9dC5vZlR5cGU7aWYoZS5raW5kPT09bS5MSVNUKXtmb3IodmFyIHU9W10sbD1lLnZhbHVlcyxmPTA7ZjxsLmxlbmd0aDtmKyspaWYobyhsW2ZdLG4pKXtpZihhIGluc3RhbmNlb2YgZy5HcmFwaFFMTm9uTnVsbClyZXR1cm47dS5wdXNoKG51bGwpfWVsc2V7dmFyIGg9aShsW2ZdLGEsbik7aWYoKDAsZC5kZWZhdWx0KShoKSlyZXR1cm47dS5wdXNoKGgpfXJldHVybiB1fXZhciB5PWkoZSxhLG4pO2lmKCgwLGQuZGVmYXVsdCkoeSkpcmV0dXJuO3JldHVyblt5XX1pZih0IGluc3RhbmNlb2YgZy5HcmFwaFFMSW5wdXRPYmplY3RUeXBlKXtpZihlLmtpbmQhPT1tLk9CSkVDVClyZXR1cm47Zm9yKHZhciB2PU9iamVjdC5jcmVhdGUobnVsbCksYj10LmdldEZpZWxkcygpLHg9KDAscy5kZWZhdWx0KShlLmZpZWxkcyxmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lLnZhbHVlfSksQz1PYmplY3Qua2V5cyhiKSxFPTA7RTxDLmxlbmd0aDtFKyspe3ZhciBEPUNbRV0sdz1iW0RdLFM9eFtEXTtpZihTJiYhbyhTLnZhbHVlLG4pKXt2YXIgaz1pKFMudmFsdWUsdy50eXBlLG4pO2lmKCgwLGQuZGVmYXVsdCkoaykpcmV0dXJuO3ZbRF09a31lbHNlIGlmKCgwLGQuZGVmYXVsdCkody5kZWZhdWx0VmFsdWUpKXtpZih3LnR5cGUgaW5zdGFuY2VvZiBnLkdyYXBoUUxOb25OdWxsKXJldHVybn1lbHNlIHZbRF09dy5kZWZhdWx0VmFsdWV9cmV0dXJuIHZ9dCBpbnN0YW5jZW9mIGcuR3JhcGhRTFNjYWxhclR5cGV8fHQgaW5zdGFuY2VvZiBnLkdyYXBoUUxFbnVtVHlwZXx8KDAsYy5kZWZhdWx0KSgwLCJNdXN0IGJlIGlucHV0IHR5cGUiKTt2YXIgQT10LnBhcnNlTGl0ZXJhbChlKTtpZighKDAscC5kZWZhdWx0KShBKXx8dC5pc1ZhbGlkTGl0ZXJhbChlKSlyZXR1cm4gQX19ZnVuY3Rpb24gbyhlLHQpe3JldHVybiBlLmtpbmQ9PT1tLlZBUklBQkxFJiYoIXR8fCgwLGQuZGVmYXVsdCkodFtlLm5hbWUudmFsdWVdKSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQudmFsdWVGcm9tQVNUPWk7dmFyIGE9big0Nikscz1yKGEpLHU9bigxMyksYz1yKHUpLGw9bigzNSkscD1yKGwpLGY9big1OCksZD1yKGYpLGg9bigxMCksbT1mdW5jdGlvbihlKXtpZihlJiZlLl9fZXNNb2R1bGUpcmV0dXJuIGU7dmFyIHQ9e307aWYobnVsbCE9ZSlmb3IodmFyIG4gaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxuKSYmKHRbbl09ZVtuXSk7cmV0dXJuIHQuZGVmYXVsdD1lLHR9KGgpLGc9big2KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PXR5cGVvZiBlO3JldHVybiBudWxsIT1lJiYoIm9iamVjdCI9PXR8fCJmdW5jdGlvbiI9PXQpfXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG51bGw9PWU/IiI6T2JqZWN0KGkuYSkoZSl9dmFyIGk9big0MjIpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO24uZCh0LCJiIixmdW5jdGlvbigpe3JldHVybiByfSksbi5kKHQsImEiLGZ1bmN0aW9uKCl7cmV0dXJuIGl9KTt2YXIgcj0iLyIsaT0ifHwifSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGV9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXshZnVuY3Rpb24odCl7InVzZSBzdHJpY3QiO3ZhciBuPTAscj1NYXRoLnBvdygzNiw0KSxpPWZ1bmN0aW9uKGUsdCl7dmFyIG49IjAwMDAwMDAwMCIrZTtyZXR1cm4gbi5zdWJzdHIobi5sZW5ndGgtdCl9LG89ZnVuY3Rpb24oKXtyZXR1cm4gaSgoTWF0aC5yYW5kb20oKSpyPDwwKS50b1N0cmluZygzNiksNCl9LGE9ZnVuY3Rpb24oKXtyZXR1cm4gbj1uPHI/bjowLCsrbi0xfSxzPWZ1bmN0aW9uKCl7dmFyIGUsdD0obmV3IERhdGUpLmdldFRpbWUoKS50b1N0cmluZygzNiksbj1zLmZpbmdlcnByaW50KCkscj1vKCkrbygpO3JldHVybiBlPWkoYSgpLnRvU3RyaW5nKDM2KSw0KSwiYyIrdCtlK24rcn07cy5zbHVnPWZ1bmN0aW9uKCl7dmFyIGUsdD0obmV3IERhdGUpLmdldFRpbWUoKS50b1N0cmluZygzNiksbj1zLmZpbmdlcnByaW50KCkuc2xpY2UoMCwxKStzLmZpbmdlcnByaW50KCkuc2xpY2UoLTEpLHI9bygpLnNsaWNlKC0yKTtyZXR1cm4gZT1hKCkudG9TdHJpbmcoMzYpLnNsaWNlKC00KSx0LnNsaWNlKC0yKStlK24rcn0scy5nbG9iYWxDb3VudD1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKCl7dmFyIGUsdD0wO2ZvcihlIGluIHdpbmRvdyl0Kys7cmV0dXJuIHR9KCk7cmV0dXJuIHMuZ2xvYmFsQ291bnQ9ZnVuY3Rpb24oKXtyZXR1cm4gZX0sZX0scy5maW5nZXJwcmludD1mdW5jdGlvbigpe3JldHVybiBpKChuYXZpZ2F0b3IubWltZVR5cGVzLmxlbmd0aCtuYXZpZ2F0b3IudXNlckFnZW50Lmxlbmd0aCkudG9TdHJpbmcoMzYpK3MuZ2xvYmFsQ291bnQoKS50b1N0cmluZygzNiksNCl9LHQucmVnaXN0ZXI/dC5yZWdpc3RlcigiY3VpZCIscyk6ZS5leHBvcnRzPXN9KHRoaXMuYXBwbGl0dWRlfHx0aGlzKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBmdW5jdGlvbigpe3ZhciB0LG4scj1bXTtmb3IodD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspclt0XT1hcmd1bWVudHNbdF07cmV0dXJuIHModGhpcyxmdW5jdGlvbih0KXtzd2l0Y2godC5sYWJlbCl7Y2FzZSAwOnJldHVybiB0LnRyeXMucHVzaChbMCwyLCwzXSksWzQsZS5hcHBseSh2b2lkIDAscildO2Nhc2UgMTpyZXR1cm4gdC5zZW50KCksWzMsM107Y2FzZSAyOnJldHVybiBuPXQuc2VudCgpLGNvbnNvbGUuZXJyb3IobiksWzMsM107Y2FzZSAzOnJldHVyblsyXX19KX19ZnVuY3Rpb24gaShlLHQpe3JldHVybiB1LmZvcm1hdChlLGEoe30sdCx7cGFyc2VyOiJncmFwaHFsIixwbHVnaW5zOltjXX0pKX1mdW5jdGlvbiBvKCl7dHJ5e3JldHVybiB3aW5kb3cuc2VsZiE9PXdpbmRvdy50b3B9Y2F0Y2goZSl7cmV0dXJuITB9fXZhciBhPWZ1bmN0aW9uKCl7cmV0dXJuIGE9T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0LG49MSxyPWFyZ3VtZW50cy5sZW5ndGg7bjxyO24rKyl7dD1hcmd1bWVudHNbbl07Zm9yKHZhciBpIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsaSkmJihlW2ldPXRbaV0pfXJldHVybiBlfSxhLmFwcGx5KHRoaXMsYXJndW1lbnRzKX0scz1mdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiByKFtlLHRdKX19ZnVuY3Rpb24gcihuKXtpZihpKXRocm93IG5ldyBUeXBlRXJyb3IoIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy4iKTtmb3IoO3U7KXRyeXtpZihpPTEsbyYmKGE9MiZuWzBdP28ucmV0dXJuOm5bMF0/by50aHJvd3x8KChhPW8ucmV0dXJuKSYmYS5jYWxsKG8pLDApOm8ubmV4dCkmJiEoYT1hLmNhbGwobyxuWzFdKSkuZG9uZSlyZXR1cm4gYTtzd2l0Y2gobz0wLGEmJihuPVsyJm5bMF0sYS52YWx1ZV0pLG5bMF0pe2Nhc2UgMDpjYXNlIDE6YT1uO2JyZWFrO2Nhc2UgNDpyZXR1cm4gdS5sYWJlbCsrLHt2YWx1ZTpuWzFdLGRvbmU6ITF9O2Nhc2UgNTp1LmxhYmVsKyssbz1uWzFdLG49WzBdO2NvbnRpbnVlO2Nhc2UgNzpuPXUub3BzLnBvcCgpLHUudHJ5cy5wb3AoKTtjb250aW51ZTtkZWZhdWx0OmlmKGE9dS50cnlzLCEoYT1hLmxlbmd0aD4wJiZhW2EubGVuZ3RoLTFdKSYmKDY9PT1uWzBdfHwyPT09blswXSkpe3U9MDtjb250aW51ZX1pZigzPT09blswXSYmKCFhfHxuWzFdPmFbMF0mJm5bMV08YVszXSkpe3UubGFiZWw9blsxXTticmVha31pZig2PT09blswXSYmdS5sYWJlbDxhWzFdKXt1LmxhYmVsPWFbMV0sYT1uO2JyZWFrfWlmKGEmJnUubGFiZWw8YVsyXSl7dS5sYWJlbD1hWzJdLHUub3BzLnB1c2gobik7YnJlYWt9YVsyXSYmdS5vcHMucG9wKCksdS50cnlzLnBvcCgpO2NvbnRpbnVlfW49dC5jYWxsKGUsdSl9Y2F0Y2goZSl7bj1bNixlXSxvPTB9ZmluYWxseXtpPWE9MH1pZig1Jm5bMF0pdGhyb3cgblsxXTtyZXR1cm57dmFsdWU6blswXT9uWzFdOnZvaWQgMCxkb25lOiEwfX12YXIgaSxvLGEscyx1PXtsYWJlbDowLHNlbnQ6ZnVuY3Rpb24oKXtpZigxJmFbMF0pdGhyb3cgYVsxXTtyZXR1cm4gYVsxXX0sdHJ5czpbXSxvcHM6W119O3JldHVybiBzPXtuZXh0Om4oMCksdGhyb3c6bigxKSxyZXR1cm46bigyKX0sImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJihzW1N5bWJvbC5pdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pLHN9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgdT1uKDUwOCksYz1uKDUwOSk7dC5zYWZlbHk9cix0LnByZXR0aWZ5PWksdC5pc0lmcmFtZT1vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4pe2Zvcih2YXIgcj1uLmdldEluKFsiZmllbGQiLCJwYXRoIl0pLG89ci5zcGxpdCgiLyIpLGE9bnVsbCxzPTAsdT1udWxsLGM9LTE7by5sZW5ndGg+MDspIWZ1bmN0aW9uKCl7dmFyIG49by5zaGlmdCgpO2lmKDA9PT1zKWE9ZVtuXSxjPU9iamVjdC5rZXlzKGUpLmluZGV4T2Yobik7ZWxzZXt2YXIgcj1hLmFyZ3MuZmluZChmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lPT09bn0pO3U9YSxyP2E9cjooYS50eXBlLm9mVHlwZSYmKGE9aShhLnR5cGUub2ZUeXBlKSksYS50eXBlJiYoYT1hLnR5cGUpLGE9YS5nZXRGaWVsZHMoKVtuXXx8YS5nZXRJbnRlcmZhY2VzKCkuZmluZChmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lPT09bn0pKX11JiYoYz1sKHQsdSxhKSkscysrfSgpO3JldHVybiBhPyhhLnBhdGg9cixhLnBhcmVudD11LG4ubWVyZ2Uoe3k6YyxmaWVsZDphfSkpOm51bGx9ZnVuY3Rpb24gaShlLHQpe3JldHVybiB2b2lkIDA9PT10JiYodD0wKSxlLm9mVHlwZSYmdDw1P2koZS5vZlR5cGUsdCsxKTplfWZ1bmN0aW9uIG8oZSl7cmV0dXJuIHAoe30sZS5nZXRRdWVyeVR5cGUoKS5nZXRGaWVsZHMoKSxlLmdldE11dGF0aW9uVHlwZSYmZS5nZXRNdXRhdGlvblR5cGUoKSYmZS5nZXRNdXRhdGlvblR5cGUoKS5nZXRGaWVsZHMoKSxlLmdldFN1YnNjcmlwdGlvblR5cGUmJmUuZ2V0U3Vic2NyaXB0aW9uVHlwZSgpJiZlLmdldFN1YnNjcmlwdGlvblR5cGUoKS5nZXRGaWVsZHMoKSl9ZnVuY3Rpb24gYShlKXt2YXIgdD17cXVlcmllczpbXSxtdXRhdGlvbnM6W10sc3Vic2NyaXB0aW9uczpbXX0sbj1lLmdldFF1ZXJ5VHlwZSgpLHI9bi5nZXRGaWVsZHMoKTt0LnF1ZXJpZXM9T2JqZWN0LmtleXMocikubWFwKGZ1bmN0aW9uKGUpe3ZhciB0PXJbZV07cmV0dXJuIHQucGF0aD1lLHQucGFyZW50PW51bGwsdH0pO3ZhciBpPWUuZ2V0TXV0YXRpb25UeXBlJiZlLmdldE11dGF0aW9uVHlwZSgpO2lmKGkpe3ZhciBvPWkuZ2V0RmllbGRzKCk7dC5tdXRhdGlvbnM9T2JqZWN0LmtleXMobykubWFwKGZ1bmN0aW9uKGUpe3ZhciB0PW9bZV07cmV0dXJuIHQucGF0aD1lLHQucGFyZW50PW51bGwsdH0pfXdpbmRvdy5zcz1lO3ZhciBhPWUuZ2V0U3Vic2NyaXB0aW9uVHlwZSYmZS5nZXRTdWJzY3JpcHRpb25UeXBlKCk7aWYoYSl7dmFyIHM9YS5nZXRGaWVsZHMoKTt0LnN1YnNjcmlwdGlvbnM9T2JqZWN0LmtleXMocykubWFwKGZ1bmN0aW9uKGUpe3ZhciB0PXNbZV07cmV0dXJuIHQucGF0aD1lLHQucGFyZW50PW51bGwsdH0pfXJldHVybiB0fWZ1bmN0aW9uIHMoZSx0KXt2YXIgbj0wO3JldHVybiBlLnF1ZXJpZXNbdCtuXT9lLnF1ZXJpZXNbdCtuXToobis9ZS5xdWVyaWVzLmxlbmd0aCxlLm11dGF0aW9uc1t0LW5dP2UubXV0YXRpb25zW3Qtbl06KG4rPWUubXV0YXRpb25zLmxlbmd0aCxlLnN1YnNjcmlwdGlvbnNbdC1uXT9lLnN1YnNjcmlwdGlvbnNbdC1uXTp2b2lkIDApKX1mdW5jdGlvbiB1KGUsdCl7dmFyIG49e2ZpZWxkczpbXSxpbnRlcmZhY2VzOltdLGFyZ3M6W10saW1wbGVtZW50YXRpb25zOltdfSxyPXQudHlwZXx8dCxvPWYuaXNUeXBlKHIpO2lmKHIub2ZUeXBlJiYocj1pKHIub2ZUeXBlKSksci5nZXRGaWVsZHMpe3ZhciBhPXIuZ2V0RmllbGRzKCk7bi5maWVsZHM9T2JqZWN0LmtleXMoYSkubWFwKGZ1bmN0aW9uKGUpe3ZhciBuPWFbZV07cmV0dXJuIG4ucGFyZW50PXQsbi5wYXRoPXQucGF0aCsiLyIrZSxufSl9cmV0dXJuIHIgaW5zdGFuY2VvZiBmLkdyYXBoUUxPYmplY3RUeXBlJiYobi5pbnRlcmZhY2VzPXIuZ2V0SW50ZXJmYWNlcygpKSxuLmFyZ3M9dC5hcmdzP3QuYXJnczpbXSxvJiZyIGluc3RhbmNlb2YgZi5HcmFwaFFMSW50ZXJmYWNlVHlwZSYmKG4uaW1wbGVtZW50YXRpb25zPWUuZ2V0UG9zc2libGVUeXBlcyhyKSksbn1mdW5jdGlvbiBjKGUsdCl7dmFyIG49MDtyZXR1cm4gZS5pbnRlcmZhY2VzW3Qrbl0/ZS5pbnRlcmZhY2VzW3Qrbl06KG4rPWUuaW50ZXJmYWNlcy5sZW5ndGgsZS5maWVsZHNbdC1uXT9lLmZpZWxkc1t0LW5dOihuKz1lLmZpZWxkcy5sZW5ndGgsZS5hcmdzW3Qtbl0/ZS5hcmdzW3Qtbl06KG4rPWUuYXJncy5sZW5ndGgsZS5pbXBsZW1lbnRhdGlvbnNbdC1uXT9lLmltcGxlbWVudGF0aW9uc1t0LW5dOnZvaWQgMCkpKX1mdW5jdGlvbiBsKGUsdCxuKXt2YXIgcj11KGUsdCksaT1yLmludGVyZmFjZXMuaW5kZXhPZihuKTtpZihpPi0xKXJldHVybiBpO3ZhciBvPXIuZmllbGRzLmluZGV4T2Yobik7aWYobz4tMSlyZXR1cm4gci5pbnRlcmZhY2VzLmxlbmd0aCtvO3ZhciBhPXIuYXJncy5pbmRleE9mKG4pO2lmKGE+LTEpcmV0dXJuIHIuaW50ZXJmYWNlcy5sZW5ndGgrci5maWVsZHMubGVuZ3RoK2E7dmFyIHM9ci5pbXBsZW1lbnRhdGlvbnMuaW5kZXhPZihuKTtyZXR1cm4gcz4tMT9yLmludGVyZmFjZXMubGVuZ3RoK3IuZmllbGRzLmxlbmd0aCtyLmFyZ3MubGVuZ3RoK3M6MH12YXIgcD1mdW5jdGlvbigpe3JldHVybiBwPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPTEscj1hcmd1bWVudHMubGVuZ3RoO248cjtuKyspe3Q9YXJndW1lbnRzW25dO2Zvcih2YXIgaSBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LGkpJiYoZVtpXT10W2ldKX1yZXR1cm4gZX0scC5hcHBseSh0aGlzLGFyZ3VtZW50cyl9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgZj1uKDcpO3QuZ2V0TmV3U3RhY2s9cix0LmdldERlZXBlclR5cGU9aSx0LmdldFJvb3RNYXA9byx0LnNlcmlhbGl6ZVJvb3Q9YSx0LmdldEVsZW1lbnRSb290PXMsdC5zZXJpYWxpemU9dSx0LmdldEVsZW1lbnQ9Yyx0LmdldEVsZW1lbnRJbmRleD1sfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcixpPW4oMjMpO3Quc2V0U3RhY2tzPShyPWkuY3JlYXRlQWN0aW9ucyh7U0VUX1NUQUNLUzpmdW5jdGlvbihlLHQpe3JldHVybntzZXNzaW9uSWQ6ZSxzdGFja3M6dH19LEFERF9TVEFDSzpmdW5jdGlvbihlLHQsbixyKXtyZXR1cm57c2Vzc2lvbklkOmUsZmllbGQ6dCx4Om4seTpyfX0sVE9HR0xFX0RPQ1M6ZnVuY3Rpb24oZSx0KXtyZXR1cm57c2Vzc2lvbklkOmUsYWN0aXZlVGFiSWR4OnR9fSxTRVRfRE9DU19WSVNJQkxFOmZ1bmN0aW9uKGUsdCxuKXtyZXR1cm57c2Vzc2lvbklkOmUsb3Blbjp0LGFjdGl2ZVRhYklkeDpufX0sQ0hBTkdFX1dJRFRIX0RPQ1M6ZnVuY3Rpb24oZSx0KXtyZXR1cm57c2Vzc2lvbklkOmUsd2lkdGg6dH19LENIQU5HRV9LRVlfTU9WRTpmdW5jdGlvbihlLHQpe3JldHVybntzZXNzaW9uSWQ6ZSxtb3ZlOnR9fSxTSE9XX0RPQ19GT1JfUkVGRVJFTkNFOmZ1bmN0aW9uKGUpe3JldHVybntyZWZlcmVuY2U6ZX19fSksci5zZXRTdGFja3MpLHQuYWRkU3RhY2s9ci5hZGRTdGFjayx0LnRvZ2dsZURvY3M9ci50b2dnbGVEb2NzLHQuc2V0RG9jc1Zpc2libGU9ci5zZXREb2NzVmlzaWJsZSx0LmNoYW5nZVdpZHRoRG9jcz1yLmNoYW5nZVdpZHRoRG9jcyx0LmNoYW5nZUtleU1vdmU9ci5jaGFuZ2VLZXlNb3ZlLHQuc2hvd0RvY0ZvclJlZmVyZW5jZT1yLnNob3dEb2NGb3JSZWZlcmVuY2V9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oOCksaT1uKDEzMCksbz1uKDE3KTt0LmdldFNlc3Npb25Eb2NzU3RhdGU9ci5jcmVhdGVTZWxlY3Rvcihbby5nZXRTZWxlY3RlZFdvcmtzcGFjZV0sZnVuY3Rpb24oZSl7dmFyIHQ9ZS5zZXNzaW9ucy5zZWxlY3RlZFNlc3Npb25JZDtyZXR1cm4gZS5kb2NzLmdldCh0KXx8bmV3IGkuRG9jc1Nlc3Npb259KSx0LmdldFNlc3Npb25Eb2NzPXIuY3JlYXRlU2VsZWN0b3IoW3QuZ2V0U2Vzc2lvbkRvY3NTdGF0ZV0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudG9KUygpfSl9LGZ1bmN0aW9uKGUsdCxuKXshZnVuY3Rpb24oZSl7ZShuKDIpKX0oZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlLHQscil7dmFyIGk9ZS5nZXRMaW5lSGFuZGxlKHQubGluZSksbz10LmNoLTEsdT1yJiZyLmFmdGVyQ3Vyc29yO251bGw9PXUmJih1PS8oXnwgKWNtLWZhdC1jdXJzb3IoJHwgKS8udGVzdChlLmdldFdyYXBwZXJFbGVtZW50KCkuY2xhc3NOYW1lKSk7dmFyIGM9IXUmJm8+PTAmJnNbaS50ZXh0LmNoYXJBdChvKV18fHNbaS50ZXh0LmNoYXJBdCgrK28pXTtpZighYylyZXR1cm4gbnVsbDt2YXIgbD0iPiI9PWMuY2hhckF0KDEpPzE6LTE7aWYociYmci5zdHJpY3QmJmw+MCE9KG89PXQuY2gpKXJldHVybiBudWxsO3ZhciBwPWUuZ2V0VG9rZW5UeXBlQXQoYSh0LmxpbmUsbysxKSksZj1uKGUsYSh0LmxpbmUsbysobD4wPzE6MCkpLGwscHx8bnVsbCxyKTtyZXR1cm4gbnVsbD09Zj9udWxsOntmcm9tOmEodC5saW5lLG8pLHRvOmYmJmYucG9zLG1hdGNoOmYmJmYuY2g9PWMuY2hhckF0KDApLGZvcndhcmQ6bD4wfX1mdW5jdGlvbiBuKGUsdCxuLHIsaSl7Zm9yKHZhciBvPWkmJmkubWF4U2NhbkxpbmVMZW5ndGh8fDFlNCx1PWkmJmkubWF4U2NhbkxpbmVzfHwxZTMsYz1bXSxsPWkmJmkuYnJhY2tldFJlZ2V4P2kuYnJhY2tldFJlZ2V4Oi9bKCl7fVtcXV0vLHA9bj4wP01hdGgubWluKHQubGluZSt1LGUubGFzdExpbmUoKSsxKTpNYXRoLm1heChlLmZpcnN0TGluZSgpLTEsdC5saW5lLXUpLGY9dC5saW5lO2YhPXA7Zis9bil7dmFyIGQ9ZS5nZXRMaW5lKGYpO2lmKGQpe3ZhciBoPW4+MD8wOmQubGVuZ3RoLTEsbT1uPjA/ZC5sZW5ndGg6LTE7aWYoIShkLmxlbmd0aD5vKSlmb3IoZj09dC5saW5lJiYoaD10LmNoLShuPDA/MTowKSk7aCE9bTtoKz1uKXt2YXIgZz1kLmNoYXJBdChoKTtpZihsLnRlc3QoZykmJih2b2lkIDA9PT1yfHxlLmdldFRva2VuVHlwZUF0KGEoZixoKzEpKT09cikpe3ZhciB5PXNbZ107aWYoIj4iPT15LmNoYXJBdCgxKT09bj4wKWMucHVzaChnKTtlbHNle2lmKCFjLmxlbmd0aClyZXR1cm57cG9zOmEoZixoKSxjaDpnfTtjLnBvcCgpfX19fX1yZXR1cm4gZi1uIT0obj4wP2UubGFzdExpbmUoKTplLmZpcnN0TGluZSgpKSYmbnVsbH1mdW5jdGlvbiByKGUsbixyKXtmb3IodmFyIGk9ZS5zdGF0ZS5tYXRjaEJyYWNrZXRzLm1heEhpZ2hsaWdodExpbmVMZW5ndGh8fDFlMyxzPVtdLHU9ZS5saXN0U2VsZWN0aW9ucygpLGM9MDtjPHUubGVuZ3RoO2MrKyl7dmFyIGw9dVtjXS5lbXB0eSgpJiZ0KGUsdVtjXS5oZWFkLHIpO2lmKGwmJmUuZ2V0TGluZShsLmZyb20ubGluZSkubGVuZ3RoPD1pKXt2YXIgcD1sLm1hdGNoPyJDb2RlTWlycm9yLW1hdGNoaW5nYnJhY2tldCI6IkNvZGVNaXJyb3Itbm9ubWF0Y2hpbmdicmFja2V0IjtzLnB1c2goZS5tYXJrVGV4dChsLmZyb20sYShsLmZyb20ubGluZSxsLmZyb20uY2grMSkse2NsYXNzTmFtZTpwfSkpLGwudG8mJmUuZ2V0TGluZShsLnRvLmxpbmUpLmxlbmd0aDw9aSYmcy5wdXNoKGUubWFya1RleHQobC50byxhKGwudG8ubGluZSxsLnRvLmNoKzEpLHtjbGFzc05hbWU6cH0pKX19aWYocy5sZW5ndGgpe28mJmUuc3RhdGUuZm9jdXNlZCYmZS5mb2N1cygpO3ZhciBmPWZ1bmN0aW9uKCl7ZS5vcGVyYXRpb24oZnVuY3Rpb24oKXtmb3IodmFyIGU9MDtlPHMubGVuZ3RoO2UrKylzW2VdLmNsZWFyKCl9KX07aWYoIW4pcmV0dXJuIGY7c2V0VGltZW91dChmLDgwMCl9fWZ1bmN0aW9uIGkoZSl7ZS5vcGVyYXRpb24oZnVuY3Rpb24oKXtlLnN0YXRlLm1hdGNoQnJhY2tldHMuY3VycmVudGx5SGlnaGxpZ2h0ZWQmJihlLnN0YXRlLm1hdGNoQnJhY2tldHMuY3VycmVudGx5SGlnaGxpZ2h0ZWQoKSxlLnN0YXRlLm1hdGNoQnJhY2tldHMuY3VycmVudGx5SGlnaGxpZ2h0ZWQ9bnVsbCksZS5zdGF0ZS5tYXRjaEJyYWNrZXRzLmN1cnJlbnRseUhpZ2hsaWdodGVkPXIoZSwhMSxlLnN0YXRlLm1hdGNoQnJhY2tldHMpfSl9dmFyIG89L01TSUUgXGQvLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCkmJihudWxsPT1kb2N1bWVudC5kb2N1bWVudE1vZGV8fGRvY3VtZW50LmRvY3VtZW50TW9kZTw4KSxhPWUuUG9zLHM9eyIoIjoiKT4iLCIpIjoiKDwiLCJbIjoiXT4iLCJdIjoiWzwiLCJ7IjoifT4iLCJ9IjoiezwifTtlLmRlZmluZU9wdGlvbigibWF0Y2hCcmFja2V0cyIsITEsZnVuY3Rpb24odCxuLHIpe3ImJnIhPWUuSW5pdCYmKHQub2ZmKCJjdXJzb3JBY3Rpdml0eSIsaSksdC5zdGF0ZS5tYXRjaEJyYWNrZXRzJiZ0LnN0YXRlLm1hdGNoQnJhY2tldHMuY3VycmVudGx5SGlnaGxpZ2h0ZWQmJih0LnN0YXRlLm1hdGNoQnJhY2tldHMuY3VycmVudGx5SGlnaGxpZ2h0ZWQoKSx0LnN0YXRlLm1hdGNoQnJhY2tldHMuY3VycmVudGx5SGlnaGxpZ2h0ZWQ9bnVsbCkpLG4mJih0LnN0YXRlLm1hdGNoQnJhY2tldHM9Im9iamVjdCI9PXR5cGVvZiBuP246e30sdC5vbigiY3Vyc29yQWN0aXZpdHkiLGkpKX0pLGUuZGVmaW5lRXh0ZW5zaW9uKCJtYXRjaEJyYWNrZXRzIixmdW5jdGlvbigpe3IodGhpcywhMCl9KSxlLmRlZmluZUV4dGVuc2lvbigiZmluZE1hdGNoaW5nQnJhY2tldCIsZnVuY3Rpb24oZSxuLHIpe3JldHVybihyfHwiYm9vbGVhbiI9PXR5cGVvZiBuKSYmKHI/KHIuc3RyaWN0PW4sbj1yKTpuPW4/e3N0cmljdDohMH06bnVsbCksdCh0aGlzLGUsbil9KSxlLmRlZmluZUV4dGVuc2lvbigic2NhbkZvckJyYWNrZXQiLGZ1bmN0aW9uKGUsdCxyLGkpe3JldHVybiBuKHRoaXMsZSx0LHIsaSl9KX0pfSxmdW5jdGlvbihlLHQsbil7IWZ1bmN0aW9uKGUpe2UobigyKSl9KGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0IjtlLnJlZ2lzdGVySGVscGVyKCJmb2xkIiwiYnJhY2UiLGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcihyKXtmb3IodmFyIHM9bi5jaCx1PTA7Oyl7dmFyIGM9czw9MD8tMTphLmxhc3RJbmRleE9mKHIscy0xKTtpZigtMSE9Yyl7aWYoMT09dSYmYzxuLmNoKWJyZWFrO2lmKGk9dC5nZXRUb2tlblR5cGVBdChlLlBvcyhvLGMrMSkpLCEvXihjb21tZW50fHN0cmluZykvLnRlc3QoaSkpcmV0dXJuIGMrMTtzPWMtMX1lbHNle2lmKDE9PXUpYnJlYWs7dT0xLHM9YS5sZW5ndGh9fX12YXIgaSxvPW4ubGluZSxhPXQuZ2V0TGluZShvKSxzPSJ7Iix1PSJ9IixjPXIoInsiKTtpZihudWxsPT1jJiYocz0iWyIsdT0iXSIsYz1yKCJbIikpLG51bGwhPWMpe3ZhciBsLHAsZj0xLGQ9dC5sYXN0TGluZSgpO2U6Zm9yKHZhciBoPW87aDw9ZDsrK2gpZm9yKHZhciBtPXQuZ2V0TGluZShoKSxnPWg9PW8/YzowOzspe3ZhciB5PW0uaW5kZXhPZihzLGcpLHY9bS5pbmRleE9mKHUsZyk7aWYoeTwwJiYoeT1tLmxlbmd0aCksdjwwJiYodj1tLmxlbmd0aCksKGc9TWF0aC5taW4oeSx2KSk9PW0ubGVuZ3RoKWJyZWFrO2lmKHQuZ2V0VG9rZW5UeXBlQXQoZS5Qb3MoaCxnKzEpKT09aSlpZihnPT15KSsrZjtlbHNlIGlmKCEtLWYpe2w9aCxwPWc7YnJlYWsgZX0rK2d9aWYobnVsbCE9bCYmKG8hPWx8fHAhPWMpKXJldHVybntmcm9tOmUuUG9zKG8sYyksdG86ZS5Qb3MobCxwKX19fSksZS5yZWdpc3RlckhlbHBlcigiZm9sZCIsImltcG9ydCIsZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKG4pe2lmKG48dC5maXJzdExpbmUoKXx8bj50Lmxhc3RMaW5lKCkpcmV0dXJuIG51bGw7dmFyIHI9dC5nZXRUb2tlbkF0KGUuUG9zKG4sMSkpO2lmKC9cUy8udGVzdChyLnN0cmluZyl8fChyPXQuZ2V0VG9rZW5BdChlLlBvcyhuLHIuZW5kKzEpKSksImtleXdvcmQiIT1yLnR5cGV8fCJpbXBvcnQiIT1yLnN0cmluZylyZXR1cm4gbnVsbDtmb3IodmFyIGk9bixvPU1hdGgubWluKHQubGFzdExpbmUoKSxuKzEwKTtpPD1vOysraSl7dmFyIGE9dC5nZXRMaW5lKGkpLHM9YS5pbmRleE9mKCI7Iik7aWYoLTEhPXMpcmV0dXJue3N0YXJ0Q2g6ci5lbmQsZW5kOmUuUG9zKGkscyl9fX12YXIgaSxvPW4ubGluZSxhPXIobyk7aWYoIWF8fHIoby0xKXx8KGk9cihvLTIpKSYmaS5lbmQubGluZT09by0xKXJldHVybiBudWxsO2Zvcih2YXIgcz1hLmVuZDs7KXt2YXIgdT1yKHMubGluZSsxKTtpZihudWxsPT11KWJyZWFrO3M9dS5lbmR9cmV0dXJue2Zyb206dC5jbGlwUG9zKGUuUG9zKG8sYS5zdGFydENoKzEpKSx0bzpzfX0pLGUucmVnaXN0ZXJIZWxwZXIoImZvbGQiLCJpbmNsdWRlIixmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIobil7aWYobjx0LmZpcnN0TGluZSgpfHxuPnQubGFzdExpbmUoKSlyZXR1cm4gbnVsbDt2YXIgcj10LmdldFRva2VuQXQoZS5Qb3MobiwxKSk7cmV0dXJuL1xTLy50ZXN0KHIuc3RyaW5nKXx8KHI9dC5nZXRUb2tlbkF0KGUuUG9zKG4sci5lbmQrMSkpKSwibWV0YSI9PXIudHlwZSYmIiNpbmNsdWRlIj09ci5zdHJpbmcuc2xpY2UoMCw4KT9yLnN0YXJ0Kzg6dm9pZCAwfXZhciBpPW4ubGluZSxvPXIoaSk7aWYobnVsbD09b3x8bnVsbCE9cihpLTEpKXJldHVybiBudWxsO2Zvcih2YXIgYT1pOzspe2lmKG51bGw9PXIoYSsxKSlicmVhazsrK2F9cmV0dXJue2Zyb206ZS5Qb3MoaSxvKzEpLHRvOnQuY2xpcFBvcyhlLlBvcyhhKSl9fSl9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9big1OTYpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJDaGFyYWN0ZXJTdHJlYW0iLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiByKGkpLmRlZmF1bHR9fSk7dmFyIG89bigyNzUpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJMZXhSdWxlcyIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8uTGV4UnVsZXN9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlBhcnNlUnVsZXMiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLlBhcnNlUnVsZXN9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzSWdub3JlZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8uaXNJZ25vcmVkfX0pO3ZhciBhPW4oMjc2KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYnV0Tm90Iix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS5idXROb3R9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImxpc3QiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBhLmxpc3R9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIm9wdCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGEub3B0fX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS5wfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJ0Iix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS50fX0pO3ZhciBzPW4oNTk3KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwib25saW5lUGFyc2VyIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcihzKS5kZWZhdWx0fX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtFcnJvci5jYWxsKHRoaXMpLHRoaXMubmFtZT0iWUFNTEV4Y2VwdGlvbiIsdGhpcy5yZWFzb249ZSx0aGlzLm1hcms9dCx0aGlzLm1lc3NhZ2U9KHRoaXMucmVhc29ufHwiKHVua25vd24gcmVhc29uKSIpKyh0aGlzLm1hcms/IiAiK3RoaXMubWFyay50b1N0cmluZygpOiIiKSxFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLHRoaXMuY29uc3RydWN0b3IpOnRoaXMuc3RhY2s9KG5ldyBFcnJvcikuc3RhY2t8fCIifXIucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoRXJyb3IucHJvdG90eXBlKSxyLnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj1yLHIucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMubmFtZSsiOiAiO3JldHVybiB0Kz10aGlzLnJlYXNvbnx8Iih1bmtub3duIHJlYXNvbikiLCFlJiZ0aGlzLm1hcmsmJih0Kz0iICIrdGhpcy5tYXJrLnRvU3RyaW5nKCkpLHR9LGUuZXhwb3J0cz1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNTMpO2UuZXhwb3J0cz1uZXcgcih7aW5jbHVkZTpbbigzMDMpXSxpbXBsaWNpdDpbbig3MzMpLG4oNzM0KV0sZXhwbGljaXQ6W24oNzM1KSxuKDc0MCksbig3NDEpLG4oNzQyKV19KX0sZnVuY3Rpb24oZSx0LG4peyhmdW5jdGlvbihlLHIpe3ZhciBpOyhmdW5jdGlvbigpe2Z1bmN0aW9uIG8oZSx0LG4pe3N3aXRjaChuLmxlbmd0aCl7Y2FzZSAwOnJldHVybiBlLmNhbGwodCk7Y2FzZSAxOnJldHVybiBlLmNhbGwodCxuWzBdKTtjYXNlIDI6cmV0dXJuIGUuY2FsbCh0LG5bMF0sblsxXSk7Y2FzZSAzOnJldHVybiBlLmNhbGwodCxuWzBdLG5bMV0sblsyXSl9cmV0dXJuIGUuYXBwbHkodCxuKX1mdW5jdGlvbiBhKGUsdCxuLHIpe2Zvcih2YXIgaT0tMSxvPW51bGw9PWU/MDplLmxlbmd0aDsrK2k8bzspe3ZhciBhPWVbaV07dChyLGEsbihhKSxlKX1yZXR1cm4gcn1mdW5jdGlvbiBzKGUsdCl7Zm9yKHZhciBuPS0xLHI9bnVsbD09ZT8wOmUubGVuZ3RoOysrbjxyJiYhMSE9PXQoZVtuXSxuLGUpOyk7cmV0dXJuIGV9ZnVuY3Rpb24gdShlLHQpe2Zvcih2YXIgbj1udWxsPT1lPzA6ZS5sZW5ndGg7bi0tJiYhMSE9PXQoZVtuXSxuLGUpOyk7cmV0dXJuIGV9ZnVuY3Rpb24gYyhlLHQpe2Zvcih2YXIgbj0tMSxyPW51bGw9PWU/MDplLmxlbmd0aDsrK248cjspaWYoIXQoZVtuXSxuLGUpKXJldHVybiExO3JldHVybiEwfWZ1bmN0aW9uIGwoZSx0KXtmb3IodmFyIG49LTEscj1udWxsPT1lPzA6ZS5sZW5ndGgsaT0wLG89W107KytuPHI7KXt2YXIgYT1lW25dO3QoYSxuLGUpJiYob1tpKytdPWEpfXJldHVybiBvfWZ1bmN0aW9uIHAoZSx0KXtyZXR1cm4hIShudWxsPT1lPzA6ZS5sZW5ndGgpJiZFKGUsdCwwKT4tMX1mdW5jdGlvbiBmKGUsdCxuKXtmb3IodmFyIHI9LTEsaT1udWxsPT1lPzA6ZS5sZW5ndGg7KytyPGk7KWlmKG4odCxlW3JdKSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiBkKGUsdCl7Zm9yKHZhciBuPS0xLHI9bnVsbD09ZT8wOmUubGVuZ3RoLGk9QXJyYXkocik7KytuPHI7KWlbbl09dChlW25dLG4sZSk7cmV0dXJuIGl9ZnVuY3Rpb24gaChlLHQpe2Zvcih2YXIgbj0tMSxyPXQubGVuZ3RoLGk9ZS5sZW5ndGg7KytuPHI7KWVbaStuXT10W25dO3JldHVybiBlfWZ1bmN0aW9uIG0oZSx0LG4scil7dmFyIGk9LTEsbz1udWxsPT1lPzA6ZS5sZW5ndGg7Zm9yKHImJm8mJihuPWVbKytpXSk7KytpPG87KW49dChuLGVbaV0saSxlKTtyZXR1cm4gbn1mdW5jdGlvbiBnKGUsdCxuLHIpe3ZhciBpPW51bGw9PWU/MDplLmxlbmd0aDtmb3IociYmaSYmKG49ZVstLWldKTtpLS07KW49dChuLGVbaV0saSxlKTtyZXR1cm4gbn1mdW5jdGlvbiB5KGUsdCl7Zm9yKHZhciBuPS0xLHI9bnVsbD09ZT8wOmUubGVuZ3RoOysrbjxyOylpZih0KGVbbl0sbixlKSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiB2KGUpe3JldHVybiBlLnNwbGl0KCIiKX1mdW5jdGlvbiBiKGUpe3JldHVybiBlLm1hdGNoKGp0KXx8W119ZnVuY3Rpb24geChlLHQsbil7dmFyIHI7cmV0dXJuIG4oZSxmdW5jdGlvbihlLG4saSl7aWYodChlLG4saSkpcmV0dXJuIHI9biwhMX0pLHJ9ZnVuY3Rpb24gQyhlLHQsbixyKXtmb3IodmFyIGk9ZS5sZW5ndGgsbz1uKyhyPzE6LTEpO3I/by0tOisrbzxpOylpZih0KGVbb10sbyxlKSlyZXR1cm4gbztyZXR1cm4tMX1mdW5jdGlvbiBFKGUsdCxuKXtyZXR1cm4gdD09PXQ/SyhlLHQsbik6QyhlLHcsbil9ZnVuY3Rpb24gRChlLHQsbixyKXtmb3IodmFyIGk9bi0xLG89ZS5sZW5ndGg7KytpPG87KWlmKHIoZVtpXSx0KSlyZXR1cm4gaTtyZXR1cm4tMX1mdW5jdGlvbiB3KGUpe3JldHVybiBlIT09ZX1mdW5jdGlvbiBTKGUsdCl7dmFyIG49bnVsbD09ZT8wOmUubGVuZ3RoO3JldHVybiBuP08oZSx0KS9uOkllfWZ1bmN0aW9uIGsoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBudWxsPT10P25lOnRbZV19fWZ1bmN0aW9uIEEoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBudWxsPT1lP25lOmVbdF19fWZ1bmN0aW9uIF8oZSx0LG4scixpKXtyZXR1cm4gaShlLGZ1bmN0aW9uKGUsaSxvKXtuPXI/KHI9ITEsZSk6dChuLGUsaSxvKX0pLG59ZnVuY3Rpb24gVChlLHQpe3ZhciBuPWUubGVuZ3RoO2ZvcihlLnNvcnQodCk7bi0tOyllW25dPWVbbl0udmFsdWU7cmV0dXJuIGV9ZnVuY3Rpb24gTyhlLHQpe2Zvcih2YXIgbixyPS0xLGk9ZS5sZW5ndGg7KytyPGk7KXt2YXIgbz10KGVbcl0pO28hPT1uZSYmKG49bj09PW5lP286bitvKX1yZXR1cm4gbn1mdW5jdGlvbiBGKGUsdCl7Zm9yKHZhciBuPS0xLHI9QXJyYXkoZSk7KytuPGU7KXJbbl09dChuKTtyZXR1cm4gcn1mdW5jdGlvbiBOKGUsdCl7cmV0dXJuIGQodCxmdW5jdGlvbih0KXtyZXR1cm5bdCxlW3RdXX0pfWZ1bmN0aW9uIEkoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBlKHQpfX1mdW5jdGlvbiBMKGUsdCl7cmV0dXJuIGQodCxmdW5jdGlvbih0KXtyZXR1cm4gZVt0XX0pfWZ1bmN0aW9uIFAoZSx0KXtyZXR1cm4gZS5oYXModCl9ZnVuY3Rpb24gTShlLHQpe2Zvcih2YXIgbj0tMSxyPWUubGVuZ3RoOysrbjxyJiZFKHQsZVtuXSwwKT4tMTspO3JldHVybiBufWZ1bmN0aW9uIGooZSx0KXtmb3IodmFyIG49ZS5sZW5ndGg7bi0tJiZFKHQsZVtuXSwwKT4tMTspO3JldHVybiBufWZ1bmN0aW9uIFIoZSx0KXtmb3IodmFyIG49ZS5sZW5ndGgscj0wO24tLTspZVtuXT09PXQmJisrcjtyZXR1cm4gcn1mdW5jdGlvbiBCKGUpe3JldHVybiJcXCIrU25bZV19ZnVuY3Rpb24gJChlLHQpe3JldHVybiBudWxsPT1lP25lOmVbdF19ZnVuY3Rpb24gVShlKXtyZXR1cm4gZ24udGVzdChlKX1mdW5jdGlvbiB6KGUpe3JldHVybiB5bi50ZXN0KGUpfWZ1bmN0aW9uIEcoZSl7Zm9yKHZhciB0LG49W107ISh0PWUubmV4dCgpKS5kb25lOyluLnB1c2godC52YWx1ZSk7cmV0dXJuIG59ZnVuY3Rpb24gVihlKXt2YXIgdD0tMSxuPUFycmF5KGUuc2l6ZSk7cmV0dXJuIGUuZm9yRWFjaChmdW5jdGlvbihlLHIpe25bKyt0XT1bcixlXX0pLG59ZnVuY3Rpb24gcShlLHQpe3JldHVybiBmdW5jdGlvbihuKXtyZXR1cm4gZSh0KG4pKX19ZnVuY3Rpb24gSChlLHQpe2Zvcih2YXIgbj0tMSxyPWUubGVuZ3RoLGk9MCxvPVtdOysrbjxyOyl7dmFyIGE9ZVtuXTthIT09dCYmYSE9PXVlfHwoZVtuXT11ZSxvW2krK109bil9cmV0dXJuIG99ZnVuY3Rpb24gVyhlKXt2YXIgdD0tMSxuPUFycmF5KGUuc2l6ZSk7cmV0dXJuIGUuZm9yRWFjaChmdW5jdGlvbihlKXtuWysrdF09ZX0pLG59ZnVuY3Rpb24gUShlKXt2YXIgdD0tMSxuPUFycmF5KGUuc2l6ZSk7cmV0dXJuIGUuZm9yRWFjaChmdW5jdGlvbihlKXtuWysrdF09W2UsZV19KSxufWZ1bmN0aW9uIEsoZSx0LG4pe2Zvcih2YXIgcj1uLTEsaT1lLmxlbmd0aDsrK3I8aTspaWYoZVtyXT09PXQpcmV0dXJuIHI7cmV0dXJuLTF9ZnVuY3Rpb24gSihlLHQsbil7Zm9yKHZhciByPW4rMTtyLS07KWlmKGVbcl09PT10KXJldHVybiByO3JldHVybiByfWZ1bmN0aW9uIFkoZSl7cmV0dXJuIFUoZSk/WihlKTp6bihlKX1mdW5jdGlvbiBYKGUpe3JldHVybiBVKGUpP2VlKGUpOnYoZSl9ZnVuY3Rpb24gWihlKXtmb3IodmFyIHQ9aG4ubGFzdEluZGV4PTA7aG4udGVzdChlKTspKyt0O3JldHVybiB0fWZ1bmN0aW9uIGVlKGUpe3JldHVybiBlLm1hdGNoKGhuKXx8W119ZnVuY3Rpb24gdGUoZSl7cmV0dXJuIGUubWF0Y2gobW4pfHxbXX12YXIgbmUscmU9MjAwLGllPSJVbnN1cHBvcnRlZCBjb3JlLWpzIHVzZS4gVHJ5IGh0dHBzOi8vbnBtcy5pby9zZWFyY2g/cT1wb255ZmlsbC4iLG9lPSJFeHBlY3RlZCBhIGZ1bmN0aW9uIixhZT0iX19sb2Rhc2hfaGFzaF91bmRlZmluZWRfXyIsc2U9NTAwLHVlPSJfX2xvZGFzaF9wbGFjZWhvbGRlcl9fIixjZT0xLGxlPTIscGU9NCxmZT0xLGRlPTIsaGU9MSxtZT0yLGdlPTQseWU9OCx2ZT0xNixiZT0zMix4ZT02NCxDZT0xMjgsRWU9MjU2LERlPTUxMix3ZT0zMCxTZT0iLi4uIixrZT04MDAsQWU9MTYsX2U9MSxUZT0yLE9lPTEvMCxGZT05MDA3MTk5MjU0NzQwOTkxLE5lPTEuNzk3NjkzMTM0ODYyMzE1N2UzMDgsSWU9TmFOLExlPTQyOTQ5NjcyOTUsUGU9TGUtMSxNZT1MZT4+PjEsamU9W1siYXJ5IixDZV0sWyJiaW5kIixoZV0sWyJiaW5kS2V5IixtZV0sWyJjdXJyeSIseWVdLFsiY3VycnlSaWdodCIsdmVdLFsiZmxpcCIsRGVdLFsicGFydGlhbCIsYmVdLFsicGFydGlhbFJpZ2h0Iix4ZV0sWyJyZWFyZyIsRWVdXSxSZT0iW29iamVjdCBBcmd1bWVudHNdIixCZT0iW29iamVjdCBBcnJheV0iLCRlPSJbb2JqZWN0IEFzeW5jRnVuY3Rpb25dIixVZT0iW29iamVjdCBCb29sZWFuXSIsemU9IltvYmplY3QgRGF0ZV0iLEdlPSJbb2JqZWN0IERPTUV4Y2VwdGlvbl0iLFZlPSJbb2JqZWN0IEVycm9yXSIscWU9IltvYmplY3QgRnVuY3Rpb25dIixIZT0iW29iamVjdCBHZW5lcmF0b3JGdW5jdGlvbl0iLFdlPSJbb2JqZWN0IE1hcF0iLFFlPSJbb2JqZWN0IE51bWJlcl0iLEtlPSJbb2JqZWN0IE51bGxdIixKZT0iW29iamVjdCBPYmplY3RdIixZZT0iW29iamVjdCBQcm94eV0iLFhlPSJbb2JqZWN0IFJlZ0V4cF0iLFplPSJbb2JqZWN0IFNldF0iLGV0PSJbb2JqZWN0IFN0cmluZ10iLHR0PSJbb2JqZWN0IFN5bWJvbF0iLG50PSJbb2JqZWN0IFVuZGVmaW5lZF0iLHJ0PSJbb2JqZWN0IFdlYWtNYXBdIixpdD0iW29iamVjdCBXZWFrU2V0XSIsb3Q9IltvYmplY3QgQXJyYXlCdWZmZXJdIixhdD0iW29iamVjdCBEYXRhVmlld10iLHN0PSJbb2JqZWN0IEZsb2F0MzJBcnJheV0iLHV0PSJbb2JqZWN0IEZsb2F0NjRBcnJheV0iLGN0PSJbb2JqZWN0IEludDhBcnJheV0iLGx0PSJbb2JqZWN0IEludDE2QXJyYXldIixwdD0iW29iamVjdCBJbnQzMkFycmF5XSIsZnQ9IltvYmplY3QgVWludDhBcnJheV0iLGR0PSJbb2JqZWN0IFVpbnQ4Q2xhbXBlZEFycmF5XSIsaHQ9IltvYmplY3QgVWludDE2QXJyYXldIixtdD0iW29iamVjdCBVaW50MzJBcnJheV0iLGd0PS9cYl9fcCBcKz0gJyc7L2cseXQ9L1xiKF9fcCBcKz0pICcnIFwrL2csdnQ9LyhfX2VcKC4qP1wpfFxiX190XCkpIFwrXG4nJzsvZyxidD0vJig/OmFtcHxsdHxndHxxdW90fCMzOSk7L2cseHQ9L1smPD4iJ10vZyxDdD1SZWdFeHAoYnQuc291cmNlKSxFdD1SZWdFeHAoeHQuc291cmNlKSxEdD0vPCUtKFtcc1xTXSs/KSU+L2csd3Q9LzwlKFtcc1xTXSs/KSU+L2csU3Q9LzwlPShbXHNcU10rPyklPi9nLGt0PS9cLnxcWyg/OlteW1xdXSp8KFsiJ10pKD86KD8hXDEpW15cXF18XFwuKSo/XDEpXF0vLEF0PS9eXHcqJC8sX3Q9L1teLltcXV0rfFxbKD86KC0/XGQrKD86XC5cZCspPyl8KFsiJ10pKCg/Oig/IVwyKVteXFxdfFxcLikqPylcMilcXXwoPz0oPzpcLnxcW1xdKSg/OlwufFxbXF18JCkpL2csVHQ9L1tcXF4kLiorPygpW1xde318XS9nLE90PVJlZ0V4cChUdC5zb3VyY2UpLEZ0PS9eXHMrfFxzKyQvZyxOdD0vXlxzKy8sSXQ9L1xzKyQvLEx0PS9ceyg/OlxuXC9cKiBcW3dyYXBwZWQgd2l0aCAuK1xdIFwqXC8pP1xuPy8sUHQ9L1x7XG5cL1wqIFxbd3JhcHBlZCB3aXRoICguKylcXSBcKi8sTXQ9Lyw/ICYgLyxqdD0vW15ceDAwLVx4MmZceDNhLVx4NDBceDViLVx4NjBceDdiLVx4N2ZdKy9nLFJ0PS9cXChcXCk/L2csQnQ9L1wkXHsoW15cXH1dKig/OlxcLlteXFx9XSopKilcfS9nLCR0PS9cdyokLyxVdD0vXlstK10weFswLTlhLWZdKyQvaSx6dD0vXjBiWzAxXSskL2ksR3Q9L15cW29iamVjdCAuKz9Db25zdHJ1Y3RvclxdJC8sVnQ9L14wb1swLTddKyQvaSxxdD0vXig/OjB8WzEtOV1cZCopJC8sSHQ9L1tceGMwLVx4ZDZceGQ4LVx4ZjZceGY4LVx4ZmZcdTAxMDAtXHUwMTdmXS9nLFd0PS8oJF4pLyxRdD0vWydcblxyXHUyMDI4XHUyMDI5XFxdL2csS3Q9IlxcdTAzMDAtXFx1MDM2ZlxcdWZlMjAtXFx1ZmUyZlxcdTIwZDAtXFx1MjBmZiIsSnQ9IlxceGFjXFx4YjFcXHhkN1xceGY3XFx4MDAtXFx4MmZcXHgzYS1cXHg0MFxceDViLVxceDYwXFx4N2ItXFx4YmZcXHUyMDAwLVxcdTIwNmYgXFx0XFx4MGJcXGZcXHhhMFxcdWZlZmZcXG5cXHJcXHUyMDI4XFx1MjAyOVxcdTE2ODBcXHUxODBlXFx1MjAwMFxcdTIwMDFcXHUyMDAyXFx1MjAwM1xcdTIwMDRcXHUyMDA1XFx1MjAwNlxcdTIwMDdcXHUyMDA4XFx1MjAwOVxcdTIwMGFcXHUyMDJmXFx1MjA1ZlxcdTMwMDAiLFl0PSJbIitKdCsiXSIsWHQ9IlsiK0t0KyJdIixadD0iW2EtelxceGRmLVxceGY2XFx4ZjgtXFx4ZmZdIixlbj0iW15cXHVkODAwLVxcdWRmZmYiK0p0KyJcXGQrXFx1MjcwMC1cXHUyN2JmYS16XFx4ZGYtXFx4ZjZcXHhmOC1cXHhmZkEtWlxceGMwLVxceGQ2XFx4ZDgtXFx4ZGVdIix0bj0iXFx1ZDgzY1tcXHVkZmZiLVxcdWRmZmZdIixubj0iKD86XFx1ZDgzY1tcXHVkZGU2LVxcdWRkZmZdKXsyfSIscm49IltcXHVkODAwLVxcdWRiZmZdW1xcdWRjMDAtXFx1ZGZmZl0iLG9uPSJbQS1aXFx4YzAtXFx4ZDZcXHhkOC1cXHhkZV0iLGFuPSIoPzoiK1p0KyJ8IitlbisiKSIsc249Iig/OltcXHUwMzAwLVxcdTAzNmZcXHVmZTIwLVxcdWZlMmZcXHUyMGQwLVxcdTIwZmZdfFxcdWQ4M2NbXFx1ZGZmYi1cXHVkZmZmXSk/Iix1bj0iKD86XFx1MjAwZCg/OiIrWyJbXlxcdWQ4MDAtXFx1ZGZmZl0iLG5uLHJuXS5qb2luKCJ8IikrIilbXFx1ZmUwZVxcdWZlMGZdPyIrc24rIikqIixjbj0iW1xcdWZlMGVcXHVmZTBmXT8iK3NuK3VuLGxuPSIoPzoiK1siW1xcdTI3MDAtXFx1MjdiZl0iLG5uLHJuXS5qb2luKCJ8IikrIikiK2NuLHBuPSIoPzoiK1siW15cXHVkODAwLVxcdWRmZmZdIitYdCsiPyIsWHQsbm4scm4sIltcXHVkODAwLVxcdWRmZmZdIl0uam9pbigifCIpKyIpIixmbj1SZWdFeHAoIlsnXHUyMDE5XSIsImciKSxkbj1SZWdFeHAoWHQsImciKSxobj1SZWdFeHAodG4rIig/PSIrdG4rIil8IitwbitjbiwiZyIpLG1uPVJlZ0V4cChbb24rIj8iK1p0KyIrKD86WydcdTIwMTldKD86ZHxsbHxtfHJlfHN8dHx2ZSkpPyg/PSIrW1l0LG9uLCIkIl0uam9pbigifCIpKyIpIiwiKD86W0EtWlxceGMwLVxceGQ2XFx4ZDgtXFx4ZGVdfFteXFx1ZDgwMC1cXHVkZmZmXFx4YWNcXHhiMVxceGQ3XFx4ZjdcXHgwMC1cXHgyZlxceDNhLVxceDQwXFx4NWItXFx4NjBcXHg3Yi1cXHhiZlxcdTIwMDAtXFx1MjA2ZiBcXHRcXHgwYlxcZlxceGEwXFx1ZmVmZlxcblxcclxcdTIwMjhcXHUyMDI5XFx1MTY4MFxcdTE4MGVcXHUyMDAwXFx1MjAwMVxcdTIwMDJcXHUyMDAzXFx1MjAwNFxcdTIwMDVcXHUyMDA2XFx1MjAwN1xcdTIwMDhcXHUyMDA5XFx1MjAwYVxcdTIwMmZcXHUyMDVmXFx1MzAwMFxcZCtcXHUyNzAwLVxcdTI3YmZhLXpcXHhkZi1cXHhmNlxceGY4LVxceGZmQS1aXFx4YzAtXFx4ZDZcXHhkOC1cXHhkZV0pKyg/OlsnXHUyMDE5XSg/OkR8TEx8TXxSRXxTfFR8VkUpKT8oPz0iK1tZdCxvbithbiwiJCJdLmpvaW4oInwiKSsiKSIsb24rIj8iK2FuKyIrKD86WydcdTIwMTldKD86ZHxsbHxtfHJlfHN8dHx2ZSkpPyIsb24rIisoPzpbJ1x1MjAxOV0oPzpEfExMfE18UkV8U3xUfFZFKSk/IiwiXFxkKig/OjFTVHwyTkR8M1JEfCg/IVsxMjNdKVxcZFRIKSg/PVxcYnxbYS16X10pIiwiXFxkKig/OjFzdHwybmR8M3JkfCg/IVsxMjNdKVxcZHRoKSg/PVxcYnxbQS1aX10pIiwiXFxkKyIsbG5dLmpvaW4oInwiKSwiZyIpLGduPVJlZ0V4cCgiW1xcdTIwMGRcXHVkODAwLVxcdWRmZmYiK0t0KyJcXHVmZTBlXFx1ZmUwZl0iKSx5bj0vW2Etel1bQS1aXXxbQS1aXXsyfVthLXpdfFswLTldW2EtekEtWl18W2EtekEtWl1bMC05XXxbXmEtekEtWjAtOSBdLyx2bj1bIkFycmF5IiwiQnVmZmVyIiwiRGF0YVZpZXciLCJEYXRlIiwiRXJyb3IiLCJGbG9hdDMyQXJyYXkiLCJGbG9hdDY0QXJyYXkiLCJGdW5jdGlvbiIsIkludDhBcnJheSIsIkludDE2QXJyYXkiLCJJbnQzMkFycmF5IiwiTWFwIiwiTWF0aCIsIk9iamVjdCIsIlByb21pc2UiLCJSZWdFeHAiLCJTZXQiLCJTdHJpbmciLCJTeW1ib2wiLCJUeXBlRXJyb3IiLCJVaW50OEFycmF5IiwiVWludDhDbGFtcGVkQXJyYXkiLCJVaW50MTZBcnJheSIsIlVpbnQzMkFycmF5IiwiV2Vha01hcCIsIl8iLCJjbGVhclRpbWVvdXQiLCJpc0Zpbml0ZSIsInBhcnNlSW50Iiwic2V0VGltZW91dCJdLGJuPS0xLHhuPXt9O3huW3N0XT14blt1dF09eG5bY3RdPXhuW2x0XT14bltwdF09eG5bZnRdPXhuW2R0XT14bltodF09eG5bbXRdPSEwLHhuW1JlXT14bltCZV09eG5bb3RdPXhuW1VlXT14blthdF09eG5bemVdPXhuW1ZlXT14bltxZV09eG5bV2VdPXhuW1FlXT14bltKZV09eG5bWGVdPXhuW1plXT14bltldF09eG5bcnRdPSExO3ZhciBDbj17fTtDbltSZV09Q25bQmVdPUNuW290XT1DblthdF09Q25bVWVdPUNuW3plXT1DbltzdF09Q25bdXRdPUNuW2N0XT1DbltsdF09Q25bcHRdPUNuW1dlXT1DbltRZV09Q25bSmVdPUNuW1hlXT1DbltaZV09Q25bZXRdPUNuW3R0XT1DbltmdF09Q25bZHRdPUNuW2h0XT1DblttdF09ITAsQ25bVmVdPUNuW3FlXT1DbltydF09ITE7dmFyIEVuPXsiXHhjMCI6IkEiLCJceGMxIjoiQSIsIlx4YzIiOiJBIiwiXHhjMyI6IkEiLCJceGM0IjoiQSIsIlx4YzUiOiJBIiwiXHhlMCI6ImEiLCJceGUxIjoiYSIsIlx4ZTIiOiJhIiwiXHhlMyI6ImEiLCJceGU0IjoiYSIsIlx4ZTUiOiJhIiwiXHhjNyI6IkMiLCJceGU3IjoiYyIsIlx4ZDAiOiJEIiwiXHhmMCI6ImQiLCJceGM4IjoiRSIsIlx4YzkiOiJFIiwiXHhjYSI6IkUiLCJceGNiIjoiRSIsIlx4ZTgiOiJlIiwiXHhlOSI6ImUiLCJceGVhIjoiZSIsIlx4ZWIiOiJlIiwiXHhjYyI6IkkiLCJceGNkIjoiSSIsIlx4Y2UiOiJJIiwiXHhjZiI6IkkiLCJceGVjIjoiaSIsIlx4ZWQiOiJpIiwiXHhlZSI6ImkiLCJceGVmIjoiaSIsIlx4ZDEiOiJOIiwiXHhmMSI6Im4iLCJceGQyIjoiTyIsIlx4ZDMiOiJPIiwiXHhkNCI6Ik8iLCJceGQ1IjoiTyIsIlx4ZDYiOiJPIiwiXHhkOCI6Ik8iLCJceGYyIjoibyIsIlx4ZjMiOiJvIiwiXHhmNCI6Im8iLCJceGY1IjoibyIsIlx4ZjYiOiJvIiwiXHhmOCI6Im8iLCJceGQ5IjoiVSIsIlx4ZGEiOiJVIiwiXHhkYiI6IlUiLCJceGRjIjoiVSIsIlx4ZjkiOiJ1IiwiXHhmYSI6InUiLCJceGZiIjoidSIsIlx4ZmMiOiJ1IiwiXHhkZCI6IlkiLCJceGZkIjoieSIsIlx4ZmYiOiJ5IiwiXHhjNiI6IkFlIiwiXHhlNiI6ImFlIiwiXHhkZSI6IlRoIiwiXHhmZSI6InRoIiwiXHhkZiI6InNzIiwiXHUwMTAwIjoiQSIsIlx1MDEwMiI6IkEiLCJcdTAxMDQiOiJBIiwiXHUwMTAxIjoiYSIsIlx1MDEwMyI6ImEiLCJcdTAxMDUiOiJhIiwiXHUwMTA2IjoiQyIsIlx1MDEwOCI6IkMiLCJcdTAxMGEiOiJDIiwiXHUwMTBjIjoiQyIsIlx1MDEwNyI6ImMiLCJcdTAxMDkiOiJjIiwiXHUwMTBiIjoiYyIsIlx1MDEwZCI6ImMiLCJcdTAxMGUiOiJEIiwiXHUwMTEwIjoiRCIsIlx1MDEwZiI6ImQiLCJcdTAxMTEiOiJkIiwiXHUwMTEyIjoiRSIsIlx1MDExNCI6IkUiLCJcdTAxMTYiOiJFIiwiXHUwMTE4IjoiRSIsIlx1MDExYSI6IkUiLCJcdTAxMTMiOiJlIiwiXHUwMTE1IjoiZSIsIlx1MDExNyI6ImUiLCJcdTAxMTkiOiJlIiwiXHUwMTFiIjoiZSIsIlx1MDExYyI6IkciLCJcdTAxMWUiOiJHIiwiXHUwMTIwIjoiRyIsIlx1MDEyMiI6IkciLCJcdTAxMWQiOiJnIiwiXHUwMTFmIjoiZyIsIlx1MDEyMSI6ImciLCJcdTAxMjMiOiJnIiwiXHUwMTI0IjoiSCIsIlx1MDEyNiI6IkgiLCJcdTAxMjUiOiJoIiwiXHUwMTI3IjoiaCIsIlx1MDEyOCI6IkkiLCJcdTAxMmEiOiJJIiwiXHUwMTJjIjoiSSIsIlx1MDEyZSI6IkkiLCJcdTAxMzAiOiJJIiwiXHUwMTI5IjoiaSIsIlx1MDEyYiI6ImkiLCJcdTAxMmQiOiJpIiwiXHUwMTJmIjoiaSIsIlx1MDEzMSI6ImkiLCJcdTAxMzQiOiJKIiwiXHUwMTM1IjoiaiIsIlx1MDEzNiI6IksiLCJcdTAxMzciOiJrIiwiXHUwMTM4IjoiayIsIlx1MDEzOSI6IkwiLCJcdTAxM2IiOiJMIiwiXHUwMTNkIjoiTCIsIlx1MDEzZiI6IkwiLCJcdTAxNDEiOiJMIiwiXHUwMTNhIjoibCIsIlx1MDEzYyI6ImwiLCJcdTAxM2UiOiJsIiwiXHUwMTQwIjoibCIsIlx1MDE0MiI6ImwiLCJcdTAxNDMiOiJOIiwiXHUwMTQ1IjoiTiIsIlx1MDE0NyI6Ik4iLCJcdTAxNGEiOiJOIiwiXHUwMTQ0IjoibiIsIlx1MDE0NiI6Im4iLCJcdTAxNDgiOiJuIiwiXHUwMTRiIjoibiIsIlx1MDE0YyI6Ik8iLCJcdTAxNGUiOiJPIiwiXHUwMTUwIjoiTyIsIlx1MDE0ZCI6Im8iLCJcdTAxNGYiOiJvIiwiXHUwMTUxIjoibyIsIlx1MDE1NCI6IlIiLCJcdTAxNTYiOiJSIiwiXHUwMTU4IjoiUiIsIlx1MDE1NSI6InIiLCJcdTAxNTciOiJyIiwiXHUwMTU5IjoiciIsIlx1MDE1YSI6IlMiLCJcdTAxNWMiOiJTIiwiXHUwMTVlIjoiUyIsIlx1MDE2MCI6IlMiLCJcdTAxNWIiOiJzIiwiXHUwMTVkIjoicyIsIlx1MDE1ZiI6InMiLCJcdTAxNjEiOiJzIiwiXHUwMTYyIjoiVCIsIlx1MDE2NCI6IlQiLCJcdTAxNjYiOiJUIiwiXHUwMTYzIjoidCIsIlx1MDE2NSI6InQiLCJcdTAxNjciOiJ0IiwiXHUwMTY4IjoiVSIsIlx1MDE2YSI6IlUiLCJcdTAxNmMiOiJVIiwiXHUwMTZlIjoiVSIsIlx1MDE3MCI6IlUiLCJcdTAxNzIiOiJVIiwiXHUwMTY5IjoidSIsIlx1MDE2YiI6InUiLCJcdTAxNmQiOiJ1IiwiXHUwMTZmIjoidSIsIlx1MDE3MSI6InUiLCJcdTAxNzMiOiJ1IiwiXHUwMTc0IjoiVyIsIlx1MDE3NSI6InciLCJcdTAxNzYiOiJZIiwiXHUwMTc3IjoieSIsIlx1MDE3OCI6IlkiLCJcdTAxNzkiOiJaIiwiXHUwMTdiIjoiWiIsIlx1MDE3ZCI6IloiLCJcdTAxN2EiOiJ6IiwiXHUwMTdjIjoieiIsIlx1MDE3ZSI6InoiLCJcdTAxMzIiOiJJSiIsIlx1MDEzMyI6ImlqIiwiXHUwMTUyIjoiT2UiLCJcdTAxNTMiOiJvZSIsIlx1MDE0OSI6IiduIiwiXHUwMTdmIjoicyJ9LERuPXsiJiI6IiZhbXA7IiwiPCI6IiZsdDsiLCI+IjoiJmd0OyIsJyInOiImcXVvdDsiLCInIjoiJiMzOTsifSx3bj17IiZhbXA7IjoiJiIsIiZsdDsiOiI8IiwiJmd0OyI6Ij4iLCImcXVvdDsiOiciJywiJiMzOTsiOiInIn0sU249eyJcXCI6IlxcIiwiJyI6IiciLCJcbiI6Im4iLCJcciI6InIiLCJcdTIwMjgiOiJ1MjAyOCIsIlx1MjAyOSI6InUyMDI5In0sa249cGFyc2VGbG9hdCxBbj1wYXJzZUludCxfbj0ib2JqZWN0Ij09dHlwZW9mIGUmJmUmJmUuT2JqZWN0PT09T2JqZWN0JiZlLFRuPSJvYmplY3QiPT10eXBlb2Ygc2VsZiYmc2VsZiYmc2VsZi5PYmplY3Q9PT1PYmplY3QmJnNlbGYsT249X258fFRufHxGdW5jdGlvbigicmV0dXJuIHRoaXMiKSgpLEZuPSJvYmplY3QiPT10eXBlb2YgdCYmdCYmIXQubm9kZVR5cGUmJnQsTm49Rm4mJiJvYmplY3QiPT10eXBlb2YgciYmciYmIXIubm9kZVR5cGUmJnIsSW49Tm4mJk5uLmV4cG9ydHM9PT1GbixMbj1JbiYmX24ucHJvY2VzcyxQbj1mdW5jdGlvbigpe3RyeXt2YXIgZT1ObiYmTm4ucmVxdWlyZSYmTm4ucmVxdWlyZSgidXRpbCIpLnR5cGVzO3JldHVybiBlfHxMbiYmTG4uYmluZGluZyYmTG4uYmluZGluZygidXRpbCIpfWNhdGNoKGUpe319KCksTW49UG4mJlBuLmlzQXJyYXlCdWZmZXIsam49UG4mJlBuLmlzRGF0ZSxSbj1QbiYmUG4uaXNNYXAsQm49UG4mJlBuLmlzUmVnRXhwLCRuPVBuJiZQbi5pc1NldCxVbj1QbiYmUG4uaXNUeXBlZEFycmF5LHpuPWsoImxlbmd0aCIpLEduPUEoRW4pLFZuPUEoRG4pLHFuPUEod24pLEhuPWZ1bmN0aW9uIGUodCl7ZnVuY3Rpb24gbihlKXtpZih0dShlKSYmIWRmKGUpJiYhKGUgaW5zdGFuY2VvZiB2KSl7aWYoZSBpbnN0YW5jZW9mIGkpcmV0dXJuIGU7aWYoZmwuY2FsbChlLCJfX3dyYXBwZWRfXyIpKXJldHVybiBYbyhlKX1yZXR1cm4gbmV3IGkoZSl9ZnVuY3Rpb24gcigpe31mdW5jdGlvbiBpKGUsdCl7dGhpcy5fX3dyYXBwZWRfXz1lLHRoaXMuX19hY3Rpb25zX189W10sdGhpcy5fX2NoYWluX189ISF0LHRoaXMuX19pbmRleF9fPTAsdGhpcy5fX3ZhbHVlc19fPW5lfWZ1bmN0aW9uIHYoZSl7dGhpcy5fX3dyYXBwZWRfXz1lLHRoaXMuX19hY3Rpb25zX189W10sdGhpcy5fX2Rpcl9fPTEsdGhpcy5fX2ZpbHRlcmVkX189ITEsdGhpcy5fX2l0ZXJhdGVlc19fPVtdLHRoaXMuX190YWtlQ291bnRfXz1MZSx0aGlzLl9fdmlld3NfXz1bXX1mdW5jdGlvbiBBKCl7dmFyIGU9bmV3IHYodGhpcy5fX3dyYXBwZWRfXyk7cmV0dXJuIGUuX19hY3Rpb25zX189TmkodGhpcy5fX2FjdGlvbnNfXyksZS5fX2Rpcl9fPXRoaXMuX19kaXJfXyxlLl9fZmlsdGVyZWRfXz10aGlzLl9fZmlsdGVyZWRfXyxlLl9faXRlcmF0ZWVzX189TmkodGhpcy5fX2l0ZXJhdGVlc19fKSxlLl9fdGFrZUNvdW50X189dGhpcy5fX3Rha2VDb3VudF9fLGUuX192aWV3c19fPU5pKHRoaXMuX192aWV3c19fKSxlfWZ1bmN0aW9uIEsoKXtpZih0aGlzLl9fZmlsdGVyZWRfXyl7dmFyIGU9bmV3IHYodGhpcyk7ZS5fX2Rpcl9fPS0xLGUuX19maWx0ZXJlZF9fPSEwfWVsc2UgZT10aGlzLmNsb25lKCksZS5fX2Rpcl9fKj0tMTtyZXR1cm4gZX1mdW5jdGlvbiBaKCl7dmFyIGU9dGhpcy5fX3dyYXBwZWRfXy52YWx1ZSgpLHQ9dGhpcy5fX2Rpcl9fLG49ZGYoZSkscj10PDAsaT1uP2UubGVuZ3RoOjAsbz1FbygwLGksdGhpcy5fX3ZpZXdzX18pLGE9by5zdGFydCxzPW8uZW5kLHU9cy1hLGM9cj9zOmEtMSxsPXRoaXMuX19pdGVyYXRlZXNfXyxwPWwubGVuZ3RoLGY9MCxkPXpsKHUsdGhpcy5fX3Rha2VDb3VudF9fKTtpZighbnx8IXImJmk9PXUmJmQ9PXUpcmV0dXJuIG1pKGUsdGhpcy5fX2FjdGlvbnNfXyk7dmFyIGg9W107ZTpmb3IoO3UtLSYmZjxkOyl7Yys9dDtmb3IodmFyIG09LTEsZz1lW2NdOysrbTxwOyl7dmFyIHk9bFttXSx2PXkuaXRlcmF0ZWUsYj15LnR5cGUseD12KGcpO2lmKGI9PVRlKWc9eDtlbHNlIGlmKCF4KXtpZihiPT1fZSljb250aW51ZSBlO2JyZWFrIGV9fWhbZisrXT1nfXJldHVybiBofWZ1bmN0aW9uIGVlKGUpe3ZhciB0PS0xLG49bnVsbD09ZT8wOmUubGVuZ3RoO2Zvcih0aGlzLmNsZWFyKCk7Kyt0PG47KXt2YXIgcj1lW3RdO3RoaXMuc2V0KHJbMF0sclsxXSl9fWZ1bmN0aW9uIGp0KCl7dGhpcy5fX2RhdGFfXz1YbD9YbChudWxsKTp7fSx0aGlzLnNpemU9MH1mdW5jdGlvbiBLdChlKXt2YXIgdD10aGlzLmhhcyhlKSYmZGVsZXRlIHRoaXMuX19kYXRhX19bZV07cmV0dXJuIHRoaXMuc2l6ZS09dD8xOjAsdH1mdW5jdGlvbiBKdChlKXt2YXIgdD10aGlzLl9fZGF0YV9fO2lmKFhsKXt2YXIgbj10W2VdO3JldHVybiBuPT09YWU/bmU6bn1yZXR1cm4gZmwuY2FsbCh0LGUpP3RbZV06bmV9ZnVuY3Rpb24gWXQoZSl7dmFyIHQ9dGhpcy5fX2RhdGFfXztyZXR1cm4gWGw/dFtlXSE9PW5lOmZsLmNhbGwodCxlKX1mdW5jdGlvbiBYdChlLHQpe3ZhciBuPXRoaXMuX19kYXRhX187cmV0dXJuIHRoaXMuc2l6ZSs9dGhpcy5oYXMoZSk/MDoxLG5bZV09WGwmJnQ9PT1uZT9hZTp0LHRoaXN9ZnVuY3Rpb24gWnQoZSl7dmFyIHQ9LTEsbj1udWxsPT1lPzA6ZS5sZW5ndGg7Zm9yKHRoaXMuY2xlYXIoKTsrK3Q8bjspe3ZhciByPWVbdF07dGhpcy5zZXQoclswXSxyWzFdKX19ZnVuY3Rpb24gZW4oKXt0aGlzLl9fZGF0YV9fPVtdLHRoaXMuc2l6ZT0wfWZ1bmN0aW9uIHRuKGUpe3ZhciB0PXRoaXMuX19kYXRhX18sbj1Xbih0LGUpO3JldHVybiEobjwwKSYmKG49PXQubGVuZ3RoLTE/dC5wb3AoKTprbC5jYWxsKHQsbiwxKSwtLXRoaXMuc2l6ZSwhMCl9ZnVuY3Rpb24gbm4oZSl7dmFyIHQ9dGhpcy5fX2RhdGFfXyxuPVduKHQsZSk7cmV0dXJuIG48MD9uZTp0W25dWzFdfWZ1bmN0aW9uIHJuKGUpe3JldHVybiBXbih0aGlzLl9fZGF0YV9fLGUpPi0xfWZ1bmN0aW9uIG9uKGUsdCl7dmFyIG49dGhpcy5fX2RhdGFfXyxyPVduKG4sZSk7cmV0dXJuIHI8MD8oKyt0aGlzLnNpemUsbi5wdXNoKFtlLHRdKSk6bltyXVsxXT10LHRoaXN9ZnVuY3Rpb24gYW4oZSl7dmFyIHQ9LTEsbj1udWxsPT1lPzA6ZS5sZW5ndGg7Zm9yKHRoaXMuY2xlYXIoKTsrK3Q8bjspe3ZhciByPWVbdF07dGhpcy5zZXQoclswXSxyWzFdKX19ZnVuY3Rpb24gc24oKXt0aGlzLnNpemU9MCx0aGlzLl9fZGF0YV9fPXtoYXNoOm5ldyBlZSxtYXA6bmV3KFFsfHxadCksc3RyaW5nOm5ldyBlZX19ZnVuY3Rpb24gdW4oZSl7dmFyIHQ9dm8odGhpcyxlKS5kZWxldGUoZSk7cmV0dXJuIHRoaXMuc2l6ZS09dD8xOjAsdH1mdW5jdGlvbiBjbihlKXtyZXR1cm4gdm8odGhpcyxlKS5nZXQoZSl9ZnVuY3Rpb24gbG4oZSl7cmV0dXJuIHZvKHRoaXMsZSkuaGFzKGUpfWZ1bmN0aW9uIHBuKGUsdCl7dmFyIG49dm8odGhpcyxlKSxyPW4uc2l6ZTtyZXR1cm4gbi5zZXQoZSx0KSx0aGlzLnNpemUrPW4uc2l6ZT09cj8wOjEsdGhpc31mdW5jdGlvbiBobihlKXt2YXIgdD0tMSxuPW51bGw9PWU/MDplLmxlbmd0aDtmb3IodGhpcy5fX2RhdGFfXz1uZXcgYW47Kyt0PG47KXRoaXMuYWRkKGVbdF0pfWZ1bmN0aW9uIG1uKGUpe3JldHVybiB0aGlzLl9fZGF0YV9fLnNldChlLGFlKSx0aGlzfWZ1bmN0aW9uIGduKGUpe3JldHVybiB0aGlzLl9fZGF0YV9fLmhhcyhlKX1mdW5jdGlvbiB5bihlKXt2YXIgdD10aGlzLl9fZGF0YV9fPW5ldyBadChlKTt0aGlzLnNpemU9dC5zaXplfWZ1bmN0aW9uIEVuKCl7dGhpcy5fX2RhdGFfXz1uZXcgWnQsdGhpcy5zaXplPTB9ZnVuY3Rpb24gRG4oZSl7dmFyIHQ9dGhpcy5fX2RhdGFfXyxuPXQuZGVsZXRlKGUpO3JldHVybiB0aGlzLnNpemU9dC5zaXplLG59ZnVuY3Rpb24gd24oZSl7cmV0dXJuIHRoaXMuX19kYXRhX18uZ2V0KGUpfWZ1bmN0aW9uIFNuKGUpe3JldHVybiB0aGlzLl9fZGF0YV9fLmhhcyhlKX1mdW5jdGlvbiBfbihlLHQpe3ZhciBuPXRoaXMuX19kYXRhX187aWYobiBpbnN0YW5jZW9mIFp0KXt2YXIgcj1uLl9fZGF0YV9fO2lmKCFRbHx8ci5sZW5ndGg8cmUtMSlyZXR1cm4gci5wdXNoKFtlLHRdKSx0aGlzLnNpemU9KytuLnNpemUsdGhpcztuPXRoaXMuX19kYXRhX189bmV3IGFuKHIpfXJldHVybiBuLnNldChlLHQpLHRoaXMuc2l6ZT1uLnNpemUsdGhpc31mdW5jdGlvbiBUbihlLHQpe3ZhciBuPWRmKGUpLHI9IW4mJmZmKGUpLGk9IW4mJiFyJiZtZihlKSxvPSFuJiYhciYmIWkmJnhmKGUpLGE9bnx8cnx8aXx8byxzPWE/RihlLmxlbmd0aCxvbCk6W10sdT1zLmxlbmd0aDtmb3IodmFyIGMgaW4gZSkhdCYmIWZsLmNhbGwoZSxjKXx8YSYmKCJsZW5ndGgiPT1jfHxpJiYoIm9mZnNldCI9PWN8fCJwYXJlbnQiPT1jKXx8byYmKCJidWZmZXIiPT1jfHwiYnl0ZUxlbmd0aCI9PWN8fCJieXRlT2Zmc2V0Ij09Yyl8fE9vKGMsdSkpfHxzLnB1c2goYyk7cmV0dXJuIHN9ZnVuY3Rpb24gRm4oZSl7dmFyIHQ9ZS5sZW5ndGg7cmV0dXJuIHQ/ZVtKcigwLHQtMSldOm5lfWZ1bmN0aW9uIE5uKGUsdCl7cmV0dXJuIFFvKE5pKGUpLFpuKHQsMCxlLmxlbmd0aCkpfWZ1bmN0aW9uIExuKGUpe3JldHVybiBRbyhOaShlKSl9ZnVuY3Rpb24gUG4oZSx0LG4peyhuPT09bmV8fFVzKGVbdF0sbikpJiYobiE9PW5lfHx0IGluIGUpfHxZbihlLHQsbil9ZnVuY3Rpb24gem4oZSx0LG4pe3ZhciByPWVbdF07ZmwuY2FsbChlLHQpJiZVcyhyLG4pJiYobiE9PW5lfHx0IGluIGUpfHxZbihlLHQsbil9ZnVuY3Rpb24gV24oZSx0KXtmb3IodmFyIG49ZS5sZW5ndGg7bi0tOylpZihVcyhlW25dWzBdLHQpKXJldHVybiBuO3JldHVybi0xfWZ1bmN0aW9uIFFuKGUsdCxuLHIpe3JldHVybiBscChlLGZ1bmN0aW9uKGUsaSxvKXt0KHIsZSxuKGUpLG8pfSkscn1mdW5jdGlvbiBLbihlLHQpe3JldHVybiBlJiZJaSh0LE11KHQpLGUpfWZ1bmN0aW9uIEpuKGUsdCl7cmV0dXJuIGUmJklpKHQsanUodCksZSl9ZnVuY3Rpb24gWW4oZSx0LG4peyJfX3Byb3RvX18iPT10JiZPbD9PbChlLHQse2NvbmZpZ3VyYWJsZTohMCxlbnVtZXJhYmxlOiEwLHZhbHVlOm4sd3JpdGFibGU6ITB9KTplW3RdPW59ZnVuY3Rpb24gWG4oZSx0KXtmb3IodmFyIG49LTEscj10Lmxlbmd0aCxpPVhjKHIpLG89bnVsbD09ZTsrK248cjspaVtuXT1vP25lOkl1KGUsdFtuXSk7cmV0dXJuIGl9ZnVuY3Rpb24gWm4oZSx0LG4pe3JldHVybiBlPT09ZSYmKG4hPT1uZSYmKGU9ZTw9bj9lOm4pLHQhPT1uZSYmKGU9ZT49dD9lOnQpKSxlfWZ1bmN0aW9uIGVyKGUsdCxuLHIsaSxvKXt2YXIgYSx1PXQmY2UsYz10JmxlLGw9dCZwZTtpZihuJiYoYT1pP24oZSxyLGksbyk6bihlKSksYSE9PW5lKXJldHVybiBhO2lmKCFldShlKSlyZXR1cm4gZTt2YXIgcD1kZihlKTtpZihwKXtpZihhPVNvKGUpLCF1KXJldHVybiBOaShlLGEpfWVsc2V7dmFyIGY9RXAoZSksZD1mPT1xZXx8Zj09SGU7aWYobWYoZSkpcmV0dXJuIEVpKGUsdSk7aWYoZj09SmV8fGY9PVJlfHxkJiYhaSl7aWYoYT1jfHxkP3t9OmtvKGUpLCF1KXJldHVybiBjP1BpKGUsSm4oYSxlKSk6TGkoZSxLbihhLGUpKX1lbHNle2lmKCFDbltmXSlyZXR1cm4gaT9lOnt9O2E9QW8oZSxmLHUpfX1vfHwobz1uZXcgeW4pO3ZhciBoPW8uZ2V0KGUpO2lmKGgpcmV0dXJuIGg7aWYoby5zZXQoZSxhKSxiZihlKSlyZXR1cm4gZS5mb3JFYWNoKGZ1bmN0aW9uKHIpe2EuYWRkKGVyKHIsdCxuLHIsZSxvKSl9KSxhO2lmKHlmKGUpKXJldHVybiBlLmZvckVhY2goZnVuY3Rpb24ocixpKXthLnNldChpLGVyKHIsdCxuLGksZSxvKSl9KSxhO3ZhciBtPWw/Yz9obzpmbzpjP2p1Ok11LGc9cD9uZTptKGUpO3JldHVybiBzKGd8fGUsZnVuY3Rpb24ocixpKXtnJiYoaT1yLHI9ZVtpXSksem4oYSxpLGVyKHIsdCxuLGksZSxvKSl9KSxhfWZ1bmN0aW9uIHRyKGUpe3ZhciB0PU11KGUpO3JldHVybiBmdW5jdGlvbihuKXtyZXR1cm4gbnIobixlLHQpfX1mdW5jdGlvbiBucihlLHQsbil7dmFyIHI9bi5sZW5ndGg7aWYobnVsbD09ZSlyZXR1cm4hcjtmb3IoZT1ybChlKTtyLS07KXt2YXIgaT1uW3JdLG89dFtpXSxhPWVbaV07aWYoYT09PW5lJiYhKGkgaW4gZSl8fCFvKGEpKXJldHVybiExfXJldHVybiEwfWZ1bmN0aW9uIHJyKGUsdCxuKXtpZigiZnVuY3Rpb24iIT10eXBlb2YgZSl0aHJvdyBuZXcgYWwob2UpO3JldHVybiBTcChmdW5jdGlvbigpe2UuYXBwbHkobmUsbil9LHQpfWZ1bmN0aW9uIGlyKGUsdCxuLHIpe3ZhciBpPS0xLG89cCxhPSEwLHM9ZS5sZW5ndGgsdT1bXSxjPXQubGVuZ3RoO2lmKCFzKXJldHVybiB1O24mJih0PWQodCxJKG4pKSkscj8obz1mLGE9ITEpOnQubGVuZ3RoPj1yZSYmKG89UCxhPSExLHQ9bmV3IGhuKHQpKTtlOmZvcig7KytpPHM7KXt2YXIgbD1lW2ldLGg9bnVsbD09bj9sOm4obCk7aWYobD1yfHwwIT09bD9sOjAsYSYmaD09PWgpe2Zvcih2YXIgbT1jO20tLTspaWYodFttXT09PWgpY29udGludWUgZTt1LnB1c2gobCl9ZWxzZSBvKHQsaCxyKXx8dS5wdXNoKGwpfXJldHVybiB1fWZ1bmN0aW9uIG9yKGUsdCl7dmFyIG49ITA7cmV0dXJuIGxwKGUsZnVuY3Rpb24oZSxyLGkpe3JldHVybiBuPSEhdChlLHIsaSl9KSxufWZ1bmN0aW9uIGFyKGUsdCxuKXtmb3IodmFyIHI9LTEsaT1lLmxlbmd0aDsrK3I8aTspe3ZhciBvPWVbcl0sYT10KG8pO2lmKG51bGwhPWEmJihzPT09bmU/YT09PWEmJiFmdShhKTpuKGEscykpKXZhciBzPWEsdT1vfXJldHVybiB1fWZ1bmN0aW9uIHNyKGUsdCxuLHIpe3ZhciBpPWUubGVuZ3RoO2ZvcihuPXZ1KG4pLG48MCYmKG49LW4+aT8wOmkrbikscj1yPT09bmV8fHI+aT9pOnZ1KHIpLHI8MCYmKHIrPWkpLHI9bj5yPzA6YnUocik7bjxyOyllW24rK109dDtyZXR1cm4gZX1mdW5jdGlvbiB1cihlLHQpe3ZhciBuPVtdO3JldHVybiBscChlLGZ1bmN0aW9uKGUscixpKXt0KGUscixpKSYmbi5wdXNoKGUpfSksbn1mdW5jdGlvbiBjcihlLHQsbixyLGkpe3ZhciBvPS0xLGE9ZS5sZW5ndGg7Zm9yKG58fChuPVRvKSxpfHwoaT1bXSk7KytvPGE7KXt2YXIgcz1lW29dO3Q+MCYmbihzKT90PjE/Y3Iocyx0LTEsbixyLGkpOmgoaSxzKTpyfHwoaVtpLmxlbmd0aF09cyl9cmV0dXJuIGl9ZnVuY3Rpb24gbHIoZSx0KXtyZXR1cm4gZSYmZnAoZSx0LE11KX1mdW5jdGlvbiBwcihlLHQpe3JldHVybiBlJiZkcChlLHQsTXUpfWZ1bmN0aW9uIGZyKGUsdCl7cmV0dXJuIGwodCxmdW5jdGlvbih0KXtyZXR1cm4gWXMoZVt0XSl9KX1mdW5jdGlvbiBkcihlLHQpe3Q9eGkodCxlKTtmb3IodmFyIG49MCxyPXQubGVuZ3RoO251bGwhPWUmJm48cjspZT1lW0tvKHRbbisrXSldO3JldHVybiBuJiZuPT1yP2U6bmV9ZnVuY3Rpb24gaHIoZSx0LG4pe3ZhciByPXQoZSk7cmV0dXJuIGRmKGUpP3I6aChyLG4oZSkpfWZ1bmN0aW9uIG1yKGUpe3JldHVybiBudWxsPT1lP2U9PT1uZT9udDpLZTpUbCYmVGwgaW4gcmwoZSk/Q28oZSk6VW8oZSl9ZnVuY3Rpb24gZ3IoZSx0KXtyZXR1cm4gZT50fWZ1bmN0aW9uIHlyKGUsdCl7cmV0dXJuIG51bGwhPWUmJmZsLmNhbGwoZSx0KX1mdW5jdGlvbiB2cihlLHQpe3JldHVybiBudWxsIT1lJiZ0IGluIHJsKGUpfWZ1bmN0aW9uIGJyKGUsdCxuKXtyZXR1cm4gZT49emwodCxuKSYmZTxVbCh0LG4pfWZ1bmN0aW9uIHhyKGUsdCxuKXtmb3IodmFyIHI9bj9mOnAsaT1lWzBdLmxlbmd0aCxvPWUubGVuZ3RoLGE9byxzPVhjKG8pLHU9MS8wLGM9W107YS0tOyl7dmFyIGw9ZVthXTthJiZ0JiYobD1kKGwsSSh0KSkpLHU9emwobC5sZW5ndGgsdSksc1thXT0hbiYmKHR8fGk+PTEyMCYmbC5sZW5ndGg+PTEyMCk/bmV3IGhuKGEmJmwpOm5lfWw9ZVswXTt2YXIgaD0tMSxtPXNbMF07ZTpmb3IoOysraDxpJiZjLmxlbmd0aDx1Oyl7dmFyIGc9bFtoXSx5PXQ/dChnKTpnO2lmKGc9bnx8MCE9PWc/ZzowLCEobT9QKG0seSk6cihjLHksbikpKXtmb3IoYT1vOy0tYTspe3ZhciB2PXNbYV07aWYoISh2P1Aodix5KTpyKGVbYV0seSxuKSkpY29udGludWUgZX1tJiZtLnB1c2goeSksYy5wdXNoKGcpfX1yZXR1cm4gY31mdW5jdGlvbiBDcihlLHQsbixyKXtyZXR1cm4gbHIoZSxmdW5jdGlvbihlLGksbyl7dChyLG4oZSksaSxvKX0pLHJ9ZnVuY3Rpb24gRXIoZSx0LG4pe3Q9eGkodCxlKSxlPUdvKGUsdCk7dmFyIHI9bnVsbD09ZT9lOmVbS28oeWEodCkpXTtyZXR1cm4gbnVsbD09cj9uZTpvKHIsZSxuKX1mdW5jdGlvbiBEcihlKXtyZXR1cm4gdHUoZSkmJm1yKGUpPT1SZX1mdW5jdGlvbiB3cihlKXtyZXR1cm4gdHUoZSkmJm1yKGUpPT1vdH1mdW5jdGlvbiBTcihlKXtyZXR1cm4gdHUoZSkmJm1yKGUpPT16ZX1mdW5jdGlvbiBrcihlLHQsbixyLGkpe3JldHVybiBlPT09dHx8KG51bGw9PWV8fG51bGw9PXR8fCF0dShlKSYmIXR1KHQpP2UhPT1lJiZ0IT09dDpBcihlLHQsbixyLGtyLGkpKX1mdW5jdGlvbiBBcihlLHQsbixyLGksbyl7dmFyIGE9ZGYoZSkscz1kZih0KSx1PWE/QmU6RXAoZSksYz1zP0JlOkVwKHQpO3U9dT09UmU/SmU6dSxjPWM9PVJlP0plOmM7dmFyIGw9dT09SmUscD1jPT1KZSxmPXU9PWM7aWYoZiYmbWYoZSkpe2lmKCFtZih0KSlyZXR1cm4hMTthPSEwLGw9ITF9aWYoZiYmIWwpcmV0dXJuIG98fChvPW5ldyB5biksYXx8eGYoZSk/dW8oZSx0LG4scixpLG8pOmNvKGUsdCx1LG4scixpLG8pO2lmKCEobiZmZSkpe3ZhciBkPWwmJmZsLmNhbGwoZSwiX193cmFwcGVkX18iKSxoPXAmJmZsLmNhbGwodCwiX193cmFwcGVkX18iKTtpZihkfHxoKXt2YXIgbT1kP2UudmFsdWUoKTplLGc9aD90LnZhbHVlKCk6dDtyZXR1cm4gb3x8KG89bmV3IHluKSxpKG0sZyxuLHIsbyl9fXJldHVybiEhZiYmKG98fChvPW5ldyB5biksbG8oZSx0LG4scixpLG8pKX1mdW5jdGlvbiBfcihlKXtyZXR1cm4gdHUoZSkmJkVwKGUpPT1XZX1mdW5jdGlvbiBUcihlLHQsbixyKXt2YXIgaT1uLmxlbmd0aCxvPWksYT0hcjtpZihudWxsPT1lKXJldHVybiFvO2ZvcihlPXJsKGUpO2ktLTspe3ZhciBzPW5baV07aWYoYSYmc1syXT9zWzFdIT09ZVtzWzBdXTohKHNbMF1pbiBlKSlyZXR1cm4hMX1mb3IoOysraTxvOyl7cz1uW2ldO3ZhciB1PXNbMF0sYz1lW3VdLGw9c1sxXTtpZihhJiZzWzJdKXtpZihjPT09bmUmJiEodSBpbiBlKSlyZXR1cm4hMX1lbHNle3ZhciBwPW5ldyB5bjtpZihyKXZhciBmPXIoYyxsLHUsZSx0LHApO2lmKCEoZj09PW5lP2tyKGwsYyxmZXxkZSxyLHApOmYpKXJldHVybiExfX1yZXR1cm4hMH1mdW5jdGlvbiBPcihlKXtyZXR1cm4hKCFldShlKXx8UG8oZSkpJiYoWXMoZSk/dmw6R3QpLnRlc3QoSm8oZSkpfWZ1bmN0aW9uIEZyKGUpe3JldHVybiB0dShlKSYmbXIoZSk9PVhlfWZ1bmN0aW9uIE5yKGUpe3JldHVybiB0dShlKSYmRXAoZSk9PVplfWZ1bmN0aW9uIElyKGUpe3JldHVybiB0dShlKSYmWnMoZS5sZW5ndGgpJiYhIXhuW21yKGUpXX1mdW5jdGlvbiBMcihlKXtyZXR1cm4iZnVuY3Rpb24iPT10eXBlb2YgZT9lOm51bGw9PWU/a2M6Im9iamVjdCI9PXR5cGVvZiBlP2RmKGUpPyRyKGVbMF0sZVsxXSk6QnIoZSk6TGMoZSl9ZnVuY3Rpb24gUHIoZSl7aWYoIU1vKGUpKXJldHVybiAkbChlKTt2YXIgdD1bXTtmb3IodmFyIG4gaW4gcmwoZSkpZmwuY2FsbChlLG4pJiYiY29uc3RydWN0b3IiIT1uJiZ0LnB1c2gobik7cmV0dXJuIHR9ZnVuY3Rpb24gTXIoZSl7aWYoIWV1KGUpKXJldHVybiAkbyhlKTt2YXIgdD1NbyhlKSxuPVtdO2Zvcih2YXIgciBpbiBlKSgiY29uc3RydWN0b3IiIT1yfHwhdCYmZmwuY2FsbChlLHIpKSYmbi5wdXNoKHIpO3JldHVybiBufWZ1bmN0aW9uIGpyKGUsdCl7cmV0dXJuIGU8dH1mdW5jdGlvbiBScihlLHQpe3ZhciBuPS0xLHI9enMoZSk/WGMoZS5sZW5ndGgpOltdO3JldHVybiBscChlLGZ1bmN0aW9uKGUsaSxvKXtyWysrbl09dChlLGksbyl9KSxyfWZ1bmN0aW9uIEJyKGUpe3ZhciB0PWJvKGUpO3JldHVybiAxPT10Lmxlbmd0aCYmdFswXVsyXT9Sbyh0WzBdWzBdLHRbMF1bMV0pOmZ1bmN0aW9uKG4pe3JldHVybiBuPT09ZXx8VHIobixlLHQpfX1mdW5jdGlvbiAkcihlLHQpe3JldHVybiBObyhlKSYmam8odCk/Um8oS28oZSksdCk6ZnVuY3Rpb24obil7dmFyIHI9SXUobixlKTtyZXR1cm4gcj09PW5lJiZyPT09dD9QdShuLGUpOmtyKHQscixmZXxkZSl9fWZ1bmN0aW9uIFVyKGUsdCxuLHIsaSl7ZSE9PXQmJmZwKHQsZnVuY3Rpb24obyxhKXtpZihldShvKSlpfHwoaT1uZXcgeW4pLHpyKGUsdCxhLG4sVXIscixpKTtlbHNle3ZhciBzPXI/cihxbyhlLGEpLG8sYSsiIixlLHQsaSk6bmU7cz09PW5lJiYocz1vKSxQbihlLGEscyl9fSxqdSl9ZnVuY3Rpb24genIoZSx0LG4scixpLG8sYSl7dmFyIHM9cW8oZSxuKSx1PXFvKHQsbiksYz1hLmdldCh1KTtpZihjKXJldHVybiB2b2lkIFBuKGUsbixjKTt2YXIgbD1vP28ocyx1LG4rIiIsZSx0LGEpOm5lLHA9bD09PW5lO2lmKHApe3ZhciBmPWRmKHUpLGQ9IWYmJm1mKHUpLGg9IWYmJiFkJiZ4Zih1KTtsPXUsZnx8ZHx8aD9kZihzKT9sPXM6R3Mocyk/bD1OaShzKTpkPyhwPSExLGw9RWkodSwhMCkpOmg/KHA9ITEsbD1BaSh1LCEwKSk6bD1bXTpjdSh1KXx8ZmYodSk/KGw9cyxmZihzKT9sPUN1KHMpOmV1KHMpJiYhWXMocyl8fChsPWtvKHUpKSk6cD0hMX1wJiYoYS5zZXQodSxsKSxpKGwsdSxyLG8sYSksYS5kZWxldGUodSkpLFBuKGUsbixsKX1mdW5jdGlvbiBHcihlLHQpe3ZhciBuPWUubGVuZ3RoO2lmKG4pcmV0dXJuIHQrPXQ8MD9uOjAsT28odCxuKT9lW3RdOm5lfWZ1bmN0aW9uIFZyKGUsdCxuKXt2YXIgcj0tMTtyZXR1cm4gdD1kKHQubGVuZ3RoP3Q6W2tjXSxJKHlvKCkpKSxUKFJyKGUsZnVuY3Rpb24oZSxuLGkpe3JldHVybntjcml0ZXJpYTpkKHQsZnVuY3Rpb24odCl7cmV0dXJuIHQoZSl9KSxpbmRleDorK3IsdmFsdWU6ZX19KSxmdW5jdGlvbihlLHQpe3JldHVybiBUaShlLHQsbil9KX1mdW5jdGlvbiBxcihlLHQpe3JldHVybiBIcihlLHQsZnVuY3Rpb24odCxuKXtyZXR1cm4gUHUoZSxuKX0pfWZ1bmN0aW9uIEhyKGUsdCxuKXtmb3IodmFyIHI9LTEsaT10Lmxlbmd0aCxvPXt9OysrcjxpOyl7dmFyIGE9dFtyXSxzPWRyKGUsYSk7bihzLGEpJiZuaShvLHhpKGEsZSkscyl9cmV0dXJuIG99ZnVuY3Rpb24gV3IoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBkcih0LGUpfX1mdW5jdGlvbiBRcihlLHQsbixyKXt2YXIgaT1yP0Q6RSxvPS0xLGE9dC5sZW5ndGgscz1lO2ZvcihlPT09dCYmKHQ9TmkodCkpLG4mJihzPWQoZSxJKG4pKSk7KytvPGE7KWZvcih2YXIgdT0wLGM9dFtvXSxsPW4/bihjKTpjOyh1PWkocyxsLHUscikpPi0xOylzIT09ZSYma2wuY2FsbChzLHUsMSksa2wuY2FsbChlLHUsMSk7cmV0dXJuIGV9ZnVuY3Rpb24gS3IoZSx0KXtmb3IodmFyIG49ZT90Lmxlbmd0aDowLHI9bi0xO24tLTspe3ZhciBpPXRbbl07aWYobj09cnx8aSE9PW8pe3ZhciBvPWk7T28oaSk/a2wuY2FsbChlLGksMSk6ZmkoZSxpKX19cmV0dXJuIGV9ZnVuY3Rpb24gSnIoZSx0KXtyZXR1cm4gZStQbChxbCgpKih0LWUrMSkpfWZ1bmN0aW9uIFlyKGUsdCxuLHIpe2Zvcih2YXIgaT0tMSxvPVVsKExsKCh0LWUpLyhufHwxKSksMCksYT1YYyhvKTtvLS07KWFbcj9vOisraV09ZSxlKz1uO3JldHVybiBhfWZ1bmN0aW9uIFhyKGUsdCl7dmFyIG49IiI7aWYoIWV8fHQ8MXx8dD5GZSlyZXR1cm4gbjtkb3t0JTImJihuKz1lKSwodD1QbCh0LzIpKSYmKGUrPWUpfXdoaWxlKHQpO3JldHVybiBufWZ1bmN0aW9uIFpyKGUsdCl7cmV0dXJuIGtwKHpvKGUsdCxrYyksZSsiIil9ZnVuY3Rpb24gZWkoZSl7cmV0dXJuIEZuKEt1KGUpKX1mdW5jdGlvbiB0aShlLHQpe3ZhciBuPUt1KGUpO3JldHVybiBRbyhuLFpuKHQsMCxuLmxlbmd0aCkpfWZ1bmN0aW9uIG5pKGUsdCxuLHIpe2lmKCFldShlKSlyZXR1cm4gZTt0PXhpKHQsZSk7Zm9yKHZhciBpPS0xLG89dC5sZW5ndGgsYT1vLTEscz1lO251bGwhPXMmJisraTxvOyl7dmFyIHU9S28odFtpXSksYz1uO2lmKGkhPWEpe3ZhciBsPXNbdV07Yz1yP3IobCx1LHMpOm5lLGM9PT1uZSYmKGM9ZXUobCk/bDpPbyh0W2krMV0pP1tdOnt9KX16bihzLHUsYykscz1zW3VdfXJldHVybiBlfWZ1bmN0aW9uIHJpKGUpe3JldHVybiBRbyhLdShlKSl9ZnVuY3Rpb24gaWkoZSx0LG4pe3ZhciByPS0xLGk9ZS5sZW5ndGg7dDwwJiYodD0tdD5pPzA6aSt0KSxuPW4+aT9pOm4sbjwwJiYobis9aSksaT10Pm4/MDpuLXQ+Pj4wLHQ+Pj49MDtmb3IodmFyIG89WGMoaSk7KytyPGk7KW9bcl09ZVtyK3RdO3JldHVybiBvfWZ1bmN0aW9uIG9pKGUsdCl7dmFyIG47cmV0dXJuIGxwKGUsZnVuY3Rpb24oZSxyLGkpe3JldHVybiEobj10KGUscixpKSl9KSwhIW59ZnVuY3Rpb24gYWkoZSx0LG4pe3ZhciByPTAsaT1udWxsPT1lP3I6ZS5sZW5ndGg7aWYoIm51bWJlciI9PXR5cGVvZiB0JiZ0PT09dCYmaTw9TWUpe2Zvcig7cjxpOyl7dmFyIG89citpPj4+MSxhPWVbb107bnVsbCE9PWEmJiFmdShhKSYmKG4/YTw9dDphPHQpP3I9bysxOmk9b31yZXR1cm4gaX1yZXR1cm4gc2koZSx0LGtjLG4pfWZ1bmN0aW9uIHNpKGUsdCxuLHIpe3Q9bih0KTtmb3IodmFyIGk9MCxvPW51bGw9PWU/MDplLmxlbmd0aCxhPXQhPT10LHM9bnVsbD09PXQsdT1mdSh0KSxjPXQ9PT1uZTtpPG87KXt2YXIgbD1QbCgoaStvKS8yKSxwPW4oZVtsXSksZj1wIT09bmUsZD1udWxsPT09cCxoPXA9PT1wLG09ZnUocCk7aWYoYSl2YXIgZz1yfHxoO2Vsc2UgZz1jP2gmJihyfHxmKTpzP2gmJmYmJihyfHwhZCk6dT9oJiZmJiYhZCYmKHJ8fCFtKTohZCYmIW0mJihyP3A8PXQ6cDx0KTtnP2k9bCsxOm89bH1yZXR1cm4gemwobyxQZSl9ZnVuY3Rpb24gdWkoZSx0KXtmb3IodmFyIG49LTEscj1lLmxlbmd0aCxpPTAsbz1bXTsrK248cjspe3ZhciBhPWVbbl0scz10P3QoYSk6YTtpZighbnx8IVVzKHMsdSkpe3ZhciB1PXM7b1tpKytdPTA9PT1hPzA6YX19cmV0dXJuIG99ZnVuY3Rpb24gY2koZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlP2U6ZnUoZSk/SWU6K2V9ZnVuY3Rpb24gbGkoZSl7aWYoInN0cmluZyI9PXR5cGVvZiBlKXJldHVybiBlO2lmKGRmKGUpKXJldHVybiBkKGUsbGkpKyIiO2lmKGZ1KGUpKXJldHVybiB1cD91cC5jYWxsKGUpOiIiO3ZhciB0PWUrIiI7cmV0dXJuIjAiPT10JiYxL2U9PS1PZT8iLTAiOnR9ZnVuY3Rpb24gcGkoZSx0LG4pe3ZhciByPS0xLGk9cCxvPWUubGVuZ3RoLGE9ITAscz1bXSx1PXM7aWYobilhPSExLGk9ZjtlbHNlIGlmKG8+PXJlKXt2YXIgYz10P251bGw6dnAoZSk7aWYoYylyZXR1cm4gVyhjKTthPSExLGk9UCx1PW5ldyBobn1lbHNlIHU9dD9bXTpzO2U6Zm9yKDsrK3I8bzspe3ZhciBsPWVbcl0sZD10P3QobCk6bDtpZihsPW58fDAhPT1sP2w6MCxhJiZkPT09ZCl7Zm9yKHZhciBoPXUubGVuZ3RoO2gtLTspaWYodVtoXT09PWQpY29udGludWUgZTt0JiZ1LnB1c2goZCkscy5wdXNoKGwpfWVsc2UgaSh1LGQsbil8fCh1IT09cyYmdS5wdXNoKGQpLHMucHVzaChsKSl9cmV0dXJuIHN9ZnVuY3Rpb24gZmkoZSx0KXtyZXR1cm4gdD14aSh0LGUpLG51bGw9PShlPUdvKGUsdCkpfHxkZWxldGUgZVtLbyh5YSh0KSldfWZ1bmN0aW9uIGRpKGUsdCxuLHIpe3JldHVybiBuaShlLHQsbihkcihlLHQpKSxyKX1mdW5jdGlvbiBoaShlLHQsbixyKXtmb3IodmFyIGk9ZS5sZW5ndGgsbz1yP2k6LTE7KHI/by0tOisrbzxpKSYmdChlW29dLG8sZSk7KTtyZXR1cm4gbj9paShlLHI/MDpvLHI/bysxOmkpOmlpKGUscj9vKzE6MCxyP2k6byl9ZnVuY3Rpb24gbWkoZSx0KXt2YXIgbj1lO3JldHVybiBuIGluc3RhbmNlb2YgdiYmKG49bi52YWx1ZSgpKSxtKHQsZnVuY3Rpb24oZSx0KXtyZXR1cm4gdC5mdW5jLmFwcGx5KHQudGhpc0FyZyxoKFtlXSx0LmFyZ3MpKX0sbil9ZnVuY3Rpb24gZ2koZSx0LG4pe3ZhciByPWUubGVuZ3RoO2lmKHI8MilyZXR1cm4gcj9waShlWzBdKTpbXTtmb3IodmFyIGk9LTEsbz1YYyhyKTsrK2k8cjspZm9yKHZhciBhPWVbaV0scz0tMTsrK3M8cjspcyE9aSYmKG9baV09aXIob1tpXXx8YSxlW3NdLHQsbikpO3JldHVybiBwaShjcihvLDEpLHQsbil9ZnVuY3Rpb24geWkoZSx0LG4pe2Zvcih2YXIgcj0tMSxpPWUubGVuZ3RoLG89dC5sZW5ndGgsYT17fTsrK3I8aTspe3ZhciBzPXI8bz90W3JdOm5lO24oYSxlW3JdLHMpfXJldHVybiBhfWZ1bmN0aW9uIHZpKGUpe3JldHVybiBHcyhlKT9lOltdfWZ1bmN0aW9uIGJpKGUpe3JldHVybiJmdW5jdGlvbiI9PXR5cGVvZiBlP2U6a2N9ZnVuY3Rpb24geGkoZSx0KXtyZXR1cm4gZGYoZSk/ZTpObyhlLHQpP1tlXTpBcChEdShlKSl9ZnVuY3Rpb24gQ2koZSx0LG4pe3ZhciByPWUubGVuZ3RoO3JldHVybiBuPW49PT1uZT9yOm4sIXQmJm4+PXI/ZTppaShlLHQsbil9ZnVuY3Rpb24gRWkoZSx0KXtpZih0KXJldHVybiBlLnNsaWNlKCk7dmFyIG49ZS5sZW5ndGgscj1FbD9FbChuKTpuZXcgZS5jb25zdHJ1Y3RvcihuKTtyZXR1cm4gZS5jb3B5KHIpLHJ9ZnVuY3Rpb24gRGkoZSl7dmFyIHQ9bmV3IGUuY29uc3RydWN0b3IoZS5ieXRlTGVuZ3RoKTtyZXR1cm4gbmV3IENsKHQpLnNldChuZXcgQ2woZSkpLHR9ZnVuY3Rpb24gd2koZSx0KXt2YXIgbj10P0RpKGUuYnVmZmVyKTplLmJ1ZmZlcjtyZXR1cm4gbmV3IGUuY29uc3RydWN0b3IobixlLmJ5dGVPZmZzZXQsZS5ieXRlTGVuZ3RoKX1mdW5jdGlvbiBTaShlKXt2YXIgdD1uZXcgZS5jb25zdHJ1Y3RvcihlLnNvdXJjZSwkdC5leGVjKGUpKTtyZXR1cm4gdC5sYXN0SW5kZXg9ZS5sYXN0SW5kZXgsdH1mdW5jdGlvbiBraShlKXtyZXR1cm4gc3A/cmwoc3AuY2FsbChlKSk6e319ZnVuY3Rpb24gQWkoZSx0KXt2YXIgbj10P0RpKGUuYnVmZmVyKTplLmJ1ZmZlcjtyZXR1cm4gbmV3IGUuY29uc3RydWN0b3IobixlLmJ5dGVPZmZzZXQsZS5sZW5ndGgpfWZ1bmN0aW9uIF9pKGUsdCl7aWYoZSE9PXQpe3ZhciBuPWUhPT1uZSxyPW51bGw9PT1lLGk9ZT09PWUsbz1mdShlKSxhPXQhPT1uZSxzPW51bGw9PT10LHU9dD09PXQsYz1mdSh0KTtpZighcyYmIWMmJiFvJiZlPnR8fG8mJmEmJnUmJiFzJiYhY3x8ciYmYSYmdXx8IW4mJnV8fCFpKXJldHVybiAxO2lmKCFyJiYhbyYmIWMmJmU8dHx8YyYmbiYmaSYmIXImJiFvfHxzJiZuJiZpfHwhYSYmaXx8IXUpcmV0dXJuLTF9cmV0dXJuIDB9ZnVuY3Rpb24gVGkoZSx0LG4pe2Zvcih2YXIgcj0tMSxpPWUuY3JpdGVyaWEsbz10LmNyaXRlcmlhLGE9aS5sZW5ndGgscz1uLmxlbmd0aDsrK3I8YTspe3ZhciB1PV9pKGlbcl0sb1tyXSk7aWYodSl7aWYocj49cylyZXR1cm4gdTtyZXR1cm4gdSooImRlc2MiPT1uW3JdPy0xOjEpfX1yZXR1cm4gZS5pbmRleC10LmluZGV4fWZ1bmN0aW9uIE9pKGUsdCxuLHIpe2Zvcih2YXIgaT0tMSxvPWUubGVuZ3RoLGE9bi5sZW5ndGgscz0tMSx1PXQubGVuZ3RoLGM9VWwoby1hLDApLGw9WGModStjKSxwPSFyOysrczx1OylsW3NdPXRbc107Zm9yKDsrK2k8YTspKHB8fGk8bykmJihsW25baV1dPWVbaV0pO2Zvcig7Yy0tOylsW3MrK109ZVtpKytdO3JldHVybiBsfWZ1bmN0aW9uIEZpKGUsdCxuLHIpe2Zvcih2YXIgaT0tMSxvPWUubGVuZ3RoLGE9LTEscz1uLmxlbmd0aCx1PS0xLGM9dC5sZW5ndGgsbD1VbChvLXMsMCkscD1YYyhsK2MpLGY9IXI7KytpPGw7KXBbaV09ZVtpXTtmb3IodmFyIGQ9aTsrK3U8YzspcFtkK3VdPXRbdV07Zm9yKDsrK2E8czspKGZ8fGk8bykmJihwW2QrblthXV09ZVtpKytdKTtyZXR1cm4gcH1mdW5jdGlvbiBOaShlLHQpe3ZhciBuPS0xLHI9ZS5sZW5ndGg7Zm9yKHR8fCh0PVhjKHIpKTsrK248cjspdFtuXT1lW25dO3JldHVybiB0fWZ1bmN0aW9uIElpKGUsdCxuLHIpe3ZhciBpPSFuO258fChuPXt9KTtmb3IodmFyIG89LTEsYT10Lmxlbmd0aDsrK288YTspe3ZhciBzPXRbb10sdT1yP3IobltzXSxlW3NdLHMsbixlKTpuZTt1PT09bmUmJih1PWVbc10pLGk/WW4obixzLHUpOnpuKG4scyx1KX1yZXR1cm4gbn1mdW5jdGlvbiBMaShlLHQpe3JldHVybiBJaShlLHhwKGUpLHQpfWZ1bmN0aW9uIFBpKGUsdCl7cmV0dXJuIElpKGUsQ3AoZSksdCl9ZnVuY3Rpb24gTWkoZSx0KXtyZXR1cm4gZnVuY3Rpb24obixyKXt2YXIgaT1kZihuKT9hOlFuLG89dD90KCk6e307cmV0dXJuIGkobixlLHlvKHIsMiksbyl9fWZ1bmN0aW9uIGppKGUpe3JldHVybiBacihmdW5jdGlvbih0LG4pe3ZhciByPS0xLGk9bi5sZW5ndGgsbz1pPjE/bltpLTFdOm5lLGE9aT4yP25bMl06bmU7Zm9yKG89ZS5sZW5ndGg+MyYmImZ1bmN0aW9uIj09dHlwZW9mIG8/KGktLSxvKTpuZSxhJiZGbyhuWzBdLG5bMV0sYSkmJihvPWk8Mz9uZTpvLGk9MSksdD1ybCh0KTsrK3I8aTspe3ZhciBzPW5bcl07cyYmZSh0LHMscixvKX1yZXR1cm4gdH0pfWZ1bmN0aW9uIFJpKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKG4scil7aWYobnVsbD09bilyZXR1cm4gbjtpZighenMobikpcmV0dXJuIGUobixyKTtmb3IodmFyIGk9bi5sZW5ndGgsbz10P2k6LTEsYT1ybChuKTsodD9vLS06KytvPGkpJiYhMSE9PXIoYVtvXSxvLGEpOyk7cmV0dXJuIG59fWZ1bmN0aW9uIEJpKGUpe3JldHVybiBmdW5jdGlvbih0LG4scil7Zm9yKHZhciBpPS0xLG89cmwodCksYT1yKHQpLHM9YS5sZW5ndGg7cy0tOyl7dmFyIHU9YVtlP3M6KytpXTtpZighMT09PW4ob1t1XSx1LG8pKWJyZWFrfXJldHVybiB0fX1mdW5jdGlvbiAkaShlLHQsbil7ZnVuY3Rpb24gcigpe3JldHVybih0aGlzJiZ0aGlzIT09T24mJnRoaXMgaW5zdGFuY2VvZiByP286ZSkuYXBwbHkoaT9uOnRoaXMsYXJndW1lbnRzKX12YXIgaT10JmhlLG89R2koZSk7cmV0dXJuIHJ9ZnVuY3Rpb24gVWkoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3Q9RHUodCk7dmFyIG49VSh0KT9YKHQpOm5lLHI9bj9uWzBdOnQuY2hhckF0KDApLGk9bj9DaShuLDEpLmpvaW4oIiIpOnQuc2xpY2UoMSk7cmV0dXJuIHJbZV0oKStpfX1mdW5jdGlvbiB6aShlKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIG0oQ2ModGModCkucmVwbGFjZShmbiwiIikpLGUsIiIpfX1mdW5jdGlvbiBHaShlKXtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgdD1hcmd1bWVudHM7c3dpdGNoKHQubGVuZ3RoKXtjYXNlIDA6cmV0dXJuIG5ldyBlO2Nhc2UgMTpyZXR1cm4gbmV3IGUodFswXSk7Y2FzZSAyOnJldHVybiBuZXcgZSh0WzBdLHRbMV0pO2Nhc2UgMzpyZXR1cm4gbmV3IGUodFswXSx0WzFdLHRbMl0pO2Nhc2UgNDpyZXR1cm4gbmV3IGUodFswXSx0WzFdLHRbMl0sdFszXSk7Y2FzZSA1OnJldHVybiBuZXcgZSh0WzBdLHRbMV0sdFsyXSx0WzNdLHRbNF0pO2Nhc2UgNjpyZXR1cm4gbmV3IGUodFswXSx0WzFdLHRbMl0sdFszXSx0WzRdLHRbNV0pO2Nhc2UgNzpyZXR1cm4gbmV3IGUodFswXSx0WzFdLHRbMl0sdFszXSx0WzRdLHRbNV0sdFs2XSl9dmFyIG49Y3AoZS5wcm90b3R5cGUpLHI9ZS5hcHBseShuLHQpO3JldHVybiBldShyKT9yOm59fWZ1bmN0aW9uIFZpKGUsdCxuKXtmdW5jdGlvbiByKCl7Zm9yKHZhciBhPWFyZ3VtZW50cy5sZW5ndGgscz1YYyhhKSx1PWEsYz1nbyhyKTt1LS07KXNbdV09YXJndW1lbnRzW3VdO3ZhciBsPWE8MyYmc1swXSE9PWMmJnNbYS0xXSE9PWM/W106SChzLGMpO3JldHVybihhLT1sLmxlbmd0aCk8bj90byhlLHQsV2ksci5wbGFjZWhvbGRlcixuZSxzLGwsbmUsbmUsbi1hKTpvKHRoaXMmJnRoaXMhPT1PbiYmdGhpcyBpbnN0YW5jZW9mIHI/aTplLHRoaXMscyl9dmFyIGk9R2koZSk7cmV0dXJuIHJ9ZnVuY3Rpb24gcWkoZSl7cmV0dXJuIGZ1bmN0aW9uKHQsbixyKXt2YXIgaT1ybCh0KTtpZighenModCkpe3ZhciBvPXlvKG4sMyk7dD1NdSh0KSxuPWZ1bmN0aW9uKGUpe3JldHVybiBvKGlbZV0sZSxpKX19dmFyIGE9ZSh0LG4scik7cmV0dXJuIGE+LTE/aVtvP3RbYV06YV06bmV9fWZ1bmN0aW9uIEhpKGUpe3JldHVybiBwbyhmdW5jdGlvbih0KXt2YXIgbj10Lmxlbmd0aCxyPW4sbz1pLnByb3RvdHlwZS50aHJ1O2ZvcihlJiZ0LnJldmVyc2UoKTtyLS07KXt2YXIgYT10W3JdO2lmKCJmdW5jdGlvbiIhPXR5cGVvZiBhKXRocm93IG5ldyBhbChvZSk7aWYobyYmIXMmJiJ3cmFwcGVyIj09bW8oYSkpdmFyIHM9bmV3IGkoW10sITApfWZvcihyPXM/cjpuOysrcjxuOyl7YT10W3JdO3ZhciB1PW1vKGEpLGM9IndyYXBwZXIiPT11P2JwKGEpOm5lO3M9YyYmTG8oY1swXSkmJmNbMV09PShDZXx5ZXxiZXxFZSkmJiFjWzRdLmxlbmd0aCYmMT09Y1s5XT9zW21vKGNbMF0pXS5hcHBseShzLGNbM10pOjE9PWEubGVuZ3RoJiZMbyhhKT9zW3VdKCk6cy50aHJ1KGEpfXJldHVybiBmdW5jdGlvbigpe3ZhciBlPWFyZ3VtZW50cyxyPWVbMF07aWYocyYmMT09ZS5sZW5ndGgmJmRmKHIpKXJldHVybiBzLnBsYW50KHIpLnZhbHVlKCk7Zm9yKHZhciBpPTAsbz1uP3RbaV0uYXBwbHkodGhpcyxlKTpyOysraTxuOylvPXRbaV0uY2FsbCh0aGlzLG8pO3JldHVybiBvfX0pfWZ1bmN0aW9uIFdpKGUsdCxuLHIsaSxvLGEscyx1LGMpe2Z1bmN0aW9uIGwoKXtmb3IodmFyIHk9YXJndW1lbnRzLmxlbmd0aCx2PVhjKHkpLGI9eTtiLS07KXZbYl09YXJndW1lbnRzW2JdO2lmKGgpdmFyIHg9Z28obCksQz1SKHYseCk7aWYociYmKHY9T2kodixyLGksaCkpLG8mJih2PUZpKHYsbyxhLGgpKSx5LT1DLGgmJnk8Yyl7dmFyIEU9SCh2LHgpO3JldHVybiB0byhlLHQsV2ksbC5wbGFjZWhvbGRlcixuLHYsRSxzLHUsYy15KX12YXIgRD1mP246dGhpcyx3PWQ/RFtlXTplO3JldHVybiB5PXYubGVuZ3RoLHM/dj1Wbyh2LHMpOm0mJnk+MSYmdi5yZXZlcnNlKCkscCYmdTx5JiYodi5sZW5ndGg9dSksdGhpcyYmdGhpcyE9PU9uJiZ0aGlzIGluc3RhbmNlb2YgbCYmKHc9Z3x8R2kodykpLHcuYXBwbHkoRCx2KX12YXIgcD10JkNlLGY9dCZoZSxkPXQmbWUsaD10Jih5ZXx2ZSksbT10JkRlLGc9ZD9uZTpHaShlKTtyZXR1cm4gbH1mdW5jdGlvbiBRaShlLHQpe3JldHVybiBmdW5jdGlvbihuLHIpe3JldHVybiBDcihuLGUsdChyKSx7fSl9fWZ1bmN0aW9uIEtpKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKG4scil7dmFyIGk7aWYobj09PW5lJiZyPT09bmUpcmV0dXJuIHQ7aWYobiE9PW5lJiYoaT1uKSxyIT09bmUpe2lmKGk9PT1uZSlyZXR1cm4gcjsic3RyaW5nIj09dHlwZW9mIG58fCJzdHJpbmciPT10eXBlb2Ygcj8obj1saShuKSxyPWxpKHIpKToobj1jaShuKSxyPWNpKHIpKSxpPWUobixyKX1yZXR1cm4gaX19ZnVuY3Rpb24gSmkoZSl7cmV0dXJuIHBvKGZ1bmN0aW9uKHQpe3JldHVybiB0PWQodCxJKHlvKCkpKSxacihmdW5jdGlvbihuKXt2YXIgcj10aGlzO3JldHVybiBlKHQsZnVuY3Rpb24oZSl7cmV0dXJuIG8oZSxyLG4pfSl9KX0pfWZ1bmN0aW9uIFlpKGUsdCl7dD10PT09bmU/IiAiOmxpKHQpO3ZhciBuPXQubGVuZ3RoO2lmKG48MilyZXR1cm4gbj9Ycih0LGUpOnQ7dmFyIHI9WHIodCxMbChlL1kodCkpKTtyZXR1cm4gVSh0KT9DaShYKHIpLDAsZSkuam9pbigiIik6ci5zbGljZSgwLGUpfWZ1bmN0aW9uIFhpKGUsdCxuLHIpe2Z1bmN0aW9uIGkoKXtmb3IodmFyIHQ9LTEsdT1hcmd1bWVudHMubGVuZ3RoLGM9LTEsbD1yLmxlbmd0aCxwPVhjKGwrdSksZj10aGlzJiZ0aGlzIT09T24mJnRoaXMgaW5zdGFuY2VvZiBpP3M6ZTsrK2M8bDspcFtjXT1yW2NdO2Zvcig7dS0tOylwW2MrK109YXJndW1lbnRzWysrdF07cmV0dXJuIG8oZixhP246dGhpcyxwKX12YXIgYT10JmhlLHM9R2koZSk7cmV0dXJuIGl9ZnVuY3Rpb24gWmkoZSl7cmV0dXJuIGZ1bmN0aW9uKHQsbixyKXtyZXR1cm4gciYmIm51bWJlciIhPXR5cGVvZiByJiZGbyh0LG4scikmJihuPXI9bmUpLHQ9eXUodCksbj09PW5lPyhuPXQsdD0wKTpuPXl1KG4pLHI9cj09PW5lP3Q8bj8xOi0xOnl1KHIpLFlyKHQsbixyLGUpfX1mdW5jdGlvbiBlbyhlKXtyZXR1cm4gZnVuY3Rpb24odCxuKXtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIHQmJiJzdHJpbmciPT10eXBlb2Ygbnx8KHQ9eHUodCksbj14dShuKSksZSh0LG4pfX1mdW5jdGlvbiB0byhlLHQsbixyLGksbyxhLHMsdSxjKXt2YXIgbD10JnllLHA9bD9hOm5lLGY9bD9uZTphLGQ9bD9vOm5lLGg9bD9uZTpvO3R8PWw/YmU6eGUsKHQmPX4obD94ZTpiZSkpJmdlfHwodCY9fihoZXxtZSkpO3ZhciBtPVtlLHQsaSxkLHAsaCxmLHMsdSxjXSxnPW4uYXBwbHkobmUsbSk7cmV0dXJuIExvKGUpJiZ3cChnLG0pLGcucGxhY2Vob2xkZXI9cixIbyhnLGUsdCl9ZnVuY3Rpb24gbm8oZSl7dmFyIHQ9bmxbZV07cmV0dXJuIGZ1bmN0aW9uKGUsbil7aWYoZT14dShlKSxuPW51bGw9PW4/MDp6bCh2dShuKSwyOTIpKXt2YXIgcj0oRHUoZSkrImUiKS5zcGxpdCgiZSIpO3JldHVybiByPShEdSh0KHJbMF0rImUiKygrclsxXStuKSkpKyJlIikuc3BsaXQoImUiKSwrKHJbMF0rImUiKygrclsxXS1uKSl9cmV0dXJuIHQoZSl9fWZ1bmN0aW9uIHJvKGUpe3JldHVybiBmdW5jdGlvbih0KXt2YXIgbj1FcCh0KTtyZXR1cm4gbj09V2U/Vih0KTpuPT1aZT9RKHQpOk4odCxlKHQpKX19ZnVuY3Rpb24gaW8oZSx0LG4scixpLG8sYSxzKXt2YXIgdT10Jm1lO2lmKCF1JiYiZnVuY3Rpb24iIT10eXBlb2YgZSl0aHJvdyBuZXcgYWwob2UpO3ZhciBjPXI/ci5sZW5ndGg6MDtpZihjfHwodCY9fihiZXx4ZSkscj1pPW5lKSxhPWE9PT1uZT9hOlVsKHZ1KGEpLDApLHM9cz09PW5lP3M6dnUocyksYy09aT9pLmxlbmd0aDowLHQmeGUpe3ZhciBsPXIscD1pO3I9aT1uZX12YXIgZj11P25lOmJwKGUpLGQ9W2UsdCxuLHIsaSxsLHAsbyxhLHNdO2lmKGYmJkJvKGQsZiksZT1kWzBdLHQ9ZFsxXSxuPWRbMl0scj1kWzNdLGk9ZFs0XSxzPWRbOV09ZFs5XT09PW5lP3U/MDplLmxlbmd0aDpVbChkWzldLWMsMCksIXMmJnQmKHllfHZlKSYmKHQmPX4oeWV8dmUpKSx0JiZ0IT1oZSloPXQ9PXllfHx0PT12ZT9WaShlLHQscyk6dCE9YmUmJnQhPShoZXxiZSl8fGkubGVuZ3RoP1dpLmFwcGx5KG5lLGQpOlhpKGUsdCxuLHIpO2Vsc2UgdmFyIGg9JGkoZSx0LG4pO3JldHVybiBIbygoZj9ocDp3cCkoaCxkKSxlLHQpfWZ1bmN0aW9uIG9vKGUsdCxuLHIpe3JldHVybiBlPT09bmV8fFVzKGUsY2xbbl0pJiYhZmwuY2FsbChyLG4pP3Q6ZX1mdW5jdGlvbiBhbyhlLHQsbixyLGksbyl7cmV0dXJuIGV1KGUpJiZldSh0KSYmKG8uc2V0KHQsZSksVXIoZSx0LG5lLGFvLG8pLG8uZGVsZXRlKHQpKSxlfWZ1bmN0aW9uIHNvKGUpe3JldHVybiBjdShlKT9uZTplfWZ1bmN0aW9uIHVvKGUsdCxuLHIsaSxvKXt2YXIgYT1uJmZlLHM9ZS5sZW5ndGgsdT10Lmxlbmd0aDtpZihzIT11JiYhKGEmJnU+cykpcmV0dXJuITE7dmFyIGM9by5nZXQoZSk7aWYoYyYmby5nZXQodCkpcmV0dXJuIGM9PXQ7dmFyIGw9LTEscD0hMCxmPW4mZGU/bmV3IGhuOm5lO2ZvcihvLnNldChlLHQpLG8uc2V0KHQsZSk7KytsPHM7KXt2YXIgZD1lW2xdLGg9dFtsXTtpZihyKXZhciBtPWE/cihoLGQsbCx0LGUsbyk6cihkLGgsbCxlLHQsbyk7aWYobSE9PW5lKXtpZihtKWNvbnRpbnVlO3A9ITE7YnJlYWt9aWYoZil7aWYoIXkodCxmdW5jdGlvbihlLHQpe2lmKCFQKGYsdCkmJihkPT09ZXx8aShkLGUsbixyLG8pKSlyZXR1cm4gZi5wdXNoKHQpfSkpe3A9ITE7YnJlYWt9fWVsc2UgaWYoZCE9PWgmJiFpKGQsaCxuLHIsbykpe3A9ITE7YnJlYWt9fXJldHVybiBvLmRlbGV0ZShlKSxvLmRlbGV0ZSh0KSxwfWZ1bmN0aW9uIGNvKGUsdCxuLHIsaSxvLGEpe3N3aXRjaChuKXtjYXNlIGF0OmlmKGUuYnl0ZUxlbmd0aCE9dC5ieXRlTGVuZ3RofHxlLmJ5dGVPZmZzZXQhPXQuYnl0ZU9mZnNldClyZXR1cm4hMTtlPWUuYnVmZmVyLHQ9dC5idWZmZXI7Y2FzZSBvdDpyZXR1cm4hKGUuYnl0ZUxlbmd0aCE9dC5ieXRlTGVuZ3RofHwhbyhuZXcgQ2woZSksbmV3IENsKHQpKSk7Y2FzZSBVZTpjYXNlIHplOmNhc2UgUWU6cmV0dXJuIFVzKCtlLCt0KTtjYXNlIFZlOnJldHVybiBlLm5hbWU9PXQubmFtZSYmZS5tZXNzYWdlPT10Lm1lc3NhZ2U7Y2FzZSBYZTpjYXNlIGV0OnJldHVybiBlPT10KyIiO2Nhc2UgV2U6dmFyIHM9VjtjYXNlIFplOnZhciB1PXImZmU7aWYoc3x8KHM9VyksZS5zaXplIT10LnNpemUmJiF1KXJldHVybiExO3ZhciBjPWEuZ2V0KGUpO2lmKGMpcmV0dXJuIGM9PXQ7cnw9ZGUsYS5zZXQoZSx0KTt2YXIgbD11byhzKGUpLHModCkscixpLG8sYSk7cmV0dXJuIGEuZGVsZXRlKGUpLGw7Y2FzZSB0dDppZihzcClyZXR1cm4gc3AuY2FsbChlKT09c3AuY2FsbCh0KX1yZXR1cm4hMX1mdW5jdGlvbiBsbyhlLHQsbixyLGksbyl7dmFyIGE9biZmZSxzPWZvKGUpLHU9cy5sZW5ndGg7aWYodSE9Zm8odCkubGVuZ3RoJiYhYSlyZXR1cm4hMTtmb3IodmFyIGM9dTtjLS07KXt2YXIgbD1zW2NdO2lmKCEoYT9sIGluIHQ6ZmwuY2FsbCh0LGwpKSlyZXR1cm4hMX12YXIgcD1vLmdldChlKTtpZihwJiZvLmdldCh0KSlyZXR1cm4gcD09dDt2YXIgZj0hMDtvLnNldChlLHQpLG8uc2V0KHQsZSk7Zm9yKHZhciBkPWE7KytjPHU7KXtsPXNbY107dmFyIGg9ZVtsXSxtPXRbbF07aWYocil2YXIgZz1hP3IobSxoLGwsdCxlLG8pOnIoaCxtLGwsZSx0LG8pO2lmKCEoZz09PW5lP2g9PT1tfHxpKGgsbSxuLHIsbyk6Zykpe2Y9ITE7YnJlYWt9ZHx8KGQ9ImNvbnN0cnVjdG9yIj09bCl9aWYoZiYmIWQpe3ZhciB5PWUuY29uc3RydWN0b3Isdj10LmNvbnN0cnVjdG9yO3khPXYmJiJjb25zdHJ1Y3RvciJpbiBlJiYiY29uc3RydWN0b3IiaW4gdCYmISgiZnVuY3Rpb24iPT10eXBlb2YgeSYmeSBpbnN0YW5jZW9mIHkmJiJmdW5jdGlvbiI9PXR5cGVvZiB2JiZ2IGluc3RhbmNlb2YgdikmJihmPSExKX1yZXR1cm4gby5kZWxldGUoZSksby5kZWxldGUodCksZn1mdW5jdGlvbiBwbyhlKXtyZXR1cm4ga3Aoem8oZSxuZSxjYSksZSsiIil9ZnVuY3Rpb24gZm8oZSl7cmV0dXJuIGhyKGUsTXUseHApfWZ1bmN0aW9uIGhvKGUpe3JldHVybiBocihlLGp1LENwKX1mdW5jdGlvbiBtbyhlKXtmb3IodmFyIHQ9ZS5uYW1lKyIiLG49ZXBbdF0scj1mbC5jYWxsKGVwLHQpP24ubGVuZ3RoOjA7ci0tOyl7dmFyIGk9bltyXSxvPWkuZnVuYztpZihudWxsPT1vfHxvPT1lKXJldHVybiBpLm5hbWV9cmV0dXJuIHR9ZnVuY3Rpb24gZ28oZSl7cmV0dXJuKGZsLmNhbGwobiwicGxhY2Vob2xkZXIiKT9uOmUpLnBsYWNlaG9sZGVyfWZ1bmN0aW9uIHlvKCl7dmFyIGU9bi5pdGVyYXRlZXx8QWM7cmV0dXJuIGU9ZT09PUFjP0xyOmUsYXJndW1lbnRzLmxlbmd0aD9lKGFyZ3VtZW50c1swXSxhcmd1bWVudHNbMV0pOmV9ZnVuY3Rpb24gdm8oZSx0KXt2YXIgbj1lLl9fZGF0YV9fO3JldHVybiBJbyh0KT9uWyJzdHJpbmciPT10eXBlb2YgdD8ic3RyaW5nIjoiaGFzaCJdOm4ubWFwfWZ1bmN0aW9uIGJvKGUpe2Zvcih2YXIgdD1NdShlKSxuPXQubGVuZ3RoO24tLTspe3ZhciByPXRbbl0saT1lW3JdO3Rbbl09W3IsaSxqbyhpKV19cmV0dXJuIHR9ZnVuY3Rpb24geG8oZSx0KXt2YXIgbj0kKGUsdCk7cmV0dXJuIE9yKG4pP246bmV9ZnVuY3Rpb24gQ28oZSl7dmFyIHQ9ZmwuY2FsbChlLFRsKSxuPWVbVGxdO3RyeXtlW1RsXT1uZTt2YXIgcj0hMH1jYXRjaChlKXt9dmFyIGk9bWwuY2FsbChlKTtyZXR1cm4gciYmKHQ/ZVtUbF09bjpkZWxldGUgZVtUbF0pLGl9ZnVuY3Rpb24gRW8oZSx0LG4pe2Zvcih2YXIgcj0tMSxpPW4ubGVuZ3RoOysrcjxpOyl7dmFyIG89bltyXSxhPW8uc2l6ZTtzd2l0Y2goby50eXBlKXtjYXNlImRyb3AiOmUrPWE7YnJlYWs7Y2FzZSJkcm9wUmlnaHQiOnQtPWE7YnJlYWs7Y2FzZSJ0YWtlIjp0PXpsKHQsZSthKTticmVhaztjYXNlInRha2VSaWdodCI6ZT1VbChlLHQtYSl9fXJldHVybntzdGFydDplLGVuZDp0fX1mdW5jdGlvbiBEbyhlKXt2YXIgdD1lLm1hdGNoKFB0KTtyZXR1cm4gdD90WzFdLnNwbGl0KE10KTpbXX1mdW5jdGlvbiB3byhlLHQsbil7dD14aSh0LGUpO2Zvcih2YXIgcj0tMSxpPXQubGVuZ3RoLG89ITE7KytyPGk7KXt2YXIgYT1Lbyh0W3JdKTtpZighKG89bnVsbCE9ZSYmbihlLGEpKSlicmVhaztlPWVbYV19cmV0dXJuIG98fCsrciE9aT9vOiEhKGk9bnVsbD09ZT8wOmUubGVuZ3RoKSYmWnMoaSkmJk9vKGEsaSkmJihkZihlKXx8ZmYoZSkpfWZ1bmN0aW9uIFNvKGUpe3ZhciB0PWUubGVuZ3RoLG49bmV3IGUuY29uc3RydWN0b3IodCk7cmV0dXJuIHQmJiJzdHJpbmciPT10eXBlb2YgZVswXSYmZmwuY2FsbChlLCJpbmRleCIpJiYobi5pbmRleD1lLmluZGV4LG4uaW5wdXQ9ZS5pbnB1dCksbn1mdW5jdGlvbiBrbyhlKXtyZXR1cm4iZnVuY3Rpb24iIT10eXBlb2YgZS5jb25zdHJ1Y3Rvcnx8TW8oZSk/e306Y3AoRGwoZSkpfWZ1bmN0aW9uIEFvKGUsdCxuKXt2YXIgcj1lLmNvbnN0cnVjdG9yO3N3aXRjaCh0KXtjYXNlIG90OnJldHVybiBEaShlKTtjYXNlIFVlOmNhc2UgemU6cmV0dXJuIG5ldyByKCtlKTtjYXNlIGF0OnJldHVybiB3aShlLG4pO2Nhc2Ugc3Q6Y2FzZSB1dDpjYXNlIGN0OmNhc2UgbHQ6Y2FzZSBwdDpjYXNlIGZ0OmNhc2UgZHQ6Y2FzZSBodDpjYXNlIG10OnJldHVybiBBaShlLG4pO2Nhc2UgV2U6cmV0dXJuIG5ldyByO2Nhc2UgUWU6Y2FzZSBldDpyZXR1cm4gbmV3IHIoZSk7Y2FzZSBYZTpyZXR1cm4gU2koZSk7Y2FzZSBaZTpyZXR1cm4gbmV3IHI7Y2FzZSB0dDpyZXR1cm4ga2koZSl9fWZ1bmN0aW9uIF9vKGUsdCl7dmFyIG49dC5sZW5ndGg7aWYoIW4pcmV0dXJuIGU7dmFyIHI9bi0xO3JldHVybiB0W3JdPShuPjE/IiYgIjoiIikrdFtyXSx0PXQuam9pbihuPjI/IiwgIjoiICIpLGUucmVwbGFjZShMdCwie1xuLyogW3dyYXBwZWQgd2l0aCAiK3QrIl0gKi9cbiIpfWZ1bmN0aW9uIFRvKGUpe3JldHVybiBkZihlKXx8ZmYoZSl8fCEhKEFsJiZlJiZlW0FsXSl9ZnVuY3Rpb24gT28oZSx0KXt2YXIgbj10eXBlb2YgZTtyZXR1cm4hISh0PW51bGw9PXQ/RmU6dCkmJigibnVtYmVyIj09bnx8InN5bWJvbCIhPW4mJnF0LnRlc3QoZSkpJiZlPi0xJiZlJTE9PTAmJmU8dH1mdW5jdGlvbiBGbyhlLHQsbil7aWYoIWV1KG4pKXJldHVybiExO3ZhciByPXR5cGVvZiB0O3JldHVybiEhKCJudW1iZXIiPT1yP3pzKG4pJiZPbyh0LG4ubGVuZ3RoKToic3RyaW5nIj09ciYmdCBpbiBuKSYmVXMoblt0XSxlKX1mdW5jdGlvbiBObyhlLHQpe2lmKGRmKGUpKXJldHVybiExO3ZhciBuPXR5cGVvZiBlO3JldHVybiEoIm51bWJlciIhPW4mJiJzeW1ib2wiIT1uJiYiYm9vbGVhbiIhPW4mJm51bGwhPWUmJiFmdShlKSl8fChBdC50ZXN0KGUpfHwha3QudGVzdChlKXx8bnVsbCE9dCYmZSBpbiBybCh0KSl9ZnVuY3Rpb24gSW8oZSl7dmFyIHQ9dHlwZW9mIGU7cmV0dXJuInN0cmluZyI9PXR8fCJudW1iZXIiPT10fHwic3ltYm9sIj09dHx8ImJvb2xlYW4iPT10PyJfX3Byb3RvX18iIT09ZTpudWxsPT09ZX1mdW5jdGlvbiBMbyhlKXt2YXIgdD1tbyhlKSxyPW5bdF07aWYoImZ1bmN0aW9uIiE9dHlwZW9mIHJ8fCEodCBpbiB2LnByb3RvdHlwZSkpcmV0dXJuITE7aWYoZT09PXIpcmV0dXJuITA7dmFyIGk9YnAocik7cmV0dXJuISFpJiZlPT09aVswXX1mdW5jdGlvbiBQbyhlKXtyZXR1cm4hIWhsJiZobCBpbiBlfWZ1bmN0aW9uIE1vKGUpe3ZhciB0PWUmJmUuY29uc3RydWN0b3I7cmV0dXJuIGU9PT0oImZ1bmN0aW9uIj09dHlwZW9mIHQmJnQucHJvdG90eXBlfHxjbCl9ZnVuY3Rpb24gam8oZSl7cmV0dXJuIGU9PT1lJiYhZXUoZSl9ZnVuY3Rpb24gUm8oZSx0KXtyZXR1cm4gZnVuY3Rpb24obil7cmV0dXJuIG51bGwhPW4mJihuW2VdPT09dCYmKHQhPT1uZXx8ZSBpbiBybChuKSkpfX1mdW5jdGlvbiBCbyhlLHQpe3ZhciBuPWVbMV0scj10WzFdLGk9bnxyLG89aTwoaGV8bWV8Q2UpLGE9cj09Q2UmJm49PXllfHxyPT1DZSYmbj09RWUmJmVbN10ubGVuZ3RoPD10WzhdfHxyPT0oQ2V8RWUpJiZ0WzddLmxlbmd0aDw9dFs4XSYmbj09eWU7aWYoIW8mJiFhKXJldHVybiBlO3ImaGUmJihlWzJdPXRbMl0saXw9biZoZT8wOmdlKTt2YXIgcz10WzNdO2lmKHMpe3ZhciB1PWVbM107ZVszXT11P09pKHUscyx0WzRdKTpzLGVbNF09dT9IKGVbM10sdWUpOnRbNF19cmV0dXJuIHM9dFs1XSxzJiYodT1lWzVdLGVbNV09dT9GaSh1LHMsdFs2XSk6cyxlWzZdPXU/SChlWzVdLHVlKTp0WzZdKSxzPXRbN10scyYmKGVbN109cyksciZDZSYmKGVbOF09bnVsbD09ZVs4XT90WzhdOnpsKGVbOF0sdFs4XSkpLG51bGw9PWVbOV0mJihlWzldPXRbOV0pLGVbMF09dFswXSxlWzFdPWksZX1mdW5jdGlvbiAkbyhlKXt2YXIgdD1bXTtpZihudWxsIT1lKWZvcih2YXIgbiBpbiBybChlKSl0LnB1c2gobik7cmV0dXJuIHR9ZnVuY3Rpb24gVW8oZSl7cmV0dXJuIG1sLmNhbGwoZSl9ZnVuY3Rpb24gem8oZSx0LG4pe3JldHVybiB0PVVsKHQ9PT1uZT9lLmxlbmd0aC0xOnQsMCksZnVuY3Rpb24oKXtmb3IodmFyIHI9YXJndW1lbnRzLGk9LTEsYT1VbChyLmxlbmd0aC10LDApLHM9WGMoYSk7KytpPGE7KXNbaV09clt0K2ldO2k9LTE7Zm9yKHZhciB1PVhjKHQrMSk7KytpPHQ7KXVbaV09cltpXTtyZXR1cm4gdVt0XT1uKHMpLG8oZSx0aGlzLHUpfX1mdW5jdGlvbiBHbyhlLHQpe3JldHVybiB0Lmxlbmd0aDwyP2U6ZHIoZSxpaSh0LDAsLTEpKX1mdW5jdGlvbiBWbyhlLHQpe2Zvcih2YXIgbj1lLmxlbmd0aCxyPXpsKHQubGVuZ3RoLG4pLGk9TmkoZSk7ci0tOyl7dmFyIG89dFtyXTtlW3JdPU9vKG8sbik/aVtvXTpuZX1yZXR1cm4gZX1mdW5jdGlvbiBxbyhlLHQpe2lmKCJfX3Byb3RvX18iIT10KXJldHVybiBlW3RdfWZ1bmN0aW9uIEhvKGUsdCxuKXt2YXIgcj10KyIiO3JldHVybiBrcChlLF9vKHIsWW8oRG8ociksbikpKX1mdW5jdGlvbiBXbyhlKXt2YXIgdD0wLG49MDtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgcj1HbCgpLGk9QWUtKHItbik7aWYobj1yLGk+MCl7aWYoKyt0Pj1rZSlyZXR1cm4gYXJndW1lbnRzWzBdfWVsc2UgdD0wO3JldHVybiBlLmFwcGx5KG5lLGFyZ3VtZW50cyl9fWZ1bmN0aW9uIFFvKGUsdCl7dmFyIG49LTEscj1lLmxlbmd0aCxpPXItMTtmb3IodD10PT09bmU/cjp0Oysrbjx0Oyl7dmFyIG89SnIobixpKSxhPWVbb107ZVtvXT1lW25dLGVbbl09YX1yZXR1cm4gZS5sZW5ndGg9dCxlfWZ1bmN0aW9uIEtvKGUpe2lmKCJzdHJpbmciPT10eXBlb2YgZXx8ZnUoZSkpcmV0dXJuIGU7dmFyIHQ9ZSsiIjtyZXR1cm4iMCI9PXQmJjEvZT09LU9lPyItMCI6dH1mdW5jdGlvbiBKbyhlKXtpZihudWxsIT1lKXt0cnl7cmV0dXJuIHBsLmNhbGwoZSl9Y2F0Y2goZSl7fXRyeXtyZXR1cm4gZSsiIn1jYXRjaChlKXt9fXJldHVybiIifWZ1bmN0aW9uIFlvKGUsdCl7cmV0dXJuIHMoamUsZnVuY3Rpb24obil7dmFyIHI9Il8uIituWzBdO3QmblsxXSYmIXAoZSxyKSYmZS5wdXNoKHIpfSksZS5zb3J0KCl9ZnVuY3Rpb24gWG8oZSl7aWYoZSBpbnN0YW5jZW9mIHYpcmV0dXJuIGUuY2xvbmUoKTt2YXIgdD1uZXcgaShlLl9fd3JhcHBlZF9fLGUuX19jaGFpbl9fKTtyZXR1cm4gdC5fX2FjdGlvbnNfXz1OaShlLl9fYWN0aW9uc19fKSx0Ll9faW5kZXhfXz1lLl9faW5kZXhfXyx0Ll9fdmFsdWVzX189ZS5fX3ZhbHVlc19fLHR9ZnVuY3Rpb24gWm8oZSx0LG4pe3Q9KG4/Rm8oZSx0LG4pOnQ9PT1uZSk/MTpVbCh2dSh0KSwwKTt2YXIgcj1udWxsPT1lPzA6ZS5sZW5ndGg7aWYoIXJ8fHQ8MSlyZXR1cm5bXTtmb3IodmFyIGk9MCxvPTAsYT1YYyhMbChyL3QpKTtpPHI7KWFbbysrXT1paShlLGksaSs9dCk7cmV0dXJuIGF9ZnVuY3Rpb24gZWEoZSl7Zm9yKHZhciB0PS0xLG49bnVsbD09ZT8wOmUubGVuZ3RoLHI9MCxpPVtdOysrdDxuOyl7dmFyIG89ZVt0XTtvJiYoaVtyKytdPW8pfXJldHVybiBpfWZ1bmN0aW9uIHRhKCl7dmFyIGU9YXJndW1lbnRzLmxlbmd0aDtpZighZSlyZXR1cm5bXTtmb3IodmFyIHQ9WGMoZS0xKSxuPWFyZ3VtZW50c1swXSxyPWU7ci0tOyl0W3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBoKGRmKG4pP05pKG4pOltuXSxjcih0LDEpKX1mdW5jdGlvbiBuYShlLHQsbil7dmFyIHI9bnVsbD09ZT8wOmUubGVuZ3RoO3JldHVybiByPyh0PW58fHQ9PT1uZT8xOnZ1KHQpLGlpKGUsdDwwPzA6dCxyKSk6W119ZnVuY3Rpb24gcmEoZSx0LG4pe3ZhciByPW51bGw9PWU/MDplLmxlbmd0aDtyZXR1cm4gcj8odD1ufHx0PT09bmU/MTp2dSh0KSx0PXItdCxpaShlLDAsdDwwPzA6dCkpOltdfWZ1bmN0aW9uIGlhKGUsdCl7cmV0dXJuIGUmJmUubGVuZ3RoP2hpKGUseW8odCwzKSwhMCwhMCk6W119ZnVuY3Rpb24gb2EoZSx0KXtyZXR1cm4gZSYmZS5sZW5ndGg/aGkoZSx5byh0LDMpLCEwKTpbXX1mdW5jdGlvbiBhYShlLHQsbixyKXt2YXIgaT1udWxsPT1lPzA6ZS5sZW5ndGg7cmV0dXJuIGk/KG4mJiJudW1iZXIiIT10eXBlb2YgbiYmRm8oZSx0LG4pJiYobj0wLHI9aSksc3IoZSx0LG4scikpOltdfWZ1bmN0aW9uIHNhKGUsdCxuKXt2YXIgcj1udWxsPT1lPzA6ZS5sZW5ndGg7aWYoIXIpcmV0dXJuLTE7dmFyIGk9bnVsbD09bj8wOnZ1KG4pO3JldHVybiBpPDAmJihpPVVsKHIraSwwKSksQyhlLHlvKHQsMyksaSl9ZnVuY3Rpb24gdWEoZSx0LG4pe3ZhciByPW51bGw9PWU/MDplLmxlbmd0aDtpZighcilyZXR1cm4tMTt2YXIgaT1yLTE7cmV0dXJuIG4hPT1uZSYmKGk9dnUobiksaT1uPDA/VWwocitpLDApOnpsKGksci0xKSksQyhlLHlvKHQsMyksaSwhMCl9ZnVuY3Rpb24gY2EoZSl7cmV0dXJuKG51bGw9PWU/MDplLmxlbmd0aCk/Y3IoZSwxKTpbXX1mdW5jdGlvbiBsYShlKXtyZXR1cm4obnVsbD09ZT8wOmUubGVuZ3RoKT9jcihlLE9lKTpbXX1mdW5jdGlvbiBwYShlLHQpe3JldHVybihudWxsPT1lPzA6ZS5sZW5ndGgpPyh0PXQ9PT1uZT8xOnZ1KHQpLGNyKGUsdCkpOltdfWZ1bmN0aW9uIGZhKGUpe2Zvcih2YXIgdD0tMSxuPW51bGw9PWU/MDplLmxlbmd0aCxyPXt9OysrdDxuOyl7dmFyIGk9ZVt0XTtyW2lbMF1dPWlbMV19cmV0dXJuIHJ9ZnVuY3Rpb24gZGEoZSl7cmV0dXJuIGUmJmUubGVuZ3RoP2VbMF06bmV9ZnVuY3Rpb24gaGEoZSx0LG4pe3ZhciByPW51bGw9PWU/MDplLmxlbmd0aDtpZighcilyZXR1cm4tMTt2YXIgaT1udWxsPT1uPzA6dnUobik7cmV0dXJuIGk8MCYmKGk9VWwocitpLDApKSxFKGUsdCxpKX1mdW5jdGlvbiBtYShlKXtyZXR1cm4obnVsbD09ZT8wOmUubGVuZ3RoKT9paShlLDAsLTEpOltdfWZ1bmN0aW9uIGdhKGUsdCl7cmV0dXJuIG51bGw9PWU/IiI6QmwuY2FsbChlLHQpfWZ1bmN0aW9uIHlhKGUpe3ZhciB0PW51bGw9PWU/MDplLmxlbmd0aDtyZXR1cm4gdD9lW3QtMV06bmV9ZnVuY3Rpb24gdmEoZSx0LG4pe3ZhciByPW51bGw9PWU/MDplLmxlbmd0aDtpZighcilyZXR1cm4tMTt2YXIgaT1yO3JldHVybiBuIT09bmUmJihpPXZ1KG4pLGk9aTwwP1VsKHIraSwwKTp6bChpLHItMSkpLHQ9PT10P0ooZSx0LGkpOkMoZSx3LGksITApfWZ1bmN0aW9uIGJhKGUsdCl7cmV0dXJuIGUmJmUubGVuZ3RoP0dyKGUsdnUodCkpOm5lfWZ1bmN0aW9uIHhhKGUsdCl7cmV0dXJuIGUmJmUubGVuZ3RoJiZ0JiZ0Lmxlbmd0aD9RcihlLHQpOmV9ZnVuY3Rpb24gQ2EoZSx0LG4pe3JldHVybiBlJiZlLmxlbmd0aCYmdCYmdC5sZW5ndGg/UXIoZSx0LHlvKG4sMikpOmV9ZnVuY3Rpb24gRWEoZSx0LG4pe3JldHVybiBlJiZlLmxlbmd0aCYmdCYmdC5sZW5ndGg/UXIoZSx0LG5lLG4pOmV9ZnVuY3Rpb24gRGEoZSx0KXt2YXIgbj1bXTtpZighZXx8IWUubGVuZ3RoKXJldHVybiBuO3ZhciByPS0xLGk9W10sbz1lLmxlbmd0aDtmb3IodD15byh0LDMpOysrcjxvOyl7dmFyIGE9ZVtyXTt0KGEscixlKSYmKG4ucHVzaChhKSxpLnB1c2gocikpfXJldHVybiBLcihlLGkpLG59ZnVuY3Rpb24gd2EoZSl7cmV0dXJuIG51bGw9PWU/ZTpIbC5jYWxsKGUpfWZ1bmN0aW9uIFNhKGUsdCxuKXt2YXIgcj1udWxsPT1lPzA6ZS5sZW5ndGg7cmV0dXJuIHI/KG4mJiJudW1iZXIiIT10eXBlb2YgbiYmRm8oZSx0LG4pPyh0PTAsbj1yKToodD1udWxsPT10PzA6dnUodCksbj1uPT09bmU/cjp2dShuKSksaWkoZSx0LG4pKTpbXX1mdW5jdGlvbiBrYShlLHQpe3JldHVybiBhaShlLHQpfWZ1bmN0aW9uIEFhKGUsdCxuKXtyZXR1cm4gc2koZSx0LHlvKG4sMikpfWZ1bmN0aW9uIF9hKGUsdCl7dmFyIG49bnVsbD09ZT8wOmUubGVuZ3RoO2lmKG4pe3ZhciByPWFpKGUsdCk7aWYocjxuJiZVcyhlW3JdLHQpKXJldHVybiByfXJldHVybi0xfWZ1bmN0aW9uIFRhKGUsdCl7cmV0dXJuIGFpKGUsdCwhMCl9ZnVuY3Rpb24gT2EoZSx0LG4pe3JldHVybiBzaShlLHQseW8obiwyKSwhMCl9ZnVuY3Rpb24gRmEoZSx0KXtpZihudWxsPT1lPzA6ZS5sZW5ndGgpe3ZhciBuPWFpKGUsdCwhMCktMTtpZihVcyhlW25dLHQpKXJldHVybiBufXJldHVybi0xfWZ1bmN0aW9uIE5hKGUpe3JldHVybiBlJiZlLmxlbmd0aD91aShlKTpbXX1mdW5jdGlvbiBJYShlLHQpe3JldHVybiBlJiZlLmxlbmd0aD91aShlLHlvKHQsMikpOltdfWZ1bmN0aW9uIExhKGUpe3ZhciB0PW51bGw9PWU/MDplLmxlbmd0aDtyZXR1cm4gdD9paShlLDEsdCk6W119ZnVuY3Rpb24gUGEoZSx0LG4pe3JldHVybiBlJiZlLmxlbmd0aD8odD1ufHx0PT09bmU/MTp2dSh0KSxpaShlLDAsdDwwPzA6dCkpOltdfWZ1bmN0aW9uIE1hKGUsdCxuKXt2YXIgcj1udWxsPT1lPzA6ZS5sZW5ndGg7cmV0dXJuIHI/KHQ9bnx8dD09PW5lPzE6dnUodCksdD1yLXQsaWkoZSx0PDA/MDp0LHIpKTpbXX1mdW5jdGlvbiBqYShlLHQpe3JldHVybiBlJiZlLmxlbmd0aD9oaShlLHlvKHQsMyksITEsITApOltdfWZ1bmN0aW9uIFJhKGUsdCl7cmV0dXJuIGUmJmUubGVuZ3RoP2hpKGUseW8odCwzKSk6W119ZnVuY3Rpb24gQmEoZSl7cmV0dXJuIGUmJmUubGVuZ3RoP3BpKGUpOltdfWZ1bmN0aW9uICRhKGUsdCl7cmV0dXJuIGUmJmUubGVuZ3RoP3BpKGUseW8odCwyKSk6W119ZnVuY3Rpb24gVWEoZSx0KXtyZXR1cm4gdD0iZnVuY3Rpb24iPT10eXBlb2YgdD90Om5lLGUmJmUubGVuZ3RoP3BpKGUsbmUsdCk6W119ZnVuY3Rpb24gemEoZSl7aWYoIWV8fCFlLmxlbmd0aClyZXR1cm5bXTt2YXIgdD0wO3JldHVybiBlPWwoZSxmdW5jdGlvbihlKXtpZihHcyhlKSlyZXR1cm4gdD1VbChlLmxlbmd0aCx0KSwhMH0pLEYodCxmdW5jdGlvbih0KXtyZXR1cm4gZChlLGsodCkpfSl9ZnVuY3Rpb24gR2EoZSx0KXtpZighZXx8IWUubGVuZ3RoKXJldHVybltdO3ZhciBuPXphKGUpO3JldHVybiBudWxsPT10P246ZChuLGZ1bmN0aW9uKGUpe3JldHVybiBvKHQsbmUsZSl9KX1mdW5jdGlvbiBWYShlLHQpe3JldHVybiB5aShlfHxbXSx0fHxbXSx6bil9ZnVuY3Rpb24gcWEoZSx0KXtyZXR1cm4geWkoZXx8W10sdHx8W10sbmkpfWZ1bmN0aW9uIEhhKGUpe3ZhciB0PW4oZSk7cmV0dXJuIHQuX19jaGFpbl9fPSEwLHR9ZnVuY3Rpb24gV2EoZSx0KXtyZXR1cm4gdChlKSxlfWZ1bmN0aW9uIFFhKGUsdCl7cmV0dXJuIHQoZSl9ZnVuY3Rpb24gS2EoKXtyZXR1cm4gSGEodGhpcyl9ZnVuY3Rpb24gSmEoKXtyZXR1cm4gbmV3IGkodGhpcy52YWx1ZSgpLHRoaXMuX19jaGFpbl9fKX1mdW5jdGlvbiBZYSgpe3RoaXMuX192YWx1ZXNfXz09PW5lJiYodGhpcy5fX3ZhbHVlc19fPWd1KHRoaXMudmFsdWUoKSkpO3ZhciBlPXRoaXMuX19pbmRleF9fPj10aGlzLl9fdmFsdWVzX18ubGVuZ3RoO3JldHVybntkb25lOmUsdmFsdWU6ZT9uZTp0aGlzLl9fdmFsdWVzX19bdGhpcy5fX2luZGV4X18rK119fWZ1bmN0aW9uIFhhKCl7cmV0dXJuIHRoaXN9ZnVuY3Rpb24gWmEoZSl7Zm9yKHZhciB0LG49dGhpcztuIGluc3RhbmNlb2Ygcjspe3ZhciBpPVhvKG4pO2kuX19pbmRleF9fPTAsaS5fX3ZhbHVlc19fPW5lLHQ/by5fX3dyYXBwZWRfXz1pOnQ9aTt2YXIgbz1pO249bi5fX3dyYXBwZWRfX31yZXR1cm4gby5fX3dyYXBwZWRfXz1lLHR9ZnVuY3Rpb24gZXMoKXt2YXIgZT10aGlzLl9fd3JhcHBlZF9fO2lmKGUgaW5zdGFuY2VvZiB2KXt2YXIgdD1lO3JldHVybiB0aGlzLl9fYWN0aW9uc19fLmxlbmd0aCYmKHQ9bmV3IHYodGhpcykpLHQ9dC5yZXZlcnNlKCksdC5fX2FjdGlvbnNfXy5wdXNoKHtmdW5jOlFhLGFyZ3M6W3dhXSx0aGlzQXJnOm5lfSksbmV3IGkodCx0aGlzLl9fY2hhaW5fXyl9cmV0dXJuIHRoaXMudGhydSh3YSl9ZnVuY3Rpb24gdHMoKXtyZXR1cm4gbWkodGhpcy5fX3dyYXBwZWRfXyx0aGlzLl9fYWN0aW9uc19fKX1mdW5jdGlvbiBucyhlLHQsbil7dmFyIHI9ZGYoZSk/YzpvcjtyZXR1cm4gbiYmRm8oZSx0LG4pJiYodD1uZSkscihlLHlvKHQsMykpfWZ1bmN0aW9uIHJzKGUsdCl7cmV0dXJuKGRmKGUpP2w6dXIpKGUseW8odCwzKSl9ZnVuY3Rpb24gaXMoZSx0KXtyZXR1cm4gY3IobHMoZSx0KSwxKX1mdW5jdGlvbiBvcyhlLHQpe3JldHVybiBjcihscyhlLHQpLE9lKX1mdW5jdGlvbiBhcyhlLHQsbil7cmV0dXJuIG49bj09PW5lPzE6dnUobiksY3IobHMoZSx0KSxuKX1mdW5jdGlvbiBzcyhlLHQpe3JldHVybihkZihlKT9zOmxwKShlLHlvKHQsMykpfWZ1bmN0aW9uIHVzKGUsdCl7cmV0dXJuKGRmKGUpP3U6cHApKGUseW8odCwzKSl9ZnVuY3Rpb24gY3MoZSx0LG4scil7ZT16cyhlKT9lOkt1KGUpLG49biYmIXI/dnUobik6MDt2YXIgaT1lLmxlbmd0aDtyZXR1cm4gbjwwJiYobj1VbChpK24sMCkpLHB1KGUpP248PWkmJmUuaW5kZXhPZih0LG4pPi0xOiEhaSYmRShlLHQsbik+LTF9ZnVuY3Rpb24gbHMoZSx0KXtyZXR1cm4oZGYoZSk/ZDpScikoZSx5byh0LDMpKX1mdW5jdGlvbiBwcyhlLHQsbixyKXtyZXR1cm4gbnVsbD09ZT9bXTooZGYodCl8fCh0PW51bGw9PXQ/W106W3RdKSxuPXI/bmU6bixkZihuKXx8KG49bnVsbD09bj9bXTpbbl0pLFZyKGUsdCxuKSl9ZnVuY3Rpb24gZnMoZSx0LG4pe3ZhciByPWRmKGUpP206XyxpPWFyZ3VtZW50cy5sZW5ndGg8MztyZXR1cm4gcihlLHlvKHQsNCksbixpLGxwKX1mdW5jdGlvbiBkcyhlLHQsbil7dmFyIHI9ZGYoZSk/ZzpfLGk9YXJndW1lbnRzLmxlbmd0aDwzO3JldHVybiByKGUseW8odCw0KSxuLGkscHApfWZ1bmN0aW9uIGhzKGUsdCl7cmV0dXJuKGRmKGUpP2w6dXIpKGUsX3MoeW8odCwzKSkpfWZ1bmN0aW9uIG1zKGUpe3JldHVybihkZihlKT9GbjplaSkoZSl9ZnVuY3Rpb24gZ3MoZSx0LG4pe3JldHVybiB0PShuP0ZvKGUsdCxuKTp0PT09bmUpPzE6dnUodCksKGRmKGUpP05uOnRpKShlLHQpfWZ1bmN0aW9uIHlzKGUpe3JldHVybihkZihlKT9MbjpyaSkoZSl9ZnVuY3Rpb24gdnMoZSl7aWYobnVsbD09ZSlyZXR1cm4gMDtpZih6cyhlKSlyZXR1cm4gcHUoZSk/WShlKTplLmxlbmd0aDt2YXIgdD1FcChlKTtyZXR1cm4gdD09V2V8fHQ9PVplP2Uuc2l6ZTpQcihlKS5sZW5ndGh9ZnVuY3Rpb24gYnMoZSx0LG4pe3ZhciByPWRmKGUpP3k6b2k7cmV0dXJuIG4mJkZvKGUsdCxuKSYmKHQ9bmUpLHIoZSx5byh0LDMpKX1mdW5jdGlvbiB4cyhlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0KXRocm93IG5ldyBhbChvZSk7cmV0dXJuIGU9dnUoZSksZnVuY3Rpb24oKXtpZigtLWU8MSlyZXR1cm4gdC5hcHBseSh0aGlzLGFyZ3VtZW50cyl9fWZ1bmN0aW9uIENzKGUsdCxuKXtyZXR1cm4gdD1uP25lOnQsdD1lJiZudWxsPT10P2UubGVuZ3RoOnQsaW8oZSxDZSxuZSxuZSxuZSxuZSx0KX1mdW5jdGlvbiBFcyhlLHQpe3ZhciBuO2lmKCJmdW5jdGlvbiIhPXR5cGVvZiB0KXRocm93IG5ldyBhbChvZSk7cmV0dXJuIGU9dnUoZSksZnVuY3Rpb24oKXtyZXR1cm4tLWU+MCYmKG49dC5hcHBseSh0aGlzLGFyZ3VtZW50cykpLGU8PTEmJih0PW5lKSxufX1mdW5jdGlvbiBEcyhlLHQsbil7dD1uP25lOnQ7dmFyIHI9aW8oZSx5ZSxuZSxuZSxuZSxuZSxuZSx0KTtyZXR1cm4gci5wbGFjZWhvbGRlcj1Ecy5wbGFjZWhvbGRlcixyfWZ1bmN0aW9uIHdzKGUsdCxuKXt0PW4/bmU6dDt2YXIgcj1pbyhlLHZlLG5lLG5lLG5lLG5lLG5lLHQpO3JldHVybiByLnBsYWNlaG9sZGVyPXdzLnBsYWNlaG9sZGVyLHJ9ZnVuY3Rpb24gU3MoZSx0LG4pe2Z1bmN0aW9uIHIodCl7dmFyIG49ZixyPWQ7cmV0dXJuIGY9ZD1uZSx2PXQsbT1lLmFwcGx5KHIsbil9ZnVuY3Rpb24gaShlKXtyZXR1cm4gdj1lLGc9U3Aocyx0KSxiP3IoZSk6bX1mdW5jdGlvbiBvKGUpe3ZhciBuPWUteSxyPWUtdixpPXQtbjtyZXR1cm4geD96bChpLGgtcik6aX1mdW5jdGlvbiBhKGUpe3ZhciBuPWUteSxyPWUtdjtyZXR1cm4geT09PW5lfHxuPj10fHxuPDB8fHgmJnI+PWh9ZnVuY3Rpb24gcygpe3ZhciBlPWVmKCk7aWYoYShlKSlyZXR1cm4gdShlKTtnPVNwKHMsbyhlKSl9ZnVuY3Rpb24gdShlKXtyZXR1cm4gZz1uZSxDJiZmP3IoZSk6KGY9ZD1uZSxtKX1mdW5jdGlvbiBjKCl7ZyE9PW5lJiZ5cChnKSx2PTAsZj15PWQ9Zz1uZX1mdW5jdGlvbiBsKCl7cmV0dXJuIGc9PT1uZT9tOnUoZWYoKSl9ZnVuY3Rpb24gcCgpe3ZhciBlPWVmKCksbj1hKGUpO2lmKGY9YXJndW1lbnRzLGQ9dGhpcyx5PWUsbil7aWYoZz09PW5lKXJldHVybiBpKHkpO2lmKHgpcmV0dXJuIGc9U3Aocyx0KSxyKHkpfXJldHVybiBnPT09bmUmJihnPVNwKHMsdCkpLG19dmFyIGYsZCxoLG0sZyx5LHY9MCxiPSExLHg9ITEsQz0hMDtpZigiZnVuY3Rpb24iIT10eXBlb2YgZSl0aHJvdyBuZXcgYWwob2UpO3JldHVybiB0PXh1KHQpfHwwLGV1KG4pJiYoYj0hIW4ubGVhZGluZyx4PSJtYXhXYWl0ImluIG4saD14P1VsKHh1KG4ubWF4V2FpdCl8fDAsdCk6aCxDPSJ0cmFpbGluZyJpbiBuPyEhbi50cmFpbGluZzpDKSxwLmNhbmNlbD1jLHAuZmx1c2g9bCxwfWZ1bmN0aW9uIGtzKGUpe3JldHVybiBpbyhlLERlKX1mdW5jdGlvbiBBcyhlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiBlfHxudWxsIT10JiYiZnVuY3Rpb24iIT10eXBlb2YgdCl0aHJvdyBuZXcgYWwob2UpO3ZhciBuPWZ1bmN0aW9uKCl7dmFyIHI9YXJndW1lbnRzLGk9dD90LmFwcGx5KHRoaXMscik6clswXSxvPW4uY2FjaGU7aWYoby5oYXMoaSkpcmV0dXJuIG8uZ2V0KGkpO3ZhciBhPWUuYXBwbHkodGhpcyxyKTtyZXR1cm4gbi5jYWNoZT1vLnNldChpLGEpfHxvLGF9O3JldHVybiBuLmNhY2hlPW5ldyhBcy5DYWNoZXx8YW4pLG59ZnVuY3Rpb24gX3MoZSl7aWYoImZ1bmN0aW9uIiE9dHlwZW9mIGUpdGhyb3cgbmV3IGFsKG9lKTtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgdD1hcmd1bWVudHM7c3dpdGNoKHQubGVuZ3RoKXtjYXNlIDA6cmV0dXJuIWUuY2FsbCh0aGlzKTtjYXNlIDE6cmV0dXJuIWUuY2FsbCh0aGlzLHRbMF0pO2Nhc2UgMjpyZXR1cm4hZS5jYWxsKHRoaXMsdFswXSx0WzFdKTtjYXNlIDM6cmV0dXJuIWUuY2FsbCh0aGlzLHRbMF0sdFsxXSx0WzJdKX1yZXR1cm4hZS5hcHBseSh0aGlzLHQpfX1mdW5jdGlvbiBUcyhlKXtyZXR1cm4gRXMoMixlKX1mdW5jdGlvbiBPcyhlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiBlKXRocm93IG5ldyBhbChvZSk7cmV0dXJuIHQ9dD09PW5lP3Q6dnUodCksWnIoZSx0KX1mdW5jdGlvbiBGcyhlLHQpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiBlKXRocm93IG5ldyBhbChvZSk7cmV0dXJuIHQ9bnVsbD09dD8wOlVsKHZ1KHQpLDApLFpyKGZ1bmN0aW9uKG4pe3ZhciByPW5bdF0saT1DaShuLDAsdCk7cmV0dXJuIHImJmgoaSxyKSxvKGUsdGhpcyxpKX0pfWZ1bmN0aW9uIE5zKGUsdCxuKXt2YXIgcj0hMCxpPSEwO2lmKCJmdW5jdGlvbiIhPXR5cGVvZiBlKXRocm93IG5ldyBhbChvZSk7cmV0dXJuIGV1KG4pJiYocj0ibGVhZGluZyJpbiBuPyEhbi5sZWFkaW5nOnIsaT0idHJhaWxpbmciaW4gbj8hIW4udHJhaWxpbmc6aSksU3MoZSx0LHtsZWFkaW5nOnIsbWF4V2FpdDp0LHRyYWlsaW5nOml9KX1mdW5jdGlvbiBJcyhlKXtyZXR1cm4gQ3MoZSwxKX1mdW5jdGlvbiBMcyhlLHQpe3JldHVybiBzZihiaSh0KSxlKX1mdW5jdGlvbiBQcygpe2lmKCFhcmd1bWVudHMubGVuZ3RoKXJldHVybltdO3ZhciBlPWFyZ3VtZW50c1swXTtyZXR1cm4gZGYoZSk/ZTpbZV19ZnVuY3Rpb24gTXMoZSl7cmV0dXJuIGVyKGUscGUpfWZ1bmN0aW9uIGpzKGUsdCl7cmV0dXJuIHQ9ImZ1bmN0aW9uIj09dHlwZW9mIHQ/dDpuZSxlcihlLHBlLHQpfWZ1bmN0aW9uIFJzKGUpe3JldHVybiBlcihlLGNlfHBlKX1mdW5jdGlvbiBCcyhlLHQpe3JldHVybiB0PSJmdW5jdGlvbiI9PXR5cGVvZiB0P3Q6bmUsZXIoZSxjZXxwZSx0KX1mdW5jdGlvbiAkcyhlLHQpe3JldHVybiBudWxsPT10fHxucihlLHQsTXUodCkpfWZ1bmN0aW9uIFVzKGUsdCl7cmV0dXJuIGU9PT10fHxlIT09ZSYmdCE9PXR9ZnVuY3Rpb24genMoZSl7cmV0dXJuIG51bGwhPWUmJlpzKGUubGVuZ3RoKSYmIVlzKGUpfWZ1bmN0aW9uIEdzKGUpe3JldHVybiB0dShlKSYmenMoZSl9ZnVuY3Rpb24gVnMoZSl7cmV0dXJuITA9PT1lfHwhMT09PWV8fHR1KGUpJiZtcihlKT09VWV9ZnVuY3Rpb24gcXMoZSl7cmV0dXJuIHR1KGUpJiYxPT09ZS5ub2RlVHlwZSYmIWN1KGUpfWZ1bmN0aW9uIEhzKGUpe2lmKG51bGw9PWUpcmV0dXJuITA7aWYoenMoZSkmJihkZihlKXx8InN0cmluZyI9PXR5cGVvZiBlfHwiZnVuY3Rpb24iPT10eXBlb2YgZS5zcGxpY2V8fG1mKGUpfHx4ZihlKXx8ZmYoZSkpKXJldHVybiFlLmxlbmd0aDt2YXIgdD1FcChlKTtpZih0PT1XZXx8dD09WmUpcmV0dXJuIWUuc2l6ZTtpZihNbyhlKSlyZXR1cm4hUHIoZSkubGVuZ3RoO2Zvcih2YXIgbiBpbiBlKWlmKGZsLmNhbGwoZSxuKSlyZXR1cm4hMTtyZXR1cm4hMH1mdW5jdGlvbiBXcyhlLHQpe3JldHVybiBrcihlLHQpfWZ1bmN0aW9uIFFzKGUsdCxuKXtuPSJmdW5jdGlvbiI9PXR5cGVvZiBuP246bmU7dmFyIHI9bj9uKGUsdCk6bmU7cmV0dXJuIHI9PT1uZT9rcihlLHQsbmUsbik6ISFyfWZ1bmN0aW9uIEtzKGUpe2lmKCF0dShlKSlyZXR1cm4hMTt2YXIgdD1tcihlKTtyZXR1cm4gdD09VmV8fHQ9PUdlfHwic3RyaW5nIj09dHlwZW9mIGUubWVzc2FnZSYmInN0cmluZyI9PXR5cGVvZiBlLm5hbWUmJiFjdShlKX1mdW5jdGlvbiBKcyhlKXtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIGUmJlJsKGUpfWZ1bmN0aW9uIFlzKGUpe2lmKCFldShlKSlyZXR1cm4hMTt2YXIgdD1tcihlKTtyZXR1cm4gdD09cWV8fHQ9PUhlfHx0PT0kZXx8dD09WWV9ZnVuY3Rpb24gWHMoZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlJiZlPT12dShlKX1mdW5jdGlvbiBacyhlKXtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIGUmJmU+LTEmJmUlMT09MCYmZTw9RmV9ZnVuY3Rpb24gZXUoZSl7dmFyIHQ9dHlwZW9mIGU7cmV0dXJuIG51bGwhPWUmJigib2JqZWN0Ij09dHx8ImZ1bmN0aW9uIj09dCl9ZnVuY3Rpb24gdHUoZSl7cmV0dXJuIG51bGwhPWUmJiJvYmplY3QiPT10eXBlb2YgZX1mdW5jdGlvbiBudShlLHQpe3JldHVybiBlPT09dHx8VHIoZSx0LGJvKHQpKX1mdW5jdGlvbiBydShlLHQsbil7cmV0dXJuIG49ImZ1bmN0aW9uIj09dHlwZW9mIG4/bjpuZSxUcihlLHQsYm8odCksbil9ZnVuY3Rpb24gaXUoZSl7cmV0dXJuIHV1KGUpJiZlIT0rZX1mdW5jdGlvbiBvdShlKXtpZihEcChlKSl0aHJvdyBuZXcgZWwoaWUpO3JldHVybiBPcihlKX1mdW5jdGlvbiBhdShlKXtyZXR1cm4gbnVsbD09PWV9ZnVuY3Rpb24gc3UoZSl7cmV0dXJuIG51bGw9PWV9ZnVuY3Rpb24gdXUoZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlfHx0dShlKSYmbXIoZSk9PVFlfWZ1bmN0aW9uIGN1KGUpe2lmKCF0dShlKXx8bXIoZSkhPUplKXJldHVybiExO3ZhciB0PURsKGUpO2lmKG51bGw9PT10KXJldHVybiEwO3ZhciBuPWZsLmNhbGwodCwiY29uc3RydWN0b3IiKSYmdC5jb25zdHJ1Y3RvcjtyZXR1cm4iZnVuY3Rpb24iPT10eXBlb2YgbiYmbiBpbnN0YW5jZW9mIG4mJnBsLmNhbGwobik9PWdsfWZ1bmN0aW9uIGx1KGUpe3JldHVybiBYcyhlKSYmZT49LUZlJiZlPD1GZX1mdW5jdGlvbiBwdShlKXtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIGV8fCFkZihlKSYmdHUoZSkmJm1yKGUpPT1ldH1mdW5jdGlvbiBmdShlKXtyZXR1cm4ic3ltYm9sIj09dHlwZW9mIGV8fHR1KGUpJiZtcihlKT09dHR9ZnVuY3Rpb24gZHUoZSl7cmV0dXJuIGU9PT1uZX1mdW5jdGlvbiBodShlKXtyZXR1cm4gdHUoZSkmJkVwKGUpPT1ydH1mdW5jdGlvbiBtdShlKXtyZXR1cm4gdHUoZSkmJm1yKGUpPT1pdH1mdW5jdGlvbiBndShlKXtpZighZSlyZXR1cm5bXTtpZih6cyhlKSlyZXR1cm4gcHUoZSk/WChlKTpOaShlKTtpZihfbCYmZVtfbF0pcmV0dXJuIEcoZVtfbF0oKSk7dmFyIHQ9RXAoZSk7cmV0dXJuKHQ9PVdlP1Y6dD09WmU/VzpLdSkoZSl9ZnVuY3Rpb24geXUoZSl7aWYoIWUpcmV0dXJuIDA9PT1lP2U6MDtpZigoZT14dShlKSk9PT1PZXx8ZT09PS1PZSl7cmV0dXJuKGU8MD8tMToxKSpOZX1yZXR1cm4gZT09PWU/ZTowfWZ1bmN0aW9uIHZ1KGUpe3ZhciB0PXl1KGUpLG49dCUxO3JldHVybiB0PT09dD9uP3Qtbjp0OjB9ZnVuY3Rpb24gYnUoZSl7cmV0dXJuIGU/Wm4odnUoZSksMCxMZSk6MH1mdW5jdGlvbiB4dShlKXtpZigibnVtYmVyIj09dHlwZW9mIGUpcmV0dXJuIGU7aWYoZnUoZSkpcmV0dXJuIEllO2lmKGV1KGUpKXt2YXIgdD0iZnVuY3Rpb24iPT10eXBlb2YgZS52YWx1ZU9mP2UudmFsdWVPZigpOmU7ZT1ldSh0KT90KyIiOnR9aWYoInN0cmluZyIhPXR5cGVvZiBlKXJldHVybiAwPT09ZT9lOitlO2U9ZS5yZXBsYWNlKEZ0LCIiKTt2YXIgbj16dC50ZXN0KGUpO3JldHVybiBufHxWdC50ZXN0KGUpP0FuKGUuc2xpY2UoMiksbj8yOjgpOlV0LnRlc3QoZSk/SWU6K2V9ZnVuY3Rpb24gQ3UoZSl7cmV0dXJuIElpKGUsanUoZSkpfWZ1bmN0aW9uIEV1KGUpe3JldHVybiBlP1puKHZ1KGUpLC1GZSxGZSk6MD09PWU/ZTowfWZ1bmN0aW9uIER1KGUpe3JldHVybiBudWxsPT1lPyIiOmxpKGUpfWZ1bmN0aW9uIHd1KGUsdCl7dmFyIG49Y3AoZSk7cmV0dXJuIG51bGw9PXQ/bjpLbihuLHQpfWZ1bmN0aW9uIFN1KGUsdCl7cmV0dXJuIHgoZSx5byh0LDMpLGxyKX1mdW5jdGlvbiBrdShlLHQpe3JldHVybiB4KGUseW8odCwzKSxwcil9ZnVuY3Rpb24gQXUoZSx0KXtyZXR1cm4gbnVsbD09ZT9lOmZwKGUseW8odCwzKSxqdSl9ZnVuY3Rpb24gX3UoZSx0KXtyZXR1cm4gbnVsbD09ZT9lOmRwKGUseW8odCwzKSxqdSl9ZnVuY3Rpb24gVHUoZSx0KXtyZXR1cm4gZSYmbHIoZSx5byh0LDMpKX1mdW5jdGlvbiBPdShlLHQpe3JldHVybiBlJiZwcihlLHlvKHQsMykpfWZ1bmN0aW9uIEZ1KGUpe3JldHVybiBudWxsPT1lP1tdOmZyKGUsTXUoZSkpfWZ1bmN0aW9uIE51KGUpe3JldHVybiBudWxsPT1lP1tdOmZyKGUsanUoZSkpfWZ1bmN0aW9uIEl1KGUsdCxuKXt2YXIgcj1udWxsPT1lP25lOmRyKGUsdCk7cmV0dXJuIHI9PT1uZT9uOnJ9ZnVuY3Rpb24gTHUoZSx0KXtyZXR1cm4gbnVsbCE9ZSYmd28oZSx0LHlyKX1mdW5jdGlvbiBQdShlLHQpe3JldHVybiBudWxsIT1lJiZ3byhlLHQsdnIpfWZ1bmN0aW9uIE11KGUpe3JldHVybiB6cyhlKT9UbihlKTpQcihlKX1mdW5jdGlvbiBqdShlKXtyZXR1cm4genMoZSk/VG4oZSwhMCk6TXIoZSl9ZnVuY3Rpb24gUnUoZSx0KXt2YXIgbj17fTtyZXR1cm4gdD15byh0LDMpLGxyKGUsZnVuY3Rpb24oZSxyLGkpe1luKG4sdChlLHIsaSksZSl9KSxufWZ1bmN0aW9uIEJ1KGUsdCl7dmFyIG49e307cmV0dXJuIHQ9eW8odCwzKSxscihlLGZ1bmN0aW9uKGUscixpKXtZbihuLHIsdChlLHIsaSkpfSksbn1mdW5jdGlvbiAkdShlLHQpe3JldHVybiBVdShlLF9zKHlvKHQpKSl9ZnVuY3Rpb24gVXUoZSx0KXtpZihudWxsPT1lKXJldHVybnt9O3ZhciBuPWQoaG8oZSksZnVuY3Rpb24oZSl7cmV0dXJuW2VdfSk7cmV0dXJuIHQ9eW8odCksSHIoZSxuLGZ1bmN0aW9uKGUsbil7cmV0dXJuIHQoZSxuWzBdKX0pfWZ1bmN0aW9uIHp1KGUsdCxuKXt0PXhpKHQsZSk7dmFyIHI9LTEsaT10Lmxlbmd0aDtmb3IoaXx8KGk9MSxlPW5lKTsrK3I8aTspe3ZhciBvPW51bGw9PWU/bmU6ZVtLbyh0W3JdKV07bz09PW5lJiYocj1pLG89biksZT1ZcyhvKT9vLmNhbGwoZSk6b31yZXR1cm4gZX1mdW5jdGlvbiBHdShlLHQsbil7cmV0dXJuIG51bGw9PWU/ZTpuaShlLHQsbil9ZnVuY3Rpb24gVnUoZSx0LG4scil7cmV0dXJuIHI9ImZ1bmN0aW9uIj09dHlwZW9mIHI/cjpuZSxudWxsPT1lP2U6bmkoZSx0LG4scil9ZnVuY3Rpb24gcXUoZSx0LG4pe3ZhciByPWRmKGUpLGk9cnx8bWYoZSl8fHhmKGUpO2lmKHQ9eW8odCw0KSxudWxsPT1uKXt2YXIgbz1lJiZlLmNvbnN0cnVjdG9yO249aT9yP25ldyBvOltdOmV1KGUpJiZZcyhvKT9jcChEbChlKSk6e319cmV0dXJuKGk/czpscikoZSxmdW5jdGlvbihlLHIsaSl7cmV0dXJuIHQobixlLHIsaSl9KSxufWZ1bmN0aW9uIEh1KGUsdCl7cmV0dXJuIG51bGw9PWV8fGZpKGUsdCl9ZnVuY3Rpb24gV3UoZSx0LG4pe3JldHVybiBudWxsPT1lP2U6ZGkoZSx0LGJpKG4pKX1mdW5jdGlvbiBRdShlLHQsbixyKXtyZXR1cm4gcj0iZnVuY3Rpb24iPT10eXBlb2Ygcj9yOm5lLG51bGw9PWU/ZTpkaShlLHQsYmkobikscil9ZnVuY3Rpb24gS3UoZSl7cmV0dXJuIG51bGw9PWU/W106TChlLE11KGUpKX1mdW5jdGlvbiBKdShlKXtyZXR1cm4gbnVsbD09ZT9bXTpMKGUsanUoZSkpfWZ1bmN0aW9uIFl1KGUsdCxuKXtyZXR1cm4gbj09PW5lJiYobj10LHQ9bmUpLG4hPT1uZSYmKG49eHUobiksbj1uPT09bj9uOjApLHQhPT1uZSYmKHQ9eHUodCksdD10PT09dD90OjApLFpuKHh1KGUpLHQsbil9ZnVuY3Rpb24gWHUoZSx0LG4pe3JldHVybiB0PXl1KHQpLG49PT1uZT8obj10LHQ9MCk6bj15dShuKSxlPXh1KGUpLGJyKGUsdCxuKX1mdW5jdGlvbiBadShlLHQsbil7aWYobiYmImJvb2xlYW4iIT10eXBlb2YgbiYmRm8oZSx0LG4pJiYodD1uPW5lKSxuPT09bmUmJigiYm9vbGVhbiI9PXR5cGVvZiB0PyhuPXQsdD1uZSk6ImJvb2xlYW4iPT10eXBlb2YgZSYmKG49ZSxlPW5lKSksZT09PW5lJiZ0PT09bmU/KGU9MCx0PTEpOihlPXl1KGUpLHQ9PT1uZT8odD1lLGU9MCk6dD15dSh0KSksZT50KXt2YXIgcj1lO2U9dCx0PXJ9aWYobnx8ZSUxfHx0JTEpe3ZhciBpPXFsKCk7cmV0dXJuIHpsKGUraSoodC1lK2tuKCIxZS0iKygoaSsiIikubGVuZ3RoLTEpKSksdCl9cmV0dXJuIEpyKGUsdCl9ZnVuY3Rpb24gZWMoZSl7cmV0dXJuIEhmKER1KGUpLnRvTG93ZXJDYXNlKCkpfWZ1bmN0aW9uIHRjKGUpe3JldHVybihlPUR1KGUpKSYmZS5yZXBsYWNlKEh0LEduKS5yZXBsYWNlKGRuLCIiKX1mdW5jdGlvbiBuYyhlLHQsbil7ZT1EdShlKSx0PWxpKHQpO3ZhciByPWUubGVuZ3RoO249bj09PW5lP3I6Wm4odnUobiksMCxyKTt2YXIgaT1uO3JldHVybihuLT10Lmxlbmd0aCk+PTAmJmUuc2xpY2UobixpKT09dH1mdW5jdGlvbiByYyhlKXtyZXR1cm4gZT1EdShlKSxlJiZFdC50ZXN0KGUpP2UucmVwbGFjZSh4dCxWbik6ZX1mdW5jdGlvbiBpYyhlKXtyZXR1cm4gZT1EdShlKSxlJiZPdC50ZXN0KGUpP2UucmVwbGFjZShUdCwiXFwkJiIpOmV9ZnVuY3Rpb24gb2MoZSx0LG4pe2U9RHUoZSksdD12dSh0KTt2YXIgcj10P1koZSk6MDtpZighdHx8cj49dClyZXR1cm4gZTt2YXIgaT0odC1yKS8yO3JldHVybiBZaShQbChpKSxuKStlK1lpKExsKGkpLG4pfWZ1bmN0aW9uIGFjKGUsdCxuKXtlPUR1KGUpLHQ9dnUodCk7dmFyIHI9dD9ZKGUpOjA7cmV0dXJuIHQmJnI8dD9lK1lpKHQtcixuKTplfWZ1bmN0aW9uIHNjKGUsdCxuKXtlPUR1KGUpLHQ9dnUodCk7dmFyIHI9dD9ZKGUpOjA7cmV0dXJuIHQmJnI8dD9ZaSh0LXIsbikrZTplfWZ1bmN0aW9uIHVjKGUsdCxuKXtyZXR1cm4gbnx8bnVsbD09dD90PTA6dCYmKHQ9K3QpLFZsKER1KGUpLnJlcGxhY2UoTnQsIiIpLHR8fDApfWZ1bmN0aW9uIGNjKGUsdCxuKXtyZXR1cm4gdD0obj9GbyhlLHQsbik6dD09PW5lKT8xOnZ1KHQpLFhyKER1KGUpLHQpfWZ1bmN0aW9uIGxjKCl7dmFyIGU9YXJndW1lbnRzLHQ9RHUoZVswXSk7cmV0dXJuIGUubGVuZ3RoPDM/dDp0LnJlcGxhY2UoZVsxXSxlWzJdKX1mdW5jdGlvbiBwYyhlLHQsbil7cmV0dXJuIG4mJiJudW1iZXIiIT10eXBlb2YgbiYmRm8oZSx0LG4pJiYodD1uPW5lKSwobj1uPT09bmU/TGU6bj4+PjApPyhlPUR1KGUpLGUmJigic3RyaW5nIj09dHlwZW9mIHR8fG51bGwhPXQmJiF2Zih0KSkmJiEodD1saSh0KSkmJlUoZSk/Q2koWChlKSwwLG4pOmUuc3BsaXQodCxuKSk6W119ZnVuY3Rpb24gZmMoZSx0LG4pe3JldHVybiBlPUR1KGUpLG49bnVsbD09bj8wOlpuKHZ1KG4pLDAsZS5sZW5ndGgpLHQ9bGkodCksZS5zbGljZShuLG4rdC5sZW5ndGgpPT10fWZ1bmN0aW9uIGRjKGUsdCxyKXt2YXIgaT1uLnRlbXBsYXRlU2V0dGluZ3M7ciYmRm8oZSx0LHIpJiYodD1uZSksZT1EdShlKSx0PVNmKHt9LHQsaSxvbyk7dmFyIG8sYSxzPVNmKHt9LHQuaW1wb3J0cyxpLmltcG9ydHMsb28pLHU9TXUocyksYz1MKHMsdSksbD0wLHA9dC5pbnRlcnBvbGF0ZXx8V3QsZj0iX19wICs9ICciLGQ9aWwoKHQuZXNjYXBlfHxXdCkuc291cmNlKyJ8IitwLnNvdXJjZSsifCIrKHA9PT1TdD9CdDpXdCkuc291cmNlKyJ8IisodC5ldmFsdWF0ZXx8V3QpLnNvdXJjZSsifCQiLCJnIiksaD0iLy8jIHNvdXJjZVVSTD0iKygic291cmNlVVJMImluIHQ/dC5zb3VyY2VVUkw6ImxvZGFzaC50ZW1wbGF0ZVNvdXJjZXNbIisgKytibisiXSIpKyJcbiI7ZS5yZXBsYWNlKGQsZnVuY3Rpb24odCxuLHIsaSxzLHUpe3JldHVybiByfHwocj1pKSxmKz1lLnNsaWNlKGwsdSkucmVwbGFjZShRdCxCKSxuJiYobz0hMCxmKz0iJyArXG5fX2UoIituKyIpICtcbiciKSxzJiYoYT0hMCxmKz0iJztcbiIrcysiO1xuX19wICs9ICciKSxyJiYoZis9IicgK1xuKChfX3QgPSAoIityKyIpKSA9PSBudWxsID8gJycgOiBfX3QpICtcbiciKSxsPXUrdC5sZW5ndGgsdH0pLGYrPSInO1xuIjt2YXIgbT10LnZhcmlhYmxlO218fChmPSJ3aXRoIChvYmopIHtcbiIrZisiXG59XG4iKSxmPShhP2YucmVwbGFjZShndCwiIik6ZikucmVwbGFjZSh5dCwiJDEiKS5yZXBsYWNlKHZ0LCIkMTsiKSxmPSJmdW5jdGlvbigiKyhtfHwib2JqIikrIikge1xuIisobT8iIjoib2JqIHx8IChvYmogPSB7fSk7XG4iKSsidmFyIF9fdCwgX19wID0gJyciKyhvPyIsIF9fZSA9IF8uZXNjYXBlIjoiIikrKGE/IiwgX19qID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG5mdW5jdGlvbiBwcmludCgpIHsgX19wICs9IF9fai5jYWxsKGFyZ3VtZW50cywgJycpIH1cbiI6IjtcbiIpK2YrInJldHVybiBfX3Bcbn0iO3ZhciBnPVdmKGZ1bmN0aW9uKCl7cmV0dXJuIHRsKHUsaCsicmV0dXJuICIrZikuYXBwbHkobmUsYyl9KTtpZihnLnNvdXJjZT1mLEtzKGcpKXRocm93IGc7cmV0dXJuIGd9ZnVuY3Rpb24gaGMoZSl7cmV0dXJuIER1KGUpLnRvTG93ZXJDYXNlKCl9ZnVuY3Rpb24gbWMoZSl7cmV0dXJuIER1KGUpLnRvVXBwZXJDYXNlKCl9ZnVuY3Rpb24gZ2MoZSx0LG4pe2lmKChlPUR1KGUpKSYmKG58fHQ9PT1uZSkpcmV0dXJuIGUucmVwbGFjZShGdCwiIik7aWYoIWV8fCEodD1saSh0KSkpcmV0dXJuIGU7dmFyIHI9WChlKSxpPVgodCk7cmV0dXJuIENpKHIsTShyLGkpLGoocixpKSsxKS5qb2luKCIiKX1mdW5jdGlvbiB5YyhlLHQsbil7aWYoKGU9RHUoZSkpJiYobnx8dD09PW5lKSlyZXR1cm4gZS5yZXBsYWNlKEl0LCIiKTtpZighZXx8ISh0PWxpKHQpKSlyZXR1cm4gZTt2YXIgcj1YKGUpO3JldHVybiBDaShyLDAsaihyLFgodCkpKzEpLmpvaW4oIiIpfWZ1bmN0aW9uIHZjKGUsdCxuKXtpZigoZT1EdShlKSkmJihufHx0PT09bmUpKXJldHVybiBlLnJlcGxhY2UoTnQsIiIpO2lmKCFlfHwhKHQ9bGkodCkpKXJldHVybiBlO3ZhciByPVgoZSk7cmV0dXJuIENpKHIsTShyLFgodCkpKS5qb2luKCIiKX1mdW5jdGlvbiBiYyhlLHQpe3ZhciBuPXdlLHI9U2U7aWYoZXUodCkpe3ZhciBpPSJzZXBhcmF0b3IiaW4gdD90LnNlcGFyYXRvcjppO249Imxlbmd0aCJpbiB0P3Z1KHQubGVuZ3RoKTpuLHI9Im9taXNzaW9uImluIHQ/bGkodC5vbWlzc2lvbik6cn1lPUR1KGUpO3ZhciBvPWUubGVuZ3RoO2lmKFUoZSkpe3ZhciBhPVgoZSk7bz1hLmxlbmd0aH1pZihuPj1vKXJldHVybiBlO3ZhciBzPW4tWShyKTtpZihzPDEpcmV0dXJuIHI7dmFyIHU9YT9DaShhLDAscykuam9pbigiIik6ZS5zbGljZSgwLHMpO2lmKGk9PT1uZSlyZXR1cm4gdStyO2lmKGEmJihzKz11Lmxlbmd0aC1zKSx2ZihpKSl7aWYoZS5zbGljZShzKS5zZWFyY2goaSkpe3ZhciBjLGw9dTtmb3IoaS5nbG9iYWx8fChpPWlsKGkuc291cmNlLER1KCR0LmV4ZWMoaSkpKyJnIikpLGkubGFzdEluZGV4PTA7Yz1pLmV4ZWMobCk7KXZhciBwPWMuaW5kZXg7dT11LnNsaWNlKDAscD09PW5lP3M6cCl9fWVsc2UgaWYoZS5pbmRleE9mKGxpKGkpLHMpIT1zKXt2YXIgZj11Lmxhc3RJbmRleE9mKGkpO2Y+LTEmJih1PXUuc2xpY2UoMCxmKSl9cmV0dXJuIHUrcn1mdW5jdGlvbiB4YyhlKXtyZXR1cm4gZT1EdShlKSxlJiZDdC50ZXN0KGUpP2UucmVwbGFjZShidCxxbik6ZX1mdW5jdGlvbiBDYyhlLHQsbil7cmV0dXJuIGU9RHUoZSksdD1uP25lOnQsdD09PW5lP3ooZSk/dGUoZSk6YihlKTplLm1hdGNoKHQpfHxbXX1mdW5jdGlvbiBFYyhlKXt2YXIgdD1udWxsPT1lPzA6ZS5sZW5ndGgsbj15bygpO3JldHVybiBlPXQ/ZChlLGZ1bmN0aW9uKGUpe2lmKCJmdW5jdGlvbiIhPXR5cGVvZiBlWzFdKXRocm93IG5ldyBhbChvZSk7cmV0dXJuW24oZVswXSksZVsxXV19KTpbXSxacihmdW5jdGlvbihuKXtmb3IodmFyIHI9LTE7KytyPHQ7KXt2YXIgaT1lW3JdO2lmKG8oaVswXSx0aGlzLG4pKXJldHVybiBvKGlbMV0sdGhpcyxuKX19KX1mdW5jdGlvbiBEYyhlKXtyZXR1cm4gdHIoZXIoZSxjZSkpfWZ1bmN0aW9uIHdjKGUpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiBlfX1mdW5jdGlvbiBTYyhlLHQpe3JldHVybiBudWxsPT1lfHxlIT09ZT90OmV9ZnVuY3Rpb24ga2MoZSl7cmV0dXJuIGV9ZnVuY3Rpb24gQWMoZSl7cmV0dXJuIExyKCJmdW5jdGlvbiI9PXR5cGVvZiBlP2U6ZXIoZSxjZSkpfWZ1bmN0aW9uIF9jKGUpe3JldHVybiBCcihlcihlLGNlKSl9ZnVuY3Rpb24gVGMoZSx0KXtyZXR1cm4gJHIoZSxlcih0LGNlKSl9ZnVuY3Rpb24gT2MoZSx0LG4pe3ZhciByPU11KHQpLGk9ZnIodCxyKTtudWxsIT1ufHxldSh0KSYmKGkubGVuZ3RofHwhci5sZW5ndGgpfHwobj10LHQ9ZSxlPXRoaXMsaT1mcih0LE11KHQpKSk7dmFyIG89IShldShuKSYmImNoYWluImluIG4pfHwhIW4uY2hhaW4sYT1ZcyhlKTtyZXR1cm4gcyhpLGZ1bmN0aW9uKG4pe3ZhciByPXRbbl07ZVtuXT1yLGEmJihlLnByb3RvdHlwZVtuXT1mdW5jdGlvbigpe3ZhciB0PXRoaXMuX19jaGFpbl9fO2lmKG98fHQpe3ZhciBuPWUodGhpcy5fX3dyYXBwZWRfXyk7cmV0dXJuKG4uX19hY3Rpb25zX189TmkodGhpcy5fX2FjdGlvbnNfXykpLnB1c2goe2Z1bmM6cixhcmdzOmFyZ3VtZW50cyx0aGlzQXJnOmV9KSxuLl9fY2hhaW5fXz10LG59cmV0dXJuIHIuYXBwbHkoZSxoKFt0aGlzLnZhbHVlKCldLGFyZ3VtZW50cykpfSl9KSxlfWZ1bmN0aW9uIEZjKCl7cmV0dXJuIE9uLl89PT10aGlzJiYoT24uXz15bCksdGhpc31mdW5jdGlvbiBOYygpe31mdW5jdGlvbiBJYyhlKXtyZXR1cm4gZT12dShlKSxacihmdW5jdGlvbih0KXtyZXR1cm4gR3IodCxlKX0pfWZ1bmN0aW9uIExjKGUpe3JldHVybiBObyhlKT9rKEtvKGUpKTpXcihlKX1mdW5jdGlvbiBQYyhlKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIG51bGw9PWU/bmU6ZHIoZSx0KX19ZnVuY3Rpb24gTWMoKXtyZXR1cm5bXX1mdW5jdGlvbiBqYygpe3JldHVybiExfWZ1bmN0aW9uIFJjKCl7cmV0dXJue319ZnVuY3Rpb24gQmMoKXtyZXR1cm4iIn1mdW5jdGlvbiAkYygpe3JldHVybiEwfWZ1bmN0aW9uIFVjKGUsdCl7aWYoKGU9dnUoZSkpPDF8fGU+RmUpcmV0dXJuW107dmFyIG49TGUscj16bChlLExlKTt0PXlvKHQpLGUtPUxlO2Zvcih2YXIgaT1GKHIsdCk7KytuPGU7KXQobik7cmV0dXJuIGl9ZnVuY3Rpb24gemMoZSl7cmV0dXJuIGRmKGUpP2QoZSxLbyk6ZnUoZSk/W2VdOk5pKEFwKER1KGUpKSl9ZnVuY3Rpb24gR2MoZSl7dmFyIHQ9KytkbDtyZXR1cm4gRHUoZSkrdH1mdW5jdGlvbiBWYyhlKXtyZXR1cm4gZSYmZS5sZW5ndGg/YXIoZSxrYyxncik6bmV9ZnVuY3Rpb24gcWMoZSx0KXtyZXR1cm4gZSYmZS5sZW5ndGg/YXIoZSx5byh0LDIpLGdyKTpuZX1mdW5jdGlvbiBIYyhlKXtyZXR1cm4gUyhlLGtjKX1mdW5jdGlvbiBXYyhlLHQpe3JldHVybiBTKGUseW8odCwyKSl9ZnVuY3Rpb24gUWMoZSl7cmV0dXJuIGUmJmUubGVuZ3RoP2FyKGUsa2MsanIpOm5lfWZ1bmN0aW9uIEtjKGUsdCl7cmV0dXJuIGUmJmUubGVuZ3RoP2FyKGUseW8odCwyKSxqcik6bmV9ZnVuY3Rpb24gSmMoZSl7cmV0dXJuIGUmJmUubGVuZ3RoP08oZSxrYyk6MH1mdW5jdGlvbiBZYyhlLHQpe3JldHVybiBlJiZlLmxlbmd0aD9PKGUseW8odCwyKSk6MH10PW51bGw9PXQ/T246SG4uZGVmYXVsdHMoT24uT2JqZWN0KCksdCxIbi5waWNrKE9uLHZuKSk7dmFyIFhjPXQuQXJyYXksWmM9dC5EYXRlLGVsPXQuRXJyb3IsdGw9dC5GdW5jdGlvbixubD10Lk1hdGgscmw9dC5PYmplY3QsaWw9dC5SZWdFeHAsb2w9dC5TdHJpbmcsYWw9dC5UeXBlRXJyb3Isc2w9WGMucHJvdG90eXBlLHVsPXRsLnByb3RvdHlwZSxjbD1ybC5wcm90b3R5cGUsbGw9dFsiX19jb3JlLWpzX3NoYXJlZF9fIl0scGw9dWwudG9TdHJpbmcsZmw9Y2wuaGFzT3duUHJvcGVydHksZGw9MCxobD1mdW5jdGlvbigpe3ZhciBlPS9bXi5dKyQvLmV4ZWMobGwmJmxsLmtleXMmJmxsLmtleXMuSUVfUFJPVE98fCIiKTtyZXR1cm4gZT8iU3ltYm9sKHNyYylfMS4iK2U6IiJ9KCksbWw9Y2wudG9TdHJpbmcsZ2w9cGwuY2FsbChybCkseWw9T24uXyx2bD1pbCgiXiIrcGwuY2FsbChmbCkucmVwbGFjZShUdCwiXFwkJiIpLnJlcGxhY2UoL2hhc093blByb3BlcnR5fChmdW5jdGlvbikuKj8oPz1cXFwoKXwgZm9yIC4rPyg/PVxcXF0pL2csIiQxLio/IikrIiQiKSxibD1Jbj90LkJ1ZmZlcjpuZSx4bD10LlN5bWJvbCxDbD10LlVpbnQ4QXJyYXksRWw9Ymw/YmwuYWxsb2NVbnNhZmU6bmUsRGw9cShybC5nZXRQcm90b3R5cGVPZixybCksd2w9cmwuY3JlYXRlLFNsPWNsLnByb3BlcnR5SXNFbnVtZXJhYmxlLGtsPXNsLnNwbGljZSxBbD14bD94bC5pc0NvbmNhdFNwcmVhZGFibGU6bmUsX2w9eGw/eGwuaXRlcmF0b3I6bmUsVGw9eGw/eGwudG9TdHJpbmdUYWc6bmUsT2w9ZnVuY3Rpb24oKXt0cnl7dmFyIGU9eG8ocmwsImRlZmluZVByb3BlcnR5Iik7cmV0dXJuIGUoe30sIiIse30pLGV9Y2F0Y2goZSl7fX0oKSxGbD10LmNsZWFyVGltZW91dCE9PU9uLmNsZWFyVGltZW91dCYmdC5jbGVhclRpbWVvdXQsTmw9WmMmJlpjLm5vdyE9PU9uLkRhdGUubm93JiZaYy5ub3csSWw9dC5zZXRUaW1lb3V0IT09T24uc2V0VGltZW91dCYmdC5zZXRUaW1lb3V0LExsPW5sLmNlaWwsUGw9bmwuZmxvb3IsTWw9cmwuZ2V0T3duUHJvcGVydHlTeW1ib2xzLGpsPWJsP2JsLmlzQnVmZmVyOm5lLFJsPXQuaXNGaW5pdGUsQmw9c2wuam9pbiwkbD1xKHJsLmtleXMscmwpLFVsPW5sLm1heCx6bD1ubC5taW4sR2w9WmMubm93LFZsPXQucGFyc2VJbnQscWw9bmwucmFuZG9tLEhsPXNsLnJldmVyc2UsV2w9eG8odCwiRGF0YVZpZXciKSxRbD14byh0LCJNYXAiKSxLbD14byh0LCJQcm9taXNlIiksSmw9eG8odCwiU2V0IiksWWw9eG8odCwiV2Vha01hcCIpLFhsPXhvKHJsLCJjcmVhdGUiKSxabD1ZbCYmbmV3IFlsLGVwPXt9LHRwPUpvKFdsKSxucD1KbyhRbCkscnA9Sm8oS2wpLGlwPUpvKEpsKSxvcD1KbyhZbCksYXA9eGw/eGwucHJvdG90eXBlOm5lLHNwPWFwP2FwLnZhbHVlT2Y6bmUsdXA9YXA/YXAudG9TdHJpbmc6bmUsY3A9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7fXJldHVybiBmdW5jdGlvbih0KXtpZighZXUodCkpcmV0dXJue307aWYod2wpcmV0dXJuIHdsKHQpO2UucHJvdG90eXBlPXQ7dmFyIG49bmV3IGU7cmV0dXJuIGUucHJvdG90eXBlPW5lLG59fSgpO24udGVtcGxhdGVTZXR0aW5ncz17ZXNjYXBlOkR0LGV2YWx1YXRlOnd0LGludGVycG9sYXRlOlN0LHZhcmlhYmxlOiIiLGltcG9ydHM6e186bn19LG4ucHJvdG90eXBlPXIucHJvdG90eXBlLG4ucHJvdG90eXBlLmNvbnN0cnVjdG9yPW4saS5wcm90b3R5cGU9Y3Aoci5wcm90b3R5cGUpLGkucHJvdG90eXBlLmNvbnN0cnVjdG9yPWksdi5wcm90b3R5cGU9Y3Aoci5wcm90b3R5cGUpLHYucHJvdG90eXBlLmNvbnN0cnVjdG9yPXYsZWUucHJvdG90eXBlLmNsZWFyPWp0LGVlLnByb3RvdHlwZS5kZWxldGU9S3QsZWUucHJvdG90eXBlLmdldD1KdCxlZS5wcm90b3R5cGUuaGFzPVl0LGVlLnByb3RvdHlwZS5zZXQ9WHQsWnQucHJvdG90eXBlLmNsZWFyPWVuLFp0LnByb3RvdHlwZS5kZWxldGU9dG4sWnQucHJvdG90eXBlLmdldD1ubixadC5wcm90b3R5cGUuaGFzPXJuLFp0LnByb3RvdHlwZS5zZXQ9b24sYW4ucHJvdG90eXBlLmNsZWFyPXNuLGFuLnByb3RvdHlwZS5kZWxldGU9dW4sYW4ucHJvdG90eXBlLmdldD1jbixhbi5wcm90b3R5cGUuaGFzPWxuLGFuLnByb3RvdHlwZS5zZXQ9cG4saG4ucHJvdG90eXBlLmFkZD1obi5wcm90b3R5cGUucHVzaD1tbixobi5wcm90b3R5cGUuaGFzPWduLHluLnByb3RvdHlwZS5jbGVhcj1Fbix5bi5wcm90b3R5cGUuZGVsZXRlPURuLHluLnByb3RvdHlwZS5nZXQ9d24seW4ucHJvdG90eXBlLmhhcz1Tbix5bi5wcm90b3R5cGUuc2V0PV9uO3ZhciBscD1SaShscikscHA9UmkocHIsITApLGZwPUJpKCksZHA9QmkoITApLGhwPVpsP2Z1bmN0aW9uKGUsdCl7cmV0dXJuIFpsLnNldChlLHQpLGV9OmtjLG1wPU9sP2Z1bmN0aW9uKGUsdCl7cmV0dXJuIE9sKGUsInRvU3RyaW5nIix7Y29uZmlndXJhYmxlOiEwLGVudW1lcmFibGU6ITEsdmFsdWU6d2ModCksd3JpdGFibGU6ITB9KX06a2MsZ3A9WnIseXA9Rmx8fGZ1bmN0aW9uKGUpe3JldHVybiBPbi5jbGVhclRpbWVvdXQoZSl9LHZwPUpsJiYxL1cobmV3IEpsKFssLTBdKSlbMV09PU9lP2Z1bmN0aW9uKGUpe3JldHVybiBuZXcgSmwoZSl9Ok5jLGJwPVpsP2Z1bmN0aW9uKGUpe3JldHVybiBabC5nZXQoZSl9Ok5jLHhwPU1sP2Z1bmN0aW9uKGUpe3JldHVybiBudWxsPT1lP1tdOihlPXJsKGUpLGwoTWwoZSksZnVuY3Rpb24odCl7cmV0dXJuIFNsLmNhbGwoZSx0KX0pKX06TWMsQ3A9TWw/ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PVtdO2U7KWgodCx4cChlKSksZT1EbChlKTtyZXR1cm4gdH06TWMsRXA9bXI7KFdsJiZFcChuZXcgV2wobmV3IEFycmF5QnVmZmVyKDEpKSkhPWF0fHxRbCYmRXAobmV3IFFsKSE9V2V8fEtsJiYiW29iamVjdCBQcm9taXNlXSIhPUVwKEtsLnJlc29sdmUoKSl8fEpsJiZFcChuZXcgSmwpIT1aZXx8WWwmJkVwKG5ldyBZbCkhPXJ0KSYmKEVwPWZ1bmN0aW9uKGUpe3ZhciB0PW1yKGUpLG49dD09SmU/ZS5jb25zdHJ1Y3RvcjpuZSxyPW4/Sm8obik6IiI7aWYocilzd2l0Y2gocil7Y2FzZSB0cDpyZXR1cm4gYXQ7Y2FzZSBucDpyZXR1cm4gV2U7Y2FzZSBycDpyZXR1cm4iW29iamVjdCBQcm9taXNlXSI7Y2FzZSBpcDpyZXR1cm4gWmU7Y2FzZSBvcDpyZXR1cm4gcnR9cmV0dXJuIHR9KTt2YXIgRHA9bGw/WXM6amMsd3A9V28oaHApLFNwPUlsfHxmdW5jdGlvbihlLHQpe3JldHVybiBPbi5zZXRUaW1lb3V0KGUsdCl9LGtwPVdvKG1wKSxBcD1mdW5jdGlvbihlKXt2YXIgdD1BcyhlLGZ1bmN0aW9uKGUpe3JldHVybiBuLnNpemU9PT1zZSYmbi5jbGVhcigpLGV9KSxuPXQuY2FjaGU7cmV0dXJuIHR9KGZ1bmN0aW9uKGUpe3ZhciB0PVtdO3JldHVybiA0Nj09PWUuY2hhckNvZGVBdCgwKSYmdC5wdXNoKCIiKSxlLnJlcGxhY2UoX3QsZnVuY3Rpb24oZSxuLHIsaSl7dC5wdXNoKHI/aS5yZXBsYWNlKFJ0LCIkMSIpOm58fGUpfSksdH0pLF9wPVpyKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIEdzKGUpP2lyKGUsY3IodCwxLEdzLCEwKSk6W119KSxUcD1acihmdW5jdGlvbihlLHQpe3ZhciBuPXlhKHQpO3JldHVybiBHcyhuKSYmKG49bmUpLEdzKGUpP2lyKGUsY3IodCwxLEdzLCEwKSx5byhuLDIpKTpbXX0pLE9wPVpyKGZ1bmN0aW9uKGUsdCl7dmFyIG49eWEodCk7cmV0dXJuIEdzKG4pJiYobj1uZSksR3MoZSk/aXIoZSxjcih0LDEsR3MsITApLG5lLG4pOltdfSksRnA9WnIoZnVuY3Rpb24oZSl7dmFyIHQ9ZChlLHZpKTtyZXR1cm4gdC5sZW5ndGgmJnRbMF09PT1lWzBdP3hyKHQpOltdfSksTnA9WnIoZnVuY3Rpb24oZSl7dmFyIHQ9eWEoZSksbj1kKGUsdmkpO3JldHVybiB0PT09eWEobik/dD1uZTpuLnBvcCgpLG4ubGVuZ3RoJiZuWzBdPT09ZVswXT94cihuLHlvKHQsMikpOltdfSksSXA9WnIoZnVuY3Rpb24oZSl7dmFyIHQ9eWEoZSksbj1kKGUsdmkpO3JldHVybiB0PSJmdW5jdGlvbiI9PXR5cGVvZiB0P3Q6bmUsdCYmbi5wb3AoKSxuLmxlbmd0aCYmblswXT09PWVbMF0/eHIobixuZSx0KTpbXX0pLExwPVpyKHhhKSxQcD1wbyhmdW5jdGlvbihlLHQpe3ZhciBuPW51bGw9PWU/MDplLmxlbmd0aCxyPVhuKGUsdCk7cmV0dXJuIEtyKGUsZCh0LGZ1bmN0aW9uKGUpe3JldHVybiBPbyhlLG4pPytlOmV9KS5zb3J0KF9pKSkscn0pLE1wPVpyKGZ1bmN0aW9uKGUpe3JldHVybiBwaShjcihlLDEsR3MsITApKX0pLGpwPVpyKGZ1bmN0aW9uKGUpe3ZhciB0PXlhKGUpO3JldHVybiBHcyh0KSYmKHQ9bmUpLHBpKGNyKGUsMSxHcywhMCkseW8odCwyKSl9KSxScD1acihmdW5jdGlvbihlKXt2YXIgdD15YShlKTtyZXR1cm4gdD0iZnVuY3Rpb24iPT10eXBlb2YgdD90Om5lLHBpKGNyKGUsMSxHcywhMCksbmUsdCl9KSxCcD1acihmdW5jdGlvbihlLHQpe3JldHVybiBHcyhlKT9pcihlLHQpOltdfSksJHA9WnIoZnVuY3Rpb24oZSl7cmV0dXJuIGdpKGwoZSxHcykpfSksVXA9WnIoZnVuY3Rpb24oZSl7dmFyIHQ9eWEoZSk7cmV0dXJuIEdzKHQpJiYodD1uZSksZ2kobChlLEdzKSx5byh0LDIpKX0pLHpwPVpyKGZ1bmN0aW9uKGUpe3ZhciB0PXlhKGUpO3JldHVybiB0PSJmdW5jdGlvbiI9PXR5cGVvZiB0P3Q6bmUsZ2kobChlLEdzKSxuZSx0KX0pLEdwPVpyKHphKSxWcD1acihmdW5jdGlvbihlKXt2YXIgdD1lLmxlbmd0aCxuPXQ+MT9lW3QtMV06bmU7cmV0dXJuIG49ImZ1bmN0aW9uIj09dHlwZW9mIG4/KGUucG9wKCksbik6bmUsR2EoZSxuKX0pLHFwPXBvKGZ1bmN0aW9uKGUpe3ZhciB0PWUubGVuZ3RoLG49dD9lWzBdOjAscj10aGlzLl9fd3JhcHBlZF9fLG89ZnVuY3Rpb24odCl7cmV0dXJuIFhuKHQsZSl9O3JldHVybiEodD4xfHx0aGlzLl9fYWN0aW9uc19fLmxlbmd0aCkmJnIgaW5zdGFuY2VvZiB2JiZPbyhuKT8ocj1yLnNsaWNlKG4sK24rKHQ/MTowKSksci5fX2FjdGlvbnNfXy5wdXNoKHtmdW5jOlFhLGFyZ3M6W29dLHRoaXNBcmc6bmV9KSxuZXcgaShyLHRoaXMuX19jaGFpbl9fKS50aHJ1KGZ1bmN0aW9uKGUpe3JldHVybiB0JiYhZS5sZW5ndGgmJmUucHVzaChuZSksZX0pKTp0aGlzLnRocnUobyl9KSxIcD1NaShmdW5jdGlvbihlLHQsbil7ZmwuY2FsbChlLG4pPysrZVtuXTpZbihlLG4sMSl9KSxXcD1xaShzYSksUXA9cWkodWEpLEtwPU1pKGZ1bmN0aW9uKGUsdCxuKXtmbC5jYWxsKGUsbik/ZVtuXS5wdXNoKHQpOlluKGUsbixbdF0pfSksSnA9WnIoZnVuY3Rpb24oZSx0LG4pe3ZhciByPS0xLGk9ImZ1bmN0aW9uIj09dHlwZW9mIHQsYT16cyhlKT9YYyhlLmxlbmd0aCk6W107cmV0dXJuIGxwKGUsZnVuY3Rpb24oZSl7YVsrK3JdPWk/byh0LGUsbik6RXIoZSx0LG4pfSksYX0pLFlwPU1pKGZ1bmN0aW9uKGUsdCxuKXtZbihlLG4sdCl9KSxYcD1NaShmdW5jdGlvbihlLHQsbil7ZVtuPzA6MV0ucHVzaCh0KX0sZnVuY3Rpb24oKXtyZXR1cm5bW10sW11dfSksWnA9WnIoZnVuY3Rpb24oZSx0KXtpZihudWxsPT1lKXJldHVybltdO3ZhciBuPXQubGVuZ3RoO3JldHVybiBuPjEmJkZvKGUsdFswXSx0WzFdKT90PVtdOm4+MiYmRm8odFswXSx0WzFdLHRbMl0pJiYodD1bdFswXV0pLFZyKGUsY3IodCwxKSxbXSl9KSxlZj1ObHx8ZnVuY3Rpb24oKXtyZXR1cm4gT24uRGF0ZS5ub3coKX0sdGY9WnIoZnVuY3Rpb24oZSx0LG4pe3ZhciByPWhlO2lmKG4ubGVuZ3RoKXt2YXIgaT1IKG4sZ28odGYpKTtyfD1iZX1yZXR1cm4gaW8oZSxyLHQsbixpKX0pLG5mPVpyKGZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1oZXxtZTtpZihuLmxlbmd0aCl7dmFyIGk9SChuLGdvKG5mKSk7cnw9YmV9cmV0dXJuIGlvKHQscixlLG4saSl9KSxyZj1acihmdW5jdGlvbihlLHQpe3JldHVybiBycihlLDEsdCl9KSxvZj1acihmdW5jdGlvbihlLHQsbil7cmV0dXJuIHJyKGUseHUodCl8fDAsbil9KTtBcy5DYWNoZT1hbjt2YXIgYWY9Z3AoZnVuY3Rpb24oZSx0KXt0PTE9PXQubGVuZ3RoJiZkZih0WzBdKT9kKHRbMF0sSSh5bygpKSk6ZChjcih0LDEpLEkoeW8oKSkpO3ZhciBuPXQubGVuZ3RoO3JldHVybiBacihmdW5jdGlvbihyKXtmb3IodmFyIGk9LTEsYT16bChyLmxlbmd0aCxuKTsrK2k8YTspcltpXT10W2ldLmNhbGwodGhpcyxyW2ldKTtyZXR1cm4gbyhlLHRoaXMscil9KX0pLHNmPVpyKGZ1bmN0aW9uKGUsdCl7dmFyIG49SCh0LGdvKHNmKSk7cmV0dXJuIGlvKGUsYmUsbmUsdCxuKX0pLHVmPVpyKGZ1bmN0aW9uKGUsdCl7dmFyIG49SCh0LGdvKHVmKSk7cmV0dXJuIGlvKGUseGUsbmUsdCxuKX0pLGNmPXBvKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGlvKGUsRWUsbmUsbmUsbmUsdCl9KSxsZj1lbyhncikscGY9ZW8oZnVuY3Rpb24oZSx0KXtyZXR1cm4gZT49dH0pLGZmPURyKGZ1bmN0aW9uKCl7cmV0dXJuIGFyZ3VtZW50c30oKSk/RHI6ZnVuY3Rpb24oZSl7cmV0dXJuIHR1KGUpJiZmbC5jYWxsKGUsImNhbGxlZSIpJiYhU2wuY2FsbChlLCJjYWxsZWUiKX0sZGY9WGMuaXNBcnJheSxoZj1Nbj9JKE1uKTp3cixtZj1qbHx8amMsZ2Y9am4/SShqbik6U3IseWY9Um4/SShSbik6X3IsdmY9Qm4/SShCbik6RnIsYmY9JG4/SSgkbik6TnIseGY9VW4/SShVbik6SXIsQ2Y9ZW8oanIpLEVmPWVvKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGU8PXR9KSxEZj1qaShmdW5jdGlvbihlLHQpe2lmKE1vKHQpfHx6cyh0KSlyZXR1cm4gdm9pZCBJaSh0LE11KHQpLGUpO2Zvcih2YXIgbiBpbiB0KWZsLmNhbGwodCxuKSYmem4oZSxuLHRbbl0pfSksd2Y9amkoZnVuY3Rpb24oZSx0KXtJaSh0LGp1KHQpLGUpfSksU2Y9amkoZnVuY3Rpb24oZSx0LG4scil7SWkodCxqdSh0KSxlLHIpfSksa2Y9amkoZnVuY3Rpb24oZSx0LG4scil7SWkodCxNdSh0KSxlLHIpfSksQWY9cG8oWG4pLF9mPVpyKGZ1bmN0aW9uKGUsdCl7ZT1ybChlKTt2YXIgbj0tMSxyPXQubGVuZ3RoLGk9cj4yP3RbMl06bmU7Zm9yKGkmJkZvKHRbMF0sdFsxXSxpKSYmKHI9MSk7KytuPHI7KWZvcih2YXIgbz10W25dLGE9anUobykscz0tMSx1PWEubGVuZ3RoOysrczx1Oyl7dmFyIGM9YVtzXSxsPWVbY107KGw9PT1uZXx8VXMobCxjbFtjXSkmJiFmbC5jYWxsKGUsYykpJiYoZVtjXT1vW2NdKX1yZXR1cm4gZX0pLFRmPVpyKGZ1bmN0aW9uKGUpe3JldHVybiBlLnB1c2gobmUsYW8pLG8oTGYsbmUsZSl9KSxPZj1RaShmdW5jdGlvbihlLHQsbil7bnVsbCE9dCYmImZ1bmN0aW9uIiE9dHlwZW9mIHQudG9TdHJpbmcmJih0PW1sLmNhbGwodCkpLGVbdF09bn0sd2Moa2MpKSxGZj1RaShmdW5jdGlvbihlLHQsbil7bnVsbCE9dCYmImZ1bmN0aW9uIiE9dHlwZW9mIHQudG9TdHJpbmcmJih0PW1sLmNhbGwodCkpLGZsLmNhbGwoZSx0KT9lW3RdLnB1c2gobik6ZVt0XT1bbl19LHlvKSxOZj1acihFciksSWY9amkoZnVuY3Rpb24oZSx0LG4pe1VyKGUsdCxuKX0pLExmPWppKGZ1bmN0aW9uKGUsdCxuLHIpe1VyKGUsdCxuLHIpfSksUGY9cG8oZnVuY3Rpb24oZSx0KXt2YXIgbj17fTtpZihudWxsPT1lKXJldHVybiBuO3ZhciByPSExO3Q9ZCh0LGZ1bmN0aW9uKHQpe3JldHVybiB0PXhpKHQsZSkscnx8KHI9dC5sZW5ndGg+MSksdH0pLElpKGUsaG8oZSksbiksciYmKG49ZXIobixjZXxsZXxwZSxzbykpO2Zvcih2YXIgaT10Lmxlbmd0aDtpLS07KWZpKG4sdFtpXSk7cmV0dXJuIG59KSxNZj1wbyhmdW5jdGlvbihlLHQpe3JldHVybiBudWxsPT1lP3t9OnFyKGUsdCl9KSxqZj1ybyhNdSksUmY9cm8oanUpLEJmPXppKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gdD10LnRvTG93ZXJDYXNlKCksZSsobj9lYyh0KTp0KX0pLCRmPXppKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZSsobj8iLSI6IiIpK3QudG9Mb3dlckNhc2UoKX0pLFVmPXppKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZSsobj8iICI6IiIpK3QudG9Mb3dlckNhc2UoKX0pLHpmPVVpKCJ0b0xvd2VyQ2FzZSIpLEdmPXppKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZSsobj8iXyI6IiIpK3QudG9Mb3dlckNhc2UoKX0pLFZmPXppKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZSsobj8iICI6IiIpK0hmKHQpfSkscWY9emkoZnVuY3Rpb24oZSx0LG4pe3JldHVybiBlKyhuPyIgIjoiIikrdC50b1VwcGVyQ2FzZSgpfSksSGY9VWkoInRvVXBwZXJDYXNlIiksV2Y9WnIoZnVuY3Rpb24oZSx0KXt0cnl7cmV0dXJuIG8oZSxuZSx0KX1jYXRjaChlKXtyZXR1cm4gS3MoZSk/ZTpuZXcgZWwoZSl9fSksUWY9cG8oZnVuY3Rpb24oZSx0KXtyZXR1cm4gcyh0LGZ1bmN0aW9uKHQpe3Q9S28odCksWW4oZSx0LHRmKGVbdF0sZSkpfSksZX0pLEtmPUhpKCksSmY9SGkoITApLFlmPVpyKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKG4pe3JldHVybiBFcihuLGUsdCl9fSksWGY9WnIoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24obil7cmV0dXJuIEVyKGUsbix0KX19KSxaZj1KaShkKSxlZD1KaShjKSx0ZD1KaSh5KSxuZD1aaSgpLHJkPVppKCEwKSxpZD1LaShmdW5jdGlvbihlLHQpe3JldHVybiBlK3R9LDApLG9kPW5vKCJjZWlsIiksYWQ9S2koZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS90fSwxKSxzZD1ubygiZmxvb3IiKSx1ZD1LaShmdW5jdGlvbihlLHQpe3JldHVybiBlKnR9LDEpLGNkPW5vKCJyb3VuZCIpLGxkPUtpKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUtdH0sMCk7cmV0dXJuIG4uYWZ0ZXI9eHMsbi5hcnk9Q3Msbi5hc3NpZ249RGYsbi5hc3NpZ25Jbj13ZixuLmFzc2lnbkluV2l0aD1TZixuLmFzc2lnbldpdGg9a2Ysbi5hdD1BZixuLmJlZm9yZT1FcyxuLmJpbmQ9dGYsbi5iaW5kQWxsPVFmLG4uYmluZEtleT1uZixuLmNhc3RBcnJheT1QcyxuLmNoYWluPUhhLG4uY2h1bms9Wm8sbi5jb21wYWN0PWVhLG4uY29uY2F0PXRhLG4uY29uZD1FYyxuLmNvbmZvcm1zPURjLG4uY29uc3RhbnQ9d2Msbi5jb3VudEJ5PUhwLG4uY3JlYXRlPXd1LG4uY3Vycnk9RHMsbi5jdXJyeVJpZ2h0PXdzLG4uZGVib3VuY2U9U3Msbi5kZWZhdWx0cz1fZixuLmRlZmF1bHRzRGVlcD1UZixuLmRlZmVyPXJmLG4uZGVsYXk9b2Ysbi5kaWZmZXJlbmNlPV9wLG4uZGlmZmVyZW5jZUJ5PVRwLG4uZGlmZmVyZW5jZVdpdGg9T3Asbi5kcm9wPW5hLG4uZHJvcFJpZ2h0PXJhLG4uZHJvcFJpZ2h0V2hpbGU9aWEsbi5kcm9wV2hpbGU9b2Esbi5maWxsPWFhLG4uZmlsdGVyPXJzLG4uZmxhdE1hcD1pcyxuLmZsYXRNYXBEZWVwPW9zLG4uZmxhdE1hcERlcHRoPWFzLG4uZmxhdHRlbj1jYSxuLmZsYXR0ZW5EZWVwPWxhLG4uZmxhdHRlbkRlcHRoPXBhLG4uZmxpcD1rcyxuLmZsb3c9S2Ysbi5mbG93UmlnaHQ9SmYsbi5mcm9tUGFpcnM9ZmEsbi5mdW5jdGlvbnM9RnUsbi5mdW5jdGlvbnNJbj1OdSxuLmdyb3VwQnk9S3Asbi5pbml0aWFsPW1hLG4uaW50ZXJzZWN0aW9uPUZwLG4uaW50ZXJzZWN0aW9uQnk9TnAsbi5pbnRlcnNlY3Rpb25XaXRoPUlwLG4uaW52ZXJ0PU9mLG4uaW52ZXJ0Qnk9RmYsbi5pbnZva2VNYXA9SnAsbi5pdGVyYXRlZT1BYyxuLmtleUJ5PVlwLG4ua2V5cz1NdSxuLmtleXNJbj1qdSxuLm1hcD1scyxuLm1hcEtleXM9UnUsbi5tYXBWYWx1ZXM9QnUsbi5tYXRjaGVzPV9jLG4ubWF0Y2hlc1Byb3BlcnR5PVRjLG4ubWVtb2l6ZT1BcyxuLm1lcmdlPUlmLG4ubWVyZ2VXaXRoPUxmLG4ubWV0aG9kPVlmLG4ubWV0aG9kT2Y9WGYsbi5taXhpbj1PYyxuLm5lZ2F0ZT1fcyxuLm50aEFyZz1JYyxuLm9taXQ9UGYsbi5vbWl0Qnk9JHUsbi5vbmNlPVRzLG4ub3JkZXJCeT1wcyxuLm92ZXI9WmYsbi5vdmVyQXJncz1hZixuLm92ZXJFdmVyeT1lZCxuLm92ZXJTb21lPXRkLG4ucGFydGlhbD1zZixuLnBhcnRpYWxSaWdodD11ZixuLnBhcnRpdGlvbj1YcCxuLnBpY2s9TWYsbi5waWNrQnk9VXUsbi5wcm9wZXJ0eT1MYyxuLnByb3BlcnR5T2Y9UGMsbi5wdWxsPUxwLG4ucHVsbEFsbD14YSxuLnB1bGxBbGxCeT1DYSxuLnB1bGxBbGxXaXRoPUVhLG4ucHVsbEF0PVBwLG4ucmFuZ2U9bmQsbi5yYW5nZVJpZ2h0PXJkLG4ucmVhcmc9Y2Ysbi5yZWplY3Q9aHMsbi5yZW1vdmU9RGEsbi5yZXN0PU9zLG4ucmV2ZXJzZT13YSxuLnNhbXBsZVNpemU9Z3Msbi5zZXQ9R3Usbi5zZXRXaXRoPVZ1LG4uc2h1ZmZsZT15cyxuLnNsaWNlPVNhLG4uc29ydEJ5PVpwLG4uc29ydGVkVW5pcT1OYSxuLnNvcnRlZFVuaXFCeT1JYSxuLnNwbGl0PXBjLG4uc3ByZWFkPUZzLG4udGFpbD1MYSxuLnRha2U9UGEsbi50YWtlUmlnaHQ9TWEsbi50YWtlUmlnaHRXaGlsZT1qYSxuLnRha2VXaGlsZT1SYSxuLnRhcD1XYSxuLnRocm90dGxlPU5zLG4udGhydT1RYSxuLnRvQXJyYXk9Z3Usbi50b1BhaXJzPWpmLG4udG9QYWlyc0luPVJmLG4udG9QYXRoPXpjLG4udG9QbGFpbk9iamVjdD1DdSxuLnRyYW5zZm9ybT1xdSxuLnVuYXJ5PUlzLG4udW5pb249TXAsbi51bmlvbkJ5PWpwLG4udW5pb25XaXRoPVJwLG4udW5pcT1CYSxuLnVuaXFCeT0kYSxuLnVuaXFXaXRoPVVhLG4udW5zZXQ9SHUsbi51bnppcD16YSxuLnVuemlwV2l0aD1HYSxuLnVwZGF0ZT1XdSxuLnVwZGF0ZVdpdGg9UXUsbi52YWx1ZXM9S3Usbi52YWx1ZXNJbj1KdSxuLndpdGhvdXQ9QnAsbi53b3Jkcz1DYyxuLndyYXA9THMsbi54b3I9JHAsbi54b3JCeT1VcCxuLnhvcldpdGg9enAsbi56aXA9R3Asbi56aXBPYmplY3Q9VmEsbi56aXBPYmplY3REZWVwPXFhLG4uemlwV2l0aD1WcCxuLmVudHJpZXM9amYsbi5lbnRyaWVzSW49UmYsbi5leHRlbmQ9d2Ysbi5leHRlbmRXaXRoPVNmLE9jKG4sbiksbi5hZGQ9aWQsbi5hdHRlbXB0PVdmLG4uY2FtZWxDYXNlPUJmLG4uY2FwaXRhbGl6ZT1lYyxuLmNlaWw9b2Qsbi5jbGFtcD1ZdSxuLmNsb25lPU1zLG4uY2xvbmVEZWVwPVJzLG4uY2xvbmVEZWVwV2l0aD1CcyxuLmNsb25lV2l0aD1qcyxuLmNvbmZvcm1zVG89JHMsbi5kZWJ1cnI9dGMsbi5kZWZhdWx0VG89U2Msbi5kaXZpZGU9YWQsbi5lbmRzV2l0aD1uYyxuLmVxPVVzLG4uZXNjYXBlPXJjLG4uZXNjYXBlUmVnRXhwPWljLG4uZXZlcnk9bnMsbi5maW5kPVdwLG4uZmluZEluZGV4PXNhLG4uZmluZEtleT1TdSxuLmZpbmRMYXN0PVFwLG4uZmluZExhc3RJbmRleD11YSxuLmZpbmRMYXN0S2V5PWt1LG4uZmxvb3I9c2Qsbi5mb3JFYWNoPXNzLG4uZm9yRWFjaFJpZ2h0PXVzLG4uZm9ySW49QXUsbi5mb3JJblJpZ2h0PV91LG4uZm9yT3duPVR1LG4uZm9yT3duUmlnaHQ9T3Usbi5nZXQ9SXUsbi5ndD1sZixuLmd0ZT1wZixuLmhhcz1MdSxuLmhhc0luPVB1LG4uaGVhZD1kYSxuLmlkZW50aXR5PWtjLG4uaW5jbHVkZXM9Y3Msbi5pbmRleE9mPWhhLG4uaW5SYW5nZT1YdSxuLmludm9rZT1OZixuLmlzQXJndW1lbnRzPWZmLG4uaXNBcnJheT1kZixuLmlzQXJyYXlCdWZmZXI9aGYsbi5pc0FycmF5TGlrZT16cyxuLmlzQXJyYXlMaWtlT2JqZWN0PUdzLG4uaXNCb29sZWFuPVZzLG4uaXNCdWZmZXI9bWYsbi5pc0RhdGU9Z2Ysbi5pc0VsZW1lbnQ9cXMsbi5pc0VtcHR5PUhzLG4uaXNFcXVhbD1XcyxuLmlzRXF1YWxXaXRoPVFzLG4uaXNFcnJvcj1LcyxuLmlzRmluaXRlPUpzLG4uaXNGdW5jdGlvbj1ZcyxuLmlzSW50ZWdlcj1YcyxuLmlzTGVuZ3RoPVpzLG4uaXNNYXA9eWYsbi5pc01hdGNoPW51LG4uaXNNYXRjaFdpdGg9cnUsbi5pc05hTj1pdSxuLmlzTmF0aXZlPW91LG4uaXNOaWw9c3Usbi5pc051bGw9YXUsbi5pc051bWJlcj11dSxuLmlzT2JqZWN0PWV1LG4uaXNPYmplY3RMaWtlPXR1LG4uaXNQbGFpbk9iamVjdD1jdSxuLmlzUmVnRXhwPXZmLG4uaXNTYWZlSW50ZWdlcj1sdSxuLmlzU2V0PWJmLG4uaXNTdHJpbmc9cHUsbi5pc1N5bWJvbD1mdSxuLmlzVHlwZWRBcnJheT14ZixuLmlzVW5kZWZpbmVkPWR1LG4uaXNXZWFrTWFwPWh1LG4uaXNXZWFrU2V0PW11LG4uam9pbj1nYSxuLmtlYmFiQ2FzZT0kZixuLmxhc3Q9eWEsbi5sYXN0SW5kZXhPZj12YSxuLmxvd2VyQ2FzZT1VZixuLmxvd2VyRmlyc3Q9emYsbi5sdD1DZixuLmx0ZT1FZixuLm1heD1WYyxuLm1heEJ5PXFjLG4ubWVhbj1IYyxuLm1lYW5CeT1XYyxuLm1pbj1RYyxuLm1pbkJ5PUtjLG4uc3R1YkFycmF5PU1jLG4uc3R1YkZhbHNlPWpjLG4uc3R1Yk9iamVjdD1SYyxuLnN0dWJTdHJpbmc9QmMsbi5zdHViVHJ1ZT0kYyxuLm11bHRpcGx5PXVkLG4ubnRoPWJhLG4ubm9Db25mbGljdD1GYyxuLm5vb3A9TmMsbi5ub3c9ZWYsbi5wYWQ9b2Msbi5wYWRFbmQ9YWMsbi5wYWRTdGFydD1zYyxuLnBhcnNlSW50PXVjLG4ucmFuZG9tPVp1LG4ucmVkdWNlPWZzLG4ucmVkdWNlUmlnaHQ9ZHMsbi5yZXBlYXQ9Y2Msbi5yZXBsYWNlPWxjLG4ucmVzdWx0PXp1LG4ucm91bmQ9Y2Qsbi5ydW5JbkNvbnRleHQ9ZSxuLnNhbXBsZT1tcyxuLnNpemU9dnMsbi5zbmFrZUNhc2U9R2Ysbi5zb21lPWJzLG4uc29ydGVkSW5kZXg9a2Esbi5zb3J0ZWRJbmRleEJ5PUFhLG4uc29ydGVkSW5kZXhPZj1fYSxuLnNvcnRlZExhc3RJbmRleD1UYSxuLnNvcnRlZExhc3RJbmRleEJ5PU9hLG4uc29ydGVkTGFzdEluZGV4T2Y9RmEsbi5zdGFydENhc2U9VmYsbi5zdGFydHNXaXRoPWZjLG4uc3VidHJhY3Q9bGQsbi5zdW09SmMsbi5zdW1CeT1ZYyxuLnRlbXBsYXRlPWRjLG4udGltZXM9VWMsbi50b0Zpbml0ZT15dSxuLnRvSW50ZWdlcj12dSxuLnRvTGVuZ3RoPWJ1LG4udG9Mb3dlcj1oYyxuLnRvTnVtYmVyPXh1LG4udG9TYWZlSW50ZWdlcj1FdSxuLnRvU3RyaW5nPUR1LG4udG9VcHBlcj1tYyxuLnRyaW09Z2Msbi50cmltRW5kPXljLG4udHJpbVN0YXJ0PXZjLG4udHJ1bmNhdGU9YmMsbi51bmVzY2FwZT14YyxuLnVuaXF1ZUlkPUdjLG4udXBwZXJDYXNlPXFmLG4udXBwZXJGaXJzdD1IZixuLmVhY2g9c3Msbi5lYWNoUmlnaHQ9dXMsbi5maXJzdD1kYSxPYyhuLGZ1bmN0aW9uKCl7dmFyIGU9e307cmV0dXJuIGxyKG4sZnVuY3Rpb24odCxyKXtmbC5jYWxsKG4ucHJvdG90eXBlLHIpfHwoZVtyXT10KX0pLGV9KCkse2NoYWluOiExfSksbi5WRVJTSU9OPSI0LjE3LjExIixzKFsiYmluZCIsImJpbmRLZXkiLCJjdXJyeSIsImN1cnJ5UmlnaHQiLCJwYXJ0aWFsIiwicGFydGlhbFJpZ2h0Il0sZnVuY3Rpb24oZSl7bltlXS5wbGFjZWhvbGRlcj1ufSkscyhbImRyb3AiLCJ0YWtlIl0sZnVuY3Rpb24oZSx0KXt2LnByb3RvdHlwZVtlXT1mdW5jdGlvbihuKXtuPW49PT1uZT8xOlVsKHZ1KG4pLDApO3ZhciByPXRoaXMuX19maWx0ZXJlZF9fJiYhdD9uZXcgdih0aGlzKTp0aGlzLmNsb25lKCk7cmV0dXJuIHIuX19maWx0ZXJlZF9fP3IuX190YWtlQ291bnRfXz16bChuLHIuX190YWtlQ291bnRfXyk6ci5fX3ZpZXdzX18ucHVzaCh7c2l6ZTp6bChuLExlKSx0eXBlOmUrKHIuX19kaXJfXzwwPyJSaWdodCI6IiIpfSkscn0sdi5wcm90b3R5cGVbZSsiUmlnaHQiXT1mdW5jdGlvbih0KXtyZXR1cm4gdGhpcy5yZXZlcnNlKClbZV0odCkucmV2ZXJzZSgpfX0pLHMoWyJmaWx0ZXIiLCJtYXAiLCJ0YWtlV2hpbGUiXSxmdW5jdGlvbihlLHQpe3ZhciBuPXQrMSxyPW49PV9lfHwzPT1uO3YucHJvdG90eXBlW2VdPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuY2xvbmUoKTtyZXR1cm4gdC5fX2l0ZXJhdGVlc19fLnB1c2goe2l0ZXJhdGVlOnlvKGUsMyksdHlwZTpufSksdC5fX2ZpbHRlcmVkX189dC5fX2ZpbHRlcmVkX198fHIsdH19KSxzKFsiaGVhZCIsImxhc3QiXSxmdW5jdGlvbihlLHQpe3ZhciBuPSJ0YWtlIisodD8iUmlnaHQiOiIiKTt2LnByb3RvdHlwZVtlXT1mdW5jdGlvbigpe3JldHVybiB0aGlzW25dKDEpLnZhbHVlKClbMF19fSkscyhbImluaXRpYWwiLCJ0YWlsIl0sZnVuY3Rpb24oZSx0KXt2YXIgbj0iZHJvcCIrKHQ/IiI6IlJpZ2h0Iik7di5wcm90b3R5cGVbZV09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fX2ZpbHRlcmVkX18/bmV3IHYodGhpcyk6dGhpc1tuXSgxKX19KSx2LnByb3RvdHlwZS5jb21wYWN0PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZmlsdGVyKGtjKX0sdi5wcm90b3R5cGUuZmluZD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5maWx0ZXIoZSkuaGVhZCgpfSx2LnByb3RvdHlwZS5maW5kTGFzdD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5yZXZlcnNlKCkuZmluZChlKX0sdi5wcm90b3R5cGUuaW52b2tlTWFwPVpyKGZ1bmN0aW9uKGUsdCl7cmV0dXJuImZ1bmN0aW9uIj09dHlwZW9mIGU/bmV3IHYodGhpcyk6dGhpcy5tYXAoZnVuY3Rpb24obil7cmV0dXJuIEVyKG4sZSx0KX0pfSksdi5wcm90b3R5cGUucmVqZWN0PWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLmZpbHRlcihfcyh5byhlKSkpfSx2LnByb3RvdHlwZS5zbGljZT1mdW5jdGlvbihlLHQpe2U9dnUoZSk7dmFyIG49dGhpcztyZXR1cm4gbi5fX2ZpbHRlcmVkX18mJihlPjB8fHQ8MCk/bmV3IHYobik6KGU8MD9uPW4udGFrZVJpZ2h0KC1lKTplJiYobj1uLmRyb3AoZSkpLHQhPT1uZSYmKHQ9dnUodCksbj10PDA/bi5kcm9wUmlnaHQoLXQpOm4udGFrZSh0LWUpKSxuKX0sdi5wcm90b3R5cGUudGFrZVJpZ2h0V2hpbGU9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMucmV2ZXJzZSgpLnRha2VXaGlsZShlKS5yZXZlcnNlKCl9LHYucHJvdG90eXBlLnRvQXJyYXk9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy50YWtlKExlKX0sbHIodi5wcm90b3R5cGUsZnVuY3Rpb24oZSx0KXt2YXIgcj0vXig/OmZpbHRlcnxmaW5kfG1hcHxyZWplY3QpfFdoaWxlJC8udGVzdCh0KSxvPS9eKD86aGVhZHxsYXN0KSQvLnRlc3QodCksYT1uW28/InRha2UiKygibGFzdCI9PXQ/IlJpZ2h0IjoiIik6dF0scz1vfHwvXmZpbmQvLnRlc3QodCk7YSYmKG4ucHJvdG90eXBlW3RdPWZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5fX3dyYXBwZWRfXyx1PW8/WzFdOmFyZ3VtZW50cyxjPXQgaW5zdGFuY2VvZiB2LGw9dVswXSxwPWN8fGRmKHQpLGY9ZnVuY3Rpb24oZSl7dmFyIHQ9YS5hcHBseShuLGgoW2VdLHUpKTtyZXR1cm4gbyYmZD90WzBdOnR9O3AmJnImJiJmdW5jdGlvbiI9PXR5cGVvZiBsJiYxIT1sLmxlbmd0aCYmKGM9cD0hMSk7dmFyIGQ9dGhpcy5fX2NoYWluX18sbT0hIXRoaXMuX19hY3Rpb25zX18ubGVuZ3RoLGc9cyYmIWQseT1jJiYhbTtpZighcyYmcCl7dD15P3Q6bmV3IHYodGhpcyk7dmFyIGI9ZS5hcHBseSh0LHUpO3JldHVybiBiLl9fYWN0aW9uc19fLnB1c2goe2Z1bmM6UWEsYXJnczpbZl0sdGhpc0FyZzpuZX0pLG5ldyBpKGIsZCl9cmV0dXJuIGcmJnk/ZS5hcHBseSh0aGlzLHUpOihiPXRoaXMudGhydShmKSxnP28/Yi52YWx1ZSgpWzBdOmIudmFsdWUoKTpiKX0pfSkscyhbInBvcCIsInB1c2giLCJzaGlmdCIsInNvcnQiLCJzcGxpY2UiLCJ1bnNoaWZ0Il0sZnVuY3Rpb24oZSl7dmFyIHQ9c2xbZV0scj0vXig/OnB1c2h8c29ydHx1bnNoaWZ0KSQvLnRlc3QoZSk/InRhcCI6InRocnUiLGk9L14oPzpwb3B8c2hpZnQpJC8udGVzdChlKTtuLnByb3RvdHlwZVtlXT1mdW5jdGlvbigpe3ZhciBlPWFyZ3VtZW50cztpZihpJiYhdGhpcy5fX2NoYWluX18pe3ZhciBuPXRoaXMudmFsdWUoKTtyZXR1cm4gdC5hcHBseShkZihuKT9uOltdLGUpfXJldHVybiB0aGlzW3JdKGZ1bmN0aW9uKG4pe3JldHVybiB0LmFwcGx5KGRmKG4pP246W10sZSl9KX19KSxscih2LnByb3RvdHlwZSxmdW5jdGlvbihlLHQpe3ZhciByPW5bdF07aWYocil7dmFyIGk9ci5uYW1lKyIiOyhlcFtpXXx8KGVwW2ldPVtdKSkucHVzaCh7bmFtZTp0LGZ1bmM6cn0pfX0pLGVwW1dpKG5lLG1lKS5uYW1lXT1be25hbWU6IndyYXBwZXIiLGZ1bmM6bmV9XSx2LnByb3RvdHlwZS5jbG9uZT1BLHYucHJvdG90eXBlLnJldmVyc2U9Syx2LnByb3RvdHlwZS52YWx1ZT1aLG4ucHJvdG90eXBlLmF0PXFwLG4ucHJvdG90eXBlLmNoYWluPUthLG4ucHJvdG90eXBlLmNvbW1pdD1KYSxuLnByb3RvdHlwZS5uZXh0PVlhLG4ucHJvdG90eXBlLnBsYW50PVphLG4ucHJvdG90eXBlLnJldmVyc2U9ZXMsbi5wcm90b3R5cGUudG9KU09OPW4ucHJvdG90eXBlLnZhbHVlT2Y9bi5wcm90b3R5cGUudmFsdWU9dHMsbi5wcm90b3R5cGUuZmlyc3Q9bi5wcm90b3R5cGUuaGVhZCxfbCYmKG4ucHJvdG90eXBlW19sXT1YYSksbn0oKTtPbi5fPUhuLChpPWZ1bmN0aW9uKCl7cmV0dXJuIEhufS5jYWxsKHQsbix0LHIpKSE9PW5lJiYoci5leHBvcnRzPWkpfSkuY2FsbCh0aGlzKX0pLmNhbGwodCxuKDExKSxuKDEwMikoZSkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcixpPW4oMjMpO3Quc2V0U2V0dGluZ3NTdHJpbmc9KHI9aS5jcmVhdGVBY3Rpb25zKHtTRVRfU0VUVElOR1NfU1RSSU5HOmZ1bmN0aW9uKGUpe3JldHVybntzZXR0aW5nc1N0cmluZzplfX0sU0VUX0NPTkZJR19TVFJJTkc6ZnVuY3Rpb24oZSl7cmV0dXJue2NvbmZpZ1N0cmluZzplfX0sT1BFTl9ISVNUT1JZOmZ1bmN0aW9uKCl7cmV0dXJue319LENMT1NFX0hJU1RPUlk6ZnVuY3Rpb24oKXtyZXR1cm57fX19KSxyLnNldFNldHRpbmdzU3RyaW5nKSx0LnNldENvbmZpZ1N0cmluZz1yLnNldENvbmZpZ1N0cmluZyx0Lm9wZW5IaXN0b3J5PXIub3Blbkhpc3RvcnksdC5jbG9zZUhpc3Rvcnk9ci5jbG9zZUhpc3Rvcnl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3ZhciBlPWFyZ3VtZW50cy5sZW5ndGg+MCYmdm9pZCAwIT09YXJndW1lbnRzWzBdP2FyZ3VtZW50c1swXToxMCx0PWFyZ3VtZW50c1sxXSxuPW5ldyBBcnJheShlKSxyPTAsaT0wLGM9MCxsPWZ1bmN0aW9uKHQpe25baV09dCxpPShpKzEpJWUscisrfSxwPWZ1bmN0aW9uKCl7aWYoMCE9cil7dmFyIHQ9bltjXTtyZXR1cm4gbltjXT1udWxsLHItLSxjPShjKzEpJWUsdH19LGY9ZnVuY3Rpb24oKXtmb3IodmFyIGU9W107cjspZS5wdXNoKHAoKSk7cmV0dXJuIGV9O3JldHVybntpc0VtcHR5OmZ1bmN0aW9uKCl7cmV0dXJuIDA9PXJ9LHB1dDpmdW5jdGlvbihwKXtpZihyPGUpbChwKTtlbHNle3ZhciBkPXZvaWQgMDtzd2l0Y2godCl7Y2FzZSBhOnRocm93IG5ldyBFcnJvcihvKTtjYXNlIHM6bltpXT1wLGk9KGkrMSklZSxjPWk7YnJlYWs7Y2FzZSB1OmQ9MiplLG49ZigpLHI9bi5sZW5ndGgsaT1uLmxlbmd0aCxjPTAsbi5sZW5ndGg9ZCxlPWQsbChwKX19fSx0YWtlOnAsZmx1c2g6Zn19bi5kKHQsImEiLGZ1bmN0aW9uKCl7cmV0dXJuIGx9KTt2YXIgaT1uKDIyKSxvPSJDaGFubmVsJ3MgQnVmZmVyIG92ZXJmbG93ISIsYT0xLHM9Myx1PTQsYz17aXNFbXB0eTppLnIscHV0OmkudSx0YWtlOmkudX0sbD17bm9uZTpmdW5jdGlvbigpe3JldHVybiBjfSxmaXhlZDpmdW5jdGlvbihlKXtyZXR1cm4gcihlLGEpfSxkcm9wcGluZzpmdW5jdGlvbihlKXtyZXR1cm4gcihlLDIpfSxzbGlkaW5nOmZ1bmN0aW9uKGUpe3JldHVybiByKGUscyl9LGV4cGFuZGluZzpmdW5jdGlvbihlKXtyZXR1cm4gcihlLHUpfX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtmPWV9ZnVuY3Rpb24gaShlKXtlJiYoRj1lLHQuc2NoZW1hRmV0Y2hlcj1uZXcgdy5TY2hlbWFGZXRjaGVyKGUpKX1mdW5jdGlvbiBvKGUpe3ZhciB0LG4scixpLG8sdSxjLGwsbSxnLHksdyxULEksTCxQLE0saixSLEIsJDtyZXR1cm4gcCh0aGlzLGZ1bmN0aW9uKHApe3N3aXRjaChwLmxhYmVsKXtjYXNlIDA6cmV0dXJuIHQ9ZS5wYXlsb2FkLm9wZXJhdGlvbk5hbWUsWzQsYi5zZWxlY3QoUy5nZXRTZWxlY3RlZFdvcmtzcGFjZUlkKV07Y2FzZSAxOnJldHVybiBuPXAuc2VudCgpLFs0LGIuc2VsZWN0KEQuZ2V0U2VsZWN0ZWRTZXNzaW9uKV07Y2FzZSAyOnJldHVybiByPXAuc2VudCgpLGk9e3F1ZXJ5OnIucXVlcnksb3BlcmF0aW9uTmFtZTp0LHZhcmlhYmxlczpELmdldFBhcnNlZFZhcmlhYmxlc0Zyb21TZXNzaW9uKHIpfSxvPUMubWFrZU9wZXJhdGlvbihpKSx1PXYuaXNTdWJzY3JpcHRpb24obyksWzQsYi5zZWxlY3QoUy5nZXRTZWxlY3RlZFdvcmtzcGFjZUlkKV07Y2FzZSAzOnJldHVybiBjPXAuc2VudCgpLFs0LGIuc2VsZWN0KFMuZ2V0U2V0dGluZ3MpXTtjYXNlIDQ6cmV0dXJuIGw9cC5zZW50KCksWzQsYi5wdXQoRS5zZXRTdWJzY3JpcHRpb25BY3RpdmUodi5pc1N1YnNjcmlwdGlvbihvKSkpXTtjYXNlIDU6cmV0dXJuIHAuc2VudCgpLFs0LGIucHV0KEUuc3RhcnRRdWVyeSgpKV07Y2FzZSA2OnJldHVybiBwLnNlbnQoKSxtPWgucGFyc2VIZWFkZXJzKHIuaGVhZGVycyksci50cmFjaW5nU3VwcG9ydGVkJiZyLnJlc3BvbnNlVHJhY2luZ09wZW4mJihtPU8uc2V0KG0sIlgtQXBvbGxvLVRyYWNpbmciLCIxIikpLGc9e2VuZHBvaW50OnIuZW5kcG9pbnQsaGVhZGVyczptLGNyZWRlbnRpYWxzOmxbInJlcXVlc3QuY3JlZGVudGlhbHMiXX0seT1GKGcsZiksdz15LmxpbmssVD15LnN1YnNjcmlwdGlvbkNsaWVudCxbNCxiLnB1dChFLnNldEN1cnJlbnRRdWVyeVN0YXJ0VGltZShuZXcgRGF0ZSkpXTtjYXNlIDc6cC5zZW50KCksST0hMSxMPXguZXZlbnRDaGFubmVsKGZ1bmN0aW9uKGUpe3ZhciB0PSExO1QmJnUmJlQub25EaXNjb25uZWN0ZWQoZnVuY3Rpb24oKXt0PSEwLGUoe2Vycm9yOm5ldyBFcnJvcigiQ291bGQgbm90IGNvbm5lY3QgdG8gd2Vic29ja2V0IGVuZHBvaW50ICIrZisiLiBQbGVhc2UgY2hlY2sgaWYgdGhlIGVuZHBvaW50IHVybCBpcyBjb3JyZWN0LiIpfSksZSh4LkVORCl9KTt2YXIgbj1kLmV4ZWN1dGUodyxvKS5zdWJzY3JpYmUoe25leHQ6ZnVuY3Rpb24odCl7ZSh7dmFsdWU6dH0pfSxlcnJvcjpmdW5jdGlvbih0KXtlKHtlcnJvcjp0fSksZSh4LkVORCl9LGNvbXBsZXRlOmZ1bmN0aW9uKCl7ZSh4LkVORCl9fSksaT1mdW5jdGlvbigpe2lmKCF0KXRyeXtuLnVuc3Vic2NyaWJlKCl9Y2F0Y2goZSl7Y29uc29sZS5lcnJvcihlKX19LGE9YysifiIrci5pZDtyZXR1cm4gTlthXT17dW5zdWJzY3JpYmU6aX0saX0pLHAubGFiZWw9ODtjYXNlIDg6cC50cnlzLnB1c2goWzgsLDIzLDI2XSkscC5sYWJlbD05O2Nhc2UgOTpyZXR1cm5bNCxiLnRha2UoTCldO2Nhc2UgMTA6cmV0dXJuIFA9cC5zZW50KCksKE09UC52YWx1ZSxqPVAuZXJyb3IsTSYmTS5leHRlbnNpb25zKT8oUj1NLmV4dGVuc2lvbnMsWzQsYi5wdXQoRS5zZXRSZXNwb25zZUV4dGVuc2lvbnMoUikpXSk6WzMsMTJdO2Nhc2UgMTE6cC5zZW50KCksTS5leHRlbnNpb25zLnRyYWNpbmcmJmxbInRyYWNpbmcuaGlkZVRyYWNpbmdSZXNwb25zZSJdJiZkZWxldGUgTS5leHRlbnNpb25zLnRyYWNpbmcscC5sYWJlbD0xMjtjYXNlIDEyOnJldHVybiBCPW5ldyBBLlJlc3BvbnNlUmVjb3JkKHtkYXRlOkpTT04uc3RyaW5naWZ5KE18fGEoaiksbnVsbCwyKSx0aW1lOm5ldyBEYXRlLHJlc3VsdElEOmsoKX0pLCQ9cyhqKSwiRmFpbGVkIHRvIGZldGNoIiE9PSQ/WzMsMTRdOls0LGIucHV0KEUuc2V0RW5kcG9pbnRVbnJlYWNoYWJsZShyLmVuZHBvaW50KSldO2Nhc2UgMTM6cC5zZW50KCkscC5sYWJlbD0xNDtjYXNlIDE0OnJldHVybiB1P0k/WzQsYi5wdXQoRS5jbGVhclJlc3BvbnNlcygpKV06WzMsMTZdOlszLDE4XTtjYXNlIDE1OnAuc2VudCgpLEk9ITEscC5sYWJlbD0xNjtjYXNlIDE2OnJldHVybls0LGIucHV0KEUuYWRkUmVzcG9uc2UobixyLmlkLEIpKV07Y2FzZSAxNzpyZXR1cm4gcC5zZW50KCksWzMsMjBdO2Nhc2UgMTg6cmV0dXJuWzQsYi5wdXQoRS5zZXRSZXNwb25zZShuLHIuaWQsQikpXTtjYXNlIDE5OnAuc2VudCgpLHAubGFiZWw9MjA7Y2FzZSAyMDpyZXR1cm5bNCxiLnB1dChfLmFkZEhpc3RvcnlJdGVtKHIpKV07Y2FzZSAyMTpyZXR1cm4gcC5zZW50KCksWzMsOV07Y2FzZSAyMjpyZXR1cm5bMywyNl07Y2FzZSAyMzpyZXR1cm5bNCxiLnB1dChFLnNldEN1cnJlbnRRdWVyeUVuZFRpbWUobmV3IERhdGUpKV07Y2FzZSAyNDpyZXR1cm4gcC5zZW50KCksWzQsYi5wdXQoRS5zdG9wUXVlcnkoci5pZCxuKSldO2Nhc2UgMjU6cmV0dXJuIHAuc2VudCgpLFs3XTtjYXNlIDI2OnJldHVyblsyXX19KX1mdW5jdGlvbiBhKGUsdCl7dm9pZCAwPT09dCYmKHQ9ITEpO3ZhciBuPXMoZSk7aWYoIkZhaWxlZCB0byBmZXRjaCI9PT1uKXtyZXR1cm57ZXJyb3I6IiIrbisodD8iIHNjaGVtYSI6IiIpKyIuIFBsZWFzZSBjaGVjayB5b3VyIGNvbm5lY3Rpb24ifX10cnl7cmV0dXJuIEpTT04ucGFyc2Uobil9Y2F0Y2goZSl7fXJldHVybntlcnJvcjpufX1mdW5jdGlvbiBzKGUpe3JldHVybiBlIGluc3RhbmNlb2YgRXJyb3I/ZS5yZXN1bHQmJiJvYmplY3QiPT09YyhlLnJlc3VsdCk/ZS5yZXN1bHQ6ZS5tZXNzYWdlOmV9ZnVuY3Rpb24gdShlKXt2YXIgdCxuLHIsaSxvLGEscyx1O3JldHVybiBwKHRoaXMsZnVuY3Rpb24oYyl7c3dpdGNoKGMubGFiZWwpe2Nhc2UgMDpyZXR1cm4gdD1lLnBheWxvYWQsbj10LnNlc3Npb25JZCxyPXQud29ya3NwYWNlSWQsWzQsYi5zZWxlY3QoRC5nZXRTZXNzaW9uc1N0YXRlKV07Y2FzZSAxOnJldHVybiBpPWMuc2VudCgpLnNlc3Npb25zLG89aS5nZXQobiksWzQscnx8Yi5zZWxlY3QoUy5nZXRTZWxlY3RlZFdvcmtzcGFjZUlkKV07Y2FzZSAyOnJldHVybiBhPWMuc2VudCgpLHM9YSsifiIrby5pZCx1PU5bc10sdSYmdS51bnN1YnNjcmliZSYmdS51bnN1YnNjcmliZSgpLGRlbGV0ZSBOW3NdLFsyXX19KX12YXIgYz0iZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmInN5bWJvbCI9PT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiZlLmNvbnN0cnVjdG9yPT09U3ltYm9sJiZlIT09U3ltYm9sLnByb3RvdHlwZT8ic3ltYm9sIjp0eXBlb2YgZX0sbD1mdW5jdGlvbigpe3JldHVybiBsPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPTEscj1hcmd1bWVudHMubGVuZ3RoO248cjtuKyspe3Q9YXJndW1lbnRzW25dO2Zvcih2YXIgaSBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LGkpJiYoZVtpXT10W2ldKX1yZXR1cm4gZX0sbC5hcHBseSh0aGlzLGFyZ3VtZW50cyl9LHA9ZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gcihbZSx0XSl9fWZ1bmN0aW9uIHIobil7aWYoaSl0aHJvdyBuZXcgVHlwZUVycm9yKCJHZW5lcmF0b3IgaXMgYWxyZWFkeSBleGVjdXRpbmcuIik7Zm9yKDt1Oyl0cnl7aWYoaT0xLG8mJihhPTImblswXT9vLnJldHVybjpuWzBdP28udGhyb3d8fCgoYT1vLnJldHVybikmJmEuY2FsbChvKSwwKTpvLm5leHQpJiYhKGE9YS5jYWxsKG8sblsxXSkpLmRvbmUpcmV0dXJuIGE7c3dpdGNoKG89MCxhJiYobj1bMiZuWzBdLGEudmFsdWVdKSxuWzBdKXtjYXNlIDA6Y2FzZSAxOmE9bjticmVhaztjYXNlIDQ6cmV0dXJuIHUubGFiZWwrKyx7dmFsdWU6blsxXSxkb25lOiExfTtjYXNlIDU6dS5sYWJlbCsrLG89blsxXSxuPVswXTtjb250aW51ZTtjYXNlIDc6bj11Lm9wcy5wb3AoKSx1LnRyeXMucG9wKCk7Y29udGludWU7ZGVmYXVsdDppZihhPXUudHJ5cywhKGE9YS5sZW5ndGg+MCYmYVthLmxlbmd0aC0xXSkmJig2PT09blswXXx8Mj09PW5bMF0pKXt1PTA7Y29udGludWV9aWYoMz09PW5bMF0mJighYXx8blsxXT5hWzBdJiZuWzFdPGFbM10pKXt1LmxhYmVsPW5bMV07YnJlYWt9aWYoNj09PW5bMF0mJnUubGFiZWw8YVsxXSl7dS5sYWJlbD1hWzFdLGE9bjticmVha31pZihhJiZ1LmxhYmVsPGFbMl0pe3UubGFiZWw9YVsyXSx1Lm9wcy5wdXNoKG4pO2JyZWFrfWFbMl0mJnUub3BzLnBvcCgpLHUudHJ5cy5wb3AoKTtjb250aW51ZX1uPXQuY2FsbChlLHUpfWNhdGNoKGUpe249WzYsZV0sbz0wfWZpbmFsbHl7aT1hPTB9aWYoNSZuWzBdKXRocm93IG5bMV07cmV0dXJue3ZhbHVlOm5bMF0/blsxXTp2b2lkIDAsZG9uZTohMH19dmFyIGksbyxhLHMsdT17bGFiZWw6MCxzZW50OmZ1bmN0aW9uKCl7aWYoMSZhWzBdKXRocm93IGFbMV07cmV0dXJuIGFbMV19LHRyeXM6W10sb3BzOltdfTtyZXR1cm4gcz17bmV4dDpuKDApLHRocm93Om4oMSkscmV0dXJuOm4oMil9LCJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiYoc1tTeW1ib2wuaXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9KSxzfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGYsZD1uKDc4KSxoPW4oMTc1KSxtPW4oMTc2KSxnPW4oMzg0KSx5PW4oMzg3KSx2PW4oMzg5KSxiPW4oNTUpLHg9bigxMDQpLEM9bigxNzgpLEU9bigxNiksRD1uKDEyKSx3PW4oNTAxKSxTPW4oMTcpLGs9big2NCksQT1uKDg1KSxfPW4oMTMxKSxUPW4oNjUpLE89bigxNCk7dC5zZXRTdWJzY3JpcHRpb25FbmRwb2ludD1yLHQuZGVmYXVsdExpbmtDcmVhdG9yPWZ1bmN0aW9uKGUsdCl7dmFyIG49e30scj1lLmhlYWRlcnMsaT1lLmNyZWRlbnRpYWxzO3ImJihuPWwoe30scikpO3ZhciBvPW5ldyBnLkh0dHBMaW5rKHt1cmk6ZS5lbmRwb2ludCxoZWFkZXJzOnIsY3JlZGVudGlhbHM6aX0pO2lmKCF0KXJldHVybntsaW5rOm99O3ZhciBhPW5ldyBtLlN1YnNjcmlwdGlvbkNsaWVudCh0LHt0aW1lb3V0OjJlNCxsYXp5OiEwLGNvbm5lY3Rpb25QYXJhbXM6bn0pLHM9bmV3IHkuV2ViU29ja2V0TGluayhhKTtyZXR1cm57bGluazpkLkFwb2xsb0xpbmsuc3BsaXQoZnVuY3Rpb24oZSl7cmV0dXJuIHYuaXNTdWJzY3JpcHRpb24oZSl9LHMsbyksc3Vic2NyaXB0aW9uQ2xpZW50OmF9fTt2YXIgRj10LmRlZmF1bHRMaW5rQ3JlYXRvcjt0LnNjaGVtYUZldGNoZXI9bmV3IHcuU2NoZW1hRmV0Y2hlcihGKSx3aW5kb3cuc2NoZW1hRmV0Y2hlcj10LnNjaGVtYUZldGNoZXIsdC5zZXRMaW5rQ3JlYXRvcj1pO3ZhciBOPXt9O3QuZm9ybWF0RXJyb3I9YSx0LmZlY3RoaW5nU2FnYXM9W2IudGFrZUV2ZXJ5KCJSVU5fUVVFUlkiLFQuc2FmZWx5KG8pKSxiLnRha2VMYXRlc3QoIlNUT1BfUVVFUlkiLFQuc2FmZWx5KHUpKV19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oMzYzKTtuLmQodCwiZW1wdHkiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuY30pLG4uZCh0LCJmcm9tIixmdW5jdGlvbigpe3JldHVybiByLmV9KSxuLmQodCwic3BsaXQiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuZn0pLG4uZCh0LCJjb25jYXQiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuYn0pLG4uZCh0LCJBcG9sbG9MaW5rIixmdW5jdGlvbigpe3JldHVybiByLmF9KSxuLmQodCwiZXhlY3V0ZSIsZnVuY3Rpb24oKXtyZXR1cm4gci5kfSk7dmFyIGk9bigxNzEpO24uZCh0LCJjcmVhdGVPcGVyYXRpb24iLGZ1bmN0aW9uKCl7cmV0dXJuIGkuYn0pLG4uZCh0LCJtYWtlUHJvbWlzZSIsZnVuY3Rpb24oKXtyZXR1cm4gaS5mfSksbi5kKHQsInRvUHJvbWlzZSIsZnVuY3Rpb24oKXtyZXR1cm4gaS5nfSksbi5kKHQsImZyb21Qcm9taXNlIixmdW5jdGlvbigpe3JldHVybiBpLmR9KSxuLmQodCwiZnJvbUVycm9yIixmdW5jdGlvbigpe3JldHVybiBpLmN9KTt2YXIgbz1uKDEwNik7bi5kKHQsIk9ic2VydmFibGUiLGZ1bmN0aW9uKCl7cmV0dXJuIG8uYX0pfSxmdW5jdGlvbihlLHQpe2UuZXhwb3J0cz1mdW5jdGlvbihlKXtpZighZS53ZWJwYWNrUG9seWZpbGwpe3ZhciB0PU9iamVjdC5jcmVhdGUoZSk7dC5jaGlsZHJlbnx8KHQuY2hpbGRyZW49W10pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJsb2FkZWQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB0Lmx9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlkIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdC5pfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJleHBvcnRzIix7ZW51bWVyYWJsZTohMH0pLHQud2VicGFja1BvbHlmaWxsPTF9cmV0dXJuIHR9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2YXIgbj0ic3RyaW5nIj09PXR5cGVvZiBlP25ldyBvZS5Tb3VyY2UoZSk6ZTtpZighKG4gaW5zdGFuY2VvZiBvZS5Tb3VyY2UpKXRocm93IG5ldyBUeXBlRXJyb3IoIk11c3QgcHJvdmlkZSBTb3VyY2UuIFJlY2VpdmVkOiAiK1N0cmluZyhuKSk7cmV0dXJuIHMoKDAsc2UuY3JlYXRlTGV4ZXIpKG4sdHx8e30pKX1mdW5jdGlvbiBpKGUsdCl7dmFyIG49InN0cmluZyI9PT10eXBlb2YgZT9uZXcgb2UuU291cmNlKGUpOmUscj0oMCxzZS5jcmVhdGVMZXhlcikobix0fHx7fSk7ZWUocixzZS5Ub2tlbktpbmQuU09GKTt2YXIgaT1FKHIsITEpO3JldHVybiBlZShyLHNlLlRva2VuS2luZC5FT0YpLGl9ZnVuY3Rpb24gbyhlLHQpe3ZhciBuPSJzdHJpbmciPT09dHlwZW9mIGU/bmV3IG9lLlNvdXJjZShlKTplLHI9KDAsc2UuY3JlYXRlTGV4ZXIpKG4sdHx8e30pO2VlKHIsc2UuVG9rZW5LaW5kLlNPRik7dmFyIGk9TyhyKTtyZXR1cm4gZWUocixzZS5Ub2tlbktpbmQuRU9GKSxpfWZ1bmN0aW9uIGEoZSl7dmFyIHQ9ZWUoZSxzZS5Ub2tlbktpbmQuTkFNRSk7cmV0dXJue2tpbmQ6dWUuTkFNRSx2YWx1ZTp0LnZhbHVlLGxvYzpKKGUsdCl9fWZ1bmN0aW9uIHMoZSl7dmFyIHQ9ZS50b2tlbjtlZShlLHNlLlRva2VuS2luZC5TT0YpO3ZhciBuPVtdO2Rve24ucHVzaCh1KGUpKX13aGlsZSghWihlLHNlLlRva2VuS2luZC5FT0YpKTtyZXR1cm57a2luZDp1ZS5ET0NVTUVOVCxkZWZpbml0aW9uczpuLGxvYzpKKGUsdCl9fWZ1bmN0aW9uIHUoZSl7aWYoWChlLHNlLlRva2VuS2luZC5CUkFDRV9MKSlyZXR1cm4gYyhlKTtpZihYKGUsc2UuVG9rZW5LaW5kLk5BTUUpKXN3aXRjaChlLnRva2VuLnZhbHVlKXtjYXNlInF1ZXJ5IjpjYXNlIm11dGF0aW9uIjpjYXNlInN1YnNjcmlwdGlvbiI6cmV0dXJuIGMoZSk7Y2FzZSJmcmFnbWVudCI6cmV0dXJuIHgoZSk7Y2FzZSJzY2hlbWEiOmNhc2Uic2NhbGFyIjpjYXNlInR5cGUiOmNhc2UiaW50ZXJmYWNlIjpjYXNlInVuaW9uIjpjYXNlImVudW0iOmNhc2UiaW5wdXQiOmNhc2UiZXh0ZW5kIjpjYXNlImRpcmVjdGl2ZSI6cmV0dXJuIE4oZSl9dGhyb3cgbmUoZSl9ZnVuY3Rpb24gYyhlKXt2YXIgdD1lLnRva2VuO2lmKFgoZSxzZS5Ub2tlbktpbmQuQlJBQ0VfTCkpcmV0dXJue2tpbmQ6dWUuT1BFUkFUSU9OX0RFRklOSVRJT04sb3BlcmF0aW9uOiJxdWVyeSIsbmFtZTpudWxsLHZhcmlhYmxlRGVmaW5pdGlvbnM6bnVsbCxkaXJlY3RpdmVzOltdLHNlbGVjdGlvblNldDpoKGUpLGxvYzpKKGUsdCl9O3ZhciBuPWwoZSkscj12b2lkIDA7cmV0dXJuIFgoZSxzZS5Ub2tlbktpbmQuTkFNRSkmJihyPWEoZSkpLHtraW5kOnVlLk9QRVJBVElPTl9ERUZJTklUSU9OLG9wZXJhdGlvbjpuLG5hbWU6cix2YXJpYWJsZURlZmluaXRpb25zOnAoZSksZGlyZWN0aXZlczpfKGUpLHNlbGVjdGlvblNldDpoKGUpLGxvYzpKKGUsdCl9fWZ1bmN0aW9uIGwoZSl7dmFyIHQ9ZWUoZSxzZS5Ub2tlbktpbmQuTkFNRSk7c3dpdGNoKHQudmFsdWUpe2Nhc2UicXVlcnkiOnJldHVybiJxdWVyeSI7Y2FzZSJtdXRhdGlvbiI6cmV0dXJuIm11dGF0aW9uIjtjYXNlInN1YnNjcmlwdGlvbiI6cmV0dXJuInN1YnNjcmlwdGlvbiJ9dGhyb3cgbmUoZSx0KX1mdW5jdGlvbiBwKGUpe3JldHVybiBYKGUsc2UuVG9rZW5LaW5kLlBBUkVOX0wpP2llKGUsc2UuVG9rZW5LaW5kLlBBUkVOX0wsZixzZS5Ub2tlbktpbmQuUEFSRU5fUik6W119ZnVuY3Rpb24gZihlKXt2YXIgdD1lLnRva2VuO3JldHVybntraW5kOnVlLlZBUklBQkxFX0RFRklOSVRJT04sdmFyaWFibGU6ZChlKSx0eXBlOihlZShlLHNlLlRva2VuS2luZC5DT0xPTiksTyhlKSksZGVmYXVsdFZhbHVlOlooZSxzZS5Ub2tlbktpbmQuRVFVQUxTKT9FKGUsITApOm51bGwsbG9jOkooZSx0KX19ZnVuY3Rpb24gZChlKXt2YXIgdD1lLnRva2VuO3JldHVybiBlZShlLHNlLlRva2VuS2luZC5ET0xMQVIpLHtraW5kOnVlLlZBUklBQkxFLG5hbWU6YShlKSxsb2M6SihlLHQpfX1mdW5jdGlvbiBoKGUpe3ZhciB0PWUudG9rZW47cmV0dXJue2tpbmQ6dWUuU0VMRUNUSU9OX1NFVCxzZWxlY3Rpb25zOmllKGUsc2UuVG9rZW5LaW5kLkJSQUNFX0wsbSxzZS5Ub2tlbktpbmQuQlJBQ0VfUiksbG9jOkooZSx0KX19ZnVuY3Rpb24gbShlKXtyZXR1cm4gWChlLHNlLlRva2VuS2luZC5TUFJFQUQpP2IoZSk6ZyhlKX1mdW5jdGlvbiBnKGUpe3ZhciB0PWUudG9rZW4sbj1hKGUpLHI9dm9pZCAwLGk9dm9pZCAwO3JldHVybiBaKGUsc2UuVG9rZW5LaW5kLkNPTE9OKT8ocj1uLGk9YShlKSk6KHI9bnVsbCxpPW4pLHtraW5kOnVlLkZJRUxELGFsaWFzOnIsbmFtZTppLGFyZ3VtZW50czp5KGUpLGRpcmVjdGl2ZXM6XyhlKSxzZWxlY3Rpb25TZXQ6WChlLHNlLlRva2VuS2luZC5CUkFDRV9MKT9oKGUpOm51bGwsbG9jOkooZSx0KX19ZnVuY3Rpb24geShlKXtyZXR1cm4gWChlLHNlLlRva2VuS2luZC5QQVJFTl9MKT9pZShlLHNlLlRva2VuS2luZC5QQVJFTl9MLHYsc2UuVG9rZW5LaW5kLlBBUkVOX1IpOltdfWZ1bmN0aW9uIHYoZSl7dmFyIHQ9ZS50b2tlbjtyZXR1cm57a2luZDp1ZS5BUkdVTUVOVCxuYW1lOmEoZSksdmFsdWU6KGVlKGUsc2UuVG9rZW5LaW5kLkNPTE9OKSxFKGUsITEpKSxsb2M6SihlLHQpfX1mdW5jdGlvbiBiKGUpe3ZhciB0PWUudG9rZW47aWYoZWUoZSxzZS5Ub2tlbktpbmQuU1BSRUFEKSxYKGUsc2UuVG9rZW5LaW5kLk5BTUUpJiYib24iIT09ZS50b2tlbi52YWx1ZSlyZXR1cm57a2luZDp1ZS5GUkFHTUVOVF9TUFJFQUQsbmFtZTpDKGUpLGRpcmVjdGl2ZXM6XyhlKSxsb2M6SihlLHQpfTt2YXIgbj1udWxsO3JldHVybiJvbiI9PT1lLnRva2VuLnZhbHVlJiYoZS5hZHZhbmNlKCksbj1GKGUpKSx7a2luZDp1ZS5JTkxJTkVfRlJBR01FTlQsdHlwZUNvbmRpdGlvbjpuLGRpcmVjdGl2ZXM6XyhlKSxzZWxlY3Rpb25TZXQ6aChlKSxsb2M6SihlLHQpfX1mdW5jdGlvbiB4KGUpe3ZhciB0PWUudG9rZW47cmV0dXJuIHRlKGUsImZyYWdtZW50Iikse2tpbmQ6dWUuRlJBR01FTlRfREVGSU5JVElPTixuYW1lOkMoZSksdHlwZUNvbmRpdGlvbjoodGUoZSwib24iKSxGKGUpKSxkaXJlY3RpdmVzOl8oZSksc2VsZWN0aW9uU2V0OmgoZSksbG9jOkooZSx0KX19ZnVuY3Rpb24gQyhlKXtpZigib24iPT09ZS50b2tlbi52YWx1ZSl0aHJvdyBuZShlKTtyZXR1cm4gYShlKX1mdW5jdGlvbiBFKGUsdCl7dmFyIG49ZS50b2tlbjtzd2l0Y2gobi5raW5kKXtjYXNlIHNlLlRva2VuS2luZC5CUkFDS0VUX0w6cmV0dXJuIFMoZSx0KTtjYXNlIHNlLlRva2VuS2luZC5CUkFDRV9MOnJldHVybiBrKGUsdCk7Y2FzZSBzZS5Ub2tlbktpbmQuSU5UOnJldHVybiBlLmFkdmFuY2UoKSx7a2luZDp1ZS5JTlQsdmFsdWU6bi52YWx1ZSxsb2M6SihlLG4pfTtjYXNlIHNlLlRva2VuS2luZC5GTE9BVDpyZXR1cm4gZS5hZHZhbmNlKCkse2tpbmQ6dWUuRkxPQVQsdmFsdWU6bi52YWx1ZSxsb2M6SihlLG4pfTtjYXNlIHNlLlRva2VuS2luZC5TVFJJTkc6cmV0dXJuIGUuYWR2YW5jZSgpLHtraW5kOnVlLlNUUklORyx2YWx1ZTpuLnZhbHVlLGxvYzpKKGUsbil9O2Nhc2Ugc2UuVG9rZW5LaW5kLk5BTUU6cmV0dXJuInRydWUiPT09bi52YWx1ZXx8ImZhbHNlIj09PW4udmFsdWU/KGUuYWR2YW5jZSgpLHtraW5kOnVlLkJPT0xFQU4sdmFsdWU6InRydWUiPT09bi52YWx1ZSxsb2M6SihlLG4pfSk6Im51bGwiPT09bi52YWx1ZT8oZS5hZHZhbmNlKCkse2tpbmQ6dWUuTlVMTCxsb2M6SihlLG4pfSk6KGUuYWR2YW5jZSgpLHtraW5kOnVlLkVOVU0sdmFsdWU6bi52YWx1ZSxsb2M6SihlLG4pfSk7Y2FzZSBzZS5Ub2tlbktpbmQuRE9MTEFSOmlmKCF0KXJldHVybiBkKGUpfXRocm93IG5lKGUpfWZ1bmN0aW9uIEQoZSl7cmV0dXJuIEUoZSwhMCl9ZnVuY3Rpb24gdyhlKXtyZXR1cm4gRShlLCExKX1mdW5jdGlvbiBTKGUsdCl7dmFyIG49ZS50b2tlbixyPXQ/RDp3O3JldHVybntraW5kOnVlLkxJU1QsdmFsdWVzOnJlKGUsc2UuVG9rZW5LaW5kLkJSQUNLRVRfTCxyLHNlLlRva2VuS2luZC5CUkFDS0VUX1IpLGxvYzpKKGUsbil9fWZ1bmN0aW9uIGsoZSx0KXt2YXIgbj1lLnRva2VuO2VlKGUsc2UuVG9rZW5LaW5kLkJSQUNFX0wpO2Zvcih2YXIgcj1bXTshWihlLHNlLlRva2VuS2luZC5CUkFDRV9SKTspci5wdXNoKEEoZSx0KSk7cmV0dXJue2tpbmQ6dWUuT0JKRUNULGZpZWxkczpyLGxvYzpKKGUsbil9fWZ1bmN0aW9uIEEoZSx0KXt2YXIgbj1lLnRva2VuO3JldHVybntraW5kOnVlLk9CSkVDVF9GSUVMRCxuYW1lOmEoZSksdmFsdWU6KGVlKGUsc2UuVG9rZW5LaW5kLkNPTE9OKSxFKGUsdCkpLGxvYzpKKGUsbil9fWZ1bmN0aW9uIF8oZSl7Zm9yKHZhciB0PVtdO1goZSxzZS5Ub2tlbktpbmQuQVQpOyl0LnB1c2goVChlKSk7cmV0dXJuIHR9ZnVuY3Rpb24gVChlKXt2YXIgdD1lLnRva2VuO3JldHVybiBlZShlLHNlLlRva2VuS2luZC5BVCkse2tpbmQ6dWUuRElSRUNUSVZFLG5hbWU6YShlKSxhcmd1bWVudHM6eShlKSxsb2M6SihlLHQpfX1mdW5jdGlvbiBPKGUpe3ZhciB0PWUudG9rZW4sbj12b2lkIDA7cmV0dXJuIFooZSxzZS5Ub2tlbktpbmQuQlJBQ0tFVF9MKT8obj1PKGUpLGVlKGUsc2UuVG9rZW5LaW5kLkJSQUNLRVRfUiksbj17a2luZDp1ZS5MSVNUX1RZUEUsdHlwZTpuLGxvYzpKKGUsdCl9KTpuPUYoZSksWihlLHNlLlRva2VuS2luZC5CQU5HKT97a2luZDp1ZS5OT05fTlVMTF9UWVBFLHR5cGU6bixsb2M6SihlLHQpfTpufWZ1bmN0aW9uIEYoZSl7dmFyIHQ9ZS50b2tlbjtyZXR1cm57a2luZDp1ZS5OQU1FRF9UWVBFLG5hbWU6YShlKSxsb2M6SihlLHQpfX1mdW5jdGlvbiBOKGUpe2lmKFgoZSxzZS5Ub2tlbktpbmQuTkFNRSkpc3dpdGNoKGUudG9rZW4udmFsdWUpe2Nhc2Uic2NoZW1hIjpyZXR1cm4gSShlKTtjYXNlInNjYWxhciI6cmV0dXJuIFAoZSk7Y2FzZSJ0eXBlIjpyZXR1cm4gTShlKTtjYXNlImludGVyZmFjZSI6cmV0dXJuIFUoZSk7Y2FzZSJ1bmlvbiI6cmV0dXJuIHooZSk7Y2FzZSJlbnVtIjpyZXR1cm4gVihlKTtjYXNlImlucHV0IjpyZXR1cm4gSChlKTtjYXNlImV4dGVuZCI6cmV0dXJuIFcoZSk7Y2FzZSJkaXJlY3RpdmUiOnJldHVybiBRKGUpfXRocm93IG5lKGUpfWZ1bmN0aW9uIEkoZSl7dmFyIHQ9ZS50b2tlbjt0ZShlLCJzY2hlbWEiKTt2YXIgbj1fKGUpLHI9aWUoZSxzZS5Ub2tlbktpbmQuQlJBQ0VfTCxMLHNlLlRva2VuS2luZC5CUkFDRV9SKTtyZXR1cm57a2luZDp1ZS5TQ0hFTUFfREVGSU5JVElPTixkaXJlY3RpdmVzOm4sb3BlcmF0aW9uVHlwZXM6cixsb2M6SihlLHQpfX1mdW5jdGlvbiBMKGUpe3ZhciB0PWUudG9rZW4sbj1sKGUpO2VlKGUsc2UuVG9rZW5LaW5kLkNPTE9OKTt2YXIgcj1GKGUpO3JldHVybntraW5kOnVlLk9QRVJBVElPTl9UWVBFX0RFRklOSVRJT04sb3BlcmF0aW9uOm4sdHlwZTpyLGxvYzpKKGUsdCl9fWZ1bmN0aW9uIFAoZSl7dmFyIHQ9ZS50b2tlbjt0ZShlLCJzY2FsYXIiKTt2YXIgbj1hKGUpLHI9XyhlKTtyZXR1cm57a2luZDp1ZS5TQ0FMQVJfVFlQRV9ERUZJTklUSU9OLG5hbWU6bixkaXJlY3RpdmVzOnIsbG9jOkooZSx0KX19ZnVuY3Rpb24gTShlKXt2YXIgdD1lLnRva2VuO3RlKGUsInR5cGUiKTt2YXIgbj1hKGUpLHI9aihlKSxpPV8oZSksbz1yZShlLHNlLlRva2VuS2luZC5CUkFDRV9MLFIsc2UuVG9rZW5LaW5kLkJSQUNFX1IpO3JldHVybntraW5kOnVlLk9CSkVDVF9UWVBFX0RFRklOSVRJT04sbmFtZTpuLGludGVyZmFjZXM6cixkaXJlY3RpdmVzOmksZmllbGRzOm8sbG9jOkooZSx0KX19ZnVuY3Rpb24gaihlKXt2YXIgdD1bXTtpZigiaW1wbGVtZW50cyI9PT1lLnRva2VuLnZhbHVlKXtlLmFkdmFuY2UoKTtkb3t0LnB1c2goRihlKSl9d2hpbGUoWChlLHNlLlRva2VuS2luZC5OQU1FKSl9cmV0dXJuIHR9ZnVuY3Rpb24gUihlKXt2YXIgdD1lLnRva2VuLG49YShlKSxyPUIoZSk7ZWUoZSxzZS5Ub2tlbktpbmQuQ09MT04pO3ZhciBpPU8oZSksbz1fKGUpO3JldHVybntraW5kOnVlLkZJRUxEX0RFRklOSVRJT04sbmFtZTpuLGFyZ3VtZW50czpyLHR5cGU6aSxkaXJlY3RpdmVzOm8sbG9jOkooZSx0KX19ZnVuY3Rpb24gQihlKXtyZXR1cm4gWChlLHNlLlRva2VuS2luZC5QQVJFTl9MKT9pZShlLHNlLlRva2VuS2luZC5QQVJFTl9MLCQsc2UuVG9rZW5LaW5kLlBBUkVOX1IpOltdfWZ1bmN0aW9uICQoZSl7dmFyIHQ9ZS50b2tlbixuPWEoZSk7ZWUoZSxzZS5Ub2tlbktpbmQuQ09MT04pO3ZhciByPU8oZSksaT1udWxsO1ooZSxzZS5Ub2tlbktpbmQuRVFVQUxTKSYmKGk9RChlKSk7dmFyIG89XyhlKTtyZXR1cm57a2luZDp1ZS5JTlBVVF9WQUxVRV9ERUZJTklUSU9OLG5hbWU6bix0eXBlOnIsZGVmYXVsdFZhbHVlOmksZGlyZWN0aXZlczpvLGxvYzpKKGUsdCl9fWZ1bmN0aW9uIFUoZSl7dmFyIHQ9ZS50b2tlbjt0ZShlLCJpbnRlcmZhY2UiKTt2YXIgbj1hKGUpLHI9XyhlKSxpPXJlKGUsc2UuVG9rZW5LaW5kLkJSQUNFX0wsUixzZS5Ub2tlbktpbmQuQlJBQ0VfUik7cmV0dXJue2tpbmQ6dWUuSU5URVJGQUNFX1RZUEVfREVGSU5JVElPTixuYW1lOm4sZGlyZWN0aXZlczpyLGZpZWxkczppLGxvYzpKKGUsdCl9fWZ1bmN0aW9uIHooZSl7dmFyIHQ9ZS50b2tlbjt0ZShlLCJ1bmlvbiIpO3ZhciBuPWEoZSkscj1fKGUpO2VlKGUsc2UuVG9rZW5LaW5kLkVRVUFMUyk7dmFyIGk9RyhlKTtyZXR1cm57a2luZDp1ZS5VTklPTl9UWVBFX0RFRklOSVRJT04sbmFtZTpuLGRpcmVjdGl2ZXM6cix0eXBlczppLGxvYzpKKGUsdCl9fWZ1bmN0aW9uIEcoZSl7WihlLHNlLlRva2VuS2luZC5QSVBFKTt2YXIgdD1bXTtkb3t0LnB1c2goRihlKSl9d2hpbGUoWihlLHNlLlRva2VuS2luZC5QSVBFKSk7cmV0dXJuIHR9ZnVuY3Rpb24gVihlKXt2YXIgdD1lLnRva2VuO3RlKGUsImVudW0iKTt2YXIgbj1hKGUpLHI9XyhlKSxpPWllKGUsc2UuVG9rZW5LaW5kLkJSQUNFX0wscSxzZS5Ub2tlbktpbmQuQlJBQ0VfUik7cmV0dXJue2tpbmQ6dWUuRU5VTV9UWVBFX0RFRklOSVRJT04sbmFtZTpuLGRpcmVjdGl2ZXM6cix2YWx1ZXM6aSxsb2M6SihlLHQpfX1mdW5jdGlvbiBxKGUpe3ZhciB0PWUudG9rZW4sbj1hKGUpLHI9XyhlKTtyZXR1cm57a2luZDp1ZS5FTlVNX1ZBTFVFX0RFRklOSVRJT04sbmFtZTpuLGRpcmVjdGl2ZXM6cixsb2M6SihlLHQpfX1mdW5jdGlvbiBIKGUpe3ZhciB0PWUudG9rZW47dGUoZSwiaW5wdXQiKTt2YXIgbj1hKGUpLHI9XyhlKSxpPXJlKGUsc2UuVG9rZW5LaW5kLkJSQUNFX0wsJCxzZS5Ub2tlbktpbmQuQlJBQ0VfUik7cmV0dXJue2tpbmQ6dWUuSU5QVVRfT0JKRUNUX1RZUEVfREVGSU5JVElPTixuYW1lOm4sZGlyZWN0aXZlczpyLGZpZWxkczppLGxvYzpKKGUsdCl9fWZ1bmN0aW9uIFcoZSl7dmFyIHQ9ZS50b2tlbjt0ZShlLCJleHRlbmQiKTt2YXIgbj1NKGUpO3JldHVybntraW5kOnVlLlRZUEVfRVhURU5TSU9OX0RFRklOSVRJT04sZGVmaW5pdGlvbjpuLGxvYzpKKGUsdCl9fWZ1bmN0aW9uIFEoZSl7dmFyIHQ9ZS50b2tlbjt0ZShlLCJkaXJlY3RpdmUiKSxlZShlLHNlLlRva2VuS2luZC5BVCk7dmFyIG49YShlKSxyPUIoZSk7dGUoZSwib24iKTt2YXIgaT1LKGUpO3JldHVybntraW5kOnVlLkRJUkVDVElWRV9ERUZJTklUSU9OLG5hbWU6bixhcmd1bWVudHM6cixsb2NhdGlvbnM6aSxsb2M6SihlLHQpfX1mdW5jdGlvbiBLKGUpe1ooZSxzZS5Ub2tlbktpbmQuUElQRSk7dmFyIHQ9W107ZG97dC5wdXNoKGEoZSkpfXdoaWxlKFooZSxzZS5Ub2tlbktpbmQuUElQRSkpO3JldHVybiB0fWZ1bmN0aW9uIEooZSx0KXtpZighZS5vcHRpb25zLm5vTG9jYXRpb24pcmV0dXJuIG5ldyBZKHQsZS5sYXN0VG9rZW4sZS5zb3VyY2UpfWZ1bmN0aW9uIFkoZSx0LG4pe3RoaXMuc3RhcnQ9ZS5zdGFydCx0aGlzLmVuZD10LmVuZCx0aGlzLnN0YXJ0VG9rZW49ZSx0aGlzLmVuZFRva2VuPXQsdGhpcy5zb3VyY2U9bn1mdW5jdGlvbiBYKGUsdCl7cmV0dXJuIGUudG9rZW4ua2luZD09PXR9ZnVuY3Rpb24gWihlLHQpe3ZhciBuPWUudG9rZW4ua2luZD09PXQ7cmV0dXJuIG4mJmUuYWR2YW5jZSgpLG59ZnVuY3Rpb24gZWUoZSx0KXt2YXIgbj1lLnRva2VuO2lmKG4ua2luZD09PXQpcmV0dXJuIGUuYWR2YW5jZSgpLG47dGhyb3coMCxhZS5zeW50YXhFcnJvcikoZS5zb3VyY2Usbi5zdGFydCwiRXhwZWN0ZWQgIit0KyIsIGZvdW5kICIrKDAsc2UuZ2V0VG9rZW5EZXNjKShuKSl9ZnVuY3Rpb24gdGUoZSx0KXt2YXIgbj1lLnRva2VuO2lmKG4ua2luZD09PXNlLlRva2VuS2luZC5OQU1FJiZuLnZhbHVlPT09dClyZXR1cm4gZS5hZHZhbmNlKCksbjt0aHJvdygwLGFlLnN5bnRheEVycm9yKShlLnNvdXJjZSxuLnN0YXJ0LCdFeHBlY3RlZCAiJyt0KyciLCBmb3VuZCAnKygwLHNlLmdldFRva2VuRGVzYykobikpfWZ1bmN0aW9uIG5lKGUsdCl7dmFyIG49dHx8ZS50b2tlbjtyZXR1cm4oMCxhZS5zeW50YXhFcnJvcikoZS5zb3VyY2Usbi5zdGFydCwiVW5leHBlY3RlZCAiKygwLHNlLmdldFRva2VuRGVzYykobikpfWZ1bmN0aW9uIHJlKGUsdCxuLHIpe2VlKGUsdCk7Zm9yKHZhciBpPVtdOyFaKGUscik7KWkucHVzaChuKGUpKTtyZXR1cm4gaX1mdW5jdGlvbiBpZShlLHQsbixyKXtlZShlLHQpO2Zvcih2YXIgaT1bbihlKV07IVooZSxyKTspaS5wdXNoKG4oZSkpO3JldHVybiBpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnBhcnNlPXIsdC5wYXJzZVZhbHVlPWksdC5wYXJzZVR5cGU9byx0LnBhcnNlQ29uc3RWYWx1ZT1ELHQucGFyc2VUeXBlUmVmZXJlbmNlPU8sdC5wYXJzZU5hbWVkVHlwZT1GO3ZhciBvZT1uKDE3OSksYWU9bigzKSxzZT1uKDExMCksdWU9bigxMCk7WS5wcm90b3R5cGUudG9KU09OPVkucHJvdG90eXBlLmluc3BlY3Q9ZnVuY3Rpb24oKXtyZXR1cm57c3RhcnQ6dGhpcy5zdGFydCxlbmQ6dGhpcy5lbmR9fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7cmV0dXJuIGU9PT10fHwoZSBpbnN0YW5jZW9mIGEuR3JhcGhRTE5vbk51bGwmJnQgaW5zdGFuY2VvZiBhLkdyYXBoUUxOb25OdWxsP3IoZS5vZlR5cGUsdC5vZlR5cGUpOmUgaW5zdGFuY2VvZiBhLkdyYXBoUUxMaXN0JiZ0IGluc3RhbmNlb2YgYS5HcmFwaFFMTGlzdCYmcihlLm9mVHlwZSx0Lm9mVHlwZSkpfWZ1bmN0aW9uIGkoZSx0LG4pe3JldHVybiB0PT09bnx8KG4gaW5zdGFuY2VvZiBhLkdyYXBoUUxOb25OdWxsP3QgaW5zdGFuY2VvZiBhLkdyYXBoUUxOb25OdWxsJiZpKGUsdC5vZlR5cGUsbi5vZlR5cGUpOnQgaW5zdGFuY2VvZiBhLkdyYXBoUUxOb25OdWxsP2koZSx0Lm9mVHlwZSxuKTpuIGluc3RhbmNlb2YgYS5HcmFwaFFMTGlzdD90IGluc3RhbmNlb2YgYS5HcmFwaFFMTGlzdCYmaShlLHQub2ZUeXBlLG4ub2ZUeXBlKTohKHQgaW5zdGFuY2VvZiBhLkdyYXBoUUxMaXN0KSYmISEoKDAsYS5pc0Fic3RyYWN0VHlwZSkobikmJnQgaW5zdGFuY2VvZiBhLkdyYXBoUUxPYmplY3RUeXBlJiZlLmlzUG9zc2libGVUeXBlKG4sdCkpKX1mdW5jdGlvbiBvKGUsdCxuKXt2YXIgcj1uO3JldHVybiB0PT09cnx8KCgwLGEuaXNBYnN0cmFjdFR5cGUpKHQpPygwLGEuaXNBYnN0cmFjdFR5cGUpKHIpP2UuZ2V0UG9zc2libGVUeXBlcyh0KS5zb21lKGZ1bmN0aW9uKHQpe3JldHVybiBlLmlzUG9zc2libGVUeXBlKHIsdCl9KTplLmlzUG9zc2libGVUeXBlKHQscik6ISEoMCxhLmlzQWJzdHJhY3RUeXBlKShyKSYmZS5pc1Bvc3NpYmxlVHlwZShyLHQpKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5pc0VxdWFsVHlwZT1yLHQuaXNUeXBlU3ViVHlwZU9mPWksdC5kb1R5cGVzT3ZlcmxhcD1vO3ZhciBhPW4oNil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gaShlLHQpe2lmKGUgaW5zdGFuY2VvZiB1LkdyYXBoUUxOb25OdWxsKXJldHVybiB0JiZ0LmtpbmQhPT1zLk5VTEw/aShlLm9mVHlwZSx0KTpbJ0V4cGVjdGVkICInK1N0cmluZyhlKSsnIiwgZm91bmQgbnVsbC4nXTtpZighdHx8dC5raW5kPT09cy5OVUxMKXJldHVybltdO2lmKHQua2luZD09PXMuVkFSSUFCTEUpcmV0dXJuW107aWYoZSBpbnN0YW5jZW9mIHUuR3JhcGhRTExpc3Qpe3ZhciBuPWUub2ZUeXBlO3JldHVybiB0LmtpbmQ9PT1zLkxJU1Q/dC52YWx1ZXMucmVkdWNlKGZ1bmN0aW9uKGUsdCxyKXt2YXIgbz1pKG4sdCk7cmV0dXJuIGUuY29uY2F0KG8ubWFwKGZ1bmN0aW9uKGUpe3JldHVybiJJbiBlbGVtZW50ICMiK3IrIjogIitlfSkpfSxbXSk6aShuLHQpfWlmKGUgaW5zdGFuY2VvZiB1LkdyYXBoUUxJbnB1dE9iamVjdFR5cGUpe2lmKHQua2luZCE9PXMuT0JKRUNUKXJldHVyblsnRXhwZWN0ZWQgIicrZS5uYW1lKyciLCBmb3VuZCBub3QgYW4gb2JqZWN0LiddO3ZhciByPWUuZ2V0RmllbGRzKCksYT1bXSxjPXQuZmllbGRzO2MuZm9yRWFjaChmdW5jdGlvbihlKXtyW2UubmFtZS52YWx1ZV18fGEucHVzaCgnSW4gZmllbGQgIicrZS5uYW1lLnZhbHVlKyciOiBVbmtub3duIGZpZWxkLicpfSk7dmFyIHA9KDAsZi5kZWZhdWx0KShjLGZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWUudmFsdWV9KTtyZXR1cm4gT2JqZWN0LmtleXMocikuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1pKHJbZV0udHlwZSxwW2VdJiZwW2VdLnZhbHVlKTthLnB1c2guYXBwbHkoYSx0Lm1hcChmdW5jdGlvbih0KXtyZXR1cm4nSW4gZmllbGQgIicrZSsnIjogJyt0fSkpfSksYX1yZXR1cm4gZSBpbnN0YW5jZW9mIHUuR3JhcGhRTFNjYWxhclR5cGV8fGUgaW5zdGFuY2VvZiB1LkdyYXBoUUxFbnVtVHlwZXx8KDAsbC5kZWZhdWx0KSgwLCJNdXN0IGJlIGlucHV0IHR5cGUiKSxlLmlzVmFsaWRMaXRlcmFsKHQpP1tdOlsnRXhwZWN0ZWQgdHlwZSAiJytlLm5hbWUrJyIsIGZvdW5kICcrKDAsby5wcmludCkodCkrIi4iXX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5pc1ZhbGlkTGl0ZXJhbFZhbHVlPWk7dmFyIG89bigxOSksYT1uKDEwKSxzPWZ1bmN0aW9uKGUpe2lmKGUmJmUuX19lc01vZHVsZSlyZXR1cm4gZTt2YXIgdD17fTtpZihudWxsIT1lKWZvcih2YXIgbiBpbiBlKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLG4pJiYodFtuXT1lW25dKTtyZXR1cm4gdC5kZWZhdWx0PWUsdH0oYSksdT1uKDYpLGM9bigxMyksbD1yKGMpLHA9big0NiksZj1yKHApfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNDQ2KSxpPW4oMjE5KSxvPW4oMjIwKSxhPW8uYSYmby5hLmlzTWFwLHM9YT9PYmplY3QoaS5hKShhKTpyLmE7dC5hPXN9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgdD1hcmd1bWVudHM7c3dpdGNoKHQubGVuZ3RoKXtjYXNlIDA6cmV0dXJuIG5ldyBlO2Nhc2UgMTpyZXR1cm4gbmV3IGUodFswXSk7Y2FzZSAyOnJldHVybiBuZXcgZSh0WzBdLHRbMV0pO2Nhc2UgMzpyZXR1cm4gbmV3IGUodFswXSx0WzFdLHRbMl0pO2Nhc2UgNDpyZXR1cm4gbmV3IGUodFswXSx0WzFdLHRbMl0sdFszXSk7Y2FzZSA1OnJldHVybiBuZXcgZSh0WzBdLHRbMV0sdFsyXSx0WzNdLHRbNF0pO2Nhc2UgNjpyZXR1cm4gbmV3IGUodFswXSx0WzFdLHRbMl0sdFszXSx0WzRdLHRbNV0pO2Nhc2UgNzpyZXR1cm4gbmV3IGUodFswXSx0WzFdLHRbMl0sdFszXSx0WzRdLHRbNV0sdFs2XSl9dmFyIG49T2JqZWN0KGkuYSkoZS5wcm90b3R5cGUpLHI9ZS5hcHBseShuLHQpO3JldHVybiBPYmplY3Qoby5hKShyKT9yOm59fXZhciBpPW4oMTI2KSxvPW4oNjApO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIHZvaWQgMD09PWUmJihlPSIiKSxuZXcgdih7ZW5kcG9pbnQ6ZX0pLnNldCgiaWQiLG0oKSl9ZnVuY3Rpb24gaShlKXtyZXR1cm4gbmV3IHYodSh7fSxlLHtoZWFkZXJzOmUuaGVhZGVycz9KU09OLnN0cmluZ2lmeShlLmhlYWRlcnMsbnVsbCwyKToiIixyZXNwb25zZXM6ZS5yZXNwb25zZXMmJmUucmVzcG9uc2VzLmxlbmd0aD4wP2wuTGlzdChlLnJlc3BvbnNlcy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIG5ldyBiKHtkYXRlOmV9KX0pKTpsLkxpc3QoKX0pKS5zZXQoImlkIixtKCkpfWZ1bmN0aW9uIG8oZSl7dmFyIHQsbj1uZXcgdih7ZW5kcG9pbnQ6ZXx8IiJ9KTtyZXR1cm4gbmV3IHgoe3Nlc3Npb25zOmwuT3JkZXJlZE1hcCgodD17fSx0W24uaWRdPW4sdCkpLHNlbGVjdGVkU2Vzc2lvbklkOm4uaWQsc2Vzc2lvbkNvdW50OjF9KX1mdW5jdGlvbiBhKGUsdCl7dmFyIG49ZS5zZXNzaW9ucy5zaXplLGk9ZS5zZXNzaW9ucy5rZXlTZXEoKSxvPWUucmVtb3ZlSW4oWyJzZXNzaW9ucyIsdF0pLGE9ZS5zZXNzaW9ucy5nZXQodCk7aWYoMT09PW4pe3ZhciBzPXtxdWVyeToiIixoZWFkZXJzOmEuaGVhZGVycyxpc1JlbG9hZGluZ1NjaGVtYTphLmlzUmVsb2FkaW5nU2NoZW1hLGVuZHBvaW50VW5yZWFjaGFibGU6YS5lbmRwb2ludFVucmVhY2hhYmxlfTthLmVuZHBvaW50VW5yZWFjaGFibGUmJihzLnJlc3BvbnNlcz1hLnJlc3BvbnNlcyk7dmFyIHU9cihhLmVuZHBvaW50KS5tZXJnZShzKTtyZXR1cm4gbz1vLnNldCgic2VsZWN0ZWRTZXNzaW9uSWQiLHUuaWQpLG8uc2V0SW4oWyJzZXNzaW9ucyIsdS5pZF0sdSl9dmFyIGM9ZC5nZXRTZWxlY3RlZFNlc3Npb25JZChlKSxsPWkuaW5kZXhPZih0KTtpZihjPT09dCl7dmFyIHA9bC0xO3JldHVybiBwPDA/by5zZXQoInNlbGVjdGVkU2Vzc2lvbklkIixpLmdldCgxKSk6by5zZXQoInNlbGVjdGVkU2Vzc2lvbklkIixpLmdldChwKSl9cmV0dXJuIG99dmFyIHM9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKSx1PWZ1bmN0aW9uKCl7cmV0dXJuIHU9T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0LG49MSxyPWFyZ3VtZW50cy5sZW5ndGg7bjxyO24rKyl7dD1hcmd1bWVudHNbbl07Zm9yKHZhciBpIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsaSkmJihlW2ldPXRbaV0pfXJldHVybiBlfSx1LmFwcGx5KHRoaXMsYXJndW1lbnRzKX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBjLGw9bigxNCkscD1uKDIzKSxmPW4oMTYpLGQ9bigxMiksaD1uKDM2KSxtPW4oNjQpLGc9big3NykseT1uKDI0Niksdj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7cmV0dXJuIG51bGwhPT1lJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpc31yZXR1cm4gcyh0LGUpLHQucHJvdG90eXBlLnRvSlNPTj1mdW5jdGlvbigpe3ZhciBlPXRoaXMudG9PYmplY3QoKSx0PXtxdWVyeVJ1bm5pbmc6ITEsc3Vic2NyaXB0aW9uQWN0aXZlOiExLHJlc3BvbnNlRXh0ZW5zaW9uczp7fX07cmV0dXJuIGUucmVzcG9uc2VzJiZlLnJlc3BvbnNlcy5zaXplPjAmJihlLnJlc3BvbnNlcy5zaXplPjIwfHxlLnJlc3BvbnNlcy5nZXQoMCkuZGF0ZS5sZW5ndGg+MmUzKSYmKHQucmVzcG9uc2VzPWwuTGlzdCgpKSxsLm1lcmdlKGUsdCl9LHR9KGwuUmVjb3JkKGguZ2V0RGVmYXVsdFNlc3Npb24oIiIpKSk7dC5TZXNzaW9uPXY7dmFyIGI9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3JldHVybiBudWxsIT09ZSYmZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fHRoaXN9cmV0dXJuIHModCxlKSx0fShsLlJlY29yZCh7cmVzdWx0SUQ6IiIsZGF0ZToiIix0aW1lOm5ldyBEYXRlLGlzU2NoZW1hRXJyb3I6ITF9KSk7dC5SZXNwb25zZVJlY29yZD1iLHQuc2Vzc2lvbkZyb21UYWI9aTt2YXIgeD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7cmV0dXJuIG51bGwhPT1lJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpc31yZXR1cm4gcyh0LGUpLHR9KGwuUmVjb3JkKHtzZXNzaW9uczpsLk9yZGVyZWRNYXAoe30pLHNlbGVjdGVkU2Vzc2lvbklkOiIiLHNlc3Npb25Db3VudDowLGhlYWRlcnM6IiJ9KSk7dC5TZXNzaW9uU3RhdGU9eCx0Lm1ha2VTZXNzaW9uU3RhdGU9bzt2YXIgQz1wLmhhbmRsZUFjdGlvbnMoKGM9e30sY1twLmNvbWJpbmVBY3Rpb25zKGYuZWRpdFF1ZXJ5LGYuZWRpdFZhcmlhYmxlcyxmLmVkaXRIZWFkZXJzLGYuZWRpdEVuZHBvaW50LGYuc2V0RWRpdG9yRmxleCxmLm9wZW5RdWVyeVZhcmlhYmxlcyxmLmNsb3NlUXVlcnlWYXJpYWJsZXMsZi5zZXRWYXJpYWJsZUVkaXRvckhlaWdodCxmLnNldFJlc3BvbnNlVHJhY2luZ0hlaWdodCxmLnNldFRyYWNpbmdTdXBwb3J0ZWQsZi5zZXRWYXJpYWJsZVRvVHlwZSxmLnNldE9wZXJhdGlvbnMsZi5zZXRPcGVyYXRpb25OYW1lLGYuc2V0U3Vic2NyaXB0aW9uQWN0aXZlLGYuc3RhcnRRdWVyeSxmLnNldFF1ZXJ5VHlwZXMsZi5lZGl0TmFtZSxmLnNldFJlc3BvbnNlRXh0ZW5zaW9ucyxmLnNldEN1cnJlbnRRdWVyeVN0YXJ0VGltZSxmLnNldEN1cnJlbnRRdWVyeUVuZFRpbWUpXT1mdW5jdGlvbihlLHQpe3ZhciBuPXQucGF5bG9hZCxyPU9iamVjdC5rZXlzKG4pLGk9MT09PXIubGVuZ3RoP3JbMF06clsxXSxvPVsic2Vzc2lvbnMiLGQuZ2V0U2VsZWN0ZWRTZXNzaW9uSWQoZSksaV07cmV0dXJuIGUuc2V0SW4obyxuW2ldKX0sYy5TVEFSVF9RVUVSWT1mdW5jdGlvbihlKXtyZXR1cm4gZS5zZXRJbihbInNlc3Npb25zIixkLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpLCJxdWVyeVJ1bm5pbmciXSwhMCkuc2V0SW4oWyJzZXNzaW9ucyIsZC5nZXRTZWxlY3RlZFNlc3Npb25JZChlKSwicmVzcG9uc2VFeHRlbnNpb25zIl0sdm9pZCAwKX0sYy5DTE9TRV9UUkFDSU5HPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLnJlc3BvbnNlVHJhY2luZ0hlaWdodDtyZXR1cm4gZS5tZXJnZURlZXBJbihbInNlc3Npb25zIixkLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpXSxsLk1hcCh7cmVzcG9uc2VUcmFjaW5nSGVpZ2h0Om4scmVzcG9uc2VUcmFjaW5nT3BlbjohMX0pKX0sYy5UT0dHTEVfVFJBQ0lORz1mdW5jdGlvbihlKXt2YXIgdD1bInNlc3Npb25zIixkLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpLCJyZXNwb25zZVRyYWNpbmdPcGVuIl07cmV0dXJuIGUuc2V0SW4odCwhZS5nZXRJbih0KSl9LGMuT1BFTl9UUkFDSU5HPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLnJlc3BvbnNlVHJhY2luZ0hlaWdodDtyZXR1cm4gZS5tZXJnZURlZXBJbihbInNlc3Npb25zIixkLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpXSxsLk1hcCh7cmVzcG9uc2VUcmFjaW5nSGVpZ2h0Om4scmVzcG9uc2VUcmFjaW5nT3BlbjohMH0pKX0sYy5DTE9TRV9WQVJJQUJMRVM9ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQudmFyaWFibGVFZGl0b3JIZWlnaHQ7cmV0dXJuIGUubWVyZ2VEZWVwSW4oWyJzZXNzaW9ucyIsZC5nZXRTZWxlY3RlZFNlc3Npb25JZChlKV0sbC5NYXAoe3ZhcmlhYmxlRWRpdG9ySGVpZ2h0Om4sdmFyaWFibGVFZGl0b3JPcGVuOiExfSkpfSxjLk9QRU5fVkFSSUFCTEVTPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLnZhcmlhYmxlRWRpdG9ySGVpZ2h0O3JldHVybiBlLm1lcmdlRGVlcEluKFsic2Vzc2lvbnMiLGQuZ2V0U2VsZWN0ZWRTZXNzaW9uSWQoZSldLGwuTWFwKHt2YXJpYWJsZUVkaXRvckhlaWdodDpuLHZhcmlhYmxlRWRpdG9yT3BlbjohMH0pKX0sYy5UT0dHTEVfVkFSSUFCTEVTPWZ1bmN0aW9uKGUpe3ZhciB0PVsic2Vzc2lvbnMiLGQuZ2V0U2VsZWN0ZWRTZXNzaW9uSWQoZSksInZhcmlhYmxlRWRpdG9yT3BlbiJdO3JldHVybiBlLnNldEluKHQsIWUuZ2V0SW4odCkpfSxjLkFERF9SRVNQT05TRT1mdW5jdGlvbihlLHQpe3ZhciBuPXQucGF5bG9hZCxyPW4ucmVzcG9uc2UsaT1uLnNlc3Npb25JZDtyZXR1cm4gZS51cGRhdGVJbihbInNlc3Npb25zIixpLCJyZXNwb25zZXMiXSxmdW5jdGlvbihlKXtyZXR1cm4gZS5wdXNoKHIpfSl9LGMuU0VUX1JFU1BPTlNFPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLHI9bi5yZXNwb25zZSxpPW4uc2Vzc2lvbklkO3JldHVybiBlLnNldEluKFsic2Vzc2lvbnMiLGksInJlc3BvbnNlcyJdLGwuTGlzdChbcl0pKX0sYy5DTEVBUl9SRVNQT05TRVM9ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc2V0SW4oWyJzZXNzaW9ucyIsZC5nZXRTZWxlY3RlZFNlc3Npb25JZChlKSwicmVzcG9uc2VzIl0sbC5MaXN0KCkpfSxjLkZFVENIX1NDSEVNQT1mdW5jdGlvbihlKXtyZXR1cm4gZS5zZXRJbihbInNlc3Npb25zIixkLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpLCJpc1JlbG9hZGluZ1NjaGVtYSJdLCEwKX0sYy5SRUZFVENIX1NDSEVNQT1mdW5jdGlvbihlKXtyZXR1cm4gZS5zZXRJbihbInNlc3Npb25zIixkLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpLCJpc1JlbG9hZGluZ1NjaGVtYSJdLCEwKX0sYy5TVE9QX1FVRVJZPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLnNlc3Npb25JZDtyZXR1cm4gZS5tZXJnZUluKFsic2Vzc2lvbnMiLG5dLHtxdWVyeVJ1bm5pbmc6ITEsc3Vic2NyaXB0aW9uQWN0aXZlOiExfSl9LGMuU0VUX1NDUk9MTF9UT1A9ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQscj1uLnNlc3Npb25JZCxpPW4uc2Nyb2xsVG9wO3JldHVybiBlLnNlc3Npb25zLmdldChyKT9lLnNldEluKFsic2Vzc2lvbnMiLHIsInNjcm9sbFRvcCJdLGkpOmV9LGMuU0NIRU1BX0ZFVENISU5HX1NVQ0NFU1M9ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQscj1lLmdldCgic2Vzc2lvbnMiKS5tYXAoZnVuY3Rpb24oZSl7aWYoZS5lbmRwb2ludD09PW4uZW5kcG9pbnQpe3ZhciB0PXt0cmFjaW5nU3VwcG9ydGVkOm4udHJhY2luZ1N1cHBvcnRlZCxpc1JlbG9hZGluZ1NjaGVtYTohMSxlbmRwb2ludFVucmVhY2hhYmxlOiExfSxyPWUucmVzcG9uc2VzP2UucmVzcG9uc2VzLmZpcnN0KCk6bnVsbDtyZXR1cm4gciYmMT09PWUucmVzcG9uc2VzLnNpemUmJnIuaXNTY2hlbWFFcnJvciYmKHQucmVzcG9uc2VzPWwuTGlzdChbXSkpLGUubWVyZ2UobC5NYXAodCkpfXJldHVybiBlfSk7cmV0dXJuIGUuc2V0KCJzZXNzaW9ucyIscil9LGMuU0VUX0VORFBPSU5UX1VOUkVBQ0hBQkxFPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLHI9ZS5nZXQoInNlc3Npb25zIikubWFwKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuZ2V0KCJlbmRwb2ludCIpPT09bi5lbmRwb2ludD9lLm1lcmdlKGwuTWFwKHtlbmRwb2ludFVucmVhY2hhYmxlOiEwfSkpOmV9KTtyZXR1cm4gZS5zZXQoInNlc3Npb25zIixyKX0sYy5TQ0hFTUFfRkVUQ0hJTkdfRVJST1I9ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQscj1lLmdldCgic2Vzc2lvbnMiKS5tYXAoZnVuY3Rpb24oZSx0KXtpZihlLmdldCgiZW5kcG9pbnQiKT09PW4uZW5kcG9pbnQpe3ZhciByPWUucmVzcG9uc2VzO2lmKHIuc2l6ZTw9MSl7dmFyIGk9ZS5yZXNwb25zZXM/ZS5yZXNwb25zZXMuZmlyc3QoKTpudWxsO2kmJiFpLmlzU2NoZW1hRXJyb3J8fChpPW5ldyBiKHtyZXN1bHRJRDptKCksaXNTY2hlbWFFcnJvcjohMCxkYXRlOkpTT04uc3RyaW5naWZ5KGcuZm9ybWF0RXJyb3Iobi5lcnJvciwhMCksbnVsbCwyKSx0aW1lOm5ldyBEYXRlfSkpLHI9bC5MaXN0KFtpXSl9cmV0dXJuIGUubWVyZ2UobC5NYXAoe2lzUmVsb2FkaW5nU2NoZW1hOiExLGVuZHBvaW50VW5yZWFjaGFibGU6ITAscmVzcG9uc2VzOnJ9KSl9cmV0dXJuIGV9KTtyZXR1cm4gZS5zZXQoInNlc3Npb25zIixyKX0sYy5TRVRfU0VMRUNURURfU0VTU0lPTl9JRD1mdW5jdGlvbihlLHQpe3ZhciBuPXQucGF5bG9hZC5zZXNzaW9uSWQ7cmV0dXJuIGUuc2V0KCJzZWxlY3RlZFNlc3Npb25JZCIsbil9LGMuT1BFTl9TRVRUSU5HU19UQUI9ZnVuY3Rpb24oZSl7dmFyIHQ9ZSxuPWUuc2Vzc2lvbnMuZmluZChmdW5jdGlvbihlKXtyZXR1cm4gZS5nZXQoImlzU2V0dGluZ3NUYWIiLCExKX0pO3JldHVybiBufHwobj1yKCkubWVyZ2Uoe2lzU2V0dGluZ3NUYWI6ITAsaXNGaWxlOiEwLG5hbWU6IlNldHRpbmdzIixjaGFuZ2VkOiExfSksdD10LnNldEluKFsic2Vzc2lvbnMiLG4uaWRdLG4pKSx0LnNldCgic2VsZWN0ZWRTZXNzaW9uSWQiLG4uaWQpfSxjLk9QRU5fQ09ORklHX1RBQj1mdW5jdGlvbihlKXt2YXIgdD1lLG49ZS5zZXNzaW9ucy5maW5kKGZ1bmN0aW9uKGUpe3JldHVybiBlLmdldCgiaXNDb25maWdUYWIiLCExKX0pO3JldHVybiBufHwobj1yKCkubWVyZ2Uoe2lzQ29uZmlnVGFiOiEwLGlzRmlsZTohMCxuYW1lOiJHcmFwaFFMIENvbmZpZyIsY2hhbmdlZDohMX0pLHQ9dC5zZXRJbihbInNlc3Npb25zIixuLmlkXSxuKSksdC5zZXQoInNlbGVjdGVkU2Vzc2lvbklkIixuLmlkKX0sYy5ORVdfRklMRV9UQUI9ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQsaT1uLmZpbGVOYW1lLG89bi5maWxlUGF0aCxhPW4uZmlsZSxzPWUsdT1lLnNlc3Npb25zLmZpbmQoZnVuY3Rpb24oZSl7cmV0dXJuIGUuZ2V0KCJuYW1lIiwiIik9PT1pfSk7cmV0dXJuIHV8fCh1PXIoKS5tZXJnZSh7aXNGaWxlOiEwLG5hbWU6aSxjaGFuZ2VkOiExLGZpbGU6YSxmaWxlUGF0aDpvfSkscz1zLnNldEluKFsic2Vzc2lvbnMiLHUuaWRdLHUpKSxzLnNldCgic2VsZWN0ZWRTZXNzaW9uSWQiLHUuaWQpLnNldCgic2Vzc2lvbkNvdW50IixzLnNlc3Npb25zLnNpemUpfSxjLk5FV19TRVNTSU9OPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLGk9bi5yZXVzZUhlYWRlcnMsbz1uLmVuZHBvaW50LGE9ZS5zZXNzaW9ucy5maXJzdCgpLHM9e3F1ZXJ5OiIiLGlzUmVsb2FkaW5nU2NoZW1hOmEuaXNSZWxvYWRpbmdTY2hlbWEsZW5kcG9pbnRVbnJlYWNoYWJsZTphLmVuZHBvaW50VW5yZWFjaGFibGV9O2EuZW5kcG9pbnRVbnJlYWNoYWJsZSYmKHMucmVzcG9uc2VzPWEucmVzcG9uc2VzKTt2YXIgdT1yKG98fGEuZW5kcG9pbnQpLm1lcmdlKHMpO2lmKGkpe3ZhciBjPWQuZ2V0U2VsZWN0ZWRTZXNzaW9uSWQoZSksbD1lLnNlc3Npb25zLmdldChjKTt1PXUuc2V0KCJoZWFkZXJzIixsLmhlYWRlcnMpfWVsc2UgdT11LnNldCgiaGVhZGVycyIsZS5oZWFkZXJzKTtyZXR1cm4gZS5zZXRJbihbInNlc3Npb25zIix1LmlkXSx1KS5zZXQoInNlbGVjdGVkU2Vzc2lvbklkIix1LmlkKS5zZXQoInNlc3Npb25Db3VudCIsZS5zZXNzaW9ucy5zaXplKzEpfSxjLklOSkVDVF9IRUFERVJTPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLGk9bi5oZWFkZXJzLG89bi5lbmRwb2ludDtpZighaXx8IiI9PT1pfHwwPT09T2JqZWN0LmtleXMoaSkubGVuZ3RoKXJldHVybiBlO3ZhciBhPSJzdHJpbmciPT09dHlwZW9mIGk/aTpKU09OLnN0cmluZ2lmeShpLG51bGwsMikscz1kLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpLHU9ZS5zZXQoImhlYWRlcnMiLGEpLGM9ZS5zZXNzaW9ucy5nZXQocyk7aWYoYy5oZWFkZXJzPT09YSlyZXR1cm4gdTtpZihjLnF1ZXJ5PT09aC5kZWZhdWx0UXVlcnkpcmV0dXJuIHUuc2V0SW4oWyJzZXNzaW9ucyIscywiaGVhZGVycyJdLGEpO3ZhciBsPXIobykuc2V0KCJoZWFkZXJzIixhKTtyZXR1cm4gdS5zZXRJbihbInNlc3Npb25zIixsLmlkXSxsKS5zZXQoInNlbGVjdGVkU2Vzc2lvbklkIixsLmlkKS5zZXQoInNlc3Npb25Db3VudCIsZS5zZXNzaW9ucy5zaXplKzEpfSxjLkRVUExJQ0FURV9TRVNTSU9OPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLnNlc3Npb24scj1uLnNldCgiaWQiLG0oKSk7cmV0dXJuIGUuc2V0SW4oWyJzZXNzaW9ucyIsci5pZF0scikuc2V0KCJzZWxlY3RlZFNlc3Npb25JZCIsci5pZCkuc2V0KCJzZXNzaW9uQ291bnQiLGUuc2Vzc2lvbnMuc2l6ZSsxKX0sYy5ORVdfU0VTU0lPTl9GUk9NX1FVRVJZPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLnF1ZXJ5LGk9cigpLnNldCgicXVlcnkiLG4pO3JldHVybiBlLnNldEluKFsic2Vzc2lvbnMiLGkuaWRdLGkpLnNldCgic2Vzc2lvbkNvdW50IixlLnNlc3Npb25zLnNpemUrMSl9LGMuQ0xPU0VfU0VMRUNURURfVEFCPWZ1bmN0aW9uKGUpe3JldHVybiBhKGUsZC5nZXRTZWxlY3RlZFNlc3Npb25JZChlKSkuc2V0KCJzZXNzaW9uQ291bnQiLGUuc2Vzc2lvbnMuc2l6ZS0xKX0sYy5TRUxFQ1RfTkVYVF9UQUI9ZnVuY3Rpb24oZSl7dmFyIHQ9ZC5nZXRTZWxlY3RlZFNlc3Npb25JZChlKSxuPWUuc2Vzc2lvbnMuc2l6ZSxyPWUuc2Vzc2lvbnMua2V5U2VxKCksaT1yLmluZGV4T2YodCk7cmV0dXJuIGkrMTxuP2Uuc2V0KCJzZWxlY3RlZFNlc3Npb25JZCIsci5nZXQoaSsxKSk6ZS5zZXQoInNlbGVjdGVkU2Vzc2lvbklkIixyLmdldCgwKSl9LGMuU0VMRUNUX1BSRVZfVEFCPWZ1bmN0aW9uKGUpe3ZhciB0PWQuZ2V0U2VsZWN0ZWRTZXNzaW9uSWQoZSksbj1lLnNlc3Npb25zLnNpemUscj1lLnNlc3Npb25zLmtleVNlcSgpLGk9ci5pbmRleE9mKHQpO3JldHVybiBpLTE+PTA/ZS5zZXQoInNlbGVjdGVkU2Vzc2lvbklkIixyLmdldChpLTEpKTplLnNldCgic2VsZWN0ZWRTZXNzaW9uSWQiLHIuZ2V0KG4tMSkpfSxjLlNFTEVDVF9UQUJfSU5ERVg9ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQuaW5kZXgscj1lLnNlc3Npb25zLmtleVNlcSgpO3JldHVybiBlLnNldCgic2VsZWN0ZWRTZXNzaW9uSWQiLHIuZ2V0KG4pKX0sYy5TRUxFQ1RfVEFCPWZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLnNlc3Npb25JZDtyZXR1cm4gZS5zZXQoInNlbGVjdGVkU2Vzc2lvbklkIixuKX0sYy5DTE9TRV9UQUI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gYShlLHQucGF5bG9hZC5zZXNzaW9uSWQpLnNldCgic2Vzc2lvbkNvdW50IixlLnNlc3Npb25zLnNpemUtMSl9LGMuUkVPUkRFUl9UQUJTPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPXQucGF5bG9hZCxyPW4uc3JjLGk9bi5kZXN0LG89ZS5zZXNzaW9ucy50b0luZGV4ZWRTZXEoKSxhPVtdLHM9MDtzPG8uc2l6ZTtzKyspYS5wdXNoKHMpO2Zvcih2YXIgdT15LmFycmF5TW92ZShhLHIsaSksYz1sLk9yZGVyZWRNYXAoKSxzPTA7czxvLnNpemU7cysrKXt2YXIgcD11W3NdLGY9by5nZXQocCk7Yz1jLnNldChmLmlkLGYpfXJldHVybiBlLnNldCgic2Vzc2lvbnMiLGMpfSxjLkVESVRfU0VUVElOR1M9ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc2V0SW4oWyJzZXNzaW9ucyIsZC5nZXRTZWxlY3RlZFNlc3Npb25JZChlKSwiY2hhbmdlZCJdLCEwKX0sYy5TQVZFX1NFVFRJTkdTPWZ1bmN0aW9uKGUpe3JldHVybiBlLnNldEluKFsic2Vzc2lvbnMiLGQuZ2V0U2VsZWN0ZWRTZXNzaW9uSWQoZSksImNoYW5nZWQiXSwhMSl9LGMuRURJVF9DT05GSUc9ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc2V0SW4oWyJzZXNzaW9ucyIsZC5nZXRTZWxlY3RlZFNlc3Npb25JZChlKSwiY2hhbmdlZCJdLCEwKX0sYy5TQVZFX0NPTkZJRz1mdW5jdGlvbihlKXtyZXR1cm4gZS5zZXRJbihbInNlc3Npb25zIixkLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpLCJjaGFuZ2VkIl0sITEpfSxjLkVESVRfRklMRT1mdW5jdGlvbihlKXtyZXR1cm4gZS5zZXRJbihbInNlc3Npb25zIixkLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpLCJjaGFuZ2VkIl0sITApfSxjLlNBVkVfRklMRT1mdW5jdGlvbihlKXtyZXR1cm4gZS5zZXRJbihbInNlc3Npb25zIixkLmdldFNlbGVjdGVkU2Vzc2lvbklkKGUpLCJjaGFuZ2VkIl0sITEpfSxjKSxvKCIiKSk7dC5kZWZhdWx0PWZ1bmN0aW9uKGUsdCl7dmFyIG49QyhlLHQpO3JldHVybiIiPT09bi5zZWxlY3RlZFNlc3Npb25JZCYmZS5zZXNzaW9ucy5zaXplPjA/bi5zZXQoInNlbGVjdGVkU2Vzc2lvbklkIixlLnNlc3Npb25zLmZpcnN0KCkuaWQpOm59fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4pe3ZhciByPWUuc2xpY2UoMCk7aWYobj49ci5sZW5ndGgpZm9yKHZhciBpPW4tci5sZW5ndGg7MStpLS07KXIucHVzaCh2b2lkIDApO3JldHVybiByLnNwbGljZShuLDAsci5zcGxpY2UodCwxKVswXSkscn1mdW5jdGlvbiBpKGUpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49QXJyYXkodD4xP3QtMTowKSxyPTE7cjx0O3IrKyluW3ItMV09YXJndW1lbnRzW3JdO3JldHVybiBPYmplY3Qua2V5cyhlKS5yZWR1Y2UoZnVuY3Rpb24odCxyKXtyZXR1cm4tMT09PW4uaW5kZXhPZihyKSYmKHRbcl09ZVtyXSksdH0se30pfWZ1bmN0aW9uIG8oZSx0KXtmb3IoO2U7KXtpZih0KGUpKXJldHVybiBlO2U9ZS5wYXJlbnROb2RlfX1mdW5jdGlvbiBhKGUsdCxuKXtyZXR1cm4gbjxlP2U6bj50P3Q6bn1mdW5jdGlvbiBzKGUpe3JldHVybiJweCI9PT1lLnN1YnN0cigtMik/cGFyc2VGbG9hdChlKTowfWZ1bmN0aW9uIHUoZSl7dmFyIHQ9d2luZG93LmdldENvbXB1dGVkU3R5bGUoZSk7cmV0dXJue3RvcDpzKHQubWFyZ2luVG9wKSxyaWdodDpzKHQubWFyZ2luUmlnaHQpLGJvdHRvbTpzKHQubWFyZ2luQm90dG9tKSxsZWZ0OnModC5tYXJnaW5MZWZ0KX19ZnVuY3Rpb24gYyhlLHQpe3ZhciBuPXQuZGlzcGxheU5hbWV8fHQubmFtZTtyZXR1cm4gbj9lKyIoIituKyIpIjplfWZ1bmN0aW9uIGwoZSl7cmV0dXJuIGUudG91Y2hlcyYmZS50b3VjaGVzLmxlbmd0aD97eDplLnRvdWNoZXNbMF0ucGFnZVgseTplLnRvdWNoZXNbMF0ucGFnZVl9OmUuY2hhbmdlZFRvdWNoZXMmJmUuY2hhbmdlZFRvdWNoZXMubGVuZ3RoP3t4OmUuY2hhbmdlZFRvdWNoZXNbMF0ucGFnZVgseTplLmNoYW5nZWRUb3VjaGVzWzBdLnBhZ2VZfTp7eDplLnBhZ2VYLHk6ZS5wYWdlWX19ZnVuY3Rpb24gcChlKXtyZXR1cm4gZS50b3VjaGVzJiZlLnRvdWNoZXMubGVuZ3RofHxlLmNoYW5nZWRUb3VjaGVzJiZlLmNoYW5nZWRUb3VjaGVzLmxlbmd0aH1mdW5jdGlvbiBmKGUsdCl7dmFyIG49YXJndW1lbnRzLmxlbmd0aD4yJiZ2b2lkIDAhPT1hcmd1bWVudHNbMl0/YXJndW1lbnRzWzJdOnt0b3A6MCxsZWZ0OjB9O2lmKGUpe3ZhciByPXt0b3A6bi50b3ArZS5vZmZzZXRUb3AsbGVmdDpuLmxlZnQrZS5vZmZzZXRMZWZ0fTtyZXR1cm4gZS5wYXJlbnROb2RlIT09dD9mKGUucGFyZW50Tm9kZSx0LHIpOnJ9fWZ1bmN0aW9uIGQoZSl7dmFyIHQ9ZS5sb2NrT2Zmc2V0LG49ZS53aWR0aCxyPWUuaGVpZ2h0LGk9dCxvPXQsYT0icHgiO2lmKCJzdHJpbmciPT09dHlwZW9mIHQpe3ZhciBzPS9eWystXT9cZCooPzpcLlxkKik/KHB4fCUpJC8uZXhlYyh0KTsoMCxtLmRlZmF1bHQpKG51bGwhPT1zLCdsb2NrT2Zmc2V0IHZhbHVlIHNob3VsZCBiZSBhIG51bWJlciBvciBhIHN0cmluZyBvZiBhIG51bWJlciBmb2xsb3dlZCBieSAicHgiIG9yICIlIi4gR2l2ZW4gJXMnLHQpLGk9bz1wYXJzZUZsb2F0KHQpLGE9c1sxXX1yZXR1cm4oMCxtLmRlZmF1bHQpKGlzRmluaXRlKGkpJiZpc0Zpbml0ZShvKSwibG9ja09mZnNldCB2YWx1ZSBzaG91bGQgYmUgYSBmaW5pdGUuIEdpdmVuICVzIix0KSwiJSI9PT1hJiYoaT1pKm4vMTAwLG89bypyLzEwMCkse3g6aSx5Om99fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnZlbmRvclByZWZpeD10LmV2ZW50cz12b2lkIDAsdC5hcnJheU1vdmU9cix0Lm9taXQ9aSx0LmNsb3Nlc3Q9byx0LmxpbWl0PWEsdC5nZXRFbGVtZW50TWFyZ2luPXUsdC5wcm92aWRlRGlzcGxheU5hbWU9Yyx0LmdldFBvc2l0aW9uPWwsdC5pc1RvdWNoRXZlbnQ9cCx0LmdldEVkZ2VPZmZzZXQ9Zix0LmdldExvY2tQaXhlbE9mZnNldD1kO3ZhciBoPW4oMjApLG09ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShoKTt0LmV2ZW50cz17c3RhcnQ6WyJ0b3VjaHN0YXJ0IiwibW91c2Vkb3duIl0sbW92ZTpbInRvdWNobW92ZSIsIm1vdXNlbW92ZSJdLGVuZDpbInRvdWNoZW5kIiwidG91Y2hjYW5jZWwiLCJtb3VzZXVwIl19LHQudmVuZG9yUHJlZml4PWZ1bmN0aW9uKCl7aWYoInVuZGVmaW5lZCI9PT10eXBlb2Ygd2luZG93fHwidW5kZWZpbmVkIj09PXR5cGVvZiBkb2N1bWVudClyZXR1cm4iIjt2YXIgZT13aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQsIiIpfHxbIi1tb3otaGlkZGVuLWlmcmFtZSJdLHQ9KEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGUpLmpvaW4oIiIpLm1hdGNoKC8tKG1venx3ZWJraXR8bXMpLS8pfHwiIj09PWUuT0xpbmsmJlsiIiwibyJdKVsxXTtzd2l0Y2godCl7Y2FzZSJtcyI6cmV0dXJuIm1zIjtkZWZhdWx0OnJldHVybiB0JiZ0Lmxlbmd0aD90WzBdLnRvVXBwZXJDYXNlKCkrdC5zdWJzdHIoMSk6IiJ9fSgpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDUyNCksaT1uKDI1OSk7dC50aGVtZT1pLnRoZW1lO3ZhciBvPXIsYT1vLmRlZmF1bHQscz1vLmNzcyx1PW8uaW5qZWN0R2xvYmFsLGM9by5rZXlmcmFtZXMsbD1vLlRoZW1lUHJvdmlkZXIscD1vLndpdGhUaGVtZSxmPW8uY3JlYXRlR2xvYmFsU3R5bGU7dC5jc3M9cyx0LmluamVjdEdsb2JhbD11LHQua2V5ZnJhbWVzPWMsdC5UaGVtZVByb3ZpZGVyPWwsdC53aXRoVGhlbWU9cCx0LmNyZWF0ZUdsb2JhbFN0eWxlPWYsdC5kZWZhdWx0PWF9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzLmVuY29kZT1uKDUzOSksZS5leHBvcnRzLmRlY29kZT1uKDU0MCksZS5leHBvcnRzLmZvcm1hdD1uKDU0MSksZS5leHBvcnRzLnBhcnNlPW4oNTQyKX0sZnVuY3Rpb24oZSx0LG4peyFmdW5jdGlvbihlKXtlKG4oMiksbig1OTMpKX0oZnVuY3Rpb24oZSl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHQoZSl7dGhpcy5vcHRpb25zPWUsdGhpcy5mcm9tPXRoaXMudG89MH1mdW5jdGlvbiBuKGUpe3JldHVybiEwPT09ZSYmKGU9e30pLG51bGw9PWUuZ3V0dGVyJiYoZS5ndXR0ZXI9IkNvZGVNaXJyb3ItZm9sZGd1dHRlciIpLG51bGw9PWUuaW5kaWNhdG9yT3BlbiYmKGUuaW5kaWNhdG9yT3Blbj0iQ29kZU1pcnJvci1mb2xkZ3V0dGVyLW9wZW4iKSxudWxsPT1lLmluZGljYXRvckZvbGRlZCYmKGUuaW5kaWNhdG9yRm9sZGVkPSJDb2RlTWlycm9yLWZvbGRndXR0ZXItZm9sZGVkIiksZX1mdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuPWUuZmluZE1hcmtzKHAodCwwKSxwKHQrMSwwKSkscj0wO3I8bi5sZW5ndGg7KytyKWlmKG5bcl0uX19pc0ZvbGQmJm5bcl0uZmluZCgpLmZyb20ubGluZT09dClyZXR1cm4gbltyXX1mdW5jdGlvbiBpKGUpe2lmKCJzdHJpbmciPT10eXBlb2YgZSl7dmFyIHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7cmV0dXJuIHQuY2xhc3NOYW1lPWUrIiBDb2RlTWlycm9yLWd1dHRlcm1hcmtlci1zdWJ0bGUiLHR9cmV0dXJuIGUuY2xvbmVOb2RlKCEwKX1mdW5jdGlvbiBvKGUsdCxuKXt2YXIgbz1lLnN0YXRlLmZvbGRHdXR0ZXIub3B0aW9ucyxhPXQscz1lLmZvbGRPcHRpb24obywibWluRm9sZFNpemUiKSx1PWUuZm9sZE9wdGlvbihvLCJyYW5nZUZpbmRlciIpO2UuZWFjaExpbmUodCxuLGZ1bmN0aW9uKHQpe3ZhciBuPW51bGw7aWYocihlLGEpKW49aShvLmluZGljYXRvckZvbGRlZCk7ZWxzZXt2YXIgYz1wKGEsMCksbD11JiZ1KGUsYyk7bCYmbC50by5saW5lLWwuZnJvbS5saW5lPj1zJiYobj1pKG8uaW5kaWNhdG9yT3BlbikpfWUuc2V0R3V0dGVyTWFya2VyKHQsby5ndXR0ZXIsbiksKythfSl9ZnVuY3Rpb24gYShlKXt2YXIgdD1lLmdldFZpZXdwb3J0KCksbj1lLnN0YXRlLmZvbGRHdXR0ZXI7biYmKGUub3BlcmF0aW9uKGZ1bmN0aW9uKCl7byhlLHQuZnJvbSx0LnRvKX0pLG4uZnJvbT10LmZyb20sbi50bz10LnRvKX1mdW5jdGlvbiBzKGUsdCxuKXt2YXIgaT1lLnN0YXRlLmZvbGRHdXR0ZXI7aWYoaSl7dmFyIG89aS5vcHRpb25zO2lmKG49PW8uZ3V0dGVyKXt2YXIgYT1yKGUsdCk7YT9hLmNsZWFyKCk6ZS5mb2xkQ29kZShwKHQsMCksby5yYW5nZUZpbmRlcil9fX1mdW5jdGlvbiB1KGUpe3ZhciB0PWUuc3RhdGUuZm9sZEd1dHRlcjtpZih0KXt2YXIgbj10Lm9wdGlvbnM7dC5mcm9tPXQudG89MCxjbGVhclRpbWVvdXQodC5jaGFuZ2VVcGRhdGUpLHQuY2hhbmdlVXBkYXRlPXNldFRpbWVvdXQoZnVuY3Rpb24oKXthKGUpfSxuLmZvbGRPbkNoYW5nZVRpbWVTcGFufHw2MDApfX1mdW5jdGlvbiBjKGUpe3ZhciB0PWUuc3RhdGUuZm9sZEd1dHRlcjtpZih0KXt2YXIgbj10Lm9wdGlvbnM7Y2xlYXJUaW1lb3V0KHQuY2hhbmdlVXBkYXRlKSx0LmNoYW5nZVVwZGF0ZT1zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dmFyIG49ZS5nZXRWaWV3cG9ydCgpO3QuZnJvbT09dC50b3x8bi5mcm9tLXQudG8+MjB8fHQuZnJvbS1uLnRvPjIwP2EoZSk6ZS5vcGVyYXRpb24oZnVuY3Rpb24oKXtuLmZyb208dC5mcm9tJiYobyhlLG4uZnJvbSx0LmZyb20pLHQuZnJvbT1uLmZyb20pLG4udG8+dC50byYmKG8oZSx0LnRvLG4udG8pLHQudG89bi50byl9KX0sbi51cGRhdGVWaWV3cG9ydFRpbWVTcGFufHw0MDApfX1mdW5jdGlvbiBsKGUsdCl7dmFyIG49ZS5zdGF0ZS5mb2xkR3V0dGVyO2lmKG4pe3ZhciByPXQubGluZTtyPj1uLmZyb20mJnI8bi50byYmbyhlLHIscisxKX19ZS5kZWZpbmVPcHRpb24oImZvbGRHdXR0ZXIiLCExLGZ1bmN0aW9uKHIsaSxvKXtvJiZvIT1lLkluaXQmJihyLmNsZWFyR3V0dGVyKHIuc3RhdGUuZm9sZEd1dHRlci5vcHRpb25zLmd1dHRlciksci5zdGF0ZS5mb2xkR3V0dGVyPW51bGwsci5vZmYoImd1dHRlckNsaWNrIixzKSxyLm9mZigiY2hhbmdlIix1KSxyLm9mZigidmlld3BvcnRDaGFuZ2UiLGMpLHIub2ZmKCJmb2xkIixsKSxyLm9mZigidW5mb2xkIixsKSxyLm9mZigic3dhcERvYyIsdSkpLGkmJihyLnN0YXRlLmZvbGRHdXR0ZXI9bmV3IHQobihpKSksYShyKSxyLm9uKCJndXR0ZXJDbGljayIscyksci5vbigiY2hhbmdlIix1KSxyLm9uKCJ2aWV3cG9ydENoYW5nZSIsYyksci5vbigiZm9sZCIsbCksci5vbigidW5mb2xkIixsKSxyLm9uKCJzd2FwRG9jIix1KSl9KTt2YXIgcD1lLlBvc30pfSxmdW5jdGlvbihlLHQsbil7IWZ1bmN0aW9uKGUpe2UobigyKSxuKDM5KSl9KGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiB0KGUsdCxuLHIsaSl7ZS5vcGVuRGlhbG9nP2Uub3BlbkRpYWxvZyh0LGkse3ZhbHVlOnIsc2VsZWN0VmFsdWVPbk9wZW46ITB9KTppKHByb21wdChuLHIpKX1mdW5jdGlvbiBuKGUsdCl7dmFyIG49TnVtYmVyKHQpO3JldHVybi9eWy0rXS8udGVzdCh0KT9lLmdldEN1cnNvcigpLmxpbmUrbjpuLTF9ZS5jb21tYW5kcy5qdW1wVG9MaW5lPWZ1bmN0aW9uKGUpe3ZhciByPWUuZ2V0Q3Vyc29yKCk7dChlLCdKdW1wIHRvIGxpbmU6IDxpbnB1dCB0eXBlPSJ0ZXh0IiBzdHlsZT0id2lkdGg6IDEwZW0iIGNsYXNzPSJDb2RlTWlycm9yLXNlYXJjaC1maWVsZCIvPiA8c3BhbiBzdHlsZT0iY29sb3I6ICM4ODgiIGNsYXNzPSJDb2RlTWlycm9yLXNlYXJjaC1oaW50Ij4oVXNlIGxpbmU6Y29sdW1uIG9yIHNjcm9sbCUgc3ludGF4KTwvc3Bhbj4nLCJKdW1wIHRvIGxpbmU6IixyLmxpbmUrMSsiOiIrci5jaCxmdW5jdGlvbih0KXtpZih0KXt2YXIgaTtpZihpPS9eXHMqKFtcK1wtXT9cZCspXHMqXDpccyooXGQrKVxzKiQvLmV4ZWModCkpZS5zZXRDdXJzb3IobihlLGlbMV0pLE51bWJlcihpWzJdKSk7ZWxzZSBpZihpPS9eXHMqKFtcK1wtXT9cZCsoXC5cZCspPylcJVxzKi8uZXhlYyh0KSl7dmFyIG89TWF0aC5yb3VuZChlLmxpbmVDb3VudCgpKk51bWJlcihpWzFdKS8xMDApOy9eWy0rXS8udGVzdChpWzFdKSYmKG89ci5saW5lK28rMSksZS5zZXRDdXJzb3Ioby0xLHIuY2gpfWVsc2UoaT0vXlxzKlw6P1xzKihbXCtcLV0/XGQrKVxzKi8uZXhlYyh0KSkmJmUuc2V0Q3Vyc29yKG4oZSxpWzFdKSxyLmNoKX19KX0sZS5rZXlNYXAuZGVmYXVsdFsiQWx0LUciXT0ianVtcFRvTGluZSJ9KX0sZnVuY3Rpb24oZSx0LG4peyFmdW5jdGlvbihlKXtlKG4oMiksbigzOCksbig2OSkpfShmdW5jdGlvbihlKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gdCh0LG4scil7aWYocjwwJiYwPT1uLmNoKXJldHVybiB0LmNsaXBQb3MoZChuLmxpbmUtMSkpO3ZhciBpPXQuZ2V0TGluZShuLmxpbmUpO2lmKHI+MCYmbi5jaD49aS5sZW5ndGgpcmV0dXJuIHQuY2xpcFBvcyhkKG4ubGluZSsxLDApKTtmb3IodmFyIG8sYT0ic3RhcnQiLHM9bi5jaCx1PXI8MD8wOmkubGVuZ3RoLGM9MDtzIT11O3MrPXIsYysrKXt2YXIgbD1pLmNoYXJBdChyPDA/cy0xOnMpLHA9Il8iIT1sJiZlLmlzV29yZENoYXIobCk/InciOiJvIjtpZigidyI9PXAmJmwudG9VcHBlckNhc2UoKT09bCYmKHA9IlciKSwic3RhcnQiPT1hKSJvIiE9cCYmKGE9ImluIixvPXApO2Vsc2UgaWYoImluIj09YSYmbyE9cCl7aWYoInciPT1vJiYiVyI9PXAmJnI8MCYmcy0tLCJXIj09byYmInciPT1wJiZyPjApe289InciO2NvbnRpbnVlfWJyZWFrfX1yZXR1cm4gZChuLmxpbmUscyl9ZnVuY3Rpb24gbihlLG4pe2UuZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uKHIpe3JldHVybiBlLmRpc3BsYXkuc2hpZnR8fGUuZG9jLmV4dGVuZHx8ci5lbXB0eSgpP3QoZS5kb2Msci5oZWFkLG4pOm48MD9yLmZyb20oKTpyLnRvKCl9KX1mdW5jdGlvbiByKHQsbil7aWYodC5pc1JlYWRPbmx5KCkpcmV0dXJuIGUuUGFzczt0Lm9wZXJhdGlvbihmdW5jdGlvbigpe2Zvcih2YXIgZT10Lmxpc3RTZWxlY3Rpb25zKCkubGVuZ3RoLHI9W10saT0tMSxvPTA7bzxlO28rKyl7dmFyIGE9dC5saXN0U2VsZWN0aW9ucygpW29dLmhlYWQ7aWYoIShhLmxpbmU8PWkpKXt2YXIgcz1kKGEubGluZSsobj8wOjEpLDApO3QucmVwbGFjZVJhbmdlKCJcbiIscyxudWxsLCIraW5zZXJ0TGluZSIpLHQuaW5kZW50TGluZShzLmxpbmUsbnVsbCwhMCksci5wdXNoKHtoZWFkOnMsYW5jaG9yOnN9KSxpPWEubGluZSsxfX10LnNldFNlbGVjdGlvbnMocil9KSx0LmV4ZWNDb21tYW5kKCJpbmRlbnRBdXRvIil9ZnVuY3Rpb24gaSh0LG4pe2Zvcih2YXIgcj1uLmNoLGk9cixvPXQuZ2V0TGluZShuLmxpbmUpO3ImJmUuaXNXb3JkQ2hhcihvLmNoYXJBdChyLTEpKTspLS1yO2Zvcig7aTxvLmxlbmd0aCYmZS5pc1dvcmRDaGFyKG8uY2hhckF0KGkpKTspKytpO3JldHVybntmcm9tOmQobi5saW5lLHIpLHRvOmQobi5saW5lLGkpLHdvcmQ6by5zbGljZShyLGkpfX1mdW5jdGlvbiBvKGUsdCl7Zm9yKHZhciBuPWUubGlzdFNlbGVjdGlvbnMoKSxyPVtdLGk9MDtpPG4ubGVuZ3RoO2krKyl7dmFyIG89bltpXSxhPWUuZmluZFBvc1Yoby5hbmNob3IsdCwibGluZSIsby5hbmNob3IuZ29hbENvbHVtbikscz1lLmZpbmRQb3NWKG8uaGVhZCx0LCJsaW5lIixvLmhlYWQuZ29hbENvbHVtbik7YS5nb2FsQ29sdW1uPW51bGwhPW8uYW5jaG9yLmdvYWxDb2x1bW4/by5hbmNob3IuZ29hbENvbHVtbjplLmN1cnNvckNvb3JkcyhvLmFuY2hvciwiZGl2IikubGVmdCxzLmdvYWxDb2x1bW49bnVsbCE9by5oZWFkLmdvYWxDb2x1bW4/by5oZWFkLmdvYWxDb2x1bW46ZS5jdXJzb3JDb29yZHMoby5oZWFkLCJkaXYiKS5sZWZ0O3ZhciB1PXthbmNob3I6YSxoZWFkOnN9O3IucHVzaChvKSxyLnB1c2godSl9ZS5zZXRTZWxlY3Rpb25zKHIpfWZ1bmN0aW9uIGEoZSx0LG4pe2Zvcih2YXIgcj0wO3I8ZS5sZW5ndGg7cisrKWlmKGVbcl0uZnJvbSgpPT10JiZlW3JdLnRvKCk9PW4pcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gcyh0KXtmb3IodmFyIG49dC5saXN0U2VsZWN0aW9ucygpLHI9W10saT0wO2k8bi5sZW5ndGg7aSsrKXt2YXIgbz1uW2ldLGE9by5oZWFkLHM9dC5zY2FuRm9yQnJhY2tldChhLC0xKTtpZighcylyZXR1cm4hMTtmb3IoOzspe3ZhciB1PXQuc2NhbkZvckJyYWNrZXQoYSwxKTtpZighdSlyZXR1cm4hMTtpZih1LmNoPT1oLmNoYXJBdChoLmluZGV4T2Yocy5jaCkrMSkpe3ZhciBjPWQocy5wb3MubGluZSxzLnBvcy5jaCsxKTtpZigwIT1lLmNtcFBvcyhjLG8uZnJvbSgpKXx8MCE9ZS5jbXBQb3ModS5wb3Msby50bygpKSl7ci5wdXNoKHthbmNob3I6YyxoZWFkOnUucG9zfSk7YnJlYWt9aWYoIShzPXQuc2NhbkZvckJyYWNrZXQocy5wb3MsLTEpKSlyZXR1cm4hMX1hPWQodS5wb3MubGluZSx1LnBvcy5jaCsxKX19cmV0dXJuIHQuc2V0U2VsZWN0aW9ucyhyKSwhMH1mdW5jdGlvbiB1KHQsbil7aWYodC5pc1JlYWRPbmx5KCkpcmV0dXJuIGUuUGFzcztmb3IodmFyIHIsaT10Lmxpc3RTZWxlY3Rpb25zKCksbz1bXSxhPTA7YTxpLmxlbmd0aDthKyspe3ZhciBzPWlbYV07aWYoIXMuZW1wdHkoKSl7Zm9yKHZhciB1PXMuZnJvbSgpLmxpbmUsYz1zLnRvKCkubGluZTthPGkubGVuZ3RoLTEmJmlbYSsxXS5mcm9tKCkubGluZT09YzspYz1pWysrYV0udG8oKS5saW5lO2lbYV0udG8oKS5jaHx8Yy0tLG8ucHVzaCh1LGMpfX1vLmxlbmd0aD9yPSEwOm8ucHVzaCh0LmZpcnN0TGluZSgpLHQubGFzdExpbmUoKSksdC5vcGVyYXRpb24oZnVuY3Rpb24oKXtmb3IodmFyIGU9W10saT0wO2k8by5sZW5ndGg7aSs9Mil7dmFyIGE9b1tpXSxzPW9baSsxXSx1PWQoYSwwKSxjPWQocyksbD10LmdldFJhbmdlKHUsYywhMSk7bj9sLnNvcnQoKTpsLnNvcnQoZnVuY3Rpb24oZSx0KXt2YXIgbj1lLnRvVXBwZXJDYXNlKCkscj10LnRvVXBwZXJDYXNlKCk7cmV0dXJuIG4hPXImJihlPW4sdD1yKSxlPHQ/LTE6ZT09dD8wOjF9KSx0LnJlcGxhY2VSYW5nZShsLHUsYyksciYmZS5wdXNoKHthbmNob3I6dSxoZWFkOmQocysxLDApfSl9ciYmdC5zZXRTZWxlY3Rpb25zKGUsMCl9KX1mdW5jdGlvbiBjKHQsbil7dC5vcGVyYXRpb24oZnVuY3Rpb24oKXtmb3IodmFyIHI9dC5saXN0U2VsZWN0aW9ucygpLG89W10sYT1bXSxzPTA7czxyLmxlbmd0aDtzKyspe3ZhciB1PXJbc107dS5lbXB0eSgpPyhvLnB1c2gocyksYS5wdXNoKCIiKSk6YS5wdXNoKG4odC5nZXRSYW5nZSh1LmZyb20oKSx1LnRvKCkpKSl9dC5yZXBsYWNlU2VsZWN0aW9ucyhhLCJhcm91bmQiLCJjYXNlIik7Zm9yKHZhciBjLHM9by5sZW5ndGgtMTtzPj0wO3MtLSl7dmFyIHU9cltvW3NdXTtpZighKGMmJmUuY21wUG9zKHUuaGVhZCxjKT4wKSl7dmFyIGw9aSh0LHUuaGVhZCk7Yz1sLmZyb20sdC5yZXBsYWNlUmFuZ2UobihsLndvcmQpLGwuZnJvbSxsLnRvKX19fSl9ZnVuY3Rpb24gbCh0KXt2YXIgbj10LmdldEN1cnNvcigiZnJvbSIpLHI9dC5nZXRDdXJzb3IoInRvIik7aWYoMD09ZS5jbXBQb3MobixyKSl7dmFyIG89aSh0LG4pO2lmKCFvLndvcmQpcmV0dXJuO249by5mcm9tLHI9by50b31yZXR1cm57ZnJvbTpuLHRvOnIscXVlcnk6dC5nZXRSYW5nZShuLHIpLHdvcmQ6b319ZnVuY3Rpb24gcChlLHQpe3ZhciBuPWwoZSk7aWYobil7dmFyIHI9bi5xdWVyeSxpPWUuZ2V0U2VhcmNoQ3Vyc29yKHIsdD9uLnRvOm4uZnJvbSk7KHQ/aS5maW5kTmV4dCgpOmkuZmluZFByZXZpb3VzKCkpP2Uuc2V0U2VsZWN0aW9uKGkuZnJvbSgpLGkudG8oKSk6KGk9ZS5nZXRTZWFyY2hDdXJzb3Iocix0P2QoZS5maXJzdExpbmUoKSwwKTplLmNsaXBQb3MoZChlLmxhc3RMaW5lKCkpKSksKHQ/aS5maW5kTmV4dCgpOmkuZmluZFByZXZpb3VzKCkpP2Uuc2V0U2VsZWN0aW9uKGkuZnJvbSgpLGkudG8oKSk6bi53b3JkJiZlLnNldFNlbGVjdGlvbihuLmZyb20sbi50bykpfX12YXIgZj1lLmNvbW1hbmRzLGQ9ZS5Qb3M7Zi5nb1N1YndvcmRMZWZ0PWZ1bmN0aW9uKGUpe24oZSwtMSl9LGYuZ29TdWJ3b3JkUmlnaHQ9ZnVuY3Rpb24oZSl7bihlLDEpfSxmLnNjcm9sbExpbmVVcD1mdW5jdGlvbihlKXt2YXIgdD1lLmdldFNjcm9sbEluZm8oKTtpZighZS5zb21ldGhpbmdTZWxlY3RlZCgpKXt2YXIgbj1lLmxpbmVBdEhlaWdodCh0LnRvcCt0LmNsaWVudEhlaWdodCwibG9jYWwiKTtlLmdldEN1cnNvcigpLmxpbmU+PW4mJmUuZXhlY0NvbW1hbmQoImdvTGluZVVwIil9ZS5zY3JvbGxUbyhudWxsLHQudG9wLWUuZGVmYXVsdFRleHRIZWlnaHQoKSl9LGYuc2Nyb2xsTGluZURvd249ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5nZXRTY3JvbGxJbmZvKCk7aWYoIWUuc29tZXRoaW5nU2VsZWN0ZWQoKSl7dmFyIG49ZS5saW5lQXRIZWlnaHQodC50b3AsImxvY2FsIikrMTtlLmdldEN1cnNvcigpLmxpbmU8PW4mJmUuZXhlY0NvbW1hbmQoImdvTGluZURvd24iKX1lLnNjcm9sbFRvKG51bGwsdC50b3ArZS5kZWZhdWx0VGV4dEhlaWdodCgpKX0sZi5zcGxpdFNlbGVjdGlvbkJ5TGluZT1mdW5jdGlvbihlKXtmb3IodmFyIHQ9ZS5saXN0U2VsZWN0aW9ucygpLG49W10scj0wO3I8dC5sZW5ndGg7cisrKWZvcih2YXIgaT10W3JdLmZyb20oKSxvPXRbcl0udG8oKSxhPWkubGluZTthPD1vLmxpbmU7KythKW8ubGluZT5pLmxpbmUmJmE9PW8ubGluZSYmMD09by5jaHx8bi5wdXNoKHthbmNob3I6YT09aS5saW5lP2k6ZChhLDApLGhlYWQ6YT09by5saW5lP286ZChhKX0pO2Uuc2V0U2VsZWN0aW9ucyhuLDApfSxmLnNpbmdsZVNlbGVjdGlvblRvcD1mdW5jdGlvbihlKXt2YXIgdD1lLmxpc3RTZWxlY3Rpb25zKClbMF07ZS5zZXRTZWxlY3Rpb24odC5hbmNob3IsdC5oZWFkLHtzY3JvbGw6ITF9KX0sZi5zZWxlY3RMaW5lPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1lLmxpc3RTZWxlY3Rpb25zKCksbj1bXSxyPTA7cjx0Lmxlbmd0aDtyKyspe3ZhciBpPXRbcl07bi5wdXNoKHthbmNob3I6ZChpLmZyb20oKS5saW5lLDApLGhlYWQ6ZChpLnRvKCkubGluZSsxLDApfSl9ZS5zZXRTZWxlY3Rpb25zKG4pfSxmLmluc2VydExpbmVBZnRlcj1mdW5jdGlvbihlKXtyZXR1cm4gcihlLCExKX0sZi5pbnNlcnRMaW5lQmVmb3JlPWZ1bmN0aW9uKGUpe3JldHVybiByKGUsITApfSxmLnNlbGVjdE5leHRPY2N1cnJlbmNlPWZ1bmN0aW9uKHQpe3ZhciBuPXQuZ2V0Q3Vyc29yKCJmcm9tIikscj10LmdldEN1cnNvcigidG8iKSxvPXQuc3RhdGUuc3VibGltZUZpbmRGdWxsV29yZD09dC5kb2Muc2VsO2lmKDA9PWUuY21wUG9zKG4scikpe3ZhciBzPWkodCxuKTtpZighcy53b3JkKXJldHVybjt0LnNldFNlbGVjdGlvbihzLmZyb20scy50byksbz0hMH1lbHNle3ZhciB1PXQuZ2V0UmFuZ2UobixyKSxjPW8/bmV3IFJlZ0V4cCgiXFxiIit1KyJcXGIiKTp1LGw9dC5nZXRTZWFyY2hDdXJzb3IoYyxyKSxwPWwuZmluZE5leHQoKTtpZihwfHwobD10LmdldFNlYXJjaEN1cnNvcihjLGQodC5maXJzdExpbmUoKSwwKSkscD1sLmZpbmROZXh0KCkpLCFwfHxhKHQubGlzdFNlbGVjdGlvbnMoKSxsLmZyb20oKSxsLnRvKCkpKXJldHVybiBlLlBhc3M7dC5hZGRTZWxlY3Rpb24obC5mcm9tKCksbC50bygpKX1vJiYodC5zdGF0ZS5zdWJsaW1lRmluZEZ1bGxXb3JkPXQuZG9jLnNlbCl9LGYuYWRkQ3Vyc29yVG9QcmV2TGluZT1mdW5jdGlvbihlKXtvKGUsLTEpfSxmLmFkZEN1cnNvclRvTmV4dExpbmU9ZnVuY3Rpb24oZSl7byhlLDEpfTt2YXIgaD0iKCl7fVtdIjtmLnNlbGVjdFNjb3BlPWZ1bmN0aW9uKGUpe3MoZSl8fGUuZXhlY0NvbW1hbmQoInNlbGVjdEFsbCIpfSxmLnNlbGVjdEJldHdlZW5CcmFja2V0cz1mdW5jdGlvbih0KXtpZighcyh0KSlyZXR1cm4gZS5QYXNzfSxmLmdvVG9CcmFja2V0PWZ1bmN0aW9uKHQpe3QuZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uKG4pe3ZhciByPXQuc2NhbkZvckJyYWNrZXQobi5oZWFkLDEpO2lmKHImJjAhPWUuY21wUG9zKHIucG9zLG4uaGVhZCkpcmV0dXJuIHIucG9zO3ZhciBpPXQuc2NhbkZvckJyYWNrZXQobi5oZWFkLC0xKTtyZXR1cm4gaSYmZChpLnBvcy5saW5lLGkucG9zLmNoKzEpfHxuLmhlYWR9KX0sZi5zd2FwTGluZVVwPWZ1bmN0aW9uKHQpe2lmKHQuaXNSZWFkT25seSgpKXJldHVybiBlLlBhc3M7Zm9yKHZhciBuPXQubGlzdFNlbGVjdGlvbnMoKSxyPVtdLGk9dC5maXJzdExpbmUoKS0xLG89W10sYT0wO2E8bi5sZW5ndGg7YSsrKXt2YXIgcz1uW2FdLHU9cy5mcm9tKCkubGluZS0xLGM9cy50bygpLmxpbmU7by5wdXNoKHthbmNob3I6ZChzLmFuY2hvci5saW5lLTEscy5hbmNob3IuY2gpLGhlYWQ6ZChzLmhlYWQubGluZS0xLHMuaGVhZC5jaCl9KSwwIT1zLnRvKCkuY2h8fHMuZW1wdHkoKXx8LS1jLHU+aT9yLnB1c2godSxjKTpyLmxlbmd0aCYmKHJbci5sZW5ndGgtMV09YyksaT1jfXQub3BlcmF0aW9uKGZ1bmN0aW9uKCl7Zm9yKHZhciBlPTA7ZTxyLmxlbmd0aDtlKz0yKXt2YXIgbj1yW2VdLGk9cltlKzFdLGE9dC5nZXRMaW5lKG4pO3QucmVwbGFjZVJhbmdlKCIiLGQobiwwKSxkKG4rMSwwKSwiK3N3YXBMaW5lIiksaT50Lmxhc3RMaW5lKCk/dC5yZXBsYWNlUmFuZ2UoIlxuIithLGQodC5sYXN0TGluZSgpKSxudWxsLCIrc3dhcExpbmUiKTp0LnJlcGxhY2VSYW5nZShhKyJcbiIsZChpLDApLG51bGwsIitzd2FwTGluZSIpfXQuc2V0U2VsZWN0aW9ucyhvKSx0LnNjcm9sbEludG9WaWV3KCl9KX0sZi5zd2FwTGluZURvd249ZnVuY3Rpb24odCl7aWYodC5pc1JlYWRPbmx5KCkpcmV0dXJuIGUuUGFzcztmb3IodmFyIG49dC5saXN0U2VsZWN0aW9ucygpLHI9W10saT10Lmxhc3RMaW5lKCkrMSxvPW4ubGVuZ3RoLTE7bz49MDtvLS0pe3ZhciBhPW5bb10scz1hLnRvKCkubGluZSsxLHU9YS5mcm9tKCkubGluZTswIT1hLnRvKCkuY2h8fGEuZW1wdHkoKXx8cy0tLHM8aT9yLnB1c2gocyx1KTpyLmxlbmd0aCYmKHJbci5sZW5ndGgtMV09dSksaT11fXQub3BlcmF0aW9uKGZ1bmN0aW9uKCl7Zm9yKHZhciBlPXIubGVuZ3RoLTI7ZT49MDtlLT0yKXt2YXIgbj1yW2VdLGk9cltlKzFdLG89dC5nZXRMaW5lKG4pO249PXQubGFzdExpbmUoKT90LnJlcGxhY2VSYW5nZSgiIixkKG4tMSksZChuKSwiK3N3YXBMaW5lIik6dC5yZXBsYWNlUmFuZ2UoIiIsZChuLDApLGQobisxLDApLCIrc3dhcExpbmUiKSx0LnJlcGxhY2VSYW5nZShvKyJcbiIsZChpLDApLG51bGwsIitzd2FwTGluZSIpfXQuc2Nyb2xsSW50b1ZpZXcoKX0pfSxmLnRvZ2dsZUNvbW1lbnRJbmRlbnRlZD1mdW5jdGlvbihlKXtlLnRvZ2dsZUNvbW1lbnQoe2luZGVudDohMH0pfSxmLmpvaW5MaW5lcz1mdW5jdGlvbihlKXtmb3IodmFyIHQ9ZS5saXN0U2VsZWN0aW9ucygpLG49W10scj0wO3I8dC5sZW5ndGg7cisrKXtmb3IodmFyIGk9dFtyXSxvPWkuZnJvbSgpLGE9by5saW5lLHM9aS50bygpLmxpbmU7cjx0Lmxlbmd0aC0xJiZ0W3IrMV0uZnJvbSgpLmxpbmU9PXM7KXM9dFsrK3JdLnRvKCkubGluZTtuLnB1c2goe3N0YXJ0OmEsZW5kOnMsYW5jaG9yOiFpLmVtcHR5KCkmJm99KX1lLm9wZXJhdGlvbihmdW5jdGlvbigpe2Zvcih2YXIgdD0wLHI9W10saT0wO2k8bi5sZW5ndGg7aSsrKXtmb3IodmFyIG8sYT1uW2ldLHM9YS5hbmNob3ImJmQoYS5hbmNob3IubGluZS10LGEuYW5jaG9yLmNoKSx1PWEuc3RhcnQ7dTw9YS5lbmQ7dSsrKXt2YXIgYz11LXQ7dT09YS5lbmQmJihvPWQoYyxlLmdldExpbmUoYykubGVuZ3RoKzEpKSxjPGUubGFzdExpbmUoKSYmKGUucmVwbGFjZVJhbmdlKCIgIixkKGMpLGQoYysxLC9eXHMqLy5leGVjKGUuZ2V0TGluZShjKzEpKVswXS5sZW5ndGgpKSwrK3QpfXIucHVzaCh7YW5jaG9yOnN8fG8saGVhZDpvfSl9ZS5zZXRTZWxlY3Rpb25zKHIsMCl9KX0sZi5kdXBsaWNhdGVMaW5lPWZ1bmN0aW9uKGUpe2Uub3BlcmF0aW9uKGZ1bmN0aW9uKCl7Zm9yKHZhciB0PWUubGlzdFNlbGVjdGlvbnMoKS5sZW5ndGgsbj0wO248dDtuKyspe3ZhciByPWUubGlzdFNlbGVjdGlvbnMoKVtuXTtyLmVtcHR5KCk/ZS5yZXBsYWNlUmFuZ2UoZS5nZXRMaW5lKHIuaGVhZC5saW5lKSsiXG4iLGQoci5oZWFkLmxpbmUsMCkpOmUucmVwbGFjZVJhbmdlKGUuZ2V0UmFuZ2Uoci5mcm9tKCksci50bygpKSxyLmZyb20oKSl9ZS5zY3JvbGxJbnRvVmlldygpfSl9LGYuc29ydExpbmVzPWZ1bmN0aW9uKGUpe3UoZSwhMCl9LGYuc29ydExpbmVzSW5zZW5zaXRpdmU9ZnVuY3Rpb24oZSl7dShlLCExKX0sZi5uZXh0Qm9va21hcms9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5zdGF0ZS5zdWJsaW1lQm9va21hcmtzO2lmKHQpZm9yKDt0Lmxlbmd0aDspe3ZhciBuPXQuc2hpZnQoKSxyPW4uZmluZCgpO2lmKHIpcmV0dXJuIHQucHVzaChuKSxlLnNldFNlbGVjdGlvbihyLmZyb20sci50byl9fSxmLnByZXZCb29rbWFyaz1mdW5jdGlvbihlKXt2YXIgdD1lLnN0YXRlLnN1YmxpbWVCb29rbWFya3M7aWYodClmb3IoO3QubGVuZ3RoOyl7dC51bnNoaWZ0KHQucG9wKCkpO3ZhciBuPXRbdC5sZW5ndGgtMV0uZmluZCgpO2lmKG4pcmV0dXJuIGUuc2V0U2VsZWN0aW9uKG4uZnJvbSxuLnRvKTt0LnBvcCgpfX0sZi50b2dnbGVCb29rbWFyaz1mdW5jdGlvbihlKXtmb3IodmFyIHQ9ZS5saXN0U2VsZWN0aW9ucygpLG49ZS5zdGF0ZS5zdWJsaW1lQm9va21hcmtzfHwoZS5zdGF0ZS5zdWJsaW1lQm9va21hcmtzPVtdKSxyPTA7cjx0Lmxlbmd0aDtyKyspe2Zvcih2YXIgaT10W3JdLmZyb20oKSxvPXRbcl0udG8oKSxhPXRbcl0uZW1wdHkoKT9lLmZpbmRNYXJrc0F0KGkpOmUuZmluZE1hcmtzKGksbykscz0wO3M8YS5sZW5ndGg7cysrKWlmKGFbc10uc3VibGltZUJvb2ttYXJrKXthW3NdLmNsZWFyKCk7Zm9yKHZhciB1PTA7dTxuLmxlbmd0aDt1Kyspblt1XT09YVtzXSYmbi5zcGxpY2UodS0tLDEpO2JyZWFrfXM9PWEubGVuZ3RoJiZuLnB1c2goZS5tYXJrVGV4dChpLG8se3N1YmxpbWVCb29rbWFyazohMCxjbGVhcldoZW5FbXB0eTohMX0pKX19LGYuY2xlYXJCb29rbWFya3M9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5zdGF0ZS5zdWJsaW1lQm9va21hcmtzO2lmKHQpZm9yKHZhciBuPTA7bjx0Lmxlbmd0aDtuKyspdFtuXS5jbGVhcigpO3QubGVuZ3RoPTB9LGYuc2VsZWN0Qm9va21hcmtzPWZ1bmN0aW9uKGUpe3ZhciB0PWUuc3RhdGUuc3VibGltZUJvb2ttYXJrcyxuPVtdO2lmKHQpZm9yKHZhciByPTA7cjx0Lmxlbmd0aDtyKyspe3ZhciBpPXRbcl0uZmluZCgpO2k/bi5wdXNoKHthbmNob3I6aS5mcm9tLGhlYWQ6aS50b30pOnQuc3BsaWNlKHItLSwwKX1uLmxlbmd0aCYmZS5zZXRTZWxlY3Rpb25zKG4sMCl9LGYuc21hcnRCYWNrc3BhY2U9ZnVuY3Rpb24odCl7aWYodC5zb21ldGhpbmdTZWxlY3RlZCgpKXJldHVybiBlLlBhc3M7dC5vcGVyYXRpb24oZnVuY3Rpb24oKXtmb3IodmFyIG49dC5saXN0U2VsZWN0aW9ucygpLHI9dC5nZXRPcHRpb24oImluZGVudFVuaXQiKSxpPW4ubGVuZ3RoLTE7aT49MDtpLS0pe3ZhciBvPW5baV0uaGVhZCxhPXQuZ2V0UmFuZ2Uoe2xpbmU6by5saW5lLGNoOjB9LG8pLHM9ZS5jb3VudENvbHVtbihhLG51bGwsdC5nZXRPcHRpb24oInRhYlNpemUiKSksdT10LmZpbmRQb3NIKG8sLTEsImNoYXIiLCExKTtpZihhJiYhL1xTLy50ZXN0KGEpJiZzJXI9PTApe3ZhciBjPW5ldyBkKG8ubGluZSxlLmZpbmRDb2x1bW4oYSxzLXIscikpO2MuY2ghPW8uY2gmJih1PWMpfXQucmVwbGFjZVJhbmdlKCIiLHUsbywiK2RlbGV0ZSIpfX0pfSxmLmRlbExpbmVSaWdodD1mdW5jdGlvbihlKXtlLm9wZXJhdGlvbihmdW5jdGlvbigpe2Zvcih2YXIgdD1lLmxpc3RTZWxlY3Rpb25zKCksbj10Lmxlbmd0aC0xO24+PTA7bi0tKWUucmVwbGFjZVJhbmdlKCIiLHRbbl0uYW5jaG9yLGQodFtuXS50bygpLmxpbmUpLCIrZGVsZXRlIik7ZS5zY3JvbGxJbnRvVmlldygpfSl9LGYudXBjYXNlQXRDdXJzb3I9ZnVuY3Rpb24oZSl7YyhlLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRvVXBwZXJDYXNlKCl9KX0sZi5kb3duY2FzZUF0Q3Vyc29yPWZ1bmN0aW9uKGUpe2MoZSxmdW5jdGlvbihlKXtyZXR1cm4gZS50b0xvd2VyQ2FzZSgpfSl9LGYuc2V0U3VibGltZU1hcms9ZnVuY3Rpb24oZSl7ZS5zdGF0ZS5zdWJsaW1lTWFyayYmZS5zdGF0ZS5zdWJsaW1lTWFyay5jbGVhcigpLGUuc3RhdGUuc3VibGltZU1hcms9ZS5zZXRCb29rbWFyayhlLmdldEN1cnNvcigpKX0sZi5zZWxlY3RUb1N1YmxpbWVNYXJrPWZ1bmN0aW9uKGUpe3ZhciB0PWUuc3RhdGUuc3VibGltZU1hcmsmJmUuc3RhdGUuc3VibGltZU1hcmsuZmluZCgpO3QmJmUuc2V0U2VsZWN0aW9uKGUuZ2V0Q3Vyc29yKCksdCl9LGYuZGVsZXRlVG9TdWJsaW1lTWFyaz1mdW5jdGlvbih0KXt2YXIgbj10LnN0YXRlLnN1YmxpbWVNYXJrJiZ0LnN0YXRlLnN1YmxpbWVNYXJrLmZpbmQoKTtpZihuKXt2YXIgcj10LmdldEN1cnNvcigpLGk9bjtpZihlLmNtcFBvcyhyLGkpPjApe3ZhciBvPWk7aT1yLHI9b310LnN0YXRlLnN1YmxpbWVLaWxsZWQ9dC5nZXRSYW5nZShyLGkpLHQucmVwbGFjZVJhbmdlKCIiLHIsaSl9fSxmLnN3YXBXaXRoU3VibGltZU1hcms9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5zdGF0ZS5zdWJsaW1lTWFyayYmZS5zdGF0ZS5zdWJsaW1lTWFyay5maW5kKCk7dCYmKGUuc3RhdGUuc3VibGltZU1hcmsuY2xlYXIoKSxlLnN0YXRlLnN1YmxpbWVNYXJrPWUuc2V0Qm9va21hcmsoZS5nZXRDdXJzb3IoKSksZS5zZXRDdXJzb3IodCkpfSxmLnN1YmxpbWVZYW5rPWZ1bmN0aW9uKGUpe251bGwhPWUuc3RhdGUuc3VibGltZUtpbGxlZCYmZS5yZXBsYWNlU2VsZWN0aW9uKGUuc3RhdGUuc3VibGltZUtpbGxlZCxudWxsLCJwYXN0ZSIpfSxmLnNob3dJbkNlbnRlcj1mdW5jdGlvbihlKXt2YXIgdD1lLmN1cnNvckNvb3JkcyhudWxsLCJsb2NhbCIpO2Uuc2Nyb2xsVG8obnVsbCwodC50b3ArdC5ib3R0b20pLzItZS5nZXRTY3JvbGxJbmZvKCkuY2xpZW50SGVpZ2h0LzIpfSxmLmZpbmRVbmRlcj1mdW5jdGlvbihlKXtwKGUsITApfSxmLmZpbmRVbmRlclByZXZpb3VzPWZ1bmN0aW9uKGUpe3AoZSwhMSl9LGYuZmluZEFsbFVuZGVyPWZ1bmN0aW9uKGUpe3ZhciB0PWwoZSk7aWYodCl7Zm9yKHZhciBuPWUuZ2V0U2VhcmNoQ3Vyc29yKHQucXVlcnkpLHI9W10saT0tMTtuLmZpbmROZXh0KCk7KXIucHVzaCh7YW5jaG9yOm4uZnJvbSgpLGhlYWQ6bi50bygpfSksbi5mcm9tKCkubGluZTw9dC5mcm9tLmxpbmUmJm4uZnJvbSgpLmNoPD10LmZyb20uY2gmJmkrKztlLnNldFNlbGVjdGlvbnMocixpKX19O3ZhciBtPWUua2V5TWFwO20ubWFjU3VibGltZT17IkNtZC1MZWZ0IjoiZ29MaW5lU3RhcnRTbWFydCIsIlNoaWZ0LVRhYiI6ImluZGVudExlc3MiLCJTaGlmdC1DdHJsLUsiOiJkZWxldGVMaW5lIiwiQWx0LVEiOiJ3cmFwTGluZXMiLCJDdHJsLUxlZnQiOiJnb1N1YndvcmRMZWZ0IiwiQ3RybC1SaWdodCI6ImdvU3Vid29yZFJpZ2h0IiwiQ3RybC1BbHQtVXAiOiJzY3JvbGxMaW5lVXAiLCJDdHJsLUFsdC1Eb3duIjoic2Nyb2xsTGluZURvd24iLCJDbWQtTCI6InNlbGVjdExpbmUiLCJTaGlmdC1DbWQtTCI6InNwbGl0U2VsZWN0aW9uQnlMaW5lIixFc2M6InNpbmdsZVNlbGVjdGlvblRvcCIsIkNtZC1FbnRlciI6Imluc2VydExpbmVBZnRlciIsIlNoaWZ0LUNtZC1FbnRlciI6Imluc2VydExpbmVCZWZvcmUiLCJDbWQtRCI6InNlbGVjdE5leHRPY2N1cnJlbmNlIiwiU2hpZnQtQ21kLVNwYWNlIjoic2VsZWN0U2NvcGUiLCJTaGlmdC1DbWQtTSI6InNlbGVjdEJldHdlZW5CcmFja2V0cyIsIkNtZC1NIjoiZ29Ub0JyYWNrZXQiLCJDbWQtQ3RybC1VcCI6InN3YXBMaW5lVXAiLCJDbWQtQ3RybC1Eb3duIjoic3dhcExpbmVEb3duIiwiQ21kLS8iOiJ0b2dnbGVDb21tZW50SW5kZW50ZWQiLCJDbWQtSiI6ImpvaW5MaW5lcyIsIlNoaWZ0LUNtZC1EIjoiZHVwbGljYXRlTGluZSIsRjk6InNvcnRMaW5lcyIsIkNtZC1GOSI6InNvcnRMaW5lc0luc2Vuc2l0aXZlIixGMjoibmV4dEJvb2ttYXJrIiwiU2hpZnQtRjIiOiJwcmV2Qm9va21hcmsiLCJDbWQtRjIiOiJ0b2dnbGVCb29rbWFyayIsIlNoaWZ0LUNtZC1GMiI6ImNsZWFyQm9va21hcmtzIiwiQWx0LUYyIjoic2VsZWN0Qm9va21hcmtzIixCYWNrc3BhY2U6InNtYXJ0QmFja3NwYWNlIiwiQ21kLUsgQ21kLUsiOiJkZWxMaW5lUmlnaHQiLCJDbWQtSyBDbWQtVSI6InVwY2FzZUF0Q3Vyc29yIiwiQ21kLUsgQ21kLUwiOiJkb3duY2FzZUF0Q3Vyc29yIiwiQ21kLUsgQ21kLVNwYWNlIjoic2V0U3VibGltZU1hcmsiLCJDbWQtSyBDbWQtQSI6InNlbGVjdFRvU3VibGltZU1hcmsiLCJDbWQtSyBDbWQtVyI6ImRlbGV0ZVRvU3VibGltZU1hcmsiLCJDbWQtSyBDbWQtWCI6InN3YXBXaXRoU3VibGltZU1hcmsiLCJDbWQtSyBDbWQtWSI6InN1YmxpbWVZYW5rIiwiQ21kLUsgQ21kLUMiOiJzaG93SW5DZW50ZXIiLCJDbWQtSyBDbWQtRyI6ImNsZWFyQm9va21hcmtzIiwiQ21kLUsgQ21kLUJhY2tzcGFjZSI6ImRlbExpbmVMZWZ0IiwiQ21kLUsgQ21kLTAiOiJ1bmZvbGRBbGwiLCJDbWQtSyBDbWQtSiI6InVuZm9sZEFsbCIsIkN0cmwtU2hpZnQtVXAiOiJhZGRDdXJzb3JUb1ByZXZMaW5lIiwiQ3RybC1TaGlmdC1Eb3duIjoiYWRkQ3Vyc29yVG9OZXh0TGluZSIsIkNtZC1GMyI6ImZpbmRVbmRlciIsIlNoaWZ0LUNtZC1GMyI6ImZpbmRVbmRlclByZXZpb3VzIiwiQWx0LUYzIjoiZmluZEFsbFVuZGVyIiwiU2hpZnQtQ21kLVsiOiJmb2xkIiwiU2hpZnQtQ21kLV0iOiJ1bmZvbGQiLCJDbWQtSSI6ImZpbmRJbmNyZW1lbnRhbCIsIlNoaWZ0LUNtZC1JIjoiZmluZEluY3JlbWVudGFsUmV2ZXJzZSIsIkNtZC1IIjoicmVwbGFjZSIsRjM6ImZpbmROZXh0IiwiU2hpZnQtRjMiOiJmaW5kUHJldiIsZmFsbHRocm91Z2g6Im1hY0RlZmF1bHQifSxlLm5vcm1hbGl6ZUtleU1hcChtLm1hY1N1YmxpbWUpLG0ucGNTdWJsaW1lPXsiU2hpZnQtVGFiIjoiaW5kZW50TGVzcyIsIlNoaWZ0LUN0cmwtSyI6ImRlbGV0ZUxpbmUiLCJBbHQtUSI6IndyYXBMaW5lcyIsIkN0cmwtVCI6InRyYW5zcG9zZUNoYXJzIiwiQWx0LUxlZnQiOiJnb1N1YndvcmRMZWZ0IiwiQWx0LVJpZ2h0IjoiZ29TdWJ3b3JkUmlnaHQiLCJDdHJsLVVwIjoic2Nyb2xsTGluZVVwIiwiQ3RybC1Eb3duIjoic2Nyb2xsTGluZURvd24iLCJDdHJsLUwiOiJzZWxlY3RMaW5lIiwiU2hpZnQtQ3RybC1MIjoic3BsaXRTZWxlY3Rpb25CeUxpbmUiLEVzYzoic2luZ2xlU2VsZWN0aW9uVG9wIiwiQ3RybC1FbnRlciI6Imluc2VydExpbmVBZnRlciIsIlNoaWZ0LUN0cmwtRW50ZXIiOiJpbnNlcnRMaW5lQmVmb3JlIiwiQ3RybC1EIjoic2VsZWN0TmV4dE9jY3VycmVuY2UiLCJTaGlmdC1DdHJsLVNwYWNlIjoic2VsZWN0U2NvcGUiLCJTaGlmdC1DdHJsLU0iOiJzZWxlY3RCZXR3ZWVuQnJhY2tldHMiLCJDdHJsLU0iOiJnb1RvQnJhY2tldCIsIlNoaWZ0LUN0cmwtVXAiOiJzd2FwTGluZVVwIiwiU2hpZnQtQ3RybC1Eb3duIjoic3dhcExpbmVEb3duIiwiQ3RybC0vIjoidG9nZ2xlQ29tbWVudEluZGVudGVkIiwiQ3RybC1KIjoiam9pbkxpbmVzIiwiU2hpZnQtQ3RybC1EIjoiZHVwbGljYXRlTGluZSIsRjk6InNvcnRMaW5lcyIsIkN0cmwtRjkiOiJzb3J0TGluZXNJbnNlbnNpdGl2ZSIsRjI6Im5leHRCb29rbWFyayIsIlNoaWZ0LUYyIjoicHJldkJvb2ttYXJrIiwiQ3RybC1GMiI6InRvZ2dsZUJvb2ttYXJrIiwiU2hpZnQtQ3RybC1GMiI6ImNsZWFyQm9va21hcmtzIiwiQWx0LUYyIjoic2VsZWN0Qm9va21hcmtzIixCYWNrc3BhY2U6InNtYXJ0QmFja3NwYWNlIiwiQ3RybC1LIEN0cmwtSyI6ImRlbExpbmVSaWdodCIsIkN0cmwtSyBDdHJsLVUiOiJ1cGNhc2VBdEN1cnNvciIsIkN0cmwtSyBDdHJsLUwiOiJkb3duY2FzZUF0Q3Vyc29yIiwiQ3RybC1LIEN0cmwtU3BhY2UiOiJzZXRTdWJsaW1lTWFyayIsIkN0cmwtSyBDdHJsLUEiOiJzZWxlY3RUb1N1YmxpbWVNYXJrIiwiQ3RybC1LIEN0cmwtVyI6ImRlbGV0ZVRvU3VibGltZU1hcmsiLCJDdHJsLUsgQ3RybC1YIjoic3dhcFdpdGhTdWJsaW1lTWFyayIsIkN0cmwtSyBDdHJsLVkiOiJzdWJsaW1lWWFuayIsIkN0cmwtSyBDdHJsLUMiOiJzaG93SW5DZW50ZXIiLCJDdHJsLUsgQ3RybC1HIjoiY2xlYXJCb29rbWFya3MiLCJDdHJsLUsgQ3RybC1CYWNrc3BhY2UiOiJkZWxMaW5lTGVmdCIsIkN0cmwtSyBDdHJsLTAiOiJ1bmZvbGRBbGwiLCJDdHJsLUsgQ3RybC1KIjoidW5mb2xkQWxsIiwiQ3RybC1BbHQtVXAiOiJhZGRDdXJzb3JUb1ByZXZMaW5lIiwiQ3RybC1BbHQtRG93biI6ImFkZEN1cnNvclRvTmV4dExpbmUiLCJDdHJsLUYzIjoiZmluZFVuZGVyIiwiU2hpZnQtQ3RybC1GMyI6ImZpbmRVbmRlclByZXZpb3VzIiwiQWx0LUYzIjoiZmluZEFsbFVuZGVyIiwiU2hpZnQtQ3RybC1bIjoiZm9sZCIsIlNoaWZ0LUN0cmwtXSI6InVuZm9sZCIsIkN0cmwtSSI6ImZpbmRJbmNyZW1lbnRhbCIsIlNoaWZ0LUN0cmwtSSI6ImZpbmRJbmNyZW1lbnRhbFJldmVyc2UiLCJDdHJsLUgiOiJyZXBsYWNlIixGMzoiZmluZE5leHQiLCJTaGlmdC1GMyI6ImZpbmRQcmV2IixmYWxsdGhyb3VnaDoicGNEZWZhdWx0In0sZS5ub3JtYWxpemVLZXlNYXAobS5wY1N1YmxpbWUpO3ZhciBnPW0uZGVmYXVsdD09bS5tYWNEZWZhdWx0O20uc3VibGltZT1nP20ubWFjU3VibGltZTptLnBjU3VibGltZX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dmFyIHQ9dm9pZCAwO3JldHVybiBvKGUsZnVuY3Rpb24oZSl7c3dpdGNoKGUua2luZCl7Y2FzZSJRdWVyeSI6Y2FzZSJTaG9ydFF1ZXJ5IjpjYXNlIk11dGF0aW9uIjpjYXNlIlN1YnNjcmlwdGlvbiI6Y2FzZSJGcmFnbWVudERlZmluaXRpb24iOnQ9ZX19KSx0fWZ1bmN0aW9uIGkoZSx0LG4pe3JldHVybiBuPT09aC5TY2hlbWFNZXRhRmllbGREZWYubmFtZSYmZS5nZXRRdWVyeVR5cGUoKT09PXQ/aC5TY2hlbWFNZXRhRmllbGREZWY6bj09PWguVHlwZU1ldGFGaWVsZERlZi5uYW1lJiZlLmdldFF1ZXJ5VHlwZSgpPT09dD9oLlR5cGVNZXRhRmllbGREZWY6bj09PWguVHlwZU5hbWVNZXRhRmllbGREZWYubmFtZSYmKDAsZC5pc0NvbXBvc2l0ZVR5cGUpKHQpP2guVHlwZU5hbWVNZXRhRmllbGREZWY6dC5nZXRGaWVsZHMmJiJmdW5jdGlvbiI9PT10eXBlb2YgdC5nZXRGaWVsZHM/dC5nZXRGaWVsZHMoKVtuXTpudWxsfWZ1bmN0aW9uIG8oZSx0KXtmb3IodmFyIG49W10scj1lO3ImJnIua2luZDspbi5wdXNoKHIpLHI9ci5wcmV2U3RhdGU7Zm9yKHZhciBpPW4ubGVuZ3RoLTE7aT49MDtpLS0pdChuW2ldKX1mdW5jdGlvbiBhKGUpe2Zvcih2YXIgdD1PYmplY3Qua2V5cyhlKSxuPXQubGVuZ3RoLHI9bmV3IEFycmF5KG4pLGk9MDtpPG47KytpKXJbaV09ZVt0W2ldXTtyZXR1cm4gcn1mdW5jdGlvbiBzKGUsdCl7cmV0dXJuIHUodCxsKGUuc3RyaW5nKSl9ZnVuY3Rpb24gdShlLHQpe3JldHVybiB0P2MoYyhlLm1hcChmdW5jdGlvbihlKXtyZXR1cm57cHJveGltaXR5OnAobChlLmxhYmVsKSx0KSxlbnRyeTplfX0pLGZ1bmN0aW9uKGUpe3JldHVybiBlLnByb3hpbWl0eTw9Mn0pLGZ1bmN0aW9uKGUpe3JldHVybiFlLmVudHJ5LmlzRGVwcmVjYXRlZH0pLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm4oZS5lbnRyeS5pc0RlcHJlY2F0ZWQ/MTowKS0odC5lbnRyeS5pc0RlcHJlY2F0ZWQ/MTowKXx8ZS5wcm94aW1pdHktdC5wcm94aW1pdHl8fGUuZW50cnkubGFiZWwubGVuZ3RoLXQuZW50cnkubGFiZWwubGVuZ3RofSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLmVudHJ5fSk6YyhlLGZ1bmN0aW9uKGUpe3JldHVybiFlLmlzRGVwcmVjYXRlZH0pfWZ1bmN0aW9uIGMoZSx0KXt2YXIgbj1lLmZpbHRlcih0KTtyZXR1cm4gMD09PW4ubGVuZ3RoP2U6bn1mdW5jdGlvbiBsKGUpe3JldHVybiBlLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvXFcvZywiIil9ZnVuY3Rpb24gcChlLHQpe3ZhciBuPWYodCxlKTtyZXR1cm4gZS5sZW5ndGg+dC5sZW5ndGgmJihuLT1lLmxlbmd0aC10Lmxlbmd0aC0xLG4rPTA9PT1lLmluZGV4T2YodCk/MDouNSksbn1mdW5jdGlvbiBmKGUsdCl7dmFyIG49dm9pZCAwLHI9dm9pZCAwLGk9W10sbz1lLmxlbmd0aCxhPXQubGVuZ3RoO2ZvcihuPTA7bjw9bztuKyspaVtuXT1bbl07Zm9yKHI9MTtyPD1hO3IrKylpWzBdW3JdPXI7Zm9yKG49MTtuPD1vO24rKylmb3Iocj0xO3I8PWE7cisrKXt2YXIgcz1lW24tMV09PT10W3ItMV0/MDoxO2lbbl1bcl09TWF0aC5taW4oaVtuLTFdW3JdKzEsaVtuXVtyLTFdKzEsaVtuLTFdW3ItMV0rcyksbj4xJiZyPjEmJmVbbi0xXT09PXRbci0yXSYmZVtuLTJdPT09dFtyLTFdJiYoaVtuXVtyXT1NYXRoLm1pbihpW25dW3JdLGlbbi0yXVtyLTJdK3MpKX1yZXR1cm4gaVtvXVthXX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5nZXREZWZpbml0aW9uU3RhdGU9cix0LmdldEZpZWxkRGVmPWksdC5mb3JFYWNoU3RhdGU9byx0Lm9iamVjdFZhbHVlcz1hLHQuaGludExpc3Q9czt2YXIgZD1uKDcpLGg9bigyOCl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbixyKXt2YXIgdT1yfHxwKHQsbiksZj0iSW52YWxpZCI9PT11LnN0YXRlLmtpbmQ/dS5zdGF0ZS5wcmV2U3RhdGU6dS5zdGF0ZTtpZighZilyZXR1cm5bXTt2YXIgZD1mLmtpbmQsbT1mLnN0ZXAsZz1oKGUsdS5zdGF0ZSk7aWYoIkRvY3VtZW50Ij09PWQpcmV0dXJuKDAsYi5oaW50TGlzdCkodSxbe2xhYmVsOiJxdWVyeSJ9LHtsYWJlbDoibXV0YXRpb24ifSx7bGFiZWw6InN1YnNjcmlwdGlvbiJ9LHtsYWJlbDoiZnJhZ21lbnQifSx7bGFiZWw6InsifV0pO2lmKCJTZWxlY3Rpb25TZXQiPT09ZHx8IkZpZWxkIj09PWR8fCJBbGlhc2VkRmllbGQiPT09ZClyZXR1cm4gaSh1LGcsZSk7aWYoIkFyZ3VtZW50cyI9PT1kfHwiQXJndW1lbnQiPT09ZCYmMD09PW0pe3ZhciB5PWcuYXJnRGVmcztpZih5KXJldHVybigwLGIuaGludExpc3QpKHUseS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJue2xhYmVsOmUubmFtZSxkZXRhaWw6U3RyaW5nKGUudHlwZSksZG9jdW1lbnRhdGlvbjplLmRlc2NyaXB0aW9ufX0pKX1pZigoIk9iamVjdFZhbHVlIj09PWR8fCJPYmplY3RGaWVsZCI9PT1kJiYwPT09bSkmJmcub2JqZWN0RmllbGREZWZzKXt2YXIgdj0oMCxiLm9iamVjdFZhbHVlcykoZy5vYmplY3RGaWVsZERlZnMpO3JldHVybigwLGIuaGludExpc3QpKHUsdi5tYXAoZnVuY3Rpb24oZSl7cmV0dXJue2xhYmVsOmUubmFtZSxkZXRhaWw6U3RyaW5nKGUudHlwZSksZG9jdW1lbnRhdGlvbjplLmRlc2NyaXB0aW9ufX0pKX1yZXR1cm4iRW51bVZhbHVlIj09PWR8fCJMaXN0VmFsdWUiPT09ZCYmMT09PW18fCJPYmplY3RGaWVsZCI9PT1kJiYyPT09bXx8IkFyZ3VtZW50Ij09PWQmJjI9PT1tP28odSxnKToiVHlwZUNvbmRpdGlvbiI9PT1kJiYxPT09bXx8Ik5hbWVkVHlwZSI9PT1kJiZudWxsIT1mLnByZXZTdGF0ZSYmIlR5cGVDb25kaXRpb24iPT09Zi5wcmV2U3RhdGUua2luZD9hKHUsZyxlKToiRnJhZ21lbnRTcHJlYWQiPT09ZCYmMT09PW0/cyh1LGcsZSx0KToiVmFyaWFibGVEZWZpbml0aW9uIj09PWQmJjI9PT1tfHwiTGlzdFR5cGUiPT09ZCYmMT09PW18fCJOYW1lZFR5cGUiPT09ZCYmZi5wcmV2U3RhdGUmJigiVmFyaWFibGVEZWZpbml0aW9uIj09PWYucHJldlN0YXRlLmtpbmR8fCJMaXN0VHlwZSI9PT1mLnByZXZTdGF0ZS5raW5kKT9jKHUsZSk6IkRpcmVjdGl2ZSI9PT1kP2wodSxmLGUpOltdfWZ1bmN0aW9uIGkoZSx0LG4pe2lmKHQucGFyZW50VHlwZSl7dmFyIHI9dC5wYXJlbnRUeXBlLGk9ci5nZXRGaWVsZHMgaW5zdGFuY2VvZiBGdW5jdGlvbj8oMCxiLm9iamVjdFZhbHVlcykoci5nZXRGaWVsZHMoKSk6W107cmV0dXJuKDAseS5pc0Fic3RyYWN0VHlwZSkocikmJmkucHVzaCh5LlR5cGVOYW1lTWV0YUZpZWxkRGVmKSxyPT09bi5nZXRRdWVyeVR5cGUoKSYmaS5wdXNoKHkuU2NoZW1hTWV0YUZpZWxkRGVmLHkuVHlwZU1ldGFGaWVsZERlZiksKDAsYi5oaW50TGlzdCkoZSxpLm1hcChmdW5jdGlvbihlKXtyZXR1cm57bGFiZWw6ZS5uYW1lLGRldGFpbDpTdHJpbmcoZS50eXBlKSxkb2N1bWVudGF0aW9uOmUuZGVzY3JpcHRpb24saXNEZXByZWNhdGVkOmUuaXNEZXByZWNhdGVkLGRlcHJlY2F0aW9uUmVhc29uOmUuZGVwcmVjYXRpb25SZWFzb259fSkpfXJldHVybltdfWZ1bmN0aW9uIG8oZSx0KXt2YXIgbj0oMCx5LmdldE5hbWVkVHlwZSkodC5pbnB1dFR5cGUpO2lmKG4gaW5zdGFuY2VvZiB5LkdyYXBoUUxFbnVtVHlwZSl7dmFyIHI9bi5nZXRWYWx1ZXMoKTtyZXR1cm4oMCxiLmhpbnRMaXN0KShlLHIubWFwKGZ1bmN0aW9uKGUpe3JldHVybntsYWJlbDplLm5hbWUsZGV0YWlsOlN0cmluZyhuKSxkb2N1bWVudGF0aW9uOmUuZGVzY3JpcHRpb24saXNEZXByZWNhdGVkOmUuaXNEZXByZWNhdGVkLGRlcHJlY2F0aW9uUmVhc29uOmUuZGVwcmVjYXRpb25SZWFzb259fSkpfXJldHVybiBuPT09eS5HcmFwaFFMQm9vbGVhbj8oMCxiLmhpbnRMaXN0KShlLFt7bGFiZWw6InRydWUiLGRldGFpbDpTdHJpbmcoeS5HcmFwaFFMQm9vbGVhbiksZG9jdW1lbnRhdGlvbjoiTm90IGZhbHNlLiJ9LHtsYWJlbDoiZmFsc2UiLGRldGFpbDpTdHJpbmcoeS5HcmFwaFFMQm9vbGVhbiksZG9jdW1lbnRhdGlvbjoiTm90IHRydWUuIn1dKTpbXX1mdW5jdGlvbiBhKGUsdCxuKXt2YXIgcj12b2lkIDA7aWYodC5wYXJlbnRUeXBlKWlmKCgwLHkuaXNBYnN0cmFjdFR5cGUpKHQucGFyZW50VHlwZSkpe3ZhciBpPSgwLHkuYXNzZXJ0QWJzdHJhY3RUeXBlKSh0LnBhcmVudFR5cGUpLG89bi5nZXRQb3NzaWJsZVR5cGVzKGkpLGE9T2JqZWN0LmNyZWF0ZShudWxsKTtvLmZvckVhY2goZnVuY3Rpb24oZSl7ZS5nZXRJbnRlcmZhY2VzKCkuZm9yRWFjaChmdW5jdGlvbihlKXthW2UubmFtZV09ZX0pfSkscj1vLmNvbmNhdCgoMCxiLm9iamVjdFZhbHVlcykoYSkpfWVsc2Ugcj1bdC5wYXJlbnRUeXBlXTtlbHNle3ZhciBzPW4uZ2V0VHlwZU1hcCgpO3I9KDAsYi5vYmplY3RWYWx1ZXMpKHMpLmZpbHRlcih5LmlzQ29tcG9zaXRlVHlwZSl9cmV0dXJuKDAsYi5oaW50TGlzdCkoZSxyLm1hcChmdW5jdGlvbihlKXt2YXIgdD0oMCx5LmdldE5hbWVkVHlwZSkoZSk7cmV0dXJue2xhYmVsOlN0cmluZyhlKSxkb2N1bWVudGF0aW9uOnQmJnQuZGVzY3JpcHRpb258fCIifX0pKX1mdW5jdGlvbiBzKGUsdCxuLHIpe3ZhciBpPW4uZ2V0VHlwZU1hcCgpLG89KDAsYi5nZXREZWZpbml0aW9uU3RhdGUpKGUuc3RhdGUpLGE9dShyKSxzPWEuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBpW2UudHlwZUNvbmRpdGlvbi5uYW1lLnZhbHVlXSYmIShvJiYiRnJhZ21lbnREZWZpbml0aW9uIj09PW8ua2luZCYmby5uYW1lPT09ZS5uYW1lLnZhbHVlKSYmKDAseS5pc0NvbXBvc2l0ZVR5cGUpKHQucGFyZW50VHlwZSkmJigwLHkuaXNDb21wb3NpdGVUeXBlKShpW2UudHlwZUNvbmRpdGlvbi5uYW1lLnZhbHVlXSkmJigwLHkuZG9UeXBlc092ZXJsYXApKG4sdC5wYXJlbnRUeXBlLGlbZS50eXBlQ29uZGl0aW9uLm5hbWUudmFsdWVdKX0pO3JldHVybigwLGIuaGludExpc3QpKGUscy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJue2xhYmVsOmUubmFtZS52YWx1ZSxkZXRhaWw6U3RyaW5nKGlbZS50eXBlQ29uZGl0aW9uLm5hbWUudmFsdWVdKSxkb2N1bWVudGF0aW9uOiJmcmFnbWVudCAiK2UubmFtZS52YWx1ZSsiIG9uICIrZS50eXBlQ29uZGl0aW9uLm5hbWUudmFsdWV9fSkpfWZ1bmN0aW9uIHUoZSl7dmFyIHQ9W107cmV0dXJuIGYoZSxmdW5jdGlvbihlLG4peyJGcmFnbWVudERlZmluaXRpb24iPT09bi5raW5kJiZuLm5hbWUmJm4udHlwZSYmdC5wdXNoKHtraW5kOiJGcmFnbWVudERlZmluaXRpb24iLG5hbWU6e2tpbmQ6Ik5hbWUiLHZhbHVlOm4ubmFtZX0sc2VsZWN0aW9uU2V0OntraW5kOiJTZWxlY3Rpb25TZXQiLHNlbGVjdGlvbnM6W119LHR5cGVDb25kaXRpb246e2tpbmQ6Ik5hbWVkVHlwZSIsbmFtZTp7a2luZDoiTmFtZSIsdmFsdWU6bi50eXBlfX19KX0pLHR9ZnVuY3Rpb24gYyhlLHQpe3ZhciBuPXQuZ2V0VHlwZU1hcCgpLHI9KDAsYi5vYmplY3RWYWx1ZXMpKG4pLmZpbHRlcih5LmlzSW5wdXRUeXBlKTtyZXR1cm4oMCxiLmhpbnRMaXN0KShlLHIubWFwKGZ1bmN0aW9uKGUpe3JldHVybntsYWJlbDplLm5hbWUsZG9jdW1lbnRhdGlvbjplLmRlc2NyaXB0aW9ufX0pKX1mdW5jdGlvbiBsKGUsdCxuKXtpZih0LnByZXZTdGF0ZSYmdC5wcmV2U3RhdGUua2luZCl7dmFyIHI9bi5nZXREaXJlY3RpdmVzKCkuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBkKHQucHJldlN0YXRlLGUpfSk7cmV0dXJuKDAsYi5oaW50TGlzdCkoZSxyLm1hcChmdW5jdGlvbihlKXtyZXR1cm57bGFiZWw6ZS5uYW1lLGRvY3VtZW50YXRpb246ZS5kZXNjcmlwdGlvbnx8IiJ9fSkpfXJldHVybltdfWZ1bmN0aW9uIHAoZSx0KXt2YXIgbj1udWxsLHI9bnVsbCxpPW51bGwsbz1mKGUsZnVuY3Rpb24oZSxvLGEscyl7aWYocz09PXQubGluZSYmZS5nZXRDdXJyZW50UG9zaXRpb24oKT49dC5jaGFyYWN0ZXIpcmV0dXJuIG49YSxyPWcoe30sbyksaT1lLmN1cnJlbnQoKSwiQlJFQUsifSk7cmV0dXJue3N0YXJ0Om8uc3RhcnQsZW5kOm8uZW5kLHN0cmluZzppfHxvLnN0cmluZyxzdGF0ZTpyfHxvLnN0YXRlLHN0eWxlOm58fG8uc3R5bGV9fWZ1bmN0aW9uIGYoZSx0KXtmb3IodmFyIG49ZS5zcGxpdCgiXG4iKSxyPSgwLHYub25saW5lUGFyc2VyKSgpLGk9ci5zdGFydFN0YXRlKCksbz0iIixhPW5ldyB2LkNoYXJhY3RlclN0cmVhbSgiIikscz0wO3M8bi5sZW5ndGg7cysrKXtmb3IoYT1uZXcgdi5DaGFyYWN0ZXJTdHJlYW0obltzXSk7IWEuZW9sKCk7KXtvPXIudG9rZW4oYSxpKTtpZigiQlJFQUsiPT09dChhLGksbyxzKSlicmVha310KGEsaSxvLHMpLGkua2luZHx8KGk9ci5zdGFydFN0YXRlKCkpfXJldHVybntzdGFydDphLmdldFN0YXJ0T2ZUb2tlbigpLGVuZDphLmdldEN1cnJlbnRQb3NpdGlvbigpLHN0cmluZzphLmN1cnJlbnQoKSxzdGF0ZTppLHN0eWxlOm99fWZ1bmN0aW9uIGQoZSx0KXtpZighZXx8IWUua2luZClyZXR1cm4hMTt2YXIgbj1lLmtpbmQscj10LmxvY2F0aW9ucztzd2l0Y2gobil7Y2FzZSJRdWVyeSI6cmV0dXJuLTEhPT1yLmluZGV4T2YoIlFVRVJZIik7Y2FzZSJNdXRhdGlvbiI6cmV0dXJuLTEhPT1yLmluZGV4T2YoIk1VVEFUSU9OIik7Y2FzZSJTdWJzY3JpcHRpb24iOnJldHVybi0xIT09ci5pbmRleE9mKCJTVUJTQ1JJUFRJT04iKTtjYXNlIkZpZWxkIjpjYXNlIkFsaWFzZWRGaWVsZCI6cmV0dXJuLTEhPT1yLmluZGV4T2YoIkZJRUxEIik7Y2FzZSJGcmFnbWVudERlZmluaXRpb24iOnJldHVybi0xIT09ci5pbmRleE9mKCJGUkFHTUVOVF9ERUZJTklUSU9OIik7Y2FzZSJGcmFnbWVudFNwcmVhZCI6cmV0dXJuLTEhPT1yLmluZGV4T2YoIkZSQUdNRU5UX1NQUkVBRCIpO2Nhc2UiSW5saW5lRnJhZ21lbnQiOnJldHVybi0xIT09ci5pbmRleE9mKCJJTkxJTkVfRlJBR01FTlQiKTtjYXNlIlNjaGVtYURlZiI6cmV0dXJuLTEhPT1yLmluZGV4T2YoIlNDSEVNQSIpO2Nhc2UiU2NhbGFyRGVmIjpyZXR1cm4tMSE9PXIuaW5kZXhPZigiU0NBTEFSIik7Y2FzZSJPYmplY3RUeXBlRGVmIjpyZXR1cm4tMSE9PXIuaW5kZXhPZigiT0JKRUNUIik7Y2FzZSJGaWVsZERlZiI6cmV0dXJuLTEhPT1yLmluZGV4T2YoIkZJRUxEX0RFRklOSVRJT04iKTtjYXNlIkludGVyZmFjZURlZiI6cmV0dXJuLTEhPT1yLmluZGV4T2YoIklOVEVSRkFDRSIpO2Nhc2UiVW5pb25EZWYiOnJldHVybi0xIT09ci5pbmRleE9mKCJVTklPTiIpO2Nhc2UiRW51bURlZiI6cmV0dXJuLTEhPT1yLmluZGV4T2YoIkVOVU0iKTtjYXNlIkVudW1WYWx1ZSI6cmV0dXJuLTEhPT1yLmluZGV4T2YoIkVOVU1fVkFMVUUiKTtjYXNlIklucHV0RGVmIjpyZXR1cm4tMSE9PXIuaW5kZXhPZigiSU5QVVRfT0JKRUNUIik7Y2FzZSJJbnB1dFZhbHVlRGVmIjpzd2l0Y2goZS5wcmV2U3RhdGUmJmUucHJldlN0YXRlLmtpbmQpe2Nhc2UiQXJndW1lbnRzRGVmIjpyZXR1cm4tMSE9PXIuaW5kZXhPZigiQVJHVU1FTlRfREVGSU5JVElPTiIpO2Nhc2UiSW5wdXREZWYiOnJldHVybi0xIT09ci5pbmRleE9mKCJJTlBVVF9GSUVMRF9ERUZJTklUSU9OIil9fXJldHVybiExfWZ1bmN0aW9uIGgoZSx0KXt2YXIgbj12b2lkIDAscj12b2lkIDAsaT12b2lkIDAsbz12b2lkIDAsYT12b2lkIDAscz12b2lkIDAsdT12b2lkIDAsYz12b2lkIDAsbD12b2lkIDA7cmV0dXJuKDAsYi5mb3JFYWNoU3RhdGUpKHQsZnVuY3Rpb24odCl7c3dpdGNoKHQua2luZCl7Y2FzZSJRdWVyeSI6Y2FzZSJTaG9ydFF1ZXJ5IjpsPWUuZ2V0UXVlcnlUeXBlKCk7YnJlYWs7Y2FzZSJNdXRhdGlvbiI6bD1lLmdldE11dGF0aW9uVHlwZSgpO2JyZWFrO2Nhc2UiU3Vic2NyaXB0aW9uIjpsPWUuZ2V0U3Vic2NyaXB0aW9uVHlwZSgpO2JyZWFrO2Nhc2UiSW5saW5lRnJhZ21lbnQiOmNhc2UiRnJhZ21lbnREZWZpbml0aW9uIjp0LnR5cGUmJihsPWUuZ2V0VHlwZSh0LnR5cGUpKTticmVhaztjYXNlIkZpZWxkIjpjYXNlIkFsaWFzZWRGaWVsZCI6bCYmdC5uYW1lPyhhPWM/KDAsYi5nZXRGaWVsZERlZikoZSxjLHQubmFtZSk6bnVsbCxsPWE/YS50eXBlOm51bGwpOmE9bnVsbDticmVhaztjYXNlIlNlbGVjdGlvblNldCI6Yz0oMCx5LmdldE5hbWVkVHlwZSkobCk7YnJlYWs7Y2FzZSJEaXJlY3RpdmUiOmk9dC5uYW1lP2UuZ2V0RGlyZWN0aXZlKHQubmFtZSk6bnVsbDticmVhaztjYXNlIkFyZ3VtZW50cyI6aWYodC5wcmV2U3RhdGUpc3dpdGNoKHQucHJldlN0YXRlLmtpbmQpe2Nhc2UiRmllbGQiOnI9YSYmYS5hcmdzO2JyZWFrO2Nhc2UiRGlyZWN0aXZlIjpyPWkmJmkuYXJnczticmVhaztjYXNlIkFsaWFzZWRGaWVsZCI6dmFyIHA9dC5wcmV2U3RhdGUmJnQucHJldlN0YXRlLm5hbWU7aWYoIXApe3I9bnVsbDticmVha312YXIgZj1jPygwLGIuZ2V0RmllbGREZWYpKGUsYyxwKTpudWxsO2lmKCFmKXtyPW51bGw7YnJlYWt9cj1mLmFyZ3M7YnJlYWs7ZGVmYXVsdDpyPW51bGx9ZWxzZSByPW51bGw7YnJlYWs7Y2FzZSJBcmd1bWVudCI6aWYocilmb3IodmFyIGQ9MDtkPHIubGVuZ3RoO2QrKylpZihyW2RdLm5hbWU9PT10Lm5hbWUpe249cltkXTticmVha31zPW4mJm4udHlwZTticmVhaztjYXNlIkVudW1WYWx1ZSI6dmFyIGg9KDAseS5nZXROYW1lZFR5cGUpKHMpO289aCBpbnN0YW5jZW9mIHkuR3JhcGhRTEVudW1UeXBlP20oaC5nZXRWYWx1ZXMoKSxmdW5jdGlvbihlKXtyZXR1cm4gZS52YWx1ZT09PXQubmFtZX0pOm51bGw7YnJlYWs7Y2FzZSJMaXN0VmFsdWUiOnZhciBnPSgwLHkuZ2V0TnVsbGFibGVUeXBlKShzKTtzPWcgaW5zdGFuY2VvZiB5LkdyYXBoUUxMaXN0P2cub2ZUeXBlOm51bGw7YnJlYWs7Y2FzZSJPYmplY3RWYWx1ZSI6dmFyIHY9KDAseS5nZXROYW1lZFR5cGUpKHMpO3U9diBpbnN0YW5jZW9mIHkuR3JhcGhRTElucHV0T2JqZWN0VHlwZT92LmdldEZpZWxkcygpOm51bGw7YnJlYWs7Y2FzZSJPYmplY3RGaWVsZCI6dmFyIHg9dC5uYW1lJiZ1P3VbdC5uYW1lXTpudWxsO3M9eCYmeC50eXBlO2JyZWFrO2Nhc2UiTmFtZWRUeXBlIjp0Lm5hbWUmJihsPWUuZ2V0VHlwZSh0Lm5hbWUpKX19KSx7YXJnRGVmOm4sYXJnRGVmczpyLGRpcmVjdGl2ZURlZjppLGVudW1WYWx1ZTpvLGZpZWxkRGVmOmEsaW5wdXRUeXBlOnMsb2JqZWN0RmllbGREZWZzOnUscGFyZW50VHlwZTpjLHR5cGU6bH19ZnVuY3Rpb24gbShlLHQpe2Zvcih2YXIgbj0wO248ZS5sZW5ndGg7bisrKWlmKHQoZVtuXSkpcmV0dXJuIGVbbl07cmV0dXJuIG51bGx9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBnPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspe3ZhciBuPWFyZ3VtZW50c1t0XTtmb3IodmFyIHIgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmKGVbcl09bltyXSl9cmV0dXJuIGV9O3QuZ2V0QXV0b2NvbXBsZXRlU3VnZ2VzdGlvbnM9cjt2YXIgeT1uKDcpLHY9big3MSksYj1uKDkyKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjsoZnVuY3Rpb24oZSl7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPXQubG9jO3JldHVybigwLGwuZGVmYXVsdCkobiwiRXhwZWN0ZWQgQVNUTm9kZSB0byBoYXZlIGEgbG9jYXRpb24uIiksKDAsdS5sb2NUb1JhbmdlKShlLG4pfWZ1bmN0aW9uIGkoZSx0KXt2YXIgbj10LmxvYztyZXR1cm4oMCxsLmRlZmF1bHQpKG4sIkV4cGVjdGVkIEFTVE5vZGUgdG8gaGF2ZSBhIGxvY2F0aW9uLiIpLCgwLHUub2Zmc2V0VG9Qb3NpdGlvbikoZSxuLnN0YXJ0KX1mdW5jdGlvbiBvKHQsbixpKXt2YXIgbyxhLHU7cmV0dXJuIHJlZ2VuZXJhdG9yUnVudGltZS5hc3luYyhmdW5jdGlvbihjKXtmb3IoOzspc3dpdGNoKGMucHJldj1jLm5leHQpe2Nhc2UgMDppZihvPW4ubmFtZS52YWx1ZSxhPWkuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBlLmRlZmluaXRpb24ubmFtZS52YWx1ZT09PW99KSwwIT09YS5sZW5ndGgpe2MubmV4dD01O2JyZWFrfXJldHVybiBlLnN0ZGVyci53cml0ZSgiRGVmaW5pdGlvbiBub3QgZm91bmQgZm9yIEdyYXBoUUwgZnJhZ21lbnQgIitvKSxjLmFicnVwdCgicmV0dXJuIix7cXVlcnlSYW5nZTpbXSxkZWZpbml0aW9uczpbXX0pO2Nhc2UgNTpyZXR1cm4gdT1hLm1hcChmdW5jdGlvbihlKXt2YXIgdD1lLmZpbGVQYXRoLG49ZS5jb250ZW50LHI9ZS5kZWZpbml0aW9uO3JldHVybiBzKHR8fCIiLG4scil9KSxjLmFicnVwdCgicmV0dXJuIix7ZGVmaW5pdGlvbnM6dSxxdWVyeVJhbmdlOnUubWFwKGZ1bmN0aW9uKGUpe3JldHVybiByKHQsbil9KX0pO2Nhc2UgNzpjYXNlImVuZCI6cmV0dXJuIGMuc3RvcCgpfX0sbnVsbCx0aGlzKX1mdW5jdGlvbiBhKGUsdCxuKXtyZXR1cm57ZGVmaW5pdGlvbnM6W3MoZSx0LG4pXSxxdWVyeVJhbmdlOm4ubmFtZT9bcih0LG4ubmFtZSldOltdfX1mdW5jdGlvbiBzKGUsdCxuKXt2YXIgbz1uLm5hbWU7cmV0dXJuKDAsbC5kZWZhdWx0KShvLCJFeHBlY3RlZCBBU1ROb2RlIHRvIGhhdmUgYSBOYW1lLiIpLHtwYXRoOmUscG9zaXRpb246aSh0LG8pLHJhbmdlOnIodCxuKSxuYW1lOm8udmFsdWV8fCIiLGxhbmd1YWdlOnAscHJvamVjdFJvb3Q6ZX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuTEFOR1VBR0U9dm9pZCAwLHQuZ2V0RGVmaW5pdGlvblF1ZXJ5UmVzdWx0Rm9yRnJhZ21lbnRTcHJlYWQ9byx0LmdldERlZmluaXRpb25RdWVyeVJlc3VsdEZvckRlZmluaXRpb25Ob2RlPWE7dmFyIHU9big5NSksYz1uKDI3OCksbD1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19KGMpLHA9dC5MQU5HVUFHRT0iR3JhcGhRTCJ9KS5jYWxsKHQsbig1NikpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDU5OCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImdldEFTVE5vZGVBdFBvc2l0aW9uIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gci5nZXRBU1ROb2RlQXRQb3NpdGlvbn19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwicG9pbnRUb09mZnNldCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIucG9pbnRUb09mZnNldH19KTt2YXIgaT1uKDI3Nyk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlBvc2l0aW9uIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5Qb3NpdGlvbn19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiUmFuZ2UiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLlJhbmdlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJsb2NUb1JhbmdlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5sb2NUb1JhbmdlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJvZmZzZXRUb1Bvc2l0aW9uIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5vZmZzZXRUb1Bvc2l0aW9ufX0pO3ZhciBvPW4oNTk5KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidmFsaWRhdGVXaXRoQ3VzdG9tUnVsZXMiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLnZhbGlkYXRlV2l0aEN1c3RvbVJ1bGVzfX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dmFyIHQ9YXJndW1lbnRzLmxlbmd0aD4xJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0/YXJndW1lbnRzWzFdOm51bGwsbj1hcmd1bWVudHNbMl0scj1hcmd1bWVudHNbM10sbz1udWxsO3RyeXtvPSgwLHAucGFyc2UpKGUpfWNhdGNoKHQpe3ZhciBhPXModC5sb2NhdGlvbnNbMF0sZSk7cmV0dXJuW3tzZXZlcml0eTpoLkVSUk9SLG1lc3NhZ2U6dC5tZXNzYWdlLHNvdXJjZToiR3JhcGhRTDogU3ludGF4IixyYW5nZTphfV19cmV0dXJuIGkobyx0LG4scil9ZnVuY3Rpb24gaShlKXt2YXIgdD1hcmd1bWVudHMubGVuZ3RoPjEmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXT9hcmd1bWVudHNbMV06bnVsbCxuPWFyZ3VtZW50c1syXSxyPWFyZ3VtZW50c1szXTtpZighdClyZXR1cm5bXTt2YXIgaT1vKCgwLGQudmFsaWRhdGVXaXRoQ3VzdG9tUnVsZXMpKHQsZSxuLHIpLGZ1bmN0aW9uKGUpe3JldHVybiBhKGUsaC5FUlJPUiwiVmFsaWRhdGlvbiIpfSkscz1wLmZpbmREZXByZWNhdGVkVXNhZ2VzP28oKDAscC5maW5kRGVwcmVjYXRlZFVzYWdlcykodCxlKSxmdW5jdGlvbihlKXtyZXR1cm4gYShlLGguV0FSTklORywiRGVwcmVjYXRpb24iKX0pOltdO3JldHVybiBpLmNvbmNhdChzKX1mdW5jdGlvbiBvKGUsdCl7cmV0dXJuIEFycmF5LnByb3RvdHlwZS5jb25jYXQuYXBwbHkoW10sZS5tYXAodCkpfWZ1bmN0aW9uIGEoZSx0LG4pe3JldHVybiBlLm5vZGVzP2Uubm9kZXMubWFwKGZ1bmN0aW9uKHIpe3ZhciBpPSJWYXJpYWJsZSIhPT1yLmtpbmQmJnIubmFtZT9yLm5hbWU6ci52YXJpYWJsZT9yLnZhcmlhYmxlOnI7KDAsbC5kZWZhdWx0KShlLmxvY2F0aW9ucywiR3JhcGhRTCB2YWxpZGF0aW9uIGVycm9yIHJlcXVpcmVzIGxvY2F0aW9ucy4iKTt2YXIgbz1lLmxvY2F0aW9uc1swXSxhPXUoaSkscz1vLmNvbHVtbisoYS5lbmQtYS5zdGFydCk7cmV0dXJue3NvdXJjZToiR3JhcGhRTDogIituLG1lc3NhZ2U6ZS5tZXNzYWdlLHNldmVyaXR5OnQscmFuZ2U6bmV3IGQuUmFuZ2UobmV3IGQuUG9zaXRpb24oby5saW5lLTEsby5jb2x1bW4tMSksbmV3IGQuUG9zaXRpb24oby5saW5lLTEscykpfX0pOltdfWZ1bmN0aW9uIHMoZSx0KXt2YXIgbj0oMCxmLm9ubGluZVBhcnNlcikoKSxyPW4uc3RhcnRTdGF0ZSgpLGk9dC5zcGxpdCgiXG4iKTsoMCxsLmRlZmF1bHQpKGkubGVuZ3RoPj1lLmxpbmUsIlF1ZXJ5IHRleHQgbXVzdCBoYXZlIG1vcmUgbGluZXMgdGhhbiB3aGVyZSB0aGUgZXJyb3IgaGFwcGVuZWQiKTtmb3IodmFyIG89bnVsbCxhPTA7YTxlLmxpbmU7YSsrKWZvcihvPW5ldyBmLkNoYXJhY3RlclN0cmVhbShpW2FdKTshby5lb2woKTspe3ZhciBzPW4udG9rZW4obyxyKTtpZigiaW52YWxpZGNoYXIiPT09cylicmVha30oMCxsLmRlZmF1bHQpKG8sIkV4cGVjdGVkIFBhcnNlciBzdHJlYW0gdG8gYmUgYXZhaWxhYmxlLiIpO3ZhciB1PWUubGluZS0xLGM9by5nZXRTdGFydE9mVG9rZW4oKSxwPW8uZ2V0Q3VycmVudFBvc2l0aW9uKCk7cmV0dXJuIG5ldyBkLlJhbmdlKG5ldyBkLlBvc2l0aW9uKHUsYyksbmV3IGQuUG9zaXRpb24odSxwKSl9ZnVuY3Rpb24gdShlKXt2YXIgdD1lLG49dC5sb2M7cmV0dXJuKDAsbC5kZWZhdWx0KShuLCJFeHBlY3RlZCBBU1ROb2RlIHRvIGhhdmUgYSBsb2NhdGlvbi4iKSxufU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlNFVkVSSVRZPXZvaWQgMCx0LmdldERpYWdub3N0aWNzPXIsdC52YWxpZGF0ZVF1ZXJ5PWksdC5nZXRSYW5nZT1zO3ZhciBjPW4oMjc4KSxsPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0oYykscD1uKDcpLGY9big3MSksZD1uKDk1KSxoPXQuU0VWRVJJVFk9e0VSUk9SOjEsV0FSTklORzoyLElORk9STUFUSU9OOjMsSElOVDo0fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9ZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiB0LmdlbmVyYWwuZ2V0KGUpfX07dC5nZXRGaXhlZEVuZHBvaW50PXIoImZpeGVkRW5kcG9pbnQiKSx0LmdldEhpc3RvcnlPcGVuPXIoImhpc3RvcnlPcGVuIiksdC5nZXRDb25maWdTdHJpbmc9cigiY29uZmlnU3RyaW5nIil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big1Myk7ZS5leHBvcnRzPXIuREVGQVVMVD1uZXcgcih7aW5jbHVkZTpbbig3MyldLGV4cGxpY2l0OltuKDc0Myksbig3NDQpLG4oNzQ1KV19KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuLHIsbyxhLHMsdSl7aWYoaSh0KSwhZSl7dmFyIGM7aWYodm9pZCAwPT09dCljPW5ldyBFcnJvcigiTWluaWZpZWQgZXhjZXB0aW9uIG9jY3VycmVkOyB1c2UgdGhlIG5vbi1taW5pZmllZCBkZXYgZW52aXJvbm1lbnQgZm9yIHRoZSBmdWxsIGVycm9yIG1lc3NhZ2UgYW5kIGFkZGl0aW9uYWwgaGVscGZ1bCB3YXJuaW5ncy4iKTtlbHNle3ZhciBsPVtuLHIsbyxhLHMsdV0scD0wO2M9bmV3IEVycm9yKHQucmVwbGFjZSgvJXMvZyxmdW5jdGlvbigpe3JldHVybiBsW3ArK119KSksYy5uYW1lPSJJbnZhcmlhbnQgVmlvbGF0aW9uIn10aHJvdyBjLmZyYW1lc1RvUG9wPTEsY319dmFyIGk9ZnVuY3Rpb24oZSl7fTtlLmV4cG9ydHM9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiBlfX12YXIgaT1mdW5jdGlvbigpe307aS50aGF0UmV0dXJucz1yLGkudGhhdFJldHVybnNGYWxzZT1yKCExKSxpLnRoYXRSZXR1cm5zVHJ1ZT1yKCEwKSxpLnRoYXRSZXR1cm5zTnVsbD1yKG51bGwpLGkudGhhdFJldHVybnNUaGlzPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LGkudGhhdFJldHVybnNBcmd1bWVudD1mdW5jdGlvbihlKXtyZXR1cm4gZX0sZS5leHBvcnRzPWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXsidW5kZWZpbmVkIiE9PXR5cGVvZiBjb25zb2xlJiYiZnVuY3Rpb24iPT09dHlwZW9mIGNvbnNvbGUuZXJyb3ImJmNvbnNvbGUuZXJyb3IoZSk7dHJ5e3Rocm93IG5ldyBFcnJvcihlKX1jYXRjaChlKXt9fXQuYT1yfSxmdW5jdGlvbihlLHQpe2UuZXhwb3J0cz1mdW5jdGlvbihlKXtyZXR1cm4gZS53ZWJwYWNrUG9seWZpbGx8fChlLmRlcHJlY2F0ZT1mdW5jdGlvbigpe30sZS5wYXRocz1bXSxlLmNoaWxkcmVufHwoZS5jaGlsZHJlbj1bXSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsImxvYWRlZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGUubH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwiaWQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBlLml9fSksZS53ZWJwYWNrUG9seWZpbGw9MSksZX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9bigyMSksaT1yLmEuU3ltYm9sO3QuYT1pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDM1NyksaT1uKDE2Nyk7bi5kKHQsInJ1blNhZ2EiLGZ1bmN0aW9uKCl7cmV0dXJuIGkuYX0pO3ZhciBvPW4oNDIpO24uZCh0LCJFTkQiLGZ1bmN0aW9uKCl7cmV0dXJuIG8uYX0pLG4uZCh0LCJldmVudENoYW5uZWwiLGZ1bmN0aW9uKCl7cmV0dXJuIG8uZH0pLG4uZCh0LCJjaGFubmVsIixmdW5jdGlvbigpe3JldHVybiBvLmJ9KTt2YXIgYT1uKDc2KTtuLmQodCwiYnVmZmVycyIsZnVuY3Rpb24oKXtyZXR1cm4gYS5hfSk7dmFyIHM9bigxNjkpO24uZCh0LCJ0YWtlRXZlcnkiLGZ1bmN0aW9uKCl7cmV0dXJuIHMuYX0pLG4uZCh0LCJ0YWtlTGF0ZXN0IixmdW5jdGlvbigpe3JldHVybiBzLmN9KSxuLmQodCwidGhyb3R0bGUiLGZ1bmN0aW9uKCl7cmV0dXJuIHMuZX0pO3ZhciB1PW4oMjIpO24uZCh0LCJkZWxheSIsZnVuY3Rpb24oKXtyZXR1cm4gdS5tfSksbi5kKHQsIkNBTkNFTCIsZnVuY3Rpb24oKXtyZXR1cm4gdS5hfSk7dmFyIGM9bigzNCk7bi5kKHQsImRldGFjaCIsZnVuY3Rpb24oKXtyZXR1cm4gYy5pfSk7dmFyIGw9big1NSkscD1uKDM2MSk7bi5kKHQsImVmZmVjdHMiLGZ1bmN0aW9uKCl7cmV0dXJuIGx9KSxuLmQodCwidXRpbHMiLGZ1bmN0aW9uKCl7cmV0dXJuIHB9KSx0LmRlZmF1bHQ9ci5hfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG8ucS5jaGFubmVsKGUpPyJjaGFubmVsIjpBcnJheS5pc0FycmF5KGUpP1N0cmluZyhlLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gU3RyaW5nKGUpfSkpOlN0cmluZyhlKX1mdW5jdGlvbiBpKGUsdCl7ZnVuY3Rpb24gbih0LG4pe2lmKHU9PT1zKXJldHVybiBhO2lmKG4pdGhyb3cgdT1zLG47aSYmaSh0KTt2YXIgcj1lW3VdKCksbz1yWzBdLGM9clsxXSxsPXJbMl07cmV0dXJuIHU9byxpPWwsdT09PXM/YTpjfXZhciByPWFyZ3VtZW50cy5sZW5ndGg+MiYmdm9pZCAwIT09YXJndW1lbnRzWzJdP2FyZ3VtZW50c1syXToiaXRlcmF0b3IiLGk9dm9pZCAwLHU9dDtyZXR1cm4gT2JqZWN0KG8udCkobixmdW5jdGlvbihlKXtyZXR1cm4gbihudWxsLGUpfSxyLCEwKX1uLmQodCwiYiIsZnVuY3Rpb24oKXtyZXR1cm4gc30pLHQuYz1yLHQuYT1pO3ZhciBvPW4oMjIpLGE9e2RvbmU6ITAsdmFsdWU6dm9pZCAwfSxzPXt9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oMTcwKTt0LmE9ci5hfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIlN0cmluZ1ZhbHVlIj09PWUua2luZH1mdW5jdGlvbiBpKGUpe3JldHVybiJCb29sZWFuVmFsdWUiPT09ZS5raW5kfWZ1bmN0aW9uIG8oZSl7cmV0dXJuIkludFZhbHVlIj09PWUua2luZH1mdW5jdGlvbiBhKGUpe3JldHVybiJGbG9hdFZhbHVlIj09PWUua2luZH1mdW5jdGlvbiBzKGUpe3JldHVybiJWYXJpYWJsZSI9PT1lLmtpbmR9ZnVuY3Rpb24gdShlKXtyZXR1cm4iT2JqZWN0VmFsdWUiPT09ZS5raW5kfWZ1bmN0aW9uIGMoZSl7cmV0dXJuIkxpc3RWYWx1ZSI9PT1lLmtpbmR9ZnVuY3Rpb24gbChlKXtyZXR1cm4iRW51bVZhbHVlIj09PWUua2luZH1mdW5jdGlvbiBwKGUpe3JldHVybiJOdWxsVmFsdWUiPT09ZS5raW5kfWZ1bmN0aW9uIGYoZSx0LG4sZCl7aWYobyhuKXx8YShuKSllW3QudmFsdWVdPU51bWJlcihuLnZhbHVlKTtlbHNlIGlmKGkobil8fHIobikpZVt0LnZhbHVlXT1uLnZhbHVlO2Vsc2UgaWYodShuKSl7dmFyIGg9e307bi5maWVsZHMubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBmKGgsZS5uYW1lLGUudmFsdWUsZCl9KSxlW3QudmFsdWVdPWh9ZWxzZSBpZihzKG4pKXt2YXIgbT0oZHx8e30pW24ubmFtZS52YWx1ZV07ZVt0LnZhbHVlXT1tfWVsc2UgaWYoYyhuKSllW3QudmFsdWVdPW4udmFsdWVzLm1hcChmdW5jdGlvbihlKXt2YXIgbj17fTtyZXR1cm4gZihuLHQsZSxkKSxuW3QudmFsdWVdfSk7ZWxzZSBpZihsKG4pKWVbdC52YWx1ZV09bi52YWx1ZTtlbHNle2lmKCFwKG4pKXRocm93IG5ldyBFcnJvcignVGhlIGlubGluZSBhcmd1bWVudCAiJyt0LnZhbHVlKyciIG9mIGtpbmQgIicrbi5raW5kKyciIGlzIG5vdCBzdXBwb3J0ZWQuXG4gICAgICAgICAgICAgICAgICAgIFVzZSB2YXJpYWJsZXMgaW5zdGVhZCBvZiBpbmxpbmUgYXJndW1lbnRzIHRvIG92ZXJjb21lIHRoaXMgbGltaXRhdGlvbi4nKTtlW3QudmFsdWVdPW51bGx9fWZ1bmN0aW9uIGQoZSx0KXtpZihlLmFyZ3VtZW50cyYmZS5hcmd1bWVudHMubGVuZ3RoKXt2YXIgbj17fTtyZXR1cm4gZS5hcmd1bWVudHMuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgcj1lLm5hbWUsaT1lLnZhbHVlO3JldHVybiBmKG4scixpLHQpfSksbn1yZXR1cm4gbnVsbH10LmI9Zix0LmE9ZDt0aGlzJiZ0aGlzLl9fYXNzaWdufHxPYmplY3QuYXNzaWdufSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiOyhmdW5jdGlvbihlKXtmdW5jdGlvbiBuKCl7cmV0dXJuInVuZGVmaW5lZCIhPT10eXBlb2YgZT8icHJvZHVjdGlvbiI6ImRldmVsb3BtZW50In1mdW5jdGlvbiByKGUpe3JldHVybiBuKCk9PT1lfWZ1bmN0aW9uIGkoKXtyZXR1cm4hMD09PXIoInByb2R1Y3Rpb24iKX1mdW5jdGlvbiBvKCl7cmV0dXJuITA9PT1yKCJkZXZlbG9wbWVudCIpfWZ1bmN0aW9uIGEoKXtyZXR1cm4hMD09PXIoInRlc3QiKX10LmI9aSx0LmE9byx0LmM9YX0pLmNhbGwodCxuKDU2KSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2Zvcih2YXIgbj0vXHJcbnxbXG5ccl0vZyxyPTEsaT10KzEsbz12b2lkIDA7KG89bi5leGVjKGUuYm9keSkpJiZvLmluZGV4PHQ7KXIrPTEsaT10KzEtKG8uaW5kZXgrb1swXS5sZW5ndGgpO3JldHVybntsaW5lOnIsY29sdW1uOml9fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmdldExvY2F0aW9uPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPW5ldyBhKGIsMCwwLDAsMCxudWxsKTtyZXR1cm57c291cmNlOmUsb3B0aW9uczp0LGxhc3RUb2tlbjpuLHRva2VuOm4sbGluZToxLGxpbmVTdGFydDowLGFkdmFuY2U6aX19ZnVuY3Rpb24gaSgpe3ZhciBlPXRoaXMubGFzdFRva2VuPXRoaXMudG9rZW47aWYoZS5raW5kIT09eCl7ZG97ZT1lLm5leHQ9dSh0aGlzLGUpfXdoaWxlKGUua2luZD09PVIpO3RoaXMudG9rZW49ZX1yZXR1cm4gZX1mdW5jdGlvbiBvKGUpe3ZhciB0PWUudmFsdWU7cmV0dXJuIHQ/ZS5raW5kKycgIicrdCsnIic6ZS5raW5kfWZ1bmN0aW9uIGEoZSx0LG4scixpLG8sYSl7dGhpcy5raW5kPWUsdGhpcy5zdGFydD10LHRoaXMuZW5kPW4sdGhpcy5saW5lPXIsdGhpcy5jb2x1bW49aSx0aGlzLnZhbHVlPWEsdGhpcy5wcmV2PW8sdGhpcy5uZXh0PW51bGx9ZnVuY3Rpb24gcyhlKXtyZXR1cm4gaXNOYU4oZSk/eDplPDEyNz9KU09OLnN0cmluZ2lmeShTdHJpbmcuZnJvbUNoYXJDb2RlKGUpKTonIlxcdScrKCIwMCIrZS50b1N0cmluZygxNikudG9VcHBlckNhc2UoKSkuc2xpY2UoLTQpKyciJ31mdW5jdGlvbiB1KGUsdCl7dmFyIG49ZS5zb3VyY2Uscj1uLmJvZHksaT1yLmxlbmd0aCxvPWwocix0LmVuZCxlKSx1PWUubGluZSxkPTErby1lLmxpbmVTdGFydDtpZihvPj1pKXJldHVybiBuZXcgYSh4LGksaSx1LGQsdCk7dmFyIG09Qi5jYWxsKHIsbyk7aWYobTwzMiYmOSE9PW0mJjEwIT09bSYmMTMhPT1tKXRocm93KDAsdi5zeW50YXhFcnJvcikobixvLCJDYW5ub3QgY29udGFpbiB0aGUgaW52YWxpZCBjaGFyYWN0ZXIgIitzKG0pKyIuIik7c3dpdGNoKG0pe2Nhc2UgMzM6cmV0dXJuIG5ldyBhKEMsbyxvKzEsdSxkLHQpO2Nhc2UgMzU6cmV0dXJuIHAobixvLHUsZCx0KTtjYXNlIDM2OnJldHVybiBuZXcgYShFLG8sbysxLHUsZCx0KTtjYXNlIDQwOnJldHVybiBuZXcgYShELG8sbysxLHUsZCx0KTtjYXNlIDQxOnJldHVybiBuZXcgYSh3LG8sbysxLHUsZCx0KTtjYXNlIDQ2OmlmKDQ2PT09Qi5jYWxsKHIsbysxKSYmNDY9PT1CLmNhbGwocixvKzIpKXJldHVybiBuZXcgYShTLG8sbyszLHUsZCx0KTticmVhaztjYXNlIDU4OnJldHVybiBuZXcgYShrLG8sbysxLHUsZCx0KTtjYXNlIDYxOnJldHVybiBuZXcgYShBLG8sbysxLHUsZCx0KTtjYXNlIDY0OnJldHVybiBuZXcgYShfLG8sbysxLHUsZCx0KTtjYXNlIDkxOnJldHVybiBuZXcgYShULG8sbysxLHUsZCx0KTtjYXNlIDkzOnJldHVybiBuZXcgYShPLG8sbysxLHUsZCx0KTtjYXNlIDEyMzpyZXR1cm4gbmV3IGEoRixvLG8rMSx1LGQsdCk7Y2FzZSAxMjQ6cmV0dXJuIG5ldyBhKE4sbyxvKzEsdSxkLHQpO2Nhc2UgMTI1OnJldHVybiBuZXcgYShJLG8sbysxLHUsZCx0KTtjYXNlIDY1OmNhc2UgNjY6Y2FzZSA2NzpjYXNlIDY4OmNhc2UgNjk6Y2FzZSA3MDpjYXNlIDcxOmNhc2UgNzI6Y2FzZSA3MzpjYXNlIDc0OmNhc2UgNzU6Y2FzZSA3NjpjYXNlIDc3OmNhc2UgNzg6Y2FzZSA3OTpjYXNlIDgwOmNhc2UgODE6Y2FzZSA4MjpjYXNlIDgzOmNhc2UgODQ6Y2FzZSA4NTpjYXNlIDg2OmNhc2UgODc6Y2FzZSA4ODpjYXNlIDg5OmNhc2UgOTA6Y2FzZSA5NTpjYXNlIDk3OmNhc2UgOTg6Y2FzZSA5OTpjYXNlIDEwMDpjYXNlIDEwMTpjYXNlIDEwMjpjYXNlIDEwMzpjYXNlIDEwNDpjYXNlIDEwNTpjYXNlIDEwNjpjYXNlIDEwNzpjYXNlIDEwODpjYXNlIDEwOTpjYXNlIDExMDpjYXNlIDExMTpjYXNlIDExMjpjYXNlIDExMzpjYXNlIDExNDpjYXNlIDExNTpjYXNlIDExNjpjYXNlIDExNzpjYXNlIDExODpjYXNlIDExOTpjYXNlIDEyMDpjYXNlIDEyMTpjYXNlIDEyMjpyZXR1cm4geShuLG8sdSxkLHQpO2Nhc2UgNDU6Y2FzZSA0ODpjYXNlIDQ5OmNhc2UgNTA6Y2FzZSA1MTpjYXNlIDUyOmNhc2UgNTM6Y2FzZSA1NDpjYXNlIDU1OmNhc2UgNTY6Y2FzZSA1NzpyZXR1cm4gZihuLG8sbSx1LGQsdCk7Y2FzZSAzNDpyZXR1cm4gaChuLG8sdSxkLHQpfXRocm93KDAsdi5zeW50YXhFcnJvcikobixvLGMobSkpfWZ1bmN0aW9uIGMoZSl7cmV0dXJuIDM5PT09ZT8iVW5leHBlY3RlZCBzaW5nbGUgcXVvdGUgY2hhcmFjdGVyICgnKSwgZGlkIHlvdSBtZWFuIHRvIHVzZSBhIGRvdWJsZSBxdW90ZSAoXCIpPyI6IkNhbm5vdCBwYXJzZSB0aGUgdW5leHBlY3RlZCBjaGFyYWN0ZXIgIitzKGUpKyIuIn1mdW5jdGlvbiBsKGUsdCxuKXtmb3IodmFyIHI9ZS5sZW5ndGgsaT10O2k8cjspe3ZhciBvPUIuY2FsbChlLGkpO2lmKDk9PT1vfHwzMj09PW98fDQ0PT09b3x8NjUyNzk9PT1vKSsraTtlbHNlIGlmKDEwPT09bykrK2ksKytuLmxpbmUsbi5saW5lU3RhcnQ9aTtlbHNle2lmKDEzIT09bylicmVhazsxMD09PUIuY2FsbChlLGkrMSk/aSs9MjorK2ksKytuLmxpbmUsbi5saW5lU3RhcnQ9aX19cmV0dXJuIGl9ZnVuY3Rpb24gcChlLHQsbixyLGkpe3ZhciBvPWUuYm9keSxzPXZvaWQgMCx1PXQ7ZG97cz1CLmNhbGwobywrK3UpfXdoaWxlKG51bGwhPT1zJiYocz4zMXx8OT09PXMpKTtyZXR1cm4gbmV3IGEoUix0LHUsbixyLGksJC5jYWxsKG8sdCsxLHUpKX1mdW5jdGlvbiBmKGUsdCxuLHIsaSxvKXt2YXIgdT1lLmJvZHksYz1uLGw9dCxwPSExO2lmKDQ1PT09YyYmKGM9Qi5jYWxsKHUsKytsKSksNDg9PT1jKXtpZigoYz1CLmNhbGwodSwrK2wpKT49NDgmJmM8PTU3KXRocm93KDAsdi5zeW50YXhFcnJvcikoZSxsLCJJbnZhbGlkIG51bWJlciwgdW5leHBlY3RlZCBkaWdpdCBhZnRlciAwOiAiK3MoYykrIi4iKX1lbHNlIGw9ZChlLGwsYyksYz1CLmNhbGwodSxsKTtyZXR1cm4gNDY9PT1jJiYocD0hMCxjPUIuY2FsbCh1LCsrbCksbD1kKGUsbCxjKSxjPUIuY2FsbCh1LGwpKSw2OSE9PWMmJjEwMSE9PWN8fChwPSEwLGM9Qi5jYWxsKHUsKytsKSw0MyE9PWMmJjQ1IT09Y3x8KGM9Qi5jYWxsKHUsKytsKSksbD1kKGUsbCxjKSksbmV3IGEocD9NOlAsdCxsLHIsaSxvLCQuY2FsbCh1LHQsbCkpfWZ1bmN0aW9uIGQoZSx0LG4pe3ZhciByPWUuYm9keSxpPXQsbz1uO2lmKG8+PTQ4JiZvPD01Nyl7ZG97bz1CLmNhbGwociwrK2kpfXdoaWxlKG8+PTQ4JiZvPD01Nyk7cmV0dXJuIGl9dGhyb3coMCx2LnN5bnRheEVycm9yKShlLGksIkludmFsaWQgbnVtYmVyLCBleHBlY3RlZCBkaWdpdCBidXQgZ290OiAiK3MobykrIi4iKX1mdW5jdGlvbiBoKGUsdCxuLHIsaSl7Zm9yKHZhciBvPWUuYm9keSx1PXQrMSxjPXUsbD0wLHA9IiI7dTxvLmxlbmd0aCYmbnVsbCE9PShsPUIuY2FsbChvLHUpKSYmMTAhPT1sJiYxMyE9PWwmJjM0IT09bDspe2lmKGw8MzImJjkhPT1sKXRocm93KDAsdi5zeW50YXhFcnJvcikoZSx1LCJJbnZhbGlkIGNoYXJhY3RlciB3aXRoaW4gU3RyaW5nOiAiK3MobCkrIi4iKTtpZigrK3UsOTI9PT1sKXtzd2l0Y2gocCs9JC5jYWxsKG8sYyx1LTEpLGw9Qi5jYWxsKG8sdSkpe2Nhc2UgMzQ6cCs9JyInO2JyZWFrO2Nhc2UgNDc6cCs9Ii8iO2JyZWFrO2Nhc2UgOTI6cCs9IlxcIjticmVhaztjYXNlIDk4OnArPSJcYiI7YnJlYWs7Y2FzZSAxMDI6cCs9IlxmIjticmVhaztjYXNlIDExMDpwKz0iXG4iO2JyZWFrO2Nhc2UgMTE0OnArPSJcciI7YnJlYWs7Y2FzZSAxMTY6cCs9Ilx0IjticmVhaztjYXNlIDExNzp2YXIgZj1tKEIuY2FsbChvLHUrMSksQi5jYWxsKG8sdSsyKSxCLmNhbGwobyx1KzMpLEIuY2FsbChvLHUrNCkpO2lmKGY8MCl0aHJvdygwLHYuc3ludGF4RXJyb3IpKGUsdSwiSW52YWxpZCBjaGFyYWN0ZXIgZXNjYXBlIHNlcXVlbmNlOiBcXHUiK28uc2xpY2UodSsxLHUrNSkrIi4iKTtwKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGYpLHUrPTQ7YnJlYWs7ZGVmYXVsdDp0aHJvdygwLHYuc3ludGF4RXJyb3IpKGUsdSwiSW52YWxpZCBjaGFyYWN0ZXIgZXNjYXBlIHNlcXVlbmNlOiBcXCIrU3RyaW5nLmZyb21DaGFyQ29kZShsKSsiLiIpfSsrdSxjPXV9fWlmKDM0IT09bCl0aHJvdygwLHYuc3ludGF4RXJyb3IpKGUsdSwiVW50ZXJtaW5hdGVkIHN0cmluZy4iKTtyZXR1cm4gcCs9JC5jYWxsKG8sYyx1KSxuZXcgYShqLHQsdSsxLG4scixpLHApfWZ1bmN0aW9uIG0oZSx0LG4scil7cmV0dXJuIGcoZSk8PDEyfGcodCk8PDh8ZyhuKTw8NHxnKHIpfWZ1bmN0aW9uIGcoZSl7cmV0dXJuIGU+PTQ4JiZlPD01Nz9lLTQ4OmU+PTY1JiZlPD03MD9lLTU1OmU+PTk3JiZlPD0xMDI/ZS04NzotMX1mdW5jdGlvbiB5KGUsdCxuLHIsaSl7Zm9yKHZhciBvPWUuYm9keSxzPW8ubGVuZ3RoLHU9dCsxLGM9MDt1IT09cyYmbnVsbCE9PShjPUIuY2FsbChvLHUpKSYmKDk1PT09Y3x8Yz49NDgmJmM8PTU3fHxjPj02NSYmYzw9OTB8fGM+PTk3JiZjPD0xMjIpOykrK3U7cmV0dXJuIG5ldyBhKEwsdCx1LG4scixpLCQuY2FsbChvLHQsdSkpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlRva2VuS2luZD12b2lkIDAsdC5jcmVhdGVMZXhlcj1yLHQuZ2V0VG9rZW5EZXNjPW87dmFyIHY9bigzKSxiPSI8U09GPiIseD0iPEVPRj4iLEM9IiEiLEU9IiQiLEQ9IigiLHc9IikiLFM9Ii4uLiIsaz0iOiIsQT0iPSIsXz0iQCIsVD0iWyIsTz0iXSIsRj0ieyIsTj0ifCIsST0ifSIsTD0iTmFtZSIsUD0iSW50IixNPSJGbG9hdCIsaj0iU3RyaW5nIixSPSJDb21tZW50IixCPSh0LlRva2VuS2luZD17U09GOmIsRU9GOngsQkFORzpDLERPTExBUjpFLFBBUkVOX0w6RCxQQVJFTl9SOncsU1BSRUFEOlMsQ09MT046ayxFUVVBTFM6QSxBVDpfLEJSQUNLRVRfTDpULEJSQUNLRVRfUjpPLEJSQUNFX0w6RixQSVBFOk4sQlJBQ0VfUjpJLE5BTUU6TCxJTlQ6UCxGTE9BVDpNLFNUUklORzpqLENPTU1FTlQ6Un0sU3RyaW5nLnByb3RvdHlwZS5jaGFyQ29kZUF0KSwkPVN0cmluZy5wcm90b3R5cGUuc2xpY2U7YS5wcm90b3R5cGUudG9KU09OPWEucHJvdG90eXBlLmluc3BlY3Q9ZnVuY3Rpb24oKXtyZXR1cm57a2luZDp0aGlzLmtpbmQsdmFsdWU6dGhpcy52YWx1ZSxsaW5lOnRoaXMubGluZSxjb2x1bW46dGhpcy5jb2x1bW59fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjsoZnVuY3Rpb24oZSl7ZnVuY3Rpb24gbihlLHQpe2lmKCFlfHwic3RyaW5nIiE9PXR5cGVvZiBlKXRocm93IG5ldyBFcnJvcigiTXVzdCBiZSBuYW1lZC4gVW5leHBlY3RlZCBuYW1lOiAiK2UrIi4iKTtpZighdCYmIXMmJiFhJiYiX18iPT09ZS5zbGljZSgwLDIpJiYocz0hMCxjb25zb2xlJiZjb25zb2xlLndhcm4pKXt2YXIgbj1uZXcgRXJyb3IoJ05hbWUgIicrZSsnIiBtdXN0IG5vdCBiZWdpbiB3aXRoICJfXyIsIHdoaWNoIGlzIHJlc2VydmVkIGJ5IEdyYXBoUUwgaW50cm9zcGVjdGlvbi4gSW4gYSBmdXR1cmUgcmVsZWFzZSBvZiBncmFwaHFsIHRoaXMgd2lsbCBiZWNvbWUgYSBoYXJkIGVycm9yLicpO2NvbnNvbGUud2FybihyKG4pKX1pZighaS50ZXN0KGUpKXRocm93IG5ldyBFcnJvcignTmFtZXMgbXVzdCBtYXRjaCAvXltfYS16QS1aXVtfYS16QS1aMC05XSokLyBidXQgIicrZSsnIiBkb2VzIG5vdC4nKX1mdW5jdGlvbiByKGUpe3ZhciB0PSIiLG49U3RyaW5nKGUpLnJlcGxhY2UobywiIikscj1lLnN0YWNrO3JldHVybiByJiYodD1yLnJlcGxhY2UobywiIikpLC0xPT09dC5pbmRleE9mKG4pJiYodD1uKyJcbiIrdCksdC50cmltKCl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuYXNzZXJ0VmFsaWROYW1lPW4sdC5mb3JtYXRXYXJuaW5nPXI7dmFyIGk9L15bX2EtekEtWl1bX2EtekEtWjAtOV0qJC8sbz0vXkVycm9yOiAvLGE9Qm9vbGVhbihlJiZPYmplY3Qoe05PREVfRU5WOiJwcm9kdWN0aW9uIixQVUJMSUNfVVJMOiIifSkmJk9iamVjdCh7Tk9ERV9FTlY6InByb2R1Y3Rpb24iLFBVQkxJQ19VUkw6IiJ9KS5HUkFQSFFMX05PX05BTUVfV0FSTklORykscz0hMX0pLmNhbGwodCxuKDU2KSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gaShlLHQpe3ZhciBuPWU7aWYodCBpbnN0YW5jZW9mIG0uR3JhcGhRTE5vbk51bGwpe3ZhciByPWkobix0Lm9mVHlwZSk7cmV0dXJuIHImJnIua2luZD09PWguTlVMTD9udWxsOnJ9aWYobnVsbD09PW4pcmV0dXJue2tpbmQ6aC5OVUxMfTtpZigoMCxmLmRlZmF1bHQpKG4pKXJldHVybiBudWxsO2lmKHQgaW5zdGFuY2VvZiBtLkdyYXBoUUxMaXN0KXt2YXIgcz10Lm9mVHlwZTtpZigoMCxhLmlzQ29sbGVjdGlvbikobikpe3ZhciBjPVtdO3JldHVybigwLGEuZm9yRWFjaCkobixmdW5jdGlvbihlKXt2YXIgdD1pKGUscyk7dCYmYy5wdXNoKHQpfSkse2tpbmQ6aC5MSVNULHZhbHVlczpjfX1yZXR1cm4gaShuLHMpfWlmKHQgaW5zdGFuY2VvZiBtLkdyYXBoUUxJbnB1dE9iamVjdFR5cGUpe2lmKG51bGw9PT1ufHwib2JqZWN0IiE9PSgidW5kZWZpbmVkIj09PXR5cGVvZiBuPyJ1bmRlZmluZWQiOm8obikpKXJldHVybiBudWxsO3ZhciBwPXQuZ2V0RmllbGRzKCksZD1bXTtyZXR1cm4gT2JqZWN0LmtleXMocCkuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1wW2VdLnR5cGUscj1pKG5bZV0sdCk7ciYmZC5wdXNoKHtraW5kOmguT0JKRUNUX0ZJRUxELG5hbWU6e2tpbmQ6aC5OQU1FLHZhbHVlOmV9LHZhbHVlOnJ9KX0pLHtraW5kOmguT0JKRUNULGZpZWxkczpkfX10IGluc3RhbmNlb2YgbS5HcmFwaFFMU2NhbGFyVHlwZXx8dCBpbnN0YW5jZW9mIG0uR3JhcGhRTEVudW1UeXBlfHwoMCx1LmRlZmF1bHQpKDAsIk11c3QgcHJvdmlkZSBJbnB1dCBUeXBlLCBjYW5ub3QgdXNlOiAiK1N0cmluZyh0KSk7dmFyIHk9dC5zZXJpYWxpemUobik7aWYoKDAsbC5kZWZhdWx0KSh5KSlyZXR1cm4gbnVsbDtpZigiYm9vbGVhbiI9PT10eXBlb2YgeSlyZXR1cm57a2luZDpoLkJPT0xFQU4sdmFsdWU6eX07aWYoIm51bWJlciI9PT10eXBlb2YgeSl7dmFyIHY9U3RyaW5nKHkpO3JldHVybi9eWzAtOV0rJC8udGVzdCh2KT97a2luZDpoLklOVCx2YWx1ZTp2fTp7a2luZDpoLkZMT0FULHZhbHVlOnZ9fWlmKCJzdHJpbmciPT09dHlwZW9mIHkpcmV0dXJuIHQgaW5zdGFuY2VvZiBtLkdyYXBoUUxFbnVtVHlwZT97a2luZDpoLkVOVU0sdmFsdWU6eX06dD09PWcuR3JhcGhRTElEJiYvXlswLTldKyQvLnRlc3QoeSk/e2tpbmQ6aC5JTlQsdmFsdWU6eX06e2tpbmQ6aC5TVFJJTkcsdmFsdWU6SlNPTi5zdHJpbmdpZnkoeSkuc2xpY2UoMSwtMSl9O3Rocm93IG5ldyBUeXBlRXJyb3IoIkNhbm5vdCBjb252ZXJ0IHZhbHVlIHRvIEFTVDogIitTdHJpbmcoeSkpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz0iZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmInN5bWJvbCI9PT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiZlLmNvbnN0cnVjdG9yPT09U3ltYm9sJiZlIT09U3ltYm9sLnByb3RvdHlwZT8ic3ltYm9sIjp0eXBlb2YgZX07dC5hc3RGcm9tVmFsdWU9aTt2YXIgYT1uKDQ0KSxzPW4oMTMpLHU9cihzKSxjPW4oMzUpLGw9cihjKSxwPW4oNTgpLGY9cihwKSxkPW4oMTApLGg9ZnVuY3Rpb24oZSl7aWYoZSYmZS5fX2VzTW9kdWxlKXJldHVybiBlO3ZhciB0PXt9O2lmKG51bGwhPWUpZm9yKHZhciBuIGluIGUpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUsbikmJih0W25dPWVbbl0pO3JldHVybiB0LmRlZmF1bHQ9ZSx0fShkKSxtPW4oNiksZz1uKDMyKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9ZnVuY3Rpb24gaShlLHQsbil7dmFyIHI9bi5uYW1lLnZhbHVlO3JldHVybiByPT09dS5TY2hlbWFNZXRhRmllbGREZWYubmFtZSYmZS5nZXRRdWVyeVR5cGUoKT09PXQ/dS5TY2hlbWFNZXRhRmllbGREZWY6cj09PXUuVHlwZU1ldGFGaWVsZERlZi5uYW1lJiZlLmdldFF1ZXJ5VHlwZSgpPT09dD91LlR5cGVNZXRhRmllbGREZWY6cj09PXUuVHlwZU5hbWVNZXRhRmllbGREZWYubmFtZSYmKDAscy5pc0NvbXBvc2l0ZVR5cGUpKHQpP3UuVHlwZU5hbWVNZXRhRmllbGREZWY6dCBpbnN0YW5jZW9mIHMuR3JhcGhRTE9iamVjdFR5cGV8fHQgaW5zdGFuY2VvZiBzLkdyYXBoUUxJbnRlcmZhY2VUeXBlP3QuZ2V0RmllbGRzKClbcl06dm9pZCAwfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlR5cGVJbmZvPXZvaWQgMDt2YXIgbz1uKDEwKSxhPWZ1bmN0aW9uKGUpe2lmKGUmJmUuX19lc01vZHVsZSlyZXR1cm4gZTt2YXIgdD17fTtpZihudWxsIT1lKWZvcih2YXIgbiBpbiBlKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLG4pJiYodFtuXT1lW25dKTtyZXR1cm4gdC5kZWZhdWx0PWUsdH0obykscz1uKDYpLHU9bigyOCksYz1uKDI5KSxsPW4oNDUpLHA9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShsKTt0LlR5cGVJbmZvPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0LG4pe3IodGhpcyxlKSx0aGlzLl9zY2hlbWE9dCx0aGlzLl90eXBlU3RhY2s9W10sdGhpcy5fcGFyZW50VHlwZVN0YWNrPVtdLHRoaXMuX2lucHV0VHlwZVN0YWNrPVtdLHRoaXMuX2ZpZWxkRGVmU3RhY2s9W10sdGhpcy5fZGlyZWN0aXZlPW51bGwsdGhpcy5fYXJndW1lbnQ9bnVsbCx0aGlzLl9lbnVtVmFsdWU9bnVsbCx0aGlzLl9nZXRGaWVsZERlZj1ufHxpfXJldHVybiBlLnByb3RvdHlwZS5nZXRUeXBlPWZ1bmN0aW9uKCl7aWYodGhpcy5fdHlwZVN0YWNrLmxlbmd0aD4wKXJldHVybiB0aGlzLl90eXBlU3RhY2tbdGhpcy5fdHlwZVN0YWNrLmxlbmd0aC0xXX0sZS5wcm90b3R5cGUuZ2V0UGFyZW50VHlwZT1mdW5jdGlvbigpe2lmKHRoaXMuX3BhcmVudFR5cGVTdGFjay5sZW5ndGg+MClyZXR1cm4gdGhpcy5fcGFyZW50VHlwZVN0YWNrW3RoaXMuX3BhcmVudFR5cGVTdGFjay5sZW5ndGgtMV19LGUucHJvdG90eXBlLmdldElucHV0VHlwZT1mdW5jdGlvbigpe2lmKHRoaXMuX2lucHV0VHlwZVN0YWNrLmxlbmd0aD4wKXJldHVybiB0aGlzLl9pbnB1dFR5cGVTdGFja1t0aGlzLl9pbnB1dFR5cGVTdGFjay5sZW5ndGgtMV19LGUucHJvdG90eXBlLmdldEZpZWxkRGVmPWZ1bmN0aW9uKCl7aWYodGhpcy5fZmllbGREZWZTdGFjay5sZW5ndGg+MClyZXR1cm4gdGhpcy5fZmllbGREZWZTdGFja1t0aGlzLl9maWVsZERlZlN0YWNrLmxlbmd0aC0xXX0sZS5wcm90b3R5cGUuZ2V0RGlyZWN0aXZlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX2RpcmVjdGl2ZX0sZS5wcm90b3R5cGUuZ2V0QXJndW1lbnQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fYXJndW1lbnR9LGUucHJvdG90eXBlLmdldEVudW1WYWx1ZT1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9lbnVtVmFsdWV9LGUucHJvdG90eXBlLmVudGVyPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuX3NjaGVtYTtzd2l0Y2goZS5raW5kKXtjYXNlIGEuU0VMRUNUSU9OX1NFVDp2YXIgbj0oMCxzLmdldE5hbWVkVHlwZSkodGhpcy5nZXRUeXBlKCkpO3RoaXMuX3BhcmVudFR5cGVTdGFjay5wdXNoKCgwLHMuaXNDb21wb3NpdGVUeXBlKShuKT9uOnZvaWQgMCk7YnJlYWs7Y2FzZSBhLkZJRUxEOnZhciByPXRoaXMuZ2V0UGFyZW50VHlwZSgpLGk9dm9pZCAwO3ImJihpPXRoaXMuX2dldEZpZWxkRGVmKHQscixlKSksdGhpcy5fZmllbGREZWZTdGFjay5wdXNoKGkpLHRoaXMuX3R5cGVTdGFjay5wdXNoKGkmJmkudHlwZSk7YnJlYWs7Y2FzZSBhLkRJUkVDVElWRTp0aGlzLl9kaXJlY3RpdmU9dC5nZXREaXJlY3RpdmUoZS5uYW1lLnZhbHVlKTticmVhaztjYXNlIGEuT1BFUkFUSU9OX0RFRklOSVRJT046dmFyIG89dm9pZCAwOyJxdWVyeSI9PT1lLm9wZXJhdGlvbj9vPXQuZ2V0UXVlcnlUeXBlKCk6Im11dGF0aW9uIj09PWUub3BlcmF0aW9uP289dC5nZXRNdXRhdGlvblR5cGUoKToic3Vic2NyaXB0aW9uIj09PWUub3BlcmF0aW9uJiYobz10LmdldFN1YnNjcmlwdGlvblR5cGUoKSksdGhpcy5fdHlwZVN0YWNrLnB1c2gobyk7YnJlYWs7Y2FzZSBhLklOTElORV9GUkFHTUVOVDpjYXNlIGEuRlJBR01FTlRfREVGSU5JVElPTjp2YXIgdT1lLnR5cGVDb25kaXRpb24sbD11PygwLGMudHlwZUZyb21BU1QpKHQsdSk6dGhpcy5nZXRUeXBlKCk7dGhpcy5fdHlwZVN0YWNrLnB1c2goKDAscy5pc091dHB1dFR5cGUpKGwpP2w6dm9pZCAwKTticmVhaztjYXNlIGEuVkFSSUFCTEVfREVGSU5JVElPTjp2YXIgZj0oMCxjLnR5cGVGcm9tQVNUKSh0LGUudHlwZSk7dGhpcy5faW5wdXRUeXBlU3RhY2sucHVzaCgoMCxzLmlzSW5wdXRUeXBlKShmKT9mOnZvaWQgMCk7YnJlYWs7Y2FzZSBhLkFSR1VNRU5UOnZhciBkPXZvaWQgMCxoPXZvaWQgMCxtPXRoaXMuZ2V0RGlyZWN0aXZlKCl8fHRoaXMuZ2V0RmllbGREZWYoKTttJiYoZD0oMCxwLmRlZmF1bHQpKG0uYXJncyxmdW5jdGlvbih0KXtyZXR1cm4gdC5uYW1lPT09ZS5uYW1lLnZhbHVlfSkpJiYoaD1kLnR5cGUpLHRoaXMuX2FyZ3VtZW50PWQsdGhpcy5faW5wdXRUeXBlU3RhY2sucHVzaChoKTticmVhaztjYXNlIGEuTElTVDp2YXIgZz0oMCxzLmdldE51bGxhYmxlVHlwZSkodGhpcy5nZXRJbnB1dFR5cGUoKSk7dGhpcy5faW5wdXRUeXBlU3RhY2sucHVzaChnIGluc3RhbmNlb2Ygcy5HcmFwaFFMTGlzdD9nLm9mVHlwZTp2b2lkIDApO2JyZWFrO2Nhc2UgYS5PQkpFQ1RfRklFTEQ6dmFyIHk9KDAscy5nZXROYW1lZFR5cGUpKHRoaXMuZ2V0SW5wdXRUeXBlKCkpLHY9dm9pZCAwO2lmKHkgaW5zdGFuY2VvZiBzLkdyYXBoUUxJbnB1dE9iamVjdFR5cGUpe3ZhciBiPXkuZ2V0RmllbGRzKClbZS5uYW1lLnZhbHVlXTt2PWI/Yi50eXBlOnZvaWQgMH10aGlzLl9pbnB1dFR5cGVTdGFjay5wdXNoKHYpO2JyZWFrO2Nhc2UgYS5FTlVNOnZhciB4PSgwLHMuZ2V0TmFtZWRUeXBlKSh0aGlzLmdldElucHV0VHlwZSgpKSxDPXZvaWQgMDt4IGluc3RhbmNlb2Ygcy5HcmFwaFFMRW51bVR5cGUmJihDPXguZ2V0VmFsdWUoZS52YWx1ZSkpLHRoaXMuX2VudW1WYWx1ZT1DfX0sZS5wcm90b3R5cGUubGVhdmU9ZnVuY3Rpb24oZSl7c3dpdGNoKGUua2luZCl7Y2FzZSBhLlNFTEVDVElPTl9TRVQ6dGhpcy5fcGFyZW50VHlwZVN0YWNrLnBvcCgpO2JyZWFrO2Nhc2UgYS5GSUVMRDp0aGlzLl9maWVsZERlZlN0YWNrLnBvcCgpLHRoaXMuX3R5cGVTdGFjay5wb3AoKTticmVhaztjYXNlIGEuRElSRUNUSVZFOnRoaXMuX2RpcmVjdGl2ZT1udWxsO2JyZWFrO2Nhc2UgYS5PUEVSQVRJT05fREVGSU5JVElPTjpjYXNlIGEuSU5MSU5FX0ZSQUdNRU5UOmNhc2UgYS5GUkFHTUVOVF9ERUZJTklUSU9OOnRoaXMuX3R5cGVTdGFjay5wb3AoKTticmVhaztjYXNlIGEuVkFSSUFCTEVfREVGSU5JVElPTjp0aGlzLl9pbnB1dFR5cGVTdGFjay5wb3AoKTticmVhaztjYXNlIGEuQVJHVU1FTlQ6dGhpcy5fYXJndW1lbnQ9bnVsbCx0aGlzLl9pbnB1dFR5cGVTdGFjay5wb3AoKTticmVhaztjYXNlIGEuTElTVDpjYXNlIGEuT0JKRUNUX0ZJRUxEOnRoaXMuX2lucHV0VHlwZVN0YWNrLnBvcCgpO2JyZWFrO2Nhc2UgYS5FTlVNOnRoaXMuX2VudW1WYWx1ZT1udWxsfX0sZX0oKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuPU9iamVjdC5jcmVhdGUobnVsbCkscj10Lmxlbmd0aCxvPWUubGVuZ3RoLzIsYT0wO2E8cjthKyspe3ZhciBzPWkoZSx0W2FdKTtzPD1NYXRoLm1heChvLHRbYV0ubGVuZ3RoLzIsMSkmJihuW3RbYV1dPXMpfXJldHVybiBPYmplY3Qua2V5cyhuKS5zb3J0KGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG5bZV0tblt0XX0pfWZ1bmN0aW9uIGkoZSx0KXt2YXIgbj12b2lkIDAscj12b2lkIDAsaT1bXSxvPWUubGVuZ3RoLGE9dC5sZW5ndGg7Zm9yKG49MDtuPD1vO24rKylpW25dPVtuXTtmb3Iocj0xO3I8PWE7cisrKWlbMF1bcl09cjtmb3Iobj0xO248PW87bisrKWZvcihyPTE7cjw9YTtyKyspe3ZhciBzPWVbbi0xXT09PXRbci0xXT8wOjE7aVtuXVtyXT1NYXRoLm1pbihpW24tMV1bcl0rMSxpW25dW3ItMV0rMSxpW24tMV1bci0xXStzKSxuPjEmJnI+MSYmZVtuLTFdPT09dFtyLTJdJiZlW24tMl09PT10W3ItMV0mJihpW25dW3JdPU1hdGgubWluKGlbbl1bcl0saVtuLTJdW3ItMl0rcykpfXJldHVybiBpW29dW2FdfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmRlZmF1bHQ9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PWUuc2xpY2UoMCxpKTtyZXR1cm4gdC5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuJyInK2UrJyInfSkucmVkdWNlKGZ1bmN0aW9uKGUsbixyKXtyZXR1cm4gZSsodC5sZW5ndGg+Mj8iLCAiOiIgIikrKHI9PT10Lmxlbmd0aC0xPyJvciAiOiIiKStufSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZGVmYXVsdD1yO3ZhciBpPTV9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4nVW5rbm93biBmcmFnbWVudCAiJytlKyciLid9ZnVuY3Rpb24gaShlKXtyZXR1cm57RnJhZ21lbnRTcHJlYWQ6ZnVuY3Rpb24odCl7dmFyIG49dC5uYW1lLnZhbHVlO2UuZ2V0RnJhZ21lbnQobil8fGUucmVwb3J0RXJyb3IobmV3IG8uR3JhcGhRTEVycm9yKHIobiksW3QubmFtZV0pKX19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnVua25vd25GcmFnbWVudE1lc3NhZ2U9cix0Lktub3duRnJhZ21lbnROYW1lcz1pO3ZhciBvPW4oMyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4nRnJhZ21lbnQgIicrZSsnIiBpcyBuZXZlciB1c2VkLid9ZnVuY3Rpb24gaShlKXt2YXIgdD1bXSxuPVtdO3JldHVybntPcGVyYXRpb25EZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiB0LnB1c2goZSksITF9LEZyYWdtZW50RGVmaW5pdGlvbjpmdW5jdGlvbihlKXtyZXR1cm4gbi5wdXNoKGUpLCExfSxEb2N1bWVudDp7bGVhdmU6ZnVuY3Rpb24oKXt2YXIgaT1PYmplY3QuY3JlYXRlKG51bGwpO3QuZm9yRWFjaChmdW5jdGlvbih0KXtlLmdldFJlY3Vyc2l2ZWx5UmVmZXJlbmNlZEZyYWdtZW50cyh0KS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2lbZS5uYW1lLnZhbHVlXT0hMH0pfSksbi5mb3JFYWNoKGZ1bmN0aW9uKHQpe3ZhciBuPXQubmFtZS52YWx1ZTshMCE9PWlbbl0mJmUucmVwb3J0RXJyb3IobmV3IG8uR3JhcGhRTEVycm9yKHIobiksW3RdKSl9KX19fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC51bnVzZWRGcmFnTWVzc2FnZT1yLHQuTm9VbnVzZWRGcmFnbWVudHM9aTt2YXIgbz1uKDMpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSx0LG4scixpLGEscyl7cmV0dXJuIDE9PT1hcmd1bWVudHMubGVuZ3RoP28oZS5zY2hlbWEsZS5kb2N1bWVudCxlLnJvb3RWYWx1ZSxlLmNvbnRleHRWYWx1ZSxlLnZhcmlhYmxlVmFsdWVzLGUub3BlcmF0aW9uTmFtZSxlLmZpZWxkUmVzb2x2ZXIpOm8oZSx0LG4scixpLGEscyl9ZnVuY3Rpb24gbyhlLHQsbixyLGksbyxhKXt1KGUsdCxpKTt2YXIgcz12b2lkIDA7dHJ5e3M9YyhlLHQsbixyLGksbyxhKX1jYXRjaChlKXtyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtlcnJvcnM6W2VdfSl9cmV0dXJuIFByb21pc2UucmVzb2x2ZShsKHMscy5vcGVyYXRpb24sbikpLnRoZW4oZnVuY3Rpb24oZSl7cmV0dXJuIDA9PT1zLmVycm9ycy5sZW5ndGg/e2RhdGE6ZX06e2Vycm9yczpzLmVycm9ycyxkYXRhOmV9fSl9ZnVuY3Rpb24gYShlKXtmb3IodmFyIHQ9W10sbj1lO247KXQucHVzaChuLmtleSksbj1uLnByZXY7cmV0dXJuIHQucmV2ZXJzZSgpfWZ1bmN0aW9uIHMoZSx0KXtyZXR1cm57cHJldjplLGtleTp0fX1mdW5jdGlvbiB1KGUsdCxuKXtlfHwoMCxCLmRlZmF1bHQpKDAsIk11c3QgcHJvdmlkZSBzY2hlbWEiKSx0fHwoMCxCLmRlZmF1bHQpKDAsIk11c3QgcHJvdmlkZSBkb2N1bWVudCIpLGUgaW5zdGFuY2VvZiBXLkdyYXBoUUxTY2hlbWF8fCgwLEIuZGVmYXVsdCkoMCwiU2NoZW1hIG11c3QgYmUgYW4gaW5zdGFuY2Ugb2YgR3JhcGhRTFNjaGVtYS4gQWxzbyBlbnN1cmUgdGhhdCB0aGVyZSBhcmUgbm90IG11bHRpcGxlIHZlcnNpb25zIG9mIEdyYXBoUUwgaW5zdGFsbGVkIGluIHlvdXIgbm9kZV9tb2R1bGVzIGRpcmVjdG9yeS4iKSxuJiYib2JqZWN0IiE9PSgidW5kZWZpbmVkIj09PXR5cGVvZiBuPyJ1bmRlZmluZWQiOlAobikpJiYoMCxCLmRlZmF1bHQpKDAsIlZhcmlhYmxlcyBtdXN0IGJlIHByb3ZpZGVkIGFzIGFuIE9iamVjdCB3aGVyZSBlYWNoIHByb3BlcnR5IGlzIGEgdmFyaWFibGUgdmFsdWUuIFBlcmhhcHMgbG9vayB0byBzZWUgaWYgYW4gdW5wYXJzZWQgSlNPTiBzdHJpbmcgd2FzIHByb3ZpZGVkLiIpfWZ1bmN0aW9uIGMoZSx0LG4scixpLG8sYSl7dmFyIHM9W10sdT12b2lkIDAsYz1PYmplY3QuY3JlYXRlKG51bGwpO2lmKHQuZGVmaW5pdGlvbnMuZm9yRWFjaChmdW5jdGlvbihlKXtzd2l0Y2goZS5raW5kKXtjYXNlIFYuT1BFUkFUSU9OX0RFRklOSVRJT046aWYoIW8mJnUpdGhyb3cgbmV3IGouR3JhcGhRTEVycm9yKCJNdXN0IHByb3ZpZGUgb3BlcmF0aW9uIG5hbWUgaWYgcXVlcnkgY29udGFpbnMgbXVsdGlwbGUgb3BlcmF0aW9ucy4iKTsoIW98fGUubmFtZSYmZS5uYW1lLnZhbHVlPT09bykmJih1PWUpO2JyZWFrO2Nhc2UgVi5GUkFHTUVOVF9ERUZJTklUSU9OOmNbZS5uYW1lLnZhbHVlXT1lO2JyZWFrO2RlZmF1bHQ6dGhyb3cgbmV3IGouR3JhcGhRTEVycm9yKCJHcmFwaFFMIGNhbm5vdCBleGVjdXRlIGEgcmVxdWVzdCBjb250YWluaW5nIGEgIitlLmtpbmQrIi4iLFtlXSl9fSksIXUpdGhyb3cgbz9uZXcgai5HcmFwaFFMRXJyb3IoJ1Vua25vd24gb3BlcmF0aW9uIG5hbWVkICInK28rJyIuJyk6bmV3IGouR3JhcGhRTEVycm9yKCJNdXN0IHByb3ZpZGUgYW4gb3BlcmF0aW9uLiIpO3ZhciBsPSgwLHEuZ2V0VmFyaWFibGVWYWx1ZXMpKGUsdS52YXJpYWJsZURlZmluaXRpb25zfHxbXSxpfHx7fSk7cmV0dXJue3NjaGVtYTplLGZyYWdtZW50czpjLHJvb3RWYWx1ZTpuLGNvbnRleHRWYWx1ZTpyLG9wZXJhdGlvbjp1LHZhcmlhYmxlVmFsdWVzOmwsZmllbGRSZXNvbHZlcjphfHxKLGVycm9yczpzfX1mdW5jdGlvbiBsKGUsdCxuKXt2YXIgcj1wKGUuc2NoZW1hLHQpLGk9aChlLHIsdC5zZWxlY3Rpb25TZXQsT2JqZWN0LmNyZWF0ZShudWxsKSxPYmplY3QuY3JlYXRlKG51bGwpKTt0cnl7dmFyIG89Im11dGF0aW9uIj09PXQub3BlcmF0aW9uP2YoZSxyLG4sdm9pZCAwLGkpOmQoZSxyLG4sdm9pZCAwLGkpLGE9SShvKTtyZXR1cm4gYT9hLnRoZW4odm9pZCAwLGZ1bmN0aW9uKHQpe3JldHVybiBlLmVycm9ycy5wdXNoKHQpLFByb21pc2UucmVzb2x2ZShudWxsKX0pOm99Y2F0Y2godCl7cmV0dXJuIGUuZXJyb3JzLnB1c2godCksbnVsbH19ZnVuY3Rpb24gcChlLHQpe3N3aXRjaCh0Lm9wZXJhdGlvbil7Y2FzZSJxdWVyeSI6cmV0dXJuIGUuZ2V0UXVlcnlUeXBlKCk7Y2FzZSJtdXRhdGlvbiI6dmFyIG49ZS5nZXRNdXRhdGlvblR5cGUoKTtpZighbil0aHJvdyBuZXcgai5HcmFwaFFMRXJyb3IoIlNjaGVtYSBpcyBub3QgY29uZmlndXJlZCBmb3IgbXV0YXRpb25zIixbdF0pO3JldHVybiBuO2Nhc2Uic3Vic2NyaXB0aW9uIjp2YXIgcj1lLmdldFN1YnNjcmlwdGlvblR5cGUoKTtpZighcil0aHJvdyBuZXcgai5HcmFwaFFMRXJyb3IoIlNjaGVtYSBpcyBub3QgY29uZmlndXJlZCBmb3Igc3Vic2NyaXB0aW9ucyIsW3RdKTtyZXR1cm4gcjtkZWZhdWx0OnRocm93IG5ldyBqLkdyYXBoUUxFcnJvcigiQ2FuIG9ubHkgZXhlY3V0ZSBxdWVyaWVzLCBtdXRhdGlvbnMgYW5kIHN1YnNjcmlwdGlvbnMiLFt0XSl9fWZ1bmN0aW9uIGYoZSx0LG4scixpKXtyZXR1cm4gT2JqZWN0LmtleXMoaSkucmVkdWNlKGZ1bmN0aW9uKG8sYSl7cmV0dXJuIG8udGhlbihmdW5jdGlvbihvKXt2YXIgdT1pW2FdLGM9cyhyLGEpLGw9YihlLHQsbix1LGMpO2lmKHZvaWQgMD09PWwpcmV0dXJuIG87dmFyIHA9SShsKTtyZXR1cm4gcD9wLnRoZW4oZnVuY3Rpb24oZSl7cmV0dXJuIG9bYV09ZSxvfSk6KG9bYV09bCxvKX0pfSxQcm9taXNlLnJlc29sdmUoe30pKX1mdW5jdGlvbiBkKGUsdCxuLHIsaSl7dmFyIG89ITEsYT1PYmplY3Qua2V5cyhpKS5yZWR1Y2UoZnVuY3Rpb24oYSx1KXt2YXIgYz1pW3VdLGw9cyhyLHUpLHA9YihlLHQsbixjLGwpO3JldHVybiB2b2lkIDA9PT1wP2E6KGFbdV09cCxJKHApJiYobz0hMCksYSl9LE9iamVjdC5jcmVhdGUobnVsbCkpO3JldHVybiBvP3koYSk6YX1mdW5jdGlvbiBoKGUsdCxuLHIsaSl7Zm9yKHZhciBvPTA7bzxuLnNlbGVjdGlvbnMubGVuZ3RoO28rKyl7dmFyIGE9bi5zZWxlY3Rpb25zW29dO3N3aXRjaChhLmtpbmQpe2Nhc2UgVi5GSUVMRDppZighbShlLGEpKWNvbnRpbnVlO3ZhciBzPXYoYSk7cltzXXx8KHJbc109W10pLHJbc10ucHVzaChhKTticmVhaztjYXNlIFYuSU5MSU5FX0ZSQUdNRU5UOmlmKCFtKGUsYSl8fCFnKGUsYSx0KSljb250aW51ZTtoKGUsdCxhLnNlbGVjdGlvblNldCxyLGkpO2JyZWFrO2Nhc2UgVi5GUkFHTUVOVF9TUFJFQUQ6dmFyIHU9YS5uYW1lLnZhbHVlO2lmKGlbdV18fCFtKGUsYSkpY29udGludWU7aVt1XT0hMDt2YXIgYz1lLmZyYWdtZW50c1t1XTtpZighY3x8IWcoZSxjLHQpKWNvbnRpbnVlO2goZSx0LGMuc2VsZWN0aW9uU2V0LHIsaSl9fXJldHVybiByfWZ1bmN0aW9uIG0oZSx0KXt2YXIgbj0oMCxxLmdldERpcmVjdGl2ZVZhbHVlcykoSy5HcmFwaFFMU2tpcERpcmVjdGl2ZSx0LGUudmFyaWFibGVWYWx1ZXMpO2lmKG4mJiEwPT09bi5pZilyZXR1cm4hMTt2YXIgcj0oMCxxLmdldERpcmVjdGl2ZVZhbHVlcykoSy5HcmFwaFFMSW5jbHVkZURpcmVjdGl2ZSx0LGUudmFyaWFibGVWYWx1ZXMpO3JldHVybiFyfHwhMSE9PXIuaWZ9ZnVuY3Rpb24gZyhlLHQsbil7dmFyIHI9dC50eXBlQ29uZGl0aW9uO2lmKCFyKXJldHVybiEwO3ZhciBpPSgwLHoudHlwZUZyb21BU1QpKGUuc2NoZW1hLHIpO3JldHVybiBpPT09bnx8ISEoMCxILmlzQWJzdHJhY3RUeXBlKShpKSYmZS5zY2hlbWEuaXNQb3NzaWJsZVR5cGUoaSxuKX1mdW5jdGlvbiB5KGUpe3ZhciB0PU9iamVjdC5rZXlzKGUpLG49dC5tYXAoZnVuY3Rpb24odCl7cmV0dXJuIGVbdF19KTtyZXR1cm4gUHJvbWlzZS5hbGwobikudGhlbihmdW5jdGlvbihlKXtyZXR1cm4gZS5yZWR1Y2UoZnVuY3Rpb24oZSxuLHIpe3JldHVybiBlW3Rbcl1dPW4sZX0sT2JqZWN0LmNyZWF0ZShudWxsKSl9KX1mdW5jdGlvbiB2KGUpe3JldHVybiBlLmFsaWFzP2UuYWxpYXMudmFsdWU6ZS5uYW1lLnZhbHVlfWZ1bmN0aW9uIGIoZSx0LG4scixpKXt2YXIgbz1yWzBdLGE9by5uYW1lLnZhbHVlLHM9TChlLnNjaGVtYSx0LGEpO2lmKHMpe3ZhciB1PXMucmVzb2x2ZXx8ZS5maWVsZFJlc29sdmVyLGM9eChlLHMscix0LGkpLGw9QyhlLHMscix1LG4sYyk7cmV0dXJuIEUoZSxzLnR5cGUscixjLGksbCl9fWZ1bmN0aW9uIHgoZSx0LG4scixpKXtyZXR1cm57ZmllbGROYW1lOm5bMF0ubmFtZS52YWx1ZSxmaWVsZE5vZGVzOm4scmV0dXJuVHlwZTp0LnR5cGUscGFyZW50VHlwZTpyLHBhdGg6aSxzY2hlbWE6ZS5zY2hlbWEsZnJhZ21lbnRzOmUuZnJhZ21lbnRzLHJvb3RWYWx1ZTplLnJvb3RWYWx1ZSxvcGVyYXRpb246ZS5vcGVyYXRpb24sdmFyaWFibGVWYWx1ZXM6ZS52YXJpYWJsZVZhbHVlc319ZnVuY3Rpb24gQyhlLHQsbixyLGksbyl7dHJ5e3JldHVybiByKGksKDAscS5nZXRBcmd1bWVudFZhbHVlcykodCxuWzBdLGUudmFyaWFibGVWYWx1ZXMpLGUuY29udGV4dFZhbHVlLG8pfWNhdGNoKGUpe3JldHVybiBlIGluc3RhbmNlb2YgRXJyb3I/ZTpuZXcgRXJyb3IoZSl9fWZ1bmN0aW9uIEUoZSx0LG4scixpLG8pe2lmKHQgaW5zdGFuY2VvZiBILkdyYXBoUUxOb25OdWxsKXJldHVybiBEKGUsdCxuLHIsaSxvKTt0cnl7dmFyIGE9RChlLHQsbixyLGksbykscz1JKGEpO3JldHVybiBzP3MudGhlbih2b2lkIDAsZnVuY3Rpb24odCl7cmV0dXJuIGUuZXJyb3JzLnB1c2godCksUHJvbWlzZS5yZXNvbHZlKG51bGwpfSk6YX1jYXRjaCh0KXtyZXR1cm4gZS5lcnJvcnMucHVzaCh0KSxudWxsfX1mdW5jdGlvbiBEKGUsdCxuLHIsaSxvKXt0cnl7dmFyIHM9dyhlLHQsbixyLGksbyksdT1JKHMpO3JldHVybiB1P3UudGhlbih2b2lkIDAsZnVuY3Rpb24oZSl7cmV0dXJuIFByb21pc2UucmVqZWN0KCgwLGoubG9jYXRlZEVycm9yKShlLG4sYShpKSkpfSk6c31jYXRjaChlKXt0aHJvdygwLGoubG9jYXRlZEVycm9yKShlLG4sYShpKSl9fWZ1bmN0aW9uIHcoZSx0LG4scixpLG8pe3ZhciBhPUkobyk7aWYoYSlyZXR1cm4gYS50aGVuKGZ1bmN0aW9uKG8pe3JldHVybiB3KGUsdCxuLHIsaSxvKX0pO2lmKG8gaW5zdGFuY2VvZiBFcnJvcil0aHJvdyBvO2lmKHQgaW5zdGFuY2VvZiBILkdyYXBoUUxOb25OdWxsKXt2YXIgcz13KGUsdC5vZlR5cGUsbixyLGksbyk7aWYobnVsbD09PXMpdGhyb3cgbmV3IEVycm9yKCJDYW5ub3QgcmV0dXJuIG51bGwgZm9yIG5vbi1udWxsYWJsZSBmaWVsZCAiK3IucGFyZW50VHlwZS5uYW1lKyIuIityLmZpZWxkTmFtZSsiLiIpO3JldHVybiBzfWlmKCgwLFUuZGVmYXVsdCkobykpcmV0dXJuIG51bGw7aWYodCBpbnN0YW5jZW9mIEguR3JhcGhRTExpc3QpcmV0dXJuIFMoZSx0LG4scixpLG8pO2lmKCgwLEguaXNMZWFmVHlwZSkodCkpcmV0dXJuIGsodCxvKTtpZigoMCxILmlzQWJzdHJhY3RUeXBlKSh0KSlyZXR1cm4gQShlLHQsbixyLGksbyk7aWYodCBpbnN0YW5jZW9mIEguR3JhcGhRTE9iamVjdFR5cGUpcmV0dXJuIFQoZSx0LG4scixpLG8pO3Rocm93IG5ldyBFcnJvcignQ2Fubm90IGNvbXBsZXRlIHZhbHVlIG9mIHVuZXhwZWN0ZWQgdHlwZSAiJytTdHJpbmcodCkrJyIuJyl9ZnVuY3Rpb24gUyhlLHQsbixyLGksbyl7KDAsTS5pc0NvbGxlY3Rpb24pKG8pfHwoMCxCLmRlZmF1bHQpKDAsIkV4cGVjdGVkIEl0ZXJhYmxlLCBidXQgZGlkIG5vdCBmaW5kIG9uZSBmb3IgZmllbGQgIityLnBhcmVudFR5cGUubmFtZSsiLiIrci5maWVsZE5hbWUrIi4iKTt2YXIgYT10Lm9mVHlwZSx1PSExLGM9W107cmV0dXJuKDAsTS5mb3JFYWNoKShvLGZ1bmN0aW9uKHQsbyl7dmFyIGw9cyhpLG8pLHA9RShlLGEsbixyLGwsdCk7IXUmJkkocCkmJih1PSEwKSxjLnB1c2gocCl9KSx1P1Byb21pc2UuYWxsKGMpOmN9ZnVuY3Rpb24gayhlLHQpe2Uuc2VyaWFsaXplfHwoMCxCLmRlZmF1bHQpKDAsIk1pc3Npbmcgc2VyaWFsaXplIG1ldGhvZCBvbiB0eXBlIik7dmFyIG49ZS5zZXJpYWxpemUodCk7aWYoKDAsVS5kZWZhdWx0KShuKSl0aHJvdyBuZXcgRXJyb3IoJ0V4cGVjdGVkIGEgdmFsdWUgb2YgdHlwZSAiJytTdHJpbmcoZSkrJyIgYnV0IHJlY2VpdmVkOiAnK1N0cmluZyh0KSk7cmV0dXJuIG59ZnVuY3Rpb24gQShlLHQsbixyLGksbyl7dmFyIGE9dC5yZXNvbHZlVHlwZT90LnJlc29sdmVUeXBlKG8sZS5jb250ZXh0VmFsdWUscik6TihvLGUuY29udGV4dFZhbHVlLHIsdCkscz1JKGEpO3JldHVybiBzP3MudGhlbihmdW5jdGlvbihhKXtyZXR1cm4gVChlLF8oYSxlLHQsbixyLG8pLG4scixpLG8pfSk6VChlLF8oYSxlLHQsbixyLG8pLG4scixpLG8pfWZ1bmN0aW9uIF8oZSx0LG4scixpLG8pe3ZhciBhPSJzdHJpbmciPT09dHlwZW9mIGU/dC5zY2hlbWEuZ2V0VHlwZShlKTplO2lmKCEoYSBpbnN0YW5jZW9mIEguR3JhcGhRTE9iamVjdFR5cGUpKXRocm93IG5ldyBqLkdyYXBoUUxFcnJvcigiQWJzdHJhY3QgdHlwZSAiK24ubmFtZSsiIG11c3QgcmVzb2x2ZSB0byBhbiBPYmplY3QgdHlwZSBhdCBydW50aW1lIGZvciBmaWVsZCAiK2kucGFyZW50VHlwZS5uYW1lKyIuIitpLmZpZWxkTmFtZSsnIHdpdGggdmFsdWUgIicrU3RyaW5nKG8pKyciLCByZWNlaXZlZCAiJytTdHJpbmcoYSkrJyIuJyxyKTtpZighdC5zY2hlbWEuaXNQb3NzaWJsZVR5cGUobixhKSl0aHJvdyBuZXcgai5HcmFwaFFMRXJyb3IoJ1J1bnRpbWUgT2JqZWN0IHR5cGUgIicrYS5uYW1lKyciIGlzIG5vdCBhIHBvc3NpYmxlIHR5cGUgZm9yICInK24ubmFtZSsnIi4nLHIpO3JldHVybiBhfWZ1bmN0aW9uIFQoZSx0LG4scixpLG8pe2lmKHQuaXNUeXBlT2Ype3ZhciBhPXQuaXNUeXBlT2YobyxlLmNvbnRleHRWYWx1ZSxyKSxzPUkoYSk7aWYocylyZXR1cm4gcy50aGVuKGZ1bmN0aW9uKGEpe2lmKCFhKXRocm93IE8odCxvLG4pO3JldHVybiBGKGUsdCxuLHIsaSxvKX0pO2lmKCFhKXRocm93IE8odCxvLG4pfXJldHVybiBGKGUsdCxuLHIsaSxvKX1mdW5jdGlvbiBPKGUsdCxuKXtyZXR1cm4gbmV3IGouR3JhcGhRTEVycm9yKCdFeHBlY3RlZCB2YWx1ZSBvZiB0eXBlICInK2UubmFtZSsnIiBidXQgZ290OiAnK1N0cmluZyh0KSsiLiIsbil9ZnVuY3Rpb24gRihlLHQsbixyLGksbyl7Zm9yKHZhciBhPU9iamVjdC5jcmVhdGUobnVsbCkscz1PYmplY3QuY3JlYXRlKG51bGwpLHU9MDt1PG4ubGVuZ3RoO3UrKyl7dmFyIGM9blt1XS5zZWxlY3Rpb25TZXQ7YyYmKGE9aChlLHQsYyxhLHMpKX1yZXR1cm4gZChlLHQsbyxpLGEpfWZ1bmN0aW9uIE4oZSx0LG4scil7Zm9yKHZhciBpPW4uc2NoZW1hLmdldFBvc3NpYmxlVHlwZXMociksbz1bXSxhPTA7YTxpLmxlbmd0aDthKyspe3ZhciBzPWlbYV07aWYocy5pc1R5cGVPZil7dmFyIHU9cy5pc1R5cGVPZihlLHQsbiksYz1JKHUpO2lmKGMpb1thXT1jO2Vsc2UgaWYodSlyZXR1cm4gc319aWYoby5sZW5ndGgpcmV0dXJuIFByb21pc2UuYWxsKG8pLnRoZW4oZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTA7dDxlLmxlbmd0aDt0KyspaWYoZVt0XSlyZXR1cm4gaVt0XX0pfWZ1bmN0aW9uIEkoZSl7aWYoIm9iamVjdCI9PT0oInVuZGVmaW5lZCI9PT10eXBlb2YgZT8idW5kZWZpbmVkIjpQKGUpKSYmbnVsbCE9PWUmJiJmdW5jdGlvbiI9PT10eXBlb2YgZS50aGVuKXJldHVybiBlfWZ1bmN0aW9uIEwoZSx0LG4pe3JldHVybiBuPT09US5TY2hlbWFNZXRhRmllbGREZWYubmFtZSYmZS5nZXRRdWVyeVR5cGUoKT09PXQ/US5TY2hlbWFNZXRhRmllbGREZWY6bj09PVEuVHlwZU1ldGFGaWVsZERlZi5uYW1lJiZlLmdldFF1ZXJ5VHlwZSgpPT09dD9RLlR5cGVNZXRhRmllbGREZWY6bj09PVEuVHlwZU5hbWVNZXRhRmllbGREZWYubmFtZT9RLlR5cGVOYW1lTWV0YUZpZWxkRGVmOnQuZ2V0RmllbGRzKClbbl19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZGVmYXVsdEZpZWxkUmVzb2x2ZXI9dm9pZCAwO3ZhciBQPSJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiYic3ltYm9sIj09PXR5cGVvZiBTeW1ib2wuaXRlcmF0b3I/ZnVuY3Rpb24oZSl7cmV0dXJuIHR5cGVvZiBlfTpmdW5jdGlvbihlKXtyZXR1cm4gZSYmImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfTt0LmV4ZWN1dGU9aSx0LnJlc3BvbnNlUGF0aEFzQXJyYXk9YSx0LmFkZFBhdGg9cyx0LmFzc2VydFZhbGlkRXhlY3V0aW9uQXJndW1lbnRzPXUsdC5idWlsZEV4ZWN1dGlvbkNvbnRleHQ9Yyx0LmdldE9wZXJhdGlvblJvb3RUeXBlPXAsdC5jb2xsZWN0RmllbGRzPWgsdC5idWlsZFJlc29sdmVJbmZvPXgsdC5yZXNvbHZlRmllbGRWYWx1ZU9yRXJyb3I9Qyx0LmdldEZpZWxkRGVmPUw7dmFyIE09big0NCksaj1uKDMpLFI9bigxMyksQj1yKFIpLCQ9bigzNSksVT1yKCQpLHo9bigyOSksRz1uKDEwKSxWPWZ1bmN0aW9uKGUpe2lmKGUmJmUuX19lc01vZHVsZSlyZXR1cm4gZTt2YXIgdD17fTtpZihudWxsIT1lKWZvcih2YXIgbiBpbiBlKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLG4pJiYodFtuXT1lW25dKTtyZXR1cm4gdC5kZWZhdWx0PWUsdH0oRykscT1uKDExOSksSD1uKDYpLFc9bigyNiksUT1uKDI4KSxLPW4oMjcpLEo9dC5kZWZhdWx0RmllbGRSZXNvbHZlcj1mdW5jdGlvbihlLHQsbixyKXtpZigib2JqZWN0Ij09PSgidW5kZWZpbmVkIj09PXR5cGVvZiBlPyJ1bmRlZmluZWQiOlAoZSkpfHwiZnVuY3Rpb24iPT09dHlwZW9mIGUpe3ZhciBpPWVbci5maWVsZE5hbWVdO3JldHVybiJmdW5jdGlvbiI9PT10eXBlb2YgaT9lW3IuZmllbGROYW1lXSh0LG4scik6aX19fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSx0LG4pe2Zvcih2YXIgcj17fSxpPTA7aTx0Lmxlbmd0aDtpKyspe3ZhciBvPXRbaV0sYT1vLnZhcmlhYmxlLm5hbWUudmFsdWUsdT0oMCxDLnR5cGVGcm9tQVNUKShlLG8udHlwZSk7aWYoISgwLF8uaXNJbnB1dFR5cGUpKHUpKXRocm93IG5ldyBsLkdyYXBoUUxFcnJvcignVmFyaWFibGUgIiQnK2ErJyIgZXhwZWN0ZWQgdmFsdWUgb2YgdHlwZSAiJysoMCxBLnByaW50KShvLnR5cGUpKyciIHdoaWNoIGNhbm5vdCBiZSB1c2VkIGFzIGFuIGlucHV0IHR5cGUuJyxbby50eXBlXSk7dmFyIGM9blthXTtpZigoMCx2LmRlZmF1bHQpKGMpKXt2YXIgcD1vLmRlZmF1bHRWYWx1ZTtpZihwJiYoclthXT0oMCxFLnZhbHVlRnJvbUFTVCkocCx1KSksdSBpbnN0YW5jZW9mIF8uR3JhcGhRTE5vbk51bGwpdGhyb3cgbmV3IGwuR3JhcGhRTEVycm9yKCdWYXJpYWJsZSAiJCcrYSsnIiBvZiByZXF1aXJlZCB0eXBlICInK1N0cmluZyh1KSsnIiB3YXMgbm90IHByb3ZpZGVkLicsW29dKX1lbHNle3ZhciBmPSgwLEQuaXNWYWxpZEpTVmFsdWUpKGMsdSk7aWYoZi5sZW5ndGgpe3ZhciBkPWY/IlxuIitmLmpvaW4oIlxuIik6IiI7dGhyb3cgbmV3IGwuR3JhcGhRTEVycm9yKCdWYXJpYWJsZSAiJCcrYSsnIiBnb3QgaW52YWxpZCB2YWx1ZSAnK0pTT04uc3RyaW5naWZ5KGMpKyIuIitkLFtvXSl9dmFyIG09cyh1LGMpOygwLHYuZGVmYXVsdCkobSkmJigwLGguZGVmYXVsdCkoMCwiU2hvdWxkIGhhdmUgcmVwb3J0ZWQgZXJyb3IuIiksclthXT1tfX1yZXR1cm4gcn1mdW5jdGlvbiBvKGUsdCxuKXt2YXIgcj17fSxpPWUuYXJncyxvPXQuYXJndW1lbnRzO2lmKCFpfHwhbylyZXR1cm4gcjtmb3IodmFyIGE9KDAseC5kZWZhdWx0KShvLGZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWUudmFsdWV9KSxzPTA7czxpLmxlbmd0aDtzKyspe3ZhciB1PWlbc10sYz11Lm5hbWUscD11LnR5cGUsZj1hW2NdLGQ9dS5kZWZhdWx0VmFsdWU7aWYoZilpZihmLnZhbHVlLmtpbmQ9PT1rLlZBUklBQkxFKXt2YXIgaD1mLnZhbHVlLm5hbWUudmFsdWU7aWYobiYmT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4saCkmJiEoMCx2LmRlZmF1bHQpKG5baF0pKXJbY109bltoXTtlbHNlIGlmKCgwLHYuZGVmYXVsdCkoZCkpe2lmKHAgaW5zdGFuY2VvZiBfLkdyYXBoUUxOb25OdWxsKXRocm93IG5ldyBsLkdyYXBoUUxFcnJvcignQXJndW1lbnQgIicrYysnIiBvZiByZXF1aXJlZCB0eXBlICInK1N0cmluZyhwKSsnIiB3YXMgcHJvdmlkZWQgdGhlIHZhcmlhYmxlICIkJytoKyciIHdoaWNoIHdhcyBub3QgcHJvdmlkZWQgYSBydW50aW1lIHZhbHVlLicsW2YudmFsdWVdKX1lbHNlIHJbY109ZH1lbHNle3ZhciBtPWYudmFsdWUsZz0oMCxFLnZhbHVlRnJvbUFTVCkobSxwLG4pO2lmKCgwLHYuZGVmYXVsdCkoZykpe3ZhciB5PSgwLHcuaXNWYWxpZExpdGVyYWxWYWx1ZSkocCxtKSxiPXk/IlxuIit5LmpvaW4oIlxuIik6IiI7dGhyb3cgbmV3IGwuR3JhcGhRTEVycm9yKCdBcmd1bWVudCAiJytjKyciIGdvdCBpbnZhbGlkIHZhbHVlICcrKDAsQS5wcmludCkobSkrIi4iK2IsW2YudmFsdWVdKX1yW2NdPWd9ZWxzZSBpZigoMCx2LmRlZmF1bHQpKGQpKXtpZihwIGluc3RhbmNlb2YgXy5HcmFwaFFMTm9uTnVsbCl0aHJvdyBuZXcgbC5HcmFwaFFMRXJyb3IoJ0FyZ3VtZW50ICInK2MrJyIgb2YgcmVxdWlyZWQgdHlwZSAiJytTdHJpbmcocCkrJyIgd2FzIG5vdCBwcm92aWRlZC4nLFt0XSl9ZWxzZSByW2NdPWR9cmV0dXJuIHJ9ZnVuY3Rpb24gYShlLHQsbil7dmFyIHI9dC5kaXJlY3RpdmVzJiYoMCxmLmRlZmF1bHQpKHQuZGlyZWN0aXZlcyxmdW5jdGlvbih0KXtyZXR1cm4gdC5uYW1lLnZhbHVlPT09ZS5uYW1lfSk7aWYocilyZXR1cm4gbyhlLHIsbil9ZnVuY3Rpb24gcyhlLHQpe3ZhciBuPXQ7aWYoISgwLHYuZGVmYXVsdCkobikpe2lmKGUgaW5zdGFuY2VvZiBfLkdyYXBoUUxOb25OdWxsKXtpZihudWxsPT09bilyZXR1cm47cmV0dXJuIHMoZS5vZlR5cGUsbil9aWYobnVsbD09PW4pcmV0dXJuIG51bGw7aWYoZSBpbnN0YW5jZW9mIF8uR3JhcGhRTExpc3Qpe3ZhciByPWUub2ZUeXBlO2lmKCgwLGMuaXNDb2xsZWN0aW9uKShuKSl7dmFyIGk9W10sbz0oMCxjLmNyZWF0ZUl0ZXJhdG9yKShuKTtpZighbylyZXR1cm47Zm9yKHZhciBhPXZvaWQgMDshKGE9by5uZXh0KCkpLmRvbmU7KXt2YXIgbD1zKHIsYS52YWx1ZSk7aWYoKDAsdi5kZWZhdWx0KShsKSlyZXR1cm47aS5wdXNoKGwpfXJldHVybiBpfXZhciBwPXMocixuKTtpZigoMCx2LmRlZmF1bHQpKHApKXJldHVybjtyZXR1cm5bcyhyLG4pXX1pZihlIGluc3RhbmNlb2YgXy5HcmFwaFFMSW5wdXRPYmplY3RUeXBlKXtpZigib2JqZWN0IiE9PSgidW5kZWZpbmVkIj09PXR5cGVvZiBuPyJ1bmRlZmluZWQiOnUobikpKXJldHVybjtmb3IodmFyIGY9T2JqZWN0LmNyZWF0ZShudWxsKSxkPWUuZ2V0RmllbGRzKCksbT1PYmplY3Qua2V5cyhkKSx5PTA7eTxtLmxlbmd0aDt5Kyspe3ZhciBiPW1beV0seD1kW2JdO2lmKCgwLHYuZGVmYXVsdCkobltiXSkpaWYoKDAsdi5kZWZhdWx0KSh4LmRlZmF1bHRWYWx1ZSkpe2lmKHgudHlwZSBpbnN0YW5jZW9mIF8uR3JhcGhRTE5vbk51bGwpcmV0dXJufWVsc2UgZltiXT14LmRlZmF1bHRWYWx1ZTtlbHNle3ZhciBDPXMoeC50eXBlLG5bYl0pO2lmKCgwLHYuZGVmYXVsdCkoQykpcmV0dXJuO2ZbYl09Q319cmV0dXJuIGZ9ZSBpbnN0YW5jZW9mIF8uR3JhcGhRTFNjYWxhclR5cGV8fGUgaW5zdGFuY2VvZiBfLkdyYXBoUUxFbnVtVHlwZXx8KDAsaC5kZWZhdWx0KSgwLCJNdXN0IGJlIGlucHV0IHR5cGUiKTt2YXIgRT1lLnBhcnNlVmFsdWUobik7aWYoISgwLGcuZGVmYXVsdCkoRSkpcmV0dXJuIEV9fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgdT0iZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmInN5bWJvbCI9PT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiZlLmNvbnN0cnVjdG9yPT09U3ltYm9sJiZlIT09U3ltYm9sLnByb3RvdHlwZT8ic3ltYm9sIjp0eXBlb2YgZX07dC5nZXRWYXJpYWJsZVZhbHVlcz1pLHQuZ2V0QXJndW1lbnRWYWx1ZXM9byx0LmdldERpcmVjdGl2ZVZhbHVlcz1hLHQuY29lcmNlVmFsdWU9czt2YXIgYz1uKDQ0KSxsPW4oMykscD1uKDQ1KSxmPXIocCksZD1uKDEzKSxoPXIoZCksbT1uKDM1KSxnPXIobSkseT1uKDU4KSx2PXIoeSksYj1uKDQ2KSx4PXIoYiksQz1uKDI5KSxFPW4oNTkpLEQ9bigyMDcpLHc9big4MiksUz1uKDEwKSxrPWZ1bmN0aW9uKGUpe2lmKGUmJmUuX19lc01vZHVsZSlyZXR1cm4gZTt2YXIgdD17fTtpZihudWxsIT1lKWZvcih2YXIgbiBpbiBlKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLG4pJiYodFtuXT1lW25dKTtyZXR1cm4gdC5kZWZhdWx0PWUsdH0oUyksQT1uKDE5KSxfPW4oNil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuIGUucmVkdWNlKGZ1bmN0aW9uKGUscil7cmV0dXJuIGVbdChyKV09bihyKSxlfSxPYmplY3QuY3JlYXRlKG51bGwpKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIGV8fCFPYmplY3Qoby5hKShlKSYmT2JqZWN0KGEuYSkoZSkmJk9iamVjdChpLmEpKGUpPT1zfXZhciBpPW4oMzMpLG89big0NyksYT1uKDMxKSxzPSJbb2JqZWN0IFN0cmluZ10iO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG51bGwhPWUmJk9iamVjdChvLmEpKGUubGVuZ3RoKSYmIU9iamVjdChpLmEpKGUpfXZhciBpPW4oNDgpLG89bigyMTYpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuInN5bWJvbCI9PXR5cGVvZiBlfHxPYmplY3Qoby5hKShlKSYmT2JqZWN0KGkuYSkoZSk9PWF9dmFyIGk9bigzMyksbz1uKDMxKSxhPSJbb2JqZWN0IFN5bWJvbF0iO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dmFyIHQ9YXJndW1lbnRzLmxlbmd0aD4xJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0/YXJndW1lbnRzWzFdOmkuYSxuPWFyZ3VtZW50c1syXTt1KCkoT2JqZWN0KG8uYSkodCl8fE9iamVjdChhLmEpKHQpLCJFeHBlY3RlZCBwYXlsb2FkQ3JlYXRvciB0byBiZSBhIGZ1bmN0aW9uLCB1bmRlZmluZWQgb3IgbnVsbCIpO3ZhciByPU9iamVjdChhLmEpKHQpfHx0PT09aS5hP2kuYTpmdW5jdGlvbihlKXtmb3IodmFyIG49YXJndW1lbnRzLmxlbmd0aCxyPUFycmF5KG4+MT9uLTE6MCksaT0xO2k8bjtpKyspcltpLTFdPWFyZ3VtZW50c1tpXTtyZXR1cm4gZSBpbnN0YW5jZW9mIEVycm9yP2U6dC5hcHBseSh2b2lkIDAsW2VdLmNvbmNhdChyKSl9LHM9T2JqZWN0KG8uYSkobiksYz1lLnRvU3RyaW5nKCksbD1mdW5jdGlvbigpe3ZhciB0PXIuYXBwbHkodm9pZCAwLGFyZ3VtZW50cyksaT17dHlwZTplfTtyZXR1cm4gdCBpbnN0YW5jZW9mIEVycm9yJiYoaS5lcnJvcj0hMCksdm9pZCAwIT09dCYmKGkucGF5bG9hZD10KSxzJiYoaS5tZXRhPW4uYXBwbHkodm9pZCAwLGFyZ3VtZW50cykpLGl9O3JldHVybiBsLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIGN9LGx9dC5hPXI7dmFyIGk9big2Myksbz1uKDQ4KSxhPW4oNDIzKSxzPW4oMjApLHU9bi5uKHMpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7aWYoT2JqZWN0KGkuYSkoZSkpcmV0dXJuIEFycmF5LmZyb20oZS5rZXlzKCkpO2lmKCJ1bmRlZmluZWQiIT09dHlwZW9mIFJlZmxlY3QmJiJmdW5jdGlvbiI9PT10eXBlb2YgUmVmbGVjdC5vd25LZXlzKXJldHVybiBSZWZsZWN0Lm93bktleXMoZSk7dmFyIHQ9T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoZSk7cmV0dXJuImZ1bmN0aW9uIj09PXR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzJiYodD10LmNvbmNhdChPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKGUpKSksdH10LmE9cjt2YXIgaT1uKDgzKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDYwKSxpPU9iamVjdC5jcmVhdGUsbz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXt9cmV0dXJuIGZ1bmN0aW9uKHQpe2lmKCFPYmplY3Qoci5hKSh0KSlyZXR1cm57fTtpZihpKXJldHVybiBpKHQpO2UucHJvdG90eXBlPXQ7dmFyIG49bmV3IGU7cmV0dXJuIGUucHJvdG90eXBlPXZvaWQgMCxufX0oKTt0LmE9b30sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3RoaXMuX193cmFwcGVkX189ZSx0aGlzLl9fYWN0aW9uc19fPVtdLHRoaXMuX19kaXJfXz0xLHRoaXMuX19maWx0ZXJlZF9fPSExLHRoaXMuX19pdGVyYXRlZXNfXz1bXSx0aGlzLl9fdGFrZUNvdW50X189YSx0aGlzLl9fdmlld3NfXz1bXX12YXIgaT1uKDEyNiksbz1uKDEyOCksYT00Mjk0OTY3Mjk1O3IucHJvdG90eXBlPU9iamVjdChpLmEpKG8uYS5wcm90b3R5cGUpLHIucHJvdG90eXBlLmNvbnN0cnVjdG9yPXIsdC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe310LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuPS0xLHI9ZS5sZW5ndGgsbz0wLGE9W107KytuPHI7KXt2YXIgcz1lW25dO3MhPT10JiZzIT09aXx8KGVbbl09aSxhW28rK109bil9cmV0dXJuIGF9dmFyIGk9Il9fbG9kYXNoX3BsYWNlaG9sZGVyX18iO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtpZighdCl0aHJvdyBuZXcgRXJyb3IoInNlc3Npb25JZCBjYW50IGJlIG51bGwiKTtyZXR1cm4gZS5nZXQodCl8fG5ldyB1fXZhciBpPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPW4oMTQpLGE9bigyMykscz1uKDM2KSx1PWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gbnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzfXJldHVybiBpKHQsZSksdC5wcm90b3R5cGUudG9KU09OPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy50b09iamVjdCgpO3JldHVybiBvLnNldChlLCJuYXZTdGFjayIsby5MaXN0KFtdKSl9LHR9KG8uUmVjb3JkKHtuYXZTdGFjazpvLkxpc3QoW10pLGRvY3NPcGVuOiExLGRvY3NXaWR0aDpzLmNvbHVtbldpZHRoLGFjdGl2ZVRhYklkeDpudWxsLGtleU1vdmU6ITF9KSk7dC5Eb2NzU2Vzc2lvbj11O3ZhciBjPW8uTWFwKHsiIjpuZXcgdX0pO3QuZGVmYXVsdD1hLmhhbmRsZUFjdGlvbnMoe1NFVF9TVEFDS1M6ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQsaT1uLnNlc3Npb25JZCxvPW4uc3RhY2tzLGE9cihlLGkpO3JldHVybiBhPWEuc2V0KCJuYXZTdGFjayIsbyksZS5zZXQoaSxhKX0sQUREX1NUQUNLOmZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLGk9bi5zZXNzaW9uSWQsYT1uLmZpZWxkLHM9bi54LHU9bi55O2EucGF0aHx8KGEucGF0aD1hLm5hbWUpO3ZhciBjPXIoZSxpKTtyZXR1cm4gYz1jLnVwZGF0ZSgibmF2U3RhY2siLGZ1bmN0aW9uKGUpe3ZhciB0PWU7cmV0dXJuIHM8dC5jb3VudCgpJiYodD10LnNsaWNlKDAscykpLHQucHVzaChvLk1hcCh7eDpzLHk6dSxmaWVsZDphfSkpfSksZS5zZXQoaSxjKX0sVE9HR0xFX0RPQ1M6ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQsaT1uLnNlc3Npb25JZCxvPW4uYWN0aXZlVGFiSWR4LGE9cihlLGkpO3JldHVybiBhPWEuc2V0KCJkb2NzT3BlbiIsIWEuZG9jc09wZW4pLCJudW1iZXIiPT09dHlwZW9mIG8mJihhPWEuc2V0KCJhY3RpdmVUYWJJZHgiLGEuZG9jc09wZW4/bzpudWxsKSksZS5zZXQoaSxhKX0sU0VUX0RPQ1NfVklTSUJMRTpmdW5jdGlvbihlLHQpe3ZhciBuPXQucGF5bG9hZCxpPW4uc2Vzc2lvbklkLG89bi5vcGVuLGE9bi5hY3RpdmVUYWJJZHgscz1yKGUsaSk7cmV0dXJuIHM9cy5zZXQoImRvY3NPcGVuIiwhIW8pLHMuZG9jc09wZW4/Im51bWJlciI9PT10eXBlb2YgYSYmKHM9cy5zZXQoImFjdGl2ZVRhYklkeCIsYSkpOnM9cy5zZXQoImFjdGl2ZVRhYklkeCIsbnVsbCksZS5zZXQoaSxzKX0sQ0hBTkdFX1dJRFRIX0RPQ1M6ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQsaT1uLnNlc3Npb25JZCxvPW4ud2lkdGgsYT1yKGUsaSk7cmV0dXJuIGE9YS5zZXQoImRvY3NXaWR0aCIsbyksZS5zZXQoaSxhKX0sQ0hBTkdFX0tFWV9NT1ZFOmZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLGk9bi5zZXNzaW9uSWQsbz1uLmtleU1vdmUsYT1yKGUsaSk7cmV0dXJuIGE9YS5zZXQoImtleU1vdmUiLG8pLGUuc2V0KGksYSl9fSxjKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHIsaT1uKDIzKTt0LnRvZ2dsZUhpc3RvcnlJdGVtU3RhcnJpbmc9KHI9aS5jcmVhdGVBY3Rpb25zKHtUT0dHTEVfSElTVE9SWV9JVEVNX1NUQVJSSU5HOmZ1bmN0aW9uKGUpe3JldHVybntzZXNzaW9uSWQ6ZX19LEFERF9ISVNUT1JZX0lURU06ZnVuY3Rpb24oZSl7cmV0dXJue3Nlc3Npb246ZX19fSksci50b2dnbGVIaXN0b3J5SXRlbVN0YXJyaW5nKSx0LmFkZEhpc3RvcnlJdGVtPXIuYWRkSGlzdG9yeUl0ZW19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByLGk9bigyMyk7dC5zaGFyZT0ocj1pLmNyZWF0ZUFjdGlvbnMoe1RPR0dMRV9TSEFSRV9ISVNUT1JZOmZ1bmN0aW9uKCl7cmV0dXJue319LFRPR0dMRV9TSEFSRV9IRUFERVJTOmZ1bmN0aW9uKCl7cmV0dXJue319LFRPR0dMRV9TSEFSRV9BTExfVEFCUzpmdW5jdGlvbigpe3JldHVybnt9fSxTSEFSRTpmdW5jdGlvbigpe3JldHVybnt9fSxTRVRfU0hBUkVfVVJMOmZ1bmN0aW9uKGUpe3JldHVybntzaGFyZVVybDplfX19KSxyLnNoYXJlKSx0LnRvZ2dsZVNoYXJlSGlzdG9yeT1yLnRvZ2dsZVNoYXJlSGlzdG9yeSx0LnRvZ2dsZVNoYXJlSGVhZGVycz1yLnRvZ2dsZVNoYXJlSGVhZGVycyx0LnRvZ2dsZVNoYXJlQWxsVGFicz1yLnRvZ2dsZVNoYXJlQWxsVGFicyx0LnNldFNoYXJlVXJsPXIuc2V0U2hhcmVVcmx9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7KGZ1bmN0aW9uKGUpe3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9big1MzcpLHM9big5KSx1PW4oMjcyKSxjPW4oMTYpLGw9big4KSxwPW4oMTIpLGY9bigzNyksZD1uKDEpLGg9big2NSksbT1uZXcgYSxnPWZ1bmN0aW9uKHQpe2Z1bmN0aW9uIGkoZSl7dmFyIG49dC5jYWxsKHRoaXMsZSl8fHRoaXM7cmV0dXJuIG4uc2V0UmVmPWZ1bmN0aW9uKGUpe24ubm9kZT1lfSxuLm9uS2V5VXA9ZnVuY3Rpb24oZSx0KXt2YXIgcj10LmtleUNvZGU7ODYhPT1yJiYocj49NjUmJnI8PTkwfHwhdC5zaGlmdEtleSYmcj49NDgmJnI8PTU3fHx0LnNoaWZ0S2V5JiYxODk9PT1yfHx0LnNoaWZ0S2V5JiY1MD09PXJ8fHQuc2hpZnRLZXkmJjU3PT09cikmJm4uZWRpdG9yLmV4ZWNDb21tYW5kKCJhdXRvY29tcGxldGUiKX0sbi5vbkVkaXQ9ZnVuY3Rpb24oKXshbi5pZ25vcmVDaGFuZ2VFdmVudCYmbi5wcm9wcy5vbkNoYW5nZSYmKG4uY2FjaGVkVmFsdWU9bi5lZGl0b3IuZ2V0VmFsdWUoKSxuLnByb3BzLm9uQ2hhbmdlKG4uY2FjaGVkVmFsdWUpKX0sbi5vbkhhc0NvbXBsZXRpb249ZnVuY3Rpb24oZSx0KXt1LmRlZmF1bHQoZSx0LG4ucHJvcHMub25IaW50SW5mb3JtYXRpb25SZW5kZXIpfSxuLmNsb3NlQ29tcGxldGlvbj1mdW5jdGlvbigpe24uZWRpdG9yLnN0YXRlLmNvbXBsZXRpb25BY3RpdmUmJiJmdW5jdGlvbiI9PT10eXBlb2Ygbi5lZGl0b3Iuc3RhdGUuY29tcGxldGlvbkFjdGl2ZS5jbG9zZSYmbi5lZGl0b3Iuc3RhdGUuY29tcGxldGlvbkFjdGl2ZS5jbG9zZSgpfSxuLmNhY2hlZFZhbHVlPWUudmFsdWV8fCIiLG4ucHJvcHMuZ2V0UmVmJiZuLnByb3BzLmdldFJlZihuKSxufXJldHVybiByKGksdCksaS5wcm90b3R5cGUuY29tcG9uZW50RGlkTW91bnQ9ZnVuY3Rpb24oKXt2YXIgdD10aGlzLHI9bigyKTtuKDEzNyksbigyNzMpLG4oNjkpLG4oMTM4KSxuKDg5KSxuKDcwKSxuKDI3NCksbigzOCksbig5MCksbigzOSksbigxMzkpLG4oOTEpLG4oNTk0KSxuKDU5NSksbig2MDcpLG4oNjA4KSxuKDYxMCksbigyODMpO3ZhciBpPVtdO2kucHVzaCgiQ29kZU1pcnJvci1saW5lbnVtYmVycyIpLGkucHVzaCgiQ29kZU1pcnJvci1mb2xkZ3V0dGVyIiksdGhpcy5lZGl0b3I9cih0aGlzLm5vZGUse2F1dG9mb2N1czohaC5pc0lmcmFtZSgpLHZhbHVlOnRoaXMucHJvcHMudmFsdWV8fCIiLGxpbmVOdW1iZXJzOiEwLHRhYlNpemU6dGhpcy5wcm9wcy50YWJXaWR0aHx8MixpbmRlbnRXaXRoVGFiczp0aGlzLnByb3BzLnVzZVRhYnN8fCExLG1vZGU6ImdyYXBocWwiLHRoZW1lOiJncmFwaGlxbCIsa2V5TWFwOiJzdWJsaW1lIixhdXRvQ2xvc2VCcmFja2V0czohMCxtYXRjaEJyYWNrZXRzOiEwLHNob3dDdXJzb3JXaGVuU2VsZWN0aW5nOiEwLHJlYWRPbmx5OiExLGZvbGRHdXR0ZXI6e21pbkZvbGRTaXplOjR9LGxpbnQ6e3NjaGVtYTp0aGlzLnByb3BzLnNjaGVtYX0saGludE9wdGlvbnM6e3NjaGVtYTp0aGlzLnByb3BzLnNjaGVtYSxjbG9zZU9uVW5mb2N1czohMCxjb21wbGV0ZVNpbmdsZTohMX0saW5mbzp7c2NoZW1hOnRoaXMucHJvcHMuc2NoZW1hLHJlbmRlckRlc2NyaXB0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiBtLnJlbmRlcihlKX0sb25DbGljazp0aGlzLnByb3BzLm9uQ2xpY2tSZWZlcmVuY2V9LGp1bXA6e3NjaGVtYTp0aGlzLnByb3BzLnNjaGVtYSxvbkNsaWNrOnRoaXMucHJvcHMub25DbGlja1JlZmVyZW5jZX0sZ3V0dGVyczppLGV4dHJhS2V5czp7IkNtZC1TcGFjZSI6ZnVuY3Rpb24oKXtyZXR1cm4gdC5lZGl0b3Iuc2hvd0hpbnQoe2NvbXBsZXRlU2luZ2xlOiEwfSl9LCJDdHJsLVNwYWNlIjpmdW5jdGlvbigpe3JldHVybiB0LmVkaXRvci5zaG93SGludCh7Y29tcGxldGVTaW5nbGU6ITB9KX0sIkFsdC1TcGFjZSI6ZnVuY3Rpb24oKXtyZXR1cm4gdC5lZGl0b3Iuc2hvd0hpbnQoe2NvbXBsZXRlU2luZ2xlOiEwfSl9LCJTaGlmdC1TcGFjZSI6ZnVuY3Rpb24oKXtyZXR1cm4gdC5lZGl0b3Iuc2hvd0hpbnQoe2NvbXBsZXRlU2luZ2xlOiEwfSl9LCJDbWQtRW50ZXIiOmZ1bmN0aW9uKCl7dC5wcm9wcy5vblJ1blF1ZXJ5JiZ0LnByb3BzLm9uUnVuUXVlcnkoKX0sIkN0cmwtRW50ZXIiOmZ1bmN0aW9uKCl7dC5wcm9wcy5vblJ1blF1ZXJ5JiZ0LnByb3BzLm9uUnVuUXVlcnkoKX0sIkN0cmwtTGVmdCI6ImdvU3Vid29yZExlZnQiLCJDdHJsLVJpZ2h0IjoiZ29TdWJ3b3JkUmlnaHQiLCJBbHQtTGVmdCI6ImdvR3JvdXBMZWZ0IiwiQWx0LVJpZ2h0IjoiZ29Hcm91cFJpZ2h0IiwiQ21kLUYiOiJmaW5kUGVyc2lzdGVudCIsIkN0cmwtRiI6ImZpbmRQZXJzaXN0ZW50In19KSx0aGlzLmVkaXRvci5vbigiY2hhbmdlIix0aGlzLm9uRWRpdCksdGhpcy5lZGl0b3Iub24oImtleXVwIix0aGlzLm9uS2V5VXApLHRoaXMuZWRpdG9yLm9uKCJoYXNDb21wbGV0aW9uIix0aGlzLm9uSGFzQ29tcGxldGlvbiksZS5lZGl0b3I9dGhpcy5lZGl0b3IsdGhpcy5wcm9wcy5zY3JvbGxUb3AmJnRoaXMuc2Nyb2xsVG8odGhpcy5wcm9wcy5zY3JvbGxUb3ApfSxpLnByb3RvdHlwZS5jb21wb25lbnREaWRVcGRhdGU9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcyxyPW4oMik7dGhpcy5pZ25vcmVDaGFuZ2VFdmVudD0hMCx0aGlzLnByb3BzLnNjaGVtYSE9PWUuc2NoZW1hJiYodGhpcy5lZGl0b3Iub3B0aW9ucy5saW50LnNjaGVtYT10aGlzLnByb3BzLnNjaGVtYSx0aGlzLmVkaXRvci5vcHRpb25zLmhpbnRPcHRpb25zLnNjaGVtYT10aGlzLnByb3BzLnNjaGVtYSx0aGlzLmVkaXRvci5vcHRpb25zLmluZm8uc2NoZW1hPXRoaXMucHJvcHMuc2NoZW1hLHRoaXMuZWRpdG9yLm9wdGlvbnMuanVtcC5zY2hlbWE9dGhpcy5wcm9wcy5zY2hlbWEsci5zaWduYWwodGhpcy5lZGl0b3IsImNoYW5nZSIsdGhpcy5lZGl0b3IpKSx0aGlzLnByb3BzLnZhbHVlIT09ZS52YWx1ZSYmdGhpcy5wcm9wcy52YWx1ZSE9PXRoaXMuY2FjaGVkVmFsdWUmJih0aGlzLmNhY2hlZFZhbHVlPXRoaXMucHJvcHMudmFsdWUsdGhpcy5lZGl0b3Iuc2V0VmFsdWUodGhpcy5wcm9wcy52YWx1ZSkpLHRoaXMuaWdub3JlQ2hhbmdlRXZlbnQ9ITEsc2V0VGltZW91dChmdW5jdGlvbigpe3QucHJvcHMuc2Vzc2lvbklkIT09ZS5zZXNzaW9uSWQmJnQucHJvcHMuc2Nyb2xsVG9wJiZ0LnNjcm9sbFRvKHQucHJvcHMuc2Nyb2xsVG9wKX0pfSxpLnByb3RvdHlwZS5jb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzPWZ1bmN0aW9uKGUpe3RoaXMucHJvcHMuc2Vzc2lvbklkIT09ZS5zZXNzaW9uSWQmJih0aGlzLmNsb3NlQ29tcGxldGlvbigpLHRoaXMudXBkYXRlU2Vzc2lvblNjcm9sbFRvcCgpLGguaXNJZnJhbWUoKXx8dGhpcy5lZGl0b3IuZm9jdXMoKSl9LGkucHJvdG90eXBlLnNjcm9sbFRvPWZ1bmN0aW9uKGUpe3RoaXMubm9kZS5xdWVyeVNlbGVjdG9yKCIuQ29kZU1pcnJvci1zY3JvbGwiKS5zY3JvbGxUb3A9ZX0saS5wcm90b3R5cGUudXBkYXRlU2Vzc2lvblNjcm9sbFRvcD1mdW5jdGlvbigpe3RoaXMucHJvcHMuc2V0U2Nyb2xsVG9wJiZ0aGlzLnByb3BzLnNlc3Npb25JZCYmdGhpcy5wcm9wcy5zZXRTY3JvbGxUb3AodGhpcy5wcm9wcy5zZXNzaW9uSWQsdGhpcy5ub2RlLnF1ZXJ5U2VsZWN0b3IoIi5Db2RlTWlycm9yLXNjcm9sbCIpLnNjcm9sbFRvcCl9LGkucHJvdG90eXBlLmNvbXBvbmVudFdpbGxVbm1vdW50PWZ1bmN0aW9uKCl7dGhpcy51cGRhdGVTZXNzaW9uU2Nyb2xsVG9wKCksdGhpcy5lZGl0b3Iub2ZmKCJjaGFuZ2UiLHRoaXMub25FZGl0KSx0aGlzLmVkaXRvci5vZmYoImtleXVwIix0aGlzLm9uS2V5VXApLHRoaXMuZWRpdG9yLm9mZigiaGFzQ29tcGxldGlvbiIsdGhpcy5vbkhhc0NvbXBsZXRpb24pLHRoaXMuZWRpdG9yPW51bGx9LGkucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoZi5kZWZhdWx0LG51bGwsby5jcmVhdGVFbGVtZW50KGIse3JlZjp0aGlzLnNldFJlZn0pKX0saS5wcm90b3R5cGUuZ2V0Q29kZU1pcnJvcj1mdW5jdGlvbigpe3JldHVybiB0aGlzLmVkaXRvcn0saS5wcm90b3R5cGUuZ2V0Q2xpZW50SGVpZ2h0PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubm9kZSYmdGhpcy5ub2RlLmNsaWVudEhlaWdodH0saX0oby5QdXJlQ29tcG9uZW50KTt0LlF1ZXJ5RWRpdG9yPWc7dmFyIHk9bC5jcmVhdGVTdHJ1Y3R1cmVkU2VsZWN0b3Ioe3ZhbHVlOnAuZ2V0UXVlcnksc2Vzc2lvbklkOnAuZ2V0U2VsZWN0ZWRTZXNzaW9uSWRGcm9tUm9vdCxzY3JvbGxUb3A6cC5nZXRTY3JvbGxUb3AsdGFiV2lkdGg6cC5nZXRUYWJXaWR0aCx1c2VUYWJzOnAuZ2V0VXNlVGFic30pO3QuZGVmYXVsdD1zLmNvbm5lY3QoeSx7b25DaGFuZ2U6Yy5lZGl0UXVlcnksc2V0U2Nyb2xsVG9wOmMuc2V0U2Nyb2xsVG9wfSkoZyk7dmFyIHYsYj1kLnN0eWxlZC5kaXYodnx8KHY9aShbIlxuICBmbGV4OiAxIDEgMCU7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcblxuICAuQ29kZU1pcnJvciB7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4iXSxbIlxuICBmbGV4OiAxIDEgMCU7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcblxuICAuQ29kZU1pcnJvciB7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuZWRpdG9yQmFja2dyb3VuZH0pfSkuY2FsbCh0LG4oMTEpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKCl7dGhpcy5fX3J1bGVzX189W10sdGhpcy5fX2NhY2hlX189bnVsbH1yLnByb3RvdHlwZS5fX2ZpbmRfXz1mdW5jdGlvbihlKXtmb3IodmFyIHQ9MDt0PHRoaXMuX19ydWxlc19fLmxlbmd0aDt0KyspaWYodGhpcy5fX3J1bGVzX19bdF0ubmFtZT09PWUpcmV0dXJuIHQ7cmV0dXJuLTF9LHIucHJvdG90eXBlLl9fY29tcGlsZV9fPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcyx0PVsiIl07ZS5fX3J1bGVzX18uZm9yRWFjaChmdW5jdGlvbihlKXtlLmVuYWJsZWQmJmUuYWx0LmZvckVhY2goZnVuY3Rpb24oZSl7dC5pbmRleE9mKGUpPDAmJnQucHVzaChlKX0pfSksZS5fX2NhY2hlX189e30sdC5mb3JFYWNoKGZ1bmN0aW9uKHQpe2UuX19jYWNoZV9fW3RdPVtdLGUuX19ydWxlc19fLmZvckVhY2goZnVuY3Rpb24obil7bi5lbmFibGVkJiYodCYmbi5hbHQuaW5kZXhPZih0KTwwfHxlLl9fY2FjaGVfX1t0XS5wdXNoKG4uZm4pKX0pfSl9LHIucHJvdG90eXBlLmF0PWZ1bmN0aW9uKGUsdCxuKXt2YXIgcj10aGlzLl9fZmluZF9fKGUpLGk9bnx8e307aWYoLTE9PT1yKXRocm93IG5ldyBFcnJvcigiUGFyc2VyIHJ1bGUgbm90IGZvdW5kOiAiK2UpO3RoaXMuX19ydWxlc19fW3JdLmZuPXQsdGhpcy5fX3J1bGVzX19bcl0uYWx0PWkuYWx0fHxbXSx0aGlzLl9fY2FjaGVfXz1udWxsfSxyLnByb3RvdHlwZS5iZWZvcmU9ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9dGhpcy5fX2ZpbmRfXyhlKSxvPXJ8fHt9O2lmKC0xPT09aSl0aHJvdyBuZXcgRXJyb3IoIlBhcnNlciBydWxlIG5vdCBmb3VuZDogIitlKTt0aGlzLl9fcnVsZXNfXy5zcGxpY2UoaSwwLHtuYW1lOnQsZW5hYmxlZDohMCxmbjpuLGFsdDpvLmFsdHx8W119KSx0aGlzLl9fY2FjaGVfXz1udWxsfSxyLnByb3RvdHlwZS5hZnRlcj1mdW5jdGlvbihlLHQsbixyKXt2YXIgaT10aGlzLl9fZmluZF9fKGUpLG89cnx8e307aWYoLTE9PT1pKXRocm93IG5ldyBFcnJvcigiUGFyc2VyIHJ1bGUgbm90IGZvdW5kOiAiK2UpO3RoaXMuX19ydWxlc19fLnNwbGljZShpKzEsMCx7bmFtZTp0LGVuYWJsZWQ6ITAsZm46bixhbHQ6by5hbHR8fFtdfSksdGhpcy5fX2NhY2hlX189bnVsbH0sci5wcm90b3R5cGUucHVzaD1mdW5jdGlvbihlLHQsbil7dmFyIHI9bnx8e307dGhpcy5fX3J1bGVzX18ucHVzaCh7bmFtZTplLGVuYWJsZWQ6ITAsZm46dCxhbHQ6ci5hbHR8fFtdfSksdGhpcy5fX2NhY2hlX189bnVsbH0sci5wcm90b3R5cGUuZW5hYmxlPWZ1bmN0aW9uKGUsdCl7QXJyYXkuaXNBcnJheShlKXx8KGU9W2VdKTt2YXIgbj1bXTtyZXR1cm4gZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciByPXRoaXMuX19maW5kX18oZSk7aWYocjwwKXtpZih0KXJldHVybjt0aHJvdyBuZXcgRXJyb3IoIlJ1bGVzIG1hbmFnZXI6IGludmFsaWQgcnVsZSBuYW1lICIrZSl9dGhpcy5fX3J1bGVzX19bcl0uZW5hYmxlZD0hMCxuLnB1c2goZSl9LHRoaXMpLHRoaXMuX19jYWNoZV9fPW51bGwsbn0sci5wcm90b3R5cGUuZW5hYmxlT25seT1mdW5jdGlvbihlLHQpe0FycmF5LmlzQXJyYXkoZSl8fChlPVtlXSksdGhpcy5fX3J1bGVzX18uZm9yRWFjaChmdW5jdGlvbihlKXtlLmVuYWJsZWQ9ITF9KSx0aGlzLmVuYWJsZShlLHQpfSxyLnByb3RvdHlwZS5kaXNhYmxlPWZ1bmN0aW9uKGUsdCl7QXJyYXkuaXNBcnJheShlKXx8KGU9W2VdKTt2YXIgbj1bXTtyZXR1cm4gZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciByPXRoaXMuX19maW5kX18oZSk7aWYocjwwKXtpZih0KXJldHVybjt0aHJvdyBuZXcgRXJyb3IoIlJ1bGVzIG1hbmFnZXI6IGludmFsaWQgcnVsZSBuYW1lICIrZSl9dGhpcy5fX3J1bGVzX19bcl0uZW5hYmxlZD0hMSxuLnB1c2goZSl9LHRoaXMpLHRoaXMuX19jYWNoZV9fPW51bGwsbn0sci5wcm90b3R5cGUuZ2V0UnVsZXM9ZnVuY3Rpb24oZSl7cmV0dXJuIG51bGw9PT10aGlzLl9fY2FjaGVfXyYmdGhpcy5fX2NvbXBpbGVfXygpLHRoaXMuX19jYWNoZV9fW2VdfHxbXX0sZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7dGhpcy50eXBlPWUsdGhpcy50YWc9dCx0aGlzLmF0dHJzPW51bGwsdGhpcy5tYXA9bnVsbCx0aGlzLm5lc3Rpbmc9bix0aGlzLmxldmVsPTAsdGhpcy5jaGlsZHJlbj1udWxsLHRoaXMuY29udGVudD0iIix0aGlzLm1hcmt1cD0iIix0aGlzLmluZm89IiIsdGhpcy5tZXRhPW51bGwsdGhpcy5ibG9jaz0hMSx0aGlzLmhpZGRlbj0hMX1yLnByb3RvdHlwZS5hdHRySW5kZXg9ZnVuY3Rpb24oZSl7dmFyIHQsbixyO2lmKCF0aGlzLmF0dHJzKXJldHVybi0xO2Zvcih0PXRoaXMuYXR0cnMsbj0wLHI9dC5sZW5ndGg7bjxyO24rKylpZih0W25dWzBdPT09ZSlyZXR1cm4gbjtyZXR1cm4tMX0sci5wcm90b3R5cGUuYXR0clB1c2g9ZnVuY3Rpb24oZSl7dGhpcy5hdHRycz90aGlzLmF0dHJzLnB1c2goZSk6dGhpcy5hdHRycz1bZV19LHIucHJvdG90eXBlLmF0dHJTZXQ9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLmF0dHJJbmRleChlKSxyPVtlLHRdO248MD90aGlzLmF0dHJQdXNoKHIpOnRoaXMuYXR0cnNbbl09cn0sci5wcm90b3R5cGUuYXR0ckdldD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLmF0dHJJbmRleChlKSxuPW51bGw7cmV0dXJuIHQ+PTAmJihuPXRoaXMuYXR0cnNbdF1bMV0pLG59LHIucHJvdG90eXBlLmF0dHJKb2luPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5hdHRySW5kZXgoZSk7bjwwP3RoaXMuYXR0clB1c2goW2UsdF0pOnRoaXMuYXR0cnNbbl1bMV09dGhpcy5hdHRyc1tuXVsxXSsiICIrdH0sZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCl7ZS5leHBvcnRzPS9bIS0jJS1cKiwtXC86O1w/QFxbLVxdX1x7XH1ceEExXHhBN1x4QUJceEI2XHhCN1x4QkJceEJGXHUwMzdFXHUwMzg3XHUwNTVBLVx1MDU1Rlx1MDU4OVx1MDU4QVx1MDVCRVx1MDVDMFx1MDVDM1x1MDVDNlx1MDVGM1x1MDVGNFx1MDYwOVx1MDYwQVx1MDYwQ1x1MDYwRFx1MDYxQlx1MDYxRVx1MDYxRlx1MDY2QS1cdTA2NkRcdTA2RDRcdTA3MDAtXHUwNzBEXHUwN0Y3LVx1MDdGOVx1MDgzMC1cdTA4M0VcdTA4NUVcdTA5NjRcdTA5NjVcdTA5NzBcdTBBRjBcdTBERjRcdTBFNEZcdTBFNUFcdTBFNUJcdTBGMDQtXHUwRjEyXHUwRjE0XHUwRjNBLVx1MEYzRFx1MEY4NVx1MEZEMC1cdTBGRDRcdTBGRDlcdTBGREFcdTEwNEEtXHUxMDRGXHUxMEZCXHUxMzYwLVx1MTM2OFx1MTQwMFx1MTY2RFx1MTY2RVx1MTY5Qlx1MTY5Q1x1MTZFQi1cdTE2RURcdTE3MzVcdTE3MzZcdTE3RDQtXHUxN0Q2XHUxN0Q4LVx1MTdEQVx1MTgwMC1cdTE4MEFcdTE5NDRcdTE5NDVcdTFBMUVcdTFBMUZcdTFBQTAtXHUxQUE2XHUxQUE4LVx1MUFBRFx1MUI1QS1cdTFCNjBcdTFCRkMtXHUxQkZGXHUxQzNCLVx1MUMzRlx1MUM3RVx1MUM3Rlx1MUNDMC1cdTFDQzdcdTFDRDNcdTIwMTAtXHUyMDI3XHUyMDMwLVx1MjA0M1x1MjA0NS1cdTIwNTFcdTIwNTMtXHUyMDVFXHUyMDdEXHUyMDdFXHUyMDhEXHUyMDhFXHUyMzA4LVx1MjMwQlx1MjMyOVx1MjMyQVx1Mjc2OC1cdTI3NzVcdTI3QzVcdTI3QzZcdTI3RTYtXHUyN0VGXHUyOTgzLVx1Mjk5OFx1MjlEOC1cdTI5REJcdTI5RkNcdTI5RkRcdTJDRjktXHUyQ0ZDXHUyQ0ZFXHUyQ0ZGXHUyRDcwXHUyRTAwLVx1MkUyRVx1MkUzMC1cdTJFNDRcdTMwMDEtXHUzMDAzXHUzMDA4LVx1MzAxMVx1MzAxNC1cdTMwMUZcdTMwMzBcdTMwM0RcdTMwQTBcdTMwRkJcdUE0RkVcdUE0RkZcdUE2MEQtXHVBNjBGXHVBNjczXHVBNjdFXHVBNkYyLVx1QTZGN1x1QTg3NC1cdUE4NzdcdUE4Q0VcdUE4Q0ZcdUE4RjgtXHVBOEZBXHVBOEZDXHVBOTJFXHVBOTJGXHVBOTVGXHVBOUMxLVx1QTlDRFx1QTlERVx1QTlERlx1QUE1Qy1cdUFBNUZcdUFBREVcdUFBREZcdUFBRjBcdUFBRjFcdUFCRUJcdUZEM0VcdUZEM0ZcdUZFMTAtXHVGRTE5XHVGRTMwLVx1RkU1Mlx1RkU1NC1cdUZFNjFcdUZFNjNcdUZFNjhcdUZFNkFcdUZFNkJcdUZGMDEtXHVGRjAzXHVGRjA1LVx1RkYwQVx1RkYwQy1cdUZGMEZcdUZGMUFcdUZGMUJcdUZGMUZcdUZGMjBcdUZGM0ItXHVGRjNEXHVGRjNGXHVGRjVCXHVGRjVEXHVGRjVGLVx1RkY2NV18XHVEODAwW1x1REQwMC1cdUREMDJcdURGOUZcdURGRDBdfFx1RDgwMVx1REQ2RnxcdUQ4MDJbXHVEQzU3XHVERDFGXHVERDNGXHVERTUwLVx1REU1OFx1REU3Rlx1REVGMC1cdURFRjZcdURGMzktXHVERjNGXHVERjk5LVx1REY5Q118XHVEODA0W1x1REM0Ny1cdURDNERcdURDQkJcdURDQkNcdURDQkUtXHVEQ0MxXHVERDQwLVx1REQ0M1x1REQ3NFx1REQ3NVx1RERDNS1cdUREQzlcdUREQ0RcdUREREJcdUREREQtXHVERERGXHVERTM4LVx1REUzRFx1REVBOV18XHVEODA1W1x1REM0Qi1cdURDNEZcdURDNUJcdURDNURcdURDQzZcdUREQzEtXHVEREQ3XHVERTQxLVx1REU0M1x1REU2MC1cdURFNkNcdURGM0MtXHVERjNFXXxcdUQ4MDdbXHVEQzQxLVx1REM0NVx1REM3MFx1REM3MV18XHVEODA5W1x1REM3MC1cdURDNzRdfFx1RDgxQVtcdURFNkVcdURFNkZcdURFRjVcdURGMzctXHVERjNCXHVERjQ0XXxcdUQ4MkZcdURDOUZ8XHVEODM2W1x1REU4Ny1cdURFOEJdfFx1RDgzQVtcdURENUVcdURENUZdL30sZnVuY3Rpb24oZSx0LG4peyFmdW5jdGlvbihlKXtlKG4oMikpfShmdW5jdGlvbihlKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gdChlLHQpe3RoaXMuY209ZSx0aGlzLm9wdGlvbnM9dCx0aGlzLndpZGdldD1udWxsLHRoaXMuZGVib3VuY2U9MCx0aGlzLnRpY2s9MCx0aGlzLnN0YXJ0UG9zPXRoaXMuY20uZ2V0Q3Vyc29yKCJzdGFydCIpLHRoaXMuc3RhcnRMZW49dGhpcy5jbS5nZXRMaW5lKHRoaXMuc3RhcnRQb3MubGluZSkubGVuZ3RoLXRoaXMuY20uZ2V0U2VsZWN0aW9uKCkubGVuZ3RoO3ZhciBuPXRoaXM7ZS5vbigiY3Vyc29yQWN0aXZpdHkiLHRoaXMuYWN0aXZpdHlGdW5jPWZ1bmN0aW9uKCl7bi5jdXJzb3JBY3Rpdml0eSgpfSl9ZnVuY3Rpb24gbihlLHQsbil7dmFyIHI9ZS5vcHRpb25zLmhpbnRPcHRpb25zLGk9e307Zm9yKHZhciBvIGluIGgpaVtvXT1oW29dO2lmKHIpZm9yKHZhciBvIGluIHIpdm9pZCAwIT09cltvXSYmKGlbb109cltvXSk7aWYobilmb3IodmFyIG8gaW4gbil2b2lkIDAhPT1uW29dJiYoaVtvXT1uW29dKTtyZXR1cm4gaS5oaW50LnJlc29sdmUmJihpLmhpbnQ9aS5oaW50LnJlc29sdmUoZSx0KSksaX1mdW5jdGlvbiByKGUpe3JldHVybiJzdHJpbmciPT10eXBlb2YgZT9lOmUudGV4dH1mdW5jdGlvbiBpKGUsdCl7ZnVuY3Rpb24gbihlLG4pe3ZhciBpO2k9InN0cmluZyIhPXR5cGVvZiBuP2Z1bmN0aW9uKGUpe3JldHVybiBuKGUsdCl9OnIuaGFzT3duUHJvcGVydHkobik/cltuXTpuLG9bZV09aX12YXIgcj17VXA6ZnVuY3Rpb24oKXt0Lm1vdmVGb2N1cygtMSl9LERvd246ZnVuY3Rpb24oKXt0Lm1vdmVGb2N1cygxKX0sUGFnZVVwOmZ1bmN0aW9uKCl7dC5tb3ZlRm9jdXMoMS10Lm1lbnVTaXplKCksITApfSxQYWdlRG93bjpmdW5jdGlvbigpe3QubW92ZUZvY3VzKHQubWVudVNpemUoKS0xLCEwKX0sSG9tZTpmdW5jdGlvbigpe3Quc2V0Rm9jdXMoMCl9LEVuZDpmdW5jdGlvbigpe3Quc2V0Rm9jdXModC5sZW5ndGgtMSl9LEVudGVyOnQucGljayxUYWI6dC5waWNrLEVzYzp0LmNsb3NlfSxpPWUub3B0aW9ucy5jdXN0b21LZXlzLG89aT97fTpyO2lmKGkpZm9yKHZhciBhIGluIGkpaS5oYXNPd25Qcm9wZXJ0eShhKSYmbihhLGlbYV0pO3ZhciBzPWUub3B0aW9ucy5leHRyYUtleXM7aWYocylmb3IodmFyIGEgaW4gcylzLmhhc093blByb3BlcnR5KGEpJiZuKGEsc1thXSk7cmV0dXJuIG99ZnVuY3Rpb24gbyhlLHQpe2Zvcig7dCYmdCE9ZTspe2lmKCJMSSI9PT10Lm5vZGVOYW1lLnRvVXBwZXJDYXNlKCkmJnQucGFyZW50Tm9kZT09ZSlyZXR1cm4gdDt0PXQucGFyZW50Tm9kZX19ZnVuY3Rpb24gYSh0LG4pe3RoaXMuY29tcGxldGlvbj10LHRoaXMuZGF0YT1uLHRoaXMucGlja2VkPSExO3ZhciBhPXRoaXMscz10LmNtLHU9dGhpcy5oaW50cz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJ1bCIpO3UuY2xhc3NOYW1lPSJDb2RlTWlycm9yLWhpbnRzIix0aGlzLnNlbGVjdGVkSGludD1uLnNlbGVjdGVkSGludHx8MDtmb3IodmFyIGM9bi5saXN0LGY9MDtmPGMubGVuZ3RoOysrZil7dmFyIGQ9dS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVFbGVtZW50KCJsaSIpKSxoPWNbZl0sbT1sKyhmIT10aGlzLnNlbGVjdGVkSGludD8iIjoiICIrcCk7bnVsbCE9aC5jbGFzc05hbWUmJihtPWguY2xhc3NOYW1lKyIgIittKSxkLmNsYXNzTmFtZT1tLGgucmVuZGVyP2gucmVuZGVyKGQsbixoKTpkLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGguZGlzcGxheVRleHR8fHIoaCkpKSxkLmhpbnRJZD1mfXZhciBnPXMuY3Vyc29yQ29vcmRzKHQub3B0aW9ucy5hbGlnbldpdGhXb3JkP24uZnJvbTpudWxsKSx5PWcubGVmdCx2PWcuYm90dG9tLGI9ITA7dS5zdHlsZS5sZWZ0PXkrInB4Iix1LnN0eWxlLnRvcD12KyJweCI7dmFyIHg9d2luZG93LmlubmVyV2lkdGh8fE1hdGgubWF4KGRvY3VtZW50LmJvZHkub2Zmc2V0V2lkdGgsZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50Lm9mZnNldFdpZHRoKSxDPXdpbmRvdy5pbm5lckhlaWdodHx8TWF0aC5tYXgoZG9jdW1lbnQuYm9keS5vZmZzZXRIZWlnaHQsZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50Lm9mZnNldEhlaWdodCk7KHQub3B0aW9ucy5jb250YWluZXJ8fGRvY3VtZW50LmJvZHkpLmFwcGVuZENoaWxkKHUpO3ZhciBFPXUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksRD1FLmJvdHRvbS1DLHc9dS5zY3JvbGxIZWlnaHQ+dS5jbGllbnRIZWlnaHQrMSxTPXMuZ2V0U2Nyb2xsSW5mbygpO2lmKEQ+MCl7dmFyIGs9RS5ib3R0b20tRS50b3A7aWYoZy50b3AtKGcuYm90dG9tLUUudG9wKS1rPjApdS5zdHlsZS50b3A9KHY9Zy50b3AtaykrInB4IixiPSExO2Vsc2UgaWYoaz5DKXt1LnN0eWxlLmhlaWdodD1DLTUrInB4Iix1LnN0eWxlLnRvcD0odj1nLmJvdHRvbS1FLnRvcCkrInB4Ijt2YXIgQT1zLmdldEN1cnNvcigpO24uZnJvbS5jaCE9QS5jaCYmKGc9cy5jdXJzb3JDb29yZHMoQSksdS5zdHlsZS5sZWZ0PSh5PWcubGVmdCkrInB4IixFPXUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkpfX12YXIgXz1FLnJpZ2h0LXg7aWYoXz4wJiYoRS5yaWdodC1FLmxlZnQ+eCYmKHUuc3R5bGUud2lkdGg9eC01KyJweCIsXy09RS5yaWdodC1FLmxlZnQteCksdS5zdHlsZS5sZWZ0PSh5PWcubGVmdC1fKSsicHgiKSx3KWZvcih2YXIgVD11LmZpcnN0Q2hpbGQ7VDtUPVQubmV4dFNpYmxpbmcpVC5zdHlsZS5wYWRkaW5nUmlnaHQ9cy5kaXNwbGF5Lm5hdGl2ZUJhcldpZHRoKyJweCI7aWYocy5hZGRLZXlNYXAodGhpcy5rZXlNYXA9aSh0LHttb3ZlRm9jdXM6ZnVuY3Rpb24oZSx0KXthLmNoYW5nZUFjdGl2ZShhLnNlbGVjdGVkSGludCtlLHQpfSxzZXRGb2N1czpmdW5jdGlvbihlKXthLmNoYW5nZUFjdGl2ZShlKX0sbWVudVNpemU6ZnVuY3Rpb24oKXtyZXR1cm4gYS5zY3JlZW5BbW91bnQoKX0sbGVuZ3RoOmMubGVuZ3RoLGNsb3NlOmZ1bmN0aW9uKCl7dC5jbG9zZSgpfSxwaWNrOmZ1bmN0aW9uKCl7YS5waWNrKCl9LGRhdGE6bn0pKSx0Lm9wdGlvbnMuY2xvc2VPblVuZm9jdXMpe3ZhciBPO3Mub24oImJsdXIiLHRoaXMub25CbHVyPWZ1bmN0aW9uKCl7Tz1zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dC5jbG9zZSgpfSwxMDApfSkscy5vbigiZm9jdXMiLHRoaXMub25Gb2N1cz1mdW5jdGlvbigpe2NsZWFyVGltZW91dChPKX0pfXJldHVybiBzLm9uKCJzY3JvbGwiLHRoaXMub25TY3JvbGw9ZnVuY3Rpb24oKXt2YXIgZT1zLmdldFNjcm9sbEluZm8oKSxuPXMuZ2V0V3JhcHBlckVsZW1lbnQoKS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSxyPXYrUy50b3AtZS50b3AsaT1yLSh3aW5kb3cucGFnZVlPZmZzZXR8fChkb2N1bWVudC5kb2N1bWVudEVsZW1lbnR8fGRvY3VtZW50LmJvZHkpLnNjcm9sbFRvcCk7aWYoYnx8KGkrPXUub2Zmc2V0SGVpZ2h0KSxpPD1uLnRvcHx8aT49bi5ib3R0b20pcmV0dXJuIHQuY2xvc2UoKTt1LnN0eWxlLnRvcD1yKyJweCIsdS5zdHlsZS5sZWZ0PXkrUy5sZWZ0LWUubGVmdCsicHgifSksZS5vbih1LCJkYmxjbGljayIsZnVuY3Rpb24oZSl7dmFyIHQ9byh1LGUudGFyZ2V0fHxlLnNyY0VsZW1lbnQpO3QmJm51bGwhPXQuaGludElkJiYoYS5jaGFuZ2VBY3RpdmUodC5oaW50SWQpLGEucGljaygpKX0pLGUub24odSwiY2xpY2siLGZ1bmN0aW9uKGUpe3ZhciBuPW8odSxlLnRhcmdldHx8ZS5zcmNFbGVtZW50KTtuJiZudWxsIT1uLmhpbnRJZCYmKGEuY2hhbmdlQWN0aXZlKG4uaGludElkKSx0Lm9wdGlvbnMuY29tcGxldGVPblNpbmdsZUNsaWNrJiZhLnBpY2soKSl9KSxlLm9uKHUsIm1vdXNlZG93biIsZnVuY3Rpb24oKXtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cy5mb2N1cygpfSwyMCl9KSxlLnNpZ25hbChuLCJzZWxlY3QiLGNbdGhpcy5zZWxlY3RlZEhpbnRdLHUuY2hpbGROb2Rlc1t0aGlzLnNlbGVjdGVkSGludF0pLCEwfWZ1bmN0aW9uIHMoZSx0KXtpZighZS5zb21ldGhpbmdTZWxlY3RlZCgpKXJldHVybiB0O2Zvcih2YXIgbj1bXSxyPTA7cjx0Lmxlbmd0aDtyKyspdFtyXS5zdXBwb3J0c1NlbGVjdGlvbiYmbi5wdXNoKHRbcl0pO3JldHVybiBufWZ1bmN0aW9uIHUoZSx0LG4scil7aWYoZS5hc3luYyllKHQscixuKTtlbHNle3ZhciBpPWUodCxuKTtpJiZpLnRoZW4/aS50aGVuKHIpOnIoaSl9fWZ1bmN0aW9uIGModCxuKXt2YXIgcixpPXQuZ2V0SGVscGVycyhuLCJoaW50Iik7aWYoaS5sZW5ndGgpe3ZhciBvPWZ1bmN0aW9uKGUsdCxuKXtmdW5jdGlvbiByKGkpe2lmKGk9PW8ubGVuZ3RoKXJldHVybiB0KG51bGwpO3Uob1tpXSxlLG4sZnVuY3Rpb24oZSl7ZSYmZS5saXN0Lmxlbmd0aD4wP3QoZSk6cihpKzEpfSl9dmFyIG89cyhlLGkpO3IoMCl9O3JldHVybiBvLmFzeW5jPSEwLG8uc3VwcG9ydHNTZWxlY3Rpb249ITAsb31yZXR1cm4ocj10LmdldEhlbHBlcih0LmdldEN1cnNvcigpLCJoaW50V29yZHMiKSk/ZnVuY3Rpb24odCl7cmV0dXJuIGUuaGludC5mcm9tTGlzdCh0LHt3b3JkczpyfSl9OmUuaGludC5hbnl3b3JkP2Z1bmN0aW9uKHQsbil7cmV0dXJuIGUuaGludC5hbnl3b3JkKHQsbil9OmZ1bmN0aW9uKCl7fX12YXIgbD0iQ29kZU1pcnJvci1oaW50IixwPSJDb2RlTWlycm9yLWhpbnQtYWN0aXZlIjtlLnNob3dIaW50PWZ1bmN0aW9uKGUsdCxuKXtpZighdClyZXR1cm4gZS5zaG93SGludChuKTtuJiZuLmFzeW5jJiYodC5hc3luYz0hMCk7dmFyIHI9e2hpbnQ6dH07aWYobilmb3IodmFyIGkgaW4gbilyW2ldPW5baV07cmV0dXJuIGUuc2hvd0hpbnQocil9LGUuZGVmaW5lRXh0ZW5zaW9uKCJzaG93SGludCIsZnVuY3Rpb24ocil7cj1uKHRoaXMsdGhpcy5nZXRDdXJzb3IoInN0YXJ0Iikscik7dmFyIGk9dGhpcy5saXN0U2VsZWN0aW9ucygpO2lmKCEoaS5sZW5ndGg+MSkpe2lmKHRoaXMuc29tZXRoaW5nU2VsZWN0ZWQoKSl7aWYoIXIuaGludC5zdXBwb3J0c1NlbGVjdGlvbilyZXR1cm47Zm9yKHZhciBvPTA7bzxpLmxlbmd0aDtvKyspaWYoaVtvXS5oZWFkLmxpbmUhPWlbb10uYW5jaG9yLmxpbmUpcmV0dXJufXRoaXMuc3RhdGUuY29tcGxldGlvbkFjdGl2ZSYmdGhpcy5zdGF0ZS5jb21wbGV0aW9uQWN0aXZlLmNsb3NlKCk7dmFyIGE9dGhpcy5zdGF0ZS5jb21wbGV0aW9uQWN0aXZlPW5ldyB0KHRoaXMscik7YS5vcHRpb25zLmhpbnQmJihlLnNpZ25hbCh0aGlzLCJzdGFydENvbXBsZXRpb24iLHRoaXMpLGEudXBkYXRlKCEwKSl9fSk7dmFyIGY9d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZXx8ZnVuY3Rpb24oZSl7cmV0dXJuIHNldFRpbWVvdXQoZSwxZTMvNjApfSxkPXdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZXx8Y2xlYXJUaW1lb3V0O3QucHJvdG90eXBlPXtjbG9zZTpmdW5jdGlvbigpe3RoaXMuYWN0aXZlKCkmJih0aGlzLmNtLnN0YXRlLmNvbXBsZXRpb25BY3RpdmU9bnVsbCx0aGlzLnRpY2s9bnVsbCx0aGlzLmNtLm9mZigiY3Vyc29yQWN0aXZpdHkiLHRoaXMuYWN0aXZpdHlGdW5jKSx0aGlzLndpZGdldCYmdGhpcy5kYXRhJiZlLnNpZ25hbCh0aGlzLmRhdGEsImNsb3NlIiksdGhpcy53aWRnZXQmJnRoaXMud2lkZ2V0LmNsb3NlKCksZS5zaWduYWwodGhpcy5jbSwiZW5kQ29tcGxldGlvbiIsdGhpcy5jbSkpfSxhY3RpdmU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5jbS5zdGF0ZS5jb21wbGV0aW9uQWN0aXZlPT10aGlzfSxwaWNrOmZ1bmN0aW9uKHQsbil7dmFyIGk9dC5saXN0W25dO2kuaGludD9pLmhpbnQodGhpcy5jbSx0LGkpOnRoaXMuY20ucmVwbGFjZVJhbmdlKHIoaSksaS5mcm9tfHx0LmZyb20saS50b3x8dC50bywiY29tcGxldGUiKSxlLnNpZ25hbCh0LCJwaWNrIixpKSx0aGlzLmNsb3NlKCl9LGN1cnNvckFjdGl2aXR5OmZ1bmN0aW9uKCl7dGhpcy5kZWJvdW5jZSYmKGQodGhpcy5kZWJvdW5jZSksdGhpcy5kZWJvdW5jZT0wKTt2YXIgZT10aGlzLmNtLmdldEN1cnNvcigpLHQ9dGhpcy5jbS5nZXRMaW5lKGUubGluZSk7aWYoZS5saW5lIT10aGlzLnN0YXJ0UG9zLmxpbmV8fHQubGVuZ3RoLWUuY2ghPXRoaXMuc3RhcnRMZW4tdGhpcy5zdGFydFBvcy5jaHx8ZS5jaDx0aGlzLnN0YXJ0UG9zLmNofHx0aGlzLmNtLnNvbWV0aGluZ1NlbGVjdGVkKCl8fGUuY2gmJnRoaXMub3B0aW9ucy5jbG9zZUNoYXJhY3RlcnMudGVzdCh0LmNoYXJBdChlLmNoLTEpKSl0aGlzLmNsb3NlKCk7ZWxzZXt2YXIgbj10aGlzO3RoaXMuZGVib3VuY2U9ZihmdW5jdGlvbigpe24udXBkYXRlKCl9KSx0aGlzLndpZGdldCYmdGhpcy53aWRnZXQuZGlzYWJsZSgpfX0sdXBkYXRlOmZ1bmN0aW9uKGUpe2lmKG51bGwhPXRoaXMudGljayl7dmFyIHQ9dGhpcyxuPSsrdGhpcy50aWNrO3UodGhpcy5vcHRpb25zLmhpbnQsdGhpcy5jbSx0aGlzLm9wdGlvbnMsZnVuY3Rpb24ocil7dC50aWNrPT1uJiZ0LmZpbmlzaFVwZGF0ZShyLGUpfSl9fSxmaW5pc2hVcGRhdGU6ZnVuY3Rpb24odCxuKXt0aGlzLmRhdGEmJmUuc2lnbmFsKHRoaXMuZGF0YSwidXBkYXRlIik7dmFyIHI9dGhpcy53aWRnZXQmJnRoaXMud2lkZ2V0LnBpY2tlZHx8biYmdGhpcy5vcHRpb25zLmNvbXBsZXRlU2luZ2xlO3RoaXMud2lkZ2V0JiZ0aGlzLndpZGdldC5jbG9zZSgpLHRoaXMuZGF0YT10LHQmJnQubGlzdC5sZW5ndGgmJihyJiYxPT10Lmxpc3QubGVuZ3RoP3RoaXMucGljayh0LDApOih0aGlzLndpZGdldD1uZXcgYSh0aGlzLHQpLGUuc2lnbmFsKHQsInNob3duIikpKX19LGEucHJvdG90eXBlPXtjbG9zZTpmdW5jdGlvbigpe2lmKHRoaXMuY29tcGxldGlvbi53aWRnZXQ9PXRoaXMpe3RoaXMuY29tcGxldGlvbi53aWRnZXQ9bnVsbCx0aGlzLmhpbnRzLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodGhpcy5oaW50cyksdGhpcy5jb21wbGV0aW9uLmNtLnJlbW92ZUtleU1hcCh0aGlzLmtleU1hcCk7dmFyIGU9dGhpcy5jb21wbGV0aW9uLmNtO3RoaXMuY29tcGxldGlvbi5vcHRpb25zLmNsb3NlT25VbmZvY3VzJiYoZS5vZmYoImJsdXIiLHRoaXMub25CbHVyKSxlLm9mZigiZm9jdXMiLHRoaXMub25Gb2N1cykpLGUub2ZmKCJzY3JvbGwiLHRoaXMub25TY3JvbGwpfX0sZGlzYWJsZTpmdW5jdGlvbigpe3RoaXMuY29tcGxldGlvbi5jbS5yZW1vdmVLZXlNYXAodGhpcy5rZXlNYXApO3ZhciBlPXRoaXM7dGhpcy5rZXlNYXA9e0VudGVyOmZ1bmN0aW9uKCl7ZS5waWNrZWQ9ITB9fSx0aGlzLmNvbXBsZXRpb24uY20uYWRkS2V5TWFwKHRoaXMua2V5TWFwKX0scGljazpmdW5jdGlvbigpe3RoaXMuY29tcGxldGlvbi5waWNrKHRoaXMuZGF0YSx0aGlzLnNlbGVjdGVkSGludCl9LGNoYW5nZUFjdGl2ZTpmdW5jdGlvbih0LG4pe2lmKHQ+PXRoaXMuZGF0YS5saXN0Lmxlbmd0aD90PW4/dGhpcy5kYXRhLmxpc3QubGVuZ3RoLTE6MDp0PDAmJih0PW4/MDp0aGlzLmRhdGEubGlzdC5sZW5ndGgtMSksdGhpcy5zZWxlY3RlZEhpbnQhPXQpe3ZhciByPXRoaXMuaGludHMuY2hpbGROb2Rlc1t0aGlzLnNlbGVjdGVkSGludF07ciYmKHIuY2xhc3NOYW1lPXIuY2xhc3NOYW1lLnJlcGxhY2UoIiAiK3AsIiIpKSxyPXRoaXMuaGludHMuY2hpbGROb2Rlc1t0aGlzLnNlbGVjdGVkSGludD10XSxyLmNsYXNzTmFtZSs9IiAiK3Asci5vZmZzZXRUb3A8dGhpcy5oaW50cy5zY3JvbGxUb3A/dGhpcy5oaW50cy5zY3JvbGxUb3A9ci5vZmZzZXRUb3AtMzpyLm9mZnNldFRvcCtyLm9mZnNldEhlaWdodD50aGlzLmhpbnRzLnNjcm9sbFRvcCt0aGlzLmhpbnRzLmNsaWVudEhlaWdodCYmKHRoaXMuaGludHMuc2Nyb2xsVG9wPXIub2Zmc2V0VG9wK3Iub2Zmc2V0SGVpZ2h0LXRoaXMuaGludHMuY2xpZW50SGVpZ2h0KzMpLGUuc2lnbmFsKHRoaXMuZGF0YSwic2VsZWN0Iix0aGlzLmRhdGEubGlzdFt0aGlzLnNlbGVjdGVkSGludF0scil9fSxzY3JlZW5BbW91bnQ6ZnVuY3Rpb24oKXtyZXR1cm4gTWF0aC5mbG9vcih0aGlzLmhpbnRzLmNsaWVudEhlaWdodC90aGlzLmhpbnRzLmZpcnN0Q2hpbGQub2Zmc2V0SGVpZ2h0KXx8MX19LGUucmVnaXN0ZXJIZWxwZXIoImhpbnQiLCJhdXRvIix7cmVzb2x2ZTpjfSksZS5yZWdpc3RlckhlbHBlcigiaGludCIsImZyb21MaXN0IixmdW5jdGlvbih0LG4pe3ZhciByLGk9dC5nZXRDdXJzb3IoKSxvPXQuZ2V0VG9rZW5BdChpKSxhPWUuUG9zKGkubGluZSxvLnN0YXJ0KSxzPWk7by5zdGFydDxpLmNoJiYvXHcvLnRlc3Qoby5zdHJpbmcuY2hhckF0KGkuY2gtby5zdGFydC0xKSk/cj1vLnN0cmluZy5zdWJzdHIoMCxpLmNoLW8uc3RhcnQpOihyPSIiLGE9aSk7Zm9yKHZhciB1PVtdLGM9MDtjPG4ud29yZHMubGVuZ3RoO2MrKyl7dmFyIGw9bi53b3Jkc1tjXTtsLnNsaWNlKDAsci5sZW5ndGgpPT1yJiZ1LnB1c2gobCl9aWYodS5sZW5ndGgpcmV0dXJue2xpc3Q6dSxmcm9tOmEsdG86c319KSxlLmNvbW1hbmRzLmF1dG9jb21wbGV0ZT1lLnNob3dIaW50O3ZhciBoPXtoaW50OmUuaGludC5hdXRvLGNvbXBsZXRlU2luZ2xlOiEwLGFsaWduV2l0aFdvcmQ6ITAsY2xvc2VDaGFyYWN0ZXJzOi9bXHMoKVxbXF17fTs6PixdLyxjbG9zZU9uVW5mb2N1czohMCxjb21wbGV0ZU9uU2luZ2xlQ2xpY2s6ITAsY29udGFpbmVyOm51bGwsY3VzdG9tS2V5czpudWxsLGV4dHJhS2V5czpudWxsfTtlLmRlZmluZU9wdGlvbigiaGludE9wdGlvbnMiLG51bGwpfSl9LGZ1bmN0aW9uKGUsdCxuKXshZnVuY3Rpb24oZSl7ZShuKDIpKX0oZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlLHQpe3JldHVybiJwYWlycyI9PXQmJiJzdHJpbmciPT10eXBlb2YgZT9lOiJvYmplY3QiPT10eXBlb2YgZSYmbnVsbCE9ZVt0XT9lW3RdOmZbdF19ZnVuY3Rpb24gbihlKXtmb3IodmFyIHQ9MDt0PGUubGVuZ3RoO3QrKyl7dmFyIG49ZS5jaGFyQXQodCksaT0iJyIrbisiJyI7aFtpXXx8KGhbaV09cihuKSl9fWZ1bmN0aW9uIHIoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiB1KHQsZSl9fWZ1bmN0aW9uIGkoZSl7dmFyIHQ9ZS5zdGF0ZS5jbG9zZUJyYWNrZXRzO3JldHVybiF0fHx0Lm92ZXJyaWRlP3Q6ZS5nZXRNb2RlQXQoZS5nZXRDdXJzb3IoKSkuY2xvc2VCcmFja2V0c3x8dH1mdW5jdGlvbiBvKG4pe3ZhciByPWkobik7aWYoIXJ8fG4uZ2V0T3B0aW9uKCJkaXNhYmxlSW5wdXQiKSlyZXR1cm4gZS5QYXNzO2Zvcih2YXIgbz10KHIsInBhaXJzIiksYT1uLmxpc3RTZWxlY3Rpb25zKCkscz0wO3M8YS5sZW5ndGg7cysrKXtpZighYVtzXS5lbXB0eSgpKXJldHVybiBlLlBhc3M7dmFyIHU9bChuLGFbc10uaGVhZCk7aWYoIXV8fG8uaW5kZXhPZih1KSUyIT0wKXJldHVybiBlLlBhc3N9Zm9yKHZhciBzPWEubGVuZ3RoLTE7cz49MDtzLS0pe3ZhciBjPWFbc10uaGVhZDtuLnJlcGxhY2VSYW5nZSgiIixkKGMubGluZSxjLmNoLTEpLGQoYy5saW5lLGMuY2grMSksIitkZWxldGUiKX19ZnVuY3Rpb24gYShuKXt2YXIgcj1pKG4pLG89ciYmdChyLCJleHBsb2RlIik7aWYoIW98fG4uZ2V0T3B0aW9uKCJkaXNhYmxlSW5wdXQiKSlyZXR1cm4gZS5QYXNzO2Zvcih2YXIgYT1uLmxpc3RTZWxlY3Rpb25zKCkscz0wO3M8YS5sZW5ndGg7cysrKXtpZighYVtzXS5lbXB0eSgpKXJldHVybiBlLlBhc3M7dmFyIHU9bChuLGFbc10uaGVhZCk7aWYoIXV8fG8uaW5kZXhPZih1KSUyIT0wKXJldHVybiBlLlBhc3N9bi5vcGVyYXRpb24oZnVuY3Rpb24oKXt2YXIgZT1uLmxpbmVTZXBhcmF0b3IoKXx8IlxuIjtuLnJlcGxhY2VTZWxlY3Rpb24oZStlLG51bGwpLG4uZXhlY0NvbW1hbmQoImdvQ2hhckxlZnQiKSxhPW4ubGlzdFNlbGVjdGlvbnMoKTtmb3IodmFyIHQ9MDt0PGEubGVuZ3RoO3QrKyl7dmFyIHI9YVt0XS5oZWFkLmxpbmU7bi5pbmRlbnRMaW5lKHIsbnVsbCwhMCksbi5pbmRlbnRMaW5lKHIrMSxudWxsLCEwKX19KX1mdW5jdGlvbiBzKHQpe3ZhciBuPWUuY21wUG9zKHQuYW5jaG9yLHQuaGVhZCk+MDtyZXR1cm57YW5jaG9yOm5ldyBkKHQuYW5jaG9yLmxpbmUsdC5hbmNob3IuY2grKG4/LTE6MSkpLGhlYWQ6bmV3IGQodC5oZWFkLmxpbmUsdC5oZWFkLmNoKyhuPzE6LTEpKX19ZnVuY3Rpb24gdShuLHIpe3ZhciBvPWkobik7aWYoIW98fG4uZ2V0T3B0aW9uKCJkaXNhYmxlSW5wdXQiKSlyZXR1cm4gZS5QYXNzO3ZhciBhPXQobywicGFpcnMiKSx1PWEuaW5kZXhPZihyKTtpZigtMT09dSlyZXR1cm4gZS5QYXNzO2Zvcih2YXIgbCxmPXQobywidHJpcGxlcyIpLGg9YS5jaGFyQXQodSsxKT09cixtPW4ubGlzdFNlbGVjdGlvbnMoKSxnPXUlMj09MCx5PTA7eTxtLmxlbmd0aDt5Kyspe3ZhciB2LGI9bVt5XSx4PWIuaGVhZCxDPW4uZ2V0UmFuZ2UoeCxkKHgubGluZSx4LmNoKzEpKTtpZihnJiYhYi5lbXB0eSgpKXY9InN1cnJvdW5kIjtlbHNlIGlmKCFoJiZnfHxDIT1yKWlmKGgmJnguY2g+MSYmZi5pbmRleE9mKHIpPj0wJiZuLmdldFJhbmdlKGQoeC5saW5lLHguY2gtMikseCk9PXIrcil7aWYoeC5jaD4yJiYvXGJzdHJpbmcvLnRlc3Qobi5nZXRUb2tlblR5cGVBdChkKHgubGluZSx4LmNoLTIpKSkpcmV0dXJuIGUuUGFzczt2PSJhZGRGb3VyIn1lbHNlIGlmKGgpe3ZhciBFPTA9PXguY2g/IiAiOm4uZ2V0UmFuZ2UoZCh4LmxpbmUseC5jaC0xKSx4KTtpZihlLmlzV29yZENoYXIoQyl8fEU9PXJ8fGUuaXNXb3JkQ2hhcihFKSlyZXR1cm4gZS5QYXNzO3Y9ImJvdGgifWVsc2V7aWYoIWd8fG4uZ2V0TGluZSh4LmxpbmUpLmxlbmd0aCE9eC5jaCYmIWMoQyxhKSYmIS9ccy8udGVzdChDKSlyZXR1cm4gZS5QYXNzO3Y9ImJvdGgifWVsc2Ugdj1oJiZwKG4seCk/ImJvdGgiOmYuaW5kZXhPZihyKT49MCYmbi5nZXRSYW5nZSh4LGQoeC5saW5lLHguY2grMykpPT1yK3Ircj8ic2tpcFRocmVlIjoic2tpcCI7aWYobCl7aWYobCE9dilyZXR1cm4gZS5QYXNzfWVsc2UgbD12fXZhciBEPXUlMj9hLmNoYXJBdCh1LTEpOnIsdz11JTI/cjphLmNoYXJBdCh1KzEpO24ub3BlcmF0aW9uKGZ1bmN0aW9uKCl7aWYoInNraXAiPT1sKW4uZXhlY0NvbW1hbmQoImdvQ2hhclJpZ2h0Iik7ZWxzZSBpZigic2tpcFRocmVlIj09bClmb3IodmFyIGU9MDtlPDM7ZSsrKW4uZXhlY0NvbW1hbmQoImdvQ2hhclJpZ2h0Iik7ZWxzZSBpZigic3Vycm91bmQiPT1sKXtmb3IodmFyIHQ9bi5nZXRTZWxlY3Rpb25zKCksZT0wO2U8dC5sZW5ndGg7ZSsrKXRbZV09RCt0W2VdK3c7bi5yZXBsYWNlU2VsZWN0aW9ucyh0LCJhcm91bmQiKSx0PW4ubGlzdFNlbGVjdGlvbnMoKS5zbGljZSgpO2Zvcih2YXIgZT0wO2U8dC5sZW5ndGg7ZSsrKXRbZV09cyh0W2VdKTtuLnNldFNlbGVjdGlvbnModCl9ZWxzZSJib3RoIj09bD8obi5yZXBsYWNlU2VsZWN0aW9uKEQrdyxudWxsKSxuLnRyaWdnZXJFbGVjdHJpYyhEK3cpLG4uZXhlY0NvbW1hbmQoImdvQ2hhckxlZnQiKSk6ImFkZEZvdXIiPT1sJiYobi5yZXBsYWNlU2VsZWN0aW9uKEQrRCtEK0QsImJlZm9yZSIpLG4uZXhlY0NvbW1hbmQoImdvQ2hhclJpZ2h0IikpfSl9ZnVuY3Rpb24gYyhlLHQpe3ZhciBuPXQubGFzdEluZGV4T2YoZSk7cmV0dXJuIG4+LTEmJm4lMj09MX1mdW5jdGlvbiBsKGUsdCl7dmFyIG49ZS5nZXRSYW5nZShkKHQubGluZSx0LmNoLTEpLGQodC5saW5lLHQuY2grMSkpO3JldHVybiAyPT1uLmxlbmd0aD9uOm51bGx9ZnVuY3Rpb24gcChlLHQpe3ZhciBuPWUuZ2V0VG9rZW5BdChkKHQubGluZSx0LmNoKzEpKTtyZXR1cm4vXGJzdHJpbmcvLnRlc3Qobi50eXBlKSYmbi5zdGFydD09dC5jaCYmKDA9PXQuY2h8fCEvXGJzdHJpbmcvLnRlc3QoZS5nZXRUb2tlblR5cGVBdCh0KSkpfXZhciBmPXtwYWlyczoiKClbXXt9JydcIlwiIix0cmlwbGVzOiIiLGV4cGxvZGU6Iltde30ifSxkPWUuUG9zO2UuZGVmaW5lT3B0aW9uKCJhdXRvQ2xvc2VCcmFja2V0cyIsITEsZnVuY3Rpb24ocixpLG8pe28mJm8hPWUuSW5pdCYmKHIucmVtb3ZlS2V5TWFwKGgpLHIuc3RhdGUuY2xvc2VCcmFja2V0cz1udWxsKSxpJiYobih0KGksInBhaXJzIikpLHIuc3RhdGUuY2xvc2VCcmFja2V0cz1pLHIuYWRkS2V5TWFwKGgpKX0pO3ZhciBoPXtCYWNrc3BhY2U6byxFbnRlcjphfTtuKGYucGFpcnMrImAiKX0pfSxmdW5jdGlvbihlLHQsbil7IWZ1bmN0aW9uKGUpe2UobigyKSl9KGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiB0KHQsbil7ZnVuY3Rpb24gcih0KXtpZighaS5wYXJlbnROb2RlKXJldHVybiBlLm9mZihkb2N1bWVudCwibW91c2Vtb3ZlIixyKTtpLnN0eWxlLnRvcD1NYXRoLm1heCgwLHQuY2xpZW50WS1pLm9mZnNldEhlaWdodC01KSsicHgiLGkuc3R5bGUubGVmdD10LmNsaWVudFgrNSsicHgifXZhciBpPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpO3JldHVybiBpLmNsYXNzTmFtZT0iQ29kZU1pcnJvci1saW50LXRvb2x0aXAiLGkuYXBwZW5kQ2hpbGQobi5jbG9uZU5vZGUoITApKSxkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGkpLGUub24oZG9jdW1lbnQsIm1vdXNlbW92ZSIscikscih0KSxudWxsIT1pLnN0eWxlLm9wYWNpdHkmJihpLnN0eWxlLm9wYWNpdHk9MSksaX1mdW5jdGlvbiBuKGUpe2UucGFyZW50Tm9kZSYmZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGUpfWZ1bmN0aW9uIHIoZSl7ZS5wYXJlbnROb2RlJiYobnVsbD09ZS5zdHlsZS5vcGFjaXR5JiZuKGUpLGUuc3R5bGUub3BhY2l0eT0wLHNldFRpbWVvdXQoZnVuY3Rpb24oKXtuKGUpfSw2MDApKX1mdW5jdGlvbiBpKG4saSxvKXtmdW5jdGlvbiBhKCl7ZS5vZmYobywibW91c2VvdXQiLGEpLHMmJihyKHMpLHM9bnVsbCl9dmFyIHM9dChuLGkpLHU9c2V0SW50ZXJ2YWwoZnVuY3Rpb24oKXtpZihzKWZvcih2YXIgZT1vOztlPWUucGFyZW50Tm9kZSl7aWYoZSYmMTE9PWUubm9kZVR5cGUmJihlPWUuaG9zdCksZT09ZG9jdW1lbnQuYm9keSlyZXR1cm47aWYoIWUpe2EoKTticmVha319aWYoIXMpcmV0dXJuIGNsZWFySW50ZXJ2YWwodSl9LDQwMCk7ZS5vbihvLCJtb3VzZW91dCIsYSl9ZnVuY3Rpb24gbyhlLHQsbil7dGhpcy5tYXJrZWQ9W10sdGhpcy5vcHRpb25zPXQsdGhpcy50aW1lb3V0PW51bGwsdGhpcy5oYXNHdXR0ZXI9bix0aGlzLm9uTW91c2VPdmVyPWZ1bmN0aW9uKHQpe3koZSx0KX0sdGhpcy53YWl0aW5nRm9yPTB9ZnVuY3Rpb24gYShlLHQpe3JldHVybiB0IGluc3RhbmNlb2YgRnVuY3Rpb24/e2dldEFubm90YXRpb25zOnR9Oih0JiYhMCE9PXR8fCh0PXt9KSx0KX1mdW5jdGlvbiBzKGUpe3ZhciB0PWUuc3RhdGUubGludDt0Lmhhc0d1dHRlciYmZS5jbGVhckd1dHRlcih2KTtmb3IodmFyIG49MDtuPHQubWFya2VkLmxlbmd0aDsrK24pdC5tYXJrZWRbbl0uY2xlYXIoKTt0Lm1hcmtlZC5sZW5ndGg9MH1mdW5jdGlvbiB1KHQsbixyLG8pe3ZhciBhPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpLHM9YTtyZXR1cm4gYS5jbGFzc05hbWU9IkNvZGVNaXJyb3ItbGludC1tYXJrZXItIituLHImJihzPWEuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IikpLHMuY2xhc3NOYW1lPSJDb2RlTWlycm9yLWxpbnQtbWFya2VyLW11bHRpcGxlIiksMCE9byYmZS5vbihzLCJtb3VzZW92ZXIiLGZ1bmN0aW9uKGUpe2koZSx0LHMpfSksYX1mdW5jdGlvbiBjKGUsdCl7cmV0dXJuImVycm9yIj09ZT9lOnR9ZnVuY3Rpb24gbChlKXtmb3IodmFyIHQ9W10sbj0wO248ZS5sZW5ndGg7KytuKXt2YXIgcj1lW25dLGk9ci5mcm9tLmxpbmU7KHRbaV18fCh0W2ldPVtdKSkucHVzaChyKX1yZXR1cm4gdH1mdW5jdGlvbiBwKGUpe3ZhciB0PWUuc2V2ZXJpdHk7dHx8KHQ9ImVycm9yIik7dmFyIG49ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7cmV0dXJuIG4uY2xhc3NOYW1lPSJDb2RlTWlycm9yLWxpbnQtbWVzc2FnZS0iK3QsInVuZGVmaW5lZCIhPXR5cGVvZiBlLm1lc3NhZ2VIVE1MP24uaW5uZXJIVE1MPWUubWVzc2FnZUhUTUw6bi5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShlLm1lc3NhZ2UpKSxufWZ1bmN0aW9uIGYodCxuLHIpe2Z1bmN0aW9uIGkoKXthPS0xLHQub2ZmKCJjaGFuZ2UiLGkpfXZhciBvPXQuc3RhdGUubGludCxhPSsrby53YWl0aW5nRm9yO3Qub24oImNoYW5nZSIsaSksbih0LmdldFZhbHVlKCksZnVuY3Rpb24obixyKXt0Lm9mZigiY2hhbmdlIixpKSxvLndhaXRpbmdGb3I9PWEmJihyJiZuIGluc3RhbmNlb2YgZSYmKG49ciksdC5vcGVyYXRpb24oZnVuY3Rpb24oKXtoKHQsbil9KSl9LHIsdCl9ZnVuY3Rpb24gZCh0KXt2YXIgbj10LnN0YXRlLmxpbnQscj1uLm9wdGlvbnMsaT1yLm9wdGlvbnN8fHIsbz1yLmdldEFubm90YXRpb25zfHx0LmdldEhlbHBlcihlLlBvcygwLDApLCJsaW50Iik7aWYobylpZihyLmFzeW5jfHxvLmFzeW5jKWYodCxvLGkpO2Vsc2V7dmFyIGE9byh0LmdldFZhbHVlKCksaSx0KTtpZighYSlyZXR1cm47YS50aGVuP2EudGhlbihmdW5jdGlvbihlKXt0Lm9wZXJhdGlvbihmdW5jdGlvbigpe2godCxlKX0pfSk6dC5vcGVyYXRpb24oZnVuY3Rpb24oKXtoKHQsYSl9KX19ZnVuY3Rpb24gaChlLHQpe3MoZSk7Zm9yKHZhciBuPWUuc3RhdGUubGludCxyPW4ub3B0aW9ucyxpPWwodCksbz0wO288aS5sZW5ndGg7KytvKXt2YXIgYT1pW29dO2lmKGEpe2Zvcih2YXIgZj1udWxsLGQ9bi5oYXNHdXR0ZXImJmRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSxoPTA7aDxhLmxlbmd0aDsrK2gpe3ZhciBtPWFbaF0sZz1tLnNldmVyaXR5O2d8fChnPSJlcnJvciIpLGY9YyhmLGcpLHIuZm9ybWF0QW5ub3RhdGlvbiYmKG09ci5mb3JtYXRBbm5vdGF0aW9uKG0pKSxuLmhhc0d1dHRlciYmZC5hcHBlbmRDaGlsZChwKG0pKSxtLnRvJiZuLm1hcmtlZC5wdXNoKGUubWFya1RleHQobS5mcm9tLG0udG8se2NsYXNzTmFtZToiQ29kZU1pcnJvci1saW50LW1hcmstIitnLF9fYW5ub3RhdGlvbjptfSkpfW4uaGFzR3V0dGVyJiZlLnNldEd1dHRlck1hcmtlcihvLHYsdShkLGYsYS5sZW5ndGg+MSxuLm9wdGlvbnMudG9vbHRpcHMpKX19ci5vblVwZGF0ZUxpbnRpbmcmJnIub25VcGRhdGVMaW50aW5nKHQsaSxlKX1mdW5jdGlvbiBtKGUpe3ZhciB0PWUuc3RhdGUubGludDt0JiYoY2xlYXJUaW1lb3V0KHQudGltZW91dCksdC50aW1lb3V0PXNldFRpbWVvdXQoZnVuY3Rpb24oKXtkKGUpfSx0Lm9wdGlvbnMuZGVsYXl8fDUwMCkpfWZ1bmN0aW9uIGcoZSx0KXtmb3IodmFyIG49dC50YXJnZXR8fHQuc3JjRWxlbWVudCxyPWRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSxvPTA7bzxlLmxlbmd0aDtvKyspe3ZhciBhPWVbb107ci5hcHBlbmRDaGlsZChwKGEpKX1pKHQscixuKX1mdW5jdGlvbiB5KGUsdCl7dmFyIG49dC50YXJnZXR8fHQuc3JjRWxlbWVudDtpZigvXGJDb2RlTWlycm9yLWxpbnQtbWFyay0vLnRlc3Qobi5jbGFzc05hbWUpKXtmb3IodmFyIHI9bi5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSxpPShyLmxlZnQrci5yaWdodCkvMixvPShyLnRvcCtyLmJvdHRvbSkvMixhPWUuZmluZE1hcmtzQXQoZS5jb29yZHNDaGFyKHtsZWZ0OmksdG9wOm99LCJjbGllbnQiKSkscz1bXSx1PTA7dTxhLmxlbmd0aDsrK3Upe3ZhciBjPWFbdV0uX19hbm5vdGF0aW9uO2MmJnMucHVzaChjKX1zLmxlbmd0aCYmZyhzLHQpfX12YXIgdj0iQ29kZU1pcnJvci1saW50LW1hcmtlcnMiO2UuZGVmaW5lT3B0aW9uKCJsaW50IiwhMSxmdW5jdGlvbih0LG4scil7aWYociYmciE9ZS5Jbml0JiYocyh0KSwhMSE9PXQuc3RhdGUubGludC5vcHRpb25zLmxpbnRPbkNoYW5nZSYmdC5vZmYoImNoYW5nZSIsbSksZS5vZmYodC5nZXRXcmFwcGVyRWxlbWVudCgpLCJtb3VzZW92ZXIiLHQuc3RhdGUubGludC5vbk1vdXNlT3ZlciksY2xlYXJUaW1lb3V0KHQuc3RhdGUubGludC50aW1lb3V0KSxkZWxldGUgdC5zdGF0ZS5saW50KSxuKXtmb3IodmFyIGk9dC5nZXRPcHRpb24oImd1dHRlcnMiKSx1PSExLGM9MDtjPGkubGVuZ3RoOysrYylpW2NdPT12JiYodT0hMCk7dmFyIGw9dC5zdGF0ZS5saW50PW5ldyBvKHQsYSh0LG4pLHUpOyExIT09bC5vcHRpb25zLmxpbnRPbkNoYW5nZSYmdC5vbigiY2hhbmdlIixtKSwwIT1sLm9wdGlvbnMudG9vbHRpcHMmJiJndXR0ZXIiIT1sLm9wdGlvbnMudG9vbHRpcHMmJmUub24odC5nZXRXcmFwcGVyRWxlbWVudCgpLCJtb3VzZW92ZXIiLGwub25Nb3VzZU92ZXIpLGQodCl9fSksZS5kZWZpbmVFeHRlbnNpb24oInBlcmZvcm1MaW50IixmdW5jdGlvbigpe3RoaXMuc3RhdGUubGludCYmZCh0aGlzKX0pfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD12b2lkIDA7dHJ5e3Q9KDAsdS5wYXJzZSkoZSl9Y2F0Y2goZSl7cmV0dXJuIG51bGx9dmFyIG49aShlKTtyZXR1cm57b3V0bGluZVRyZWVzOigwLHUudmlzaXQpKHQse2xlYXZlOmZ1bmN0aW9uKGUpe3JldHVybiBwLmhhc093blByb3BlcnR5KGUua2luZCkmJm5bZS5raW5kXT9uW2Uua2luZF0oZSk6bnVsbH19KX19ZnVuY3Rpb24gaShlKXt2YXIgdD1mdW5jdGlvbih0KXtyZXR1cm57cmVwcmVzZW50YXRpdmVOYW1lOnQubmFtZSxzdGFydFBvc2l0aW9uOigwLGwub2Zmc2V0VG9Qb3NpdGlvbikoZSx0LmxvYy5zdGFydCksZW5kUG9zaXRpb246KDAsbC5vZmZzZXRUb1Bvc2l0aW9uKShlLHQubG9jLmVuZCksY2hpbGRyZW46dC5zZWxlY3Rpb25TZXR8fFtdfX07cmV0dXJue0ZpZWxkOmZ1bmN0aW9uKGUpe3ZhciBuPWUuYWxpYXM/W28oInBsYWluIixlLmFsaWFzKSxvKCJwbGFpbiIsIjogIildOltdO3JldHVybiBuLnB1c2gobygicGxhaW4iLGUubmFtZSkpLHMoe3Rva2VuaXplZFRleHQ6bn0sdChlKSl9LE9wZXJhdGlvbkRlZmluaXRpb246ZnVuY3Rpb24oZSl7cmV0dXJuIHMoe3Rva2VuaXplZFRleHQ6W28oImtleXdvcmQiLGUub3BlcmF0aW9uKSxvKCJ3aGl0ZXNwYWNlIiwiICIpLG8oImNsYXNzLW5hbWUiLGUubmFtZSldfSx0KGUpKX0sRG9jdW1lbnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZGVmaW5pdGlvbnN9LFNlbGVjdGlvblNldDpmdW5jdGlvbihlKXtyZXR1cm4gYShlLnNlbGVjdGlvbnMsZnVuY3Rpb24oZSl7cmV0dXJuIGUua2luZD09PWMuSU5MSU5FX0ZSQUdNRU5UP2Uuc2VsZWN0aW9uU2V0OmV9KX0sTmFtZTpmdW5jdGlvbihlKXtyZXR1cm4gZS52YWx1ZX0sRnJhZ21lbnREZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiBzKHt0b2tlbml6ZWRUZXh0OltvKCJrZXl3b3JkIiwiZnJhZ21lbnQiKSxvKCJ3aGl0ZXNwYWNlIiwiICIpLG8oImNsYXNzLW5hbWUiLGUubmFtZSldfSx0KGUpKX0sRnJhZ21lbnRTcHJlYWQ6ZnVuY3Rpb24oZSl7cmV0dXJuIHMoe3Rva2VuaXplZFRleHQ6W28oInBsYWluIiwiLi4uIiksbygiY2xhc3MtbmFtZSIsZS5uYW1lKV19LHQoZSkpfSxJbmxpbmVGcmFnbWVudDpmdW5jdGlvbihlKXtyZXR1cm4gZS5zZWxlY3Rpb25TZXR9fX1mdW5jdGlvbiBvKGUsdCl7cmV0dXJue2tpbmQ6ZSx2YWx1ZTp0fX1mdW5jdGlvbiBhKGUsdCl7Zm9yKHZhciBuPVtdLHI9MDtyPGUubGVuZ3RoO3IrKyl7dmFyIGk9dChlW3JdLHIpO0FycmF5LmlzQXJyYXkoaSk/bi5wdXNoLmFwcGx5KG4saSk6bi5wdXNoKGkpfXJldHVybiBufU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcz1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfTt0LmdldE91dGxpbmU9cjt2YXIgdT1uKDcpLGM9bigxMCksbD1uKDk1KSxwPXtGaWVsZDohMCxPcGVyYXRpb25EZWZpbml0aW9uOiEwLERvY3VtZW50OiEwLFNlbGVjdGlvblNldDohMCxOYW1lOiEwLEZyYWdtZW50RGVmaW5pdGlvbjohMCxGcmFnbWVudFNwcmVhZDohMCxJbmxpbmVGcmFnbWVudDohMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2lmKCEoZSBpbnN0YW5jZW9mIHQpKXRocm93IG5ldyBUeXBlRXJyb3IoIkNhbm5vdCBjYWxsIGEgY2xhc3MgYXMgYSBmdW5jdGlvbiIpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkdyYXBoUUxMYW5ndWFnZVNlcnZpY2U9dm9pZCAwO3ZhciBpPW4oMTApLG89big3KSxhPW4oOTMpLHM9big5NiksdT1uKDk0KSxjPW4oOTUpO3QuR3JhcGhRTExhbmd1YWdlU2VydmljZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7cih0aGlzLGUpLHRoaXMuX2dyYXBoUUxDYWNoZT10LHRoaXMuX2dyYXBoUUxDb25maWc9dC5nZXRHcmFwaFFMQ29uZmlnKCl9cmV0dXJuIGUucHJvdG90eXBlLmdldERpYWdub3N0aWNzPWZ1bmN0aW9uKGUsdCxyKXt2YXIgYSx1LGMsbCxwLGYsZCxoLG0sZyx5LHYsYix4O3JldHVybiByZWdlbmVyYXRvclJ1bnRpbWUuYXN5bmMoZnVuY3Rpb24oQyl7Zm9yKDs7KXN3aXRjaChDLnByZXY9Qy5uZXh0KXtjYXNlIDA6YT0hMSx1PXRoaXMuX2dyYXBoUUxDb25maWcuZ2V0Q29uZmlnRm9yRmlsZSh0KSxjPXUuc2NoZW1hUGF0aCxDLnByZXY9MyxsPSgwLG8ucGFyc2UpKGUpLGMmJnQ9PT1jfHwoYT1sLmRlZmluaXRpb25zLnNvbWUoZnVuY3Rpb24oZSl7c3dpdGNoKGUua2luZCl7Y2FzZSBpLk9CSkVDVF9UWVBFX0RFRklOSVRJT046Y2FzZSBpLklOVEVSRkFDRV9UWVBFX0RFRklOSVRJT046Y2FzZSBpLkVOVU1fVFlQRV9ERUZJTklUSU9OOmNhc2UgaS5VTklPTl9UWVBFX0RFRklOSVRJT046Y2FzZSBpLlNDQUxBUl9UWVBFX0RFRklOSVRJT046Y2FzZSBpLklOUFVUX09CSkVDVF9UWVBFX0RFRklOSVRJT046Y2FzZSBpLlNDQUxBUl9UWVBFX0VYVEVOU0lPTjpjYXNlIGkuT0JKRUNUX1RZUEVfRVhURU5TSU9OOmNhc2UgaS5JTlRFUkZBQ0VfVFlQRV9FWFRFTlNJT046Y2FzZSBpLlVOSU9OX1RZUEVfRVhURU5TSU9OOmNhc2UgaS5FTlVNX1RZUEVfRVhURU5TSU9OOmNhc2UgaS5JTlBVVF9PQkpFQ1RfVFlQRV9FWFRFTlNJT046Y2FzZSBpLkRJUkVDVElWRV9ERUZJTklUSU9OOnJldHVybiEwfXJldHVybiExfSkpLEMubmV4dD0xMjticmVhaztjYXNlIDg6cmV0dXJuIEMucHJldj04LEMudDA9Qy5jYXRjaCgzKSxwPSgwLHMuZ2V0UmFuZ2UpKEMudDAubG9jYXRpb25zWzBdLGUpLEMuYWJydXB0KCJyZXR1cm4iLFt7c2V2ZXJpdHk6cy5TRVZFUklUWS5FUlJPUixtZXNzYWdlOkMudDAubWVzc2FnZSxzb3VyY2U6IkdyYXBoUUw6IFN5bnRheCIscmFuZ2U6cH1dKTtjYXNlIDEyOmlmKGMpe0MubmV4dD0xNDticmVha31yZXR1cm4gQy5hYnJ1cHQoInJldHVybiIsW10pO2Nhc2UgMTQ6cmV0dXJuIGY9ZSxDLm5leHQ9MTcscmVnZW5lcmF0b3JSdW50aW1lLmF3cmFwKHRoaXMuX2dyYXBoUUxDYWNoZS5nZXRGcmFnbWVudERlZmluaXRpb25zKHUpKTtjYXNlIDE3OnJldHVybiBkPUMuc2VudCxDLm5leHQ9MjAscmVnZW5lcmF0b3JSdW50aW1lLmF3cmFwKHRoaXMuX2dyYXBoUUxDYWNoZS5nZXRGcmFnbWVudERlcGVuZGVuY2llcyhlLGQpKTtjYXNlIDIwOmg9Qy5zZW50LG09aC5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZSsiICIrKDAsby5wcmludCkodC5kZWZpbml0aW9uKX0sIiIpLGY9ZisiICIrbSxnPW51bGwsQy5wcmV2PTI0LGc9KDAsby5wYXJzZSkoZiksQy5uZXh0PTMxO2JyZWFrO2Nhc2UgMjg6cmV0dXJuIEMucHJldj0yOCxDLnQxPUMuY2F0Y2goMjQpLEMuYWJydXB0KCJyZXR1cm4iLFtdKTtjYXNlIDMxOnJldHVybiBDLm5leHQ9MzMscmVnZW5lcmF0b3JSdW50aW1lLmF3cmFwKHRoaXMuX2dyYXBoUUxDYWNoZS5nZXRTY2hlbWEodS5wcm9qZWN0TmFtZSxhKSk7Y2FzZSAzMzpyZXR1cm4geT1DLnNlbnQsdj12b2lkIDAsYj11LmV4dGVuc2lvbnMuY3VzdG9tVmFsaWRhdGlvblJ1bGVzLGImJih4PW4oMjc5KS5yZXNvbHZlKCIiK2IpKSYmKHY9bigyNzkpKCIiK3gpKHRoaXMuX2dyYXBoUUxDb25maWcpKSxDLmFicnVwdCgicmV0dXJuIiwoMCxzLnZhbGlkYXRlUXVlcnkpKGcseSx2LHIpKTtjYXNlIDM4OmNhc2UiZW5kIjpyZXR1cm4gQy5zdG9wKCl9fSxudWxsLHRoaXMsW1szLDhdLFsyNCwyOF1dKX0sZS5wcm90b3R5cGUuZ2V0QXV0b2NvbXBsZXRlU3VnZ2VzdGlvbnM9ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGk7cmV0dXJuIHJlZ2VuZXJhdG9yUnVudGltZS5hc3luYyhmdW5jdGlvbihvKXtmb3IoOzspc3dpdGNoKG8ucHJldj1vLm5leHQpe2Nhc2UgMDppZihyPXRoaXMuX2dyYXBoUUxDb25maWcuZ2V0Q29uZmlnRm9yRmlsZShuKSwhci5zY2hlbWFQYXRoKXtvLm5leHQ9NzticmVha31yZXR1cm4gby5uZXh0PTQscmVnZW5lcmF0b3JSdW50aW1lLmF3cmFwKHRoaXMuX2dyYXBoUUxDYWNoZS5nZXRTY2hlbWEoci5wcm9qZWN0TmFtZSkpO2Nhc2UgNDppZighKGk9by5zZW50KSl7by5uZXh0PTc7YnJlYWt9cmV0dXJuIG8uYWJydXB0KCJyZXR1cm4iLCgwLGEuZ2V0QXV0b2NvbXBsZXRlU3VnZ2VzdGlvbnMpKGksZSx0KSk7Y2FzZSA3OnJldHVybiBvLmFicnVwdCgicmV0dXJuIixbXSk7Y2FzZSA4OmNhc2UiZW5kIjpyZXR1cm4gby5zdG9wKCl9fSxudWxsLHRoaXMpfSxlLnByb3RvdHlwZS5nZXREZWZpbml0aW9uPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcixhLHM7cmV0dXJuIHJlZ2VuZXJhdG9yUnVudGltZS5hc3luYyhmdW5jdGlvbihsKXtmb3IoOzspc3dpdGNoKGwucHJldj1sLm5leHQpe2Nhc2UgMDpyPXRoaXMuX2dyYXBoUUxDb25maWcuZ2V0Q29uZmlnRm9yRmlsZShuKSxhPXZvaWQgMCxsLnByZXY9MixhPSgwLG8ucGFyc2UpKGUpLGwubmV4dD05O2JyZWFrO2Nhc2UgNjpyZXR1cm4gbC5wcmV2PTYsbC50MD1sLmNhdGNoKDIpLGwuYWJydXB0KCJyZXR1cm4iLG51bGwpO2Nhc2UgOTppZighKHM9KDAsYy5nZXRBU1ROb2RlQXRQb3NpdGlvbikoZSxhLHQpKSl7bC5uZXh0PTE2O2JyZWFrfWwudDE9cy5raW5kLGwubmV4dD1sLnQxPT09aS5GUkFHTUVOVF9TUFJFQUQ/MTQ6bC50MT09PWkuRlJBR01FTlRfREVGSU5JVElPTj8xNTpsLnQxPT09aS5PUEVSQVRJT05fREVGSU5JVElPTj8xNToxNjticmVhaztjYXNlIDE0OnJldHVybiBsLmFicnVwdCgicmV0dXJuIix0aGlzLl9nZXREZWZpbml0aW9uRm9yRnJhZ21lbnRTcHJlYWQoZSxhLHMsbixyKSk7Y2FzZSAxNTpyZXR1cm4gbC5hYnJ1cHQoInJldHVybiIsKDAsdS5nZXREZWZpbml0aW9uUXVlcnlSZXN1bHRGb3JEZWZpbml0aW9uTm9kZSkobixlLHMpKTtjYXNlIDE2OnJldHVybiBsLmFicnVwdCgicmV0dXJuIixudWxsKTtjYXNlIDE3OmNhc2UiZW5kIjpyZXR1cm4gbC5zdG9wKCl9fSxudWxsLHRoaXMsW1syLDZdXSl9LGUucHJvdG90eXBlLl9nZXREZWZpbml0aW9uRm9yRnJhZ21lbnRTcHJlYWQ9ZnVuY3Rpb24oZSx0LG4scixvKXt2YXIgYSxzLGMsbCxwLGY7cmV0dXJuIHJlZ2VuZXJhdG9yUnVudGltZS5hc3luYyhmdW5jdGlvbihkKXtmb3IoOzspc3dpdGNoKGQucHJldj1kLm5leHQpe2Nhc2UgMDpyZXR1cm4gZC5uZXh0PTIscmVnZW5lcmF0b3JSdW50aW1lLmF3cmFwKHRoaXMuX2dyYXBoUUxDYWNoZS5nZXRGcmFnbWVudERlZmluaXRpb25zKG8pKTtjYXNlIDI6cmV0dXJuIGE9ZC5zZW50LGQubmV4dD01LHJlZ2VuZXJhdG9yUnVudGltZS5hd3JhcCh0aGlzLl9ncmFwaFFMQ2FjaGUuZ2V0RnJhZ21lbnREZXBlbmRlbmNpZXNGb3JBU1QodCxhKSk7Y2FzZSA1OnJldHVybiBzPWQuc2VudCxjPXQuZGVmaW5pdGlvbnMuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBlLmtpbmQ9PT1pLkZSQUdNRU5UX0RFRklOSVRJT059KSxsPWMscD1sLm1hcChmdW5jdGlvbih0KXtyZXR1cm57ZmlsZVBhdGg6cixjb250ZW50OmUsZGVmaW5pdGlvbjp0fX0pLGQubmV4dD0xMSxyZWdlbmVyYXRvclJ1bnRpbWUuYXdyYXAoKDAsdS5nZXREZWZpbml0aW9uUXVlcnlSZXN1bHRGb3JGcmFnbWVudFNwcmVhZCkoZSxuLHMuY29uY2F0KHApKSk7Y2FzZSAxMTpyZXR1cm4gZj1kLnNlbnQsZC5hYnJ1cHQoInJldHVybiIsZik7Y2FzZSAxMzpjYXNlImVuZCI6cmV0dXJuIGQuc3RvcCgpfX0sbnVsbCx0aGlzKX0sZX0oKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfSxvPWZ1bmN0aW9uKCl7cmV0dXJuIG89T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0LG49MSxyPWFyZ3VtZW50cy5sZW5ndGg7bjxyO24rKyl7dD1hcmd1bWVudHNbbl07Zm9yKHZhciBpIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsaSkmJihlW2ldPXRbaV0pfXJldHVybiBlfSxvLmFwcGx5KHRoaXMsYXJndW1lbnRzKX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBhPW4oMCkscz1uKDEpLHU9bigyODQpLGM9big2MTQpLGw9big2MjApLHA9big4KSxmPW4oMTIpLGQ9big5KSxoPW4oOTcpLG09bigxOCksZz1uKDE2KSx5PW4oMTMyKSx2PW4oNzUpLGI9bigxNykseD1mdW5jdGlvbihlKXtmdW5jdGlvbiBuKCl7dmFyIHQ9bnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzO3JldHVybiB0LmNvcHlDdXJsVG9DbGlwYm9hcmQ9ZnVuY3Rpb24oKXt2YXIgZT10LmdldEN1cmwoKTt1KGUpfSx0Lm9uQ2hhbmdlPWZ1bmN0aW9uKGUpe3QucHJvcHMuZWRpdEVuZHBvaW50KGUudGFyZ2V0LnZhbHVlKX0sdC5vbktleURvd249ZnVuY3Rpb24oZSl7MTM9PT1lLmtleUNvZGUmJnQucHJvcHMucmVmZXRjaFNjaGVtYSgpfSx0Lm9wZW5IaXN0b3J5PWZ1bmN0aW9uKCl7dC5wcm9wcy5vcGVuSGlzdG9yeSgpfSx0LmdldEN1cmw9ZnVuY3Rpb24oKXt2YXIgZSxuPWYuZ2V0U2VsZWN0ZWRTZXNzaW9uKHQuY29udGV4dC5zdG9yZS5nZXRTdGF0ZSgpKTt0cnl7ZT1KU09OLnBhcnNlKG4udmFyaWFibGVzKX1jYXRjaChlKXt9dmFyIHIsaT1KU09OLnN0cmluZ2lmeSh7cXVlcnk6bi5xdWVyeSx2YXJpYWJsZXM6ZSxvcGVyYXRpb25OYW1lOm4ub3BlcmF0aW9uTmFtZX0pO3RyeXtyPUpTT04ucGFyc2Uobi5oZWFkZXJzKX1jYXRjaChlKXt9dmFyIGE9byh7IkFjY2VwdC1FbmNvZGluZyI6Imd6aXAsIGRlZmxhdGUsIGJyIiwiQ29udGVudC1UeXBlIjoiYXBwbGljYXRpb24vanNvbiIsQWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uIixDb25uZWN0aW9uOiJrZWVwLWFsaXZlIixETlQ6IjEiLE9yaWdpbjpsb2NhdGlvbi5vcmlnaW58fG4uZW5kcG9pbnR9LHIpLHM9T2JqZWN0LmtleXMoYSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiItSCAnIitlKyI6ICIrYVtlXSsiJyJ9KS5qb2luKCIgIik7cmV0dXJuImN1cmwgJyIrbi5lbmRwb2ludCsiJyAiK3MrIiAtLWRhdGEtYmluYXJ5ICciK2krIicgLS1jb21wcmVzc2VkIn0sdH1yZXR1cm4gcihuLGUpLG4ucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMsbj1lLmVuZHBvaW50VW5yZWFjaGFibGUscj1lLnNldHRpbmdzO3JldHVybiBhLmNyZWF0ZUVsZW1lbnQoVCxudWxsLGEuY3JlYXRlRWxlbWVudCh0LkJ1dHRvbix7b25DbGljazp0aGlzLnByb3BzLnByZXR0aWZ5UXVlcnl9LCJQcmV0dGlmeSIpLGEuY3JlYXRlRWxlbWVudCh0LkJ1dHRvbix7b25DbGljazp0aGlzLm9wZW5IaXN0b3J5fSwiSGlzdG9yeSIpLGEuY3JlYXRlRWxlbWVudChGLG51bGwsYS5jcmVhdGVFbGVtZW50KE8se3ZhbHVlOnRoaXMucHJvcHMuZW5kcG9pbnQsb25DaGFuZ2U6dGhpcy5vbkNoYW5nZSxvbktleURvd246dGhpcy5vbktleURvd24sb25CbHVyOnRoaXMucHJvcHMucmVmZXRjaFNjaGVtYSxkaXNhYmxlZDp0aGlzLnByb3BzLmZpeGVkRW5kcG9pbnQsYWN0aXZlOiF0aGlzLnByb3BzLmZpeGVkRW5kcG9pbnR9KSxuP2EuY3JlYXRlRWxlbWVudChOLG51bGwsYS5jcmVhdGVFbGVtZW50KCJzcGFuIixudWxsLCJTZXJ2ZXIgY2Fubm90IGJlIHJlYWNoZWQiKSxhLmNyZWF0ZUVsZW1lbnQoUCxudWxsKSk6YS5jcmVhdGVFbGVtZW50KCJkaXYiLHtzdHlsZTp7ZGlzcGxheToiZmxleCIsZmxleERpcmVjdGlvbjoicm93IixhbGlnbkl0ZW1zOiJjZW50ZXIiLHBvc2l0aW9uOiJhYnNvbHV0ZSIsbGVmdDoiNnB4In19LGEuY3JlYXRlRWxlbWVudChsLmRlZmF1bHQse3NldHRpbmdzOnIsaXNQb2xsaW5nU2NoZW1hOnRoaXMucHJvcHMuaXNQb2xsaW5nU2NoZW1hLG9uUmVsb2FkU2NoZW1hOnRoaXMucHJvcHMucmVmZXRjaFNjaGVtYX0pKSksYS5jcmVhdGVFbGVtZW50KHQuQnV0dG9uLHtvbkNsaWNrOnRoaXMuY29weUN1cmxUb0NsaXBib2FyZH0sIkNvcHkgQ1VSTCIpLHRoaXMucHJvcHMuc2hhcmVFbmFibGVkJiZhLmNyZWF0ZUVsZW1lbnQoYy5kZWZhdWx0LG51bGwsYS5jcmVhdGVFbGVtZW50KHQuQnV0dG9uLG51bGwsIlNoYXJlIFBsYXlncm91bmQiKSkpfSxuLmNvbnRleHRUeXBlcz17c3RvcmU6bS5zaGFwZSh7c3Vic2NyaWJlOm0uZnVuYy5pc1JlcXVpcmVkLGRpc3BhdGNoOm0uZnVuYy5pc1JlcXVpcmVkLGdldFN0YXRlOm0uZnVuYy5pc1JlcXVpcmVkfSl9LG59KGEuQ29tcG9uZW50KSxDPXAuY3JlYXRlU3RydWN0dXJlZFNlbGVjdG9yKHtlbmRwb2ludDpmLmdldEVuZHBvaW50LGZpeGVkRW5kcG9pbnQ6aC5nZXRGaXhlZEVuZHBvaW50LGlzUG9sbGluZ1NjaGVtYTpmLmdldElzUG9sbGluZ1NjaGVtYSxlbmRwb2ludFVucmVhY2hhYmxlOmYuZ2V0RW5kcG9pbnRVbnJlYWNoYWJsZSxzZXR0aW5nczpiLmdldFNldHRpbmdzfSk7dC5kZWZhdWx0PWQuY29ubmVjdChDLHtlZGl0RW5kcG9pbnQ6Zy5lZGl0RW5kcG9pbnQscHJldHRpZnlRdWVyeTpnLnByZXR0aWZ5UXVlcnksb3Blbkhpc3Rvcnk6di5vcGVuSGlzdG9yeSxzaGFyZTp5LnNoYXJlLHJlZmV0Y2hTY2hlbWE6Zy5yZWZldGNoU2NoZW1hfSkoeCksdC5CdXR0b249cy5zdHlsZWQuYnV0dG9uKEV8fChFPWkoWyJcbiAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTtcbiAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgY29sb3I6ICIsIjtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBib3JkZXItcmFkaXVzOiAycHg7XG4gIGZsZXg6IDAgMCBhdXRvO1xuICBsZXR0ZXItc3BhY2luZzogMC41M3B4O1xuICBmb250LXNpemU6IDE0cHg7XG4gIHBhZGRpbmc6IDZweCA5cHggN3B4IDEwcHg7XG4gIG1hcmdpbi1sZWZ0OiA2cHg7XG5cbiAgY3Vyc29yOiBwb2ludGVyO1xuICB0cmFuc2l0aW9uOiAwLjFzIGxpbmVhciBiYWNrZ3JvdW5kLWNvbG9yO1xuICAmOmZpcnN0LWNoaWxkIHtcbiAgICBtYXJnaW4tbGVmdDogMDtcbiAgfVxuICAmOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAiLCI7XG4gIH1cbiJdLFsiXG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIGNvbG9yOiAiLCI7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgYm9yZGVyLXJhZGl1czogMnB4O1xuICBmbGV4OiAwIDAgYXV0bztcbiAgbGV0dGVyLXNwYWNpbmc6IDAuNTNweDtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBwYWRkaW5nOiA2cHggOXB4IDdweCAxMHB4O1xuICBtYXJnaW4tbGVmdDogNnB4O1xuXG4gIGN1cnNvcjogcG9pbnRlcjtcbiAgdHJhbnNpdGlvbjogMC4xcyBsaW5lYXIgYmFja2dyb3VuZC1jb2xvcjtcbiAgJjpmaXJzdC1jaGlsZCB7XG4gICAgbWFyZ2luLWxlZnQ6IDA7XG4gIH1cbiAgJjpob3ZlciB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogIiwiO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuYnV0dG9uVGV4dH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5idXR0b259LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuYnV0dG9uSG92ZXJ9KTt2YXIgRSxELHcsUyxrLEEsXyxUPXMuc3R5bGVkLmRpdihEfHwoRD1pKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgcGFkZGluZzogMTBweCAxMHB4IDRweDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgcGFkZGluZzogMTBweCAxMHB4IDRweDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5uYXZpZ2F0aW9uQmFyfSksTz1zLnN0eWxlZCgiaW5wdXQiKSh3fHwodz1pKFsiXG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgYm9yZGVyLXJhZGl1czogNHB4O1xuICBjb2xvcjogIiwiO1xuICBib3JkZXI6IDFweCBzb2xpZCAiLCI7XG4gIHBhZGRpbmc6IDZweCAxMnB4O1xuICBwYWRkaW5nLWxlZnQ6IDMwcHg7XG4gIGZvbnQtc2l6ZTogMTNweDtcbiAgZmxleDogMTtcbiJdLFsiXG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgYm9yZGVyLXJhZGl1czogNHB4O1xuICBjb2xvcjogIiwiO1xuICBib3JkZXI6IDFweCBzb2xpZCAiLCI7XG4gIHBhZGRpbmc6IDZweCAxMnB4O1xuICBwYWRkaW5nLWxlZnQ6IDMwcHg7XG4gIGZvbnQtc2l6ZTogMTNweDtcbiAgZmxleDogMTtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5idXR0b259LGZ1bmN0aW9uKGUpe3JldHVybiBlLmFjdGl2ZT9lLnRoZW1lLmVkaXRvckNvbG91cnMubmF2aWdhdGlvbkJhclRleHQ6ZS50aGVtZS5lZGl0b3JDb2xvdXJzLnRleHRJbmFjdGl2ZX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5iYWNrZ3JvdW5kfSksRj1zLnN0eWxlZC5kaXYoU3x8KFM9aShbIlxuICBmbGV4OiAxO1xuICBtYXJnaW4tbGVmdDogNnB4O1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4iXSxbIlxuICBmbGV4OiAxO1xuICBtYXJnaW4tbGVmdDogNnB4O1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4iXSkpKSxOPXMuc3R5bGVkLmRpdihrfHwoaz1pKFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgcmlnaHQ6IDVweDtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgY29sb3I6ICNmMjVjNTQ7XG4iXSxbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHJpZ2h0OiA1cHg7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGNvbG9yOiAjZjI1YzU0O1xuIl0pKSksST1zLnN0eWxlZC5kaXYoQXx8KEE9aShbIlxuICB3aWR0aDogMTZweDtcbiAgaGVpZ2h0OiAxNnB4O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAiLCI7XG4gIGJvcmRlci1yYWRpdXM6IDEwMCU7XG4iXSxbIlxuICB3aWR0aDogMTZweDtcbiAgaGVpZ2h0OiAxNnB4O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAiLCI7XG4gIGJvcmRlci1yYWRpdXM6IDEwMCU7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuaWNvbn0pLEw9cy5zdHlsZWQuZGl2KF98fChfPWkoWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBtYXJnaW46IDZweDtcbiJdLFsiXG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgbWFyZ2luOiA2cHg7XG4iXSkpKSxQPWZ1bmN0aW9uKCl7cmV0dXJuIGEuY3JlYXRlRWxlbWVudChMLG51bGwsYS5jcmVhdGVFbGVtZW50KEksbnVsbCkpfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDApLG89bigxKSxhPWZ1bmN0aW9uKCl7cmV0dXJuIGkuY3JlYXRlRWxlbWVudCh1LG51bGwsaS5jcmVhdGVFbGVtZW50KGMsbnVsbCkpfSxzPW8ua2V5ZnJhbWVzKGx8fChsPXIoWyJcbiAgZnJvbSB7XG4gICAgdHJhbnNmb3JtOiByb3RhdGUoMGRlZyk7XG4gIH1cbiAgdG8ge1xuICAgIHRyYW5zZm9ybTogcm90YXRlKDM1OWRlZyk7XG4gIH1cbiJdLFsiXG4gIGZyb20ge1xuICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpO1xuICB9XG4gIHRvIHtcbiAgICB0cmFuc2Zvcm06IHJvdGF0ZSgzNTlkZWcpO1xuICB9XG4iXSkpKSx1PW8uc3R5bGVkLmRpdihwfHwocD1yKFsiXG4gIGhlaWdodDogMzZweDtcbiAgbGVmdDogNTAlO1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogNTAlO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNTAlKTtcbiAgd2lkdGg6IDM2cHg7XG4gIHotaW5kZXg6IDEwO1xuIl0sWyJcbiAgaGVpZ2h0OiAzNnB4O1xuICBsZWZ0OiA1MCU7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiA1MCU7XG4gIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpO1xuICB3aWR0aDogMzZweDtcbiAgei1pbmRleDogMTA7XG4iXSkpKSxjPW8uc3R5bGVkLmRpdihmfHwoZj1yKFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICBoZWlnaHQ6IDI0cHg7XG4gIHdpZHRoOiAyNHB4O1xuICB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO1xuXG4gIGFuaW1hdGlvbjogIiwiIDAuNnMgaW5maW5pdGUgbGluZWFyO1xuXG4gIGJvcmRlci1yYWRpdXM6IDEwMCU7XG4gIGJvcmRlci1ib3R0b206IDZweCBzb2xpZCByZ2JhKDE1MCwgMTUwLCAxNTAsIDAuMTUpO1xuICBib3JkZXItbGVmdDogNnB4IHNvbGlkIHJnYmEoMTUwLCAxNTAsIDE1MCwgMC4xNSk7XG4gIGJvcmRlci1yaWdodDogNnB4IHNvbGlkIHJnYmEoMTUwLCAxNTAsIDE1MCwgMC4xNSk7XG4gIGJvcmRlci10b3A6IDZweCBzb2xpZCByZ2JhKDE1MCwgMTUwLCAxNTAsIDAuOCk7XG4iXSxbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgaGVpZ2h0OiAyNHB4O1xuICB3aWR0aDogMjRweDtcbiAgdmVydGljYWwtYWxpZ246IG1pZGRsZTtcblxuICBhbmltYXRpb246ICIsIiAwLjZzIGluZmluaXRlIGxpbmVhcjtcblxuICBib3JkZXItcmFkaXVzOiAxMDAlO1xuICBib3JkZXItYm90dG9tOiA2cHggc29saWQgcmdiYSgxNTAsIDE1MCwgMTUwLCAwLjE1KTtcbiAgYm9yZGVyLWxlZnQ6IDZweCBzb2xpZCByZ2JhKDE1MCwgMTUwLCAxNTAsIDAuMTUpO1xuICBib3JkZXItcmlnaHQ6IDZweCBzb2xpZCByZ2JhKDE1MCwgMTUwLCAxNTAsIDAuMTUpO1xuICBib3JkZXItdG9wOiA2cHggc29saWQgcmdiYSgxNTAsIDE1MCwgMTUwLCAwLjgpO1xuIl0pKSxzKTt0LmRlZmF1bHQ9YTt2YXIgbCxwLGZ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3RoaXMuX19ydWxlc19fPVtdLHRoaXMuX19jYWNoZV9fPW51bGx9ci5wcm90b3R5cGUuX19maW5kX189ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTA7dDx0aGlzLl9fcnVsZXNfXy5sZW5ndGg7dCsrKWlmKHRoaXMuX19ydWxlc19fW3RdLm5hbWU9PT1lKXJldHVybiB0O3JldHVybi0xfSxyLnByb3RvdHlwZS5fX2NvbXBpbGVfXz1mdW5jdGlvbigpe3ZhciBlPXRoaXMsdD1bIiJdO2UuX19ydWxlc19fLmZvckVhY2goZnVuY3Rpb24oZSl7ZS5lbmFibGVkJiZlLmFsdC5mb3JFYWNoKGZ1bmN0aW9uKGUpe3QuaW5kZXhPZihlKTwwJiZ0LnB1c2goZSl9KX0pLGUuX19jYWNoZV9fPXt9LHQuZm9yRWFjaChmdW5jdGlvbih0KXtlLl9fY2FjaGVfX1t0XT1bXSxlLl9fcnVsZXNfXy5mb3JFYWNoKGZ1bmN0aW9uKG4pe24uZW5hYmxlZCYmKHQmJm4uYWx0LmluZGV4T2YodCk8MHx8ZS5fX2NhY2hlX19bdF0ucHVzaChuLmZuKSl9KX0pfSxyLnByb3RvdHlwZS5hdD1mdW5jdGlvbihlLHQsbil7dmFyIHI9dGhpcy5fX2ZpbmRfXyhlKSxpPW58fHt9O2lmKC0xPT09cil0aHJvdyBuZXcgRXJyb3IoIlBhcnNlciBydWxlIG5vdCBmb3VuZDogIitlKTt0aGlzLl9fcnVsZXNfX1tyXS5mbj10LHRoaXMuX19ydWxlc19fW3JdLmFsdD1pLmFsdHx8W10sdGhpcy5fX2NhY2hlX189bnVsbH0sci5wcm90b3R5cGUuYmVmb3JlPWZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpPXRoaXMuX19maW5kX18oZSksbz1yfHx7fTtpZigtMT09PWkpdGhyb3cgbmV3IEVycm9yKCJQYXJzZXIgcnVsZSBub3QgZm91bmQ6ICIrZSk7dGhpcy5fX3J1bGVzX18uc3BsaWNlKGksMCx7bmFtZTp0LGVuYWJsZWQ6ITAsZm46bixhbHQ6by5hbHR8fFtdfSksdGhpcy5fX2NhY2hlX189bnVsbH0sci5wcm90b3R5cGUuYWZ0ZXI9ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9dGhpcy5fX2ZpbmRfXyhlKSxvPXJ8fHt9O2lmKC0xPT09aSl0aHJvdyBuZXcgRXJyb3IoIlBhcnNlciBydWxlIG5vdCBmb3VuZDogIitlKTt0aGlzLl9fcnVsZXNfXy5zcGxpY2UoaSsxLDAse25hbWU6dCxlbmFibGVkOiEwLGZuOm4sYWx0Om8uYWx0fHxbXX0pLHRoaXMuX19jYWNoZV9fPW51bGx9LHIucHJvdG90eXBlLnB1c2g9ZnVuY3Rpb24oZSx0LG4pe3ZhciByPW58fHt9O3RoaXMuX19ydWxlc19fLnB1c2goe25hbWU6ZSxlbmFibGVkOiEwLGZuOnQsYWx0OnIuYWx0fHxbXX0pLHRoaXMuX19jYWNoZV9fPW51bGx9LHIucHJvdG90eXBlLmVuYWJsZT1mdW5jdGlvbihlLHQpe0FycmF5LmlzQXJyYXkoZSl8fChlPVtlXSk7dmFyIG49W107cmV0dXJuIGUuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgcj10aGlzLl9fZmluZF9fKGUpO2lmKHI8MCl7aWYodClyZXR1cm47dGhyb3cgbmV3IEVycm9yKCJSdWxlcyBtYW5hZ2VyOiBpbnZhbGlkIHJ1bGUgbmFtZSAiK2UpfXRoaXMuX19ydWxlc19fW3JdLmVuYWJsZWQ9ITAsbi5wdXNoKGUpfSx0aGlzKSx0aGlzLl9fY2FjaGVfXz1udWxsLG59LHIucHJvdG90eXBlLmVuYWJsZU9ubHk9ZnVuY3Rpb24oZSx0KXtBcnJheS5pc0FycmF5KGUpfHwoZT1bZV0pLHRoaXMuX19ydWxlc19fLmZvckVhY2goZnVuY3Rpb24oZSl7ZS5lbmFibGVkPSExfSksdGhpcy5lbmFibGUoZSx0KX0sci5wcm90b3R5cGUuZGlzYWJsZT1mdW5jdGlvbihlLHQpe0FycmF5LmlzQXJyYXkoZSl8fChlPVtlXSk7dmFyIG49W107cmV0dXJuIGUuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgcj10aGlzLl9fZmluZF9fKGUpO2lmKHI8MCl7aWYodClyZXR1cm47dGhyb3cgbmV3IEVycm9yKCJSdWxlcyBtYW5hZ2VyOiBpbnZhbGlkIHJ1bGUgbmFtZSAiK2UpfXRoaXMuX19ydWxlc19fW3JdLmVuYWJsZWQ9ITEsbi5wdXNoKGUpfSx0aGlzKSx0aGlzLl9fY2FjaGVfXz1udWxsLG59LHIucHJvdG90eXBlLmdldFJ1bGVzPWZ1bmN0aW9uKGUpe3JldHVybiBudWxsPT09dGhpcy5fX2NhY2hlX18mJnRoaXMuX19jb21waWxlX18oKSx0aGlzLl9fY2FjaGVfX1tlXXx8W119LGUuZXhwb3J0cz1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4pe3RoaXMudHlwZT1lLHRoaXMudGFnPXQsdGhpcy5hdHRycz1udWxsLHRoaXMubWFwPW51bGwsdGhpcy5uZXN0aW5nPW4sdGhpcy5sZXZlbD0wLHRoaXMuY2hpbGRyZW49bnVsbCx0aGlzLmNvbnRlbnQ9IiIsdGhpcy5tYXJrdXA9IiIsdGhpcy5pbmZvPSIiLHRoaXMubWV0YT1udWxsLHRoaXMuYmxvY2s9ITEsdGhpcy5oaWRkZW49ITF9ci5wcm90b3R5cGUuYXR0ckluZGV4PWZ1bmN0aW9uKGUpe3ZhciB0LG4scjtpZighdGhpcy5hdHRycylyZXR1cm4tMTtmb3IodD10aGlzLmF0dHJzLG49MCxyPXQubGVuZ3RoO248cjtuKyspaWYodFtuXVswXT09PWUpcmV0dXJuIG47cmV0dXJuLTF9LHIucHJvdG90eXBlLmF0dHJQdXNoPWZ1bmN0aW9uKGUpe3RoaXMuYXR0cnM/dGhpcy5hdHRycy5wdXNoKGUpOnRoaXMuYXR0cnM9W2VdfSxyLnByb3RvdHlwZS5hdHRyU2V0PWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5hdHRySW5kZXgoZSkscj1bZSx0XTtuPDA/dGhpcy5hdHRyUHVzaChyKTp0aGlzLmF0dHJzW25dPXJ9LHIucHJvdG90eXBlLmF0dHJHZXQ9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5hdHRySW5kZXgoZSksbj1udWxsO3JldHVybiB0Pj0wJiYobj10aGlzLmF0dHJzW3RdWzFdKSxufSxyLnByb3RvdHlwZS5hdHRySm9pbj1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMuYXR0ckluZGV4KGUpO248MD90aGlzLmF0dHJQdXNoKFtlLHRdKTp0aGlzLmF0dHJzW25dWzFdPXRoaXMuYXR0cnNbbl1bMV0rIiAiK3R9LGUuZXhwb3J0cz1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPW4oMSk7dC5Eb2NUeXBlPWkuc3R5bGVkLmRpdihvfHwobz1yKFsiXG4gIHBhZGRpbmc6IDIwcHggMTZweCAwIDE2cHg7XG4gIG92ZXJmbG93OiBhdXRvO1xuICBmb250LXNpemU6IDE0cHg7XG4iXSxbIlxuICBwYWRkaW5nOiAyMHB4IDE2cHggMCAxNnB4O1xuICBvdmVyZmxvdzogYXV0bztcbiAgZm9udC1zaXplOiAxNHB4O1xuIl0pKSk7dmFyIG99LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7aWYobil7dmFyIHI9ZS5wcm9qZWN0c1tuXS5leHRlbnNpb25zLmVuZHBvaW50c1t0XTtyZXR1cm4gaShyKX12YXIgcj1lLmV4dGVuc2lvbnMuZW5kcG9pbnRzW3RdO3JldHVybiBpKHIpfWZ1bmN0aW9uIGkoZSl7cmV0dXJuInN0cmluZyI9PT10eXBlb2YgZT97ZW5kcG9pbnQ6ZSxzdWJzY3JpcHRpb25FbmRwb2ludDp2b2lkIDB9OntlbmRwb2ludDplLnVybCxzdWJzY3JpcHRpb25FbmRwb2ludDplLnN1YnNjcmlwdGlvbj9lLnN1YnNjcmlwdGlvbi51cmw6dm9pZCAwLGhlYWRlcnM6ZS5oZWFkZXJzfX1mdW5jdGlvbiBvKGUpe3ZhciB0PXUuZ2V0KGUpO2lmKHQpcmV0dXJuIHQ7dmFyIG49YS5wcmludFNjaGVtYShlKTtyZXR1cm4gdS5zZXQoZSxuKSxufU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgYT1uKDcpLHM9bigyNTIpO3QuZ2V0QWN0aXZlRW5kcG9pbnRzPXIsdC5nZXRFbmRwb2ludEZyb21FbmRwb2ludENvbmZpZz1pO3ZhciB1PW5ldyBzKHttYXg6MTB9KTt0LmNhY2hlZFByaW50U2NoZW1hPW99LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big1Myk7ZS5leHBvcnRzPW5ldyByKHtleHBsaWNpdDpbbig3MjYpLG4oNzI3KSxuKDcyOCldfSl9LCxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcixpPW4oMjMpO3Quc2VsZWN0V29ya3NwYWNlPShyPWkuY3JlYXRlQWN0aW9ucyh7U0VMRUNUX1dPUktTUEFDRTpmdW5jdGlvbihlKXtyZXR1cm57d29ya3NwYWNlOmV9fSxJTklUX1NUQVRFOmZ1bmN0aW9uKGUsdCl7cmV0dXJue3dvcmtzcGFjZUlkOmUsZW5kcG9pbnQ6dH19LElOSkVDVF9TVEFURTpmdW5jdGlvbihlKXtyZXR1cm57c3RhdGU6ZX19LElOSkVDVF9UQUJTOmZ1bmN0aW9uKGUpe3JldHVybnt0YWJzOmV9fX0pLHIuc2VsZWN0V29ya3NwYWNlKSx0LmluaXRTdGF0ZT1yLmluaXRTdGF0ZSx0LmluamVjdFN0YXRlPXIuaW5qZWN0U3RhdGUsdC5pbmplY3RUYWJzPXIuaW5qZWN0VGFic30sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKCl7fWZ1bmN0aW9uIGkoZSl7dHJ5e3JldHVybiBlLnRoZW59Y2F0Y2goZSl7cmV0dXJuIHk9ZSx2fX1mdW5jdGlvbiBvKGUsdCl7dHJ5e3JldHVybiBlKHQpfWNhdGNoKGUpe3JldHVybiB5PWUsdn19ZnVuY3Rpb24gYShlLHQsbil7dHJ5e2UodCxuKX1jYXRjaChlKXtyZXR1cm4geT1lLHZ9fWZ1bmN0aW9uIHMoZSl7aWYoIm9iamVjdCIhPT10eXBlb2YgdGhpcyl0aHJvdyBuZXcgVHlwZUVycm9yKCJQcm9taXNlcyBtdXN0IGJlIGNvbnN0cnVjdGVkIHZpYSBuZXciKTtpZigiZnVuY3Rpb24iIT09dHlwZW9mIGUpdGhyb3cgbmV3IFR5cGVFcnJvcigiUHJvbWlzZSBjb25zdHJ1Y3RvcidzIGFyZ3VtZW50IGlzIG5vdCBhIGZ1bmN0aW9uIik7dGhpcy5fNzU9MCx0aGlzLl84Mz0wLHRoaXMuXzE4PW51bGwsdGhpcy5fMzg9bnVsbCxlIT09ciYmbShlLHRoaXMpfWZ1bmN0aW9uIHUoZSx0LG4pe3JldHVybiBuZXcgZS5jb25zdHJ1Y3RvcihmdW5jdGlvbihpLG8pe3ZhciBhPW5ldyBzKHIpO2EudGhlbihpLG8pLGMoZSxuZXcgaCh0LG4sYSkpfSl9ZnVuY3Rpb24gYyhlLHQpe2Zvcig7Mz09PWUuXzgzOyllPWUuXzE4O2lmKHMuXzQ3JiZzLl80NyhlKSwwPT09ZS5fODMpcmV0dXJuIDA9PT1lLl83NT8oZS5fNzU9MSx2b2lkKGUuXzM4PXQpKToxPT09ZS5fNzU/KGUuXzc1PTIsdm9pZChlLl8zOD1bZS5fMzgsdF0pKTp2b2lkIGUuXzM4LnB1c2godCk7bChlLHQpfWZ1bmN0aW9uIGwoZSx0KXtnKGZ1bmN0aW9uKCl7dmFyIG49MT09PWUuXzgzP3Qub25GdWxmaWxsZWQ6dC5vblJlamVjdGVkO2lmKG51bGw9PT1uKXJldHVybiB2b2lkKDE9PT1lLl84Mz9wKHQucHJvbWlzZSxlLl8xOCk6Zih0LnByb21pc2UsZS5fMTgpKTt2YXIgcj1vKG4sZS5fMTgpO3I9PT12P2YodC5wcm9taXNlLHkpOnAodC5wcm9taXNlLHIpfSl9ZnVuY3Rpb24gcChlLHQpe2lmKHQ9PT1lKXJldHVybiBmKGUsbmV3IFR5cGVFcnJvcigiQSBwcm9taXNlIGNhbm5vdCBiZSByZXNvbHZlZCB3aXRoIGl0c2VsZi4iKSk7aWYodCYmKCJvYmplY3QiPT09dHlwZW9mIHR8fCJmdW5jdGlvbiI9PT10eXBlb2YgdCkpe3ZhciBuPWkodCk7aWYobj09PXYpcmV0dXJuIGYoZSx5KTtpZihuPT09ZS50aGVuJiZ0IGluc3RhbmNlb2YgcylyZXR1cm4gZS5fODM9MyxlLl8xOD10LHZvaWQgZChlKTtpZigiZnVuY3Rpb24iPT09dHlwZW9mIG4pcmV0dXJuIHZvaWQgbShuLmJpbmQodCksZSl9ZS5fODM9MSxlLl8xOD10LGQoZSl9ZnVuY3Rpb24gZihlLHQpe2UuXzgzPTIsZS5fMTg9dCxzLl83MSYmcy5fNzEoZSx0KSxkKGUpfWZ1bmN0aW9uIGQoZSl7aWYoMT09PWUuXzc1JiYoYyhlLGUuXzM4KSxlLl8zOD1udWxsKSwyPT09ZS5fNzUpe2Zvcih2YXIgdD0wO3Q8ZS5fMzgubGVuZ3RoO3QrKyljKGUsZS5fMzhbdF0pO2UuXzM4PW51bGx9fWZ1bmN0aW9uIGgoZSx0LG4pe3RoaXMub25GdWxmaWxsZWQ9ImZ1bmN0aW9uIj09PXR5cGVvZiBlP2U6bnVsbCx0aGlzLm9uUmVqZWN0ZWQ9ImZ1bmN0aW9uIj09PXR5cGVvZiB0P3Q6bnVsbCx0aGlzLnByb21pc2U9bn1mdW5jdGlvbiBtKGUsdCl7dmFyIG49ITEscj1hKGUsZnVuY3Rpb24oZSl7bnx8KG49ITAscCh0LGUpKX0sZnVuY3Rpb24oZSl7bnx8KG49ITAsZih0LGUpKX0pO258fHIhPT12fHwobj0hMCxmKHQseSkpfXZhciBnPW4oMzExKSx5PW51bGwsdj17fTtlLmV4cG9ydHM9cyxzLl80Nz1udWxsLHMuXzcxPW51bGwscy5fNDQ9cixzLnByb3RvdHlwZS50aGVuPWZ1bmN0aW9uKGUsdCl7aWYodGhpcy5jb25zdHJ1Y3RvciE9PXMpcmV0dXJuIHUodGhpcyxlLHQpO3ZhciBuPW5ldyBzKHIpO3JldHVybiBjKHRoaXMsbmV3IGgoZSx0LG4pKSxufX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj17fTtlLmV4cG9ydHM9cn0sLCxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO24uZCh0LCJiIixmdW5jdGlvbigpe3JldHVybiBvfSksbi5kKHQsImEiLGZ1bmN0aW9uKCl7cmV0dXJuIGF9KTt2YXIgcj1uKDE4KSxpPW4ubihyKSxvPWkuYS5zaGFwZSh7dHJ5U3Vic2NyaWJlOmkuYS5mdW5jLmlzUmVxdWlyZWQsdHJ5VW5zdWJzY3JpYmU6aS5hLmZ1bmMuaXNSZXF1aXJlZCxub3RpZnlOZXN0ZWRTdWJzOmkuYS5mdW5jLmlzUmVxdWlyZWQsaXNTdWJzY3JpYmVkOmkuYS5mdW5jLmlzUmVxdWlyZWR9KSxhPWkuYS5zaGFwZSh7c3Vic2NyaWJlOmkuYS5mdW5jLmlzUmVxdWlyZWQsZGlzcGF0Y2g6aS5hLmZ1bmMuaXNSZXF1aXJlZCxnZXRTdGF0ZTppLmEuZnVuYy5pc1JlcXVpcmVkfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2lmKCEoZSBpbnN0YW5jZW9mIHQpKXRocm93IG5ldyBUeXBlRXJyb3IoIkNhbm5vdCBjYWxsIGEgY2xhc3MgYXMgYSBmdW5jdGlvbiIpfWZ1bmN0aW9uIGkoZSx0KXtpZighZSl0aHJvdyBuZXcgUmVmZXJlbmNlRXJyb3IoInRoaXMgaGFzbid0IGJlZW4gaW5pdGlhbGlzZWQgLSBzdXBlcigpIGhhc24ndCBiZWVuIGNhbGxlZCIpO3JldHVybiF0fHwib2JqZWN0IiE9PXR5cGVvZiB0JiYiZnVuY3Rpb24iIT09dHlwZW9mIHQ/ZTp0fWZ1bmN0aW9uIG8oZSx0KXtpZigiZnVuY3Rpb24iIT09dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIlN1cGVyIGV4cHJlc3Npb24gbXVzdCBlaXRoZXIgYmUgbnVsbCBvciBhIGZ1bmN0aW9uLCBub3QgIit0eXBlb2YgdCk7ZS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZSh0JiZ0LnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOmUsZW51bWVyYWJsZTohMSx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9fSksdCYmKE9iamVjdC5zZXRQcm90b3R5cGVPZj9PYmplY3Quc2V0UHJvdG90eXBlT2YoZSx0KTplLl9fcHJvdG9fXz10KX1mdW5jdGlvbiBhKGUsdCl7dmFyIG49e307Zm9yKHZhciByIGluIGUpdC5pbmRleE9mKHIpPj0wfHxPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxyKSYmKG5bcl09ZVtyXSk7cmV0dXJuIG59ZnVuY3Rpb24gcygpe31mdW5jdGlvbiB1KGUsdCl7dmFyIG49e3J1bjpmdW5jdGlvbihyKXt0cnl7dmFyIGk9ZSh0LmdldFN0YXRlKCkscik7KGkhPT1uLnByb3BzfHxuLmVycm9yKSYmKG4uc2hvdWxkQ29tcG9uZW50VXBkYXRlPSEwLG4ucHJvcHM9aSxuLmVycm9yPW51bGwpfWNhdGNoKGUpe24uc2hvdWxkQ29tcG9uZW50VXBkYXRlPSEwLG4uZXJyb3I9ZX19fTtyZXR1cm4gbn1mdW5jdGlvbiBjKGUpe3ZhciB0LG4sYz1hcmd1bWVudHMubGVuZ3RoPjEmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXT9hcmd1bWVudHNbMV06e30sbD1jLmdldERpc3BsYXlOYW1lLGY9dm9pZCAwPT09bD9mdW5jdGlvbihlKXtyZXR1cm4iQ29ubmVjdEFkdmFuY2VkKCIrZSsiKSJ9OmwseD1jLm1ldGhvZE5hbWUsQz12b2lkIDA9PT14PyJjb25uZWN0QWR2YW5jZWQiOngsRT1jLnJlbmRlckNvdW50UHJvcCxEPXZvaWQgMD09PUU/dm9pZCAwOkUsdz1jLnNob3VsZEhhbmRsZVN0YXRlQ2hhbmdlcyxTPXZvaWQgMD09PXd8fHcsaz1jLnN0b3JlS2V5LEE9dm9pZCAwPT09az8ic3RvcmUiOmssXz1jLndpdGhSZWYsVD12b2lkIDAhPT1fJiZfLE89YShjLFsiZ2V0RGlzcGxheU5hbWUiLCJtZXRob2ROYW1lIiwicmVuZGVyQ291bnRQcm9wIiwic2hvdWxkSGFuZGxlU3RhdGVDaGFuZ2VzIiwic3RvcmVLZXkiLCJ3aXRoUmVmIl0pLEY9QSsiU3Vic2NyaXB0aW9uIixOPXYrKyxJPSh0PXt9LHRbQV09Zy5hLHRbRl09Zy5iLHQpLEw9KG49e30sbltGXT1nLmIsbik7cmV0dXJuIGZ1bmN0aW9uKHQpe2QoKSgiZnVuY3Rpb24iPT10eXBlb2YgdCwiWW91IG11c3QgcGFzcyBhIGNvbXBvbmVudCB0byB0aGUgZnVuY3Rpb24gcmV0dXJuZWQgYnkgIitDKyIuIEluc3RlYWQgcmVjZWl2ZWQgIitKU09OLnN0cmluZ2lmeSh0KSk7dmFyIG49dC5kaXNwbGF5TmFtZXx8dC5uYW1lfHwiQ29tcG9uZW50IixhPWYobiksYz15KHt9LE8se2dldERpc3BsYXlOYW1lOmYsbWV0aG9kTmFtZTpDLHJlbmRlckNvdW50UHJvcDpELHNob3VsZEhhbmRsZVN0YXRlQ2hhbmdlczpTLHN0b3JlS2V5OkEsd2l0aFJlZjpULGRpc3BsYXlOYW1lOmEsd3JhcHBlZENvbXBvbmVudE5hbWU6bixXcmFwcGVkQ29tcG9uZW50OnR9KSxsPWZ1bmN0aW9uKG4pe2Z1bmN0aW9uIGwoZSx0KXtyKHRoaXMsbCk7dmFyIG89aSh0aGlzLG4uY2FsbCh0aGlzLGUsdCkpO3JldHVybiBvLnZlcnNpb249TixvLnN0YXRlPXt9LG8ucmVuZGVyQ291bnQ9MCxvLnN0b3JlPWVbQV18fHRbQV0sby5wcm9wc01vZGU9Qm9vbGVhbihlW0FdKSxvLnNldFdyYXBwZWRJbnN0YW5jZT1vLnNldFdyYXBwZWRJbnN0YW5jZS5iaW5kKG8pLGQoKShvLnN0b3JlLCdDb3VsZCBub3QgZmluZCAiJytBKyciIGluIGVpdGhlciB0aGUgY29udGV4dCBvciBwcm9wcyBvZiAiJythKyciLiBFaXRoZXIgd3JhcCB0aGUgcm9vdCBjb21wb25lbnQgaW4gYSA8UHJvdmlkZXI+LCBvciBleHBsaWNpdGx5IHBhc3MgIicrQSsnIiBhcyBhIHByb3AgdG8gIicrYSsnIi4nKSxvLmluaXRTZWxlY3RvcigpLG8uaW5pdFN1YnNjcmlwdGlvbigpLG99cmV0dXJuIG8obCxuKSxsLnByb3RvdHlwZS5nZXRDaGlsZENvbnRleHQ9ZnVuY3Rpb24oKXt2YXIgZSx0PXRoaXMucHJvcHNNb2RlP251bGw6dGhpcy5zdWJzY3JpcHRpb247cmV0dXJuIGU9e30sZVtGXT10fHx0aGlzLmNvbnRleHRbRl0sZX0sbC5wcm90b3R5cGUuY29tcG9uZW50RGlkTW91bnQ9ZnVuY3Rpb24oKXtTJiYodGhpcy5zdWJzY3JpcHRpb24udHJ5U3Vic2NyaWJlKCksdGhpcy5zZWxlY3Rvci5ydW4odGhpcy5wcm9wcyksdGhpcy5zZWxlY3Rvci5zaG91bGRDb21wb25lbnRVcGRhdGUmJnRoaXMuZm9yY2VVcGRhdGUoKSl9LGwucHJvdG90eXBlLmNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHM9ZnVuY3Rpb24oZSl7dGhpcy5zZWxlY3Rvci5ydW4oZSl9LGwucHJvdG90eXBlLnNob3VsZENvbXBvbmVudFVwZGF0ZT1mdW5jdGlvbigpe3JldHVybiB0aGlzLnNlbGVjdG9yLnNob3VsZENvbXBvbmVudFVwZGF0ZX0sbC5wcm90b3R5cGUuY29tcG9uZW50V2lsbFVubW91bnQ9ZnVuY3Rpb24oKXt0aGlzLnN1YnNjcmlwdGlvbiYmdGhpcy5zdWJzY3JpcHRpb24udHJ5VW5zdWJzY3JpYmUoKSx0aGlzLnN1YnNjcmlwdGlvbj1udWxsLHRoaXMubm90aWZ5TmVzdGVkU3Vicz1zLHRoaXMuc3RvcmU9bnVsbCx0aGlzLnNlbGVjdG9yLnJ1bj1zLHRoaXMuc2VsZWN0b3Iuc2hvdWxkQ29tcG9uZW50VXBkYXRlPSExfSxsLnByb3RvdHlwZS5nZXRXcmFwcGVkSW5zdGFuY2U9ZnVuY3Rpb24oKXtyZXR1cm4gZCgpKFQsIlRvIGFjY2VzcyB0aGUgd3JhcHBlZCBpbnN0YW5jZSwgeW91IG5lZWQgdG8gc3BlY2lmeSB7IHdpdGhSZWY6IHRydWUgfSBpbiB0aGUgb3B0aW9ucyBhcmd1bWVudCBvZiB0aGUgIitDKyIoKSBjYWxsLiIpLHRoaXMud3JhcHBlZEluc3RhbmNlfSxsLnByb3RvdHlwZS5zZXRXcmFwcGVkSW5zdGFuY2U9ZnVuY3Rpb24oZSl7dGhpcy53cmFwcGVkSW5zdGFuY2U9ZX0sbC5wcm90b3R5cGUuaW5pdFNlbGVjdG9yPWZ1bmN0aW9uKCl7dmFyIHQ9ZSh0aGlzLnN0b3JlLmRpc3BhdGNoLGMpO3RoaXMuc2VsZWN0b3I9dSh0LHRoaXMuc3RvcmUpLHRoaXMuc2VsZWN0b3IucnVuKHRoaXMucHJvcHMpfSxsLnByb3RvdHlwZS5pbml0U3Vic2NyaXB0aW9uPWZ1bmN0aW9uKCl7aWYoUyl7dmFyIGU9KHRoaXMucHJvcHNNb2RlP3RoaXMucHJvcHM6dGhpcy5jb250ZXh0KVtGXTt0aGlzLnN1YnNjcmlwdGlvbj1uZXcgbS5hKHRoaXMuc3RvcmUsZSx0aGlzLm9uU3RhdGVDaGFuZ2UuYmluZCh0aGlzKSksdGhpcy5ub3RpZnlOZXN0ZWRTdWJzPXRoaXMuc3Vic2NyaXB0aW9uLm5vdGlmeU5lc3RlZFN1YnMuYmluZCh0aGlzLnN1YnNjcmlwdGlvbil9fSxsLnByb3RvdHlwZS5vblN0YXRlQ2hhbmdlPWZ1bmN0aW9uKCl7dGhpcy5zZWxlY3Rvci5ydW4odGhpcy5wcm9wcyksdGhpcy5zZWxlY3Rvci5zaG91bGRDb21wb25lbnRVcGRhdGU/KHRoaXMuY29tcG9uZW50RGlkVXBkYXRlPXRoaXMubm90aWZ5TmVzdGVkU3Vic09uQ29tcG9uZW50RGlkVXBkYXRlLHRoaXMuc2V0U3RhdGUoYikpOnRoaXMubm90aWZ5TmVzdGVkU3VicygpfSxsLnByb3RvdHlwZS5ub3RpZnlOZXN0ZWRTdWJzT25Db21wb25lbnREaWRVcGRhdGU9ZnVuY3Rpb24oKXt0aGlzLmNvbXBvbmVudERpZFVwZGF0ZT12b2lkIDAsdGhpcy5ub3RpZnlOZXN0ZWRTdWJzKCl9LGwucHJvdG90eXBlLmlzU3Vic2NyaWJlZD1mdW5jdGlvbigpe3JldHVybiBCb29sZWFuKHRoaXMuc3Vic2NyaXB0aW9uKSYmdGhpcy5zdWJzY3JpcHRpb24uaXNTdWJzY3JpYmVkKCl9LGwucHJvdG90eXBlLmFkZEV4dHJhUHJvcHM9ZnVuY3Rpb24oZSl7aWYoIVQmJiFEJiYoIXRoaXMucHJvcHNNb2RlfHwhdGhpcy5zdWJzY3JpcHRpb24pKXJldHVybiBlO3ZhciB0PXkoe30sZSk7cmV0dXJuIFQmJih0LnJlZj10aGlzLnNldFdyYXBwZWRJbnN0YW5jZSksRCYmKHRbRF09dGhpcy5yZW5kZXJDb3VudCsrKSx0aGlzLnByb3BzTW9kZSYmdGhpcy5zdWJzY3JpcHRpb24mJih0W0ZdPXRoaXMuc3Vic2NyaXB0aW9uKSx0fSxsLnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnNlbGVjdG9yO2lmKGUuc2hvdWxkQ29tcG9uZW50VXBkYXRlPSExLGUuZXJyb3IpdGhyb3cgZS5lcnJvcjtyZXR1cm4gT2JqZWN0KGguY3JlYXRlRWxlbWVudCkodCx0aGlzLmFkZEV4dHJhUHJvcHMoZS5wcm9wcykpfSxsfShoLkNvbXBvbmVudCk7cmV0dXJuIGwuV3JhcHBlZENvbXBvbmVudD10LGwuZGlzcGxheU5hbWU9YSxsLmNoaWxkQ29udGV4dFR5cGVzPUwsbC5jb250ZXh0VHlwZXM9SSxsLnByb3BUeXBlcz1JLHAoKShsLHQpfX10LmE9Yzt2YXIgbD1uKDMzMCkscD1uLm4obCksZj1uKDIwKSxkPW4ubihmKSxoPW4oMCksbT0obi5uKGgpLG4oMzMxKSksZz1uKDE1NSkseT1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfSx2PTAsYj17fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXtmdW5jdGlvbiBvKCl7eT09PWcmJih5PWcuc2xpY2UoKSl9ZnVuY3Rpb24gdSgpe3JldHVybiBtfWZ1bmN0aW9uIGMoZSl7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiBlKXRocm93IG5ldyBFcnJvcigiRXhwZWN0ZWQgbGlzdGVuZXIgdG8gYmUgYSBmdW5jdGlvbi4iKTt2YXIgdD0hMDtyZXR1cm4gbygpLHkucHVzaChlKSxmdW5jdGlvbigpe2lmKHQpe3Q9ITEsbygpO3ZhciBuPXkuaW5kZXhPZihlKTt5LnNwbGljZShuLDEpfX19ZnVuY3Rpb24gbChlKXtpZighT2JqZWN0KGkuYSkoZSkpdGhyb3cgbmV3IEVycm9yKCJBY3Rpb25zIG11c3QgYmUgcGxhaW4gb2JqZWN0cy4gVXNlIGN1c3RvbSBtaWRkbGV3YXJlIGZvciBhc3luYyBhY3Rpb25zLiIpO2lmKCJ1bmRlZmluZWQiPT09dHlwZW9mIGUudHlwZSl0aHJvdyBuZXcgRXJyb3IoJ0FjdGlvbnMgbWF5IG5vdCBoYXZlIGFuIHVuZGVmaW5lZCAidHlwZSIgcHJvcGVydHkuIEhhdmUgeW91IG1pc3NwZWxsZWQgYSBjb25zdGFudD8nKTtpZih2KXRocm93IG5ldyBFcnJvcigiUmVkdWNlcnMgbWF5IG5vdCBkaXNwYXRjaCBhY3Rpb25zLiIpO3RyeXt2PSEwLG09aChtLGUpfWZpbmFsbHl7dj0hMX1mb3IodmFyIHQ9Zz15LG49MDtuPHQubGVuZ3RoO24rKyl7KDAsdFtuXSkoKX1yZXR1cm4gZX1mdW5jdGlvbiBwKGUpe2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgZSl0aHJvdyBuZXcgRXJyb3IoIkV4cGVjdGVkIHRoZSBuZXh0UmVkdWNlciB0byBiZSBhIGZ1bmN0aW9uLiIpO2g9ZSxsKHt0eXBlOnMuSU5JVH0pfWZ1bmN0aW9uIGYoKXt2YXIgZSx0PWM7cmV0dXJuIGU9e3N1YnNjcmliZTpmdW5jdGlvbihlKXtmdW5jdGlvbiBuKCl7ZS5uZXh0JiZlLm5leHQodSgpKX1pZigib2JqZWN0IiE9PXR5cGVvZiBlKXRocm93IG5ldyBUeXBlRXJyb3IoIkV4cGVjdGVkIHRoZSBvYnNlcnZlciB0byBiZSBhbiBvYmplY3QuIik7cmV0dXJuIG4oKSx7dW5zdWJzY3JpYmU6dChuKX19fSxlW2EuYV09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sZX12YXIgZDtpZigiZnVuY3Rpb24iPT09dHlwZW9mIHQmJiJ1bmRlZmluZWQiPT09dHlwZW9mIG4mJihuPXQsdD12b2lkIDApLCJ1bmRlZmluZWQiIT09dHlwZW9mIG4pe2lmKCJmdW5jdGlvbiIhPT10eXBlb2Ygbil0aHJvdyBuZXcgRXJyb3IoIkV4cGVjdGVkIHRoZSBlbmhhbmNlciB0byBiZSBhIGZ1bmN0aW9uLiIpO3JldHVybiBuKHIpKGUsdCl9aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiBlKXRocm93IG5ldyBFcnJvcigiRXhwZWN0ZWQgdGhlIHJlZHVjZXIgdG8gYmUgYSBmdW5jdGlvbi4iKTt2YXIgaD1lLG09dCxnPVtdLHk9Zyx2PSExO3JldHVybiBsKHt0eXBlOnMuSU5JVH0pLGQ9e2Rpc3BhdGNoOmwsc3Vic2NyaWJlOmMsZ2V0U3RhdGU6dSxyZXBsYWNlUmVkdWNlcjpwfSxkW2EuYV09ZixkfW4uZCh0LCJhIixmdW5jdGlvbigpe3JldHVybiBzfSksdC5iPXI7dmFyIGk9bigxNTgpLG89bigzNDMpLGE9bi5uKG8pLHM9e0lOSVQ6IkBAcmVkdXgvSU5JVCJ9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7aWYoIU9iamVjdChhLmEpKGUpfHxPYmplY3QoaS5hKShlKSE9cylyZXR1cm4hMTt2YXIgdD1PYmplY3Qoby5hKShlKTtpZihudWxsPT09dClyZXR1cm4hMDt2YXIgbj1wLmNhbGwodCwiY29uc3RydWN0b3IiKSYmdC5jb25zdHJ1Y3RvcjtyZXR1cm4iZnVuY3Rpb24iPT10eXBlb2YgbiYmbiBpbnN0YW5jZW9mIG4mJmwuY2FsbChuKT09Zn12YXIgaT1uKDMzNSksbz1uKDM0MCksYT1uKDM0Mikscz0iW29iamVjdCBPYmplY3RdIix1PUZ1bmN0aW9uLnByb3RvdHlwZSxjPU9iamVjdC5wcm90b3R5cGUsbD11LnRvU3RyaW5nLHA9Yy5oYXNPd25Qcm9wZXJ0eSxmPWwuY2FsbChPYmplY3QpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oMzM2KSxpPXIuYS5TeW1ib2w7dC5hPWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe2Zvcih2YXIgZT1hcmd1bWVudHMubGVuZ3RoLHQ9QXJyYXkoZSksbj0wO248ZTtuKyspdFtuXT1hcmd1bWVudHNbbl07cmV0dXJuIDA9PT10Lmxlbmd0aD9mdW5jdGlvbihlKXtyZXR1cm4gZX06MT09PXQubGVuZ3RoP3RbMF06dC5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gZSh0LmFwcGx5KHZvaWQgMCxhcmd1bWVudHMpKX19KX10LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXtyZXR1cm4gaX12YXIgaT1lKHQsbik7cmV0dXJuIHIuZGVwZW5kc09uT3duUHJvcHM9ITEscn19ZnVuY3Rpb24gaShlKXtyZXR1cm4gbnVsbCE9PWUuZGVwZW5kc09uT3duUHJvcHMmJnZvaWQgMCE9PWUuZGVwZW5kc09uT3duUHJvcHM/Qm9vbGVhbihlLmRlcGVuZHNPbk93blByb3BzKToxIT09ZS5sZW5ndGh9ZnVuY3Rpb24gbyhlLHQpe3JldHVybiBmdW5jdGlvbih0LG4pe3ZhciByPShuLmRpc3BsYXlOYW1lLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHIuZGVwZW5kc09uT3duUHJvcHM/ci5tYXBUb1Byb3BzKGUsdCk6ci5tYXBUb1Byb3BzKGUpfSk7cmV0dXJuIHIuZGVwZW5kc09uT3duUHJvcHM9ITAsci5tYXBUb1Byb3BzPWZ1bmN0aW9uKHQsbil7ci5tYXBUb1Byb3BzPWUsci5kZXBlbmRzT25Pd25Qcm9wcz1pKGUpO3ZhciBvPXIodCxuKTtyZXR1cm4iZnVuY3Rpb24iPT09dHlwZW9mIG8mJihyLm1hcFRvUHJvcHM9byxyLmRlcGVuZHNPbk93blByb3BzPWkobyksbz1yKHQsbikpLG99LHJ9fXQuYT1yLHQuYj1vO24oMTYzKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtuKDQxKSxuKDEwMSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7KGZ1bmN0aW9uKGUpe3ZhciBuPSJvYmplY3QiPT10eXBlb2YgZSYmZSYmZS5PYmplY3Q9PT1PYmplY3QmJmU7dC5hPW59KS5jYWxsKHQsbigxMSkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4gZnVuY3Rpb24obil7cmV0dXJuIGUodChuKSl9fXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dHJ5e28oKSxlKCl9ZmluYWxseXthKCl9fWZ1bmN0aW9uIGkoZSl7dS5wdXNoKGUpLGN8fChvKCkscygpKX1mdW5jdGlvbiBvKCl7YysrfWZ1bmN0aW9uIGEoKXtjLS19ZnVuY3Rpb24gcygpe2EoKTtmb3IodmFyIGU9dm9pZCAwOyFjJiZ2b2lkIDAhPT0oZT11LnNoaWZ0KCkpOylyKGUpfXQuYT1pLHQuYz1vLHQuYj1zO3ZhciB1PVtdLGM9MH0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuPWFyZ3VtZW50cy5sZW5ndGgscj1BcnJheShuPjI/bi0yOjApLGE9MjthPG47YSsrKXJbYS0yXT1hcmd1bWVudHNbYV07dmFyIHU9dm9pZCAwO2kucS5pdGVyYXRvcihlKT8odT1lLGU9dCk6KE9iamVjdChpLmgpKHQsaS5xLmZ1bmMscyksdT10LmFwcGx5KHZvaWQgMCxyKSxPYmplY3QoaS5oKSh1LGkucS5pdGVyYXRvcixzKSk7dmFyIGM9ZSxsPWMuc3Vic2NyaWJlLHA9Yy5kaXNwYXRjaCxmPWMuZ2V0U3RhdGUsZD1jLmNvbnRleHQsaD1jLnNhZ2FNb25pdG9yLG09Yy5sb2dnZXIsZz1jLm9uRXJyb3IseT1PYmplY3QoaS55KSgpO2gmJihoLmVmZmVjdFRyaWdnZXJlZD1oLmVmZmVjdFRyaWdnZXJlZHx8aS51LGguZWZmZWN0UmVzb2x2ZWQ9aC5lZmZlY3RSZXNvbHZlZHx8aS51LGguZWZmZWN0UmVqZWN0ZWQ9aC5lZmZlY3RSZWplY3RlZHx8aS51LGguZWZmZWN0Q2FuY2VsbGVkPWguZWZmZWN0Q2FuY2VsbGVkfHxpLnUsaC5hY3Rpb25EaXNwYXRjaGVkPWguYWN0aW9uRGlzcGF0Y2hlZHx8aS51LGguZWZmZWN0VHJpZ2dlcmVkKHtlZmZlY3RJZDp5LHJvb3Q6ITAscGFyZW50RWZmZWN0SWQ6MCxlZmZlY3Q6e3Jvb3Q6ITAsc2FnYTp0LGFyZ3M6cn19KSk7dmFyIHY9T2JqZWN0KG8uYikodSxsLE9iamVjdChpLkEpKHApLGYsZCx7c2FnYU1vbml0b3I6aCxsb2dnZXI6bSxvbkVycm9yOmd9LHksdC5uYW1lKTtyZXR1cm4gaCYmaC5lZmZlY3RSZXNvbHZlZCh5LHYpLHZ9dC5hPXI7dmFyIGk9bigyMiksbz1uKDE2OCksYT0icnVuU2FnYShzdG9yZUludGVyZmFjZSwgc2FnYSwgLi4uYXJncykiLHM9YSsiOiBzYWdhIGFyZ3VtZW50IG11c3QgYmUgYSBHZW5lcmF0b3IgZnVuY3Rpb24hIn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuIGluIHQpe3ZhciByPXRbbl07ci5jb25maWd1cmFibGU9ci5lbnVtZXJhYmxlPSEwLCJ2YWx1ZSJpbiByJiYoci53cml0YWJsZT0hMCksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsbixyKX1yZXR1cm4gZX1mdW5jdGlvbiBpKGUpe3JldHVybigiKiI9PT1lP3Yud2lsZGNhcmQ6dS5xLmFycmF5KGUpP3YuYXJyYXk6dS5xLnN0cmluZ2FibGVGdW5jKGUpP3YuZGVmYXVsdDp1LnEuZnVuYyhlKT92LnByZWRpY2F0ZTp2LmRlZmF1bHQpKGUpfWZ1bmN0aW9uIG8oZSx0LG4pe2Z1bmN0aW9uIHIoZSl7bygpLG4oZSwhMCl9ZnVuY3Rpb24gaShlKXthLnB1c2goZSksZS5jb250PWZ1bmN0aW9uKGksbyl7Y3x8KE9iamVjdCh1LncpKGEsZSksZS5jb250PXUudSxvP3IoaSk6KGU9PT10JiYocz1pKSxhLmxlbmd0aHx8KGM9ITAsbihzKSkpKX19ZnVuY3Rpb24gbygpe2N8fChjPSEwLGEuZm9yRWFjaChmdW5jdGlvbihlKXtlLmNvbnQ9dS51LGUuY2FuY2VsKCl9KSxhPVtdKX12YXIgYT1bXSxzPXZvaWQgMCxjPSExO3JldHVybiBpKHQpLHthZGRUYXNrOmksY2FuY2VsQWxsOm8sYWJvcnQ6cixnZXRUYXNrczpmdW5jdGlvbigpe3JldHVybiBhfSx0YXNrTmFtZXM6ZnVuY3Rpb24oKXtyZXR1cm4gYS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZX0pfX19ZnVuY3Rpb24gYShlKXt2YXIgdD1lLmNvbnRleHQsbj1lLmZuLHI9ZS5hcmdzO2lmKHUucS5pdGVyYXRvcihuKSlyZXR1cm4gbjt2YXIgaT12b2lkIDAsbz12b2lkIDA7dHJ5e2k9bi5hcHBseSh0LHIpfWNhdGNoKGUpe289ZX1yZXR1cm4gdS5xLml0ZXJhdG9yKGkpP2k6bz9PYmplY3QodS50KShmdW5jdGlvbigpe3Rocm93IG99KTpPYmplY3QodS50KShmdW5jdGlvbigpe3ZhciBlPXZvaWQgMCx0PXtkb25lOiExLHZhbHVlOml9LG49ZnVuY3Rpb24oZSl7cmV0dXJue2RvbmU6ITAsdmFsdWU6ZX19O3JldHVybiBmdW5jdGlvbihyKXtyZXR1cm4gZT9uKHIpOihlPSEwLHQpfX0oKSl9ZnVuY3Rpb24gcyhlKXtmdW5jdGlvbiB0KCl7dGUuaXNSdW5uaW5nJiYhdGUuaXNDYW5jZWxsZWQmJih0ZS5pc0NhbmNlbGxlZD0hMCxoKHkpKX1mdW5jdGlvbiBuKCl7ZS5faXNSdW5uaW5nJiYhZS5faXNDYW5jZWxsZWQmJihlLl9pc0NhbmNlbGxlZD0hMCxuZS5jYW5jZWxBbGwoKSx2KHkpKX1mdW5jdGlvbiBoKHQsbil7aWYoIXRlLmlzUnVubmluZyl0aHJvdyBuZXcgRXJyb3IoIlRyeWluZyB0byByZXN1bWUgYW4gYWxyZWFkeSBmaW5pc2hlZCBnZW5lcmF0b3IiKTt0cnl7dmFyIHI9dm9pZCAwO24/cj1lLnRocm93KHQpOnQ9PT15Pyh0ZS5pc0NhbmNlbGxlZD0hMCxoLmNhbmNlbCgpLHI9dS5xLmZ1bmMoZS5yZXR1cm4pP2UucmV0dXJuKHkpOntkb25lOiEwLHZhbHVlOnl9KTpyPXQ9PT1nP3UucS5mdW5jKGUucmV0dXJuKT9lLnJldHVybigpOntkb25lOiEwfTplLm5leHQodCksci5kb25lPyh0ZS5pc01haW5SdW5uaW5nPSExLHRlLmNvbnQmJnRlLmNvbnQoci52YWx1ZSkpOngoci52YWx1ZSxHLCIiLGgpfWNhdGNoKGUpe3RlLmlzQ2FuY2VsbGVkJiZZKGUpLHRlLmlzTWFpblJ1bm5pbmc9ITEsdGUuY29udChlLCEwKX19ZnVuY3Rpb24gdih0LG4pe2UuX2lzUnVubmluZz0hMSxYLmNsb3NlKCksbj8odCBpbnN0YW5jZW9mIEVycm9yJiZPYmplY3QuZGVmaW5lUHJvcGVydHkodCwic2FnYVN0YWNrIix7dmFsdWU6ImF0ICIrVisiIFxuICIrKHQuc2FnYVN0YWNrfHx0LnN0YWNrKSxjb25maWd1cmFibGU6ITB9KSxlZS5jb250fHwodCBpbnN0YW5jZW9mIEVycm9yJiZLP0sodCk6WSh0KSksZS5fZXJyb3I9dCxlLl9pc0Fib3J0ZWQ9ITAsZS5fZGVmZXJyZWRFbmQmJmUuX2RlZmVycmVkRW5kLnJlamVjdCh0KSk6KGUuX3Jlc3VsdD10LGUuX2RlZmVycmVkRW5kJiZlLl9kZWZlcnJlZEVuZC5yZXNvbHZlKHQpKSxlZS5jb250JiZlZS5jb250KHQsbiksZWUuam9pbmVycy5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBlLmNiKHQsbil9KSxlZS5qb2luZXJzPW51bGx9ZnVuY3Rpb24geChlLHQpe2Z1bmN0aW9uIG4oZSx0KXthfHwoYT0hMCxpLmNhbmNlbD11LnUsVyYmKHQ/Vy5lZmZlY3RSZWplY3RlZChvLGUpOlcuZWZmZWN0UmVzb2x2ZWQobyxlKSksaShlLHQpKX12YXIgcj1hcmd1bWVudHMubGVuZ3RoPjImJnZvaWQgMCE9PWFyZ3VtZW50c1syXT9hcmd1bWVudHNbMl06IiIsaT1hcmd1bWVudHNbM10sbz1PYmplY3QodS55KSgpO1cmJlcuZWZmZWN0VHJpZ2dlcmVkKHtlZmZlY3RJZDpvLHBhcmVudEVmZmVjdElkOnQsbGFiZWw6cixlZmZlY3Q6ZX0pO3ZhciBhPXZvaWQgMDtuLmNhbmNlbD11LnUsaS5jYW5jZWw9ZnVuY3Rpb24oKXtpZighYSl7YT0hMDt0cnl7bi5jYW5jZWwoKX1jYXRjaChlKXtZKGUpfW4uY2FuY2VsPXUudSxXJiZXLmVmZmVjdENhbmNlbGxlZChvKX19O3ZhciBzPXZvaWQgMDtyZXR1cm4gdS5xLnByb21pc2UoZSk/QyhlLG4pOnUucS5oZWxwZXIoZSk/QShiKGUpLG8sbik6dS5xLml0ZXJhdG9yKGUpP0UoZSxvLFYsbik6dS5xLmFycmF5KGUpP0goZSxvLG4pOihzPWwuZC50YWtlKGUpKT9EKHMsbik6KHM9bC5kLnB1dChlKSk/dyhzLG4pOihzPWwuZC5hbGwoZSkpP08ocyxvLG4pOihzPWwuZC5yYWNlKGUpKT9GKHMsbyxuKToocz1sLmQuY2FsbChlKSk/UyhzLG8sbik6KHM9bC5kLmNwcyhlKSk/ayhzLG4pOihzPWwuZC5mb3JrKGUpKT9BKHMsbyxuKToocz1sLmQuam9pbihlKSk/XyhzLG4pOihzPWwuZC5jYW5jZWwoZSkpP1QocyxuKToocz1sLmQuc2VsZWN0KGUpKT9OKHMsbik6KHM9bC5kLmFjdGlvbkNoYW5uZWwoZSkpP0kocyxuKToocz1sLmQuZmx1c2goZSkpP1AocyxuKToocz1sLmQuY2FuY2VsbGVkKGUpKT9MKHMsbik6KHM9bC5kLmdldENvbnRleHQoZSkpP00ocyxuKToocz1sLmQuc2V0Q29udGV4dChlKSk/aihzLG4pOm4oZSl9ZnVuY3Rpb24gQyhlLHQpe3ZhciBuPWVbdS5hXTt1LnEuZnVuYyhuKT90LmNhbmNlbD1uOnUucS5mdW5jKGUuYWJvcnQpJiYodC5jYW5jZWw9ZnVuY3Rpb24oKXtyZXR1cm4gZS5hYm9ydCgpfSksZS50aGVuKHQsZnVuY3Rpb24oZSl7cmV0dXJuIHQoZSwhMCl9KX1mdW5jdGlvbiBFKGUsdCxuLHIpe3MoZSxSLEIsJCxaLHosdCxuLHIpfWZ1bmN0aW9uIEQoZSx0KXt2YXIgbj1lLmNoYW5uZWwscj1lLnBhdHRlcm4sbz1lLm1heWJlO249bnx8WDt2YXIgYT1mdW5jdGlvbihlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIEVycm9yP3QoZSwhMCk6dChPYmplY3QocC5lKShlKSYmIW8/ZzplKX07dHJ5e24udGFrZShhLGkocikpfWNhdGNoKGUpe3JldHVybiB0KGUsITApfXQuY2FuY2VsPWEuY2FuY2VsfWZ1bmN0aW9uIHcoZSx0KXt2YXIgbj1lLmNoYW5uZWwscj1lLmFjdGlvbixpPWUucmVzb2x2ZTtPYmplY3QoYy5hKShmdW5jdGlvbigpe3ZhciBlPXZvaWQgMDt0cnl7ZT0obj9uLnB1dDpCKShyKX1jYXRjaChlKXtpZihufHxpKXJldHVybiB0KGUsITApO1koZSl9aWYoIWl8fCF1LnEucHJvbWlzZShlKSlyZXR1cm4gdChlKTtDKGUsdCl9KX1mdW5jdGlvbiBTKGUsdCxuKXt2YXIgcj1lLmNvbnRleHQsaT1lLmZuLG89ZS5hcmdzLGE9dm9pZCAwO3RyeXthPWkuYXBwbHkocixvKX1jYXRjaChlKXtyZXR1cm4gbihlLCEwKX1yZXR1cm4gdS5xLnByb21pc2UoYSk/QyhhLG4pOnUucS5pdGVyYXRvcihhKT9FKGEsdCxpLm5hbWUsbik6bihhKX1mdW5jdGlvbiBrKGUsdCl7dmFyIG49ZS5jb250ZXh0LHI9ZS5mbixpPWUuYXJnczt0cnl7dmFyIG89ZnVuY3Rpb24oZSxuKXtyZXR1cm4gdS5xLnVuZGVmKGUpP3Qobik6dChlLCEwKX07ci5hcHBseShuLGkuY29uY2F0KG8pKSxvLmNhbmNlbCYmKHQuY2FuY2VsPWZ1bmN0aW9uKCl7cmV0dXJuIG8uY2FuY2VsKCl9KX1jYXRjaChlKXtyZXR1cm4gdChlLCEwKX19ZnVuY3Rpb24gQShlLHQsbil7dmFyIHI9ZS5jb250ZXh0LGk9ZS5mbixvPWUuYXJncyxsPWUuZGV0YWNoZWQscD1hKHtjb250ZXh0OnIsZm46aSxhcmdzOm99KTt0cnl7T2JqZWN0KGMuYykoKTt2YXIgZj1zKHAsUixCLCQsWix6LHQsaS5uYW1lLGw/bnVsbDp1LnUpO2w/bihmKTpwLl9pc1J1bm5pbmc/KG5lLmFkZFRhc2soZiksbihmKSk6cC5fZXJyb3I/bmUuYWJvcnQocC5fZXJyb3IpOm4oZil9ZmluYWxseXtPYmplY3QoYy5iKSgpfX1mdW5jdGlvbiBfKGUsdCl7aWYoZS5pc1J1bm5pbmcoKSl7dmFyIG49e3Rhc2s6ZWUsY2I6dH07dC5jYW5jZWw9ZnVuY3Rpb24oKXtyZXR1cm4gT2JqZWN0KHUudykoZS5qb2luZXJzLG4pfSxlLmpvaW5lcnMucHVzaChuKX1lbHNlIGUuaXNBYm9ydGVkKCk/dChlLmVycm9yKCksITApOnQoZS5yZXN1bHQoKSl9ZnVuY3Rpb24gVChlLHQpe2U9PT11LmQmJihlPWVlKSxlLmlzUnVubmluZygpJiZlLmNhbmNlbCgpLHQoKX1mdW5jdGlvbiBPKGUsdCxuKXtmdW5jdGlvbiByKCl7bz09PWkubGVuZ3RoJiYoYT0hMCxuKHUucS5hcnJheShlKT91LmYuZnJvbShkKHt9LHMse2xlbmd0aDppLmxlbmd0aH0pKTpzKSl9dmFyIGk9T2JqZWN0LmtleXMoZSk7aWYoIWkubGVuZ3RoKXJldHVybiBuKHUucS5hcnJheShlKT9bXTp7fSk7dmFyIG89MCxhPXZvaWQgMCxzPXt9LGM9e307aS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWZ1bmN0aW9uKHQsaSl7YXx8KGl8fE9iamVjdChwLmUpKHQpfHx0PT09Z3x8dD09PXk/KG4uY2FuY2VsKCksbih0LGkpKTooc1tlXT10LG8rKyxyKCkpKX07dC5jYW5jZWw9dS51LGNbZV09dH0pLG4uY2FuY2VsPWZ1bmN0aW9uKCl7YXx8KGE9ITAsaS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBjW2VdLmNhbmNlbCgpfSkpfSxpLmZvckVhY2goZnVuY3Rpb24obil7cmV0dXJuIHgoZVtuXSx0LG4sY1tuXSl9KX1mdW5jdGlvbiBGKGUsdCxuKXt2YXIgcj12b2lkIDAsaT1PYmplY3Qua2V5cyhlKSxvPXt9O2kuZm9yRWFjaChmdW5jdGlvbih0KXt2YXIgYT1mdW5jdGlvbihvLGEpe2lmKCFyKWlmKGEpbi5jYW5jZWwoKSxuKG8sITApO2Vsc2UgaWYoIU9iamVjdChwLmUpKG8pJiZvIT09ZyYmbyE9PXkpe3ZhciBzO24uY2FuY2VsKCkscj0hMDt2YXIgYz0ocz17fSxzW3RdPW8scyk7bih1LnEuYXJyYXkoZSk/W10uc2xpY2UuY2FsbChkKHt9LGMse2xlbmd0aDppLmxlbmd0aH0pKTpjKX19O2EuY2FuY2VsPXUudSxvW3RdPWF9KSxuLmNhbmNlbD1mdW5jdGlvbigpe3J8fChyPSEwLGkuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gb1tlXS5jYW5jZWwoKX0pKX0saS5mb3JFYWNoKGZ1bmN0aW9uKG4pe3J8fHgoZVtuXSx0LG4sb1tuXSl9KX1mdW5jdGlvbiBOKGUsdCl7dmFyIG49ZS5zZWxlY3RvcixyPWUuYXJnczt0cnl7dmFyIGk9bi5hcHBseSh2b2lkIDAsWyQoKV0uY29uY2F0KHIpKTt0KGkpfWNhdGNoKGUpe3QoZSwhMCl9fWZ1bmN0aW9uIEkoZSx0KXt2YXIgbj1lLnBhdHRlcm4scj1lLmJ1ZmZlcixvPWkobik7by5wYXR0ZXJuPW4sdChPYmplY3QocC5kKShSLHJ8fGYuYS5maXhlZCgpLG8pKX1mdW5jdGlvbiBMKGUsdCl7dCghIXRlLmlzQ2FuY2VsbGVkKX1mdW5jdGlvbiBQKGUsdCl7ZS5mbHVzaCh0KX1mdW5jdGlvbiBNKGUsdCl7dChaW2VdKX1mdW5jdGlvbiBqKGUsdCl7dS52LmFzc2lnbihaLGUpLHQoKX12YXIgUj1hcmd1bWVudHMubGVuZ3RoPjEmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXT9hcmd1bWVudHNbMV06ZnVuY3Rpb24oKXtyZXR1cm4gdS51fSxCPWFyZ3VtZW50cy5sZW5ndGg+MiYmdm9pZCAwIT09YXJndW1lbnRzWzJdP2FyZ3VtZW50c1syXTp1LnUsJD1hcmd1bWVudHMubGVuZ3RoPjMmJnZvaWQgMCE9PWFyZ3VtZW50c1szXT9hcmd1bWVudHNbM106dS51LFU9YXJndW1lbnRzLmxlbmd0aD40JiZ2b2lkIDAhPT1hcmd1bWVudHNbNF0/YXJndW1lbnRzWzRdOnt9LHo9YXJndW1lbnRzLmxlbmd0aD41JiZ2b2lkIDAhPT1hcmd1bWVudHNbNV0/YXJndW1lbnRzWzVdOnt9LEc9YXJndW1lbnRzLmxlbmd0aD42JiZ2b2lkIDAhPT1hcmd1bWVudHNbNl0/YXJndW1lbnRzWzZdOjAsVj1hcmd1bWVudHMubGVuZ3RoPjcmJnZvaWQgMCE9PWFyZ3VtZW50c1s3XT9hcmd1bWVudHNbN106ImFub255bW91cyIscT1hcmd1bWVudHNbOF07T2JqZWN0KHUuaCkoZSx1LnEuaXRlcmF0b3IsbSk7dmFyIEg9T2JqZWN0KHUubikoTyxPYmplY3QodS56KSgiWy4uLmVmZmVjdHNdIiwiYWxsKFsuLi5lZmZlY3RzXSkiKSksVz16LnNhZ2FNb25pdG9yLFE9ei5sb2dnZXIsSz16Lm9uRXJyb3IsSj1RfHx1LnMsWT1mdW5jdGlvbihlKXt2YXIgdD1lLnNhZ2FTdGFjazshdCYmZS5zdGFjayYmKHQ9LTEhPT1lLnN0YWNrLnNwbGl0KCJcbiIpWzBdLmluZGV4T2YoZS5tZXNzYWdlKT9lLnN0YWNrOiJFcnJvcjogIitlLm1lc3NhZ2UrIlxuIitlLnN0YWNrKSxKKCJlcnJvciIsInVuY2F1Z2h0IGF0ICIrVix0fHxlLm1lc3NhZ2V8fGUpfSxYPU9iamVjdChwLmYpKFIpLFo9T2JqZWN0LmNyZWF0ZShVKTtoLmNhbmNlbD11LnU7dmFyIGVlPWZ1bmN0aW9uKGUsdCxpLG8pe3ZhciBhLHMsYztyZXR1cm4gaS5fZGVmZXJyZWRFbmQ9bnVsbCxzPXt9LHNbdS5lXT0hMCxzLmlkPWUscy5uYW1lPXQsYT0iZG9uZSIsYz17fSxjW2FdPWNbYV18fHt9LGNbYV0uZ2V0PWZ1bmN0aW9uKCl7aWYoaS5fZGVmZXJyZWRFbmQpcmV0dXJuIGkuX2RlZmVycmVkRW5kLnByb21pc2U7dmFyIGU9T2JqZWN0KHUubCkoKTtyZXR1cm4gaS5fZGVmZXJyZWRFbmQ9ZSxpLl9pc1J1bm5pbmd8fChpLl9lcnJvcj9lLnJlamVjdChpLl9lcnJvcik6ZS5yZXNvbHZlKGkuX3Jlc3VsdCkpLGUucHJvbWlzZX0scy5jb250PW8scy5qb2luZXJzPVtdLHMuY2FuY2VsPW4scy5pc1J1bm5pbmc9ZnVuY3Rpb24oKXtyZXR1cm4gaS5faXNSdW5uaW5nfSxzLmlzQ2FuY2VsbGVkPWZ1bmN0aW9uKCl7cmV0dXJuIGkuX2lzQ2FuY2VsbGVkfSxzLmlzQWJvcnRlZD1mdW5jdGlvbigpe3JldHVybiBpLl9pc0Fib3J0ZWR9LHMucmVzdWx0PWZ1bmN0aW9uKCl7cmV0dXJuIGkuX3Jlc3VsdH0scy5lcnJvcj1mdW5jdGlvbigpe3JldHVybiBpLl9lcnJvcn0scy5zZXRDb250ZXh0PWZ1bmN0aW9uKGUpe09iamVjdCh1LmgpKGUsdS5xLm9iamVjdCxPYmplY3QodS5rKSgidGFzayIsZSkpLHUudi5hc3NpZ24oWixlKX0scihzLGMpLHN9KEcsVixlLHEpLHRlPXtuYW1lOlYsY2FuY2VsOnQsaXNSdW5uaW5nOiEwfSxuZT1vKFYsdGUsdik7cmV0dXJuIHEmJihxLmNhbmNlbD1uKSxlLl9pc1J1bm5pbmc9ITAsaCgpLGVlfW4uZCh0LCJhIixmdW5jdGlvbigpe3JldHVybiBnfSksdC5iPXM7dmFyIHU9bigyMiksYz1uKDE2NiksbD1uKDM0KSxwPW4oNDIpLGY9big3NiksZD1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfSxoPSJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiYic3ltYm9sIj09PXR5cGVvZiBTeW1ib2wuaXRlcmF0b3I/ZnVuY3Rpb24oZSl7cmV0dXJuIHR5cGVvZiBlfTpmdW5jdGlvbihlKXtyZXR1cm4gZSYmImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfSxtPSJwcm9jIGZpcnN0IGFyZ3VtZW50IChTYWdhIGZ1bmN0aW9uIHJlc3VsdCkgbXVzdCBiZSBhbiBpdGVyYXRvciIsZz17dG9TdHJpbmc6ZnVuY3Rpb24oKXtyZXR1cm4iQEByZWR1eC1zYWdhL0NIQU5ORUxfRU5EIn19LHk9e3RvU3RyaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIkBAcmVkdXgtc2FnYS9UQVNLX0NBTkNFTCJ9fSx2PXt3aWxkY2FyZDpmdW5jdGlvbigpe3JldHVybiB1LnJ9LGRlZmF1bHQ6ZnVuY3Rpb24oZSl7cmV0dXJuInN5bWJvbCI9PT0oInVuZGVmaW5lZCI9PT10eXBlb2YgZT8idW5kZWZpbmVkIjpoKGUpKT9mdW5jdGlvbih0KXtyZXR1cm4gdC50eXBlPT09ZX06ZnVuY3Rpb24odCl7cmV0dXJuIHQudHlwZT09PVN0cmluZyhlKX19LGFycmF5OmZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gZS5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiBpKGUpKHQpfSl9fSxwcmVkaWNhdGU6ZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBlKHQpfX19LGI9ZnVuY3Rpb24oZSl7cmV0dXJue2ZuOmV9fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtuLmQodCwiYSIsZnVuY3Rpb24oKXtyZXR1cm4gdX0pLG4uZCh0LCJjIixmdW5jdGlvbigpe3JldHVybiBjfSksbi5kKHQsImUiLGZ1bmN0aW9uKCl7cmV0dXJuIGx9KTt2YXIgcj1uKDM1OCksaT1uKDM1OSksbz1uKDM2MCksYT1uKDIyKTtuLmQodCwiYiIsZnVuY3Rpb24oKXtyZXR1cm4gci5hfSksbi5kKHQsImQiLGZ1bmN0aW9uKCl7cmV0dXJuIGkuYX0pLG4uZCh0LCJmIixmdW5jdGlvbigpe3JldHVybiBvLmF9KTt2YXIgcz1mdW5jdGlvbihlKXtyZXR1cm4iaW1wb3J0IHsgIitlKyIgfSBmcm9tICdyZWR1eC1zYWdhJyBoYXMgYmVlbiBkZXByZWNhdGVkIGluIGZhdm9yIG9mIGltcG9ydCB7ICIrZSsiIH0gZnJvbSAncmVkdXgtc2FnYS9lZmZlY3RzJy5cblRoZSBsYXR0ZXIgd2lsbCBub3Qgd29yayB3aXRoIHlpZWxkKiwgYXMgaGVscGVyIGVmZmVjdHMgYXJlIHdyYXBwZWQgYXV0b21hdGljYWxseSBmb3IgeW91IGluIGZvcmsgZWZmZWN0LlxuVGhlcmVmb3JlIHlpZWxkICIrZSsiIHdpbGwgcmV0dXJuIHRhc2sgZGVzY3JpcHRvciB0byB5b3VyIHNhZ2EgYW5kIGV4ZWN1dGUgbmV4dCBsaW5lcyBvZiBjb2RlLiJ9LHU9T2JqZWN0KGEubikoci5hLHMoInRha2VFdmVyeSIpKSxjPU9iamVjdChhLm4pKGkuYSxzKCJ0YWtlTGF0ZXN0IikpLGw9T2JqZWN0KGEubikoby5hLHMoInRocm90dGxlIikpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO24uZCh0LCJhIixmdW5jdGlvbigpe3JldHVybiBvfSk7dmFyIHI9bigzNjQpLGk9bi5uKHIpLG89aS5hfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7Zm9yKHZhciB0PVsicXVlcnkiLCJvcGVyYXRpb25OYW1lIiwidmFyaWFibGVzIiwiZXh0ZW5zaW9ucyIsImNvbnRleHQiXSxuPTAscj1PYmplY3Qua2V5cyhlKTtuPHIubGVuZ3RoO24rKyl7dmFyIGk9cltuXTtpZih0LmluZGV4T2YoaSk8MCl0aHJvdyBuZXcgRXJyb3IoImlsbGVnYWwgYXJndW1lbnQ6ICIraSl9cmV0dXJuIGV9ZnVuY3Rpb24gaShlKXtyZXR1cm4gZS5yZXF1ZXN0Lmxlbmd0aDw9MX1mdW5jdGlvbiBvKGUpe3ZhciB0PSExO3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihuLHIpe2Uuc3Vic2NyaWJlKHtuZXh0OmZ1bmN0aW9uKGUpe3Q/Y29uc29sZS53YXJuKCJQcm9taXNlIFdyYXBwZXIgZG9lcyBub3Qgc3VwcG9ydCBtdWx0aXBsZSByZXN1bHRzIGZyb20gT2JzZXJ2YWJsZSIpOih0PSEwLG4oZSkpfSxlcnJvcjpyfSl9KX1mdW5jdGlvbiBhKGUpe3JldHVybiBuZXcgZi5hKGZ1bmN0aW9uKHQpe2UudGhlbihmdW5jdGlvbihlKXt0Lm5leHQoZSksdC5jb21wbGV0ZSgpfSkuY2F0Y2godC5lcnJvci5iaW5kKHQpKX0pfWZ1bmN0aW9uIHMoZSl7cmV0dXJuIG5ldyBmLmEoZnVuY3Rpb24odCl7dC5lcnJvcihlKX0pfWZ1bmN0aW9uIHUoZSl7dmFyIHQ9e3ZhcmlhYmxlczplLnZhcmlhYmxlc3x8e30sZXh0ZW5zaW9uczplLmV4dGVuc2lvbnN8fHt9LG9wZXJhdGlvbk5hbWU6ZS5vcGVyYXRpb25OYW1lLHF1ZXJ5OmUucXVlcnl9O3JldHVybiB0Lm9wZXJhdGlvbk5hbWV8fCh0Lm9wZXJhdGlvbk5hbWU9InN0cmluZyIhPT10eXBlb2YgdC5xdWVyeT9PYmplY3QocC5hKSh0LnF1ZXJ5KToiIiksdH1mdW5jdGlvbiBjKGUsdCl7dmFyIG49bSh7fSxlKSxyPWZ1bmN0aW9uKGUpe249ImZ1bmN0aW9uIj09PXR5cGVvZiBlP20oe30sbixlKG4pKTptKHt9LG4sZSl9LGk9ZnVuY3Rpb24oKXtyZXR1cm4gbSh7fSxuKX07cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJzZXRDb250ZXh0Iix7ZW51bWVyYWJsZTohMSx2YWx1ZTpyfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImdldENvbnRleHQiLHtlbnVtZXJhYmxlOiExLHZhbHVlOml9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidG9LZXkiLHtlbnVtZXJhYmxlOiExLHZhbHVlOmZ1bmN0aW9uKCl7cmV0dXJuIGwodCl9fSksdH1mdW5jdGlvbiBsKGUpe3JldHVybiBPYmplY3QoZC5wcmludCkoZS5xdWVyeSkrInwiK0pTT04uc3RyaW5naWZ5KGUudmFyaWFibGVzKSsifCIrZS5vcGVyYXRpb25OYW1lfXQuaT1yLG4uZCh0LCJhIixmdW5jdGlvbigpe3JldHVybiBnfSksdC5lPWksdC5nPW8sbi5kKHQsImYiLGZ1bmN0aW9uKCl7cmV0dXJuIHl9KSx0LmQ9YSx0LmM9cyx0Lmg9dSx0LmI9Yzt2YXIgcD1uKDM2NiksZj1uKDEwNiksZD1uKDE5KSxoPShuLm4oZCksdGhpcyYmdGhpcy5fX2V4dGVuZHN8fGZ1bmN0aW9uKCl7dmFyIGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCkpLG09dGhpcyYmdGhpcy5fX2Fzc2lnbnx8T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0LG49MSxyPWFyZ3VtZW50cy5sZW5ndGg7bjxyO24rKyl7dD1hcmd1bWVudHNbbl07Zm9yKHZhciBpIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsaSkmJihlW2ldPXRbaV0pfXJldHVybiBlfSxnPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCxuKXt2YXIgcj1lLmNhbGwodGhpcyx0KXx8dGhpcztyZXR1cm4gci5saW5rPW4scn1yZXR1cm4gaCh0LGUpLHR9KEVycm9yKSx5PW99LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZigiRG9jdW1lbnQiIT09ZS5raW5kKXRocm93IG5ldyBFcnJvcignRXhwZWN0aW5nIGEgcGFyc2VkIEdyYXBoUUwgZG9jdW1lbnQuIFBlcmhhcHMgeW91IG5lZWQgdG8gd3JhcCB0aGUgcXVlcnkgc3RyaW5nIGluIGEgImdxbCIgdGFnPyBodHRwOi8vZG9jcy5hcG9sbG9zdGFjay5jb20vYXBvbGxvLWNsaWVudC9jb3JlLmh0bWwjZ3FsJyk7dmFyIHQ9ZS5kZWZpbml0aW9ucy5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIkZyYWdtZW50RGVmaW5pdGlvbiIhPT1lLmtpbmR9KS5tYXAoZnVuY3Rpb24oZSl7aWYoIk9wZXJhdGlvbkRlZmluaXRpb24iIT09ZS5raW5kKXRocm93IG5ldyBFcnJvcignU2NoZW1hIHR5cGUgZGVmaW5pdGlvbnMgbm90IGFsbG93ZWQgaW4gcXVlcmllcy4gRm91bmQ6ICInK2Uua2luZCsnIicpO3JldHVybiBlfSk7aWYodC5sZW5ndGg+MSl0aHJvdyBuZXcgRXJyb3IoIkFtYmlndW91cyBHcmFwaFFMIGRvY3VtZW50OiBjb250YWlucyAiK3QubGVuZ3RoKyIgb3BlcmF0aW9ucyIpfWZ1bmN0aW9uIGkoZSl7cmV0dXJuIHIoZSksZS5kZWZpbml0aW9ucy5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIk9wZXJhdGlvbkRlZmluaXRpb24iPT09ZS5raW5kfSlbMF19ZnVuY3Rpb24gbyhlKXt2YXIgdD1pKGUpO2lmKCF0KXRocm93IG5ldyBFcnJvcigiR3JhcGhRTCBkb2N1bWVudCBpcyBtaXNzaW5nIGFuIG9wZXJhdGlvbiIpO3JldHVybiB0fWZ1bmN0aW9uIGEoZSl7cmV0dXJuIGUuZGVmaW5pdGlvbnMuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiJPcGVyYXRpb25EZWZpbml0aW9uIj09PWUua2luZCYmZS5uYW1lfSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWUudmFsdWV9KVswXXx8bnVsbH1mdW5jdGlvbiBzKGUpe3JldHVybiBlLmRlZmluaXRpb25zLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4iRnJhZ21lbnREZWZpbml0aW9uIj09PWUua2luZH0pfWZ1bmN0aW9uIHUoZSl7dm9pZCAwPT09ZSYmKGU9W10pO3ZhciB0PXt9O3JldHVybiBlLmZvckVhY2goZnVuY3Rpb24oZSl7dFtlLm5hbWUudmFsdWVdPWV9KSx0fXQuYT1yLHQuZD1vLHQuZT1hLHQuYz1zLHQuYj11O24oMTczKSxuKDEwNyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtmb3IodmFyIHQ9W10sbj0xO248YXJndW1lbnRzLmxlbmd0aDtuKyspdFtuLTFdPWFyZ3VtZW50c1tuXTtyZXR1cm4gdC5mb3JFYWNoKGZ1bmN0aW9uKHQpeyJ1bmRlZmluZWQiIT09dHlwZW9mIHQmJm51bGwhPT10JiZPYmplY3Qua2V5cyh0KS5mb3JFYWNoKGZ1bmN0aW9uKG4pe2Vbbl09dFtuXX0pfSksZX10LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe2lmKEFycmF5LmlzQXJyYXkoZSkpcmV0dXJuIGUubWFwKGZ1bmN0aW9uKGUpe3JldHVybiByKGUpfSk7aWYobnVsbCE9PWUmJiJvYmplY3QiPT09dHlwZW9mIGUpe3ZhciB0PXt9O2Zvcih2YXIgbiBpbiBlKWUuaGFzT3duUHJvcGVydHkobikmJih0W25dPXIoZVtuXSkpO3JldHVybiB0fXJldHVybiBlfXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7aWYoIWUpcmV0dXJue307dHJ5e3JldHVybiBKU09OLnBhcnNlKGUpfWNhdGNoKGUpe3JldHVybnt9fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5wYXJzZUhlYWRlcnM9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjsoZnVuY3Rpb24oZSl7dmFyIHI9dGhpcyYmdGhpcy5fX2Fzc2lnbnx8T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0LG49MSxyPWFyZ3VtZW50cy5sZW5ndGg7bjxyO24rKyl7dD1hcmd1bWVudHNbbl07Zm9yKHZhciBpIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsaSkmJihlW2ldPXRbaV0pfXJldHVybiBlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9InVuZGVmaW5lZCIhPT10eXBlb2YgZT9lOiJ1bmRlZmluZWQiIT09dHlwZW9mIHdpbmRvdz93aW5kb3c6e30sbz1pLldlYlNvY2tldHx8aS5Nb3pXZWJTb2NrZXQsYT1uKDM3NSkscz1uKDM3NiksdT1uKDM3NyksYz1uKDM3OCksbD1uKDE5KSxwPW4oMTc3KSxmPW4oMzc5KSxkPW4oMzgxKSxoPW4oMzgyKSxtPW4oMzgzKSxnPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dmFyIHI9dHx8e30saT1yLmNvbm5lY3Rpb25DYWxsYmFjayx1PXZvaWQgMD09PWk/dm9pZCAwOmksYz1yLmNvbm5lY3Rpb25QYXJhbXMsbD12b2lkIDA9PT1jP3t9OmMscD1yLnRpbWVvdXQsZj12b2lkIDA9PT1wP2guV1NfVElNRU9VVDpwLGQ9ci5yZWNvbm5lY3QsbT12b2lkIDAhPT1kJiZkLGc9ci5yZWNvbm5lY3Rpb25BdHRlbXB0cyx5PXZvaWQgMD09PWc/MS8wOmcsdj1yLmxhenksYj12b2lkIDAhPT12JiZ2LHg9ci5pbmFjdGl2aXR5VGltZW91dCxDPXZvaWQgMD09PXg/MDp4O2lmKHRoaXMud3NJbXBsPW58fG8sIXRoaXMud3NJbXBsKXRocm93IG5ldyBFcnJvcigiVW5hYmxlIHRvIGZpbmQgbmF0aXZlIGltcGxlbWVudGF0aW9uLCBvciBhbHRlcm5hdGl2ZSBpbXBsZW1lbnRhdGlvbiBmb3IgV2ViU29ja2V0ISIpO3RoaXMuY29ubmVjdGlvblBhcmFtcz1sLHRoaXMuY29ubmVjdGlvbkNhbGxiYWNrPXUsdGhpcy51cmw9ZSx0aGlzLm9wZXJhdGlvbnM9e30sdGhpcy5uZXh0T3BlcmF0aW9uSWQ9MCx0aGlzLndzVGltZW91dD1mLHRoaXMudW5zZW50TWVzc2FnZXNRdWV1ZT1bXSx0aGlzLnJlY29ubmVjdD1tLHRoaXMucmVjb25uZWN0aW5nPSExLHRoaXMucmVjb25uZWN0aW9uQXR0ZW1wdHM9eSx0aGlzLmxhenk9ISFiLHRoaXMuaW5hY3Rpdml0eVRpbWVvdXQ9Qyx0aGlzLmNsb3NlZEJ5VXNlcj0hMSx0aGlzLmJhY2tvZmY9bmV3IGEoe2ppdHRlcjouNX0pLHRoaXMuZXZlbnRFbWl0dGVyPW5ldyBzLkV2ZW50RW1pdHRlcix0aGlzLm1pZGRsZXdhcmVzPVtdLHRoaXMuY2xpZW50PW51bGwsdGhpcy5tYXhDb25uZWN0VGltZUdlbmVyYXRvcj10aGlzLmNyZWF0ZU1heENvbm5lY3RUaW1lR2VuZXJhdG9yKCksdGhpcy5sYXp5fHx0aGlzLmNvbm5lY3QoKX1yZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KGUucHJvdG90eXBlLCJzdGF0dXMiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbD09PXRoaXMuY2xpZW50P3RoaXMud3NJbXBsLkNMT1NFRDp0aGlzLmNsaWVudC5yZWFkeVN0YXRlfSxlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pLGUucHJvdG90eXBlLmNsb3NlPWZ1bmN0aW9uKGUsdCl7dm9pZCAwPT09ZSYmKGU9ITApLHZvaWQgMD09PXQmJih0PSEwKSx0aGlzLmNsZWFySW5hY3Rpdml0eVRpbWVvdXQoKSxudWxsIT09dGhpcy5jbGllbnQmJih0aGlzLmNsb3NlZEJ5VXNlcj10LGUmJih0aGlzLmNsZWFyQ2hlY2tDb25uZWN0aW9uSW50ZXJ2YWwoKSx0aGlzLmNsZWFyTWF4Q29ubmVjdFRpbWVvdXQoKSx0aGlzLmNsZWFyVHJ5UmVjb25uZWN0VGltZW91dCgpLHRoaXMudW5zdWJzY3JpYmVBbGwoKSx0aGlzLnNlbmRNZXNzYWdlKHZvaWQgMCxtLmRlZmF1bHQuR1FMX0NPTk5FQ1RJT05fVEVSTUlOQVRFLG51bGwpKSx0aGlzLmNsaWVudC5jbG9zZSgpLHRoaXMuY2xpZW50PW51bGwsdGhpcy5ldmVudEVtaXR0ZXIuZW1pdCgiZGlzY29ubmVjdGVkIiksZXx8dGhpcy50cnlSZWNvbm5lY3QoKSl9LGUucHJvdG90eXBlLnJlcXVlc3Q9ZnVuY3Rpb24oZSl7dmFyIHQsbj10aGlzLmdldE9ic2VydmVyLmJpbmQodGhpcykscj10aGlzLmV4ZWN1dGVPcGVyYXRpb24uYmluZCh0aGlzKSxpPXRoaXMudW5zdWJzY3JpYmUuYmluZCh0aGlzKTtyZXR1cm4gdGhpcy5jbGVhckluYWN0aXZpdHlUaW1lb3V0KCksbz17fSxvW2YuZGVmYXVsdF09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sby5zdWJzY3JpYmU9ZnVuY3Rpb24obyxhLHMpe3ZhciB1PW4obyxhLHMpO3JldHVybiB0PXIoZSxmdW5jdGlvbihlLHQpe251bGw9PT1lJiZudWxsPT09dD91LmNvbXBsZXRlJiZ1LmNvbXBsZXRlKCk6ZT91LmVycm9yJiZ1LmVycm9yKGVbMF0pOnUubmV4dCYmdS5uZXh0KHQpfSkse3Vuc3Vic2NyaWJlOmZ1bmN0aW9uKCl7dCYmKGkodCksdD1udWxsKX19fSxvO3ZhciBvfSxlLnByb3RvdHlwZS5vbj1mdW5jdGlvbihlLHQsbil7dmFyIHI9dGhpcy5ldmVudEVtaXR0ZXIub24oZSx0LG4pO3JldHVybiBmdW5jdGlvbigpe3Iub2ZmKGUsdCxuKX19LGUucHJvdG90eXBlLm9uQ29ubmVjdGVkPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMub24oImNvbm5lY3RlZCIsZSx0KX0sZS5wcm90b3R5cGUub25Db25uZWN0aW5nPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMub24oImNvbm5lY3RpbmciLGUsdCl9LGUucHJvdG90eXBlLm9uRGlzY29ubmVjdGVkPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMub24oImRpc2Nvbm5lY3RlZCIsZSx0KX0sZS5wcm90b3R5cGUub25SZWNvbm5lY3RlZD1mdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLm9uKCJyZWNvbm5lY3RlZCIsZSx0KX0sZS5wcm90b3R5cGUub25SZWNvbm5lY3Rpbmc9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5vbigicmVjb25uZWN0aW5nIixlLHQpfSxlLnByb3RvdHlwZS5vbkVycm9yPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMub24oImVycm9yIixlLHQpfSxlLnByb3RvdHlwZS51bnN1YnNjcmliZUFsbD1mdW5jdGlvbigpe3ZhciBlPXRoaXM7T2JqZWN0LmtleXModGhpcy5vcGVyYXRpb25zKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe2UudW5zdWJzY3JpYmUodCl9KX0sZS5wcm90b3R5cGUuYXBwbHlNaWRkbGV3YXJlcz1mdW5jdGlvbihlKXt2YXIgdD10aGlzO3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihuLHIpeyFmdW5jdGlvbih0LGkpe3ZhciBvPWZ1bmN0aW9uKGEpe2lmKGEpcihhKTtlbHNlIGlmKHQubGVuZ3RoPjApe3ZhciBzPXQuc2hpZnQoKTtzJiZzLmFwcGx5TWlkZGxld2FyZS5hcHBseShpLFtlLG9dKX1lbHNlIG4oZSl9O28oKX0odC5taWRkbGV3YXJlcy5zbGljZSgpLHQpfSl9LGUucHJvdG90eXBlLnVzZT1mdW5jdGlvbihlKXt2YXIgdD10aGlzO3JldHVybiBlLm1hcChmdW5jdGlvbihlKXtpZigiZnVuY3Rpb24iIT09dHlwZW9mIGUuYXBwbHlNaWRkbGV3YXJlKXRocm93IG5ldyBFcnJvcigiTWlkZGxld2FyZSBtdXN0IGltcGxlbWVudCB0aGUgYXBwbHlNaWRkbGV3YXJlIGZ1bmN0aW9uLiIpO3QubWlkZGxld2FyZXMucHVzaChlKX0pLHRoaXN9LGUucHJvdG90eXBlLmV4ZWN1dGVPcGVyYXRpb249ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzO251bGw9PT10aGlzLmNsaWVudCYmdGhpcy5jb25uZWN0KCk7dmFyIHI9dGhpcy5nZW5lcmF0ZU9wZXJhdGlvbklkKCk7cmV0dXJuIHRoaXMub3BlcmF0aW9uc1tyXT17b3B0aW9uczplLGhhbmRsZXI6dH0sdGhpcy5hcHBseU1pZGRsZXdhcmVzKGUpLnRoZW4oZnVuY3Rpb24oZSl7bi5jaGVja09wZXJhdGlvbk9wdGlvbnMoZSx0KSxuLm9wZXJhdGlvbnNbcl0mJihuLm9wZXJhdGlvbnNbcl09e29wdGlvbnM6ZSxoYW5kbGVyOnR9LG4uc2VuZE1lc3NhZ2UocixtLmRlZmF1bHQuR1FMX1NUQVJULGUpKX0pLmNhdGNoKGZ1bmN0aW9uKGUpe24udW5zdWJzY3JpYmUociksdChuLmZvcm1hdEVycm9ycyhlKSl9KSxyfSxlLnByb3RvdHlwZS5nZXRPYnNlcnZlcj1mdW5jdGlvbihlLHQsbil7cmV0dXJuImZ1bmN0aW9uIj09PXR5cGVvZiBlP3tuZXh0OmZ1bmN0aW9uKHQpe3JldHVybiBlKHQpfSxlcnJvcjpmdW5jdGlvbihlKXtyZXR1cm4gdCYmdChlKX0sY29tcGxldGU6ZnVuY3Rpb24oKXtyZXR1cm4gbiYmbigpfX06ZX0sZS5wcm90b3R5cGUuY3JlYXRlTWF4Q29ubmVjdFRpbWVHZW5lcmF0b3I9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLndzVGltZW91dDtyZXR1cm4gbmV3IGEoe21pbjoxZTMsbWF4OmUsZmFjdG9yOjEuMn0pfSxlLnByb3RvdHlwZS5jbGVhckNoZWNrQ29ubmVjdGlvbkludGVydmFsPWZ1bmN0aW9uKCl7dGhpcy5jaGVja0Nvbm5lY3Rpb25JbnRlcnZhbElkJiYoY2xlYXJJbnRlcnZhbCh0aGlzLmNoZWNrQ29ubmVjdGlvbkludGVydmFsSWQpLHRoaXMuY2hlY2tDb25uZWN0aW9uSW50ZXJ2YWxJZD1udWxsKX0sZS5wcm90b3R5cGUuY2xlYXJNYXhDb25uZWN0VGltZW91dD1mdW5jdGlvbigpe3RoaXMubWF4Q29ubmVjdFRpbWVvdXRJZCYmKGNsZWFyVGltZW91dCh0aGlzLm1heENvbm5lY3RUaW1lb3V0SWQpLHRoaXMubWF4Q29ubmVjdFRpbWVvdXRJZD1udWxsKX0sZS5wcm90b3R5cGUuY2xlYXJUcnlSZWNvbm5lY3RUaW1lb3V0PWZ1bmN0aW9uKCl7dGhpcy50cnlSZWNvbm5lY3RUaW1lb3V0SWQmJihjbGVhclRpbWVvdXQodGhpcy50cnlSZWNvbm5lY3RUaW1lb3V0SWQpLHRoaXMudHJ5UmVjb25uZWN0VGltZW91dElkPW51bGwpfSxlLnByb3RvdHlwZS5jbGVhckluYWN0aXZpdHlUaW1lb3V0PWZ1bmN0aW9uKCl7dGhpcy5pbmFjdGl2aXR5VGltZW91dElkJiYoY2xlYXJUaW1lb3V0KHRoaXMuaW5hY3Rpdml0eVRpbWVvdXRJZCksdGhpcy5pbmFjdGl2aXR5VGltZW91dElkPW51bGwpfSxlLnByb3RvdHlwZS5zZXRJbmFjdGl2aXR5VGltZW91dD1mdW5jdGlvbigpe3ZhciBlPXRoaXM7dGhpcy5pbmFjdGl2aXR5VGltZW91dD4wJiYwPT09T2JqZWN0LmtleXModGhpcy5vcGVyYXRpb25zKS5sZW5ndGgmJih0aGlzLmluYWN0aXZpdHlUaW1lb3V0SWQ9c2V0VGltZW91dChmdW5jdGlvbigpezA9PT1PYmplY3Qua2V5cyhlLm9wZXJhdGlvbnMpLmxlbmd0aCYmZS5jbG9zZSgpfSx0aGlzLmluYWN0aXZpdHlUaW1lb3V0KSl9LGUucHJvdG90eXBlLmNoZWNrT3BlcmF0aW9uT3B0aW9ucz1mdW5jdGlvbihlLHQpe3ZhciBuPWUucXVlcnkscj1lLnZhcmlhYmxlcyxpPWUub3BlcmF0aW9uTmFtZTtpZighbil0aHJvdyBuZXcgRXJyb3IoIk11c3QgcHJvdmlkZSBhIHF1ZXJ5LiIpO2lmKCF0KXRocm93IG5ldyBFcnJvcigiTXVzdCBwcm92aWRlIGFuIGhhbmRsZXIuIik7aWYoIXUobikmJiFwLmdldE9wZXJhdGlvbkFTVChuLGkpfHxpJiYhdShpKXx8ciYmIWMocikpdGhyb3cgbmV3IEVycm9yKCJJbmNvcnJlY3Qgb3B0aW9uIHR5cGVzLiBxdWVyeSBtdXN0IGJlIGEgc3RyaW5nIG9yIGEgZG9jdW1lbnQsYG9wZXJhdGlvbk5hbWVgIG11c3QgYmUgYSBzdHJpbmcsIGFuZCBgdmFyaWFibGVzYCBtdXN0IGJlIGFuIG9iamVjdC4iKX0sZS5wcm90b3R5cGUuYnVpbGRNZXNzYWdlPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm57aWQ6ZSx0eXBlOnQscGF5bG9hZDpuJiZuLnF1ZXJ5P3Ioe30sbix7cXVlcnk6InN0cmluZyI9PT10eXBlb2Ygbi5xdWVyeT9uLnF1ZXJ5OmwucHJpbnQobi5xdWVyeSl9KTpufX0sZS5wcm90b3R5cGUuZm9ybWF0RXJyb3JzPWZ1bmN0aW9uKGUpe3JldHVybiBBcnJheS5pc0FycmF5KGUpP2U6ZSYmZS5lcnJvcnM/dGhpcy5mb3JtYXRFcnJvcnMoZS5lcnJvcnMpOmUmJmUubWVzc2FnZT9bZV06W3tuYW1lOiJGb3JtYXRlZEVycm9yIixtZXNzYWdlOiJVbmtub3duIGVycm9yIixvcmlnaW5hbEVycm9yOmV9XX0sZS5wcm90b3R5cGUuc2VuZE1lc3NhZ2U9ZnVuY3Rpb24oZSx0LG4pe3RoaXMuc2VuZE1lc3NhZ2VSYXcodGhpcy5idWlsZE1lc3NhZ2UoZSx0LG4pKX0sZS5wcm90b3R5cGUuc2VuZE1lc3NhZ2VSYXc9ZnVuY3Rpb24oZSl7c3dpdGNoKHRoaXMuc3RhdHVzKXtjYXNlIHRoaXMud3NJbXBsLk9QRU46dmFyIHQ9SlNPTi5zdHJpbmdpZnkoZSk7dHJ5e0pTT04ucGFyc2UodCl9Y2F0Y2godCl7dGhyb3cgbmV3IEVycm9yKCJNZXNzYWdlIG11c3QgYmUgSlNPTi1zZXJpYWxpemFibGUuIEdvdDogIitlKX10aGlzLmNsaWVudC5zZW5kKHQpO2JyZWFrO2Nhc2UgdGhpcy53c0ltcGwuQ09OTkVDVElORzp0aGlzLnVuc2VudE1lc3NhZ2VzUXVldWUucHVzaChlKTticmVhaztkZWZhdWx0OmlmKCF0aGlzLnJlY29ubmVjdGluZyl0aHJvdyBuZXcgRXJyb3IoIkEgbWVzc2FnZSB3YXMgbm90IHNlbnQgYmVjYXVzZSBzb2NrZXQgaXMgbm90IGNvbm5lY3RlZCwgaXMgY2xvc2luZyBvciBpcyBhbHJlYWR5IGNsb3NlZC4gTWVzc2FnZSB3YXM6ICIrSlNPTi5zdHJpbmdpZnkoZSkpfX0sZS5wcm90b3R5cGUuZ2VuZXJhdGVPcGVyYXRpb25JZD1mdW5jdGlvbigpe3JldHVybiBTdHJpbmcoKyt0aGlzLm5leHRPcGVyYXRpb25JZCl9LGUucHJvdG90eXBlLnRyeVJlY29ubmVjdD1mdW5jdGlvbigpe3ZhciBlPXRoaXM7aWYodGhpcy5yZWNvbm5lY3QmJiEodGhpcy5iYWNrb2ZmLmF0dGVtcHRzPj10aGlzLnJlY29ubmVjdGlvbkF0dGVtcHRzKSl7dGhpcy5yZWNvbm5lY3Rpbmd8fChPYmplY3Qua2V5cyh0aGlzLm9wZXJhdGlvbnMpLmZvckVhY2goZnVuY3Rpb24odCl7ZS51bnNlbnRNZXNzYWdlc1F1ZXVlLnB1c2goZS5idWlsZE1lc3NhZ2UodCxtLmRlZmF1bHQuR1FMX1NUQVJULGUub3BlcmF0aW9uc1t0XS5vcHRpb25zKSl9KSx0aGlzLnJlY29ubmVjdGluZz0hMCksdGhpcy5jbGVhclRyeVJlY29ubmVjdFRpbWVvdXQoKTt2YXIgdD10aGlzLmJhY2tvZmYuZHVyYXRpb24oKTt0aGlzLnRyeVJlY29ubmVjdFRpbWVvdXRJZD1zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7ZS5jb25uZWN0KCl9LHQpfX0sZS5wcm90b3R5cGUuZmx1c2hVbnNlbnRNZXNzYWdlc1F1ZXVlPWZ1bmN0aW9uKCl7dmFyIGU9dGhpczt0aGlzLnVuc2VudE1lc3NhZ2VzUXVldWUuZm9yRWFjaChmdW5jdGlvbih0KXtlLnNlbmRNZXNzYWdlUmF3KHQpfSksdGhpcy51bnNlbnRNZXNzYWdlc1F1ZXVlPVtdfSxlLnByb3RvdHlwZS5jaGVja0Nvbm5lY3Rpb249ZnVuY3Rpb24oKXtpZih0aGlzLndhc0tlZXBBbGl2ZVJlY2VpdmVkKXJldHVybiB2b2lkKHRoaXMud2FzS2VlcEFsaXZlUmVjZWl2ZWQ9ITEpO3RoaXMucmVjb25uZWN0aW5nfHx0aGlzLmNsb3NlKCExLCEwKX0sZS5wcm90b3R5cGUuY2hlY2tNYXhDb25uZWN0VGltZW91dD1mdW5jdGlvbigpe3ZhciBlPXRoaXM7dGhpcy5jbGVhck1heENvbm5lY3RUaW1lb3V0KCksdGhpcy5tYXhDb25uZWN0VGltZW91dElkPXNldFRpbWVvdXQoZnVuY3Rpb24oKXtlLnN0YXR1cyE9PWUud3NJbXBsLk9QRU4mJmUuY2xvc2UoITEsITApfSx0aGlzLm1heENvbm5lY3RUaW1lR2VuZXJhdG9yLmR1cmF0aW9uKCkpfSxlLnByb3RvdHlwZS5jb25uZWN0PWZ1bmN0aW9uKCl7dmFyIGU9dGhpczt0aGlzLmNsaWVudD1uZXcgdGhpcy53c0ltcGwodGhpcy51cmwsZC5HUkFQSFFMX1dTKSx0aGlzLmNoZWNrTWF4Q29ubmVjdFRpbWVvdXQoKSx0aGlzLmNsaWVudC5vbm9wZW49ZnVuY3Rpb24oKXtlLmNsZWFyTWF4Q29ubmVjdFRpbWVvdXQoKSxlLmNsb3NlZEJ5VXNlcj0hMSxlLmV2ZW50RW1pdHRlci5lbWl0KGUucmVjb25uZWN0aW5nPyJyZWNvbm5lY3RpbmciOiJjb25uZWN0aW5nIik7dmFyIHQ9ImZ1bmN0aW9uIj09PXR5cGVvZiBlLmNvbm5lY3Rpb25QYXJhbXM/ZS5jb25uZWN0aW9uUGFyYW1zKCk6ZS5jb25uZWN0aW9uUGFyYW1zO2Uuc2VuZE1lc3NhZ2Uodm9pZCAwLG0uZGVmYXVsdC5HUUxfQ09OTkVDVElPTl9JTklULHQpLGUuZmx1c2hVbnNlbnRNZXNzYWdlc1F1ZXVlKCl9LHRoaXMuY2xpZW50Lm9uY2xvc2U9ZnVuY3Rpb24oKXtlLmNsb3NlZEJ5VXNlcnx8ZS5jbG9zZSghMSwhMSl9LHRoaXMuY2xpZW50Lm9uZXJyb3I9ZnVuY3Rpb24odCl7ZS5ldmVudEVtaXR0ZXIuZW1pdCgiZXJyb3IiLHQpfSx0aGlzLmNsaWVudC5vbm1lc3NhZ2U9ZnVuY3Rpb24odCl7dmFyIG49dC5kYXRhO2UucHJvY2Vzc1JlY2VpdmVkRGF0YShuKX19LGUucHJvdG90eXBlLnByb2Nlc3NSZWNlaXZlZERhdGE9ZnVuY3Rpb24oZSl7dmFyIHQsbjt0cnl7dD1KU09OLnBhcnNlKGUpLG49dC5pZH1jYXRjaCh0KXt0aHJvdyBuZXcgRXJyb3IoIk1lc3NhZ2UgbXVzdCBiZSBKU09OLXBhcnNlYWJsZS4gR290OiAiK2UpfWlmKC0xIT09W20uZGVmYXVsdC5HUUxfREFUQSxtLmRlZmF1bHQuR1FMX0NPTVBMRVRFLG0uZGVmYXVsdC5HUUxfRVJST1JdLmluZGV4T2YodC50eXBlKSYmIXRoaXMub3BlcmF0aW9uc1tuXSlyZXR1cm4gdm9pZCB0aGlzLnVuc3Vic2NyaWJlKG4pO3N3aXRjaCh0LnR5cGUpe2Nhc2UgbS5kZWZhdWx0LkdRTF9DT05ORUNUSU9OX0VSUk9SOnRoaXMuY29ubmVjdGlvbkNhbGxiYWNrJiZ0aGlzLmNvbm5lY3Rpb25DYWxsYmFjayh0LnBheWxvYWQpO2JyZWFrO2Nhc2UgbS5kZWZhdWx0LkdRTF9DT05ORUNUSU9OX0FDSzp0aGlzLmV2ZW50RW1pdHRlci5lbWl0KHRoaXMucmVjb25uZWN0aW5nPyJyZWNvbm5lY3RlZCI6ImNvbm5lY3RlZCIpLHRoaXMucmVjb25uZWN0aW5nPSExLHRoaXMuYmFja29mZi5yZXNldCgpLHRoaXMubWF4Q29ubmVjdFRpbWVHZW5lcmF0b3IucmVzZXQoKSx0aGlzLmNvbm5lY3Rpb25DYWxsYmFjayYmdGhpcy5jb25uZWN0aW9uQ2FsbGJhY2soKTticmVhaztjYXNlIG0uZGVmYXVsdC5HUUxfQ09NUExFVEU6dGhpcy5vcGVyYXRpb25zW25dLmhhbmRsZXIobnVsbCxudWxsKSxkZWxldGUgdGhpcy5vcGVyYXRpb25zW25dO2JyZWFrO2Nhc2UgbS5kZWZhdWx0LkdRTF9FUlJPUjp0aGlzLm9wZXJhdGlvbnNbbl0uaGFuZGxlcih0aGlzLmZvcm1hdEVycm9ycyh0LnBheWxvYWQpLG51bGwpLGRlbGV0ZSB0aGlzLm9wZXJhdGlvbnNbbl07YnJlYWs7Y2FzZSBtLmRlZmF1bHQuR1FMX0RBVEE6dmFyIGk9dC5wYXlsb2FkLmVycm9ycz9yKHt9LHQucGF5bG9hZCx7ZXJyb3JzOnRoaXMuZm9ybWF0RXJyb3JzKHQucGF5bG9hZC5lcnJvcnMpfSk6dC5wYXlsb2FkO3RoaXMub3BlcmF0aW9uc1tuXS5oYW5kbGVyKG51bGwsaSk7YnJlYWs7Y2FzZSBtLmRlZmF1bHQuR1FMX0NPTk5FQ1RJT05fS0VFUF9BTElWRTp2YXIgbz0idW5kZWZpbmVkIj09PXR5cGVvZiB0aGlzLndhc0tlZXBBbGl2ZVJlY2VpdmVkO3RoaXMud2FzS2VlcEFsaXZlUmVjZWl2ZWQ9ITAsbyYmdGhpcy5jaGVja0Nvbm5lY3Rpb24oKSx0aGlzLmNoZWNrQ29ubmVjdGlvbkludGVydmFsSWQmJihjbGVhckludGVydmFsKHRoaXMuY2hlY2tDb25uZWN0aW9uSW50ZXJ2YWxJZCksdGhpcy5jaGVja0Nvbm5lY3Rpb24oKSksdGhpcy5jaGVja0Nvbm5lY3Rpb25JbnRlcnZhbElkPXNldEludGVydmFsKHRoaXMuY2hlY2tDb25uZWN0aW9uLmJpbmQodGhpcyksdGhpcy53c1RpbWVvdXQpO2JyZWFrO2RlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJJbnZhbGlkIG1lc3NhZ2UgdHlwZSEiKX19LGUucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKGUpe3RoaXMub3BlcmF0aW9uc1tlXSYmKGRlbGV0ZSB0aGlzLm9wZXJhdGlvbnNbZV0sdGhpcy5zZXRJbmFjdGl2aXR5VGltZW91dCgpLHRoaXMuc2VuZE1lc3NhZ2UoZSxtLmRlZmF1bHQuR1FMX1NUT1Asdm9pZCAwKSl9LGV9KCk7dC5TdWJzY3JpcHRpb25DbGllbnQ9Z30pLmNhbGwodCxuKDExKSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2Zvcih2YXIgbj1udWxsLHI9MDtyPGUuZGVmaW5pdGlvbnMubGVuZ3RoO3IrKyl7dmFyIG89ZS5kZWZpbml0aW9uc1tyXTtpZihvLmtpbmQ9PT1pLk9QRVJBVElPTl9ERUZJTklUSU9OKWlmKHQpe2lmKG8ubmFtZSYmby5uYW1lLnZhbHVlPT09dClyZXR1cm4gb31lbHNle2lmKG4pcmV0dXJuIG51bGw7bj1vfX1yZXR1cm4gbn1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5nZXRPcGVyYXRpb25BU1Q9cjt2YXIgaT1uKDEwKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBpLnNldEluKGUsWyJxdWVyeSJdLG8ucGFyc2UoZS5xdWVyeSkpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDE0KSxvPW4oNyk7dC5tYWtlT3BlcmF0aW9uPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2lmKCEoZSBpbnN0YW5jZW9mIHQpKXRocm93IG5ldyBUeXBlRXJyb3IoIkNhbm5vdCBjYWxsIGEgY2xhc3MgYXMgYSBmdW5jdGlvbiIpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlNvdXJjZT12b2lkIDA7dmFyIGk9bigxMyksbz1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19KGkpO3QuU291cmNlPWZ1bmN0aW9uIGUodCxuLGkpe3IodGhpcyxlKSx0aGlzLmJvZHk9dCx0aGlzLm5hbWU9bnx8IkdyYXBoUUwgcmVxdWVzdCIsdGhpcy5sb2NhdGlvbk9mZnNldD1pfHx7bGluZToxLGNvbHVtbjoxfSx0aGlzLmxvY2F0aW9uT2Zmc2V0LmxpbmU+MHx8KDAsby5kZWZhdWx0KSgwLCJsaW5lIGluIGxvY2F0aW9uT2Zmc2V0IGlzIDEtaW5kZXhlZCBhbmQgbXVzdCBiZSBwb3NpdGl2ZSIpLHRoaXMubG9jYXRpb25PZmZzZXQuY29sdW1uPjB8fCgwLG8uZGVmYXVsdCkoMCwiY29sdW1uIGluIGxvY2F0aW9uT2Zmc2V0IGlzIDEtaW5kZXhlZCBhbmQgbXVzdCBiZSBwb3NpdGl2ZSIpfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXtpZihlJiZlLnBhdGgpcmV0dXJuIGU7dmFyIHI9ZT9lLm1lc3NhZ2V8fFN0cmluZyhlKToiQW4gdW5rbm93biBlcnJvciBvY2N1cnJlZC4iO3JldHVybiBuZXcgaS5HcmFwaFFMRXJyb3IocixlJiZlLm5vZGVzfHx0LGUmJmUuc291cmNlLGUmJmUucG9zaXRpb25zLG4sZSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQubG9jYXRlZEVycm9yPXI7dmFyIGk9big0Myl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2lmKCEoZSBpbnN0YW5jZW9mIHQpKXRocm93IG5ldyBUeXBlRXJyb3IoIkNhbm5vdCBjYWxsIGEgY2xhc3MgYXMgYSBmdW5jdGlvbiIpfWZ1bmN0aW9uIGkoZSx0LG4scil7cmV0dXJuIGV8fCgwLHMuZGVmYXVsdCkoMCwiTXVzdCBwcm92aWRlIHNjaGVtYSIpLHR8fCgwLHMuZGVmYXVsdCkoMCwiTXVzdCBwcm92aWRlIGRvY3VtZW50IiksZSBpbnN0YW5jZW9mIHAuR3JhcGhRTFNjaGVtYXx8KDAscy5kZWZhdWx0KSgwLCJTY2hlbWEgbXVzdCBiZSBhbiBpbnN0YW5jZSBvZiBHcmFwaFFMU2NoZW1hLiBBbHNvIGVuc3VyZSB0aGF0IHRoZXJlIGFyZSBub3QgbXVsdGlwbGUgdmVyc2lvbnMgb2YgR3JhcGhRTCBpbnN0YWxsZWQgaW4geW91ciBub2RlX21vZHVsZXMgZGlyZWN0b3J5LiIpLG8oZSxyfHxuZXcgZi5UeXBlSW5mbyhlKSx0LG58fGQuc3BlY2lmaWVkUnVsZXMpfWZ1bmN0aW9uIG8oZSx0LG4scil7dmFyIGk9bmV3IGgoZSxuLHQpLG89ci5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUoaSl9KTtyZXR1cm4oMCx1LnZpc2l0KShuLCgwLHUudmlzaXRXaXRoVHlwZUluZm8pKHQsKDAsdS52aXNpdEluUGFyYWxsZWwpKG8pKSksaS5nZXRFcnJvcnMoKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5WYWxpZGF0aW9uQ29udGV4dD12b2lkIDAsdC52YWxpZGF0ZT1pO3ZhciBhPW4oMTMpLHM9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShhKSx1PShuKDMpLG4oNTcpKSxjPW4oMTApLGw9ZnVuY3Rpb24oZSl7aWYoZSYmZS5fX2VzTW9kdWxlKXJldHVybiBlO3ZhciB0PXt9O2lmKG51bGwhPWUpZm9yKHZhciBuIGluIGUpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUsbikmJih0W25dPWVbbl0pO3JldHVybiB0LmRlZmF1bHQ9ZSx0fShjKSxwPW4oMjYpLGY9bigxMTMpLGQ9bigxODIpLGg9dC5WYWxpZGF0aW9uQ29udGV4dD1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCxuLGkpe3IodGhpcyxlKSx0aGlzLl9zY2hlbWE9dCx0aGlzLl9hc3Q9bix0aGlzLl90eXBlSW5mbz1pLHRoaXMuX2Vycm9ycz1bXSx0aGlzLl9mcmFnbWVudFNwcmVhZHM9bmV3IE1hcCx0aGlzLl9yZWN1cnNpdmVseVJlZmVyZW5jZWRGcmFnbWVudHM9bmV3IE1hcCx0aGlzLl92YXJpYWJsZVVzYWdlcz1uZXcgTWFwLHRoaXMuX3JlY3Vyc2l2ZVZhcmlhYmxlVXNhZ2VzPW5ldyBNYXB9cmV0dXJuIGUucHJvdG90eXBlLnJlcG9ydEVycm9yPWZ1bmN0aW9uKGUpe3RoaXMuX2Vycm9ycy5wdXNoKGUpfSxlLnByb3RvdHlwZS5nZXRFcnJvcnM9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fZXJyb3JzfSxlLnByb3RvdHlwZS5nZXRTY2hlbWE9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fc2NoZW1hfSxlLnByb3RvdHlwZS5nZXREb2N1bWVudD1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9hc3R9LGUucHJvdG90eXBlLmdldEZyYWdtZW50PWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuX2ZyYWdtZW50cztyZXR1cm4gdHx8KHRoaXMuX2ZyYWdtZW50cz10PXRoaXMuZ2V0RG9jdW1lbnQoKS5kZWZpbml0aW9ucy5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gdC5raW5kPT09bC5GUkFHTUVOVF9ERUZJTklUSU9OJiYoZVt0Lm5hbWUudmFsdWVdPXQpLGV9LE9iamVjdC5jcmVhdGUobnVsbCkpKSx0W2VdfSxlLnByb3RvdHlwZS5nZXRGcmFnbWVudFNwcmVhZHM9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fZnJhZ21lbnRTcHJlYWRzLmdldChlKTtpZighdCl7dD1bXTtmb3IodmFyIG49W2VdOzAhPT1uLmxlbmd0aDspZm9yKHZhciByPW4ucG9wKCksaT0wO2k8ci5zZWxlY3Rpb25zLmxlbmd0aDtpKyspe3ZhciBvPXIuc2VsZWN0aW9uc1tpXTtvLmtpbmQ9PT1sLkZSQUdNRU5UX1NQUkVBRD90LnB1c2gobyk6by5zZWxlY3Rpb25TZXQmJm4ucHVzaChvLnNlbGVjdGlvblNldCl9dGhpcy5fZnJhZ21lbnRTcHJlYWRzLnNldChlLHQpfXJldHVybiB0fSxlLnByb3RvdHlwZS5nZXRSZWN1cnNpdmVseVJlZmVyZW5jZWRGcmFnbWVudHM9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fcmVjdXJzaXZlbHlSZWZlcmVuY2VkRnJhZ21lbnRzLmdldChlKTtpZighdCl7dD1bXTtmb3IodmFyIG49T2JqZWN0LmNyZWF0ZShudWxsKSxyPVtlLnNlbGVjdGlvblNldF07MCE9PXIubGVuZ3RoOylmb3IodmFyIGk9ci5wb3AoKSxvPXRoaXMuZ2V0RnJhZ21lbnRTcHJlYWRzKGkpLGE9MDthPG8ubGVuZ3RoO2ErKyl7dmFyIHM9b1thXS5uYW1lLnZhbHVlO2lmKCEwIT09bltzXSl7bltzXT0hMDt2YXIgdT10aGlzLmdldEZyYWdtZW50KHMpO3UmJih0LnB1c2godSksci5wdXNoKHUuc2VsZWN0aW9uU2V0KSl9fXRoaXMuX3JlY3Vyc2l2ZWx5UmVmZXJlbmNlZEZyYWdtZW50cy5zZXQoZSx0KX1yZXR1cm4gdH0sZS5wcm90b3R5cGUuZ2V0VmFyaWFibGVVc2FnZXM9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fdmFyaWFibGVVc2FnZXMuZ2V0KGUpO2lmKCF0KXt2YXIgbj1bXSxyPW5ldyBmLlR5cGVJbmZvKHRoaXMuX3NjaGVtYSk7KDAsdS52aXNpdCkoZSwoMCx1LnZpc2l0V2l0aFR5cGVJbmZvKShyLHtWYXJpYWJsZURlZmluaXRpb246ZnVuY3Rpb24oKXtyZXR1cm4hMX0sVmFyaWFibGU6ZnVuY3Rpb24oZSl7bi5wdXNoKHtub2RlOmUsdHlwZTpyLmdldElucHV0VHlwZSgpfSl9fSkpLHQ9bix0aGlzLl92YXJpYWJsZVVzYWdlcy5zZXQoZSx0KX1yZXR1cm4gdH0sZS5wcm90b3R5cGUuZ2V0UmVjdXJzaXZlVmFyaWFibGVVc2FnZXM9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fcmVjdXJzaXZlVmFyaWFibGVVc2FnZXMuZ2V0KGUpO2lmKCF0KXt0PXRoaXMuZ2V0VmFyaWFibGVVc2FnZXMoZSk7Zm9yKHZhciBuPXRoaXMuZ2V0UmVjdXJzaXZlbHlSZWZlcmVuY2VkRnJhZ21lbnRzKGUpLHI9MDtyPG4ubGVuZ3RoO3IrKylBcnJheS5wcm90b3R5cGUucHVzaC5hcHBseSh0LHRoaXMuZ2V0VmFyaWFibGVVc2FnZXMobltyXSkpO3RoaXMuX3JlY3Vyc2l2ZVZhcmlhYmxlVXNhZ2VzLnNldChlLHQpfXJldHVybiB0fSxlLnByb3RvdHlwZS5nZXRUeXBlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3R5cGVJbmZvLmdldFR5cGUoKX0sZS5wcm90b3R5cGUuZ2V0UGFyZW50VHlwZT1mdW5jdGlvbigpe3JldHVybiB0aGlzLl90eXBlSW5mby5nZXRQYXJlbnRUeXBlKCl9LGUucHJvdG90eXBlLmdldElucHV0VHlwZT1mdW5jdGlvbigpe3JldHVybiB0aGlzLl90eXBlSW5mby5nZXRJbnB1dFR5cGUoKX0sZS5wcm90b3R5cGUuZ2V0RmllbGREZWY9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fdHlwZUluZm8uZ2V0RmllbGREZWYoKX0sZS5wcm90b3R5cGUuZ2V0RGlyZWN0aXZlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3R5cGVJbmZvLmdldERpcmVjdGl2ZSgpfSxlLnByb3RvdHlwZS5nZXRBcmd1bWVudD1mdW5jdGlvbigpe3JldHVybiB0aGlzLl90eXBlSW5mby5nZXRBcmd1bWVudCgpfSxlfSgpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnNwZWNpZmllZFJ1bGVzPXZvaWQgMDt2YXIgcj1uKDE4MyksaT1uKDE4NCksbz1uKDE4NSksYT1uKDE4Nikscz1uKDE4NyksdT1uKDE4OCksYz1uKDE4OSksbD1uKDE5MCkscD1uKDE5MSksZj1uKDExNiksZD1uKDExNyksaD1uKDE5MiksbT1uKDE5MyksZz1uKDE5NCkseT1uKDE5NSksdj1uKDE5NiksYj1uKDE5NykseD1uKDE5OCksQz1uKDE5OSksRT1uKDIwMCksRD1uKDIwMSksdz1uKDIwMiksUz1uKDIwMyksaz1uKDIwNCksQT1uKDIwNSksXz1uKDIwNik7dC5zcGVjaWZpZWRSdWxlcz1bci5VbmlxdWVPcGVyYXRpb25OYW1lcyxpLkxvbmVBbm9ueW1vdXNPcGVyYXRpb24sby5TaW5nbGVGaWVsZFN1YnNjcmlwdGlvbnMsYS5Lbm93blR5cGVOYW1lcyxzLkZyYWdtZW50c09uQ29tcG9zaXRlVHlwZXMsdS5WYXJpYWJsZXNBcmVJbnB1dFR5cGVzLGMuU2NhbGFyTGVhZnMsbC5GaWVsZHNPbkNvcnJlY3RUeXBlLHAuVW5pcXVlRnJhZ21lbnROYW1lcyxmLktub3duRnJhZ21lbnROYW1lcyxkLk5vVW51c2VkRnJhZ21lbnRzLGguUG9zc2libGVGcmFnbWVudFNwcmVhZHMsbS5Ob0ZyYWdtZW50Q3ljbGVzLGcuVW5pcXVlVmFyaWFibGVOYW1lcyx5Lk5vVW5kZWZpbmVkVmFyaWFibGVzLHYuTm9VbnVzZWRWYXJpYWJsZXMsYi5Lbm93bkRpcmVjdGl2ZXMseC5VbmlxdWVEaXJlY3RpdmVzUGVyTG9jYXRpb24sQy5Lbm93bkFyZ3VtZW50TmFtZXMsRS5VbmlxdWVBcmd1bWVudE5hbWVzLEQuQXJndW1lbnRzT2ZDb3JyZWN0VHlwZSx3LlByb3ZpZGVkTm9uTnVsbEFyZ3VtZW50cyxTLkRlZmF1bHRWYWx1ZXNPZkNvcnJlY3RUeXBlLGsuVmFyaWFibGVzSW5BbGxvd2VkUG9zaXRpb24sQS5PdmVybGFwcGluZ0ZpZWxkc0NhbkJlTWVyZ2VkLF8uVW5pcXVlSW5wdXRGaWVsZE5hbWVzXX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybidUaGVyZSBjYW4gYmUgb25seSBvbmUgb3BlcmF0aW9uIG5hbWVkICInK2UrJyIuJ31mdW5jdGlvbiBpKGUpe3ZhciB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJue09wZXJhdGlvbkRlZmluaXRpb246ZnVuY3Rpb24obil7dmFyIGk9bi5uYW1lO3JldHVybiBpJiYodFtpLnZhbHVlXT9lLnJlcG9ydEVycm9yKG5ldyBvLkdyYXBoUUxFcnJvcihyKGkudmFsdWUpLFt0W2kudmFsdWVdLGldKSk6dFtpLnZhbHVlXT1pKSwhMX0sRnJhZ21lbnREZWZpbml0aW9uOmZ1bmN0aW9uKCl7cmV0dXJuITF9fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kdXBsaWNhdGVPcGVyYXRpb25OYW1lTWVzc2FnZT1yLHQuVW5pcXVlT3BlcmF0aW9uTmFtZXM9aTt2YXIgbz1uKDMpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXtyZXR1cm4iVGhpcyBhbm9ueW1vdXMgb3BlcmF0aW9uIG11c3QgYmUgdGhlIG9ubHkgZGVmaW5lZCBvcGVyYXRpb24uIn1mdW5jdGlvbiBpKGUpe3ZhciB0PTA7cmV0dXJue0RvY3VtZW50OmZ1bmN0aW9uKGUpe3Q9ZS5kZWZpbml0aW9ucy5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIGUua2luZD09PWEuT1BFUkFUSU9OX0RFRklOSVRJT059KS5sZW5ndGh9LE9wZXJhdGlvbkRlZmluaXRpb246ZnVuY3Rpb24obil7IW4ubmFtZSYmdD4xJiZlLnJlcG9ydEVycm9yKG5ldyBvLkdyYXBoUUxFcnJvcihyKCksW25dKSl9fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5hbm9uT3BlcmF0aW9uTm90QWxvbmVNZXNzYWdlPXIsdC5Mb25lQW5vbnltb3VzT3BlcmF0aW9uPWk7dmFyIG89bigzKSxhPW4oMTApfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuKGU/J1N1YnNjcmlwdGlvbiAiJytlKyciICc6IkFub255bW91cyBTdWJzY3JpcHRpb24gIikrIm11c3Qgc2VsZWN0IG9ubHkgb25lIHRvcCBsZXZlbCBmaWVsZC4ifWZ1bmN0aW9uIGkoZSl7cmV0dXJue09wZXJhdGlvbkRlZmluaXRpb246ZnVuY3Rpb24odCl7InN1YnNjcmlwdGlvbiI9PT10Lm9wZXJhdGlvbiYmMSE9PXQuc2VsZWN0aW9uU2V0LnNlbGVjdGlvbnMubGVuZ3RoJiZlLnJlcG9ydEVycm9yKG5ldyBvLkdyYXBoUUxFcnJvcihyKHQubmFtZSYmdC5uYW1lLnZhbHVlKSx0LnNlbGVjdGlvblNldC5zZWxlY3Rpb25zLnNsaWNlKDEpKSl9fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5zaW5nbGVGaWVsZE9ubHlNZXNzYWdlPXIsdC5TaW5nbGVGaWVsZFN1YnNjcmlwdGlvbnM9aTt2YXIgbz1uKDMpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSx0KXt2YXIgbj0nVW5rbm93biB0eXBlICInK1N0cmluZyhlKSsnIi4nO3JldHVybiB0Lmxlbmd0aCYmKG4rPSIgRGlkIHlvdSBtZWFuICIrKDAsbC5kZWZhdWx0KSh0KSsiPyIpLG59ZnVuY3Rpb24gbyhlKXtyZXR1cm57T2JqZWN0VHlwZURlZmluaXRpb246ZnVuY3Rpb24oKXtyZXR1cm4hMX0sSW50ZXJmYWNlVHlwZURlZmluaXRpb246ZnVuY3Rpb24oKXtyZXR1cm4hMX0sVW5pb25UeXBlRGVmaW5pdGlvbjpmdW5jdGlvbigpe3JldHVybiExfSxJbnB1dE9iamVjdFR5cGVEZWZpbml0aW9uOmZ1bmN0aW9uKCl7cmV0dXJuITF9LE5hbWVkVHlwZTpmdW5jdGlvbih0KXt2YXIgbj1lLmdldFNjaGVtYSgpLHI9dC5uYW1lLnZhbHVlO24uZ2V0VHlwZShyKXx8ZS5yZXBvcnRFcnJvcihuZXcgYS5HcmFwaFFMRXJyb3IoaShyLCgwLHUuZGVmYXVsdCkocixPYmplY3Qua2V5cyhuLmdldFR5cGVNYXAoKSkpKSxbdF0pKX19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnVua25vd25UeXBlTWVzc2FnZT1pLHQuS25vd25UeXBlTmFtZXM9bzt2YXIgYT1uKDMpLHM9bigxMTQpLHU9cihzKSxjPW4oMTE1KSxsPXIoYyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4nRnJhZ21lbnQgY2Fubm90IGNvbmRpdGlvbiBvbiBub24gY29tcG9zaXRlIHR5cGUgIicrU3RyaW5nKGUpKyciLid9ZnVuY3Rpb24gaShlLHQpe3JldHVybidGcmFnbWVudCAiJytlKyciIGNhbm5vdCBjb25kaXRpb24gb24gbm9uIGNvbXBvc2l0ZSB0eXBlICInK1N0cmluZyh0KSsnIi4nfWZ1bmN0aW9uIG8oZSl7cmV0dXJue0lubGluZUZyYWdtZW50OmZ1bmN0aW9uKHQpe2lmKHQudHlwZUNvbmRpdGlvbil7dmFyIG49KDAsYy50eXBlRnJvbUFTVCkoZS5nZXRTY2hlbWEoKSx0LnR5cGVDb25kaXRpb24pO24mJiEoMCx1LmlzQ29tcG9zaXRlVHlwZSkobikmJmUucmVwb3J0RXJyb3IobmV3IGEuR3JhcGhRTEVycm9yKHIoKDAscy5wcmludCkodC50eXBlQ29uZGl0aW9uKSksW3QudHlwZUNvbmRpdGlvbl0pKX19LEZyYWdtZW50RGVmaW5pdGlvbjpmdW5jdGlvbih0KXt2YXIgbj0oMCxjLnR5cGVGcm9tQVNUKShlLmdldFNjaGVtYSgpLHQudHlwZUNvbmRpdGlvbik7biYmISgwLHUuaXNDb21wb3NpdGVUeXBlKShuKSYmZS5yZXBvcnRFcnJvcihuZXcgYS5HcmFwaFFMRXJyb3IoaSh0Lm5hbWUudmFsdWUsKDAscy5wcmludCkodC50eXBlQ29uZGl0aW9uKSksW3QudHlwZUNvbmRpdGlvbl0pKX19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmlubGluZUZyYWdtZW50T25Ob25Db21wb3NpdGVFcnJvck1lc3NhZ2U9cix0LmZyYWdtZW50T25Ob25Db21wb3NpdGVFcnJvck1lc3NhZ2U9aSx0LkZyYWdtZW50c09uQ29tcG9zaXRlVHlwZXM9bzt2YXIgYT1uKDMpLHM9bigxOSksdT1uKDYpLGM9bigyOSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybidWYXJpYWJsZSAiJCcrZSsnIiBjYW5ub3QgYmUgbm9uLWlucHV0IHR5cGUgIicrdCsnIi4nfWZ1bmN0aW9uIGkoZSl7cmV0dXJue1ZhcmlhYmxlRGVmaW5pdGlvbjpmdW5jdGlvbih0KXt2YXIgbj0oMCx1LnR5cGVGcm9tQVNUKShlLmdldFNjaGVtYSgpLHQudHlwZSk7aWYobiYmISgwLHMuaXNJbnB1dFR5cGUpKG4pKXt2YXIgaT10LnZhcmlhYmxlLm5hbWUudmFsdWU7ZS5yZXBvcnRFcnJvcihuZXcgby5HcmFwaFFMRXJyb3IocihpLCgwLGEucHJpbnQpKHQudHlwZSkpLFt0LnR5cGVdKSl9fX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQubm9uSW5wdXRUeXBlT25WYXJNZXNzYWdlPXIsdC5WYXJpYWJsZXNBcmVJbnB1dFR5cGVzPWk7dmFyIG89bigzKSxhPW4oMTkpLHM9big2KSx1PW4oMjkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4nRmllbGQgIicrZSsnIiBtdXN0IG5vdCBoYXZlIGEgc2VsZWN0aW9uIHNpbmNlIHR5cGUgIicrU3RyaW5nKHQpKyciIGhhcyBubyBzdWJmaWVsZHMuJ31mdW5jdGlvbiBpKGUsdCl7cmV0dXJuJ0ZpZWxkICInK2UrJyIgb2YgdHlwZSAiJytTdHJpbmcodCkrJyIgbXVzdCBoYXZlIGEgc2VsZWN0aW9uIG9mIHN1YmZpZWxkcy4gRGlkIHlvdSBtZWFuICInK2UrJyB7IC4uLiB9Ij8nfWZ1bmN0aW9uIG8oZSl7cmV0dXJue0ZpZWxkOmZ1bmN0aW9uKHQpe3ZhciBuPWUuZ2V0VHlwZSgpO24mJigoMCxzLmlzTGVhZlR5cGUpKCgwLHMuZ2V0TmFtZWRUeXBlKShuKSk/dC5zZWxlY3Rpb25TZXQmJmUucmVwb3J0RXJyb3IobmV3IGEuR3JhcGhRTEVycm9yKHIodC5uYW1lLnZhbHVlLG4pLFt0LnNlbGVjdGlvblNldF0pKTp0LnNlbGVjdGlvblNldHx8ZS5yZXBvcnRFcnJvcihuZXcgYS5HcmFwaFFMRXJyb3IoaSh0Lm5hbWUudmFsdWUsbiksW3RdKSkpfX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQubm9TdWJzZWxlY3Rpb25BbGxvd2VkTWVzc2FnZT1yLHQucmVxdWlyZWRTdWJzZWxlY3Rpb25NZXNzYWdlPWksdC5TY2FsYXJMZWFmcz1vO3ZhciBhPW4oMykscz1uKDYpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSx0LG4scil7dmFyIGk9J0Nhbm5vdCBxdWVyeSBmaWVsZCAiJytlKyciIG9uIHR5cGUgIicrdCsnIi4nO2lmKDAhPT1uLmxlbmd0aCl7aSs9IiBEaWQgeW91IG1lYW4gdG8gdXNlIGFuIGlubGluZSBmcmFnbWVudCBvbiAiKygwLGYuZGVmYXVsdCkobikrIj8ifWVsc2UgMCE9PXIubGVuZ3RoJiYoaSs9IiBEaWQgeW91IG1lYW4gIisoMCxmLmRlZmF1bHQpKHIpKyI/Iik7cmV0dXJuIGl9ZnVuY3Rpb24gbyhlKXtyZXR1cm57RmllbGQ6ZnVuY3Rpb24odCl7dmFyIG49ZS5nZXRQYXJlbnRUeXBlKCk7aWYobil7aWYoIWUuZ2V0RmllbGREZWYoKSl7dmFyIHI9ZS5nZXRTY2hlbWEoKSxvPXQubmFtZS52YWx1ZSxjPWEocixuLG8pLGw9MCE9PWMubGVuZ3RoP1tdOnMocixuLG8pO2UucmVwb3J0RXJyb3IobmV3IHUuR3JhcGhRTEVycm9yKGkobyxuLm5hbWUsYyxsKSxbdF0pKX19fX19ZnVuY3Rpb24gYShlLHQsbil7aWYoKDAsZC5pc0Fic3RyYWN0VHlwZSkodCkpe3ZhciByPVtdLGk9T2JqZWN0LmNyZWF0ZShudWxsKTtlLmdldFBvc3NpYmxlVHlwZXModCkuZm9yRWFjaChmdW5jdGlvbihlKXtlLmdldEZpZWxkcygpW25dJiYoci5wdXNoKGUubmFtZSksZS5nZXRJbnRlcmZhY2VzKCkuZm9yRWFjaChmdW5jdGlvbihlKXtlLmdldEZpZWxkcygpW25dJiYoaVtlLm5hbWVdPShpW2UubmFtZV18fDApKzEpfSkpfSk7cmV0dXJuIE9iamVjdC5rZXlzKGkpLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm4gaVt0XS1pW2VdfSkuY29uY2F0KHIpfXJldHVybltdfWZ1bmN0aW9uIHMoZSx0LG4pe2lmKHQgaW5zdGFuY2VvZiBkLkdyYXBoUUxPYmplY3RUeXBlfHx0IGluc3RhbmNlb2YgZC5HcmFwaFFMSW50ZXJmYWNlVHlwZSl7dmFyIHI9T2JqZWN0LmtleXModC5nZXRGaWVsZHMoKSk7cmV0dXJuKDAsbC5kZWZhdWx0KShuLHIpfXJldHVybltdfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnVuZGVmaW5lZEZpZWxkTWVzc2FnZT1pLHQuRmllbGRzT25Db3JyZWN0VHlwZT1vO3ZhciB1PW4oMyksYz1uKDExNCksbD1yKGMpLHA9bigxMTUpLGY9cihwKSxkPW4oNil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4nVGhlcmUgY2FuIGJlIG9ubHkgb25lIGZyYWdtZW50IG5hbWVkICInK2UrJyIuJ31mdW5jdGlvbiBpKGUpe3ZhciB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJue09wZXJhdGlvbkRlZmluaXRpb246ZnVuY3Rpb24oKXtyZXR1cm4hMX0sRnJhZ21lbnREZWZpbml0aW9uOmZ1bmN0aW9uKG4pe3ZhciBpPW4ubmFtZS52YWx1ZTtyZXR1cm4gdFtpXT9lLnJlcG9ydEVycm9yKG5ldyBvLkdyYXBoUUxFcnJvcihyKGkpLFt0W2ldLG4ubmFtZV0pKTp0W2ldPW4ubmFtZSwhMX19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmR1cGxpY2F0ZUZyYWdtZW50TmFtZU1lc3NhZ2U9cix0LlVuaXF1ZUZyYWdtZW50TmFtZXM9aTt2YXIgbz1uKDMpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4pe3JldHVybidGcmFnbWVudCAiJytlKyciIGNhbm5vdCBiZSBzcHJlYWQgaGVyZSBhcyBvYmplY3RzIG9mIHR5cGUgIicrU3RyaW5nKHQpKyciIGNhbiBuZXZlciBiZSBvZiB0eXBlICInK1N0cmluZyhuKSsnIi4nfWZ1bmN0aW9uIGkoZSx0KXtyZXR1cm4nRnJhZ21lbnQgY2Fubm90IGJlIHNwcmVhZCBoZXJlIGFzIG9iamVjdHMgb2YgdHlwZSAiJytTdHJpbmcoZSkrJyIgY2FuIG5ldmVyIGJlIG9mIHR5cGUgIicrU3RyaW5nKHQpKyciLid9ZnVuY3Rpb24gbyhlKXtyZXR1cm57SW5saW5lRnJhZ21lbnQ6ZnVuY3Rpb24odCl7dmFyIG49ZS5nZXRUeXBlKCkscj1lLmdldFBhcmVudFR5cGUoKTsoMCxsLmlzQ29tcG9zaXRlVHlwZSkobikmJigwLGwuaXNDb21wb3NpdGVUeXBlKShyKSYmISgwLHUuZG9UeXBlc092ZXJsYXApKGUuZ2V0U2NoZW1hKCksbixyKSYmZS5yZXBvcnRFcnJvcihuZXcgcy5HcmFwaFFMRXJyb3IoaShyLG4pLFt0XSkpfSxGcmFnbWVudFNwcmVhZDpmdW5jdGlvbih0KXt2YXIgbj10Lm5hbWUudmFsdWUsaT1hKGUsbiksbz1lLmdldFBhcmVudFR5cGUoKTtpJiZvJiYhKDAsdS5kb1R5cGVzT3ZlcmxhcCkoZS5nZXRTY2hlbWEoKSxpLG8pJiZlLnJlcG9ydEVycm9yKG5ldyBzLkdyYXBoUUxFcnJvcihyKG4sbyxpKSxbdF0pKX19fWZ1bmN0aW9uIGEoZSx0KXt2YXIgbj1lLmdldEZyYWdtZW50KHQpO3JldHVybiBuJiYoMCxjLnR5cGVGcm9tQVNUKShlLmdldFNjaGVtYSgpLG4udHlwZUNvbmRpdGlvbil9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQudHlwZUluY29tcGF0aWJsZVNwcmVhZE1lc3NhZ2U9cix0LnR5cGVJbmNvbXBhdGlibGVBbm9uU3ByZWFkTWVzc2FnZT1pLHQuUG9zc2libGVGcmFnbWVudFNwcmVhZHM9bzt2YXIgcz1uKDMpLHU9big4MSksYz1uKDI5KSxsPW4oNil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybidDYW5ub3Qgc3ByZWFkIGZyYWdtZW50ICInK2UrJyIgd2l0aGluIGl0c2VsZicrKHQubGVuZ3RoPyIgdmlhICIrdC5qb2luKCIsICIpOiIiKSsiLiJ9ZnVuY3Rpb24gaShlKXtmdW5jdGlvbiB0KHMpe3ZhciB1PXMubmFtZS52YWx1ZTtuW3VdPSEwO3ZhciBjPWUuZ2V0RnJhZ21lbnRTcHJlYWRzKHMuc2VsZWN0aW9uU2V0KTtpZigwIT09Yy5sZW5ndGgpe2FbdV09aS5sZW5ndGg7Zm9yKHZhciBsPTA7bDxjLmxlbmd0aDtsKyspe3ZhciBwPWNbbF0sZj1wLm5hbWUudmFsdWUsZD1hW2ZdO2lmKHZvaWQgMD09PWQpe2lmKGkucHVzaChwKSwhbltmXSl7dmFyIGg9ZS5nZXRGcmFnbWVudChmKTtoJiZ0KGgpfWkucG9wKCl9ZWxzZXt2YXIgbT1pLnNsaWNlKGQpO2UucmVwb3J0RXJyb3IobmV3IG8uR3JhcGhRTEVycm9yKHIoZixtLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lLnZhbHVlfSkpLG0uY29uY2F0KHApKSl9fWFbdV09dm9pZCAwfX12YXIgbj1PYmplY3QuY3JlYXRlKG51bGwpLGk9W10sYT1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybntPcGVyYXRpb25EZWZpbml0aW9uOmZ1bmN0aW9uKCl7cmV0dXJuITF9LEZyYWdtZW50RGVmaW5pdGlvbjpmdW5jdGlvbihlKXtyZXR1cm4gbltlLm5hbWUudmFsdWVdfHx0KGUpLCExfX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuY3ljbGVFcnJvck1lc3NhZ2U9cix0Lk5vRnJhZ21lbnRDeWNsZXM9aTt2YXIgbz1uKDMpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuJ1RoZXJlIGNhbiBiZSBvbmx5IG9uZSB2YXJpYWJsZSBuYW1lZCAiJytlKyciLid9ZnVuY3Rpb24gaShlKXt2YXIgdD1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybntPcGVyYXRpb25EZWZpbml0aW9uOmZ1bmN0aW9uKCl7dD1PYmplY3QuY3JlYXRlKG51bGwpfSxWYXJpYWJsZURlZmluaXRpb246ZnVuY3Rpb24obil7dmFyIGk9bi52YXJpYWJsZS5uYW1lLnZhbHVlO3RbaV0/ZS5yZXBvcnRFcnJvcihuZXcgby5HcmFwaFFMRXJyb3IocihpKSxbdFtpXSxuLnZhcmlhYmxlLm5hbWVdKSk6dFtpXT1uLnZhcmlhYmxlLm5hbWV9fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kdXBsaWNhdGVWYXJpYWJsZU1lc3NhZ2U9cix0LlVuaXF1ZVZhcmlhYmxlTmFtZXM9aTt2YXIgbz1uKDMpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4gdD8nVmFyaWFibGUgIiQnK2UrJyIgaXMgbm90IGRlZmluZWQgYnkgb3BlcmF0aW9uICInK3QrJyIuJzonVmFyaWFibGUgIiQnK2UrJyIgaXMgbm90IGRlZmluZWQuJ31mdW5jdGlvbiBpKGUpe3ZhciB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJue09wZXJhdGlvbkRlZmluaXRpb246e2VudGVyOmZ1bmN0aW9uKCl7dD1PYmplY3QuY3JlYXRlKG51bGwpfSxsZWF2ZTpmdW5jdGlvbihuKXtlLmdldFJlY3Vyc2l2ZVZhcmlhYmxlVXNhZ2VzKG4pLmZvckVhY2goZnVuY3Rpb24oaSl7dmFyIGE9aS5ub2RlLHM9YS5uYW1lLnZhbHVlOyEwIT09dFtzXSYmZS5yZXBvcnRFcnJvcihuZXcgby5HcmFwaFFMRXJyb3IocihzLG4ubmFtZSYmbi5uYW1lLnZhbHVlKSxbYSxuXSkpfSl9fSxWYXJpYWJsZURlZmluaXRpb246ZnVuY3Rpb24oZSl7dFtlLnZhcmlhYmxlLm5hbWUudmFsdWVdPSEwfX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQudW5kZWZpbmVkVmFyTWVzc2FnZT1yLHQuTm9VbmRlZmluZWRWYXJpYWJsZXM9aTt2YXIgbz1uKDMpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4gdD8nVmFyaWFibGUgIiQnK2UrJyIgaXMgbmV2ZXIgdXNlZCBpbiBvcGVyYXRpb24gIicrdCsnIi4nOidWYXJpYWJsZSAiJCcrZSsnIiBpcyBuZXZlciB1c2VkLid9ZnVuY3Rpb24gaShlKXt2YXIgdD1bXTtyZXR1cm57T3BlcmF0aW9uRGVmaW5pdGlvbjp7ZW50ZXI6ZnVuY3Rpb24oKXt0PVtdfSxsZWF2ZTpmdW5jdGlvbihuKXt2YXIgaT1PYmplY3QuY3JlYXRlKG51bGwpLGE9ZS5nZXRSZWN1cnNpdmVWYXJpYWJsZVVzYWdlcyhuKSxzPW4ubmFtZT9uLm5hbWUudmFsdWU6bnVsbDthLmZvckVhY2goZnVuY3Rpb24oZSl7dmFyIHQ9ZS5ub2RlO2lbdC5uYW1lLnZhbHVlXT0hMH0pLHQuZm9yRWFjaChmdW5jdGlvbih0KXt2YXIgbj10LnZhcmlhYmxlLm5hbWUudmFsdWU7ITAhPT1pW25dJiZlLnJlcG9ydEVycm9yKG5ldyBvLkdyYXBoUUxFcnJvcihyKG4scyksW3RdKSl9KX19LFZhcmlhYmxlRGVmaW5pdGlvbjpmdW5jdGlvbihlKXt0LnB1c2goZSl9fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC51bnVzZWRWYXJpYWJsZU1lc3NhZ2U9cix0Lk5vVW51c2VkVmFyaWFibGVzPWk7dmFyIG89bigzKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybidVbmtub3duIGRpcmVjdGl2ZSAiJytlKyciLid9ZnVuY3Rpb24gaShlLHQpe3JldHVybidEaXJlY3RpdmUgIicrZSsnIiBtYXkgbm90IGJlIHVzZWQgb24gJyt0KyIuIn1mdW5jdGlvbiBvKGUpe3JldHVybntEaXJlY3RpdmU6ZnVuY3Rpb24odCxuLG8sdSxsKXt2YXIgcD0oMCxjLmRlZmF1bHQpKGUuZ2V0U2NoZW1hKCkuZ2V0RGlyZWN0aXZlcygpLGZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWU9PT10Lm5hbWUudmFsdWV9KTtpZighcClyZXR1cm4gdm9pZCBlLnJlcG9ydEVycm9yKG5ldyBzLkdyYXBoUUxFcnJvcihyKHQubmFtZS52YWx1ZSksW3RdKSk7dmFyIGY9YShsKTtmPy0xPT09cC5sb2NhdGlvbnMuaW5kZXhPZihmKSYmZS5yZXBvcnRFcnJvcihuZXcgcy5HcmFwaFFMRXJyb3IoaSh0Lm5hbWUudmFsdWUsZiksW3RdKSk6ZS5yZXBvcnRFcnJvcihuZXcgcy5HcmFwaFFMRXJyb3IoaSh0Lm5hbWUudmFsdWUsdC50eXBlKSxbdF0pKX19fWZ1bmN0aW9uIGEoZSl7dmFyIHQ9ZVtlLmxlbmd0aC0xXTtzd2l0Y2godC5raW5kKXtjYXNlIHAuT1BFUkFUSU9OX0RFRklOSVRJT046c3dpdGNoKHQub3BlcmF0aW9uKXtjYXNlInF1ZXJ5IjpyZXR1cm4gZi5EaXJlY3RpdmVMb2NhdGlvbi5RVUVSWTtjYXNlIm11dGF0aW9uIjpyZXR1cm4gZi5EaXJlY3RpdmVMb2NhdGlvbi5NVVRBVElPTjtjYXNlInN1YnNjcmlwdGlvbiI6cmV0dXJuIGYuRGlyZWN0aXZlTG9jYXRpb24uU1VCU0NSSVBUSU9OfWJyZWFrO2Nhc2UgcC5GSUVMRDpyZXR1cm4gZi5EaXJlY3RpdmVMb2NhdGlvbi5GSUVMRDtjYXNlIHAuRlJBR01FTlRfU1BSRUFEOnJldHVybiBmLkRpcmVjdGl2ZUxvY2F0aW9uLkZSQUdNRU5UX1NQUkVBRDtjYXNlIHAuSU5MSU5FX0ZSQUdNRU5UOnJldHVybiBmLkRpcmVjdGl2ZUxvY2F0aW9uLklOTElORV9GUkFHTUVOVDtjYXNlIHAuRlJBR01FTlRfREVGSU5JVElPTjpyZXR1cm4gZi5EaXJlY3RpdmVMb2NhdGlvbi5GUkFHTUVOVF9ERUZJTklUSU9OO2Nhc2UgcC5TQ0hFTUFfREVGSU5JVElPTjpyZXR1cm4gZi5EaXJlY3RpdmVMb2NhdGlvbi5TQ0hFTUE7Y2FzZSBwLlNDQUxBUl9UWVBFX0RFRklOSVRJT046cmV0dXJuIGYuRGlyZWN0aXZlTG9jYXRpb24uU0NBTEFSO2Nhc2UgcC5PQkpFQ1RfVFlQRV9ERUZJTklUSU9OOnJldHVybiBmLkRpcmVjdGl2ZUxvY2F0aW9uLk9CSkVDVDtjYXNlIHAuRklFTERfREVGSU5JVElPTjpyZXR1cm4gZi5EaXJlY3RpdmVMb2NhdGlvbi5GSUVMRF9ERUZJTklUSU9OO2Nhc2UgcC5JTlRFUkZBQ0VfVFlQRV9ERUZJTklUSU9OOnJldHVybiBmLkRpcmVjdGl2ZUxvY2F0aW9uLklOVEVSRkFDRTtjYXNlIHAuVU5JT05fVFlQRV9ERUZJTklUSU9OOnJldHVybiBmLkRpcmVjdGl2ZUxvY2F0aW9uLlVOSU9OO2Nhc2UgcC5FTlVNX1RZUEVfREVGSU5JVElPTjpyZXR1cm4gZi5EaXJlY3RpdmVMb2NhdGlvbi5FTlVNO2Nhc2UgcC5FTlVNX1ZBTFVFX0RFRklOSVRJT046cmV0dXJuIGYuRGlyZWN0aXZlTG9jYXRpb24uRU5VTV9WQUxVRTtjYXNlIHAuSU5QVVRfT0JKRUNUX1RZUEVfREVGSU5JVElPTjpyZXR1cm4gZi5EaXJlY3RpdmVMb2NhdGlvbi5JTlBVVF9PQkpFQ1Q7Y2FzZSBwLklOUFVUX1ZBTFVFX0RFRklOSVRJT046cmV0dXJuIGVbZS5sZW5ndGgtM10ua2luZD09PXAuSU5QVVRfT0JKRUNUX1RZUEVfREVGSU5JVElPTj9mLkRpcmVjdGl2ZUxvY2F0aW9uLklOUFVUX0ZJRUxEX0RFRklOSVRJT046Zi5EaXJlY3RpdmVMb2NhdGlvbi5BUkdVTUVOVF9ERUZJTklUSU9OfX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC51bmtub3duRGlyZWN0aXZlTWVzc2FnZT1yLHQubWlzcGxhY2VkRGlyZWN0aXZlTWVzc2FnZT1pLHQuS25vd25EaXJlY3RpdmVzPW87dmFyIHM9bigzKSx1PW4oNDUpLGM9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fSh1KSxsPW4oMTApLHA9ZnVuY3Rpb24oZSl7aWYoZSYmZS5fX2VzTW9kdWxlKXJldHVybiBlO3ZhciB0PXt9O2lmKG51bGwhPWUpZm9yKHZhciBuIGluIGUpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUsbikmJih0W25dPWVbbl0pO3JldHVybiB0LmRlZmF1bHQ9ZSx0fShsKSxmPW4oMjcpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuJ1RoZSBkaXJlY3RpdmUgIicrZSsnIiBjYW4gb25seSBiZSB1c2VkIG9uY2UgYXQgdGhpcyBsb2NhdGlvbi4nfWZ1bmN0aW9uIGkoZSl7cmV0dXJue2VudGVyOmZ1bmN0aW9uKHQpe2lmKHQuZGlyZWN0aXZlcyl7dmFyIG49T2JqZWN0LmNyZWF0ZShudWxsKTt0LmRpcmVjdGl2ZXMuZm9yRWFjaChmdW5jdGlvbih0KXt2YXIgaT10Lm5hbWUudmFsdWU7bltpXT9lLnJlcG9ydEVycm9yKG5ldyBvLkdyYXBoUUxFcnJvcihyKGkpLFtuW2ldLHRdKSk6bltpXT10fSl9fX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZHVwbGljYXRlRGlyZWN0aXZlTWVzc2FnZT1yLHQuVW5pcXVlRGlyZWN0aXZlc1BlckxvY2F0aW9uPWk7dmFyIG89bigzKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1mdW5jdGlvbiBpKGUsdCxuLHIpe3ZhciBpPSdVbmtub3duIGFyZ3VtZW50ICInK2UrJyIgb24gZmllbGQgIicrdCsnIiBvZiB0eXBlICInK24rJyIuJztyZXR1cm4gci5sZW5ndGgmJihpKz0iIERpZCB5b3UgbWVhbiAiKygwLG0uZGVmYXVsdCkocikrIj8iKSxpfWZ1bmN0aW9uIG8oZSx0LG4pe3ZhciByPSdVbmtub3duIGFyZ3VtZW50ICInK2UrJyIgb24gZGlyZWN0aXZlICJAJyt0KyciLic7cmV0dXJuIG4ubGVuZ3RoJiYocis9IiBEaWQgeW91IG1lYW4gIisoMCxtLmRlZmF1bHQpKG4pKyI/Iikscn1mdW5jdGlvbiBhKGUpe3JldHVybntBcmd1bWVudDpmdW5jdGlvbih0LG4scixhLHUpe3ZhciBsPXVbdS5sZW5ndGgtMV07aWYobC5raW5kPT09eS5GSUVMRCl7dmFyIGY9ZS5nZXRGaWVsZERlZigpO2lmKGYpe2lmKCEoMCxjLmRlZmF1bHQpKGYuYXJncyxmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lPT09dC5uYW1lLnZhbHVlfSkpe3ZhciBoPWUuZ2V0UGFyZW50VHlwZSgpO2h8fCgwLHAuZGVmYXVsdCkoMCksZS5yZXBvcnRFcnJvcihuZXcgcy5HcmFwaFFMRXJyb3IoaSh0Lm5hbWUudmFsdWUsZi5uYW1lLGgubmFtZSwoMCxkLmRlZmF1bHQpKHQubmFtZS52YWx1ZSxmLmFyZ3MubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWV9KSkpLFt0XSkpfX19ZWxzZSBpZihsLmtpbmQ9PT15LkRJUkVDVElWRSl7dmFyIG09ZS5nZXREaXJlY3RpdmUoKTtpZihtKXt2YXIgZz0oMCxjLmRlZmF1bHQpKG0uYXJncyxmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lPT09dC5uYW1lLnZhbHVlfSk7Z3x8ZS5yZXBvcnRFcnJvcihuZXcgcy5HcmFwaFFMRXJyb3Iobyh0Lm5hbWUudmFsdWUsbS5uYW1lLCgwLGQuZGVmYXVsdCkodC5uYW1lLnZhbHVlLG0uYXJncy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZX0pKSksW3RdKSl9fX19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnVua25vd25BcmdNZXNzYWdlPWksdC51bmtub3duRGlyZWN0aXZlQXJnTWVzc2FnZT1vLHQuS25vd25Bcmd1bWVudE5hbWVzPWE7dmFyIHM9bigzKSx1PW4oNDUpLGM9cih1KSxsPW4oMTMpLHA9cihsKSxmPW4oMTE0KSxkPXIoZiksaD1uKDExNSksbT1yKGgpLGc9bigxMCkseT1mdW5jdGlvbihlKXtpZihlJiZlLl9fZXNNb2R1bGUpcmV0dXJuIGU7dmFyIHQ9e307aWYobnVsbCE9ZSlmb3IodmFyIG4gaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxuKSYmKHRbbl09ZVtuXSk7cmV0dXJuIHQuZGVmYXVsdD1lLHR9KGcpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuJ1RoZXJlIGNhbiBiZSBvbmx5IG9uZSBhcmd1bWVudCBuYW1lZCAiJytlKyciLid9ZnVuY3Rpb24gaShlKXt2YXIgdD1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybntGaWVsZDpmdW5jdGlvbigpe3Q9T2JqZWN0LmNyZWF0ZShudWxsKX0sRGlyZWN0aXZlOmZ1bmN0aW9uKCl7dD1PYmplY3QuY3JlYXRlKG51bGwpfSxBcmd1bWVudDpmdW5jdGlvbihuKXt2YXIgaT1uLm5hbWUudmFsdWU7cmV0dXJuIHRbaV0/ZS5yZXBvcnRFcnJvcihuZXcgby5HcmFwaFFMRXJyb3IocihpKSxbdFtpXSxuLm5hbWVdKSk6dFtpXT1uLm5hbWUsITF9fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kdXBsaWNhdGVBcmdNZXNzYWdlPXIsdC5VbmlxdWVBcmd1bWVudE5hbWVzPWk7dmFyIG89bigzKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuLHIpe3JldHVybidBcmd1bWVudCAiJytlKyciIGhhcyBpbnZhbGlkIHZhbHVlICcrbisiLiIrKHI/IlxuIityLmpvaW4oIlxuIik6IiIpfWZ1bmN0aW9uIGkoZSl7cmV0dXJue0FyZ3VtZW50OmZ1bmN0aW9uKHQpe3ZhciBuPWUuZ2V0QXJndW1lbnQoKTtpZihuKXt2YXIgaT0oMCxzLmlzVmFsaWRMaXRlcmFsVmFsdWUpKG4udHlwZSx0LnZhbHVlKTtpJiZpLmxlbmd0aD4wJiZlLnJlcG9ydEVycm9yKG5ldyBvLkdyYXBoUUxFcnJvcihyKHQubmFtZS52YWx1ZSxuLnR5cGUsKDAsYS5wcmludCkodC52YWx1ZSksaSksW3QudmFsdWVdKSl9cmV0dXJuITF9fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5iYWRWYWx1ZU1lc3NhZ2U9cix0LkFyZ3VtZW50c09mQ29ycmVjdFR5cGU9aTt2YXIgbz1uKDMpLGE9bigxOSkscz1uKDgyKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXtyZXR1cm4nRmllbGQgIicrZSsnIiBhcmd1bWVudCAiJyt0KyciIG9mIHR5cGUgIicrU3RyaW5nKG4pKyciIGlzIHJlcXVpcmVkIGJ1dCBub3QgcHJvdmlkZWQuJ31mdW5jdGlvbiBpKGUsdCxuKXtyZXR1cm4nRGlyZWN0aXZlICJAJytlKyciIGFyZ3VtZW50ICInK3QrJyIgb2YgdHlwZSAiJytTdHJpbmcobikrJyIgaXMgcmVxdWlyZWQgYnV0IG5vdCBwcm92aWRlZC4nfWZ1bmN0aW9uIG8oZSl7cmV0dXJue0ZpZWxkOntsZWF2ZTpmdW5jdGlvbih0KXt2YXIgbj1lLmdldEZpZWxkRGVmKCk7aWYoIW4pcmV0dXJuITE7dmFyIGk9dC5hcmd1bWVudHN8fFtdLG89KDAsdS5kZWZhdWx0KShpLGZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWUudmFsdWV9KTtuLmFyZ3MuZm9yRWFjaChmdW5jdGlvbihuKXshb1tuLm5hbWVdJiZuLnR5cGUgaW5zdGFuY2VvZiBjLkdyYXBoUUxOb25OdWxsJiZlLnJlcG9ydEVycm9yKG5ldyBhLkdyYXBoUUxFcnJvcihyKHQubmFtZS52YWx1ZSxuLm5hbWUsbi50eXBlKSxbdF0pKX0pfX0sRGlyZWN0aXZlOntsZWF2ZTpmdW5jdGlvbih0KXt2YXIgbj1lLmdldERpcmVjdGl2ZSgpO2lmKCFuKXJldHVybiExO3ZhciByPXQuYXJndW1lbnRzfHxbXSxvPSgwLHUuZGVmYXVsdCkocixmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lLnZhbHVlfSk7bi5hcmdzLmZvckVhY2goZnVuY3Rpb24obil7IW9bbi5uYW1lXSYmbi50eXBlIGluc3RhbmNlb2YgYy5HcmFwaFFMTm9uTnVsbCYmZS5yZXBvcnRFcnJvcihuZXcgYS5HcmFwaFFMRXJyb3IoaSh0Lm5hbWUudmFsdWUsbi5uYW1lLG4udHlwZSksW3RdKSl9KX19fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5taXNzaW5nRmllbGRBcmdNZXNzYWdlPXIsdC5taXNzaW5nRGlyZWN0aXZlQXJnTWVzc2FnZT1pLHQuUHJvdmlkZWROb25OdWxsQXJndW1lbnRzPW87dmFyIGE9bigzKSxzPW4oNDYpLHU9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShzKSxjPW4oNil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuJ1ZhcmlhYmxlICIkJytlKyciIG9mIHR5cGUgIicrU3RyaW5nKHQpKyciIGlzIHJlcXVpcmVkIGFuZCB3aWxsIG5vdCB1c2UgdGhlIGRlZmF1bHQgdmFsdWUuIFBlcmhhcHMgeW91IG1lYW50IHRvIHVzZSB0eXBlICInK1N0cmluZyhuKSsnIi4nfWZ1bmN0aW9uIGkoZSx0LG4scil7dmFyIGk9cj8iXG4iK3Iuam9pbigiXG4iKToiIjtyZXR1cm4nVmFyaWFibGUgIiQnK2UrJyIgb2YgdHlwZSAiJytTdHJpbmcodCkrJyIgaGFzIGludmFsaWQgZGVmYXVsdCB2YWx1ZSAnK24rIi4iK2l9ZnVuY3Rpb24gbyhlKXtyZXR1cm57VmFyaWFibGVEZWZpbml0aW9uOmZ1bmN0aW9uKHQpe3ZhciBuPXQudmFyaWFibGUubmFtZS52YWx1ZSxvPXQuZGVmYXVsdFZhbHVlLGw9ZS5nZXRJbnB1dFR5cGUoKTtpZihsIGluc3RhbmNlb2YgdS5HcmFwaFFMTm9uTnVsbCYmbyYmZS5yZXBvcnRFcnJvcihuZXcgYS5HcmFwaFFMRXJyb3IocihuLGwsbC5vZlR5cGUpLFtvXSkpLGwmJm8pe3ZhciBwPSgwLGMuaXNWYWxpZExpdGVyYWxWYWx1ZSkobCxvKTtwJiZwLmxlbmd0aD4wJiZlLnJlcG9ydEVycm9yKG5ldyBhLkdyYXBoUUxFcnJvcihpKG4sbCwoMCxzLnByaW50KShvKSxwKSxbb10pKX1yZXR1cm4hMX0sU2VsZWN0aW9uU2V0OmZ1bmN0aW9uKCl7cmV0dXJuITF9LEZyYWdtZW50RGVmaW5pdGlvbjpmdW5jdGlvbigpe3JldHVybiExfX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZGVmYXVsdEZvck5vbk51bGxBcmdNZXNzYWdlPXIsdC5iYWRWYWx1ZUZvckRlZmF1bHRBcmdNZXNzYWdlPWksdC5EZWZhdWx0VmFsdWVzT2ZDb3JyZWN0VHlwZT1vO3ZhciBhPW4oMykscz1uKDE5KSx1PW4oNiksYz1uKDgyKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXtyZXR1cm4nVmFyaWFibGUgIiQnK2UrJyIgb2YgdHlwZSAiJytTdHJpbmcodCkrJyIgdXNlZCBpbiBwb3NpdGlvbiBleHBlY3RpbmcgdHlwZSAiJytTdHJpbmcobikrJyIuJ31mdW5jdGlvbiBpKGUpe3ZhciB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJue09wZXJhdGlvbkRlZmluaXRpb246e2VudGVyOmZ1bmN0aW9uKCl7dD1PYmplY3QuY3JlYXRlKG51bGwpfSxsZWF2ZTpmdW5jdGlvbihuKXtlLmdldFJlY3Vyc2l2ZVZhcmlhYmxlVXNhZ2VzKG4pLmZvckVhY2goZnVuY3Rpb24obil7dmFyIGk9bi5ub2RlLHM9bi50eXBlLGw9aS5uYW1lLnZhbHVlLHA9dFtsXTtpZihwJiZzKXt2YXIgZj1lLmdldFNjaGVtYSgpLGQ9KDAsYy50eXBlRnJvbUFTVCkoZixwLnR5cGUpO2QmJiEoMCx1LmlzVHlwZVN1YlR5cGVPZikoZixvKGQscCkscykmJmUucmVwb3J0RXJyb3IobmV3IGEuR3JhcGhRTEVycm9yKHIobCxkLHMpLFtwLGldKSl9fSl9fSxWYXJpYWJsZURlZmluaXRpb246ZnVuY3Rpb24oZSl7dFtlLnZhcmlhYmxlLm5hbWUudmFsdWVdPWV9fX1mdW5jdGlvbiBvKGUsdCl7cmV0dXJuIXQuZGVmYXVsdFZhbHVlfHxlIGluc3RhbmNlb2Ygcy5HcmFwaFFMTm9uTnVsbD9lOm5ldyBzLkdyYXBoUUxOb25OdWxsKGUpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmJhZFZhclBvc01lc3NhZ2U9cix0LlZhcmlhYmxlc0luQWxsb3dlZFBvc2l0aW9uPWk7dmFyIGE9bigzKSxzPW4oNiksdT1uKDgxKSxjPW4oMjkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBpKGUsdCl7cmV0dXJuJ0ZpZWxkcyAiJytlKyciIGNvbmZsaWN0IGJlY2F1c2UgJytvKHQpKyIuIFVzZSBkaWZmZXJlbnQgYWxpYXNlcyBvbiB0aGUgZmllbGRzIHRvIGZldGNoIGJvdGggaWYgdGhpcyB3YXMgaW50ZW50aW9uYWwuIn1mdW5jdGlvbiBvKGUpe3JldHVybiBBcnJheS5pc0FycmF5KGUpP2UubWFwKGZ1bmN0aW9uKGUpe3JldHVybidzdWJmaWVsZHMgIicrZVswXSsnIiBjb25mbGljdCBiZWNhdXNlICcrbyhlWzFdKX0pLmpvaW4oIiBhbmQgIik6ZX1mdW5jdGlvbiBhKGUpe3ZhciB0PW5ldyBPLG49bmV3IE1hcDtyZXR1cm57U2VsZWN0aW9uU2V0OmZ1bmN0aW9uKHIpe3MoZSxuLHQsZS5nZXRQYXJlbnRUeXBlKCkscikuZm9yRWFjaChmdW5jdGlvbih0KXt2YXIgbj10WzBdLHI9blswXSxvPW5bMV0sYT10WzFdLHM9dFsyXTtyZXR1cm4gZS5yZXBvcnRFcnJvcihuZXcgRS5HcmFwaFFMRXJyb3IoaShyLG8pLGEuY29uY2F0KHMpKSl9KX19fWZ1bmN0aW9uIHMoZSx0LG4scixpKXt2YXIgbz1bXSxhPXkoZSx0LHIsaSkscz1hWzBdLGw9YVsxXTtwKGUsbyx0LG4scyk7Zm9yKHZhciBmPTA7ZjxsLmxlbmd0aDtmKyspe3UoZSxvLHQsbiwhMSxzLGxbZl0pO2Zvcih2YXIgZD1mKzE7ZDxsLmxlbmd0aDtkKyspYyhlLG8sdCxuLCExLGxbZl0sbFtkXSl9cmV0dXJuIG99ZnVuY3Rpb24gdShlLHQsbixyLGksbyxhKXt2YXIgcz1lLmdldEZyYWdtZW50KGEpO2lmKHMpe3ZhciBjPXYoZSxuLHMpLGw9Y1swXSxwPWNbMV07ZihlLHQsbixyLGksbyxsKTtmb3IodmFyIGQ9MDtkPHAubGVuZ3RoO2QrKyl1KGUsdCxuLHIsaSxvLHBbZF0pfX1mdW5jdGlvbiBjKGUsdCxuLHIsaSxvLGEpe3ZhciBzPWUuZ2V0RnJhZ21lbnQobyksdT1lLmdldEZyYWdtZW50KGEpO2lmKHMmJnUmJnMhPT11JiYhci5oYXMobyxhLGkpKXtyLmFkZChvLGEsaSk7dmFyIGw9dihlLG4scykscD1sWzBdLGQ9bFsxXSxoPXYoZSxuLHUpLG09aFswXSxnPWhbMV07ZihlLHQsbixyLGkscCxtKTtmb3IodmFyIHk9MDt5PGcubGVuZ3RoO3krKyljKGUsdCxuLHIsaSxvLGdbeV0pO2Zvcih2YXIgYj0wO2I8ZC5sZW5ndGg7YisrKWMoZSx0LG4scixpLGRbYl0sYSl9fWZ1bmN0aW9uIGwoZSx0LG4scixpLG8sYSxzKXt2YXIgbD1bXSxwPXkoZSx0LGksbyksZD1wWzBdLGg9cFsxXSxtPXkoZSx0LGEscyksZz1tWzBdLHY9bVsxXTtmKGUsbCx0LG4scixkLGcpO2Zvcih2YXIgYj0wO2I8di5sZW5ndGg7YisrKXUoZSxsLHQsbixyLGQsdltiXSk7Zm9yKHZhciB4PTA7eDxoLmxlbmd0aDt4KyspdShlLGwsdCxuLHIsZyxoW3hdKTtmb3IodmFyIEM9MDtDPGgubGVuZ3RoO0MrKylmb3IodmFyIEU9MDtFPHYubGVuZ3RoO0UrKyljKGUsbCx0LG4scixoW0NdLHZbRV0pO3JldHVybiBsfWZ1bmN0aW9uIHAoZSx0LG4scixpKXtPYmplY3Qua2V5cyhpKS5mb3JFYWNoKGZ1bmN0aW9uKG8pe3ZhciBhPWlbb107aWYoYS5sZW5ndGg+MSlmb3IodmFyIHM9MDtzPGEubGVuZ3RoO3MrKylmb3IodmFyIHU9cysxO3U8YS5sZW5ndGg7dSsrKXt2YXIgYz1kKGUsbixyLCExLG8sYVtzXSxhW3VdKTtjJiZ0LnB1c2goYyl9fSl9ZnVuY3Rpb24gZihlLHQsbixyLGksbyxhKXtPYmplY3Qua2V5cyhvKS5mb3JFYWNoKGZ1bmN0aW9uKHMpe3ZhciB1PWFbc107aWYodSlmb3IodmFyIGM9b1tzXSxsPTA7bDxjLmxlbmd0aDtsKyspZm9yKHZhciBwPTA7cDx1Lmxlbmd0aDtwKyspe3ZhciBmPWQoZSxuLHIsaSxzLGNbbF0sdVtwXSk7ZiYmdC5wdXNoKGYpfX0pfWZ1bmN0aW9uIGQoZSx0LG4scixpLG8sYSl7dmFyIHM9b1swXSx1PW9bMV0sYz1vWzJdLHA9YVswXSxmPWFbMV0sZD1hWzJdLG09cnx8cyE9PXAmJnMgaW5zdGFuY2VvZiBfLkdyYXBoUUxPYmplY3RUeXBlJiZwIGluc3RhbmNlb2YgXy5HcmFwaFFMT2JqZWN0VHlwZSx5PWMmJmMudHlwZSx2PWQmJmQudHlwZTtpZighbSl7dmFyIGI9dS5uYW1lLnZhbHVlLEM9Zi5uYW1lLnZhbHVlO2lmKGIhPT1DKXJldHVybltbaSxiKyIgYW5kICIrQysiIGFyZSBkaWZmZXJlbnQgZmllbGRzIl0sW3VdLFtmXV07aWYoIWgodS5hcmd1bWVudHN8fFtdLGYuYXJndW1lbnRzfHxbXSkpcmV0dXJuW1tpLCJ0aGV5IGhhdmUgZGlmZmVyaW5nIGFyZ3VtZW50cyJdLFt1XSxbZl1dfWlmKHkmJnYmJmcoeSx2KSlyZXR1cm5bW2ksInRoZXkgcmV0dXJuIGNvbmZsaWN0aW5nIHR5cGVzICIrU3RyaW5nKHkpKyIgYW5kICIrU3RyaW5nKHYpXSxbdV0sW2ZdXTt2YXIgRT11LnNlbGVjdGlvblNldCxEPWYuc2VsZWN0aW9uU2V0O2lmKEUmJkQpe3JldHVybiB4KGwoZSx0LG4sbSwoMCxfLmdldE5hbWVkVHlwZSkoeSksRSwoMCxfLmdldE5hbWVkVHlwZSkodiksRCksaSx1LGYpfX1mdW5jdGlvbiBoKGUsdCl7cmV0dXJuIGUubGVuZ3RoPT09dC5sZW5ndGgmJmUuZXZlcnkoZnVuY3Rpb24oZSl7dmFyIG49KDAsdy5kZWZhdWx0KSh0LGZ1bmN0aW9uKHQpe3JldHVybiB0Lm5hbWUudmFsdWU9PT1lLm5hbWUudmFsdWV9KTtyZXR1cm4hIW4mJm0oZS52YWx1ZSxuLnZhbHVlKX0pfWZ1bmN0aW9uIG0oZSx0KXtyZXR1cm4hZSYmIXR8fCgwLEEucHJpbnQpKGUpPT09KDAsQS5wcmludCkodCl9ZnVuY3Rpb24gZyhlLHQpe3JldHVybiBlIGluc3RhbmNlb2YgXy5HcmFwaFFMTGlzdD8hKHQgaW5zdGFuY2VvZiBfLkdyYXBoUUxMaXN0KXx8ZyhlLm9mVHlwZSx0Lm9mVHlwZSk6dCBpbnN0YW5jZW9mIF8uR3JhcGhRTExpc3Q/IShlIGluc3RhbmNlb2YgXy5HcmFwaFFMTGlzdCl8fGcoZS5vZlR5cGUsdC5vZlR5cGUpOmUgaW5zdGFuY2VvZiBfLkdyYXBoUUxOb25OdWxsPyEodCBpbnN0YW5jZW9mIF8uR3JhcGhRTE5vbk51bGwpfHxnKGUub2ZUeXBlLHQub2ZUeXBlKTp0IGluc3RhbmNlb2YgXy5HcmFwaFFMTm9uTnVsbD8hKGUgaW5zdGFuY2VvZiBfLkdyYXBoUUxOb25OdWxsKXx8ZyhlLm9mVHlwZSx0Lm9mVHlwZSk6ISghKDAsXy5pc0xlYWZUeXBlKShlKSYmISgwLF8uaXNMZWFmVHlwZSkodCkpJiZlIT09dH1mdW5jdGlvbiB5KGUsdCxuLHIpe3ZhciBpPXQuZ2V0KHIpO2lmKCFpKXt2YXIgbz1PYmplY3QuY3JlYXRlKG51bGwpLGE9T2JqZWN0LmNyZWF0ZShudWxsKTtiKGUsbixyLG8sYSksaT1bbyxPYmplY3Qua2V5cyhhKV0sdC5zZXQocixpKX1yZXR1cm4gaX1mdW5jdGlvbiB2KGUsdCxuKXt2YXIgcj10LmdldChuLnNlbGVjdGlvblNldCk7cmV0dXJuIHJ8fHkoZSx0LCgwLFQudHlwZUZyb21BU1QpKGUuZ2V0U2NoZW1hKCksbi50eXBlQ29uZGl0aW9uKSxuLnNlbGVjdGlvblNldCl9ZnVuY3Rpb24gYihlLHQsbixyLGkpe2Zvcih2YXIgbz0wO288bi5zZWxlY3Rpb25zLmxlbmd0aDtvKyspe3ZhciBhPW4uc2VsZWN0aW9uc1tvXTtzd2l0Y2goYS5raW5kKXtjYXNlIGsuRklFTEQ6dmFyIHM9YS5uYW1lLnZhbHVlLHU9dm9pZCAwOyh0IGluc3RhbmNlb2YgXy5HcmFwaFFMT2JqZWN0VHlwZXx8dCBpbnN0YW5jZW9mIF8uR3JhcGhRTEludGVyZmFjZVR5cGUpJiYodT10LmdldEZpZWxkcygpW3NdKTt2YXIgYz1hLmFsaWFzP2EuYWxpYXMudmFsdWU6cztyW2NdfHwocltjXT1bXSkscltjXS5wdXNoKFt0LGEsdV0pO2JyZWFrO2Nhc2Ugay5GUkFHTUVOVF9TUFJFQUQ6aVthLm5hbWUudmFsdWVdPSEwO2JyZWFrO2Nhc2Ugay5JTkxJTkVfRlJBR01FTlQ6dmFyIGw9YS50eXBlQ29uZGl0aW9uO2IoZSxsPygwLFQudHlwZUZyb21BU1QpKGUuZ2V0U2NoZW1hKCksbCk6dCxhLnNlbGVjdGlvblNldCxyLGkpfX19ZnVuY3Rpb24geChlLHQsbixyKXtpZihlLmxlbmd0aD4wKXJldHVybltbdCxlLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZVswXX0pXSxlLnJlZHVjZShmdW5jdGlvbihlLHQpe3ZhciBuPXRbMV07cmV0dXJuIGUuY29uY2F0KG4pfSxbbl0pLGUucmVkdWNlKGZ1bmN0aW9uKGUsdCl7dmFyIG49dFsyXTtyZXR1cm4gZS5jb25jYXQobil9LFtyXSldfWZ1bmN0aW9uIEMoZSx0LG4scil7dmFyIGk9ZVt0XTtpfHwoaT1PYmplY3QuY3JlYXRlKG51bGwpLGVbdF09aSksaVtuXT1yfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmZpZWxkc0NvbmZsaWN0TWVzc2FnZT1pLHQuT3ZlcmxhcHBpbmdGaWVsZHNDYW5CZU1lcmdlZD1hO3ZhciBFPW4oMyksRD1uKDQ1KSx3PWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0oRCksUz1uKDEwKSxrPWZ1bmN0aW9uKGUpe2lmKGUmJmUuX19lc01vZHVsZSlyZXR1cm4gZTt2YXIgdD17fTtpZihudWxsIT1lKWZvcih2YXIgbiBpbiBlKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLG4pJiYodFtuXT1lW25dKTtyZXR1cm4gdC5kZWZhdWx0PWUsdH0oUyksQT1uKDE5KSxfPW4oNiksVD1uKDI5KSxPPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3IodGhpcyxlKSx0aGlzLl9kYXRhPU9iamVjdC5jcmVhdGUobnVsbCl9cmV0dXJuIGUucHJvdG90eXBlLmhhcz1mdW5jdGlvbihlLHQsbil7dmFyIHI9dGhpcy5fZGF0YVtlXSxpPXImJnJbdF07cmV0dXJuIHZvaWQgMCE9PWkmJighMSE9PW58fCExPT09aSl9LGUucHJvdG90eXBlLmFkZD1mdW5jdGlvbihlLHQsbil7Qyh0aGlzLl9kYXRhLGUsdCxuKSxDKHRoaXMuX2RhdGEsdCxlLG4pfSxlfSgpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuJ1RoZXJlIGNhbiBiZSBvbmx5IG9uZSBpbnB1dCBmaWVsZCBuYW1lZCAiJytlKyciLid9ZnVuY3Rpb24gaShlKXt2YXIgdD1bXSxuPU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJue09iamVjdFZhbHVlOntlbnRlcjpmdW5jdGlvbigpe3QucHVzaChuKSxuPU9iamVjdC5jcmVhdGUobnVsbCl9LGxlYXZlOmZ1bmN0aW9uKCl7bj10LnBvcCgpfX0sT2JqZWN0RmllbGQ6ZnVuY3Rpb24odCl7dmFyIGk9dC5uYW1lLnZhbHVlO3JldHVybiBuW2ldP2UucmVwb3J0RXJyb3IobmV3IG8uR3JhcGhRTEVycm9yKHIoaSksW25baV0sdC5uYW1lXSkpOm5baV09dC5uYW1lLCExfX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZHVwbGljYXRlSW5wdXRGaWVsZE1lc3NhZ2U9cix0LlVuaXF1ZUlucHV0RmllbGROYW1lcz1pO3ZhciBvPW4oMyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gaShlLHQpe2lmKHQgaW5zdGFuY2VvZiBwLkdyYXBoUUxOb25OdWxsKXJldHVybigwLGwuZGVmYXVsdCkoZSk/WydFeHBlY3RlZCAiJytTdHJpbmcodCkrJyIsIGZvdW5kIG51bGwuJ106aShlLHQub2ZUeXBlKTtpZigoMCxsLmRlZmF1bHQpKGUpKXJldHVybltdO2lmKHQgaW5zdGFuY2VvZiBwLkdyYXBoUUxMaXN0KXt2YXIgbj10Lm9mVHlwZTtpZigoMCxhLmlzQ29sbGVjdGlvbikoZSkpe3ZhciByPVtdO3JldHVybigwLGEuZm9yRWFjaCkoZSxmdW5jdGlvbihlLHQpe3IucHVzaC5hcHBseShyLGkoZSxuKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIkluIGVsZW1lbnQgIyIrdCsiOiAiK2V9KSl9KSxyfXJldHVybiBpKGUsbil9aWYodCBpbnN0YW5jZW9mIHAuR3JhcGhRTElucHV0T2JqZWN0VHlwZSl7aWYoIm9iamVjdCIhPT0oInVuZGVmaW5lZCI9PT10eXBlb2YgZT8idW5kZWZpbmVkIjpvKGUpKXx8bnVsbD09PWUpcmV0dXJuWydFeHBlY3RlZCAiJyt0Lm5hbWUrJyIsIGZvdW5kIG5vdCBhbiBvYmplY3QuJ107dmFyIHM9dC5nZXRGaWVsZHMoKSxjPVtdO3JldHVybiBPYmplY3Qua2V5cyhlKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3NbZV18fGMucHVzaCgnSW4gZmllbGQgIicrZSsnIjogVW5rbm93biBmaWVsZC4nKX0pLE9iamVjdC5rZXlzKHMpLmZvckVhY2goZnVuY3Rpb24odCl7dmFyIG49aShlW3RdLHNbdF0udHlwZSk7Yy5wdXNoLmFwcGx5KGMsbi5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuJ0luIGZpZWxkICInK3QrJyI6ICcrZX0pKX0pLGN9dCBpbnN0YW5jZW9mIHAuR3JhcGhRTFNjYWxhclR5cGV8fHQgaW5zdGFuY2VvZiBwLkdyYXBoUUxFbnVtVHlwZXx8KDAsdS5kZWZhdWx0KSgwLCJNdXN0IGJlIGlucHV0IHR5cGUiKTt0cnl7dmFyIGY9dC5wYXJzZVZhbHVlKGUpO2lmKCgwLGwuZGVmYXVsdCkoZikmJiF0LmlzVmFsaWRWYWx1ZShlKSlyZXR1cm5bJ0V4cGVjdGVkIHR5cGUgIicrdC5uYW1lKyciLCBmb3VuZCAnK0pTT04uc3RyaW5naWZ5KGUpKyIuIl19Y2F0Y2gobil7cmV0dXJuWydFeHBlY3RlZCB0eXBlICInK3QubmFtZSsnIiwgZm91bmQgJytKU09OLnN0cmluZ2lmeShlKSsiOiAiK24ubWVzc2FnZV19cmV0dXJuW119T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPSJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiYic3ltYm9sIj09PXR5cGVvZiBTeW1ib2wuaXRlcmF0b3I/ZnVuY3Rpb24oZSl7cmV0dXJuIHR5cGVvZiBlfTpmdW5jdGlvbihlKXtyZXR1cm4gZSYmImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfTt0LmlzVmFsaWRKU1ZhbHVlPWk7dmFyIGE9big0NCkscz1uKDEzKSx1PXIocyksYz1uKDM1KSxsPXIoYykscD1uKDYpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSx0KXtpZih0LmtpbmQ9PT1DLkxJU1RfVFlQRSlyZXR1cm4gbmV3IHcuR3JhcGhRTExpc3QoaShlLHQudHlwZSkpO2lmKHQua2luZD09PUMuTk9OX05VTExfVFlQRSl7dmFyIG49aShlLHQudHlwZSk7cmV0dXJuIG4gaW5zdGFuY2VvZiB3LkdyYXBoUUxOb25OdWxsJiYoMCxkLmRlZmF1bHQpKDAsIk5vIG5lc3Rpbmcgbm9ubnVsbC4iKSxuZXcgdy5HcmFwaFFMTm9uTnVsbChuKX1yZXR1cm4gZX1mdW5jdGlvbiBvKGUpe2Zvcih2YXIgdD1lO3Qua2luZD09PUMuTElTVF9UWVBFfHx0LmtpbmQ9PT1DLk5PTl9OVUxMX1RZUEU7KXQ9dC50eXBlO3JldHVybiB0fWZ1bmN0aW9uIGEoZSl7ZnVuY3Rpb24gdChlKXtyZXR1cm4gbmV3IFMuR3JhcGhRTERpcmVjdGl2ZSh7bmFtZTplLm5hbWUudmFsdWUsZGVzY3JpcHRpb246dShlKSxsb2NhdGlvbnM6ZS5sb2NhdGlvbnMubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnZhbHVlfSksYXJnczplLmFyZ3VtZW50cyYmQShlLmFyZ3VtZW50cyksYXN0Tm9kZTplfSl9ZnVuY3Rpb24gbihlKXt2YXIgdD1oKGUubmFtZS52YWx1ZSk7cmV0dXJuIHQgaW5zdGFuY2VvZiB3LkdyYXBoUUxPYmplY3RUeXBlfHwoMCxkLmRlZmF1bHQpKDAsIkFTVCBtdXN0IHByb3ZpZGUgb2JqZWN0IHR5cGUuIiksdH1mdW5jdGlvbiByKGUpe3JldHVybiBpKGgobyhlKS5uYW1lLnZhbHVlKSxlKX1mdW5jdGlvbiBhKGUpe3JldHVybigwLHcuYXNzZXJ0SW5wdXRUeXBlKShyKGUpKX1mdW5jdGlvbiBjKGUpe3JldHVybigwLHcuYXNzZXJ0T3V0cHV0VHlwZSkocihlKSl9ZnVuY3Rpb24gbChlKXt2YXIgdD1yKGUpO3JldHVybiB0IGluc3RhbmNlb2Ygdy5HcmFwaFFMT2JqZWN0VHlwZXx8KDAsZC5kZWZhdWx0KSgwLCJFeHBlY3RlZCBPYmplY3QgdHlwZS4iKSx0fWZ1bmN0aW9uIGYoZSl7dmFyIHQ9cihlKTtyZXR1cm4gdCBpbnN0YW5jZW9mIHcuR3JhcGhRTEludGVyZmFjZVR5cGV8fCgwLGQuZGVmYXVsdCkoMCwiRXhwZWN0ZWQgSW50ZXJmYWNlIHR5cGUuIiksdH1mdW5jdGlvbiBoKGUpe2lmKCFHW2VdKXtpZighUFtlXSl0aHJvdyBuZXcgRXJyb3IoJ1R5cGUgIicrZSsnIiBub3QgZm91bmQgaW4gZG9jdW1lbnQuJyk7R1tlXT15KFBbZV0pfXJldHVybiBHW2VdfWZ1bmN0aW9uIHkoZSl7c3dpdGNoKGUua2luZCl7Y2FzZSBDLk9CSkVDVF9UWVBFX0RFRklOSVRJT046cmV0dXJuIHYoZSk7Y2FzZSBDLklOVEVSRkFDRV9UWVBFX0RFRklOSVRJT046cmV0dXJuIF8oZSk7Y2FzZSBDLkVOVU1fVFlQRV9ERUZJTklUSU9OOnJldHVybiBUKGUpO2Nhc2UgQy5VTklPTl9UWVBFX0RFRklOSVRJT046cmV0dXJuIE8oZSk7Y2FzZSBDLlNDQUxBUl9UWVBFX0RFRklOSVRJT046cmV0dXJuIEYoZSk7Y2FzZSBDLklOUFVUX09CSkVDVF9UWVBFX0RFRklOSVRJT046cmV0dXJuIE4oZSk7ZGVmYXVsdDp0aHJvdyBuZXcgRXJyb3IoJ1R5cGUga2luZCAiJytlLmtpbmQrJyIgbm90IHN1cHBvcnRlZC4nKX19ZnVuY3Rpb24gdihlKXt2YXIgdD1lLm5hbWUudmFsdWU7cmV0dXJuIG5ldyB3LkdyYXBoUUxPYmplY3RUeXBlKHtuYW1lOnQsZGVzY3JpcHRpb246dShlKSxmaWVsZHM6ZnVuY3Rpb24oKXtyZXR1cm4gYihlKX0saW50ZXJmYWNlczpmdW5jdGlvbigpe3JldHVybiB4KGUpfSxhc3ROb2RlOmV9KX1mdW5jdGlvbiBiKGUpe3JldHVybigwLG0uZGVmYXVsdCkoZS5maWVsZHMsZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZS52YWx1ZX0sZnVuY3Rpb24oZSl7cmV0dXJue3R5cGU6YyhlLnR5cGUpLGRlc2NyaXB0aW9uOnUoZSksYXJnczpBKGUuYXJndW1lbnRzKSxkZXByZWNhdGlvblJlYXNvbjpzKGUpLGFzdE5vZGU6ZX19KX1mdW5jdGlvbiB4KGUpe3JldHVybiBlLmludGVyZmFjZXMmJmUuaW50ZXJmYWNlcy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGYoZSl9KX1mdW5jdGlvbiBBKGUpe3JldHVybigwLG0uZGVmYXVsdCkoZSxmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lLnZhbHVlfSxmdW5jdGlvbihlKXt2YXIgdD1hKGUudHlwZSk7cmV0dXJue3R5cGU6dCxkZXNjcmlwdGlvbjp1KGUpLGRlZmF1bHRWYWx1ZTooMCxnLnZhbHVlRnJvbUFTVCkoZS5kZWZhdWx0VmFsdWUsdCksYXN0Tm9kZTplfX0pfWZ1bmN0aW9uIF8oZSl7cmV0dXJuIG5ldyB3LkdyYXBoUUxJbnRlcmZhY2VUeXBlKHtuYW1lOmUubmFtZS52YWx1ZSxkZXNjcmlwdGlvbjp1KGUpLGZpZWxkczpmdW5jdGlvbigpe3JldHVybiBiKGUpfSxhc3ROb2RlOmUscmVzb2x2ZVR5cGU6cH0pfWZ1bmN0aW9uIFQoZSl7cmV0dXJuIG5ldyB3LkdyYXBoUUxFbnVtVHlwZSh7bmFtZTplLm5hbWUudmFsdWUsZGVzY3JpcHRpb246dShlKSx2YWx1ZXM6KDAsbS5kZWZhdWx0KShlLnZhbHVlcyxmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lLnZhbHVlfSxmdW5jdGlvbihlKXtyZXR1cm57ZGVzY3JpcHRpb246dShlKSxkZXByZWNhdGlvblJlYXNvbjpzKGUpLGFzdE5vZGU6ZX19KSxhc3ROb2RlOmV9KX1mdW5jdGlvbiBPKGUpe3JldHVybiBuZXcgdy5HcmFwaFFMVW5pb25UeXBlKHtuYW1lOmUubmFtZS52YWx1ZSxkZXNjcmlwdGlvbjp1KGUpLHR5cGVzOmUudHlwZXMubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBsKGUpfSkscmVzb2x2ZVR5cGU6cCxhc3ROb2RlOmV9KX1mdW5jdGlvbiBGKGUpe3JldHVybiBuZXcgdy5HcmFwaFFMU2NhbGFyVHlwZSh7bmFtZTplLm5hbWUudmFsdWUsZGVzY3JpcHRpb246dShlKSxhc3ROb2RlOmUsc2VyaWFsaXplOmZ1bmN0aW9uKCl7cmV0dXJuIG51bGx9LHBhcnNlVmFsdWU6ZnVuY3Rpb24oKXtyZXR1cm4hMX0scGFyc2VMaXRlcmFsOmZ1bmN0aW9uKCl7cmV0dXJuITF9fSl9ZnVuY3Rpb24gTihlKXtyZXR1cm4gbmV3IHcuR3JhcGhRTElucHV0T2JqZWN0VHlwZSh7bmFtZTplLm5hbWUudmFsdWUsZGVzY3JpcHRpb246dShlKSxmaWVsZHM6ZnVuY3Rpb24oKXtyZXR1cm4gQShlLmZpZWxkcyl9LGFzdE5vZGU6ZX0pfWlmKCFlfHxlLmtpbmQhPT1DLkRPQ1VNRU5UKXRocm93IG5ldyBFcnJvcigiTXVzdCBwcm92aWRlIGEgZG9jdW1lbnQgYXN0LiIpO2Zvcih2YXIgST12b2lkIDAsTD1bXSxQPU9iamVjdC5jcmVhdGUobnVsbCksTT1bXSxqPTA7ajxlLmRlZmluaXRpb25zLmxlbmd0aDtqKyspe3ZhciBSPWUuZGVmaW5pdGlvbnNbal07c3dpdGNoKFIua2luZCl7Y2FzZSBDLlNDSEVNQV9ERUZJTklUSU9OOmlmKEkpdGhyb3cgbmV3IEVycm9yKCJNdXN0IHByb3ZpZGUgb25seSBvbmUgc2NoZW1hIGRlZmluaXRpb24uIik7ST1SO2JyZWFrO2Nhc2UgQy5TQ0FMQVJfVFlQRV9ERUZJTklUSU9OOmNhc2UgQy5PQkpFQ1RfVFlQRV9ERUZJTklUSU9OOmNhc2UgQy5JTlRFUkZBQ0VfVFlQRV9ERUZJTklUSU9OOmNhc2UgQy5FTlVNX1RZUEVfREVGSU5JVElPTjpjYXNlIEMuVU5JT05fVFlQRV9ERUZJTklUSU9OOmNhc2UgQy5JTlBVVF9PQkpFQ1RfVFlQRV9ERUZJTklUSU9OOnZhciBCPVIubmFtZS52YWx1ZTtpZihQW0JdKXRocm93IG5ldyBFcnJvcignVHlwZSAiJytCKyciIHdhcyBkZWZpbmVkIG1vcmUgdGhhbiBvbmNlLicpO0wucHVzaChSKSxQW0JdPVI7YnJlYWs7Y2FzZSBDLkRJUkVDVElWRV9ERUZJTklUSU9OOk0ucHVzaChSKX19dmFyICQ9dm9pZCAwLFU9dm9pZCAwLHo9dm9pZCAwO2lmKEk/SS5vcGVyYXRpb25UeXBlcy5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWUudHlwZS5uYW1lLnZhbHVlO2lmKCJxdWVyeSI9PT1lLm9wZXJhdGlvbil7aWYoJCl0aHJvdyBuZXcgRXJyb3IoIk11c3QgcHJvdmlkZSBvbmx5IG9uZSBxdWVyeSB0eXBlIGluIHNjaGVtYS4iKTtpZighUFt0XSl0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBxdWVyeSB0eXBlICInK3QrJyIgbm90IGZvdW5kIGluIGRvY3VtZW50LicpOyQ9dH1lbHNlIGlmKCJtdXRhdGlvbiI9PT1lLm9wZXJhdGlvbil7aWYoVSl0aHJvdyBuZXcgRXJyb3IoIk11c3QgcHJvdmlkZSBvbmx5IG9uZSBtdXRhdGlvbiB0eXBlIGluIHNjaGVtYS4iKTtpZighUFt0XSl0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBtdXRhdGlvbiB0eXBlICInK3QrJyIgbm90IGZvdW5kIGluIGRvY3VtZW50LicpO1U9dH1lbHNlIGlmKCJzdWJzY3JpcHRpb24iPT09ZS5vcGVyYXRpb24pe2lmKHopdGhyb3cgbmV3IEVycm9yKCJNdXN0IHByb3ZpZGUgb25seSBvbmUgc3Vic2NyaXB0aW9uIHR5cGUgaW4gc2NoZW1hLiIpO2lmKCFQW3RdKXRocm93IG5ldyBFcnJvcignU3BlY2lmaWVkIHN1YnNjcmlwdGlvbiB0eXBlICInK3QrJyIgbm90IGZvdW5kIGluIGRvY3VtZW50LicpO3o9dH19KTooUC5RdWVyeSYmKCQ9IlF1ZXJ5IiksUC5NdXRhdGlvbiYmKFU9Ik11dGF0aW9uIiksUC5TdWJzY3JpcHRpb24mJih6PSJTdWJzY3JpcHRpb24iKSksISQpdGhyb3cgbmV3IEVycm9yKCJNdXN0IHByb3ZpZGUgc2NoZW1hIGRlZmluaXRpb24gd2l0aCBxdWVyeSB0eXBlIG9yIGEgdHlwZSBuYW1lZCBRdWVyeS4iKTt2YXIgRz17U3RyaW5nOkQuR3JhcGhRTFN0cmluZyxJbnQ6RC5HcmFwaFFMSW50LEZsb2F0OkQuR3JhcGhRTEZsb2F0LEJvb2xlYW46RC5HcmFwaFFMQm9vbGVhbixJRDpELkdyYXBoUUxJRCxfX1NjaGVtYTprLl9fU2NoZW1hLF9fRGlyZWN0aXZlOmsuX19EaXJlY3RpdmUsX19EaXJlY3RpdmVMb2NhdGlvbjprLl9fRGlyZWN0aXZlTG9jYXRpb24sX19UeXBlOmsuX19UeXBlLF9fRmllbGQ6ay5fX0ZpZWxkLF9fSW5wdXRWYWx1ZTprLl9fSW5wdXRWYWx1ZSxfX0VudW1WYWx1ZTprLl9fRW51bVZhbHVlLF9fVHlwZUtpbmQ6ay5fX1R5cGVLaW5kfSxWPUwubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBoKGUubmFtZS52YWx1ZSl9KSxxPU0ubWFwKHQpO3JldHVybiBxLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuInNraXAiPT09ZS5uYW1lfSl8fHEucHVzaChTLkdyYXBoUUxTa2lwRGlyZWN0aXZlKSxxLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuImluY2x1ZGUiPT09ZS5uYW1lfSl8fHEucHVzaChTLkdyYXBoUUxJbmNsdWRlRGlyZWN0aXZlKSxxLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuImRlcHJlY2F0ZWQiPT09ZS5uYW1lfSl8fHEucHVzaChTLkdyYXBoUUxEZXByZWNhdGVkRGlyZWN0aXZlKSxuZXcgRS5HcmFwaFFMU2NoZW1hKHtxdWVyeTpuKFBbJF0pLG11dGF0aW9uOlU/bihQW1VdKTpudWxsLHN1YnNjcmlwdGlvbjp6P24oUFt6XSk6bnVsbCx0eXBlczpWLGRpcmVjdGl2ZXM6cSxhc3ROb2RlOkl9KX1mdW5jdGlvbiBzKGUpe3ZhciB0PSgwLGIuZ2V0RGlyZWN0aXZlVmFsdWVzKShTLkdyYXBoUUxEZXByZWNhdGVkRGlyZWN0aXZlLGUpO3JldHVybiB0JiZ0LnJlYXNvbn1mdW5jdGlvbiB1KGUpe3ZhciB0PWUubG9jO2lmKHQpe2Zvcih2YXIgbj1bXSxyPXZvaWQgMCxpPXQuc3RhcnRUb2tlbi5wcmV2O2kmJmkua2luZD09PXkuVG9rZW5LaW5kLkNPTU1FTlQmJmkubmV4dCYmaS5wcmV2JiZpLmxpbmUrMT09PWkubmV4dC5saW5lJiZpLmxpbmUhPT1pLnByZXYubGluZTspe3ZhciBvPVN0cmluZyhpLnZhbHVlKSxhPWwobyk7KHZvaWQgMD09PXJ8fGE8cikmJihyPWEpLG4ucHVzaChvKSxpPWkucHJldn1yZXR1cm4gbi5yZXZlcnNlKCkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnNsaWNlKHIpfSkuam9pbigiXG4iKX19ZnVuY3Rpb24gYyhlKXtyZXR1cm4gYSgoMCx2LnBhcnNlKShlKSl9ZnVuY3Rpb24gbChlKXtmb3IodmFyIHQ9MDt0PGUubGVuZ3RoJiYiICI9PT1lW3RdO3QrKyk7cmV0dXJuIHR9ZnVuY3Rpb24gcCgpe3Rocm93IG5ldyBFcnJvcigiR2VuZXJhdGVkIFNjaGVtYSBjYW5ub3QgdXNlIEludGVyZmFjZSBvciBVbmlvbiB0eXBlcyBmb3IgZXhlY3V0aW9uLiIpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmJ1aWxkQVNUU2NoZW1hPWEsdC5nZXREZXByZWNhdGlvblJlYXNvbj1zLHQuZ2V0RGVzY3JpcHRpb249dSx0LmJ1aWxkU2NoZW1hPWM7dmFyIGY9bigxMyksZD1yKGYpLGg9bigxMjApLG09cihoKSxnPW4oNTkpLHk9bigxMTApLHY9big4MCksYj1uKDExOSkseD1uKDEwKSxDPWZ1bmN0aW9uKGUpe2lmKGUmJmUuX19lc01vZHVsZSlyZXR1cm4gZTt2YXIgdD17fTtpZihudWxsIT1lKWZvcih2YXIgbiBpbiBlKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLG4pJiYodFtuXT1lW25dKTtyZXR1cm4gdC5kZWZhdWx0PWUsdH0oeCksRT1uKDI2KSxEPW4oMzIpLHc9big2KSxTPW4oMjcpLGs9bigyOCl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZihudWxsPT1lKXJldHVybiEwO2lmKE9iamVjdCh1LmEpKGUpJiYoT2JqZWN0KHMuYSkoZSl8fCJzdHJpbmciPT10eXBlb2YgZXx8ImZ1bmN0aW9uIj09dHlwZW9mIGUuc3BsaWNlfHxPYmplY3QoYy5hKShlKXx8T2JqZWN0KHAuYSkoZSl8fE9iamVjdChhLmEpKGUpKSlyZXR1cm4hZS5sZW5ndGg7dmFyIHQ9T2JqZWN0KG8uYSkoZSk7aWYodD09Znx8dD09ZClyZXR1cm4hZS5zaXplO2lmKE9iamVjdChsLmEpKGUpKXJldHVybiFPYmplY3QoaS5hKShlKS5sZW5ndGg7Zm9yKHZhciBuIGluIGUpaWYobS5jYWxsKGUsbikpcmV0dXJuITE7cmV0dXJuITB9dmFyIGk9bigyMTApLG89bigyMTIpLGE9bigyMTUpLHM9big0NyksdT1uKDEyMiksYz1uKDIxNyksbD1uKDIxMSkscD1uKDIxOCksZj0iW29iamVjdCBNYXBdIixkPSJbb2JqZWN0IFNldF0iLGg9T2JqZWN0LnByb3RvdHlwZSxtPWguaGFzT3duUHJvcGVydHk7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZighT2JqZWN0KGkuYSkoZSkpcmV0dXJuIE9iamVjdChvLmEpKGUpO3ZhciB0PVtdO2Zvcih2YXIgbiBpbiBPYmplY3QoZSkpcy5jYWxsKGUsbikmJiJjb25zdHJ1Y3RvciIhPW4mJnQucHVzaChuKTtyZXR1cm4gdH12YXIgaT1uKDIxMSksbz1uKDQxMCksYT1PYmplY3QucHJvdG90eXBlLHM9YS5oYXNPd25Qcm9wZXJ0eTt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PWUmJmUuY29uc3RydWN0b3I7cmV0dXJuIGU9PT0oImZ1bmN0aW9uIj09dHlwZW9mIHQmJnQucHJvdG90eXBlfHxpKX12YXIgaT1PYmplY3QucHJvdG90eXBlO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNDExKSxpPW4oNDE2KSxvPW4oNDE3KSxhPW4oNDE4KSxzPW4oMjE0KSx1PW4oMzMpLGM9bigyMTMpLGw9T2JqZWN0KGMuYSkoci5hKSxwPU9iamVjdChjLmEpKGkuYSksZj1PYmplY3QoYy5hKShvLmEpLGQ9T2JqZWN0KGMuYSkoYS5hKSxoPU9iamVjdChjLmEpKHMuYSksbT11LmE7KHIuYSYmIltvYmplY3QgRGF0YVZpZXddIiE9bShuZXcgci5hKG5ldyBBcnJheUJ1ZmZlcigxKSkpfHxpLmEmJiJbb2JqZWN0IE1hcF0iIT1tKG5ldyBpLmEpfHxvLmEmJiJbb2JqZWN0IFByb21pc2VdIiE9bShvLmEucmVzb2x2ZSgpKXx8YS5hJiYiW29iamVjdCBTZXRdIiE9bShuZXcgYS5hKXx8cy5hJiYiW29iamVjdCBXZWFrTWFwXSIhPW0obmV3IHMuYSkpJiYobT1mdW5jdGlvbihlKXt2YXIgdD1PYmplY3QodS5hKShlKSxuPSJbb2JqZWN0IE9iamVjdF0iPT10P2UuY29uc3RydWN0b3I6dm9pZCAwLHI9bj9PYmplY3QoYy5hKShuKToiIjtpZihyKXN3aXRjaChyKXtjYXNlIGw6cmV0dXJuIltvYmplY3QgRGF0YVZpZXddIjtjYXNlIHA6cmV0dXJuIltvYmplY3QgTWFwXSI7Y2FzZSBmOnJldHVybiJbb2JqZWN0IFByb21pc2VdIjtjYXNlIGQ6cmV0dXJuIltvYmplY3QgU2V0XSI7Y2FzZSBoOnJldHVybiJbb2JqZWN0IFdlYWtNYXBdIn1yZXR1cm4gdH0pLHQuYT1tfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7aWYobnVsbCE9ZSl7dHJ5e3JldHVybiBvLmNhbGwoZSl9Y2F0Y2goZSl7fXRyeXtyZXR1cm4gZSsiIn1jYXRjaChlKXt9fXJldHVybiIifXZhciBpPUZ1bmN0aW9uLnByb3RvdHlwZSxvPWkudG9TdHJpbmc7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0OSksaT1uKDIxKSxvPU9iamVjdChyLmEpKGkuYSwiV2Vha01hcCIpO3QuYT1vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNDE5KSxpPW4oMzEpLG89T2JqZWN0LnByb3RvdHlwZSxhPW8uaGFzT3duUHJvcGVydHkscz1vLnByb3BlcnR5SXNFbnVtZXJhYmxlLHU9T2JqZWN0KHIuYSkoZnVuY3Rpb24oKXtyZXR1cm4gYXJndW1lbnRzfSgpKT9yLmE6ZnVuY3Rpb24oZSl7cmV0dXJuIE9iamVjdChpLmEpKGUpJiZhLmNhbGwoZSwiY2FsbGVlIikmJiFzLmNhbGwoZSwiY2FsbGVlIil9O3QuYT11fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlJiZlPi0xJiZlJTE9PTAmJmU8PWl9dmFyIGk9OTAwNzE5OTI1NDc0MDk5MTt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjsoZnVuY3Rpb24oZSl7dmFyIHI9bigyMSksaT1uKDQyMCksbz0ib2JqZWN0Ij09dHlwZW9mIGV4cG9ydHMmJmV4cG9ydHMmJiFleHBvcnRzLm5vZGVUeXBlJiZleHBvcnRzLGE9byYmIm9iamVjdCI9PXR5cGVvZiBlJiZlJiYhZS5ub2RlVHlwZSYmZSxzPWEmJmEuZXhwb3J0cz09PW8sdT1zP3IuYS5CdWZmZXI6dm9pZCAwLGM9dT91LmlzQnVmZmVyOnZvaWQgMCxsPWN8fGkuYTt0LmE9bH0pLmNhbGwodCxuKDc5KShlKSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0MjEpLGk9bigyMTkpLG89bigyMjApLGE9by5hJiZvLmEuaXNUeXBlZEFycmF5LHM9YT9PYmplY3QoaS5hKShhKTpyLmE7dC5hPXN9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIGUodCl9fXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiOyhmdW5jdGlvbihlKXt2YXIgcj1uKDE2NCksaT0ib2JqZWN0Ij09dHlwZW9mIGV4cG9ydHMmJmV4cG9ydHMmJiFleHBvcnRzLm5vZGVUeXBlJiZleHBvcnRzLG89aSYmIm9iamVjdCI9PXR5cGVvZiBlJiZlJiYhZS5ub2RlVHlwZSYmZSxhPW8mJm8uZXhwb3J0cz09PWkscz1hJiZyLmEucHJvY2Vzcyx1PWZ1bmN0aW9uKCl7dHJ5e3ZhciBlPW8mJm8ucmVxdWlyZSYmby5yZXF1aXJlKCJ1dGlsIikudHlwZXM7cmV0dXJuIGV8fHMmJnMuYmluZGluZyYmcy5iaW5kaW5nKCJ1dGlsIil9Y2F0Y2goZSl7fX0oKTt0LmE9dX0pLmNhbGwodCxuKDc5KShlKSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2Zvcih2YXIgbj0tMSxyPW51bGw9PWU/MDplLmxlbmd0aCxpPUFycmF5KHIpOysrbjxyOylpW25dPXQoZVtuXSxuLGUpO3JldHVybiBpfXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG51bGw9PWV9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0MjYpO3QuYT1mdW5jdGlvbihlKXtyZXR1cm4tMT09PWUuaW5kZXhPZigiLyIpP09iamVjdChyLmEpKGUpOmUuc3BsaXQoIi8iKS5tYXAoci5hKS5qb2luKCIvIil9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGkudGVzdChlKX12YXIgaT1SZWdFeHAoIltcXHUyMDBkXFx1ZDgwMC1cXHVkZmZmXFx1MDMwMC1cXHUwMzZmXFx1ZmUyMC1cXHVmZTJmXFx1MjBkMC1cXHUyMGZmXFx1ZmUwZVxcdWZlMGZdIik7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZihBcnJheS5pc0FycmF5KGUpKXtmb3IodmFyIHQ9MCxuPUFycmF5KGUubGVuZ3RoKTt0PGUubGVuZ3RoO3QrKyluW3RdPWVbdF07cmV0dXJuIG59cmV0dXJuIEFycmF5LmZyb20oZSl9ZnVuY3Rpb24gaShlLHQpe3JldHVybiBPYmplY3Qoby5hKSh0KT90LmdldChlKTp0W2VdfXZhciBvPW4oODMpLGE9big2Mikscz1uKDEyNSk7dC5hPWZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbiB0KG4pe2Z1bmN0aW9uIG8oZSl7dmFyIHQ7aWYoIWgpcmV0dXJuIGU7dmFyIG49ZS50b1N0cmluZygpLnNwbGl0KGEuYSksaT1oLnNwbGl0KGEuYSk7cmV0dXJuKHQ9W10pLmNvbmNhdC5hcHBseSh0LHIoaS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIG4ubWFwKGZ1bmN0aW9uKHQpe3JldHVybiIiK2UrcCt0fSl9KSkpLmpvaW4oYS5hKX1mdW5jdGlvbiB1KGUpe3JldHVybiBofHwhZj9lOiIiK2YrcCtlfXZhciBjPWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7fSxsPWMubmFtZXNwYWNlLHA9dm9pZCAwPT09bD9hLmI6bCxmPWMucHJlZml4LGQ9YXJndW1lbnRzLmxlbmd0aD4yJiZ2b2lkIDAhPT1hcmd1bWVudHNbMl0/YXJndW1lbnRzWzJdOnt9LGg9YXJndW1lbnRzLmxlbmd0aD4zJiZ2b2lkIDAhPT1hcmd1bWVudHNbM10/YXJndW1lbnRzWzNdOiIiO3JldHVybiBPYmplY3Qocy5hKShuKS5mb3JFYWNoKGZ1bmN0aW9uKHIpe3ZhciBhPXUobyhyKSkscz1pKHIsbik7ZShzKT90KHMse25hbWVzcGFjZTpwLHByZWZpeDpmfSxkLGEpOmRbYV09c30pLGR9fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDYzKSxpPW4oMjI3KSxvPWkuYT9mdW5jdGlvbihlLHQpe3JldHVybiBpLmEuc2V0KGUsdCksZX06ci5hO3QuYT1vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oMjE0KSxpPXIuYSYmbmV3IHIuYTt0LmE9aX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXtzd2l0Y2gobi5sZW5ndGgpe2Nhc2UgMDpyZXR1cm4gZS5jYWxsKHQpO2Nhc2UgMTpyZXR1cm4gZS5jYWxsKHQsblswXSk7Y2FzZSAyOnJldHVybiBlLmNhbGwodCxuWzBdLG5bMV0pO2Nhc2UgMzpyZXR1cm4gZS5jYWxsKHQsblswXSxuWzFdLG5bMl0pfXJldHVybiBlLmFwcGx5KHQsbil9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbixiLHgsQyxFLEQsdyxTKXtmdW5jdGlvbiBrKCl7Zm9yKHZhciBkPWFyZ3VtZW50cy5sZW5ndGgsaD1BcnJheShkKSxtPWQ7bS0tOyloW21dPWFyZ3VtZW50c1ttXTtpZihPKXZhciBnPU9iamVjdChjLmEpKGspLHk9T2JqZWN0KGEuYSkoaCxnKTtpZihiJiYoaD1PYmplY3QoaS5hKShoLGIseCxPKSksQyYmKGg9T2JqZWN0KG8uYSkoaCxDLEUsTykpLGQtPXksTyYmZDxTKXt2YXIgdj1PYmplY3QocC5hKShoLGcpO3JldHVybiBPYmplY3QodS5hKShlLHQscixrLnBsYWNlaG9sZGVyLG4saCx2LEQsdyxTLWQpfXZhciBJPV8/bjp0aGlzLEw9VD9JW2VdOmU7cmV0dXJuIGQ9aC5sZW5ndGgsRD9oPU9iamVjdChsLmEpKGgsRCk6RiYmZD4xJiZoLnJldmVyc2UoKSxBJiZ3PGQmJihoLmxlbmd0aD13KSx0aGlzJiZ0aGlzIT09Zi5hJiZ0aGlzIGluc3RhbmNlb2YgayYmKEw9Tnx8T2JqZWN0KHMuYSkoTCkpLEwuYXBwbHkoSSxoKX12YXIgQT10JnksXz10JmQsVD10JmgsTz10JihtfGcpLEY9dCZ2LE49VD92b2lkIDA6T2JqZWN0KHMuYSkoZSk7cmV0dXJuIGt9dmFyIGk9bigyMzApLG89bigyMzEpLGE9big0NTMpLHM9big4NCksdT1uKDIzMiksYz1uKDI0MCksbD1uKDQ3MikscD1uKDEyOSksZj1uKDIxKSxkPTEsaD0yLG09OCxnPTE2LHk9MTI4LHY9NTEyO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4scil7Zm9yKHZhciBvPS0xLGE9ZS5sZW5ndGgscz1uLmxlbmd0aCx1PS0xLGM9dC5sZW5ndGgsbD1pKGEtcywwKSxwPUFycmF5KGMrbCksZj0hcjsrK3U8YzspcFt1XT10W3VdO2Zvcig7KytvPHM7KShmfHxvPGEpJiYocFtuW29dXT1lW29dKTtmb3IoO2wtLTspcFt1KytdPWVbbysrXTtyZXR1cm4gcH12YXIgaT1NYXRoLm1heDt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuLHIpe2Zvcih2YXIgbz0tMSxhPWUubGVuZ3RoLHM9LTEsdT1uLmxlbmd0aCxjPS0xLGw9dC5sZW5ndGgscD1pKGEtdSwwKSxmPUFycmF5KHArbCksZD0hcjsrK288cDspZltvXT1lW29dO2Zvcih2YXIgaD1vOysrYzxsOylmW2grY109dFtjXTtmb3IoOysrczx1OykoZHx8bzxhKSYmKGZbaCtuW3NdXT1lW28rK10pO3JldHVybiBmfXZhciBpPU1hdGgubWF4O3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4scixkLGgsbSxnLHksdil7dmFyIGI9dCZsLHg9Yj9tOnZvaWQgMCxDPWI/dm9pZCAwOm0sRT1iP2g6dm9pZCAwLEQ9Yj92b2lkIDA6aDt0fD1iP3A6ZiwodCY9fihiP2Y6cCkpJmN8fCh0Jj1+KHN8dSkpO3ZhciB3PVtlLHQsZCxFLHgsRCxDLGcseSx2XSxTPW4uYXBwbHkodm9pZCAwLHcpO3JldHVybiBPYmplY3QoaS5hKShlKSYmT2JqZWN0KG8uYSkoUyx3KSxTLnBsYWNlaG9sZGVyPXIsT2JqZWN0KGEuYSkoUyxlLHQpfXZhciBpPW4oNDU0KSxvPW4oMjM2KSxhPW4oMjM4KSxzPTEsdT0yLGM9NCxsPTgscD0zMixmPTY0O3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oMjI3KSxpPW4oNDU1KSxvPXIuYT9mdW5jdGlvbihlKXtyZXR1cm4gci5hLmdldChlKX06aS5hO3QuYT1vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt0aGlzLl9fd3JhcHBlZF9fPWUsdGhpcy5fX2FjdGlvbnNfXz1bXSx0aGlzLl9fY2hhaW5fXz0hIXQsdGhpcy5fX2luZGV4X189MCx0aGlzLl9fdmFsdWVzX189dm9pZCAwfXZhciBpPW4oMTI2KSxvPW4oMTI4KTtyLnByb3RvdHlwZT1PYmplY3QoaS5hKShvLmEucHJvdG90eXBlKSxyLnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj1yLHQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2YXIgbj0tMSxyPWUubGVuZ3RoO2Zvcih0fHwodD1BcnJheShyKSk7KytuPHI7KXRbbl09ZVtuXTtyZXR1cm4gdH10LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDIyNiksaT1uKDIzNyksbz1PYmplY3QoaS5hKShyLmEpO3QuYT1vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dmFyIHQ9MCxuPTA7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIHI9YSgpLHM9by0oci1uKTtpZihuPXIscz4wKXtpZigrK3Q+PWkpcmV0dXJuIGFyZ3VtZW50c1swXX1lbHNlIHQ9MDtyZXR1cm4gZS5hcHBseSh2b2lkIDAsYXJndW1lbnRzKX19dmFyIGk9ODAwLG89MTYsYT1EYXRlLm5vdzt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXt2YXIgcj10KyIiO3JldHVybiBPYmplY3QoYS5hKShlLE9iamVjdChvLmEpKHIsT2JqZWN0KHMuYSkoT2JqZWN0KGkuYSkociksbikpKX12YXIgaT1uKDQ2MCksbz1uKDQ2MSksYT1uKDQ2Mikscz1uKDQ2Nik7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuIHQ9PT10P09iamVjdChhLmEpKGUsdCxuKTpPYmplY3QoaS5hKShlLG8uYSxuKX12YXIgaT1uKDQ2OSksbz1uKDQ3MCksYT1uKDQ3MSk7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZS5wbGFjZWhvbGRlcn10LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dmFyIG49dHlwZW9mIGU7cmV0dXJuISEodD1udWxsPT10P2k6dCkmJigibnVtYmVyIj09bnx8InN5bWJvbCIhPW4mJm8udGVzdChlKSkmJmU+LTEmJmUlMT09MCYmZTx0fXZhciBpPTkwMDcxOTkyNTQ3NDA5OTEsbz0vXig/OjB8WzEtOV1cZCopJC87dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD1PYmplY3QoaS5hKShlKSxuPXQlMTtyZXR1cm4gdD09PXQ/bj90LW46dDowfXZhciBpPW4oNDc1KTt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTphLmEsbj1hcmd1bWVudHNbMl0scj1lLnRvU3RyaW5nKCkuc3BsaXQoZi5hKTtwKCkoIU9iamVjdCh1LmEpKG4pLCJkZWZhdWx0U3RhdGUgZm9yIHJlZHVjZXIgaGFuZGxpbmcgIityLmpvaW4oIiwgIikrIiBzaG91bGQgYmUgZGVmaW5lZCIpLHAoKShPYmplY3QoaS5hKSh0KXx8T2JqZWN0KG8uYSkodCksIkV4cGVjdGVkIHJlZHVjZXIgdG8gYmUgYSBmdW5jdGlvbiBvciBvYmplY3Qgd2l0aCBuZXh0IGFuZCB0aHJvdyByZWR1Y2VycyIpO3ZhciBsPU9iamVjdChpLmEpKHQpP1t0LHRdOlt0Lm5leHQsdC50aHJvd10ubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBPYmplY3Qocy5hKShlKT9hLmE6ZX0pLGg9ZChsLDIpLG09aFswXSxnPWhbMV07cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIGU9YXJndW1lbnRzLmxlbmd0aD4wJiZ2b2lkIDAhPT1hcmd1bWVudHNbMF0/YXJndW1lbnRzWzBdOm4sdD1hcmd1bWVudHNbMV0saT10LnR5cGU7cmV0dXJuIGkmJk9iamVjdChjLmEpKHIsaS50b1N0cmluZygpKT8oITA9PT10LmVycm9yP2c6bSkoZSx0KTplfX10LmE9cjt2YXIgaT1uKDQ4KSxvPW4oNDEpLGE9big2Mykscz1uKDIyMiksdT1uKDQ3NyksYz1uKDQ3OCksbD1uKDIwKSxwPW4ubihsKSxmPW4oNjIpLGQ9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dmFyIG49W10scj0hMCxpPSExLG89dm9pZCAwO3RyeXtmb3IodmFyIGEscz1lW1N5bWJvbC5pdGVyYXRvcl0oKTshKHI9KGE9cy5uZXh0KCkpLmRvbmUpJiYobi5wdXNoKGEudmFsdWUpLCF0fHxuLmxlbmd0aCE9PXQpO3I9ITApO31jYXRjaChlKXtpPSEwLG89ZX1maW5hbGx5e3RyeXshciYmcy5yZXR1cm4mJnMucmV0dXJuKCl9ZmluYWxseXtpZihpKXRocm93IG99fXJldHVybiBufXJldHVybiBmdW5jdGlvbih0LG4pe2lmKEFycmF5LmlzQXJyYXkodCkpcmV0dXJuIHQ7aWYoU3ltYm9sLml0ZXJhdG9yIGluIE9iamVjdCh0KSlyZXR1cm4gZSh0LG4pO3Rocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgYXR0ZW1wdCB0byBkZXN0cnVjdHVyZSBub24taXRlcmFibGUgaW5zdGFuY2UiKX19KCl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZGVmYXVsdD1mdW5jdGlvbihlKXtyZXR1cm4gZSYmIkBAcmVkdXgvSU5JVCI9PT1lLnR5cGU/ImluaXRpYWxTdGF0ZSBhcmd1bWVudCBwYXNzZWQgdG8gY3JlYXRlU3RvcmUiOiJwcmV2aW91cyBzdGF0ZSByZWNlaXZlZCBieSB0aGUgcmVkdWNlciJ9LGUuZXhwb3J0cz10LmRlZmF1bHR9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZ2V0UXVlcnlUeXBlcz1mdW5jdGlvbihlKXt2YXIgdD0hMSxuPSExLHI9ITEsaT1udWxsO3JldHVybiBlJiZlLmRlZmluaXRpb25zJiZlLmRlZmluaXRpb25zLmZvckVhY2goZnVuY3Rpb24oZSl7aXx8KGk9ZS5uYW1lJiZlLm5hbWUudmFsdWUpLGl8fChpPWUuc2VsZWN0aW9uU2V0JiZlLnNlbGVjdGlvblNldC5zZWxlY3Rpb25zJiZlLnNlbGVjdGlvblNldC5zZWxlY3Rpb25zLmxlbmd0aD4wJiZlLnNlbGVjdGlvblNldC5zZWxlY3Rpb25zWzBdLm5hbWUudmFsdWUpLCJzdWJzY3JpcHRpb24iPT09ZS5vcGVyYXRpb24mJih0PSEwKSwicXVlcnkiPT09ZS5vcGVyYXRpb24mJihuPSEwKSwibXV0YXRpb24iPT09ZS5vcGVyYXRpb24mJihyPSEwKX0pLHtmaXJzdE9wZXJhdGlvbk5hbWU6aSxzdWJzY3JpcHRpb246dCxxdWVyeTpuLG11dGF0aW9uOnJ9fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5hcnJheU1vdmU9dC5zb3J0YWJsZUhhbmRsZT10LnNvcnRhYmxlRWxlbWVudD10LnNvcnRhYmxlQ29udGFpbmVyPXQuU29ydGFibGVIYW5kbGU9dC5Tb3J0YWJsZUVsZW1lbnQ9dC5Tb3J0YWJsZUNvbnRhaW5lcj12b2lkIDA7dmFyIGk9big4Nik7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImFycmF5TW92ZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuYXJyYXlNb3ZlfX0pO3ZhciBvPW4oNDkzKSxhPXIobykscz1uKDQ5NyksdT1yKHMpLGM9big0OTgpLGw9cihjKTt0LlNvcnRhYmxlQ29udGFpbmVyPWEuZGVmYXVsdCx0LlNvcnRhYmxlRWxlbWVudD11LmRlZmF1bHQsdC5Tb3J0YWJsZUhhbmRsZT1sLmRlZmF1bHQsdC5zb3J0YWJsZUNvbnRhaW5lcj1hLmRlZmF1bHQsdC5zb3J0YWJsZUVsZW1lbnQ9dS5kZWZhdWx0LHQuc29ydGFibGVIYW5kbGU9bC5kZWZhdWx0fSxmdW5jdGlvbihlLHQsbil7ZS5leHBvcnRzPW4oNDk0KSgpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPW4oMTQpLG89bigyMyksYT1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7cmV0dXJuIG51bGwhPT1lJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpc31yZXR1cm4gcih0LGUpLHR9KGkuUmVjb3JkKHtoaXN0b3J5OiExLGhlYWRlcnM6ITAsYWxsVGFiczohMCxzaGFyZVVybDpudWxsfSkpO3QuU2hhcmluZ1N0YXRlPWEsdC5kZWZhdWx0PW8uaGFuZGxlQWN0aW9ucyh7VE9HR0xFX1NIQVJFX0hJU1RPUlk6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc2V0KCJoaXN0b3J5IiwhZS5oaXN0b3J5KX0sVE9HR0xFX1NIQVJFX0hFQURFUlM6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc2V0KCJoZWFkZXJzIiwhZS5oZWFkZXJzKX0sVE9HR0xFX1NIQVJFX0FMTF9UQUJTOmZ1bmN0aW9uKGUpe3JldHVybiBlLnNldCgiYWxsVGFicyIsIWUuYWxsVGFicyl9LFNFVF9TSEFSRV9VUkw6ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQuc2hhcmVVcmw7cmV0dXJuIGUuc2V0KCJzaGFyZVVybCIsbil9fSxuZXcgYSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigxNCksbz1uKDIzKSxhPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gbnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzfXJldHVybiByKHQsZSksdH0oaS5SZWNvcmQoe2hpc3RvcnlPcGVuOiExLGZpeGVkRW5kcG9pbnQ6ITEsZW5kcG9pbnQ6IiIsY29uZmlnU3RyaW5nOiIiLGVudlZhcnM6e319KSk7dC5HZW5lcmFsU3RhdGU9YSx0LmRlZmF1bHQ9by5oYW5kbGVBY3Rpb25zKHtPUEVOX0hJU1RPUlk6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc2V0KCJoaXN0b3J5T3BlbiIsITApfSxDTE9TRV9ISVNUT1JZOmZ1bmN0aW9uKGUpe3JldHVybiBlLnNldCgiaGlzdG9yeU9wZW4iLCExKX0sU0VUX0VORFBPSU5UX0RJU0FCTEVEOmZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLnZhbHVlO3JldHVybiBlLnNldCgiZW5kcG9pbnREaXNhYmxlZCIsbil9LFNFVF9DT05GSUdfU1RSSU5HOmZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLmNvbmZpZ1N0cmluZztyZXR1cm4gZS5zZXQoImNvbmZpZ1N0cmluZyIsbil9fSxuZXcgYSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gbmV3IHcuUm9vdFN0YXRlKHt3b3Jrc3BhY2VzOmkoZS53b3Jrc3BhY2VzKSxzZWxlY3RlZFdvcmtzcGFjZTplLnNlbGVjdGVkV29ya3NwYWNlLHNldHRpbmdzU3RyaW5nOncubm9ybWFsaXplU2V0dGluZ3NTdHJpbmcoZS5zZXR0aW5nc1N0cmluZyksYXBwSGlzdG9yeTpvKGUuYXBwSGlzdG9yeSksZ2VuZXJhbDptKGUuZ2VuZXJhbCl9KX1mdW5jdGlvbiBpKGUpe3JldHVybiBDLk1hcChELm1hcFZhbHVlcyhlLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG5ldyB3LldvcmtzcGFjZSh7ZG9jczphKGUuZG9jcyksc2Vzc2lvbnM6dShlLnNlc3Npb25zKSxzaGFyaW5nOmQoZS5zaGFyaW5nKSxoaXN0b3J5OmgoZS5oaXN0b3J5KX0pfSkpfWZ1bmN0aW9uIG8oZSl7cmV0dXJuIG5ldyBTLkFwcEhpc3Rvcnkoe2l0ZW1zOkMuT3JkZXJlZE1hcChELm1hcFZhbHVlcyhlLml0ZW1zLGZ1bmN0aW9uKGUpe3JldHVybiBuZXcgUy5BcHBIaXN0b3J5SXRlbShlKX0pKX0pfWZ1bmN0aW9uIGEoZSl7cmV0dXJuIEMuTWFwKEQubWFwVmFsdWVzKGUsZnVuY3Rpb24oZSl7cmV0dXJuIG5ldyB2LkRvY3NTZXNzaW9uKHtkb2NzT3BlbjplLmRvY3NPcGVuLGtleU1vdmU6ZS5rZXlNb3ZlLGRvY3NXaWR0aDplLmRvY3NXaWR0aCxuYXZTdGFjazpzKGUubmF2U3RhY2spfSl9KSl9ZnVuY3Rpb24gcyhlKXtyZXR1cm4gQy5MaXN0KGUubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBDLk1hcChlKX0pKX1mdW5jdGlvbiB1KGUpe3ZhciB0PWMoZS5zZXNzaW9ucyksbj1lLnNlbGVjdGVkU2Vzc2lvbklkJiYiIiE9PWUuc2VsZWN0ZWRTZXNzaW9uSWQ/ZS5zZWxlY3RlZFNlc3Npb25JZDp0LmZpcnN0KCkuaWQ7cmV0dXJuIG5ldyBiLlNlc3Npb25TdGF0ZSh7c2VsZWN0ZWRTZXNzaW9uSWQ6bixzZXNzaW9uczp0LHNlc3Npb25Db3VudDp0LnNpemUsaGVhZGVyczplLmhlYWRlcnN9KX1mdW5jdGlvbiBjKGUpe3JldHVybiBDLk9yZGVyZWRNYXAoRC5tYXBWYWx1ZXMoZSxmdW5jdGlvbihlKXtyZXR1cm4gbChlKX0pKX1mdW5jdGlvbiBsKGUpe3JldHVybiBuZXcgYi5TZXNzaW9uKGcoe30sZSx7cmVzcG9uc2VzOnAoZS5yZXNwb25zZXMpLG9wZXJhdGlvbnM6Qy5mcm9tSlMoZS5vcGVyYXRpb25zKSx2YXJpYWJsZVRvVHlwZTpDLk1hcChlLnZhcmlhYmxlVG9UeXBlKSxkYXRlOmUuZGF0ZT9uZXcgRGF0ZShlLmRhdGUpOnZvaWQgMCxjdXJyZW50UXVlcnlTdGFydFRpbWU6ZS5jdXJyZW50UXVlcnlTdGFydFRpbWU/bmV3IERhdGUoZS5jdXJyZW50UXVlcnlTdGFydFRpbWUpOnZvaWQgMCxjdXJyZW50UXVlcnlFbmRUaW1lOmUuY3VycmVudFF1ZXJ5RW5kVGltZT9uZXcgRGF0ZShlLmN1cnJlbnRRdWVyeUVuZFRpbWUpOnZvaWQgMCxuZXh0UXVlcnlTdGFydFRpbWU6ZS5uZXh0UXVlcnlTdGFydFRpbWU/bmV3IERhdGUoZS5uZXh0UXVlcnlTdGFydFRpbWUpOnZvaWQgMH0pKX1mdW5jdGlvbiBwKGUpe3JldHVybiBDLkxpc3QoZS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIGUuaXNTY2hlbWFFcnJvcn0pLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZihlKX0pKX1mdW5jdGlvbiBmKGUpe3JldHVybiBuZXcgYi5SZXNwb25zZVJlY29yZCh7cmVzdWx0SUQ6ZS5yZXN1bHRJRCxkYXRlOmUuZGF0ZSx0aW1lOm5ldyBEYXRlKGUudGltZSksaXNTY2hlbWFFcnJvcjplLmlzU2NoZW1hRXJyb3J8fCExfSl9ZnVuY3Rpb24gZChlKXt2YXIgdD0oZS5zaGFyZVVybCx5KGUsWyJzaGFyZVVybCJdKSk7cmV0dXJuIG5ldyB4LlNoYXJpbmdTdGF0ZSh0KX1mdW5jdGlvbiBoKGUpe3JldHVybiBjKGUpfWZ1bmN0aW9uIG0oZSl7cmV0dXJuIG5ldyBFLkdlbmVyYWxTdGF0ZShlKX12YXIgZz1mdW5jdGlvbigpe3JldHVybiBnPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPTEscj1hcmd1bWVudHMubGVuZ3RoO248cjtuKyspe3Q9YXJndW1lbnRzW25dO2Zvcih2YXIgaSBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LGkpJiYoZVtpXT10W2ldKX1yZXR1cm4gZX0sZy5hcHBseSh0aGlzLGFyZ3VtZW50cyl9LHk9ZnVuY3Rpb24oZSx0KXt2YXIgbj17fTtmb3IodmFyIHIgaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxyKSYmdC5pbmRleE9mKHIpPDAmJihuW3JdPWVbcl0pO2lmKG51bGwhPWUmJiJmdW5jdGlvbiI9PT10eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scylmb3IodmFyIGk9MCxyPU9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMoZSk7aTxyLmxlbmd0aDtpKyspdC5pbmRleE9mKHJbaV0pPDAmJihuW3JbaV1dPWVbcltpXV0pO3JldHVybiBufTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHY9bigxMzApLGI9big4NSkseD1uKDI0OCksQz1uKDE0KSxFPW4oMjQ5KSxEPW4oNzQpLHc9bigxNyksUz1uKDI1MSk7dC5kZXNlcmlhbGl6ZVBlcnNpc3RlZFN0YXRlPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigxNCksbz1uKDIzKSxhPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gbnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzfXJldHVybiByKHQsZSksdH0oaS5SZWNvcmQoe2l0ZW1zOmkuT3JkZXJlZE1hcCgpfSkpO3QuQXBwSGlzdG9yeT1hO3ZhciBzPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gbnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzfXJldHVybiByKHQsZSksdH0oaS5SZWNvcmQoe3R5cGU6ImxvY2FsIixjb25maWdTdHJpbmc6dm9pZCAwLGNvbmZpZ1BhdGg6dm9pZCAwLGVuZHBvaW50OnZvaWQgMCxmb2xkZXJOYW1lOnZvaWQgMCxlbnY6dm9pZCAwLHBsYXRmb3JtVG9rZW46dm9pZCAwLGxhc3RPcGVuZWQ6bmV3IERhdGUsY29uZmlnOnZvaWQgMH0pKTt0LkFwcEhpc3RvcnlJdGVtPXMsdC5kZWZhdWx0PW8uaGFuZGxlQWN0aW9ucyh7U0VMRUNUX0FQUF9ISVNUT1JZX0lURU06ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQ7cmV0dXJuIGUuc2V0SW4oWyJpdGVtcyIsbi5pdGVtLnBhdGhdLG4uaXRlbSl9fSxuZXcgYSksdC5nZXRBcHBIaXN0b3J5PWZ1bmN0aW9uKGUpe3JldHVybiBlLmFwcEhpc3Rvcnl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXtyZXR1cm4gMX1mdW5jdGlvbiBpKGUpe2lmKCEodGhpcyBpbnN0YW5jZW9mIGkpKXJldHVybiBuZXcgaShlKTsibnVtYmVyIj09PXR5cGVvZiBlJiYoZT17bWF4OmV9KSxlfHwoZT17fSk7dmFyIHQ9dGhpc1tnXT1lLm1heDsoIXR8fCJudW1iZXIiIT09dHlwZW9mIHR8fHQ8PTApJiYodGhpc1tnXT0xLzApO3ZhciBuPWUubGVuZ3RofHxyOyJmdW5jdGlvbiIhPT10eXBlb2YgbiYmKG49ciksdGhpc1t2XT1uLHRoaXNbYl09ZS5zdGFsZXx8ITEsdGhpc1t4XT1lLm1heEFnZXx8MCx0aGlzW0NdPWUuZGlzcG9zZSx0aGlzW0VdPWUubm9EaXNwb3NlT25TZXR8fCExLHRoaXMucmVzZXQoKX1mdW5jdGlvbiBvKGUsdCxuLHIpe3ZhciBpPW4udmFsdWU7cyhlLGkpJiYoYyhlLG4pLGVbYl18fChpPXZvaWQgMCkpLGkmJnQuY2FsbChyLGkudmFsdWUsaS5rZXksZSl9ZnVuY3Rpb24gYShlLHQsbil7dmFyIHI9ZVt3XS5nZXQodCk7aWYocil7dmFyIGk9ci52YWx1ZTtzKGUsaSk/KGMoZSxyKSxlW2JdfHwoaT12b2lkIDApKTpuJiZlW0RdLnVuc2hpZnROb2RlKHIpLGkmJihpPWkudmFsdWUpfXJldHVybiBpfWZ1bmN0aW9uIHMoZSx0KXtpZighdHx8IXQubWF4QWdlJiYhZVt4XSlyZXR1cm4hMTt2YXIgbj1EYXRlLm5vdygpLXQubm93O3JldHVybiB0Lm1heEFnZT9uPnQubWF4QWdlOmVbeF0mJm4+ZVt4XX1mdW5jdGlvbiB1KGUpe2lmKGVbeV0+ZVtnXSlmb3IodmFyIHQ9ZVtEXS50YWlsO2VbeV0+ZVtnXSYmbnVsbCE9PXQ7KXt2YXIgbj10LnByZXY7YyhlLHQpLHQ9bn19ZnVuY3Rpb24gYyhlLHQpe2lmKHQpe3ZhciBuPXQudmFsdWU7ZVtDXSYmZVtDXShuLmtleSxuLnZhbHVlKSxlW3ldLT1uLmxlbmd0aCxlW3ddLmRlbGV0ZShuLmtleSksZVtEXS5yZW1vdmVOb2RlKHQpfX1mdW5jdGlvbiBsKGUsdCxuLHIsaSl7dGhpcy5rZXk9ZSx0aGlzLnZhbHVlPXQsdGhpcy5sZW5ndGg9bix0aGlzLm5vdz1yLHRoaXMubWF4QWdlPWl8fDB9ZS5leHBvcnRzPWk7dmFyIHAsZj1uKDUwMyksZD1uKDI1MyksaD1uKDUwNyksbT0iZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbDtwPW0/ZnVuY3Rpb24oZSl7cmV0dXJuIFN5bWJvbC5mb3IoZSl9OmZ1bmN0aW9uKGUpe3JldHVybiJfIitlfTt2YXIgZz1wKCJtYXgiKSx5PXAoImxlbmd0aCIpLHY9cCgibGVuZ3RoQ2FsY3VsYXRvciIpLGI9cCgiYWxsb3dTdGFsZSIpLHg9cCgibWF4QWdlIiksQz1wKCJkaXNwb3NlIiksRT1wKCJub0Rpc3Bvc2VPblNldCIpLEQ9cCgibHJ1TGlzdCIpLHc9cCgiY2FjaGUiKTtPYmplY3QuZGVmaW5lUHJvcGVydHkoaS5wcm90b3R5cGUsIm1heCIse3NldDpmdW5jdGlvbihlKXsoIWV8fCJudW1iZXIiIT09dHlwZW9mIGV8fGU8PTApJiYoZT0xLzApLHRoaXNbZ109ZSx1KHRoaXMpfSxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc1tnXX0sZW51bWVyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShpLnByb3RvdHlwZSwiYWxsb3dTdGFsZSIse3NldDpmdW5jdGlvbihlKXt0aGlzW2JdPSEhZX0sZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXNbYl19LGVudW1lcmFibGU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoaS5wcm90b3R5cGUsIm1heEFnZSIse3NldDpmdW5jdGlvbihlKXsoIWV8fCJudW1iZXIiIT09dHlwZW9mIGV8fGU8MCkmJihlPTApLHRoaXNbeF09ZSx1KHRoaXMpfSxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc1t4XX0sZW51bWVyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShpLnByb3RvdHlwZSwibGVuZ3RoQ2FsY3VsYXRvciIse3NldDpmdW5jdGlvbihlKXsiZnVuY3Rpb24iIT09dHlwZW9mIGUmJihlPXIpLGUhPT10aGlzW3ZdJiYodGhpc1t2XT1lLHRoaXNbeV09MCx0aGlzW0RdLmZvckVhY2goZnVuY3Rpb24oZSl7ZS5sZW5ndGg9dGhpc1t2XShlLnZhbHVlLGUua2V5KSx0aGlzW3ldKz1lLmxlbmd0aH0sdGhpcykpLHUodGhpcyl9LGdldDpmdW5jdGlvbigpe3JldHVybiB0aGlzW3ZdfSxlbnVtZXJhYmxlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGkucHJvdG90eXBlLCJsZW5ndGgiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc1t5XX0sZW51bWVyYWJsZTohMH0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShpLnByb3RvdHlwZSwiaXRlbUNvdW50Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXNbRF0ubGVuZ3RofSxlbnVtZXJhYmxlOiEwfSksaS5wcm90b3R5cGUucmZvckVhY2g9ZnVuY3Rpb24oZSx0KXt0PXR8fHRoaXM7Zm9yKHZhciBuPXRoaXNbRF0udGFpbDtudWxsIT09bjspe3ZhciByPW4ucHJldjtvKHRoaXMsZSxuLHQpLG49cn19LGkucHJvdG90eXBlLmZvckVhY2g9ZnVuY3Rpb24oZSx0KXt0PXR8fHRoaXM7Zm9yKHZhciBuPXRoaXNbRF0uaGVhZDtudWxsIT09bjspe3ZhciByPW4ubmV4dDtvKHRoaXMsZSxuLHQpLG49cn19LGkucHJvdG90eXBlLmtleXM9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc1tEXS50b0FycmF5KCkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLmtleX0sdGhpcyl9LGkucHJvdG90eXBlLnZhbHVlcz1mdW5jdGlvbigpe3JldHVybiB0aGlzW0RdLnRvQXJyYXkoKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUudmFsdWV9LHRoaXMpfSxpLnByb3RvdHlwZS5yZXNldD1mdW5jdGlvbigpe3RoaXNbQ10mJnRoaXNbRF0mJnRoaXNbRF0ubGVuZ3RoJiZ0aGlzW0RdLmZvckVhY2goZnVuY3Rpb24oZSl7dGhpc1tDXShlLmtleSxlLnZhbHVlKX0sdGhpcyksdGhpc1t3XT1uZXcgZix0aGlzW0RdPW5ldyBoLHRoaXNbeV09MH0saS5wcm90b3R5cGUuZHVtcD1mdW5jdGlvbigpe3JldHVybiB0aGlzW0RdLm1hcChmdW5jdGlvbihlKXtpZighcyh0aGlzLGUpKXJldHVybntrOmUua2V5LHY6ZS52YWx1ZSxlOmUubm93KyhlLm1heEFnZXx8MCl9fSx0aGlzKS50b0FycmF5KCkuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBlfSl9LGkucHJvdG90eXBlLmR1bXBMcnU9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc1tEXX0saS5wcm90b3R5cGUuaW5zcGVjdD1mdW5jdGlvbihlLHQpe3ZhciBuPSJMUlVDYWNoZSB7IixpPSExO3RoaXNbYl0mJihuKz0iXG4gIGFsbG93U3RhbGU6IHRydWUiLGk9ITApO3ZhciBvPXRoaXNbZ107byYmbyE9PTEvMCYmKGkmJihuKz0iLCIpLG4rPSJcbiAgbWF4OiAiK2QuaW5zcGVjdChvLHQpLGk9ITApO3ZhciBhPXRoaXNbeF07YSYmKGkmJihuKz0iLCIpLG4rPSJcbiAgbWF4QWdlOiAiK2QuaW5zcGVjdChhLHQpLGk9ITApO3ZhciB1PXRoaXNbdl07dSYmdSE9PXImJihpJiYobis9IiwiKSxuKz0iXG4gIGxlbmd0aDogIitkLmluc3BlY3QodGhpc1t5XSx0KSxpPSEwKTt2YXIgYz0hMTtyZXR1cm4gdGhpc1tEXS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2M/bis9IixcbiAgIjooaSYmKG4rPSIsXG4iKSxjPSEwLG4rPSJcbiAgIik7dmFyIG89ZC5pbnNwZWN0KGUua2V5KS5zcGxpdCgiXG4iKS5qb2luKCJcbiAgIiksbD17dmFsdWU6ZS52YWx1ZX07ZS5tYXhBZ2UhPT1hJiYobC5tYXhBZ2U9ZS5tYXhBZ2UpLHUhPT1yJiYobC5sZW5ndGg9ZS5sZW5ndGgpLHModGhpcyxlKSYmKGwuc3RhbGU9ITApLGw9ZC5pbnNwZWN0KGwsdCkuc3BsaXQoIlxuIikuam9pbigiXG4gICIpLG4rPW8rIiA9PiAiK2x9KSwoY3x8aSkmJihuKz0iXG4iKSxuKz0ifSJ9LGkucHJvdG90eXBlLnNldD1mdW5jdGlvbihlLHQsbil7bj1ufHx0aGlzW3hdO3ZhciByPW4/RGF0ZS5ub3coKTowLGk9dGhpc1t2XSh0LGUpO2lmKHRoaXNbd10uaGFzKGUpKXtpZihpPnRoaXNbZ10pcmV0dXJuIGModGhpcyx0aGlzW3ddLmdldChlKSksITE7dmFyIG89dGhpc1t3XS5nZXQoZSksYT1vLnZhbHVlO3JldHVybiB0aGlzW0NdJiYodGhpc1tFXXx8dGhpc1tDXShlLGEudmFsdWUpKSxhLm5vdz1yLGEubWF4QWdlPW4sYS52YWx1ZT10LHRoaXNbeV0rPWktYS5sZW5ndGgsYS5sZW5ndGg9aSx0aGlzLmdldChlKSx1KHRoaXMpLCEwfXZhciBzPW5ldyBsKGUsdCxpLHIsbik7cmV0dXJuIHMubGVuZ3RoPnRoaXNbZ10/KHRoaXNbQ10mJnRoaXNbQ10oZSx0KSwhMSk6KHRoaXNbeV0rPXMubGVuZ3RoLHRoaXNbRF0udW5zaGlmdChzKSx0aGlzW3ddLnNldChlLHRoaXNbRF0uaGVhZCksdSh0aGlzKSwhMCl9LGkucHJvdG90eXBlLmhhcz1mdW5jdGlvbihlKXtyZXR1cm4hIXRoaXNbd10uaGFzKGUpJiYhcyh0aGlzLHRoaXNbd10uZ2V0KGUpLnZhbHVlKX0saS5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUpe3JldHVybiBhKHRoaXMsZSwhMCl9LGkucHJvdG90eXBlLnBlZWs9ZnVuY3Rpb24oZSl7cmV0dXJuIGEodGhpcyxlLCExKX0saS5wcm90b3R5cGUucG9wPWZ1bmN0aW9uKCl7dmFyIGU9dGhpc1tEXS50YWlsO3JldHVybiBlPyhjKHRoaXMsZSksZS52YWx1ZSk6bnVsbH0saS5wcm90b3R5cGUuZGVsPWZ1bmN0aW9uKGUpe2ModGhpcyx0aGlzW3ddLmdldChlKSl9LGkucHJvdG90eXBlLmxvYWQ9ZnVuY3Rpb24oZSl7dGhpcy5yZXNldCgpO2Zvcih2YXIgdD1EYXRlLm5vdygpLG49ZS5sZW5ndGgtMTtuPj0wO24tLSl7dmFyIHI9ZVtuXSxpPXIuZXx8MDtpZigwPT09aSl0aGlzLnNldChyLmssci52KTtlbHNle3ZhciBvPWktdDtvPjAmJnRoaXMuc2V0KHIuayxyLnYsbyl9fX0saS5wcm90b3R5cGUucHJ1bmU9ZnVuY3Rpb24oKXt2YXIgZT10aGlzO3RoaXNbd10uZm9yRWFjaChmdW5jdGlvbih0LG4pe2EoZSxuLCExKX0pfX0sZnVuY3Rpb24oZSx0LG4peyhmdW5jdGlvbihlLHIpe2Z1bmN0aW9uIGkoZSxuKXt2YXIgcj17c2VlbjpbXSxzdHlsaXplOmF9O3JldHVybiBhcmd1bWVudHMubGVuZ3RoPj0zJiYoci5kZXB0aD1hcmd1bWVudHNbMl0pLGFyZ3VtZW50cy5sZW5ndGg+PTQmJihyLmNvbG9ycz1hcmd1bWVudHNbM10pLG0obik/ci5zaG93SGlkZGVuPW46biYmdC5fZXh0ZW5kKHIsbiksQyhyLnNob3dIaWRkZW4pJiYoci5zaG93SGlkZGVuPSExKSxDKHIuZGVwdGgpJiYoci5kZXB0aD0yKSxDKHIuY29sb3JzKSYmKHIuY29sb3JzPSExKSxDKHIuY3VzdG9tSW5zcGVjdCkmJihyLmN1c3RvbUluc3BlY3Q9ITApLHIuY29sb3JzJiYoci5zdHlsaXplPW8pLHUocixlLHIuZGVwdGgpfWZ1bmN0aW9uIG8oZSx0KXt2YXIgbj1pLnN0eWxlc1t0XTtyZXR1cm4gbj8iXHgxYlsiK2kuY29sb3JzW25dWzBdKyJtIitlKyJceDFiWyIraS5jb2xvcnNbbl1bMV0rIm0iOmV9ZnVuY3Rpb24gYShlLHQpe3JldHVybiBlfWZ1bmN0aW9uIHMoZSl7dmFyIHQ9e307cmV0dXJuIGUuZm9yRWFjaChmdW5jdGlvbihlLG4pe3RbZV09ITB9KSx0fWZ1bmN0aW9uIHUoZSxuLHIpe2lmKGUuY3VzdG9tSW5zcGVjdCYmbiYmayhuLmluc3BlY3QpJiZuLmluc3BlY3QhPT10Lmluc3BlY3QmJighbi5jb25zdHJ1Y3Rvcnx8bi5jb25zdHJ1Y3Rvci5wcm90b3R5cGUhPT1uKSl7dmFyIGk9bi5pbnNwZWN0KHIsZSk7cmV0dXJuIGIoaSl8fChpPXUoZSxpLHIpKSxpfXZhciBvPWMoZSxuKTtpZihvKXJldHVybiBvO3ZhciBhPU9iamVjdC5rZXlzKG4pLG09cyhhKTtpZihlLnNob3dIaWRkZW4mJihhPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKG4pKSxTKG4pJiYoYS5pbmRleE9mKCJtZXNzYWdlIik+PTB8fGEuaW5kZXhPZigiZGVzY3JpcHRpb24iKT49MCkpcmV0dXJuIGwobik7aWYoMD09PWEubGVuZ3RoKXtpZihrKG4pKXt2YXIgZz1uLm5hbWU/IjogIituLm5hbWU6IiI7cmV0dXJuIGUuc3R5bGl6ZSgiW0Z1bmN0aW9uIitnKyJdIiwic3BlY2lhbCIpfWlmKEUobikpcmV0dXJuIGUuc3R5bGl6ZShSZWdFeHAucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwobiksInJlZ2V4cCIpO2lmKHcobikpcmV0dXJuIGUuc3R5bGl6ZShEYXRlLnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG4pLCJkYXRlIik7aWYoUyhuKSlyZXR1cm4gbChuKX12YXIgeT0iIix2PSExLHg9WyJ7IiwifSJdO2lmKGgobikmJih2PSEwLHg9WyJbIiwiXSJdKSxrKG4pKXt5PSIgW0Z1bmN0aW9uIisobi5uYW1lPyI6ICIrbi5uYW1lOiIiKSsiXSJ9aWYoRShuKSYmKHk9IiAiK1JlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChuKSksdyhuKSYmKHk9IiAiK0RhdGUucHJvdG90eXBlLnRvVVRDU3RyaW5nLmNhbGwobikpLFMobikmJih5PSIgIitsKG4pKSwwPT09YS5sZW5ndGgmJighdnx8MD09bi5sZW5ndGgpKXJldHVybiB4WzBdK3kreFsxXTtpZihyPDApcmV0dXJuIEUobik/ZS5zdHlsaXplKFJlZ0V4cC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChuKSwicmVnZXhwIik6ZS5zdHlsaXplKCJbT2JqZWN0XSIsInNwZWNpYWwiKTtlLnNlZW4ucHVzaChuKTt2YXIgQztyZXR1cm4gQz12P3AoZSxuLHIsbSxhKTphLm1hcChmdW5jdGlvbih0KXtyZXR1cm4gZihlLG4scixtLHQsdil9KSxlLnNlZW4ucG9wKCksZChDLHkseCl9ZnVuY3Rpb24gYyhlLHQpe2lmKEModCkpcmV0dXJuIGUuc3R5bGl6ZSgidW5kZWZpbmVkIiwidW5kZWZpbmVkIik7aWYoYih0KSl7dmFyIG49IiciK0pTT04uc3RyaW5naWZ5KHQpLnJlcGxhY2UoL14ifCIkL2csIiIpLnJlcGxhY2UoLycvZywiXFwnIikucmVwbGFjZSgvXFwiL2csJyInKSsiJyI7cmV0dXJuIGUuc3R5bGl6ZShuLCJzdHJpbmciKX1yZXR1cm4gdih0KT9lLnN0eWxpemUoIiIrdCwibnVtYmVyIik6bSh0KT9lLnN0eWxpemUoIiIrdCwiYm9vbGVhbiIpOmcodCk/ZS5zdHlsaXplKCJudWxsIiwibnVsbCIpOnZvaWQgMH1mdW5jdGlvbiBsKGUpe3JldHVybiJbIitFcnJvci5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChlKSsiXSJ9ZnVuY3Rpb24gcChlLHQsbixyLGkpe2Zvcih2YXIgbz1bXSxhPTAscz10Lmxlbmd0aDthPHM7KythKUYodCxTdHJpbmcoYSkpP28ucHVzaChmKGUsdCxuLHIsU3RyaW5nKGEpLCEwKSk6by5wdXNoKCIiKTtyZXR1cm4gaS5mb3JFYWNoKGZ1bmN0aW9uKGkpe2kubWF0Y2goL15cZCskLyl8fG8ucHVzaChmKGUsdCxuLHIsaSwhMCkpfSksb31mdW5jdGlvbiBmKGUsdCxuLHIsaSxvKXt2YXIgYSxzLGM7aWYoYz1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHQsaSl8fHt2YWx1ZTp0W2ldfSxjLmdldD9zPWMuc2V0P2Uuc3R5bGl6ZSgiW0dldHRlci9TZXR0ZXJdIiwic3BlY2lhbCIpOmUuc3R5bGl6ZSgiW0dldHRlcl0iLCJzcGVjaWFsIik6Yy5zZXQmJihzPWUuc3R5bGl6ZSgiW1NldHRlcl0iLCJzcGVjaWFsIikpLEYocixpKXx8KGE9IlsiK2krIl0iKSxzfHwoZS5zZWVuLmluZGV4T2YoYy52YWx1ZSk8MD8ocz1nKG4pP3UoZSxjLnZhbHVlLG51bGwpOnUoZSxjLnZhbHVlLG4tMSkscy5pbmRleE9mKCJcbiIpPi0xJiYocz1vP3Muc3BsaXQoIlxuIikubWFwKGZ1bmN0aW9uKGUpe3JldHVybiIgICIrZX0pLmpvaW4oIlxuIikuc3Vic3RyKDIpOiJcbiIrcy5zcGxpdCgiXG4iKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIiAgICIrZX0pLmpvaW4oIlxuIikpKTpzPWUuc3R5bGl6ZSgiW0NpcmN1bGFyXSIsInNwZWNpYWwiKSksQyhhKSl7aWYobyYmaS5tYXRjaCgvXlxkKyQvKSlyZXR1cm4gczthPUpTT04uc3RyaW5naWZ5KCIiK2kpLGEubWF0Y2goL14iKFthLXpBLVpfXVthLXpBLVpfMC05XSopIiQvKT8oYT1hLnN1YnN0cigxLGEubGVuZ3RoLTIpLGE9ZS5zdHlsaXplKGEsIm5hbWUiKSk6KGE9YS5yZXBsYWNlKC8nL2csIlxcJyIpLnJlcGxhY2UoL1xcIi9nLCciJykucmVwbGFjZSgvKF4ifCIkKS9nLCInIiksYT1lLnN0eWxpemUoYSwic3RyaW5nIikpfXJldHVybiBhKyI6ICIrc31mdW5jdGlvbiBkKGUsdCxuKXt2YXIgcj0wO3JldHVybiBlLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiByKyssdC5pbmRleE9mKCJcbiIpPj0wJiZyKyssZSt0LnJlcGxhY2UoL1x1MDAxYlxbXGRcZD9tL2csIiIpLmxlbmd0aCsxfSwwKT42MD9uWzBdKygiIj09PXQ/IiI6dCsiXG4gIikrIiAiK2Uuam9pbigiLFxuICAiKSsiICIrblsxXTpuWzBdK3QrIiAiK2Uuam9pbigiLCAiKSsiICIrblsxXX1mdW5jdGlvbiBoKGUpe3JldHVybiBBcnJheS5pc0FycmF5KGUpfWZ1bmN0aW9uIG0oZSl7cmV0dXJuImJvb2xlYW4iPT09dHlwZW9mIGV9ZnVuY3Rpb24gZyhlKXtyZXR1cm4gbnVsbD09PWV9ZnVuY3Rpb24geShlKXtyZXR1cm4gbnVsbD09ZX1mdW5jdGlvbiB2KGUpe3JldHVybiJudW1iZXIiPT09dHlwZW9mIGV9ZnVuY3Rpb24gYihlKXtyZXR1cm4ic3RyaW5nIj09PXR5cGVvZiBlfWZ1bmN0aW9uIHgoZSl7cmV0dXJuInN5bWJvbCI9PT10eXBlb2YgZX1mdW5jdGlvbiBDKGUpe3JldHVybiB2b2lkIDA9PT1lfWZ1bmN0aW9uIEUoZSl7cmV0dXJuIEQoZSkmJiJbb2JqZWN0IFJlZ0V4cF0iPT09XyhlKX1mdW5jdGlvbiBEKGUpe3JldHVybiJvYmplY3QiPT09dHlwZW9mIGUmJm51bGwhPT1lfWZ1bmN0aW9uIHcoZSl7cmV0dXJuIEQoZSkmJiJbb2JqZWN0IERhdGVdIj09PV8oZSl9ZnVuY3Rpb24gUyhlKXtyZXR1cm4gRChlKSYmKCJbb2JqZWN0IEVycm9yXSI9PT1fKGUpfHxlIGluc3RhbmNlb2YgRXJyb3IpfWZ1bmN0aW9uIGsoZSl7cmV0dXJuImZ1bmN0aW9uIj09PXR5cGVvZiBlfWZ1bmN0aW9uIEEoZSl7cmV0dXJuIG51bGw9PT1lfHwiYm9vbGVhbiI9PT10eXBlb2YgZXx8Im51bWJlciI9PT10eXBlb2YgZXx8InN0cmluZyI9PT10eXBlb2YgZXx8InN5bWJvbCI9PT10eXBlb2YgZXx8InVuZGVmaW5lZCI9PT10eXBlb2YgZX1mdW5jdGlvbiBfKGUpe3JldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZSl9ZnVuY3Rpb24gVChlKXtyZXR1cm4gZTwxMD8iMCIrZS50b1N0cmluZygxMCk6ZS50b1N0cmluZygxMCl9ZnVuY3Rpb24gTygpe3ZhciBlPW5ldyBEYXRlLHQ9W1QoZS5nZXRIb3VycygpKSxUKGUuZ2V0TWludXRlcygpKSxUKGUuZ2V0U2Vjb25kcygpKV0uam9pbigiOiIpO3JldHVybltlLmdldERhdGUoKSxQW2UuZ2V0TW9udGgoKV0sdF0uam9pbigiICIpfWZ1bmN0aW9uIEYoZSx0KXtyZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUsdCl9dmFyIE49LyVbc2RqJV0vZzt0LmZvcm1hdD1mdW5jdGlvbihlKXtpZighYihlKSl7Zm9yKHZhciB0PVtdLG49MDtuPGFyZ3VtZW50cy5sZW5ndGg7bisrKXQucHVzaChpKGFyZ3VtZW50c1tuXSkpO3JldHVybiB0LmpvaW4oIiAiKX1mb3IodmFyIG49MSxyPWFyZ3VtZW50cyxvPXIubGVuZ3RoLGE9U3RyaW5nKGUpLnJlcGxhY2UoTixmdW5jdGlvbihlKXtpZigiJSUiPT09ZSlyZXR1cm4iJSI7aWYobj49bylyZXR1cm4gZTtzd2l0Y2goZSl7Y2FzZSIlcyI6cmV0dXJuIFN0cmluZyhyW24rK10pO2Nhc2UiJWQiOnJldHVybiBOdW1iZXIocltuKytdKTtjYXNlIiVqIjp0cnl7cmV0dXJuIEpTT04uc3RyaW5naWZ5KHJbbisrXSl9Y2F0Y2goZSl7cmV0dXJuIltDaXJjdWxhcl0ifWRlZmF1bHQ6cmV0dXJuIGV9fSkscz1yW25dO248bztzPXJbKytuXSlnKHMpfHwhRChzKT9hKz0iICIrczphKz0iICIraShzKTtyZXR1cm4gYX0sdC5kZXByZWNhdGU9ZnVuY3Rpb24obixpKXtmdW5jdGlvbiBvKCl7aWYoIWEpe2lmKHIudGhyb3dEZXByZWNhdGlvbil0aHJvdyBuZXcgRXJyb3IoaSk7ci50cmFjZURlcHJlY2F0aW9uP2NvbnNvbGUudHJhY2UoaSk6Y29uc29sZS5lcnJvcihpKSxhPSEwfXJldHVybiBuLmFwcGx5KHRoaXMsYXJndW1lbnRzKX1pZihDKGUucHJvY2VzcykpcmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIHQuZGVwcmVjYXRlKG4saSkuYXBwbHkodGhpcyxhcmd1bWVudHMpfTtpZighMD09PXIubm9EZXByZWNhdGlvbilyZXR1cm4gbjt2YXIgYT0hMTtyZXR1cm4gb307dmFyIEksTD17fTt0LmRlYnVnbG9nPWZ1bmN0aW9uKGUpe2lmKEMoSSkmJihJPU9iamVjdCh7Tk9ERV9FTlY6InByb2R1Y3Rpb24iLFBVQkxJQ19VUkw6IiJ9KS5OT0RFX0RFQlVHfHwiIiksZT1lLnRvVXBwZXJDYXNlKCksIUxbZV0paWYobmV3IFJlZ0V4cCgiXFxiIitlKyJcXGIiLCJpIikudGVzdChJKSl7dmFyIG49ci5waWQ7TFtlXT1mdW5jdGlvbigpe3ZhciByPXQuZm9ybWF0LmFwcGx5KHQsYXJndW1lbnRzKTtjb25zb2xlLmVycm9yKCIlcyAlZDogJXMiLGUsbixyKX19ZWxzZSBMW2VdPWZ1bmN0aW9uKCl7fTtyZXR1cm4gTFtlXX0sdC5pbnNwZWN0PWksaS5jb2xvcnM9e2JvbGQ6WzEsMjJdLGl0YWxpYzpbMywyM10sdW5kZXJsaW5lOls0LDI0XSxpbnZlcnNlOls3LDI3XSx3aGl0ZTpbMzcsMzldLGdyZXk6WzkwLDM5XSxibGFjazpbMzAsMzldLGJsdWU6WzM0LDM5XSxjeWFuOlszNiwzOV0sZ3JlZW46WzMyLDM5XSxtYWdlbnRhOlszNSwzOV0scmVkOlszMSwzOV0seWVsbG93OlszMywzOV19LGkuc3R5bGVzPXtzcGVjaWFsOiJjeWFuIixudW1iZXI6InllbGxvdyIsYm9vbGVhbjoieWVsbG93Iix1bmRlZmluZWQ6ImdyZXkiLG51bGw6ImJvbGQiLHN0cmluZzoiZ3JlZW4iLGRhdGU6Im1hZ2VudGEiLHJlZ2V4cDoicmVkIn0sdC5pc0FycmF5PWgsdC5pc0Jvb2xlYW49bSx0LmlzTnVsbD1nLHQuaXNOdWxsT3JVbmRlZmluZWQ9eSx0LmlzTnVtYmVyPXYsdC5pc1N0cmluZz1iLHQuaXNTeW1ib2w9eCx0LmlzVW5kZWZpbmVkPUMsdC5pc1JlZ0V4cD1FLHQuaXNPYmplY3Q9RCx0LmlzRGF0ZT13LHQuaXNFcnJvcj1TLHQuaXNGdW5jdGlvbj1rLHQuaXNQcmltaXRpdmU9QSx0LmlzQnVmZmVyPW4oNTA1KTt2YXIgUD1bIkphbiIsIkZlYiIsIk1hciIsIkFwciIsIk1heSIsIkp1biIsIkp1bCIsIkF1ZyIsIlNlcCIsIk9jdCIsIk5vdiIsIkRlYyJdO3QubG9nPWZ1bmN0aW9uKCl7Y29uc29sZS5sb2coIiVzIC0gJXMiLE8oKSx0LmZvcm1hdC5hcHBseSh0LGFyZ3VtZW50cykpfSx0LmluaGVyaXRzPW4oNTA2KSx0Ll9leHRlbmQ9ZnVuY3Rpb24oZSx0KXtpZighdHx8IUQodCkpcmV0dXJuIGU7Zm9yKHZhciBuPU9iamVjdC5rZXlzKHQpLHI9bi5sZW5ndGg7ci0tOyllW25bcl1dPXRbbltyXV07cmV0dXJuIGV9fSkuY2FsbCh0LG4oMTEpLG4oNTYpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9big4KSxpPW4oMTcpO3QuZ2V0U2hhcmluZ1N0YXRlPXIuY3JlYXRlU2VsZWN0b3IoW2kuZ2V0U2VsZWN0ZWRXb3Jrc3BhY2VdLGZ1bmN0aW9uKGUpe3JldHVybiBlLnNoYXJpbmd9KTt2YXIgbz1mdW5jdGlvbihlKXtyZXR1cm4gci5jcmVhdGVTZWxlY3RvcihbdC5nZXRTaGFyaW5nU3RhdGVdLGZ1bmN0aW9uKHQpe3JldHVybiB0LmdldChlKX0pfTt0LmdldFNoYXJpbmdIaXN0b3J5PW8oImhpc3RvcnkiKSx0LmdldFNoYXJpbmdIZWFkZXJzPW8oImhlYWRlcnMiKSx0LmdldFNoYXJpbmdBbGxUYWJzPW8oImFsbFRhYnMiKSx0LmdldFNoYXJlVXJsPW8oInNoYXJlVXJsIil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD1lLm9mZnNldFdpZHRoPD0wJiZlLm9mZnNldEhlaWdodDw9MDtpZih0JiYhZS5pbm5lckhUTUwpcmV0dXJuITA7dmFyIG49d2luZG93LmdldENvbXB1dGVkU3R5bGUoZSk7cmV0dXJuIHQ/InZpc2libGUiIT09bi5nZXRQcm9wZXJ0eVZhbHVlKCJvdmVyZmxvdyIpOiJub25lIj09bi5nZXRQcm9wZXJ0eVZhbHVlKCJkaXNwbGF5Iil9ZnVuY3Rpb24gaShlKXtmb3IodmFyIHQ9ZTt0JiZ0IT09ZG9jdW1lbnQuYm9keTspe2lmKHIodCkpcmV0dXJuITE7dD10LnBhcmVudE5vZGV9cmV0dXJuITB9ZnVuY3Rpb24gbyhlLHQpe3ZhciBuPWUubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtyZXR1cm4odS50ZXN0KG4pJiYhZS5kaXNhYmxlZHx8KCJhIj09PW4/ZS5ocmVmfHx0OnQpKSYmaShlKX1mdW5jdGlvbiBhKGUpe3ZhciB0PWUuZ2V0QXR0cmlidXRlKCJ0YWJpbmRleCIpO251bGw9PT10JiYodD12b2lkIDApO3ZhciBuPWlzTmFOKHQpO3JldHVybihufHx0Pj0wKSYmbyhlLCFuKX1mdW5jdGlvbiBzKGUpe3JldHVybltdLnNsaWNlLmNhbGwoZS5xdWVyeVNlbGVjdG9yQWxsKCIqIiksMCkuZmlsdGVyKGEpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmRlZmF1bHQ9czt2YXIgdT0vaW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbnxvYmplY3QvO2UuZXhwb3J0cz10LmRlZmF1bHR9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2lmKCFlfHwhZS5sZW5ndGgpdGhyb3cgbmV3IEVycm9yKCJyZWFjdC1tb2RhbDogTm8gZWxlbWVudHMgd2VyZSBmb3VuZCBmb3Igc2VsZWN0b3IgIit0KyIuIil9ZnVuY3Rpb24gaShlKXt2YXIgdD1lO2lmKCJzdHJpbmciPT09dHlwZW9mIHQpe3ZhciBuPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwodCk7cihuLHQpLHQ9Imxlbmd0aCJpbiBuP25bMF06bn1yZXR1cm4gZj10fHxmfWZ1bmN0aW9uIG8oZSl7cmV0dXJuISghZSYmIWYpfHwoKDAscC5kZWZhdWx0KSghMSxbInJlYWN0LW1vZGFsOiBBcHAgZWxlbWVudCBpcyBub3QgZGVmaW5lZC4iLCJQbGVhc2UgdXNlIGBNb2RhbC5zZXRBcHBFbGVtZW50KGVsKWAgb3Igc2V0IGBhcHBFbGVtZW50PXtlbH1gLiIsIlRoaXMgaXMgbmVlZGVkIHNvIHNjcmVlbiByZWFkZXJzIGRvbid0IHNlZSBtYWluIGNvbnRlbnQiLCJ3aGVuIG1vZGFsIGlzIG9wZW5lZC4gSXQgaXMgbm90IHJlY29tbWVuZGVkLCBidXQgeW91IGNhbiBvcHQtb3V0IiwiYnkgc2V0dGluZyBgYXJpYUhpZGVBcHA9e2ZhbHNlfWAuIl0uam9pbigiICIpKSwhMSl9ZnVuY3Rpb24gYShlKXtvKGUpJiYoZXx8Zikuc2V0QXR0cmlidXRlKCJhcmlhLWhpZGRlbiIsInRydWUiKX1mdW5jdGlvbiBzKGUpe28oZSkmJihlfHxmKS5yZW1vdmVBdHRyaWJ1dGUoImFyaWEtaGlkZGVuIil9ZnVuY3Rpb24gdSgpe2Y9bnVsbH1mdW5jdGlvbiBjKCl7Zj1udWxsfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmFzc2VydE5vZGVMaXN0PXIsdC5zZXRFbGVtZW50PWksdC52YWxpZGF0ZUVsZW1lbnQ9byx0LmhpZGU9YSx0LnNob3c9cyx0LmRvY3VtZW50Tm90UmVhZHlPclNTUlRlc3Rpbmc9dSx0LnJlc2V0Rm9yVGVzdGluZz1jO3ZhciBsPW4oMjUpLHA9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShsKSxmPW51bGx9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuY2FuVXNlRE9NPXZvaWQgMDt2YXIgcj1uKDI1OCksaT1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19KHIpLG89aS5kZWZhdWx0LGE9by5jYW5Vc2VET00/d2luZG93LkhUTUxFbGVtZW50Ont9O3QuY2FuVXNlRE9NPW8uY2FuVXNlRE9NO3QuZGVmYXVsdD1hfSxmdW5jdGlvbihlLHQsbil7dmFyIHI7IWZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO3ZhciBpPSEoInVuZGVmaW5lZCI9PT10eXBlb2Ygd2luZG93fHwhd2luZG93LmRvY3VtZW50fHwhd2luZG93LmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQpLG89e2NhblVzZURPTTppLGNhblVzZVdvcmtlcnM6InVuZGVmaW5lZCIhPT10eXBlb2YgV29ya2VyLGNhblVzZUV2ZW50TGlzdGVuZXJzOmkmJiEoIXdpbmRvdy5hZGRFdmVudExpc3RlbmVyJiYhd2luZG93LmF0dGFjaEV2ZW50KSxjYW5Vc2VWaWV3cG9ydDppJiYhIXdpbmRvdy5zY3JlZW59O3ZvaWQgMCE9PShyPWZ1bmN0aW9uKCl7cmV0dXJuIG99LmNhbGwodCxuLHQsZSkpJiYoZS5leHBvcnRzPXIpfSgpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDE3KTt0LmRhcmtDb2xvdXJzPXtncmVlbjoiIzI3YWU2MCIsZGFya0JsdWU6InJnYigyMywgNDIsIDU4KSIsZGFya0JsdWU1MDoicmdiYSgyMywgNDIsIDU4LCAwLjUpIixkYXJrQmx1ZTgwOiJyZ2JhKDIzLCA0MiwgNTgsIDAuOCkiLGRhcmtCbHVlNjA6InJnYmEoMjMsIDQyLCA1OCwgMC42KSIsZGFya0JsdWUzMDoicmdiYSgyMywgNDIsIDU4LCAwLjMpIixkYXJrQmx1ZTIwOiJyZ2JhKDIzLCA0MiwgNTgsIDAuMikiLGRhcmtCbHVlMTA6InJnYmEoMjMsIDQyLCA1OCwgMC4xKSIsZGFya2VyQmx1ZToiIzBGMjAyRCIsZGFya2VzdEJsdWU6InJnYigxMSwyMCwyOCkiLHdoaXRlMTA6InJnYmEoMjU1LCAyNTUsIDI1NSwgMC4xKSIsd2hpdGUyMDoicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjIpIix3aGl0ZTMwOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuMykiLHdoaXRlNjA6InJnYmEoMjU1LCAyNTUsIDI1NSwgMC42KSIsd2hpdGU3MDoicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjcpIix3aGl0ZTgwOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuOCkiLHdoaXRlOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDEpIixibGFjazAyOiJyZ2JhKDAsIDAsIDAsIDAuMDIpIixibGFjazA3OiJyZ2JhKDAsIDAsIDAsIDAuMDcpIixibGFjazA0OiJyZ2JhKDAsIDAsIDAsIDAuMDQpIixibGFjazEwOiJyZ2JhKDAsIDAsIDAsIDAuMSkiLGJsYWNrMzA6InJnYmEoMCwgMCwgMCwgMC4zKSIsYmxhY2s0MDoicmdiYSgwLCAwLCAwLCAwLjQpIixibGFjazUwOiJyZ2JhKDAsIDAsIDAsIDAuNSkiLHJlZDoiI2YyNWM1NCIsb3JhbmdlOiJyZ2JhKDI0MSwgMTQzLCAxLCAxKSIsYmx1ZToicmdiYSg0MiwgMTI2LCAyMTAsIDEpIixwdXJwbGU6InJnYigxNjQsIDMsIDExMSkiLHBhbGVUZXh0OiJyZ2JhKDAsIDAsIDAsIDAuNSkiLHBhbGVHcmV5OiIjZjNmNGY0IixsaWdodEdyZXk6IiNlZWVmZjAiLGxpZ2h0ZXJHcmV5OiIjZjZmN2Y3Iix0ZXh0OiJyZ2JhKDI1NSwyNTUsMjU1LDAuNikiLHRleHRJbmFjdGl2ZToiIzU1NWU2NiJ9LHQubGlnaHRDb2xvdXJzPXtncmVlbjoiIzI3YWU2MCIsZGFya0JsdWU6InJnYigyMywgNDIsIDU4KSIsZGFya0JsdWU1MDoicmdiYSgyMywgNDIsIDU4LCAwLjUpIixkYXJrQmx1ZTgwOiJyZ2JhKDIzLCA0MiwgNTgsIDAuOCkiLGRhcmtCbHVlNjA6InJnYmEoMjMsIDQyLCA1OCwgMC42KSIsZGFya0JsdWUzMDoicmdiYSgyMywgNDIsIDU4LCAwLjMpIixkYXJrQmx1ZTIwOiJyZ2JhKDIzLCA0MiwgNTgsIDAuMikiLGRhcmtCbHVlMTA6InJnYmEoMjMsIDQyLCA1OCwgMC4xKSIsZGFya2VyQmx1ZToiIzBGMjAyRCIsZGFya2VzdEJsdWU6InJnYigxMSwyMCwyOCkiLHdoaXRlMTA6InJnYmEoMjU1LCAyNTUsIDI1NSwgMC4xKSIsd2hpdGUyMDoicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjIpIix3aGl0ZTMwOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuMykiLHdoaXRlNjA6InJnYmEoMjU1LCAyNTUsIDI1NSwgMC42KSIsd2hpdGU3MDoicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjcpIix3aGl0ZTgwOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuOCkiLHdoaXRlOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDEpIixibGFjazAyOiJyZ2JhKDAsIDAsIDAsIDAuMDIpIixibGFjazA0OiJyZ2JhKDAsIDAsIDAsIDAuMDQpIixibGFjazEwOiJyZ2JhKDAsIDAsIDAsIDAuMSkiLGJsYWNrMDc6InJnYmEoMCwgMCwgMCwgMC4wNykiLGJsYWNrMzA6InJnYmEoMCwgMCwgMCwgMC4zKSIsYmxhY2s0MDoicmdiYSgwLCAwLCAwLCAwLjQpIixibGFjazUwOiJyZ2JhKDAsIDAsIDAsIDAuNSkiLHJlZDoiI2YyNWM1NCIsb3JhbmdlOiJyZ2JhKDI0MSwgMTQzLCAxLCAxKSIsYmx1ZToicmdiYSg0MiwgMTI2LCAyMTAsIDEpIixwdXJwbGU6InJnYigxNjQsIDMsIDExMSkiLHBhbGVUZXh0OiJyZ2JhKDAsIDAsIDAsIDAuNSkiLHBhbGVHcmV5OiIjZjNmNGY0IixsaWdodEdyZXk6IiNlZWVmZjAiLGxpZ2h0ZXJHcmV5OiIjZjZmN2Y3Iix0ZXh0OiJyZ2JhKDAsMCwwLC43KSIsdGV4dEluYWN0aXZlOiJyZ2JhKDAsMCwwLC4zKSJ9LHQuZGFya0VkaXRvckNvbG91cnM9e3Byb3BlcnR5OiJyZ2IoNDEsIDE4NSwgMTE1KSIsY29tbWVudDoicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjMpIixwdW5jdHVhdGlvbjoicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjQpIixrZXl3b3JkOiJyZ2IoNDIsIDEyNiwgMjExKSIsZGVmOiJyZ2IoNTYsIDE4OSwgMTkzKSIscXVhbGlmaWVyOiIjMWM5MmE5IixhdHRyaWJ1dGU6InJnYigyNDcsIDExNiwgMTAyKSIsbnVtYmVyOiIjMjg4MmY5IixzdHJpbmc6IiNkNjQyOTIiLGJ1aWx0aW46IiNkNDc1MDkiLHN0cmluZzI6IiMwYjdmYzciLHZhcmlhYmxlOiJyZ2IoMTgxLCAzNCwgMTMwKSIsbWV0YToiI2IzMzA4NiIsYXRvbToicmdiKDI0OSwgMjMzLCAzNCkiLHdzOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuNCkiLHNlbGVjdGlvbjoicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjEpIixjdXJzb3JDb2xvcjoicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjQpIix0ZXh0OiIjZmZmIix0ZXh0SW5hY3RpdmU6InJnYmEoMjU1LCAyNTUsIDI1NSwgMC42KSIsYmFja2dyb3VuZDoiIzA5MTQxYyIsc2lkZWJhclRvcDoiIzBmMjAyZCIsc2lkZWJhcjoiIzE3MmIzYSIsc2lkZWJhckJvdHRvbToiIzE3MmIzYSIsc2lkZWJhckl0ZW1BY3RpdmU6InJnYigyMywgNDIsIDU4KSIsc2lkZWJhckl0ZW1TaWRlOiIjMjdhZTYwIixzaWRlYmFySXRlbVNlc3Npb25zOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuMDUpIix0YWI6IiMxNzJiM2EiLHRhYkluYWN0aXZlOiIjMGYyMDJkIix0YWJUZXh0OiIjZmZmIixuYXZpZ2F0aW9uQmFyOiIjMTcyYjNhIixuYXZpZ2F0aW9uQmFyVGV4dDoicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjYpIixlZGl0b3JCYWNrZ3JvdW5kOiIjMGYyMDJkIixyZXN1bHRCYWNrZ3JvdW5kOiIjMTcyYjNhIixsZWZ0RHJhd2VyQmFja2dyb3VuZDoiIzBiMTkyNCIscmlnaHREcmF3ZXJCYWNrZ3JvdW5kOiIjMGIxOTI0IixkcmF3ZXJUZXh0OiJyZ2JhKDI1NSwyNTUsMjU1LDAuNikiLGRyYXdlclRleHRJbmFjdGl2ZToiIzU1NWU2NiIsZXhlY3V0ZUJ1dHRvbjoicmdiKDE4NSwgMTkxLCAxOTYpIixleGVjdXRlQnV0dG9uQm9yZGVyOiJyZ2IoMTEsIDIwLCAyOCkiLGV4ZWN1dGVCdXR0b25Ib3ZlcjoicmdiKDE5NSwgMjAxLCAyMDYpIixleGVjdXRlQnV0dG9uU3Vic2NyaXB0aW9uOiIjZjI1YzU0IixleGVjdXRlQnV0dG9uU3Vic2NyaXB0aW9uSG92ZXI6IiNmMzZjNjUiLGljb246InJnYig3NCwgODUsIDk1KSIsaWNvbkhvdmVyOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuNikiLHBvbGxpbmdJY29uOiJyZ2JhKDEzOSwgMTQ5LCAxNTYsIDEpIixwb2xsaW5nSWNvblNoYWRvdzoicmdiYSgxMzksIDE0OSwgMTU2LCAwLjQpIixidXR0b246IiMwRjIwMkQiLGJ1dHRvbkhvdmVyOiIjMTIyNTM1IixidXR0b25UZXh0OiJyZ2JhKDI1NSwyNTUsMjU1LDAuNikiLGJ1dHRvbldvcmtzcGFjZToiI2I5YmZjNCIsYnV0dG9uV29ya3NwYWNlSG92ZXI6IiNhNGFjYjIiLGJ1dHRvbldvcmtzcGFjZVRleHQ6InJnYigyMywgNDIsIDU4KSIsY2lyY2xlOiJyZ2JhKDI1NSwgMjU1LCAyNTUsIDAuNCkiLHN1YnNjcmlwdGlvblRpbWVCb2FkZXJUb3A6InJnYmEoMjU1LCAyNTUsIDI1NSwgMC4yKSIsc3Vic2NyaXB0aW9uVGltZVRleHQ6InJnYmEoMjU1LCAyNTUsIDI1NSwgMC41KSJ9LHQubGlnaHRFZGl0b3JDb2xvdXJzPXtwcm9wZXJ0eToiIzMyOGM4YyIsY29tbWVudDoicmdiYSgwLCAwLCAwLCAwLjMpIixwdW5jdHVhdGlvbjoicmdiYSgyMyw0Miw1OCwuOCkiLGtleXdvcmQ6IiMzNjZiNmIiLGRlZjoicmdiKDU2LCAxODksIDE5MykiLHF1YWxpZmllcjoiIzFjOTJhOSIsYXR0cmlidXRlOiIjYjU2NTMxIixudW1iZXI6IiMxZjZlZDY7IixzdHJpbmc6IiNkNjQyOTIiLGJ1aWx0aW46IiNkNDc1MDkiLHN0cmluZzI6IiMwYjdmYzciLHZhcmlhYmxlOiJyZ2IoMjM2LCA5NSwgMTAzKSIsbWV0YToiI2IzMzA4NiIsYXRvbToicmdiKDI0NSwgMTYwLCAwKSIsd3M6InJnYmEoMjMsIDQyLCA1OCwgMC44KSIsc2VsZWN0aW9uOiIjZDFlOWZkIixjdXJzb3JDb2xvcjoicmdiYSgwLCAwLCAwLCAwLjQpIix0ZXh0OiJyZ2JhKDAsIDAsIDAsIDAuNykiLHRleHRJbmFjdGl2ZToicmdiYSgwLCAwLCAwLCAwLjMpIixiYWNrZ3JvdW5kOiIjZGJkZWUwIixzaWRlYmFyVG9wOiIjZWVlZmYwIixzaWRlYmFyOiIjZWVlZmYwIixzaWRlYmFyQm90dG9tOiIjZjZmN2Y3IixzaWRlYmFySXRlbUFjdGl2ZToiI2Y2ZjdmNyIsc2lkZWJhckl0ZW1TaWRlOiIjMjdhZTYwIixzaWRlYmFySXRlbVNlc3Npb25zOiIjZGJkZWUwIix0YWI6IiNlZWVmZjAiLHRhYkluYWN0aXZlOiIjZTdlYWVjIix0YWJUZXh0OiJyZ2JhKDIzLCA0MiwgNTgsIC44KSIsbmF2aWdhdGlvbkJhcjoiI2VlZWZmMCIsbmF2aWdhdGlvbkJhclRleHQ6InJnYmEoMjMsIDQyLCA1OCwgMC44KSIsZWRpdG9yQmFja2dyb3VuZDoiI2Y2ZjdmNyIscmVzdWx0QmFja2dyb3VuZDoiI2VlZWZmMCIsbGVmdERyYXdlckJhY2tncm91bmQ6IiNlOWVhZWEiLHJpZ2h0RHJhd2VyQmFja2dyb3VuZDoiI2U1ZTdlNyIsZHJhd2VyVGV4dDoicmdiYSgwLCAwLCAwLCAwLjcpIixkcmF3ZXJUZXh0SW5hY3RpdmU6InJnYmEoMCwgMCwgMCwgMC4zKSIsZXhlY3V0ZUJ1dHRvbjoicmdiKDExNSwgMTI3LCAxMzYpIixleGVjdXRlQnV0dG9uQm9yZGVyOiIjZWVlZmYwIixleGVjdXRlQnV0dG9uSG92ZXI6IiIsZXhlY3V0ZUJ1dHRvblN1YnNjcmlwdGlvbjoiI2YyNWM1NCIsZXhlY3V0ZUJ1dHRvblN1YnNjcmlwdGlvbkhvdmVyOiIjZjM2YzY1IixpY29uOiJyZ2IoMTk0LCAyMDAsIDIwMykiLGljb25Ib3ZlcjoicmdiYSgyMywgNDIsIDU4LCAwLjYpIixwb2xsaW5nSWNvbjoicmdiYSgxMzksIDE0OSwgMTU2LCAxKSIscG9sbGluZ0ljb25TaGFkb3c6InJnYmEoMTM5LCAxNDksIDE1NiwgMC40KSIsYnV0dG9uOiIjZDhkYmRlIixidXR0b25Ib3ZlcjoicmdiYSgyMCwgMzcsIDUxLCAwLjIpIixidXR0b25UZXh0OiJyZ2JhKDIzLCA0MiwgNTgsIDAuOCkiLGJ1dHRvbldvcmtzcGFjZToicmdiKDE4NSwgMTkxLCAxOTYpIixidXR0b25Xb3Jrc3BhY2VIb3ZlcjoicmdiKDE1NywgMTY2LCAxNzMpIixidXR0b25Xb3Jrc3BhY2VUZXh0OiJyZ2IoMjM4LCAyMzksIDI0MCkiLGNpcmNsZToicmdiYSgyMyw0Miw1OCwuNCkiLHN1YnNjcmlwdGlvblRpbWVCb2FkZXJUb3A6InJnYmEoMjMsIDQyLCA1OCwgMC4yKSIsc3Vic2NyaXB0aW9uVGltZVRleHQ6InJnYmEoMjMsIDQyLCA1OCwgMC41KSJ9LHQuc2l6ZXM9e3NtYWxsNjoiNnB4IixzbWFsbDEwOiIxMHB4IixzbWFsbDEyOiIxMnB4IixzbWFsbDE2OiIxNnB4IixtZWRpdW0yNToiMjVweCIsZm9udExpZ2h0OiIzMDAiLGZvbnRTZW1pQm9sZDoiNjAwIixmb250VGlueToiMTJweCIsZm9udFNtYWxsOiIxNHB4Iixmb250TWVkaXVtOiIyMHB4IixzbWFsbFJhZGl1czoiMnB4In0sdC5zaG9ydGhhbmRzPXt9LHQudGhlbWU9e21vZGU6ImRhcmsiLGNvbG91cnM6dC5kYXJrQ29sb3VycyxzaXplczp0LnNpemVzLHNob3J0aGFuZHM6dC5zaG9ydGhhbmRzLGVkaXRvckNvbG91cnM6dC5kYXJrRWRpdG9yQ29sb3VycyxzZXR0aW5nczpyLmRlZmF1bHRTZXR0aW5nc319LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oMCksaT1uKDE0KTt0LnRvSlM9ZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3ZhciBuPU9iamVjdC5lbnRyaWVzKHQpLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlW3RbMF1dPWkuaXNJbW11dGFibGUodFsxXSk/dFsxXS50b0pTKCk6dFsxXSxlfSx7fSk7cmV0dXJuIHIuY3JlYXRlRWxlbWVudChlLG4pfX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPW4oMjYyKX0sZnVuY3Rpb24oZSx0KXtlLmV4cG9ydHM9e0FhY3V0ZToiXHhjMSIsYWFjdXRlOiJceGUxIixBYnJldmU6Ilx1MDEwMiIsYWJyZXZlOiJcdTAxMDMiLGFjOiJcdTIyM2UiLGFjZDoiXHUyMjNmIixhY0U6Ilx1MjIzZVx1MDMzMyIsQWNpcmM6Ilx4YzIiLGFjaXJjOiJceGUyIixhY3V0ZToiXHhiNCIsQWN5OiJcdTA0MTAiLGFjeToiXHUwNDMwIixBRWxpZzoiXHhjNiIsYWVsaWc6Ilx4ZTYiLGFmOiJcdTIwNjEiLEFmcjoiXHVkODM1XHVkZDA0IixhZnI6Ilx1ZDgzNVx1ZGQxZSIsQWdyYXZlOiJceGMwIixhZ3JhdmU6Ilx4ZTAiLGFsZWZzeW06Ilx1MjEzNSIsYWxlcGg6Ilx1MjEzNSIsQWxwaGE6Ilx1MDM5MSIsYWxwaGE6Ilx1MDNiMSIsQW1hY3I6Ilx1MDEwMCIsYW1hY3I6Ilx1MDEwMSIsYW1hbGc6Ilx1MmEzZiIsYW1wOiImIixBTVA6IiYiLGFuZGFuZDoiXHUyYTU1IixBbmQ6Ilx1MmE1MyIsYW5kOiJcdTIyMjciLGFuZGQ6Ilx1MmE1YyIsYW5kc2xvcGU6Ilx1MmE1OCIsYW5kdjoiXHUyYTVhIixhbmc6Ilx1MjIyMCIsYW5nZToiXHUyOWE0IixhbmdsZToiXHUyMjIwIixhbmdtc2RhYToiXHUyOWE4Iixhbmdtc2RhYjoiXHUyOWE5Iixhbmdtc2RhYzoiXHUyOWFhIixhbmdtc2RhZDoiXHUyOWFiIixhbmdtc2RhZToiXHUyOWFjIixhbmdtc2RhZjoiXHUyOWFkIixhbmdtc2RhZzoiXHUyOWFlIixhbmdtc2RhaDoiXHUyOWFmIixhbmdtc2Q6Ilx1MjIyMSIsYW5ncnQ6Ilx1MjIxZiIsYW5ncnR2YjoiXHUyMmJlIixhbmdydHZiZDoiXHUyOTlkIixhbmdzcGg6Ilx1MjIyMiIsYW5nc3Q6Ilx4YzUiLGFuZ3phcnI6Ilx1MjM3YyIsQW9nb246Ilx1MDEwNCIsYW9nb246Ilx1MDEwNSIsQW9wZjoiXHVkODM1XHVkZDM4Iixhb3BmOiJcdWQ4MzVcdWRkNTIiLGFwYWNpcjoiXHUyYTZmIixhcDoiXHUyMjQ4IixhcEU6Ilx1MmE3MCIsYXBlOiJcdTIyNGEiLGFwaWQ6Ilx1MjI0YiIsYXBvczoiJyIsQXBwbHlGdW5jdGlvbjoiXHUyMDYxIixhcHByb3g6Ilx1MjI0OCIsYXBwcm94ZXE6Ilx1MjI0YSIsQXJpbmc6Ilx4YzUiLGFyaW5nOiJceGU1IixBc2NyOiJcdWQ4MzVcdWRjOWMiLGFzY3I6Ilx1ZDgzNVx1ZGNiNiIsQXNzaWduOiJcdTIyNTQiLGFzdDoiKiIsYXN5bXA6Ilx1MjI0OCIsYXN5bXBlcToiXHUyMjRkIixBdGlsZGU6Ilx4YzMiLGF0aWxkZToiXHhlMyIsQXVtbDoiXHhjNCIsYXVtbDoiXHhlNCIsYXdjb25pbnQ6Ilx1MjIzMyIsYXdpbnQ6Ilx1MmExMSIsYmFja2Nvbmc6Ilx1MjI0YyIsYmFja2Vwc2lsb246Ilx1MDNmNiIsYmFja3ByaW1lOiJcdTIwMzUiLGJhY2tzaW06Ilx1MjIzZCIsYmFja3NpbWVxOiJcdTIyY2QiLEJhY2tzbGFzaDoiXHUyMjE2IixCYXJ2OiJcdTJhZTciLGJhcnZlZToiXHUyMmJkIixiYXJ3ZWQ6Ilx1MjMwNSIsQmFyd2VkOiJcdTIzMDYiLGJhcndlZGdlOiJcdTIzMDUiLGJicms6Ilx1MjNiNSIsYmJya3Ricms6Ilx1MjNiNiIsYmNvbmc6Ilx1MjI0YyIsQmN5OiJcdTA0MTEiLGJjeToiXHUwNDMxIixiZHF1bzoiXHUyMDFlIixiZWNhdXM6Ilx1MjIzNSIsYmVjYXVzZToiXHUyMjM1IixCZWNhdXNlOiJcdTIyMzUiLGJlbXB0eXY6Ilx1MjliMCIsYmVwc2k6Ilx1MDNmNiIsYmVybm91OiJcdTIxMmMiLEJlcm5vdWxsaXM6Ilx1MjEyYyIsQmV0YToiXHUwMzkyIixiZXRhOiJcdTAzYjIiLGJldGg6Ilx1MjEzNiIsYmV0d2VlbjoiXHUyMjZjIixCZnI6Ilx1ZDgzNVx1ZGQwNSIsYmZyOiJcdWQ4MzVcdWRkMWYiLGJpZ2NhcDoiXHUyMmMyIixiaWdjaXJjOiJcdTI1ZWYiLGJpZ2N1cDoiXHUyMmMzIixiaWdvZG90OiJcdTJhMDAiLGJpZ29wbHVzOiJcdTJhMDEiLGJpZ290aW1lczoiXHUyYTAyIixiaWdzcWN1cDoiXHUyYTA2IixiaWdzdGFyOiJcdTI2MDUiLGJpZ3RyaWFuZ2xlZG93bjoiXHUyNWJkIixiaWd0cmlhbmdsZXVwOiJcdTI1YjMiLGJpZ3VwbHVzOiJcdTJhMDQiLGJpZ3ZlZToiXHUyMmMxIixiaWd3ZWRnZToiXHUyMmMwIixia2Fyb3c6Ilx1MjkwZCIsYmxhY2tsb3plbmdlOiJcdTI5ZWIiLGJsYWNrc3F1YXJlOiJcdTI1YWEiLGJsYWNrdHJpYW5nbGU6Ilx1MjViNCIsYmxhY2t0cmlhbmdsZWRvd246Ilx1MjViZSIsYmxhY2t0cmlhbmdsZWxlZnQ6Ilx1MjVjMiIsYmxhY2t0cmlhbmdsZXJpZ2h0OiJcdTI1YjgiLGJsYW5rOiJcdTI0MjMiLGJsazEyOiJcdTI1OTIiLGJsazE0OiJcdTI1OTEiLGJsazM0OiJcdTI1OTMiLGJsb2NrOiJcdTI1ODgiLGJuZToiPVx1MjBlNSIsYm5lcXVpdjoiXHUyMjYxXHUyMGU1IixiTm90OiJcdTJhZWQiLGJub3Q6Ilx1MjMxMCIsQm9wZjoiXHVkODM1XHVkZDM5Iixib3BmOiJcdWQ4MzVcdWRkNTMiLGJvdDoiXHUyMmE1Iixib3R0b206Ilx1MjJhNSIsYm93dGllOiJcdTIyYzgiLGJveGJveDoiXHUyOWM5Iixib3hkbDoiXHUyNTEwIixib3hkTDoiXHUyNTU1Iixib3hEbDoiXHUyNTU2Iixib3hETDoiXHUyNTU3Iixib3hkcjoiXHUyNTBjIixib3hkUjoiXHUyNTUyIixib3hEcjoiXHUyNTUzIixib3hEUjoiXHUyNTU0Iixib3hoOiJcdTI1MDAiLGJveEg6Ilx1MjU1MCIsYm94aGQ6Ilx1MjUyYyIsYm94SGQ6Ilx1MjU2NCIsYm94aEQ6Ilx1MjU2NSIsYm94SEQ6Ilx1MjU2NiIsYm94aHU6Ilx1MjUzNCIsYm94SHU6Ilx1MjU2NyIsYm94aFU6Ilx1MjU2OCIsYm94SFU6Ilx1MjU2OSIsYm94bWludXM6Ilx1MjI5ZiIsYm94cGx1czoiXHUyMjllIixib3h0aW1lczoiXHUyMmEwIixib3h1bDoiXHUyNTE4Iixib3h1TDoiXHUyNTViIixib3hVbDoiXHUyNTVjIixib3hVTDoiXHUyNTVkIixib3h1cjoiXHUyNTE0Iixib3h1UjoiXHUyNTU4Iixib3hVcjoiXHUyNTU5Iixib3hVUjoiXHUyNTVhIixib3h2OiJcdTI1MDIiLGJveFY6Ilx1MjU1MSIsYm94dmg6Ilx1MjUzYyIsYm94dkg6Ilx1MjU2YSIsYm94Vmg6Ilx1MjU2YiIsYm94Vkg6Ilx1MjU2YyIsYm94dmw6Ilx1MjUyNCIsYm94dkw6Ilx1MjU2MSIsYm94Vmw6Ilx1MjU2MiIsYm94Vkw6Ilx1MjU2MyIsYm94dnI6Ilx1MjUxYyIsYm94dlI6Ilx1MjU1ZSIsYm94VnI6Ilx1MjU1ZiIsYm94VlI6Ilx1MjU2MCIsYnByaW1lOiJcdTIwMzUiLGJyZXZlOiJcdTAyZDgiLEJyZXZlOiJcdTAyZDgiLGJydmJhcjoiXHhhNiIsYnNjcjoiXHVkODM1XHVkY2I3IixCc2NyOiJcdTIxMmMiLGJzZW1pOiJcdTIwNGYiLGJzaW06Ilx1MjIzZCIsYnNpbWU6Ilx1MjJjZCIsYnNvbGI6Ilx1MjljNSIsYnNvbDoiXFwiLGJzb2xoc3ViOiJcdTI3YzgiLGJ1bGw6Ilx1MjAyMiIsYnVsbGV0OiJcdTIwMjIiLGJ1bXA6Ilx1MjI0ZSIsYnVtcEU6Ilx1MmFhZSIsYnVtcGU6Ilx1MjI0ZiIsQnVtcGVxOiJcdTIyNGUiLGJ1bXBlcToiXHUyMjRmIixDYWN1dGU6Ilx1MDEwNiIsY2FjdXRlOiJcdTAxMDciLGNhcGFuZDoiXHUyYTQ0IixjYXBicmN1cDoiXHUyYTQ5IixjYXBjYXA6Ilx1MmE0YiIsY2FwOiJcdTIyMjkiLENhcDoiXHUyMmQyIixjYXBjdXA6Ilx1MmE0NyIsY2FwZG90OiJcdTJhNDAiLENhcGl0YWxEaWZmZXJlbnRpYWxEOiJcdTIxNDUiLGNhcHM6Ilx1MjIyOVx1ZmUwMCIsY2FyZXQ6Ilx1MjA0MSIsY2Fyb246Ilx1MDJjNyIsQ2F5bGV5czoiXHUyMTJkIixjY2FwczoiXHUyYTRkIixDY2Fyb246Ilx1MDEwYyIsY2Nhcm9uOiJcdTAxMGQiLENjZWRpbDoiXHhjNyIsY2NlZGlsOiJceGU3IixDY2lyYzoiXHUwMTA4IixjY2lyYzoiXHUwMTA5IixDY29uaW50OiJcdTIyMzAiLGNjdXBzOiJcdTJhNGMiLGNjdXBzc206Ilx1MmE1MCIsQ2RvdDoiXHUwMTBhIixjZG90OiJcdTAxMGIiLGNlZGlsOiJceGI4IixDZWRpbGxhOiJceGI4IixjZW1wdHl2OiJcdTI5YjIiLGNlbnQ6Ilx4YTIiLGNlbnRlcmRvdDoiXHhiNyIsQ2VudGVyRG90OiJceGI3IixjZnI6Ilx1ZDgzNVx1ZGQyMCIsQ2ZyOiJcdTIxMmQiLENIY3k6Ilx1MDQyNyIsY2hjeToiXHUwNDQ3IixjaGVjazoiXHUyNzEzIixjaGVja21hcms6Ilx1MjcxMyIsQ2hpOiJcdTAzYTciLGNoaToiXHUwM2M3IixjaXJjOiJcdTAyYzYiLGNpcmNlcToiXHUyMjU3IixjaXJjbGVhcnJvd2xlZnQ6Ilx1MjFiYSIsY2lyY2xlYXJyb3dyaWdodDoiXHUyMWJiIixjaXJjbGVkYXN0OiJcdTIyOWIiLGNpcmNsZWRjaXJjOiJcdTIyOWEiLGNpcmNsZWRkYXNoOiJcdTIyOWQiLENpcmNsZURvdDoiXHUyMjk5IixjaXJjbGVkUjoiXHhhZSIsY2lyY2xlZFM6Ilx1MjRjOCIsQ2lyY2xlTWludXM6Ilx1MjI5NiIsQ2lyY2xlUGx1czoiXHUyMjk1IixDaXJjbGVUaW1lczoiXHUyMjk3IixjaXI6Ilx1MjVjYiIsY2lyRToiXHUyOWMzIixjaXJlOiJcdTIyNTciLGNpcmZuaW50OiJcdTJhMTAiLGNpcm1pZDoiXHUyYWVmIixjaXJzY2lyOiJcdTI5YzIiLENsb2Nrd2lzZUNvbnRvdXJJbnRlZ3JhbDoiXHUyMjMyIixDbG9zZUN1cmx5RG91YmxlUXVvdGU6Ilx1MjAxZCIsQ2xvc2VDdXJseVF1b3RlOiJcdTIwMTkiLGNsdWJzOiJcdTI2NjMiLGNsdWJzdWl0OiJcdTI2NjMiLGNvbG9uOiI6IixDb2xvbjoiXHUyMjM3IixDb2xvbmU6Ilx1MmE3NCIsY29sb25lOiJcdTIyNTQiLGNvbG9uZXE6Ilx1MjI1NCIsY29tbWE6IiwiLGNvbW1hdDoiQCIsY29tcDoiXHUyMjAxIixjb21wZm46Ilx1MjIxOCIsY29tcGxlbWVudDoiXHUyMjAxIixjb21wbGV4ZXM6Ilx1MjEwMiIsY29uZzoiXHUyMjQ1Iixjb25nZG90OiJcdTJhNmQiLENvbmdydWVudDoiXHUyMjYxIixjb25pbnQ6Ilx1MjIyZSIsQ29uaW50OiJcdTIyMmYiLENvbnRvdXJJbnRlZ3JhbDoiXHUyMjJlIixjb3BmOiJcdWQ4MzVcdWRkNTQiLENvcGY6Ilx1MjEwMiIsY29wcm9kOiJcdTIyMTAiLENvcHJvZHVjdDoiXHUyMjEwIixjb3B5OiJceGE5IixDT1BZOiJceGE5Iixjb3B5c3I6Ilx1MjExNyIsQ291bnRlckNsb2Nrd2lzZUNvbnRvdXJJbnRlZ3JhbDoiXHUyMjMzIixjcmFycjoiXHUyMWI1Iixjcm9zczoiXHUyNzE3IixDcm9zczoiXHUyYTJmIixDc2NyOiJcdWQ4MzVcdWRjOWUiLGNzY3I6Ilx1ZDgzNVx1ZGNiOCIsY3N1YjoiXHUyYWNmIixjc3ViZToiXHUyYWQxIixjc3VwOiJcdTJhZDAiLGNzdXBlOiJcdTJhZDIiLGN0ZG90OiJcdTIyZWYiLGN1ZGFycmw6Ilx1MjkzOCIsY3VkYXJycjoiXHUyOTM1IixjdWVwcjoiXHUyMmRlIixjdWVzYzoiXHUyMmRmIixjdWxhcnI6Ilx1MjFiNiIsY3VsYXJycDoiXHUyOTNkIixjdXBicmNhcDoiXHUyYTQ4IixjdXBjYXA6Ilx1MmE0NiIsQ3VwQ2FwOiJcdTIyNGQiLGN1cDoiXHUyMjJhIixDdXA6Ilx1MjJkMyIsY3VwY3VwOiJcdTJhNGEiLGN1cGRvdDoiXHUyMjhkIixjdXBvcjoiXHUyYTQ1IixjdXBzOiJcdTIyMmFcdWZlMDAiLGN1cmFycjoiXHUyMWI3IixjdXJhcnJtOiJcdTI5M2MiLGN1cmx5ZXFwcmVjOiJcdTIyZGUiLGN1cmx5ZXFzdWNjOiJcdTIyZGYiLGN1cmx5dmVlOiJcdTIyY2UiLGN1cmx5d2VkZ2U6Ilx1MjJjZiIsY3VycmVuOiJceGE0IixjdXJ2ZWFycm93bGVmdDoiXHUyMWI2IixjdXJ2ZWFycm93cmlnaHQ6Ilx1MjFiNyIsY3V2ZWU6Ilx1MjJjZSIsY3V3ZWQ6Ilx1MjJjZiIsY3djb25pbnQ6Ilx1MjIzMiIsY3dpbnQ6Ilx1MjIzMSIsY3lsY3R5OiJcdTIzMmQiLGRhZ2dlcjoiXHUyMDIwIixEYWdnZXI6Ilx1MjAyMSIsZGFsZXRoOiJcdTIxMzgiLGRhcnI6Ilx1MjE5MyIsRGFycjoiXHUyMWExIixkQXJyOiJcdTIxZDMiLGRhc2g6Ilx1MjAxMCIsRGFzaHY6Ilx1MmFlNCIsZGFzaHY6Ilx1MjJhMyIsZGJrYXJvdzoiXHUyOTBmIixkYmxhYzoiXHUwMmRkIixEY2Fyb246Ilx1MDEwZSIsZGNhcm9uOiJcdTAxMGYiLERjeToiXHUwNDE0IixkY3k6Ilx1MDQzNCIsZGRhZ2dlcjoiXHUyMDIxIixkZGFycjoiXHUyMWNhIixERDoiXHUyMTQ1IixkZDoiXHUyMTQ2IixERG90cmFoZDoiXHUyOTExIixkZG90c2VxOiJcdTJhNzciLGRlZzoiXHhiMCIsRGVsOiJcdTIyMDciLERlbHRhOiJcdTAzOTQiLGRlbHRhOiJcdTAzYjQiLGRlbXB0eXY6Ilx1MjliMSIsZGZpc2h0OiJcdTI5N2YiLERmcjoiXHVkODM1XHVkZDA3IixkZnI6Ilx1ZDgzNVx1ZGQyMSIsZEhhcjoiXHUyOTY1IixkaGFybDoiXHUyMWMzIixkaGFycjoiXHUyMWMyIixEaWFjcml0aWNhbEFjdXRlOiJceGI0IixEaWFjcml0aWNhbERvdDoiXHUwMmQ5IixEaWFjcml0aWNhbERvdWJsZUFjdXRlOiJcdTAyZGQiLERpYWNyaXRpY2FsR3JhdmU6ImAiLERpYWNyaXRpY2FsVGlsZGU6Ilx1MDJkYyIsZGlhbToiXHUyMmM0IixkaWFtb25kOiJcdTIyYzQiLERpYW1vbmQ6Ilx1MjJjNCIsZGlhbW9uZHN1aXQ6Ilx1MjY2NiIsZGlhbXM6Ilx1MjY2NiIsZGllOiJceGE4IixEaWZmZXJlbnRpYWxEOiJcdTIxNDYiLGRpZ2FtbWE6Ilx1MDNkZCIsZGlzaW46Ilx1MjJmMiIsZGl2OiJceGY3IixkaXZpZGU6Ilx4ZjciLGRpdmlkZW9udGltZXM6Ilx1MjJjNyIsZGl2b254OiJcdTIyYzciLERKY3k6Ilx1MDQwMiIsZGpjeToiXHUwNDUyIixkbGNvcm46Ilx1MjMxZSIsZGxjcm9wOiJcdTIzMGQiLGRvbGxhcjoiJCIsRG9wZjoiXHVkODM1XHVkZDNiIixkb3BmOiJcdWQ4MzVcdWRkNTUiLERvdDoiXHhhOCIsZG90OiJcdTAyZDkiLERvdERvdDoiXHUyMGRjIixkb3RlcToiXHUyMjUwIixkb3RlcWRvdDoiXHUyMjUxIixEb3RFcXVhbDoiXHUyMjUwIixkb3RtaW51czoiXHUyMjM4Iixkb3RwbHVzOiJcdTIyMTQiLGRvdHNxdWFyZToiXHUyMmExIixkb3VibGViYXJ3ZWRnZToiXHUyMzA2IixEb3VibGVDb250b3VySW50ZWdyYWw6Ilx1MjIyZiIsRG91YmxlRG90OiJceGE4IixEb3VibGVEb3duQXJyb3c6Ilx1MjFkMyIsRG91YmxlTGVmdEFycm93OiJcdTIxZDAiLERvdWJsZUxlZnRSaWdodEFycm93OiJcdTIxZDQiLERvdWJsZUxlZnRUZWU6Ilx1MmFlNCIsRG91YmxlTG9uZ0xlZnRBcnJvdzoiXHUyN2Y4IixEb3VibGVMb25nTGVmdFJpZ2h0QXJyb3c6Ilx1MjdmYSIsRG91YmxlTG9uZ1JpZ2h0QXJyb3c6Ilx1MjdmOSIsRG91YmxlUmlnaHRBcnJvdzoiXHUyMWQyIixEb3VibGVSaWdodFRlZToiXHUyMmE4IixEb3VibGVVcEFycm93OiJcdTIxZDEiLERvdWJsZVVwRG93bkFycm93OiJcdTIxZDUiLERvdWJsZVZlcnRpY2FsQmFyOiJcdTIyMjUiLERvd25BcnJvd0JhcjoiXHUyOTEzIixkb3duYXJyb3c6Ilx1MjE5MyIsRG93bkFycm93OiJcdTIxOTMiLERvd25hcnJvdzoiXHUyMWQzIixEb3duQXJyb3dVcEFycm93OiJcdTIxZjUiLERvd25CcmV2ZToiXHUwMzExIixkb3duZG93bmFycm93czoiXHUyMWNhIixkb3duaGFycG9vbmxlZnQ6Ilx1MjFjMyIsZG93bmhhcnBvb25yaWdodDoiXHUyMWMyIixEb3duTGVmdFJpZ2h0VmVjdG9yOiJcdTI5NTAiLERvd25MZWZ0VGVlVmVjdG9yOiJcdTI5NWUiLERvd25MZWZ0VmVjdG9yQmFyOiJcdTI5NTYiLERvd25MZWZ0VmVjdG9yOiJcdTIxYmQiLERvd25SaWdodFRlZVZlY3RvcjoiXHUyOTVmIixEb3duUmlnaHRWZWN0b3JCYXI6Ilx1Mjk1NyIsRG93blJpZ2h0VmVjdG9yOiJcdTIxYzEiLERvd25UZWVBcnJvdzoiXHUyMWE3IixEb3duVGVlOiJcdTIyYTQiLGRyYmthcm93OiJcdTI5MTAiLGRyY29ybjoiXHUyMzFmIixkcmNyb3A6Ilx1MjMwYyIsRHNjcjoiXHVkODM1XHVkYzlmIixkc2NyOiJcdWQ4MzVcdWRjYjkiLERTY3k6Ilx1MDQwNSIsZHNjeToiXHUwNDU1Iixkc29sOiJcdTI5ZjYiLERzdHJvazoiXHUwMTEwIixkc3Ryb2s6Ilx1MDExMSIsZHRkb3Q6Ilx1MjJmMSIsZHRyaToiXHUyNWJmIixkdHJpZjoiXHUyNWJlIixkdWFycjoiXHUyMWY1IixkdWhhcjoiXHUyOTZmIixkd2FuZ2xlOiJcdTI5YTYiLERaY3k6Ilx1MDQwZiIsZHpjeToiXHUwNDVmIixkemlncmFycjoiXHUyN2ZmIixFYWN1dGU6Ilx4YzkiLGVhY3V0ZToiXHhlOSIsZWFzdGVyOiJcdTJhNmUiLEVjYXJvbjoiXHUwMTFhIixlY2Fyb246Ilx1MDExYiIsRWNpcmM6Ilx4Y2EiLGVjaXJjOiJceGVhIixlY2lyOiJcdTIyNTYiLGVjb2xvbjoiXHUyMjU1IixFY3k6Ilx1MDQyZCIsZWN5OiJcdTA0NGQiLGVERG90OiJcdTJhNzciLEVkb3Q6Ilx1MDExNiIsZWRvdDoiXHUwMTE3IixlRG90OiJcdTIyNTEiLGVlOiJcdTIxNDciLGVmRG90OiJcdTIyNTIiLEVmcjoiXHVkODM1XHVkZDA4IixlZnI6Ilx1ZDgzNVx1ZGQyMiIsZWc6Ilx1MmE5YSIsRWdyYXZlOiJceGM4IixlZ3JhdmU6Ilx4ZTgiLGVnczoiXHUyYTk2IixlZ3Nkb3Q6Ilx1MmE5OCIsZWw6Ilx1MmE5OSIsRWxlbWVudDoiXHUyMjA4IixlbGludGVyczoiXHUyM2U3IixlbGw6Ilx1MjExMyIsZWxzOiJcdTJhOTUiLGVsc2RvdDoiXHUyYTk3IixFbWFjcjoiXHUwMTEyIixlbWFjcjoiXHUwMTEzIixlbXB0eToiXHUyMjA1IixlbXB0eXNldDoiXHUyMjA1IixFbXB0eVNtYWxsU3F1YXJlOiJcdTI1ZmIiLGVtcHR5djoiXHUyMjA1IixFbXB0eVZlcnlTbWFsbFNxdWFyZToiXHUyNWFiIixlbXNwMTM6Ilx1MjAwNCIsZW1zcDE0OiJcdTIwMDUiLGVtc3A6Ilx1MjAwMyIsRU5HOiJcdTAxNGEiLGVuZzoiXHUwMTRiIixlbnNwOiJcdTIwMDIiLEVvZ29uOiJcdTAxMTgiLGVvZ29uOiJcdTAxMTkiLEVvcGY6Ilx1ZDgzNVx1ZGQzYyIsZW9wZjoiXHVkODM1XHVkZDU2IixlcGFyOiJcdTIyZDUiLGVwYXJzbDoiXHUyOWUzIixlcGx1czoiXHUyYTcxIixlcHNpOiJcdTAzYjUiLEVwc2lsb246Ilx1MDM5NSIsZXBzaWxvbjoiXHUwM2I1IixlcHNpdjoiXHUwM2Y1IixlcWNpcmM6Ilx1MjI1NiIsZXFjb2xvbjoiXHUyMjU1IixlcXNpbToiXHUyMjQyIixlcXNsYW50Z3RyOiJcdTJhOTYiLGVxc2xhbnRsZXNzOiJcdTJhOTUiLEVxdWFsOiJcdTJhNzUiLGVxdWFsczoiPSIsRXF1YWxUaWxkZToiXHUyMjQyIixlcXVlc3Q6Ilx1MjI1ZiIsRXF1aWxpYnJpdW06Ilx1MjFjYyIsZXF1aXY6Ilx1MjI2MSIsZXF1aXZERDoiXHUyYTc4IixlcXZwYXJzbDoiXHUyOWU1IixlcmFycjoiXHUyOTcxIixlckRvdDoiXHUyMjUzIixlc2NyOiJcdTIxMmYiLEVzY3I6Ilx1MjEzMCIsZXNkb3Q6Ilx1MjI1MCIsRXNpbToiXHUyYTczIixlc2ltOiJcdTIyNDIiLEV0YToiXHUwMzk3IixldGE6Ilx1MDNiNyIsRVRIOiJceGQwIixldGg6Ilx4ZjAiLEV1bWw6Ilx4Y2IiLGV1bWw6Ilx4ZWIiLGV1cm86Ilx1MjBhYyIsZXhjbDoiISIsZXhpc3Q6Ilx1MjIwMyIsRXhpc3RzOiJcdTIyMDMiLGV4cGVjdGF0aW9uOiJcdTIxMzAiLGV4cG9uZW50aWFsZToiXHUyMTQ3IixFeHBvbmVudGlhbEU6Ilx1MjE0NyIsZmFsbGluZ2RvdHNlcToiXHUyMjUyIixGY3k6Ilx1MDQyNCIsZmN5OiJcdTA0NDQiLGZlbWFsZToiXHUyNjQwIixmZmlsaWc6Ilx1ZmIwMyIsZmZsaWc6Ilx1ZmIwMCIsZmZsbGlnOiJcdWZiMDQiLEZmcjoiXHVkODM1XHVkZDA5IixmZnI6Ilx1ZDgzNVx1ZGQyMyIsZmlsaWc6Ilx1ZmIwMSIsRmlsbGVkU21hbGxTcXVhcmU6Ilx1MjVmYyIsRmlsbGVkVmVyeVNtYWxsU3F1YXJlOiJcdTI1YWEiLGZqbGlnOiJmaiIsZmxhdDoiXHUyNjZkIixmbGxpZzoiXHVmYjAyIixmbHRuczoiXHUyNWIxIixmbm9mOiJcdTAxOTIiLEZvcGY6Ilx1ZDgzNVx1ZGQzZCIsZm9wZjoiXHVkODM1XHVkZDU3Iixmb3JhbGw6Ilx1MjIwMCIsRm9yQWxsOiJcdTIyMDAiLGZvcms6Ilx1MjJkNCIsZm9ya3Y6Ilx1MmFkOSIsRm91cmllcnRyZjoiXHUyMTMxIixmcGFydGludDoiXHUyYTBkIixmcmFjMTI6Ilx4YmQiLGZyYWMxMzoiXHUyMTUzIixmcmFjMTQ6Ilx4YmMiLGZyYWMxNToiXHUyMTU1IixmcmFjMTY6Ilx1MjE1OSIsZnJhYzE4OiJcdTIxNWIiLGZyYWMyMzoiXHUyMTU0IixmcmFjMjU6Ilx1MjE1NiIsZnJhYzM0OiJceGJlIixmcmFjMzU6Ilx1MjE1NyIsZnJhYzM4OiJcdTIxNWMiLGZyYWM0NToiXHUyMTU4IixmcmFjNTY6Ilx1MjE1YSIsZnJhYzU4OiJcdTIxNWQiLGZyYWM3ODoiXHUyMTVlIixmcmFzbDoiXHUyMDQ0Iixmcm93bjoiXHUyMzIyIixmc2NyOiJcdWQ4MzVcdWRjYmIiLEZzY3I6Ilx1MjEzMSIsZ2FjdXRlOiJcdTAxZjUiLEdhbW1hOiJcdTAzOTMiLGdhbW1hOiJcdTAzYjMiLEdhbW1hZDoiXHUwM2RjIixnYW1tYWQ6Ilx1MDNkZCIsZ2FwOiJcdTJhODYiLEdicmV2ZToiXHUwMTFlIixnYnJldmU6Ilx1MDExZiIsR2NlZGlsOiJcdTAxMjIiLEdjaXJjOiJcdTAxMWMiLGdjaXJjOiJcdTAxMWQiLEdjeToiXHUwNDEzIixnY3k6Ilx1MDQzMyIsR2RvdDoiXHUwMTIwIixnZG90OiJcdTAxMjEiLGdlOiJcdTIyNjUiLGdFOiJcdTIyNjciLGdFbDoiXHUyYThjIixnZWw6Ilx1MjJkYiIsZ2VxOiJcdTIyNjUiLGdlcXE6Ilx1MjI2NyIsZ2Vxc2xhbnQ6Ilx1MmE3ZSIsZ2VzY2M6Ilx1MmFhOSIsZ2VzOiJcdTJhN2UiLGdlc2RvdDoiXHUyYTgwIixnZXNkb3RvOiJcdTJhODIiLGdlc2RvdG9sOiJcdTJhODQiLGdlc2w6Ilx1MjJkYlx1ZmUwMCIsZ2VzbGVzOiJcdTJhOTQiLEdmcjoiXHVkODM1XHVkZDBhIixnZnI6Ilx1ZDgzNVx1ZGQyNCIsZ2c6Ilx1MjI2YiIsR2c6Ilx1MjJkOSIsZ2dnOiJcdTIyZDkiLGdpbWVsOiJcdTIxMzciLEdKY3k6Ilx1MDQwMyIsZ2pjeToiXHUwNDUzIixnbGE6Ilx1MmFhNSIsZ2w6Ilx1MjI3NyIsZ2xFOiJcdTJhOTIiLGdsajoiXHUyYWE0IixnbmFwOiJcdTJhOGEiLGduYXBwcm94OiJcdTJhOGEiLGduZToiXHUyYTg4IixnbkU6Ilx1MjI2OSIsZ25lcToiXHUyYTg4IixnbmVxcToiXHUyMjY5IixnbnNpbToiXHUyMmU3IixHb3BmOiJcdWQ4MzVcdWRkM2UiLGdvcGY6Ilx1ZDgzNVx1ZGQ1OCIsZ3JhdmU6ImAiLEdyZWF0ZXJFcXVhbDoiXHUyMjY1IixHcmVhdGVyRXF1YWxMZXNzOiJcdTIyZGIiLEdyZWF0ZXJGdWxsRXF1YWw6Ilx1MjI2NyIsR3JlYXRlckdyZWF0ZXI6Ilx1MmFhMiIsR3JlYXRlckxlc3M6Ilx1MjI3NyIsR3JlYXRlclNsYW50RXF1YWw6Ilx1MmE3ZSIsR3JlYXRlclRpbGRlOiJcdTIyNzMiLEdzY3I6Ilx1ZDgzNVx1ZGNhMiIsZ3NjcjoiXHUyMTBhIixnc2ltOiJcdTIyNzMiLGdzaW1lOiJcdTJhOGUiLGdzaW1sOiJcdTJhOTAiLGd0Y2M6Ilx1MmFhNyIsZ3RjaXI6Ilx1MmE3YSIsZ3Q6Ij4iLEdUOiI+IixHdDoiXHUyMjZiIixndGRvdDoiXHUyMmQ3IixndGxQYXI6Ilx1Mjk5NSIsZ3RxdWVzdDoiXHUyYTdjIixndHJhcHByb3g6Ilx1MmE4NiIsZ3RyYXJyOiJcdTI5NzgiLGd0cmRvdDoiXHUyMmQ3IixndHJlcWxlc3M6Ilx1MjJkYiIsZ3RyZXFxbGVzczoiXHUyYThjIixndHJsZXNzOiJcdTIyNzciLGd0cnNpbToiXHUyMjczIixndmVydG5lcXE6Ilx1MjI2OVx1ZmUwMCIsZ3ZuRToiXHUyMjY5XHVmZTAwIixIYWNlazoiXHUwMmM3IixoYWlyc3A6Ilx1MjAwYSIsaGFsZjoiXHhiZCIsaGFtaWx0OiJcdTIxMGIiLEhBUkRjeToiXHUwNDJhIixoYXJkY3k6Ilx1MDQ0YSIsaGFycmNpcjoiXHUyOTQ4IixoYXJyOiJcdTIxOTQiLGhBcnI6Ilx1MjFkNCIsaGFycnc6Ilx1MjFhZCIsSGF0OiJeIixoYmFyOiJcdTIxMGYiLEhjaXJjOiJcdTAxMjQiLGhjaXJjOiJcdTAxMjUiLGhlYXJ0czoiXHUyNjY1IixoZWFydHN1aXQ6Ilx1MjY2NSIsaGVsbGlwOiJcdTIwMjYiLGhlcmNvbjoiXHUyMmI5IixoZnI6Ilx1ZDgzNVx1ZGQyNSIsSGZyOiJcdTIxMGMiLEhpbGJlcnRTcGFjZToiXHUyMTBiIixoa3NlYXJvdzoiXHUyOTI1Iixoa3N3YXJvdzoiXHUyOTI2Iixob2FycjoiXHUyMWZmIixob210aHQ6Ilx1MjIzYiIsaG9va2xlZnRhcnJvdzoiXHUyMWE5Iixob29rcmlnaHRhcnJvdzoiXHUyMWFhIixob3BmOiJcdWQ4MzVcdWRkNTkiLEhvcGY6Ilx1MjEwZCIsaG9yYmFyOiJcdTIwMTUiLEhvcml6b250YWxMaW5lOiJcdTI1MDAiLGhzY3I6Ilx1ZDgzNVx1ZGNiZCIsSHNjcjoiXHUyMTBiIixoc2xhc2g6Ilx1MjEwZiIsSHN0cm9rOiJcdTAxMjYiLGhzdHJvazoiXHUwMTI3IixIdW1wRG93bkh1bXA6Ilx1MjI0ZSIsSHVtcEVxdWFsOiJcdTIyNGYiLGh5YnVsbDoiXHUyMDQzIixoeXBoZW46Ilx1MjAxMCIsSWFjdXRlOiJceGNkIixpYWN1dGU6Ilx4ZWQiLGljOiJcdTIwNjMiLEljaXJjOiJceGNlIixpY2lyYzoiXHhlZSIsSWN5OiJcdTA0MTgiLGljeToiXHUwNDM4IixJZG90OiJcdTAxMzAiLElFY3k6Ilx1MDQxNSIsaWVjeToiXHUwNDM1IixpZXhjbDoiXHhhMSIsaWZmOiJcdTIxZDQiLGlmcjoiXHVkODM1XHVkZDI2IixJZnI6Ilx1MjExMSIsSWdyYXZlOiJceGNjIixpZ3JhdmU6Ilx4ZWMiLGlpOiJcdTIxNDgiLGlpaWludDoiXHUyYTBjIixpaWludDoiXHUyMjJkIixpaW5maW46Ilx1MjlkYyIsaWlvdGE6Ilx1MjEyOSIsSUpsaWc6Ilx1MDEzMiIsaWpsaWc6Ilx1MDEzMyIsSW1hY3I6Ilx1MDEyYSIsaW1hY3I6Ilx1MDEyYiIsaW1hZ2U6Ilx1MjExMSIsSW1hZ2luYXJ5SToiXHUyMTQ4IixpbWFnbGluZToiXHUyMTEwIixpbWFncGFydDoiXHUyMTExIixpbWF0aDoiXHUwMTMxIixJbToiXHUyMTExIixpbW9mOiJcdTIyYjciLGltcGVkOiJcdTAxYjUiLEltcGxpZXM6Ilx1MjFkMiIsaW5jYXJlOiJcdTIxMDUiLGluOiJcdTIyMDgiLGluZmluOiJcdTIyMWUiLGluZmludGllOiJcdTI5ZGQiLGlub2RvdDoiXHUwMTMxIixpbnRjYWw6Ilx1MjJiYSIsaW50OiJcdTIyMmIiLEludDoiXHUyMjJjIixpbnRlZ2VyczoiXHUyMTI0IixJbnRlZ3JhbDoiXHUyMjJiIixpbnRlcmNhbDoiXHUyMmJhIixJbnRlcnNlY3Rpb246Ilx1MjJjMiIsaW50bGFyaGs6Ilx1MmExNyIsaW50cHJvZDoiXHUyYTNjIixJbnZpc2libGVDb21tYToiXHUyMDYzIixJbnZpc2libGVUaW1lczoiXHUyMDYyIixJT2N5OiJcdTA0MDEiLGlvY3k6Ilx1MDQ1MSIsSW9nb246Ilx1MDEyZSIsaW9nb246Ilx1MDEyZiIsSW9wZjoiXHVkODM1XHVkZDQwIixpb3BmOiJcdWQ4MzVcdWRkNWEiLElvdGE6Ilx1MDM5OSIsaW90YToiXHUwM2I5IixpcHJvZDoiXHUyYTNjIixpcXVlc3Q6Ilx4YmYiLGlzY3I6Ilx1ZDgzNVx1ZGNiZSIsSXNjcjoiXHUyMTEwIixpc2luOiJcdTIyMDgiLGlzaW5kb3Q6Ilx1MjJmNSIsaXNpbkU6Ilx1MjJmOSIsaXNpbnM6Ilx1MjJmNCIsaXNpbnN2OiJcdTIyZjMiLGlzaW52OiJcdTIyMDgiLGl0OiJcdTIwNjIiLEl0aWxkZToiXHUwMTI4IixpdGlsZGU6Ilx1MDEyOSIsSXVrY3k6Ilx1MDQwNiIsaXVrY3k6Ilx1MDQ1NiIsSXVtbDoiXHhjZiIsaXVtbDoiXHhlZiIsSmNpcmM6Ilx1MDEzNCIsamNpcmM6Ilx1MDEzNSIsSmN5OiJcdTA0MTkiLGpjeToiXHUwNDM5IixKZnI6Ilx1ZDgzNVx1ZGQwZCIsamZyOiJcdWQ4MzVcdWRkMjciLGptYXRoOiJcdTAyMzciLEpvcGY6Ilx1ZDgzNVx1ZGQ0MSIsam9wZjoiXHVkODM1XHVkZDViIixKc2NyOiJcdWQ4MzVcdWRjYTUiLGpzY3I6Ilx1ZDgzNVx1ZGNiZiIsSnNlcmN5OiJcdTA0MDgiLGpzZXJjeToiXHUwNDU4IixKdWtjeToiXHUwNDA0IixqdWtjeToiXHUwNDU0IixLYXBwYToiXHUwMzlhIixrYXBwYToiXHUwM2JhIixrYXBwYXY6Ilx1MDNmMCIsS2NlZGlsOiJcdTAxMzYiLGtjZWRpbDoiXHUwMTM3IixLY3k6Ilx1MDQxYSIsa2N5OiJcdTA0M2EiLEtmcjoiXHVkODM1XHVkZDBlIixrZnI6Ilx1ZDgzNVx1ZGQyOCIsa2dyZWVuOiJcdTAxMzgiLEtIY3k6Ilx1MDQyNSIsa2hjeToiXHUwNDQ1IixLSmN5OiJcdTA0MGMiLGtqY3k6Ilx1MDQ1YyIsS29wZjoiXHVkODM1XHVkZDQyIixrb3BmOiJcdWQ4MzVcdWRkNWMiLEtzY3I6Ilx1ZDgzNVx1ZGNhNiIsa3NjcjoiXHVkODM1XHVkY2MwIixsQWFycjoiXHUyMWRhIixMYWN1dGU6Ilx1MDEzOSIsbGFjdXRlOiJcdTAxM2EiLGxhZW1wdHl2OiJcdTI5YjQiLGxhZ3JhbjoiXHUyMTEyIixMYW1iZGE6Ilx1MDM5YiIsbGFtYmRhOiJcdTAzYmIiLGxhbmc6Ilx1MjdlOCIsTGFuZzoiXHUyN2VhIixsYW5nZDoiXHUyOTkxIixsYW5nbGU6Ilx1MjdlOCIsbGFwOiJcdTJhODUiLExhcGxhY2V0cmY6Ilx1MjExMiIsbGFxdW86Ilx4YWIiLGxhcnJiOiJcdTIxZTQiLGxhcnJiZnM6Ilx1MjkxZiIsbGFycjoiXHUyMTkwIixMYXJyOiJcdTIxOWUiLGxBcnI6Ilx1MjFkMCIsbGFycmZzOiJcdTI5MWQiLGxhcnJoazoiXHUyMWE5IixsYXJybHA6Ilx1MjFhYiIsbGFycnBsOiJcdTI5MzkiLGxhcnJzaW06Ilx1Mjk3MyIsbGFycnRsOiJcdTIxYTIiLGxhdGFpbDoiXHUyOTE5IixsQXRhaWw6Ilx1MjkxYiIsbGF0OiJcdTJhYWIiLGxhdGU6Ilx1MmFhZCIsbGF0ZXM6Ilx1MmFhZFx1ZmUwMCIsbGJhcnI6Ilx1MjkwYyIsbEJhcnI6Ilx1MjkwZSIsbGJicms6Ilx1Mjc3MiIsbGJyYWNlOiJ7IixsYnJhY2s6IlsiLGxicmtlOiJcdTI5OGIiLGxicmtzbGQ6Ilx1Mjk4ZiIsbGJya3NsdToiXHUyOThkIixMY2Fyb246Ilx1MDEzZCIsbGNhcm9uOiJcdTAxM2UiLExjZWRpbDoiXHUwMTNiIixsY2VkaWw6Ilx1MDEzYyIsbGNlaWw6Ilx1MjMwOCIsbGN1YjoieyIsTGN5OiJcdTA0MWIiLGxjeToiXHUwNDNiIixsZGNhOiJcdTI5MzYiLGxkcXVvOiJcdTIwMWMiLGxkcXVvcjoiXHUyMDFlIixsZHJkaGFyOiJcdTI5NjciLGxkcnVzaGFyOiJcdTI5NGIiLGxkc2g6Ilx1MjFiMiIsbGU6Ilx1MjI2NCIsbEU6Ilx1MjI2NiIsTGVmdEFuZ2xlQnJhY2tldDoiXHUyN2U4IixMZWZ0QXJyb3dCYXI6Ilx1MjFlNCIsbGVmdGFycm93OiJcdTIxOTAiLExlZnRBcnJvdzoiXHUyMTkwIixMZWZ0YXJyb3c6Ilx1MjFkMCIsTGVmdEFycm93UmlnaHRBcnJvdzoiXHUyMWM2IixsZWZ0YXJyb3d0YWlsOiJcdTIxYTIiLExlZnRDZWlsaW5nOiJcdTIzMDgiLExlZnREb3VibGVCcmFja2V0OiJcdTI3ZTYiLExlZnREb3duVGVlVmVjdG9yOiJcdTI5NjEiLExlZnREb3duVmVjdG9yQmFyOiJcdTI5NTkiLExlZnREb3duVmVjdG9yOiJcdTIxYzMiLExlZnRGbG9vcjoiXHUyMzBhIixsZWZ0aGFycG9vbmRvd246Ilx1MjFiZCIsbGVmdGhhcnBvb251cDoiXHUyMWJjIixsZWZ0bGVmdGFycm93czoiXHUyMWM3IixsZWZ0cmlnaHRhcnJvdzoiXHUyMTk0IixMZWZ0UmlnaHRBcnJvdzoiXHUyMTk0IixMZWZ0cmlnaHRhcnJvdzoiXHUyMWQ0IixsZWZ0cmlnaHRhcnJvd3M6Ilx1MjFjNiIsbGVmdHJpZ2h0aGFycG9vbnM6Ilx1MjFjYiIsbGVmdHJpZ2h0c3F1aWdhcnJvdzoiXHUyMWFkIixMZWZ0UmlnaHRWZWN0b3I6Ilx1Mjk0ZSIsTGVmdFRlZUFycm93OiJcdTIxYTQiLExlZnRUZWU6Ilx1MjJhMyIsTGVmdFRlZVZlY3RvcjoiXHUyOTVhIixsZWZ0dGhyZWV0aW1lczoiXHUyMmNiIixMZWZ0VHJpYW5nbGVCYXI6Ilx1MjljZiIsTGVmdFRyaWFuZ2xlOiJcdTIyYjIiLExlZnRUcmlhbmdsZUVxdWFsOiJcdTIyYjQiLExlZnRVcERvd25WZWN0b3I6Ilx1Mjk1MSIsTGVmdFVwVGVlVmVjdG9yOiJcdTI5NjAiLExlZnRVcFZlY3RvckJhcjoiXHUyOTU4IixMZWZ0VXBWZWN0b3I6Ilx1MjFiZiIsTGVmdFZlY3RvckJhcjoiXHUyOTUyIixMZWZ0VmVjdG9yOiJcdTIxYmMiLGxFZzoiXHUyYThiIixsZWc6Ilx1MjJkYSIsbGVxOiJcdTIyNjQiLGxlcXE6Ilx1MjI2NiIsbGVxc2xhbnQ6Ilx1MmE3ZCIsbGVzY2M6Ilx1MmFhOCIsbGVzOiJcdTJhN2QiLGxlc2RvdDoiXHUyYTdmIixsZXNkb3RvOiJcdTJhODEiLGxlc2RvdG9yOiJcdTJhODMiLGxlc2c6Ilx1MjJkYVx1ZmUwMCIsbGVzZ2VzOiJcdTJhOTMiLGxlc3NhcHByb3g6Ilx1MmE4NSIsbGVzc2RvdDoiXHUyMmQ2IixsZXNzZXFndHI6Ilx1MjJkYSIsbGVzc2VxcWd0cjoiXHUyYThiIixMZXNzRXF1YWxHcmVhdGVyOiJcdTIyZGEiLExlc3NGdWxsRXF1YWw6Ilx1MjI2NiIsTGVzc0dyZWF0ZXI6Ilx1MjI3NiIsbGVzc2d0cjoiXHUyMjc2IixMZXNzTGVzczoiXHUyYWExIixsZXNzc2ltOiJcdTIyNzIiLExlc3NTbGFudEVxdWFsOiJcdTJhN2QiLExlc3NUaWxkZToiXHUyMjcyIixsZmlzaHQ6Ilx1Mjk3YyIsbGZsb29yOiJcdTIzMGEiLExmcjoiXHVkODM1XHVkZDBmIixsZnI6Ilx1ZDgzNVx1ZGQyOSIsbGc6Ilx1MjI3NiIsbGdFOiJcdTJhOTEiLGxIYXI6Ilx1Mjk2MiIsbGhhcmQ6Ilx1MjFiZCIsbGhhcnU6Ilx1MjFiYyIsbGhhcnVsOiJcdTI5NmEiLGxoYmxrOiJcdTI1ODQiLExKY3k6Ilx1MDQwOSIsbGpjeToiXHUwNDU5IixsbGFycjoiXHUyMWM3IixsbDoiXHUyMjZhIixMbDoiXHUyMmQ4IixsbGNvcm5lcjoiXHUyMzFlIixMbGVmdGFycm93OiJcdTIxZGEiLGxsaGFyZDoiXHUyOTZiIixsbHRyaToiXHUyNWZhIixMbWlkb3Q6Ilx1MDEzZiIsbG1pZG90OiJcdTAxNDAiLGxtb3VzdGFjaGU6Ilx1MjNiMCIsbG1vdXN0OiJcdTIzYjAiLGxuYXA6Ilx1MmE4OSIsbG5hcHByb3g6Ilx1MmE4OSIsbG5lOiJcdTJhODciLGxuRToiXHUyMjY4IixsbmVxOiJcdTJhODciLGxuZXFxOiJcdTIyNjgiLGxuc2ltOiJcdTIyZTYiLGxvYW5nOiJcdTI3ZWMiLGxvYXJyOiJcdTIxZmQiLGxvYnJrOiJcdTI3ZTYiLGxvbmdsZWZ0YXJyb3c6Ilx1MjdmNSIsTG9uZ0xlZnRBcnJvdzoiXHUyN2Y1IixMb25nbGVmdGFycm93OiJcdTI3ZjgiLGxvbmdsZWZ0cmlnaHRhcnJvdzoiXHUyN2Y3IixMb25nTGVmdFJpZ2h0QXJyb3c6Ilx1MjdmNyIsTG9uZ2xlZnRyaWdodGFycm93OiJcdTI3ZmEiLGxvbmdtYXBzdG86Ilx1MjdmYyIsbG9uZ3JpZ2h0YXJyb3c6Ilx1MjdmNiIsTG9uZ1JpZ2h0QXJyb3c6Ilx1MjdmNiIsTG9uZ3JpZ2h0YXJyb3c6Ilx1MjdmOSIsbG9vcGFycm93bGVmdDoiXHUyMWFiIixsb29wYXJyb3dyaWdodDoiXHUyMWFjIixsb3BhcjoiXHUyOTg1IixMb3BmOiJcdWQ4MzVcdWRkNDMiLGxvcGY6Ilx1ZDgzNVx1ZGQ1ZCIsbG9wbHVzOiJcdTJhMmQiLGxvdGltZXM6Ilx1MmEzNCIsbG93YXN0OiJcdTIyMTciLGxvd2JhcjoiXyIsTG93ZXJMZWZ0QXJyb3c6Ilx1MjE5OSIsTG93ZXJSaWdodEFycm93OiJcdTIxOTgiLGxvejoiXHUyNWNhIixsb3plbmdlOiJcdTI1Y2EiLGxvemY6Ilx1MjllYiIsbHBhcjoiKCIsbHBhcmx0OiJcdTI5OTMiLGxyYXJyOiJcdTIxYzYiLGxyY29ybmVyOiJcdTIzMWYiLGxyaGFyOiJcdTIxY2IiLGxyaGFyZDoiXHUyOTZkIixscm06Ilx1MjAwZSIsbHJ0cmk6Ilx1MjJiZiIsbHNhcXVvOiJcdTIwMzkiLGxzY3I6Ilx1ZDgzNVx1ZGNjMSIsTHNjcjoiXHUyMTEyIixsc2g6Ilx1MjFiMCIsTHNoOiJcdTIxYjAiLGxzaW06Ilx1MjI3MiIsbHNpbWU6Ilx1MmE4ZCIsbHNpbWc6Ilx1MmE4ZiIsbHNxYjoiWyIsbHNxdW86Ilx1MjAxOCIsbHNxdW9yOiJcdTIwMWEiLExzdHJvazoiXHUwMTQxIixsc3Ryb2s6Ilx1MDE0MiIsbHRjYzoiXHUyYWE2IixsdGNpcjoiXHUyYTc5IixsdDoiPCIsTFQ6IjwiLEx0OiJcdTIyNmEiLGx0ZG90OiJcdTIyZDYiLGx0aHJlZToiXHUyMmNiIixsdGltZXM6Ilx1MjJjOSIsbHRsYXJyOiJcdTI5NzYiLGx0cXVlc3Q6Ilx1MmE3YiIsbHRyaToiXHUyNWMzIixsdHJpZToiXHUyMmI0IixsdHJpZjoiXHUyNWMyIixsdHJQYXI6Ilx1Mjk5NiIsbHVyZHNoYXI6Ilx1Mjk0YSIsbHVydWhhcjoiXHUyOTY2IixsdmVydG5lcXE6Ilx1MjI2OFx1ZmUwMCIsbHZuRToiXHUyMjY4XHVmZTAwIixtYWNyOiJceGFmIixtYWxlOiJcdTI2NDIiLG1hbHQ6Ilx1MjcyMCIsbWFsdGVzZToiXHUyNzIwIixNYXA6Ilx1MjkwNSIsbWFwOiJcdTIxYTYiLG1hcHN0bzoiXHUyMWE2IixtYXBzdG9kb3duOiJcdTIxYTciLG1hcHN0b2xlZnQ6Ilx1MjFhNCIsbWFwc3RvdXA6Ilx1MjFhNSIsbWFya2VyOiJcdTI1YWUiLG1jb21tYToiXHUyYTI5IixNY3k6Ilx1MDQxYyIsbWN5OiJcdTA0M2MiLG1kYXNoOiJcdTIwMTQiLG1ERG90OiJcdTIyM2EiLG1lYXN1cmVkYW5nbGU6Ilx1MjIyMSIsTWVkaXVtU3BhY2U6Ilx1MjA1ZiIsTWVsbGludHJmOiJcdTIxMzMiLE1mcjoiXHVkODM1XHVkZDEwIixtZnI6Ilx1ZDgzNVx1ZGQyYSIsbWhvOiJcdTIxMjciLG1pY3JvOiJceGI1IixtaWRhc3Q6IioiLG1pZGNpcjoiXHUyYWYwIixtaWQ6Ilx1MjIyMyIsbWlkZG90OiJceGI3IixtaW51c2I6Ilx1MjI5ZiIsbWludXM6Ilx1MjIxMiIsbWludXNkOiJcdTIyMzgiLG1pbnVzZHU6Ilx1MmEyYSIsTWludXNQbHVzOiJcdTIyMTMiLG1sY3A6Ilx1MmFkYiIsbWxkcjoiXHUyMDI2IixtbnBsdXM6Ilx1MjIxMyIsbW9kZWxzOiJcdTIyYTciLE1vcGY6Ilx1ZDgzNVx1ZGQ0NCIsbW9wZjoiXHVkODM1XHVkZDVlIixtcDoiXHUyMjEzIixtc2NyOiJcdWQ4MzVcdWRjYzIiLE1zY3I6Ilx1MjEzMyIsbXN0cG9zOiJcdTIyM2UiLE11OiJcdTAzOWMiLG11OiJcdTAzYmMiLG11bHRpbWFwOiJcdTIyYjgiLG11bWFwOiJcdTIyYjgiLG5hYmxhOiJcdTIyMDciLE5hY3V0ZToiXHUwMTQzIixuYWN1dGU6Ilx1MDE0NCIsbmFuZzoiXHUyMjIwXHUyMGQyIixuYXA6Ilx1MjI0OSIsbmFwRToiXHUyYTcwXHUwMzM4IixuYXBpZDoiXHUyMjRiXHUwMzM4IixuYXBvczoiXHUwMTQ5IixuYXBwcm94OiJcdTIyNDkiLG5hdHVyYWw6Ilx1MjY2ZSIsbmF0dXJhbHM6Ilx1MjExNSIsbmF0dXI6Ilx1MjY2ZSIsbmJzcDoiXHhhMCIsbmJ1bXA6Ilx1MjI0ZVx1MDMzOCIsbmJ1bXBlOiJcdTIyNGZcdTAzMzgiLG5jYXA6Ilx1MmE0MyIsTmNhcm9uOiJcdTAxNDciLG5jYXJvbjoiXHUwMTQ4IixOY2VkaWw6Ilx1MDE0NSIsbmNlZGlsOiJcdTAxNDYiLG5jb25nOiJcdTIyNDciLG5jb25nZG90OiJcdTJhNmRcdTAzMzgiLG5jdXA6Ilx1MmE0MiIsTmN5OiJcdTA0MWQiLG5jeToiXHUwNDNkIixuZGFzaDoiXHUyMDEzIixuZWFyaGs6Ilx1MjkyNCIsbmVhcnI6Ilx1MjE5NyIsbmVBcnI6Ilx1MjFkNyIsbmVhcnJvdzoiXHUyMTk3IixuZToiXHUyMjYwIixuZWRvdDoiXHUyMjUwXHUwMzM4IixOZWdhdGl2ZU1lZGl1bVNwYWNlOiJcdTIwMGIiLE5lZ2F0aXZlVGhpY2tTcGFjZToiXHUyMDBiIixOZWdhdGl2ZVRoaW5TcGFjZToiXHUyMDBiIixOZWdhdGl2ZVZlcnlUaGluU3BhY2U6Ilx1MjAwYiIsbmVxdWl2OiJcdTIyNjIiLG5lc2VhcjoiXHUyOTI4IixuZXNpbToiXHUyMjQyXHUwMzM4IixOZXN0ZWRHcmVhdGVyR3JlYXRlcjoiXHUyMjZiIixOZXN0ZWRMZXNzTGVzczoiXHUyMjZhIixOZXdMaW5lOiJcbiIsbmV4aXN0OiJcdTIyMDQiLG5leGlzdHM6Ilx1MjIwNCIsTmZyOiJcdWQ4MzVcdWRkMTEiLG5mcjoiXHVkODM1XHVkZDJiIixuZ0U6Ilx1MjI2N1x1MDMzOCIsbmdlOiJcdTIyNzEiLG5nZXE6Ilx1MjI3MSIsbmdlcXE6Ilx1MjI2N1x1MDMzOCIsbmdlcXNsYW50OiJcdTJhN2VcdTAzMzgiLG5nZXM6Ilx1MmE3ZVx1MDMzOCIsbkdnOiJcdTIyZDlcdTAzMzgiLG5nc2ltOiJcdTIyNzUiLG5HdDoiXHUyMjZiXHUyMGQyIixuZ3Q6Ilx1MjI2ZiIsbmd0cjoiXHUyMjZmIixuR3R2OiJcdTIyNmJcdTAzMzgiLG5oYXJyOiJcdTIxYWUiLG5oQXJyOiJcdTIxY2UiLG5ocGFyOiJcdTJhZjIiLG5pOiJcdTIyMGIiLG5pczoiXHUyMmZjIixuaXNkOiJcdTIyZmEiLG5pdjoiXHUyMjBiIixOSmN5OiJcdTA0MGEiLG5qY3k6Ilx1MDQ1YSIsbmxhcnI6Ilx1MjE5YSIsbmxBcnI6Ilx1MjFjZCIsbmxkcjoiXHUyMDI1IixubEU6Ilx1MjI2Nlx1MDMzOCIsbmxlOiJcdTIyNzAiLG5sZWZ0YXJyb3c6Ilx1MjE5YSIsbkxlZnRhcnJvdzoiXHUyMWNkIixubGVmdHJpZ2h0YXJyb3c6Ilx1MjFhZSIsbkxlZnRyaWdodGFycm93OiJcdTIxY2UiLG5sZXE6Ilx1MjI3MCIsbmxlcXE6Ilx1MjI2Nlx1MDMzOCIsbmxlcXNsYW50OiJcdTJhN2RcdTAzMzgiLG5sZXM6Ilx1MmE3ZFx1MDMzOCIsbmxlc3M6Ilx1MjI2ZSIsbkxsOiJcdTIyZDhcdTAzMzgiLG5sc2ltOiJcdTIyNzQiLG5MdDoiXHUyMjZhXHUyMGQyIixubHQ6Ilx1MjI2ZSIsbmx0cmk6Ilx1MjJlYSIsbmx0cmllOiJcdTIyZWMiLG5MdHY6Ilx1MjI2YVx1MDMzOCIsbm1pZDoiXHUyMjI0IixOb0JyZWFrOiJcdTIwNjAiLE5vbkJyZWFraW5nU3BhY2U6Ilx4YTAiLG5vcGY6Ilx1ZDgzNVx1ZGQ1ZiIsTm9wZjoiXHUyMTE1IixOb3Q6Ilx1MmFlYyIsbm90OiJceGFjIixOb3RDb25ncnVlbnQ6Ilx1MjI2MiIsTm90Q3VwQ2FwOiJcdTIyNmQiLE5vdERvdWJsZVZlcnRpY2FsQmFyOiJcdTIyMjYiLE5vdEVsZW1lbnQ6Ilx1MjIwOSIsTm90RXF1YWw6Ilx1MjI2MCIsTm90RXF1YWxUaWxkZToiXHUyMjQyXHUwMzM4IixOb3RFeGlzdHM6Ilx1MjIwNCIsTm90R3JlYXRlcjoiXHUyMjZmIixOb3RHcmVhdGVyRXF1YWw6Ilx1MjI3MSIsTm90R3JlYXRlckZ1bGxFcXVhbDoiXHUyMjY3XHUwMzM4IixOb3RHcmVhdGVyR3JlYXRlcjoiXHUyMjZiXHUwMzM4IixOb3RHcmVhdGVyTGVzczoiXHUyMjc5IixOb3RHcmVhdGVyU2xhbnRFcXVhbDoiXHUyYTdlXHUwMzM4IixOb3RHcmVhdGVyVGlsZGU6Ilx1MjI3NSIsTm90SHVtcERvd25IdW1wOiJcdTIyNGVcdTAzMzgiLE5vdEh1bXBFcXVhbDoiXHUyMjRmXHUwMzM4Iixub3RpbjoiXHUyMjA5Iixub3RpbmRvdDoiXHUyMmY1XHUwMzM4Iixub3RpbkU6Ilx1MjJmOVx1MDMzOCIsbm90aW52YToiXHUyMjA5Iixub3RpbnZiOiJcdTIyZjciLG5vdGludmM6Ilx1MjJmNiIsTm90TGVmdFRyaWFuZ2xlQmFyOiJcdTI5Y2ZcdTAzMzgiLE5vdExlZnRUcmlhbmdsZToiXHUyMmVhIixOb3RMZWZ0VHJpYW5nbGVFcXVhbDoiXHUyMmVjIixOb3RMZXNzOiJcdTIyNmUiLE5vdExlc3NFcXVhbDoiXHUyMjcwIixOb3RMZXNzR3JlYXRlcjoiXHUyMjc4IixOb3RMZXNzTGVzczoiXHUyMjZhXHUwMzM4IixOb3RMZXNzU2xhbnRFcXVhbDoiXHUyYTdkXHUwMzM4IixOb3RMZXNzVGlsZGU6Ilx1MjI3NCIsTm90TmVzdGVkR3JlYXRlckdyZWF0ZXI6Ilx1MmFhMlx1MDMzOCIsTm90TmVzdGVkTGVzc0xlc3M6Ilx1MmFhMVx1MDMzOCIsbm90bmk6Ilx1MjIwYyIsbm90bml2YToiXHUyMjBjIixub3RuaXZiOiJcdTIyZmUiLG5vdG5pdmM6Ilx1MjJmZCIsTm90UHJlY2VkZXM6Ilx1MjI4MCIsTm90UHJlY2VkZXNFcXVhbDoiXHUyYWFmXHUwMzM4IixOb3RQcmVjZWRlc1NsYW50RXF1YWw6Ilx1MjJlMCIsTm90UmV2ZXJzZUVsZW1lbnQ6Ilx1MjIwYyIsTm90UmlnaHRUcmlhbmdsZUJhcjoiXHUyOWQwXHUwMzM4IixOb3RSaWdodFRyaWFuZ2xlOiJcdTIyZWIiLE5vdFJpZ2h0VHJpYW5nbGVFcXVhbDoiXHUyMmVkIixOb3RTcXVhcmVTdWJzZXQ6Ilx1MjI4Zlx1MDMzOCIsTm90U3F1YXJlU3Vic2V0RXF1YWw6Ilx1MjJlMiIsTm90U3F1YXJlU3VwZXJzZXQ6Ilx1MjI5MFx1MDMzOCIsTm90U3F1YXJlU3VwZXJzZXRFcXVhbDoiXHUyMmUzIixOb3RTdWJzZXQ6Ilx1MjI4Mlx1MjBkMiIsTm90U3Vic2V0RXF1YWw6Ilx1MjI4OCIsTm90U3VjY2VlZHM6Ilx1MjI4MSIsTm90U3VjY2VlZHNFcXVhbDoiXHUyYWIwXHUwMzM4IixOb3RTdWNjZWVkc1NsYW50RXF1YWw6Ilx1MjJlMSIsTm90U3VjY2VlZHNUaWxkZToiXHUyMjdmXHUwMzM4IixOb3RTdXBlcnNldDoiXHUyMjgzXHUyMGQyIixOb3RTdXBlcnNldEVxdWFsOiJcdTIyODkiLE5vdFRpbGRlOiJcdTIyNDEiLE5vdFRpbGRlRXF1YWw6Ilx1MjI0NCIsTm90VGlsZGVGdWxsRXF1YWw6Ilx1MjI0NyIsTm90VGlsZGVUaWxkZToiXHUyMjQ5IixOb3RWZXJ0aWNhbEJhcjoiXHUyMjI0IixucGFyYWxsZWw6Ilx1MjIyNiIsbnBhcjoiXHUyMjI2IixucGFyc2w6Ilx1MmFmZFx1MjBlNSIsbnBhcnQ6Ilx1MjIwMlx1MDMzOCIsbnBvbGludDoiXHUyYTE0IixucHI6Ilx1MjI4MCIsbnByY3VlOiJcdTIyZTAiLG5wcmVjOiJcdTIyODAiLG5wcmVjZXE6Ilx1MmFhZlx1MDMzOCIsbnByZToiXHUyYWFmXHUwMzM4IixucmFycmM6Ilx1MjkzM1x1MDMzOCIsbnJhcnI6Ilx1MjE5YiIsbnJBcnI6Ilx1MjFjZiIsbnJhcnJ3OiJcdTIxOWRcdTAzMzgiLG5yaWdodGFycm93OiJcdTIxOWIiLG5SaWdodGFycm93OiJcdTIxY2YiLG5ydHJpOiJcdTIyZWIiLG5ydHJpZToiXHUyMmVkIixuc2M6Ilx1MjI4MSIsbnNjY3VlOiJcdTIyZTEiLG5zY2U6Ilx1MmFiMFx1MDMzOCIsTnNjcjoiXHVkODM1XHVkY2E5Iixuc2NyOiJcdWQ4MzVcdWRjYzMiLG5zaG9ydG1pZDoiXHUyMjI0Iixuc2hvcnRwYXJhbGxlbDoiXHUyMjI2Iixuc2ltOiJcdTIyNDEiLG5zaW1lOiJcdTIyNDQiLG5zaW1lcToiXHUyMjQ0Iixuc21pZDoiXHUyMjI0Iixuc3BhcjoiXHUyMjI2Iixuc3FzdWJlOiJcdTIyZTIiLG5zcXN1cGU6Ilx1MjJlMyIsbnN1YjoiXHUyMjg0Iixuc3ViRToiXHUyYWM1XHUwMzM4Iixuc3ViZToiXHUyMjg4Iixuc3Vic2V0OiJcdTIyODJcdTIwZDIiLG5zdWJzZXRlcToiXHUyMjg4Iixuc3Vic2V0ZXFxOiJcdTJhYzVcdTAzMzgiLG5zdWNjOiJcdTIyODEiLG5zdWNjZXE6Ilx1MmFiMFx1MDMzOCIsbnN1cDoiXHUyMjg1Iixuc3VwRToiXHUyYWM2XHUwMzM4Iixuc3VwZToiXHUyMjg5Iixuc3Vwc2V0OiJcdTIyODNcdTIwZDIiLG5zdXBzZXRlcToiXHUyMjg5Iixuc3Vwc2V0ZXFxOiJcdTJhYzZcdTAzMzgiLG50Z2w6Ilx1MjI3OSIsTnRpbGRlOiJceGQxIixudGlsZGU6Ilx4ZjEiLG50bGc6Ilx1MjI3OCIsbnRyaWFuZ2xlbGVmdDoiXHUyMmVhIixudHJpYW5nbGVsZWZ0ZXE6Ilx1MjJlYyIsbnRyaWFuZ2xlcmlnaHQ6Ilx1MjJlYiIsbnRyaWFuZ2xlcmlnaHRlcToiXHUyMmVkIixOdToiXHUwMzlkIixudToiXHUwM2JkIixudW06IiMiLG51bWVybzoiXHUyMTE2IixudW1zcDoiXHUyMDA3IixudmFwOiJcdTIyNGRcdTIwZDIiLG52ZGFzaDoiXHUyMmFjIixudkRhc2g6Ilx1MjJhZCIsblZkYXNoOiJcdTIyYWUiLG5WRGFzaDoiXHUyMmFmIixudmdlOiJcdTIyNjVcdTIwZDIiLG52Z3Q6Ij5cdTIwZDIiLG52SGFycjoiXHUyOTA0IixudmluZmluOiJcdTI5ZGUiLG52bEFycjoiXHUyOTAyIixudmxlOiJcdTIyNjRcdTIwZDIiLG52bHQ6IjxcdTIwZDIiLG52bHRyaWU6Ilx1MjJiNFx1MjBkMiIsbnZyQXJyOiJcdTI5MDMiLG52cnRyaWU6Ilx1MjJiNVx1MjBkMiIsbnZzaW06Ilx1MjIzY1x1MjBkMiIsbndhcmhrOiJcdTI5MjMiLG53YXJyOiJcdTIxOTYiLG53QXJyOiJcdTIxZDYiLG53YXJyb3c6Ilx1MjE5NiIsbnduZWFyOiJcdTI5MjciLE9hY3V0ZToiXHhkMyIsb2FjdXRlOiJceGYzIixvYXN0OiJcdTIyOWIiLE9jaXJjOiJceGQ0IixvY2lyYzoiXHhmNCIsb2NpcjoiXHUyMjlhIixPY3k6Ilx1MDQxZSIsb2N5OiJcdTA0M2UiLG9kYXNoOiJcdTIyOWQiLE9kYmxhYzoiXHUwMTUwIixvZGJsYWM6Ilx1MDE1MSIsb2RpdjoiXHUyYTM4IixvZG90OiJcdTIyOTkiLG9kc29sZDoiXHUyOWJjIixPRWxpZzoiXHUwMTUyIixvZWxpZzoiXHUwMTUzIixvZmNpcjoiXHUyOWJmIixPZnI6Ilx1ZDgzNVx1ZGQxMiIsb2ZyOiJcdWQ4MzVcdWRkMmMiLG9nb246Ilx1MDJkYiIsT2dyYXZlOiJceGQyIixvZ3JhdmU6Ilx4ZjIiLG9ndDoiXHUyOWMxIixvaGJhcjoiXHUyOWI1IixvaG06Ilx1MDNhOSIsb2ludDoiXHUyMjJlIixvbGFycjoiXHUyMWJhIixvbGNpcjoiXHUyOWJlIixvbGNyb3NzOiJcdTI5YmIiLG9saW5lOiJcdTIwM2UiLG9sdDoiXHUyOWMwIixPbWFjcjoiXHUwMTRjIixvbWFjcjoiXHUwMTRkIixPbWVnYToiXHUwM2E5IixvbWVnYToiXHUwM2M5IixPbWljcm9uOiJcdTAzOWYiLG9taWNyb246Ilx1MDNiZiIsb21pZDoiXHUyOWI2IixvbWludXM6Ilx1MjI5NiIsT29wZjoiXHVkODM1XHVkZDQ2Iixvb3BmOiJcdWQ4MzVcdWRkNjAiLG9wYXI6Ilx1MjliNyIsT3BlbkN1cmx5RG91YmxlUXVvdGU6Ilx1MjAxYyIsT3BlbkN1cmx5UXVvdGU6Ilx1MjAxOCIsb3BlcnA6Ilx1MjliOSIsb3BsdXM6Ilx1MjI5NSIsb3JhcnI6Ilx1MjFiYiIsT3I6Ilx1MmE1NCIsb3I6Ilx1MjIyOCIsb3JkOiJcdTJhNWQiLG9yZGVyOiJcdTIxMzQiLG9yZGVyb2Y6Ilx1MjEzNCIsb3JkZjoiXHhhYSIsb3JkbToiXHhiYSIsb3JpZ29mOiJcdTIyYjYiLG9yb3I6Ilx1MmE1NiIsb3JzbG9wZToiXHUyYTU3IixvcnY6Ilx1MmE1YiIsb1M6Ilx1MjRjOCIsT3NjcjoiXHVkODM1XHVkY2FhIixvc2NyOiJcdTIxMzQiLE9zbGFzaDoiXHhkOCIsb3NsYXNoOiJceGY4Iixvc29sOiJcdTIyOTgiLE90aWxkZToiXHhkNSIsb3RpbGRlOiJceGY1IixvdGltZXNhczoiXHUyYTM2IixPdGltZXM6Ilx1MmEzNyIsb3RpbWVzOiJcdTIyOTciLE91bWw6Ilx4ZDYiLG91bWw6Ilx4ZjYiLG92YmFyOiJcdTIzM2QiLE92ZXJCYXI6Ilx1MjAzZSIsT3ZlckJyYWNlOiJcdTIzZGUiLE92ZXJCcmFja2V0OiJcdTIzYjQiLE92ZXJQYXJlbnRoZXNpczoiXHUyM2RjIixwYXJhOiJceGI2IixwYXJhbGxlbDoiXHUyMjI1IixwYXI6Ilx1MjIyNSIscGFyc2ltOiJcdTJhZjMiLHBhcnNsOiJcdTJhZmQiLHBhcnQ6Ilx1MjIwMiIsUGFydGlhbEQ6Ilx1MjIwMiIsUGN5OiJcdTA0MWYiLHBjeToiXHUwNDNmIixwZXJjbnQ6IiUiLHBlcmlvZDoiLiIscGVybWlsOiJcdTIwMzAiLHBlcnA6Ilx1MjJhNSIscGVydGVuazoiXHUyMDMxIixQZnI6Ilx1ZDgzNVx1ZGQxMyIscGZyOiJcdWQ4MzVcdWRkMmQiLFBoaToiXHUwM2E2IixwaGk6Ilx1MDNjNiIscGhpdjoiXHUwM2Q1IixwaG1tYXQ6Ilx1MjEzMyIscGhvbmU6Ilx1MjYwZSIsUGk6Ilx1MDNhMCIscGk6Ilx1MDNjMCIscGl0Y2hmb3JrOiJcdTIyZDQiLHBpdjoiXHUwM2Q2IixwbGFuY2s6Ilx1MjEwZiIscGxhbmNraDoiXHUyMTBlIixwbGFua3Y6Ilx1MjEwZiIscGx1c2FjaXI6Ilx1MmEyMyIscGx1c2I6Ilx1MjI5ZSIscGx1c2NpcjoiXHUyYTIyIixwbHVzOiIrIixwbHVzZG86Ilx1MjIxNCIscGx1c2R1OiJcdTJhMjUiLHBsdXNlOiJcdTJhNzIiLFBsdXNNaW51czoiXHhiMSIscGx1c21uOiJceGIxIixwbHVzc2ltOiJcdTJhMjYiLHBsdXN0d286Ilx1MmEyNyIscG06Ilx4YjEiLFBvaW5jYXJlcGxhbmU6Ilx1MjEwYyIscG9pbnRpbnQ6Ilx1MmExNSIscG9wZjoiXHVkODM1XHVkZDYxIixQb3BmOiJcdTIxMTkiLHBvdW5kOiJceGEzIixwcmFwOiJcdTJhYjciLFByOiJcdTJhYmIiLHByOiJcdTIyN2EiLHByY3VlOiJcdTIyN2MiLHByZWNhcHByb3g6Ilx1MmFiNyIscHJlYzoiXHUyMjdhIixwcmVjY3VybHllcToiXHUyMjdjIixQcmVjZWRlczoiXHUyMjdhIixQcmVjZWRlc0VxdWFsOiJcdTJhYWYiLFByZWNlZGVzU2xhbnRFcXVhbDoiXHUyMjdjIixQcmVjZWRlc1RpbGRlOiJcdTIyN2UiLHByZWNlcToiXHUyYWFmIixwcmVjbmFwcHJveDoiXHUyYWI5IixwcmVjbmVxcToiXHUyYWI1IixwcmVjbnNpbToiXHUyMmU4IixwcmU6Ilx1MmFhZiIscHJFOiJcdTJhYjMiLHByZWNzaW06Ilx1MjI3ZSIscHJpbWU6Ilx1MjAzMiIsUHJpbWU6Ilx1MjAzMyIscHJpbWVzOiJcdTIxMTkiLHBybmFwOiJcdTJhYjkiLHBybkU6Ilx1MmFiNSIscHJuc2ltOiJcdTIyZTgiLHByb2Q6Ilx1MjIwZiIsUHJvZHVjdDoiXHUyMjBmIixwcm9mYWxhcjoiXHUyMzJlIixwcm9mbGluZToiXHUyMzEyIixwcm9mc3VyZjoiXHUyMzEzIixwcm9wOiJcdTIyMWQiLFByb3BvcnRpb25hbDoiXHUyMjFkIixQcm9wb3J0aW9uOiJcdTIyMzciLHByb3B0bzoiXHUyMjFkIixwcnNpbToiXHUyMjdlIixwcnVyZWw6Ilx1MjJiMCIsUHNjcjoiXHVkODM1XHVkY2FiIixwc2NyOiJcdWQ4MzVcdWRjYzUiLFBzaToiXHUwM2E4Iixwc2k6Ilx1MDNjOCIscHVuY3NwOiJcdTIwMDgiLFFmcjoiXHVkODM1XHVkZDE0IixxZnI6Ilx1ZDgzNVx1ZGQyZSIscWludDoiXHUyYTBjIixxb3BmOiJcdWQ4MzVcdWRkNjIiLFFvcGY6Ilx1MjExYSIscXByaW1lOiJcdTIwNTciLFFzY3I6Ilx1ZDgzNVx1ZGNhYyIscXNjcjoiXHVkODM1XHVkY2M2IixxdWF0ZXJuaW9uczoiXHUyMTBkIixxdWF0aW50OiJcdTJhMTYiLHF1ZXN0OiI/IixxdWVzdGVxOiJcdTIyNWYiLHF1b3Q6JyInLFFVT1Q6JyInLHJBYXJyOiJcdTIxZGIiLHJhY2U6Ilx1MjIzZFx1MDMzMSIsUmFjdXRlOiJcdTAxNTQiLHJhY3V0ZToiXHUwMTU1IixyYWRpYzoiXHUyMjFhIixyYWVtcHR5djoiXHUyOWIzIixyYW5nOiJcdTI3ZTkiLFJhbmc6Ilx1MjdlYiIscmFuZ2Q6Ilx1Mjk5MiIscmFuZ2U6Ilx1MjlhNSIscmFuZ2xlOiJcdTI3ZTkiLHJhcXVvOiJceGJiIixyYXJyYXA6Ilx1Mjk3NSIscmFycmI6Ilx1MjFlNSIscmFycmJmczoiXHUyOTIwIixyYXJyYzoiXHUyOTMzIixyYXJyOiJcdTIxOTIiLFJhcnI6Ilx1MjFhMCIsckFycjoiXHUyMWQyIixyYXJyZnM6Ilx1MjkxZSIscmFycmhrOiJcdTIxYWEiLHJhcnJscDoiXHUyMWFjIixyYXJycGw6Ilx1Mjk0NSIscmFycnNpbToiXHUyOTc0IixSYXJydGw6Ilx1MjkxNiIscmFycnRsOiJcdTIxYTMiLHJhcnJ3OiJcdTIxOWQiLHJhdGFpbDoiXHUyOTFhIixyQXRhaWw6Ilx1MjkxYyIscmF0aW86Ilx1MjIzNiIscmF0aW9uYWxzOiJcdTIxMWEiLHJiYXJyOiJcdTI5MGQiLHJCYXJyOiJcdTI5MGYiLFJCYXJyOiJcdTI5MTAiLHJiYnJrOiJcdTI3NzMiLHJicmFjZToifSIscmJyYWNrOiJdIixyYnJrZToiXHUyOThjIixyYnJrc2xkOiJcdTI5OGUiLHJicmtzbHU6Ilx1Mjk5MCIsUmNhcm9uOiJcdTAxNTgiLHJjYXJvbjoiXHUwMTU5IixSY2VkaWw6Ilx1MDE1NiIscmNlZGlsOiJcdTAxNTciLHJjZWlsOiJcdTIzMDkiLHJjdWI6In0iLFJjeToiXHUwNDIwIixyY3k6Ilx1MDQ0MCIscmRjYToiXHUyOTM3IixyZGxkaGFyOiJcdTI5NjkiLHJkcXVvOiJcdTIwMWQiLHJkcXVvcjoiXHUyMDFkIixyZHNoOiJcdTIxYjMiLHJlYWw6Ilx1MjExYyIscmVhbGluZToiXHUyMTFiIixyZWFscGFydDoiXHUyMTFjIixyZWFsczoiXHUyMTFkIixSZToiXHUyMTFjIixyZWN0OiJcdTI1YWQiLHJlZzoiXHhhZSIsUkVHOiJceGFlIixSZXZlcnNlRWxlbWVudDoiXHUyMjBiIixSZXZlcnNlRXF1aWxpYnJpdW06Ilx1MjFjYiIsUmV2ZXJzZVVwRXF1aWxpYnJpdW06Ilx1Mjk2ZiIscmZpc2h0OiJcdTI5N2QiLHJmbG9vcjoiXHUyMzBiIixyZnI6Ilx1ZDgzNVx1ZGQyZiIsUmZyOiJcdTIxMWMiLHJIYXI6Ilx1Mjk2NCIscmhhcmQ6Ilx1MjFjMSIscmhhcnU6Ilx1MjFjMCIscmhhcnVsOiJcdTI5NmMiLFJobzoiXHUwM2ExIixyaG86Ilx1MDNjMSIscmhvdjoiXHUwM2YxIixSaWdodEFuZ2xlQnJhY2tldDoiXHUyN2U5IixSaWdodEFycm93QmFyOiJcdTIxZTUiLHJpZ2h0YXJyb3c6Ilx1MjE5MiIsUmlnaHRBcnJvdzoiXHUyMTkyIixSaWdodGFycm93OiJcdTIxZDIiLFJpZ2h0QXJyb3dMZWZ0QXJyb3c6Ilx1MjFjNCIscmlnaHRhcnJvd3RhaWw6Ilx1MjFhMyIsUmlnaHRDZWlsaW5nOiJcdTIzMDkiLFJpZ2h0RG91YmxlQnJhY2tldDoiXHUyN2U3IixSaWdodERvd25UZWVWZWN0b3I6Ilx1Mjk1ZCIsUmlnaHREb3duVmVjdG9yQmFyOiJcdTI5NTUiLFJpZ2h0RG93blZlY3RvcjoiXHUyMWMyIixSaWdodEZsb29yOiJcdTIzMGIiLHJpZ2h0aGFycG9vbmRvd246Ilx1MjFjMSIscmlnaHRoYXJwb29udXA6Ilx1MjFjMCIscmlnaHRsZWZ0YXJyb3dzOiJcdTIxYzQiLHJpZ2h0bGVmdGhhcnBvb25zOiJcdTIxY2MiLHJpZ2h0cmlnaHRhcnJvd3M6Ilx1MjFjOSIscmlnaHRzcXVpZ2Fycm93OiJcdTIxOWQiLFJpZ2h0VGVlQXJyb3c6Ilx1MjFhNiIsUmlnaHRUZWU6Ilx1MjJhMiIsUmlnaHRUZWVWZWN0b3I6Ilx1Mjk1YiIscmlnaHR0aHJlZXRpbWVzOiJcdTIyY2MiLFJpZ2h0VHJpYW5nbGVCYXI6Ilx1MjlkMCIsUmlnaHRUcmlhbmdsZToiXHUyMmIzIixSaWdodFRyaWFuZ2xlRXF1YWw6Ilx1MjJiNSIsUmlnaHRVcERvd25WZWN0b3I6Ilx1Mjk0ZiIsUmlnaHRVcFRlZVZlY3RvcjoiXHUyOTVjIixSaWdodFVwVmVjdG9yQmFyOiJcdTI5NTQiLFJpZ2h0VXBWZWN0b3I6Ilx1MjFiZSIsUmlnaHRWZWN0b3JCYXI6Ilx1Mjk1MyIsUmlnaHRWZWN0b3I6Ilx1MjFjMCIscmluZzoiXHUwMmRhIixyaXNpbmdkb3RzZXE6Ilx1MjI1MyIscmxhcnI6Ilx1MjFjNCIscmxoYXI6Ilx1MjFjYyIscmxtOiJcdTIwMGYiLHJtb3VzdGFjaGU6Ilx1MjNiMSIscm1vdXN0OiJcdTIzYjEiLHJubWlkOiJcdTJhZWUiLHJvYW5nOiJcdTI3ZWQiLHJvYXJyOiJcdTIxZmUiLHJvYnJrOiJcdTI3ZTciLHJvcGFyOiJcdTI5ODYiLHJvcGY6Ilx1ZDgzNVx1ZGQ2MyIsUm9wZjoiXHUyMTFkIixyb3BsdXM6Ilx1MmEyZSIscm90aW1lczoiXHUyYTM1IixSb3VuZEltcGxpZXM6Ilx1Mjk3MCIscnBhcjoiKSIscnBhcmd0OiJcdTI5OTQiLHJwcG9saW50OiJcdTJhMTIiLHJyYXJyOiJcdTIxYzkiLFJyaWdodGFycm93OiJcdTIxZGIiLHJzYXF1bzoiXHUyMDNhIixyc2NyOiJcdWQ4MzVcdWRjYzciLFJzY3I6Ilx1MjExYiIscnNoOiJcdTIxYjEiLFJzaDoiXHUyMWIxIixyc3FiOiJdIixyc3F1bzoiXHUyMDE5Iixyc3F1b3I6Ilx1MjAxOSIscnRocmVlOiJcdTIyY2MiLHJ0aW1lczoiXHUyMmNhIixydHJpOiJcdTI1YjkiLHJ0cmllOiJcdTIyYjUiLHJ0cmlmOiJcdTI1YjgiLHJ0cmlsdHJpOiJcdTI5Y2UiLFJ1bGVEZWxheWVkOiJcdTI5ZjQiLHJ1bHVoYXI6Ilx1Mjk2OCIscng6Ilx1MjExZSIsU2FjdXRlOiJcdTAxNWEiLHNhY3V0ZToiXHUwMTViIixzYnF1bzoiXHUyMDFhIixzY2FwOiJcdTJhYjgiLFNjYXJvbjoiXHUwMTYwIixzY2Fyb246Ilx1MDE2MSIsU2M6Ilx1MmFiYyIsc2M6Ilx1MjI3YiIsc2NjdWU6Ilx1MjI3ZCIsc2NlOiJcdTJhYjAiLHNjRToiXHUyYWI0IixTY2VkaWw6Ilx1MDE1ZSIsc2NlZGlsOiJcdTAxNWYiLFNjaXJjOiJcdTAxNWMiLHNjaXJjOiJcdTAxNWQiLHNjbmFwOiJcdTJhYmEiLHNjbkU6Ilx1MmFiNiIsc2Nuc2ltOiJcdTIyZTkiLHNjcG9saW50OiJcdTJhMTMiLHNjc2ltOiJcdTIyN2YiLFNjeToiXHUwNDIxIixzY3k6Ilx1MDQ0MSIsc2RvdGI6Ilx1MjJhMSIsc2RvdDoiXHUyMmM1IixzZG90ZToiXHUyYTY2IixzZWFyaGs6Ilx1MjkyNSIsc2VhcnI6Ilx1MjE5OCIsc2VBcnI6Ilx1MjFkOCIsc2VhcnJvdzoiXHUyMTk4IixzZWN0OiJceGE3IixzZW1pOiI7IixzZXN3YXI6Ilx1MjkyOSIsc2V0bWludXM6Ilx1MjIxNiIsc2V0bW46Ilx1MjIxNiIsc2V4dDoiXHUyNzM2IixTZnI6Ilx1ZDgzNVx1ZGQxNiIsc2ZyOiJcdWQ4MzVcdWRkMzAiLHNmcm93bjoiXHUyMzIyIixzaGFycDoiXHUyNjZmIixTSENIY3k6Ilx1MDQyOSIsc2hjaGN5OiJcdTA0NDkiLFNIY3k6Ilx1MDQyOCIsc2hjeToiXHUwNDQ4IixTaG9ydERvd25BcnJvdzoiXHUyMTkzIixTaG9ydExlZnRBcnJvdzoiXHUyMTkwIixzaG9ydG1pZDoiXHUyMjIzIixzaG9ydHBhcmFsbGVsOiJcdTIyMjUiLFNob3J0UmlnaHRBcnJvdzoiXHUyMTkyIixTaG9ydFVwQXJyb3c6Ilx1MjE5MSIsc2h5OiJceGFkIixTaWdtYToiXHUwM2EzIixzaWdtYToiXHUwM2MzIixzaWdtYWY6Ilx1MDNjMiIsc2lnbWF2OiJcdTAzYzIiLHNpbToiXHUyMjNjIixzaW1kb3Q6Ilx1MmE2YSIsc2ltZToiXHUyMjQzIixzaW1lcToiXHUyMjQzIixzaW1nOiJcdTJhOWUiLHNpbWdFOiJcdTJhYTAiLHNpbWw6Ilx1MmE5ZCIsc2ltbEU6Ilx1MmE5ZiIsc2ltbmU6Ilx1MjI0NiIsc2ltcGx1czoiXHUyYTI0IixzaW1yYXJyOiJcdTI5NzIiLHNsYXJyOiJcdTIxOTAiLFNtYWxsQ2lyY2xlOiJcdTIyMTgiLHNtYWxsc2V0bWludXM6Ilx1MjIxNiIsc21hc2hwOiJcdTJhMzMiLHNtZXBhcnNsOiJcdTI5ZTQiLHNtaWQ6Ilx1MjIyMyIsc21pbGU6Ilx1MjMyMyIsc210OiJcdTJhYWEiLHNtdGU6Ilx1MmFhYyIsc210ZXM6Ilx1MmFhY1x1ZmUwMCIsU09GVGN5OiJcdTA0MmMiLHNvZnRjeToiXHUwNDRjIixzb2xiYXI6Ilx1MjMzZiIsc29sYjoiXHUyOWM0Iixzb2w6Ii8iLFNvcGY6Ilx1ZDgzNVx1ZGQ0YSIsc29wZjoiXHVkODM1XHVkZDY0IixzcGFkZXM6Ilx1MjY2MCIsc3BhZGVzdWl0OiJcdTI2NjAiLHNwYXI6Ilx1MjIyNSIsc3FjYXA6Ilx1MjI5MyIsc3FjYXBzOiJcdTIyOTNcdWZlMDAiLHNxY3VwOiJcdTIyOTQiLHNxY3VwczoiXHUyMjk0XHVmZTAwIixTcXJ0OiJcdTIyMWEiLHNxc3ViOiJcdTIyOGYiLHNxc3ViZToiXHUyMjkxIixzcXN1YnNldDoiXHUyMjhmIixzcXN1YnNldGVxOiJcdTIyOTEiLHNxc3VwOiJcdTIyOTAiLHNxc3VwZToiXHUyMjkyIixzcXN1cHNldDoiXHUyMjkwIixzcXN1cHNldGVxOiJcdTIyOTIiLHNxdWFyZToiXHUyNWExIixTcXVhcmU6Ilx1MjVhMSIsU3F1YXJlSW50ZXJzZWN0aW9uOiJcdTIyOTMiLFNxdWFyZVN1YnNldDoiXHUyMjhmIixTcXVhcmVTdWJzZXRFcXVhbDoiXHUyMjkxIixTcXVhcmVTdXBlcnNldDoiXHUyMjkwIixTcXVhcmVTdXBlcnNldEVxdWFsOiJcdTIyOTIiLFNxdWFyZVVuaW9uOiJcdTIyOTQiLHNxdWFyZjoiXHUyNWFhIixzcXU6Ilx1MjVhMSIsc3F1ZjoiXHUyNWFhIixzcmFycjoiXHUyMTkyIixTc2NyOiJcdWQ4MzVcdWRjYWUiLHNzY3I6Ilx1ZDgzNVx1ZGNjOCIsc3NldG1uOiJcdTIyMTYiLHNzbWlsZToiXHUyMzIzIixzc3RhcmY6Ilx1MjJjNiIsU3RhcjoiXHUyMmM2IixzdGFyOiJcdTI2MDYiLHN0YXJmOiJcdTI2MDUiLHN0cmFpZ2h0ZXBzaWxvbjoiXHUwM2Y1IixzdHJhaWdodHBoaToiXHUwM2Q1IixzdHJuczoiXHhhZiIsc3ViOiJcdTIyODIiLFN1YjoiXHUyMmQwIixzdWJkb3Q6Ilx1MmFiZCIsc3ViRToiXHUyYWM1IixzdWJlOiJcdTIyODYiLHN1YmVkb3Q6Ilx1MmFjMyIsc3VibXVsdDoiXHUyYWMxIixzdWJuRToiXHUyYWNiIixzdWJuZToiXHUyMjhhIixzdWJwbHVzOiJcdTJhYmYiLHN1YnJhcnI6Ilx1Mjk3OSIsc3Vic2V0OiJcdTIyODIiLFN1YnNldDoiXHUyMmQwIixzdWJzZXRlcToiXHUyMjg2IixzdWJzZXRlcXE6Ilx1MmFjNSIsU3Vic2V0RXF1YWw6Ilx1MjI4NiIsc3Vic2V0bmVxOiJcdTIyOGEiLHN1YnNldG5lcXE6Ilx1MmFjYiIsc3Vic2ltOiJcdTJhYzciLHN1YnN1YjoiXHUyYWQ1IixzdWJzdXA6Ilx1MmFkMyIsc3VjY2FwcHJveDoiXHUyYWI4IixzdWNjOiJcdTIyN2IiLHN1Y2NjdXJseWVxOiJcdTIyN2QiLFN1Y2NlZWRzOiJcdTIyN2IiLFN1Y2NlZWRzRXF1YWw6Ilx1MmFiMCIsU3VjY2VlZHNTbGFudEVxdWFsOiJcdTIyN2QiLFN1Y2NlZWRzVGlsZGU6Ilx1MjI3ZiIsc3VjY2VxOiJcdTJhYjAiLHN1Y2NuYXBwcm94OiJcdTJhYmEiLHN1Y2NuZXFxOiJcdTJhYjYiLHN1Y2Nuc2ltOiJcdTIyZTkiLHN1Y2NzaW06Ilx1MjI3ZiIsU3VjaFRoYXQ6Ilx1MjIwYiIsc3VtOiJcdTIyMTEiLFN1bToiXHUyMjExIixzdW5nOiJcdTI2NmEiLHN1cDE6Ilx4YjkiLHN1cDI6Ilx4YjIiLHN1cDM6Ilx4YjMiLHN1cDoiXHUyMjgzIixTdXA6Ilx1MjJkMSIsc3VwZG90OiJcdTJhYmUiLHN1cGRzdWI6Ilx1MmFkOCIsc3VwRToiXHUyYWM2IixzdXBlOiJcdTIyODciLHN1cGVkb3Q6Ilx1MmFjNCIsU3VwZXJzZXQ6Ilx1MjI4MyIsU3VwZXJzZXRFcXVhbDoiXHUyMjg3IixzdXBoc29sOiJcdTI3YzkiLHN1cGhzdWI6Ilx1MmFkNyIsc3VwbGFycjoiXHUyOTdiIixzdXBtdWx0OiJcdTJhYzIiLHN1cG5FOiJcdTJhY2MiLHN1cG5lOiJcdTIyOGIiLHN1cHBsdXM6Ilx1MmFjMCIsc3Vwc2V0OiJcdTIyODMiLFN1cHNldDoiXHUyMmQxIixzdXBzZXRlcToiXHUyMjg3IixzdXBzZXRlcXE6Ilx1MmFjNiIsc3Vwc2V0bmVxOiJcdTIyOGIiLHN1cHNldG5lcXE6Ilx1MmFjYyIsc3Vwc2ltOiJcdTJhYzgiLHN1cHN1YjoiXHUyYWQ0IixzdXBzdXA6Ilx1MmFkNiIsc3dhcmhrOiJcdTI5MjYiLHN3YXJyOiJcdTIxOTkiLHN3QXJyOiJcdTIxZDkiLHN3YXJyb3c6Ilx1MjE5OSIsc3dud2FyOiJcdTI5MmEiLHN6bGlnOiJceGRmIixUYWI6Ilx0Iix0YXJnZXQ6Ilx1MjMxNiIsVGF1OiJcdTAzYTQiLHRhdToiXHUwM2M0Iix0YnJrOiJcdTIzYjQiLFRjYXJvbjoiXHUwMTY0Iix0Y2Fyb246Ilx1MDE2NSIsVGNlZGlsOiJcdTAxNjIiLHRjZWRpbDoiXHUwMTYzIixUY3k6Ilx1MDQyMiIsdGN5OiJcdTA0NDIiLHRkb3Q6Ilx1MjBkYiIsdGVscmVjOiJcdTIzMTUiLFRmcjoiXHVkODM1XHVkZDE3Iix0ZnI6Ilx1ZDgzNVx1ZGQzMSIsdGhlcmU0OiJcdTIyMzQiLHRoZXJlZm9yZToiXHUyMjM0IixUaGVyZWZvcmU6Ilx1MjIzNCIsVGhldGE6Ilx1MDM5OCIsdGhldGE6Ilx1MDNiOCIsdGhldGFzeW06Ilx1MDNkMSIsdGhldGF2OiJcdTAzZDEiLHRoaWNrYXBwcm94OiJcdTIyNDgiLHRoaWNrc2ltOiJcdTIyM2MiLFRoaWNrU3BhY2U6Ilx1MjA1Zlx1MjAwYSIsVGhpblNwYWNlOiJcdTIwMDkiLHRoaW5zcDoiXHUyMDA5Iix0aGthcDoiXHUyMjQ4Iix0aGtzaW06Ilx1MjIzYyIsVEhPUk46Ilx4ZGUiLHRob3JuOiJceGZlIix0aWxkZToiXHUwMmRjIixUaWxkZToiXHUyMjNjIixUaWxkZUVxdWFsOiJcdTIyNDMiLFRpbGRlRnVsbEVxdWFsOiJcdTIyNDUiLFRpbGRlVGlsZGU6Ilx1MjI0OCIsdGltZXNiYXI6Ilx1MmEzMSIsdGltZXNiOiJcdTIyYTAiLHRpbWVzOiJceGQ3Iix0aW1lc2Q6Ilx1MmEzMCIsdGludDoiXHUyMjJkIix0b2VhOiJcdTI5MjgiLHRvcGJvdDoiXHUyMzM2Iix0b3BjaXI6Ilx1MmFmMSIsdG9wOiJcdTIyYTQiLFRvcGY6Ilx1ZDgzNVx1ZGQ0YiIsdG9wZjoiXHVkODM1XHVkZDY1Iix0b3Bmb3JrOiJcdTJhZGEiLHRvc2E6Ilx1MjkyOSIsdHByaW1lOiJcdTIwMzQiLHRyYWRlOiJcdTIxMjIiLFRSQURFOiJcdTIxMjIiLHRyaWFuZ2xlOiJcdTI1YjUiLHRyaWFuZ2xlZG93bjoiXHUyNWJmIix0cmlhbmdsZWxlZnQ6Ilx1MjVjMyIsdHJpYW5nbGVsZWZ0ZXE6Ilx1MjJiNCIsdHJpYW5nbGVxOiJcdTIyNWMiLHRyaWFuZ2xlcmlnaHQ6Ilx1MjViOSIsdHJpYW5nbGVyaWdodGVxOiJcdTIyYjUiLHRyaWRvdDoiXHUyNWVjIix0cmllOiJcdTIyNWMiLHRyaW1pbnVzOiJcdTJhM2EiLFRyaXBsZURvdDoiXHUyMGRiIix0cmlwbHVzOiJcdTJhMzkiLHRyaXNiOiJcdTI5Y2QiLHRyaXRpbWU6Ilx1MmEzYiIsdHJwZXppdW06Ilx1MjNlMiIsVHNjcjoiXHVkODM1XHVkY2FmIix0c2NyOiJcdWQ4MzVcdWRjYzkiLFRTY3k6Ilx1MDQyNiIsdHNjeToiXHUwNDQ2IixUU0hjeToiXHUwNDBiIix0c2hjeToiXHUwNDViIixUc3Ryb2s6Ilx1MDE2NiIsdHN0cm9rOiJcdTAxNjciLHR3aXh0OiJcdTIyNmMiLHR3b2hlYWRsZWZ0YXJyb3c6Ilx1MjE5ZSIsdHdvaGVhZHJpZ2h0YXJyb3c6Ilx1MjFhMCIsVWFjdXRlOiJceGRhIix1YWN1dGU6Ilx4ZmEiLHVhcnI6Ilx1MjE5MSIsVWFycjoiXHUyMTlmIix1QXJyOiJcdTIxZDEiLFVhcnJvY2lyOiJcdTI5NDkiLFVicmN5OiJcdTA0MGUiLHVicmN5OiJcdTA0NWUiLFVicmV2ZToiXHUwMTZjIix1YnJldmU6Ilx1MDE2ZCIsVWNpcmM6Ilx4ZGIiLHVjaXJjOiJceGZiIixVY3k6Ilx1MDQyMyIsdWN5OiJcdTA0NDMiLHVkYXJyOiJcdTIxYzUiLFVkYmxhYzoiXHUwMTcwIix1ZGJsYWM6Ilx1MDE3MSIsdWRoYXI6Ilx1Mjk2ZSIsdWZpc2h0OiJcdTI5N2UiLFVmcjoiXHVkODM1XHVkZDE4Iix1ZnI6Ilx1ZDgzNVx1ZGQzMiIsVWdyYXZlOiJceGQ5Iix1Z3JhdmU6Ilx4ZjkiLHVIYXI6Ilx1Mjk2MyIsdWhhcmw6Ilx1MjFiZiIsdWhhcnI6Ilx1MjFiZSIsdWhibGs6Ilx1MjU4MCIsdWxjb3JuOiJcdTIzMWMiLHVsY29ybmVyOiJcdTIzMWMiLHVsY3JvcDoiXHUyMzBmIix1bHRyaToiXHUyNWY4IixVbWFjcjoiXHUwMTZhIix1bWFjcjoiXHUwMTZiIix1bWw6Ilx4YTgiLFVuZGVyQmFyOiJfIixVbmRlckJyYWNlOiJcdTIzZGYiLFVuZGVyQnJhY2tldDoiXHUyM2I1IixVbmRlclBhcmVudGhlc2lzOiJcdTIzZGQiLFVuaW9uOiJcdTIyYzMiLFVuaW9uUGx1czoiXHUyMjhlIixVb2dvbjoiXHUwMTcyIix1b2dvbjoiXHUwMTczIixVb3BmOiJcdWQ4MzVcdWRkNGMiLHVvcGY6Ilx1ZDgzNVx1ZGQ2NiIsVXBBcnJvd0JhcjoiXHUyOTEyIix1cGFycm93OiJcdTIxOTEiLFVwQXJyb3c6Ilx1MjE5MSIsVXBhcnJvdzoiXHUyMWQxIixVcEFycm93RG93bkFycm93OiJcdTIxYzUiLHVwZG93bmFycm93OiJcdTIxOTUiLFVwRG93bkFycm93OiJcdTIxOTUiLFVwZG93bmFycm93OiJcdTIxZDUiLFVwRXF1aWxpYnJpdW06Ilx1Mjk2ZSIsdXBoYXJwb29ubGVmdDoiXHUyMWJmIix1cGhhcnBvb25yaWdodDoiXHUyMWJlIix1cGx1czoiXHUyMjhlIixVcHBlckxlZnRBcnJvdzoiXHUyMTk2IixVcHBlclJpZ2h0QXJyb3c6Ilx1MjE5NyIsdXBzaToiXHUwM2M1IixVcHNpOiJcdTAzZDIiLHVwc2loOiJcdTAzZDIiLFVwc2lsb246Ilx1MDNhNSIsdXBzaWxvbjoiXHUwM2M1IixVcFRlZUFycm93OiJcdTIxYTUiLFVwVGVlOiJcdTIyYTUiLHVwdXBhcnJvd3M6Ilx1MjFjOCIsdXJjb3JuOiJcdTIzMWQiLHVyY29ybmVyOiJcdTIzMWQiLHVyY3JvcDoiXHUyMzBlIixVcmluZzoiXHUwMTZlIix1cmluZzoiXHUwMTZmIix1cnRyaToiXHUyNWY5IixVc2NyOiJcdWQ4MzVcdWRjYjAiLHVzY3I6Ilx1ZDgzNVx1ZGNjYSIsdXRkb3Q6Ilx1MjJmMCIsVXRpbGRlOiJcdTAxNjgiLHV0aWxkZToiXHUwMTY5Iix1dHJpOiJcdTI1YjUiLHV0cmlmOiJcdTI1YjQiLHV1YXJyOiJcdTIxYzgiLFV1bWw6Ilx4ZGMiLHV1bWw6Ilx4ZmMiLHV3YW5nbGU6Ilx1MjlhNyIsdmFuZ3J0OiJcdTI5OWMiLHZhcmVwc2lsb246Ilx1MDNmNSIsdmFya2FwcGE6Ilx1MDNmMCIsdmFybm90aGluZzoiXHUyMjA1Iix2YXJwaGk6Ilx1MDNkNSIsdmFycGk6Ilx1MDNkNiIsdmFycHJvcHRvOiJcdTIyMWQiLHZhcnI6Ilx1MjE5NSIsdkFycjoiXHUyMWQ1Iix2YXJyaG86Ilx1MDNmMSIsdmFyc2lnbWE6Ilx1MDNjMiIsdmFyc3Vic2V0bmVxOiJcdTIyOGFcdWZlMDAiLHZhcnN1YnNldG5lcXE6Ilx1MmFjYlx1ZmUwMCIsdmFyc3Vwc2V0bmVxOiJcdTIyOGJcdWZlMDAiLHZhcnN1cHNldG5lcXE6Ilx1MmFjY1x1ZmUwMCIsdmFydGhldGE6Ilx1MDNkMSIsdmFydHJpYW5nbGVsZWZ0OiJcdTIyYjIiLHZhcnRyaWFuZ2xlcmlnaHQ6Ilx1MjJiMyIsdkJhcjoiXHUyYWU4IixWYmFyOiJcdTJhZWIiLHZCYXJ2OiJcdTJhZTkiLFZjeToiXHUwNDEyIix2Y3k6Ilx1MDQzMiIsdmRhc2g6Ilx1MjJhMiIsdkRhc2g6Ilx1MjJhOCIsVmRhc2g6Ilx1MjJhOSIsVkRhc2g6Ilx1MjJhYiIsVmRhc2hsOiJcdTJhZTYiLHZlZWJhcjoiXHUyMmJiIix2ZWU6Ilx1MjIyOCIsVmVlOiJcdTIyYzEiLHZlZWVxOiJcdTIyNWEiLHZlbGxpcDoiXHUyMmVlIix2ZXJiYXI6InwiLFZlcmJhcjoiXHUyMDE2Iix2ZXJ0OiJ8IixWZXJ0OiJcdTIwMTYiLFZlcnRpY2FsQmFyOiJcdTIyMjMiLFZlcnRpY2FsTGluZToifCIsVmVydGljYWxTZXBhcmF0b3I6Ilx1Mjc1OCIsVmVydGljYWxUaWxkZToiXHUyMjQwIixWZXJ5VGhpblNwYWNlOiJcdTIwMGEiLFZmcjoiXHVkODM1XHVkZDE5Iix2ZnI6Ilx1ZDgzNVx1ZGQzMyIsdmx0cmk6Ilx1MjJiMiIsdm5zdWI6Ilx1MjI4Mlx1MjBkMiIsdm5zdXA6Ilx1MjI4M1x1MjBkMiIsVm9wZjoiXHVkODM1XHVkZDRkIix2b3BmOiJcdWQ4MzVcdWRkNjciLHZwcm9wOiJcdTIyMWQiLHZydHJpOiJcdTIyYjMiLFZzY3I6Ilx1ZDgzNVx1ZGNiMSIsdnNjcjoiXHVkODM1XHVkY2NiIix2c3VibkU6Ilx1MmFjYlx1ZmUwMCIsdnN1Ym5lOiJcdTIyOGFcdWZlMDAiLHZzdXBuRToiXHUyYWNjXHVmZTAwIix2c3VwbmU6Ilx1MjI4Ylx1ZmUwMCIsVnZkYXNoOiJcdTIyYWEiLHZ6aWd6YWc6Ilx1Mjk5YSIsV2NpcmM6Ilx1MDE3NCIsd2NpcmM6Ilx1MDE3NSIsd2VkYmFyOiJcdTJhNWYiLHdlZGdlOiJcdTIyMjciLFdlZGdlOiJcdTIyYzAiLHdlZGdlcToiXHUyMjU5Iix3ZWllcnA6Ilx1MjExOCIsV2ZyOiJcdWQ4MzVcdWRkMWEiLHdmcjoiXHVkODM1XHVkZDM0IixXb3BmOiJcdWQ4MzVcdWRkNGUiLHdvcGY6Ilx1ZDgzNVx1ZGQ2OCIsd3A6Ilx1MjExOCIsd3I6Ilx1MjI0MCIsd3JlYXRoOiJcdTIyNDAiLFdzY3I6Ilx1ZDgzNVx1ZGNiMiIsd3NjcjoiXHVkODM1XHVkY2NjIix4Y2FwOiJcdTIyYzIiLHhjaXJjOiJcdTI1ZWYiLHhjdXA6Ilx1MjJjMyIseGR0cmk6Ilx1MjViZCIsWGZyOiJcdWQ4MzVcdWRkMWIiLHhmcjoiXHVkODM1XHVkZDM1Iix4aGFycjoiXHUyN2Y3Iix4aEFycjoiXHUyN2ZhIixYaToiXHUwMzllIix4aToiXHUwM2JlIix4bGFycjoiXHUyN2Y1Iix4bEFycjoiXHUyN2Y4Iix4bWFwOiJcdTI3ZmMiLHhuaXM6Ilx1MjJmYiIseG9kb3Q6Ilx1MmEwMCIsWG9wZjoiXHVkODM1XHVkZDRmIix4b3BmOiJcdWQ4MzVcdWRkNjkiLHhvcGx1czoiXHUyYTAxIix4b3RpbWU6Ilx1MmEwMiIseHJhcnI6Ilx1MjdmNiIseHJBcnI6Ilx1MjdmOSIsWHNjcjoiXHVkODM1XHVkY2IzIix4c2NyOiJcdWQ4MzVcdWRjY2QiLHhzcWN1cDoiXHUyYTA2Iix4dXBsdXM6Ilx1MmEwNCIseHV0cmk6Ilx1MjViMyIseHZlZToiXHUyMmMxIix4d2VkZ2U6Ilx1MjJjMCIsWWFjdXRlOiJceGRkIix5YWN1dGU6Ilx4ZmQiLFlBY3k6Ilx1MDQyZiIseWFjeToiXHUwNDRmIixZY2lyYzoiXHUwMTc2Iix5Y2lyYzoiXHUwMTc3IixZY3k6Ilx1MDQyYiIseWN5OiJcdTA0NGIiLHllbjoiXHhhNSIsWWZyOiJcdWQ4MzVcdWRkMWMiLHlmcjoiXHVkODM1XHVkZDM2IixZSWN5OiJcdTA0MDciLHlpY3k6Ilx1MDQ1NyIsWW9wZjoiXHVkODM1XHVkZDUwIix5b3BmOiJcdWQ4MzVcdWRkNmEiLFlzY3I6Ilx1ZDgzNVx1ZGNiNCIseXNjcjoiXHVkODM1XHVkY2NlIixZVWN5OiJcdTA0MmUiLHl1Y3k6Ilx1MDQ0ZSIseXVtbDoiXHhmZiIsWXVtbDoiXHUwMTc4IixaYWN1dGU6Ilx1MDE3OSIsemFjdXRlOiJcdTAxN2EiLFpjYXJvbjoiXHUwMTdkIix6Y2Fyb246Ilx1MDE3ZSIsWmN5OiJcdTA0MTciLHpjeToiXHUwNDM3IixaZG90OiJcdTAxN2IiLHpkb3Q6Ilx1MDE3YyIsemVldHJmOiJcdTIxMjgiLFplcm9XaWR0aFNwYWNlOiJcdTIwMGIiLFpldGE6Ilx1MDM5NiIsemV0YToiXHUwM2I2Iix6ZnI6Ilx1ZDgzNVx1ZGQzNyIsWmZyOiJcdTIxMjgiLFpIY3k6Ilx1MDQxNiIsemhjeToiXHUwNDM2Iix6aWdyYXJyOiJcdTIxZGQiLHpvcGY6Ilx1ZDgzNVx1ZGQ2YiIsWm9wZjoiXHUyMTI0Iixac2NyOiJcdWQ4MzVcdWRjYjUiLHpzY3I6Ilx1ZDgzNVx1ZGNjZiIsendqOiJcdTIwMGQiLHp3bmo6Ilx1MjAwYyJ9fSxmdW5jdGlvbihlLHQpe2UuZXhwb3J0cz0vWyEtIyUtXCosLVwvOjtcP0BcWy1cXV9ce1x9XHhBMVx4QTdceEFCXHhCNlx4QjdceEJCXHhCRlx1MDM3RVx1MDM4N1x1MDU1QS1cdTA1NUZcdTA1ODlcdTA1OEFcdTA1QkVcdTA1QzBcdTA1QzNcdTA1QzZcdTA1RjNcdTA1RjRcdTA2MDlcdTA2MEFcdTA2MENcdTA2MERcdTA2MUJcdTA2MUVcdTA2MUZcdTA2NkEtXHUwNjZEXHUwNkQ0XHUwNzAwLVx1MDcwRFx1MDdGNy1cdTA3RjlcdTA4MzAtXHUwODNFXHUwODVFXHUwOTY0XHUwOTY1XHUwOTcwXHUwOUZEXHUwQUYwXHUwREY0XHUwRTRGXHUwRTVBXHUwRTVCXHUwRjA0LVx1MEYxMlx1MEYxNFx1MEYzQS1cdTBGM0RcdTBGODVcdTBGRDAtXHUwRkQ0XHUwRkQ5XHUwRkRBXHUxMDRBLVx1MTA0Rlx1MTBGQlx1MTM2MC1cdTEzNjhcdTE0MDBcdTE2NkRcdTE2NkVcdTE2OUJcdTE2OUNcdTE2RUItXHUxNkVEXHUxNzM1XHUxNzM2XHUxN0Q0LVx1MTdENlx1MTdEOC1cdTE3REFcdTE4MDAtXHUxODBBXHUxOTQ0XHUxOTQ1XHUxQTFFXHUxQTFGXHUxQUEwLVx1MUFBNlx1MUFBOC1cdTFBQURcdTFCNUEtXHUxQjYwXHUxQkZDLVx1MUJGRlx1MUMzQi1cdTFDM0ZcdTFDN0VcdTFDN0ZcdTFDQzAtXHUxQ0M3XHUxQ0QzXHUyMDEwLVx1MjAyN1x1MjAzMC1cdTIwNDNcdTIwNDUtXHUyMDUxXHUyMDUzLVx1MjA1RVx1MjA3RFx1MjA3RVx1MjA4RFx1MjA4RVx1MjMwOC1cdTIzMEJcdTIzMjlcdTIzMkFcdTI3NjgtXHUyNzc1XHUyN0M1XHUyN0M2XHUyN0U2LVx1MjdFRlx1Mjk4My1cdTI5OThcdTI5RDgtXHUyOURCXHUyOUZDXHUyOUZEXHUyQ0Y5LVx1MkNGQ1x1MkNGRVx1MkNGRlx1MkQ3MFx1MkUwMC1cdTJFMkVcdTJFMzAtXHUyRTQ5XHUzMDAxLVx1MzAwM1x1MzAwOC1cdTMwMTFcdTMwMTQtXHUzMDFGXHUzMDMwXHUzMDNEXHUzMEEwXHUzMEZCXHVBNEZFXHVBNEZGXHVBNjBELVx1QTYwRlx1QTY3M1x1QTY3RVx1QTZGMi1cdUE2RjdcdUE4NzQtXHVBODc3XHVBOENFXHVBOENGXHVBOEY4LVx1QThGQVx1QThGQ1x1QTkyRVx1QTkyRlx1QTk1Rlx1QTlDMS1cdUE5Q0RcdUE5REVcdUE5REZcdUFBNUMtXHVBQTVGXHVBQURFXHVBQURGXHVBQUYwXHVBQUYxXHVBQkVCXHVGRDNFXHVGRDNGXHVGRTEwLVx1RkUxOVx1RkUzMC1cdUZFNTJcdUZFNTQtXHVGRTYxXHVGRTYzXHVGRTY4XHVGRTZBXHVGRTZCXHVGRjAxLVx1RkYwM1x1RkYwNS1cdUZGMEFcdUZGMEMtXHVGRjBGXHVGRjFBXHVGRjFCXHVGRjFGXHVGRjIwXHVGRjNCLVx1RkYzRFx1RkYzRlx1RkY1Qlx1RkY1RFx1RkY1Ri1cdUZGNjVdfFx1RDgwMFtcdUREMDAtXHVERDAyXHVERjlGXHVERkQwXXxcdUQ4MDFcdURENkZ8XHVEODAyW1x1REM1N1x1REQxRlx1REQzRlx1REU1MC1cdURFNThcdURFN0ZcdURFRjAtXHVERUY2XHVERjM5LVx1REYzRlx1REY5OS1cdURGOUNdfFx1RDgwNFtcdURDNDctXHVEQzREXHVEQ0JCXHVEQ0JDXHVEQ0JFLVx1RENDMVx1REQ0MC1cdURENDNcdURENzRcdURENzVcdUREQzUtXHVEREM5XHVERENEXHVERERCXHVERERELVx1RERERlx1REUzOC1cdURFM0RcdURFQTldfFx1RDgwNVtcdURDNEItXHVEQzRGXHVEQzVCXHVEQzVEXHVEQ0M2XHVEREMxLVx1REREN1x1REU0MS1cdURFNDNcdURFNjAtXHVERTZDXHVERjNDLVx1REYzRV18XHVEODA2W1x1REUzRi1cdURFNDZcdURFOUEtXHVERTlDXHVERTlFLVx1REVBMl18XHVEODA3W1x1REM0MS1cdURDNDVcdURDNzBcdURDNzFdfFx1RDgwOVtcdURDNzAtXHVEQzc0XXxcdUQ4MUFbXHVERTZFXHVERTZGXHVERUY1XHVERjM3LVx1REYzQlx1REY0NF18XHVEODJGXHVEQzlGfFx1RDgzNltcdURFODctXHVERThCXXxcdUQ4M0FbXHVERDVFXHVERDVGXS99LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9IjxbQS1aYS16XVtBLVphLXowLTlcXC1dKig/OlxccytbYS16QS1aXzpdW2EtekEtWjAtOTouXy1dKig/Olxccyo9XFxzKig/OlteXCInPTw+YFxceDAwLVxceDIwXSt8J1teJ10qJ3xcIlteXCJdKlwiKSk/KSpcXHMqXFwvPz4iLGk9IjxcXC9bQS1aYS16XVtBLVphLXowLTlcXC1dKlxccyo+IixvPW5ldyBSZWdFeHAoIl4oPzoiK3IrInwiK2krInxceDNjIS0tLS1ceDNlfFx4M2MhLS0oPzotP1tePi1dKSg/Oi0/W14tXSkqLS1ceDNlfDxbP10uKj9bP10+fDwhW0EtWl0rXFxzK1tePl0qPnw8IVxcW0NEQVRBXFxbW1xcc1xcU10qP1xcXVxcXT4pIiksYT1uZXcgUmVnRXhwKCJeKD86IityKyJ8IitpKyIpIik7ZS5leHBvcnRzLkhUTUxfVEFHX1JFPW8sZS5leHBvcnRzLkhUTUxfT1BFTl9DTE9TRV9UQUdfUkU9YX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHMudG9rZW5pemU9ZnVuY3Rpb24oZSx0KXt2YXIgbixyLGksbyxhLHM9ZS5wb3MsdT1lLnNyYy5jaGFyQ29kZUF0KHMpO2lmKHQpcmV0dXJuITE7aWYoMTI2IT09dSlyZXR1cm4hMTtpZihyPWUuc2NhbkRlbGltcyhlLnBvcywhMCksbz1yLmxlbmd0aCxhPVN0cmluZy5mcm9tQ2hhckNvZGUodSksbzwyKXJldHVybiExO2ZvcihvJTImJihpPWUucHVzaCgidGV4dCIsIiIsMCksaS5jb250ZW50PWEsby0tKSxuPTA7bjxvO24rPTIpaT1lLnB1c2goInRleHQiLCIiLDApLGkuY29udGVudD1hK2EsZS5kZWxpbWl0ZXJzLnB1c2goe21hcmtlcjp1LGp1bXA6bix0b2tlbjplLnRva2Vucy5sZW5ndGgtMSxsZXZlbDplLmxldmVsLGVuZDotMSxvcGVuOnIuY2FuX29wZW4sY2xvc2U6ci5jYW5fY2xvc2V9KTtyZXR1cm4gZS5wb3MrPXIubGVuZ3RoLCEwfSxlLmV4cG9ydHMucG9zdFByb2Nlc3M9ZnVuY3Rpb24oZSl7dmFyIHQsbixyLGksbyxhPVtdLHM9ZS5kZWxpbWl0ZXJzLHU9ZS5kZWxpbWl0ZXJzLmxlbmd0aDtmb3IodD0wO3Q8dTt0Kyspcj1zW3RdLDEyNj09PXIubWFya2VyJiYtMSE9PXIuZW5kJiYoaT1zW3IuZW5kXSxvPWUudG9rZW5zW3IudG9rZW5dLG8udHlwZT0ic19vcGVuIixvLnRhZz0icyIsby5uZXN0aW5nPTEsby5tYXJrdXA9In5+IixvLmNvbnRlbnQ9IiIsbz1lLnRva2Vuc1tpLnRva2VuXSxvLnR5cGU9InNfY2xvc2UiLG8udGFnPSJzIixvLm5lc3Rpbmc9LTEsby5tYXJrdXA9In5+IixvLmNvbnRlbnQ9IiIsInRleHQiPT09ZS50b2tlbnNbaS50b2tlbi0xXS50eXBlJiYifiI9PT1lLnRva2Vuc1tpLnRva2VuLTFdLmNvbnRlbnQmJmEucHVzaChpLnRva2VuLTEpKTtmb3IoO2EubGVuZ3RoOyl7Zm9yKHQ9YS5wb3AoKSxuPXQrMTtuPGUudG9rZW5zLmxlbmd0aCYmInNfY2xvc2UiPT09ZS50b2tlbnNbbl0udHlwZTspbisrO24tLSx0IT09biYmKG89ZS50b2tlbnNbbl0sZS50b2tlbnNbbl09ZS50b2tlbnNbdF0sZS50b2tlbnNbdF09byl9fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHMudG9rZW5pemU9ZnVuY3Rpb24oZSx0KXt2YXIgbixyLGksbz1lLnBvcyxhPWUuc3JjLmNoYXJDb2RlQXQobyk7aWYodClyZXR1cm4hMTtpZig5NSE9PWEmJjQyIT09YSlyZXR1cm4hMTtmb3Iocj1lLnNjYW5EZWxpbXMoZS5wb3MsNDI9PT1hKSxuPTA7bjxyLmxlbmd0aDtuKyspaT1lLnB1c2goInRleHQiLCIiLDApLGkuY29udGVudD1TdHJpbmcuZnJvbUNoYXJDb2RlKGEpLGUuZGVsaW1pdGVycy5wdXNoKHttYXJrZXI6YSxsZW5ndGg6ci5sZW5ndGgsanVtcDpuLHRva2VuOmUudG9rZW5zLmxlbmd0aC0xLGxldmVsOmUubGV2ZWwsZW5kOi0xLG9wZW46ci5jYW5fb3BlbixjbG9zZTpyLmNhbl9jbG9zZX0pO3JldHVybiBlLnBvcys9ci5sZW5ndGgsITB9LGUuZXhwb3J0cy5wb3N0UHJvY2Vzcz1mdW5jdGlvbihlKXt2YXIgdCxuLHIsaSxvLGEscz1lLmRlbGltaXRlcnMsdT1lLmRlbGltaXRlcnMubGVuZ3RoO2Zvcih0PXUtMTt0Pj0wO3QtLSluPXNbdF0sOTUhPT1uLm1hcmtlciYmNDIhPT1uLm1hcmtlcnx8LTEhPT1uLmVuZCYmKHI9c1tuLmVuZF0sYT10PjAmJnNbdC0xXS5lbmQ9PT1uLmVuZCsxJiZzW3QtMV0udG9rZW49PT1uLnRva2VuLTEmJnNbbi5lbmQrMV0udG9rZW49PT1yLnRva2VuKzEmJnNbdC0xXS5tYXJrZXI9PT1uLm1hcmtlcixvPVN0cmluZy5mcm9tQ2hhckNvZGUobi5tYXJrZXIpLGk9ZS50b2tlbnNbbi50b2tlbl0saS50eXBlPWE/InN0cm9uZ19vcGVuIjoiZW1fb3BlbiIsaS50YWc9YT8ic3Ryb25nIjoiZW0iLGkubmVzdGluZz0xLGkubWFya3VwPWE/bytvOm8saS5jb250ZW50PSIiLGk9ZS50b2tlbnNbci50b2tlbl0saS50eXBlPWE/InN0cm9uZ19jbG9zZSI6ImVtX2Nsb3NlIixpLnRhZz1hPyJzdHJvbmciOiJlbSIsaS5uZXN0aW5nPS0xLGkubWFya3VwPWE/bytvOm8saS5jb250ZW50PSIiLGEmJihlLnRva2Vuc1tzW3QtMV0udG9rZW5dLmNvbnRlbnQ9IiIsZS50b2tlbnNbc1tuLmVuZCsxXS50b2tlbl0uY29udGVudD0iIix0LS0pKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLDEpLmZvckVhY2goZnVuY3Rpb24odCl7dCYmT2JqZWN0LmtleXModCkuZm9yRWFjaChmdW5jdGlvbihuKXtlW25dPXRbbl19KX0pLGV9ZnVuY3Rpb24gaShlKXtyZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGUpfWZ1bmN0aW9uIG8oZSl7cmV0dXJuIltvYmplY3QgU3RyaW5nXSI9PT1pKGUpfWZ1bmN0aW9uIGEoZSl7cmV0dXJuIltvYmplY3QgT2JqZWN0XSI9PT1pKGUpfWZ1bmN0aW9uIHMoZSl7cmV0dXJuIltvYmplY3QgUmVnRXhwXSI9PT1pKGUpfWZ1bmN0aW9uIHUoZSl7cmV0dXJuIltvYmplY3QgRnVuY3Rpb25dIj09PWkoZSl9ZnVuY3Rpb24gYyhlKXtyZXR1cm4gZS5yZXBsYWNlKC9bLj8qK14kW1xdXFwoKXt9fC1dL2csIlxcJCYiKX1mdW5jdGlvbiBsKGUpe3JldHVybiBPYmplY3Qua2V5cyhlfHx7fSkucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGV8fHYuaGFzT3duUHJvcGVydHkodCl9LCExKX1mdW5jdGlvbiBwKGUpe2UuX19pbmRleF9fPS0xLGUuX190ZXh0X2NhY2hlX189IiJ9ZnVuY3Rpb24gZihlKXtyZXR1cm4gZnVuY3Rpb24odCxuKXt2YXIgcj10LnNsaWNlKG4pO3JldHVybiBlLnRlc3Qocik/ci5tYXRjaChlKVswXS5sZW5ndGg6MH19ZnVuY3Rpb24gZCgpe3JldHVybiBmdW5jdGlvbihlLHQpe3Qubm9ybWFsaXplKGUpfX1mdW5jdGlvbiBoKGUpe2Z1bmN0aW9uIHQoZSl7cmV0dXJuIGUucmVwbGFjZSgiJVRMRFMlIixpLnNyY190bGRzKX1mdW5jdGlvbiByKGUsdCl7dGhyb3cgbmV3IEVycm9yKCcoTGlua2lmeUl0KSBJbnZhbGlkIHNjaGVtYSAiJytlKyciOiAnK3QpfXZhciBpPWUucmU9big1ODgpKGUuX19vcHRzX18pLGw9ZS5fX3RsZHNfXy5zbGljZSgpO2Uub25Db21waWxlKCksZS5fX3RsZHNfcmVwbGFjZWRfX3x8bC5wdXNoKHgpLGwucHVzaChpLnNyY194biksaS5zcmNfdGxkcz1sLmpvaW4oInwiKSxpLmVtYWlsX2Z1enp5PVJlZ0V4cCh0KGkudHBsX2VtYWlsX2Z1enp5KSwiaSIpLGkubGlua19mdXp6eT1SZWdFeHAodChpLnRwbF9saW5rX2Z1enp5KSwiaSIpLGkubGlua19ub19pcF9mdXp6eT1SZWdFeHAodChpLnRwbF9saW5rX25vX2lwX2Z1enp5KSwiaSIpLGkuaG9zdF9mdXp6eV90ZXN0PVJlZ0V4cCh0KGkudHBsX2hvc3RfZnV6enlfdGVzdCksImkiKTt2YXIgaD1bXTtlLl9fY29tcGlsZWRfXz17fSxPYmplY3Qua2V5cyhlLl9fc2NoZW1hc19fKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe3ZhciBuPWUuX19zY2hlbWFzX19bdF07aWYobnVsbCE9PW4pe3ZhciBpPXt2YWxpZGF0ZTpudWxsLGxpbms6bnVsbH07cmV0dXJuIGUuX19jb21waWxlZF9fW3RdPWksYShuKT8ocyhuLnZhbGlkYXRlKT9pLnZhbGlkYXRlPWYobi52YWxpZGF0ZSk6dShuLnZhbGlkYXRlKT9pLnZhbGlkYXRlPW4udmFsaWRhdGU6cih0LG4pLHZvaWQodShuLm5vcm1hbGl6ZSk/aS5ub3JtYWxpemU9bi5ub3JtYWxpemU6bi5ub3JtYWxpemU/cih0LG4pOmkubm9ybWFsaXplPWQoKSkpOm8obik/dm9pZCBoLnB1c2godCk6dm9pZCByKHQsbil9fSksaC5mb3JFYWNoKGZ1bmN0aW9uKHQpe2UuX19jb21waWxlZF9fW2UuX19zY2hlbWFzX19bdF1dJiYoZS5fX2NvbXBpbGVkX19bdF0udmFsaWRhdGU9ZS5fX2NvbXBpbGVkX19bZS5fX3NjaGVtYXNfX1t0XV0udmFsaWRhdGUsZS5fX2NvbXBpbGVkX19bdF0ubm9ybWFsaXplPWUuX19jb21waWxlZF9fW2UuX19zY2hlbWFzX19bdF1dLm5vcm1hbGl6ZSl9KSxlLl9fY29tcGlsZWRfX1siIl09e3ZhbGlkYXRlOm51bGwsbm9ybWFsaXplOmQoKX07dmFyIG09T2JqZWN0LmtleXMoZS5fX2NvbXBpbGVkX18pLmZpbHRlcihmdW5jdGlvbih0KXtyZXR1cm4gdC5sZW5ndGg+MCYmZS5fX2NvbXBpbGVkX19bdF19KS5tYXAoYykuam9pbigifCIpO2UucmUuc2NoZW1hX3Rlc3Q9UmVnRXhwKCIoXnwoPyFfKSg/Ols+PFx1ZmY1Y118IitpLnNyY19aUENjKyIpKSgiK20rIikiLCJpIiksZS5yZS5zY2hlbWFfc2VhcmNoPVJlZ0V4cCgiKF58KD8hXykoPzpbPjxcdWZmNWNdfCIraS5zcmNfWlBDYysiKSkoIittKyIpIiwiaWciKSxlLnJlLnByZXRlc3Q9UmVnRXhwKCIoIitlLnJlLnNjaGVtYV90ZXN0LnNvdXJjZSsiKXwoIitlLnJlLmhvc3RfZnV6enlfdGVzdC5zb3VyY2UrIil8QCIsImkiKSxwKGUpfWZ1bmN0aW9uIG0oZSx0KXt2YXIgbj1lLl9faW5kZXhfXyxyPWUuX19sYXN0X2luZGV4X18saT1lLl9fdGV4dF9jYWNoZV9fLnNsaWNlKG4scik7dGhpcy5zY2hlbWE9ZS5fX3NjaGVtYV9fLnRvTG93ZXJDYXNlKCksdGhpcy5pbmRleD1uK3QsdGhpcy5sYXN0SW5kZXg9cit0LHRoaXMucmF3PWksdGhpcy50ZXh0PWksdGhpcy51cmw9aX1mdW5jdGlvbiBnKGUsdCl7dmFyIG49bmV3IG0oZSx0KTtyZXR1cm4gZS5fX2NvbXBpbGVkX19bbi5zY2hlbWFdLm5vcm1hbGl6ZShuLGUpLG59ZnVuY3Rpb24geShlLHQpe2lmKCEodGhpcyBpbnN0YW5jZW9mIHkpKXJldHVybiBuZXcgeShlLHQpO3R8fGwoZSkmJih0PWUsZT17fSksdGhpcy5fX29wdHNfXz1yKHt9LHYsdCksdGhpcy5fX2luZGV4X189LTEsdGhpcy5fX2xhc3RfaW5kZXhfXz0tMSx0aGlzLl9fc2NoZW1hX189IiIsdGhpcy5fX3RleHRfY2FjaGVfXz0iIix0aGlzLl9fc2NoZW1hc19fPXIoe30sYixlKSx0aGlzLl9fY29tcGlsZWRfXz17fSx0aGlzLl9fdGxkc19fPUMsdGhpcy5fX3RsZHNfcmVwbGFjZWRfXz0hMSx0aGlzLnJlPXt9LGgodGhpcyl9dmFyIHY9e2Z1enp5TGluazohMCxmdXp6eUVtYWlsOiEwLGZ1enp5SVA6ITF9LGI9eyJodHRwOiI6e3ZhbGlkYXRlOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1lLnNsaWNlKHQpO3JldHVybiBuLnJlLmh0dHB8fChuLnJlLmh0dHA9bmV3IFJlZ0V4cCgiXlxcL1xcLyIrbi5yZS5zcmNfYXV0aCtuLnJlLnNyY19ob3N0X3BvcnRfc3RyaWN0K24ucmUuc3JjX3BhdGgsImkiKSksbi5yZS5odHRwLnRlc3Qocik/ci5tYXRjaChuLnJlLmh0dHApWzBdLmxlbmd0aDowfX0sImh0dHBzOiI6Imh0dHA6IiwiZnRwOiI6Imh0dHA6IiwiLy8iOnt2YWxpZGF0ZTpmdW5jdGlvbihlLHQsbil7dmFyIHI9ZS5zbGljZSh0KTtyZXR1cm4gbi5yZS5ub19odHRwfHwobi5yZS5ub19odHRwPW5ldyBSZWdFeHAoIl4iK24ucmUuc3JjX2F1dGgrIig/OmxvY2FsaG9zdHwoPzooPzoiK24ucmUuc3JjX2RvbWFpbisiKVxcLikrIituLnJlLnNyY19kb21haW5fcm9vdCsiKSIrbi5yZS5zcmNfcG9ydCtuLnJlLnNyY19ob3N0X3Rlcm1pbmF0b3Irbi5yZS5zcmNfcGF0aCwiaSIpKSxuLnJlLm5vX2h0dHAudGVzdChyKT90Pj0zJiYiOiI9PT1lW3QtM10/MDp0Pj0zJiYiLyI9PT1lW3QtM10/MDpyLm1hdGNoKG4ucmUubm9faHR0cClbMF0ubGVuZ3RoOjB9fSwibWFpbHRvOiI6e3ZhbGlkYXRlOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1lLnNsaWNlKHQpO3JldHVybiBuLnJlLm1haWx0b3x8KG4ucmUubWFpbHRvPW5ldyBSZWdFeHAoIl4iK24ucmUuc3JjX2VtYWlsX25hbWUrIkAiK24ucmUuc3JjX2hvc3Rfc3RyaWN0LCJpIikpLG4ucmUubWFpbHRvLnRlc3Qocik/ci5tYXRjaChuLnJlLm1haWx0bylbMF0ubGVuZ3RoOjB9fX0seD0iYVtjZGVmZ2lsbW5vcXJzdHV3eHpdfGJbYWJkZWZnaGlqbW5vcnN0dnd5el18Y1thY2RmZ2hpa2xtbm9ydXZ3eHl6XXxkW2Vqa21vel18ZVtjZWdyc3R1XXxmW2lqa21vcl18Z1thYmRlZmdoaWxtbnBxcnN0dXd5XXxoW2ttbnJ0dV18aVtkZWxtbm9xcnN0XXxqW2Vtb3BdfGtbZWdoaW1ucHJ3eXpdfGxbYWJjaWtyc3R1dnldfG1bYWNkZWdoa2xtbm9wcXJzdHV2d3h5el18blthY2VmZ2lsb3BydXpdfG9tfHBbYWVmZ2hrbG1ucnN0d3ldfHFhfHJbZW9zdXddfHNbYWJjZGVnaGlqa2xtbm9ydHV2eHl6XXx0W2NkZmdoamtsbW5vcnR2d3pdfHVbYWdrc3l6XXx2W2FjZWdpbnVdfHdbZnNdfHlbZXRdfHpbYW13XSIsQz0iYml6fGNvbXxlZHV8Z292fG5ldHxvcmd8cHJvfHdlYnx4eHh8YWVyb3xhc2lhfGNvb3B8aW5mb3xtdXNldW18bmFtZXxzaG9wfFx1MDQ0MFx1MDQ0NCIuc3BsaXQoInwiKTt5LnByb3RvdHlwZS5hZGQ9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdGhpcy5fX3NjaGVtYXNfX1tlXT10LGgodGhpcyksdGhpc30seS5wcm90b3R5cGUuc2V0PWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLl9fb3B0c19fPXIodGhpcy5fX29wdHNfXyxlKSx0aGlzfSx5LnByb3RvdHlwZS50ZXN0PWZ1bmN0aW9uKGUpe2lmKHRoaXMuX190ZXh0X2NhY2hlX189ZSx0aGlzLl9faW5kZXhfXz0tMSwhZS5sZW5ndGgpcmV0dXJuITE7dmFyIHQsbixyLGksbyxhLHMsdTtpZih0aGlzLnJlLnNjaGVtYV90ZXN0LnRlc3QoZSkpZm9yKHM9dGhpcy5yZS5zY2hlbWFfc2VhcmNoLHMubGFzdEluZGV4PTA7bnVsbCE9PSh0PXMuZXhlYyhlKSk7KWlmKGk9dGhpcy50ZXN0U2NoZW1hQXQoZSx0WzJdLHMubGFzdEluZGV4KSl7dGhpcy5fX3NjaGVtYV9fPXRbMl0sdGhpcy5fX2luZGV4X189dC5pbmRleCt0WzFdLmxlbmd0aCx0aGlzLl9fbGFzdF9pbmRleF9fPXQuaW5kZXgrdFswXS5sZW5ndGgraTticmVha31yZXR1cm4gdGhpcy5fX29wdHNfXy5mdXp6eUxpbmsmJnRoaXMuX19jb21waWxlZF9fWyJodHRwOiJdJiYodT1lLnNlYXJjaCh0aGlzLnJlLmhvc3RfZnV6enlfdGVzdCkpPj0wJiYodGhpcy5fX2luZGV4X188MHx8dTx0aGlzLl9faW5kZXhfXykmJm51bGwhPT0obj1lLm1hdGNoKHRoaXMuX19vcHRzX18uZnV6enlJUD90aGlzLnJlLmxpbmtfZnV6enk6dGhpcy5yZS5saW5rX25vX2lwX2Z1enp5KSkmJihvPW4uaW5kZXgrblsxXS5sZW5ndGgsKHRoaXMuX19pbmRleF9fPDB8fG88dGhpcy5fX2luZGV4X18pJiYodGhpcy5fX3NjaGVtYV9fPSIiLHRoaXMuX19pbmRleF9fPW8sdGhpcy5fX2xhc3RfaW5kZXhfXz1uLmluZGV4K25bMF0ubGVuZ3RoKSksdGhpcy5fX29wdHNfXy5mdXp6eUVtYWlsJiZ0aGlzLl9fY29tcGlsZWRfX1sibWFpbHRvOiJdJiZlLmluZGV4T2YoIkAiKT49MCYmbnVsbCE9PShyPWUubWF0Y2godGhpcy5yZS5lbWFpbF9mdXp6eSkpJiYobz1yLmluZGV4K3JbMV0ubGVuZ3RoLGE9ci5pbmRleCtyWzBdLmxlbmd0aCwodGhpcy5fX2luZGV4X188MHx8bzx0aGlzLl9faW5kZXhfX3x8bz09PXRoaXMuX19pbmRleF9fJiZhPnRoaXMuX19sYXN0X2luZGV4X18pJiYodGhpcy5fX3NjaGVtYV9fPSJtYWlsdG86Iix0aGlzLl9faW5kZXhfXz1vLHRoaXMuX19sYXN0X2luZGV4X189YSkpLHRoaXMuX19pbmRleF9fPj0wfSx5LnByb3RvdHlwZS5wcmV0ZXN0PWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLnJlLnByZXRlc3QudGVzdChlKX0seS5wcm90b3R5cGUudGVzdFNjaGVtYUF0PWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gdGhpcy5fX2NvbXBpbGVkX19bdC50b0xvd2VyQ2FzZSgpXT90aGlzLl9fY29tcGlsZWRfX1t0LnRvTG93ZXJDYXNlKCldLnZhbGlkYXRlKGUsbix0aGlzKTowfSx5LnByb3RvdHlwZS5tYXRjaD1mdW5jdGlvbihlKXt2YXIgdD0wLG49W107dGhpcy5fX2luZGV4X18+PTAmJnRoaXMuX190ZXh0X2NhY2hlX189PT1lJiYobi5wdXNoKGcodGhpcyx0KSksdD10aGlzLl9fbGFzdF9pbmRleF9fKTtmb3IodmFyIHI9dD9lLnNsaWNlKHQpOmU7dGhpcy50ZXN0KHIpOyluLnB1c2goZyh0aGlzLHQpKSxyPXIuc2xpY2UodGhpcy5fX2xhc3RfaW5kZXhfXyksdCs9dGhpcy5fX2xhc3RfaW5kZXhfXztyZXR1cm4gbi5sZW5ndGg/bjpudWxsfSx5LnByb3RvdHlwZS50bGRzPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGU9QXJyYXkuaXNBcnJheShlKT9lOltlXSx0Pyh0aGlzLl9fdGxkc19fPXRoaXMuX190bGRzX18uY29uY2F0KGUpLnNvcnQoKS5maWx0ZXIoZnVuY3Rpb24oZSx0LG4pe3JldHVybiBlIT09blt0LTFdfSkucmV2ZXJzZSgpLGgodGhpcyksdGhpcyk6KHRoaXMuX190bGRzX189ZS5zbGljZSgpLHRoaXMuX190bGRzX3JlcGxhY2VkX189ITAsaCh0aGlzKSx0aGlzKX0seS5wcm90b3R5cGUubm9ybWFsaXplPWZ1bmN0aW9uKGUpe2Uuc2NoZW1hfHwoZS51cmw9Imh0dHA6Ly8iK2UudXJsKSwibWFpbHRvOiIhPT1lLnNjaGVtYXx8L15tYWlsdG86L2kudGVzdChlLnVybCl8fChlLnVybD0ibWFpbHRvOiIrZS51cmwpfSx5LnByb3RvdHlwZS5vbkNvbXBpbGU9ZnVuY3Rpb24oKXt9LGUuZXhwb3J0cz15fSxmdW5jdGlvbihlLHQpe2UuZXhwb3J0cz0vW1wwLVx1RDdGRlx1RTAwMC1cdUZGRkZdfFtcdUQ4MDAtXHVEQkZGXVtcdURDMDAtXHVERkZGXXxbXHVEODAwLVx1REJGRl0oPyFbXHVEQzAwLVx1REZGRl0pfCg/OlteXHVEODAwLVx1REJGRl18XilbXHVEQzAwLVx1REZGRl0vfSxmdW5jdGlvbihlLHQpe2UuZXhwb3J0cz0vW1wwLVx4MUZceDdGLVx4OUZdL30sZnVuY3Rpb24oZSx0KXtlLmV4cG9ydHM9L1sgXHhBMFx1MTY4MFx1MjAwMC1cdTIwMEFcdTIwMkZcdTIwNUZcdTMwMDBdL30sZnVuY3Rpb24oZSx0LG4peyhmdW5jdGlvbihlLHIpe3ZhciBpOyFmdW5jdGlvbihvKXtmdW5jdGlvbiBhKGUpe3Rocm93IG5ldyBSYW5nZUVycm9yKE5bZV0pfWZ1bmN0aW9uIHMoZSx0KXtmb3IodmFyIG49ZS5sZW5ndGgscj1bXTtuLS07KXJbbl09dChlW25dKTtyZXR1cm4gcn1mdW5jdGlvbiB1KGUsdCl7dmFyIG49ZS5zcGxpdCgiQCIpLHI9IiI7cmV0dXJuIG4ubGVuZ3RoPjEmJihyPW5bMF0rIkAiLGU9blsxXSksZT1lLnJlcGxhY2UoRiwiLiIpLHIrcyhlLnNwbGl0KCIuIiksdCkuam9pbigiLiIpfWZ1bmN0aW9uIGMoZSl7Zm9yKHZhciB0LG4scj1bXSxpPTAsbz1lLmxlbmd0aDtpPG87KXQ9ZS5jaGFyQ29kZUF0KGkrKyksdD49NTUyOTYmJnQ8PTU2MzE5JiZpPG8/KG49ZS5jaGFyQ29kZUF0KGkrKyksNTYzMjA9PSg2NDUxMiZuKT9yLnB1c2goKCgxMDIzJnQpPDwxMCkrKDEwMjMmbikrNjU1MzYpOihyLnB1c2godCksaS0tKSk6ci5wdXNoKHQpO3JldHVybiByfWZ1bmN0aW9uIGwoZSl7cmV0dXJuIHMoZSxmdW5jdGlvbihlKXt2YXIgdD0iIjtyZXR1cm4gZT42NTUzNSYmKGUtPTY1NTM2LHQrPVAoZT4+PjEwJjEwMjN8NTUyOTYpLGU9NTYzMjB8MTAyMyZlKSx0Kz1QKGUpfSkuam9pbigiIil9ZnVuY3Rpb24gcChlKXtyZXR1cm4gZS00ODwxMD9lLTIyOmUtNjU8MjY/ZS02NTplLTk3PDI2P2UtOTc6Q31mdW5jdGlvbiBmKGUsdCl7cmV0dXJuIGUrMjIrNzUqKGU8MjYpLSgoMCE9dCk8PDUpfWZ1bmN0aW9uIGQoZSx0LG4pe3ZhciByPTA7Zm9yKGU9bj9MKGUvUyk6ZT4+MSxlKz1MKGUvdCk7ZT5JKkQ+PjE7cis9QyllPUwoZS9JKTtyZXR1cm4gTChyKyhJKzEpKmUvKGUrdykpfWZ1bmN0aW9uIGgoZSl7dmFyIHQsbixyLGksbyxzLHUsYyxmLGgsbT1bXSxnPWUubGVuZ3RoLHk9MCx2PUEsYj1rO2ZvcihuPWUubGFzdEluZGV4T2YoXyksbjwwJiYobj0wKSxyPTA7cjxuOysrcillLmNoYXJDb2RlQXQocik+PTEyOCYmYSgibm90LWJhc2ljIiksbS5wdXNoKGUuY2hhckNvZGVBdChyKSk7Zm9yKGk9bj4wP24rMTowO2k8Zzspe2ZvcihvPXkscz0xLHU9QztpPj1nJiZhKCJpbnZhbGlkLWlucHV0IiksYz1wKGUuY2hhckNvZGVBdChpKyspKSwoYz49Q3x8Yz5MKCh4LXkpL3MpKSYmYSgib3ZlcmZsb3ciKSx5Kz1jKnMsZj11PD1iP0U6dT49YitEP0Q6dS1iLCEoYzxmKTt1Kz1DKWg9Qy1mLHM+TCh4L2gpJiZhKCJvdmVyZmxvdyIpLHMqPWg7dD1tLmxlbmd0aCsxLGI9ZCh5LW8sdCwwPT1vKSxMKHkvdCk+eC12JiZhKCJvdmVyZmxvdyIpLHYrPUwoeS90KSx5JT10LG0uc3BsaWNlKHkrKywwLHYpfXJldHVybiBsKG0pfWZ1bmN0aW9uIG0oZSl7dmFyIHQsbixyLGksbyxzLHUsbCxwLGgsbSxnLHksdixiLHc9W107Zm9yKGU9YyhlKSxnPWUubGVuZ3RoLHQ9QSxuPTAsbz1rLHM9MDtzPGc7KytzKShtPWVbc10pPDEyOCYmdy5wdXNoKFAobSkpO2ZvcihyPWk9dy5sZW5ndGgsaSYmdy5wdXNoKF8pO3I8Zzspe2Zvcih1PXgscz0wO3M8ZzsrK3MpKG09ZVtzXSk+PXQmJm08dSYmKHU9bSk7Zm9yKHk9cisxLHUtdD5MKCh4LW4pL3kpJiZhKCJvdmVyZmxvdyIpLG4rPSh1LXQpKnksdD11LHM9MDtzPGc7KytzKWlmKG09ZVtzXSxtPHQmJisrbj54JiZhKCJvdmVyZmxvdyIpLG09PXQpe2ZvcihsPW4scD1DO2g9cDw9bz9FOnA+PW8rRD9EOnAtbywhKGw8aCk7cCs9QyliPWwtaCx2PUMtaCx3LnB1c2goUChmKGgrYiV2LDApKSksbD1MKGIvdik7dy5wdXNoKFAoZihsLDApKSksbz1kKG4seSxyPT1pKSxuPTAsKytyfSsrbiwrK3R9cmV0dXJuIHcuam9pbigiIil9ZnVuY3Rpb24gZyhlKXtyZXR1cm4gdShlLGZ1bmN0aW9uKGUpe3JldHVybiBULnRlc3QoZSk/aChlLnNsaWNlKDQpLnRvTG93ZXJDYXNlKCkpOmV9KX1mdW5jdGlvbiB5KGUpe3JldHVybiB1KGUsZnVuY3Rpb24oZSl7cmV0dXJuIE8udGVzdChlKT8ieG4tLSIrbShlKTplfSl9dmFyIHY9KCJvYmplY3QiPT10eXBlb2YgdCYmdCYmdC5ub2RlVHlwZSwib2JqZWN0Ij09dHlwZW9mIGUmJmUmJmUubm9kZVR5cGUsIm9iamVjdCI9PXR5cGVvZiByJiZyKTt2YXIgYix4PTIxNDc0ODM2NDcsQz0zNixFPTEsRD0yNix3PTM4LFM9NzAwLGs9NzIsQT0xMjgsXz0iLSIsVD0vXnhuLS0vLE89L1teXHgyMC1ceDdFXS8sRj0vW1x4MkVcdTMwMDJcdUZGMEVcdUZGNjFdL2csTj17b3ZlcmZsb3c6Ik92ZXJmbG93OiBpbnB1dCBuZWVkcyB3aWRlciBpbnRlZ2VycyB0byBwcm9jZXNzIiwibm90LWJhc2ljIjoiSWxsZWdhbCBpbnB1dCA+PSAweDgwIChub3QgYSBiYXNpYyBjb2RlIHBvaW50KSIsImludmFsaWQtaW5wdXQiOiJJbnZhbGlkIGlucHV0In0sST1DLUUsTD1NYXRoLmZsb29yLFA9U3RyaW5nLmZyb21DaGFyQ29kZTtiPXt2ZXJzaW9uOiIxLjQuMSIsdWNzMjp7ZGVjb2RlOmMsZW5jb2RlOmx9LGRlY29kZTpoLGVuY29kZTptLHRvQVNDSUk6eSx0b1VuaWNvZGU6Z30sdm9pZCAwIT09KGk9ZnVuY3Rpb24oKXtyZXR1cm4gYn0uY2FsbCh0LG4sdCxlKSkmJihlLmV4cG9ydHM9aSl9KCl9KS5jYWxsKHQsbigxMDIpKGUpLG4oMTEpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjsoZnVuY3Rpb24oZSl7ZnVuY3Rpb24gcih0LHIsYSl7dmFyIHMsdSxjLGw9bigyKTtsLm9uKHIsInNlbGVjdCIsZnVuY3Rpb24obixyKXtpZighcyl7dmFyIGw9ci5wYXJlbnROb2RlLHA9bC5wYXJlbnROb2RlO3M9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IikscC5hcHBlbmRDaGlsZChzKTt2YXIgZj1sLnN0eWxlLnRvcCxkPSIiLGg9dC5jdXJzb3JDb29yZHMoKS50b3A7cGFyc2VJbnQoZiwxMCk8aCYmKGY9IiIsZD13aW5kb3cuaW5uZXJIZWlnaHQtaCszKyJweCIpLHMuY2xhc3NOYW1lPSJDb2RlTWlycm9yLWhpbnRzLXdyYXBwZXIiLHMuc3R5bGUubGVmdD1sLnN0eWxlLmxlZnQscy5zdHlsZS50b3A9ZixzLnN0eWxlLmJvdHRvbT1kLGwuc3R5bGUubGVmdD0iIixsLnN0eWxlLnRvcD0iIix1PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpLHUuY2xhc3NOYW1lPSJDb2RlTWlycm9yLWhpbnQtaW5mb3JtYXRpb24iLGM9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IiksYy5jbGFzc05hbWU9IkNvZGVNaXJyb3ItaGludC1kZXByZWNhdGlvbiIsZD8ocy5hcHBlbmRDaGlsZChjKSxzLmFwcGVuZENoaWxkKHUpLHMuYXBwZW5kQ2hpbGQobCkpOihzLmFwcGVuZENoaWxkKGwpLHMuYXBwZW5kQ2hpbGQodSkscy5hcHBlbmRDaGlsZChjKSk7dmFyIG09cy5jbGllbnRIZWlnaHQsZz1wYXJzZUZsb2F0KFN0cmluZyhmKS5yZXBsYWNlKCJweCIsIiIpKSx5PWc7bStnPndpbmRvdy5pbm5lckhlaWdodCYmKHk9d2luZG93LmlubmVySGVpZ2h0LTQwLW0pLHMuc3R5bGUudG9wPXkrInB4IixlLndyYXBwZXI9czt2YXIgdjtzLmFkZEV2ZW50TGlzdGVuZXIoIkRPTU5vZGVSZW1vdmVkIix2PWZ1bmN0aW9uKGUpe2UudGFyZ2V0PT09bCYmKHMucmVtb3ZlRXZlbnRMaXN0ZW5lcigiRE9NTm9kZVJlbW92ZWQiLHYpLHMucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChzKSxzPW51bGwsdT1udWxsLHY9bnVsbCl9KX12YXIgYj1uLmRlc2NyaXB0aW9uP28obi5kZXNjcmlwdGlvbix7c2FuaXRpemU6ITB9KToiIix4PW4udHlwZSYmInVuZGVmaW5lZCIhPT1uLnR5cGU/JzxzcGFuIGNsYXNzPSJpbmZvVHlwZSI+JytpKG4udHlwZSkrIjwvc3Bhbj4iOiIiO2lmKHUuaW5uZXJIVE1MPSc8ZGl2IGNsYXNzPSJjb250ZW50Ij4nKygiPHA+Ij09PWIuc2xpY2UoMCwzKT8iPHA+Iit4K2Iuc2xpY2UoMyk6eCtiKSsiPC9kaXY+IixuLmlzRGVwcmVjYXRlZCl7dmFyIEM9bi5kZXByZWNhdGlvblJlYXNvbj9vKG4uZGVwcmVjYXRpb25SZWFzb24se3Nhbml0aXplOiEwfSk6IiI7Yy5pbm5lckhUTUw9JzxzcGFuIGNsYXNzPSJkZXByZWNhdGlvbi1sYWJlbCI+RGVwcmVjYXRlZDwvc3Bhbj4nK0MsYy5zdHlsZS5kaXNwbGF5PSJibG9jayJ9ZWxzZSBjLnN0eWxlLmRpc3BsYXk9Im5vbmUiO2EmJmEodSl9KX1mdW5jdGlvbiBpKGUpe3JldHVybic8YSBjbGFzcz0idHlwZU5hbWUiPicrZSsiPC9hPiJ9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPW4oNTkyKTt0LmRlZmF1bHQ9cn0pLmNhbGwodCxuKDExKSl9LGZ1bmN0aW9uKGUsdCxuKXshZnVuY3Rpb24oZSl7ZShuKDIpKX0oZnVuY3Rpb24oZSl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHQoZSl7dmFyIHQ9ZS5zZWFyY2gobyk7cmV0dXJuLTE9PXQ/MDp0fWZ1bmN0aW9uIG4oZSx0LG4pe3JldHVybi9cYnN0cmluZ1xiLy50ZXN0KGUuZ2V0VG9rZW5UeXBlQXQoYSh0LmxpbmUsMCkpKSYmIS9eW1wnXCJcYF0vLnRlc3Qobil9ZnVuY3Rpb24gcihlLHQpe3ZhciBuPWUuZ2V0TW9kZSgpO3JldHVybiExIT09bi51c2VJbm5lckNvbW1lbnRzJiZuLmlubmVyTW9kZT9lLmdldE1vZGVBdCh0KTpufXZhciBpPXt9LG89L1teXHNcdTAwYTBdLyxhPWUuUG9zO2UuY29tbWFuZHMudG9nZ2xlQ29tbWVudD1mdW5jdGlvbihlKXtlLnRvZ2dsZUNvbW1lbnQoKX0sZS5kZWZpbmVFeHRlbnNpb24oInRvZ2dsZUNvbW1lbnQiLGZ1bmN0aW9uKGUpe2V8fChlPWkpO2Zvcih2YXIgdD10aGlzLG49MS8wLHI9dGhpcy5saXN0U2VsZWN0aW9ucygpLG89bnVsbCxzPXIubGVuZ3RoLTE7cz49MDtzLS0pe3ZhciB1PXJbc10uZnJvbSgpLGM9cltzXS50bygpO3UubGluZT49bnx8KGMubGluZT49biYmKGM9YShuLDApKSxuPXUubGluZSxudWxsPT1vP3QudW5jb21tZW50KHUsYyxlKT9vPSJ1biI6KHQubGluZUNvbW1lbnQodSxjLGUpLG89ImxpbmUiKToidW4iPT1vP3QudW5jb21tZW50KHUsYyxlKTp0LmxpbmVDb21tZW50KHUsYyxlKSl9fSksZS5kZWZpbmVFeHRlbnNpb24oImxpbmVDb21tZW50IixmdW5jdGlvbihlLHMsdSl7dXx8KHU9aSk7dmFyIGM9dGhpcyxsPXIoYyxlKSxwPWMuZ2V0TGluZShlLmxpbmUpO2lmKG51bGwhPXAmJiFuKGMsZSxwKSl7dmFyIGY9dS5saW5lQ29tbWVudHx8bC5saW5lQ29tbWVudDtpZighZilyZXR1cm4gdm9pZCgodS5ibG9ja0NvbW1lbnRTdGFydHx8bC5ibG9ja0NvbW1lbnRTdGFydCkmJih1LmZ1bGxMaW5lcz0hMCxjLmJsb2NrQ29tbWVudChlLHMsdSkpKTt2YXIgZD1NYXRoLm1pbigwIT1zLmNofHxzLmxpbmU9PWUubGluZT9zLmxpbmUrMTpzLmxpbmUsYy5sYXN0TGluZSgpKzEpLGg9bnVsbD09dS5wYWRkaW5nPyIgIjp1LnBhZGRpbmcsbT11LmNvbW1lbnRCbGFua0xpbmVzfHxlLmxpbmU9PXMubGluZTtjLm9wZXJhdGlvbihmdW5jdGlvbigpe2lmKHUuaW5kZW50KXtmb3IodmFyIG49bnVsbCxyPWUubGluZTtyPGQ7KytyKXt2YXIgaT1jLmdldExpbmUocikscz1pLnNsaWNlKDAsdChpKSk7KG51bGw9PW58fG4ubGVuZ3RoPnMubGVuZ3RoKSYmKG49cyl9Zm9yKHZhciByPWUubGluZTtyPGQ7KytyKXt2YXIgaT1jLmdldExpbmUociksbD1uLmxlbmd0aDsobXx8by50ZXN0KGkpKSYmKGkuc2xpY2UoMCxsKSE9biYmKGw9dChpKSksYy5yZXBsYWNlUmFuZ2UobitmK2gsYShyLDApLGEocixsKSkpfX1lbHNlIGZvcih2YXIgcj1lLmxpbmU7cjxkOysrcikobXx8by50ZXN0KGMuZ2V0TGluZShyKSkpJiZjLnJlcGxhY2VSYW5nZShmK2gsYShyLDApKX0pfX0pLGUuZGVmaW5lRXh0ZW5zaW9uKCJibG9ja0NvbW1lbnQiLGZ1bmN0aW9uKGUsdCxuKXtufHwobj1pKTt2YXIgcz10aGlzLHU9cihzLGUpLGM9bi5ibG9ja0NvbW1lbnRTdGFydHx8dS5ibG9ja0NvbW1lbnRTdGFydCxsPW4uYmxvY2tDb21tZW50RW5kfHx1LmJsb2NrQ29tbWVudEVuZDtpZighY3x8IWwpcmV0dXJuIHZvaWQoKG4ubGluZUNvbW1lbnR8fHUubGluZUNvbW1lbnQpJiYwIT1uLmZ1bGxMaW5lcyYmcy5saW5lQ29tbWVudChlLHQsbikpO2lmKCEvXGJjb21tZW50XGIvLnRlc3Qocy5nZXRUb2tlblR5cGVBdChhKGUubGluZSwwKSkpKXt2YXIgcD1NYXRoLm1pbih0LmxpbmUscy5sYXN0TGluZSgpKTtwIT1lLmxpbmUmJjA9PXQuY2gmJm8udGVzdChzLmdldExpbmUocCkpJiYtLXA7dmFyIGY9bnVsbD09bi5wYWRkaW5nPyIgIjpuLnBhZGRpbmc7ZS5saW5lPnB8fHMub3BlcmF0aW9uKGZ1bmN0aW9uKCl7aWYoMCE9bi5mdWxsTGluZXMpe3ZhciByPW8udGVzdChzLmdldExpbmUocCkpO3MucmVwbGFjZVJhbmdlKGYrbCxhKHApKSxzLnJlcGxhY2VSYW5nZShjK2YsYShlLmxpbmUsMCkpO3ZhciBpPW4uYmxvY2tDb21tZW50TGVhZHx8dS5ibG9ja0NvbW1lbnRMZWFkO2lmKG51bGwhPWkpZm9yKHZhciBkPWUubGluZSsxO2Q8PXA7KytkKShkIT1wfHxyKSYmcy5yZXBsYWNlUmFuZ2UoaStmLGEoZCwwKSl9ZWxzZSBzLnJlcGxhY2VSYW5nZShsLHQpLHMucmVwbGFjZVJhbmdlKGMsZSl9KX19KSxlLmRlZmluZUV4dGVuc2lvbigidW5jb21tZW50IixmdW5jdGlvbihlLHQsbil7bnx8KG49aSk7dmFyIHMsdT10aGlzLGM9cih1LGUpLGw9TWF0aC5taW4oMCE9dC5jaHx8dC5saW5lPT1lLmxpbmU/dC5saW5lOnQubGluZS0xLHUubGFzdExpbmUoKSkscD1NYXRoLm1pbihlLmxpbmUsbCksZj1uLmxpbmVDb21tZW50fHxjLmxpbmVDb21tZW50LGQ9W10saD1udWxsPT1uLnBhZGRpbmc/IiAiOm4ucGFkZGluZztlOmlmKGYpe2Zvcih2YXIgbT1wO208PWw7KyttKXt2YXIgZz11LmdldExpbmUobSkseT1nLmluZGV4T2YoZik7aWYoeT4tMSYmIS9jb21tZW50Ly50ZXN0KHUuZ2V0VG9rZW5UeXBlQXQoYShtLHkrMSkpKSYmKHk9LTEpLC0xPT15JiZvLnRlc3QoZykpYnJlYWsgZTtpZih5Pi0xJiZvLnRlc3QoZy5zbGljZSgwLHkpKSlicmVhayBlO2QucHVzaChnKX1pZih1Lm9wZXJhdGlvbihmdW5jdGlvbigpe2Zvcih2YXIgZT1wO2U8PWw7KytlKXt2YXIgdD1kW2UtcF0sbj10LmluZGV4T2YoZikscj1uK2YubGVuZ3RoO248MHx8KHQuc2xpY2UocixyK2gubGVuZ3RoKT09aCYmKHIrPWgubGVuZ3RoKSxzPSEwLHUucmVwbGFjZVJhbmdlKCIiLGEoZSxuKSxhKGUscikpKX19KSxzKXJldHVybiEwfXZhciB2PW4uYmxvY2tDb21tZW50U3RhcnR8fGMuYmxvY2tDb21tZW50U3RhcnQsYj1uLmJsb2NrQ29tbWVudEVuZHx8Yy5ibG9ja0NvbW1lbnRFbmQ7aWYoIXZ8fCFiKXJldHVybiExO3ZhciB4PW4uYmxvY2tDb21tZW50TGVhZHx8Yy5ibG9ja0NvbW1lbnRMZWFkLEM9dS5nZXRMaW5lKHApLEU9Qy5pbmRleE9mKHYpO2lmKC0xPT1FKXJldHVybiExO3ZhciBEPWw9PXA/Qzp1LmdldExpbmUobCksdz1ELmluZGV4T2YoYixsPT1wP0Urdi5sZW5ndGg6MCksUz1hKHAsRSsxKSxrPWEobCx3KzEpO2lmKC0xPT13fHwhL2NvbW1lbnQvLnRlc3QodS5nZXRUb2tlblR5cGVBdChTKSl8fCEvY29tbWVudC8udGVzdCh1LmdldFRva2VuVHlwZUF0KGspKXx8dS5nZXRSYW5nZShTLGssIlxuIikuaW5kZXhPZihiKT4tMSlyZXR1cm4hMTt2YXIgQT1DLmxhc3RJbmRleE9mKHYsZS5jaCksXz0tMT09QT8tMTpDLnNsaWNlKDAsZS5jaCkuaW5kZXhPZihiLEErdi5sZW5ndGgpO2lmKC0xIT1BJiYtMSE9XyYmXytiLmxlbmd0aCE9ZS5jaClyZXR1cm4hMTtfPUQuaW5kZXhPZihiLHQuY2gpO3ZhciBUPUQuc2xpY2UodC5jaCkubGFzdEluZGV4T2YodixfLXQuY2gpO3JldHVybiBBPS0xPT1ffHwtMT09VD8tMTp0LmNoK1QsKC0xPT1ffHwtMT09QXx8QT09dC5jaCkmJih1Lm9wZXJhdGlvbihmdW5jdGlvbigpe3UucmVwbGFjZVJhbmdlKCIiLGEobCx3LShoJiZELnNsaWNlKHctaC5sZW5ndGgsdyk9PWg/aC5sZW5ndGg6MCkpLGEobCx3K2IubGVuZ3RoKSk7dmFyIGU9RSt2Lmxlbmd0aDtpZihoJiZDLnNsaWNlKGUsZStoLmxlbmd0aCk9PWgmJihlKz1oLmxlbmd0aCksdS5yZXBsYWNlUmFuZ2UoIiIsYShwLEUpLGEocCxlKSkseClmb3IodmFyIHQ9cCsxO3Q8PWw7Kyt0KXt2YXIgbj11LmdldExpbmUodCkscj1uLmluZGV4T2YoeCk7aWYoLTEhPXImJiFvLnRlc3Qobi5zbGljZSgwLHIpKSl7dmFyIGk9cit4Lmxlbmd0aDtoJiZuLnNsaWNlKGksaStoLmxlbmd0aCk9PWgmJihpKz1oLmxlbmd0aCksdS5yZXBsYWNlUmFuZ2UoIiIsYSh0LHIpLGEodCxpKSl9fX0pLCEwKX0pfSl9LGZ1bmN0aW9uKGUsdCxuKXshZnVuY3Rpb24oZSl7ZShuKDIpLG4oMzgpLG4oMzkpKX0oZnVuY3Rpb24oZSl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHQoZSx0KXtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIGU/ZT1uZXcgUmVnRXhwKGUucmVwbGFjZSgvW1wtXFtcXVwvXHtcfVwoXClcKlwrXD9cLlxcXF5cJFx8XS9nLCJcXCQmIiksdD8iZ2kiOiJnIik6ZS5nbG9iYWx8fChlPW5ldyBSZWdFeHAoZS5zb3VyY2UsZS5pZ25vcmVDYXNlPyJnaSI6ImciKSkse3Rva2VuOmZ1bmN0aW9uKHQpe2UubGFzdEluZGV4PXQucG9zO3ZhciBuPWUuZXhlYyh0LnN0cmluZyk7aWYobiYmbi5pbmRleD09dC5wb3MpcmV0dXJuIHQucG9zKz1uWzBdLmxlbmd0aHx8MSwic2VhcmNoaW5nIjtuP3QucG9zPW4uaW5kZXg6dC5za2lwVG9FbmQoKX19fWZ1bmN0aW9uIG4oKXt0aGlzLnBvc0Zyb209dGhpcy5wb3NUbz10aGlzLmxhc3RRdWVyeT10aGlzLnF1ZXJ5PW51bGwsdGhpcy5vdmVybGF5PW51bGx9ZnVuY3Rpb24gcihlKXtyZXR1cm4gZS5zdGF0ZS5zZWFyY2h8fChlLnN0YXRlLnNlYXJjaD1uZXcgbil9ZnVuY3Rpb24gaShlKXtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIGUmJmU9PWUudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBvKGUsdCxuKXtyZXR1cm4gZS5nZXRTZWFyY2hDdXJzb3IodCxuLHtjYXNlRm9sZDppKHQpLG11bHRpbGluZTohMH0pfWZ1bmN0aW9uIGEoZSx0LG4scixpKXtlLm9wZW5EaWFsb2codCxyLHt2YWx1ZTpuLHNlbGVjdFZhbHVlT25PcGVuOiEwLGNsb3NlT25FbnRlcjohMSxvbkNsb3NlOmZ1bmN0aW9uKCl7aChlKX0sb25LZXlEb3duOml9KX1mdW5jdGlvbiBzKGUsdCxuLHIsaSl7ZS5vcGVuRGlhbG9nP2Uub3BlbkRpYWxvZyh0LGkse3ZhbHVlOnIsc2VsZWN0VmFsdWVPbk9wZW46ITB9KTppKHByb21wdChuLHIpKX1mdW5jdGlvbiB1KGUsdCxuLHIpe2Uub3BlbkNvbmZpcm0/ZS5vcGVuQ29uZmlybSh0LHIpOmNvbmZpcm0obikmJnJbMF0oKX1mdW5jdGlvbiBjKGUpe3JldHVybiBlLnJlcGxhY2UoL1xcKC4pL2csZnVuY3Rpb24oZSx0KXtyZXR1cm4ibiI9PXQ/IlxuIjoiciI9PXQ/IlxyIjp0fSl9ZnVuY3Rpb24gbChlKXt2YXIgdD1lLm1hdGNoKC9eXC8oLiopXC8oW2Etel0qKSQvKTtpZih0KXRyeXtlPW5ldyBSZWdFeHAodFsxXSwtMT09dFsyXS5pbmRleE9mKCJpIik/IiI6ImkiKX1jYXRjaChlKXt9ZWxzZSBlPWMoZSk7cmV0dXJuKCJzdHJpbmciPT10eXBlb2YgZT8iIj09ZTplLnRlc3QoIiIpKSYmKGU9L3heLyksZX1mdW5jdGlvbiBwKGUsbixyKXtuLnF1ZXJ5VGV4dD1yLG4ucXVlcnk9bChyKSxlLnJlbW92ZU92ZXJsYXkobi5vdmVybGF5LGkobi5xdWVyeSkpLG4ub3ZlcmxheT10KG4ucXVlcnksaShuLnF1ZXJ5KSksZS5hZGRPdmVybGF5KG4ub3ZlcmxheSksZS5zaG93TWF0Y2hlc09uU2Nyb2xsYmFyJiYobi5hbm5vdGF0ZSYmKG4uYW5ub3RhdGUuY2xlYXIoKSxuLmFubm90YXRlPW51bGwpLG4uYW5ub3RhdGU9ZS5zaG93TWF0Y2hlc09uU2Nyb2xsYmFyKG4ucXVlcnksaShuLnF1ZXJ5KSkpfWZ1bmN0aW9uIGYodCxuLGksbyl7dmFyIHU9cih0KTtpZih1LnF1ZXJ5KXJldHVybiBkKHQsbik7dmFyIGM9dC5nZXRTZWxlY3Rpb24oKXx8dS5sYXN0UXVlcnk7aWYoYyBpbnN0YW5jZW9mIFJlZ0V4cCYmInheIj09Yy5zb3VyY2UmJihjPW51bGwpLGkmJnQub3BlbkRpYWxvZyl7dmFyIGw9bnVsbCxmPWZ1bmN0aW9uKG4scil7ZS5lX3N0b3AociksbiYmKG4hPXUucXVlcnlUZXh0JiYocCh0LHUsbiksdS5wb3NGcm9tPXUucG9zVG89dC5nZXRDdXJzb3IoKSksbCYmKGwuc3R5bGUub3BhY2l0eT0xKSxkKHQsci5zaGlmdEtleSxmdW5jdGlvbihlLG4pe3ZhciByO24ubGluZTwzJiZkb2N1bWVudC5xdWVyeVNlbGVjdG9yJiYocj10LmRpc3BsYXkud3JhcHBlci5xdWVyeVNlbGVjdG9yKCIuQ29kZU1pcnJvci1kaWFsb2ciKSkmJnIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuYm90dG9tLTQ+dC5jdXJzb3JDb29yZHMobiwid2luZG93IikudG9wJiYoKGw9cikuc3R5bGUub3BhY2l0eT0uNCl9KSl9O2EodCx5LGMsZixmdW5jdGlvbihuLGkpe3ZhciBvPWUua2V5TmFtZShuKSxhPXQuZ2V0T3B0aW9uKCJleHRyYUtleXMiKSxzPWEmJmFbb118fGUua2V5TWFwW3QuZ2V0T3B0aW9uKCJrZXlNYXAiKV1bb107ImZpbmROZXh0Ij09c3x8ImZpbmRQcmV2Ij09c3x8ImZpbmRQZXJzaXN0ZW50TmV4dCI9PXN8fCJmaW5kUGVyc2lzdGVudFByZXYiPT1zPyhlLmVfc3RvcChuKSxwKHQscih0KSxpKSx0LmV4ZWNDb21tYW5kKHMpKToiZmluZCIhPXMmJiJmaW5kUGVyc2lzdGVudCIhPXN8fChlLmVfc3RvcChuKSxmKGksbikpfSksbyYmYyYmKHAodCx1LGMpLGQodCxuKSl9ZWxzZSBzKHQseSwiU2VhcmNoIGZvcjoiLGMsZnVuY3Rpb24oZSl7ZSYmIXUucXVlcnkmJnQub3BlcmF0aW9uKGZ1bmN0aW9uKCl7cCh0LHUsZSksdS5wb3NGcm9tPXUucG9zVG89dC5nZXRDdXJzb3IoKSxkKHQsbil9KX0pfWZ1bmN0aW9uIGQodCxuLGkpe3Qub3BlcmF0aW9uKGZ1bmN0aW9uKCl7dmFyIGE9cih0KSxzPW8odCxhLnF1ZXJ5LG4/YS5wb3NGcm9tOmEucG9zVG8pOyhzLmZpbmQobil8fChzPW8odCxhLnF1ZXJ5LG4/ZS5Qb3ModC5sYXN0TGluZSgpKTplLlBvcyh0LmZpcnN0TGluZSgpLDApKSxzLmZpbmQobikpKSYmKHQuc2V0U2VsZWN0aW9uKHMuZnJvbSgpLHMudG8oKSksdC5zY3JvbGxJbnRvVmlldyh7ZnJvbTpzLmZyb20oKSx0bzpzLnRvKCl9LDIwKSxhLnBvc0Zyb209cy5mcm9tKCksYS5wb3NUbz1zLnRvKCksaSYmaShzLmZyb20oKSxzLnRvKCkpKX0pfWZ1bmN0aW9uIGgoZSl7ZS5vcGVyYXRpb24oZnVuY3Rpb24oKXt2YXIgdD1yKGUpO3QubGFzdFF1ZXJ5PXQucXVlcnksdC5xdWVyeSYmKHQucXVlcnk9dC5xdWVyeVRleHQ9bnVsbCxlLnJlbW92ZU92ZXJsYXkodC5vdmVybGF5KSx0LmFubm90YXRlJiYodC5hbm5vdGF0ZS5jbGVhcigpLHQuYW5ub3RhdGU9bnVsbCkpfSl9ZnVuY3Rpb24gbShlLHQsbil7ZS5vcGVyYXRpb24oZnVuY3Rpb24oKXtmb3IodmFyIHI9byhlLHQpO3IuZmluZE5leHQoKTspaWYoInN0cmluZyIhPXR5cGVvZiB0KXt2YXIgaT1lLmdldFJhbmdlKHIuZnJvbSgpLHIudG8oKSkubWF0Y2godCk7ci5yZXBsYWNlKG4ucmVwbGFjZSgvXCQoXGQpL2csZnVuY3Rpb24oZSx0KXtyZXR1cm4gaVt0XX0pKX1lbHNlIHIucmVwbGFjZShuKX0pfWZ1bmN0aW9uIGcoZSx0KXtpZighZS5nZXRPcHRpb24oInJlYWRPbmx5Iikpe3ZhciBuPWUuZ2V0U2VsZWN0aW9uKCl8fHIoZSkubGFzdFF1ZXJ5LGk9JzxzcGFuIGNsYXNzPSJDb2RlTWlycm9yLXNlYXJjaC1sYWJlbCI+JysodD8iUmVwbGFjZSBhbGw6IjoiUmVwbGFjZToiKSsiPC9zcGFuPiI7cyhlLGkrdixpLG4sZnVuY3Rpb24obil7biYmKG49bChuKSxzKGUsYiwiUmVwbGFjZSB3aXRoOiIsIiIsZnVuY3Rpb24ocil7aWYocj1jKHIpLHQpbShlLG4scik7ZWxzZXtoKGUpO3ZhciBpPW8oZSxuLGUuZ2V0Q3Vyc29yKCJmcm9tIikpLGE9ZnVuY3Rpb24oKXt2YXIgdCxjPWkuZnJvbSgpOyEodD1pLmZpbmROZXh0KCkpJiYoaT1vKGUsbiksISh0PWkuZmluZE5leHQoKSl8fGMmJmkuZnJvbSgpLmxpbmU9PWMubGluZSYmaS5mcm9tKCkuY2g9PWMuY2gpfHwoZS5zZXRTZWxlY3Rpb24oaS5mcm9tKCksaS50bygpKSxlLnNjcm9sbEludG9WaWV3KHtmcm9tOmkuZnJvbSgpLHRvOmkudG8oKX0pLHUoZSx4LCJSZXBsYWNlPyIsW2Z1bmN0aW9uKCl7cyh0KX0sYSxmdW5jdGlvbigpe20oZSxuLHIpfV0pKX0scz1mdW5jdGlvbihlKXtpLnJlcGxhY2UoInN0cmluZyI9PXR5cGVvZiBuP3I6ci5yZXBsYWNlKC9cJChcZCkvZyxmdW5jdGlvbih0LG4pe3JldHVybiBlW25dfSkpLGEoKX07YSgpfX0pKX0pfX12YXIgeT0nPHNwYW4gY2xhc3M9IkNvZGVNaXJyb3Itc2VhcmNoLWxhYmVsIj5TZWFyY2g6PC9zcGFuPiA8aW5wdXQgdHlwZT0idGV4dCIgc3R5bGU9IndpZHRoOiAxMGVtIiBjbGFzcz0iQ29kZU1pcnJvci1zZWFyY2gtZmllbGQiLz4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjODg4IiBjbGFzcz0iQ29kZU1pcnJvci1zZWFyY2gtaGludCI+KFVzZSAvcmUvIHN5bnRheCBmb3IgcmVnZXhwIHNlYXJjaCk8L3NwYW4+Jyx2PScgPGlucHV0IHR5cGU9InRleHQiIHN0eWxlPSJ3aWR0aDogMTBlbSIgY2xhc3M9IkNvZGVNaXJyb3Itc2VhcmNoLWZpZWxkIi8+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzg4OCIgY2xhc3M9IkNvZGVNaXJyb3Itc2VhcmNoLWhpbnQiPihVc2UgL3JlLyBzeW50YXggZm9yIHJlZ2V4cCBzZWFyY2gpPC9zcGFuPicsYj0nPHNwYW4gY2xhc3M9IkNvZGVNaXJyb3Itc2VhcmNoLWxhYmVsIj5XaXRoOjwvc3Bhbj4gPGlucHV0IHR5cGU9InRleHQiIHN0eWxlPSJ3aWR0aDogMTBlbSIgY2xhc3M9IkNvZGVNaXJyb3Itc2VhcmNoLWZpZWxkIi8+Jyx4PSc8c3BhbiBjbGFzcz0iQ29kZU1pcnJvci1zZWFyY2gtbGFiZWwiPlJlcGxhY2U/PC9zcGFuPiA8YnV0dG9uPlllczwvYnV0dG9uPiA8YnV0dG9uPk5vPC9idXR0b24+IDxidXR0b24+QWxsPC9idXR0b24+IDxidXR0b24+U3RvcDwvYnV0dG9uPic7ZS5jb21tYW5kcy5maW5kPWZ1bmN0aW9uKGUpe2goZSksZihlKX0sZS5jb21tYW5kcy5maW5kUGVyc2lzdGVudD1mdW5jdGlvbihlKXtoKGUpLGYoZSwhMSwhMCl9LGUuY29tbWFuZHMuZmluZFBlcnNpc3RlbnROZXh0PWZ1bmN0aW9uKGUpe2YoZSwhMSwhMCwhMCl9LGUuY29tbWFuZHMuZmluZFBlcnNpc3RlbnRQcmV2PWZ1bmN0aW9uKGUpe2YoZSwhMCwhMCwhMCl9LGUuY29tbWFuZHMuZmluZE5leHQ9ZixlLmNvbW1hbmRzLmZpbmRQcmV2PWZ1bmN0aW9uKGUpe2YoZSwhMCl9LGUuY29tbWFuZHMuY2xlYXJTZWFyY2g9aCxlLmNvbW1hbmRzLnJlcGxhY2U9ZyxlLmNvbW1hbmRzLnJlcGxhY2VBbGw9ZnVuY3Rpb24oZSl7ZyhlLCEwKX19KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybntzdHlsZToia2V5d29yZCIsbWF0Y2g6ZnVuY3Rpb24odCl7cmV0dXJuIk5hbWUiPT09dC5raW5kJiZ0LnZhbHVlPT09ZX19fWZ1bmN0aW9uIGkoZSl7cmV0dXJue3N0eWxlOmUsbWF0Y2g6ZnVuY3Rpb24oZSl7cmV0dXJuIk5hbWUiPT09ZS5raW5kfSx1cGRhdGU6ZnVuY3Rpb24oZSx0KXtlLm5hbWU9dC52YWx1ZX19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlBhcnNlUnVsZXM9dC5MZXhSdWxlcz10LmlzSWdub3JlZD12b2lkIDA7dmFyIG89bigyNzYpO3QuaXNJZ25vcmVkPWZ1bmN0aW9uKGUpe3JldHVybiIgIj09PWV8fCJcdCI9PT1lfHwiLCI9PT1lfHwiXG4iPT09ZXx8IlxyIj09PWV8fCJcdWZlZmYiPT09ZX0sdC5MZXhSdWxlcz17TmFtZTovXltfQS1aYS16XVtfMC05QS1aYS16XSovLFB1bmN0dWF0aW9uOi9eKD86IXxcJHxcKHxcKXxcLlwuXC58Onw9fEB8XFt8XXxce3xcfHxcfSkvLE51bWJlcjovXi0/KD86MHwoPzpbMS05XVswLTldKikpKD86XC5bMC05XSopPyg/OltlRV1bKy1dP1swLTldKyk/LyxTdHJpbmc6L14oPzoiIiIoPzpcXCIiInxbXiJdfCJbXiJdfCIiW14iXSkqKD86IiIiKT98Iig/OlteIlxcXXxcXCg/OiJ8XC98XFx8YnxmfG58cnx0fHVbMC05YS1mQS1GXXs0fSkpKiI/KS8sQ29tbWVudDovXiMuKi99LHQuUGFyc2VSdWxlcz17RG9jdW1lbnQ6WygwLG8ubGlzdCkoIkRlZmluaXRpb24iKV0sRGVmaW5pdGlvbjpmdW5jdGlvbihlKXtzd2l0Y2goZS52YWx1ZSl7Y2FzZSJ7IjpyZXR1cm4iU2hvcnRRdWVyeSI7Y2FzZSJxdWVyeSI6cmV0dXJuIlF1ZXJ5IjtjYXNlIm11dGF0aW9uIjpyZXR1cm4iTXV0YXRpb24iO2Nhc2Uic3Vic2NyaXB0aW9uIjpyZXR1cm4iU3Vic2NyaXB0aW9uIjtjYXNlImZyYWdtZW50IjpyZXR1cm4iRnJhZ21lbnREZWZpbml0aW9uIjtjYXNlInNjaGVtYSI6cmV0dXJuIlNjaGVtYURlZiI7Y2FzZSJzY2FsYXIiOnJldHVybiJTY2FsYXJEZWYiO2Nhc2UidHlwZSI6cmV0dXJuIk9iamVjdFR5cGVEZWYiO2Nhc2UiaW50ZXJmYWNlIjpyZXR1cm4iSW50ZXJmYWNlRGVmIjtjYXNlInVuaW9uIjpyZXR1cm4iVW5pb25EZWYiO2Nhc2UiZW51bSI6cmV0dXJuIkVudW1EZWYiO2Nhc2UiaW5wdXQiOnJldHVybiJJbnB1dERlZiI7Y2FzZSJleHRlbmQiOnJldHVybiJFeHRlbmREZWYiO2Nhc2UiZGlyZWN0aXZlIjpyZXR1cm4iRGlyZWN0aXZlRGVmIn19LFNob3J0UXVlcnk6WyJTZWxlY3Rpb25TZXQiXSxRdWVyeTpbcigicXVlcnkiKSwoMCxvLm9wdCkoaSgiZGVmIikpLCgwLG8ub3B0KSgiVmFyaWFibGVEZWZpbml0aW9ucyIpLCgwLG8ubGlzdCkoIkRpcmVjdGl2ZSIpLCJTZWxlY3Rpb25TZXQiXSxNdXRhdGlvbjpbcigibXV0YXRpb24iKSwoMCxvLm9wdCkoaSgiZGVmIikpLCgwLG8ub3B0KSgiVmFyaWFibGVEZWZpbml0aW9ucyIpLCgwLG8ubGlzdCkoIkRpcmVjdGl2ZSIpLCJTZWxlY3Rpb25TZXQiXSxTdWJzY3JpcHRpb246W3IoInN1YnNjcmlwdGlvbiIpLCgwLG8ub3B0KShpKCJkZWYiKSksKDAsby5vcHQpKCJWYXJpYWJsZURlZmluaXRpb25zIiksKDAsby5saXN0KSgiRGlyZWN0aXZlIiksIlNlbGVjdGlvblNldCJdLFZhcmlhYmxlRGVmaW5pdGlvbnM6WygwLG8ucCkoIigiKSwoMCxvLmxpc3QpKCJWYXJpYWJsZURlZmluaXRpb24iKSwoMCxvLnApKCIpIildLFZhcmlhYmxlRGVmaW5pdGlvbjpbIlZhcmlhYmxlIiwoMCxvLnApKCI6IiksIlR5cGUiLCgwLG8ub3B0KSgiRGVmYXVsdFZhbHVlIildLFZhcmlhYmxlOlsoMCxvLnApKCIkIiwidmFyaWFibGUiKSxpKCJ2YXJpYWJsZSIpXSxEZWZhdWx0VmFsdWU6WygwLG8ucCkoIj0iKSwiVmFsdWUiXSxTZWxlY3Rpb25TZXQ6WygwLG8ucCkoInsiKSwoMCxvLmxpc3QpKCJTZWxlY3Rpb24iKSwoMCxvLnApKCJ9IildLFNlbGVjdGlvbjpmdW5jdGlvbihlLHQpe3JldHVybiIuLi4iPT09ZS52YWx1ZT90Lm1hdGNoKC9bXHNcdTAwYTAsXSoob25cYnxAfHspLywhMSk/IklubGluZUZyYWdtZW50IjoiRnJhZ21lbnRTcHJlYWQiOnQubWF0Y2goL1tcc1x1MDBhMCxdKjovLCExKT8iQWxpYXNlZEZpZWxkIjoiRmllbGQifSxBbGlhc2VkRmllbGQ6W2koInByb3BlcnR5IiksKDAsby5wKSgiOiIpLGkoInF1YWxpZmllciIpLCgwLG8ub3B0KSgiQXJndW1lbnRzIiksKDAsby5saXN0KSgiRGlyZWN0aXZlIiksKDAsby5vcHQpKCJTZWxlY3Rpb25TZXQiKV0sRmllbGQ6W2koInByb3BlcnR5IiksKDAsby5vcHQpKCJBcmd1bWVudHMiKSwoMCxvLmxpc3QpKCJEaXJlY3RpdmUiKSwoMCxvLm9wdCkoIlNlbGVjdGlvblNldCIpXSxBcmd1bWVudHM6WygwLG8ucCkoIigiKSwoMCxvLmxpc3QpKCJBcmd1bWVudCIpLCgwLG8ucCkoIikiKV0sQXJndW1lbnQ6W2koImF0dHJpYnV0ZSIpLCgwLG8ucCkoIjoiKSwiVmFsdWUiXSxGcmFnbWVudFNwcmVhZDpbKDAsby5wKSgiLi4uIiksaSgiZGVmIiksKDAsby5saXN0KSgiRGlyZWN0aXZlIildLElubGluZUZyYWdtZW50OlsoMCxvLnApKCIuLi4iKSwoMCxvLm9wdCkoIlR5cGVDb25kaXRpb24iKSwoMCxvLmxpc3QpKCJEaXJlY3RpdmUiKSwiU2VsZWN0aW9uU2V0Il0sRnJhZ21lbnREZWZpbml0aW9uOltyKCJmcmFnbWVudCIpLCgwLG8ub3B0KSgoMCxvLmJ1dE5vdCkoaSgiZGVmIiksW3IoIm9uIildKSksIlR5cGVDb25kaXRpb24iLCgwLG8ubGlzdCkoIkRpcmVjdGl2ZSIpLCJTZWxlY3Rpb25TZXQiXSxUeXBlQ29uZGl0aW9uOltyKCJvbiIpLCJOYW1lZFR5cGUiXSxWYWx1ZTpmdW5jdGlvbihlKXtzd2l0Y2goZS5raW5kKXtjYXNlIk51bWJlciI6cmV0dXJuIk51bWJlclZhbHVlIjtjYXNlIlN0cmluZyI6cmV0dXJuIlN0cmluZ1ZhbHVlIjtjYXNlIlB1bmN0dWF0aW9uIjpzd2l0Y2goZS52YWx1ZSl7Y2FzZSJbIjpyZXR1cm4iTGlzdFZhbHVlIjtjYXNlInsiOnJldHVybiJPYmplY3RWYWx1ZSI7Y2FzZSIkIjpyZXR1cm4iVmFyaWFibGUifXJldHVybiBudWxsO2Nhc2UiTmFtZSI6c3dpdGNoKGUudmFsdWUpe2Nhc2UidHJ1ZSI6Y2FzZSJmYWxzZSI6cmV0dXJuIkJvb2xlYW5WYWx1ZSJ9cmV0dXJuIm51bGwiPT09ZS52YWx1ZT8iTnVsbFZhbHVlIjoiRW51bVZhbHVlIn19LE51bWJlclZhbHVlOlsoMCxvLnQpKCJOdW1iZXIiLCJudW1iZXIiKV0sU3RyaW5nVmFsdWU6WygwLG8udCkoIlN0cmluZyIsInN0cmluZyIpXSxCb29sZWFuVmFsdWU6WygwLG8udCkoIk5hbWUiLCJidWlsdGluIildLE51bGxWYWx1ZTpbKDAsby50KSgiTmFtZSIsImtleXdvcmQiKV0sRW51bVZhbHVlOltpKCJzdHJpbmctMiIpXSxMaXN0VmFsdWU6WygwLG8ucCkoIlsiKSwoMCxvLmxpc3QpKCJWYWx1ZSIpLCgwLG8ucCkoIl0iKV0sT2JqZWN0VmFsdWU6WygwLG8ucCkoInsiKSwoMCxvLmxpc3QpKCJPYmplY3RGaWVsZCIpLCgwLG8ucCkoIn0iKV0sT2JqZWN0RmllbGQ6W2koImF0dHJpYnV0ZSIpLCgwLG8ucCkoIjoiKSwiVmFsdWUiXSxUeXBlOmZ1bmN0aW9uKGUpe3JldHVybiJbIj09PWUudmFsdWU/Ikxpc3RUeXBlIjoiTm9uTnVsbFR5cGUifSxMaXN0VHlwZTpbKDAsby5wKSgiWyIpLCJUeXBlIiwoMCxvLnApKCJdIiksKDAsby5vcHQpKCgwLG8ucCkoIiEiKSldLE5vbk51bGxUeXBlOlsiTmFtZWRUeXBlIiwoMCxvLm9wdCkoKDAsby5wKSgiISIpKV0sTmFtZWRUeXBlOltmdW5jdGlvbihlKXtyZXR1cm57c3R5bGU6ZSxtYXRjaDpmdW5jdGlvbihlKXtyZXR1cm4iTmFtZSI9PT1lLmtpbmR9LHVwZGF0ZTpmdW5jdGlvbihlLHQpe2UucHJldlN0YXRlJiZlLnByZXZTdGF0ZS5wcmV2U3RhdGUmJihlLm5hbWU9dC52YWx1ZSxlLnByZXZTdGF0ZS5wcmV2U3RhdGUudHlwZT10LnZhbHVlKX19fSgiYXRvbSIpXSxEaXJlY3RpdmU6WygwLG8ucCkoIkAiLCJtZXRhIiksaSgibWV0YSIpLCgwLG8ub3B0KSgiQXJndW1lbnRzIildLFNjaGVtYURlZjpbcigic2NoZW1hIiksKDAsby5saXN0KSgiRGlyZWN0aXZlIiksKDAsby5wKSgieyIpLCgwLG8ubGlzdCkoIk9wZXJhdGlvblR5cGVEZWYiKSwoMCxvLnApKCJ9IildLE9wZXJhdGlvblR5cGVEZWY6W2koImtleXdvcmQiKSwoMCxvLnApKCI6IiksaSgiYXRvbSIpXSxTY2FsYXJEZWY6W3IoInNjYWxhciIpLGkoImF0b20iKSwoMCxvLmxpc3QpKCJEaXJlY3RpdmUiKV0sT2JqZWN0VHlwZURlZjpbcigidHlwZSIpLGkoImF0b20iKSwoMCxvLm9wdCkoIkltcGxlbWVudHMiKSwoMCxvLmxpc3QpKCJEaXJlY3RpdmUiKSwoMCxvLnApKCJ7IiksKDAsby5saXN0KSgiRmllbGREZWYiKSwoMCxvLnApKCJ9IildLEltcGxlbWVudHM6W3IoImltcGxlbWVudHMiKSwoMCxvLmxpc3QpKCJOYW1lZFR5cGUiKV0sRmllbGREZWY6W2koInByb3BlcnR5IiksKDAsby5vcHQpKCJBcmd1bWVudHNEZWYiKSwoMCxvLnApKCI6IiksIlR5cGUiLCgwLG8ubGlzdCkoIkRpcmVjdGl2ZSIpXSxBcmd1bWVudHNEZWY6WygwLG8ucCkoIigiKSwoMCxvLmxpc3QpKCJJbnB1dFZhbHVlRGVmIiksKDAsby5wKSgiKSIpXSxJbnB1dFZhbHVlRGVmOltpKCJhdHRyaWJ1dGUiKSwoMCxvLnApKCI6IiksIlR5cGUiLCgwLG8ub3B0KSgiRGVmYXVsdFZhbHVlIiksKDAsby5saXN0KSgiRGlyZWN0aXZlIildLEludGVyZmFjZURlZjpbcigiaW50ZXJmYWNlIiksaSgiYXRvbSIpLCgwLG8ubGlzdCkoIkRpcmVjdGl2ZSIpLCgwLG8ucCkoInsiKSwoMCxvLmxpc3QpKCJGaWVsZERlZiIpLCgwLG8ucCkoIn0iKV0sVW5pb25EZWY6W3IoInVuaW9uIiksaSgiYXRvbSIpLCgwLG8ubGlzdCkoIkRpcmVjdGl2ZSIpLCgwLG8ucCkoIj0iKSwoMCxvLmxpc3QpKCJVbmlvbk1lbWJlciIsKDAsby5wKSgifCIpKV0sVW5pb25NZW1iZXI6WyJOYW1lZFR5cGUiXSxFbnVtRGVmOltyKCJlbnVtIiksaSgiYXRvbSIpLCgwLG8ubGlzdCkoIkRpcmVjdGl2ZSIpLCgwLG8ucCkoInsiKSwoMCxvLmxpc3QpKCJFbnVtVmFsdWVEZWYiKSwoMCxvLnApKCJ9IildLEVudW1WYWx1ZURlZjpbaSgic3RyaW5nLTIiKSwoMCxvLmxpc3QpKCJEaXJlY3RpdmUiKV0sSW5wdXREZWY6W3IoImlucHV0IiksaSgiYXRvbSIpLCgwLG8ubGlzdCkoIkRpcmVjdGl2ZSIpLCgwLG8ucCkoInsiKSwoMCxvLmxpc3QpKCJJbnB1dFZhbHVlRGVmIiksKDAsby5wKSgifSIpXSxFeHRlbmREZWY6W3IoImV4dGVuZCIpLCJPYmplY3RUeXBlRGVmIl0sRGlyZWN0aXZlRGVmOltyKCJkaXJlY3RpdmUiKSwoMCxvLnApKCJAIiwibWV0YSIpLGkoIm1ldGEiKSwoMCxvLm9wdCkoIkFyZ3VtZW50c0RlZiIpLHIoIm9uIiksKDAsby5saXN0KSgiRGlyZWN0aXZlTG9jYXRpb24iLCgwLG8ucCkoInwiKSldLERpcmVjdGl2ZUxvY2F0aW9uOltpKCJzdHJpbmctMiIpXX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm57b2ZSdWxlOmV9fWZ1bmN0aW9uIGkoZSx0KXtyZXR1cm57b2ZSdWxlOmUsaXNMaXN0OiEwLHNlcGFyYXRvcjp0fX1mdW5jdGlvbiBvKGUsdCl7dmFyIG49ZS5tYXRjaDtyZXR1cm4gZS5tYXRjaD1mdW5jdGlvbihlKXt2YXIgcj0hMTtyZXR1cm4gbiYmKHI9bihlKSksciYmdC5ldmVyeShmdW5jdGlvbih0KXtyZXR1cm4gdC5tYXRjaCYmIXQubWF0Y2goZSl9KX0sZX1mdW5jdGlvbiBhKGUsdCl7cmV0dXJue3N0eWxlOnQsbWF0Y2g6ZnVuY3Rpb24odCl7cmV0dXJuIHQua2luZD09PWV9fX1mdW5jdGlvbiBzKGUsdCl7cmV0dXJue3N0eWxlOnR8fCJwdW5jdHVhdGlvbiIsbWF0Y2g6ZnVuY3Rpb24odCl7cmV0dXJuIlB1bmN0dWF0aW9uIj09PXQua2luZCYmdC52YWx1ZT09PWV9fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5vcHQ9cix0Lmxpc3Q9aSx0LmJ1dE5vdD1vLHQudD1hLHQucD1zfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBpKGUsdCl7dmFyIG49ZS5zbGljZSgwLHQpLHI9bi5zcGxpdCgiXG4iKS5sZW5ndGgtMSxpPW4ubGFzdEluZGV4T2YoIlxuIik7cmV0dXJuIG5ldyBzKHIsdC1pLTEpfWZ1bmN0aW9uIG8oZSx0KXt2YXIgbj1pKGUsdC5zdGFydCkscj1pKGUsdC5lbmQpO3JldHVybiBuZXcgYShuLHIpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0Lm9mZnNldFRvUG9zaXRpb249aSx0LmxvY1RvUmFuZ2U9bzt2YXIgYT10LlJhbmdlPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0LG4pe3ZhciBpPXRoaXM7cih0aGlzLGUpLHRoaXMuY29udGFpbnNQb3NpdGlvbj1mdW5jdGlvbihlKXtyZXR1cm4gaS5zdGFydC5saW5lPT09ZS5saW5lP2kuc3RhcnQuY2hhcmFjdGVyPD1lLmNoYXJhY3RlcjppLmVuZC5saW5lPT09ZS5saW5lP2kuZW5kLmNoYXJhY3Rlcj49ZS5jaGFyYWN0ZXI6aS5zdGFydC5saW5lPD1lLmxpbmUmJmkuZW5kLmxpbmU+PWUubGluZX0sdGhpcy5zdGFydD10LHRoaXMuZW5kPW59cmV0dXJuIGUucHJvdG90eXBlLnNldFN0YXJ0PWZ1bmN0aW9uKGUsdCl7dGhpcy5zdGFydD1uZXcgcyhlLHQpfSxlLnByb3RvdHlwZS5zZXRFbmQ9ZnVuY3Rpb24oZSx0KXt0aGlzLmVuZD1uZXcgcyhlLHQpfSxlfSgpLHM9dC5Qb3NpdGlvbj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCxuKXt2YXIgaT10aGlzO3IodGhpcyxlKSx0aGlzLmxlc3NUaGFuT3JFcXVhbFRvPWZ1bmN0aW9uKGUpe3JldHVybiBpLmxpbmU8ZS5saW5lfHxpLmxpbmU9PT1lLmxpbmUmJmkuY2hhcmFjdGVyPD1lLmNoYXJhY3Rlcn0sdGhpcy5saW5lPXQsdGhpcy5jaGFyYWN0ZXI9bn1yZXR1cm4gZS5wcm90b3R5cGUuc2V0TGluZT1mdW5jdGlvbihlKXt0aGlzLmxpbmU9ZX0sZS5wcm90b3R5cGUuc2V0Q2hhcmFjdGVyPWZ1bmN0aW9uKGUpe3RoaXMuY2hhcmFjdGVyPWV9LGV9KCl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7KGZ1bmN0aW9uKHQpe2Z1bmN0aW9uIHIoZSx0KXtpZihlPT09dClyZXR1cm4gMDtmb3IodmFyIG49ZS5sZW5ndGgscj10Lmxlbmd0aCxpPTAsbz1NYXRoLm1pbihuLHIpO2k8bzsrK2kpaWYoZVtpXSE9PXRbaV0pe249ZVtpXSxyPXRbaV07YnJlYWt9cmV0dXJuIG48cj8tMTpyPG4/MTowfWZ1bmN0aW9uIGkoZSl7cmV0dXJuIHQuQnVmZmVyJiYiZnVuY3Rpb24iPT09dHlwZW9mIHQuQnVmZmVyLmlzQnVmZmVyP3QuQnVmZmVyLmlzQnVmZmVyKGUpOiEobnVsbD09ZXx8IWUuX2lzQnVmZmVyKX1mdW5jdGlvbiBvKGUpe3JldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZSl9ZnVuY3Rpb24gYShlKXtyZXR1cm4haShlKSYmKCJmdW5jdGlvbiI9PT10eXBlb2YgdC5BcnJheUJ1ZmZlciYmKCJmdW5jdGlvbiI9PT10eXBlb2YgQXJyYXlCdWZmZXIuaXNWaWV3P0FycmF5QnVmZmVyLmlzVmlldyhlKTohIWUmJihlIGluc3RhbmNlb2YgRGF0YVZpZXd8fCEhKGUuYnVmZmVyJiZlLmJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSkpKX1mdW5jdGlvbiBzKGUpe2lmKHguaXNGdW5jdGlvbihlKSl7aWYoRClyZXR1cm4gZS5uYW1lO3ZhciB0PWUudG9TdHJpbmcoKSxuPXQubWF0Y2goUyk7cmV0dXJuIG4mJm5bMV19fWZ1bmN0aW9uIHUoZSx0KXtyZXR1cm4ic3RyaW5nIj09PXR5cGVvZiBlP2UubGVuZ3RoPHQ/ZTplLnNsaWNlKDAsdCk6ZX1mdW5jdGlvbiBjKGUpe2lmKER8fCF4LmlzRnVuY3Rpb24oZSkpcmV0dXJuIHguaW5zcGVjdChlKTt2YXIgdD1zKGUpO3JldHVybiJbRnVuY3Rpb24iKyh0PyI6ICIrdDoiIikrIl0ifWZ1bmN0aW9uIGwoZSl7cmV0dXJuIHUoYyhlLmFjdHVhbCksMTI4KSsiICIrZS5vcGVyYXRvcisiICIrdShjKGUuZXhwZWN0ZWQpLDEyOCl9ZnVuY3Rpb24gcChlLHQsbixyLGkpe3Rocm93IG5ldyB3LkFzc2VydGlvbkVycm9yKHttZXNzYWdlOm4sYWN0dWFsOmUsZXhwZWN0ZWQ6dCxvcGVyYXRvcjpyLHN0YWNrU3RhcnRGdW5jdGlvbjppfSl9ZnVuY3Rpb24gZihlLHQpe2V8fHAoZSwhMCx0LCI9PSIsdy5vayl9ZnVuY3Rpb24gZChlLHQsbixzKXtpZihlPT09dClyZXR1cm4hMDtpZihpKGUpJiZpKHQpKXJldHVybiAwPT09cihlLHQpO2lmKHguaXNEYXRlKGUpJiZ4LmlzRGF0ZSh0KSlyZXR1cm4gZS5nZXRUaW1lKCk9PT10LmdldFRpbWUoKTtpZih4LmlzUmVnRXhwKGUpJiZ4LmlzUmVnRXhwKHQpKXJldHVybiBlLnNvdXJjZT09PXQuc291cmNlJiZlLmdsb2JhbD09PXQuZ2xvYmFsJiZlLm11bHRpbGluZT09PXQubXVsdGlsaW5lJiZlLmxhc3RJbmRleD09PXQubGFzdEluZGV4JiZlLmlnbm9yZUNhc2U9PT10Lmlnbm9yZUNhc2U7aWYobnVsbCE9PWUmJiJvYmplY3QiPT09dHlwZW9mIGV8fG51bGwhPT10JiYib2JqZWN0Ij09PXR5cGVvZiB0KXtpZihhKGUpJiZhKHQpJiZvKGUpPT09byh0KSYmIShlIGluc3RhbmNlb2YgRmxvYXQzMkFycmF5fHxlIGluc3RhbmNlb2YgRmxvYXQ2NEFycmF5KSlyZXR1cm4gMD09PXIobmV3IFVpbnQ4QXJyYXkoZS5idWZmZXIpLG5ldyBVaW50OEFycmF5KHQuYnVmZmVyKSk7aWYoaShlKSE9PWkodCkpcmV0dXJuITE7cz1zfHx7YWN0dWFsOltdLGV4cGVjdGVkOltdfTt2YXIgdT1zLmFjdHVhbC5pbmRleE9mKGUpO3JldHVybi0xIT09dSYmdT09PXMuZXhwZWN0ZWQuaW5kZXhPZih0KXx8KHMuYWN0dWFsLnB1c2goZSkscy5leHBlY3RlZC5wdXNoKHQpLG0oZSx0LG4scykpfXJldHVybiBuP2U9PT10OmU9PXR9ZnVuY3Rpb24gaChlKXtyZXR1cm4iW29iamVjdCBBcmd1bWVudHNdIj09T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGUpfWZ1bmN0aW9uIG0oZSx0LG4scil7aWYobnVsbD09PWV8fHZvaWQgMD09PWV8fG51bGw9PT10fHx2b2lkIDA9PT10KXJldHVybiExO2lmKHguaXNQcmltaXRpdmUoZSl8fHguaXNQcmltaXRpdmUodCkpcmV0dXJuIGU9PT10O2lmKG4mJk9iamVjdC5nZXRQcm90b3R5cGVPZihlKSE9PU9iamVjdC5nZXRQcm90b3R5cGVPZih0KSlyZXR1cm4hMTt2YXIgaT1oKGUpLG89aCh0KTtpZihpJiYhb3x8IWkmJm8pcmV0dXJuITE7aWYoaSlyZXR1cm4gZT1FLmNhbGwoZSksdD1FLmNhbGwodCksZChlLHQsbik7dmFyIGEscyx1PWsoZSksYz1rKHQpO2lmKHUubGVuZ3RoIT09Yy5sZW5ndGgpcmV0dXJuITE7Zm9yKHUuc29ydCgpLGMuc29ydCgpLHM9dS5sZW5ndGgtMTtzPj0wO3MtLSlpZih1W3NdIT09Y1tzXSlyZXR1cm4hMTtmb3Iocz11Lmxlbmd0aC0xO3M+PTA7cy0tKWlmKGE9dVtzXSwhZChlW2FdLHRbYV0sbixyKSlyZXR1cm4hMTtyZXR1cm4hMH1mdW5jdGlvbiBnKGUsdCxuKXtkKGUsdCwhMCkmJnAoZSx0LG4sIm5vdERlZXBTdHJpY3RFcXVhbCIsZyl9ZnVuY3Rpb24geShlLHQpe2lmKCFlfHwhdClyZXR1cm4hMTtpZigiW29iamVjdCBSZWdFeHBdIj09T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHQpKXJldHVybiB0LnRlc3QoZSk7dHJ5e2lmKGUgaW5zdGFuY2VvZiB0KXJldHVybiEwfWNhdGNoKGUpe31yZXR1cm4hRXJyb3IuaXNQcm90b3R5cGVPZih0KSYmITA9PT10LmNhbGwoe30sZSl9ZnVuY3Rpb24gdihlKXt2YXIgdDt0cnl7ZSgpfWNhdGNoKGUpe3Q9ZX1yZXR1cm4gdH1mdW5jdGlvbiBiKGUsdCxuLHIpe3ZhciBpO2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgdCl0aHJvdyBuZXcgVHlwZUVycm9yKCciYmxvY2siIGFyZ3VtZW50IG11c3QgYmUgYSBmdW5jdGlvbicpOyJzdHJpbmciPT09dHlwZW9mIG4mJihyPW4sbj1udWxsKSxpPXYodCkscj0obiYmbi5uYW1lPyIgKCIrbi5uYW1lKyIpLiI6Ii4iKSsocj8iICIrcjoiLiIpLGUmJiFpJiZwKGksbiwiTWlzc2luZyBleHBlY3RlZCBleGNlcHRpb24iK3IpO3ZhciBvPSJzdHJpbmciPT09dHlwZW9mIHIsYT0hZSYmeC5pc0Vycm9yKGkpLHM9IWUmJmkmJiFuO2lmKChhJiZvJiZ5KGksbil8fHMpJiZwKGksbiwiR290IHVud2FudGVkIGV4Y2VwdGlvbiIrciksZSYmaSYmbiYmIXkoaSxuKXx8IWUmJmkpdGhyb3cgaX12YXIgeD1uKDI1MyksQz1PYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LEU9QXJyYXkucHJvdG90eXBlLnNsaWNlLEQ9ZnVuY3Rpb24oKXtyZXR1cm4iZm9vIj09PWZ1bmN0aW9uKCl7fS5uYW1lfSgpLHc9ZS5leHBvcnRzPWYsUz0vXHMqZnVuY3Rpb25ccysoW15cKFxzXSopXHMqLzt3LkFzc2VydGlvbkVycm9yPWZ1bmN0aW9uKGUpe3RoaXMubmFtZT0iQXNzZXJ0aW9uRXJyb3IiLHRoaXMuYWN0dWFsPWUuYWN0dWFsLHRoaXMuZXhwZWN0ZWQ9ZS5leHBlY3RlZCx0aGlzLm9wZXJhdG9yPWUub3BlcmF0b3IsZS5tZXNzYWdlPyh0aGlzLm1lc3NhZ2U9ZS5tZXNzYWdlLHRoaXMuZ2VuZXJhdGVkTWVzc2FnZT0hMSk6KHRoaXMubWVzc2FnZT1sKHRoaXMpLHRoaXMuZ2VuZXJhdGVkTWVzc2FnZT0hMCk7dmFyIHQ9ZS5zdGFja1N0YXJ0RnVuY3Rpb258fHA7aWYoRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UpRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UodGhpcyx0KTtlbHNle3ZhciBuPW5ldyBFcnJvcjtpZihuLnN0YWNrKXt2YXIgcj1uLnN0YWNrLGk9cyh0KSxvPXIuaW5kZXhPZigiXG4iK2kpO2lmKG8+PTApe3ZhciBhPXIuaW5kZXhPZigiXG4iLG8rMSk7cj1yLnN1YnN0cmluZyhhKzEpfXRoaXMuc3RhY2s9cn19fSx4LmluaGVyaXRzKHcuQXNzZXJ0aW9uRXJyb3IsRXJyb3IpLHcuZmFpbD1wLHcub2s9Zix3LmVxdWFsPWZ1bmN0aW9uKGUsdCxuKXtlIT10JiZwKGUsdCxuLCI9PSIsdy5lcXVhbCl9LHcubm90RXF1YWw9ZnVuY3Rpb24oZSx0LG4pe2U9PXQmJnAoZSx0LG4sIiE9Iix3Lm5vdEVxdWFsKX0sdy5kZWVwRXF1YWw9ZnVuY3Rpb24oZSx0LG4pe2QoZSx0LCExKXx8cChlLHQsbiwiZGVlcEVxdWFsIix3LmRlZXBFcXVhbCl9LHcuZGVlcFN0cmljdEVxdWFsPWZ1bmN0aW9uKGUsdCxuKXtkKGUsdCwhMCl8fHAoZSx0LG4sImRlZXBTdHJpY3RFcXVhbCIsdy5kZWVwU3RyaWN0RXF1YWwpfSx3Lm5vdERlZXBFcXVhbD1mdW5jdGlvbihlLHQsbil7ZChlLHQsITEpJiZwKGUsdCxuLCJub3REZWVwRXF1YWwiLHcubm90RGVlcEVxdWFsKX0sdy5ub3REZWVwU3RyaWN0RXF1YWw9Zyx3LnN0cmljdEVxdWFsPWZ1bmN0aW9uKGUsdCxuKXtlIT09dCYmcChlLHQsbiwiPT09Iix3LnN0cmljdEVxdWFsKX0sdy5ub3RTdHJpY3RFcXVhbD1mdW5jdGlvbihlLHQsbil7ZT09PXQmJnAoZSx0LG4sIiE9PSIsdy5ub3RTdHJpY3RFcXVhbCl9LHcudGhyb3dzPWZ1bmN0aW9uKGUsdCxuKXtiKCEwLGUsdCxuKX0sdy5kb2VzTm90VGhyb3c9ZnVuY3Rpb24oZSx0LG4pe2IoITEsZSx0LG4pfSx3LmlmRXJyb3I9ZnVuY3Rpb24oZSl7aWYoZSl0aHJvdyBlfTt2YXIgaz1PYmplY3Qua2V5c3x8ZnVuY3Rpb24oZSl7dmFyIHQ9W107Zm9yKHZhciBuIGluIGUpQy5jYWxsKGUsbikmJnQucHVzaChuKTtyZXR1cm4gdH19KS5jYWxsKHQsbigxMSkpfSxmdW5jdGlvbihlLHQsbil7ZnVuY3Rpb24gcihlKXtyZXR1cm4gbihpKGUpKX1mdW5jdGlvbiBpKGUpe3ZhciB0PW9bZV07aWYoISh0KzEpKXRocm93IG5ldyBFcnJvcigiQ2Fubm90IGZpbmQgbW9kdWxlICciK2UrIicuIik7cmV0dXJuIHR9dmFyIG89eyIuIjo1MCwiLi8iOjUwLCIuL0dyYXBoUUxMYW5ndWFnZVNlcnZpY2UiOjE0MSwiLi9HcmFwaFFMTGFuZ3VhZ2VTZXJ2aWNlLmpzIjoxNDEsIi4vR3JhcGhRTExhbmd1YWdlU2VydmljZS5qcy5mbG93Ijo2MDAsIi4vYXV0b2NvbXBsZXRlVXRpbHMiOjkyLCIuL2F1dG9jb21wbGV0ZVV0aWxzLmpzIjo5MiwiLi9hdXRvY29tcGxldGVVdGlscy5qcy5mbG93Ijo2MDEsIi4vZ2V0QXV0b2NvbXBsZXRlU3VnZ2VzdGlvbnMiOjkzLCIuL2dldEF1dG9jb21wbGV0ZVN1Z2dlc3Rpb25zLmpzIjo5MywiLi9nZXRBdXRvY29tcGxldGVTdWdnZXN0aW9ucy5qcy5mbG93Ijo2MDIsIi4vZ2V0RGVmaW5pdGlvbiI6OTQsIi4vZ2V0RGVmaW5pdGlvbi5qcyI6OTQsIi4vZ2V0RGVmaW5pdGlvbi5qcy5mbG93Ijo2MDMsIi4vZ2V0RGlhZ25vc3RpY3MiOjk2LCIuL2dldERpYWdub3N0aWNzLmpzIjo5NiwiLi9nZXREaWFnbm9zdGljcy5qcy5mbG93Ijo2MDQsIi4vZ2V0T3V0bGluZSI6MTQwLCIuL2dldE91dGxpbmUuanMiOjE0MCwiLi9nZXRPdXRsaW5lLmpzLmZsb3ciOjYwNSwiLi9pbmRleCI6NTAsIi4vaW5kZXguanMiOjUwLCIuL2luZGV4LmpzLmZsb3ciOjYwNn07ci5rZXlzPWZ1bmN0aW9uKCl7cmV0dXJuIE9iamVjdC5rZXlzKG8pfSxyLnJlc29sdmU9aSxlLmV4cG9ydHM9cixyLmlkPTI3OX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dmFyIG49e3NjaGVtYTplLHR5cGU6bnVsbCxwYXJlbnRUeXBlOm51bGwsaW5wdXRUeXBlOm51bGwsZGlyZWN0aXZlRGVmOm51bGwsZmllbGREZWY6bnVsbCxhcmdEZWY6bnVsbCxhcmdEZWZzOm51bGwsb2JqZWN0RmllbGREZWZzOm51bGx9O3JldHVybigwLGMuZGVmYXVsdCkodCxmdW5jdGlvbih0KXtzd2l0Y2godC5raW5kKXtjYXNlIlF1ZXJ5IjpjYXNlIlNob3J0UXVlcnkiOm4udHlwZT1lLmdldFF1ZXJ5VHlwZSgpO2JyZWFrO2Nhc2UiTXV0YXRpb24iOm4udHlwZT1lLmdldE11dGF0aW9uVHlwZSgpO2JyZWFrO2Nhc2UiU3Vic2NyaXB0aW9uIjpuLnR5cGU9ZS5nZXRTdWJzY3JpcHRpb25UeXBlKCk7YnJlYWs7Y2FzZSJJbmxpbmVGcmFnbWVudCI6Y2FzZSJGcmFnbWVudERlZmluaXRpb24iOnQudHlwZSYmKG4udHlwZT1lLmdldFR5cGUodC50eXBlKSk7YnJlYWs7Y2FzZSJGaWVsZCI6Y2FzZSJBbGlhc2VkRmllbGQiOm4uZmllbGREZWY9bi50eXBlJiZ0Lm5hbWU/aShlLG4ucGFyZW50VHlwZSx0Lm5hbWUpOm51bGwsbi50eXBlPW4uZmllbGREZWYmJm4uZmllbGREZWYudHlwZTticmVhaztjYXNlIlNlbGVjdGlvblNldCI6bi5wYXJlbnRUeXBlPSgwLGEuZ2V0TmFtZWRUeXBlKShuLnR5cGUpO2JyZWFrO2Nhc2UiRGlyZWN0aXZlIjpuLmRpcmVjdGl2ZURlZj10Lm5hbWUmJmUuZ2V0RGlyZWN0aXZlKHQubmFtZSk7YnJlYWs7Y2FzZSJBcmd1bWVudHMiOnZhciByPSJGaWVsZCI9PT10LnByZXZTdGF0ZS5raW5kP24uZmllbGREZWY6IkRpcmVjdGl2ZSI9PT10LnByZXZTdGF0ZS5raW5kP24uZGlyZWN0aXZlRGVmOiJBbGlhc2VkRmllbGQiPT09dC5wcmV2U3RhdGUua2luZD90LnByZXZTdGF0ZS5uYW1lJiZpKGUsbi5wYXJlbnRUeXBlLHQucHJldlN0YXRlLm5hbWUpOm51bGw7bi5hcmdEZWZzPXImJnIuYXJnczticmVhaztjYXNlIkFyZ3VtZW50IjppZihuLmFyZ0RlZj1udWxsLG4uYXJnRGVmcylmb3IodmFyIHM9MDtzPG4uYXJnRGVmcy5sZW5ndGg7cysrKWlmKG4uYXJnRGVmc1tzXS5uYW1lPT09dC5uYW1lKXtuLmFyZ0RlZj1uLmFyZ0RlZnNbc107YnJlYWt9bi5pbnB1dFR5cGU9bi5hcmdEZWYmJm4uYXJnRGVmLnR5cGU7YnJlYWs7Y2FzZSJFbnVtVmFsdWUiOnZhciB1PSgwLGEuZ2V0TmFtZWRUeXBlKShuLmlucHV0VHlwZSk7bi5lbnVtVmFsdWU9dSBpbnN0YW5jZW9mIGEuR3JhcGhRTEVudW1UeXBlP28odS5nZXRWYWx1ZXMoKSxmdW5jdGlvbihlKXtyZXR1cm4gZS52YWx1ZT09PXQubmFtZX0pOm51bGw7YnJlYWs7Y2FzZSJMaXN0VmFsdWUiOnZhciBjPSgwLGEuZ2V0TnVsbGFibGVUeXBlKShuLmlucHV0VHlwZSk7bi5pbnB1dFR5cGU9YyBpbnN0YW5jZW9mIGEuR3JhcGhRTExpc3Q/Yy5vZlR5cGU6bnVsbDticmVhaztjYXNlIk9iamVjdFZhbHVlIjp2YXIgbD0oMCxhLmdldE5hbWVkVHlwZSkobi5pbnB1dFR5cGUpO24ub2JqZWN0RmllbGREZWZzPWwgaW5zdGFuY2VvZiBhLkdyYXBoUUxJbnB1dE9iamVjdFR5cGU/bC5nZXRGaWVsZHMoKTpudWxsO2JyZWFrO2Nhc2UiT2JqZWN0RmllbGQiOnZhciBwPXQubmFtZSYmbi5vYmplY3RGaWVsZERlZnM/bi5vYmplY3RGaWVsZERlZnNbdC5uYW1lXTpudWxsO24uaW5wdXRUeXBlPXAmJnAudHlwZTticmVhaztjYXNlIk5hbWVkVHlwZSI6bi50eXBlPWUuZ2V0VHlwZSh0Lm5hbWUpfX0pLG59ZnVuY3Rpb24gaShlLHQsbil7cmV0dXJuIG49PT1zLlNjaGVtYU1ldGFGaWVsZERlZi5uYW1lJiZlLmdldFF1ZXJ5VHlwZSgpPT09dD9zLlNjaGVtYU1ldGFGaWVsZERlZjpuPT09cy5UeXBlTWV0YUZpZWxkRGVmLm5hbWUmJmUuZ2V0UXVlcnlUeXBlKCk9PT10P3MuVHlwZU1ldGFGaWVsZERlZjpuPT09cy5UeXBlTmFtZU1ldGFGaWVsZERlZi5uYW1lJiYoMCxhLmlzQ29tcG9zaXRlVHlwZSkodCk/cy5UeXBlTmFtZU1ldGFGaWVsZERlZjp0LmdldEZpZWxkcz90LmdldEZpZWxkcygpW25dOnZvaWQgMH1mdW5jdGlvbiBvKGUsdCl7Zm9yKHZhciBuPTA7bjxlLmxlbmd0aDtuKyspaWYodChlW25dKSlyZXR1cm4gZVtuXX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXI7dmFyIGE9big3KSxzPW4oMjgpLHU9bigyODEpLGM9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fSh1KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuPVtdLHI9ZTtyJiZyLmtpbmQ7KW4ucHVzaChyKSxyPXIucHJldlN0YXRlO2Zvcih2YXIgaT1uLmxlbmd0aC0xO2k+PTA7aS0tKXQobltpXSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZGVmYXVsdD1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJue2tpbmQ6IkZpZWxkIixzY2hlbWE6ZS5zY2hlbWEsZmllbGQ6ZS5maWVsZERlZix0eXBlOnUoZS5maWVsZERlZik/bnVsbDplLnBhcmVudFR5cGV9fWZ1bmN0aW9uIGkoZSl7cmV0dXJue2tpbmQ6IkRpcmVjdGl2ZSIsc2NoZW1hOmUuc2NoZW1hLGRpcmVjdGl2ZTplLmRpcmVjdGl2ZURlZn19ZnVuY3Rpb24gbyhlKXtyZXR1cm4gZS5kaXJlY3RpdmVEZWY/e2tpbmQ6IkFyZ3VtZW50IixzY2hlbWE6ZS5zY2hlbWEsYXJndW1lbnQ6ZS5hcmdEZWYsZGlyZWN0aXZlOmUuZGlyZWN0aXZlRGVmfTp7a2luZDoiQXJndW1lbnQiLHNjaGVtYTplLnNjaGVtYSxhcmd1bWVudDplLmFyZ0RlZixmaWVsZDplLmZpZWxkRGVmLHR5cGU6dShlLmZpZWxkRGVmKT9udWxsOmUucGFyZW50VHlwZX19ZnVuY3Rpb24gYShlKXtyZXR1cm57a2luZDoiRW51bVZhbHVlIix2YWx1ZTplLmVudW1WYWx1ZSx0eXBlOigwLGMuZ2V0TmFtZWRUeXBlKShlLmlucHV0VHlwZSl9fWZ1bmN0aW9uIHMoZSx0KXtyZXR1cm57a2luZDoiVHlwZSIsc2NoZW1hOmUuc2NoZW1hLHR5cGU6dHx8ZS50eXBlfX1mdW5jdGlvbiB1KGUpe3JldHVybiJfXyI9PT1lLm5hbWUuc2xpY2UoMCwyKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5nZXRGaWVsZFJlZmVyZW5jZT1yLHQuZ2V0RGlyZWN0aXZlUmVmZXJlbmNlPWksdC5nZXRBcmd1bWVudFJlZmVyZW5jZT1vLHQuZ2V0RW51bVZhbHVlUmVmZXJlbmNlPWEsdC5nZXRUeXBlUmVmZXJlbmNlPXM7dmFyIGM9big3KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dmFyIG49ZS5sZXZlbHM7cmV0dXJuKG4mJjAhPT1uLmxlbmd0aD9uW24ubGVuZ3RoLTFdLSh0aGlzLmVsZWN0cmljSW5wdXQudGVzdCh0KT8xOjApOmUuaW5kZW50TGV2ZWwpKnRoaXMuY29uZmlnLmluZGVudFVuaXR9dmFyIGk9bigyKSxvPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0oaSksYT1uKDcxKTtvLmRlZmF1bHQuZGVmaW5lTW9kZSgiZ3JhcGhxbCIsZnVuY3Rpb24oZSl7dmFyIHQ9KDAsYS5vbmxpbmVQYXJzZXIpKHtlYXRXaGl0ZXNwYWNlOmZ1bmN0aW9uKGUpe3JldHVybiBlLmVhdFdoaWxlKGEuaXNJZ25vcmVkKX0sbGV4UnVsZXM6YS5MZXhSdWxlcyxwYXJzZVJ1bGVzOmEuUGFyc2VSdWxlcyxlZGl0b3JDb25maWc6e3RhYlNpemU6ZS50YWJTaXplfX0pO3JldHVybntjb25maWc6ZSxzdGFydFN0YXRlOnQuc3RhcnRTdGF0ZSx0b2tlbjp0LnRva2VuLGluZGVudDpyLGVsZWN0cmljSW5wdXQ6L15ccypbfSlcXV0vLGZvbGQ6ImJyYWNlIixsaW5lQ29tbWVudDoiIyIsY2xvc2VCcmFja2V0czp7cGFpcnM6JygpW117fSIiJyxleHBsb2RlOiIoKVtde30ifX19KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PSgvbWFjIG9zIHgvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpPyJcdTIzMTgiOiJDdHJsIikrIitDIjtyZXR1cm4gZS5yZXBsYWNlKC8je1xzKmtleVxzKn0vZyx0KX1mdW5jdGlvbiBpKGUsdCl7dmFyIG4saSxzLHUsYyxsLHA9ITE7dHx8KHQ9e30pLG49dC5kZWJ1Z3x8ITE7dHJ5e3M9bygpLHU9ZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKSxjPWRvY3VtZW50LmdldFNlbGVjdGlvbigpLGw9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic3BhbiIpLGwudGV4dENvbnRlbnQ9ZSxsLnN0eWxlLmFsbD0idW5zZXQiLGwuc3R5bGUucG9zaXRpb249ImZpeGVkIixsLnN0eWxlLnRvcD0wLGwuc3R5bGUuY2xpcD0icmVjdCgwLCAwLCAwLCAwKSIsbC5zdHlsZS53aGl0ZVNwYWNlPSJwcmUiLGwuc3R5bGUud2Via2l0VXNlclNlbGVjdD0idGV4dCIsbC5zdHlsZS5Nb3pVc2VyU2VsZWN0PSJ0ZXh0IixsLnN0eWxlLm1zVXNlclNlbGVjdD0idGV4dCIsbC5zdHlsZS51c2VyU2VsZWN0PSJ0ZXh0Iixkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGwpLHUuc2VsZWN0Tm9kZShsKSxjLmFkZFJhbmdlKHUpO2lmKCFkb2N1bWVudC5leGVjQ29tbWFuZCgiY29weSIpKXRocm93IG5ldyBFcnJvcigiY29weSBjb21tYW5kIHdhcyB1bnN1Y2Nlc3NmdWwiKTtwPSEwfWNhdGNoKG8pe24mJmNvbnNvbGUuZXJyb3IoInVuYWJsZSB0byBjb3B5IHVzaW5nIGV4ZWNDb21tYW5kOiAiLG8pLG4mJmNvbnNvbGUud2FybigidHJ5aW5nIElFIHNwZWNpZmljIHN0dWZmIik7dHJ5e3dpbmRvdy5jbGlwYm9hcmREYXRhLnNldERhdGEoInRleHQiLGUpLHA9ITB9Y2F0Y2gobyl7biYmY29uc29sZS5lcnJvcigidW5hYmxlIHRvIGNvcHkgdXNpbmcgY2xpcGJvYXJkRGF0YTogIixvKSxuJiZjb25zb2xlLmVycm9yKCJmYWxsaW5nIGJhY2sgdG8gcHJvbXB0IiksaT1yKCJtZXNzYWdlImluIHQ/dC5tZXNzYWdlOmEpLHdpbmRvdy5wcm9tcHQoaSxlKX19ZmluYWxseXtjJiYoImZ1bmN0aW9uIj09dHlwZW9mIGMucmVtb3ZlUmFuZ2U/Yy5yZW1vdmVSYW5nZSh1KTpjLnJlbW92ZUFsbFJhbmdlcygpKSxsJiZkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKGwpLHMoKX1yZXR1cm4gcH12YXIgbz1uKDYxMyksYT0iQ29weSB0byBjbGlwYm9hcmQ6ICN7a2V5fSwgRW50ZXIiO2UuZXhwb3J0cz1pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPW4oMSk7dC5kZWZhdWx0PWkuc3R5bGVkLmRpdihvfHwobz1yKFsiXG4gIHdpZHRoOiAyMHB4O1xuICBoZWlnaHQ6IDIwcHg7XG4iXSxbIlxuICB3aWR0aDogMjBweDtcbiAgaGVpZ2h0OiAyMHB4O1xuIl0pKSk7dmFyIG99LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gaShlLHQsbil7dmFyIHI9IkludmFsaWQiPT09dC5zdGF0ZS5raW5kP3Quc3RhdGUucHJldlN0YXRlOnQuc3RhdGUsaT1yLmtpbmQsYT1yLnN0ZXA7aWYoIkRvY3VtZW50Ij09PWkmJjA9PT1hKXJldHVybigwLGYuZGVmYXVsdCkoZSx0LFt7dGV4dDoieyJ9XSk7dmFyIHM9bi52YXJpYWJsZVRvVHlwZTtpZihzKXt2YXIgYz1vKHMsdC5zdGF0ZSk7aWYoIkRvY3VtZW50Ij09PWl8fCJWYXJpYWJsZSI9PT1pJiYwPT09YSl7dmFyIGw9T2JqZWN0LmtleXMocyk7cmV0dXJuKDAsZi5kZWZhdWx0KShlLHQsbC5tYXAoZnVuY3Rpb24oZSl7cmV0dXJue3RleHQ6JyInK2UrJyI6ICcsdHlwZTpzW2VdfX0pKX1pZigoIk9iamVjdFZhbHVlIj09PWl8fCJPYmplY3RGaWVsZCI9PT1pJiYwPT09YSkmJmMuZmllbGRzKXt2YXIgcD1PYmplY3Qua2V5cyhjLmZpZWxkcykubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBjLmZpZWxkc1tlXX0pO3JldHVybigwLGYuZGVmYXVsdCkoZSx0LHAubWFwKGZ1bmN0aW9uKGUpe3JldHVybnt0ZXh0OiciJytlLm5hbWUrJyI6ICcsdHlwZTplLnR5cGUsZGVzY3JpcHRpb246ZS5kZXNjcmlwdGlvbn19KSl9aWYoIlN0cmluZ1ZhbHVlIj09PWl8fCJOdW1iZXJWYWx1ZSI9PT1pfHwiQm9vbGVhblZhbHVlIj09PWl8fCJOdWxsVmFsdWUiPT09aXx8Ikxpc3RWYWx1ZSI9PT1pJiYxPT09YXx8Ik9iamVjdEZpZWxkIj09PWkmJjI9PT1hfHwiVmFyaWFibGUiPT09aSYmMj09PWEpe3ZhciBkPSgwLHUuZ2V0TmFtZWRUeXBlKShjLnR5cGUpO2lmKGQgaW5zdGFuY2VvZiB1LkdyYXBoUUxJbnB1dE9iamVjdFR5cGUpcmV0dXJuKDAsZi5kZWZhdWx0KShlLHQsW3t0ZXh0OiJ7In1dKTtpZihkIGluc3RhbmNlb2YgdS5HcmFwaFFMRW51bVR5cGUpe3ZhciBoPWQuZ2V0VmFsdWVzKCksbT1PYmplY3Qua2V5cyhoKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGhbZV19KTtyZXR1cm4oMCxmLmRlZmF1bHQpKGUsdCxtLm1hcChmdW5jdGlvbihlKXtyZXR1cm57dGV4dDonIicrZS5uYW1lKyciJyx0eXBlOmQsZGVzY3JpcHRpb246ZS5kZXNjcmlwdGlvbn19KSl9aWYoZD09PXUuR3JhcGhRTEJvb2xlYW4pcmV0dXJuKDAsZi5kZWZhdWx0KShlLHQsW3t0ZXh0OiJ0cnVlIix0eXBlOnUuR3JhcGhRTEJvb2xlYW4sZGVzY3JpcHRpb246Ik5vdCBmYWxzZS4ifSx7dGV4dDoiZmFsc2UiLHR5cGU6dS5HcmFwaFFMQm9vbGVhbixkZXNjcmlwdGlvbjoiTm90IHRydWUuIn1dKX19fWZ1bmN0aW9uIG8oZSx0KXt2YXIgbj17dHlwZTpudWxsLGZpZWxkczpudWxsfTtyZXR1cm4oMCxsLmRlZmF1bHQpKHQsZnVuY3Rpb24odCl7aWYoIlZhcmlhYmxlIj09PXQua2luZCluLnR5cGU9ZVt0Lm5hbWVdO2Vsc2UgaWYoIkxpc3RWYWx1ZSI9PT10LmtpbmQpe3ZhciByPSgwLHUuZ2V0TnVsbGFibGVUeXBlKShuLnR5cGUpO24udHlwZT1yIGluc3RhbmNlb2YgdS5HcmFwaFFMTGlzdD9yLm9mVHlwZTpudWxsfWVsc2UgaWYoIk9iamVjdFZhbHVlIj09PXQua2luZCl7dmFyIGk9KDAsdS5nZXROYW1lZFR5cGUpKG4udHlwZSk7bi5maWVsZHM9aSBpbnN0YW5jZW9mIHUuR3JhcGhRTElucHV0T2JqZWN0VHlwZT9pLmdldEZpZWxkcygpOm51bGx9ZWxzZSBpZigiT2JqZWN0RmllbGQiPT09dC5raW5kKXt2YXIgbz10Lm5hbWUmJm4uZmllbGRzP24uZmllbGRzW3QubmFtZV06bnVsbDtuLnR5cGU9byYmby50eXBlfX0pLG59dmFyIGE9bigyKSxzPXIoYSksdT1uKDcpLGM9bigyODEpLGw9cihjKSxwPW4oNjI2KSxmPXIocCk7cy5kZWZhdWx0LnJlZ2lzdGVySGVscGVyKCJoaW50IiwiZ3JhcGhxbC12YXJpYWJsZXMiLGZ1bmN0aW9uKGUsdCl7dmFyIG49ZS5nZXRDdXJzb3IoKSxyPWUuZ2V0VG9rZW5BdChuKSxvPWkobixyLHQpO3JldHVybiBvJiZvLmxpc3QmJm8ubGlzdC5sZW5ndGg+MCYmKG8uZnJvbT1zLmRlZmF1bHQuUG9zKG8uZnJvbS5saW5lLG8uZnJvbS5jb2x1bW4pLG8udG89cy5kZWZhdWx0LlBvcyhvLnRvLmxpbmUsby50by5jb2x1bW4pLHMuZGVmYXVsdC5zaWduYWwoZSwiaGFzQ29tcGxldGlvbiIsZSxvLHIpKSxvfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gaShlLHQsbil7dmFyIHI9W107cmV0dXJuIG4ubWVtYmVycy5mb3JFYWNoKGZ1bmN0aW9uKG4pe3ZhciBpPW4ua2V5LnZhbHVlLHM9dFtpXTtzP28ocyxuLnZhbHVlKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe3ZhciBuPXRbMF0saT10WzFdO3IucHVzaChhKGUsbixpKSl9KTpyLnB1c2goYShlLG4ua2V5LCdWYXJpYWJsZSAiJCcraSsnIiBkb2VzIG5vdCBhcHBlYXIgaW4gYW55IEdyYXBoUUwgcXVlcnkuJykpfSkscn1mdW5jdGlvbiBvKGUsdCl7aWYoZSBpbnN0YW5jZW9mIHAuR3JhcGhRTE5vbk51bGwpcmV0dXJuIk51bGwiPT09dC5raW5kP1tbdCwnVHlwZSAiJytlKyciIGlzIG5vbi1udWxsYWJsZSBhbmQgY2Fubm90IGJlIG51bGwuJ11dOm8oZS5vZlR5cGUsdCk7aWYoIk51bGwiPT09dC5raW5kKXJldHVybltdO2lmKGUgaW5zdGFuY2VvZiBwLkdyYXBoUUxMaXN0KXt2YXIgbj1lLm9mVHlwZTtyZXR1cm4iQXJyYXkiPT09dC5raW5kP3UodC52YWx1ZXMsZnVuY3Rpb24oZSl7cmV0dXJuIG8obixlKX0pOm8obix0KX1pZihlIGluc3RhbmNlb2YgcC5HcmFwaFFMSW5wdXRPYmplY3RUeXBlKXtpZigiT2JqZWN0IiE9PXQua2luZClyZXR1cm5bW3QsJ1R5cGUgIicrZSsnIiBtdXN0IGJlIGFuIE9iamVjdC4nXV07dmFyIHI9T2JqZWN0LmNyZWF0ZShudWxsKSxpPXUodC5tZW1iZXJzLGZ1bmN0aW9uKHQpe3ZhciBuPXQua2V5LnZhbHVlO3Jbbl09ITA7dmFyIGk9ZS5nZXRGaWVsZHMoKVtuXTtyZXR1cm4gaT9vKGk/aS50eXBlOnZvaWQgMCx0LnZhbHVlKTpbW3Qua2V5LCdUeXBlICInK2UrJyIgZG9lcyBub3QgaGF2ZSBhIGZpZWxkICInK24rJyIuJ11dfSk7cmV0dXJuIE9iamVjdC5rZXlzKGUuZ2V0RmllbGRzKCkpLmZvckVhY2goZnVuY3Rpb24obil7aWYoIXJbbl0pe2UuZ2V0RmllbGRzKClbbl0udHlwZSBpbnN0YW5jZW9mIHAuR3JhcGhRTE5vbk51bGwmJmkucHVzaChbdCwnT2JqZWN0IG9mIHR5cGUgIicrZSsnIiBpcyBtaXNzaW5nIHJlcXVpcmVkIGZpZWxkICInK24rJyIuJ10pfX0pLGl9cmV0dXJuIkJvb2xlYW4iPT09ZS5uYW1lJiYiQm9vbGVhbiIhPT10LmtpbmR8fCJTdHJpbmciPT09ZS5uYW1lJiYiU3RyaW5nIiE9PXQua2luZHx8IklEIj09PWUubmFtZSYmIk51bWJlciIhPT10LmtpbmQmJiJTdHJpbmciIT09dC5raW5kfHwiRmxvYXQiPT09ZS5uYW1lJiYiTnVtYmVyIiE9PXQua2luZHx8IkludCI9PT1lLm5hbWUmJigiTnVtYmVyIiE9PXQua2luZHx8KDB8dC52YWx1ZSkhPT10LnZhbHVlKT9bW3QsJ0V4cGVjdGVkIHZhbHVlIG9mIHR5cGUgIicrZSsnIi4nXV06KGUgaW5zdGFuY2VvZiBwLkdyYXBoUUxFbnVtVHlwZXx8ZSBpbnN0YW5jZW9mIHAuR3JhcGhRTFNjYWxhclR5cGUpJiYoIlN0cmluZyIhPT10LmtpbmQmJiJOdW1iZXIiIT09dC5raW5kJiYiQm9vbGVhbiIhPT10LmtpbmQmJiJOdWxsIiE9PXQua2luZHx8cyhlLnBhcnNlVmFsdWUodC52YWx1ZSkpKT9bW3QsJ0V4cGVjdGVkIHZhbHVlIG9mIHR5cGUgIicrZSsnIi4nXV06W119ZnVuY3Rpb24gYShlLHQsbil7cmV0dXJue21lc3NhZ2U6bixzZXZlcml0eToiZXJyb3IiLHR5cGU6InZhbGlkYXRpb24iLGZyb206ZS5wb3NGcm9tSW5kZXgodC5zdGFydCksdG86ZS5wb3NGcm9tSW5kZXgodC5lbmQpfX1mdW5jdGlvbiBzKGUpe3JldHVybiBudWxsPT09ZXx8dm9pZCAwPT09ZXx8ZSE9PWV9ZnVuY3Rpb24gdShlLHQpe3JldHVybiBBcnJheS5wcm90b3R5cGUuY29uY2F0LmFwcGx5KFtdLGUubWFwKHQpKX12YXIgYz1uKDIpLGw9cihjKSxwPW4oNyksZj1uKDYyNyksZD1yKGYpO2wuZGVmYXVsdC5yZWdpc3RlckhlbHBlcigibGludCIsImdyYXBocWwtdmFyaWFibGVzIixmdW5jdGlvbihlLHQsbil7aWYoIWUpcmV0dXJuW107dmFyIHI9dm9pZCAwO3RyeXtyPSgwLGQuZGVmYXVsdCkoZSl9Y2F0Y2goZSl7aWYoZS5zdGFjayl0aHJvdyBlO3JldHVyblthKG4sZSxlLm1lc3NhZ2UpXX12YXIgbz10LnZhcmlhYmxlVG9UeXBlO3JldHVybiBvP2kobixvLHIpOltdfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPWUubGV2ZWxzO3JldHVybihuJiYwIT09bi5sZW5ndGg/bltuLmxlbmd0aC0xXS0odGhpcy5lbGVjdHJpY0lucHV0LnRlc3QodCk/MTowKTplLmluZGVudExldmVsKSp0aGlzLmNvbmZpZy5pbmRlbnRVbml0fWZ1bmN0aW9uIGkoZSl7cmV0dXJue3N0eWxlOmUsbWF0Y2g6ZnVuY3Rpb24oZSl7cmV0dXJuIlN0cmluZyI9PT1lLmtpbmR9LHVwZGF0ZTpmdW5jdGlvbihlLHQpe2UubmFtZT10LnZhbHVlLnNsaWNlKDEsLTEpfX19dmFyIG89bigyKSxhPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0obykscz1uKDcxKTthLmRlZmF1bHQuZGVmaW5lTW9kZSgiZ3JhcGhxbC12YXJpYWJsZXMiLGZ1bmN0aW9uKGUpe3ZhciB0PSgwLHMub25saW5lUGFyc2VyKSh7ZWF0V2hpdGVzcGFjZTpmdW5jdGlvbihlKXtyZXR1cm4gZS5lYXRTcGFjZSgpfSxsZXhSdWxlczp1LHBhcnNlUnVsZXM6YyxlZGl0b3JDb25maWc6e3RhYlNpemU6ZS50YWJTaXplfX0pO3JldHVybntjb25maWc6ZSxzdGFydFN0YXRlOnQuc3RhcnRTdGF0ZSx0b2tlbjp0LnRva2VuLGluZGVudDpyLGVsZWN0cmljSW5wdXQ6L15ccypbfVxdXS8sZm9sZDoiYnJhY2UiLGNsb3NlQnJhY2tldHM6e3BhaXJzOidbXXt9IiInLGV4cGxvZGU6Iltde30ifX19KTt2YXIgdT17UHVuY3R1YXRpb246L15cW3xdfFx7fFx9fDp8LC8sTnVtYmVyOi9eLT8oPzowfCg/OlsxLTldWzAtOV0qKSkoPzpcLlswLTldKik/KD86W2VFXVsrLV0/WzAtOV0rKT8vLFN0cmluZzovXiIoPzpbXiJcXF18XFwoPzoifFwvfFxcfGJ8ZnxufHJ8dHx1WzAtOWEtZkEtRl17NH0pKSoiPy8sS2V5d29yZDovXnRydWV8ZmFsc2V8bnVsbC99LGM9e0RvY3VtZW50OlsoMCxzLnApKCJ7IiksKDAscy5saXN0KSgiVmFyaWFibGUiLCgwLHMub3B0KSgoMCxzLnApKCIsIikpKSwoMCxzLnApKCJ9IildLFZhcmlhYmxlOltpKCJ2YXJpYWJsZSIpLCgwLHMucCkoIjoiKSwiVmFsdWUiXSxWYWx1ZTpmdW5jdGlvbihlKXtzd2l0Y2goZS5raW5kKXtjYXNlIk51bWJlciI6cmV0dXJuIk51bWJlclZhbHVlIjtjYXNlIlN0cmluZyI6cmV0dXJuIlN0cmluZ1ZhbHVlIjtjYXNlIlB1bmN0dWF0aW9uIjpzd2l0Y2goZS52YWx1ZSl7Y2FzZSJbIjpyZXR1cm4iTGlzdFZhbHVlIjtjYXNlInsiOnJldHVybiJPYmplY3RWYWx1ZSJ9cmV0dXJuIG51bGw7Y2FzZSJLZXl3b3JkIjpzd2l0Y2goZS52YWx1ZSl7Y2FzZSJ0cnVlIjpjYXNlImZhbHNlIjpyZXR1cm4iQm9vbGVhblZhbHVlIjtjYXNlIm51bGwiOnJldHVybiJOdWxsVmFsdWUifXJldHVybiBudWxsfX0sTnVtYmVyVmFsdWU6WygwLHMudCkoIk51bWJlciIsIm51bWJlciIpXSxTdHJpbmdWYWx1ZTpbKDAscy50KSgiU3RyaW5nIiwic3RyaW5nIildLEJvb2xlYW5WYWx1ZTpbKDAscy50KSgiS2V5d29yZCIsImJ1aWx0aW4iKV0sTnVsbFZhbHVlOlsoMCxzLnQpKCJLZXl3b3JkIiwia2V5d29yZCIpXSxMaXN0VmFsdWU6WygwLHMucCkoIlsiKSwoMCxzLmxpc3QpKCJWYWx1ZSIsKDAscy5vcHQpKCgwLHMucCkoIiwiKSkpLCgwLHMucCkoIl0iKV0sT2JqZWN0VmFsdWU6WygwLHMucCkoInsiKSwoMCxzLmxpc3QpKCJPYmplY3RGaWVsZCIsKDAscy5vcHQpKCgwLHMucCkoIiwiKSkpLCgwLHMucCkoIn0iKV0sT2JqZWN0RmllbGQ6W2koImF0dHJpYnV0ZSIpLCgwLHMucCkoIjoiKSwiVmFsdWUiXX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtmb3IodmFyIHQ9MCxuPWU7bi5vZmZzZXRQYXJlbnQ7KXQrPW4ub2Zmc2V0TGVmdCxuPW4ub2Zmc2V0UGFyZW50O3JldHVybiB0fWZ1bmN0aW9uIGkoZSl7Zm9yKHZhciB0PTAsbj1lO24ub2Zmc2V0UGFyZW50Oyl0Kz1uLm9mZnNldFRvcCxuPW4ub2Zmc2V0UGFyZW50O3JldHVybiB0fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmdldExlZnQ9cix0LmdldFRvcD1pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9bigxKSxzPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gbnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzfXJldHVybiByKHQsZSksdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcyx0PWUubGFiZWwsbj1lLmFjdGl2ZUNvbG9yLHI9ZS5hY3RpdmUsaT1lLm9uQ2xpY2ssYT1lLnRhYldpZHRoO3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoYyx7b25DbGljazppLGFjdGl2ZUNvbG9yOm4sYWN0aXZlOnIsdGFiV2lkdGg6YX0sdCl9LHR9KG8uUHVyZUNvbXBvbmVudCk7dC5kZWZhdWx0PXM7dmFyIHUsYz1hLnN0eWxlZCgiZGl2IikodXx8KHU9aShbIlxuICB6LWluZGV4OiAiLCI7XG4gIHBhZGRpbmc6IDhweCA4cHggOHB4IDhweDtcbiAgYm9yZGVyLXJhZGl1czogMnB4IDJweCAwcHggMHB4O1xuICBjb2xvcjogIiwiO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGJveC1zaGFkb3c6IC0xcHggMXB4IDZweCAwIHJnYmEoMCwgMCwgMCwgMC4zKTtcbiAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xuICBmb250LXdlaWdodDogNjAwO1xuICBmb250LXNpemU6IDEycHg7XG4gIGxpbmUtaGVpZ2h0OiAxMnB4O1xuICBsZXR0ZXItc3BhY2luZzogMC40NXB4O1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIHRyYW5zZm9ybTogcm90YXRlKC05MGRlZyk7XG4gIHRyYW5zZm9ybS1vcmlnaW46IGJvdHRvbSBsZWZ0O1xuICBtYXJnaW4tdG9wOiA2NXB4O1xuICB3aWR0aDogIiwiO1xuIl0sWyJcbiAgei1pbmRleDogIiwiO1xuICBwYWRkaW5nOiA4cHggOHB4IDhweCA4cHg7XG4gIGJvcmRlci1yYWRpdXM6IDJweCAycHggMHB4IDBweDtcbiAgY29sb3I6ICIsIjtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBib3gtc2hhZG93OiAtMXB4IDFweCA2cHggMCByZ2JhKDAsIDAsIDAsIDAuMyk7XG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgZm9udC1zaXplOiAxMnB4O1xuICBsaW5lLWhlaWdodDogMTJweDtcbiAgbGV0dGVyLXNwYWNpbmc6IDAuNDVweDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICB0cmFuc2Zvcm06IHJvdGF0ZSgtOTBkZWcpO1xuICB0cmFuc2Zvcm0tb3JpZ2luOiBib3R0b20gbGVmdDtcbiAgbWFyZ2luLXRvcDogNjVweDtcbiAgd2lkdGg6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUuYWN0aXZlPzEwOjJ9LGZ1bmN0aW9uKGUpe3JldHVybiJkYXJrIj09PWUudGhlbWUubW9kZT9lLnRoZW1lLmNvbG91cnMud2hpdGU6ZS50aGVtZS5jb2xvdXJzW2UuYWN0aXZlPyJ3aGl0ZSI6ImRhcmtCbHVlIl19LGZ1bmN0aW9uKGUpe3JldHVybiBlLmFjdGl2ZSYmZS5hY3RpdmVDb2xvcj9lLnRoZW1lLmNvbG91cnNbZS5hY3RpdmVDb2xvcl06ImRhcmsiPT09ZS50aGVtZS5tb2RlPyIjM0Q1ODY2IjoiI0RCREVFMCJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRhYldpZHRofHwiMTAwJSJ9KX0sZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe2lmKGUmJiJvYmplY3QiPT09dHlwZW9mIGUpe3ZhciB0PWUud2hpY2h8fGUua2V5Q29kZXx8ZS5jaGFyQ29kZTt0JiYoZT10KX1pZigibnVtYmVyIj09PXR5cGVvZiBlKXJldHVybiBhW2VdO3ZhciBuPVN0cmluZyhlKSxvPXJbbi50b0xvd2VyQ2FzZSgpXTtpZihvKXJldHVybiBvO3ZhciBvPWlbbi50b0xvd2VyQ2FzZSgpXTtyZXR1cm4gb3x8KDE9PT1uLmxlbmd0aD9uLmNoYXJDb2RlQXQoMCk6dm9pZCAwKX1uLmlzRXZlbnRLZXk9ZnVuY3Rpb24oZSx0KXtpZihlJiYib2JqZWN0Ij09PXR5cGVvZiBlKXt2YXIgbj1lLndoaWNofHxlLmtleUNvZGV8fGUuY2hhckNvZGU7aWYobnVsbD09PW58fHZvaWQgMD09PW4pcmV0dXJuITE7aWYoInN0cmluZyI9PT10eXBlb2YgdCl7dmFyIG89clt0LnRvTG93ZXJDYXNlKCldO2lmKG8pcmV0dXJuIG89PT1uO3ZhciBvPWlbdC50b0xvd2VyQ2FzZSgpXTtpZihvKXJldHVybiBvPT09bn1lbHNlIGlmKCJudW1iZXIiPT09dHlwZW9mIHQpcmV0dXJuIHQ9PT1uO3JldHVybiExfX0sdD1lLmV4cG9ydHM9bjt2YXIgcj10LmNvZGU9dC5jb2Rlcz17YmFja3NwYWNlOjgsdGFiOjksZW50ZXI6MTMsc2hpZnQ6MTYsY3RybDoxNyxhbHQ6MTgsInBhdXNlL2JyZWFrIjoxOSwiY2FwcyBsb2NrIjoyMCxlc2M6Mjcsc3BhY2U6MzIsInBhZ2UgdXAiOjMzLCJwYWdlIGRvd24iOjM0LGVuZDozNSxob21lOjM2LGxlZnQ6MzcsdXA6MzgscmlnaHQ6MzksZG93bjo0MCxpbnNlcnQ6NDUsZGVsZXRlOjQ2LGNvbW1hbmQ6OTEsImxlZnQgY29tbWFuZCI6OTEsInJpZ2h0IGNvbW1hbmQiOjkzLCJudW1wYWQgKiI6MTA2LCJudW1wYWQgKyI6MTA3LCJudW1wYWQgLSI6MTA5LCJudW1wYWQgLiI6MTEwLCJudW1wYWQgLyI6MTExLCJudW0gbG9jayI6MTQ0LCJzY3JvbGwgbG9jayI6MTQ1LCJteSBjb21wdXRlciI6MTgyLCJteSBjYWxjdWxhdG9yIjoxODMsIjsiOjE4NiwiPSI6MTg3LCIsIjoxODgsIi0iOjE4OSwiLiI6MTkwLCIvIjoxOTEsImAiOjE5MiwiWyI6MjE5LCJcXCI6MjIwLCJdIjoyMjEsIiciOjIyMn0saT10LmFsaWFzZXM9e3dpbmRvd3M6OTEsIlx1MjFlNyI6MTYsIlx1MjMyNSI6MTgsIlx1MjMwMyI6MTcsIlx1MjMxOCI6OTEsY3RsOjE3LGNvbnRyb2w6MTcsb3B0aW9uOjE4LHBhdXNlOjE5LGJyZWFrOjE5LGNhcHM6MjAscmV0dXJuOjEzLGVzY2FwZToyNyxzcGM6MzIsc3BhY2ViYXI6MzIscGd1cDozMyxwZ2RuOjM0LGluczo0NSxkZWw6NDYsY21kOjkxfTtmb3Iobz05NztvPDEyMztvKyspcltTdHJpbmcuZnJvbUNoYXJDb2RlKG8pXT1vLTMyO2Zvcih2YXIgbz00ODtvPDU4O28rKylyW28tNDhdPW87Zm9yKG89MTtvPDEzO28rKylyWyJmIitvXT1vKzExMTtmb3Iobz0wO288MTA7bysrKXJbIm51bXBhZCAiK29dPW8rOTY7dmFyIGE9dC5uYW1lcz10LnRpdGxlPXt9O2ZvcihvIGluIHIpYVtyW29dXT1vO2Zvcih2YXIgcyBpbiBpKXJbc109aVtzXX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDEpO3QuRXJyb3JDb250YWluZXI9aS5zdHlsZWQuZGl2KG98fChvPXIoWyJcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG4gIGxlZnQ6IDA7XG4gIGxldHRlci1zcGFjaW5nOiAxcHg7XG4gIG9wYWNpdHk6IDAuNTtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICByaWdodDogMDtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICB0b3A6IDUwJTtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoMCwgLTUwJSk7XG4iXSxbIlxuICBmb250LXdlaWdodDogYm9sZDtcbiAgbGVmdDogMDtcbiAgbGV0dGVyLXNwYWNpbmc6IDFweDtcbiAgb3BhY2l0eTogMC41O1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHJpZ2h0OiAwO1xuICB0ZXh0LWFsaWduOiBjZW50ZXI7XG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gIHRvcDogNTAlO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgwLCAtNTAlKTtcbiJdKSkpO3ZhciBvfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4oT2JqZWN0LnZhbHVlc3x8ZnVuY3Rpb24oZSl7cmV0dXJuIE9iamVjdC5rZXlzKGUpLm1hcChmdW5jdGlvbih0KXtyZXR1cm4gZVt0XX0pfSkoZS5nZXRUeXBlTWFwKCkpLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5uYW1lLmxvY2FsZUNvbXBhcmUodC5uYW1lKX0pLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4hZC5pbmNsdWRlcyhlLm5hbWUpfSkubWFwKGZ1bmN0aW9uKHQpe3JldHVybiBjKHt9LHQscC5zZXJpYWxpemUoZSx0KSx7aW5zdGFuY2VPZjppKHQpfSl9KX1mdW5jdGlvbiBpKGUpe3JldHVybiBlIGluc3RhbmNlb2YgbC5HcmFwaFFMSW50ZXJmYWNlVHlwZT8iaW50ZXJmYWNlIjplIGluc3RhbmNlb2YgbC5HcmFwaFFMVW5pb25UeXBlPyJ1bmlvbiI6ZSBpbnN0YW5jZW9mIGwuR3JhcGhRTEVudW1UeXBlPyJlbnVtIjplIGluc3RhbmNlb2YgbC5HcmFwaFFMSW5wdXRPYmplY3RUeXBlPyJpbnB1dCI6InR5cGUifWZ1bmN0aW9uIG8oZSx0KXt2b2lkIDA9PT10JiYodD0hMCk7dmFyIG49ZS5yZXBsYWNlKC9eXHMqJCg/OlxyXG4/fFxuKS9nbSwiIikscj1uLnJlcGxhY2UoL1t9XS9nbSwiJCZcclxuIiksaT1yLnJlcGxhY2UoLyg/OnNjYWxhciApXHcrL2csIiQmXHJcbiIpO3JldHVybiB0P2k6aS5yZXBsYWNlKC8oPzpcI1tcd1wnXHNcclxuXCpdKC4qKSQpL2dtLCIkJlxyIil9ZnVuY3Rpb24gYShlLHQpe2lmKHZvaWQgMD09PXQmJih0PSEwKSxlIGluc3RhbmNlb2YgbC5HcmFwaFFMU2NoZW1hKXt2YXIgbj1sLnByaW50U2NoZW1hKGUse2NvbW1lbnREZXNjcmlwdGlvbnM6ITB9KTtpZih0KXt2YXIgcj1uLnJlcGxhY2UoLyhcI1tcd1wnXHNcclxuXCpdKC4qKSQpL2dtLCIiKTtyZXR1cm4gbyhmLnByZXR0aWZ5KHIse3ByaW50V2lkdGg6ODAsdGFiV2lkdGg6Mix1c2VUYWJzOiExfSksdCl9cmV0dXJuIG8oZi5wcmV0dGlmeShuLHtwcmludFdpZHRoOjgwLHRhYldpZHRoOjIsdXNlVGFiczohMX0pKX1yZXR1cm4iIn1mdW5jdGlvbiBzKGUsdCl7aWYoInNkbCI9PT10KXt2YXIgbj1hKGUsITEpLHI9InNjaGVtYS5ncmFwaHFsIjtyZXR1cm4gdShuLHIpfXZhciBuPUpTT04uc3RyaW5naWZ5KGUpLHI9Imluc3Ryb3NwZWN0aW9uU2NoZW1hLmpzb24iO3JldHVybiB1KG4scil9ZnVuY3Rpb24gdShlLHQsbil7dmFyIHI9bmV3IEJsb2IoW2VdLHt0eXBlOm58fCJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0ifSk7aWYoInVuZGVmaW5lZCIhPT10eXBlb2Ygd2luZG93Lm5hdmlnYXRvci5tc1NhdmVCbG9iKXdpbmRvdy5uYXZpZ2F0b3IubXNTYXZlQmxvYihyLHQpO2Vsc2V7dmFyIGk9d2luZG93LlVSTC5jcmVhdGVPYmplY3RVUkwociksbz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIik7by5zdHlsZS5kaXNwbGF5PSJub25lIixvLmhyZWY9aSxvLnNldEF0dHJpYnV0ZSgiZG93bmxvYWQiLHQpLCJ1bmRlZmluZWQiPT09dHlwZW9mIG8uZG93bmxvYWQmJm8uc2V0QXR0cmlidXRlKCJ0YXJnZXQiLCJfYmxhbmsiKSxkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKG8pLG8uY2xpY2soKSxkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKG8pLHdpbmRvdy5VUkwucmV2b2tlT2JqZWN0VVJMKGkpfX12YXIgYz1mdW5jdGlvbigpe3JldHVybiBjPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPTEscj1hcmd1bWVudHMubGVuZ3RoO248cjtuKyspe3Q9YXJndW1lbnRzW25dO2Zvcih2YXIgaSBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LGkpJiYoZVtpXT10W2ldKX1yZXR1cm4gZX0sYy5hcHBseSh0aGlzLGFyZ3VtZW50cyl9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbD1uKDcpLHA9big2NiksZj1uKDY1KSxkPVsiX19TY2hlbWEiLCJfX0RpcmVjdGl2ZSIsIl9fRGlyZWN0aXZlTG9jYXRpb24iLCJfX1R5cGUiLCJfX0ZpZWxkIiwiX19JbnB1dFZhbHVlIiwiX19FbnVtVmFsdWUiLCJfX1R5cGVLaW5kIiwiU3RyaW5nIiwiSUQiLCJCb29sZWFuIiwiSW50IiwiRmxvYXQiXTt0LnNkbEFycmF5PXIsdC5nZXRTREw9YSx0LmRvd25sb2FkU2NoZW1hPXN9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPW4oMjYyKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj0iPFtBLVphLXpdW0EtWmEtejAtOVxcLV0qKD86XFxzK1thLXpBLVpfOl1bYS16QS1aMC05Oi5fLV0qKD86XFxzKj1cXHMqKD86W15cIic9PD5gXFx4MDAtXFx4MjBdK3wnW14nXSonfFwiW15cIl0qXCIpKT8pKlxccypcXC8/PiIsaT0iPFxcL1tBLVphLXpdW0EtWmEtejAtOVxcLV0qXFxzKj4iLG89bmV3IFJlZ0V4cCgiXig/OiIrcisifCIraSsifFx4M2MhLS0tLVx4M2V8XHgzYyEtLSg/Oi0/W14+LV0pKD86LT9bXi1dKSotLVx4M2V8PFs/XS4qP1s/XT58PCFbQS1aXStcXHMrW14+XSo+fDwhXFxbQ0RBVEFcXFtbXFxzXFxTXSo/XFxdXFxdPikiKSxhPW5ldyBSZWdFeHAoIl4oPzoiK3IrInwiK2krIikiKTtlLmV4cG9ydHMuSFRNTF9UQUdfUkU9byxlLmV4cG9ydHMuSFRNTF9PUEVOX0NMT1NFX1RBR19SRT1hfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cy50b2tlbml6ZT1mdW5jdGlvbihlLHQpe3ZhciBuLHIsaSxvLGEscz1lLnBvcyx1PWUuc3JjLmNoYXJDb2RlQXQocyk7aWYodClyZXR1cm4hMTtpZigxMjYhPT11KXJldHVybiExO2lmKHI9ZS5zY2FuRGVsaW1zKGUucG9zLCEwKSxvPXIubGVuZ3RoLGE9U3RyaW5nLmZyb21DaGFyQ29kZSh1KSxvPDIpcmV0dXJuITE7Zm9yKG8lMiYmKGk9ZS5wdXNoKCJ0ZXh0IiwiIiwwKSxpLmNvbnRlbnQ9YSxvLS0pLG49MDtuPG87bis9MilpPWUucHVzaCgidGV4dCIsIiIsMCksaS5jb250ZW50PWErYSxlLmRlbGltaXRlcnMucHVzaCh7bWFya2VyOnUsanVtcDpuLHRva2VuOmUudG9rZW5zLmxlbmd0aC0xLGxldmVsOmUubGV2ZWwsZW5kOi0xLG9wZW46ci5jYW5fb3BlbixjbG9zZTpyLmNhbl9jbG9zZX0pO3JldHVybiBlLnBvcys9ci5sZW5ndGgsITB9LGUuZXhwb3J0cy5wb3N0UHJvY2Vzcz1mdW5jdGlvbihlKXt2YXIgdCxuLHIsaSxvLGE9W10scz1lLmRlbGltaXRlcnMsdT1lLmRlbGltaXRlcnMubGVuZ3RoO2Zvcih0PTA7dDx1O3QrKylyPXNbdF0sMTI2PT09ci5tYXJrZXImJi0xIT09ci5lbmQmJihpPXNbci5lbmRdLG89ZS50b2tlbnNbci50b2tlbl0sby50eXBlPSJzX29wZW4iLG8udGFnPSJzIixvLm5lc3Rpbmc9MSxvLm1hcmt1cD0ifn4iLG8uY29udGVudD0iIixvPWUudG9rZW5zW2kudG9rZW5dLG8udHlwZT0ic19jbG9zZSIsby50YWc9InMiLG8ubmVzdGluZz0tMSxvLm1hcmt1cD0ifn4iLG8uY29udGVudD0iIiwidGV4dCI9PT1lLnRva2Vuc1tpLnRva2VuLTFdLnR5cGUmJiJ+Ij09PWUudG9rZW5zW2kudG9rZW4tMV0uY29udGVudCYmYS5wdXNoKGkudG9rZW4tMSkpO2Zvcig7YS5sZW5ndGg7KXtmb3IodD1hLnBvcCgpLG49dCsxO248ZS50b2tlbnMubGVuZ3RoJiYic19jbG9zZSI9PT1lLnRva2Vuc1tuXS50eXBlOyluKys7bi0tLHQhPT1uJiYobz1lLnRva2Vuc1tuXSxlLnRva2Vuc1tuXT1lLnRva2Vuc1t0XSxlLnRva2Vuc1t0XT1vKX19fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cy50b2tlbml6ZT1mdW5jdGlvbihlLHQpe3ZhciBuLHIsaSxvPWUucG9zLGE9ZS5zcmMuY2hhckNvZGVBdChvKTtpZih0KXJldHVybiExO2lmKDk1IT09YSYmNDIhPT1hKXJldHVybiExO2ZvcihyPWUuc2NhbkRlbGltcyhlLnBvcyw0Mj09PWEpLG49MDtuPHIubGVuZ3RoO24rKylpPWUucHVzaCgidGV4dCIsIiIsMCksaS5jb250ZW50PVN0cmluZy5mcm9tQ2hhckNvZGUoYSksZS5kZWxpbWl0ZXJzLnB1c2goe21hcmtlcjphLGxlbmd0aDpyLmxlbmd0aCxqdW1wOm4sdG9rZW46ZS50b2tlbnMubGVuZ3RoLTEsbGV2ZWw6ZS5sZXZlbCxlbmQ6LTEsb3BlbjpyLmNhbl9vcGVuLGNsb3NlOnIuY2FuX2Nsb3NlfSk7cmV0dXJuIGUucG9zKz1yLmxlbmd0aCwhMH0sZS5leHBvcnRzLnBvc3RQcm9jZXNzPWZ1bmN0aW9uKGUpe3ZhciB0LG4scixpLG8sYSxzPWUuZGVsaW1pdGVycyx1PWUuZGVsaW1pdGVycy5sZW5ndGg7Zm9yKHQ9dS0xO3Q+PTA7dC0tKW49c1t0XSw5NSE9PW4ubWFya2VyJiY0MiE9PW4ubWFya2VyfHwtMSE9PW4uZW5kJiYocj1zW24uZW5kXSxhPXQ+MCYmc1t0LTFdLmVuZD09PW4uZW5kKzEmJnNbdC0xXS50b2tlbj09PW4udG9rZW4tMSYmc1tuLmVuZCsxXS50b2tlbj09PXIudG9rZW4rMSYmc1t0LTFdLm1hcmtlcj09PW4ubWFya2VyLG89U3RyaW5nLmZyb21DaGFyQ29kZShuLm1hcmtlciksaT1lLnRva2Vuc1tuLnRva2VuXSxpLnR5cGU9YT8ic3Ryb25nX29wZW4iOiJlbV9vcGVuIixpLnRhZz1hPyJzdHJvbmciOiJlbSIsaS5uZXN0aW5nPTEsaS5tYXJrdXA9YT9vK286byxpLmNvbnRlbnQ9IiIsaT1lLnRva2Vuc1tyLnRva2VuXSxpLnR5cGU9YT8ic3Ryb25nX2Nsb3NlIjoiZW1fY2xvc2UiLGkudGFnPWE/InN0cm9uZyI6ImVtIixpLm5lc3Rpbmc9LTEsaS5tYXJrdXA9YT9vK286byxpLmNvbnRlbnQ9IiIsYSYmKGUudG9rZW5zW3NbdC0xXS50b2tlbl0uY29udGVudD0iIixlLnRva2Vuc1tzW24uZW5kKzFdLnRva2VuXS5jb250ZW50PSIiLHQtLSkpfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDApLG89bigxKSxhPW8uc3R5bGVkLmRpdihzfHwocz1yKFsiXG4gIGNvbG9yOiByZ2JhKDAsIDAsIDAsIDAuMyk7XG4gIGN1cnNvcjogZGVmYXVsdDtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBmb250LXdlaWdodDogNjAwO1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlICFpbXBvcnRhbnQ7XG4gIGxldHRlci1zcGFjaW5nOiAxcHg7XG4gIHBhZGRpbmc6IDE2cHg7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuIl0sWyJcbiAgY29sb3I6IHJnYmEoMCwgMCwgMCwgMC4zKTtcbiAgY3Vyc29yOiBkZWZhdWx0O1xuICBmb250LXNpemU6IDE0cHg7XG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2UgIWltcG9ydGFudDtcbiAgbGV0dGVyLXNwYWNpbmc6IDFweDtcbiAgcGFkZGluZzogMTZweDtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4iXSkpKTt0LkNhdGVnb3J5VGl0bGU9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5jaGlsZHJlbjtyZXR1cm4gaS5jcmVhdGVFbGVtZW50KGEsbnVsbCx0KX07dmFyIHN9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigwKSxvPW4oMzYpLGE9bigxKSxzPWZ1bmN0aW9uKGUpe3ZhciB0PWUuY2hpbGRyZW4sbj1lLm92ZXJmbG93LHI9dm9pZCAwPT09bnx8bixhPWUud2lkdGgscz12b2lkIDA9PT1hP28uY29sdW1uV2lkdGg6YTtyZXR1cm4gaS5jcmVhdGVFbGVtZW50KGMse3N0eWxlOnt3aWR0aDpzfSx2ZXJ0aWNhbFNjcm9sbDpyfSx0KX07dC5kZWZhdWx0PXM7dmFyIHUsYz1hLnN0eWxlZCgiZGl2IikodXx8KHU9cihbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4OiAwIDAgYXV0bztcbiAgZmxleC1mbG93OiBjb2x1bW47XG4gIHBhZGRpbmctYm90dG9tOiAyMHB4O1xuICBib3JkZXItcmlnaHQ6IDFweCBzb2xpZCAiLCI7XG4gIG92ZXJmbG93LXg6ICIsIlxuICBvdmVyZmxvdy15OiAiLCJcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXg6IDAgMCBhdXRvO1xuICBmbGV4LWZsb3c6IGNvbHVtbjtcbiAgcGFkZGluZy1ib3R0b206IDIwcHg7XG4gIGJvcmRlci1yaWdodDogMXB4IHNvbGlkICIsIjtcbiAgb3ZlcmZsb3cteDogIiwiXG4gIG92ZXJmbG93LXk6ICIsIlxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5jb2xvdXJzLmJsYWNrMTB9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnZlcnRpY2FsU2Nyb2xsPyJoaWRkZW4iOiJhdXRvIn0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudmVydGljYWxTY3JvbGw/InNjcm9sbCI6ImF1dG8ifSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKSxpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPW4oMCksYT1uKDY5OSkscz1uKDI0KSx1PW4oMSksYz1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe3ZhciBuPWUuY2FsbCh0aGlzLHQpfHx0aGlzO3JldHVybiBuLmhhbmRsZUNoYW5nZT1mdW5jdGlvbihlKXtuLnNldFN0YXRlKHt2YWx1ZTplLnRhcmdldC52YWx1ZX0pLG4uZGVib3VuY2VkT25TZWFyY2goKX0sbi5zdGF0ZT17dmFsdWU6IiJ9LG4uZGVib3VuY2VkT25TZWFyY2g9YS5kZWZhdWx0KDIwMCxmdW5jdGlvbigpe24ucHJvcHMub25TZWFyY2gobi5zdGF0ZS52YWx1ZSl9KSxufXJldHVybiByKHQsZSksdC5wcm90b3R5cGUuc2hvdWxkQ29tcG9uZW50VXBkYXRlPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQudmFsdWUhPT10aGlzLnN0YXRlLnZhbHVlfSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgZT1vLmNyZWF0ZUVsZW1lbnQoaCxudWxsLG8uY3JlYXRlRWxlbWVudChzLlNlYXJjaCx7aGVpZ2h0OjE2LHdpZHRoOjE2LHN0cm9rZVdpZHRoOjMsY29sb3I6InJnYmEoMCwgMCwgMCwgMC4zKSJ9KSxvLmNyZWF0ZUVsZW1lbnQobSx7b25DaGFuZ2U6dGhpcy5oYW5kbGVDaGFuZ2UsdHlwZToidGV4dCIsdmFsdWU6dGhpcy5zdGF0ZS52YWx1ZSxwbGFjZWhvbGRlcjp0aGlzLnByb3BzLnBsYWNlaG9sZGVyfHwiU2VhcmNoIHRoZSBkb2NzIC4uLiJ9KSk7cmV0dXJuIHRoaXMucHJvcHMuY2xlYW4/ZTpvLmNyZWF0ZUVsZW1lbnQoZCxudWxsLGUpfSx0fShvLkNvbXBvbmVudCk7dC5kZWZhdWx0PWM7dmFyIGwscCxmLGQ9dS5zdHlsZWQuZGl2KGx8fChsPWkoWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBmbGV4OiAwIDAgYXV0bztcbiAgei1pbmRleDogMTtcbiAgZGlzcGxheTogZmxleDtcbiAgbWFyZ2luLWxlZnQ6IDZweDtcbiAgcGFkZGluZzogMjVweDtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBib3JkZXItYm90dG9tOiAxcHggc29saWQgIiwiO1xuICBkaXYge1xuICAgIHdpZHRoOiAxMDAlO1xuICB9XG4iXSxbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGZsZXg6IDAgMCBhdXRvO1xuICB6LWluZGV4OiAxO1xuICBkaXNwbGF5OiBmbGV4O1xuICBtYXJnaW4tbGVmdDogNnB4O1xuICBwYWRkaW5nOiAyNXB4O1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAiLCI7XG4gIGRpdiB7XG4gICAgd2lkdGg6IDEwMCU7XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5ibGFjazAyfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5jb2xvdXJzLmJsYWNrMTB9KSxoPXUuc3R5bGVkLmRpdihwfHwocD1pKFsiXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIHBhZGRpbmc6IDEycHggMTRweCAxM3B4IDE1cHg7XG4gIGJveC1zaGFkb3c6IDAgMXB4IDNweCByZ2JhKDAsIDAsIDAsIDAuMSk7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdLFsiXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIHBhZGRpbmc6IDEycHggMTRweCAxM3B4IDE1cHg7XG4gIGJveC1zaGFkb3c6IDAgMXB4IDNweCByZ2JhKDAsIDAsIDAsIDAuMSk7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy53aGl0ZX0pLG09dS5zdHlsZWQuaW5wdXQoZnx8KGY9aShbIlxuICBmb250LXNpemU6IDE2cHg7XG4gIG1hcmdpbi1sZWZ0OiAxMHB4O1xuICAmOjpwbGFjZWhvbGRlciB7XG4gICAgY29sb3I6ICIsIjtcbiAgfVxuIl0sWyJcbiAgZm9udC1zaXplOiAxNnB4O1xuICBtYXJnaW4tbGVmdDogMTBweDtcbiAgJjo6cGxhY2Vob2xkZXIge1xuICAgIGNvbG9yOiAiLCI7XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5ibGFjazMwfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4oZS5jb25maWdQYXRoP2UuY29uZmlnUGF0aCsifiI6IiIpKyhlLndvcmtzcGFjZU5hbWU/ZS53b3Jrc3BhY2VOYW1lKyJ+IjoiIikrZS5lbmRwb2ludH1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5nZXRXb3Jrc3BhY2VJZD1yfSxmdW5jdGlvbihlLHQpe3QuX19lc01vZHVsZT0hMDt2YXIgbj0odC5BVFRSSUJVVEVfTkFNRVM9e0JPRFk6ImJvZHlBdHRyaWJ1dGVzIixIVE1MOiJodG1sQXR0cmlidXRlcyIsVElUTEU6InRpdGxlQXR0cmlidXRlcyJ9LHQuVEFHX05BTUVTPXtCQVNFOiJiYXNlIixCT0RZOiJib2R5IixIRUFEOiJoZWFkIixIVE1MOiJodG1sIixMSU5LOiJsaW5rIixNRVRBOiJtZXRhIixOT1NDUklQVDoibm9zY3JpcHQiLFNDUklQVDoic2NyaXB0IixTVFlMRToic3R5bGUiLFRJVExFOiJ0aXRsZSJ9KSxyPSh0LlZBTElEX1RBR19OQU1FUz1PYmplY3Qua2V5cyhuKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIG5bZV19KSx0LlRBR19QUk9QRVJUSUVTPXtDSEFSU0VUOiJjaGFyc2V0IixDU1NfVEVYVDoiY3NzVGV4dCIsSFJFRjoiaHJlZiIsSFRUUEVRVUlWOiJodHRwLWVxdWl2IixJTk5FUl9IVE1MOiJpbm5lckhUTUwiLElURU1fUFJPUDoiaXRlbXByb3AiLE5BTUU6Im5hbWUiLFBST1BFUlRZOiJwcm9wZXJ0eSIsUkVMOiJyZWwiLFNSQzoic3JjIn0sdC5SRUFDVF9UQUdfTUFQPXthY2Nlc3NrZXk6ImFjY2Vzc0tleSIsY2hhcnNldDoiY2hhclNldCIsY2xhc3M6ImNsYXNzTmFtZSIsY29udGVudGVkaXRhYmxlOiJjb250ZW50RWRpdGFibGUiLGNvbnRleHRtZW51OiJjb250ZXh0TWVudSIsImh0dHAtZXF1aXYiOiJodHRwRXF1aXYiLGl0ZW1wcm9wOiJpdGVtUHJvcCIsdGFiaW5kZXg6InRhYkluZGV4In0pO3QuSEVMTUVUX1BST1BTPXtERUZBVUxUX1RJVExFOiJkZWZhdWx0VGl0bGUiLERFRkVSOiJkZWZlciIsRU5DT0RFX1NQRUNJQUxfQ0hBUkFDVEVSUzoiZW5jb2RlU3BlY2lhbENoYXJhY3RlcnMiLE9OX0NIQU5HRV9DTElFTlRfU1RBVEU6Im9uQ2hhbmdlQ2xpZW50U3RhdGUiLFRJVExFX1RFTVBMQVRFOiJ0aXRsZVRlbXBsYXRlIn0sdC5IVE1MX1RBR19NQVA9T2JqZWN0LmtleXMocikucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGVbclt0XV09dCxlfSx7fSksdC5TRUxGX0NMT1NJTkdfVEFHUz1bbi5OT1NDUklQVCxuLlNDUklQVCxuLlNUWUxFXSx0LkhFTE1FVF9BVFRSSUJVVEU9ImRhdGEtcmVhY3QtaGVsbWV0In0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDUzKTtlLmV4cG9ydHM9bmV3IHIoe2luY2x1ZGU6W24oMzA0KV19KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDUzKTtlLmV4cG9ydHM9bmV3IHIoe2luY2x1ZGU6W24oMTQ4KV0saW1wbGljaXQ6W24oNzI5KSxuKDczMCksbig3MzEpLG4oNzMyKV19KX0sZnVuY3Rpb24oZSx0KXshZnVuY3Rpb24oZSl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHQoZSl7aWYoInN0cmluZyIhPT10eXBlb2YgZSYmKGU9U3RyaW5nKGUpKSwvW15hLXowLTlcLSMkJSYnKisuXF5fYHx+XS9pLnRlc3QoZSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiSW52YWxpZCBjaGFyYWN0ZXIgaW4gaGVhZGVyIGZpZWxkIG5hbWUiKTtyZXR1cm4gZS50b0xvd2VyQ2FzZSgpfWZ1bmN0aW9uIG4oZSl7cmV0dXJuInN0cmluZyIhPT10eXBlb2YgZSYmKGU9U3RyaW5nKGUpKSxlfWZ1bmN0aW9uIHIoZSl7dmFyIHQ9e25leHQ6ZnVuY3Rpb24oKXt2YXIgdD1lLnNoaWZ0KCk7cmV0dXJue2RvbmU6dm9pZCAwPT09dCx2YWx1ZTp0fX19O3JldHVybiB5Lml0ZXJhYmxlJiYodFtTeW1ib2wuaXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHR9KSx0fWZ1bmN0aW9uIGkoZSl7dGhpcy5tYXA9e30sZSBpbnN0YW5jZW9mIGk/ZS5mb3JFYWNoKGZ1bmN0aW9uKGUsdCl7dGhpcy5hcHBlbmQodCxlKX0sdGhpcyk6QXJyYXkuaXNBcnJheShlKT9lLmZvckVhY2goZnVuY3Rpb24oZSl7dGhpcy5hcHBlbmQoZVswXSxlWzFdKX0sdGhpcyk6ZSYmT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoZSkuZm9yRWFjaChmdW5jdGlvbih0KXt0aGlzLmFwcGVuZCh0LGVbdF0pfSx0aGlzKX1mdW5jdGlvbiBvKGUpe2lmKGUuYm9keVVzZWQpcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBUeXBlRXJyb3IoIkFscmVhZHkgcmVhZCIpKTtlLmJvZHlVc2VkPSEwfWZ1bmN0aW9uIGEoZSl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHQsbil7ZS5vbmxvYWQ9ZnVuY3Rpb24oKXt0KGUucmVzdWx0KX0sZS5vbmVycm9yPWZ1bmN0aW9uKCl7bihlLmVycm9yKX19KX1mdW5jdGlvbiBzKGUpe3ZhciB0PW5ldyBGaWxlUmVhZGVyLG49YSh0KTtyZXR1cm4gdC5yZWFkQXNBcnJheUJ1ZmZlcihlKSxufWZ1bmN0aW9uIHUoZSl7dmFyIHQ9bmV3IEZpbGVSZWFkZXIsbj1hKHQpO3JldHVybiB0LnJlYWRBc1RleHQoZSksbn1mdW5jdGlvbiBjKGUpe2Zvcih2YXIgdD1uZXcgVWludDhBcnJheShlKSxuPW5ldyBBcnJheSh0Lmxlbmd0aCkscj0wO3I8dC5sZW5ndGg7cisrKW5bcl09U3RyaW5nLmZyb21DaGFyQ29kZSh0W3JdKTtyZXR1cm4gbi5qb2luKCIiKX1mdW5jdGlvbiBsKGUpe2lmKGUuc2xpY2UpcmV0dXJuIGUuc2xpY2UoMCk7dmFyIHQ9bmV3IFVpbnQ4QXJyYXkoZS5ieXRlTGVuZ3RoKTtyZXR1cm4gdC5zZXQobmV3IFVpbnQ4QXJyYXkoZSkpLHQuYnVmZmVyfWZ1bmN0aW9uIHAoKXtyZXR1cm4gdGhpcy5ib2R5VXNlZD0hMSx0aGlzLl9pbml0Qm9keT1mdW5jdGlvbihlKXtpZih0aGlzLl9ib2R5SW5pdD1lLGUpaWYoInN0cmluZyI9PT10eXBlb2YgZSl0aGlzLl9ib2R5VGV4dD1lO2Vsc2UgaWYoeS5ibG9iJiZCbG9iLnByb3RvdHlwZS5pc1Byb3RvdHlwZU9mKGUpKXRoaXMuX2JvZHlCbG9iPWU7ZWxzZSBpZih5LmZvcm1EYXRhJiZGb3JtRGF0YS5wcm90b3R5cGUuaXNQcm90b3R5cGVPZihlKSl0aGlzLl9ib2R5Rm9ybURhdGE9ZTtlbHNlIGlmKHkuc2VhcmNoUGFyYW1zJiZVUkxTZWFyY2hQYXJhbXMucHJvdG90eXBlLmlzUHJvdG90eXBlT2YoZSkpdGhpcy5fYm9keVRleHQ9ZS50b1N0cmluZygpO2Vsc2UgaWYoeS5hcnJheUJ1ZmZlciYmeS5ibG9iJiZiKGUpKXRoaXMuX2JvZHlBcnJheUJ1ZmZlcj1sKGUuYnVmZmVyKSx0aGlzLl9ib2R5SW5pdD1uZXcgQmxvYihbdGhpcy5fYm9keUFycmF5QnVmZmVyXSk7ZWxzZXtpZigheS5hcnJheUJ1ZmZlcnx8IUFycmF5QnVmZmVyLnByb3RvdHlwZS5pc1Byb3RvdHlwZU9mKGUpJiYheChlKSl0aHJvdyBuZXcgRXJyb3IoInVuc3VwcG9ydGVkIEJvZHlJbml0IHR5cGUiKTt0aGlzLl9ib2R5QXJyYXlCdWZmZXI9bChlKX1lbHNlIHRoaXMuX2JvZHlUZXh0PSIiO3RoaXMuaGVhZGVycy5nZXQoImNvbnRlbnQtdHlwZSIpfHwoInN0cmluZyI9PT10eXBlb2YgZT90aGlzLmhlYWRlcnMuc2V0KCJjb250ZW50LXR5cGUiLCJ0ZXh0L3BsYWluO2NoYXJzZXQ9VVRGLTgiKTp0aGlzLl9ib2R5QmxvYiYmdGhpcy5fYm9keUJsb2IudHlwZT90aGlzLmhlYWRlcnMuc2V0KCJjb250ZW50LXR5cGUiLHRoaXMuX2JvZHlCbG9iLnR5cGUpOnkuc2VhcmNoUGFyYW1zJiZVUkxTZWFyY2hQYXJhbXMucHJvdG90eXBlLmlzUHJvdG90eXBlT2YoZSkmJnRoaXMuaGVhZGVycy5zZXQoImNvbnRlbnQtdHlwZSIsImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PVVURi04IikpfSx5LmJsb2ImJih0aGlzLmJsb2I9ZnVuY3Rpb24oKXt2YXIgZT1vKHRoaXMpO2lmKGUpcmV0dXJuIGU7aWYodGhpcy5fYm9keUJsb2IpcmV0dXJuIFByb21pc2UucmVzb2x2ZSh0aGlzLl9ib2R5QmxvYik7aWYodGhpcy5fYm9keUFycmF5QnVmZmVyKXJldHVybiBQcm9taXNlLnJlc29sdmUobmV3IEJsb2IoW3RoaXMuX2JvZHlBcnJheUJ1ZmZlcl0pKTtpZih0aGlzLl9ib2R5Rm9ybURhdGEpdGhyb3cgbmV3IEVycm9yKCJjb3VsZCBub3QgcmVhZCBGb3JtRGF0YSBib2R5IGFzIGJsb2IiKTtyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG5ldyBCbG9iKFt0aGlzLl9ib2R5VGV4dF0pKX0sdGhpcy5hcnJheUJ1ZmZlcj1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9ib2R5QXJyYXlCdWZmZXI/byh0aGlzKXx8UHJvbWlzZS5yZXNvbHZlKHRoaXMuX2JvZHlBcnJheUJ1ZmZlcik6dGhpcy5ibG9iKCkudGhlbihzKX0pLHRoaXMudGV4dD1mdW5jdGlvbigpe3ZhciBlPW8odGhpcyk7aWYoZSlyZXR1cm4gZTtpZih0aGlzLl9ib2R5QmxvYilyZXR1cm4gdSh0aGlzLl9ib2R5QmxvYik7aWYodGhpcy5fYm9keUFycmF5QnVmZmVyKXJldHVybiBQcm9taXNlLnJlc29sdmUoYyh0aGlzLl9ib2R5QXJyYXlCdWZmZXIpKTtpZih0aGlzLl9ib2R5Rm9ybURhdGEpdGhyb3cgbmV3IEVycm9yKCJjb3VsZCBub3QgcmVhZCBGb3JtRGF0YSBib2R5IGFzIHRleHQiKTtyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMuX2JvZHlUZXh0KX0seS5mb3JtRGF0YSYmKHRoaXMuZm9ybURhdGE9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy50ZXh0KCkudGhlbihoKX0pLHRoaXMuanNvbj1mdW5jdGlvbigpe3JldHVybiB0aGlzLnRleHQoKS50aGVuKEpTT04ucGFyc2UpfSx0aGlzfWZ1bmN0aW9uIGYoZSl7dmFyIHQ9ZS50b1VwcGVyQ2FzZSgpO3JldHVybiBDLmluZGV4T2YodCk+LTE/dDplfWZ1bmN0aW9uIGQoZSx0KXt0PXR8fHt9O3ZhciBuPXQuYm9keTtpZihlIGluc3RhbmNlb2YgZCl7aWYoZS5ib2R5VXNlZCl0aHJvdyBuZXcgVHlwZUVycm9yKCJBbHJlYWR5IHJlYWQiKTt0aGlzLnVybD1lLnVybCx0aGlzLmNyZWRlbnRpYWxzPWUuY3JlZGVudGlhbHMsdC5oZWFkZXJzfHwodGhpcy5oZWFkZXJzPW5ldyBpKGUuaGVhZGVycykpLHRoaXMubWV0aG9kPWUubWV0aG9kLHRoaXMubW9kZT1lLm1vZGUsbnx8bnVsbD09ZS5fYm9keUluaXR8fChuPWUuX2JvZHlJbml0LGUuYm9keVVzZWQ9ITApfWVsc2UgdGhpcy51cmw9U3RyaW5nKGUpO2lmKHRoaXMuY3JlZGVudGlhbHM9dC5jcmVkZW50aWFsc3x8dGhpcy5jcmVkZW50aWFsc3x8Im9taXQiLCF0LmhlYWRlcnMmJnRoaXMuaGVhZGVyc3x8KHRoaXMuaGVhZGVycz1uZXcgaSh0LmhlYWRlcnMpKSx0aGlzLm1ldGhvZD1mKHQubWV0aG9kfHx0aGlzLm1ldGhvZHx8IkdFVCIpLHRoaXMubW9kZT10Lm1vZGV8fHRoaXMubW9kZXx8bnVsbCx0aGlzLnJlZmVycmVyPW51bGwsKCJHRVQiPT09dGhpcy5tZXRob2R8fCJIRUFEIj09PXRoaXMubWV0aG9kKSYmbil0aHJvdyBuZXcgVHlwZUVycm9yKCJCb2R5IG5vdCBhbGxvd2VkIGZvciBHRVQgb3IgSEVBRCByZXF1ZXN0cyIpO3RoaXMuX2luaXRCb2R5KG4pfWZ1bmN0aW9uIGgoZSl7dmFyIHQ9bmV3IEZvcm1EYXRhO3JldHVybiBlLnRyaW0oKS5zcGxpdCgiJiIpLmZvckVhY2goZnVuY3Rpb24oZSl7aWYoZSl7dmFyIG49ZS5zcGxpdCgiPSIpLHI9bi5zaGlmdCgpLnJlcGxhY2UoL1wrL2csIiAiKSxpPW4uam9pbigiPSIpLnJlcGxhY2UoL1wrL2csIiAiKTt0LmFwcGVuZChkZWNvZGVVUklDb21wb25lbnQociksZGVjb2RlVVJJQ29tcG9uZW50KGkpKX19KSx0fWZ1bmN0aW9uIG0oZSl7dmFyIHQ9bmV3IGk7cmV0dXJuIGUucmVwbGFjZSgvXHI/XG5bXHQgXSsvZywiICIpLnNwbGl0KC9ccj9cbi8pLmZvckVhY2goZnVuY3Rpb24oZSl7dmFyIG49ZS5zcGxpdCgiOiIpLHI9bi5zaGlmdCgpLnRyaW0oKTtpZihyKXt2YXIgaT1uLmpvaW4oIjoiKS50cmltKCk7dC5hcHBlbmQocixpKX19KSx0fWZ1bmN0aW9uIGcoZSx0KXt0fHwodD17fSksdGhpcy50eXBlPSJkZWZhdWx0Iix0aGlzLnN0YXR1cz12b2lkIDA9PT10LnN0YXR1cz8yMDA6dC5zdGF0dXMsdGhpcy5vaz10aGlzLnN0YXR1cz49MjAwJiZ0aGlzLnN0YXR1czwzMDAsdGhpcy5zdGF0dXNUZXh0PSJzdGF0dXNUZXh0ImluIHQ/dC5zdGF0dXNUZXh0OiJPSyIsdGhpcy5oZWFkZXJzPW5ldyBpKHQuaGVhZGVycyksdGhpcy51cmw9dC51cmx8fCIiLHRoaXMuX2luaXRCb2R5KGUpfWlmKCFlLmZldGNoKXt2YXIgeT17c2VhcmNoUGFyYW1zOiJVUkxTZWFyY2hQYXJhbXMiaW4gZSxpdGVyYWJsZToiU3ltYm9sImluIGUmJiJpdGVyYXRvciJpbiBTeW1ib2wsYmxvYjoiRmlsZVJlYWRlciJpbiBlJiYiQmxvYiJpbiBlJiZmdW5jdGlvbigpe3RyeXtyZXR1cm4gbmV3IEJsb2IsITB9Y2F0Y2goZSl7cmV0dXJuITF9fSgpLGZvcm1EYXRhOiJGb3JtRGF0YSJpbiBlLGFycmF5QnVmZmVyOiJBcnJheUJ1ZmZlciJpbiBlfTtpZih5LmFycmF5QnVmZmVyKXZhciB2PVsiW29iamVjdCBJbnQ4QXJyYXldIiwiW29iamVjdCBVaW50OEFycmF5XSIsIltvYmplY3QgVWludDhDbGFtcGVkQXJyYXldIiwiW29iamVjdCBJbnQxNkFycmF5XSIsIltvYmplY3QgVWludDE2QXJyYXldIiwiW29iamVjdCBJbnQzMkFycmF5XSIsIltvYmplY3QgVWludDMyQXJyYXldIiwiW29iamVjdCBGbG9hdDMyQXJyYXldIiwiW29iamVjdCBGbG9hdDY0QXJyYXldIl0sYj1mdW5jdGlvbihlKXtyZXR1cm4gZSYmRGF0YVZpZXcucHJvdG90eXBlLmlzUHJvdG90eXBlT2YoZSl9LHg9QXJyYXlCdWZmZXIuaXNWaWV3fHxmdW5jdGlvbihlKXtyZXR1cm4gZSYmdi5pbmRleE9mKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChlKSk+LTF9O2kucHJvdG90eXBlLmFwcGVuZD1mdW5jdGlvbihlLHIpe2U9dChlKSxyPW4ocik7dmFyIGk9dGhpcy5tYXBbZV07dGhpcy5tYXBbZV09aT9pKyIsIityOnJ9LGkucHJvdG90eXBlLmRlbGV0ZT1mdW5jdGlvbihlKXtkZWxldGUgdGhpcy5tYXBbdChlKV19LGkucHJvdG90eXBlLmdldD1mdW5jdGlvbihlKXtyZXR1cm4gZT10KGUpLHRoaXMuaGFzKGUpP3RoaXMubWFwW2VdOm51bGx9LGkucHJvdG90eXBlLmhhcz1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5tYXAuaGFzT3duUHJvcGVydHkodChlKSl9LGkucHJvdG90eXBlLnNldD1mdW5jdGlvbihlLHIpe3RoaXMubWFwW3QoZSldPW4ocil9LGkucHJvdG90eXBlLmZvckVhY2g9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdGhpcy5tYXApdGhpcy5tYXAuaGFzT3duUHJvcGVydHkobikmJmUuY2FsbCh0LHRoaXMubWFwW25dLG4sdGhpcyl9LGkucHJvdG90eXBlLmtleXM9ZnVuY3Rpb24oKXt2YXIgZT1bXTtyZXR1cm4gdGhpcy5mb3JFYWNoKGZ1bmN0aW9uKHQsbil7ZS5wdXNoKG4pfSkscihlKX0saS5wcm90b3R5cGUudmFsdWVzPWZ1bmN0aW9uKCl7dmFyIGU9W107cmV0dXJuIHRoaXMuZm9yRWFjaChmdW5jdGlvbih0KXtlLnB1c2godCl9KSxyKGUpfSxpLnByb3RvdHlwZS5lbnRyaWVzPWZ1bmN0aW9uKCl7dmFyIGU9W107cmV0dXJuIHRoaXMuZm9yRWFjaChmdW5jdGlvbih0LG4pe2UucHVzaChbbix0XSl9KSxyKGUpfSx5Lml0ZXJhYmxlJiYoaS5wcm90b3R5cGVbU3ltYm9sLml0ZXJhdG9yXT1pLnByb3RvdHlwZS5lbnRyaWVzKTt2YXIgQz1bIkRFTEVURSIsIkdFVCIsIkhFQUQiLCJPUFRJT05TIiwiUE9TVCIsIlBVVCJdO2QucHJvdG90eXBlLmNsb25lPWZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBkKHRoaXMse2JvZHk6dGhpcy5fYm9keUluaXR9KX0scC5jYWxsKGQucHJvdG90eXBlKSxwLmNhbGwoZy5wcm90b3R5cGUpLGcucHJvdG90eXBlLmNsb25lPWZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBnKHRoaXMuX2JvZHlJbml0LHtzdGF0dXM6dGhpcy5zdGF0dXMsc3RhdHVzVGV4dDp0aGlzLnN0YXR1c1RleHQsaGVhZGVyczpuZXcgaSh0aGlzLmhlYWRlcnMpLHVybDp0aGlzLnVybH0pfSxnLmVycm9yPWZ1bmN0aW9uKCl7dmFyIGU9bmV3IGcobnVsbCx7c3RhdHVzOjAsc3RhdHVzVGV4dDoiIn0pO3JldHVybiBlLnR5cGU9ImVycm9yIixlfTt2YXIgRT1bMzAxLDMwMiwzMDMsMzA3LDMwOF07Zy5yZWRpcmVjdD1mdW5jdGlvbihlLHQpe2lmKC0xPT09RS5pbmRleE9mKHQpKXRocm93IG5ldyBSYW5nZUVycm9yKCJJbnZhbGlkIHN0YXR1cyBjb2RlIik7cmV0dXJuIG5ldyBnKG51bGwse3N0YXR1czp0LGhlYWRlcnM6e2xvY2F0aW9uOmV9fSl9LGUuSGVhZGVycz1pLGUuUmVxdWVzdD1kLGUuUmVzcG9uc2U9ZyxlLmZldGNoPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKG4scil7dmFyIGk9bmV3IGQoZSx0KSxvPW5ldyBYTUxIdHRwUmVxdWVzdDtvLm9ubG9hZD1mdW5jdGlvbigpe3ZhciBlPXtzdGF0dXM6by5zdGF0dXMsc3RhdHVzVGV4dDpvLnN0YXR1c1RleHQsaGVhZGVyczptKG8uZ2V0QWxsUmVzcG9uc2VIZWFkZXJzKCl8fCIiKX07ZS51cmw9InJlc3BvbnNlVVJMImluIG8/by5yZXNwb25zZVVSTDplLmhlYWRlcnMuZ2V0KCJYLVJlcXVlc3QtVVJMIik7dmFyIHQ9InJlc3BvbnNlImluIG8/by5yZXNwb25zZTpvLnJlc3BvbnNlVGV4dDtuKG5ldyBnKHQsZSkpfSxvLm9uZXJyb3I9ZnVuY3Rpb24oKXtyKG5ldyBUeXBlRXJyb3IoIk5ldHdvcmsgcmVxdWVzdCBmYWlsZWQiKSl9LG8ub250aW1lb3V0PWZ1bmN0aW9uKCl7cihuZXcgVHlwZUVycm9yKCJOZXR3b3JrIHJlcXVlc3QgZmFpbGVkIikpfSxvLm9wZW4oaS5tZXRob2QsaS51cmwsITApLCJpbmNsdWRlIj09PWkuY3JlZGVudGlhbHM/by53aXRoQ3JlZGVudGlhbHM9ITA6Im9taXQiPT09aS5jcmVkZW50aWFscyYmKG8ud2l0aENyZWRlbnRpYWxzPSExKSwicmVzcG9uc2VUeXBlImluIG8mJnkuYmxvYiYmKG8ucmVzcG9uc2VUeXBlPSJibG9iIiksaS5oZWFkZXJzLmZvckVhY2goZnVuY3Rpb24oZSx0KXtvLnNldFJlcXVlc3RIZWFkZXIodCxlKX0pLG8uc2VuZCgidW5kZWZpbmVkIj09PXR5cGVvZiBpLl9ib2R5SW5pdD9udWxsOmkuX2JvZHlJbml0KX0pfSxlLmZldGNoLnBvbHlmaWxsPSEwfX0oInVuZGVmaW5lZCIhPT10eXBlb2Ygc2VsZj9zZWxmOnRoaXMpfSwsZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9big1MTgpLGk9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShyKTt0LmRlZmF1bHQ9aS5kZWZhdWx0LGUuZXhwb3J0cz10LmRlZmF1bHR9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigwKSxvPW4oMSksYT1uKDI0KTt0LkJ1dHRvbj1mdW5jdGlvbihlKXt2YXIgbj1lLnB1cnBsZSxyPWUuaGlkZUFycm93LG89ZS5jaGlsZHJlbixzPWUub25DbGljaztyZXR1cm4gaS5jcmVhdGVFbGVtZW50KHQuQnV0dG9uQm94LHtwdXJwbGU6bixvbkNsaWNrOnN9LG98fCJMZWFybiBtb3JlIiwhciYmaS5jcmVhdGVFbGVtZW50KGEuRnVsbEFycm93UmlnaHRJY29uLHtjb2xvcjoicmVkIix3aWR0aDoxNCxoZWlnaHQ6MTF9KSl9LHQuQnV0dG9uQm94PW8uc3R5bGVkKCJkaXYiKShzfHwocz1yKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG5cbiAgcGFkZGluZzogNnB4IDE2cHg7XG4gIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBjb2xvcjogIiwiO1xuICBib3gtc2hhZG93OiAwIDFweCAzcHggMCByZ2JhKDAsIDAsIDAsIDAuMik7XG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgbGV0dGVyLXNwYWNpbmc6IDFweDtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcblxuICB0cmFuc2l0aW9uOiBiYWNrZ3JvdW5kIDAuMjVzIGVhc2UsIGJveC1zaGFkb3cgMC4yNXMgZWFzZSwgdHJhbnNmb3JtIDAuMjVzIGVhc2U7XG4gIGN1cnNvcjogcG9pbnRlcjtcbiAgJjpob3ZlciB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICAgIHRyYW5zZm9ybTogIiwiO1xuICAgIHN2ZyB7XG4gICAgICBhbmltYXRpb246IG1vdmUgMXMgZWFzZSBpbmZpbml0ZTtcbiAgICB9XG4gIH1cblxuICBzdmcge1xuICAgIG1hcmdpbi1sZWZ0OiAxMHB4O1xuICAgIGZpbGw6ICIsIjtcbiAgfVxuXG4gIEBrZXlmcmFtZXMgbW92ZSB7XG4gICAgMCUge1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzRCgwLCAwLCAwKTtcbiAgICB9XG5cbiAgICA1MCUge1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzRCgzcHgsIDAsIDApO1xuICAgIH1cblxuICAgIDEwMCUge1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzRCgwLCAwLCAwKTtcbiAgICB9XG4gIH1cbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG5cbiAgcGFkZGluZzogNnB4IDE2cHg7XG4gIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBjb2xvcjogIiwiO1xuICBib3gtc2hhZG93OiAwIDFweCAzcHggMCByZ2JhKDAsIDAsIDAsIDAuMik7XG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgbGV0dGVyLXNwYWNpbmc6IDFweDtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcblxuICB0cmFuc2l0aW9uOiBiYWNrZ3JvdW5kIDAuMjVzIGVhc2UsIGJveC1zaGFkb3cgMC4yNXMgZWFzZSwgdHJhbnNmb3JtIDAuMjVzIGVhc2U7XG4gIGN1cnNvcjogcG9pbnRlcjtcbiAgJjpob3ZlciB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICAgIHRyYW5zZm9ybTogIiwiO1xuICAgIHN2ZyB7XG4gICAgICBhbmltYXRpb246IG1vdmUgMXMgZWFzZSBpbmZpbml0ZTtcbiAgICB9XG4gIH1cblxuICBzdmcge1xuICAgIG1hcmdpbi1sZWZ0OiAxMHB4O1xuICAgIGZpbGw6ICIsIjtcbiAgfVxuXG4gIEBrZXlmcmFtZXMgbW92ZSB7XG4gICAgMCUge1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzRCgwLCAwLCAwKTtcbiAgICB9XG5cbiAgICA1MCUge1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzRCgzcHgsIDAsIDApO1xuICAgIH1cblxuICAgIDEwMCUge1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzRCgwLCAwLCAwKTtcbiAgICB9XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUucHVycGxlPyJyZ2IoMjE4LCAyNywgMTI3KSI6IiMyYTdlZDIifSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5jb2xvdXJzLndoaXRlfSxmdW5jdGlvbihlKXtyZXR1cm4gZS5wdXJwbGU/InJnYigxNjQsIDMsIDExMSkiOiIjM2Y4YWQ3In0sZnVuY3Rpb24oZSl7cmV0dXJuIGUucHVycGxlPyJ0cmFuc2xhdGUzRCgwLCAwLCAwKSI6InRyYW5zbGF0ZTNEKDAsIC0xcHgsIDApIn0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy53aGl0ZX0pO3ZhciBzfSxmdW5jdGlvbihlLHQsbil7InVuZGVmaW5lZCI9PT10eXBlb2YgUHJvbWlzZSYmKG4oMzEwKS5lbmFibGUoKSx3aW5kb3cuUHJvbWlzZT1uKDMxMikpLG4oMzA1KSxPYmplY3QuYXNzaWduPW4oNTQpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXtjPSExLHMuXzQ3PW51bGwscy5fNzE9bnVsbH1mdW5jdGlvbiBpKGUpe2Z1bmN0aW9uIHQodCl7KGUuYWxsUmVqZWN0aW9uc3x8YShwW3RdLmVycm9yLGUud2hpdGVsaXN0fHx1KSkmJihwW3RdLmRpc3BsYXlJZD1sKyssZS5vblVuaGFuZGxlZD8ocFt0XS5sb2dnZWQ9ITAsZS5vblVuaGFuZGxlZChwW3RdLmRpc3BsYXlJZCxwW3RdLmVycm9yKSk6KHBbdF0ubG9nZ2VkPSEwLG8ocFt0XS5kaXNwbGF5SWQscFt0XS5lcnJvcikpKX1mdW5jdGlvbiBuKHQpe3BbdF0ubG9nZ2VkJiYoZS5vbkhhbmRsZWQ/ZS5vbkhhbmRsZWQocFt0XS5kaXNwbGF5SWQscFt0XS5lcnJvcik6cFt0XS5vblVuaGFuZGxlZHx8KGNvbnNvbGUud2FybigiUHJvbWlzZSBSZWplY3Rpb24gSGFuZGxlZCAoaWQ6ICIrcFt0XS5kaXNwbGF5SWQrIik6IiksY29uc29sZS53YXJuKCcgIFRoaXMgbWVhbnMgeW91IGNhbiBpZ25vcmUgYW55IHByZXZpb3VzIG1lc3NhZ2VzIG9mIHRoZSBmb3JtICJQb3NzaWJsZSBVbmhhbmRsZWQgUHJvbWlzZSBSZWplY3Rpb24iIHdpdGggaWQgJytwW3RdLmRpc3BsYXlJZCsiLiIpKSl9ZT1lfHx7fSxjJiZyKCksYz0hMDt2YXIgaT0wLGw9MCxwPXt9O3MuXzQ3PWZ1bmN0aW9uKGUpezI9PT1lLl84MyYmcFtlLl81Nl0mJihwW2UuXzU2XS5sb2dnZWQ/bihlLl81Nik6Y2xlYXJUaW1lb3V0KHBbZS5fNTZdLnRpbWVvdXQpLGRlbGV0ZSBwW2UuXzU2XSl9LHMuXzcxPWZ1bmN0aW9uKGUsbil7MD09PWUuXzc1JiYoZS5fNTY9aSsrLHBbZS5fNTZdPXtkaXNwbGF5SWQ6bnVsbCxlcnJvcjpuLHRpbWVvdXQ6c2V0VGltZW91dCh0LmJpbmQobnVsbCxlLl81NiksYShuLHUpPzEwMDoyZTMpLGxvZ2dlZDohMX0pfX1mdW5jdGlvbiBvKGUsdCl7Y29uc29sZS53YXJuKCJQb3NzaWJsZSBVbmhhbmRsZWQgUHJvbWlzZSBSZWplY3Rpb24gKGlkOiAiK2UrIik6IiksKCh0JiYodC5zdGFja3x8dCkpKyIiKS5zcGxpdCgiXG4iKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2NvbnNvbGUud2FybigiICAiK2UpfSl9ZnVuY3Rpb24gYShlLHQpe3JldHVybiB0LnNvbWUoZnVuY3Rpb24odCl7cmV0dXJuIGUgaW5zdGFuY2VvZiB0fSl9dmFyIHM9bigxNTEpLHU9W1JlZmVyZW5jZUVycm9yLFR5cGVFcnJvcixSYW5nZUVycm9yXSxjPSExO3QuZGlzYWJsZT1yLHQuZW5hYmxlPWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7KGZ1bmN0aW9uKHQpe2Z1bmN0aW9uIG4oZSl7YS5sZW5ndGh8fChvKCkscz0hMCksYVthLmxlbmd0aF09ZX1mdW5jdGlvbiByKCl7Zm9yKDt1PGEubGVuZ3RoOyl7dmFyIGU9dTtpZih1Kz0xLGFbZV0uY2FsbCgpLHU+Yyl7Zm9yKHZhciB0PTAsbj1hLmxlbmd0aC11O3Q8bjt0KyspYVt0XT1hW3QrdV07YS5sZW5ndGgtPXUsdT0wfX1hLmxlbmd0aD0wLHU9MCxzPSExfWZ1bmN0aW9uIGkoZSl7cmV0dXJuIGZ1bmN0aW9uKCl7ZnVuY3Rpb24gdCgpe2NsZWFyVGltZW91dChuKSxjbGVhckludGVydmFsKHIpLGUoKX12YXIgbj1zZXRUaW1lb3V0KHQsMCkscj1zZXRJbnRlcnZhbCh0LDUwKX19ZS5leHBvcnRzPW47dmFyIG8sYT1bXSxzPSExLHU9MCxjPTEwMjQsbD0idW5kZWZpbmVkIiE9PXR5cGVvZiB0P3Q6c2VsZixwPWwuTXV0YXRpb25PYnNlcnZlcnx8bC5XZWJLaXRNdXRhdGlvbk9ic2VydmVyO289ImZ1bmN0aW9uIj09PXR5cGVvZiBwP2Z1bmN0aW9uKGUpe3ZhciB0PTEsbj1uZXcgcChlKSxyPWRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCIiKTtyZXR1cm4gbi5vYnNlcnZlKHIse2NoYXJhY3RlckRhdGE6ITB9KSxmdW5jdGlvbigpe3Q9LXQsci5kYXRhPXR9fShyKTppKHIpLG4ucmVxdWVzdEZsdXNoPW8sbi5tYWtlUmVxdWVzdENhbGxGcm9tVGltZXI9aX0pLmNhbGwodCxuKDExKSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD1uZXcgaShpLl80NCk7cmV0dXJuIHQuXzgzPTEsdC5fMTg9ZSx0fXZhciBpPW4oMTUxKTtlLmV4cG9ydHM9aTt2YXIgbz1yKCEwKSxhPXIoITEpLHM9cihudWxsKSx1PXIodm9pZCAwKSxjPXIoMCksbD1yKCIiKTtpLnJlc29sdmU9ZnVuY3Rpb24oZSl7aWYoZSBpbnN0YW5jZW9mIGkpcmV0dXJuIGU7aWYobnVsbD09PWUpcmV0dXJuIHM7aWYodm9pZCAwPT09ZSlyZXR1cm4gdTtpZighMD09PWUpcmV0dXJuIG87aWYoITE9PT1lKXJldHVybiBhO2lmKDA9PT1lKXJldHVybiBjO2lmKCIiPT09ZSlyZXR1cm4gbDtpZigib2JqZWN0Ij09PXR5cGVvZiBlfHwiZnVuY3Rpb24iPT09dHlwZW9mIGUpdHJ5e3ZhciB0PWUudGhlbjtpZigiZnVuY3Rpb24iPT09dHlwZW9mIHQpcmV0dXJuIG5ldyBpKHQuYmluZChlKSl9Y2F0Y2goZSl7cmV0dXJuIG5ldyBpKGZ1bmN0aW9uKHQsbil7bihlKX0pfXJldHVybiByKGUpfSxpLmFsbD1mdW5jdGlvbihlKXt2YXIgdD1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChlKTtyZXR1cm4gbmV3IGkoZnVuY3Rpb24oZSxuKXtmdW5jdGlvbiByKGEscyl7aWYocyYmKCJvYmplY3QiPT09dHlwZW9mIHN8fCJmdW5jdGlvbiI9PT10eXBlb2Ygcykpe2lmKHMgaW5zdGFuY2VvZiBpJiZzLnRoZW49PT1pLnByb3RvdHlwZS50aGVuKXtmb3IoOzM9PT1zLl84Mzspcz1zLl8xODtyZXR1cm4gMT09PXMuXzgzP3IoYSxzLl8xOCk6KDI9PT1zLl84MyYmbihzLl8xOCksdm9pZCBzLnRoZW4oZnVuY3Rpb24oZSl7cihhLGUpfSxuKSl9dmFyIHU9cy50aGVuO2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgdSl7cmV0dXJuIHZvaWQgbmV3IGkodS5iaW5kKHMpKS50aGVuKGZ1bmN0aW9uKGUpe3IoYSxlKX0sbil9fXRbYV09cywwPT09LS1vJiZlKHQpfWlmKDA9PT10Lmxlbmd0aClyZXR1cm4gZShbXSk7Zm9yKHZhciBvPXQubGVuZ3RoLGE9MDthPHQubGVuZ3RoO2ErKylyKGEsdFthXSl9KX0saS5yZWplY3Q9ZnVuY3Rpb24oZSl7cmV0dXJuIG5ldyBpKGZ1bmN0aW9uKHQsbil7bihlKX0pfSxpLnJhY2U9ZnVuY3Rpb24oZSl7cmV0dXJuIG5ldyBpKGZ1bmN0aW9uKHQsbil7ZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2kucmVzb2x2ZShlKS50aGVuKHQsbil9KX0pfSxpLnByb3RvdHlwZS5jYXRjaD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy50aGVuKG51bGwsZSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgtMSxuPSJodHRwczovL3JlYWN0anMub3JnL2RvY3MvZXJyb3ItZGVjb2Rlci5odG1sP2ludmFyaWFudD0iK2Uscj0wO3I8dDtyKyspbis9IiZhcmdzW109IitlbmNvZGVVUklDb21wb25lbnQoYXJndW1lbnRzW3IrMV0pO3YoITEsIk1pbmlmaWVkIFJlYWN0IGVycm9yICMiK2UrIjsgdmlzaXQgJXMgZm9yIHRoZSBmdWxsIG1lc3NhZ2Ugb3IgdXNlIHRoZSBub24tbWluaWZpZWQgZGV2IGVudmlyb25tZW50IGZvciBmdWxsIGVycm9ycyBhbmQgYWRkaXRpb25hbCBoZWxwZnVsIHdhcm5pbmdzLiAiLG4pfWZ1bmN0aW9uIGkoZSx0LG4pe3RoaXMucHJvcHM9ZSx0aGlzLmNvbnRleHQ9dCx0aGlzLnJlZnM9Yix0aGlzLnVwZGF0ZXI9bnx8Tn1mdW5jdGlvbiBvKCl7fWZ1bmN0aW9uIGEoZSx0LG4pe3RoaXMucHJvcHM9ZSx0aGlzLmNvbnRleHQ9dCx0aGlzLnJlZnM9Yix0aGlzLnVwZGF0ZXI9bnx8Tn1mdW5jdGlvbiBzKGUsdCxuKXt2YXIgcj12b2lkIDAsaT17fSxvPW51bGwsYT1udWxsO2lmKG51bGwhPXQpZm9yKHIgaW4gdm9pZCAwIT09dC5yZWYmJihhPXQucmVmKSx2b2lkIDAhPT10LmtleSYmKG89IiIrdC5rZXkpLHQpUC5jYWxsKHQscikmJiFNLmhhc093blByb3BlcnR5KHIpJiYoaVtyXT10W3JdKTt2YXIgcz1hcmd1bWVudHMubGVuZ3RoLTI7aWYoMT09PXMpaS5jaGlsZHJlbj1uO2Vsc2UgaWYoMTxzKXtmb3IodmFyIHU9QXJyYXkocyksYz0wO2M8cztjKyspdVtjXT1hcmd1bWVudHNbYysyXTtpLmNoaWxkcmVuPXV9aWYoZSYmZS5kZWZhdWx0UHJvcHMpZm9yKHIgaW4gcz1lLmRlZmF1bHRQcm9wcyl2b2lkIDA9PT1pW3JdJiYoaVtyXT1zW3JdKTtyZXR1cm57JCR0eXBlb2Y6RSx0eXBlOmUsa2V5Om8scmVmOmEscHJvcHM6aSxfb3duZXI6TC5jdXJyZW50fX1mdW5jdGlvbiB1KGUpe3JldHVybiJvYmplY3QiPT09dHlwZW9mIGUmJm51bGwhPT1lJiZlLiQkdHlwZW9mPT09RX1mdW5jdGlvbiBjKGUpe3ZhciB0PXsiPSI6Ij0wIiwiOiI6Ij0yIn07cmV0dXJuIiQiKygiIitlKS5yZXBsYWNlKC9bPTpdL2csZnVuY3Rpb24oZSl7cmV0dXJuIHRbZV19KX1mdW5jdGlvbiBsKGUsdCxuLHIpe2lmKFIubGVuZ3RoKXt2YXIgaT1SLnBvcCgpO3JldHVybiBpLnJlc3VsdD1lLGkua2V5UHJlZml4PXQsaS5mdW5jPW4saS5jb250ZXh0PXIsaS5jb3VudD0wLGl9cmV0dXJue3Jlc3VsdDplLGtleVByZWZpeDp0LGZ1bmM6bixjb250ZXh0OnIsY291bnQ6MH19ZnVuY3Rpb24gcChlKXtlLnJlc3VsdD1udWxsLGUua2V5UHJlZml4PW51bGwsZS5mdW5jPW51bGwsZS5jb250ZXh0PW51bGwsZS5jb3VudD0wLDEwPlIubGVuZ3RoJiZSLnB1c2goZSl9ZnVuY3Rpb24gZihlLHQsbixpKXt2YXIgbz10eXBlb2YgZTsidW5kZWZpbmVkIiE9PW8mJiJib29sZWFuIiE9PW98fChlPW51bGwpO3ZhciBhPSExO2lmKG51bGw9PT1lKWE9ITA7ZWxzZSBzd2l0Y2gobyl7Y2FzZSJzdHJpbmciOmNhc2UibnVtYmVyIjphPSEwO2JyZWFrO2Nhc2Uib2JqZWN0Ijpzd2l0Y2goZS4kJHR5cGVvZil7Y2FzZSBFOmNhc2UgRDphPSEwfX1pZihhKXJldHVybiBuKGksZSwiIj09PXQ/Ii4iK2QoZSwwKTp0KSwxO2lmKGE9MCx0PSIiPT09dD8iLiI6dCsiOiIsQXJyYXkuaXNBcnJheShlKSlmb3IodmFyIHM9MDtzPGUubGVuZ3RoO3MrKyl7bz1lW3NdO3ZhciB1PXQrZChvLHMpO2ErPWYobyx1LG4saSl9ZWxzZSBpZihudWxsPT09ZXx8InVuZGVmaW5lZCI9PT10eXBlb2YgZT91PW51bGw6KHU9RiYmZVtGXXx8ZVsiQEBpdGVyYXRvciJdLHU9ImZ1bmN0aW9uIj09PXR5cGVvZiB1P3U6bnVsbCksImZ1bmN0aW9uIj09PXR5cGVvZiB1KWZvcihlPXUuY2FsbChlKSxzPTA7IShvPWUubmV4dCgpKS5kb25lOylvPW8udmFsdWUsdT10K2QobyxzKyspLGErPWYobyx1LG4saSk7ZWxzZSJvYmplY3QiPT09byYmKG49IiIrZSxyKCIzMSIsIltvYmplY3QgT2JqZWN0XSI9PT1uPyJvYmplY3Qgd2l0aCBrZXlzIHsiK09iamVjdC5rZXlzKGUpLmpvaW4oIiwgIikrIn0iOm4sIiIpKTtyZXR1cm4gYX1mdW5jdGlvbiBkKGUsdCl7cmV0dXJuIm9iamVjdCI9PT10eXBlb2YgZSYmbnVsbCE9PWUmJm51bGwhPWUua2V5P2MoZS5rZXkpOnQudG9TdHJpbmcoMzYpfWZ1bmN0aW9uIGgoZSx0KXtlLmZ1bmMuY2FsbChlLmNvbnRleHQsdCxlLmNvdW50KyspfWZ1bmN0aW9uIG0oZSx0LG4pe3ZhciByPWUucmVzdWx0LGk9ZS5rZXlQcmVmaXg7ZT1lLmZ1bmMuY2FsbChlLmNvbnRleHQsdCxlLmNvdW50KyspLEFycmF5LmlzQXJyYXkoZSk/ZyhlLHIsbix4LnRoYXRSZXR1cm5zQXJndW1lbnQpOm51bGwhPWUmJih1KGUpJiYodD1pKyghZS5rZXl8fHQmJnQua2V5PT09ZS5rZXk/IiI6KCIiK2Uua2V5KS5yZXBsYWNlKGosIiQmLyIpKyIvIikrbixlPXskJHR5cGVvZjpFLHR5cGU6ZS50eXBlLGtleTp0LHJlZjplLnJlZixwcm9wczplLnByb3BzLF9vd25lcjplLl9vd25lcn0pLHIucHVzaChlKSl9ZnVuY3Rpb24gZyhlLHQsbixyLGkpe3ZhciBvPSIiO251bGwhPW4mJihvPSgiIituKS5yZXBsYWNlKGosIiQmLyIpKyIvIiksdD1sKHQsbyxyLGkpLG51bGw9PWV8fGYoZSwiIixtLHQpLHAodCl9dmFyIHk9big1NCksdj1uKDk5KSxiPW4oMTUyKSx4PW4oMTAwKSxDPSJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiZTeW1ib2wuZm9yLEU9Qz9TeW1ib2wuZm9yKCJyZWFjdC5lbGVtZW50Iik6NjAxMDMsRD1DP1N5bWJvbC5mb3IoInJlYWN0LnBvcnRhbCIpOjYwMTA2LHc9Qz9TeW1ib2wuZm9yKCJyZWFjdC5mcmFnbWVudCIpOjYwMTA3LFM9Qz9TeW1ib2wuZm9yKCJyZWFjdC5zdHJpY3RfbW9kZSIpOjYwMTA4LGs9Qz9TeW1ib2wuZm9yKCJyZWFjdC5wcm9maWxlciIpOjYwMTE0LEE9Qz9TeW1ib2wuZm9yKCJyZWFjdC5wcm92aWRlciIpOjYwMTA5LF89Qz9TeW1ib2wuZm9yKCJyZWFjdC5jb250ZXh0Iik6NjAxMTAsVD1DP1N5bWJvbC5mb3IoInJlYWN0LmFzeW5jX21vZGUiKTo2MDExMSxPPUM/U3ltYm9sLmZvcigicmVhY3QuZm9yd2FyZF9yZWYiKTo2MDExMjtDJiZTeW1ib2wuZm9yKCJyZWFjdC50aW1lb3V0Iik7dmFyIEY9ImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJlN5bWJvbC5pdGVyYXRvcixOPXtpc01vdW50ZWQ6ZnVuY3Rpb24oKXtyZXR1cm4hMX0sZW5xdWV1ZUZvcmNlVXBkYXRlOmZ1bmN0aW9uKCl7fSxlbnF1ZXVlUmVwbGFjZVN0YXRlOmZ1bmN0aW9uKCl7fSxlbnF1ZXVlU2V0U3RhdGU6ZnVuY3Rpb24oKXt9fTtpLnByb3RvdHlwZS5pc1JlYWN0Q29tcG9uZW50PXt9LGkucHJvdG90eXBlLnNldFN0YXRlPWZ1bmN0aW9uKGUsdCl7Im9iamVjdCIhPT10eXBlb2YgZSYmImZ1bmN0aW9uIiE9PXR5cGVvZiBlJiZudWxsIT1lJiZyKCI4NSIpLHRoaXMudXBkYXRlci5lbnF1ZXVlU2V0U3RhdGUodGhpcyxlLHQsInNldFN0YXRlIil9LGkucHJvdG90eXBlLmZvcmNlVXBkYXRlPWZ1bmN0aW9uKGUpe3RoaXMudXBkYXRlci5lbnF1ZXVlRm9yY2VVcGRhdGUodGhpcyxlLCJmb3JjZVVwZGF0ZSIpfSxvLnByb3RvdHlwZT1pLnByb3RvdHlwZTt2YXIgST1hLnByb3RvdHlwZT1uZXcgbztJLmNvbnN0cnVjdG9yPWEseShJLGkucHJvdG90eXBlKSxJLmlzUHVyZVJlYWN0Q29tcG9uZW50PSEwO3ZhciBMPXtjdXJyZW50Om51bGx9LFA9T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eSxNPXtrZXk6ITAscmVmOiEwLF9fc2VsZjohMCxfX3NvdXJjZTohMH0saj0vXC8rL2csUj1bXSxCPXtDaGlsZHJlbjp7bWFwOmZ1bmN0aW9uKGUsdCxuKXtpZihudWxsPT1lKXJldHVybiBlO3ZhciByPVtdO3JldHVybiBnKGUscixudWxsLHQsbikscn0sZm9yRWFjaDpmdW5jdGlvbihlLHQsbil7aWYobnVsbD09ZSlyZXR1cm4gZTt0PWwobnVsbCxudWxsLHQsbiksbnVsbD09ZXx8ZihlLCIiLGgsdCkscCh0KX0sY291bnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIG51bGw9PWU/MDpmKGUsIiIseC50aGF0UmV0dXJuc051bGwsbnVsbCl9LHRvQXJyYXk6ZnVuY3Rpb24oZSl7dmFyIHQ9W107cmV0dXJuIGcoZSx0LG51bGwseC50aGF0UmV0dXJuc0FyZ3VtZW50KSx0fSxvbmx5OmZ1bmN0aW9uKGUpe3JldHVybiB1KGUpfHxyKCIxNDMiKSxlfX0sY3JlYXRlUmVmOmZ1bmN0aW9uKCl7cmV0dXJue2N1cnJlbnQ6bnVsbH19LENvbXBvbmVudDppLFB1cmVDb21wb25lbnQ6YSxjcmVhdGVDb250ZXh0OmZ1bmN0aW9uKGUsdCl7cmV0dXJuIHZvaWQgMD09PXQmJih0PW51bGwpLGU9eyQkdHlwZW9mOl8sX2NhbGN1bGF0ZUNoYW5nZWRCaXRzOnQsX2RlZmF1bHRWYWx1ZTplLF9jdXJyZW50VmFsdWU6ZSxfY3VycmVudFZhbHVlMjplLF9jaGFuZ2VkQml0czowLF9jaGFuZ2VkQml0czI6MCxQcm92aWRlcjpudWxsLENvbnN1bWVyOm51bGx9LGUuUHJvdmlkZXI9eyQkdHlwZW9mOkEsX2NvbnRleHQ6ZX0sZS5Db25zdW1lcj1lfSxmb3J3YXJkUmVmOmZ1bmN0aW9uKGUpe3JldHVybnskJHR5cGVvZjpPLHJlbmRlcjplfX0sRnJhZ21lbnQ6dyxTdHJpY3RNb2RlOlMsdW5zdGFibGVfQXN5bmNNb2RlOlQsdW5zdGFibGVfUHJvZmlsZXI6ayxjcmVhdGVFbGVtZW50OnMsY2xvbmVFbGVtZW50OmZ1bmN0aW9uKGUsdCxuKXsobnVsbD09PWV8fHZvaWQgMD09PWUpJiZyKCIyNjciLGUpO3ZhciBpPXZvaWQgMCxvPXkoe30sZS5wcm9wcyksYT1lLmtleSxzPWUucmVmLHU9ZS5fb3duZXI7aWYobnVsbCE9dCl7dm9pZCAwIT09dC5yZWYmJihzPXQucmVmLHU9TC5jdXJyZW50KSx2b2lkIDAhPT10LmtleSYmKGE9IiIrdC5rZXkpO3ZhciBjPXZvaWQgMDtlLnR5cGUmJmUudHlwZS5kZWZhdWx0UHJvcHMmJihjPWUudHlwZS5kZWZhdWx0UHJvcHMpO2ZvcihpIGluIHQpUC5jYWxsKHQsaSkmJiFNLmhhc093blByb3BlcnR5KGkpJiYob1tpXT12b2lkIDA9PT10W2ldJiZ2b2lkIDAhPT1jP2NbaV06dFtpXSl9aWYoMT09PShpPWFyZ3VtZW50cy5sZW5ndGgtMikpby5jaGlsZHJlbj1uO2Vsc2UgaWYoMTxpKXtjPUFycmF5KGkpO2Zvcih2YXIgbD0wO2w8aTtsKyspY1tsXT1hcmd1bWVudHNbbCsyXTtvLmNoaWxkcmVuPWN9cmV0dXJueyQkdHlwZW9mOkUsdHlwZTplLnR5cGUsa2V5OmEscmVmOnMscHJvcHM6byxfb3duZXI6dX19LGNyZWF0ZUZhY3Rvcnk6ZnVuY3Rpb24oZSl7dmFyIHQ9cy5iaW5kKG51bGwsZSk7cmV0dXJuIHQudHlwZT1lLHR9LGlzVmFsaWRFbGVtZW50OnUsdmVyc2lvbjoiMTYuNC4wIixfX1NFQ1JFVF9JTlRFUk5BTFNfRE9fTk9UX1VTRV9PUl9ZT1VfV0lMTF9CRV9GSVJFRDp7UmVhY3RDdXJyZW50T3duZXI6TCxhc3NpZ246eX19LCQ9e2RlZmF1bHQ6Qn0sVT0kJiZCfHwkO2UuZXhwb3J0cz1VLmRlZmF1bHQ/VS5kZWZhdWx0OlV9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aC0xLG49Imh0dHBzOi8vcmVhY3Rqcy5vcmcvZG9jcy9lcnJvci1kZWNvZGVyLmh0bWw/aW52YXJpYW50PSIrZSxyPTA7cjx0O3IrKyluKz0iJmFyZ3NbXT0iK2VuY29kZVVSSUNvbXBvbmVudChhcmd1bWVudHNbcisxXSk7SXIoITEsIk1pbmlmaWVkIFJlYWN0IGVycm9yICMiK2UrIjsgdmlzaXQgJXMgZm9yIHRoZSBmdWxsIG1lc3NhZ2Ugb3IgdXNlIHRoZSBub24tbWluaWZpZWQgZGV2IGVudmlyb25tZW50IGZvciBmdWxsIGVycm9ycyBhbmQgYWRkaXRpb25hbCBoZWxwZnVsIHdhcm5pbmdzLiAiLG4pfWZ1bmN0aW9uIGkoZSx0LG4scixpLG8sYSxzLHUpe3RoaXMuX2hhc0NhdWdodEVycm9yPSExLHRoaXMuX2NhdWdodEVycm9yPW51bGw7dmFyIGM9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLDMpO3RyeXt0LmFwcGx5KG4sYyl9Y2F0Y2goZSl7dGhpcy5fY2F1Z2h0RXJyb3I9ZSx0aGlzLl9oYXNDYXVnaHRFcnJvcj0hMH19ZnVuY3Rpb24gbygpe2lmKHpyLl9oYXNSZXRocm93RXJyb3Ipe3ZhciBlPXpyLl9yZXRocm93RXJyb3I7dGhyb3cgenIuX3JldGhyb3dFcnJvcj1udWxsLHpyLl9oYXNSZXRocm93RXJyb3I9ITEsZX19ZnVuY3Rpb24gYSgpe2lmKEdyKWZvcih2YXIgZSBpbiBWcil7dmFyIHQ9VnJbZV0sbj1Hci5pbmRleE9mKGUpO2lmKC0xPG58fHIoIjk2IixlKSwhcXJbbl0pe3QuZXh0cmFjdEV2ZW50c3x8cigiOTciLGUpLHFyW25dPXQsbj10LmV2ZW50VHlwZXM7Zm9yKHZhciBpIGluIG4pe3ZhciBvPXZvaWQgMCxhPW5baV0sdT10LGM9aTtIci5oYXNPd25Qcm9wZXJ0eShjKSYmcigiOTkiLGMpLEhyW2NdPWE7dmFyIGw9YS5waGFzZWRSZWdpc3RyYXRpb25OYW1lcztpZihsKXtmb3IobyBpbiBsKWwuaGFzT3duUHJvcGVydHkobykmJnMobFtvXSx1LGMpO289ITB9ZWxzZSBhLnJlZ2lzdHJhdGlvbk5hbWU/KHMoYS5yZWdpc3RyYXRpb25OYW1lLHUsYyksbz0hMCk6bz0hMTtvfHxyKCI5OCIsaSxlKX19fX1mdW5jdGlvbiBzKGUsdCxuKXtXcltlXSYmcigiMTAwIixlKSxXcltlXT10LFFyW2VdPXQuZXZlbnRUeXBlc1tuXS5kZXBlbmRlbmNpZXN9ZnVuY3Rpb24gdShlKXtHciYmcigiMTAxIiksR3I9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoZSksYSgpfWZ1bmN0aW9uIGMoZSl7dmFyIHQsbj0hMTtmb3IodCBpbiBlKWlmKGUuaGFzT3duUHJvcGVydHkodCkpe3ZhciBpPWVbdF07VnIuaGFzT3duUHJvcGVydHkodCkmJlZyW3RdPT09aXx8KFZyW3RdJiZyKCIxMDIiLHQpLFZyW3RdPWksbj0hMCl9biYmYSgpfWZ1bmN0aW9uIGwoZSx0LG4scil7dD1lLnR5cGV8fCJ1bmtub3duLWV2ZW50IixlLmN1cnJlbnRUYXJnZXQ9WHIociksenIuaW52b2tlR3VhcmRlZENhbGxiYWNrQW5kQ2F0Y2hGaXJzdEVycm9yKHQsbix2b2lkIDAsZSksZS5jdXJyZW50VGFyZ2V0PW51bGx9ZnVuY3Rpb24gcChlLHQpe3JldHVybiBudWxsPT10JiZyKCIzMCIpLG51bGw9PWU/dDpBcnJheS5pc0FycmF5KGUpP0FycmF5LmlzQXJyYXkodCk/KGUucHVzaC5hcHBseShlLHQpLGUpOihlLnB1c2godCksZSk6QXJyYXkuaXNBcnJheSh0KT9bZV0uY29uY2F0KHQpOltlLHRdfWZ1bmN0aW9uIGYoZSx0LG4pe0FycmF5LmlzQXJyYXkoZSk/ZS5mb3JFYWNoKHQsbik6ZSYmdC5jYWxsKG4sZSl9ZnVuY3Rpb24gZChlLHQpe2lmKGUpe3ZhciBuPWUuX2Rpc3BhdGNoTGlzdGVuZXJzLHI9ZS5fZGlzcGF0Y2hJbnN0YW5jZXM7aWYoQXJyYXkuaXNBcnJheShuKSlmb3IodmFyIGk9MDtpPG4ubGVuZ3RoJiYhZS5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpO2krKylsKGUsdCxuW2ldLHJbaV0pO2Vsc2UgbiYmbChlLHQsbixyKTtlLl9kaXNwYXRjaExpc3RlbmVycz1udWxsLGUuX2Rpc3BhdGNoSW5zdGFuY2VzPW51bGwsZS5pc1BlcnNpc3RlbnQoKXx8ZS5jb25zdHJ1Y3Rvci5yZWxlYXNlKGUpfX1mdW5jdGlvbiBoKGUpe3JldHVybiBkKGUsITApfWZ1bmN0aW9uIG0oZSl7cmV0dXJuIGQoZSwhMSl9ZnVuY3Rpb24gZyhlLHQpe3ZhciBuPWUuc3RhdGVOb2RlO2lmKCFuKXJldHVybiBudWxsO3ZhciBpPUpyKG4pO2lmKCFpKXJldHVybiBudWxsO249aVt0XTtlOnN3aXRjaCh0KXtjYXNlIm9uQ2xpY2siOmNhc2Uib25DbGlja0NhcHR1cmUiOmNhc2Uib25Eb3VibGVDbGljayI6Y2FzZSJvbkRvdWJsZUNsaWNrQ2FwdHVyZSI6Y2FzZSJvbk1vdXNlRG93biI6Y2FzZSJvbk1vdXNlRG93bkNhcHR1cmUiOmNhc2Uib25Nb3VzZU1vdmUiOmNhc2Uib25Nb3VzZU1vdmVDYXB0dXJlIjpjYXNlIm9uTW91c2VVcCI6Y2FzZSJvbk1vdXNlVXBDYXB0dXJlIjooaT0haS5kaXNhYmxlZCl8fChlPWUudHlwZSxpPSEoImJ1dHRvbiI9PT1lfHwiaW5wdXQiPT09ZXx8InNlbGVjdCI9PT1lfHwidGV4dGFyZWEiPT09ZSkpLGU9IWk7YnJlYWsgZTtkZWZhdWx0OmU9ITF9cmV0dXJuIGU/bnVsbDoobiYmImZ1bmN0aW9uIiE9PXR5cGVvZiBuJiZyKCIyMzEiLHQsdHlwZW9mIG4pLG4pfWZ1bmN0aW9uIHkoZSx0KXtudWxsIT09ZSYmKFpyPXAoWnIsZSkpLGU9WnIsWnI9bnVsbCxlJiYodD9mKGUsaCk6ZihlLG0pLFpyJiZyKCI5NSIpLHpyLnJldGhyb3dDYXVnaHRFcnJvcigpKX1mdW5jdGlvbiB2KGUsdCxuLHIpe2Zvcih2YXIgaT1udWxsLG89MDtvPHFyLmxlbmd0aDtvKyspe3ZhciBhPXFyW29dO2EmJihhPWEuZXh0cmFjdEV2ZW50cyhlLHQsbixyKSkmJihpPXAoaSxhKSl9eShpLCExKX1mdW5jdGlvbiBiKGUpe2lmKGVbcmldKXJldHVybiBlW3JpXTtmb3IoOyFlW3JpXTspe2lmKCFlLnBhcmVudE5vZGUpcmV0dXJuIG51bGw7ZT1lLnBhcmVudE5vZGV9cmV0dXJuIGU9ZVtyaV0sNT09PWUudGFnfHw2PT09ZS50YWc/ZTpudWxsfWZ1bmN0aW9uIHgoZSl7aWYoNT09PWUudGFnfHw2PT09ZS50YWcpcmV0dXJuIGUuc3RhdGVOb2RlO3IoIjMzIil9ZnVuY3Rpb24gQyhlKXtyZXR1cm4gZVtpaV18fG51bGx9ZnVuY3Rpb24gRShlKXtkb3tlPWUucmV0dXJufXdoaWxlKGUmJjUhPT1lLnRhZyk7cmV0dXJuIGV8fG51bGx9ZnVuY3Rpb24gRChlLHQsbil7Zm9yKHZhciByPVtdO2U7KXIucHVzaChlKSxlPUUoZSk7Zm9yKGU9ci5sZW5ndGg7MDxlLS07KXQocltlXSwiY2FwdHVyZWQiLG4pO2ZvcihlPTA7ZTxyLmxlbmd0aDtlKyspdChyW2VdLCJidWJibGVkIixuKX1mdW5jdGlvbiB3KGUsdCxuKXsodD1nKGUsbi5kaXNwYXRjaENvbmZpZy5waGFzZWRSZWdpc3RyYXRpb25OYW1lc1t0XSkpJiYobi5fZGlzcGF0Y2hMaXN0ZW5lcnM9cChuLl9kaXNwYXRjaExpc3RlbmVycyx0KSxuLl9kaXNwYXRjaEluc3RhbmNlcz1wKG4uX2Rpc3BhdGNoSW5zdGFuY2VzLGUpKX1mdW5jdGlvbiBTKGUpe2UmJmUuZGlzcGF0Y2hDb25maWcucGhhc2VkUmVnaXN0cmF0aW9uTmFtZXMmJkQoZS5fdGFyZ2V0SW5zdCx3LGUpfWZ1bmN0aW9uIGsoZSl7aWYoZSYmZS5kaXNwYXRjaENvbmZpZy5waGFzZWRSZWdpc3RyYXRpb25OYW1lcyl7dmFyIHQ9ZS5fdGFyZ2V0SW5zdDt0PXQ/RSh0KTpudWxsLEQodCx3LGUpfX1mdW5jdGlvbiBBKGUsdCxuKXtlJiZuJiZuLmRpc3BhdGNoQ29uZmlnLnJlZ2lzdHJhdGlvbk5hbWUmJih0PWcoZSxuLmRpc3BhdGNoQ29uZmlnLnJlZ2lzdHJhdGlvbk5hbWUpKSYmKG4uX2Rpc3BhdGNoTGlzdGVuZXJzPXAobi5fZGlzcGF0Y2hMaXN0ZW5lcnMsdCksbi5fZGlzcGF0Y2hJbnN0YW5jZXM9cChuLl9kaXNwYXRjaEluc3RhbmNlcyxlKSl9ZnVuY3Rpb24gXyhlKXtlJiZlLmRpc3BhdGNoQ29uZmlnLnJlZ2lzdHJhdGlvbk5hbWUmJkEoZS5fdGFyZ2V0SW5zdCxudWxsLGUpfWZ1bmN0aW9uIFQoZSl7ZihlLFMpfWZ1bmN0aW9uIE8oZSx0LG4scil7aWYobiYmcillOntmb3IodmFyIGk9bixvPXIsYT0wLHM9aTtzO3M9RShzKSlhKys7cz0wO2Zvcih2YXIgdT1vO3U7dT1FKHUpKXMrKztmb3IoOzA8YS1zOylpPUUoaSksYS0tO2Zvcig7MDxzLWE7KW89RShvKSxzLS07Zm9yKDthLS07KXtpZihpPT09b3x8aT09PW8uYWx0ZXJuYXRlKWJyZWFrIGU7aT1FKGkpLG89RShvKX1pPW51bGx9ZWxzZSBpPW51bGw7Zm9yKG89aSxpPVtdO24mJm4hPT1vJiYobnVsbD09PShhPW4uYWx0ZXJuYXRlKXx8YSE9PW8pOylpLnB1c2gobiksbj1FKG4pO2ZvcihuPVtdO3ImJnIhPT1vJiYobnVsbD09PShhPXIuYWx0ZXJuYXRlKXx8YSE9PW8pOyluLnB1c2gocikscj1FKHIpO2ZvcihyPTA7cjxpLmxlbmd0aDtyKyspQShpW3JdLCJidWJibGVkIixlKTtmb3IoZT1uLmxlbmd0aDswPGUtLTspQShuW2VdLCJjYXB0dXJlZCIsdCl9ZnVuY3Rpb24gRihlLHQpe3ZhciBuPXt9O3JldHVybiBuW2UudG9Mb3dlckNhc2UoKV09dC50b0xvd2VyQ2FzZSgpLG5bIldlYmtpdCIrZV09IndlYmtpdCIrdCxuWyJNb3oiK2VdPSJtb3oiK3QsblsibXMiK2VdPSJNUyIrdCxuWyJPIitlXT0ibyIrdC50b0xvd2VyQ2FzZSgpLG59ZnVuY3Rpb24gTihlKXtpZih1aVtlXSlyZXR1cm4gdWlbZV07aWYoIXNpW2VdKXJldHVybiBlO3ZhciB0LG49c2lbZV07Zm9yKHQgaW4gbilpZihuLmhhc093blByb3BlcnR5KHQpJiZ0IGluIGNpKXJldHVybiB1aVtlXT1uW3RdO3JldHVybiBlfWZ1bmN0aW9uIEkoKXtyZXR1cm4hbWkmJlByLmNhblVzZURPTSYmKG1pPSJ0ZXh0Q29udGVudCJpbiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ/InRleHRDb250ZW50IjoiaW5uZXJUZXh0IiksbWl9ZnVuY3Rpb24gTCgpe2lmKGdpLl9mYWxsYmFja1RleHQpcmV0dXJuIGdpLl9mYWxsYmFja1RleHQ7dmFyIGUsdCxuPWdpLl9zdGFydFRleHQscj1uLmxlbmd0aCxpPVAoKSxvPWkubGVuZ3RoO2ZvcihlPTA7ZTxyJiZuW2VdPT09aVtlXTtlKyspO3ZhciBhPXItZTtmb3IodD0xO3Q8PWEmJm5bci10XT09PWlbby10XTt0KyspO3JldHVybiBnaS5fZmFsbGJhY2tUZXh0PWkuc2xpY2UoZSwxPHQ/MS10OnZvaWQgMCksZ2kuX2ZhbGxiYWNrVGV4dH1mdW5jdGlvbiBQKCl7cmV0dXJuInZhbHVlImluIGdpLl9yb290P2dpLl9yb290LnZhbHVlOmdpLl9yb290W0koKV19ZnVuY3Rpb24gTShlLHQsbixyKXt0aGlzLmRpc3BhdGNoQ29uZmlnPWUsdGhpcy5fdGFyZ2V0SW5zdD10LHRoaXMubmF0aXZlRXZlbnQ9bixlPXRoaXMuY29uc3RydWN0b3IuSW50ZXJmYWNlO2Zvcih2YXIgaSBpbiBlKWUuaGFzT3duUHJvcGVydHkoaSkmJigodD1lW2ldKT90aGlzW2ldPXQobik6InRhcmdldCI9PT1pP3RoaXMudGFyZ2V0PXI6dGhpc1tpXT1uW2ldKTtyZXR1cm4gdGhpcy5pc0RlZmF1bHRQcmV2ZW50ZWQ9KG51bGwhPW4uZGVmYXVsdFByZXZlbnRlZD9uLmRlZmF1bHRQcmV2ZW50ZWQ6ITE9PT1uLnJldHVyblZhbHVlKT9qci50aGF0UmV0dXJuc1RydWU6anIudGhhdFJldHVybnNGYWxzZSx0aGlzLmlzUHJvcGFnYXRpb25TdG9wcGVkPWpyLnRoYXRSZXR1cm5zRmFsc2UsdGhpc31mdW5jdGlvbiBqKGUsdCxuLHIpe2lmKHRoaXMuZXZlbnRQb29sLmxlbmd0aCl7dmFyIGk9dGhpcy5ldmVudFBvb2wucG9wKCk7cmV0dXJuIHRoaXMuY2FsbChpLGUsdCxuLHIpLGl9cmV0dXJuIG5ldyB0aGlzKGUsdCxuLHIpfWZ1bmN0aW9uIFIoZSl7ZSBpbnN0YW5jZW9mIHRoaXN8fHIoIjIyMyIpLGUuZGVzdHJ1Y3RvcigpLDEwPnRoaXMuZXZlbnRQb29sLmxlbmd0aCYmdGhpcy5ldmVudFBvb2wucHVzaChlKX1mdW5jdGlvbiBCKGUpe2UuZXZlbnRQb29sPVtdLGUuZ2V0UG9vbGVkPWosZS5yZWxlYXNlPVJ9ZnVuY3Rpb24gJChlLHQpe3N3aXRjaChlKXtjYXNlImtleXVwIjpyZXR1cm4tMSE9PUNpLmluZGV4T2YodC5rZXlDb2RlKTtjYXNlImtleWRvd24iOnJldHVybiAyMjkhPT10LmtleUNvZGU7Y2FzZSJrZXlwcmVzcyI6Y2FzZSJtb3VzZWRvd24iOmNhc2UiYmx1ciI6cmV0dXJuITA7ZGVmYXVsdDpyZXR1cm4hMX19ZnVuY3Rpb24gVShlKXtyZXR1cm4gZT1lLmRldGFpbCwib2JqZWN0Ij09PXR5cGVvZiBlJiYiZGF0YSJpbiBlP2UuZGF0YTpudWxsfWZ1bmN0aW9uIHooZSx0KXtzd2l0Y2goZSl7Y2FzZSJjb21wb3NpdGlvbmVuZCI6cmV0dXJuIFUodCk7Y2FzZSJrZXlwcmVzcyI6cmV0dXJuIDMyIT09dC53aGljaD9udWxsOihfaT0hMCxraSk7Y2FzZSJ0ZXh0SW5wdXQiOnJldHVybiBlPXQuZGF0YSxlPT09a2kmJl9pP251bGw6ZTtkZWZhdWx0OnJldHVybiBudWxsfX1mdW5jdGlvbiBHKGUsdCl7aWYoVGkpcmV0dXJuImNvbXBvc2l0aW9uZW5kIj09PWV8fCFFaSYmJChlLHQpPyhlPUwoKSxnaS5fcm9vdD1udWxsLGdpLl9zdGFydFRleHQ9bnVsbCxnaS5fZmFsbGJhY2tUZXh0PW51bGwsVGk9ITEsZSk6bnVsbDtzd2l0Y2goZSl7Y2FzZSJwYXN0ZSI6cmV0dXJuIG51bGw7Y2FzZSJrZXlwcmVzcyI6aWYoISh0LmN0cmxLZXl8fHQuYWx0S2V5fHx0Lm1ldGFLZXkpfHx0LmN0cmxLZXkmJnQuYWx0S2V5KXtpZih0LmNoYXImJjE8dC5jaGFyLmxlbmd0aClyZXR1cm4gdC5jaGFyO2lmKHQud2hpY2gpcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUodC53aGljaCl9cmV0dXJuIG51bGw7Y2FzZSJjb21wb3NpdGlvbmVuZCI6cmV0dXJuIFNpP251bGw6dC5kYXRhO2RlZmF1bHQ6cmV0dXJuIG51bGx9fWZ1bmN0aW9uIFYoZSl7aWYoZT1ZcihlKSl7RmkmJiJmdW5jdGlvbiI9PT10eXBlb2YgRmkucmVzdG9yZUNvbnRyb2xsZWRTdGF0ZXx8cigiMTk0Iik7dmFyIHQ9SnIoZS5zdGF0ZU5vZGUpO0ZpLnJlc3RvcmVDb250cm9sbGVkU3RhdGUoZS5zdGF0ZU5vZGUsZS50eXBlLHQpfX1mdW5jdGlvbiBxKGUpe0lpP0xpP0xpLnB1c2goZSk6TGk9W2VdOklpPWV9ZnVuY3Rpb24gSCgpe3JldHVybiBudWxsIT09SWl8fG51bGwhPT1MaX1mdW5jdGlvbiBXKCl7aWYoSWkpe3ZhciBlPUlpLHQ9TGk7aWYoTGk9SWk9bnVsbCxWKGUpLHQpZm9yKGU9MDtlPHQubGVuZ3RoO2UrKylWKHRbZV0pfX1mdW5jdGlvbiBRKGUsdCl7cmV0dXJuIGUodCl9ZnVuY3Rpb24gSyhlLHQsbil7cmV0dXJuIGUodCxuKX1mdW5jdGlvbiBKKCl7fWZ1bmN0aW9uIFkoZSx0KXtpZihNaSlyZXR1cm4gZSh0KTtNaT0hMDt0cnl7cmV0dXJuIFEoZSx0KX1maW5hbGx5e01pPSExLEgoKSYmKEooKSxXKCkpfX1mdW5jdGlvbiBYKGUpe3ZhciB0PWUmJmUubm9kZU5hbWUmJmUubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtyZXR1cm4iaW5wdXQiPT09dD8hIWppW2UudHlwZV06InRleHRhcmVhIj09PXR9ZnVuY3Rpb24gWihlKXtyZXR1cm4gZT1lLnRhcmdldHx8d2luZG93LGUuY29ycmVzcG9uZGluZ1VzZUVsZW1lbnQmJihlPWUuY29ycmVzcG9uZGluZ1VzZUVsZW1lbnQpLDM9PT1lLm5vZGVUeXBlP2UucGFyZW50Tm9kZTplfWZ1bmN0aW9uIGVlKGUsdCl7cmV0dXJuISghUHIuY2FuVXNlRE9NfHx0JiYhKCJhZGRFdmVudExpc3RlbmVyImluIGRvY3VtZW50KSkmJihlPSJvbiIrZSx0PWUgaW4gZG9jdW1lbnQsdHx8KHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IiksdC5zZXRBdHRyaWJ1dGUoZSwicmV0dXJuOyIpLHQ9ImZ1bmN0aW9uIj09PXR5cGVvZiB0W2VdKSx0KX1mdW5jdGlvbiB0ZShlKXt2YXIgdD1lLnR5cGU7cmV0dXJuKGU9ZS5ub2RlTmFtZSkmJiJpbnB1dCI9PT1lLnRvTG93ZXJDYXNlKCkmJigiY2hlY2tib3giPT09dHx8InJhZGlvIj09PXQpfWZ1bmN0aW9uIG5lKGUpe3ZhciB0PXRlKGUpPyJjaGVja2VkIjoidmFsdWUiLG49T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihlLmNvbnN0cnVjdG9yLnByb3RvdHlwZSx0KSxyPSIiK2VbdF07aWYoIWUuaGFzT3duUHJvcGVydHkodCkmJiJ1bmRlZmluZWQiIT09dHlwZW9mIG4mJiJmdW5jdGlvbiI9PT10eXBlb2Ygbi5nZXQmJiJmdW5jdGlvbiI9PT10eXBlb2Ygbi5zZXQpe3ZhciBpPW4uZ2V0LG89bi5zZXQ7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHQse2NvbmZpZ3VyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5jYWxsKHRoaXMpfSxzZXQ6ZnVuY3Rpb24oZSl7cj0iIitlLG8uY2FsbCh0aGlzLGUpfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHQse2VudW1lcmFibGU6bi5lbnVtZXJhYmxlfSkse2dldFZhbHVlOmZ1bmN0aW9uKCl7cmV0dXJuIHJ9LHNldFZhbHVlOmZ1bmN0aW9uKGUpe3I9IiIrZX0sc3RvcFRyYWNraW5nOmZ1bmN0aW9uKCl7ZS5fdmFsdWVUcmFja2VyPW51bGwsZGVsZXRlIGVbdF19fX19ZnVuY3Rpb24gcmUoZSl7ZS5fdmFsdWVUcmFja2VyfHwoZS5fdmFsdWVUcmFja2VyPW5lKGUpKX1mdW5jdGlvbiBpZShlKXtpZighZSlyZXR1cm4hMTt2YXIgdD1lLl92YWx1ZVRyYWNrZXI7aWYoIXQpcmV0dXJuITA7dmFyIG49dC5nZXRWYWx1ZSgpLHI9IiI7cmV0dXJuIGUmJihyPXRlKGUpP2UuY2hlY2tlZD8idHJ1ZSI6ImZhbHNlIjplLnZhbHVlKSwoZT1yKSE9PW4mJih0LnNldFZhbHVlKGUpLCEwKX1mdW5jdGlvbiBvZShlKXtyZXR1cm4gbnVsbD09PWV8fCJ1bmRlZmluZWQiPT09dHlwZW9mIGU/bnVsbDooZT1KaSYmZVtKaV18fGVbIkBAaXRlcmF0b3IiXSwiZnVuY3Rpb24iPT09dHlwZW9mIGU/ZTpudWxsKX1mdW5jdGlvbiBhZShlKXt2YXIgdD1lLnR5cGU7aWYoImZ1bmN0aW9uIj09PXR5cGVvZiB0KXJldHVybiB0LmRpc3BsYXlOYW1lfHx0Lm5hbWU7aWYoInN0cmluZyI9PT10eXBlb2YgdClyZXR1cm4gdDtzd2l0Y2godCl7Y2FzZSBXaTpyZXR1cm4iQXN5bmNNb2RlIjtjYXNlIEhpOnJldHVybiJDb250ZXh0LkNvbnN1bWVyIjtjYXNlIHppOnJldHVybiJSZWFjdEZyYWdtZW50IjtjYXNlIFVpOnJldHVybiJSZWFjdFBvcnRhbCI7Y2FzZSBWaTpyZXR1cm4iUHJvZmlsZXIoIitlLnBlbmRpbmdQcm9wcy5pZCsiKSI7Y2FzZSBxaTpyZXR1cm4iQ29udGV4dC5Qcm92aWRlciI7Y2FzZSBHaTpyZXR1cm4iU3RyaWN0TW9kZSI7Y2FzZSBLaTpyZXR1cm4iVGltZW91dCJ9aWYoIm9iamVjdCI9PT10eXBlb2YgdCYmbnVsbCE9PXQpc3dpdGNoKHQuJCR0eXBlb2Ype2Nhc2UgUWk6cmV0dXJuIGU9dC5yZW5kZXIuZGlzcGxheU5hbWV8fHQucmVuZGVyLm5hbWV8fCIiLCIiIT09ZT8iRm9yd2FyZFJlZigiK2UrIikiOiJGb3J3YXJkUmVmIn1yZXR1cm4gbnVsbH1mdW5jdGlvbiBzZShlKXt2YXIgdD0iIjtkb3tlOnN3aXRjaChlLnRhZyl7Y2FzZSAwOmNhc2UgMTpjYXNlIDI6Y2FzZSA1OnZhciBuPWUuX2RlYnVnT3duZXIscj1lLl9kZWJ1Z1NvdXJjZSxpPWFlKGUpLG89bnVsbDtuJiYobz1hZShuKSksbj1yLGk9IlxuICAgIGluICIrKGl8fCJVbmtub3duIikrKG4/IiAoYXQgIituLmZpbGVOYW1lLnJlcGxhY2UoL14uKltcXFwvXS8sIiIpKyI6IituLmxpbmVOdW1iZXIrIikiOm8/IiAoY3JlYXRlZCBieSAiK28rIikiOiIiKTticmVhayBlO2RlZmF1bHQ6aT0iIn10Kz1pLGU9ZS5yZXR1cm59d2hpbGUoZSk7cmV0dXJuIHR9ZnVuY3Rpb24gdWUoZSl7cmV0dXJuISFaaS5oYXNPd25Qcm9wZXJ0eShlKXx8IVhpLmhhc093blByb3BlcnR5KGUpJiYoWWkudGVzdChlKT9aaVtlXT0hMDooWGlbZV09ITAsITEpKX1mdW5jdGlvbiBjZShlLHQsbixyKXtpZihudWxsIT09biYmMD09PW4udHlwZSlyZXR1cm4hMTtzd2l0Y2godHlwZW9mIHQpe2Nhc2UiZnVuY3Rpb24iOmNhc2Uic3ltYm9sIjpyZXR1cm4hMDtjYXNlImJvb2xlYW4iOnJldHVybiFyJiYobnVsbCE9PW4/IW4uYWNjZXB0c0Jvb2xlYW5zOiJkYXRhLSIhPT0oZT1lLnRvTG93ZXJDYXNlKCkuc2xpY2UoMCw1KSkmJiJhcmlhLSIhPT1lKTtkZWZhdWx0OnJldHVybiExfX1mdW5jdGlvbiBsZShlLHQsbixyKXtpZihudWxsPT09dHx8InVuZGVmaW5lZCI9PT10eXBlb2YgdHx8Y2UoZSx0LG4scikpcmV0dXJuITA7aWYocilyZXR1cm4hMTtpZihudWxsIT09bilzd2l0Y2gobi50eXBlKXtjYXNlIDM6cmV0dXJuIXQ7Y2FzZSA0OnJldHVybiExPT09dDtjYXNlIDU6cmV0dXJuIGlzTmFOKHQpO2Nhc2UgNjpyZXR1cm4gaXNOYU4odCl8fDE+dH1yZXR1cm4hMX1mdW5jdGlvbiBwZShlLHQsbixyLGkpe3RoaXMuYWNjZXB0c0Jvb2xlYW5zPTI9PT10fHwzPT09dHx8ND09PXQsdGhpcy5hdHRyaWJ1dGVOYW1lPXIsdGhpcy5hdHRyaWJ1dGVOYW1lc3BhY2U9aSx0aGlzLm11c3RVc2VQcm9wZXJ0eT1uLHRoaXMucHJvcGVydHlOYW1lPWUsdGhpcy50eXBlPXR9ZnVuY3Rpb24gZmUoZSl7cmV0dXJuIGVbMV0udG9VcHBlckNhc2UoKX1mdW5jdGlvbiBkZShlLHQsbixyKXt2YXIgaT1lby5oYXNPd25Qcm9wZXJ0eSh0KT9lb1t0XTpudWxsOyhudWxsIT09aT8wPT09aS50eXBlOiFyJiYoMjx0Lmxlbmd0aCYmKCJvIj09PXRbMF18fCJPIj09PXRbMF0pJiYoIm4iPT09dFsxXXx8Ik4iPT09dFsxXSkpKXx8KGxlKHQsbixpLHIpJiYobj1udWxsKSxyfHxudWxsPT09aT91ZSh0KSYmKG51bGw9PT1uP2UucmVtb3ZlQXR0cmlidXRlKHQpOmUuc2V0QXR0cmlidXRlKHQsIiIrbikpOmkubXVzdFVzZVByb3BlcnR5P2VbaS5wcm9wZXJ0eU5hbWVdPW51bGw9PT1uPzMhPT1pLnR5cGUmJiIiOm46KHQ9aS5hdHRyaWJ1dGVOYW1lLHI9aS5hdHRyaWJ1dGVOYW1lc3BhY2UsbnVsbD09PW4/ZS5yZW1vdmVBdHRyaWJ1dGUodCk6KGk9aS50eXBlLG49Mz09PWl8fDQ9PT1pJiYhMD09PW4/IiI6IiIrbixyP2Uuc2V0QXR0cmlidXRlTlMocix0LG4pOmUuc2V0QXR0cmlidXRlKHQsbikpKSl9ZnVuY3Rpb24gaGUoZSx0KXt2YXIgbj10LmNoZWNrZWQ7cmV0dXJuIE1yKHt9LHQse2RlZmF1bHRDaGVja2VkOnZvaWQgMCxkZWZhdWx0VmFsdWU6dm9pZCAwLHZhbHVlOnZvaWQgMCxjaGVja2VkOm51bGwhPW4/bjplLl93cmFwcGVyU3RhdGUuaW5pdGlhbENoZWNrZWR9KX1mdW5jdGlvbiBtZShlLHQpe3ZhciBuPW51bGw9PXQuZGVmYXVsdFZhbHVlPyIiOnQuZGVmYXVsdFZhbHVlLHI9bnVsbCE9dC5jaGVja2VkP3QuY2hlY2tlZDp0LmRlZmF1bHRDaGVja2VkO249eGUobnVsbCE9dC52YWx1ZT90LnZhbHVlOm4pLGUuX3dyYXBwZXJTdGF0ZT17aW5pdGlhbENoZWNrZWQ6cixpbml0aWFsVmFsdWU6bixjb250cm9sbGVkOiJjaGVja2JveCI9PT10LnR5cGV8fCJyYWRpbyI9PT10LnR5cGU/bnVsbCE9dC5jaGVja2VkOm51bGwhPXQudmFsdWV9fWZ1bmN0aW9uIGdlKGUsdCl7bnVsbCE9KHQ9dC5jaGVja2VkKSYmZGUoZSwiY2hlY2tlZCIsdCwhMSl9ZnVuY3Rpb24geWUoZSx0KXtnZShlLHQpO3ZhciBuPXhlKHQudmFsdWUpO251bGwhPW4mJigibnVtYmVyIj09PXQudHlwZT8oMD09PW4mJiIiPT09ZS52YWx1ZXx8ZS52YWx1ZSE9bikmJihlLnZhbHVlPSIiK24pOmUudmFsdWUhPT0iIituJiYoZS52YWx1ZT0iIituKSksdC5oYXNPd25Qcm9wZXJ0eSgidmFsdWUiKT9iZShlLHQudHlwZSxuKTp0Lmhhc093blByb3BlcnR5KCJkZWZhdWx0VmFsdWUiKSYmYmUoZSx0LnR5cGUseGUodC5kZWZhdWx0VmFsdWUpKSxudWxsPT10LmNoZWNrZWQmJm51bGwhPXQuZGVmYXVsdENoZWNrZWQmJihlLmRlZmF1bHRDaGVja2VkPSEhdC5kZWZhdWx0Q2hlY2tlZCl9ZnVuY3Rpb24gdmUoZSx0KXsodC5oYXNPd25Qcm9wZXJ0eSgidmFsdWUiKXx8dC5oYXNPd25Qcm9wZXJ0eSgiZGVmYXVsdFZhbHVlIikpJiYoIiI9PT1lLnZhbHVlJiYoZS52YWx1ZT0iIitlLl93cmFwcGVyU3RhdGUuaW5pdGlhbFZhbHVlKSxlLmRlZmF1bHRWYWx1ZT0iIitlLl93cmFwcGVyU3RhdGUuaW5pdGlhbFZhbHVlKSx0PWUubmFtZSwiIiE9PXQmJihlLm5hbWU9IiIpLGUuZGVmYXVsdENoZWNrZWQ9IWUuZGVmYXVsdENoZWNrZWQsZS5kZWZhdWx0Q2hlY2tlZD0hZS5kZWZhdWx0Q2hlY2tlZCwiIiE9PXQmJihlLm5hbWU9dCl9ZnVuY3Rpb24gYmUoZSx0LG4peyJudW1iZXIiPT09dCYmZS5vd25lckRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ9PT1lfHwobnVsbD09bj9lLmRlZmF1bHRWYWx1ZT0iIitlLl93cmFwcGVyU3RhdGUuaW5pdGlhbFZhbHVlOmUuZGVmYXVsdFZhbHVlIT09IiIrbiYmKGUuZGVmYXVsdFZhbHVlPSIiK24pKX1mdW5jdGlvbiB4ZShlKXtzd2l0Y2godHlwZW9mIGUpe2Nhc2UiYm9vbGVhbiI6Y2FzZSJudW1iZXIiOmNhc2Uib2JqZWN0IjpjYXNlInN0cmluZyI6Y2FzZSJ1bmRlZmluZWQiOnJldHVybiBlO2RlZmF1bHQ6cmV0dXJuIiJ9fWZ1bmN0aW9uIENlKGUsdCxuKXtyZXR1cm4gZT1NLmdldFBvb2xlZChuby5jaGFuZ2UsZSx0LG4pLGUudHlwZT0iY2hhbmdlIixxKG4pLFQoZSksZX1mdW5jdGlvbiBFZShlKXt5KGUsITEpfWZ1bmN0aW9uIERlKGUpe2lmKGllKHgoZSkpKXJldHVybiBlfWZ1bmN0aW9uIHdlKGUsdCl7aWYoImNoYW5nZSI9PT1lKXJldHVybiB0fWZ1bmN0aW9uIFNlKCl7cm8mJihyby5kZXRhY2hFdmVudCgib25wcm9wZXJ0eWNoYW5nZSIsa2UpLGlvPXJvPW51bGwpfWZ1bmN0aW9uIGtlKGUpeyJ2YWx1ZSI9PT1lLnByb3BlcnR5TmFtZSYmRGUoaW8pJiYoZT1DZShpbyxlLFooZSkpLFkoRWUsZSkpfWZ1bmN0aW9uIEFlKGUsdCxuKXsiZm9jdXMiPT09ZT8oU2UoKSxybz10LGlvPW4scm8uYXR0YWNoRXZlbnQoIm9ucHJvcGVydHljaGFuZ2UiLGtlKSk6ImJsdXIiPT09ZSYmU2UoKX1mdW5jdGlvbiBfZShlKXtpZigic2VsZWN0aW9uY2hhbmdlIj09PWV8fCJrZXl1cCI9PT1lfHwia2V5ZG93biI9PT1lKXJldHVybiBEZShpbyl9ZnVuY3Rpb24gVGUoZSx0KXtpZigiY2xpY2siPT09ZSlyZXR1cm4gRGUodCl9ZnVuY3Rpb24gT2UoZSx0KXtpZigiaW5wdXQiPT09ZXx8ImNoYW5nZSI9PT1lKXJldHVybiBEZSh0KX1mdW5jdGlvbiBGZShlKXt2YXIgdD10aGlzLm5hdGl2ZUV2ZW50O3JldHVybiB0LmdldE1vZGlmaWVyU3RhdGU/dC5nZXRNb2RpZmllclN0YXRlKGUpOiEhKGU9dW9bZV0pJiYhIXRbZV19ZnVuY3Rpb24gTmUoKXtyZXR1cm4gRmV9ZnVuY3Rpb24gSWUoZSl7dmFyIHQ9ZTtpZihlLmFsdGVybmF0ZSlmb3IoO3QucmV0dXJuOyl0PXQucmV0dXJuO2Vsc2V7aWYoMCE9PSgyJnQuZWZmZWN0VGFnKSlyZXR1cm4gMTtmb3IoO3QucmV0dXJuOylpZih0PXQucmV0dXJuLDAhPT0oMiZ0LmVmZmVjdFRhZykpcmV0dXJuIDF9cmV0dXJuIDM9PT10LnRhZz8yOjN9ZnVuY3Rpb24gTGUoZSl7MiE9PUllKGUpJiZyKCIxODgiKX1mdW5jdGlvbiBQZShlKXt2YXIgdD1lLmFsdGVybmF0ZTtpZighdClyZXR1cm4gdD1JZShlKSwzPT09dCYmcigiMTg4IiksMT09PXQ/bnVsbDplO2Zvcih2YXIgbj1lLGk9dDs7KXt2YXIgbz1uLnJldHVybixhPW8/by5hbHRlcm5hdGU6bnVsbDtpZighb3x8IWEpYnJlYWs7aWYoby5jaGlsZD09PWEuY2hpbGQpe2Zvcih2YXIgcz1vLmNoaWxkO3M7KXtpZihzPT09bilyZXR1cm4gTGUobyksZTtpZihzPT09aSlyZXR1cm4gTGUobyksdDtzPXMuc2libGluZ31yKCIxODgiKX1pZihuLnJldHVybiE9PWkucmV0dXJuKW49byxpPWE7ZWxzZXtzPSExO2Zvcih2YXIgdT1vLmNoaWxkO3U7KXtpZih1PT09bil7cz0hMCxuPW8saT1hO2JyZWFrfWlmKHU9PT1pKXtzPSEwLGk9byxuPWE7YnJlYWt9dT11LnNpYmxpbmd9aWYoIXMpe2Zvcih1PWEuY2hpbGQ7dTspe2lmKHU9PT1uKXtzPSEwLG49YSxpPW87YnJlYWt9aWYodT09PWkpe3M9ITAsaT1hLG49bzticmVha311PXUuc2libGluZ31zfHxyKCIxODkiKX19bi5hbHRlcm5hdGUhPT1pJiZyKCIxOTAiKX1yZXR1cm4gMyE9PW4udGFnJiZyKCIxODgiKSxuLnN0YXRlTm9kZS5jdXJyZW50PT09bj9lOnR9ZnVuY3Rpb24gTWUoZSl7aWYoIShlPVBlKGUpKSlyZXR1cm4gbnVsbDtmb3IodmFyIHQ9ZTs7KXtpZig1PT09dC50YWd8fDY9PT10LnRhZylyZXR1cm4gdDtpZih0LmNoaWxkKXQuY2hpbGQucmV0dXJuPXQsdD10LmNoaWxkO2Vsc2V7aWYodD09PWUpYnJlYWs7Zm9yKDshdC5zaWJsaW5nOyl7aWYoIXQucmV0dXJufHx0LnJldHVybj09PWUpcmV0dXJuIG51bGw7dD10LnJldHVybn10LnNpYmxpbmcucmV0dXJuPXQucmV0dXJuLHQ9dC5zaWJsaW5nfX1yZXR1cm4gbnVsbH1mdW5jdGlvbiBqZShlKXtpZighKGU9UGUoZSkpKXJldHVybiBudWxsO2Zvcih2YXIgdD1lOzspe2lmKDU9PT10LnRhZ3x8Nj09PXQudGFnKXJldHVybiB0O2lmKHQuY2hpbGQmJjQhPT10LnRhZyl0LmNoaWxkLnJldHVybj10LHQ9dC5jaGlsZDtlbHNle2lmKHQ9PT1lKWJyZWFrO2Zvcig7IXQuc2libGluZzspe2lmKCF0LnJldHVybnx8dC5yZXR1cm49PT1lKXJldHVybiBudWxsO3Q9dC5yZXR1cm59dC5zaWJsaW5nLnJldHVybj10LnJldHVybix0PXQuc2libGluZ319cmV0dXJuIG51bGx9ZnVuY3Rpb24gUmUoZSl7dmFyIHQ9ZS5rZXlDb2RlO3JldHVybiJjaGFyQ29kZSJpbiBlPzA9PT0oZT1lLmNoYXJDb2RlKSYmMTM9PT10JiYoZT0xMyk6ZT10LDEwPT09ZSYmKGU9MTMpLDMyPD1lfHwxMz09PWU/ZTowfWZ1bmN0aW9uIEJlKGUsdCl7dmFyIG49ZVswXTtlPWVbMV07dmFyIHI9Im9uIisoZVswXS50b1VwcGVyQ2FzZSgpK2Uuc2xpY2UoMSkpO3Q9e3BoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOntidWJibGVkOnIsY2FwdHVyZWQ6cisiQ2FwdHVyZSJ9LGRlcGVuZGVuY2llczpbbl0saXNJbnRlcmFjdGl2ZTp0fSxTb1tlXT10LGtvW25dPXR9ZnVuY3Rpb24gJGUoZSl7dmFyIHQ9ZS50YXJnZXRJbnN0O2Rve2lmKCF0KXtlLmFuY2VzdG9ycy5wdXNoKHQpO2JyZWFrfXZhciBuO2ZvcihuPXQ7bi5yZXR1cm47KW49bi5yZXR1cm47aWYoIShuPTMhPT1uLnRhZz9udWxsOm4uc3RhdGVOb2RlLmNvbnRhaW5lckluZm8pKWJyZWFrO2UuYW5jZXN0b3JzLnB1c2godCksdD1iKG4pfXdoaWxlKHQpO2ZvcihuPTA7bjxlLmFuY2VzdG9ycy5sZW5ndGg7bisrKXQ9ZS5hbmNlc3RvcnNbbl0sdihlLnRvcExldmVsVHlwZSx0LGUubmF0aXZlRXZlbnQsWihlLm5hdGl2ZUV2ZW50KSl9ZnVuY3Rpb24gVWUoZSl7T289ISFlfWZ1bmN0aW9uIHplKGUsdCl7aWYoIXQpcmV0dXJuIG51bGw7dmFyIG49KF9vKGUpP1ZlOnFlKS5iaW5kKG51bGwsZSk7dC5hZGRFdmVudExpc3RlbmVyKGUsbiwhMSl9ZnVuY3Rpb24gR2UoZSx0KXtpZighdClyZXR1cm4gbnVsbDt2YXIgbj0oX28oZSk/VmU6cWUpLmJpbmQobnVsbCxlKTt0LmFkZEV2ZW50TGlzdGVuZXIoZSxuLCEwKX1mdW5jdGlvbiBWZShlLHQpe0socWUsZSx0KX1mdW5jdGlvbiBxZShlLHQpe2lmKE9vKXt2YXIgbj1aKHQpO2lmKG49YihuKSxudWxsPT09bnx8Im51bWJlciIhPT10eXBlb2Ygbi50YWd8fDI9PT1JZShuKXx8KG49bnVsbCksVG8ubGVuZ3RoKXt2YXIgcj1Uby5wb3AoKTtyLnRvcExldmVsVHlwZT1lLHIubmF0aXZlRXZlbnQ9dCxyLnRhcmdldEluc3Q9bixlPXJ9ZWxzZSBlPXt0b3BMZXZlbFR5cGU6ZSxuYXRpdmVFdmVudDp0LHRhcmdldEluc3Q6bixhbmNlc3RvcnM6W119O3RyeXtZKCRlLGUpfWZpbmFsbHl7ZS50b3BMZXZlbFR5cGU9bnVsbCxlLm5hdGl2ZUV2ZW50PW51bGwsZS50YXJnZXRJbnN0PW51bGwsZS5hbmNlc3RvcnMubGVuZ3RoPTAsMTA+VG8ubGVuZ3RoJiZUby5wdXNoKGUpfX19ZnVuY3Rpb24gSGUoZSl7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLExvKXx8KGVbTG9dPUlvKyssTm9bZVtMb11dPXt9KSxOb1tlW0xvXV19ZnVuY3Rpb24gV2UoZSl7Zm9yKDtlJiZlLmZpcnN0Q2hpbGQ7KWU9ZS5maXJzdENoaWxkO3JldHVybiBlfWZ1bmN0aW9uIFFlKGUsdCl7dmFyIG49V2UoZSk7ZT0wO2Zvcih2YXIgcjtuOyl7aWYoMz09PW4ubm9kZVR5cGUpe2lmKHI9ZStuLnRleHRDb250ZW50Lmxlbmd0aCxlPD10JiZyPj10KXJldHVybntub2RlOm4sb2Zmc2V0OnQtZX07ZT1yfWU6e2Zvcig7bjspe2lmKG4ubmV4dFNpYmxpbmcpe249bi5uZXh0U2libGluZzticmVhayBlfW49bi5wYXJlbnROb2RlfW49dm9pZCAwfW49V2Uobil9fWZ1bmN0aW9uIEtlKGUpe3ZhciB0PWUmJmUubm9kZU5hbWUmJmUubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtyZXR1cm4gdCYmKCJpbnB1dCI9PT10JiYidGV4dCI9PT1lLnR5cGV8fCJ0ZXh0YXJlYSI9PT10fHwidHJ1ZSI9PT1lLmNvbnRlbnRFZGl0YWJsZSl9ZnVuY3Rpb24gSmUoZSx0KXtpZigkb3x8bnVsbD09am98fGpvIT09UnIoKSlyZXR1cm4gbnVsbDt2YXIgbj1qbztyZXR1cm4ic2VsZWN0aW9uU3RhcnQiaW4gbiYmS2Uobik/bj17c3RhcnQ6bi5zZWxlY3Rpb25TdGFydCxlbmQ6bi5zZWxlY3Rpb25FbmR9OndpbmRvdy5nZXRTZWxlY3Rpb24/KG49d2luZG93LmdldFNlbGVjdGlvbigpLG49e2FuY2hvck5vZGU6bi5hbmNob3JOb2RlLGFuY2hvck9mZnNldDpuLmFuY2hvck9mZnNldCxmb2N1c05vZGU6bi5mb2N1c05vZGUsZm9jdXNPZmZzZXQ6bi5mb2N1c09mZnNldH0pOm49dm9pZCAwLEJvJiZCcihCbyxuKT9udWxsOihCbz1uLGU9TS5nZXRQb29sZWQoTW8uc2VsZWN0LFJvLGUsdCksZS50eXBlPSJzZWxlY3QiLGUudGFyZ2V0PWpvLFQoZSksZSl9ZnVuY3Rpb24gWWUoZSl7dmFyIHQ9IiI7cmV0dXJuIExyLkNoaWxkcmVuLmZvckVhY2goZSxmdW5jdGlvbihlKXtudWxsPT1lfHwic3RyaW5nIiE9PXR5cGVvZiBlJiYibnVtYmVyIiE9PXR5cGVvZiBlfHwodCs9ZSl9KSx0fWZ1bmN0aW9uIFhlKGUsdCl7cmV0dXJuIGU9TXIoe2NoaWxkcmVuOnZvaWQgMH0sdCksKHQ9WWUodC5jaGlsZHJlbikpJiYoZS5jaGlsZHJlbj10KSxlfWZ1bmN0aW9uIFplKGUsdCxuLHIpe2lmKGU9ZS5vcHRpb25zLHQpe3Q9e307Zm9yKHZhciBpPTA7aTxuLmxlbmd0aDtpKyspdFsiJCIrbltpXV09ITA7Zm9yKG49MDtuPGUubGVuZ3RoO24rKylpPXQuaGFzT3duUHJvcGVydHkoIiQiK2Vbbl0udmFsdWUpLGVbbl0uc2VsZWN0ZWQhPT1pJiYoZVtuXS5zZWxlY3RlZD1pKSxpJiZyJiYoZVtuXS5kZWZhdWx0U2VsZWN0ZWQ9ITApfWVsc2V7Zm9yKG49IiIrbix0PW51bGwsaT0wO2k8ZS5sZW5ndGg7aSsrKXtpZihlW2ldLnZhbHVlPT09bilyZXR1cm4gZVtpXS5zZWxlY3RlZD0hMCx2b2lkKHImJihlW2ldLmRlZmF1bHRTZWxlY3RlZD0hMCkpO251bGwhPT10fHxlW2ldLmRpc2FibGVkfHwodD1lW2ldKX1udWxsIT09dCYmKHQuc2VsZWN0ZWQ9ITApfX1mdW5jdGlvbiBldChlLHQpe3ZhciBuPXQudmFsdWU7ZS5fd3JhcHBlclN0YXRlPXtpbml0aWFsVmFsdWU6bnVsbCE9bj9uOnQuZGVmYXVsdFZhbHVlLHdhc011bHRpcGxlOiEhdC5tdWx0aXBsZX19ZnVuY3Rpb24gdHQoZSx0KXtyZXR1cm4gbnVsbCE9dC5kYW5nZXJvdXNseVNldElubmVySFRNTCYmcigiOTEiKSxNcih7fSx0LHt2YWx1ZTp2b2lkIDAsZGVmYXVsdFZhbHVlOnZvaWQgMCxjaGlsZHJlbjoiIitlLl93cmFwcGVyU3RhdGUuaW5pdGlhbFZhbHVlfSl9ZnVuY3Rpb24gbnQoZSx0KXt2YXIgbj10LnZhbHVlO251bGw9PW4mJihuPXQuZGVmYXVsdFZhbHVlLHQ9dC5jaGlsZHJlbixudWxsIT10JiYobnVsbCE9biYmcigiOTIiKSxBcnJheS5pc0FycmF5KHQpJiYoMT49dC5sZW5ndGh8fHIoIjkzIiksdD10WzBdKSxuPSIiK3QpLG51bGw9PW4mJihuPSIiKSksZS5fd3JhcHBlclN0YXRlPXtpbml0aWFsVmFsdWU6IiIrbn19ZnVuY3Rpb24gcnQoZSx0KXt2YXIgbj10LnZhbHVlO251bGwhPW4mJihuPSIiK24sbiE9PWUudmFsdWUmJihlLnZhbHVlPW4pLG51bGw9PXQuZGVmYXVsdFZhbHVlJiYoZS5kZWZhdWx0VmFsdWU9bikpLG51bGwhPXQuZGVmYXVsdFZhbHVlJiYoZS5kZWZhdWx0VmFsdWU9dC5kZWZhdWx0VmFsdWUpfWZ1bmN0aW9uIGl0KGUpe3ZhciB0PWUudGV4dENvbnRlbnQ7dD09PWUuX3dyYXBwZXJTdGF0ZS5pbml0aWFsVmFsdWUmJihlLnZhbHVlPXQpfWZ1bmN0aW9uIG90KGUpe3N3aXRjaChlKXtjYXNlInN2ZyI6cmV0dXJuImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIjtjYXNlIm1hdGgiOnJldHVybiJodHRwOi8vd3d3LnczLm9yZy8xOTk4L01hdGgvTWF0aE1MIjtkZWZhdWx0OnJldHVybiJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIn19ZnVuY3Rpb24gYXQoZSx0KXtyZXR1cm4gbnVsbD09ZXx8Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPT09ZT9vdCh0KToiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPT09ZSYmImZvcmVpZ25PYmplY3QiPT09dD8iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI6ZX1mdW5jdGlvbiBzdChlLHQpe2lmKHQpe3ZhciBuPWUuZmlyc3RDaGlsZDtpZihuJiZuPT09ZS5sYXN0Q2hpbGQmJjM9PT1uLm5vZGVUeXBlKXJldHVybiB2b2lkKG4ubm9kZVZhbHVlPXQpfWUudGV4dENvbnRlbnQ9dH1mdW5jdGlvbiB1dChlLHQpe2U9ZS5zdHlsZTtmb3IodmFyIG4gaW4gdClpZih0Lmhhc093blByb3BlcnR5KG4pKXt2YXIgcj0wPT09bi5pbmRleE9mKCItLSIpLGk9bixvPXRbbl07aT1udWxsPT1vfHwiYm9vbGVhbiI9PT10eXBlb2Ygb3x8IiI9PT1vPyIiOnJ8fCJudW1iZXIiIT09dHlwZW9mIG98fDA9PT1vfHxjYS5oYXNPd25Qcm9wZXJ0eShpKSYmY2FbaV0/KCIiK28pLnRyaW0oKTpvKyJweCIsImZsb2F0Ij09PW4mJihuPSJjc3NGbG9hdCIpLHI/ZS5zZXRQcm9wZXJ0eShuLGkpOmVbbl09aX19ZnVuY3Rpb24gY3QoZSx0LG4pe3QmJihwYVtlXSYmKG51bGwhPXQuY2hpbGRyZW58fG51bGwhPXQuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwpJiZyKCIxMzciLGUsbigpKSxudWxsIT10LmRhbmdlcm91c2x5U2V0SW5uZXJIVE1MJiYobnVsbCE9dC5jaGlsZHJlbiYmcigiNjAiKSwib2JqZWN0Ij09PXR5cGVvZiB0LmRhbmdlcm91c2x5U2V0SW5uZXJIVE1MJiYiX19odG1sImluIHQuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUx8fHIoIjYxIikpLG51bGwhPXQuc3R5bGUmJiJvYmplY3QiIT09dHlwZW9mIHQuc3R5bGUmJnIoIjYyIixuKCkpKX1mdW5jdGlvbiBsdChlLHQpe2lmKC0xPT09ZS5pbmRleE9mKCItIikpcmV0dXJuInN0cmluZyI9PT10eXBlb2YgdC5pcztzd2l0Y2goZSl7Y2FzZSJhbm5vdGF0aW9uLXhtbCI6Y2FzZSJjb2xvci1wcm9maWxlIjpjYXNlImZvbnQtZmFjZSI6Y2FzZSJmb250LWZhY2Utc3JjIjpjYXNlImZvbnQtZmFjZS11cmkiOmNhc2UiZm9udC1mYWNlLWZvcm1hdCI6Y2FzZSJmb250LWZhY2UtbmFtZSI6Y2FzZSJtaXNzaW5nLWdseXBoIjpyZXR1cm4hMTtkZWZhdWx0OnJldHVybiEwfX1mdW5jdGlvbiBwdChlLHQpe2U9OT09PWUubm9kZVR5cGV8fDExPT09ZS5ub2RlVHlwZT9lOmUub3duZXJEb2N1bWVudDt2YXIgbj1IZShlKTt0PVFyW3RdO2Zvcih2YXIgcj0wO3I8dC5sZW5ndGg7cisrKXt2YXIgaT10W3JdO2lmKCFuLmhhc093blByb3BlcnR5KGkpfHwhbltpXSl7c3dpdGNoKGkpe2Nhc2Uic2Nyb2xsIjpHZSgic2Nyb2xsIixlKTticmVhaztjYXNlImZvY3VzIjpjYXNlImJsdXIiOkdlKCJmb2N1cyIsZSksR2UoImJsdXIiLGUpLG4uYmx1cj0hMCxuLmZvY3VzPSEwO2JyZWFrO2Nhc2UiY2FuY2VsIjpjYXNlImNsb3NlIjplZShpLCEwKSYmR2UoaSxlKTticmVhaztjYXNlImludmFsaWQiOmNhc2Uic3VibWl0IjpjYXNlInJlc2V0IjpicmVhaztkZWZhdWx0Oi0xPT09aGkuaW5kZXhPZihpKSYmemUoaSxlKX1uW2ldPSEwfX19ZnVuY3Rpb24gZnQoZSx0LG4scil7cmV0dXJuIG49OT09PW4ubm9kZVR5cGU/bjpuLm93bmVyRG9jdW1lbnQscj09PWFhLmh0bWwmJihyPW90KGUpKSxyPT09YWEuaHRtbD8ic2NyaXB0Ij09PWU/KGU9bi5jcmVhdGVFbGVtZW50KCJkaXYiKSxlLmlubmVySFRNTD0iPHNjcmlwdD48XC9zY3JpcHQ+IixlPWUucmVtb3ZlQ2hpbGQoZS5maXJzdENoaWxkKSk6ZT0ic3RyaW5nIj09PXR5cGVvZiB0LmlzP24uY3JlYXRlRWxlbWVudChlLHtpczp0LmlzfSk6bi5jcmVhdGVFbGVtZW50KGUpOmU9bi5jcmVhdGVFbGVtZW50TlMocixlKSxlfWZ1bmN0aW9uIGR0KGUsdCl7cmV0dXJuKDk9PT10Lm5vZGVUeXBlP3Q6dC5vd25lckRvY3VtZW50KS5jcmVhdGVUZXh0Tm9kZShlKX1mdW5jdGlvbiBodChlLHQsbixyKXt2YXIgaT1sdCh0LG4pO3N3aXRjaCh0KXtjYXNlImlmcmFtZSI6Y2FzZSJvYmplY3QiOnplKCJsb2FkIixlKTt2YXIgbz1uO2JyZWFrO2Nhc2UidmlkZW8iOmNhc2UiYXVkaW8iOmZvcihvPTA7bzxoaS5sZW5ndGg7bysrKXplKGhpW29dLGUpO289bjticmVhaztjYXNlInNvdXJjZSI6emUoImVycm9yIixlKSxvPW47YnJlYWs7Y2FzZSJpbWciOmNhc2UiaW1hZ2UiOmNhc2UibGluayI6emUoImVycm9yIixlKSx6ZSgibG9hZCIsZSksbz1uO2JyZWFrO2Nhc2UiZm9ybSI6emUoInJlc2V0IixlKSx6ZSgic3VibWl0IixlKSxvPW47YnJlYWs7Y2FzZSJkZXRhaWxzIjp6ZSgidG9nZ2xlIixlKSxvPW47YnJlYWs7Y2FzZSJpbnB1dCI6bWUoZSxuKSxvPWhlKGUsbiksemUoImludmFsaWQiLGUpLHB0KHIsIm9uQ2hhbmdlIik7YnJlYWs7Y2FzZSJvcHRpb24iOm89WGUoZSxuKTticmVhaztjYXNlInNlbGVjdCI6ZXQoZSxuKSxvPU1yKHt9LG4se3ZhbHVlOnZvaWQgMH0pLHplKCJpbnZhbGlkIixlKSxwdChyLCJvbkNoYW5nZSIpO2JyZWFrO2Nhc2UidGV4dGFyZWEiOm50KGUsbiksbz10dChlLG4pLHplKCJpbnZhbGlkIixlKSxwdChyLCJvbkNoYW5nZSIpO2JyZWFrO2RlZmF1bHQ6bz1ufWN0KHQsbyxmYSk7dmFyIGEscz1vO2ZvcihhIGluIHMpaWYocy5oYXNPd25Qcm9wZXJ0eShhKSl7dmFyIHU9c1thXTsic3R5bGUiPT09YT91dChlLHUsZmEpOiJkYW5nZXJvdXNseVNldElubmVySFRNTCI9PT1hP251bGwhPSh1PXU/dS5fX2h0bWw6dm9pZCAwKSYmdWEoZSx1KToiY2hpbGRyZW4iPT09YT8ic3RyaW5nIj09PXR5cGVvZiB1PygidGV4dGFyZWEiIT09dHx8IiIhPT11KSYmc3QoZSx1KToibnVtYmVyIj09PXR5cGVvZiB1JiZzdChlLCIiK3UpOiJzdXBwcmVzc0NvbnRlbnRFZGl0YWJsZVdhcm5pbmciIT09YSYmInN1cHByZXNzSHlkcmF0aW9uV2FybmluZyIhPT1hJiYiYXV0b0ZvY3VzIiE9PWEmJihXci5oYXNPd25Qcm9wZXJ0eShhKT9udWxsIT11JiZwdChyLGEpOm51bGwhPXUmJmRlKGUsYSx1LGkpKX1zd2l0Y2godCl7Y2FzZSJpbnB1dCI6cmUoZSksdmUoZSxuKTticmVhaztjYXNlInRleHRhcmVhIjpyZShlKSxpdChlLG4pO2JyZWFrO2Nhc2Uib3B0aW9uIjpudWxsIT1uLnZhbHVlJiZlLnNldEF0dHJpYnV0ZSgidmFsdWUiLG4udmFsdWUpO2JyZWFrO2Nhc2Uic2VsZWN0IjplLm11bHRpcGxlPSEhbi5tdWx0aXBsZSx0PW4udmFsdWUsbnVsbCE9dD9aZShlLCEhbi5tdWx0aXBsZSx0LCExKTpudWxsIT1uLmRlZmF1bHRWYWx1ZSYmWmUoZSwhIW4ubXVsdGlwbGUsbi5kZWZhdWx0VmFsdWUsITApO2JyZWFrO2RlZmF1bHQ6ImZ1bmN0aW9uIj09PXR5cGVvZiBvLm9uQ2xpY2smJihlLm9uY2xpY2s9anIpfX1mdW5jdGlvbiBtdChlLHQsbixyLGkpe3ZhciBvPW51bGw7c3dpdGNoKHQpe2Nhc2UiaW5wdXQiOm49aGUoZSxuKSxyPWhlKGUsciksbz1bXTticmVhaztjYXNlIm9wdGlvbiI6bj1YZShlLG4pLHI9WGUoZSxyKSxvPVtdO2JyZWFrO2Nhc2Uic2VsZWN0IjpuPU1yKHt9LG4se3ZhbHVlOnZvaWQgMH0pLHI9TXIoe30scix7dmFsdWU6dm9pZCAwfSksbz1bXTticmVhaztjYXNlInRleHRhcmVhIjpuPXR0KGUsbikscj10dChlLHIpLG89W107YnJlYWs7ZGVmYXVsdDoiZnVuY3Rpb24iIT09dHlwZW9mIG4ub25DbGljayYmImZ1bmN0aW9uIj09PXR5cGVvZiByLm9uQ2xpY2smJihlLm9uY2xpY2s9anIpfWN0KHQscixmYSksdD1lPXZvaWQgMDt2YXIgYT1udWxsO2ZvcihlIGluIG4paWYoIXIuaGFzT3duUHJvcGVydHkoZSkmJm4uaGFzT3duUHJvcGVydHkoZSkmJm51bGwhPW5bZV0paWYoInN0eWxlIj09PWUpe3ZhciBzPW5bZV07Zm9yKHQgaW4gcylzLmhhc093blByb3BlcnR5KHQpJiYoYXx8KGE9e30pLGFbdF09IiIpfWVsc2UiZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwiIT09ZSYmImNoaWxkcmVuIiE9PWUmJiJzdXBwcmVzc0NvbnRlbnRFZGl0YWJsZVdhcm5pbmciIT09ZSYmInN1cHByZXNzSHlkcmF0aW9uV2FybmluZyIhPT1lJiYiYXV0b0ZvY3VzIiE9PWUmJihXci5oYXNPd25Qcm9wZXJ0eShlKT9vfHwobz1bXSk6KG89b3x8W10pLnB1c2goZSxudWxsKSk7Zm9yKGUgaW4gcil7dmFyIHU9cltlXTtpZihzPW51bGwhPW4/bltlXTp2b2lkIDAsci5oYXNPd25Qcm9wZXJ0eShlKSYmdSE9PXMmJihudWxsIT11fHxudWxsIT1zKSlpZigic3R5bGUiPT09ZSlpZihzKXtmb3IodCBpbiBzKSFzLmhhc093blByb3BlcnR5KHQpfHx1JiZ1Lmhhc093blByb3BlcnR5KHQpfHwoYXx8KGE9e30pLGFbdF09IiIpO2Zvcih0IGluIHUpdS5oYXNPd25Qcm9wZXJ0eSh0KSYmc1t0XSE9PXVbdF0mJihhfHwoYT17fSksYVt0XT11W3RdKX1lbHNlIGF8fChvfHwobz1bXSksby5wdXNoKGUsYSkpLGE9dTtlbHNlImRhbmdlcm91c2x5U2V0SW5uZXJIVE1MIj09PWU/KHU9dT91Ll9faHRtbDp2b2lkIDAscz1zP3MuX19odG1sOnZvaWQgMCxudWxsIT11JiZzIT09dSYmKG89b3x8W10pLnB1c2goZSwiIit1KSk6ImNoaWxkcmVuIj09PWU/cz09PXV8fCJzdHJpbmciIT09dHlwZW9mIHUmJiJudW1iZXIiIT09dHlwZW9mIHV8fChvPW98fFtdKS5wdXNoKGUsIiIrdSk6InN1cHByZXNzQ29udGVudEVkaXRhYmxlV2FybmluZyIhPT1lJiYic3VwcHJlc3NIeWRyYXRpb25XYXJuaW5nIiE9PWUmJihXci5oYXNPd25Qcm9wZXJ0eShlKT8obnVsbCE9dSYmcHQoaSxlKSxvfHxzPT09dXx8KG89W10pKToobz1vfHxbXSkucHVzaChlLHUpKX1yZXR1cm4gYSYmKG89b3x8W10pLnB1c2goInN0eWxlIixhKSxvfWZ1bmN0aW9uIGd0KGUsdCxuLHIsaSl7ImlucHV0Ij09PW4mJiJyYWRpbyI9PT1pLnR5cGUmJm51bGwhPWkubmFtZSYmZ2UoZSxpKSxsdChuLHIpLHI9bHQobixpKTtmb3IodmFyIG89MDtvPHQubGVuZ3RoO28rPTIpe3ZhciBhPXRbb10scz10W28rMV07InN0eWxlIj09PWE/dXQoZSxzLGZhKToiZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwiPT09YT91YShlLHMpOiJjaGlsZHJlbiI9PT1hP3N0KGUscyk6ZGUoZSxhLHMscil9c3dpdGNoKG4pe2Nhc2UiaW5wdXQiOnllKGUsaSk7YnJlYWs7Y2FzZSJ0ZXh0YXJlYSI6cnQoZSxpKTticmVhaztjYXNlInNlbGVjdCI6ZS5fd3JhcHBlclN0YXRlLmluaXRpYWxWYWx1ZT12b2lkIDAsdD1lLl93cmFwcGVyU3RhdGUud2FzTXVsdGlwbGUsZS5fd3JhcHBlclN0YXRlLndhc011bHRpcGxlPSEhaS5tdWx0aXBsZSxuPWkudmFsdWUsbnVsbCE9bj9aZShlLCEhaS5tdWx0aXBsZSxuLCExKTp0IT09ISFpLm11bHRpcGxlJiYobnVsbCE9aS5kZWZhdWx0VmFsdWU/WmUoZSwhIWkubXVsdGlwbGUsaS5kZWZhdWx0VmFsdWUsITApOlplKGUsISFpLm11bHRpcGxlLGkubXVsdGlwbGU/W106IiIsITEpKX19ZnVuY3Rpb24geXQoZSx0LG4scixpKXtzd2l0Y2godCl7Y2FzZSJpZnJhbWUiOmNhc2Uib2JqZWN0Ijp6ZSgibG9hZCIsZSk7YnJlYWs7Y2FzZSJ2aWRlbyI6Y2FzZSJhdWRpbyI6Zm9yKHI9MDtyPGhpLmxlbmd0aDtyKyspemUoaGlbcl0sZSk7YnJlYWs7Y2FzZSJzb3VyY2UiOnplKCJlcnJvciIsZSk7YnJlYWs7Y2FzZSJpbWciOmNhc2UiaW1hZ2UiOmNhc2UibGluayI6emUoImVycm9yIixlKSx6ZSgibG9hZCIsZSk7YnJlYWs7Y2FzZSJmb3JtIjp6ZSgicmVzZXQiLGUpLHplKCJzdWJtaXQiLGUpO2JyZWFrO2Nhc2UiZGV0YWlscyI6emUoInRvZ2dsZSIsZSk7YnJlYWs7Y2FzZSJpbnB1dCI6bWUoZSxuKSx6ZSgiaW52YWxpZCIsZSkscHQoaSwib25DaGFuZ2UiKTticmVhaztjYXNlInNlbGVjdCI6ZXQoZSxuKSx6ZSgiaW52YWxpZCIsZSkscHQoaSwib25DaGFuZ2UiKTticmVhaztjYXNlInRleHRhcmVhIjpudChlLG4pLHplKCJpbnZhbGlkIixlKSxwdChpLCJvbkNoYW5nZSIpfWN0KHQsbixmYSkscj1udWxsO2Zvcih2YXIgbyBpbiBuKWlmKG4uaGFzT3duUHJvcGVydHkobykpe3ZhciBhPW5bb107ImNoaWxkcmVuIj09PW8/InN0cmluZyI9PT10eXBlb2YgYT9lLnRleHRDb250ZW50IT09YSYmKHI9WyJjaGlsZHJlbiIsYV0pOiJudW1iZXIiPT09dHlwZW9mIGEmJmUudGV4dENvbnRlbnQhPT0iIithJiYocj1bImNoaWxkcmVuIiwiIithXSk6V3IuaGFzT3duUHJvcGVydHkobykmJm51bGwhPWEmJnB0KGksbyl9c3dpdGNoKHQpe2Nhc2UiaW5wdXQiOnJlKGUpLHZlKGUsbik7YnJlYWs7Y2FzZSJ0ZXh0YXJlYSI6cmUoZSksaXQoZSxuKTticmVhaztjYXNlInNlbGVjdCI6Y2FzZSJvcHRpb24iOmJyZWFrO2RlZmF1bHQ6ImZ1bmN0aW9uIj09PXR5cGVvZiBuLm9uQ2xpY2smJihlLm9uY2xpY2s9anIpfXJldHVybiByfWZ1bmN0aW9uIHZ0KGUsdCl7cmV0dXJuIGUubm9kZVZhbHVlIT09dH1mdW5jdGlvbiBidChlLHQpe3N3aXRjaChlKXtjYXNlImJ1dHRvbiI6Y2FzZSJpbnB1dCI6Y2FzZSJzZWxlY3QiOmNhc2UidGV4dGFyZWEiOnJldHVybiEhdC5hdXRvRm9jdXN9cmV0dXJuITF9ZnVuY3Rpb24geHQoZSx0KXtyZXR1cm4idGV4dGFyZWEiPT09ZXx8InN0cmluZyI9PT10eXBlb2YgdC5jaGlsZHJlbnx8Im51bWJlciI9PT10eXBlb2YgdC5jaGlsZHJlbnx8Im9iamVjdCI9PT10eXBlb2YgdC5kYW5nZXJvdXNseVNldElubmVySFRNTCYmbnVsbCE9PXQuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwmJiJzdHJpbmciPT09dHlwZW9mIHQuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwuX19odG1sfWZ1bmN0aW9uIEN0KGUpe2ZvcihlPWUubmV4dFNpYmxpbmc7ZSYmMSE9PWUubm9kZVR5cGUmJjMhPT1lLm5vZGVUeXBlOyllPWUubmV4dFNpYmxpbmc7cmV0dXJuIGV9ZnVuY3Rpb24gRXQoZSl7Zm9yKGU9ZS5maXJzdENoaWxkO2UmJjEhPT1lLm5vZGVUeXBlJiYzIT09ZS5ub2RlVHlwZTspZT1lLm5leHRTaWJsaW5nO3JldHVybiBlfWZ1bmN0aW9uIER0KGUpe3JldHVybntjdXJyZW50OmV9fWZ1bmN0aW9uIHd0KGUpezA+eGF8fChlLmN1cnJlbnQ9YmFbeGFdLGJhW3hhXT1udWxsLHhhLS0pfWZ1bmN0aW9uIFN0KGUsdCl7eGErKyxiYVt4YV09ZS5jdXJyZW50LGUuY3VycmVudD10fWZ1bmN0aW9uIGt0KGUpe3JldHVybiBfdChlKT9EYTpDYS5jdXJyZW50fWZ1bmN0aW9uIEF0KGUsdCl7dmFyIG49ZS50eXBlLmNvbnRleHRUeXBlcztpZighbilyZXR1cm4gVXI7dmFyIHI9ZS5zdGF0ZU5vZGU7aWYociYmci5fX3JlYWN0SW50ZXJuYWxNZW1vaXplZFVubWFza2VkQ2hpbGRDb250ZXh0PT09dClyZXR1cm4gci5fX3JlYWN0SW50ZXJuYWxNZW1vaXplZE1hc2tlZENoaWxkQ29udGV4dDt2YXIgaSxvPXt9O2ZvcihpIGluIG4pb1tpXT10W2ldO3JldHVybiByJiYoZT1lLnN0YXRlTm9kZSxlLl9fcmVhY3RJbnRlcm5hbE1lbW9pemVkVW5tYXNrZWRDaGlsZENvbnRleHQ9dCxlLl9fcmVhY3RJbnRlcm5hbE1lbW9pemVkTWFza2VkQ2hpbGRDb250ZXh0PW8pLG99ZnVuY3Rpb24gX3QoZSl7cmV0dXJuIDI9PT1lLnRhZyYmbnVsbCE9ZS50eXBlLmNoaWxkQ29udGV4dFR5cGVzfWZ1bmN0aW9uIFR0KGUpe190KGUpJiYod3QoRWEsZSksd3QoQ2EsZSkpfWZ1bmN0aW9uIE90KGUpe3d0KEVhLGUpLHd0KENhLGUpfWZ1bmN0aW9uIEZ0KGUsdCxuKXtDYS5jdXJyZW50IT09VXImJnIoIjE2OCIpLFN0KENhLHQsZSksU3QoRWEsbixlKX1mdW5jdGlvbiBOdChlLHQpe3ZhciBuPWUuc3RhdGVOb2RlLGk9ZS50eXBlLmNoaWxkQ29udGV4dFR5cGVzO2lmKCJmdW5jdGlvbiIhPT10eXBlb2Ygbi5nZXRDaGlsZENvbnRleHQpcmV0dXJuIHQ7bj1uLmdldENoaWxkQ29udGV4dCgpO2Zvcih2YXIgbyBpbiBuKW8gaW4gaXx8cigiMTA4IixhZShlKXx8IlVua25vd24iLG8pO3JldHVybiBNcih7fSx0LG4pfWZ1bmN0aW9uIEl0KGUpe2lmKCFfdChlKSlyZXR1cm4hMTt2YXIgdD1lLnN0YXRlTm9kZTtyZXR1cm4gdD10JiZ0Ll9fcmVhY3RJbnRlcm5hbE1lbW9pemVkTWVyZ2VkQ2hpbGRDb250ZXh0fHxVcixEYT1DYS5jdXJyZW50LFN0KENhLHQsZSksU3QoRWEsRWEuY3VycmVudCxlKSwhMH1mdW5jdGlvbiBMdChlLHQpe3ZhciBuPWUuc3RhdGVOb2RlO2lmKG58fHIoIjE2OSIpLHQpe3ZhciBpPU50KGUsRGEpO24uX19yZWFjdEludGVybmFsTWVtb2l6ZWRNZXJnZWRDaGlsZENvbnRleHQ9aSx3dChFYSxlKSx3dChDYSxlKSxTdChDYSxpLGUpfWVsc2Ugd3QoRWEsZSk7U3QoRWEsdCxlKX1mdW5jdGlvbiBQdChlLHQsbixyKXt0aGlzLnRhZz1lLHRoaXMua2V5PW4sdGhpcy5zaWJsaW5nPXRoaXMuY2hpbGQ9dGhpcy5yZXR1cm49dGhpcy5zdGF0ZU5vZGU9dGhpcy50eXBlPW51bGwsdGhpcy5pbmRleD0wLHRoaXMucmVmPW51bGwsdGhpcy5wZW5kaW5nUHJvcHM9dCx0aGlzLm1lbW9pemVkU3RhdGU9dGhpcy51cGRhdGVRdWV1ZT10aGlzLm1lbW9pemVkUHJvcHM9bnVsbCx0aGlzLm1vZGU9cix0aGlzLmVmZmVjdFRhZz0wLHRoaXMubGFzdEVmZmVjdD10aGlzLmZpcnN0RWZmZWN0PXRoaXMubmV4dEVmZmVjdD1udWxsLHRoaXMuZXhwaXJhdGlvblRpbWU9MCx0aGlzLmFsdGVybmF0ZT1udWxsfWZ1bmN0aW9uIE10KGUsdCxuKXt2YXIgcj1lLmFsdGVybmF0ZTtyZXR1cm4gbnVsbD09PXI/KHI9bmV3IFB0KGUudGFnLHQsZS5rZXksZS5tb2RlKSxyLnR5cGU9ZS50eXBlLHIuc3RhdGVOb2RlPWUuc3RhdGVOb2RlLHIuYWx0ZXJuYXRlPWUsZS5hbHRlcm5hdGU9cik6KHIucGVuZGluZ1Byb3BzPXQsci5lZmZlY3RUYWc9MCxyLm5leHRFZmZlY3Q9bnVsbCxyLmZpcnN0RWZmZWN0PW51bGwsci5sYXN0RWZmZWN0PW51bGwpLHIuZXhwaXJhdGlvblRpbWU9bixyLmNoaWxkPWUuY2hpbGQsci5tZW1vaXplZFByb3BzPWUubWVtb2l6ZWRQcm9wcyxyLm1lbW9pemVkU3RhdGU9ZS5tZW1vaXplZFN0YXRlLHIudXBkYXRlUXVldWU9ZS51cGRhdGVRdWV1ZSxyLnNpYmxpbmc9ZS5zaWJsaW5nLHIuaW5kZXg9ZS5pbmRleCxyLnJlZj1lLnJlZixyfWZ1bmN0aW9uIGp0KGUsdCxuKXt2YXIgaT1lLnR5cGUsbz1lLmtleTtpZihlPWUucHJvcHMsImZ1bmN0aW9uIj09PXR5cGVvZiBpKXZhciBhPWkucHJvdG90eXBlJiZpLnByb3RvdHlwZS5pc1JlYWN0Q29tcG9uZW50PzI6MDtlbHNlIGlmKCJzdHJpbmciPT09dHlwZW9mIGkpYT01O2Vsc2Ugc3dpdGNoKGkpe2Nhc2Ugemk6cmV0dXJuIFJ0KGUuY2hpbGRyZW4sdCxuLG8pO2Nhc2UgV2k6YT0xMSx0fD0zO2JyZWFrO2Nhc2UgR2k6YT0xMSx0fD0yO2JyZWFrO2Nhc2UgVmk6cmV0dXJuIGk9bmV3IFB0KDE1LGUsbyw0fHQpLGkudHlwZT1WaSxpLmV4cGlyYXRpb25UaW1lPW4saTtjYXNlIEtpOmE9MTYsdHw9MjticmVhaztkZWZhdWx0OmU6e3N3aXRjaCgib2JqZWN0Ij09PXR5cGVvZiBpJiZudWxsIT09aT9pLiQkdHlwZW9mOm51bGwpe2Nhc2UgcWk6YT0xMzticmVhayBlO2Nhc2UgSGk6YT0xMjticmVhayBlO2Nhc2UgUWk6YT0xNDticmVhayBlO2RlZmF1bHQ6cigiMTMwIixudWxsPT1pP2k6dHlwZW9mIGksIiIpfWE9dm9pZCAwfX1yZXR1cm4gdD1uZXcgUHQoYSxlLG8sdCksdC50eXBlPWksdC5leHBpcmF0aW9uVGltZT1uLHR9ZnVuY3Rpb24gUnQoZSx0LG4scil7cmV0dXJuIGU9bmV3IFB0KDEwLGUscix0KSxlLmV4cGlyYXRpb25UaW1lPW4sZX1mdW5jdGlvbiBCdChlLHQsbil7cmV0dXJuIGU9bmV3IFB0KDYsZSxudWxsLHQpLGUuZXhwaXJhdGlvblRpbWU9bixlfWZ1bmN0aW9uICR0KGUsdCxuKXtyZXR1cm4gdD1uZXcgUHQoNCxudWxsIT09ZS5jaGlsZHJlbj9lLmNoaWxkcmVuOltdLGUua2V5LHQpLHQuZXhwaXJhdGlvblRpbWU9bix0LnN0YXRlTm9kZT17Y29udGFpbmVySW5mbzplLmNvbnRhaW5lckluZm8scGVuZGluZ0NoaWxkcmVuOm51bGwsaW1wbGVtZW50YXRpb246ZS5pbXBsZW1lbnRhdGlvbn0sdH1mdW5jdGlvbiBVdChlLHQsbil7cmV0dXJuIHQ9bmV3IFB0KDMsbnVsbCxudWxsLHQ/MzowKSxlPXtjdXJyZW50OnQsY29udGFpbmVySW5mbzplLHBlbmRpbmdDaGlsZHJlbjpudWxsLGVhcmxpZXN0UGVuZGluZ1RpbWU6MCxsYXRlc3RQZW5kaW5nVGltZTowLGVhcmxpZXN0U3VzcGVuZGVkVGltZTowLGxhdGVzdFN1c3BlbmRlZFRpbWU6MCxsYXRlc3RQaW5nZWRUaW1lOjAscGVuZGluZ0NvbW1pdEV4cGlyYXRpb25UaW1lOjAsZmluaXNoZWRXb3JrOm51bGwsY29udGV4dDpudWxsLHBlbmRpbmdDb250ZXh0Om51bGwsaHlkcmF0ZTpuLHJlbWFpbmluZ0V4cGlyYXRpb25UaW1lOjAsZmlyc3RCYXRjaDpudWxsLG5leHRTY2hlZHVsZWRSb290Om51bGx9LHQuc3RhdGVOb2RlPWV9ZnVuY3Rpb24genQoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3RyeXtyZXR1cm4gZSh0KX1jYXRjaChlKXt9fX1mdW5jdGlvbiBHdChlKXtpZigidW5kZWZpbmVkIj09PXR5cGVvZiBfX1JFQUNUX0RFVlRPT0xTX0dMT0JBTF9IT09LX18pcmV0dXJuITE7dmFyIHQ9X19SRUFDVF9ERVZUT09MU19HTE9CQUxfSE9PS19fO2lmKHQuaXNEaXNhYmxlZHx8IXQuc3VwcG9ydHNGaWJlcilyZXR1cm4hMDt0cnl7dmFyIG49dC5pbmplY3QoZSk7d2E9enQoZnVuY3Rpb24oZSl7cmV0dXJuIHQub25Db21taXRGaWJlclJvb3QobixlKX0pLFNhPXp0KGZ1bmN0aW9uKGUpe3JldHVybiB0Lm9uQ29tbWl0RmliZXJVbm1vdW50KG4sZSl9KX1jYXRjaChlKXt9cmV0dXJuITB9ZnVuY3Rpb24gVnQoZSl7ImZ1bmN0aW9uIj09PXR5cGVvZiB3YSYmd2EoZSl9ZnVuY3Rpb24gcXQoZSl7ImZ1bmN0aW9uIj09PXR5cGVvZiBTYSYmU2EoZSl9ZnVuY3Rpb24gSHQoZSl7cmV0dXJue2V4cGlyYXRpb25UaW1lOjAsYmFzZVN0YXRlOmUsZmlyc3RVcGRhdGU6bnVsbCxsYXN0VXBkYXRlOm51bGwsZmlyc3RDYXB0dXJlZFVwZGF0ZTpudWxsLGxhc3RDYXB0dXJlZFVwZGF0ZTpudWxsLGZpcnN0RWZmZWN0Om51bGwsbGFzdEVmZmVjdDpudWxsLGZpcnN0Q2FwdHVyZWRFZmZlY3Q6bnVsbCxsYXN0Q2FwdHVyZWRFZmZlY3Q6bnVsbH19ZnVuY3Rpb24gV3QoZSl7cmV0dXJue2V4cGlyYXRpb25UaW1lOmUuZXhwaXJhdGlvblRpbWUsYmFzZVN0YXRlOmUuYmFzZVN0YXRlLGZpcnN0VXBkYXRlOmUuZmlyc3RVcGRhdGUsbGFzdFVwZGF0ZTplLmxhc3RVcGRhdGUsZmlyc3RDYXB0dXJlZFVwZGF0ZTpudWxsLGxhc3RDYXB0dXJlZFVwZGF0ZTpudWxsLGZpcnN0RWZmZWN0Om51bGwsbGFzdEVmZmVjdDpudWxsLGZpcnN0Q2FwdHVyZWRFZmZlY3Q6bnVsbCxsYXN0Q2FwdHVyZWRFZmZlY3Q6bnVsbH19ZnVuY3Rpb24gUXQoZSl7cmV0dXJue2V4cGlyYXRpb25UaW1lOmUsdGFnOjAscGF5bG9hZDpudWxsLGNhbGxiYWNrOm51bGwsbmV4dDpudWxsLG5leHRFZmZlY3Q6bnVsbH19ZnVuY3Rpb24gS3QoZSx0LG4pe251bGw9PT1lLmxhc3RVcGRhdGU/ZS5maXJzdFVwZGF0ZT1lLmxhc3RVcGRhdGU9dDooZS5sYXN0VXBkYXRlLm5leHQ9dCxlLmxhc3RVcGRhdGU9dCksKDA9PT1lLmV4cGlyYXRpb25UaW1lfHxlLmV4cGlyYXRpb25UaW1lPm4pJiYoZS5leHBpcmF0aW9uVGltZT1uKX1mdW5jdGlvbiBKdChlLHQsbil7dmFyIHI9ZS5hbHRlcm5hdGU7aWYobnVsbD09PXIpe3ZhciBpPWUudXBkYXRlUXVldWUsbz1udWxsO251bGw9PT1pJiYoaT1lLnVwZGF0ZVF1ZXVlPUh0KGUubWVtb2l6ZWRTdGF0ZSkpfWVsc2UgaT1lLnVwZGF0ZVF1ZXVlLG89ci51cGRhdGVRdWV1ZSxudWxsPT09aT9udWxsPT09bz8oaT1lLnVwZGF0ZVF1ZXVlPUh0KGUubWVtb2l6ZWRTdGF0ZSksbz1yLnVwZGF0ZVF1ZXVlPUh0KHIubWVtb2l6ZWRTdGF0ZSkpOmk9ZS51cGRhdGVRdWV1ZT1XdChvKTpudWxsPT09byYmKG89ci51cGRhdGVRdWV1ZT1XdChpKSk7bnVsbD09PW98fGk9PT1vP0t0KGksdCxuKTpudWxsPT09aS5sYXN0VXBkYXRlfHxudWxsPT09by5sYXN0VXBkYXRlPyhLdChpLHQsbiksS3Qobyx0LG4pKTooS3QoaSx0LG4pLG8ubGFzdFVwZGF0ZT10KX1mdW5jdGlvbiBZdChlLHQsbil7dmFyIHI9ZS51cGRhdGVRdWV1ZTtyPW51bGw9PT1yP2UudXBkYXRlUXVldWU9SHQoZS5tZW1vaXplZFN0YXRlKTpYdChlLHIpLG51bGw9PT1yLmxhc3RDYXB0dXJlZFVwZGF0ZT9yLmZpcnN0Q2FwdHVyZWRVcGRhdGU9ci5sYXN0Q2FwdHVyZWRVcGRhdGU9dDooci5sYXN0Q2FwdHVyZWRVcGRhdGUubmV4dD10LHIubGFzdENhcHR1cmVkVXBkYXRlPXQpLCgwPT09ci5leHBpcmF0aW9uVGltZXx8ci5leHBpcmF0aW9uVGltZT5uKSYmKHIuZXhwaXJhdGlvblRpbWU9bil9ZnVuY3Rpb24gWHQoZSx0KXt2YXIgbj1lLmFsdGVybmF0ZTtyZXR1cm4gbnVsbCE9PW4mJnQ9PT1uLnVwZGF0ZVF1ZXVlJiYodD1lLnVwZGF0ZVF1ZXVlPVd0KHQpKSx0fWZ1bmN0aW9uIFp0KGUsdCxuLHIsaSxvKXtzd2l0Y2gobi50YWcpe2Nhc2UgMTpyZXR1cm4gZT1uLnBheWxvYWQsImZ1bmN0aW9uIj09PXR5cGVvZiBlP2UuY2FsbChvLHIsaSk6ZTtjYXNlIDM6ZS5lZmZlY3RUYWc9LTEwMjUmZS5lZmZlY3RUYWd8NjQ7Y2FzZSAwOmlmKGU9bi5wYXlsb2FkLG51bGw9PT0oaT0iZnVuY3Rpb24iPT09dHlwZW9mIGU/ZS5jYWxsKG8scixpKTplKXx8dm9pZCAwPT09aSlicmVhaztyZXR1cm4gTXIoe30scixpKTtjYXNlIDI6a2E9ITB9cmV0dXJuIHJ9ZnVuY3Rpb24gZW4oZSx0LG4scixpKXtpZihrYT0hMSwhKDA9PT10LmV4cGlyYXRpb25UaW1lfHx0LmV4cGlyYXRpb25UaW1lPmkpKXt0PVh0KGUsdCk7Zm9yKHZhciBvPXQuYmFzZVN0YXRlLGE9bnVsbCxzPTAsdT10LmZpcnN0VXBkYXRlLGM9bztudWxsIT09dTspe3ZhciBsPXUuZXhwaXJhdGlvblRpbWU7bD5pPyhudWxsPT09YSYmKGE9dSxvPWMpLCgwPT09c3x8cz5sKSYmKHM9bCkpOihjPVp0KGUsdCx1LGMsbixyKSxudWxsIT09dS5jYWxsYmFjayYmKGUuZWZmZWN0VGFnfD0zMix1Lm5leHRFZmZlY3Q9bnVsbCxudWxsPT09dC5sYXN0RWZmZWN0P3QuZmlyc3RFZmZlY3Q9dC5sYXN0RWZmZWN0PXU6KHQubGFzdEVmZmVjdC5uZXh0RWZmZWN0PXUsdC5sYXN0RWZmZWN0PXUpKSksdT11Lm5leHR9Zm9yKGw9bnVsbCx1PXQuZmlyc3RDYXB0dXJlZFVwZGF0ZTtudWxsIT09dTspe3ZhciBwPXUuZXhwaXJhdGlvblRpbWU7cD5pPyhudWxsPT09bCYmKGw9dSxudWxsPT09YSYmKG89YykpLCgwPT09c3x8cz5wKSYmKHM9cCkpOihjPVp0KGUsdCx1LGMsbixyKSxudWxsIT09dS5jYWxsYmFjayYmKGUuZWZmZWN0VGFnfD0zMix1Lm5leHRFZmZlY3Q9bnVsbCxudWxsPT09dC5sYXN0Q2FwdHVyZWRFZmZlY3Q/dC5maXJzdENhcHR1cmVkRWZmZWN0PXQubGFzdENhcHR1cmVkRWZmZWN0PXU6KHQubGFzdENhcHR1cmVkRWZmZWN0Lm5leHRFZmZlY3Q9dSx0Lmxhc3RDYXB0dXJlZEVmZmVjdD11KSkpLHU9dS5uZXh0fW51bGw9PT1hJiYodC5sYXN0VXBkYXRlPW51bGwpLG51bGw9PT1sP3QubGFzdENhcHR1cmVkVXBkYXRlPW51bGw6ZS5lZmZlY3RUYWd8PTMyLG51bGw9PT1hJiZudWxsPT09bCYmKG89YyksdC5iYXNlU3RhdGU9byx0LmZpcnN0VXBkYXRlPWEsdC5maXJzdENhcHR1cmVkVXBkYXRlPWwsdC5leHBpcmF0aW9uVGltZT1zLGUubWVtb2l6ZWRTdGF0ZT1jfX1mdW5jdGlvbiB0bihlLHQpeyJmdW5jdGlvbiIhPT10eXBlb2YgZSYmcigiMTkxIixlKSxlLmNhbGwodCl9ZnVuY3Rpb24gbm4oZSx0LG4pe2ZvcihudWxsIT09dC5maXJzdENhcHR1cmVkVXBkYXRlJiYobnVsbCE9PXQubGFzdFVwZGF0ZSYmKHQubGFzdFVwZGF0ZS5uZXh0PXQuZmlyc3RDYXB0dXJlZFVwZGF0ZSx0Lmxhc3RVcGRhdGU9dC5sYXN0Q2FwdHVyZWRVcGRhdGUpLHQuZmlyc3RDYXB0dXJlZFVwZGF0ZT10Lmxhc3RDYXB0dXJlZFVwZGF0ZT1udWxsKSxlPXQuZmlyc3RFZmZlY3QsdC5maXJzdEVmZmVjdD10Lmxhc3RFZmZlY3Q9bnVsbDtudWxsIT09ZTspe3ZhciByPWUuY2FsbGJhY2s7bnVsbCE9PXImJihlLmNhbGxiYWNrPW51bGwsdG4ocixuKSksZT1lLm5leHRFZmZlY3R9Zm9yKGU9dC5maXJzdENhcHR1cmVkRWZmZWN0LHQuZmlyc3RDYXB0dXJlZEVmZmVjdD10Lmxhc3RDYXB0dXJlZEVmZmVjdD1udWxsO251bGwhPT1lOyl0PWUuY2FsbGJhY2ssbnVsbCE9PXQmJihlLmNhbGxiYWNrPW51bGwsdG4odCxuKSksZT1lLm5leHRFZmZlY3R9ZnVuY3Rpb24gcm4oZSx0KXtyZXR1cm57dmFsdWU6ZSxzb3VyY2U6dCxzdGFjazpzZSh0KX19ZnVuY3Rpb24gb24oZSl7dmFyIHQ9ZS50eXBlLl9jb250ZXh0O1N0KFRhLHQuX2NoYW5nZWRCaXRzLGUpLFN0KF9hLHQuX2N1cnJlbnRWYWx1ZSxlKSxTdChBYSxlLGUpLHQuX2N1cnJlbnRWYWx1ZT1lLnBlbmRpbmdQcm9wcy52YWx1ZSx0Ll9jaGFuZ2VkQml0cz1lLnN0YXRlTm9kZX1mdW5jdGlvbiBhbihlKXt2YXIgdD1UYS5jdXJyZW50LG49X2EuY3VycmVudDt3dChBYSxlKSx3dChfYSxlKSx3dChUYSxlKSxlPWUudHlwZS5fY29udGV4dCxlLl9jdXJyZW50VmFsdWU9bixlLl9jaGFuZ2VkQml0cz10fWZ1bmN0aW9uIHNuKGUpe3JldHVybiBlPT09T2EmJnIoIjE3NCIpLGV9ZnVuY3Rpb24gdW4oZSx0KXtTdChJYSx0LGUpLFN0KE5hLGUsZSksU3QoRmEsT2EsZSk7dmFyIG49dC5ub2RlVHlwZTtzd2l0Y2gobil7Y2FzZSA5OmNhc2UgMTE6dD0odD10LmRvY3VtZW50RWxlbWVudCk/dC5uYW1lc3BhY2VVUkk6YXQobnVsbCwiIik7YnJlYWs7ZGVmYXVsdDpuPTg9PT1uP3QucGFyZW50Tm9kZTp0LHQ9bi5uYW1lc3BhY2VVUkl8fG51bGwsbj1uLnRhZ05hbWUsdD1hdCh0LG4pfXd0KEZhLGUpLFN0KEZhLHQsZSl9ZnVuY3Rpb24gY24oZSl7d3QoRmEsZSksd3QoTmEsZSksd3QoSWEsZSl9ZnVuY3Rpb24gbG4oZSl7TmEuY3VycmVudD09PWUmJih3dChGYSxlKSx3dChOYSxlKSl9ZnVuY3Rpb24gcG4oZSx0LG4pe3ZhciByPWUubWVtb2l6ZWRTdGF0ZTt0PXQobixyKSxyPW51bGw9PT10fHx2b2lkIDA9PT10P3I6TXIoe30scix0KSxlLm1lbW9pemVkU3RhdGU9cixudWxsIT09KGU9ZS51cGRhdGVRdWV1ZSkmJjA9PT1lLmV4cGlyYXRpb25UaW1lJiYoZS5iYXNlU3RhdGU9cil9ZnVuY3Rpb24gZm4oZSx0LG4scixpLG8pe3ZhciBhPWUuc3RhdGVOb2RlO3JldHVybiBlPWUudHlwZSwiZnVuY3Rpb24iPT09dHlwZW9mIGEuc2hvdWxkQ29tcG9uZW50VXBkYXRlP2Euc2hvdWxkQ29tcG9uZW50VXBkYXRlKG4saSxvKTohZS5wcm90b3R5cGV8fCFlLnByb3RvdHlwZS5pc1B1cmVSZWFjdENvbXBvbmVudHx8KCFCcih0LG4pfHwhQnIocixpKSl9ZnVuY3Rpb24gZG4oZSx0LG4scil7ZT10LnN0YXRlLCJmdW5jdGlvbiI9PT10eXBlb2YgdC5jb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzJiZ0LmNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHMobixyKSwiZnVuY3Rpb24iPT09dHlwZW9mIHQuVU5TQUZFX2NvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHMmJnQuVU5TQUZFX2NvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHMobixyKSx0LnN0YXRlIT09ZSYmTGEuZW5xdWV1ZVJlcGxhY2VTdGF0ZSh0LHQuc3RhdGUsbnVsbCl9ZnVuY3Rpb24gaG4oZSx0KXt2YXIgbj1lLnR5cGUscj1lLnN0YXRlTm9kZSxpPWUucGVuZGluZ1Byb3BzLG89a3QoZSk7ci5wcm9wcz1pLHIuc3RhdGU9ZS5tZW1vaXplZFN0YXRlLHIucmVmcz1VcixyLmNvbnRleHQ9QXQoZSxvKSxvPWUudXBkYXRlUXVldWUsbnVsbCE9PW8mJihlbihlLG8saSxyLHQpLHIuc3RhdGU9ZS5tZW1vaXplZFN0YXRlKSxvPWUudHlwZS5nZXREZXJpdmVkU3RhdGVGcm9tUHJvcHMsImZ1bmN0aW9uIj09PXR5cGVvZiBvJiYocG4oZSxvLGkpLHIuc3RhdGU9ZS5tZW1vaXplZFN0YXRlKSwiZnVuY3Rpb24iPT09dHlwZW9mIG4uZ2V0RGVyaXZlZFN0YXRlRnJvbVByb3BzfHwiZnVuY3Rpb24iPT09dHlwZW9mIHIuZ2V0U25hcHNob3RCZWZvcmVVcGRhdGV8fCJmdW5jdGlvbiIhPT10eXBlb2Ygci5VTlNBRkVfY29tcG9uZW50V2lsbE1vdW50JiYiZnVuY3Rpb24iIT09dHlwZW9mIHIuY29tcG9uZW50V2lsbE1vdW50fHwobj1yLnN0YXRlLCJmdW5jdGlvbiI9PT10eXBlb2Ygci5jb21wb25lbnRXaWxsTW91bnQmJnIuY29tcG9uZW50V2lsbE1vdW50KCksImZ1bmN0aW9uIj09PXR5cGVvZiByLlVOU0FGRV9jb21wb25lbnRXaWxsTW91bnQmJnIuVU5TQUZFX2NvbXBvbmVudFdpbGxNb3VudCgpLG4hPT1yLnN0YXRlJiZMYS5lbnF1ZXVlUmVwbGFjZVN0YXRlKHIsci5zdGF0ZSxudWxsKSxudWxsIT09KG89ZS51cGRhdGVRdWV1ZSkmJihlbihlLG8saSxyLHQpLHIuc3RhdGU9ZS5tZW1vaXplZFN0YXRlKSksImZ1bmN0aW9uIj09PXR5cGVvZiByLmNvbXBvbmVudERpZE1vdW50JiYoZS5lZmZlY3RUYWd8PTQpfWZ1bmN0aW9uIG1uKGUsdCxuKXtpZihudWxsIT09KGU9bi5yZWYpJiYiZnVuY3Rpb24iIT09dHlwZW9mIGUmJiJvYmplY3QiIT09dHlwZW9mIGUpe2lmKG4uX293bmVyKXtuPW4uX293bmVyO3ZhciBpPXZvaWQgMDtuJiYoMiE9PW4udGFnJiZyKCIxMTAiKSxpPW4uc3RhdGVOb2RlKSxpfHxyKCIxNDciLGUpO3ZhciBvPSIiK2U7cmV0dXJuIG51bGwhPT10JiZudWxsIT09dC5yZWYmJiJmdW5jdGlvbiI9PT10eXBlb2YgdC5yZWYmJnQucmVmLl9zdHJpbmdSZWY9PT1vP3QucmVmOih0PWZ1bmN0aW9uKGUpe3ZhciB0PWkucmVmcz09PVVyP2kucmVmcz17fTppLnJlZnM7bnVsbD09PWU/ZGVsZXRlIHRbb106dFtvXT1lfSx0Ll9zdHJpbmdSZWY9byx0KX0ic3RyaW5nIiE9PXR5cGVvZiBlJiZyKCIxNDgiKSxuLl9vd25lcnx8cigiMjU0IixlKX1yZXR1cm4gZX1mdW5jdGlvbiBnbihlLHQpeyJ0ZXh0YXJlYSIhPT1lLnR5cGUmJnIoIjMxIiwiW29iamVjdCBPYmplY3RdIj09PU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh0KT8ib2JqZWN0IHdpdGgga2V5cyB7IitPYmplY3Qua2V5cyh0KS5qb2luKCIsICIpKyJ9Ijp0LCIiKX1mdW5jdGlvbiB5bihlKXtmdW5jdGlvbiB0KHQsbil7aWYoZSl7dmFyIHI9dC5sYXN0RWZmZWN0O251bGwhPT1yPyhyLm5leHRFZmZlY3Q9bix0Lmxhc3RFZmZlY3Q9bik6dC5maXJzdEVmZmVjdD10Lmxhc3RFZmZlY3Q9bixuLm5leHRFZmZlY3Q9bnVsbCxuLmVmZmVjdFRhZz04fX1mdW5jdGlvbiBuKG4scil7aWYoIWUpcmV0dXJuIG51bGw7Zm9yKDtudWxsIT09cjspdChuLHIpLHI9ci5zaWJsaW5nO3JldHVybiBudWxsfWZ1bmN0aW9uIGkoZSx0KXtmb3IoZT1uZXcgTWFwO251bGwhPT10OyludWxsIT09dC5rZXk/ZS5zZXQodC5rZXksdCk6ZS5zZXQodC5pbmRleCx0KSx0PXQuc2libGluZztyZXR1cm4gZX1mdW5jdGlvbiBvKGUsdCxuKXtyZXR1cm4gZT1NdChlLHQsbiksZS5pbmRleD0wLGUuc2libGluZz1udWxsLGV9ZnVuY3Rpb24gYSh0LG4scil7cmV0dXJuIHQuaW5kZXg9cixlP251bGwhPT0ocj10LmFsdGVybmF0ZSk/KHI9ci5pbmRleCxyPG4/KHQuZWZmZWN0VGFnPTIsbik6cik6KHQuZWZmZWN0VGFnPTIsbik6bn1mdW5jdGlvbiBzKHQpe3JldHVybiBlJiZudWxsPT09dC5hbHRlcm5hdGUmJih0LmVmZmVjdFRhZz0yKSx0fWZ1bmN0aW9uIHUoZSx0LG4scil7cmV0dXJuIG51bGw9PT10fHw2IT09dC50YWc/KHQ9QnQobixlLm1vZGUsciksdC5yZXR1cm49ZSx0KToodD1vKHQsbixyKSx0LnJldHVybj1lLHQpfWZ1bmN0aW9uIGMoZSx0LG4scil7cmV0dXJuIG51bGwhPT10JiZ0LnR5cGU9PT1uLnR5cGU/KHI9byh0LG4ucHJvcHMsciksci5yZWY9bW4oZSx0LG4pLHIucmV0dXJuPWUscik6KHI9anQobixlLm1vZGUsciksci5yZWY9bW4oZSx0LG4pLHIucmV0dXJuPWUscil9ZnVuY3Rpb24gbChlLHQsbixyKXtyZXR1cm4gbnVsbD09PXR8fDQhPT10LnRhZ3x8dC5zdGF0ZU5vZGUuY29udGFpbmVySW5mbyE9PW4uY29udGFpbmVySW5mb3x8dC5zdGF0ZU5vZGUuaW1wbGVtZW50YXRpb24hPT1uLmltcGxlbWVudGF0aW9uPyh0PSR0KG4sZS5tb2RlLHIpLHQucmV0dXJuPWUsdCk6KHQ9byh0LG4uY2hpbGRyZW58fFtdLHIpLHQucmV0dXJuPWUsdCl9ZnVuY3Rpb24gcChlLHQsbixyLGkpe3JldHVybiBudWxsPT09dHx8MTAhPT10LnRhZz8odD1SdChuLGUubW9kZSxyLGkpLHQucmV0dXJuPWUsdCk6KHQ9byh0LG4sciksdC5yZXR1cm49ZSx0KX1mdW5jdGlvbiBmKGUsdCxuKXtpZigic3RyaW5nIj09PXR5cGVvZiB0fHwibnVtYmVyIj09PXR5cGVvZiB0KXJldHVybiB0PUJ0KCIiK3QsZS5tb2RlLG4pLHQucmV0dXJuPWUsdDtpZigib2JqZWN0Ij09PXR5cGVvZiB0JiZudWxsIT09dCl7c3dpdGNoKHQuJCR0eXBlb2Ype2Nhc2UgJGk6cmV0dXJuIG49anQodCxlLm1vZGUsbiksbi5yZWY9bW4oZSxudWxsLHQpLG4ucmV0dXJuPWUsbjtjYXNlIFVpOnJldHVybiB0PSR0KHQsZS5tb2RlLG4pLHQucmV0dXJuPWUsdH1pZihQYSh0KXx8b2UodCkpcmV0dXJuIHQ9UnQodCxlLm1vZGUsbixudWxsKSx0LnJldHVybj1lLHQ7Z24oZSx0KX1yZXR1cm4gbnVsbH1mdW5jdGlvbiBkKGUsdCxuLHIpe3ZhciBpPW51bGwhPT10P3Qua2V5Om51bGw7aWYoInN0cmluZyI9PT10eXBlb2Ygbnx8Im51bWJlciI9PT10eXBlb2YgbilyZXR1cm4gbnVsbCE9PWk/bnVsbDp1KGUsdCwiIituLHIpO2lmKCJvYmplY3QiPT09dHlwZW9mIG4mJm51bGwhPT1uKXtzd2l0Y2gobi4kJHR5cGVvZil7Y2FzZSAkaTpyZXR1cm4gbi5rZXk9PT1pP24udHlwZT09PXppP3AoZSx0LG4ucHJvcHMuY2hpbGRyZW4scixpKTpjKGUsdCxuLHIpOm51bGw7Y2FzZSBVaTpyZXR1cm4gbi5rZXk9PT1pP2woZSx0LG4scik6bnVsbH1pZihQYShuKXx8b2UobikpcmV0dXJuIG51bGwhPT1pP251bGw6cChlLHQsbixyLG51bGwpO2duKGUsbil9cmV0dXJuIG51bGx9ZnVuY3Rpb24gaChlLHQsbixyLGkpe2lmKCJzdHJpbmciPT09dHlwZW9mIHJ8fCJudW1iZXIiPT09dHlwZW9mIHIpcmV0dXJuIGU9ZS5nZXQobil8fG51bGwsdSh0LGUsIiIrcixpKTtpZigib2JqZWN0Ij09PXR5cGVvZiByJiZudWxsIT09cil7c3dpdGNoKHIuJCR0eXBlb2Ype2Nhc2UgJGk6cmV0dXJuIGU9ZS5nZXQobnVsbD09PXIua2V5P246ci5rZXkpfHxudWxsLHIudHlwZT09PXppP3AodCxlLHIucHJvcHMuY2hpbGRyZW4saSxyLmtleSk6Yyh0LGUscixpKTtjYXNlIFVpOnJldHVybiBlPWUuZ2V0KG51bGw9PT1yLmtleT9uOnIua2V5KXx8bnVsbCxsKHQsZSxyLGkpfWlmKFBhKHIpfHxvZShyKSlyZXR1cm4gZT1lLmdldChuKXx8bnVsbCxwKHQsZSxyLGksbnVsbCk7Z24odCxyKX1yZXR1cm4gbnVsbH1mdW5jdGlvbiBtKHIsbyxzLHUpe2Zvcih2YXIgYz1udWxsLGw9bnVsbCxwPW8sbT1vPTAsZz1udWxsO251bGwhPT1wJiZtPHMubGVuZ3RoO20rKyl7cC5pbmRleD5tPyhnPXAscD1udWxsKTpnPXAuc2libGluZzt2YXIgeT1kKHIscCxzW21dLHUpO2lmKG51bGw9PT15KXtudWxsPT09cCYmKHA9Zyk7YnJlYWt9ZSYmcCYmbnVsbD09PXkuYWx0ZXJuYXRlJiZ0KHIscCksbz1hKHksbyxtKSxudWxsPT09bD9jPXk6bC5zaWJsaW5nPXksbD15LHA9Z31pZihtPT09cy5sZW5ndGgpcmV0dXJuIG4ocixwKSxjO2lmKG51bGw9PT1wKXtmb3IoO208cy5sZW5ndGg7bSsrKShwPWYocixzW21dLHUpKSYmKG89YShwLG8sbSksbnVsbD09PWw/Yz1wOmwuc2libGluZz1wLGw9cCk7cmV0dXJuIGN9Zm9yKHA9aShyLHApO208cy5sZW5ndGg7bSsrKShnPWgocCxyLG0sc1ttXSx1KSkmJihlJiZudWxsIT09Zy5hbHRlcm5hdGUmJnAuZGVsZXRlKG51bGw9PT1nLmtleT9tOmcua2V5KSxvPWEoZyxvLG0pLG51bGw9PT1sP2M9ZzpsLnNpYmxpbmc9ZyxsPWcpO3JldHVybiBlJiZwLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIHQocixlKX0pLGN9ZnVuY3Rpb24gZyhvLHMsdSxjKXt2YXIgbD1vZSh1KTsiZnVuY3Rpb24iIT09dHlwZW9mIGwmJnIoIjE1MCIpLG51bGw9PSh1PWwuY2FsbCh1KSkmJnIoIjE1MSIpO2Zvcih2YXIgcD1sPW51bGwsbT1zLGc9cz0wLHk9bnVsbCx2PXUubmV4dCgpO251bGwhPT1tJiYhdi5kb25lO2crKyx2PXUubmV4dCgpKXttLmluZGV4Pmc/KHk9bSxtPW51bGwpOnk9bS5zaWJsaW5nO3ZhciBiPWQobyxtLHYudmFsdWUsYyk7aWYobnVsbD09PWIpe218fChtPXkpO2JyZWFrfWUmJm0mJm51bGw9PT1iLmFsdGVybmF0ZSYmdChvLG0pLHM9YShiLHMsZyksbnVsbD09PXA/bD1iOnAuc2libGluZz1iLHA9YixtPXl9aWYodi5kb25lKXJldHVybiBuKG8sbSksbDtpZihudWxsPT09bSl7Zm9yKDshdi5kb25lO2crKyx2PXUubmV4dCgpKW51bGwhPT0odj1mKG8sdi52YWx1ZSxjKSkmJihzPWEodixzLGcpLG51bGw9PT1wP2w9djpwLnNpYmxpbmc9dixwPXYpO3JldHVybiBsfWZvcihtPWkobyxtKTshdi5kb25lO2crKyx2PXUubmV4dCgpKW51bGwhPT0odj1oKG0sbyxnLHYudmFsdWUsYykpJiYoZSYmbnVsbCE9PXYuYWx0ZXJuYXRlJiZtLmRlbGV0ZShudWxsPT09di5rZXk/Zzp2LmtleSkscz1hKHYscyxnKSxudWxsPT09cD9sPXY6cC5zaWJsaW5nPXYscD12KTtyZXR1cm4gZSYmbS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiB0KG8sZSl9KSxsfXJldHVybiBmdW5jdGlvbihlLGksYSx1KXsib2JqZWN0Ij09PXR5cGVvZiBhJiZudWxsIT09YSYmYS50eXBlPT09emkmJm51bGw9PT1hLmtleSYmKGE9YS5wcm9wcy5jaGlsZHJlbik7dmFyIGM9Im9iamVjdCI9PT10eXBlb2YgYSYmbnVsbCE9PWE7aWYoYylzd2l0Y2goYS4kJHR5cGVvZil7Y2FzZSAkaTplOnt2YXIgbD1hLmtleTtmb3IoYz1pO251bGwhPT1jOyl7aWYoYy5rZXk9PT1sKXtpZigxMD09PWMudGFnP2EudHlwZT09PXppOmMudHlwZT09PWEudHlwZSl7bihlLGMuc2libGluZyksaT1vKGMsYS50eXBlPT09emk/YS5wcm9wcy5jaGlsZHJlbjphLnByb3BzLHUpLGkucmVmPW1uKGUsYyxhKSxpLnJldHVybj1lLGU9aTticmVhayBlfW4oZSxjKTticmVha310KGUsYyksYz1jLnNpYmxpbmd9YS50eXBlPT09emk/KGk9UnQoYS5wcm9wcy5jaGlsZHJlbixlLm1vZGUsdSxhLmtleSksaS5yZXR1cm49ZSxlPWkpOih1PWp0KGEsZS5tb2RlLHUpLHUucmVmPW1uKGUsaSxhKSx1LnJldHVybj1lLGU9dSl9cmV0dXJuIHMoZSk7Y2FzZSBVaTplOntmb3IoYz1hLmtleTtudWxsIT09aTspe2lmKGkua2V5PT09Yyl7aWYoND09PWkudGFnJiZpLnN0YXRlTm9kZS5jb250YWluZXJJbmZvPT09YS5jb250YWluZXJJbmZvJiZpLnN0YXRlTm9kZS5pbXBsZW1lbnRhdGlvbj09PWEuaW1wbGVtZW50YXRpb24pe24oZSxpLnNpYmxpbmcpLGk9byhpLGEuY2hpbGRyZW58fFtdLHUpLGkucmV0dXJuPWUsZT1pO2JyZWFrIGV9bihlLGkpO2JyZWFrfXQoZSxpKSxpPWkuc2libGluZ31pPSR0KGEsZS5tb2RlLHUpLGkucmV0dXJuPWUsZT1pfXJldHVybiBzKGUpfWlmKCJzdHJpbmciPT09dHlwZW9mIGF8fCJudW1iZXIiPT09dHlwZW9mIGEpcmV0dXJuIGE9IiIrYSxudWxsIT09aSYmNj09PWkudGFnPyhuKGUsaS5zaWJsaW5nKSxpPW8oaSxhLHUpLGkucmV0dXJuPWUsZT1pKToobihlLGkpLGk9QnQoYSxlLm1vZGUsdSksaS5yZXR1cm49ZSxlPWkpLHMoZSk7aWYoUGEoYSkpcmV0dXJuIG0oZSxpLGEsdSk7aWYob2UoYSkpcmV0dXJuIGcoZSxpLGEsdSk7aWYoYyYmZ24oZSxhKSwidW5kZWZpbmVkIj09PXR5cGVvZiBhKXN3aXRjaChlLnRhZyl7Y2FzZSAyOmNhc2UgMTp1PWUudHlwZSxyKCIxNTIiLHUuZGlzcGxheU5hbWV8fHUubmFtZXx8IkNvbXBvbmVudCIpfXJldHVybiBuKGUsaSl9fWZ1bmN0aW9uIHZuKGUsdCl7dmFyIG49bmV3IFB0KDUsbnVsbCxudWxsLDApO24udHlwZT0iREVMRVRFRCIsbi5zdGF0ZU5vZGU9dCxuLnJldHVybj1lLG4uZWZmZWN0VGFnPTgsbnVsbCE9PWUubGFzdEVmZmVjdD8oZS5sYXN0RWZmZWN0Lm5leHRFZmZlY3Q9bixlLmxhc3RFZmZlY3Q9bik6ZS5maXJzdEVmZmVjdD1lLmxhc3RFZmZlY3Q9bn1mdW5jdGlvbiBibihlLHQpe3N3aXRjaChlLnRhZyl7Y2FzZSA1OnZhciBuPWUudHlwZTtyZXR1cm4gbnVsbCE9PSh0PTEhPT10Lm5vZGVUeXBlfHxuLnRvTG93ZXJDYXNlKCkhPT10Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk/bnVsbDp0KSYmKGUuc3RhdGVOb2RlPXQsITApO2Nhc2UgNjpyZXR1cm4gbnVsbCE9PSh0PSIiPT09ZS5wZW5kaW5nUHJvcHN8fDMhPT10Lm5vZGVUeXBlP251bGw6dCkmJihlLnN0YXRlTm9kZT10LCEwKTtkZWZhdWx0OnJldHVybiExfX1mdW5jdGlvbiB4bihlKXtpZigkYSl7dmFyIHQ9QmE7aWYodCl7dmFyIG49dDtpZighYm4oZSx0KSl7aWYoISh0PUN0KG4pKXx8IWJuKGUsdCkpcmV0dXJuIGUuZWZmZWN0VGFnfD0yLCRhPSExLHZvaWQoUmE9ZSk7dm4oUmEsbil9UmE9ZSxCYT1FdCh0KX1lbHNlIGUuZWZmZWN0VGFnfD0yLCRhPSExLFJhPWV9fWZ1bmN0aW9uIENuKGUpe2ZvcihlPWUucmV0dXJuO251bGwhPT1lJiY1IT09ZS50YWcmJjMhPT1lLnRhZzspZT1lLnJldHVybjtSYT1lfWZ1bmN0aW9uIEVuKGUpe2lmKGUhPT1SYSlyZXR1cm4hMTtpZighJGEpcmV0dXJuIENuKGUpLCRhPSEwLCExO3ZhciB0PWUudHlwZTtpZig1IT09ZS50YWd8fCJoZWFkIiE9PXQmJiJib2R5IiE9PXQmJiF4dCh0LGUubWVtb2l6ZWRQcm9wcykpZm9yKHQ9QmE7dDspdm4oZSx0KSx0PUN0KHQpO3JldHVybiBDbihlKSxCYT1SYT9DdChlLnN0YXRlTm9kZSk6bnVsbCwhMH1mdW5jdGlvbiBEbigpe0JhPVJhPW51bGwsJGE9ITF9ZnVuY3Rpb24gd24oZSx0LG4pe1NuKGUsdCxuLHQuZXhwaXJhdGlvblRpbWUpfWZ1bmN0aW9uIFNuKGUsdCxuLHIpe3QuY2hpbGQ9bnVsbD09PWU/amEodCxudWxsLG4scik6TWEodCxlLmNoaWxkLG4scil9ZnVuY3Rpb24ga24oZSx0KXt2YXIgbj10LnJlZjsobnVsbD09PWUmJm51bGwhPT1ufHxudWxsIT09ZSYmZS5yZWYhPT1uKSYmKHQuZWZmZWN0VGFnfD0xMjgpfWZ1bmN0aW9uIEFuKGUsdCxuLHIsaSl7a24oZSx0KTt2YXIgbz0wIT09KDY0JnQuZWZmZWN0VGFnKTtpZighbiYmIW8pcmV0dXJuIHImJkx0KHQsITEpLEZuKGUsdCk7bj10LnN0YXRlTm9kZSxSaS5jdXJyZW50PXQ7dmFyIGE9bz9udWxsOm4ucmVuZGVyKCk7cmV0dXJuIHQuZWZmZWN0VGFnfD0xLG8mJihTbihlLHQsbnVsbCxpKSx0LmNoaWxkPW51bGwpLFNuKGUsdCxhLGkpLHQubWVtb2l6ZWRTdGF0ZT1uLnN0YXRlLHQubWVtb2l6ZWRQcm9wcz1uLnByb3BzLHImJkx0KHQsITApLHQuY2hpbGR9ZnVuY3Rpb24gX24oZSl7dmFyIHQ9ZS5zdGF0ZU5vZGU7dC5wZW5kaW5nQ29udGV4dD9GdChlLHQucGVuZGluZ0NvbnRleHQsdC5wZW5kaW5nQ29udGV4dCE9PXQuY29udGV4dCk6dC5jb250ZXh0JiZGdChlLHQuY29udGV4dCwhMSksdW4oZSx0LmNvbnRhaW5lckluZm8pfWZ1bmN0aW9uIFRuKGUsdCxuLHIpe3ZhciBpPWUuY2hpbGQ7Zm9yKG51bGwhPT1pJiYoaS5yZXR1cm49ZSk7bnVsbCE9PWk7KXtzd2l0Y2goaS50YWcpe2Nhc2UgMTI6dmFyIG89MHxpLnN0YXRlTm9kZTtpZihpLnR5cGU9PT10JiYwIT09KG8mbikpe2ZvcihvPWk7bnVsbCE9PW87KXt2YXIgYT1vLmFsdGVybmF0ZTtpZigwPT09by5leHBpcmF0aW9uVGltZXx8by5leHBpcmF0aW9uVGltZT5yKW8uZXhwaXJhdGlvblRpbWU9cixudWxsIT09YSYmKDA9PT1hLmV4cGlyYXRpb25UaW1lfHxhLmV4cGlyYXRpb25UaW1lPnIpJiYoYS5leHBpcmF0aW9uVGltZT1yKTtlbHNle2lmKG51bGw9PT1hfHwhKDA9PT1hLmV4cGlyYXRpb25UaW1lfHxhLmV4cGlyYXRpb25UaW1lPnIpKWJyZWFrO2EuZXhwaXJhdGlvblRpbWU9cn1vPW8ucmV0dXJufW89bnVsbH1lbHNlIG89aS5jaGlsZDticmVhaztjYXNlIDEzOm89aS50eXBlPT09ZS50eXBlP251bGw6aS5jaGlsZDticmVhaztkZWZhdWx0Om89aS5jaGlsZH1pZihudWxsIT09bylvLnJldHVybj1pO2Vsc2UgZm9yKG89aTtudWxsIT09bzspe2lmKG89PT1lKXtvPW51bGw7YnJlYWt9aWYobnVsbCE9PShpPW8uc2libGluZykpe2kucmV0dXJuPW8ucmV0dXJuLG89aTticmVha31vPW8ucmV0dXJufWk9b319ZnVuY3Rpb24gT24oZSx0LG4pe3ZhciByPXQudHlwZS5fY29udGV4dCxpPXQucGVuZGluZ1Byb3BzLG89dC5tZW1vaXplZFByb3BzLGE9ITA7aWYoRWEuY3VycmVudClhPSExO2Vsc2UgaWYobz09PWkpcmV0dXJuIHQuc3RhdGVOb2RlPTAsb24odCksRm4oZSx0KTt2YXIgcz1pLnZhbHVlO2lmKHQubWVtb2l6ZWRQcm9wcz1pLG51bGw9PT1vKXM9MTA3Mzc0MTgyMztlbHNlIGlmKG8udmFsdWU9PT1pLnZhbHVlKXtpZihvLmNoaWxkcmVuPT09aS5jaGlsZHJlbiYmYSlyZXR1cm4gdC5zdGF0ZU5vZGU9MCxvbih0KSxGbihlLHQpO3M9MH1lbHNle3ZhciB1PW8udmFsdWU7aWYodT09PXMmJigwIT09dXx8MS91PT09MS9zKXx8dSE9PXUmJnMhPT1zKXtpZihvLmNoaWxkcmVuPT09aS5jaGlsZHJlbiYmYSlyZXR1cm4gdC5zdGF0ZU5vZGU9MCxvbih0KSxGbihlLHQpO3M9MH1lbHNlIGlmKHM9ImZ1bmN0aW9uIj09PXR5cGVvZiByLl9jYWxjdWxhdGVDaGFuZ2VkQml0cz9yLl9jYWxjdWxhdGVDaGFuZ2VkQml0cyh1LHMpOjEwNzM3NDE4MjMsMD09PShzfD0wKSl7aWYoby5jaGlsZHJlbj09PWkuY2hpbGRyZW4mJmEpcmV0dXJuIHQuc3RhdGVOb2RlPTAsb24odCksRm4oZSx0KX1lbHNlIFRuKHQscixzLG4pfXJldHVybiB0LnN0YXRlTm9kZT1zLG9uKHQpLHduKGUsdCxpLmNoaWxkcmVuKSx0LmNoaWxkfWZ1bmN0aW9uIEZuKGUsdCl7aWYobnVsbCE9PWUmJnQuY2hpbGQhPT1lLmNoaWxkJiZyKCIxNTMiKSxudWxsIT09dC5jaGlsZCl7ZT10LmNoaWxkO3ZhciBuPU10KGUsZS5wZW5kaW5nUHJvcHMsZS5leHBpcmF0aW9uVGltZSk7Zm9yKHQuY2hpbGQ9bixuLnJldHVybj10O251bGwhPT1lLnNpYmxpbmc7KWU9ZS5zaWJsaW5nLG49bi5zaWJsaW5nPU10KGUsZS5wZW5kaW5nUHJvcHMsZS5leHBpcmF0aW9uVGltZSksbi5yZXR1cm49dDtuLnNpYmxpbmc9bnVsbH1yZXR1cm4gdC5jaGlsZH1mdW5jdGlvbiBObihlLHQsbil7aWYoMD09PXQuZXhwaXJhdGlvblRpbWV8fHQuZXhwaXJhdGlvblRpbWU+bil7c3dpdGNoKHQudGFnKXtjYXNlIDM6X24odCk7YnJlYWs7Y2FzZSAyOkl0KHQpO2JyZWFrO2Nhc2UgNDp1bih0LHQuc3RhdGVOb2RlLmNvbnRhaW5lckluZm8pO2JyZWFrO2Nhc2UgMTM6b24odCl9cmV0dXJuIG51bGx9c3dpdGNoKHQudGFnKXtjYXNlIDA6bnVsbCE9PWUmJnIoIjE1NSIpO3ZhciBpPXQudHlwZSxvPXQucGVuZGluZ1Byb3BzLGE9a3QodCk7cmV0dXJuIGE9QXQodCxhKSxpPWkobyxhKSx0LmVmZmVjdFRhZ3w9MSwib2JqZWN0Ij09PXR5cGVvZiBpJiZudWxsIT09aSYmImZ1bmN0aW9uIj09PXR5cGVvZiBpLnJlbmRlciYmdm9pZCAwPT09aS4kJHR5cGVvZj8oYT10LnR5cGUsdC50YWc9Mix0Lm1lbW9pemVkU3RhdGU9bnVsbCE9PWkuc3RhdGUmJnZvaWQgMCE9PWkuc3RhdGU/aS5zdGF0ZTpudWxsLGE9YS5nZXREZXJpdmVkU3RhdGVGcm9tUHJvcHMsImZ1bmN0aW9uIj09PXR5cGVvZiBhJiZwbih0LGEsbyksbz1JdCh0KSxpLnVwZGF0ZXI9TGEsdC5zdGF0ZU5vZGU9aSxpLl9yZWFjdEludGVybmFsRmliZXI9dCxobih0LG4pLGU9QW4oZSx0LCEwLG8sbikpOih0LnRhZz0xLHduKGUsdCxpKSx0Lm1lbW9pemVkUHJvcHM9byxlPXQuY2hpbGQpLGU7Y2FzZSAxOnJldHVybiBvPXQudHlwZSxuPXQucGVuZGluZ1Byb3BzLEVhLmN1cnJlbnR8fHQubWVtb2l6ZWRQcm9wcyE9PW4/KGk9a3QodCksaT1BdCh0LGkpLG89byhuLGkpLHQuZWZmZWN0VGFnfD0xLHduKGUsdCxvKSx0Lm1lbW9pemVkUHJvcHM9bixlPXQuY2hpbGQpOmU9Rm4oZSx0KSxlO2Nhc2UgMjppZihvPUl0KHQpLG51bGw9PT1lKWlmKG51bGw9PT10LnN0YXRlTm9kZSl7dmFyIHM9dC5wZW5kaW5nUHJvcHMsdT10LnR5cGU7aT1rdCh0KTt2YXIgYz0yPT09dC50YWcmJm51bGwhPXQudHlwZS5jb250ZXh0VHlwZXM7YT1jP0F0KHQsaSk6VXIscz1uZXcgdShzLGEpLHQubWVtb2l6ZWRTdGF0ZT1udWxsIT09cy5zdGF0ZSYmdm9pZCAwIT09cy5zdGF0ZT9zLnN0YXRlOm51bGwscy51cGRhdGVyPUxhLHQuc3RhdGVOb2RlPXMscy5fcmVhY3RJbnRlcm5hbEZpYmVyPXQsYyYmKGM9dC5zdGF0ZU5vZGUsYy5fX3JlYWN0SW50ZXJuYWxNZW1vaXplZFVubWFza2VkQ2hpbGRDb250ZXh0PWksYy5fX3JlYWN0SW50ZXJuYWxNZW1vaXplZE1hc2tlZENoaWxkQ29udGV4dD1hKSxobih0LG4pLGk9ITB9ZWxzZXt1PXQudHlwZSxpPXQuc3RhdGVOb2RlLGM9dC5tZW1vaXplZFByb3BzLGE9dC5wZW5kaW5nUHJvcHMsaS5wcm9wcz1jO3ZhciBsPWkuY29udGV4dDtzPWt0KHQpLHM9QXQodCxzKTt2YXIgcD11LmdldERlcml2ZWRTdGF0ZUZyb21Qcm9wczsodT0iZnVuY3Rpb24iPT09dHlwZW9mIHB8fCJmdW5jdGlvbiI9PT10eXBlb2YgaS5nZXRTbmFwc2hvdEJlZm9yZVVwZGF0ZSl8fCJmdW5jdGlvbiIhPT10eXBlb2YgaS5VTlNBRkVfY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wcyYmImZ1bmN0aW9uIiE9PXR5cGVvZiBpLmNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHN8fChjIT09YXx8bCE9PXMpJiZkbih0LGksYSxzKSxrYT0hMTt2YXIgZj10Lm1lbW9pemVkU3RhdGU7bD1pLnN0YXRlPWY7dmFyIGQ9dC51cGRhdGVRdWV1ZTtudWxsIT09ZCYmKGVuKHQsZCxhLGksbiksbD10Lm1lbW9pemVkU3RhdGUpLGMhPT1hfHxmIT09bHx8RWEuY3VycmVudHx8a2E/KCJmdW5jdGlvbiI9PT10eXBlb2YgcCYmKHBuKHQscCxhKSxsPXQubWVtb2l6ZWRTdGF0ZSksKGM9a2F8fGZuKHQsYyxhLGYsbCxzKSk/KHV8fCJmdW5jdGlvbiIhPT10eXBlb2YgaS5VTlNBRkVfY29tcG9uZW50V2lsbE1vdW50JiYiZnVuY3Rpb24iIT09dHlwZW9mIGkuY29tcG9uZW50V2lsbE1vdW50fHwoImZ1bmN0aW9uIj09PXR5cGVvZiBpLmNvbXBvbmVudFdpbGxNb3VudCYmaS5jb21wb25lbnRXaWxsTW91bnQoKSwiZnVuY3Rpb24iPT09dHlwZW9mIGkuVU5TQUZFX2NvbXBvbmVudFdpbGxNb3VudCYmaS5VTlNBRkVfY29tcG9uZW50V2lsbE1vdW50KCkpLCJmdW5jdGlvbiI9PT10eXBlb2YgaS5jb21wb25lbnREaWRNb3VudCYmKHQuZWZmZWN0VGFnfD00KSk6KCJmdW5jdGlvbiI9PT10eXBlb2YgaS5jb21wb25lbnREaWRNb3VudCYmKHQuZWZmZWN0VGFnfD00KSx0Lm1lbW9pemVkUHJvcHM9YSx0Lm1lbW9pemVkU3RhdGU9bCksaS5wcm9wcz1hLGkuc3RhdGU9bCxpLmNvbnRleHQ9cyxpPWMpOigiZnVuY3Rpb24iPT09dHlwZW9mIGkuY29tcG9uZW50RGlkTW91bnQmJih0LmVmZmVjdFRhZ3w9NCksaT0hMSl9ZWxzZSB1PXQudHlwZSxpPXQuc3RhdGVOb2RlLGE9dC5tZW1vaXplZFByb3BzLGM9dC5wZW5kaW5nUHJvcHMsaS5wcm9wcz1hLGw9aS5jb250ZXh0LHM9a3QodCkscz1BdCh0LHMpLHA9dS5nZXREZXJpdmVkU3RhdGVGcm9tUHJvcHMsKHU9ImZ1bmN0aW9uIj09PXR5cGVvZiBwfHwiZnVuY3Rpb24iPT09dHlwZW9mIGkuZ2V0U25hcHNob3RCZWZvcmVVcGRhdGUpfHwiZnVuY3Rpb24iIT09dHlwZW9mIGkuVU5TQUZFX2NvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHMmJiJmdW5jdGlvbiIhPT10eXBlb2YgaS5jb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzfHwoYSE9PWN8fGwhPT1zKSYmZG4odCxpLGMscyksa2E9ITEsbD10Lm1lbW9pemVkU3RhdGUsZj1pLnN0YXRlPWwsZD10LnVwZGF0ZVF1ZXVlLG51bGwhPT1kJiYoZW4odCxkLGMsaSxuKSxmPXQubWVtb2l6ZWRTdGF0ZSksYSE9PWN8fGwhPT1mfHxFYS5jdXJyZW50fHxrYT8oImZ1bmN0aW9uIj09PXR5cGVvZiBwJiYocG4odCxwLGMpLGY9dC5tZW1vaXplZFN0YXRlKSwocD1rYXx8Zm4odCxhLGMsbCxmLHMpKT8odXx8ImZ1bmN0aW9uIiE9PXR5cGVvZiBpLlVOU0FGRV9jb21wb25lbnRXaWxsVXBkYXRlJiYiZnVuY3Rpb24iIT09dHlwZW9mIGkuY29tcG9uZW50V2lsbFVwZGF0ZXx8KCJmdW5jdGlvbiI9PT10eXBlb2YgaS5jb21wb25lbnRXaWxsVXBkYXRlJiZpLmNvbXBvbmVudFdpbGxVcGRhdGUoYyxmLHMpLCJmdW5jdGlvbiI9PT10eXBlb2YgaS5VTlNBRkVfY29tcG9uZW50V2lsbFVwZGF0ZSYmaS5VTlNBRkVfY29tcG9uZW50V2lsbFVwZGF0ZShjLGYscykpLCJmdW5jdGlvbiI9PT10eXBlb2YgaS5jb21wb25lbnREaWRVcGRhdGUmJih0LmVmZmVjdFRhZ3w9NCksImZ1bmN0aW9uIj09PXR5cGVvZiBpLmdldFNuYXBzaG90QmVmb3JlVXBkYXRlJiYodC5lZmZlY3RUYWd8PTI1NikpOigiZnVuY3Rpb24iIT09dHlwZW9mIGkuY29tcG9uZW50RGlkVXBkYXRlfHxhPT09ZS5tZW1vaXplZFByb3BzJiZsPT09ZS5tZW1vaXplZFN0YXRlfHwodC5lZmZlY3RUYWd8PTQpLCJmdW5jdGlvbiIhPT10eXBlb2YgaS5nZXRTbmFwc2hvdEJlZm9yZVVwZGF0ZXx8YT09PWUubWVtb2l6ZWRQcm9wcyYmbD09PWUubWVtb2l6ZWRTdGF0ZXx8KHQuZWZmZWN0VGFnfD0yNTYpLHQubWVtb2l6ZWRQcm9wcz1jLHQubWVtb2l6ZWRTdGF0ZT1mKSxpLnByb3BzPWMsaS5zdGF0ZT1mLGkuY29udGV4dD1zLGk9cCk6KCJmdW5jdGlvbiIhPT10eXBlb2YgaS5jb21wb25lbnREaWRVcGRhdGV8fGE9PT1lLm1lbW9pemVkUHJvcHMmJmw9PT1lLm1lbW9pemVkU3RhdGV8fCh0LmVmZmVjdFRhZ3w9NCksImZ1bmN0aW9uIiE9PXR5cGVvZiBpLmdldFNuYXBzaG90QmVmb3JlVXBkYXRlfHxhPT09ZS5tZW1vaXplZFByb3BzJiZsPT09ZS5tZW1vaXplZFN0YXRlfHwodC5lZmZlY3RUYWd8PTI1NiksaT0hMSk7cmV0dXJuIEFuKGUsdCxpLG8sbik7Y2FzZSAzOnJldHVybiBfbih0KSxvPXQudXBkYXRlUXVldWUsbnVsbCE9PW8/KGk9dC5tZW1vaXplZFN0YXRlLGk9bnVsbCE9PWk/aS5lbGVtZW50Om51bGwsZW4odCxvLHQucGVuZGluZ1Byb3BzLG51bGwsbiksKG89dC5tZW1vaXplZFN0YXRlLmVsZW1lbnQpPT09aT8oRG4oKSxlPUZuKGUsdCkpOihpPXQuc3RhdGVOb2RlLChpPShudWxsPT09ZXx8bnVsbD09PWUuY2hpbGQpJiZpLmh5ZHJhdGUpJiYoQmE9RXQodC5zdGF0ZU5vZGUuY29udGFpbmVySW5mbyksUmE9dCxpPSRhPSEwKSxpPyh0LmVmZmVjdFRhZ3w9Mix0LmNoaWxkPWphKHQsbnVsbCxvLG4pKTooRG4oKSx3bihlLHQsbykpLGU9dC5jaGlsZCkpOihEbigpLGU9Rm4oZSx0KSksZTtjYXNlIDU6cmV0dXJuIHNuKElhLmN1cnJlbnQpLG89c24oRmEuY3VycmVudCksaT1hdChvLHQudHlwZSksbyE9PWkmJihTdChOYSx0LHQpLFN0KEZhLGksdCkpLG51bGw9PT1lJiZ4bih0KSxvPXQudHlwZSxjPXQubWVtb2l6ZWRQcm9wcyxpPXQucGVuZGluZ1Byb3BzLGE9bnVsbCE9PWU/ZS5tZW1vaXplZFByb3BzOm51bGwsRWEuY3VycmVudHx8YyE9PWl8fCgoYz0xJnQubW9kZSYmISFpLmhpZGRlbikmJih0LmV4cGlyYXRpb25UaW1lPTEwNzM3NDE4MjMpLGMmJjEwNzM3NDE4MjM9PT1uKT8oYz1pLmNoaWxkcmVuLHh0KG8saSk/Yz1udWxsOmEmJnh0KG8sYSkmJih0LmVmZmVjdFRhZ3w9MTYpLGtuKGUsdCksMTA3Mzc0MTgyMyE9PW4mJjEmdC5tb2RlJiZpLmhpZGRlbj8odC5leHBpcmF0aW9uVGltZT0xMDczNzQxODIzLHQubWVtb2l6ZWRQcm9wcz1pLGU9bnVsbCk6KHduKGUsdCxjKSx0Lm1lbW9pemVkUHJvcHM9aSxlPXQuY2hpbGQpKTplPUZuKGUsdCksZTtjYXNlIDY6cmV0dXJuIG51bGw9PT1lJiZ4bih0KSx0Lm1lbW9pemVkUHJvcHM9dC5wZW5kaW5nUHJvcHMsbnVsbDtjYXNlIDE2OnJldHVybiBudWxsO2Nhc2UgNDpyZXR1cm4gdW4odCx0LnN0YXRlTm9kZS5jb250YWluZXJJbmZvKSxvPXQucGVuZGluZ1Byb3BzLEVhLmN1cnJlbnR8fHQubWVtb2l6ZWRQcm9wcyE9PW8/KG51bGw9PT1lP3QuY2hpbGQ9TWEodCxudWxsLG8sbik6d24oZSx0LG8pLHQubWVtb2l6ZWRQcm9wcz1vLGU9dC5jaGlsZCk6ZT1GbihlLHQpLGU7Y2FzZSAxNDpyZXR1cm4gbz10LnR5cGUucmVuZGVyLG49dC5wZW5kaW5nUHJvcHMsaT10LnJlZixFYS5jdXJyZW50fHx0Lm1lbW9pemVkUHJvcHMhPT1ufHxpIT09KG51bGwhPT1lP2UucmVmOm51bGwpPyhvPW8obixpKSx3bihlLHQsbyksdC5tZW1vaXplZFByb3BzPW4sZT10LmNoaWxkKTplPUZuKGUsdCksZTtjYXNlIDEwOnJldHVybiBuPXQucGVuZGluZ1Byb3BzLEVhLmN1cnJlbnR8fHQubWVtb2l6ZWRQcm9wcyE9PW4/KHduKGUsdCxuKSx0Lm1lbW9pemVkUHJvcHM9bixlPXQuY2hpbGQpOmU9Rm4oZSx0KSxlO2Nhc2UgMTE6cmV0dXJuIG49dC5wZW5kaW5nUHJvcHMuY2hpbGRyZW4sRWEuY3VycmVudHx8bnVsbCE9PW4mJnQubWVtb2l6ZWRQcm9wcyE9PW4/KHduKGUsdCxuKSx0Lm1lbW9pemVkUHJvcHM9bixlPXQuY2hpbGQpOmU9Rm4oZSx0KSxlO2Nhc2UgMTU6cmV0dXJuIG49dC5wZW5kaW5nUHJvcHMsdC5tZW1vaXplZFByb3BzPT09bj9lPUZuKGUsdCk6KHduKGUsdCxuLmNoaWxkcmVuKSx0Lm1lbW9pemVkUHJvcHM9bixlPXQuY2hpbGQpLGU7Y2FzZSAxMzpyZXR1cm4gT24oZSx0LG4pO2Nhc2UgMTI6ZTppZihpPXQudHlwZSxhPXQucGVuZGluZ1Byb3BzLGM9dC5tZW1vaXplZFByb3BzLG89aS5fY3VycmVudFZhbHVlLHM9aS5fY2hhbmdlZEJpdHMsRWEuY3VycmVudHx8MCE9PXN8fGMhPT1hKXtpZih0Lm1lbW9pemVkUHJvcHM9YSx1PWEudW5zdGFibGVfb2JzZXJ2ZWRCaXRzLHZvaWQgMCE9PXUmJm51bGwhPT11fHwodT0xMDczNzQxODIzKSx0LnN0YXRlTm9kZT11LDAhPT0ocyZ1KSlUbih0LGkscyxuKTtlbHNlIGlmKGM9PT1hKXtlPUZuKGUsdCk7YnJlYWsgZX1uPWEuY2hpbGRyZW4sbj1uKG8pLHQuZWZmZWN0VGFnfD0xLHduKGUsdCxuKSxlPXQuY2hpbGR9ZWxzZSBlPUZuKGUsdCk7cmV0dXJuIGU7ZGVmYXVsdDpyKCIxNTYiKX19ZnVuY3Rpb24gSW4oZSl7ZS5lZmZlY3RUYWd8PTR9ZnVuY3Rpb24gTG4oZSx0KXt2YXIgbj10LnBlbmRpbmdQcm9wcztzd2l0Y2godC50YWcpe2Nhc2UgMTpyZXR1cm4gbnVsbDtjYXNlIDI6cmV0dXJuIFR0KHQpLG51bGw7Y2FzZSAzOmNuKHQpLE90KHQpO3ZhciBpPXQuc3RhdGVOb2RlO3JldHVybiBpLnBlbmRpbmdDb250ZXh0JiYoaS5jb250ZXh0PWkucGVuZGluZ0NvbnRleHQsaS5wZW5kaW5nQ29udGV4dD1udWxsKSxudWxsIT09ZSYmbnVsbCE9PWUuY2hpbGR8fChFbih0KSx0LmVmZmVjdFRhZyY9LTMpLFVhKHQpLG51bGw7Y2FzZSA1OmxuKHQpLGk9c24oSWEuY3VycmVudCk7dmFyIG89dC50eXBlO2lmKG51bGwhPT1lJiZudWxsIT10LnN0YXRlTm9kZSl7dmFyIGE9ZS5tZW1vaXplZFByb3BzLHM9dC5zdGF0ZU5vZGUsdT1zbihGYS5jdXJyZW50KTtzPW10KHMsbyxhLG4saSksemEoZSx0LHMsbyxhLG4saSx1KSxlLnJlZiE9PXQucmVmJiYodC5lZmZlY3RUYWd8PTEyOCl9ZWxzZXtpZighbilyZXR1cm4gbnVsbD09PXQuc3RhdGVOb2RlJiZyKCIxNjYiKSxudWxsO2lmKGU9c24oRmEuY3VycmVudCksRW4odCkpbj10LnN0YXRlTm9kZSxvPXQudHlwZSxhPXQubWVtb2l6ZWRQcm9wcyxuW3JpXT10LG5baWldPWEsaT15dChuLG8sYSxlLGkpLHQudXBkYXRlUXVldWU9aSxudWxsIT09aSYmSW4odCk7ZWxzZXtlPWZ0KG8sbixpLGUpLGVbcmldPXQsZVtpaV09bjtlOmZvcihhPXQuY2hpbGQ7bnVsbCE9PWE7KXtpZig1PT09YS50YWd8fDY9PT1hLnRhZyllLmFwcGVuZENoaWxkKGEuc3RhdGVOb2RlKTtlbHNlIGlmKDQhPT1hLnRhZyYmbnVsbCE9PWEuY2hpbGQpe2EuY2hpbGQucmV0dXJuPWEsYT1hLmNoaWxkO2NvbnRpbnVlfWlmKGE9PT10KWJyZWFrO2Zvcig7bnVsbD09PWEuc2libGluZzspe2lmKG51bGw9PT1hLnJldHVybnx8YS5yZXR1cm49PT10KWJyZWFrIGU7YT1hLnJldHVybn1hLnNpYmxpbmcucmV0dXJuPWEucmV0dXJuLGE9YS5zaWJsaW5nfWh0KGUsbyxuLGkpLGJ0KG8sbikmJkluKHQpLHQuc3RhdGVOb2RlPWV9bnVsbCE9PXQucmVmJiYodC5lZmZlY3RUYWd8PTEyOCl9cmV0dXJuIG51bGw7Y2FzZSA2OmlmKGUmJm51bGwhPXQuc3RhdGVOb2RlKUdhKGUsdCxlLm1lbW9pemVkUHJvcHMsbik7ZWxzZXtpZigic3RyaW5nIiE9PXR5cGVvZiBuKXJldHVybiBudWxsPT09dC5zdGF0ZU5vZGUmJnIoIjE2NiIpLG51bGw7aT1zbihJYS5jdXJyZW50KSxzbihGYS5jdXJyZW50KSxFbih0KT8oaT10LnN0YXRlTm9kZSxuPXQubWVtb2l6ZWRQcm9wcyxpW3JpXT10LHZ0KGksbikmJkluKHQpKTooaT1kdChuLGkpLGlbcmldPXQsdC5zdGF0ZU5vZGU9aSl9cmV0dXJuIG51bGw7Y2FzZSAxNDpjYXNlIDE2OmNhc2UgMTA6Y2FzZSAxMTpjYXNlIDE1OnJldHVybiBudWxsO2Nhc2UgNDpyZXR1cm4gY24odCksVWEodCksbnVsbDtjYXNlIDEzOnJldHVybiBhbih0KSxudWxsO2Nhc2UgMTI6cmV0dXJuIG51bGw7Y2FzZSAwOnIoIjE2NyIpO2RlZmF1bHQ6cigiMTU2Iil9fWZ1bmN0aW9uIFBuKGUsdCl7dmFyIG49dC5zb3VyY2U7bnVsbD09PXQuc3RhY2smJm51bGwhPT1uJiZzZShuKSxudWxsIT09biYmYWUobiksdD10LnZhbHVlLG51bGwhPT1lJiYyPT09ZS50YWcmJmFlKGUpO3RyeXt0JiZ0LnN1cHByZXNzUmVhY3RFcnJvckxvZ2dpbmd8fGNvbnNvbGUuZXJyb3IodCl9Y2F0Y2goZSl7ZSYmZS5zdXBwcmVzc1JlYWN0RXJyb3JMb2dnaW5nfHxjb25zb2xlLmVycm9yKGUpfX1mdW5jdGlvbiBNbihlKXt2YXIgdD1lLnJlZjtpZihudWxsIT09dClpZigiZnVuY3Rpb24iPT09dHlwZW9mIHQpdHJ5e3QobnVsbCl9Y2F0Y2godCl7Sm4oZSx0KX1lbHNlIHQuY3VycmVudD1udWxsfWZ1bmN0aW9uIGpuKGUpe3N3aXRjaCgiZnVuY3Rpb24iPT09dHlwZW9mIHF0JiZxdChlKSxlLnRhZyl7Y2FzZSAyOk1uKGUpO3ZhciB0PWUuc3RhdGVOb2RlO2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgdC5jb21wb25lbnRXaWxsVW5tb3VudCl0cnl7dC5wcm9wcz1lLm1lbW9pemVkUHJvcHMsdC5zdGF0ZT1lLm1lbW9pemVkU3RhdGUsdC5jb21wb25lbnRXaWxsVW5tb3VudCgpfWNhdGNoKHQpe0puKGUsdCl9YnJlYWs7Y2FzZSA1Ok1uKGUpO2JyZWFrO2Nhc2UgNDokbihlKX19ZnVuY3Rpb24gUm4oZSl7cmV0dXJuIDU9PT1lLnRhZ3x8Mz09PWUudGFnfHw0PT09ZS50YWd9ZnVuY3Rpb24gQm4oZSl7ZTp7Zm9yKHZhciB0PWUucmV0dXJuO251bGwhPT10Oyl7aWYoUm4odCkpe3ZhciBuPXQ7YnJlYWsgZX10PXQucmV0dXJufXIoIjE2MCIpLG49dm9pZCAwfXZhciBpPXQ9dm9pZCAwO3N3aXRjaChuLnRhZyl7Y2FzZSA1OnQ9bi5zdGF0ZU5vZGUsaT0hMTticmVhaztjYXNlIDM6Y2FzZSA0OnQ9bi5zdGF0ZU5vZGUuY29udGFpbmVySW5mbyxpPSEwO2JyZWFrO2RlZmF1bHQ6cigiMTYxIil9MTYmbi5lZmZlY3RUYWcmJihzdCh0LCIiKSxuLmVmZmVjdFRhZyY9LTE3KTtlOnQ6Zm9yKG49ZTs7KXtmb3IoO251bGw9PT1uLnNpYmxpbmc7KXtpZihudWxsPT09bi5yZXR1cm58fFJuKG4ucmV0dXJuKSl7bj1udWxsO2JyZWFrIGV9bj1uLnJldHVybn1mb3Iobi5zaWJsaW5nLnJldHVybj1uLnJldHVybixuPW4uc2libGluZzs1IT09bi50YWcmJjYhPT1uLnRhZzspe2lmKDImbi5lZmZlY3RUYWcpY29udGludWUgdDtpZihudWxsPT09bi5jaGlsZHx8ND09PW4udGFnKWNvbnRpbnVlIHQ7bi5jaGlsZC5yZXR1cm49bixuPW4uY2hpbGR9aWYoISgyJm4uZWZmZWN0VGFnKSl7bj1uLnN0YXRlTm9kZTticmVhayBlfX1mb3IodmFyIG89ZTs7KXtpZig1PT09by50YWd8fDY9PT1vLnRhZylpZihuKWlmKGkpe3ZhciBhPXQscz1vLnN0YXRlTm9kZSx1PW47OD09PWEubm9kZVR5cGU/YS5wYXJlbnROb2RlLmluc2VydEJlZm9yZShzLHUpOmEuaW5zZXJ0QmVmb3JlKHMsdSl9ZWxzZSB0Lmluc2VydEJlZm9yZShvLnN0YXRlTm9kZSxuKTtlbHNlIGk/KGE9dCxzPW8uc3RhdGVOb2RlLDg9PT1hLm5vZGVUeXBlP2EucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUocyxhKTphLmFwcGVuZENoaWxkKHMpKTp0LmFwcGVuZENoaWxkKG8uc3RhdGVOb2RlKTtlbHNlIGlmKDQhPT1vLnRhZyYmbnVsbCE9PW8uY2hpbGQpe28uY2hpbGQucmV0dXJuPW8sbz1vLmNoaWxkO2NvbnRpbnVlfWlmKG89PT1lKWJyZWFrO2Zvcig7bnVsbD09PW8uc2libGluZzspe2lmKG51bGw9PT1vLnJldHVybnx8by5yZXR1cm49PT1lKXJldHVybjtvPW8ucmV0dXJufW8uc2libGluZy5yZXR1cm49by5yZXR1cm4sbz1vLnNpYmxpbmd9fWZ1bmN0aW9uICRuKGUpe2Zvcih2YXIgdD1lLG49ITEsaT12b2lkIDAsbz12b2lkIDA7Oyl7aWYoIW4pe249dC5yZXR1cm47ZTpmb3IoOzspe3N3aXRjaChudWxsPT09biYmcigiMTYwIiksbi50YWcpe2Nhc2UgNTppPW4uc3RhdGVOb2RlLG89ITE7YnJlYWsgZTtjYXNlIDM6Y2FzZSA0Omk9bi5zdGF0ZU5vZGUuY29udGFpbmVySW5mbyxvPSEwO2JyZWFrIGV9bj1uLnJldHVybn1uPSEwfWlmKDU9PT10LnRhZ3x8Nj09PXQudGFnKXtlOmZvcih2YXIgYT10LHM9YTs7KWlmKGpuKHMpLG51bGwhPT1zLmNoaWxkJiY0IT09cy50YWcpcy5jaGlsZC5yZXR1cm49cyxzPXMuY2hpbGQ7ZWxzZXtpZihzPT09YSlicmVhaztmb3IoO251bGw9PT1zLnNpYmxpbmc7KXtpZihudWxsPT09cy5yZXR1cm58fHMucmV0dXJuPT09YSlicmVhayBlO3M9cy5yZXR1cm59cy5zaWJsaW5nLnJldHVybj1zLnJldHVybixzPXMuc2libGluZ31vPyhhPWkscz10LnN0YXRlTm9kZSw4PT09YS5ub2RlVHlwZT9hLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQocyk6YS5yZW1vdmVDaGlsZChzKSk6aS5yZW1vdmVDaGlsZCh0LnN0YXRlTm9kZSl9ZWxzZSBpZig0PT09dC50YWc/aT10LnN0YXRlTm9kZS5jb250YWluZXJJbmZvOmpuKHQpLG51bGwhPT10LmNoaWxkKXt0LmNoaWxkLnJldHVybj10LHQ9dC5jaGlsZDtjb250aW51ZX1pZih0PT09ZSlicmVhaztmb3IoO251bGw9PT10LnNpYmxpbmc7KXtpZihudWxsPT09dC5yZXR1cm58fHQucmV0dXJuPT09ZSlyZXR1cm47dD10LnJldHVybiw0PT09dC50YWcmJihuPSExKX10LnNpYmxpbmcucmV0dXJuPXQucmV0dXJuLHQ9dC5zaWJsaW5nfX1mdW5jdGlvbiBVbihlLHQpe3N3aXRjaCh0LnRhZyl7Y2FzZSAyOmJyZWFrO2Nhc2UgNTp2YXIgbj10LnN0YXRlTm9kZTtpZihudWxsIT1uKXt2YXIgaT10Lm1lbW9pemVkUHJvcHM7ZT1udWxsIT09ZT9lLm1lbW9pemVkUHJvcHM6aTt2YXIgbz10LnR5cGUsYT10LnVwZGF0ZVF1ZXVlO3QudXBkYXRlUXVldWU9bnVsbCxudWxsIT09YSYmKG5baWldPWksZ3QobixhLG8sZSxpKSl9YnJlYWs7Y2FzZSA2Om51bGw9PT10LnN0YXRlTm9kZSYmcigiMTYyIiksdC5zdGF0ZU5vZGUubm9kZVZhbHVlPXQubWVtb2l6ZWRQcm9wczticmVhaztjYXNlIDM6Y2FzZSAxNTpjYXNlIDE2OmJyZWFrO2RlZmF1bHQ6cigiMTYzIil9fWZ1bmN0aW9uIHpuKGUsdCxuKXtuPVF0KG4pLG4udGFnPTMsbi5wYXlsb2FkPXtlbGVtZW50Om51bGx9O3ZhciByPXQudmFsdWU7cmV0dXJuIG4uY2FsbGJhY2s9ZnVuY3Rpb24oKXtocihyKSxQbihlLHQpfSxufWZ1bmN0aW9uIEduKGUsdCxuKXtuPVF0KG4pLG4udGFnPTM7dmFyIHI9ZS5zdGF0ZU5vZGU7cmV0dXJuIG51bGwhPT1yJiYiZnVuY3Rpb24iPT09dHlwZW9mIHIuY29tcG9uZW50RGlkQ2F0Y2gmJihuLmNhbGxiYWNrPWZ1bmN0aW9uKCl7bnVsbD09PWlzP2lzPW5ldyBTZXQoW3RoaXNdKTppcy5hZGQodGhpcyk7dmFyIG49dC52YWx1ZSxyPXQuc3RhY2s7UG4oZSx0KSx0aGlzLmNvbXBvbmVudERpZENhdGNoKG4se2NvbXBvbmVudFN0YWNrOm51bGwhPT1yP3I6IiJ9KX0pLG59ZnVuY3Rpb24gVm4oZSx0LG4scixpLG8pe24uZWZmZWN0VGFnfD01MTIsbi5maXJzdEVmZmVjdD1uLmxhc3RFZmZlY3Q9bnVsbCxyPXJuKHIsbiksZT10O2Rve3N3aXRjaChlLnRhZyl7Y2FzZSAzOnJldHVybiBlLmVmZmVjdFRhZ3w9MTAyNCxyPXpuKGUscixvKSx2b2lkIFl0KGUscixvKTtjYXNlIDI6aWYodD1yLG49ZS5zdGF0ZU5vZGUsMD09PSg2NCZlLmVmZmVjdFRhZykmJm51bGwhPT1uJiYiZnVuY3Rpb24iPT09dHlwZW9mIG4uY29tcG9uZW50RGlkQ2F0Y2gmJihudWxsPT09aXN8fCFpcy5oYXMobikpKXJldHVybiBlLmVmZmVjdFRhZ3w9MTAyNCxyPUduKGUsdCxvKSx2b2lkIFl0KGUscixvKX1lPWUucmV0dXJufXdoaWxlKG51bGwhPT1lKX1mdW5jdGlvbiBxbihlKXtzd2l0Y2goZS50YWcpe2Nhc2UgMjpUdChlKTt2YXIgdD1lLmVmZmVjdFRhZztyZXR1cm4gMTAyNCZ0PyhlLmVmZmVjdFRhZz0tMTAyNSZ0fDY0LGUpOm51bGw7Y2FzZSAzOnJldHVybiBjbihlKSxPdChlKSx0PWUuZWZmZWN0VGFnLDEwMjQmdD8oZS5lZmZlY3RUYWc9LTEwMjUmdHw2NCxlKTpudWxsO2Nhc2UgNTpyZXR1cm4gbG4oZSksbnVsbDtjYXNlIDE2OnJldHVybiB0PWUuZWZmZWN0VGFnLDEwMjQmdD8oZS5lZmZlY3RUYWc9LTEwMjUmdHw2NCxlKTpudWxsO2Nhc2UgNDpyZXR1cm4gY24oZSksbnVsbDtjYXNlIDEzOnJldHVybiBhbihlKSxudWxsO2RlZmF1bHQ6cmV0dXJuIG51bGx9fWZ1bmN0aW9uIEhuKCl7aWYobnVsbCE9PUphKWZvcih2YXIgZT1KYS5yZXR1cm47bnVsbCE9PWU7KXt2YXIgdD1lO3N3aXRjaCh0LnRhZyl7Y2FzZSAyOlR0KHQpO2JyZWFrO2Nhc2UgMzpjbih0KSxPdCh0KTticmVhaztjYXNlIDU6bG4odCk7YnJlYWs7Y2FzZSA0OmNuKHQpO2JyZWFrO2Nhc2UgMTM6YW4odCl9ZT1lLnJldHVybn1ZYT1udWxsLFhhPTAsWmE9LTEsZXM9ITEsSmE9bnVsbCxycz0hMX1mdW5jdGlvbiBXbihlKXtmb3IoOzspe3ZhciB0PWUuYWx0ZXJuYXRlLG49ZS5yZXR1cm4scj1lLnNpYmxpbmc7aWYoMD09PSg1MTImZS5lZmZlY3RUYWcpKXt0PUxuKHQsZSxYYSk7dmFyIGk9ZTtpZigxMDczNzQxODIzPT09WGF8fDEwNzM3NDE4MjMhPT1pLmV4cGlyYXRpb25UaW1lKXt2YXIgbz0wO3N3aXRjaChpLnRhZyl7Y2FzZSAzOmNhc2UgMjp2YXIgYT1pLnVwZGF0ZVF1ZXVlO251bGwhPT1hJiYobz1hLmV4cGlyYXRpb25UaW1lKX1mb3IoYT1pLmNoaWxkO251bGwhPT1hOykwIT09YS5leHBpcmF0aW9uVGltZSYmKDA9PT1vfHxvPmEuZXhwaXJhdGlvblRpbWUpJiYobz1hLmV4cGlyYXRpb25UaW1lKSxhPWEuc2libGluZztpLmV4cGlyYXRpb25UaW1lPW99aWYobnVsbCE9PXQpcmV0dXJuIHQ7aWYobnVsbCE9PW4mJjA9PT0oNTEyJm4uZWZmZWN0VGFnKSYmKG51bGw9PT1uLmZpcnN0RWZmZWN0JiYobi5maXJzdEVmZmVjdD1lLmZpcnN0RWZmZWN0KSxudWxsIT09ZS5sYXN0RWZmZWN0JiYobnVsbCE9PW4ubGFzdEVmZmVjdCYmKG4ubGFzdEVmZmVjdC5uZXh0RWZmZWN0PWUuZmlyc3RFZmZlY3QpLG4ubGFzdEVmZmVjdD1lLmxhc3RFZmZlY3QpLDE8ZS5lZmZlY3RUYWcmJihudWxsIT09bi5sYXN0RWZmZWN0P24ubGFzdEVmZmVjdC5uZXh0RWZmZWN0PWU6bi5maXJzdEVmZmVjdD1lLG4ubGFzdEVmZmVjdD1lKSksbnVsbCE9PXIpcmV0dXJuIHI7aWYobnVsbD09PW4pe3JzPSEwO2JyZWFrfWU9bn1lbHNle2lmKG51bGwhPT0oZT1xbihlLGVzLFhhKSkpcmV0dXJuIGUuZWZmZWN0VGFnJj01MTEsZTtpZihudWxsIT09biYmKG4uZmlyc3RFZmZlY3Q9bi5sYXN0RWZmZWN0PW51bGwsbi5lZmZlY3RUYWd8PTUxMiksbnVsbCE9PXIpcmV0dXJuIHI7aWYobnVsbD09PW4pYnJlYWs7ZT1ufX1yZXR1cm4gbnVsbH1mdW5jdGlvbiBRbihlKXt2YXIgdD1ObihlLmFsdGVybmF0ZSxlLFhhKTtyZXR1cm4gbnVsbD09PXQmJih0PVduKGUpKSxSaS5jdXJyZW50PW51bGwsdH1mdW5jdGlvbiBLbihlLHQsbil7S2EmJnIoIjI0MyIpLEthPSEwLHQ9PT1YYSYmZT09PVlhJiZudWxsIT09SmF8fChIbigpLFlhPWUsWGE9dCxaYT0tMSxKYT1NdChZYS5jdXJyZW50LG51bGwsWGEpLGUucGVuZGluZ0NvbW1pdEV4cGlyYXRpb25UaW1lPTApO3ZhciBpPSExO2Zvcihlcz0hbnx8WGE8PXFhOzspe3RyeXtpZihuKWZvcig7bnVsbCE9PUphJiYhZHIoKTspSmE9UW4oSmEpO2Vsc2UgZm9yKDtudWxsIT09SmE7KUphPVFuKEphKX1jYXRjaCh0KXtpZihudWxsPT09SmEpaT0hMCxocih0KTtlbHNle251bGw9PT1KYSYmcigiMjcxIiksbj1KYTt2YXIgbz1uLnJldHVybjtpZihudWxsPT09byl7aT0hMCxocih0KTticmVha31WbihlLG8sbix0LGVzLFhhLEhhKSxKYT1XbihuKX19YnJlYWt9aWYoS2E9ITEsaSlyZXR1cm4gbnVsbDtpZihudWxsPT09SmEpe2lmKHJzKXJldHVybiBlLnBlbmRpbmdDb21taXRFeHBpcmF0aW9uVGltZT10LGUuY3VycmVudC5hbHRlcm5hdGU7ZXMmJnIoIjI2MiIpLDA8PVphJiZzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dmFyIHQ9ZS5jdXJyZW50LmV4cGlyYXRpb25UaW1lOzAhPT10JiYoMD09PWUucmVtYWluaW5nRXhwaXJhdGlvblRpbWV8fGUucmVtYWluaW5nRXhwaXJhdGlvblRpbWU8dCkmJmlyKGUsdCl9LFphKSxtcihlLmN1cnJlbnQuZXhwaXJhdGlvblRpbWUpfXJldHVybiBudWxsfWZ1bmN0aW9uIEpuKGUsdCl7dmFyIG47ZTp7Zm9yKEthJiYhbnMmJnIoIjI2MyIpLG49ZS5yZXR1cm47bnVsbCE9PW47KXtzd2l0Y2gobi50YWcpe2Nhc2UgMjp2YXIgaT1uLnN0YXRlTm9kZTtpZigiZnVuY3Rpb24iPT09dHlwZW9mIG4udHlwZS5nZXREZXJpdmVkU3RhdGVGcm9tQ2F0Y2h8fCJmdW5jdGlvbiI9PT10eXBlb2YgaS5jb21wb25lbnREaWRDYXRjaCYmKG51bGw9PT1pc3x8IWlzLmhhcyhpKSkpe2U9cm4odCxlKSxlPUduKG4sZSwxKSxKdChuLGUsMSksWm4obiwxKSxuPXZvaWQgMDticmVhayBlfWJyZWFrO2Nhc2UgMzplPXJuKHQsZSksZT16bihuLGUsMSksSnQobixlLDEpLFpuKG4sMSksbj12b2lkIDA7YnJlYWsgZX1uPW4ucmV0dXJufTM9PT1lLnRhZyYmKG49cm4odCxlKSxuPXpuKGUsbiwxKSxKdChlLG4sMSksWm4oZSwxKSksbj12b2lkIDB9cmV0dXJuIG59ZnVuY3Rpb24gWW4oKXt2YXIgZT0yKzI1KigxKygoZXIoKS0yKzUwMCkvMjV8MCkpO3JldHVybiBlPD1XYSYmKGU9V2ErMSksV2E9ZX1mdW5jdGlvbiBYbihlLHQpe3JldHVybiBlPTAhPT1RYT9RYTpLYT9ucz8xOlhhOjEmdC5tb2RlP2JzPzIrMTAqKDErKChlLTIrMTUpLzEwfDApKToyKzI1KigxKygoZS0yKzUwMCkvMjV8MCkpOjEsYnMmJigwPT09ZnN8fGU+ZnMpJiYoZnM9ZSksZX1mdW5jdGlvbiBabihlLHQpe2Zvcig7bnVsbCE9PWU7KXtpZigoMD09PWUuZXhwaXJhdGlvblRpbWV8fGUuZXhwaXJhdGlvblRpbWU+dCkmJihlLmV4cGlyYXRpb25UaW1lPXQpLG51bGwhPT1lLmFsdGVybmF0ZSYmKDA9PT1lLmFsdGVybmF0ZS5leHBpcmF0aW9uVGltZXx8ZS5hbHRlcm5hdGUuZXhwaXJhdGlvblRpbWU+dCkmJihlLmFsdGVybmF0ZS5leHBpcmF0aW9uVGltZT10KSxudWxsPT09ZS5yZXR1cm4pe2lmKDMhPT1lLnRhZylicmVhazt2YXIgbj1lLnN0YXRlTm9kZTshS2EmJjAhPT1YYSYmdDxYYSYmSG4oKTt2YXIgaT1uLmN1cnJlbnQuZXhwaXJhdGlvblRpbWU7S2EmJiFucyYmWWE9PT1ufHxpcihuLGkpLEVzPkNzJiZyKCIxODUiKX1lPWUucmV0dXJufX1mdW5jdGlvbiBlcigpe3JldHVybiBIYT1nYSgpLVZhLHFhPTIrKEhhLzEwfDApfWZ1bmN0aW9uIHRyKGUpe3ZhciB0PVFhO1FhPTIrMjUqKDErKChlcigpLTIrNTAwKS8yNXwwKSk7dHJ5e3JldHVybiBlKCl9ZmluYWxseXtRYT10fX1mdW5jdGlvbiBucihlLHQsbixyLGkpe3ZhciBvPVFhO1FhPTE7dHJ5e3JldHVybiBlKHQsbixyLGkpfWZpbmFsbHl7UWE9b319ZnVuY3Rpb24gcnIoZSl7aWYoMCE9PXNzKXtpZihlPnNzKXJldHVybjt2YSh1cyl9dmFyIHQ9Z2EoKS1WYTtzcz1lLHVzPXlhKGFyLHt0aW1lb3V0OjEwKihlLTIpLXR9KX1mdW5jdGlvbiBpcihlLHQpe2lmKG51bGw9PT1lLm5leHRTY2hlZHVsZWRSb290KWUucmVtYWluaW5nRXhwaXJhdGlvblRpbWU9dCxudWxsPT09YXM/KG9zPWFzPWUsZS5uZXh0U2NoZWR1bGVkUm9vdD1lKTooYXM9YXMubmV4dFNjaGVkdWxlZFJvb3Q9ZSxhcy5uZXh0U2NoZWR1bGVkUm9vdD1vcyk7ZWxzZXt2YXIgbj1lLnJlbWFpbmluZ0V4cGlyYXRpb25UaW1lOygwPT09bnx8dDxuKSYmKGUucmVtYWluaW5nRXhwaXJhdGlvblRpbWU9dCl9Y3N8fCh5cz92cyYmKGxzPWUscHM9MSxwcihlLDEsITEpKToxPT09dD9zcigpOnJyKHQpKX1mdW5jdGlvbiBvcigpe3ZhciBlPTAsdD1udWxsO2lmKG51bGwhPT1hcylmb3IodmFyIG49YXMsaT1vcztudWxsIT09aTspe3ZhciBvPWkucmVtYWluaW5nRXhwaXJhdGlvblRpbWU7aWYoMD09PW8pe2lmKChudWxsPT09bnx8bnVsbD09PWFzKSYmcigiMjQ0IiksaT09PWkubmV4dFNjaGVkdWxlZFJvb3Qpe29zPWFzPWkubmV4dFNjaGVkdWxlZFJvb3Q9bnVsbDticmVha31pZihpPT09b3Mpb3M9bz1pLm5leHRTY2hlZHVsZWRSb290LGFzLm5leHRTY2hlZHVsZWRSb290PW8saS5uZXh0U2NoZWR1bGVkUm9vdD1udWxsO2Vsc2V7aWYoaT09PWFzKXthcz1uLGFzLm5leHRTY2hlZHVsZWRSb290PW9zLGkubmV4dFNjaGVkdWxlZFJvb3Q9bnVsbDticmVha31uLm5leHRTY2hlZHVsZWRSb290PWkubmV4dFNjaGVkdWxlZFJvb3QsaS5uZXh0U2NoZWR1bGVkUm9vdD1udWxsfWk9bi5uZXh0U2NoZWR1bGVkUm9vdH1lbHNle2lmKCgwPT09ZXx8bzxlKSYmKGU9byx0PWkpLGk9PT1hcylicmVhaztuPWksaT1pLm5leHRTY2hlZHVsZWRSb290fX1uPWxzLG51bGwhPT1uJiZuPT09dCYmMT09PWU/RXMrKzpFcz0wLGxzPXQscHM9ZX1mdW5jdGlvbiBhcihlKXt1cigwLCEwLGUpfWZ1bmN0aW9uIHNyKCl7dXIoMSwhMSxudWxsKX1mdW5jdGlvbiB1cihlLHQsbil7aWYoZ3M9bixvcigpLHQpZm9yKDtudWxsIT09bHMmJjAhPT1wcyYmKDA9PT1lfHxlPj1wcykmJighZHN8fGVyKCk+PXBzKTspZXIoKSxwcihscyxwcywhZHMpLG9yKCk7ZWxzZSBmb3IoO251bGwhPT1scyYmMCE9PXBzJiYoMD09PWV8fGU+PXBzKTspcHIobHMscHMsITEpLG9yKCk7bnVsbCE9PWdzJiYoc3M9MCx1cz0tMSksMCE9PXBzJiZycihwcyksZ3M9bnVsbCxkcz0hMSxscigpfWZ1bmN0aW9uIGNyKGUsdCl7Y3MmJnIoIjI1MyIpLGxzPWUscHM9dCxwcihlLHQsITEpLHNyKCksbHIoKX1mdW5jdGlvbiBscigpe2lmKEVzPTAsbnVsbCE9PXhzKXt2YXIgZT14czt4cz1udWxsO2Zvcih2YXIgdD0wO3Q8ZS5sZW5ndGg7dCsrKXt2YXIgbj1lW3RdO3RyeXtuLl9vbkNvbXBsZXRlKCl9Y2F0Y2goZSl7aHN8fChocz0hMCxtcz1lKX19fWlmKGhzKXRocm93IGU9bXMsbXM9bnVsbCxocz0hMSxlfWZ1bmN0aW9uIHByKGUsdCxuKXtjcyYmcigiMjQ1IiksY3M9ITAsbj8obj1lLmZpbmlzaGVkV29yayxudWxsIT09bj9mcihlLG4sdCk6KGUuZmluaXNoZWRXb3JrPW51bGwsbnVsbCE9PShuPUtuKGUsdCwhMCkpJiYoZHIoKT9lLmZpbmlzaGVkV29yaz1uOmZyKGUsbix0KSkpKToobj1lLmZpbmlzaGVkV29yayxudWxsIT09bj9mcihlLG4sdCk6KGUuZmluaXNoZWRXb3JrPW51bGwsbnVsbCE9PShuPUtuKGUsdCwhMSkpJiZmcihlLG4sdCkpKSxjcz0hMX1mdW5jdGlvbiBmcihlLHQsbil7dmFyIGk9ZS5maXJzdEJhdGNoO2lmKG51bGwhPT1pJiZpLl9leHBpcmF0aW9uVGltZTw9biYmKG51bGw9PT14cz94cz1baV06eHMucHVzaChpKSxpLl9kZWZlcikpcmV0dXJuIGUuZmluaXNoZWRXb3JrPXQsdm9pZChlLnJlbWFpbmluZ0V4cGlyYXRpb25UaW1lPTApO2lmKGUuZmluaXNoZWRXb3JrPW51bGwsbnM9S2E9ITAsbj10LnN0YXRlTm9kZSxuLmN1cnJlbnQ9PT10JiZyKCIxNzciKSxpPW4ucGVuZGluZ0NvbW1pdEV4cGlyYXRpb25UaW1lLDA9PT1pJiZyKCIyNjEiKSxuLnBlbmRpbmdDb21taXRFeHBpcmF0aW9uVGltZT0wLGVyKCksUmkuY3VycmVudD1udWxsLDE8dC5lZmZlY3RUYWcpaWYobnVsbCE9PXQubGFzdEVmZmVjdCl7dC5sYXN0RWZmZWN0Lm5leHRFZmZlY3Q9dDt2YXIgbz10LmZpcnN0RWZmZWN0fWVsc2Ugbz10O2Vsc2Ugbz10LmZpcnN0RWZmZWN0O2hhPU9vO3ZhciBhPVJyKCk7aWYoS2UoYSkpe2lmKCJzZWxlY3Rpb25TdGFydCJpbiBhKXZhciBzPXtzdGFydDphLnNlbGVjdGlvblN0YXJ0LGVuZDphLnNlbGVjdGlvbkVuZH07ZWxzZSBlOnt2YXIgdT13aW5kb3cuZ2V0U2VsZWN0aW9uJiZ3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7aWYodSYmMCE9PXUucmFuZ2VDb3VudCl7cz11LmFuY2hvck5vZGU7dmFyIGM9dS5hbmNob3JPZmZzZXQsbD11LmZvY3VzTm9kZTt1PXUuZm9jdXNPZmZzZXQ7dHJ5e3Mubm9kZVR5cGUsbC5ub2RlVHlwZX1jYXRjaChlKXtzPW51bGw7YnJlYWsgZX12YXIgcD0wLGY9LTEsZD0tMSxoPTAsbT0wLGc9YSx5PW51bGw7dDpmb3IoOzspe2Zvcih2YXIgdjtnIT09c3x8MCE9PWMmJjMhPT1nLm5vZGVUeXBlfHwoZj1wK2MpLGchPT1sfHwwIT09dSYmMyE9PWcubm9kZVR5cGV8fChkPXArdSksMz09PWcubm9kZVR5cGUmJihwKz1nLm5vZGVWYWx1ZS5sZW5ndGgpLG51bGwhPT0odj1nLmZpcnN0Q2hpbGQpOyl5PWcsZz12O2Zvcig7Oyl7aWYoZz09PWEpYnJlYWsgdDtpZih5PT09cyYmKytoPT09YyYmKGY9cCkseT09PWwmJisrbT09PXUmJihkPXApLG51bGwhPT0odj1nLm5leHRTaWJsaW5nKSlicmVhaztnPXkseT1nLnBhcmVudE5vZGV9Zz12fXM9LTE9PT1mfHwtMT09PWQ/bnVsbDp7c3RhcnQ6ZixlbmQ6ZH19ZWxzZSBzPW51bGx9cz1zfHx7c3RhcnQ6MCxlbmQ6MH19ZWxzZSBzPW51bGw7Zm9yKG1hPXtmb2N1c2VkRWxlbTphLHNlbGVjdGlvblJhbmdlOnN9LFVlKCExKSx0cz1vO251bGwhPT10czspe2E9ITEscz12b2lkIDA7dHJ5e2Zvcig7bnVsbCE9PXRzOyl7aWYoMjU2JnRzLmVmZmVjdFRhZyl7dmFyIGI9dHMuYWx0ZXJuYXRlO3N3aXRjaChjPXRzLGMudGFnKXtjYXNlIDI6aWYoMjU2JmMuZWZmZWN0VGFnJiZudWxsIT09Yil7dmFyIHg9Yi5tZW1vaXplZFByb3BzLEM9Yi5tZW1vaXplZFN0YXRlLEU9Yy5zdGF0ZU5vZGU7RS5wcm9wcz1jLm1lbW9pemVkUHJvcHMsRS5zdGF0ZT1jLm1lbW9pemVkU3RhdGU7dmFyIEQ9RS5nZXRTbmFwc2hvdEJlZm9yZVVwZGF0ZSh4LEMpO0UuX19yZWFjdEludGVybmFsU25hcHNob3RCZWZvcmVVcGRhdGU9RH1icmVhaztjYXNlIDM6Y2FzZSA1OmNhc2UgNjpjYXNlIDQ6YnJlYWs7ZGVmYXVsdDpyKCIxNjMiKX19dHM9dHMubmV4dEVmZmVjdH19Y2F0Y2goZSl7YT0hMCxzPWV9YSYmKG51bGw9PT10cyYmcigiMTc4IiksSm4odHMscyksbnVsbCE9PXRzJiYodHM9dHMubmV4dEVmZmVjdCkpfWZvcih0cz1vO251bGwhPT10czspe2I9ITEseD12b2lkIDA7dHJ5e2Zvcig7bnVsbCE9PXRzOyl7dmFyIHc9dHMuZWZmZWN0VGFnO2lmKDE2JncmJnN0KHRzLnN0YXRlTm9kZSwiIiksMTI4Jncpe3ZhciBTPXRzLmFsdGVybmF0ZTtpZihudWxsIT09Uyl7dmFyIGs9Uy5yZWY7bnVsbCE9PWsmJigiZnVuY3Rpb24iPT09dHlwZW9mIGs/ayhudWxsKTprLmN1cnJlbnQ9bnVsbCl9fXN3aXRjaCgxNCZ3KXtjYXNlIDI6Qm4odHMpLHRzLmVmZmVjdFRhZyY9LTM7YnJlYWs7Y2FzZSA2OkJuKHRzKSx0cy5lZmZlY3RUYWcmPS0zLFVuKHRzLmFsdGVybmF0ZSx0cyk7YnJlYWs7Y2FzZSA0OlVuKHRzLmFsdGVybmF0ZSx0cyk7YnJlYWs7Y2FzZSA4OkM9dHMsJG4oQyksQy5yZXR1cm49bnVsbCxDLmNoaWxkPW51bGwsQy5hbHRlcm5hdGUmJihDLmFsdGVybmF0ZS5jaGlsZD1udWxsLEMuYWx0ZXJuYXRlLnJldHVybj1udWxsKX10cz10cy5uZXh0RWZmZWN0fX1jYXRjaChlKXtiPSEwLHg9ZX1iJiYobnVsbD09PXRzJiZyKCIxNzgiKSxKbih0cyx4KSxudWxsIT09dHMmJih0cz10cy5uZXh0RWZmZWN0KSl9aWYoaz1tYSxTPVJyKCksdz1rLmZvY3VzZWRFbGVtLGI9ay5zZWxlY3Rpb25SYW5nZSxTIT09dyYmJHIoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LHcpKXtLZSh3KSYmKFM9Yi5zdGFydCxrPWIuZW5kLHZvaWQgMD09PWsmJihrPVMpLCJzZWxlY3Rpb25TdGFydCJpbiB3Pyh3LnNlbGVjdGlvblN0YXJ0PVMsdy5zZWxlY3Rpb25FbmQ9TWF0aC5taW4oayx3LnZhbHVlLmxlbmd0aCkpOndpbmRvdy5nZXRTZWxlY3Rpb24mJihTPXdpbmRvdy5nZXRTZWxlY3Rpb24oKSx4PXdbSSgpXS5sZW5ndGgsaz1NYXRoLm1pbihiLnN0YXJ0LHgpLGI9dm9pZCAwPT09Yi5lbmQ/azpNYXRoLm1pbihiLmVuZCx4KSwhUy5leHRlbmQmJms+YiYmKHg9YixiPWssaz14KSx4PVFlKHcsayksQz1RZSh3LGIpLHgmJkMmJigxIT09Uy5yYW5nZUNvdW50fHxTLmFuY2hvck5vZGUhPT14Lm5vZGV8fFMuYW5jaG9yT2Zmc2V0IT09eC5vZmZzZXR8fFMuZm9jdXNOb2RlIT09Qy5ub2RlfHxTLmZvY3VzT2Zmc2V0IT09Qy5vZmZzZXQpJiYoRT1kb2N1bWVudC5jcmVhdGVSYW5nZSgpLEUuc2V0U3RhcnQoeC5ub2RlLHgub2Zmc2V0KSxTLnJlbW92ZUFsbFJhbmdlcygpLGs+Yj8oUy5hZGRSYW5nZShFKSxTLmV4dGVuZChDLm5vZGUsQy5vZmZzZXQpKTooRS5zZXRFbmQoQy5ub2RlLEMub2Zmc2V0KSxTLmFkZFJhbmdlKEUpKSkpKSxTPVtdO2ZvcihrPXc7az1rLnBhcmVudE5vZGU7KTE9PT1rLm5vZGVUeXBlJiZTLnB1c2goe2VsZW1lbnQ6ayxsZWZ0Omsuc2Nyb2xsTGVmdCx0b3A6ay5zY3JvbGxUb3B9KTtmb3Iody5mb2N1cygpLHc9MDt3PFMubGVuZ3RoO3crKylrPVNbd10say5lbGVtZW50LnNjcm9sbExlZnQ9ay5sZWZ0LGsuZWxlbWVudC5zY3JvbGxUb3A9ay50b3B9Zm9yKG1hPW51bGwsVWUoaGEpLGhhPW51bGwsbi5jdXJyZW50PXQsdHM9bztudWxsIT09dHM7KXtvPSExLHc9dm9pZCAwO3RyeXtmb3IoUz1pO251bGwhPT10czspe3ZhciBBPXRzLmVmZmVjdFRhZztpZigzNiZBKXt2YXIgXz10cy5hbHRlcm5hdGU7c3dpdGNoKGs9dHMsYj1TLGsudGFnKXtjYXNlIDI6dmFyIFQ9ay5zdGF0ZU5vZGU7aWYoNCZrLmVmZmVjdFRhZylpZihudWxsPT09XylULnByb3BzPWsubWVtb2l6ZWRQcm9wcyxULnN0YXRlPWsubWVtb2l6ZWRTdGF0ZSxULmNvbXBvbmVudERpZE1vdW50KCk7ZWxzZXt2YXIgTz1fLm1lbW9pemVkUHJvcHMsRj1fLm1lbW9pemVkU3RhdGU7VC5wcm9wcz1rLm1lbW9pemVkUHJvcHMsVC5zdGF0ZT1rLm1lbW9pemVkU3RhdGUsVC5jb21wb25lbnREaWRVcGRhdGUoTyxGLFQuX19yZWFjdEludGVybmFsU25hcHNob3RCZWZvcmVVcGRhdGUpfXZhciBOPWsudXBkYXRlUXVldWU7bnVsbCE9PU4mJihULnByb3BzPWsubWVtb2l6ZWRQcm9wcyxULnN0YXRlPWsubWVtb2l6ZWRTdGF0ZSxubihrLE4sVCxiKSk7YnJlYWs7Y2FzZSAzOnZhciBMPWsudXBkYXRlUXVldWU7aWYobnVsbCE9PUwpe2lmKHg9bnVsbCxudWxsIT09ay5jaGlsZClzd2l0Y2goay5jaGlsZC50YWcpe2Nhc2UgNTp4PWsuY2hpbGQuc3RhdGVOb2RlO2JyZWFrO2Nhc2UgMjp4PWsuY2hpbGQuc3RhdGVOb2RlfW5uKGssTCx4LGIpfWJyZWFrO2Nhc2UgNTp2YXIgUD1rLnN0YXRlTm9kZTtudWxsPT09XyYmNCZrLmVmZmVjdFRhZyYmYnQoay50eXBlLGsubWVtb2l6ZWRQcm9wcykmJlAuZm9jdXMoKTticmVhaztjYXNlIDY6Y2FzZSA0OmNhc2UgMTU6Y2FzZSAxNjpicmVhaztkZWZhdWx0OnIoIjE2MyIpfX1pZigxMjgmQSl7az12b2lkIDA7dmFyIE09dHMucmVmO2lmKG51bGwhPT1NKXt2YXIgaj10cy5zdGF0ZU5vZGU7c3dpdGNoKHRzLnRhZyl7Y2FzZSA1Oms9ajticmVhaztkZWZhdWx0Oms9an0iZnVuY3Rpb24iPT09dHlwZW9mIE0/TShrKTpNLmN1cnJlbnQ9a319dmFyIFI9dHMubmV4dEVmZmVjdDt0cy5uZXh0RWZmZWN0PW51bGwsdHM9Un19Y2F0Y2goZSl7bz0hMCx3PWV9byYmKG51bGw9PT10cyYmcigiMTc4IiksSm4odHMsdyksbnVsbCE9PXRzJiYodHM9dHMubmV4dEVmZmVjdCkpfUthPW5zPSExLCJmdW5jdGlvbiI9PT10eXBlb2YgVnQmJlZ0KHQuc3RhdGVOb2RlKSx0PW4uY3VycmVudC5leHBpcmF0aW9uVGltZSwwPT09dCYmKGlzPW51bGwpLGUucmVtYWluaW5nRXhwaXJhdGlvblRpbWU9dH1mdW5jdGlvbiBkcigpe3JldHVybiEobnVsbD09PWdzfHxncy50aW1lUmVtYWluaW5nKCk+RHMpJiYoZHM9ITApfWZ1bmN0aW9uIGhyKGUpe251bGw9PT1scyYmcigiMjQ2IiksbHMucmVtYWluaW5nRXhwaXJhdGlvblRpbWU9MCxoc3x8KGhzPSEwLG1zPWUpfWZ1bmN0aW9uIG1yKGUpe251bGw9PT1scyYmcigiMjQ2IiksbHMucmVtYWluaW5nRXhwaXJhdGlvblRpbWU9ZX1mdW5jdGlvbiBncihlLHQpe3ZhciBuPXlzO3lzPSEwO3RyeXtyZXR1cm4gZSh0KX1maW5hbGx5eyh5cz1uKXx8Y3N8fHNyKCl9fWZ1bmN0aW9uIHlyKGUsdCl7aWYoeXMmJiF2cyl7dnM9ITA7dHJ5e3JldHVybiBlKHQpfWZpbmFsbHl7dnM9ITF9fXJldHVybiBlKHQpfWZ1bmN0aW9uIHZyKGUsdCl7Y3MmJnIoIjE4NyIpO3ZhciBuPXlzO3lzPSEwO3RyeXtyZXR1cm4gbnIoZSx0KX1maW5hbGx5e3lzPW4sc3IoKX19ZnVuY3Rpb24gYnIoZSl7dmFyIHQ9eXM7eXM9ITA7dHJ5e25yKGUpfWZpbmFsbHl7KHlzPXQpfHxjc3x8dXIoMSwhMSxudWxsKX19ZnVuY3Rpb24geHIoZSx0LG4saSxvKXt2YXIgYT10LmN1cnJlbnQ7aWYobil7bj1uLl9yZWFjdEludGVybmFsRmliZXI7dmFyIHM7ZTp7Zm9yKDI9PT1JZShuKSYmMj09PW4udGFnfHxyKCIxNzAiKSxzPW47MyE9PXMudGFnOyl7aWYoX3Qocykpe3M9cy5zdGF0ZU5vZGUuX19yZWFjdEludGVybmFsTWVtb2l6ZWRNZXJnZWRDaGlsZENvbnRleHQ7YnJlYWsgZX0ocz1zLnJldHVybil8fHIoIjE3MSIpfXM9cy5zdGF0ZU5vZGUuY29udGV4dH1uPV90KG4pP050KG4scyk6c31lbHNlIG49VXI7cmV0dXJuIG51bGw9PT10LmNvbnRleHQ/dC5jb250ZXh0PW46dC5wZW5kaW5nQ29udGV4dD1uLHQ9byxvPVF0KGkpLG8ucGF5bG9hZD17ZWxlbWVudDplfSx0PXZvaWQgMD09PXQ/bnVsbDp0LG51bGwhPT10JiYoby5jYWxsYmFjaz10KSxKdChhLG8saSksWm4oYSxpKSxpfWZ1bmN0aW9uIENyKGUpe3ZhciB0PWUuX3JlYWN0SW50ZXJuYWxGaWJlcjtyZXR1cm4gdm9pZCAwPT09dCYmKCJmdW5jdGlvbiI9PT10eXBlb2YgZS5yZW5kZXI/cigiMTg4Iik6cigiMjY4IixPYmplY3Qua2V5cyhlKSkpLGU9TWUodCksbnVsbD09PWU/bnVsbDplLnN0YXRlTm9kZX1mdW5jdGlvbiBFcihlLHQsbixyKXt2YXIgaT10LmN1cnJlbnQ7cmV0dXJuIGk9WG4oZXIoKSxpKSx4cihlLHQsbixpLHIpfWZ1bmN0aW9uIERyKGUpe2lmKGU9ZS5jdXJyZW50LCFlLmNoaWxkKXJldHVybiBudWxsO3N3aXRjaChlLmNoaWxkLnRhZyl7Y2FzZSA1OmRlZmF1bHQ6cmV0dXJuIGUuY2hpbGQuc3RhdGVOb2RlfX1mdW5jdGlvbiB3cihlKXt2YXIgdD1lLmZpbmRGaWJlckJ5SG9zdEluc3RhbmNlO3JldHVybiBHdChNcih7fSxlLHtmaW5kSG9zdEluc3RhbmNlQnlGaWJlcjpmdW5jdGlvbihlKXtyZXR1cm4gZT1NZShlKSxudWxsPT09ZT9udWxsOmUuc3RhdGVOb2RlfSxmaW5kRmliZXJCeUhvc3RJbnN0YW5jZTpmdW5jdGlvbihlKXtyZXR1cm4gdD90KGUpOm51bGx9fSkpfWZ1bmN0aW9uIFNyKGUsdCxuKXt2YXIgcj0zPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1szXT9hcmd1bWVudHNbM106bnVsbDtyZXR1cm57JCR0eXBlb2Y6VWksa2V5Om51bGw9PXI/bnVsbDoiIityLGNoaWxkcmVuOmUsY29udGFpbmVySW5mbzp0LGltcGxlbWVudGF0aW9uOm59fWZ1bmN0aW9uIGtyKGUpe3RoaXMuX2V4cGlyYXRpb25UaW1lPVluKCksdGhpcy5fcm9vdD1lLHRoaXMuX2NhbGxiYWNrcz10aGlzLl9uZXh0PW51bGwsdGhpcy5faGFzQ2hpbGRyZW49dGhpcy5fZGlkQ29tcGxldGU9ITEsdGhpcy5fY2hpbGRyZW49bnVsbCx0aGlzLl9kZWZlcj0hMH1mdW5jdGlvbiBBcigpe3RoaXMuX2NhbGxiYWNrcz1udWxsLHRoaXMuX2RpZENvbW1pdD0hMSx0aGlzLl9vbkNvbW1pdD10aGlzLl9vbkNvbW1pdC5iaW5kKHRoaXMpfWZ1bmN0aW9uIF9yKGUsdCxuKXt0aGlzLl9pbnRlcm5hbFJvb3Q9VXQoZSx0LG4pfWZ1bmN0aW9uIFRyKGUpe3JldHVybiEoIWV8fDEhPT1lLm5vZGVUeXBlJiY5IT09ZS5ub2RlVHlwZSYmMTEhPT1lLm5vZGVUeXBlJiYoOCE9PWUubm9kZVR5cGV8fCIgcmVhY3QtbW91bnQtcG9pbnQtdW5zdGFibGUgIiE9PWUubm9kZVZhbHVlKSl9ZnVuY3Rpb24gT3IoZSx0KXtpZih0fHwodD1lPzk9PT1lLm5vZGVUeXBlP2UuZG9jdW1lbnRFbGVtZW50OmUuZmlyc3RDaGlsZDpudWxsLHQ9ISghdHx8MSE9PXQubm9kZVR5cGV8fCF0Lmhhc0F0dHJpYnV0ZSgiZGF0YS1yZWFjdHJvb3QiKSkpLCF0KWZvcih2YXIgbjtuPWUubGFzdENoaWxkOyllLnJlbW92ZUNoaWxkKG4pO3JldHVybiBuZXcgX3IoZSwhMSx0KX1mdW5jdGlvbiBGcihlLHQsbixpLG8pe1RyKG4pfHxyKCIyMDAiKTt2YXIgYT1uLl9yZWFjdFJvb3RDb250YWluZXI7aWYoYSl7aWYoImZ1bmN0aW9uIj09PXR5cGVvZiBvKXt2YXIgcz1vO289ZnVuY3Rpb24oKXt2YXIgZT1EcihhLl9pbnRlcm5hbFJvb3QpO3MuY2FsbChlKX19bnVsbCE9ZT9hLmxlZ2FjeV9yZW5kZXJTdWJ0cmVlSW50b0NvbnRhaW5lcihlLHQsbyk6YS5yZW5kZXIodCxvKX1lbHNle2lmKGE9bi5fcmVhY3RSb290Q29udGFpbmVyPU9yKG4saSksImZ1bmN0aW9uIj09PXR5cGVvZiBvKXt2YXIgdT1vO289ZnVuY3Rpb24oKXt2YXIgZT1EcihhLl9pbnRlcm5hbFJvb3QpO3UuY2FsbChlKX19eXIoZnVuY3Rpb24oKXtudWxsIT1lP2EubGVnYWN5X3JlbmRlclN1YnRyZWVJbnRvQ29udGFpbmVyKGUsdCxvKTphLnJlbmRlcih0LG8pfSl9cmV0dXJuIERyKGEuX2ludGVybmFsUm9vdCl9ZnVuY3Rpb24gTnIoZSx0KXt2YXIgbj0yPGFyZ3VtZW50cy5sZW5ndGgmJnZvaWQgMCE9PWFyZ3VtZW50c1syXT9hcmd1bWVudHNbMl06bnVsbDtyZXR1cm4gVHIodCl8fHIoIjIwMCIpLFNyKGUsdCxudWxsLG4pfXZhciBJcj1uKDk5KSxMcj1uKDApLFByPW4oMzE1KSxNcj1uKDU0KSxqcj1uKDEwMCksUnI9bigzMTYpLEJyPW4oMzE3KSwkcj1uKDMxOCksVXI9bigxNTIpO0xyfHxyKCIyMjciKTt2YXIgenI9e19jYXVnaHRFcnJvcjpudWxsLF9oYXNDYXVnaHRFcnJvcjohMSxfcmV0aHJvd0Vycm9yOm51bGwsX2hhc1JldGhyb3dFcnJvcjohMSxpbnZva2VHdWFyZGVkQ2FsbGJhY2s6ZnVuY3Rpb24oZSx0LG4scixvLGEscyx1LGMpe2kuYXBwbHkoenIsYXJndW1lbnRzKX0saW52b2tlR3VhcmRlZENhbGxiYWNrQW5kQ2F0Y2hGaXJzdEVycm9yOmZ1bmN0aW9uKGUsdCxuLHIsaSxvLGEscyx1KXtpZih6ci5pbnZva2VHdWFyZGVkQ2FsbGJhY2suYXBwbHkodGhpcyxhcmd1bWVudHMpLHpyLmhhc0NhdWdodEVycm9yKCkpe3ZhciBjPXpyLmNsZWFyQ2F1Z2h0RXJyb3IoKTt6ci5faGFzUmV0aHJvd0Vycm9yfHwoenIuX2hhc1JldGhyb3dFcnJvcj0hMCx6ci5fcmV0aHJvd0Vycm9yPWMpfX0scmV0aHJvd0NhdWdodEVycm9yOmZ1bmN0aW9uKCl7cmV0dXJuIG8uYXBwbHkoenIsYXJndW1lbnRzKX0saGFzQ2F1Z2h0RXJyb3I6ZnVuY3Rpb24oKXtyZXR1cm4genIuX2hhc0NhdWdodEVycm9yfSxjbGVhckNhdWdodEVycm9yOmZ1bmN0aW9uKCl7aWYoenIuX2hhc0NhdWdodEVycm9yKXt2YXIgZT16ci5fY2F1Z2h0RXJyb3I7cmV0dXJuIHpyLl9jYXVnaHRFcnJvcj1udWxsLHpyLl9oYXNDYXVnaHRFcnJvcj0hMSxlfXIoIjE5OCIpfX0sR3I9bnVsbCxWcj17fSxxcj1bXSxIcj17fSxXcj17fSxRcj17fSxLcj17cGx1Z2luczpxcixldmVudE5hbWVEaXNwYXRjaENvbmZpZ3M6SHIscmVnaXN0cmF0aW9uTmFtZU1vZHVsZXM6V3IscmVnaXN0cmF0aW9uTmFtZURlcGVuZGVuY2llczpRcixwb3NzaWJsZVJlZ2lzdHJhdGlvbk5hbWVzOm51bGwsaW5qZWN0RXZlbnRQbHVnaW5PcmRlcjp1LGluamVjdEV2ZW50UGx1Z2luc0J5TmFtZTpjfSxKcj1udWxsLFlyPW51bGwsWHI9bnVsbCxacj1udWxsLGVpPXtpbmplY3RFdmVudFBsdWdpbk9yZGVyOnUsaW5qZWN0RXZlbnRQbHVnaW5zQnlOYW1lOmN9LHRpPXtpbmplY3Rpb246ZWksZ2V0TGlzdGVuZXI6ZyxydW5FdmVudHNJbkJhdGNoOnkscnVuRXh0cmFjdGVkRXZlbnRzSW5CYXRjaDp2fSxuaT1NYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zbGljZSgyKSxyaT0iX19yZWFjdEludGVybmFsSW5zdGFuY2UkIituaSxpaT0iX19yZWFjdEV2ZW50SGFuZGxlcnMkIituaSxvaT17cHJlY2FjaGVGaWJlck5vZGU6ZnVuY3Rpb24oZSx0KXt0W3JpXT1lfSxnZXRDbG9zZXN0SW5zdGFuY2VGcm9tTm9kZTpiLGdldEluc3RhbmNlRnJvbU5vZGU6ZnVuY3Rpb24oZSl7cmV0dXJuIGU9ZVtyaV0sIWV8fDUhPT1lLnRhZyYmNiE9PWUudGFnP251bGw6ZX0sZ2V0Tm9kZUZyb21JbnN0YW5jZTp4LGdldEZpYmVyQ3VycmVudFByb3BzRnJvbU5vZGU6Qyx1cGRhdGVGaWJlclByb3BzOmZ1bmN0aW9uKGUsdCl7ZVtpaV09dH19LGFpPXthY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzOlQsYWNjdW11bGF0ZVR3b1BoYXNlRGlzcGF0Y2hlc1NraXBUYXJnZXQ6ZnVuY3Rpb24oZSl7ZihlLGspfSxhY2N1bXVsYXRlRW50ZXJMZWF2ZURpc3BhdGNoZXM6TyxhY2N1bXVsYXRlRGlyZWN0RGlzcGF0Y2hlczpmdW5jdGlvbihlKXtmKGUsXyl9fSxzaT17YW5pbWF0aW9uZW5kOkYoIkFuaW1hdGlvbiIsIkFuaW1hdGlvbkVuZCIpLGFuaW1hdGlvbml0ZXJhdGlvbjpGKCJBbmltYXRpb24iLCJBbmltYXRpb25JdGVyYXRpb24iKSxhbmltYXRpb25zdGFydDpGKCJBbmltYXRpb24iLCJBbmltYXRpb25TdGFydCIpLHRyYW5zaXRpb25lbmQ6RigiVHJhbnNpdGlvbiIsIlRyYW5zaXRpb25FbmQiKX0sdWk9e30sY2k9e307UHIuY2FuVXNlRE9NJiYoY2k9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iikuc3R5bGUsIkFuaW1hdGlvbkV2ZW50ImluIHdpbmRvd3x8KGRlbGV0ZSBzaS5hbmltYXRpb25lbmQuYW5pbWF0aW9uLGRlbGV0ZSBzaS5hbmltYXRpb25pdGVyYXRpb24uYW5pbWF0aW9uLGRlbGV0ZSBzaS5hbmltYXRpb25zdGFydC5hbmltYXRpb24pLCJUcmFuc2l0aW9uRXZlbnQiaW4gd2luZG93fHxkZWxldGUgc2kudHJhbnNpdGlvbmVuZC50cmFuc2l0aW9uKTt2YXIgbGk9TigiYW5pbWF0aW9uZW5kIikscGk9TigiYW5pbWF0aW9uaXRlcmF0aW9uIiksZmk9TigiYW5pbWF0aW9uc3RhcnQiKSxkaT1OKCJ0cmFuc2l0aW9uZW5kIiksaGk9ImFib3J0IGNhbnBsYXkgY2FucGxheXRocm91Z2ggZHVyYXRpb25jaGFuZ2UgZW1wdGllZCBlbmNyeXB0ZWQgZW5kZWQgZXJyb3IgbG9hZGVkZGF0YSBsb2FkZWRtZXRhZGF0YSBsb2Fkc3RhcnQgcGF1c2UgcGxheSBwbGF5aW5nIHByb2dyZXNzIHJhdGVjaGFuZ2Ugc2Vla2VkIHNlZWtpbmcgc3RhbGxlZCBzdXNwZW5kIHRpbWV1cGRhdGUgdm9sdW1lY2hhbmdlIHdhaXRpbmciLnNwbGl0KCIgIiksbWk9bnVsbCxnaT17X3Jvb3Q6bnVsbCxfc3RhcnRUZXh0Om51bGwsX2ZhbGxiYWNrVGV4dDpudWxsfSx5aT0iZGlzcGF0Y2hDb25maWcgX3RhcmdldEluc3QgbmF0aXZlRXZlbnQgaXNEZWZhdWx0UHJldmVudGVkIGlzUHJvcGFnYXRpb25TdG9wcGVkIF9kaXNwYXRjaExpc3RlbmVycyBfZGlzcGF0Y2hJbnN0YW5jZXMiLnNwbGl0KCIgIiksdmk9e3R5cGU6bnVsbCx0YXJnZXQ6bnVsbCxjdXJyZW50VGFyZ2V0OmpyLnRoYXRSZXR1cm5zTnVsbCxldmVudFBoYXNlOm51bGwsYnViYmxlczpudWxsLGNhbmNlbGFibGU6bnVsbCx0aW1lU3RhbXA6ZnVuY3Rpb24oZSl7cmV0dXJuIGUudGltZVN0YW1wfHxEYXRlLm5vdygpfSxkZWZhdWx0UHJldmVudGVkOm51bGwsaXNUcnVzdGVkOm51bGx9O01yKE0ucHJvdG90eXBlLHtwcmV2ZW50RGVmYXVsdDpmdW5jdGlvbigpe3RoaXMuZGVmYXVsdFByZXZlbnRlZD0hMDt2YXIgZT10aGlzLm5hdGl2ZUV2ZW50O2UmJihlLnByZXZlbnREZWZhdWx0P2UucHJldmVudERlZmF1bHQoKToidW5rbm93biIhPT10eXBlb2YgZS5yZXR1cm5WYWx1ZSYmKGUucmV0dXJuVmFsdWU9ITEpLHRoaXMuaXNEZWZhdWx0UHJldmVudGVkPWpyLnRoYXRSZXR1cm5zVHJ1ZSl9LHN0b3BQcm9wYWdhdGlvbjpmdW5jdGlvbigpe3ZhciBlPXRoaXMubmF0aXZlRXZlbnQ7ZSYmKGUuc3RvcFByb3BhZ2F0aW9uP2Uuc3RvcFByb3BhZ2F0aW9uKCk6InVua25vd24iIT09dHlwZW9mIGUuY2FuY2VsQnViYmxlJiYoZS5jYW5jZWxCdWJibGU9ITApLHRoaXMuaXNQcm9wYWdhdGlvblN0b3BwZWQ9anIudGhhdFJldHVybnNUcnVlKX0scGVyc2lzdDpmdW5jdGlvbigpe3RoaXMuaXNQZXJzaXN0ZW50PWpyLnRoYXRSZXR1cm5zVHJ1ZX0saXNQZXJzaXN0ZW50OmpyLnRoYXRSZXR1cm5zRmFsc2UsZGVzdHJ1Y3RvcjpmdW5jdGlvbigpe3ZhciBlLHQ9dGhpcy5jb25zdHJ1Y3Rvci5JbnRlcmZhY2U7Zm9yKGUgaW4gdCl0aGlzW2VdPW51bGw7Zm9yKHQ9MDt0PHlpLmxlbmd0aDt0KyspdGhpc1t5aVt0XV09bnVsbH19KSxNLkludGVyZmFjZT12aSxNLmV4dGVuZD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7fWZ1bmN0aW9uIG4oKXtyZXR1cm4gci5hcHBseSh0aGlzLGFyZ3VtZW50cyl9dmFyIHI9dGhpczt0LnByb3RvdHlwZT1yLnByb3RvdHlwZTt2YXIgaT1uZXcgdDtyZXR1cm4gTXIoaSxuLnByb3RvdHlwZSksbi5wcm90b3R5cGU9aSxuLnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj1uLG4uSW50ZXJmYWNlPU1yKHt9LHIuSW50ZXJmYWNlLGUpLG4uZXh0ZW5kPXIuZXh0ZW5kLEIobiksbn0sQihNKTt2YXIgYmk9TS5leHRlbmQoe2RhdGE6bnVsbH0pLHhpPU0uZXh0ZW5kKHtkYXRhOm51bGx9KSxDaT1bOSwxMywyNywzMl0sRWk9UHIuY2FuVXNlRE9NJiYiQ29tcG9zaXRpb25FdmVudCJpbiB3aW5kb3csRGk9bnVsbDtQci5jYW5Vc2VET00mJiJkb2N1bWVudE1vZGUiaW4gZG9jdW1lbnQmJihEaT1kb2N1bWVudC5kb2N1bWVudE1vZGUpO3ZhciB3aT1Qci5jYW5Vc2VET00mJiJUZXh0RXZlbnQiaW4gd2luZG93JiYhRGksU2k9UHIuY2FuVXNlRE9NJiYoIUVpfHxEaSYmODxEaSYmMTE+PURpKSxraT1TdHJpbmcuZnJvbUNoYXJDb2RlKDMyKSxBaT17YmVmb3JlSW5wdXQ6e3BoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOntidWJibGVkOiJvbkJlZm9yZUlucHV0IixjYXB0dXJlZDoib25CZWZvcmVJbnB1dENhcHR1cmUifSxkZXBlbmRlbmNpZXM6WyJjb21wb3NpdGlvbmVuZCIsImtleXByZXNzIiwidGV4dElucHV0IiwicGFzdGUiXX0sY29tcG9zaXRpb25FbmQ6e3BoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOntidWJibGVkOiJvbkNvbXBvc2l0aW9uRW5kIixjYXB0dXJlZDoib25Db21wb3NpdGlvbkVuZENhcHR1cmUifSxkZXBlbmRlbmNpZXM6ImJsdXIgY29tcG9zaXRpb25lbmQga2V5ZG93biBrZXlwcmVzcyBrZXl1cCBtb3VzZWRvd24iLnNwbGl0KCIgIil9LGNvbXBvc2l0aW9uU3RhcnQ6e3BoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOntidWJibGVkOiJvbkNvbXBvc2l0aW9uU3RhcnQiLGNhcHR1cmVkOiJvbkNvbXBvc2l0aW9uU3RhcnRDYXB0dXJlIn0sZGVwZW5kZW5jaWVzOiJibHVyIGNvbXBvc2l0aW9uc3RhcnQga2V5ZG93biBrZXlwcmVzcyBrZXl1cCBtb3VzZWRvd24iLnNwbGl0KCIgIil9LGNvbXBvc2l0aW9uVXBkYXRlOntwaGFzZWRSZWdpc3RyYXRpb25OYW1lczp7YnViYmxlZDoib25Db21wb3NpdGlvblVwZGF0ZSIsY2FwdHVyZWQ6Im9uQ29tcG9zaXRpb25VcGRhdGVDYXB0dXJlIn0sZGVwZW5kZW5jaWVzOiJibHVyIGNvbXBvc2l0aW9udXBkYXRlIGtleWRvd24ga2V5cHJlc3Mga2V5dXAgbW91c2Vkb3duIi5zcGxpdCgiICIpfX0sX2k9ITEsVGk9ITEsT2k9e2V2ZW50VHlwZXM6QWksZXh0cmFjdEV2ZW50czpmdW5jdGlvbihlLHQsbixyKXt2YXIgaT12b2lkIDAsbz12b2lkIDA7aWYoRWkpZTp7c3dpdGNoKGUpe2Nhc2UiY29tcG9zaXRpb25zdGFydCI6aT1BaS5jb21wb3NpdGlvblN0YXJ0O2JyZWFrIGU7Y2FzZSJjb21wb3NpdGlvbmVuZCI6aT1BaS5jb21wb3NpdGlvbkVuZDticmVhayBlO2Nhc2UiY29tcG9zaXRpb251cGRhdGUiOmk9QWkuY29tcG9zaXRpb25VcGRhdGU7YnJlYWsgZX1pPXZvaWQgMH1lbHNlIFRpPyQoZSxuKSYmKGk9QWkuY29tcG9zaXRpb25FbmQpOiJrZXlkb3duIj09PWUmJjIyOT09PW4ua2V5Q29kZSYmKGk9QWkuY29tcG9zaXRpb25TdGFydCk7cmV0dXJuIGk/KFNpJiYoVGl8fGkhPT1BaS5jb21wb3NpdGlvblN0YXJ0P2k9PT1BaS5jb21wb3NpdGlvbkVuZCYmVGkmJihvPUwoKSk6KGdpLl9yb290PXIsZ2kuX3N0YXJ0VGV4dD1QKCksVGk9ITApKSxpPWJpLmdldFBvb2xlZChpLHQsbixyKSxvP2kuZGF0YT1vOm51bGwhPT0obz1VKG4pKSYmKGkuZGF0YT1vKSxUKGkpLG89aSk6bz1udWxsLChlPXdpP3ooZSxuKTpHKGUsbikpPyh0PXhpLmdldFBvb2xlZChBaS5iZWZvcmVJbnB1dCx0LG4sciksdC5kYXRhPWUsVCh0KSk6dD1udWxsLG51bGw9PT1vP3Q6bnVsbD09PXQ/bzpbbyx0XX19LEZpPW51bGwsTmk9e2luamVjdEZpYmVyQ29udHJvbGxlZEhvc3RDb21wb25lbnQ6ZnVuY3Rpb24oZSl7Rmk9ZX19LElpPW51bGwsTGk9bnVsbCxQaT17aW5qZWN0aW9uOk5pLGVucXVldWVTdGF0ZVJlc3RvcmU6cSxuZWVkc1N0YXRlUmVzdG9yZTpILHJlc3RvcmVTdGF0ZUlmTmVlZGVkOld9LE1pPSExLGppPXtjb2xvcjohMCxkYXRlOiEwLGRhdGV0aW1lOiEwLCJkYXRldGltZS1sb2NhbCI6ITAsZW1haWw6ITAsbW9udGg6ITAsbnVtYmVyOiEwLHBhc3N3b3JkOiEwLHJhbmdlOiEwLHNlYXJjaDohMCx0ZWw6ITAsdGV4dDohMCx0aW1lOiEwLHVybDohMCx3ZWVrOiEwfSxSaT1Mci5fX1NFQ1JFVF9JTlRFUk5BTFNfRE9fTk9UX1VTRV9PUl9ZT1VfV0lMTF9CRV9GSVJFRC5SZWFjdEN1cnJlbnRPd25lcixCaT0iZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmU3ltYm9sLmZvciwkaT1CaT9TeW1ib2wuZm9yKCJyZWFjdC5lbGVtZW50Iik6NjAxMDMsVWk9Qmk/U3ltYm9sLmZvcigicmVhY3QucG9ydGFsIik6NjAxMDYsemk9Qmk/U3ltYm9sLmZvcigicmVhY3QuZnJhZ21lbnQiKTo2MDEwNyxHaT1CaT9TeW1ib2wuZm9yKCJyZWFjdC5zdHJpY3RfbW9kZSIpOjYwMTA4LFZpPUJpP1N5bWJvbC5mb3IoInJlYWN0LnByb2ZpbGVyIik6NjAxMTQscWk9Qmk/U3ltYm9sLmZvcigicmVhY3QucHJvdmlkZXIiKTo2MDEwOSxIaT1CaT9TeW1ib2wuZm9yKCJyZWFjdC5jb250ZXh0Iik6NjAxMTAsV2k9Qmk/U3ltYm9sLmZvcigicmVhY3QuYXN5bmNfbW9kZSIpOjYwMTExLFFpPUJpP1N5bWJvbC5mb3IoInJlYWN0LmZvcndhcmRfcmVmIik6NjAxMTIsS2k9Qmk/U3ltYm9sLmZvcigicmVhY3QudGltZW91dCIpOjYwMTEzLEppPSJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiZTeW1ib2wuaXRlcmF0b3IsWWk9L15bOkEtWl9hLXpcdTAwQzAtXHUwMEQ2XHUwMEQ4LVx1MDBGNlx1MDBGOC1cdTAyRkZcdTAzNzAtXHUwMzdEXHUwMzdGLVx1MUZGRlx1MjAwQy1cdTIwMERcdTIwNzAtXHUyMThGXHUyQzAwLVx1MkZFRlx1MzAwMS1cdUQ3RkZcdUY5MDAtXHVGRENGXHVGREYwLVx1RkZGRF1bOkEtWl9hLXpcdTAwQzAtXHUwMEQ2XHUwMEQ4LVx1MDBGNlx1MDBGOC1cdTAyRkZcdTAzNzAtXHUwMzdEXHUwMzdGLVx1MUZGRlx1MjAwQy1cdTIwMERcdTIwNzAtXHUyMThGXHUyQzAwLVx1MkZFRlx1MzAwMS1cdUQ3RkZcdUY5MDAtXHVGRENGXHVGREYwLVx1RkZGRFwtLjAtOVx1MDBCN1x1MDMwMC1cdTAzNkZcdTIwM0YtXHUyMDQwXSokLyxYaT17fSxaaT17fSxlbz17fTsiY2hpbGRyZW4gZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwgZGVmYXVsdFZhbHVlIGRlZmF1bHRDaGVja2VkIGlubmVySFRNTCBzdXBwcmVzc0NvbnRlbnRFZGl0YWJsZVdhcm5pbmcgc3VwcHJlc3NIeWRyYXRpb25XYXJuaW5nIHN0eWxlIi5zcGxpdCgiICIpLmZvckVhY2goZnVuY3Rpb24oZSl7ZW9bZV09bmV3IHBlKGUsMCwhMSxlLG51bGwpfSksW1siYWNjZXB0Q2hhcnNldCIsImFjY2VwdC1jaGFyc2V0Il0sWyJjbGFzc05hbWUiLCJjbGFzcyJdLFsiaHRtbEZvciIsImZvciJdLFsiaHR0cEVxdWl2IiwiaHR0cC1lcXVpdiJdXS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWVbMF07ZW9bdF09bmV3IHBlKHQsMSwhMSxlWzFdLG51bGwpfSksWyJjb250ZW50RWRpdGFibGUiLCJkcmFnZ2FibGUiLCJzcGVsbENoZWNrIiwidmFsdWUiXS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2VvW2VdPW5ldyBwZShlLDIsITEsZS50b0xvd2VyQ2FzZSgpLG51bGwpfSksWyJhdXRvUmV2ZXJzZSIsImV4dGVybmFsUmVzb3VyY2VzUmVxdWlyZWQiLCJwcmVzZXJ2ZUFscGhhIl0uZm9yRWFjaChmdW5jdGlvbihlKXtlb1tlXT1uZXcgcGUoZSwyLCExLGUsbnVsbCl9KSwiYWxsb3dGdWxsU2NyZWVuIGFzeW5jIGF1dG9Gb2N1cyBhdXRvUGxheSBjb250cm9scyBkZWZhdWx0IGRlZmVyIGRpc2FibGVkIGZvcm1Ob1ZhbGlkYXRlIGhpZGRlbiBsb29wIG5vTW9kdWxlIG5vVmFsaWRhdGUgb3BlbiBwbGF5c0lubGluZSByZWFkT25seSByZXF1aXJlZCByZXZlcnNlZCBzY29wZWQgc2VhbWxlc3MgaXRlbVNjb3BlIi5zcGxpdCgiICIpLmZvckVhY2goZnVuY3Rpb24oZSl7ZW9bZV09bmV3IHBlKGUsMywhMSxlLnRvTG93ZXJDYXNlKCksbnVsbCl9KSxbImNoZWNrZWQiLCJtdWx0aXBsZSIsIm11dGVkIiwic2VsZWN0ZWQiXS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2VvW2VdPW5ldyBwZShlLDMsITAsZS50b0xvd2VyQ2FzZSgpLG51bGwpfSksWyJjYXB0dXJlIiwiZG93bmxvYWQiXS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2VvW2VdPW5ldyBwZShlLDQsITEsZS50b0xvd2VyQ2FzZSgpLG51bGwpfSksWyJjb2xzIiwicm93cyIsInNpemUiLCJzcGFuIl0uZm9yRWFjaChmdW5jdGlvbihlKXtlb1tlXT1uZXcgcGUoZSw2LCExLGUudG9Mb3dlckNhc2UoKSxudWxsKX0pLFsicm93U3BhbiIsInN0YXJ0Il0uZm9yRWFjaChmdW5jdGlvbihlKXtlb1tlXT1uZXcgcGUoZSw1LCExLGUudG9Mb3dlckNhc2UoKSxudWxsKX0pO3ZhciB0bz0vW1wtOl0oW2Etel0pL2c7ImFjY2VudC1oZWlnaHQgYWxpZ25tZW50LWJhc2VsaW5lIGFyYWJpYy1mb3JtIGJhc2VsaW5lLXNoaWZ0IGNhcC1oZWlnaHQgY2xpcC1wYXRoIGNsaXAtcnVsZSBjb2xvci1pbnRlcnBvbGF0aW9uIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycyBjb2xvci1wcm9maWxlIGNvbG9yLXJlbmRlcmluZyBkb21pbmFudC1iYXNlbGluZSBlbmFibGUtYmFja2dyb3VuZCBmaWxsLW9wYWNpdHkgZmlsbC1ydWxlIGZsb29kLWNvbG9yIGZsb29kLW9wYWNpdHkgZm9udC1mYW1pbHkgZm9udC1zaXplIGZvbnQtc2l6ZS1hZGp1c3QgZm9udC1zdHJldGNoIGZvbnQtc3R5bGUgZm9udC12YXJpYW50IGZvbnQtd2VpZ2h0IGdseXBoLW5hbWUgZ2x5cGgtb3JpZW50YXRpb24taG9yaXpvbnRhbCBnbHlwaC1vcmllbnRhdGlvbi12ZXJ0aWNhbCBob3Jpei1hZHYteCBob3Jpei1vcmlnaW4teCBpbWFnZS1yZW5kZXJpbmcgbGV0dGVyLXNwYWNpbmcgbGlnaHRpbmctY29sb3IgbWFya2VyLWVuZCBtYXJrZXItbWlkIG1hcmtlci1zdGFydCBvdmVybGluZS1wb3NpdGlvbiBvdmVybGluZS10aGlja25lc3MgcGFpbnQtb3JkZXIgcGFub3NlLTEgcG9pbnRlci1ldmVudHMgcmVuZGVyaW5nLWludGVudCBzaGFwZS1yZW5kZXJpbmcgc3RvcC1jb2xvciBzdG9wLW9wYWNpdHkgc3RyaWtldGhyb3VnaC1wb3NpdGlvbiBzdHJpa2V0aHJvdWdoLXRoaWNrbmVzcyBzdHJva2UtZGFzaGFycmF5IHN0cm9rZS1kYXNob2Zmc2V0IHN0cm9rZS1saW5lY2FwIHN0cm9rZS1saW5lam9pbiBzdHJva2UtbWl0ZXJsaW1pdCBzdHJva2Utb3BhY2l0eSBzdHJva2Utd2lkdGggdGV4dC1hbmNob3IgdGV4dC1kZWNvcmF0aW9uIHRleHQtcmVuZGVyaW5nIHVuZGVybGluZS1wb3NpdGlvbiB1bmRlcmxpbmUtdGhpY2tuZXNzIHVuaWNvZGUtYmlkaSB1bmljb2RlLXJhbmdlIHVuaXRzLXBlci1lbSB2LWFscGhhYmV0aWMgdi1oYW5naW5nIHYtaWRlb2dyYXBoaWMgdi1tYXRoZW1hdGljYWwgdmVjdG9yLWVmZmVjdCB2ZXJ0LWFkdi15IHZlcnQtb3JpZ2luLXggdmVydC1vcmlnaW4teSB3b3JkLXNwYWNpbmcgd3JpdGluZy1tb2RlIHhtbG5zOnhsaW5rIHgtaGVpZ2h0Ii5zcGxpdCgiICIpLmZvckVhY2goZnVuY3Rpb24oZSl7dmFyIHQ9ZS5yZXBsYWNlKHRvLGZlKTtlb1t0XT1uZXcgcGUodCwxLCExLGUsbnVsbCl9KSwieGxpbms6YWN0dWF0ZSB4bGluazphcmNyb2xlIHhsaW5rOmhyZWYgeGxpbms6cm9sZSB4bGluazpzaG93IHhsaW5rOnRpdGxlIHhsaW5rOnR5cGUiLnNwbGl0KCIgIikuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1lLnJlcGxhY2UodG8sZmUpO2VvW3RdPW5ldyBwZSh0LDEsITEsZSwiaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIpfSksWyJ4bWw6YmFzZSIsInhtbDpsYW5nIiwieG1sOnNwYWNlIl0uZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1lLnJlcGxhY2UodG8sZmUpO2VvW3RdPW5ldyBwZSh0LDEsITEsZSwiaHR0cDovL3d3dy53My5vcmcvWE1MLzE5OTgvbmFtZXNwYWNlIil9KSxlby50YWJJbmRleD1uZXcgcGUoInRhYkluZGV4IiwxLCExLCJ0YWJpbmRleCIsbnVsbCk7dmFyIG5vPXtjaGFuZ2U6e3BoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOntidWJibGVkOiJvbkNoYW5nZSIsY2FwdHVyZWQ6Im9uQ2hhbmdlQ2FwdHVyZSJ9LGRlcGVuZGVuY2llczoiYmx1ciBjaGFuZ2UgY2xpY2sgZm9jdXMgaW5wdXQga2V5ZG93biBrZXl1cCBzZWxlY3Rpb25jaGFuZ2UiLnNwbGl0KCIgIil9fSxybz1udWxsLGlvPW51bGwsb289ITE7UHIuY2FuVXNlRE9NJiYob289ZWUoImlucHV0IikmJighZG9jdW1lbnQuZG9jdW1lbnRNb2RlfHw5PGRvY3VtZW50LmRvY3VtZW50TW9kZSkpO3ZhciBhbz17ZXZlbnRUeXBlczpubyxfaXNJbnB1dEV2ZW50U3VwcG9ydGVkOm9vLGV4dHJhY3RFdmVudHM6ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9dD94KHQpOndpbmRvdyxvPXZvaWQgMCxhPXZvaWQgMCxzPWkubm9kZU5hbWUmJmkubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtpZigic2VsZWN0Ij09PXN8fCJpbnB1dCI9PT1zJiYiZmlsZSI9PT1pLnR5cGU/bz13ZTpYKGkpP29vP289T2U6KG89X2UsYT1BZSk6KHM9aS5ub2RlTmFtZSkmJiJpbnB1dCI9PT1zLnRvTG93ZXJDYXNlKCkmJigiY2hlY2tib3giPT09aS50eXBlfHwicmFkaW8iPT09aS50eXBlKSYmKG89VGUpLG8mJihvPW8oZSx0KSkpcmV0dXJuIENlKG8sbixyKTthJiZhKGUsaSx0KSwiYmx1ciI9PT1lJiZudWxsIT10JiYoZT10Ll93cmFwcGVyU3RhdGV8fGkuX3dyYXBwZXJTdGF0ZSkmJmUuY29udHJvbGxlZCYmIm51bWJlciI9PT1pLnR5cGUmJmJlKGksIm51bWJlciIsaS52YWx1ZSl9fSxzbz1NLmV4dGVuZCh7dmlldzpudWxsLGRldGFpbDpudWxsfSksdW89e0FsdDoiYWx0S2V5IixDb250cm9sOiJjdHJsS2V5IixNZXRhOiJtZXRhS2V5IixTaGlmdDoic2hpZnRLZXkifSxjbz1zby5leHRlbmQoe3NjcmVlblg6bnVsbCxzY3JlZW5ZOm51bGwsY2xpZW50WDpudWxsLGNsaWVudFk6bnVsbCxwYWdlWDpudWxsLHBhZ2VZOm51bGwsY3RybEtleTpudWxsLHNoaWZ0S2V5Om51bGwsYWx0S2V5Om51bGwsbWV0YUtleTpudWxsLGdldE1vZGlmaWVyU3RhdGU6TmUsYnV0dG9uOm51bGwsYnV0dG9uczpudWxsLHJlbGF0ZWRUYXJnZXQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGUucmVsYXRlZFRhcmdldHx8KGUuZnJvbUVsZW1lbnQ9PT1lLnNyY0VsZW1lbnQ/ZS50b0VsZW1lbnQ6ZS5mcm9tRWxlbWVudCl9fSksbG89Y28uZXh0ZW5kKHtwb2ludGVySWQ6bnVsbCx3aWR0aDpudWxsLGhlaWdodDpudWxsLHByZXNzdXJlOm51bGwsdGlsdFg6bnVsbCx0aWx0WTpudWxsLHBvaW50ZXJUeXBlOm51bGwsaXNQcmltYXJ5Om51bGx9KSxwbz17bW91c2VFbnRlcjp7cmVnaXN0cmF0aW9uTmFtZToib25Nb3VzZUVudGVyIixkZXBlbmRlbmNpZXM6WyJtb3VzZW91dCIsIm1vdXNlb3ZlciJdfSxtb3VzZUxlYXZlOntyZWdpc3RyYXRpb25OYW1lOiJvbk1vdXNlTGVhdmUiLGRlcGVuZGVuY2llczpbIm1vdXNlb3V0IiwibW91c2VvdmVyIl19LHBvaW50ZXJFbnRlcjp7cmVnaXN0cmF0aW9uTmFtZToib25Qb2ludGVyRW50ZXIiLGRlcGVuZGVuY2llczpbInBvaW50ZXJvdXQiLCJwb2ludGVyb3ZlciJdfSxwb2ludGVyTGVhdmU6e3JlZ2lzdHJhdGlvbk5hbWU6Im9uUG9pbnRlckxlYXZlIixkZXBlbmRlbmNpZXM6WyJwb2ludGVyb3V0IiwicG9pbnRlcm92ZXIiXX19LGZvPXtldmVudFR5cGVzOnBvLGV4dHJhY3RFdmVudHM6ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9Im1vdXNlb3ZlciI9PT1lfHwicG9pbnRlcm92ZXIiPT09ZSxvPSJtb3VzZW91dCI9PT1lfHwicG9pbnRlcm91dCI9PT1lO2lmKGkmJihuLnJlbGF0ZWRUYXJnZXR8fG4uZnJvbUVsZW1lbnQpfHwhbyYmIWkpcmV0dXJuIG51bGw7aWYoaT1yLndpbmRvdz09PXI/cjooaT1yLm93bmVyRG9jdW1lbnQpP2kuZGVmYXVsdFZpZXd8fGkucGFyZW50V2luZG93OndpbmRvdyxvPyhvPXQsdD0odD1uLnJlbGF0ZWRUYXJnZXR8fG4udG9FbGVtZW50KT9iKHQpOm51bGwpOm89bnVsbCxvPT09dClyZXR1cm4gbnVsbDt2YXIgYT12b2lkIDAscz12b2lkIDAsdT12b2lkIDAsYz12b2lkIDA7cmV0dXJuIm1vdXNlb3V0Ij09PWV8fCJtb3VzZW92ZXIiPT09ZT8oYT1jbyxzPXBvLm1vdXNlTGVhdmUsdT1wby5tb3VzZUVudGVyLGM9Im1vdXNlIik6InBvaW50ZXJvdXQiIT09ZSYmInBvaW50ZXJvdmVyIiE9PWV8fChhPWxvLHM9cG8ucG9pbnRlckxlYXZlLHU9cG8ucG9pbnRlckVudGVyLGM9InBvaW50ZXIiKSxlPW51bGw9PW8/aTp4KG8pLGk9bnVsbD09dD9pOngodCkscz1hLmdldFBvb2xlZChzLG8sbixyKSxzLnR5cGU9YysibGVhdmUiLHMudGFyZ2V0PWUscy5yZWxhdGVkVGFyZ2V0PWksbj1hLmdldFBvb2xlZCh1LHQsbixyKSxuLnR5cGU9YysiZW50ZXIiLG4udGFyZ2V0PWksbi5yZWxhdGVkVGFyZ2V0PWUsTyhzLG4sbyx0KSxbcyxuXX19LGhvPU0uZXh0ZW5kKHthbmltYXRpb25OYW1lOm51bGwsZWxhcHNlZFRpbWU6bnVsbCxwc2V1ZG9FbGVtZW50Om51bGx9KSxtbz1NLmV4dGVuZCh7Y2xpcGJvYXJkRGF0YTpmdW5jdGlvbihlKXtyZXR1cm4iY2xpcGJvYXJkRGF0YSJpbiBlP2UuY2xpcGJvYXJkRGF0YTp3aW5kb3cuY2xpcGJvYXJkRGF0YX19KSxnbz1zby5leHRlbmQoe3JlbGF0ZWRUYXJnZXQ6bnVsbH0pLHlvPXtFc2M6IkVzY2FwZSIsU3BhY2ViYXI6IiAiLExlZnQ6IkFycm93TGVmdCIsVXA6IkFycm93VXAiLFJpZ2h0OiJBcnJvd1JpZ2h0IixEb3duOiJBcnJvd0Rvd24iLERlbDoiRGVsZXRlIixXaW46Ik9TIixNZW51OiJDb250ZXh0TWVudSIsQXBwczoiQ29udGV4dE1lbnUiLFNjcm9sbDoiU2Nyb2xsTG9jayIsTW96UHJpbnRhYmxlS2V5OiJVbmlkZW50aWZpZWQifSx2bz17ODoiQmFja3NwYWNlIiw5OiJUYWIiLDEyOiJDbGVhciIsMTM6IkVudGVyIiwxNjoiU2hpZnQiLDE3OiJDb250cm9sIiwxODoiQWx0IiwxOToiUGF1c2UiLDIwOiJDYXBzTG9jayIsMjc6IkVzY2FwZSIsMzI6IiAiLDMzOiJQYWdlVXAiLDM0OiJQYWdlRG93biIsMzU6IkVuZCIsMzY6IkhvbWUiLDM3OiJBcnJvd0xlZnQiLDM4OiJBcnJvd1VwIiwzOToiQXJyb3dSaWdodCIsNDA6IkFycm93RG93biIsNDU6Ikluc2VydCIsNDY6IkRlbGV0ZSIsMTEyOiJGMSIsMTEzOiJGMiIsMTE0OiJGMyIsMTE1OiJGNCIsMTE2OiJGNSIsMTE3OiJGNiIsMTE4OiJGNyIsMTE5OiJGOCIsMTIwOiJGOSIsMTIxOiJGMTAiLDEyMjoiRjExIiwxMjM6IkYxMiIsMTQ0OiJOdW1Mb2NrIiwxNDU6IlNjcm9sbExvY2siLDIyNDoiTWV0YSJ9LGJvPXNvLmV4dGVuZCh7a2V5OmZ1bmN0aW9uKGUpe2lmKGUua2V5KXt2YXIgdD15b1tlLmtleV18fGUua2V5O2lmKCJVbmlkZW50aWZpZWQiIT09dClyZXR1cm4gdH1yZXR1cm4ia2V5cHJlc3MiPT09ZS50eXBlPyhlPVJlKGUpLDEzPT09ZT8iRW50ZXIiOlN0cmluZy5mcm9tQ2hhckNvZGUoZSkpOiJrZXlkb3duIj09PWUudHlwZXx8ImtleXVwIj09PWUudHlwZT92b1tlLmtleUNvZGVdfHwiVW5pZGVudGlmaWVkIjoiIn0sbG9jYXRpb246bnVsbCxjdHJsS2V5Om51bGwsc2hpZnRLZXk6bnVsbCxhbHRLZXk6bnVsbCxtZXRhS2V5Om51bGwscmVwZWF0Om51bGwsbG9jYWxlOm51bGwsZ2V0TW9kaWZpZXJTdGF0ZTpOZSxjaGFyQ29kZTpmdW5jdGlvbihlKXtyZXR1cm4ia2V5cHJlc3MiPT09ZS50eXBlP1JlKGUpOjB9LGtleUNvZGU6ZnVuY3Rpb24oZSl7cmV0dXJuImtleWRvd24iPT09ZS50eXBlfHwia2V5dXAiPT09ZS50eXBlP2Uua2V5Q29kZTowfSx3aGljaDpmdW5jdGlvbihlKXtyZXR1cm4ia2V5cHJlc3MiPT09ZS50eXBlP1JlKGUpOiJrZXlkb3duIj09PWUudHlwZXx8ImtleXVwIj09PWUudHlwZT9lLmtleUNvZGU6MH19KSx4bz1jby5leHRlbmQoe2RhdGFUcmFuc2ZlcjpudWxsfSksQ289c28uZXh0ZW5kKHt0b3VjaGVzOm51bGwsdGFyZ2V0VG91Y2hlczpudWxsLGNoYW5nZWRUb3VjaGVzOm51bGwsYWx0S2V5Om51bGwsbWV0YUtleTpudWxsLGN0cmxLZXk6bnVsbCxzaGlmdEtleTpudWxsLGdldE1vZGlmaWVyU3RhdGU6TmV9KSxFbz1NLmV4dGVuZCh7cHJvcGVydHlOYW1lOm51bGwsZWxhcHNlZFRpbWU6bnVsbCxwc2V1ZG9FbGVtZW50Om51bGx9KSxEbz1jby5leHRlbmQoe2RlbHRhWDpmdW5jdGlvbihlKXtyZXR1cm4iZGVsdGFYImluIGU/ZS5kZWx0YVg6IndoZWVsRGVsdGFYImluIGU/LWUud2hlZWxEZWx0YVg6MH0sZGVsdGFZOmZ1bmN0aW9uKGUpe3JldHVybiJkZWx0YVkiaW4gZT9lLmRlbHRhWToid2hlZWxEZWx0YVkiaW4gZT8tZS53aGVlbERlbHRhWToid2hlZWxEZWx0YSJpbiBlPy1lLndoZWVsRGVsdGE6MH0sZGVsdGFaOm51bGwsZGVsdGFNb2RlOm51bGx9KSx3bz1bWyJhYm9ydCIsImFib3J0Il0sW2xpLCJhbmltYXRpb25FbmQiXSxbcGksImFuaW1hdGlvbkl0ZXJhdGlvbiJdLFtmaSwiYW5pbWF0aW9uU3RhcnQiXSxbImNhbnBsYXkiLCJjYW5QbGF5Il0sWyJjYW5wbGF5dGhyb3VnaCIsImNhblBsYXlUaHJvdWdoIl0sWyJkcmFnIiwiZHJhZyJdLFsiZHJhZ2VudGVyIiwiZHJhZ0VudGVyIl0sWyJkcmFnZXhpdCIsImRyYWdFeGl0Il0sWyJkcmFnbGVhdmUiLCJkcmFnTGVhdmUiXSxbImRyYWdvdmVyIiwiZHJhZ092ZXIiXSxbImR1cmF0aW9uY2hhbmdlIiwiZHVyYXRpb25DaGFuZ2UiXSxbImVtcHRpZWQiLCJlbXB0aWVkIl0sWyJlbmNyeXB0ZWQiLCJlbmNyeXB0ZWQiXSxbImVuZGVkIiwiZW5kZWQiXSxbImVycm9yIiwiZXJyb3IiXSxbImdvdHBvaW50ZXJjYXB0dXJlIiwiZ290UG9pbnRlckNhcHR1cmUiXSxbImxvYWQiLCJsb2FkIl0sWyJsb2FkZWRkYXRhIiwibG9hZGVkRGF0YSJdLFsibG9hZGVkbWV0YWRhdGEiLCJsb2FkZWRNZXRhZGF0YSJdLFsibG9hZHN0YXJ0IiwibG9hZFN0YXJ0Il0sWyJsb3N0cG9pbnRlcmNhcHR1cmUiLCJsb3N0UG9pbnRlckNhcHR1cmUiXSxbIm1vdXNlbW92ZSIsIm1vdXNlTW92ZSJdLFsibW91c2VvdXQiLCJtb3VzZU91dCJdLFsibW91c2VvdmVyIiwibW91c2VPdmVyIl0sWyJwbGF5aW5nIiwicGxheWluZyJdLFsicG9pbnRlcm1vdmUiLCJwb2ludGVyTW92ZSJdLFsicG9pbnRlcm91dCIsInBvaW50ZXJPdXQiXSxbInBvaW50ZXJvdmVyIiwicG9pbnRlck92ZXIiXSxbInByb2dyZXNzIiwicHJvZ3Jlc3MiXSxbInNjcm9sbCIsInNjcm9sbCJdLFsic2Vla2luZyIsInNlZWtpbmciXSxbInN0YWxsZWQiLCJzdGFsbGVkIl0sWyJzdXNwZW5kIiwic3VzcGVuZCJdLFsidGltZXVwZGF0ZSIsInRpbWVVcGRhdGUiXSxbInRvZ2dsZSIsInRvZ2dsZSJdLFsidG91Y2htb3ZlIiwidG91Y2hNb3ZlIl0sW2RpLCJ0cmFuc2l0aW9uRW5kIl0sWyJ3YWl0aW5nIiwid2FpdGluZyJdLFsid2hlZWwiLCJ3aGVlbCJdXSxTbz17fSxrbz17fTtbWyJibHVyIiwiYmx1ciJdLFsiY2FuY2VsIiwiY2FuY2VsIl0sWyJjbGljayIsImNsaWNrIl0sWyJjbG9zZSIsImNsb3NlIl0sWyJjb250ZXh0bWVudSIsImNvbnRleHRNZW51Il0sWyJjb3B5IiwiY29weSJdLFsiY3V0IiwiY3V0Il0sWyJkYmxjbGljayIsImRvdWJsZUNsaWNrIl0sWyJkcmFnZW5kIiwiZHJhZ0VuZCJdLFsiZHJhZ3N0YXJ0IiwiZHJhZ1N0YXJ0Il0sWyJkcm9wIiwiZHJvcCJdLFsiZm9jdXMiLCJmb2N1cyJdLFsiaW5wdXQiLCJpbnB1dCJdLFsiaW52YWxpZCIsImludmFsaWQiXSxbImtleWRvd24iLCJrZXlEb3duIl0sWyJrZXlwcmVzcyIsImtleVByZXNzIl0sWyJrZXl1cCIsImtleVVwIl0sWyJtb3VzZWRvd24iLCJtb3VzZURvd24iXSxbIm1vdXNldXAiLCJtb3VzZVVwIl0sWyJwYXN0ZSIsInBhc3RlIl0sWyJwYXVzZSIsInBhdXNlIl0sWyJwbGF5IiwicGxheSJdLFsicG9pbnRlcmNhbmNlbCIsInBvaW50ZXJDYW5jZWwiXSxbInBvaW50ZXJkb3duIiwicG9pbnRlckRvd24iXSxbInBvaW50ZXJ1cCIsInBvaW50ZXJVcCJdLFsicmF0ZWNoYW5nZSIsInJhdGVDaGFuZ2UiXSxbInJlc2V0IiwicmVzZXQiXSxbInNlZWtlZCIsInNlZWtlZCJdLFsic3VibWl0Iiwic3VibWl0Il0sWyJ0b3VjaGNhbmNlbCIsInRvdWNoQ2FuY2VsIl0sWyJ0b3VjaGVuZCIsInRvdWNoRW5kIl0sWyJ0b3VjaHN0YXJ0IiwidG91Y2hTdGFydCJdLFsidm9sdW1lY2hhbmdlIiwidm9sdW1lQ2hhbmdlIl1dLmZvckVhY2goZnVuY3Rpb24oZSl7QmUoZSwhMCl9KSx3by5mb3JFYWNoKGZ1bmN0aW9uKGUpe0JlKGUsITEpfSk7dmFyIEFvPXtldmVudFR5cGVzOlNvLGlzSW50ZXJhY3RpdmVUb3BMZXZlbEV2ZW50VHlwZTpmdW5jdGlvbihlKXtyZXR1cm4gdm9pZCAwIT09KGU9a29bZV0pJiYhMD09PWUuaXNJbnRlcmFjdGl2ZX0sZXh0cmFjdEV2ZW50czpmdW5jdGlvbihlLHQsbixyKXt2YXIgaT1rb1tlXTtpZighaSlyZXR1cm4gbnVsbDtzd2l0Y2goZSl7Y2FzZSJrZXlwcmVzcyI6aWYoMD09PVJlKG4pKXJldHVybiBudWxsO2Nhc2Uia2V5ZG93biI6Y2FzZSJrZXl1cCI6ZT1ibzticmVhaztjYXNlImJsdXIiOmNhc2UiZm9jdXMiOmU9Z287YnJlYWs7Y2FzZSJjbGljayI6aWYoMj09PW4uYnV0dG9uKXJldHVybiBudWxsO2Nhc2UiZGJsY2xpY2siOmNhc2UibW91c2Vkb3duIjpjYXNlIm1vdXNlbW92ZSI6Y2FzZSJtb3VzZXVwIjpjYXNlIm1vdXNlb3V0IjpjYXNlIm1vdXNlb3ZlciI6Y2FzZSJjb250ZXh0bWVudSI6ZT1jbzticmVhaztjYXNlImRyYWciOmNhc2UiZHJhZ2VuZCI6Y2FzZSJkcmFnZW50ZXIiOmNhc2UiZHJhZ2V4aXQiOmNhc2UiZHJhZ2xlYXZlIjpjYXNlImRyYWdvdmVyIjpjYXNlImRyYWdzdGFydCI6Y2FzZSJkcm9wIjplPXhvO2JyZWFrO2Nhc2UidG91Y2hjYW5jZWwiOmNhc2UidG91Y2hlbmQiOmNhc2UidG91Y2htb3ZlIjpjYXNlInRvdWNoc3RhcnQiOmU9Q287YnJlYWs7Y2FzZSBsaTpjYXNlIHBpOmNhc2UgZmk6ZT1obzticmVhaztjYXNlIGRpOmU9RW87YnJlYWs7Y2FzZSJzY3JvbGwiOmU9c287YnJlYWs7Y2FzZSJ3aGVlbCI6ZT1EbzticmVhaztjYXNlImNvcHkiOmNhc2UiY3V0IjpjYXNlInBhc3RlIjplPW1vO2JyZWFrO2Nhc2UiZ290cG9pbnRlcmNhcHR1cmUiOmNhc2UibG9zdHBvaW50ZXJjYXB0dXJlIjpjYXNlInBvaW50ZXJjYW5jZWwiOmNhc2UicG9pbnRlcmRvd24iOmNhc2UicG9pbnRlcm1vdmUiOmNhc2UicG9pbnRlcm91dCI6Y2FzZSJwb2ludGVyb3ZlciI6Y2FzZSJwb2ludGVydXAiOmU9bG87YnJlYWs7ZGVmYXVsdDplPU19cmV0dXJuIHQ9ZS5nZXRQb29sZWQoaSx0LG4sciksVCh0KSx0fX0sX289QW8uaXNJbnRlcmFjdGl2ZVRvcExldmVsRXZlbnRUeXBlLFRvPVtdLE9vPSEwLEZvPXtnZXQgX2VuYWJsZWQoKXtyZXR1cm4gT299LHNldEVuYWJsZWQ6VWUsaXNFbmFibGVkOmZ1bmN0aW9uKCl7cmV0dXJuIE9vfSx0cmFwQnViYmxlZEV2ZW50OnplLHRyYXBDYXB0dXJlZEV2ZW50OkdlLGRpc3BhdGNoRXZlbnQ6cWV9LE5vPXt9LElvPTAsTG89Il9yZWFjdExpc3RlbmVyc0lEIisoIiIrTWF0aC5yYW5kb20oKSkuc2xpY2UoMiksUG89UHIuY2FuVXNlRE9NJiYiZG9jdW1lbnRNb2RlImluIGRvY3VtZW50JiYxMT49ZG9jdW1lbnQuZG9jdW1lbnRNb2RlLE1vPXtzZWxlY3Q6e3BoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOntidWJibGVkOiJvblNlbGVjdCIsY2FwdHVyZWQ6Im9uU2VsZWN0Q2FwdHVyZSJ9LGRlcGVuZGVuY2llczoiYmx1ciBjb250ZXh0bWVudSBmb2N1cyBrZXlkb3duIGtleXVwIG1vdXNlZG93biBtb3VzZXVwIHNlbGVjdGlvbmNoYW5nZSIuc3BsaXQoIiAiKX19LGpvPW51bGwsUm89bnVsbCxCbz1udWxsLCRvPSExLFVvPXtldmVudFR5cGVzOk1vLGV4dHJhY3RFdmVudHM6ZnVuY3Rpb24oZSx0LG4scil7dmFyIGksbz1yLndpbmRvdz09PXI/ci5kb2N1bWVudDo5PT09ci5ub2RlVHlwZT9yOnIub3duZXJEb2N1bWVudDtpZighKGk9IW8pKXtlOntvPUhlKG8pLGk9UXIub25TZWxlY3Q7Zm9yKHZhciBhPTA7YTxpLmxlbmd0aDthKyspe3ZhciBzPWlbYV07aWYoIW8uaGFzT3duUHJvcGVydHkocyl8fCFvW3NdKXtvPSExO2JyZWFrIGV9fW89ITB9aT0hb31pZihpKXJldHVybiBudWxsO3N3aXRjaChvPXQ/eCh0KTp3aW5kb3csZSl7Y2FzZSJmb2N1cyI6KFgobyl8fCJ0cnVlIj09PW8uY29udGVudEVkaXRhYmxlKSYmKGpvPW8sUm89dCxCbz1udWxsKTticmVhaztjYXNlImJsdXIiOkJvPVJvPWpvPW51bGw7YnJlYWs7Y2FzZSJtb3VzZWRvd24iOiRvPSEwO2JyZWFrO2Nhc2UiY29udGV4dG1lbnUiOmNhc2UibW91c2V1cCI6cmV0dXJuICRvPSExLEplKG4scik7Y2FzZSJzZWxlY3Rpb25jaGFuZ2UiOmlmKFBvKWJyZWFrO2Nhc2Uia2V5ZG93biI6Y2FzZSJrZXl1cCI6cmV0dXJuIEplKG4scil9cmV0dXJuIG51bGx9fTtlaS5pbmplY3RFdmVudFBsdWdpbk9yZGVyKCJSZXNwb25kZXJFdmVudFBsdWdpbiBTaW1wbGVFdmVudFBsdWdpbiBUYXBFdmVudFBsdWdpbiBFbnRlckxlYXZlRXZlbnRQbHVnaW4gQ2hhbmdlRXZlbnRQbHVnaW4gU2VsZWN0RXZlbnRQbHVnaW4gQmVmb3JlSW5wdXRFdmVudFBsdWdpbiIuc3BsaXQoIiAiKSksSnI9b2kuZ2V0RmliZXJDdXJyZW50UHJvcHNGcm9tTm9kZSxZcj1vaS5nZXRJbnN0YW5jZUZyb21Ob2RlLFhyPW9pLmdldE5vZGVGcm9tSW5zdGFuY2UsZWkuaW5qZWN0RXZlbnRQbHVnaW5zQnlOYW1lKHtTaW1wbGVFdmVudFBsdWdpbjpBbyxFbnRlckxlYXZlRXZlbnRQbHVnaW46Zm8sQ2hhbmdlRXZlbnRQbHVnaW46YW8sU2VsZWN0RXZlbnRQbHVnaW46VW8sQmVmb3JlSW5wdXRFdmVudFBsdWdpbjpPaX0pO3ZhciB6bz12b2lkIDA7em89Im9iamVjdCI9PT10eXBlb2YgcGVyZm9ybWFuY2UmJiJmdW5jdGlvbiI9PT10eXBlb2YgcGVyZm9ybWFuY2Uubm93P2Z1bmN0aW9uKCl7cmV0dXJuIHBlcmZvcm1hbmNlLm5vdygpfTpmdW5jdGlvbigpe3JldHVybiBEYXRlLm5vdygpfTt2YXIgR289dm9pZCAwLFZvPXZvaWQgMDtpZihQci5jYW5Vc2VET00pe3ZhciBxbz1bXSxIbz0wLFdvPXt9LFFvPS0xLEtvPSExLEpvPSExLFlvPTAsWG89MzMsWm89MzMsZWE9e2RpZFRpbWVvdXQ6ITEsdGltZVJlbWFpbmluZzpmdW5jdGlvbigpe3ZhciBlPVlvLXpvKCk7cmV0dXJuIDA8ZT9lOjB9fSx0YT1mdW5jdGlvbihlLHQpe2lmKFdvW3RdKXRyeXtlKGVhKX1maW5hbGx5e2RlbGV0ZSBXb1t0XX19LG5hPSJfX3JlYWN0SWRsZUNhbGxiYWNrJCIrTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMik7d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uKGUpe2lmKGUuc291cmNlPT09d2luZG93JiZlLmRhdGE9PT1uYSYmKEtvPSExLDAhPT1xby5sZW5ndGgpKXtpZigwIT09cW8ubGVuZ3RoJiYoZT16bygpLCEoLTE9PT1Rb3x8UW8+ZSkpKXtRbz0tMSxlYS5kaWRUaW1lb3V0PSEwO2Zvcih2YXIgdD0wLG49cW8ubGVuZ3RoO3Q8bjt0Kyspe3ZhciByPXFvW3RdLGk9ci50aW1lb3V0VGltZTstMSE9PWkmJmk8PWU/dGEoci5zY2hlZHVsZWRDYWxsYmFjayxyLmNhbGxiYWNrSWQpOi0xIT09aSYmKC0xPT09UW98fGk8UW8pJiYoUW89aSl9fWZvcihlPXpvKCk7MDxZby1lJiYwPHFvLmxlbmd0aDspZT1xby5zaGlmdCgpLGVhLmRpZFRpbWVvdXQ9ITEsdGEoZS5zY2hlZHVsZWRDYWxsYmFjayxlLmNhbGxiYWNrSWQpLGU9em8oKTswPHFvLmxlbmd0aCYmIUpvJiYoSm89ITAscmVxdWVzdEFuaW1hdGlvbkZyYW1lKHJhKSl9fSwhMSk7dmFyIHJhPWZ1bmN0aW9uKGUpe0pvPSExO3ZhciB0PWUtWW8rWm87dDxabyYmWG88Wm8/KDg+dCYmKHQ9OCksWm89dDxYbz9Ybzp0KTpYbz10LFlvPWUrWm8sS298fChLbz0hMCx3aW5kb3cucG9zdE1lc3NhZ2UobmEsIioiKSl9O0dvPWZ1bmN0aW9uKGUsdCl7dmFyIG49LTE7cmV0dXJuIG51bGwhPXQmJiJudW1iZXIiPT09dHlwZW9mIHQudGltZW91dCYmKG49em8oKSt0LnRpbWVvdXQpLCgtMT09PVFvfHwtMSE9PW4mJm48UW8pJiYoUW89biksSG8rKyx0PUhvLHFvLnB1c2goe3NjaGVkdWxlZENhbGxiYWNrOmUsY2FsbGJhY2tJZDp0LHRpbWVvdXRUaW1lOm59KSxXb1t0XT0hMCxKb3x8KEpvPSEwLHJlcXVlc3RBbmltYXRpb25GcmFtZShyYSkpLHR9LFZvPWZ1bmN0aW9uKGUpe2RlbGV0ZSBXb1tlXX19ZWxzZXt2YXIgaWE9MCxvYT17fTtHbz1mdW5jdGlvbihlKXt2YXIgdD1pYSsrLG49c2V0VGltZW91dChmdW5jdGlvbigpe2Uoe3RpbWVSZW1haW5pbmc6ZnVuY3Rpb24oKXtyZXR1cm4gMS8wfSxkaWRUaW1lb3V0OiExfSl9KTtyZXR1cm4gb2FbdF09bix0fSxWbz1mdW5jdGlvbihlKXt2YXIgdD1vYVtlXTtkZWxldGUgb2FbZV0sY2xlYXJUaW1lb3V0KHQpfX12YXIgYWE9e2h0bWw6Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiLG1hdGhtbDoiaHR0cDovL3d3dy53My5vcmcvMTk5OC9NYXRoL01hdGhNTCIsc3ZnOiJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyJ9LHNhPXZvaWQgMCx1YT1mdW5jdGlvbihlKXtyZXR1cm4idW5kZWZpbmVkIiE9PXR5cGVvZiBNU0FwcCYmTVNBcHAuZXhlY1Vuc2FmZUxvY2FsRnVuY3Rpb24/ZnVuY3Rpb24odCxuLHIsaSl7TVNBcHAuZXhlY1Vuc2FmZUxvY2FsRnVuY3Rpb24oZnVuY3Rpb24oKXtyZXR1cm4gZSh0LG4pfSl9OmV9KGZ1bmN0aW9uKGUsdCl7aWYoZS5uYW1lc3BhY2VVUkkhPT1hYS5zdmd8fCJpbm5lckhUTUwiaW4gZSllLmlubmVySFRNTD10O2Vsc2V7Zm9yKHNhPXNhfHxkb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKSxzYS5pbm5lckhUTUw9Ijxzdmc+Iit0KyI8L3N2Zz4iLHQ9c2EuZmlyc3RDaGlsZDtlLmZpcnN0Q2hpbGQ7KWUucmVtb3ZlQ2hpbGQoZS5maXJzdENoaWxkKTtmb3IoO3QuZmlyc3RDaGlsZDspZS5hcHBlbmRDaGlsZCh0LmZpcnN0Q2hpbGQpfX0pLGNhPXthbmltYXRpb25JdGVyYXRpb25Db3VudDohMCxib3JkZXJJbWFnZU91dHNldDohMCxib3JkZXJJbWFnZVNsaWNlOiEwLGJvcmRlckltYWdlV2lkdGg6ITAsYm94RmxleDohMCxib3hGbGV4R3JvdXA6ITAsYm94T3JkaW5hbEdyb3VwOiEwLGNvbHVtbkNvdW50OiEwLGNvbHVtbnM6ITAsZmxleDohMCxmbGV4R3JvdzohMCxmbGV4UG9zaXRpdmU6ITAsZmxleFNocmluazohMCxmbGV4TmVnYXRpdmU6ITAsZmxleE9yZGVyOiEwLGdyaWRSb3c6ITAsZ3JpZFJvd0VuZDohMCxncmlkUm93U3BhbjohMCxncmlkUm93U3RhcnQ6ITAsZ3JpZENvbHVtbjohMCxncmlkQ29sdW1uRW5kOiEwLGdyaWRDb2x1bW5TcGFuOiEwLGdyaWRDb2x1bW5TdGFydDohMCxmb250V2VpZ2h0OiEwLGxpbmVDbGFtcDohMCxsaW5lSGVpZ2h0OiEwLG9wYWNpdHk6ITAsb3JkZXI6ITAsb3JwaGFuczohMCx0YWJTaXplOiEwLHdpZG93czohMCx6SW5kZXg6ITAsem9vbTohMCxmaWxsT3BhY2l0eTohMCxmbG9vZE9wYWNpdHk6ITAsc3RvcE9wYWNpdHk6ITAsc3Ryb2tlRGFzaGFycmF5OiEwLHN0cm9rZURhc2hvZmZzZXQ6ITAsc3Ryb2tlTWl0ZXJsaW1pdDohMCxzdHJva2VPcGFjaXR5OiEwLHN0cm9rZVdpZHRoOiEwfSxsYT1bIldlYmtpdCIsIm1zIiwiTW96IiwiTyJdO09iamVjdC5rZXlzKGNhKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2xhLmZvckVhY2goZnVuY3Rpb24odCl7dD10K2UuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkrZS5zdWJzdHJpbmcoMSksY2FbdF09Y2FbZV19KX0pO3ZhciBwYT1Ncih7bWVudWl0ZW06ITB9LHthcmVhOiEwLGJhc2U6ITAsYnI6ITAsY29sOiEwLGVtYmVkOiEwLGhyOiEwLGltZzohMCxpbnB1dDohMCxrZXlnZW46ITAsbGluazohMCxtZXRhOiEwLHBhcmFtOiEwLHNvdXJjZTohMCx0cmFjazohMCx3YnI6ITB9KSxmYT1qci50aGF0UmV0dXJucygiIiksZGE9e2NyZWF0ZUVsZW1lbnQ6ZnQsY3JlYXRlVGV4dE5vZGU6ZHQsc2V0SW5pdGlhbFByb3BlcnRpZXM6aHQsZGlmZlByb3BlcnRpZXM6bXQsdXBkYXRlUHJvcGVydGllczpndCxkaWZmSHlkcmF0ZWRQcm9wZXJ0aWVzOnl0LGRpZmZIeWRyYXRlZFRleHQ6dnQsd2FybkZvclVubWF0Y2hlZFRleHQ6ZnVuY3Rpb24oKXt9LHdhcm5Gb3JEZWxldGVkSHlkcmF0YWJsZUVsZW1lbnQ6ZnVuY3Rpb24oKXt9LHdhcm5Gb3JEZWxldGVkSHlkcmF0YWJsZVRleHQ6ZnVuY3Rpb24oKXt9LHdhcm5Gb3JJbnNlcnRlZEh5ZHJhdGVkRWxlbWVudDpmdW5jdGlvbigpe30sd2FybkZvckluc2VydGVkSHlkcmF0ZWRUZXh0OmZ1bmN0aW9uKCl7fSxyZXN0b3JlQ29udHJvbGxlZFN0YXRlOmZ1bmN0aW9uKGUsdCxuKXtzd2l0Y2godCl7Y2FzZSJpbnB1dCI6aWYoeWUoZSxuKSx0PW4ubmFtZSwicmFkaW8iPT09bi50eXBlJiZudWxsIT10KXtmb3Iobj1lO24ucGFyZW50Tm9kZTspbj1uLnBhcmVudE5vZGU7Zm9yKG49bi5xdWVyeVNlbGVjdG9yQWxsKCJpbnB1dFtuYW1lPSIrSlNPTi5zdHJpbmdpZnkoIiIrdCkrJ11bdHlwZT0icmFkaW8iXScpLHQ9MDt0PG4ubGVuZ3RoO3QrKyl7dmFyIGk9blt0XTtpZihpIT09ZSYmaS5mb3JtPT09ZS5mb3JtKXt2YXIgbz1DKGkpO298fHIoIjkwIiksaWUoaSkseWUoaSxvKX19fWJyZWFrO2Nhc2UidGV4dGFyZWEiOnJ0KGUsbik7YnJlYWs7Y2FzZSJzZWxlY3QiOm51bGwhPSh0PW4udmFsdWUpJiZaZShlLCEhbi5tdWx0aXBsZSx0LCExKX19fSxoYT1udWxsLG1hPW51bGwsZ2E9em8seWE9R28sdmE9Vm87bmV3IFNldDt2YXIgYmE9W10seGE9LTEsQ2E9RHQoVXIpLEVhPUR0KCExKSxEYT1Vcix3YT1udWxsLFNhPW51bGwsa2E9ITEsQWE9RHQobnVsbCksX2E9RHQobnVsbCksVGE9RHQoMCksT2E9e30sRmE9RHQoT2EpLE5hPUR0KE9hKSxJYT1EdChPYSksTGE9e2lzTW91bnRlZDpmdW5jdGlvbihlKXtyZXR1cm4hIShlPWUuX3JlYWN0SW50ZXJuYWxGaWJlcikmJjI9PT1JZShlKX0sZW5xdWV1ZVNldFN0YXRlOmZ1bmN0aW9uKGUsdCxuKXtlPWUuX3JlYWN0SW50ZXJuYWxGaWJlcjt2YXIgcj1lcigpO3I9WG4ocixlKTt2YXIgaT1RdChyKTtpLnBheWxvYWQ9dCx2b2lkIDAhPT1uJiZudWxsIT09biYmKGkuY2FsbGJhY2s9biksSnQoZSxpLHIpLFpuKGUscil9LGVucXVldWVSZXBsYWNlU3RhdGU6ZnVuY3Rpb24oZSx0LG4pe2U9ZS5fcmVhY3RJbnRlcm5hbEZpYmVyO3ZhciByPWVyKCk7cj1YbihyLGUpO3ZhciBpPVF0KHIpO2kudGFnPTEsaS5wYXlsb2FkPXQsdm9pZCAwIT09biYmbnVsbCE9PW4mJihpLmNhbGxiYWNrPW4pLEp0KGUsaSxyKSxabihlLHIpfSxlbnF1ZXVlRm9yY2VVcGRhdGU6ZnVuY3Rpb24oZSx0KXtlPWUuX3JlYWN0SW50ZXJuYWxGaWJlcjt2YXIgbj1lcigpO249WG4obixlKTt2YXIgcj1RdChuKTtyLnRhZz0yLHZvaWQgMCE9PXQmJm51bGwhPT10JiYoci5jYWxsYmFjaz10KSxKdChlLHIsbiksWm4oZSxuKX19LFBhPUFycmF5LmlzQXJyYXksTWE9eW4oITApLGphPXluKCExKSxSYT1udWxsLEJhPW51bGwsJGE9ITEsVWE9dm9pZCAwLHphPXZvaWQgMCxHYT12b2lkIDA7VWE9ZnVuY3Rpb24oKXt9LHphPWZ1bmN0aW9uKGUsdCxuKXsodC51cGRhdGVRdWV1ZT1uKSYmSW4odCl9LEdhPWZ1bmN0aW9uKGUsdCxuLHIpe24hPT1yJiZJbih0KX07dmFyIFZhPWdhKCkscWE9MixIYT1WYSxXYT0wLFFhPTAsS2E9ITEsSmE9bnVsbCxZYT1udWxsLFhhPTAsWmE9LTEsZXM9ITEsdHM9bnVsbCxucz0hMSxycz0hMSxpcz1udWxsLG9zPW51bGwsYXM9bnVsbCxzcz0wLHVzPS0xLGNzPSExLGxzPW51bGwscHM9MCxmcz0wLGRzPSExLGhzPSExLG1zPW51bGwsZ3M9bnVsbCx5cz0hMSx2cz0hMSxicz0hMSx4cz1udWxsLENzPTFlMyxFcz0wLERzPTEsd3M9e3VwZGF0ZUNvbnRhaW5lckF0RXhwaXJhdGlvblRpbWU6eHIsY3JlYXRlQ29udGFpbmVyOmZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gVXQoZSx0LG4pfSx1cGRhdGVDb250YWluZXI6RXIsZmx1c2hSb290OmNyLHJlcXVlc3RXb3JrOmlyLGNvbXB1dGVVbmlxdWVBc3luY0V4cGlyYXRpb246WW4sYmF0Y2hlZFVwZGF0ZXM6Z3IsdW5iYXRjaGVkVXBkYXRlczp5cixkZWZlcnJlZFVwZGF0ZXM6dHIsc3luY1VwZGF0ZXM6bnIsaW50ZXJhY3RpdmVVcGRhdGVzOmZ1bmN0aW9uKGUsdCxuKXtpZihicylyZXR1cm4gZSh0LG4pO3lzfHxjc3x8MD09PWZzfHwodXIoZnMsITEsbnVsbCksZnM9MCk7dmFyIHI9YnMsaT15czt5cz1icz0hMDt0cnl7cmV0dXJuIGUodCxuKX1maW5hbGx5e2JzPXIsKHlzPWkpfHxjc3x8c3IoKX19LGZsdXNoSW50ZXJhY3RpdmVVcGRhdGVzOmZ1bmN0aW9uKCl7Y3N8fDA9PT1mc3x8KHVyKGZzLCExLG51bGwpLGZzPTApfSxmbHVzaENvbnRyb2xsZWQ6YnIsZmx1c2hTeW5jOnZyLGdldFB1YmxpY1Jvb3RJbnN0YW5jZTpEcixmaW5kSG9zdEluc3RhbmNlOkNyLGZpbmRIb3N0SW5zdGFuY2VXaXRoTm9Qb3J0YWxzOmZ1bmN0aW9uKGUpe3JldHVybiBlPWplKGUpLG51bGw9PT1lP251bGw6ZS5zdGF0ZU5vZGV9LGluamVjdEludG9EZXZUb29sczp3cn07TmkuaW5qZWN0RmliZXJDb250cm9sbGVkSG9zdENvbXBvbmVudChkYSksa3IucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbihlKXt0aGlzLl9kZWZlcnx8cigiMjUwIiksdGhpcy5faGFzQ2hpbGRyZW49ITAsdGhpcy5fY2hpbGRyZW49ZTt2YXIgdD10aGlzLl9yb290Ll9pbnRlcm5hbFJvb3Qsbj10aGlzLl9leHBpcmF0aW9uVGltZSxpPW5ldyBBcjtyZXR1cm4geHIoZSx0LG51bGwsbixpLl9vbkNvbW1pdCksaX0sa3IucHJvdG90eXBlLnRoZW49ZnVuY3Rpb24oZSl7aWYodGhpcy5fZGlkQ29tcGxldGUpZSgpO2Vsc2V7dmFyIHQ9dGhpcy5fY2FsbGJhY2tzO251bGw9PT10JiYodD10aGlzLl9jYWxsYmFja3M9W10pLHQucHVzaChlKX19LGtyLnByb3RvdHlwZS5jb21taXQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLl9yb290Ll9pbnRlcm5hbFJvb3QsdD1lLmZpcnN0QmF0Y2g7aWYodGhpcy5fZGVmZXImJm51bGwhPT10fHxyKCIyNTEiKSx0aGlzLl9oYXNDaGlsZHJlbil7dmFyIG49dGhpcy5fZXhwaXJhdGlvblRpbWU7aWYodCE9PXRoaXMpe3RoaXMuX2hhc0NoaWxkcmVuJiYobj10aGlzLl9leHBpcmF0aW9uVGltZT10Ll9leHBpcmF0aW9uVGltZSx0aGlzLnJlbmRlcih0aGlzLl9jaGlsZHJlbikpO2Zvcih2YXIgaT1udWxsLG89dDtvIT09dGhpczspaT1vLG89by5fbmV4dDtudWxsPT09aSYmcigiMjUxIiksaS5fbmV4dD1vLl9uZXh0LHRoaXMuX25leHQ9dCxlLmZpcnN0QmF0Y2g9dGhpc310aGlzLl9kZWZlcj0hMSxjcihlLG4pLHQ9dGhpcy5fbmV4dCx0aGlzLl9uZXh0PW51bGwsdD1lLmZpcnN0QmF0Y2g9dCxudWxsIT09dCYmdC5faGFzQ2hpbGRyZW4mJnQucmVuZGVyKHQuX2NoaWxkcmVuKX1lbHNlIHRoaXMuX25leHQ9bnVsbCx0aGlzLl9kZWZlcj0hMX0sa3IucHJvdG90eXBlLl9vbkNvbXBsZXRlPWZ1bmN0aW9uKCl7aWYoIXRoaXMuX2RpZENvbXBsZXRlKXt0aGlzLl9kaWRDb21wbGV0ZT0hMDt2YXIgZT10aGlzLl9jYWxsYmFja3M7aWYobnVsbCE9PWUpZm9yKHZhciB0PTA7dDxlLmxlbmd0aDt0KyspKDAsZVt0XSkoKX19LEFyLnByb3RvdHlwZS50aGVuPWZ1bmN0aW9uKGUpe2lmKHRoaXMuX2RpZENvbW1pdCllKCk7ZWxzZXt2YXIgdD10aGlzLl9jYWxsYmFja3M7bnVsbD09PXQmJih0PXRoaXMuX2NhbGxiYWNrcz1bXSksdC5wdXNoKGUpfX0sQXIucHJvdG90eXBlLl9vbkNvbW1pdD1mdW5jdGlvbigpe2lmKCF0aGlzLl9kaWRDb21taXQpe3RoaXMuX2RpZENvbW1pdD0hMDt2YXIgZT10aGlzLl9jYWxsYmFja3M7aWYobnVsbCE9PWUpZm9yKHZhciB0PTA7dDxlLmxlbmd0aDt0Kyspe3ZhciBuPWVbdF07ImZ1bmN0aW9uIiE9PXR5cGVvZiBuJiZyKCIxOTEiLG4pLG4oKX19fSxfci5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5faW50ZXJuYWxSb290LHI9bmV3IEFyO3JldHVybiB0PXZvaWQgMD09PXQ/bnVsbDp0LG51bGwhPT10JiZyLnRoZW4odCksRXIoZSxuLG51bGwsci5fb25Db21taXQpLHJ9LF9yLnByb3RvdHlwZS51bm1vdW50PWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuX2ludGVybmFsUm9vdCxuPW5ldyBBcjtyZXR1cm4gZT12b2lkIDA9PT1lP251bGw6ZSxudWxsIT09ZSYmbi50aGVuKGUpLEVyKG51bGwsdCxudWxsLG4uX29uQ29tbWl0KSxufSxfci5wcm90b3R5cGUubGVnYWN5X3JlbmRlclN1YnRyZWVJbnRvQ29udGFpbmVyPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcj10aGlzLl9pbnRlcm5hbFJvb3QsaT1uZXcgQXI7cmV0dXJuIG49dm9pZCAwPT09bj9udWxsOm4sbnVsbCE9PW4mJmkudGhlbihuKSxFcih0LHIsZSxpLl9vbkNvbW1pdCksaX0sX3IucHJvdG90eXBlLmNyZWF0ZUJhdGNoPWZ1bmN0aW9uKCl7dmFyIGU9bmV3IGtyKHRoaXMpLHQ9ZS5fZXhwaXJhdGlvblRpbWUsbj10aGlzLl9pbnRlcm5hbFJvb3Qscj1uLmZpcnN0QmF0Y2g7aWYobnVsbD09PXIpbi5maXJzdEJhdGNoPWUsZS5fbmV4dD1udWxsO2Vsc2V7Zm9yKG49bnVsbDtudWxsIT09ciYmci5fZXhwaXJhdGlvblRpbWU8PXQ7KW49cixyPXIuX25leHQ7ZS5fbmV4dD1yLG51bGwhPT1uJiYobi5fbmV4dD1lKX1yZXR1cm4gZX0sUT13cy5iYXRjaGVkVXBkYXRlcyxLPXdzLmludGVyYWN0aXZlVXBkYXRlcyxKPXdzLmZsdXNoSW50ZXJhY3RpdmVVcGRhdGVzO3ZhciBTcz17Y3JlYXRlUG9ydGFsOk5yLGZpbmRET01Ob2RlOmZ1bmN0aW9uKGUpe3JldHVybiBudWxsPT1lP251bGw6MT09PWUubm9kZVR5cGU/ZTpDcihlKX0saHlkcmF0ZTpmdW5jdGlvbihlLHQsbil7cmV0dXJuIEZyKG51bGwsZSx0LCEwLG4pfSxyZW5kZXI6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBGcihudWxsLGUsdCwhMSxuKX0sdW5zdGFibGVfcmVuZGVyU3VidHJlZUludG9Db250YWluZXI6ZnVuY3Rpb24oZSx0LG4saSl7cmV0dXJuKG51bGw9PWV8fHZvaWQgMD09PWUuX3JlYWN0SW50ZXJuYWxGaWJlcikmJnIoIjM4IiksRnIoZSx0LG4sITEsaSl9LHVubW91bnRDb21wb25lbnRBdE5vZGU6ZnVuY3Rpb24oZSl7cmV0dXJuIFRyKGUpfHxyKCI0MCIpLCEhZS5fcmVhY3RSb290Q29udGFpbmVyJiYoeXIoZnVuY3Rpb24oKXtGcihudWxsLG51bGwsZSwhMSxmdW5jdGlvbigpe2UuX3JlYWN0Um9vdENvbnRhaW5lcj1udWxsfSl9KSwhMCl9LHVuc3RhYmxlX2NyZWF0ZVBvcnRhbDpmdW5jdGlvbigpe3JldHVybiBOci5hcHBseSh2b2lkIDAsYXJndW1lbnRzKX0sdW5zdGFibGVfYmF0Y2hlZFVwZGF0ZXM6Z3IsdW5zdGFibGVfZGVmZXJyZWRVcGRhdGVzOnRyLGZsdXNoU3luYzp2cix1bnN0YWJsZV9mbHVzaENvbnRyb2xsZWQ6YnIsX19TRUNSRVRfSU5URVJOQUxTX0RPX05PVF9VU0VfT1JfWU9VX1dJTExfQkVfRklSRUQ6e0V2ZW50UGx1Z2luSHViOnRpLEV2ZW50UGx1Z2luUmVnaXN0cnk6S3IsRXZlbnRQcm9wYWdhdG9yczphaSxSZWFjdENvbnRyb2xsZWRDb21wb25lbnQ6UGksUmVhY3RET01Db21wb25lbnRUcmVlOm9pLFJlYWN0RE9NRXZlbnRMaXN0ZW5lcjpGb30sdW5zdGFibGVfY3JlYXRlUm9vdDpmdW5jdGlvbihlLHQpe3JldHVybiBuZXcgX3IoZSwhMCxudWxsIT10JiYhMD09PXQuaHlkcmF0ZSl9fTt3cih7ZmluZEZpYmVyQnlIb3N0SW5zdGFuY2U6YixidW5kbGVUeXBlOjAsdmVyc2lvbjoiMTYuNC4wIixyZW5kZXJlclBhY2thZ2VOYW1lOiJyZWFjdC1kb20ifSk7dmFyIGtzPXtkZWZhdWx0OlNzfSxBcz1rcyYmU3N8fGtzO2UuZXhwb3J0cz1Bcy5kZWZhdWx0P0FzLmRlZmF1bHQ6QXN9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ISgidW5kZWZpbmVkIj09PXR5cGVvZiB3aW5kb3d8fCF3aW5kb3cuZG9jdW1lbnR8fCF3aW5kb3cuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCksaT17Y2FuVXNlRE9NOnIsY2FuVXNlV29ya2VyczoidW5kZWZpbmVkIiE9PXR5cGVvZiBXb3JrZXIsY2FuVXNlRXZlbnRMaXN0ZW5lcnM6ciYmISghd2luZG93LmFkZEV2ZW50TGlzdGVuZXImJiF3aW5kb3cuYXR0YWNoRXZlbnQpLGNhblVzZVZpZXdwb3J0OnImJiEhd2luZG93LnNjcmVlbixpc0luV29ya2VyOiFyfTtlLmV4cG9ydHM9aX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe2lmKCJ1bmRlZmluZWQiPT09dHlwZW9mKGU9ZXx8KCJ1bmRlZmluZWQiIT09dHlwZW9mIGRvY3VtZW50P2RvY3VtZW50OnZvaWQgMCkpKXJldHVybiBudWxsO3RyeXtyZXR1cm4gZS5hY3RpdmVFbGVtZW50fHxlLmJvZHl9Y2F0Y2godCl7cmV0dXJuIGUuYm9keX19ZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybiBlPT09dD8wIT09ZXx8MCE9PXR8fDEvZT09PTEvdDplIT09ZSYmdCE9PXR9ZnVuY3Rpb24gaShlLHQpe2lmKHIoZSx0KSlyZXR1cm4hMDtpZigib2JqZWN0IiE9PXR5cGVvZiBlfHxudWxsPT09ZXx8Im9iamVjdCIhPT10eXBlb2YgdHx8bnVsbD09PXQpcmV0dXJuITE7dmFyIG49T2JqZWN0LmtleXMoZSksaT1PYmplY3Qua2V5cyh0KTtpZihuLmxlbmd0aCE9PWkubGVuZ3RoKXJldHVybiExO2Zvcih2YXIgYT0wO2E8bi5sZW5ndGg7YSsrKWlmKCFvLmNhbGwodCxuW2FdKXx8IXIoZVtuW2FdXSx0W25bYV1dKSlyZXR1cm4hMTtyZXR1cm4hMH12YXIgbz1PYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5O2UuZXhwb3J0cz1pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4hKCFlfHwhdCkmJihlPT09dHx8IWkoZSkmJihpKHQpP3IoZSx0LnBhcmVudE5vZGUpOiJjb250YWlucyJpbiBlP2UuY29udGFpbnModCk6ISFlLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uJiYhISgxNiZlLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKHQpKSkpfXZhciBpPW4oMzE5KTtlLmV4cG9ydHM9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBpKGUpJiYzPT1lLm5vZGVUeXBlfXZhciBpPW4oMzIwKTtlLmV4cG9ydHM9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PWU/ZS5vd25lckRvY3VtZW50fHxlOmRvY3VtZW50LG49dC5kZWZhdWx0Vmlld3x8d2luZG93O3JldHVybiEoIWV8fCEoImZ1bmN0aW9uIj09PXR5cGVvZiBuLk5vZGU/ZSBpbnN0YW5jZW9mIG4uTm9kZToib2JqZWN0Ij09PXR5cGVvZiBlJiYibnVtYmVyIj09PXR5cGVvZiBlLm5vZGVUeXBlJiYic3RyaW5nIj09PXR5cGVvZiBlLm5vZGVOYW1lKSl9ZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9bigxMDApLGk9big5OSksbz1uKDMyMik7ZS5leHBvcnRzPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbixyLGEscyl7cyE9PW8mJmkoITEsIkNhbGxpbmcgUHJvcFR5cGVzIHZhbGlkYXRvcnMgZGlyZWN0bHkgaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgYHByb3AtdHlwZXNgIHBhY2thZ2UuIFVzZSBQcm9wVHlwZXMuY2hlY2tQcm9wVHlwZXMoKSB0byBjYWxsIHRoZW0uIFJlYWQgbW9yZSBhdCBodHRwOi8vZmIubWUvdXNlLWNoZWNrLXByb3AtdHlwZXMiKX1mdW5jdGlvbiB0KCl7cmV0dXJuIGV9ZS5pc1JlcXVpcmVkPWU7dmFyIG49e2FycmF5OmUsYm9vbDplLGZ1bmM6ZSxudW1iZXI6ZSxvYmplY3Q6ZSxzdHJpbmc6ZSxzeW1ib2w6ZSxhbnk6ZSxhcnJheU9mOnQsZWxlbWVudDplLGluc3RhbmNlT2Y6dCxub2RlOmUsb2JqZWN0T2Y6dCxvbmVPZjp0LG9uZU9mVHlwZTp0LHNoYXBlOnQsZXhhY3Q6dH07cmV0dXJuIG4uY2hlY2tQcm9wVHlwZXM9cixuLlByb3BUeXBlcz1uLG59fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz0iU0VDUkVUX0RPX05PVF9QQVNTX1RISVNfT1JfWU9VX1dJTExfQkVfRklSRUQifSwsLCwsLCxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBpKGUsdCl7aWYoIWUpdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKCJ0aGlzIGhhc24ndCBiZWVuIGluaXRpYWxpc2VkIC0gc3VwZXIoKSBoYXNuJ3QgYmVlbiBjYWxsZWQiKTtyZXR1cm4hdHx8Im9iamVjdCIhPT10eXBlb2YgdCYmImZ1bmN0aW9uIiE9PXR5cGVvZiB0P2U6dH1mdW5jdGlvbiBvKGUsdCl7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJTdXBlciBleHByZXNzaW9uIG11c3QgZWl0aGVyIGJlIG51bGwgb3IgYSBmdW5jdGlvbiwgbm90ICIrdHlwZW9mIHQpO2UucHJvdG90eXBlPU9iamVjdC5jcmVhdGUodCYmdC5wcm90b3R5cGUse2NvbnN0cnVjdG9yOnt2YWx1ZTplLGVudW1lcmFibGU6ITEsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfX0pLHQmJihPYmplY3Quc2V0UHJvdG90eXBlT2Y/T2JqZWN0LnNldFByb3RvdHlwZU9mKGUsdCk6ZS5fX3Byb3RvX189dCl9ZnVuY3Rpb24gYSgpe3ZhciBlLHQ9YXJndW1lbnRzLmxlbmd0aD4wJiZ2b2lkIDAhPT1hcmd1bWVudHNbMF0/YXJndW1lbnRzWzBdOiJzdG9yZSIsbj1hcmd1bWVudHNbMV0sYT1ufHx0KyJTdWJzY3JpcHRpb24iLHU9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gbihvLGEpe3IodGhpcyxuKTt2YXIgcz1pKHRoaXMsZS5jYWxsKHRoaXMsbyxhKSk7cmV0dXJuIHNbdF09by5zdG9yZSxzfXJldHVybiBvKG4sZSksbi5wcm90b3R5cGUuZ2V0Q2hpbGRDb250ZXh0PWZ1bmN0aW9uKCl7dmFyIGU7cmV0dXJuIGU9e30sZVt0XT10aGlzW3RdLGVbYV09bnVsbCxlfSxuLnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXtyZXR1cm4gcy5DaGlsZHJlbi5vbmx5KHRoaXMucHJvcHMuY2hpbGRyZW4pfSxufShzLkNvbXBvbmVudCk7cmV0dXJuIHUucHJvcFR5cGVzPXtzdG9yZTpsLmEuaXNSZXF1aXJlZCxjaGlsZHJlbjpjLmEuZWxlbWVudC5pc1JlcXVpcmVkfSx1LmNoaWxkQ29udGV4dFR5cGVzPShlPXt9LGVbdF09bC5hLmlzUmVxdWlyZWQsZVthXT1sLmIsZSksdX10LmE9YTt2YXIgcz1uKDApLHU9KG4ubihzKSxuKDE4KSksYz1uLm4odSksbD1uKDE1NSk7bigxMDEpO3QuYj1hKCl9LGZ1bmN0aW9uKGUsdCxuKXshZnVuY3Rpb24odCxuKXtlLmV4cG9ydHM9bigpfSgwLGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO3ZhciBlPXtjaGlsZENvbnRleHRUeXBlczohMCxjb250ZXh0VHlwZXM6ITAsZGVmYXVsdFByb3BzOiEwLGRpc3BsYXlOYW1lOiEwLGdldERlZmF1bHRQcm9wczohMCxnZXREZXJpdmVkU3RhdGVGcm9tUHJvcHM6ITAsbWl4aW5zOiEwLHByb3BUeXBlczohMCx0eXBlOiEwfSx0PXtuYW1lOiEwLGxlbmd0aDohMCxwcm90b3R5cGU6ITAsY2FsbGVyOiEwLGNhbGxlZTohMCxhcmd1bWVudHM6ITAsYXJpdHk6ITB9LG49T2JqZWN0LmRlZmluZVByb3BlcnR5LHI9T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMsaT1PYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzLG89T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcixhPU9iamVjdC5nZXRQcm90b3R5cGVPZixzPWEmJmEoT2JqZWN0KTtyZXR1cm4gZnVuY3Rpb24gdShjLGwscCl7aWYoInN0cmluZyIhPT10eXBlb2YgbCl7aWYocyl7dmFyIGY9YShsKTtmJiZmIT09cyYmdShjLGYscCl9dmFyIGQ9cihsKTtpJiYoZD1kLmNvbmNhdChpKGwpKSk7Zm9yKHZhciBoPTA7aDxkLmxlbmd0aDsrK2gpe3ZhciBtPWRbaF07aWYoIWVbbV0mJiF0W21dJiYoIXB8fCFwW21dKSl7dmFyIGc9byhsLG0pO3RyeXtuKGMsbSxnKX1jYXRjaChlKXt9fX1yZXR1cm4gY31yZXR1cm4gY319KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9ZnVuY3Rpb24gaSgpe3ZhciBlPVtdLHQ9W107cmV0dXJue2NsZWFyOmZ1bmN0aW9uKCl7dD1vLGU9b30sbm90aWZ5OmZ1bmN0aW9uKCl7Zm9yKHZhciBuPWU9dCxyPTA7cjxuLmxlbmd0aDtyKyspbltyXSgpfSxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdH0sc3Vic2NyaWJlOmZ1bmN0aW9uKG4pe3ZhciByPSEwO3JldHVybiB0PT09ZSYmKHQ9ZS5zbGljZSgpKSx0LnB1c2gobiksZnVuY3Rpb24oKXtyJiZlIT09byYmKHI9ITEsdD09PWUmJih0PWUuc2xpY2UoKSksdC5zcGxpY2UodC5pbmRleE9mKG4pLDEpKX19fX1uLmQodCwiYSIsZnVuY3Rpb24oKXtyZXR1cm4gc30pO3ZhciBvPW51bGwsYT17bm90aWZ5OmZ1bmN0aW9uKCl7fX0scz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCxuLGkpe3IodGhpcyxlKSx0aGlzLnN0b3JlPXQsdGhpcy5wYXJlbnRTdWI9bix0aGlzLm9uU3RhdGVDaGFuZ2U9aSx0aGlzLnVuc3Vic2NyaWJlPW51bGwsdGhpcy5saXN0ZW5lcnM9YX1yZXR1cm4gZS5wcm90b3R5cGUuYWRkTmVzdGVkU3ViPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLnRyeVN1YnNjcmliZSgpLHRoaXMubGlzdGVuZXJzLnN1YnNjcmliZShlKX0sZS5wcm90b3R5cGUubm90aWZ5TmVzdGVkU3Vicz1mdW5jdGlvbigpe3RoaXMubGlzdGVuZXJzLm5vdGlmeSgpfSxlLnByb3RvdHlwZS5pc1N1YnNjcmliZWQ9ZnVuY3Rpb24oKXtyZXR1cm4gQm9vbGVhbih0aGlzLnVuc3Vic2NyaWJlKX0sZS5wcm90b3R5cGUudHJ5U3Vic2NyaWJlPWZ1bmN0aW9uKCl7dGhpcy51bnN1YnNjcmliZXx8KHRoaXMudW5zdWJzY3JpYmU9dGhpcy5wYXJlbnRTdWI/dGhpcy5wYXJlbnRTdWIuYWRkTmVzdGVkU3ViKHRoaXMub25TdGF0ZUNoYW5nZSk6dGhpcy5zdG9yZS5zdWJzY3JpYmUodGhpcy5vblN0YXRlQ2hhbmdlKSx0aGlzLmxpc3RlbmVycz1pKCkpfSxlLnByb3RvdHlwZS50cnlVbnN1YnNjcmliZT1mdW5jdGlvbigpe3RoaXMudW5zdWJzY3JpYmUmJih0aGlzLnVuc3Vic2NyaWJlKCksdGhpcy51bnN1YnNjcmliZT1udWxsLHRoaXMubGlzdGVuZXJzLmNsZWFyKCksdGhpcy5saXN0ZW5lcnM9YSl9LGV9KCl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPXt9O2Zvcih2YXIgciBpbiBlKXQuaW5kZXhPZihyKT49MHx8T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUscikmJihuW3JdPWVbcl0pO3JldHVybiBufWZ1bmN0aW9uIGkoZSx0LG4pe2Zvcih2YXIgcj10Lmxlbmd0aC0xO3I+PTA7ci0tKXt2YXIgaT10W3JdKGUpO2lmKGkpcmV0dXJuIGl9cmV0dXJuIGZ1bmN0aW9uKHQscil7dGhyb3cgbmV3IEVycm9yKCJJbnZhbGlkIHZhbHVlIG9mIHR5cGUgIit0eXBlb2YgZSsiIGZvciAiK24rIiBhcmd1bWVudCB3aGVuIGNvbm5lY3RpbmcgY29tcG9uZW50ICIrci53cmFwcGVkQ29tcG9uZW50TmFtZSsiLiIpfX1mdW5jdGlvbiBvKGUsdCl7cmV0dXJuIGU9PT10fXZhciBhPW4oMTU2KSxzPW4oMzMzKSx1PW4oMzM0KSxjPW4oMzUyKSxsPW4oMzUzKSxwPW4oMzU0KSxmPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspe3ZhciBuPWFyZ3VtZW50c1t0XTtmb3IodmFyIHIgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmKGVbcl09bltyXSl9cmV0dXJuIGV9O3QuYT1mdW5jdGlvbigpe3ZhciBlPWFyZ3VtZW50cy5sZW5ndGg+MCYmdm9pZCAwIT09YXJndW1lbnRzWzBdP2FyZ3VtZW50c1swXTp7fSx0PWUuY29ubmVjdEhPQyxuPXZvaWQgMD09PXQ/YS5hOnQsZD1lLm1hcFN0YXRlVG9Qcm9wc0ZhY3RvcmllcyxoPXZvaWQgMD09PWQ/Yy5hOmQsbT1lLm1hcERpc3BhdGNoVG9Qcm9wc0ZhY3RvcmllcyxnPXZvaWQgMD09PW0/dS5hOm0seT1lLm1lcmdlUHJvcHNGYWN0b3JpZXMsdj12b2lkIDA9PT15P2wuYTp5LGI9ZS5zZWxlY3RvckZhY3RvcnkseD12b2lkIDA9PT1iP3AuYTpiO3JldHVybiBmdW5jdGlvbihlLHQsYSl7dmFyIHU9YXJndW1lbnRzLmxlbmd0aD4zJiZ2b2lkIDAhPT1hcmd1bWVudHNbM10/YXJndW1lbnRzWzNdOnt9LGM9dS5wdXJlLGw9dm9pZCAwPT09Y3x8YyxwPXUuYXJlU3RhdGVzRXF1YWwsZD12b2lkIDA9PT1wP286cCxtPXUuYXJlT3duUHJvcHNFcXVhbCx5PXZvaWQgMD09PW0/cy5hOm0sYj11LmFyZVN0YXRlUHJvcHNFcXVhbCxDPXZvaWQgMD09PWI/cy5hOmIsRT11LmFyZU1lcmdlZFByb3BzRXF1YWwsRD12b2lkIDA9PT1FP3MuYTpFLHc9cih1LFsicHVyZSIsImFyZVN0YXRlc0VxdWFsIiwiYXJlT3duUHJvcHNFcXVhbCIsImFyZVN0YXRlUHJvcHNFcXVhbCIsImFyZU1lcmdlZFByb3BzRXF1YWwiXSksUz1pKGUsaCwibWFwU3RhdGVUb1Byb3BzIiksaz1pKHQsZywibWFwRGlzcGF0Y2hUb1Byb3BzIiksQT1pKGEsdiwibWVyZ2VQcm9wcyIpO3JldHVybiBuKHgsZih7bWV0aG9kTmFtZToiY29ubmVjdCIsZ2V0RGlzcGxheU5hbWU6ZnVuY3Rpb24oZSl7cmV0dXJuIkNvbm5lY3QoIitlKyIpIn0sc2hvdWxkSGFuZGxlU3RhdGVDaGFuZ2VzOkJvb2xlYW4oZSksaW5pdE1hcFN0YXRlVG9Qcm9wczpTLGluaXRNYXBEaXNwYXRjaFRvUHJvcHM6ayxpbml0TWVyZ2VQcm9wczpBLHB1cmU6bCxhcmVTdGF0ZXNFcXVhbDpkLGFyZU93blByb3BzRXF1YWw6eSxhcmVTdGF0ZVByb3BzRXF1YWw6QyxhcmVNZXJnZWRQcm9wc0VxdWFsOkR9LHcpKX19KCl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybiBlPT09dD8wIT09ZXx8MCE9PXR8fDEvZT09PTEvdDplIT09ZSYmdCE9PXR9ZnVuY3Rpb24gaShlLHQpe2lmKHIoZSx0KSlyZXR1cm4hMDtpZigib2JqZWN0IiE9PXR5cGVvZiBlfHxudWxsPT09ZXx8Im9iamVjdCIhPT10eXBlb2YgdHx8bnVsbD09PXQpcmV0dXJuITE7dmFyIG49T2JqZWN0LmtleXMoZSksaT1PYmplY3Qua2V5cyh0KTtpZihuLmxlbmd0aCE9PWkubGVuZ3RoKXJldHVybiExO2Zvcih2YXIgYT0wO2E8bi5sZW5ndGg7YSsrKWlmKCFvLmNhbGwodCxuW2FdKXx8IXIoZVtuW2FdXSx0W25bYV1dKSlyZXR1cm4hMTtyZXR1cm4hMH10LmE9aTt2YXIgbz1PYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuImZ1bmN0aW9uIj09PXR5cGVvZiBlP09iamVjdChzLmIpKGUsIm1hcERpc3BhdGNoVG9Qcm9wcyIpOnZvaWQgMH1mdW5jdGlvbiBpKGUpe3JldHVybiBlP3ZvaWQgMDpPYmplY3Qocy5hKShmdW5jdGlvbihlKXtyZXR1cm57ZGlzcGF0Y2g6ZX19KX1mdW5jdGlvbiBvKGUpe3JldHVybiBlJiYib2JqZWN0Ij09PXR5cGVvZiBlP09iamVjdChzLmEpKGZ1bmN0aW9uKHQpe3JldHVybiBPYmplY3QoYS5iaW5kQWN0aW9uQ3JlYXRvcnMpKGUsdCl9KTp2b2lkIDB9dmFyIGE9big0MCkscz1uKDE2Mik7dC5hPVtyLGksb119LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gbnVsbD09ZT92b2lkIDA9PT1lP3U6czpjJiZjIGluIE9iamVjdChlKT9PYmplY3Qoby5hKShlKTpPYmplY3QoYS5hKShlKX12YXIgaT1uKDE1OSksbz1uKDMzOCksYT1uKDMzOSkscz0iW29iamVjdCBOdWxsXSIsdT0iW29iamVjdCBVbmRlZmluZWRdIixjPWkuYT9pLmEudG9TdHJpbmdUYWc6dm9pZCAwO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oMzM3KSxpPSJvYmplY3QiPT10eXBlb2Ygc2VsZiYmc2VsZiYmc2VsZi5PYmplY3Q9PT1PYmplY3QmJnNlbGYsbz1yLmF8fGl8fEZ1bmN0aW9uKCJyZXR1cm4gdGhpcyIpKCk7dC5hPW99LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7KGZ1bmN0aW9uKGUpe3ZhciBuPSJvYmplY3QiPT10eXBlb2YgZSYmZSYmZS5PYmplY3Q9PT1PYmplY3QmJmU7dC5hPW59KS5jYWxsKHQsbigxMSkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dmFyIHQ9YS5jYWxsKGUsdSksbj1lW3VdO3RyeXtlW3VdPXZvaWQgMDt2YXIgcj0hMH1jYXRjaChlKXt9dmFyIGk9cy5jYWxsKGUpO3JldHVybiByJiYodD9lW3VdPW46ZGVsZXRlIGVbdV0pLGl9dmFyIGk9bigxNTkpLG89T2JqZWN0LnByb3RvdHlwZSxhPW8uaGFzT3duUHJvcGVydHkscz1vLnRvU3RyaW5nLHU9aS5hP2kuYS50b1N0cmluZ1RhZzp2b2lkIDA7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gby5jYWxsKGUpfXZhciBpPU9iamVjdC5wcm90b3R5cGUsbz1pLnRvU3RyaW5nO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oMzQxKSxpPU9iamVjdChyLmEpKE9iamVjdC5nZXRQcm90b3R5cGVPZixPYmplY3QpO3QuYT1pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4gZnVuY3Rpb24obil7cmV0dXJuIGUodChuKSl9fXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG51bGwhPWUmJiJvYmplY3QiPT10eXBlb2YgZX10LmE9cn0sZnVuY3Rpb24oZSx0LG4pe2UuZXhwb3J0cz1uKDM0NCl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7KGZ1bmN0aW9uKGUscil7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpLG89bigzNDUpLGE9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShvKTtpPSJ1bmRlZmluZWQiIT09dHlwZW9mIHNlbGY/c2VsZjoidW5kZWZpbmVkIiE9PXR5cGVvZiB3aW5kb3c/d2luZG93OiJ1bmRlZmluZWQiIT09dHlwZW9mIGU/ZTpyO3ZhciBzPSgwLGEuZGVmYXVsdCkoaSk7dC5kZWZhdWx0PXN9KS5jYWxsKHQsbigxMSksbigxMDIpKGUpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0LG49ZS5TeW1ib2w7cmV0dXJuImZ1bmN0aW9uIj09PXR5cGVvZiBuP24ub2JzZXJ2YWJsZT90PW4ub2JzZXJ2YWJsZToodD1uKCJvYnNlcnZhYmxlIiksbi5vYnNlcnZhYmxlPXQpOnQ9IkBAb2JzZXJ2YWJsZSIsdH1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPXQmJnQudHlwZTtyZXR1cm4iR2l2ZW4gYWN0aW9uICIrKG4mJiciJytuLnRvU3RyaW5nKCkrJyInfHwiYW4gYWN0aW9uIikrJywgcmVkdWNlciAiJytlKyciIHJldHVybmVkIHVuZGVmaW5lZC4gVG8gaWdub3JlIGFuIGFjdGlvbiwgeW91IG11c3QgZXhwbGljaXRseSByZXR1cm4gdGhlIHByZXZpb3VzIHN0YXRlLiBJZiB5b3Ugd2FudCB0aGlzIHJlZHVjZXIgdG8gaG9sZCBubyB2YWx1ZSwgeW91IGNhbiByZXR1cm4gbnVsbCBpbnN0ZWFkIG9mIHVuZGVmaW5lZC4nfWZ1bmN0aW9uIGkoZSl7T2JqZWN0LmtleXMoZSkuZm9yRWFjaChmdW5jdGlvbih0KXt2YXIgbj1lW3RdO2lmKCJ1bmRlZmluZWQiPT09dHlwZW9mIG4odm9pZCAwLHt0eXBlOmEuYS5JTklUfSkpdGhyb3cgbmV3IEVycm9yKCdSZWR1Y2VyICInK3QrIlwiIHJldHVybmVkIHVuZGVmaW5lZCBkdXJpbmcgaW5pdGlhbGl6YXRpb24uIElmIHRoZSBzdGF0ZSBwYXNzZWQgdG8gdGhlIHJlZHVjZXIgaXMgdW5kZWZpbmVkLCB5b3UgbXVzdCBleHBsaWNpdGx5IHJldHVybiB0aGUgaW5pdGlhbCBzdGF0ZS4gVGhlIGluaXRpYWwgc3RhdGUgbWF5IG5vdCBiZSB1bmRlZmluZWQuIElmIHlvdSBkb24ndCB3YW50IHRvIHNldCBhIHZhbHVlIGZvciB0aGlzIHJlZHVjZXIsIHlvdSBjYW4gdXNlIG51bGwgaW5zdGVhZCBvZiB1bmRlZmluZWQuIik7aWYoInVuZGVmaW5lZCI9PT10eXBlb2Ygbih2b2lkIDAse3R5cGU6IkBAcmVkdXgvUFJPQkVfVU5LTk9XTl9BQ1RJT05fIitNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHJpbmcoNykuc3BsaXQoIiIpLmpvaW4oIi4iKX0pKXRocm93IG5ldyBFcnJvcignUmVkdWNlciAiJyt0KyJcIiByZXR1cm5lZCB1bmRlZmluZWQgd2hlbiBwcm9iZWQgd2l0aCBhIHJhbmRvbSB0eXBlLiBEb24ndCB0cnkgdG8gaGFuZGxlICIrYS5hLklOSVQrJyBvciBvdGhlciBhY3Rpb25zIGluICJyZWR1eC8qIiBuYW1lc3BhY2UuIFRoZXkgYXJlIGNvbnNpZGVyZWQgcHJpdmF0ZS4gSW5zdGVhZCwgeW91IG11c3QgcmV0dXJuIHRoZSBjdXJyZW50IHN0YXRlIGZvciBhbnkgdW5rbm93biBhY3Rpb25zLCB1bmxlc3MgaXQgaXMgdW5kZWZpbmVkLCBpbiB3aGljaCBjYXNlIHlvdSBtdXN0IHJldHVybiB0aGUgaW5pdGlhbCBzdGF0ZSwgcmVnYXJkbGVzcyBvZiB0aGUgYWN0aW9uIHR5cGUuIFRoZSBpbml0aWFsIHN0YXRlIG1heSBub3QgYmUgdW5kZWZpbmVkLCBidXQgY2FuIGJlIG51bGwuJyl9KX1mdW5jdGlvbiBvKGUpe2Zvcih2YXIgdD1PYmplY3Qua2V5cyhlKSxuPXt9LG89MDtvPHQubGVuZ3RoO28rKyl7dmFyIGE9dFtvXTsiZnVuY3Rpb24iPT09dHlwZW9mIGVbYV0mJihuW2FdPWVbYV0pfXZhciBzPU9iamVjdC5rZXlzKG4pLHU9dm9pZCAwO3RyeXtpKG4pfWNhdGNoKGUpe3U9ZX1yZXR1cm4gZnVuY3Rpb24oKXt2YXIgZT1hcmd1bWVudHMubGVuZ3RoPjAmJnZvaWQgMCE9PWFyZ3VtZW50c1swXT9hcmd1bWVudHNbMF06e30sdD1hcmd1bWVudHNbMV07aWYodSl0aHJvdyB1O2Zvcih2YXIgaT0hMSxvPXt9LGE9MDthPHMubGVuZ3RoO2ErKyl7dmFyIGM9c1thXSxsPW5bY10scD1lW2NdLGY9bChwLHQpO2lmKCJ1bmRlZmluZWQiPT09dHlwZW9mIGYpe3ZhciBkPXIoYyx0KTt0aHJvdyBuZXcgRXJyb3IoZCl9b1tjXT1mLGk9aXx8ZiE9PXB9cmV0dXJuIGk/bzplfX10LmE9bzt2YXIgYT1uKDE1Nyk7bigxNTgpLG4oMTYwKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIHQoZS5hcHBseSh2b2lkIDAsYXJndW1lbnRzKSl9fWZ1bmN0aW9uIGkoZSx0KXtpZigiZnVuY3Rpb24iPT09dHlwZW9mIGUpcmV0dXJuIHIoZSx0KTtpZigib2JqZWN0IiE9PXR5cGVvZiBlfHxudWxsPT09ZSl0aHJvdyBuZXcgRXJyb3IoImJpbmRBY3Rpb25DcmVhdG9ycyBleHBlY3RlZCBhbiBvYmplY3Qgb3IgYSBmdW5jdGlvbiwgaW5zdGVhZCByZWNlaXZlZCAiKyhudWxsPT09ZT8ibnVsbCI6dHlwZW9mIGUpKycuIERpZCB5b3Ugd3JpdGUgImltcG9ydCBBY3Rpb25DcmVhdG9ycyBmcm9tIiBpbnN0ZWFkIG9mICJpbXBvcnQgKiBhcyBBY3Rpb25DcmVhdG9ycyBmcm9tIj8nKTtmb3IodmFyIG49T2JqZWN0LmtleXMoZSksaT17fSxvPTA7bzxuLmxlbmd0aDtvKyspe3ZhciBhPW5bb10scz1lW2FdOyJmdW5jdGlvbiI9PT10eXBlb2YgcyYmKGlbYV09cihzLHQpKX1yZXR1cm4gaX10LmE9aX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKCl7Zm9yKHZhciBlPWFyZ3VtZW50cy5sZW5ndGgsdD1BcnJheShlKSxuPTA7bjxlO24rKyl0W25dPWFyZ3VtZW50c1tuXTtyZXR1cm4gZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKG4scixhKXt2YXIgcz1lKG4scixhKSx1PXMuZGlzcGF0Y2gsYz1bXSxsPXtnZXRTdGF0ZTpzLmdldFN0YXRlLGRpc3BhdGNoOmZ1bmN0aW9uKGUpe3JldHVybiB1KGUpfX07cmV0dXJuIGM9dC5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUobCl9KSx1PWkuYS5hcHBseSh2b2lkIDAsYykocy5kaXNwYXRjaCksbyh7fSxzLHtkaXNwYXRjaDp1fSl9fX10LmE9cjt2YXIgaT1uKDE2MSksbz1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PWEuY2FsbChlLHUpLG49ZVt1XTt0cnl7ZVt1XT12b2lkIDA7dmFyIHI9ITB9Y2F0Y2goZSl7fXZhciBpPXMuY2FsbChlKTtyZXR1cm4gciYmKHQ/ZVt1XT1uOmRlbGV0ZSBlW3VdKSxpfXZhciBpPW4oMTAzKSxvPU9iamVjdC5wcm90b3R5cGUsYT1vLmhhc093blByb3BlcnR5LHM9by50b1N0cmluZyx1PWkuYT9pLmEudG9TdHJpbmdUYWc6dm9pZCAwO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG8uY2FsbChlKX12YXIgaT1PYmplY3QucHJvdG90eXBlLG89aS50b1N0cmluZzt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDE2NSksaT1PYmplY3Qoci5hKShPYmplY3QuZ2V0UHJvdG90eXBlT2YsT2JqZWN0KTt0LmE9aX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiJmdW5jdGlvbiI9PT10eXBlb2YgZT9PYmplY3Qoby5iKShlLCJtYXBTdGF0ZVRvUHJvcHMiKTp2b2lkIDB9ZnVuY3Rpb24gaShlKXtyZXR1cm4gZT92b2lkIDA6T2JqZWN0KG8uYSkoZnVuY3Rpb24oKXtyZXR1cm57fX0pfXZhciBvPW4oMTYyKTt0LmE9W3IsaV19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuIHMoe30sbixlLHQpfWZ1bmN0aW9uIGkoZSl7cmV0dXJuIGZ1bmN0aW9uKHQsbil7dmFyIHI9KG4uZGlzcGxheU5hbWUsbi5wdXJlKSxpPW4uYXJlTWVyZ2VkUHJvcHNFcXVhbCxvPSExLGE9dm9pZCAwO3JldHVybiBmdW5jdGlvbih0LG4scyl7dmFyIHU9ZSh0LG4scyk7cmV0dXJuIG8/ciYmaSh1LGEpfHwoYT11KToobz0hMCxhPXUpLGF9fX1mdW5jdGlvbiBvKGUpe3JldHVybiJmdW5jdGlvbiI9PT10eXBlb2YgZT9pKGUpOnZvaWQgMH1mdW5jdGlvbiBhKGUpe3JldHVybiBlP3ZvaWQgMDpmdW5jdGlvbigpe3JldHVybiByfX12YXIgcz0obigxNjMpLE9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspe3ZhciBuPWFyZ3VtZW50c1t0XTtmb3IodmFyIHIgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmKGVbcl09bltyXSl9cmV0dXJuIGV9KTt0LmE9W28sYV19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPXt9O2Zvcih2YXIgciBpbiBlKXQuaW5kZXhPZihyKT49MHx8T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUscikmJihuW3JdPWVbcl0pO3JldHVybiBufWZ1bmN0aW9uIGkoZSx0LG4scil7cmV0dXJuIGZ1bmN0aW9uKGksbyl7cmV0dXJuIG4oZShpLG8pLHQocixvKSxvKX19ZnVuY3Rpb24gbyhlLHQsbixyLGkpe2Z1bmN0aW9uIG8oaSxvKXtyZXR1cm4gaD1pLG09byxnPWUoaCxtKSx5PXQocixtKSx2PW4oZyx5LG0pLGQ9ITAsdn1mdW5jdGlvbiBhKCl7cmV0dXJuIGc9ZShoLG0pLHQuZGVwZW5kc09uT3duUHJvcHMmJih5PXQocixtKSksdj1uKGcseSxtKX1mdW5jdGlvbiBzKCl7cmV0dXJuIGUuZGVwZW5kc09uT3duUHJvcHMmJihnPWUoaCxtKSksdC5kZXBlbmRzT25Pd25Qcm9wcyYmKHk9dChyLG0pKSx2PW4oZyx5LG0pfWZ1bmN0aW9uIHUoKXt2YXIgdD1lKGgsbSkscj0hZih0LGcpO3JldHVybiBnPXQsciYmKHY9bihnLHksbSkpLHZ9ZnVuY3Rpb24gYyhlLHQpe3ZhciBuPSFwKHQsbSkscj0hbChlLGgpO3JldHVybiBoPWUsbT10LG4mJnI/YSgpOm4/cygpOnI/dSgpOnZ9dmFyIGw9aS5hcmVTdGF0ZXNFcXVhbCxwPWkuYXJlT3duUHJvcHNFcXVhbCxmPWkuYXJlU3RhdGVQcm9wc0VxdWFsLGQ9ITEsaD12b2lkIDAsbT12b2lkIDAsZz12b2lkIDAseT12b2lkIDAsdj12b2lkIDA7cmV0dXJuIGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGQ/YyhlLHQpOm8oZSx0KX19ZnVuY3Rpb24gYShlLHQpe3ZhciBuPXQuaW5pdE1hcFN0YXRlVG9Qcm9wcyxhPXQuaW5pdE1hcERpc3BhdGNoVG9Qcm9wcyxzPXQuaW5pdE1lcmdlUHJvcHMsdT1yKHQsWyJpbml0TWFwU3RhdGVUb1Byb3BzIiwiaW5pdE1hcERpc3BhdGNoVG9Qcm9wcyIsImluaXRNZXJnZVByb3BzIl0pLGM9bihlLHUpLGw9YShlLHUpLHA9cyhlLHUpO3JldHVybih1LnB1cmU/bzppKShjLGwscCxlLHUpfXQuYT1hO24oMzU1KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtuKDEwMSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oNDApLGk9bigxMDQpLG89bigzNjIpLGE9bigxNykscz1uKDEyKSx1PW4oNTE3KSxjPWkuZGVmYXVsdCgpLGw9W3IuYXBwbHlNaWRkbGV3YXJlKGMpXSxwPXdpbmRvdy5fX1JFRFVYX0RFVlRPT0xTX0VYVEVOU0lPTl9DT01QT1NFX198fHIuY29tcG9zZSxmPXUuZGVzZXJpYWxpemVTdGF0ZSgpO3QuZGVmYXVsdD1mdW5jdGlvbigpe3ZhciBlPXIuY3JlYXRlU3RvcmUoYS5kZWZhdWx0LGYscC5hcHBseShudWxsLGwpKTtyZXR1cm4gZS5zdWJzY3JpYmUodS5zZXJpYWxpemVTdGF0ZShlKSksd2luZG93LnM9ZSx3aW5kb3cuc2Vzc2lvbj1mdW5jdGlvbigpe3JldHVybiBzLmdldFNlbGVjdGVkU2Vzc2lvbihlLmdldFN0YXRlKCkpfSxjLnJ1bihvLmRlZmF1bHQpLGV9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2YXIgbj17fTtmb3IodmFyIHIgaW4gZSl0LmluZGV4T2Yocik+PTB8fE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLHIpJiYobltyXT1lW3JdKTtyZXR1cm4gbn1mdW5jdGlvbiBpKCl7ZnVuY3Rpb24gZSh0KXt2YXIgbj10LmdldFN0YXRlLHI9dC5kaXNwYXRjaCxmPU9iamVjdChhLmMpKCk7cmV0dXJuIGYuZW1pdD0odS5lbWl0dGVyfHxvLm8pKGYuZW1pdCksZS5ydW49cy5hLmJpbmQobnVsbCx7Y29udGV4dDppLHN1YnNjcmliZTpmLnN1YnNjcmliZSxkaXNwYXRjaDpyLGdldFN0YXRlOm4sc2FnYU1vbml0b3I6Yyxsb2dnZXI6bCxvbkVycm9yOnB9KSxmdW5jdGlvbihlKXtyZXR1cm4gZnVuY3Rpb24odCl7YyYmYy5hY3Rpb25EaXNwYXRjaGVkJiZjLmFjdGlvbkRpc3BhdGNoZWQodCk7dmFyIG49ZSh0KTtyZXR1cm4gZi5lbWl0KHQpLG59fX12YXIgdD1hcmd1bWVudHMubGVuZ3RoPjAmJnZvaWQgMCE9PWFyZ3VtZW50c1swXT9hcmd1bWVudHNbMF06e30sbj10LmNvbnRleHQsaT12b2lkIDA9PT1uP3t9Om4sdT1yKHQsWyJjb250ZXh0Il0pLGM9dS5zYWdhTW9uaXRvcixsPXUubG9nZ2VyLHA9dS5vbkVycm9yO2lmKG8ucS5mdW5jKHUpKXRocm93IG5ldyBFcnJvcigiU2FnYSBtaWRkbGV3YXJlIG5vIGxvbmdlciBhY2NlcHQgR2VuZXJhdG9yIGZ1bmN0aW9ucy4gVXNlIHNhZ2FNaWRkbGV3YXJlLnJ1biBpbnN0ZWFkIik7aWYobCYmIW8ucS5mdW5jKGwpKXRocm93IG5ldyBFcnJvcigiYG9wdGlvbnMubG9nZ2VyYCBwYXNzZWQgdG8gdGhlIFNhZ2EgbWlkZGxld2FyZSBpcyBub3QgYSBmdW5jdGlvbiEiKTtpZihwJiYhby5xLmZ1bmMocCkpdGhyb3cgbmV3IEVycm9yKCJgb3B0aW9ucy5vbkVycm9yYCBwYXNzZWQgdG8gdGhlIFNhZ2EgbWlkZGxld2FyZSBpcyBub3QgYSBmdW5jdGlvbiEiKTtpZih1LmVtaXR0ZXImJiFvLnEuZnVuYyh1LmVtaXR0ZXIpKXRocm93IG5ldyBFcnJvcigiYG9wdGlvbnMuZW1pdHRlcmAgcGFzc2VkIHRvIHRoZSBTYWdhIG1pZGRsZXdhcmUgaXMgbm90IGEgZnVuY3Rpb24hIik7cmV0dXJuIGUucnVuPWZ1bmN0aW9uKCl7dGhyb3cgbmV3IEVycm9yKCJCZWZvcmUgcnVubmluZyBhIFNhZ2EsIHlvdSBtdXN0IG1vdW50IHRoZSBTYWdhIG1pZGRsZXdhcmUgb24gdGhlIFN0b3JlIHVzaW5nIGFwcGx5TWlkZGxld2FyZSIpfSxlLnNldENvbnRleHQ9ZnVuY3Rpb24oZSl7T2JqZWN0KG8uaCkoZSxvLnEub2JqZWN0LE9iamVjdChvLmspKCJzYWdhTWlkZGxld2FyZSIsZSkpLG8udi5hc3NpZ24oaSxlKX0sZX10LmE9aTt2YXIgbz1uKDIyKSxhPW4oNDIpLHM9bigxNjcpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtmb3IodmFyIG49YXJndW1lbnRzLmxlbmd0aCxyPUFycmF5KG4+Mj9uLTI6MCkscz0yO3M8bjtzKyspcltzLTJdPWFyZ3VtZW50c1tzXTt2YXIgdT17ZG9uZTohMSx2YWx1ZTpPYmplY3Qoby5zKShlKX0sYz1mdW5jdGlvbihlKXtyZXR1cm57ZG9uZTohMSx2YWx1ZTpvLmsuYXBwbHkodm9pZCAwLFt0XS5jb25jYXQocixbZV0pKX19LGw9dm9pZCAwLHA9ZnVuY3Rpb24oZSl7cmV0dXJuIGw9ZX07cmV0dXJuIE9iamVjdChpLmEpKHtxMTpmdW5jdGlvbigpe3JldHVyblsicTIiLHUscF19LHEyOmZ1bmN0aW9uKCl7cmV0dXJuIGw9PT1hLmE/W2kuYl06WyJxMSIsYyhsKV19fSwicTEiLCJ0YWtlRXZlcnkoIitPYmplY3QoaS5jKShlKSsiLCAiK3QubmFtZSsiKSIpfXQuYT1yO3ZhciBpPW4oMTA1KSxvPW4oMzQpLGE9big0Mil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2Zvcih2YXIgbj1hcmd1bWVudHMubGVuZ3RoLHI9QXJyYXkobj4yP24tMjowKSxzPTI7czxuO3MrKylyW3MtMl09YXJndW1lbnRzW3NdO3ZhciB1PXtkb25lOiExLHZhbHVlOk9iamVjdChvLnMpKGUpfSxjPWZ1bmN0aW9uKGUpe3JldHVybntkb25lOiExLHZhbHVlOm8uay5hcHBseSh2b2lkIDAsW3RdLmNvbmNhdChyLFtlXSkpfX0sbD1mdW5jdGlvbihlKXtyZXR1cm57ZG9uZTohMSx2YWx1ZTpPYmplY3Qoby5mKShlKX19LHA9dm9pZCAwLGY9dm9pZCAwLGQ9ZnVuY3Rpb24oZSl7cmV0dXJuIHA9ZX0saD1mdW5jdGlvbihlKXtyZXR1cm4gZj1lfTtyZXR1cm4gT2JqZWN0KGkuYSkoe3ExOmZ1bmN0aW9uKCl7cmV0dXJuWyJxMiIsdSxoXX0scTI6ZnVuY3Rpb24oKXtyZXR1cm4gZj09PWEuYT9baS5iXTpwP1sicTMiLGwocCldOlsicTEiLGMoZiksZF19LHEzOmZ1bmN0aW9uKCl7cmV0dXJuWyJxMSIsYyhmKSxkXX19LCJxMSIsInRha2VMYXRlc3QoIitPYmplY3QoaS5jKShlKSsiLCAiK3QubmFtZSsiKSIpfXQuYT1yO3ZhciBpPW4oMTA1KSxvPW4oMzQpLGE9big0Mil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7Zm9yKHZhciByPWFyZ3VtZW50cy5sZW5ndGgsYz1BcnJheShyPjM/ci0zOjApLGw9MztsPHI7bCsrKWNbbC0zXT1hcmd1bWVudHNbbF07dmFyIHA9dm9pZCAwLGY9dm9pZCAwLGQ9e2RvbmU6ITEsdmFsdWU6T2JqZWN0KG8uYSkodCxzLmEuc2xpZGluZygxKSl9LGg9ZnVuY3Rpb24oKXtyZXR1cm57ZG9uZTohMSx2YWx1ZTpPYmplY3Qoby5zKShmKX19LG09ZnVuY3Rpb24oZSl7cmV0dXJue2RvbmU6ITEsdmFsdWU6by5rLmFwcGx5KHZvaWQgMCxbbl0uY29uY2F0KGMsW2VdKSl9fSxnPXtkb25lOiExLHZhbHVlOk9iamVjdChvLmUpKHUubSxlKX0seT1mdW5jdGlvbihlKXtyZXR1cm4gcD1lfSx2PWZ1bmN0aW9uKGUpe3JldHVybiBmPWV9O3JldHVybiBPYmplY3QoaS5hKSh7cTE6ZnVuY3Rpb24oKXtyZXR1cm5bInEyIixkLHZdfSxxMjpmdW5jdGlvbigpe3JldHVyblsicTMiLGgoKSx5XX0scTM6ZnVuY3Rpb24oKXtyZXR1cm4gcD09PWEuYT9baS5iXTpbInE0IixtKHApXX0scTQ6ZnVuY3Rpb24oKXtyZXR1cm5bInEyIixnXX19LCJxMSIsInRocm90dGxlKCIrT2JqZWN0KGkuYykodCkrIiwgIituLm5hbWUrIikiKX10LmE9cjt2YXIgaT1uKDEwNSksbz1uKDM0KSxhPW4oNDIpLHM9big3NiksdT1uKDIyKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9bigyMik7bi5kKHQsIlRBU0siLGZ1bmN0aW9uKCl7cmV0dXJuIHIuZX0pLG4uZCh0LCJTQUdBX0FDVElPTiIsZnVuY3Rpb24oKXtyZXR1cm4gci5jfSksbi5kKHQsIm5vb3AiLGZ1bmN0aW9uKCl7cmV0dXJuIHIudX0pLG4uZCh0LCJpcyIsZnVuY3Rpb24oKXtyZXR1cm4gci5xfSksbi5kKHQsImRlZmVycmVkIixmdW5jdGlvbigpe3JldHVybiByLmx9KSxuLmQodCwiYXJyYXlPZkRlZmZlcmVkIixmdW5jdGlvbigpe3JldHVybiByLmd9KSxuLmQodCwiY3JlYXRlTW9ja1Rhc2siLGZ1bmN0aW9uKCl7cmV0dXJuIHIuan0pLG4uZCh0LCJjbG9uZWFibGVHZW5lcmF0b3IiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuaX0pO3ZhciBpPW4oMzQpO24uZCh0LCJhc0VmZmVjdCIsZnVuY3Rpb24oKXtyZXR1cm4gaS5kfSk7dmFyIG89bigxNjgpO24uZCh0LCJDSEFOTkVMX0VORCIsZnVuY3Rpb24oKXtyZXR1cm4gby5hfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3JldHVybiBpKHRoaXMsZnVuY3Rpb24oZSl7c3dpdGNoKGUubGFiZWwpe2Nhc2UgMDpyZXR1cm5bNCxzLmFsbChhLnNlc3Npb25zU2FnYXMuY29uY2F0KG8uZmVjdGhpbmdTYWdhcyx1LnNoYXJpbmdTYWdhcykpXTtjYXNlIDE6cmV0dXJuIGUuc2VudCgpLFsyXX19KX12YXIgaT1mdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiByKFtlLHRdKX19ZnVuY3Rpb24gcihuKXtpZihpKXRocm93IG5ldyBUeXBlRXJyb3IoIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy4iKTtmb3IoO3U7KXRyeXtpZihpPTEsbyYmKGE9MiZuWzBdP28ucmV0dXJuOm5bMF0/by50aHJvd3x8KChhPW8ucmV0dXJuKSYmYS5jYWxsKG8pLDApOm8ubmV4dCkmJiEoYT1hLmNhbGwobyxuWzFdKSkuZG9uZSlyZXR1cm4gYTtzd2l0Y2gobz0wLGEmJihuPVsyJm5bMF0sYS52YWx1ZV0pLG5bMF0pe2Nhc2UgMDpjYXNlIDE6YT1uO2JyZWFrO2Nhc2UgNDpyZXR1cm4gdS5sYWJlbCsrLHt2YWx1ZTpuWzFdLGRvbmU6ITF9O2Nhc2UgNTp1LmxhYmVsKyssbz1uWzFdLG49WzBdO2NvbnRpbnVlO2Nhc2UgNzpuPXUub3BzLnBvcCgpLHUudHJ5cy5wb3AoKTtjb250aW51ZTtkZWZhdWx0OmlmKGE9dS50cnlzLCEoYT1hLmxlbmd0aD4wJiZhW2EubGVuZ3RoLTFdKSYmKDY9PT1uWzBdfHwyPT09blswXSkpe3U9MDtjb250aW51ZX1pZigzPT09blswXSYmKCFhfHxuWzFdPmFbMF0mJm5bMV08YVszXSkpe3UubGFiZWw9blsxXTticmVha31pZig2PT09blswXSYmdS5sYWJlbDxhWzFdKXt1LmxhYmVsPWFbMV0sYT1uO2JyZWFrfWlmKGEmJnUubGFiZWw8YVsyXSl7dS5sYWJlbD1hWzJdLHUub3BzLnB1c2gobik7YnJlYWt9YVsyXSYmdS5vcHMucG9wKCksdS50cnlzLnBvcCgpO2NvbnRpbnVlfW49dC5jYWxsKGUsdSl9Y2F0Y2goZSl7bj1bNixlXSxvPTB9ZmluYWxseXtpPWE9MH1pZig1Jm5bMF0pdGhyb3cgblsxXTtyZXR1cm57dmFsdWU6blswXT9uWzFdOnZvaWQgMCxkb25lOiEwfX12YXIgaSxvLGEscyx1PXtsYWJlbDowLHNlbnQ6ZnVuY3Rpb24oKXtpZigxJmFbMF0pdGhyb3cgYVsxXTtyZXR1cm4gYVsxXX0sdHJ5czpbXSxvcHM6W119O3JldHVybiBzPXtuZXh0Om4oMCksdGhyb3c6bigxKSxyZXR1cm46bigyKX0sImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJihzW1N5bWJvbC5pdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pLHN9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDc3KSxhPW4oNTEwKSxzPW4oNTUpLHU9big1MTYpO3QuZGVmYXVsdD1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4gZS5yZXF1ZXN0KE9iamVjdChvLmIpKHQuY29udGV4dCxPYmplY3Qoby5oKShPYmplY3Qoby5pKSh0KSkpKXx8aS5hLm9mKCl9bi5kKHQsImMiLGZ1bmN0aW9uKCl7cmV0dXJuIHV9KSxuLmQodCwiZSIsZnVuY3Rpb24oKXtyZXR1cm4gY30pLG4uZCh0LCJmIixmdW5jdGlvbigpe3JldHVybiBsfSksbi5kKHQsImIiLGZ1bmN0aW9uKCl7cmV0dXJuIHB9KSxuLmQodCwiYSIsZnVuY3Rpb24oKXtyZXR1cm4gZn0pLHQuZD1yO3ZhciBpPW4oMTA2KSxvPW4oMTcxKSxhPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQ/dChlKTppLmEub2YoKX0scz1mdW5jdGlvbihlKXtyZXR1cm4iZnVuY3Rpb24iPT09dHlwZW9mIGU/bmV3IGYoZSk6ZX0sdT1mdW5jdGlvbigpe3JldHVybiBuZXcgZihmdW5jdGlvbihlLHQpe3JldHVybiBpLmEub2YoKX0pfSxjPWZ1bmN0aW9uKGUpe3JldHVybiAwPT09ZS5sZW5ndGg/dSgpOmUubWFwKHMpLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlLmNvbmNhdCh0KX0pfSxsPWZ1bmN0aW9uKGUsdCxuKXt2b2lkIDA9PT1uJiYobj1uZXcgZihhKSk7dmFyIHI9cyh0KSx1PXMobik7cmV0dXJuIG5ldyBmKE9iamVjdChvLmUpKHIpJiZPYmplY3Qoby5lKSh1KT9mdW5jdGlvbih0KXtyZXR1cm4gZSh0KT9yLnJlcXVlc3QodCl8fGkuYS5vZigpOnUucmVxdWVzdCh0KXx8aS5hLm9mKCl9OmZ1bmN0aW9uKHQsbil7cmV0dXJuIGUodCk/ci5yZXF1ZXN0KHQsbil8fGkuYS5vZigpOnUucmVxdWVzdCh0LG4pfHxpLmEub2YoKX0pfSxwPWZ1bmN0aW9uKGUsdCl7dmFyIG49cyhlKTtpZihPYmplY3Qoby5lKShuKSlyZXR1cm4gY29uc29sZS53YXJuKG5ldyBvLmEoIllvdSBhcmUgY2FsbGluZyBjb25jYXQgb24gYSB0ZXJtaW5hdGluZyBsaW5rLCB3aGljaCB3aWxsIGhhdmUgbm8gZWZmZWN0IixuKSksbjt2YXIgcj1zKHQpO3JldHVybiBuZXcgZihPYmplY3Qoby5lKShyKT9mdW5jdGlvbihlKXtyZXR1cm4gbi5yZXF1ZXN0KGUsZnVuY3Rpb24oZSl7cmV0dXJuIHIucmVxdWVzdChlKXx8aS5hLm9mKCl9KXx8aS5hLm9mKCl9OmZ1bmN0aW9uKGUsdCl7cmV0dXJuIG4ucmVxdWVzdChlLGZ1bmN0aW9uKGUpe3JldHVybiByLnJlcXVlc3QoZSx0KXx8aS5hLm9mKCl9KXx8aS5hLm9mKCl9KX0sZj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7ZSYmKHRoaXMucmVxdWVzdD1lKX1yZXR1cm4gZS5wcm90b3R5cGUuc3BsaXQ9ZnVuY3Rpb24odCxuLHIpe3JldHVybiB2b2lkIDA9PT1yJiYocj1uZXcgZShhKSksdGhpcy5jb25jYXQobCh0LG4scikpfSxlLnByb3RvdHlwZS5jb25jYXQ9ZnVuY3Rpb24oZSl7cmV0dXJuIHAodGhpcyxlKX0sZS5wcm90b3R5cGUucmVxdWVzdD1mdW5jdGlvbihlLHQpe3Rocm93IG5ldyBFcnJvcigicmVxdWVzdCBpcyBub3QgaW1wbGVtZW50ZWQiKX0sZS5lbXB0eT11LGUuZnJvbT1jLGUuc3BsaXQ9bCxlLmV4ZWN1dGU9cixlfSgpfSxmdW5jdGlvbihlLHQsbil7ZS5leHBvcnRzPW4oMzY1KS5PYnNlcnZhYmxlfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBpKGUsdCl7dmFyIG49ZVt0XTtpZihudWxsIT1uKXtpZigiZnVuY3Rpb24iIT09dHlwZW9mIG4pdGhyb3cgbmV3IFR5cGVFcnJvcihuKyIgaXMgbm90IGEgZnVuY3Rpb24iKTtyZXR1cm4gbn19ZnVuY3Rpb24gbyhlKXt2YXIgdD1lLmNvbnN0cnVjdG9yO3JldHVybiB2b2lkIDAhPT10JiZudWxsPT09KHQ9dFt5KCJzcGVjaWVzIildKSYmKHQ9dm9pZCAwKSx2b2lkIDAhPT10P3Q6eH1mdW5jdGlvbiBhKGUpe3JldHVybiBlIGluc3RhbmNlb2YgeH1mdW5jdGlvbiBzKGUpe3MubG9nP3MubG9nKGUpOnNldFRpbWVvdXQoZnVuY3Rpb24oKXt0aHJvdyBlfSl9ZnVuY3Rpb24gdShlKXtQcm9taXNlLnJlc29sdmUoKS50aGVuKGZ1bmN0aW9uKCl7dHJ5e2UoKX1jYXRjaChlKXtzKGUpfX0pfWZ1bmN0aW9uIGMoZSl7dmFyIHQ9ZS5fY2xlYW51cDtpZih2b2lkIDAhPT10JiYoZS5fY2xlYW51cD12b2lkIDAsdCkpdHJ5e2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgdCl0KCk7ZWxzZXt2YXIgbj1pKHQsInVuc3Vic2NyaWJlIik7biYmbi5jYWxsKHQpfX1jYXRjaChlKXtzKGUpfX1mdW5jdGlvbiBsKGUpe2UuX29ic2VydmVyPXZvaWQgMCxlLl9xdWV1ZT12b2lkIDAsZS5fc3RhdGU9ImNsb3NlZCJ9ZnVuY3Rpb24gcChlKXt2YXIgdD1lLl9xdWV1ZTtpZih0KXtlLl9xdWV1ZT12b2lkIDAsZS5fc3RhdGU9InJlYWR5Ijtmb3IodmFyIG49MDtuPHQubGVuZ3RoJiYoZihlLHRbbl0udHlwZSx0W25dLnZhbHVlKSwiY2xvc2VkIiE9PWUuX3N0YXRlKTsrK24pO319ZnVuY3Rpb24gZihlLHQsbil7ZS5fc3RhdGU9InJ1bm5pbmciO3ZhciByPWUuX29ic2VydmVyO3RyeXt2YXIgbz1pKHIsdCk7c3dpdGNoKHQpe2Nhc2UibmV4dCI6byYmby5jYWxsKHIsbik7YnJlYWs7Y2FzZSJlcnJvciI6aWYobChlKSwhbyl0aHJvdyBuO28uY2FsbChyLG4pO2JyZWFrO2Nhc2UiY29tcGxldGUiOmwoZSksbyYmby5jYWxsKHIpfX1jYXRjaChlKXtzKGUpfSJjbG9zZWQiPT09ZS5fc3RhdGU/YyhlKToicnVubmluZyI9PT1lLl9zdGF0ZSYmKGUuX3N0YXRlPSJyZWFkeSIpfWZ1bmN0aW9uIGQoZSx0LG4pe2lmKCJjbG9zZWQiIT09ZS5fc3RhdGUpcmV0dXJuImJ1ZmZlcmluZyI9PT1lLl9zdGF0ZT92b2lkIGUuX3F1ZXVlLnB1c2goe3R5cGU6dCx2YWx1ZTpufSk6InJlYWR5IiE9PWUuX3N0YXRlPyhlLl9zdGF0ZT0iYnVmZmVyaW5nIixlLl9xdWV1ZT1be3R5cGU6dCx2YWx1ZTpufV0sdm9pZCB1KGZ1bmN0aW9uKCl7cmV0dXJuIHAoZSl9KSk6dm9pZCBmKGUsdCxuKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGg9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7Zm9yKHZhciBuPTA7bjx0Lmxlbmd0aDtuKyspe3ZhciByPXRbbl07ci5lbnVtZXJhYmxlPXIuZW51bWVyYWJsZXx8ITEsci5jb25maWd1cmFibGU9ITAsInZhbHVlImluIHImJihyLndyaXRhYmxlPSEwKSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZSxyLmtleSxyKX19cmV0dXJuIGZ1bmN0aW9uKHQsbixyKXtyZXR1cm4gbiYmZSh0LnByb3RvdHlwZSxuKSxyJiZlKHQsciksdH19KCksbT1mdW5jdGlvbigpe3JldHVybiJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sfSxnPWZ1bmN0aW9uKGUpe3JldHVybiBtKCkmJkJvb2xlYW4oU3ltYm9sW2VdKX0seT1mdW5jdGlvbihlKXtyZXR1cm4gZyhlKT9TeW1ib2xbZV06IkBAIitlfTttKCkmJiFnKCJvYnNlcnZhYmxlIikmJihTeW1ib2wub2JzZXJ2YWJsZT1TeW1ib2woIm9ic2VydmFibGUiKSk7dmFyIHY9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQsbil7cih0aGlzLGUpLHRoaXMuX2NsZWFudXA9dm9pZCAwLHRoaXMuX29ic2VydmVyPXQsdGhpcy5fcXVldWU9dm9pZCAwLHRoaXMuX3N0YXRlPSJpbml0aWFsaXppbmciO3ZhciBpPW5ldyBiKHRoaXMpO3RyeXt0aGlzLl9jbGVhbnVwPW4uY2FsbCh2b2lkIDAsaSl9Y2F0Y2goZSl7aS5lcnJvcihlKX0iaW5pdGlhbGl6aW5nIj09PXRoaXMuX3N0YXRlJiYodGhpcy5fc3RhdGU9InJlYWR5Iil9cmV0dXJuIGgoZSxbe2tleToidW5zdWJzY3JpYmUiLHZhbHVlOmZ1bmN0aW9uKCl7ImNsb3NlZCIhPT10aGlzLl9zdGF0ZSYmKGwodGhpcyksYyh0aGlzKSl9fSx7a2V5OiJjbG9zZWQiLGdldDpmdW5jdGlvbigpe3JldHVybiJjbG9zZWQiPT09dGhpcy5fc3RhdGV9fV0pLGV9KCksYj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7cih0aGlzLGUpLHRoaXMuX3N1YnNjcmlwdGlvbj10fXJldHVybiBoKGUsW3trZXk6Im5leHQiLHZhbHVlOmZ1bmN0aW9uKGUpe2QodGhpcy5fc3Vic2NyaXB0aW9uLCJuZXh0IixlKX19LHtrZXk6ImVycm9yIix2YWx1ZTpmdW5jdGlvbihlKXtkKHRoaXMuX3N1YnNjcmlwdGlvbiwiZXJyb3IiLGUpfX0se2tleToiY29tcGxldGUiLHZhbHVlOmZ1bmN0aW9uKCl7ZCh0aGlzLl9zdWJzY3JpcHRpb24sImNvbXBsZXRlIil9fSx7a2V5OiJjbG9zZWQiLGdldDpmdW5jdGlvbigpe3JldHVybiJjbG9zZWQiPT09dGhpcy5fc3Vic2NyaXB0aW9uLl9zdGF0ZX19XSksZX0oKSx4PXQuT2JzZXJ2YWJsZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7aWYocih0aGlzLGUpLCEodGhpcyBpbnN0YW5jZW9mIGUpKXRocm93IG5ldyBUeXBlRXJyb3IoIk9ic2VydmFibGUgY2Fubm90IGJlIGNhbGxlZCBhcyBhIGZ1bmN0aW9uIik7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0KXRocm93IG5ldyBUeXBlRXJyb3IoIk9ic2VydmFibGUgaW5pdGlhbGl6ZXIgbXVzdCBiZSBhIGZ1bmN0aW9uIik7dGhpcy5fc3Vic2NyaWJlcj10fXJldHVybiBoKGUsW3trZXk6InN1YnNjcmliZSIsdmFsdWU6ZnVuY3Rpb24oZSl7cmV0dXJuIm9iamVjdCI9PT10eXBlb2YgZSYmbnVsbCE9PWV8fChlPXtuZXh0OmUsZXJyb3I6YXJndW1lbnRzWzFdLGNvbXBsZXRlOmFyZ3VtZW50c1syXX0pLG5ldyB2KGUsdGhpcy5fc3Vic2NyaWJlcil9fSx7a2V5OiJmb3JFYWNoIix2YWx1ZTpmdW5jdGlvbihlKXt2YXIgdD10aGlzO3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihuLHIpe2Z1bmN0aW9uIGkoKXtvLnVuc3Vic2NyaWJlKCksbigpfWlmKCJmdW5jdGlvbiIhPT10eXBlb2YgZSlyZXR1cm4gdm9pZCByKG5ldyBUeXBlRXJyb3IoZSsiIGlzIG5vdCBhIGZ1bmN0aW9uIikpO3ZhciBvPXQuc3Vic2NyaWJlKHtuZXh0OmZ1bmN0aW9uKHQpe3RyeXtlKHQsaSl9Y2F0Y2goZSl7cihlKSxvLnVuc3Vic2NyaWJlKCl9fSxlcnJvcjpyLGNvbXBsZXRlOm59KX0pfX0se2tleToibWFwIix2YWx1ZTpmdW5jdGlvbihlKXt2YXIgdD10aGlzO2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgZSl0aHJvdyBuZXcgVHlwZUVycm9yKGUrIiBpcyBub3QgYSBmdW5jdGlvbiIpO3JldHVybiBuZXcobyh0aGlzKSkoZnVuY3Rpb24obil7cmV0dXJuIHQuc3Vic2NyaWJlKHtuZXh0OmZ1bmN0aW9uKHQpe3RyeXt0PWUodCl9Y2F0Y2goZSl7cmV0dXJuIG4uZXJyb3IoZSl9bi5uZXh0KHQpfSxlcnJvcjpmdW5jdGlvbihlKXtuLmVycm9yKGUpfSxjb21wbGV0ZTpmdW5jdGlvbigpe24uY29tcGxldGUoKX19KX0pfX0se2tleToiZmlsdGVyIix2YWx1ZTpmdW5jdGlvbihlKXt2YXIgdD10aGlzO2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgZSl0aHJvdyBuZXcgVHlwZUVycm9yKGUrIiBpcyBub3QgYSBmdW5jdGlvbiIpO3JldHVybiBuZXcobyh0aGlzKSkoZnVuY3Rpb24obil7cmV0dXJuIHQuc3Vic2NyaWJlKHtuZXh0OmZ1bmN0aW9uKHQpe3RyeXtpZighZSh0KSlyZXR1cm59Y2F0Y2goZSl7cmV0dXJuIG4uZXJyb3IoZSl9bi5uZXh0KHQpfSxlcnJvcjpmdW5jdGlvbihlKXtuLmVycm9yKGUpfSxjb21wbGV0ZTpmdW5jdGlvbigpe24uY29tcGxldGUoKX19KX0pfX0se2tleToicmVkdWNlIix2YWx1ZTpmdW5jdGlvbihlKXt2YXIgdD10aGlzO2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgZSl0aHJvdyBuZXcgVHlwZUVycm9yKGUrIiBpcyBub3QgYSBmdW5jdGlvbiIpO3ZhciBuPW8odGhpcykscj1hcmd1bWVudHMubGVuZ3RoPjEsaT0hMSxhPWFyZ3VtZW50c1sxXSxzPWE7cmV0dXJuIG5ldyBuKGZ1bmN0aW9uKG4pe3JldHVybiB0LnN1YnNjcmliZSh7bmV4dDpmdW5jdGlvbih0KXt2YXIgbz0haTtpZihpPSEwLCFvfHxyKXRyeXtzPWUocyx0KX1jYXRjaChlKXtyZXR1cm4gbi5lcnJvcihlKX1lbHNlIHM9dH0sZXJyb3I6ZnVuY3Rpb24oZSl7bi5lcnJvcihlKX0sY29tcGxldGU6ZnVuY3Rpb24oKXtpZighaSYmIXIpcmV0dXJuIG4uZXJyb3IobmV3IFR5cGVFcnJvcigiQ2Fubm90IHJlZHVjZSBhbiBlbXB0eSBzZXF1ZW5jZSIpKTtuLm5leHQocyksbi5jb21wbGV0ZSgpfX0pfSl9fSx7a2V5OiJjb25jYXQiLHZhbHVlOmZ1bmN0aW9uKCl7Zm9yKHZhciBlPXRoaXMsdD1hcmd1bWVudHMubGVuZ3RoLG49QXJyYXkodCkscj0wO3I8dDtyKyspbltyXT1hcmd1bWVudHNbcl07dmFyIGk9byh0aGlzKTtyZXR1cm4gbmV3IGkoZnVuY3Rpb24odCl7ZnVuY3Rpb24gcihlKXtvPWUuc3Vic2NyaWJlKHtuZXh0OmZ1bmN0aW9uKGUpe3QubmV4dChlKX0sZXJyb3I6ZnVuY3Rpb24oZSl7dC5lcnJvcihlKX0sY29tcGxldGU6ZnVuY3Rpb24oKXswPT09bi5sZW5ndGg/KG89dm9pZCAwLHQuY29tcGxldGUoKSk6cihpLmZyb20obi5zaGlmdCgpKSl9fSl9dmFyIG89dm9pZCAwO3JldHVybiByKGUpLGZ1bmN0aW9uKCl7byYmKG89dm9pZCAwLG8udW5zdWJzY3JpYmUoKSl9fSl9fSx7a2V5OiJmbGF0TWFwIix2YWx1ZTpmdW5jdGlvbihlKXt2YXIgdD10aGlzO2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgZSl0aHJvdyBuZXcgVHlwZUVycm9yKGUrIiBpcyBub3QgYSBmdW5jdGlvbiIpO3ZhciBuPW8odGhpcyk7cmV0dXJuIG5ldyBuKGZ1bmN0aW9uKHIpe2Z1bmN0aW9uIGkoKXthLmNsb3NlZCYmMD09PW8ubGVuZ3RoJiZyLmNvbXBsZXRlKCl9dmFyIG89W10sYT10LnN1YnNjcmliZSh7bmV4dDpmdW5jdGlvbih0KXtpZihlKXRyeXt0PWUodCl9Y2F0Y2goZSl7cmV0dXJuIHIuZXJyb3IoZSl9dmFyIGE9bi5mcm9tKHQpLnN1YnNjcmliZSh7bmV4dDpmdW5jdGlvbihlKXtyLm5leHQoZSl9LGVycm9yOmZ1bmN0aW9uKGUpe3IuZXJyb3IoZSl9LGNvbXBsZXRlOmZ1bmN0aW9uKCl7dmFyIGU9by5pbmRleE9mKGEpO2U+PTAmJm8uc3BsaWNlKGUsMSksaSgpfX0pO28ucHVzaChhKX0sZXJyb3I6ZnVuY3Rpb24oZSl7ci5lcnJvcihlKX0sY29tcGxldGU6ZnVuY3Rpb24oKXtpKCl9fSk7cmV0dXJuIGZ1bmN0aW9uKCl7by5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBlLnVuc3Vic2NyaWJlKCl9KSxhLnVuc3Vic2NyaWJlKCl9fSl9fSx7a2V5OnkoIm9ic2VydmFibGUiKSx2YWx1ZTpmdW5jdGlvbigpe3JldHVybiB0aGlzfX1dLFt7a2V5OiJmcm9tIix2YWx1ZTpmdW5jdGlvbih0KXt2YXIgbj0iZnVuY3Rpb24iPT09dHlwZW9mIHRoaXM/dGhpczplO2lmKG51bGw9PXQpdGhyb3cgbmV3IFR5cGVFcnJvcih0KyIgaXMgbm90IGFuIG9iamVjdCIpO3ZhciByPWkodCx5KCJvYnNlcnZhYmxlIikpO2lmKHIpe3ZhciBvPXIuY2FsbCh0KTtpZihPYmplY3QobykhPT1vKXRocm93IG5ldyBUeXBlRXJyb3IobysiIGlzIG5vdCBhbiBvYmplY3QiKTtyZXR1cm4gYShvKSYmby5jb25zdHJ1Y3Rvcj09PW4/bzpuZXcgbihmdW5jdGlvbihlKXtyZXR1cm4gby5zdWJzY3JpYmUoZSl9KX1pZihnKCJpdGVyYXRvciIpJiYocj1pKHQseSgiaXRlcmF0b3IiKSkpKXJldHVybiBuZXcgbihmdW5jdGlvbihlKXt1KGZ1bmN0aW9uKCl7aWYoIWUuY2xvc2VkKXt2YXIgbj0hMCxpPSExLG89dm9pZCAwO3RyeXtmb3IodmFyIGEscz1yLmNhbGwodClbU3ltYm9sLml0ZXJhdG9yXSgpOyEobj0oYT1zLm5leHQoKSkuZG9uZSk7bj0hMCl7dmFyIHU9YS52YWx1ZTtpZihlLm5leHQodSksZS5jbG9zZWQpcmV0dXJufX1jYXRjaChlKXtpPSEwLG89ZX1maW5hbGx5e3RyeXshbiYmcy5yZXR1cm4mJnMucmV0dXJuKCl9ZmluYWxseXtpZihpKXRocm93IG99fWUuY29tcGxldGUoKX19KX0pO2lmKEFycmF5LmlzQXJyYXkodCkpcmV0dXJuIG5ldyBuKGZ1bmN0aW9uKGUpe3UoZnVuY3Rpb24oKXtpZighZS5jbG9zZWQpe2Zvcih2YXIgbj0wO248dC5sZW5ndGg7KytuKWlmKGUubmV4dCh0W25dKSxlLmNsb3NlZClyZXR1cm47ZS5jb21wbGV0ZSgpfX0pfSk7dGhyb3cgbmV3IFR5cGVFcnJvcih0KyIgaXMgbm90IG9ic2VydmFibGUiKX19LHtrZXk6Im9mIix2YWx1ZTpmdW5jdGlvbigpe2Zvcih2YXIgdD1hcmd1bWVudHMubGVuZ3RoLG49QXJyYXkodCkscj0wO3I8dDtyKyspbltyXT1hcmd1bWVudHNbcl07cmV0dXJuIG5ldygiZnVuY3Rpb24iPT09dHlwZW9mIHRoaXM/dGhpczplKShmdW5jdGlvbihlKXt1KGZ1bmN0aW9uKCl7aWYoIWUuY2xvc2VkKXtmb3IodmFyIHQ9MDt0PG4ubGVuZ3RoOysrdClpZihlLm5leHQoblt0XSksZS5jbG9zZWQpcmV0dXJuO2UuY29tcGxldGUoKX19KX0pfX0se2tleTp5KCJzcGVjaWVzIiksZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9fV0pLGV9KCk7bSgpJiZPYmplY3QuZGVmaW5lUHJvcGVydHkoeCxTeW1ib2woImV4dGVuc2lvbnMiKSx7dmFsdWU6e3N5bWJvbDp5KCJvYnNlcnZhYmxlIiksaG9zdFJlcG9ydEVycm9yOnN9LGNvbmZpZ3VyYWJlOiEwfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9KG4oMzY3KSxuKDM2OCksbigxNzIpKTtuLmQodCwiYSIsZnVuY3Rpb24oKXtyZXR1cm4gci5lfSk7bigzNjkpLG4oMTA3KSxuKDE3MyksbigxNzQpLG4oMTA4KSxuKDM3MCksbigzNzEpLG4oMzcyKSxuKDM3MyksbigzNzQpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO24oMTA3KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt0aGlzJiZ0aGlzLl9fYXNzaWdufHxPYmplY3QuYXNzaWdufSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO24oMTc0KSxuKDE3Mil9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7bigxMDgpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO24oMTA4KSxPYmplY3QuY3JlYXRlKHt9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0In0sZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe2U9ZXx8e30sdGhpcy5tcz1lLm1pbnx8MTAwLHRoaXMubWF4PWUubWF4fHwxZTQsdGhpcy5mYWN0b3I9ZS5mYWN0b3J8fDIsdGhpcy5qaXR0ZXI9ZS5qaXR0ZXI+MCYmZS5qaXR0ZXI8PTE/ZS5qaXR0ZXI6MCx0aGlzLmF0dGVtcHRzPTB9ZS5leHBvcnRzPW4sbi5wcm90b3R5cGUuZHVyYXRpb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLm1zKk1hdGgucG93KHRoaXMuZmFjdG9yLHRoaXMuYXR0ZW1wdHMrKyk7aWYodGhpcy5qaXR0ZXIpe3ZhciB0PU1hdGgucmFuZG9tKCksbj1NYXRoLmZsb29yKHQqdGhpcy5qaXR0ZXIqZSk7ZT0wPT0oMSZNYXRoLmZsb29yKDEwKnQpKT9lLW46ZStufXJldHVybiAwfE1hdGgubWluKGUsdGhpcy5tYXgpfSxuLnByb3RvdHlwZS5yZXNldD1mdW5jdGlvbigpe3RoaXMuYXR0ZW1wdHM9MH0sbi5wcm90b3R5cGUuc2V0TWluPWZ1bmN0aW9uKGUpe3RoaXMubXM9ZX0sbi5wcm90b3R5cGUuc2V0TWF4PWZ1bmN0aW9uKGUpe3RoaXMubWF4PWV9LG4ucHJvdG90eXBlLnNldEppdHRlcj1mdW5jdGlvbihlKXt0aGlzLmppdHRlcj1lfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKCl7fWZ1bmN0aW9uIGkoZSx0LG4pe3RoaXMuZm49ZSx0aGlzLmNvbnRleHQ9dCx0aGlzLm9uY2U9bnx8ITF9ZnVuY3Rpb24gbygpe3RoaXMuX2V2ZW50cz1uZXcgcix0aGlzLl9ldmVudHNDb3VudD0wfXZhciBhPU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkscz0ifiI7T2JqZWN0LmNyZWF0ZSYmKHIucHJvdG90eXBlPU9iamVjdC5jcmVhdGUobnVsbCksKG5ldyByKS5fX3Byb3RvX198fChzPSExKSksby5wcm90b3R5cGUuZXZlbnROYW1lcz1mdW5jdGlvbigpe3ZhciBlLHQsbj1bXTtpZigwPT09dGhpcy5fZXZlbnRzQ291bnQpcmV0dXJuIG47Zm9yKHQgaW4gZT10aGlzLl9ldmVudHMpYS5jYWxsKGUsdCkmJm4ucHVzaChzP3Quc2xpY2UoMSk6dCk7cmV0dXJuIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHM/bi5jb25jYXQoT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhlKSk6bn0sby5wcm90b3R5cGUubGlzdGVuZXJzPWZ1bmN0aW9uKGUsdCl7dmFyIG49cz9zK2U6ZSxyPXRoaXMuX2V2ZW50c1tuXTtpZih0KXJldHVybiEhcjtpZighcilyZXR1cm5bXTtpZihyLmZuKXJldHVybltyLmZuXTtmb3IodmFyIGk9MCxvPXIubGVuZ3RoLGE9bmV3IEFycmF5KG8pO2k8bztpKyspYVtpXT1yW2ldLmZuO3JldHVybiBhfSxvLnByb3RvdHlwZS5lbWl0PWZ1bmN0aW9uKGUsdCxuLHIsaSxvKXt2YXIgYT1zP3MrZTplO2lmKCF0aGlzLl9ldmVudHNbYV0pcmV0dXJuITE7dmFyIHUsYyxsPXRoaXMuX2V2ZW50c1thXSxwPWFyZ3VtZW50cy5sZW5ndGg7aWYobC5mbil7c3dpdGNoKGwub25jZSYmdGhpcy5yZW1vdmVMaXN0ZW5lcihlLGwuZm4sdm9pZCAwLCEwKSxwKXtjYXNlIDE6cmV0dXJuIGwuZm4uY2FsbChsLmNvbnRleHQpLCEwO2Nhc2UgMjpyZXR1cm4gbC5mbi5jYWxsKGwuY29udGV4dCx0KSwhMDtjYXNlIDM6cmV0dXJuIGwuZm4uY2FsbChsLmNvbnRleHQsdCxuKSwhMDtjYXNlIDQ6cmV0dXJuIGwuZm4uY2FsbChsLmNvbnRleHQsdCxuLHIpLCEwO2Nhc2UgNTpyZXR1cm4gbC5mbi5jYWxsKGwuY29udGV4dCx0LG4scixpKSwhMDtjYXNlIDY6cmV0dXJuIGwuZm4uY2FsbChsLmNvbnRleHQsdCxuLHIsaSxvKSwhMH1mb3IoYz0xLHU9bmV3IEFycmF5KHAtMSk7YzxwO2MrKyl1W2MtMV09YXJndW1lbnRzW2NdO2wuZm4uYXBwbHkobC5jb250ZXh0LHUpfWVsc2V7dmFyIGYsZD1sLmxlbmd0aDtmb3IoYz0wO2M8ZDtjKyspc3dpdGNoKGxbY10ub25jZSYmdGhpcy5yZW1vdmVMaXN0ZW5lcihlLGxbY10uZm4sdm9pZCAwLCEwKSxwKXtjYXNlIDE6bFtjXS5mbi5jYWxsKGxbY10uY29udGV4dCk7YnJlYWs7Y2FzZSAyOmxbY10uZm4uY2FsbChsW2NdLmNvbnRleHQsdCk7YnJlYWs7Y2FzZSAzOmxbY10uZm4uY2FsbChsW2NdLmNvbnRleHQsdCxuKTticmVhaztjYXNlIDQ6bFtjXS5mbi5jYWxsKGxbY10uY29udGV4dCx0LG4scik7YnJlYWs7ZGVmYXVsdDppZighdSlmb3IoZj0xLHU9bmV3IEFycmF5KHAtMSk7ZjxwO2YrKyl1W2YtMV09YXJndW1lbnRzW2ZdO2xbY10uZm4uYXBwbHkobFtjXS5jb250ZXh0LHUpfX1yZXR1cm4hMH0sby5wcm90b3R5cGUub249ZnVuY3Rpb24oZSx0LG4pe3ZhciByPW5ldyBpKHQsbnx8dGhpcyksbz1zP3MrZTplO3JldHVybiB0aGlzLl9ldmVudHNbb10/dGhpcy5fZXZlbnRzW29dLmZuP3RoaXMuX2V2ZW50c1tvXT1bdGhpcy5fZXZlbnRzW29dLHJdOnRoaXMuX2V2ZW50c1tvXS5wdXNoKHIpOih0aGlzLl9ldmVudHNbb109cix0aGlzLl9ldmVudHNDb3VudCsrKSx0aGlzfSxvLnByb3RvdHlwZS5vbmNlPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1uZXcgaSh0LG58fHRoaXMsITApLG89cz9zK2U6ZTtyZXR1cm4gdGhpcy5fZXZlbnRzW29dP3RoaXMuX2V2ZW50c1tvXS5mbj90aGlzLl9ldmVudHNbb109W3RoaXMuX2V2ZW50c1tvXSxyXTp0aGlzLl9ldmVudHNbb10ucHVzaChyKToodGhpcy5fZXZlbnRzW29dPXIsdGhpcy5fZXZlbnRzQ291bnQrKyksdGhpc30sby5wcm90b3R5cGUucmVtb3ZlTGlzdGVuZXI9ZnVuY3Rpb24oZSx0LG4saSl7dmFyIG89cz9zK2U6ZTtpZighdGhpcy5fZXZlbnRzW29dKXJldHVybiB0aGlzO2lmKCF0KXJldHVybiAwPT09LS10aGlzLl9ldmVudHNDb3VudD90aGlzLl9ldmVudHM9bmV3IHI6ZGVsZXRlIHRoaXMuX2V2ZW50c1tvXSx0aGlzO3ZhciBhPXRoaXMuX2V2ZW50c1tvXTtpZihhLmZuKWEuZm4hPT10fHxpJiYhYS5vbmNlfHxuJiZhLmNvbnRleHQhPT1ufHwoMD09PS0tdGhpcy5fZXZlbnRzQ291bnQ/dGhpcy5fZXZlbnRzPW5ldyByOmRlbGV0ZSB0aGlzLl9ldmVudHNbb10pO2Vsc2V7Zm9yKHZhciB1PTAsYz1bXSxsPWEubGVuZ3RoO3U8bDt1KyspKGFbdV0uZm4hPT10fHxpJiYhYVt1XS5vbmNlfHxuJiZhW3VdLmNvbnRleHQhPT1uKSYmYy5wdXNoKGFbdV0pO2MubGVuZ3RoP3RoaXMuX2V2ZW50c1tvXT0xPT09Yy5sZW5ndGg/Y1swXTpjOjA9PT0tLXRoaXMuX2V2ZW50c0NvdW50P3RoaXMuX2V2ZW50cz1uZXcgcjpkZWxldGUgdGhpcy5fZXZlbnRzW29dfXJldHVybiB0aGlzfSxvLnByb3RvdHlwZS5yZW1vdmVBbGxMaXN0ZW5lcnM9ZnVuY3Rpb24oZSl7dmFyIHQ7cmV0dXJuIGU/KHQ9cz9zK2U6ZSx0aGlzLl9ldmVudHNbdF0mJigwPT09LS10aGlzLl9ldmVudHNDb3VudD90aGlzLl9ldmVudHM9bmV3IHI6ZGVsZXRlIHRoaXMuX2V2ZW50c1t0XSkpOih0aGlzLl9ldmVudHM9bmV3IHIsdGhpcy5fZXZlbnRzQ291bnQ9MCksdGhpc30sby5wcm90b3R5cGUub2ZmPW8ucHJvdG90eXBlLnJlbW92ZUxpc3RlbmVyLG8ucHJvdG90eXBlLmFkZExpc3RlbmVyPW8ucHJvdG90eXBlLm9uLG8ucHJvdG90eXBlLnNldE1heExpc3RlbmVycz1mdW5jdGlvbigpe3JldHVybiB0aGlzfSxvLnByZWZpeGVkPXMsby5FdmVudEVtaXR0ZXI9byxlLmV4cG9ydHM9b30sZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe3JldHVybiEhZSYmIm9iamVjdCI9PXR5cGVvZiBlfWZ1bmN0aW9uIHIoZSl7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBlfHwhcyhlKSYmbihlKSYmYS5jYWxsKGUpPT1pfXZhciBpPSJbb2JqZWN0IFN0cmluZ10iLG89T2JqZWN0LnByb3RvdHlwZSxhPW8udG9TdHJpbmcscz1BcnJheS5pc0FycmF5O2UuZXhwb3J0cz1yfSxmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7dmFyIHQ9dHlwZW9mIGU7cmV0dXJuISFlJiYoIm9iamVjdCI9PXR8fCJmdW5jdGlvbiI9PXQpfWUuZXhwb3J0cz1ufSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSxmdW5jdGlvbihlLHIpe3ZhciBpLG89bigzODApO2k9InVuZGVmaW5lZCIhPT10eXBlb2Ygc2VsZj9zZWxmOiJ1bmRlZmluZWQiIT09dHlwZW9mIHdpbmRvdz93aW5kb3c6InVuZGVmaW5lZCIhPT10eXBlb2YgZT9lOnI7dmFyIGE9T2JqZWN0KG8uYSkoaSk7dC5kZWZhdWx0PWF9LmNhbGwodCxuKDExKSxuKDc5KShlKSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdCxuPWUuU3ltYm9sO3JldHVybiJmdW5jdGlvbiI9PT10eXBlb2Ygbj9uLm9ic2VydmFibGU/dD1uLm9ic2VydmFibGU6KHQ9bigib2JzZXJ2YWJsZSIpLG4ub2JzZXJ2YWJsZT10KTp0PSJAQG9ic2VydmFibGUiLHR9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3QuR1JBUEhRTF9XUz0iZ3JhcGhxbC13cyI7dC5HUkFQSFFMX1NVQlNDUklQVElPTlM9ImdyYXBocWwtc3Vic2NyaXB0aW9ucyJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3QuV1NfVElNRU9VVD0zZTR9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3Rocm93IG5ldyBFcnJvcigiU3RhdGljIENsYXNzIil9cmV0dXJuIGUuR1FMX0NPTk5FQ1RJT05fSU5JVD0iY29ubmVjdGlvbl9pbml0IixlLkdRTF9DT05ORUNUSU9OX0FDSz0iY29ubmVjdGlvbl9hY2siLGUuR1FMX0NPTk5FQ1RJT05fRVJST1I9ImNvbm5lY3Rpb25fZXJyb3IiLGUuR1FMX0NPTk5FQ1RJT05fS0VFUF9BTElWRT0ia2EiLGUuR1FMX0NPTk5FQ1RJT05fVEVSTUlOQVRFPSJjb25uZWN0aW9uX3Rlcm1pbmF0ZSIsZS5HUUxfU1RBUlQ9InN0YXJ0IixlLkdRTF9EQVRBPSJkYXRhIixlLkdRTF9FUlJPUj0iZXJyb3IiLGUuR1FMX0NPTVBMRVRFPSJjb21wbGV0ZSIsZS5HUUxfU1RPUD0ic3RvcCIsZS5TVUJTQ1JJUFRJT05fU1RBUlQ9InN1YnNjcmlwdGlvbl9zdGFydCIsZS5TVUJTQ1JJUFRJT05fREFUQT0ic3Vic2NyaXB0aW9uX2RhdGEiLGUuU1VCU0NSSVBUSU9OX1NVQ0NFU1M9InN1YnNjcmlwdGlvbl9zdWNjZXNzIixlLlNVQlNDUklQVElPTl9GQUlMPSJzdWJzY3JpcHRpb25fZmFpbCIsZS5TVUJTQ1JJUFRJT05fRU5EPSJzdWJzY3JpcHRpb25fZW5kIixlLklOSVQ9ImluaXQiLGUuSU5JVF9TVUNDRVNTPSJpbml0X3N1Y2Nlc3MiLGUuSU5JVF9GQUlMPSJpbml0X2ZhaWwiLGUuS0VFUF9BTElWRT0ia2VlcGFsaXZlIixlfSgpO3QuZGVmYXVsdD1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDM4NSk7bi5kKHQsImNyZWF0ZUh0dHBMaW5rIixmdW5jdGlvbigpe3JldHVybiByLmJ9KSxuLmQodCwiSHR0cExpbmsiLGZ1bmN0aW9uKCl7cmV0dXJuIHIuYX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2YXIgbj1bXSxyPWZ1bmN0aW9uKGUsdCl7bi5wdXNoKGUrIj0iK2VuY29kZVVSSUNvbXBvbmVudCh0KSl9O2lmKCJxdWVyeSJpbiB0JiZyKCJxdWVyeSIsdC5xdWVyeSksdC5vcGVyYXRpb25OYW1lJiZyKCJvcGVyYXRpb25OYW1lIix0Lm9wZXJhdGlvbk5hbWUpLHQudmFyaWFibGVzKXt2YXIgaT12b2lkIDA7dHJ5e2k9T2JqZWN0KG8uZykodC52YXJpYWJsZXMsIlZhcmlhYmxlcyBtYXAiKX1jYXRjaChlKXtyZXR1cm57cGFyc2VFcnJvcjplfX1yKCJ2YXJpYWJsZXMiLGkpfWlmKHQuZXh0ZW5zaW9ucyl7dmFyIGE9dm9pZCAwO3RyeXthPU9iamVjdChvLmcpKHQuZXh0ZW5zaW9ucywiRXh0ZW5zaW9ucyBtYXAiKX1jYXRjaChlKXtyZXR1cm57cGFyc2VFcnJvcjplfX1yKCJleHRlbnNpb25zIixhKX12YXIgcz0iIix1PWUsYz1lLmluZGV4T2YoIiMiKTtyZXR1cm4tMSE9PWMmJihzPWUuc3Vic3RyKGMpLHU9ZS5zdWJzdHIoMCxjKSkse25ld1VSSTp1KygtMT09PXUuaW5kZXhPZigiPyIpPyI/IjoiJiIpK24uam9pbigiJiIpK3N9fW4uZCh0LCJiIixmdW5jdGlvbigpe3JldHVybiB1fSksbi5kKHQsImEiLGZ1bmN0aW9uKCl7cmV0dXJuIGN9KTt2YXIgaT1uKDc4KSxvPW4oMzg2KSxhPXRoaXMmJnRoaXMuX19leHRlbmRzfHxmdW5jdGlvbigpe3ZhciBlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLHM9dGhpcyYmdGhpcy5fX3Jlc3R8fGZ1bmN0aW9uKGUsdCl7dmFyIG49e307Zm9yKHZhciByIGluIGUpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUscikmJnQuaW5kZXhPZihyKTwwJiYobltyXT1lW3JdKTtpZihudWxsIT1lJiYiZnVuY3Rpb24iPT09dHlwZW9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMpZm9yKHZhciBpPTAscj1PYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKGUpO2k8ci5sZW5ndGg7aSsrKXQuaW5kZXhPZihyW2ldKTwwJiYobltyW2ldXT1lW3JbaV1dKTtyZXR1cm4gbn0sdT1mdW5jdGlvbihlKXt2b2lkIDA9PT1lJiYoZT17fSk7dmFyIHQ9ZS51cmksbj12b2lkIDA9PT10PyIvZ3JhcGhxbCI6dCxhPWUuZmV0Y2gsdT1lLmluY2x1ZGVFeHRlbnNpb25zLGM9ZS51c2VHRVRGb3JRdWVyaWVzLGw9cyhlLFsidXJpIiwiZmV0Y2giLCJpbmNsdWRlRXh0ZW5zaW9ucyIsInVzZUdFVEZvclF1ZXJpZXMiXSk7T2JqZWN0KG8uYSkoYSksYXx8KGE9ZmV0Y2gpO3ZhciBwPXtodHRwOntpbmNsdWRlRXh0ZW5zaW9uczp1fSxvcHRpb25zOmwuZmV0Y2hPcHRpb25zLGNyZWRlbnRpYWxzOmwuY3JlZGVudGlhbHMsaGVhZGVyczpsLmhlYWRlcnN9O3JldHVybiBuZXcgaS5BcG9sbG9MaW5rKGZ1bmN0aW9uKGUpe3ZhciB0LHM9T2JqZWN0KG8uZikoZSxuKSx1PWUuZ2V0Q29udGV4dCgpLGw9e2h0dHA6dS5odHRwLG9wdGlvbnM6dS5mZXRjaE9wdGlvbnMsY3JlZGVudGlhbHM6dS5jcmVkZW50aWFscyxoZWFkZXJzOnUuaGVhZGVyc30sZj1PYmplY3Qoby5lKShlLG8uYyxwLGwpLGQ9Zi5vcHRpb25zLGg9Zi5ib2R5O2lmKCFkLnNpZ25hbCl7dmFyIG09T2JqZWN0KG8uYikoKSxnPW0uY29udHJvbGxlcix5PW0uc2lnbmFsO3Q9Zyx0JiYoZC5zaWduYWw9eSl9dmFyIHY9ZnVuY3Rpb24oZSl7cmV0dXJuIk9wZXJhdGlvbkRlZmluaXRpb24iPT09ZS5raW5kJiYibXV0YXRpb24iPT09ZS5vcGVyYXRpb259O2lmKGMmJiFlLnF1ZXJ5LmRlZmluaXRpb25zLnNvbWUodikmJihkLm1ldGhvZD0iR0VUIiksIkdFVCI9PT1kLm1ldGhvZCl7dmFyIGI9cihzLGgpLHg9Yi5uZXdVUkksQz1iLnBhcnNlRXJyb3I7aWYoQylyZXR1cm4gT2JqZWN0KGkuZnJvbUVycm9yKShDKTtzPXh9ZWxzZSB0cnl7ZC5ib2R5PU9iamVjdChvLmcpKGgsIlBheWxvYWQiKX1jYXRjaChDKXtyZXR1cm4gT2JqZWN0KGkuZnJvbUVycm9yKShDKX1yZXR1cm4gbmV3IGkuT2JzZXJ2YWJsZShmdW5jdGlvbihuKXtyZXR1cm4gYShzLGQpLnRoZW4oZnVuY3Rpb24odCl7cmV0dXJuIGUuc2V0Q29udGV4dCh7cmVzcG9uc2U6dH0pLHR9KS50aGVuKE9iamVjdChvLmQpKGUpKS50aGVuKGZ1bmN0aW9uKGUpe3JldHVybiBuLm5leHQoZSksbi5jb21wbGV0ZSgpLGV9KS5jYXRjaChmdW5jdGlvbihlKXsiQWJvcnRFcnJvciIhPT1lLm5hbWUmJihlLnJlc3VsdCYmZS5yZXN1bHQuZXJyb3JzJiZlLnJlc3VsdC5kYXRhJiZuLm5leHQoZS5yZXN1bHQpLG4uZXJyb3IoZSkpfSksZnVuY3Rpb24oKXt0JiZ0LmFib3J0KCl9fSl9KX0sYz1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe3JldHVybiBlLmNhbGwodGhpcyx1KHQpLnJlcXVlc3QpfHx0aGlzfXJldHVybiBhKHQsZSksdH0oaS5BcG9sbG9MaW5rKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtuLmQodCwiYyIsZnVuY3Rpb24oKXtyZXR1cm4gdX0pLG4uZCh0LCJkIixmdW5jdGlvbigpe3JldHVybiBsfSksbi5kKHQsImEiLGZ1bmN0aW9uKCl7cmV0dXJuIHB9KSxuLmQodCwiYiIsZnVuY3Rpb24oKXtyZXR1cm4gZn0pLG4uZCh0LCJlIixmdW5jdGlvbigpe3JldHVybiBkfSksbi5kKHQsImciLGZ1bmN0aW9uKCl7cmV0dXJuIGh9KSxuLmQodCwiZiIsZnVuY3Rpb24oKXtyZXR1cm4gbX0pO3ZhciByPW4oMTkpLGk9KG4ubihyKSx0aGlzJiZ0aGlzLl9fYXNzaWdufHxPYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQsbj0xLHI9YXJndW1lbnRzLmxlbmd0aDtuPHI7bisrKXt0PWFyZ3VtZW50c1tuXTtmb3IodmFyIGkgaW4gdClPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxpKSYmKGVbaV09dFtpXSl9cmV0dXJuIGV9KSxvPXtpbmNsdWRlUXVlcnk6ITAsaW5jbHVkZUV4dGVuc2lvbnM6ITF9LGE9e2FjY2VwdDoiKi8qIiwiY29udGVudC10eXBlIjoiYXBwbGljYXRpb24vanNvbiJ9LHM9e21ldGhvZDoiUE9TVCJ9LHU9e2h0dHA6byxoZWFkZXJzOmEsb3B0aW9uczpzfSxjPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1uZXcgRXJyb3Iobik7dGhyb3cgci5yZXNwb25zZT1lLHIuc3RhdHVzQ29kZT1lLnN0YXR1cyxyLnJlc3VsdD10LHJ9LGw9ZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiB0LnRleHQoKS50aGVuKGZ1bmN0aW9uKGUpe3RyeXtyZXR1cm4gSlNPTi5wYXJzZShlKX1jYXRjaChyKXt2YXIgbj1yO3JldHVybiBuLnJlc3BvbnNlPXQsbi5zdGF0dXNDb2RlPXQuc3RhdHVzLG4uYm9keVRleHQ9ZSxQcm9taXNlLnJlamVjdChuKX19KS50aGVuKGZ1bmN0aW9uKG4pe3JldHVybiB0LnN0YXR1cz49MzAwJiZjKHQsbiwiUmVzcG9uc2Ugbm90IHN1Y2Nlc3NmdWw6IFJlY2VpdmVkIHN0YXR1cyBjb2RlICIrdC5zdGF0dXMpLEFycmF5LmlzQXJyYXkobil8fG4uaGFzT3duUHJvcGVydHkoImRhdGEiKXx8bi5oYXNPd25Qcm9wZXJ0eSgiZXJyb3JzIil8fGModCxuLCJTZXJ2ZXIgcmVzcG9uc2Ugd2FzIG1pc3NpbmcgZm9yIHF1ZXJ5ICciKyhBcnJheS5pc0FycmF5KGUpP2UubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLm9wZXJhdGlvbk5hbWV9KTplLm9wZXJhdGlvbk5hbWUpKyInLiIpLG59KX19LHA9ZnVuY3Rpb24oZSl7aWYoIWUmJiJ1bmRlZmluZWQiPT09dHlwZW9mIGZldGNoKXt2YXIgdD0idW5mZXRjaCI7dGhyb3cidW5kZWZpbmVkIj09PXR5cGVvZiB3aW5kb3cmJih0PSJub2RlLWZldGNoIiksbmV3IEVycm9yKCJcbmZldGNoIGlzIG5vdCBmb3VuZCBnbG9iYWxseSBhbmQgbm8gZmV0Y2hlciBwYXNzZWQsIHRvIGZpeCBwYXNzIGEgZmV0Y2ggZm9yXG55b3VyIGVudmlyb25tZW50IGxpa2UgaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2UvIit0KyIuXG5cbkZvciBleGFtcGxlOlxuaW1wb3J0IGZldGNoIGZyb20gJyIrdCsiJztcbmltcG9ydCB7IGNyZWF0ZUh0dHBMaW5rIH0gZnJvbSAnYXBvbGxvLWxpbmstaHR0cCc7XG5cbmNvbnN0IGxpbmsgPSBjcmVhdGVIdHRwTGluayh7IHVyaTogJy9ncmFwaHFsJywgZmV0Y2g6IGZldGNoIH0pOyIpfX0sZj1mdW5jdGlvbigpe2lmKCJ1bmRlZmluZWQiPT09dHlwZW9mIEFib3J0Q29udHJvbGxlcilyZXR1cm57Y29udHJvbGxlcjohMSxzaWduYWw6ITF9O3ZhciBlPW5ldyBBYm9ydENvbnRyb2xsZXI7cmV0dXJue2NvbnRyb2xsZXI6ZSxzaWduYWw6ZS5zaWduYWx9fSxkPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPVtdLG89MjtvPGFyZ3VtZW50cy5sZW5ndGg7bysrKW5bby0yXT1hcmd1bWVudHNbb107dmFyIGE9aSh7fSx0Lm9wdGlvbnMse2hlYWRlcnM6dC5oZWFkZXJzLGNyZWRlbnRpYWxzOnQuY3JlZGVudGlhbHN9KSxzPXQuaHR0cDtuLmZvckVhY2goZnVuY3Rpb24oZSl7YT1pKHt9LGEsZS5vcHRpb25zLHtoZWFkZXJzOmkoe30sYS5oZWFkZXJzLGUuaGVhZGVycyl9KSxlLmNyZWRlbnRpYWxzJiYoYS5jcmVkZW50aWFscz1lLmNyZWRlbnRpYWxzKSxzPWkoe30scyxlLmh0dHApfSk7dmFyIHU9ZS5vcGVyYXRpb25OYW1lLGM9ZS5leHRlbnNpb25zLGw9ZS52YXJpYWJsZXMscD1lLnF1ZXJ5LGY9e29wZXJhdGlvbk5hbWU6dSx2YXJpYWJsZXM6bH07cmV0dXJuIHMuaW5jbHVkZUV4dGVuc2lvbnMmJihmLmV4dGVuc2lvbnM9Yykscy5pbmNsdWRlUXVlcnkmJihmLnF1ZXJ5PU9iamVjdChyLnByaW50KShwKSkse29wdGlvbnM6YSxib2R5OmZ9fSxoPWZ1bmN0aW9uKGUsdCl7dmFyIG47dHJ5e249SlNPTi5zdHJpbmdpZnkoZSl9Y2F0Y2goZSl7dmFyIHI9bmV3IEVycm9yKCJOZXR3b3JrIHJlcXVlc3QgZmFpbGVkLiAiK3QrIiBpcyBub3Qgc2VyaWFsaXphYmxlOiAiK2UubWVzc2FnZSk7dGhyb3cgci5wYXJzZUVycm9yPWUscn1yZXR1cm4gbn0sbT1mdW5jdGlvbihlLHQpe3ZhciBuPWUuZ2V0Q29udGV4dCgpLHI9bi51cmk7cmV0dXJuIHJ8fCgiZnVuY3Rpb24iPT09dHlwZW9mIHQ/dChlKTp0fHwiL2dyYXBocWwiKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oMzg4KTtuLmQodCwiV2ViU29ja2V0TGluayIsZnVuY3Rpb24oKXtyZXR1cm4gci5hfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7bi5kKHQsImEiLGZ1bmN0aW9uKCl7cmV0dXJuIGF9KTt2YXIgcj1uKDc4KSxpPW4oMTc2KSxvPShuLm4oaSksdGhpcyYmdGhpcy5fX2V4dGVuZHN8fGZ1bmN0aW9uKCl7dmFyIGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCkpLGE9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0KXt2YXIgbj1lLmNhbGwodGhpcyl8fHRoaXM7cmV0dXJuIHQgaW5zdGFuY2VvZiBpLlN1YnNjcmlwdGlvbkNsaWVudD9uLnN1YnNjcmlwdGlvbkNsaWVudD10Om4uc3Vic2NyaXB0aW9uQ2xpZW50PW5ldyBpLlN1YnNjcmlwdGlvbkNsaWVudCh0LnVyaSx0Lm9wdGlvbnMsdC53ZWJTb2NrZXRJbXBsKSxufXJldHVybiBvKHQsZSksdC5wcm90b3R5cGUucmVxdWVzdD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5zdWJzY3JpcHRpb25DbGllbnQucmVxdWVzdChlKX0sdH0oci5BcG9sbG9MaW5rKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PWkoZSk7cmV0dXJuISF0JiYic3Vic2NyaXB0aW9uIj09PXQub3BlcmF0aW9ufWZ1bmN0aW9uIGkoZSl7cmV0dXJuIDE9PT1lLnF1ZXJ5LmRlZmluaXRpb25zLmxlbmd0aD9lLnF1ZXJ5LmRlZmluaXRpb25zWzBdOmUucXVlcnkuZGVmaW5pdGlvbnMuZmluZChmdW5jdGlvbih0KXtyZXR1cm4iT3BlcmF0aW9uRGVmaW5pdGlvbiI9PT10LmtpbmQmJiEhdC5uYW1lJiZ0Lm5hbWUudmFsdWU9PT1lLm9wZXJhdGlvbk5hbWV9KX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5pc1N1YnNjcmlwdGlvbj1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4scixvLGEscyl7cmV0dXJuIDE9PT1hcmd1bWVudHMubGVuZ3RoP2koZS5zY2hlbWEsZS5zb3VyY2UsZS5yb290VmFsdWUsZS5jb250ZXh0VmFsdWUsZS52YXJpYWJsZVZhbHVlcyxlLm9wZXJhdGlvbk5hbWUsZS5maWVsZFJlc29sdmVyKTppKGUsdCxuLHIsbyxhLHMpfWZ1bmN0aW9uIGkoZSx0LG4scixpLHUsYyl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKGwpe3ZhciBwPXZvaWQgMDt0cnl7cD0oMCxvLnBhcnNlKSh0KX1jYXRjaChlKXtyZXR1cm4gbCh7ZXJyb3JzOltlXX0pfXZhciBmPSgwLGEudmFsaWRhdGUpKGUscCk7aWYoZi5sZW5ndGg+MClyZXR1cm4gbCh7ZXJyb3JzOmZ9KTtsKCgwLHMuZXhlY3V0ZSkoZSxwLG4scixpLHUsYykpfSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZ3JhcGhxbD1yO3ZhciBvPW4oODApLGE9bigxODEpLHM9bigxMTgpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4pe3ZhciByPSgwLHUuZ2V0TG9jYXRpb24pKGUsdCksYT1yLmxpbmUrZS5sb2NhdGlvbk9mZnNldC5saW5lLTEscz1vKGUsciksbD1yLmNvbHVtbitzO3JldHVybiBuZXcgYy5HcmFwaFFMRXJyb3IoIlN5bnRheCBFcnJvciAiK2UubmFtZSsiICgiK2ErIjoiK2wrIikgIituKyJcblxuIitpKGUsciksdm9pZCAwLGUsW3RdKX1mdW5jdGlvbiBpKGUsdCl7dmFyIG49dC5saW5lLHI9ZS5sb2NhdGlvbk9mZnNldC5saW5lLTEsaT1vKGUsdCksdT1uK3IsYz0odS0xKS50b1N0cmluZygpLGw9dS50b1N0cmluZygpLHA9KHUrMSkudG9TdHJpbmcoKSxmPXAubGVuZ3RoLGQ9ZS5ib2R5LnNwbGl0KC9cclxufFtcblxyXS9nKTtyZXR1cm4gZFswXT1hKGUubG9jYXRpb25PZmZzZXQuY29sdW1uLTEpK2RbMF0sKG4+PTI/cyhmLGMpKyI6ICIrZFtuLTJdKyJcbiI6IiIpK3MoZixsKSsiOiAiK2Rbbi0xXSsiXG4iK2EoMitmK3QuY29sdW1uLTEraSkrIl5cbiIrKG48ZC5sZW5ndGg/cyhmLHApKyI6ICIrZFtuXSsiXG4iOiIiKX1mdW5jdGlvbiBvKGUsdCl7cmV0dXJuIDE9PT10LmxpbmU/ZS5sb2NhdGlvbk9mZnNldC5jb2x1bW4tMTowfWZ1bmN0aW9uIGEoZSl7cmV0dXJuIEFycmF5KGUrMSkuam9pbigiICIpfWZ1bmN0aW9uIHMoZSx0KXtyZXR1cm4gYShlLXQubGVuZ3RoKSt0fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnN5bnRheEVycm9yPXI7dmFyIHU9bigxMDkpLGM9big0Myl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZXx8KDAsby5kZWZhdWx0KSgwLCJSZWNlaXZlZCBudWxsIG9yIHVuZGVmaW5lZCBlcnJvci4iKSx7bWVzc2FnZTplLm1lc3NhZ2UsbG9jYXRpb25zOmUubG9jYXRpb25zLHBhdGg6ZS5wYXRofX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5mb3JtYXRFcnJvcj1yO3ZhciBpPW4oMTMpLG89ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9bigyNik7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxTY2hlbWEiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiByLkdyYXBoUUxTY2hlbWF9fSk7dmFyIGk9big2KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiaXNUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5pc1R5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzSW5wdXRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5pc0lucHV0VHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiaXNPdXRwdXRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5pc091dHB1dFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzTGVhZlR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLmlzTGVhZlR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzQ29tcG9zaXRlVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuaXNDb21wb3NpdGVUeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJpc0Fic3RyYWN0VHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuaXNBYnN0cmFjdFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzTmFtZWRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5pc05hbWVkVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXNzZXJ0VHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuYXNzZXJ0VHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXNzZXJ0SW5wdXRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5hc3NlcnRJbnB1dFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImFzc2VydE91dHB1dFR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLmFzc2VydE91dHB1dFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImFzc2VydExlYWZUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5hc3NlcnRMZWFmVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXNzZXJ0Q29tcG9zaXRlVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuYXNzZXJ0Q29tcG9zaXRlVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiYXNzZXJ0QWJzdHJhY3RUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5hc3NlcnRBYnN0cmFjdFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImFzc2VydE5hbWVkVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuYXNzZXJ0TmFtZWRUeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJnZXROdWxsYWJsZVR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLmdldE51bGxhYmxlVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0TmFtZWRUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5nZXROYW1lZFR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxTY2FsYXJUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5HcmFwaFFMU2NhbGFyVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiR3JhcGhRTE9iamVjdFR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLkdyYXBoUUxPYmplY3RUeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMSW50ZXJmYWNlVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTEludGVyZmFjZVR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxVbmlvblR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBpLkdyYXBoUUxVbmlvblR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxFbnVtVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTEVudW1UeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMSW5wdXRPYmplY3RUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5HcmFwaFFMSW5wdXRPYmplY3RUeXBlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMTGlzdCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuR3JhcGhRTExpc3R9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxOb25OdWxsIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5HcmFwaFFMTm9uTnVsbH19KTt2YXIgbz1uKDI3KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiRGlyZWN0aXZlTG9jYXRpb24iLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLkRpcmVjdGl2ZUxvY2F0aW9ufX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMRGlyZWN0aXZlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby5HcmFwaFFMRGlyZWN0aXZlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJzcGVjaWZpZWREaXJlY3RpdmVzIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby5zcGVjaWZpZWREaXJlY3RpdmVzfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMSW5jbHVkZURpcmVjdGl2ZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8uR3JhcGhRTEluY2x1ZGVEaXJlY3RpdmV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxTa2lwRGlyZWN0aXZlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby5HcmFwaFFMU2tpcERpcmVjdGl2ZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiR3JhcGhRTERlcHJlY2F0ZWREaXJlY3RpdmUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLkdyYXBoUUxEZXByZWNhdGVkRGlyZWN0aXZlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJERUZBVUxUX0RFUFJFQ0FUSU9OX1JFQVNPTiIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8uREVGQVVMVF9ERVBSRUNBVElPTl9SRUFTT059fSk7dmFyIGE9bigzMik7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxJbnQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBhLkdyYXBoUUxJbnR9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxGbG9hdCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGEuR3JhcGhRTEZsb2F0fX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMU3RyaW5nIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS5HcmFwaFFMU3RyaW5nfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJHcmFwaFFMQm9vbGVhbiIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGEuR3JhcGhRTEJvb2xlYW59fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkdyYXBoUUxJRCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGEuR3JhcGhRTElEfX0pO3ZhciBzPW4oMjgpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJUeXBlS2luZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHMuVHlwZUtpbmR9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fU2NoZW1hIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcy5fX1NjaGVtYX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19EaXJlY3RpdmUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBzLl9fRGlyZWN0aXZlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX0RpcmVjdGl2ZUxvY2F0aW9uIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcy5fX0RpcmVjdGl2ZUxvY2F0aW9ufX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX1R5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBzLl9fVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19GaWVsZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHMuX19GaWVsZH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19JbnB1dFZhbHVlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcy5fX0lucHV0VmFsdWV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fRW51bVZhbHVlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcy5fX0VudW1WYWx1ZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19UeXBlS2luZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHMuX19UeXBlS2luZH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiU2NoZW1hTWV0YUZpZWxkRGVmIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcy5TY2hlbWFNZXRhRmllbGREZWZ9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlR5cGVNZXRhRmllbGREZWYiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBzLlR5cGVNZXRhRmllbGREZWZ9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlR5cGVOYW1lTWV0YUZpZWxkRGVmIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcy5UeXBlTmFtZU1ldGFGaWVsZERlZn19KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5CUkVBSz10LmdldFZpc2l0Rm49dC52aXNpdFdpdGhUeXBlSW5mbz10LnZpc2l0SW5QYXJhbGxlbD10LnZpc2l0PXQuU291cmNlPXQucHJpbnQ9dC5wYXJzZVR5cGU9dC5wYXJzZVZhbHVlPXQucGFyc2U9dC5Ub2tlbktpbmQ9dC5jcmVhdGVMZXhlcj10LktpbmQ9dC5nZXRMb2NhdGlvbj12b2lkIDA7dmFyIHI9bigxMDkpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJnZXRMb2NhdGlvbiIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIuZ2V0TG9jYXRpb259fSk7dmFyIGk9bigxMTApO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJjcmVhdGVMZXhlciIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuY3JlYXRlTGV4ZXJ9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlRva2VuS2luZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuVG9rZW5LaW5kfX0pO3ZhciBvPW4oODApO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwYXJzZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8ucGFyc2V9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInBhcnNlVmFsdWUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLnBhcnNlVmFsdWV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInBhcnNlVHlwZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8ucGFyc2VUeXBlfX0pO3ZhciBhPW4oMTkpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwcmludCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGEucHJpbnR9fSk7dmFyIHM9bigxNzkpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJTb3VyY2UiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBzLlNvdXJjZX19KTt2YXIgdT1uKDU3KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidmlzaXQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LnZpc2l0fX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJ2aXNpdEluUGFyYWxsZWwiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LnZpc2l0SW5QYXJhbGxlbH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidmlzaXRXaXRoVHlwZUluZm8iLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LnZpc2l0V2l0aFR5cGVJbmZvfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJnZXRWaXNpdEZuIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5nZXRWaXNpdEZufX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJCUkVBSyIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHUuQlJFQUt9fSk7dmFyIGM9bigxMCksbD1mdW5jdGlvbihlKXtpZihlJiZlLl9fZXNNb2R1bGUpcmV0dXJuIGU7dmFyIHQ9e307aWYobnVsbCE9ZSlmb3IodmFyIG4gaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxuKSYmKHRbbl09ZVtuXSk7cmV0dXJuIHQuZGVmYXVsdD1lLHR9KGMpO3QuS2luZD1sfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDExOCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImV4ZWN1dGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiByLmV4ZWN1dGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImRlZmF1bHRGaWVsZFJlc29sdmVyIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gci5kZWZhdWx0RmllbGRSZXNvbHZlcn19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwicmVzcG9uc2VQYXRoQXNBcnJheSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIucmVzcG9uc2VQYXRoQXNBcnJheX19KTt2YXIgaT1uKDExOSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImdldERpcmVjdGl2ZVZhbHVlcyIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGkuZ2V0RGlyZWN0aXZlVmFsdWVzfX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDM5Nyk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInN1YnNjcmliZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIuc3Vic2NyaWJlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJjcmVhdGVTb3VyY2VFdmVudFN0cmVhbSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIuY3JlYXRlU291cmNlRXZlbnRTdHJlYW19fSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gaShlLHQsbixyLGksbyxzLHUpe3ZhciBjPTE9PT1hcmd1bWVudHMubGVuZ3RoP2U6dm9pZCAwLGw9Yz9jLnNjaGVtYTplO3JldHVybiBjP2EobCxjLmRvY3VtZW50LGMucm9vdFZhbHVlLGMuY29udGV4dFZhbHVlLGMudmFyaWFibGVWYWx1ZXMsYy5vcGVyYXRpb25OYW1lLGMuZmllbGRSZXNvbHZlcixjLnN1YnNjcmliZUZpZWxkUmVzb2x2ZXIpOmEobCx0LG4scixpLG8scyx1KX1mdW5jdGlvbiBvKGUpe2lmKGUgaW5zdGFuY2VvZiBjLkdyYXBoUUxFcnJvcilyZXR1cm57ZXJyb3JzOltlXX07dGhyb3cgZX1mdW5jdGlvbiBhKGUsdCxuLHIsaSxhLHUsYyl7dmFyIGw9ZnVuY3Rpb24obil7cmV0dXJuKDAscC5leGVjdXRlKShlLHQsbixyLGksYSx1KX07cmV0dXJuIHMoZSx0LG4scixpLGEsYykudGhlbihmdW5jdGlvbihlKXtyZXR1cm4oMCxtLmRlZmF1bHQpKGUsbCxvKX0sbyl9ZnVuY3Rpb24gcyhlLHQsbixyLGksbyxhKXtyZXR1cm4oMCxwLmFzc2VydFZhbGlkRXhlY3V0aW9uQXJndW1lbnRzKShlLHQsaSksbmV3IFByb21pc2UoZnVuY3Rpb24ocyxjKXt2YXIgZj0oMCxwLmJ1aWxkRXhlY3V0aW9uQ29udGV4dCkoZSx0LG4scixpLG8sYSksaD0oMCxwLmdldE9wZXJhdGlvblJvb3RUeXBlKShlLGYub3BlcmF0aW9uKSxtPSgwLHAuY29sbGVjdEZpZWxkcykoZixoLGYub3BlcmF0aW9uLnNlbGVjdGlvblNldCxPYmplY3QuY3JlYXRlKG51bGwpLE9iamVjdC5jcmVhdGUobnVsbCkpLGc9T2JqZWN0LmtleXMobSkseT1nWzBdLHY9bVt5XSxiPXZbMF0seD0oMCxwLmdldEZpZWxkRGVmKShlLGgsYi5uYW1lLnZhbHVlKTt4fHwoMCxkLmRlZmF1bHQpKDAsIlRoaXMgc3Vic2NyaXB0aW9uIGlzIG5vdCBkZWZpbmVkIGJ5IHRoZSBzY2hlbWEuIik7dmFyIEM9eC5zdWJzY3JpYmV8fGYuZmllbGRSZXNvbHZlcixFPSgwLHAuYWRkUGF0aCkodm9pZCAwLHkpLEQ9KDAscC5idWlsZFJlc29sdmVJbmZvKShmLHgsdixoLEUpO1Byb21pc2UucmVzb2x2ZSgoMCxwLnJlc29sdmVGaWVsZFZhbHVlT3JFcnJvcikoZix4LHYsQyxuLEQpKS50aGVuKGZ1bmN0aW9uKGUpe2lmKGUgaW5zdGFuY2VvZiBFcnJvcil7dmFyIHQ9KDAsbC5sb2NhdGVkRXJyb3IpKGUsdiwoMCxwLnJlc3BvbnNlUGF0aEFzQXJyYXkpKEUpKTtjKHQpfSgwLHUuaXNBc3luY0l0ZXJhYmxlKShlKXx8YyhuZXcgRXJyb3IoIlN1YnNjcmlwdGlvbiBtdXN0IHJldHVybiBBc3luYyBJdGVyYWJsZS4gUmVjZWl2ZWQ6ICIrU3RyaW5nKGUpKSkscyhlKX0pLmNhdGNoKGMpfSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuc3Vic2NyaWJlPWksdC5jcmVhdGVTb3VyY2VFdmVudFN0cmVhbT1zO3ZhciB1PW4oNDQpLGM9big0MyksbD1uKDE4MCkscD1uKDExOCksZj0obigyNiksbigxMykpLGQ9cihmKSxoPW4oMzk4KSxtPXIoaCl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuIHQgaW4gZT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0LHt2YWx1ZTpuLGVudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiEwLHdyaXRhYmxlOiEwfSk6ZVt0XT1uLGV9ZnVuY3Rpb24gaShlLHQsbil7ZnVuY3Rpb24gaShlKXtyZXR1cm4gZS5kb25lP2U6byhlLnZhbHVlLHQpLnRoZW4oYSxsKX12YXIgdT0oMCxzLmdldEFzeW5jSXRlcmF0b3IpKGUpLGM9dm9pZCAwLGw9dm9pZCAwOyJmdW5jdGlvbiI9PT10eXBlb2YgdS5yZXR1cm4mJihjPXUucmV0dXJuLGw9ZnVuY3Rpb24oZSl7dmFyIHQ9ZnVuY3Rpb24oKXtyZXR1cm4gUHJvbWlzZS5yZWplY3QoZSl9O3JldHVybiBjLmNhbGwodSkudGhlbih0LHQpfSk7dmFyIHA9dm9pZCAwO2lmKG4pe3ZhciBmPW47cD1mdW5jdGlvbihlKXtyZXR1cm4gbyhlLGYpLnRoZW4oYSxsKX19cmV0dXJuIHIoe25leHQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5uZXh0KCkudGhlbihpLHApfSxyZXR1cm46ZnVuY3Rpb24oKXtyZXR1cm4gYz9jLmNhbGwodSkudGhlbihpLHApOlByb21pc2UucmVzb2x2ZSh7dmFsdWU6dm9pZCAwLGRvbmU6ITB9KX0sdGhyb3c6ZnVuY3Rpb24oZSl7cmV0dXJuImZ1bmN0aW9uIj09PXR5cGVvZiB1LnRocm93P3UudGhyb3coZSkudGhlbihpLHApOlByb21pc2UucmVqZWN0KGUpLmNhdGNoKGwpfX0scy4kJGFzeW5jSXRlcmF0b3IsZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pfWZ1bmN0aW9uIG8oZSx0KXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24obil7cmV0dXJuIG4odChlKSl9KX1mdW5jdGlvbiBhKGUpe3JldHVybnt2YWx1ZTplLGRvbmU6ITF9fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmRlZmF1bHQ9aTt2YXIgcz1uKDQ0KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9bigxODEpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJ2YWxpZGF0ZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIudmFsaWRhdGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlZhbGlkYXRpb25Db250ZXh0Iix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gci5WYWxpZGF0aW9uQ29udGV4dH19KTt2YXIgaT1uKDE4Mik7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInNwZWNpZmllZFJ1bGVzIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5zcGVjaWZpZWRSdWxlc319KTt2YXIgbz1uKDIwMSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkFyZ3VtZW50c09mQ29ycmVjdFR5cGVSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gby5Bcmd1bWVudHNPZkNvcnJlY3RUeXBlfX0pO3ZhciBhPW4oMjAzKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiRGVmYXVsdFZhbHVlc09mQ29ycmVjdFR5cGVSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS5EZWZhdWx0VmFsdWVzT2ZDb3JyZWN0VHlwZX19KTt2YXIgcz1uKDE5MCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkZpZWxkc09uQ29ycmVjdFR5cGVSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcy5GaWVsZHNPbkNvcnJlY3RUeXBlfX0pO3ZhciB1PW4oMTg3KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiRnJhZ21lbnRzT25Db21wb3NpdGVUeXBlc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LkZyYWdtZW50c09uQ29tcG9zaXRlVHlwZXN9fSk7dmFyIGM9bigxOTkpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJLbm93bkFyZ3VtZW50TmFtZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYy5Lbm93bkFyZ3VtZW50TmFtZXN9fSk7dmFyIGw9bigxOTcpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJLbm93bkRpcmVjdGl2ZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC5Lbm93bkRpcmVjdGl2ZXN9fSk7dmFyIHA9bigxMTYpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJLbm93bkZyYWdtZW50TmFtZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcC5Lbm93bkZyYWdtZW50TmFtZXN9fSk7dmFyIGY9bigxODYpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJLbm93blR5cGVOYW1lc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBmLktub3duVHlwZU5hbWVzfX0pO3ZhciBkPW4oMTg0KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiTG9uZUFub255bW91c09wZXJhdGlvblJ1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBkLkxvbmVBbm9ueW1vdXNPcGVyYXRpb259fSk7dmFyIGg9bigxOTMpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJOb0ZyYWdtZW50Q3ljbGVzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGguTm9GcmFnbWVudEN5Y2xlc319KTt2YXIgbT1uKDE5NSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIk5vVW5kZWZpbmVkVmFyaWFibGVzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG0uTm9VbmRlZmluZWRWYXJpYWJsZXN9fSk7dmFyIGc9bigxMTcpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJOb1VudXNlZEZyYWdtZW50c1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBnLk5vVW51c2VkRnJhZ21lbnRzfX0pO3ZhciB5PW4oMTk2KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiTm9VbnVzZWRWYXJpYWJsZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4geS5Ob1VudXNlZFZhcmlhYmxlc319KTt2YXIgdj1uKDIwNSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIk92ZXJsYXBwaW5nRmllbGRzQ2FuQmVNZXJnZWRSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdi5PdmVybGFwcGluZ0ZpZWxkc0NhbkJlTWVyZ2VkfX0pO3ZhciBiPW4oMTkyKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiUG9zc2libGVGcmFnbWVudFNwcmVhZHNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYi5Qb3NzaWJsZUZyYWdtZW50U3ByZWFkc319KTt2YXIgeD1uKDIwMik7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlByb3ZpZGVkTm9uTnVsbEFyZ3VtZW50c1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB4LlByb3ZpZGVkTm9uTnVsbEFyZ3VtZW50c319KTt2YXIgQz1uKDE4OSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlNjYWxhckxlYWZzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIEMuU2NhbGFyTGVhZnN9fSk7dmFyIEU9bigxODUpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJTaW5nbGVGaWVsZFN1YnNjcmlwdGlvbnNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gRS5TaW5nbGVGaWVsZFN1YnNjcmlwdGlvbnN9fSk7dmFyIEQ9bigyMDApO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJVbmlxdWVBcmd1bWVudE5hbWVzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIEQuVW5pcXVlQXJndW1lbnROYW1lc319KTt2YXIgdz1uKDE5OCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlVuaXF1ZURpcmVjdGl2ZXNQZXJMb2NhdGlvblJ1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB3LlVuaXF1ZURpcmVjdGl2ZXNQZXJMb2NhdGlvbn19KTt2YXIgUz1uKDE5MSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlVuaXF1ZUZyYWdtZW50TmFtZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gUy5VbmlxdWVGcmFnbWVudE5hbWVzfX0pO3ZhciBrPW4oMjA2KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiVW5pcXVlSW5wdXRGaWVsZE5hbWVzUnVsZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGsuVW5pcXVlSW5wdXRGaWVsZE5hbWVzfX0pO3ZhciBBPW4oMTgzKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiVW5pcXVlT3BlcmF0aW9uTmFtZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gQS5VbmlxdWVPcGVyYXRpb25OYW1lc319KTt2YXIgXz1uKDE5NCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlVuaXF1ZVZhcmlhYmxlTmFtZXNSdWxlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gXy5VbmlxdWVWYXJpYWJsZU5hbWVzfX0pO3ZhciBUPW4oMTg4KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiVmFyaWFibGVzQXJlSW5wdXRUeXBlc1J1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBULlZhcmlhYmxlc0FyZUlucHV0VHlwZXN9fSk7dmFyIE89bigyMDQpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJWYXJpYWJsZXNJbkFsbG93ZWRQb3NpdGlvblJ1bGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBPLlZhcmlhYmxlc0luQWxsb3dlZFBvc2l0aW9ufX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDQwMSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImludHJvc3BlY3Rpb25RdWVyeSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIuaW50cm9zcGVjdGlvblF1ZXJ5fX0pO3ZhciBpPW4oMTc3KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiZ2V0T3BlcmF0aW9uQVNUIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5nZXRPcGVyYXRpb25BU1R9fSk7dmFyIG89big0MDIpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJidWlsZENsaWVudFNjaGVtYSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8uYnVpbGRDbGllbnRTY2hlbWF9fSk7dmFyIGE9bigyMDgpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJidWlsZEFTVFNjaGVtYSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGEuYnVpbGRBU1RTY2hlbWF9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImJ1aWxkU2NoZW1hIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYS5idWlsZFNjaGVtYX19KTt2YXIgcz1uKDQwMyk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImV4dGVuZFNjaGVtYSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHMuZXh0ZW5kU2NoZW1hfX0pO3ZhciB1PW4oNDA0KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwicHJpbnRTY2hlbWEiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LnByaW50U2NoZW1hfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwcmludFR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB1LnByaW50VHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwicHJpbnRJbnRyb3NwZWN0aW9uU2NoZW1hIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5wcmludEludHJvc3BlY3Rpb25TY2hlbWF9fSk7dmFyIGM9bigyOSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInR5cGVGcm9tQVNUIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYy50eXBlRnJvbUFTVH19KTt2YXIgbD1uKDU5KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidmFsdWVGcm9tQVNUIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gbC52YWx1ZUZyb21BU1R9fSk7dmFyIHA9bigxMTIpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJhc3RGcm9tVmFsdWUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBwLmFzdEZyb21WYWx1ZX19KTt2YXIgZj1uKDExMyk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIlR5cGVJbmZvIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gZi5UeXBlSW5mb319KTt2YXIgZD1uKDIwNyk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzVmFsaWRKU1ZhbHVlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gZC5pc1ZhbGlkSlNWYWx1ZX19KTt2YXIgaD1uKDgyKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiaXNWYWxpZExpdGVyYWxWYWx1ZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIGguaXNWYWxpZExpdGVyYWxWYWx1ZX19KTt2YXIgbT1uKDQwNSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImNvbmNhdEFTVCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG0uY29uY2F0QVNUfX0pO3ZhciBnPW4oNDA2KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwic2VwYXJhdGVPcGVyYXRpb25zIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gZy5zZXBhcmF0ZU9wZXJhdGlvbnN9fSk7dmFyIHk9big4MSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImlzRXF1YWxUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4geS5pc0VxdWFsVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiaXNUeXBlU3ViVHlwZU9mIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4geS5pc1R5cGVTdWJUeXBlT2Z9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImRvVHlwZXNPdmVybGFwIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4geS5kb1R5cGVzT3ZlcmxhcH19KTt2YXIgdj1uKDExMSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImFzc2VydFZhbGlkTmFtZSIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHYuYXNzZXJ0VmFsaWROYW1lfX0pO3ZhciBiPW4oNDA3KTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiQnJlYWtpbmdDaGFuZ2VUeXBlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYi5CcmVha2luZ0NoYW5nZVR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkRhbmdlcm91c0NoYW5nZVR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBiLkRhbmdlcm91c0NoYW5nZVR5cGV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImZpbmRCcmVha2luZ0NoYW5nZXMiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBiLmZpbmRCcmVha2luZ0NoYW5nZXN9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImZpbmREYW5nZXJvdXNDaGFuZ2VzIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYi5maW5kRGFuZ2Vyb3VzQ2hhbmdlc319KTt2YXIgeD1uKDQwOCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImZpbmREZXByZWNhdGVkVXNhZ2VzIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4geC5maW5kRGVwcmVjYXRlZFVzYWdlc319KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dC5pbnRyb3NwZWN0aW9uUXVlcnk9IlxuICBxdWVyeSBJbnRyb3NwZWN0aW9uUXVlcnkge1xuICAgIF9fc2NoZW1hIHtcbiAgICAgIHF1ZXJ5VHlwZSB7IG5hbWUgfVxuICAgICAgbXV0YXRpb25UeXBlIHsgbmFtZSB9XG4gICAgICBzdWJzY3JpcHRpb25UeXBlIHsgbmFtZSB9XG4gICAgICB0eXBlcyB7XG4gICAgICAgIC4uLkZ1bGxUeXBlXG4gICAgICB9XG4gICAgICBkaXJlY3RpdmVzIHtcbiAgICAgICAgbmFtZVxuICAgICAgICBkZXNjcmlwdGlvblxuICAgICAgICBsb2NhdGlvbnNcbiAgICAgICAgYXJncyB7XG4gICAgICAgICAgLi4uSW5wdXRWYWx1ZVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZnJhZ21lbnQgRnVsbFR5cGUgb24gX19UeXBlIHtcbiAgICBraW5kXG4gICAgbmFtZVxuICAgIGRlc2NyaXB0aW9uXG4gICAgZmllbGRzKGluY2x1ZGVEZXByZWNhdGVkOiB0cnVlKSB7XG4gICAgICBuYW1lXG4gICAgICBkZXNjcmlwdGlvblxuICAgICAgYXJncyB7XG4gICAgICAgIC4uLklucHV0VmFsdWVcbiAgICAgIH1cbiAgICAgIHR5cGUge1xuICAgICAgICAuLi5UeXBlUmVmXG4gICAgICB9XG4gICAgICBpc0RlcHJlY2F0ZWRcbiAgICAgIGRlcHJlY2F0aW9uUmVhc29uXG4gICAgfVxuICAgIGlucHV0RmllbGRzIHtcbiAgICAgIC4uLklucHV0VmFsdWVcbiAgICB9XG4gICAgaW50ZXJmYWNlcyB7XG4gICAgICAuLi5UeXBlUmVmXG4gICAgfVxuICAgIGVudW1WYWx1ZXMoaW5jbHVkZURlcHJlY2F0ZWQ6IHRydWUpIHtcbiAgICAgIG5hbWVcbiAgICAgIGRlc2NyaXB0aW9uXG4gICAgICBpc0RlcHJlY2F0ZWRcbiAgICAgIGRlcHJlY2F0aW9uUmVhc29uXG4gICAgfVxuICAgIHBvc3NpYmxlVHlwZXMge1xuICAgICAgLi4uVHlwZVJlZlxuICAgIH1cbiAgfVxuXG4gIGZyYWdtZW50IElucHV0VmFsdWUgb24gX19JbnB1dFZhbHVlIHtcbiAgICBuYW1lXG4gICAgZGVzY3JpcHRpb25cbiAgICB0eXBlIHsgLi4uVHlwZVJlZiB9XG4gICAgZGVmYXVsdFZhbHVlXG4gIH1cblxuICBmcmFnbWVudCBUeXBlUmVmIG9uIF9fVHlwZSB7XG4gICAga2luZFxuICAgIG5hbWVcbiAgICBvZlR5cGUge1xuICAgICAga2luZFxuICAgICAgbmFtZVxuICAgICAgb2ZUeXBlIHtcbiAgICAgICAga2luZFxuICAgICAgICBuYW1lXG4gICAgICAgIG9mVHlwZSB7XG4gICAgICAgICAga2luZFxuICAgICAgICAgIG5hbWVcbiAgICAgICAgICBvZlR5cGUge1xuICAgICAgICAgICAga2luZFxuICAgICAgICAgICAgbmFtZVxuICAgICAgICAgICAgb2ZUeXBlIHtcbiAgICAgICAgICAgICAga2luZFxuICAgICAgICAgICAgICBuYW1lXG4gICAgICAgICAgICAgIG9mVHlwZSB7XG4gICAgICAgICAgICAgICAga2luZFxuICAgICAgICAgICAgICAgIG5hbWVcbiAgICAgICAgICAgICAgICBvZlR5cGUge1xuICAgICAgICAgICAgICAgICAga2luZFxuICAgICAgICAgICAgICAgICAgbmFtZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuIn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1mdW5jdGlvbiBpKGUpe2Z1bmN0aW9uIHQoZSl7aWYoZS5raW5kPT09Zy5UeXBlS2luZC5MSVNUKXt2YXIgcj1lLm9mVHlwZTtpZighcil0aHJvdyBuZXcgRXJyb3IoIkRlY29yYXRlZCB0eXBlIGRlZXBlciB0aGFuIGludHJvc3BlY3Rpb24gcXVlcnkuIik7cmV0dXJuIG5ldyBtLkdyYXBoUUxMaXN0KHQocikpfWlmKGUua2luZD09PWcuVHlwZUtpbmQuTk9OX05VTEwpe3ZhciBpPWUub2ZUeXBlO2lmKCFpKXRocm93IG5ldyBFcnJvcigiRGVjb3JhdGVkIHR5cGUgZGVlcGVyIHRoYW4gaW50cm9zcGVjdGlvbiBxdWVyeS4iKTt2YXIgbz10KGkpO3JldHVybiBvIGluc3RhbmNlb2YgbS5HcmFwaFFMTm9uTnVsbCYmKDAscy5kZWZhdWx0KSgwLCJObyBuZXN0aW5nIG5vbm51bGwuIiksbmV3IG0uR3JhcGhRTE5vbk51bGwobyl9cmV0dXJuIG4oZS5uYW1lKX1mdW5jdGlvbiBuKGUpe2lmKEZbZV0pcmV0dXJuIEZbZV07dmFyIHQ9T1tlXTtpZighdCl0aHJvdyBuZXcgRXJyb3IoIkludmFsaWQgb3IgaW5jb21wbGV0ZSBzY2hlbWEsIHVua25vd24gdHlwZTogIitlKyIuIEVuc3VyZSB0aGF0IGEgZnVsbCBpbnRyb3NwZWN0aW9uIHF1ZXJ5IGlzIHVzZWQgaW4gb3JkZXIgdG8gYnVpbGQgYSBjbGllbnQgc2NoZW1hLiIpO3ZhciBuPWwodCk7cmV0dXJuIEZbZV09bixufWZ1bmN0aW9uIHIoZSl7dmFyIG49dChlKTtyZXR1cm4oMCxtLmlzSW5wdXRUeXBlKShuKXx8KDAscy5kZWZhdWx0KSgwLCJJbnRyb3NwZWN0aW9uIG11c3QgcHJvdmlkZSBpbnB1dCB0eXBlIGZvciBhcmd1bWVudHMuIiksbn1mdW5jdGlvbiBpKGUpe3ZhciBuPXQoZSk7cmV0dXJuKDAsbS5pc091dHB1dFR5cGUpKG4pfHwoMCxzLmRlZmF1bHQpKDAsIkludHJvc3BlY3Rpb24gbXVzdCBwcm92aWRlIG91dHB1dCB0eXBlIGZvciBmaWVsZHMuIiksbn1mdW5jdGlvbiBhKGUpe3ZhciBuPXQoZSk7cmV0dXJuIG4gaW5zdGFuY2VvZiBtLkdyYXBoUUxPYmplY3RUeXBlfHwoMCxzLmRlZmF1bHQpKDAsIkludHJvc3BlY3Rpb24gbXVzdCBwcm92aWRlIG9iamVjdCB0eXBlIGZvciBwb3NzaWJsZVR5cGVzLiIpLG59ZnVuY3Rpb24gdShlKXt2YXIgbj10KGUpO3JldHVybiBuIGluc3RhbmNlb2YgbS5HcmFwaFFMSW50ZXJmYWNlVHlwZXx8KDAscy5kZWZhdWx0KSgwLCJJbnRyb3NwZWN0aW9uIG11c3QgcHJvdmlkZSBpbnRlcmZhY2UgdHlwZSBmb3IgaW50ZXJmYWNlcy4iKSxufWZ1bmN0aW9uIGwoZSl7c3dpdGNoKGUua2luZCl7Y2FzZSBnLlR5cGVLaW5kLlNDQUxBUjpyZXR1cm4gYihlKTtjYXNlIGcuVHlwZUtpbmQuT0JKRUNUOnJldHVybiB4KGUpO2Nhc2UgZy5UeXBlS2luZC5JTlRFUkZBQ0U6cmV0dXJuIEMoZSk7Y2FzZSBnLlR5cGVLaW5kLlVOSU9OOnJldHVybiBFKGUpO2Nhc2UgZy5UeXBlS2luZC5FTlVNOnJldHVybiBEKGUpO2Nhc2UgZy5UeXBlS2luZC5JTlBVVF9PQkpFQ1Q6cmV0dXJuIHcoZSk7ZGVmYXVsdDp0aHJvdyBuZXcgRXJyb3IoIkludmFsaWQgb3IgaW5jb21wbGV0ZSBzY2hlbWEsIHVua25vd24ga2luZDogIitlLmtpbmQrIi4gRW5zdXJlIHRoYXQgYSBmdWxsIGludHJvc3BlY3Rpb24gcXVlcnkgaXMgdXNlZCBpbiBvcmRlciB0byBidWlsZCBhIGNsaWVudCBzY2hlbWEuIil9fWZ1bmN0aW9uIGIoZSl7cmV0dXJuIG5ldyBtLkdyYXBoUUxTY2FsYXJUeXBlKHtuYW1lOmUubmFtZSxkZXNjcmlwdGlvbjplLmRlc2NyaXB0aW9uLHNlcmlhbGl6ZTpmdW5jdGlvbihlKXtyZXR1cm4gZX0scGFyc2VWYWx1ZTpmdW5jdGlvbigpe3JldHVybiExfSxwYXJzZUxpdGVyYWw6ZnVuY3Rpb24oKXtyZXR1cm4hMX19KX1mdW5jdGlvbiB4KGUpe3JldHVybiBuZXcgbS5HcmFwaFFMT2JqZWN0VHlwZSh7bmFtZTplLm5hbWUsZGVzY3JpcHRpb246ZS5kZXNjcmlwdGlvbixpbnRlcmZhY2VzOmUuaW50ZXJmYWNlcy5tYXAodSksZmllbGRzOmZ1bmN0aW9uKCl7cmV0dXJuIFMoZSl9fSl9ZnVuY3Rpb24gQyhlKXtyZXR1cm4gbmV3IG0uR3JhcGhRTEludGVyZmFjZVR5cGUoe25hbWU6ZS5uYW1lLGRlc2NyaXB0aW9uOmUuZGVzY3JpcHRpb24sZmllbGRzOmZ1bmN0aW9uKCl7cmV0dXJuIFMoZSl9LHJlc29sdmVUeXBlOm99KX1mdW5jdGlvbiBFKGUpe3JldHVybiBuZXcgbS5HcmFwaFFMVW5pb25UeXBlKHtuYW1lOmUubmFtZSxkZXNjcmlwdGlvbjplLmRlc2NyaXB0aW9uLHR5cGVzOmUucG9zc2libGVUeXBlcy5tYXAoYSkscmVzb2x2ZVR5cGU6b30pfWZ1bmN0aW9uIEQoZSl7cmV0dXJuIG5ldyBtLkdyYXBoUUxFbnVtVHlwZSh7bmFtZTplLm5hbWUsZGVzY3JpcHRpb246ZS5kZXNjcmlwdGlvbix2YWx1ZXM6KDAscC5kZWZhdWx0KShlLmVudW1WYWx1ZXMsZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZX0sZnVuY3Rpb24oZSl7cmV0dXJue2Rlc2NyaXB0aW9uOmUuZGVzY3JpcHRpb24sZGVwcmVjYXRpb25SZWFzb246ZS5kZXByZWNhdGlvblJlYXNvbn19KX0pfWZ1bmN0aW9uIHcoZSl7cmV0dXJuIG5ldyBtLkdyYXBoUUxJbnB1dE9iamVjdFR5cGUoe25hbWU6ZS5uYW1lLGRlc2NyaXB0aW9uOmUuZGVzY3JpcHRpb24sZmllbGRzOmZ1bmN0aW9uKCl7cmV0dXJuIGsoZS5pbnB1dEZpZWxkcyl9fSl9ZnVuY3Rpb24gUyhlKXtyZXR1cm4oMCxwLmRlZmF1bHQpKGUuZmllbGRzLGZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWV9LGZ1bmN0aW9uKGUpe3JldHVybntkZXNjcmlwdGlvbjplLmRlc2NyaXB0aW9uLGRlcHJlY2F0aW9uUmVhc29uOmUuZGVwcmVjYXRpb25SZWFzb24sdHlwZTppKGUudHlwZSksYXJnczprKGUuYXJncyl9fSl9ZnVuY3Rpb24gayhlKXtyZXR1cm4oMCxwLmRlZmF1bHQpKGUsZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZX0sQSl9ZnVuY3Rpb24gQShlKXt2YXIgdD1yKGUudHlwZSksbj1lLmRlZmF1bHRWYWx1ZT8oMCxmLnZhbHVlRnJvbUFTVCkoKDAsZC5wYXJzZVZhbHVlKShlLmRlZmF1bHRWYWx1ZSksdCk6dm9pZCAwO3JldHVybntuYW1lOmUubmFtZSxkZXNjcmlwdGlvbjplLmRlc2NyaXB0aW9uLHR5cGU6dCxkZWZhdWx0VmFsdWU6bn19ZnVuY3Rpb24gXyhlKXt2YXIgdD1lLmxvY2F0aW9ucz9lLmxvY2F0aW9ucy5zbGljZSgpOltdLmNvbmNhdChlLm9uRmllbGQ/W3YuRGlyZWN0aXZlTG9jYXRpb24uRklFTERdOltdLGUub25PcGVyYXRpb24/W3YuRGlyZWN0aXZlTG9jYXRpb24uUVVFUlksdi5EaXJlY3RpdmVMb2NhdGlvbi5NVVRBVElPTix2LkRpcmVjdGl2ZUxvY2F0aW9uLlNVQlNDUklQVElPTl06W10sZS5vbkZyYWdtZW50P1t2LkRpcmVjdGl2ZUxvY2F0aW9uLkZSQUdNRU5UX0RFRklOSVRJT04sdi5EaXJlY3RpdmVMb2NhdGlvbi5GUkFHTUVOVF9TUFJFQUQsdi5EaXJlY3RpdmVMb2NhdGlvbi5JTkxJTkVfRlJBR01FTlRdOltdKTtyZXR1cm4gbmV3IHYuR3JhcGhRTERpcmVjdGl2ZSh7bmFtZTplLm5hbWUsZGVzY3JpcHRpb246ZS5kZXNjcmlwdGlvbixsb2NhdGlvbnM6dCxhcmdzOmsoZS5hcmdzKX0pfXZhciBUPWUuX19zY2hlbWEsTz0oMCxjLmRlZmF1bHQpKFQudHlwZXMsZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZX0pLEY9e1N0cmluZzp5LkdyYXBoUUxTdHJpbmcsSW50OnkuR3JhcGhRTEludCxGbG9hdDp5LkdyYXBoUUxGbG9hdCxCb29sZWFuOnkuR3JhcGhRTEJvb2xlYW4sSUQ6eS5HcmFwaFFMSUQsX19TY2hlbWE6Zy5fX1NjaGVtYSxfX0RpcmVjdGl2ZTpnLl9fRGlyZWN0aXZlLF9fRGlyZWN0aXZlTG9jYXRpb246Zy5fX0RpcmVjdGl2ZUxvY2F0aW9uLF9fVHlwZTpnLl9fVHlwZSxfX0ZpZWxkOmcuX19GaWVsZCxfX0lucHV0VmFsdWU6Zy5fX0lucHV0VmFsdWUsX19FbnVtVmFsdWU6Zy5fX0VudW1WYWx1ZSxfX1R5cGVLaW5kOmcuX19UeXBlS2luZH0sTj1ULnR5cGVzLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gbihlLm5hbWUpfSksST1hKFQucXVlcnlUeXBlKSxMPVQubXV0YXRpb25UeXBlP2EoVC5tdXRhdGlvblR5cGUpOm51bGwsUD1ULnN1YnNjcmlwdGlvblR5cGU/YShULnN1YnNjcmlwdGlvblR5cGUpOm51bGwsTT1ULmRpcmVjdGl2ZXM/VC5kaXJlY3RpdmVzLm1hcChfKTpbXTtyZXR1cm4gbmV3IGguR3JhcGhRTFNjaGVtYSh7cXVlcnk6SSxtdXRhdGlvbjpMLHN1YnNjcmlwdGlvbjpQLHR5cGVzOk4sZGlyZWN0aXZlczpNfSl9ZnVuY3Rpb24gbygpe3Rocm93IG5ldyBFcnJvcigiQ2xpZW50IFNjaGVtYSBjYW5ub3QgdXNlIEludGVyZmFjZSBvciBVbmlvbiB0eXBlcyBmb3IgZXhlY3V0aW9uLiIpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmJ1aWxkQ2xpZW50U2NoZW1hPWk7dmFyIGE9bigxMykscz1yKGEpLHU9big0NiksYz1yKHUpLGw9bigxMjApLHA9cihsKSxmPW4oNTkpLGQ9big4MCksaD1uKDI2KSxtPW4oNiksZz1uKDI4KSx5PW4oMzIpLHY9bigyNyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gaShlLHQpe2Z1bmN0aW9uIG4oZSl7dmFyIHQ9eChlLm5hbWUpO3JldHVybiB0fHwoMCxzLmRlZmF1bHQpKDAsIk1pc3NpbmcgdHlwZSBmcm9tIHNjaGVtYSIpLHR9ZnVuY3Rpb24gcihlKXt2YXIgdD14KGUubmFtZS52YWx1ZSk7aWYoIXQpdGhyb3cgbmV3IGguR3JhcGhRTEVycm9yKCdVbmtub3duIHR5cGU6ICInK2UubmFtZS52YWx1ZSsnIi4gRW5zdXJlIHRoYXQgdGhpcyB0eXBlIGV4aXN0cyBlaXRoZXIgaW4gdGhlIG9yaWdpbmFsIHNjaGVtYSwgb3IgaXMgYWRkZWQgaW4gYSB0eXBlIGRlZmluaXRpb24uJyxbZV0pO3JldHVybiB0fWZ1bmN0aW9uIGkoZSl7dmFyIHQ9cihlKTtyZXR1cm4gdCBpbnN0YW5jZW9mIGcuR3JhcGhRTE9iamVjdFR5cGV8fCgwLHMuZGVmYXVsdCkoMCwiTXVzdCBiZSBPYmplY3QgdHlwZS4iKSx0fWZ1bmN0aW9uIGEoZSl7dmFyIHQ9cihlKTtyZXR1cm4gdCBpbnN0YW5jZW9mIGcuR3JhcGhRTEludGVyZmFjZVR5cGV8fCgwLHMuZGVmYXVsdCkoMCwiTXVzdCBiZSBJbnRlcmZhY2UgdHlwZS4iKSx0fWZ1bmN0aW9uIHUoZSl7cmV0dXJuKDAsZy5hc3NlcnRJbnB1dFR5cGUpKHIoZSkpfWZ1bmN0aW9uIGwoZSl7cmV0dXJuKDAsZy5hc3NlcnRPdXRwdXRUeXBlKShyKGUpKX1mdW5jdGlvbiB4KHQpe3ZhciBuPVhbdF07aWYobilyZXR1cm4gbjt2YXIgcj1lLmdldFR5cGUodCk7aWYocil7dmFyIGk9RShyKTtyZXR1cm4gWFt0XT1pLGl9dmFyIG89elt0XTtpZihvKXt2YXIgYT1UKG8pO3JldHVybiBYW3RdPWEsYX19ZnVuY3Rpb24gRShlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIGcuR3JhcGhRTE9iamVjdFR5cGU/RChlKTplIGluc3RhbmNlb2YgZy5HcmFwaFFMSW50ZXJmYWNlVHlwZT93KGUpOmUgaW5zdGFuY2VvZiBnLkdyYXBoUUxVbmlvblR5cGU/UyhlKTplfWZ1bmN0aW9uIEQoZSl7dmFyIHQ9ZS5uYW1lLG49ZS5leHRlbnNpb25BU1ROb2RlcztyZXR1cm4gR1t0XSYmKG49bi5jb25jYXQoR1t0XSkpLG5ldyBnLkdyYXBoUUxPYmplY3RUeXBlKHtuYW1lOnQsZGVzY3JpcHRpb246ZS5kZXNjcmlwdGlvbixpbnRlcmZhY2VzOmZ1bmN0aW9uKCl7cmV0dXJuIGsoZSl9LGZpZWxkczpmdW5jdGlvbigpe3JldHVybiBBKGUpfSxhc3ROb2RlOmUuYXN0Tm9kZSxleHRlbnNpb25BU1ROb2RlczpuLGlzVHlwZU9mOmUuaXNUeXBlT2Z9KX1mdW5jdGlvbiB3KGUpe3JldHVybiBuZXcgZy5HcmFwaFFMSW50ZXJmYWNlVHlwZSh7bmFtZTplLm5hbWUsZGVzY3JpcHRpb246ZS5kZXNjcmlwdGlvbixmaWVsZHM6ZnVuY3Rpb24oKXtyZXR1cm4gQShlKX0sYXN0Tm9kZTplLmFzdE5vZGUscmVzb2x2ZVR5cGU6ZS5yZXNvbHZlVHlwZX0pfWZ1bmN0aW9uIFMoZSl7cmV0dXJuIG5ldyBnLkdyYXBoUUxVbmlvblR5cGUoe25hbWU6ZS5uYW1lLGRlc2NyaXB0aW9uOmUuZGVzY3JpcHRpb24sdHlwZXM6ZS5nZXRUeXBlcygpLm1hcChuKSxhc3ROb2RlOmUuYXN0Tm9kZSxyZXNvbHZlVHlwZTplLnJlc29sdmVUeXBlfSl9ZnVuY3Rpb24gayhlKXt2YXIgdD1lLmdldEludGVyZmFjZXMoKS5tYXAobikscj1HW2UubmFtZV07cmV0dXJuIHImJnIuZm9yRWFjaChmdW5jdGlvbihuKXtuLmRlZmluaXRpb24uaW50ZXJmYWNlcy5mb3JFYWNoKGZ1bmN0aW9uKG4pe3ZhciByPW4ubmFtZS52YWx1ZTtpZih0LnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZT09PXJ9KSl0aHJvdyBuZXcgaC5HcmFwaFFMRXJyb3IoJ1R5cGUgIicrZS5uYW1lKyciIGFscmVhZHkgaW1wbGVtZW50cyAiJytyKyciLiBJdCBjYW5ub3QgYWxzbyBiZSBpbXBsZW1lbnRlZCBpbiB0aGlzIHR5cGUgZXh0ZW5zaW9uLicsW25dKTt0LnB1c2goYShuKSl9KX0pLHR9ZnVuY3Rpb24gQShlKXt2YXIgdD1PYmplY3QuY3JlYXRlKG51bGwpLG49ZS5nZXRGaWVsZHMoKTtPYmplY3Qua2V5cyhuKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciByPW5bZV07dFtlXT17ZGVzY3JpcHRpb246ci5kZXNjcmlwdGlvbixkZXByZWNhdGlvblJlYXNvbjpyLmRlcHJlY2F0aW9uUmVhc29uLHR5cGU6XyhyLnR5cGUpLGFyZ3M6KDAsYy5kZWZhdWx0KShyLmFyZ3MsZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZX0pLGFzdE5vZGU6ci5hc3ROb2RlLHJlc29sdmU6ci5yZXNvbHZlfX0pO3ZhciByPUdbZS5uYW1lXTtyZXR1cm4gciYmci5mb3JFYWNoKGZ1bmN0aW9uKHIpe3IuZGVmaW5pdGlvbi5maWVsZHMuZm9yRWFjaChmdW5jdGlvbihyKXt2YXIgaT1yLm5hbWUudmFsdWU7aWYobltpXSl0aHJvdyBuZXcgaC5HcmFwaFFMRXJyb3IoJ0ZpZWxkICInK2UubmFtZSsiLiIraSsnIiBhbHJlYWR5IGV4aXN0cyBpbiB0aGUgc2NoZW1hLiBJdCBjYW5ub3QgYWxzbyBiZSBkZWZpbmVkIGluIHRoaXMgdHlwZSBleHRlbnNpb24uJyxbcl0pO3RbaV09e2Rlc2NyaXB0aW9uOigwLGYuZ2V0RGVzY3JpcHRpb24pKHIpLHR5cGU6VShyLnR5cGUpLGFyZ3M6QihyLmFyZ3VtZW50cyksZGVwcmVjYXRpb25SZWFzb246KDAsZi5nZXREZXByZWNhdGlvblJlYXNvbikociksYXN0Tm9kZTpyfX0pfSksdH1mdW5jdGlvbiBfKGUpe3JldHVybiBlIGluc3RhbmNlb2YgZy5HcmFwaFFMTGlzdD9uZXcgZy5HcmFwaFFMTGlzdChfKGUub2ZUeXBlKSk6ZSBpbnN0YW5jZW9mIGcuR3JhcGhRTE5vbk51bGw/bmV3IGcuR3JhcGhRTE5vbk51bGwoXyhlLm9mVHlwZSkpOm4oZSl9ZnVuY3Rpb24gVChlKXtzd2l0Y2goZS5raW5kKXtjYXNlIEMuT0JKRUNUX1RZUEVfREVGSU5JVElPTjpyZXR1cm4gTyhlKTtjYXNlIEMuSU5URVJGQUNFX1RZUEVfREVGSU5JVElPTjpyZXR1cm4gRihlKTtjYXNlIEMuVU5JT05fVFlQRV9ERUZJTklUSU9OOnJldHVybiBOKGUpO2Nhc2UgQy5TQ0FMQVJfVFlQRV9ERUZJTklUSU9OOnJldHVybiBJKGUpO2Nhc2UgQy5FTlVNX1RZUEVfREVGSU5JVElPTjpyZXR1cm4gTChlKTtjYXNlIEMuSU5QVVRfT0JKRUNUX1RZUEVfREVGSU5JVElPTjpyZXR1cm4gUChlKX10aHJvdyBuZXcgVHlwZUVycm9yKCJVbmtub3duIHR5cGUga2luZCAiK2Uua2luZCl9ZnVuY3Rpb24gTyhlKXtyZXR1cm4gbmV3IGcuR3JhcGhRTE9iamVjdFR5cGUoe25hbWU6ZS5uYW1lLnZhbHVlLGRlc2NyaXB0aW9uOigwLGYuZ2V0RGVzY3JpcHRpb24pKGUpLGludGVyZmFjZXM6ZnVuY3Rpb24oKXtyZXR1cm4gaihlKX0sZmllbGRzOmZ1bmN0aW9uKCl7cmV0dXJuIFIoZSl9LGFzdE5vZGU6ZX0pfWZ1bmN0aW9uIEYoZSl7cmV0dXJuIG5ldyBnLkdyYXBoUUxJbnRlcmZhY2VUeXBlKHtuYW1lOmUubmFtZS52YWx1ZSxkZXNjcmlwdGlvbjooMCxmLmdldERlc2NyaXB0aW9uKShlKSxmaWVsZHM6ZnVuY3Rpb24oKXtyZXR1cm4gUihlKX0sYXN0Tm9kZTplLHJlc29sdmVUeXBlOm99KX1mdW5jdGlvbiBOKGUpe3JldHVybiBuZXcgZy5HcmFwaFFMVW5pb25UeXBlKHtuYW1lOmUubmFtZS52YWx1ZSxkZXNjcmlwdGlvbjooMCxmLmdldERlc2NyaXB0aW9uKShlKSx0eXBlczplLnR5cGVzLm1hcChpKSxhc3ROb2RlOmUscmVzb2x2ZVR5cGU6b30pfWZ1bmN0aW9uIEkoZSl7cmV0dXJuIG5ldyBnLkdyYXBoUUxTY2FsYXJUeXBlKHtuYW1lOmUubmFtZS52YWx1ZSxkZXNjcmlwdGlvbjooMCxmLmdldERlc2NyaXB0aW9uKShlKSxhc3ROb2RlOmUsc2VyaWFsaXplOmZ1bmN0aW9uKGUpe3JldHVybiBlfSxwYXJzZVZhbHVlOmZ1bmN0aW9uKCl7cmV0dXJuITF9LHBhcnNlTGl0ZXJhbDpmdW5jdGlvbigpe3JldHVybiExfX0pfWZ1bmN0aW9uIEwoZSl7cmV0dXJuIG5ldyBnLkdyYXBoUUxFbnVtVHlwZSh7bmFtZTplLm5hbWUudmFsdWUsZGVzY3JpcHRpb246KDAsZi5nZXREZXNjcmlwdGlvbikoZSksdmFsdWVzOigwLHAuZGVmYXVsdCkoZS52YWx1ZXMsZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZS52YWx1ZX0sZnVuY3Rpb24oZSl7cmV0dXJue2Rlc2NyaXB0aW9uOigwLGYuZ2V0RGVzY3JpcHRpb24pKGUpLGRlcHJlY2F0aW9uUmVhc29uOigwLGYuZ2V0RGVwcmVjYXRpb25SZWFzb24pKGUpLGFzdE5vZGU6ZX19KSxhc3ROb2RlOmV9KX1mdW5jdGlvbiBQKGUpe3JldHVybiBuZXcgZy5HcmFwaFFMSW5wdXRPYmplY3RUeXBlKHtuYW1lOmUubmFtZS52YWx1ZSxkZXNjcmlwdGlvbjooMCxmLmdldERlc2NyaXB0aW9uKShlKSxmaWVsZHM6ZnVuY3Rpb24oKXtyZXR1cm4gQihlLmZpZWxkcyl9LGFzdE5vZGU6ZX0pfWZ1bmN0aW9uIE0oZSl7cmV0dXJuIG5ldyB5LkdyYXBoUUxEaXJlY3RpdmUoe25hbWU6ZS5uYW1lLnZhbHVlLGRlc2NyaXB0aW9uOigwLGYuZ2V0RGVzY3JpcHRpb24pKGUpLGxvY2F0aW9uczplLmxvY2F0aW9ucy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUudmFsdWV9KSxhcmdzOmUuYXJndW1lbnRzJiZCKGUuYXJndW1lbnRzKSxhc3ROb2RlOmV9KX1mdW5jdGlvbiBqKGUpe3JldHVybiBlLmludGVyZmFjZXMmJmUuaW50ZXJmYWNlcy5tYXAoYSl9ZnVuY3Rpb24gUihlKXtyZXR1cm4oMCxwLmRlZmF1bHQpKGUuZmllbGRzLGZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWUudmFsdWV9LGZ1bmN0aW9uKGUpe3JldHVybnt0eXBlOlUoZS50eXBlKSxkZXNjcmlwdGlvbjooMCxmLmdldERlc2NyaXB0aW9uKShlKSxhcmdzOkIoZS5hcmd1bWVudHMpLGRlcHJlY2F0aW9uUmVhc29uOigwLGYuZ2V0RGVwcmVjYXRpb25SZWFzb24pKGUpLGFzdE5vZGU6ZX19KX1mdW5jdGlvbiBCKGUpe3JldHVybigwLHAuZGVmYXVsdCkoZSxmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lLnZhbHVlfSxmdW5jdGlvbihlKXt2YXIgdD0kKGUudHlwZSk7cmV0dXJue3R5cGU6dCxkZXNjcmlwdGlvbjooMCxmLmdldERlc2NyaXB0aW9uKShlKSxkZWZhdWx0VmFsdWU6KDAsZC52YWx1ZUZyb21BU1QpKGUuZGVmYXVsdFZhbHVlLHQpLGFzdE5vZGU6ZX19KX1mdW5jdGlvbiAkKGUpe2lmKGUua2luZD09PUMuTElTVF9UWVBFKXJldHVybiBuZXcgZy5HcmFwaFFMTGlzdCgkKGUudHlwZSkpO2lmKGUua2luZD09PUMuTk9OX05VTExfVFlQRSl7dmFyIHQ9JChlLnR5cGUpO3JldHVybiB0IGluc3RhbmNlb2YgZy5HcmFwaFFMTm9uTnVsbCYmKDAscy5kZWZhdWx0KSgwLCJNdXN0IGJlIG51bGxhYmxlIiksbmV3IGcuR3JhcGhRTE5vbk51bGwodCl9cmV0dXJuIHUoZSl9ZnVuY3Rpb24gVShlKXtpZihlLmtpbmQ9PT1DLkxJU1RfVFlQRSlyZXR1cm4gbmV3IGcuR3JhcGhRTExpc3QoVShlLnR5cGUpKTtpZihlLmtpbmQ9PT1DLk5PTl9OVUxMX1RZUEUpe3ZhciB0PVUoZS50eXBlKTtyZXR1cm4gdCBpbnN0YW5jZW9mIGcuR3JhcGhRTE5vbk51bGwmJigwLHMuZGVmYXVsdCkoMCwiTXVzdCBiZSBudWxsYWJsZSIpLG5ldyBnLkdyYXBoUUxOb25OdWxsKHQpfXJldHVybiBsKGUpfWUgaW5zdGFuY2VvZiBtLkdyYXBoUUxTY2hlbWF8fCgwLHMuZGVmYXVsdCkoMCwiTXVzdCBwcm92aWRlIHZhbGlkIEdyYXBoUUxTY2hlbWEiKSx0JiZ0LmtpbmQ9PT1DLkRPQ1VNRU5UfHwoMCxzLmRlZmF1bHQpKDAsIk11c3QgcHJvdmlkZSB2YWxpZCBEb2N1bWVudCBBU1QiKTtmb3IodmFyIHo9T2JqZWN0LmNyZWF0ZShudWxsKSxHPU9iamVjdC5jcmVhdGUobnVsbCksVj1bXSxxPTA7cTx0LmRlZmluaXRpb25zLmxlbmd0aDtxKyspe3ZhciBIPXQuZGVmaW5pdGlvbnNbcV07c3dpdGNoKEgua2luZCl7Y2FzZSBDLk9CSkVDVF9UWVBFX0RFRklOSVRJT046Y2FzZSBDLklOVEVSRkFDRV9UWVBFX0RFRklOSVRJT046Y2FzZSBDLkVOVU1fVFlQRV9ERUZJTklUSU9OOmNhc2UgQy5VTklPTl9UWVBFX0RFRklOSVRJT046Y2FzZSBDLlNDQUxBUl9UWVBFX0RFRklOSVRJT046Y2FzZSBDLklOUFVUX09CSkVDVF9UWVBFX0RFRklOSVRJT046dmFyIFc9SC5uYW1lLnZhbHVlO2lmKGUuZ2V0VHlwZShXKSl0aHJvdyBuZXcgaC5HcmFwaFFMRXJyb3IoJ1R5cGUgIicrVysnIiBhbHJlYWR5IGV4aXN0cyBpbiB0aGUgc2NoZW1hLiBJdCBjYW5ub3QgYWxzbyBiZSBkZWZpbmVkIGluIHRoaXMgdHlwZSBkZWZpbml0aW9uLicsW0hdKTt6W1ddPUg7YnJlYWs7Y2FzZSBDLlRZUEVfRVhURU5TSU9OX0RFRklOSVRJT046dmFyIFE9SC5kZWZpbml0aW9uLm5hbWUudmFsdWUsSz1lLmdldFR5cGUoUSk7aWYoIUspdGhyb3cgbmV3IGguR3JhcGhRTEVycm9yKCdDYW5ub3QgZXh0ZW5kIHR5cGUgIicrUSsnIiBiZWNhdXNlIGl0IGRvZXMgbm90IGV4aXN0IGluIHRoZSBleGlzdGluZyBzY2hlbWEuJyxbSC5kZWZpbml0aW9uXSk7aWYoIShLIGluc3RhbmNlb2YgZy5HcmFwaFFMT2JqZWN0VHlwZSkpdGhyb3cgbmV3IGguR3JhcGhRTEVycm9yKCdDYW5ub3QgZXh0ZW5kIG5vbi1vYmplY3QgdHlwZSAiJytRKyciLicsW0guZGVmaW5pdGlvbl0pO3ZhciBKPUdbUV07Sj9KLnB1c2goSCk6Sj1bSF0sR1tRXT1KO2JyZWFrO2Nhc2UgQy5ESVJFQ1RJVkVfREVGSU5JVElPTjp2YXIgWT1ILm5hbWUudmFsdWU7aWYoZS5nZXREaXJlY3RpdmUoWSkpdGhyb3cgbmV3IGguR3JhcGhRTEVycm9yKCdEaXJlY3RpdmUgIicrWSsnIiBhbHJlYWR5IGV4aXN0cyBpbiB0aGUgc2NoZW1hLiBJdCBjYW5ub3QgYmUgcmVkZWZpbmVkLicsW0hdKTtWLnB1c2goSCl9fWlmKDA9PT1PYmplY3Qua2V5cyhHKS5sZW5ndGgmJjA9PT1PYmplY3Qua2V5cyh6KS5sZW5ndGgmJjA9PT1WLmxlbmd0aClyZXR1cm4gZTt2YXIgWD17U3RyaW5nOmIuR3JhcGhRTFN0cmluZyxJbnQ6Yi5HcmFwaFFMSW50LEZsb2F0OmIuR3JhcGhRTEZsb2F0LEJvb2xlYW46Yi5HcmFwaFFMQm9vbGVhbixJRDpiLkdyYXBoUUxJRCxfX1NjaGVtYTp2Ll9fU2NoZW1hLF9fRGlyZWN0aXZlOnYuX19EaXJlY3RpdmUsX19EaXJlY3RpdmVMb2NhdGlvbjp2Ll9fRGlyZWN0aXZlTG9jYXRpb24sX19UeXBlOnYuX19UeXBlLF9fRmllbGQ6di5fX0ZpZWxkLF9fSW5wdXRWYWx1ZTp2Ll9fSW5wdXRWYWx1ZSxfX0VudW1WYWx1ZTp2Ll9fRW51bVZhbHVlLF9fVHlwZUtpbmQ6di5fX1R5cGVLaW5kfSxaPW4oZS5nZXRRdWVyeVR5cGUoKSksZWU9ZS5nZXRNdXRhdGlvblR5cGUoKSx0ZT1lZT9uKGVlKTpudWxsLG5lPWUuZ2V0U3Vic2NyaXB0aW9uVHlwZSgpLHJlPW5lP24obmUpOm51bGwsaWU9ZS5nZXRUeXBlTWFwKCksb2U9T2JqZWN0LmtleXMoaWUpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gbihpZVtlXSl9KTtyZXR1cm4gT2JqZWN0LmtleXMoeikuZm9yRWFjaChmdW5jdGlvbihlKXtvZS5wdXNoKHIoeltlXSkpfSksbmV3IG0uR3JhcGhRTFNjaGVtYSh7cXVlcnk6WixtdXRhdGlvbjp0ZSxzdWJzY3JpcHRpb246cmUsdHlwZXM6b2UsZGlyZWN0aXZlczpmdW5jdGlvbigpe3ZhciB0PWUuZ2V0RGlyZWN0aXZlcygpO3R8fCgwLHMuZGVmYXVsdCkoMCwic2NoZW1hIG11c3QgaGF2ZSBkZWZhdWx0IGRpcmVjdGl2ZXMiKTt2YXIgbj1WLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gTShlKX0pO3JldHVybiB0LmNvbmNhdChuKX0oKSxhc3ROb2RlOmUuYXN0Tm9kZX0pfWZ1bmN0aW9uIG8oKXt0aHJvdyBuZXcgRXJyb3IoIkV4dGVuZGVkIFNjaGVtYSBjYW5ub3QgdXNlIEludGVyZmFjZSBvciBVbmlvbiB0eXBlcyBmb3IgZXhlY3V0aW9uLiIpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmV4dGVuZFNjaGVtYT1pO3ZhciBhPW4oMTMpLHM9cihhKSx1PW4oNDYpLGM9cih1KSxsPW4oMTIwKSxwPXIobCksZj1uKDIwOCksZD1uKDU5KSxoPW4oNDMpLG09bigyNiksZz1uKDYpLHk9bigyNyksdj1uKDI4KSxiPW4oMzIpLHg9bigxMCksQz1mdW5jdGlvbihlKXtpZihlJiZlLl9fZXNNb2R1bGUpcmV0dXJuIGU7dmFyIHQ9e307aWYobnVsbCE9ZSlmb3IodmFyIG4gaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxuKSYmKHRbbl09ZVtuXSk7cmV0dXJuIHQuZGVmYXVsdD1lLHR9KHgpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSl7cmV0dXJuIGwoZSxmdW5jdGlvbihlKXtyZXR1cm4hYShlKX0scyl9ZnVuY3Rpb24gbyhlKXtyZXR1cm4gbChlLGEsdSl9ZnVuY3Rpb24gYShlKXtyZXR1cm4ic2tpcCI9PT1lfHwiaW5jbHVkZSI9PT1lfHwiZGVwcmVjYXRlZCI9PT1lfWZ1bmN0aW9uIHMoZSl7cmV0dXJuIXUoZSkmJiFjKGUpfWZ1bmN0aW9uIHUoZSl7cmV0dXJuIDA9PT1lLmluZGV4T2YoIl9fIil9ZnVuY3Rpb24gYyhlKXtyZXR1cm4iU3RyaW5nIj09PWV8fCJCb29sZWFuIj09PWV8fCJJbnQiPT09ZXx8IkZsb2F0Ij09PWV8fCJJRCI9PT1lfWZ1bmN0aW9uIGwoZSx0LG4pe3ZhciByPWUuZ2V0RGlyZWN0aXZlcygpLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gdChlLm5hbWUpfSksaT1lLmdldFR5cGVNYXAoKSxvPU9iamVjdC5rZXlzKGkpLmZpbHRlcihuKS5zb3J0KGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUubG9jYWxlQ29tcGFyZSh0KX0pLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gaVtlXX0pO3JldHVybltwKGUpXS5jb25jYXQoci5tYXAodyksby5tYXAoZCkpLmZpbHRlcihCb29sZWFuKS5qb2luKCJcblxuIikrIlxuIn1mdW5jdGlvbiBwKGUpe2lmKCFmKGUpKXt2YXIgdD1bXSxuPWUuZ2V0UXVlcnlUeXBlKCk7biYmdC5wdXNoKCIgIHF1ZXJ5OiAiK24ubmFtZSk7dmFyIHI9ZS5nZXRNdXRhdGlvblR5cGUoKTtyJiZ0LnB1c2goIiAgbXV0YXRpb246ICIrci5uYW1lKTt2YXIgaT1lLmdldFN1YnNjcmlwdGlvblR5cGUoKTtyZXR1cm4gaSYmdC5wdXNoKCIgIHN1YnNjcmlwdGlvbjogIitpLm5hbWUpLCJzY2hlbWEge1xuIit0LmpvaW4oIlxuIikrIlxufSJ9fWZ1bmN0aW9uIGYoZSl7dmFyIHQ9ZS5nZXRRdWVyeVR5cGUoKTtpZih0JiYiUXVlcnkiIT09dC5uYW1lKXJldHVybiExO3ZhciBuPWUuZ2V0TXV0YXRpb25UeXBlKCk7aWYobiYmIk11dGF0aW9uIiE9PW4ubmFtZSlyZXR1cm4hMTt2YXIgcj1lLmdldFN1YnNjcmlwdGlvblR5cGUoKTtyZXR1cm4hcnx8IlN1YnNjcmlwdGlvbiI9PT1yLm5hbWV9ZnVuY3Rpb24gZChlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIE0uR3JhcGhRTFNjYWxhclR5cGU/aChlKTplIGluc3RhbmNlb2YgTS5HcmFwaFFMT2JqZWN0VHlwZT9tKGUpOmUgaW5zdGFuY2VvZiBNLkdyYXBoUUxJbnRlcmZhY2VUeXBlP2coZSk6ZSBpbnN0YW5jZW9mIE0uR3JhcGhRTFVuaW9uVHlwZT95KGUpOmUgaW5zdGFuY2VvZiBNLkdyYXBoUUxFbnVtVHlwZT92KGUpOihlIGluc3RhbmNlb2YgTS5HcmFwaFFMSW5wdXRPYmplY3RUeXBlfHwoMCxULmRlZmF1bHQpKDApLHgoZSkpfWZ1bmN0aW9uIGgoZSl7cmV0dXJuIGsoZSkrInNjYWxhciAiK2UubmFtZX1mdW5jdGlvbiBtKGUpe3ZhciB0PWUuZ2V0SW50ZXJmYWNlcygpLG49dC5sZW5ndGg/IiBpbXBsZW1lbnRzICIrdC5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZX0pLmpvaW4oIiwgIik6IiI7cmV0dXJuIGsoZSkrInR5cGUgIitlLm5hbWUrbisiIHtcbiIrQyhlKSsiXG59In1mdW5jdGlvbiBnKGUpe3JldHVybiBrKGUpKyJpbnRlcmZhY2UgIitlLm5hbWUrIiB7XG4iK0MoZSkrIlxufSJ9ZnVuY3Rpb24geShlKXtyZXR1cm4gayhlKSsidW5pb24gIitlLm5hbWUrIiA9ICIrZS5nZXRUeXBlcygpLmpvaW4oIiB8ICIpfWZ1bmN0aW9uIHYoZSl7cmV0dXJuIGsoZSkrImVudW0gIitlLm5hbWUrIiB7XG4iK2IoZS5nZXRWYWx1ZXMoKSkrIlxufSJ9ZnVuY3Rpb24gYihlKXtyZXR1cm4gZS5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4gayhlLCIgICIsIXQpKyIgICIrZS5uYW1lK1MoZSl9KS5qb2luKCJcbiIpfWZ1bmN0aW9uIHgoZSl7dmFyIHQ9ZS5nZXRGaWVsZHMoKSxuPU9iamVjdC5rZXlzKHQpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gdFtlXX0pO3JldHVybiBrKGUpKyJpbnB1dCAiK2UubmFtZSsiIHtcbiIrbi5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4gayhlLCIgICIsIXQpKyIgICIrRChlKX0pLmpvaW4oIlxuIikrIlxufSJ9ZnVuY3Rpb24gQyhlKXt2YXIgdD1lLmdldEZpZWxkcygpO3JldHVybiBPYmplY3Qua2V5cyh0KS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIHRbZV19KS5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4gayhlLCIgICIsIXQpKyIgICIrZS5uYW1lK0UoZS5hcmdzLCIgICIpKyI6ICIrU3RyaW5nKGUudHlwZSkrUyhlKX0pLmpvaW4oIlxuIil9ZnVuY3Rpb24gRShlKXt2YXIgdD1hcmd1bWVudHMubGVuZ3RoPjEmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXT9hcmd1bWVudHNbMV06IiI7cmV0dXJuIDA9PT1lLmxlbmd0aD8iIjplLmV2ZXJ5KGZ1bmN0aW9uKGUpe3JldHVybiFlLmRlc2NyaXB0aW9ufSk/IigiK2UubWFwKEQpLmpvaW4oIiwgIikrIikiOiIoXG4iK2UubWFwKGZ1bmN0aW9uKGUsbil7cmV0dXJuIGsoZSwiICAiK3QsIW4pKyIgICIrdCtEKGUpfSkuam9pbigiXG4iKSsiXG4iK3QrIikifWZ1bmN0aW9uIEQoZSl7dmFyIHQ9ZS5uYW1lKyI6ICIrU3RyaW5nKGUudHlwZSk7cmV0dXJuKDAsSS5kZWZhdWx0KShlLmRlZmF1bHRWYWx1ZSl8fCh0Kz0iID0gIisoMCxQLnByaW50KSgoMCxMLmFzdEZyb21WYWx1ZSkoZS5kZWZhdWx0VmFsdWUsZS50eXBlKSkpLHR9ZnVuY3Rpb24gdyhlKXtyZXR1cm4gayhlKSsiZGlyZWN0aXZlIEAiK2UubmFtZStFKGUuYXJncykrIiBvbiAiK2UubG9jYXRpb25zLmpvaW4oIiB8ICIpfWZ1bmN0aW9uIFMoZSl7dmFyIHQ9ZS5kZXByZWNhdGlvblJlYXNvbjtyZXR1cm4oMCxGLmRlZmF1bHQpKHQpPyIiOiIiPT09dHx8dD09PVIuREVGQVVMVF9ERVBSRUNBVElPTl9SRUFTT04/IiBAZGVwcmVjYXRlZCI6IiBAZGVwcmVjYXRlZChyZWFzb246ICIrKDAsUC5wcmludCkoKDAsTC5hc3RGcm9tVmFsdWUpKHQsai5HcmFwaFFMU3RyaW5nKSkrIikifWZ1bmN0aW9uIGsoZSl7dmFyIHQ9YXJndW1lbnRzLmxlbmd0aD4xJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0/YXJndW1lbnRzWzFdOiIiLG49IShhcmd1bWVudHMubGVuZ3RoPjImJnZvaWQgMCE9PWFyZ3VtZW50c1syXSl8fGFyZ3VtZW50c1syXTtpZighZS5kZXNjcmlwdGlvbilyZXR1cm4iIjtmb3IodmFyIHI9ZS5kZXNjcmlwdGlvbi5zcGxpdCgiXG4iKSxpPXQmJiFuPyJcbiI6IiIsbz0wO288ci5sZW5ndGg7bysrKWlmKCIiPT09cltvXSlpKz10KyIjXG4iO2Vsc2UgZm9yKHZhciBhPUEocltvXSwxMjAtdC5sZW5ndGgpLHM9MDtzPGEubGVuZ3RoO3MrKylpKz10KyIjICIrYVtzXSsiXG4iO3JldHVybiBpfWZ1bmN0aW9uIEEoZSx0KXtpZihlLmxlbmd0aDx0KzUpcmV0dXJuW2VdO3ZhciBuPWUuc3BsaXQobmV3IFJlZ0V4cCgiKCg/OiB8XikuezE1LCIrKHQtNDApKyJ9KD89IHwkKSkiKSk7aWYobi5sZW5ndGg8NClyZXR1cm5bZV07Zm9yKHZhciByPVtuWzBdK25bMV0rblsyXV0saT0zO2k8bi5sZW5ndGg7aSs9MilyLnB1c2gobltpXS5zbGljZSgxKStuW2krMV0pO3JldHVybiByfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnByaW50U2NoZW1hPWksdC5wcmludEludHJvc3BlY3Rpb25TY2hlbWE9byx0LnByaW50VHlwZT1kO3ZhciBfPW4oMTMpLFQ9cihfKSxPPW4oMzUpLEY9cihPKSxOPW4oNTgpLEk9cihOKSxMPW4oMTEyKSxQPW4oMTkpLE09big2KSxqPW4oMzIpLFI9bigyNyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtmb3IodmFyIHQ9W10sbj0wO248ZS5sZW5ndGg7bisrKWZvcih2YXIgcj1lW25dLmRlZmluaXRpb25zLGk9MDtpPHIubGVuZ3RoO2krKyl0LnB1c2gocltpXSk7cmV0dXJue2tpbmQ6IkRvY3VtZW50IixkZWZpbml0aW9uczp0fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5jb25jYXRBU1Q9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PVtdLG49T2JqZWN0LmNyZWF0ZShudWxsKSxyPW5ldyBNYXAscz1PYmplY3QuY3JlYXRlKG51bGwpLHU9dm9pZCAwLGM9MDsoMCxhLnZpc2l0KShlLHtPcGVyYXRpb25EZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3U9aShlKSx0LnB1c2goZSksci5zZXQoZSxjKyspfSxGcmFnbWVudERlZmluaXRpb246ZnVuY3Rpb24oZSl7dT1lLm5hbWUudmFsdWUsblt1XT1lLHIuc2V0KGUsYysrKX0sRnJhZ21lbnRTcHJlYWQ6ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5uYW1lLnZhbHVlOyhzW3VdfHwoc1t1XT1PYmplY3QuY3JlYXRlKG51bGwpKSlbdF09ITB9fSk7dmFyIGw9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gdC5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWkoZSksYT1PYmplY3QuY3JlYXRlKG51bGwpO28oYSxzLHQpO3ZhciB1PVtlXTtPYmplY3Qua2V5cyhhKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3UucHVzaChuW2VdKX0pLHUuc29ydChmdW5jdGlvbihlLHQpe3JldHVybihyLmdldChlKXx8MCktKHIuZ2V0KHQpfHwwKX0pLGxbdF09e2tpbmQ6IkRvY3VtZW50IixkZWZpbml0aW9uczp1fX0pLGx9ZnVuY3Rpb24gaShlKXtyZXR1cm4gZS5uYW1lP2UubmFtZS52YWx1ZToiIn1mdW5jdGlvbiBvKGUsdCxuKXt2YXIgcj10W25dO3ImJk9iamVjdC5rZXlzKHIpLmZvckVhY2goZnVuY3Rpb24obil7ZVtuXXx8KGVbbl09ITAsbyhlLHQsbikpfSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuc2VwYXJhdGVPcGVyYXRpb25zPXI7dmFyIGE9big1Nyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybltdLmNvbmNhdChvKGUsdCksYShlLHQpLGMoZSx0KSxoKGUsdCksZyhlLHQpLHMoZSx0KS5icmVha2luZ0NoYW5nZXMsdihlLHQpKX1mdW5jdGlvbiBpKGUsdCl7cmV0dXJuW10uY29uY2F0KHMoZSx0KS5kYW5nZXJvdXNDaGFuZ2VzLHkoZSx0KSxtKGUsdCkpfWZ1bmN0aW9uIG8oZSx0KXt2YXIgbj1lLmdldFR5cGVNYXAoKSxyPXQuZ2V0VHlwZU1hcCgpLGk9W107cmV0dXJuIE9iamVjdC5rZXlzKG4pLmZvckVhY2goZnVuY3Rpb24oZSl7cltlXXx8aS5wdXNoKHt0eXBlOnguVFlQRV9SRU1PVkVELGRlc2NyaXB0aW9uOmUrIiB3YXMgcmVtb3ZlZC4ifSl9KSxpfWZ1bmN0aW9uIGEoZSx0KXt2YXIgbj1lLmdldFR5cGVNYXAoKSxyPXQuZ2V0VHlwZU1hcCgpLGk9W107cmV0dXJuIE9iamVjdC5rZXlzKG4pLmZvckVhY2goZnVuY3Rpb24oZSl7aWYocltlXSl7dmFyIHQ9bltlXSxvPXJbZV07dCBpbnN0YW5jZW9mIG8uY29uc3RydWN0b3J8fGkucHVzaCh7dHlwZTp4LlRZUEVfQ0hBTkdFRF9LSU5ELGRlc2NyaXB0aW9uOmUrIiBjaGFuZ2VkIGZyb20gIit1KHQpKyIgdG8gIit1KG8pKyIuIn0pfX0pLGl9ZnVuY3Rpb24gcyhlLHQpe3ZhciBuPWUuZ2V0VHlwZU1hcCgpLHI9dC5nZXRUeXBlTWFwKCksaT1bXSxvPVtdO3JldHVybiBPYmplY3Qua2V5cyhuKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PW5bZV0sYT1yW2VdO2lmKCh0IGluc3RhbmNlb2YgYi5HcmFwaFFMT2JqZWN0VHlwZXx8dCBpbnN0YW5jZW9mIGIuR3JhcGhRTEludGVyZmFjZVR5cGUpJiZhIGluc3RhbmNlb2YgdC5jb25zdHJ1Y3Rvcil7dmFyIHM9dC5nZXRGaWVsZHMoKSx1PWEuZ2V0RmllbGRzKCk7T2JqZWN0LmtleXMocykuZm9yRWFjaChmdW5jdGlvbihlKXt1W2VdJiYoc1tlXS5hcmdzLmZvckVhY2goZnVuY3Rpb24obil7dmFyIHI9dVtlXS5hcmdzLGE9ci5maW5kKGZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWU9PT1uLm5hbWV9KTtpZihhKXtkKG4udHlwZSxhLnR5cGUpP3ZvaWQgMCE9PW4uZGVmYXVsdFZhbHVlJiZuLmRlZmF1bHRWYWx1ZSE9PWEuZGVmYXVsdFZhbHVlJiZvLnB1c2goe3R5cGU6Qy5BUkdfREVGQVVMVF9WQUxVRV9DSEFOR0UsZGVzY3JpcHRpb246dC5uYW1lKyIuIitlKyIgYXJnICIrbi5uYW1lKyIgaGFzIGNoYW5nZWQgZGVmYXVsdFZhbHVlIn0pOmkucHVzaCh7dHlwZTp4LkFSR19DSEFOR0VEX0tJTkQsZGVzY3JpcHRpb246dC5uYW1lKyIuIitlKyIgYXJnICIrbi5uYW1lKyIgaGFzIGNoYW5nZWQgdHlwZSBmcm9tICIrbi50eXBlLnRvU3RyaW5nKCkrIiB0byAiK2EudHlwZS50b1N0cmluZygpfSl9ZWxzZSBpLnB1c2goe3R5cGU6eC5BUkdfUkVNT1ZFRCxkZXNjcmlwdGlvbjp0Lm5hbWUrIi4iK2UrIiBhcmcgIituLm5hbWUrIiB3YXMgcmVtb3ZlZCJ9KX0pLHVbZV0uYXJncy5mb3JFYWNoKGZ1bmN0aW9uKHQpeyFzW2VdLmFyZ3MuZmluZChmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lPT09dC5uYW1lfSkmJnQudHlwZSBpbnN0YW5jZW9mIGIuR3JhcGhRTE5vbk51bGwmJmkucHVzaCh7dHlwZTp4Lk5PTl9OVUxMX0FSR19BRERFRCxkZXNjcmlwdGlvbjoiQSBub24tbnVsbCBhcmcgIit0Lm5hbWUrIiBvbiAiK2EubmFtZSsiLiIrZSsiIHdhcyBhZGRlZCJ9KX0pKX0pfX0pLHticmVha2luZ0NoYW5nZXM6aSxkYW5nZXJvdXNDaGFuZ2VzOm99fWZ1bmN0aW9uIHUoZSl7aWYoZSBpbnN0YW5jZW9mIGIuR3JhcGhRTFNjYWxhclR5cGUpcmV0dXJuImEgU2NhbGFyIHR5cGUiO2lmKGUgaW5zdGFuY2VvZiBiLkdyYXBoUUxPYmplY3RUeXBlKXJldHVybiJhbiBPYmplY3QgdHlwZSI7aWYoZSBpbnN0YW5jZW9mIGIuR3JhcGhRTEludGVyZmFjZVR5cGUpcmV0dXJuImFuIEludGVyZmFjZSB0eXBlIjtpZihlIGluc3RhbmNlb2YgYi5HcmFwaFFMVW5pb25UeXBlKXJldHVybiJhIFVuaW9uIHR5cGUiO2lmKGUgaW5zdGFuY2VvZiBiLkdyYXBoUUxFbnVtVHlwZSlyZXR1cm4iYW4gRW51bSB0eXBlIjtpZihlIGluc3RhbmNlb2YgYi5HcmFwaFFMSW5wdXRPYmplY3RUeXBlKXJldHVybiJhbiBJbnB1dCB0eXBlIjt0aHJvdyBuZXcgVHlwZUVycm9yKCJVbmtub3duIHR5cGUgIitlLmNvbnN0cnVjdG9yLm5hbWUpfWZ1bmN0aW9uIGMoZSx0KXtyZXR1cm5bXS5jb25jYXQobChlLHQpLHAoZSx0KSl9ZnVuY3Rpb24gbChlLHQpe3ZhciBuPWUuZ2V0VHlwZU1hcCgpLHI9dC5nZXRUeXBlTWFwKCksaT1bXTtyZXR1cm4gT2JqZWN0LmtleXMobikuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1uW2VdLG89cltlXTtpZigodCBpbnN0YW5jZW9mIGIuR3JhcGhRTE9iamVjdFR5cGV8fHQgaW5zdGFuY2VvZiBiLkdyYXBoUUxJbnRlcmZhY2VUeXBlKSYmbyBpbnN0YW5jZW9mIHQuY29uc3RydWN0b3Ipe3ZhciBhPXQuZ2V0RmllbGRzKCkscz1vLmdldEZpZWxkcygpO09iamVjdC5rZXlzKGEpLmZvckVhY2goZnVuY3Rpb24odCl7aWYodCBpbiBzKXt2YXIgbj1hW3RdLnR5cGUscj1zW3RdLnR5cGU7aWYoIWYobixyKSl7dmFyIG89KDAsYi5pc05hbWVkVHlwZSkobik/bi5uYW1lOm4udG9TdHJpbmcoKSx1PSgwLGIuaXNOYW1lZFR5cGUpKHIpP3IubmFtZTpyLnRvU3RyaW5nKCk7aS5wdXNoKHt0eXBlOnguRklFTERfQ0hBTkdFRF9LSU5ELGRlc2NyaXB0aW9uOmUrIi4iK3QrIiBjaGFuZ2VkIHR5cGUgZnJvbSAiK28rIiB0byAiK3UrIi4ifSl9fWVsc2UgaS5wdXNoKHt0eXBlOnguRklFTERfUkVNT1ZFRCxkZXNjcmlwdGlvbjplKyIuIit0KyIgd2FzIHJlbW92ZWQuIn0pfSl9fSksaX1mdW5jdGlvbiBwKGUsdCl7dmFyIG49ZS5nZXRUeXBlTWFwKCkscj10LmdldFR5cGVNYXAoKSxpPVtdO3JldHVybiBPYmplY3Qua2V5cyhuKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PW5bZV0sbz1yW2VdO2lmKHQgaW5zdGFuY2VvZiBiLkdyYXBoUUxJbnB1dE9iamVjdFR5cGUmJm8gaW5zdGFuY2VvZiBiLkdyYXBoUUxJbnB1dE9iamVjdFR5cGUpe3ZhciBhPXQuZ2V0RmllbGRzKCkscz1vLmdldEZpZWxkcygpO09iamVjdC5rZXlzKGEpLmZvckVhY2goZnVuY3Rpb24odCl7aWYodCBpbiBzKXt2YXIgbj1hW3RdLnR5cGUscj1zW3RdLnR5cGU7aWYoIWQobixyKSl7dmFyIG89KDAsYi5pc05hbWVkVHlwZSkobik/bi5uYW1lOm4udG9TdHJpbmcoKSx1PSgwLGIuaXNOYW1lZFR5cGUpKHIpP3IubmFtZTpyLnRvU3RyaW5nKCk7aS5wdXNoKHt0eXBlOnguRklFTERfQ0hBTkdFRF9LSU5ELGRlc2NyaXB0aW9uOmUrIi4iK3QrIiBjaGFuZ2VkIHR5cGUgZnJvbSAiK28rIiB0byAiK3UrIi4ifSl9fWVsc2UgaS5wdXNoKHt0eXBlOnguRklFTERfUkVNT1ZFRCxkZXNjcmlwdGlvbjplKyIuIit0KyIgd2FzIHJlbW92ZWQuIn0pfSksT2JqZWN0LmtleXMocykuZm9yRWFjaChmdW5jdGlvbihlKXshKGUgaW4gYSkmJnNbZV0udHlwZSBpbnN0YW5jZW9mIGIuR3JhcGhRTE5vbk51bGwmJmkucHVzaCh7dHlwZTp4Lk5PTl9OVUxMX0lOUFVUX0ZJRUxEX0FEREVELGRlc2NyaXB0aW9uOiJBIG5vbi1udWxsIGZpZWxkICIrZSsiIG9uIGlucHV0IHR5cGUgIitvLm5hbWUrIiB3YXMgYWRkZWQuIn0pfSl9fSksaX1mdW5jdGlvbiBmKGUsdCl7cmV0dXJuKDAsYi5pc05hbWVkVHlwZSkoZSk/KDAsYi5pc05hbWVkVHlwZSkodCkmJmUubmFtZT09PXQubmFtZXx8dCBpbnN0YW5jZW9mIGIuR3JhcGhRTE5vbk51bGwmJmYoZSx0Lm9mVHlwZSk6ZSBpbnN0YW5jZW9mIGIuR3JhcGhRTExpc3Q/dCBpbnN0YW5jZW9mIGIuR3JhcGhRTExpc3QmJmYoZS5vZlR5cGUsdC5vZlR5cGUpfHx0IGluc3RhbmNlb2YgYi5HcmFwaFFMTm9uTnVsbCYmZihlLHQub2ZUeXBlKTplIGluc3RhbmNlb2YgYi5HcmFwaFFMTm9uTnVsbCYmKHQgaW5zdGFuY2VvZiBiLkdyYXBoUUxOb25OdWxsJiZmKGUub2ZUeXBlLHQub2ZUeXBlKSl9ZnVuY3Rpb24gZChlLHQpe3JldHVybigwLGIuaXNOYW1lZFR5cGUpKGUpPygwLGIuaXNOYW1lZFR5cGUpKHQpJiZlLm5hbWU9PT10Lm5hbWU6ZSBpbnN0YW5jZW9mIGIuR3JhcGhRTExpc3Q/dCBpbnN0YW5jZW9mIGIuR3JhcGhRTExpc3QmJmQoZS5vZlR5cGUsdC5vZlR5cGUpOmUgaW5zdGFuY2VvZiBiLkdyYXBoUUxOb25OdWxsJiYodCBpbnN0YW5jZW9mIGIuR3JhcGhRTE5vbk51bGwmJmQoZS5vZlR5cGUsdC5vZlR5cGUpfHwhKHQgaW5zdGFuY2VvZiBiLkdyYXBoUUxOb25OdWxsKSYmZChlLm9mVHlwZSx0KSl9ZnVuY3Rpb24gaChlLHQpe3ZhciBuPWUuZ2V0VHlwZU1hcCgpLHI9dC5nZXRUeXBlTWFwKCksaT1bXTtyZXR1cm4gT2JqZWN0LmtleXMobikuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1uW2VdLG89cltlXTtpZih0IGluc3RhbmNlb2YgYi5HcmFwaFFMVW5pb25UeXBlJiZvIGluc3RhbmNlb2YgYi5HcmFwaFFMVW5pb25UeXBlKXt2YXIgYT1PYmplY3QuY3JlYXRlKG51bGwpO28uZ2V0VHlwZXMoKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2FbZS5uYW1lXT0hMH0pLHQuZ2V0VHlwZXMoKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe2FbdC5uYW1lXXx8aS5wdXNoKHt0eXBlOnguVFlQRV9SRU1PVkVEX0ZST01fVU5JT04sZGVzY3JpcHRpb246dC5uYW1lKyIgd2FzIHJlbW92ZWQgZnJvbSB1bmlvbiB0eXBlICIrZSsiLiJ9KX0pfX0pLGl9ZnVuY3Rpb24gbShlLHQpe3ZhciBuPWUuZ2V0VHlwZU1hcCgpLHI9dC5nZXRUeXBlTWFwKCksaT1bXTtyZXR1cm4gT2JqZWN0LmtleXMocikuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1uW2VdLG89cltlXTtpZih0IGluc3RhbmNlb2YgYi5HcmFwaFFMVW5pb25UeXBlJiZvIGluc3RhbmNlb2YgYi5HcmFwaFFMVW5pb25UeXBlKXt2YXIgYT1PYmplY3QuY3JlYXRlKG51bGwpO3QuZ2V0VHlwZXMoKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2FbZS5uYW1lXT0hMH0pLG8uZ2V0VHlwZXMoKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe2FbdC5uYW1lXXx8aS5wdXNoKHt0eXBlOkMuVFlQRV9BRERFRF9UT19VTklPTixkZXNjcmlwdGlvbjp0Lm5hbWUrIiB3YXMgYWRkZWQgdG8gdW5pb24gdHlwZSAiK2UrIi4ifSl9KX19KSxpfWZ1bmN0aW9uIGcoZSx0KXt2YXIgbj1lLmdldFR5cGVNYXAoKSxyPXQuZ2V0VHlwZU1hcCgpLGk9W107cmV0dXJuIE9iamVjdC5rZXlzKG4pLmZvckVhY2goZnVuY3Rpb24oZSl7dmFyIHQ9bltlXSxvPXJbZV07aWYodCBpbnN0YW5jZW9mIGIuR3JhcGhRTEVudW1UeXBlJiZvIGluc3RhbmNlb2YgYi5HcmFwaFFMRW51bVR5cGUpe3ZhciBhPU9iamVjdC5jcmVhdGUobnVsbCk7by5nZXRWYWx1ZXMoKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2FbZS5uYW1lXT0hMH0pLHQuZ2V0VmFsdWVzKCkuZm9yRWFjaChmdW5jdGlvbih0KXthW3QubmFtZV18fGkucHVzaCh7dHlwZTp4LlZBTFVFX1JFTU9WRURfRlJPTV9FTlVNLGRlc2NyaXB0aW9uOnQubmFtZSsiIHdhcyByZW1vdmVkIGZyb20gZW51bSB0eXBlICIrZSsiLiJ9KX0pfX0pLGl9ZnVuY3Rpb24geShlLHQpe3ZhciBuPWUuZ2V0VHlwZU1hcCgpLHI9dC5nZXRUeXBlTWFwKCksaT1bXTtyZXR1cm4gT2JqZWN0LmtleXMobikuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1uW2VdLG89cltlXTtpZih0IGluc3RhbmNlb2YgYi5HcmFwaFFMRW51bVR5cGUmJm8gaW5zdGFuY2VvZiBiLkdyYXBoUUxFbnVtVHlwZSl7dmFyIGE9T2JqZWN0LmNyZWF0ZShudWxsKTt0LmdldFZhbHVlcygpLmZvckVhY2goZnVuY3Rpb24oZSl7YVtlLm5hbWVdPSEwfSksby5nZXRWYWx1ZXMoKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe2FbdC5uYW1lXXx8aS5wdXNoKHt0eXBlOkMuVkFMVUVfQURERURfVE9fRU5VTSxkZXNjcmlwdGlvbjp0Lm5hbWUrIiB3YXMgYWRkZWQgdG8gZW51bSB0eXBlICIrZSsiLiJ9KX0pfX0pLGl9ZnVuY3Rpb24gdihlLHQpe3ZhciBuPWUuZ2V0VHlwZU1hcCgpLHI9dC5nZXRUeXBlTWFwKCksaT1bXTtyZXR1cm4gT2JqZWN0LmtleXMobikuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1uW2VdLG89cltlXTtpZih0IGluc3RhbmNlb2YgYi5HcmFwaFFMT2JqZWN0VHlwZSYmbyBpbnN0YW5jZW9mIGIuR3JhcGhRTE9iamVjdFR5cGUpe3ZhciBhPXQuZ2V0SW50ZXJmYWNlcygpLHM9by5nZXRJbnRlcmZhY2VzKCk7YS5mb3JFYWNoKGZ1bmN0aW9uKHQpe3Muc29tZShmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lPT09dC5uYW1lfSl8fGkucHVzaCh7dHlwZTp4LklOVEVSRkFDRV9SRU1PVkVEX0ZST01fT0JKRUNULGRlc2NyaXB0aW9uOmUrIiBubyBsb25nZXIgaW1wbGVtZW50cyBpbnRlcmZhY2UgIit0Lm5hbWUrIi4ifSl9KX19KSxpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LkRhbmdlcm91c0NoYW5nZVR5cGU9dC5CcmVha2luZ0NoYW5nZVR5cGU9dm9pZCAwLHQuZmluZEJyZWFraW5nQ2hhbmdlcz1yLHQuZmluZERhbmdlcm91c0NoYW5nZXM9aSx0LmZpbmRSZW1vdmVkVHlwZXM9byx0LmZpbmRUeXBlc1RoYXRDaGFuZ2VkS2luZD1hLHQuZmluZEFyZ0NoYW5nZXM9cyx0LmZpbmRGaWVsZHNUaGF0Q2hhbmdlZFR5cGU9Yyx0LmZpbmRGaWVsZHNUaGF0Q2hhbmdlZFR5cGVPbklucHV0T2JqZWN0VHlwZXM9cCx0LmZpbmRUeXBlc1JlbW92ZWRGcm9tVW5pb25zPWgsdC5maW5kVHlwZXNBZGRlZFRvVW5pb25zPW0sdC5maW5kVmFsdWVzUmVtb3ZlZEZyb21FbnVtcz1nLHQuZmluZFZhbHVlc0FkZGVkVG9FbnVtcz15LHQuZmluZEludGVyZmFjZXNSZW1vdmVkRnJvbU9iamVjdFR5cGVzPXY7dmFyIGI9big2KSx4PShuKDI2KSx0LkJyZWFraW5nQ2hhbmdlVHlwZT17RklFTERfQ0hBTkdFRF9LSU5EOiJGSUVMRF9DSEFOR0VEX0tJTkQiLEZJRUxEX1JFTU9WRUQ6IkZJRUxEX1JFTU9WRUQiLFRZUEVfQ0hBTkdFRF9LSU5EOiJUWVBFX0NIQU5HRURfS0lORCIsVFlQRV9SRU1PVkVEOiJUWVBFX1JFTU9WRUQiLFRZUEVfUkVNT1ZFRF9GUk9NX1VOSU9OOiJUWVBFX1JFTU9WRURfRlJPTV9VTklPTiIsVkFMVUVfUkVNT1ZFRF9GUk9NX0VOVU06IlZBTFVFX1JFTU9WRURfRlJPTV9FTlVNIixBUkdfUkVNT1ZFRDoiQVJHX1JFTU9WRUQiLEFSR19DSEFOR0VEX0tJTkQ6IkFSR19DSEFOR0VEX0tJTkQiLE5PTl9OVUxMX0FSR19BRERFRDoiTk9OX05VTExfQVJHX0FEREVEIixOT05fTlVMTF9JTlBVVF9GSUVMRF9BRERFRDoiTk9OX05VTExfSU5QVVRfRklFTERfQURERUQiLElOVEVSRkFDRV9SRU1PVkVEX0ZST01fT0JKRUNUOiJJTlRFUkZBQ0VfUkVNT1ZFRF9GUk9NX09CSkVDVCJ9KSxDPXQuRGFuZ2Vyb3VzQ2hhbmdlVHlwZT17QVJHX0RFRkFVTFRfVkFMVUVfQ0hBTkdFOiJBUkdfREVGQVVMVF9WQUxVRV9DSEFOR0UiLFZBTFVFX0FEREVEX1RPX0VOVU06IlZBTFVFX0FEREVEX1RPX0VOVU0iLFRZUEVfQURERURfVE9fVU5JT046IlRZUEVfQURERURfVE9fVU5JT04ifX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dmFyIG49W10scj1uZXcgcy5UeXBlSW5mbyhlKTtyZXR1cm4oMCxvLnZpc2l0KSh0LCgwLG8udmlzaXRXaXRoVHlwZUluZm8pKHIse0ZpZWxkOmZ1bmN0aW9uKGUpe3ZhciB0PXIuZ2V0RmllbGREZWYoKTtpZih0JiZ0LmlzRGVwcmVjYXRlZCl7dmFyIG89ci5nZXRQYXJlbnRUeXBlKCk7aWYobyl7dmFyIGE9dC5kZXByZWNhdGlvblJlYXNvbjtuLnB1c2gobmV3IGkuR3JhcGhRTEVycm9yKCJUaGUgZmllbGQgIitvLm5hbWUrIi4iK3QubmFtZSsiIGlzIGRlcHJlY2F0ZWQuIisoYT8iICIrYToiIiksW2VdKSl9fX0sRW51bVZhbHVlOmZ1bmN0aW9uKGUpe3ZhciB0PXIuZ2V0RW51bVZhbHVlKCk7aWYodCYmdC5pc0RlcHJlY2F0ZWQpe3ZhciBvPSgwLGEuZ2V0TmFtZWRUeXBlKShyLmdldElucHV0VHlwZSgpKTtpZihvKXt2YXIgcz10LmRlcHJlY2F0aW9uUmVhc29uO24ucHVzaChuZXcgaS5HcmFwaFFMRXJyb3IoIlRoZSBlbnVtIHZhbHVlICIrby5uYW1lKyIuIit0Lm5hbWUrIiBpcyBkZXByZWNhdGVkLiIrKHM/IiAiK3M6IiIpLFtlXSkpfX19fSkpLG59T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZmluZERlcHJlY2F0ZWRVc2FnZXM9cjt2YXIgaT1uKDQzKSxvPW4oNTcpLGE9big2KSxzPShuKDI2KSxuKDExMykpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIE9iamVjdChhLmEpKGUpfHxPYmplY3Qocy5hKShlKXx8T2JqZWN0KGwuYSkoZSl9ZnVuY3Rpb24gaShlKXtyZXR1cm4hT2JqZWN0KHUuYSkoZSkmJmUuZXZlcnkocil9ZnVuY3Rpb24gbygpe2Zvcih2YXIgZT1hcmd1bWVudHMubGVuZ3RoLHQ9QXJyYXkoZSksbj0wO248ZTtuKyspdFtuXT1hcmd1bWVudHNbbl07ZigpKGkodCksIkV4cGVjdGVkIGFjdGlvbiB0eXBlcyB0byBiZSBzdHJpbmdzLCBzeW1ib2xzLCBvciBhY3Rpb24gY3JlYXRvcnMiKTt2YXIgcj10Lm1hcChjLmEpLmpvaW4oZC5hKTtyZXR1cm57dG9TdHJpbmc6ZnVuY3Rpb24oKXtyZXR1cm4gcn19fXQuYT1vO3ZhciBhPW4oMTIxKSxzPW4oNDgpLHU9bigyMDkpLGM9big2MSksbD1uKDEyMykscD1uKDIwKSxmPW4ubihwKSxkPW4oNjIpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oMTY1KSxpPU9iamVjdChyLmEpKE9iamVjdC5rZXlzLE9iamVjdCk7dC5hPWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0OSksaT1uKDIxKSxvPU9iamVjdChyLmEpKGkuYSwiRGF0YVZpZXciKTt0LmE9b30sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiEoIU9iamVjdChhLmEpKGUpfHxPYmplY3Qoby5hKShlKSkmJihPYmplY3QoaS5hKShlKT9oOmMpLnRlc3QoT2JqZWN0KHMuYSkoZSkpfXZhciBpPW4oNDgpLG89big0MTMpLGE9big2MCkscz1uKDIxMyksdT0vW1xcXiQuKis/KClbXF17fXxdL2csYz0vXlxbb2JqZWN0IC4rP0NvbnN0cnVjdG9yXF0kLyxsPUZ1bmN0aW9uLnByb3RvdHlwZSxwPU9iamVjdC5wcm90b3R5cGUsZj1sLnRvU3RyaW5nLGQ9cC5oYXNPd25Qcm9wZXJ0eSxoPVJlZ0V4cCgiXiIrZi5jYWxsKGQpLnJlcGxhY2UodSwiXFwkJiIpLnJlcGxhY2UoL2hhc093blByb3BlcnR5fChmdW5jdGlvbikuKj8oPz1cXFwoKXwgZm9yIC4rPyg/PVxcXF0pL2csIiQxLio/IikrIiQiKTt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiEhbyYmbyBpbiBlfXZhciBpPW4oNDE0KSxvPWZ1bmN0aW9uKCl7dmFyIGU9L1teLl0rJC8uZXhlYyhpLmEmJmkuYS5rZXlzJiZpLmEua2V5cy5JRV9QUk9UT3x8IiIpO3JldHVybiBlPyJTeW1ib2woc3JjKV8xLiIrZToiIn0oKTt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDIxKSxpPXIuYVsiX19jb3JlLWpzX3NoYXJlZF9fIl07dC5hPWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybiBudWxsPT1lP3ZvaWQgMDplW3RdfXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNDkpLGk9bigyMSksbz1PYmplY3Qoci5hKShpLmEsIk1hcCIpO3QuYT1vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNDkpLGk9bigyMSksbz1PYmplY3Qoci5hKShpLmEsIlByb21pc2UiKTt0LmE9b30sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDQ5KSxpPW4oMjEpLG89T2JqZWN0KHIuYSkoaS5hLCJTZXQiKTt0LmE9b30sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBPYmplY3Qoby5hKShlKSYmT2JqZWN0KGkuYSkoZSk9PWF9dmFyIGk9bigzMyksbz1uKDMxKSxhPSJbb2JqZWN0IEFyZ3VtZW50c10iO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXtyZXR1cm4hMX10LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBPYmplY3QoYS5hKShlKSYmT2JqZWN0KG8uYSkoZS5sZW5ndGgpJiYhIXNbT2JqZWN0KGkuYSkoZSldfXZhciBpPW4oMzMpLG89bigyMTYpLGE9bigzMSkscz17fTtzWyJbb2JqZWN0IEZsb2F0MzJBcnJheV0iXT1zWyJbb2JqZWN0IEZsb2F0NjRBcnJheV0iXT1zWyJbb2JqZWN0IEludDhBcnJheV0iXT1zWyJbb2JqZWN0IEludDE2QXJyYXldIl09c1siW29iamVjdCBJbnQzMkFycmF5XSJdPXNbIltvYmplY3QgVWludDhBcnJheV0iXT1zWyJbb2JqZWN0IFVpbnQ4Q2xhbXBlZEFycmF5XSJdPXNbIltvYmplY3QgVWludDE2QXJyYXldIl09c1siW29iamVjdCBVaW50MzJBcnJheV0iXT0hMCxzWyJbb2JqZWN0IEFyZ3VtZW50c10iXT1zWyJbb2JqZWN0IEFycmF5XSJdPXNbIltvYmplY3QgQXJyYXlCdWZmZXJdIl09c1siW29iamVjdCBCb29sZWFuXSJdPXNbIltvYmplY3QgRGF0YVZpZXddIl09c1siW29iamVjdCBEYXRlXSJdPXNbIltvYmplY3QgRXJyb3JdIl09c1siW29iamVjdCBGdW5jdGlvbl0iXT1zWyJbb2JqZWN0IE1hcF0iXT1zWyJbb2JqZWN0IE51bWJlcl0iXT1zWyJbb2JqZWN0IE9iamVjdF0iXT1zWyJbb2JqZWN0IFJlZ0V4cF0iXT1zWyJbb2JqZWN0IFNldF0iXT1zWyJbb2JqZWN0IFN0cmluZ10iXT1zWyJbb2JqZWN0IFdlYWtNYXBdIl09ITEsdC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZigic3RyaW5nIj09dHlwZW9mIGUpcmV0dXJuIGU7aWYoT2JqZWN0KGEuYSkoZSkpcmV0dXJuIE9iamVjdChvLmEpKGUscikrIiI7aWYoT2JqZWN0KHMuYSkoZSkpcmV0dXJuIGw/bC5jYWxsKGUpOiIiO3ZhciB0PWUrIiI7cmV0dXJuIjAiPT10JiYxL2U9PS11PyItMCI6dH12YXIgaT1uKDEwMyksbz1uKDIyMSksYT1uKDQ3KSxzPW4oMTIzKSx1PTEvMCxjPWkuYT9pLmEucHJvdG90eXBlOnZvaWQgMCxsPWM/Yy50b1N0cmluZzp2b2lkIDA7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gbnVsbD09PWV9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuIHQgaW4gZT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0LHt2YWx1ZTpuLGVudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiEwLHdyaXRhYmxlOiEwfSk6ZVt0XT1uLGV9ZnVuY3Rpb24gaShlKXtpZihBcnJheS5pc0FycmF5KGUpKXtmb3IodmFyIHQ9MCxuPUFycmF5KGUubGVuZ3RoKTt0PGUubGVuZ3RoO3QrKyluW3RdPWVbdF07cmV0dXJuIG59cmV0dXJuIEFycmF5LmZyb20oZSl9ZnVuY3Rpb24gbyhlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPUFycmF5KHQ+MT90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTt2YXIgaT1PYmplY3QobC5hKShPYmplY3QoZi5hKShuKSk/bi5wb3AoKTp7fTtyZXR1cm4geSgpKG4uZXZlcnkoZC5hKSYmKE9iamVjdChkLmEpKGUpfHxPYmplY3QobC5hKShlKSksIkV4cGVjdGVkIG9wdGlvbmFsIG9iamVjdCBmb2xsb3dlZCBieSBzdHJpbmcgYWN0aW9uIHR5cGVzIiksT2JqZWN0KGQuYSkoZSk/dShbZV0uY29uY2F0KG4pLGkpOlMoe30sYShlLGkpLHUobixpKSl9ZnVuY3Rpb24gYShlLHQpe3ZhciBuPU9iamVjdCh4LmEpKGUsdCkscj1zKG4pO3JldHVybiBPYmplY3QoQy5hKShyLHQpfWZ1bmN0aW9uIHMoZSl7ZnVuY3Rpb24gdChlKXtpZihPYmplY3QoaC5hKShlKXx8T2JqZWN0KG0uYSkoZSkpcmV0dXJuITA7aWYoT2JqZWN0KHAuYSkoZSkpe3ZhciB0PXcoZSwyKSxuPXRbMF0scj12b2lkIDA9PT1uP2MuYTpuLGk9dFsxXTtyZXR1cm4gT2JqZWN0KGguYSkocikmJk9iamVjdChoLmEpKGkpfXJldHVybiExfXZhciBuPWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7fSxvPW4ucHJlZml4LGE9bi5uYW1lc3BhY2Uscz12b2lkIDA9PT1hP0QuYjphO3JldHVybiBPYmplY3QoYi5hKShPYmplY3Qua2V5cyhlKSxmdW5jdGlvbihuLGEpe3ZhciB1PWVbYV07eSgpKHQodSksIkV4cGVjdGVkIGZ1bmN0aW9uLCB1bmRlZmluZWQsIG51bGwsIG9yIGFycmF5IHdpdGggcGF5bG9hZCBhbmQgbWV0YSBmdW5jdGlvbnMgZm9yICIrYSk7dmFyIGM9bz8iIitvK3MrYTphLGw9T2JqZWN0KHAuYSkodSk/RS5hLmFwcGx5KHZvaWQgMCxbY10uY29uY2F0KGkodSkpKTpPYmplY3QoRS5hKShjLHUpO3JldHVybiBTKHt9LG4scih7fSxhLGwpKX0pfWZ1bmN0aW9uIHUoZSx0KXt2YXIgbj1PYmplY3QoYi5hKShlLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIFMoe30sZSxyKHt9LHQsYy5hKSl9KSxpPXMobix0KTtyZXR1cm4gT2JqZWN0KGIuYSkoT2JqZWN0LmtleXMoaSksZnVuY3Rpb24oZSx0KXtyZXR1cm4gUyh7fSxlLHIoe30sT2JqZWN0KHYuYSkodCksaVt0XSkpfSl9dC5hPW87dmFyIGM9big2MyksbD1uKDQxKSxwPW4oNDcpLGY9big0MjUpLGQ9bigxMjEpLGg9big0OCksbT1uKDIyMiksZz1uKDIwKSx5PW4ubihnKSx2PW4oMjIzKSxiPW4oNDQ0KSx4PW4oNDQ1KSxDPW4oNDQ3KSxFPW4oMTI0KSxEPW4oNjIpLHc9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dmFyIG49W10scj0hMCxpPSExLG89dm9pZCAwO3RyeXtmb3IodmFyIGEscz1lW1N5bWJvbC5pdGVyYXRvcl0oKTshKHI9KGE9cy5uZXh0KCkpLmRvbmUpJiYobi5wdXNoKGEudmFsdWUpLCF0fHxuLmxlbmd0aCE9PXQpO3I9ITApO31jYXRjaChlKXtpPSEwLG89ZX1maW5hbGx5e3RyeXshciYmcy5yZXR1cm4mJnMucmV0dXJuKCl9ZmluYWxseXtpZihpKXRocm93IG99fXJldHVybiBufXJldHVybiBmdW5jdGlvbih0LG4pe2lmKEFycmF5LmlzQXJyYXkodCkpcmV0dXJuIHQ7aWYoU3ltYm9sLml0ZXJhdG9yIGluIE9iamVjdCh0KSlyZXR1cm4gZSh0LG4pO3Rocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgYXR0ZW1wdCB0byBkZXN0cnVjdHVyZSBub24taXRlcmFibGUgaW5zdGFuY2UiKX19KCksUz1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PW51bGw9PWU/MDplLmxlbmd0aDtyZXR1cm4gdD9lW3QtMV06dm9pZCAwfXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNDI3KSxpPW4oNDM1KSxvPU9iamVjdChpLmEpKGZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gdD10LnRvTG93ZXJDYXNlKCksZSsobj9PYmplY3Qoci5hKSh0KTp0KX0pO3QuYT1vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIE9iamVjdChvLmEpKE9iamVjdChpLmEpKGUpLnRvTG93ZXJDYXNlKCkpfXZhciBpPW4oNjEpLG89big0MjgpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNDI5KSxpPU9iamVjdChyLmEpKCJ0b1VwcGVyQ2FzZSIpO3QuYT1pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3Q9T2JqZWN0KHMuYSkodCk7dmFyIG49T2JqZWN0KG8uYSkodCk/T2JqZWN0KGEuYSkodCk6dm9pZCAwLHI9bj9uWzBdOnQuY2hhckF0KDApLHU9bj9PYmplY3QoaS5hKShuLDEpLmpvaW4oIiIpOnQuc2xpY2UoMSk7cmV0dXJuIHJbZV0oKSt1fX12YXIgaT1uKDQzMCksbz1uKDIyNCksYT1uKDQzMikscz1uKDYxKTt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXt2YXIgcj1lLmxlbmd0aDtyZXR1cm4gbj12b2lkIDA9PT1uP3I6biwhdCYmbj49cj9lOk9iamVjdChpLmEpKGUsdCxuKX12YXIgaT1uKDQzMSk7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7dmFyIHI9LTEsaT1lLmxlbmd0aDt0PDAmJih0PS10Pmk/MDppK3QpLG49bj5pP2k6bixuPDAmJihuKz1pKSxpPXQ+bj8wOm4tdD4+PjAsdD4+Pj0wO2Zvcih2YXIgbz1BcnJheShpKTsrK3I8aTspb1tyXT1lW3IrdF07cmV0dXJuIG99dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gT2JqZWN0KG8uYSkoZSk/T2JqZWN0KGEuYSkoZSk6T2JqZWN0KGkuYSkoZSl9dmFyIGk9big0MzMpLG89bigyMjQpLGE9big0MzQpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUuc3BsaXQoIiIpfXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUubWF0Y2goZil8fFtdfXZhciBpPSJbXFx1MDMwMC1cXHUwMzZmXFx1ZmUyMC1cXHVmZTJmXFx1MjBkMC1cXHUyMGZmXSIsbz0iXFx1ZDgzY1tcXHVkZmZiLVxcdWRmZmZdIixhPSIoPzpcXHVkODNjW1xcdWRkZTYtXFx1ZGRmZl0pezJ9IixzPSJbXFx1ZDgwMC1cXHVkYmZmXVtcXHVkYzAwLVxcdWRmZmZdIix1PSIoPzpbXFx1MDMwMC1cXHUwMzZmXFx1ZmUyMC1cXHVmZTJmXFx1MjBkMC1cXHUyMGZmXXxcXHVkODNjW1xcdWRmZmItXFx1ZGZmZl0pPyIsYz0iKD86XFx1MjAwZCg/OiIrWyJbXlxcdWQ4MDAtXFx1ZGZmZl0iLGEsc10uam9pbigifCIpKyIpW1xcdWZlMGVcXHVmZTBmXT8iK3UrIikqIixsPSJbXFx1ZmUwZVxcdWZlMGZdPyIrdStjLHA9Iig/OiIrWyJbXlxcdWQ4MDAtXFx1ZGZmZl0iK2krIj8iLGksYSxzLCJbXFx1ZDgwMC1cXHVkZmZmXSJdLmpvaW4oInwiKSsiKSIsZj1SZWdFeHAobysiKD89IitvKyIpfCIrcCtsLCJnIik7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIE9iamVjdChpLmEpKE9iamVjdChhLmEpKE9iamVjdChvLmEpKHQpLnJlcGxhY2UocywiIikpLGUsIiIpfX12YXIgaT1uKDQzNiksbz1uKDQzNyksYT1uKDQ0MCkscz1SZWdFeHAoIlsnXHUyMDE5XSIsImciKTt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuLHIpe3ZhciBpPS0xLG89bnVsbD09ZT8wOmUubGVuZ3RoO2ZvcihyJiZvJiYobj1lWysraV0pOysraTxvOyluPXQobixlW2ldLGksZSk7cmV0dXJuIG59dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4oZT1PYmplY3Qoby5hKShlKSkmJmUucmVwbGFjZShhLGkuYSkucmVwbGFjZShzLCIiKX12YXIgaT1uKDQzOCksbz1uKDYxKSxhPS9bXHhjMC1ceGQ2XHhkOC1ceGY2XHhmOC1ceGZmXHUwMTAwLVx1MDE3Zl0vZyxzPVJlZ0V4cCgiW1xcdTAzMDAtXFx1MDM2ZlxcdWZlMjAtXFx1ZmUyZlxcdTIwZDAtXFx1MjBmZl0iLCJnIik7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0MzkpLGk9eyJceGMwIjoiQSIsIlx4YzEiOiJBIiwiXHhjMiI6IkEiLCJceGMzIjoiQSIsIlx4YzQiOiJBIiwiXHhjNSI6IkEiLCJceGUwIjoiYSIsIlx4ZTEiOiJhIiwiXHhlMiI6ImEiLCJceGUzIjoiYSIsIlx4ZTQiOiJhIiwiXHhlNSI6ImEiLCJceGM3IjoiQyIsIlx4ZTciOiJjIiwiXHhkMCI6IkQiLCJceGYwIjoiZCIsIlx4YzgiOiJFIiwiXHhjOSI6IkUiLCJceGNhIjoiRSIsIlx4Y2IiOiJFIiwiXHhlOCI6ImUiLCJceGU5IjoiZSIsIlx4ZWEiOiJlIiwiXHhlYiI6ImUiLCJceGNjIjoiSSIsIlx4Y2QiOiJJIiwiXHhjZSI6IkkiLCJceGNmIjoiSSIsIlx4ZWMiOiJpIiwiXHhlZCI6ImkiLCJceGVlIjoiaSIsIlx4ZWYiOiJpIiwiXHhkMSI6Ik4iLCJceGYxIjoibiIsIlx4ZDIiOiJPIiwiXHhkMyI6Ik8iLCJceGQ0IjoiTyIsIlx4ZDUiOiJPIiwiXHhkNiI6Ik8iLCJceGQ4IjoiTyIsIlx4ZjIiOiJvIiwiXHhmMyI6Im8iLCJceGY0IjoibyIsIlx4ZjUiOiJvIiwiXHhmNiI6Im8iLCJceGY4IjoibyIsIlx4ZDkiOiJVIiwiXHhkYSI6IlUiLCJceGRiIjoiVSIsIlx4ZGMiOiJVIiwiXHhmOSI6InUiLCJceGZhIjoidSIsIlx4ZmIiOiJ1IiwiXHhmYyI6InUiLCJceGRkIjoiWSIsIlx4ZmQiOiJ5IiwiXHhmZiI6InkiLCJceGM2IjoiQWUiLCJceGU2IjoiYWUiLCJceGRlIjoiVGgiLCJceGZlIjoidGgiLCJceGRmIjoic3MiLCJcdTAxMDAiOiJBIiwiXHUwMTAyIjoiQSIsIlx1MDEwNCI6IkEiLCJcdTAxMDEiOiJhIiwiXHUwMTAzIjoiYSIsIlx1MDEwNSI6ImEiLCJcdTAxMDYiOiJDIiwiXHUwMTA4IjoiQyIsIlx1MDEwYSI6IkMiLCJcdTAxMGMiOiJDIiwiXHUwMTA3IjoiYyIsIlx1MDEwOSI6ImMiLCJcdTAxMGIiOiJjIiwiXHUwMTBkIjoiYyIsIlx1MDEwZSI6IkQiLCJcdTAxMTAiOiJEIiwiXHUwMTBmIjoiZCIsIlx1MDExMSI6ImQiLCJcdTAxMTIiOiJFIiwiXHUwMTE0IjoiRSIsIlx1MDExNiI6IkUiLCJcdTAxMTgiOiJFIiwiXHUwMTFhIjoiRSIsIlx1MDExMyI6ImUiLCJcdTAxMTUiOiJlIiwiXHUwMTE3IjoiZSIsIlx1MDExOSI6ImUiLCJcdTAxMWIiOiJlIiwiXHUwMTFjIjoiRyIsIlx1MDExZSI6IkciLCJcdTAxMjAiOiJHIiwiXHUwMTIyIjoiRyIsIlx1MDExZCI6ImciLCJcdTAxMWYiOiJnIiwiXHUwMTIxIjoiZyIsIlx1MDEyMyI6ImciLCJcdTAxMjQiOiJIIiwiXHUwMTI2IjoiSCIsIlx1MDEyNSI6ImgiLCJcdTAxMjciOiJoIiwiXHUwMTI4IjoiSSIsIlx1MDEyYSI6IkkiLCJcdTAxMmMiOiJJIiwiXHUwMTJlIjoiSSIsIlx1MDEzMCI6IkkiLCJcdTAxMjkiOiJpIiwiXHUwMTJiIjoiaSIsIlx1MDEyZCI6ImkiLCJcdTAxMmYiOiJpIiwiXHUwMTMxIjoiaSIsIlx1MDEzNCI6IkoiLCJcdTAxMzUiOiJqIiwiXHUwMTM2IjoiSyIsIlx1MDEzNyI6ImsiLCJcdTAxMzgiOiJrIiwiXHUwMTM5IjoiTCIsIlx1MDEzYiI6IkwiLCJcdTAxM2QiOiJMIiwiXHUwMTNmIjoiTCIsIlx1MDE0MSI6IkwiLCJcdTAxM2EiOiJsIiwiXHUwMTNjIjoibCIsIlx1MDEzZSI6ImwiLCJcdTAxNDAiOiJsIiwiXHUwMTQyIjoibCIsIlx1MDE0MyI6Ik4iLCJcdTAxNDUiOiJOIiwiXHUwMTQ3IjoiTiIsIlx1MDE0YSI6Ik4iLCJcdTAxNDQiOiJuIiwiXHUwMTQ2IjoibiIsIlx1MDE0OCI6Im4iLCJcdTAxNGIiOiJuIiwiXHUwMTRjIjoiTyIsIlx1MDE0ZSI6Ik8iLCJcdTAxNTAiOiJPIiwiXHUwMTRkIjoibyIsIlx1MDE0ZiI6Im8iLCJcdTAxNTEiOiJvIiwiXHUwMTU0IjoiUiIsIlx1MDE1NiI6IlIiLCJcdTAxNTgiOiJSIiwiXHUwMTU1IjoiciIsIlx1MDE1NyI6InIiLCJcdTAxNTkiOiJyIiwiXHUwMTVhIjoiUyIsIlx1MDE1YyI6IlMiLCJcdTAxNWUiOiJTIiwiXHUwMTYwIjoiUyIsIlx1MDE1YiI6InMiLCJcdTAxNWQiOiJzIiwiXHUwMTVmIjoicyIsIlx1MDE2MSI6InMiLCJcdTAxNjIiOiJUIiwiXHUwMTY0IjoiVCIsIlx1MDE2NiI6IlQiLCJcdTAxNjMiOiJ0IiwiXHUwMTY1IjoidCIsIlx1MDE2NyI6InQiLCJcdTAxNjgiOiJVIiwiXHUwMTZhIjoiVSIsIlx1MDE2YyI6IlUiLCJcdTAxNmUiOiJVIiwiXHUwMTcwIjoiVSIsIlx1MDE3MiI6IlUiLCJcdTAxNjkiOiJ1IiwiXHUwMTZiIjoidSIsIlx1MDE2ZCI6InUiLCJcdTAxNmYiOiJ1IiwiXHUwMTcxIjoidSIsIlx1MDE3MyI6InUiLCJcdTAxNzQiOiJXIiwiXHUwMTc1IjoidyIsIlx1MDE3NiI6IlkiLCJcdTAxNzciOiJ5IiwiXHUwMTc4IjoiWSIsIlx1MDE3OSI6IloiLCJcdTAxN2IiOiJaIiwiXHUwMTdkIjoiWiIsIlx1MDE3YSI6InoiLCJcdTAxN2MiOiJ6IiwiXHUwMTdlIjoieiIsIlx1MDEzMiI6IklKIiwiXHUwMTMzIjoiaWoiLCJcdTAxNTIiOiJPZSIsIlx1MDE1MyI6Im9lIiwiXHUwMTQ5IjoiJ24iLCJcdTAxN2YiOiJzIn0sbz1PYmplY3Qoci5hKShpKTt0LmE9b30sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gbnVsbD09ZT92b2lkIDA6ZVt0XX19dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuIGU9T2JqZWN0KGEuYSkoZSksdD1uP3ZvaWQgMDp0LHZvaWQgMD09PXQ/T2JqZWN0KG8uYSkoZSk/T2JqZWN0KHMuYSkoZSk6T2JqZWN0KGkuYSkoZSk6ZS5tYXRjaCh0KXx8W119dmFyIGk9big0NDEpLG89big0NDIpLGE9big2MSkscz1uKDQ0Myk7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZS5tYXRjaChpKXx8W119dmFyIGk9L1teXHgwMC1ceDJmXHgzYS1ceDQwXHg1Yi1ceDYwXHg3Yi1ceDdmXSsvZzt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBpLnRlc3QoZSl9dmFyIGk9L1thLXpdW0EtWl18W0EtWl17Mix9W2Etel18WzAtOV1bYS16QS1aXXxbYS16QS1aXVswLTldfFteYS16QS1aMC05IF0vO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUubWF0Y2goZyl8fFtdfXZhciBpPSJcXHhhY1xceGIxXFx4ZDdcXHhmN1xceDAwLVxceDJmXFx4M2EtXFx4NDBcXHg1Yi1cXHg2MFxceDdiLVxceGJmXFx1MjAwMC1cXHUyMDZmIFxcdFxceDBiXFxmXFx4YTBcXHVmZWZmXFxuXFxyXFx1MjAyOFxcdTIwMjlcXHUxNjgwXFx1MTgwZVxcdTIwMDBcXHUyMDAxXFx1MjAwMlxcdTIwMDNcXHUyMDA0XFx1MjAwNVxcdTIwMDZcXHUyMDA3XFx1MjAwOFxcdTIwMDlcXHUyMDBhXFx1MjAyZlxcdTIwNWZcXHUzMDAwIixvPSJbIitpKyJdIixhPSJbYS16XFx4ZGYtXFx4ZjZcXHhmOC1cXHhmZl0iLHM9IlteXFx1ZDgwMC1cXHVkZmZmIitpKyJcXGQrXFx1MjcwMC1cXHUyN2JmYS16XFx4ZGYtXFx4ZjZcXHhmOC1cXHhmZkEtWlxceGMwLVxceGQ2XFx4ZDgtXFx4ZGVdIix1PSIoPzpcXHVkODNjW1xcdWRkZTYtXFx1ZGRmZl0pezJ9IixjPSJbXFx1ZDgwMC1cXHVkYmZmXVtcXHVkYzAwLVxcdWRmZmZdIixsPSJbQS1aXFx4YzAtXFx4ZDZcXHhkOC1cXHhkZV0iLHA9Iig/OiIrYSsifCIrcysiKSIsZj0iKD86W1xcdTAzMDAtXFx1MDM2ZlxcdWZlMjAtXFx1ZmUyZlxcdTIwZDAtXFx1MjBmZl18XFx1ZDgzY1tcXHVkZmZiLVxcdWRmZmZdKT8iLGQ9Iig/OlxcdTIwMGQoPzoiK1siW15cXHVkODAwLVxcdWRmZmZdIix1LGNdLmpvaW4oInwiKSsiKVtcXHVmZTBlXFx1ZmUwZl0/IitmKyIpKiIsaD0iW1xcdWZlMGVcXHVmZTBmXT8iK2YrZCxtPSIoPzoiK1siW1xcdTI3MDAtXFx1MjdiZl0iLHUsY10uam9pbigifCIpKyIpIitoLGc9UmVnRXhwKFtsKyI/IithKyIrKD86WydcdTIwMTldKD86ZHxsbHxtfHJlfHN8dHx2ZSkpPyg/PSIrW28sbCwiJCJdLmpvaW4oInwiKSsiKSIsIig/OltBLVpcXHhjMC1cXHhkNlxceGQ4LVxceGRlXXxbXlxcdWQ4MDAtXFx1ZGZmZlxceGFjXFx4YjFcXHhkN1xceGY3XFx4MDAtXFx4MmZcXHgzYS1cXHg0MFxceDViLVxceDYwXFx4N2ItXFx4YmZcXHUyMDAwLVxcdTIwNmYgXFx0XFx4MGJcXGZcXHhhMFxcdWZlZmZcXG5cXHJcXHUyMDI4XFx1MjAyOVxcdTE2ODBcXHUxODBlXFx1MjAwMFxcdTIwMDFcXHUyMDAyXFx1MjAwM1xcdTIwMDRcXHUyMDA1XFx1MjAwNlxcdTIwMDdcXHUyMDA4XFx1MjAwOVxcdTIwMGFcXHUyMDJmXFx1MjA1ZlxcdTMwMDBcXGQrXFx1MjcwMC1cXHUyN2JmYS16XFx4ZGYtXFx4ZjZcXHhmOC1cXHhmZkEtWlxceGMwLVxceGQ2XFx4ZDgtXFx4ZGVdKSsoPzpbJ1x1MjAxOV0oPzpEfExMfE18UkV8U3xUfFZFKSk/KD89IitbbyxsK3AsIiQiXS5qb2luKCJ8IikrIikiLGwrIj8iK3ArIisoPzpbJ1x1MjAxOV0oPzpkfGxsfG18cmV8c3x0fHZlKSk/IixsKyIrKD86WydcdTIwMTldKD86RHxMTHxNfFJFfFN8VHxWRSkpPyIsIlxcZCooPzoxU1R8Mk5EfDNSRHwoPyFbMTIzXSlcXGRUSCkoPz1cXGJ8W2Etel9dKSIsIlxcZCooPzoxc3R8Mm5kfDNyZHwoPyFbMTIzXSlcXGR0aCkoPz1cXGJ8W0EtWl9dKSIsIlxcZCsiLG1dLmpvaW4oInwiKSwiZyIpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3QuYT1mdW5jdGlvbihlLHQpe3JldHVybiBlLnJlZHVjZShmdW5jdGlvbihlLG4pe3JldHVybiB0KGUsbil9LHt9KX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0MSksaT1uKDIyNSk7dC5hPU9iamVjdChpLmEpKHIuYSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gT2JqZWN0KG8uYSkoZSkmJk9iamVjdChpLmEpKGUpPT1hfXZhciBpPW4oMjEyKSxvPW4oMzEpLGE9IltvYmplY3QgTWFwXSI7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtmdW5jdGlvbiB0KG4pe3ZhciByPWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7fSxvPWFyZ3VtZW50cy5sZW5ndGg+MiYmdm9pZCAwIT09YXJndW1lbnRzWzJdP2FyZ3VtZW50c1syXTpbXSxzPU9iamVjdChhLmEpKG8uc2hpZnQoKSk7T2JqZWN0KGkuYSkobyk/cltzXT1lW25dOihyW3NdfHwocltzXT17fSksdChuLHJbc10sbykpfXZhciBuPWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7fSxyPW4ubmFtZXNwYWNlLHM9dm9pZCAwPT09cj9vLmI6cix1PW4ucHJlZml4LGM9e307cmV0dXJuIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGUpLmZvckVhY2goZnVuY3Rpb24oZSl7dmFyIG49dT9lLnJlcGxhY2UoIiIrdStzLCIiKTplO3JldHVybiB0KGUsYyxuLnNwbGl0KHMpKX0pLGN9dC5hPXI7dmFyIGk9bigyMDkpLG89big2MiksYT1uKDIyMyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0NDkpLGk9bigxMjQpO3QuYT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3Qoci5hKShPYmplY3QoaS5hKShlLHQpLHQubGVuZ3RoKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7dD1uP3ZvaWQgMDp0O3ZhciBhPU9iamVjdChpLmEpKGUsbyx2b2lkIDAsdm9pZCAwLHZvaWQgMCx2b2lkIDAsdm9pZCAwLHQpO3JldHVybiBhLnBsYWNlaG9sZGVyPXIucGxhY2Vob2xkZXIsYX12YXIgaT1uKDQ1MCksbz04O3IucGxhY2Vob2xkZXI9e30sdC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbixyLEUsRCx3LFMpe3ZhciBrPXQmZztpZighayYmImZ1bmN0aW9uIiE9dHlwZW9mIGUpdGhyb3cgbmV3IFR5cGVFcnJvcihoKTt2YXIgQT1yP3IubGVuZ3RoOjA7aWYoQXx8KHQmPX4oYnx4KSxyPUU9dm9pZCAwKSx3PXZvaWQgMD09PXc/dzpDKE9iamVjdChkLmEpKHcpLDApLFM9dm9pZCAwPT09Uz9TOk9iamVjdChkLmEpKFMpLEEtPUU/RS5sZW5ndGg6MCx0Jngpe3ZhciBfPXIsVD1FO3I9RT12b2lkIDB9dmFyIE89az92b2lkIDA6T2JqZWN0KGMuYSkoZSksRj1bZSx0LG4scixFLF8sVCxELHcsU107aWYoTyYmT2JqZWN0KGwuYSkoRixPKSxlPUZbMF0sdD1GWzFdLG49RlsyXSxyPUZbM10sRT1GWzRdLFM9Rls5XT12b2lkIDA9PT1GWzldP2s/MDplLmxlbmd0aDpDKEZbOV0tQSwwKSwhUyYmdCYoeXx2KSYmKHQmPX4oeXx2KSksdCYmdCE9bSlOPXQ9PXl8fHQ9PXY/T2JqZWN0KGEuYSkoZSx0LFMpOnQhPWImJnQhPShtfGIpfHxFLmxlbmd0aD9zLmEuYXBwbHkodm9pZCAwLEYpOk9iamVjdCh1LmEpKGUsdCxuLHIpO2Vsc2UgdmFyIE49T2JqZWN0KG8uYSkoZSx0LG4pO3ZhciBJPU8/aS5hOnAuYTtyZXR1cm4gT2JqZWN0KGYuYSkoSShOLEYpLGUsdCl9dmFyIGk9bigyMjYpLG89big0NTEpLGE9big0NTIpLHM9bigyMjkpLHU9big0NzMpLGM9bigyMzMpLGw9big0NzQpLHA9bigyMzYpLGY9bigyMzgpLGQ9bigyNDIpLGg9IkV4cGVjdGVkIGEgZnVuY3Rpb24iLG09MSxnPTIseT04LHY9MTYsYj0zMix4PTY0LEM9TWF0aC5tYXg7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7ZnVuY3Rpb24gcigpe3JldHVybih0aGlzJiZ0aGlzIT09by5hJiZ0aGlzIGluc3RhbmNlb2Ygcj91OmUpLmFwcGx5KHM/bjp0aGlzLGFyZ3VtZW50cyl9dmFyIHM9dCZhLHU9T2JqZWN0KGkuYSkoZSk7cmV0dXJuIHJ9dmFyIGk9big4NCksbz1uKDIxKSxhPTE7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7ZnVuY3Rpb24gcigpe2Zvcih2YXIgbz1hcmd1bWVudHMubGVuZ3RoLGY9QXJyYXkobyksZD1vLGg9T2JqZWN0KHUuYSkocik7ZC0tOylmW2RdPWFyZ3VtZW50c1tkXTt2YXIgbT1vPDMmJmZbMF0hPT1oJiZmW28tMV0hPT1oP1tdOk9iamVjdChjLmEpKGYsaCk7aWYoKG8tPW0ubGVuZ3RoKTxuKXJldHVybiBPYmplY3Qocy5hKShlLHQsYS5hLHIucGxhY2Vob2xkZXIsdm9pZCAwLGYsbSx2b2lkIDAsdm9pZCAwLG4tbyk7dmFyIGc9dGhpcyYmdGhpcyE9PWwuYSYmdGhpcyBpbnN0YW5jZW9mIHI/cDplO3JldHVybiBPYmplY3QoaS5hKShnLHRoaXMsZil9dmFyIHA9T2JqZWN0KG8uYSkoZSk7cmV0dXJuIHJ9dmFyIGk9bigyMjgpLG89big4NCksYT1uKDIyOSkscz1uKDIzMiksdT1uKDI0MCksYz1uKDEyOSksbD1uKDIxKTt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuPWUubGVuZ3RoLHI9MDtuLS07KWVbbl09PT10JiYrK3I7cmV0dXJuIHJ9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD1PYmplY3QoYS5hKShlKSxuPXMuYVt0XTtpZigiZnVuY3Rpb24iIT10eXBlb2Ygbnx8ISh0IGluIGkuYS5wcm90b3R5cGUpKXJldHVybiExO2lmKGU9PT1uKXJldHVybiEwO3ZhciByPU9iamVjdChvLmEpKG4pO3JldHVybiEhciYmZT09PXJbMF19dmFyIGk9bigxMjcpLG89bigyMzMpLGE9big0NTYpLHM9big0NTgpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXt9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtmb3IodmFyIHQ9ZS5uYW1lKyIiLG49aS5hW3RdLHI9YS5jYWxsKGkuYSx0KT9uLmxlbmd0aDowO3ItLTspe3ZhciBvPW5bcl0scz1vLmZ1bmM7aWYobnVsbD09c3x8cz09ZSlyZXR1cm4gby5uYW1lfXJldHVybiB0fXZhciBpPW4oNDU3KSxvPU9iamVjdC5wcm90b3R5cGUsYT1vLmhhc093blByb3BlcnR5O3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPXt9O3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7aWYoT2JqZWN0KHUuYSkoZSkmJiFPYmplY3Qocy5hKShlKSYmIShlIGluc3RhbmNlb2YgaS5hKSl7aWYoZSBpbnN0YW5jZW9mIG8uYSlyZXR1cm4gZTtpZihwLmNhbGwoZSwiX193cmFwcGVkX18iKSlyZXR1cm4gT2JqZWN0KGMuYSkoZSl9cmV0dXJuIG5ldyBvLmEoZSl9dmFyIGk9bigxMjcpLG89bigyMzQpLGE9bigxMjgpLHM9big0NyksdT1uKDMxKSxjPW4oNDU5KSxsPU9iamVjdC5wcm90b3R5cGUscD1sLmhhc093blByb3BlcnR5O3IucHJvdG90eXBlPWEuYS5wcm90b3R5cGUsci5wcm90b3R5cGUuY29uc3RydWN0b3I9cix0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe2lmKGUgaW5zdGFuY2VvZiBpLmEpcmV0dXJuIGUuY2xvbmUoKTt2YXIgdD1uZXcgby5hKGUuX193cmFwcGVkX18sZS5fX2NoYWluX18pO3JldHVybiB0Ll9fYWN0aW9uc19fPU9iamVjdChhLmEpKGUuX19hY3Rpb25zX18pLHQuX19pbmRleF9fPWUuX19pbmRleF9fLHQuX192YWx1ZXNfXz1lLl9fdmFsdWVzX18sdH12YXIgaT1uKDEyNyksbz1uKDIzNCksYT1uKDIzNSk7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD1lLm1hdGNoKGkpO3JldHVybiB0P3RbMV0uc3BsaXQobyk6W119dmFyIGk9L1x7XG5cL1wqIFxbd3JhcHBlZCB3aXRoICguKylcXSBcKi8sbz0vLD8gJiAvO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2YXIgbj10Lmxlbmd0aDtpZighbilyZXR1cm4gZTt2YXIgcj1uLTE7cmV0dXJuIHRbcl09KG4+MT8iJiAiOiIiKSt0W3JdLHQ9dC5qb2luKG4+Mj8iLCAiOiIgIiksZS5yZXBsYWNlKGksIntcbi8qIFt3cmFwcGVkIHdpdGggIit0KyJdICovXG4iKX12YXIgaT0vXHsoPzpcblwvXCogXFt3cmFwcGVkIHdpdGggLitcXSBcKlwvKT9cbj8vO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNDYzKSxpPW4oMjM3KSxvPU9iamVjdChpLmEpKHIuYSk7dC5hPW99LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0NjQpLGk9big0NjUpLG89big2MyksYT1pLmE/ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0KGkuYSkoZSwidG9TdHJpbmciLHtjb25maWd1cmFibGU6ITAsZW51bWVyYWJsZTohMSx2YWx1ZTpPYmplY3Qoci5hKSh0KSx3cml0YWJsZTohMH0pfTpvLmE7dC5hPWF9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gZX19dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0OSksaT1mdW5jdGlvbigpe3RyeXt2YXIgZT1PYmplY3Qoci5hKShPYmplY3QsImRlZmluZVByb3BlcnR5Iik7cmV0dXJuIGUoe30sIiIse30pLGV9Y2F0Y2goZSl7fX0oKTt0LmE9aX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7cmV0dXJuIE9iamVjdChpLmEpKGEsZnVuY3Rpb24obil7dmFyIHI9Il8uIituWzBdO3QmblsxXSYmIU9iamVjdChvLmEpKGUscikmJmUucHVzaChyKX0pLGUuc29ydCgpfXZhciBpPW4oNDY3KSxvPW4oNDY4KSxhPVtbImFyeSIsMTI4XSxbImJpbmQiLDFdLFsiYmluZEtleSIsMl0sWyJjdXJyeSIsOF0sWyJjdXJyeVJpZ2h0IiwxNl0sWyJmbGlwIiw1MTJdLFsicGFydGlhbCIsMzJdLFsicGFydGlhbFJpZ2h0Iiw2NF0sWyJyZWFyZyIsMjU2XV07dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2Zvcih2YXIgbj0tMSxyPW51bGw9PWU/MDplLmxlbmd0aDsrK248ciYmITEhPT10KGVbbl0sbixlKTspO3JldHVybiBlfXQuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4hIShudWxsPT1lPzA6ZS5sZW5ndGgpJiZPYmplY3QoaS5hKShlLHQsMCk+LTF9dmFyIGk9bigyMzkpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4scil7Zm9yKHZhciBpPWUubGVuZ3RoLG89bisocj8xOi0xKTtyP28tLTorK288aTspaWYodChlW29dLG8sZSkpcmV0dXJuIG87cmV0dXJuLTF9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSE9PWV9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7Zm9yKHZhciByPW4tMSxpPWUubGVuZ3RoOysrcjxpOylpZihlW3JdPT09dClyZXR1cm4gcjtyZXR1cm4tMX10LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7Zm9yKHZhciBuPWUubGVuZ3RoLHI9YSh0Lmxlbmd0aCxuKSxzPU9iamVjdChpLmEpKGUpO3ItLTspe3ZhciB1PXRbcl07ZVtyXT1PYmplY3Qoby5hKSh1LG4pP3NbdV06dm9pZCAwfXJldHVybiBlfXZhciBpPW4oMjM1KSxvPW4oMjQxKSxhPU1hdGgubWluO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4scil7ZnVuY3Rpb24gdSgpe2Zvcih2YXIgdD0tMSxvPWFyZ3VtZW50cy5sZW5ndGgscz0tMSxwPXIubGVuZ3RoLGY9QXJyYXkocCtvKSxkPXRoaXMmJnRoaXMhPT1hLmEmJnRoaXMgaW5zdGFuY2VvZiB1P2w6ZTsrK3M8cDspZltzXT1yW3NdO2Zvcig7by0tOylmW3MrK109YXJndW1lbnRzWysrdF07cmV0dXJuIE9iamVjdChpLmEpKGQsYz9uOnRoaXMsZil9dmFyIGM9dCZzLGw9T2JqZWN0KG8uYSkoZSk7cmV0dXJuIHV9dmFyIGk9bigyMjgpLG89big4NCksYT1uKDIxKSxzPTE7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPWVbMV0scj10WzFdLG09bnxyLGc9bTwodXxjfGYpLHk9cj09ZiYmbj09cHx8cj09ZiYmbj09ZCYmZVs3XS5sZW5ndGg8PXRbOF18fHI9PShmfGQpJiZ0WzddLmxlbmd0aDw9dFs4XSYmbj09cDtpZighZyYmIXkpcmV0dXJuIGU7ciZ1JiYoZVsyXT10WzJdLG18PW4mdT8wOmwpO3ZhciB2PXRbM107aWYodil7dmFyIGI9ZVszXTtlWzNdPWI/T2JqZWN0KGkuYSkoYix2LHRbNF0pOnYsZVs0XT1iP09iamVjdChhLmEpKGVbM10scyk6dFs0XX1yZXR1cm4gdj10WzVdLHYmJihiPWVbNV0sZVs1XT1iP09iamVjdChvLmEpKGIsdix0WzZdKTp2LGVbNl09Yj9PYmplY3QoYS5hKShlWzVdLHMpOnRbNl0pLHY9dFs3XSx2JiYoZVs3XT12KSxyJmYmJihlWzhdPW51bGw9PWVbOF0/dFs4XTpoKGVbOF0sdFs4XSkpLG51bGw9PWVbOV0mJihlWzldPXRbOV0pLGVbMF09dFswXSxlWzFdPW0sZX12YXIgaT1uKDIzMCksbz1uKDIzMSksYT1uKDEyOSkscz0iX19sb2Rhc2hfcGxhY2Vob2xkZXJfXyIsdT0xLGM9MixsPTQscD04LGY9MTI4LGQ9MjU2LGg9TWF0aC5taW47dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZighZSlyZXR1cm4gMD09PWU/ZTowO2lmKChlPU9iamVjdChpLmEpKGUpKT09PW98fGU9PT0tbyl7cmV0dXJuKGU8MD8tMToxKSphfXJldHVybiBlPT09ZT9lOjB9dmFyIGk9big0NzYpLG89MS8wLGE9MS43OTc2OTMxMzQ4NjIzMTU3ZTMwODt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe2lmKCJudW1iZXIiPT10eXBlb2YgZSlyZXR1cm4gZTtpZihPYmplY3Qoby5hKShlKSlyZXR1cm4gYTtpZihPYmplY3QoaS5hKShlKSl7dmFyIHQ9ImZ1bmN0aW9uIj09dHlwZW9mIGUudmFsdWVPZj9lLnZhbHVlT2YoKTplO2U9T2JqZWN0KGkuYSkodCk/dCsiIjp0fWlmKCJzdHJpbmciIT10eXBlb2YgZSlyZXR1cm4gMD09PWU/ZTorZTtlPWUucmVwbGFjZShzLCIiKTt2YXIgbj1jLnRlc3QoZSk7cmV0dXJuIG58fGwudGVzdChlKT9wKGUuc2xpY2UoMiksbj8yOjgpOnUudGVzdChlKT9hOitlfXZhciBpPW4oNjApLG89bigxMjMpLGE9TmFOLHM9L15ccyt8XHMrJC9nLHU9L15bLStdMHhbMC05YS1mXSskL2ksYz0vXjBiWzAxXSskL2ksbD0vXjBvWzAtN10rJC9pLHA9cGFyc2VJbnQ7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gdm9pZCAwPT09ZX10LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuLHIpe2U9T2JqZWN0KG8uYSkoZSk/ZTpPYmplY3QodS5hKShlKSxuPW4mJiFyP09iamVjdChzLmEpKG4pOjA7dmFyIGw9ZS5sZW5ndGg7cmV0dXJuIG48MCYmKG49YyhsK24sMCkpLE9iamVjdChhLmEpKGUpP248PWwmJmUuaW5kZXhPZih0LG4pPi0xOiEhbCYmT2JqZWN0KGkuYSkoZSx0LG4pPi0xfXZhciBpPW4oMjM5KSxvPW4oMTIyKSxhPW4oMTIxKSxzPW4oMjQyKSx1PW4oNDc5KSxjPU1hdGgubWF4O3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG51bGw9PWU/W106T2JqZWN0KGkuYSkoZSxPYmplY3Qoby5hKShlKSl9dmFyIGk9big0ODApLG89big0ODEpO3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtyZXR1cm4gT2JqZWN0KGkuYSkodCxmdW5jdGlvbih0KXtyZXR1cm4gZVt0XX0pfXZhciBpPW4oMjIxKTt0LmE9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBPYmplY3QoYS5hKShlKT9PYmplY3QoaS5hKShlKTpPYmplY3Qoby5hKShlKX12YXIgaT1uKDQ4Miksbz1uKDIxMCksYT1uKDEyMik7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPU9iamVjdChhLmEpKGUpLHI9IW4mJk9iamVjdChvLmEpKGUpLGw9IW4mJiFyJiZPYmplY3Qocy5hKShlKSxmPSFuJiYhciYmIWwmJk9iamVjdChjLmEpKGUpLGQ9bnx8cnx8bHx8ZixoPWQ/T2JqZWN0KGkuYSkoZS5sZW5ndGgsU3RyaW5nKTpbXSxtPWgubGVuZ3RoO2Zvcih2YXIgZyBpbiBlKSF0JiYhcC5jYWxsKGUsZyl8fGQmJigibGVuZ3RoIj09Z3x8bCYmKCJvZmZzZXQiPT1nfHwicGFyZW50Ij09Zyl8fGYmJigiYnVmZmVyIj09Z3x8ImJ5dGVMZW5ndGgiPT1nfHwiYnl0ZU9mZnNldCI9PWcpfHxPYmplY3QodS5hKShnLG0pKXx8aC5wdXNoKGcpO3JldHVybiBofXZhciBpPW4oNDgzKSxvPW4oMjE1KSxhPW4oNDcpLHM9bigyMTcpLHU9bigyNDEpLGM9bigyMTgpLGw9T2JqZWN0LnByb3RvdHlwZSxwPWwuaGFzT3duUHJvcGVydHk7dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe2Zvcih2YXIgbj0tMSxyPUFycmF5KGUpOysrbjxlOylyW25dPXQobik7cmV0dXJuIHJ9dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZihBcnJheS5pc0FycmF5KGUpKXtmb3IodmFyIHQ9MCxuPUFycmF5KGUubGVuZ3RoKTt0PGUubGVuZ3RoO3QrKyluW3RdPWVbdF07cmV0dXJuIG59cmV0dXJuIEFycmF5LmZyb20oZSl9ZnVuY3Rpb24gaShlLHQpe3JldHVybiBPYmplY3Qocy5hKSh0KT90LmdldChlKTp0W2VdfWZ1bmN0aW9uIG8oZSx0KXt2YXIgbj1hcmd1bWVudHMubGVuZ3RoPjImJnZvaWQgMCE9PWFyZ3VtZW50c1syXT9hcmd1bWVudHNbMl06e307cCgpKE9iamVjdChhLmEpKGUpfHxPYmplY3Qocy5hKShlKSwiRXhwZWN0ZWQgaGFuZGxlcnMgdG8gYmUgYSBwbGFpbiBvYmplY3QuIik7dmFyIG89T2JqZWN0KGguYSkoZSxuKSx1PU9iamVjdChkLmEpKG8pLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gT2JqZWN0KGYuYSkoZSxpKGUsbyksdCl9KSxsPWMuYS5hcHBseSh2b2lkIDAscih1KSk7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIGU9YXJndW1lbnRzLmxlbmd0aD4wJiZ2b2lkIDAhPT1hcmd1bWVudHNbMF0/YXJndW1lbnRzWzBdOnQsbj1hcmd1bWVudHNbMV07cmV0dXJuIGwoZSxuKX19dC5hPW87dmFyIGE9big0MSkscz1uKDgzKSx1PW4oNDg1KSxjPW4ubih1KSxsPW4oMjApLHA9bi5uKGwpLGY9bigyNDMpLGQ9bigxMjUpLGg9big0ODYpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmRlZmF1bHQ9ZnVuY3Rpb24oKXtmb3IodmFyIGU9YXJndW1lbnRzLmxlbmd0aCx0PUFycmF5KGUpLG49MDtuPGU7bisrKXRbbl09YXJndW1lbnRzW25dO3JldHVybiBmdW5jdGlvbihlLG4pe3JldHVybiB0LnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiB0KGUsbil9LGUpfX0sZS5leHBvcnRzPXQuZGVmYXVsdH0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDQxKSxpPW4oODMpLG89big0ODcpLGE9bigyMjUpO3QuYT1PYmplY3QoYS5hKShmdW5jdGlvbihlKXtyZXR1cm4oT2JqZWN0KHIuYSkoZSl8fE9iamVjdChpLmEpKGUpKSYmIU9iamVjdChvLmEpKGUpfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD1PYmplY3QoaS5hKShlKSxuPXQuZXZlcnkoZnVuY3Rpb24oZSl7cmV0dXJuIm5leHQiPT09ZXx8InRocm93Ij09PWV9KTtyZXR1cm4gdC5sZW5ndGgmJnQubGVuZ3RoPD0yJiZufXQuYT1yO3ZhciBpPW4oMTI1KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5jb21iaW5lUmVkdWNlcnM9dm9pZCAwO3ZhciByPW4oNDg5KSxpPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0ocik7dC5jb21iaW5lUmVkdWNlcnM9aS5kZWZhdWx0fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDE0KSxpPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0ociksbz1uKDQ5MCk7dC5kZWZhdWx0PWZ1bmN0aW9uKGUpe3ZhciB0PWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTppLmRlZmF1bHQuTWFwLG49T2JqZWN0LmtleXMoZSk7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIHI9YXJndW1lbnRzLmxlbmd0aD4wJiZ2b2lkIDAhPT1hcmd1bWVudHNbMF0/YXJndW1lbnRzWzBdOnQoKSxpPWFyZ3VtZW50c1sxXTtyZXR1cm4gci53aXRoTXV0YXRpb25zKGZ1bmN0aW9uKHQpe24uZm9yRWFjaChmdW5jdGlvbihuKXt2YXIgcj1lW25dLGE9dC5nZXQobikscz1yKGEsaSk7KDAsby52YWxpZGF0ZU5leHRTdGF0ZSkocyxuLGkpLHQuc2V0KG4scyl9KX0pfX0sZS5leHBvcnRzPXQuZGVmYXVsdH0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC52YWxpZGF0ZU5leHRTdGF0ZT10LmdldFVuZXhwZWN0ZWRJbnZvY2F0aW9uUGFyYW1ldGVyTWVzc2FnZT10LmdldFN0YXRlTmFtZT12b2lkIDA7dmFyIGk9bigyNDQpLG89cihpKSxhPW4oNDkxKSxzPXIoYSksdT1uKDQ5MiksYz1yKHUpO3QuZ2V0U3RhdGVOYW1lPW8uZGVmYXVsdCx0LmdldFVuZXhwZWN0ZWRJbnZvY2F0aW9uUGFyYW1ldGVyTWVzc2FnZT1zLmRlZmF1bHQsdC52YWxpZGF0ZU5leHRTdGF0ZT1jLmRlZmF1bHR9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPW4oMTQpLG89cihpKSxhPW4oMjQ0KSxzPXIoYSk7dC5kZWZhdWx0PWZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1PYmplY3Qua2V5cyh0KTtpZighci5sZW5ndGgpcmV0dXJuIlN0b3JlIGRvZXMgbm90IGhhdmUgYSB2YWxpZCByZWR1Y2VyLiBNYWtlIHN1cmUgdGhlIGFyZ3VtZW50IHBhc3NlZCB0byBjb21iaW5lUmVkdWNlcnMgaXMgYW4gb2JqZWN0IHdob3NlIHZhbHVlcyBhcmUgcmVkdWNlcnMuIjt2YXIgaT0oMCxzLmRlZmF1bHQpKG4pO2lmKG8uZGVmYXVsdC5pc0ltbXV0YWJsZT8hby5kZWZhdWx0LmlzSW1tdXRhYmxlKGUpOiFvLmRlZmF1bHQuSXRlcmFibGUuaXNJdGVyYWJsZShlKSlyZXR1cm4iVGhlICIraSsnIGlzIG9mIHVuZXhwZWN0ZWQgdHlwZS4gRXhwZWN0ZWQgYXJndW1lbnQgdG8gYmUgYW4gaW5zdGFuY2Ugb2YgSW1tdXRhYmxlLkNvbGxlY3Rpb24gb3IgSW1tdXRhYmxlLlJlY29yZCB3aXRoIHRoZSBmb2xsb3dpbmcgcHJvcGVydGllczogIicrci5qb2luKCciLCAiJykrJyIuJzt2YXIgYT1lLnRvU2VxKCkua2V5U2VxKCkudG9BcnJheSgpLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4hdC5oYXNPd25Qcm9wZXJ0eShlKX0pO3JldHVybiBhLmxlbmd0aD4wPyJVbmV4cGVjdGVkICIrKDE9PT1hLmxlbmd0aD8icHJvcGVydHkiOiJwcm9wZXJ0aWVzIikrJyAiJythLmpvaW4oJyIsICInKSsnIiBmb3VuZCBpbiAnK2krJy4gRXhwZWN0ZWQgdG8gZmluZCBvbmUgb2YgdGhlIGtub3duIHJlZHVjZXIgcHJvcGVydHkgbmFtZXMgaW5zdGVhZDogIicrci5qb2luKCciLCAiJykrJyIuIFVuZXhwZWN0ZWQgcHJvcGVydGllcyB3aWxsIGJlIGlnbm9yZWQuJzpudWxsfSxlLmV4cG9ydHM9dC5kZWZhdWx0fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmRlZmF1bHQ9ZnVuY3Rpb24oZSx0LG4pe2lmKHZvaWQgMD09PWUpdGhyb3cgbmV3IEVycm9yKCdSZWR1Y2VyICInK3QrJyIgcmV0dXJuZWQgdW5kZWZpbmVkIHdoZW4gaGFuZGxpbmcgIicrbi50eXBlKyciIGFjdGlvbi4gVG8gaWdub3JlIGFuIGFjdGlvbiwgeW91IG11c3QgZXhwbGljaXRseSByZXR1cm4gdGhlIHByZXZpb3VzIHN0YXRlLicpfSxlLmV4cG9ydHM9dC5kZWZhdWx0fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSl7aWYoQXJyYXkuaXNBcnJheShlKSl7Zm9yKHZhciB0PTAsbj1BcnJheShlLmxlbmd0aCk7dDxlLmxlbmd0aDt0Kyspblt0XT1lW3RdO3JldHVybiBufXJldHVybiBBcnJheS5mcm9tKGUpfWZ1bmN0aW9uIG8oZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBhKGUsdCl7aWYoIWUpdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKCJ0aGlzIGhhc24ndCBiZWVuIGluaXRpYWxpc2VkIC0gc3VwZXIoKSBoYXNuJ3QgYmVlbiBjYWxsZWQiKTtyZXR1cm4hdHx8Im9iamVjdCIhPT10eXBlb2YgdCYmImZ1bmN0aW9uIiE9PXR5cGVvZiB0P2U6dH1mdW5jdGlvbiBzKGUsdCl7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJTdXBlciBleHByZXNzaW9uIG11c3QgZWl0aGVyIGJlIG51bGwgb3IgYSBmdW5jdGlvbiwgbm90ICIrdHlwZW9mIHQpO2UucHJvdG90eXBlPU9iamVjdC5jcmVhdGUodCYmdC5wcm90b3R5cGUse2NvbnN0cnVjdG9yOnt2YWx1ZTplLGVudW1lcmFibGU6ITEsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfX0pLHQmJihPYmplY3Quc2V0UHJvdG90eXBlT2Y/T2JqZWN0LnNldFByb3RvdHlwZU9mKGUsdCk6ZS5fX3Byb3RvX189dCl9ZnVuY3Rpb24gdShlKXt2YXIgdCxuLHI9YXJndW1lbnRzLmxlbmd0aD4xJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0/YXJndW1lbnRzWzFdOnt3aXRoUmVmOiExfTtyZXR1cm4gbj10PWZ1bmN0aW9uKHQpe2Z1bmN0aW9uIG4oZSl7byh0aGlzLG4pO3ZhciB0PWEodGhpcywobi5fX3Byb3RvX198fE9iamVjdC5nZXRQcm90b3R5cGVPZihuKSkuY2FsbCh0aGlzLGUpKTtyZXR1cm4gdC5oYW5kbGVTdGFydD1mdW5jdGlvbihlKXt2YXIgbj10LnByb3BzLHI9bi5kaXN0YW5jZSxpPW4uc2hvdWxkQ2FuY2VsU3RhcnQ7aWYoMj09PWUuYnV0dG9ufHxpKGUpKXJldHVybiExO3QuX3RvdWNoZWQ9ITAsdC5fcG9zPSgwLEMuZ2V0UG9zaXRpb24pKGUpO3ZhciBvPSgwLEMuY2xvc2VzdCkoZS50YXJnZXQsZnVuY3Rpb24oZSl7cmV0dXJuIG51bGwhPWUuc29ydGFibGVJbmZvfSk7aWYobyYmby5zb3J0YWJsZUluZm8mJnQubm9kZUlzQ2hpbGQobykmJiF0LnN0YXRlLnNvcnRpbmcpe3ZhciBhPXQucHJvcHMudXNlRHJhZ0hhbmRsZSxzPW8uc29ydGFibGVJbmZvLHU9cy5pbmRleCxjPXMuY29sbGVjdGlvbjtpZihhJiYhKDAsQy5jbG9zZXN0KShlLnRhcmdldCxmdW5jdGlvbihlKXtyZXR1cm4gbnVsbCE9ZS5zb3J0YWJsZUhhbmRsZX0pKXJldHVybjt0Lm1hbmFnZXIuYWN0aXZlPXtpbmRleDp1LGNvbGxlY3Rpb246Y30sKDAsQy5pc1RvdWNoRXZlbnQpKGUpfHwiYSIhPT1lLnRhcmdldC50YWdOYW1lLnRvTG93ZXJDYXNlKCl8fGUucHJldmVudERlZmF1bHQoKSxyfHwoMD09PXQucHJvcHMucHJlc3NEZWxheT90LmhhbmRsZVByZXNzKGUpOnQucHJlc3NUaW1lcj1zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIHQuaGFuZGxlUHJlc3MoZSl9LHQucHJvcHMucHJlc3NEZWxheSkpfX0sdC5ub2RlSXNDaGlsZD1mdW5jdGlvbihlKXtyZXR1cm4gZS5zb3J0YWJsZUluZm8ubWFuYWdlcj09PXQubWFuYWdlcn0sdC5oYW5kbGVNb3ZlPWZ1bmN0aW9uKGUpe3ZhciBuPXQucHJvcHMscj1uLmRpc3RhbmNlLGk9bi5wcmVzc1RocmVzaG9sZDtpZighdC5zdGF0ZS5zb3J0aW5nJiZ0Ll90b3VjaGVkKXt2YXIgbz0oMCxDLmdldFBvc2l0aW9uKShlKSxhPXQuX2RlbHRhPXt4OnQuX3Bvcy54LW8ueCx5OnQuX3Bvcy55LW8ueX0scz1NYXRoLmFicyhhLngpK01hdGguYWJzKGEueSk7cnx8aSYmIShpJiZzPj1pKT9yJiZzPj1yJiZ0Lm1hbmFnZXIuaXNBY3RpdmUoKSYmdC5oYW5kbGVQcmVzcyhlKTooY2xlYXJUaW1lb3V0KHQuY2FuY2VsVGltZXIpLHQuY2FuY2VsVGltZXI9c2V0VGltZW91dCh0LmNhbmNlbCwwKSl9fSx0LmhhbmRsZUVuZD1mdW5jdGlvbigpe3ZhciBlPXQucHJvcHMuZGlzdGFuY2U7dC5fdG91Y2hlZD0hMSxlfHx0LmNhbmNlbCgpfSx0LmNhbmNlbD1mdW5jdGlvbigpe3Quc3RhdGUuc29ydGluZ3x8KGNsZWFyVGltZW91dCh0LnByZXNzVGltZXIpLHQubWFuYWdlci5hY3RpdmU9bnVsbCl9LHQuaGFuZGxlUHJlc3M9ZnVuY3Rpb24oZSl7dmFyIG49dC5tYW5hZ2VyLmdldEFjdGl2ZSgpO2lmKG4pe3ZhciByPXQucHJvcHMsbz1yLmF4aXMsYT1yLmdldEhlbHBlckRpbWVuc2lvbnMscz1yLmhlbHBlckNsYXNzLHU9ci5oaWRlU29ydGFibGVHaG9zdCxjPXIub25Tb3J0U3RhcnQsbD1yLnVzZVdpbmRvd0FzU2Nyb2xsQ29udGFpbmVyLHA9bi5ub2RlLGY9bi5jb2xsZWN0aW9uLGQ9cC5zb3J0YWJsZUluZm8uaW5kZXgsaD0oMCxDLmdldEVsZW1lbnRNYXJnaW4pKHApLG09dC5jb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksZz1hKHtpbmRleDpkLG5vZGU6cCxjb2xsZWN0aW9uOmZ9KTt0Lm5vZGU9cCx0Lm1hcmdpbj1oLHQud2lkdGg9Zy53aWR0aCx0LmhlaWdodD1nLmhlaWdodCx0Lm1hcmdpbk9mZnNldD17eDp0Lm1hcmdpbi5sZWZ0K3QubWFyZ2luLnJpZ2h0LHk6TWF0aC5tYXgodC5tYXJnaW4udG9wLHQubWFyZ2luLmJvdHRvbSl9LHQuYm91bmRpbmdDbGllbnRSZWN0PXAuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksdC5jb250YWluZXJCb3VuZGluZ1JlY3Q9bSx0LmluZGV4PWQsdC5uZXdJbmRleD1kLHQuYXhpcz17eDpvLmluZGV4T2YoIngiKT49MCx5Om8uaW5kZXhPZigieSIpPj0wfSx0Lm9mZnNldEVkZ2U9KDAsQy5nZXRFZGdlT2Zmc2V0KShwLHQuY29udGFpbmVyKSx0LmluaXRpYWxPZmZzZXQ9KDAsQy5nZXRQb3NpdGlvbikoZSksdC5pbml0aWFsU2Nyb2xsPXt0b3A6dC5jb250YWluZXIuc2Nyb2xsVG9wLGxlZnQ6dC5jb250YWluZXIuc2Nyb2xsTGVmdH0sdC5pbml0aWFsV2luZG93U2Nyb2xsPXt0b3A6d2luZG93LnBhZ2VZT2Zmc2V0LGxlZnQ6d2luZG93LnBhZ2VYT2Zmc2V0fTt2YXIgeT1wLnF1ZXJ5U2VsZWN0b3JBbGwoImlucHV0LCB0ZXh0YXJlYSwgc2VsZWN0Iiksdj1wLmNsb25lTm9kZSghMCk7aWYoW10uY29uY2F0KGkodi5xdWVyeVNlbGVjdG9yQWxsKCJpbnB1dCwgdGV4dGFyZWEsIHNlbGVjdCIpKSkuZm9yRWFjaChmdW5jdGlvbihlLHQpeyJmaWxlIiE9PWUudHlwZSYmeVt0XSYmKGUudmFsdWU9eVt0XS52YWx1ZSl9KSx0LmhlbHBlcj10LmRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQodiksdC5oZWxwZXIuc3R5bGUucG9zaXRpb249ImZpeGVkIix0LmhlbHBlci5zdHlsZS50b3A9dC5ib3VuZGluZ0NsaWVudFJlY3QudG9wLWgudG9wKyJweCIsdC5oZWxwZXIuc3R5bGUubGVmdD10LmJvdW5kaW5nQ2xpZW50UmVjdC5sZWZ0LWgubGVmdCsicHgiLHQuaGVscGVyLnN0eWxlLndpZHRoPXQud2lkdGgrInB4Iix0LmhlbHBlci5zdHlsZS5oZWlnaHQ9dC5oZWlnaHQrInB4Iix0LmhlbHBlci5zdHlsZS5ib3hTaXppbmc9ImJvcmRlci1ib3giLHQuaGVscGVyLnN0eWxlLnBvaW50ZXJFdmVudHM9Im5vbmUiLHUmJih0LnNvcnRhYmxlR2hvc3Q9cCxwLnN0eWxlLnZpc2liaWxpdHk9ImhpZGRlbiIscC5zdHlsZS5vcGFjaXR5PTApLHQubWluVHJhbnNsYXRlPXt9LHQubWF4VHJhbnNsYXRlPXt9LHQuYXhpcy54JiYodC5taW5UcmFuc2xhdGUueD0obD8wOm0ubGVmdCktdC5ib3VuZGluZ0NsaWVudFJlY3QubGVmdC10LndpZHRoLzIsdC5tYXhUcmFuc2xhdGUueD0obD90LmNvbnRlbnRXaW5kb3cuaW5uZXJXaWR0aDptLmxlZnQrbS53aWR0aCktdC5ib3VuZGluZ0NsaWVudFJlY3QubGVmdC10LndpZHRoLzIpLHQuYXhpcy55JiYodC5taW5UcmFuc2xhdGUueT0obD8wOm0udG9wKS10LmJvdW5kaW5nQ2xpZW50UmVjdC50b3AtdC5oZWlnaHQvMix0Lm1heFRyYW5zbGF0ZS55PShsP3QuY29udGVudFdpbmRvdy5pbm5lckhlaWdodDptLnRvcCttLmhlaWdodCktdC5ib3VuZGluZ0NsaWVudFJlY3QudG9wLXQuaGVpZ2h0LzIpLHMpe3ZhciBiOyhiPXQuaGVscGVyLmNsYXNzTGlzdCkuYWRkLmFwcGx5KGIsaShzLnNwbGl0KCIgIikpKX10Lmxpc3RlbmVyTm9kZT1lLnRvdWNoZXM/cDp0LmNvbnRlbnRXaW5kb3csQy5ldmVudHMubW92ZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiB0Lmxpc3RlbmVyTm9kZS5hZGRFdmVudExpc3RlbmVyKGUsdC5oYW5kbGVTb3J0TW92ZSwhMSl9KSxDLmV2ZW50cy5lbmQuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gdC5saXN0ZW5lck5vZGUuYWRkRXZlbnRMaXN0ZW5lcihlLHQuaGFuZGxlU29ydEVuZCwhMSl9KSx0LnNldFN0YXRlKHtzb3J0aW5nOiEwLHNvcnRpbmdJbmRleDpkfSksYyYmYyh7bm9kZTpwLGluZGV4OmQsY29sbGVjdGlvbjpmfSxlKX19LHQuaGFuZGxlU29ydE1vdmU9ZnVuY3Rpb24oZSl7dmFyIG49dC5wcm9wcy5vblNvcnRNb3ZlO2UucHJldmVudERlZmF1bHQoKSx0LnVwZGF0ZVBvc2l0aW9uKGUpLHQuYW5pbWF0ZU5vZGVzKCksdC5hdXRvc2Nyb2xsKCksbiYmbihlKX0sdC5oYW5kbGVTb3J0RW5kPWZ1bmN0aW9uKGUpe3ZhciBuPXQucHJvcHMscj1uLmhpZGVTb3J0YWJsZUdob3N0LGk9bi5vblNvcnRFbmQsbz10Lm1hbmFnZXIuYWN0aXZlLmNvbGxlY3Rpb247dC5saXN0ZW5lck5vZGUmJihDLmV2ZW50cy5tb3ZlLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIHQubGlzdGVuZXJOb2RlLnJlbW92ZUV2ZW50TGlzdGVuZXIoZSx0LmhhbmRsZVNvcnRNb3ZlKX0pLEMuZXZlbnRzLmVuZC5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiB0Lmxpc3RlbmVyTm9kZS5yZW1vdmVFdmVudExpc3RlbmVyKGUsdC5oYW5kbGVTb3J0RW5kKX0pKSx0LmhlbHBlci5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHQuaGVscGVyKSxyJiZ0LnNvcnRhYmxlR2hvc3QmJih0LnNvcnRhYmxlR2hvc3Quc3R5bGUudmlzaWJpbGl0eT0iIix0LnNvcnRhYmxlR2hvc3Quc3R5bGUub3BhY2l0eT0iIik7Zm9yKHZhciBhPXQubWFuYWdlci5yZWZzW29dLHM9MCx1PWEubGVuZ3RoO3M8dTtzKyspe3ZhciBjPWFbc10sbD1jLm5vZGU7Yy5lZGdlT2Zmc2V0PW51bGwsbC5zdHlsZVtDLnZlbmRvclByZWZpeCsiVHJhbnNmb3JtIl09IiIsbC5zdHlsZVtDLnZlbmRvclByZWZpeCsiVHJhbnNpdGlvbkR1cmF0aW9uIl09IiJ9Y2xlYXJJbnRlcnZhbCh0LmF1dG9zY3JvbGxJbnRlcnZhbCksdC5hdXRvc2Nyb2xsSW50ZXJ2YWw9bnVsbCx0Lm1hbmFnZXIuYWN0aXZlPW51bGwsdC5zZXRTdGF0ZSh7c29ydGluZzohMSxzb3J0aW5nSW5kZXg6bnVsbH0pLCJmdW5jdGlvbiI9PT10eXBlb2YgaSYmaSh7b2xkSW5kZXg6dC5pbmRleCxuZXdJbmRleDp0Lm5ld0luZGV4LGNvbGxlY3Rpb246b30sZSksdC5fdG91Y2hlZD0hMX0sdC5hdXRvc2Nyb2xsPWZ1bmN0aW9uKCl7dmFyIGU9dC50cmFuc2xhdGUsbj17eDowLHk6MH0scj17eDoxLHk6MX0saT17eDoxMCx5OjEwfTtlLnk+PXQubWF4VHJhbnNsYXRlLnktdC5oZWlnaHQvMj8obi55PTEsci55PWkueSpNYXRoLmFicygodC5tYXhUcmFuc2xhdGUueS10LmhlaWdodC8yLWUueSkvdC5oZWlnaHQpKTplLng+PXQubWF4VHJhbnNsYXRlLngtdC53aWR0aC8yPyhuLng9MSxyLng9aS54Kk1hdGguYWJzKCh0Lm1heFRyYW5zbGF0ZS54LXQud2lkdGgvMi1lLngpL3Qud2lkdGgpKTplLnk8PXQubWluVHJhbnNsYXRlLnkrdC5oZWlnaHQvMj8obi55PS0xLHIueT1pLnkqTWF0aC5hYnMoKGUueS10LmhlaWdodC8yLXQubWluVHJhbnNsYXRlLnkpL3QuaGVpZ2h0KSk6ZS54PD10Lm1pblRyYW5zbGF0ZS54K3Qud2lkdGgvMiYmKG4ueD0tMSxyLng9aS54Kk1hdGguYWJzKChlLngtdC53aWR0aC8yLXQubWluVHJhbnNsYXRlLngpL3Qud2lkdGgpKSx0LmF1dG9zY3JvbGxJbnRlcnZhbCYmKGNsZWFySW50ZXJ2YWwodC5hdXRvc2Nyb2xsSW50ZXJ2YWwpLHQuYXV0b3Njcm9sbEludGVydmFsPW51bGwsdC5pc0F1dG9TY3JvbGxpbmc9ITEpLDA9PT1uLngmJjA9PT1uLnl8fCh0LmF1dG9zY3JvbGxJbnRlcnZhbD1zZXRJbnRlcnZhbChmdW5jdGlvbigpe3QuaXNBdXRvU2Nyb2xsaW5nPSEwO3ZhciBlPXtsZWZ0OjEqci54Km4ueCx0b3A6MSpyLnkqbi55fTt0LnNjcm9sbENvbnRhaW5lci5zY3JvbGxUb3ArPWUudG9wLHQuc2Nyb2xsQ29udGFpbmVyLnNjcm9sbExlZnQrPWUubGVmdCx0LnRyYW5zbGF0ZS54Kz1lLmxlZnQsdC50cmFuc2xhdGUueSs9ZS50b3AsdC5hbmltYXRlTm9kZXMoKX0sNSkpfSx0Lm1hbmFnZXI9bmV3IHguZGVmYXVsdCx0LmV2ZW50cz17c3RhcnQ6dC5oYW5kbGVTdGFydCxtb3ZlOnQuaGFuZGxlTW92ZSxlbmQ6dC5oYW5kbGVFbmR9LCgwLHYuZGVmYXVsdCkoIShlLmRpc3RhbmNlJiZlLnByZXNzRGVsYXkpLCJBdHRlbXB0ZWQgdG8gc2V0IGJvdGggYHByZXNzRGVsYXlgIGFuZCBgZGlzdGFuY2VgIG9uIFNvcnRhYmxlQ29udGFpbmVyLCB5b3UgbWF5IG9ubHkgdXNlIG9uZSBvciB0aGUgb3RoZXIsIG5vdCBib3RoIGF0IHRoZSBzYW1lIHRpbWUuIiksdC5zdGF0ZT17fSx0fXJldHVybiBzKG4sdCkscChuLFt7a2V5OiJnZXRDaGlsZENvbnRleHQiLHZhbHVlOmZ1bmN0aW9uKCl7cmV0dXJue21hbmFnZXI6dGhpcy5tYW5hZ2VyfX19LHtrZXk6ImNvbXBvbmVudERpZE1vdW50Iix2YWx1ZTpmdW5jdGlvbigpe3ZhciBlPXRoaXMsdD10aGlzLnByb3BzLnVzZVdpbmRvd0FzU2Nyb2xsQ29udGFpbmVyLG49dGhpcy5nZXRDb250YWluZXIoKTtQcm9taXNlLnJlc29sdmUobikudGhlbihmdW5jdGlvbihuKXtlLmNvbnRhaW5lcj1uLGUuZG9jdW1lbnQ9ZS5jb250YWluZXIub3duZXJEb2N1bWVudHx8ZG9jdW1lbnQ7dmFyIHI9ZS5wcm9wcy5jb250ZW50V2luZG93fHxlLmRvY3VtZW50LmRlZmF1bHRWaWV3fHx3aW5kb3c7ZS5jb250ZW50V2luZG93PSJmdW5jdGlvbiI9PT10eXBlb2Ygcj9yKCk6cixlLnNjcm9sbENvbnRhaW5lcj10P2UuZG9jdW1lbnQuc2Nyb2xsaW5nRWxlbWVudHx8ZS5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ6ZS5jb250YWluZXI7Zm9yKHZhciBpIGluIGUuZXZlbnRzKSFmdW5jdGlvbih0KXtlLmV2ZW50cy5oYXNPd25Qcm9wZXJ0eSh0KSYmQy5ldmVudHNbdF0uZm9yRWFjaChmdW5jdGlvbihuKXtyZXR1cm4gZS5jb250YWluZXIuYWRkRXZlbnRMaXN0ZW5lcihuLGUuZXZlbnRzW3RdLCExKX0pfShpKX0pfX0se2tleToiY29tcG9uZW50V2lsbFVubW91bnQiLHZhbHVlOmZ1bmN0aW9uKCl7dmFyIGU9dGhpcztpZih0aGlzLmNvbnRhaW5lcil7Zm9yKHZhciB0IGluIHRoaXMuZXZlbnRzKSFmdW5jdGlvbih0KXtlLmV2ZW50cy5oYXNPd25Qcm9wZXJ0eSh0KSYmQy5ldmVudHNbdF0uZm9yRWFjaChmdW5jdGlvbihuKXtyZXR1cm4gZS5jb250YWluZXIucmVtb3ZlRXZlbnRMaXN0ZW5lcihuLGUuZXZlbnRzW3RdKX0pfSh0KX19fSx7a2V5OiJnZXRMb2NrUGl4ZWxPZmZzZXRzIix2YWx1ZTpmdW5jdGlvbigpe3ZhciBlPXRoaXMud2lkdGgsdD10aGlzLmhlaWdodCxuPXRoaXMucHJvcHMubG9ja09mZnNldCxyPUFycmF5LmlzQXJyYXkobik/bjpbbixuXTsoMCx2LmRlZmF1bHQpKDI9PT1yLmxlbmd0aCwibG9ja09mZnNldCBwcm9wIG9mIFNvcnRhYmxlQ29udGFpbmVyIHNob3VsZCBiZSBhIHNpbmdsZSB2YWx1ZSBvciBhbiBhcnJheSBvZiBleGFjdGx5IHR3byB2YWx1ZXMuIEdpdmVuICVzIixuKTt2YXIgaT1sKHIsMiksbz1pWzBdLGE9aVsxXTtyZXR1cm5bKDAsQy5nZXRMb2NrUGl4ZWxPZmZzZXQpKHtsb2NrT2Zmc2V0Om8sd2lkdGg6ZSxoZWlnaHQ6dH0pLCgwLEMuZ2V0TG9ja1BpeGVsT2Zmc2V0KSh7bG9ja09mZnNldDphLHdpZHRoOmUsaGVpZ2h0OnR9KV19fSx7a2V5OiJ1cGRhdGVQb3NpdGlvbiIsdmFsdWU6ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5wcm9wcyxuPXQubG9ja0F4aXMscj10LmxvY2tUb0NvbnRhaW5lckVkZ2VzLGk9KDAsQy5nZXRQb3NpdGlvbikoZSksbz17eDppLngtdGhpcy5pbml0aWFsT2Zmc2V0LngseTppLnktdGhpcy5pbml0aWFsT2Zmc2V0Lnl9O2lmKG8ueS09d2luZG93LnBhZ2VZT2Zmc2V0LXRoaXMuaW5pdGlhbFdpbmRvd1Njcm9sbC50b3Asby54LT13aW5kb3cucGFnZVhPZmZzZXQtdGhpcy5pbml0aWFsV2luZG93U2Nyb2xsLmxlZnQsdGhpcy50cmFuc2xhdGU9byxyKXt2YXIgYT10aGlzLmdldExvY2tQaXhlbE9mZnNldHMoKSxzPWwoYSwyKSx1PXNbMF0sYz1zWzFdLHA9e3g6dGhpcy53aWR0aC8yLXUueCx5OnRoaXMuaGVpZ2h0LzItdS55fSxmPXt4OnRoaXMud2lkdGgvMi1jLngseTp0aGlzLmhlaWdodC8yLWMueX07by54PSgwLEMubGltaXQpKHRoaXMubWluVHJhbnNsYXRlLngrcC54LHRoaXMubWF4VHJhbnNsYXRlLngtZi54LG8ueCksby55PSgwLEMubGltaXQpKHRoaXMubWluVHJhbnNsYXRlLnkrcC55LHRoaXMubWF4VHJhbnNsYXRlLnktZi55LG8ueSl9IngiPT09bj9vLnk9MDoieSI9PT1uJiYoby54PTApLHRoaXMuaGVscGVyLnN0eWxlW0MudmVuZG9yUHJlZml4KyJUcmFuc2Zvcm0iXT0idHJhbnNsYXRlM2QoIitvLngrInB4LCIrby55KyJweCwgMCkifX0se2tleToiYW5pbWF0ZU5vZGVzIix2YWx1ZTpmdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMsdD1lLnRyYW5zaXRpb25EdXJhdGlvbixuPWUuaGlkZVNvcnRhYmxlR2hvc3Qscj1lLm9uU29ydE92ZXIsaT10aGlzLm1hbmFnZXIuZ2V0T3JkZXJlZFJlZnMoKSxvPXtsZWZ0OnRoaXMuY29udGFpbmVyLnNjcm9sbExlZnQtdGhpcy5pbml0aWFsU2Nyb2xsLmxlZnQsdG9wOnRoaXMuY29udGFpbmVyLnNjcm9sbFRvcC10aGlzLmluaXRpYWxTY3JvbGwudG9wfSxhPXtsZWZ0OnRoaXMub2Zmc2V0RWRnZS5sZWZ0K3RoaXMudHJhbnNsYXRlLngrby5sZWZ0LHRvcDp0aGlzLm9mZnNldEVkZ2UudG9wK3RoaXMudHJhbnNsYXRlLnkrby50b3B9LHM9e3RvcDp3aW5kb3cucGFnZVlPZmZzZXQtdGhpcy5pbml0aWFsV2luZG93U2Nyb2xsLnRvcCxsZWZ0OndpbmRvdy5wYWdlWE9mZnNldC10aGlzLmluaXRpYWxXaW5kb3dTY3JvbGwubGVmdH0sdT10aGlzLm5ld0luZGV4O3RoaXMubmV3SW5kZXg9bnVsbDtmb3IodmFyIGM9MCxsPWkubGVuZ3RoO2M8bDtjKyspe3ZhciBwPWlbY10ubm9kZSxmPXAuc29ydGFibGVJbmZvLmluZGV4LGQ9cC5vZmZzZXRXaWR0aCxoPXAub2Zmc2V0SGVpZ2h0LG09e3dpZHRoOnRoaXMud2lkdGg+ZD9kLzI6dGhpcy53aWR0aC8yLGhlaWdodDp0aGlzLmhlaWdodD5oP2gvMjp0aGlzLmhlaWdodC8yfSxnPXt4OjAseTowfSx5PWlbY10uZWRnZU9mZnNldDt5fHwoaVtjXS5lZGdlT2Zmc2V0PXk9KDAsQy5nZXRFZGdlT2Zmc2V0KShwLHRoaXMuY29udGFpbmVyKSk7dmFyIHY9YzxpLmxlbmd0aC0xJiZpW2MrMV0sYj1jPjAmJmlbYy0xXTt2JiYhdi5lZGdlT2Zmc2V0JiYodi5lZGdlT2Zmc2V0PSgwLEMuZ2V0RWRnZU9mZnNldCkodi5ub2RlLHRoaXMuY29udGFpbmVyKSksZiE9PXRoaXMuaW5kZXg/KHQmJihwLnN0eWxlW0MudmVuZG9yUHJlZml4KyJUcmFuc2l0aW9uRHVyYXRpb24iXT10KyJtcyIpLHRoaXMuYXhpcy54P3RoaXMuYXhpcy55P2Y8dGhpcy5pbmRleCYmKGEubGVmdCtzLmxlZnQtbS53aWR0aDw9eS5sZWZ0JiZhLnRvcCtzLnRvcDw9eS50b3ArbS5oZWlnaHR8fGEudG9wK3MudG9wK20uaGVpZ2h0PD15LnRvcCk/KGcueD10aGlzLndpZHRoK3RoaXMubWFyZ2luT2Zmc2V0LngseS5sZWZ0K2cueD50aGlzLmNvbnRhaW5lckJvdW5kaW5nUmVjdC53aWR0aC1tLndpZHRoJiYoZy54PXYuZWRnZU9mZnNldC5sZWZ0LXkubGVmdCxnLnk9di5lZGdlT2Zmc2V0LnRvcC15LnRvcCksbnVsbD09PXRoaXMubmV3SW5kZXgmJih0aGlzLm5ld0luZGV4PWYpKTpmPnRoaXMuaW5kZXgmJihhLmxlZnQrcy5sZWZ0K20ud2lkdGg+PXkubGVmdCYmYS50b3Arcy50b3ArbS5oZWlnaHQ+PXkudG9wfHxhLnRvcCtzLnRvcCttLmhlaWdodD49eS50b3AraCkmJihnLng9LSh0aGlzLndpZHRoK3RoaXMubWFyZ2luT2Zmc2V0LngpLHkubGVmdCtnLng8dGhpcy5jb250YWluZXJCb3VuZGluZ1JlY3QubGVmdCttLndpZHRoJiYoZy54PWIuZWRnZU9mZnNldC5sZWZ0LXkubGVmdCxnLnk9Yi5lZGdlT2Zmc2V0LnRvcC15LnRvcCksdGhpcy5uZXdJbmRleD1mKTpmPnRoaXMuaW5kZXgmJmEubGVmdCtzLmxlZnQrbS53aWR0aD49eS5sZWZ0PyhnLng9LSh0aGlzLndpZHRoK3RoaXMubWFyZ2luT2Zmc2V0LngpLHRoaXMubmV3SW5kZXg9Zik6Zjx0aGlzLmluZGV4JiZhLmxlZnQrcy5sZWZ0PD15LmxlZnQrbS53aWR0aCYmKGcueD10aGlzLndpZHRoK3RoaXMubWFyZ2luT2Zmc2V0LngsbnVsbD09dGhpcy5uZXdJbmRleCYmKHRoaXMubmV3SW5kZXg9ZikpOnRoaXMuYXhpcy55JiYoZj50aGlzLmluZGV4JiZhLnRvcCtzLnRvcCttLmhlaWdodD49eS50b3A/KGcueT0tKHRoaXMuaGVpZ2h0K3RoaXMubWFyZ2luT2Zmc2V0LnkpLHRoaXMubmV3SW5kZXg9Zik6Zjx0aGlzLmluZGV4JiZhLnRvcCtzLnRvcDw9eS50b3ArbS5oZWlnaHQmJihnLnk9dGhpcy5oZWlnaHQrdGhpcy5tYXJnaW5PZmZzZXQueSxudWxsPT10aGlzLm5ld0luZGV4JiYodGhpcy5uZXdJbmRleD1mKSkpLHAuc3R5bGVbQy52ZW5kb3JQcmVmaXgrIlRyYW5zZm9ybSJdPSJ0cmFuc2xhdGUzZCgiK2cueCsicHgsIitnLnkrInB4LDApIik6biYmKHRoaXMuc29ydGFibGVHaG9zdD1wLHAuc3R5bGUudmlzaWJpbGl0eT0iaGlkZGVuIixwLnN0eWxlLm9wYWNpdHk9MCl9bnVsbD09dGhpcy5uZXdJbmRleCYmKHRoaXMubmV3SW5kZXg9dGhpcy5pbmRleCksciYmdGhpcy5uZXdJbmRleCE9PXUmJnIoe25ld0luZGV4OnRoaXMubmV3SW5kZXgsb2xkSW5kZXg6dSxpbmRleDp0aGlzLmluZGV4LGNvbGxlY3Rpb246dGhpcy5tYW5hZ2VyLmFjdGl2ZS5jb2xsZWN0aW9ufSl9fSx7a2V5OiJnZXRXcmFwcGVkSW5zdGFuY2UiLHZhbHVlOmZ1bmN0aW9uKCl7cmV0dXJuKDAsdi5kZWZhdWx0KShyLndpdGhSZWYsIlRvIGFjY2VzcyB0aGUgd3JhcHBlZCBpbnN0YW5jZSwgeW91IG5lZWQgdG8gcGFzcyBpbiB7d2l0aFJlZjogdHJ1ZX0gYXMgdGhlIHNlY29uZCBhcmd1bWVudCBvZiB0aGUgU29ydGFibGVDb250YWluZXIoKSBjYWxsIiksdGhpcy5yZWZzLndyYXBwZWRJbnN0YW5jZX19LHtrZXk6ImdldENvbnRhaW5lciIsdmFsdWU6ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnByb3BzLmdldENvbnRhaW5lcjtyZXR1cm4iZnVuY3Rpb24iIT09dHlwZW9mIGU/KDAsZy5maW5kRE9NTm9kZSkodGhpcyk6ZShyLndpdGhSZWY/dGhpcy5nZXRXcmFwcGVkSW5zdGFuY2UoKTp2b2lkIDApfX0se2tleToicmVuZGVyIix2YWx1ZTpmdW5jdGlvbigpe3ZhciB0PXIud2l0aFJlZj8id3JhcHBlZEluc3RhbmNlIjpudWxsO3JldHVybiBkLmRlZmF1bHQuY3JlYXRlRWxlbWVudChlLGMoe3JlZjp0fSwoMCxDLm9taXQpKHRoaXMucHJvcHMsImNvbnRlbnRXaW5kb3ciLCJ1c2VXaW5kb3dBc1Njcm9sbENvbnRhaW5lciIsImRpc3RhbmNlIiwiaGVscGVyQ2xhc3MiLCJoaWRlU29ydGFibGVHaG9zdCIsInRyYW5zaXRpb25EdXJhdGlvbiIsInVzZURyYWdIYW5kbGUiLCJwcmVzc0RlbGF5IiwicHJlc3NUaHJlc2hvbGQiLCJzaG91bGRDYW5jZWxTdGFydCIsIm9uU29ydFN0YXJ0Iiwib25Tb3J0TW92ZSIsIm9uU29ydEVuZCIsImF4aXMiLCJsb2NrQXhpcyIsImxvY2tPZmZzZXQiLCJsb2NrVG9Db250YWluZXJFZGdlcyIsImdldENvbnRhaW5lciIsImdldEhlbHBlckRpbWVuc2lvbnMiKSkpfX1dKSxufShmLkNvbXBvbmVudCksdC5kaXNwbGF5TmFtZT0oMCxDLnByb3ZpZGVEaXNwbGF5TmFtZSkoInNvcnRhYmxlTGlzdCIsZSksdC5kZWZhdWx0UHJvcHM9e2F4aXM6InkiLHRyYW5zaXRpb25EdXJhdGlvbjozMDAscHJlc3NEZWxheTowLHByZXNzVGhyZXNob2xkOjUsZGlzdGFuY2U6MCx1c2VXaW5kb3dBc1Njcm9sbENvbnRhaW5lcjohMSxoaWRlU29ydGFibGVHaG9zdDohMCxzaG91bGRDYW5jZWxTdGFydDpmdW5jdGlvbihlKXtpZigtMSE9PVsiaW5wdXQiLCJ0ZXh0YXJlYSIsInNlbGVjdCIsIm9wdGlvbiIsImJ1dHRvbiJdLmluZGV4T2YoZS50YXJnZXQudGFnTmFtZS50b0xvd2VyQ2FzZSgpKSlyZXR1cm4hMH0sbG9ja1RvQ29udGFpbmVyRWRnZXM6ITEsbG9ja09mZnNldDoiNTAlIixnZXRIZWxwZXJEaW1lbnNpb25zOmZ1bmN0aW9uKGUpe3ZhciB0PWUubm9kZTtyZXR1cm57d2lkdGg6dC5vZmZzZXRXaWR0aCxoZWlnaHQ6dC5vZmZzZXRIZWlnaHR9fX0sdC5wcm9wVHlwZXM9e2F4aXM6bS5kZWZhdWx0Lm9uZU9mKFsieCIsInkiLCJ4eSJdKSxkaXN0YW5jZTptLmRlZmF1bHQubnVtYmVyLGxvY2tBeGlzOm0uZGVmYXVsdC5zdHJpbmcsaGVscGVyQ2xhc3M6bS5kZWZhdWx0LnN0cmluZyx0cmFuc2l0aW9uRHVyYXRpb246bS5kZWZhdWx0Lm51bWJlcixjb250ZW50V2luZG93Om0uZGVmYXVsdC5hbnksb25Tb3J0U3RhcnQ6bS5kZWZhdWx0LmZ1bmMsb25Tb3J0TW92ZTptLmRlZmF1bHQuZnVuYyxvblNvcnRPdmVyOm0uZGVmYXVsdC5mdW5jLG9uU29ydEVuZDptLmRlZmF1bHQuZnVuYyxzaG91bGRDYW5jZWxTdGFydDptLmRlZmF1bHQuZnVuYyxwcmVzc0RlbGF5Om0uZGVmYXVsdC5udW1iZXIsdXNlRHJhZ0hhbmRsZTptLmRlZmF1bHQuYm9vbCx1c2VXaW5kb3dBc1Njcm9sbENvbnRhaW5lcjptLmRlZmF1bHQuYm9vbCxoaWRlU29ydGFibGVHaG9zdDptLmRlZmF1bHQuYm9vbCxsb2NrVG9Db250YWluZXJFZGdlczptLmRlZmF1bHQuYm9vbCxsb2NrT2Zmc2V0Om0uZGVmYXVsdC5vbmVPZlR5cGUoW20uZGVmYXVsdC5udW1iZXIsbS5kZWZhdWx0LnN0cmluZyxtLmRlZmF1bHQuYXJyYXlPZihtLmRlZmF1bHQub25lT2ZUeXBlKFttLmRlZmF1bHQubnVtYmVyLG0uZGVmYXVsdC5zdHJpbmddKSldKSxnZXRDb250YWluZXI6bS5kZWZhdWx0LmZ1bmMsZ2V0SGVscGVyRGltZW5zaW9uczptLmRlZmF1bHQuZnVuY30sdC5jaGlsZENvbnRleHRUeXBlcz17bWFuYWdlcjptLmRlZmF1bHQub2JqZWN0LmlzUmVxdWlyZWR9LG59T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBjPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspe3ZhciBuPWFyZ3VtZW50c1t0XTtmb3IodmFyIHIgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmKGVbcl09bltyXSl9cmV0dXJuIGV9LGw9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dmFyIG49W10scj0hMCxpPSExLG89dm9pZCAwO3RyeXtmb3IodmFyIGEscz1lW1N5bWJvbC5pdGVyYXRvcl0oKTshKHI9KGE9cy5uZXh0KCkpLmRvbmUpJiYobi5wdXNoKGEudmFsdWUpLCF0fHxuLmxlbmd0aCE9PXQpO3I9ITApO31jYXRjaChlKXtpPSEwLG89ZX1maW5hbGx5e3RyeXshciYmcy5yZXR1cm4mJnMucmV0dXJuKCl9ZmluYWxseXtpZihpKXRocm93IG99fXJldHVybiBufXJldHVybiBmdW5jdGlvbih0LG4pe2lmKEFycmF5LmlzQXJyYXkodCkpcmV0dXJuIHQ7aWYoU3ltYm9sLml0ZXJhdG9yIGluIE9iamVjdCh0KSlyZXR1cm4gZSh0LG4pO3Rocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgYXR0ZW1wdCB0byBkZXN0cnVjdHVyZSBub24taXRlcmFibGUgaW5zdGFuY2UiKX19KCkscD1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXtmb3IodmFyIG49MDtuPHQubGVuZ3RoO24rKyl7dmFyIHI9dFtuXTtyLmVudW1lcmFibGU9ci5lbnVtZXJhYmxlfHwhMSxyLmNvbmZpZ3VyYWJsZT0hMCwidmFsdWUiaW4gciYmKHIud3JpdGFibGU9ITApLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIua2V5LHIpfX1yZXR1cm4gZnVuY3Rpb24odCxuLHIpe3JldHVybiBuJiZlKHQucHJvdG90eXBlLG4pLHImJmUodCxyKSx0fX0oKTt0LmRlZmF1bHQ9dTt2YXIgZj1uKDApLGQ9cihmKSxoPW4oMjQ3KSxtPXIoaCksZz1uKDMwKSx5PW4oMjApLHY9cih5KSxiPW4oNDk2KSx4PXIoYiksQz1uKDg2KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKCl7fXZhciBpPW4oNDk1KTtlLmV4cG9ydHM9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxuLHIsbyxhKXtpZihhIT09aSl7dmFyIHM9bmV3IEVycm9yKCJDYWxsaW5nIFByb3BUeXBlcyB2YWxpZGF0b3JzIGRpcmVjdGx5IGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGBwcm9wLXR5cGVzYCBwYWNrYWdlLiBVc2UgUHJvcFR5cGVzLmNoZWNrUHJvcFR5cGVzKCkgdG8gY2FsbCB0aGVtLiBSZWFkIG1vcmUgYXQgaHR0cDovL2ZiLm1lL3VzZS1jaGVjay1wcm9wLXR5cGVzIik7dGhyb3cgcy5uYW1lPSJJbnZhcmlhbnQgVmlvbGF0aW9uIixzfX1mdW5jdGlvbiB0KCl7cmV0dXJuIGV9ZS5pc1JlcXVpcmVkPWU7dmFyIG49e2FycmF5OmUsYm9vbDplLGZ1bmM6ZSxudW1iZXI6ZSxvYmplY3Q6ZSxzdHJpbmc6ZSxzeW1ib2w6ZSxhbnk6ZSxhcnJheU9mOnQsZWxlbWVudDplLGluc3RhbmNlT2Y6dCxub2RlOmUsb2JqZWN0T2Y6dCxvbmVPZjp0LG9uZU9mVHlwZTp0LHNoYXBlOnQsZXhhY3Q6dH07cmV0dXJuIG4uY2hlY2tQcm9wVHlwZXM9cixuLlByb3BUeXBlcz1uLG59fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz0iU0VDUkVUX0RPX05PVF9QQVNTX1RISVNfT1JfWU9VX1dJTExfQkVfRklSRUQifSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBpKGUsdCl7cmV0dXJuIGUubm9kZS5zb3J0YWJsZUluZm8uaW5kZXgtdC5ub2RlLnNvcnRhYmxlSW5mby5pbmRleH1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7Zm9yKHZhciBuPTA7bjx0Lmxlbmd0aDtuKyspe3ZhciByPXRbbl07ci5lbnVtZXJhYmxlPXIuZW51bWVyYWJsZXx8ITEsci5jb25maWd1cmFibGU9ITAsInZhbHVlImluIHImJihyLndyaXRhYmxlPSEwKSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZSxyLmtleSxyKX19cmV0dXJuIGZ1bmN0aW9uKHQsbixyKXtyZXR1cm4gbiYmZSh0LnByb3RvdHlwZSxuKSxyJiZlKHQsciksdH19KCksYT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXtyKHRoaXMsZSksdGhpcy5yZWZzPXt9fXJldHVybiBvKGUsW3trZXk6ImFkZCIsdmFsdWU6ZnVuY3Rpb24oZSx0KXt0aGlzLnJlZnNbZV18fCh0aGlzLnJlZnNbZV09W10pLHRoaXMucmVmc1tlXS5wdXNoKHQpfX0se2tleToicmVtb3ZlIix2YWx1ZTpmdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMuZ2V0SW5kZXgoZSx0KTstMSE9PW4mJnRoaXMucmVmc1tlXS5zcGxpY2UobiwxKX19LHtrZXk6ImlzQWN0aXZlIix2YWx1ZTpmdW5jdGlvbigpe3JldHVybiB0aGlzLmFjdGl2ZX19LHtrZXk6ImdldEFjdGl2ZSIsdmFsdWU6ZnVuY3Rpb24oKXt2YXIgZT10aGlzO3JldHVybiB0aGlzLnJlZnNbdGhpcy5hY3RpdmUuY29sbGVjdGlvbl0uZmluZChmdW5jdGlvbih0KXtyZXR1cm4gdC5ub2RlLnNvcnRhYmxlSW5mby5pbmRleD09ZS5hY3RpdmUuaW5kZXh9KX19LHtrZXk6ImdldEluZGV4Iix2YWx1ZTpmdW5jdGlvbihlLHQpe3JldHVybiB0aGlzLnJlZnNbZV0uaW5kZXhPZih0KX19LHtrZXk6ImdldE9yZGVyZWRSZWZzIix2YWx1ZTpmdW5jdGlvbigpe3ZhciBlPWFyZ3VtZW50cy5sZW5ndGg+MCYmdm9pZCAwIT09YXJndW1lbnRzWzBdP2FyZ3VtZW50c1swXTp0aGlzLmFjdGl2ZS5jb2xsZWN0aW9uO3JldHVybiB0aGlzLnJlZnNbZV0uc29ydChpKX19XSksZX0oKTt0LmRlZmF1bHQ9YX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1mdW5jdGlvbiBpKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9ZnVuY3Rpb24gbyhlLHQpe2lmKCFlKXRocm93IG5ldyBSZWZlcmVuY2VFcnJvcigidGhpcyBoYXNuJ3QgYmVlbiBpbml0aWFsaXNlZCAtIHN1cGVyKCkgaGFzbid0IGJlZW4gY2FsbGVkIik7cmV0dXJuIXR8fCJvYmplY3QiIT09dHlwZW9mIHQmJiJmdW5jdGlvbiIhPT10eXBlb2YgdD9lOnR9ZnVuY3Rpb24gYShlLHQpe2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgdCYmbnVsbCE9PXQpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3VwZXIgZXhwcmVzc2lvbiBtdXN0IGVpdGhlciBiZSBudWxsIG9yIGEgZnVuY3Rpb24sIG5vdCAiK3R5cGVvZiB0KTtlLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKHQmJnQucHJvdG90eXBlLHtjb25zdHJ1Y3Rvcjp7dmFsdWU6ZSxlbnVtZXJhYmxlOiExLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH19KSx0JiYoT2JqZWN0LnNldFByb3RvdHlwZU9mP09iamVjdC5zZXRQcm90b3R5cGVPZihlLHQpOmUuX19wcm90b19fPXQpfWZ1bmN0aW9uIHMoZSl7dmFyIHQsbixyPWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7d2l0aFJlZjohMX07cmV0dXJuIG49dD1mdW5jdGlvbih0KXtmdW5jdGlvbiBuKCl7cmV0dXJuIGkodGhpcyxuKSxvKHRoaXMsKG4uX19wcm90b19ffHxPYmplY3QuZ2V0UHJvdG90eXBlT2YobikpLmFwcGx5KHRoaXMsYXJndW1lbnRzKSl9cmV0dXJuIGEobix0KSxjKG4sW3trZXk6ImNvbXBvbmVudERpZE1vdW50Iix2YWx1ZTpmdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMsdD1lLmNvbGxlY3Rpb24sbj1lLmRpc2FibGVkLHI9ZS5pbmRleDtufHx0aGlzLnNldERyYWdnYWJsZSh0LHIpfX0se2tleToiY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wcyIsdmFsdWU6ZnVuY3Rpb24oZSl7aWYodGhpcy5wcm9wcy5pbmRleCE9PWUuaW5kZXgmJnRoaXMubm9kZSYmKHRoaXMubm9kZS5zb3J0YWJsZUluZm8uaW5kZXg9ZS5pbmRleCksdGhpcy5wcm9wcy5kaXNhYmxlZCE9PWUuZGlzYWJsZWQpe3ZhciB0PWUuY29sbGVjdGlvbixuPWUuZGlzYWJsZWQscj1lLmluZGV4O24/dGhpcy5yZW1vdmVEcmFnZ2FibGUodCk6dGhpcy5zZXREcmFnZ2FibGUodCxyKX1lbHNlIHRoaXMucHJvcHMuY29sbGVjdGlvbiE9PWUuY29sbGVjdGlvbiYmKHRoaXMucmVtb3ZlRHJhZ2dhYmxlKHRoaXMucHJvcHMuY29sbGVjdGlvbiksdGhpcy5zZXREcmFnZ2FibGUoZS5jb2xsZWN0aW9uLGUuaW5kZXgpKX19LHtrZXk6ImNvbXBvbmVudFdpbGxVbm1vdW50Iix2YWx1ZTpmdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMsdD1lLmNvbGxlY3Rpb247ZS5kaXNhYmxlZHx8dGhpcy5yZW1vdmVEcmFnZ2FibGUodCl9fSx7a2V5OiJzZXREcmFnZ2FibGUiLHZhbHVlOmZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5ub2RlPSgwLGguZmluZERPTU5vZGUpKHRoaXMpO24uc29ydGFibGVJbmZvPXtpbmRleDp0LGNvbGxlY3Rpb246ZSxtYW5hZ2VyOnRoaXMuY29udGV4dC5tYW5hZ2VyfSx0aGlzLnJlZj17bm9kZTpufSx0aGlzLmNvbnRleHQubWFuYWdlci5hZGQoZSx0aGlzLnJlZil9fSx7a2V5OiJyZW1vdmVEcmFnZ2FibGUiLHZhbHVlOmZ1bmN0aW9uKGUpe3RoaXMuY29udGV4dC5tYW5hZ2VyLnJlbW92ZShlLHRoaXMucmVmKX19LHtrZXk6ImdldFdyYXBwZWRJbnN0YW5jZSIsdmFsdWU6ZnVuY3Rpb24oKXtyZXR1cm4oMCxnLmRlZmF1bHQpKHIud2l0aFJlZiwiVG8gYWNjZXNzIHRoZSB3cmFwcGVkIGluc3RhbmNlLCB5b3UgbmVlZCB0byBwYXNzIGluIHt3aXRoUmVmOiB0cnVlfSBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IG9mIHRoZSBTb3J0YWJsZUVsZW1lbnQoKSBjYWxsIiksdGhpcy5yZWZzLndyYXBwZWRJbnN0YW5jZX19LHtrZXk6InJlbmRlciIsdmFsdWU6ZnVuY3Rpb24oKXt2YXIgdD1yLndpdGhSZWY/IndyYXBwZWRJbnN0YW5jZSI6bnVsbDtyZXR1cm4gcC5kZWZhdWx0LmNyZWF0ZUVsZW1lbnQoZSx1KHtyZWY6dH0sKDAseS5vbWl0KSh0aGlzLnByb3BzLCJjb2xsZWN0aW9uIiwiZGlzYWJsZWQiLCJpbmRleCIpKSl9fV0pLG59KGwuQ29tcG9uZW50KSx0LmRpc3BsYXlOYW1lPSgwLHkucHJvdmlkZURpc3BsYXlOYW1lKSgic29ydGFibGVFbGVtZW50IixlKSx0LmNvbnRleHRUeXBlcz17bWFuYWdlcjpkLmRlZmF1bHQub2JqZWN0LmlzUmVxdWlyZWR9LHQucHJvcFR5cGVzPXtpbmRleDpkLmRlZmF1bHQubnVtYmVyLmlzUmVxdWlyZWQsY29sbGVjdGlvbjpkLmRlZmF1bHQub25lT2ZUeXBlKFtkLmRlZmF1bHQubnVtYmVyLGQuZGVmYXVsdC5zdHJpbmddKSxkaXNhYmxlZDpkLmRlZmF1bHQuYm9vbH0sdC5kZWZhdWx0UHJvcHM9e2NvbGxlY3Rpb246MH0sbn1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHU9T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTE7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyl7dmFyIG49YXJndW1lbnRzW3RdO2Zvcih2YXIgciBpbiBuKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChuLHIpJiYoZVtyXT1uW3JdKX1yZXR1cm4gZX0sYz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXtmb3IodmFyIG49MDtuPHQubGVuZ3RoO24rKyl7dmFyIHI9dFtuXTtyLmVudW1lcmFibGU9ci5lbnVtZXJhYmxlfHwhMSxyLmNvbmZpZ3VyYWJsZT0hMCwidmFsdWUiaW4gciYmKHIud3JpdGFibGU9ITApLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIua2V5LHIpfX1yZXR1cm4gZnVuY3Rpb24odCxuLHIpe3JldHVybiBuJiZlKHQucHJvdG90eXBlLG4pLHImJmUodCxyKSx0fX0oKTt0LmRlZmF1bHQ9czt2YXIgbD1uKDApLHA9cihsKSxmPW4oMjQ3KSxkPXIoZiksaD1uKDMwKSxtPW4oMjApLGc9cihtKSx5PW4oODYpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBvKGUsdCl7aWYoIWUpdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKCJ0aGlzIGhhc24ndCBiZWVuIGluaXRpYWxpc2VkIC0gc3VwZXIoKSBoYXNuJ3QgYmVlbiBjYWxsZWQiKTtyZXR1cm4hdHx8Im9iamVjdCIhPT10eXBlb2YgdCYmImZ1bmN0aW9uIiE9PXR5cGVvZiB0P2U6dH1mdW5jdGlvbiBhKGUsdCl7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJTdXBlciBleHByZXNzaW9uIG11c3QgZWl0aGVyIGJlIG51bGwgb3IgYSBmdW5jdGlvbiwgbm90ICIrdHlwZW9mIHQpO2UucHJvdG90eXBlPU9iamVjdC5jcmVhdGUodCYmdC5wcm90b3R5cGUse2NvbnN0cnVjdG9yOnt2YWx1ZTplLGVudW1lcmFibGU6ITEsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfX0pLHQmJihPYmplY3Quc2V0UHJvdG90eXBlT2Y/T2JqZWN0LnNldFByb3RvdHlwZU9mKGUsdCk6ZS5fX3Byb3RvX189dCl9ZnVuY3Rpb24gcyhlKXt2YXIgdCxuLHI9YXJndW1lbnRzLmxlbmd0aD4xJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0/YXJndW1lbnRzWzFdOnt3aXRoUmVmOiExfTtyZXR1cm4gbj10PWZ1bmN0aW9uKHQpe2Z1bmN0aW9uIG4oKXtyZXR1cm4gaSh0aGlzLG4pLG8odGhpcywobi5fX3Byb3RvX198fE9iamVjdC5nZXRQcm90b3R5cGVPZihuKSkuYXBwbHkodGhpcyxhcmd1bWVudHMpKX1yZXR1cm4gYShuLHQpLGMobixbe2tleToiY29tcG9uZW50RGlkTW91bnQiLHZhbHVlOmZ1bmN0aW9uKCl7KDAsZi5maW5kRE9NTm9kZSkodGhpcykuc29ydGFibGVIYW5kbGU9ITB9fSx7a2V5OiJnZXRXcmFwcGVkSW5zdGFuY2UiLHZhbHVlOmZ1bmN0aW9uKCl7cmV0dXJuKDAsaC5kZWZhdWx0KShyLndpdGhSZWYsIlRvIGFjY2VzcyB0aGUgd3JhcHBlZCBpbnN0YW5jZSwgeW91IG5lZWQgdG8gcGFzcyBpbiB7d2l0aFJlZjogdHJ1ZX0gYXMgdGhlIHNlY29uZCBhcmd1bWVudCBvZiB0aGUgU29ydGFibGVIYW5kbGUoKSBjYWxsIiksdGhpcy5yZWZzLndyYXBwZWRJbnN0YW5jZX19LHtrZXk6InJlbmRlciIsdmFsdWU6ZnVuY3Rpb24oKXt2YXIgdD1yLndpdGhSZWY/IndyYXBwZWRJbnN0YW5jZSI6bnVsbDtyZXR1cm4gcC5kZWZhdWx0LmNyZWF0ZUVsZW1lbnQoZSx1KHtyZWY6dH0sdGhpcy5wcm9wcykpfX1dKSxufShsLkNvbXBvbmVudCksdC5kaXNwbGF5TmFtZT0oMCxtLnByb3ZpZGVEaXNwbGF5TmFtZSkoInNvcnRhYmxlSGFuZGxlIixlKSxufU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgdT1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfSxjPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe2Zvcih2YXIgbj0wO248dC5sZW5ndGg7bisrKXt2YXIgcj10W25dO3IuZW51bWVyYWJsZT1yLmVudW1lcmFibGV8fCExLHIuY29uZmlndXJhYmxlPSEwLCJ2YWx1ZSJpbiByJiYoci53cml0YWJsZT0hMCksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsci5rZXkscil9fXJldHVybiBmdW5jdGlvbih0LG4scil7cmV0dXJuIG4mJmUodC5wcm90b3R5cGUsbiksciYmZSh0LHIpLHR9fSgpO3QuZGVmYXVsdD1zO3ZhciBsPW4oMCkscD1yKGwpLGY9bigzMCksZD1uKDIwKSxoPXIoZCksbT1uKDg2KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9bigxNCksaT1uKDIzKSxvPW4oNjQpO3QuZGVmYXVsdEhpc3RvcnlTdGF0ZT1yLk9yZGVyZWRNYXAoe30pLHQuZGVmYXVsdD1pLmhhbmRsZUFjdGlvbnMoe1RPR0dMRV9ISVNUT1JZX0lURU1fU1RBUlJJTkc6ZnVuY3Rpb24oZSx0KXt2YXIgbj10LnBheWxvYWQuc2Vzc2lvbklkO3JldHVybiBlLnNldEluKFtuLCJzdGFycmVkIl0sIWUuZ2V0SW4oW24sInN0YXJyZWQiXSkpfSxBRERfSElTVE9SWV9JVEVNOmZ1bmN0aW9uKGUsdCl7dmFyIG49dC5wYXlsb2FkLnNlc3Npb24saT1vKCk7cmV0dXJuIGUuc2xpY2UoLTQwKS5zZXQoaSxuLm1lcmdlKHtpZDppLGRhdGU6bmV3IERhdGUscmVzcG9uc2VzOnIuTGlzdCgpfSkpfX0sdC5kZWZhdWx0SGlzdG9yeVN0YXRlKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0O3JldHVybiBmdW5jdGlvbihuKXt2YXIgcj1lKG4pO3JldHVybiBpLmlzKHQscil8fCh0PXIpLHR9fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDE0KTt0LmltbXV0YWJsZU1lbW9pemU9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3JldHVybiByPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPTEscj1hcmd1bWVudHMubGVuZ3RoO248cjtuKyspe3Q9YXJndW1lbnRzW25dO2Zvcih2YXIgaSBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LGkpJiYoZVtpXT10W2ldKX1yZXR1cm4gZX0sci5hcHBseSh0aGlzLGFyZ3VtZW50cyl9LGk9ZnVuY3Rpb24oZSx0LG4scil7cmV0dXJuIG5ldyhufHwobj1Qcm9taXNlKSkoZnVuY3Rpb24oaSxvKXtmdW5jdGlvbiBhKGUpe3RyeXt1KHIubmV4dChlKSl9Y2F0Y2goZSl7byhlKX19ZnVuY3Rpb24gcyhlKXt0cnl7dShyLnRocm93KGUpKX1jYXRjaChlKXtvKGUpfX1mdW5jdGlvbiB1KGUpe2UuZG9uZT9pKGUudmFsdWUpOm5ldyBuKGZ1bmN0aW9uKHQpe3QoZS52YWx1ZSl9KS50aGVuKGEscyl9dSgocj1yLmFwcGx5KGUsdHx8W10pKS5uZXh0KCkpfSl9LG89ZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gcihbZSx0XSl9fWZ1bmN0aW9uIHIobil7aWYoaSl0aHJvdyBuZXcgVHlwZUVycm9yKCJHZW5lcmF0b3IgaXMgYWxyZWFkeSBleGVjdXRpbmcuIik7Zm9yKDt1Oyl0cnl7aWYoaT0xLG8mJihhPTImblswXT9vLnJldHVybjpuWzBdP28udGhyb3d8fCgoYT1vLnJldHVybikmJmEuY2FsbChvKSwwKTpvLm5leHQpJiYhKGE9YS5jYWxsKG8sblsxXSkpLmRvbmUpcmV0dXJuIGE7c3dpdGNoKG89MCxhJiYobj1bMiZuWzBdLGEudmFsdWVdKSxuWzBdKXtjYXNlIDA6Y2FzZSAxOmE9bjticmVhaztjYXNlIDQ6cmV0dXJuIHUubGFiZWwrKyx7dmFsdWU6blsxXSxkb25lOiExfTtjYXNlIDU6dS5sYWJlbCsrLG89blsxXSxuPVswXTtjb250aW51ZTtjYXNlIDc6bj11Lm9wcy5wb3AoKSx1LnRyeXMucG9wKCk7Y29udGludWU7ZGVmYXVsdDppZihhPXUudHJ5cywhKGE9YS5sZW5ndGg+MCYmYVthLmxlbmd0aC0xXSkmJig2PT09blswXXx8Mj09PW5bMF0pKXt1PTA7Y29udGludWV9aWYoMz09PW5bMF0mJighYXx8blsxXT5hWzBdJiZuWzFdPGFbM10pKXt1LmxhYmVsPW5bMV07YnJlYWt9aWYoNj09PW5bMF0mJnUubGFiZWw8YVsxXSl7dS5sYWJlbD1hWzFdLGE9bjticmVha31pZihhJiZ1LmxhYmVsPGFbMl0pe3UubGFiZWw9YVsyXSx1Lm9wcy5wdXNoKG4pO2JyZWFrfWFbMl0mJnUub3BzLnBvcCgpLHUudHJ5cy5wb3AoKTtjb250aW51ZX1uPXQuY2FsbChlLHUpfWNhdGNoKGUpe249WzYsZV0sbz0wfWZpbmFsbHl7aT1hPTB9aWYoNSZuWzBdKXRocm93IG5bMV07cmV0dXJue3ZhbHVlOm5bMF0/blsxXTp2b2lkIDAsZG9uZTohMH19dmFyIGksbyxhLHMsdT17bGFiZWw6MCxzZW50OmZ1bmN0aW9uKCl7aWYoMSZhWzBdKXRocm93IGFbMV07cmV0dXJuIGFbMV19LHRyeXM6W10sb3BzOltdfTtyZXR1cm4gcz17bmV4dDpuKDApLHRocm93Om4oMSkscmV0dXJuOm4oMil9LCJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiYoc1tTeW1ib2wuaXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9KSxzfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGE9big3KSxzPW4oNTAyKSx1PW4oNzgpLGM9bigxNCksbD1uKDE3OCkscD1uKDE3NSksZj1uKDI1MiksZD1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy5zdWJzY3JpcHRpb25zPWMuTWFwKCksdGhpcy5zZXNzaW9uQ2FjaGU9bmV3IGYoe21heDoxMH0pLHRoaXMuc2NoZW1hSW5zdGFuY2VDYWNoZT1uZXcgZih7bWF4OjEwfSksdGhpcy5mZXRjaGluZz1jLk1hcCgpLHRoaXMubGlua0dldHRlcj1lfXJldHVybiBlLnByb3RvdHlwZS5mZXRjaD1mdW5jdGlvbihlKXtyZXR1cm4gaSh0aGlzLHZvaWQgMCx2b2lkIDAsZnVuY3Rpb24oKXt2YXIgdCxuLHIsaTtyZXR1cm4gbyh0aGlzLGZ1bmN0aW9uKG8pe3JldHVybiB0PXRoaXMuaGFzaChlKSwobj10aGlzLnNlc3Npb25DYWNoZS5nZXQodCkpP1syLG5dOihyPXRoaXMuZmV0Y2hpbmcuZ2V0KHQpKT9bMixyXTooaT10aGlzLmZldGNoU2NoZW1hKGUpLHRoaXMuZmV0Y2hpbmc9dGhpcy5mZXRjaGluZy5zZXQodCxpKSxbMixpXSl9KX0pfSxlLnByb3RvdHlwZS5zdWJzY3JpYmU9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLmhhc2goZSk7dGhpcy5zdWJzY3JpcHRpb25zPXRoaXMuc3Vic2NyaXB0aW9ucy5zZXQobix0KX0sZS5wcm90b3R5cGUucmVmZXRjaD1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5mZXRjaFNjaGVtYShlKX0sZS5wcm90b3R5cGUuaGFzaD1mdW5jdGlvbihlKXtyZXR1cm4gZS5lbmRwb2ludCsifiIrKGUuaGVhZGVyc3x8IiIpfSxlLnByb3RvdHlwZS5nZXRTY2hlbWE9ZnVuY3Rpb24oZSl7dmFyIHQ9SlNPTi5zdHJpbmdpZnkoZSksbj10aGlzLnNjaGVtYUluc3RhbmNlQ2FjaGUuZ2V0KHQpO2lmKG4pcmV0dXJuIG47dmFyIHI9YS5idWlsZENsaWVudFNjaGVtYShlKTtyZXR1cm4gdGhpcy5zY2hlbWFJbnN0YW5jZUNhY2hlLnNldCh0LHIpLHJ9LGUucHJvdG90eXBlLmZldGNoU2NoZW1hPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMsbj10aGlzLmhhc2goZSksaT1lLmVuZHBvaW50LG89cih7fSxwLnBhcnNlSGVhZGVycyhlLmhlYWRlcnMpLHsiWC1BcG9sbG8tVHJhY2luZyI6IjEifSksZj1jLnNldChlLCJoZWFkZXJzIixvKSxkPXRoaXMubGlua0dldHRlcihmKS5saW5rLGg9bC5tYWtlT3BlcmF0aW9uKHtxdWVyeTphLmludHJvc3BlY3Rpb25RdWVyeX0pO3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyLG8pe3UuZXhlY3V0ZShkLGgpLnN1YnNjcmliZSh7bmV4dDpmdW5jdGlvbihvKXtpZihvJiYoby5lcnJvcnMmJm8uZXJyb3JzLmxlbmd0aD4wfHwhby5kYXRhKSl0aHJvdyBuZXcgRXJyb3IoSlNPTi5zdHJpbmdpZnkobyxudWxsLDIpKTtpZighbyl0aHJvdyBuZXcgcy5Ob1NjaGVtYUVycm9yKGkpO3ZhciBhPXQuZ2V0U2NoZW1hKG8uZGF0YSksdT1vLmV4dGVuc2lvbnMmJkJvb2xlYW4oby5leHRlbnNpb25zLnRyYWNpbmcpfHwhMSxjPXtzY2hlbWE6YSx0cmFjaW5nU3VwcG9ydGVkOnV9O3Quc2Vzc2lvbkNhY2hlLnNldCh0Lmhhc2goZSksYykscihjKSx0LmZldGNoaW5nPXQuZmV0Y2hpbmcucmVtb3ZlKG4pO3ZhciBsPXQuc3Vic2NyaXB0aW9ucy5nZXQobik7bCYmbChjLnNjaGVtYSl9LGVycm9yOmZ1bmN0aW9uKG4pe28obiksdC5mZXRjaGluZz10LmZldGNoaW5nLnJlbW92ZSh0Lmhhc2goZSkpfX0pfSl9LGV9KCk7dC5TY2hlbWFGZXRjaGVyPWR9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0KXtyZXR1cm4gZS5jYWxsKHRoaXMsIlNjaGVtYSBjb3VsZCBub3QgYmUgZmV0Y2hlZC5cblBsZWFzZSBjaGVjayBpZiB0aGUgZW5kcG9pbnQgJyIrdCsiJyBpcyBhIHZhbGlkIEdyYXBoUUwgRW5kcG9pbnQuIil8fHRoaXN9cmV0dXJuIHIodCxlKSx0fShFcnJvcik7dC5Ob1NjaGVtYUVycm9yPWl9LGZ1bmN0aW9uKGUsdCxuKXsicHNldWRvbWFwIj09PU9iamVjdCh7Tk9ERV9FTlY6InByb2R1Y3Rpb24iLFBVQkxJQ19VUkw6IiJ9KS5ucG1fcGFja2FnZV9uYW1lJiYidGVzdCI9PT1PYmplY3Qoe05PREVfRU5WOiJwcm9kdWN0aW9uIixQVUJMSUNfVVJMOiIifSkubnBtX2xpZmVjeWNsZV9zY3JpcHQmJihPYmplY3Qoe05PREVfRU5WOiJwcm9kdWN0aW9uIixQVUJMSUNfVVJMOiIifSkuVEVTVF9QU0VVRE9NQVA9InRydWUiKSwiZnVuY3Rpb24iIT09dHlwZW9mIE1hcHx8T2JqZWN0KHtOT0RFX0VOVjoicHJvZHVjdGlvbiIsUFVCTElDX1VSTDoiIn0pLlRFU1RfUFNFVURPTUFQP2UuZXhwb3J0cz1uKDUwNCk6ZS5leHBvcnRzPU1hcH0sZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe2lmKCEodGhpcyBpbnN0YW5jZW9mIG4pKXRocm93IG5ldyBUeXBlRXJyb3IoIkNvbnN0cnVjdG9yIFBzZXVkb01hcCByZXF1aXJlcyAnbmV3JyIpO2lmKHRoaXMuY2xlYXIoKSxlKWlmKGUgaW5zdGFuY2VvZiBufHwiZnVuY3Rpb24iPT09dHlwZW9mIE1hcCYmZSBpbnN0YW5jZW9mIE1hcCllLmZvckVhY2goZnVuY3Rpb24oZSx0KXt0aGlzLnNldCh0LGUpfSx0aGlzKTtlbHNle2lmKCFBcnJheS5pc0FycmF5KGUpKXRocm93IG5ldyBUeXBlRXJyb3IoImludmFsaWQgYXJndW1lbnQiKTtlLmZvckVhY2goZnVuY3Rpb24oZSl7dGhpcy5zZXQoZVswXSxlWzFdKX0sdGhpcyl9fWZ1bmN0aW9uIHIoZSx0KXtyZXR1cm4gZT09PXR8fGUhPT1lJiZ0IT09dH1mdW5jdGlvbiBpKGUsdCxuKXt0aGlzLmtleT1lLHRoaXMudmFsdWU9dCx0aGlzLl9pbmRleD1ufWZ1bmN0aW9uIG8oZSx0KXtmb3IodmFyIG49MCxpPSJfIit0LG89aTtzLmNhbGwoZSxvKTtvPWkrbisrKWlmKHIoZVtvXS5rZXksdCkpcmV0dXJuIGVbb119ZnVuY3Rpb24gYShlLHQsbil7Zm9yKHZhciBvPTAsYT0iXyIrdCx1PWE7cy5jYWxsKGUsdSk7dT1hK28rKylpZihyKGVbdV0ua2V5LHQpKXJldHVybiB2b2lkKGVbdV0udmFsdWU9bik7ZS5zaXplKyssZVt1XT1uZXcgaSh0LG4sdSl9dmFyIHM9T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtlLmV4cG9ydHM9bixuLnByb3RvdHlwZS5mb3JFYWNoPWZ1bmN0aW9uKGUsdCl7dD10fHx0aGlzLE9iamVjdC5rZXlzKHRoaXMuX2RhdGEpLmZvckVhY2goZnVuY3Rpb24obil7InNpemUiIT09biYmZS5jYWxsKHQsdGhpcy5fZGF0YVtuXS52YWx1ZSx0aGlzLl9kYXRhW25dLmtleSl9LHRoaXMpfSxuLnByb3RvdHlwZS5oYXM9ZnVuY3Rpb24oZSl7cmV0dXJuISFvKHRoaXMuX2RhdGEsZSl9LG4ucHJvdG90eXBlLmdldD1mdW5jdGlvbihlKXt2YXIgdD1vKHRoaXMuX2RhdGEsZSk7cmV0dXJuIHQmJnQudmFsdWV9LG4ucHJvdG90eXBlLnNldD1mdW5jdGlvbihlLHQpe2EodGhpcy5fZGF0YSxlLHQpfSxuLnByb3RvdHlwZS5kZWxldGU9ZnVuY3Rpb24oZSl7dmFyIHQ9byh0aGlzLl9kYXRhLGUpO3QmJihkZWxldGUgdGhpcy5fZGF0YVt0Ll9pbmRleF0sdGhpcy5fZGF0YS5zaXplLS0pfSxuLnByb3RvdHlwZS5jbGVhcj1mdW5jdGlvbigpe3ZhciBlPU9iamVjdC5jcmVhdGUobnVsbCk7ZS5zaXplPTAsT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIl9kYXRhIix7dmFsdWU6ZSxlbnVtZXJhYmxlOiExLGNvbmZpZ3VyYWJsZTohMCx3cml0YWJsZTohMX0pfSxPYmplY3QuZGVmaW5lUHJvcGVydHkobi5wcm90b3R5cGUsInNpemUiLHtnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fZGF0YS5zaXplfSxzZXQ6ZnVuY3Rpb24oZSl7fSxlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pLG4ucHJvdG90eXBlLnZhbHVlcz1uLnByb3RvdHlwZS5rZXlzPW4ucHJvdG90eXBlLmVudHJpZXM9ZnVuY3Rpb24oKXt0aHJvdyBuZXcgRXJyb3IoIml0ZXJhdG9ycyBhcmUgbm90IGltcGxlbWVudGVkIGluIHRoaXMgdmVyc2lvbiIpfX0sZnVuY3Rpb24oZSx0KXtlLmV4cG9ydHM9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJvYmplY3QiPT09dHlwZW9mIGUmJiJmdW5jdGlvbiI9PT10eXBlb2YgZS5jb3B5JiYiZnVuY3Rpb24iPT09dHlwZW9mIGUuZmlsbCYmImZ1bmN0aW9uIj09PXR5cGVvZiBlLnJlYWRVSW50OH19LGZ1bmN0aW9uKGUsdCl7ImZ1bmN0aW9uIj09PXR5cGVvZiBPYmplY3QuY3JlYXRlP2UuZXhwb3J0cz1mdW5jdGlvbihlLHQpe2Uuc3VwZXJfPXQsZS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZSh0LnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOmUsZW51bWVyYWJsZTohMSx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9fSl9OmUuZXhwb3J0cz1mdW5jdGlvbihlLHQpe2Uuc3VwZXJfPXQ7dmFyIG49ZnVuY3Rpb24oKXt9O24ucHJvdG90eXBlPXQucHJvdG90eXBlLGUucHJvdG90eXBlPW5ldyBuLGUucHJvdG90eXBlLmNvbnN0cnVjdG9yPWV9fSxmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7dmFyIHQ9dGhpcztpZih0IGluc3RhbmNlb2Ygbnx8KHQ9bmV3IG4pLHQudGFpbD1udWxsLHQuaGVhZD1udWxsLHQubGVuZ3RoPTAsZSYmImZ1bmN0aW9uIj09PXR5cGVvZiBlLmZvckVhY2gpZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3QucHVzaChlKX0pO2Vsc2UgaWYoYXJndW1lbnRzLmxlbmd0aD4wKWZvcih2YXIgcj0wLGk9YXJndW1lbnRzLmxlbmd0aDtyPGk7cisrKXQucHVzaChhcmd1bWVudHNbcl0pO3JldHVybiB0fWZ1bmN0aW9uIHIoZSx0KXtlLnRhaWw9bmV3IG8odCxlLnRhaWwsbnVsbCxlKSxlLmhlYWR8fChlLmhlYWQ9ZS50YWlsKSxlLmxlbmd0aCsrfWZ1bmN0aW9uIGkoZSx0KXtlLmhlYWQ9bmV3IG8odCxudWxsLGUuaGVhZCxlKSxlLnRhaWx8fChlLnRhaWw9ZS5oZWFkKSxlLmxlbmd0aCsrfWZ1bmN0aW9uIG8oZSx0LG4scil7aWYoISh0aGlzIGluc3RhbmNlb2YgbykpcmV0dXJuIG5ldyBvKGUsdCxuLHIpO3RoaXMubGlzdD1yLHRoaXMudmFsdWU9ZSx0Pyh0Lm5leHQ9dGhpcyx0aGlzLnByZXY9dCk6dGhpcy5wcmV2PW51bGwsbj8obi5wcmV2PXRoaXMsdGhpcy5uZXh0PW4pOnRoaXMubmV4dD1udWxsfWUuZXhwb3J0cz1uLG4uTm9kZT1vLG4uY3JlYXRlPW4sbi5wcm90b3R5cGUucmVtb3ZlTm9kZT1mdW5jdGlvbihlKXtpZihlLmxpc3QhPT10aGlzKXRocm93IG5ldyBFcnJvcigicmVtb3Zpbmcgbm9kZSB3aGljaCBkb2VzIG5vdCBiZWxvbmcgdG8gdGhpcyBsaXN0Iik7dmFyIHQ9ZS5uZXh0LG49ZS5wcmV2O3QmJih0LnByZXY9biksbiYmKG4ubmV4dD10KSxlPT09dGhpcy5oZWFkJiYodGhpcy5oZWFkPXQpLGU9PT10aGlzLnRhaWwmJih0aGlzLnRhaWw9biksZS5saXN0Lmxlbmd0aC0tLGUubmV4dD1udWxsLGUucHJldj1udWxsLGUubGlzdD1udWxsfSxuLnByb3RvdHlwZS51bnNoaWZ0Tm9kZT1mdW5jdGlvbihlKXtpZihlIT09dGhpcy5oZWFkKXtlLmxpc3QmJmUubGlzdC5yZW1vdmVOb2RlKGUpO3ZhciB0PXRoaXMuaGVhZDtlLmxpc3Q9dGhpcyxlLm5leHQ9dCx0JiYodC5wcmV2PWUpLHRoaXMuaGVhZD1lLHRoaXMudGFpbHx8KHRoaXMudGFpbD1lKSx0aGlzLmxlbmd0aCsrfX0sbi5wcm90b3R5cGUucHVzaE5vZGU9ZnVuY3Rpb24oZSl7aWYoZSE9PXRoaXMudGFpbCl7ZS5saXN0JiZlLmxpc3QucmVtb3ZlTm9kZShlKTt2YXIgdD10aGlzLnRhaWw7ZS5saXN0PXRoaXMsZS5wcmV2PXQsdCYmKHQubmV4dD1lKSx0aGlzLnRhaWw9ZSx0aGlzLmhlYWR8fCh0aGlzLmhlYWQ9ZSksdGhpcy5sZW5ndGgrK319LG4ucHJvdG90eXBlLnB1c2g9ZnVuY3Rpb24oKXtmb3IodmFyIGU9MCx0PWFyZ3VtZW50cy5sZW5ndGg7ZTx0O2UrKylyKHRoaXMsYXJndW1lbnRzW2VdKTtyZXR1cm4gdGhpcy5sZW5ndGh9LG4ucHJvdG90eXBlLnVuc2hpZnQ9ZnVuY3Rpb24oKXtmb3IodmFyIGU9MCx0PWFyZ3VtZW50cy5sZW5ndGg7ZTx0O2UrKylpKHRoaXMsYXJndW1lbnRzW2VdKTtyZXR1cm4gdGhpcy5sZW5ndGh9LG4ucHJvdG90eXBlLnBvcD1mdW5jdGlvbigpe2lmKHRoaXMudGFpbCl7dmFyIGU9dGhpcy50YWlsLnZhbHVlO3JldHVybiB0aGlzLnRhaWw9dGhpcy50YWlsLnByZXYsdGhpcy50YWlsP3RoaXMudGFpbC5uZXh0PW51bGw6dGhpcy5oZWFkPW51bGwsdGhpcy5sZW5ndGgtLSxlfX0sbi5wcm90b3R5cGUuc2hpZnQ9ZnVuY3Rpb24oKXtpZih0aGlzLmhlYWQpe3ZhciBlPXRoaXMuaGVhZC52YWx1ZTtyZXR1cm4gdGhpcy5oZWFkPXRoaXMuaGVhZC5uZXh0LHRoaXMuaGVhZD90aGlzLmhlYWQucHJldj1udWxsOnRoaXMudGFpbD1udWxsLHRoaXMubGVuZ3RoLS0sZX19LG4ucHJvdG90eXBlLmZvckVhY2g9ZnVuY3Rpb24oZSx0KXt0PXR8fHRoaXM7Zm9yKHZhciBuPXRoaXMuaGVhZCxyPTA7bnVsbCE9PW47cisrKWUuY2FsbCh0LG4udmFsdWUscix0aGlzKSxuPW4ubmV4dH0sbi5wcm90b3R5cGUuZm9yRWFjaFJldmVyc2U9ZnVuY3Rpb24oZSx0KXt0PXR8fHRoaXM7Zm9yKHZhciBuPXRoaXMudGFpbCxyPXRoaXMubGVuZ3RoLTE7bnVsbCE9PW47ci0tKWUuY2FsbCh0LG4udmFsdWUscix0aGlzKSxuPW4ucHJldn0sbi5wcm90b3R5cGUuZ2V0PWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0wLG49dGhpcy5oZWFkO251bGwhPT1uJiZ0PGU7dCsrKW49bi5uZXh0O2lmKHQ9PT1lJiZudWxsIT09bilyZXR1cm4gbi52YWx1ZX0sbi5wcm90b3R5cGUuZ2V0UmV2ZXJzZT1mdW5jdGlvbihlKXtmb3IodmFyIHQ9MCxuPXRoaXMudGFpbDtudWxsIT09biYmdDxlO3QrKyluPW4ucHJldjtpZih0PT09ZSYmbnVsbCE9PW4pcmV0dXJuIG4udmFsdWV9LG4ucHJvdG90eXBlLm1hcD1mdW5jdGlvbihlLHQpe3Q9dHx8dGhpcztmb3IodmFyIHI9bmV3IG4saT10aGlzLmhlYWQ7bnVsbCE9PWk7KXIucHVzaChlLmNhbGwodCxpLnZhbHVlLHRoaXMpKSxpPWkubmV4dDtyZXR1cm4gcn0sbi5wcm90b3R5cGUubWFwUmV2ZXJzZT1mdW5jdGlvbihlLHQpe3Q9dHx8dGhpcztmb3IodmFyIHI9bmV3IG4saT10aGlzLnRhaWw7bnVsbCE9PWk7KXIucHVzaChlLmNhbGwodCxpLnZhbHVlLHRoaXMpKSxpPWkucHJldjtyZXR1cm4gcn0sbi5wcm90b3R5cGUucmVkdWNlPWZ1bmN0aW9uKGUsdCl7dmFyIG4scj10aGlzLmhlYWQ7aWYoYXJndW1lbnRzLmxlbmd0aD4xKW49dDtlbHNle2lmKCF0aGlzLmhlYWQpdGhyb3cgbmV3IFR5cGVFcnJvcigiUmVkdWNlIG9mIGVtcHR5IGxpc3Qgd2l0aCBubyBpbml0aWFsIHZhbHVlIik7cj10aGlzLmhlYWQubmV4dCxuPXRoaXMuaGVhZC52YWx1ZX1mb3IodmFyIGk9MDtudWxsIT09cjtpKyspbj1lKG4sci52YWx1ZSxpKSxyPXIubmV4dDtyZXR1cm4gbn0sbi5wcm90b3R5cGUucmVkdWNlUmV2ZXJzZT1mdW5jdGlvbihlLHQpe3ZhciBuLHI9dGhpcy50YWlsO2lmKGFyZ3VtZW50cy5sZW5ndGg+MSluPXQ7ZWxzZXtpZighdGhpcy50YWlsKXRocm93IG5ldyBUeXBlRXJyb3IoIlJlZHVjZSBvZiBlbXB0eSBsaXN0IHdpdGggbm8gaW5pdGlhbCB2YWx1ZSIpO3I9dGhpcy50YWlsLnByZXYsbj10aGlzLnRhaWwudmFsdWV9Zm9yKHZhciBpPXRoaXMubGVuZ3RoLTE7bnVsbCE9PXI7aS0tKW49ZShuLHIudmFsdWUsaSkscj1yLnByZXY7cmV0dXJuIG59LG4ucHJvdG90eXBlLnRvQXJyYXk9ZnVuY3Rpb24oKXtmb3IodmFyIGU9bmV3IEFycmF5KHRoaXMubGVuZ3RoKSx0PTAsbj10aGlzLmhlYWQ7bnVsbCE9PW47dCsrKWVbdF09bi52YWx1ZSxuPW4ubmV4dDtyZXR1cm4gZX0sbi5wcm90b3R5cGUudG9BcnJheVJldmVyc2U9ZnVuY3Rpb24oKXtmb3IodmFyIGU9bmV3IEFycmF5KHRoaXMubGVuZ3RoKSx0PTAsbj10aGlzLnRhaWw7bnVsbCE9PW47dCsrKWVbdF09bi52YWx1ZSxuPW4ucHJldjtyZXR1cm4gZX0sbi5wcm90b3R5cGUuc2xpY2U9ZnVuY3Rpb24oZSx0KXt0PXR8fHRoaXMubGVuZ3RoLHQ8MCYmKHQrPXRoaXMubGVuZ3RoKSwoZT1lfHwwKTwwJiYoZSs9dGhpcy5sZW5ndGgpO3ZhciByPW5ldyBuO2lmKHQ8ZXx8dDwwKXJldHVybiByO2U8MCYmKGU9MCksdD50aGlzLmxlbmd0aCYmKHQ9dGhpcy5sZW5ndGgpO2Zvcih2YXIgaT0wLG89dGhpcy5oZWFkO251bGwhPT1vJiZpPGU7aSsrKW89by5uZXh0O2Zvcig7bnVsbCE9PW8mJmk8dDtpKyssbz1vLm5leHQpci5wdXNoKG8udmFsdWUpO3JldHVybiByfSxuLnByb3RvdHlwZS5zbGljZVJldmVyc2U9ZnVuY3Rpb24oZSx0KXt0PXR8fHRoaXMubGVuZ3RoLHQ8MCYmKHQrPXRoaXMubGVuZ3RoKSwoZT1lfHwwKTwwJiYoZSs9dGhpcy5sZW5ndGgpO3ZhciByPW5ldyBuO2lmKHQ8ZXx8dDwwKXJldHVybiByO2U8MCYmKGU9MCksdD50aGlzLmxlbmd0aCYmKHQ9dGhpcy5sZW5ndGgpO2Zvcih2YXIgaT10aGlzLmxlbmd0aCxvPXRoaXMudGFpbDtudWxsIT09byYmaT50O2ktLSlvPW8ucHJldjtmb3IoO251bGwhPT1vJiZpPmU7aS0tLG89by5wcmV2KXIucHVzaChvLnZhbHVlKTtyZXR1cm4gcn0sbi5wcm90b3R5cGUucmV2ZXJzZT1mdW5jdGlvbigpe2Zvcih2YXIgZT10aGlzLmhlYWQsdD10aGlzLnRhaWwsbj1lO251bGwhPT1uO249bi5wcmV2KXt2YXIgcj1uLnByZXY7bi5wcmV2PW4ubmV4dCxuLm5leHQ9cn1yZXR1cm4gdGhpcy5oZWFkPXQsdGhpcy50YWlsPWUsdGhpc319LGZ1bmN0aW9uKG1vZHVsZSxleHBvcnRzLF9fd2VicGFja19yZXF1aXJlX18peyhmdW5jdGlvbihnbG9iYWwpeyFmdW5jdGlvbihlLHQpe21vZHVsZS5leHBvcnRzPXQoKX0oMCxmdW5jdGlvbigpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiB1bndyYXBFeHBvcnRzKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGUmJk9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLCJkZWZhdWx0Iik/ZS5kZWZhdWx0OmV9ZnVuY3Rpb24gY3JlYXRlQ29tbW9uanNNb2R1bGUoZSx0KXtyZXR1cm4gdD17ZXhwb3J0czp7fX0sZSh0LHQuZXhwb3J0cyksdC5leHBvcnRzfWZ1bmN0aW9uIF90eXBlb2YoZSl7cmV0dXJuKF90eXBlb2Y9ImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJiJzeW1ib2wiPT09dHlwZW9mIFN5bWJvbC5pdGVyYXRvcj9mdW5jdGlvbihlKXtyZXR1cm4gdHlwZW9mIGV9OmZ1bmN0aW9uKGUpe3JldHVybiBlJiYiZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmZS5jb25zdHJ1Y3Rvcj09PVN5bWJvbCYmZSE9PVN5bWJvbC5wcm90b3R5cGU/InN5bWJvbCI6dHlwZW9mIGV9KShlKX1mdW5jdGlvbiBfY2xhc3NDYWxsQ2hlY2soZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBfZGVmaW5lUHJvcGVydHkoZSx0LG4pe3JldHVybiB0IGluIGU/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsdCx7dmFsdWU6bixlbnVtZXJhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMCx3cml0YWJsZTohMH0pOmVbdF09bixlfWZ1bmN0aW9uIF9pbmhlcml0cyhlLHQpe2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgdCYmbnVsbCE9PXQpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3VwZXIgZXhwcmVzc2lvbiBtdXN0IGVpdGhlciBiZSBudWxsIG9yIGEgZnVuY3Rpb24iKTtlLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKHQmJnQucHJvdG90eXBlLHtjb25zdHJ1Y3Rvcjp7dmFsdWU6ZSx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9fSksdCYmX3NldFByb3RvdHlwZU9mKGUsdCl9ZnVuY3Rpb24gX2dldFByb3RvdHlwZU9mKGUpe3JldHVybihfZ2V0UHJvdG90eXBlT2Y9T2JqZWN0LnNldFByb3RvdHlwZU9mP09iamVjdC5nZXRQcm90b3R5cGVPZjpmdW5jdGlvbihlKXtyZXR1cm4gZS5fX3Byb3RvX198fE9iamVjdC5nZXRQcm90b3R5cGVPZihlKX0pKGUpfWZ1bmN0aW9uIF9zZXRQcm90b3R5cGVPZihlLHQpe3JldHVybihfc2V0UHJvdG90eXBlT2Y9T2JqZWN0LnNldFByb3RvdHlwZU9mfHxmdW5jdGlvbihlLHQpe3JldHVybiBlLl9fcHJvdG9fXz10LGV9KShlLHQpfWZ1bmN0aW9uIGlzTmF0aXZlUmVmbGVjdENvbnN0cnVjdCgpe2lmKCJ1bmRlZmluZWQiPT09dHlwZW9mIFJlZmxlY3R8fCFSZWZsZWN0LmNvbnN0cnVjdClyZXR1cm4hMTtpZihSZWZsZWN0LmNvbnN0cnVjdC5zaGFtKXJldHVybiExO2lmKCJmdW5jdGlvbiI9PT10eXBlb2YgUHJveHkpcmV0dXJuITA7dHJ5e3JldHVybiBEYXRlLnByb3RvdHlwZS50b1N0cmluZy5jYWxsKFJlZmxlY3QuY29uc3RydWN0KERhdGUsW10sZnVuY3Rpb24oKXt9KSksITB9Y2F0Y2goZSl7cmV0dXJuITF9fWZ1bmN0aW9uIF9jb25zdHJ1Y3QoZSx0LG4pe3JldHVybiBfY29uc3RydWN0PWlzTmF0aXZlUmVmbGVjdENvbnN0cnVjdCgpP1JlZmxlY3QuY29uc3RydWN0OmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1bbnVsbF07ci5wdXNoLmFwcGx5KHIsdCk7dmFyIGk9RnVuY3Rpb24uYmluZC5hcHBseShlLHIpLG89bmV3IGk7cmV0dXJuIG4mJl9zZXRQcm90b3R5cGVPZihvLG4ucHJvdG90eXBlKSxvfSxfY29uc3RydWN0LmFwcGx5KG51bGwsYXJndW1lbnRzKX1mdW5jdGlvbiBfd3JhcE5hdGl2ZVN1cGVyKGUpe3ZhciB0PSJmdW5jdGlvbiI9PT10eXBlb2YgTWFwP25ldyBNYXA6dm9pZCAwO3JldHVybihfd3JhcE5hdGl2ZVN1cGVyPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIG4oKXtyZXR1cm4gX2NvbnN0cnVjdChlLGFyZ3VtZW50cyxfZ2V0UHJvdG90eXBlT2YodGhpcykuY29uc3RydWN0b3IpfWlmKG51bGw9PT1lKXJldHVybiBudWxsO2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgZSl0aHJvdyBuZXcgVHlwZUVycm9yKCJTdXBlciBleHByZXNzaW9uIG11c3QgZWl0aGVyIGJlIG51bGwgb3IgYSBmdW5jdGlvbiIpO2lmKCJ1bmRlZmluZWQiIT09dHlwZW9mIHQpe2lmKHQuaGFzKGUpKXJldHVybiB0LmdldChlKTt0LnNldChlLG4pfXJldHVybiBuLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUucHJvdG90eXBlLHtjb25zdHJ1Y3Rvcjp7dmFsdWU6bixlbnVtZXJhYmxlOiExLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH19KSxfc2V0UHJvdG90eXBlT2YobixlKX0pKGUpfWZ1bmN0aW9uIF9hc3NlcnRUaGlzSW5pdGlhbGl6ZWQoZSl7aWYodm9pZCAwPT09ZSl0aHJvdyBuZXcgUmVmZXJlbmNlRXJyb3IoInRoaXMgaGFzbid0IGJlZW4gaW5pdGlhbGlzZWQgLSBzdXBlcigpIGhhc24ndCBiZWVuIGNhbGxlZCIpO3JldHVybiBlfWZ1bmN0aW9uIF9wb3NzaWJsZUNvbnN0cnVjdG9yUmV0dXJuKGUsdCl7cmV0dXJuIXR8fCJvYmplY3QiIT09dHlwZW9mIHQmJiJmdW5jdGlvbiIhPT10eXBlb2YgdD9fYXNzZXJ0VGhpc0luaXRpYWxpemVkKGUpOnR9ZnVuY3Rpb24gX3RhZ2dlZFRlbXBsYXRlTGl0ZXJhbChlLHQpe3JldHVybiB0fHwodD1lLnNsaWNlKDApKSxPYmplY3QuZnJlZXplKE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKGUse3Jhdzp7dmFsdWU6T2JqZWN0LmZyZWV6ZSh0KX19KSl9ZnVuY3Rpb24gX3NsaWNlZFRvQXJyYXkoZSx0KXtyZXR1cm4gX2FycmF5V2l0aEhvbGVzKGUpfHxfaXRlcmFibGVUb0FycmF5TGltaXQoZSx0KXx8X25vbkl0ZXJhYmxlUmVzdCgpfWZ1bmN0aW9uIF9hcnJheVdpdGhIb2xlcyhlKXtpZihBcnJheS5pc0FycmF5KGUpKXJldHVybiBlfWZ1bmN0aW9uIF9pdGVyYWJsZVRvQXJyYXlMaW1pdChlLHQpe3ZhciBuPVtdLHI9ITAsaT0hMSxvPXZvaWQgMDt0cnl7Zm9yKHZhciBhLHM9ZVtTeW1ib2wuaXRlcmF0b3JdKCk7IShyPShhPXMubmV4dCgpKS5kb25lKSYmKG4ucHVzaChhLnZhbHVlKSwhdHx8bi5sZW5ndGghPT10KTtyPSEwKTt9Y2F0Y2goZSl7aT0hMCxvPWV9ZmluYWxseXt0cnl7cnx8bnVsbD09cy5yZXR1cm58fHMucmV0dXJuKCl9ZmluYWxseXtpZihpKXRocm93IG99fXJldHVybiBufWZ1bmN0aW9uIF9ub25JdGVyYWJsZVJlc3QoKXt0aHJvdyBuZXcgVHlwZUVycm9yKCJJbnZhbGlkIGF0dGVtcHQgdG8gZGVzdHJ1Y3R1cmUgbm9uLWl0ZXJhYmxlIGluc3RhbmNlIil9ZnVuY3Rpb24gZGVmYXVsdFNldFRpbW91dCgpe3Rocm93IG5ldyBFcnJvcigic2V0VGltZW91dCBoYXMgbm90IGJlZW4gZGVmaW5lZCIpfWZ1bmN0aW9uIGRlZmF1bHRDbGVhclRpbWVvdXQoKXt0aHJvdyBuZXcgRXJyb3IoImNsZWFyVGltZW91dCBoYXMgbm90IGJlZW4gZGVmaW5lZCIpfWZ1bmN0aW9uIHJ1blRpbWVvdXQoZSl7aWYoY2FjaGVkU2V0VGltZW91dD09PXNldFRpbWVvdXQpcmV0dXJuIHNldFRpbWVvdXQoZSwwKTtpZigoY2FjaGVkU2V0VGltZW91dD09PWRlZmF1bHRTZXRUaW1vdXR8fCFjYWNoZWRTZXRUaW1lb3V0KSYmc2V0VGltZW91dClyZXR1cm4gY2FjaGVkU2V0VGltZW91dD1zZXRUaW1lb3V0LHNldFRpbWVvdXQoZSwwKTt0cnl7cmV0dXJuIGNhY2hlZFNldFRpbWVvdXQoZSwwKX1jYXRjaCh0KXt0cnl7cmV0dXJuIGNhY2hlZFNldFRpbWVvdXQuY2FsbChudWxsLGUsMCl9Y2F0Y2godCl7cmV0dXJuIGNhY2hlZFNldFRpbWVvdXQuY2FsbCh0aGlzLGUsMCl9fX1mdW5jdGlvbiBydW5DbGVhclRpbWVvdXQoZSl7aWYoY2FjaGVkQ2xlYXJUaW1lb3V0PT09Y2xlYXJUaW1lb3V0KXJldHVybiBjbGVhclRpbWVvdXQoZSk7aWYoKGNhY2hlZENsZWFyVGltZW91dD09PWRlZmF1bHRDbGVhclRpbWVvdXR8fCFjYWNoZWRDbGVhclRpbWVvdXQpJiZjbGVhclRpbWVvdXQpcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dD1jbGVhclRpbWVvdXQsY2xlYXJUaW1lb3V0KGUpO3RyeXtyZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0KGUpfWNhdGNoKHQpe3RyeXtyZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0LmNhbGwobnVsbCxlKX1jYXRjaCh0KXtyZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0LmNhbGwodGhpcyxlKX19fWZ1bmN0aW9uIGNsZWFuVXBOZXh0VGljaygpe2RyYWluaW5nJiZjdXJyZW50UXVldWUmJihkcmFpbmluZz0hMSxjdXJyZW50UXVldWUubGVuZ3RoP3F1ZXVlPWN1cnJlbnRRdWV1ZS5jb25jYXQocXVldWUpOnF1ZXVlSW5kZXg9LTEscXVldWUubGVuZ3RoJiZkcmFpblF1ZXVlKCkpfWZ1bmN0aW9uIGRyYWluUXVldWUoKXtpZighZHJhaW5pbmcpe3ZhciBlPXJ1blRpbWVvdXQoY2xlYW5VcE5leHRUaWNrKTtkcmFpbmluZz0hMDtmb3IodmFyIHQ9cXVldWUubGVuZ3RoO3Q7KXtmb3IoY3VycmVudFF1ZXVlPXF1ZXVlLHF1ZXVlPVtdOysrcXVldWVJbmRleDx0OyljdXJyZW50UXVldWUmJmN1cnJlbnRRdWV1ZVtxdWV1ZUluZGV4XS5ydW4oKTtxdWV1ZUluZGV4PS0xLHQ9cXVldWUubGVuZ3RofWN1cnJlbnRRdWV1ZT1udWxsLGRyYWluaW5nPSExLHJ1bkNsZWFyVGltZW91dChlKX19ZnVuY3Rpb24gbmV4dFRpY2soZSl7dmFyIHQ9bmV3IEFycmF5KGFyZ3VtZW50cy5sZW5ndGgtMSk7aWYoYXJndW1lbnRzLmxlbmd0aD4xKWZvcih2YXIgbj0xO248YXJndW1lbnRzLmxlbmd0aDtuKyspdFtuLTFdPWFyZ3VtZW50c1tuXTtxdWV1ZS5wdXNoKG5ldyBJdGVtKGUsdCkpLDEhPT1xdWV1ZS5sZW5ndGh8fGRyYWluaW5nfHxydW5UaW1lb3V0KGRyYWluUXVldWUpfWZ1bmN0aW9uIEl0ZW0oZSx0KXt0aGlzLmZ1bj1lLHRoaXMuYXJyYXk9dH1mdW5jdGlvbiBub29wKCl7fWZ1bmN0aW9uIGJpbmRpbmcoZSl7dGhyb3cgbmV3IEVycm9yKCJwcm9jZXNzLmJpbmRpbmcgaXMgbm90IHN1cHBvcnRlZCIpfWZ1bmN0aW9uIGN3ZCgpe3JldHVybiIvIn1mdW5jdGlvbiBjaGRpcihlKXt0aHJvdyBuZXcgRXJyb3IoInByb2Nlc3MuY2hkaXIgaXMgbm90IHN1cHBvcnRlZCIpfWZ1bmN0aW9uIHVtYXNrKCl7cmV0dXJuIDB9ZnVuY3Rpb24gaHJ0aW1lKGUpe3ZhciB0PS4wMDEqcGVyZm9ybWFuY2VOb3cuY2FsbChwZXJmb3JtYW5jZSksbj1NYXRoLmZsb29yKHQpLHI9TWF0aC5mbG9vcih0JTEqMWU5KTtyZXR1cm4gZSYmKG4tPWVbMF0sKHItPWVbMV0pPDAmJihuLS0scis9MWU5KSksW24scl19ZnVuY3Rpb24gdXB0aW1lKCl7cmV0dXJuKG5ldyBEYXRlLXN0YXJ0VGltZSkvMWUzfWZ1bmN0aW9uIF90ZW1wbGF0ZU9iamVjdDUoKXt2YXIgZT1fdGFnZ2VkVGVtcGxhdGVMaXRlcmFsKFsiXG4gICAgICBSZXF1aXJlIGVpdGhlciAnQHByZXR0aWVyJyBvciAnQGZvcm1hdCcgdG8gYmUgcHJlc2VudCBpbiB0aGUgZmlsZSdzIGZpcnN0IGRvY2Jsb2NrIGNvbW1lbnRcbiAgICAgIGluIG9yZGVyIGZvciBpdCB0byBiZSBmb3JtYXR0ZWQuXG4gICAgIl0pO3JldHVybiBfdGVtcGxhdGVPYmplY3Q1PWZ1bmN0aW9uKCl7cmV0dXJuIGV9LGV9ZnVuY3Rpb24gX3RlbXBsYXRlT2JqZWN0NCgpe3ZhciBlPV90YWdnZWRUZW1wbGF0ZUxpdGVyYWwoWyJcbiAgICAgIEZvcm1hdCBjb2RlIHN0YXJ0aW5nIGF0IGEgZ2l2ZW4gY2hhcmFjdGVyIG9mZnNldC5cbiAgICAgIFRoZSByYW5nZSB3aWxsIGV4dGVuZCBiYWNrd2FyZHMgdG8gdGhlIHN0YXJ0IG9mIHRoZSBmaXJzdCBsaW5lIGNvbnRhaW5pbmcgdGhlIHNlbGVjdGVkIHN0YXRlbWVudC5cbiAgICAgIFRoaXMgb3B0aW9uIGNhbm5vdCBiZSB1c2VkIHdpdGggLS1jdXJzb3Itb2Zmc2V0LlxuICAgICJdKTtyZXR1cm4gX3RlbXBsYXRlT2JqZWN0ND1mdW5jdGlvbigpe3JldHVybiBlfSxlfWZ1bmN0aW9uIF90ZW1wbGF0ZU9iamVjdDMoKXt2YXIgZT1fdGFnZ2VkVGVtcGxhdGVMaXRlcmFsKFsiXG4gICAgICBGb3JtYXQgY29kZSBlbmRpbmcgYXQgYSBnaXZlbiBjaGFyYWN0ZXIgb2Zmc2V0IChleGNsdXNpdmUpLlxuICAgICAgVGhlIHJhbmdlIHdpbGwgZXh0ZW5kIGZvcndhcmRzIHRvIHRoZSBlbmQgb2YgdGhlIHNlbGVjdGVkIHN0YXRlbWVudC5cbiAgICAgIFRoaXMgb3B0aW9uIGNhbm5vdCBiZSB1c2VkIHdpdGggLS1jdXJzb3Itb2Zmc2V0LlxuICAgICJdKTtyZXR1cm4gX3RlbXBsYXRlT2JqZWN0Mz1mdW5jdGlvbigpe3JldHVybiBlfSxlfWZ1bmN0aW9uIF90ZW1wbGF0ZU9iamVjdDIoKXt2YXIgZT1fdGFnZ2VkVGVtcGxhdGVMaXRlcmFsKFsiXG4gICAgICBDdXN0b20gZGlyZWN0b3J5IHRoYXQgY29udGFpbnMgcHJldHRpZXIgcGx1Z2lucyBpbiBub2RlX21vZHVsZXMgc3ViZGlyZWN0b3J5LlxuICAgICAgT3ZlcnJpZGVzIGRlZmF1bHQgYmVoYXZpb3Igd2hlbiBwbHVnaW5zIGFyZSBzZWFyY2hlZCByZWxhdGl2ZWx5IHRvIHRoZSBsb2NhdGlvbiBvZiBQcmV0dGllci5cbiAgICAgIE11bHRpcGxlIHZhbHVlcyBhcmUgYWNjZXB0ZWQuXG4gICAgIl0pO3JldHVybiBfdGVtcGxhdGVPYmplY3QyPWZ1bmN0aW9uKCl7cmV0dXJuIGV9LGV9ZnVuY3Rpb24gX3RlbXBsYXRlT2JqZWN0KCl7dmFyIGU9X3RhZ2dlZFRlbXBsYXRlTGl0ZXJhbChbIlxuICAgICAgUHJpbnQgKHRvIHN0ZGVycikgd2hlcmUgYSBjdXJzb3IgYXQgdGhlIGdpdmVuIHBvc2l0aW9uIHdvdWxkIG1vdmUgdG8gYWZ0ZXIgZm9ybWF0dGluZy5cbiAgICAgIFRoaXMgb3B0aW9uIGNhbm5vdCBiZSB1c2VkIHdpdGggLS1yYW5nZS1zdGFydCBhbmQgLS1yYW5nZS1lbmQuXG4gICAgIl0pO3JldHVybiBfdGVtcGxhdGVPYmplY3Q9ZnVuY3Rpb24oKXtyZXR1cm4gZX0sZX1mdW5jdGlvbiBnZXRTdXBwb3J0SW5mbyQyKGUsdCl7ZnVuY3Rpb24gbihuKXtyZXR1cm4gdC5zaG93VW5yZWxlYXNlZHx8ISgic2luY2UiaW4gbil8fG4uc2luY2UmJnNlbXZlci5ndGUoZSxuLnNpbmNlKX1mdW5jdGlvbiByKG4pe3JldHVybiB0LnNob3dEZXByZWNhdGVkfHwhKCJkZXByZWNhdGVkImluIG4pfHxuLmRlcHJlY2F0ZWQmJnNlbXZlci5sdChlLG4uZGVwcmVjYXRlZCl9ZnVuY3Rpb24gaShlKXtpZighZS5kZXByZWNhdGVkfHx0LnNob3dEZXByZWNhdGVkKXJldHVybiBlO3ZhciBuPU9iamVjdC5hc3NpZ24oe30sZSk7cmV0dXJuIGRlbGV0ZSBuLmRlcHJlY2F0ZWQsZGVsZXRlIG4ucmVkaXJlY3Qsbn1mdW5jdGlvbiBvKGUpe2lmKHQuc2hvd0ludGVybmFsKXJldHVybiBlO3ZhciBuPU9iamVjdC5hc3NpZ24oe30sZSk7cmV0dXJuIGRlbGV0ZSBuLmNsaU5hbWUsZGVsZXRlIG4uY2xpQ2F0ZWdvcnksZGVsZXRlIG4uY2xpRGVzY3JpcHRpb24sbn10PU9iamVjdC5hc3NpZ24oe3BsdWdpbnM6W10sc2hvd1VucmVsZWFzZWQ6ITEsc2hvd0RlcHJlY2F0ZWQ6ITEsc2hvd0ludGVybmFsOiExfSx0KSxlfHwoZT1jdXJyZW50VmVyc2lvbik7dmFyIGE9dC5wbHVnaW5zLHM9YXJyYXlpZnkoT2JqZWN0LmFzc2lnbihhLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuYXNzaWduKGUsdC5vcHRpb25zKX0se30pLGNvcmVPcHRpb25zKSwibmFtZSIpLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5uYW1lPT09dC5uYW1lPzA6ZS5uYW1lPHQubmFtZT8tMToxfSkuZmlsdGVyKG4pLmZpbHRlcihyKS5tYXAoaSkubWFwKG8pLm1hcChmdW5jdGlvbihlKXt2YXIgdD1PYmplY3QuYXNzaWduKHt9LGUpO3JldHVybiBBcnJheS5pc0FycmF5KHQuZGVmYXVsdCkmJih0LmRlZmF1bHQ9MT09PXQuZGVmYXVsdC5sZW5ndGg/dC5kZWZhdWx0WzBdLnZhbHVlOnQuZGVmYXVsdC5maWx0ZXIobikuc29ydChmdW5jdGlvbihlLHQpe3JldHVybiBzZW12ZXIuY29tcGFyZSh0LnNpbmNlLGUuc2luY2UpfSlbMF0udmFsdWUpLEFycmF5LmlzQXJyYXkodC5jaG9pY2VzKSYmKHQuY2hvaWNlcz10LmNob2ljZXMuZmlsdGVyKG4pLmZpbHRlcihyKS5tYXAoaSkpLHR9KS5tYXAoZnVuY3Rpb24oZSl7dmFyIHQ9YS5maWx0ZXIoZnVuY3Rpb24odCl7cmV0dXJuIHQuZGVmYXVsdE9wdGlvbnMmJnQuZGVmYXVsdE9wdGlvbnNbZS5uYW1lXX0pLG49dC5yZWR1Y2UoZnVuY3Rpb24odCxuKXtyZXR1cm4gdFtuLm5hbWVdPW4uZGVmYXVsdE9wdGlvbnNbZS5uYW1lXSx0fSx7fSk7cmV0dXJuIE9iamVjdC5hc3NpZ24oZSx7cGx1Z2luRGVmYXVsdHM6bn0pfSksdT1zZW12ZXIubHQoZSwiMS43LjEiKTtyZXR1cm57bGFuZ3VhZ2VzOmEucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuY29uY2F0KHQubGFuZ3VhZ2VzfHxbXSl9LFtdKS5maWx0ZXIoZnVuY3Rpb24odCl7cmV0dXJuIHQuc2luY2U/c2VtdmVyLmd0ZShlLHQuc2luY2UpOm51bGwhPT10LnNpbmNlfSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiJNYXJrZG93biI9PT1lLm5hbWU/T2JqZWN0LmFzc2lnbih7fSxlLHtwYXJzZXJzOlsibWFya2Rvd24iXX0pOiJUeXBlU2NyaXB0Ij09PWUubmFtZT9PYmplY3QuYXNzaWduKHt9LGUse3BhcnNlcnM6WyJ0eXBlc2NyaXB0Il19KTp1JiYiQ1NTIj09PWUuZ3JvdXA/T2JqZWN0LmFzc2lnbih7fSxlLHtwYXJzZXJzOlsicG9zdGNzcyJdfSk6ZX0pLG9wdGlvbnM6c319ZnVuY3Rpb24gYXBpRGVzY3JpcHRvcihlLHQpe3JldHVybiAxPT09YXJndW1lbnRzLmxlbmd0aD9KU09OLnN0cmluZ2lmeShlKToiYHsgIi5jb25jYXQoYXBpRGVzY3JpcHRvcihlKSwiOiAiKS5jb25jYXQoSlNPTi5zdHJpbmdpZnkodCksIiB9YCIpfWZ1bmN0aW9uIGNsaURlc2NyaXB0b3IoZSx0KXtyZXR1cm4hMT09PXQ/ImAtLW5vLSIuY29uY2F0KGUsImAiKTohMD09PXR8fDE9PT1hcmd1bWVudHMubGVuZ3RoPyJgLS0iLmNvbmNhdChlLCJgIik6IiI9PT10PyJgLS0iLmNvbmNhdChlLCJgIHdpdGhvdXQgYW4gYXJndW1lbnQiKToiYC0tIi5jb25jYXQoZSwiPSIpLmNvbmNhdCh0LCJgIil9ZnVuY3Rpb24gdmFsaWRhdGVPcHRpb24oZSx0LG4pe249bnx8e307dmFyIHI9bi5kZXNjcmlwdG9yfHxvcHRpb25zRGVzY3JpcHRvci5hcGlEZXNjcmlwdG9yO2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgdC5leGNlcHRpb258fCF0LmV4Y2VwdGlvbihlKSl0cnl7dmFsaWRhdGVPcHRpb25UeXBlKGUsdCl9Y2F0Y2gobil7dGhyb3cgbmV3IEVycm9yKCJJbnZhbGlkIGAiLmNvbmNhdChyKHQubmFtZSksImAgdmFsdWUuICIpLmNvbmNhdChuLm1lc3NhZ2UsIiwgYnV0IHJlY2VpdmVkIGAiKS5jb25jYXQoSlNPTi5zdHJpbmdpZnkoZSksImAuIikpfX1mdW5jdGlvbiB2YWxpZGF0ZU9wdGlvblR5cGUoZSx0KXtpZih0LmFycmF5KXtpZighQXJyYXkuaXNBcnJheShlKSl0aHJvdyBuZXcgRXJyb3IoIkV4cGVjdGVkIGFuIGFycmF5Iik7ZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiB2YWxpZGF0ZU9wdGlvblR5cGUoZSxPYmplY3QuYXNzaWduKHt9LHQse2FycmF5OiExfSkpfSl9ZWxzZSBzd2l0Y2godC50eXBlKXtjYXNlImludCI6dmFsaWRhdGVJbnRPcHRpb24oZSk7YnJlYWs7Y2FzZSJib29sZWFuIjp2YWxpZGF0ZUJvb2xlYW5PcHRpb24oZSk7YnJlYWs7Y2FzZSJjaG9pY2UiOnZhbGlkYXRlQ2hvaWNlT3B0aW9uKGUsdC5jaG9pY2VzKX19ZnVuY3Rpb24gdmFsaWRhdGVCb29sZWFuT3B0aW9uKGUpe2lmKCJib29sZWFuIiE9PXR5cGVvZiBlKXRocm93IG5ldyBFcnJvcigiRXhwZWN0ZWQgYSBib29sZWFuIil9ZnVuY3Rpb24gdmFsaWRhdGVJbnRPcHRpb24oZSl7aWYoISgibnVtYmVyIj09PXR5cGVvZiBlJiZNYXRoLmZsb29yKGUpPT09ZSYmZT49MCYmZSE9PTEvMCkpdGhyb3cgbmV3IEVycm9yKCJFeHBlY3RlZCBhbiBpbnRlZ2VyIil9ZnVuY3Rpb24gdmFsaWRhdGVDaG9pY2VPcHRpb24oZSx0KXtpZighdC5zb21lKGZ1bmN0aW9uKHQpe3JldHVybiB0LnZhbHVlPT09ZX0pKXt2YXIgbj10LmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4hZS5kZXByZWNhdGVkfSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBKU09OLnN0cmluZ2lmeShlLnZhbHVlKX0pLnNvcnQoKSxyPW4uc2xpY2UoMCwtMiksaT1uLnNsaWNlKC0yKTt0aHJvdyBuZXcgRXJyb3IoIkV4cGVjdGVkICIuY29uY2F0KHIuY29uY2F0KGkuam9pbigiIG9yICIpKS5qb2luKCIsICIpKSl9fWZ1bmN0aW9uIG5vcm1hbGl6ZU9wdGlvbnMkMShlLHQsbil7bj1ufHx7fTt2YXIgcj0hMT09PW4ubG9nZ2VyP3t3YXJuOmZ1bmN0aW9uKCl7fX06dm9pZCAwIT09bi5sb2dnZXI/bi5sb2dnZXI6Y29uc29sZSxpPW4uZGVzY3JpcHRvcnx8b3B0aW9uc0Rlc2NyaXB0b3IuYXBpRGVzY3JpcHRvcixvPW4ucGFzc1Rocm91Z2h8fFtdLGE9dC5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmFzc2lnbihlLF9kZWZpbmVQcm9wZXJ0eSh7fSx0Lm5hbWUsdCkpfSx7fSk7cmV0dXJuIE9iamVjdC5rZXlzKGUpLnJlZHVjZShmdW5jdGlvbihuLHMpe3ZhciB1PWFbc10sYz1zLGw9ZVtzXTtpZighdSlyZXR1cm4hMD09PW98fC0xIT09by5pbmRleE9mKGMpP25bY109bDpyLndhcm4oY3JlYXRlVW5rbm93bk9wdGlvbk1lc3NhZ2UoYyxsLHQsaSkpLG47aWYodS5kZXByZWNhdGVkPyJzdHJpbmciPT09dHlwZW9mIHUucmVkaXJlY3Q/KHIud2FybihjcmVhdGVSZWRpcmVjdE9wdGlvbk1lc3NhZ2UodSxpKSksYz11LnJlZGlyZWN0KTpsJiYoci53YXJuKGNyZWF0ZVJlZGlyZWN0T3B0aW9uTWVzc2FnZSh1LGkpKSxsPXUucmVkaXJlY3QudmFsdWUsYz11LnJlZGlyZWN0Lm9wdGlvbik6bD1ub3JtYWxpemVPcHRpb24obCx1KSx1LmNob2ljZXMpe3ZhciBwPXUuY2hvaWNlcy5maW5kKGZ1bmN0aW9uKGUpe3JldHVybiBlLnZhbHVlPT09bH0pO3AmJnAuZGVwcmVjYXRlZCYmKHIud2FybihjcmVhdGVSZWRpcmVjdENob2ljZU1lc3NhZ2UodSxwLGkpKSxsPXAucmVkaXJlY3QpfXJldHVybiB1LmFycmF5JiYhQXJyYXkuaXNBcnJheShsKSYmKGw9W2xdKSxsIT09dS5kZWZhdWx0JiZvcHRpb25zVmFsaWRhdG9yLnZhbGlkYXRlT3B0aW9uKGwsYVtjXSx7ZGVzY3JpcHRvcjppfSksbltjXT1sLG59LHt9KX1mdW5jdGlvbiBub3JtYWxpemVPcHRpb24oZSx0KXtyZXR1cm4iaW50Ij09PXQudHlwZT9OdW1iZXIoZSk6ZX1mdW5jdGlvbiBjcmVhdGVVbmtub3duT3B0aW9uTWVzc2FnZShlLHQsbixyKXt2YXIgaT1bIklnbm9yZWQgdW5rbm93biBvcHRpb24gIi5jb25jYXQocihlLHQpLCIuIildLG89bi5maW5kKGZ1bmN0aW9uKHQpe3JldHVybiBsZXZlbih0Lm5hbWUsZSk8M30pO3JldHVybiBvJiZpLnB1c2goIkRpZCB5b3UgbWVhbiAiLmNvbmNhdChKU09OLnN0cmluZ2lmeShvLm5hbWUpLCI/IikpLGkuam9pbigiICIpfWZ1bmN0aW9uIGNyZWF0ZVJlZGlyZWN0T3B0aW9uTWVzc2FnZShlLHQpe3JldHVybiIiLmNvbmNhdCh0KGUubmFtZSksIiBpcyBkZXByZWNhdGVkLiBQcmV0dGllciBub3cgdHJlYXRzIGl0IGFzICIpLmNvbmNhdCgic3RyaW5nIj09PXR5cGVvZiBlLnJlZGlyZWN0P3QoZS5yZWRpcmVjdCk6dChlLnJlZGlyZWN0Lm9wdGlvbixlLnJlZGlyZWN0LnZhbHVlKSwiLiIpfWZ1bmN0aW9uIGNyZWF0ZVJlZGlyZWN0Q2hvaWNlTWVzc2FnZShlLHQsbil7cmV0dXJuIiIuY29uY2F0KG4oZS5uYW1lLHQudmFsdWUpLCIgaXMgZGVwcmVjYXRlZC4gUHJldHRpZXIgbm93IHRyZWF0cyBpdCBhcyAiKS5jb25jYXQobihlLm5hbWUsdC5yZWRpcmVjdCksIi4iKX1mdW5jdGlvbiBub3JtYWxpemVBcGlPcHRpb25zKGUsdCxuKXtyZXR1cm4gbm9ybWFsaXplT3B0aW9ucyQxKGUsdCxPYmplY3QuYXNzaWduKHtkZXNjcmlwdG9yOm9wdGlvbnNEZXNjcmlwdG9yLmFwaURlc2NyaXB0b3J9LG4pKX1mdW5jdGlvbiBub3JtYWxpemVDbGlPcHRpb25zKGUsdCxuKXt2YXIgcj1lLl98fFtdLGk9bm9ybWFsaXplT3B0aW9ucyQxKE9iamVjdC5rZXlzKGUpLnJlZHVjZShmdW5jdGlvbih0LG4pe3JldHVybiBPYmplY3QuYXNzaWduKHQsMT09PW4ubGVuZ3RoP251bGw6X2RlZmluZVByb3BlcnR5KHt9LG4sZVtuXSkpfSx7fSksdCxPYmplY3QuYXNzaWduKHtkZXNjcmlwdG9yOm9wdGlvbnNEZXNjcmlwdG9yLmNsaURlc2NyaXB0b3J9LG4pKTtyZXR1cm4gaS5fPXIsaX1mdW5jdGlvbiBsb2NTdGFydCQxKGUpe3JldHVybiBlLmRlY2xhcmF0aW9uJiZlLmRlY2xhcmF0aW9uLmRlY29yYXRvcnMmJmUuZGVjbGFyYXRpb24uZGVjb3JhdG9ycy5sZW5ndGg+MD9sb2NTdGFydCQxKGUuZGVjbGFyYXRpb24uZGVjb3JhdG9yc1swXSk6ZS5kZWNvcmF0b3JzJiZlLmRlY29yYXRvcnMubGVuZ3RoPjA/bG9jU3RhcnQkMShlLmRlY29yYXRvcnNbMF0pOmUuX19sb2NhdGlvbj9lLl9fbG9jYXRpb24uc3RhcnRPZmZzZXQ6ZS5yYW5nZT9lLnJhbmdlWzBdOiJudW1iZXIiPT09dHlwZW9mIGUuc3RhcnQ/ZS5zdGFydDplLmxvYz9lLmxvYy5zdGFydDpudWxsfWZ1bmN0aW9uIGxvY0VuZCQxKGUpe3ZhciB0PWUubm9kZXMmJmdldExhc3QoZS5ub2Rlcyk7aWYodCYmZS5zb3VyY2UmJiFlLnNvdXJjZS5lbmQmJihlPXQpLGUuX19sb2NhdGlvbilyZXR1cm4gZS5fX2xvY2F0aW9uLmVuZE9mZnNldDt2YXIgbj1lLnJhbmdlP2UucmFuZ2VbMV06Im51bWJlciI9PT10eXBlb2YgZS5lbmQ/ZS5lbmQ6bnVsbDtyZXR1cm4gZS50eXBlQW5ub3RhdGlvbj9NYXRoLm1heChuLGxvY0VuZCQxKGUudHlwZUFubm90YXRpb24pKTplLmxvYyYmIW4/ZS5sb2MuZW5kOm59ZnVuY3Rpb24gYnVpbGRHcmFwaCgpe2Zvcih2YXIgZT17fSx0PW1vZGVscyQxLmxlbmd0aCxuPTA7bjx0O24rKyllW21vZGVscyQxW25dXT17ZGlzdGFuY2U6LTEscGFyZW50Om51bGx9O3JldHVybiBlfWZ1bmN0aW9uIGRlcml2ZUJGUyhlKXt2YXIgdD1idWlsZEdyYXBoKCksbj1bZV07Zm9yKHRbZV0uZGlzdGFuY2U9MDtuLmxlbmd0aDspZm9yKHZhciByPW4ucG9wKCksaT1PYmplY3Qua2V5cyhjb252ZXJzaW9uc1tyXSksbz1pLmxlbmd0aCxhPTA7YTxvO2ErKyl7dmFyIHM9aVthXSx1PXRbc107LTE9PT11LmRpc3RhbmNlJiYodS5kaXN0YW5jZT10W3JdLmRpc3RhbmNlKzEsdS5wYXJlbnQ9cixuLnVuc2hpZnQocykpfXJldHVybiB0fWZ1bmN0aW9uIGxpbmsoZSx0KXtyZXR1cm4gZnVuY3Rpb24obil7cmV0dXJuIHQoZShuKSl9fWZ1bmN0aW9uIHdyYXBDb252ZXJzaW9uKGUsdCl7Zm9yKHZhciBuPVt0W2VdLnBhcmVudCxlXSxyPWNvbnZlcnNpb25zW3RbZV0ucGFyZW50XVtlXSxpPXRbZV0ucGFyZW50O3RbaV0ucGFyZW50OyluLnVuc2hpZnQodFtpXS5wYXJlbnQpLHI9bGluayhjb252ZXJzaW9uc1t0W2ldLnBhcmVudF1baV0sciksaT10W2ldLnBhcmVudDtyZXR1cm4gci5jb252ZXJzaW9uPW4scn1mdW5jdGlvbiB3cmFwUmF3KGUpe3ZhciB0PWZ1bmN0aW9uKHQpe3JldHVybiB2b2lkIDA9PT10fHxudWxsPT09dD90Oihhcmd1bWVudHMubGVuZ3RoPjEmJih0PUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykpLGUodCkpfTtyZXR1cm4iY29udmVyc2lvbiJpbiBlJiYodC5jb252ZXJzaW9uPWUuY29udmVyc2lvbiksdH1mdW5jdGlvbiB3cmFwUm91bmRlZChlKXt2YXIgdD1mdW5jdGlvbih0KXtpZih2b2lkIDA9PT10fHxudWxsPT09dClyZXR1cm4gdDthcmd1bWVudHMubGVuZ3RoPjEmJih0PUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykpO3ZhciBuPWUodCk7aWYoIm9iamVjdCI9PT1fdHlwZW9mKG4pKWZvcih2YXIgcj1uLmxlbmd0aCxpPTA7aTxyO2krKyluW2ldPU1hdGgucm91bmQobltpXSk7cmV0dXJuIG59O3JldHVybiJjb252ZXJzaW9uImluIGUmJih0LmNvbnZlcnNpb249ZS5jb252ZXJzaW9uKSx0fWZ1bmN0aW9uIGdldFBhcnNlcnMoZSl7dmFyIHQ9e30sbj0hMCxyPSExLGk9dm9pZCAwO3RyeXtmb3IodmFyIG8sYT1lLnBsdWdpbnNbU3ltYm9sLml0ZXJhdG9yXSgpOyEobj0obz1hLm5leHQoKSkuZG9uZSk7bj0hMCl7dmFyIHM9by52YWx1ZTtpZihzLnBhcnNlcnMpe3ZhciB1PSEwLGM9ITEsbD12b2lkIDA7dHJ5e2Zvcih2YXIgcCxmPW93bk5hbWVzKHMucGFyc2VycylbU3ltYm9sLml0ZXJhdG9yXSgpOyEodT0ocD1mLm5leHQoKSkuZG9uZSk7dT0hMCl7dmFyIGQ9cC52YWx1ZTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCxkLG93bkRlc2NyaXB0b3Iocy5wYXJzZXJzLGQpKX19Y2F0Y2goZSl7Yz0hMCxsPWV9ZmluYWxseXt0cnl7dXx8bnVsbD09Zi5yZXR1cm58fGYucmV0dXJuKCl9ZmluYWxseXtpZihjKXRocm93IGx9fX19fWNhdGNoKGUpe3I9ITAsaT1lfWZpbmFsbHl7dHJ5e258fG51bGw9PWEucmV0dXJufHxhLnJldHVybigpfWZpbmFsbHl7aWYocil0aHJvdyBpfX1yZXR1cm4gdH1mdW5jdGlvbiByZXNvbHZlUGFyc2VyJDEob3B0cyxwYXJzZXJzKXtpZihwYXJzZXJzPXBhcnNlcnN8fGdldFBhcnNlcnMob3B0cyksImZ1bmN0aW9uIj09PXR5cGVvZiBvcHRzLnBhcnNlcilyZXR1cm57cGFyc2U6b3B0cy5wYXJzZXIsYXN0Rm9ybWF0OiJlc3RyZWUiLGxvY1N0YXJ0OmxvY1N0YXJ0LGxvY0VuZDpsb2NFbmR9O2lmKCJzdHJpbmciPT09dHlwZW9mIG9wdHMucGFyc2VyKXtpZihwYXJzZXJzLmhhc093blByb3BlcnR5KG9wdHMucGFyc2VyKSlyZXR1cm4gcGFyc2Vyc1tvcHRzLnBhcnNlcl07dHJ5e3JldHVybntwYXJzZTpldmFsKCJyZXF1aXJlIikocGF0aCQ0LnJlc29sdmUocHJvY2Vzcy5jd2QoKSxvcHRzLnBhcnNlcikpLGFzdEZvcm1hdDoiZXN0cmVlIixsb2NTdGFydDpsb2NTdGFydCxsb2NFbmQ6bG9jRW5kfX1jYXRjaChlKXt0aHJvdyBuZXcgQ29uZmlnRXJyb3IkMSgiQ291bGRuJ3QgcmVzb2x2ZSBwYXJzZXIgXCIiLmNvbmNhdChvcHRzLnBhcnNlciwnIicpKX19fWZ1bmN0aW9uIHBhcnNlJDIoZSx0KXt2YXIgbj1nZXRQYXJzZXJzKHQpLHI9T2JqZWN0LmtleXMobikucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHQse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG5bdF0ucGFyc2V9fSl9LHt9KSxpPXJlc29sdmVQYXJzZXIkMSh0LG4pO3RyeXtyZXR1cm4gaS5wcmVwcm9jZXNzJiYoZT1pLnByZXByb2Nlc3MoZSx0KSkse3RleHQ6ZSxhc3Q6aS5wYXJzZShlLHIsdCl9fWNhdGNoKHQpe3ZhciBvPXQubG9jO2lmKG8pe3ZhciBhPWxpYiQxO3Rocm93IHQuY29kZUZyYW1lPWEuY29kZUZyYW1lQ29sdW1ucyhlLG8se2hpZ2hsaWdodENvZGU6ITB9KSx0Lm1lc3NhZ2UrPSJcbiIrdC5jb2RlRnJhbWUsdH10aHJvdyB0LnN0YWNrfX1mdW5jdGlvbiBub3JtYWxpemUoZSx0KXt0PXR8fHt9O3ZhciBuPU9iamVjdC5hc3NpZ24oe30sZSkscj1nZXRTdXBwb3J0SW5mbyQxKG51bGwse3BsdWdpbnM6ZS5wbHVnaW5zLHNob3dVbnJlbGVhc2VkOiEwLHNob3dEZXByZWNhdGVkOiEwfSkub3B0aW9ucyxpPXIucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5hc3NpZ24oZSxfZGVmaW5lUHJvcGVydHkoe30sdC5uYW1lLHQuZGVmYXVsdCkpfSxPYmplY3QuYXNzaWduKHt9LGhpZGRlbkRlZmF1bHRzKSk7aWYoIW4ucGFyc2VyKWlmKG4uZmlsZXBhdGgpe2lmKG4ucGFyc2VyPWluZmVyUGFyc2VyKG4uZmlsZXBhdGgsbi5wbHVnaW5zKSwhbi5wYXJzZXIpdGhyb3cgbmV3IFVuZGVmaW5lZFBhcnNlckVycm9yKCJObyBwYXJzZXIgY291bGQgYmUgaW5mZXJyZWQgZm9yIGZpbGU6ICIuY29uY2F0KG4uZmlsZXBhdGgpKX1lbHNle3ZhciBvPXQubG9nZ2VyfHxjb25zb2xlO28ud2FybigiTm8gcGFyc2VyIGFuZCBubyBmaWxlcGF0aCBnaXZlbiwgdXNpbmcgJ2JhYnlsb24nIHRoZSBwYXJzZXIgbm93IGJ1dCB0aGlzIHdpbGwgdGhyb3cgYW4gZXJyb3IgaW4gdGhlIGZ1dHVyZS4gUGxlYXNlIHNwZWNpZnkgYSBwYXJzZXIgb3IgYSBmaWxlcGF0aCBzbyBvbmUgY2FuIGJlIGluZmVycmVkLiIpLG4ucGFyc2VyPSJiYWJ5bG9uIn12YXIgYT1yZXNvbHZlUGFyc2VyKG9wdGlvbnNOb3JtYWxpemVyLm5vcm1hbGl6ZUFwaU9wdGlvbnMobixbci5maW5kKGZ1bmN0aW9uKGUpe3JldHVybiJwYXJzZXIiPT09ZS5uYW1lfSldLHtwYXNzVGhyb3VnaDohMCxsb2dnZXI6ITF9KSk7bi5hc3RGb3JtYXQ9YS5hc3RGb3JtYXQsbi5sb2NFbmQ9YS5sb2NFbmQsbi5sb2NTdGFydD1hLmxvY1N0YXJ0O3ZhciBzPWdldFBsdWdpbihuKTtuLnByaW50ZXI9cy5wcmludGVyc1tuLmFzdEZvcm1hdF07dmFyIHU9ci5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIGUucGx1Z2luRGVmYXVsdHMmJmUucGx1Z2luRGVmYXVsdHNbcy5uYW1lXX0pLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuYXNzaWduKGUsX2RlZmluZVByb3BlcnR5KHt9LHQubmFtZSx0LnBsdWdpbkRlZmF1bHRzW3MubmFtZV0pKX0se30pLGM9T2JqZWN0LmFzc2lnbih7fSxpLHUpO3JldHVybiBPYmplY3Qua2V5cyhjKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe251bGw9PW5bZV0mJihuW2VdPWNbZV0pfSksImpzb24iPT09bi5wYXJzZXImJihuLnRyYWlsaW5nQ29tbWE9Im5vbmUiKSxvcHRpb25zTm9ybWFsaXplci5ub3JtYWxpemVBcGlPcHRpb25zKG4scixPYmplY3QuYXNzaWduKHtwYXNzVGhyb3VnaDpPYmplY3Qua2V5cyhoaWRkZW5EZWZhdWx0cyl9LHQpKX1mdW5jdGlvbiBnZXRQbHVnaW4oZSl7dmFyIHQ9ZS5hc3RGb3JtYXQ7aWYoIXQpdGhyb3cgbmV3IEVycm9yKCJnZXRQbHVnaW4oKSByZXF1aXJlcyBhc3RGb3JtYXQgdG8gYmUgc2V0Iik7dmFyIG49ZS5wbHVnaW5zLmZpbmQoZnVuY3Rpb24oZSl7cmV0dXJuIGUucHJpbnRlcnMmJmUucHJpbnRlcnNbdF19KTtpZighbil0aHJvdyBuZXcgRXJyb3IoIkNvdWxkbid0IGZpbmQgcGx1Z2luIGZvciBBU1QgZm9ybWF0IFwiIi5jb25jYXQodCwnIicpKTtyZXR1cm4gbn1mdW5jdGlvbiBpbmZlclBhcnNlcihlLHQpe3ZhciBuPXBhdGgkOC5leHRuYW1lKGUpLHI9cGF0aCQ4LmJhc2VuYW1lKGUpLnRvTG93ZXJDYXNlKCksaT1nZXRTdXBwb3J0SW5mbyQxKG51bGwse3BsdWdpbnM6dH0pLmxhbmd1YWdlcy5maW5kKGZ1bmN0aW9uKGUpe3JldHVybiBudWxsIT09ZS5zaW5jZSYmKGUuZXh0ZW5zaW9ucyYmZS5leHRlbnNpb25zLmluZGV4T2Yobik+LTF8fGUuZmlsZW5hbWVzJiZlLmZpbGVuYW1lcy5maW5kKGZ1bmN0aW9uKGUpe3JldHVybiBlLnRvTG93ZXJDYXNlKCk9PT1yfSkpfSk7cmV0dXJuIGkmJmkucGFyc2Vyc1swXX1mdW5jdGlvbiBtYXNzYWdlQVNUKGUsdCxuKXtpZihBcnJheS5pc0FycmF5KGUpKXJldHVybiBlLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gbWFzc2FnZUFTVChlLHQsbil9KS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIGV9KTtpZighZXx8Im9iamVjdCIhPT1fdHlwZW9mKGUpKXJldHVybiBlO2Zvcih2YXIgcj17fSxpPU9iamVjdC5rZXlzKGUpLG89MDtvPGkubGVuZ3RoO28rKyl7dmFyIGE9aVtvXTsiZnVuY3Rpb24iIT09dHlwZW9mIGVbYV0mJihyW2FdPW1hc3NhZ2VBU1QoZVthXSx0LGUpKX1pZih0LnByaW50ZXIubWFzc2FnZUFzdE5vZGUpe3ZhciBzPXQucHJpbnRlci5tYXNzYWdlQXN0Tm9kZShlLHIsbik7aWYobnVsbD09PXMpcmV0dXJuO2lmKHMpcmV0dXJuIHN9cmV0dXJuIHJ9ZnVuY3Rpb24gYXNzZXJ0RG9jKGUpe2lmKCJzdHJpbmciIT09dHlwZW9mIGUmJihudWxsPT1lfHwic3RyaW5nIiE9PXR5cGVvZiBlLnR5cGUpKXRocm93IG5ldyBFcnJvcigiVmFsdWUgIitKU09OLnN0cmluZ2lmeShlKSsiIGlzIG5vdCBhIHZhbGlkIGRvY3VtZW50Iil9ZnVuY3Rpb24gY29uY2F0JDEoZSl7cmV0dXJuInByb2R1Y3Rpb24iIT09cHJvY2Vzcy5lbnYuTk9ERV9FTlYmJmUuZm9yRWFjaChhc3NlcnREb2MpLHt0eXBlOiJjb25jYXQiLHBhcnRzOmV9fWZ1bmN0aW9uIGluZGVudCQxKGUpe3JldHVybiJwcm9kdWN0aW9uIiE9PXByb2Nlc3MuZW52Lk5PREVfRU5WJiZhc3NlcnREb2MoZSkse3R5cGU6ImluZGVudCIsY29udGVudHM6ZX19ZnVuY3Rpb24gYWxpZ24oZSx0KXtyZXR1cm4icHJvZHVjdGlvbiIhPT1wcm9jZXNzLmVudi5OT0RFX0VOViYmYXNzZXJ0RG9jKHQpLHt0eXBlOiJhbGlnbiIsY29udGVudHM6dCxuOmV9fWZ1bmN0aW9uIGdyb3VwKGUsdCl7cmV0dXJuIHQ9dHx8e30sInByb2R1Y3Rpb24iIT09cHJvY2Vzcy5lbnYuTk9ERV9FTlYmJmFzc2VydERvYyhlKSx7dHlwZToiZ3JvdXAiLGNvbnRlbnRzOmUsYnJlYWs6ISF0LnNob3VsZEJyZWFrLGV4cGFuZGVkU3RhdGVzOnQuZXhwYW5kZWRTdGF0ZXN9fWZ1bmN0aW9uIGRlZGVudFRvUm9vdChlKXtyZXR1cm4gYWxpZ24oLTEvMCxlKX1mdW5jdGlvbiBtYXJrQXNSb290KGUpe3JldHVybiBhbGlnbih7dHlwZToicm9vdCJ9LGUpfWZ1bmN0aW9uIGRlZGVudCQxKGUpe3JldHVybiBhbGlnbigtMSxlKX1mdW5jdGlvbiBjb25kaXRpb25hbEdyb3VwKGUsdCl7cmV0dXJuIGdyb3VwKGVbMF0sT2JqZWN0LmFzc2lnbih0fHx7fSx7ZXhwYW5kZWRTdGF0ZXM6ZX0pKX1mdW5jdGlvbiBmaWxsKGUpe3JldHVybiJwcm9kdWN0aW9uIiE9PXByb2Nlc3MuZW52Lk5PREVfRU5WJiZlLmZvckVhY2goYXNzZXJ0RG9jKSx7dHlwZToiZmlsbCIscGFydHM6ZX19ZnVuY3Rpb24gaWZCcmVhayhlLHQpe3JldHVybiJwcm9kdWN0aW9uIiE9PXByb2Nlc3MuZW52Lk5PREVfRU5WJiYoZSYmYXNzZXJ0RG9jKGUpLHQmJmFzc2VydERvYyh0KSkse3R5cGU6ImlmLWJyZWFrIixicmVha0NvbnRlbnRzOmUsZmxhdENvbnRlbnRzOnR9fWZ1bmN0aW9uIGxpbmVTdWZmaXgkMShlKXtyZXR1cm4icHJvZHVjdGlvbiIhPT1wcm9jZXNzLmVudi5OT0RFX0VOViYmYXNzZXJ0RG9jKGUpLHt0eXBlOiJsaW5lLXN1ZmZpeCIsY29udGVudHM6ZX19ZnVuY3Rpb24gam9pbiQxKGUsdCl7Zm9yKHZhciBuPVtdLHI9MDtyPHQubGVuZ3RoO3IrKykwIT09ciYmbi5wdXNoKGUpLG4ucHVzaCh0W3JdKTtyZXR1cm4gY29uY2F0JDEobil9ZnVuY3Rpb24gYWRkQWxpZ25tZW50VG9Eb2MoZSx0LG4pe3ZhciByPWU7aWYodD4wKXtmb3IodmFyIGk9MDtpPE1hdGguZmxvb3IodC9uKTsrK2kpcj1pbmRlbnQkMShyKTtyPWFsaWduKHQlbixyKSxyPWFsaWduKC0xLzAscil9cmV0dXJuIHJ9ZnVuY3Rpb24gZ2V0X3JlZ2V4KCl7cmV0dXJuIGNyZWF0ZV9yZWdleChjaGFyYWN0ZXJfcmFuZ2VzLmNvbmNhdChwdW5jdHVhdGlvbl9yYW5nZXMpKX1mdW5jdGlvbiBjcmVhdGVfcmVnZXgoZSl7cmV0dXJuIG5ldyBSZWdFeHAoIlsiK2UubWFwKGdldF9icmFja2V0X2NvbnRlbnQpLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlK3R9KSsiXSIsImciKX1mdW5jdGlvbiBnZXRfYnJhY2tldF9jb250ZW50KGUpe3JldHVybiBnZXRfZXNjYXBlZF91bmljb2RlKGVbMF0pKyItIitnZXRfZXNjYXBlZF91bmljb2RlKGVbMV0pfWZ1bmN0aW9uIGdldF9lc2NhcGVkX3VuaWNvZGUoZSl7cmV0dXJuIlxcdSIrZS50b1N0cmluZygxNil9ZnVuY3Rpb24gaXNFeHBvcnREZWNsYXJhdGlvbihlKXtpZihlKXN3aXRjaChlLnR5cGUpe2Nhc2UiRXhwb3J0RGVmYXVsdERlY2xhcmF0aW9uIjpjYXNlIkV4cG9ydERlZmF1bHRTcGVjaWZpZXIiOmNhc2UiRGVjbGFyZUV4cG9ydERlY2xhcmF0aW9uIjpjYXNlIkV4cG9ydE5hbWVkRGVjbGFyYXRpb24iOmNhc2UiRXhwb3J0QWxsRGVjbGFyYXRpb24iOnJldHVybiEwfXJldHVybiExfWZ1bmN0aW9uIGdldFBhcmVudEV4cG9ydERlY2xhcmF0aW9uKGUpe3ZhciB0PWUuZ2V0UGFyZW50Tm9kZSgpO3JldHVybiJkZWNsYXJhdGlvbiI9PT1lLmdldE5hbWUoKSYmaXNFeHBvcnREZWNsYXJhdGlvbih0KT90Om51bGx9ZnVuY3Rpb24gZ2V0UGVudWx0aW1hdGUoZSl7cmV0dXJuIGUubGVuZ3RoPjE/ZVtlLmxlbmd0aC0yXTpudWxsfWZ1bmN0aW9uIGdldExhc3QkMyhlKXtyZXR1cm4gZS5sZW5ndGg+MD9lW2UubGVuZ3RoLTFdOm51bGx9ZnVuY3Rpb24gc2tpcChlKXtyZXR1cm4gZnVuY3Rpb24odCxuLHIpe3ZhciBpPXImJnIuYmFja3dhcmRzO2lmKCExPT09bilyZXR1cm4hMTtmb3IodmFyIG89dC5sZW5ndGgsYT1uO2E+PTAmJmE8bzspe3ZhciBzPXQuY2hhckF0KGEpO2lmKGUgaW5zdGFuY2VvZiBSZWdFeHApe2lmKCFlLnRlc3QocykpcmV0dXJuIGF9ZWxzZSBpZigtMT09PWUuaW5kZXhPZihzKSlyZXR1cm4gYTtpP2EtLTphKyt9cmV0dXJuKC0xPT09YXx8YT09PW8pJiZhfX1mdW5jdGlvbiBza2lwSW5saW5lQ29tbWVudChlLHQpe2lmKCExPT09dClyZXR1cm4hMTtpZigiLyI9PT1lLmNoYXJBdCh0KSYmIioiPT09ZS5jaGFyQXQodCsxKSlmb3IodmFyIG49dCsyO248ZS5sZW5ndGg7KytuKWlmKCIqIj09PWUuY2hhckF0KG4pJiYiLyI9PT1lLmNoYXJBdChuKzEpKXJldHVybiBuKzI7cmV0dXJuIHR9ZnVuY3Rpb24gc2tpcFRyYWlsaW5nQ29tbWVudChlLHQpe3JldHVybiExIT09dCYmKCIvIj09PWUuY2hhckF0KHQpJiYiLyI9PT1lLmNoYXJBdCh0KzEpP3NraXBFdmVyeXRoaW5nQnV0TmV3TGluZShlLHQpOnQpfWZ1bmN0aW9uIHNraXBOZXdsaW5lJDEoZSx0LG4pe3ZhciByPW4mJm4uYmFja3dhcmRzO2lmKCExPT09dClyZXR1cm4hMTt2YXIgaT1lLmNoYXJBdCh0KTtpZihyKXtpZigiXHIiPT09ZS5jaGFyQXQodC0xKSYmIlxuIj09PWkpcmV0dXJuIHQtMjtpZigiXG4iPT09aXx8IlxyIj09PWl8fCJcdTIwMjgiPT09aXx8Ilx1MjAyOSI9PT1pKXJldHVybiB0LTF9ZWxzZXtpZigiXHIiPT09aSYmIlxuIj09PWUuY2hhckF0KHQrMSkpcmV0dXJuIHQrMjtpZigiXG4iPT09aXx8IlxyIj09PWl8fCJcdTIwMjgiPT09aXx8Ilx1MjAyOSI9PT1pKXJldHVybiB0KzF9cmV0dXJuIHR9ZnVuY3Rpb24gaGFzTmV3bGluZSQxKGUsdCxuKXtuPW58fHt9O3ZhciByPXNraXBTcGFjZXMoZSxuLmJhY2t3YXJkcz90LTE6dCxuKTtyZXR1cm4gciE9PXNraXBOZXdsaW5lJDEoZSxyLG4pfWZ1bmN0aW9uIGhhc05ld2xpbmVJblJhbmdlKGUsdCxuKXtmb3IodmFyIHI9dDtyPG47KytyKWlmKCJcbiI9PT1lLmNoYXJBdChyKSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiBpc1ByZXZpb3VzTGluZUVtcHR5JDEoZSx0LG4pe3ZhciByPW4odCktMTtyZXR1cm4gcj1za2lwU3BhY2VzKGUscix7YmFja3dhcmRzOiEwfSkscj1za2lwTmV3bGluZSQxKGUscix7YmFja3dhcmRzOiEwfSksKHI9c2tpcFNwYWNlcyhlLHIse2JhY2t3YXJkczohMH0pKSE9PXNraXBOZXdsaW5lJDEoZSxyLHtiYWNrd2FyZHM6ITB9KX1mdW5jdGlvbiBpc05leHRMaW5lRW1wdHlBZnRlckluZGV4KGUsdCl7Zm9yKHZhciBuPW51bGwscj10O3IhPT1uOyluPXIscj1za2lwVG9MaW5lRW5kKGUscikscj1za2lwSW5saW5lQ29tbWVudChlLHIpLHI9c2tpcFNwYWNlcyhlLHIpO3JldHVybiByPXNraXBUcmFpbGluZ0NvbW1lbnQoZSxyKSxyPXNraXBOZXdsaW5lJDEoZSxyKSxoYXNOZXdsaW5lJDEoZSxyKX1mdW5jdGlvbiBpc05leHRMaW5lRW1wdHkoZSx0LG4pe3JldHVybiBpc05leHRMaW5lRW1wdHlBZnRlckluZGV4KGUsbih0KSl9ZnVuY3Rpb24gZ2V0TmV4dE5vblNwYWNlTm9uQ29tbWVudENoYXJhY3RlckluZGV4KGUsdCxuKXtmb3IodmFyIHI9bnVsbCxpPW4odCk7aSE9PXI7KXI9aSxpPXNraXBTcGFjZXMoZSxpKSxpPXNraXBJbmxpbmVDb21tZW50KGUsaSksaT1za2lwVHJhaWxpbmdDb21tZW50KGUsaSksaT1za2lwTmV3bGluZSQxKGUsaSk7cmV0dXJuIGl9ZnVuY3Rpb24gZ2V0TmV4dE5vblNwYWNlTm9uQ29tbWVudENoYXJhY3RlcihlLHQsbil7cmV0dXJuIGUuY2hhckF0KGdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXJJbmRleChlLHQsbikpfWZ1bmN0aW9uIGhhc1NwYWNlcyhlLHQsbil7cmV0dXJuIG49bnx8e30sc2tpcFNwYWNlcyhlLG4uYmFja3dhcmRzP3QtMTp0LG4pIT09dH1mdW5jdGlvbiBzZXRMb2NTdGFydChlLHQpe2UucmFuZ2U/ZS5yYW5nZVswXT10OmUuc3RhcnQ9dH1mdW5jdGlvbiBzZXRMb2NFbmQoZSx0KXtlLnJhbmdlP2UucmFuZ2VbMV09dDplLmVuZD10fWZ1bmN0aW9uIGdldFByZWNlZGVuY2UoZSl7cmV0dXJuIFBSRUNFREVOQ0VbZV19ZnVuY3Rpb24gc2hvdWxkRmxhdHRlbihlLHQpe3JldHVybiBnZXRQcmVjZWRlbmNlKHQpIT09Z2V0UHJlY2VkZW5jZShlKT8iJSI9PT10JiYhYWRkaXRpdmVPcGVyYXRvcnNbZV06IioqIiE9PWUmJigoIWVxdWFsaXR5T3BlcmF0b3JzW2VdfHwhZXF1YWxpdHlPcGVyYXRvcnNbdF0pJiYoISgiJSI9PT10JiZtdWx0aXBsaWNhdGl2ZU9wZXJhdG9yc1tlXXx8IiUiPT09ZSYmbXVsdGlwbGljYXRpdmVPcGVyYXRvcnNbdF0pJiYoKHQ9PT1lfHwhbXVsdGlwbGljYXRpdmVPcGVyYXRvcnNbdF18fCFtdWx0aXBsaWNhdGl2ZU9wZXJhdG9yc1tlXSkmJighYml0c2hpZnRPcGVyYXRvcnNbZV18fCFiaXRzaGlmdE9wZXJhdG9yc1t0XSkpKSl9ZnVuY3Rpb24gaXNCaXR3aXNlT3BlcmF0b3IoZSl7cmV0dXJuISFiaXRzaGlmdE9wZXJhdG9yc1tlXXx8InwiPT09ZXx8Il4iPT09ZXx8IiYiPT09ZX1mdW5jdGlvbiBzdGFydHNXaXRoTm9Mb29rYWhlYWRUb2tlbihlLHQpe3N3aXRjaChlPWdldExlZnRNb3N0KGUpLGUudHlwZSl7Y2FzZSJPYmplY3RQYXR0ZXJuIjpyZXR1cm4hdDtjYXNlIkZ1bmN0aW9uRXhwcmVzc2lvbiI6Y2FzZSJDbGFzc0V4cHJlc3Npb24iOmNhc2UiRG9FeHByZXNzaW9uIjpyZXR1cm4gdDtjYXNlIk9iamVjdEV4cHJlc3Npb24iOnJldHVybiEwO2Nhc2UiTWVtYmVyRXhwcmVzc2lvbiI6cmV0dXJuIHN0YXJ0c1dpdGhOb0xvb2thaGVhZFRva2VuKGUub2JqZWN0LHQpO2Nhc2UiVGFnZ2VkVGVtcGxhdGVFeHByZXNzaW9uIjpyZXR1cm4iRnVuY3Rpb25FeHByZXNzaW9uIiE9PWUudGFnLnR5cGUmJnN0YXJ0c1dpdGhOb0xvb2thaGVhZFRva2VuKGUudGFnLHQpO2Nhc2UiQ2FsbEV4cHJlc3Npb24iOnJldHVybiJGdW5jdGlvbkV4cHJlc3Npb24iIT09ZS5jYWxsZWUudHlwZSYmc3RhcnRzV2l0aE5vTG9va2FoZWFkVG9rZW4oZS5jYWxsZWUsdCk7Y2FzZSJDb25kaXRpb25hbEV4cHJlc3Npb24iOnJldHVybiBzdGFydHNXaXRoTm9Mb29rYWhlYWRUb2tlbihlLnRlc3QsdCk7Y2FzZSJVcGRhdGVFeHByZXNzaW9uIjpyZXR1cm4hZS5wcmVmaXgmJnN0YXJ0c1dpdGhOb0xvb2thaGVhZFRva2VuKGUuYXJndW1lbnQsdCk7Y2FzZSJCaW5kRXhwcmVzc2lvbiI6cmV0dXJuIGUub2JqZWN0JiZzdGFydHNXaXRoTm9Mb29rYWhlYWRUb2tlbihlLm9iamVjdCx0KTtjYXNlIlNlcXVlbmNlRXhwcmVzc2lvbiI6cmV0dXJuIHN0YXJ0c1dpdGhOb0xvb2thaGVhZFRva2VuKGUuZXhwcmVzc2lvbnNbMF0sdCk7Y2FzZSJUU0FzRXhwcmVzc2lvbiI6cmV0dXJuIHN0YXJ0c1dpdGhOb0xvb2thaGVhZFRva2VuKGUuZXhwcmVzc2lvbix0KTtkZWZhdWx0OnJldHVybiExfX1mdW5jdGlvbiBnZXRMZWZ0TW9zdChlKXtyZXR1cm4gZS5sZWZ0P2dldExlZnRNb3N0KGUubGVmdCk6ZX1mdW5jdGlvbiBnZXRBbGlnbm1lbnRTaXplKGUsdCxuKXtuPW58fDA7Zm9yKHZhciByPTAsaT1uO2k8ZS5sZW5ndGg7KytpKSJcdCI9PT1lW2ldP3I9cit0LXIldDpyKys7cmV0dXJuIHJ9ZnVuY3Rpb24gZ2V0SW5kZW50U2l6ZShlLHQpe3ZhciBuPWUubGFzdEluZGV4T2YoIlxuIik7cmV0dXJuLTE9PT1uPzA6Z2V0QWxpZ25tZW50U2l6ZShlLnNsaWNlKG4rMSkubWF0Y2goL15bIFx0XSovKVswXSx0KX1mdW5jdGlvbiBwcmludFN0cmluZyhlLHQsbil7dmFyIHI9ZS5zbGljZSgxLC0xKSxpPXtxdW90ZTonIicscmVnZXg6LyIvZ30sbz17cXVvdGU6IiciLHJlZ2V4Oi8nL2d9LGE9dC5zaW5nbGVRdW90ZT9vOmkscz1hPT09bz9pOm8sdT0hMSxjPSExO2lmKHIuaW5jbHVkZXMoYS5xdW90ZSl8fHIuaW5jbHVkZXMocy5xdW90ZSkpe3U9KHIubWF0Y2goYS5yZWdleCl8fFtdKS5sZW5ndGg+KHIubWF0Y2gocy5yZWdleCl8fFtdKS5sZW5ndGh9ZWxzZSBjPSEwO3ZhciBsPSJqc29uIj09PXQucGFyc2VyP2kucXVvdGU6dT9zLnF1b3RlOmEucXVvdGU7cmV0dXJuIG4/Yz9sK3IrbDplOm1ha2VTdHJpbmcocixsLCEoImNzcyI9PT10LnBhcnNlcnx8Imxlc3MiPT09dC5wYXJzZXJ8fCJzY3NzIj09PXQucGFyc2VyKSl9ZnVuY3Rpb24gbWFrZVN0cmluZyhlLHQsbil7dmFyIHI9JyInPT09dD8iJyI6JyInLGk9L1xcKFtcc1xTXSl8KFsnIl0pL2csbz1lLnJlcGxhY2UoaSxmdW5jdGlvbihlLGksbyl7cmV0dXJuIGk9PT1yP2k6bz09PXQ/IlxcIitvOm98fChuJiYvXlteXFxucnZ0YmZ1eFxyXG5cdTIwMjhcdTIwMjkiJzAtN10kLy50ZXN0KGkpP2k6IlxcIitpKX0pO3JldHVybiB0K28rdH1mdW5jdGlvbiBwcmludE51bWJlcihlKXtyZXR1cm4gZS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL14oWystXT9bXGQuXStlKSg/OlwrfCgtKSk/MCooXGQpLywiJDEkMiQzIikucmVwbGFjZSgvXihbKy1dP1tcZC5dKyllWystXT8wKyQvLCIkMSIpLnJlcGxhY2UoL14oWystXSk/XC4vLCIkMTAuIikucmVwbGFjZSgvKFwuXGQrPykwKyg/PWV8JCkvLCIkMSIpLnJlcGxhY2UoL1wuKD89ZXwkKS8sIiIpfWZ1bmN0aW9uIGdldE1heENvbnRpbnVvdXNDb3VudChlLHQpe3ZhciBuPWUubWF0Y2gobmV3IFJlZ0V4cCgiKCIuY29uY2F0KGVzY2FwZVN0cmluZ1JlZ2V4cCh0KSwiKSsiKSwiZyIpKTtyZXR1cm4gbnVsbD09PW4/MDpuLnJlZHVjZShmdW5jdGlvbihlLG4pe3JldHVybiBNYXRoLm1heChlLG4ubGVuZ3RoL3QubGVuZ3RoKX0sMCl9ZnVuY3Rpb24gc3BsaXRUZXh0KGUsdCl7ZnVuY3Rpb24gbihlKXt2YXIgdD1nZXRMYXN0JDMoYSk7dCYmIndvcmQiPT09dC50eXBlJiYodC5raW5kPT09ciYmZS5raW5kPT09aSYmIXQuaGFzVHJhaWxpbmdQdW5jdHVhdGlvbnx8dC5raW5kPT09aSYmZS5raW5kPT09ciYmIWUuaGFzTGVhZGluZ1B1bmN0dWF0aW9uP2EucHVzaCh7dHlwZToid2hpdGVzcGFjZSIsdmFsdWU6IiAifSk6ZnVuY3Rpb24obixyKXtyZXR1cm4gdC5raW5kPT09biYmZS5raW5kPT09cnx8dC5raW5kPT09ciYmZS5raW5kPT09bn0ocixvKXx8W3QudmFsdWUsZS52YWx1ZV0uc29tZShmdW5jdGlvbihlKXtyZXR1cm4vXHUzMDAwLy50ZXN0KGUpfSl8fGEucHVzaCh7dHlwZToid2hpdGVzcGFjZSIsdmFsdWU6IiJ9KSksYS5wdXNoKGUpfXZhciByPSJub24tY2prIixpPSJjamstY2hhcmFjdGVyIixvPSJjamstcHVuY3R1YXRpb24iLGE9W107cmV0dXJuKCJwcmVzZXJ2ZSI9PT10LnByb3NlV3JhcD9lOmUucmVwbGFjZShuZXcgUmVnRXhwKCIoIi5jb25jYXQoY2prUGF0dGVybiwiKVxuKCIpLmNvbmNhdChjamtQYXR0ZXJuLCIpIiksImciKSwiJDEkMiIpKS5zcGxpdCgvKFsgXHRcbl0rKS8pLmZvckVhY2goZnVuY3Rpb24oZSx0LHMpe2lmKHQlMj09PTEpcmV0dXJuIHZvaWQgYS5wdXNoKHt0eXBlOiJ3aGl0ZXNwYWNlIix2YWx1ZTovXG4vLnRlc3QoZSk/IlxuIjoiICJ9KTsoMCE9PXQmJnQhPT1zLmxlbmd0aC0xfHwiIiE9PWUpJiZlLnNwbGl0KG5ldyBSZWdFeHAoIigiLmNvbmNhdChjamtQYXR0ZXJuLCIpIikpKS5mb3JFYWNoKGZ1bmN0aW9uKGUsdCxhKXtpZigwIT09dCYmdCE9PWEubGVuZ3RoLTF8fCIiIT09ZSlyZXR1cm4gdCUyPT09MD92b2lkKCIiIT09ZSYmbih7dHlwZToid29yZCIsdmFsdWU6ZSxraW5kOnIsaGFzTGVhZGluZ1B1bmN0dWF0aW9uOnB1bmN0dWF0aW9uUmVnZXgudGVzdChlWzBdKSxoYXNUcmFpbGluZ1B1bmN0dWF0aW9uOnB1bmN0dWF0aW9uUmVnZXgudGVzdChnZXRMYXN0JDMoZSkpfSkpOnZvaWQgbihwdW5jdHVhdGlvblJlZ2V4LnRlc3QoZSk/e3R5cGU6IndvcmQiLHZhbHVlOmUsa2luZDpvLGhhc0xlYWRpbmdQdW5jdHVhdGlvbjohMCxoYXNUcmFpbGluZ1B1bmN0dWF0aW9uOiEwfTp7dHlwZToid29yZCIsdmFsdWU6ZSxraW5kOmksaGFzTGVhZGluZ1B1bmN0dWF0aW9uOiExLGhhc1RyYWlsaW5nUHVuY3R1YXRpb246ITF9KX0pfSksYX1mdW5jdGlvbiBnZXRTdHJpbmdXaWR0aChlKXtyZXR1cm4gZT9zdHJpbmdXaWR0aChlLnJlcGxhY2UoZW1vamlSZWdleCwiICAiKSk6MH1mdW5jdGlvbiBoYXNJZ25vcmVDb21tZW50KGUpe3JldHVybiBoYXNOb2RlSWdub3JlQ29tbWVudChlLmdldFZhbHVlKCkpfWZ1bmN0aW9uIGhhc05vZGVJZ25vcmVDb21tZW50KGUpe3JldHVybiBlJiZlLmNvbW1lbnRzJiZlLmNvbW1lbnRzLmxlbmd0aD4wJiZlLmNvbW1lbnRzLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuInByZXR0aWVyLWlnbm9yZSI9PT1lLnZhbHVlLnRyaW0oKX0pfWZ1bmN0aW9uIGFkZENvbW1lbnRIZWxwZXIoZSx0KXsoZS5jb21tZW50c3x8KGUuY29tbWVudHM9W10pKS5wdXNoKHQpLHQucHJpbnRlZD0hMSwiSlNYVGV4dCI9PT1lLnR5cGUmJih0LnByaW50ZWQ9ITApfWZ1bmN0aW9uIGFkZExlYWRpbmdDb21tZW50JDEoZSx0KXt0LmxlYWRpbmc9ITAsdC50cmFpbGluZz0hMSxhZGRDb21tZW50SGVscGVyKGUsdCl9ZnVuY3Rpb24gYWRkRGFuZ2xpbmdDb21tZW50JDEoZSx0KXt0LmxlYWRpbmc9ITEsdC50cmFpbGluZz0hMSxhZGRDb21tZW50SGVscGVyKGUsdCl9ZnVuY3Rpb24gYWRkVHJhaWxpbmdDb21tZW50JDEoZSx0KXt0LmxlYWRpbmc9ITEsdC50cmFpbGluZz0hMCxhZGRDb21tZW50SGVscGVyKGUsdCl9ZnVuY3Rpb24gcm9vdEluZGVudCgpe3JldHVybnt2YWx1ZToiIixsZW5ndGg6MCxxdWV1ZTpbXX19ZnVuY3Rpb24gbWFrZUluZGVudChlLHQpe3JldHVybiBnZW5lcmF0ZUluZChlLHt0eXBlOiJpbmRlbnQifSx0KX1mdW5jdGlvbiBtYWtlQWxpZ24oZSx0LG4pe3JldHVybiB0PT09LTEvMD9lLnJvb3R8fHJvb3RJbmRlbnQoKTp0PDA/Z2VuZXJhdGVJbmQoZSx7dHlwZToiZGVkZW50In0sbik6dD8icm9vdCI9PT10LnR5cGU/T2JqZWN0LmFzc2lnbih7fSxlLHtyb290OmV9KToic3RyaW5nIj09PXR5cGVvZiB0P2dlbmVyYXRlSW5kKGUse3R5cGU6InN0cmluZ0FsaWduIixuOnR9LG4pOmdlbmVyYXRlSW5kKGUse3R5cGU6Im51bWJlckFsaWduIixuOnR9LG4pOmV9ZnVuY3Rpb24gZ2VuZXJhdGVJbmQoZSx0LG4pe2Z1bmN0aW9uIHIoZSl7bCs9Ilx0Ii5yZXBlYXQoZSkscCs9bi50YWJXaWR0aCplfWZ1bmN0aW9uIGkoZSl7bCs9IiAiLnJlcGVhdChlKSxwKz1lfWZ1bmN0aW9uIG8oKXtuLnVzZVRhYnM/YSgpOnMoKX1mdW5jdGlvbiBhKCl7Zj4wJiZyKGYpLHUoKX1mdW5jdGlvbiBzKCl7ZD4wJiZpKGQpLHUoKX1mdW5jdGlvbiB1KCl7Zj0wLGQ9MH12YXIgYz0iZGVkZW50Ij09PXQudHlwZT9lLnF1ZXVlLnNsaWNlKDAsLTEpOmUucXVldWUuY29uY2F0KHQpLGw9IiIscD0wLGY9MCxkPTAsaD0hMCxtPSExLGc9dm9pZCAwO3RyeXtmb3IodmFyIHksdj1jW1N5bWJvbC5pdGVyYXRvcl0oKTshKGg9KHk9di5uZXh0KCkpLmRvbmUpO2g9ITApe3ZhciBiPXkudmFsdWU7c3dpdGNoKGIudHlwZSl7Y2FzZSJpbmRlbnQiOm8oKSxuLnVzZVRhYnM/cigxKTppKG4udGFiV2lkdGgpO2JyZWFrO2Nhc2Uic3RyaW5nQWxpZ24iOm8oKSxsKz1iLm4scCs9Yi5uLmxlbmd0aDticmVhaztjYXNlIm51bWJlckFsaWduIjpmKz0xLGQrPWIubjticmVhaztkZWZhdWx0OnRocm93IG5ldyBFcnJvcigiVW5leHBlY3RlZCB0eXBlICciLmNvbmNhdChiLnR5cGUsIiciKSl9fX1jYXRjaChlKXttPSEwLGc9ZX1maW5hbGx5e3RyeXtofHxudWxsPT12LnJldHVybnx8di5yZXR1cm4oKX1maW5hbGx5e2lmKG0pdGhyb3cgZ319cmV0dXJuIHMoKSxPYmplY3QuYXNzaWduKHt9LGUse3ZhbHVlOmwsbGVuZ3RoOnAscXVldWU6Y30pfWZ1bmN0aW9uIGZpdHMoZSx0LG4scixpKXtmb3IodmFyIG89dC5sZW5ndGgsYT1bZV07bj49MDspaWYoMCE9PWEubGVuZ3RoKXt2YXIgcz1hLnBvcCgpLHU9c1swXSxjPXNbMV0sbD1zWzJdO2lmKCJzdHJpbmciPT09dHlwZW9mIGwpbi09dXRpbC5nZXRTdHJpbmdXaWR0aChsKTtlbHNlIHN3aXRjaChsLnR5cGUpe2Nhc2UiY29uY2F0Ijpmb3IodmFyIHA9bC5wYXJ0cy5sZW5ndGgtMTtwPj0wO3AtLSlhLnB1c2goW3UsYyxsLnBhcnRzW3BdXSk7YnJlYWs7Y2FzZSJpbmRlbnQiOmEucHVzaChbbWFrZUluZGVudCh1LHIpLGMsbC5jb250ZW50c10pO2JyZWFrO2Nhc2UiYWxpZ24iOmEucHVzaChbbWFrZUFsaWduKHUsbC5uLHIpLGMsbC5jb250ZW50c10pO2JyZWFrO2Nhc2UiZ3JvdXAiOmlmKGkmJmwuYnJlYWspcmV0dXJuITE7YS5wdXNoKFt1LGwuYnJlYWs/TU9ERV9CUkVBSzpjLGwuY29udGVudHNdKTticmVhaztjYXNlImZpbGwiOmZvcih2YXIgZj1sLnBhcnRzLmxlbmd0aC0xO2Y+PTA7Zi0tKWEucHVzaChbdSxjLGwucGFydHNbZl1dKTticmVhaztjYXNlImlmLWJyZWFrIjpjPT09TU9ERV9CUkVBSyYmbC5icmVha0NvbnRlbnRzJiZhLnB1c2goW3UsYyxsLmJyZWFrQ29udGVudHNdKSxjPT09TU9ERV9GTEFUJiZsLmZsYXRDb250ZW50cyYmYS5wdXNoKFt1LGMsbC5mbGF0Q29udGVudHNdKTticmVhaztjYXNlImxpbmUiOnN3aXRjaChjKXtjYXNlIE1PREVfRkxBVDppZighbC5oYXJkKXtsLnNvZnR8fChuLT0xKTticmVha31yZXR1cm4hMDtjYXNlIE1PREVfQlJFQUs6cmV0dXJuITB9fX1lbHNle2lmKDA9PT1vKXJldHVybiEwO2EucHVzaCh0W28tMV0pLG8tLX1yZXR1cm4hMX1mdW5jdGlvbiBwcmludERvY1RvU3RyaW5nKGUsdCl7Zm9yKHZhciBuPXQucHJpbnRXaWR0aCxyPXQubmV3TGluZXx8IlxuIixpPTAsbz1bW3Jvb3RJbmRlbnQoKSxNT0RFX0JSRUFLLGVdXSxhPVtdLHM9ITEsdT1bXTswIT09by5sZW5ndGg7KXt2YXIgYz1vLnBvcCgpLGw9Y1swXSxwPWNbMV0sZj1jWzJdO2lmKCJzdHJpbmciPT09dHlwZW9mIGYpYS5wdXNoKGYpLGkrPXV0aWwuZ2V0U3RyaW5nV2lkdGgoZik7ZWxzZSBzd2l0Y2goZi50eXBlKXtjYXNlImN1cnNvciI6YS5wdXNoKGN1cnNvciQyLnBsYWNlaG9sZGVyKTticmVhaztjYXNlImNvbmNhdCI6Zm9yKHZhciBkPWYucGFydHMubGVuZ3RoLTE7ZD49MDtkLS0pby5wdXNoKFtsLHAsZi5wYXJ0c1tkXV0pO2JyZWFrO2Nhc2UiaW5kZW50IjpvLnB1c2goW21ha2VJbmRlbnQobCx0KSxwLGYuY29udGVudHNdKTticmVhaztjYXNlImFsaWduIjpvLnB1c2goW21ha2VBbGlnbihsLGYubix0KSxwLGYuY29udGVudHNdKTticmVhaztjYXNlImdyb3VwIjpzd2l0Y2gocCl7Y2FzZSBNT0RFX0ZMQVQ6aWYoIXMpe28ucHVzaChbbCxmLmJyZWFrP01PREVfQlJFQUs6TU9ERV9GTEFULGYuY29udGVudHNdKTticmVha31jYXNlIE1PREVfQlJFQUs6cz0hMTt2YXIgaD1bbCxNT0RFX0ZMQVQsZi5jb250ZW50c10sbT1uLWk7aWYoIWYuYnJlYWsmJmZpdHMoaCxvLG0sdCkpby5wdXNoKGgpO2Vsc2UgaWYoZi5leHBhbmRlZFN0YXRlcyl7dmFyIGc9Zi5leHBhbmRlZFN0YXRlc1tmLmV4cGFuZGVkU3RhdGVzLmxlbmd0aC0xXTtpZihmLmJyZWFrKXtvLnB1c2goW2wsTU9ERV9CUkVBSyxnXSk7YnJlYWt9Zm9yKHZhciB5PTE7eTxmLmV4cGFuZGVkU3RhdGVzLmxlbmd0aCsxO3krKyl7aWYoeT49Zi5leHBhbmRlZFN0YXRlcy5sZW5ndGgpe28ucHVzaChbbCxNT0RFX0JSRUFLLGddKTticmVha312YXIgdj1mLmV4cGFuZGVkU3RhdGVzW3ldLGI9W2wsTU9ERV9GTEFULHZdO2lmKGZpdHMoYixvLG0sdCkpe28ucHVzaChiKTticmVha319fWVsc2Ugby5wdXNoKFtsLE1PREVfQlJFQUssZi5jb250ZW50c10pfWJyZWFrO2Nhc2UiZmlsbCI6dmFyIHg9bi1pLEM9Zi5wYXJ0cztpZigwPT09Qy5sZW5ndGgpYnJlYWs7dmFyIEU9Q1swXSxEPVtsLE1PREVfRkxBVCxFXSx3PVtsLE1PREVfQlJFQUssRV0sUz1maXRzKEQsW10seCx0LCEwKTtpZigxPT09Qy5sZW5ndGgpe1M/by5wdXNoKEQpOm8ucHVzaCh3KTticmVha312YXIgaz1DWzFdLEE9W2wsTU9ERV9GTEFULGtdLF89W2wsTU9ERV9CUkVBSyxrXTtpZigyPT09Qy5sZW5ndGgpe1M/KG8ucHVzaChBKSxvLnB1c2goRCkpOihvLnB1c2goXyksby5wdXNoKHcpKTticmVha31DLnNwbGljZSgwLDIpO3ZhciBUPVtsLHAsZmlsbCQxKEMpXSxPPUNbMF07Zml0cyhbbCxNT0RFX0ZMQVQsY29uY2F0JDIoW0UsayxPXSldLFtdLHgsdCwhMCk/KG8ucHVzaChUKSxvLnB1c2goQSksby5wdXNoKEQpKTpTPyhvLnB1c2goVCksby5wdXNoKF8pLG8ucHVzaChEKSk6KG8ucHVzaChUKSxvLnB1c2goXyksby5wdXNoKHcpKTticmVhaztjYXNlImlmLWJyZWFrIjpwPT09TU9ERV9CUkVBSyYmZi5icmVha0NvbnRlbnRzJiZvLnB1c2goW2wscCxmLmJyZWFrQ29udGVudHNdKSxwPT09TU9ERV9GTEFUJiZmLmZsYXRDb250ZW50cyYmby5wdXNoKFtsLHAsZi5mbGF0Q29udGVudHNdKTticmVhaztjYXNlImxpbmUtc3VmZml4Ijp1LnB1c2goW2wscCxmLmNvbnRlbnRzXSk7YnJlYWs7Y2FzZSJsaW5lLXN1ZmZpeC1ib3VuZGFyeSI6dS5sZW5ndGg+MCYmby5wdXNoKFtsLHAse3R5cGU6ImxpbmUiLGhhcmQ6ITB9XSk7YnJlYWs7Y2FzZSJsaW5lIjpzd2l0Y2gocCl7Y2FzZSBNT0RFX0ZMQVQ6aWYoIWYuaGFyZCl7Zi5zb2Z0fHwoYS5wdXNoKCIgIiksaSs9MSk7YnJlYWt9cz0hMDtjYXNlIE1PREVfQlJFQUs6aWYodS5sZW5ndGgpe28ucHVzaChbbCxwLGZdKSxbXS5wdXNoLmFwcGx5KG8sdS5yZXZlcnNlKCkpLHU9W107YnJlYWt9aWYoZi5saXRlcmFsKWwucm9vdD8oYS5wdXNoKHIsbC5yb290LnZhbHVlKSxpPWwucm9vdC5sZW5ndGgpOihhLnB1c2gociksaT0wKTtlbHNle2lmKGEubGVuZ3RoPjApe2Zvcig7YS5sZW5ndGg+MCYmInN0cmluZyI9PT10eXBlb2YgYVthLmxlbmd0aC0xXSYmYVthLmxlbmd0aC0xXS5tYXRjaCgvXlteXFNcbl0qJC8pOylhLnBvcCgpOyFhLmxlbmd0aHx8InN0cmluZyIhPT10eXBlb2YgYVthLmxlbmd0aC0xXXx8Im1hcmtkb3duIj09PXQucGFyc2VyJiYvXFMgezJ9JC8udGVzdChhW2EubGVuZ3RoLTFdKXx8KGFbYS5sZW5ndGgtMV09YVthLmxlbmd0aC0xXS5yZXBsYWNlKC9bXlxTXG5dKiQvLCIiKSl9YS5wdXNoKHIrbC52YWx1ZSksaT1sLmxlbmd0aH19fX12YXIgRj1hLmluZGV4T2YoY3Vyc29yJDIucGxhY2Vob2xkZXIpO2lmKC0xIT09Ril7dmFyIE49YS5pbmRleE9mKGN1cnNvciQyLnBsYWNlaG9sZGVyLEYrMSksST1hLnNsaWNlKDAsRikuam9pbigiIiksTD1hLnNsaWNlKEYrMSxOKS5qb2luKCIiKTtyZXR1cm57Zm9ybWF0dGVkOkkrTCthLnNsaWNlKE4rMSkuam9pbigiIiksY3Vyc29yTm9kZVN0YXJ0OkkubGVuZ3RoLGN1cnNvck5vZGVUZXh0Okx9fXJldHVybntmb3JtYXR0ZWQ6YS5qb2luKCIiKX19ZnVuY3Rpb24gdHJhdmVyc2VEb2MoZSx0LG4scil7ZnVuY3Rpb24gaShlKXt2YXIgbz0hMDtpZih0JiYhMT09PXQoZSkmJihvPSExKSxvKWlmKCJjb25jYXQiPT09ZS50eXBlfHwiZmlsbCI9PT1lLnR5cGUpZm9yKHZhciBhPTA7YTxlLnBhcnRzLmxlbmd0aDthKyspaShlLnBhcnRzW2FdKTtlbHNlImlmLWJyZWFrIj09PWUudHlwZT8oZS5icmVha0NvbnRlbnRzJiZpKGUuYnJlYWtDb250ZW50cyksZS5mbGF0Q29udGVudHMmJmkoZS5mbGF0Q29udGVudHMpKToiZ3JvdXAiPT09ZS50eXBlJiZlLmV4cGFuZGVkU3RhdGVzP3I/ZS5leHBhbmRlZFN0YXRlcy5mb3JFYWNoKGkpOmkoZS5jb250ZW50cyk6ZS5jb250ZW50cyYmaShlLmNvbnRlbnRzKTtuJiZuKGUpfWkoZSl9ZnVuY3Rpb24gbWFwRG9jKGUsdCl7aWYoImNvbmNhdCI9PT1lLnR5cGV8fCJmaWxsIj09PWUudHlwZSl7dmFyIG49ZS5wYXJ0cy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIG1hcERvYyhlLHQpfSk7cmV0dXJuIHQoT2JqZWN0LmFzc2lnbih7fSxlLHtwYXJ0czpufSkpfWlmKCJpZi1icmVhayI9PT1lLnR5cGUpe3ZhciByPWUuYnJlYWtDb250ZW50cyYmbWFwRG9jKGUuYnJlYWtDb250ZW50cyx0KSxpPWUuZmxhdENvbnRlbnRzJiZtYXBEb2MoZS5mbGF0Q29udGVudHMsdCk7cmV0dXJuIHQoT2JqZWN0LmFzc2lnbih7fSxlLHticmVha0NvbnRlbnRzOnIsZmxhdENvbnRlbnRzOml9KSl9aWYoZS5jb250ZW50cyl7dmFyIG89bWFwRG9jKGUuY29udGVudHMsdCk7cmV0dXJuIHQoT2JqZWN0LmFzc2lnbih7fSxlLHtjb250ZW50czpvfSkpfXJldHVybiB0KGUpfWZ1bmN0aW9uIGZpbmRJbkRvYyhlLHQsbil7dmFyIHI9bixpPSExO3JldHVybiB0cmF2ZXJzZURvYyhlLGZ1bmN0aW9uKGUpe3ZhciBuPXQoZSk7aWYodm9pZCAwIT09biYmKGk9ITAscj1uKSxpKXJldHVybiExfSkscn1mdW5jdGlvbiBpc0VtcHR5KGUpe3JldHVybiJzdHJpbmciPT09dHlwZW9mIGUmJjA9PT1lLmxlbmd0aH1mdW5jdGlvbiBpc0xpbmVOZXh0KGUpe3JldHVybiBmaW5kSW5Eb2MoZSxmdW5jdGlvbihlKXtyZXR1cm4ic3RyaW5nIiE9PXR5cGVvZiBlJiYoImxpbmUiPT09ZS50eXBlfHx2b2lkIDApfSwhMSl9ZnVuY3Rpb24gd2lsbEJyZWFrKGUpe3JldHVybiBmaW5kSW5Eb2MoZSxmdW5jdGlvbihlKXtyZXR1cm4hKCJncm91cCIhPT1lLnR5cGV8fCFlLmJyZWFrKXx8KCEoImxpbmUiIT09ZS50eXBlfHwhZS5oYXJkKXx8KCJicmVhay1wYXJlbnQiPT09ZS50eXBlfHx2b2lkIDApKX0sITEpfWZ1bmN0aW9uIGJyZWFrUGFyZW50R3JvdXAoZSl7aWYoZS5sZW5ndGg+MCl7dmFyIHQ9ZVtlLmxlbmd0aC0xXTt0LmV4cGFuZGVkU3RhdGVzfHwodC5icmVhaz0hMCl9cmV0dXJuIG51bGx9ZnVuY3Rpb24gcHJvcGFnYXRlQnJlYWtzKGUpe3ZhciB0PW5ldyBNYXAsbj1bXTt0cmF2ZXJzZURvYyhlLGZ1bmN0aW9uKGUpe2lmKCJicmVhay1wYXJlbnQiPT09ZS50eXBlJiZicmVha1BhcmVudEdyb3VwKG4pLCJncm91cCI9PT1lLnR5cGUpe2lmKG4ucHVzaChlKSx0LmhhcyhlKSlyZXR1cm4hMTt0LnNldChlLCEwKX19LGZ1bmN0aW9uKGUpe2lmKCJncm91cCI9PT1lLnR5cGUpe24ucG9wKCkuYnJlYWsmJmJyZWFrUGFyZW50R3JvdXAobil9fSwhMCl9ZnVuY3Rpb24gcmVtb3ZlTGluZXMoZSl7cmV0dXJuIG1hcERvYyhlLGZ1bmN0aW9uKGUpe3JldHVybiJsaW5lIiE9PWUudHlwZXx8ZS5oYXJkPyJpZi1icmVhayI9PT1lLnR5cGU/ZS5mbGF0Q29udGVudHN8fCIiOmU6ZS5zb2Z0PyIiOiIgIn0pfWZ1bmN0aW9uIHN0cmlwVHJhaWxpbmdIYXJkbGluZShlKXtyZXR1cm4iY29uY2F0Ij09PWUudHlwZSYmMj09PWUucGFydHMubGVuZ3RoJiYiY29uY2F0Ij09PWUucGFydHNbMV0udHlwZSYmMj09PWUucGFydHNbMV0ucGFydHMubGVuZ3RoJiZlLnBhcnRzWzFdLnBhcnRzWzBdLmhhcmQmJiJicmVhay1wYXJlbnQiPT09ZS5wYXJ0c1sxXS5wYXJ0c1sxXS50eXBlP2UucGFydHNbMF06ZX1mdW5jdGlvbiBmbGF0dGVuRG9jKGUpe2lmKCJjb25jYXQiPT09ZS50eXBlKXtmb3IodmFyIHQ9W10sbj0wO248ZS5wYXJ0cy5sZW5ndGg7KytuKXt2YXIgcj1lLnBhcnRzW25dO2lmKCJzdHJpbmciIT09dHlwZW9mIHImJiJjb25jYXQiPT09ci50eXBlKVtdLnB1c2guYXBwbHkodCxmbGF0dGVuRG9jKHIpLnBhcnRzKTtlbHNle3ZhciBpPWZsYXR0ZW5Eb2Mocik7IiIhPT1pJiZ0LnB1c2goaSl9fXJldHVybiBPYmplY3QuYXNzaWduKHt9LGUse3BhcnRzOnR9KX1yZXR1cm4iaWYtYnJlYWsiPT09ZS50eXBlP09iamVjdC5hc3NpZ24oe30sZSx7YnJlYWtDb250ZW50czpudWxsIT1lLmJyZWFrQ29udGVudHM/ZmxhdHRlbkRvYyhlLmJyZWFrQ29udGVudHMpOm51bGwsZmxhdENvbnRlbnRzOm51bGwhPWUuZmxhdENvbnRlbnRzP2ZsYXR0ZW5Eb2MoZS5mbGF0Q29udGVudHMpOm51bGx9KToiZ3JvdXAiPT09ZS50eXBlP09iamVjdC5hc3NpZ24oe30sZSx7Y29udGVudHM6ZmxhdHRlbkRvYyhlLmNvbnRlbnRzKSxleHBhbmRlZFN0YXRlczplLmV4cGFuZGVkU3RhdGVzP2UuZXhwYW5kZWRTdGF0ZXMubWFwKGZsYXR0ZW5Eb2MpOmUuZXhwYW5kZWRTdGF0ZXN9KTplLmNvbnRlbnRzP09iamVjdC5hc3NpZ24oe30sZSx7Y29udGVudHM6ZmxhdHRlbkRvYyhlLmNvbnRlbnRzKX0pOmV9ZnVuY3Rpb24gcHJpbnREb2MoZSl7aWYoInN0cmluZyI9PT10eXBlb2YgZSlyZXR1cm4gSlNPTi5zdHJpbmdpZnkoZSk7aWYoImxpbmUiPT09ZS50eXBlKXJldHVybiBlLmxpdGVyYWxsaW5lPyJsaXRlcmFsbGluZSI6ZS5oYXJkPyJoYXJkbGluZSI6ZS5zb2Z0PyJzb2Z0bGluZSI6ImxpbmUiO2lmKCJicmVhay1wYXJlbnQiPT09ZS50eXBlKXJldHVybiJicmVha1BhcmVudCI7aWYoImNvbmNhdCI9PT1lLnR5cGUpcmV0dXJuIlsiK2UucGFydHMubWFwKHByaW50RG9jKS5qb2luKCIsICIpKyJdIjtpZigiaW5kZW50Ij09PWUudHlwZSlyZXR1cm4iaW5kZW50KCIrcHJpbnREb2MoZS5jb250ZW50cykrIikiO2lmKCJhbGlnbiI9PT1lLnR5cGUpcmV0dXJuIGUubj09PS0xLzA/ImRlZGVudFRvUm9vdCgiK3ByaW50RG9jKGUuY29udGVudHMpKyIpIjplLm48MD8iZGVkZW50KCIrcHJpbnREb2MoZS5jb250ZW50cykrIikiOiJyb290Ij09PWUubi50eXBlPyJtYXJrQXNSb290KCIrcHJpbnREb2MoZS5jb250ZW50cykrIikiOiJhbGlnbigiK0pTT04uc3RyaW5naWZ5KGUubikrIiwgIitwcmludERvYyhlLmNvbnRlbnRzKSsiKSI7aWYoImlmLWJyZWFrIj09PWUudHlwZSlyZXR1cm4iaWZCcmVhaygiK3ByaW50RG9jKGUuYnJlYWtDb250ZW50cykrKGUuZmxhdENvbnRlbnRzPyIsICIrcHJpbnREb2MoZS5mbGF0Q29udGVudHMpOiIiKSsiKSI7aWYoImdyb3VwIj09PWUudHlwZSlyZXR1cm4gZS5leHBhbmRlZFN0YXRlcz8iY29uZGl0aW9uYWxHcm91cChbIitlLmV4cGFuZGVkU3RhdGVzLm1hcChwcmludERvYykuam9pbigiLCIpKyJdKSI6KGUuYnJlYWs/IndyYXBwZWRHcm91cCI6Imdyb3VwIikrIigiK3ByaW50RG9jKGUuY29udGVudHMpKyIpIjtpZigiZmlsbCI9PT1lLnR5cGUpcmV0dXJuImZpbGwoIitlLnBhcnRzLm1hcChwcmludERvYykuam9pbigiLCAiKSsiKSI7aWYoImxpbmUtc3VmZml4Ij09PWUudHlwZSlyZXR1cm4ibGluZVN1ZmZpeCgiK3ByaW50RG9jKGUuY29udGVudHMpKyIpIjtpZigibGluZS1zdWZmaXgtYm91bmRhcnkiPT09ZS50eXBlKXJldHVybiJsaW5lU3VmZml4Qm91bmRhcnkiO3Rocm93IG5ldyBFcnJvcigiVW5rbm93biBkb2MgdHlwZSAiK2UudHlwZSl9ZnVuY3Rpb24gaXNOZXh0TGluZUVtcHR5JDEoZSx0LG4pe3JldHVybiB1dGlsLmlzTmV4dExpbmVFbXB0eShlLHQsbi5sb2NFbmQpfWZ1bmN0aW9uIGdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXJJbmRleCQxKGUsdCxuKXtyZXR1cm4gdXRpbC5nZXROZXh0Tm9uU3BhY2VOb25Db21tZW50Q2hhcmFjdGVySW5kZXgoZSx0LG4ubG9jRW5kKX1mdW5jdGlvbiBnZXRTb3J0ZWRDaGlsZE5vZGVzKGUsdCxuKXtpZihlKXt2YXIgcj10LnByaW50ZXIsaT10LmxvY1N0YXJ0LG89dC5sb2NFbmQ7aWYobil7aWYoZSYmci5jYW5BdHRhY2hDb21tZW50JiZyLmNhbkF0dGFjaENvbW1lbnQoZSkpe3ZhciBhO2ZvcihhPW4ubGVuZ3RoLTE7YT49MCYmIShpKG5bYV0pPD1pKGUpJiZvKG5bYV0pPD1vKGUpKTstLWEpO3JldHVybiB2b2lkIG4uc3BsaWNlKGErMSwwLGUpfX1lbHNlIGlmKGVbY2hpbGROb2Rlc0NhY2hlS2V5XSlyZXR1cm4gZVtjaGlsZE5vZGVzQ2FjaGVLZXldO3ZhciBzO2lmKHIuZ2V0Q29tbWVudENoaWxkTm9kZXM/cz1yLmdldENvbW1lbnRDaGlsZE5vZGVzKGUpOmUmJiJvYmplY3QiPT09X3R5cGVvZihlKSYmKHM9T2JqZWN0LmtleXMoZSkuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiJlbmNsb3NpbmdOb2RlIiE9PWUmJiJwcmVjZWRpbmdOb2RlIiE9PWUmJiJmb2xsb3dpbmdOb2RlIiE9PWV9KS5tYXAoZnVuY3Rpb24odCl7cmV0dXJuIGVbdF19KSkscylyZXR1cm4gbnx8T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsY2hpbGROb2Rlc0NhY2hlS2V5LHt2YWx1ZTpuPVtdLGVudW1lcmFibGU6ITF9KSxzLmZvckVhY2goZnVuY3Rpb24oZSl7Z2V0U29ydGVkQ2hpbGROb2RlcyhlLHQsbil9KSxufX1mdW5jdGlvbiBkZWNvcmF0ZUNvbW1lbnQoZSx0LG4pe2Zvcih2YXIgcixpLG89bi5sb2NTdGFydCxhPW4ubG9jRW5kLHM9Z2V0U29ydGVkQ2hpbGROb2RlcyhlLG4pLHU9MCxjPXMubGVuZ3RoO3U8Yzspe3ZhciBsPXUrYz4+MSxwPXNbbF07aWYobyhwKS1vKHQpPD0wJiZhKHQpLWEocCk8PTApcmV0dXJuIHQuZW5jbG9zaW5nTm9kZT1wLHZvaWQgZGVjb3JhdGVDb21tZW50KHAsdCxuKTtpZihhKHApLW8odCk8PTApcj1wLHU9bCsxO2Vsc2V7aWYoIShhKHQpLW8ocCk8PTApKXRocm93IG5ldyBFcnJvcigiQ29tbWVudCBsb2NhdGlvbiBvdmVybGFwcyB3aXRoIG5vZGUgbG9jYXRpb24iKTtpPXAsYz1sfX1pZih0LmVuY2xvc2luZ05vZGUmJiJUZW1wbGF0ZUxpdGVyYWwiPT09dC5lbmNsb3NpbmdOb2RlLnR5cGUpe3ZhciBmPXQuZW5jbG9zaW5nTm9kZS5xdWFzaXMsZD1maW5kRXhwcmVzc2lvbkluZGV4Rm9yQ29tbWVudChmLHQsbik7ciYmZmluZEV4cHJlc3Npb25JbmRleEZvckNvbW1lbnQoZixyLG4pIT09ZCYmKHI9bnVsbCksaSYmZmluZEV4cHJlc3Npb25JbmRleEZvckNvbW1lbnQoZixpLG4pIT09ZCYmKGk9bnVsbCl9ciYmKHQucHJlY2VkaW5nTm9kZT1yKSxpJiYodC5mb2xsb3dpbmdOb2RlPWkpfWZ1bmN0aW9uIGF0dGFjaChlLHQsbixyKXtpZihBcnJheS5pc0FycmF5KGUpKXt2YXIgaT1bXSxvPXIubG9jU3RhcnQsYT1yLmxvY0VuZDtlLmZvckVhY2goZnVuY3Rpb24ocyx1KXtpZigoImpzb24iPT09ci5wYXJzZXJ8fCJqc29uNSI9PT1yLnBhcnNlcikmJm8ocyktbyh0KTw9MClyZXR1cm4gdm9pZCBhZGRMZWFkaW5nQ29tbWVudCh0LHMpO2RlY29yYXRlQ29tbWVudCh0LHMscik7dmFyIGM9cy5wcmVjZWRpbmdOb2RlLGw9cy5lbmNsb3NpbmdOb2RlLHA9cy5mb2xsb3dpbmdOb2RlLGY9ci5wcmludGVyLmhhbmRsZUNvbW1lbnRzJiZyLnByaW50ZXIuaGFuZGxlQ29tbWVudHMub3duTGluZT9yLnByaW50ZXIuaGFuZGxlQ29tbWVudHMub3duTGluZTpmdW5jdGlvbigpe3JldHVybiExfSxkPXIucHJpbnRlci5oYW5kbGVDb21tZW50cyYmci5wcmludGVyLmhhbmRsZUNvbW1lbnRzLmVuZE9mTGluZT9yLnByaW50ZXIuaGFuZGxlQ29tbWVudHMuZW5kT2ZMaW5lOmZ1bmN0aW9uKCl7cmV0dXJuITF9LGg9ci5wcmludGVyLmhhbmRsZUNvbW1lbnRzJiZyLnByaW50ZXIuaGFuZGxlQ29tbWVudHMucmVtYWluaW5nP3IucHJpbnRlci5oYW5kbGVDb21tZW50cy5yZW1haW5pbmc6ZnVuY3Rpb24oKXtyZXR1cm4hMX0sbT1lLmxlbmd0aC0xPT09dTtpZihoYXNOZXdsaW5lKG4sbyhzKSx7YmFja3dhcmRzOiEwfSkpZihzLG4scix0LG0pfHwocD9hZGRMZWFkaW5nQ29tbWVudChwLHMpOmM/YWRkVHJhaWxpbmdDb21tZW50KGMscyk6bD9hZGREYW5nbGluZ0NvbW1lbnQobCxzKTphZGREYW5nbGluZ0NvbW1lbnQodCxzKSk7ZWxzZSBpZihoYXNOZXdsaW5lKG4sYShzKSkpZChzLG4scix0LG0pfHwoYz9hZGRUcmFpbGluZ0NvbW1lbnQoYyxzKTpwP2FkZExlYWRpbmdDb21tZW50KHAscyk6bD9hZGREYW5nbGluZ0NvbW1lbnQobCxzKTphZGREYW5nbGluZ0NvbW1lbnQodCxzKSk7ZWxzZSBpZihoKHMsbixyLHQsbSkpO2Vsc2UgaWYoYyYmcCl7dmFyIGc9aS5sZW5ndGg7aWYoZz4wKXt2YXIgeT1pW2ctMV07eS5mb2xsb3dpbmdOb2RlIT09cy5mb2xsb3dpbmdOb2RlJiZicmVha1RpZXMoaSxuLHIpfWkucHVzaChzKX1lbHNlIGM/YWRkVHJhaWxpbmdDb21tZW50KGMscyk6cD9hZGRMZWFkaW5nQ29tbWVudChwLHMpOmw/YWRkRGFuZ2xpbmdDb21tZW50KGwscyk6YWRkRGFuZ2xpbmdDb21tZW50KHQscyl9KSxicmVha1RpZXMoaSxuLHIpLGUuZm9yRWFjaChmdW5jdGlvbihlKXtkZWxldGUgZS5wcmVjZWRpbmdOb2RlLGRlbGV0ZSBlLmVuY2xvc2luZ05vZGUsZGVsZXRlIGUuZm9sbG93aW5nTm9kZX0pfX1mdW5jdGlvbiBicmVha1RpZXMoZSx0LG4pe3ZhciByPWUubGVuZ3RoO2lmKDAhPT1yKXt2YXIgaSxvPWVbMF0ucHJlY2VkaW5nTm9kZSxhPWVbMF0uZm9sbG93aW5nTm9kZSxzPW4ubG9jU3RhcnQoYSk7Zm9yKGk9cjtpPjA7LS1pKXt2YXIgdT1lW2ktMV07YXNzZXJ0LnN0cmljdEVxdWFsKHUucHJlY2VkaW5nTm9kZSxvKSxhc3NlcnQuc3RyaWN0RXF1YWwodS5mb2xsb3dpbmdOb2RlLGEpO3ZhciBjPXQuc2xpY2Uobi5sb2NFbmQodSkscykudHJpbSgpO2lmKCIiIT09YyYmIS9eXCgrJC8udGVzdChjKSlicmVhaztzPW4ubG9jU3RhcnQodSl9ZS5mb3JFYWNoKGZ1bmN0aW9uKGUsdCl7dDxpP2FkZFRyYWlsaW5nQ29tbWVudChvLGUpOmFkZExlYWRpbmdDb21tZW50KGEsZSl9KSxlLmxlbmd0aD0wfX1mdW5jdGlvbiBwcmludENvbW1lbnQoZSx0KXtyZXR1cm4gZS5nZXRWYWx1ZSgpLnByaW50ZWQ9ITAsdC5wcmludGVyLnByaW50Q29tbWVudChlLHQpfWZ1bmN0aW9uIGZpbmRFeHByZXNzaW9uSW5kZXhGb3JDb21tZW50KGUsdCxuKXtmb3IodmFyIHI9bi5sb2NTdGFydCh0KS0xLGk9MTtpPGUubGVuZ3RoOysraSlpZihyPGdldFF1YXNpUmFuZ2UoZVtpXSkuc3RhcnQpcmV0dXJuIGktMTtyZXR1cm4gMH1mdW5jdGlvbiBnZXRRdWFzaVJhbmdlKGUpe3JldHVybiB2b2lkIDAhPT1lLnN0YXJ0P3tzdGFydDplLnN0YXJ0LGVuZDplLmVuZH06e3N0YXJ0OmUucmFuZ2VbMF0sZW5kOmUucmFuZ2VbMV19fWZ1bmN0aW9uIHByaW50TGVhZGluZ0NvbW1lbnQoZSx0LG4pe3ZhciByPWUuZ2V0VmFsdWUoKSxpPXByaW50Q29tbWVudChlLG4pO2lmKCFpKXJldHVybiIiO3ZhciBvPW4ucHJpbnRlci5pc0Jsb2NrQ29tbWVudCYmbi5wcmludGVyLmlzQmxvY2tDb21tZW50KHIpO3JldHVybiBjb25jYXQobz9baSxoYXNOZXdsaW5lKG4ub3JpZ2luYWxUZXh0LG4ubG9jRW5kKHIpKT9oYXJkbGluZToiICJdOltpLGhhcmRsaW5lXSl9ZnVuY3Rpb24gcHJpbnRUcmFpbGluZ0NvbW1lbnQoZSx0LG4pe3ZhciByPWUuZ2V0VmFsdWUoKSxpPXByaW50Q29tbWVudChlLG4pO2lmKCFpKXJldHVybiIiO3ZhciBvPW4ucHJpbnRlci5pc0Jsb2NrQ29tbWVudCYmbi5wcmludGVyLmlzQmxvY2tDb21tZW50KHIpLGE9ZS5nZXROb2RlKDEpLHM9ZS5nZXROb2RlKDIpLHU9cyYmKCJDbGFzc0RlY2xhcmF0aW9uIj09PXMudHlwZXx8IkNsYXNzRXhwcmVzc2lvbiI9PT1zLnR5cGUpJiZzLnN1cGVyQ2xhc3M9PT1hO2lmKGhhc05ld2xpbmUobi5vcmlnaW5hbFRleHQsbi5sb2NTdGFydChyKSx7YmFja3dhcmRzOiEwfSkpe3ZhciBjPWlzUHJldmlvdXNMaW5lRW1wdHkobi5vcmlnaW5hbFRleHQscixuLmxvY1N0YXJ0KTtyZXR1cm4gbGluZVN1ZmZpeChjb25jYXQoW2hhcmRsaW5lLGM/aGFyZGxpbmU6IiIsaV0pKX1yZXR1cm4gY29uY2F0KG98fHU/WyIgIixpXTpbbGluZVN1ZmZpeCgiICIraSksbz8iIjpicmVha1BhcmVudF0pfWZ1bmN0aW9uIHByaW50RGFuZ2xpbmdDb21tZW50cyhlLHQsbixyKXt2YXIgaT1bXSxvPWUuZ2V0VmFsdWUoKTtyZXR1cm4gbyYmby5jb21tZW50cz8oZS5lYWNoKGZ1bmN0aW9uKGUpe3ZhciBuPWUuZ2V0VmFsdWUoKTshbnx8bi5sZWFkaW5nfHxuLnRyYWlsaW5nfHxyJiYhcihuKXx8aS5wdXNoKHByaW50Q29tbWVudChlLHQpKX0sImNvbW1lbnRzIiksMD09PWkubGVuZ3RoPyIiOm4/am9pbihoYXJkbGluZSxpKTppbmRlbnQoY29uY2F0KFtoYXJkbGluZSxqb2luKGhhcmRsaW5lLGkpXSkpKToiIn1mdW5jdGlvbiBwcmVwZW5kQ3Vyc29yUGxhY2Vob2xkZXIoZSx0LG4pe3JldHVybiBlLmdldE5vZGUoKT09PXQuY3Vyc29yTm9kZSYmZS5nZXRWYWx1ZSgpP2NvbmNhdChbY3Vyc29yLG4sY3Vyc29yXSk6bn1mdW5jdGlvbiBwcmludENvbW1lbnRzKGUsdCxuLHIpe3ZhciBpPWUuZ2V0VmFsdWUoKSxvPXQoZSksYT1pJiZpLmNvbW1lbnRzO2lmKCFhfHwwPT09YS5sZW5ndGgpcmV0dXJuIHByZXBlbmRDdXJzb3JQbGFjZWhvbGRlcihlLG4sbyk7dmFyIHM9W10sdT1bcj8iOyI6IiIsb107cmV0dXJuIGUuZWFjaChmdW5jdGlvbihlKXt2YXIgcj1lLmdldFZhbHVlKCksaT1yLmxlYWRpbmcsbz1yLnRyYWlsaW5nO2lmKGkpe3ZhciBhPXByaW50TGVhZGluZ0NvbW1lbnQoZSx0LG4pO2lmKCFhKXJldHVybjtzLnB1c2goYSk7dmFyIGM9bi5vcmlnaW5hbFRleHQ7aGFzTmV3bGluZShjLHNraXBOZXdsaW5lKGMsbi5sb2NFbmQocikpKSYmcy5wdXNoKGhhcmRsaW5lKX1lbHNlIG8mJnUucHVzaChwcmludFRyYWlsaW5nQ29tbWVudChlLHQsbikpfSwiY29tbWVudHMiKSxwcmVwZW5kQ3Vyc29yUGxhY2Vob2xkZXIoZSxuLGNvbmNhdChzLmNvbmNhdCh1KSkpfWZ1bmN0aW9uIEZhc3RQYXRoKGUpe2Fzc2VydC5vayh0aGlzIGluc3RhbmNlb2YgRmFzdFBhdGgpLHRoaXMuc3RhY2s9W2VdfWZ1bmN0aW9uIGdldE5vZGVIZWxwZXIoZSx0KXtmb3IodmFyIG49ZS5zdGFjayxyPW4ubGVuZ3RoLTE7cj49MDtyLT0yKXt2YXIgaT1uW3JdO2lmKGkmJiFBcnJheS5pc0FycmF5KGkpJiYtLXQ8MClyZXR1cm4gaX1yZXR1cm4gbnVsbH1mdW5jdGlvbiBwcmludFN1YnRyZWUoZSx0LG4scil7aWYobi5wcmludGVyLmVtYmVkKXJldHVybiBuLnByaW50ZXIuZW1iZWQoZSx0LGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRleHRUb0RvYyhlLHQsbixyKX0sbil9ZnVuY3Rpb24gdGV4dFRvRG9jKGUsdCxuLHIpe3ZhciBpPW5vcm1hbGl6ZSQxKE9iamVjdC5hc3NpZ24oe30sbix0LHtwYXJlbnRQYXJzZXI6bi5wYXJzZXIsb3JpZ2luYWxUZXh0OmV9KSx7cGFzc1Rocm91Z2g6ITB9KSxvPXBhcnNlci5wYXJzZShlLGkpLGE9by5hc3Q7ZT1vLnRleHQ7dmFyIHM9YS5jb21tZW50cztyZXR1cm4gZGVsZXRlIGEuY29tbWVudHMsY29tbWVudHMuYXR0YWNoKHMsYSxlLGkpLHIoYSxpKX1mdW5jdGlvbiBwcmludEFzdFRvRG9jKGUsdCxuKXtmdW5jdGlvbiByKGUsbil7dmFyIGE9ZS5nZXRWYWx1ZSgpLHM9YSYmIm9iamVjdCI9PT1fdHlwZW9mKGEpJiZ2b2lkIDA9PT1uO2lmKHMmJm8uaGFzKGEpKXJldHVybiBvLmdldChhKTt2YXIgdTtyZXR1cm4gdT1pLndpbGxQcmludE93bkNvbW1lbnRzJiZpLndpbGxQcmludE93bkNvbW1lbnRzKGUpP2dlbmVyaWNQcmludChlLHQscixuKTpjb21tZW50cy5wcmludENvbW1lbnRzKGUsZnVuY3Rpb24oZSl7cmV0dXJuIGdlbmVyaWNQcmludChlLHQscixuKX0sdCxuJiZuLm5lZWRzU2VtaSkscyYmby5zZXQoYSx1KSx1fW49bnx8MDt2YXIgaT10LnByaW50ZXIsbz1uZXcgTWFwLGE9cihuZXcgZmFzdFBhdGgoZSkpO3JldHVybiBuPjAmJihhPWFkZEFsaWdubWVudFRvRG9jJDEoZG9jVXRpbHMkMi5yZW1vdmVMaW5lcyhjb25jYXQkMyhbaGFyZGxpbmUkMixhXSkpLG4sdC50YWJXaWR0aCkpLGRvY1V0aWxzJDIucHJvcGFnYXRlQnJlYWtzKGEpLCJqc29uIiE9PXQucGFyc2VyJiYianNvbjUiIT09dC5wYXJzZXImJiJqc29uLXN0cmluZ2lmeSIhPT10LnBhcnNlcnx8KGE9Y29uY2F0JDMoW2EsaGFyZGxpbmUkMl0pKSxhfWZ1bmN0aW9uIGdlbmVyaWNQcmludChlLHQsbixyKXthc3NlcnQub2soZSBpbnN0YW5jZW9mIGZhc3RQYXRoKTt2YXIgaT1lLmdldFZhbHVlKCksbz10LnByaW50ZXI7aWYoby5oYXNQcmV0dGllcklnbm9yZSYmby5oYXNQcmV0dGllcklnbm9yZShlKSlyZXR1cm4gdC5vcmlnaW5hbFRleHQuc2xpY2UodC5sb2NTdGFydChpKSx0LmxvY0VuZChpKSk7aWYoaSl0cnl7dmFyIGE9bXVsdGlwYXJzZXIucHJpbnRTdWJ0cmVlKGUsbix0LHByaW50QXN0VG9Eb2MpO2lmKGEpcmV0dXJuIGF9Y2F0Y2goZSl7aWYoY29tbW9uanNHbG9iYWwuUFJFVFRJRVJfREVCVUcpdGhyb3cgZX1yZXR1cm4gby5wcmludChlLHQsbixyKX1mdW5jdGlvbiBmaW5kU2libGluZ0FuY2VzdG9ycyhlLHQsbil7dmFyIHI9ZS5ub2RlLGk9dC5ub2RlO2lmKHI9PT1pKXJldHVybntzdGFydE5vZGU6cixlbmROb2RlOml9O3ZhciBvPSEwLGE9ITEscz12b2lkIDA7dHJ5e2Zvcih2YXIgdSxjPXQucGFyZW50Tm9kZXNbU3ltYm9sLml0ZXJhdG9yXSgpOyEobz0odT1jLm5leHQoKSkuZG9uZSk7bz0hMCl7dmFyIGw9dS52YWx1ZTtpZighKCJQcm9ncmFtIiE9PWwudHlwZSYmIkZpbGUiIT09bC50eXBlJiZuLmxvY1N0YXJ0KGwpPj1uLmxvY1N0YXJ0KGUubm9kZSkpKWJyZWFrO2k9bH19Y2F0Y2goZSl7YT0hMCxzPWV9ZmluYWxseXt0cnl7b3x8bnVsbD09Yy5yZXR1cm58fGMucmV0dXJuKCl9ZmluYWxseXtpZihhKXRocm93IHN9fXZhciBwPSEwLGY9ITEsZD12b2lkIDA7dHJ5e2Zvcih2YXIgaCxtPWUucGFyZW50Tm9kZXNbU3ltYm9sLml0ZXJhdG9yXSgpOyEocD0oaD1tLm5leHQoKSkuZG9uZSk7cD0hMCl7dmFyIGc9aC52YWx1ZTtpZighKCJQcm9ncmFtIiE9PWcudHlwZSYmIkZpbGUiIT09Zy50eXBlJiZuLmxvY0VuZChnKTw9bi5sb2NFbmQodC5ub2RlKSkpYnJlYWs7cj1nfX1jYXRjaChlKXtmPSEwLGQ9ZX1maW5hbGx5e3RyeXtwfHxudWxsPT1tLnJldHVybnx8bS5yZXR1cm4oKX1maW5hbGx5e2lmKGYpdGhyb3cgZH19cmV0dXJue3N0YXJ0Tm9kZTpyLGVuZE5vZGU6aX19ZnVuY3Rpb24gZmluZE5vZGVBdE9mZnNldChlLHQsbixyLGkpe3I9cnx8ZnVuY3Rpb24oKXtyZXR1cm4hMH0saT1pfHxbXTt2YXIgbz1uLmxvY1N0YXJ0KGUsbi5sb2NTdGFydCksYT1uLmxvY0VuZChlLG4ubG9jRW5kKTtpZihvPD10JiZ0PD1hKXt2YXIgcz0hMCx1PSExLGM9dm9pZCAwO3RyeXtmb3IodmFyIGwscD1jb21tZW50cy5nZXRTb3J0ZWRDaGlsZE5vZGVzKGUsbilbU3ltYm9sLml0ZXJhdG9yXSgpOyEocz0obD1wLm5leHQoKSkuZG9uZSk7cz0hMCl7dmFyIGY9bC52YWx1ZSxkPWZpbmROb2RlQXRPZmZzZXQoZix0LG4scixbZV0uY29uY2F0KGkpKTtpZihkKXJldHVybiBkfX1jYXRjaChlKXt1PSEwLGM9ZX1maW5hbGx5e3RyeXtzfHxudWxsPT1wLnJldHVybnx8cC5yZXR1cm4oKX1maW5hbGx5e2lmKHUpdGhyb3cgY319aWYocihlKSlyZXR1cm57bm9kZTplLHBhcmVudE5vZGVzOml9fX1mdW5jdGlvbiBpc1NvdXJjZUVsZW1lbnQoZSx0KXtpZihudWxsPT10KXJldHVybiExO3ZhciBuPVsiRnVuY3Rpb25EZWNsYXJhdGlvbiIsIkJsb2NrU3RhdGVtZW50IiwiQnJlYWtTdGF0ZW1lbnQiLCJDb250aW51ZVN0YXRlbWVudCIsIkRlYnVnZ2VyU3RhdGVtZW50IiwiRG9XaGlsZVN0YXRlbWVudCIsIkVtcHR5U3RhdGVtZW50IiwiRXhwcmVzc2lvblN0YXRlbWVudCIsIkZvckluU3RhdGVtZW50IiwiRm9yU3RhdGVtZW50IiwiSWZTdGF0ZW1lbnQiLCJMYWJlbGVkU3RhdGVtZW50IiwiUmV0dXJuU3RhdGVtZW50IiwiU3dpdGNoU3RhdGVtZW50IiwiVGhyb3dTdGF0ZW1lbnQiLCJUcnlTdGF0ZW1lbnQiLCJWYXJpYWJsZURlY2xhcmF0aW9uIiwiV2hpbGVTdGF0ZW1lbnQiLCJXaXRoU3RhdGVtZW50IiwiQ2xhc3NEZWNsYXJhdGlvbiIsIkltcG9ydERlY2xhcmF0aW9uIiwiRXhwb3J0RGVmYXVsdERlY2xhcmF0aW9uIiwiRXhwb3J0TmFtZWREZWNsYXJhdGlvbiIsIkV4cG9ydEFsbERlY2xhcmF0aW9uIiwiVHlwZUFsaWFzIiwiSW50ZXJmYWNlRGVjbGFyYXRpb24iLCJUeXBlQWxpYXNEZWNsYXJhdGlvbiIsIkV4cG9ydEFzc2lnbm1lbnQiLCJFeHBvcnREZWNsYXJhdGlvbiJdLHI9WyJPYmplY3RFeHByZXNzaW9uIiwiQXJyYXlFeHByZXNzaW9uIiwiU3RyaW5nTGl0ZXJhbCIsIk51bWVyaWNMaXRlcmFsIiwiQm9vbGVhbkxpdGVyYWwiLCJOdWxsTGl0ZXJhbCJdLGk9WyJPcGVyYXRpb25EZWZpbml0aW9uIiwiRnJhZ21lbnREZWZpbml0aW9uIiwiVmFyaWFibGVEZWZpbml0aW9uIiwiVHlwZUV4dGVuc2lvbkRlZmluaXRpb24iLCJPYmplY3RUeXBlRGVmaW5pdGlvbiIsIkZpZWxkRGVmaW5pdGlvbiIsIkRpcmVjdGl2ZURlZmluaXRpb24iLCJFbnVtVHlwZURlZmluaXRpb24iLCJFbnVtVmFsdWVEZWZpbml0aW9uIiwiSW5wdXRWYWx1ZURlZmluaXRpb24iLCJJbnB1dE9iamVjdFR5cGVEZWZpbml0aW9uIiwiU2NoZW1hRGVmaW5pdGlvbiIsIk9wZXJhdGlvblR5cGVEZWZpbml0aW9uIiwiSW50ZXJmYWNlVHlwZURlZmluaXRpb24iLCJVbmlvblR5cGVEZWZpbml0aW9uIiwiU2NhbGFyVHlwZURlZmluaXRpb24iXTtzd2l0Y2goZS5wYXJzZXIpe2Nhc2UiZmxvdyI6Y2FzZSJiYWJ5bG9uIjpjYXNlInR5cGVzY3JpcHQiOnJldHVybiBuLmluZGV4T2YodC50eXBlKT4tMTtjYXNlImpzb24iOnJldHVybiByLmluZGV4T2YodC50eXBlKT4tMTtjYXNlImdyYXBocWwiOnJldHVybiBpLmluZGV4T2YodC5raW5kKT4tMX1yZXR1cm4hMX1mdW5jdGlvbiBjYWxjdWxhdGVSYW5nZShlLHQsbil7dmFyIHIsaT1lLnNsaWNlKHQucmFuZ2VTdGFydCx0LnJhbmdlRW5kKSxvPU1hdGgubWF4KHQucmFuZ2VTdGFydCtpLnNlYXJjaCgvXFMvKSx0LnJhbmdlU3RhcnQpO2ZvcihyPXQucmFuZ2VFbmQ7cj50LnJhbmdlU3RhcnQmJiFlW3ItMV0ubWF0Y2goL1xTLyk7LS1yKTt2YXIgYT1maW5kTm9kZUF0T2Zmc2V0KG4sbyx0LGZ1bmN0aW9uKGUpe3JldHVybiBpc1NvdXJjZUVsZW1lbnQodCxlKX0pLHM9ZmluZE5vZGVBdE9mZnNldChuLHIsdCxmdW5jdGlvbihlKXtyZXR1cm4gaXNTb3VyY2VFbGVtZW50KHQsZSl9KTtpZighYXx8IXMpcmV0dXJue3JhbmdlU3RhcnQ6MCxyYW5nZUVuZDowfTt2YXIgdT1maW5kU2libGluZ0FuY2VzdG9ycyhhLHMsdCksYz11LnN0YXJ0Tm9kZSxsPXUuZW5kTm9kZTtyZXR1cm57cmFuZ2VTdGFydDpNYXRoLm1pbih0LmxvY1N0YXJ0KGMsdC5sb2NTdGFydCksdC5sb2NTdGFydChsLHQubG9jU3RhcnQpKSxyYW5nZUVuZDpNYXRoLm1heCh0LmxvY0VuZChjLHQubG9jRW5kKSx0LmxvY0VuZChsLHQubG9jRW5kKSl9fWZ1bmN0aW9uIGd1ZXNzTGluZUVuZGluZyhlKXt2YXIgdD1lLmluZGV4T2YoIlxuIik7cmV0dXJuIHQ+PTAmJiJcciI9PT1lLmNoYXJBdCh0LTEpPyJcclxuIjoiXG4ifWZ1bmN0aW9uIGVuc3VyZUFsbENvbW1lbnRzUHJpbnRlZChlKXtpZihlKXtmb3IodmFyIHQ9MDt0PGUubGVuZ3RoOysrdClpZigicHJldHRpZXItaWdub3JlIj09PWVbdF0udmFsdWUudHJpbSgpKXJldHVybjtlLmZvckVhY2goZnVuY3Rpb24oZSl7aWYoIWUucHJpbnRlZCl0aHJvdyBuZXcgRXJyb3IoJ0NvbW1lbnQgIicrZS52YWx1ZS50cmltKCkrJyIgd2FzIG5vdCBwcmludGVkLiBQbGVhc2UgcmVwb3J0IHRoaXMgZXJyb3IhJyk7ZGVsZXRlIGUucHJpbnRlZH0pfX1mdW5jdGlvbiBhdHRhY2hDb21tZW50cyhlLHQsbil7dmFyIHI9dC5jb21tZW50cztyZXR1cm4gciYmKGRlbGV0ZSB0LmNvbW1lbnRzLGNvbW1lbnRzLmF0dGFjaChyLHQsZSxuKSksdC50b2tlbnM9W10sbi5vcmlnaW5hbFRleHQ9ZS50cmltUmlnaHQoKSxyfWZ1bmN0aW9uIGNvcmVGb3JtYXQoZSx0LG4pe249bnx8MDt2YXIgcj1wYXJzZXIucGFyc2UoZSx0KSxpPXIuYXN0O2lmKGU9ci50ZXh0LHQuY3Vyc29yT2Zmc2V0Pj0wKXt2YXIgbz1yYW5nZVV0aWwuZmluZE5vZGVBdE9mZnNldChpLHQuY3Vyc29yT2Zmc2V0LHQpO28mJm8ubm9kZSYmKHQuY3Vyc29yTm9kZT1vLm5vZGUpfXZhciBhPWF0dGFjaENvbW1lbnRzKGUsaSx0KSxzPWFzdFRvRG9jKGksdCxuKTt0Lm5ld0xpbmU9Z3Vlc3NMaW5lRW5kaW5nKGUpO3ZhciB1PV9wcmludERvY1RvU3RyaW5nKHMsdCk7aWYoZW5zdXJlQWxsQ29tbWVudHNQcmludGVkKGEpLG4+MCl7dmFyIGM9dS5mb3JtYXR0ZWQudHJpbSgpO3ZvaWQgMCE9PXUuY3Vyc29yTm9kZVN0YXJ0JiYodS5jdXJzb3JOb2RlU3RhcnQtPXUuZm9ybWF0dGVkLmluZGV4T2YoYykpLHUuZm9ybWF0dGVkPWMrdC5uZXdMaW5lfWlmKHQuY3Vyc29yT2Zmc2V0Pj0wKXt2YXIgbCxwLGYsZCxoO2lmKHQuY3Vyc29yTm9kZSYmdS5jdXJzb3JOb2RlVGV4dD8obD10LmxvY1N0YXJ0KHQuY3Vyc29yTm9kZSkscD1lLnNsaWNlKGwsdC5sb2NFbmQodC5jdXJzb3JOb2RlKSksZj10LmN1cnNvck9mZnNldC1sLGQ9dS5jdXJzb3JOb2RlU3RhcnQsaD11LmN1cnNvck5vZGVUZXh0KToobD0wLHA9ZSxmPXQuY3Vyc29yT2Zmc2V0LGQ9MCxoPXUuZm9ybWF0dGVkKSxwPT09aClyZXR1cm57Zm9ybWF0dGVkOnUuZm9ybWF0dGVkLGN1cnNvck9mZnNldDpkK2Z9O3ZhciBtPXAuc3BsaXQoIiIpO20uc3BsaWNlKGYsMCxDVVJTT1IpO3ZhciBnPWguc3BsaXQoIiIpLHk9bGliLmRpZmZBcnJheXMobSxnKSx2PWQsYj0hMCx4PSExLEM9dm9pZCAwO3RyeXtmb3IodmFyIEUsRD15W1N5bWJvbC5pdGVyYXRvcl0oKTshKGI9KEU9RC5uZXh0KCkpLmRvbmUpO2I9ITApe3ZhciB3PUUudmFsdWU7aWYody5yZW1vdmVkKXtpZih3LnZhbHVlLmluZGV4T2YoQ1VSU09SKT4tMSlicmVha31lbHNlIHYrPXcuY291bnR9fWNhdGNoKGUpe3g9ITAsQz1lfWZpbmFsbHl7dHJ5e2J8fG51bGw9PUQucmV0dXJufHxELnJldHVybigpfWZpbmFsbHl7aWYoeCl0aHJvdyBDfX1yZXR1cm57Zm9ybWF0dGVkOnUuZm9ybWF0dGVkLGN1cnNvck9mZnNldDp2fX1yZXR1cm57Zm9ybWF0dGVkOnUuZm9ybWF0dGVkfX1mdW5jdGlvbiBmb3JtYXRSYW5nZShlLHQpe3ZhciBuPXBhcnNlci5wYXJzZShlLHQpLHI9bi5hc3Q7ZT1uLnRleHQ7dmFyIGk9cmFuZ2VVdGlsLmNhbGN1bGF0ZVJhbmdlKGUsdCxyKSxvPWkucmFuZ2VTdGFydCxhPWkucmFuZ2VFbmQscz1lLnNsaWNlKG8sYSksdT1NYXRoLm1pbihvLGUubGFzdEluZGV4T2YoIlxuIixvKSsxKSxjPWUuc2xpY2UodSxvKSxsPXV0aWwuZ2V0QWxpZ25tZW50U2l6ZShjLHQudGFiV2lkdGgpLHA9Y29yZUZvcm1hdChzLE9iamVjdC5hc3NpZ24oe30sdCx7cmFuZ2VTdGFydDowLHJhbmdlRW5kOjEvMCxwcmludFdpZHRoOnQucHJpbnRXaWR0aC1sLGN1cnNvck9mZnNldDp0LmN1cnNvck9mZnNldD49byYmdC5jdXJzb3JPZmZzZXQ8YT90LmN1cnNvck9mZnNldC1vOi0xfSksbCksZj1wLmZvcm1hdHRlZC50cmltUmlnaHQoKSxkPWUuc2xpY2UoMCxvKStmK2Uuc2xpY2UoYSksaD10LmN1cnNvck9mZnNldDtyZXR1cm4gdC5jdXJzb3JPZmZzZXQ+PWE/aD10LmN1cnNvck9mZnNldC1hKyhvK2YubGVuZ3RoKTp2b2lkIDAhPT1wLmN1cnNvck9mZnNldCYmKGg9cC5jdXJzb3JPZmZzZXQrbykse2Zvcm1hdHRlZDpkLGN1cnNvck9mZnNldDpofX1mdW5jdGlvbiBmb3JtYXQoZSx0KXt2YXIgbj1wYXJzZXIucmVzb2x2ZVBhcnNlcih0KSxyPSFuLmhhc1ByYWdtYXx8bi5oYXNQcmFnbWEoZSk7aWYodC5yZXF1aXJlUHJhZ21hJiYhcilyZXR1cm57Zm9ybWF0dGVkOmV9O2lmKHQucmFuZ2VTdGFydD4wfHx0LnJhbmdlRW5kPGUubGVuZ3RoKXJldHVybiBmb3JtYXRSYW5nZShlLHQpO3ZhciBpPWUuY2hhckNvZGVBdCgwKT09PVVURjhCT007aSYmKGU9ZS5zdWJzdHJpbmcoMSkpLHQuaW5zZXJ0UHJhZ21hJiZ0LnByaW50ZXIuaW5zZXJ0UHJhZ21hJiYhciYmKGU9dC5wcmludGVyLmluc2VydFByYWdtYShlKSk7dmFyIG89Y29yZUZvcm1hdChlLHQpO3JldHVybiBpJiYoby5mb3JtYXR0ZWQ9U3RyaW5nLmZyb21DaGFyQ29kZShVVEY4Qk9NKStvLmZvcm1hdHRlZCksb31mdW5jdGlvbiBlbWJlZChlLHQsbil7ZnVuY3Rpb24gcihlKXt2YXIgdD1uKGUse3BhcnNlcjoibWFya2Rvd24iLF9faW5Kc1RlbXBsYXRlOiEwfSk7cmV0dXJuIHN0cmlwVHJhaWxpbmdIYXJkbGluZSQxKGVzY2FwZUJhY2t0aWNrcyh0KSl9dmFyIGk9ZS5nZXRWYWx1ZSgpLG89ZS5nZXRQYXJlbnROb2RlKCksYT1lLmdldFBhcmVudE5vZGUoMSk7c3dpdGNoKGkudHlwZSl7Y2FzZSJUZW1wbGF0ZUxpdGVyYWwiOmlmKFtpc1N0eWxlZEpzeCxpc1N0eWxlZENvbXBvbmVudHMsaXNDc3NQcm9wLGlzQW5ndWxhckNvbXBvbmVudFN0eWxlc10uc29tZShmdW5jdGlvbih0KXtyZXR1cm4gdChlKX0pKXt2YXIgcz1pLnF1YXNpcy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUudmFsdWUucmF3fSksdT0wLGM9cy5yZWR1Y2UoZnVuY3Rpb24oZSx0LG4pe3JldHVybiAwPT1uP3Q6ZSsiQHByZXR0aWVyLXBsYWNlaG9sZGVyLSIrdSsrKyItaWQiK3R9LCIiKTtyZXR1cm4gdHJhbnNmb3JtQ3NzRG9jKG4oYyx7cGFyc2VyOiJjc3MifSksZSx0KX1pZihpc0dyYXBoUUwoZSkpe3ZhciBsPWkuZXhwcmVzc2lvbnM/ZS5tYXAodCwiZXhwcmVzc2lvbnMiKTpbXSxwPWkucXVhc2lzLmxlbmd0aDtpZigxPT09cCYmIiI9PT1pLnF1YXNpc1swXS52YWx1ZS5yYXcudHJpbSgpKXJldHVybiJgYCI7Zm9yKHZhciBmPVtdLGQ9MDtkPHA7ZCsrKXt2YXIgaD1pLnF1YXNpc1tkXSxtPTA9PT1kLGc9ZD09PXAtMSx5PWgudmFsdWUuY29va2VkO2lmKCJzdHJpbmciIT09dHlwZW9mIHkpcmV0dXJuIG51bGw7dmFyIHY9eS5zcGxpdCgiXG4iKSxiPXYubGVuZ3RoLHg9bFtkXSxDPWI+MiYmIiI9PT12WzBdLnRyaW0oKSYmIiI9PT12WzFdLnRyaW0oKSxFPWI+MiYmIiI9PT12W2ItMV0udHJpbSgpJiYiIj09PXZbYi0yXS50cmltKCksRD12LmV2ZXJ5KGZ1bmN0aW9uKGUpe3JldHVybi9eXHMqKD86I1teXHJcbl0qKT8kLy50ZXN0KGUpfSk7aWYoIWcmJi8jW15cclxuXSokLy50ZXN0KHZbYi0xXSkpcmV0dXJuIG51bGw7dmFyIHc9bnVsbDt3PUQ/cHJpbnRHcmFwaHFsQ29tbWVudHModik6c3RyaXBUcmFpbGluZ0hhcmRsaW5lJDEobih5LHtwYXJzZXI6ImdyYXBocWwifSkpLHc/KHc9ZXNjYXBlQmFja3RpY2tzKHcpLCFtJiZDJiZmLnB1c2goIiIpLGYucHVzaCh3KSwhZyYmRSYmZi5wdXNoKCIiKSk6bXx8Z3x8IUN8fGYucHVzaCgiIikseCYmZi5wdXNoKGNvbmNhdCQ1KFsiJHsiLHgsIn0iXSkpfXJldHVybiBjb25jYXQkNShbImAiLGluZGVudCQzKGNvbmNhdCQ1KFtoYXJkbGluZSQ0LGpvaW4kMyhoYXJkbGluZSQ0LGYpXSkpLGhhcmRsaW5lJDQsImAiXSl9YnJlYWs7Y2FzZSJUZW1wbGF0ZUVsZW1lbnQiOmlmKGEmJiJUYWdnZWRUZW1wbGF0ZUV4cHJlc3Npb24iPT09YS50eXBlJiYxPT09by5xdWFzaXMubGVuZ3RoJiYiSWRlbnRpZmllciI9PT1hLnRhZy50eXBlJiYoIm1kIj09PWEudGFnLm5hbWV8fCJtYXJrZG93biI9PT1hLnRhZy5uYW1lKSl7dmFyIFM9by5xdWFzaXNbMF0udmFsdWUucmF3LnJlcGxhY2UoLygoPzpcXFxcKSopXFxgL2csZnVuY3Rpb24oZSx0KXtyZXR1cm4iXFwiLnJlcGVhdCh0Lmxlbmd0aC8yKSsiYCJ9KSxrPWdldEluZGVudGF0aW9uKFMpO3JldHVybiBjb25jYXQkNShbIiIhPT1rP2luZGVudCQzKGNvbmNhdCQ1KFtzb2Z0bGluZSQyLHIoUy5yZXBsYWNlKG5ldyBSZWdFeHAoIl4iLmNvbmNhdChrKSwiZ20iKSwiIikpXSkpOmNvbmNhdCQ1KFtsaXRlcmFsbGluZSQyLGRlZGVudFRvUm9vdCQxKHIoUykpXSksc29mdGxpbmUkMl0pfX19ZnVuY3Rpb24gaXNQcm9wZXJ0eVdpdGhpbkFuZ3VsYXJDb21wb25lbnREZWNvcmF0b3IoZSx0KXt2YXIgbj1lLmdldFBhcmVudE5vZGUodCk7cmV0dXJuISEobiYmIkRlY29yYXRvciI9PT1uLnR5cGUmJm4uZXhwcmVzc2lvbiYmIkNhbGxFeHByZXNzaW9uIj09PW4uZXhwcmVzc2lvbi50eXBlJiZuLmV4cHJlc3Npb24uY2FsbGVlJiYiQ29tcG9uZW50Ij09PW4uZXhwcmVzc2lvbi5jYWxsZWUubmFtZSl9ZnVuY3Rpb24gZ2V0SW5kZW50YXRpb24oZSl7dmFyIHQ9ZS5tYXRjaCgvXihbXlxTXG5dKilcUy9tKTtyZXR1cm4gbnVsbD09PXQ/IiI6dFsxXX1mdW5jdGlvbiBlc2NhcGVCYWNrdGlja3MoZSl7cmV0dXJuIG1hcERvYyQyKGUsZnVuY3Rpb24oZSl7aWYoIWUucGFydHMpcmV0dXJuIGU7dmFyIHQ9W107cmV0dXJuIGUucGFydHMuZm9yRWFjaChmdW5jdGlvbihlKXsic3RyaW5nIj09PXR5cGVvZiBlP3QucHVzaChlLnJlcGxhY2UoLyhcXCopYC9nLCIkMSQxXFxgIikpOnQucHVzaChlKX0pLE9iamVjdC5hc3NpZ24oe30sZSx7cGFydHM6dH0pfSl9ZnVuY3Rpb24gdHJhbnNmb3JtQ3NzRG9jKGUsdCxuKXt2YXIgcj10LmdldFZhbHVlKCk7aWYoMT09PXIucXVhc2lzLmxlbmd0aCYmIXIucXVhc2lzWzBdLnZhbHVlLnJhdy50cmltKCkpcmV0dXJuImBgIjt2YXIgaT1yLmV4cHJlc3Npb25zP3QubWFwKG4sImV4cHJlc3Npb25zIik6W10sbz1yZXBsYWNlUGxhY2Vob2xkZXJzKGUsaSk7aWYoIW8pdGhyb3cgbmV3IEVycm9yKCJDb3VsZG4ndCBpbnNlcnQgYWxsIHRoZSBleHByZXNzaW9ucyIpO3JldHVybiBjb25jYXQkNShbImAiLGluZGVudCQzKGNvbmNhdCQ1KFtoYXJkbGluZSQ0LHN0cmlwVHJhaWxpbmdIYXJkbGluZSQxKG8pXSkpLHNvZnRsaW5lJDIsImAiXSl9ZnVuY3Rpb24gcmVwbGFjZVBsYWNlaG9sZGVycyhlLHQpe2lmKCF0fHwhdC5sZW5ndGgpcmV0dXJuIGU7dmFyIG49dC5zbGljZSgpLHI9MCxpPW1hcERvYyQyKGUsZnVuY3Rpb24oZSl7aWYoIWV8fCFlLnBhcnRzfHwhZS5wYXJ0cy5sZW5ndGgpcmV0dXJuIGU7dmFyIHQ9ZS5wYXJ0cyxpPXQuaW5kZXhPZigiQCIpLG89aSsxO2lmKGk+LTEmJiJzdHJpbmciPT09dHlwZW9mIHRbb10mJnRbb10uc3RhcnRzV2l0aCgicHJldHRpZXItcGxhY2Vob2xkZXIiKSl7dmFyIGE9dFtpXSxzPXRbb10sdT10LnNsaWNlKG8rMSk7dD10LnNsaWNlKDAsaSkuY29uY2F0KFthK3NdKS5jb25jYXQodSl9dmFyIGM9dC5maW5kSW5kZXgoZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyI9PT10eXBlb2YgZSYmZS5zdGFydHNXaXRoKCJAcHJldHRpZXItcGxhY2Vob2xkZXIiKX0pO2lmKGM+LTEpe3ZhciBsPXRbY10scD10LnNsaWNlKGMrMSksZj1sLm1hdGNoKC9AcHJldHRpZXItcGxhY2Vob2xkZXItKC4rKS1pZChbXHNcU10qKS8pLGQ9ZlsxXSxoPWZbMl0sbT1uW2RdO3IrKyx0PXQuc2xpY2UoMCxjKS5jb25jYXQoWyIkeyIsbSwifSIraF0pLmNvbmNhdChwKX1yZXR1cm4gT2JqZWN0LmFzc2lnbih7fSxlLHtwYXJ0czp0fSl9KTtyZXR1cm4gbi5sZW5ndGg9PT1yP2k6bnVsbH1mdW5jdGlvbiBwcmludEdyYXBocWxDb21tZW50cyhlKXt2YXIgdD1bXSxuPSExO3JldHVybiBlLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS50cmltKCl9KS5mb3JFYWNoKGZ1bmN0aW9uKGUscixpKXsiIiE9PWUmJigiIj09PWlbci0xXSYmbj90LnB1c2goY29uY2F0JDUoW2hhcmRsaW5lJDQsZV0pKTp0LnB1c2goZSksbj0hMCl9KSwwPT09dC5sZW5ndGg/bnVsbDpqb2luJDMoaGFyZGxpbmUkNCx0KX1mdW5jdGlvbiBpc1N0eWxlZEpzeChlKXt2YXIgdD1lLmdldFZhbHVlKCksbj1lLmdldFBhcmVudE5vZGUoKSxyPWUuZ2V0UGFyZW50Tm9kZSgxKTtyZXR1cm4gciYmdC5xdWFzaXMmJiJKU1hFeHByZXNzaW9uQ29udGFpbmVyIj09PW4udHlwZSYmIkpTWEVsZW1lbnQiPT09ci50eXBlJiYic3R5bGUiPT09ci5vcGVuaW5nRWxlbWVudC5uYW1lLm5hbWUmJnIub3BlbmluZ0VsZW1lbnQuYXR0cmlidXRlcy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiJqc3giPT09ZS5uYW1lLm5hbWV9KX1mdW5jdGlvbiBpc0FuZ3VsYXJDb21wb25lbnRTdHlsZXMoZSl7dmFyIHQ9ZS5nZXRQYXJlbnROb2RlKCksbj1lLmdldFBhcmVudE5vZGUoMSk7cmV0dXJuISghdHx8IkFycmF5RXhwcmVzc2lvbiIhPT10LnR5cGV8fCJQcm9wZXJ0eSIhPT1uLnR5cGV8fCFpc1Byb3BlcnR5V2l0aGluQW5ndWxhckNvbXBvbmVudERlY29yYXRvcihlLDQpfHwhbi5rZXl8fCJzdHlsZXMiIT09bi5rZXkubmFtZSl9ZnVuY3Rpb24gaXNTdHlsZWRDb21wb25lbnRzKGUpe3ZhciB0PWUuZ2V0UGFyZW50Tm9kZSgpO2lmKCF0fHwiVGFnZ2VkVGVtcGxhdGVFeHByZXNzaW9uIiE9PXQudHlwZSlyZXR1cm4hMTt2YXIgbj10LnRhZztzd2l0Y2gobi50eXBlKXtjYXNlIk1lbWJlckV4cHJlc3Npb24iOnJldHVybiBpc1N0eWxlZElkZW50aWZpZXIobi5vYmplY3QpfHxpc1N0eWxlZEV4dGVuZChuKTtjYXNlIkNhbGxFeHByZXNzaW9uIjpyZXR1cm4gaXNTdHlsZWRJZGVudGlmaWVyKG4uY2FsbGVlKXx8Ik1lbWJlckV4cHJlc3Npb24iPT09bi5jYWxsZWUudHlwZSYmKCJNZW1iZXJFeHByZXNzaW9uIj09PW4uY2FsbGVlLm9iamVjdC50eXBlJiYoaXNTdHlsZWRJZGVudGlmaWVyKG4uY2FsbGVlLm9iamVjdC5vYmplY3QpfHxpc1N0eWxlZEV4dGVuZChuLmNhbGxlZS5vYmplY3QpKXx8IkNhbGxFeHByZXNzaW9uIj09PW4uY2FsbGVlLm9iamVjdC50eXBlJiZpc1N0eWxlZElkZW50aWZpZXIobi5jYWxsZWUub2JqZWN0LmNhbGxlZSkpO2Nhc2UiSWRlbnRpZmllciI6cmV0dXJuImNzcyI9PT1uLm5hbWU7ZGVmYXVsdDpyZXR1cm4hMX19ZnVuY3Rpb24gaXNDc3NQcm9wKGUpe3ZhciB0PWUuZ2V0UGFyZW50Tm9kZSgpLG49ZS5nZXRQYXJlbnROb2RlKDEpO3JldHVybiBuJiYiSlNYRXhwcmVzc2lvbkNvbnRhaW5lciI9PT10LnR5cGUmJiJKU1hBdHRyaWJ1dGUiPT09bi50eXBlJiYiSlNYSWRlbnRpZmllciI9PT1uLm5hbWUudHlwZSYmImNzcyI9PT1uLm5hbWUubmFtZX1mdW5jdGlvbiBpc1N0eWxlZElkZW50aWZpZXIoZSl7cmV0dXJuIklkZW50aWZpZXIiPT09ZS50eXBlJiYic3R5bGVkIj09PWUubmFtZX1mdW5jdGlvbiBpc1N0eWxlZEV4dGVuZChlKXtyZXR1cm4vXltBLVpdLy50ZXN0KGUub2JqZWN0Lm5hbWUpJiYiZXh0ZW5kIj09PWUucHJvcGVydHkubmFtZX1mdW5jdGlvbiBpc0dyYXBoUUwoZSl7dmFyIHQ9ZS5nZXRWYWx1ZSgpLG49ZS5nZXRQYXJlbnROb2RlKCk7cmV0dXJuIHQubGVhZGluZ0NvbW1lbnRzJiZ0LmxlYWRpbmdDb21tZW50cy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiJDb21tZW50QmxvY2siPT09ZS50eXBlJiYiIEdyYXBoUUwgIj09PWUudmFsdWV9KXx8biYmKCJUYWdnZWRUZW1wbGF0ZUV4cHJlc3Npb24iPT09bi50eXBlJiYoIk1lbWJlckV4cHJlc3Npb24iPT09bi50YWcudHlwZSYmImdyYXBocWwiPT09bi50YWcub2JqZWN0Lm5hbWUmJiJleHBlcmltZW50YWwiPT09bi50YWcucHJvcGVydHkubmFtZXx8IklkZW50aWZpZXIiPT09bi50YWcudHlwZSYmKCJncWwiPT09bi50YWcubmFtZXx8ImdyYXBocWwiPT09bi50YWcubmFtZSkpfHwiQ2FsbEV4cHJlc3Npb24iPT09bi50eXBlJiYiSWRlbnRpZmllciI9PT1uLmNhbGxlZS50eXBlJiYiZ3JhcGhxbCI9PT1uLmNhbGxlZS5uYW1lKX1mdW5jdGlvbiBjbGVhbihlLHQsbil7aWYoWyJyYW5nZSIsInJhdyIsImNvbW1lbnRzIiwibGVhZGluZ0NvbW1lbnRzIiwidHJhaWxpbmdDb21tZW50cyIsImV4dHJhIiwic3RhcnQiLCJlbmQiLCJmbGFncyJdLmZvckVhY2goZnVuY3Rpb24oZSl7ZGVsZXRlIHRbZV19KSwiRW1wdHlTdGF0ZW1lbnQiPT09ZS50eXBlKXJldHVybiBudWxsO2lmKCJKU1hUZXh0Ij09PWUudHlwZSlyZXR1cm4gbnVsbDtpZigiSlNYRXhwcmVzc2lvbkNvbnRhaW5lciI9PT1lLnR5cGUmJiJMaXRlcmFsIj09PWUuZXhwcmVzc2lvbi50eXBlJiYiICI9PT1lLmV4cHJlc3Npb24udmFsdWUpcmV0dXJuIG51bGw7aWYoIlRTUGFyYW1ldGVyUHJvcGVydHkiPT09ZS50eXBlJiZudWxsPT09ZS5hY2Nlc3NpYmlsaXR5JiYhZS5yZWFkb25seSlyZXR1cm57dHlwZToiSWRlbnRpZmllciIsbmFtZTplLnBhcmFtZXRlci5uYW1lLHR5cGVBbm5vdGF0aW9uOnQucGFyYW1ldGVyLnR5cGVBbm5vdGF0aW9uLGRlY29yYXRvcnM6dC5kZWNvcmF0b3JzfTtpZigiVFNOYW1lc3BhY2VFeHBvcnREZWNsYXJhdGlvbiI9PT1lLnR5cGUmJmUuc3BlY2lmaWVycyYmMD09PWUuc3BlY2lmaWVycy5sZW5ndGgmJmRlbGV0ZSB0LnNwZWNpZmllcnMsIlRTUGFyZW50aGVzaXplZFR5cGUiPT09ZS50eXBlJiYiVFNUeXBlQW5ub3RhdGlvbiI9PT1lLnR5cGVBbm5vdGF0aW9uLnR5cGUpcmV0dXJuIHQudHlwZUFubm90YXRpb24udHlwZUFubm90YXRpb247aWYoIkpTWE9wZW5pbmdFbGVtZW50Ij09PWUudHlwZSYmZGVsZXRlIHQuc2VsZkNsb3NpbmcsIkpTWEVsZW1lbnQiPT09ZS50eXBlJiZkZWxldGUgdC5jbG9zaW5nRWxlbWVudCwiUHJvcGVydHkiIT09ZS50eXBlJiYiT2JqZWN0UHJvcGVydHkiIT09ZS50eXBlJiYiTWV0aG9kRGVmaW5pdGlvbiIhPT1lLnR5cGUmJiJDbGFzc1Byb3BlcnR5IiE9PWUudHlwZSYmIlRTUHJvcGVydHlTaWduYXR1cmUiIT09ZS50eXBlJiYiT2JqZWN0VHlwZVByb3BlcnR5IiE9PWUudHlwZXx8Im9iamVjdCIhPT1fdHlwZW9mKGUua2V5KXx8IWUua2V5fHwiTGl0ZXJhbCIhPT1lLmtleS50eXBlJiYiU3RyaW5nTGl0ZXJhbCIhPT1lLmtleS50eXBlJiYiSWRlbnRpZmllciIhPT1lLmtleS50eXBlfHxkZWxldGUgdC5rZXksIk9wdGlvbmFsTWVtYmVyRXhwcmVzc2lvbiI9PT1lLnR5cGUmJiExPT09ZS5vcHRpb25hbCYmKHQudHlwZT0iTWVtYmVyRXhwcmVzc2lvbiIsZGVsZXRlIHQub3B0aW9uYWwpLCJKU1hFbGVtZW50Ij09PWUudHlwZSYmInN0eWxlIj09PWUub3BlbmluZ0VsZW1lbnQubmFtZS5uYW1lJiZlLm9wZW5pbmdFbGVtZW50LmF0dHJpYnV0ZXMuc29tZShmdW5jdGlvbihlKXtyZXR1cm4ianN4Ij09PWUubmFtZS5uYW1lfSkpe3QuY2hpbGRyZW4uZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiJKU1hFeHByZXNzaW9uQ29udGFpbmVyIj09PWUudHlwZSYmIlRlbXBsYXRlTGl0ZXJhbCI9PT1lLmV4cHJlc3Npb24udHlwZX0pLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS5leHByZXNzaW9ufSkucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuY29uY2F0KHQucXVhc2lzKX0sW10pLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGRlbGV0ZSBlLnZhbHVlfSl9IkpTWEF0dHJpYnV0ZSI9PT1lLnR5cGUmJiJjc3MiPT09ZS5uYW1lLm5hbWUmJiJKU1hFeHByZXNzaW9uQ29udGFpbmVyIj09PWUudmFsdWUudHlwZSYmIlRlbXBsYXRlTGl0ZXJhbCI9PT1lLnZhbHVlLmV4cHJlc3Npb24udHlwZSYmdC52YWx1ZS5leHByZXNzaW9uLnF1YXNpcy5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBkZWxldGUgZS52YWx1ZX0pO3ZhciByPWUuZXhwcmVzc2lvbnx8ZS5jYWxsZWU7aWYoIkRlY29yYXRvciI9PT1lLnR5cGUmJiJDYWxsRXhwcmVzc2lvbiI9PT1yLnR5cGUmJiJDb21wb25lbnQiPT09ci5jYWxsZWUubmFtZSYmMT09PXIuYXJndW1lbnRzLmxlbmd0aCYmci5hcmd1bWVudHNbMF0ucHJvcGVydGllcy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiJzdHlsZXMiPT09ZS5rZXkubmFtZSYmIkFycmF5RXhwcmVzc2lvbiI9PT1lLnZhbHVlLnR5cGV9KSYmdC5leHByZXNzaW9uLmFyZ3VtZW50c1swXS5wcm9wZXJ0aWVzLmZvckVhY2goZnVuY3Rpb24oZSl7IkFycmF5RXhwcmVzc2lvbiI9PT1lLnZhbHVlLnR5cGUmJmUudmFsdWUuZWxlbWVudHNbMF0ucXVhc2lzLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGRlbGV0ZSBlLnZhbHVlfSl9KSwiVGFnZ2VkVGVtcGxhdGVFeHByZXNzaW9uIiE9PWUudHlwZXx8Ik1lbWJlckV4cHJlc3Npb24iIT09ZS50YWcudHlwZSYmKCJJZGVudGlmaWVyIiE9PWUudGFnLnR5cGV8fCJncWwiIT09ZS50YWcubmFtZSYmImdyYXBocWwiIT09ZS50YWcubmFtZSYmImNzcyIhPT1lLnRhZy5uYW1lJiYibWQiIT09ZS50YWcubmFtZSYmIm1hcmtkb3duIiE9PWUudGFnLm5hbWUpJiYiQ2FsbEV4cHJlc3Npb24iIT09ZS50YWcudHlwZXx8dC5xdWFzaS5xdWFzaXMuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gZGVsZXRlIGUudmFsdWV9KSwiVGVtcGxhdGVMaXRlcmFsIj09PWUudHlwZSl7KGUubGVhZGluZ0NvbW1lbnRzJiZlLmxlYWRpbmdDb21tZW50cy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiJDb21tZW50QmxvY2siPT09ZS50eXBlJiYiIEdyYXBoUUwgIj09PWUudmFsdWV9KXx8IkNhbGxFeHByZXNzaW9uIj09PW4udHlwZSYmImdyYXBocWwiPT09bi5jYWxsZWUubmFtZSkmJnQucXVhc2lzLmZvckVhY2goZnVuY3Rpb24oZSl7cmV0dXJuIGRlbGV0ZSBlLnZhbHVlfSl9fWZ1bmN0aW9uIGhhc1ByYWdtYShlKXt2YXIgdD1PYmplY3Qua2V5cyhidWlsZC5wYXJzZShidWlsZC5leHRyYWN0KGUpKSk7cmV0dXJuLTEhPT10LmluZGV4T2YoInByZXR0aWVyIil8fC0xIT09dC5pbmRleE9mKCJmb3JtYXQiKX1mdW5jdGlvbiBpbnNlcnRQcmFnbWEkMShlKXt2YXIgdD1idWlsZC5wYXJzZVdpdGhDb21tZW50cyhidWlsZC5leHRyYWN0KGUpKSxuPU9iamVjdC5hc3NpZ24oe2Zvcm1hdDoiIn0sdC5wcmFnbWFzKSxyPWJ1aWxkLnByaW50KHtwcmFnbWFzOm4sY29tbWVudHM6dC5jb21tZW50cy5yZXBsYWNlKC9eKFxzKz9ccj9cbikrLywiIil9KSxpPWJ1aWxkLnN0cmlwKGUpO3JldHVybiByKyhpLnN0YXJ0c1dpdGgoIlxuIik/IlxuIjoiXG5cbiIpK2l9ZnVuY3Rpb24gaGFuZGxlT3duTGluZUNvbW1lbnQoZSx0LG4scixpKXt2YXIgbz1lLnByZWNlZGluZ05vZGUsYT1lLmVuY2xvc2luZ05vZGUscz1lLmZvbGxvd2luZ05vZGU7cmV0dXJuISEoaGFuZGxlTGFzdEZ1bmN0aW9uQXJnQ29tbWVudHModCxvLGEscyxlLG4pfHxoYW5kbGVNZW1iZXJFeHByZXNzaW9uQ29tbWVudHMoYSxzLGUpfHxoYW5kbGVJZlN0YXRlbWVudENvbW1lbnRzKHQsbyxhLHMsZSxuKXx8aGFuZGxlVHJ5U3RhdGVtZW50Q29tbWVudHMoYSxzLGUpfHxoYW5kbGVDbGFzc0NvbW1lbnRzKGEsbyxzLGUpfHxoYW5kbGVJbXBvcnRTcGVjaWZpZXJDb21tZW50cyhhLGUpfHxoYW5kbGVGb3JDb21tZW50cyhhLG8sZSl8fGhhbmRsZVVuaW9uVHlwZUNvbW1lbnRzKG8sYSxzLGUpfHxoYW5kbGVPbmx5Q29tbWVudHMoYSxyLGUsaSl8fGhhbmRsZUltcG9ydERlY2xhcmF0aW9uQ29tbWVudHModCxhLG8sZSxuKXx8aGFuZGxlQXNzaWdubWVudFBhdHRlcm5Db21tZW50cyhhLGUpfHxoYW5kbGVNZXRob2ROYW1lQ29tbWVudHModCxhLG8sZSxuKSl9ZnVuY3Rpb24gaGFuZGxlRW5kT2ZMaW5lQ29tbWVudChlLHQsbixyLGkpe3ZhciBvPWUucHJlY2VkaW5nTm9kZSxhPWUuZW5jbG9zaW5nTm9kZSxzPWUuZm9sbG93aW5nTm9kZTtyZXR1cm4hIShoYW5kbGVMYXN0RnVuY3Rpb25BcmdDb21tZW50cyh0LG8sYSxzLGUsbil8fGhhbmRsZUNvbmRpdGlvbmFsRXhwcmVzc2lvbkNvbW1lbnRzKGEsbyxzLGUsdCxuKXx8aGFuZGxlSW1wb3J0U3BlY2lmaWVyQ29tbWVudHMoYSxlKXx8aGFuZGxlSWZTdGF0ZW1lbnRDb21tZW50cyh0LG8sYSxzLGUsbil8fGhhbmRsZUNsYXNzQ29tbWVudHMoYSxvLHMsZSl8fGhhbmRsZUxhYmVsZWRTdGF0ZW1lbnRDb21tZW50cyhhLGUpfHxoYW5kbGVDYWxsRXhwcmVzc2lvbkNvbW1lbnRzKG8sYSxlKXx8aGFuZGxlUHJvcGVydHlDb21tZW50cyhhLGUpfHxoYW5kbGVPbmx5Q29tbWVudHMoYSxyLGUsaSl8fGhhbmRsZVR5cGVBbGlhc0NvbW1lbnRzKGEscyxlKXx8aGFuZGxlVmFyaWFibGVEZWNsYXJhdG9yQ29tbWVudHMoYSxzLGUpKX1mdW5jdGlvbiBoYW5kbGVSZW1haW5pbmdDb21tZW50KGUsdCxuLHIsaSl7dmFyIG89ZS5wcmVjZWRpbmdOb2RlLGE9ZS5lbmNsb3NpbmdOb2RlLHM9ZS5mb2xsb3dpbmdOb2RlO3JldHVybiEhKGhhbmRsZUlmU3RhdGVtZW50Q29tbWVudHModCxvLGEscyxlLG4pfHxoYW5kbGVPYmplY3RQcm9wZXJ0eUFzc2lnbm1lbnQoYSxvLGUpfHxoYW5kbGVDb21tZW50SW5FbXB0eVBhcmVucyh0LGEsZSxuKXx8aGFuZGxlTWV0aG9kTmFtZUNvbW1lbnRzKHQsYSxvLGUsbil8fGhhbmRsZU9ubHlDb21tZW50cyhhLHIsZSxpKXx8aGFuZGxlQ29tbWVudEFmdGVyQXJyb3dQYXJhbXModCxhLGUsbil8fGhhbmRsZUZ1bmN0aW9uTmFtZUNvbW1lbnRzKHQsYSxvLGUsbil8fGhhbmRsZVRTTWFwcGVkVHlwZUNvbW1lbnRzKHQsYSxvLHMsZSl8fGhhbmRsZUJyZWFrQW5kQ29udGludWVTdGF0ZW1lbnRDb21tZW50cyhhLGUpKX1mdW5jdGlvbiBhZGRCbG9ja1N0YXRlbWVudEZpcnN0Q29tbWVudChlLHQpe3ZhciBuPWUuYm9keS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIkVtcHR5U3RhdGVtZW50IiE9PWUudHlwZX0pOzA9PT1uLmxlbmd0aD9hZGREYW5nbGluZ0NvbW1lbnQkMihlLHQpOmFkZExlYWRpbmdDb21tZW50JDIoblswXSx0KX1mdW5jdGlvbiBhZGRCbG9ja09yTm90Q29tbWVudChlLHQpeyJCbG9ja1N0YXRlbWVudCI9PT1lLnR5cGU/YWRkQmxvY2tTdGF0ZW1lbnRGaXJzdENvbW1lbnQoZSx0KTphZGRMZWFkaW5nQ29tbWVudCQyKGUsdCl9ZnVuY3Rpb24gaGFuZGxlSWZTdGF0ZW1lbnRDb21tZW50cyhlLHQsbixyLGksbyl7aWYoIW58fCJJZlN0YXRlbWVudCIhPT1uLnR5cGV8fCFyKXJldHVybiExO3ZhciBhPXV0aWwuZ2V0TmV4dE5vblNwYWNlTm9uQ29tbWVudENoYXJhY3RlcihlLGksby5sb2NFbmQpO3JldHVybiIpIj09PWE/KGFkZFRyYWlsaW5nQ29tbWVudCQyKHQsaSksITApOnQ9PT1uLmNvbnNlcXVlbnQmJnI9PT1uLmFsdGVybmF0ZT8oIkJsb2NrU3RhdGVtZW50Ij09PXQudHlwZT9hZGRUcmFpbGluZ0NvbW1lbnQkMih0LGkpOmFkZERhbmdsaW5nQ29tbWVudCQyKG4saSksITApOiJCbG9ja1N0YXRlbWVudCI9PT1yLnR5cGU/KGFkZEJsb2NrU3RhdGVtZW50Rmlyc3RDb21tZW50KHIsaSksITApOiJJZlN0YXRlbWVudCI9PT1yLnR5cGU/KGFkZEJsb2NrT3JOb3RDb21tZW50KHIuY29uc2VxdWVudCxpKSwhMCk6KCJ7Ij09PWF8fG4uY29uc2VxdWVudD09PXIpJiYoYWRkTGVhZGluZ0NvbW1lbnQkMihyLGkpLCEwKX1mdW5jdGlvbiBoYW5kbGVUcnlTdGF0ZW1lbnRDb21tZW50cyhlLHQsbil7cmV0dXJuISghZXx8IlRyeVN0YXRlbWVudCIhPT1lLnR5cGV8fCF0KSYmKCJCbG9ja1N0YXRlbWVudCI9PT10LnR5cGU/KGFkZEJsb2NrU3RhdGVtZW50Rmlyc3RDb21tZW50KHQsbiksITApOiJUcnlTdGF0ZW1lbnQiPT09dC50eXBlPyhhZGRCbG9ja09yTm90Q29tbWVudCh0LmZpbmFsaXplcixuKSwhMCk6IkNhdGNoQ2xhdXNlIj09PXQudHlwZSYmKGFkZEJsb2NrT3JOb3RDb21tZW50KHQuYm9keSxuKSwhMCkpfWZ1bmN0aW9uIGhhbmRsZU1lbWJlckV4cHJlc3Npb25Db21tZW50cyhlLHQsbil7cmV0dXJuISghZXx8Ik1lbWJlckV4cHJlc3Npb24iIT09ZS50eXBlfHwhdHx8IklkZW50aWZpZXIiIT09dC50eXBlKSYmKGFkZExlYWRpbmdDb21tZW50JDIoZSxuKSwhMCl9ZnVuY3Rpb24gaGFuZGxlQ29uZGl0aW9uYWxFeHByZXNzaW9uQ29tbWVudHMoZSx0LG4scixpLG8pe3ZhciBhPXQmJiF1dGlsLmhhc05ld2xpbmVJblJhbmdlKGksby5sb2NFbmQodCksby5sb2NTdGFydChyKSk7cmV0dXJuISh0JiZhfHwhZXx8IkNvbmRpdGlvbmFsRXhwcmVzc2lvbiIhPT1lLnR5cGV8fCFuKSYmKGFkZExlYWRpbmdDb21tZW50JDIobixyKSwhMCl9ZnVuY3Rpb24gaGFuZGxlT2JqZWN0UHJvcGVydHlBc3NpZ25tZW50KGUsdCxuKXtyZXR1cm4hKCFlfHwiT2JqZWN0UHJvcGVydHkiIT09ZS50eXBlJiYiUHJvcGVydHkiIT09ZS50eXBlfHwhZS5zaG9ydGhhbmR8fGUua2V5IT09dHx8IkFzc2lnbm1lbnRQYXR0ZXJuIiE9PWUudmFsdWUudHlwZSkmJihhZGRUcmFpbGluZ0NvbW1lbnQkMihlLnZhbHVlLmxlZnQsbiksITApfWZ1bmN0aW9uIGhhbmRsZUNsYXNzQ29tbWVudHMoZSx0LG4scil7cmV0dXJuISghKGUmJigiQ2xhc3NEZWNsYXJhdGlvbiI9PT1lLnR5cGV8fCJDbGFzc0V4cHJlc3Npb24iPT09ZS50eXBlKSYmZS5kZWNvcmF0b3JzJiZlLmRlY29yYXRvcnMubGVuZ3RoPjApfHxuJiYiRGVjb3JhdG9yIj09PW4udHlwZSkmJihlLmRlY29yYXRvcnMmJjAhPT1lLmRlY29yYXRvcnMubGVuZ3RoP2FkZFRyYWlsaW5nQ29tbWVudCQyKGUuZGVjb3JhdG9yc1tlLmRlY29yYXRvcnMubGVuZ3RoLTFdLHIpOmFkZExlYWRpbmdDb21tZW50JDIoZSxyKSwhMCl9ZnVuY3Rpb24gaGFuZGxlTWV0aG9kTmFtZUNvbW1lbnRzKGUsdCxuLHIsaSl7cmV0dXJuIHQmJm4mJigiUHJvcGVydHkiPT09dC50eXBlfHwiTWV0aG9kRGVmaW5pdGlvbiI9PT10LnR5cGUpJiYiSWRlbnRpZmllciI9PT1uLnR5cGUmJnQua2V5PT09biYmIjoiIT09dXRpbC5nZXROZXh0Tm9uU3BhY2VOb25Db21tZW50Q2hhcmFjdGVyKGUsbixpLmxvY0VuZCk/KGFkZFRyYWlsaW5nQ29tbWVudCQyKG4sciksITApOiEoIW58fCF0fHwiRGVjb3JhdG9yIiE9PW4udHlwZXx8IkNsYXNzTWV0aG9kIiE9PXQudHlwZSYmIkNsYXNzUHJvcGVydHkiIT09dC50eXBlJiYiVFNBYnN0cmFjdENsYXNzUHJvcGVydHkiIT09dC50eXBlJiYiVFNBYnN0cmFjdE1ldGhvZERlZmluaXRpb24iIT09dC50eXBlJiYiTWV0aG9kRGVmaW5pdGlvbiIhPT10LnR5cGUpJiYoYWRkVHJhaWxpbmdDb21tZW50JDIobixyKSwhMCl9ZnVuY3Rpb24gaGFuZGxlRnVuY3Rpb25OYW1lQ29tbWVudHMoZSx0LG4scixpKXtyZXR1cm4iKCI9PT11dGlsLmdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXIoZSxyLGkubG9jRW5kKSYmKCEoIW58fCF0fHwiRnVuY3Rpb25EZWNsYXJhdGlvbiIhPT10LnR5cGUmJiJGdW5jdGlvbkV4cHJlc3Npb24iIT09dC50eXBlJiYiQ2xhc3NNZXRob2QiIT09dC50eXBlJiYiTWV0aG9kRGVmaW5pdGlvbiIhPT10LnR5cGUmJiJPYmplY3RNZXRob2QiIT09dC50eXBlKSYmKGFkZFRyYWlsaW5nQ29tbWVudCQyKG4sciksITApKX1mdW5jdGlvbiBoYW5kbGVDb21tZW50QWZ0ZXJBcnJvd1BhcmFtcyhlLHQsbixyKXtpZighdHx8IkFycm93RnVuY3Rpb25FeHByZXNzaW9uIiE9PXQudHlwZSlyZXR1cm4hMTt2YXIgaT11dGlsU2hhcmVkLmdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXJJbmRleChlLG4scik7cmV0dXJuIj0+Ij09PWUuc3Vic3RyKGksMikmJihhZGREYW5nbGluZ0NvbW1lbnQkMih0LG4pLCEwKX1mdW5jdGlvbiBoYW5kbGVDb21tZW50SW5FbXB0eVBhcmVucyhlLHQsbixyKXtyZXR1cm4iKSI9PT11dGlsLmdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXIoZSxuLHIubG9jRW5kKSYmKHQmJigoIkZ1bmN0aW9uRGVjbGFyYXRpb24iPT09dC50eXBlfHwiRnVuY3Rpb25FeHByZXNzaW9uIj09PXQudHlwZXx8IkFycm93RnVuY3Rpb25FeHByZXNzaW9uIj09PXQudHlwZSYmKCJDYWxsRXhwcmVzc2lvbiIhPT10LmJvZHkudHlwZXx8MD09PXQuYm9keS5hcmd1bWVudHMubGVuZ3RoKXx8IkNsYXNzTWV0aG9kIj09PXQudHlwZXx8Ik9iamVjdE1ldGhvZCI9PT10LnR5cGUpJiYwPT09dC5wYXJhbXMubGVuZ3RofHwiQ2FsbEV4cHJlc3Npb24iPT09dC50eXBlJiYwPT09dC5hcmd1bWVudHMubGVuZ3RoKT8oYWRkRGFuZ2xpbmdDb21tZW50JDIodCxuKSwhMCk6ISghdHx8Ik1ldGhvZERlZmluaXRpb24iIT09dC50eXBlfHwwIT09dC52YWx1ZS5wYXJhbXMubGVuZ3RoKSYmKGFkZERhbmdsaW5nQ29tbWVudCQyKHQudmFsdWUsbiksITApKX1mdW5jdGlvbiBoYW5kbGVMYXN0RnVuY3Rpb25BcmdDb21tZW50cyhlLHQsbixyLGksbyl7cmV0dXJuIHQmJiJGdW5jdGlvblR5cGVQYXJhbSI9PT10LnR5cGUmJm4mJiJGdW5jdGlvblR5cGVBbm5vdGF0aW9uIj09PW4udHlwZSYmciYmIkZ1bmN0aW9uVHlwZVBhcmFtIiE9PXIudHlwZT8oYWRkVHJhaWxpbmdDb21tZW50JDIodCxpKSwhMCk6ISghdHx8IklkZW50aWZpZXIiIT09dC50eXBlJiYiQXNzaWdubWVudFBhdHRlcm4iIT09dC50eXBlfHwhbnx8IkFycm93RnVuY3Rpb25FeHByZXNzaW9uIiE9PW4udHlwZSYmIkZ1bmN0aW9uRXhwcmVzc2lvbiIhPT1uLnR5cGUmJiJGdW5jdGlvbkRlY2xhcmF0aW9uIiE9PW4udHlwZSYmIk9iamVjdE1ldGhvZCIhPT1uLnR5cGUmJiJDbGFzc01ldGhvZCIhPT1uLnR5cGV8fCIpIiE9PXV0aWwuZ2V0TmV4dE5vblNwYWNlTm9uQ29tbWVudENoYXJhY3RlcihlLGksby5sb2NFbmQpKSYmKGFkZFRyYWlsaW5nQ29tbWVudCQyKHQsaSksITApfWZ1bmN0aW9uIGhhbmRsZUltcG9ydFNwZWNpZmllckNvbW1lbnRzKGUsdCl7cmV0dXJuISghZXx8IkltcG9ydFNwZWNpZmllciIhPT1lLnR5cGUpJiYoYWRkTGVhZGluZ0NvbW1lbnQkMihlLHQpLCEwKX1mdW5jdGlvbiBoYW5kbGVMYWJlbGVkU3RhdGVtZW50Q29tbWVudHMoZSx0KXtyZXR1cm4hKCFlfHwiTGFiZWxlZFN0YXRlbWVudCIhPT1lLnR5cGUpJiYoYWRkTGVhZGluZ0NvbW1lbnQkMihlLHQpLCEwKX1mdW5jdGlvbiBoYW5kbGVCcmVha0FuZENvbnRpbnVlU3RhdGVtZW50Q29tbWVudHMoZSx0KXtyZXR1cm4hKCFlfHwiQ29udGludWVTdGF0ZW1lbnQiIT09ZS50eXBlJiYiQnJlYWtTdGF0ZW1lbnQiIT09ZS50eXBlfHxlLmxhYmVsKSYmKGFkZFRyYWlsaW5nQ29tbWVudCQyKGUsdCksITApfWZ1bmN0aW9uIGhhbmRsZUNhbGxFeHByZXNzaW9uQ29tbWVudHMoZSx0LG4pe3JldHVybiEhKHQmJiJDYWxsRXhwcmVzc2lvbiI9PT10LnR5cGUmJmUmJnQuY2FsbGVlPT09ZSYmdC5hcmd1bWVudHMubGVuZ3RoPjApJiYoYWRkTGVhZGluZ0NvbW1lbnQkMih0LmFyZ3VtZW50c1swXSxuKSwhMCl9ZnVuY3Rpb24gaGFuZGxlVW5pb25UeXBlQ29tbWVudHMoZSx0LG4scil7cmV0dXJuISghdHx8IlVuaW9uVHlwZUFubm90YXRpb24iIT09dC50eXBlJiYiVFNVbmlvblR5cGUiIT09dC50eXBlKSYmKGFkZFRyYWlsaW5nQ29tbWVudCQyKGUsciksITApfWZ1bmN0aW9uIGhhbmRsZVByb3BlcnR5Q29tbWVudHMoZSx0KXtyZXR1cm4hKCFlfHwiUHJvcGVydHkiIT09ZS50eXBlJiYiT2JqZWN0UHJvcGVydHkiIT09ZS50eXBlKSYmKGFkZExlYWRpbmdDb21tZW50JDIoZSx0KSwhMCl9ZnVuY3Rpb24gaGFuZGxlT25seUNvbW1lbnRzKGUsdCxuLHIpe3JldHVybiB0JiZ0LmJvZHkmJjA9PT10LmJvZHkubGVuZ3RoPyhyP2FkZERhbmdsaW5nQ29tbWVudCQyKHQsbik6YWRkTGVhZGluZ0NvbW1lbnQkMih0LG4pLCEwKTohKCFlfHwiUHJvZ3JhbSIhPT1lLnR5cGV8fDAhPT1lLmJvZHkubGVuZ3RofHwhZS5kaXJlY3RpdmVzfHwwIT09ZS5kaXJlY3RpdmVzLmxlbmd0aCkmJihyP2FkZERhbmdsaW5nQ29tbWVudCQyKGUsbik6YWRkTGVhZGluZ0NvbW1lbnQkMihlLG4pLCEwKX1mdW5jdGlvbiBoYW5kbGVGb3JDb21tZW50cyhlLHQsbil7cmV0dXJuISghZXx8IkZvckluU3RhdGVtZW50IiE9PWUudHlwZSYmIkZvck9mU3RhdGVtZW50IiE9PWUudHlwZSkmJihhZGRMZWFkaW5nQ29tbWVudCQyKGUsbiksITApfWZ1bmN0aW9uIGhhbmRsZUltcG9ydERlY2xhcmF0aW9uQ29tbWVudHMoZSx0LG4scixpKXtyZXR1cm4hIShuJiZ0JiYiSW1wb3J0RGVjbGFyYXRpb24iPT09dC50eXBlJiZ1dGlsLmhhc05ld2xpbmUoZSxpLmxvY0VuZChyKSkpJiYoYWRkVHJhaWxpbmdDb21tZW50JDIobixyKSwhMCl9ZnVuY3Rpb24gaGFuZGxlQXNzaWdubWVudFBhdHRlcm5Db21tZW50cyhlLHQpe3JldHVybiEoIWV8fCJBc3NpZ25tZW50UGF0dGVybiIhPT1lLnR5cGUpJiYoYWRkTGVhZGluZ0NvbW1lbnQkMihlLHQpLCEwKX1mdW5jdGlvbiBoYW5kbGVUeXBlQWxpYXNDb21tZW50cyhlLHQsbil7cmV0dXJuISghZXx8IlR5cGVBbGlhcyIhPT1lLnR5cGUpJiYoYWRkTGVhZGluZ0NvbW1lbnQkMihlLG4pLCEwKX1mdW5jdGlvbiBoYW5kbGVWYXJpYWJsZURlY2xhcmF0b3JDb21tZW50cyhlLHQsbil7cmV0dXJuISghZXx8IlZhcmlhYmxlRGVjbGFyYXRvciIhPT1lLnR5cGUmJiJBc3NpZ25tZW50RXhwcmVzc2lvbiIhPT1lLnR5cGV8fCF0fHwiT2JqZWN0RXhwcmVzc2lvbiIhPT10LnR5cGUmJiJBcnJheUV4cHJlc3Npb24iIT09dC50eXBlJiYiVGVtcGxhdGVMaXRlcmFsIiE9PXQudHlwZSYmIlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbiIhPT10LnR5cGUpJiYoYWRkTGVhZGluZ0NvbW1lbnQkMih0LG4pLCEwKX1mdW5jdGlvbiBoYW5kbGVUU01hcHBlZFR5cGVDb21tZW50cyhlLHQsbixyLGkpe3JldHVybiEoIXR8fCJUU01hcHBlZFR5cGUiIT09dC50eXBlKSYmKHImJiJUU1R5cGVQYXJhbWV0ZXIiPT09ci50eXBlJiZyLm5hbWU/KGFkZExlYWRpbmdDb21tZW50JDIoci5uYW1lLGkpLCEwKTohKCFufHwiVFNUeXBlUGFyYW1ldGVyIiE9PW4udHlwZXx8IW4uY29uc3RyYWludCkmJihhZGRUcmFpbGluZ0NvbW1lbnQkMihuLmNvbnN0cmFpbnQsaSksITApKX1mdW5jdGlvbiBpc0Jsb2NrQ29tbWVudChlKXtyZXR1cm4iQmxvY2siPT09ZS50eXBlfHwiQ29tbWVudEJsb2NrIj09PWUudHlwZX1mdW5jdGlvbiBoYXNDbG9zdXJlQ29tcGlsZXJUeXBlQ2FzdENvbW1lbnQoZSx0LG4pe3JldHVybiB0LmNvbW1lbnRzJiZ0LmNvbW1lbnRzLnNvbWUoZnVuY3Rpb24odCl7cmV0dXJuIHQubGVhZGluZyYmY29tbWVudHMkMy5pc0Jsb2NrQ29tbWVudCh0KSYmdC52YWx1ZS5tYXRjaCgvXlwqXHMqQHR5cGVccyp7W159XSt9XHMqJC8pJiYiKCI9PT11dGlsLmdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXIoZSx0LG4pfSl9ZnVuY3Rpb24gbmVlZHNQYXJlbnMoZSx0KXt2YXIgbj1lLmdldFBhcmVudE5vZGUoKTtpZighbilyZXR1cm4hMTt2YXIgcj1lLmdldE5hbWUoKSxpPWUuZ2V0Tm9kZSgpO2lmKGUuZ2V0VmFsdWUoKSE9PWkpcmV0dXJuITE7aWYoaXNTdGF0ZW1lbnQoaSkpcmV0dXJuITE7aWYoaGFzQ2xvc3VyZUNvbXBpbGVyVHlwZUNhc3RDb21tZW50KHQub3JpZ2luYWxUZXh0LGksdC5sb2NFbmQpKXJldHVybiEwO2lmKCJJZGVudGlmaWVyIj09PWkudHlwZSlyZXR1cm4hMTtpZigiUGFyZW50aGVzaXplZEV4cHJlc3Npb24iPT09bi50eXBlKXJldHVybiExO2lmKCgiQ2xhc3NEZWNsYXJhdGlvbiI9PT1uLnR5cGV8fCJDbGFzc0V4cHJlc3Npb24iPT09bi50eXBlKSYmbi5zdXBlckNsYXNzPT09aSYmKCJBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbiI9PT1pLnR5cGV8fCJBc3NpZ25tZW50RXhwcmVzc2lvbiI9PT1pLnR5cGV8fCJBd2FpdEV4cHJlc3Npb24iPT09aS50eXBlfHwiQmluYXJ5RXhwcmVzc2lvbiI9PT1pLnR5cGV8fCJDb25kaXRpb25hbEV4cHJlc3Npb24iPT09aS50eXBlfHwiTG9naWNhbEV4cHJlc3Npb24iPT09aS50eXBlfHwiTmV3RXhwcmVzc2lvbiI9PT1pLnR5cGV8fCJPYmplY3RFeHByZXNzaW9uIj09PWkudHlwZXx8IlBhcmVudGhlc2l6ZWRFeHByZXNzaW9uIj09PWkudHlwZXx8IlNlcXVlbmNlRXhwcmVzc2lvbiI9PT1pLnR5cGV8fCJUYWdnZWRUZW1wbGF0ZUV4cHJlc3Npb24iPT09aS50eXBlfHwiVW5hcnlFeHByZXNzaW9uIj09PWkudHlwZXx8IlVwZGF0ZUV4cHJlc3Npb24iPT09aS50eXBlfHwiWWllbGRFeHByZXNzaW9uIj09PWkudHlwZSkpcmV0dXJuITA7aWYoIkFycm93RnVuY3Rpb25FeHByZXNzaW9uIj09PW4udHlwZSYmbi5ib2R5PT09aSYmIlNlcXVlbmNlRXhwcmVzc2lvbiIhPT1pLnR5cGUmJnV0aWwuc3RhcnRzV2l0aE5vTG9va2FoZWFkVG9rZW4oaSwhMSl8fCJFeHByZXNzaW9uU3RhdGVtZW50Ij09PW4udHlwZSYmdXRpbC5zdGFydHNXaXRoTm9Mb29rYWhlYWRUb2tlbihpLCEwKSlyZXR1cm4hMDtzd2l0Y2goaS50eXBlKXtjYXNlIkNhbGxFeHByZXNzaW9uIjpmb3IodmFyIG89bixhPTA7byYmIk1lbWJlckV4cHJlc3Npb24iPT09by50eXBlOylvPWUuZ2V0UGFyZW50Tm9kZSgrK2EpO3JldHVybiJOZXdFeHByZXNzaW9uIj09PW8udHlwZSYmby5jYWxsZWU9PT1lLmdldFBhcmVudE5vZGUoYS0xKTtjYXNlIlNwcmVhZEVsZW1lbnQiOmNhc2UiU3ByZWFkUHJvcGVydHkiOnJldHVybiJNZW1iZXJFeHByZXNzaW9uIj09PW4udHlwZSYmIm9iamVjdCI9PT1yJiZuLm9iamVjdD09PWk7Y2FzZSJVcGRhdGVFeHByZXNzaW9uIjppZigiVW5hcnlFeHByZXNzaW9uIj09PW4udHlwZSlyZXR1cm4gaS5wcmVmaXgmJigiKysiPT09aS5vcGVyYXRvciYmIisiPT09bi5vcGVyYXRvcnx8Ii0tIj09PWkub3BlcmF0b3ImJiItIj09PW4ub3BlcmF0b3IpO2Nhc2UiVW5hcnlFeHByZXNzaW9uIjpzd2l0Y2gobi50eXBlKXtjYXNlIlVuYXJ5RXhwcmVzc2lvbiI6cmV0dXJuIGkub3BlcmF0b3I9PT1uLm9wZXJhdG9yJiYoIisiPT09aS5vcGVyYXRvcnx8Ii0iPT09aS5vcGVyYXRvcik7Y2FzZSJNZW1iZXJFeHByZXNzaW9uIjpyZXR1cm4ib2JqZWN0Ij09PXImJm4ub2JqZWN0PT09aTtjYXNlIlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbiI6cmV0dXJuITA7Y2FzZSJOZXdFeHByZXNzaW9uIjpjYXNlIkNhbGxFeHByZXNzaW9uIjpyZXR1cm4iY2FsbGVlIj09PXImJm4uY2FsbGVlPT09aTtjYXNlIkJpbmFyeUV4cHJlc3Npb24iOnJldHVybiIqKiI9PT1uLm9wZXJhdG9yJiYibGVmdCI9PT1yO2Nhc2UiVFNOb25OdWxsRXhwcmVzc2lvbiI6cmV0dXJuITA7ZGVmYXVsdDpyZXR1cm4hMX1jYXNlIkJpbmFyeUV4cHJlc3Npb24iOmlmKCJVcGRhdGVFeHByZXNzaW9uIj09PW4udHlwZSlyZXR1cm4hMDtpZigiaW4iPT09aS5vcGVyYXRvciYmZnVuY3Rpb24odCl7Zm9yKHZhciBuPTA7dDspe3ZhciByPWUuZ2V0UGFyZW50Tm9kZShuKyspO2lmKCFyKXJldHVybiExO2lmKCJGb3JTdGF0ZW1lbnQiPT09ci50eXBlJiZyLmluaXQ9PT10KXJldHVybiEwO3Q9cn1yZXR1cm4hMX0oaSkpcmV0dXJuITA7Y2FzZSJUU1R5cGVBc3NlcnRpb25FeHByZXNzaW9uIjpjYXNlIlRTQXNFeHByZXNzaW9uIjpjYXNlIkxvZ2ljYWxFeHByZXNzaW9uIjpzd2l0Y2gobi50eXBlKXtjYXNlIkNvbmRpdGlvbmFsRXhwcmVzc2lvbiI6cmV0dXJuIlRTQXNFeHByZXNzaW9uIj09PWkudHlwZTtjYXNlIkNhbGxFeHByZXNzaW9uIjpjYXNlIk5ld0V4cHJlc3Npb24iOnJldHVybiJjYWxsZWUiPT09ciYmbi5jYWxsZWU9PT1pO2Nhc2UiQ2xhc3NEZWNsYXJhdGlvbiI6Y2FzZSJUU0Fic3RyYWN0Q2xhc3NEZWNsYXJhdGlvbiI6cmV0dXJuInN1cGVyQ2xhc3MiPT09ciYmbi5zdXBlckNsYXNzPT09aTtjYXNlIlRTVHlwZUFzc2VydGlvbkV4cHJlc3Npb24iOmNhc2UiVGFnZ2VkVGVtcGxhdGVFeHByZXNzaW9uIjpjYXNlIlVuYXJ5RXhwcmVzc2lvbiI6Y2FzZSJTcHJlYWRFbGVtZW50IjpjYXNlIlNwcmVhZFByb3BlcnR5IjpjYXNlIkV4cGVyaW1lbnRhbFNwcmVhZFByb3BlcnR5IjpjYXNlIkJpbmRFeHByZXNzaW9uIjpjYXNlIkF3YWl0RXhwcmVzc2lvbiI6Y2FzZSJUU0FzRXhwcmVzc2lvbiI6Y2FzZSJUU05vbk51bGxFeHByZXNzaW9uIjpjYXNlIlVwZGF0ZUV4cHJlc3Npb24iOnJldHVybiEwO2Nhc2UiTWVtYmVyRXhwcmVzc2lvbiI6cmV0dXJuIm9iamVjdCI9PT1yJiZuLm9iamVjdD09PWk7Y2FzZSJBc3NpZ25tZW50RXhwcmVzc2lvbiI6cmV0dXJuIG4ubGVmdD09PWkmJigiVFNUeXBlQXNzZXJ0aW9uRXhwcmVzc2lvbiI9PT1pLnR5cGV8fCJUU0FzRXhwcmVzc2lvbiI9PT1pLnR5cGUpO2Nhc2UiRGVjb3JhdG9yIjpyZXR1cm4gbi5leHByZXNzaW9uPT09aSYmKCJUU1R5cGVBc3NlcnRpb25FeHByZXNzaW9uIj09PWkudHlwZXx8IlRTQXNFeHByZXNzaW9uIj09PWkudHlwZSk7Y2FzZSJCaW5hcnlFeHByZXNzaW9uIjpjYXNlIkxvZ2ljYWxFeHByZXNzaW9uIjppZighaS5vcGVyYXRvciYmIlRTVHlwZUFzc2VydGlvbkV4cHJlc3Npb24iIT09aS50eXBlKXJldHVybiEwO3ZhciBzPW4ub3BlcmF0b3IsdT11dGlsLmdldFByZWNlZGVuY2UocyksYz1pLm9wZXJhdG9yLGw9dXRpbC5nZXRQcmVjZWRlbmNlKGMpO3JldHVybiB1Pmx8fCgoInx8Ij09PXN8fCI/PyI9PT1zKSYmIiYmIj09PWN8fCh1PT09bCYmInJpZ2h0Ij09PXI/KGFzc2VydC5zdHJpY3RFcXVhbChuLnJpZ2h0LGkpLCEwKTp1PT09bCYmIXV0aWwuc2hvdWxkRmxhdHRlbihzLGMpfHwodTxsJiYiJSI9PT1jPyF1dGlsLnNob3VsZEZsYXR0ZW4ocyxjKTohIXV0aWwuaXNCaXR3aXNlT3BlcmF0b3IocykpKSk7ZGVmYXVsdDpyZXR1cm4hMX1jYXNlIlRTUGFyZW50aGVzaXplZFR5cGUiOnZhciBwPWUuZ2V0UGFyZW50Tm9kZSgxKTtyZXR1cm4oIlRTVHlwZVBhcmFtZXRlciIhPT1uLnR5cGUmJiJUeXBlUGFyYW1ldGVyIiE9PW4udHlwZSYmIlZhcmlhYmxlRGVjbGFyYXRvciIhPT1uLnR5cGUmJiJUU1R5cGVBbm5vdGF0aW9uIiE9PW4udHlwZSYmIkdlbmVyaWNUeXBlQW5ub3RhdGlvbiIhPT1uLnR5cGUmJiJUU1R5cGVSZWZlcmVuY2UiIT09bi50eXBlfHwiVFNUeXBlQW5ub3RhdGlvbiIhPT1pLnR5cGVBbm5vdGF0aW9uLnR5cGV8fCJUU0Z1bmN0aW9uVHlwZSI9PT1pLnR5cGVBbm5vdGF0aW9uLnR5cGVBbm5vdGF0aW9uLnR5cGV8fCJUU1R5cGVPcGVyYXRvciI9PT1wLnR5cGUpJiYiVFNQYXJlbnRoZXNpemVkVHlwZSIhPT1pLnR5cGVBbm5vdGF0aW9uLnR5cGU7Y2FzZSJTZXF1ZW5jZUV4cHJlc3Npb24iOnN3aXRjaChuLnR5cGUpe2Nhc2UiUmV0dXJuU3RhdGVtZW50IjpjYXNlIkZvclN0YXRlbWVudCI6cmV0dXJuITE7Y2FzZSJFeHByZXNzaW9uU3RhdGVtZW50IjpyZXR1cm4iZXhwcmVzc2lvbiIhPT1yO2Nhc2UiQXJyb3dGdW5jdGlvbkV4cHJlc3Npb24iOnJldHVybiJib2R5IiE9PXI7ZGVmYXVsdDpyZXR1cm4hMH1jYXNlIllpZWxkRXhwcmVzc2lvbiI6aWYoIlVuYXJ5RXhwcmVzc2lvbiI9PT1uLnR5cGV8fCJBd2FpdEV4cHJlc3Npb24iPT09bi50eXBlfHwiVFNBc0V4cHJlc3Npb24iPT09bi50eXBlfHwiVFNOb25OdWxsRXhwcmVzc2lvbiI9PT1uLnR5cGUpcmV0dXJuITA7Y2FzZSJBd2FpdEV4cHJlc3Npb24iOnN3aXRjaChuLnR5cGUpe2Nhc2UiVGFnZ2VkVGVtcGxhdGVFeHByZXNzaW9uIjpjYXNlIlVuYXJ5RXhwcmVzc2lvbiI6Y2FzZSJCaW5hcnlFeHByZXNzaW9uIjpjYXNlIkxvZ2ljYWxFeHByZXNzaW9uIjpjYXNlIlNwcmVhZEVsZW1lbnQiOmNhc2UiU3ByZWFkUHJvcGVydHkiOmNhc2UiRXhwZXJpbWVudGFsU3ByZWFkUHJvcGVydHkiOmNhc2UiVFNBc0V4cHJlc3Npb24iOmNhc2UiVFNOb25OdWxsRXhwcmVzc2lvbiI6cmV0dXJuITA7Y2FzZSJNZW1iZXJFeHByZXNzaW9uIjpyZXR1cm4gbi5vYmplY3Q9PT1pO2Nhc2UiTmV3RXhwcmVzc2lvbiI6Y2FzZSJDYWxsRXhwcmVzc2lvbiI6cmV0dXJuIG4uY2FsbGVlPT09aTtjYXNlIkNvbmRpdGlvbmFsRXhwcmVzc2lvbiI6cmV0dXJuIG4udGVzdD09PWk7ZGVmYXVsdDpyZXR1cm4hMX1jYXNlIkFycmF5VHlwZUFubm90YXRpb24iOnJldHVybiJOdWxsYWJsZVR5cGVBbm5vdGF0aW9uIj09PW4udHlwZTtjYXNlIkludGVyc2VjdGlvblR5cGVBbm5vdGF0aW9uIjpjYXNlIlVuaW9uVHlwZUFubm90YXRpb24iOnJldHVybiJBcnJheVR5cGVBbm5vdGF0aW9uIj09PW4udHlwZXx8Ik51bGxhYmxlVHlwZUFubm90YXRpb24iPT09bi50eXBlfHwiSW50ZXJzZWN0aW9uVHlwZUFubm90YXRpb24iPT09bi50eXBlfHwiVW5pb25UeXBlQW5ub3RhdGlvbiI9PT1uLnR5cGU7Y2FzZSJOdWxsYWJsZVR5cGVBbm5vdGF0aW9uIjpyZXR1cm4iQXJyYXlUeXBlQW5ub3RhdGlvbiI9PT1uLnR5cGU7Y2FzZSJGdW5jdGlvblR5cGVBbm5vdGF0aW9uIjp2YXIgZj0iTnVsbGFibGVUeXBlQW5ub3RhdGlvbiI9PT1uLnR5cGU/ZS5nZXRQYXJlbnROb2RlKDEpOm47cmV0dXJuIlVuaW9uVHlwZUFubm90YXRpb24iPT09Zi50eXBlfHwiSW50ZXJzZWN0aW9uVHlwZUFubm90YXRpb24iPT09Zi50eXBlfHwiQXJyYXlUeXBlQW5ub3RhdGlvbiI9PT1mLnR5cGV8fCJOdWxsYWJsZVR5cGVBbm5vdGF0aW9uIj09PWYudHlwZTtjYXNlIlN0cmluZ0xpdGVyYWwiOmNhc2UiTnVtZXJpY0xpdGVyYWwiOmNhc2UiTGl0ZXJhbCI6aWYoInN0cmluZyI9PT10eXBlb2YgaS52YWx1ZSYmIkV4cHJlc3Npb25TdGF0ZW1lbnQiPT09bi50eXBlJiYoInR5cGVzY3JpcHQiIT09dC5wYXJzZXImJiFuLmRpcmVjdGl2ZXx8InR5cGVzY3JpcHQiPT09dC5wYXJzZXImJiIoIj09PXQub3JpZ2luYWxUZXh0LnN1YnN0cih0LmxvY1N0YXJ0KGkpLTEsMSkpKXt2YXIgZD1lLmdldFBhcmVudE5vZGUoMSk7cmV0dXJuIlByb2dyYW0iPT09ZC50eXBlfHwiQmxvY2tTdGF0ZW1lbnQiPT09ZC50eXBlfXJldHVybiJNZW1iZXJFeHByZXNzaW9uIj09PW4udHlwZSYmIm51bWJlciI9PT10eXBlb2YgaS52YWx1ZSYmIm9iamVjdCI9PT1yJiZuLm9iamVjdD09PWk7Y2FzZSJBc3NpZ25tZW50RXhwcmVzc2lvbiI6dmFyIGg9ZS5nZXRQYXJlbnROb2RlKDEpO3JldHVybiJBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbiI9PT1uLnR5cGUmJm4uYm9keT09PWl8fCgiQ2xhc3NQcm9wZXJ0eSIhPT1uLnR5cGV8fG4ua2V5IT09aXx8IW4uY29tcHV0ZWQpJiYoKCJUU1Byb3BlcnR5U2lnbmF0dXJlIiE9PW4udHlwZXx8bi5uYW1lIT09aSkmJigoIkZvclN0YXRlbWVudCIhPT1uLnR5cGV8fG4uaW5pdCE9PWkmJm4udXBkYXRlIT09aSkmJigiRXhwcmVzc2lvblN0YXRlbWVudCI9PT1uLnR5cGU/Ik9iamVjdFBhdHRlcm4iPT09aS5sZWZ0LnR5cGU6KCJUU1Byb3BlcnR5U2lnbmF0dXJlIiE9PW4udHlwZXx8bi5rZXkhPT1pKSYmKCJBc3NpZ25tZW50RXhwcmVzc2lvbiIhPT1uLnR5cGUmJigiU2VxdWVuY2VFeHByZXNzaW9uIiE9PW4udHlwZXx8IWh8fCJGb3JTdGF0ZW1lbnQiIT09aC50eXBlfHxoLmluaXQhPT1uJiZoLnVwZGF0ZSE9PW4pKSkpKTtjYXNlIkNvbmRpdGlvbmFsRXhwcmVzc2lvbiI6c3dpdGNoKG4udHlwZSl7Y2FzZSJUYWdnZWRUZW1wbGF0ZUV4cHJlc3Npb24iOmNhc2UiVW5hcnlFeHByZXNzaW9uIjpjYXNlIlNwcmVhZEVsZW1lbnQiOmNhc2UiU3ByZWFkUHJvcGVydHkiOmNhc2UiRXhwZXJpbWVudGFsU3ByZWFkUHJvcGVydHkiOmNhc2UiQmluYXJ5RXhwcmVzc2lvbiI6Y2FzZSJMb2dpY2FsRXhwcmVzc2lvbiI6Y2FzZSJFeHBvcnREZWZhdWx0RGVjbGFyYXRpb24iOmNhc2UiQXdhaXRFeHByZXNzaW9uIjpjYXNlIkpTWFNwcmVhZEF0dHJpYnV0ZSI6Y2FzZSJUU1R5cGVBc3NlcnRpb25FeHByZXNzaW9uIjpjYXNlIlR5cGVDYXN0RXhwcmVzc2lvbiI6Y2FzZSJUU0FzRXhwcmVzc2lvbiI6Y2FzZSJUU05vbk51bGxFeHByZXNzaW9uIjpyZXR1cm4hMDtjYXNlIk5ld0V4cHJlc3Npb24iOmNhc2UiQ2FsbEV4cHJlc3Npb24iOnJldHVybiJjYWxsZWUiPT09ciYmbi5jYWxsZWU9PT1pO2Nhc2UiQ29uZGl0aW9uYWxFeHByZXNzaW9uIjpyZXR1cm4idGVzdCI9PT1yJiZuLnRlc3Q9PT1pO2Nhc2UiTWVtYmVyRXhwcmVzc2lvbiI6cmV0dXJuIm9iamVjdCI9PT1yJiZuLm9iamVjdD09PWk7ZGVmYXVsdDpyZXR1cm4hMX1jYXNlIkZ1bmN0aW9uRXhwcmVzc2lvbiI6c3dpdGNoKG4udHlwZSl7Y2FzZSJDYWxsRXhwcmVzc2lvbiI6cmV0dXJuImNhbGxlZSI9PT1yO2Nhc2UiVGFnZ2VkVGVtcGxhdGVFeHByZXNzaW9uIjpjYXNlIkV4cG9ydERlZmF1bHREZWNsYXJhdGlvbiI6cmV0dXJuITA7ZGVmYXVsdDpyZXR1cm4hMX1jYXNlIkFycm93RnVuY3Rpb25FeHByZXNzaW9uIjpzd2l0Y2gobi50eXBlKXtjYXNlIkNhbGxFeHByZXNzaW9uIjpjYXNlIk5ld0V4cHJlc3Npb24iOnJldHVybiJjYWxsZWUiPT09cjtjYXNlIk1lbWJlckV4cHJlc3Npb24iOnJldHVybiJvYmplY3QiPT09cjtjYXNlIlRTQXNFeHByZXNzaW9uIjpjYXNlIkJpbmRFeHByZXNzaW9uIjpjYXNlIlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbiI6Y2FzZSJVbmFyeUV4cHJlc3Npb24iOmNhc2UiTG9naWNhbEV4cHJlc3Npb24iOmNhc2UiQmluYXJ5RXhwcmVzc2lvbiI6Y2FzZSJBd2FpdEV4cHJlc3Npb24iOmNhc2UiVFNUeXBlQXNzZXJ0aW9uRXhwcmVzc2lvbiI6cmV0dXJuITA7Y2FzZSJDb25kaXRpb25hbEV4cHJlc3Npb24iOnJldHVybiJ0ZXN0Ij09PXI7ZGVmYXVsdDpyZXR1cm4hMX1jYXNlIkNsYXNzRXhwcmVzc2lvbiI6cmV0dXJuIkV4cG9ydERlZmF1bHREZWNsYXJhdGlvbiI9PT1uLnR5cGU7Y2FzZSJPcHRpb25hbE1lbWJlckV4cHJlc3Npb24iOnJldHVybiJNZW1iZXJFeHByZXNzaW9uIj09PW4udHlwZX1yZXR1cm4hMX1mdW5jdGlvbiBpc1N0YXRlbWVudChlKXtyZXR1cm4iQmxvY2tTdGF0ZW1lbnQiPT09ZS50eXBlfHwiQnJlYWtTdGF0ZW1lbnQiPT09ZS50eXBlfHwiQ2xhc3NCb2R5Ij09PWUudHlwZXx8IkNsYXNzRGVjbGFyYXRpb24iPT09ZS50eXBlfHwiQ2xhc3NNZXRob2QiPT09ZS50eXBlfHwiQ2xhc3NQcm9wZXJ0eSI9PT1lLnR5cGV8fCJDbGFzc1ByaXZhdGVQcm9wZXJ0eSI9PT1lLnR5cGV8fCJDb250aW51ZVN0YXRlbWVudCI9PT1lLnR5cGV8fCJEZWJ1Z2dlclN0YXRlbWVudCI9PT1lLnR5cGV8fCJEZWNsYXJlQ2xhc3MiPT09ZS50eXBlfHwiRGVjbGFyZUV4cG9ydEFsbERlY2xhcmF0aW9uIj09PWUudHlwZXx8IkRlY2xhcmVFeHBvcnREZWNsYXJhdGlvbiI9PT1lLnR5cGV8fCJEZWNsYXJlRnVuY3Rpb24iPT09ZS50eXBlfHwiRGVjbGFyZUludGVyZmFjZSI9PT1lLnR5cGV8fCJEZWNsYXJlTW9kdWxlIj09PWUudHlwZXx8IkRlY2xhcmVNb2R1bGVFeHBvcnRzIj09PWUudHlwZXx8IkRlY2xhcmVWYXJpYWJsZSI9PT1lLnR5cGV8fCJEb1doaWxlU3RhdGVtZW50Ij09PWUudHlwZXx8IkV4cG9ydEFsbERlY2xhcmF0aW9uIj09PWUudHlwZXx8IkV4cG9ydERlZmF1bHREZWNsYXJhdGlvbiI9PT1lLnR5cGV8fCJFeHBvcnROYW1lZERlY2xhcmF0aW9uIj09PWUudHlwZXx8IkV4cHJlc3Npb25TdGF0ZW1lbnQiPT09ZS50eXBlfHwiRm9yQXdhaXRTdGF0ZW1lbnQiPT09ZS50eXBlfHwiRm9ySW5TdGF0ZW1lbnQiPT09ZS50eXBlfHwiRm9yT2ZTdGF0ZW1lbnQiPT09ZS50eXBlfHwiRm9yU3RhdGVtZW50Ij09PWUudHlwZXx8IkZ1bmN0aW9uRGVjbGFyYXRpb24iPT09ZS50eXBlfHwiSWZTdGF0ZW1lbnQiPT09ZS50eXBlfHwiSW1wb3J0RGVjbGFyYXRpb24iPT09ZS50eXBlfHwiSW50ZXJmYWNlRGVjbGFyYXRpb24iPT09ZS50eXBlfHwiTGFiZWxlZFN0YXRlbWVudCI9PT1lLnR5cGV8fCJNZXRob2REZWZpbml0aW9uIj09PWUudHlwZXx8IlJldHVyblN0YXRlbWVudCI9PT1lLnR5cGV8fCJTd2l0Y2hTdGF0ZW1lbnQiPT09ZS50eXBlfHwiVGhyb3dTdGF0ZW1lbnQiPT09ZS50eXBlfHwiVHJ5U3RhdGVtZW50Ij09PWUudHlwZXx8IlRTQWJzdHJhY3RDbGFzc0RlY2xhcmF0aW9uIj09PWUudHlwZXx8IlRTRW51bURlY2xhcmF0aW9uIj09PWUudHlwZXx8IlRTSW1wb3J0RXF1YWxzRGVjbGFyYXRpb24iPT09ZS50eXBlfHwiVFNJbnRlcmZhY2VEZWNsYXJhdGlvbiI9PT1lLnR5cGV8fCJUU01vZHVsZURlY2xhcmF0aW9uIj09PWUudHlwZXx8IlRTTmFtZXNwYWNlRXhwb3J0RGVjbGFyYXRpb24iPT09ZS50eXBlfHwiVHlwZUFsaWFzIj09PWUudHlwZXx8IlZhcmlhYmxlRGVjbGFyYXRpb24iPT09ZS50eXBlfHwiV2hpbGVTdGF0ZW1lbnQiPT09ZS50eXBlfHwiV2l0aFN0YXRlbWVudCI9PT1lLnR5cGV9ZnVuY3Rpb24gc2hvdWxkUHJpbnRDb21tYShlLHQpe3N3aXRjaCh0PXR8fCJlczUiLGUudHJhaWxpbmdDb21tYSl7Y2FzZSJhbGwiOmlmKCJhbGwiPT09dClyZXR1cm4hMDtjYXNlImVzNSI6aWYoImVzNSI9PT10KXJldHVybiEwO2Nhc2Uibm9uZSI6ZGVmYXVsdDpyZXR1cm4hMX19ZnVuY3Rpb24gZ2VuZXJpY1ByaW50JDEoZSx0LG4scil7dmFyIGk9ZS5nZXRWYWx1ZSgpLG89ITEsYT1wcmludFBhdGhOb1BhcmVucyhlLHQsbixyKTtpZighaXx8aXNFbXB0eSQxKGEpKXJldHVybiBhO3ZhciBzPVtdO2lmKGkuZGVjb3JhdG9ycyYmaS5kZWNvcmF0b3JzLmxlbmd0aD4wJiYhZ2V0UGFyZW50RXhwb3J0RGVjbGFyYXRpb24kMShlKSl7dmFyIHU9aGFyZGxpbmUkMztlLmVhY2goZnVuY3Rpb24oZSl7dmFyIHQ9ZS5nZXRWYWx1ZSgpO3Q9dC5leHByZXNzaW9uP3QuZXhwcmVzc2lvbjp0LmNhbGxlZSwxIT09aS5kZWNvcmF0b3JzLmxlbmd0aHx8IkNsYXNzRGVjbGFyYXRpb24iPT09aS50eXBlfHwiTWV0aG9kRGVmaW5pdGlvbiI9PT1pLnR5cGV8fCJDbGFzc01ldGhvZCI9PT1pLnR5cGV8fCJJZGVudGlmaWVyIiE9PXQudHlwZSYmIk1lbWJlckV4cHJlc3Npb24iIT09dC50eXBlJiYiT3B0aW9uYWxNZW1iZXJFeHByZXNzaW9uIiE9PXQudHlwZSYmKCJDYWxsRXhwcmVzc2lvbiIhPT10LnR5cGUmJiJPcHRpb25hbENhbGxFeHByZXNzaW9uIiE9PXQudHlwZXx8MCE9PXQuYXJndW1lbnRzLmxlbmd0aCYmKDEhPT10LmFyZ3VtZW50cy5sZW5ndGh8fCFpc1N0cmluZ0xpdGVyYWwodC5hcmd1bWVudHNbMF0pJiYiSWRlbnRpZmllciIhPT10LmFyZ3VtZW50c1swXS50eXBlJiYiTWVtYmVyRXhwcmVzc2lvbiIhPT10LmFyZ3VtZW50c1swXS50eXBlJiYiT3B0aW9uYWxNZW1iZXJFeHByZXNzaW9uIiE9PXQuYXJndW1lbnRzWzBdLnR5cGUpKXx8KHU9bGluZSQzKSxzLnB1c2gobihlKSx1KX0sImRlY29yYXRvcnMiKX1lbHNlIGlzRXhwb3J0RGVjbGFyYXRpb24kMShpKSYmaS5kZWNsYXJhdGlvbiYmaS5kZWNsYXJhdGlvbi5kZWNvcmF0b3JzP2UuZWFjaChmdW5jdGlvbihlKXt2YXIgdD1lLmdldFZhbHVlKCkscj0iRGVjb3JhdG9yIj09PXQudHlwZT8iIjoiQCI7cy5wdXNoKHIsbihlKSxoYXJkbGluZSQzKX0sImRlY2xhcmF0aW9uIiwiZGVjb3JhdG9ycyIpOm89bmVlZHNQYXJlbnNfMShlLHQpO3ZhciBjPVtdO3JldHVybiBvJiZjLnVuc2hpZnQoIigiKSxjLnB1c2goYSksbyYmYy5wdXNoKCIpIikscy5sZW5ndGg+MD9ncm91cCQxKGNvbmNhdCQ0KHMuY29uY2F0KGMpKSk6Y29uY2F0JDQoYyl9ZnVuY3Rpb24gaGFzUHJldHRpZXJJZ25vcmUoZSl7cmV0dXJuIGhhc0lnbm9yZUNvbW1lbnQkMShlKXx8aGFzSnN4SWdub3JlQ29tbWVudChlKX1mdW5jdGlvbiBoYXNKc3hJZ25vcmVDb21tZW50KGUpe3ZhciB0PWUuZ2V0VmFsdWUoKSxuPWUuZ2V0UGFyZW50Tm9kZSgpO2lmKCFufHwhdHx8IWlzSlNYTm9kZSh0KXx8IWlzSlNYTm9kZShuKSlyZXR1cm4hMTtmb3IodmFyIHI9bi5jaGlsZHJlbi5pbmRleE9mKHQpLGk9bnVsbCxvPXI7bz4wO28tLSl7dmFyIGE9bi5jaGlsZHJlbltvLTFdO2lmKCJKU1hUZXh0IiE9PWEudHlwZXx8aXNNZWFuaW5nZnVsSlNYVGV4dChhKSl7aT1hO2JyZWFrfX1yZXR1cm4gaSYmIkpTWEV4cHJlc3Npb25Db250YWluZXIiPT09aS50eXBlJiYiSlNYRW1wdHlFeHByZXNzaW9uIj09PWkuZXhwcmVzc2lvbi50eXBlJiZpLmV4cHJlc3Npb24uY29tbWVudHMmJmkuZXhwcmVzc2lvbi5jb21tZW50cy5maW5kKGZ1bmN0aW9uKGUpe3JldHVybiJwcmV0dGllci1pZ25vcmUiPT09ZS52YWx1ZS50cmltKCl9KX1mdW5jdGlvbiBmb3JtYXRUZXJuYXJ5T3BlcmF0b3IoZSx0LG4scil7dmFyIGksbyxhPWUuZ2V0VmFsdWUoKSxzPVtdLHU9T2JqZWN0LmFzc2lnbih7YmVmb3JlUGFydHM6ZnVuY3Rpb24oKXtyZXR1cm5bIiJdfSxhZnRlclBhcnRzOmZ1bmN0aW9uKCl7cmV0dXJuWyIiXX0sc2hvdWxkQ2hlY2tKc3g6ITAsb3BlcmF0b3JOYW1lOiJDb25kaXRpb25hbEV4cHJlc3Npb24iLGNvbnNlcXVlbnROb2RlOiJjb25zZXF1ZW50IixhbHRlcm5hdGVOb2RlOiJhbHRlcm5hdGUiLHRlc3ROb2RlOiJ0ZXN0IixicmVha05lc3RlZDohMH0scnx8e30pLGM9ITEsbD1lLmdldFBhcmVudE5vZGUoKSxwPWwudHlwZT09PXUub3BlcmF0b3JOYW1lLGY9MDtkb3tvPWl8fGEsaT1lLmdldFBhcmVudE5vZGUoZiksZisrfXdoaWxlKGkmJmkudHlwZT09PXUub3BlcmF0b3JOYW1lKTt2YXIgZD1pfHxsLGg9bztpZih1LnNob3VsZENoZWNrSnN4JiZpc0pTWE5vZGUoYVt1LnRlc3ROb2RlXSl8fGlzSlNYTm9kZShhW3UuY29uc2VxdWVudE5vZGVdKXx8aXNKU1hOb2RlKGFbdS5hbHRlcm5hdGVOb2RlXSl8fGNvbmRpdGlvbmFsRXhwcmVzc2lvbkNoYWluQ29udGFpbnNKU1goaCkpe2M9ITAscD0hMDt2YXIgbT1mdW5jdGlvbihlKXtyZXR1cm4gY29uY2F0JDQoW2lmQnJlYWskMSgiKCIsIiIpLGluZGVudCQyKGNvbmNhdCQ0KFtzb2Z0bGluZSQxLGVdKSksc29mdGxpbmUkMSxpZkJyZWFrJDEoIikiLCIiKV0pfSxnPWZ1bmN0aW9uKGUpe3JldHVybiJOdWxsTGl0ZXJhbCI9PT1lLnR5cGV8fCJMaXRlcmFsIj09PWUudHlwZSYmbnVsbD09PWUudmFsdWV9O3MucHVzaCgiID8gIixnKGFbdS5jb25zZXF1ZW50Tm9kZV0pP2UuY2FsbChuLHUuY29uc2VxdWVudE5vZGUpOm0oZS5jYWxsKG4sdS5jb25zZXF1ZW50Tm9kZSkpLCIgOiAiLGFbdS5hbHRlcm5hdGVOb2RlXS50eXBlPT09dS5vcGVyYXRvck5hbWV8fGcoYVt1LmFsdGVybmF0ZU5vZGVdKT9lLmNhbGwobix1LmFsdGVybmF0ZU5vZGUpOm0oZS5jYWxsKG4sdS5hbHRlcm5hdGVOb2RlKSkpfWVsc2V7dmFyIHk9Y29uY2F0JDQoW2xpbmUkMywiPyAiLGFbdS5jb25zZXF1ZW50Tm9kZV0udHlwZT09PXUub3BlcmF0b3JOYW1lP2lmQnJlYWskMSgiIiwiKCIpOiIiLGFsaWduJDEoMixlLmNhbGwobix1LmNvbnNlcXVlbnROb2RlKSksYVt1LmNvbnNlcXVlbnROb2RlXS50eXBlPT09dS5vcGVyYXRvck5hbWU/aWZCcmVhayQxKCIiLCIpIik6IiIsbGluZSQzLCI6ICIsYWxpZ24kMSgyLGUuY2FsbChuLHUuYWx0ZXJuYXRlTm9kZSkpXSk7cy5wdXNoKGwudHlwZT09PXUub3BlcmF0b3JOYW1lP3QudXNlVGFicz9kZWRlbnQkMihpbmRlbnQkMih5KSk6YWxpZ24kMShNYXRoLm1heCgwLHQudGFiV2lkdGgtMikseSk6eSl9dmFyIHY9IWMmJigiTWVtYmVyRXhwcmVzc2lvbiI9PT1sLnR5cGV8fCJPcHRpb25hbE1lbWJlckV4cHJlc3Npb24iPT09bC50eXBlKSYmIWwuY29tcHV0ZWQ7cmV0dXJuIGZ1bmN0aW9uKGUpe3JldHVybiB1LmJyZWFrTmVzdGVkP2w9PT1kP2dyb3VwJDEoZSk6ZTpncm91cCQxKGUpfShjb25jYXQkNChbXS5jb25jYXQodS5iZWZvcmVQYXJ0cygpLHA/Y29uY2F0JDQocyk6aW5kZW50JDIoY29uY2F0JDQocykpLHUuYWZ0ZXJQYXJ0cyh2KSkpKX1mdW5jdGlvbiBnZXRUeXBlU2NyaXB0TWFwcGVkVHlwZU1vZGlmaWVyKGUsdCl7cmV0dXJuIlRTUGx1c1Rva2VuIj09PWUudHlwZT8iKyIrdDoiVFNNaW51c1Rva2VuIj09PWUudHlwZT8iLSIrdDp0fWZ1bmN0aW9uIHByaW50UGF0aE5vUGFyZW5zKGUsdCxuLHIpe3ZhciBpPWUuZ2V0VmFsdWUoKSxvPXQuc2VtaT8iOyI6IiI7aWYoIWkpcmV0dXJuIiI7aWYoInN0cmluZyI9PT10eXBlb2YgaSlyZXR1cm4gaTt2YXIgYT1bXTtzd2l0Y2goaS50eXBlKXtjYXNlIkZpbGUiOnJldHVybiBpLnByb2dyYW0mJmkucHJvZ3JhbS5pbnRlcnByZXRlciYmYS5wdXNoKGUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gZS5jYWxsKG4sImludGVycHJldGVyIil9LCJwcm9ncmFtIikpLGEucHVzaChlLmNhbGwobiwicHJvZ3JhbSIpKSxjb25jYXQkNChhKTtjYXNlIlByb2dyYW0iOnJldHVybiBpLmRpcmVjdGl2ZXMmJmUuZWFjaChmdW5jdGlvbihlKXthLnB1c2gobihlKSxvLGhhcmRsaW5lJDMpLGlzTmV4dExpbmVFbXB0eSQyKHQub3JpZ2luYWxUZXh0LGUuZ2V0VmFsdWUoKSx0KSYmYS5wdXNoKGhhcmRsaW5lJDMpfSwiZGlyZWN0aXZlcyIpLGEucHVzaChlLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIHByaW50U3RhdGVtZW50U2VxdWVuY2UoZSx0LG4pfSwiYm9keSIpKSxhLnB1c2goY29tbWVudHMucHJpbnREYW5nbGluZ0NvbW1lbnRzKGUsdCwhMCkpLChpLmJvZHkubGVuZ3RofHxpLmNvbW1lbnRzKSYmYS5wdXNoKGhhcmRsaW5lJDMpLGNvbmNhdCQ0KGEpO2Nhc2UiRW1wdHlTdGF0ZW1lbnQiOnJldHVybiIiO2Nhc2UiRXhwcmVzc2lvblN0YXRlbWVudCI6cmV0dXJuIGNvbmNhdCQ0KGkuZGlyZWN0aXZlP1tub2RlU3RyKGkuZXhwcmVzc2lvbix0LCEwKSxvXTpbZS5jYWxsKG4sImV4cHJlc3Npb24iKSxpc1RoZU9ubHlKU1hFbGVtZW50SW5NYXJrZG93bih0LGUpPyIiOm9dKTtjYXNlIlBhcmVudGhlc2l6ZWRFeHByZXNzaW9uIjpyZXR1cm4gY29uY2F0JDQoWyIoIixlLmNhbGwobiwiZXhwcmVzc2lvbiIpLCIpIl0pO2Nhc2UiQXNzaWdubWVudEV4cHJlc3Npb24iOnJldHVybiBwcmludEFzc2lnbm1lbnQoaS5sZWZ0LGUuY2FsbChuLCJsZWZ0IiksY29uY2F0JDQoWyIgIixpLm9wZXJhdG9yXSksaS5yaWdodCxlLmNhbGwobiwicmlnaHQiKSx0KTtjYXNlIkJpbmFyeUV4cHJlc3Npb24iOmNhc2UiTG9naWNhbEV4cHJlc3Npb24iOnZhciBzPWUuZ2V0UGFyZW50Tm9kZSgpLHU9ZS5nZXRQYXJlbnROb2RlKDEpLGM9aSE9PXMuYm9keSYmKCJJZlN0YXRlbWVudCI9PT1zLnR5cGV8fCJXaGlsZVN0YXRlbWVudCI9PT1zLnR5cGV8fCJEb1doaWxlU3RhdGVtZW50Ij09PXMudHlwZSksbD1wcmludEJpbmFyeWlzaEV4cHJlc3Npb25zKGUsbix0LCExLGMpO2lmKGMpcmV0dXJuIGNvbmNhdCQ0KGwpO2lmKCJVbmFyeUV4cHJlc3Npb24iPT09cy50eXBlfHwoIk1lbWJlckV4cHJlc3Npb24iPT09cy50eXBlfHwiT3B0aW9uYWxNZW1iZXJFeHByZXNzaW9uIj09PXMudHlwZSkmJiFzLmNvbXB1dGVkKXJldHVybiBncm91cCQxKGNvbmNhdCQ0KFtpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxjb25jYXQkNChsKV0pKSxzb2Z0bGluZSQxXSkpO3ZhciBwPSJSZXR1cm5TdGF0ZW1lbnQiPT09cy50eXBlfHwiSlNYRXhwcmVzc2lvbkNvbnRhaW5lciI9PT1zLnR5cGUmJiJKU1hBdHRyaWJ1dGUiPT09dS50eXBlfHxpPT09cy5ib2R5JiYiQXJyb3dGdW5jdGlvbkV4cHJlc3Npb24iPT09cy50eXBlfHxpIT09cy5ib2R5JiYiRm9yU3RhdGVtZW50Ij09PXMudHlwZXx8IkNvbmRpdGlvbmFsRXhwcmVzc2lvbiI9PT1zLnR5cGUmJiJSZXR1cm5TdGF0ZW1lbnQiIT09dS50eXBlLGY9IkFzc2lnbm1lbnRFeHByZXNzaW9uIj09PXMudHlwZXx8IlZhcmlhYmxlRGVjbGFyYXRvciI9PT1zLnR5cGV8fCJDbGFzc1Byb3BlcnR5Ij09PXMudHlwZXx8IlRTQWJzdHJhY3RDbGFzc1Byb3BlcnR5Ij09PXMudHlwZXx8IkNsYXNzUHJpdmF0ZVByb3BlcnR5Ij09PXMudHlwZXx8Ik9iamVjdFByb3BlcnR5Ij09PXMudHlwZXx8IlByb3BlcnR5Ij09PXMudHlwZSxkPWlzQmluYXJ5aXNoKGkubGVmdCkmJnNob3VsZEZsYXR0ZW4kMShpLm9wZXJhdG9yLGkubGVmdC5vcGVyYXRvcik7aWYocHx8c2hvdWxkSW5saW5lTG9naWNhbEV4cHJlc3Npb24oaSkmJiFkfHwhc2hvdWxkSW5saW5lTG9naWNhbEV4cHJlc3Npb24oaSkmJmYpcmV0dXJuIGdyb3VwJDEoY29uY2F0JDQobCkpO3ZhciBoPWNvbmNhdCQ0KGwuc2xpY2UoMSkpO3JldHVybiBncm91cCQxKGNvbmNhdCQ0KFtsLmxlbmd0aD4wP2xbMF06IiIsaW5kZW50JDIoaCldKSk7Y2FzZSJBc3NpZ25tZW50UGF0dGVybiI6cmV0dXJuIGNvbmNhdCQ0KFtlLmNhbGwobiwibGVmdCIpLCIgPSAiLGUuY2FsbChuLCJyaWdodCIpXSk7Y2FzZSJUU1R5cGVBc3NlcnRpb25FeHByZXNzaW9uIjp2YXIgbT0hKCJBcnJheUV4cHJlc3Npb24iPT09aS5leHByZXNzaW9uLnR5cGV8fCJPYmplY3RFeHByZXNzaW9uIj09PWkuZXhwcmVzc2lvbi50eXBlKSxnPWdyb3VwJDEoY29uY2F0JDQoWyI8IixpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxlLmNhbGwobiwidHlwZUFubm90YXRpb24iKV0pKSxzb2Z0bGluZSQxLCI+Il0pKSx5PWNvbmNhdCQ0KFtpZkJyZWFrJDEoIigiKSxpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxlLmNhbGwobiwiZXhwcmVzc2lvbiIpXSkpLHNvZnRsaW5lJDEsaWZCcmVhayQxKCIpIildKTtyZXR1cm4gbT9jb25kaXRpb25hbEdyb3VwJDEoW2NvbmNhdCQ0KFtnLGUuY2FsbChuLCJleHByZXNzaW9uIildKSxjb25jYXQkNChbZyxncm91cCQxKHkse3Nob3VsZEJyZWFrOiEwfSldKSxjb25jYXQkNChbZyxlLmNhbGwobiwiZXhwcmVzc2lvbiIpXSldKTpncm91cCQxKGNvbmNhdCQ0KFtnLGUuY2FsbChuLCJleHByZXNzaW9uIildKSk7Y2FzZSJPcHRpb25hbE1lbWJlckV4cHJlc3Npb24iOmNhc2UiTWVtYmVyRXhwcmVzc2lvbiI6dmFyIHYsYj1lLmdldFBhcmVudE5vZGUoKSx4PTA7ZG97dj1lLmdldFBhcmVudE5vZGUoeCkseCsrfXdoaWxlKHYmJigiTWVtYmVyRXhwcmVzc2lvbiI9PT12LnR5cGV8fCJPcHRpb25hbE1lbWJlckV4cHJlc3Npb24iPT09di50eXBlfHwiVFNOb25OdWxsRXhwcmVzc2lvbiI9PT12LnR5cGUpKTt2YXIgQz12JiYoIk5ld0V4cHJlc3Npb24iPT09di50eXBlfHwiQmluZEV4cHJlc3Npb24iPT09di50eXBlfHwiVmFyaWFibGVEZWNsYXJhdG9yIj09PXYudHlwZSYmIklkZW50aWZpZXIiIT09di5pZC50eXBlfHwiQXNzaWdubWVudEV4cHJlc3Npb24iPT09di50eXBlJiYiSWRlbnRpZmllciIhPT12LmxlZnQudHlwZSl8fGkuY29tcHV0ZWR8fCJJZGVudGlmaWVyIj09PWkub2JqZWN0LnR5cGUmJiJJZGVudGlmaWVyIj09PWkucHJvcGVydHkudHlwZSYmIk1lbWJlckV4cHJlc3Npb24iIT09Yi50eXBlJiYiT3B0aW9uYWxNZW1iZXJFeHByZXNzaW9uIiE9PWIudHlwZTtyZXR1cm4gY29uY2F0JDQoW2UuY2FsbChuLCJvYmplY3QiKSxDP3ByaW50TWVtYmVyTG9va3VwKGUsdCxuKTpncm91cCQxKGluZGVudCQyKGNvbmNhdCQ0KFtzb2Z0bGluZSQxLHByaW50TWVtYmVyTG9va3VwKGUsdCxuKV0pKSldKTtjYXNlIk1ldGFQcm9wZXJ0eSI6cmV0dXJuIGNvbmNhdCQ0KFtlLmNhbGwobiwibWV0YSIpLCIuIixlLmNhbGwobiwicHJvcGVydHkiKV0pO2Nhc2UiQmluZEV4cHJlc3Npb24iOnJldHVybiBpLm9iamVjdCYmYS5wdXNoKGUuY2FsbChuLCJvYmplY3QiKSksYS5wdXNoKGdyb3VwJDEoaW5kZW50JDIoY29uY2F0JDQoW3NvZnRsaW5lJDEscHJpbnRCaW5kRXhwcmVzc2lvbkNhbGxlZShlLHQsbildKSkpKSxjb25jYXQkNChhKTtjYXNlIklkZW50aWZpZXIiOnJldHVybiBjb25jYXQkNChbaS5uYW1lLHByaW50T3B0aW9uYWxUb2tlbihlKSxwcmludFR5cGVBbm5vdGF0aW9uKGUsdCxuKV0pO2Nhc2UiU3ByZWFkRWxlbWVudCI6Y2FzZSJTcHJlYWRFbGVtZW50UGF0dGVybiI6Y2FzZSJSZXN0UHJvcGVydHkiOmNhc2UiRXhwZXJpbWVudGFsUmVzdFByb3BlcnR5IjpjYXNlIkV4cGVyaW1lbnRhbFNwcmVhZFByb3BlcnR5IjpjYXNlIlNwcmVhZFByb3BlcnR5IjpjYXNlIlNwcmVhZFByb3BlcnR5UGF0dGVybiI6Y2FzZSJSZXN0RWxlbWVudCI6Y2FzZSJPYmplY3RUeXBlU3ByZWFkUHJvcGVydHkiOnJldHVybiBjb25jYXQkNChbIi4uLiIsZS5jYWxsKG4sImFyZ3VtZW50IikscHJpbnRUeXBlQW5ub3RhdGlvbihlLHQsbildKTtjYXNlIkZ1bmN0aW9uRGVjbGFyYXRpb24iOmNhc2UiRnVuY3Rpb25FeHByZXNzaW9uIjpyZXR1cm4gaXNOb2RlU3RhcnRpbmdXaXRoRGVjbGFyZShpLHQpJiZhLnB1c2goImRlY2xhcmUgIiksYS5wdXNoKHByaW50RnVuY3Rpb25EZWNsYXJhdGlvbihlLG4sdCkpLGkuYm9keXx8YS5wdXNoKG8pLGNvbmNhdCQ0KGEpO2Nhc2UiQXJyb3dGdW5jdGlvbkV4cHJlc3Npb24iOmkuYXN5bmMmJmEucHVzaCgiYXN5bmMgIiksc2hvdWxkUHJpbnRQYXJhbXNXaXRob3V0UGFyZW5zKGUsdCk/YS5wdXNoKGUuY2FsbChuLCJwYXJhbXMiLDApKTphLnB1c2goZ3JvdXAkMShjb25jYXQkNChbcHJpbnRGdW5jdGlvblBhcmFtcyhlLG4sdCxyJiYoci5leHBhbmRMYXN0QXJnfHxyLmV4cGFuZEZpcnN0QXJnKSwhMCkscHJpbnRSZXR1cm5UeXBlKGUsbix0KV0pKSk7dmFyIEU9Y29tbWVudHMucHJpbnREYW5nbGluZ0NvbW1lbnRzKGUsdCwhMCxmdW5jdGlvbihlKXt2YXIgbj1nZXROZXh0Tm9uU3BhY2VOb25Db21tZW50Q2hhcmFjdGVySW5kZXgkMih0Lm9yaWdpbmFsVGV4dCxlLHQpO3JldHVybiI9PiI9PT10Lm9yaWdpbmFsVGV4dC5zdWJzdHIobiwyKX0pO0UmJmEucHVzaCgiICIsRSksYS5wdXNoKCIgPT4iKTt2YXIgRD1lLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIG4oZSxyKX0sImJvZHkiKTtpZighaGFzTGVhZGluZ093bkxpbmVDb21tZW50KHQub3JpZ2luYWxUZXh0LGkuYm9keSx0KSYmKCJBcnJheUV4cHJlc3Npb24iPT09aS5ib2R5LnR5cGV8fCJPYmplY3RFeHByZXNzaW9uIj09PWkuYm9keS50eXBlfHwiQmxvY2tTdGF0ZW1lbnQiPT09aS5ib2R5LnR5cGV8fGlzSlNYTm9kZShpLmJvZHkpfHxpc1RlbXBsYXRlT25JdHNPd25MaW5lKGkuYm9keSx0Lm9yaWdpbmFsVGV4dCx0KXx8IkFycm93RnVuY3Rpb25FeHByZXNzaW9uIj09PWkuYm9keS50eXBlfHwiRG9FeHByZXNzaW9uIj09PWkuYm9keS50eXBlKSlyZXR1cm4gZ3JvdXAkMShjb25jYXQkNChbY29uY2F0JDQoYSksIiAiLERdKSk7aWYoIlNlcXVlbmNlRXhwcmVzc2lvbiI9PT1pLmJvZHkudHlwZSlyZXR1cm4gZ3JvdXAkMShjb25jYXQkNChbY29uY2F0JDQoYSksZ3JvdXAkMShjb25jYXQkNChbIiAoIixpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxEXSkpLHNvZnRsaW5lJDEsIikiXSkpXSkpO3ZhciB3PShyJiZyLmV4cGFuZExhc3RBcmd8fCJKU1hFeHByZXNzaW9uQ29udGFpbmVyIj09PWUuZ2V0UGFyZW50Tm9kZSgpLnR5cGUpJiYhKGkuY29tbWVudHMmJmkuY29tbWVudHMubGVuZ3RoKSxTPXImJnIuZXhwYW5kTGFzdEFyZyYmc2hvdWxkUHJpbnRDb21tYSh0LCJhbGwiKSxrPSJDb25kaXRpb25hbEV4cHJlc3Npb24iPT09aS5ib2R5LnR5cGUmJiFzdGFydHNXaXRoTm9Mb29rYWhlYWRUb2tlbiQxKGkuYm9keSwhMSk7cmV0dXJuIGdyb3VwJDEoY29uY2F0JDQoW2NvbmNhdCQ0KGEpLGdyb3VwJDEoY29uY2F0JDQoW2luZGVudCQyKGNvbmNhdCQ0KFtsaW5lJDMsaz9pZkJyZWFrJDEoIiIsIigiKToiIixELGs/aWZCcmVhayQxKCIiLCIpIik6IiJdKSksdz9jb25jYXQkNChbaWZCcmVhayQxKFM/IiwiOiIiKSxzb2Z0bGluZSQxXSk6IiJdKSldKSk7Y2FzZSJNZXRob2REZWZpbml0aW9uIjpjYXNlIlRTQWJzdHJhY3RNZXRob2REZWZpbml0aW9uIjpyZXR1cm4gaS5hY2Nlc3NpYmlsaXR5JiZhLnB1c2goaS5hY2Nlc3NpYmlsaXR5KyIgIiksaS5zdGF0aWMmJmEucHVzaCgic3RhdGljICIpLCJUU0Fic3RyYWN0TWV0aG9kRGVmaW5pdGlvbiI9PT1pLnR5cGUmJmEucHVzaCgiYWJzdHJhY3QgIiksYS5wdXNoKHByaW50TWV0aG9kKGUsdCxuKSksY29uY2F0JDQoYSk7Y2FzZSJZaWVsZEV4cHJlc3Npb24iOnJldHVybiBhLnB1c2goInlpZWxkIiksaS5kZWxlZ2F0ZSYmYS5wdXNoKCIqIiksaS5hcmd1bWVudCYmYS5wdXNoKCIgIixlLmNhbGwobiwiYXJndW1lbnQiKSksY29uY2F0JDQoYSk7Y2FzZSJBd2FpdEV4cHJlc3Npb24iOnJldHVybiBjb25jYXQkNChbImF3YWl0ICIsZS5jYWxsKG4sImFyZ3VtZW50IildKTtjYXNlIkltcG9ydFNwZWNpZmllciI6cmV0dXJuIGkuaW1wb3J0S2luZCYmYS5wdXNoKGUuY2FsbChuLCJpbXBvcnRLaW5kIiksIiAiKSxhLnB1c2goZS5jYWxsKG4sImltcG9ydGVkIikpLGkubG9jYWwmJmkubG9jYWwubmFtZSE9PWkuaW1wb3J0ZWQubmFtZSYmYS5wdXNoKCIgYXMgIixlLmNhbGwobiwibG9jYWwiKSksY29uY2F0JDQoYSk7Y2FzZSJFeHBvcnRTcGVjaWZpZXIiOnJldHVybiBhLnB1c2goZS5jYWxsKG4sImxvY2FsIikpLGkuZXhwb3J0ZWQmJmkuZXhwb3J0ZWQubmFtZSE9PWkubG9jYWwubmFtZSYmYS5wdXNoKCIgYXMgIixlLmNhbGwobiwiZXhwb3J0ZWQiKSksY29uY2F0JDQoYSk7Y2FzZSJJbXBvcnROYW1lc3BhY2VTcGVjaWZpZXIiOnJldHVybiBhLnB1c2goIiogYXMgIiksaS5sb2NhbD9hLnB1c2goZS5jYWxsKG4sImxvY2FsIikpOmkuaWQmJmEucHVzaChlLmNhbGwobiwiaWQiKSksY29uY2F0JDQoYSk7Y2FzZSJJbXBvcnREZWZhdWx0U3BlY2lmaWVyIjpyZXR1cm4gaS5sb2NhbD9lLmNhbGwobiwibG9jYWwiKTplLmNhbGwobiwiaWQiKTtjYXNlIlRTRXhwb3J0QXNzaWdubWVudCI6cmV0dXJuIGNvbmNhdCQ0KFsiZXhwb3J0ID0gIixlLmNhbGwobiwiZXhwcmVzc2lvbiIpLG9dKTtjYXNlIkV4cG9ydERlZmF1bHREZWNsYXJhdGlvbiI6Y2FzZSJFeHBvcnROYW1lZERlY2xhcmF0aW9uIjpyZXR1cm4gcHJpbnRFeHBvcnREZWNsYXJhdGlvbihlLHQsbik7Y2FzZSJFeHBvcnRBbGxEZWNsYXJhdGlvbiI6cmV0dXJuIGEucHVzaCgiZXhwb3J0ICIpLCJ0eXBlIj09PWkuZXhwb3J0S2luZCYmYS5wdXNoKCJ0eXBlICIpLGEucHVzaCgiKiBmcm9tICIsZS5jYWxsKG4sInNvdXJjZSIpLG8pLGNvbmNhdCQ0KGEpO2Nhc2UiRXhwb3J0TmFtZXNwYWNlU3BlY2lmaWVyIjpjYXNlIkV4cG9ydERlZmF1bHRTcGVjaWZpZXIiOnJldHVybiBlLmNhbGwobiwiZXhwb3J0ZWQiKTtjYXNlIkltcG9ydERlY2xhcmF0aW9uIjphLnB1c2goImltcG9ydCAiKSxpLmltcG9ydEtpbmQmJiJ2YWx1ZSIhPT1pLmltcG9ydEtpbmQmJmEucHVzaChpLmltcG9ydEtpbmQrIiAiKTt2YXIgQT1bXSxfPVtdO3JldHVybiBpLnNwZWNpZmllcnMmJmkuc3BlY2lmaWVycy5sZW5ndGg+MD8oZS5lYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWUuZ2V0VmFsdWUoKTsiSW1wb3J0RGVmYXVsdFNwZWNpZmllciI9PT10LnR5cGV8fCJJbXBvcnROYW1lc3BhY2VTcGVjaWZpZXIiPT09dC50eXBlP0EucHVzaChuKGUpKTpfLnB1c2gobihlKSl9LCJzcGVjaWZpZXJzIiksQS5sZW5ndGg+MCYmYS5wdXNoKGpvaW4kMigiLCAiLEEpKSxBLmxlbmd0aD4wJiZfLmxlbmd0aD4wJiZhLnB1c2goIiwgIiksMT09PV8ubGVuZ3RoJiYwPT09QS5sZW5ndGgmJmkuc3BlY2lmaWVycyYmIWkuc3BlY2lmaWVycy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiBlLmNvbW1lbnRzfSk/YS5wdXNoKGNvbmNhdCQ0KFsieyIsdC5icmFja2V0U3BhY2luZz8iICI6IiIsY29uY2F0JDQoXyksdC5icmFja2V0U3BhY2luZz8iICI6IiIsIn0iXSkpOl8ubGVuZ3RoPj0xJiZhLnB1c2goZ3JvdXAkMShjb25jYXQkNChbInsiLGluZGVudCQyKGNvbmNhdCQ0KFt0LmJyYWNrZXRTcGFjaW5nP2xpbmUkMzpzb2Z0bGluZSQxLGpvaW4kMihjb25jYXQkNChbIiwiLGxpbmUkM10pLF8pXSkpLGlmQnJlYWskMShzaG91bGRQcmludENvbW1hKHQpPyIsIjoiIiksdC5icmFja2V0U3BhY2luZz9saW5lJDM6c29mdGxpbmUkMSwifSJdKSkpLGEucHVzaCgiIGZyb20gIikpOihpLmltcG9ydEtpbmQmJiJ0eXBlIj09PWkuaW1wb3J0S2luZHx8L3tccyp9Ly50ZXN0KHQub3JpZ2luYWxUZXh0LnNsaWNlKHQubG9jU3RhcnQoaSksdC5sb2NTdGFydChpLnNvdXJjZSkpKSkmJmEucHVzaCgie30gZnJvbSAiKSxhLnB1c2goZS5jYWxsKG4sInNvdXJjZSIpLG8pLGNvbmNhdCQ0KGEpO2Nhc2UiSW1wb3J0IjpyZXR1cm4iaW1wb3J0IjtjYXNlIkJsb2NrU3RhdGVtZW50Ijp2YXIgVD1lLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIHByaW50U3RhdGVtZW50U2VxdWVuY2UoZSx0LG4pfSwiYm9keSIpLE89aS5ib2R5LmZpbmQoZnVuY3Rpb24oZSl7cmV0dXJuIkVtcHR5U3RhdGVtZW50IiE9PWUudHlwZX0pLEY9aS5kaXJlY3RpdmVzJiZpLmRpcmVjdGl2ZXMubGVuZ3RoPjAsTj1lLmdldFBhcmVudE5vZGUoKSxJPWUuZ2V0UGFyZW50Tm9kZSgxKTtyZXR1cm4gT3x8Rnx8aGFzRGFuZ2xpbmdDb21tZW50cyhpKXx8IkFycm93RnVuY3Rpb25FeHByZXNzaW9uIiE9PU4udHlwZSYmIkZ1bmN0aW9uRXhwcmVzc2lvbiIhPT1OLnR5cGUmJiJGdW5jdGlvbkRlY2xhcmF0aW9uIiE9PU4udHlwZSYmIk9iamVjdE1ldGhvZCIhPT1OLnR5cGUmJiJDbGFzc01ldGhvZCIhPT1OLnR5cGUmJiJGb3JTdGF0ZW1lbnQiIT09Ti50eXBlJiYiV2hpbGVTdGF0ZW1lbnQiIT09Ti50eXBlJiYiRG9XaGlsZVN0YXRlbWVudCIhPT1OLnR5cGUmJiJEb0V4cHJlc3Npb24iIT09Ti50eXBlJiYoIkNhdGNoQ2xhdXNlIiE9PU4udHlwZXx8SS5maW5hbGl6ZXIpPyhhLnB1c2goInsiKSxGJiZlLmVhY2goZnVuY3Rpb24oZSl7YS5wdXNoKGluZGVudCQyKGNvbmNhdCQ0KFtoYXJkbGluZSQzLG4oZSksb10pKSksaXNOZXh0TGluZUVtcHR5JDIodC5vcmlnaW5hbFRleHQsZS5nZXRWYWx1ZSgpLHQpJiZhLnB1c2goaGFyZGxpbmUkMyl9LCJkaXJlY3RpdmVzIiksTyYmYS5wdXNoKGluZGVudCQyKGNvbmNhdCQ0KFtoYXJkbGluZSQzLFRdKSkpLGEucHVzaChjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0KSksYS5wdXNoKGhhcmRsaW5lJDMsIn0iKSxjb25jYXQkNChhKSk6Int9IjtjYXNlIlJldHVyblN0YXRlbWVudCI6cmV0dXJuIGEucHVzaCgicmV0dXJuIiksaS5hcmd1bWVudCYmKHJldHVybkFyZ3VtZW50SGFzTGVhZGluZ0NvbW1lbnQodCxpLmFyZ3VtZW50KT9hLnB1c2goY29uY2F0JDQoWyIgKCIsaW5kZW50JDIoY29uY2F0JDQoW2hhcmRsaW5lJDMsZS5jYWxsKG4sImFyZ3VtZW50IildKSksaGFyZGxpbmUkMywiKSJdKSk6IkxvZ2ljYWxFeHByZXNzaW9uIj09PWkuYXJndW1lbnQudHlwZXx8IkJpbmFyeUV4cHJlc3Npb24iPT09aS5hcmd1bWVudC50eXBlfHwiU2VxdWVuY2VFeHByZXNzaW9uIj09PWkuYXJndW1lbnQudHlwZT9hLnB1c2goZ3JvdXAkMShjb25jYXQkNChbaWZCcmVhayQxKCIgKCIsIiAiKSxpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxlLmNhbGwobiwiYXJndW1lbnQiKV0pKSxzb2Z0bGluZSQxLGlmQnJlYWskMSgiKSIpXSkpKTphLnB1c2goIiAiLGUuY2FsbChuLCJhcmd1bWVudCIpKSksaGFzRGFuZ2xpbmdDb21tZW50cyhpKSYmYS5wdXNoKCIgIixjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0LCEwKSksYS5wdXNoKG8pLGNvbmNhdCQ0KGEpO2Nhc2UiTmV3RXhwcmVzc2lvbiI6Y2FzZSJPcHRpb25hbENhbGxFeHByZXNzaW9uIjpjYXNlIkNhbGxFeHByZXNzaW9uIjp2YXIgTD0iTmV3RXhwcmVzc2lvbiI9PT1pLnR5cGUsUD1wcmludE9wdGlvbmFsVG9rZW4oZSk7cmV0dXJuIUwmJiJJZGVudGlmaWVyIj09PWkuY2FsbGVlLnR5cGUmJigicmVxdWlyZSI9PT1pLmNhbGxlZS5uYW1lfHwiZGVmaW5lIj09PWkuY2FsbGVlLm5hbWUpfHwiSW1wb3J0Ij09PWkuY2FsbGVlLnR5cGV8fDE9PT1pLmFyZ3VtZW50cy5sZW5ndGgmJmlzVGVtcGxhdGVPbkl0c093bkxpbmUoaS5hcmd1bWVudHNbMF0sdC5vcmlnaW5hbFRleHQsdCl8fCFMJiZpc1Rlc3RDYWxsKGksZS5nZXRQYXJlbnROb2RlKCkpP2NvbmNhdCQ0KFtMPyJuZXcgIjoiIixlLmNhbGwobiwiY2FsbGVlIiksUCxwcmludEZ1bmN0aW9uVHlwZVBhcmFtZXRlcnMoZSx0LG4pLGNvbmNhdCQ0KFsiKCIsam9pbiQyKCIsICIsZS5tYXAobiwiYXJndW1lbnRzIikpLCIpIl0pXSk6IUwmJmlzTWVtYmVyaXNoKGkuY2FsbGVlKT9wcmludE1lbWJlckNoYWluKGUsdCxuKTpjb25jYXQkNChbTD8ibmV3ICI6IiIsZS5jYWxsKG4sImNhbGxlZSIpLFAscHJpbnRGdW5jdGlvblR5cGVQYXJhbWV0ZXJzKGUsdCxuKSxwcmludEFyZ3VtZW50c0xpc3QoZSx0LG4pXSk7Y2FzZSJUU0ludGVyZmFjZURlY2xhcmF0aW9uIjpyZXR1cm4gaXNOb2RlU3RhcnRpbmdXaXRoRGVjbGFyZShpLHQpJiZhLnB1c2goImRlY2xhcmUgIiksYS5wdXNoKGkuYWJzdHJhY3Q/ImFic3RyYWN0ICI6IiIscHJpbnRUeXBlU2NyaXB0TW9kaWZpZXJzKGUsdCxuKSwiaW50ZXJmYWNlICIsZS5jYWxsKG4sImlkIiksaS50eXBlUGFyYW1ldGVycz9lLmNhbGwobiwidHlwZVBhcmFtZXRlcnMiKToiIiwiICIpLGkuaGVyaXRhZ2UubGVuZ3RoJiZhLnB1c2goZ3JvdXAkMShpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSwiZXh0ZW5kcyAiLGluZGVudCQyKGpvaW4kMihjb25jYXQkNChbIiwiLGxpbmUkM10pLGUubWFwKG4sImhlcml0YWdlIikpKSwiICJdKSkpKSxhLnB1c2goZS5jYWxsKG4sImJvZHkiKSksY29uY2F0JDQoYSk7Y2FzZSJPYmplY3RFeHByZXNzaW9uIjpjYXNlIk9iamVjdFBhdHRlcm4iOmNhc2UiT2JqZWN0VHlwZUFubm90YXRpb24iOmNhc2UiVFNJbnRlcmZhY2VCb2R5IjpjYXNlIlRTVHlwZUxpdGVyYWwiOnZhciBNLGo9Ik9iamVjdFR5cGVBbm5vdGF0aW9uIj09PWkudHlwZSxSPWUuZ2V0UGFyZW50Tm9kZSgwKSxCPSJUU0ludGVyZmFjZUJvZHkiPT09aS50eXBlfHwiT2JqZWN0UGF0dGVybiI9PT1pLnR5cGUmJiJGdW5jdGlvbkRlY2xhcmF0aW9uIiE9PVIudHlwZSYmIkZ1bmN0aW9uRXhwcmVzc2lvbiIhPT1SLnR5cGUmJiJBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbiIhPT1SLnR5cGUmJiJBc3NpZ25tZW50UGF0dGVybiIhPT1SLnR5cGUmJiJDYXRjaENsYXVzZSIhPT1SLnR5cGUmJmkucHJvcGVydGllcy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiBlLnZhbHVlJiYoIk9iamVjdFBhdHRlcm4iPT09ZS52YWx1ZS50eXBlfHwiQXJyYXlQYXR0ZXJuIj09PWUudmFsdWUudHlwZSl9KXx8Ik9iamVjdFBhdHRlcm4iIT09aS50eXBlJiZoYXNOZXdsaW5lSW5SYW5nZSQxKHQub3JpZ2luYWxUZXh0LHQubG9jU3RhcnQoaSksdC5sb2NFbmQoaSkpLCQ9aiYmUiYmKCJJbnRlcmZhY2VEZWNsYXJhdGlvbiI9PT1SLnR5cGV8fCJEZWNsYXJlSW50ZXJmYWNlIj09PVIudHlwZXx8IkRlY2xhcmVDbGFzcyI9PT1SLnR5cGUpJiYiYm9keSI9PT1lLmdldE5hbWUoKSxVPSQ/IjsiOiJUU0ludGVyZmFjZUJvZHkiPT09aS50eXBlfHwiVFNUeXBlTGl0ZXJhbCI9PT1pLnR5cGU/aWZCcmVhayQxKG8sIjsiKToiLCIsej1bXSxHPWkuZXhhY3Q/Int8IjoieyIsVj1pLmV4YWN0PyJ8fSI6In0iO009IlRTVHlwZUxpdGVyYWwiPT09aS50eXBlPyJtZW1iZXJzIjoiVFNJbnRlcmZhY2VCb2R5Ij09PWkudHlwZT8iYm9keSI6InByb3BlcnRpZXMiLGomJnoucHVzaCgiaW5kZXhlcnMiLCJjYWxsUHJvcGVydGllcyIpLHoucHVzaChNKTt2YXIgcT1bXTt6LmZvckVhY2goZnVuY3Rpb24ocil7ZS5lYWNoKGZ1bmN0aW9uKGUpe3ZhciByPWUuZ2V0VmFsdWUoKTtxLnB1c2goe25vZGU6cixwcmludGVkOm4oZSksbG9jOnQubG9jU3RhcnQocil9KX0scil9KTt2YXIgSCxXPVtdLFE9cS5zb3J0KGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUubG9jLXQubG9jfSkubWFwKGZ1bmN0aW9uKGUpe3ZhciBuPWNvbmNhdCQ0KFcuY29uY2F0KGdyb3VwJDEoZS5wcmludGVkKSkpO3JldHVybiBXPVtVLGxpbmUkM10sIlRTUHJvcGVydHlTaWduYXR1cmUiPT09ZS5ub2RlLnR5cGUmJmhhc05vZGVJZ25vcmVDb21tZW50JDEoZS5ub2RlKSYmVy5zaGlmdCgpLGlzTmV4dExpbmVFbXB0eSQyKHQub3JpZ2luYWxUZXh0LGUubm9kZSx0KSYmVy5wdXNoKGhhcmRsaW5lJDMpLG59KSxLPWdldExhc3QkNChpW01dKSxKPSEoSyYmKCJSZXN0UHJvcGVydHkiPT09Sy50eXBlfHwiUmVzdEVsZW1lbnQiPT09Sy50eXBlfHwiRXhwZXJpbWVudGFsUmVzdFByb3BlcnR5Ij09PUsudHlwZXx8aGFzTm9kZUlnbm9yZUNvbW1lbnQkMShLKSkpO2lmKDAhPT1RLmxlbmd0aHx8aS50eXBlQW5ub3RhdGlvbilIPWNvbmNhdCQ0KFtHLGluZGVudCQyKGNvbmNhdCQ0KFt0LmJyYWNrZXRTcGFjaW5nP2xpbmUkMzpzb2Z0bGluZSQxLGNvbmNhdCQ0KFEpXSkpLGlmQnJlYWskMShKJiYoIiwiIT09VXx8c2hvdWxkUHJpbnRDb21tYSh0KSk/VToiIiksY29uY2F0JDQoW3QuYnJhY2tldFNwYWNpbmc/bGluZSQzOnNvZnRsaW5lJDEsVl0pLHByaW50T3B0aW9uYWxUb2tlbihlKSxwcmludFR5cGVBbm5vdGF0aW9uKGUsdCxuKV0pO2Vsc2V7aWYoIWhhc0RhbmdsaW5nQ29tbWVudHMoaSkpcmV0dXJuIGNvbmNhdCQ0KFtHLFZdKTtIPWdyb3VwJDEoY29uY2F0JDQoW0csY29tbWVudHMucHJpbnREYW5nbGluZ0NvbW1lbnRzKGUsdCksc29mdGxpbmUkMSxWLHByaW50T3B0aW9uYWxUb2tlbihlKV0pKX12YXIgWT1lLmdldFBhcmVudE5vZGUoMik7cmV0dXJuIk9iamVjdFBhdHRlcm4iPT09aS50eXBlJiZSJiZzaG91bGRIdWdBcmd1bWVudHMoUikmJlIucGFyYW1zWzBdPT09aXx8c2hvdWxkSHVnVHlwZShpKSYmWSYmc2hvdWxkSHVnQXJndW1lbnRzKFkpJiZZLnBhcmFtc1swXS50eXBlQW5ub3RhdGlvbiYmWS5wYXJhbXNbMF0udHlwZUFubm90YXRpb24udHlwZUFubm90YXRpb249PT1pP0g6Z3JvdXAkMShILHtzaG91bGRCcmVhazpCfSk7Y2FzZSJPYmplY3RQcm9wZXJ0eSI6Y2FzZSJQcm9wZXJ0eSI6aWYoaS5tZXRob2R8fCJnZXQiPT09aS5raW5kfHwic2V0Ij09PWkua2luZClyZXR1cm4gcHJpbnRNZXRob2QoZSx0LG4pO2lmKGkuc2hvcnRoYW5kKWEucHVzaChlLmNhbGwobiwidmFsdWUiKSk7ZWxzZXt2YXIgWDtYPWkuY29tcHV0ZWQ/Y29uY2F0JDQoWyJbIixlLmNhbGwobiwia2V5IiksIl0iXSk6cHJpbnRQcm9wZXJ0eUtleShlLHQsbiksYS5wdXNoKHByaW50QXNzaWdubWVudChpLmtleSxYLCI6IixpLnZhbHVlLGUuY2FsbChuLCJ2YWx1ZSIpLHQpKX1yZXR1cm4gY29uY2F0JDQoYSk7Y2FzZSJDbGFzc01ldGhvZCI6cmV0dXJuIGkuc3RhdGljJiZhLnB1c2goInN0YXRpYyAiKSxhPWEuY29uY2F0KHByaW50T2JqZWN0TWV0aG9kKGUsdCxuKSksY29uY2F0JDQoYSk7Y2FzZSJPYmplY3RNZXRob2QiOnJldHVybiBwcmludE9iamVjdE1ldGhvZChlLHQsbik7Y2FzZSJEZWNvcmF0b3IiOnJldHVybiBjb25jYXQkNChbIkAiLGUuY2FsbChuLCJleHByZXNzaW9uIiksZS5jYWxsKG4sImNhbGxlZSIpXSk7Y2FzZSJBcnJheUV4cHJlc3Npb24iOmNhc2UiQXJyYXlQYXR0ZXJuIjppZigwPT09aS5lbGVtZW50cy5sZW5ndGgpaGFzRGFuZ2xpbmdDb21tZW50cyhpKT9hLnB1c2goZ3JvdXAkMShjb25jYXQkNChbIlsiLGNvbW1lbnRzLnByaW50RGFuZ2xpbmdDb21tZW50cyhlLHQpLHNvZnRsaW5lJDEsIl0iXSkpKTphLnB1c2goIltdIik7ZWxzZXt2YXIgWj1nZXRMYXN0JDQoaS5lbGVtZW50cyksZWU9IShaJiYiUmVzdEVsZW1lbnQiPT09Wi50eXBlKSx0ZT1lZSYmbnVsbD09PVo7YS5wdXNoKGdyb3VwJDEoY29uY2F0JDQoWyJbIixpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxwcmludEFycmF5SXRlbXMoZSx0LCJlbGVtZW50cyIsbildKSksdGU/IiwiOiIiLGlmQnJlYWskMShlZSYmIXRlJiZzaG91bGRQcmludENvbW1hKHQpPyIsIjoiIiksY29tbWVudHMucHJpbnREYW5nbGluZ0NvbW1lbnRzKGUsdCwhMCksc29mdGxpbmUkMSwiXSJdKSkpfXJldHVybiBhLnB1c2gocHJpbnRPcHRpb25hbFRva2VuKGUpLHByaW50VHlwZUFubm90YXRpb24oZSx0LG4pKSxjb25jYXQkNChhKTtjYXNlIlNlcXVlbmNlRXhwcmVzc2lvbiI6dmFyIG5lPWUuZ2V0UGFyZW50Tm9kZSgwKTtpZigiRXhwcmVzc2lvblN0YXRlbWVudCI9PT1uZS50eXBlfHwiRm9yU3RhdGVtZW50Ij09PW5lLnR5cGUpe3ZhciByZT1bXTtyZXR1cm4gZS5lYWNoKGZ1bmN0aW9uKGUpezA9PT1lLmdldE5hbWUoKT9yZS5wdXNoKG4oZSkpOnJlLnB1c2goIiwiLGluZGVudCQyKGNvbmNhdCQ0KFtsaW5lJDMsbihlKV0pKSl9LCJleHByZXNzaW9ucyIpLGdyb3VwJDEoY29uY2F0JDQocmUpKX1yZXR1cm4gZ3JvdXAkMShjb25jYXQkNChbam9pbiQyKGNvbmNhdCQ0KFsiLCIsbGluZSQzXSksZS5tYXAobiwiZXhwcmVzc2lvbnMiKSldKSk7Y2FzZSJUaGlzRXhwcmVzc2lvbiI6cmV0dXJuInRoaXMiO2Nhc2UiU3VwZXIiOnJldHVybiJzdXBlciI7Y2FzZSJOdWxsTGl0ZXJhbCI6cmV0dXJuIm51bGwiO2Nhc2UiUmVnRXhwTGl0ZXJhbCI6cmV0dXJuIHByaW50UmVnZXgoaSk7Y2FzZSJOdW1lcmljTGl0ZXJhbCI6cmV0dXJuIHByaW50TnVtYmVyJDEoaS5leHRyYS5yYXcpO2Nhc2UiQm9vbGVhbkxpdGVyYWwiOmNhc2UiU3RyaW5nTGl0ZXJhbCI6Y2FzZSJMaXRlcmFsIjppZihpLnJlZ2V4KXJldHVybiBwcmludFJlZ2V4KGkucmVnZXgpO2lmKCJudW1iZXIiPT09dHlwZW9mIGkudmFsdWUpcmV0dXJuIHByaW50TnVtYmVyJDEoaS5yYXcpO2lmKCJzdHJpbmciIT09dHlwZW9mIGkudmFsdWUpcmV0dXJuIiIraS52YWx1ZTt2YXIgaWU9ZS5nZXRQYXJlbnROb2RlKDEpLG9lPSJ0eXBlc2NyaXB0Ij09PXQucGFyc2VyJiYic3RyaW5nIj09PXR5cGVvZiBpLnZhbHVlJiZpZSYmKCJQcm9ncmFtIj09PWllLnR5cGV8fCJCbG9ja1N0YXRlbWVudCI9PT1pZS50eXBlKTtyZXR1cm4gbm9kZVN0cihpLHQsb2UpO2Nhc2UiRGlyZWN0aXZlIjpyZXR1cm4gZS5jYWxsKG4sInZhbHVlIik7Y2FzZSJEaXJlY3RpdmVMaXRlcmFsIjpyZXR1cm4gbm9kZVN0cihpLHQpO2Nhc2UiVW5hcnlFeHByZXNzaW9uIjpyZXR1cm4gYS5wdXNoKGkub3BlcmF0b3IpLC9bYS16XSQvLnRlc3QoaS5vcGVyYXRvcikmJmEucHVzaCgiICIpLGEucHVzaChlLmNhbGwobiwiYXJndW1lbnQiKSksY29uY2F0JDQoYSk7Y2FzZSJVcGRhdGVFeHByZXNzaW9uIjpyZXR1cm4gYS5wdXNoKGUuY2FsbChuLCJhcmd1bWVudCIpLGkub3BlcmF0b3IpLGkucHJlZml4JiZhLnJldmVyc2UoKSxjb25jYXQkNChhKTtjYXNlIkNvbmRpdGlvbmFsRXhwcmVzc2lvbiI6cmV0dXJuIGZvcm1hdFRlcm5hcnlPcGVyYXRvcihlLHQsbix7YmVmb3JlUGFydHM6ZnVuY3Rpb24oKXtyZXR1cm5bZS5jYWxsKG4sInRlc3QiKV19LGFmdGVyUGFydHM6ZnVuY3Rpb24oZSl7cmV0dXJuW2U/c29mdGxpbmUkMToiIl19fSk7Y2FzZSJWYXJpYWJsZURlY2xhcmF0aW9uIjp2YXIgYWUsc2U9ZS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIG4oZSl9LCJkZWNsYXJhdGlvbnMiKSx1ZT1lLmdldFBhcmVudE5vZGUoKSxjZT0iRm9yU3RhdGVtZW50Ij09PXVlLnR5cGV8fCJGb3JJblN0YXRlbWVudCI9PT11ZS50eXBlfHwiRm9yT2ZTdGF0ZW1lbnQiPT09dWUudHlwZXx8IkZvckF3YWl0U3RhdGVtZW50Ij09PXVlLnR5cGUsbGU9aS5kZWNsYXJhdGlvbnMuc29tZShmdW5jdGlvbihlKXtyZXR1cm4gZS5pbml0fSk7cmV0dXJuIDE9PT1zZS5sZW5ndGg/YWU9c2VbMF06c2UubGVuZ3RoPjEmJihhZT1pbmRlbnQkMihzZVswXSkpLGE9W2lzTm9kZVN0YXJ0aW5nV2l0aERlY2xhcmUoaSx0KT8iZGVjbGFyZSAiOiIiLGkua2luZCxhZT9jb25jYXQkNChbIiAiLGFlXSk6IiIsaW5kZW50JDIoY29uY2F0JDQoc2Uuc2xpY2UoMSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBjb25jYXQkNChbIiwiLGxlJiYhY2U/aGFyZGxpbmUkMzpsaW5lJDMsZV0pfSkpKV0sY2UmJnVlLmJvZHkhPT1pfHxhLnB1c2gobyksZ3JvdXAkMShjb25jYXQkNChhKSk7Y2FzZSJWYXJpYWJsZURlY2xhcmF0b3IiOnJldHVybiBwcmludEFzc2lnbm1lbnQoaS5pZCxjb25jYXQkNChbZS5jYWxsKG4sImlkIiksZS5jYWxsKG4sInR5cGVQYXJhbWV0ZXJzIildKSwiID0iLGkuaW5pdCxpLmluaXQmJmUuY2FsbChuLCJpbml0IiksdCk7Y2FzZSJXaXRoU3RhdGVtZW50IjpyZXR1cm4gZ3JvdXAkMShjb25jYXQkNChbIndpdGggKCIsZS5jYWxsKG4sIm9iamVjdCIpLCIpIixhZGp1c3RDbGF1c2UoaS5ib2R5LGUuY2FsbChuLCJib2R5IikpXSkpO2Nhc2UiSWZTdGF0ZW1lbnQiOnZhciBwZT1hZGp1c3RDbGF1c2UoaS5jb25zZXF1ZW50LGUuY2FsbChuLCJjb25zZXF1ZW50IikpLGZlPWdyb3VwJDEoY29uY2F0JDQoWyJpZiAoIixncm91cCQxKGNvbmNhdCQ0KFtpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxlLmNhbGwobiwidGVzdCIpXSkpLHNvZnRsaW5lJDFdKSksIikiLHBlXSkpO2lmKGEucHVzaChmZSksaS5hbHRlcm5hdGUpe3ZhciBkZT1oYXNUcmFpbGluZ0NvbW1lbnQoaS5jb25zZXF1ZW50KSYmaS5jb25zZXF1ZW50LmNvbW1lbnRzLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGUudHJhaWxpbmcmJiFjb21tZW50cyQzLmlzQmxvY2tDb21tZW50KGUpfSl8fG5lZWRzSGFyZGxpbmVBZnRlckRhbmdsaW5nQ29tbWVudChpKSxoZT0iQmxvY2tTdGF0ZW1lbnQiPT09aS5jb25zZXF1ZW50LnR5cGUmJiFkZTthLnB1c2goaGU/IiAiOmhhcmRsaW5lJDMpLGhhc0RhbmdsaW5nQ29tbWVudHMoaSkmJmEucHVzaChjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0LCEwKSxkZT9oYXJkbGluZSQzOiIgIiksYS5wdXNoKCJlbHNlIixncm91cCQxKGFkanVzdENsYXVzZShpLmFsdGVybmF0ZSxlLmNhbGwobiwiYWx0ZXJuYXRlIiksIklmU3RhdGVtZW50Ij09PWkuYWx0ZXJuYXRlLnR5cGUpKSl9cmV0dXJuIGNvbmNhdCQ0KGEpO2Nhc2UiRm9yU3RhdGVtZW50Ijp2YXIgbWU9YWRqdXN0Q2xhdXNlKGkuYm9keSxlLmNhbGwobiwiYm9keSIpKSxnZT1jb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0LCEwKSx5ZT1nZT9jb25jYXQkNChbZ2Usc29mdGxpbmUkMV0pOiIiO3JldHVybiBjb25jYXQkNChpLmluaXR8fGkudGVzdHx8aS51cGRhdGU/W3llLGdyb3VwJDEoY29uY2F0JDQoWyJmb3IgKCIsZ3JvdXAkMShjb25jYXQkNChbaW5kZW50JDIoY29uY2F0JDQoW3NvZnRsaW5lJDEsZS5jYWxsKG4sImluaXQiKSwiOyIsbGluZSQzLGUuY2FsbChuLCJ0ZXN0IiksIjsiLGxpbmUkMyxlLmNhbGwobiwidXBkYXRlIildKSksc29mdGxpbmUkMV0pKSwiKSIsbWVdKSldOlt5ZSxncm91cCQxKGNvbmNhdCQ0KFsiZm9yICg7OykiLG1lXSkpXSk7Y2FzZSJXaGlsZVN0YXRlbWVudCI6cmV0dXJuIGdyb3VwJDEoY29uY2F0JDQoWyJ3aGlsZSAoIixncm91cCQxKGNvbmNhdCQ0KFtpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxlLmNhbGwobiwidGVzdCIpXSkpLHNvZnRsaW5lJDFdKSksIikiLGFkanVzdENsYXVzZShpLmJvZHksZS5jYWxsKG4sImJvZHkiKSldKSk7Y2FzZSJGb3JJblN0YXRlbWVudCI6cmV0dXJuIGdyb3VwJDEoY29uY2F0JDQoW2kuZWFjaD8iZm9yIGVhY2ggKCI6ImZvciAoIixlLmNhbGwobiwibGVmdCIpLCIgaW4gIixlLmNhbGwobiwicmlnaHQiKSwiKSIsYWRqdXN0Q2xhdXNlKGkuYm9keSxlLmNhbGwobiwiYm9keSIpKV0pKTtjYXNlIkZvck9mU3RhdGVtZW50IjpjYXNlIkZvckF3YWl0U3RhdGVtZW50Ijp2YXIgdmU9IkZvckF3YWl0U3RhdGVtZW50Ij09PWkudHlwZXx8aS5hd2FpdDtyZXR1cm4gZ3JvdXAkMShjb25jYXQkNChbImZvciIsdmU/IiBhd2FpdCI6IiIsIiAoIixlLmNhbGwobiwibGVmdCIpLCIgb2YgIixlLmNhbGwobiwicmlnaHQiKSwiKSIsYWRqdXN0Q2xhdXNlKGkuYm9keSxlLmNhbGwobiwiYm9keSIpKV0pKTtjYXNlIkRvV2hpbGVTdGF0ZW1lbnQiOnZhciBiZT1hZGp1c3RDbGF1c2UoaS5ib2R5LGUuY2FsbChuLCJib2R5IikpLHhlPWdyb3VwJDEoY29uY2F0JDQoWyJkbyIsYmVdKSk7cmV0dXJuIGE9W3hlXSwiQmxvY2tTdGF0ZW1lbnQiPT09aS5ib2R5LnR5cGU/YS5wdXNoKCIgIik6YS5wdXNoKGhhcmRsaW5lJDMpLGEucHVzaCgid2hpbGUgKCIpLGEucHVzaChncm91cCQxKGNvbmNhdCQ0KFtpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxlLmNhbGwobiwidGVzdCIpXSkpLHNvZnRsaW5lJDFdKSksIikiLG8pLGNvbmNhdCQ0KGEpO2Nhc2UiRG9FeHByZXNzaW9uIjpyZXR1cm4gY29uY2F0JDQoWyJkbyAiLGUuY2FsbChuLCJib2R5IildKTtjYXNlIkJyZWFrU3RhdGVtZW50IjpyZXR1cm4gYS5wdXNoKCJicmVhayIpLGkubGFiZWwmJmEucHVzaCgiICIsZS5jYWxsKG4sImxhYmVsIikpLGEucHVzaChvKSxjb25jYXQkNChhKTtjYXNlIkNvbnRpbnVlU3RhdGVtZW50IjpyZXR1cm4gYS5wdXNoKCJjb250aW51ZSIpLGkubGFiZWwmJmEucHVzaCgiICIsZS5jYWxsKG4sImxhYmVsIikpLGEucHVzaChvKSxjb25jYXQkNChhKTtjYXNlIkxhYmVsZWRTdGF0ZW1lbnQiOnJldHVybiBjb25jYXQkNCgiRW1wdHlTdGF0ZW1lbnQiPT09aS5ib2R5LnR5cGU/W2UuY2FsbChuLCJsYWJlbCIpLCI6OyJdOltlLmNhbGwobiwibGFiZWwiKSwiOiAiLGUuY2FsbChuLCJib2R5IildKTtjYXNlIlRyeVN0YXRlbWVudCI6cmV0dXJuIGNvbmNhdCQ0KFsidHJ5ICIsZS5jYWxsKG4sImJsb2NrIiksaS5oYW5kbGVyP2NvbmNhdCQ0KFsiICIsZS5jYWxsKG4sImhhbmRsZXIiKV0pOiIiLGkuZmluYWxpemVyP2NvbmNhdCQ0KFsiIGZpbmFsbHkgIixlLmNhbGwobiwiZmluYWxpemVyIildKToiIl0pO2Nhc2UiQ2F0Y2hDbGF1c2UiOnJldHVybiBjb25jYXQkNChbImNhdGNoICIsaS5wYXJhbT9jb25jYXQkNChbIigiLGUuY2FsbChuLCJwYXJhbSIpLCIpICJdKToiIixlLmNhbGwobiwiYm9keSIpXSk7Y2FzZSJUaHJvd1N0YXRlbWVudCI6cmV0dXJuIGNvbmNhdCQ0KFsidGhyb3cgIixlLmNhbGwobiwiYXJndW1lbnQiKSxvXSk7Y2FzZSJTd2l0Y2hTdGF0ZW1lbnQiOnJldHVybiBjb25jYXQkNChbZ3JvdXAkMShjb25jYXQkNChbInN3aXRjaCAoIixpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxlLmNhbGwobiwiZGlzY3JpbWluYW50IildKSksc29mdGxpbmUkMSwiKSJdKSksIiB7IixpLmNhc2VzLmxlbmd0aD4wP2luZGVudCQyKGNvbmNhdCQ0KFtoYXJkbGluZSQzLGpvaW4kMihoYXJkbGluZSQzLGUubWFwKGZ1bmN0aW9uKGUpe3ZhciByPWUuZ2V0VmFsdWUoKTtyZXR1cm4gY29uY2F0JDQoW2UuY2FsbChuKSxpLmNhc2VzLmluZGV4T2YocikhPT1pLmNhc2VzLmxlbmd0aC0xJiZpc05leHRMaW5lRW1wdHkkMih0Lm9yaWdpbmFsVGV4dCxyLHQpP2hhcmRsaW5lJDM6IiJdKX0sImNhc2VzIikpXSkpOiIiLGhhcmRsaW5lJDMsIn0iXSk7Y2FzZSJTd2l0Y2hDYXNlIjppLnRlc3Q/YS5wdXNoKCJjYXNlICIsZS5jYWxsKG4sInRlc3QiKSwiOiIpOmEucHVzaCgiZGVmYXVsdDoiKTt2YXIgQ2U9aS5jb25zZXF1ZW50LmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4iRW1wdHlTdGF0ZW1lbnQiIT09ZS50eXBlfSk7aWYoQ2UubGVuZ3RoPjApe3ZhciBFZT1lLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIHByaW50U3RhdGVtZW50U2VxdWVuY2UoZSx0LG4pfSwiY29uc2VxdWVudCIpO2EucHVzaCgxPT09Q2UubGVuZ3RoJiYiQmxvY2tTdGF0ZW1lbnQiPT09Q2VbMF0udHlwZT9jb25jYXQkNChbIiAiLEVlXSk6aW5kZW50JDIoY29uY2F0JDQoW2hhcmRsaW5lJDMsRWVdKSkpfXJldHVybiBjb25jYXQkNChhKTtjYXNlIkRlYnVnZ2VyU3RhdGVtZW50IjpyZXR1cm4gY29uY2F0JDQoWyJkZWJ1Z2dlciIsb10pO2Nhc2UiSlNYQXR0cmlidXRlIjppZihhLnB1c2goZS5jYWxsKG4sIm5hbWUiKSksaS52YWx1ZSl7dmFyIERlO2lmKGlzU3RyaW5nTGl0ZXJhbChpLnZhbHVlKSl7RGU9JyInK3Jhd1RleHQoaS52YWx1ZSkuc2xpY2UoMSwtMSkucmVwbGFjZSgvIi9nLCImcXVvdDsiKSsnIid9ZWxzZSBEZT1lLmNhbGwobiwidmFsdWUiKTthLnB1c2goIj0iLERlKX1yZXR1cm4gY29uY2F0JDQoYSk7Y2FzZSJKU1hJZGVudGlmaWVyIjpyZXR1cm4gaS5uYW1lPyIiK2kubmFtZToidGhpcyI7Y2FzZSJKU1hOYW1lc3BhY2VkTmFtZSI6cmV0dXJuIGpvaW4kMigiOiIsW2UuY2FsbChuLCJuYW1lc3BhY2UiKSxlLmNhbGwobiwibmFtZSIpXSk7Y2FzZSJKU1hNZW1iZXJFeHByZXNzaW9uIjpyZXR1cm4gam9pbiQyKCIuIixbZS5jYWxsKG4sIm9iamVjdCIpLGUuY2FsbChuLCJwcm9wZXJ0eSIpXSk7Y2FzZSJUU1F1YWxpZmllZE5hbWUiOnJldHVybiBqb2luJDIoIi4iLFtlLmNhbGwobiwibGVmdCIpLGUuY2FsbChuLCJyaWdodCIpXSk7Y2FzZSJKU1hTcHJlYWRBdHRyaWJ1dGUiOmNhc2UiSlNYU3ByZWFkQ2hpbGQiOnJldHVybiBjb25jYXQkNChbInsiLGUuY2FsbChmdW5jdGlvbihlKXt2YXIgcj1jb25jYXQkNChbIi4uLiIsbihlKV0pLGk9ZS5nZXRWYWx1ZSgpO3JldHVybiBpLmNvbW1lbnRzJiZpLmNvbW1lbnRzLmxlbmd0aD9jb25jYXQkNChbaW5kZW50JDIoY29uY2F0JDQoW3NvZnRsaW5lJDEsY29tbWVudHMucHJpbnRDb21tZW50cyhlLGZ1bmN0aW9uKCl7cmV0dXJuIHJ9LHQpXSkpLHNvZnRsaW5lJDFdKTpyfSwiSlNYU3ByZWFkQXR0cmlidXRlIj09PWkudHlwZT8iYXJndW1lbnQiOiJleHByZXNzaW9uIiksIn0iXSk7Y2FzZSJKU1hFeHByZXNzaW9uQ29udGFpbmVyIjp2YXIgd2U9ZS5nZXRQYXJlbnROb2RlKDApLFNlPSJKU1hBdHRyaWJ1dGUiPT09d2UudHlwZSYmaS5leHByZXNzaW9uLmNvbW1lbnRzJiZpLmV4cHJlc3Npb24uY29tbWVudHMubGVuZ3RoPjAsa2U9IVNlJiYoIkFycmF5RXhwcmVzc2lvbiI9PT1pLmV4cHJlc3Npb24udHlwZXx8Ik9iamVjdEV4cHJlc3Npb24iPT09aS5leHByZXNzaW9uLnR5cGV8fCJBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbiI9PT1pLmV4cHJlc3Npb24udHlwZXx8IkNhbGxFeHByZXNzaW9uIj09PWkuZXhwcmVzc2lvbi50eXBlfHwiT3B0aW9uYWxDYWxsRXhwcmVzc2lvbiI9PT1pLmV4cHJlc3Npb24udHlwZXx8IkZ1bmN0aW9uRXhwcmVzc2lvbiI9PT1pLmV4cHJlc3Npb24udHlwZXx8IkpTWEVtcHR5RXhwcmVzc2lvbiI9PT1pLmV4cHJlc3Npb24udHlwZXx8IlRlbXBsYXRlTGl0ZXJhbCI9PT1pLmV4cHJlc3Npb24udHlwZXx8IlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbiI9PT1pLmV4cHJlc3Npb24udHlwZXx8IkRvRXhwcmVzc2lvbiI9PT1pLmV4cHJlc3Npb24udHlwZXx8aXNKU1hOb2RlKHdlKSYmKCJDb25kaXRpb25hbEV4cHJlc3Npb24iPT09aS5leHByZXNzaW9uLnR5cGV8fGlzQmluYXJ5aXNoKGkuZXhwcmVzc2lvbikpKTtyZXR1cm4gZ3JvdXAkMShrZT9jb25jYXQkNChbInsiLGUuY2FsbChuLCJleHByZXNzaW9uIiksbGluZVN1ZmZpeEJvdW5kYXJ5JDEsIn0iXSk6Y29uY2F0JDQoWyJ7IixpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxlLmNhbGwobiwiZXhwcmVzc2lvbiIpXSkpLHNvZnRsaW5lJDEsbGluZVN1ZmZpeEJvdW5kYXJ5JDEsIn0iXSkpO2Nhc2UiSlNYRnJhZ21lbnQiOmNhc2UiVFNKc3hGcmFnbWVudCI6Y2FzZSJKU1hFbGVtZW50Ijp2YXIgQWU9Y29tbWVudHMucHJpbnRDb21tZW50cyhlLGZ1bmN0aW9uKCl7cmV0dXJuIHByaW50SlNYRWxlbWVudChlLHQsbil9LHQpO3JldHVybiBtYXliZVdyYXBKU1hFbGVtZW50SW5QYXJlbnMoZSxBZSk7Y2FzZSJKU1hPcGVuaW5nRWxlbWVudCI6dmFyIF9lPWUuZ2V0VmFsdWUoKSxUZT1fZS5uYW1lJiZfZS5uYW1lLmNvbW1lbnRzJiZfZS5uYW1lLmNvbW1lbnRzLmxlbmd0aD4wO2lmKF9lLnNlbGZDbG9zaW5nJiYhX2UuYXR0cmlidXRlcy5sZW5ndGgmJiFUZSlyZXR1cm4gY29uY2F0JDQoWyI8IixlLmNhbGwobiwibmFtZSIpLGUuY2FsbChuLCJ0eXBlUGFyYW1ldGVycyIpLCIgLz4iXSk7aWYoX2UuYXR0cmlidXRlcyYmMT09PV9lLmF0dHJpYnV0ZXMubGVuZ3RoJiZfZS5hdHRyaWJ1dGVzWzBdLnZhbHVlJiZpc1N0cmluZ0xpdGVyYWwoX2UuYXR0cmlidXRlc1swXS52YWx1ZSkmJiFfZS5hdHRyaWJ1dGVzWzBdLnZhbHVlLnZhbHVlLmluY2x1ZGVzKCJcbiIpJiYhVGUmJighX2UuYXR0cmlidXRlc1swXS5jb21tZW50c3x8IV9lLmF0dHJpYnV0ZXNbMF0uY29tbWVudHMubGVuZ3RoKSlyZXR1cm4gZ3JvdXAkMShjb25jYXQkNChbIjwiLGUuY2FsbChuLCJuYW1lIiksZS5jYWxsKG4sInR5cGVQYXJhbWV0ZXJzIiksIiAiLGNvbmNhdCQ0KGUubWFwKG4sImF0dHJpYnV0ZXMiKSksX2Uuc2VsZkNsb3Npbmc/IiAvPiI6Ij4iXSkpO3ZhciBPZT1fZS5hdHRyaWJ1dGVzLmxlbmd0aCYmaGFzVHJhaWxpbmdDb21tZW50KGdldExhc3QkNChfZS5hdHRyaWJ1dGVzKSksRmU9dC5qc3hCcmFja2V0U2FtZUxpbmUmJighVGV8fF9lLmF0dHJpYnV0ZXMubGVuZ3RoKSYmIU9lLE5lPV9lLmF0dHJpYnV0ZXMmJl9lLmF0dHJpYnV0ZXMuc29tZShmdW5jdGlvbihlKXtyZXR1cm4gZS52YWx1ZSYmaXNTdHJpbmdMaXRlcmFsKGUudmFsdWUpJiZlLnZhbHVlLnZhbHVlLmluY2x1ZGVzKCJcbiIpfSk7cmV0dXJuIGdyb3VwJDEoY29uY2F0JDQoWyI8IixlLmNhbGwobiwibmFtZSIpLGUuY2FsbChuLCJ0eXBlUGFyYW1ldGVycyIpLGNvbmNhdCQ0KFtpbmRlbnQkMihjb25jYXQkNChlLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gY29uY2F0JDQoW2xpbmUkMyxuKGUpXSl9LCJhdHRyaWJ1dGVzIikpKSxfZS5zZWxmQ2xvc2luZz9saW5lJDM6RmU/Ij4iOnNvZnRsaW5lJDFdKSxfZS5zZWxmQ2xvc2luZz8iLz4iOkZlPyIiOiI+Il0pLHtzaG91bGRCcmVhazpOZX0pO2Nhc2UiSlNYQ2xvc2luZ0VsZW1lbnQiOnJldHVybiBjb25jYXQkNChbIjwvIixlLmNhbGwobiwibmFtZSIpLCI+Il0pO2Nhc2UiSlNYT3BlbmluZ0ZyYWdtZW50IjpjYXNlIkpTWENsb3NpbmdGcmFnbWVudCI6Y2FzZSJUU0pzeE9wZW5pbmdGcmFnbWVudCI6Y2FzZSJUU0pzeENsb3NpbmdGcmFnbWVudCI6dmFyIEllPWkuY29tbWVudHMmJmkuY29tbWVudHMubGVuZ3RoLExlPUllJiYhaS5jb21tZW50cy5ldmVyeShjb21tZW50cyQzLmlzQmxvY2tDb21tZW50KSxQZT0iSlNYT3BlbmluZ0ZyYWdtZW50Ij09PWkudHlwZXx8IlRTSnN4T3BlbmluZ0ZyYWdtZW50Ij09PWkudHlwZTtyZXR1cm4gY29uY2F0JDQoW1BlPyI8IjoiPC8iLGluZGVudCQyKGNvbmNhdCQ0KFtMZT9oYXJkbGluZSQzOkllJiYhUGU/IiAiOiIiLGNvbW1lbnRzLnByaW50RGFuZ2xpbmdDb21tZW50cyhlLHQsITApXSkpLExlP2hhcmRsaW5lJDM6IiIsIj4iXSk7Y2FzZSJKU1hUZXh0Ijp0aHJvdyBuZXcgRXJyb3IoIkpTWFRlc3Qgc2hvdWxkIGJlIGhhbmRsZWQgYnkgSlNYRWxlbWVudCIpO2Nhc2UiSlNYRW1wdHlFeHByZXNzaW9uIjp2YXIgTWU9aS5jb21tZW50cyYmIWkuY29tbWVudHMuZXZlcnkoY29tbWVudHMkMy5pc0Jsb2NrQ29tbWVudCk7cmV0dXJuIGNvbmNhdCQ0KFtjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0LCFNZSksTWU/aGFyZGxpbmUkMzoiIl0pO2Nhc2UiQ2xhc3NCb2R5IjpyZXR1cm4gaS5jb21tZW50c3x8MCE9PWkuYm9keS5sZW5ndGg/Y29uY2F0JDQoWyJ7IixpLmJvZHkubGVuZ3RoPjA/aW5kZW50JDIoY29uY2F0JDQoW2hhcmRsaW5lJDMsZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBwcmludFN0YXRlbWVudFNlcXVlbmNlKGUsdCxuKX0sImJvZHkiKV0pKTpjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0KSxoYXJkbGluZSQzLCJ9Il0pOiJ7fSI7Y2FzZSJDbGFzc1Byb3BlcnR5IjpjYXNlIlRTQWJzdHJhY3RDbGFzc1Byb3BlcnR5IjpjYXNlIkNsYXNzUHJpdmF0ZVByb3BlcnR5IjppLmFjY2Vzc2liaWxpdHkmJmEucHVzaChpLmFjY2Vzc2liaWxpdHkrIiAiKSxpLnN0YXRpYyYmYS5wdXNoKCJzdGF0aWMgIiksIlRTQWJzdHJhY3RDbGFzc1Byb3BlcnR5Ij09PWkudHlwZSYmYS5wdXNoKCJhYnN0cmFjdCAiKSxpLnJlYWRvbmx5JiZhLnB1c2goInJlYWRvbmx5ICIpO3ZhciBqZT1nZXRGbG93VmFyaWFuY2UoaSk7cmV0dXJuIGplJiZhLnB1c2goamUpLGkuY29tcHV0ZWQ/YS5wdXNoKCJbIixlLmNhbGwobiwia2V5IiksIl0iKTphLnB1c2gocHJpbnRQcm9wZXJ0eUtleShlLHQsbikpLGEucHVzaChwcmludFR5cGVBbm5vdGF0aW9uKGUsdCxuKSksaS52YWx1ZSYmYS5wdXNoKCIgPSIscHJpbnRBc3NpZ25tZW50UmlnaHQoaS5rZXksaS52YWx1ZSxlLmNhbGwobiwidmFsdWUiKSx0KSksYS5wdXNoKG8pLGdyb3VwJDEoY29uY2F0JDQoYSkpO2Nhc2UiQ2xhc3NEZWNsYXJhdGlvbiI6Y2FzZSJDbGFzc0V4cHJlc3Npb24iOmNhc2UiVFNBYnN0cmFjdENsYXNzRGVjbGFyYXRpb24iOnJldHVybiBpc05vZGVTdGFydGluZ1dpdGhEZWNsYXJlKGksdCkmJmEucHVzaCgiZGVjbGFyZSAiKSxhLnB1c2goY29uY2F0JDQocHJpbnRDbGFzcyhlLHQsbikpKSxjb25jYXQkNChhKTtjYXNlIlRTSW50ZXJmYWNlSGVyaXRhZ2UiOnJldHVybiBhLnB1c2goZS5jYWxsKG4sImlkIikpLGkudHlwZVBhcmFtZXRlcnMmJmEucHVzaChlLmNhbGwobiwidHlwZVBhcmFtZXRlcnMiKSksY29uY2F0JDQoYSk7Y2FzZSJUZW1wbGF0ZUVsZW1lbnQiOnJldHVybiBqb2luJDIobGl0ZXJhbGxpbmUkMSxpLnZhbHVlLnJhdy5zcGxpdCgvXHI/XG4vZykpO2Nhc2UiVGVtcGxhdGVMaXRlcmFsIjp2YXIgUmU9ZS5tYXAobiwiZXhwcmVzc2lvbnMiKSxCZT1lLmdldFBhcmVudE5vZGUoKSwkZT0vXlt4Zl0/KGRlc2NyaWJlfGl0fHRlc3QpJC87aWYoIlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbiI9PT1CZS50eXBlJiZCZS5xdWFzaT09PWkmJiJNZW1iZXJFeHByZXNzaW9uIj09PUJlLnRhZy50eXBlJiYiSWRlbnRpZmllciI9PT1CZS50YWcucHJvcGVydHkudHlwZSYmImVhY2giPT09QmUudGFnLnByb3BlcnR5Lm5hbWUmJigiSWRlbnRpZmllciI9PT1CZS50YWcub2JqZWN0LnR5cGUmJiRlLnRlc3QoQmUudGFnLm9iamVjdC5uYW1lKXx8Ik1lbWJlckV4cHJlc3Npb24iPT09QmUudGFnLm9iamVjdC50eXBlJiYiSWRlbnRpZmllciI9PT1CZS50YWcub2JqZWN0LnByb3BlcnR5LnR5cGUmJigib25seSI9PT1CZS50YWcub2JqZWN0LnByb3BlcnR5Lm5hbWV8fCJza2lwIj09PUJlLnRhZy5vYmplY3QucHJvcGVydHkubmFtZSkmJiJJZGVudGlmaWVyIj09PUJlLnRhZy5vYmplY3Qub2JqZWN0LnR5cGUmJiRlLnRlc3QoQmUudGFnLm9iamVjdC5vYmplY3QubmFtZSkpKXt2YXIgVWU9aS5xdWFzaXNbMF0udmFsdWUucmF3LnRyaW0oKS5zcGxpdCgvXHMqXHxccyovKTtpZihVZS5sZW5ndGg+MXx8VWUuc29tZShmdW5jdGlvbihlKXtyZXR1cm4gMCE9PWUubGVuZ3RofSkpe2Zvcih2YXIgemU9UmUubWFwKGZ1bmN0aW9uKGUpe3JldHVybiIkeyIrcHJpbnREb2NUb1N0cmluZyQxKGUsT2JqZWN0LmFzc2lnbih7fSx0LHtwcmludFdpZHRoOjEvMH0pKS5mb3JtYXR0ZWQrIn0ifSksR2U9W3toYXNMaW5lQnJlYWs6ITEsY2VsbHM6W119XSxWZT0xO1ZlPGkucXVhc2lzLmxlbmd0aDtWZSsrKXt2YXIgcWU9R2VbR2UubGVuZ3RoLTFdLEhlPXplW1ZlLTFdO3FlLmNlbGxzLnB1c2goSGUpLC0xIT09SGUuaW5kZXhPZigiXG4iKSYmKHFlLmhhc0xpbmVCcmVhaz0hMCksLTEhPT1pLnF1YXNpc1tWZV0udmFsdWUucmF3LmluZGV4T2YoIlxuIikmJkdlLnB1c2goe2hhc0xpbmVCcmVhazohMSxjZWxsczpbXX0pfXZhciBXZT1HZS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gTWF0aC5tYXgoZSx0LmNlbGxzLmxlbmd0aCl9LFVlLmxlbmd0aCksUWU9QXJyYXkuZnJvbShuZXcgQXJyYXkoV2UpLGZ1bmN0aW9uKCl7cmV0dXJuIDB9KSxLZT1be2NlbGxzOlVlfV0uY29uY2F0KEdlLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gMCE9PWUuY2VsbHMubGVuZ3RofSkpO3JldHVybiBLZS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIWUuaGFzTGluZUJyZWFrfSkuZm9yRWFjaChmdW5jdGlvbihlKXtlLmNlbGxzLmZvckVhY2goZnVuY3Rpb24oZSx0KXtRZVt0XT1NYXRoLm1heChRZVt0XSxnZXRTdHJpbmdXaWR0aCQxKGUpKX0pfSksYS5wdXNoKCJgIixpbmRlbnQkMihjb25jYXQkNChbaGFyZGxpbmUkMyxqb2luJDIoaGFyZGxpbmUkMyxLZS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGpvaW4kMigiIHwgIixlLmNlbGxzLm1hcChmdW5jdGlvbih0LG4pe3JldHVybiBlLmhhc0xpbmVCcmVhaz90OnQrIiAiLnJlcGVhdChRZVtuXS1nZXRTdHJpbmdXaWR0aCQxKHQpKX0pKX0pKV0pKSxoYXJkbGluZSQzLCJgIiksY29uY2F0JDQoYSl9fXJldHVybiBhLnB1c2goImAiKSxlLmVhY2goZnVuY3Rpb24oZSl7dmFyIHI9ZS5nZXROYW1lKCk7aWYoYS5wdXNoKG4oZSkpLHI8UmUubGVuZ3RoKXt2YXIgbz10LnRhYldpZHRoLHM9Z2V0SW5kZW50U2l6ZSQxKGUuZ2V0VmFsdWUoKS52YWx1ZS5yYXcsbyksdT1SZVtyXTsoaS5leHByZXNzaW9uc1tyXS5jb21tZW50cyYmaS5leHByZXNzaW9uc1tyXS5jb21tZW50cy5sZW5ndGh8fCJNZW1iZXJFeHByZXNzaW9uIj09PWkuZXhwcmVzc2lvbnNbcl0udHlwZXx8Ik9wdGlvbmFsTWVtYmVyRXhwcmVzc2lvbiI9PT1pLmV4cHJlc3Npb25zW3JdLnR5cGV8fCJDb25kaXRpb25hbEV4cHJlc3Npb24iPT09aS5leHByZXNzaW9uc1tyXS50eXBlKSYmKHU9Y29uY2F0JDQoW2luZGVudCQyKGNvbmNhdCQ0KFtzb2Z0bGluZSQxLHVdKSksc29mdGxpbmUkMV0pKTt2YXIgYz1hZGRBbGlnbm1lbnRUb0RvYyQyKHUscyxvKTthLnB1c2goZ3JvdXAkMShjb25jYXQkNChbIiR7IixjLGxpbmVTdWZmaXhCb3VuZGFyeSQxLCJ9Il0pKSl9fSwicXVhc2lzIiksYS5wdXNoKCJgIiksY29uY2F0JDQoYSk7Y2FzZSJUYWdnZWRUZW1wbGF0ZUV4cHJlc3Npb24iOnJldHVybiBjb25jYXQkNChbZS5jYWxsKG4sInRhZyIpLGUuY2FsbChuLCJ0eXBlUGFyYW1ldGVycyIpLGUuY2FsbChuLCJxdWFzaSIpXSk7Y2FzZSJOb2RlIjpjYXNlIlByaW50YWJsZSI6Y2FzZSJTb3VyY2VMb2NhdGlvbiI6Y2FzZSJQb3NpdGlvbiI6Y2FzZSJTdGF0ZW1lbnQiOmNhc2UiRnVuY3Rpb24iOmNhc2UiUGF0dGVybiI6Y2FzZSJFeHByZXNzaW9uIjpjYXNlIkRlY2xhcmF0aW9uIjpjYXNlIlNwZWNpZmllciI6Y2FzZSJOYW1lZFNwZWNpZmllciI6Y2FzZSJDb21tZW50IjpjYXNlIk1lbWJlclR5cGVBbm5vdGF0aW9uIjpjYXNlIlR5cGUiOnRocm93IG5ldyBFcnJvcigidW5wcmludGFibGUgdHlwZTogIitKU09OLnN0cmluZ2lmeShpLnR5cGUpKTtjYXNlIlR5cGVBbm5vdGF0aW9uIjpjYXNlIlRTVHlwZUFubm90YXRpb24iOnJldHVybiBpLnR5cGVBbm5vdGF0aW9uP2UuY2FsbChuLCJ0eXBlQW5ub3RhdGlvbiIpOiIiO2Nhc2UiVFNUdXBsZVR5cGUiOmNhc2UiVHVwbGVUeXBlQW5ub3RhdGlvbiI6dmFyIEplPSJUU1R1cGxlVHlwZSI9PT1pLnR5cGU/ImVsZW1lbnRUeXBlcyI6InR5cGVzIjtyZXR1cm4gZ3JvdXAkMShjb25jYXQkNChbIlsiLGluZGVudCQyKGNvbmNhdCQ0KFtzb2Z0bGluZSQxLHByaW50QXJyYXlJdGVtcyhlLHQsSmUsbildKSksIlRTVHVwbGVUeXBlIj09PWkudHlwZT8iIjppZkJyZWFrJDEoc2hvdWxkUHJpbnRDb21tYSh0KT8iLCI6IiIpLGNvbW1lbnRzLnByaW50RGFuZ2xpbmdDb21tZW50cyhlLHQsITApLHNvZnRsaW5lJDEsIl0iXSkpO2Nhc2UiRXhpc3RzVHlwZUFubm90YXRpb24iOnJldHVybiIqIjtjYXNlIkVtcHR5VHlwZUFubm90YXRpb24iOnJldHVybiJlbXB0eSI7Y2FzZSJBbnlUeXBlQW5ub3RhdGlvbiI6cmV0dXJuImFueSI7Y2FzZSJNaXhlZFR5cGVBbm5vdGF0aW9uIjpyZXR1cm4ibWl4ZWQiO2Nhc2UiQXJyYXlUeXBlQW5ub3RhdGlvbiI6cmV0dXJuIGNvbmNhdCQ0KFtlLmNhbGwobiwiZWxlbWVudFR5cGUiKSwiW10iXSk7Y2FzZSJCb29sZWFuVHlwZUFubm90YXRpb24iOnJldHVybiJib29sZWFuIjtjYXNlIkJvb2xlYW5MaXRlcmFsVHlwZUFubm90YXRpb24iOnJldHVybiIiK2kudmFsdWU7Y2FzZSJEZWNsYXJlQ2xhc3MiOnJldHVybiBwcmludEZsb3dEZWNsYXJhdGlvbihlLHByaW50Q2xhc3MoZSx0LG4pKTtjYXNlIkRlY2xhcmVGdW5jdGlvbiI6cmV0dXJuIGkucGFyYW1zP2NvbmNhdCQ0KFsiZGVjbGFyZSAiLHByaW50RnVuY3Rpb25EZWNsYXJhdGlvbihlLG4sdCksb10pOnByaW50Rmxvd0RlY2xhcmF0aW9uKGUsWyJmdW5jdGlvbiAiLGUuY2FsbChuLCJpZCIpLGkucHJlZGljYXRlPyIgIjoiIixlLmNhbGwobiwicHJlZGljYXRlIiksb10pO2Nhc2UiRGVjbGFyZU1vZHVsZSI6cmV0dXJuIHByaW50Rmxvd0RlY2xhcmF0aW9uKGUsWyJtb2R1bGUgIixlLmNhbGwobiwiaWQiKSwiICIsZS5jYWxsKG4sImJvZHkiKV0pO2Nhc2UiRGVjbGFyZU1vZHVsZUV4cG9ydHMiOnJldHVybiBwcmludEZsb3dEZWNsYXJhdGlvbihlLFsibW9kdWxlLmV4cG9ydHMiLCI6ICIsZS5jYWxsKG4sInR5cGVBbm5vdGF0aW9uIiksb10pO2Nhc2UiRGVjbGFyZVZhcmlhYmxlIjpyZXR1cm4gcHJpbnRGbG93RGVjbGFyYXRpb24oZSxbInZhciAiLGUuY2FsbChuLCJpZCIpLG9dKTtjYXNlIkRlY2xhcmVFeHBvcnRBbGxEZWNsYXJhdGlvbiI6cmV0dXJuIGNvbmNhdCQ0KFsiZGVjbGFyZSBleHBvcnQgKiBmcm9tICIsZS5jYWxsKG4sInNvdXJjZSIpXSk7Y2FzZSJEZWNsYXJlRXhwb3J0RGVjbGFyYXRpb24iOnJldHVybiBjb25jYXQkNChbImRlY2xhcmUgIixwcmludEV4cG9ydERlY2xhcmF0aW9uKGUsdCxuKV0pO2Nhc2UiRGVjbGFyZU9wYXF1ZVR5cGUiOmNhc2UiT3BhcXVlVHlwZSI6cmV0dXJuIGEucHVzaCgib3BhcXVlIHR5cGUgIixlLmNhbGwobiwiaWQiKSxlLmNhbGwobiwidHlwZVBhcmFtZXRlcnMiKSksaS5zdXBlcnR5cGUmJmEucHVzaCgiOiAiLGUuY2FsbChuLCJzdXBlcnR5cGUiKSksaS5pbXBsdHlwZSYmYS5wdXNoKCIgPSAiLGUuY2FsbChuLCJpbXBsdHlwZSIpKSxhLnB1c2gobyksIkRlY2xhcmVPcGFxdWVUeXBlIj09PWkudHlwZT9wcmludEZsb3dEZWNsYXJhdGlvbihlLGEpOmNvbmNhdCQ0KGEpO2Nhc2UiRnVuY3Rpb25UeXBlQW5ub3RhdGlvbiI6Y2FzZSJUU0Z1bmN0aW9uVHlwZSI6dmFyIFllPWUuZ2V0UGFyZW50Tm9kZSgwKSxYZT1lLmdldFBhcmVudE5vZGUoMSksWmU9ZS5nZXRQYXJlbnROb2RlKDIpLGV0PSJUU0Z1bmN0aW9uVHlwZSI9PT1pLnR5cGV8fCEoIk9iamVjdFR5cGVQcm9wZXJ0eSI9PT1ZZS50eXBlJiYhZ2V0Rmxvd1ZhcmlhbmNlKFllKSYmIVllLm9wdGlvbmFsJiZ0LmxvY1N0YXJ0KFllKT09PXQubG9jU3RhcnQoaSl8fCJPYmplY3RUeXBlQ2FsbFByb3BlcnR5Ij09PVllLnR5cGV8fFplJiYiRGVjbGFyZUZ1bmN0aW9uIj09PVplLnR5cGUpLHR0PWV0JiYoIlR5cGVBbm5vdGF0aW9uIj09PVllLnR5cGV8fCJUU1R5cGVBbm5vdGF0aW9uIj09PVllLnR5cGUpLG50PXR0JiZldCYmKCJUeXBlQW5ub3RhdGlvbiI9PT1ZZS50eXBlfHwiVFNUeXBlQW5ub3RhdGlvbiI9PT1ZZS50eXBlKSYmIkFycm93RnVuY3Rpb25FeHByZXNzaW9uIj09PVhlLnR5cGU7cmV0dXJuIGlzT2JqZWN0VHlwZVByb3BlcnR5QUZ1bmN0aW9uKFllLHQpJiYoZXQ9ITAsdHQ9ITApLG50JiZhLnB1c2goIigiKSxhLnB1c2gocHJpbnRGdW5jdGlvblBhcmFtcyhlLG4sdCwhMSwhMCkpLChpLnJldHVyblR5cGV8fGkucHJlZGljYXRlfHxpLnR5cGVBbm5vdGF0aW9uKSYmYS5wdXNoKGV0PyIgPT4gIjoiOiAiLGUuY2FsbChuLCJyZXR1cm5UeXBlIiksZS5jYWxsKG4sInByZWRpY2F0ZSIpLGUuY2FsbChuLCJ0eXBlQW5ub3RhdGlvbiIpKSxudCYmYS5wdXNoKCIpIiksZ3JvdXAkMShjb25jYXQkNChhKSk7Y2FzZSJGdW5jdGlvblR5cGVQYXJhbSI6cmV0dXJuIGNvbmNhdCQ0KFtlLmNhbGwobiwibmFtZSIpLHByaW50T3B0aW9uYWxUb2tlbihlKSxpLm5hbWU/IjogIjoiIixlLmNhbGwobiwidHlwZUFubm90YXRpb24iKV0pO2Nhc2UiR2VuZXJpY1R5cGVBbm5vdGF0aW9uIjpyZXR1cm4gY29uY2F0JDQoW2UuY2FsbChuLCJpZCIpLGUuY2FsbChuLCJ0eXBlUGFyYW1ldGVycyIpXSk7Y2FzZSJEZWNsYXJlSW50ZXJmYWNlIjpjYXNlIkludGVyZmFjZURlY2xhcmF0aW9uIjpjYXNlIkludGVyZmFjZVR5cGUiOmNhc2UiSW50ZXJmYWNlVHlwZUFubm90YXRpb24iOnJldHVybigiRGVjbGFyZUludGVyZmFjZSI9PT1pLnR5cGV8fGlzTm9kZVN0YXJ0aW5nV2l0aERlY2xhcmUoaSx0KSkmJmEucHVzaCgiZGVjbGFyZSAiKSxhLnB1c2goImludGVyZmFjZSIpLCJEZWNsYXJlSW50ZXJmYWNlIiE9PWkudHlwZSYmIkludGVyZmFjZURlY2xhcmF0aW9uIiE9PWkudHlwZXx8YS5wdXNoKCIgIixlLmNhbGwobiwiaWQiKSxlLmNhbGwobiwidHlwZVBhcmFtZXRlcnMiKSksaS5leHRlbmRzLmxlbmd0aD4wJiZhLnB1c2goZ3JvdXAkMShpbmRlbnQkMihjb25jYXQkNChbbGluZSQzLCJleHRlbmRzICIsam9pbiQyKCIsICIsZS5tYXAobiwiZXh0ZW5kcyIpKV0pKSkpLGEucHVzaCgiICIsZS5jYWxsKG4sImJvZHkiKSksZ3JvdXAkMShjb25jYXQkNChhKSk7Y2FzZSJDbGFzc0ltcGxlbWVudHMiOmNhc2UiSW50ZXJmYWNlRXh0ZW5kcyI6cmV0dXJuIGNvbmNhdCQ0KFtlLmNhbGwobiwiaWQiKSxlLmNhbGwobiwidHlwZVBhcmFtZXRlcnMiKV0pO2Nhc2UiVFNJbnRlcnNlY3Rpb25UeXBlIjpjYXNlIkludGVyc2VjdGlvblR5cGVBbm5vdGF0aW9uIjpmb3IodmFyIHJ0PWUubWFwKG4sInR5cGVzIiksaXQ9W10sb3Q9ITEsYXQ9MDthdDxydC5sZW5ndGg7KythdCkwPT09YXQ/aXQucHVzaChydFthdF0pOmlzT2JqZWN0VHlwZShpLnR5cGVzW2F0LTFdKSYmaXNPYmplY3RUeXBlKGkudHlwZXNbYXRdKT9pdC5wdXNoKGNvbmNhdCQ0KFsiICYgIixvdD9pbmRlbnQkMihydFthdF0pOnJ0W2F0XV0pKTppc09iamVjdFR5cGUoaS50eXBlc1thdC0xXSl8fGlzT2JqZWN0VHlwZShpLnR5cGVzW2F0XSk/KGF0PjEmJihvdD0hMCksaXQucHVzaCgiICYgIixhdD4xP2luZGVudCQyKHJ0W2F0XSk6cnRbYXRdKSk6aXQucHVzaChpbmRlbnQkMihjb25jYXQkNChbIiAmIixsaW5lJDMscnRbYXRdXSkpKTtyZXR1cm4gZ3JvdXAkMShjb25jYXQkNChpdCkpO2Nhc2UiVFNVbmlvblR5cGUiOmNhc2UiVW5pb25UeXBlQW5ub3RhdGlvbiI6dmFyIHN0PWUuZ2V0UGFyZW50Tm9kZSgpLHV0PWUuZ2V0UGFyZW50Tm9kZSgxKSxjdD0iVHlwZVBhcmFtZXRlckluc3RhbnRpYXRpb24iIT09c3QudHlwZSYmIlRTVHlwZVBhcmFtZXRlckluc3RhbnRpYXRpb24iIT09c3QudHlwZSYmIkdlbmVyaWNUeXBlQW5ub3RhdGlvbiIhPT1zdC50eXBlJiYiVFNUeXBlUmVmZXJlbmNlIiE9PXN0LnR5cGUmJiEoIkZ1bmN0aW9uVHlwZVBhcmFtIj09PXN0LnR5cGUmJiFzdC5uYW1lKSYmIlRTVHlwZUFzc2VydGlvbkV4cHJlc3Npb24iIT09dXQudHlwZSYmISgoIlR5cGVBbGlhcyI9PT1zdC50eXBlfHwiVmFyaWFibGVEZWNsYXJhdG9yIj09PXN0LnR5cGUpJiZoYXNMZWFkaW5nT3duTGluZUNvbW1lbnQodC5vcmlnaW5hbFRleHQsaSx0KSksbHQ9c2hvdWxkSHVnVHlwZShpKSxwdD1lLm1hcChmdW5jdGlvbihlKXt2YXIgcj1lLmNhbGwobik7cmV0dXJuIGx0fHwocj1hbGlnbiQxKDIscikpLGNvbW1lbnRzLnByaW50Q29tbWVudHMoZSxmdW5jdGlvbigpe3JldHVybiByfSx0KX0sInR5cGVzIik7aWYobHQpcmV0dXJuIGpvaW4kMigiIHwgIixwdCk7dmFyIGZ0LGR0PWNvbmNhdCQ0KFtpZkJyZWFrJDEoY29uY2F0JDQoW2N0P2xpbmUkMzoiIiwifCAiXSkpLGpvaW4kMihjb25jYXQkNChbbGluZSQzLCJ8ICJdKSxwdCldKTtpZigiVFNVbmlvblR5cGUiPT09aS50eXBlKXt2YXIgaHQ9ZS5nZXRQYXJlbnROb2RlKDIpLG10PWUuZ2V0UGFyZW50Tm9kZSgzKTtmdD1odCYmIlRTUGFyZW50aGVzaXplZFR5cGUiPT09aHQudHlwZSYmbXQmJigiVFNVbmlvblR5cGUiPT09bXQudHlwZXx8IlRTSW50ZXJzZWN0aW9uVHlwZSI9PT1tdC50eXBlKX1lbHNlIGZ0PW5lZWRzUGFyZW5zXzEoZSx0KTtyZXR1cm4gZ3JvdXAkMShmdD9jb25jYXQkNChbaW5kZW50JDIoZHQpLHNvZnRsaW5lJDFdKTpjdD9pbmRlbnQkMihkdCk6ZHQpO2Nhc2UiTnVsbGFibGVUeXBlQW5ub3RhdGlvbiI6cmV0dXJuIGNvbmNhdCQ0KFsiPyIsZS5jYWxsKG4sInR5cGVBbm5vdGF0aW9uIildKTtjYXNlIlRTTnVsbEtleXdvcmQiOmNhc2UiTnVsbExpdGVyYWxUeXBlQW5ub3RhdGlvbiI6cmV0dXJuIm51bGwiO2Nhc2UiVGhpc1R5cGVBbm5vdGF0aW9uIjpyZXR1cm4idGhpcyI7Y2FzZSJOdW1iZXJUeXBlQW5ub3RhdGlvbiI6cmV0dXJuIm51bWJlciI7Y2FzZSJPYmplY3RUeXBlQ2FsbFByb3BlcnR5IjpyZXR1cm4gaS5zdGF0aWMmJmEucHVzaCgic3RhdGljICIpLGEucHVzaChlLmNhbGwobiwidmFsdWUiKSksY29uY2F0JDQoYSk7Y2FzZSJPYmplY3RUeXBlSW5kZXhlciI6dmFyIGd0PWdldEZsb3dWYXJpYW5jZShpKTtyZXR1cm4gY29uY2F0JDQoW2d0fHwiIiwiWyIsZS5jYWxsKG4sImlkIiksaS5pZD8iOiAiOiIiLGUuY2FsbChuLCJrZXkiKSwiXTogIixlLmNhbGwobiwidmFsdWUiKV0pO2Nhc2UiT2JqZWN0VHlwZVByb3BlcnR5Ijp2YXIgeXQ9Z2V0Rmxvd1ZhcmlhbmNlKGkpLHZ0PSIiO3JldHVybiBpLnByb3RvP3Z0PSJwcm90byAiOmkuc3RhdGljJiYodnQ9InN0YXRpYyAiKSxjb25jYXQkNChbdnQsaXNHZXR0ZXJPclNldHRlcihpKT9pLmtpbmQrIiAiOiIiLHl0fHwiIixwcmludFByb3BlcnR5S2V5KGUsdCxuKSxwcmludE9wdGlvbmFsVG9rZW4oZSksaXNGdW5jdGlvbk5vdGF0aW9uKGksdCk/IiI6IjogIixlLmNhbGwobiwidmFsdWUiKV0pO2Nhc2UiUXVhbGlmaWVkVHlwZUlkZW50aWZpZXIiOnJldHVybiBjb25jYXQkNChbZS5jYWxsKG4sInF1YWxpZmljYXRpb24iKSwiLiIsZS5jYWxsKG4sImlkIildKTtjYXNlIlN0cmluZ0xpdGVyYWxUeXBlQW5ub3RhdGlvbiI6cmV0dXJuIG5vZGVTdHIoaSx0KTtjYXNlIk51bWJlckxpdGVyYWxUeXBlQW5ub3RhdGlvbiI6cmV0dXJuIGFzc2VydC5zdHJpY3RFcXVhbChfdHlwZW9mKGkudmFsdWUpLCJudW1iZXIiKSxwcmludE51bWJlciQxKG51bGwhPWkuZXh0cmE/aS5leHRyYS5yYXc6aS5yYXcpO2Nhc2UiU3RyaW5nVHlwZUFubm90YXRpb24iOnJldHVybiJzdHJpbmciO2Nhc2UiRGVjbGFyZVR5cGVBbGlhcyI6Y2FzZSJUeXBlQWxpYXMiOigiRGVjbGFyZVR5cGVBbGlhcyI9PT1pLnR5cGV8fGlzTm9kZVN0YXJ0aW5nV2l0aERlY2xhcmUoaSx0KSkmJmEucHVzaCgiZGVjbGFyZSAiKTt2YXIgYnQ9cHJpbnRBc3NpZ25tZW50UmlnaHQoaS5pZCxpLnJpZ2h0LGUuY2FsbChuLCJyaWdodCIpLHQpO3JldHVybiBhLnB1c2goInR5cGUgIixlLmNhbGwobiwiaWQiKSxlLmNhbGwobiwidHlwZVBhcmFtZXRlcnMiKSwiID0iLGJ0LG8pLGdyb3VwJDEoY29uY2F0JDQoYSkpO2Nhc2UiVHlwZUNhc3RFeHByZXNzaW9uIjpyZXR1cm4gY29uY2F0JDQoWyIoIixlLmNhbGwobiwiZXhwcmVzc2lvbiIpLCI6ICIsZS5jYWxsKG4sInR5cGVBbm5vdGF0aW9uIiksIikiXSk7Y2FzZSJUeXBlUGFyYW1ldGVyRGVjbGFyYXRpb24iOmNhc2UiVHlwZVBhcmFtZXRlckluc3RhbnRpYXRpb24iOmNhc2UiVFNUeXBlUGFyYW1ldGVyRGVjbGFyYXRpb24iOmNhc2UiVFNUeXBlUGFyYW1ldGVySW5zdGFudGlhdGlvbiI6cmV0dXJuIHByaW50VHlwZVBhcmFtZXRlcnMoZSx0LG4sInBhcmFtcyIpO2Nhc2UiVFNUeXBlUGFyYW1ldGVyIjpjYXNlIlR5cGVQYXJhbWV0ZXIiOmlmKCJUU01hcHBlZFR5cGUiPT09ZS5nZXRQYXJlbnROb2RlKCkudHlwZSlyZXR1cm4gYS5wdXNoKCJbIixlLmNhbGwobiwibmFtZSIpKSxpLmNvbnN0cmFpbnQmJmEucHVzaCgiIGluICIsZS5jYWxsKG4sImNvbnN0cmFpbnQiKSksYS5wdXNoKCJdIiksY29uY2F0JDQoYSk7dmFyIHh0PWdldEZsb3dWYXJpYW5jZShpKTtyZXR1cm4geHQmJmEucHVzaCh4dCksYS5wdXNoKGUuY2FsbChuLCJuYW1lIikpLGkuYm91bmQmJihhLnB1c2goIjogIiksYS5wdXNoKGUuY2FsbChuLCJib3VuZCIpKSksaS5jb25zdHJhaW50JiZhLnB1c2goIiBleHRlbmRzICIsZS5jYWxsKG4sImNvbnN0cmFpbnQiKSksaS5kZWZhdWx0JiZhLnB1c2goIiA9ICIsZS5jYWxsKG4sImRlZmF1bHQiKSksY29uY2F0JDQoYSk7Y2FzZSJUeXBlb2ZUeXBlQW5ub3RhdGlvbiI6cmV0dXJuIGNvbmNhdCQ0KFsidHlwZW9mICIsZS5jYWxsKG4sImFyZ3VtZW50IildKTtjYXNlIlZvaWRUeXBlQW5ub3RhdGlvbiI6cmV0dXJuInZvaWQiO2Nhc2UiSW5mZXJyZWRQcmVkaWNhdGUiOnJldHVybiIlY2hlY2tzIjtjYXNlIkRlY2xhcmVkUHJlZGljYXRlIjpyZXR1cm4gY29uY2F0JDQoWyIlY2hlY2tzKCIsZS5jYWxsKG4sInZhbHVlIiksIikiXSk7Y2FzZSJUU0Fic3RyYWN0S2V5d29yZCI6cmV0dXJuImFic3RyYWN0IjtjYXNlIlRTQW55S2V5d29yZCI6cmV0dXJuImFueSI7Y2FzZSJUU0FzeW5jS2V5d29yZCI6cmV0dXJuImFzeW5jIjtjYXNlIlRTQm9vbGVhbktleXdvcmQiOnJldHVybiJib29sZWFuIjtjYXNlIlRTQ29uc3RLZXl3b3JkIjpyZXR1cm4iY29uc3QiO2Nhc2UiVFNEZWNsYXJlS2V5d29yZCI6cmV0dXJuImRlY2xhcmUiO2Nhc2UiVFNFeHBvcnRLZXl3b3JkIjpyZXR1cm4iZXhwb3J0IjtjYXNlIlRTTmV2ZXJLZXl3b3JkIjpyZXR1cm4ibmV2ZXIiO2Nhc2UiVFNOdW1iZXJLZXl3b3JkIjpyZXR1cm4ibnVtYmVyIjtjYXNlIlRTT2JqZWN0S2V5d29yZCI6cmV0dXJuIm9iamVjdCI7Y2FzZSJUU1Byb3RlY3RlZEtleXdvcmQiOnJldHVybiJwcm90ZWN0ZWQiO2Nhc2UiVFNQcml2YXRlS2V5d29yZCI6cmV0dXJuInByaXZhdGUiO2Nhc2UiVFNQdWJsaWNLZXl3b3JkIjpyZXR1cm4icHVibGljIjtjYXNlIlRTUmVhZG9ubHlLZXl3b3JkIjpyZXR1cm4icmVhZG9ubHkiO2Nhc2UiVFNTeW1ib2xLZXl3b3JkIjpyZXR1cm4ic3ltYm9sIjtjYXNlIlRTU3RhdGljS2V5d29yZCI6cmV0dXJuInN0YXRpYyI7Y2FzZSJUU1N0cmluZ0tleXdvcmQiOnJldHVybiJzdHJpbmciO2Nhc2UiVFNVbmRlZmluZWRLZXl3b3JkIjpyZXR1cm4idW5kZWZpbmVkIjtjYXNlIlRTVm9pZEtleXdvcmQiOnJldHVybiJ2b2lkIjtjYXNlIlRTQXNFeHByZXNzaW9uIjpyZXR1cm4gY29uY2F0JDQoW2UuY2FsbChuLCJleHByZXNzaW9uIiksIiBhcyAiLGUuY2FsbChuLCJ0eXBlQW5ub3RhdGlvbiIpXSk7Y2FzZSJUU0FycmF5VHlwZSI6cmV0dXJuIGNvbmNhdCQ0KFtlLmNhbGwobiwiZWxlbWVudFR5cGUiKSwiW10iXSk7Y2FzZSJUU1Byb3BlcnR5U2lnbmF0dXJlIjpyZXR1cm4gaS5leHBvcnQmJmEucHVzaCgiZXhwb3J0ICIpLGkuYWNjZXNzaWJpbGl0eSYmYS5wdXNoKGkuYWNjZXNzaWJpbGl0eSsiICIpLGkuc3RhdGljJiZhLnB1c2goInN0YXRpYyAiKSxpLnJlYWRvbmx5JiZhLnB1c2goInJlYWRvbmx5ICIpLGkuY29tcHV0ZWQmJmEucHVzaCgiWyIpLGEucHVzaChwcmludFByb3BlcnR5S2V5KGUsdCxuKSksaS5jb21wdXRlZCYmYS5wdXNoKCJdIiksYS5wdXNoKHByaW50T3B0aW9uYWxUb2tlbihlKSksaS50eXBlQW5ub3RhdGlvbiYmKGEucHVzaCgiOiAiKSxhLnB1c2goZS5jYWxsKG4sInR5cGVBbm5vdGF0aW9uIikpKSxpLmluaXRpYWxpemVyJiZhLnB1c2goIiA9ICIsZS5jYWxsKG4sImluaXRpYWxpemVyIikpLGNvbmNhdCQ0KGEpO2Nhc2UiVFNQYXJhbWV0ZXJQcm9wZXJ0eSI6cmV0dXJuIGkuYWNjZXNzaWJpbGl0eSYmYS5wdXNoKGkuYWNjZXNzaWJpbGl0eSsiICIpLGkuZXhwb3J0JiZhLnB1c2goImV4cG9ydCAiKSxpLnN0YXRpYyYmYS5wdXNoKCJzdGF0aWMgIiksaS5yZWFkb25seSYmYS5wdXNoKCJyZWFkb25seSAiKSxhLnB1c2goZS5jYWxsKG4sInBhcmFtZXRlciIpKSxjb25jYXQkNChhKTtjYXNlIlRTVHlwZVJlZmVyZW5jZSI6cmV0dXJuIGNvbmNhdCQ0KFtlLmNhbGwobiwidHlwZU5hbWUiKSxwcmludFR5cGVQYXJhbWV0ZXJzKGUsdCxuLCJ0eXBlUGFyYW1ldGVycyIpXSk7Y2FzZSJUU1R5cGVRdWVyeSI6cmV0dXJuIGNvbmNhdCQ0KFsidHlwZW9mICIsZS5jYWxsKG4sImV4cHJOYW1lIildKTtjYXNlIlRTUGFyZW50aGVzaXplZFR5cGUiOnJldHVybiBlLmNhbGwobiwidHlwZUFubm90YXRpb24iKTtjYXNlIlRTSW5kZXhTaWduYXR1cmUiOnZhciBDdD1lLmdldFBhcmVudE5vZGUoKTtyZXR1cm4gY29uY2F0JDQoW2kuZXhwb3J0PyJleHBvcnQgIjoiIixpLmFjY2Vzc2liaWxpdHk/Y29uY2F0JDQoW2kuYWNjZXNzaWJpbGl0eSwiICJdKToiIixpLnN0YXRpYz8ic3RhdGljICI6IiIsaS5yZWFkb25seT8icmVhZG9ubHkgIjoiIiwiWyIsZS5jYWxsKG4sImluZGV4IiksIl06ICIsZS5jYWxsKG4sInR5cGVBbm5vdGF0aW9uIiksIkNsYXNzQm9keSI9PT1DdC50eXBlP286IiJdKTtjYXNlIlRTVHlwZVByZWRpY2F0ZSI6cmV0dXJuIGNvbmNhdCQ0KFtlLmNhbGwobiwicGFyYW1ldGVyTmFtZSIpLCIgaXMgIixlLmNhbGwobiwidHlwZUFubm90YXRpb24iKV0pO2Nhc2UiVFNOb25OdWxsRXhwcmVzc2lvbiI6cmV0dXJuIGNvbmNhdCQ0KFtlLmNhbGwobiwiZXhwcmVzc2lvbiIpLCIhIl0pO2Nhc2UiVFNUaGlzVHlwZSI6cmV0dXJuInRoaXMiO2Nhc2UiVFNMYXN0VHlwZU5vZGUiOnJldHVybiBjb25jYXQkNChbaS5pc1R5cGVPZj8idHlwZW9mICI6IiIsImltcG9ydCgiLGUuY2FsbChuLCJhcmd1bWVudCIpLCIpIixpLnF1YWxpZmllcj9jb25jYXQkNChbIi4iLGUuY2FsbChuLCJxdWFsaWZpZXIiKV0pOiIiXSk7Y2FzZSJUU0xpdGVyYWxUeXBlIjpyZXR1cm4gZS5jYWxsKG4sImxpdGVyYWwiKTtjYXNlIlRTSW5kZXhlZEFjY2Vzc1R5cGUiOnJldHVybiBjb25jYXQkNChbZS5jYWxsKG4sIm9iamVjdFR5cGUiKSwiWyIsZS5jYWxsKG4sImluZGV4VHlwZSIpLCJdIl0pO2Nhc2UiVFNDb25zdHJ1Y3RTaWduYXR1cmUiOmNhc2UiVFNDb25zdHJ1Y3RvclR5cGUiOmNhc2UiVFNDYWxsU2lnbmF0dXJlIjppZigiVFNDYWxsU2lnbmF0dXJlIiE9PWkudHlwZSYmYS5wdXNoKCJuZXcgIiksYS5wdXNoKGdyb3VwJDEocHJpbnRGdW5jdGlvblBhcmFtcyhlLG4sdCwhMSwhMCkpKSxpLnR5cGVBbm5vdGF0aW9uKXt2YXIgRXQ9IlRTQ29uc3RydWN0b3JUeXBlIj09PWkudHlwZTthLnB1c2goRXQ/IiA9PiAiOiI6ICIsZS5jYWxsKG4sInR5cGVBbm5vdGF0aW9uIikpfXJldHVybiBjb25jYXQkNChhKTtjYXNlIlRTVHlwZU9wZXJhdG9yIjpyZXR1cm4gY29uY2F0JDQoW2kub3BlcmF0b3IsIiAiLGUuY2FsbChuLCJ0eXBlQW5ub3RhdGlvbiIpXSk7Y2FzZSJUU01hcHBlZFR5cGUiOnJldHVybiBncm91cCQxKGNvbmNhdCQ0KFsieyIsaW5kZW50JDIoY29uY2F0JDQoW3QuYnJhY2tldFNwYWNpbmc/bGluZSQzOnNvZnRsaW5lJDEsaS5yZWFkb25seVRva2VuP2NvbmNhdCQ0KFtnZXRUeXBlU2NyaXB0TWFwcGVkVHlwZU1vZGlmaWVyKGkucmVhZG9ubHlUb2tlbiwicmVhZG9ubHkiKSwiICJdKToiIixwcmludFR5cGVTY3JpcHRNb2RpZmllcnMoZSx0LG4pLGUuY2FsbChuLCJ0eXBlUGFyYW1ldGVyIiksaS5xdWVzdGlvblRva2VuP2dldFR5cGVTY3JpcHRNYXBwZWRUeXBlTW9kaWZpZXIoaS5xdWVzdGlvblRva2VuLCI/Iik6IiIsIjogIixlLmNhbGwobiwidHlwZUFubm90YXRpb24iKV0pKSxjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0LCEwKSx0LmJyYWNrZXRTcGFjaW5nP2xpbmUkMzpzb2Z0bGluZSQxLCJ9Il0pKTtjYXNlIlRTTWV0aG9kU2lnbmF0dXJlIjpyZXR1cm4gYS5wdXNoKGkuYWNjZXNzaWJpbGl0eT9jb25jYXQkNChbaS5hY2Nlc3NpYmlsaXR5LCIgIl0pOiIiLGkuZXhwb3J0PyJleHBvcnQgIjoiIixpLnN0YXRpYz8ic3RhdGljICI6IiIsaS5yZWFkb25seT8icmVhZG9ubHkgIjoiIixpLmNvbXB1dGVkPyJbIjoiIixlLmNhbGwobiwia2V5IiksaS5jb21wdXRlZD8iXSI6IiIscHJpbnRPcHRpb25hbFRva2VuKGUpLHByaW50RnVuY3Rpb25QYXJhbXMoZSxuLHQsITEsITApKSxpLnR5cGVBbm5vdGF0aW9uJiZhLnB1c2goIjogIixlLmNhbGwobiwidHlwZUFubm90YXRpb24iKSksZ3JvdXAkMShjb25jYXQkNChhKSk7Y2FzZSJUU05hbWVzcGFjZUV4cG9ydERlY2xhcmF0aW9uIjpyZXR1cm4gYS5wdXNoKCJleHBvcnQgYXMgbmFtZXNwYWNlICIsZS5jYWxsKG4sIm5hbWUiKSksdC5zZW1pJiZhLnB1c2goIjsiKSxncm91cCQxKGNvbmNhdCQ0KGEpKTtjYXNlIlRTRW51bURlY2xhcmF0aW9uIjpyZXR1cm4gaXNOb2RlU3RhcnRpbmdXaXRoRGVjbGFyZShpLHQpJiZhLnB1c2goImRlY2xhcmUgIiksaS5tb2RpZmllcnMmJmEucHVzaChwcmludFR5cGVTY3JpcHRNb2RpZmllcnMoZSx0LG4pKSxpLmNvbnN0JiZhLnB1c2goImNvbnN0ICIpLGEucHVzaCgiZW51bSAiLGUuY2FsbChuLCJpZCIpLCIgIiksMD09PWkubWVtYmVycy5sZW5ndGg/YS5wdXNoKGdyb3VwJDEoY29uY2F0JDQoWyJ7Iixjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0KSxzb2Z0bGluZSQxLCJ9Il0pKSk6YS5wdXNoKGdyb3VwJDEoY29uY2F0JDQoWyJ7IixpbmRlbnQkMihjb25jYXQkNChbaGFyZGxpbmUkMyxwcmludEFycmF5SXRlbXMoZSx0LCJtZW1iZXJzIixuKSxzaG91bGRQcmludENvbW1hKHQsImVzNSIpPyIsIjoiIl0pKSxjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0LCEwKSxoYXJkbGluZSQzLCJ9Il0pKSksY29uY2F0JDQoYSk7Y2FzZSJUU0VudW1NZW1iZXIiOnJldHVybiBhLnB1c2goZS5jYWxsKG4sImlkIikpLGkuaW5pdGlhbGl6ZXImJmEucHVzaCgiID0gIixlLmNhbGwobiwiaW5pdGlhbGl6ZXIiKSksY29uY2F0JDQoYSk7Y2FzZSJUU0ltcG9ydEVxdWFsc0RlY2xhcmF0aW9uIjpyZXR1cm4gYS5wdXNoKHByaW50VHlwZVNjcmlwdE1vZGlmaWVycyhlLHQsbiksImltcG9ydCAiLGUuY2FsbChuLCJuYW1lIiksIiA9ICIsZS5jYWxsKG4sIm1vZHVsZVJlZmVyZW5jZSIpKSx0LnNlbWkmJmEucHVzaCgiOyIpLGdyb3VwJDEoY29uY2F0JDQoYSkpO2Nhc2UiVFNFeHRlcm5hbE1vZHVsZVJlZmVyZW5jZSI6cmV0dXJuIGNvbmNhdCQ0KFsicmVxdWlyZSgiLGUuY2FsbChuLCJleHByZXNzaW9uIiksIikiXSk7Y2FzZSJUU01vZHVsZURlY2xhcmF0aW9uIjp2YXIgRHQ9ZS5nZXRQYXJlbnROb2RlKCksd3Q9aXNMaXRlcmFsKGkuaWQpLFN0PSJUU01vZHVsZURlY2xhcmF0aW9uIj09PUR0LnR5cGUsa3Q9aS5ib2R5JiYiVFNNb2R1bGVEZWNsYXJhdGlvbiI9PT1pLmJvZHkudHlwZTtpZihTdClhLnB1c2goIi4iKTtlbHNleyEwPT09aS5kZWNsYXJlJiZhLnB1c2goImRlY2xhcmUgIiksYS5wdXNoKHByaW50VHlwZVNjcmlwdE1vZGlmaWVycyhlLHQsbikpOyJJZGVudGlmaWVyIj09PWkuaWQudHlwZSYmImdsb2JhbCI9PT1pLmlkLm5hbWUmJiEvbmFtZXNwYWNlfG1vZHVsZS8udGVzdCh0Lm9yaWdpbmFsVGV4dC5zbGljZSh0LmxvY1N0YXJ0KGkpLHQubG9jU3RhcnQoaS5pZCkpKXx8YS5wdXNoKHd0PyJtb2R1bGUgIjoibmFtZXNwYWNlICIpfXJldHVybiBhLnB1c2goZS5jYWxsKG4sImlkIikpLGt0P2EucHVzaChlLmNhbGwobiwiYm9keSIpKTppLmJvZHk/YS5wdXNoKCIgeyIsaW5kZW50JDIoY29uY2F0JDQoW2xpbmUkMyxlLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIGNvbW1lbnRzLnByaW50RGFuZ2xpbmdDb21tZW50cyhlLHQsITApfSwiYm9keSIpLGdyb3VwJDEoZS5jYWxsKG4sImJvZHkiKSldKSksbGluZSQzLCJ9Iik6YS5wdXNoKG8pLGNvbmNhdCQ0KGEpO2Nhc2UiVFNNb2R1bGVCbG9jayI6cmV0dXJuIGUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gcHJpbnRTdGF0ZW1lbnRTZXF1ZW5jZShlLHQsbil9LCJib2R5Iik7Y2FzZSJQcml2YXRlTmFtZSI6cmV0dXJuIGNvbmNhdCQ0KFsiIyIsZS5jYWxsKG4sImlkIildKTtjYXNlIlRTQ29uZGl0aW9uYWxUeXBlIjpyZXR1cm4gZm9ybWF0VGVybmFyeU9wZXJhdG9yKGUsdCxuLHtiZWZvcmVQYXJ0czpmdW5jdGlvbigpe3JldHVybltlLmNhbGwobiwiY2hlY2tUeXBlIiksIiAiLCJleHRlbmRzIiwiICIsZS5jYWxsKG4sImV4dGVuZHNUeXBlIildfSxzaG91bGRDaGVja0pzeDohMSxvcGVyYXRvck5hbWU6IlRTQ29uZGl0aW9uYWxUeXBlIixjb25zZXF1ZW50Tm9kZToidHJ1ZVR5cGUiLGFsdGVybmF0ZU5vZGU6ImZhbHNlVHlwZSIsdGVzdE5vZGU6ImNoZWNrVHlwZSIsYnJlYWtOZXN0ZWQ6ITF9KTtjYXNlIlRTSW5mZXJUeXBlIjpyZXR1cm4gY29uY2F0JDQoWyJpbmZlciIsIiAiLGUuY2FsbChuLCJ0eXBlUGFyYW1ldGVyIildKTtjYXNlIkludGVycHJldGVyRGlyZWN0aXZlIjpyZXR1cm4gYS5wdXNoKCIjISIsaS52YWx1ZSxoYXJkbGluZSQzKSxpc05leHRMaW5lRW1wdHkkMih0Lm9yaWdpbmFsVGV4dCxpLHQpJiZhLnB1c2goaGFyZGxpbmUkMyksY29uY2F0JDQoYSk7ZGVmYXVsdDp0aHJvdyBuZXcgRXJyb3IoInVua25vd24gdHlwZTogIitKU09OLnN0cmluZ2lmeShpLnR5cGUpKX19ZnVuY3Rpb24gcHJpbnRTdGF0ZW1lbnRTZXF1ZW5jZShlLHQsbil7dmFyIHI9W10saT1lLmdldE5vZGUoKSxvPSJDbGFzc0JvZHkiPT09aS50eXBlO3JldHVybiBlLm1hcChmdW5jdGlvbihlLGEpe3ZhciBzPWUuZ2V0VmFsdWUoKTtpZihzJiYiRW1wdHlTdGF0ZW1lbnQiIT09cy50eXBlKXt2YXIgdT1uKGUpLGM9dC5vcmlnaW5hbFRleHQsbD1bXTtpZih0LnNlbWl8fG98fGlzVGhlT25seUpTWEVsZW1lbnRJbk1hcmtkb3duKHQsZSl8fCFzdG10TmVlZHNBU0lQcm90ZWN0aW9uKGUsdCk/bC5wdXNoKHUpOnMuY29tbWVudHMmJnMuY29tbWVudHMuc29tZShmdW5jdGlvbihlKXtyZXR1cm4gZS5sZWFkaW5nfSk/bC5wdXNoKG4oZSx7bmVlZHNTZW1pOiEwfSkpOmwucHVzaCgiOyIsdSksIXQuc2VtaSYmbylpZihjbGFzc1Byb3BNYXlDYXVzZUFTSVByb2JsZW1zKGUpKWwucHVzaCgiOyIpO2Vsc2UgaWYoIkNsYXNzUHJvcGVydHkiPT09cy50eXBlKXt2YXIgcD1pLmJvZHlbYSsxXTtjbGFzc0NoaWxkTmVlZHNBU0lQcm90ZWN0aW9uKHApJiZsLnB1c2goIjsiKX1pc05leHRMaW5lRW1wdHkkMihjLHMsdCkmJiFpc0xhc3RTdGF0ZW1lbnQoZSkmJmwucHVzaChoYXJkbGluZSQzKSxyLnB1c2goY29uY2F0JDQobCkpfX0pLGpvaW4kMihoYXJkbGluZSQzLHIpfWZ1bmN0aW9uIHByaW50UHJvcGVydHlLZXkoZSx0LG4pe3ZhciByPWUuZ2V0Tm9kZSgpLGk9ci5rZXk7cmV0dXJuIklkZW50aWZpZXIiIT09aS50eXBlfHxyLmNvbXB1dGVkfHwianNvbiIhPT10LnBhcnNlcj8haXNTdHJpbmdMaXRlcmFsKGkpfHwhaXNJZGVudGlmaWVyTmFtZShpLnZhbHVlKXx8ci5jb21wdXRlZHx8Impzb24iPT09dC5wYXJzZXJ8fCJ0eXBlc2NyaXB0Ij09PXQucGFyc2VyJiYiQ2xhc3NQcm9wZXJ0eSI9PT1yLnR5cGU/ZS5jYWxsKG4sImtleSIpOmUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gY29tbWVudHMucHJpbnRDb21tZW50cyhlLGZ1bmN0aW9uKCl7cmV0dXJuIGkudmFsdWV9LHQpfSwia2V5Iik6ZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBjb21tZW50cy5wcmludENvbW1lbnRzKGUsZnVuY3Rpb24oKXtyZXR1cm4gSlNPTi5zdHJpbmdpZnkoaS5uYW1lKX0sdCl9LCJrZXkiKX1mdW5jdGlvbiBwcmludE1ldGhvZChlLHQsbil7dmFyIHI9ZS5nZXROb2RlKCksaT10LnNlbWk/IjsiOiIiLG89ci5raW5kLGE9W107Ik9iamVjdE1ldGhvZCIhPT1yLnR5cGUmJiJDbGFzc01ldGhvZCIhPT1yLnR5cGV8fChyLnZhbHVlPXIpLHIudmFsdWUuYXN5bmMmJmEucHVzaCgiYXN5bmMgIiksbyYmImluaXQiIT09byYmIm1ldGhvZCIhPT1vJiYiY29uc3RydWN0b3IiIT09bz8oYXNzZXJ0Lm9rKCJnZXQiPT09b3x8InNldCI9PT1vKSxhLnB1c2gobywiICIpKTpyLnZhbHVlLmdlbmVyYXRvciYmYS5wdXNoKCIqIik7dmFyIHM9cHJpbnRQcm9wZXJ0eUtleShlLHQsbik7cmV0dXJuIHIuY29tcHV0ZWQmJihzPWNvbmNhdCQ0KFsiWyIscywiXSJdKSksYS5wdXNoKHMsY29uY2F0JDQoZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybltwcmludEZ1bmN0aW9uVHlwZVBhcmFtZXRlcnMoZSx0LG4pLGdyb3VwJDEoY29uY2F0JDQoW3ByaW50RnVuY3Rpb25QYXJhbXMoZSxuLHQpLHByaW50UmV0dXJuVHlwZShlLG4sdCldKSldfSwidmFsdWUiKSkpLHIudmFsdWUuYm9keSYmMCE9PXIudmFsdWUuYm9keS5sZW5ndGg/YS5wdXNoKCIgIixlLmNhbGwobiwidmFsdWUiLCJib2R5IikpOmEucHVzaChpKSxjb25jYXQkNChhKX1mdW5jdGlvbiBjb3VsZEdyb3VwQXJnKGUpe3JldHVybiJPYmplY3RFeHByZXNzaW9uIj09PWUudHlwZSYmKGUucHJvcGVydGllcy5sZW5ndGg+MHx8ZS5jb21tZW50cyl8fCJBcnJheUV4cHJlc3Npb24iPT09ZS50eXBlJiYoZS5lbGVtZW50cy5sZW5ndGg+MHx8ZS5jb21tZW50cyl8fCJUU1R5cGVBc3NlcnRpb25FeHByZXNzaW9uIj09PWUudHlwZXx8IlRTQXNFeHByZXNzaW9uIj09PWUudHlwZXx8IkZ1bmN0aW9uRXhwcmVzc2lvbiI9PT1lLnR5cGV8fCJBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbiI9PT1lLnR5cGUmJiFlLnJldHVyblR5cGUmJigiQmxvY2tTdGF0ZW1lbnQiPT09ZS5ib2R5LnR5cGV8fCJBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbiI9PT1lLmJvZHkudHlwZXx8Ik9iamVjdEV4cHJlc3Npb24iPT09ZS5ib2R5LnR5cGV8fCJBcnJheUV4cHJlc3Npb24iPT09ZS5ib2R5LnR5cGV8fCJDYWxsRXhwcmVzc2lvbiI9PT1lLmJvZHkudHlwZXx8Ik9wdGlvbmFsQ2FsbEV4cHJlc3Npb24iPT09ZS5ib2R5LnR5cGV8fGlzSlNYTm9kZShlLmJvZHkpKX1mdW5jdGlvbiBzaG91bGRHcm91cExhc3RBcmcoZSl7dmFyIHQ9Z2V0TGFzdCQ0KGUpLG49Z2V0UGVudWx0aW1hdGUkMShlKTtyZXR1cm4haGFzTGVhZGluZ0NvbW1lbnQodCkmJiFoYXNUcmFpbGluZ0NvbW1lbnQodCkmJmNvdWxkR3JvdXBBcmcodCkmJighbnx8bi50eXBlIT09dC50eXBlKX1mdW5jdGlvbiBzaG91bGRHcm91cEZpcnN0QXJnKGUpe2lmKDIhPT1lLmxlbmd0aClyZXR1cm4hMTt2YXIgdD1lWzBdLG49ZVsxXTtyZXR1cm4oIXQuY29tbWVudHN8fCF0LmNvbW1lbnRzLmxlbmd0aCkmJigiRnVuY3Rpb25FeHByZXNzaW9uIj09PXQudHlwZXx8IkFycm93RnVuY3Rpb25FeHByZXNzaW9uIj09PXQudHlwZSYmIkJsb2NrU3RhdGVtZW50Ij09PXQuYm9keS50eXBlKSYmIWNvdWxkR3JvdXBBcmcobil9ZnVuY3Rpb24gaXNGdW5jdGlvbkNvbXBvc2l0aW9uRnVuY3Rpb24oZSl7c3dpdGNoKGUudHlwZSl7Y2FzZSJPcHRpb25hbE1lbWJlckV4cHJlc3Npb24iOmNhc2UiTWVtYmVyRXhwcmVzc2lvbiI6cmV0dXJuIGlzRnVuY3Rpb25Db21wb3NpdGlvbkZ1bmN0aW9uKGUucHJvcGVydHkpO2Nhc2UiSWRlbnRpZmllciI6cmV0dXJuIGZ1bmN0aW9uQ29tcG9zaXRpb25GdW5jdGlvbk5hbWVzW2UubmFtZV07Y2FzZSJTdHJpbmdMaXRlcmFsIjpjYXNlIkxpdGVyYWwiOnJldHVybiBmdW5jdGlvbkNvbXBvc2l0aW9uRnVuY3Rpb25OYW1lc1tlLnZhbHVlXX19ZnVuY3Rpb24gcHJpbnRBcmd1bWVudHNMaXN0KGUsdCxuKXtmdW5jdGlvbiByKCl7cmV0dXJuIGdyb3VwJDEoY29uY2F0JDQoWyIoIixpbmRlbnQkMihjb25jYXQkNChbbGluZSQzLGNvbmNhdCQ0KGMpXSkpLGwsbGluZSQzLCIpIl0pLHtzaG91bGRCcmVhazohMH0pfXZhciBpPWUuZ2V0VmFsdWUoKSxvPWkuYXJndW1lbnRzO2lmKDA9PT1vLmxlbmd0aClyZXR1cm4gY29uY2F0JDQoWyIoIixjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0LCEwKSwiKSJdKTt2YXIgYT0hMSxzPSExLHU9by5sZW5ndGgtMSxjPWUubWFwKGZ1bmN0aW9uKGUscil7dmFyIGk9ZS5nZXROb2RlKCksbz1bbihlKV07cmV0dXJuIHI9PT11fHwoaXNOZXh0TGluZUVtcHR5JDIodC5vcmlnaW5hbFRleHQsaSx0KT8oMD09PXImJihzPSEwKSxhPSEwLG8ucHVzaCgiLCIsaGFyZGxpbmUkMyxoYXJkbGluZSQzKSk6by5wdXNoKCIsIixsaW5lJDMpKSxjb25jYXQkNChvKX0sImFyZ3VtZW50cyIpLGw9c2hvdWxkUHJpbnRDb21tYSh0LCJhbGwiKT8iLCI6IiI7aWYoaXNGdW5jdGlvbkNvbXBvc2l0aW9uRnVuY3Rpb24oaS5jYWxsZWUpJiZvLmxlbmd0aD4xKXJldHVybiByKCk7dmFyIHA9c2hvdWxkR3JvdXBGaXJzdEFyZyhvKSxmPXNob3VsZEdyb3VwTGFzdEFyZyhvKTtpZihwfHxmKXt2YXIgZCxoPShwP2Muc2xpY2UoMSkuc29tZSh3aWxsQnJlYWskMSk6Yy5zbGljZSgwLC0xKS5zb21lKHdpbGxCcmVhayQxKSl8fGEsbT0wO2UuZWFjaChmdW5jdGlvbihlKXtwJiYwPT09bSYmKGQ9W2NvbmNhdCQ0KFtlLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIG4oZSx7ZXhwYW5kRmlyc3RBcmc6ITB9KX0pLGMubGVuZ3RoPjE/IiwiOiIiLHM/aGFyZGxpbmUkMzpsaW5lJDMscz9oYXJkbGluZSQzOiIiXSldLmNvbmNhdChjLnNsaWNlKDEpKSksZiYmbT09PW8ubGVuZ3RoLTEmJihkPWMuc2xpY2UoMCwtMSkuY29uY2F0KGUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gbihlLHtleHBhbmRMYXN0QXJnOiEwfSl9KSkpLG0rK30sImFyZ3VtZW50cyIpO3ZhciBnPWMuc29tZSh3aWxsQnJlYWskMSk7cmV0dXJuIGNvbmNhdCQ0KFtnP2JyZWFrUGFyZW50JDI6IiIsY29uZGl0aW9uYWxHcm91cCQxKFtjb25jYXQkNChbaWZCcmVhayQxKGluZGVudCQyKGNvbmNhdCQ0KFsiKCIsc29mdGxpbmUkMSxjb25jYXQkNChkKV0pKSxjb25jYXQkNChbIigiLGNvbmNhdCQ0KGQpXSkpLGc/Y29uY2F0JDQoW2lmQnJlYWskMShsKSxzb2Z0bGluZSQxXSk6IiIsIikiXSksY29uY2F0JDQocD9bIigiLGdyb3VwJDEoZFswXSx7c2hvdWxkQnJlYWs6ITB9KSxjb25jYXQkNChkLnNsaWNlKDEpKSwiKSJdOlsiKCIsY29uY2F0JDQoYy5zbGljZSgwLC0xKSksZ3JvdXAkMShnZXRMYXN0JDQoZCkse3Nob3VsZEJyZWFrOiEwfSksIikiXSkscigpXSx7c2hvdWxkQnJlYWs6aH0pXSl9cmV0dXJuIGdyb3VwJDEoY29uY2F0JDQoWyIoIixpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxjb25jYXQkNChjKV0pKSxpZkJyZWFrJDEoc2hvdWxkUHJpbnRDb21tYSh0LCJhbGwiKT8iLCI6IiIpLHNvZnRsaW5lJDEsIikiXSkse3Nob3VsZEJyZWFrOmMuc29tZSh3aWxsQnJlYWskMSl8fGF9KX1mdW5jdGlvbiBwcmludFR5cGVBbm5vdGF0aW9uKGUsdCxuKXt2YXIgcj1lLmdldFZhbHVlKCk7aWYoIXIudHlwZUFubm90YXRpb24pcmV0dXJuIiI7dmFyIGk9ZS5nZXRQYXJlbnROb2RlKCksbz1yLmRlZmluaXRlfHxpJiYiVmFyaWFibGVEZWNsYXJhdG9yIj09PWkudHlwZSYmaS5kZWZpbml0ZSxhPSJEZWNsYXJlRnVuY3Rpb24iPT09aS50eXBlJiZpLmlkPT09cjtyZXR1cm4gY29uY2F0JDQoaXNGbG93QW5ub3RhdGlvbkNvbW1lbnQodC5vcmlnaW5hbFRleHQsci50eXBlQW5ub3RhdGlvbix0KT9bIiAvKjogIixlLmNhbGwobiwidHlwZUFubm90YXRpb24iKSwiICovIl06W2E/IiI6bz8iITogIjoiOiAiLGUuY2FsbChuLCJ0eXBlQW5ub3RhdGlvbiIpXSl9ZnVuY3Rpb24gcHJpbnRGdW5jdGlvblR5cGVQYXJhbWV0ZXJzKGUsdCxuKXt2YXIgcj1lLmdldFZhbHVlKCk7cmV0dXJuIHIudHlwZUFyZ3VtZW50cz9lLmNhbGwobiwidHlwZUFyZ3VtZW50cyIpOnIudHlwZVBhcmFtZXRlcnM/ZS5jYWxsKG4sInR5cGVQYXJhbWV0ZXJzIik6IiJ9ZnVuY3Rpb24gcHJpbnRGdW5jdGlvblBhcmFtcyhlLHQsbixyLGkpe3ZhciBvPWUuZ2V0VmFsdWUoKSxhPW8ucGFyYW1ldGVycz8icGFyYW1ldGVycyI6InBhcmFtcyIscz1pP3ByaW50RnVuY3Rpb25UeXBlUGFyYW1ldGVycyhlLG4sdCk6IiIsdT1bXTtpZihvW2FdJiYodT1lLm1hcCh0LGEpKSxvLnJlc3QmJnUucHVzaChjb25jYXQkNChbIi4uLiIsZS5jYWxsKHQsInJlc3QiKV0pKSwwPT09dS5sZW5ndGgpcmV0dXJuIGNvbmNhdCQ0KFtzLCIoIixjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSxuLCEwLGZ1bmN0aW9uKGUpe3JldHVybiIpIj09PWdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXIkMShuLm9yaWdpbmFsVGV4dCxlLG4ubG9jRW5kKX0pLCIpIl0pO3ZhciBjPWdldExhc3QkNChvW2FdKTtpZihyJiYoIW9bYV18fCFvW2FdLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGUuY29tbWVudHN9KSkpcmV0dXJuIGdyb3VwJDEoY29uY2F0JDQoW3JlbW92ZUxpbmVzJDEocyksIigiLGpvaW4kMigiLCAiLHUubWFwKHJlbW92ZUxpbmVzJDEpKSwiKSJdKSk7aWYoc2hvdWxkSHVnQXJndW1lbnRzKG8pKXJldHVybiBjb25jYXQkNChbcywiKCIsam9pbiQyKCIsICIsdSksIikiXSk7dmFyIGw9ZS5nZXRQYXJlbnROb2RlKCk7aWYoaXNUZXN0Q2FsbChsKSlyZXR1cm4gY29uY2F0JDQoW3MsIigiLGpvaW4kMigiLCAiLHUpLCIpIl0pO3ZhciBwPVsiQW55VHlwZUFubm90YXRpb24iLCJOdWxsTGl0ZXJhbFR5cGVBbm5vdGF0aW9uIiwiR2VuZXJpY1R5cGVBbm5vdGF0aW9uIiwiVGhpc1R5cGVBbm5vdGF0aW9uIiwiTnVtYmVyVHlwZUFubm90YXRpb24iLCJWb2lkVHlwZUFubm90YXRpb24iLCJFbXB0eVR5cGVBbm5vdGF0aW9uIiwiTWl4ZWRUeXBlQW5ub3RhdGlvbiIsIkJvb2xlYW5UeXBlQW5ub3RhdGlvbiIsIkJvb2xlYW5MaXRlcmFsVHlwZUFubm90YXRpb24iLCJTdHJpbmdUeXBlQW5ub3RhdGlvbiJdO2lmKChpc09iamVjdFR5cGVQcm9wZXJ0eUFGdW5jdGlvbihsLG4pfHxpc1R5cGVBbm5vdGF0aW9uQUZ1bmN0aW9uKGwsbil8fCJUeXBlQWxpYXMiPT09bC50eXBlfHwiVW5pb25UeXBlQW5ub3RhdGlvbiI9PT1sLnR5cGV8fCJUU1VuaW9uVHlwZSI9PT1sLnR5cGV8fCJJbnRlcnNlY3Rpb25UeXBlQW5ub3RhdGlvbiI9PT1sLnR5cGV8fCJGdW5jdGlvblR5cGVBbm5vdGF0aW9uIj09PWwudHlwZSYmbC5yZXR1cm5UeXBlPT09bykmJjE9PT1vW2FdLmxlbmd0aCYmbnVsbD09PW9bYV1bMF0ubmFtZSYmb1thXVswXS50eXBlQW5ub3RhdGlvbiYmbnVsbD09PW8udHlwZVBhcmFtZXRlcnMmJi0xIT09cC5pbmRleE9mKG9bYV1bMF0udHlwZUFubm90YXRpb24udHlwZSkmJiEoIkdlbmVyaWNUeXBlQW5ub3RhdGlvbiI9PT1vW2FdWzBdLnR5cGVBbm5vdGF0aW9uLnR5cGUmJm9bYV1bMF0udHlwZUFubm90YXRpb24udHlwZVBhcmFtZXRlcnMpJiYhby5yZXN0KXJldHVybiBjb25jYXQkNCgiYWx3YXlzIj09PW4uYXJyb3dQYXJlbnM/WyIoIixjb25jYXQkNCh1KSwiKSJdOnUpO3ZhciBmPSEoYyYmIlJlc3RFbGVtZW50Ij09PWMudHlwZSkmJiFvLnJlc3Q7cmV0dXJuIGNvbmNhdCQ0KFtzLCIoIixpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxqb2luJDIoY29uY2F0JDQoWyIsIixsaW5lJDNdKSx1KV0pKSxpZkJyZWFrJDEoZiYmc2hvdWxkUHJpbnRDb21tYShuLCJhbGwiKT8iLCI6IiIpLHNvZnRsaW5lJDEsIikiXSl9ZnVuY3Rpb24gc2hvdWxkUHJpbnRQYXJhbXNXaXRob3V0UGFyZW5zKGUsdCl7aWYoImFsd2F5cyI9PT10LmFycm93UGFyZW5zKXJldHVybiExO2lmKCJhdm9pZCI9PT10LmFycm93UGFyZW5zKXtyZXR1cm4gY2FuUHJpbnRQYXJhbXNXaXRob3V0UGFyZW5zKGUuZ2V0VmFsdWUoKSl9cmV0dXJuITF9ZnVuY3Rpb24gY2FuUHJpbnRQYXJhbXNXaXRob3V0UGFyZW5zKGUpe3JldHVybiAxPT09ZS5wYXJhbXMubGVuZ3RoJiYhZS5yZXN0JiYhZS50eXBlUGFyYW1ldGVycyYmIWhhc0RhbmdsaW5nQ29tbWVudHMoZSkmJiJJZGVudGlmaWVyIj09PWUucGFyYW1zWzBdLnR5cGUmJiFlLnBhcmFtc1swXS50eXBlQW5ub3RhdGlvbiYmIWUucGFyYW1zWzBdLmNvbW1lbnRzJiYhZS5wYXJhbXNbMF0ub3B0aW9uYWwmJiFlLnByZWRpY2F0ZSYmIWUucmV0dXJuVHlwZX1mdW5jdGlvbiBwcmludEZ1bmN0aW9uRGVjbGFyYXRpb24oZSx0LG4pe3ZhciByPWUuZ2V0VmFsdWUoKSxpPVtdO3JldHVybiByLmFzeW5jJiZpLnB1c2goImFzeW5jICIpLGkucHVzaCgiZnVuY3Rpb24iKSxyLmdlbmVyYXRvciYmaS5wdXNoKCIqIiksci5pZCYmaS5wdXNoKCIgIixlLmNhbGwodCwiaWQiKSksaS5wdXNoKHByaW50RnVuY3Rpb25UeXBlUGFyYW1ldGVycyhlLG4sdCksZ3JvdXAkMShjb25jYXQkNChbcHJpbnRGdW5jdGlvblBhcmFtcyhlLHQsbikscHJpbnRSZXR1cm5UeXBlKGUsdCxuKV0pKSxyLmJvZHk/IiAiOiIiLGUuY2FsbCh0LCJib2R5IikpLGNvbmNhdCQ0KGkpfWZ1bmN0aW9uIHByaW50T2JqZWN0TWV0aG9kKGUsdCxuKXt2YXIgcj1lLmdldFZhbHVlKCksaT1bXTtpZihyLmFzeW5jJiZpLnB1c2goImFzeW5jICIpLHIuZ2VuZXJhdG9yJiZpLnB1c2goIioiKSxyLm1ldGhvZHx8ImdldCI9PT1yLmtpbmR8fCJzZXQiPT09ci5raW5kKXJldHVybiBwcmludE1ldGhvZChlLHQsbik7dmFyIG89cHJpbnRQcm9wZXJ0eUtleShlLHQsbik7cmV0dXJuIHIuY29tcHV0ZWQ/aS5wdXNoKCJbIixvLCJdIik6aS5wdXNoKG8pLGkucHVzaChwcmludEZ1bmN0aW9uVHlwZVBhcmFtZXRlcnMoZSx0LG4pLGdyb3VwJDEoY29uY2F0JDQoW3ByaW50RnVuY3Rpb25QYXJhbXMoZSxuLHQpLHByaW50UmV0dXJuVHlwZShlLG4sdCldKSksIiAiLGUuY2FsbChuLCJib2R5IikpLGNvbmNhdCQ0KGkpfWZ1bmN0aW9uIHByaW50UmV0dXJuVHlwZShlLHQsbil7dmFyIHI9ZS5nZXRWYWx1ZSgpLGk9ZS5jYWxsKHQsInJldHVyblR5cGUiKTtpZihyLnJldHVyblR5cGUmJmlzRmxvd0Fubm90YXRpb25Db21tZW50KG4ub3JpZ2luYWxUZXh0LHIucmV0dXJuVHlwZSxuKSlyZXR1cm4gY29uY2F0JDQoWyIgLyo6ICIsaSwiICovIl0pO3ZhciBvPVtpXTtyZXR1cm4gci5yZXR1cm5UeXBlJiZyLnJldHVyblR5cGUudHlwZUFubm90YXRpb24mJm8udW5zaGlmdCgiOiAiKSxyLnByZWRpY2F0ZSYmby5wdXNoKHIucmV0dXJuVHlwZT8iICI6IjogIixlLmNhbGwodCwicHJlZGljYXRlIikpLGNvbmNhdCQ0KG8pfWZ1bmN0aW9uIHByaW50RXhwb3J0RGVjbGFyYXRpb24oZSx0LG4pe3ZhciByPWUuZ2V0VmFsdWUoKSxpPXQuc2VtaT8iOyI6IiIsbz1bImV4cG9ydCAiXSxhPXIuZGVmYXVsdHx8IkV4cG9ydERlZmF1bHREZWNsYXJhdGlvbiI9PT1yLnR5cGU7aWYoYSYmby5wdXNoKCJkZWZhdWx0ICIpLG8ucHVzaChjb21tZW50cy5wcmludERhbmdsaW5nQ29tbWVudHMoZSx0LCEwKSksbmVlZHNIYXJkbGluZUFmdGVyRGFuZ2xpbmdDb21tZW50KHIpJiZvLnB1c2goaGFyZGxpbmUkMyksci5kZWNsYXJhdGlvbilvLnB1c2goZS5jYWxsKG4sImRlY2xhcmF0aW9uIikpLGEmJiJDbGFzc0RlY2xhcmF0aW9uIiE9PXIuZGVjbGFyYXRpb24udHlwZSYmIkZ1bmN0aW9uRGVjbGFyYXRpb24iIT09ci5kZWNsYXJhdGlvbi50eXBlJiYiVFNBYnN0cmFjdENsYXNzRGVjbGFyYXRpb24iIT09ci5kZWNsYXJhdGlvbi50eXBlJiYiVFNJbnRlcmZhY2VEZWNsYXJhdGlvbiIhPT1yLmRlY2xhcmF0aW9uLnR5cGUmJiJEZWNsYXJlQ2xhc3MiIT09ci5kZWNsYXJhdGlvbi50eXBlJiYiRGVjbGFyZUZ1bmN0aW9uIiE9PXIuZGVjbGFyYXRpb24udHlwZSYmby5wdXNoKGkpO2Vsc2V7aWYoci5zcGVjaWZpZXJzJiZyLnNwZWNpZmllcnMubGVuZ3RoPjApe3ZhciBzPVtdLHU9W10sYz1bXTtlLmVhY2goZnVuY3Rpb24odCl7dmFyIHI9ZS5nZXRWYWx1ZSgpLnR5cGU7IkV4cG9ydFNwZWNpZmllciI9PT1yP3MucHVzaChuKHQpKToiRXhwb3J0RGVmYXVsdFNwZWNpZmllciI9PT1yP3UucHVzaChuKHQpKToiRXhwb3J0TmFtZXNwYWNlU3BlY2lmaWVyIj09PXImJmMucHVzaChjb25jYXQkNChbIiogYXMgIixuKHQpXSkpfSwic3BlY2lmaWVycyIpO3ZhciBsPTAhPT1jLmxlbmd0aCYmMCE9PXMubGVuZ3RoLHA9MCE9PXUubGVuZ3RoJiYoMCE9PWMubGVuZ3RofHwwIT09cy5sZW5ndGgpO28ucHVzaCgidHlwZSI9PT1yLmV4cG9ydEtpbmQ/InR5cGUgIjoiIixjb25jYXQkNCh1KSxjb25jYXQkNChbcD8iLCAiOiIiXSksY29uY2F0JDQoYyksY29uY2F0JDQoW2w/IiwgIjoiIl0pLDAhPT1zLmxlbmd0aD9ncm91cCQxKGNvbmNhdCQ0KFsieyIsaW5kZW50JDIoY29uY2F0JDQoW3QuYnJhY2tldFNwYWNpbmc/bGluZSQzOnNvZnRsaW5lJDEsam9pbiQyKGNvbmNhdCQ0KFsiLCIsbGluZSQzXSkscyldKSksaWZCcmVhayQxKHNob3VsZFByaW50Q29tbWEodCk/IiwiOiIiKSx0LmJyYWNrZXRTcGFjaW5nP2xpbmUkMzpzb2Z0bGluZSQxLCJ9Il0pKToiIil9ZWxzZSBvLnB1c2goInt9Iik7ci5zb3VyY2UmJm8ucHVzaCgiIGZyb20gIixlLmNhbGwobiwic291cmNlIikpLG8ucHVzaChpKX1yZXR1cm4gY29uY2F0JDQobyl9ZnVuY3Rpb24gcHJpbnRGbG93RGVjbGFyYXRpb24oZSx0KXt2YXIgbj1nZXRQYXJlbnRFeHBvcnREZWNsYXJhdGlvbiQxKGUpO3JldHVybiBuP2Fzc2VydC5zdHJpY3RFcXVhbChuLnR5cGUsIkRlY2xhcmVFeHBvcnREZWNsYXJhdGlvbiIpOnQudW5zaGlmdCgiZGVjbGFyZSAiKSxjb25jYXQkNCh0KX1mdW5jdGlvbiBnZXRGbG93VmFyaWFuY2UoZSl7aWYoIWUudmFyaWFuY2UpcmV0dXJuIG51bGw7dmFyIHQ9ZS52YXJpYW5jZS5raW5kfHxlLnZhcmlhbmNlO3N3aXRjaCh0KXtjYXNlInBsdXMiOnJldHVybiIrIjtjYXNlIm1pbnVzIjpyZXR1cm4iLSI7ZGVmYXVsdDpyZXR1cm4gdH19ZnVuY3Rpb24gcHJpbnRUeXBlU2NyaXB0TW9kaWZpZXJzKGUsdCxuKXt2YXIgcj1lLmdldFZhbHVlKCk7cmV0dXJuIHIubW9kaWZpZXJzJiZyLm1vZGlmaWVycy5sZW5ndGg/Y29uY2F0JDQoW2pvaW4kMigiICIsZS5tYXAobiwibW9kaWZpZXJzIikpLCIgIl0pOiIifWZ1bmN0aW9uIHByaW50VHlwZVBhcmFtZXRlcnMoZSx0LG4scil7dmFyIGk9ZS5nZXRWYWx1ZSgpO2lmKCFpW3JdKXJldHVybiIiO2lmKCFBcnJheS5pc0FycmF5KGlbcl0pKXJldHVybiBlLmNhbGwobixyKTt2YXIgbz1lLmdldE5vZGUoMik7cmV0dXJuIG51bGwhPW8mJmlzVGVzdENhbGwobyl8fDA9PT1pW3JdLmxlbmd0aHx8MT09PWlbcl0ubGVuZ3RoJiYoc2hvdWxkSHVnVHlwZShpW3JdWzBdKXx8IkdlbmVyaWNUeXBlQW5ub3RhdGlvbiI9PT1pW3JdWzBdLnR5cGUmJnNob3VsZEh1Z1R5cGUoaVtyXVswXS5pZCl8fCJUU1R5cGVSZWZlcmVuY2UiPT09aVtyXVswXS50eXBlJiZzaG91bGRIdWdUeXBlKGlbcl1bMF0udHlwZU5hbWUpfHwiTnVsbGFibGVUeXBlQW5ub3RhdGlvbiI9PT1pW3JdWzBdLnR5cGUpP2NvbmNhdCQ0KFsiPCIsam9pbiQyKCIsICIsZS5tYXAobixyKSksIj4iXSk6Z3JvdXAkMShjb25jYXQkNChbIjwiLGluZGVudCQyKGNvbmNhdCQ0KFtzb2Z0bGluZSQxLGpvaW4kMihjb25jYXQkNChbIiwiLGxpbmUkM10pLGUubWFwKG4scikpXSkpLGlmQnJlYWskMSgidHlwZXNjcmlwdCIhPT10LnBhcnNlciYmc2hvdWxkUHJpbnRDb21tYSh0LCJhbGwiKT8iLCI6IiIpLHNvZnRsaW5lJDEsIj4iXSkpfWZ1bmN0aW9uIHByaW50Q2xhc3MoZSx0LG4pe3ZhciByPWUuZ2V0VmFsdWUoKSxpPVtdOyJUU0Fic3RyYWN0Q2xhc3NEZWNsYXJhdGlvbiI9PT1yLnR5cGUmJmkucHVzaCgiYWJzdHJhY3QgIiksaS5wdXNoKCJjbGFzcyIpLHIuaWQmJmkucHVzaCgiICIsZS5jYWxsKG4sImlkIikpLGkucHVzaChlLmNhbGwobiwidHlwZVBhcmFtZXRlcnMiKSk7dmFyIG89W107aWYoci5zdXBlckNsYXNzKXt2YXIgYT1jb25jYXQkNChbImV4dGVuZHMgIixlLmNhbGwobiwic3VwZXJDbGFzcyIpLGUuY2FsbChuLCJzdXBlclR5cGVQYXJhbWV0ZXJzIildKTtyLmltcGxlbWVudHMmJjAhPT1yLmltcGxlbWVudHMubGVuZ3RofHxyLnN1cGVyQ2xhc3MuY29tbWVudHMmJjAhPT1yLnN1cGVyQ2xhc3MuY29tbWVudHMubGVuZ3RoP28ucHVzaChncm91cCQxKGNvbmNhdCQ0KFtsaW5lJDMsZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBjb21tZW50cy5wcmludENvbW1lbnRzKGUsZnVuY3Rpb24oKXtyZXR1cm4gYX0sdCl9LCJzdXBlckNsYXNzIildKSkpOmkucHVzaChjb25jYXQkNChbIiAiLGUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gY29tbWVudHMucHJpbnRDb21tZW50cyhlLGZ1bmN0aW9uKCl7cmV0dXJuIGF9LHQpfSwic3VwZXJDbGFzcyIpXSkpfWVsc2Ugci5leHRlbmRzJiZyLmV4dGVuZHMubGVuZ3RoPjAmJmkucHVzaCgiIGV4dGVuZHMgIixqb2luJDIoIiwgIixlLm1hcChuLCJleHRlbmRzIikpKTtyZXR1cm4gci5taXhpbnMmJnIubWl4aW5zLmxlbmd0aD4wJiZvLnB1c2gobGluZSQzLCJtaXhpbnMgIixncm91cCQxKGluZGVudCQyKGpvaW4kMihjb25jYXQkNChbIiwiLGxpbmUkM10pLGUubWFwKG4sIm1peGlucyIpKSkpKSxyLmltcGxlbWVudHMmJnIuaW1wbGVtZW50cy5sZW5ndGg+MCYmby5wdXNoKGxpbmUkMywiaW1wbGVtZW50cyIsZ3JvdXAkMShpbmRlbnQkMihjb25jYXQkNChbbGluZSQzLGpvaW4kMihjb25jYXQkNChbIiwiLGxpbmUkM10pLGUubWFwKG4sImltcGxlbWVudHMiKSldKSkpKSxvLmxlbmd0aD4wJiZpLnB1c2goZ3JvdXAkMShpbmRlbnQkMihjb25jYXQkNChvKSkpKSxyLmJvZHkmJnIuYm9keS5jb21tZW50cyYmaGFzTGVhZGluZ093bkxpbmVDb21tZW50KHQub3JpZ2luYWxUZXh0LHIuYm9keSx0KT9pLnB1c2goaGFyZGxpbmUkMyk6aS5wdXNoKCIgIiksaS5wdXNoKGUuY2FsbChuLCJib2R5IikpLGl9ZnVuY3Rpb24gcHJpbnRPcHRpb25hbFRva2VuKGUpe3ZhciB0PWUuZ2V0VmFsdWUoKTtyZXR1cm4gdC5vcHRpb25hbD8iT3B0aW9uYWxDYWxsRXhwcmVzc2lvbiI9PT10LnR5cGV8fCJPcHRpb25hbE1lbWJlckV4cHJlc3Npb24iPT09dC50eXBlJiZ0LmNvbXB1dGVkPyI/LiI6Ij8iOiIifWZ1bmN0aW9uIHByaW50TWVtYmVyTG9va3VwKGUsdCxuKXt2YXIgcj1lLmNhbGwobiwicHJvcGVydHkiKSxpPWUuZ2V0VmFsdWUoKSxvPXByaW50T3B0aW9uYWxUb2tlbihlKTtyZXR1cm4gaS5jb21wdXRlZD8haS5wcm9wZXJ0eXx8aXNOdW1lcmljTGl0ZXJhbChpLnByb3BlcnR5KT9jb25jYXQkNChbbywiWyIsciwiXSJdKTpncm91cCQxKGNvbmNhdCQ0KFtvLCJbIixpbmRlbnQkMihjb25jYXQkNChbc29mdGxpbmUkMSxyXSkpLHNvZnRsaW5lJDEsIl0iXSkpOmNvbmNhdCQ0KFtvLCIuIixyXSl9ZnVuY3Rpb24gcHJpbnRCaW5kRXhwcmVzc2lvbkNhbGxlZShlLHQsbil7cmV0dXJuIGNvbmNhdCQ0KFsiOjoiLGUuY2FsbChuLCJjYWxsZWUiKV0pfWZ1bmN0aW9uIHByaW50TWVtYmVyQ2hhaW4oZSx0LG4pe2Z1bmN0aW9uIHIoZSl7dmFyIG49dC5vcmlnaW5hbFRleHQscj1nZXROZXh0Tm9uU3BhY2VOb25Db21tZW50Q2hhcmFjdGVySW5kZXgkMihuLGUsdCk7cmV0dXJuIikiPT1uLmNoYXJBdChyKT9pc05leHRMaW5lRW1wdHlBZnRlckluZGV4JDEobixyKzEsdCk6aXNOZXh0TGluZUVtcHR5JDIobixlLHQpfWZ1bmN0aW9uIGkoZSl7dmFyIG89ZS5nZXRWYWx1ZSgpOyJDYWxsRXhwcmVzc2lvbiIhPT1vLnR5cGUmJiJPcHRpb25hbENhbGxFeHByZXNzaW9uIiE9PW8udHlwZXx8IWlzTWVtYmVyaXNoKG8uY2FsbGVlKSYmIkNhbGxFeHByZXNzaW9uIiE9PW8uY2FsbGVlLnR5cGUmJiJPcHRpb25hbENhbGxFeHByZXNzaW9uIiE9PW8uY2FsbGVlLnR5cGU/aXNNZW1iZXJpc2gobyk/KHUudW5zaGlmdCh7bm9kZTpvLG5lZWRzUGFyZW5zOm5lZWRzUGFyZW5zXzEoZSx0KSxwcmludGVkOmNvbW1lbnRzLnByaW50Q29tbWVudHMoZSxmdW5jdGlvbigpe3JldHVybiJPcHRpb25hbE1lbWJlckV4cHJlc3Npb24iPT09by50eXBlfHwiTWVtYmVyRXhwcmVzc2lvbiI9PT1vLnR5cGU/cHJpbnRNZW1iZXJMb29rdXAoZSx0LG4pOnByaW50QmluZEV4cHJlc3Npb25DYWxsZWUoZSx0LG4pfSx0KX0pLGUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gaShlKX0sIm9iamVjdCIpKToiVFNOb25OdWxsRXhwcmVzc2lvbiI9PT1vLnR5cGU/KHUudW5zaGlmdCh7bm9kZTpvLHByaW50ZWQ6Y29tbWVudHMucHJpbnRDb21tZW50cyhlLGZ1bmN0aW9uKCl7cmV0dXJuIiEifSx0KX0pLGUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gaShlKX0sImV4cHJlc3Npb24iKSk6dS51bnNoaWZ0KHtub2RlOm8scHJpbnRlZDplLmNhbGwobil9KToodS51bnNoaWZ0KHtub2RlOm8scHJpbnRlZDpjb25jYXQkNChbY29tbWVudHMucHJpbnRDb21tZW50cyhlLGZ1bmN0aW9uKCl7cmV0dXJuIGNvbmNhdCQ0KFtwcmludE9wdGlvbmFsVG9rZW4oZSkscHJpbnRGdW5jdGlvblR5cGVQYXJhbWV0ZXJzKGUsdCxuKSxwcmludEFyZ3VtZW50c0xpc3QoZSx0LG4pXSl9LHQpLHIobyk/aGFyZGxpbmUkMzoiIl0pfSksZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBpKGUpfSwiY2FsbGVlIikpfWZ1bmN0aW9uIG8oZSl7cmV0dXJuL15bQS1aXS8udGVzdChlKX1mdW5jdGlvbiBhKGUpe3JldHVybiBlLmxlbmd0aDw9dC50YWJXaWR0aH1mdW5jdGlvbiBzKGUpe2Zvcih2YXIgdD1bXSxuPTA7bjxlLmxlbmd0aDtuKyspZVtuKzFdJiZlW24rMV0ubmVlZHNQYXJlbnM/KHQucHVzaCgiKCIsZVtuXS5wcmludGVkLGVbbisxXS5wcmludGVkLCIpIiksbisrKTp0LnB1c2goZVtuXS5wcmludGVkKTtyZXR1cm4gY29uY2F0JDQodCl9dmFyIHU9W10sYz1lLmdldFZhbHVlKCk7dS51bnNoaWZ0KHtub2RlOmMscHJpbnRlZDpjb25jYXQkNChbcHJpbnRPcHRpb25hbFRva2VuKGUpLHByaW50RnVuY3Rpb25UeXBlUGFyYW1ldGVycyhlLHQsbikscHJpbnRBcmd1bWVudHNMaXN0KGUsdCxuKV0pfSksZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBpKGUpfSwiY2FsbGVlIik7Zm9yKHZhciBsPVtdLHA9W3VbMF1dLGY9MTtmPHUubGVuZ3RoJiYoIlRTTm9uTnVsbEV4cHJlc3Npb24iPT09dVtmXS5ub2RlLnR5cGV8fCJPcHRpb25hbENhbGxFeHByZXNzaW9uIj09PXVbZl0ubm9kZS50eXBlfHwiQ2FsbEV4cHJlc3Npb24iPT09dVtmXS5ub2RlLnR5cGV8fCgiTWVtYmVyRXhwcmVzc2lvbiI9PT11W2ZdLm5vZGUudHlwZXx8Ik9wdGlvbmFsTWVtYmVyRXhwcmVzc2lvbiI9PT11W2ZdLm5vZGUudHlwZSkmJnVbZl0ubm9kZS5jb21wdXRlZCYmaXNOdW1lcmljTGl0ZXJhbCh1W2ZdLm5vZGUucHJvcGVydHkpKTsrK2YpcC5wdXNoKHVbZl0pO2lmKCJDYWxsRXhwcmVzc2lvbiIhPT11WzBdLm5vZGUudHlwZSYmIk9wdGlvbmFsQ2FsbEV4cHJlc3Npb24iIT09dVswXS5ub2RlLnR5cGUpZm9yKDtmKzE8dS5sZW5ndGgmJihpc01lbWJlcmlzaCh1W2ZdLm5vZGUpJiZpc01lbWJlcmlzaCh1W2YrMV0ubm9kZSkpOysrZilwLnB1c2godVtmXSk7bC5wdXNoKHApLHA9W107Zm9yKHZhciBkPSExO2Y8dS5sZW5ndGg7KytmKXtpZihkJiZpc01lbWJlcmlzaCh1W2ZdLm5vZGUpKXtpZih1W2ZdLm5vZGUuY29tcHV0ZWQmJmlzTnVtZXJpY0xpdGVyYWwodVtmXS5ub2RlLnByb3BlcnR5KSl7cC5wdXNoKHVbZl0pO2NvbnRpbnVlfWwucHVzaChwKSxwPVtdLGQ9ITF9IkNhbGxFeHByZXNzaW9uIiE9PXVbZl0ubm9kZS50eXBlJiYiT3B0aW9uYWxDYWxsRXhwcmVzc2lvbiIhPT11W2ZdLm5vZGUudHlwZXx8KGQ9ITApLHAucHVzaCh1W2ZdKSx1W2ZdLm5vZGUuY29tbWVudHMmJnVbZl0ubm9kZS5jb21tZW50cy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiBlLnRyYWlsaW5nfSkmJihsLnB1c2gocCkscD1bXSxkPSExKX1wLmxlbmd0aD4wJiZsLnB1c2gocCk7dmFyIGg9bC5sZW5ndGg+PTImJiFsWzFdWzBdLm5vZGUuY29tbWVudHMmJmZ1bmN0aW9uKHQpe3ZhciBuPWUuZ2V0UGFyZW50Tm9kZSgpLHI9biYmIkV4cHJlc3Npb25TdGF0ZW1lbnQiPT09bi50eXBlLGk9dFsxXS5sZW5ndGgmJnRbMV1bMF0ubm9kZS5jb21wdXRlZDtpZigxPT09dFswXS5sZW5ndGgpe3ZhciBzPXRbMF1bMF0ubm9kZTtyZXR1cm4iVGhpc0V4cHJlc3Npb24iPT09cy50eXBlfHwiSWRlbnRpZmllciI9PT1zLnR5cGUmJihvKHMubmFtZSl8fHImJmEocy5uYW1lKXx8aSl9dmFyIHU9Z2V0TGFzdCQ0KHRbMF0pLm5vZGU7cmV0dXJuKCJNZW1iZXJFeHByZXNzaW9uIj09PXUudHlwZXx8Ik9wdGlvbmFsTWVtYmVyRXhwcmVzc2lvbiI9PT11LnR5cGUpJiYiSWRlbnRpZmllciI9PT11LnByb3BlcnR5LnR5cGUmJihvKHUucHJvcGVydHkubmFtZSl8fGkpfShsKSxtPWwubWFwKHMpLGc9Y29uY2F0JDQobSkseT1oPzM6Mix2PWwuc2xpY2UoMCx5KS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS5jb25jYXQodCl9LFtdKSxiPXYuc2xpY2UoMSwtMSkuc29tZShmdW5jdGlvbihlKXtyZXR1cm4gaGFzTGVhZGluZ0NvbW1lbnQoZS5ub2RlKX0pfHx2LnNsaWNlKDAsLTEpLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGhhc1RyYWlsaW5nQ29tbWVudChlLm5vZGUpfSl8fGxbeV0mJmhhc0xlYWRpbmdDb21tZW50KGxbeV1bMF0ubm9kZSk7aWYobC5sZW5ndGg8PXkmJiFiKXJldHVybiBncm91cCQxKGcpO3ZhciB4PWdldExhc3QkNChoP2wuc2xpY2UoMSwyKVswXTpsWzBdKS5ub2RlLEM9IkNhbGxFeHByZXNzaW9uIiE9PXgudHlwZSYmIk9wdGlvbmFsQ2FsbEV4cHJlc3Npb24iIT09eC50eXBlJiZyKHgpLEU9Y29uY2F0JDQoW3MobFswXSksaD9jb25jYXQkNChsLnNsaWNlKDEsMikubWFwKHMpKToiIixDP2hhcmRsaW5lJDM6IiIsZnVuY3Rpb24oZSl7cmV0dXJuIDA9PT1lLmxlbmd0aD8iIjppbmRlbnQkMihncm91cCQxKGNvbmNhdCQ0KFtoYXJkbGluZSQzLGpvaW4kMihoYXJkbGluZSQzLGUubWFwKHMpKV0pKSl9KGwuc2xpY2UoaD8yOjEpKV0pLEQ9dS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIkNhbGxFeHByZXNzaW9uIj09PWUubm9kZS50eXBlfHwiT3B0aW9uYWxDYWxsRXhwcmVzc2lvbiI9PT1lLm5vZGUudHlwZX0pLmxlbmd0aDtyZXR1cm4gYnx8RD49M3x8bS5zbGljZSgwLC0xKS5zb21lKHdpbGxCcmVhayQxKT9ncm91cCQxKEUpOmNvbmNhdCQ0KFt3aWxsQnJlYWskMShnKXx8Qz9icmVha1BhcmVudCQyOiIiLGNvbmRpdGlvbmFsR3JvdXAkMShbZyxFXSldKX1mdW5jdGlvbiBpc0pTWE5vZGUoZSl7cmV0dXJuIkpTWEVsZW1lbnQiPT09ZS50eXBlfHwiSlNYRnJhZ21lbnQiPT09ZS50eXBlfHwiVFNKc3hGcmFnbWVudCI9PT1lLnR5cGV9ZnVuY3Rpb24gaXNFbXB0eUpTWEVsZW1lbnQoZSl7aWYoMD09PWUuY2hpbGRyZW4ubGVuZ3RoKXJldHVybiEwO2lmKGUuY2hpbGRyZW4ubGVuZ3RoPjEpcmV0dXJuITE7dmFyIHQ9ZS5jaGlsZHJlblswXTtyZXR1cm4gaXNMaXRlcmFsKHQpJiYhaXNNZWFuaW5nZnVsSlNYVGV4dCh0KX1mdW5jdGlvbiBpc01lYW5pbmdmdWxKU1hUZXh0KGUpe3JldHVybiBpc0xpdGVyYWwoZSkmJihjb250YWluc05vbkpzeFdoaXRlc3BhY2VSZWdleC50ZXN0KHJhd1RleHQoZSkpfHwhL1xuLy50ZXN0KHJhd1RleHQoZSkpKX1mdW5jdGlvbiBjb25kaXRpb25hbEV4cHJlc3Npb25DaGFpbkNvbnRhaW5zSlNYKGUpe3JldHVybiBCb29sZWFuKGdldENvbmRpdGlvbmFsQ2hhaW5Db250ZW50cyhlKS5maW5kKGlzSlNYTm9kZSkpfWZ1bmN0aW9uIGdldENvbmRpdGlvbmFsQ2hhaW5Db250ZW50cyhlKXtmdW5jdGlvbiB0KGUpeyJDb25kaXRpb25hbEV4cHJlc3Npb24iPT09ZS50eXBlPyh0KGUudGVzdCksdChlLmNvbnNlcXVlbnQpLHQoZS5hbHRlcm5hdGUpKTpuLnB1c2goZSl9dmFyIG49W107cmV0dXJuIHQoZSksbn1mdW5jdGlvbiBpc0pTWFdoaXRlc3BhY2VFeHByZXNzaW9uKGUpe3JldHVybiJKU1hFeHByZXNzaW9uQ29udGFpbmVyIj09PWUudHlwZSYmaXNMaXRlcmFsKGUuZXhwcmVzc2lvbikmJiIgIj09PWUuZXhwcmVzc2lvbi52YWx1ZSYmIWUuZXhwcmVzc2lvbi5jb21tZW50c31mdW5jdGlvbiBwcmludEpTWENoaWxkcmVuKGUsdCxuLHIpe3ZhciBpPWUuZ2V0VmFsdWUoKSxvPVtdO3JldHVybiBlLm1hcChmdW5jdGlvbihlLHQpe3ZhciBhPWUuZ2V0VmFsdWUoKTtpZihpc0xpdGVyYWwoYSkpe3ZhciBzPXJhd1RleHQoYSk7aWYoaXNNZWFuaW5nZnVsSlNYVGV4dChhKSl7dmFyIHU9cy5zcGxpdChtYXRjaEpzeFdoaXRlc3BhY2VSZWdleCk7IiI9PT11WzBdJiYoby5wdXNoKCIiKSx1LnNoaWZ0KCksL1xuLy50ZXN0KHVbMF0pP28ucHVzaChoYXJkbGluZSQzKTpvLnB1c2gociksdS5zaGlmdCgpKTt2YXIgYztpZigiIj09PWdldExhc3QkNCh1KSYmKHUucG9wKCksYz11LnBvcCgpKSwwPT09dS5sZW5ndGgpcmV0dXJuO3UuZm9yRWFjaChmdW5jdGlvbihlLHQpe3QlMj09PTE/by5wdXNoKGxpbmUkMyk6by5wdXNoKGUpfSksdm9pZCAwIT09Yz8vXG4vLnRlc3QoYyk/by5wdXNoKGhhcmRsaW5lJDMpOm8ucHVzaChyKTpvLnB1c2goIiIpfWVsc2UvXG4vLnRlc3Qocyk/cy5tYXRjaCgvXG4vZykubGVuZ3RoPjEmJihvLnB1c2goIiIpLG8ucHVzaChoYXJkbGluZSQzKSk6KG8ucHVzaCgiIiksby5wdXNoKHIpKX1lbHNle3ZhciBsPW4oZSk7by5wdXNoKGwpO3ZhciBwPWkuY2hpbGRyZW5bdCsxXTtwJiZpc01lYW5pbmdmdWxKU1hUZXh0KHApJiYhL15bIFxuXHJcdF0vLnRlc3QocmF3VGV4dChwKSk/by5wdXNoKCIiKTpvLnB1c2goaGFyZGxpbmUkMyl9fSwiY2hpbGRyZW4iKSxvfWZ1bmN0aW9uIHByaW50SlNYRWxlbWVudChlLHQsbil7dmFyIHI9ZS5nZXRWYWx1ZSgpO2lmKCJKU1hFbGVtZW50Ij09PXIudHlwZSYmaXNFbXB0eUpTWEVsZW1lbnQocikpcmV0dXJuIHIub3BlbmluZ0VsZW1lbnQuc2VsZkNsb3Npbmc9ITAsZS5jYWxsKG4sIm9wZW5pbmdFbGVtZW50Iik7dmFyIGk9IkpTWEVsZW1lbnQiPT09ci50eXBlP2UuY2FsbChuLCJvcGVuaW5nRWxlbWVudCIpOmUuY2FsbChuLCJvcGVuaW5nRnJhZ21lbnQiKSxvPSJKU1hFbGVtZW50Ij09PXIudHlwZT9lLmNhbGwobiwiY2xvc2luZ0VsZW1lbnQiKTplLmNhbGwobiwiY2xvc2luZ0ZyYWdtZW50Iik7aWYoMT09PXIuY2hpbGRyZW4ubGVuZ3RoJiYiSlNYRXhwcmVzc2lvbkNvbnRhaW5lciI9PT1yLmNoaWxkcmVuWzBdLnR5cGUmJigiVGVtcGxhdGVMaXRlcmFsIj09PXIuY2hpbGRyZW5bMF0uZXhwcmVzc2lvbi50eXBlfHwiVGFnZ2VkVGVtcGxhdGVFeHByZXNzaW9uIj09PXIuY2hpbGRyZW5bMF0uZXhwcmVzc2lvbi50eXBlKSlyZXR1cm4gY29uY2F0JDQoW2ksY29uY2F0JDQoZS5tYXAobiwiY2hpbGRyZW4iKSksb10pO3IuY2hpbGRyZW49ci5jaGlsZHJlbi5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGlzSlNYV2hpdGVzcGFjZUV4cHJlc3Npb24oZSk/e3R5cGU6IkpTWFRleHQiLHZhbHVlOiIgIixyYXc6IiAifTplfSk7Zm9yKHZhciBhPXIuY2hpbGRyZW4uZmlsdGVyKGlzSlNYTm9kZSkubGVuZ3RoPjAscz1yLmNoaWxkcmVuLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4iSlNYRXhwcmVzc2lvbkNvbnRhaW5lciI9PT1lLnR5cGV9KS5sZW5ndGg+MSx1PSJKU1hFbGVtZW50Ij09PXIudHlwZSYmci5vcGVuaW5nRWxlbWVudC5hdHRyaWJ1dGVzLmxlbmd0aD4xLGM9d2lsbEJyZWFrJDEoaSl8fGF8fHV8fHMsbD10LnNpbmdsZVF1b3RlPyJ7JyAnfSI6J3siICJ9JyxwPWlmQnJlYWskMShjb25jYXQkNChbbCxzb2Z0bGluZSQxXSksIiAiKSxmPXByaW50SlNYQ2hpbGRyZW4oZSx0LG4scCksZD1yLmNoaWxkcmVuLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gaXNNZWFuaW5nZnVsSlNYVGV4dChlKX0pLmxlbmd0aD4wLGg9Zi5sZW5ndGgtMjtoPj0wO2gtLSl7dmFyIG09IiI9PT1mW2hdJiYiIj09PWZbaCsxXSxnPWZbaF09PT1oYXJkbGluZSQzJiYiIj09PWZbaCsxXSYmZltoKzJdPT09aGFyZGxpbmUkMyx5PShmW2hdPT09c29mdGxpbmUkMXx8ZltoXT09PWhhcmRsaW5lJDMpJiYiIj09PWZbaCsxXSYmZltoKzJdPT09cCx2PWZbaF09PT1wJiYiIj09PWZbaCsxXSYmKGZbaCsyXT09PXNvZnRsaW5lJDF8fGZbaCsyXT09PWhhcmRsaW5lJDMpLGI9ZltoXT09PXAmJiIiPT09ZltoKzFdJiZmW2grMl09PT1wO2cmJmR8fG18fHl8fGI/Zi5zcGxpY2UoaCwyKTp2JiZmLnNwbGljZShoKzEsMil9Zm9yKDtmLmxlbmd0aCYmKGlzTGluZU5leHQkMShnZXRMYXN0JDQoZikpfHxpc0VtcHR5JDEoZ2V0TGFzdCQ0KGYpKSk7KWYucG9wKCk7Zm9yKDtmLmxlbmd0aCYmKGlzTGluZU5leHQkMShmWzBdKXx8aXNFbXB0eSQxKGZbMF0pKSYmKGlzTGluZU5leHQkMShmWzFdKXx8aXNFbXB0eSQxKGZbMV0pKTspZi5zaGlmdCgpLGYuc2hpZnQoKTt2YXIgeD1bXTtmLmZvckVhY2goZnVuY3Rpb24oZSx0KXtpZihlPT09cCl7aWYoMT09PXQmJiIiPT09Zlt0LTFdKXJldHVybiAyPT09Zi5sZW5ndGg/dm9pZCB4LnB1c2gobCk6dm9pZCB4LnB1c2goY29uY2F0JDQoW2wsaGFyZGxpbmUkM10pKTtpZih0PT09Zi5sZW5ndGgtMSlyZXR1cm4gdm9pZCB4LnB1c2gobCk7aWYoIiI9PT1mW3QtMV0mJmZbdC0yXT09PWhhcmRsaW5lJDMpcmV0dXJuIHZvaWQgeC5wdXNoKGwpfXgucHVzaChlKSx3aWxsQnJlYWskMShlKSYmKGM9ITApfSk7dmFyIEM9ZD9maWxsJDIoeCk6Z3JvdXAkMShjb25jYXQkNCh4KSx7c2hvdWxkQnJlYWs6ITB9KSxFPWdyb3VwJDEoY29uY2F0JDQoW2ksaW5kZW50JDIoY29uY2F0JDQoW2hhcmRsaW5lJDMsQ10pKSxoYXJkbGluZSQzLG9dKSk7cmV0dXJuIGM/RTpjb25kaXRpb25hbEdyb3VwJDEoW2dyb3VwJDEoY29uY2F0JDQoW2ksY29uY2F0JDQoZiksb10pKSxFXSl9ZnVuY3Rpb24gbWF5YmVXcmFwSlNYRWxlbWVudEluUGFyZW5zKGUsdCl7dmFyIG49ZS5nZXRQYXJlbnROb2RlKCk7cmV0dXJuIG4/e0FycmF5RXhwcmVzc2lvbjohMCxKU1hBdHRyaWJ1dGU6ITAsSlNYRWxlbWVudDohMCxKU1hFeHByZXNzaW9uQ29udGFpbmVyOiEwLEpTWEZyYWdtZW50OiEwLFRTSnN4RnJhZ21lbnQ6ITAsRXhwcmVzc2lvblN0YXRlbWVudDohMCxDYWxsRXhwcmVzc2lvbjohMCxPcHRpb25hbENhbGxFeHByZXNzaW9uOiEwLENvbmRpdGlvbmFsRXhwcmVzc2lvbjohMH1bbi50eXBlXT90Omdyb3VwJDEoY29uY2F0JDQoW2lmQnJlYWskMSgiKCIpLGluZGVudCQyKGNvbmNhdCQ0KFtzb2Z0bGluZSQxLHRdKSksc29mdGxpbmUkMSxpZkJyZWFrJDEoIikiKV0pKTp0fWZ1bmN0aW9uIGlzQmluYXJ5aXNoKGUpe3JldHVybiJCaW5hcnlFeHByZXNzaW9uIj09PWUudHlwZXx8IkxvZ2ljYWxFeHByZXNzaW9uIj09PWUudHlwZX1mdW5jdGlvbiBpc01lbWJlcmlzaChlKXtyZXR1cm4iTWVtYmVyRXhwcmVzc2lvbiI9PT1lLnR5cGV8fCJPcHRpb25hbE1lbWJlckV4cHJlc3Npb24iPT09ZS50eXBlfHwiQmluZEV4cHJlc3Npb24iPT09ZS50eXBlJiZlLm9iamVjdH1mdW5jdGlvbiBzaG91bGRJbmxpbmVMb2dpY2FsRXhwcmVzc2lvbihlKXtyZXR1cm4iTG9naWNhbEV4cHJlc3Npb24iPT09ZS50eXBlJiYoIk9iamVjdEV4cHJlc3Npb24iPT09ZS5yaWdodC50eXBlJiYwIT09ZS5yaWdodC5wcm9wZXJ0aWVzLmxlbmd0aHx8KCJBcnJheUV4cHJlc3Npb24iPT09ZS5yaWdodC50eXBlJiYwIT09ZS5yaWdodC5lbGVtZW50cy5sZW5ndGh8fCEhaXNKU1hOb2RlKGUucmlnaHQpKSl9ZnVuY3Rpb24gcHJpbnRCaW5hcnlpc2hFeHByZXNzaW9ucyhlLHQsbixyLGkpe3ZhciBvPVtdLGE9ZS5nZXRWYWx1ZSgpO2lmKGlzQmluYXJ5aXNoKGEpKXtzaG91bGRGbGF0dGVuJDEoYS5vcGVyYXRvcixhLmxlZnQub3BlcmF0b3IpP289by5jb25jYXQoZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBwcmludEJpbmFyeWlzaEV4cHJlc3Npb25zKGUsdCxuLCEwLGkpfSwibGVmdCIpKTpvLnB1c2goZS5jYWxsKHQsImxlZnQiKSk7dmFyIHM9c2hvdWxkSW5saW5lTG9naWNhbEV4cHJlc3Npb24oYSksdT0ifD4iPT09YS5vcGVyYXRvcixjPWNvbmNhdCQ0KHM/W2Eub3BlcmF0b3IsIiAiLGUuY2FsbCh0LCJyaWdodCIpXTpbdT9zb2Z0bGluZSQxOiIiLGEub3BlcmF0b3IsdT8iICI6bGluZSQzLGUuY2FsbCh0LCJyaWdodCIpXSksbD1lLmdldFBhcmVudE5vZGUoKSxwPSEoaSYmIkxvZ2ljYWxFeHByZXNzaW9uIj09PWEudHlwZSkmJmwudHlwZSE9PWEudHlwZSYmYS5sZWZ0LnR5cGUhPT1hLnR5cGUmJmEucmlnaHQudHlwZSE9PWEudHlwZTtvLnB1c2goIiAiLHA/Z3JvdXAkMShjKTpjKSxyJiZhLmNvbW1lbnRzJiYobz1jb21tZW50cy5wcmludENvbW1lbnRzKGUsZnVuY3Rpb24oKXtyZXR1cm4gY29uY2F0JDQobyl9LG4pKX1lbHNlIG8ucHVzaChlLmNhbGwodCkpO3JldHVybiBvfWZ1bmN0aW9uIHByaW50QXNzaWdubWVudFJpZ2h0KGUsdCxuLHIpe3JldHVybiBoYXNMZWFkaW5nT3duTGluZUNvbW1lbnQoci5vcmlnaW5hbFRleHQsdCxyKT9pbmRlbnQkMihjb25jYXQkNChbaGFyZGxpbmUkMyxuXSkpOmlzQmluYXJ5aXNoKHQpJiYhc2hvdWxkSW5saW5lTG9naWNhbEV4cHJlc3Npb24odCl8fCJDb25kaXRpb25hbEV4cHJlc3Npb24iPT09dC50eXBlJiZpc0JpbmFyeWlzaCh0LnRlc3QpJiYhc2hvdWxkSW5saW5lTG9naWNhbEV4cHJlc3Npb24odC50ZXN0KXx8IlN0cmluZ0xpdGVyYWxUeXBlQW5ub3RhdGlvbiI9PT10LnR5cGV8fCgiSWRlbnRpZmllciI9PT1lLnR5cGV8fGlzU3RyaW5nTGl0ZXJhbChlKXx8Ik1lbWJlckV4cHJlc3Npb24iPT09ZS50eXBlKSYmKGlzU3RyaW5nTGl0ZXJhbCh0KXx8aXNNZW1iZXJFeHByZXNzaW9uQ2hhaW4odCkpP2luZGVudCQyKGNvbmNhdCQ0KFtsaW5lJDMsbl0pKTpjb25jYXQkNChbIiAiLG5dKX1mdW5jdGlvbiBwcmludEFzc2lnbm1lbnQoZSx0LG4scixpLG8pe2lmKCFyKXJldHVybiB0O3ZhciBhPXByaW50QXNzaWdubWVudFJpZ2h0KGUscixpLG8pO3JldHVybiBncm91cCQxKGNvbmNhdCQ0KFt0LG4sYV0pKX1mdW5jdGlvbiBhZGp1c3RDbGF1c2UoZSx0LG4pe3JldHVybiJFbXB0eVN0YXRlbWVudCI9PT1lLnR5cGU/IjsiOiJCbG9ja1N0YXRlbWVudCI9PT1lLnR5cGV8fG4/Y29uY2F0JDQoWyIgIix0XSk6aW5kZW50JDIoY29uY2F0JDQoW2xpbmUkMyx0XSkpfWZ1bmN0aW9uIG5vZGVTdHIoZSx0LG4pe3ZhciByPXJhd1RleHQoZSksaT1ufHwiRGlyZWN0aXZlTGl0ZXJhbCI9PT1lLnR5cGU7cmV0dXJuIHByaW50U3RyaW5nJDEocix0LGkpfWZ1bmN0aW9uIHByaW50UmVnZXgoZSl7dmFyIHQ9ZS5mbGFncy5zcGxpdCgiIikuc29ydCgpLmpvaW4oIiIpO3JldHVybiIvIi5jb25jYXQoZS5wYXR0ZXJuLCIvIikuY29uY2F0KHQpfWZ1bmN0aW9uIGlzTGFzdFN0YXRlbWVudChlKXt2YXIgdD1lLmdldFBhcmVudE5vZGUoKTtpZighdClyZXR1cm4hMDt2YXIgbj1lLmdldFZhbHVlKCkscj0odC5ib2R5fHx0LmNvbnNlcXVlbnQpLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4iRW1wdHlTdGF0ZW1lbnQiIT09ZS50eXBlfSk7cmV0dXJuIHImJnJbci5sZW5ndGgtMV09PT1ufWZ1bmN0aW9uIGhhc0xlYWRpbmdDb21tZW50KGUpe3JldHVybiBlLmNvbW1lbnRzJiZlLmNvbW1lbnRzLnNvbWUoZnVuY3Rpb24oZSl7cmV0dXJuIGUubGVhZGluZ30pfWZ1bmN0aW9uIGhhc1RyYWlsaW5nQ29tbWVudChlKXtyZXR1cm4gZS5jb21tZW50cyYmZS5jb21tZW50cy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiBlLnRyYWlsaW5nfSl9ZnVuY3Rpb24gaGFzTGVhZGluZ093bkxpbmVDb21tZW50KGUsdCxuKXtyZXR1cm4gaXNKU1hOb2RlKHQpP2hhc05vZGVJZ25vcmVDb21tZW50JDEodCk6dC5jb21tZW50cyYmdC5jb21tZW50cy5zb21lKGZ1bmN0aW9uKHQpe3JldHVybiB0LmxlYWRpbmcmJmhhc05ld2xpbmUkMihlLG4ubG9jRW5kKHQpKX0pfWZ1bmN0aW9uIGhhc05ha2VkTGVmdFNpZGUoZSl7cmV0dXJuIkFzc2lnbm1lbnRFeHByZXNzaW9uIj09PWUudHlwZXx8IkJpbmFyeUV4cHJlc3Npb24iPT09ZS50eXBlfHwiTG9naWNhbEV4cHJlc3Npb24iPT09ZS50eXBlfHwiQ29uZGl0aW9uYWxFeHByZXNzaW9uIj09PWUudHlwZXx8IkNhbGxFeHByZXNzaW9uIj09PWUudHlwZXx8Ik9wdGlvbmFsQ2FsbEV4cHJlc3Npb24iPT09ZS50eXBlfHwiTWVtYmVyRXhwcmVzc2lvbiI9PT1lLnR5cGV8fCJPcHRpb25hbE1lbWJlckV4cHJlc3Npb24iPT09ZS50eXBlfHwiU2VxdWVuY2VFeHByZXNzaW9uIj09PWUudHlwZXx8IlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbiI9PT1lLnR5cGV8fCJCaW5kRXhwcmVzc2lvbiI9PT1lLnR5cGUmJiFlLm9iamVjdHx8IlVwZGF0ZUV4cHJlc3Npb24iPT09ZS50eXBlJiYhZS5wcmVmaXh9ZnVuY3Rpb24gaXNGbG93QW5ub3RhdGlvbkNvbW1lbnQoZSx0LG4pe3ZhciByPW4ubG9jU3RhcnQodCksaT1za2lwV2hpdGVzcGFjZSQxKGUsbi5sb2NFbmQodCkpO3JldHVybiIvKiI9PT1lLnN1YnN0cihyLDIpJiYiKi8iPT09ZS5zdWJzdHIoaSwyKX1mdW5jdGlvbiBnZXRMZWZ0U2lkZShlKXtyZXR1cm4gZS5leHByZXNzaW9ucz9lLmV4cHJlc3Npb25zWzBdOmUubGVmdHx8ZS50ZXN0fHxlLmNhbGxlZXx8ZS5vYmplY3R8fGUudGFnfHxlLmFyZ3VtZW50fHxlLmV4cHJlc3Npb259ZnVuY3Rpb24gZ2V0TGVmdFNpZGVQYXRoTmFtZShlLHQpe2lmKHQuZXhwcmVzc2lvbnMpcmV0dXJuWyJleHByZXNzaW9ucyIsMF07aWYodC5sZWZ0KXJldHVyblsibGVmdCJdO2lmKHQudGVzdClyZXR1cm5bInRlc3QiXTtpZih0LmNhbGxlZSlyZXR1cm5bImNhbGxlZSJdO2lmKHQub2JqZWN0KXJldHVyblsib2JqZWN0Il07aWYodC50YWcpcmV0dXJuWyJ0YWciXTtpZih0LmFyZ3VtZW50KXJldHVyblsiYXJndW1lbnQiXTtpZih0LmV4cHJlc3Npb24pcmV0dXJuWyJleHByZXNzaW9uIl07dGhyb3cgbmV3IEVycm9yKCJVbmV4cGVjdGVkIG5vZGUgaGFzIG5vIGxlZnQgc2lkZSIsdCl9ZnVuY3Rpb24gZXhwck5lZWRzQVNJUHJvdGVjdGlvbihlLHQpe3ZhciBuPWUuZ2V0VmFsdWUoKTtyZXR1cm4hIShuZWVkc1BhcmVuc18xKGUsdCl8fCJQYXJlbnRoZXNpemVkRXhwcmVzc2lvbiI9PT1uLnR5cGV8fCJUeXBlQ2FzdEV4cHJlc3Npb24iPT09bi50eXBlfHwiQXJyb3dGdW5jdGlvbkV4cHJlc3Npb24iPT09bi50eXBlJiYhc2hvdWxkUHJpbnRQYXJhbXNXaXRob3V0UGFyZW5zKGUsdCl8fCJBcnJheUV4cHJlc3Npb24iPT09bi50eXBlfHwiQXJyYXlQYXR0ZXJuIj09PW4udHlwZXx8IlVuYXJ5RXhwcmVzc2lvbiI9PT1uLnR5cGUmJm4ucHJlZml4JiYoIisiPT09bi5vcGVyYXRvcnx8Ii0iPT09bi5vcGVyYXRvcil8fCJUZW1wbGF0ZUxpdGVyYWwiPT09bi50eXBlfHwiVGVtcGxhdGVFbGVtZW50Ij09PW4udHlwZXx8aXNKU1hOb2RlKG4pfHwiQmluZEV4cHJlc3Npb24iPT09bi50eXBlfHwiUmVnRXhwTGl0ZXJhbCI9PT1uLnR5cGV8fCJMaXRlcmFsIj09PW4udHlwZSYmbi5wYXR0ZXJufHwiTGl0ZXJhbCI9PT1uLnR5cGUmJm4ucmVnZXgpfHwhIWhhc05ha2VkTGVmdFNpZGUobikmJmUuY2FsbC5hcHBseShlLFtmdW5jdGlvbihlKXtyZXR1cm4gZXhwck5lZWRzQVNJUHJvdGVjdGlvbihlLHQpfV0uY29uY2F0KGdldExlZnRTaWRlUGF0aE5hbWUoZSxuKSkpfWZ1bmN0aW9uIHN0bXROZWVkc0FTSVByb3RlY3Rpb24oZSx0KXtyZXR1cm4iRXhwcmVzc2lvblN0YXRlbWVudCI9PT1lLmdldE5vZGUoKS50eXBlJiZlLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIGV4cHJOZWVkc0FTSVByb3RlY3Rpb24oZSx0KX0sImV4cHJlc3Npb24iKX1mdW5jdGlvbiBjbGFzc1Byb3BNYXlDYXVzZUFTSVByb2JsZW1zKGUpe3ZhciB0PWUuZ2V0Tm9kZSgpO2lmKCJDbGFzc1Byb3BlcnR5IiE9PXQudHlwZSlyZXR1cm4hMTt2YXIgbj10LmtleSYmdC5rZXkubmFtZTtyZXR1cm4hKCJzdGF0aWMiIT09biYmImdldCIhPT1uJiYic2V0IiE9PW58fHQudmFsdWV8fHQudHlwZUFubm90YXRpb24pfHx2b2lkIDB9ZnVuY3Rpb24gY2xhc3NDaGlsZE5lZWRzQVNJUHJvdGVjdGlvbihlKXtpZihlKXtpZighZS5jb21wdXRlZCl7dmFyIHQ9ZS5rZXkmJmUua2V5Lm5hbWU7aWYoImluIj09PXR8fCJpbnN0YW5jZW9mIj09PXQpcmV0dXJuITB9c3dpdGNoKGUudHlwZSl7Y2FzZSJDbGFzc1Byb3BlcnR5IjpjYXNlIlRTQWJzdHJhY3RDbGFzc1Byb3BlcnR5IjpyZXR1cm4gZS5jb21wdXRlZDtjYXNlIk1ldGhvZERlZmluaXRpb24iOmNhc2UiVFNBYnN0cmFjdE1ldGhvZERlZmluaXRpb24iOmNhc2UiQ2xhc3NNZXRob2QiOnZhciBuPWUudmFsdWU/ZS52YWx1ZS5hc3luYzplLmFzeW5jLHI9ZS52YWx1ZT9lLnZhbHVlLmdlbmVyYXRvcjplLmdlbmVyYXRvcjtyZXR1cm4hbiYmIWUuc3RhdGljJiYiZ2V0IiE9PWUua2luZCYmInNldCIhPT1lLmtpbmQmJiEoIWUuY29tcHV0ZWQmJiFyKTtkZWZhdWx0OnJldHVybiExfX19ZnVuY3Rpb24gcmV0dXJuQXJndW1lbnRIYXNMZWFkaW5nQ29tbWVudChlLHQpe2lmKGhhc0xlYWRpbmdPd25MaW5lQ29tbWVudChlLm9yaWdpbmFsVGV4dCx0LGUpKXJldHVybiEwO2lmKGhhc05ha2VkTGVmdFNpZGUodCkpZm9yKHZhciBuLHI9dDtuPWdldExlZnRTaWRlKHIpOylpZihyPW4saGFzTGVhZGluZ093bkxpbmVDb21tZW50KGUub3JpZ2luYWxUZXh0LHIsZSkpcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gaXNNZW1iZXJFeHByZXNzaW9uQ2hhaW4oZSl7cmV0dXJuKCJNZW1iZXJFeHByZXNzaW9uIj09PWUudHlwZXx8Ik9wdGlvbmFsTWVtYmVyRXhwcmVzc2lvbiI9PT1lLnR5cGUpJiYoIklkZW50aWZpZXIiPT09ZS5vYmplY3QudHlwZXx8aXNNZW1iZXJFeHByZXNzaW9uQ2hhaW4oZS5vYmplY3QpKX1mdW5jdGlvbiBpc09iamVjdFR5cGVQcm9wZXJ0eUFGdW5jdGlvbihlLHQpe3JldHVybiJPYmplY3RUeXBlUHJvcGVydHkiPT09ZS50eXBlJiYiRnVuY3Rpb25UeXBlQW5ub3RhdGlvbiI9PT1lLnZhbHVlLnR5cGUmJiFlLnN0YXRpYyYmIWlzRnVuY3Rpb25Ob3RhdGlvbihlLHQpfWZ1bmN0aW9uIGlzRnVuY3Rpb25Ob3RhdGlvbihlLHQpe3JldHVybiBpc0dldHRlck9yU2V0dGVyKGUpfHxzYW1lTG9jU3RhcnQoZSxlLnZhbHVlLHQpfWZ1bmN0aW9uIGlzR2V0dGVyT3JTZXR0ZXIoZSl7cmV0dXJuImdldCI9PT1lLmtpbmR8fCJzZXQiPT09ZS5raW5kfWZ1bmN0aW9uIHNhbWVMb2NTdGFydChlLHQsbil7cmV0dXJuIG4ubG9jU3RhcnQoZSk9PT1uLmxvY1N0YXJ0KHQpfWZ1bmN0aW9uIGlzVHlwZUFubm90YXRpb25BRnVuY3Rpb24oZSx0KXtyZXR1cm4oIlR5cGVBbm5vdGF0aW9uIj09PWUudHlwZXx8IlRTVHlwZUFubm90YXRpb24iPT09ZS50eXBlKSYmIkZ1bmN0aW9uVHlwZUFubm90YXRpb24iPT09ZS50eXBlQW5ub3RhdGlvbi50eXBlJiYhZS5zdGF0aWMmJiFzYW1lTG9jU3RhcnQoZSxlLnR5cGVBbm5vdGF0aW9uLHQpfWZ1bmN0aW9uIGlzTm9kZVN0YXJ0aW5nV2l0aERlY2xhcmUoZSx0KXtyZXR1cm4oImZsb3ciPT09dC5wYXJzZXJ8fCJ0eXBlc2NyaXB0Ij09PXQucGFyc2VyKSYmKHQub3JpZ2luYWxUZXh0LnNsaWNlKDAsdC5sb2NTdGFydChlKSkubWF0Y2goL2RlY2xhcmVbIFx0XSokLyl8fHQub3JpZ2luYWxUZXh0LnNsaWNlKGUucmFuZ2VbMF0sZS5yYW5nZVsxXSkuc3RhcnRzV2l0aCgiZGVjbGFyZSAiKSl9ZnVuY3Rpb24gc2hvdWxkSHVnVHlwZShlKXtpZihpc09iamVjdFR5cGUoZSkpcmV0dXJuITA7aWYoIlVuaW9uVHlwZUFubm90YXRpb24iPT09ZS50eXBlfHwiVFNVbmlvblR5cGUiPT09ZS50eXBlKXt2YXIgdD1lLnR5cGVzLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4iVm9pZFR5cGVBbm5vdGF0aW9uIj09PWUudHlwZXx8IlRTVm9pZEtleXdvcmQiPT09ZS50eXBlfHwiTnVsbExpdGVyYWxUeXBlQW5ub3RhdGlvbiI9PT1lLnR5cGV8fCJUU051bGxLZXl3b3JkIj09PWUudHlwZX0pLmxlbmd0aCxuPWUudHlwZXMuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiJPYmplY3RUeXBlQW5ub3RhdGlvbiI9PT1lLnR5cGV8fCJUU1R5cGVMaXRlcmFsIj09PWUudHlwZXx8IkdlbmVyaWNUeXBlQW5ub3RhdGlvbiI9PT1lLnR5cGV8fCJUU1R5cGVSZWZlcmVuY2UiPT09ZS50eXBlfSkubGVuZ3RoO2lmKGUudHlwZXMubGVuZ3RoLTE9PT10JiZuPjApcmV0dXJuITB9cmV0dXJuITF9ZnVuY3Rpb24gc2hvdWxkSHVnQXJndW1lbnRzKGUpe3JldHVybiBlJiZlLnBhcmFtcyYmMT09PWUucGFyYW1zLmxlbmd0aCYmIWUucGFyYW1zWzBdLmNvbW1lbnRzJiYoIk9iamVjdFBhdHRlcm4iPT09ZS5wYXJhbXNbMF0udHlwZXx8IkFycmF5UGF0dGVybiI9PT1lLnBhcmFtc1swXS50eXBlfHwiSWRlbnRpZmllciI9PT1lLnBhcmFtc1swXS50eXBlJiZlLnBhcmFtc1swXS50eXBlQW5ub3RhdGlvbiYmKCJUeXBlQW5ub3RhdGlvbiI9PT1lLnBhcmFtc1swXS50eXBlQW5ub3RhdGlvbi50eXBlfHwiVFNUeXBlQW5ub3RhdGlvbiI9PT1lLnBhcmFtc1swXS50eXBlQW5ub3RhdGlvbi50eXBlKSYmaXNPYmplY3RUeXBlKGUucGFyYW1zWzBdLnR5cGVBbm5vdGF0aW9uLnR5cGVBbm5vdGF0aW9uKXx8IkZ1bmN0aW9uVHlwZVBhcmFtIj09PWUucGFyYW1zWzBdLnR5cGUmJmlzT2JqZWN0VHlwZShlLnBhcmFtc1swXS50eXBlQW5ub3RhdGlvbil8fCJBc3NpZ25tZW50UGF0dGVybiI9PT1lLnBhcmFtc1swXS50eXBlJiYoIk9iamVjdFBhdHRlcm4iPT09ZS5wYXJhbXNbMF0ubGVmdC50eXBlfHwiQXJyYXlQYXR0ZXJuIj09PWUucGFyYW1zWzBdLmxlZnQudHlwZSkmJigiSWRlbnRpZmllciI9PT1lLnBhcmFtc1swXS5yaWdodC50eXBlfHwiT2JqZWN0RXhwcmVzc2lvbiI9PT1lLnBhcmFtc1swXS5yaWdodC50eXBlJiYwPT09ZS5wYXJhbXNbMF0ucmlnaHQucHJvcGVydGllcy5sZW5ndGh8fCJBcnJheUV4cHJlc3Npb24iPT09ZS5wYXJhbXNbMF0ucmlnaHQudHlwZSYmMD09PWUucGFyYW1zWzBdLnJpZ2h0LmVsZW1lbnRzLmxlbmd0aCkpJiYhZS5yZXN0fWZ1bmN0aW9uIHRlbXBsYXRlTGl0ZXJhbEhhc05ld0xpbmVzKGUpe3JldHVybiBlLnF1YXNpcy5zb21lKGZ1bmN0aW9uKGUpe3JldHVybiBlLnZhbHVlLnJhdy5pbmNsdWRlcygiXG4iKX0pfWZ1bmN0aW9uIGlzVGVtcGxhdGVPbkl0c093bkxpbmUoZSx0LG4pe3JldHVybigiVGVtcGxhdGVMaXRlcmFsIj09PWUudHlwZSYmdGVtcGxhdGVMaXRlcmFsSGFzTmV3TGluZXMoZSl8fCJUYWdnZWRUZW1wbGF0ZUV4cHJlc3Npb24iPT09ZS50eXBlJiZ0ZW1wbGF0ZUxpdGVyYWxIYXNOZXdMaW5lcyhlLnF1YXNpKSkmJiFoYXNOZXdsaW5lJDIodCxuLmxvY1N0YXJ0KGUpLHtiYWNrd2FyZHM6ITB9KX1mdW5jdGlvbiBwcmludEFycmF5SXRlbXMoZSx0LG4scil7dmFyIGk9W10sbz1bXTtyZXR1cm4gZS5lYWNoKGZ1bmN0aW9uKGUpe2kucHVzaChjb25jYXQkNChvKSksaS5wdXNoKGdyb3VwJDEocihlKSkpLG89WyIsIixsaW5lJDNdLGUuZ2V0VmFsdWUoKSYmaXNOZXh0TGluZUVtcHR5JDIodC5vcmlnaW5hbFRleHQsZS5nZXRWYWx1ZSgpLHQpJiZvLnB1c2goc29mdGxpbmUkMSl9LG4pLGNvbmNhdCQ0KGkpfWZ1bmN0aW9uIGhhc0RhbmdsaW5nQ29tbWVudHMoZSl7cmV0dXJuIGUuY29tbWVudHMmJmUuY29tbWVudHMuc29tZShmdW5jdGlvbihlKXtyZXR1cm4hZS5sZWFkaW5nJiYhZS50cmFpbGluZ30pfWZ1bmN0aW9uIG5lZWRzSGFyZGxpbmVBZnRlckRhbmdsaW5nQ29tbWVudChlKXtpZighZS5jb21tZW50cylyZXR1cm4hMTt2YXIgdD1nZXRMYXN0JDQoZS5jb21tZW50cy5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIWUubGVhZGluZyYmIWUudHJhaWxpbmd9KSk7cmV0dXJuIHQmJiFjb21tZW50cyQzLmlzQmxvY2tDb21tZW50KHQpfWZ1bmN0aW9uIGlzTGl0ZXJhbChlKXtyZXR1cm4iQm9vbGVhbkxpdGVyYWwiPT09ZS50eXBlfHwiRGlyZWN0aXZlTGl0ZXJhbCI9PT1lLnR5cGV8fCJMaXRlcmFsIj09PWUudHlwZXx8Ik51bGxMaXRlcmFsIj09PWUudHlwZXx8Ik51bWVyaWNMaXRlcmFsIj09PWUudHlwZXx8IlJlZ0V4cExpdGVyYWwiPT09ZS50eXBlfHwiU3RyaW5nTGl0ZXJhbCI9PT1lLnR5cGV8fCJUZW1wbGF0ZUxpdGVyYWwiPT09ZS50eXBlfHwiVFNUeXBlTGl0ZXJhbCI9PT1lLnR5cGV8fCJKU1hUZXh0Ij09PWUudHlwZX1mdW5jdGlvbiBpc051bWVyaWNMaXRlcmFsKGUpe3JldHVybiJOdW1lcmljTGl0ZXJhbCI9PT1lLnR5cGV8fCJMaXRlcmFsIj09PWUudHlwZSYmIm51bWJlciI9PT10eXBlb2YgZS52YWx1ZX1mdW5jdGlvbiBpc1N0cmluZ0xpdGVyYWwoZSl7cmV0dXJuIlN0cmluZ0xpdGVyYWwiPT09ZS50eXBlfHwiTGl0ZXJhbCI9PT1lLnR5cGUmJiJzdHJpbmciPT09dHlwZW9mIGUudmFsdWV9ZnVuY3Rpb24gaXNPYmplY3RUeXBlKGUpe3JldHVybiJPYmplY3RUeXBlQW5ub3RhdGlvbiI9PT1lLnR5cGV8fCJUU1R5cGVMaXRlcmFsIj09PWUudHlwZX1mdW5jdGlvbiBpc1Rlc3RDYWxsKGUsdCl7aWYoIkNhbGxFeHByZXNzaW9uIiE9PWUudHlwZSlyZXR1cm4hMTtpZigxPT09ZS5hcmd1bWVudHMubGVuZ3RoKXtpZihpc0FuZ3VsYXJUZXN0V3JhcHBlcihlKSYmdCYmaXNUZXN0Q2FsbCh0KSlyZXR1cm4gaXNGdW5jdGlvbk9yQXJyb3dFeHByZXNzaW9uKGUuYXJndW1lbnRzWzBdLnR5cGUpO2lmKGlzVW5pdFRlc3RTZXRVcChlKSlyZXR1cm4gaXNGdW5jdGlvbk9yQXJyb3dFeHByZXNzaW9uKGUuYXJndW1lbnRzWzBdLnR5cGUpfHxpc0FuZ3VsYXJUZXN0V3JhcHBlcihlLmFyZ3VtZW50c1swXSl9ZWxzZSBpZigyPT09ZS5hcmd1bWVudHMubGVuZ3RoJiYoIklkZW50aWZpZXIiPT09ZS5jYWxsZWUudHlwZSYmdW5pdFRlc3RSZS50ZXN0KGUuY2FsbGVlLm5hbWUpfHxpc1NraXBPck9ubHlCbG9jayhlKSkmJihpc1RlbXBsYXRlTGl0ZXJhbChlLmFyZ3VtZW50c1swXSl8fGlzU3RyaW5nTGl0ZXJhbChlLmFyZ3VtZW50c1swXSkpKXJldHVybiBpc0Z1bmN0aW9uT3JBcnJvd0V4cHJlc3Npb24oZS5hcmd1bWVudHNbMV0udHlwZSkmJmUuYXJndW1lbnRzWzFdLnBhcmFtcy5sZW5ndGg8PTF8fGlzQW5ndWxhclRlc3RXcmFwcGVyKGUuYXJndW1lbnRzWzFdKTtyZXR1cm4hMX1mdW5jdGlvbiBpc1NraXBPck9ubHlCbG9jayhlKXtyZXR1cm4oIk1lbWJlckV4cHJlc3Npb24iPT09ZS5jYWxsZWUudHlwZXx8Ik9wdGlvbmFsTWVtYmVyRXhwcmVzc2lvbiI9PT1lLmNhbGxlZS50eXBlKSYmIklkZW50aWZpZXIiPT09ZS5jYWxsZWUub2JqZWN0LnR5cGUmJiJJZGVudGlmaWVyIj09PWUuY2FsbGVlLnByb3BlcnR5LnR5cGUmJnVuaXRUZXN0UmUudGVzdChlLmNhbGxlZS5vYmplY3QubmFtZSkmJigib25seSI9PT1lLmNhbGxlZS5wcm9wZXJ0eS5uYW1lfHwic2tpcCI9PT1lLmNhbGxlZS5wcm9wZXJ0eS5uYW1lKX1mdW5jdGlvbiBpc1RlbXBsYXRlTGl0ZXJhbChlKXtyZXR1cm4iVGVtcGxhdGVMaXRlcmFsIj09PWUudHlwZX1mdW5jdGlvbiBpc0FuZ3VsYXJUZXN0V3JhcHBlcihlKXtyZXR1cm4oIkNhbGxFeHByZXNzaW9uIj09PWUudHlwZXx8Ik9wdGlvbmFsQ2FsbEV4cHJlc3Npb24iPT09ZS50eXBlKSYmIklkZW50aWZpZXIiPT09ZS5jYWxsZWUudHlwZSYmKCJhc3luYyI9PT1lLmNhbGxlZS5uYW1lfHwiaW5qZWN0Ij09PWUuY2FsbGVlLm5hbWUpfWZ1bmN0aW9uIGlzRnVuY3Rpb25PckFycm93RXhwcmVzc2lvbihlKXtyZXR1cm4iRnVuY3Rpb25FeHByZXNzaW9uIj09PWV8fCJBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbiI9PT1lfWZ1bmN0aW9uIGlzVW5pdFRlc3RTZXRVcChlKXt2YXIgdD0vXihiZWZvcmV8YWZ0ZXIpKEVhY2h8QWxsKSQvO3JldHVybiJJZGVudGlmaWVyIj09PWUuY2FsbGVlLnR5cGUmJnQudGVzdChlLmNhbGxlZS5uYW1lKSYmMT09PWUuYXJndW1lbnRzLmxlbmd0aH1mdW5jdGlvbiBpc1RoZU9ubHlKU1hFbGVtZW50SW5NYXJrZG93bihlLHQpe2lmKCJtYXJrZG93biIhPT1lLnBhcmVudFBhcnNlcilyZXR1cm4hMTt2YXIgbj10LmdldE5vZGUoKTtpZighbi5leHByZXNzaW9ufHwhaXNKU1hOb2RlKG4uZXhwcmVzc2lvbikpcmV0dXJuITE7dmFyIHI9dC5nZXRQYXJlbnROb2RlKCk7cmV0dXJuIlByb2dyYW0iPT09ci50eXBlJiYxPT1yLmJvZHkubGVuZ3RofWZ1bmN0aW9uIHdpbGxQcmludE93bkNvbW1lbnRzKGUpe3ZhciB0PWUuZ2V0VmFsdWUoKSxuPWUuZ2V0UGFyZW50Tm9kZSgpO3JldHVybih0JiZpc0pTWE5vZGUodCl8fG4mJigiSlNYU3ByZWFkQXR0cmlidXRlIj09PW4udHlwZXx8IkpTWFNwcmVhZENoaWxkIj09PW4udHlwZXx8IlVuaW9uVHlwZUFubm90YXRpb24iPT09bi50eXBlfHwiVFNVbmlvblR5cGUiPT09bi50eXBlfHwoIkNsYXNzRGVjbGFyYXRpb24iPT09bi50eXBlfHwiQ2xhc3NFeHByZXNzaW9uIj09PW4udHlwZSkmJm4uc3VwZXJDbGFzcz09PXQpKSYmIWhhc0lnbm9yZUNvbW1lbnQkMShlKX1mdW5jdGlvbiBjYW5BdHRhY2hDb21tZW50KGUpe3JldHVybiBlLnR5cGUmJiJDb21tZW50QmxvY2siIT09ZS50eXBlJiYiQ29tbWVudExpbmUiIT09ZS50eXBlJiYiTGluZSIhPT1lLnR5cGUmJiJCbG9jayIhPT1lLnR5cGUmJiJFbXB0eVN0YXRlbWVudCIhPT1lLnR5cGUmJiJUZW1wbGF0ZUVsZW1lbnQiIT09ZS50eXBlJiYiSW1wb3J0IiE9PWUudHlwZSYmIShlLmNhbGxlZSYmIkltcG9ydCI9PT1lLmNhbGxlZS50eXBlKX1mdW5jdGlvbiBwcmludENvbW1lbnQkMShlLHQpe3ZhciBuPWUuZ2V0VmFsdWUoKTtzd2l0Y2gobi50eXBlKXtjYXNlIkNvbW1lbnRCbG9jayI6Y2FzZSJCbG9jayI6aWYoaXNKc0RvY0NvbW1lbnQobikpe3ZhciByPXByaW50SnNEb2NDb21tZW50KG4pO3JldHVybiBuLnRyYWlsaW5nJiYhaGFzTmV3bGluZSQyKHQub3JpZ2luYWxUZXh0LHQubG9jU3RhcnQobikse2JhY2t3YXJkczohMH0pP2NvbmNhdCQ0KFtoYXJkbGluZSQzLHJdKTpyfXZhciBpPSIqLS8iPT09dC5vcmlnaW5hbFRleHQuc3Vic3RyKHQubG9jRW5kKG4pLTMsMyk7cmV0dXJuIi8qIituLnZhbHVlKyhpPyIqLS8iOiIqLyIpO2Nhc2UiQ29tbWVudExpbmUiOmNhc2UiTGluZSI6cmV0dXJuIHQub3JpZ2luYWxUZXh0LnNsaWNlKHQubG9jU3RhcnQobikpLnN0YXJ0c1dpdGgoIiMhIik/IiMhIituLnZhbHVlLnRyaW1SaWdodCgpOiIvLyIrbi52YWx1ZS50cmltUmlnaHQoKTtkZWZhdWx0OnRocm93IG5ldyBFcnJvcigiTm90IGEgY29tbWVudDogIitKU09OLnN0cmluZ2lmeShuKSl9fWZ1bmN0aW9uIGlzSnNEb2NDb21tZW50KGUpe3ZhciB0PWUudmFsdWUuc3BsaXQoIlxuIik7cmV0dXJuIHQubGVuZ3RoPjEmJnQuc2xpY2UoMCx0Lmxlbmd0aC0xKS5ldmVyeShmdW5jdGlvbihlKXtyZXR1cm4iKiI9PT1lLnRyaW0oKVswXX0pfWZ1bmN0aW9uIHByaW50SnNEb2NDb21tZW50KGUpe3ZhciB0PWUudmFsdWUuc3BsaXQoIlxuIik7cmV0dXJuIGNvbmNhdCQ0KFsiLyoiLGpvaW4kMihoYXJkbGluZSQzLHQubWFwKGZ1bmN0aW9uKGUsbil7cmV0dXJuKG4+MD8iICI6IiIpKyhuPHQubGVuZ3RoLTE/ZS50cmltKCk6ZS50cmltTGVmdCgpKX0pKSwiKi8iXSl9ZnVuY3Rpb24gcmF3VGV4dChlKXtyZXR1cm4gZS5leHRyYT9lLmV4dHJhLnJhdzplLnJhd31mdW5jdGlvbiBnZW5lcmljUHJpbnQkMihlLHQsbil7dmFyIHI9ZS5nZXRWYWx1ZSgpO3N3aXRjaChyLnR5cGUpe2Nhc2UiQXJyYXlFeHByZXNzaW9uIjpyZXR1cm4gMD09PXIuZWxlbWVudHMubGVuZ3RoPyJbXSI6Y29uY2F0JDYoWyJbIixpbmRlbnQkNChjb25jYXQkNihbaGFyZGxpbmUkNSxqb2luJDQoY29uY2F0JDYoWyIsIixoYXJkbGluZSQ1XSksZS5tYXAobiwiZWxlbWVudHMiKSldKSksaGFyZGxpbmUkNSwiXSJdKTtjYXNlIk9iamVjdEV4cHJlc3Npb24iOnJldHVybiAwPT09ci5wcm9wZXJ0aWVzLmxlbmd0aD8ie30iOmNvbmNhdCQ2KFsieyIsaW5kZW50JDQoY29uY2F0JDYoW2hhcmRsaW5lJDUsam9pbiQ0KGNvbmNhdCQ2KFsiLCIsaGFyZGxpbmUkNV0pLGUubWFwKG4sInByb3BlcnRpZXMiKSldKSksaGFyZGxpbmUkNSwifSJdKTtjYXNlIk9iamVjdFByb3BlcnR5IjpyZXR1cm4gY29uY2F0JDYoW2UuY2FsbChuLCJrZXkiKSwiOiAiLGUuY2FsbChuLCJ2YWx1ZSIpXSk7Y2FzZSJVbmFyeUV4cHJlc3Npb24iOnJldHVybiBjb25jYXQkNihbIisiPT09ci5vcGVyYXRvcj8iIjpyLm9wZXJhdG9yLGUuY2FsbChuLCJhcmd1bWVudCIpXSk7Y2FzZSJOdWxsTGl0ZXJhbCI6cmV0dXJuIm51bGwiO2Nhc2UiQm9vbGVhbkxpdGVyYWwiOnJldHVybiByLnZhbHVlPyJ0cnVlIjoiZmFsc2UiO2Nhc2UiU3RyaW5nTGl0ZXJhbCI6Y2FzZSJOdW1lcmljTGl0ZXJhbCI6cmV0dXJuIEpTT04uc3RyaW5naWZ5KHIudmFsdWUpO2Nhc2UiSWRlbnRpZmllciI6cmV0dXJuIEpTT04uc3RyaW5naWZ5KHIubmFtZSl9fWZ1bmN0aW9uIGNsZWFuJDIoZSx0KXtyZXR1cm4gZGVsZXRlIHQuc3RhcnQsZGVsZXRlIHQuZW5kLGRlbGV0ZSB0LmV4dHJhLGRlbGV0ZSB0LmxvYyxkZWxldGUgdC5jb21tZW50cywiSWRlbnRpZmllciI9PT1lLnR5cGU/e3R5cGU6IlN0cmluZ0xpdGVyYWwiLHZhbHVlOmUubmFtZX06IlVuYXJ5RXhwcmVzc2lvbiI9PT1lLnR5cGUmJiIrIj09PWUub3BlcmF0b3I/dC5hcmd1bWVudDp2b2lkIDB9ZnVuY3Rpb24gY2xlYW4kMyhlLHQpe2lmKFsicmF3cyIsInNvdXJjZUluZGV4Iiwic291cmNlIiwiYmVmb3JlIiwiYWZ0ZXIiLCJ0cmFpbGluZ0NvbW1hIl0uZm9yRWFjaChmdW5jdGlvbihlKXtkZWxldGUgdFtlXX0pLCJtZWRpYS1xdWVyeSIhPT1lLnR5cGUmJiJtZWRpYS1xdWVyeS1saXN0IiE9PWUudHlwZSYmIm1lZGlhLWZlYXR1cmUtZXhwcmVzc2lvbiIhPT1lLnR5cGV8fGRlbGV0ZSB0LnZhbHVlLCJjc3MtcnVsZSI9PT1lLnR5cGUmJmRlbGV0ZSB0LnBhcmFtcywic2VsZWN0b3ItY29tYmluYXRvciI9PT1lLnR5cGUmJih0LnZhbHVlPXQudmFsdWUucmVwbGFjZSgvXHMrL2csIiAiKSksIm1lZGlhLWZlYXR1cmUiPT09ZS50eXBlJiYodC52YWx1ZT10LnZhbHVlLnJlcGxhY2UoLyAvZywiIikpLCgidmFsdWUtd29yZCI9PT1lLnR5cGUmJihlLmlzQ29sb3ImJmUuaXNIZXh8fC0xIT09WyJpbml0aWFsIiwiaW5oZXJpdCIsInVuc2V0IiwicmV2ZXJ0Il0uaW5kZXhPZih0LnZhbHVlLnJlcGxhY2UoKS50b0xvd2VyQ2FzZSgpKSl8fCJtZWRpYS1mZWF0dXJlIj09PWUudHlwZXx8InNlbGVjdG9yLXJvb3QtaW52YWxpZCI9PT1lLnR5cGV8fCJzZWxlY3Rvci1wc2V1ZG8iPT09ZS50eXBlKSYmKHQudmFsdWU9dC52YWx1ZS50b0xvd2VyQ2FzZSgpKSwiY3NzLWRlY2wiPT09ZS50eXBlJiYodC5wcm9wPXQucHJvcC50b0xvd2VyQ2FzZSgpKSwiY3NzLWF0cnVsZSIhPT1lLnR5cGUmJiJjc3MtaW1wb3J0IiE9PWUudHlwZXx8KHQubmFtZT10Lm5hbWUudG9Mb3dlckNhc2UoKSksInZhbHVlLW51bWJlciI9PT1lLnR5cGUmJih0LnVuaXQ9dC51bml0LnRvTG93ZXJDYXNlKCkpLCJtZWRpYS1mZWF0dXJlIiE9PWUudHlwZSYmIm1lZGlhLWtleXdvcmQiIT09ZS50eXBlJiYibWVkaWEtdHlwZSIhPT1lLnR5cGUmJiJtZWRpYS11bmtub3duIiE9PWUudHlwZSYmIm1lZGlhLXVybCIhPT1lLnR5cGUmJiJtZWRpYS12YWx1ZSIhPT1lLnR5cGUmJiJzZWxlY3Rvci1hdHRyaWJ1dGUiIT09ZS50eXBlJiYic2VsZWN0b3Itc3RyaW5nIiE9PWUudHlwZSYmInNlbGVjdG9yLWNsYXNzIiE9PWUudHlwZSYmInNlbGVjdG9yLWNvbWJpbmF0b3IiIT09ZS50eXBlJiYidmFsdWUtc3RyaW5nIiE9PWUudHlwZXx8IXQudmFsdWV8fCh0LnZhbHVlPWNsZWFuQ1NTU3RyaW5ncyh0LnZhbHVlKSksInNlbGVjdG9yLWF0dHJpYnV0ZSI9PT1lLnR5cGUmJih0LmF0dHJpYnV0ZT10LmF0dHJpYnV0ZS50cmltKCksdC5uYW1lc3BhY2UmJiJzdHJpbmciPT09dHlwZW9mIHQubmFtZXNwYWNlJiYodC5uYW1lc3BhY2U9dC5uYW1lc3BhY2UudHJpbSgpLDA9PT10Lm5hbWVzcGFjZS5sZW5ndGgmJih0Lm5hbWVzcGFjZT0hMCkpLHQudmFsdWUmJih0LnZhbHVlPXQudmFsdWUudHJpbSgpLnJlcGxhY2UoL15bJyJdfFsnIl0kL2csIiIpLGRlbGV0ZSB0LnF1b3RlZCkpLCJtZWRpYS12YWx1ZSIhPT1lLnR5cGUmJiJtZWRpYS10eXBlIiE9PWUudHlwZSYmInZhbHVlLW51bWJlciIhPT1lLnR5cGUmJiJzZWxlY3Rvci1yb290LWludmFsaWQiIT09ZS50eXBlJiYic2VsZWN0b3ItY2xhc3MiIT09ZS50eXBlJiYic2VsZWN0b3ItY29tYmluYXRvciIhPT1lLnR5cGUmJiJzZWxlY3Rvci10YWciIT09ZS50eXBlfHwhdC52YWx1ZXx8KHQudmFsdWU9dC52YWx1ZS5yZXBsYWNlKC8oW1xkLmVFKy1dKykoW2EtekEtWl0qKS9nLGZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1OdW1iZXIodCk7cmV0dXJuIGlzTmFOKHIpP2U6cituLnRvTG93ZXJDYXNlKCl9KSksInNlbGVjdG9yLXRhZyI9PT1lLnR5cGUpe3ZhciBuPWUudmFsdWUudG9Mb3dlckNhc2UoKTstMSE9PWh0bWxUYWdOYW1lcyQxLmluZGV4T2YobikmJih0LnZhbHVlPW4pLC0xIT09WyJmcm9tIiwidG8iXS5pbmRleE9mKG4pJiYodC52YWx1ZT1uKX0iY3NzLWF0cnVsZSI9PT1lLnR5cGUmJiJzdXBwb3J0cyI9PT1lLm5hbWUudG9Mb3dlckNhc2UoKSYmZGVsZXRlIHQudmFsdWUsInNlbGVjdG9yLXVua25vd24iPT09ZS50eXBlJiZkZWxldGUgdC52YWx1ZX1mdW5jdGlvbiBjbGVhbkNTU1N0cmluZ3MoZSl7cmV0dXJuIGUucmVwbGFjZSgvJy9nLCciJykucmVwbGFjZSgvXFwoW15hLWZBLUZcZF0pL2csIiQxIil9ZnVuY3Rpb24gZ2V0QW5jZXN0b3JDb3VudGVyKGUsdCl7Zm9yKHZhciBuLHI9W10uY29uY2F0KHQpLGk9LTE7bj1lLmdldFBhcmVudE5vZGUoKytpKTspaWYoLTEhPT1yLmluZGV4T2Yobi50eXBlKSlyZXR1cm4gaTtyZXR1cm4tMX1mdW5jdGlvbiBnZXRBbmNlc3Rvck5vZGUkMShlLHQpe3ZhciBuPWdldEFuY2VzdG9yQ291bnRlcihlLHQpO3JldHVybi0xPT09bj9udWxsOmUuZ2V0UGFyZW50Tm9kZShuKX1mdW5jdGlvbiBnZXRQcm9wT2ZEZWNsTm9kZSQxKGUpe3ZhciB0PWdldEFuY2VzdG9yTm9kZSQxKGUsImNzcy1kZWNsIik7cmV0dXJuIHQmJnQucHJvcCYmdC5wcm9wLnRvTG93ZXJDYXNlKCl9ZnVuY3Rpb24gaXNTQ1NTJDEoZSx0KXt2YXIgbj0ibGVzcyI9PT1lfHwic2NzcyI9PT1lLHI9Lyhcd1xzKjogW159Ol0rfCMpe3xAaW1wb3J0W15cbl0rKHVybHwsKS87cmV0dXJuIG4/InNjc3MiPT09ZTpyLnRlc3QodCl9ZnVuY3Rpb24gaXNXaWRlS2V5d29yZHMkMShlKXtyZXR1cm4tMSE9PVsiaW5pdGlhbCIsImluaGVyaXQiLCJ1bnNldCIsInJldmVydCJdLmluZGV4T2YoZS50b0xvd2VyQ2FzZSgpKX1mdW5jdGlvbiBpc0tleWZyYW1lQXRSdWxlS2V5d29yZHMkMShlLHQpe3ZhciBuPWdldEFuY2VzdG9yTm9kZSQxKGUsImNzcy1hdHJ1bGUiKTtyZXR1cm4gbiYmbi5uYW1lJiZuLm5hbWUudG9Mb3dlckNhc2UoKS5lbmRzV2l0aCgia2V5ZnJhbWVzIikmJi0xIT09WyJmcm9tIiwidG8iXS5pbmRleE9mKHQudG9Mb3dlckNhc2UoKSl9ZnVuY3Rpb24gbWF5YmVUb0xvd2VyQ2FzZSQxKGUpe3JldHVybiBlLmluY2x1ZGVzKCIkIil8fGUuaW5jbHVkZXMoIkAiKXx8ZS5pbmNsdWRlcygiIyIpfHxlLnN0YXJ0c1dpdGgoIiUiKXx8ZS5zdGFydHNXaXRoKCItLSIpfHxlLnN0YXJ0c1dpdGgoIjotLSIpfHxlLmluY2x1ZGVzKCIoIikmJmUuaW5jbHVkZXMoIikiKT9lOmUudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBpbnNpZGVWYWx1ZUZ1bmN0aW9uTm9kZSQxKGUsdCl7dmFyIG49Z2V0QW5jZXN0b3JOb2RlJDEoZSwidmFsdWUtZnVuYyIpO3JldHVybiBuJiZuLnZhbHVlJiZuLnZhbHVlLnRvTG93ZXJDYXNlKCk9PT10fWZ1bmN0aW9uIGluc2lkZUlDU1NSdWxlTm9kZSQxKGUpe3ZhciB0PWdldEFuY2VzdG9yTm9kZSQxKGUsImNzcy1ydWxlIik7cmV0dXJuIHQmJnQucmF3cyYmdC5yYXdzLnNlbGVjdG9yJiYodC5yYXdzLnNlbGVjdG9yLnN0YXJ0c1dpdGgoIjppbXBvcnQiKXx8dC5yYXdzLnNlbGVjdG9yLnN0YXJ0c1dpdGgoIjpleHBvcnQiKSl9ZnVuY3Rpb24gaW5zaWRlQXRSdWxlTm9kZSQxKGUsdCl7dmFyIG49W10uY29uY2F0KHQpLHI9Z2V0QW5jZXN0b3JOb2RlJDEoZSwiY3NzLWF0cnVsZSIpO3JldHVybiByJiYtMSE9PW4uaW5kZXhPZihyLm5hbWUudG9Mb3dlckNhc2UoKSl9ZnVuY3Rpb24gaW5zaWRlVVJMRnVuY3Rpb25JbkltcG9ydEF0UnVsZU5vZGUkMShlKXt2YXIgdD1lLmdldFZhbHVlKCksbj1nZXRBbmNlc3Rvck5vZGUkMShlLCJjc3MtYXRydWxlIik7cmV0dXJuIG4mJiJpbXBvcnQiPT09bi5uYW1lJiYidXJsIj09PXQuZ3JvdXBzWzBdLnZhbHVlJiYyPT09dC5ncm91cHMubGVuZ3RofWZ1bmN0aW9uIGlzVVJMRnVuY3Rpb25Ob2RlJDEoZSl7cmV0dXJuInZhbHVlLWZ1bmMiPT09ZS50eXBlJiYidXJsIj09PWUudmFsdWUudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBpc0xhc3ROb2RlJDEoZSx0KXt2YXIgbj1lLmdldFBhcmVudE5vZGUoKTtpZighbilyZXR1cm4hMTt2YXIgcj1uLm5vZGVzO3JldHVybiByJiZyLmluZGV4T2YodCk9PT1yLmxlbmd0aC0xfWZ1bmN0aW9uIGlzSFRNTFRhZyQxKGUpe3JldHVybi0xIT09aHRtbFRhZ05hbWVzJDEuaW5kZXhPZihlLnRvTG93ZXJDYXNlKCkpfWZ1bmN0aW9uIGlzRGV0YWNoZWRSdWxlc2V0RGVjbGFyYXRpb25Ob2RlJDEoZSl7cmV0dXJuISFlLnNlbGVjdG9yJiYoInN0cmluZyI9PT10eXBlb2YgZS5zZWxlY3RvciYmL15ALis6LiokLy50ZXN0KGUuc2VsZWN0b3IpfHxlLnNlbGVjdG9yLnZhbHVlJiYvXkAuKzouKiQvLnRlc3QoZS5zZWxlY3Rvci52YWx1ZSkpfWZ1bmN0aW9uIGlzRm9yS2V5d29yZE5vZGUkMShlKXtyZXR1cm4idmFsdWUtd29yZCI9PT1lLnR5cGUmJi0xIT09WyJmcm9tIiwidGhyb3VnaCIsImVuZCJdLmluZGV4T2YoZS52YWx1ZSl9ZnVuY3Rpb24gaXNJZkVsc2VLZXl3b3JkTm9kZSQxKGUpe3JldHVybiJ2YWx1ZS13b3JkIj09PWUudHlwZSYmLTEhPT1bImFuZCIsIm9yIiwibm90Il0uaW5kZXhPZihlLnZhbHVlKX1mdW5jdGlvbiBpc0VhY2hLZXl3b3JkTm9kZSQxKGUpe3JldHVybiJ2YWx1ZS13b3JkIj09PWUudHlwZSYmImluIj09PWUudmFsdWV9ZnVuY3Rpb24gaXNNdWx0aXBsaWNhdGlvbk5vZGUkMShlKXtyZXR1cm4idmFsdWUtb3BlcmF0b3IiPT09ZS50eXBlJiYiKiI9PT1lLnZhbHVlfWZ1bmN0aW9uIGlzRGl2aXNpb25Ob2RlJDEoZSl7cmV0dXJuInZhbHVlLW9wZXJhdG9yIj09PWUudHlwZSYmIi8iPT09ZS52YWx1ZX1mdW5jdGlvbiBpc0FkZGl0aW9uTm9kZSQxKGUpe3JldHVybiJ2YWx1ZS1vcGVyYXRvciI9PT1lLnR5cGUmJiIrIj09PWUudmFsdWV9ZnVuY3Rpb24gaXNTdWJ0cmFjdGlvbk5vZGUkMShlKXtyZXR1cm4idmFsdWUtb3BlcmF0b3IiPT09ZS50eXBlJiYiLSI9PT1lLnZhbHVlfWZ1bmN0aW9uIGlzTW9kdWxvTm9kZShlKXtyZXR1cm4idmFsdWUtb3BlcmF0b3IiPT09ZS50eXBlJiYiJSI9PT1lLnZhbHVlfWZ1bmN0aW9uIGlzTWF0aE9wZXJhdG9yTm9kZSQxKGUpe3JldHVybiBpc011bHRpcGxpY2F0aW9uTm9kZSQxKGUpfHxpc0RpdmlzaW9uTm9kZSQxKGUpfHxpc0FkZGl0aW9uTm9kZSQxKGUpfHxpc1N1YnRyYWN0aW9uTm9kZSQxKGUpfHxpc01vZHVsb05vZGUoZSl9ZnVuY3Rpb24gaXNFcXVhbGl0eU9wZXJhdG9yTm9kZSQxKGUpe3JldHVybiJ2YWx1ZS13b3JkIj09PWUudHlwZSYmLTEhPT1bIj09IiwiIT0iXS5pbmRleE9mKGUudmFsdWUpfWZ1bmN0aW9uIGlzUmVsYXRpb25hbE9wZXJhdG9yTm9kZSQxKGUpe3JldHVybiJ2YWx1ZS13b3JkIj09PWUudHlwZSYmLTEhPT1bIjwiLCI+IiwiPD0iLCI+PSJdLmluZGV4T2YoZS52YWx1ZSl9ZnVuY3Rpb24gaXNTQ1NTQ29udHJvbERpcmVjdGl2ZU5vZGUkMShlKXtyZXR1cm4iY3NzLWF0cnVsZSI9PT1lLnR5cGUmJi0xIT09WyJpZiIsImVsc2UiLCJmb3IiLCJlYWNoIiwid2hpbGUiXS5pbmRleE9mKGUubmFtZSl9ZnVuY3Rpb24gaXNTQ1NTTmVzdGVkUHJvcGVydHlOb2RlKGUpe3JldHVybiEhZS5zZWxlY3RvciYmZS5zZWxlY3Rvci5yZXBsYWNlKC9cL1wqLio/XCpcLy8sIiIpLnJlcGxhY2UoL1wvXC8uKj9cbi8sIiIpLnRyaW0oKS5lbmRzV2l0aCgiOiIpfWZ1bmN0aW9uIGlzRGV0YWNoZWRSdWxlc2V0Q2FsbE5vZGUkMShlKXtyZXR1cm4gZS5yYXdzJiZlLnJhd3MucGFyYW1zJiYvXlwoXHMqXCkkLy50ZXN0KGUucmF3cy5wYXJhbXMpfWZ1bmN0aW9uIGlzUG9zdGNzc1NpbXBsZVZhck5vZGUkMShlLHQpe3JldHVybiIkJCI9PT1lLnZhbHVlJiYidmFsdWUtZnVuYyI9PT1lLnR5cGUmJnQmJiJ2YWx1ZS13b3JkIj09PXQudHlwZSYmIXQucmF3cy5iZWZvcmV9ZnVuY3Rpb24gaGFzQ29tcG9zZXNOb2RlJDEoZSl7cmV0dXJuIGUudmFsdWUmJiJ2YWx1ZS1yb290Ij09PWUudmFsdWUudHlwZSYmZS52YWx1ZS5ncm91cCYmInZhbHVlLXZhbHVlIj09PWUudmFsdWUuZ3JvdXAudHlwZSYmImNvbXBvc2VzIj09PWUucHJvcC50b0xvd2VyQ2FzZSgpfWZ1bmN0aW9uIGhhc1BhcmVuc0Fyb3VuZE5vZGUkMShlKXtyZXR1cm4gZS52YWx1ZSYmZS52YWx1ZS5ncm91cCYmZS52YWx1ZS5ncm91cC5ncm91cCYmInZhbHVlLXBhcmVuX2dyb3VwIj09PWUudmFsdWUuZ3JvdXAuZ3JvdXAudHlwZSYmbnVsbCE9PWUudmFsdWUuZ3JvdXAuZ3JvdXAub3BlbiYmbnVsbCE9PWUudmFsdWUuZ3JvdXAuZ3JvdXAuY2xvc2V9ZnVuY3Rpb24gaGFzRW1wdHlSYXdCZWZvcmUkMShlKXtyZXR1cm4gZS5yYXdzJiYiIj09PWUucmF3cy5iZWZvcmV9ZnVuY3Rpb24gaXNLZXlWYWx1ZVBhaXJOb2RlJDEoZSl7cmV0dXJuInZhbHVlLWNvbW1hX2dyb3VwIj09PWUudHlwZSYmZS5ncm91cHMmJmUuZ3JvdXBzWzFdJiYidmFsdWUtY29sb24iPT09ZS5ncm91cHNbMV0udHlwZX1mdW5jdGlvbiBpc0tleVZhbHVlUGFpckluUGFyZW5Hcm91cE5vZGUoZSl7cmV0dXJuInZhbHVlLXBhcmVuX2dyb3VwIj09PWUudHlwZSYmZS5ncm91cHMmJmUuZ3JvdXBzWzBdJiZpc0tleVZhbHVlUGFpck5vZGUkMShlLmdyb3Vwc1swXSl9ZnVuY3Rpb24gaXNTQ1NTTWFwSXRlbU5vZGUkMShlKXt2YXIgdD1lLmdldFZhbHVlKCk7aWYoMD09PXQuZ3JvdXBzLmxlbmd0aClyZXR1cm4hMTt2YXIgbj1lLmdldFBhcmVudE5vZGUoMSk7aWYoIWlzS2V5VmFsdWVQYWlySW5QYXJlbkdyb3VwTm9kZSh0KSYmKCFufHwhaXNLZXlWYWx1ZVBhaXJJblBhcmVuR3JvdXBOb2RlKG4pKSlyZXR1cm4hMTt2YXIgcj1nZXRBbmNlc3Rvck5vZGUkMShlLCJjc3MtZGVjbCIpO3JldHVybiEhKHImJnIucHJvcCYmci5wcm9wLnN0YXJ0c1dpdGgoIiQiKSl8fCghIWlzS2V5VmFsdWVQYWlySW5QYXJlbkdyb3VwTm9kZShuKXx8InZhbHVlLWZ1bmMiPT09bi50eXBlKX1mdW5jdGlvbiBpc0lubGluZVZhbHVlQ29tbWVudE5vZGUkMShlKXtyZXR1cm4idmFsdWUtY29tbWVudCI9PT1lLnR5cGUmJmUuaW5saW5lfWZ1bmN0aW9uIGlzSGFzaE5vZGUkMShlKXtyZXR1cm4idmFsdWUtd29yZCI9PT1lLnR5cGUmJiIjIj09PWUudmFsdWV9ZnVuY3Rpb24gaXNMZWZ0Q3VybHlCcmFjZU5vZGUkMShlKXtyZXR1cm4idmFsdWUtd29yZCI9PT1lLnR5cGUmJiJ7Ij09PWUudmFsdWV9ZnVuY3Rpb24gaXNSaWdodEN1cmx5QnJhY2VOb2RlJDEoZSl7cmV0dXJuInZhbHVlLXdvcmQiPT09ZS50eXBlJiYifSI9PT1lLnZhbHVlfWZ1bmN0aW9uIGlzV29yZE5vZGUkMShlKXtyZXR1cm4tMSE9PVsidmFsdWUtd29yZCIsInZhbHVlLWF0d29yZCJdLmluZGV4T2YoZS50eXBlKX1mdW5jdGlvbiBpc0NvbG9uTm9kZSQxKGUpe3JldHVybiJ2YWx1ZS1jb2xvbiI9PT1lLnR5cGV9ZnVuY3Rpb24gaXNNZWRpYUFuZFN1cHBvcnRzS2V5d29yZHMkMShlKXtyZXR1cm4gZS52YWx1ZSYmLTEhPT1bIm5vdCIsImFuZCIsIm9yIl0uaW5kZXhPZihlLnZhbHVlLnRvTG93ZXJDYXNlKCkpfWZ1bmN0aW9uIHNob3VsZFByaW50Q29tbWEkMShlKXtzd2l0Y2goZS50cmFpbGluZ0NvbW1hKXtjYXNlImFsbCI6Y2FzZSJlczUiOnJldHVybiEwO2Nhc2Uibm9uZSI6ZGVmYXVsdDpyZXR1cm4hMX19ZnVuY3Rpb24gZ2VuZXJpY1ByaW50JDMoZSx0LG4pe3ZhciByPWUuZ2V0VmFsdWUoKTtpZighcilyZXR1cm4iIjtpZigic3RyaW5nIj09PXR5cGVvZiByKXJldHVybiByO3N3aXRjaChyLnR5cGUpe2Nhc2UiZnJvbnQtbWF0dGVyIjpyZXR1cm4gY29uY2F0JDcoW3IudmFsdWUsaGFyZGxpbmUkNl0pO2Nhc2UiY3NzLXJvb3QiOnZhciBpPXByaW50Tm9kZVNlcXVlbmNlKGUsdCxuKTtyZXR1cm4gaS5wYXJ0cy5sZW5ndGg/Y29uY2F0JDcoW2ksaGFyZGxpbmUkNl0pOmk7Y2FzZSJjc3MtY29tbWVudCI6aWYoci5yYXdzLmNvbnRlbnQpcmV0dXJuIHIucmF3cy5jb250ZW50O3ZhciBvPXQub3JpZ2luYWxUZXh0LnNsaWNlKHQubG9jU3RhcnQociksdC5sb2NFbmQocikpLGE9ci5yYXdzLnRleHR8fHIudGV4dDtyZXR1cm4tMT09PW8uaW5kZXhPZihhKT9jb25jYXQkNyhyLnJhd3MuaW5saW5lP1siLy8gIixhXTpbIi8qICIsYSwiICovIl0pOm87Y2FzZSJjc3MtcnVsZSI6cmV0dXJuIGNvbmNhdCQ3KFtlLmNhbGwobiwic2VsZWN0b3IiKSxyLmltcG9ydGFudD8iICFpbXBvcnRhbnQiOiIiLHIubm9kZXM/Y29uY2F0JDcoWyIgeyIsci5ub2Rlcy5sZW5ndGg+MD9pbmRlbnQkNShjb25jYXQkNyhbaGFyZGxpbmUkNixwcmludE5vZGVTZXF1ZW5jZShlLHQsbildKSk6IiIsaGFyZGxpbmUkNiwifSIsaXNEZXRhY2hlZFJ1bGVzZXREZWNsYXJhdGlvbk5vZGUocik/IjsiOiIiXSk6IjsiXSk7Y2FzZSJjc3MtZGVjbCI6cmV0dXJuIGNvbmNhdCQ3KFtyLnJhd3MuYmVmb3JlLnJlcGxhY2UoL1tccztdL2csIiIpLGluc2lkZUlDU1NSdWxlTm9kZShlKT9yLnByb3A6bWF5YmVUb0xvd2VyQ2FzZShyLnByb3ApLCI6Ij09PXIucmF3cy5iZXR3ZWVuLnRyaW0oKT8iOiI6ci5yYXdzLmJldHdlZW4udHJpbSgpLHIuZXh0ZW5kPyIiOiIgIixoYXNDb21wb3Nlc05vZGUocik/cmVtb3ZlTGluZXMkMihlLmNhbGwobiwidmFsdWUiKSk6ZS5jYWxsKG4sInZhbHVlIiksci5yYXdzLmltcG9ydGFudD9yLnJhd3MuaW1wb3J0YW50LnJlcGxhY2UoL1xzKiFccyppbXBvcnRhbnQvaSwiICFpbXBvcnRhbnQiKTpyLmltcG9ydGFudD8iICFpbXBvcnRhbnQiOiIiLHIucmF3cy5zY3NzRGVmYXVsdD9yLnJhd3Muc2Nzc0RlZmF1bHQucmVwbGFjZSgvXHMqIWRlZmF1bHQvaSwiICFkZWZhdWx0Iik6ci5zY3NzRGVmYXVsdD8iICFkZWZhdWx0IjoiIixyLnJhd3Muc2Nzc0dsb2JhbD9yLnJhd3Muc2Nzc0dsb2JhbC5yZXBsYWNlKC9ccyohZ2xvYmFsL2ksIiAhZ2xvYmFsIik6ci5zY3NzR2xvYmFsPyIgIWdsb2JhbCI6IiIsci5ub2Rlcz9jb25jYXQkNyhbIiB7IixpbmRlbnQkNShjb25jYXQkNyhbc29mdGxpbmUkMyxwcmludE5vZGVTZXF1ZW5jZShlLHQsbildKSksc29mdGxpbmUkMywifSJdKToiOyJdKTtjYXNlImNzcy1hdHJ1bGUiOnJldHVybiBjb25jYXQkNyhbIkAiLGlzRGV0YWNoZWRSdWxlc2V0Q2FsbE5vZGUocil8fHIubmFtZS5lbmRzV2l0aCgiOiIpP3IubmFtZTptYXliZVRvTG93ZXJDYXNlKHIubmFtZSksci5wYXJhbXM/Y29uY2F0JDcoW2lzRGV0YWNoZWRSdWxlc2V0Q2FsbE5vZGUocik/IiI6IiAiLGUuY2FsbChuLCJwYXJhbXMiKV0pOiIiLHIuc2VsZWN0b3I/aW5kZW50JDUoY29uY2F0JDcoWyIgIixlLmNhbGwobiwic2VsZWN0b3IiKV0pKToiIixyLnZhbHVlP2dyb3VwJDIoY29uY2F0JDcoWyIgIixlLmNhbGwobiwidmFsdWUiKSxpc1NDU1NDb250cm9sRGlyZWN0aXZlTm9kZShyKT9oYXNQYXJlbnNBcm91bmROb2RlKHIpPyIgIjpsaW5lJDQ6IiJdKSk6ImVsc2UiPT09ci5uYW1lPyIgIjoiIixyLm5vZGVzP2NvbmNhdCQ3KFtpc1NDU1NDb250cm9sRGlyZWN0aXZlTm9kZShyKT8iIjoiICIsInsiLGluZGVudCQ1KGNvbmNhdCQ3KFtyLm5vZGVzLmxlbmd0aD4wP3NvZnRsaW5lJDM6IiIscHJpbnROb2RlU2VxdWVuY2UoZSx0LG4pXSkpLHNvZnRsaW5lJDMsIn0iXSk6IjsiXSk7Y2FzZSJtZWRpYS1xdWVyeS1saXN0Ijp2YXIgcz1bXTtyZXR1cm4gZS5lYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWUuZ2V0VmFsdWUoKTsibWVkaWEtcXVlcnkiPT09dC50eXBlJiYiIj09PXQudmFsdWV8fHMucHVzaChlLmNhbGwobikpfSwibm9kZXMiKSxncm91cCQyKGluZGVudCQ1KGpvaW4kNShsaW5lJDQscykpKTtjYXNlIm1lZGlhLXF1ZXJ5IjpyZXR1cm4gY29uY2F0JDcoW2pvaW4kNSgiICIsZS5tYXAobiwibm9kZXMiKSksaXNMYXN0Tm9kZShlLHIpPyIiOiIsIl0pO2Nhc2UibWVkaWEtdHlwZSI6cmV0dXJuIGFkanVzdE51bWJlcnMoYWRqdXN0U3RyaW5ncyhyLnZhbHVlLHQpKTtjYXNlIm1lZGlhLWZlYXR1cmUtZXhwcmVzc2lvbiI6cmV0dXJuIHIubm9kZXM/Y29uY2F0JDcoWyIoIixjb25jYXQkNyhlLm1hcChuLCJub2RlcyIpKSwiKSJdKTpyLnZhbHVlO2Nhc2UibWVkaWEtZmVhdHVyZSI6cmV0dXJuIG1heWJlVG9Mb3dlckNhc2UoYWRqdXN0U3RyaW5ncyhyLnZhbHVlLnJlcGxhY2UoLyArL2csIiAiKSx0KSk7Y2FzZSJtZWRpYS1jb2xvbiI6cmV0dXJuIGNvbmNhdCQ3KFtyLnZhbHVlLCIgIl0pO2Nhc2UibWVkaWEtdmFsdWUiOnJldHVybiBhZGp1c3ROdW1iZXJzKGFkanVzdFN0cmluZ3Moci52YWx1ZSx0KSk7Y2FzZSJtZWRpYS1rZXl3b3JkIjpyZXR1cm4gYWRqdXN0U3RyaW5ncyhyLnZhbHVlLHQpO2Nhc2UibWVkaWEtdXJsIjpyZXR1cm4gYWRqdXN0U3RyaW5ncyhyLnZhbHVlLnJlcGxhY2UoL151cmxcKFxzKy9naSwidXJsKCIpLnJlcGxhY2UoL1xzK1wpJC9naSwiKSIpLHQpO2Nhc2UibWVkaWEtdW5rbm93biI6cmV0dXJuIHIudmFsdWU7Y2FzZSJzZWxlY3Rvci1yb290IjpyZXR1cm4gZ3JvdXAkMihjb25jYXQkNyhbaW5zaWRlQXRSdWxlTm9kZShlLCJjdXN0b20tc2VsZWN0b3IiKT9jb25jYXQkNyhbZ2V0QW5jZXN0b3JOb2RlKGUsImNzcy1hdHJ1bGUiKS5jdXN0b21TZWxlY3RvcixsaW5lJDRdKToiIixqb2luJDUoY29uY2F0JDcoWyIsIixpbnNpZGVBdFJ1bGVOb2RlKGUsWyJleHRlbmQiLCJjdXN0b20tc2VsZWN0b3IiLCJuZXN0Il0pP2xpbmUkNDpoYXJkbGluZSQ2XSksZS5tYXAobiwibm9kZXMiKSldKSk7Y2FzZSJzZWxlY3Rvci1zZWxlY3RvciI6cmV0dXJuIGdyb3VwJDIoaW5kZW50JDUoY29uY2F0JDcoZS5tYXAobiwibm9kZXMiKSkpKTtjYXNlInNlbGVjdG9yLWNvbW1lbnQiOnJldHVybiByLnZhbHVlO2Nhc2Uic2VsZWN0b3Itc3RyaW5nIjpyZXR1cm4gYWRqdXN0U3RyaW5ncyhyLnZhbHVlLHQpO2Nhc2Uic2VsZWN0b3ItdGFnIjp2YXIgdT1lLmdldFBhcmVudE5vZGUoKSxjPXUmJnUubm9kZXMuaW5kZXhPZihyKSxsPWMmJnUubm9kZXNbYy0xXTtyZXR1cm4gY29uY2F0JDcoW3IubmFtZXNwYWNlP2NvbmNhdCQ3KFshMD09PXIubmFtZXNwYWNlPyIiOnIubmFtZXNwYWNlLnRyaW0oKSwifCJdKToiIiwic2VsZWN0b3ItbmVzdGluZyI9PT1sLnR5cGU/ci52YWx1ZTphZGp1c3ROdW1iZXJzKGlzSFRNTFRhZyhyLnZhbHVlKXx8aXNLZXlmcmFtZUF0UnVsZUtleXdvcmRzKGUsci52YWx1ZSk/ci52YWx1ZS50b0xvd2VyQ2FzZSgpOnIudmFsdWUpXSk7Y2FzZSJzZWxlY3Rvci1pZCI6cmV0dXJuIGNvbmNhdCQ3KFsiIyIsci52YWx1ZV0pO2Nhc2Uic2VsZWN0b3ItY2xhc3MiOnJldHVybiBjb25jYXQkNyhbIi4iLGFkanVzdE51bWJlcnMoYWRqdXN0U3RyaW5ncyhyLnZhbHVlLHQpKV0pO2Nhc2Uic2VsZWN0b3ItYXR0cmlidXRlIjpyZXR1cm4gY29uY2F0JDcoWyJbIixyLm5hbWVzcGFjZT9jb25jYXQkNyhbITA9PT1yLm5hbWVzcGFjZT8iIjpyLm5hbWVzcGFjZS50cmltKCksInwiXSk6IiIsci5hdHRyaWJ1dGUudHJpbSgpLHIub3BlcmF0b3I/ci5vcGVyYXRvcjoiIixyLnZhbHVlP3F1b3RlQXR0cmlidXRlVmFsdWUoYWRqdXN0U3RyaW5ncyhyLnZhbHVlLnRyaW0oKSx0KSx0KToiIixyLmluc2Vuc2l0aXZlPyIgaSI6IiIsIl0iXSk7Y2FzZSJzZWxlY3Rvci1jb21iaW5hdG9yIjppZigiKyI9PT1yLnZhbHVlfHwiPiI9PT1yLnZhbHVlfHwifiI9PT1yLnZhbHVlfHwiPj4+Ij09PXIudmFsdWUpe3ZhciBwPWUuZ2V0UGFyZW50Tm9kZSgpLGY9InNlbGVjdG9yLXNlbGVjdG9yIj09PXAudHlwZSYmcC5ub2Rlc1swXT09PXI/IiI6bGluZSQ0O3JldHVybiBjb25jYXQkNyhbZixyLnZhbHVlLGlzTGFzdE5vZGUoZSxyKT8iIjoiICJdKX12YXIgZD1yLnZhbHVlLnRyaW0oKS5zdGFydHNXaXRoKCIoIik/bGluZSQ0OiIiLGg9YWRqdXN0TnVtYmVycyhhZGp1c3RTdHJpbmdzKHIudmFsdWUudHJpbSgpLHQpKXx8bGluZSQ0O3JldHVybiBjb25jYXQkNyhbZCxoXSk7Y2FzZSJzZWxlY3Rvci11bml2ZXJzYWwiOnJldHVybiBjb25jYXQkNyhbci5uYW1lc3BhY2U/Y29uY2F0JDcoWyEwPT09ci5uYW1lc3BhY2U/IiI6ci5uYW1lc3BhY2UudHJpbSgpLCJ8Il0pOiIiLGFkanVzdE51bWJlcnMoci52YWx1ZSldKTtjYXNlInNlbGVjdG9yLXBzZXVkbyI6cmV0dXJuIGNvbmNhdCQ3KFttYXliZVRvTG93ZXJDYXNlKHIudmFsdWUpLHIubm9kZXMmJnIubm9kZXMubGVuZ3RoPjA/Y29uY2F0JDcoWyIoIixqb2luJDUoIiwgIixlLm1hcChuLCJub2RlcyIpKSwiKSJdKToiIl0pO2Nhc2Uic2VsZWN0b3ItbmVzdGluZyI6cmV0dXJuIHIudmFsdWU7Y2FzZSJzZWxlY3Rvci11bmtub3duIjp2YXIgbT1nZXRBbmNlc3Rvck5vZGUoZSwiY3NzLXJ1bGUiKTtyZXR1cm4gbSYmbS5pc1NDU1NOZXN0ZXJQcm9wZXJ0eT9hZGp1c3ROdW1iZXJzKGFkanVzdFN0cmluZ3MobWF5YmVUb0xvd2VyQ2FzZShyLnZhbHVlKSx0KSk6ci52YWx1ZTtjYXNlInZhbHVlLXZhbHVlIjpjYXNlInZhbHVlLXJvb3QiOnJldHVybiBlLmNhbGwobiwiZ3JvdXAiKTtjYXNlInZhbHVlLWNvbW1lbnQiOnJldHVybiBjb25jYXQkNyhbci5pbmxpbmU/Ii8vIjoiLyoiLHIudmFsdWUsci5pbmxpbmU/IiI6IiovIl0pO2Nhc2UidmFsdWUtY29tbWFfZ3JvdXAiOmZvcih2YXIgZz1lLmdldFBhcmVudE5vZGUoKSx5PWdldFByb3BPZkRlY2xOb2RlKGUpLHY9eSYmInZhbHVlLXZhbHVlIj09PWcudHlwZSYmKCJncmlkIj09PXl8fHkuc3RhcnRzV2l0aCgiZ3JpZC10ZW1wbGF0ZSIpKSxiPWdldEFuY2VzdG9yTm9kZShlLCJjc3MtYXRydWxlIikseD1iJiZpc1NDU1NDb250cm9sRGlyZWN0aXZlTm9kZShiKSxDPWUubWFwKG4sImdyb3VwcyIpLEU9W10sRD1pbnNpZGVWYWx1ZUZ1bmN0aW9uTm9kZShlLCJ1cmwiKSx3PSExLFM9ITEsaz0wO2s8ci5ncm91cHMubGVuZ3RoOysraylpZihFLnB1c2goQ1trXSksIUQpe3ZhciBBPXIuZ3JvdXBzW2stMV0sXz1yLmdyb3Vwc1trXSxUPXIuZ3JvdXBzW2srMV0sTz1yLmdyb3Vwc1trKzJdO2lmKFQpe3ZhciBGPSJ2YWx1ZS1zdHJpbmciPT09Xy50eXBlJiZfLnZhbHVlLnN0YXJ0c1dpdGgoIiN7IiksTj13JiYidmFsdWUtc3RyaW5nIj09PVQudHlwZSYmVC52YWx1ZS5lbmRzV2l0aCgifSIpO2lmKEZ8fE4pdz0hdztlbHNlIGlmKCF3JiYhaXNDb2xvbk5vZGUoXykmJiFpc0NvbG9uTm9kZShUKSYmKCJ2YWx1ZS1hdHdvcmQiIT09Xy50eXBlfHwiIiE9PV8udmFsdWUpJiYifiIhPT1fLnZhbHVlJiYiXFwiIT09Xy52YWx1ZSYmIWlzUG9zdGNzc1NpbXBsZVZhck5vZGUoXyxUKSYmIShpc0hhc2hOb2RlKF8pfHxpc0xlZnRDdXJseUJyYWNlTm9kZShfKXx8aXNSaWdodEN1cmx5QnJhY2VOb2RlKFQpfHxpc0xlZnRDdXJseUJyYWNlTm9kZShUKSYmaGFzRW1wdHlSYXdCZWZvcmUoVCl8fGlzUmlnaHRDdXJseUJyYWNlTm9kZShfKSYmaGFzRW1wdHlSYXdCZWZvcmUoVCkpJiYoIi0tIiE9PV8udmFsdWV8fCFpc0hhc2hOb2RlKFQpKSl7dmFyIEk9aXNNYXRoT3BlcmF0b3JOb2RlKF8pLEw9aXNNYXRoT3BlcmF0b3JOb2RlKFQpO2lmKCghKEkmJmlzSGFzaE5vZGUoVCl8fEwmJmlzUmlnaHRDdXJseUJyYWNlTm9kZShfKSl8fCFoYXNFbXB0eVJhd0JlZm9yZShUKSkmJiEoaW5zaWRlVmFsdWVGdW5jdGlvbk5vZGUoZSwiY2FsYyIpJiYoaXNBZGRpdGlvbk5vZGUoXyl8fGlzQWRkaXRpb25Ob2RlKFQpfHxpc1N1YnRyYWN0aW9uTm9kZShfKXx8aXNTdWJ0cmFjdGlvbk5vZGUoVCkpJiZoYXNFbXB0eVJhd0JlZm9yZShUKSkpe3ZhciBQPU8mJiJ2YWx1ZS1mdW5jIj09PU8udHlwZXx8TyYmaXNXb3JkTm9kZShPKXx8InZhbHVlLWZ1bmMiPT09Xy50eXBlfHxpc1dvcmROb2RlKF8pLE09InZhbHVlLWZ1bmMiPT09VC50eXBlfHxpc1dvcmROb2RlKFQpfHxBJiYidmFsdWUtZnVuYyI9PT1BLnR5cGV8fEEmJmlzV29yZE5vZGUoQSk7aWYoaXNNdWx0aXBsaWNhdGlvbk5vZGUoVCl8fGlzTXVsdGlwbGljYXRpb25Ob2RlKF8pfHxpbnNpZGVWYWx1ZUZ1bmN0aW9uTm9kZShlLCJjYWxjIil8fCEoaXNEaXZpc2lvbk5vZGUoVCkmJiFQfHxpc0RpdmlzaW9uTm9kZShfKSYmIU18fGlzQWRkaXRpb25Ob2RlKFQpJiYhUHx8aXNBZGRpdGlvbk5vZGUoXykmJiFNfHxpc1N1YnRyYWN0aW9uTm9kZShUKXx8aXNTdWJ0cmFjdGlvbk5vZGUoXykpfHwhKGhhc0VtcHR5UmF3QmVmb3JlKFQpfHxJJiYoIUF8fEEmJmlzTWF0aE9wZXJhdG9yTm9kZShBKSkpKXt2YXIgaj1pc0lubGluZVZhbHVlQ29tbWVudE5vZGUoXyk7QSYmaXNJbmxpbmVWYWx1ZUNvbW1lbnROb2RlKEEpfHxqfHxpc0lubGluZVZhbHVlQ29tbWVudE5vZGUoVCk/aiYmRS5wdXNoKGhhcmRsaW5lJDYpOngmJihpc0VxdWFsaXR5T3BlcmF0b3JOb2RlKFQpfHxpc1JlbGF0aW9uYWxPcGVyYXRvck5vZGUoVCl8fGlzSWZFbHNlS2V5d29yZE5vZGUoVCl8fGlzRWFjaEtleXdvcmROb2RlKF8pfHxpc0ZvcktleXdvcmROb2RlKF8pKT9FLnB1c2goIiAiKTpiJiYibmFtZXNwYWNlIj09PWIubmFtZS50b0xvd2VyQ2FzZSgpP0UucHVzaCgiICIpOnY/Xy5zb3VyY2Uuc3RhcnQubGluZSE9PVQuc291cmNlLnN0YXJ0LmxpbmU/KEUucHVzaChoYXJkbGluZSQ2KSxTPSEwKTpFLnB1c2goIiAiKTpMP0UucHVzaCgiICIpOkUucHVzaChsaW5lJDQpfX19fX1yZXR1cm4gUyYmRS51bnNoaWZ0KGhhcmRsaW5lJDYpLGdyb3VwJDIoeD9pbmRlbnQkNShjb25jYXQkNyhFKSk6aW5zaWRlVVJMRnVuY3Rpb25JbkltcG9ydEF0UnVsZU5vZGUoZSk/ZmlsbCQzKEUpOmluZGVudCQ1KGZpbGwkMyhFKSkpO2Nhc2UidmFsdWUtcGFyZW5fZ3JvdXAiOnZhciBSPWUuZ2V0UGFyZW50Tm9kZSgpO2lmKFImJmlzVVJMRnVuY3Rpb25Ob2RlKFIpJiYoMT09PXIuZ3JvdXBzLmxlbmd0aHx8ci5ncm91cHMubGVuZ3RoPjAmJiJ2YWx1ZS1jb21tYV9ncm91cCI9PT1yLmdyb3Vwc1swXS50eXBlJiZyLmdyb3Vwc1swXS5ncm91cHMubGVuZ3RoPjAmJiJ2YWx1ZS13b3JkIj09PXIuZ3JvdXBzWzBdLmdyb3Vwc1swXS50eXBlJiZyLmdyb3Vwc1swXS5ncm91cHNbMF0udmFsdWUuc3RhcnRzV2l0aCgiZGF0YToiKSkpcmV0dXJuIGNvbmNhdCQ3KFtyLm9wZW4/ZS5jYWxsKG4sIm9wZW4iKToiIixqb2luJDUoIiwiLGUubWFwKG4sImdyb3VwcyIpKSxyLmNsb3NlP2UuY2FsbChuLCJjbG9zZSIpOiIiXSk7aWYoIXIub3Blbil7Zm9yKHZhciBCPWUubWFwKG4sImdyb3VwcyIpLCQ9W10sVT0wO1U8Qi5sZW5ndGg7VSsrKTAhPT1VJiYkLnB1c2goY29uY2F0JDcoWyIsIixsaW5lJDRdKSksJC5wdXNoKEJbVV0pO3JldHVybiBncm91cCQyKGluZGVudCQ1KGZpbGwkMygkKSkpfXZhciB6PWlzU0NTU01hcEl0ZW1Ob2RlKGUpO3JldHVybiBncm91cCQyKGNvbmNhdCQ3KFtyLm9wZW4/ZS5jYWxsKG4sIm9wZW4iKToiIixpbmRlbnQkNShjb25jYXQkNyhbc29mdGxpbmUkMyxqb2luJDUoY29uY2F0JDcoWyIsIixsaW5lJDRdKSxlLm1hcChmdW5jdGlvbihlKXt2YXIgdD1lLmdldFZhbHVlKCkscj1uKGUpO3JldHVybiBpc0tleVZhbHVlUGFpck5vZGUodCkmJiJ2YWx1ZS1jb21tYV9ncm91cCI9PT10LnR5cGUmJnQuZ3JvdXBzJiZ0Lmdyb3Vwc1syXSYmInZhbHVlLXBhcmVuX2dyb3VwIj09PXQuZ3JvdXBzWzJdLnR5cGU/KHIuY29udGVudHMuY29udGVudHMucGFydHNbMV09Z3JvdXAkMihyLmNvbnRlbnRzLmNvbnRlbnRzLnBhcnRzWzFdKSxncm91cCQyKGRlZGVudCQzKHIpKSk6cn0sImdyb3VwcyIpKV0pKSxpZkJyZWFrJDIoaXNTQ1NTKHQucGFyc2VyLHQub3JpZ2luYWxUZXh0KSYmeiYmc2hvdWxkUHJpbnRDb21tYSQxKHQpPyIsIjoiIiksc29mdGxpbmUkMyxyLmNsb3NlP2UuY2FsbChuLCJjbG9zZSIpOiIiXSkse3Nob3VsZEJyZWFrOnp9KTtjYXNlInZhbHVlLWZ1bmMiOnJldHVybiBjb25jYXQkNyhbci52YWx1ZSxpbnNpZGVBdFJ1bGVOb2RlKGUsInN1cHBvcnRzIikmJmlzTWVkaWFBbmRTdXBwb3J0c0tleXdvcmRzKHIpPyIgIjoiIixlLmNhbGwobiwiZ3JvdXAiKV0pO2Nhc2UidmFsdWUtcGFyZW4iOnJldHVybiByLnZhbHVlO2Nhc2UidmFsdWUtbnVtYmVyIjpyZXR1cm4gY29uY2F0JDcoW3ByaW50Q3NzTnVtYmVyKHIudmFsdWUpLG1heWJlVG9Mb3dlckNhc2Uoci51bml0KV0pO2Nhc2UidmFsdWUtb3BlcmF0b3IiOnJldHVybiByLnZhbHVlO2Nhc2UidmFsdWUtd29yZCI6cmV0dXJuIHIuaXNDb2xvciYmci5pc0hleHx8aXNXaWRlS2V5d29yZHMoci52YWx1ZSk/ci52YWx1ZS50b0xvd2VyQ2FzZSgpOnIudmFsdWU7Y2FzZSJ2YWx1ZS1jb2xvbiI6cmV0dXJuIGNvbmNhdCQ3KFtyLnZhbHVlLGluc2lkZVZhbHVlRnVuY3Rpb25Ob2RlKGUsInVybCIpPyIiOmxpbmUkNF0pO2Nhc2UidmFsdWUtY29tbWEiOnJldHVybiBjb25jYXQkNyhbci52YWx1ZSwiICJdKTtjYXNlInZhbHVlLXN0cmluZyI6cmV0dXJuIHByaW50U3RyaW5nJDIoci5yYXdzLnF1b3RlK3IudmFsdWUrci5yYXdzLnF1b3RlLHQpO2Nhc2UidmFsdWUtYXR3b3JkIjpyZXR1cm4gY29uY2F0JDcoWyJAIixyLnZhbHVlXSk7Y2FzZSJ2YWx1ZS11bmljb2RlLXJhbmdlIjpjYXNlInZhbHVlLXVua25vd24iOnJldHVybiByLnZhbHVlO2RlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJVbmtub3duIHBvc3Rjc3MgdHlwZSAiLmNvbmNhdChKU09OLnN0cmluZ2lmeShyLnR5cGUpKSl9fWZ1bmN0aW9uIHByaW50Tm9kZVNlcXVlbmNlKGUsdCxuKXt2YXIgcj1lLmdldFZhbHVlKCksaT1bXSxvPTA7cmV0dXJuIGUubWFwKGZ1bmN0aW9uKGUpe3ZhciBhPXIubm9kZXNbby0xXTtpZihhJiYiY3NzLWNvbW1lbnQiPT09YS50eXBlJiYicHJldHRpZXItaWdub3JlIj09PWEudGV4dC50cmltKCkpe3ZhciBzPWUuZ2V0VmFsdWUoKTtpLnB1c2godC5vcmlnaW5hbFRleHQuc2xpY2UodC5sb2NTdGFydChzKSx0LmxvY0VuZChzKSkpfWVsc2UgaS5wdXNoKGUuY2FsbChuKSk7byE9PXIubm9kZXMubGVuZ3RoLTEmJigiY3NzLWNvbW1lbnQiPT09ci5ub2Rlc1tvKzFdLnR5cGUmJiFoYXNOZXdsaW5lJDModC5vcmlnaW5hbFRleHQsdC5sb2NTdGFydChyLm5vZGVzW28rMV0pLHtiYWNrd2FyZHM6ITB9KXx8ImNzcy1hdHJ1bGUiPT09ci5ub2Rlc1tvKzFdLnR5cGUmJiJlbHNlIj09PXIubm9kZXNbbysxXS5uYW1lJiYiY3NzLWNvbW1lbnQiIT09ci5ub2Rlc1tvXS50eXBlP2kucHVzaCgiICIpOihpLnB1c2goaGFyZGxpbmUkNiksaXNOZXh0TGluZUVtcHR5JDModC5vcmlnaW5hbFRleHQsZS5nZXRWYWx1ZSgpLHQpJiZpLnB1c2goaGFyZGxpbmUkNikpKSxvKyt9LCJub2RlcyIpLGNvbmNhdCQ3KGkpfWZ1bmN0aW9uIGFkanVzdFN0cmluZ3MoZSx0KXtyZXR1cm4gZS5yZXBsYWNlKFNUUklOR19SRUdFWCxmdW5jdGlvbihlKXtyZXR1cm4gcHJpbnRTdHJpbmckMihlLHQpfSl9ZnVuY3Rpb24gcXVvdGVBdHRyaWJ1dGVWYWx1ZShlLHQpe3ZhciBuPXQuc2luZ2xlUXVvdGU/IiciOiciJztyZXR1cm4gZS5pbmNsdWRlcygnIicpfHxlLmluY2x1ZGVzKCInIik/ZTpuK2Urbn1mdW5jdGlvbiBhZGp1c3ROdW1iZXJzKGUpe3JldHVybiBlLnJlcGxhY2UoQURKVVNUX05VTUJFUlNfUkVHRVgsZnVuY3Rpb24oZSx0LG4scixpKXtyZXR1cm4hbiYmcj8obnx8IiIpK3ByaW50Q3NzTnVtYmVyKHIpK21heWJlVG9Mb3dlckNhc2UoaXx8IiIpOmV9KX1mdW5jdGlvbiBwcmludENzc051bWJlcihlKXtyZXR1cm4gcHJpbnROdW1iZXIkMihlKS5yZXBsYWNlKC9cLjAoPz0kfGUpLywiIil9ZnVuY3Rpb24gZ2VuZXJpY1ByaW50JDQoZSx0LG4pe3ZhciByPWUuZ2V0VmFsdWUoKTtpZighcilyZXR1cm4iIjtpZigic3RyaW5nIj09PXR5cGVvZiByKXJldHVybiByO3N3aXRjaChyLmtpbmQpe2Nhc2UiRG9jdW1lbnQiOnZhciBpPVtdO3JldHVybiBlLm1hcChmdW5jdGlvbihlLG8pe2kucHVzaChjb25jYXQkOChbZS5jYWxsKG4pXSkpLGkucHVzaChoYXJkbGluZSQ3KSxvIT09ci5kZWZpbml0aW9ucy5sZW5ndGgtMSYmaXNOZXh0TGluZUVtcHR5JDQodC5vcmlnaW5hbFRleHQsZS5nZXRWYWx1ZSgpLHQpJiZpLnB1c2goaGFyZGxpbmUkNyl9LCJkZWZpbml0aW9ucyIpLGNvbmNhdCQ4KGksaGFyZGxpbmUkNyk7Y2FzZSJPcGVyYXRpb25EZWZpbml0aW9uIjp2YXIgbz0ieyIhPT10Lm9yaWdpbmFsVGV4dFt0LmxvY1N0YXJ0KHIpXSxhPSEhci5uYW1lO3JldHVybiBjb25jYXQkOChbbz9yLm9wZXJhdGlvbjoiIixvJiZhP2NvbmNhdCQ4KFsiICIsZS5jYWxsKG4sIm5hbWUiKV0pOiIiLHIudmFyaWFibGVEZWZpbml0aW9ucyYmci52YXJpYWJsZURlZmluaXRpb25zLmxlbmd0aD9ncm91cCQzKGNvbmNhdCQ4KFsiKCIsaW5kZW50JDYoY29uY2F0JDgoW3NvZnRsaW5lJDQsam9pbiQ2KGNvbmNhdCQ4KFtpZkJyZWFrJDMoIiIsIiwgIiksc29mdGxpbmUkNF0pLGUubWFwKG4sInZhcmlhYmxlRGVmaW5pdGlvbnMiKSldKSksc29mdGxpbmUkNCwiKSJdKSk6IiIscHJpbnREaXJlY3RpdmVzKGUsbixyKSxyLnNlbGVjdGlvblNldCYmKG98fGEpPyIgIjoiIixlLmNhbGwobiwic2VsZWN0aW9uU2V0IildKTtjYXNlIkZyYWdtZW50RGVmaW5pdGlvbiI6cmV0dXJuIGNvbmNhdCQ4KFsiZnJhZ21lbnQgIixlLmNhbGwobiwibmFtZSIpLCIgb24gIixlLmNhbGwobiwidHlwZUNvbmRpdGlvbiIpLHByaW50RGlyZWN0aXZlcyhlLG4sciksIiAiLGUuY2FsbChuLCJzZWxlY3Rpb25TZXQiKV0pO2Nhc2UiU2VsZWN0aW9uU2V0IjpyZXR1cm4gY29uY2F0JDgoWyJ7IixpbmRlbnQkNihjb25jYXQkOChbaGFyZGxpbmUkNyxqb2luJDYoaGFyZGxpbmUkNyxlLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIHByaW50U2VxdWVuY2UoZSx0LG4pfSwic2VsZWN0aW9ucyIpKV0pKSxoYXJkbGluZSQ3LCJ9Il0pO2Nhc2UiRmllbGQiOnJldHVybiBncm91cCQzKGNvbmNhdCQ4KFtyLmFsaWFzP2NvbmNhdCQ4KFtlLmNhbGwobiwiYWxpYXMiKSwiOiAiXSk6IiIsZS5jYWxsKG4sIm5hbWUiKSxyLmFyZ3VtZW50cy5sZW5ndGg+MD9ncm91cCQzKGNvbmNhdCQ4KFsiKCIsaW5kZW50JDYoY29uY2F0JDgoW3NvZnRsaW5lJDQsam9pbiQ2KGNvbmNhdCQ4KFtpZkJyZWFrJDMoIiIsIiwgIiksc29mdGxpbmUkNF0pLGUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gcHJpbnRTZXF1ZW5jZShlLHQsbil9LCJhcmd1bWVudHMiKSldKSksc29mdGxpbmUkNCwiKSJdKSk6IiIscHJpbnREaXJlY3RpdmVzKGUsbixyKSxyLnNlbGVjdGlvblNldD8iICI6IiIsZS5jYWxsKG4sInNlbGVjdGlvblNldCIpXSkpO2Nhc2UiTmFtZSI6cmV0dXJuIHIudmFsdWU7Y2FzZSJTdHJpbmdWYWx1ZSI6cmV0dXJuIGNvbmNhdCQ4KHIuYmxvY2s/WyciIiInLGhhcmRsaW5lJDcsam9pbiQ2KGhhcmRsaW5lJDcsci52YWx1ZS5yZXBsYWNlKC8iIiIvZywiXFwkJiIpLnNwbGl0KCJcbiIpKSxoYXJkbGluZSQ3LCciIiInXTpbJyInLHIudmFsdWUucmVwbGFjZSgvWyJcXF0vZywiXFwkJiIpLCciJ10pO2Nhc2UiSW50VmFsdWUiOmNhc2UiRmxvYXRWYWx1ZSI6Y2FzZSJFbnVtVmFsdWUiOnJldHVybiByLnZhbHVlO2Nhc2UiQm9vbGVhblZhbHVlIjpyZXR1cm4gci52YWx1ZT8idHJ1ZSI6ImZhbHNlIjtjYXNlIk51bGxWYWx1ZSI6cmV0dXJuIm51bGwiO2Nhc2UiVmFyaWFibGUiOnJldHVybiBjb25jYXQkOChbIiQiLGUuY2FsbChuLCJuYW1lIildKTtjYXNlIkxpc3RWYWx1ZSI6cmV0dXJuIGdyb3VwJDMoY29uY2F0JDgoWyJbIixpbmRlbnQkNihjb25jYXQkOChbc29mdGxpbmUkNCxqb2luJDYoY29uY2F0JDgoW2lmQnJlYWskMygiIiwiLCAiKSxzb2Z0bGluZSQ0XSksZS5tYXAobiwidmFsdWVzIikpXSkpLHNvZnRsaW5lJDQsIl0iXSkpO2Nhc2UiT2JqZWN0VmFsdWUiOnJldHVybiBncm91cCQzKGNvbmNhdCQ4KFsieyIsdC5icmFja2V0U3BhY2luZyYmci5maWVsZHMubGVuZ3RoPjA/IiAiOiIiLGluZGVudCQ2KGNvbmNhdCQ4KFtzb2Z0bGluZSQ0LGpvaW4kNihjb25jYXQkOChbaWZCcmVhayQzKCIiLCIsICIpLHNvZnRsaW5lJDRdKSxlLm1hcChuLCJmaWVsZHMiKSldKSksc29mdGxpbmUkNCxpZkJyZWFrJDMoIiIsdC5icmFja2V0U3BhY2luZyYmci5maWVsZHMubGVuZ3RoPjA/IiAiOiIiKSwifSJdKSk7Y2FzZSJPYmplY3RGaWVsZCI6Y2FzZSJBcmd1bWVudCI6cmV0dXJuIGNvbmNhdCQ4KFtlLmNhbGwobiwibmFtZSIpLCI6ICIsZS5jYWxsKG4sInZhbHVlIildKTtjYXNlIkRpcmVjdGl2ZSI6cmV0dXJuIGNvbmNhdCQ4KFsiQCIsZS5jYWxsKG4sIm5hbWUiKSxyLmFyZ3VtZW50cy5sZW5ndGg+MD9ncm91cCQzKGNvbmNhdCQ4KFsiKCIsaW5kZW50JDYoY29uY2F0JDgoW3NvZnRsaW5lJDQsam9pbiQ2KGNvbmNhdCQ4KFtpZkJyZWFrJDMoIiIsIiwgIiksc29mdGxpbmUkNF0pLGUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gcHJpbnRTZXF1ZW5jZShlLHQsbil9LCJhcmd1bWVudHMiKSldKSksc29mdGxpbmUkNCwiKSJdKSk6IiJdKTtjYXNlIk5hbWVkVHlwZSI6cmV0dXJuIGUuY2FsbChuLCJuYW1lIik7Y2FzZSJWYXJpYWJsZURlZmluaXRpb24iOnJldHVybiBjb25jYXQkOChbZS5jYWxsKG4sInZhcmlhYmxlIiksIjogIixlLmNhbGwobiwidHlwZSIpLHIuZGVmYXVsdFZhbHVlP2NvbmNhdCQ4KFsiID0gIixlLmNhbGwobiwiZGVmYXVsdFZhbHVlIildKToiIl0pO2Nhc2UiVHlwZUV4dGVuc2lvbkRlZmluaXRpb24iOnJldHVybiBjb25jYXQkOChbImV4dGVuZCAiLGUuY2FsbChuLCJkZWZpbml0aW9uIildKTtjYXNlIk9iamVjdFR5cGVFeHRlbnNpb24iOmNhc2UiT2JqZWN0VHlwZURlZmluaXRpb24iOnJldHVybiBjb25jYXQkOChbZS5jYWxsKG4sImRlc2NyaXB0aW9uIiksci5kZXNjcmlwdGlvbj9oYXJkbGluZSQ3OiIiLCJPYmplY3RUeXBlRXh0ZW5zaW9uIj09PXIua2luZD8iZXh0ZW5kICI6IiIsInR5cGUgIixlLmNhbGwobiwibmFtZSIpLHIuaW50ZXJmYWNlcy5sZW5ndGg+MD9jb25jYXQkOChbIiBpbXBsZW1lbnRzICIsam9pbiQ2KGRldGVybWluZUludGVyZmFjZVNlcGFyYXRvcih0Lm9yaWdpbmFsVGV4dC5zdWJzdHIodC5sb2NTdGFydChyKSx0LmxvY0VuZChyKSkpLGUubWFwKG4sImludGVyZmFjZXMiKSldKToiIixwcmludERpcmVjdGl2ZXMoZSxuLHIpLHIuZmllbGRzLmxlbmd0aD4wP2NvbmNhdCQ4KFsiIHsiLGluZGVudCQ2KGNvbmNhdCQ4KFtoYXJkbGluZSQ3LGpvaW4kNihoYXJkbGluZSQ3LGUuY2FsbChmdW5jdGlvbihlKXtyZXR1cm4gcHJpbnRTZXF1ZW5jZShlLHQsbil9LCJmaWVsZHMiKSldKSksaGFyZGxpbmUkNywifSJdKToiIl0pO2Nhc2UiRmllbGREZWZpbml0aW9uIjpyZXR1cm4gY29uY2F0JDgoW2UuY2FsbChuLCJkZXNjcmlwdGlvbiIpLHIuZGVzY3JpcHRpb24/aGFyZGxpbmUkNzoiIixlLmNhbGwobiwibmFtZSIpLHIuYXJndW1lbnRzLmxlbmd0aD4wP2dyb3VwJDMoY29uY2F0JDgoWyIoIixpbmRlbnQkNihjb25jYXQkOChbc29mdGxpbmUkNCxqb2luJDYoY29uY2F0JDgoW2lmQnJlYWskMygiIiwiLCAiKSxzb2Z0bGluZSQ0XSksZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBwcmludFNlcXVlbmNlKGUsdCxuKX0sImFyZ3VtZW50cyIpKV0pKSxzb2Z0bGluZSQ0LCIpIl0pKToiIiwiOiAiLGUuY2FsbChuLCJ0eXBlIikscHJpbnREaXJlY3RpdmVzKGUsbixyKV0pO2Nhc2UiRGlyZWN0aXZlRGVmaW5pdGlvbiI6cmV0dXJuIGNvbmNhdCQ4KFtlLmNhbGwobiwiZGVzY3JpcHRpb24iKSxyLmRlc2NyaXB0aW9uP2hhcmRsaW5lJDc6IiIsImRpcmVjdGl2ZSAiLCJAIixlLmNhbGwobiwibmFtZSIpLHIuYXJndW1lbnRzLmxlbmd0aD4wP2dyb3VwJDMoY29uY2F0JDgoWyIoIixpbmRlbnQkNihjb25jYXQkOChbc29mdGxpbmUkNCxqb2luJDYoY29uY2F0JDgoW2lmQnJlYWskMygiIiwiLCAiKSxzb2Z0bGluZSQ0XSksZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBwcmludFNlcXVlbmNlKGUsdCxuKX0sImFyZ3VtZW50cyIpKV0pKSxzb2Z0bGluZSQ0LCIpIl0pKToiIixjb25jYXQkOChbIiBvbiAiLGpvaW4kNigiIHwgIixlLm1hcChuLCJsb2NhdGlvbnMiKSldKV0pO2Nhc2UiRW51bVR5cGVFeHRlbnNpb24iOmNhc2UiRW51bVR5cGVEZWZpbml0aW9uIjpyZXR1cm4gY29uY2F0JDgoW2UuY2FsbChuLCJkZXNjcmlwdGlvbiIpLHIuZGVzY3JpcHRpb24/aGFyZGxpbmUkNzoiIiwiRW51bVR5cGVFeHRlbnNpb24iPT09ci5raW5kPyJleHRlbmQgIjoiIiwiZW51bSAiLGUuY2FsbChuLCJuYW1lIikscHJpbnREaXJlY3RpdmVzKGUsbixyKSxyLnZhbHVlcy5sZW5ndGg+MD9jb25jYXQkOChbIiB7IixpbmRlbnQkNihjb25jYXQkOChbaGFyZGxpbmUkNyxqb2luJDYoaGFyZGxpbmUkNyxlLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIHByaW50U2VxdWVuY2UoZSx0LG4pfSwidmFsdWVzIikpXSkpLGhhcmRsaW5lJDcsIn0iXSk6IiJdKTtjYXNlIkVudW1WYWx1ZURlZmluaXRpb24iOnJldHVybiBjb25jYXQkOChbZS5jYWxsKG4sImRlc2NyaXB0aW9uIiksci5kZXNjcmlwdGlvbj9oYXJkbGluZSQ3OiIiLGUuY2FsbChuLCJuYW1lIikscHJpbnREaXJlY3RpdmVzKGUsbixyKV0pO2Nhc2UiSW5wdXRWYWx1ZURlZmluaXRpb24iOnJldHVybiBjb25jYXQkOChbZS5jYWxsKG4sImRlc2NyaXB0aW9uIiksci5kZXNjcmlwdGlvbj9yLmRlc2NyaXB0aW9uLmJsb2NrP2hhcmRsaW5lJDc6bGluZSQ1OiIiLGUuY2FsbChuLCJuYW1lIiksIjogIixlLmNhbGwobiwidHlwZSIpLHIuZGVmYXVsdFZhbHVlP2NvbmNhdCQ4KFsiID0gIixlLmNhbGwobiwiZGVmYXVsdFZhbHVlIildKToiIixwcmludERpcmVjdGl2ZXMoZSxuLHIpXSk7Y2FzZSJJbnB1dE9iamVjdFR5cGVFeHRlbnNpb24iOmNhc2UiSW5wdXRPYmplY3RUeXBlRGVmaW5pdGlvbiI6cmV0dXJuIGNvbmNhdCQ4KFtlLmNhbGwobiwiZGVzY3JpcHRpb24iKSxyLmRlc2NyaXB0aW9uP2hhcmRsaW5lJDc6IiIsIklucHV0T2JqZWN0VHlwZUV4dGVuc2lvbiI9PT1yLmtpbmQ/ImV4dGVuZCAiOiIiLCJpbnB1dCAiLGUuY2FsbChuLCJuYW1lIikscHJpbnREaXJlY3RpdmVzKGUsbixyKSxyLmZpZWxkcy5sZW5ndGg+MD9jb25jYXQkOChbIiB7IixpbmRlbnQkNihjb25jYXQkOChbaGFyZGxpbmUkNyxqb2luJDYoaGFyZGxpbmUkNyxlLmNhbGwoZnVuY3Rpb24oZSl7cmV0dXJuIHByaW50U2VxdWVuY2UoZSx0LG4pfSwiZmllbGRzIikpXSkpLGhhcmRsaW5lJDcsIn0iXSk6IiJdKTtjYXNlIlNjaGVtYURlZmluaXRpb24iOnJldHVybiBjb25jYXQkOChbInNjaGVtYSIscHJpbnREaXJlY3RpdmVzKGUsbixyKSwiIHsiLHIub3BlcmF0aW9uVHlwZXMubGVuZ3RoPjA/aW5kZW50JDYoY29uY2F0JDgoW2hhcmRsaW5lJDcsam9pbiQ2KGhhcmRsaW5lJDcsZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBwcmludFNlcXVlbmNlKGUsdCxuKX0sIm9wZXJhdGlvblR5cGVzIikpXSkpOiIiLGhhcmRsaW5lJDcsIn0iXSk7Y2FzZSJPcGVyYXRpb25UeXBlRGVmaW5pdGlvbiI6cmV0dXJuIGNvbmNhdCQ4KFtlLmNhbGwobiwib3BlcmF0aW9uIiksIjogIixlLmNhbGwobiwidHlwZSIpXSk7Y2FzZSJJbnRlcmZhY2VUeXBlRXh0ZW5zaW9uIjpjYXNlIkludGVyZmFjZVR5cGVEZWZpbml0aW9uIjpyZXR1cm4gY29uY2F0JDgoW2UuY2FsbChuLCJkZXNjcmlwdGlvbiIpLHIuZGVzY3JpcHRpb24/aGFyZGxpbmUkNzoiIiwiSW50ZXJmYWNlVHlwZUV4dGVuc2lvbiI9PT1yLmtpbmQ/ImV4dGVuZCAiOiIiLCJpbnRlcmZhY2UgIixlLmNhbGwobiwibmFtZSIpLHByaW50RGlyZWN0aXZlcyhlLG4sciksci5maWVsZHMubGVuZ3RoPjA/Y29uY2F0JDgoWyIgeyIsaW5kZW50JDYoY29uY2F0JDgoW2hhcmRsaW5lJDcsam9pbiQ2KGhhcmRsaW5lJDcsZS5jYWxsKGZ1bmN0aW9uKGUpe3JldHVybiBwcmludFNlcXVlbmNlKGUsdCxuKX0sImZpZWxkcyIpKV0pKSxoYXJkbGluZSQ3LCJ9Il0pOiIiXSk7Y2FzZSJGcmFnbWVudFNwcmVhZCI6cmV0dXJuIGNvbmNhdCQ4KFsiLi4uIixlLmNhbGwobiwibmFtZSIpLHByaW50RGlyZWN0aXZlcyhlLG4scildKTtjYXNlIklubGluZUZyYWdtZW50IjpyZXR1cm4gY29uY2F0JDgoWyIuLi4iLHIudHlwZUNvbmRpdGlvbj9jb25jYXQkOChbIiBvbiAiLGUuY2FsbChuLCJ0eXBlQ29uZGl0aW9uIildKToiIixwcmludERpcmVjdGl2ZXMoZSxuLHIpLCIgIixlLmNhbGwobiwic2VsZWN0aW9uU2V0IildKTtjYXNlIlVuaW9uVHlwZUV4dGVuc2lvbiI6Y2FzZSJVbmlvblR5cGVEZWZpbml0aW9uIjpyZXR1cm4gZ3JvdXAkMyhjb25jYXQkOChbZS5jYWxsKG4sImRlc2NyaXB0aW9uIiksci5kZXNjcmlwdGlvbj9oYXJkbGluZSQ3OiIiLGdyb3VwJDMoY29uY2F0JDgoWyJVbmlvblR5cGVFeHRlbnNpb24iPT09ci5raW5kPyJleHRlbmQgIjoiIiwidW5pb24gIixlLmNhbGwobiwibmFtZSIpLHByaW50RGlyZWN0aXZlcyhlLG4sciksci50eXBlcy5sZW5ndGg+MD9jb25jYXQkOChbIiA9IixpZkJyZWFrJDMoIiIsIiAiKSxpbmRlbnQkNihjb25jYXQkOChbaWZCcmVhayQzKGNvbmNhdCQ4KFtsaW5lJDUsIiAgIl0pKSxqb2luJDYoY29uY2F0JDgoW2xpbmUkNSwifCAiXSksZS5tYXAobiwidHlwZXMiKSldKSldKToiIl0pKV0pKTtjYXNlIlNjYWxhclR5cGVFeHRlbnNpb24iOmNhc2UiU2NhbGFyVHlwZURlZmluaXRpb24iOnJldHVybiBjb25jYXQkOChbZS5jYWxsKG4sImRlc2NyaXB0aW9uIiksci5kZXNjcmlwdGlvbj9oYXJkbGluZSQ3OiIiLCJTY2FsYXJUeXBlRXh0ZW5zaW9uIj09PXIua2luZD8iZXh0ZW5kICI6IiIsInNjYWxhciAiLGUuY2FsbChuLCJuYW1lIikscHJpbnREaXJlY3RpdmVzKGUsbixyKV0pO2Nhc2UiTm9uTnVsbFR5cGUiOnJldHVybiBjb25jYXQkOChbZS5jYWxsKG4sInR5cGUiKSwiISJdKTtjYXNlIkxpc3RUeXBlIjpyZXR1cm4gY29uY2F0JDgoWyJbIixlLmNhbGwobiwidHlwZSIpLCJdIl0pO2RlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJ1bmtub3duIGdyYXBocWwgdHlwZTogIitKU09OLnN0cmluZ2lmeShyLmtpbmQpKX19ZnVuY3Rpb24gcHJpbnREaXJlY3RpdmVzKGUsdCxuKXtyZXR1cm4gMD09PW4uZGlyZWN0aXZlcy5sZW5ndGg/IiI6Y29uY2F0JDgoWyIgIixncm91cCQzKGluZGVudCQ2KGNvbmNhdCQ4KFtzb2Z0bGluZSQ0LGpvaW4kNihjb25jYXQkOChbaWZCcmVhayQzKCIiLCIgIiksc29mdGxpbmUkNF0pLGUubWFwKHQsImRpcmVjdGl2ZXMiKSldKSkpXSl9ZnVuY3Rpb24gcHJpbnRTZXF1ZW5jZShlLHQsbil7dmFyIHI9ZS5nZXRWYWx1ZSgpLmxlbmd0aDtyZXR1cm4gZS5tYXAoZnVuY3Rpb24oZSxpKXt2YXIgbz1uKGUpO3JldHVybiBpc05leHRMaW5lRW1wdHkkNCh0Lm9yaWdpbmFsVGV4dCxlLmdldFZhbHVlKCksdCkmJmk8ci0xP2NvbmNhdCQ4KFtvLGhhcmRsaW5lJDddKTpvfSl9ZnVuY3Rpb24gY2FuQXR0YWNoQ29tbWVudCQxKGUpe3JldHVybiBlLmtpbmQmJiJDb21tZW50IiE9PWUua2luZH1mdW5jdGlvbiBwcmludENvbW1lbnQkMihlKXt2YXIgdD1lLmdldFZhbHVlKCk7c3dpdGNoKHQua2luZCl7Y2FzZSJDb21tZW50IjpyZXR1cm4iIyIrdC52YWx1ZS50cmltUmlnaHQoKTtkZWZhdWx0OnRocm93IG5ldyBFcnJvcigiTm90IGEgY29tbWVudDogIitKU09OLnN0cmluZ2lmeSh0KSl9fWZ1bmN0aW9uIGRldGVybWluZUludGVyZmFjZVNlcGFyYXRvcihlKXt2YXIgdD1lLmluZGV4T2YoImltcGxlbWVudHMiKTtpZigtMT09PXQpdGhyb3cgbmV3IEVycm9yKCJNdXN0IGltcGxlbWVudCBpbnRlcmZhY2VzOiAiK2UpO3ZhciBuPWUuaW5kZXhPZigieyIpO3JldHVybi0xPT09biYmKG49ZS5sZW5ndGgpLGUuc3Vic3RyKHQsbikuaW5jbHVkZXMoIiYiKT8iICYgIjoiLCAifWZ1bmN0aW9uIGNsZWFuJDUoZSx0KXtkZWxldGUgdC5sb2MsZGVsZXRlIHQuY29tbWVudHN9ZnVuY3Rpb24gZW1iZWQkMihlLHQsbixyKXt2YXIgaT1lLmdldFZhbHVlKCk7aWYoImNvZGUiPT09aS50eXBlJiZudWxsIT09aS5sYW5nKXt2YXIgbz1pLmxhbmcuc3BsaXQoL1xzLywxKVswXSxhPWZ1bmN0aW9uKGUpe3ZhciB0PXN1cHBvcnQuZ2V0U3VwcG9ydEluZm8obnVsbCx7cGx1Z2luczpyLnBsdWdpbnN9KSxuPXQubGFuZ3VhZ2VzLmZpbmQoZnVuY3Rpb24odCl7cmV0dXJuIHQubmFtZS50b0xvd2VyQ2FzZSgpPT09ZXx8dC5leHRlbnNpb25zJiZ0LmV4dGVuc2lvbnMuZmluZChmdW5jdGlvbih0KXtyZXR1cm4gdC5zdWJzdHJpbmcoMSk9PT1lfSl9KTtyZXR1cm4gbj9uLnBhcnNlcnNbMF06bnVsbH0obyk7aWYoYSl7dmFyIHM9ci5fX2luSnNUZW1wbGF0ZT8ifiI6ImAiLHU9cy5yZXBlYXQoTWF0aC5tYXgoMyx1dGlsLmdldE1heENvbnRpbnVvdXNDb3VudChpLnZhbHVlLHMpKzEpKSxjPW4oaS52YWx1ZSx7cGFyc2VyOmF9KTtyZXR1cm4gbWFya0FzUm9vdCQxKGNvbmNhdCQxMChbdSxpLmxhbmcsaGFyZGxpbmUkOSxmdW5jdGlvbihlKXtyZXR1cm4gbWFwRG9jJDQoZSxmdW5jdGlvbihlKXtyZXR1cm4ic3RyaW5nIj09PXR5cGVvZiBlJiZlLmluY2x1ZGVzKCJcbiIpP2NvbmNhdCQxMChlLnNwbGl0KC8oXG4pL2cpLm1hcChmdW5jdGlvbihlLHQpe3JldHVybiB0JTI9PT0wP2U6bGl0ZXJhbGxpbmUkM30pKTplfSl9KGMpLHVdKSl9fXJldHVybiBudWxsfWZ1bmN0aW9uIHBhcnNlJDMoZSl7dmFyIHQ7MD09PWUuaW5kZXhPZigiLS0tIik/dD0iLS0tIjowPT09ZS5pbmRleE9mKCIrKysiKSYmKHQ9IisrKyIpO3ZhciBuPS0xO3JldHVybiB0JiYtMSE9PShuPWUuaW5kZXhPZigiXG4iLmNvbmNhdCh0KSwzKSk/KG4rPTQse2Zyb250TWF0dGVyOmUuc2xpY2UoMCxuKSxjb250ZW50OmUuc2xpY2Uobil9KTp7ZnJvbnRNYXR0ZXI6bnVsbCxjb250ZW50OmV9fWZ1bmN0aW9uIGdlbmVyaWNQcmludCQ1KGUsdCxuKXt2YXIgcj1lLmdldFZhbHVlKCk7aWYoc2hvdWxkUmVtYWluVGhlU2FtZUNvbnRlbnQoZSkpcmV0dXJuIGNvbmNhdCQ5KHV0aWwuc3BsaXRUZXh0KHQub3JpZ2luYWxUZXh0LnNsaWNlKHIucG9zaXRpb24uc3RhcnQub2Zmc2V0LHIucG9zaXRpb24uZW5kLm9mZnNldCksdCkubWFwKGZ1bmN0aW9uKG4pe3JldHVybiJ3b3JkIj09PW4udHlwZT9uLnZhbHVlOiIiPT09bi52YWx1ZT8iIjpwcmludExpbmUoZSxuLnZhbHVlLHQpfSkpO3N3aXRjaChyLnR5cGUpe2Nhc2Uicm9vdCI6cmV0dXJuIDA9PT1yLmNoaWxkcmVuLmxlbmd0aD8iIjpjb25jYXQkOShbbm9ybWFsaXplRG9jKHByaW50Um9vdChlLHQsbikpLGhhcmRsaW5lJDhdKTtjYXNlInBhcmFncmFwaCI6cmV0dXJuIHByaW50Q2hpbGRyZW4oZSx0LG4se3Bvc3Rwcm9jZXNzb3I6ZmlsbCQ0fSk7Y2FzZSJzZW50ZW5jZSI6cmV0dXJuIHByaW50Q2hpbGRyZW4oZSx0LG4pO2Nhc2Uid29yZCI6cmV0dXJuIHIudmFsdWUucmVwbGFjZSgvWypdL2csIlxcKiIpLnJlcGxhY2UobmV3IFJlZ0V4cChbIihefFsiLmNvbmNhdCh1dGlsLnB1bmN0dWF0aW9uQ2hhclJhbmdlLCJdKShfKykiKSwiKF8rKShbIi5jb25jYXQodXRpbC5wdW5jdHVhdGlvbkNoYXJSYW5nZSwiXXwkKSIpXS5qb2luKCJ8IiksImciKSxmdW5jdGlvbihlLHQsbixyLGkpe3JldHVybihuPyIiLmNvbmNhdCh0KS5jb25jYXQobik6IiIuY29uY2F0KHIpLmNvbmNhdChpKSkucmVwbGFjZSgvXy9nLCJcXF8iKX0pO2Nhc2Uid2hpdGVzcGFjZSI6dmFyIGk9ZS5nZXRQYXJlbnROb2RlKCksbz1pLmNoaWxkcmVuLmluZGV4T2YociksYT1pLmNoaWxkcmVuW28rMV0scz1hJiYvXj58XihbLSsqXXwjezEsNn18WzAtOV0rWy4pXSkkLy50ZXN0KGEudmFsdWUpPyJuZXZlciI6dC5wcm9zZVdyYXA7cmV0dXJuIHByaW50TGluZShlLHIudmFsdWUse3Byb3NlV3JhcDpzfSk7Y2FzZSJlbXBoYXNpcyI6dmFyIHU9ZS5nZXRQYXJlbnROb2RlKCksYz11LmNoaWxkcmVuLmluZGV4T2YociksbD11LmNoaWxkcmVuW2MtMV0scD11LmNoaWxkcmVuW2MrMV0sZj1sJiYic2VudGVuY2UiPT09bC50eXBlJiZsLmNoaWxkcmVuLmxlbmd0aD4wJiYid29yZCI9PT11dGlsLmdldExhc3QobC5jaGlsZHJlbikudHlwZSYmIXV0aWwuZ2V0TGFzdChsLmNoaWxkcmVuKS5oYXNUcmFpbGluZ1B1bmN0dWF0aW9ufHxwJiYic2VudGVuY2UiPT09cC50eXBlJiZwLmNoaWxkcmVuLmxlbmd0aD4wJiYid29yZCI9PT1wLmNoaWxkcmVuWzBdLnR5cGUmJiFwLmNoaWxkcmVuWzBdLmhhc0xlYWRpbmdQdW5jdHVhdGlvbixkPWZ8fGdldEFuY2VzdG9yTm9kZSQyKGUsImVtcGhhc2lzIik/IioiOiJfIjtyZXR1cm4gY29uY2F0JDkoW2QscHJpbnRDaGlsZHJlbihlLHQsbiksZF0pO2Nhc2Uic3Ryb25nIjpyZXR1cm4gY29uY2F0JDkoWyIqKiIscHJpbnRDaGlsZHJlbihlLHQsbiksIioqIl0pO2Nhc2UiZGVsZXRlIjpyZXR1cm4gY29uY2F0JDkoWyJ+fiIscHJpbnRDaGlsZHJlbihlLHQsbiksIn5+Il0pO2Nhc2UiaW5saW5lQ29kZSI6dmFyIGg9dXRpbC5nZXRNYXhDb250aW51b3VzQ291bnQoci52YWx1ZSwiYCIpLG09MT09PWg/ImBgIjoiYCIsZz1oPyIgIjoiIjtyZXR1cm4gY29uY2F0JDkoW20sZyxyLnZhbHVlLGcsbV0pO2Nhc2UibGluayI6c3dpdGNoKHQub3JpZ2luYWxUZXh0W3IucG9zaXRpb24uc3RhcnQub2Zmc2V0XSl7Y2FzZSI8IjpyZXR1cm4gY29uY2F0JDkoWyI8IixyLnVybCwiPiJdKTtjYXNlIlsiOnJldHVybiBjb25jYXQkOShbIlsiLHByaW50Q2hpbGRyZW4oZSx0LG4pLCJdKCIscHJpbnRVcmwoci51cmwsIikiKSxwcmludFRpdGxlKHIudGl0bGUsdCksIikiXSk7ZGVmYXVsdDpyZXR1cm4gdC5vcmlnaW5hbFRleHQuc2xpY2Uoci5wb3NpdGlvbi5zdGFydC5vZmZzZXQsci5wb3NpdGlvbi5lbmQub2Zmc2V0KX1jYXNlImltYWdlIjpyZXR1cm4gY29uY2F0JDkoWyIhWyIsci5hbHR8fCIiLCJdKCIscHJpbnRVcmwoci51cmwsIikiKSxwcmludFRpdGxlKHIudGl0bGUsdCksIikiXSk7Y2FzZSJibG9ja3F1b3RlIjpyZXR1cm4gY29uY2F0JDkoWyI+ICIsYWxpZ24kMigiPiAiLHByaW50Q2hpbGRyZW4oZSx0LG4pKV0pO2Nhc2UiaGVhZGluZyI6cmV0dXJuIGNvbmNhdCQ5KFsiIyIucmVwZWF0KHIuZGVwdGgpKyIgIixwcmludENoaWxkcmVuKGUsdCxuKV0pO2Nhc2UiY29kZSI6aWYoL15cbj8oIHs0LH18XHQpLy50ZXN0KHQub3JpZ2luYWxUZXh0LnNsaWNlKHIucG9zaXRpb24uc3RhcnQub2Zmc2V0LHIucG9zaXRpb24uZW5kLm9mZnNldCkpKXt2YXIgeT0iICIucmVwZWF0KDQpO3JldHVybiBhbGlnbiQyKHksY29uY2F0JDkoW3ksam9pbiQ3KGhhcmRsaW5lJDgsci52YWx1ZS5zcGxpdCgiXG4iKSldKSl9dmFyIHY9dC5fX2luSnNUZW1wbGF0ZT8ifiI6ImAiLGI9di5yZXBlYXQoTWF0aC5tYXgoMyx1dGlsLmdldE1heENvbnRpbnVvdXNDb3VudChyLnZhbHVlLHYpKzEpKTtyZXR1cm4gY29uY2F0JDkoW2Isci5sYW5nfHwiIixoYXJkbGluZSQ4LGpvaW4kNyhoYXJkbGluZSQ4LHIudmFsdWUuc3BsaXQoIlxuIikpLGhhcmRsaW5lJDgsYl0pO2Nhc2UiZnJvbnQtbWF0dGVyIjpyZXR1cm4gci52YWx1ZTtjYXNlImh0bWwiOnZhciB4PWUuZ2V0UGFyZW50Tm9kZSgpO3JldHVybiByZXBsYWNlTmV3bGluZXNXaXRoSGFyZGxpbmVzKCJyb290Ij09PXgudHlwZSYmdXRpbC5nZXRMYXN0KHguY2hpbGRyZW4pPT09cj9yLnZhbHVlLnRyaW1SaWdodCgpOnIudmFsdWUpO2Nhc2UibGlzdCI6dmFyIEM9Z2V0TnRoTGlzdFNpYmxpbmdJbmRleChyLGUuZ2V0UGFyZW50Tm9kZSgpKSxFPXIub3JkZXJlZCYmci5jaGlsZHJlbi5sZW5ndGg+MSYmL15ccyoxKFwufFwpKS8udGVzdCh0Lm9yaWdpbmFsVGV4dC5zbGljZShyLmNoaWxkcmVuWzFdLnBvc2l0aW9uLnN0YXJ0Lm9mZnNldCxyLmNoaWxkcmVuWzFdLnBvc2l0aW9uLmVuZC5vZmZzZXQpKTtyZXR1cm4gcHJpbnRDaGlsZHJlbihlLHQsbix7cHJvY2Vzc29yOmZ1bmN0aW9uKGUsaSl7dmFyIG89ZnVuY3Rpb24oKXt2YXIgbj1yLm9yZGVyZWQ/KDA9PT1pP3Iuc3RhcnQ6RT8xOnIuc3RhcnQraSkrKEMlMj09PTA/Ii4gIjoiKSAiKTpDJTI9PT0wPyItICI6IiogIjtyZXR1cm4gZS5nZXRWYWx1ZSgpLmNoaWxkcmVuLmxlbmd0aD9hbGlnbkxpc3RQcmVmaXgobix0KTpufSgpO3JldHVybiBjb25jYXQkOShbbyxhbGlnbiQyKCIgIi5yZXBlYXQoby5sZW5ndGgpLHByaW50TGlzdEl0ZW0oZSx0LG4sbykpXSl9fSk7Y2FzZSJ0aGVtYXRpY0JyZWFrIjp2YXIgRD1nZXRBbmNlc3RvckNvdW50ZXIkMShlLCJsaXN0Iik7aWYoLTE9PT1EKXJldHVybiItLS0iO3JldHVybiBnZXROdGhMaXN0U2libGluZ0luZGV4KGUuZ2V0UGFyZW50Tm9kZShEKSxlLmdldFBhcmVudE5vZGUoRCsxKSklMj09PTA/IioqKiI6Ii0tLSI7Y2FzZSJsaW5rUmVmZXJlbmNlIjpyZXR1cm4gY29uY2F0JDkoWyJbIixwcmludENoaWxkcmVuKGUsdCxuKSwiXSIsImZ1bGwiPT09ci5yZWZlcmVuY2VUeXBlP2NvbmNhdCQ5KFsiWyIsci5pZGVudGlmaWVyLCJdIl0pOiJjb2xsYXBzZWQiPT09ci5yZWZlcmVuY2VUeXBlPyJbXSI6IiJdKTtjYXNlImltYWdlUmVmZXJlbmNlIjpzd2l0Y2goci5yZWZlcmVuY2VUeXBlKXtjYXNlImZ1bGwiOnJldHVybiBjb25jYXQkOShbIiFbIixyLmFsdHx8IiIsIl1bIixyLmlkZW50aWZpZXIsIl0iXSk7ZGVmYXVsdDpyZXR1cm4gY29uY2F0JDkoWyIhWyIsci5hbHQsIl0iLCJjb2xsYXBzZWQiPT09ci5yZWZlcmVuY2VUeXBlPyJbXSI6IiJdKX1jYXNlImRlZmluaXRpb24iOnZhciB3PSJhbHdheXMiPT09dC5wcm9zZVdyYXA/bGluZSQ2OiIgIjtyZXR1cm4gZ3JvdXAkNChjb25jYXQkOShbY29uY2F0JDkoWyJbIixyLmlkZW50aWZpZXIsIl06Il0pLGluZGVudCQ3KGNvbmNhdCQ5KFt3LHByaW50VXJsKHIudXJsKSxudWxsPT09ci50aXRsZT8iIjpjb25jYXQkOShbdyxwcmludFRpdGxlKHIudGl0bGUsdCwhMSldKV0pKV0pKTtjYXNlImZvb3Rub3RlIjpyZXR1cm4gY29uY2F0JDkoWyJbXiIscHJpbnRDaGlsZHJlbihlLHQsbiksIl0iXSk7Y2FzZSJmb290bm90ZVJlZmVyZW5jZSI6cmV0dXJuIGNvbmNhdCQ5KFsiW14iLHIuaWRlbnRpZmllciwiXSJdKTtjYXNlImZvb3Rub3RlRGVmaW5pdGlvbiI6dmFyIFM9ZS5nZXRQYXJlbnROb2RlKCkuY2hpbGRyZW5bZS5nZXROYW1lKCkrMV07cmV0dXJuIGNvbmNhdCQ5KFsiW14iLHIuaWRlbnRpZmllciwiXTogIixncm91cCQ0KGNvbmNhdCQ5KFthbGlnbiQyKCIgIi5yZXBlYXQodC50YWJXaWR0aCkscHJpbnRDaGlsZHJlbihlLHQsbix7cHJvY2Vzc29yOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIDA9PT10P2dyb3VwJDQoY29uY2F0JDkoW3NvZnRsaW5lJDUsc29mdGxpbmUkNSxlLmNhbGwobildKSk6ZS5jYWxsKG4pfX0pKSxTJiYiZm9vdG5vdGVEZWZpbml0aW9uIj09PVMudHlwZT9zb2Z0bGluZSQ1OiIiXSkpXSk7Y2FzZSJ0YWJsZSI6cmV0dXJuIHByaW50VGFibGUoZSx0LG4pO2Nhc2UidGFibGVDZWxsIjpyZXR1cm4gcHJpbnRDaGlsZHJlbihlLHQsbik7Y2FzZSJicmVhayI6cmV0dXJuIGNvbmNhdCQ5KFsvXHMvLnRlc3QodC5vcmlnaW5hbFRleHRbci5wb3NpdGlvbi5zdGFydC5vZmZzZXRdKT8iICAiOiJcXCIsaGFyZGxpbmUkOF0pO2Nhc2UibGlxdWlkTm9kZSI6cmV0dXJuIHJlcGxhY2VOZXdsaW5lc1dpdGhIYXJkbGluZXMoci52YWx1ZSk7Y2FzZSJ0YWJsZVJvdyI6Y2FzZSJsaXN0SXRlbSI6ZGVmYXVsdDp0aHJvdyBuZXcgRXJyb3IoIlVua25vd24gbWFya2Rvd24gdHlwZSAiLmNvbmNhdChKU09OLnN0cmluZ2lmeShyLnR5cGUpKSl9fWZ1bmN0aW9uIHByaW50TGlzdEl0ZW0oZSx0LG4scil7dmFyIGk9ZS5nZXRWYWx1ZSgpLG89bnVsbD09PWkuY2hlY2tlZD8iIjppLmNoZWNrZWQ/Ilt4XSAiOiJbIF0gIjtyZXR1cm4gY29uY2F0JDkoW28scHJpbnRDaGlsZHJlbihlLHQsbix7cHJvY2Vzc29yOmZ1bmN0aW9uKGUsaSl7aWYoMD09PWkmJiJsaXN0IiE9PWUuZ2V0VmFsdWUoKS50eXBlKXJldHVybiBhbGlnbiQyKCIgIi5yZXBlYXQoby5sZW5ndGgpLGUuY2FsbChuKSk7dmFyIGE9IiAiLnJlcGVhdChjbGFtcCh0LnRhYldpZHRoLXIubGVuZ3RoLDAsMykpO3JldHVybiBjb25jYXQkOShbYSxhbGlnbiQyKGEsZS5jYWxsKG4pKV0pfX0pXSl9ZnVuY3Rpb24gYWxpZ25MaXN0UHJlZml4KGUsdCl7dmFyIG49ZnVuY3Rpb24oKXt2YXIgbj1lLmxlbmd0aCV0LnRhYldpZHRoO3JldHVybiAwPT09bj8wOnQudGFiV2lkdGgtbn0oKTtyZXR1cm4gZSsiICIucmVwZWF0KG4+PTQ/MDpuKX1mdW5jdGlvbiBnZXROdGhMaXN0U2libGluZ0luZGV4KGUsdCl7cmV0dXJuIGdldE50aFNpYmxpbmdJbmRleChlLHQsZnVuY3Rpb24odCl7cmV0dXJuIHQub3JkZXJlZD09PWUub3JkZXJlZH0pfWZ1bmN0aW9uIHJlcGxhY2VOZXdsaW5lc1dpdGhIYXJkbGluZXMoZSl7cmV0dXJuIGpvaW4kNyhoYXJkbGluZSQ4LGUuc3BsaXQoIlxuIikpfWZ1bmN0aW9uIGdldE50aFNpYmxpbmdJbmRleChlLHQsbil7bj1ufHxmdW5jdGlvbigpe3JldHVybiEwfTt2YXIgcj0tMSxpPSEwLG89ITEsYT12b2lkIDA7dHJ5e2Zvcih2YXIgcyx1PXQuY2hpbGRyZW5bU3ltYm9sLml0ZXJhdG9yXSgpOyEoaT0ocz11Lm5leHQoKSkuZG9uZSk7aT0hMCl7dmFyIGM9cy52YWx1ZTtpZihjLnR5cGU9PT1lLnR5cGUmJm4oYyk/cisrOnI9LTEsYz09PWUpcmV0dXJuIHJ9fWNhdGNoKGUpe289ITAsYT1lfWZpbmFsbHl7dHJ5e2l8fG51bGw9PXUucmV0dXJufHx1LnJldHVybigpfWZpbmFsbHl7aWYobyl0aHJvdyBhfX19ZnVuY3Rpb24gZ2V0QW5jZXN0b3JDb3VudGVyJDEoZSx0KXtmb3IodmFyIG4scj1bXS5jb25jYXQodCksaT0tMTtuPWUuZ2V0UGFyZW50Tm9kZSgrK2kpOylpZigtMSE9PXIuaW5kZXhPZihuLnR5cGUpKXJldHVybiBpO3JldHVybi0xfWZ1bmN0aW9uIGdldEFuY2VzdG9yTm9kZSQyKGUsdCl7dmFyIG49Z2V0QW5jZXN0b3JDb3VudGVyJDEoZSx0KTtyZXR1cm4tMT09PW4/bnVsbDplLmdldFBhcmVudE5vZGUobil9ZnVuY3Rpb24gcHJpbnRMaW5lKGUsdCxuKXtpZigicHJlc2VydmUiPT09bi5wcm9zZVdyYXAmJiJcbiI9PT10KXJldHVybiBoYXJkbGluZSQ4O3ZhciByPSJhbHdheXMiPT09bi5wcm9zZVdyYXAmJiFnZXRBbmNlc3Rvck5vZGUkMihlLFNJTkdMRV9MSU5FX05PREVfVFlQRVMpO3JldHVybiIiIT09dD9yP2xpbmUkNjoiICI6cj9zb2Z0bGluZSQ1OiIifWZ1bmN0aW9uIHByaW50VGFibGUoZSx0LG4pe2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGNvbmNhdCQ5KFsifCAiLGpvaW4kNygiIHwgIixlLm1hcChmdW5jdGlvbihlLHQpe3N3aXRjaChzLmFsaWduW3RdKXtjYXNlInJpZ2h0IjpyZXR1cm4gbyhlLGNbdF0pO2Nhc2UiY2VudGVyIjpyZXR1cm4gYShlLGNbdF0pO2RlZmF1bHQ6cmV0dXJuIGkoZSxjW3RdKX19KSksIiB8Il0pfWZ1bmN0aW9uIGkoZSx0KXtyZXR1cm4gY29uY2F0JDkoW2UsIiAiLnJlcGVhdCh0LXV0aWwuZ2V0U3RyaW5nV2lkdGgoZSkpXSl9ZnVuY3Rpb24gbyhlLHQpe3JldHVybiBjb25jYXQkOShbIiAiLnJlcGVhdCh0LXV0aWwuZ2V0U3RyaW5nV2lkdGgoZSkpLGVdKX1mdW5jdGlvbiBhKGUsdCl7dmFyIG49dC11dGlsLmdldFN0cmluZ1dpZHRoKGUpLHI9TWF0aC5mbG9vcihuLzIpLGk9bi1yO3JldHVybiBjb25jYXQkOShbIiAiLnJlcGVhdChyKSxlLCIgIi5yZXBlYXQoaSldKX12YXIgcz1lLmdldFZhbHVlKCksdT1bXTtlLm1hcChmdW5jdGlvbihlKXt2YXIgcj1bXTtlLm1hcChmdW5jdGlvbihlKXtyLnB1c2gocHJpbnREb2NUb1N0cmluZyQyKGUuY2FsbChuKSx0KS5mb3JtYXR0ZWQpfSwiY2hpbGRyZW4iKSx1LnB1c2gocil9LCJjaGlsZHJlbiIpO3ZhciBjPXUucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUubWFwKGZ1bmN0aW9uKGUsbil7cmV0dXJuIE1hdGgubWF4KGUsdXRpbC5nZXRTdHJpbmdXaWR0aCh0W25dKSl9KX0sdVswXS5tYXAoZnVuY3Rpb24oKXtyZXR1cm4gM30pKTtyZXR1cm4gam9pbiQ3KGhhcmRsaW5lJDgsW3IodVswXSksZnVuY3Rpb24oKXtyZXR1cm4gY29uY2F0JDkoWyJ8ICIsam9pbiQ3KCIgfCAiLGMubWFwKGZ1bmN0aW9uKGUsdCl7c3dpdGNoKHMuYWxpZ25bdF0pe2Nhc2UibGVmdCI6cmV0dXJuIjoiKyItIi5yZXBlYXQoZS0xKTtjYXNlInJpZ2h0IjpyZXR1cm4iLSIucmVwZWF0KGUtMSkrIjoiO2Nhc2UiY2VudGVyIjpyZXR1cm4iOiIrIi0iLnJlcGVhdChlLTIpKyI6IjtkZWZhdWx0OnJldHVybiItIi5yZXBlYXQoZSl9fSkpLCIgfCJdKX0oKSxqb2luJDcoaGFyZGxpbmUkOCx1LnNsaWNlKDEpLm1hcChyKSldKX1mdW5jdGlvbiBwcmludFJvb3QoZSx0LG4pe3ZhciByPVtdLGk9bnVsbCxvPWUuZ2V0VmFsdWUoKS5jaGlsZHJlbjtyZXR1cm4gby5mb3JFYWNoKGZ1bmN0aW9uKGUsdCl7c3dpdGNoKGlzUHJldHRpZXJJZ25vcmUoZSkpe2Nhc2Uic3RhcnQiOm51bGw9PT1pJiYoaT17aW5kZXg6dCxvZmZzZXQ6ZS5wb3NpdGlvbi5lbmQub2Zmc2V0fSk7YnJlYWs7Y2FzZSJlbmQiOm51bGwhPT1pJiYoci5wdXNoKHtzdGFydDppLGVuZDp7aW5kZXg6dCxvZmZzZXQ6ZS5wb3NpdGlvbi5zdGFydC5vZmZzZXR9fSksaT1udWxsKX19KSxwcmludENoaWxkcmVuKGUsdCxuLHtwcm9jZXNzb3I6ZnVuY3Rpb24oZSxpKXtpZigwIT09ci5sZW5ndGgpe3ZhciBhPXJbMF07aWYoaT09PWEuc3RhcnQuaW5kZXgpcmV0dXJuIGNvbmNhdCQ5KFtvW2Euc3RhcnQuaW5kZXhdLnZhbHVlLHQub3JpZ2luYWxUZXh0LnNsaWNlKGEuc3RhcnQub2Zmc2V0LGEuZW5kLm9mZnNldCksb1thLmVuZC5pbmRleF0udmFsdWVdKTtpZihhLnN0YXJ0LmluZGV4PGkmJmk8YS5lbmQuaW5kZXgpcmV0dXJuITE7aWYoaT09PWEuZW5kLmluZGV4KXJldHVybiByLnNoaWZ0KCksITF9cmV0dXJuIGUuY2FsbChuKX19KX1mdW5jdGlvbiBwcmludENoaWxkcmVuKGUsdCxuLHIpe3I9cnx8e307dmFyIGksbz1yLnBvc3Rwcm9jZXNzb3J8fGNvbmNhdCQ5LGE9ci5wcm9jZXNzb3J8fGZ1bmN0aW9uKGUpe3JldHVybiBlLmNhbGwobil9LHM9ZS5nZXRWYWx1ZSgpLHU9W107cmV0dXJuIGUubWFwKGZ1bmN0aW9uKGUsbil7dmFyIHI9ZS5nZXRWYWx1ZSgpLG89YShlLG4pO2lmKCExIT09byl7dmFyIGM9e3BhcnRzOnUscHJldk5vZGU6aSxwYXJlbnROb2RlOnMsb3B0aW9uczp0fTtzaG91bGROb3RQcmVQcmludEhhcmRsaW5lKHIsYyl8fCh1LnB1c2goaGFyZGxpbmUkOCksKHNob3VsZFByZVByaW50RG91YmxlSGFyZGxpbmUocixjKXx8c2hvdWxkUHJlUHJpbnRUcmlwbGVIYXJkbGluZShyLGMpKSYmdS5wdXNoKGhhcmRsaW5lJDgpLHNob3VsZFByZVByaW50VHJpcGxlSGFyZGxpbmUocixjKSYmdS5wdXNoKGhhcmRsaW5lJDgpKSx1LnB1c2gobyksaT1yfX0sImNoaWxkcmVuIiksbyh1KX1mdW5jdGlvbiBpc1ByZXR0aWVySWdub3JlKGUpe2lmKCJodG1sIiE9PWUudHlwZSlyZXR1cm4hMTt2YXIgdD1lLnZhbHVlLm1hdGNoKC9ePCEtLVxzKnByZXR0aWVyLWlnbm9yZSg/Oi0oc3RhcnR8ZW5kKSk/XHMqLS0+JC8pO3JldHVybiBudWxsIT09dCYmKHRbMV0/dFsxXToibmV4dCIpfWZ1bmN0aW9uIHNob3VsZE5vdFByZVByaW50SGFyZGxpbmUoZSx0KXt2YXIgbj0wPT09dC5wYXJ0cy5sZW5ndGgscj0tMSE9PUlOTElORV9OT0RFX1RZUEVTLmluZGV4T2YoZS50eXBlKSxpPSJodG1sIj09PWUudHlwZSYmLTEhPT1JTkxJTkVfTk9ERV9XUkFQUEVSX1RZUEVTLmluZGV4T2YodC5wYXJlbnROb2RlLnR5cGUpO3JldHVybiBufHxyfHxpfWZ1bmN0aW9uIHNob3VsZFByZVByaW50RG91YmxlSGFyZGxpbmUoZSx0KXt2YXIgbj0odC5wcmV2Tm9kZSYmdC5wcmV2Tm9kZS50eXBlKT09PWUudHlwZSxyPW4mJi0xIT09U0lCTElOR19OT0RFX1RZUEVTLmluZGV4T2YoZS50eXBlKSxpPSJsaXN0SXRlbSI9PT10LnBhcmVudE5vZGUudHlwZSYmIXQucGFyZW50Tm9kZS5sb29zZSxvPXQucHJldk5vZGUmJiJsaXN0SXRlbSI9PT10LnByZXZOb2RlLnR5cGUmJnQucHJldk5vZGUubG9vc2UsYT0ibmV4dCI9PT1pc1ByZXR0aWVySWdub3JlKHQucHJldk5vZGUpO3JldHVybiBvfHwhKHJ8fGl8fGEpfWZ1bmN0aW9uIHNob3VsZFByZVByaW50VHJpcGxlSGFyZGxpbmUoZSx0KXt2YXIgbj10LnByZXZOb2RlJiYibGlzdCI9PT10LnByZXZOb2RlLnR5cGUscj0iY29kZSI9PT1lLnR5cGUmJi9ccy8udGVzdCh0Lm9wdGlvbnMub3JpZ2luYWxUZXh0W2UucG9zaXRpb24uc3RhcnQub2Zmc2V0XSk7cmV0dXJuIG4mJnJ9ZnVuY3Rpb24gc2hvdWxkUmVtYWluVGhlU2FtZUNvbnRlbnQoZSl7dmFyIHQ9Z2V0QW5jZXN0b3JOb2RlJDIoZSxbImxpbmtSZWZlcmVuY2UiLCJpbWFnZVJlZmVyZW5jZSJdKTtyZXR1cm4gdCYmKCJsaW5rUmVmZXJlbmNlIiE9PXQudHlwZXx8ImZ1bGwiIT09dC5yZWZlcmVuY2VUeXBlKX1mdW5jdGlvbiBub3JtYWxpemVEb2MoZSl7cmV0dXJuIG1hcERvYyQzKGUsZnVuY3Rpb24oZSl7aWYoIWUucGFydHMpcmV0dXJuIGU7aWYoImNvbmNhdCI9PT1lLnR5cGUmJjE9PT1lLnBhcnRzLmxlbmd0aClyZXR1cm4gZS5wYXJ0c1swXTt2YXIgdD1bXTtyZXR1cm4gZS5wYXJ0cy5mb3JFYWNoKGZ1bmN0aW9uKGUpeyJjb25jYXQiPT09ZS50eXBlP3QucHVzaC5hcHBseSh0LGUucGFydHMpOiIiIT09ZSYmdC5wdXNoKGUpfSksT2JqZWN0LmFzc2lnbih7fSxlLHtwYXJ0czpub3JtYWxpemVQYXJ0cyh0KX0pfSl9ZnVuY3Rpb24gcHJpbnRVcmwoZSx0KXt2YXIgbj1bIiAiXS5jb25jYXQodHx8W10pO3JldHVybiBuZXcgUmVnRXhwKG4ubWFwKGZ1bmN0aW9uKGUpe3JldHVybiJcXCIuY29uY2F0KGUpfSkuam9pbigifCIpKS50ZXN0KGUpPyI8Ii5jb25jYXQoZSwiPiIpOmV9ZnVuY3Rpb24gcHJpbnRUaXRsZShlLHQsbil7aWYobnVsbD09biYmKG49ITApLCFlKXJldHVybiIiO2lmKG4pcmV0dXJuIiAiK3ByaW50VGl0bGUoZSx0LCExKTtpZihlLmluY2x1ZGVzKCciJykmJmUuaW5jbHVkZXMoIiciKSYmIWUuaW5jbHVkZXMoIikiKSlyZXR1cm4iKCIuY29uY2F0KGUsIikiKTt2YXIgcj1lLnNwbGl0KCInIikubGVuZ3RoLTEsaT1lLnNwbGl0KCciJykubGVuZ3RoLTEsbz1yPmk/JyInOmk+cj8iJyI6dC5zaW5nbGVRdW90ZT8iJyI6JyInO3JldHVybiBlPWUucmVwbGFjZShuZXcgUmVnRXhwKCIoIi5jb25jYXQobywiKSIpLCJnIiksIlxcJDEiKSwiIi5jb25jYXQobykuY29uY2F0KGUpLmNvbmNhdChvKX1mdW5jdGlvbiBub3JtYWxpemVQYXJ0cyhlKXtyZXR1cm4gZS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXt2YXIgbj11dGlsLmdldExhc3QoZSk7cmV0dXJuInN0cmluZyI9PT10eXBlb2YgbiYmInN0cmluZyI9PT10eXBlb2YgdD9lLnNwbGljZSgtMSwxLG4rdCk6ZS5wdXNoKHQpLGV9LFtdKX1mdW5jdGlvbiBjbGFtcChlLHQsbil7cmV0dXJuIGU8dD90OmU+bj9uOmV9ZnVuY3Rpb24gY2xlYW4kNihlLHQsbil7aWYoZGVsZXRlIHQucG9zaXRpb24sImNvZGUiPT09ZS50eXBlJiZkZWxldGUgdC52YWx1ZSwid2hpdGVzcGFjZSI9PT1lLnR5cGUmJiJcbiI9PT1lLnZhbHVlJiYodC52YWx1ZT0iICIpLG4mJiJyb290Ij09PW4udHlwZSYmbi5jaGlsZHJlbi5sZW5ndGg+MCYmKG4uY2hpbGRyZW5bMF09PT1lfHwiZnJvbnQtbWF0dGVyIj09PW4uY2hpbGRyZW5bMF0udHlwZSYmbi5jaGlsZHJlblsxXT09PWUpJiYiaHRtbCI9PT1lLnR5cGUmJnByYWdtYSQyLnN0YXJ0V2l0aFByYWdtYShlLnZhbHVlKSlyZXR1cm4gbnVsbH1mdW5jdGlvbiBoYXNQcmV0dGllcklnbm9yZSQxKGUpe3ZhciB0PStlLmdldE5hbWUoKTtyZXR1cm4gMCE9PXQmJiJuZXh0Ij09PWlzUHJldHRpZXJJZ25vcmUoZS5nZXRQYXJlbnROb2RlKCkuY2hpbGRyZW5bdC0xXSl9ZnVuY3Rpb24gZW1iZWQkNChlLHQsbixyKXt2YXIgaT1lLmdldFZhbHVlKCksbz1lLmdldFBhcmVudE5vZGUoKTtpZighb3x8InJvb3QiIT09by50YWd8fGkudW5hcnkpcmV0dXJuIG51bGw7dmFyIGE7aWYoInN0eWxlIj09PWkudGFnKXt2YXIgcz1pLmF0dHJzLmZpbmQoZnVuY3Rpb24oZSl7cmV0dXJuImxhbmciPT09ZS5uYW1lfSk7cyYmInBvc3Rjc3MiIT09cy52YWx1ZT8ic2NzcyI9PT1zLnZhbHVlP2E9InNjc3MiOiJsZXNzIj09PXMudmFsdWUmJihhPSJsZXNzIik6YT0iY3NzIn1pZigic2NyaXB0Ij09PWkudGFnKXt2YXIgdT1pLmF0dHJzLmZpbmQoZnVuY3Rpb24oZSl7cmV0dXJuImxhbmciPT09ZS5uYW1lfSk7dT8idHMiIT09dS52YWx1ZSYmInRzeCIhPT11LnZhbHVlfHwoYT0idHlwZXNjcmlwdCIpOmE9ImJhYnlsb24ifXJldHVybiBhP2NvbmNhdCQxMihbci5vcmlnaW5hbFRleHQuc2xpY2UoaS5zdGFydCxpLmNvbnRlbnRTdGFydCksaGFyZGxpbmUkMTEsbihyLm9yaWdpbmFsVGV4dC5zbGljZShpLmNvbnRlbnRTdGFydCxpLmNvbnRlbnRFbmQpLHtwYXJzZXI6YX0pLHIub3JpZ2luYWxUZXh0LnNsaWNlKGkuY29udGVudEVuZCxpLmVuZCldKTpudWxsfWZ1bmN0aW9uIGdlbmVyaWNQcmludCQ2KGUsdCxuKXt2YXIgcj1lLmdldFZhbHVlKCksaT1bXSxvPXIuc3RhcnQ7cmV0dXJuIGUuZWFjaChmdW5jdGlvbihlKXt2YXIgcj1lLmdldFZhbHVlKCk7aS5wdXNoKHQub3JpZ2luYWxUZXh0LnNsaWNlKG8sci5zdGFydCkpLGkucHVzaChlLmNhbGwobikpLG89ci5lbmR9LCJjaGlsZHJlbiIpLGkucHVzaCh0Lm9yaWdpbmFsVGV4dC5zbGljZShvLHIuZW5kKSksInJvb3QiPT09ci50YWcmJnIuY2hpbGRyZW4ubGVuZ3RoJiZpLnB1c2goaGFyZGxpbmUkMTApLGNvbmNhdCQxMShpKX1mdW5jdGlvbiB3aXRoUGx1Z2lucyhlKXtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgdD1BcnJheS5mcm9tKGFyZ3VtZW50cyksbj10WzFdJiZ0WzFdLnBsdWdpbnN8fFtdO3JldHVybiBpc0FycmF5KG4pfHwobj1PYmplY3QudmFsdWVzKG4pKSx0WzFdPU9iamVjdC5hc3NpZ24oe30sdFsxXSx7cGx1Z2luczppbnRlcm5hbFBsdWdpbnMuY29uY2F0KG4pfSksZS5hcHBseShudWxsLHQpfX12YXIgbmFtZT0icHJldHRpZXIiLHZlcnNpb24kMT0iMS4xMy4yIixkZXNjcmlwdGlvbj0iUHJldHRpZXIgaXMgYW4gb3BpbmlvbmF0ZWQgY29kZSBmb3JtYXR0ZXIiLGJpbj17cHJldHRpZXI6Ii4vYmluL3ByZXR0aWVyLmpzIn0scmVwb3NpdG9yeT0icHJldHRpZXIvcHJldHRpZXIiLGhvbWVwYWdlPSJodHRwczovL3ByZXR0aWVyLmlvIixhdXRob3I9IkphbWVzIExvbmciLGxpY2Vuc2U9Ik1JVCIsbWFpbj0iLi9pbmRleC5qcyIsZW5naW5lcz17bm9kZToiPj02In0sZGVwZW5kZW5jaWVzPXsiQGJhYmVsL2NvZGUtZnJhbWUiOiI3LjAuMC1iZXRhLjQ5IiwiQGJhYmVsL3BhcnNlciI6IjcuMC4wLWJldGEuNDkiLCJAZ2xpbW1lci9zeW50YXgiOiIwLjMwLjMiLGNhbWVsY2FzZToiNC4xLjAiLGNoYWxrOiIyLjEuMCIsImNqay1yZWdleCI6IjEuMC4yIixjb3NtaWNvbmZpZzoiMy4xLjAiLGRhc2hpZnk6IjAuMi4yIixkZWRlbnQ6IjAuNy4wIixkaWZmOiIzLjIuMCIsZWRpdG9yY29uZmlnOiIwLjE1LjAiLCJlZGl0b3Jjb25maWctdG8tcHJldHRpZXIiOiIwLjAuNiIsImVtb2ppLXJlZ2V4IjoiNi41LjEiLCJlc2NhcGUtc3RyaW5nLXJlZ2V4cCI6IjEuMC41Iixlc3V0aWxzOiIyLjAuMiIsImZpbmQtcGFyZW50LWRpciI6IjAuMy4wIiwiZmluZC1wcm9qZWN0LXJvb3QiOiIxLjEuMSIsImZsb3ctcGFyc2VyIjoiMC43My4wIiwiZ2V0LXN0cmVhbSI6IjMuMC4wIixnbG9iYnk6IjYuMS4wIixncmFwaHFsOiIwLjEzLjIiLCJodG1sLXRhZy1uYW1lcyI6IjEuMS4yIixpZ25vcmU6IjMuMy43IiwiamVzdC1kb2NibG9jayI6IjIyLjIuMiIsImpzb24tc3RhYmxlLXN0cmluZ2lmeSI6IjEuMC4xIixsZXZlbjoiMi4xLjAiLCJsb2Rhc2gudW5pcWJ5IjoiNC43LjAiLG1lbToiMS4xLjAiLG1pbmltYXRjaDoiMy4wLjQiLG1pbmltaXN0OiIxLjIuMCIscGFyc2U1OiIzLjAuMyIsInBvc3Rjc3MtbGVzcyI6IjEuMS41IiwicG9zdGNzcy1tZWRpYS1xdWVyeS1wYXJzZXIiOiIwLjIuMyIsInBvc3Rjc3Mtc2NzcyI6IjEuMC41IiwicG9zdGNzcy1zZWxlY3Rvci1wYXJzZXIiOiIyLjIuMyIsInBvc3Rjc3MtdmFsdWVzLXBhcnNlciI6IjEuNS4wIiwicmVtYXJrLXBhcnNlIjoiNS4wLjAiLHJlc29sdmU6IjEuNS4wIixzZW12ZXI6IjUuNC4xIiwic3RyaW5nLXdpZHRoIjoiMi4xLjEiLHR5cGVzY3JpcHQ6IjIuOS4wLWRldi4yMDE4MDQyMSIsInR5cGVzY3JpcHQtZXNsaW50LXBhcnNlciI6ImVzbGludC90eXBlc2NyaXB0LWVzbGludC1wYXJzZXIjMjk2MGIwMDI3NDZjMDFmYjljYjE1YmI1ZjRjMWU3ZTkyNWM2NTE5YSIsInVuaWNvZGUtcmVnZXgiOiIxLjAuMSIsdW5pZmllZDoiNi4xLjYifSxkZXZEZXBlbmRlbmNpZXM9eyJAYmFiZWwvY2xpIjoiNy4wLjAtYmV0YS40OSIsIkBiYWJlbC9jb3JlIjoiNy4wLjAtYmV0YS40OSIsIkBiYWJlbC9wcmVzZXQtZW52IjoiNy4wLjAtYmV0YS40OSIsImJ1aWx0aW4tbW9kdWxlcyI6IjIuMC4wIixjb2RlY292OiIyLjIuMCIsImNyb3NzLWVudiI6IjUuMC41Iixlc2xpbnQ6IjQuMTguMiIsImVzbGludC1jb25maWctcHJldHRpZXIiOiIyLjkuMCIsImVzbGludC1mcmllbmRseS1mb3JtYXR0ZXIiOiIzLjAuMCIsImVzbGludC1wbHVnaW4taW1wb3J0IjoiMi45LjAiLCJlc2xpbnQtcGx1Z2luLXByZXR0aWVyIjoiMi42LjAiLCJlc2xpbnQtcGx1Z2luLXJlYWN0IjoiNy43LjAiLGplc3Q6IjIxLjEuMCIsbWtkaXJwOiIwLjUuMSIscHJldHRpZXI6IjEuMTMuMCIscHJldHR5bGludDoiMS4wLjAiLHJpbXJhZjoiMi42LjIiLHJvbGx1cDoiMC40Ny42Iiwicm9sbHVwLXBsdWdpbi1iYWJlbCI6IjQuMC4wLWJldGEuNCIsInJvbGx1cC1wbHVnaW4tY29tbW9uanMiOiI4LjIuNiIsInJvbGx1cC1wbHVnaW4tanNvbiI6IjIuMS4xIiwicm9sbHVwLXBsdWdpbi1ub2RlLWJ1aWx0aW5zIjoiMi4wLjAiLCJyb2xsdXAtcGx1Z2luLW5vZGUtZ2xvYmFscyI6IjEuMS4wIiwicm9sbHVwLXBsdWdpbi1ub2RlLXJlc29sdmUiOiIyLjAuMCIsInJvbGx1cC1wbHVnaW4tcmVwbGFjZSI6IjEuMi4xIiwicm9sbHVwLXBsdWdpbi11Z2xpZnkiOiIzLjAuMCIsc2hlbGxqczoiMC44LjEiLCJzbmFwc2hvdC1kaWZmIjoiMC4yLjIiLCJzdHJpcC1hbnNpIjoiNC4wLjAiLHRlbXB5OiIwLjIuMSIsd2VicGFjazoiMi42LjEifSxzY3JpcHRzPXtwcmVwdWJsaXNoT25seTonZWNobyAiRXJyb3I6IG11c3QgcHVibGlzaCBmcm9tIGRpc3QvIiAmJiBleGl0IDEnLCJwcmVwYXJlLXJlbGVhc2UiOiJ5YXJuICYmIHlhcm4gYnVpbGQgJiYgeWFybiB0ZXN0OmRpc3QiLHRlc3Q6Implc3QiLCJ0ZXN0OmRpc3QiOiJub2RlIC4vc2NyaXB0cy90ZXN0LWRpc3QuanMiLCJ0ZXN0LWludGVncmF0aW9uIjoiamVzdCB0ZXN0c19pbnRlZ3JhdGlvbiIsbGludDoiY3Jvc3MtZW52IEVGRl9OT19MSU5LX1JVTEVTPXRydWUgZXNsaW50IC4gLS1mb3JtYXQgbm9kZV9tb2R1bGVzL2VzbGludC1mcmllbmRseS1mb3JtYXR0ZXIiLCJsaW50LWRvY3MiOiJwcmV0dHlsaW50IHsuLGRvY3Msd2Vic2l0ZSx3ZWJzaXRlL2Jsb2d9LyoubWQiLGJ1aWxkOiJub2RlIC4vc2NyaXB0cy9idWlsZC9idWlsZC5qcyIsImJ1aWxkLWRvY3MiOiJub2RlIC4vc2NyaXB0cy9idWlsZC1kb2NzLmpzIiwiY2hlY2stZGVwcyI6Im5vZGUgLi9zY3JpcHRzL2NoZWNrLWRlcHMuanMifSxfcGFja2FnZT17bmFtZTpuYW1lLHZlcnNpb246dmVyc2lvbiQxLGRlc2NyaXB0aW9uOmRlc2NyaXB0aW9uLGJpbjpiaW4scmVwb3NpdG9yeTpyZXBvc2l0b3J5LGhvbWVwYWdlOmhvbWVwYWdlLGF1dGhvcjphdXRob3IsbGljZW5zZTpsaWNlbnNlLG1haW46bWFpbixlbmdpbmVzOmVuZ2luZXMsZGVwZW5kZW5jaWVzOmRlcGVuZGVuY2llcyxkZXZEZXBlbmRlbmNpZXM6ZGV2RGVwZW5kZW5jaWVzLHNjcmlwdHM6c2NyaXB0c30sX3BhY2thZ2UkMT1PYmplY3QuZnJlZXplKHtuYW1lOm5hbWUsdmVyc2lvbjp2ZXJzaW9uJDEsZGVzY3JpcHRpb246ZGVzY3JpcHRpb24sYmluOmJpbixyZXBvc2l0b3J5OnJlcG9zaXRvcnksaG9tZXBhZ2U6aG9tZXBhZ2UsYXV0aG9yOmF1dGhvcixsaWNlbnNlOmxpY2Vuc2UsbWFpbjptYWluLGVuZ2luZXM6ZW5naW5lcyxkZXBlbmRlbmNpZXM6ZGVwZW5kZW5jaWVzLGRldkRlcGVuZGVuY2llczpkZXZEZXBlbmRlbmNpZXMsc2NyaXB0czpzY3JpcHRzLGRlZmF1bHQ6X3BhY2thZ2V9KSxjb21tb25qc0dsb2JhbD0idW5kZWZpbmVkIiE9PXR5cGVvZiB3aW5kb3c/d2luZG93OiJ1bmRlZmluZWQiIT09dHlwZW9mIGdsb2JhbD9nbG9iYWw6InVuZGVmaW5lZCIhPT10eXBlb2Ygc2VsZj9zZWxmOnt9LGJhc2U9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKCl7fWZ1bmN0aW9uIHIoZSx0LG4scixpKXtmb3IodmFyIG89MCxhPXQubGVuZ3RoLHM9MCx1PTA7bzxhO28rKyl7dmFyIGM9dFtvXTtpZihjLnJlbW92ZWQpe2lmKGMudmFsdWU9ZS5qb2luKHIuc2xpY2UodSx1K2MuY291bnQpKSx1Kz1jLmNvdW50LG8mJnRbby0xXS5hZGRlZCl7dmFyIGw9dFtvLTFdO3Rbby0xXT10W29dLHRbb109bH19ZWxzZXtpZighYy5hZGRlZCYmaSl7dmFyIHA9bi5zbGljZShzLHMrYy5jb3VudCk7cD1wLm1hcChmdW5jdGlvbihlLHQpe3ZhciBuPXJbdSt0XTtyZXR1cm4gbi5sZW5ndGg+ZS5sZW5ndGg/bjplfSksYy52YWx1ZT1lLmpvaW4ocCl9ZWxzZSBjLnZhbHVlPWUuam9pbihuLnNsaWNlKHMscytjLmNvdW50KSk7cys9Yy5jb3VudCxjLmFkZGVkfHwodSs9Yy5jb3VudCl9fXZhciBmPXRbYS0xXTtyZXR1cm4gYT4xJiYoZi5hZGRlZHx8Zi5yZW1vdmVkKSYmZS5lcXVhbHMoIiIsZi52YWx1ZSkmJih0W2EtMl0udmFsdWUrPWYudmFsdWUsdC5wb3AoKSksdH1mdW5jdGlvbiBpKGUpe3JldHVybntuZXdQb3M6ZS5uZXdQb3MsY29tcG9uZW50czplLmNvbXBvbmVudHMuc2xpY2UoMCl9fXQuX19lc01vZHVsZT0hMCx0LmRlZmF1bHQ9bixuLnByb3RvdHlwZT17ZGlmZjpmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7cmV0dXJuIHM/KHNldFRpbWVvdXQoZnVuY3Rpb24oKXtzKHZvaWQgMCxlKX0sMCksITApOmV9ZnVuY3Rpb24gbygpe2Zvcih2YXIgbz0tMSpwO288PXA7bys9Mil7dmFyIGE9dm9pZCAwLHM9ZFtvLTFdLGY9ZFtvKzFdLGg9KGY/Zi5uZXdQb3M6MCktbztzJiYoZFtvLTFdPXZvaWQgMCk7dmFyIG09cyYmcy5uZXdQb3MrMTxjLGc9ZiYmMDw9aCYmaDxsO2lmKG18fGcpe2lmKCFtfHxnJiZzLm5ld1BvczxmLm5ld1Bvcz8oYT1pKGYpLHUucHVzaENvbXBvbmVudChhLmNvbXBvbmVudHMsdm9pZCAwLCEwKSk6KGE9cyxhLm5ld1BvcysrLHUucHVzaENvbXBvbmVudChhLmNvbXBvbmVudHMsITAsdm9pZCAwKSksaD11LmV4dHJhY3RDb21tb24oYSx0LGUsbyksYS5uZXdQb3MrMT49YyYmaCsxPj1sKXJldHVybiBuKHIodSxhLmNvbXBvbmVudHMsdCxlLHUudXNlTG9uZ2VzdFRva2VuKSk7ZFtvXT1hfWVsc2UgZFtvXT12b2lkIDB9cCsrfXZhciBhPWFyZ3VtZW50cy5sZW5ndGg8PTJ8fHZvaWQgMD09PWFyZ3VtZW50c1syXT97fTphcmd1bWVudHNbMl0scz1hLmNhbGxiYWNrOyJmdW5jdGlvbiI9PT10eXBlb2YgYSYmKHM9YSxhPXt9KSx0aGlzLm9wdGlvbnM9YTt2YXIgdT10aGlzO2U9dGhpcy5jYXN0SW5wdXQoZSksdD10aGlzLmNhc3RJbnB1dCh0KSxlPXRoaXMucmVtb3ZlRW1wdHkodGhpcy50b2tlbml6ZShlKSksdD10aGlzLnJlbW92ZUVtcHR5KHRoaXMudG9rZW5pemUodCkpO3ZhciBjPXQubGVuZ3RoLGw9ZS5sZW5ndGgscD0xLGY9YytsLGQ9W3tuZXdQb3M6LTEsY29tcG9uZW50czpbXX1dLGg9dGhpcy5leHRyYWN0Q29tbW9uKGRbMF0sdCxlLDApO2lmKGRbMF0ubmV3UG9zKzE+PWMmJmgrMT49bClyZXR1cm4gbihbe3ZhbHVlOnRoaXMuam9pbih0KSxjb3VudDp0Lmxlbmd0aH1dKTtpZihzKSFmdW5jdGlvbiBlKCl7c2V0VGltZW91dChmdW5jdGlvbigpe2lmKHA+ZilyZXR1cm4gcygpO28oKXx8ZSgpfSwwKX0oKTtlbHNlIGZvcig7cDw9Zjspe3ZhciBtPW8oKTtpZihtKXJldHVybiBtfX0scHVzaENvbXBvbmVudDpmdW5jdGlvbihlLHQsbil7dmFyIHI9ZVtlLmxlbmd0aC0xXTtyJiZyLmFkZGVkPT09dCYmci5yZW1vdmVkPT09bj9lW2UubGVuZ3RoLTFdPXtjb3VudDpyLmNvdW50KzEsYWRkZWQ6dCxyZW1vdmVkOm59OmUucHVzaCh7Y291bnQ6MSxhZGRlZDp0LHJlbW92ZWQ6bn0pfSxleHRyYWN0Q29tbW9uOmZ1bmN0aW9uKGUsdCxuLHIpe2Zvcih2YXIgaT10Lmxlbmd0aCxvPW4ubGVuZ3RoLGE9ZS5uZXdQb3Mscz1hLXIsdT0wO2ErMTxpJiZzKzE8byYmdGhpcy5lcXVhbHModFthKzFdLG5bcysxXSk7KWErKyxzKyssdSsrO3JldHVybiB1JiZlLmNvbXBvbmVudHMucHVzaCh7Y291bnQ6dX0pLGUubmV3UG9zPWEsc30sZXF1YWxzOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIGU9PT10fSxyZW1vdmVFbXB0eTpmdW5jdGlvbihlKXtmb3IodmFyIHQ9W10sbj0wO248ZS5sZW5ndGg7bisrKWVbbl0mJnQucHVzaChlW25dKTtyZXR1cm4gdH0sY2FzdElucHV0OmZ1bmN0aW9uKGUpe3JldHVybiBlfSx0b2tlbml6ZTpmdW5jdGlvbihlKXtyZXR1cm4gZS5zcGxpdCgiIil9LGpvaW46ZnVuY3Rpb24oZSl7cmV0dXJuIGUuam9pbigiIil9fX0pO3Vud3JhcEV4cG9ydHMoYmFzZSk7dmFyIGNoYXJhY3Rlcj1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSx0LG4pe3JldHVybiBpLmRpZmYoZSx0LG4pfXQuX19lc01vZHVsZT0hMCx0LmNoYXJhY3RlckRpZmY9dm9pZCAwLHQuZGlmZkNoYXJzPW47dmFyIHI9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShiYXNlKSxpPXQuY2hhcmFjdGVyRGlmZj1uZXcgci5kZWZhdWx0fSk7dW53cmFwRXhwb3J0cyhjaGFyYWN0ZXIpO3ZhciBwYXJhbXM9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUsdCl7aWYoImZ1bmN0aW9uIj09PXR5cGVvZiBlKXQuY2FsbGJhY2s9ZTtlbHNlIGlmKGUpZm9yKHZhciBuIGluIGUpZS5oYXNPd25Qcm9wZXJ0eShuKSYmKHRbbl09ZVtuXSk7cmV0dXJuIHR9dC5fX2VzTW9kdWxlPSEwLHQuZ2VuZXJhdGVPcHRpb25zPW59KTt1bndyYXBFeHBvcnRzKHBhcmFtcyk7dmFyIHdvcmQ9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUsdCxuKXt2YXIgcj0oMCxwYXJhbXMuZ2VuZXJhdGVPcHRpb25zKShuLHtpZ25vcmVXaGl0ZXNwYWNlOiEwfSk7cmV0dXJuIHMuZGlmZihlLHQscil9ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuIHMuZGlmZihlLHQsbil9dC5fX2VzTW9kdWxlPSEwLHQud29yZERpZmY9dm9pZCAwLHQuZGlmZldvcmRzPW4sdC5kaWZmV29yZHNXaXRoU3BhY2U9cjt2YXIgaT1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19KGJhc2UpLG89L15bQS1aYS16XHhDMC1cdTAyQzZcdTAyQzgtXHUwMkQ3XHUwMkRFLVx1MDJGRlx1MUUwMC1cdTFFRkZdKyQvLGE9L1xTLyxzPXQud29yZERpZmY9bmV3IGkuZGVmYXVsdDtzLmVxdWFscz1mdW5jdGlvbihlLHQpe3JldHVybiBlPT09dHx8dGhpcy5vcHRpb25zLmlnbm9yZVdoaXRlc3BhY2UmJiFhLnRlc3QoZSkmJiFhLnRlc3QodCl9LHMudG9rZW5pemU9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWUuc3BsaXQoLyhccyt8XGIpLyksbj0wO248dC5sZW5ndGgtMTtuKyspIXRbbisxXSYmdFtuKzJdJiZvLnRlc3QodFtuXSkmJm8udGVzdCh0W24rMl0pJiYodFtuXSs9dFtuKzJdLHQuc3BsaWNlKG4rMSwyKSxuLS0pO3JldHVybiB0fX0pO3Vud3JhcEV4cG9ydHMod29yZCk7dmFyIGxpbmU9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUsdCxuKXtyZXR1cm4gby5kaWZmKGUsdCxuKX1mdW5jdGlvbiByKGUsdCxuKXt2YXIgcj0oMCxwYXJhbXMuZ2VuZXJhdGVPcHRpb25zKShuLHtpZ25vcmVXaGl0ZXNwYWNlOiEwfSk7cmV0dXJuIG8uZGlmZihlLHQscil9dC5fX2VzTW9kdWxlPSEwLHQubGluZURpZmY9dm9pZCAwLHQuZGlmZkxpbmVzPW4sdC5kaWZmVHJpbW1lZExpbmVzPXI7dmFyIGk9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShiYXNlKSxvPXQubGluZURpZmY9bmV3IGkuZGVmYXVsdDtvLnRva2VuaXplPWZ1bmN0aW9uKGUpe3ZhciB0PVtdLG49ZS5zcGxpdCgvKFxufFxyXG4pLyk7bltuLmxlbmd0aC0xXXx8bi5wb3AoKTtmb3IodmFyIHI9MDtyPG4ubGVuZ3RoO3IrKyl7dmFyIGk9bltyXTtyJTImJiF0aGlzLm9wdGlvbnMubmV3bGluZUlzVG9rZW4/dFt0Lmxlbmd0aC0xXSs9aToodGhpcy5vcHRpb25zLmlnbm9yZVdoaXRlc3BhY2UmJihpPWkudHJpbSgpKSx0LnB1c2goaSkpfXJldHVybiB0fX0pO3Vud3JhcEV4cG9ydHMobGluZSk7dmFyIHNlbnRlbmNlPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUsdCl7ZnVuY3Rpb24gbihlLHQsbil7cmV0dXJuIGkuZGlmZihlLHQsbil9dC5fX2VzTW9kdWxlPSEwLHQuc2VudGVuY2VEaWZmPXZvaWQgMCx0LmRpZmZTZW50ZW5jZXM9bjt2YXIgcj1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19KGJhc2UpLGk9dC5zZW50ZW5jZURpZmY9bmV3IHIuZGVmYXVsdDtpLnRva2VuaXplPWZ1bmN0aW9uKGUpe3JldHVybiBlLnNwbGl0KC8oXFMuKz9bLiE/XSkoPz1ccyt8JCkvKX19KTt1bndyYXBFeHBvcnRzKHNlbnRlbmNlKTt2YXIgY3NzPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUsdCl7ZnVuY3Rpb24gbihlLHQsbil7cmV0dXJuIGkuZGlmZihlLHQsbil9dC5fX2VzTW9kdWxlPSEwLHQuY3NzRGlmZj12b2lkIDAsdC5kaWZmQ3NzPW47dmFyIHI9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShiYXNlKSxpPXQuY3NzRGlmZj1uZXcgci5kZWZhdWx0O2kudG9rZW5pemU9ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc3BsaXQoLyhbe306OyxdfFxzKykvKX19KTt1bndyYXBFeHBvcnRzKGNzcyk7dmFyIGpzb249Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUsdCxuKXtyZXR1cm4gcy5kaWZmKGUsdCxuKX1mdW5jdGlvbiByKGUsdCxuKXt0PXR8fFtdLG49bnx8W107dmFyIG89dm9pZCAwO2ZvcihvPTA7bzx0Lmxlbmd0aDtvKz0xKWlmKHRbb109PT1lKXJldHVybiBuW29dO3ZhciBzPXZvaWQgMDtpZigiW29iamVjdCBBcnJheV0iPT09YS5jYWxsKGUpKXtmb3IodC5wdXNoKGUpLHM9bmV3IEFycmF5KGUubGVuZ3RoKSxuLnB1c2gocyksbz0wO288ZS5sZW5ndGg7bys9MSlzW29dPXIoZVtvXSx0LG4pO3JldHVybiB0LnBvcCgpLG4ucG9wKCksc31pZihlJiZlLnRvSlNPTiYmKGU9ZS50b0pTT04oKSksIm9iamVjdCI9PT0oInVuZGVmaW5lZCI9PT10eXBlb2YgZT8idW5kZWZpbmVkIjppKGUpKSYmbnVsbCE9PWUpe3QucHVzaChlKSxzPXt9LG4ucHVzaChzKTt2YXIgdT1bXSxjPXZvaWQgMDtmb3IoYyBpbiBlKWUuaGFzT3duUHJvcGVydHkoYykmJnUucHVzaChjKTtmb3IodS5zb3J0KCksbz0wO288dS5sZW5ndGg7bys9MSljPXVbb10sc1tjXT1yKGVbY10sdCxuKTt0LnBvcCgpLG4ucG9wKCl9ZWxzZSBzPWU7cmV0dXJuIHN9dC5fX2VzTW9kdWxlPSEwLHQuanNvbkRpZmY9dm9pZCAwO3ZhciBpPSJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiYic3ltYm9sIj09PV90eXBlb2YoU3ltYm9sLml0ZXJhdG9yKT9mdW5jdGlvbihlKXtyZXR1cm4gX3R5cGVvZihlKX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiZlLmNvbnN0cnVjdG9yPT09U3ltYm9sPyJzeW1ib2wiOl90eXBlb2YoZSl9O3QuZGlmZkpzb249bix0LmNhbm9uaWNhbGl6ZT1yO3ZhciBvPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0oYmFzZSksYT1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLHM9dC5qc29uRGlmZj1uZXcgby5kZWZhdWx0O3MudXNlTG9uZ2VzdFRva2VuPSEwLHMudG9rZW5pemU9bGluZS5saW5lRGlmZi50b2tlbml6ZSxzLmNhc3RJbnB1dD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLm9wdGlvbnMudW5kZWZpbmVkUmVwbGFjZW1lbnQ7cmV0dXJuInN0cmluZyI9PT10eXBlb2YgZT9lOkpTT04uc3RyaW5naWZ5KHIoZSksZnVuY3Rpb24oZSxuKXtyZXR1cm4idW5kZWZpbmVkIj09PXR5cGVvZiBuP3Q6bn0sIiAgIil9LHMuZXF1YWxzPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIG8uZGVmYXVsdC5wcm90b3R5cGUuZXF1YWxzKGUucmVwbGFjZSgvLChbXHJcbl0pL2csIiQxIiksdC5yZXBsYWNlKC8sKFtcclxuXSkvZywiJDEiKSl9fSk7dW53cmFwRXhwb3J0cyhqc29uKTt2YXIgYXJyYXk9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUsdCxuKXtyZXR1cm4gaS5kaWZmKGUsdCxuKX10Ll9fZXNNb2R1bGU9ITAsdC5hcnJheURpZmY9dm9pZCAwLHQuZGlmZkFycmF5cz1uO3ZhciByPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0oYmFzZSksaT10LmFycmF5RGlmZj1uZXcgci5kZWZhdWx0O2kudG9rZW5pemU9aS5qb2luPWZ1bmN0aW9uKGUpe3JldHVybiBlLnNsaWNlKCl9fSk7dW53cmFwRXhwb3J0cyhhcnJheSk7dmFyIHBhcnNlPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUsdCl7ZnVuY3Rpb24gbihlKXtmdW5jdGlvbiB0KGUpe3ZhciB0PS9eKC0tLXxcK1wrXCspXHMrKFtcUyBdKikoPzpcdCguKj8pXHMqKT8kLyxuPXQuZXhlYyhpW3NdKTtpZihuKXt2YXIgcj0iLS0tIj09PW5bMV0/Im9sZCI6Im5ldyI7ZVtyKyJGaWxlTmFtZSJdPW5bMl0sZVtyKyJIZWFkZXIiXT1uWzNdLHMrK319ZnVuY3Rpb24gbigpe2Zvcih2YXIgZT1zLHQ9aVtzKytdLG49dC5zcGxpdCgvQEAgLShcZCspKD86LChcZCspKT8gXCsoXGQrKSg/OiwoXGQrKSk/IEBALyksYT17b2xkU3RhcnQ6K25bMV0sb2xkTGluZXM6K25bMl18fDEsbmV3U3RhcnQ6K25bM10sbmV3TGluZXM6K25bNF18fDEsbGluZXM6W10sbGluZWRlbGltaXRlcnM6W119LHU9MCxjPTA7czxpLmxlbmd0aCYmISgwPT09aVtzXS5pbmRleE9mKCItLS0gIikmJnMrMjxpLmxlbmd0aCYmMD09PWlbcysxXS5pbmRleE9mKCIrKysgIikmJjA9PT1pW3MrMl0uaW5kZXhPZigiQEAiKSk7cysrKXt2YXIgbD1pW3NdWzBdO2lmKCIrIiE9PWwmJiItIiE9PWwmJiIgIiE9PWwmJiJcXCIhPT1sKWJyZWFrO2EubGluZXMucHVzaChpW3NdKSxhLmxpbmVkZWxpbWl0ZXJzLnB1c2gob1tzXXx8IlxuIiksIisiPT09bD91Kys6Ii0iPT09bD9jKys6IiAiPT09bCYmKHUrKyxjKyspfWlmKHV8fDEhPT1hLm5ld0xpbmVzfHwoYS5uZXdMaW5lcz0wKSxjfHwxIT09YS5vbGRMaW5lc3x8KGEub2xkTGluZXM9MCksci5zdHJpY3Qpe2lmKHUhPT1hLm5ld0xpbmVzKXRocm93IG5ldyBFcnJvcigiQWRkZWQgbGluZSBjb3VudCBkaWQgbm90IG1hdGNoIGZvciBodW5rIGF0IGxpbmUgIisoZSsxKSk7aWYoYyE9PWEub2xkTGluZXMpdGhyb3cgbmV3IEVycm9yKCJSZW1vdmVkIGxpbmUgY291bnQgZGlkIG5vdCBtYXRjaCBmb3IgaHVuayBhdCBsaW5lICIrKGUrMSkpfXJldHVybiBhfWZvcih2YXIgcj1hcmd1bWVudHMubGVuZ3RoPD0xfHx2b2lkIDA9PT1hcmd1bWVudHNbMV0/e306YXJndW1lbnRzWzFdLGk9ZS5zcGxpdCgvXHJcbnxbXG5cdlxmXHJceDg1XS8pLG89ZS5tYXRjaCgvXHJcbnxbXG5cdlxmXHJceDg1XS9nKXx8W10sYT1bXSxzPTA7czxpLmxlbmd0aDspIWZ1bmN0aW9uKCl7dmFyIGU9e307Zm9yKGEucHVzaChlKTtzPGkubGVuZ3RoOyl7dmFyIG89aVtzXTtpZigvXihcLVwtXC18XCtcK1wrfEBAKVxzLy50ZXN0KG8pKWJyZWFrO3ZhciB1PS9eKD86SW5kZXg6fGRpZmYoPzogLXIgXHcrKSspXHMrKC4rPylccyokLy5leGVjKG8pO3UmJihlLmluZGV4PXVbMV0pLHMrK31mb3IodChlKSx0KGUpLGUuaHVua3M9W107czxpLmxlbmd0aDspe3ZhciBjPWlbc107aWYoL14oSW5kZXg6fGRpZmZ8XC1cLVwtfFwrXCtcKylccy8udGVzdChjKSlicmVhaztpZigvXkBALy50ZXN0KGMpKWUuaHVua3MucHVzaChuKCkpO2Vsc2V7aWYoYyYmci5zdHJpY3QpdGhyb3cgbmV3IEVycm9yKCJVbmtub3duIGxpbmUgIisocysxKSsiICIrSlNPTi5zdHJpbmdpZnkoYykpO3MrK319fSgpO3JldHVybiBhfXQuX19lc01vZHVsZT0hMCx0LnBhcnNlUGF0Y2g9bn0pO3Vud3JhcEV4cG9ydHMocGFyc2UpO3ZhciBkaXN0YW5jZUl0ZXJhdG9yPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUsdCl7dC5fX2VzTW9kdWxlPSEwLHQuZGVmYXVsdD1mdW5jdGlvbihlLHQsbil7dmFyIHI9ITAsaT0hMSxvPSExLGE9MTtyZXR1cm4gZnVuY3Rpb24gcygpe2lmKHImJiFvKXtpZihpP2ErKzpyPSExLGUrYTw9bilyZXR1cm4gYTtvPSEwfWlmKCFpKXJldHVybiBvfHwocj0hMCksdDw9ZS1hPy1hKys6KGk9ITAscygpKX19fSk7dW53cmFwRXhwb3J0cyhkaXN0YW5jZUl0ZXJhdG9yKTt2YXIgYXBwbHk9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUsdCl7dmFyIG49YXJndW1lbnRzLmxlbmd0aDw9Mnx8dm9pZCAwPT09YXJndW1lbnRzWzJdP3t9OmFyZ3VtZW50c1syXTtpZigic3RyaW5nIj09PXR5cGVvZiB0JiYodD0oMCxwYXJzZS5wYXJzZVBhdGNoKSh0KSksQXJyYXkuaXNBcnJheSh0KSl7aWYodC5sZW5ndGg+MSl0aHJvdyBuZXcgRXJyb3IoImFwcGx5UGF0Y2ggb25seSB3b3JrcyB3aXRoIGEgc2luZ2xlIGlucHV0LiIpO3Q9dFswXX1mb3IodmFyIHI9ZS5zcGxpdCgvXHJcbnxbXG5cdlxmXHJceDg1XS8pLG89ZS5tYXRjaCgvXHJcbnxbXG5cdlxmXHJceDg1XS9nKXx8W10sYT10Lmh1bmtzLHM9bi5jb21wYXJlTGluZXx8ZnVuY3Rpb24oZSx0LG4scil7cmV0dXJuIHQ9PT1yfSx1PTAsYz1uLmZ1enpGYWN0b3J8fDAsbD0wLHA9MCxmPXZvaWQgMCxkPXZvaWQgMCxoPTA7aDxhLmxlbmd0aDtoKyspe2Zvcih2YXIgbT1hW2hdLGc9ci5sZW5ndGgtbS5vbGRMaW5lcyx5PTAsdj1wK20ub2xkU3RhcnQtMSxiPSgwLGkuZGVmYXVsdCkodixsLGcpO3ZvaWQgMCE9PXk7eT1iKCkpaWYoZnVuY3Rpb24oZSx0KXtmb3IodmFyIG49MDtuPGUubGluZXMubGVuZ3RoO24rKyl7dmFyIGk9ZS5saW5lc1tuXSxvPWlbMF0sYT1pLnN1YnN0cigxKTtpZigiICI9PT1vfHwiLSI9PT1vKXtpZighcyh0KzEsclt0XSxvLGEpJiYrK3U+YylyZXR1cm4hMTt0Kyt9fXJldHVybiEwfShtLHYreSkpe20ub2Zmc2V0PXArPXk7YnJlYWt9aWYodm9pZCAwPT09eSlyZXR1cm4hMTtsPW0ub2Zmc2V0K20ub2xkU3RhcnQrbS5vbGRMaW5lc31mb3IodmFyIHg9MDt4PGEubGVuZ3RoO3grKyl7dmFyIEM9YVt4XSxFPUMub2Zmc2V0K0MubmV3U3RhcnQtMTswPT1DLm5ld0xpbmVzJiZFKys7Zm9yKHZhciBEPTA7RDxDLmxpbmVzLmxlbmd0aDtEKyspe3ZhciB3PUMubGluZXNbRF0sUz13WzBdLGs9dy5zdWJzdHIoMSksQT1DLmxpbmVkZWxpbWl0ZXJzW0RdO2lmKCIgIj09PVMpRSsrO2Vsc2UgaWYoIi0iPT09UylyLnNwbGljZShFLDEpLG8uc3BsaWNlKEUsMSk7ZWxzZSBpZigiKyI9PT1TKXIuc3BsaWNlKEUsMCxrKSxvLnNwbGljZShFLDAsQSksRSsrO2Vsc2UgaWYoIlxcIj09PVMpe3ZhciBfPUMubGluZXNbRC0xXT9DLmxpbmVzW0QtMV1bMF06bnVsbDsiKyI9PT1fP2Y9ITA6Ii0iPT09XyYmKGQ9ITApfX19aWYoZilmb3IoOyFyW3IubGVuZ3RoLTFdOylyLnBvcCgpLG8ucG9wKCk7ZWxzZSBkJiYoci5wdXNoKCIiKSxvLnB1c2goIlxuIikpO2Zvcih2YXIgVD0wO1Q8ci5sZW5ndGgtMTtUKyspcltUXT1yW1RdK29bVF07cmV0dXJuIHIuam9pbigiIil9ZnVuY3Rpb24gcihlLHQpe2Z1bmN0aW9uIHIoKXt2YXIgbz1lW2krK107aWYoIW8pcmV0dXJuIHQuY29tcGxldGUoKTt0LmxvYWRGaWxlKG8sZnVuY3Rpb24oZSxpKXtpZihlKXJldHVybiB0LmNvbXBsZXRlKGUpO3ZhciBhPW4oaSxvLHQpO3QucGF0Y2hlZChvLGEsZnVuY3Rpb24oZSl7aWYoZSlyZXR1cm4gdC5jb21wbGV0ZShlKTtyKCl9KX0pfSJzdHJpbmciPT09dHlwZW9mIGUmJihlPSgwLHBhcnNlLnBhcnNlUGF0Y2gpKGUpKTt2YXIgaT0wO3IoKX10Ll9fZXNNb2R1bGU9ITAsdC5hcHBseVBhdGNoPW4sdC5hcHBseVBhdGNoZXM9cjt2YXIgaT1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19KGRpc3RhbmNlSXRlcmF0b3IpfSk7dW53cmFwRXhwb3J0cyhhcHBseSk7dmFyIGNyZWF0ZT1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7aWYoQXJyYXkuaXNBcnJheShlKSl7Zm9yKHZhciB0PTAsbj1BcnJheShlLmxlbmd0aCk7dDxlLmxlbmd0aDt0Kyspblt0XT1lW3RdO3JldHVybiBufXJldHVybiBBcnJheS5mcm9tKGUpfWZ1bmN0aW9uIHIoZSx0LHIsaSxvLGEscyl7ZnVuY3Rpb24gdShlKXtyZXR1cm4gZS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIiAiK2V9KX1zfHwocz17fSksInVuZGVmaW5lZCI9PT10eXBlb2Ygcy5jb250ZXh0JiYocy5jb250ZXh0PTQpO3ZhciBjPSgwLGxpbmUuZGlmZkxpbmVzKShyLGkscyk7Yy5wdXNoKHt2YWx1ZToiIixsaW5lczpbXX0pO2Zvcih2YXIgbD1bXSxwPTAsZj0wLGQ9W10saD0xLG09MSxnPTA7ZzxjLmxlbmd0aDtnKyspIWZ1bmN0aW9uKGUpe3ZhciB0PWNbZV0sbz10LmxpbmVzfHx0LnZhbHVlLnJlcGxhY2UoL1xuJC8sIiIpLnNwbGl0KCJcbiIpO2lmKHQubGluZXM9byx0LmFkZGVkfHx0LnJlbW92ZWQpe3ZhciBhO2lmKCFwKXt2YXIgZz1jW2UtMV07cD1oLGY9bSxnJiYoZD1zLmNvbnRleHQ+MD91KGcubGluZXMuc2xpY2UoLXMuY29udGV4dCkpOltdLHAtPWQubGVuZ3RoLGYtPWQubGVuZ3RoKX0oYT1kKS5wdXNoLmFwcGx5KGEsbihvLm1hcChmdW5jdGlvbihlKXtyZXR1cm4odC5hZGRlZD8iKyI6Ii0iKStlfSkpKSx0LmFkZGVkP20rPW8ubGVuZ3RoOmgrPW8ubGVuZ3RofWVsc2V7aWYocClpZihvLmxlbmd0aDw9MipzLmNvbnRleHQmJmU8Yy5sZW5ndGgtMil7dmFyIHk7KHk9ZCkucHVzaC5hcHBseSh5LG4odShvKSkpfWVsc2V7dmFyIHYsYj1NYXRoLm1pbihvLmxlbmd0aCxzLmNvbnRleHQpOyh2PWQpLnB1c2guYXBwbHkodixuKHUoby5zbGljZSgwLGIpKSkpO3ZhciB4PXtvbGRTdGFydDpwLG9sZExpbmVzOmgtcCtiLG5ld1N0YXJ0OmYsbmV3TGluZXM6bS1mK2IsbGluZXM6ZH07aWYoZT49Yy5sZW5ndGgtMiYmby5sZW5ndGg8PXMuY29udGV4dCl7dmFyIEM9L1xuJC8udGVzdChyKSxFPS9cbiQvLnRlc3QoaSk7MCE9by5sZW5ndGh8fEM/QyYmRXx8ZC5wdXNoKCJcXCBObyBuZXdsaW5lIGF0IGVuZCBvZiBmaWxlIik6ZC5zcGxpY2UoeC5vbGRMaW5lcywwLCJcXCBObyBuZXdsaW5lIGF0IGVuZCBvZiBmaWxlIil9bC5wdXNoKHgpLHA9MCxmPTAsZD1bXX1oKz1vLmxlbmd0aCxtKz1vLmxlbmd0aH19KGcpO3JldHVybntvbGRGaWxlTmFtZTplLG5ld0ZpbGVOYW1lOnQsb2xkSGVhZGVyOm8sbmV3SGVhZGVyOmEsaHVua3M6bH19ZnVuY3Rpb24gaShlLHQsbixpLG8sYSxzKXt2YXIgdT1yKGUsdCxuLGksbyxhLHMpLGM9W107ZT09dCYmYy5wdXNoKCJJbmRleDogIitlKSxjLnB1c2goIj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0iKSxjLnB1c2goIi0tLSAiK3Uub2xkRmlsZU5hbWUrKCJ1bmRlZmluZWQiPT09dHlwZW9mIHUub2xkSGVhZGVyPyIiOiJcdCIrdS5vbGRIZWFkZXIpKSxjLnB1c2goIisrKyAiK3UubmV3RmlsZU5hbWUrKCJ1bmRlZmluZWQiPT09dHlwZW9mIHUubmV3SGVhZGVyPyIiOiJcdCIrdS5uZXdIZWFkZXIpKTtmb3IodmFyIGw9MDtsPHUuaHVua3MubGVuZ3RoO2wrKyl7dmFyIHA9dS5odW5rc1tsXTtjLnB1c2goIkBAIC0iK3Aub2xkU3RhcnQrIiwiK3Aub2xkTGluZXMrIiArIitwLm5ld1N0YXJ0KyIsIitwLm5ld0xpbmVzKyIgQEAiKSxjLnB1c2guYXBwbHkoYyxwLmxpbmVzKX1yZXR1cm4gYy5qb2luKCJcbiIpKyJcbiJ9ZnVuY3Rpb24gbyhlLHQsbixyLG8sYSl7cmV0dXJuIGkoZSxlLHQsbixyLG8sYSl9dC5fX2VzTW9kdWxlPSEwLHQuc3RydWN0dXJlZFBhdGNoPXIsdC5jcmVhdGVUd29GaWxlc1BhdGNoPWksdC5jcmVhdGVQYXRjaD1vfSk7dW53cmFwRXhwb3J0cyhjcmVhdGUpO3ZhciBkbXA9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe2Zvcih2YXIgdD1bXSxuPXZvaWQgMCxyPXZvaWQgMCxpPTA7aTxlLmxlbmd0aDtpKyspbj1lW2ldLHI9bi5hZGRlZD8xOm4ucmVtb3ZlZD8tMTowLHQucHVzaChbcixuLnZhbHVlXSk7cmV0dXJuIHR9dC5fX2VzTW9kdWxlPSEwLHQuY29udmVydENoYW5nZXNUb0RNUD1ufSk7dW53cmFwRXhwb3J0cyhkbXApO3ZhciB4bWw9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe2Zvcih2YXIgdD1bXSxuPTA7bjxlLmxlbmd0aDtuKyspe3ZhciBpPWVbbl07aS5hZGRlZD90LnB1c2goIjxpbnM+Iik6aS5yZW1vdmVkJiZ0LnB1c2goIjxkZWw+IiksdC5wdXNoKHIoaS52YWx1ZSkpLGkuYWRkZWQ/dC5wdXNoKCI8L2lucz4iKTppLnJlbW92ZWQmJnQucHVzaCgiPC9kZWw+Iil9cmV0dXJuIHQuam9pbigiIil9ZnVuY3Rpb24gcihlKXt2YXIgdD1lO3JldHVybiB0PXQucmVwbGFjZSgvJi9nLCImYW1wOyIpLHQ9dC5yZXBsYWNlKC88L2csIiZsdDsiKSx0PXQucmVwbGFjZSgvPi9nLCImZ3Q7IiksdD10LnJlcGxhY2UoLyIvZywiJnF1b3Q7Iil9dC5fX2VzTW9kdWxlPSEwLHQuY29udmVydENoYW5nZXNUb1hNTD1ufSk7dW53cmFwRXhwb3J0cyh4bWwpO3ZhciBsaWI9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXt0Ll9fZXNNb2R1bGU9ITAsdC5jYW5vbmljYWxpemU9dC5jb252ZXJ0Q2hhbmdlc1RvWE1MPXQuY29udmVydENoYW5nZXNUb0RNUD10LnBhcnNlUGF0Y2g9dC5hcHBseVBhdGNoZXM9dC5hcHBseVBhdGNoPXQuY3JlYXRlUGF0Y2g9dC5jcmVhdGVUd29GaWxlc1BhdGNoPXQuc3RydWN0dXJlZFBhdGNoPXQuZGlmZkFycmF5cz10LmRpZmZKc29uPXQuZGlmZkNzcz10LmRpZmZTZW50ZW5jZXM9dC5kaWZmVHJpbW1lZExpbmVzPXQuZGlmZkxpbmVzPXQuZGlmZldvcmRzV2l0aFNwYWNlPXQuZGlmZldvcmRzPXQuZGlmZkNoYXJzPXQuRGlmZj12b2lkIDA7dmFyIG49ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShiYXNlKTt0LkRpZmY9bi5kZWZhdWx0LHQuZGlmZkNoYXJzPWNoYXJhY3Rlci5kaWZmQ2hhcnMsdC5kaWZmV29yZHM9d29yZC5kaWZmV29yZHMsdC5kaWZmV29yZHNXaXRoU3BhY2U9d29yZC5kaWZmV29yZHNXaXRoU3BhY2UsdC5kaWZmTGluZXM9bGluZS5kaWZmTGluZXMsdC5kaWZmVHJpbW1lZExpbmVzPWxpbmUuZGlmZlRyaW1tZWRMaW5lcyx0LmRpZmZTZW50ZW5jZXM9c2VudGVuY2UuZGlmZlNlbnRlbmNlcyx0LmRpZmZDc3M9Y3NzLmRpZmZDc3MsdC5kaWZmSnNvbj1qc29uLmRpZmZKc29uLHQuZGlmZkFycmF5cz1hcnJheS5kaWZmQXJyYXlzLHQuc3RydWN0dXJlZFBhdGNoPWNyZWF0ZS5zdHJ1Y3R1cmVkUGF0Y2gsdC5jcmVhdGVUd29GaWxlc1BhdGNoPWNyZWF0ZS5jcmVhdGVUd29GaWxlc1BhdGNoLHQuY3JlYXRlUGF0Y2g9Y3JlYXRlLmNyZWF0ZVBhdGNoLHQuYXBwbHlQYXRjaD1hcHBseS5hcHBseVBhdGNoLHQuYXBwbHlQYXRjaGVzPWFwcGx5LmFwcGx5UGF0Y2hlcyx0LnBhcnNlUGF0Y2g9cGFyc2UucGFyc2VQYXRjaCx0LmNvbnZlcnRDaGFuZ2VzVG9ETVA9ZG1wLmNvbnZlcnRDaGFuZ2VzVG9ETVAsdC5jb252ZXJ0Q2hhbmdlc1RvWE1MPXhtbC5jb252ZXJ0Q2hhbmdlc1RvWE1MLHQuY2Fub25pY2FsaXplPWpzb24uY2Fub25pY2FsaXplfSk7dW53cmFwRXhwb3J0cyhsaWIpO3ZhciBDb25maWdFcnJvcj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7cmV0dXJuIF9jbGFzc0NhbGxDaGVjayh0aGlzLHQpLF9wb3NzaWJsZUNvbnN0cnVjdG9yUmV0dXJuKHRoaXMsX2dldFByb3RvdHlwZU9mKHQpLmFwcGx5KHRoaXMsYXJndW1lbnRzKSl9cmV0dXJuIF9pbmhlcml0cyh0LGUpLHR9KF93cmFwTmF0aXZlU3VwZXIoRXJyb3IpKSxEZWJ1Z0Vycm9yPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gX2NsYXNzQ2FsbENoZWNrKHRoaXMsdCksX3Bvc3NpYmxlQ29uc3RydWN0b3JSZXR1cm4odGhpcyxfZ2V0UHJvdG90eXBlT2YodCkuYXBwbHkodGhpcyxhcmd1bWVudHMpKX1yZXR1cm4gX2luaGVyaXRzKHQsZSksdH0oX3dyYXBOYXRpdmVTdXBlcihFcnJvcikpLFVuZGVmaW5lZFBhcnNlckVycm9yJDE9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3JldHVybiBfY2xhc3NDYWxsQ2hlY2sodGhpcyx0KSxfcG9zc2libGVDb25zdHJ1Y3RvclJldHVybih0aGlzLF9nZXRQcm90b3R5cGVPZih0KS5hcHBseSh0aGlzLGFyZ3VtZW50cykpfXJldHVybiBfaW5oZXJpdHModCxlKSx0fShfd3JhcE5hdGl2ZVN1cGVyKEVycm9yKSksZXJyb3JzPXtDb25maWdFcnJvcjpDb25maWdFcnJvcixEZWJ1Z0Vycm9yOkRlYnVnRXJyb3IsVW5kZWZpbmVkUGFyc2VyRXJyb3I6VW5kZWZpbmVkUGFyc2VyRXJyb3IkMX0sZ2xvYmFsJDE9InVuZGVmaW5lZCIhPT10eXBlb2YgZ2xvYmFsP2dsb2JhbDoidW5kZWZpbmVkIiE9PXR5cGVvZiBzZWxmP3NlbGY6InVuZGVmaW5lZCIhPT10eXBlb2Ygd2luZG93P3dpbmRvdzp7fSxjYWNoZWRTZXRUaW1lb3V0PWRlZmF1bHRTZXRUaW1vdXQsY2FjaGVkQ2xlYXJUaW1lb3V0PWRlZmF1bHRDbGVhclRpbWVvdXQ7ImZ1bmN0aW9uIj09PXR5cGVvZiBnbG9iYWwkMS5zZXRUaW1lb3V0JiYoY2FjaGVkU2V0VGltZW91dD1zZXRUaW1lb3V0KSwiZnVuY3Rpb24iPT09dHlwZW9mIGdsb2JhbCQxLmNsZWFyVGltZW91dCYmKGNhY2hlZENsZWFyVGltZW91dD1jbGVhclRpbWVvdXQpO3ZhciBxdWV1ZT1bXSxkcmFpbmluZz0hMSxjdXJyZW50UXVldWUscXVldWVJbmRleD0tMTtJdGVtLnByb3RvdHlwZS5ydW49ZnVuY3Rpb24oKXt0aGlzLmZ1bi5hcHBseShudWxsLHRoaXMuYXJyYXkpfTt2YXIgdGl0bGU9ImJyb3dzZXIiLHBsYXRmb3JtPSJicm93c2VyIixicm93c2VyPSEwLGVudj17fSxhcmd2PVtdLHZlcnNpb24kMj0iIix2ZXJzaW9ucz17fSxyZWxlYXNlPXt9LGNvbmZpZz17fSxvbj1ub29wLGFkZExpc3RlbmVyPW5vb3Asb25jZT1ub29wLG9mZj1ub29wLHJlbW92ZUxpc3RlbmVyPW5vb3AscmVtb3ZlQWxsTGlzdGVuZXJzPW5vb3AsZW1pdD1ub29wLHBlcmZvcm1hbmNlPWdsb2JhbCQxLnBlcmZvcm1hbmNlfHx7fSxwZXJmb3JtYW5jZU5vdz1wZXJmb3JtYW5jZS5ub3d8fHBlcmZvcm1hbmNlLm1vek5vd3x8cGVyZm9ybWFuY2UubXNOb3d8fHBlcmZvcm1hbmNlLm9Ob3d8fHBlcmZvcm1hbmNlLndlYmtpdE5vd3x8ZnVuY3Rpb24oKXtyZXR1cm4obmV3IERhdGUpLmdldFRpbWUoKX0sc3RhcnRUaW1lPW5ldyBEYXRlLHByb2Nlc3M9e25leHRUaWNrOm5leHRUaWNrLHRpdGxlOnRpdGxlLGJyb3dzZXI6YnJvd3NlcixlbnY6ZW52LGFyZ3Y6YXJndix2ZXJzaW9uOnZlcnNpb24kMix2ZXJzaW9uczp2ZXJzaW9ucyxvbjpvbixhZGRMaXN0ZW5lcjphZGRMaXN0ZW5lcixvbmNlOm9uY2Usb2ZmOm9mZixyZW1vdmVMaXN0ZW5lcjpyZW1vdmVMaXN0ZW5lcixyZW1vdmVBbGxMaXN0ZW5lcnM6cmVtb3ZlQWxsTGlzdGVuZXJzLGVtaXQ6ZW1pdCxiaW5kaW5nOmJpbmRpbmcsY3dkOmN3ZCxjaGRpcjpjaGRpcix1bWFzazp1bWFzayxocnRpbWU6aHJ0aW1lLHBsYXRmb3JtOnBsYXRmb3JtLHJlbGVhc2U6cmVsZWFzZSxjb25maWc6Y29uZmlnLHVwdGltZTp1cHRpbWV9LHNlbXZlcj1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSx0KXtpZihlIGluc3RhbmNlb2YgbylyZXR1cm4gZTtpZigic3RyaW5nIiE9PXR5cGVvZiBlKXJldHVybiBudWxsO2lmKGUubGVuZ3RoPkspcmV0dXJuIG51bGw7aWYoISh0P1lbaGVdOllbcGVdKS50ZXN0KGUpKXJldHVybiBudWxsO3RyeXtyZXR1cm4gbmV3IG8oZSx0KX1jYXRjaChlKXtyZXR1cm4gbnVsbH19ZnVuY3Rpb24gcihlLHQpe3ZhciByPW4oZSx0KTtyZXR1cm4gcj9yLnZlcnNpb246bnVsbH1mdW5jdGlvbiBpKGUsdCl7dmFyIHI9bihlLnRyaW0oKS5yZXBsYWNlKC9eWz12XSsvLCIiKSx0KTtyZXR1cm4gcj9yLnZlcnNpb246bnVsbH1mdW5jdGlvbiBvKGUsdCl7aWYoZSBpbnN0YW5jZW9mIG8pe2lmKGUubG9vc2U9PT10KXJldHVybiBlO2U9ZS52ZXJzaW9ufWVsc2UgaWYoInN0cmluZyIhPT10eXBlb2YgZSl0aHJvdyBuZXcgVHlwZUVycm9yKCJJbnZhbGlkIFZlcnNpb246ICIrZSk7aWYoZS5sZW5ndGg+Syl0aHJvdyBuZXcgVHlwZUVycm9yKCJ2ZXJzaW9uIGlzIGxvbmdlciB0aGFuICIrSysiIGNoYXJhY3RlcnMiKTtpZighKHRoaXMgaW5zdGFuY2VvZiBvKSlyZXR1cm4gbmV3IG8oZSx0KTtRKCJTZW1WZXIiLGUsdCksdGhpcy5sb29zZT10O3ZhciBuPWUudHJpbSgpLm1hdGNoKHQ/WVtoZV06WVtwZV0pO2lmKCFuKXRocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgVmVyc2lvbjogIitlKTtpZih0aGlzLnJhdz1lLHRoaXMubWFqb3I9K25bMV0sdGhpcy5taW5vcj0rblsyXSx0aGlzLnBhdGNoPStuWzNdLHRoaXMubWFqb3I+Snx8dGhpcy5tYWpvcjwwKXRocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgbWFqb3IgdmVyc2lvbiIpO2lmKHRoaXMubWlub3I+Snx8dGhpcy5taW5vcjwwKXRocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgbWlub3IgdmVyc2lvbiIpO2lmKHRoaXMucGF0Y2g+Snx8dGhpcy5wYXRjaDwwKXRocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgcGF0Y2ggdmVyc2lvbiIpO25bNF0/dGhpcy5wcmVyZWxlYXNlPW5bNF0uc3BsaXQoIi4iKS5tYXAoZnVuY3Rpb24oZSl7aWYoL15bMC05XSskLy50ZXN0KGUpKXt2YXIgdD0rZTtpZih0Pj0wJiZ0PEopcmV0dXJuIHR9cmV0dXJuIGV9KTp0aGlzLnByZXJlbGVhc2U9W10sdGhpcy5idWlsZD1uWzVdP25bNV0uc3BsaXQoIi4iKTpbXSx0aGlzLmZvcm1hdCgpfWZ1bmN0aW9uIGEoZSx0LG4scil7InN0cmluZyI9PT10eXBlb2YgbiYmKHI9bixuPXZvaWQgMCk7dHJ5e3JldHVybiBuZXcgbyhlLG4pLmluYyh0LHIpLnZlcnNpb259Y2F0Y2goZSl7cmV0dXJuIG51bGx9fWZ1bmN0aW9uIHMoZSx0KXtpZih4KGUsdCkpcmV0dXJuIG51bGw7dmFyIHI9bihlKSxpPW4odCk7aWYoci5wcmVyZWxlYXNlLmxlbmd0aHx8aS5wcmVyZWxlYXNlLmxlbmd0aCl7Zm9yKHZhciBvIGluIHIpaWYoKCJtYWpvciI9PT1vfHwibWlub3IiPT09b3x8InBhdGNoIj09PW8pJiZyW29dIT09aVtvXSlyZXR1cm4icHJlIitvO3JldHVybiJwcmVyZWxlYXNlIn1mb3IodmFyIG8gaW4gcilpZigoIm1ham9yIj09PW98fCJtaW5vciI9PT1vfHwicGF0Y2giPT09bykmJnJbb10hPT1pW29dKXJldHVybiBvfWZ1bmN0aW9uIHUoZSx0KXt2YXIgbj1qZS50ZXN0KGUpLHI9amUudGVzdCh0KTtyZXR1cm4gbiYmciYmKGU9K2UsdD0rdCksbiYmIXI/LTE6ciYmIW4/MTplPHQ/LTE6ZT50PzE6MH1mdW5jdGlvbiBjKGUsdCl7cmV0dXJuIHUodCxlKX1mdW5jdGlvbiBsKGUsdCl7cmV0dXJuIG5ldyBvKGUsdCkubWFqb3J9ZnVuY3Rpb24gcChlLHQpe3JldHVybiBuZXcgbyhlLHQpLm1pbm9yfWZ1bmN0aW9uIGYoZSx0KXtyZXR1cm4gbmV3IG8oZSx0KS5wYXRjaH1mdW5jdGlvbiBkKGUsdCxuKXtyZXR1cm4gbmV3IG8oZSxuKS5jb21wYXJlKG5ldyBvKHQsbikpfWZ1bmN0aW9uIGgoZSx0KXtyZXR1cm4gZChlLHQsITApfWZ1bmN0aW9uIG0oZSx0LG4pe3JldHVybiBkKHQsZSxuKX1mdW5jdGlvbiBnKGUsbil7cmV0dXJuIGUuc29ydChmdW5jdGlvbihlLHIpe3JldHVybiB0LmNvbXBhcmUoZSxyLG4pfSl9ZnVuY3Rpb24geShlLG4pe3JldHVybiBlLnNvcnQoZnVuY3Rpb24oZSxyKXtyZXR1cm4gdC5yY29tcGFyZShlLHIsbil9KX1mdW5jdGlvbiB2KGUsdCxuKXtyZXR1cm4gZChlLHQsbik+MH1mdW5jdGlvbiBiKGUsdCxuKXtyZXR1cm4gZChlLHQsbik8MH1mdW5jdGlvbiB4KGUsdCxuKXtyZXR1cm4gMD09PWQoZSx0LG4pfWZ1bmN0aW9uIEMoZSx0LG4pe3JldHVybiAwIT09ZChlLHQsbil9ZnVuY3Rpb24gRShlLHQsbil7cmV0dXJuIGQoZSx0LG4pPj0wfWZ1bmN0aW9uIEQoZSx0LG4pe3JldHVybiBkKGUsdCxuKTw9MH1mdW5jdGlvbiB3KGUsdCxuLHIpe3ZhciBpO3N3aXRjaCh0KXtjYXNlIj09PSI6Im9iamVjdCI9PT1fdHlwZW9mKGUpJiYoZT1lLnZlcnNpb24pLCJvYmplY3QiPT09X3R5cGVvZihuKSYmKG49bi52ZXJzaW9uKSxpPWU9PT1uO2JyZWFrO2Nhc2UiIT09Ijoib2JqZWN0Ij09PV90eXBlb2YoZSkmJihlPWUudmVyc2lvbiksIm9iamVjdCI9PT1fdHlwZW9mKG4pJiYobj1uLnZlcnNpb24pLGk9ZSE9PW47YnJlYWs7Y2FzZSIiOmNhc2UiPSI6Y2FzZSI9PSI6aT14KGUsbixyKTticmVhaztjYXNlIiE9IjppPUMoZSxuLHIpO2JyZWFrO2Nhc2UiPiI6aT12KGUsbixyKTticmVhaztjYXNlIj49IjppPUUoZSxuLHIpO2JyZWFrO2Nhc2UiPCI6aT1iKGUsbixyKTticmVhaztjYXNlIjw9IjppPUQoZSxuLHIpO2JyZWFrO2RlZmF1bHQ6dGhyb3cgbmV3IFR5cGVFcnJvcigiSW52YWxpZCBvcGVyYXRvcjogIit0KX1yZXR1cm4gaX1mdW5jdGlvbiBTKGUsdCl7aWYoZSBpbnN0YW5jZW9mIFMpe2lmKGUubG9vc2U9PT10KXJldHVybiBlO2U9ZS52YWx1ZX1pZighKHRoaXMgaW5zdGFuY2VvZiBTKSlyZXR1cm4gbmV3IFMoZSx0KTtRKCJjb21wYXJhdG9yIixlLHQpLHRoaXMubG9vc2U9dCx0aGlzLnBhcnNlKGUpLHRoaXMuc2VtdmVyPT09UmU/dGhpcy52YWx1ZT0iIjp0aGlzLnZhbHVlPXRoaXMub3BlcmF0b3IrdGhpcy5zZW12ZXIudmVyc2lvbixRKCJjb21wIix0aGlzKX1mdW5jdGlvbiBrKGUsdCl7aWYoZSBpbnN0YW5jZW9mIGspcmV0dXJuIGUubG9vc2U9PT10P2U6bmV3IGsoZS5yYXcsdCk7aWYoZSBpbnN0YW5jZW9mIFMpcmV0dXJuIG5ldyBrKGUudmFsdWUsdCk7aWYoISh0aGlzIGluc3RhbmNlb2YgaykpcmV0dXJuIG5ldyBrKGUsdCk7aWYodGhpcy5sb29zZT10LHRoaXMucmF3PWUsdGhpcy5zZXQ9ZS5zcGxpdCgvXHMqXHxcfFxzKi8pLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5wYXJzZVJhbmdlKGUudHJpbSgpKX0sdGhpcykuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBlLmxlbmd0aH0pLCF0aGlzLnNldC5sZW5ndGgpdGhyb3cgbmV3IFR5cGVFcnJvcigiSW52YWxpZCBTZW1WZXIgUmFuZ2U6ICIrZSk7dGhpcy5mb3JtYXQoKX1mdW5jdGlvbiBBKGUsdCl7cmV0dXJuIG5ldyBrKGUsdCkuc2V0Lm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUudmFsdWV9KS5qb2luKCIgIikudHJpbSgpLnNwbGl0KCIgIil9KX1mdW5jdGlvbiBfKGUsdCl7cmV0dXJuIFEoImNvbXAiLGUpLGU9TihlLHQpLFEoImNhcmV0IixlKSxlPU8oZSx0KSxRKCJ0aWxkZXMiLGUpLGU9TChlLHQpLFEoInhyYW5nZSIsZSksZT1NKGUsdCksUSgic3RhcnMiLGUpLGV9ZnVuY3Rpb24gVChlKXtyZXR1cm4hZXx8IngiPT09ZS50b0xvd2VyQ2FzZSgpfHwiKiI9PT1lfWZ1bmN0aW9uIE8oZSx0KXtyZXR1cm4gZS50cmltKCkuc3BsaXQoL1xzKy8pLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gRihlLHQpfSkuam9pbigiICIpfWZ1bmN0aW9uIEYoZSx0KXt2YXIgbj10P1lbU2VdOllbd2VdO3JldHVybiBlLnJlcGxhY2UobixmdW5jdGlvbih0LG4scixpLG8pe1EoInRpbGRlIixlLHQsbixyLGksbyk7dmFyIGE7cmV0dXJuIFQobik/YT0iIjpUKHIpP2E9Ij49IituKyIuMC4wIDwiKygrbisxKSsiLjAuMCI6VChpKT9hPSI+PSIrbisiLiIrcisiLjAgPCIrbisiLiIrKCtyKzEpKyIuMCI6bz8oUSgicmVwbGFjZVRpbGRlIHByIixvKSwiLSIhPT1vLmNoYXJBdCgwKSYmKG89Ii0iK28pLGE9Ij49IituKyIuIityKyIuIitpK28rIiA8IituKyIuIisoK3IrMSkrIi4wIik6YT0iPj0iK24rIi4iK3IrIi4iK2krIiA8IituKyIuIisoK3IrMSkrIi4wIixRKCJ0aWxkZSByZXR1cm4iLGEpLGF9KX1mdW5jdGlvbiBOKGUsdCl7cmV0dXJuIGUudHJpbSgpLnNwbGl0KC9ccysvKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIEkoZSx0KX0pLmpvaW4oIiAiKX1mdW5jdGlvbiBJKGUsdCl7USgiY2FyZXQiLGUsdCk7dmFyIG49dD9ZW1RlXTpZW19lXTtyZXR1cm4gZS5yZXBsYWNlKG4sZnVuY3Rpb24odCxuLHIsaSxvKXtRKCJjYXJldCIsZSx0LG4scixpLG8pO3ZhciBhO3JldHVybiBUKG4pP2E9IiI6VChyKT9hPSI+PSIrbisiLjAuMCA8IisoK24rMSkrIi4wLjAiOlQoaSk/YT0iMCI9PT1uPyI+PSIrbisiLiIrcisiLjAgPCIrbisiLiIrKCtyKzEpKyIuMCI6Ij49IituKyIuIityKyIuMCA8IisoK24rMSkrIi4wLjAiOm8/KFEoInJlcGxhY2VDYXJldCBwciIsbyksIi0iIT09by5jaGFyQXQoMCkmJihvPSItIitvKSxhPSIwIj09PW4/IjAiPT09cj8iPj0iK24rIi4iK3IrIi4iK2krbysiIDwiK24rIi4iK3IrIi4iKygraSsxKToiPj0iK24rIi4iK3IrIi4iK2krbysiIDwiK24rIi4iKygrcisxKSsiLjAiOiI+PSIrbisiLiIrcisiLiIraStvKyIgPCIrKCtuKzEpKyIuMC4wIik6KFEoIm5vIHByIiksYT0iMCI9PT1uPyIwIj09PXI/Ij49IituKyIuIityKyIuIitpKyIgPCIrbisiLiIrcisiLiIrKCtpKzEpOiI+PSIrbisiLiIrcisiLiIraSsiIDwiK24rIi4iKygrcisxKSsiLjAiOiI+PSIrbisiLiIrcisiLiIraSsiIDwiKygrbisxKSsiLjAuMCIpLFEoImNhcmV0IHJldHVybiIsYSksYX0pfWZ1bmN0aW9uIEwoZSx0KXtyZXR1cm4gUSgicmVwbGFjZVhSYW5nZXMiLGUsdCksZS5zcGxpdCgvXHMrLykubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBQKGUsdCl9KS5qb2luKCIgIil9ZnVuY3Rpb24gUChlLHQpe2U9ZS50cmltKCk7dmFyIG49dD9ZW0NlXTpZW3hlXTtyZXR1cm4gZS5yZXBsYWNlKG4sZnVuY3Rpb24odCxuLHIsaSxvLGEpe1EoInhSYW5nZSIsZSx0LG4scixpLG8sYSk7dmFyIHM9VChyKSx1PXN8fFQoaSksYz11fHxUKG8pLGw9YztyZXR1cm4iPSI9PT1uJiZsJiYobj0iIikscz90PSI+Ij09PW58fCI8Ij09PW4/IjwwLjAuMCI6IioiOm4mJmw/KHUmJihpPTApLGMmJihvPTApLCI+Ij09PW4/KG49Ij49Iix1PyhyPStyKzEsaT0wLG89MCk6YyYmKGk9K2krMSxvPTApKToiPD0iPT09biYmKG49IjwiLHU/cj0rcisxOmk9K2krMSksdD1uK3IrIi4iK2krIi4iK28pOnU/dD0iPj0iK3IrIi4wLjAgPCIrKCtyKzEpKyIuMC4wIjpjJiYodD0iPj0iK3IrIi4iK2krIi4wIDwiK3IrIi4iKygraSsxKSsiLjAiKSxRKCJ4UmFuZ2UgcmV0dXJuIix0KSx0fSl9ZnVuY3Rpb24gTShlLHQpe3JldHVybiBRKCJyZXBsYWNlU3RhcnMiLGUsdCksZS50cmltKCkucmVwbGFjZShZW1BlXSwiIil9ZnVuY3Rpb24gaihlLHQsbixyLGksbyxhLHMsdSxjLGwscCxmKXtyZXR1cm4gdD1UKG4pPyIiOlQocik/Ij49IituKyIuMC4wIjpUKGkpPyI+PSIrbisiLiIrcisiLjAiOiI+PSIrdCxzPVQodSk/IiI6VChjKT8iPCIrKCt1KzEpKyIuMC4wIjpUKGwpPyI8Iit1KyIuIisoK2MrMSkrIi4wIjpwPyI8PSIrdSsiLiIrYysiLiIrbCsiLSIrcDoiPD0iK3MsKHQrIiAiK3MpLnRyaW0oKX1mdW5jdGlvbiBSKGUsdCl7Zm9yKHZhciBuPTA7bjxlLmxlbmd0aDtuKyspaWYoIWVbbl0udGVzdCh0KSlyZXR1cm4hMTtpZih0LnByZXJlbGVhc2UubGVuZ3RoKXtmb3IodmFyIG49MDtuPGUubGVuZ3RoO24rKylpZihRKGVbbl0uc2VtdmVyKSxlW25dLnNlbXZlciE9PVJlJiZlW25dLnNlbXZlci5wcmVyZWxlYXNlLmxlbmd0aD4wKXt2YXIgcj1lW25dLnNlbXZlcjtpZihyLm1ham9yPT09dC5tYWpvciYmci5taW5vcj09PXQubWlub3ImJnIucGF0Y2g9PT10LnBhdGNoKXJldHVybiEwfXJldHVybiExfXJldHVybiEwfWZ1bmN0aW9uIEIoZSx0LG4pe3RyeXt0PW5ldyBrKHQsbil9Y2F0Y2goZSl7cmV0dXJuITF9cmV0dXJuIHQudGVzdChlKX1mdW5jdGlvbiAkKGUsdCxuKXt2YXIgcj1udWxsLGk9bnVsbDt0cnl7dmFyIGE9bmV3IGsodCxuKX1jYXRjaChlKXtyZXR1cm4gbnVsbH1yZXR1cm4gZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2EudGVzdChlKSYmKHImJi0xIT09aS5jb21wYXJlKGUpfHwocj1lLGk9bmV3IG8ocixuKSkpfSkscn1mdW5jdGlvbiBVKGUsdCxuKXt2YXIgcj1udWxsLGk9bnVsbDt0cnl7dmFyIGE9bmV3IGsodCxuKX1jYXRjaChlKXtyZXR1cm4gbnVsbH1yZXR1cm4gZS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2EudGVzdChlKSYmKHImJjEhPT1pLmNvbXBhcmUoZSl8fChyPWUsaT1uZXcgbyhyLG4pKSl9KSxyfWZ1bmN0aW9uIHooZSx0KXt0cnl7cmV0dXJuIG5ldyBrKGUsdCkucmFuZ2V8fCIqIn1jYXRjaChlKXtyZXR1cm4gbnVsbH19ZnVuY3Rpb24gRyhlLHQsbil7cmV0dXJuIHEoZSx0LCI8IixuKX1mdW5jdGlvbiBWKGUsdCxuKXtyZXR1cm4gcShlLHQsIj4iLG4pfWZ1bmN0aW9uIHEoZSx0LG4scil7ZT1uZXcgbyhlLHIpLHQ9bmV3IGsodCxyKTt2YXIgaSxhLHMsdSxjO3N3aXRjaChuKXtjYXNlIj4iOmk9dixhPUQscz1iLHU9Ij4iLGM9Ij49IjticmVhaztjYXNlIjwiOmk9YixhPUUscz12LHU9IjwiLGM9Ijw9IjticmVhaztkZWZhdWx0OnRocm93IG5ldyBUeXBlRXJyb3IoJ011c3QgcHJvdmlkZSBhIGhpbG8gdmFsIG9mICI8IiBvciAiPiInKX1pZihCKGUsdCxyKSlyZXR1cm4hMTtmb3IodmFyIGw9MDtsPHQuc2V0Lmxlbmd0aDsrK2wpe3ZhciBwPXQuc2V0W2xdLGY9bnVsbCxkPW51bGw7aWYocC5mb3JFYWNoKGZ1bmN0aW9uKGUpe2Uuc2VtdmVyPT09UmUmJihlPW5ldyBTKCI+PTAuMC4wIikpLGY9Znx8ZSxkPWR8fGUsaShlLnNlbXZlcixmLnNlbXZlcixyKT9mPWU6cyhlLnNlbXZlcixkLnNlbXZlcixyKSYmKGQ9ZSl9KSxmLm9wZXJhdG9yPT09dXx8Zi5vcGVyYXRvcj09PWMpcmV0dXJuITE7aWYoKCFkLm9wZXJhdG9yfHxkLm9wZXJhdG9yPT09dSkmJmEoZSxkLnNlbXZlcikpcmV0dXJuITE7aWYoZC5vcGVyYXRvcj09PWMmJnMoZSxkLnNlbXZlcikpcmV0dXJuITF9cmV0dXJuITB9ZnVuY3Rpb24gSChlLHQpe3ZhciByPW4oZSx0KTtyZXR1cm4gciYmci5wcmVyZWxlYXNlLmxlbmd0aD9yLnByZXJlbGVhc2U6bnVsbH1mdW5jdGlvbiBXKGUsdCxuKXtyZXR1cm4gZT1uZXcgayhlLG4pLHQ9bmV3IGsodCxuKSxlLmludGVyc2VjdHModCl9dD1lLmV4cG9ydHM9bzt2YXIgUTtRPSJvYmplY3QiPT09X3R5cGVvZihwcm9jZXNzKSYmcHJvY2Vzcy5lbnYmJnByb2Nlc3MuZW52Lk5PREVfREVCVUcmJi9cYnNlbXZlclxiL2kudGVzdChwcm9jZXNzLmVudi5OT0RFX0RFQlVHKT9mdW5jdGlvbigpe3ZhciBlPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywwKTtlLnVuc2hpZnQoIlNFTVZFUiIpLGNvbnNvbGUubG9nLmFwcGx5KGNvbnNvbGUsZSl9OmZ1bmN0aW9uKCl7fSx0LlNFTVZFUl9TUEVDX1ZFUlNJT049IjIuMC4wIjt2YXIgSz0yNTYsSj1OdW1iZXIuTUFYX1NBRkVfSU5URUdFUnx8OTAwNzE5OTI1NDc0MDk5MSxZPXQucmU9W10sWD10LnNyYz1bXSxaPTAsZWU9WisrO1hbZWVdPSIwfFsxLTldXFxkKiI7dmFyIHRlPVorKztYW3RlXT0iWzAtOV0rIjt2YXIgbmU9WisrO1hbbmVdPSJcXGQqW2EtekEtWi1dW2EtekEtWjAtOS1dKiI7dmFyIHJlPVorKztYW3JlXT0iKCIrWFtlZV0rIilcXC4oIitYW2VlXSsiKVxcLigiK1hbZWVdKyIpIjt2YXIgaWU9WisrO1hbaWVdPSIoIitYW3RlXSsiKVxcLigiK1hbdGVdKyIpXFwuKCIrWFt0ZV0rIikiO3ZhciBvZT1aKys7WFtvZV09Iig/OiIrWFtlZV0rInwiK1hbbmVdKyIpIjt2YXIgYWU9WisrO1hbYWVdPSIoPzoiK1hbdGVdKyJ8IitYW25lXSsiKSI7dmFyIHNlPVorKztYW3NlXT0iKD86LSgiK1hbb2VdKyIoPzpcXC4iK1hbb2VdKyIpKikpIjt2YXIgdWU9WisrO1hbdWVdPSIoPzotPygiK1hbYWVdKyIoPzpcXC4iK1hbYWVdKyIpKikpIjt2YXIgY2U9WisrO1hbY2VdPSJbMC05QS1aYS16LV0rIjt2YXIgbGU9WisrO1hbbGVdPSIoPzpcXCsoIitYW2NlXSsiKD86XFwuIitYW2NlXSsiKSopKSI7dmFyIHBlPVorKyxmZT0idj8iK1hbcmVdK1hbc2VdKyI/IitYW2xlXSsiPyI7WFtwZV09Il4iK2ZlKyIkIjt2YXIgZGU9Ilt2PVxcc10qIitYW2llXStYW3VlXSsiPyIrWFtsZV0rIj8iLGhlPVorKztYW2hlXT0iXiIrZGUrIiQiO3ZhciBtZT1aKys7WFttZV09IigoPzo8fD4pPz0/KSI7dmFyIGdlPVorKztYW2dlXT1YW3RlXSsifHh8WHxcXCoiO3ZhciB5ZT1aKys7WFt5ZV09WFtlZV0rInx4fFh8XFwqIjt2YXIgdmU9WisrO1hbdmVdPSJbdj1cXHNdKigiK1hbeWVdKyIpKD86XFwuKCIrWFt5ZV0rIikoPzpcXC4oIitYW3llXSsiKSg/OiIrWFtzZV0rIik/IitYW2xlXSsiPyk/KT8iO3ZhciBiZT1aKys7WFtiZV09Ilt2PVxcc10qKCIrWFtnZV0rIikoPzpcXC4oIitYW2dlXSsiKSg/OlxcLigiK1hbZ2VdKyIpKD86IitYW3VlXSsiKT8iK1hbbGVdKyI/KT8pPyI7dmFyIHhlPVorKztYW3hlXT0iXiIrWFttZV0rIlxccyoiK1hbdmVdKyIkIjt2YXIgQ2U9WisrO1hbQ2VdPSJeIitYW21lXSsiXFxzKiIrWFtiZV0rIiQiO3ZhciBFZT1aKys7WFtFZV09Iig/On4+PykiO3ZhciBEZT1aKys7WFtEZV09IihcXHMqKSIrWFtFZV0rIlxccysiLFlbRGVdPW5ldyBSZWdFeHAoWFtEZV0sImciKTt2YXIgd2U9WisrO1hbd2VdPSJeIitYW0VlXStYW3ZlXSsiJCI7dmFyIFNlPVorKztYW1NlXT0iXiIrWFtFZV0rWFtiZV0rIiQiO3ZhciBrZT1aKys7WFtrZV09Iig/OlxcXikiO3ZhciBBZT1aKys7WFtBZV09IihcXHMqKSIrWFtrZV0rIlxccysiLFlbQWVdPW5ldyBSZWdFeHAoWFtBZV0sImciKTt2YXIgX2U9WisrO1hbX2VdPSJeIitYW2tlXStYW3ZlXSsiJCI7dmFyIFRlPVorKztYW1RlXT0iXiIrWFtrZV0rWFtiZV0rIiQiO3ZhciBPZT1aKys7WFtPZV09Il4iK1hbbWVdKyJcXHMqKCIrZGUrIikkfF4kIjt2YXIgRmU9WisrO1hbRmVdPSJeIitYW21lXSsiXFxzKigiK2ZlKyIpJHxeJCI7dmFyIE5lPVorKztYW05lXT0iKFxccyopIitYW21lXSsiXFxzKigiK2RlKyJ8IitYW3ZlXSsiKSIsWVtOZV09bmV3IFJlZ0V4cChYW05lXSwiZyIpO3ZhciBJZT1aKys7WFtJZV09Il5cXHMqKCIrWFt2ZV0rIilcXHMrLVxccysoIitYW3ZlXSsiKVxccyokIjt2YXIgTGU9WisrO1hbTGVdPSJeXFxzKigiK1hbYmVdKyIpXFxzKy1cXHMrKCIrWFtiZV0rIilcXHMqJCI7dmFyIFBlPVorKztYW1BlXT0iKDx8Pik/PT9cXHMqXFwqIjtmb3IodmFyIE1lPTA7TWU8WjtNZSsrKVEoTWUsWFtNZV0pLFlbTWVdfHwoWVtNZV09bmV3IFJlZ0V4cChYW01lXSkpO3QucGFyc2U9bix0LnZhbGlkPXIsdC5jbGVhbj1pLHQuU2VtVmVyPW8sby5wcm90b3R5cGUuZm9ybWF0PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudmVyc2lvbj10aGlzLm1ham9yKyIuIit0aGlzLm1pbm9yKyIuIit0aGlzLnBhdGNoLHRoaXMucHJlcmVsZWFzZS5sZW5ndGgmJih0aGlzLnZlcnNpb24rPSItIit0aGlzLnByZXJlbGVhc2Uuam9pbigiLiIpKSx0aGlzLnZlcnNpb259LG8ucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudmVyc2lvbn0sby5wcm90b3R5cGUuY29tcGFyZT1mdW5jdGlvbihlKXtyZXR1cm4gUSgiU2VtVmVyLmNvbXBhcmUiLHRoaXMudmVyc2lvbix0aGlzLmxvb3NlLGUpLGUgaW5zdGFuY2VvZiBvfHwoZT1uZXcgbyhlLHRoaXMubG9vc2UpKSx0aGlzLmNvbXBhcmVNYWluKGUpfHx0aGlzLmNvbXBhcmVQcmUoZSl9LG8ucHJvdG90eXBlLmNvbXBhcmVNYWluPWZ1bmN0aW9uKGUpe3JldHVybiBlIGluc3RhbmNlb2Ygb3x8KGU9bmV3IG8oZSx0aGlzLmxvb3NlKSksdSh0aGlzLm1ham9yLGUubWFqb3IpfHx1KHRoaXMubWlub3IsZS5taW5vcil8fHUodGhpcy5wYXRjaCxlLnBhdGNoKX0sby5wcm90b3R5cGUuY29tcGFyZVByZT1mdW5jdGlvbihlKXtpZihlIGluc3RhbmNlb2Ygb3x8KGU9bmV3IG8oZSx0aGlzLmxvb3NlKSksdGhpcy5wcmVyZWxlYXNlLmxlbmd0aCYmIWUucHJlcmVsZWFzZS5sZW5ndGgpcmV0dXJuLTE7aWYoIXRoaXMucHJlcmVsZWFzZS5sZW5ndGgmJmUucHJlcmVsZWFzZS5sZW5ndGgpcmV0dXJuIDE7aWYoIXRoaXMucHJlcmVsZWFzZS5sZW5ndGgmJiFlLnByZXJlbGVhc2UubGVuZ3RoKXJldHVybiAwO3ZhciB0PTA7ZG97dmFyIG49dGhpcy5wcmVyZWxlYXNlW3RdLHI9ZS5wcmVyZWxlYXNlW3RdO2lmKFEoInByZXJlbGVhc2UgY29tcGFyZSIsdCxuLHIpLHZvaWQgMD09PW4mJnZvaWQgMD09PXIpcmV0dXJuIDA7aWYodm9pZCAwPT09cilyZXR1cm4gMTtpZih2b2lkIDA9PT1uKXJldHVybi0xO2lmKG4hPT1yKXJldHVybiB1KG4scil9d2hpbGUoKyt0KX0sby5wcm90b3R5cGUuaW5jPWZ1bmN0aW9uKGUsdCl7c3dpdGNoKGUpe2Nhc2UicHJlbWFqb3IiOnRoaXMucHJlcmVsZWFzZS5sZW5ndGg9MCx0aGlzLnBhdGNoPTAsdGhpcy5taW5vcj0wLHRoaXMubWFqb3IrKyx0aGlzLmluYygicHJlIix0KTticmVhaztjYXNlInByZW1pbm9yIjp0aGlzLnByZXJlbGVhc2UubGVuZ3RoPTAsdGhpcy5wYXRjaD0wLHRoaXMubWlub3IrKyx0aGlzLmluYygicHJlIix0KTticmVhaztjYXNlInByZXBhdGNoIjp0aGlzLnByZXJlbGVhc2UubGVuZ3RoPTAsdGhpcy5pbmMoInBhdGNoIix0KSx0aGlzLmluYygicHJlIix0KTticmVhaztjYXNlInByZXJlbGVhc2UiOjA9PT10aGlzLnByZXJlbGVhc2UubGVuZ3RoJiZ0aGlzLmluYygicGF0Y2giLHQpLHRoaXMuaW5jKCJwcmUiLHQpO2JyZWFrO2Nhc2UibWFqb3IiOjA9PT10aGlzLm1pbm9yJiYwPT09dGhpcy5wYXRjaCYmMCE9PXRoaXMucHJlcmVsZWFzZS5sZW5ndGh8fHRoaXMubWFqb3IrKyx0aGlzLm1pbm9yPTAsdGhpcy5wYXRjaD0wLHRoaXMucHJlcmVsZWFzZT1bXTticmVhaztjYXNlIm1pbm9yIjowPT09dGhpcy5wYXRjaCYmMCE9PXRoaXMucHJlcmVsZWFzZS5sZW5ndGh8fHRoaXMubWlub3IrKyx0aGlzLnBhdGNoPTAsdGhpcy5wcmVyZWxlYXNlPVtdO2JyZWFrO2Nhc2UicGF0Y2giOjA9PT10aGlzLnByZXJlbGVhc2UubGVuZ3RoJiZ0aGlzLnBhdGNoKyssdGhpcy5wcmVyZWxlYXNlPVtdO2JyZWFrO2Nhc2UicHJlIjppZigwPT09dGhpcy5wcmVyZWxlYXNlLmxlbmd0aCl0aGlzLnByZXJlbGVhc2U9WzBdO2Vsc2V7Zm9yKHZhciBuPXRoaXMucHJlcmVsZWFzZS5sZW5ndGg7LS1uPj0wOykibnVtYmVyIj09PXR5cGVvZiB0aGlzLnByZXJlbGVhc2Vbbl0mJih0aGlzLnByZXJlbGVhc2Vbbl0rKyxuPS0yKTstMT09PW4mJnRoaXMucHJlcmVsZWFzZS5wdXNoKDApfXQmJih0aGlzLnByZXJlbGVhc2VbMF09PT10P2lzTmFOKHRoaXMucHJlcmVsZWFzZVsxXSkmJih0aGlzLnByZXJlbGVhc2U9W3QsMF0pOnRoaXMucHJlcmVsZWFzZT1bdCwwXSk7YnJlYWs7ZGVmYXVsdDp0aHJvdyBuZXcgRXJyb3IoImludmFsaWQgaW5jcmVtZW50IGFyZ3VtZW50OiAiK2UpfXJldHVybiB0aGlzLmZvcm1hdCgpLHRoaXMucmF3PXRoaXMudmVyc2lvbix0aGlzfSx0LmluYz1hLHQuZGlmZj1zLHQuY29tcGFyZUlkZW50aWZpZXJzPXU7dmFyIGplPS9eWzAtOV0rJC87dC5yY29tcGFyZUlkZW50aWZpZXJzPWMsdC5tYWpvcj1sLHQubWlub3I9cCx0LnBhdGNoPWYsdC5jb21wYXJlPWQsdC5jb21wYXJlTG9vc2U9aCx0LnJjb21wYXJlPW0sdC5zb3J0PWcsdC5yc29ydD15LHQuZ3Q9dix0Lmx0PWIsdC5lcT14LHQubmVxPUMsdC5ndGU9RSx0Lmx0ZT1ELHQuY21wPXcsdC5Db21wYXJhdG9yPVM7dmFyIFJlPXt9O1MucHJvdG90eXBlLnBhcnNlPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMubG9vc2U/WVtPZV06WVtGZV0sbj1lLm1hdGNoKHQpO2lmKCFuKXRocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgY29tcGFyYXRvcjogIitlKTt0aGlzLm9wZXJhdG9yPW5bMV0sIj0iPT09dGhpcy5vcGVyYXRvciYmKHRoaXMub3BlcmF0b3I9IiIpLG5bMl0/dGhpcy5zZW12ZXI9bmV3IG8oblsyXSx0aGlzLmxvb3NlKTp0aGlzLnNlbXZlcj1SZX0sUy5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy52YWx1ZX0sUy5wcm90b3R5cGUudGVzdD1mdW5jdGlvbihlKXtyZXR1cm4gUSgiQ29tcGFyYXRvci50ZXN0IixlLHRoaXMubG9vc2UpLHRoaXMuc2VtdmVyPT09UmV8fCgic3RyaW5nIj09PXR5cGVvZiBlJiYoZT1uZXcgbyhlLHRoaXMubG9vc2UpKSx3KGUsdGhpcy5vcGVyYXRvcix0aGlzLnNlbXZlcix0aGlzLmxvb3NlKSl9LFMucHJvdG90eXBlLmludGVyc2VjdHM9ZnVuY3Rpb24oZSx0KXtpZighKGUgaW5zdGFuY2VvZiBTKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJhIENvbXBhcmF0b3IgaXMgcmVxdWlyZWQiKTt2YXIgbjtpZigiIj09PXRoaXMub3BlcmF0b3IpcmV0dXJuIG49bmV3IGsoZS52YWx1ZSx0KSxCKHRoaXMudmFsdWUsbix0KTtpZigiIj09PWUub3BlcmF0b3IpcmV0dXJuIG49bmV3IGsodGhpcy52YWx1ZSx0KSxCKGUuc2VtdmVyLG4sdCk7dmFyIHI9KCI+PSI9PT10aGlzLm9wZXJhdG9yfHwiPiI9PT10aGlzLm9wZXJhdG9yKSYmKCI+PSI9PT1lLm9wZXJhdG9yfHwiPiI9PT1lLm9wZXJhdG9yKSxpPSgiPD0iPT09dGhpcy5vcGVyYXRvcnx8IjwiPT09dGhpcy5vcGVyYXRvcikmJigiPD0iPT09ZS5vcGVyYXRvcnx8IjwiPT09ZS5vcGVyYXRvciksbz10aGlzLnNlbXZlci52ZXJzaW9uPT09ZS5zZW12ZXIudmVyc2lvbixhPSgiPj0iPT09dGhpcy5vcGVyYXRvcnx8Ijw9Ij09PXRoaXMub3BlcmF0b3IpJiYoIj49Ij09PWUub3BlcmF0b3J8fCI8PSI9PT1lLm9wZXJhdG9yKSxzPXcodGhpcy5zZW12ZXIsIjwiLGUuc2VtdmVyLHQpJiYoIj49Ij09PXRoaXMub3BlcmF0b3J8fCI+Ij09PXRoaXMub3BlcmF0b3IpJiYoIjw9Ij09PWUub3BlcmF0b3J8fCI8Ij09PWUub3BlcmF0b3IpLHU9dyh0aGlzLnNlbXZlciwiPiIsZS5zZW12ZXIsdCkmJigiPD0iPT09dGhpcy5vcGVyYXRvcnx8IjwiPT09dGhpcy5vcGVyYXRvcikmJigiPj0iPT09ZS5vcGVyYXRvcnx8Ij4iPT09ZS5vcGVyYXRvcik7cmV0dXJuIHJ8fGl8fG8mJmF8fHN8fHV9LHQuUmFuZ2U9ayxrLnByb3RvdHlwZS5mb3JtYXQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5yYW5nZT10aGlzLnNldC5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUuam9pbigiICIpLnRyaW0oKX0pLmpvaW4oInx8IikudHJpbSgpLHRoaXMucmFuZ2V9LGsucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucmFuZ2V9LGsucHJvdG90eXBlLnBhcnNlUmFuZ2U9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5sb29zZTtlPWUudHJpbSgpLFEoInJhbmdlIixlLHQpO3ZhciBuPXQ/WVtMZV06WVtJZV07ZT1lLnJlcGxhY2UobixqKSxRKCJoeXBoZW4gcmVwbGFjZSIsZSksZT1lLnJlcGxhY2UoWVtOZV0sIiQxJDIkMyIpLFEoImNvbXBhcmF0b3IgdHJpbSIsZSxZW05lXSksZT1lLnJlcGxhY2UoWVtEZV0sIiQxfiIpLGU9ZS5yZXBsYWNlKFlbQWVdLCIkMV4iKSxlPWUuc3BsaXQoL1xzKy8pLmpvaW4oIiAiKTt2YXIgcj10P1lbT2VdOllbRmVdLGk9ZS5zcGxpdCgiICIpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gXyhlLHQpfSkuam9pbigiICIpLnNwbGl0KC9ccysvKTtyZXR1cm4gdGhpcy5sb29zZSYmKGk9aS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuISFlLm1hdGNoKHIpfSkpLGk9aS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIG5ldyBTKGUsdCl9KX0say5wcm90b3R5cGUuaW50ZXJzZWN0cz1mdW5jdGlvbihlLHQpe2lmKCEoZSBpbnN0YW5jZW9mIGspKXRocm93IG5ldyBUeXBlRXJyb3IoImEgUmFuZ2UgaXMgcmVxdWlyZWQiKTtyZXR1cm4gdGhpcy5zZXQuc29tZShmdW5jdGlvbihuKXtyZXR1cm4gbi5ldmVyeShmdW5jdGlvbihuKXtyZXR1cm4gZS5zZXQuc29tZShmdW5jdGlvbihlKXtyZXR1cm4gZS5ldmVyeShmdW5jdGlvbihlKXtyZXR1cm4gbi5pbnRlcnNlY3RzKGUsdCl9KX0pfSl9KX0sdC50b0NvbXBhcmF0b3JzPUEsay5wcm90b3R5cGUudGVzdD1mdW5jdGlvbihlKXtpZighZSlyZXR1cm4hMTsic3RyaW5nIj09PXR5cGVvZiBlJiYoZT1uZXcgbyhlLHRoaXMubG9vc2UpKTtmb3IodmFyIHQ9MDt0PHRoaXMuc2V0Lmxlbmd0aDt0KyspaWYoUih0aGlzLnNldFt0XSxlKSlyZXR1cm4hMDtyZXR1cm4hMX0sdC5zYXRpc2ZpZXM9Qix0Lm1heFNhdGlzZnlpbmc9JCx0Lm1pblNhdGlzZnlpbmc9VSx0LnZhbGlkUmFuZ2U9eix0Lmx0cj1HLHQuZ3RyPVYsdC5vdXRzaWRlPXEsdC5wcmVyZWxlYXNlPUgsdC5pbnRlcnNlY3RzPVd9KSxhcnJheWlmeT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3Qua2V5cyhlKS5yZWR1Y2UoZnVuY3Rpb24obixyKXtyZXR1cm4gbi5jb25jYXQoT2JqZWN0LmFzc2lnbihfZGVmaW5lUHJvcGVydHkoe30sdCxyKSxlW3JdKSl9LFtdKX0sZGVkZW50XzE9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlKXt2YXIgdD12b2lkIDA7dD0ic3RyaW5nIj09PXR5cGVvZiBlP1tlXTplLnJhdztmb3IodmFyIG49IiIscj0wO3I8dC5sZW5ndGg7cisrKW4rPXRbcl0ucmVwbGFjZSgvXFxcblsgXHRdKi9nLCIiKS5yZXBsYWNlKC9cXGAvZywiYCIpLHI8KGFyZ3VtZW50cy5sZW5ndGg8PTE/MDphcmd1bWVudHMubGVuZ3RoLTEpJiYobis9YXJndW1lbnRzLmxlbmd0aDw9cisxP3ZvaWQgMDphcmd1bWVudHNbcisxXSk7dmFyIGk9bi5zcGxpdCgiXG4iKSxvPW51bGw7cmV0dXJuIGkuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgdD1lLm1hdGNoKC9eKFxzKylcUysvKTtpZih0KXt2YXIgbj10WzFdLmxlbmd0aDtvPW8/TWF0aC5taW4obyxuKTpufX0pLG51bGwhPT1vJiYobj1pLm1hcChmdW5jdGlvbihlKXtyZXR1cm4iICI9PT1lWzBdP2Uuc2xpY2Uobyk6ZX0pLmpvaW4oIlxuIikpLG49bi50cmltKCksbi5yZXBsYWNlKC9cXG4vZywiXG4iKX1lLmV4cG9ydHM9dH0pLENBVEVHT1JZX0NPTkZJRz0iQ29uZmlnIixDQVRFR09SWV9FRElUT1I9IkVkaXRvciIsQ0FURUdPUllfRk9STUFUPSJGb3JtYXQiLENBVEVHT1JZX09USEVSPSJPdGhlciIsQ0FURUdPUllfT1VUUFVUPSJPdXRwdXQiLENBVEVHT1JZX0dMT0JBTD0iR2xvYmFsIixDQVRFR09SWV9TUEVDSUFMPSJTcGVjaWFsIixvcHRpb25zJDI9e2N1cnNvck9mZnNldDp7c2luY2U6IjEuNC4wIixjYXRlZ29yeTpDQVRFR09SWV9TUEVDSUFMLHR5cGU6ImludCIsZGVmYXVsdDotMSxyYW5nZTp7c3RhcnQ6LTEsZW5kOjEvMCxzdGVwOjF9LGRlc2NyaXB0aW9uOmRlZGVudF8xKF90ZW1wbGF0ZU9iamVjdCgpKSxjbGlDYXRlZ29yeTpDQVRFR09SWV9FRElUT1J9LGZpbGVwYXRoOntzaW5jZToiMS40LjAiLGNhdGVnb3J5OkNBVEVHT1JZX1NQRUNJQUwsdHlwZToicGF0aCIsZGVmYXVsdDp2b2lkIDAsZGVzY3JpcHRpb246IlNwZWNpZnkgdGhlIGlucHV0IGZpbGVwYXRoLiBUaGlzIHdpbGwgYmUgdXNlZCB0byBkbyBwYXJzZXIgaW5mZXJlbmNlLiIsY2xpTmFtZToic3RkaW4tZmlsZXBhdGgiLGNsaUNhdGVnb3J5OkNBVEVHT1JZX09USEVSLGNsaURlc2NyaXB0aW9uOiJQYXRoIHRvIHRoZSBmaWxlIHRvIHByZXRlbmQgdGhhdCBzdGRpbiBjb21lcyBmcm9tLiJ9LGluc2VydFByYWdtYTp7c2luY2U6IjEuOC4wIixjYXRlZ29yeTpDQVRFR09SWV9TUEVDSUFMLHR5cGU6ImJvb2xlYW4iLGRlZmF1bHQ6ITEsZGVzY3JpcHRpb246Ikluc2VydCBAZm9ybWF0IHByYWdtYSBpbnRvIGZpbGUncyBmaXJzdCBkb2NibG9jayBjb21tZW50LiIsY2xpQ2F0ZWdvcnk6Q0FURUdPUllfT1RIRVJ9LHBhcnNlcjp7c2luY2U6IjAuMC4xMCIsY2F0ZWdvcnk6Q0FURUdPUllfR0xPQkFMLHR5cGU6ImNob2ljZSIsZGVmYXVsdDpbe3NpbmNlOiIwLjAuMTAiLHZhbHVlOiJiYWJ5bG9uIn0se3NpbmNlOiIxLjEzLjAiLHZhbHVlOnZvaWQgMH1dLGRlc2NyaXB0aW9uOiJXaGljaCBwYXJzZXIgdG8gdXNlLiIsZXhjZXB0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciPT09dHlwZW9mIGV8fCJmdW5jdGlvbiI9PT10eXBlb2YgZX0sY2hvaWNlczpbe3ZhbHVlOiJmbG93IixkZXNjcmlwdGlvbjoiRmxvdyJ9LHt2YWx1ZToiYmFieWxvbiIsZGVzY3JpcHRpb246IkphdmFTY3JpcHQifSx7dmFsdWU6InR5cGVzY3JpcHQiLHNpbmNlOiIxLjQuMCIsZGVzY3JpcHRpb246IlR5cGVTY3JpcHQifSx7dmFsdWU6ImNzcyIsc2luY2U6IjEuNy4xIixkZXNjcmlwdGlvbjoiQ1NTIn0se3ZhbHVlOiJwb3N0Y3NzIixzaW5jZToiMS40LjAiLGRlc2NyaXB0aW9uOiJDU1MvTGVzcy9TQ1NTIixkZXByZWNhdGVkOiIxLjcuMSIscmVkaXJlY3Q6ImNzcyJ9LHt2YWx1ZToibGVzcyIsc2luY2U6IjEuNy4xIixkZXNjcmlwdGlvbjoiTGVzcyJ9LHt2YWx1ZToic2NzcyIsc2luY2U6IjEuNy4xIixkZXNjcmlwdGlvbjoiU0NTUyJ9LHt2YWx1ZToianNvbiIsc2luY2U6IjEuNS4wIixkZXNjcmlwdGlvbjoiSlNPTiJ9LHt2YWx1ZToianNvbjUiLHNpbmNlOiIxLjEzLjAiLGRlc2NyaXB0aW9uOiJKU09ONSJ9LHt2YWx1ZToianNvbi1zdHJpbmdpZnkiLHNpbmNlOiIxLjEzLjAiLGRlc2NyaXB0aW9uOiJKU09OLnN0cmluZ2lmeSJ9LHt2YWx1ZToiZ3JhcGhxbCIsc2luY2U6IjEuNS4wIixkZXNjcmlwdGlvbjoiR3JhcGhRTCJ9LHt2YWx1ZToibWFya2Rvd24iLHNpbmNlOiIxLjguMCIsZGVzY3JpcHRpb246Ik1hcmtkb3duIn0se3ZhbHVlOiJ2dWUiLHNpbmNlOiIxLjEwLjAiLGRlc2NyaXB0aW9uOiJWdWUifV19LHBsdWdpbnM6e3NpbmNlOiIxLjEwLjAiLHR5cGU6InBhdGgiLGFycmF5OiEwLGRlZmF1bHQ6W3t2YWx1ZTpbXX1dLGNhdGVnb3J5OkNBVEVHT1JZX0dMT0JBTCxkZXNjcmlwdGlvbjoiQWRkIGEgcGx1Z2luLiBNdWx0aXBsZSBwbHVnaW5zIGNhbiBiZSBwYXNzZWQgYXMgc2VwYXJhdGUgYC0tcGx1Z2luYHMuIixleGNlcHRpb246ZnVuY3Rpb24oZSl7cmV0dXJuInN0cmluZyI9PT10eXBlb2YgZXx8Im9iamVjdCI9PT1fdHlwZW9mKGUpfSxjbGlOYW1lOiJwbHVnaW4iLGNsaUNhdGVnb3J5OkNBVEVHT1JZX0NPTkZJR30scGx1Z2luU2VhcmNoRGlyczp7c2luY2U6IjEuMTMuMCIsdHlwZToicGF0aCIsYXJyYXk6ITAsZGVmYXVsdDpbe3ZhbHVlOltdfV0sY2F0ZWdvcnk6Q0FURUdPUllfR0xPQkFMLGRlc2NyaXB0aW9uOmRlZGVudF8xKF90ZW1wbGF0ZU9iamVjdDIoKSksZXhjZXB0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciPT09dHlwZW9mIGV8fCJvYmplY3QiPT09X3R5cGVvZihlKX0sY2xpTmFtZToicGx1Z2luLXNlYXJjaC1kaXIiLGNsaUNhdGVnb3J5OkNBVEVHT1JZX0NPTkZJR30scHJpbnRXaWR0aDp7c2luY2U6IjAuMC4wIixjYXRlZ29yeTpDQVRFR09SWV9HTE9CQUwsdHlwZToiaW50IixkZWZhdWx0OjgwLGRlc2NyaXB0aW9uOiJUaGUgbGluZSBsZW5ndGggd2hlcmUgUHJldHRpZXIgd2lsbCB0cnkgd3JhcC4iLHJhbmdlOntzdGFydDowLGVuZDoxLzAsc3RlcDoxfX0scmFuZ2VFbmQ6e3NpbmNlOiIxLjQuMCIsY2F0ZWdvcnk6Q0FURUdPUllfU1BFQ0lBTCx0eXBlOiJpbnQiLGRlZmF1bHQ6MS8wLHJhbmdlOntzdGFydDowLGVuZDoxLzAsc3RlcDoxfSxkZXNjcmlwdGlvbjpkZWRlbnRfMShfdGVtcGxhdGVPYmplY3QzKCkpLGNsaUNhdGVnb3J5OkNBVEVHT1JZX0VESVRPUn0scmFuZ2VTdGFydDp7c2luY2U6IjEuNC4wIixjYXRlZ29yeTpDQVRFR09SWV9TUEVDSUFMLHR5cGU6ImludCIsZGVmYXVsdDowLHJhbmdlOntzdGFydDowLGVuZDoxLzAsc3RlcDoxfSxkZXNjcmlwdGlvbjpkZWRlbnRfMShfdGVtcGxhdGVPYmplY3Q0KCkpLGNsaUNhdGVnb3J5OkNBVEVHT1JZX0VESVRPUn0scmVxdWlyZVByYWdtYTp7c2luY2U6IjEuNy4wIixjYXRlZ29yeTpDQVRFR09SWV9TUEVDSUFMLHR5cGU6ImJvb2xlYW4iLGRlZmF1bHQ6ITEsZGVzY3JpcHRpb246ZGVkZW50XzEoX3RlbXBsYXRlT2JqZWN0NSgpKSxjbGlDYXRlZ29yeTpDQVRFR09SWV9PVEhFUn0sdGFiV2lkdGg6e3R5cGU6ImludCIsY2F0ZWdvcnk6Q0FURUdPUllfR0xPQkFMLGRlZmF1bHQ6MixkZXNjcmlwdGlvbjoiTnVtYmVyIG9mIHNwYWNlcyBwZXIgaW5kZW50YXRpb24gbGV2ZWwuIixyYW5nZTp7c3RhcnQ6MCxlbmQ6MS8wLHN0ZXA6MX19LHVzZUZsb3dQYXJzZXI6e3NpbmNlOiIwLjAuMCIsY2F0ZWdvcnk6Q0FURUdPUllfR0xPQkFMLHR5cGU6ImJvb2xlYW4iLGRlZmF1bHQ6ITEsZGVwcmVjYXRlZDoiMC4wLjEwIixkZXNjcmlwdGlvbjoiVXNlIGZsb3cgcGFyc2VyLiIscmVkaXJlY3Q6e29wdGlvbjoicGFyc2VyIix2YWx1ZToiZmxvdyJ9LGNsaU5hbWU6ImZsb3ctcGFyc2VyIn0sdXNlVGFiczp7c2luY2U6IjEuMC4wIixjYXRlZ29yeTpDQVRFR09SWV9HTE9CQUwsdHlwZToiYm9vbGVhbiIsZGVmYXVsdDohMSxkZXNjcmlwdGlvbjoiSW5kZW50IHdpdGggdGFicyBpbnN0ZWFkIG9mIHNwYWNlcy4ifX0sY29yZU9wdGlvbnMkMT17Q0FURUdPUllfQ09ORklHOkNBVEVHT1JZX0NPTkZJRyxDQVRFR09SWV9FRElUT1I6Q0FURUdPUllfRURJVE9SLENBVEVHT1JZX0ZPUk1BVDpDQVRFR09SWV9GT1JNQVQsQ0FURUdPUllfT1RIRVI6Q0FURUdPUllfT1RIRVIsQ0FURUdPUllfT1VUUFVUOkNBVEVHT1JZX09VVFBVVCxDQVRFR09SWV9HTE9CQUw6Q0FURUdPUllfR0xPQkFMLENBVEVHT1JZX1NQRUNJQUw6Q0FURUdPUllfU1BFQ0lBTCxvcHRpb25zOm9wdGlvbnMkMn0scmVxdWlyZSQkMD1fcGFja2FnZSQxJiZfcGFja2FnZXx8X3BhY2thZ2UkMSxjdXJyZW50VmVyc2lvbj1yZXF1aXJlJCQwLnZlcnNpb24sY29yZU9wdGlvbnM9Y29yZU9wdGlvbnMkMS5vcHRpb25zLHN1cHBvcnQ9e2dldFN1cHBvcnRJbmZvOmdldFN1cHBvcnRJbmZvJDJ9LGFycj1bXSxjaGFyQ29kZUNhY2hlPVtdLGxldmVuPWZ1bmN0aW9uKGUsdCl7aWYoZT09PXQpcmV0dXJuIDA7dmFyIG49ZTtlLmxlbmd0aD50Lmxlbmd0aCYmKGU9dCx0PW4pO3ZhciByPWUubGVuZ3RoLGk9dC5sZW5ndGg7aWYoMD09PXIpcmV0dXJuIGk7aWYoMD09PWkpcmV0dXJuIHI7Zm9yKDtyPjAmJmUuY2hhckNvZGVBdCh+LXIpPT09dC5jaGFyQ29kZUF0KH4taSk7KXItLSxpLS07aWYoMD09PXIpcmV0dXJuIGk7Zm9yKHZhciBvPTA7bzxyJiZlLmNoYXJDb2RlQXQobyk9PT10LmNoYXJDb2RlQXQobyk7KW8rKztpZihyLT1vLGktPW8sMD09PXIpcmV0dXJuIGk7Zm9yKHZhciBhLHMsdSxjLGw9MCxwPTA7bDxyOyljaGFyQ29kZUNhY2hlW28rbF09ZS5jaGFyQ29kZUF0KG8rbCksYXJyW2xdPSsrbDtmb3IoO3A8aTspZm9yKGE9dC5jaGFyQ29kZUF0KG8rcCksdT1wKysscz1wLGw9MDtsPHI7bCsrKWM9YT09PWNoYXJDb2RlQ2FjaGVbbytsXT91OnUrMSx1PWFycltsXSxzPWFycltsXT11PnM/Yz5zP3MrMTpjOmM+dT91KzE6YztyZXR1cm4gc30sb3B0aW9uc0Rlc2NyaXB0b3I9e2FwaURlc2NyaXB0b3I6YXBpRGVzY3JpcHRvcixjbGlEZXNjcmlwdG9yOmNsaURlc2NyaXB0b3J9LG9wdGlvbnNWYWxpZGF0b3I9e3ZhbGlkYXRlT3B0aW9uOnZhbGlkYXRlT3B0aW9ufSxvcHRpb25zTm9ybWFsaXplcj17bm9ybWFsaXplQXBpT3B0aW9uczpub3JtYWxpemVBcGlPcHRpb25zLG5vcm1hbGl6ZUNsaU9wdGlvbnM6bm9ybWFsaXplQ2xpT3B0aW9uc30sZ2V0TGFzdD1mdW5jdGlvbihlKXtyZXR1cm4gZS5sZW5ndGg+MD9lW2UubGVuZ3RoLTFdOm51bGx9LGxvYz17bG9jU3RhcnQ6bG9jU3RhcnQkMSxsb2NFbmQ6bG9jRW5kJDF9LGpzVG9rZW5zPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUsdCl7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZGVmYXVsdD0vKChbJyJdKSg/Oig/IVwyfFxcKS58XFwoPzpcclxufFtcc1xTXSkpKihcMik/fGAoPzpbXmBcXCRdfFxcW1xzXFNdfFwkKD8hXHspfFwkXHsoPzpbXnt9XXxce1tefV0qXH0/KSpcfT8pKihgKT8pfChcL1wvLiopfChcL1wqKD86W14qXXxcKig/IVwvKSkqKFwqXC8pPyl8KFwvKD8hXCopKD86XFsoPzooPyFbXF1cXF0pLnxcXC4pKlxdfCg/IVtcL1xdXFxdKS58XFwuKStcLyg/Oig/IVxzKig/OlxifFtcdTAwODAtXHVGRkZGJFxcJyJ+KHtdfFsrXC0hXSg/IT0pfFwuP1xkKSl8W2dtaXl1XXsxLDV9XGIoPyFbXHUwMDgwLVx1RkZGRiRcXF18XHMqKD86WytcLSolJnxePD4hPT8oe118XC8oPyFbXC8qXSkpKSkpfCgwW3hYXVtcZGEtZkEtRl0rfDBbb09dWzAtN10rfDBbYkJdWzAxXSt8KD86XGQqXC5cZCt8XGQrXC4/KSg/OltlRV1bKy1dP1xkKyk/KXwoKD8hXGQpKD86KD8hXHMpWyRcd1x1MDA4MC1cdUZGRkZdfFxcdVtcZGEtZkEtRl17NH18XFx1XHtbXGRhLWZBLUZdK1x9KSspfCgtLXxcK1wrfCYmfFx8XHx8PT58XC57M318KD86WytcLVwvJSZ8Xl18XCp7MSwyfXw8ezEsMn18PnsxLDN9fCE9P3w9ezEsMn0pPT98Wz9+Liw6O1tcXSgpe31dKXwoXHMrKXwoXiR8W1xzXFNdKS9nLHQubWF0Y2hUb1Rva2VuPWZ1bmN0aW9uKGUpe3ZhciB0PXt0eXBlOiJpbnZhbGlkIix2YWx1ZTplWzBdfTtyZXR1cm4gZVsxXT8odC50eXBlPSJzdHJpbmciLHQuY2xvc2VkPSEoIWVbM10mJiFlWzRdKSk6ZVs1XT90LnR5cGU9ImNvbW1lbnQiOmVbNl0/KHQudHlwZT0iY29tbWVudCIsdC5jbG9zZWQ9ISFlWzddKTplWzhdP3QudHlwZT0icmVnZXgiOmVbOV0/dC50eXBlPSJudW1iZXIiOmVbMTBdP3QudHlwZT0ibmFtZSI6ZVsxMV0/dC50eXBlPSJwdW5jdHVhdG9yIjplWzEyXSYmKHQudHlwZT0id2hpdGVzcGFjZSIpLHR9fSk7dW53cmFwRXhwb3J0cyhqc1Rva2Vucyk7dmFyIGFzdD1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlKXshZnVuY3Rpb24oKXtmdW5jdGlvbiB0KGUpe2lmKG51bGw9PWUpcmV0dXJuITE7c3dpdGNoKGUudHlwZSl7Y2FzZSJBcnJheUV4cHJlc3Npb24iOmNhc2UiQXNzaWdubWVudEV4cHJlc3Npb24iOmNhc2UiQmluYXJ5RXhwcmVzc2lvbiI6Y2FzZSJDYWxsRXhwcmVzc2lvbiI6Y2FzZSJDb25kaXRpb25hbEV4cHJlc3Npb24iOmNhc2UiRnVuY3Rpb25FeHByZXNzaW9uIjpjYXNlIklkZW50aWZpZXIiOmNhc2UiTGl0ZXJhbCI6Y2FzZSJMb2dpY2FsRXhwcmVzc2lvbiI6Y2FzZSJNZW1iZXJFeHByZXNzaW9uIjpjYXNlIk5ld0V4cHJlc3Npb24iOmNhc2UiT2JqZWN0RXhwcmVzc2lvbiI6Y2FzZSJTZXF1ZW5jZUV4cHJlc3Npb24iOmNhc2UiVGhpc0V4cHJlc3Npb24iOmNhc2UiVW5hcnlFeHByZXNzaW9uIjpjYXNlIlVwZGF0ZUV4cHJlc3Npb24iOnJldHVybiEwfXJldHVybiExfWZ1bmN0aW9uIG4oZSl7aWYobnVsbD09ZSlyZXR1cm4hMTtzd2l0Y2goZS50eXBlKXtjYXNlIkRvV2hpbGVTdGF0ZW1lbnQiOmNhc2UiRm9ySW5TdGF0ZW1lbnQiOmNhc2UiRm9yU3RhdGVtZW50IjpjYXNlIldoaWxlU3RhdGVtZW50IjpyZXR1cm4hMH1yZXR1cm4hMX1mdW5jdGlvbiByKGUpe2lmKG51bGw9PWUpcmV0dXJuITE7c3dpdGNoKGUudHlwZSl7Y2FzZSJCbG9ja1N0YXRlbWVudCI6Y2FzZSJCcmVha1N0YXRlbWVudCI6Y2FzZSJDb250aW51ZVN0YXRlbWVudCI6Y2FzZSJEZWJ1Z2dlclN0YXRlbWVudCI6Y2FzZSJEb1doaWxlU3RhdGVtZW50IjpjYXNlIkVtcHR5U3RhdGVtZW50IjpjYXNlIkV4cHJlc3Npb25TdGF0ZW1lbnQiOmNhc2UiRm9ySW5TdGF0ZW1lbnQiOmNhc2UiRm9yU3RhdGVtZW50IjpjYXNlIklmU3RhdGVtZW50IjpjYXNlIkxhYmVsZWRTdGF0ZW1lbnQiOmNhc2UiUmV0dXJuU3RhdGVtZW50IjpjYXNlIlN3aXRjaFN0YXRlbWVudCI6Y2FzZSJUaHJvd1N0YXRlbWVudCI6Y2FzZSJUcnlTdGF0ZW1lbnQiOmNhc2UiVmFyaWFibGVEZWNsYXJhdGlvbiI6Y2FzZSJXaGlsZVN0YXRlbWVudCI6Y2FzZSJXaXRoU3RhdGVtZW50IjpyZXR1cm4hMH1yZXR1cm4hMX1mdW5jdGlvbiBpKGUpe3JldHVybiByKGUpfHxudWxsIT1lJiYiRnVuY3Rpb25EZWNsYXJhdGlvbiI9PT1lLnR5cGV9ZnVuY3Rpb24gbyhlKXtzd2l0Y2goZS50eXBlKXtjYXNlIklmU3RhdGVtZW50IjpyZXR1cm4gbnVsbCE9ZS5hbHRlcm5hdGU/ZS5hbHRlcm5hdGU6ZS5jb25zZXF1ZW50O2Nhc2UiTGFiZWxlZFN0YXRlbWVudCI6Y2FzZSJGb3JTdGF0ZW1lbnQiOmNhc2UiRm9ySW5TdGF0ZW1lbnQiOmNhc2UiV2hpbGVTdGF0ZW1lbnQiOmNhc2UiV2l0aFN0YXRlbWVudCI6cmV0dXJuIGUuYm9keX1yZXR1cm4gbnVsbH1mdW5jdGlvbiBhKGUpe3ZhciB0O2lmKCJJZlN0YXRlbWVudCIhPT1lLnR5cGUpcmV0dXJuITE7aWYobnVsbD09ZS5hbHRlcm5hdGUpcmV0dXJuITE7dD1lLmNvbnNlcXVlbnQ7ZG97aWYoIklmU3RhdGVtZW50Ij09PXQudHlwZSYmbnVsbD09dC5hbHRlcm5hdGUpcmV0dXJuITA7dD1vKHQpfXdoaWxlKHQpO3JldHVybiExfWUuZXhwb3J0cz17aXNFeHByZXNzaW9uOnQsaXNTdGF0ZW1lbnQ6cixpc0l0ZXJhdGlvblN0YXRlbWVudDpuLGlzU291cmNlRWxlbWVudDppLGlzUHJvYmxlbWF0aWNJZlN0YXRlbWVudDphLHRyYWlsaW5nU3RhdGVtZW50Om99fSgpfSksY29kZT1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlKXshZnVuY3Rpb24oKXtmdW5jdGlvbiB0KGUpe3JldHVybiA0ODw9ZSYmZTw9NTd9ZnVuY3Rpb24gbihlKXtyZXR1cm4gNDg8PWUmJmU8PTU3fHw5Nzw9ZSYmZTw9MTAyfHw2NTw9ZSYmZTw9NzB9ZnVuY3Rpb24gcihlKXtyZXR1cm4gZT49NDgmJmU8PTU1fWZ1bmN0aW9uIGkoZSl7cmV0dXJuIDMyPT09ZXx8OT09PWV8fDExPT09ZXx8MTI9PT1lfHwxNjA9PT1lfHxlPj01NzYwJiZkLmluZGV4T2YoZSk+PTB9ZnVuY3Rpb24gbyhlKXtyZXR1cm4gMTA9PT1lfHwxMz09PWV8fDgyMzI9PT1lfHw4MjMzPT09ZX1mdW5jdGlvbiBhKGUpe3JldHVybiBlPD02NTUzNT9TdHJpbmcuZnJvbUNoYXJDb2RlKGUpOlN0cmluZy5mcm9tQ2hhckNvZGUoTWF0aC5mbG9vcigoZS02NTUzNikvMTAyNCkrNTUyOTYpK1N0cmluZy5mcm9tQ2hhckNvZGUoKGUtNjU1MzYpJTEwMjQrNTYzMjApfWZ1bmN0aW9uIHMoZSl7cmV0dXJuIGU8MTI4P2hbZV06Zi5Ob25Bc2NpaUlkZW50aWZpZXJTdGFydC50ZXN0KGEoZSkpfWZ1bmN0aW9uIHUoZSl7cmV0dXJuIGU8MTI4P21bZV06Zi5Ob25Bc2NpaUlkZW50aWZpZXJQYXJ0LnRlc3QoYShlKSl9ZnVuY3Rpb24gYyhlKXtyZXR1cm4gZTwxMjg/aFtlXTpwLk5vbkFzY2lpSWRlbnRpZmllclN0YXJ0LnRlc3QoYShlKSl9ZnVuY3Rpb24gbChlKXtyZXR1cm4gZTwxMjg/bVtlXTpwLk5vbkFzY2lpSWRlbnRpZmllclBhcnQudGVzdChhKGUpKX12YXIgcCxmLGQsaCxtLGc7Zm9yKGY9e05vbkFzY2lpSWRlbnRpZmllclN0YXJ0Oi9bXHhBQVx4QjVceEJBXHhDMC1ceEQ2XHhEOC1ceEY2XHhGOC1cdTAyQzFcdTAyQzYtXHUwMkQxXHUwMkUwLVx1MDJFNFx1MDJFQ1x1MDJFRVx1MDM3MC1cdTAzNzRcdTAzNzZcdTAzNzdcdTAzN0EtXHUwMzdEXHUwMzdGXHUwMzg2XHUwMzg4LVx1MDM4QVx1MDM4Q1x1MDM4RS1cdTAzQTFcdTAzQTMtXHUwM0Y1XHUwM0Y3LVx1MDQ4MVx1MDQ4QS1cdTA1MkZcdTA1MzEtXHUwNTU2XHUwNTU5XHUwNTYxLVx1MDU4N1x1MDVEMC1cdTA1RUFcdTA1RjAtXHUwNUYyXHUwNjIwLVx1MDY0QVx1MDY2RVx1MDY2Rlx1MDY3MS1cdTA2RDNcdTA2RDVcdTA2RTVcdTA2RTZcdTA2RUVcdTA2RUZcdTA2RkEtXHUwNkZDXHUwNkZGXHUwNzEwXHUwNzEyLVx1MDcyRlx1MDc0RC1cdTA3QTVcdTA3QjFcdTA3Q0EtXHUwN0VBXHUwN0Y0XHUwN0Y1XHUwN0ZBXHUwODAwLVx1MDgxNVx1MDgxQVx1MDgyNFx1MDgyOFx1MDg0MC1cdTA4NThcdTA4QTAtXHUwOEIyXHUwOTA0LVx1MDkzOVx1MDkzRFx1MDk1MFx1MDk1OC1cdTA5NjFcdTA5NzEtXHUwOTgwXHUwOTg1LVx1MDk4Q1x1MDk4Rlx1MDk5MFx1MDk5My1cdTA5QThcdTA5QUEtXHUwOUIwXHUwOUIyXHUwOUI2LVx1MDlCOVx1MDlCRFx1MDlDRVx1MDlEQ1x1MDlERFx1MDlERi1cdTA5RTFcdTA5RjBcdTA5RjFcdTBBMDUtXHUwQTBBXHUwQTBGXHUwQTEwXHUwQTEzLVx1MEEyOFx1MEEyQS1cdTBBMzBcdTBBMzJcdTBBMzNcdTBBMzVcdTBBMzZcdTBBMzhcdTBBMzlcdTBBNTktXHUwQTVDXHUwQTVFXHUwQTcyLVx1MEE3NFx1MEE4NS1cdTBBOERcdTBBOEYtXHUwQTkxXHUwQTkzLVx1MEFBOFx1MEFBQS1cdTBBQjBcdTBBQjJcdTBBQjNcdTBBQjUtXHUwQUI5XHUwQUJEXHUwQUQwXHUwQUUwXHUwQUUxXHUwQjA1LVx1MEIwQ1x1MEIwRlx1MEIxMFx1MEIxMy1cdTBCMjhcdTBCMkEtXHUwQjMwXHUwQjMyXHUwQjMzXHUwQjM1LVx1MEIzOVx1MEIzRFx1MEI1Q1x1MEI1RFx1MEI1Ri1cdTBCNjFcdTBCNzFcdTBCODNcdTBCODUtXHUwQjhBXHUwQjhFLVx1MEI5MFx1MEI5Mi1cdTBCOTVcdTBCOTlcdTBCOUFcdTBCOUNcdTBCOUVcdTBCOUZcdTBCQTNcdTBCQTRcdTBCQTgtXHUwQkFBXHUwQkFFLVx1MEJCOVx1MEJEMFx1MEMwNS1cdTBDMENcdTBDMEUtXHUwQzEwXHUwQzEyLVx1MEMyOFx1MEMyQS1cdTBDMzlcdTBDM0RcdTBDNThcdTBDNTlcdTBDNjBcdTBDNjFcdTBDODUtXHUwQzhDXHUwQzhFLVx1MEM5MFx1MEM5Mi1cdTBDQThcdTBDQUEtXHUwQ0IzXHUwQ0I1LVx1MENCOVx1MENCRFx1MENERVx1MENFMFx1MENFMVx1MENGMVx1MENGMlx1MEQwNS1cdTBEMENcdTBEMEUtXHUwRDEwXHUwRDEyLVx1MEQzQVx1MEQzRFx1MEQ0RVx1MEQ2MFx1MEQ2MVx1MEQ3QS1cdTBEN0ZcdTBEODUtXHUwRDk2XHUwRDlBLVx1MERCMVx1MERCMy1cdTBEQkJcdTBEQkRcdTBEQzAtXHUwREM2XHUwRTAxLVx1MEUzMFx1MEUzMlx1MEUzM1x1MEU0MC1cdTBFNDZcdTBFODFcdTBFODJcdTBFODRcdTBFODdcdTBFODhcdTBFOEFcdTBFOERcdTBFOTQtXHUwRTk3XHUwRTk5LVx1MEU5Rlx1MEVBMS1cdTBFQTNcdTBFQTVcdTBFQTdcdTBFQUFcdTBFQUJcdTBFQUQtXHUwRUIwXHUwRUIyXHUwRUIzXHUwRUJEXHUwRUMwLVx1MEVDNFx1MEVDNlx1MEVEQy1cdTBFREZcdTBGMDBcdTBGNDAtXHUwRjQ3XHUwRjQ5LVx1MEY2Q1x1MEY4OC1cdTBGOENcdTEwMDAtXHUxMDJBXHUxMDNGXHUxMDUwLVx1MTA1NVx1MTA1QS1cdTEwNURcdTEwNjFcdTEwNjVcdTEwNjZcdTEwNkUtXHUxMDcwXHUxMDc1LVx1MTA4MVx1MTA4RVx1MTBBMC1cdTEwQzVcdTEwQzdcdTEwQ0RcdTEwRDAtXHUxMEZBXHUxMEZDLVx1MTI0OFx1MTI0QS1cdTEyNERcdTEyNTAtXHUxMjU2XHUxMjU4XHUxMjVBLVx1MTI1RFx1MTI2MC1cdTEyODhcdTEyOEEtXHUxMjhEXHUxMjkwLVx1MTJCMFx1MTJCMi1cdTEyQjVcdTEyQjgtXHUxMkJFXHUxMkMwXHUxMkMyLVx1MTJDNVx1MTJDOC1cdTEyRDZcdTEyRDgtXHUxMzEwXHUxMzEyLVx1MTMxNVx1MTMxOC1cdTEzNUFcdTEzODAtXHUxMzhGXHUxM0EwLVx1MTNGNFx1MTQwMS1cdTE2NkNcdTE2NkYtXHUxNjdGXHUxNjgxLVx1MTY5QVx1MTZBMC1cdTE2RUFcdTE2RUUtXHUxNkY4XHUxNzAwLVx1MTcwQ1x1MTcwRS1cdTE3MTFcdTE3MjAtXHUxNzMxXHUxNzQwLVx1MTc1MVx1MTc2MC1cdTE3NkNcdTE3NkUtXHUxNzcwXHUxNzgwLVx1MTdCM1x1MTdEN1x1MTdEQ1x1MTgyMC1cdTE4NzdcdTE4ODAtXHUxOEE4XHUxOEFBXHUxOEIwLVx1MThGNVx1MTkwMC1cdTE5MUVcdTE5NTAtXHUxOTZEXHUxOTcwLVx1MTk3NFx1MTk4MC1cdTE5QUJcdTE5QzEtXHUxOUM3XHUxQTAwLVx1MUExNlx1MUEyMC1cdTFBNTRcdTFBQTdcdTFCMDUtXHUxQjMzXHUxQjQ1LVx1MUI0Qlx1MUI4My1cdTFCQTBcdTFCQUVcdTFCQUZcdTFCQkEtXHUxQkU1XHUxQzAwLVx1MUMyM1x1MUM0RC1cdTFDNEZcdTFDNUEtXHUxQzdEXHUxQ0U5LVx1MUNFQ1x1MUNFRS1cdTFDRjFcdTFDRjVcdTFDRjZcdTFEMDAtXHUxREJGXHUxRTAwLVx1MUYxNVx1MUYxOC1cdTFGMURcdTFGMjAtXHUxRjQ1XHUxRjQ4LVx1MUY0RFx1MUY1MC1cdTFGNTdcdTFGNTlcdTFGNUJcdTFGNURcdTFGNUYtXHUxRjdEXHUxRjgwLVx1MUZCNFx1MUZCNi1cdTFGQkNcdTFGQkVcdTFGQzItXHUxRkM0XHUxRkM2LVx1MUZDQ1x1MUZEMC1cdTFGRDNcdTFGRDYtXHUxRkRCXHUxRkUwLVx1MUZFQ1x1MUZGMi1cdTFGRjRcdTFGRjYtXHUxRkZDXHUyMDcxXHUyMDdGXHUyMDkwLVx1MjA5Q1x1MjEwMlx1MjEwN1x1MjEwQS1cdTIxMTNcdTIxMTVcdTIxMTktXHUyMTFEXHUyMTI0XHUyMTI2XHUyMTI4XHUyMTJBLVx1MjEyRFx1MjEyRi1cdTIxMzlcdTIxM0MtXHUyMTNGXHUyMTQ1LVx1MjE0OVx1MjE0RVx1MjE2MC1cdTIxODhcdTJDMDAtXHUyQzJFXHUyQzMwLVx1MkM1RVx1MkM2MC1cdTJDRTRcdTJDRUItXHUyQ0VFXHUyQ0YyXHUyQ0YzXHUyRDAwLVx1MkQyNVx1MkQyN1x1MkQyRFx1MkQzMC1cdTJENjdcdTJENkZcdTJEODAtXHUyRDk2XHUyREEwLVx1MkRBNlx1MkRBOC1cdTJEQUVcdTJEQjAtXHUyREI2XHUyREI4LVx1MkRCRVx1MkRDMC1cdTJEQzZcdTJEQzgtXHUyRENFXHUyREQwLVx1MkRENlx1MkREOC1cdTJEREVcdTJFMkZcdTMwMDUtXHUzMDA3XHUzMDIxLVx1MzAyOVx1MzAzMS1cdTMwMzVcdTMwMzgtXHUzMDNDXHUzMDQxLVx1MzA5Nlx1MzA5RC1cdTMwOUZcdTMwQTEtXHUzMEZBXHUzMEZDLVx1MzBGRlx1MzEwNS1cdTMxMkRcdTMxMzEtXHUzMThFXHUzMUEwLVx1MzFCQVx1MzFGMC1cdTMxRkZcdTM0MDAtXHU0REI1XHU0RTAwLVx1OUZDQ1x1QTAwMC1cdUE0OENcdUE0RDAtXHVBNEZEXHVBNTAwLVx1QTYwQ1x1QTYxMC1cdUE2MUZcdUE2MkFcdUE2MkJcdUE2NDAtXHVBNjZFXHVBNjdGLVx1QTY5RFx1QTZBMC1cdUE2RUZcdUE3MTctXHVBNzFGXHVBNzIyLVx1QTc4OFx1QTc4Qi1cdUE3OEVcdUE3OTAtXHVBN0FEXHVBN0IwXHVBN0IxXHVBN0Y3LVx1QTgwMVx1QTgwMy1cdUE4MDVcdUE4MDctXHVBODBBXHVBODBDLVx1QTgyMlx1QTg0MC1cdUE4NzNcdUE4ODItXHVBOEIzXHVBOEYyLVx1QThGN1x1QThGQlx1QTkwQS1cdUE5MjVcdUE5MzAtXHVBOTQ2XHVBOTYwLVx1QTk3Q1x1QTk4NC1cdUE5QjJcdUE5Q0ZcdUE5RTAtXHVBOUU0XHVBOUU2LVx1QTlFRlx1QTlGQS1cdUE5RkVcdUFBMDAtXHVBQTI4XHVBQTQwLVx1QUE0Mlx1QUE0NC1cdUFBNEJcdUFBNjAtXHVBQTc2XHVBQTdBXHVBQTdFLVx1QUFBRlx1QUFCMVx1QUFCNVx1QUFCNlx1QUFCOS1cdUFBQkRcdUFBQzBcdUFBQzJcdUFBREItXHVBQUREXHVBQUUwLVx1QUFFQVx1QUFGMi1cdUFBRjRcdUFCMDEtXHVBQjA2XHVBQjA5LVx1QUIwRVx1QUIxMS1cdUFCMTZcdUFCMjAtXHVBQjI2XHVBQjI4LVx1QUIyRVx1QUIzMC1cdUFCNUFcdUFCNUMtXHVBQjVGXHVBQjY0XHVBQjY1XHVBQkMwLVx1QUJFMlx1QUMwMC1cdUQ3QTNcdUQ3QjAtXHVEN0M2XHVEN0NCLVx1RDdGQlx1RjkwMC1cdUZBNkRcdUZBNzAtXHVGQUQ5XHVGQjAwLVx1RkIwNlx1RkIxMy1cdUZCMTdcdUZCMURcdUZCMUYtXHVGQjI4XHVGQjJBLVx1RkIzNlx1RkIzOC1cdUZCM0NcdUZCM0VcdUZCNDBcdUZCNDFcdUZCNDNcdUZCNDRcdUZCNDYtXHVGQkIxXHVGQkQzLVx1RkQzRFx1RkQ1MC1cdUZEOEZcdUZEOTItXHVGREM3XHVGREYwLVx1RkRGQlx1RkU3MC1cdUZFNzRcdUZFNzYtXHVGRUZDXHVGRjIxLVx1RkYzQVx1RkY0MS1cdUZGNUFcdUZGNjYtXHVGRkJFXHVGRkMyLVx1RkZDN1x1RkZDQS1cdUZGQ0ZcdUZGRDItXHVGRkQ3XHVGRkRBLVx1RkZEQ10vLE5vbkFzY2lpSWRlbnRpZmllclBhcnQ6L1tceEFBXHhCNVx4QkFceEMwLVx4RDZceEQ4LVx4RjZceEY4LVx1MDJDMVx1MDJDNi1cdTAyRDFcdTAyRTAtXHUwMkU0XHUwMkVDXHUwMkVFXHUwMzAwLVx1MDM3NFx1MDM3Nlx1MDM3N1x1MDM3QS1cdTAzN0RcdTAzN0ZcdTAzODZcdTAzODgtXHUwMzhBXHUwMzhDXHUwMzhFLVx1MDNBMVx1MDNBMy1cdTAzRjVcdTAzRjctXHUwNDgxXHUwNDgzLVx1MDQ4N1x1MDQ4QS1cdTA1MkZcdTA1MzEtXHUwNTU2XHUwNTU5XHUwNTYxLVx1MDU4N1x1MDU5MS1cdTA1QkRcdTA1QkZcdTA1QzFcdTA1QzJcdTA1QzRcdTA1QzVcdTA1QzdcdTA1RDAtXHUwNUVBXHUwNUYwLVx1MDVGMlx1MDYxMC1cdTA2MUFcdTA2MjAtXHUwNjY5XHUwNjZFLVx1MDZEM1x1MDZENS1cdTA2RENcdTA2REYtXHUwNkU4XHUwNkVBLVx1MDZGQ1x1MDZGRlx1MDcxMC1cdTA3NEFcdTA3NEQtXHUwN0IxXHUwN0MwLVx1MDdGNVx1MDdGQVx1MDgwMC1cdTA4MkRcdTA4NDAtXHUwODVCXHUwOEEwLVx1MDhCMlx1MDhFNC1cdTA5NjNcdTA5NjYtXHUwOTZGXHUwOTcxLVx1MDk4M1x1MDk4NS1cdTA5OENcdTA5OEZcdTA5OTBcdTA5OTMtXHUwOUE4XHUwOUFBLVx1MDlCMFx1MDlCMlx1MDlCNi1cdTA5QjlcdTA5QkMtXHUwOUM0XHUwOUM3XHUwOUM4XHUwOUNCLVx1MDlDRVx1MDlEN1x1MDlEQ1x1MDlERFx1MDlERi1cdTA5RTNcdTA5RTYtXHUwOUYxXHUwQTAxLVx1MEEwM1x1MEEwNS1cdTBBMEFcdTBBMEZcdTBBMTBcdTBBMTMtXHUwQTI4XHUwQTJBLVx1MEEzMFx1MEEzMlx1MEEzM1x1MEEzNVx1MEEzNlx1MEEzOFx1MEEzOVx1MEEzQ1x1MEEzRS1cdTBBNDJcdTBBNDdcdTBBNDhcdTBBNEItXHUwQTREXHUwQTUxXHUwQTU5LVx1MEE1Q1x1MEE1RVx1MEE2Ni1cdTBBNzVcdTBBODEtXHUwQTgzXHUwQTg1LVx1MEE4RFx1MEE4Ri1cdTBBOTFcdTBBOTMtXHUwQUE4XHUwQUFBLVx1MEFCMFx1MEFCMlx1MEFCM1x1MEFCNS1cdTBBQjlcdTBBQkMtXHUwQUM1XHUwQUM3LVx1MEFDOVx1MEFDQi1cdTBBQ0RcdTBBRDBcdTBBRTAtXHUwQUUzXHUwQUU2LVx1MEFFRlx1MEIwMS1cdTBCMDNcdTBCMDUtXHUwQjBDXHUwQjBGXHUwQjEwXHUwQjEzLVx1MEIyOFx1MEIyQS1cdTBCMzBcdTBCMzJcdTBCMzNcdTBCMzUtXHUwQjM5XHUwQjNDLVx1MEI0NFx1MEI0N1x1MEI0OFx1MEI0Qi1cdTBCNERcdTBCNTZcdTBCNTdcdTBCNUNcdTBCNURcdTBCNUYtXHUwQjYzXHUwQjY2LVx1MEI2Rlx1MEI3MVx1MEI4Mlx1MEI4M1x1MEI4NS1cdTBCOEFcdTBCOEUtXHUwQjkwXHUwQjkyLVx1MEI5NVx1MEI5OVx1MEI5QVx1MEI5Q1x1MEI5RVx1MEI5Rlx1MEJBM1x1MEJBNFx1MEJBOC1cdTBCQUFcdTBCQUUtXHUwQkI5XHUwQkJFLVx1MEJDMlx1MEJDNi1cdTBCQzhcdTBCQ0EtXHUwQkNEXHUwQkQwXHUwQkQ3XHUwQkU2LVx1MEJFRlx1MEMwMC1cdTBDMDNcdTBDMDUtXHUwQzBDXHUwQzBFLVx1MEMxMFx1MEMxMi1cdTBDMjhcdTBDMkEtXHUwQzM5XHUwQzNELVx1MEM0NFx1MEM0Ni1cdTBDNDhcdTBDNEEtXHUwQzREXHUwQzU1XHUwQzU2XHUwQzU4XHUwQzU5XHUwQzYwLVx1MEM2M1x1MEM2Ni1cdTBDNkZcdTBDODEtXHUwQzgzXHUwQzg1LVx1MEM4Q1x1MEM4RS1cdTBDOTBcdTBDOTItXHUwQ0E4XHUwQ0FBLVx1MENCM1x1MENCNS1cdTBDQjlcdTBDQkMtXHUwQ0M0XHUwQ0M2LVx1MENDOFx1MENDQS1cdTBDQ0RcdTBDRDVcdTBDRDZcdTBDREVcdTBDRTAtXHUwQ0UzXHUwQ0U2LVx1MENFRlx1MENGMVx1MENGMlx1MEQwMS1cdTBEMDNcdTBEMDUtXHUwRDBDXHUwRDBFLVx1MEQxMFx1MEQxMi1cdTBEM0FcdTBEM0QtXHUwRDQ0XHUwRDQ2LVx1MEQ0OFx1MEQ0QS1cdTBENEVcdTBENTdcdTBENjAtXHUwRDYzXHUwRDY2LVx1MEQ2Rlx1MEQ3QS1cdTBEN0ZcdTBEODJcdTBEODNcdTBEODUtXHUwRDk2XHUwRDlBLVx1MERCMVx1MERCMy1cdTBEQkJcdTBEQkRcdTBEQzAtXHUwREM2XHUwRENBXHUwRENGLVx1MERENFx1MERENlx1MEREOC1cdTBEREZcdTBERTYtXHUwREVGXHUwREYyXHUwREYzXHUwRTAxLVx1MEUzQVx1MEU0MC1cdTBFNEVcdTBFNTAtXHUwRTU5XHUwRTgxXHUwRTgyXHUwRTg0XHUwRTg3XHUwRTg4XHUwRThBXHUwRThEXHUwRTk0LVx1MEU5N1x1MEU5OS1cdTBFOUZcdTBFQTEtXHUwRUEzXHUwRUE1XHUwRUE3XHUwRUFBXHUwRUFCXHUwRUFELVx1MEVCOVx1MEVCQi1cdTBFQkRcdTBFQzAtXHUwRUM0XHUwRUM2XHUwRUM4LVx1MEVDRFx1MEVEMC1cdTBFRDlcdTBFREMtXHUwRURGXHUwRjAwXHUwRjE4XHUwRjE5XHUwRjIwLVx1MEYyOVx1MEYzNVx1MEYzN1x1MEYzOVx1MEYzRS1cdTBGNDdcdTBGNDktXHUwRjZDXHUwRjcxLVx1MEY4NFx1MEY4Ni1cdTBGOTdcdTBGOTktXHUwRkJDXHUwRkM2XHUxMDAwLVx1MTA0OVx1MTA1MC1cdTEwOURcdTEwQTAtXHUxMEM1XHUxMEM3XHUxMENEXHUxMEQwLVx1MTBGQVx1MTBGQy1cdTEyNDhcdTEyNEEtXHUxMjREXHUxMjUwLVx1MTI1Nlx1MTI1OFx1MTI1QS1cdTEyNURcdTEyNjAtXHUxMjg4XHUxMjhBLVx1MTI4RFx1MTI5MC1cdTEyQjBcdTEyQjItXHUxMkI1XHUxMkI4LVx1MTJCRVx1MTJDMFx1MTJDMi1cdTEyQzVcdTEyQzgtXHUxMkQ2XHUxMkQ4LVx1MTMxMFx1MTMxMi1cdTEzMTVcdTEzMTgtXHUxMzVBXHUxMzVELVx1MTM1Rlx1MTM4MC1cdTEzOEZcdTEzQTAtXHUxM0Y0XHUxNDAxLVx1MTY2Q1x1MTY2Ri1cdTE2N0ZcdTE2ODEtXHUxNjlBXHUxNkEwLVx1MTZFQVx1MTZFRS1cdTE2RjhcdTE3MDAtXHUxNzBDXHUxNzBFLVx1MTcxNFx1MTcyMC1cdTE3MzRcdTE3NDAtXHUxNzUzXHUxNzYwLVx1MTc2Q1x1MTc2RS1cdTE3NzBcdTE3NzJcdTE3NzNcdTE3ODAtXHUxN0QzXHUxN0Q3XHUxN0RDXHUxN0REXHUxN0UwLVx1MTdFOVx1MTgwQi1cdTE4MERcdTE4MTAtXHUxODE5XHUxODIwLVx1MTg3N1x1MTg4MC1cdTE4QUFcdTE4QjAtXHUxOEY1XHUxOTAwLVx1MTkxRVx1MTkyMC1cdTE5MkJcdTE5MzAtXHUxOTNCXHUxOTQ2LVx1MTk2RFx1MTk3MC1cdTE5NzRcdTE5ODAtXHUxOUFCXHUxOUIwLVx1MTlDOVx1MTlEMC1cdTE5RDlcdTFBMDAtXHUxQTFCXHUxQTIwLVx1MUE1RVx1MUE2MC1cdTFBN0NcdTFBN0YtXHUxQTg5XHUxQTkwLVx1MUE5OVx1MUFBN1x1MUFCMC1cdTFBQkRcdTFCMDAtXHUxQjRCXHUxQjUwLVx1MUI1OVx1MUI2Qi1cdTFCNzNcdTFCODAtXHUxQkYzXHUxQzAwLVx1MUMzN1x1MUM0MC1cdTFDNDlcdTFDNEQtXHUxQzdEXHUxQ0QwLVx1MUNEMlx1MUNENC1cdTFDRjZcdTFDRjhcdTFDRjlcdTFEMDAtXHUxREY1XHUxREZDLVx1MUYxNVx1MUYxOC1cdTFGMURcdTFGMjAtXHUxRjQ1XHUxRjQ4LVx1MUY0RFx1MUY1MC1cdTFGNTdcdTFGNTlcdTFGNUJcdTFGNURcdTFGNUYtXHUxRjdEXHUxRjgwLVx1MUZCNFx1MUZCNi1cdTFGQkNcdTFGQkVcdTFGQzItXHUxRkM0XHUxRkM2LVx1MUZDQ1x1MUZEMC1cdTFGRDNcdTFGRDYtXHUxRkRCXHUxRkUwLVx1MUZFQ1x1MUZGMi1cdTFGRjRcdTFGRjYtXHUxRkZDXHUyMDBDXHUyMDBEXHUyMDNGXHUyMDQwXHUyMDU0XHUyMDcxXHUyMDdGXHUyMDkwLVx1MjA5Q1x1MjBEMC1cdTIwRENcdTIwRTFcdTIwRTUtXHUyMEYwXHUyMTAyXHUyMTA3XHUyMTBBLVx1MjExM1x1MjExNVx1MjExOS1cdTIxMURcdTIxMjRcdTIxMjZcdTIxMjhcdTIxMkEtXHUyMTJEXHUyMTJGLVx1MjEzOVx1MjEzQy1cdTIxM0ZcdTIxNDUtXHUyMTQ5XHUyMTRFXHUyMTYwLVx1MjE4OFx1MkMwMC1cdTJDMkVcdTJDMzAtXHUyQzVFXHUyQzYwLVx1MkNFNFx1MkNFQi1cdTJDRjNcdTJEMDAtXHUyRDI1XHUyRDI3XHUyRDJEXHUyRDMwLVx1MkQ2N1x1MkQ2Rlx1MkQ3Ri1cdTJEOTZcdTJEQTAtXHUyREE2XHUyREE4LVx1MkRBRVx1MkRCMC1cdTJEQjZcdTJEQjgtXHUyREJFXHUyREMwLVx1MkRDNlx1MkRDOC1cdTJEQ0VcdTJERDAtXHUyREQ2XHUyREQ4LVx1MkRERVx1MkRFMC1cdTJERkZcdTJFMkZcdTMwMDUtXHUzMDA3XHUzMDIxLVx1MzAyRlx1MzAzMS1cdTMwMzVcdTMwMzgtXHUzMDNDXHUzMDQxLVx1MzA5Nlx1MzA5OVx1MzA5QVx1MzA5RC1cdTMwOUZcdTMwQTEtXHUzMEZBXHUzMEZDLVx1MzBGRlx1MzEwNS1cdTMxMkRcdTMxMzEtXHUzMThFXHUzMUEwLVx1MzFCQVx1MzFGMC1cdTMxRkZcdTM0MDAtXHU0REI1XHU0RTAwLVx1OUZDQ1x1QTAwMC1cdUE0OENcdUE0RDAtXHVBNEZEXHVBNTAwLVx1QTYwQ1x1QTYxMC1cdUE2MkJcdUE2NDAtXHVBNjZGXHVBNjc0LVx1QTY3RFx1QTY3Ri1cdUE2OURcdUE2OUYtXHVBNkYxXHVBNzE3LVx1QTcxRlx1QTcyMi1cdUE3ODhcdUE3OEItXHVBNzhFXHVBNzkwLVx1QTdBRFx1QTdCMFx1QTdCMVx1QTdGNy1cdUE4MjdcdUE4NDAtXHVBODczXHVBODgwLVx1QThDNFx1QThEMC1cdUE4RDlcdUE4RTAtXHVBOEY3XHVBOEZCXHVBOTAwLVx1QTkyRFx1QTkzMC1cdUE5NTNcdUE5NjAtXHVBOTdDXHVBOTgwLVx1QTlDMFx1QTlDRi1cdUE5RDlcdUE5RTAtXHVBOUZFXHVBQTAwLVx1QUEzNlx1QUE0MC1cdUFBNERcdUFBNTAtXHVBQTU5XHVBQTYwLVx1QUE3Nlx1QUE3QS1cdUFBQzJcdUFBREItXHVBQUREXHVBQUUwLVx1QUFFRlx1QUFGMi1cdUFBRjZcdUFCMDEtXHVBQjA2XHVBQjA5LVx1QUIwRVx1QUIxMS1cdUFCMTZcdUFCMjAtXHVBQjI2XHVBQjI4LVx1QUIyRVx1QUIzMC1cdUFCNUFcdUFCNUMtXHVBQjVGXHVBQjY0XHVBQjY1XHVBQkMwLVx1QUJFQVx1QUJFQ1x1QUJFRFx1QUJGMC1cdUFCRjlcdUFDMDAtXHVEN0EzXHVEN0IwLVx1RDdDNlx1RDdDQi1cdUQ3RkJcdUY5MDAtXHVGQTZEXHVGQTcwLVx1RkFEOVx1RkIwMC1cdUZCMDZcdUZCMTMtXHVGQjE3XHVGQjFELVx1RkIyOFx1RkIyQS1cdUZCMzZcdUZCMzgtXHVGQjNDXHVGQjNFXHVGQjQwXHVGQjQxXHVGQjQzXHVGQjQ0XHVGQjQ2LVx1RkJCMVx1RkJEMy1cdUZEM0RcdUZENTAtXHVGRDhGXHVGRDkyLVx1RkRDN1x1RkRGMC1cdUZERkJcdUZFMDAtXHVGRTBGXHVGRTIwLVx1RkUyRFx1RkUzM1x1RkUzNFx1RkU0RC1cdUZFNEZcdUZFNzAtXHVGRTc0XHVGRTc2LVx1RkVGQ1x1RkYxMC1cdUZGMTlcdUZGMjEtXHVGRjNBXHVGRjNGXHVGRjQxLVx1RkY1QVx1RkY2Ni1cdUZGQkVcdUZGQzItXHVGRkM3XHVGRkNBLVx1RkZDRlx1RkZEMi1cdUZGRDdcdUZGREEtXHVGRkRDXS99LHA9e05vbkFzY2lpSWRlbnRpZmllclN0YXJ0Oi9bXHhBQVx4QjVceEJBXHhDMC1ceEQ2XHhEOC1ceEY2XHhGOC1cdTAyQzFcdTAyQzYtXHUwMkQxXHUwMkUwLVx1MDJFNFx1MDJFQ1x1MDJFRVx1MDM3MC1cdTAzNzRcdTAzNzZcdTAzNzdcdTAzN0EtXHUwMzdEXHUwMzdGXHUwMzg2XHUwMzg4LVx1MDM4QVx1MDM4Q1x1MDM4RS1cdTAzQTFcdTAzQTMtXHUwM0Y1XHUwM0Y3LVx1MDQ4MVx1MDQ4QS1cdTA1MkZcdTA1MzEtXHUwNTU2XHUwNTU5XHUwNTYxLVx1MDU4N1x1MDVEMC1cdTA1RUFcdTA1RjAtXHUwNUYyXHUwNjIwLVx1MDY0QVx1MDY2RVx1MDY2Rlx1MDY3MS1cdTA2RDNcdTA2RDVcdTA2RTVcdTA2RTZcdTA2RUVcdTA2RUZcdTA2RkEtXHUwNkZDXHUwNkZGXHUwNzEwXHUwNzEyLVx1MDcyRlx1MDc0RC1cdTA3QTVcdTA3QjFcdTA3Q0EtXHUwN0VBXHUwN0Y0XHUwN0Y1XHUwN0ZBXHUwODAwLVx1MDgxNVx1MDgxQVx1MDgyNFx1MDgyOFx1MDg0MC1cdTA4NThcdTA4QTAtXHUwOEIyXHUwOTA0LVx1MDkzOVx1MDkzRFx1MDk1MFx1MDk1OC1cdTA5NjFcdTA5NzEtXHUwOTgwXHUwOTg1LVx1MDk4Q1x1MDk4Rlx1MDk5MFx1MDk5My1cdTA5QThcdTA5QUEtXHUwOUIwXHUwOUIyXHUwOUI2LVx1MDlCOVx1MDlCRFx1MDlDRVx1MDlEQ1x1MDlERFx1MDlERi1cdTA5RTFcdTA5RjBcdTA5RjFcdTBBMDUtXHUwQTBBXHUwQTBGXHUwQTEwXHUwQTEzLVx1MEEyOFx1MEEyQS1cdTBBMzBcdTBBMzJcdTBBMzNcdTBBMzVcdTBBMzZcdTBBMzhcdTBBMzlcdTBBNTktXHUwQTVDXHUwQTVFXHUwQTcyLVx1MEE3NFx1MEE4NS1cdTBBOERcdTBBOEYtXHUwQTkxXHUwQTkzLVx1MEFBOFx1MEFBQS1cdTBBQjBcdTBBQjJcdTBBQjNcdTBBQjUtXHUwQUI5XHUwQUJEXHUwQUQwXHUwQUUwXHUwQUUxXHUwQjA1LVx1MEIwQ1x1MEIwRlx1MEIxMFx1MEIxMy1cdTBCMjhcdTBCMkEtXHUwQjMwXHUwQjMyXHUwQjMzXHUwQjM1LVx1MEIzOVx1MEIzRFx1MEI1Q1x1MEI1RFx1MEI1Ri1cdTBCNjFcdTBCNzFcdTBCODNcdTBCODUtXHUwQjhBXHUwQjhFLVx1MEI5MFx1MEI5Mi1cdTBCOTVcdTBCOTlcdTBCOUFcdTBCOUNcdTBCOUVcdTBCOUZcdTBCQTNcdTBCQTRcdTBCQTgtXHUwQkFBXHUwQkFFLVx1MEJCOVx1MEJEMFx1MEMwNS1cdTBDMENcdTBDMEUtXHUwQzEwXHUwQzEyLVx1MEMyOFx1MEMyQS1cdTBDMzlcdTBDM0RcdTBDNThcdTBDNTlcdTBDNjBcdTBDNjFcdTBDODUtXHUwQzhDXHUwQzhFLVx1MEM5MFx1MEM5Mi1cdTBDQThcdTBDQUEtXHUwQ0IzXHUwQ0I1LVx1MENCOVx1MENCRFx1MENERVx1MENFMFx1MENFMVx1MENGMVx1MENGMlx1MEQwNS1cdTBEMENcdTBEMEUtXHUwRDEwXHUwRDEyLVx1MEQzQVx1MEQzRFx1MEQ0RVx1MEQ2MFx1MEQ2MVx1MEQ3QS1cdTBEN0ZcdTBEODUtXHUwRDk2XHUwRDlBLVx1MERCMVx1MERCMy1cdTBEQkJcdTBEQkRcdTBEQzAtXHUwREM2XHUwRTAxLVx1MEUzMFx1MEUzMlx1MEUzM1x1MEU0MC1cdTBFNDZcdTBFODFcdTBFODJcdTBFODRcdTBFODdcdTBFODhcdTBFOEFcdTBFOERcdTBFOTQtXHUwRTk3XHUwRTk5LVx1MEU5Rlx1MEVBMS1cdTBFQTNcdTBFQTVcdTBFQTdcdTBFQUFcdTBFQUJcdTBFQUQtXHUwRUIwXHUwRUIyXHUwRUIzXHUwRUJEXHUwRUMwLVx1MEVDNFx1MEVDNlx1MEVEQy1cdTBFREZcdTBGMDBcdTBGNDAtXHUwRjQ3XHUwRjQ5LVx1MEY2Q1x1MEY4OC1cdTBGOENcdTEwMDAtXHUxMDJBXHUxMDNGXHUxMDUwLVx1MTA1NVx1MTA1QS1cdTEwNURcdTEwNjFcdTEwNjVcdTEwNjZcdTEwNkUtXHUxMDcwXHUxMDc1LVx1MTA4MVx1MTA4RVx1MTBBMC1cdTEwQzVcdTEwQzdcdTEwQ0RcdTEwRDAtXHUxMEZBXHUxMEZDLVx1MTI0OFx1MTI0QS1cdTEyNERcdTEyNTAtXHUxMjU2XHUxMjU4XHUxMjVBLVx1MTI1RFx1MTI2MC1cdTEyODhcdTEyOEEtXHUxMjhEXHUxMjkwLVx1MTJCMFx1MTJCMi1cdTEyQjVcdTEyQjgtXHUxMkJFXHUxMkMwXHUxMkMyLVx1MTJDNVx1MTJDOC1cdTEyRDZcdTEyRDgtXHUxMzEwXHUxMzEyLVx1MTMxNVx1MTMxOC1cdTEzNUFcdTEzODAtXHUxMzhGXHUxM0EwLVx1MTNGNFx1MTQwMS1cdTE2NkNcdTE2NkYtXHUxNjdGXHUxNjgxLVx1MTY5QVx1MTZBMC1cdTE2RUFcdTE2RUUtXHUxNkY4XHUxNzAwLVx1MTcwQ1x1MTcwRS1cdTE3MTFcdTE3MjAtXHUxNzMxXHUxNzQwLVx1MTc1MVx1MTc2MC1cdTE3NkNcdTE3NkUtXHUxNzcwXHUxNzgwLVx1MTdCM1x1MTdEN1x1MTdEQ1x1MTgyMC1cdTE4NzdcdTE4ODAtXHUxOEE4XHUxOEFBXHUxOEIwLVx1MThGNVx1MTkwMC1cdTE5MUVcdTE5NTAtXHUxOTZEXHUxOTcwLVx1MTk3NFx1MTk4MC1cdTE5QUJcdTE5QzEtXHUxOUM3XHUxQTAwLVx1MUExNlx1MUEyMC1cdTFBNTRcdTFBQTdcdTFCMDUtXHUxQjMzXHUxQjQ1LVx1MUI0Qlx1MUI4My1cdTFCQTBcdTFCQUVcdTFCQUZcdTFCQkEtXHUxQkU1XHUxQzAwLVx1MUMyM1x1MUM0RC1cdTFDNEZcdTFDNUEtXHUxQzdEXHUxQ0U5LVx1MUNFQ1x1MUNFRS1cdTFDRjFcdTFDRjVcdTFDRjZcdTFEMDAtXHUxREJGXHUxRTAwLVx1MUYxNVx1MUYxOC1cdTFGMURcdTFGMjAtXHUxRjQ1XHUxRjQ4LVx1MUY0RFx1MUY1MC1cdTFGNTdcdTFGNTlcdTFGNUJcdTFGNURcdTFGNUYtXHUxRjdEXHUxRjgwLVx1MUZCNFx1MUZCNi1cdTFGQkNcdTFGQkVcdTFGQzItXHUxRkM0XHUxRkM2LVx1MUZDQ1x1MUZEMC1cdTFGRDNcdTFGRDYtXHUxRkRCXHUxRkUwLVx1MUZFQ1x1MUZGMi1cdTFGRjRcdTFGRjYtXHUxRkZDXHUyMDcxXHUyMDdGXHUyMDkwLVx1MjA5Q1x1MjEwMlx1MjEwN1x1MjEwQS1cdTIxMTNcdTIxMTVcdTIxMTgtXHUyMTFEXHUyMTI0XHUyMTI2XHUyMTI4XHUyMTJBLVx1MjEzOVx1MjEzQy1cdTIxM0ZcdTIxNDUtXHUyMTQ5XHUyMTRFXHUyMTYwLVx1MjE4OFx1MkMwMC1cdTJDMkVcdTJDMzAtXHUyQzVFXHUyQzYwLVx1MkNFNFx1MkNFQi1cdTJDRUVcdTJDRjJcdTJDRjNcdTJEMDAtXHUyRDI1XHUyRDI3XHUyRDJEXHUyRDMwLVx1MkQ2N1x1MkQ2Rlx1MkQ4MC1cdTJEOTZcdTJEQTAtXHUyREE2XHUyREE4LVx1MkRBRVx1MkRCMC1cdTJEQjZcdTJEQjgtXHUyREJFXHUyREMwLVx1MkRDNlx1MkRDOC1cdTJEQ0VcdTJERDAtXHUyREQ2XHUyREQ4LVx1MkRERVx1MzAwNS1cdTMwMDdcdTMwMjEtXHUzMDI5XHUzMDMxLVx1MzAzNVx1MzAzOC1cdTMwM0NcdTMwNDEtXHUzMDk2XHUzMDlCLVx1MzA5Rlx1MzBBMS1cdTMwRkFcdTMwRkMtXHUzMEZGXHUzMTA1LVx1MzEyRFx1MzEzMS1cdTMxOEVcdTMxQTAtXHUzMUJBXHUzMUYwLVx1MzFGRlx1MzQwMC1cdTREQjVcdTRFMDAtXHU5RkNDXHVBMDAwLVx1QTQ4Q1x1QTREMC1cdUE0RkRcdUE1MDAtXHVBNjBDXHVBNjEwLVx1QTYxRlx1QTYyQVx1QTYyQlx1QTY0MC1cdUE2NkVcdUE2N0YtXHVBNjlEXHVBNkEwLVx1QTZFRlx1QTcxNy1cdUE3MUZcdUE3MjItXHVBNzg4XHVBNzhCLVx1QTc4RVx1QTc5MC1cdUE3QURcdUE3QjBcdUE3QjFcdUE3RjctXHVBODAxXHVBODAzLVx1QTgwNVx1QTgwNy1cdUE4MEFcdUE4MEMtXHVBODIyXHVBODQwLVx1QTg3M1x1QTg4Mi1cdUE4QjNcdUE4RjItXHVBOEY3XHVBOEZCXHVBOTBBLVx1QTkyNVx1QTkzMC1cdUE5NDZcdUE5NjAtXHVBOTdDXHVBOTg0LVx1QTlCMlx1QTlDRlx1QTlFMC1cdUE5RTRcdUE5RTYtXHVBOUVGXHVBOUZBLVx1QTlGRVx1QUEwMC1cdUFBMjhcdUFBNDAtXHVBQTQyXHVBQTQ0LVx1QUE0Qlx1QUE2MC1cdUFBNzZcdUFBN0FcdUFBN0UtXHVBQUFGXHVBQUIxXHVBQUI1XHVBQUI2XHVBQUI5LVx1QUFCRFx1QUFDMFx1QUFDMlx1QUFEQi1cdUFBRERcdUFBRTAtXHVBQUVBXHVBQUYyLVx1QUFGNFx1QUIwMS1cdUFCMDZcdUFCMDktXHVBQjBFXHVBQjExLVx1QUIxNlx1QUIyMC1cdUFCMjZcdUFCMjgtXHVBQjJFXHVBQjMwLVx1QUI1QVx1QUI1Qy1cdUFCNUZcdUFCNjRcdUFCNjVcdUFCQzAtXHVBQkUyXHVBQzAwLVx1RDdBM1x1RDdCMC1cdUQ3QzZcdUQ3Q0ItXHVEN0ZCXHVGOTAwLVx1RkE2RFx1RkE3MC1cdUZBRDlcdUZCMDAtXHVGQjA2XHVGQjEzLVx1RkIxN1x1RkIxRFx1RkIxRi1cdUZCMjhcdUZCMkEtXHVGQjM2XHVGQjM4LVx1RkIzQ1x1RkIzRVx1RkI0MFx1RkI0MVx1RkI0M1x1RkI0NFx1RkI0Ni1cdUZCQjFcdUZCRDMtXHVGRDNEXHVGRDUwLVx1RkQ4Rlx1RkQ5Mi1cdUZEQzdcdUZERjAtXHVGREZCXHVGRTcwLVx1RkU3NFx1RkU3Ni1cdUZFRkNcdUZGMjEtXHVGRjNBXHVGRjQxLVx1RkY1QVx1RkY2Ni1cdUZGQkVcdUZGQzItXHVGRkM3XHVGRkNBLVx1RkZDRlx1RkZEMi1cdUZGRDdcdUZGREEtXHVGRkRDXXxcdUQ4MDBbXHVEQzAwLVx1REMwQlx1REMwRC1cdURDMjZcdURDMjgtXHVEQzNBXHVEQzNDXHVEQzNEXHVEQzNGLVx1REM0RFx1REM1MC1cdURDNURcdURDODAtXHVEQ0ZBXHVERDQwLVx1REQ3NFx1REU4MC1cdURFOUNcdURFQTAtXHVERUQwXHVERjAwLVx1REYxRlx1REYzMC1cdURGNEFcdURGNTAtXHVERjc1XHVERjgwLVx1REY5RFx1REZBMC1cdURGQzNcdURGQzgtXHVERkNGXHVERkQxLVx1REZENV18XHVEODAxW1x1REMwMC1cdURDOURcdUREMDAtXHVERDI3XHVERDMwLVx1REQ2M1x1REUwMC1cdURGMzZcdURGNDAtXHVERjU1XHVERjYwLVx1REY2N118XHVEODAyW1x1REMwMC1cdURDMDVcdURDMDhcdURDMEEtXHVEQzM1XHVEQzM3XHVEQzM4XHVEQzNDXHVEQzNGLVx1REM1NVx1REM2MC1cdURDNzZcdURDODAtXHVEQzlFXHVERDAwLVx1REQxNVx1REQyMC1cdUREMzlcdUREODAtXHVEREI3XHVEREJFXHVEREJGXHVERTAwXHVERTEwLVx1REUxM1x1REUxNS1cdURFMTdcdURFMTktXHVERTMzXHVERTYwLVx1REU3Q1x1REU4MC1cdURFOUNcdURFQzAtXHVERUM3XHVERUM5LVx1REVFNFx1REYwMC1cdURGMzVcdURGNDAtXHVERjU1XHVERjYwLVx1REY3Mlx1REY4MC1cdURGOTFdfFx1RDgwM1tcdURDMDAtXHVEQzQ4XXxcdUQ4MDRbXHVEQzAzLVx1REMzN1x1REM4My1cdURDQUZcdURDRDAtXHVEQ0U4XHVERDAzLVx1REQyNlx1REQ1MC1cdURENzJcdURENzZcdUREODMtXHVEREIyXHVEREMxLVx1RERDNFx1REREQVx1REUwMC1cdURFMTFcdURFMTMtXHVERTJCXHVERUIwLVx1REVERVx1REYwNS1cdURGMENcdURGMEZcdURGMTBcdURGMTMtXHVERjI4XHVERjJBLVx1REYzMFx1REYzMlx1REYzM1x1REYzNS1cdURGMzlcdURGM0RcdURGNUQtXHVERjYxXXxcdUQ4MDVbXHVEQzgwLVx1RENBRlx1RENDNFx1RENDNVx1RENDN1x1REQ4MC1cdUREQUVcdURFMDAtXHVERTJGXHVERTQ0XHVERTgwLVx1REVBQV18XHVEODA2W1x1RENBMC1cdURDREZcdURDRkZcdURFQzAtXHVERUY4XXxcdUQ4MDhbXHVEQzAwLVx1REY5OF18XHVEODA5W1x1REMwMC1cdURDNkVdfFtcdUQ4MENcdUQ4NDAtXHVEODY4XHVEODZBLVx1RDg2Q11bXHVEQzAwLVx1REZGRl18XHVEODBEW1x1REMwMC1cdURDMkVdfFx1RDgxQVtcdURDMDAtXHVERTM4XHVERTQwLVx1REU1RVx1REVEMC1cdURFRURcdURGMDAtXHVERjJGXHVERjQwLVx1REY0M1x1REY2My1cdURGNzdcdURGN0QtXHVERjhGXXxcdUQ4MUJbXHVERjAwLVx1REY0NFx1REY1MFx1REY5My1cdURGOUZdfFx1RDgyQ1tcdURDMDBcdURDMDFdfFx1RDgyRltcdURDMDAtXHVEQzZBXHVEQzcwLVx1REM3Q1x1REM4MC1cdURDODhcdURDOTAtXHVEQzk5XXxcdUQ4MzVbXHVEQzAwLVx1REM1NFx1REM1Ni1cdURDOUNcdURDOUVcdURDOUZcdURDQTJcdURDQTVcdURDQTZcdURDQTktXHVEQ0FDXHVEQ0FFLVx1RENCOVx1RENCQlx1RENCRC1cdURDQzNcdURDQzUtXHVERDA1XHVERDA3LVx1REQwQVx1REQwRC1cdUREMTRcdUREMTYtXHVERDFDXHVERDFFLVx1REQzOVx1REQzQi1cdUREM0VcdURENDAtXHVERDQ0XHVERDQ2XHVERDRBLVx1REQ1MFx1REQ1Mi1cdURFQTVcdURFQTgtXHVERUMwXHVERUMyLVx1REVEQVx1REVEQy1cdURFRkFcdURFRkMtXHVERjE0XHVERjE2LVx1REYzNFx1REYzNi1cdURGNEVcdURGNTAtXHVERjZFXHVERjcwLVx1REY4OFx1REY4QS1cdURGQThcdURGQUEtXHVERkMyXHVERkM0LVx1REZDQl18XHVEODNBW1x1REMwMC1cdURDQzRdfFx1RDgzQltcdURFMDAtXHVERTAzXHVERTA1LVx1REUxRlx1REUyMVx1REUyMlx1REUyNFx1REUyN1x1REUyOS1cdURFMzJcdURFMzQtXHVERTM3XHVERTM5XHVERTNCXHVERTQyXHVERTQ3XHVERTQ5XHVERTRCXHVERTRELVx1REU0Rlx1REU1MVx1REU1Mlx1REU1NFx1REU1N1x1REU1OVx1REU1Qlx1REU1RFx1REU1Rlx1REU2MVx1REU2Mlx1REU2NFx1REU2Ny1cdURFNkFcdURFNkMtXHVERTcyXHVERTc0LVx1REU3N1x1REU3OS1cdURFN0NcdURFN0VcdURFODAtXHVERTg5XHVERThCLVx1REU5Qlx1REVBMS1cdURFQTNcdURFQTUtXHVERUE5XHVERUFCLVx1REVCQl18XHVEODY5W1x1REMwMC1cdURFRDZcdURGMDAtXHVERkZGXXxcdUQ4NkRbXHVEQzAwLVx1REYzNFx1REY0MC1cdURGRkZdfFx1RDg2RVtcdURDMDAtXHVEQzFEXXxcdUQ4N0VbXHVEQzAwLVx1REUxRF0vLE5vbkFzY2lpSWRlbnRpZmllclBhcnQ6L1tceEFBXHhCNVx4QjdceEJBXHhDMC1ceEQ2XHhEOC1ceEY2XHhGOC1cdTAyQzFcdTAyQzYtXHUwMkQxXHUwMkUwLVx1MDJFNFx1MDJFQ1x1MDJFRVx1MDMwMC1cdTAzNzRcdTAzNzZcdTAzNzdcdTAzN0EtXHUwMzdEXHUwMzdGXHUwMzg2LVx1MDM4QVx1MDM4Q1x1MDM4RS1cdTAzQTFcdTAzQTMtXHUwM0Y1XHUwM0Y3LVx1MDQ4MVx1MDQ4My1cdTA0ODdcdTA0OEEtXHUwNTJGXHUwNTMxLVx1MDU1Nlx1MDU1OVx1MDU2MS1cdTA1ODdcdTA1OTEtXHUwNUJEXHUwNUJGXHUwNUMxXHUwNUMyXHUwNUM0XHUwNUM1XHUwNUM3XHUwNUQwLVx1MDVFQVx1MDVGMC1cdTA1RjJcdTA2MTAtXHUwNjFBXHUwNjIwLVx1MDY2OVx1MDY2RS1cdTA2RDNcdTA2RDUtXHUwNkRDXHUwNkRGLVx1MDZFOFx1MDZFQS1cdTA2RkNcdTA2RkZcdTA3MTAtXHUwNzRBXHUwNzRELVx1MDdCMVx1MDdDMC1cdTA3RjVcdTA3RkFcdTA4MDAtXHUwODJEXHUwODQwLVx1MDg1Qlx1MDhBMC1cdTA4QjJcdTA4RTQtXHUwOTYzXHUwOTY2LVx1MDk2Rlx1MDk3MS1cdTA5ODNcdTA5ODUtXHUwOThDXHUwOThGXHUwOTkwXHUwOTkzLVx1MDlBOFx1MDlBQS1cdTA5QjBcdTA5QjJcdTA5QjYtXHUwOUI5XHUwOUJDLVx1MDlDNFx1MDlDN1x1MDlDOFx1MDlDQi1cdTA5Q0VcdTA5RDdcdTA5RENcdTA5RERcdTA5REYtXHUwOUUzXHUwOUU2LVx1MDlGMVx1MEEwMS1cdTBBMDNcdTBBMDUtXHUwQTBBXHUwQTBGXHUwQTEwXHUwQTEzLVx1MEEyOFx1MEEyQS1cdTBBMzBcdTBBMzJcdTBBMzNcdTBBMzVcdTBBMzZcdTBBMzhcdTBBMzlcdTBBM0NcdTBBM0UtXHUwQTQyXHUwQTQ3XHUwQTQ4XHUwQTRCLVx1MEE0RFx1MEE1MVx1MEE1OS1cdTBBNUNcdTBBNUVcdTBBNjYtXHUwQTc1XHUwQTgxLVx1MEE4M1x1MEE4NS1cdTBBOERcdTBBOEYtXHUwQTkxXHUwQTkzLVx1MEFBOFx1MEFBQS1cdTBBQjBcdTBBQjJcdTBBQjNcdTBBQjUtXHUwQUI5XHUwQUJDLVx1MEFDNVx1MEFDNy1cdTBBQzlcdTBBQ0ItXHUwQUNEXHUwQUQwXHUwQUUwLVx1MEFFM1x1MEFFNi1cdTBBRUZcdTBCMDEtXHUwQjAzXHUwQjA1LVx1MEIwQ1x1MEIwRlx1MEIxMFx1MEIxMy1cdTBCMjhcdTBCMkEtXHUwQjMwXHUwQjMyXHUwQjMzXHUwQjM1LVx1MEIzOVx1MEIzQy1cdTBCNDRcdTBCNDdcdTBCNDhcdTBCNEItXHUwQjREXHUwQjU2XHUwQjU3XHUwQjVDXHUwQjVEXHUwQjVGLVx1MEI2M1x1MEI2Ni1cdTBCNkZcdTBCNzFcdTBCODJcdTBCODNcdTBCODUtXHUwQjhBXHUwQjhFLVx1MEI5MFx1MEI5Mi1cdTBCOTVcdTBCOTlcdTBCOUFcdTBCOUNcdTBCOUVcdTBCOUZcdTBCQTNcdTBCQTRcdTBCQTgtXHUwQkFBXHUwQkFFLVx1MEJCOVx1MEJCRS1cdTBCQzJcdTBCQzYtXHUwQkM4XHUwQkNBLVx1MEJDRFx1MEJEMFx1MEJEN1x1MEJFNi1cdTBCRUZcdTBDMDAtXHUwQzAzXHUwQzA1LVx1MEMwQ1x1MEMwRS1cdTBDMTBcdTBDMTItXHUwQzI4XHUwQzJBLVx1MEMzOVx1MEMzRC1cdTBDNDRcdTBDNDYtXHUwQzQ4XHUwQzRBLVx1MEM0RFx1MEM1NVx1MEM1Nlx1MEM1OFx1MEM1OVx1MEM2MC1cdTBDNjNcdTBDNjYtXHUwQzZGXHUwQzgxLVx1MEM4M1x1MEM4NS1cdTBDOENcdTBDOEUtXHUwQzkwXHUwQzkyLVx1MENBOFx1MENBQS1cdTBDQjNcdTBDQjUtXHUwQ0I5XHUwQ0JDLVx1MENDNFx1MENDNi1cdTBDQzhcdTBDQ0EtXHUwQ0NEXHUwQ0Q1XHUwQ0Q2XHUwQ0RFXHUwQ0UwLVx1MENFM1x1MENFNi1cdTBDRUZcdTBDRjFcdTBDRjJcdTBEMDEtXHUwRDAzXHUwRDA1LVx1MEQwQ1x1MEQwRS1cdTBEMTBcdTBEMTItXHUwRDNBXHUwRDNELVx1MEQ0NFx1MEQ0Ni1cdTBENDhcdTBENEEtXHUwRDRFXHUwRDU3XHUwRDYwLVx1MEQ2M1x1MEQ2Ni1cdTBENkZcdTBEN0EtXHUwRDdGXHUwRDgyXHUwRDgzXHUwRDg1LVx1MEQ5Nlx1MEQ5QS1cdTBEQjFcdTBEQjMtXHUwREJCXHUwREJEXHUwREMwLVx1MERDNlx1MERDQVx1MERDRi1cdTBERDRcdTBERDZcdTBERDgtXHUwRERGXHUwREU2LVx1MERFRlx1MERGMlx1MERGM1x1MEUwMS1cdTBFM0FcdTBFNDAtXHUwRTRFXHUwRTUwLVx1MEU1OVx1MEU4MVx1MEU4Mlx1MEU4NFx1MEU4N1x1MEU4OFx1MEU4QVx1MEU4RFx1MEU5NC1cdTBFOTdcdTBFOTktXHUwRTlGXHUwRUExLVx1MEVBM1x1MEVBNVx1MEVBN1x1MEVBQVx1MEVBQlx1MEVBRC1cdTBFQjlcdTBFQkItXHUwRUJEXHUwRUMwLVx1MEVDNFx1MEVDNlx1MEVDOC1cdTBFQ0RcdTBFRDAtXHUwRUQ5XHUwRURDLVx1MEVERlx1MEYwMFx1MEYxOFx1MEYxOVx1MEYyMC1cdTBGMjlcdTBGMzVcdTBGMzdcdTBGMzlcdTBGM0UtXHUwRjQ3XHUwRjQ5LVx1MEY2Q1x1MEY3MS1cdTBGODRcdTBGODYtXHUwRjk3XHUwRjk5LVx1MEZCQ1x1MEZDNlx1MTAwMC1cdTEwNDlcdTEwNTAtXHUxMDlEXHUxMEEwLVx1MTBDNVx1MTBDN1x1MTBDRFx1MTBEMC1cdTEwRkFcdTEwRkMtXHUxMjQ4XHUxMjRBLVx1MTI0RFx1MTI1MC1cdTEyNTZcdTEyNThcdTEyNUEtXHUxMjVEXHUxMjYwLVx1MTI4OFx1MTI4QS1cdTEyOERcdTEyOTAtXHUxMkIwXHUxMkIyLVx1MTJCNVx1MTJCOC1cdTEyQkVcdTEyQzBcdTEyQzItXHUxMkM1XHUxMkM4LVx1MTJENlx1MTJEOC1cdTEzMTBcdTEzMTItXHUxMzE1XHUxMzE4LVx1MTM1QVx1MTM1RC1cdTEzNUZcdTEzNjktXHUxMzcxXHUxMzgwLVx1MTM4Rlx1MTNBMC1cdTEzRjRcdTE0MDEtXHUxNjZDXHUxNjZGLVx1MTY3Rlx1MTY4MS1cdTE2OUFcdTE2QTAtXHUxNkVBXHUxNkVFLVx1MTZGOFx1MTcwMC1cdTE3MENcdTE3MEUtXHUxNzE0XHUxNzIwLVx1MTczNFx1MTc0MC1cdTE3NTNcdTE3NjAtXHUxNzZDXHUxNzZFLVx1MTc3MFx1MTc3Mlx1MTc3M1x1MTc4MC1cdTE3RDNcdTE3RDdcdTE3RENcdTE3RERcdTE3RTAtXHUxN0U5XHUxODBCLVx1MTgwRFx1MTgxMC1cdTE4MTlcdTE4MjAtXHUxODc3XHUxODgwLVx1MThBQVx1MThCMC1cdTE4RjVcdTE5MDAtXHUxOTFFXHUxOTIwLVx1MTkyQlx1MTkzMC1cdTE5M0JcdTE5NDYtXHUxOTZEXHUxOTcwLVx1MTk3NFx1MTk4MC1cdTE5QUJcdTE5QjAtXHUxOUM5XHUxOUQwLVx1MTlEQVx1MUEwMC1cdTFBMUJcdTFBMjAtXHUxQTVFXHUxQTYwLVx1MUE3Q1x1MUE3Ri1cdTFBODlcdTFBOTAtXHUxQTk5XHUxQUE3XHUxQUIwLVx1MUFCRFx1MUIwMC1cdTFCNEJcdTFCNTAtXHUxQjU5XHUxQjZCLVx1MUI3M1x1MUI4MC1cdTFCRjNcdTFDMDAtXHUxQzM3XHUxQzQwLVx1MUM0OVx1MUM0RC1cdTFDN0RcdTFDRDAtXHUxQ0QyXHUxQ0Q0LVx1MUNGNlx1MUNGOFx1MUNGOVx1MUQwMC1cdTFERjVcdTFERkMtXHUxRjE1XHUxRjE4LVx1MUYxRFx1MUYyMC1cdTFGNDVcdTFGNDgtXHUxRjREXHUxRjUwLVx1MUY1N1x1MUY1OVx1MUY1Qlx1MUY1RFx1MUY1Ri1cdTFGN0RcdTFGODAtXHUxRkI0XHUxRkI2LVx1MUZCQ1x1MUZCRVx1MUZDMi1cdTFGQzRcdTFGQzYtXHUxRkNDXHUxRkQwLVx1MUZEM1x1MUZENi1cdTFGREJcdTFGRTAtXHUxRkVDXHUxRkYyLVx1MUZGNFx1MUZGNi1cdTFGRkNcdTIwMENcdTIwMERcdTIwM0ZcdTIwNDBcdTIwNTRcdTIwNzFcdTIwN0ZcdTIwOTAtXHUyMDlDXHUyMEQwLVx1MjBEQ1x1MjBFMVx1MjBFNS1cdTIwRjBcdTIxMDJcdTIxMDdcdTIxMEEtXHUyMTEzXHUyMTE1XHUyMTE4LVx1MjExRFx1MjEyNFx1MjEyNlx1MjEyOFx1MjEyQS1cdTIxMzlcdTIxM0MtXHUyMTNGXHUyMTQ1LVx1MjE0OVx1MjE0RVx1MjE2MC1cdTIxODhcdTJDMDAtXHUyQzJFXHUyQzMwLVx1MkM1RVx1MkM2MC1cdTJDRTRcdTJDRUItXHUyQ0YzXHUyRDAwLVx1MkQyNVx1MkQyN1x1MkQyRFx1MkQzMC1cdTJENjdcdTJENkZcdTJEN0YtXHUyRDk2XHUyREEwLVx1MkRBNlx1MkRBOC1cdTJEQUVcdTJEQjAtXHUyREI2XHUyREI4LVx1MkRCRVx1MkRDMC1cdTJEQzZcdTJEQzgtXHUyRENFXHUyREQwLVx1MkRENlx1MkREOC1cdTJEREVcdTJERTAtXHUyREZGXHUzMDA1LVx1MzAwN1x1MzAyMS1cdTMwMkZcdTMwMzEtXHUzMDM1XHUzMDM4LVx1MzAzQ1x1MzA0MS1cdTMwOTZcdTMwOTktXHUzMDlGXHUzMEExLVx1MzBGQVx1MzBGQy1cdTMwRkZcdTMxMDUtXHUzMTJEXHUzMTMxLVx1MzE4RVx1MzFBMC1cdTMxQkFcdTMxRjAtXHUzMUZGXHUzNDAwLVx1NERCNVx1NEUwMC1cdTlGQ0NcdUEwMDAtXHVBNDhDXHVBNEQwLVx1QTRGRFx1QTUwMC1cdUE2MENcdUE2MTAtXHVBNjJCXHVBNjQwLVx1QTY2Rlx1QTY3NC1cdUE2N0RcdUE2N0YtXHVBNjlEXHVBNjlGLVx1QTZGMVx1QTcxNy1cdUE3MUZcdUE3MjItXHVBNzg4XHVBNzhCLVx1QTc4RVx1QTc5MC1cdUE3QURcdUE3QjBcdUE3QjFcdUE3RjctXHVBODI3XHVBODQwLVx1QTg3M1x1QTg4MC1cdUE4QzRcdUE4RDAtXHVBOEQ5XHVBOEUwLVx1QThGN1x1QThGQlx1QTkwMC1cdUE5MkRcdUE5MzAtXHVBOTUzXHVBOTYwLVx1QTk3Q1x1QTk4MC1cdUE5QzBcdUE5Q0YtXHVBOUQ5XHVBOUUwLVx1QTlGRVx1QUEwMC1cdUFBMzZcdUFBNDAtXHVBQTREXHVBQTUwLVx1QUE1OVx1QUE2MC1cdUFBNzZcdUFBN0EtXHVBQUMyXHVBQURCLVx1QUFERFx1QUFFMC1cdUFBRUZcdUFBRjItXHVBQUY2XHVBQjAxLVx1QUIwNlx1QUIwOS1cdUFCMEVcdUFCMTEtXHVBQjE2XHVBQjIwLVx1QUIyNlx1QUIyOC1cdUFCMkVcdUFCMzAtXHVBQjVBXHVBQjVDLVx1QUI1Rlx1QUI2NFx1QUI2NVx1QUJDMC1cdUFCRUFcdUFCRUNcdUFCRURcdUFCRjAtXHVBQkY5XHVBQzAwLVx1RDdBM1x1RDdCMC1cdUQ3QzZcdUQ3Q0ItXHVEN0ZCXHVGOTAwLVx1RkE2RFx1RkE3MC1cdUZBRDlcdUZCMDAtXHVGQjA2XHVGQjEzLVx1RkIxN1x1RkIxRC1cdUZCMjhcdUZCMkEtXHVGQjM2XHVGQjM4LVx1RkIzQ1x1RkIzRVx1RkI0MFx1RkI0MVx1RkI0M1x1RkI0NFx1RkI0Ni1cdUZCQjFcdUZCRDMtXHVGRDNEXHVGRDUwLVx1RkQ4Rlx1RkQ5Mi1cdUZEQzdcdUZERjAtXHVGREZCXHVGRTAwLVx1RkUwRlx1RkUyMC1cdUZFMkRcdUZFMzNcdUZFMzRcdUZFNEQtXHVGRTRGXHVGRTcwLVx1RkU3NFx1RkU3Ni1cdUZFRkNcdUZGMTAtXHVGRjE5XHVGRjIxLVx1RkYzQVx1RkYzRlx1RkY0MS1cdUZGNUFcdUZGNjYtXHVGRkJFXHVGRkMyLVx1RkZDN1x1RkZDQS1cdUZGQ0ZcdUZGRDItXHVGRkQ3XHVGRkRBLVx1RkZEQ118XHVEODAwW1x1REMwMC1cdURDMEJcdURDMEQtXHVEQzI2XHVEQzI4LVx1REMzQVx1REMzQ1x1REMzRFx1REMzRi1cdURDNERcdURDNTAtXHVEQzVEXHVEQzgwLVx1RENGQVx1REQ0MC1cdURENzRcdURERkRcdURFODAtXHVERTlDXHVERUEwLVx1REVEMFx1REVFMFx1REYwMC1cdURGMUZcdURGMzAtXHVERjRBXHVERjUwLVx1REY3QVx1REY4MC1cdURGOURcdURGQTAtXHVERkMzXHVERkM4LVx1REZDRlx1REZEMS1cdURGRDVdfFx1RDgwMVtcdURDMDAtXHVEQzlEXHVEQ0EwLVx1RENBOVx1REQwMC1cdUREMjdcdUREMzAtXHVERDYzXHVERTAwLVx1REYzNlx1REY0MC1cdURGNTVcdURGNjAtXHVERjY3XXxcdUQ4MDJbXHVEQzAwLVx1REMwNVx1REMwOFx1REMwQS1cdURDMzVcdURDMzdcdURDMzhcdURDM0NcdURDM0YtXHVEQzU1XHVEQzYwLVx1REM3Nlx1REM4MC1cdURDOUVcdUREMDAtXHVERDE1XHVERDIwLVx1REQzOVx1REQ4MC1cdUREQjdcdUREQkVcdUREQkZcdURFMDAtXHVERTAzXHVERTA1XHVERTA2XHVERTBDLVx1REUxM1x1REUxNS1cdURFMTdcdURFMTktXHVERTMzXHVERTM4LVx1REUzQVx1REUzRlx1REU2MC1cdURFN0NcdURFODAtXHVERTlDXHVERUMwLVx1REVDN1x1REVDOS1cdURFRTZcdURGMDAtXHVERjM1XHVERjQwLVx1REY1NVx1REY2MC1cdURGNzJcdURGODAtXHVERjkxXXxcdUQ4MDNbXHVEQzAwLVx1REM0OF18XHVEODA0W1x1REMwMC1cdURDNDZcdURDNjYtXHVEQzZGXHVEQzdGLVx1RENCQVx1RENEMC1cdURDRThcdURDRjAtXHVEQ0Y5XHVERDAwLVx1REQzNFx1REQzNi1cdUREM0ZcdURENTAtXHVERDczXHVERDc2XHVERDgwLVx1RERDNFx1REREMC1cdUREREFcdURFMDAtXHVERTExXHVERTEzLVx1REUzN1x1REVCMC1cdURFRUFcdURFRjAtXHVERUY5XHVERjAxLVx1REYwM1x1REYwNS1cdURGMENcdURGMEZcdURGMTBcdURGMTMtXHVERjI4XHVERjJBLVx1REYzMFx1REYzMlx1REYzM1x1REYzNS1cdURGMzlcdURGM0MtXHVERjQ0XHVERjQ3XHVERjQ4XHVERjRCLVx1REY0RFx1REY1N1x1REY1RC1cdURGNjNcdURGNjYtXHVERjZDXHVERjcwLVx1REY3NF18XHVEODA1W1x1REM4MC1cdURDQzVcdURDQzdcdURDRDAtXHVEQ0Q5XHVERDgwLVx1RERCNVx1RERCOC1cdUREQzBcdURFMDAtXHVERTQwXHVERTQ0XHVERTUwLVx1REU1OVx1REU4MC1cdURFQjdcdURFQzAtXHVERUM5XXxcdUQ4MDZbXHVEQ0EwLVx1RENFOVx1RENGRlx1REVDMC1cdURFRjhdfFx1RDgwOFtcdURDMDAtXHVERjk4XXxcdUQ4MDlbXHVEQzAwLVx1REM2RV18W1x1RDgwQ1x1RDg0MC1cdUQ4NjhcdUQ4NkEtXHVEODZDXVtcdURDMDAtXHVERkZGXXxcdUQ4MERbXHVEQzAwLVx1REMyRV18XHVEODFBW1x1REMwMC1cdURFMzhcdURFNDAtXHVERTVFXHVERTYwLVx1REU2OVx1REVEMC1cdURFRURcdURFRjAtXHVERUY0XHVERjAwLVx1REYzNlx1REY0MC1cdURGNDNcdURGNTAtXHVERjU5XHVERjYzLVx1REY3N1x1REY3RC1cdURGOEZdfFx1RDgxQltcdURGMDAtXHVERjQ0XHVERjUwLVx1REY3RVx1REY4Ri1cdURGOUZdfFx1RDgyQ1tcdURDMDBcdURDMDFdfFx1RDgyRltcdURDMDAtXHVEQzZBXHVEQzcwLVx1REM3Q1x1REM4MC1cdURDODhcdURDOTAtXHVEQzk5XHVEQzlEXHVEQzlFXXxcdUQ4MzRbXHVERDY1LVx1REQ2OVx1REQ2RC1cdURENzJcdUREN0ItXHVERDgyXHVERDg1LVx1REQ4Qlx1RERBQS1cdUREQURcdURFNDItXHVERTQ0XXxcdUQ4MzVbXHVEQzAwLVx1REM1NFx1REM1Ni1cdURDOUNcdURDOUVcdURDOUZcdURDQTJcdURDQTVcdURDQTZcdURDQTktXHVEQ0FDXHVEQ0FFLVx1RENCOVx1RENCQlx1RENCRC1cdURDQzNcdURDQzUtXHVERDA1XHVERDA3LVx1REQwQVx1REQwRC1cdUREMTRcdUREMTYtXHVERDFDXHVERDFFLVx1REQzOVx1REQzQi1cdUREM0VcdURENDAtXHVERDQ0XHVERDQ2XHVERDRBLVx1REQ1MFx1REQ1Mi1cdURFQTVcdURFQTgtXHVERUMwXHVERUMyLVx1REVEQVx1REVEQy1cdURFRkFcdURFRkMtXHVERjE0XHVERjE2LVx1REYzNFx1REYzNi1cdURGNEVcdURGNTAtXHVERjZFXHVERjcwLVx1REY4OFx1REY4QS1cdURGQThcdURGQUEtXHVERkMyXHVERkM0LVx1REZDQlx1REZDRS1cdURGRkZdfFx1RDgzQVtcdURDMDAtXHVEQ0M0XHVEQ0QwLVx1RENENl18XHVEODNCW1x1REUwMC1cdURFMDNcdURFMDUtXHVERTFGXHVERTIxXHVERTIyXHVERTI0XHVERTI3XHVERTI5LVx1REUzMlx1REUzNC1cdURFMzdcdURFMzlcdURFM0JcdURFNDJcdURFNDdcdURFNDlcdURFNEJcdURFNEQtXHVERTRGXHVERTUxXHVERTUyXHVERTU0XHVERTU3XHVERTU5XHVERTVCXHVERTVEXHVERTVGXHVERTYxXHVERTYyXHVERTY0XHVERTY3LVx1REU2QVx1REU2Qy1cdURFNzJcdURFNzQtXHVERTc3XHVERTc5LVx1REU3Q1x1REU3RVx1REU4MC1cdURFODlcdURFOEItXHVERTlCXHVERUExLVx1REVBM1x1REVBNS1cdURFQTlcdURFQUItXHVERUJCXXxcdUQ4NjlbXHVEQzAwLVx1REVENlx1REYwMC1cdURGRkZdfFx1RDg2RFtcdURDMDAtXHVERjM0XHVERjQwLVx1REZGRl18XHVEODZFW1x1REMwMC1cdURDMURdfFx1RDg3RVtcdURDMDAtXHVERTFEXXxcdURCNDBbXHVERDAwLVx1RERFRl0vfSxkPVs1NzYwLDYxNTgsODE5Miw4MTkzLDgxOTQsODE5NSw4MTk2LDgxOTcsODE5OCw4MTk5LDgyMDAsODIwMSw4MjAyLDgyMzksODI4NywxMjI4OCw2NTI3OV0saD1uZXcgQXJyYXkoMTI4KSxnPTA7ZzwxMjg7KytnKWhbZ109Zz49OTcmJmc8PTEyMnx8Zz49NjUmJmc8PTkwfHwzNj09PWd8fDk1PT09Zztmb3IobT1uZXcgQXJyYXkoMTI4KSxnPTA7ZzwxMjg7KytnKW1bZ109Zz49OTcmJmc8PTEyMnx8Zz49NjUmJmc8PTkwfHxnPj00OCYmZzw9NTd8fDM2PT09Z3x8OTU9PT1nO2UuZXhwb3J0cz17aXNEZWNpbWFsRGlnaXQ6dCxpc0hleERpZ2l0Om4saXNPY3RhbERpZ2l0OnIsaXNXaGl0ZVNwYWNlOmksaXNMaW5lVGVybWluYXRvcjpvLGlzSWRlbnRpZmllclN0YXJ0RVM1OnMsaXNJZGVudGlmaWVyUGFydEVTNTp1LGlzSWRlbnRpZmllclN0YXJ0RVM2OmMsaXNJZGVudGlmaWVyUGFydEVTNjpsfX0oKX0pLGtleXdvcmQ9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSl7IWZ1bmN0aW9uKCl7ZnVuY3Rpb24gdChlKXtzd2l0Y2goZSl7Y2FzZSJpbXBsZW1lbnRzIjpjYXNlImludGVyZmFjZSI6Y2FzZSJwYWNrYWdlIjpjYXNlInByaXZhdGUiOmNhc2UicHJvdGVjdGVkIjpjYXNlInB1YmxpYyI6Y2FzZSJzdGF0aWMiOmNhc2UibGV0IjpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiExfX1mdW5jdGlvbiBuKGUsdCl7cmV0dXJuISghdCYmInlpZWxkIj09PWUpJiZyKGUsdCl9ZnVuY3Rpb24gcihlLG4pe2lmKG4mJnQoZSkpcmV0dXJuITA7c3dpdGNoKGUubGVuZ3RoKXtjYXNlIDI6cmV0dXJuImlmIj09PWV8fCJpbiI9PT1lfHwiZG8iPT09ZTtjYXNlIDM6cmV0dXJuInZhciI9PT1lfHwiZm9yIj09PWV8fCJuZXciPT09ZXx8InRyeSI9PT1lO2Nhc2UgNDpyZXR1cm4idGhpcyI9PT1lfHwiZWxzZSI9PT1lfHwiY2FzZSI9PT1lfHwidm9pZCI9PT1lfHwid2l0aCI9PT1lfHwiZW51bSI9PT1lO2Nhc2UgNTpyZXR1cm4id2hpbGUiPT09ZXx8ImJyZWFrIj09PWV8fCJjYXRjaCI9PT1lfHwidGhyb3ciPT09ZXx8ImNvbnN0Ij09PWV8fCJ5aWVsZCI9PT1lfHwiY2xhc3MiPT09ZXx8InN1cGVyIj09PWU7Y2FzZSA2OnJldHVybiJyZXR1cm4iPT09ZXx8InR5cGVvZiI9PT1lfHwiZGVsZXRlIj09PWV8fCJzd2l0Y2giPT09ZXx8ImV4cG9ydCI9PT1lfHwiaW1wb3J0Ij09PWU7Y2FzZSA3OnJldHVybiJkZWZhdWx0Ij09PWV8fCJmaW5hbGx5Ij09PWV8fCJleHRlbmRzIj09PWU7Y2FzZSA4OnJldHVybiJmdW5jdGlvbiI9PT1lfHwiY29udGludWUiPT09ZXx8ImRlYnVnZ2VyIj09PWU7Y2FzZSAxMDpyZXR1cm4iaW5zdGFuY2VvZiI9PT1lO2RlZmF1bHQ6cmV0dXJuITF9fWZ1bmN0aW9uIGkoZSx0KXtyZXR1cm4ibnVsbCI9PT1lfHwidHJ1ZSI9PT1lfHwiZmFsc2UiPT09ZXx8bihlLHQpfWZ1bmN0aW9uIG8oZSx0KXtyZXR1cm4ibnVsbCI9PT1lfHwidHJ1ZSI9PT1lfHwiZmFsc2UiPT09ZXx8cihlLHQpfWZ1bmN0aW9uIGEoZSl7cmV0dXJuImV2YWwiPT09ZXx8ImFyZ3VtZW50cyI9PT1lfWZ1bmN0aW9uIHMoZSl7dmFyIHQsbixyO2lmKDA9PT1lLmxlbmd0aClyZXR1cm4hMTtpZihyPWUuY2hhckNvZGVBdCgwKSwhZi5pc0lkZW50aWZpZXJTdGFydEVTNShyKSlyZXR1cm4hMTtmb3IodD0xLG49ZS5sZW5ndGg7dDxuOysrdClpZihyPWUuY2hhckNvZGVBdCh0KSwhZi5pc0lkZW50aWZpZXJQYXJ0RVM1KHIpKXJldHVybiExO3JldHVybiEwfWZ1bmN0aW9uIHUoZSx0KXtyZXR1cm4gMTAyNCooZS01NTI5NikrKHQtNTYzMjApKzY1NTM2fWZ1bmN0aW9uIGMoZSl7dmFyIHQsbixyLGksbztpZigwPT09ZS5sZW5ndGgpcmV0dXJuITE7Zm9yKG89Zi5pc0lkZW50aWZpZXJTdGFydEVTNix0PTAsbj1lLmxlbmd0aDt0PG47Kyt0KXtpZig1NTI5Njw9KHI9ZS5jaGFyQ29kZUF0KHQpKSYmcjw9NTYzMTkpe2lmKCsrdD49bilyZXR1cm4hMTtpZighKDU2MzIwPD0oaT1lLmNoYXJDb2RlQXQodCkpJiZpPD01NzM0MykpcmV0dXJuITE7cj11KHIsaSl9aWYoIW8ocikpcmV0dXJuITE7bz1mLmlzSWRlbnRpZmllclBhcnRFUzZ9cmV0dXJuITB9ZnVuY3Rpb24gbChlLHQpe3JldHVybiBzKGUpJiYhaShlLHQpfWZ1bmN0aW9uIHAoZSx0KXtyZXR1cm4gYyhlKSYmIW8oZSx0KX12YXIgZj1jb2RlO2UuZXhwb3J0cz17aXNLZXl3b3JkRVM1Om4saXNLZXl3b3JkRVM2OnIsaXNSZXNlcnZlZFdvcmRFUzU6aSxpc1Jlc2VydmVkV29yZEVTNjpvLGlzUmVzdHJpY3RlZFdvcmQ6YSxpc0lkZW50aWZpZXJOYW1lRVM1OnMsaXNJZGVudGlmaWVyTmFtZUVTNjpjLGlzSWRlbnRpZmllckVTNTpsLGlzSWRlbnRpZmllckVTNjpwfX0oKX0pLHV0aWxzPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUsdCl7IWZ1bmN0aW9uKCl7dC5hc3Q9YXN0LHQuY29kZT1jb2RlLHQua2V5d29yZD1rZXl3b3JkfSgpfSksbWF0Y2hPcGVyYXRvcnNSZT0vW3xcXHt9KClbXF1eJCsqPy5dL2csZXNjYXBlU3RyaW5nUmVnZXhwPWZ1bmN0aW9uKGUpe2lmKCJzdHJpbmciIT09dHlwZW9mIGUpdGhyb3cgbmV3IFR5cGVFcnJvcigiRXhwZWN0ZWQgYSBzdHJpbmciKTtyZXR1cm4gZS5yZXBsYWNlKG1hdGNoT3BlcmF0b3JzUmUsIlxcJCYiKX0sY29sb3JOYW1lPXthbGljZWJsdWU6WzI0MCwyNDgsMjU1XSxhbnRpcXVld2hpdGU6WzI1MCwyMzUsMjE1XSxhcXVhOlswLDI1NSwyNTVdLGFxdWFtYXJpbmU6WzEyNywyNTUsMjEyXSxhenVyZTpbMjQwLDI1NSwyNTVdLGJlaWdlOlsyNDUsMjQ1LDIyMF0sYmlzcXVlOlsyNTUsMjI4LDE5Nl0sYmxhY2s6WzAsMCwwXSxibGFuY2hlZGFsbW9uZDpbMjU1LDIzNSwyMDVdLGJsdWU6WzAsMCwyNTVdLGJsdWV2aW9sZXQ6WzEzOCw0MywyMjZdLGJyb3duOlsxNjUsNDIsNDJdLGJ1cmx5d29vZDpbMjIyLDE4NCwxMzVdLGNhZGV0Ymx1ZTpbOTUsMTU4LDE2MF0sY2hhcnRyZXVzZTpbMTI3LDI1NSwwXSxjaG9jb2xhdGU6WzIxMCwxMDUsMzBdLGNvcmFsOlsyNTUsMTI3LDgwXSxjb3JuZmxvd2VyYmx1ZTpbMTAwLDE0OSwyMzddLGNvcm5zaWxrOlsyNTUsMjQ4LDIyMF0sY3JpbXNvbjpbMjIwLDIwLDYwXSxjeWFuOlswLDI1NSwyNTVdLGRhcmtibHVlOlswLDAsMTM5XSxkYXJrY3lhbjpbMCwxMzksMTM5XSxkYXJrZ29sZGVucm9kOlsxODQsMTM0LDExXSxkYXJrZ3JheTpbMTY5LDE2OSwxNjldLGRhcmtncmVlbjpbMCwxMDAsMF0sZGFya2dyZXk6WzE2OSwxNjksMTY5XSxkYXJra2hha2k6WzE4OSwxODMsMTA3XSxkYXJrbWFnZW50YTpbMTM5LDAsMTM5XSxkYXJrb2xpdmVncmVlbjpbODUsMTA3LDQ3XSxkYXJrb3JhbmdlOlsyNTUsMTQwLDBdLGRhcmtvcmNoaWQ6WzE1Myw1MCwyMDRdLGRhcmtyZWQ6WzEzOSwwLDBdLGRhcmtzYWxtb246WzIzMywxNTAsMTIyXSxkYXJrc2VhZ3JlZW46WzE0MywxODgsMTQzXSxkYXJrc2xhdGVibHVlOls3Miw2MSwxMzldLGRhcmtzbGF0ZWdyYXk6WzQ3LDc5LDc5XSxkYXJrc2xhdGVncmV5Ols0Nyw3OSw3OV0sZGFya3R1cnF1b2lzZTpbMCwyMDYsMjA5XSxkYXJrdmlvbGV0OlsxNDgsMCwyMTFdLGRlZXBwaW5rOlsyNTUsMjAsMTQ3XSxkZWVwc2t5Ymx1ZTpbMCwxOTEsMjU1XSxkaW1ncmF5OlsxMDUsMTA1LDEwNV0sZGltZ3JleTpbMTA1LDEwNSwxMDVdLGRvZGdlcmJsdWU6WzMwLDE0NCwyNTVdLGZpcmVicmljazpbMTc4LDM0LDM0XSxmbG9yYWx3aGl0ZTpbMjU1LDI1MCwyNDBdLGZvcmVzdGdyZWVuOlszNCwxMzksMzRdLGZ1Y2hzaWE6WzI1NSwwLDI1NV0sZ2FpbnNib3JvOlsyMjAsMjIwLDIyMF0sZ2hvc3R3aGl0ZTpbMjQ4LDI0OCwyNTVdLGdvbGQ6WzI1NSwyMTUsMF0sZ29sZGVucm9kOlsyMTgsMTY1LDMyXSxncmF5OlsxMjgsMTI4LDEyOF0sZ3JlZW46WzAsMTI4LDBdLGdyZWVueWVsbG93OlsxNzMsMjU1LDQ3XSxncmV5OlsxMjgsMTI4LDEyOF0saG9uZXlkZXc6WzI0MCwyNTUsMjQwXSxob3RwaW5rOlsyNTUsMTA1LDE4MF0saW5kaWFucmVkOlsyMDUsOTIsOTJdLGluZGlnbzpbNzUsMCwxMzBdLGl2b3J5OlsyNTUsMjU1LDI0MF0sa2hha2k6WzI0MCwyMzAsMTQwXSxsYXZlbmRlcjpbMjMwLDIzMCwyNTBdLGxhdmVuZGVyYmx1c2g6WzI1NSwyNDAsMjQ1XSxsYXduZ3JlZW46WzEyNCwyNTIsMF0sbGVtb25jaGlmZm9uOlsyNTUsMjUwLDIwNV0sbGlnaHRibHVlOlsxNzMsMjE2LDIzMF0sbGlnaHRjb3JhbDpbMjQwLDEyOCwxMjhdLGxpZ2h0Y3lhbjpbMjI0LDI1NSwyNTVdLGxpZ2h0Z29sZGVucm9keWVsbG93OlsyNTAsMjUwLDIxMF0sbGlnaHRncmF5OlsyMTEsMjExLDIxMV0sbGlnaHRncmVlbjpbMTQ0LDIzOCwxNDRdLGxpZ2h0Z3JleTpbMjExLDIxMSwyMTFdLGxpZ2h0cGluazpbMjU1LDE4MiwxOTNdLGxpZ2h0c2FsbW9uOlsyNTUsMTYwLDEyMl0sbGlnaHRzZWFncmVlbjpbMzIsMTc4LDE3MF0sbGlnaHRza3libHVlOlsxMzUsMjA2LDI1MF0sbGlnaHRzbGF0ZWdyYXk6WzExOSwxMzYsMTUzXSxsaWdodHNsYXRlZ3JleTpbMTE5LDEzNiwxNTNdLGxpZ2h0c3RlZWxibHVlOlsxNzYsMTk2LDIyMl0sbGlnaHR5ZWxsb3c6WzI1NSwyNTUsMjI0XSxsaW1lOlswLDI1NSwwXSxsaW1lZ3JlZW46WzUwLDIwNSw1MF0sbGluZW46WzI1MCwyNDAsMjMwXSxtYWdlbnRhOlsyNTUsMCwyNTVdLG1hcm9vbjpbMTI4LDAsMF0sbWVkaXVtYXF1YW1hcmluZTpbMTAyLDIwNSwxNzBdLG1lZGl1bWJsdWU6WzAsMCwyMDVdLG1lZGl1bW9yY2hpZDpbMTg2LDg1LDIxMV0sbWVkaXVtcHVycGxlOlsxNDcsMTEyLDIxOV0sbWVkaXVtc2VhZ3JlZW46WzYwLDE3OSwxMTNdLG1lZGl1bXNsYXRlYmx1ZTpbMTIzLDEwNCwyMzhdLG1lZGl1bXNwcmluZ2dyZWVuOlswLDI1MCwxNTRdLG1lZGl1bXR1cnF1b2lzZTpbNzIsMjA5LDIwNF0sbWVkaXVtdmlvbGV0cmVkOlsxOTksMjEsMTMzXSxtaWRuaWdodGJsdWU6WzI1LDI1LDExMl0sbWludGNyZWFtOlsyNDUsMjU1LDI1MF0sbWlzdHlyb3NlOlsyNTUsMjI4LDIyNV0sbW9jY2FzaW46WzI1NSwyMjgsMTgxXSxuYXZham93aGl0ZTpbMjU1LDIyMiwxNzNdLG5hdnk6WzAsMCwxMjhdLG9sZGxhY2U6WzI1MywyNDUsMjMwXSxvbGl2ZTpbMTI4LDEyOCwwXSxvbGl2ZWRyYWI6WzEwNywxNDIsMzVdLG9yYW5nZTpbMjU1LDE2NSwwXSxvcmFuZ2VyZWQ6WzI1NSw2OSwwXSxvcmNoaWQ6WzIxOCwxMTIsMjE0XSxwYWxlZ29sZGVucm9kOlsyMzgsMjMyLDE3MF0scGFsZWdyZWVuOlsxNTIsMjUxLDE1Ml0scGFsZXR1cnF1b2lzZTpbMTc1LDIzOCwyMzhdLHBhbGV2aW9sZXRyZWQ6WzIxOSwxMTIsMTQ3XSxwYXBheWF3aGlwOlsyNTUsMjM5LDIxM10scGVhY2hwdWZmOlsyNTUsMjE4LDE4NV0scGVydTpbMjA1LDEzMyw2M10scGluazpbMjU1LDE5MiwyMDNdLHBsdW06WzIyMSwxNjAsMjIxXSxwb3dkZXJibHVlOlsxNzYsMjI0LDIzMF0scHVycGxlOlsxMjgsMCwxMjhdLHJlYmVjY2FwdXJwbGU6WzEwMiw1MSwxNTNdLHJlZDpbMjU1LDAsMF0scm9zeWJyb3duOlsxODgsMTQzLDE0M10scm95YWxibHVlOls2NSwxMDUsMjI1XSxzYWRkbGVicm93bjpbMTM5LDY5LDE5XSxzYWxtb246WzI1MCwxMjgsMTE0XSxzYW5keWJyb3duOlsyNDQsMTY0LDk2XSxzZWFncmVlbjpbNDYsMTM5LDg3XSxzZWFzaGVsbDpbMjU1LDI0NSwyMzhdLHNpZW5uYTpbMTYwLDgyLDQ1XSxzaWx2ZXI6WzE5MiwxOTIsMTkyXSxza3libHVlOlsxMzUsMjA2LDIzNV0sc2xhdGVibHVlOlsxMDYsOTAsMjA1XSxzbGF0ZWdyYXk6WzExMiwxMjgsMTQ0XSxzbGF0ZWdyZXk6WzExMiwxMjgsMTQ0XSxzbm93OlsyNTUsMjUwLDI1MF0sc3ByaW5nZ3JlZW46WzAsMjU1LDEyN10sc3RlZWxibHVlOls3MCwxMzAsMTgwXSx0YW46WzIxMCwxODAsMTQwXSx0ZWFsOlswLDEyOCwxMjhdLHRoaXN0bGU6WzIxNiwxOTEsMjE2XSx0b21hdG86WzI1NSw5OSw3MV0sdHVycXVvaXNlOls2NCwyMjQsMjA4XSx2aW9sZXQ6WzIzOCwxMzAsMjM4XSx3aGVhdDpbMjQ1LDIyMiwxNzldLHdoaXRlOlsyNTUsMjU1LDI1NV0sd2hpdGVzbW9rZTpbMjQ1LDI0NSwyNDVdLHllbGxvdzpbMjU1LDI1NSwwXSx5ZWxsb3dncmVlbjpbMTU0LDIwNSw1MF19LGNvbnZlcnNpb25zPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSx0KXtyZXR1cm4gTWF0aC5wb3coZVswXS10WzBdLDIpK01hdGgucG93KGVbMV0tdFsxXSwyKStNYXRoLnBvdyhlWzJdLXRbMl0sMil9dmFyIG49e307Zm9yKHZhciByIGluIGNvbG9yTmFtZSljb2xvck5hbWUuaGFzT3duUHJvcGVydHkocikmJihuW2NvbG9yTmFtZVtyXV09cik7dmFyIGk9ZS5leHBvcnRzPXtyZ2I6e2NoYW5uZWxzOjMsbGFiZWxzOiJyZ2IifSxoc2w6e2NoYW5uZWxzOjMsbGFiZWxzOiJoc2wifSxoc3Y6e2NoYW5uZWxzOjMsbGFiZWxzOiJoc3YifSxod2I6e2NoYW5uZWxzOjMsbGFiZWxzOiJod2IifSxjbXlrOntjaGFubmVsczo0LGxhYmVsczoiY215ayJ9LHh5ejp7Y2hhbm5lbHM6MyxsYWJlbHM6Inh5eiJ9LGxhYjp7Y2hhbm5lbHM6MyxsYWJlbHM6ImxhYiJ9LGxjaDp7Y2hhbm5lbHM6MyxsYWJlbHM6ImxjaCJ9LGhleDp7Y2hhbm5lbHM6MSxsYWJlbHM6WyJoZXgiXX0sa2V5d29yZDp7Y2hhbm5lbHM6MSxsYWJlbHM6WyJrZXl3b3JkIl19LGFuc2kxNjp7Y2hhbm5lbHM6MSxsYWJlbHM6WyJhbnNpMTYiXX0sYW5zaTI1Njp7Y2hhbm5lbHM6MSxsYWJlbHM6WyJhbnNpMjU2Il19LGhjZzp7Y2hhbm5lbHM6MyxsYWJlbHM6WyJoIiwiYyIsImciXX0sYXBwbGU6e2NoYW5uZWxzOjMsbGFiZWxzOlsicjE2IiwiZzE2IiwiYjE2Il19LGdyYXk6e2NoYW5uZWxzOjEsbGFiZWxzOlsiZ3JheSJdfX07Zm9yKHZhciBvIGluIGkpaWYoaS5oYXNPd25Qcm9wZXJ0eShvKSl7aWYoISgiY2hhbm5lbHMiaW4gaVtvXSkpdGhyb3cgbmV3IEVycm9yKCJtaXNzaW5nIGNoYW5uZWxzIHByb3BlcnR5OiAiK28pO2lmKCEoImxhYmVscyJpbiBpW29dKSl0aHJvdyBuZXcgRXJyb3IoIm1pc3NpbmcgY2hhbm5lbCBsYWJlbHMgcHJvcGVydHk6ICIrbyk7aWYoaVtvXS5sYWJlbHMubGVuZ3RoIT09aVtvXS5jaGFubmVscyl0aHJvdyBuZXcgRXJyb3IoImNoYW5uZWwgYW5kIGxhYmVsIGNvdW50cyBtaXNtYXRjaDogIitvKTt2YXIgYT1pW29dLmNoYW5uZWxzLHM9aVtvXS5sYWJlbHM7ZGVsZXRlIGlbb10uY2hhbm5lbHMsZGVsZXRlIGlbb10ubGFiZWxzLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShpW29dLCJjaGFubmVscyIse3ZhbHVlOmF9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoaVtvXSwibGFiZWxzIix7dmFsdWU6c30pfWkucmdiLmhzbD1mdW5jdGlvbihlKXt2YXIgdCxuLHIsaT1lWzBdLzI1NSxvPWVbMV0vMjU1LGE9ZVsyXS8yNTUscz1NYXRoLm1pbihpLG8sYSksdT1NYXRoLm1heChpLG8sYSksYz11LXM7cmV0dXJuIHU9PT1zP3Q9MDppPT09dT90PShvLWEpL2M6bz09PXU/dD0yKyhhLWkpL2M6YT09PXUmJih0PTQrKGktbykvYyksdD1NYXRoLm1pbig2MCp0LDM2MCksdDwwJiYodCs9MzYwKSxyPShzK3UpLzIsbj11PT09cz8wOnI8PS41P2MvKHUrcyk6Yy8oMi11LXMpLFt0LDEwMCpuLDEwMCpyXX0saS5yZ2IuaHN2PWZ1bmN0aW9uKGUpe3ZhciB0LG4scixpPWVbMF0sbz1lWzFdLGE9ZVsyXSxzPU1hdGgubWluKGksbyxhKSx1PU1hdGgubWF4KGksbyxhKSxjPXUtcztyZXR1cm4gbj0wPT09dT8wOmMvdSoxZTMvMTAsdT09PXM/dD0wOmk9PT11P3Q9KG8tYSkvYzpvPT09dT90PTIrKGEtaSkvYzphPT09dSYmKHQ9NCsoaS1vKS9jKSx0PU1hdGgubWluKDYwKnQsMzYwKSx0PDAmJih0Kz0zNjApLHI9dS8yNTUqMWUzLzEwLFt0LG4scl19LGkucmdiLmh3Yj1mdW5jdGlvbihlKXt2YXIgdD1lWzBdLG49ZVsxXSxyPWVbMl0sbz1pLnJnYi5oc2woZSlbMF0sYT0xLzI1NSpNYXRoLm1pbih0LE1hdGgubWluKG4scikpO3JldHVybiByPTEtMS8yNTUqTWF0aC5tYXgodCxNYXRoLm1heChuLHIpKSxbbywxMDAqYSwxMDAqcl19LGkucmdiLmNteWs9ZnVuY3Rpb24oZSl7dmFyIHQsbixyLGksbz1lWzBdLzI1NSxhPWVbMV0vMjU1LHM9ZVsyXS8yNTU7cmV0dXJuIGk9TWF0aC5taW4oMS1vLDEtYSwxLXMpLHQ9KDEtby1pKS8oMS1pKXx8MCxuPSgxLWEtaSkvKDEtaSl8fDAscj0oMS1zLWkpLygxLWkpfHwwLFsxMDAqdCwxMDAqbiwxMDAqciwxMDAqaV19LGkucmdiLmtleXdvcmQ9ZnVuY3Rpb24oZSl7dmFyIHI9bltlXTtpZihyKXJldHVybiByO3ZhciBpLG89MS8wO2Zvcih2YXIgYSBpbiBjb2xvck5hbWUpaWYoY29sb3JOYW1lLmhhc093blByb3BlcnR5KGEpKXt2YXIgcz1jb2xvck5hbWVbYV0sdT10KGUscyk7dTxvJiYobz11LGk9YSl9cmV0dXJuIGl9LGkua2V5d29yZC5yZ2I9ZnVuY3Rpb24oZSl7cmV0dXJuIGNvbG9yTmFtZVtlXX0saS5yZ2IueHl6PWZ1bmN0aW9uKGUpe3ZhciB0PWVbMF0vMjU1LG49ZVsxXS8yNTUscj1lWzJdLzI1NTtyZXR1cm4gdD10Pi4wNDA0NT9NYXRoLnBvdygodCsuMDU1KS8xLjA1NSwyLjQpOnQvMTIuOTIsbj1uPi4wNDA0NT9NYXRoLnBvdygobisuMDU1KS8xLjA1NSwyLjQpOm4vMTIuOTIscj1yPi4wNDA0NT9NYXRoLnBvdygocisuMDU1KS8xLjA1NSwyLjQpOnIvMTIuOTIsWzEwMCooLjQxMjQqdCsuMzU3NipuKy4xODA1KnIpLDEwMCooLjIxMjYqdCsuNzE1MipuKy4wNzIyKnIpLDEwMCooLjAxOTMqdCsuMTE5MipuKy45NTA1KnIpXX0saS5yZ2IubGFiPWZ1bmN0aW9uKGUpe3ZhciB0LG4scixvPWkucmdiLnh5eihlKSxhPW9bMF0scz1vWzFdLHU9b1syXTtyZXR1cm4gYS89OTUuMDQ3LHMvPTEwMCx1Lz0xMDguODgzLGE9YT4uMDA4ODU2P01hdGgucG93KGEsMS8zKTo3Ljc4NyphKzE2LzExNixzPXM+LjAwODg1Nj9NYXRoLnBvdyhzLDEvMyk6Ny43ODcqcysxNi8xMTYsdT11Pi4wMDg4NTY/TWF0aC5wb3codSwxLzMpOjcuNzg3KnUrMTYvMTE2LHQ9MTE2KnMtMTYsbj01MDAqKGEtcykscj0yMDAqKHMtdSksW3QsbixyXX0saS5oc2wucmdiPWZ1bmN0aW9uKGUpe3ZhciB0LG4scixpLG8sYT1lWzBdLzM2MCxzPWVbMV0vMTAwLHU9ZVsyXS8xMDA7aWYoMD09PXMpcmV0dXJuIG89MjU1KnUsW28sbyxvXTtuPXU8LjU/dSooMStzKTp1K3MtdSpzLHQ9Mip1LW4saT1bMCwwLDBdO2Zvcih2YXIgYz0wO2M8MztjKyspcj1hKzEvMyotKGMtMSkscjwwJiZyKysscj4xJiZyLS0sbz02KnI8MT90KzYqKG4tdCkqcjoyKnI8MT9uOjMqcjwyP3QrKG4tdCkqKDIvMy1yKSo2OnQsaVtjXT0yNTUqbztyZXR1cm4gaX0saS5oc2wuaHN2PWZ1bmN0aW9uKGUpe3ZhciB0LG4scj1lWzBdLGk9ZVsxXS8xMDAsbz1lWzJdLzEwMCxhPWkscz1NYXRoLm1heChvLC4wMSk7cmV0dXJuIG8qPTIsaSo9bzw9MT9vOjItbyxhKj1zPD0xP3M6Mi1zLG49KG8raSkvMix0PTA9PT1vPzIqYS8ocythKToyKmkvKG8raSksW3IsMTAwKnQsMTAwKm5dfSxpLmhzdi5yZ2I9ZnVuY3Rpb24oZSl7dmFyIHQ9ZVswXS82MCxuPWVbMV0vMTAwLHI9ZVsyXS8xMDAsaT1NYXRoLmZsb29yKHQpJTYsbz10LU1hdGguZmxvb3IodCksYT0yNTUqciooMS1uKSxzPTI1NSpyKigxLW4qbyksdT0yNTUqciooMS1uKigxLW8pKTtzd2l0Y2gocio9MjU1LGkpe2Nhc2UgMDpyZXR1cm5bcix1LGFdO2Nhc2UgMTpyZXR1cm5bcyxyLGFdO2Nhc2UgMjpyZXR1cm5bYSxyLHVdO2Nhc2UgMzpyZXR1cm5bYSxzLHJdO2Nhc2UgNDpyZXR1cm5bdSxhLHJdO2Nhc2UgNTpyZXR1cm5bcixhLHNdfX0saS5oc3YuaHNsPWZ1bmN0aW9uKGUpe3ZhciB0LG4scixpPWVbMF0sbz1lWzFdLzEwMCxhPWVbMl0vMTAwLHM9TWF0aC5tYXgoYSwuMDEpO3JldHVybiByPSgyLW8pKmEsdD0oMi1vKSpzLG49bypzLG4vPXQ8PTE/dDoyLXQsbj1ufHwwLHIvPTIsW2ksMTAwKm4sMTAwKnJdfSxpLmh3Yi5yZ2I9ZnVuY3Rpb24oZSl7dmFyIHQsbixyLGksbz1lWzBdLzM2MCxhPWVbMV0vMTAwLHM9ZVsyXS8xMDAsdT1hK3M7dT4xJiYoYS89dSxzLz11KSx0PU1hdGguZmxvb3IoNipvKSxuPTEtcyxyPTYqby10LDAhPT0oMSZ0KSYmKHI9MS1yKSxpPWErcioobi1hKTt2YXIgYyxsLHA7c3dpdGNoKHQpe2RlZmF1bHQ6Y2FzZSA2OmNhc2UgMDpjPW4sbD1pLHA9YTticmVhaztjYXNlIDE6Yz1pLGw9bixwPWE7YnJlYWs7Y2FzZSAyOmM9YSxsPW4scD1pO2JyZWFrO2Nhc2UgMzpjPWEsbD1pLHA9bjticmVhaztjYXNlIDQ6Yz1pLGw9YSxwPW47YnJlYWs7Y2FzZSA1OmM9bixsPWEscD1pfXJldHVyblsyNTUqYywyNTUqbCwyNTUqcF19LGkuY215ay5yZ2I9ZnVuY3Rpb24oZSl7dmFyIHQsbixyLGk9ZVswXS8xMDAsbz1lWzFdLzEwMCxhPWVbMl0vMTAwLHM9ZVszXS8xMDA7cmV0dXJuIHQ9MS1NYXRoLm1pbigxLGkqKDEtcykrcyksbj0xLU1hdGgubWluKDEsbyooMS1zKStzKSxyPTEtTWF0aC5taW4oMSxhKigxLXMpK3MpLFsyNTUqdCwyNTUqbiwyNTUqcl19LGkueHl6LnJnYj1mdW5jdGlvbihlKXt2YXIgdCxuLHIsaT1lWzBdLzEwMCxvPWVbMV0vMTAwLGE9ZVsyXS8xMDA7cmV0dXJuIHQ9My4yNDA2KmkrLTEuNTM3MipvKy0uNDk4NiphLG49LS45Njg5KmkrMS44NzU4Km8rLjA0MTUqYSxyPS4wNTU3KmkrLS4yMDQqbysxLjA1NyphLHQ9dD4uMDAzMTMwOD8xLjA1NSpNYXRoLnBvdyh0LDEvMi40KS0uMDU1OjEyLjkyKnQsbj1uPi4wMDMxMzA4PzEuMDU1Kk1hdGgucG93KG4sMS8yLjQpLS4wNTU6MTIuOTIqbixyPXI+LjAwMzEzMDg/MS4wNTUqTWF0aC5wb3cociwxLzIuNCktLjA1NToxMi45MipyLHQ9TWF0aC5taW4oTWF0aC5tYXgoMCx0KSwxKSxuPU1hdGgubWluKE1hdGgubWF4KDAsbiksMSkscj1NYXRoLm1pbihNYXRoLm1heCgwLHIpLDEpLFsyNTUqdCwyNTUqbiwyNTUqcl19LGkueHl6LmxhYj1mdW5jdGlvbihlKXt2YXIgdCxuLHIsaT1lWzBdLG89ZVsxXSxhPWVbMl07cmV0dXJuIGkvPTk1LjA0NyxvLz0xMDAsYS89MTA4Ljg4MyxpPWk+LjAwODg1Nj9NYXRoLnBvdyhpLDEvMyk6Ny43ODcqaSsxNi8xMTYsbz1vPi4wMDg4NTY/TWF0aC5wb3cobywxLzMpOjcuNzg3Km8rMTYvMTE2LGE9YT4uMDA4ODU2P01hdGgucG93KGEsMS8zKTo3Ljc4NyphKzE2LzExNix0PTExNipvLTE2LG49NTAwKihpLW8pLHI9MjAwKihvLWEpLFt0LG4scl19LGkubGFiLnh5ej1mdW5jdGlvbihlKXt2YXIgdCxuLHIsaT1lWzBdLG89ZVsxXSxhPWVbMl07bj0oaSsxNikvMTE2LHQ9by81MDArbixyPW4tYS8yMDA7dmFyIHM9TWF0aC5wb3cobiwzKSx1PU1hdGgucG93KHQsMyksYz1NYXRoLnBvdyhyLDMpO3JldHVybiBuPXM+LjAwODg1Nj9zOihuLTE2LzExNikvNy43ODcsdD11Pi4wMDg4NTY/dToodC0xNi8xMTYpLzcuNzg3LHI9Yz4uMDA4ODU2P2M6KHItMTYvMTE2KS83Ljc4Nyx0Kj05NS4wNDcsbio9MTAwLHIqPTEwOC44ODMsW3QsbixyXX0saS5sYWIubGNoPWZ1bmN0aW9uKGUpe3ZhciB0LG4scixpPWVbMF0sbz1lWzFdLGE9ZVsyXTtyZXR1cm4gdD1NYXRoLmF0YW4yKGEsbyksbj0zNjAqdC8yL01hdGguUEksbjwwJiYobis9MzYwKSxyPU1hdGguc3FydChvKm8rYSphKSxbaSxyLG5dfSxpLmxjaC5sYWI9ZnVuY3Rpb24oZSl7dmFyIHQsbixyLGk9ZVswXSxvPWVbMV0sYT1lWzJdO3JldHVybiByPWEvMzYwKjIqTWF0aC5QSSx0PW8qTWF0aC5jb3Mociksbj1vKk1hdGguc2luKHIpLFtpLHQsbl19LGkucmdiLmFuc2kxNj1mdW5jdGlvbihlKXt2YXIgdD1lWzBdLG49ZVsxXSxyPWVbMl0sbz0xIGluIGFyZ3VtZW50cz9hcmd1bWVudHNbMV06aS5yZ2IuaHN2KGUpWzJdO2lmKDA9PT0obz1NYXRoLnJvdW5kKG8vNTApKSlyZXR1cm4gMzA7dmFyIGE9MzArKE1hdGgucm91bmQoci8yNTUpPDwyfE1hdGgucm91bmQobi8yNTUpPDwxfE1hdGgucm91bmQodC8yNTUpKTtyZXR1cm4gMj09PW8mJihhKz02MCksYX0saS5oc3YuYW5zaTE2PWZ1bmN0aW9uKGUpe3JldHVybiBpLnJnYi5hbnNpMTYoaS5oc3YucmdiKGUpLGVbMl0pfSxpLnJnYi5hbnNpMjU2PWZ1bmN0aW9uKGUpe3ZhciB0PWVbMF0sbj1lWzFdLHI9ZVsyXTtyZXR1cm4gdD09PW4mJm49PT1yP3Q8OD8xNjp0PjI0OD8yMzE6TWF0aC5yb3VuZCgodC04KS8yNDcqMjQpKzIzMjoxNiszNipNYXRoLnJvdW5kKHQvMjU1KjUpKzYqTWF0aC5yb3VuZChuLzI1NSo1KStNYXRoLnJvdW5kKHIvMjU1KjUpfSxpLmFuc2kxNi5yZ2I9ZnVuY3Rpb24oZSl7dmFyIHQ9ZSUxMDtpZigwPT09dHx8Nz09PXQpcmV0dXJuIGU+NTAmJih0Kz0zLjUpLHQ9dC8xMC41KjI1NSxbdCx0LHRdO3ZhciBuPS41KigxK35+KGU+NTApKTtyZXR1cm5bKDEmdCkqbioyNTUsKHQ+PjEmMSkqbioyNTUsKHQ+PjImMSkqbioyNTVdfSxpLmFuc2kyNTYucmdiPWZ1bmN0aW9uKGUpe2lmKGU+PTIzMil7dmFyIHQ9MTAqKGUtMjMyKSs4O3JldHVyblt0LHQsdF19ZS09MTY7dmFyIG47cmV0dXJuW01hdGguZmxvb3IoZS8zNikvNSoyNTUsTWF0aC5mbG9vcigobj1lJTM2KS82KS81KjI1NSxuJTYvNSoyNTVdfSxpLnJnYi5oZXg9ZnVuY3Rpb24oZSl7dmFyIHQ9KCgyNTUmTWF0aC5yb3VuZChlWzBdKSk8PDE2KSsoKDI1NSZNYXRoLnJvdW5kKGVbMV0pKTw8OCkrKDI1NSZNYXRoLnJvdW5kKGVbMl0pKSxuPXQudG9TdHJpbmcoMTYpLnRvVXBwZXJDYXNlKCk7cmV0dXJuIjAwMDAwMCIuc3Vic3RyaW5nKG4ubGVuZ3RoKStufSxpLmhleC5yZ2I9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS50b1N0cmluZygxNikubWF0Y2goL1thLWYwLTldezZ9fFthLWYwLTldezN9L2kpO2lmKCF0KXJldHVyblswLDAsMF07dmFyIG49dFswXTszPT09dFswXS5sZW5ndGgmJihuPW4uc3BsaXQoIiIpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZStlfSkuam9pbigiIikpO3ZhciByPXBhcnNlSW50KG4sMTYpO3JldHVybltyPj4xNiYyNTUscj4+OCYyNTUsMjU1JnJdfSxpLnJnYi5oY2c9ZnVuY3Rpb24oZSl7dmFyIHQsbixyPWVbMF0vMjU1LGk9ZVsxXS8yNTUsbz1lWzJdLzI1NSxhPU1hdGgubWF4KE1hdGgubWF4KHIsaSksbykscz1NYXRoLm1pbihNYXRoLm1pbihyLGkpLG8pLHU9YS1zO3JldHVybiB0PXU8MT9zLygxLXUpOjAsbj11PD0wPzA6YT09PXI/KGktbykvdSU2OmE9PT1pPzIrKG8tcikvdTo0KyhyLWkpL3UrNCxuLz02LG4lPTEsWzM2MCpuLDEwMCp1LDEwMCp0XX0saS5oc2wuaGNnPWZ1bmN0aW9uKGUpe3ZhciB0PWVbMV0vMTAwLG49ZVsyXS8xMDAscj0xLGk9MDtyZXR1cm4gcj1uPC41PzIqdCpuOjIqdCooMS1uKSxyPDEmJihpPShuLS41KnIpLygxLXIpKSxbZVswXSwxMDAqciwxMDAqaV19LGkuaHN2LmhjZz1mdW5jdGlvbihlKXt2YXIgdD1lWzFdLzEwMCxuPWVbMl0vMTAwLHI9dCpuLGk9MDtyZXR1cm4gcjwxJiYoaT0obi1yKS8oMS1yKSksW2VbMF0sMTAwKnIsMTAwKmldfSxpLmhjZy5yZ2I9ZnVuY3Rpb24oZSl7dmFyIHQ9ZVswXS8zNjAsbj1lWzFdLzEwMCxyPWVbMl0vMTAwO2lmKDA9PT1uKXJldHVyblsyNTUqciwyNTUqciwyNTUqcl07dmFyIGk9WzAsMCwwXSxvPXQlMSo2LGE9byUxLHM9MS1hLHU9MDtzd2l0Y2goTWF0aC5mbG9vcihvKSl7Y2FzZSAwOmlbMF09MSxpWzFdPWEsaVsyXT0wO2JyZWFrO2Nhc2UgMTppWzBdPXMsaVsxXT0xLGlbMl09MDticmVhaztjYXNlIDI6aVswXT0wLGlbMV09MSxpWzJdPWE7YnJlYWs7Y2FzZSAzOmlbMF09MCxpWzFdPXMsaVsyXT0xO2JyZWFrO2Nhc2UgNDppWzBdPWEsaVsxXT0wLGlbMl09MTticmVhaztkZWZhdWx0OmlbMF09MSxpWzFdPTAsaVsyXT1zfXJldHVybiB1PSgxLW4pKnIsWzI1NSoobippWzBdK3UpLDI1NSoobippWzFdK3UpLDI1NSoobippWzJdK3UpXX0saS5oY2cuaHN2PWZ1bmN0aW9uKGUpe3ZhciB0PWVbMV0vMTAwLG49ZVsyXS8xMDAscj10K24qKDEtdCksaT0wO3JldHVybiByPjAmJihpPXQvciksW2VbMF0sMTAwKmksMTAwKnJdfSxpLmhjZy5oc2w9ZnVuY3Rpb24oZSl7dmFyIHQ9ZVsxXS8xMDAsbj1lWzJdLzEwMCxyPW4qKDEtdCkrLjUqdCxpPTA7cmV0dXJuIHI+MCYmcjwuNT9pPXQvKDIqcik6cj49LjUmJnI8MSYmKGk9dC8oMiooMS1yKSkpLFtlWzBdLDEwMCppLDEwMCpyXX0saS5oY2cuaHdiPWZ1bmN0aW9uKGUpe3ZhciB0PWVbMV0vMTAwLG49ZVsyXS8xMDAscj10K24qKDEtdCk7cmV0dXJuW2VbMF0sMTAwKihyLXQpLDEwMCooMS1yKV19LGkuaHdiLmhjZz1mdW5jdGlvbihlKXt2YXIgdD1lWzFdLzEwMCxuPWVbMl0vMTAwLHI9MS1uLGk9ci10LG89MDtyZXR1cm4gaTwxJiYobz0oci1pKS8oMS1pKSksW2VbMF0sMTAwKmksMTAwKm9dfSxpLmFwcGxlLnJnYj1mdW5jdGlvbihlKXtyZXR1cm5bZVswXS82NTUzNSoyNTUsZVsxXS82NTUzNSoyNTUsZVsyXS82NTUzNSoyNTVdfSxpLnJnYi5hcHBsZT1mdW5jdGlvbihlKXtyZXR1cm5bZVswXS8yNTUqNjU1MzUsZVsxXS8yNTUqNjU1MzUsZVsyXS8yNTUqNjU1MzVdfSxpLmdyYXkucmdiPWZ1bmN0aW9uKGUpe3JldHVybltlWzBdLzEwMCoyNTUsZVswXS8xMDAqMjU1LGVbMF0vMTAwKjI1NV19LGkuZ3JheS5oc2w9aS5ncmF5Lmhzdj1mdW5jdGlvbihlKXtyZXR1cm5bMCwwLGVbMF1dfSxpLmdyYXkuaHdiPWZ1bmN0aW9uKGUpe3JldHVyblswLDEwMCxlWzBdXX0saS5ncmF5LmNteWs9ZnVuY3Rpb24oZSl7cmV0dXJuWzAsMCwwLGVbMF1dfSxpLmdyYXkubGFiPWZ1bmN0aW9uKGUpe3JldHVybltlWzBdLDAsMF19LGkuZ3JheS5oZXg9ZnVuY3Rpb24oZSl7dmFyIHQ9MjU1Jk1hdGgucm91bmQoZVswXS8xMDAqMjU1KSxuPSh0PDwxNikrKHQ8PDgpK3Qscj1uLnRvU3RyaW5nKDE2KS50b1VwcGVyQ2FzZSgpO3JldHVybiIwMDAwMDAiLnN1YnN0cmluZyhyLmxlbmd0aCkrcn0saS5yZ2IuZ3JheT1mdW5jdGlvbihlKXtyZXR1cm5bKGVbMF0rZVsxXStlWzJdKS8zLzI1NSoxMDBdfX0pLG1vZGVscyQxPU9iamVjdC5rZXlzKGNvbnZlcnNpb25zKSxyb3V0ZT1mdW5jdGlvbihlKXtmb3IodmFyIHQ9ZGVyaXZlQkZTKGUpLG49e30scj1PYmplY3Qua2V5cyh0KSxpPXIubGVuZ3RoLG89MDtvPGk7bysrKXt2YXIgYT1yW29dO251bGwhPT10W2FdLnBhcmVudCYmKG5bYV09d3JhcENvbnZlcnNpb24oYSx0KSl9cmV0dXJuIG59LGNvbnZlcnQ9e30sbW9kZWxzPU9iamVjdC5rZXlzKGNvbnZlcnNpb25zKTttb2RlbHMuZm9yRWFjaChmdW5jdGlvbihlKXtjb252ZXJ0W2VdPXt9LE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjb252ZXJ0W2VdLCJjaGFubmVscyIse3ZhbHVlOmNvbnZlcnNpb25zW2VdLmNoYW5uZWxzfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KGNvbnZlcnRbZV0sImxhYmVscyIse3ZhbHVlOmNvbnZlcnNpb25zW2VdLmxhYmVsc30pO3ZhciB0PXJvdXRlKGUpO09iamVjdC5rZXlzKHQpLmZvckVhY2goZnVuY3Rpb24obil7dmFyIHI9dFtuXTtjb252ZXJ0W2VdW25dPXdyYXBSb3VuZGVkKHIpLGNvbnZlcnRbZV1bbl0ucmF3PXdyYXBSYXcocil9KX0pO3ZhciBjb2xvckNvbnZlcnQ9Y29udmVydCxhbnNpU3R5bGVzPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXt2YXIgZT17bW9kaWZpZXI6e3Jlc2V0OlswLDBdLGJvbGQ6WzEsMjJdLGRpbTpbMiwyMl0saXRhbGljOlszLDIzXSx1bmRlcmxpbmU6WzQsMjRdLGludmVyc2U6WzcsMjddLGhpZGRlbjpbOCwyOF0sc3RyaWtldGhyb3VnaDpbOSwyOV19LGNvbG9yOntibGFjazpbMzAsMzldLHJlZDpbMzEsMzldLGdyZWVuOlszMiwzOV0seWVsbG93OlszMywzOV0sYmx1ZTpbMzQsMzldLG1hZ2VudGE6WzM1LDM5XSxjeWFuOlszNiwzOV0sd2hpdGU6WzM3LDM5XSxncmF5Ols5MCwzOV0scmVkQnJpZ2h0Ols5MSwzOV0sZ3JlZW5CcmlnaHQ6WzkyLDM5XSx5ZWxsb3dCcmlnaHQ6WzkzLDM5XSxibHVlQnJpZ2h0Ols5NCwzOV0sbWFnZW50YUJyaWdodDpbOTUsMzldLGN5YW5CcmlnaHQ6Wzk2LDM5XSx3aGl0ZUJyaWdodDpbOTcsMzldfSxiZ0NvbG9yOntiZ0JsYWNrOls0MCw0OV0sYmdSZWQ6WzQxLDQ5XSxiZ0dyZWVuOls0Miw0OV0sYmdZZWxsb3c6WzQzLDQ5XSxiZ0JsdWU6WzQ0LDQ5XSxiZ01hZ2VudGE6WzQ1LDQ5XSxiZ0N5YW46WzQ2LDQ5XSxiZ1doaXRlOls0Nyw0OV0sYmdCbGFja0JyaWdodDpbMTAwLDQ5XSxiZ1JlZEJyaWdodDpbMTAxLDQ5XSxiZ0dyZWVuQnJpZ2h0OlsxMDIsNDldLGJnWWVsbG93QnJpZ2h0OlsxMDMsNDldLGJnQmx1ZUJyaWdodDpbMTA0LDQ5XSxiZ01hZ2VudGFCcmlnaHQ6WzEwNSw0OV0sYmdDeWFuQnJpZ2h0OlsxMDYsNDldLGJnV2hpdGVCcmlnaHQ6WzEwNyw0OV19fTtlLmNvbG9yLmdyZXk9ZS5jb2xvci5ncmF5LE9iamVjdC5rZXlzKGUpLmZvckVhY2goZnVuY3Rpb24odCl7dmFyIG49ZVt0XTtPYmplY3Qua2V5cyhuKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe3ZhciByPW5bdF07ZVt0XT17b3BlbjoiXHgxYlsiLmNvbmNhdChyWzBdLCJtIiksY2xvc2U6Ilx4MWJbIi5jb25jYXQoclsxXSwibSIpfSxuW3RdPWVbdF19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZSx0LHt2YWx1ZTpuLGVudW1lcmFibGU6ITF9KX0pO3ZhciB0PWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm5bZSx0LG5dfTtlLmNvbG9yLmNsb3NlPSJceDFiWzM5bSIsZS5iZ0NvbG9yLmNsb3NlPSJceDFiWzQ5bSIsZS5jb2xvci5hbnNpPXt9LGUuY29sb3IuYW5zaTI1Nj17fSxlLmNvbG9yLmFuc2kxNm09e3JnYjppKHQsMCl9LGUuYmdDb2xvci5hbnNpPXt9LGUuYmdDb2xvci5hbnNpMjU2PXt9LGUuYmdDb2xvci5hbnNpMTZtPXtyZ2I6aSh0LDEwKX07Zm9yKHZhciBvPU9iamVjdC5rZXlzKGNvbG9yQ29udmVydCksYT0wO2E8by5sZW5ndGg7YSsrKXt2YXIgcz1vW2FdO2lmKCJvYmplY3QiPT09X3R5cGVvZihjb2xvckNvbnZlcnRbc10pKXt2YXIgdT1jb2xvckNvbnZlcnRbc107ImFuc2kxNiJpbiB1JiYoZS5jb2xvci5hbnNpW3NdPW4odS5hbnNpMTYsMCksZS5iZ0NvbG9yLmFuc2lbc109bih1LmFuc2kxNiwxMCkpLCJhbnNpMjU2ImluIHUmJihlLmNvbG9yLmFuc2kyNTZbc109cih1LmFuc2kyNTYsMCksZS5iZ0NvbG9yLmFuc2kyNTZbc109cih1LmFuc2kyNTYsMTApKSwicmdiImluIHUmJihlLmNvbG9yLmFuc2kxNm1bc109aSh1LnJnYiwwKSxlLmJnQ29sb3IuYW5zaTE2bVtzXT1pKHUucmdiLDEwKSl9fXJldHVybiBlfXZhciBuPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIlx4MWJbIi5jb25jYXQoZS5hcHBseShjb2xvckNvbnZlcnQsYXJndW1lbnRzKSt0LCJtIil9fSxyPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIG49ZS5hcHBseShjb2xvckNvbnZlcnQsYXJndW1lbnRzKTtyZXR1cm4iXHgxYlsiLmNvbmNhdCgzOCt0LCI7NTsiKS5jb25jYXQobiwibSIpfX0saT1mdW5jdGlvbihlLHQpe3JldHVybiBmdW5jdGlvbigpe3ZhciBuPWUuYXBwbHkoY29sb3JDb252ZXJ0LGFyZ3VtZW50cyk7cmV0dXJuIlx4MWJbIi5jb25jYXQoMzgrdCwiOzI7IikuY29uY2F0KG5bMF0sIjsiKS5jb25jYXQoblsxXSwiOyIpLmNvbmNhdChuWzJdLCJtIil9fTtPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwiZXhwb3J0cyIse2VudW1lcmFibGU6ITAsZ2V0OnR9KX0pLGhhc0ZsYWc9ZnVuY3Rpb24oZSx0KXt0PXR8fHByb2Nlc3MuYXJndjt2YXIgbj10LmluZGV4T2YoIi0tIikscj0vXi17MSwyfS8udGVzdChlKT8iIjoiLS0iLGk9dC5pbmRleE9mKHIrZSk7cmV0dXJuLTEhPT1pJiYoLTE9PT1ufHxpPG4pfSxvcyQzPXt9LG9zJDU9T2JqZWN0LmZyZWV6ZSh7ZGVmYXVsdDpvcyQzLF9fbW9kdWxlRXhwb3J0czpvcyQzfSksb3MkMj1vcyQ1JiZvcyQzfHxvcyQ1LHN1cHBvcnRzQ29sb3I9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSl7dmFyIHQ9cHJvY2Vzcy5lbnYsbj1mdW5jdGlvbigpe2lmKGhhc0ZsYWcoIm5vLWNvbG9yIil8fGhhc0ZsYWcoIm5vLWNvbG9ycyIpfHxoYXNGbGFnKCJjb2xvcj1mYWxzZSIpKXJldHVybiAwO2lmKGhhc0ZsYWcoImNvbG9yPTE2bSIpfHxoYXNGbGFnKCJjb2xvcj1mdWxsIil8fGhhc0ZsYWcoImNvbG9yPXRydWVjb2xvciIpKXJldHVybiAzO2lmKGhhc0ZsYWcoImNvbG9yPTI1NiIpKXJldHVybiAyO2lmKGhhc0ZsYWcoImNvbG9yIil8fGhhc0ZsYWcoImNvbG9ycyIpfHxoYXNGbGFnKCJjb2xvcj10cnVlIil8fGhhc0ZsYWcoImNvbG9yPWFsd2F5cyIpKXJldHVybiAxO2lmKHByb2Nlc3Muc3Rkb3V0JiYhcHJvY2Vzcy5zdGRvdXQuaXNUVFkpcmV0dXJuIDA7aWYoIndpbjMyIj09PXByb2Nlc3MucGxhdGZvcm0pe3ZhciBlPW9zJDIucmVsZWFzZSgpLnNwbGl0KCIuIik7cmV0dXJuIE51bWJlcihwcm9jZXNzLnZlcnNpb24uc3BsaXQoIi4iKVswXSk+PTgmJk51bWJlcihlWzBdKT49MTAmJk51bWJlcihlWzJdKT49MTA1ODY/MjoxfWlmKCJDSSJpbiB0KXJldHVybiJUUkFWSVMiaW4gdHx8IlRyYXZpcyI9PT10LkNJfHwiQ0lSQ0xFQ0kiaW4gdD8xOjA7aWYoIlRFQU1DSVRZX1ZFUlNJT04iaW4gdClyZXR1cm4vXig5XC4oMCpbMS05XVxkKilcLnxcZHsyLH1cLikvLnRlc3QodC5URUFNQ0lUWV9WRVJTSU9OKT8xOjA7aWYoIlRFUk1fUFJPR1JBTSJpbiB0KXt2YXIgbj1wYXJzZUludCgodC5URVJNX1BST0dSQU1fVkVSU0lPTnx8IiIpLnNwbGl0KCIuIilbMF0sMTApO3N3aXRjaCh0LlRFUk1fUFJPR1JBTSl7Y2FzZSJpVGVybS5hcHAiOnJldHVybiBuPj0zPzM6MjtjYXNlIkh5cGVyIjpyZXR1cm4gMztjYXNlIkFwcGxlX1Rlcm1pbmFsIjpyZXR1cm4gMn19cmV0dXJuL14oc2NyZWVufHh0ZXJtKS0yNTYoPzpjb2xvcik/Ly50ZXN0KHQuVEVSTSk/MjovXnNjcmVlbnxeeHRlcm18XnZ0MTAwfGNvbG9yfGFuc2l8Y3lnd2lufGxpbnV4L2kudGVzdCh0LlRFUk0pPzE6IkNPTE9SVEVSTSJpbiB0PzE6KHQuVEVSTSwwKX0oKTsiRk9SQ0VfQ09MT1IiaW4gdCYmKG49MD09PXBhcnNlSW50KHQuRk9SQ0VfQ09MT1IsMTApPzA6bnx8MSksZS5leHBvcnRzPXByb2Nlc3MmJmZ1bmN0aW9uKGUpe3JldHVybiAwIT09ZSYme2xldmVsOmUsaGFzQmFzaWM6ITAsaGFzMjU2OmU+PTIsaGFzMTZtOmU+PTN9fShuKX0pLHRlbXBsYXRlcz1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUpe3JldHVybiJ1Ij09PWVbMF0mJjU9PT1lLmxlbmd0aHx8IngiPT09ZVswXSYmMz09PWUubGVuZ3RoP1N0cmluZy5mcm9tQ2hhckNvZGUocGFyc2VJbnQoZS5zbGljZSgxKSwxNikpOmMuZ2V0KGUpfHxlfWZ1bmN0aW9uIG4oZSxuKXt2YXIgcixpPVtdLG89bi50cmltKCkuc3BsaXQoL1xzKixccyovZyksYT0hMCxjPSExLGw9dm9pZCAwO3RyeXtmb3IodmFyIHAsZj1vW1N5bWJvbC5pdGVyYXRvcl0oKTshKGE9KHA9Zi5uZXh0KCkpLmRvbmUpO2E9ITApe3ZhciBkPXAudmFsdWU7aWYoaXNOYU4oZCkpe2lmKCEocj1kLm1hdGNoKHMpKSl0aHJvdyBuZXcgRXJyb3IoIkludmFsaWQgQ2hhbGsgdGVtcGxhdGUgc3R5bGUgYXJndW1lbnQ6ICIuY29uY2F0KGQsIiAoaW4gc3R5bGUgJyIpLmNvbmNhdChlLCInKSIpKTtpLnB1c2goclsyXS5yZXBsYWNlKHUsZnVuY3Rpb24oZSxuLHIpe3JldHVybiBuP3Qobik6cn0pKX1lbHNlIGkucHVzaChOdW1iZXIoZCkpfX1jYXRjaChlKXtjPSEwLGw9ZX1maW5hbGx5e3RyeXthfHxudWxsPT1mLnJldHVybnx8Zi5yZXR1cm4oKX1maW5hbGx5e2lmKGMpdGhyb3cgbH19cmV0dXJuIGl9ZnVuY3Rpb24gcihlKXthLmxhc3RJbmRleD0wO2Zvcih2YXIgdCxyPVtdO251bGwhPT0odD1hLmV4ZWMoZSkpOyl7dmFyIGk9dFsxXTtpZih0WzJdKXt2YXIgbz1uKGksdFsyXSk7ci5wdXNoKFtpXS5jb25jYXQobykpfWVsc2Ugci5wdXNoKFtpXSl9cmV0dXJuIHJ9ZnVuY3Rpb24gaShlLHQpe3ZhciBuPXt9LHI9ITAsaT0hMSxvPXZvaWQgMDt0cnl7Zm9yKHZhciBhLHM9dFtTeW1ib2wuaXRlcmF0b3JdKCk7IShyPShhPXMubmV4dCgpKS5kb25lKTtyPSEwKXt2YXIgdT1hLnZhbHVlLGM9ITAsbD0hMSxwPXZvaWQgMDt0cnl7Zm9yKHZhciBmLGQ9dS5zdHlsZXNbU3ltYm9sLml0ZXJhdG9yXSgpOyEoYz0oZj1kLm5leHQoKSkuZG9uZSk7Yz0hMCl7dmFyIGg9Zi52YWx1ZTtuW2hbMF1dPXUuaW52ZXJzZT9udWxsOmguc2xpY2UoMSl9fWNhdGNoKGUpe2w9ITAscD1lfWZpbmFsbHl7dHJ5e2N8fG51bGw9PWQucmV0dXJufHxkLnJldHVybigpfWZpbmFsbHl7aWYobCl0aHJvdyBwfX19fWNhdGNoKGUpe2k9ITAsbz1lfWZpbmFsbHl7dHJ5e3J8fG51bGw9PXMucmV0dXJufHxzLnJldHVybigpfWZpbmFsbHl7aWYoaSl0aHJvdyBvfX1mb3IodmFyIG09ZSxnPU9iamVjdC5rZXlzKG4pLHk9MDt5PGcubGVuZ3RoO3krKyl7dmFyIHY9Z1t5XTtpZihBcnJheS5pc0FycmF5KG5bdl0pKXtpZighKHYgaW4gbSkpdGhyb3cgbmV3IEVycm9yKCJVbmtub3duIENoYWxrIHN0eWxlOiAiLmNvbmNhdCh2KSk7bT1uW3ZdLmxlbmd0aD4wP21bdl0uYXBwbHkobSxuW3ZdKTptW3ZdfX1yZXR1cm4gbX12YXIgbz0vKD86XFwodVthLWZcZF17NH18eFthLWZcZF17Mn18LikpfCg/Olx7KH4pPyhcdysoPzpcKFteKV0qXCkpPyg/OlwuXHcrKD86XChbXildKlwpKT8pKikoPzpbIFx0XXwoPz1ccj9cbikpKXwoXH0pfCgoPzoufFtcclxuXGZdKSs/KS9naSxhPS8oPzpefFwuKShcdyspKD86XCgoW14pXSopXCkpPy9nLHM9L14oWyciXSkoKD86XFwufCg/IVwxKVteXFxdKSopXDEkLyx1PS9cXCh1W2EtZlxkXXs0fXx4W2EtZlxkXXsyfXwuKXwoW15cXF0pL2dpLGM9bmV3IE1hcChbWyJuIiwiXG4iXSxbInIiLCJcciJdLFsidCIsIlx0Il0sWyJiIiwiXGIiXSxbImYiLCJcZiJdLFsidiIsIlx2Il0sWyIwIiwiXDAiXSxbIlxcIiwiXFwiXSxbImUiLCJceDFiIl0sWyJhIiwiXHgwNyJdXSk7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsbil7dmFyIGE9W10scz1bXSx1PVtdO2lmKG4ucmVwbGFjZShvLGZ1bmN0aW9uKG4sbyxjLGwscCxmKXtpZihvKXUucHVzaCh0KG8pKTtlbHNlIGlmKGwpe3ZhciBkPXUuam9pbigiIik7dT1bXSxzLnB1c2goMD09PWEubGVuZ3RoP2Q6aShlLGEpKGQpKSxhLnB1c2goe2ludmVyc2U6YyxzdHlsZXM6cihsKX0pfWVsc2UgaWYocCl7aWYoMD09PWEubGVuZ3RoKXRocm93IG5ldyBFcnJvcigiRm91bmQgZXh0cmFuZW91cyB9IGluIENoYWxrIHRlbXBsYXRlIGxpdGVyYWwiKTtzLnB1c2goaShlLGEpKHUuam9pbigiIikpKSx1PVtdLGEucG9wKCl9ZWxzZSB1LnB1c2goZil9KSxzLnB1c2godS5qb2luKCIiKSksYS5sZW5ndGg+MCl7dmFyIGM9IkNoYWxrIHRlbXBsYXRlIGxpdGVyYWwgaXMgbWlzc2luZyAiLmNvbmNhdChhLmxlbmd0aCwiIGNsb3NpbmcgYnJhY2tldCIpLmNvbmNhdCgxPT09YS5sZW5ndGg/IiI6InMiLCIgKGB9YCkiKTt0aHJvdyBuZXcgRXJyb3IoYyl9cmV0dXJuIHMuam9pbigiIil9fSksY2hhbGs9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChlLHQpe3Q9dHx8e307dmFyIG49c3VwcG9ydHNDb2xvcj9zdXBwb3J0c0NvbG9yLmxldmVsOjA7ZS5sZXZlbD12b2lkIDA9PT10LmxldmVsP246dC5sZXZlbCxlLmVuYWJsZWQ9ImVuYWJsZWQiaW4gdD90LmVuYWJsZWQ6ZS5sZXZlbD4wfWZ1bmN0aW9uIG4oZSl7aWYoIXRoaXN8fCEodGhpcyBpbnN0YW5jZW9mIG4pfHx0aGlzLnRlbXBsYXRlKXt2YXIgcj17fTtyZXR1cm4gdChyLGUpLHIudGVtcGxhdGU9ZnVuY3Rpb24oKXt2YXIgZT1bXS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7cmV0dXJuIG8uYXBwbHkobnVsbCxbci50ZW1wbGF0ZV0uY29uY2F0KGUpKX0sT2JqZWN0LnNldFByb3RvdHlwZU9mKHIsbi5wcm90b3R5cGUpLE9iamVjdC5zZXRQcm90b3R5cGVPZihyLnRlbXBsYXRlLHIpLHIudGVtcGxhdGUuY29uc3RydWN0b3I9bixyLnRlbXBsYXRlfXQodGhpcyxlKX1mdW5jdGlvbiByKGUsdCxuKXt2YXIgcj1mdW5jdGlvbiBlKCl7cmV0dXJuIGkuYXBwbHkoZSxhcmd1bWVudHMpfTtyLl9zdHlsZXM9ZSxyLl9lbXB0eT10O3ZhciBvPXRoaXM7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShyLCJsZXZlbCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8ubGV2ZWx9LHNldDpmdW5jdGlvbihlKXtvLmxldmVsPWV9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHIsImVuYWJsZWQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBvLmVuYWJsZWR9LHNldDpmdW5jdGlvbihlKXtvLmVuYWJsZWQ9ZX19KSxyLmhhc0dyZXk9dGhpcy5oYXNHcmV5fHwiZ3JheSI9PT1ufHwiZ3JleSI9PT1uLHIuX19wcm90b19fPWcscn1mdW5jdGlvbiBpKCl7dmFyIGU9YXJndW1lbnRzLHQ9ZS5sZW5ndGgsbj1TdHJpbmcoYXJndW1lbnRzWzBdKTtpZigwPT09dClyZXR1cm4iIjtpZih0PjEpZm9yKHZhciByPTE7cjx0O3IrKyluKz0iICIrZVtyXTtpZighdGhpcy5lbmFibGVkfHx0aGlzLmxldmVsPD0wfHwhbilyZXR1cm4gdGhpcy5fZW1wdHk/IiI6bjt2YXIgaT1hbnNpU3R5bGVzLmRpbS5vcGVuO2EmJnRoaXMuaGFzR3JleSYmKGFuc2lTdHlsZXMuZGltLm9wZW49IiIpO3ZhciBvPSEwLHM9ITEsdT12b2lkIDA7dHJ5e2Zvcih2YXIgYyxsPXRoaXMuX3N0eWxlcy5zbGljZSgpLnJldmVyc2UoKVtTeW1ib2wuaXRlcmF0b3JdKCk7IShvPShjPWwubmV4dCgpKS5kb25lKTtvPSEwKXt2YXIgcD1jLnZhbHVlO249cC5vcGVuK24ucmVwbGFjZShwLmNsb3NlUmUscC5vcGVuKStwLmNsb3NlLG49bi5yZXBsYWNlKC9ccj9cbi9nLCIiLmNvbmNhdChwLmNsb3NlLCIkJiIpLmNvbmNhdChwLm9wZW4pKX19Y2F0Y2goZSl7cz0hMCx1PWV9ZmluYWxseXt0cnl7b3x8bnVsbD09bC5yZXR1cm58fGwucmV0dXJuKCl9ZmluYWxseXtpZihzKXRocm93IHV9fXJldHVybiBhbnNpU3R5bGVzLmRpbS5vcGVuPWksbn1mdW5jdGlvbiBvKGUsdCl7aWYoIUFycmF5LmlzQXJyYXkodCkpcmV0dXJuW10uc2xpY2UuY2FsbChhcmd1bWVudHMsMSkuam9pbigiICIpO2Zvcih2YXIgbj1bXS5zbGljZS5jYWxsKGFyZ3VtZW50cywyKSxyPVt0LnJhd1swXV0saT0xO2k8dC5sZW5ndGg7aSsrKXIucHVzaChTdHJpbmcobltpLTFdKS5yZXBsYWNlKC9be31cXF0vZywiXFwkJiIpKSxyLnB1c2goU3RyaW5nKHQucmF3W2ldKSk7cmV0dXJuIHRlbXBsYXRlcyhlLHIuam9pbigiIikpfXZhciBhPSJ3aW4zMiI9PT1wcm9jZXNzLnBsYXRmb3JtJiYhKHByb2Nlc3MuZW52LlRFUk18fCIiKS50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoInh0ZXJtIikscz1bImFuc2kiLCJhbnNpIiwiYW5zaTI1NiIsImFuc2kxNm0iXSx1PW5ldyBTZXQoWyJncmF5Il0pLGM9T2JqZWN0LmNyZWF0ZShudWxsKTthJiYoYW5zaVN0eWxlcy5ibHVlLm9wZW49Ilx4MWJbOTRtIik7Zm9yKHZhciBsPU9iamVjdC5rZXlzKGFuc2lTdHlsZXMpLHA9MDtwPGwubGVuZ3RoO3ArKykhZnVuY3Rpb24oKXt2YXIgZT1sW3BdO2Fuc2lTdHlsZXNbZV0uY2xvc2VSZT1uZXcgUmVnRXhwKGVzY2FwZVN0cmluZ1JlZ2V4cChhbnNpU3R5bGVzW2VdLmNsb3NlKSwiZyIpLGNbZV09e2dldDpmdW5jdGlvbigpe3ZhciB0PWFuc2lTdHlsZXNbZV07cmV0dXJuIHIuY2FsbCh0aGlzLHRoaXMuX3N0eWxlcz90aGlzLl9zdHlsZXMuY29uY2F0KHQpOlt0XSx0aGlzLl9lbXB0eSxlKX19fSgpO2MudmlzaWJsZT17Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHIuY2FsbCh0aGlzLHRoaXMuX3N0eWxlc3x8W10sITAsInZpc2libGUiKX19LGFuc2lTdHlsZXMuY29sb3IuY2xvc2VSZT1uZXcgUmVnRXhwKGVzY2FwZVN0cmluZ1JlZ2V4cChhbnNpU3R5bGVzLmNvbG9yLmNsb3NlKSwiZyIpO2Zvcih2YXIgZj1PYmplY3Qua2V5cyhhbnNpU3R5bGVzLmNvbG9yLmFuc2kpLGQ9MDtkPGYubGVuZ3RoO2QrKyl7KGZ1bmN0aW9uKCl7dmFyIGU9ZltkXTtpZih1LmhhcyhlKSlyZXR1cm4iY29udGludWUiO2NbZV09e2dldDpmdW5jdGlvbigpe3ZhciB0PXRoaXMubGV2ZWw7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIG49YW5zaVN0eWxlcy5jb2xvcltzW3RdXVtlXS5hcHBseShudWxsLGFyZ3VtZW50cyksaT17b3BlbjpuLGNsb3NlOmFuc2lTdHlsZXMuY29sb3IuY2xvc2UsY2xvc2VSZTphbnNpU3R5bGVzLmNvbG9yLmNsb3NlUmV9O3JldHVybiByLmNhbGwodGhpcyx0aGlzLl9zdHlsZXM/dGhpcy5fc3R5bGVzLmNvbmNhdChpKTpbaV0sdGhpcy5fZW1wdHksZSl9fX19KSgpfWFuc2lTdHlsZXMuYmdDb2xvci5jbG9zZVJlPW5ldyBSZWdFeHAoZXNjYXBlU3RyaW5nUmVnZXhwKGFuc2lTdHlsZXMuYmdDb2xvci5jbG9zZSksImciKTtmb3IodmFyIGg9T2JqZWN0LmtleXMoYW5zaVN0eWxlcy5iZ0NvbG9yLmFuc2kpLG09MDttPGgubGVuZ3RoO20rKyl7KGZ1bmN0aW9uKCl7dmFyIGU9aFttXTtpZih1LmhhcyhlKSlyZXR1cm4iY29udGludWUiO3ZhciB0PSJiZyIrZVswXS50b1VwcGVyQ2FzZSgpK2Uuc2xpY2UoMSk7Y1t0XT17Z2V0OmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5sZXZlbDtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgbj1hbnNpU3R5bGVzLmJnQ29sb3Jbc1t0XV1bZV0uYXBwbHkobnVsbCxhcmd1bWVudHMpLGk9e29wZW46bixjbG9zZTphbnNpU3R5bGVzLmJnQ29sb3IuY2xvc2UsY2xvc2VSZTphbnNpU3R5bGVzLmJnQ29sb3IuY2xvc2VSZX07cmV0dXJuIHIuY2FsbCh0aGlzLHRoaXMuX3N0eWxlcz90aGlzLl9zdHlsZXMuY29uY2F0KGkpOltpXSx0aGlzLl9lbXB0eSxlKX19fX0pKCl9dmFyIGc9T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoZnVuY3Rpb24oKXt9LGMpO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKG4ucHJvdG90eXBlLGMpLGUuZXhwb3J0cz1uKCksZS5leHBvcnRzLnN1cHBvcnRzQ29sb3I9c3VwcG9ydHNDb2xvcixlLmV4cG9ydHMuZGVmYXVsdD1lLmV4cG9ydHN9KSxsaWIkMj1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oKXt2YXIgZT1hKGpzVG9rZW5zKTtyZXR1cm4gbj1mdW5jdGlvbigpe3JldHVybiBlfSxlfWZ1bmN0aW9uIHIoKXt2YXIgZT1vKHV0aWxzKTtyZXR1cm4gcj1mdW5jdGlvbigpe3JldHVybiBlfSxlfWZ1bmN0aW9uIGkoKXt2YXIgZT1vKGNoYWxrKTtyZXR1cm4gaT1mdW5jdGlvbigpe3JldHVybiBlfSxlfWZ1bmN0aW9uIG8oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGEoZSl7aWYoZSYmZS5fX2VzTW9kdWxlKXJldHVybiBlO3ZhciB0PXt9O2lmKG51bGwhPWUpZm9yKHZhciBuIGluIGUpaWYoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUsbikpe3ZhciByPU9iamVjdC5kZWZpbmVQcm9wZXJ0eSYmT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcj9PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGUsbik6e307ci5nZXR8fHIuc2V0P09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LG4scik6dFtuXT1lW25dfXJldHVybiB0LmRlZmF1bHQ9ZSx0fWZ1bmN0aW9uIHMoZSl7cmV0dXJue2tleXdvcmQ6ZS5jeWFuLGNhcGl0YWxpemVkOmUueWVsbG93LGpzeF90YWc6ZS55ZWxsb3cscHVuY3R1YXRvcjplLnllbGxvdyxudW1iZXI6ZS5tYWdlbnRhLHN0cmluZzplLmdyZWVuLHJlZ2V4OmUubWFnZW50YSxjb21tZW50OmUuZ3JleSxpbnZhbGlkOmUud2hpdGUuYmdSZWQuYm9sZH19ZnVuY3Rpb24gdShlKXt2YXIgdD1lLnNsaWNlKC0yKSxpPV9zbGljZWRUb0FycmF5KHQsMiksbz1pWzBdLGE9aVsxXSxzPSgwLG4oKS5tYXRjaFRvVG9rZW4pKGUpO2lmKCJuYW1lIj09PXMudHlwZSl7aWYocigpLmRlZmF1bHQua2V5d29yZC5pc1Jlc2VydmVkV29yZEVTNihzLnZhbHVlKSlyZXR1cm4ia2V5d29yZCI7aWYoaC50ZXN0KHMudmFsdWUpJiYoIjwiPT09YVtvLTFdfHwiPC8iPT1hLnN1YnN0cihvLTIsMikpKXJldHVybiJqc3hfdGFnIjtpZihzLnZhbHVlWzBdIT09cy52YWx1ZVswXS50b0xvd2VyQ2FzZSgpKXJldHVybiJjYXBpdGFsaXplZCJ9cmV0dXJuInB1bmN0dWF0b3IiPT09cy50eXBlJiZtLnRlc3Qocy52YWx1ZSk/ImJyYWNrZXQiOiJpbnZhbGlkIiE9PXMudHlwZXx8IkAiIT09cy52YWx1ZSYmIiMiIT09cy52YWx1ZT9zLnR5cGU6InB1bmN0dWF0b3IifWZ1bmN0aW9uIGMoZSx0KXtyZXR1cm4gdC5yZXBsYWNlKG4oKS5kZWZhdWx0LGZ1bmN0aW9uKCl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1uZXcgQXJyYXkodCkscj0wO3I8dDtyKyspbltyXT1hcmd1bWVudHNbcl07dmFyIGk9dShuKSxvPWVbaV07cmV0dXJuIG8/blswXS5zcGxpdChkKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIG8oZSl9KS5qb2luKCJcbiIpOm5bMF19KX1mdW5jdGlvbiBsKGUpe3JldHVybiBpKCkuZGVmYXVsdC5zdXBwb3J0c0NvbG9yfHxlLmZvcmNlQ29sb3J9ZnVuY3Rpb24gcChlKXt2YXIgdD1pKCkuZGVmYXVsdDtyZXR1cm4gZS5mb3JjZUNvbG9yJiYodD1uZXcoaSgpLmRlZmF1bHQuY29uc3RydWN0b3IpKHtlbmFibGVkOiEwLGxldmVsOjF9KSksdH1mdW5jdGlvbiBmKGUpe3ZhciB0PWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7fTtpZihsKHQpKXtyZXR1cm4gYyhzKHAodCkpLGUpfXJldHVybiBlfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnNob3VsZEhpZ2hsaWdodD1sLHQuZ2V0Q2hhbGs9cCx0LmRlZmF1bHQ9Zjt2YXIgZD0vXHJcbnxbXG5cclx1MjAyOFx1MjAyOV0vLGg9L15bYS16XVtcdy1dKiQvaSxtPS9eWygpW1xde31dJC99KTt1bndyYXBFeHBvcnRzKGxpYiQyKTt2YXIgbGliJDE9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKCl7dmFyIGU9cihsaWIkMik7cmV0dXJuIG49ZnVuY3Rpb24oKXtyZXR1cm4gZX0sZX1mdW5jdGlvbiByKGUpe2lmKGUmJmUuX19lc01vZHVsZSlyZXR1cm4gZTt2YXIgdD17fTtpZihudWxsIT1lKWZvcih2YXIgbiBpbiBlKWlmKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLG4pKXt2YXIgcj1PYmplY3QuZGVmaW5lUHJvcGVydHkmJk9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3I/T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihlLG4pOnt9O3IuZ2V0fHxyLnNldD9PYmplY3QuZGVmaW5lUHJvcGVydHkodCxuLHIpOnRbbl09ZVtuXX1yZXR1cm4gdC5kZWZhdWx0PWUsdH1mdW5jdGlvbiBpKGUpe3JldHVybntndXR0ZXI6ZS5ncmV5LG1hcmtlcjplLnJlZC5ib2xkLG1lc3NhZ2U6ZS5yZWQuYm9sZH19ZnVuY3Rpb24gbyhlLHQsbil7dmFyIHI9T2JqZWN0LmFzc2lnbih7Y29sdW1uOjAsbGluZTotMX0sZS5zdGFydCksaT1PYmplY3QuYXNzaWduKHt9LHIsZS5lbmQpLG89bnx8e30sYT1vLmxpbmVzQWJvdmUscz12b2lkIDA9PT1hPzI6YSx1PW8ubGluZXNCZWxvdyxjPXZvaWQgMD09PXU/Mzp1LGw9ci5saW5lLHA9ci5jb2x1bW4sZj1pLmxpbmUsZD1pLmNvbHVtbixoPU1hdGgubWF4KGwtKHMrMSksMCksbT1NYXRoLm1pbih0Lmxlbmd0aCxmK2MpOy0xPT09bCYmKGg9MCksLTE9PT1mJiYobT10Lmxlbmd0aCk7dmFyIGc9Zi1sLHk9e307aWYoZylmb3IodmFyIHY9MDt2PD1nO3YrKyl7dmFyIGI9ditsO2lmKHApaWYoMD09PXYpe3ZhciB4PXRbYi0xXS5sZW5ndGg7eVtiXT1bcCx4LXBdfWVsc2UgaWYodj09PWcpeVtiXT1bMCxkXTtlbHNle3ZhciBDPXRbYi12XS5sZW5ndGg7eVtiXT1bMCxDXX1lbHNlIHlbYl09ITB9ZWxzZSB5W2xdPXA9PT1kPyFwfHxbcCwwXTpbcCxkLXBdO3JldHVybntzdGFydDpoLGVuZDptLG1hcmtlckxpbmVzOnl9fWZ1bmN0aW9uIGEoZSx0KXt2YXIgcj1hcmd1bWVudHMubGVuZ3RoPjImJnZvaWQgMCE9PWFyZ3VtZW50c1syXT9hcmd1bWVudHNbMl06e30sYT0oci5oaWdobGlnaHRDb2RlfHxyLmZvcmNlQ29sb3IpJiYoMCxuKCkuc2hvdWxkSGlnaGxpZ2h0KShyKSxzPSgwLG4oKS5nZXRDaGFsaykociksdT1pKHMpLGw9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gYT9lKHQpOnR9O2EmJihlPSgwLG4oKS5kZWZhdWx0KShlLHIpKTt2YXIgcD1lLnNwbGl0KGMpLGY9byh0LHAsciksZD1mLnN0YXJ0LGg9Zi5lbmQsbT1mLm1hcmtlckxpbmVzLGc9dC5zdGFydCYmIm51bWJlciI9PT10eXBlb2YgdC5zdGFydC5jb2x1bW4seT1TdHJpbmcoaCkubGVuZ3RoLHY9cC5zbGljZShkLGgpLm1hcChmdW5jdGlvbihlLHQpe3ZhciBuPWQrMSt0LGk9IiAiLmNvbmNhdChuKS5zbGljZSgteSksbz0iICIuY29uY2F0KGksIiB8ICIpLGE9bVtuXSxzPSFtW24rMV07aWYoYSl7dmFyIGM9IiI7aWYoQXJyYXkuaXNBcnJheShhKSl7dmFyIHA9ZS5zbGljZSgwLE1hdGgubWF4KGFbMF0tMSwwKSkucmVwbGFjZSgvW15cdF0vZywiICIpLGY9YVsxXXx8MTtjPVsiXG4gIixsKHUuZ3V0dGVyLG8ucmVwbGFjZSgvXGQvZywiICIpKSxwLGwodS5tYXJrZXIsIl4iKS5yZXBlYXQoZildLmpvaW4oIiIpLHMmJnIubWVzc2FnZSYmKGMrPSIgIitsKHUubWVzc2FnZSxyLm1lc3NhZ2UpKX1yZXR1cm5bbCh1Lm1hcmtlciwiPiIpLGwodS5ndXR0ZXIsbyksZSxjXS5qb2luKCIiKX1yZXR1cm4iICIuY29uY2F0KGwodS5ndXR0ZXIsbykpLmNvbmNhdChlKX0pLmpvaW4oIlxuIik7cmV0dXJuIHIubWVzc2FnZSYmIWcmJih2PSIiLmNvbmNhdCgiICIucmVwZWF0KHkrMSkpLmNvbmNhdChyLm1lc3NhZ2UsIlxuIikuY29uY2F0KHYpKSxhP3MucmVzZXQodik6dn1mdW5jdGlvbiBzKGUsdCxuKXt2YXIgcj1hcmd1bWVudHMubGVuZ3RoPjMmJnZvaWQgMCE9PWFyZ3VtZW50c1szXT9hcmd1bWVudHNbM106e307aWYoIXUpe3U9ITA7dmFyIGk9IlBhc3NpbmcgbGluZU51bWJlciBhbmQgY29sTnVtYmVyIGlzIGRlcHJlY2F0ZWQgdG8gQGJhYmVsL2NvZGUtZnJhbWUuIFBsZWFzZSB1c2UgYGNvZGVGcmFtZUNvbHVtbnNgLiI7aWYocHJvY2Vzcy5lbWl0V2FybmluZylwcm9jZXNzLmVtaXRXYXJuaW5nKGksIkRlcHJlY2F0aW9uV2FybmluZyIpO2Vsc2V7bmV3IEVycm9yKGkpLm5hbWU9IkRlcHJlY2F0aW9uV2FybmluZyIsY29uc29sZS53YXJuKG5ldyBFcnJvcihpKSl9fXJldHVybiBuPU1hdGgubWF4KG4sMCksYShlLHtzdGFydDp7Y29sdW1uOm4sbGluZTp0fX0scil9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuY29kZUZyYW1lQ29sdW1ucz1hLHQuZGVmYXVsdD1zO3ZhciB1PSExLGM9L1xyXG58W1xuXHJcdTIwMjhcdTIwMjldL30pO3Vud3JhcEV4cG9ydHMobGliJDEpO3ZhciBwYXRoJDU9e30scGF0aCQ3PU9iamVjdC5mcmVlemUoe2RlZmF1bHQ6cGF0aCQ1LF9fbW9kdWxlRXhwb3J0czpwYXRoJDV9KSxwYXRoJDQ9cGF0aCQ3JiZwYXRoJDV8fHBhdGgkNyxDb25maWdFcnJvciQxPWVycm9ycy5Db25maWdFcnJvcixsb2NTdGFydD1sb2MubG9jU3RhcnQsbG9jRW5kPWxvYy5sb2NFbmQsb3duTmFtZXM9T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMsb3duRGVzY3JpcHRvcj1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yLHBhcnNlcj17cGFyc2U6cGFyc2UkMixyZXNvbHZlUGFyc2VyOnJlc29sdmVQYXJzZXIkMX0scGF0aCQ5PXt9LHBhdGgkMTE9T2JqZWN0LmZyZWV6ZSh7ZGVmYXVsdDpwYXRoJDksX19tb2R1bGVFeHBvcnRzOnBhdGgkOX0pLHBhdGgkOD1wYXRoJDExJiZwYXRoJDl8fHBhdGgkMTEsVW5kZWZpbmVkUGFyc2VyRXJyb3I9ZXJyb3JzLlVuZGVmaW5lZFBhcnNlckVycm9yLGdldFN1cHBvcnRJbmZvJDE9c3VwcG9ydC5nZXRTdXBwb3J0SW5mbyxyZXNvbHZlUGFyc2VyPXBhcnNlci5yZXNvbHZlUGFyc2VyLGhpZGRlbkRlZmF1bHRzPXthc3RGb3JtYXQ6ImVzdHJlZSIscHJpbnRlcjp7fSxsb2NTdGFydDpudWxsLGxvY0VuZDpudWxsfSxvcHRpb25zPXtub3JtYWxpemU6bm9ybWFsaXplLGhpZGRlbkRlZmF1bHRzOmhpZGRlbkRlZmF1bHRzLGluZmVyUGFyc2VyOmluZmVyUGFyc2VyfSxtYXNzYWdlQXN0PW1hc3NhZ2VBU1QsYXNzZXJ0PXtvazpmdW5jdGlvbigpe30sc3RyaWN0RXF1YWw6ZnVuY3Rpb24oKXt9fSxsaW5lU3VmZml4Qm91bmRhcnk9e3R5cGU6ImxpbmUtc3VmZml4LWJvdW5kYXJ5In0sYnJlYWtQYXJlbnQkMT17dHlwZToiYnJlYWstcGFyZW50In0sbGluZSQyPXt0eXBlOiJsaW5lIn0sc29mdGxpbmU9e3R5cGU6ImxpbmUiLHNvZnQ6ITB9LGhhcmRsaW5lJDE9Y29uY2F0JDEoW3t0eXBlOiJsaW5lIixoYXJkOiEwfSxicmVha1BhcmVudCQxXSksbGl0ZXJhbGxpbmU9Y29uY2F0JDEoW3t0eXBlOiJsaW5lIixoYXJkOiEwLGxpdGVyYWw6ITB9LGJyZWFrUGFyZW50JDFdKSxjdXJzb3IkMT17dHlwZToiY3Vyc29yIixwbGFjZWhvbGRlcjpTeW1ib2woImN1cnNvciIpfSxkb2NCdWlsZGVycz17Y29uY2F0OmNvbmNhdCQxLGpvaW46am9pbiQxLGxpbmU6bGluZSQyLHNvZnRsaW5lOnNvZnRsaW5lLGhhcmRsaW5lOmhhcmRsaW5lJDEsbGl0ZXJhbGxpbmU6bGl0ZXJhbGxpbmUsZ3JvdXA6Z3JvdXAsY29uZGl0aW9uYWxHcm91cDpjb25kaXRpb25hbEdyb3VwLGZpbGw6ZmlsbCxsaW5lU3VmZml4OmxpbmVTdWZmaXgkMSxsaW5lU3VmZml4Qm91bmRhcnk6bGluZVN1ZmZpeEJvdW5kYXJ5LGN1cnNvcjpjdXJzb3IkMSxicmVha1BhcmVudDpicmVha1BhcmVudCQxLGlmQnJlYWs6aWZCcmVhayxpbmRlbnQ6aW5kZW50JDEsYWxpZ246YWxpZ24sYWRkQWxpZ25tZW50VG9Eb2M6YWRkQWxpZ25tZW50VG9Eb2MsbWFya0FzUm9vdDptYXJrQXNSb290LGRlZGVudFRvUm9vdDpkZWRlbnRUb1Jvb3QsZGVkZW50OmRlZGVudCQxfSxhbnNpUmVnZXg9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSl7ZS5leHBvcnRzPWZ1bmN0aW9uKCl7dmFyIGU9WyJbXFx1MDAxQlxcdTAwOUJdW1tcXF0oKSM7P10qKD86KD86KD86W2EtekEtWlxcZF0qKD86O1thLXpBLVpcXGRdKikqKT9cXHUwMDA3KSIsIig/Oig/OlxcZHsxLDR9KD86O1xcZHswLDR9KSopP1tcXGRBLVBSWmNmLW50cXJ5PT48fl0pKSJdLmpvaW4oInwiKTtyZXR1cm4gbmV3IFJlZ0V4cChlLCJnIil9fSksc3RyaXBBbnNpPWZ1bmN0aW9uKGUpe3JldHVybiJzdHJpbmciPT09dHlwZW9mIGU/ZS5yZXBsYWNlKGFuc2lSZWdleCgpLCIiKTplfSxpc0Z1bGx3aWR0aENvZGVQb2ludD1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlKXtlLmV4cG9ydHM9ZnVuY3Rpb24oZSl7cmV0dXJuIU51bWJlci5pc05hTihlKSYmKGU+PTQzNTImJihlPD00NDQ3fHw5MDAxPT09ZXx8OTAwMj09PWV8fDExOTA0PD1lJiZlPD0xMjg3MSYmMTIzNTEhPT1lfHwxMjg4MDw9ZSYmZTw9MTk5MDN8fDE5OTY4PD1lJiZlPD00MjE4Mnx8NDMzNjA8PWUmJmU8PTQzMzg4fHw0NDAzMjw9ZSYmZTw9NTUyMDN8fDYzNzQ0PD1lJiZlPD02NDI1NXx8NjUwNDA8PWUmJmU8PTY1MDQ5fHw2NTA3Mjw9ZSYmZTw9NjUxMzF8fDY1MjgxPD1lJiZlPD02NTM3Nnx8NjU1MDQ8PWUmJmU8PTY1NTEwfHwxMTA1OTI8PWUmJmU8PTExMDU5M3x8MTI3NDg4PD1lJiZlPD0xMjc1Njl8fDEzMTA3Mjw9ZSYmZTw9MjYyMTQxKSl9fSksc3RyaW5nV2lkdGg9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSl7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe2lmKCJzdHJpbmciIT09dHlwZW9mIGV8fDA9PT1lLmxlbmd0aClyZXR1cm4gMDtlPXN0cmlwQW5zaShlKTtmb3IodmFyIHQ9MCxuPTA7bjxlLmxlbmd0aDtuKyspe3ZhciByPWUuY29kZVBvaW50QXQobik7cjw9MzF8fHI+PTEyNyYmcjw9MTU5fHwocj49NzY4JiZyPD04Nzl8fChyPjY1NTM1JiZuKyssdCs9aXNGdWxsd2lkdGhDb2RlUG9pbnQocik/MjoxKSl9cmV0dXJuIHR9fSksZW1vamlSZWdleCQxPWZ1bmN0aW9uKCl7cmV0dXJuL1x1RDgzQ1x1REZGNFx1REI0MFx1REM2N1x1REI0MFx1REM2Mig/Olx1REI0MFx1REM2NVx1REI0MFx1REM2RVx1REI0MFx1REM2N3xcdURCNDBcdURDNzdcdURCNDBcdURDNkNcdURCNDBcdURDNzN8XHVEQjQwXHVEQzczXHVEQjQwXHVEQzYzXHVEQjQwXHVEQzc0KVx1REI0MFx1REM3RnxcdUQ4M0RcdURDNjlcdTIwMERcdUQ4M0RcdURDNjlcdTIwMEQoPzpcdUQ4M0RcdURDNjZcdTIwMERcdUQ4M0RcdURDNjZ8XHVEODNEXHVEQzY3XHUyMDBEKD86XHVEODNEW1x1REM2Nlx1REM2N10pKXxcdUQ4M0RcdURDNjgoPzpcdTIwMEQoPzpcdTI3NjRcdUZFMEZcdTIwMEQoPzpcdUQ4M0RcdURDOEJcdTIwMEQpP1x1RDgzRFx1REM2OHwoPzpcdUQ4M0RbXHVEQzY4XHVEQzY5XSlcdTIwMEQoPzpcdUQ4M0RcdURDNjZcdTIwMERcdUQ4M0RcdURDNjZ8XHVEODNEXHVEQzY3XHUyMDBEKD86XHVEODNEW1x1REM2Nlx1REM2N10pKXxcdUQ4M0RcdURDNjZcdTIwMERcdUQ4M0RcdURDNjZ8XHVEODNEXHVEQzY3XHUyMDBEKD86XHVEODNEW1x1REM2Nlx1REM2N10pfFtcdTI2OTVcdTI2OTZcdTI3MDhdXHVGRTBGfFx1RDgzQ1tcdURGM0VcdURGNzNcdURGOTNcdURGQTRcdURGQThcdURGRUJcdURGRURdfFx1RDgzRFtcdURDQkJcdURDQkNcdUREMjdcdUREMkNcdURFODBcdURFOTJdKXwoPzpcdUQ4M0NbXHVERkZCLVx1REZGRl0pXHUyMDBEW1x1MjY5NVx1MjY5Nlx1MjcwOF1cdUZFMEZ8KD86XHVEODNDW1x1REZGQi1cdURGRkZdKVx1MjAwRCg/Olx1RDgzQ1tcdURGM0VcdURGNzNcdURGOTNcdURGQTRcdURGQThcdURGRUJcdURGRURdfFx1RDgzRFtcdURDQkJcdURDQkNcdUREMjdcdUREMkNcdURFODBcdURFOTJdKSl8XHVEODNEXHVEQzY5XHUyMDBEKD86XHUyNzY0XHVGRTBGXHUyMDBEKD86XHVEODNEXHVEQzhCXHUyMDBEKD86XHVEODNEW1x1REM2OFx1REM2OV0pfFx1RDgzRFtcdURDNjhcdURDNjldKXxcdUQ4M0NbXHVERjNFXHVERjczXHVERjkzXHVERkE0XHVERkE4XHVERkVCXHVERkVEXXxcdUQ4M0RbXHVEQ0JCXHVEQ0JDXHVERDI3XHVERDJDXHVERTgwXHVERTkyXSl8XHVEODNEXHVEQzY5XHUyMDBEXHVEODNEXHVEQzY2XHUyMDBEXHVEODNEXHVEQzY2fCg/Olx1RDgzRFx1REM0MVx1RkUwRlx1MjAwRFx1RDgzRFx1RERFOHxcdUQ4M0RcdURDNjkoPzpcdUQ4M0NbXHVERkZCLVx1REZGRl0pXHUyMDBEW1x1MjY5NVx1MjY5Nlx1MjcwOF18KD86KD86XHUyNkY5fFx1RDgzQ1tcdURGQ0JcdURGQ0NdfFx1RDgzRFx1REQ3NSlcdUZFMEZ8XHVEODNEXHVEQzZGfFx1RDgzRVtcdUREM0NcdUREREVcdUREREZdKVx1MjAwRFtcdTI2NDBcdTI2NDJdfCg/Olx1MjZGOXxcdUQ4M0NbXHVERkNCXHVERkNDXXxcdUQ4M0RcdURENzUpKD86XHVEODNDW1x1REZGQi1cdURGRkZdKVx1MjAwRFtcdTI2NDBcdTI2NDJdfCg/Olx1RDgzQ1tcdURGQzNcdURGQzRcdURGQ0FdfFx1RDgzRFtcdURDNkVcdURDNzFcdURDNzNcdURDNzdcdURDODFcdURDODJcdURDODZcdURDODdcdURFNDUtXHVERTQ3XHVERTRCXHVERTREXHVERTRFXHVERUEzXHVERUI0LVx1REVCNl18XHVEODNFW1x1REQyNlx1REQzNy1cdUREMzlcdUREM0RcdUREM0VcdURERDYtXHVEREREXSkoPzooPzpcdUQ4M0NbXHVERkZCLVx1REZGRl0pXHUyMDBEW1x1MjY0MFx1MjY0Ml18XHUyMDBEW1x1MjY0MFx1MjY0Ml0pfFx1RDgzRFx1REM2OVx1MjAwRFtcdTI2OTVcdTI2OTZcdTI3MDhdKVx1RkUwRnxcdUQ4M0RcdURDNjlcdTIwMERcdUQ4M0RcdURDNjdcdTIwMEQoPzpcdUQ4M0RbXHVEQzY2XHVEQzY3XSl8XHVEODNEXHVEQzY5XHUyMDBEXHVEODNEXHVEQzY5XHUyMDBEKD86XHVEODNEW1x1REM2Nlx1REM2N10pfFx1RDgzRFx1REM2OCg/Olx1MjAwRCg/Oig/Olx1RDgzRFtcdURDNjhcdURDNjldKVx1MjAwRCg/Olx1RDgzRFtcdURDNjZcdURDNjddKXxcdUQ4M0RbXHVEQzY2XHVEQzY3XSl8XHVEODNDW1x1REZGQi1cdURGRkZdKXxcdUQ4M0NcdURGRjNcdUZFMEZcdTIwMERcdUQ4M0NcdURGMDh8XHVEODNEXHVEQzY5XHUyMDBEXHVEODNEXHVEQzY3fFx1RDgzRFx1REM2OSg/Olx1RDgzQ1tcdURGRkItXHVERkZGXSlcdTIwMEQoPzpcdUQ4M0NbXHVERjNFXHVERjczXHVERjkzXHVERkE0XHVERkE4XHVERkVCXHVERkVEXXxcdUQ4M0RbXHVEQ0JCXHVEQ0JDXHVERDI3XHVERDJDXHVERTgwXHVERTkyXSl8XHVEODNEXHVEQzY5XHUyMDBEXHVEODNEXHVEQzY2fFx1RDgzQ1x1RERGNFx1RDgzQ1x1RERGMnxcdUQ4M0NcdURERkRcdUQ4M0NcdURERjB8XHVEODNDXHVEREY2XHVEODNDXHVEREU2fFx1RDgzRFx1REM2OSg/Olx1RDgzQ1tcdURGRkItXHVERkZGXSl8XHVEODNDXHVEREZDKD86XHVEODNDW1x1RERFQlx1RERGOF0pfFx1RDgzQ1x1RERFQig/Olx1RDgzQ1tcdURERUUtXHVEREYwXHVEREYyXHVEREY0XHVEREY3XSl8XHVEODNDXHVEREU5KD86XHVEODNDW1x1RERFQVx1RERFQ1x1RERFRlx1RERGMFx1RERGMlx1RERGNFx1RERGRl0pfFx1RDgzQ1x1RERFNyg/Olx1RDgzQ1tcdURERTZcdURERTdcdURERTktXHVEREVGXHVEREYxLVx1RERGNFx1RERGNi1cdURERjlcdURERkJcdURERkNcdURERkVcdURERkZdKXxcdUQ4M0NcdURERjEoPzpcdUQ4M0NbXHVEREU2LVx1RERFOFx1RERFRVx1RERGMFx1RERGNy1cdURERkJcdURERkVdKXxcdUQ4M0NcdURERkUoPzpcdUQ4M0NbXHVEREVBXHVEREY5XSl8XHVEODNDXHVEREY5KD86XHVEODNDW1x1RERFNlx1RERFOFx1RERFOVx1RERFQi1cdURERURcdURERUYtXHVEREY0XHVEREY3XHVEREY5XHVEREZCXHVEREZDXHVEREZGXSl8XHVEODNDXHVEREY1KD86XHVEODNDW1x1RERFNlx1RERFQS1cdURERURcdURERjAtXHVEREYzXHVEREY3LVx1RERGOVx1RERGQ1x1RERGRV0pfFx1RDgzQ1x1RERFRig/Olx1RDgzQ1tcdURERUFcdURERjJcdURERjRcdURERjVdKXxcdUQ4M0NcdURERUQoPzpcdUQ4M0NbXHVEREYwXHVEREYyXHVEREYzXHVEREY3XHVEREY5XHVEREZBXSl8XHVEODNDXHVEREVFKD86XHVEODNDW1x1RERFOC1cdURERUFcdURERjEtXHVEREY0XHVEREY2LVx1RERGOV0pfFx1RDgzQ1x1RERGQig/Olx1RDgzQ1tcdURERTZcdURERThcdURERUFcdURERUNcdURERUVcdURERjNcdURERkFdKXxcdUQ4M0NcdURERUMoPzpcdUQ4M0NbXHVEREU2XHVEREU3XHVEREU5LVx1RERFRVx1RERGMS1cdURERjNcdURERjUtXHVEREZBXHVEREZDXHVEREZFXSl8XHVEODNDXHVEREY3KD86XHVEODNDW1x1RERFQVx1RERGNFx1RERGOFx1RERGQVx1RERGQ10pfFx1RDgzQ1x1RERFQSg/Olx1RDgzQ1tcdURERTZcdURERThcdURERUFcdURERUNcdURERURcdURERjctXHVEREZBXSl8XHVEODNDXHVEREZBKD86XHVEODNDW1x1RERFNlx1RERFQ1x1RERGMlx1RERGM1x1RERGOFx1RERGRVx1RERGRl0pfFx1RDgzQ1x1RERFOCg/Olx1RDgzQ1tcdURERTZcdURERThcdURERTlcdURERUItXHVEREVFXHVEREYwLVx1RERGNVx1RERGN1x1RERGQS1cdURERkZdKXxcdUQ4M0NcdURERTYoPzpcdUQ4M0NbXHVEREU4LVx1RERFQ1x1RERFRVx1RERGMVx1RERGMlx1RERGNFx1RERGNi1cdURERkFcdURERkNcdURERkRcdURERkZdKXxbI1wqMC05XVx1RkUwRlx1MjBFM3xcdUQ4M0NcdURERjgoPzpcdUQ4M0NbXHVEREU2LVx1RERFQVx1RERFQy1cdURERjRcdURERjctXHVEREY5XHVEREZCXHVEREZELVx1RERGRl0pfFx1RDgzQ1x1RERGRig/Olx1RDgzQ1tcdURERTZcdURERjJcdURERkNdKXxcdUQ4M0NcdURERjAoPzpcdUQ4M0NbXHVEREVBXHVEREVDLVx1RERFRVx1RERGMlx1RERGM1x1RERGNVx1RERGN1x1RERGQ1x1RERGRVx1RERGRl0pfFx1RDgzQ1x1RERGMyg/Olx1RDgzQ1tcdURERTZcdURERThcdURERUEtXHVEREVDXHVEREVFXHVEREYxXHVEREY0XHVEREY1XHVEREY3XHVEREZBXHVEREZGXSl8XHVEODNDXHVEREYyKD86XHVEODNDW1x1RERFNlx1RERFOC1cdURERURcdURERjAtXHVEREZGXSl8KD86XHVEODNDW1x1REZDM1x1REZDNFx1REZDQV18XHVEODNEW1x1REM2RVx1REM3MVx1REM3M1x1REM3N1x1REM4MVx1REM4Mlx1REM4Nlx1REM4N1x1REU0NS1cdURFNDdcdURFNEJcdURFNERcdURFNEVcdURFQTNcdURFQjQtXHVERUI2XXxcdUQ4M0VbXHVERDI2XHVERDM3LVx1REQzOVx1REQzRFx1REQzRVx1RERENi1cdURERERdKSg/Olx1RDgzQ1tcdURGRkItXHVERkZGXSl8KD86XHUyNkY5fFx1RDgzQ1tcdURGQ0JcdURGQ0NdfFx1RDgzRFx1REQ3NSkoPzpcdUQ4M0NbXHVERkZCLVx1REZGRl0pfCg/OltcdTI2MURcdTI3MEEtXHUyNzBEXXxcdUQ4M0NbXHVERjg1XHVERkMyXHVERkM3XXxcdUQ4M0RbXHVEQzQyXHVEQzQzXHVEQzQ2LVx1REM1MFx1REM2Nlx1REM2N1x1REM3MFx1REM3Mlx1REM3NC1cdURDNzZcdURDNzhcdURDN0NcdURDODNcdURDODVcdURDQUFcdURENzRcdUREN0FcdUREOTBcdUREOTVcdUREOTZcdURFNENcdURFNEZcdURFQzBcdURFQ0NdfFx1RDgzRVtcdUREMTgtXHVERDFDXHVERDFFXHVERDFGXHVERDMwLVx1REQzNlx1REREMS1cdURERDVdKSg/Olx1RDgzQ1tcdURGRkItXHVERkZGXSl8KD86W1x1MjYxRFx1MjZGOVx1MjcwQS1cdTI3MERdfFx1RDgzQ1tcdURGODVcdURGQzItXHVERkM0XHVERkM3XHVERkNBLVx1REZDQ118XHVEODNEW1x1REM0Mlx1REM0M1x1REM0Ni1cdURDNTBcdURDNjYtXHVEQzY5XHVEQzZFXHVEQzcwLVx1REM3OFx1REM3Q1x1REM4MS1cdURDODNcdURDODUtXHVEQzg3XHVEQ0FBXHVERDc0XHVERDc1XHVERDdBXHVERDkwXHVERDk1XHVERDk2XHVERTQ1LVx1REU0N1x1REU0Qi1cdURFNEZcdURFQTNcdURFQjQtXHVERUI2XHVERUMwXHVERUNDXXxcdUQ4M0VbXHVERDE4LVx1REQxQ1x1REQxRVx1REQxRlx1REQyNlx1REQzMC1cdUREMzlcdUREM0RcdUREM0VcdURERDEtXHVEREREXSkoPzpcdUQ4M0NbXHVERkZCLVx1REZGRl0pP3woPzpbXHUyMzFBXHUyMzFCXHUyM0U5LVx1MjNFQ1x1MjNGMFx1MjNGM1x1MjVGRFx1MjVGRVx1MjYxNFx1MjYxNVx1MjY0OC1cdTI2NTNcdTI2N0ZcdTI2OTNcdTI2QTFcdTI2QUFcdTI2QUJcdTI2QkRcdTI2QkVcdTI2QzRcdTI2QzVcdTI2Q0VcdTI2RDRcdTI2RUFcdTI2RjJcdTI2RjNcdTI2RjVcdTI2RkFcdTI2RkRcdTI3MDVcdTI3MEFcdTI3MEJcdTI3MjhcdTI3NENcdTI3NEVcdTI3NTMtXHUyNzU1XHUyNzU3XHUyNzk1LVx1Mjc5N1x1MjdCMFx1MjdCRlx1MkIxQlx1MkIxQ1x1MkI1MFx1MkI1NV18XHVEODNDW1x1REMwNFx1RENDRlx1REQ4RVx1REQ5MS1cdUREOUFcdURERTYtXHVEREZGXHVERTAxXHVERTFBXHVERTJGXHVERTMyLVx1REUzNlx1REUzOC1cdURFM0FcdURFNTBcdURFNTFcdURGMDAtXHVERjIwXHVERjJELVx1REYzNVx1REYzNy1cdURGN0NcdURGN0UtXHVERjkzXHVERkEwLVx1REZDQVx1REZDRi1cdURGRDNcdURGRTAtXHVERkYwXHVERkY0XHVERkY4LVx1REZGRl18XHVEODNEW1x1REMwMC1cdURDM0VcdURDNDBcdURDNDItXHVEQ0ZDXHVEQ0ZGLVx1REQzRFx1REQ0Qi1cdURENEVcdURENTAtXHVERDY3XHVERDdBXHVERDk1XHVERDk2XHVEREE0XHVEREZCLVx1REU0Rlx1REU4MC1cdURFQzVcdURFQ0NcdURFRDAtXHVERUQyXHVERUVCXHVERUVDXHVERUY0LVx1REVGOF18XHVEODNFW1x1REQxMC1cdUREM0FcdUREM0MtXHVERDNFXHVERDQwLVx1REQ0NVx1REQ0Ny1cdURENENcdURENTAtXHVERDZCXHVERDgwLVx1REQ5N1x1RERDMFx1REREMC1cdURERTZdKXwoPzpbI1wqMC05XHhBOVx4QUVcdTIwM0NcdTIwNDlcdTIxMjJcdTIxMzlcdTIxOTQtXHUyMTk5XHUyMUE5XHUyMUFBXHUyMzFBXHUyMzFCXHUyMzI4XHUyM0NGXHUyM0U5LVx1MjNGM1x1MjNGOC1cdTIzRkFcdTI0QzJcdTI1QUFcdTI1QUJcdTI1QjZcdTI1QzBcdTI1RkItXHUyNUZFXHUyNjAwLVx1MjYwNFx1MjYwRVx1MjYxMVx1MjYxNFx1MjYxNVx1MjYxOFx1MjYxRFx1MjYyMFx1MjYyMlx1MjYyM1x1MjYyNlx1MjYyQVx1MjYyRVx1MjYyRlx1MjYzOC1cdTI2M0FcdTI2NDBcdTI2NDJcdTI2NDgtXHUyNjUzXHUyNjYwXHUyNjYzXHUyNjY1XHUyNjY2XHUyNjY4XHUyNjdCXHUyNjdGXHUyNjkyLVx1MjY5N1x1MjY5OVx1MjY5Qlx1MjY5Q1x1MjZBMFx1MjZBMVx1MjZBQVx1MjZBQlx1MjZCMFx1MjZCMVx1MjZCRFx1MjZCRVx1MjZDNFx1MjZDNVx1MjZDOFx1MjZDRVx1MjZDRlx1MjZEMVx1MjZEM1x1MjZENFx1MjZFOVx1MjZFQVx1MjZGMC1cdTI2RjVcdTI2RjctXHUyNkZBXHUyNkZEXHUyNzAyXHUyNzA1XHUyNzA4LVx1MjcwRFx1MjcwRlx1MjcxMlx1MjcxNFx1MjcxNlx1MjcxRFx1MjcyMVx1MjcyOFx1MjczM1x1MjczNFx1Mjc0NFx1Mjc0N1x1Mjc0Q1x1Mjc0RVx1Mjc1My1cdTI3NTVcdTI3NTdcdTI3NjNcdTI3NjRcdTI3OTUtXHUyNzk3XHUyN0ExXHUyN0IwXHUyN0JGXHUyOTM0XHUyOTM1XHUyQjA1LVx1MkIwN1x1MkIxQlx1MkIxQ1x1MkI1MFx1MkI1NVx1MzAzMFx1MzAzRFx1MzI5N1x1MzI5OV18XHVEODNDW1x1REMwNFx1RENDRlx1REQ3MFx1REQ3MVx1REQ3RVx1REQ3Rlx1REQ4RVx1REQ5MS1cdUREOUFcdURERTYtXHVEREZGXHVERTAxXHVERTAyXHVERTFBXHVERTJGXHVERTMyLVx1REUzQVx1REU1MFx1REU1MVx1REYwMC1cdURGMjFcdURGMjQtXHVERjkzXHVERjk2XHVERjk3XHVERjk5LVx1REY5Qlx1REY5RS1cdURGRjBcdURGRjMtXHVERkY1XHVERkY3LVx1REZGRl18XHVEODNEW1x1REMwMC1cdURDRkRcdURDRkYtXHVERDNEXHVERDQ5LVx1REQ0RVx1REQ1MC1cdURENjdcdURENkZcdURENzBcdURENzMtXHVERDdBXHVERDg3XHVERDhBLVx1REQ4RFx1REQ5MFx1REQ5NVx1REQ5Nlx1RERBNFx1RERBNVx1RERBOFx1RERCMVx1RERCMlx1RERCQ1x1RERDMi1cdUREQzRcdURERDEtXHVEREQzXHVERERDLVx1RERERVx1RERFMVx1RERFM1x1RERFOFx1RERFRlx1RERGM1x1RERGQS1cdURFNEZcdURFODAtXHVERUM1XHVERUNCLVx1REVEMlx1REVFMC1cdURFRTVcdURFRTlcdURFRUJcdURFRUNcdURFRjBcdURFRjMtXHVERUY4XXxcdUQ4M0VbXHVERDEwLVx1REQzQVx1REQzQy1cdUREM0VcdURENDAtXHVERDQ1XHVERDQ3LVx1REQ0Q1x1REQ1MC1cdURENkJcdUREODAtXHVERDk3XHVEREMwXHVEREQwLVx1RERFNl0pXHVGRTBGL2d9LHB1bmN0dWF0aW9uX3Jhbmdlcz1bWzEyMjg4LDEyMzUxXSxbNDQwMzIsNTUyMTVdLFs2NTA0MCw2NTA1NV0sWzY1MDcyLDY1MTM1XSxbNjUyODAsNjUzNzZdLFs2NTUwNCw2NTUxOV1dLGNoYXJhY3Rlcl9yYW5nZXM9W1s0MzUyLDQ2MDddLFsxMTkwNCwxMjI1NV0sWzEyMzUyLDEyNjg3XSxbMTI4MDAsMTk5MDNdLFsxOTk2OCw0MDk1OV0sWzQzMzYwLDQzMzkxXSxbNjM3NDQsNjQyNTVdXTshZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3JldHVybiBjcmVhdGVfcmVnZXgocHVuY3R1YXRpb25fcmFuZ2VzKX1mdW5jdGlvbiBuKCl7cmV0dXJuIGNyZWF0ZV9yZWdleChjaGFyYWN0ZXJfcmFuZ2VzKX1lLnB1bmN0dWF0aW9ucz10LGUuY2hhcmFjdGVycz1ufShnZXRfcmVnZXh8fChnZXRfcmVnZXg9e30pKTt2YXIgbGliJDM9Z2V0X3JlZ2V4LGRhdGFfZ2VuZXJhdGVkPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUsdCl7dC5fX2VzTW9kdWxlPSEwLHQuZ2V0X2RhdGE9ZnVuY3Rpb24oKXtyZXR1cm57UGM6W1s5NSw5NV0sWzgyNTUsODI1Nl0sWzgyNzYsODI3Nl0sWzY1MDc1LDY1MDc2XSxbNjUxMDEsNjUxMDNdLFs2NTM0Myw2NTM0M11dLFBlOltbNDEsNDFdLFs5Myw5M10sWzEyNSwxMjVdLFszODk5LDM4OTldLFszOTAxLDM5MDFdLFs1Nzg4LDU3ODhdLFs4MjYyLDgyNjJdLFs4MzE4LDgzMThdLFs4MzM0LDgzMzRdLFs4OTY5LDg5NjldLFs4OTcxLDg5NzFdLFs5MDAyLDkwMDJdLFsxMDA4OSwxMDA4OV0sWzEwMDkxLDEwMDkxXSxbMTAwOTMsMTAwOTNdLFsxMDA5NSwxMDA5NV0sWzEwMDk3LDEwMDk3XSxbMTAwOTksMTAwOTldLFsxMDEwMSwxMDEwMV0sWzEwMTgyLDEwMTgyXSxbMTAyMTUsMTAyMTVdLFsxMDIxNywxMDIxN10sWzEwMjE5LDEwMjE5XSxbMTAyMjEsMTAyMjFdLFsxMDIyMywxMDIyM10sWzEwNjI4LDEwNjI4XSxbMTA2MzAsMTA2MzBdLFsxMDYzMiwxMDYzMl0sWzEwNjM0LDEwNjM0XSxbMTA2MzYsMTA2MzZdLFsxMDYzOCwxMDYzOF0sWzEwNjQwLDEwNjQwXSxbMTA2NDIsMTA2NDJdLFsxMDY0NCwxMDY0NF0sWzEwNjQ2LDEwNjQ2XSxbMTA2NDgsMTA2NDhdLFsxMDcxMywxMDcxM10sWzEwNzE1LDEwNzE1XSxbMTA3NDksMTA3NDldLFsxMTgxMSwxMTgxMV0sWzExODEzLDExODEzXSxbMTE4MTUsMTE4MTVdLFsxMTgxNywxMTgxN10sWzEyMjk3LDEyMjk3XSxbMTIyOTksMTIyOTldLFsxMjMwMSwxMjMwMV0sWzEyMzAzLDEyMzAzXSxbMTIzMDUsMTIzMDVdLFsxMjMwOSwxMjMwOV0sWzEyMzExLDEyMzExXSxbMTIzMTMsMTIzMTNdLFsxMjMxNSwxMjMxNV0sWzEyMzE4LDEyMzE5XSxbNjQ4MzAsNjQ4MzBdLFs2NTA0OCw2NTA0OF0sWzY1MDc4LDY1MDc4XSxbNjUwODAsNjUwODBdLFs2NTA4Miw2NTA4Ml0sWzY1MDg0LDY1MDg0XSxbNjUwODYsNjUwODZdLFs2NTA4OCw2NTA4OF0sWzY1MDkwLDY1MDkwXSxbNjUwOTIsNjUwOTJdLFs2NTA5Niw2NTA5Nl0sWzY1MTE0LDY1MTE0XSxbNjUxMTYsNjUxMTZdLFs2NTExOCw2NTExOF0sWzY1Mjg5LDY1Mjg5XSxbNjUzNDEsNjUzNDFdLFs2NTM3Myw2NTM3M10sWzY1Mzc2LDY1Mzc2XSxbNjUzNzksNjUzNzldXSxQczpbWzQwLDQwXSxbOTEsOTFdLFsxMjMsMTIzXSxbMzg5OCwzODk4XSxbMzkwMCwzOTAwXSxbNTc4Nyw1Nzg3XSxbODIxOCw4MjE4XSxbODIyMiw4MjIyXSxbODI2MSw4MjYxXSxbODMxNyw4MzE3XSxbODMzMyw4MzMzXSxbODk2OCw4OTY4XSxbODk3MCw4OTcwXSxbOTAwMSw5MDAxXSxbMTAwODgsMTAwODhdLFsxMDA5MCwxMDA5MF0sWzEwMDkyLDEwMDkyXSxbMTAwOTQsMTAwOTRdLFsxMDA5NiwxMDA5Nl0sWzEwMDk4LDEwMDk4XSxbMTAxMDAsMTAxMDBdLFsxMDE4MSwxMDE4MV0sWzEwMjE0LDEwMjE0XSxbMTAyMTYsMTAyMTZdLFsxMDIxOCwxMDIxOF0sWzEwMjIwLDEwMjIwXSxbMTAyMjIsMTAyMjJdLFsxMDYyNywxMDYyN10sWzEwNjI5LDEwNjI5XSxbMTA2MzEsMTA2MzFdLFsxMDYzMywxMDYzM10sWzEwNjM1LDEwNjM1XSxbMTA2MzcsMTA2MzddLFsxMDYzOSwxMDYzOV0sWzEwNjQxLDEwNjQxXSxbMTA2NDMsMTA2NDNdLFsxMDY0NSwxMDY0NV0sWzEwNjQ3LDEwNjQ3XSxbMTA3MTIsMTA3MTJdLFsxMDcxNCwxMDcxNF0sWzEwNzQ4LDEwNzQ4XSxbMTE4MTAsMTE4MTBdLFsxMTgxMiwxMTgxMl0sWzExODE0LDExODE0XSxbMTE4MTYsMTE4MTZdLFsxMTg0MiwxMTg0Ml0sWzEyMjk2LDEyMjk2XSxbMTIyOTgsMTIyOThdLFsxMjMwMCwxMjMwMF0sWzEyMzAyLDEyMzAyXSxbMTIzMDQsMTIzMDRdLFsxMjMwOCwxMjMwOF0sWzEyMzEwLDEyMzEwXSxbMTIzMTIsMTIzMTJdLFsxMjMxNCwxMjMxNF0sWzEyMzE3LDEyMzE3XSxbNjQ4MzEsNjQ4MzFdLFs2NTA0Nyw2NTA0N10sWzY1MDc3LDY1MDc3XSxbNjUwNzksNjUwNzldLFs2NTA4MSw2NTA4MV0sWzY1MDgzLDY1MDgzXSxbNjUwODUsNjUwODVdLFs2NTA4Nyw2NTA4N10sWzY1MDg5LDY1MDg5XSxbNjUwOTEsNjUwOTFdLFs2NTA5NSw2NTA5NV0sWzY1MTEzLDY1MTEzXSxbNjUxMTUsNjUxMTVdLFs2NTExNyw2NTExN10sWzY1Mjg4LDY1Mjg4XSxbNjUzMzksNjUzMzldLFs2NTM3MSw2NTM3MV0sWzY1Mzc1LDY1Mzc1XSxbNjUzNzgsNjUzNzhdXSxMbTpbWzY4OCw3MDVdLFs3MTAsNzIxXSxbNzM2LDc0MF0sWzc0OCw3NDhdLFs3NTAsNzUwXSxbODg0LDg4NF0sWzg5MCw4OTBdLFsxMzY5LDEzNjldLFsxNjAwLDE2MDBdLFsxNzY1LDE3NjZdLFsyMDM2LDIwMzddLFsyMDQyLDIwNDJdLFsyMDc0LDIwNzRdLFsyMDg0LDIwODRdLFsyMDg4LDIwODhdLFsyNDE3LDI0MTddLFszNjU0LDM2NTRdLFszNzgyLDM3ODJdLFs0MzQ4LDQzNDhdLFs2MTAzLDYxMDNdLFs2MjExLDYyMTFdLFs2ODIzLDY4MjNdLFs3Mjg4LDcyOTNdLFs3NDY4LDc1MzBdLFs3NTQ0LDc1NDRdLFs3NTc5LDc2MTVdLFs4MzA1LDgzMDVdLFs4MzE5LDgzMTldLFs4MzM2LDgzNDhdLFsxMTM4OCwxMTM4OV0sWzExNjMxLDExNjMxXSxbMTE4MjMsMTE4MjNdLFsxMjI5MywxMjI5M10sWzEyMzM3LDEyMzQxXSxbMTIzNDcsMTIzNDddLFsxMjQ0NSwxMjQ0Nl0sWzEyNTQwLDEyNTQyXSxbNDA5ODEsNDA5ODFdLFs0MjIzMiw0MjIzN10sWzQyNTA4LDQyNTA4XSxbNDI2MjMsNDI2MjNdLFs0MjY1Miw0MjY1M10sWzQyNzc1LDQyNzgzXSxbNDI4NjQsNDI4NjRdLFs0Mjg4OCw0Mjg4OF0sWzQzZTMsNDMwMDFdLFs0MzQ3MSw0MzQ3MV0sWzQzNDk0LDQzNDk0XSxbNDM2MzIsNDM2MzJdLFs0Mzc0MSw0Mzc0MV0sWzQzNzYzLDQzNzY0XSxbNDM4NjgsNDM4NzFdLFs2NTM5Miw2NTM5Ml0sWzY1NDM4LDY1NDM5XV0sTWM6W1syMzA3LDIzMDddLFsyMzYzLDIzNjNdLFsyMzY2LDIzNjhdLFsyMzc3LDIzODBdLFsyMzgyLDIzODNdLFsyNDM0LDI0MzVdLFsyNDk0LDI0OTZdLFsyNTAzLDI1MDRdLFsyNTA3LDI1MDhdLFsyNTE5LDI1MTldLFsyNTYzLDI1NjNdLFsyNjIyLDI2MjRdLFsyNjkxLDI2OTFdLFsyNzUwLDI3NTJdLFsyNzYxLDI3NjFdLFsyNzYzLDI3NjRdLFsyODE4LDI4MTldLFsyODc4LDI4NzhdLFsyODgwLDI4ODBdLFsyODg3LDI4ODhdLFsyODkxLDI4OTJdLFsyOTAzLDI5MDNdLFszMDA2LDMwMDddLFszMDA5LDMwMTBdLFszMDE0LDMwMTZdLFszMDE4LDMwMjBdLFszMDMxLDMwMzFdLFszMDczLDMwNzVdLFszMTM3LDMxNDBdLFszMjAyLDMyMDNdLFszMjYyLDMyNjJdLFszMjY0LDMyNjhdLFszMjcxLDMyNzJdLFszMjc0LDMyNzVdLFszMjg1LDMyODZdLFszMzMwLDMzMzFdLFszMzkwLDMzOTJdLFszMzk4LDM0MDBdLFszNDAyLDM0MDRdLFszNDE1LDM0MTVdLFszNDU4LDM0NTldLFszNTM1LDM1MzddLFszNTQ0LDM1NTFdLFszNTcwLDM1NzFdLFszOTAyLDM5MDNdLFszOTY3LDM5NjddLFs0MTM5LDQxNDBdLFs0MTQ1LDQxNDVdLFs0MTUyLDQxNTJdLFs0MTU1LDQxNTZdLFs0MTgyLDQxODNdLFs0MTk0LDQxOTZdLFs0MTk5LDQyMDVdLFs0MjI3LDQyMjhdLFs0MjMxLDQyMzZdLFs0MjM5LDQyMzldLFs0MjUwLDQyNTJdLFs2MDcwLDYwNzBdLFs2MDc4LDYwODVdLFs2MDg3LDYwODhdLFs2NDM1LDY0MzhdLFs2NDQxLDY0NDNdLFs2NDQ4LDY0NDldLFs2NDUxLDY0NTZdLFs2NjgxLDY2ODJdLFs2NzQxLDY3NDFdLFs2NzQzLDY3NDNdLFs2NzUzLDY3NTNdLFs2NzU1LDY3NTZdLFs2NzY1LDY3NzBdLFs2OTE2LDY5MTZdLFs2OTY1LDY5NjVdLFs2OTcxLDY5NzFdLFs2OTczLDY5NzddLFs2OTc5LDY5ODBdLFs3MDQyLDcwNDJdLFs3MDczLDcwNzNdLFs3MDc4LDcwNzldLFs3MDgyLDcwODJdLFs3MTQzLDcxNDNdLFs3MTQ2LDcxNDhdLFs3MTUwLDcxNTBdLFs3MTU0LDcxNTVdLFs3MjA0LDcyMTFdLFs3MjIwLDcyMjFdLFs3MzkzLDczOTNdLFs3NDEwLDc0MTFdLFs3NDE1LDc0MTVdLFsxMjMzNCwxMjMzNV0sWzQzMDQzLDQzMDQ0XSxbNDMwNDcsNDMwNDddLFs0MzEzNiw0MzEzN10sWzQzMTg4LDQzMjAzXSxbNDMzNDYsNDMzNDddLFs0MzM5NSw0MzM5NV0sWzQzNDQ0LDQzNDQ1XSxbNDM0NTAsNDM0NTFdLFs0MzQ1Myw0MzQ1Nl0sWzQzNTY3LDQzNTY4XSxbNDM1NzEsNDM1NzJdLFs0MzU5Nyw0MzU5N10sWzQzNjQzLDQzNjQzXSxbNDM2NDUsNDM2NDVdLFs0Mzc1NSw0Mzc1NV0sWzQzNzU4LDQzNzU5XSxbNDM3NjUsNDM3NjVdLFs0NDAwMyw0NDAwNF0sWzQ0MDA2LDQ0MDA3XSxbNDQwMDksNDQwMTBdLFs0NDAxMiw0NDAxMl1dLFpwOltbODIzMyw4MjMzXV0sU2M6W1szNiwzNl0sWzE2MiwxNjVdLFsxNDIzLDE0MjNdLFsxNTQ3LDE1NDddLFsyNTQ2LDI1NDddLFsyNTU1LDI1NTVdLFsyODAxLDI4MDFdLFszMDY1LDMwNjVdLFszNjQ3LDM2NDddLFs2MTA3LDYxMDddLFs4MzUyLDgzODNdLFs0MzA2NCw0MzA2NF0sWzY1MDIwLDY1MDIwXSxbNjUxMjksNjUxMjldLFs2NTI4NCw2NTI4NF0sWzY1NTA0LDY1NTA1XSxbNjU1MDksNjU1MTBdXSxNZTpbWzExNjAsMTE2MV0sWzY4NDYsNjg0Nl0sWzg0MTMsODQxNl0sWzg0MTgsODQyMF0sWzQyNjA4LDQyNjEwXV0sU2s6W1s5NCw5NF0sWzk2LDk2XSxbMTY4LDE2OF0sWzE3NSwxNzVdLFsxODAsMTgwXSxbMTg0LDE4NF0sWzcwNiw3MDldLFs3MjIsNzM1XSxbNzQxLDc0N10sWzc0OSw3NDldLFs3NTEsNzY3XSxbODg1LDg4NV0sWzkwMCw5MDFdLFs4MTI1LDgxMjVdLFs4MTI3LDgxMjldLFs4MTQxLDgxNDNdLFs4MTU3LDgxNTldLFs4MTczLDgxNzVdLFs4MTg5LDgxOTBdLFsxMjQ0MywxMjQ0NF0sWzQyNzUyLDQyNzc0XSxbNDI3ODQsNDI3ODVdLFs0Mjg4OSw0Mjg5MF0sWzQzODY3LDQzODY3XSxbNjQ0MzQsNjQ0NDldLFs2NTM0Miw2NTM0Ml0sWzY1MzQ0LDY1MzQ0XSxbNjU1MDcsNjU1MDddXSxDczpbWzU1Mjk2LDU1Mjk2XSxbNTYxOTEsNTYxOTJdLFs1NjMxOSw1NjMyMF0sWzU3MzQzLDU3MzQzXV0sTmw6W1s1ODcwLDU4NzJdLFs4NTQ0LDg1NzhdLFs4NTgxLDg1ODRdLFsxMjI5NSwxMjI5NV0sWzEyMzIxLDEyMzI5XSxbMTIzNDQsMTIzNDZdLFs0MjcyNiw0MjczNV1dLFNvOltbMTY2LDE2Nl0sWzE2OSwxNjldLFsxNzQsMTc0XSxbMTc2LDE3Nl0sWzExNTQsMTE1NF0sWzE0MjEsMTQyMl0sWzE1NTAsMTU1MV0sWzE3NTgsMTc1OF0sWzE3NjksMTc2OV0sWzE3ODksMTc5MF0sWzIwMzgsMjAzOF0sWzI1NTQsMjU1NF0sWzI5MjgsMjkyOF0sWzMwNTksMzA2NF0sWzMwNjYsMzA2Nl0sWzMxOTksMzE5OV0sWzM0MDcsMzQwN10sWzM0NDksMzQ0OV0sWzM4NDEsMzg0M10sWzM4NTksMzg1OV0sWzM4NjEsMzg2M10sWzM4NjYsMzg3MV0sWzM4OTIsMzg5Ml0sWzM4OTQsMzg5NF0sWzM4OTYsMzg5Nl0sWzQwMzAsNDAzN10sWzQwMzksNDA0NF0sWzQwNDYsNDA0N10sWzQwNTMsNDA1Nl0sWzQyNTQsNDI1NV0sWzUwMDgsNTAxN10sWzY0NjQsNjQ2NF0sWzY2MjIsNjY1NV0sWzcwMDksNzAxOF0sWzcwMjgsNzAzNl0sWzg0NDgsODQ0OV0sWzg0NTEsODQ1NF0sWzg0NTYsODQ1N10sWzg0NjgsODQ2OF0sWzg0NzAsODQ3MV0sWzg0NzgsODQ4M10sWzg0ODUsODQ4NV0sWzg0ODcsODQ4N10sWzg0ODksODQ4OV0sWzg0OTQsODQ5NF0sWzg1MDYsODUwN10sWzg1MjIsODUyMl0sWzg1MjQsODUyNV0sWzg1MjcsODUyN10sWzg1ODYsODU4N10sWzg1OTcsODYwMV0sWzg2MDQsODYwN10sWzg2MDksODYxMF0sWzg2MTIsODYxM10sWzg2MTUsODYyMV0sWzg2MjMsODY1M10sWzg2NTYsODY1N10sWzg2NTksODY1OV0sWzg2NjEsODY5MV0sWzg5NjAsODk2N10sWzg5NzIsODk5MV0sWzg5OTQsOWUzXSxbOTAwMyw5MDgzXSxbOTA4NSw5MTE0XSxbOTE0MCw5MTc5XSxbOTE4Niw5MjU0XSxbOTI4MCw5MjkwXSxbOTM3Miw5NDQ5XSxbOTQ3Miw5NjU0XSxbOTY1Niw5NjY0XSxbOTY2Niw5NzE5XSxbOTcyOCw5ODM4XSxbOTg0MCwxMDA4N10sWzEwMTMyLDEwMTc1XSxbMTAyNDAsMTA0OTVdLFsxMTAwOCwxMTA1NV0sWzExMDc3LDExMDc4XSxbMTEwODUsMTExMjNdLFsxMTEyNiwxMTE1N10sWzExMTYwLDExMTkzXSxbMTExOTcsMTEyMDhdLFsxMTIxMCwxMTIxOF0sWzExMjQ0LDExMjQ3XSxbMTE0OTMsMTE0OThdLFsxMTkwNCwxMTkyOV0sWzExOTMxLDEyMDE5XSxbMTIwMzIsMTIyNDVdLFsxMjI3MiwxMjI4M10sWzEyMjkyLDEyMjkyXSxbMTIzMDYsMTIzMDddLFsxMjMyMCwxMjMyMF0sWzEyMzQyLDEyMzQzXSxbMTIzNTAsMTIzNTFdLFsxMjY4OCwxMjY4OV0sWzEyNjk0LDEyNzAzXSxbMTI3MzYsMTI3NzFdLFsxMjgwMCwxMjgzMF0sWzEyODQyLDEyODcxXSxbMTI4ODAsMTI4ODBdLFsxMjg5NiwxMjkyN10sWzEyOTM4LDEyOTc2XSxbMTI5OTIsMTMwNTRdLFsxMzA1NiwxMzMxMV0sWzE5OTA0LDE5OTY3XSxbNDIxMjgsNDIxODJdLFs0MzA0OCw0MzA1MV0sWzQzMDYyLDQzMDYzXSxbNDMwNjUsNDMwNjVdLFs0MzYzOSw0MzY0MV0sWzY1MDIxLDY1MDIxXSxbNjU1MDgsNjU1MDhdLFs2NTUxMiw2NTUxMl0sWzY1NTE3LDY1NTE4XSxbNjU1MzIsNjU1MzNdXSxMdDpbWzQ1Myw0NTNdLFs0NTYsNDU2XSxbNDU5LDQ1OV0sWzQ5OCw0OThdLFs4MDcyLDgwNzldLFs4MDg4LDgwOTVdLFs4MTA0LDgxMTFdLFs4MTI0LDgxMjRdLFs4MTQwLDgxNDBdLFs4MTg4LDgxODhdXSxabDpbWzgyMzIsODIzMl1dLExvOltbMTcwLDE3MF0sWzE4NiwxODZdLFs0NDMsNDQzXSxbNDQ4LDQ1MV0sWzY2MCw2NjBdLFsxNDg4LDE1MTRdLFsxNTIwLDE1MjJdLFsxNTY4LDE1OTldLFsxNjAxLDE2MTBdLFsxNjQ2LDE2NDddLFsxNjQ5LDE3NDddLFsxNzQ5LDE3NDldLFsxNzc0LDE3NzVdLFsxNzg2LDE3ODhdLFsxNzkxLDE3OTFdLFsxODA4LDE4MDhdLFsxODEwLDE4MzldLFsxODY5LDE5NTddLFsxOTY5LDE5NjldLFsxOTk0LDIwMjZdLFsyMDQ4LDIwNjldLFsyMTEyLDIxMzZdLFsyMTQ0LDIxNTRdLFsyMjA4LDIyMjhdLFsyMjMwLDIyMzddLFsyMzA4LDIzNjFdLFsyMzY1LDIzNjVdLFsyMzg0LDIzODRdLFsyMzkyLDI0MDFdLFsyNDE4LDI0MzJdLFsyNDM3LDI0NDRdLFsyNDQ3LDI0NDhdLFsyNDUxLDI0NzJdLFsyNDc0LDI0ODBdLFsyNDgyLDI0ODJdLFsyNDg2LDI0ODldLFsyNDkzLDI0OTNdLFsyNTEwLDI1MTBdLFsyNTI0LDI1MjVdLFsyNTI3LDI1MjldLFsyNTQ0LDI1NDVdLFsyNTU2LDI1NTZdLFsyNTY1LDI1NzBdLFsyNTc1LDI1NzZdLFsyNTc5LDI2MDBdLFsyNjAyLDI2MDhdLFsyNjEwLDI2MTFdLFsyNjEzLDI2MTRdLFsyNjE2LDI2MTddLFsyNjQ5LDI2NTJdLFsyNjU0LDI2NTRdLFsyNjc0LDI2NzZdLFsyNjkzLDI3MDFdLFsyNzAzLDI3MDVdLFsyNzA3LDI3MjhdLFsyNzMwLDI3MzZdLFsyNzM4LDI3MzldLFsyNzQxLDI3NDVdLFsyNzQ5LDI3NDldLFsyNzY4LDI3NjhdLFsyNzg0LDI3ODVdLFsyODA5LDI4MDldLFsyODIxLDI4MjhdLFsyODMxLDI4MzJdLFsyODM1LDI4NTZdLFsyODU4LDI4NjRdLFsyODY2LDI4NjddLFsyODY5LDI4NzNdLFsyODc3LDI4NzddLFsyOTA4LDI5MDldLFsyOTExLDI5MTNdLFsyOTI5LDI5MjldLFsyOTQ3LDI5NDddLFsyOTQ5LDI5NTRdLFsyOTU4LDI5NjBdLFsyOTYyLDI5NjVdLFsyOTY5LDI5NzBdLFsyOTcyLDI5NzJdLFsyOTc0LDI5NzVdLFsyOTc5LDI5ODBdLFsyOTg0LDI5ODZdLFsyOTkwLDMwMDFdLFszMDI0LDMwMjRdLFszMDc3LDMwODRdLFszMDg2LDMwODhdLFszMDkwLDMxMTJdLFszMTE0LDMxMjldLFszMTMzLDMxMzNdLFszMTYwLDMxNjJdLFszMTY4LDMxNjldLFszMjAwLDMyMDBdLFszMjA1LDMyMTJdLFszMjE0LDMyMTZdLFszMjE4LDMyNDBdLFszMjQyLDMyNTFdLFszMjUzLDMyNTddLFszMjYxLDMyNjFdLFszMjk0LDMyOTRdLFszMjk2LDMyOTddLFszMzEzLDMzMTRdLFszMzMzLDMzNDBdLFszMzQyLDMzNDRdLFszMzQ2LDMzODZdLFszMzg5LDMzODldLFszNDA2LDM0MDZdLFszNDEyLDM0MTRdLFszNDIzLDM0MjVdLFszNDUwLDM0NTVdLFszNDYxLDM0NzhdLFszNDgyLDM1MDVdLFszNTA3LDM1MTVdLFszNTE3LDM1MTddLFszNTIwLDM1MjZdLFszNTg1LDM2MzJdLFszNjM0LDM2MzVdLFszNjQ4LDM2NTNdLFszNzEzLDM3MTRdLFszNzE2LDM3MTZdLFszNzE5LDM3MjBdLFszNzIyLDM3MjJdLFszNzI1LDM3MjVdLFszNzMyLDM3MzVdLFszNzM3LDM3NDNdLFszNzQ1LDM3NDddLFszNzQ5LDM3NDldLFszNzUxLDM3NTFdLFszNzU0LDM3NTVdLFszNzU3LDM3NjBdLFszNzYyLDM3NjNdLFszNzczLDM3NzNdLFszNzc2LDM3ODBdLFszODA0LDM4MDddLFszODQwLDM4NDBdLFszOTA0LDM5MTFdLFszOTEzLDM5NDhdLFszOTc2LDM5ODBdLFs0MDk2LDQxMzhdLFs0MTU5LDQxNTldLFs0MTc2LDQxODFdLFs0MTg2LDQxODldLFs0MTkzLDQxOTNdLFs0MTk3LDQxOThdLFs0MjA2LDQyMDhdLFs0MjEzLDQyMjVdLFs0MjM4LDQyMzhdLFs0MzA0LDQzNDZdLFs0MzQ5LDQ2ODBdLFs0NjgyLDQ2ODVdLFs0Njg4LDQ2OTRdLFs0Njk2LDQ2OTZdLFs0Njk4LDQ3MDFdLFs0NzA0LDQ3NDRdLFs0NzQ2LDQ3NDldLFs0NzUyLDQ3ODRdLFs0Nzg2LDQ3ODldLFs0NzkyLDQ3OThdLFs0ODAwLDQ4MDBdLFs0ODAyLDQ4MDVdLFs0ODA4LDQ4MjJdLFs0ODI0LDQ4ODBdLFs0ODgyLDQ4ODVdLFs0ODg4LDQ5NTRdLFs0OTkyLDUwMDddLFs1MTIxLDU3NDBdLFs1NzQzLDU3NTldLFs1NzYxLDU3ODZdLFs1NzkyLDU4NjZdLFs1ODczLDU4ODBdLFs1ODg4LDU5MDBdLFs1OTAyLDU5MDVdLFs1OTIwLDU5MzddLFs1OTUyLDU5NjldLFs1OTg0LDU5OTZdLFs1OTk4LDZlM10sWzYwMTYsNjA2N10sWzYxMDgsNjEwOF0sWzYxNzYsNjIxMF0sWzYyMTIsNjI2M10sWzYyNzIsNjI3Nl0sWzYyNzksNjMxMl0sWzYzMTQsNjMxNF0sWzYzMjAsNjM4OV0sWzY0MDAsNjQzMF0sWzY0ODAsNjUwOV0sWzY1MTIsNjUxNl0sWzY1MjgsNjU3MV0sWzY1NzYsNjYwMV0sWzY2NTYsNjY3OF0sWzY2ODgsNjc0MF0sWzY5MTcsNjk2M10sWzY5ODEsNjk4N10sWzcwNDMsNzA3Ml0sWzcwODYsNzA4N10sWzcwOTgsNzE0MV0sWzcxNjgsNzIwM10sWzcyNDUsNzI0N10sWzcyNTgsNzI4N10sWzc0MDEsNzQwNF0sWzc0MDYsNzQwOV0sWzc0MTMsNzQxNF0sWzg1MDEsODUwNF0sWzExNTY4LDExNjIzXSxbMTE2NDgsMTE2NzBdLFsxMTY4MCwxMTY4Nl0sWzExNjg4LDExNjk0XSxbMTE2OTYsMTE3MDJdLFsxMTcwNCwxMTcxMF0sWzExNzEyLDExNzE4XSxbMTE3MjAsMTE3MjZdLFsxMTcyOCwxMTczNF0sWzExNzM2LDExNzQyXSxbMTIyOTQsMTIyOTRdLFsxMjM0OCwxMjM0OF0sWzEyMzUzLDEyNDM4XSxbMTI0NDcsMTI0NDddLFsxMjQ0OSwxMjUzOF0sWzEyNTQzLDEyNTQzXSxbMTI1NDksMTI1OTBdLFsxMjU5MywxMjY4Nl0sWzEyNzA0LDEyNzMwXSxbMTI3ODQsMTI3OTldLFsxMzMxMiwxMzMxMl0sWzE5ODkzLDE5ODkzXSxbMTk5NjgsMTk5NjhdLFs0MDkzOCw0MDkzOF0sWzQwOTYwLDQwOTgwXSxbNDA5ODIsNDIxMjRdLFs0MjE5Miw0MjIzMV0sWzQyMjQwLDQyNTA3XSxbNDI1MTIsNDI1MjddLFs0MjUzOCw0MjUzOV0sWzQyNjA2LDQyNjA2XSxbNDI2NTYsNDI3MjVdLFs0Mjg5NSw0Mjg5NV0sWzQyOTk5LDQyOTk5XSxbNDMwMDMsNDMwMDldLFs0MzAxMSw0MzAxM10sWzQzMDE1LDQzMDE4XSxbNDMwMjAsNDMwNDJdLFs0MzA3Miw0MzEyM10sWzQzMTM4LDQzMTg3XSxbNDMyNTAsNDMyNTVdLFs0MzI1OSw0MzI1OV0sWzQzMjYxLDQzMjYxXSxbNDMyNzQsNDMzMDFdLFs0MzMxMiw0MzMzNF0sWzQzMzYwLDQzMzg4XSxbNDMzOTYsNDM0NDJdLFs0MzQ4OCw0MzQ5Ml0sWzQzNDk1LDQzNTAzXSxbNDM1MTQsNDM1MThdLFs0MzUyMCw0MzU2MF0sWzQzNTg0LDQzNTg2XSxbNDM1ODgsNDM1OTVdLFs0MzYxNiw0MzYzMV0sWzQzNjMzLDQzNjM4XSxbNDM2NDIsNDM2NDJdLFs0MzY0Niw0MzY5NV0sWzQzNjk3LDQzNjk3XSxbNDM3MDEsNDM3MDJdLFs0MzcwNSw0MzcwOV0sWzQzNzEyLDQzNzEyXSxbNDM3MTQsNDM3MTRdLFs0MzczOSw0Mzc0MF0sWzQzNzQ0LDQzNzU0XSxbNDM3NjIsNDM3NjJdLFs0Mzc3Nyw0Mzc4Ml0sWzQzNzg1LDQzNzkwXSxbNDM3OTMsNDM3OThdLFs0MzgwOCw0MzgxNF0sWzQzODE2LDQzODIyXSxbNDM5NjgsNDQwMDJdLFs0NDAzMiw0NDAzMl0sWzU1MjAzLDU1MjAzXSxbNTUyMTYsNTUyMzhdLFs1NTI0Myw1NTI5MV0sWzYzNzQ0LDY0MTA5XSxbNjQxMTIsNjQyMTddLFs2NDI4NSw2NDI4NV0sWzY0Mjg3LDY0Mjk2XSxbNjQyOTgsNjQzMTBdLFs2NDMxMiw2NDMxNl0sWzY0MzE4LDY0MzE4XSxbNjQzMjAsNjQzMjFdLFs2NDMyMyw2NDMyNF0sWzY0MzI2LDY0NDMzXSxbNjQ0NjcsNjQ4MjldLFs2NDg0OCw2NDkxMV0sWzY0OTE0LDY0OTY3XSxbNjUwMDgsNjUwMTldLFs2NTEzNiw2NTE0MF0sWzY1MTQyLDY1Mjc2XSxbNjUzODIsNjUzOTFdLFs2NTM5Myw2NTQzN10sWzY1NDQwLDY1NDcwXSxbNjU0NzQsNjU0NzldLFs2NTQ4Miw2NTQ4N10sWzY1NDkwLDY1NDk1XSxbNjU0OTgsNjU1MDBdXSxNbjpbWzc2OCw4NzldLFsxMTU1LDExNTldLFsxNDI1LDE0NjldLFsxNDcxLDE0NzFdLFsxNDczLDE0NzRdLFsxNDc2LDE0NzddLFsxNDc5LDE0NzldLFsxNTUyLDE1NjJdLFsxNjExLDE2MzFdLFsxNjQ4LDE2NDhdLFsxNzUwLDE3NTZdLFsxNzU5LDE3NjRdLFsxNzY3LDE3NjhdLFsxNzcwLDE3NzNdLFsxODA5LDE4MDldLFsxODQwLDE4NjZdLFsxOTU4LDE5NjhdLFsyMDI3LDIwMzVdLFsyMDcwLDIwNzNdLFsyMDc1LDIwODNdLFsyMDg1LDIwODddLFsyMDg5LDIwOTNdLFsyMTM3LDIxMzldLFsyMjYwLDIyNzNdLFsyMjc1LDIzMDZdLFsyMzYyLDIzNjJdLFsyMzY0LDIzNjRdLFsyMzY5LDIzNzZdLFsyMzgxLDIzODFdLFsyMzg1LDIzOTFdLFsyNDAyLDI0MDNdLFsyNDMzLDI0MzNdLFsyNDkyLDI0OTJdLFsyNDk3LDI1MDBdLFsyNTA5LDI1MDldLFsyNTMwLDI1MzFdLFsyNTYxLDI1NjJdLFsyNjIwLDI2MjBdLFsyNjI1LDI2MjZdLFsyNjMxLDI2MzJdLFsyNjM1LDI2MzddLFsyNjQxLDI2NDFdLFsyNjcyLDI2NzNdLFsyNjc3LDI2NzddLFsyNjg5LDI2OTBdLFsyNzQ4LDI3NDhdLFsyNzUzLDI3NTddLFsyNzU5LDI3NjBdLFsyNzY1LDI3NjVdLFsyNzg2LDI3ODddLFsyODEwLDI4MTVdLFsyODE3LDI4MTddLFsyODc2LDI4NzZdLFsyODc5LDI4NzldLFsyODgxLDI4ODRdLFsyODkzLDI4OTNdLFsyOTAyLDI5MDJdLFsyOTE0LDI5MTVdLFsyOTQ2LDI5NDZdLFszMDA4LDMwMDhdLFszMDIxLDMwMjFdLFszMDcyLDMwNzJdLFszMTM0LDMxMzZdLFszMTQyLDMxNDRdLFszMTQ2LDMxNDldLFszMTU3LDMxNThdLFszMTcwLDMxNzFdLFszMjAxLDMyMDFdLFszMjYwLDMyNjBdLFszMjYzLDMyNjNdLFszMjcwLDMyNzBdLFszMjc2LDMyNzddLFszMjk4LDMyOTldLFszMzI4LDMzMjldLFszMzg3LDMzODhdLFszMzkzLDMzOTZdLFszNDA1LDM0MDVdLFszNDI2LDM0MjddLFszNTMwLDM1MzBdLFszNTM4LDM1NDBdLFszNTQyLDM1NDJdLFszNjMzLDM2MzNdLFszNjM2LDM2NDJdLFszNjU1LDM2NjJdLFszNzYxLDM3NjFdLFszNzY0LDM3NjldLFszNzcxLDM3NzJdLFszNzg0LDM3ODldLFszODY0LDM4NjVdLFszODkzLDM4OTNdLFszODk1LDM4OTVdLFszODk3LDM4OTddLFszOTUzLDM5NjZdLFszOTY4LDM5NzJdLFszOTc0LDM5NzVdLFszOTgxLDM5OTFdLFszOTkzLDQwMjhdLFs0MDM4LDQwMzhdLFs0MTQxLDQxNDRdLFs0MTQ2LDQxNTFdLFs0MTUzLDQxNTRdLFs0MTU3LDQxNThdLFs0MTg0LDQxODVdLFs0MTkwLDQxOTJdLFs0MjA5LDQyMTJdLFs0MjI2LDQyMjZdLFs0MjI5LDQyMzBdLFs0MjM3LDQyMzddLFs0MjUzLDQyNTNdLFs0OTU3LDQ5NTldLFs1OTA2LDU5MDhdLFs1OTM4LDU5NDBdLFs1OTcwLDU5NzFdLFs2MDAyLDYwMDNdLFs2MDY4LDYwNjldLFs2MDcxLDYwNzddLFs2MDg2LDYwODZdLFs2MDg5LDYwOTldLFs2MTA5LDYxMDldLFs2MTU1LDYxNTddLFs2Mjc3LDYyNzhdLFs2MzEzLDYzMTNdLFs2NDMyLDY0MzRdLFs2NDM5LDY0NDBdLFs2NDUwLDY0NTBdLFs2NDU3LDY0NTldLFs2Njc5LDY2ODBdLFs2NjgzLDY2ODNdLFs2NzQyLDY3NDJdLFs2NzQ0LDY3NTBdLFs2NzUyLDY3NTJdLFs2NzU0LDY3NTRdLFs2NzU3LDY3NjRdLFs2NzcxLDY3ODBdLFs2NzgzLDY3ODNdLFs2ODMyLDY4NDVdLFs2OTEyLDY5MTVdLFs2OTY0LDY5NjRdLFs2OTY2LDY5NzBdLFs2OTcyLDY5NzJdLFs2OTc4LDY5NzhdLFs3MDE5LDcwMjddLFs3MDQwLDcwNDFdLFs3MDc0LDcwNzddLFs3MDgwLDcwODFdLFs3MDgzLDcwODVdLFs3MTQyLDcxNDJdLFs3MTQ0LDcxNDVdLFs3MTQ5LDcxNDldLFs3MTUxLDcxNTNdLFs3MjEyLDcyMTldLFs3MjIyLDcyMjNdLFs3Mzc2LDczNzhdLFs3MzgwLDczOTJdLFs3Mzk0LDc0MDBdLFs3NDA1LDc0MDVdLFs3NDEyLDc0MTJdLFs3NDE2LDc0MTddLFs3NjE2LDc2NzNdLFs3Njc1LDc2NzldLFs4NDAwLDg0MTJdLFs4NDE3LDg0MTddLFs4NDIxLDg0MzJdLFsxMTUwMywxMTUwNV0sWzExNjQ3LDExNjQ3XSxbMTE3NDQsMTE3NzVdLFsxMjMzMCwxMjMzM10sWzEyNDQxLDEyNDQyXSxbNDI2MDcsNDI2MDddLFs0MjYxMiw0MjYyMV0sWzQyNjU0LDQyNjU1XSxbNDI3MzYsNDI3MzddLFs0MzAxMCw0MzAxMF0sWzQzMDE0LDQzMDE0XSxbNDMwMTksNDMwMTldLFs0MzA0NSw0MzA0Nl0sWzQzMjA0LDQzMjA1XSxbNDMyMzIsNDMyNDldLFs0MzMwMiw0MzMwOV0sWzQzMzM1LDQzMzQ1XSxbNDMzOTIsNDMzOTRdLFs0MzQ0Myw0MzQ0M10sWzQzNDQ2LDQzNDQ5XSxbNDM0NTIsNDM0NTJdLFs0MzQ5Myw0MzQ5M10sWzQzNTYxLDQzNTY2XSxbNDM1NjksNDM1NzBdLFs0MzU3Myw0MzU3NF0sWzQzNTg3LDQzNTg3XSxbNDM1OTYsNDM1OTZdLFs0MzY0NCw0MzY0NF0sWzQzNjk2LDQzNjk2XSxbNDM2OTgsNDM3MDBdLFs0MzcwMyw0MzcwNF0sWzQzNzEwLDQzNzExXSxbNDM3MTMsNDM3MTNdLFs0Mzc1Niw0Mzc1N10sWzQzNzY2LDQzNzY2XSxbNDQwMDUsNDQwMDVdLFs0NDAwOCw0NDAwOF0sWzQ0MDEzLDQ0MDEzXSxbNjQyODYsNjQyODZdLFs2NTAyNCw2NTAzOV0sWzY1MDU2LDY1MDcxXV0sUG86W1szMywzNV0sWzM3LDM5XSxbNDIsNDJdLFs0NCw0NF0sWzQ2LDQ3XSxbNTgsNTldLFs2Myw2NF0sWzkyLDkyXSxbMTYxLDE2MV0sWzE2NywxNjddLFsxODIsMTgzXSxbMTkxLDE5MV0sWzg5NCw4OTRdLFs5MDMsOTAzXSxbMTM3MCwxMzc1XSxbMTQxNywxNDE3XSxbMTQ3MiwxNDcyXSxbMTQ3NSwxNDc1XSxbMTQ3OCwxNDc4XSxbMTUyMywxNTI0XSxbMTU0NSwxNTQ2XSxbMTU0OCwxNTQ5XSxbMTU2MywxNTYzXSxbMTU2NiwxNTY3XSxbMTY0MiwxNjQ1XSxbMTc0OCwxNzQ4XSxbMTc5MiwxODA1XSxbMjAzOSwyMDQxXSxbMjA5NiwyMTEwXSxbMjE0MiwyMTQyXSxbMjQwNCwyNDA1XSxbMjQxNiwyNDE2XSxbMjU1NywyNTU3XSxbMjgwMCwyODAwXSxbMzU3MiwzNTcyXSxbMzY2MywzNjYzXSxbMzY3NCwzNjc1XSxbMzg0NCwzODU4XSxbMzg2MCwzODYwXSxbMzk3MywzOTczXSxbNDA0OCw0MDUyXSxbNDA1Nyw0MDU4XSxbNDE3MCw0MTc1XSxbNDM0Nyw0MzQ3XSxbNDk2MCw0OTY4XSxbNTc0MSw1NzQyXSxbNTg2Nyw1ODY5XSxbNTk0MSw1OTQyXSxbNjEwMCw2MTAyXSxbNjEwNCw2MTA2XSxbNjE0NCw2MTQ5XSxbNjE1MSw2MTU0XSxbNjQ2OCw2NDY5XSxbNjY4Niw2Njg3XSxbNjgxNiw2ODIyXSxbNjgyNCw2ODI5XSxbNzAwMiw3MDA4XSxbNzE2NCw3MTY3XSxbNzIyNyw3MjMxXSxbNzI5NCw3Mjk1XSxbNzM2MCw3MzY3XSxbNzM3OSw3Mzc5XSxbODIxNCw4MjE1XSxbODIyNCw4MjMxXSxbODI0MCw4MjQ4XSxbODI1MSw4MjU0XSxbODI1Nyw4MjU5XSxbODI2Myw4MjczXSxbODI3NSw4Mjc1XSxbODI3Nyw4Mjg2XSxbMTE1MTMsMTE1MTZdLFsxMTUxOCwxMTUxOV0sWzExNjMyLDExNjMyXSxbMTE3NzYsMTE3NzddLFsxMTc4MiwxMTc4NF0sWzExNzg3LDExNzg3XSxbMTE3OTAsMTE3OThdLFsxMTgwMCwxMTgwMV0sWzExODAzLDExODAzXSxbMTE4MDYsMTE4MDddLFsxMTgxOCwxMTgyMl0sWzExODI0LDExODMzXSxbMTE4MzYsMTE4MzldLFsxMTg0MSwxMTg0MV0sWzExODQzLDExODQ5XSxbMTIyODksMTIyOTFdLFsxMjM0OSwxMjM0OV0sWzEyNTM5LDEyNTM5XSxbNDIyMzgsNDIyMzldLFs0MjUwOSw0MjUxMV0sWzQyNjExLDQyNjExXSxbNDI2MjIsNDI2MjJdLFs0MjczOCw0Mjc0M10sWzQzMTI0LDQzMTI3XSxbNDMyMTQsNDMyMTVdLFs0MzI1Niw0MzI1OF0sWzQzMjYwLDQzMjYwXSxbNDMzMTAsNDMzMTFdLFs0MzM1OSw0MzM1OV0sWzQzNDU3LDQzNDY5XSxbNDM0ODYsNDM0ODddLFs0MzYxMiw0MzYxNV0sWzQzNzQyLDQzNzQzXSxbNDM3NjAsNDM3NjFdLFs0NDAxMSw0NDAxMV0sWzY1MDQwLDY1MDQ2XSxbNjUwNDksNjUwNDldLFs2NTA3Miw2NTA3Ml0sWzY1MDkzLDY1MDk0XSxbNjUwOTcsNjUxMDBdLFs2NTEwNCw2NTEwNl0sWzY1MTA4LDY1MTExXSxbNjUxMTksNjUxMjFdLFs2NTEyOCw2NTEyOF0sWzY1MTMwLDY1MTMxXSxbNjUyODEsNjUyODNdLFs2NTI4NSw2NTI4N10sWzY1MjkwLDY1MjkwXSxbNjUyOTIsNjUyOTJdLFs2NTI5NCw2NTI5NV0sWzY1MzA2LDY1MzA3XSxbNjUzMTEsNjUzMTJdLFs2NTM0MCw2NTM0MF0sWzY1Mzc3LDY1Mzc3XSxbNjUzODAsNjUzODFdXSxDbzpbWzU3MzQ0LDU3MzQ0XSxbNjM3NDMsNjM3NDNdXSxTbTpbWzQzLDQzXSxbNjAsNjJdLFsxMjQsMTI0XSxbMTI2LDEyNl0sWzE3MiwxNzJdLFsxNzcsMTc3XSxbMjE1LDIxNV0sWzI0NywyNDddLFsxMDE0LDEwMTRdLFsxNTQyLDE1NDRdLFs4MjYwLDgyNjBdLFs4Mjc0LDgyNzRdLFs4MzE0LDgzMTZdLFs4MzMwLDgzMzJdLFs4NDcyLDg0NzJdLFs4NTEyLDg1MTZdLFs4NTIzLDg1MjNdLFs4NTkyLDg1OTZdLFs4NjAyLDg2MDNdLFs4NjA4LDg2MDhdLFs4NjExLDg2MTFdLFs4NjE0LDg2MTRdLFs4NjIyLDg2MjJdLFs4NjU0LDg2NTVdLFs4NjU4LDg2NThdLFs4NjYwLDg2NjBdLFs4NjkyLDg5NTldLFs4OTkyLDg5OTNdLFs5MDg0LDkwODRdLFs5MTE1LDkxMzldLFs5MTgwLDkxODVdLFs5NjU1LDk2NTVdLFs5NjY1LDk2NjVdLFs5NzIwLDk3MjddLFs5ODM5LDk4MzldLFsxMDE3NiwxMDE4MF0sWzEwMTgzLDEwMjEzXSxbMTAyMjQsMTAyMzldLFsxMDQ5NiwxMDYyNl0sWzEwNjQ5LDEwNzExXSxbMTA3MTYsMTA3NDddLFsxMDc1MCwxMTAwN10sWzExMDU2LDExMDc2XSxbMTEwNzksMTEwODRdLFs2NDI5Nyw2NDI5N10sWzY1MTIyLDY1MTIyXSxbNjUxMjQsNjUxMjZdLFs2NTI5MSw2NTI5MV0sWzY1MzA4LDY1MzEwXSxbNjUzNzIsNjUzNzJdLFs2NTM3NCw2NTM3NF0sWzY1NTA2LDY1NTA2XSxbNjU1MTMsNjU1MTZdXSxQZjpbWzE4NywxODddLFs4MjE3LDgyMTddLFs4MjIxLDgyMjFdLFs4MjUwLDgyNTBdLFsxMTc3OSwxMTc3OV0sWzExNzgxLDExNzgxXSxbMTE3ODYsMTE3ODZdLFsxMTc4OSwxMTc4OV0sWzExODA1LDExODA1XSxbMTE4MDksMTE4MDldXSxDYzpbWzAsMzFdLFsxMjcsMTU5XV0sUGk6W1sxNzEsMTcxXSxbODIxNiw4MjE2XSxbODIxOSw4MjIwXSxbODIyMyw4MjIzXSxbODI0OSw4MjQ5XSxbMTE3NzgsMTE3NzhdLFsxMTc4MCwxMTc4MF0sWzExNzg1LDExNzg1XSxbMTE3ODgsMTE3ODhdLFsxMTgwNCwxMTgwNF0sWzExODA4LDExODA4XV0sTHU6W1s2NSw5MF0sWzE5MiwyMTRdLFsyMTYsMjIyXSxbMjU2LDI1Nl0sWzI1OCwyNThdLFsyNjAsMjYwXSxbMjYyLDI2Ml0sWzI2NCwyNjRdLFsyNjYsMjY2XSxbMjY4LDI2OF0sWzI3MCwyNzBdLFsyNzIsMjcyXSxbMjc0LDI3NF0sWzI3NiwyNzZdLFsyNzgsMjc4XSxbMjgwLDI4MF0sWzI4MiwyODJdLFsyODQsMjg0XSxbMjg2LDI4Nl0sWzI4OCwyODhdLFsyOTAsMjkwXSxbMjkyLDI5Ml0sWzI5NCwyOTRdLFsyOTYsMjk2XSxbMjk4LDI5OF0sWzMwMCwzMDBdLFszMDIsMzAyXSxbMzA0LDMwNF0sWzMwNiwzMDZdLFszMDgsMzA4XSxbMzEwLDMxMF0sWzMxMywzMTNdLFszMTUsMzE1XSxbMzE3LDMxN10sWzMxOSwzMTldLFszMjEsMzIxXSxbMzIzLDMyM10sWzMyNSwzMjVdLFszMjcsMzI3XSxbMzMwLDMzMF0sWzMzMiwzMzJdLFszMzQsMzM0XSxbMzM2LDMzNl0sWzMzOCwzMzhdLFszNDAsMzQwXSxbMzQyLDM0Ml0sWzM0NCwzNDRdLFszNDYsMzQ2XSxbMzQ4LDM0OF0sWzM1MCwzNTBdLFszNTIsMzUyXSxbMzU0LDM1NF0sWzM1NiwzNTZdLFszNTgsMzU4XSxbMzYwLDM2MF0sWzM2MiwzNjJdLFszNjQsMzY0XSxbMzY2LDM2Nl0sWzM2OCwzNjhdLFszNzAsMzcwXSxbMzcyLDM3Ml0sWzM3NCwzNzRdLFszNzYsMzc3XSxbMzc5LDM3OV0sWzM4MSwzODFdLFszODUsMzg2XSxbMzg4LDM4OF0sWzM5MCwzOTFdLFszOTMsMzk1XSxbMzk4LDQwMV0sWzQwMyw0MDRdLFs0MDYsNDA4XSxbNDEyLDQxM10sWzQxNSw0MTZdLFs0MTgsNDE4XSxbNDIwLDQyMF0sWzQyMiw0MjNdLFs0MjUsNDI1XSxbNDI4LDQyOF0sWzQzMCw0MzFdLFs0MzMsNDM1XSxbNDM3LDQzN10sWzQzOSw0NDBdLFs0NDQsNDQ0XSxbNDUyLDQ1Ml0sWzQ1NSw0NTVdLFs0NTgsNDU4XSxbNDYxLDQ2MV0sWzQ2Myw0NjNdLFs0NjUsNDY1XSxbNDY3LDQ2N10sWzQ2OSw0NjldLFs0NzEsNDcxXSxbNDczLDQ3M10sWzQ3NSw0NzVdLFs0NzgsNDc4XSxbNDgwLDQ4MF0sWzQ4Miw0ODJdLFs0ODQsNDg0XSxbNDg2LDQ4Nl0sWzQ4OCw0ODhdLFs0OTAsNDkwXSxbNDkyLDQ5Ml0sWzQ5NCw0OTRdLFs0OTcsNDk3XSxbNTAwLDUwMF0sWzUwMiw1MDRdLFs1MDYsNTA2XSxbNTA4LDUwOF0sWzUxMCw1MTBdLFs1MTIsNTEyXSxbNTE0LDUxNF0sWzUxNiw1MTZdLFs1MTgsNTE4XSxbNTIwLDUyMF0sWzUyMiw1MjJdLFs1MjQsNTI0XSxbNTI2LDUyNl0sWzUyOCw1MjhdLFs1MzAsNTMwXSxbNTMyLDUzMl0sWzUzNCw1MzRdLFs1MzYsNTM2XSxbNTM4LDUzOF0sWzU0MCw1NDBdLFs1NDIsNTQyXSxbNTQ0LDU0NF0sWzU0Niw1NDZdLFs1NDgsNTQ4XSxbNTUwLDU1MF0sWzU1Miw1NTJdLFs1NTQsNTU0XSxbNTU2LDU1Nl0sWzU1OCw1NThdLFs1NjAsNTYwXSxbNTYyLDU2Ml0sWzU3MCw1NzFdLFs1NzMsNTc0XSxbNTc3LDU3N10sWzU3OSw1ODJdLFs1ODQsNTg0XSxbNTg2LDU4Nl0sWzU4OCw1ODhdLFs1OTAsNTkwXSxbODgwLDg4MF0sWzg4Miw4ODJdLFs4ODYsODg2XSxbODk1LDg5NV0sWzkwMiw5MDJdLFs5MDQsOTA2XSxbOTA4LDkwOF0sWzkxMCw5MTFdLFs5MTMsOTI5XSxbOTMxLDkzOV0sWzk3NSw5NzVdLFs5NzgsOTgwXSxbOTg0LDk4NF0sWzk4Niw5ODZdLFs5ODgsOTg4XSxbOTkwLDk5MF0sWzk5Miw5OTJdLFs5OTQsOTk0XSxbOTk2LDk5Nl0sWzk5OCw5OThdLFsxZTMsMWUzXSxbMTAwMiwxMDAyXSxbMTAwNCwxMDA0XSxbMTAwNiwxMDA2XSxbMTAxMiwxMDEyXSxbMTAxNSwxMDE1XSxbMTAxNywxMDE4XSxbMTAyMSwxMDcxXSxbMTEyMCwxMTIwXSxbMTEyMiwxMTIyXSxbMTEyNCwxMTI0XSxbMTEyNiwxMTI2XSxbMTEyOCwxMTI4XSxbMTEzMCwxMTMwXSxbMTEzMiwxMTMyXSxbMTEzNCwxMTM0XSxbMTEzNiwxMTM2XSxbMTEzOCwxMTM4XSxbMTE0MCwxMTQwXSxbMTE0MiwxMTQyXSxbMTE0NCwxMTQ0XSxbMTE0NiwxMTQ2XSxbMTE0OCwxMTQ4XSxbMTE1MCwxMTUwXSxbMTE1MiwxMTUyXSxbMTE2MiwxMTYyXSxbMTE2NCwxMTY0XSxbMTE2NiwxMTY2XSxbMTE2OCwxMTY4XSxbMTE3MCwxMTcwXSxbMTE3MiwxMTcyXSxbMTE3NCwxMTc0XSxbMTE3NiwxMTc2XSxbMTE3OCwxMTc4XSxbMTE4MCwxMTgwXSxbMTE4MiwxMTgyXSxbMTE4NCwxMTg0XSxbMTE4NiwxMTg2XSxbMTE4OCwxMTg4XSxbMTE5MCwxMTkwXSxbMTE5MiwxMTkyXSxbMTE5NCwxMTk0XSxbMTE5NiwxMTk2XSxbMTE5OCwxMTk4XSxbMTIwMCwxMjAwXSxbMTIwMiwxMjAyXSxbMTIwNCwxMjA0XSxbMTIwNiwxMjA2XSxbMTIwOCwxMjA4XSxbMTIxMCwxMjEwXSxbMTIxMiwxMjEyXSxbMTIxNCwxMjE0XSxbMTIxNiwxMjE3XSxbMTIxOSwxMjE5XSxbMTIyMSwxMjIxXSxbMTIyMywxMjIzXSxbMTIyNSwxMjI1XSxbMTIyNywxMjI3XSxbMTIyOSwxMjI5XSxbMTIzMiwxMjMyXSxbMTIzNCwxMjM0XSxbMTIzNiwxMjM2XSxbMTIzOCwxMjM4XSxbMTI0MCwxMjQwXSxbMTI0MiwxMjQyXSxbMTI0NCwxMjQ0XSxbMTI0NiwxMjQ2XSxbMTI0OCwxMjQ4XSxbMTI1MCwxMjUwXSxbMTI1MiwxMjUyXSxbMTI1NCwxMjU0XSxbMTI1NiwxMjU2XSxbMTI1OCwxMjU4XSxbMTI2MCwxMjYwXSxbMTI2MiwxMjYyXSxbMTI2NCwxMjY0XSxbMTI2NiwxMjY2XSxbMTI2OCwxMjY4XSxbMTI3MCwxMjcwXSxbMTI3MiwxMjcyXSxbMTI3NCwxMjc0XSxbMTI3NiwxMjc2XSxbMTI3OCwxMjc4XSxbMTI4MCwxMjgwXSxbMTI4MiwxMjgyXSxbMTI4NCwxMjg0XSxbMTI4NiwxMjg2XSxbMTI4OCwxMjg4XSxbMTI5MCwxMjkwXSxbMTI5MiwxMjkyXSxbMTI5NCwxMjk0XSxbMTI5NiwxMjk2XSxbMTI5OCwxMjk4XSxbMTMwMCwxMzAwXSxbMTMwMiwxMzAyXSxbMTMwNCwxMzA0XSxbMTMwNiwxMzA2XSxbMTMwOCwxMzA4XSxbMTMxMCwxMzEwXSxbMTMxMiwxMzEyXSxbMTMxNCwxMzE0XSxbMTMxNiwxMzE2XSxbMTMxOCwxMzE4XSxbMTMyMCwxMzIwXSxbMTMyMiwxMzIyXSxbMTMyNCwxMzI0XSxbMTMyNiwxMzI2XSxbMTMyOSwxMzY2XSxbNDI1Niw0MjkzXSxbNDI5NSw0Mjk1XSxbNDMwMSw0MzAxXSxbNTAyNCw1MTA5XSxbNzY4MCw3NjgwXSxbNzY4Miw3NjgyXSxbNzY4NCw3Njg0XSxbNzY4Niw3Njg2XSxbNzY4OCw3Njg4XSxbNzY5MCw3NjkwXSxbNzY5Miw3NjkyXSxbNzY5NCw3Njk0XSxbNzY5Niw3Njk2XSxbNzY5OCw3Njk4XSxbNzcwMCw3NzAwXSxbNzcwMiw3NzAyXSxbNzcwNCw3NzA0XSxbNzcwNiw3NzA2XSxbNzcwOCw3NzA4XSxbNzcxMCw3NzEwXSxbNzcxMiw3NzEyXSxbNzcxNCw3NzE0XSxbNzcxNiw3NzE2XSxbNzcxOCw3NzE4XSxbNzcyMCw3NzIwXSxbNzcyMiw3NzIyXSxbNzcyNCw3NzI0XSxbNzcyNiw3NzI2XSxbNzcyOCw3NzI4XSxbNzczMCw3NzMwXSxbNzczMiw3NzMyXSxbNzczNCw3NzM0XSxbNzczNiw3NzM2XSxbNzczOCw3NzM4XSxbNzc0MCw3NzQwXSxbNzc0Miw3NzQyXSxbNzc0NCw3NzQ0XSxbNzc0Niw3NzQ2XSxbNzc0OCw3NzQ4XSxbNzc1MCw3NzUwXSxbNzc1Miw3NzUyXSxbNzc1NCw3NzU0XSxbNzc1Niw3NzU2XSxbNzc1OCw3NzU4XSxbNzc2MCw3NzYwXSxbNzc2Miw3NzYyXSxbNzc2NCw3NzY0XSxbNzc2Niw3NzY2XSxbNzc2OCw3NzY4XSxbNzc3MCw3NzcwXSxbNzc3Miw3NzcyXSxbNzc3NCw3Nzc0XSxbNzc3Niw3Nzc2XSxbNzc3OCw3Nzc4XSxbNzc4MCw3NzgwXSxbNzc4Miw3NzgyXSxbNzc4NCw3Nzg0XSxbNzc4Niw3Nzg2XSxbNzc4OCw3Nzg4XSxbNzc5MCw3NzkwXSxbNzc5Miw3NzkyXSxbNzc5NCw3Nzk0XSxbNzc5Niw3Nzk2XSxbNzc5OCw3Nzk4XSxbNzgwMCw3ODAwXSxbNzgwMiw3ODAyXSxbNzgwNCw3ODA0XSxbNzgwNiw3ODA2XSxbNzgwOCw3ODA4XSxbNzgxMCw3ODEwXSxbNzgxMiw3ODEyXSxbNzgxNCw3ODE0XSxbNzgxNiw3ODE2XSxbNzgxOCw3ODE4XSxbNzgyMCw3ODIwXSxbNzgyMiw3ODIyXSxbNzgyNCw3ODI0XSxbNzgyNiw3ODI2XSxbNzgyOCw3ODI4XSxbNzgzOCw3ODM4XSxbNzg0MCw3ODQwXSxbNzg0Miw3ODQyXSxbNzg0NCw3ODQ0XSxbNzg0Niw3ODQ2XSxbNzg0OCw3ODQ4XSxbNzg1MCw3ODUwXSxbNzg1Miw3ODUyXSxbNzg1NCw3ODU0XSxbNzg1Niw3ODU2XSxbNzg1OCw3ODU4XSxbNzg2MCw3ODYwXSxbNzg2Miw3ODYyXSxbNzg2NCw3ODY0XSxbNzg2Niw3ODY2XSxbNzg2OCw3ODY4XSxbNzg3MCw3ODcwXSxbNzg3Miw3ODcyXSxbNzg3NCw3ODc0XSxbNzg3Niw3ODc2XSxbNzg3OCw3ODc4XSxbNzg4MCw3ODgwXSxbNzg4Miw3ODgyXSxbNzg4NCw3ODg0XSxbNzg4Niw3ODg2XSxbNzg4OCw3ODg4XSxbNzg5MCw3ODkwXSxbNzg5Miw3ODkyXSxbNzg5NCw3ODk0XSxbNzg5Niw3ODk2XSxbNzg5OCw3ODk4XSxbNzkwMCw3OTAwXSxbNzkwMiw3OTAyXSxbNzkwNCw3OTA0XSxbNzkwNiw3OTA2XSxbNzkwOCw3OTA4XSxbNzkxMCw3OTEwXSxbNzkxMiw3OTEyXSxbNzkxNCw3OTE0XSxbNzkxNiw3OTE2XSxbNzkxOCw3OTE4XSxbNzkyMCw3OTIwXSxbNzkyMiw3OTIyXSxbNzkyNCw3OTI0XSxbNzkyNiw3OTI2XSxbNzkyOCw3OTI4XSxbNzkzMCw3OTMwXSxbNzkzMiw3OTMyXSxbNzkzNCw3OTM0XSxbNzk0NCw3OTUxXSxbNzk2MCw3OTY1XSxbNzk3Niw3OTgzXSxbNzk5Miw3OTk5XSxbODAwOCw4MDEzXSxbODAyNSw4MDI1XSxbODAyNyw4MDI3XSxbODAyOSw4MDI5XSxbODAzMSw4MDMxXSxbODA0MCw4MDQ3XSxbODEyMCw4MTIzXSxbODEzNiw4MTM5XSxbODE1Miw4MTU1XSxbODE2OCw4MTcyXSxbODE4NCw4MTg3XSxbODQ1MCw4NDUwXSxbODQ1NSw4NDU1XSxbODQ1OSw4NDYxXSxbODQ2NCw4NDY2XSxbODQ2OSw4NDY5XSxbODQ3Myw4NDc3XSxbODQ4NCw4NDg0XSxbODQ4Niw4NDg2XSxbODQ4OCw4NDg4XSxbODQ5MCw4NDkzXSxbODQ5Niw4NDk5XSxbODUxMCw4NTExXSxbODUxNyw4NTE3XSxbODU3OSw4NTc5XSxbMTEyNjQsMTEzMTBdLFsxMTM2MCwxMTM2MF0sWzExMzYyLDExMzY0XSxbMTEzNjcsMTEzNjddLFsxMTM2OSwxMTM2OV0sWzExMzcxLDExMzcxXSxbMTEzNzMsMTEzNzZdLFsxMTM3OCwxMTM3OF0sWzExMzgxLDExMzgxXSxbMTEzOTAsMTEzOTJdLFsxMTM5NCwxMTM5NF0sWzExMzk2LDExMzk2XSxbMTEzOTgsMTEzOThdLFsxMTQwMCwxMTQwMF0sWzExNDAyLDExNDAyXSxbMTE0MDQsMTE0MDRdLFsxMTQwNiwxMTQwNl0sWzExNDA4LDExNDA4XSxbMTE0MTAsMTE0MTBdLFsxMTQxMiwxMTQxMl0sWzExNDE0LDExNDE0XSxbMTE0MTYsMTE0MTZdLFsxMTQxOCwxMTQxOF0sWzExNDIwLDExNDIwXSxbMTE0MjIsMTE0MjJdLFsxMTQyNCwxMTQyNF0sWzExNDI2LDExNDI2XSxbMTE0MjgsMTE0MjhdLFsxMTQzMCwxMTQzMF0sWzExNDMyLDExNDMyXSxbMTE0MzQsMTE0MzRdLFsxMTQzNiwxMTQzNl0sWzExNDM4LDExNDM4XSxbMTE0NDAsMTE0NDBdLFsxMTQ0MiwxMTQ0Ml0sWzExNDQ0LDExNDQ0XSxbMTE0NDYsMTE0NDZdLFsxMTQ0OCwxMTQ0OF0sWzExNDUwLDExNDUwXSxbMTE0NTIsMTE0NTJdLFsxMTQ1NCwxMTQ1NF0sWzExNDU2LDExNDU2XSxbMTE0NTgsMTE0NThdLFsxMTQ2MCwxMTQ2MF0sWzExNDYyLDExNDYyXSxbMTE0NjQsMTE0NjRdLFsxMTQ2NiwxMTQ2Nl0sWzExNDY4LDExNDY4XSxbMTE0NzAsMTE0NzBdLFsxMTQ3MiwxMTQ3Ml0sWzExNDc0LDExNDc0XSxbMTE0NzYsMTE0NzZdLFsxMTQ3OCwxMTQ3OF0sWzExNDgwLDExNDgwXSxbMTE0ODIsMTE0ODJdLFsxMTQ4NCwxMTQ4NF0sWzExNDg2LDExNDg2XSxbMTE0ODgsMTE0ODhdLFsxMTQ5MCwxMTQ5MF0sWzExNDk5LDExNDk5XSxbMTE1MDEsMTE1MDFdLFsxMTUwNiwxMTUwNl0sWzQyNTYwLDQyNTYwXSxbNDI1NjIsNDI1NjJdLFs0MjU2NCw0MjU2NF0sWzQyNTY2LDQyNTY2XSxbNDI1NjgsNDI1NjhdLFs0MjU3MCw0MjU3MF0sWzQyNTcyLDQyNTcyXSxbNDI1NzQsNDI1NzRdLFs0MjU3Niw0MjU3Nl0sWzQyNTc4LDQyNTc4XSxbNDI1ODAsNDI1ODBdLFs0MjU4Miw0MjU4Ml0sWzQyNTg0LDQyNTg0XSxbNDI1ODYsNDI1ODZdLFs0MjU4OCw0MjU4OF0sWzQyNTkwLDQyNTkwXSxbNDI1OTIsNDI1OTJdLFs0MjU5NCw0MjU5NF0sWzQyNTk2LDQyNTk2XSxbNDI1OTgsNDI1OThdLFs0MjYwMCw0MjYwMF0sWzQyNjAyLDQyNjAyXSxbNDI2MDQsNDI2MDRdLFs0MjYyNCw0MjYyNF0sWzQyNjI2LDQyNjI2XSxbNDI2MjgsNDI2MjhdLFs0MjYzMCw0MjYzMF0sWzQyNjMyLDQyNjMyXSxbNDI2MzQsNDI2MzRdLFs0MjYzNiw0MjYzNl0sWzQyNjM4LDQyNjM4XSxbNDI2NDAsNDI2NDBdLFs0MjY0Miw0MjY0Ml0sWzQyNjQ0LDQyNjQ0XSxbNDI2NDYsNDI2NDZdLFs0MjY0OCw0MjY0OF0sWzQyNjUwLDQyNjUwXSxbNDI3ODYsNDI3ODZdLFs0Mjc4OCw0Mjc4OF0sWzQyNzkwLDQyNzkwXSxbNDI3OTIsNDI3OTJdLFs0Mjc5NCw0Mjc5NF0sWzQyNzk2LDQyNzk2XSxbNDI3OTgsNDI3OThdLFs0MjgwMiw0MjgwMl0sWzQyODA0LDQyODA0XSxbNDI4MDYsNDI4MDZdLFs0MjgwOCw0MjgwOF0sWzQyODEwLDQyODEwXSxbNDI4MTIsNDI4MTJdLFs0MjgxNCw0MjgxNF0sWzQyODE2LDQyODE2XSxbNDI4MTgsNDI4MThdLFs0MjgyMCw0MjgyMF0sWzQyODIyLDQyODIyXSxbNDI4MjQsNDI4MjRdLFs0MjgyNiw0MjgyNl0sWzQyODI4LDQyODI4XSxbNDI4MzAsNDI4MzBdLFs0MjgzMiw0MjgzMl0sWzQyODM0LDQyODM0XSxbNDI4MzYsNDI4MzZdLFs0MjgzOCw0MjgzOF0sWzQyODQwLDQyODQwXSxbNDI4NDIsNDI4NDJdLFs0Mjg0NCw0Mjg0NF0sWzQyODQ2LDQyODQ2XSxbNDI4NDgsNDI4NDhdLFs0Mjg1MCw0Mjg1MF0sWzQyODUyLDQyODUyXSxbNDI4NTQsNDI4NTRdLFs0Mjg1Niw0Mjg1Nl0sWzQyODU4LDQyODU4XSxbNDI4NjAsNDI4NjBdLFs0Mjg2Miw0Mjg2Ml0sWzQyODczLDQyODczXSxbNDI4NzUsNDI4NzVdLFs0Mjg3Nyw0Mjg3OF0sWzQyODgwLDQyODgwXSxbNDI4ODIsNDI4ODJdLFs0Mjg4NCw0Mjg4NF0sWzQyODg2LDQyODg2XSxbNDI4OTEsNDI4OTFdLFs0Mjg5Myw0Mjg5M10sWzQyODk2LDQyODk2XSxbNDI4OTgsNDI4OThdLFs0MjkwMiw0MjkwMl0sWzQyOTA0LDQyOTA0XSxbNDI5MDYsNDI5MDZdLFs0MjkwOCw0MjkwOF0sWzQyOTEwLDQyOTEwXSxbNDI5MTIsNDI5MTJdLFs0MjkxNCw0MjkxNF0sWzQyOTE2LDQyOTE2XSxbNDI5MTgsNDI5MThdLFs0MjkyMCw0MjkyMF0sWzQyOTIyLDQyOTI2XSxbNDI5MjgsNDI5MzJdLFs0MjkzNCw0MjkzNF0sWzY1MzEzLDY1MzM4XV0sUGQ6W1s0NSw0NV0sWzE0MTgsMTQxOF0sWzE0NzAsMTQ3MF0sWzUxMjAsNTEyMF0sWzYxNTAsNjE1MF0sWzgyMDgsODIxM10sWzExNzk5LDExNzk5XSxbMTE4MDIsMTE4MDJdLFsxMTgzNCwxMTgzNV0sWzExODQwLDExODQwXSxbMTIzMTYsMTIzMTZdLFsxMjMzNiwxMjMzNl0sWzEyNDQ4LDEyNDQ4XSxbNjUwNzMsNjUwNzRdLFs2NTExMiw2NTExMl0sWzY1MTIzLDY1MTIzXSxbNjUyOTMsNjUyOTNdXSxDZjpbWzE3MywxNzNdLFsxNTM2LDE1NDFdLFsxNTY0LDE1NjRdLFsxNzU3LDE3NTddLFsxODA3LDE4MDddLFsyMjc0LDIyNzRdLFs2MTU4LDYxNThdLFs4MjAzLDgyMDddLFs4MjM0LDgyMzhdLFs4Mjg4LDgyOTJdLFs4Mjk0LDgzMDNdLFs2NTI3OSw2NTI3OV0sWzY1NTI5LDY1NTMxXV0sTmQ6W1s0OCw1N10sWzE2MzIsMTY0MV0sWzE3NzYsMTc4NV0sWzE5ODQsMTk5M10sWzI0MDYsMjQxNV0sWzI1MzQsMjU0M10sWzI2NjIsMjY3MV0sWzI3OTAsMjc5OV0sWzI5MTgsMjkyN10sWzMwNDYsMzA1NV0sWzMxNzQsMzE4M10sWzMzMDIsMzMxMV0sWzM0MzAsMzQzOV0sWzM1NTgsMzU2N10sWzM2NjQsMzY3M10sWzM3OTIsMzgwMV0sWzM4NzIsMzg4MV0sWzQxNjAsNDE2OV0sWzQyNDAsNDI0OV0sWzYxMTIsNjEyMV0sWzYxNjAsNjE2OV0sWzY0NzAsNjQ3OV0sWzY2MDgsNjYxN10sWzY3ODQsNjc5M10sWzY4MDAsNjgwOV0sWzY5OTIsNzAwMV0sWzcwODgsNzA5N10sWzcyMzIsNzI0MV0sWzcyNDgsNzI1N10sWzQyNTI4LDQyNTM3XSxbNDMyMTYsNDMyMjVdLFs0MzI2NCw0MzI3M10sWzQzNDcyLDQzNDgxXSxbNDM1MDQsNDM1MTNdLFs0MzYwMCw0MzYwOV0sWzQ0MDE2LDQ0MDI1XSxbNjUyOTYsNjUzMDVdXSxMbDpbWzk3LDEyMl0sWzE4MSwxODFdLFsyMjMsMjQ2XSxbMjQ4LDI1NV0sWzI1NywyNTddLFsyNTksMjU5XSxbMjYxLDI2MV0sWzI2MywyNjNdLFsyNjUsMjY1XSxbMjY3LDI2N10sWzI2OSwyNjldLFsyNzEsMjcxXSxbMjczLDI3M10sWzI3NSwyNzVdLFsyNzcsMjc3XSxbMjc5LDI3OV0sWzI4MSwyODFdLFsyODMsMjgzXSxbMjg1LDI4NV0sWzI4NywyODddLFsyODksMjg5XSxbMjkxLDI5MV0sWzI5MywyOTNdLFsyOTUsMjk1XSxbMjk3LDI5N10sWzI5OSwyOTldLFszMDEsMzAxXSxbMzAzLDMwM10sWzMwNSwzMDVdLFszMDcsMzA3XSxbMzA5LDMwOV0sWzMxMSwzMTJdLFszMTQsMzE0XSxbMzE2LDMxNl0sWzMxOCwzMThdLFszMjAsMzIwXSxbMzIyLDMyMl0sWzMyNCwzMjRdLFszMjYsMzI2XSxbMzI4LDMyOV0sWzMzMSwzMzFdLFszMzMsMzMzXSxbMzM1LDMzNV0sWzMzNywzMzddLFszMzksMzM5XSxbMzQxLDM0MV0sWzM0MywzNDNdLFszNDUsMzQ1XSxbMzQ3LDM0N10sWzM0OSwzNDldLFszNTEsMzUxXSxbMzUzLDM1M10sWzM1NSwzNTVdLFszNTcsMzU3XSxbMzU5LDM1OV0sWzM2MSwzNjFdLFszNjMsMzYzXSxbMzY1LDM2NV0sWzM2NywzNjddLFszNjksMzY5XSxbMzcxLDM3MV0sWzM3MywzNzNdLFszNzUsMzc1XSxbMzc4LDM3OF0sWzM4MCwzODBdLFszODIsMzg0XSxbMzg3LDM4N10sWzM4OSwzODldLFszOTIsMzkyXSxbMzk2LDM5N10sWzQwMiw0MDJdLFs0MDUsNDA1XSxbNDA5LDQxMV0sWzQxNCw0MTRdLFs0MTcsNDE3XSxbNDE5LDQxOV0sWzQyMSw0MjFdLFs0MjQsNDI0XSxbNDI2LDQyN10sWzQyOSw0MjldLFs0MzIsNDMyXSxbNDM2LDQzNl0sWzQzOCw0MzhdLFs0NDEsNDQyXSxbNDQ1LDQ0N10sWzQ1NCw0NTRdLFs0NTcsNDU3XSxbNDYwLDQ2MF0sWzQ2Miw0NjJdLFs0NjQsNDY0XSxbNDY2LDQ2Nl0sWzQ2OCw0NjhdLFs0NzAsNDcwXSxbNDcyLDQ3Ml0sWzQ3NCw0NzRdLFs0NzYsNDc3XSxbNDc5LDQ3OV0sWzQ4MSw0ODFdLFs0ODMsNDgzXSxbNDg1LDQ4NV0sWzQ4Nyw0ODddLFs0ODksNDg5XSxbNDkxLDQ5MV0sWzQ5Myw0OTNdLFs0OTUsNDk2XSxbNDk5LDQ5OV0sWzUwMSw1MDFdLFs1MDUsNTA1XSxbNTA3LDUwN10sWzUwOSw1MDldLFs1MTEsNTExXSxbNTEzLDUxM10sWzUxNSw1MTVdLFs1MTcsNTE3XSxbNTE5LDUxOV0sWzUyMSw1MjFdLFs1MjMsNTIzXSxbNTI1LDUyNV0sWzUyNyw1MjddLFs1MjksNTI5XSxbNTMxLDUzMV0sWzUzMyw1MzNdLFs1MzUsNTM1XSxbNTM3LDUzN10sWzUzOSw1MzldLFs1NDEsNTQxXSxbNTQzLDU0M10sWzU0NSw1NDVdLFs1NDcsNTQ3XSxbNTQ5LDU0OV0sWzU1MSw1NTFdLFs1NTMsNTUzXSxbNTU1LDU1NV0sWzU1Nyw1NTddLFs1NTksNTU5XSxbNTYxLDU2MV0sWzU2Myw1NjldLFs1NzIsNTcyXSxbNTc1LDU3Nl0sWzU3OCw1NzhdLFs1ODMsNTgzXSxbNTg1LDU4NV0sWzU4Nyw1ODddLFs1ODksNTg5XSxbNTkxLDY1OV0sWzY2MSw2ODddLFs4ODEsODgxXSxbODgzLDg4M10sWzg4Nyw4ODddLFs4OTEsODkzXSxbOTEyLDkxMl0sWzk0MCw5NzRdLFs5NzYsOTc3XSxbOTgxLDk4M10sWzk4NSw5ODVdLFs5ODcsOTg3XSxbOTg5LDk4OV0sWzk5MSw5OTFdLFs5OTMsOTkzXSxbOTk1LDk5NV0sWzk5Nyw5OTddLFs5OTksOTk5XSxbMTAwMSwxMDAxXSxbMTAwMywxMDAzXSxbMTAwNSwxMDA1XSxbMTAwNywxMDExXSxbMTAxMywxMDEzXSxbMTAxNiwxMDE2XSxbMTAxOSwxMDIwXSxbMTA3MiwxMTE5XSxbMTEyMSwxMTIxXSxbMTEyMywxMTIzXSxbMTEyNSwxMTI1XSxbMTEyNywxMTI3XSxbMTEyOSwxMTI5XSxbMTEzMSwxMTMxXSxbMTEzMywxMTMzXSxbMTEzNSwxMTM1XSxbMTEzNywxMTM3XSxbMTEzOSwxMTM5XSxbMTE0MSwxMTQxXSxbMTE0MywxMTQzXSxbMTE0NSwxMTQ1XSxbMTE0NywxMTQ3XSxbMTE0OSwxMTQ5XSxbMTE1MSwxMTUxXSxbMTE1MywxMTUzXSxbMTE2MywxMTYzXSxbMTE2NSwxMTY1XSxbMTE2NywxMTY3XSxbMTE2OSwxMTY5XSxbMTE3MSwxMTcxXSxbMTE3MywxMTczXSxbMTE3NSwxMTc1XSxbMTE3NywxMTc3XSxbMTE3OSwxMTc5XSxbMTE4MSwxMTgxXSxbMTE4MywxMTgzXSxbMTE4NSwxMTg1XSxbMTE4NywxMTg3XSxbMTE4OSwxMTg5XSxbMTE5MSwxMTkxXSxbMTE5MywxMTkzXSxbMTE5NSwxMTk1XSxbMTE5NywxMTk3XSxbMTE5OSwxMTk5XSxbMTIwMSwxMjAxXSxbMTIwMywxMjAzXSxbMTIwNSwxMjA1XSxbMTIwNywxMjA3XSxbMTIwOSwxMjA5XSxbMTIxMSwxMjExXSxbMTIxMywxMjEzXSxbMTIxNSwxMjE1XSxbMTIxOCwxMjE4XSxbMTIyMCwxMjIwXSxbMTIyMiwxMjIyXSxbMTIyNCwxMjI0XSxbMTIyNiwxMjI2XSxbMTIyOCwxMjI4XSxbMTIzMCwxMjMxXSxbMTIzMywxMjMzXSxbMTIzNSwxMjM1XSxbMTIzNywxMjM3XSxbMTIzOSwxMjM5XSxbMTI0MSwxMjQxXSxbMTI0MywxMjQzXSxbMTI0NSwxMjQ1XSxbMTI0NywxMjQ3XSxbMTI0OSwxMjQ5XSxbMTI1MSwxMjUxXSxbMTI1MywxMjUzXSxbMTI1NSwxMjU1XSxbMTI1NywxMjU3XSxbMTI1OSwxMjU5XSxbMTI2MSwxMjYxXSxbMTI2MywxMjYzXSxbMTI2NSwxMjY1XSxbMTI2NywxMjY3XSxbMTI2OSwxMjY5XSxbMTI3MSwxMjcxXSxbMTI3MywxMjczXSxbMTI3NSwxMjc1XSxbMTI3NywxMjc3XSxbMTI3OSwxMjc5XSxbMTI4MSwxMjgxXSxbMTI4MywxMjgzXSxbMTI4NSwxMjg1XSxbMTI4NywxMjg3XSxbMTI4OSwxMjg5XSxbMTI5MSwxMjkxXSxbMTI5MywxMjkzXSxbMTI5NSwxMjk1XSxbMTI5NywxMjk3XSxbMTI5OSwxMjk5XSxbMTMwMSwxMzAxXSxbMTMwMywxMzAzXSxbMTMwNSwxMzA1XSxbMTMwNywxMzA3XSxbMTMwOSwxMzA5XSxbMTMxMSwxMzExXSxbMTMxMywxMzEzXSxbMTMxNSwxMzE1XSxbMTMxNywxMzE3XSxbMTMxOSwxMzE5XSxbMTMyMSwxMzIxXSxbMTMyMywxMzIzXSxbMTMyNSwxMzI1XSxbMTMyNywxMzI3XSxbMTM3NywxNDE1XSxbNTExMiw1MTE3XSxbNzI5Niw3MzA0XSxbNzQyNCw3NDY3XSxbNzUzMSw3NTQzXSxbNzU0NSw3NTc4XSxbNzY4MSw3NjgxXSxbNzY4Myw3NjgzXSxbNzY4NSw3Njg1XSxbNzY4Nyw3Njg3XSxbNzY4OSw3Njg5XSxbNzY5MSw3NjkxXSxbNzY5Myw3NjkzXSxbNzY5NSw3Njk1XSxbNzY5Nyw3Njk3XSxbNzY5OSw3Njk5XSxbNzcwMSw3NzAxXSxbNzcwMyw3NzAzXSxbNzcwNSw3NzA1XSxbNzcwNyw3NzA3XSxbNzcwOSw3NzA5XSxbNzcxMSw3NzExXSxbNzcxMyw3NzEzXSxbNzcxNSw3NzE1XSxbNzcxNyw3NzE3XSxbNzcxOSw3NzE5XSxbNzcyMSw3NzIxXSxbNzcyMyw3NzIzXSxbNzcyNSw3NzI1XSxbNzcyNyw3NzI3XSxbNzcyOSw3NzI5XSxbNzczMSw3NzMxXSxbNzczMyw3NzMzXSxbNzczNSw3NzM1XSxbNzczNyw3NzM3XSxbNzczOSw3NzM5XSxbNzc0MSw3NzQxXSxbNzc0Myw3NzQzXSxbNzc0NSw3NzQ1XSxbNzc0Nyw3NzQ3XSxbNzc0OSw3NzQ5XSxbNzc1MSw3NzUxXSxbNzc1Myw3NzUzXSxbNzc1NSw3NzU1XSxbNzc1Nyw3NzU3XSxbNzc1OSw3NzU5XSxbNzc2MSw3NzYxXSxbNzc2Myw3NzYzXSxbNzc2NSw3NzY1XSxbNzc2Nyw3NzY3XSxbNzc2OSw3NzY5XSxbNzc3MSw3NzcxXSxbNzc3Myw3NzczXSxbNzc3NSw3Nzc1XSxbNzc3Nyw3Nzc3XSxbNzc3OSw3Nzc5XSxbNzc4MSw3NzgxXSxbNzc4Myw3NzgzXSxbNzc4NSw3Nzg1XSxbNzc4Nyw3Nzg3XSxbNzc4OSw3Nzg5XSxbNzc5MSw3NzkxXSxbNzc5Myw3NzkzXSxbNzc5NSw3Nzk1XSxbNzc5Nyw3Nzk3XSxbNzc5OSw3Nzk5XSxbNzgwMSw3ODAxXSxbNzgwMyw3ODAzXSxbNzgwNSw3ODA1XSxbNzgwNyw3ODA3XSxbNzgwOSw3ODA5XSxbNzgxMSw3ODExXSxbNzgxMyw3ODEzXSxbNzgxNSw3ODE1XSxbNzgxNyw3ODE3XSxbNzgxOSw3ODE5XSxbNzgyMSw3ODIxXSxbNzgyMyw3ODIzXSxbNzgyNSw3ODI1XSxbNzgyNyw3ODI3XSxbNzgyOSw3ODM3XSxbNzgzOSw3ODM5XSxbNzg0MSw3ODQxXSxbNzg0Myw3ODQzXSxbNzg0NSw3ODQ1XSxbNzg0Nyw3ODQ3XSxbNzg0OSw3ODQ5XSxbNzg1MSw3ODUxXSxbNzg1Myw3ODUzXSxbNzg1NSw3ODU1XSxbNzg1Nyw3ODU3XSxbNzg1OSw3ODU5XSxbNzg2MSw3ODYxXSxbNzg2Myw3ODYzXSxbNzg2NSw3ODY1XSxbNzg2Nyw3ODY3XSxbNzg2OSw3ODY5XSxbNzg3MSw3ODcxXSxbNzg3Myw3ODczXSxbNzg3NSw3ODc1XSxbNzg3Nyw3ODc3XSxbNzg3OSw3ODc5XSxbNzg4MSw3ODgxXSxbNzg4Myw3ODgzXSxbNzg4NSw3ODg1XSxbNzg4Nyw3ODg3XSxbNzg4OSw3ODg5XSxbNzg5MSw3ODkxXSxbNzg5Myw3ODkzXSxbNzg5NSw3ODk1XSxbNzg5Nyw3ODk3XSxbNzg5OSw3ODk5XSxbNzkwMSw3OTAxXSxbNzkwMyw3OTAzXSxbNzkwNSw3OTA1XSxbNzkwNyw3OTA3XSxbNzkwOSw3OTA5XSxbNzkxMSw3OTExXSxbNzkxMyw3OTEzXSxbNzkxNSw3OTE1XSxbNzkxNyw3OTE3XSxbNzkxOSw3OTE5XSxbNzkyMSw3OTIxXSxbNzkyMyw3OTIzXSxbNzkyNSw3OTI1XSxbNzkyNyw3OTI3XSxbNzkyOSw3OTI5XSxbNzkzMSw3OTMxXSxbNzkzMyw3OTMzXSxbNzkzNSw3OTQzXSxbNzk1Miw3OTU3XSxbNzk2OCw3OTc1XSxbNzk4NCw3OTkxXSxbOGUzLDgwMDVdLFs4MDE2LDgwMjNdLFs4MDMyLDgwMzldLFs4MDQ4LDgwNjFdLFs4MDY0LDgwNzFdLFs4MDgwLDgwODddLFs4MDk2LDgxMDNdLFs4MTEyLDgxMTZdLFs4MTE4LDgxMTldLFs4MTI2LDgxMjZdLFs4MTMwLDgxMzJdLFs4MTM0LDgxMzVdLFs4MTQ0LDgxNDddLFs4MTUwLDgxNTFdLFs4MTYwLDgxNjddLFs4MTc4LDgxODBdLFs4MTgyLDgxODNdLFs4NDU4LDg0NThdLFs4NDYyLDg0NjNdLFs4NDY3LDg0NjddLFs4NDk1LDg0OTVdLFs4NTAwLDg1MDBdLFs4NTA1LDg1MDVdLFs4NTA4LDg1MDldLFs4NTE4LDg1MjFdLFs4NTI2LDg1MjZdLFs4NTgwLDg1ODBdLFsxMTMxMiwxMTM1OF0sWzExMzYxLDExMzYxXSxbMTEzNjUsMTEzNjZdLFsxMTM2OCwxMTM2OF0sWzExMzcwLDExMzcwXSxbMTEzNzIsMTEzNzJdLFsxMTM3NywxMTM3N10sWzExMzc5LDExMzgwXSxbMTEzODIsMTEzODddLFsxMTM5MywxMTM5M10sWzExMzk1LDExMzk1XSxbMTEzOTcsMTEzOTddLFsxMTM5OSwxMTM5OV0sWzExNDAxLDExNDAxXSxbMTE0MDMsMTE0MDNdLFsxMTQwNSwxMTQwNV0sWzExNDA3LDExNDA3XSxbMTE0MDksMTE0MDldLFsxMTQxMSwxMTQxMV0sWzExNDEzLDExNDEzXSxbMTE0MTUsMTE0MTVdLFsxMTQxNywxMTQxN10sWzExNDE5LDExNDE5XSxbMTE0MjEsMTE0MjFdLFsxMTQyMywxMTQyM10sWzExNDI1LDExNDI1XSxbMTE0MjcsMTE0MjddLFsxMTQyOSwxMTQyOV0sWzExNDMxLDExNDMxXSxbMTE0MzMsMTE0MzNdLFsxMTQzNSwxMTQzNV0sWzExNDM3LDExNDM3XSxbMTE0MzksMTE0MzldLFsxMTQ0MSwxMTQ0MV0sWzExNDQzLDExNDQzXSxbMTE0NDUsMTE0NDVdLFsxMTQ0NywxMTQ0N10sWzExNDQ5LDExNDQ5XSxbMTE0NTEsMTE0NTFdLFsxMTQ1MywxMTQ1M10sWzExNDU1LDExNDU1XSxbMTE0NTcsMTE0NTddLFsxMTQ1OSwxMTQ1OV0sWzExNDYxLDExNDYxXSxbMTE0NjMsMTE0NjNdLFsxMTQ2NSwxMTQ2NV0sWzExNDY3LDExNDY3XSxbMTE0NjksMTE0NjldLFsxMTQ3MSwxMTQ3MV0sWzExNDczLDExNDczXSxbMTE0NzUsMTE0NzVdLFsxMTQ3NywxMTQ3N10sWzExNDc5LDExNDc5XSxbMTE0ODEsMTE0ODFdLFsxMTQ4MywxMTQ4M10sWzExNDg1LDExNDg1XSxbMTE0ODcsMTE0ODddLFsxMTQ4OSwxMTQ4OV0sWzExNDkxLDExNDkyXSxbMTE1MDAsMTE1MDBdLFsxMTUwMiwxMTUwMl0sWzExNTA3LDExNTA3XSxbMTE1MjAsMTE1NTddLFsxMTU1OSwxMTU1OV0sWzExNTY1LDExNTY1XSxbNDI1NjEsNDI1NjFdLFs0MjU2Myw0MjU2M10sWzQyNTY1LDQyNTY1XSxbNDI1NjcsNDI1NjddLFs0MjU2OSw0MjU2OV0sWzQyNTcxLDQyNTcxXSxbNDI1NzMsNDI1NzNdLFs0MjU3NSw0MjU3NV0sWzQyNTc3LDQyNTc3XSxbNDI1NzksNDI1NzldLFs0MjU4MSw0MjU4MV0sWzQyNTgzLDQyNTgzXSxbNDI1ODUsNDI1ODVdLFs0MjU4Nyw0MjU4N10sWzQyNTg5LDQyNTg5XSxbNDI1OTEsNDI1OTFdLFs0MjU5Myw0MjU5M10sWzQyNTk1LDQyNTk1XSxbNDI1OTcsNDI1OTddLFs0MjU5OSw0MjU5OV0sWzQyNjAxLDQyNjAxXSxbNDI2MDMsNDI2MDNdLFs0MjYwNSw0MjYwNV0sWzQyNjI1LDQyNjI1XSxbNDI2MjcsNDI2MjddLFs0MjYyOSw0MjYyOV0sWzQyNjMxLDQyNjMxXSxbNDI2MzMsNDI2MzNdLFs0MjYzNSw0MjYzNV0sWzQyNjM3LDQyNjM3XSxbNDI2MzksNDI2MzldLFs0MjY0MSw0MjY0MV0sWzQyNjQzLDQyNjQzXSxbNDI2NDUsNDI2NDVdLFs0MjY0Nyw0MjY0N10sWzQyNjQ5LDQyNjQ5XSxbNDI2NTEsNDI2NTFdLFs0Mjc4Nyw0Mjc4N10sWzQyNzg5LDQyNzg5XSxbNDI3OTEsNDI3OTFdLFs0Mjc5Myw0Mjc5M10sWzQyNzk1LDQyNzk1XSxbNDI3OTcsNDI3OTddLFs0Mjc5OSw0MjgwMV0sWzQyODAzLDQyODAzXSxbNDI4MDUsNDI4MDVdLFs0MjgwNyw0MjgwN10sWzQyODA5LDQyODA5XSxbNDI4MTEsNDI4MTFdLFs0MjgxMyw0MjgxM10sWzQyODE1LDQyODE1XSxbNDI4MTcsNDI4MTddLFs0MjgxOSw0MjgxOV0sWzQyODIxLDQyODIxXSxbNDI4MjMsNDI4MjNdLFs0MjgyNSw0MjgyNV0sWzQyODI3LDQyODI3XSxbNDI4MjksNDI4MjldLFs0MjgzMSw0MjgzMV0sWzQyODMzLDQyODMzXSxbNDI4MzUsNDI4MzVdLFs0MjgzNyw0MjgzN10sWzQyODM5LDQyODM5XSxbNDI4NDEsNDI4NDFdLFs0Mjg0Myw0Mjg0M10sWzQyODQ1LDQyODQ1XSxbNDI4NDcsNDI4NDddLFs0Mjg0OSw0Mjg0OV0sWzQyODUxLDQyODUxXSxbNDI4NTMsNDI4NTNdLFs0Mjg1NSw0Mjg1NV0sWzQyODU3LDQyODU3XSxbNDI4NTksNDI4NTldLFs0Mjg2MSw0Mjg2MV0sWzQyODYzLDQyODYzXSxbNDI4NjUsNDI4NzJdLFs0Mjg3NCw0Mjg3NF0sWzQyODc2LDQyODc2XSxbNDI4NzksNDI4NzldLFs0Mjg4MSw0Mjg4MV0sWzQyODgzLDQyODgzXSxbNDI4ODUsNDI4ODVdLFs0Mjg4Nyw0Mjg4N10sWzQyODkyLDQyODkyXSxbNDI4OTQsNDI4OTRdLFs0Mjg5Nyw0Mjg5N10sWzQyODk5LDQyOTAxXSxbNDI5MDMsNDI5MDNdLFs0MjkwNSw0MjkwNV0sWzQyOTA3LDQyOTA3XSxbNDI5MDksNDI5MDldLFs0MjkxMSw0MjkxMV0sWzQyOTEzLDQyOTEzXSxbNDI5MTUsNDI5MTVdLFs0MjkxNyw0MjkxN10sWzQyOTE5LDQyOTE5XSxbNDI5MjEsNDI5MjFdLFs0MjkzMyw0MjkzM10sWzQyOTM1LDQyOTM1XSxbNDMwMDIsNDMwMDJdLFs0MzgyNCw0Mzg2Nl0sWzQzODcyLDQzODc3XSxbNDM4ODgsNDM5NjddLFs2NDI1Niw2NDI2Ml0sWzY0Mjc1LDY0Mjc5XSxbNjUzNDUsNjUzNzBdXSxObzpbWzE3OCwxNzldLFsxODUsMTg1XSxbMTg4LDE5MF0sWzI1NDgsMjU1M10sWzI5MzAsMjkzNV0sWzMwNTYsMzA1OF0sWzMxOTIsMzE5OF0sWzM0MTYsMzQyMl0sWzM0NDAsMzQ0OF0sWzM4ODIsMzg5MV0sWzQ5NjksNDk4OF0sWzYxMjgsNjEzN10sWzY2MTgsNjYxOF0sWzgzMDQsODMwNF0sWzgzMDgsODMxM10sWzgzMjAsODMyOV0sWzg1MjgsODU0M10sWzg1ODUsODU4NV0sWzkzMTIsOTM3MV0sWzk0NTAsOTQ3MV0sWzEwMTAyLDEwMTMxXSxbMTE1MTcsMTE1MTddLFsxMjY5MCwxMjY5M10sWzEyODMyLDEyODQxXSxbMTI4NzIsMTI4NzldLFsxMjg4MSwxMjg5NV0sWzEyOTI4LDEyOTM3XSxbMTI5NzcsMTI5OTFdLFs0MzA1Niw0MzA2MV1dLFpzOltbMzIsMzJdLFsxNjAsMTYwXSxbNTc2MCw1NzYwXSxbODE5Miw4MjAyXSxbODIzOSw4MjM5XSxbODI4Nyw4Mjg3XSxbMTIyODgsMTIyODhdXX19fSk7dW53cmFwRXhwb3J0cyhkYXRhX2dlbmVyYXRlZCk7dmFyIHV0aWxzJDI9Y3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe3JldHVybiBlLnNvcnQoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZVswXS10WzBdfSkucmVkdWNlKGZ1bmN0aW9uKGUsdCxuKXtpZigwPT09bilyZXR1cm5bdF07dmFyIHI9ZVtlLmxlbmd0aC0xXSxpPXJbMF0sbz1yWzFdLGE9dFswXSxzPXRbMV07cmV0dXJuIG8rMT09PWE/ZS5zbGljZSgwLC0xKS5jb25jYXQoW1tpLHNdXSk6ZS5jb25jYXQoW3RdKX0sW10pfWZ1bmN0aW9uIHIoZSx0KXt2YXIgbj1lLm1hcChmdW5jdGlvbihlKXt2YXIgdD1lWzBdLG49ZVsxXTtyZXR1cm4gdD09PW4/IlxcdSIraSh0KToiXFx1IitpKHQpKyItXFx1IitpKG4pfSkuam9pbigiIik7cmV0dXJuIG5ldyBSZWdFeHAoIlsiK24rIl0iLHQpfWZ1bmN0aW9uIGkoZSl7Zm9yKHZhciB0PWUudG9TdHJpbmcoMTYpO3QubGVuZ3RoPDQ7KXQ9IjAiK3Q7cmV0dXJuIHR9dC5fX2VzTW9kdWxlPSEwLHQubm9ybWFsaXplX3Jhbmdlcz1uLHQuYnVpbGRfcmVnZXg9cn0pO3Vud3JhcEV4cG9ydHModXRpbHMkMik7dmFyIGxpYiQ1PWZ1bmN0aW9uKGUsdCl7dmFyIG49ZGF0YV9nZW5lcmF0ZWQuZ2V0X2RhdGEoKSxyPWUucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUuY29uY2F0KG5bdF0pfSxbXSk7cmV0dXJuIHV0aWxzJDIuYnVpbGRfcmVnZXgodXRpbHMkMi5ub3JtYWxpemVfcmFuZ2VzKHIpLHQpfSxlbW9qaVJlZ2V4PWVtb2ppUmVnZXgkMSgpLGNqa1BhdHRlcm49bGliJDMoKS5zb3VyY2UsYXNjaWlQdW5jdHVhdGlvbkNoYXJSYW5nZT1lc2NhcGVTdHJpbmdSZWdleHAoIiFcIiMkJSYnKCkqKywtLi86Ozw9Pj9AW1xcXV5fYHt8fX4iKSxwdW5jdHVhdGlvbkNoYXJSYW5nZT0iIi5jb25jYXQoYXNjaWlQdW5jdHVhdGlvbkNoYXJSYW5nZSkuY29uY2F0KGxpYiQ1KFsiUGMiLCJQZCIsIlBlIiwiUGYiLCJQaSIsIlBvIiwiUHMiXSkuc291cmNlLnNsaWNlKDEsLTEpKSxwdW5jdHVhdGlvblJlZ2V4PW5ldyBSZWdFeHAoIlsiLmNvbmNhdChwdW5jdHVhdGlvbkNoYXJSYW5nZSwiXSIpKSxza2lwV2hpdGVzcGFjZT1za2lwKC9ccy8pLHNraXBTcGFjZXM9c2tpcCgiIFx0Iiksc2tpcFRvTGluZUVuZD1za2lwKCIsOyBcdCIpLHNraXBFdmVyeXRoaW5nQnV0TmV3TGluZT1za2lwKC9bXlxyXG5dLyksUFJFQ0VERU5DRT17fTtbWyJ8PiJdLFsifHwiLCI/PyJdLFsiJiYiXSxbInwiXSxbIl4iXSxbIiYiXSxbIj09IiwiPT09IiwiIT0iLCIhPT0iXSxbIjwiLCI+IiwiPD0iLCI+PSIsImluIiwiaW5zdGFuY2VvZiJdLFsiPj4iLCI8PCIsIj4+PiJdLFsiKyIsIi0iXSxbIioiLCIvIiwiJSJdLFsiKioiXV0uZm9yRWFjaChmdW5jdGlvbihlLHQpe2UuZm9yRWFjaChmdW5jdGlvbihlKXtQUkVDRURFTkNFW2VdPXR9KX0pO3ZhciBlcXVhbGl0eU9wZXJhdG9ycz17Ij09IjohMCwiIT0iOiEwLCI9PT0iOiEwLCIhPT0iOiEwfSxhZGRpdGl2ZU9wZXJhdG9ycz17IisiOiEwLCItIjohMH0sbXVsdGlwbGljYXRpdmVPcGVyYXRvcnM9eyIqIjohMCwiLyI6ITAsIiUiOiEwfSxiaXRzaGlmdE9wZXJhdG9ycz17Ij4+IjohMCwiPj4+IjohMCwiPDwiOiEwfSx1dGlsPXtwdW5jdHVhdGlvblJlZ2V4OnB1bmN0dWF0aW9uUmVnZXgscHVuY3R1YXRpb25DaGFyUmFuZ2U6cHVuY3R1YXRpb25DaGFyUmFuZ2UsZ2V0U3RyaW5nV2lkdGg6Z2V0U3RyaW5nV2lkdGgsc3BsaXRUZXh0OnNwbGl0VGV4dCxnZXRNYXhDb250aW51b3VzQ291bnQ6Z2V0TWF4Q29udGludW91c0NvdW50LGdldFByZWNlZGVuY2U6Z2V0UHJlY2VkZW5jZSxzaG91bGRGbGF0dGVuOnNob3VsZEZsYXR0ZW4saXNCaXR3aXNlT3BlcmF0b3I6aXNCaXR3aXNlT3BlcmF0b3IsaXNFeHBvcnREZWNsYXJhdGlvbjppc0V4cG9ydERlY2xhcmF0aW9uLGdldFBhcmVudEV4cG9ydERlY2xhcmF0aW9uOmdldFBhcmVudEV4cG9ydERlY2xhcmF0aW9uLGdldFBlbnVsdGltYXRlOmdldFBlbnVsdGltYXRlLGdldExhc3Q6Z2V0TGFzdCQzLGdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXJJbmRleDpnZXROZXh0Tm9uU3BhY2VOb25Db21tZW50Q2hhcmFjdGVySW5kZXgsZ2V0TmV4dE5vblNwYWNlTm9uQ29tbWVudENoYXJhY3RlcjpnZXROZXh0Tm9uU3BhY2VOb25Db21tZW50Q2hhcmFjdGVyLHNraXBXaGl0ZXNwYWNlOnNraXBXaGl0ZXNwYWNlLHNraXBTcGFjZXM6c2tpcFNwYWNlcyxza2lwTmV3bGluZTpza2lwTmV3bGluZSQxLGlzTmV4dExpbmVFbXB0eUFmdGVySW5kZXg6aXNOZXh0TGluZUVtcHR5QWZ0ZXJJbmRleCxpc05leHRMaW5lRW1wdHk6aXNOZXh0TGluZUVtcHR5LGlzUHJldmlvdXNMaW5lRW1wdHk6aXNQcmV2aW91c0xpbmVFbXB0eSQxLGhhc05ld2xpbmU6aGFzTmV3bGluZSQxLGhhc05ld2xpbmVJblJhbmdlOmhhc05ld2xpbmVJblJhbmdlLGhhc1NwYWNlczpoYXNTcGFjZXMsc2V0TG9jU3RhcnQ6c2V0TG9jU3RhcnQsc2V0TG9jRW5kOnNldExvY0VuZCxzdGFydHNXaXRoTm9Mb29rYWhlYWRUb2tlbjpzdGFydHNXaXRoTm9Mb29rYWhlYWRUb2tlbixnZXRBbGlnbm1lbnRTaXplOmdldEFsaWdubWVudFNpemUsZ2V0SW5kZW50U2l6ZTpnZXRJbmRlbnRTaXplLHByaW50U3RyaW5nOnByaW50U3RyaW5nLHByaW50TnVtYmVyOnByaW50TnVtYmVyLGhhc0lnbm9yZUNvbW1lbnQ6aGFzSWdub3JlQ29tbWVudCxoYXNOb2RlSWdub3JlQ29tbWVudDpoYXNOb2RlSWdub3JlQ29tbWVudCxtYWtlU3RyaW5nOm1ha2VTdHJpbmcsYWRkTGVhZGluZ0NvbW1lbnQ6YWRkTGVhZGluZ0NvbW1lbnQkMSxhZGREYW5nbGluZ0NvbW1lbnQ6YWRkRGFuZ2xpbmdDb21tZW50JDEsYWRkVHJhaWxpbmdDb21tZW50OmFkZFRyYWlsaW5nQ29tbWVudCQxfSxjb25jYXQkMj1kb2NCdWlsZGVycy5jb25jYXQsZmlsbCQxPWRvY0J1aWxkZXJzLmZpbGwsY3Vyc29yJDI9ZG9jQnVpbGRlcnMuY3Vyc29yLE1PREVfQlJFQUs9MSxNT0RFX0ZMQVQ9Mixkb2NQcmludGVyPXtwcmludERvY1RvU3RyaW5nOnByaW50RG9jVG9TdHJpbmd9LGRvY1V0aWxzPXtpc0VtcHR5OmlzRW1wdHksd2lsbEJyZWFrOndpbGxCcmVhayxpc0xpbmVOZXh0OmlzTGluZU5leHQsdHJhdmVyc2VEb2M6dHJhdmVyc2VEb2MsbWFwRG9jOm1hcERvYyxwcm9wYWdhdGVCcmVha3M6cHJvcGFnYXRlQnJlYWtzLHJlbW92ZUxpbmVzOnJlbW92ZUxpbmVzLHN0cmlwVHJhaWxpbmdIYXJkbGluZTpzdHJpcFRyYWlsaW5nSGFyZGxpbmV9LGRvY0RlYnVnPXtwcmludERvY1RvRGVidWc6ZnVuY3Rpb24oZSl7cmV0dXJuIHByaW50RG9jKGZsYXR0ZW5Eb2MoZSkpfX0sZG9jPXtidWlsZGVyczpkb2NCdWlsZGVycyxwcmludGVyOmRvY1ByaW50ZXIsdXRpbHM6ZG9jVXRpbHMsZGVidWc6ZG9jRGVidWd9LG1hcERvYyQxPWRvYy51dGlscy5tYXBEb2MsdXRpbFNoYXJlZD17aXNOZXh0TGluZUVtcHR5OmlzTmV4dExpbmVFbXB0eSQxLGlzTmV4dExpbmVFbXB0eUFmdGVySW5kZXg6dXRpbC5pc05leHRMaW5lRW1wdHlBZnRlckluZGV4LGdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXJJbmRleDpnZXROZXh0Tm9uU3BhY2VOb25Db21tZW50Q2hhcmFjdGVySW5kZXgkMSxtYXBEb2M6bWFwRG9jJDEsbWFrZVN0cmluZzp1dGlsLm1ha2VTdHJpbmcsYWRkTGVhZGluZ0NvbW1lbnQ6dXRpbC5hZGRMZWFkaW5nQ29tbWVudCxhZGREYW5nbGluZ0NvbW1lbnQ6dXRpbC5hZGREYW5nbGluZ0NvbW1lbnQsYWRkVHJhaWxpbmdDb21tZW50OnV0aWwuYWRkVHJhaWxpbmdDb21tZW50fSxfcmVxdWlyZSQkMCRidWlsZGVycz1kb2MuYnVpbGRlcnMsY29uY2F0PV9yZXF1aXJlJCQwJGJ1aWxkZXJzLmNvbmNhdCxoYXJkbGluZT1fcmVxdWlyZSQkMCRidWlsZGVycy5oYXJkbGluZSxicmVha1BhcmVudD1fcmVxdWlyZSQkMCRidWlsZGVycy5icmVha1BhcmVudCxpbmRlbnQ9X3JlcXVpcmUkJDAkYnVpbGRlcnMuaW5kZW50LGxpbmVTdWZmaXg9X3JlcXVpcmUkJDAkYnVpbGRlcnMubGluZVN1ZmZpeCxqb2luPV9yZXF1aXJlJCQwJGJ1aWxkZXJzLmpvaW4sY3Vyc29yPV9yZXF1aXJlJCQwJGJ1aWxkZXJzLmN1cnNvcixoYXNOZXdsaW5lPXV0aWwuaGFzTmV3bGluZSxza2lwTmV3bGluZT11dGlsLnNraXBOZXdsaW5lLGlzUHJldmlvdXNMaW5lRW1wdHk9dXRpbC5pc1ByZXZpb3VzTGluZUVtcHR5LGFkZExlYWRpbmdDb21tZW50PXV0aWxTaGFyZWQuYWRkTGVhZGluZ0NvbW1lbnQsYWRkRGFuZ2xpbmdDb21tZW50PXV0aWxTaGFyZWQuYWRkRGFuZ2xpbmdDb21tZW50LGFkZFRyYWlsaW5nQ29tbWVudD11dGlsU2hhcmVkLmFkZFRyYWlsaW5nQ29tbWVudCxjaGlsZE5vZGVzQ2FjaGVLZXk9U3ltYm9sKCJjaGlsZC1ub2RlcyIpLGNvbW1lbnRzPXthdHRhY2g6YXR0YWNoLHByaW50Q29tbWVudHM6cHJpbnRDb21tZW50cyxwcmludERhbmdsaW5nQ29tbWVudHM6cHJpbnREYW5nbGluZ0NvbW1lbnRzLGdldFNvcnRlZENoaWxkTm9kZXM6Z2V0U29ydGVkQ2hpbGROb2Rlc307RmFzdFBhdGgucHJvdG90eXBlLmdldE5hbWU9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnN0YWNrLHQ9ZS5sZW5ndGg7cmV0dXJuIHQ+MT9lW3QtMl06bnVsbH0sRmFzdFBhdGgucHJvdG90eXBlLmdldFZhbHVlPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5zdGFjaztyZXR1cm4gZVtlLmxlbmd0aC0xXX0sRmFzdFBhdGgucHJvdG90eXBlLmdldE5vZGU9ZnVuY3Rpb24oZSl7cmV0dXJuIGdldE5vZGVIZWxwZXIodGhpcyx+fmUpfSxGYXN0UGF0aC5wcm90b3R5cGUuZ2V0UGFyZW50Tm9kZT1mdW5jdGlvbihlKXtyZXR1cm4gZ2V0Tm9kZUhlbHBlcih0aGlzLDErfn5lKX0sRmFzdFBhdGgucHJvdG90eXBlLmNhbGw9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PXRoaXMuc3RhY2ssbj10Lmxlbmd0aCxyPXRbbi0xXSxpPWFyZ3VtZW50cy5sZW5ndGgsbz0xO288aTsrK28pe3ZhciBhPWFyZ3VtZW50c1tvXTtyPXJbYV0sdC5wdXNoKGEscil9dmFyIHM9ZSh0aGlzKTtyZXR1cm4gdC5sZW5ndGg9bixzfSxGYXN0UGF0aC5wcm90b3R5cGUuZWFjaD1mdW5jdGlvbihlKXtmb3IodmFyIHQ9dGhpcy5zdGFjayxuPXQubGVuZ3RoLHI9dFtuLTFdLGk9YXJndW1lbnRzLmxlbmd0aCxvPTE7bzxpOysrbyl7dmFyIGE9YXJndW1lbnRzW29dO3I9clthXSx0LnB1c2goYSxyKX1mb3IodmFyIHM9MDtzPHIubGVuZ3RoOysrcylzIGluIHImJih0LnB1c2gocyxyW3NdKSxlKHRoaXMpLHQubGVuZ3RoLT0yKTt0Lmxlbmd0aD1ufSxGYXN0UGF0aC5wcm90b3R5cGUubWFwPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD10aGlzLnN0YWNrLG49dC5sZW5ndGgscj10W24tMV0saT1hcmd1bWVudHMubGVuZ3RoLG89MTtvPGk7KytvKXt2YXIgYT1hcmd1bWVudHNbb107cj1yW2FdLHQucHVzaChhLHIpfWZvcih2YXIgcz1uZXcgQXJyYXkoci5sZW5ndGgpLHU9MDt1PHIubGVuZ3RoOysrdSl1IGluIHImJih0LnB1c2godSxyW3VdKSxzW3VdPWUodGhpcyx1KSx0Lmxlbmd0aC09Mik7cmV0dXJuIHQubGVuZ3RoPW4sc307dmFyIGZhc3RQYXRoPUZhc3RQYXRoLG5vcm1hbGl6ZSQxPW9wdGlvbnMubm9ybWFsaXplLG11bHRpcGFyc2VyPXtwcmludFN1YnRyZWU6cHJpbnRTdWJ0cmVlfSxkb2MkMj1kb2MsZG9jQnVpbGRlcnMkMj1kb2MkMi5idWlsZGVycyxjb25jYXQkMz1kb2NCdWlsZGVycyQyLmNvbmNhdCxoYXJkbGluZSQyPWRvY0J1aWxkZXJzJDIuaGFyZGxpbmUsYWRkQWxpZ25tZW50VG9Eb2MkMT1kb2NCdWlsZGVycyQyLmFkZEFsaWdubWVudFRvRG9jLGRvY1V0aWxzJDI9ZG9jJDIudXRpbHMsYXN0VG9Eb2M9cHJpbnRBc3RUb0RvYyxyYW5nZVV0aWw9e2NhbGN1bGF0ZVJhbmdlOmNhbGN1bGF0ZVJhbmdlLGZpbmROb2RlQXRPZmZzZXQ6ZmluZE5vZGVBdE9mZnNldH0sbm9ybWFsaXplT3B0aW9ucz1vcHRpb25zLm5vcm1hbGl6ZSxfcHJpbnREb2NUb1N0cmluZz1kb2MucHJpbnRlci5wcmludERvY1RvU3RyaW5nLHByaW50RG9jVG9EZWJ1Zz1kb2MuZGVidWcucHJpbnREb2NUb0RlYnVnLFVURjhCT009NjUyNzksQ1VSU09SPVN5bWJvbCgiY3Vyc29yIiksY29yZT17Zm9ybWF0V2l0aEN1cnNvcjpmdW5jdGlvbihlLHQpe3JldHVybiB0PW5vcm1hbGl6ZU9wdGlvbnModCksZm9ybWF0KGUsbm9ybWFsaXplT3B0aW9ucyh0KSl9LHBhcnNlOmZ1bmN0aW9uKGUsdCxuKXt0PW5vcm1hbGl6ZU9wdGlvbnModCk7dmFyIHI9cGFyc2VyLnBhcnNlKGUsdCk7cmV0dXJuIG4mJihyLmFzdD1tYXNzYWdlQXN0KHIuYXN0LHQpKSxyfSxmb3JtYXRBU1Q6ZnVuY3Rpb24oZSx0KXt0PW5vcm1hbGl6ZU9wdGlvbnModCk7dmFyIG49YXN0VG9Eb2MoZSx0KTtyZXR1cm4gX3ByaW50RG9jVG9TdHJpbmcobix0KX0sZm9ybWF0RG9jOmZ1bmN0aW9uKGUsdCl7dmFyIG49cHJpbnREb2NUb0RlYnVnKGUpO3JldHVybiB0PW5vcm1hbGl6ZU9wdGlvbnMoT2JqZWN0LmFzc2lnbih7fSx0LHtwYXJzZXI6ImJhYnlsb24ifSkpLGZvcm1hdChuLHQpLmZvcm1hdHRlZH0scHJpbnRUb0RvYzpmdW5jdGlvbihlLHQpe3Q9bm9ybWFsaXplT3B0aW9ucyh0KTt2YXIgbj1wYXJzZXIucGFyc2UoZSx0KSxyPW4uYXN0O3JldHVybiBlPW4udGV4dCxhdHRhY2hDb21tZW50cyhlLHIsdCksYXN0VG9Eb2Mocix0KX0scHJpbnREb2NUb1N0cmluZzpmdW5jdGlvbihlLHQpe3JldHVybiBfcHJpbnREb2NUb1N0cmluZyhlLG5vcm1hbGl6ZU9wdGlvbnModCkpfX0sX3JlcXVpcmUkJDAkYnVpbGRlcnMkMT1kb2MuYnVpbGRlcnMsaW5kZW50JDM9X3JlcXVpcmUkJDAkYnVpbGRlcnMkMS5pbmRlbnQsam9pbiQzPV9yZXF1aXJlJCQwJGJ1aWxkZXJzJDEuam9pbixoYXJkbGluZSQ0PV9yZXF1aXJlJCQwJGJ1aWxkZXJzJDEuaGFyZGxpbmUsc29mdGxpbmUkMj1fcmVxdWlyZSQkMCRidWlsZGVycyQxLnNvZnRsaW5lLGxpdGVyYWxsaW5lJDI9X3JlcXVpcmUkJDAkYnVpbGRlcnMkMS5saXRlcmFsbGluZSxjb25jYXQkNT1fcmVxdWlyZSQkMCRidWlsZGVycyQxLmNvbmNhdCxkZWRlbnRUb1Jvb3QkMT1fcmVxdWlyZSQkMCRidWlsZGVycyQxLmRlZGVudFRvUm9vdCxfcmVxdWlyZSQkMCR1dGlscz1kb2MudXRpbHMsbWFwRG9jJDI9X3JlcXVpcmUkJDAkdXRpbHMubWFwRG9jLHN0cmlwVHJhaWxpbmdIYXJkbGluZSQxPV9yZXF1aXJlJCQwJHV0aWxzLnN0cmlwVHJhaWxpbmdIYXJkbGluZSxlbWJlZF8xPWVtYmVkLGNsZWFuXzE9Y2xlYW4sZGV0ZWN0TmV3bGluZT1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlKXtlLmV4cG9ydHM9ZnVuY3Rpb24oZSl7aWYoInN0cmluZyIhPT10eXBlb2YgZSl0aHJvdyBuZXcgVHlwZUVycm9yKCJFeHBlY3RlZCBhIHN0cmluZyIpO3ZhciB0PWUubWF0Y2goLyg/OlxyP1xuKS9nKXx8W107aWYoMD09PXQubGVuZ3RoKXJldHVybiBudWxsO3ZhciBuPXQuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiJcclxuIj09PWV9KS5sZW5ndGg7cmV0dXJuIG4+dC5sZW5ndGgtbj8iXHJcbiI6IlxuIn0sZS5leHBvcnRzLmdyYWNlZnVsPWZ1bmN0aW9uKHQpe3JldHVybiBlLmV4cG9ydHModCl8fCJcbiJ9fSksb3MkOD17fSxvcyQxMD1PYmplY3QuZnJlZXplKHtkZWZhdWx0Om9zJDgsX19tb2R1bGVFeHBvcnRzOm9zJDh9KSxyZXF1aXJlJCQxJDQ9b3MkMTAmJm9zJDh8fG9zJDEwLGJ1aWxkPWNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uKGUsdCl7ZnVuY3Rpb24gbigpe3JldHVybiBwPWkoZGV0ZWN0TmV3bGluZSl9ZnVuY3Rpb24gcigpe3JldHVybiBmPXJlcXVpcmUkJDEkNH1mdW5jdGlvbiBpKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1mdW5jdGlvbiBvKGUpe3ZhciB0PWUubWF0Y2gobSk7cmV0dXJuIHQ/dFswXS5yZXBsYWNlKHksIiIpfHwiIjoiIn1mdW5jdGlvbiBhKGUpe3ZhciB0PWUubWF0Y2gobSk7cmV0dXJuIHQmJnRbMF0/ZS5zdWJzdHJpbmcodFswXS5sZW5ndGgpOmV9ZnVuY3Rpb24gcyhlKXtyZXR1cm4gdShlKS5wcmFnbWFzfWZ1bmN0aW9uIHUoZSl7dmFyIHQ9KDAsKHB8fG4oKSkuZGVmYXVsdCkoZSl8fChmfHxyKCkpLkVPTDtlPWUucmVwbGFjZShoLCIiKS5yZXBsYWNlKGQsIiIpLnJlcGxhY2UoRSwiJDEiKTtmb3IodmFyIGk9IiI7aSE9PWU7KWk9ZSxlPWUucmVwbGFjZSh4LCIiLmNvbmNhdCh0LCIkMSAkMiIpLmNvbmNhdCh0KSk7ZT1lLnJlcGxhY2UoYiwiIikucmVwbGFjZSh2LCIiKTtmb3IodmFyIG8sYT1PYmplY3QuY3JlYXRlKG51bGwpLHM9ZS5yZXBsYWNlKEMsIiIpLnJlcGxhY2UoYiwiIikucmVwbGFjZSh2LCIiKTtvPUMuZXhlYyhlKTspe3ZhciB1PW9bMl0ucmVwbGFjZShnLCIiKTsic3RyaW5nIj09PXR5cGVvZiBhW29bMV1dfHxBcnJheS5pc0FycmF5KGFbb1sxXV0pP2Fbb1sxXV09W10uY29uY2F0KGFbb1sxXV0sdSk6YVtvWzFdXT11fXJldHVybntjb21tZW50czpzLHByYWdtYXM6YX19ZnVuY3Rpb24gYyhlKXt2YXIgdD1lLmNvbW1lbnRzLGk9dm9pZCAwPT09dD8iIjp0LG89ZS5wcmFnbWFzLGE9dm9pZCAwPT09bz97fTpvLHM9KDAsKHB8fG4oKSkuZGVmYXVsdCkoaSl8fChmfHxyKCkpLkVPTCx1PU9iamVjdC5rZXlzKGEpLGM9dS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGwoZSxhW2VdKX0pLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlLmNvbmNhdCh0KX0sW10pLm1hcChmdW5jdGlvbihlKXtyZXR1cm4iICogIitlK3N9KS5qb2luKCIiKTtpZighaSl7aWYoMD09PXUubGVuZ3RoKXJldHVybiIiO2lmKDE9PT11Lmxlbmd0aCYmIUFycmF5LmlzQXJyYXkoYVt1WzBdXSkpe3ZhciBkPWFbdVswXV07cmV0dXJuIiIuY29uY2F0KCIvKioiLCIgIikuY29uY2F0KGwodVswXSxkKVswXSkuY29uY2F0KCIgKi8iKX19dmFyIGg9aS5zcGxpdChzKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIiIuY29uY2F0KCIgKiIsIiAiKS5jb25jYXQoZSl9KS5qb2luKHMpK3M7cmV0dXJuIi8qKiIrcysoaT9oOiIiKSsoaSYmdS5sZW5ndGg/IiAqIitzOiIiKStjKyIgKi8ifWZ1bmN0aW9uIGwoZSx0KXtyZXR1cm5bXS5jb25jYXQodCkubWFwKGZ1bmN0aW9uKHQpe3JldHVybiJAIi5jb25jYXQoZSwiICIpLmNvbmNhdCh0KS50cmltKCl9KX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5leHRyYWN0PW8sdC5zdHJpcD1hLHQucGFyc2U9cyx0LnBhcnNlV2l0aENvbW1lbnRzPXUsdC5wcmludD1jO3ZhciBwLGYsZD0vXCpcLyQvLGg9L15cL1wqXCovLG09L15ccyooXC9cKlwqPygufFxyP1xuKSo/XCpcLykvLGc9LyhefFxzKylcL1wvKFteXHJcbl0qKS9nLHk9L15ccyovLHY9L1xzKiQvLGI9L14oXHI/XG4pKy8seD0vKD86Xnxccj9cbikgKihAW15cclxuXSo/KSAqXHI/XG4gKig/IVteQFxyXG5dKlwvXC9bXl0qKShbXkBcclxuXHNdW15AXHJcbl0rPykgKlxyP1xuL2csQz0vKD86Xnxccj9cbikgKkAoXFMrKSAqKFteXHJcbl0qKS9nLEU9Lyhccj9cbnxeKSAqXCogPy9nfSk7dW53cmFwRXhwb3J0cyhidWlsZCk7dmFyIHByYWdtYT17aGFzUHJhZ21hOmhhc1ByYWdtYSxpbnNlcnRQcmFnbWE6aW5zZXJ0UHJhZ21hJDF9LGFkZExlYWRpbmdDb21tZW50JDI9dXRpbFNoYXJlZC5hZGRMZWFkaW5nQ29tbWVudCxhZGRUcmFpbGluZ0NvbW1lbnQkMj11dGlsU2hhcmVkLmFkZFRyYWlsaW5nQ29tbWVudCxhZGREYW5nbGluZ0NvbW1lbnQkMj11dGlsU2hhcmVkLmFkZERhbmdsaW5nQ29tbWVudCxjb21tZW50cyQzPXtoYW5kbGVPd25MaW5lQ29tbWVudDpoYW5kbGVPd25MaW5lQ29tbWVudCxoYW5kbGVFbmRPZkxpbmVDb21tZW50OmhhbmRsZUVuZE9mTGluZUNvbW1lbnQsaGFuZGxlUmVtYWluaW5nQ29tbWVudDpoYW5kbGVSZW1haW5pbmdDb21tZW50LGlzQmxvY2tDb21tZW50OmlzQmxvY2tDb21tZW50fSxuZWVkc1BhcmVuc18xPW5lZWRzUGFyZW5zLGdldFBhcmVudEV4cG9ydERlY2xhcmF0aW9uJDE9dXRpbC5nZXRQYXJlbnRFeHBvcnREZWNsYXJhdGlvbixpc0V4cG9ydERlY2xhcmF0aW9uJDE9dXRpbC5pc0V4cG9ydERlY2xhcmF0aW9uLHNob3VsZEZsYXR0ZW4kMT11dGlsLnNob3VsZEZsYXR0ZW4sZ2V0TmV4dE5vblNwYWNlTm9uQ29tbWVudENoYXJhY3RlciQxPXV0aWwuZ2V0TmV4dE5vblNwYWNlTm9uQ29tbWVudENoYXJhY3RlcixoYXNOZXdsaW5lJDI9dXRpbC5oYXNOZXdsaW5lLGhhc05ld2xpbmVJblJhbmdlJDE9dXRpbC5oYXNOZXdsaW5lSW5SYW5nZSxnZXRMYXN0JDQ9dXRpbC5nZXRMYXN0LGdldFN0cmluZ1dpZHRoJDE9dXRpbC5nZXRTdHJpbmdXaWR0aCxwcmludFN0cmluZyQxPXV0aWwucHJpbnRTdHJpbmcscHJpbnROdW1iZXIkMT11dGlsLnByaW50TnVtYmVyLGhhc0lnbm9yZUNvbW1lbnQkMT11dGlsLmhhc0lnbm9yZUNvbW1lbnQsc2tpcFdoaXRlc3BhY2UkMT11dGlsLnNraXBXaGl0ZXNwYWNlLGhhc05vZGVJZ25vcmVDb21tZW50JDE9dXRpbC5oYXNOb2RlSWdub3JlQ29tbWVudCxnZXRQZW51bHRpbWF0ZSQxPXV0aWwuZ2V0UGVudWx0aW1hdGUsc3RhcnRzV2l0aE5vTG9va2FoZWFkVG9rZW4kMT11dGlsLnN0YXJ0c1dpdGhOb0xvb2thaGVhZFRva2VuLGdldEluZGVudFNpemUkMT11dGlsLmdldEluZGVudFNpemUsaXNOZXh0TGluZUVtcHR5JDI9dXRpbFNoYXJlZC5pc05leHRMaW5lRW1wdHksaXNOZXh0TGluZUVtcHR5QWZ0ZXJJbmRleCQxPXV0aWxTaGFyZWQuaXNOZXh0TGluZUVtcHR5QWZ0ZXJJbmRleCxnZXROZXh0Tm9uU3BhY2VOb25Db21tZW50Q2hhcmFjdGVySW5kZXgkMj11dGlsU2hhcmVkLmdldE5leHROb25TcGFjZU5vbkNvbW1lbnRDaGFyYWN0ZXJJbmRleCxpc0lkZW50aWZpZXJOYW1lPXV0aWxzLmtleXdvcmQuaXNJZGVudGlmaWVyTmFtZUVTNixpbnNlcnRQcmFnbWE9cHJhZ21hLmluc2VydFByYWdtYSxfcmVxdWlyZSQkNCRidWlsZGVycz1kb2MuYnVpbGRlcnMsY29uY2F0JDQ9X3JlcXVpcmUkJDQkYnVpbGRlcnMuY29uY2F0LGpvaW4kMj1fcmVxdWlyZSQkNCRidWlsZGVycy5qb2luLGxpbmUkMz1fcmVxdWlyZSQkNCRidWlsZGVycy5saW5lLGhhcmRsaW5lJDM9X3JlcXVpcmUkJDQkYnVpbGRlcnMuaGFyZGxpbmUsc29mdGxpbmUkMT1fcmVxdWlyZSQkNCRidWlsZGVycy5zb2Z0bGluZSxsaXRlcmFsbGluZSQxPV9yZXF1aXJlJCQ0JGJ1aWxkZXJzLmxpdGVyYWxsaW5lLGdyb3VwJDE9X3JlcXVpcmUkJDQkYnVpbGRlcnMuZ3JvdXAsaW5kZW50JDI9X3JlcXVpcmUkJDQkYnVpbGRlcnMuaW5kZW50LGFsaWduJDE9X3JlcXVpcmUkJDQkYnVpbGRlcnMuYWxpZ24sY29uZGl0aW9uYWxHcm91cCQxPV9yZXF1aXJlJCQ0JGJ1aWxkZXJzLmNvbmRpdGlvbmFsR3JvdXAsZmlsbCQyPV9yZXF1aXJlJCQ0JGJ1aWxkZXJzLmZpbGwsaWZCcmVhayQxPV9yZXF1aXJlJCQ0JGJ1aWxkZXJzLmlmQnJlYWssYnJlYWtQYXJlbnQkMj1fcmVxdWlyZSQkNCRidWlsZGVycy5icmVha1BhcmVudCxsaW5lU3VmZml4Qm91bmRhcnkkMT1fcmVxdWlyZSQkNCRidWlsZGVycy5saW5lU3VmZml4Qm91bmRhcnksYWRkQWxpZ25tZW50VG9Eb2MkMj1fcmVxdWlyZSQkNCRidWlsZGVycy5hZGRBbGlnbm1lbnRUb0RvYyxkZWRlbnQkMj1fcmVxdWlyZSQkNCRidWlsZGVycy5kZWRlbnQsX3JlcXVpcmUkJDQkdXRpbHM9ZG9jLnV0aWxzLHdpbGxCcmVhayQxPV9yZXF1aXJlJCQ0JHV0aWxzLndpbGxCcmVhayxpc0xpbmVOZXh0JDE9X3JlcXVpcmUkJDQkdXRpbHMuaXNMaW5lTmV4dCxpc0VtcHR5JDE9X3JlcXVpcmUkJDQkdXRpbHMuaXNFbXB0eSxyZW1vdmVMaW5lcyQxPV9yZXF1aXJlJCQ0JHV0aWxzLnJlbW92ZUxpbmVzLHByaW50RG9jVG9TdHJpbmckMT1kb2MucHJpbnRlci5wcmludERvY1RvU3RyaW5nLGZ1bmN0aW9uQ29tcG9zaXRpb25GdW5jdGlvbk5hbWVzPXtwaXBlOiEwLHBpcGVQOiEwLHBpcGVLOiEwLGNvbXBvc2U6ITAsY29tcG9zZUZsaXBwZWQ6ITAsY29tcG9zZVA6ITAsY29tcG9zZUs6ITAsZmxvdzohMCxmbG93UmlnaHQ6ITAsY29ubmVjdDohMH0sanN4V2hpdGVzcGFjZUNoYXJzPSIgXG5cclx0Iixjb250YWluc05vbkpzeFdoaXRlc3BhY2VSZWdleD1uZXcgUmVnRXhwKCJbXiIranN4V2hpdGVzcGFjZUNoYXJzKyJdIiksbWF0Y2hKc3hXaGl0ZXNwYWNlUmVnZXg9bmV3IFJlZ0V4cCgiKFsiK2pzeFdoaXRlc3BhY2VDaGFycysiXSspIiksdW5pdFRlc3RSZT0vXihza2lwfFtmeF0/KGl0fGRlc2NyaWJlfHRlc3QpKSQvLHByaW50ZXJFc3RyZWU9e3ByaW50OmdlbmVyaWNQcmludCQxLGVtYmVkOmVtYmVkXzEsaW5zZXJ0UHJhZ21hOmluc2VydFByYWdtYSxtYXNzYWdlQXN0Tm9kZTpjbGVhbl8xLGhhc1ByZXR0aWVySWdub3JlOmhhc1ByZXR0aWVySWdub3JlLHdpbGxQcmludE93bkNvbW1lbnRzOndpbGxQcmludE93bkNvbW1lbnRzLGNhbkF0dGFjaENvbW1lbnQ6Y2FuQXR0YWNoQ29tbWVudCxwcmludENvbW1lbnQ6cHJpbnRDb21tZW50JDEsaXNCbG9ja0NvbW1lbnQ6Y29tbWVudHMkMy5pc0Jsb2NrQ29tbWVudCxoYW5kbGVDb21tZW50czp7b3duTGluZTpjb21tZW50cyQzLmhhbmRsZU93bkxpbmVDb21tZW50LGVuZE9mTGluZTpjb21tZW50cyQzLmhhbmRsZUVuZE9mTGluZUNvbW1lbnQscmVtYWluaW5nOmNvbW1lbnRzJDMuaGFuZGxlUmVtYWluaW5nQ29tbWVudH19LF9yZXF1aXJlJCQwJGJ1aWxkZXJzJDI9ZG9jLmJ1aWxkZXJzLGNvbmNhdCQ2PV9yZXF1aXJlJCQwJGJ1aWxkZXJzJDIuY29uY2F0LGhhcmRsaW5lJDU9X3JlcXVpcmUkJDAkYnVpbGRlcnMkMi5oYXJkbGluZSxpbmRlbnQkND1fcmVxdWlyZSQkMCRidWlsZGVycyQyLmluZGVudCxqb2luJDQ9X3JlcXVpcmUkJDAkYnVpbGRlcnMkMi5qb2luLHByaW50ZXJFc3RyZWVKc29uPXtwcmludDpnZW5lcmljUHJpbnQkMixtYXNzYWdlQXN0Tm9kZTpjbGVhbiQyfSxDQVRFR09SWV9DT01NT049IkNvbW1vbiIsY29tbW9uT3B0aW9ucz17YnJhY2tldFNwYWNpbmc6e3NpbmNlOiIwLjAuMCIsY2F0ZWdvcnk6Q0FURUdPUllfQ09NTU9OLHR5cGU6ImJvb2xlYW4iLGRlZmF1bHQ6ITAsZGVzY3JpcHRpb246IlByaW50IHNwYWNlcyBiZXR3ZWVuIGJyYWNrZXRzLiIsb3Bwb3NpdGVEZXNjcmlwdGlvbjoiRG8gbm90IHByaW50IHNwYWNlcyBiZXR3ZWVuIGJyYWNrZXRzLiJ9LHNpbmdsZVF1b3RlOntzaW5jZToiMC4wLjAiLGNhdGVnb3J5OkNBVEVHT1JZX0NPTU1PTix0eXBlOiJib29sZWFuIixkZWZhdWx0OiExLGRlc2NyaXB0aW9uOiJVc2Ugc2luZ2xlIHF1b3RlcyBpbnN0ZWFkIG9mIGRvdWJsZSBxdW90ZXMuIn19LENBVEVHT1JZX0pBVkFTQ1JJUFQ9IkphdmFTY3JpcHQiLG9wdGlvbnMkMz17YXJyb3dQYXJlbnM6e3NpbmNlOiIxLjkuMCIsY2F0ZWdvcnk6Q0FURUdPUllfSkFWQVNDUklQVCx0eXBlOiJjaG9pY2UiLGRlZmF1bHQ6ImF2b2lkIixkZXNjcmlwdGlvbjoiSW5jbHVkZSBwYXJlbnRoZXNlcyBhcm91bmQgYSBzb2xlIGFycm93IGZ1bmN0aW9uIHBhcmFtZXRlci4iLGNob2ljZXM6W3t2YWx1ZToiYXZvaWQiLGRlc2NyaXB0aW9uOiJPbWl0IHBhcmVucyB3aGVuIHBvc3NpYmxlLiBFeGFtcGxlOiBgeCA9PiB4YCJ9LHt2YWx1ZToiYWx3YXlzIixkZXNjcmlwdGlvbjoiQWx3YXlzIGluY2x1ZGUgcGFyZW5zLiBFeGFtcGxlOiBgKHgpID0+IHhgIn1dfSxicmFja2V0U3BhY2luZzpjb21tb25PcHRpb25zLmJyYWNrZXRTcGFjaW5nLGpzeEJyYWNrZXRTYW1lTGluZTp7c2luY2U6IjAuMTcuMCIsY2F0ZWdvcnk6Q0FURUdPUllfSkFWQVNDUklQVCx0eXBlOiJib29sZWFuIixkZWZhdWx0OiExLGRlc2NyaXB0aW9uOiJQdXQgPiBvbiB0aGUgbGFzdCBsaW5lIGluc3RlYWQgb2YgYXQgYSBuZXcgbGluZS4ifSxzZW1pOntzaW5jZToiMS4wLjAiLGNhdGVnb3J5OkNBVEVHT1JZX0pBVkFTQ1JJUFQsdHlwZToiYm9vbGVhbiIsZGVmYXVsdDohMCxkZXNjcmlwdGlvbjoiUHJpbnQgc2VtaWNvbG9ucy4iLG9wcG9zaXRlRGVzY3JpcHRpb246IkRvIG5vdCBwcmludCBzZW1pY29sb25zLCBleGNlcHQgYXQgdGhlIGJlZ2lubmluZyBvZiBsaW5lcyB3aGljaCBtYXkgbmVlZCB0aGVtLiJ9LHNpbmdsZVF1b3RlOmNvbW1vbk9wdGlvbnMuc2luZ2xlUXVvdGUsdHJhaWxpbmdDb21tYTp7c2luY2U6IjAuMC4wIixjYXRlZ29yeTpDQVRFR09SWV9KQVZBU0NSSVBULHR5cGU6ImNob2ljZSIsZGVmYXVsdDpbe3NpbmNlOiIwLjAuMCIsdmFsdWU6ITF9LHtzaW5jZToiMC4xOS4wIix2YWx1ZToibm9uZSJ9XSxkZXNjcmlwdGlvbjoiUHJpbnQgdHJhaWxpbmcgY29tbWFzIHdoZXJldmVyIHBvc3NpYmxlIHdoZW4gbXVsdGktbGluZS4iLGNob2ljZXM6W3t2YWx1ZToibm9uZSIsZGVzY3JpcHRpb246Ik5vIHRyYWlsaW5nIGNvbW1hcy4ifSx7dmFsdWU6ImVzNSIsZGVzY3JpcHRpb246IlRyYWlsaW5nIGNvbW1hcyB3aGVyZSB2YWxpZCBpbiBFUzUgKG9iamVjdHMsIGFycmF5cywgZXRjLikifSx7dmFsdWU6ImFsbCIsZGVzY3JpcHRpb246IlRyYWlsaW5nIGNvbW1hcyB3aGVyZXZlciBwb3NzaWJsZSAoaW5jbHVkaW5nIGZ1bmN0aW9uIGFyZ3VtZW50cykuIn0se3ZhbHVlOiEwLGRlcHJlY2F0ZWQ6IjAuMTkuMCIscmVkaXJlY3Q6ImVzNSJ9LHt2YWx1ZTohMSxkZXByZWNhdGVkOiIwLjE5LjAiLHJlZGlyZWN0OiJub25lIn1dfX0sbGFuZ3VhZ2VzPVt7bmFtZToiSmF2YVNjcmlwdCIsc2luY2U6IjAuMC4wIixwYXJzZXJzOlsiYmFieWxvbiIsImZsb3ciXSxncm91cDoiSmF2YVNjcmlwdCIsdG1TY29wZToic291cmNlLmpzIixhY2VNb2RlOiJqYXZhc2NyaXB0Iixjb2RlbWlycm9yTW9kZToiamF2YXNjcmlwdCIsY29kZW1pcnJvck1pbWVUeXBlOiJ0ZXh0L2phdmFzY3JpcHQiLGFsaWFzZXM6WyJqcyIsIm5vZGUiXSxleHRlbnNpb25zOlsiLmpzIiwiLl9qcyIsIi5ib25lcyIsIi5lcyIsIi5lczYiLCIuZnJhZyIsIi5ncyIsIi5qYWtlIiwiLmpzYiIsIi5qc2NhZCIsIi5qc2ZsIiwiLmpzbSIsIi5qc3MiLCIubWpzIiwiLm5qcyIsIi5wYWMiLCIuc2pzIiwiLnNzanMiLCIueHNqcyIsIi54c2pzbGliIl0sZmlsZW5hbWVzOlsiSmFrZWZpbGUiXSxsaW5ndWlzdExhbmd1YWdlSWQ6MTgzLHZzY29kZUxhbmd1YWdlSWRzOlsiamF2YXNjcmlwdCJdfSx7bmFtZToiSlNYIixzaW5jZToiMC4wLjAiLHBhcnNlcnM6WyJiYWJ5bG9uIiwiZmxvdyJdLGdyb3VwOiJKYXZhU2NyaXB0IixleHRlbnNpb25zOlsiLmpzeCJdLHRtU2NvcGU6InNvdXJjZS5qcy5qc3giLGFjZU1vZGU6ImphdmFzY3JpcHQiLGNvZGVtaXJyb3JNb2RlOiJqc3giLGNvZGVtaXJyb3JNaW1lVHlwZToidGV4dC9qc3giLGxpZ3Vpc3RMYW5ndWFnZUlkOjE3OCx2c2NvZGVMYW5ndWFnZUlkczpbImphdmFzY3JpcHRyZWFjdCJdfSx7bmFtZToiVHlwZVNjcmlwdCIsc2luY2U6IjEuNC4wIixwYXJzZXJzOlsidHlwZXNjcmlwdC1lc2xpbnQiXSxncm91cDoiSmF2YVNjcmlwdCIsYWxpYXNlczpbInRzIl0sZXh0ZW5zaW9uczpbIi50cyIsIi50c3giXSx0bVNjb3BlOiJzb3VyY2UudHMiLGFjZU1vZGU6InR5cGVzY3JpcHQiLGNvZGVtaXJyb3JNb2RlOiJqYXZhc2NyaXB0Iixjb2RlbWlycm9yTWltZVR5cGU6ImFwcGxpY2F0aW9uL3R5cGVzY3JpcHQiLGxpZ3Vpc3RMYW5ndWFnZUlkOjM3OCx2c2NvZGVMYW5ndWFnZUlkczpbInR5cGVzY3JpcHQiLCJ0eXBlc2NyaXB0cmVhY3QiXX0se25hbWU6IkpTT04uc3RyaW5naWZ5IixzaW5jZToiMS4xMy4wIixwYXJzZXJzOlsianNvbi1zdHJpbmdpZnkiXSxncm91cDoiSmF2YVNjcmlwdCIsdG1TY29wZToic291cmNlLmpzb24iLGFjZU1vZGU6Impzb24iLGNvZGVtaXJyb3JNb2RlOiJqYXZhc2NyaXB0Iixjb2RlbWlycm9yTWltZVR5cGU6ImFwcGxpY2F0aW9uL2pzb24iLGV4dGVuc2lvbnM6W10sZmlsZW5hbWVzOlsicGFja2FnZS5qc29uIiwicGFja2FnZS1sb2NrLmpzb24iLCJjb21wb3Nlci5qc29uIl0sbGluZ3Vpc3RMYW5ndWFnZUlkOjE3NCx2c2NvZGVMYW5ndWFnZUlkczpbImpzb24iXX0se25hbWU6IkpTT04iLHNpbmNlOiIxLjUuMCIscGFyc2VyczpbImpzb24iXSxncm91cDoiSmF2YVNjcmlwdCIsdG1TY29wZToic291cmNlLmpzb24iLGFjZU1vZGU6Impzb24iLGNvZGVtaXJyb3JNb2RlOiJqYXZhc2NyaXB0Iixjb2RlbWlycm9yTWltZVR5cGU6ImFwcGxpY2F0aW9uL2pzb24iLGV4dGVuc2lvbnM6WyIuanNvbiIsIi5nZW9qc29uIiwiLkpTT04tdG1MYW5ndWFnZSIsIi50b3BvanNvbiJdLGZpbGVuYW1lczpbIi5hcmNjb25maWciLCIuanNoaW50cmMiLCIuZXNsaW50cmMiLCIucHJldHRpZXJyYyIsImNvbXBvc2VyLmxvY2siLCJtY21vZC5pbmZvIl0sbGluZ3Vpc3RMYW5ndWFnZUlkOjE3NCx2c2NvZGVMYW5ndWFnZUlkczpbImpzb24iLCJqc29uYyJdfSx7bmFtZToiSlNPTjUiLHNpbmNlOiIxLjEzLjAiLHBhcnNlcnM6WyJqc29uNSJdLGdyb3VwOiJKYXZhU2NyaXB0Iix0bVNjb3BlOiJzb3VyY2UuanNvbiIsYWNlTW9kZToianNvbiIsY29kZW1pcnJvck1vZGU6ImphdmFzY3JpcHQiLGNvZGVtaXJyb3JNaW1lVHlwZToiYXBwbGljYXRpb24vanNvbiIsZXh0ZW5zaW9uczpbIi5qc29uNSJdLGZpbGVuYW1lczpbIi5iYWJlbHJjIl0sbGluZ3Vpc3RMYW5ndWFnZUlkOjE3NSx2c2NvZGVMYW5ndWFnZUlkczpbImpzb241Il19XSxwcmludGVycz17ZXN0cmVlOnByaW50ZXJFc3RyZWUsImVzdHJlZS1qc29uIjpwcmludGVyRXN0cmVlSnNvbn0sbGFuZ3VhZ2VKcz17bGFuZ3VhZ2VzOmxhbmd1YWdlcyxvcHRpb25zOm9wdGlvbnMkMyxwcmludGVyczpwcmludGVyc30saW5kZXgkNT1bImEiLCJhYmJyIiwiYWNyb255bSIsImFkZHJlc3MiLCJhcHBsZXQiLCJhcmVhIiwiYXJ0aWNsZSIsImFzaWRlIiwiYXVkaW8iLCJiIiwiYmFzZSIsImJhc2Vmb250IiwiYmRpIiwiYmRvIiwiYmdzb3VuZCIsImJpZyIsImJsaW5rIiwiYmxvY2txdW90ZSIsImJvZHkiLCJiciIsImJ1dHRvbiIsImNhbnZhcyIsImNhcHRpb24iLCJjZW50ZXIiLCJjaXRlIiwiY29kZSIsImNvbCIsImNvbGdyb3VwIiwiY29tbWFuZCIsImNvbnRlbnQiLCJkYXRhIiwiZGF0YWxpc3QiLCJkZCIsImRlbCIsImRldGFpbHMiLCJkZm4iLCJkaWFsb2ciLCJkaXIiLCJkaXYiLCJkbCIsImR0IiwiZWxlbWVudCIsImVtIiwiZW1iZWQiLCJmaWVsZHNldCIsImZpZ2NhcHRpb24iLCJmaWd1cmUiLCJmb250IiwiZm9vdGVyIiwiZm9ybSIsImZyYW1lIiwiZnJhbWVzZXQiLCJoMSIsImgyIiwiaDMiLCJoNCIsImg1IiwiaDYiLCJoZWFkIiwiaGVhZGVyIiwiaGdyb3VwIiwiaHIiLCJodG1sIiwiaSIsImlmcmFtZSIsImltYWdlIiwiaW1nIiwiaW5wdXQiLCJpbnMiLCJpc2luZGV4Iiwia2JkIiwia2V5Z2VuIiwibGFiZWwiLCJsZWdlbmQiLCJsaSIsImxpbmsiLCJsaXN0aW5nIiwibWFpbiIsIm1hcCIsIm1hcmsiLCJtYXJxdWVlIiwibWF0aCIsIm1lbnUiLCJtZW51aXRlbSIsIm1ldGEiLCJtZXRlciIsIm11bHRpY29sIiwibmF2IiwibmV4dGlkIiwibm9iciIsIm5vZW1iZWQiLCJub2ZyYW1lcyIsIm5vc2NyaXB0Iiwib2JqZWN0Iiwib2wiLCJvcHRncm91cCIsIm9wdGlvbiIsIm91dHB1dCIsInAiLCJwYXJhbSIsInBpY3R1cmUiLCJwbGFpbnRleHQiLCJwcmUiLCJwcm9ncmVzcyIsInEiLCJyYiIsInJiYyIsInJwIiwicnQiLCJydGMiLCJydWJ5IiwicyIsInNhbXAiLCJzY3JpcHQiLCJzZWN0aW9uIiwic2VsZWN0Iiwic2hhZG93Iiwic2xvdCIsInNtYWxsIiwic291cmNlIiwic3BhY2VyIiwic3BhbiIsInN0cmlrZSIsInN0cm9uZyIsInN0eWxlIiwic3ViIiwic3VtbWFyeSIsInN1cCIsInN2ZyIsInRhYmxlIiwidGJvZHkiLCJ0ZCIsInRlbXBsYXRlIiwidGV4dGFyZWEiLCJ0Zm9vdCIsInRoIiwidGhlYWQiLCJ0aW1lIiwidGl0bGUiLCJ0ciIsInRyYWNrIiwidHQiLCJ1IiwidWwiLCJ2YXIiLCJ2aWRlbyIsIndiciIsInhtcCJdLGh0bWxUYWdOYW1lcz1PYmplY3QuZnJlZXplKHtkZWZhdWx0OmluZGV4JDV9KSxodG1sVGFnTmFtZXMkMT1odG1sVGFnTmFtZXMmJmluZGV4JDV8fGh0bWxUYWdOYW1lcyxjbGVhbl8xJDI9Y2xlYW4kMyx1dGlscyQ0PXtnZXRBbmNlc3RvckNvdW50ZXI6Z2V0QW5jZXN0b3JDb3VudGVyLGdldEFuY2VzdG9yTm9kZTpnZXRBbmNlc3Rvck5vZGUkMSxnZXRQcm9wT2ZEZWNsTm9kZTpnZXRQcm9wT2ZEZWNsTm9kZSQxLG1heWJlVG9Mb3dlckNhc2U6bWF5YmVUb0xvd2VyQ2FzZSQxLGluc2lkZVZhbHVlRnVuY3Rpb25Ob2RlOmluc2lkZVZhbHVlRnVuY3Rpb25Ob2RlJDEsaW5zaWRlSUNTU1J1bGVOb2RlOmluc2lkZUlDU1NSdWxlTm9kZSQxLGluc2lkZUF0UnVsZU5vZGU6aW5zaWRlQXRSdWxlTm9kZSQxLGluc2lkZVVSTEZ1bmN0aW9uSW5JbXBvcnRBdFJ1bGVOb2RlOmluc2lkZVVSTEZ1bmN0aW9uSW5JbXBvcnRBdFJ1bGVOb2RlJDEsaXNLZXlmcmFtZUF0UnVsZUtleXdvcmRzOmlzS2V5ZnJhbWVBdFJ1bGVLZXl3b3JkcyQxLGlzSFRNTFRhZzppc0hUTUxUYWckMSxpc1dpZGVLZXl3b3Jkczppc1dpZGVLZXl3b3JkcyQxLGlzU0NTUzppc1NDU1MkMSxpc0xhc3ROb2RlOmlzTGFzdE5vZGUkMSxpc1NDU1NDb250cm9sRGlyZWN0aXZlTm9kZTppc1NDU1NDb250cm9sRGlyZWN0aXZlTm9kZSQxLGlzRGV0YWNoZWRSdWxlc2V0RGVjbGFyYXRpb25Ob2RlOmlzRGV0YWNoZWRSdWxlc2V0RGVjbGFyYXRpb25Ob2RlJDEsaXNSZWxhdGlvbmFsT3BlcmF0b3JOb2RlOmlzUmVsYXRpb25hbE9wZXJhdG9yTm9kZSQxLGlzRXF1YWxpdHlPcGVyYXRvck5vZGU6aXNFcXVhbGl0eU9wZXJhdG9yTm9kZSQxLGlzTXVsdGlwbGljYXRpb25Ob2RlOmlzTXVsdGlwbGljYXRpb25Ob2RlJDEsaXNEaXZpc2lvbk5vZGU6aXNEaXZpc2lvbk5vZGUkMSxpc0FkZGl0aW9uTm9kZTppc0FkZGl0aW9uTm9kZSQxLGlzU3VidHJhY3Rpb25Ob2RlOmlzU3VidHJhY3Rpb25Ob2RlJDEsaXNNb2R1bG9Ob2RlOmlzTW9kdWxvTm9kZSxpc01hdGhPcGVyYXRvck5vZGU6aXNNYXRoT3BlcmF0b3JOb2RlJDEsaXNFYWNoS2V5d29yZE5vZGU6aXNFYWNoS2V5d29yZE5vZGUkMSxpc0ZvcktleXdvcmROb2RlOmlzRm9yS2V5d29yZE5vZGUkMSxpc1VSTEZ1bmN0aW9uTm9kZTppc1VSTEZ1bmN0aW9uTm9kZSQxLGlzSWZFbHNlS2V5d29yZE5vZGU6aXNJZkVsc2VLZXl3b3JkTm9kZSQxLGhhc0NvbXBvc2VzTm9kZTpoYXNDb21wb3Nlc05vZGUkMSxoYXNQYXJlbnNBcm91bmROb2RlOmhhc1BhcmVuc0Fyb3VuZE5vZGUkMSxoYXNFbXB0eVJhd0JlZm9yZTpoYXNFbXB0eVJhd0JlZm9yZSQxLGlzU0NTU05lc3RlZFByb3BlcnR5Tm9kZTppc1NDU1NOZXN0ZWRQcm9wZXJ0eU5vZGUsaXNEZXRhY2hlZFJ1bGVzZXRDYWxsTm9kZTppc0RldGFjaGVkUnVsZXNldENhbGxOb2RlJDEsaXNQb3N0Y3NzU2ltcGxlVmFyTm9kZTppc1Bvc3Rjc3NTaW1wbGVWYXJOb2RlJDEsaXNLZXlWYWx1ZVBhaXJOb2RlOmlzS2V5VmFsdWVQYWlyTm9kZSQxLGlzS2V5VmFsdWVQYWlySW5QYXJlbkdyb3VwTm9kZTppc0tleVZhbHVlUGFpckluUGFyZW5Hcm91cE5vZGUsaXNTQ1NTTWFwSXRlbU5vZGU6aXNTQ1NTTWFwSXRlbU5vZGUkMSxpc0lubGluZVZhbHVlQ29tbWVudE5vZGU6aXNJbmxpbmVWYWx1ZUNvbW1lbnROb2RlJDEsaXNIYXNoTm9kZTppc0hhc2hOb2RlJDEsaXNMZWZ0Q3VybHlCcmFjZU5vZGU6aXNMZWZ0Q3VybHlCcmFjZU5vZGUkMSxpc1JpZ2h0Q3VybHlCcmFjZU5vZGU6aXNSaWdodEN1cmx5QnJhY2VOb2RlJDEsaXNXb3JkTm9kZTppc1dvcmROb2RlJDEsaXNDb2xvbk5vZGU6aXNDb2xvbk5vZGUkMSxpc01lZGlhQW5kU3VwcG9ydHNLZXl3b3Jkczppc01lZGlhQW5kU3VwcG9ydHNLZXl3b3JkcyQxfSxwcmludE51bWJlciQyPXV0aWwucHJpbnROdW1iZXIscHJpbnRTdHJpbmckMj11dGlsLnByaW50U3RyaW5nLGhhc0lnbm9yZUNvbW1lbnQkMj11dGlsLmhhc0lnbm9yZUNvbW1lbnQsaGFzTmV3bGluZSQzPXV0aWwuaGFzTmV3bGluZSxpc05leHRMaW5lRW1wdHkkMz11dGlsU2hhcmVkLmlzTmV4dExpbmVFbXB0eSxfcmVxdWlyZSQkMiRidWlsZGVycz1kb2MuYnVpbGRlcnMsY29uY2F0JDc9X3JlcXVpcmUkJDIkYnVpbGRlcnMuY29uY2F0LGpvaW4kNT1fcmVxdWlyZSQkMiRidWlsZGVycy5qb2luLGxpbmUkND1fcmVxdWlyZSQkMiRidWlsZGVycy5saW5lLGhhcmRsaW5lJDY9X3JlcXVpcmUkJDIkYnVpbGRlcnMuaGFyZGxpbmUsc29mdGxpbmUkMz1fcmVxdWlyZSQkMiRidWlsZGVycy5zb2Z0bGluZSxncm91cCQyPV9yZXF1aXJlJCQyJGJ1aWxkZXJzLmdyb3VwLGZpbGwkMz1fcmVxdWlyZSQkMiRidWlsZGVycy5maWxsLGluZGVudCQ1PV9yZXF1aXJlJCQyJGJ1aWxkZXJzLmluZGVudCxkZWRlbnQkMz1fcmVxdWlyZSQkMiRidWlsZGVycy5kZWRlbnQsaWZCcmVhayQyPV9yZXF1aXJlJCQyJGJ1aWxkZXJzLmlmQnJlYWsscmVtb3ZlTGluZXMkMj1kb2MudXRpbHMucmVtb3ZlTGluZXMsZ2V0QW5jZXN0b3JOb2RlPXV0aWxzJDQuZ2V0QW5jZXN0b3JOb2RlLGdldFByb3BPZkRlY2xOb2RlPXV0aWxzJDQuZ2V0UHJvcE9mRGVjbE5vZGUsbWF5YmVUb0xvd2VyQ2FzZT11dGlscyQ0Lm1heWJlVG9Mb3dlckNhc2UsaW5zaWRlVmFsdWVGdW5jdGlvbk5vZGU9dXRpbHMkNC5pbnNpZGVWYWx1ZUZ1bmN0aW9uTm9kZSxpbnNpZGVJQ1NTUnVsZU5vZGU9dXRpbHMkNC5pbnNpZGVJQ1NTUnVsZU5vZGUsaW5zaWRlQXRSdWxlTm9kZT11dGlscyQ0Lmluc2lkZUF0UnVsZU5vZGUsaW5zaWRlVVJMRnVuY3Rpb25JbkltcG9ydEF0UnVsZU5vZGU9dXRpbHMkNC5pbnNpZGVVUkxGdW5jdGlvbkluSW1wb3J0QXRSdWxlTm9kZSxpc0tleWZyYW1lQXRSdWxlS2V5d29yZHM9dXRpbHMkNC5pc0tleWZyYW1lQXRSdWxlS2V5d29yZHMsaXNIVE1MVGFnPXV0aWxzJDQuaXNIVE1MVGFnLGlzV2lkZUtleXdvcmRzPXV0aWxzJDQuaXNXaWRlS2V5d29yZHMsaXNTQ1NTPXV0aWxzJDQuaXNTQ1NTLGlzTGFzdE5vZGU9dXRpbHMkNC5pc0xhc3ROb2RlLGlzU0NTU0NvbnRyb2xEaXJlY3RpdmVOb2RlPXV0aWxzJDQuaXNTQ1NTQ29udHJvbERpcmVjdGl2ZU5vZGUsaXNEZXRhY2hlZFJ1bGVzZXREZWNsYXJhdGlvbk5vZGU9dXRpbHMkNC5pc0RldGFjaGVkUnVsZXNldERlY2xhcmF0aW9uTm9kZSxpc1JlbGF0aW9uYWxPcGVyYXRvck5vZGU9dXRpbHMkNC5pc1JlbGF0aW9uYWxPcGVyYXRvck5vZGUsaXNFcXVhbGl0eU9wZXJhdG9yTm9kZT11dGlscyQ0LmlzRXF1YWxpdHlPcGVyYXRvck5vZGUsaXNNdWx0aXBsaWNhdGlvbk5vZGU9dXRpbHMkNC5pc011bHRpcGxpY2F0aW9uTm9kZSxpc0RpdmlzaW9uTm9kZT11dGlscyQ0LmlzRGl2aXNpb25Ob2RlLGlzQWRkaXRpb25Ob2RlPXV0aWxzJDQuaXNBZGRpdGlvbk5vZGUsaXNTdWJ0cmFjdGlvbk5vZGU9dXRpbHMkNC5pc1N1YnRyYWN0aW9uTm9kZSxpc01hdGhPcGVyYXRvck5vZGU9dXRpbHMkNC5pc01hdGhPcGVyYXRvck5vZGUsaXNFYWNoS2V5d29yZE5vZGU9dXRpbHMkNC5pc0VhY2hLZXl3b3JkTm9kZSxpc0ZvcktleXdvcmROb2RlPXV0aWxzJDQuaXNGb3JLZXl3b3JkTm9kZSxpc1VSTEZ1bmN0aW9uTm9kZT11dGlscyQ0LmlzVVJMRnVuY3Rpb25Ob2RlLGlzSWZFbHNlS2V5d29yZE5vZGU9dXRpbHMkNC5pc0lmRWxzZUtleXdvcmROb2RlLGhhc0NvbXBvc2VzTm9kZT11dGlscyQ0Lmhhc0NvbXBvc2VzTm9kZSxoYXNQYXJlbnNBcm91bmROb2RlPXV0aWxzJDQuaGFzUGFyZW5zQXJvdW5kTm9kZSxoYXNFbXB0eVJhd0JlZm9yZT11dGlscyQ0Lmhhc0VtcHR5UmF3QmVmb3JlLGlzS2V5VmFsdWVQYWlyTm9kZT11dGlscyQ0LmlzS2V5VmFsdWVQYWlyTm9kZSxpc0RldGFjaGVkUnVsZXNldENhbGxOb2RlPXV0aWxzJDQuaXNEZXRhY2hlZFJ1bGVzZXRDYWxsTm9kZSxpc1Bvc3Rjc3NTaW1wbGVWYXJOb2RlPXV0aWxzJDQuaXNQb3N0Y3NzU2ltcGxlVmFyTm9kZSxpc1NDU1NNYXBJdGVtTm9kZT11dGlscyQ0LmlzU0NTU01hcEl0ZW1Ob2RlLGlzSW5saW5lVmFsdWVDb21tZW50Tm9kZT11dGlscyQ0LmlzSW5saW5lVmFsdWVDb21tZW50Tm9kZSxpc0hhc2hOb2RlPXV0aWxzJDQuaXNIYXNoTm9kZSxpc0xlZnRDdXJseUJyYWNlTm9kZT11dGlscyQ0LmlzTGVmdEN1cmx5QnJhY2VOb2RlLGlzUmlnaHRDdXJseUJyYWNlTm9kZT11dGlscyQ0LmlzUmlnaHRDdXJseUJyYWNlTm9kZSxpc1dvcmROb2RlPXV0aWxzJDQuaXNXb3JkTm9kZSxpc0NvbG9uTm9kZT11dGlscyQ0LmlzQ29sb25Ob2RlLGlzTWVkaWFBbmRTdXBwb3J0c0tleXdvcmRzPXV0aWxzJDQuaXNNZWRpYUFuZFN1cHBvcnRzS2V5d29yZHMsU1RSSU5HX1JFR0VYPS8oWyciXSkoPzooPyFcMSlbXlxcXXxcXFtcc1xTXSkqXDEvZyxOVU1CRVJfUkVHRVg9Lyg/OlxkKlwuXGQrfFxkK1wuPykoPzpbZUVdWystXT9cZCspPy9nLFNUQU5EQVJEX1VOSVRfUkVHRVg9L1thLXpBLVpdKy9nLFdPUkRfUEFSVF9SRUdFWD0vWyRAXT9bYS16QS1aX1x1MDA4MC1cdUZGRkZdW1x3XC1cdTAwODAtXHVGRkZGXSovZyxBREpVU1RfTlVNQkVSU19SRUdFWD1SZWdFeHAoU1RSSU5HX1JFR0VYLnNvdXJjZSsifCIrIigiLmNvbmNhdChXT1JEX1BBUlRfUkVHRVguc291cmNlLCIpPyIpKyIoIi5jb25jYXQoTlVNQkVSX1JFR0VYLnNvdXJjZSwiKSIpKyIoIi5jb25jYXQoU1RBTkRBUkRfVU5JVF9SRUdFWC5zb3VyY2UsIik/IiksImciKSxwcmludGVyUG9zdGNzcz17cHJpbnQ6Z2VuZXJpY1ByaW50JDMsaGFzUHJldHRpZXJJZ25vcmU6aGFzSWdub3JlQ29tbWVudCQyLG1hc3NhZ2VBc3ROb2RlOmNsZWFuXzEkMn0sb3B0aW9ucyQ2PXtzaW5nbGVRdW90ZTpjb21tb25PcHRpb25zLnNpbmdsZVF1b3RlfSxsYW5ndWFnZXMkMT1be25hbWU6IkNTUyIsc2luY2U6IjEuNC4wIixwYXJzZXJzOlsiY3NzIl0sZ3JvdXA6IkNTUyIsdG1TY29wZToic291cmNlLmNzcyIsYWNlTW9kZToiY3NzIixjb2RlbWlycm9yTW9kZToiY3NzIixjb2RlbWlycm9yTWltZVR5cGU6InRleHQvY3NzIixleHRlbnNpb25zOlsiLmNzcyIsIi5wY3NzIiwiLnBvc3Rjc3MiXSxsaWd1aXN0TGFuZ3VhZ2VJZDo1MCx2c2NvZGVMYW5ndWFnZUlkczpbImNzcyIsInBvc3Rjc3MiXX0se25hbWU6Ikxlc3MiLHNpbmNlOiIxLjQuMCIscGFyc2VyczpbImxlc3MiXSxncm91cDoiQ1NTIixleHRlbnNpb25zOlsiLmxlc3MiXSx0bVNjb3BlOiJzb3VyY2UuY3NzLmxlc3MiLGFjZU1vZGU6Imxlc3MiLGNvZGVtaXJyb3JNb2RlOiJjc3MiLGNvZGVtaXJyb3JNaW1lVHlwZToidGV4dC9jc3MiLGxpZ3Vpc3RMYW5ndWFnZUlkOjE5OCx2c2NvZGVMYW5ndWFnZUlkczpbImxlc3MiXX0se25hbWU6IlNDU1MiLHNpbmNlOiIxLjQuMCIscGFyc2VyczpbInNjc3MiXSxncm91cDoiQ1NTIix0bVNjb3BlOiJzb3VyY2Uuc2NzcyIsYWNlTW9kZToic2NzcyIsY29kZW1pcnJvck1vZGU6ImNzcyIsY29kZW1pcnJvck1pbWVUeXBlOiJ0ZXh0L3gtc2NzcyIsZXh0ZW5zaW9uczpbIi5zY3NzIl0sbGlndWlzdExhbmd1YWdlSWQ6MzI5LHZzY29kZUxhbmd1YWdlSWRzOlsic2NzcyJdfV0scHJpbnRlcnMkMT17cG9zdGNzczpwcmludGVyUG9zdGNzc30sbGFuZ3VhZ2VDc3M9e2xhbmd1YWdlczpsYW5ndWFnZXMkMSxvcHRpb25zOm9wdGlvbnMkNixwcmludGVyczpwcmludGVycyQxfSxfcmVxdWlyZSQkMCRidWlsZGVycyQzPWRvYy5idWlsZGVycyxjb25jYXQkOD1fcmVxdWlyZSQkMCRidWlsZGVycyQzLmNvbmNhdCxqb2luJDY9X3JlcXVpcmUkJDAkYnVpbGRlcnMkMy5qb2luLGhhcmRsaW5lJDc9X3JlcXVpcmUkJDAkYnVpbGRlcnMkMy5oYXJkbGluZSxsaW5lJDU9X3JlcXVpcmUkJDAkYnVpbGRlcnMkMy5saW5lLHNvZnRsaW5lJDQ9X3JlcXVpcmUkJDAkYnVpbGRlcnMkMy5zb2Z0bGluZSxncm91cCQzPV9yZXF1aXJlJCQwJGJ1aWxkZXJzJDMuZ3JvdXAsaW5kZW50JDY9X3JlcXVpcmUkJDAkYnVpbGRlcnMkMy5pbmRlbnQsaWZCcmVhayQzPV9yZXF1aXJlJCQwJGJ1aWxkZXJzJDMuaWZCcmVhayxoYXNJZ25vcmVDb21tZW50JDM9dXRpbC5oYXNJZ25vcmVDb21tZW50LGlzTmV4dExpbmVFbXB0eSQ0PXV0aWxTaGFyZWQuaXNOZXh0TGluZUVtcHR5LHByaW50ZXJHcmFwaHFsPXtwcmludDpnZW5lcmljUHJpbnQkNCxtYXNzYWdlQXN0Tm9kZTpjbGVhbiQ1LGhhc1ByZXR0aWVySWdub3JlOmhhc0lnbm9yZUNvbW1lbnQkMyxwcmludENvbW1lbnQ6cHJpbnRDb21tZW50JDIsY2FuQXR0YWNoQ29tbWVudDpjYW5BdHRhY2hDb21tZW50JDF9LG9wdGlvbnMkOT17YnJhY2tldFNwYWNpbmc6Y29tbW9uT3B0aW9ucy5icmFja2V0U3BhY2luZ30sbGFuZ3VhZ2VzJDI9W3tuYW1lOiJHcmFwaFFMIixzaW5jZToiMS41LjAiLHBhcnNlcnM6WyJncmFwaHFsIl0sZXh0ZW5zaW9uczpbIi5ncmFwaHFsIiwiLmdxbCJdLHRtU2NvcGU6InNvdXJjZS5ncmFwaHFsIixhY2VNb2RlOiJ0ZXh0IixsaWd1aXN0TGFuZ3VhZ2VJZDoxMzksdnNjb2RlTGFuZ3VhZ2VJZHM6WyJncmFwaHFsIl19XSxwcmludGVycyQyPXtncmFwaHFsOnByaW50ZXJHcmFwaHFsfSxsYW5ndWFnZUdyYXBocWw9e2xhbmd1YWdlczpsYW5ndWFnZXMkMixvcHRpb25zOm9wdGlvbnMkOSxwcmludGVyczpwcmludGVycyQyfSxfcmVxdWlyZSQkMCRidWlsZGVycyQ1PWRvYy5idWlsZGVycyxoYXJkbGluZSQ5PV9yZXF1aXJlJCQwJGJ1aWxkZXJzJDUuaGFyZGxpbmUsbGl0ZXJhbGxpbmUkMz1fcmVxdWlyZSQkMCRidWlsZGVycyQ1LmxpdGVyYWxsaW5lLGNvbmNhdCQxMD1fcmVxdWlyZSQkMCRidWlsZGVycyQ1LmNvbmNhdCxtYXJrQXNSb290JDE9X3JlcXVpcmUkJDAkYnVpbGRlcnMkNS5tYXJrQXNSb290LG1hcERvYyQ0PWRvYy51dGlscy5tYXBEb2MsZW1iZWRfMSQyPWVtYmVkJDIsZnJvbnRNYXR0ZXI9cGFyc2UkMyxwcmFnbWEkMj1jcmVhdGVDb21tb25qc01vZHVsZShmdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUpe3ZhciB0PSJAKCIuY29uY2F0KG4uam9pbigifCIpLCIpIikscj1uZXcgUmVnRXhwKFsiXHgzYyEtLVxccyoiLmNvbmNhdCh0LCJcXHMqLS1ceDNlIiksIlx4M2MhLS0uKlxuW1xcc1xcU10qKF58XG4pW15cXFNcbl0qIi5jb25jYXQodCwiW15cXFNcbl0qKCR8XG4pW1xcc1xcU10qXG4uKi0tXHgzZSIpXS5qb2luKCJ8IiksIm0iKSxpPWUubWF0Y2gocik7cmV0dXJuIGkmJjA9PT1pLmluZGV4fXZhciBuPVsiZm9ybWF0IiwicHJldHRpZXIiXTtlLmV4cG9ydHM9e3N0YXJ0V2l0aFByYWdtYTp0LGhhc1ByYWdtYTpmdW5jdGlvbihlKXtyZXR1cm4gdChmcm9udE1hdHRlcihlKS5jb250ZW50LnRyaW1MZWZ0KCkpfSxpbnNlcnRQcmFnbWE6ZnVuY3Rpb24oZSl7dmFyIHQ9ZnJvbnRNYXR0ZXIoZSkscj0iXHgzYyEtLSBAIi5jb25jYXQoblswXSwiIC0tXHgzZSIpO3JldHVybiB0LmZyb250TWF0dGVyPyIiLmNvbmNhdCh0LmZyb250TWF0dGVyLCJcblxuIikuY29uY2F0KHIsIlxuXG4iKS5jb25jYXQodC5jb250ZW50KToiIi5jb25jYXQociwiXG5cbiIpLmNvbmNhdCh0LmNvbnRlbnQpfX19KSxfcmVxdWlyZSQkMCRidWlsZGVycyQ0PWRvYy5idWlsZGVycyxjb25jYXQkOT1fcmVxdWlyZSQkMCRidWlsZGVycyQ0LmNvbmNhdCxqb2luJDc9X3JlcXVpcmUkJDAkYnVpbGRlcnMkNC5qb2luLGxpbmUkNj1fcmVxdWlyZSQkMCRidWlsZGVycyQ0LmxpbmUsaGFyZGxpbmUkOD1fcmVxdWlyZSQkMCRidWlsZGVycyQ0LmhhcmRsaW5lLHNvZnRsaW5lJDU9X3JlcXVpcmUkJDAkYnVpbGRlcnMkNC5zb2Z0bGluZSxmaWxsJDQ9X3JlcXVpcmUkJDAkYnVpbGRlcnMkNC5maWxsLGFsaWduJDI9X3JlcXVpcmUkJDAkYnVpbGRlcnMkNC5hbGlnbixpbmRlbnQkNz1fcmVxdWlyZSQkMCRidWlsZGVycyQ0LmluZGVudCxncm91cCQ0PV9yZXF1aXJlJCQwJGJ1aWxkZXJzJDQuZ3JvdXAsbWFwRG9jJDM9ZG9jLnV0aWxzLm1hcERvYyxwcmludERvY1RvU3RyaW5nJDI9ZG9jLnByaW50ZXIucHJpbnREb2NUb1N0cmluZyxTSU5HTEVfTElORV9OT0RFX1RZUEVTPVsiaGVhZGluZyIsInRhYmxlQ2VsbCIsImxpbmsiXSxTSUJMSU5HX05PREVfVFlQRVM9WyJsaXN0SXRlbSIsImRlZmluaXRpb24iLCJmb290bm90ZURlZmluaXRpb24iXSxJTkxJTkVfTk9ERV9UWVBFUz1bImxpcXVpZE5vZGUiLCJpbmxpbmVDb2RlIiwiZW1waGFzaXMiLCJzdHJvbmciLCJkZWxldGUiLCJsaW5rIiwibGlua1JlZmVyZW5jZSIsImltYWdlIiwiaW1hZ2VSZWZlcmVuY2UiLCJmb290bm90ZSIsImZvb3Rub3RlUmVmZXJlbmNlIiwic2VudGVuY2UiLCJ3aGl0ZXNwYWNlIiwid29yZCIsImJyZWFrIl0sSU5MSU5FX05PREVfV1JBUFBFUl9UWVBFUz1JTkxJTkVfTk9ERV9UWVBFUy5jb25jYXQoWyJ0YWJsZUNlbGwiLCJwYXJhZ3JhcGgiLCJoZWFkaW5nIl0pLHByaW50ZXJNYXJrZG93bj17cHJpbnQ6Z2VuZXJpY1ByaW50JDUsZW1iZWQ6ZW1iZWRfMSQyLG1hc3NhZ2VBc3ROb2RlOmNsZWFuJDYsaGFzUHJldHRpZXJJZ25vcmU6aGFzUHJldHRpZXJJZ25vcmUkMSxpbnNlcnRQcmFnbWE6cHJhZ21hJDIuaW5zZXJ0UHJhZ21hfSxDQVRFR09SWV9NQVJLRE9XTj0iTWFya2Rvd24iLG9wdGlvbnMkMTI9e3Byb3NlV3JhcDp7c2luY2U6IjEuOC4yIixjYXRlZ29yeTpDQVRFR09SWV9NQVJLRE9XTix0eXBlOiJjaG9pY2UiLGRlZmF1bHQ6W3tzaW5jZToiMS44LjIiLHZhbHVlOiEwfSx7c2luY2U6IjEuOS4wIix2YWx1ZToicHJlc2VydmUifV0sZGVzY3JpcHRpb246IkhvdyB0byB3cmFwIHByb3NlLiAobWFya2Rvd24pIixjaG9pY2VzOlt7c2luY2U6IjEuOS4wIix2YWx1ZToiYWx3YXlzIixkZXNjcmlwdGlvbjoiV3JhcCBwcm9zZSBpZiBpdCBleGNlZWRzIHRoZSBwcmludCB3aWR0aC4ifSx7c2luY2U6IjEuOS4wIix2YWx1ZToibmV2ZXIiLGRlc2NyaXB0aW9uOiJEbyBub3Qgd3JhcCBwcm9zZS4ifSx7c2luY2U6IjEuOS4wIix2YWx1ZToicHJlc2VydmUiLGRlc2NyaXB0aW9uOiJXcmFwIHByb3NlIGFzLWlzLiJ9LHt2YWx1ZTohMSxkZXByZWNhdGVkOiIxLjkuMCIscmVkaXJlY3Q6Im5ldmVyIn0se3ZhbHVlOiEwLGRlcHJlY2F0ZWQ6IjEuOS4wIixyZWRpcmVjdDoiYWx3YXlzIn1dfSxzaW5nbGVRdW90ZTpjb21tb25PcHRpb25zLnNpbmdsZVF1b3RlfSxsYW5ndWFnZXMkMz1be25hbWU6Ik1hcmtkb3duIixzaW5jZToiMS44LjAiLHBhcnNlcnM6WyJyZW1hcmsiXSxhbGlhc2VzOlsicGFuZG9jIl0sYWNlTW9kZToibWFya2Rvd24iLGNvZGVtaXJyb3JNb2RlOiJnZm0iLGNvZGVtaXJyb3JNaW1lVHlwZToidGV4dC94LWdmbSIsd3JhcDohMCxleHRlbnNpb25zOlsiLm1kIiwiLm1hcmtkb3duIiwiLm1kb3duIiwiLm1kd24iLCIubWtkIiwiLm1rZG4iLCIubWtkb3duIiwiLnJvbiIsIi53b3JrYm9vayJdLGZpbGVuYW1lczpbIlJFQURNRSJdLHRtU2NvcGU6InNvdXJjZS5nZm0iLGxpbmd1aXN0TGFuZ3VhZ2VJZDoyMjIsdnNjb2RlTGFuZ3VhZ2VJZHM6WyJtYXJrZG93biJdfV0scHJpbnRlcnMkMz17bWRhc3Q6cHJpbnRlck1hcmtkb3dufSxsYW5ndWFnZU1hcmtkb3duPXtsYW5ndWFnZXM6bGFuZ3VhZ2VzJDMsb3B0aW9uczpvcHRpb25zJDEyLHByaW50ZXJzOnByaW50ZXJzJDN9LF9yZXF1aXJlJCQwJGJ1aWxkZXJzJDc9ZG9jLmJ1aWxkZXJzLGNvbmNhdCQxMj1fcmVxdWlyZSQkMCRidWlsZGVycyQ3LmNvbmNhdCxoYXJkbGluZSQxMT1fcmVxdWlyZSQkMCRidWlsZGVycyQ3LmhhcmRsaW5lLGVtYmVkXzEkND1lbWJlZCQ0LF9yZXF1aXJlJCQwJGJ1aWxkZXJzJDY9ZG9jLmJ1aWxkZXJzLGNvbmNhdCQxMT1fcmVxdWlyZSQkMCRidWlsZGVycyQ2LmNvbmNhdCxoYXJkbGluZSQxMD1fcmVxdWlyZSQkMCRidWlsZGVycyQ2LmhhcmRsaW5lLGNsZWFuJDc9ZnVuY3Rpb24oZSx0KXtkZWxldGUgdC5zdGFydCxkZWxldGUgdC5lbmQsZGVsZXRlIHQuY29udGVudFN0YXJ0LGRlbGV0ZSB0LmNvbnRlbnRFbmR9LHByaW50ZXJWdWU9e3ByaW50OmdlbmVyaWNQcmludCQ2LGVtYmVkOmVtYmVkXzEkNCxtYXNzYWdlQXN0Tm9kZTpjbGVhbiQ3fSxsYW5ndWFnZXMkND1be25hbWU6IlZ1ZSIsc2luY2U6IjEuMTAuMCIscGFyc2VyczpbInZ1ZSJdLGdyb3VwOiJIVE1MIix0bVNjb3BlOiJ0ZXh0Lmh0bWwudnVlIixhY2VNb2RlOiJodG1sIixjb2RlbWlycm9yTW9kZToiaHRtbG1peGVkIixjb2RlbWlycm9yTWltZVR5cGU6InRleHQvaHRtbCIsZXh0ZW5zaW9uczpbIi52dWUiXSxsaW5ndWlzdExhbmd1YWdlSWQ6MTQ2LHZzY29kZUxhbmd1YWdlSWRzOlsidnVlIl19XSxwcmludGVycyQ0PXt2dWU6cHJpbnRlclZ1ZX0sbGFuZ3VhZ2VWdWU9e2xhbmd1YWdlczpsYW5ndWFnZXMkNCxwcmludGVyczpwcmludGVycyQ0fSx2ZXJzaW9uPXJlcXVpcmUkJDAudmVyc2lvbixnZXRTdXBwb3J0SW5mbz1zdXBwb3J0LmdldFN1cHBvcnRJbmZvLGludGVybmFsUGx1Z2lucz1bbGFuZ3VhZ2VKcyxsYW5ndWFnZUNzcyxsYW5ndWFnZUdyYXBocWwsbGFuZ3VhZ2VNYXJrZG93bixsYW5ndWFnZVZ1ZV0saXNBcnJheT1BcnJheS5pc0FycmF5fHxmdW5jdGlvbihlKXtyZXR1cm4iW29iamVjdCBBcnJheV0iPT09T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGUpfSxmb3JtYXRXaXRoQ3Vyc29yPXdpdGhQbHVnaW5zKGNvcmUuZm9ybWF0V2l0aEN1cnNvciksc3RhbmRhbG9uZT17Zm9ybWF0V2l0aEN1cnNvcjpmb3JtYXRXaXRoQ3Vyc29yLGZvcm1hdDpmdW5jdGlvbihlLHQpe3JldHVybiBmb3JtYXRXaXRoQ3Vyc29yKGUsdCkuZm9ybWF0dGVkfSxjaGVjazpmdW5jdGlvbihlLHQpe3JldHVybiBmb3JtYXRXaXRoQ3Vyc29yKGUsdCkuZm9ybWF0dGVkPT09ZX0sZG9jOmRvYyxnZXRTdXBwb3J0SW5mbzp3aXRoUGx1Z2lucyhnZXRTdXBwb3J0SW5mbyksdmVyc2lvbjp2ZXJzaW9uLHV0aWw6dXRpbFNoYXJlZCxfX2RlYnVnOntwYXJzZTp3aXRoUGx1Z2lucyhjb3JlLnBhcnNlKSxmb3JtYXRBU1Q6d2l0aFBsdWdpbnMoY29yZS5mb3JtYXRBU1QpLGZvcm1hdERvYzp3aXRoUGx1Z2lucyhjb3JlLmZvcm1hdERvYykscHJpbnRUb0RvYzp3aXRoUGx1Z2lucyhjb3JlLnByaW50VG9Eb2MpLHByaW50RG9jVG9TdHJpbmc6d2l0aFBsdWdpbnMoY29yZS5wcmludERvY1RvU3RyaW5nKX19O3JldHVybiBzdGFuZGFsb25lfSl9KS5jYWxsKGV4cG9ydHMsX193ZWJwYWNrX3JlcXVpcmVfXygxMSkpfSxmdW5jdGlvbihlLHQsbil7IWZ1bmN0aW9uKHQsbil7ZS5leHBvcnRzPW4oKX0oMCxmdW5jdGlvbigpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBlKHQpe3JldHVybihlPSJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJiJzeW1ib2wiPT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PXR5cGVvZiBTeW1ib2wmJmUuY29uc3RydWN0b3I9PT1TeW1ib2wmJmUhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBlfSkodCl9ZnVuY3Rpb24gdChlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlJiZPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSwiZGVmYXVsdCIpP2UuZGVmYXVsdDplfWZ1bmN0aW9uIG4oZSx0KXtyZXR1cm4gZSh0PXtleHBvcnRzOnt9fSx0LmV4cG9ydHMpLHQuZXhwb3J0c312YXIgcj1mdW5jdGlvbihlLHQpe3ZhciBuPW5ldyBTeW50YXhFcnJvcihlKyIgKCIrdC5zdGFydC5saW5lKyI6Iit0LnN0YXJ0LmNvbHVtbisiKSIpO3JldHVybiBuLmxvYz10LG59LGk9bihmdW5jdGlvbihlLHQpe09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmdldExvY2F0aW9uPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPS9cclxufFtcblxyXS9nLHI9MSxpPXQrMSxvPXZvaWQgMDsobz1uLmV4ZWMoZS5ib2R5KSkmJm8uaW5kZXg8dDspcis9MSxpPXQrMS0oby5pbmRleCtvWzBdLmxlbmd0aCk7cmV0dXJue2xpbmU6cixjb2x1bW46aX19fSk7dChpKTt2YXIgbz1uKGZ1bmN0aW9uKGUsdCl7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuS2luZD1PYmplY3QuZnJlZXplKHtOQU1FOiJOYW1lIixET0NVTUVOVDoiRG9jdW1lbnQiLE9QRVJBVElPTl9ERUZJTklUSU9OOiJPcGVyYXRpb25EZWZpbml0aW9uIixWQVJJQUJMRV9ERUZJTklUSU9OOiJWYXJpYWJsZURlZmluaXRpb24iLFZBUklBQkxFOiJWYXJpYWJsZSIsU0VMRUNUSU9OX1NFVDoiU2VsZWN0aW9uU2V0IixGSUVMRDoiRmllbGQiLEFSR1VNRU5UOiJBcmd1bWVudCIsRlJBR01FTlRfU1BSRUFEOiJGcmFnbWVudFNwcmVhZCIsSU5MSU5FX0ZSQUdNRU5UOiJJbmxpbmVGcmFnbWVudCIsRlJBR01FTlRfREVGSU5JVElPTjoiRnJhZ21lbnREZWZpbml0aW9uIixJTlQ6IkludFZhbHVlIixGTE9BVDoiRmxvYXRWYWx1ZSIsU1RSSU5HOiJTdHJpbmdWYWx1ZSIsQk9PTEVBTjoiQm9vbGVhblZhbHVlIixOVUxMOiJOdWxsVmFsdWUiLEVOVU06IkVudW1WYWx1ZSIsTElTVDoiTGlzdFZhbHVlIixPQkpFQ1Q6Ik9iamVjdFZhbHVlIixPQkpFQ1RfRklFTEQ6Ik9iamVjdEZpZWxkIixESVJFQ1RJVkU6IkRpcmVjdGl2ZSIsTkFNRURfVFlQRToiTmFtZWRUeXBlIixMSVNUX1RZUEU6Ikxpc3RUeXBlIixOT05fTlVMTF9UWVBFOiJOb25OdWxsVHlwZSIsU0NIRU1BX0RFRklOSVRJT046IlNjaGVtYURlZmluaXRpb24iLE9QRVJBVElPTl9UWVBFX0RFRklOSVRJT046Ik9wZXJhdGlvblR5cGVEZWZpbml0aW9uIixTQ0FMQVJfVFlQRV9ERUZJTklUSU9OOiJTY2FsYXJUeXBlRGVmaW5pdGlvbiIsT0JKRUNUX1RZUEVfREVGSU5JVElPTjoiT2JqZWN0VHlwZURlZmluaXRpb24iLEZJRUxEX0RFRklOSVRJT046IkZpZWxkRGVmaW5pdGlvbiIsSU5QVVRfVkFMVUVfREVGSU5JVElPTjoiSW5wdXRWYWx1ZURlZmluaXRpb24iLElOVEVSRkFDRV9UWVBFX0RFRklOSVRJT046IkludGVyZmFjZVR5cGVEZWZpbml0aW9uIixVTklPTl9UWVBFX0RFRklOSVRJT046IlVuaW9uVHlwZURlZmluaXRpb24iLEVOVU1fVFlQRV9ERUZJTklUSU9OOiJFbnVtVHlwZURlZmluaXRpb24iLEVOVU1fVkFMVUVfREVGSU5JVElPTjoiRW51bVZhbHVlRGVmaW5pdGlvbiIsSU5QVVRfT0JKRUNUX1RZUEVfREVGSU5JVElPTjoiSW5wdXRPYmplY3RUeXBlRGVmaW5pdGlvbiIsU0NBTEFSX1RZUEVfRVhURU5TSU9OOiJTY2FsYXJUeXBlRXh0ZW5zaW9uIixPQkpFQ1RfVFlQRV9FWFRFTlNJT046Ik9iamVjdFR5cGVFeHRlbnNpb24iLElOVEVSRkFDRV9UWVBFX0VYVEVOU0lPTjoiSW50ZXJmYWNlVHlwZUV4dGVuc2lvbiIsVU5JT05fVFlQRV9FWFRFTlNJT046IlVuaW9uVHlwZUV4dGVuc2lvbiIsRU5VTV9UWVBFX0VYVEVOU0lPTjoiRW51bVR5cGVFeHRlbnNpb24iLElOUFVUX09CSkVDVF9UWVBFX0VYVEVOU0lPTjoiSW5wdXRPYmplY3RUeXBlRXh0ZW5zaW9uIixESVJFQ1RJVkVfREVGSU5JVElPTjoiRGlyZWN0aXZlRGVmaW5pdGlvbiJ9KX0pO3Qobyk7dmFyIGE9bihmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSx0KXt2YXIgbj10LmxpbmUsaT1lLmxvY2F0aW9uT2Zmc2V0LmxpbmUtMSxhPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIDE9PT10LmxpbmU/ZS5sb2NhdGlvbk9mZnNldC5jb2x1bW4tMTowfShlLHQpLHM9bitpLHU9dC5jb2x1bW4rYSxjPShzLTEpLnRvU3RyaW5nKCksbD1zLnRvU3RyaW5nKCkscD0ocysxKS50b1N0cmluZygpLGY9cC5sZW5ndGgsZD1lLmJvZHkuc3BsaXQoL1xyXG58W1xuXHJdL2cpO3JldHVybiBkWzBdPXIoZS5sb2NhdGlvbk9mZnNldC5jb2x1bW4tMSkrZFswXSxbZS5uYW1lKyIgKCIrcysiOiIrdSsiKSIsbj49MiYmbyhmLGMpKyI6ICIrZFtuLTJdLG8oZixsKSsiOiAiK2Rbbi0xXSxyKDIrZit1LTEpKyJeIixuPGQubGVuZ3RoJiZvKGYscCkrIjogIitkW25dXS5maWx0ZXIoQm9vbGVhbikuam9pbigiXG4iKX1mdW5jdGlvbiByKGUpe3JldHVybiBBcnJheShlKzEpLmpvaW4oIiAiKX1mdW5jdGlvbiBvKGUsdCl7cmV0dXJuIHIoZS10Lmxlbmd0aCkrdH1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5wcmludEVycm9yPWZ1bmN0aW9uKGUpe3ZhciB0PVtdO2lmKGUubm9kZXMpZS5ub2Rlcy5mb3JFYWNoKGZ1bmN0aW9uKGUpe2UubG9jJiZ0LnB1c2gobihlLmxvYy5zb3VyY2UsKDAsaS5nZXRMb2NhdGlvbikoZS5sb2Muc291cmNlLGUubG9jLnN0YXJ0KSkpfSk7ZWxzZSBpZihlLnNvdXJjZSYmZS5sb2NhdGlvbnMpe3ZhciByPWUuc291cmNlO2UubG9jYXRpb25zLmZvckVhY2goZnVuY3Rpb24oZSl7dC5wdXNoKG4ocixlKSl9KX1yZXR1cm4gMD09PXQubGVuZ3RoP2UubWVzc2FnZTpbZS5tZXNzYWdlXS5jb25jYXQodCkuam9pbigiXG5cbiIpKyJcbiJ9fSk7dChhKTt2YXIgcz1uKGZ1bmN0aW9uKGUsdCl7ZnVuY3Rpb24gbihlLHQscixvLGEscyx1KXt2YXIgYz1BcnJheS5pc0FycmF5KHQpPzAhPT10Lmxlbmd0aD90OnZvaWQgMDp0P1t0XTp2b2lkIDAsbD1yO2lmKCFsJiZjKXt2YXIgcD1jWzBdO2w9cCYmcC5sb2MmJnAubG9jLnNvdXJjZX12YXIgZj1vOyFmJiZjJiYoZj1jLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiB0LmxvYyYmZS5wdXNoKHQubG9jLnN0YXJ0KSxlfSxbXSkpLGYmJjA9PT1mLmxlbmd0aCYmKGY9dm9pZCAwKTt2YXIgZD12b2lkIDA7byYmcj9kPW8ubWFwKGZ1bmN0aW9uKGUpe3JldHVybigwLGkuZ2V0TG9jYXRpb24pKHIsZSl9KTpjJiYoZD1jLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiB0LmxvYyYmZS5wdXNoKCgwLGkuZ2V0TG9jYXRpb24pKHQubG9jLnNvdXJjZSx0LmxvYy5zdGFydCkpLGV9LFtdKSksT2JqZWN0LmRlZmluZVByb3BlcnRpZXModGhpcyx7bWVzc2FnZTp7dmFsdWU6ZSxlbnVtZXJhYmxlOiEwLHdyaXRhYmxlOiEwfSxsb2NhdGlvbnM6e3ZhbHVlOmR8fHZvaWQgMCxlbnVtZXJhYmxlOiEwfSxwYXRoOnt2YWx1ZTphfHx2b2lkIDAsZW51bWVyYWJsZTohMH0sbm9kZXM6e3ZhbHVlOmN8fHZvaWQgMH0sc291cmNlOnt2YWx1ZTpsfHx2b2lkIDB9LHBvc2l0aW9uczp7dmFsdWU6Znx8dm9pZCAwfSxvcmlnaW5hbEVycm9yOnt2YWx1ZTpzfSxleHRlbnNpb25zOnt2YWx1ZTp1fHxzJiZzLmV4dGVuc2lvbnN9fSkscyYmcy5zdGFjaz9PYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywic3RhY2siLHt2YWx1ZTpzLnN0YWNrLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pOkVycm9yLmNhcHR1cmVTdGFja1RyYWNlP0Vycm9yLmNhcHR1cmVTdGFja1RyYWNlKHRoaXMsbik6T2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsInN0YWNrIix7dmFsdWU6RXJyb3IoKS5zdGFjayx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9KX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5HcmFwaFFMRXJyb3I9bixuLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKEVycm9yLnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOm59LG5hbWU6e3ZhbHVlOiJHcmFwaFFMRXJyb3IifSx0b1N0cmluZzp7dmFsdWU6ZnVuY3Rpb24oKXtyZXR1cm4oMCxhLnByaW50RXJyb3IpKHRoaXMpfX19KX0pO3Qocyk7dmFyIHU9bihmdW5jdGlvbihlLHQpe09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnN5bnRheEVycm9yPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gbmV3IHMuR3JhcGhRTEVycm9yKCJTeW50YXggRXJyb3I6ICIrbix2b2lkIDAsZSxbdF0pfX0pO3QodSk7dmFyIGM9bihmdW5jdGlvbihlLHQpe09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmxvY2F0ZWRFcnJvcj1mdW5jdGlvbihlLHQsbil7cmV0dXJuIGUmJkFycmF5LmlzQXJyYXkoZS5wYXRoKT9lOm5ldyBzLkdyYXBoUUxFcnJvcihlJiZlLm1lc3NhZ2UsZSYmZS5ub2Rlc3x8dCxlJiZlLnNvdXJjZSxlJiZlLnBvc2l0aW9ucyxuLGUpfX0pO3QoYyk7dmFyIGw9bihmdW5jdGlvbihlLHQpe09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmRlZmF1bHQ9ZnVuY3Rpb24oZSx0KXtpZighZSl0aHJvdyBuZXcgRXJyb3IodCl9fSk7dChsKTt2YXIgcD1uKGZ1bmN0aW9uKGUsdCl7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBuPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspe3ZhciBuPWFyZ3VtZW50c1t0XTtmb3IodmFyIHIgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmKGVbcl09bltyXSl9cmV0dXJuIGV9O3QuZm9ybWF0RXJyb3I9ZnVuY3Rpb24oZSl7cmV0dXJuIGV8fCgwLGkuZGVmYXVsdCkoMCwiUmVjZWl2ZWQgbnVsbCBvciB1bmRlZmluZWQgZXJyb3IuIiksbih7fSxlLmV4dGVuc2lvbnMse21lc3NhZ2U6ZS5tZXNzYWdlfHwiQW4gdW5rbm93biBlcnJvciBvY2N1cnJlZC4iLGxvY2F0aW9uczplLmxvY2F0aW9ucyxwYXRoOmUucGF0aH0pfTt2YXIgcixpPShyPWwpJiZyLl9fZXNNb2R1bGU/cjp7ZGVmYXVsdDpyfX0pO3QocCk7dmFyIGY9bihmdW5jdGlvbihlLHQpe09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiR3JhcGhRTEVycm9yIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcy5HcmFwaFFMRXJyb3J9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInN5bnRheEVycm9yIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdS5zeW50YXhFcnJvcn19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwibG9jYXRlZEVycm9yIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gYy5sb2NhdGVkRXJyb3J9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsInByaW50RXJyb3IiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBhLnByaW50RXJyb3J9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImZvcm1hdEVycm9yIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gcC5mb3JtYXRFcnJvcn19KX0pO3QoZik7dmFyIGQ9bihmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7Zm9yKHZhciB0PTA7dDxlLmxlbmd0aCYmKCIgIj09PWVbdF18fCJcdCI9PT1lW3RdKTspdCsrO3JldHVybiB0fWZ1bmN0aW9uIHIoZSl7cmV0dXJuIG4oZSk9PT1lLmxlbmd0aH1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1lLnNwbGl0KC9cclxufFtcblxyXS9nKSxpPW51bGwsbz0xO288dC5sZW5ndGg7bysrKXt2YXIgYT10W29dLHM9bihhKTtpZihzPGEubGVuZ3RoJiYobnVsbD09PWl8fHM8aSkmJjA9PT0oaT1zKSlicmVha31pZihpKWZvcih2YXIgdT0xO3U8dC5sZW5ndGg7dSsrKXRbdV09dFt1XS5zbGljZShpKTtmb3IoO3QubGVuZ3RoPjAmJnIodFswXSk7KXQuc2hpZnQoKTtmb3IoO3QubGVuZ3RoPjAmJnIodFt0Lmxlbmd0aC0xXSk7KXQucG9wKCk7cmV0dXJuIHQuam9pbigiXG4iKX19KTt0KGQpO3ZhciBoPW4oZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKCl7cmV0dXJuIHRoaXMubGFzdFRva2VuPXRoaXMudG9rZW4sdGhpcy50b2tlbj10aGlzLmxvb2thaGVhZCgpfWZ1bmN0aW9uIHIoKXt2YXIgZT10aGlzLnRva2VuO2lmKGUua2luZCE9PXAuRU9GKWRve2U9ZS5uZXh0fHwoZS5uZXh0PWEodGhpcyxlKSl9d2hpbGUoZS5raW5kPT09cC5DT01NRU5UKTtyZXR1cm4gZX1mdW5jdGlvbiBpKGUsdCxuLHIsaSxvLGEpe3RoaXMua2luZD1lLHRoaXMuc3RhcnQ9dCx0aGlzLmVuZD1uLHRoaXMubGluZT1yLHRoaXMuY29sdW1uPWksdGhpcy52YWx1ZT1hLHRoaXMucHJldj1vLHRoaXMubmV4dD1udWxsfWZ1bmN0aW9uIG8oZSl7cmV0dXJuIGlzTmFOKGUpP3AuRU9GOmU8MTI3P0pTT04uc3RyaW5naWZ5KFN0cmluZy5mcm9tQ2hhckNvZGUoZSkpOiciXFx1JysoIjAwIitlLnRvU3RyaW5nKDE2KS50b1VwcGVyQ2FzZSgpKS5zbGljZSgtNCkrJyInfWZ1bmN0aW9uIGEoZSx0KXt2YXIgbj1lLnNvdXJjZSxyPW4uYm9keSxhPXIubGVuZ3RoLGM9ZnVuY3Rpb24oZSx0LG4pe2Zvcih2YXIgcj1lLmxlbmd0aCxpPXQ7aTxyOyl7dmFyIG89aC5jYWxsKGUsaSk7aWYoOT09PW98fDMyPT09b3x8NDQ9PT1vfHw2NTI3OT09PW8pKytpO2Vsc2UgaWYoMTA9PT1vKSsraSwrK24ubGluZSxuLmxpbmVTdGFydD1pO2Vsc2V7aWYoMTMhPT1vKWJyZWFrOzEwPT09aC5jYWxsKGUsaSsxKT9pKz0yOisraSwrK24ubGluZSxuLmxpbmVTdGFydD1pfX1yZXR1cm4gaX0ocix0LmVuZCxlKSxkPWUubGluZSxnPTErYy1lLmxpbmVTdGFydDtpZihjPj1hKXJldHVybiBuZXcgaShwLkVPRixhLGEsZCxnLHQpO3ZhciB5PWguY2FsbChyLGMpO2lmKHk8MzImJjkhPT15JiYxMCE9PXkmJjEzIT09eSl0aHJvdygwLGYuc3ludGF4RXJyb3IpKG4sYywiQ2Fubm90IGNvbnRhaW4gdGhlIGludmFsaWQgY2hhcmFjdGVyICIrbyh5KSsiLiIpO3N3aXRjaCh5KXtjYXNlIDMzOnJldHVybiBuZXcgaShwLkJBTkcsYyxjKzEsZCxnLHQpO2Nhc2UgMzU6cmV0dXJuIGZ1bmN0aW9uKGUsdCxuLHIsbyl7dmFyIGE9ZS5ib2R5LHM9dm9pZCAwLHU9dDtkb3tzPWguY2FsbChhLCsrdSl9d2hpbGUobnVsbCE9PXMmJihzPjMxfHw5PT09cykpO3JldHVybiBuZXcgaShwLkNPTU1FTlQsdCx1LG4scixvLG0uY2FsbChhLHQrMSx1KSl9KG4sYyxkLGcsdCk7Y2FzZSAzNjpyZXR1cm4gbmV3IGkocC5ET0xMQVIsYyxjKzEsZCxnLHQpO2Nhc2UgMzg6cmV0dXJuIG5ldyBpKHAuQU1QLGMsYysxLGQsZyx0KTtjYXNlIDQwOnJldHVybiBuZXcgaShwLlBBUkVOX0wsYyxjKzEsZCxnLHQpO2Nhc2UgNDE6cmV0dXJuIG5ldyBpKHAuUEFSRU5fUixjLGMrMSxkLGcsdCk7Y2FzZSA0NjppZig0Nj09PWguY2FsbChyLGMrMSkmJjQ2PT09aC5jYWxsKHIsYysyKSlyZXR1cm4gbmV3IGkocC5TUFJFQUQsYyxjKzMsZCxnLHQpO2JyZWFrO2Nhc2UgNTg6cmV0dXJuIG5ldyBpKHAuQ09MT04sYyxjKzEsZCxnLHQpO2Nhc2UgNjE6cmV0dXJuIG5ldyBpKHAuRVFVQUxTLGMsYysxLGQsZyx0KTtjYXNlIDY0OnJldHVybiBuZXcgaShwLkFULGMsYysxLGQsZyx0KTtjYXNlIDkxOnJldHVybiBuZXcgaShwLkJSQUNLRVRfTCxjLGMrMSxkLGcsdCk7Y2FzZSA5MzpyZXR1cm4gbmV3IGkocC5CUkFDS0VUX1IsYyxjKzEsZCxnLHQpO2Nhc2UgMTIzOnJldHVybiBuZXcgaShwLkJSQUNFX0wsYyxjKzEsZCxnLHQpO2Nhc2UgMTI0OnJldHVybiBuZXcgaShwLlBJUEUsYyxjKzEsZCxnLHQpO2Nhc2UgMTI1OnJldHVybiBuZXcgaShwLkJSQUNFX1IsYyxjKzEsZCxnLHQpO2Nhc2UgNjU6Y2FzZSA2NjpjYXNlIDY3OmNhc2UgNjg6Y2FzZSA2OTpjYXNlIDcwOmNhc2UgNzE6Y2FzZSA3MjpjYXNlIDczOmNhc2UgNzQ6Y2FzZSA3NTpjYXNlIDc2OmNhc2UgNzc6Y2FzZSA3ODpjYXNlIDc5OmNhc2UgODA6Y2FzZSA4MTpjYXNlIDgyOmNhc2UgODM6Y2FzZSA4NDpjYXNlIDg1OmNhc2UgODY6Y2FzZSA4NzpjYXNlIDg4OmNhc2UgODk6Y2FzZSA5MDpjYXNlIDk1OmNhc2UgOTc6Y2FzZSA5ODpjYXNlIDk5OmNhc2UgMTAwOmNhc2UgMTAxOmNhc2UgMTAyOmNhc2UgMTAzOmNhc2UgMTA0OmNhc2UgMTA1OmNhc2UgMTA2OmNhc2UgMTA3OmNhc2UgMTA4OmNhc2UgMTA5OmNhc2UgMTEwOmNhc2UgMTExOmNhc2UgMTEyOmNhc2UgMTEzOmNhc2UgMTE0OmNhc2UgMTE1OmNhc2UgMTE2OmNhc2UgMTE3OmNhc2UgMTE4OmNhc2UgMTE5OmNhc2UgMTIwOmNhc2UgMTIxOmNhc2UgMTIyOnJldHVybiBmdW5jdGlvbihlLHQsbixyLG8pe2Zvcih2YXIgYT1lLmJvZHkscz1hLmxlbmd0aCx1PXQrMSxjPTA7dSE9PXMmJm51bGwhPT0oYz1oLmNhbGwoYSx1KSkmJig5NT09PWN8fGM+PTQ4JiZjPD01N3x8Yz49NjUmJmM8PTkwfHxjPj05NyYmYzw9MTIyKTspKyt1O3JldHVybiBuZXcgaShwLk5BTUUsdCx1LG4scixvLG0uY2FsbChhLHQsdSkpfShuLGMsZCxnLHQpO2Nhc2UgNDU6Y2FzZSA0ODpjYXNlIDQ5OmNhc2UgNTA6Y2FzZSA1MTpjYXNlIDUyOmNhc2UgNTM6Y2FzZSA1NDpjYXNlIDU1OmNhc2UgNTY6Y2FzZSA1NzpyZXR1cm4gZnVuY3Rpb24oZSx0LG4scixhLHUpe3ZhciBjPWUuYm9keSxsPW4sZD10LGc9ITE7aWYoNDU9PT1sJiYobD1oLmNhbGwoYywrK2QpKSw0OD09PWwpe2lmKChsPWguY2FsbChjLCsrZCkpPj00OCYmbDw9NTcpdGhyb3coMCxmLnN5bnRheEVycm9yKShlLGQsIkludmFsaWQgbnVtYmVyLCB1bmV4cGVjdGVkIGRpZ2l0IGFmdGVyIDA6ICIrbyhsKSsiLiIpfWVsc2UgZD1zKGUsZCxsKSxsPWguY2FsbChjLGQpO3JldHVybiA0Nj09PWwmJihnPSEwLGw9aC5jYWxsKGMsKytkKSxkPXMoZSxkLGwpLGw9aC5jYWxsKGMsZCkpLDY5IT09bCYmMTAxIT09bHx8KGc9ITAsNDMhPT0obD1oLmNhbGwoYywrK2QpKSYmNDUhPT1sfHwobD1oLmNhbGwoYywrK2QpKSxkPXMoZSxkLGwpKSxuZXcgaShnP3AuRkxPQVQ6cC5JTlQsdCxkLHIsYSx1LG0uY2FsbChjLHQsZCkpfShuLGMseSxkLGcsdCk7Y2FzZSAzNDpyZXR1cm4gMzQ9PT1oLmNhbGwocixjKzEpJiYzND09PWguY2FsbChyLGMrMik/ZnVuY3Rpb24oZSx0LG4scixhKXtmb3IodmFyIHM9ZS5ib2R5LHU9dCszLGM9dSxkPTAsZz0iIjt1PHMubGVuZ3RoJiZudWxsIT09KGQ9aC5jYWxsKHMsdSkpOyl7aWYoMzQ9PT1kJiYzND09PWguY2FsbChzLHUrMSkmJjM0PT09aC5jYWxsKHMsdSsyKSlyZXR1cm4gZys9bS5jYWxsKHMsYyx1KSxuZXcgaShwLkJMT0NLX1NUUklORyx0LHUrMyxuLHIsYSwoMCxsLmRlZmF1bHQpKGcpKTtpZihkPDMyJiY5IT09ZCYmMTAhPT1kJiYxMyE9PWQpdGhyb3coMCxmLnN5bnRheEVycm9yKShlLHUsIkludmFsaWQgY2hhcmFjdGVyIHdpdGhpbiBTdHJpbmc6ICIrbyhkKSsiLiIpOzkyPT09ZCYmMzQ9PT1oLmNhbGwocyx1KzEpJiYzND09PWguY2FsbChzLHUrMikmJjM0PT09aC5jYWxsKHMsdSszKT8oZys9bS5jYWxsKHMsYyx1KSsnIiIiJyxjPXUrPTQpOisrdX10aHJvdygwLGYuc3ludGF4RXJyb3IpKGUsdSwiVW50ZXJtaW5hdGVkIHN0cmluZy4iKX0obixjLGQsZyx0KTpmdW5jdGlvbihlLHQsbixyLGEpe2Zvcih2YXIgcz1lLmJvZHksYz10KzEsbD1jLGQ9MCxnPSIiO2M8cy5sZW5ndGgmJm51bGwhPT0oZD1oLmNhbGwocyxjKSkmJjEwIT09ZCYmMTMhPT1kOyl7aWYoMzQ9PT1kKXJldHVybiBnKz1tLmNhbGwocyxsLGMpLG5ldyBpKHAuU1RSSU5HLHQsYysxLG4scixhLGcpO2lmKGQ8MzImJjkhPT1kKXRocm93KDAsZi5zeW50YXhFcnJvcikoZSxjLCJJbnZhbGlkIGNoYXJhY3RlciB3aXRoaW4gU3RyaW5nOiAiK28oZCkrIi4iKTtpZigrK2MsOTI9PT1kKXtzd2l0Y2goZys9bS5jYWxsKHMsbCxjLTEpLGQ9aC5jYWxsKHMsYykpe2Nhc2UgMzQ6Zys9JyInO2JyZWFrO2Nhc2UgNDc6Zys9Ii8iO2JyZWFrO2Nhc2UgOTI6Zys9IlxcIjticmVhaztjYXNlIDk4OmcrPSJcYiI7YnJlYWs7Y2FzZSAxMDI6Zys9IlxmIjticmVhaztjYXNlIDExMDpnKz0iXG4iO2JyZWFrO2Nhc2UgMTE0OmcrPSJcciI7YnJlYWs7Y2FzZSAxMTY6Zys9Ilx0IjticmVhaztjYXNlIDExNzp2YXIgeT0odj1oLmNhbGwocyxjKzEpLGI9aC5jYWxsKHMsYysyKSx4PWguY2FsbChzLGMrMyksQz1oLmNhbGwocyxjKzQpLHUodik8PDEyfHUoYik8PDh8dSh4KTw8NHx1KEMpKTtpZih5PDApdGhyb3coMCxmLnN5bnRheEVycm9yKShlLGMsIkludmFsaWQgY2hhcmFjdGVyIGVzY2FwZSBzZXF1ZW5jZTogXFx1IitzLnNsaWNlKGMrMSxjKzUpKyIuIik7Zys9U3RyaW5nLmZyb21DaGFyQ29kZSh5KSxjKz00O2JyZWFrO2RlZmF1bHQ6dGhyb3coMCxmLnN5bnRheEVycm9yKShlLGMsIkludmFsaWQgY2hhcmFjdGVyIGVzY2FwZSBzZXF1ZW5jZTogXFwiK1N0cmluZy5mcm9tQ2hhckNvZGUoZCkrIi4iKX1sPSsrY319dmFyIHYsYix4LEM7dGhyb3coMCxmLnN5bnRheEVycm9yKShlLGMsIlVudGVybWluYXRlZCBzdHJpbmcuIil9KG4sYyxkLGcsdCl9dGhyb3coMCxmLnN5bnRheEVycm9yKShuLGMsZnVuY3Rpb24oZSl7cmV0dXJuIDM5PT09ZT8iVW5leHBlY3RlZCBzaW5nbGUgcXVvdGUgY2hhcmFjdGVyICgnKSwgZGlkIHlvdSBtZWFuIHRvIHVzZSBhIGRvdWJsZSBxdW90ZSAoXCIpPyI6IkNhbm5vdCBwYXJzZSB0aGUgdW5leHBlY3RlZCBjaGFyYWN0ZXIgIitvKGUpKyIuIn0oeSkpfWZ1bmN0aW9uIHMoZSx0LG4pe3ZhciByPWUuYm9keSxpPXQsYT1uO2lmKGE+PTQ4JiZhPD01Nyl7ZG97YT1oLmNhbGwociwrK2kpfXdoaWxlKGE+PTQ4JiZhPD01Nyk7cmV0dXJuIGl9dGhyb3coMCxmLnN5bnRheEVycm9yKShlLGksIkludmFsaWQgbnVtYmVyLCBleHBlY3RlZCBkaWdpdCBidXQgZ290OiAiK28oYSkrIi4iKX1mdW5jdGlvbiB1KGUpe3JldHVybiBlPj00OCYmZTw9NTc/ZS00ODplPj02NSYmZTw9NzA/ZS01NTplPj05NyYmZTw9MTAyP2UtODc6LTF9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuVG9rZW5LaW5kPXZvaWQgMCx0LmNyZWF0ZUxleGVyPWZ1bmN0aW9uKGUsdCl7dmFyIG89bmV3IGkocC5TT0YsMCwwLDAsMCxudWxsKTtyZXR1cm57c291cmNlOmUsb3B0aW9uczp0LGxhc3RUb2tlbjpvLHRva2VuOm8sbGluZToxLGxpbmVTdGFydDowLGFkdmFuY2U6bixsb29rYWhlYWQ6cn19LHQuZ2V0VG9rZW5EZXNjPWZ1bmN0aW9uKGUpe3ZhciB0PWUudmFsdWU7cmV0dXJuIHQ/ZS5raW5kKycgIicrdCsnIic6ZS5raW5kfTt2YXIgYyxsPShjPWQpJiZjLl9fZXNNb2R1bGU/Yzp7ZGVmYXVsdDpjfSxwPXQuVG9rZW5LaW5kPU9iamVjdC5mcmVlemUoe1NPRjoiPFNPRj4iLEVPRjoiPEVPRj4iLEJBTkc6IiEiLERPTExBUjoiJCIsQU1QOiImIixQQVJFTl9MOiIoIixQQVJFTl9SOiIpIixTUFJFQUQ6Ii4uLiIsQ09MT046IjoiLEVRVUFMUzoiPSIsQVQ6IkAiLEJSQUNLRVRfTDoiWyIsQlJBQ0tFVF9SOiJdIixCUkFDRV9MOiJ7IixQSVBFOiJ8IixCUkFDRV9SOiJ9IixOQU1FOiJOYW1lIixJTlQ6IkludCIsRkxPQVQ6IkZsb2F0IixTVFJJTkc6IlN0cmluZyIsQkxPQ0tfU1RSSU5HOiJCbG9ja1N0cmluZyIsQ09NTUVOVDoiQ29tbWVudCJ9KSxoPVN0cmluZy5wcm90b3R5cGUuY2hhckNvZGVBdCxtPVN0cmluZy5wcm90b3R5cGUuc2xpY2U7aS5wcm90b3R5cGUudG9KU09OPWkucHJvdG90eXBlLmluc3BlY3Q9ZnVuY3Rpb24oKXtyZXR1cm57a2luZDp0aGlzLmtpbmQsdmFsdWU6dGhpcy52YWx1ZSxsaW5lOnRoaXMubGluZSxjb2x1bW46dGhpcy5jb2x1bW59fX0pO3QoaCk7dmFyIG09bihmdW5jdGlvbihlLHQpe09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LlNvdXJjZT12b2lkIDA7dmFyIG4scj0obj1sKSYmbi5fX2VzTW9kdWxlP246e2RlZmF1bHQ6bn07dC5Tb3VyY2U9ZnVuY3Rpb24gZSh0LG4saSl7IWZ1bmN0aW9uKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9KHRoaXMsZSksdGhpcy5ib2R5PXQsdGhpcy5uYW1lPW58fCJHcmFwaFFMIHJlcXVlc3QiLHRoaXMubG9jYXRpb25PZmZzZXQ9aXx8e2xpbmU6MSxjb2x1bW46MX0sdGhpcy5sb2NhdGlvbk9mZnNldC5saW5lPjB8fCgwLHIuZGVmYXVsdCkoMCwibGluZSBpbiBsb2NhdGlvbk9mZnNldCBpcyAxLWluZGV4ZWQgYW5kIG11c3QgYmUgcG9zaXRpdmUiKSx0aGlzLmxvY2F0aW9uT2Zmc2V0LmNvbHVtbj4wfHwoMCxyLmRlZmF1bHQpKDAsImNvbHVtbiBpbiBsb2NhdGlvbk9mZnNldCBpcyAxLWluZGV4ZWQgYW5kIG11c3QgYmUgcG9zaXRpdmUiKX19KTt0KG0pO3ZhciBnPW4oZnVuY3Rpb24oZSx0KXtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5EaXJlY3RpdmVMb2NhdGlvbj1PYmplY3QuZnJlZXplKHtRVUVSWToiUVVFUlkiLE1VVEFUSU9OOiJNVVRBVElPTiIsU1VCU0NSSVBUSU9OOiJTVUJTQ1JJUFRJT04iLEZJRUxEOiJGSUVMRCIsRlJBR01FTlRfREVGSU5JVElPTjoiRlJBR01FTlRfREVGSU5JVElPTiIsRlJBR01FTlRfU1BSRUFEOiJGUkFHTUVOVF9TUFJFQUQiLElOTElORV9GUkFHTUVOVDoiSU5MSU5FX0ZSQUdNRU5UIixTQ0hFTUE6IlNDSEVNQSIsU0NBTEFSOiJTQ0FMQVIiLE9CSkVDVDoiT0JKRUNUIixGSUVMRF9ERUZJTklUSU9OOiJGSUVMRF9ERUZJTklUSU9OIixBUkdVTUVOVF9ERUZJTklUSU9OOiJBUkdVTUVOVF9ERUZJTklUSU9OIixJTlRFUkZBQ0U6IklOVEVSRkFDRSIsVU5JT046IlVOSU9OIixFTlVNOiJFTlVNIixFTlVNX1ZBTFVFOiJFTlVNX1ZBTFVFIixJTlBVVF9PQkpFQ1Q6IklOUFVUX09CSkVDVCIsSU5QVVRfRklFTERfREVGSU5JVElPTjoiSU5QVVRfRklFTERfREVGSU5JVElPTiJ9KX0pO3QoZyk7dmFyIHk9bihmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7dmFyIHQ9UShlLGguVG9rZW5LaW5kLk5BTUUpO3JldHVybntraW5kOm8uS2luZC5OQU1FLHZhbHVlOnQudmFsdWUsbG9jOlYoZSx0KX19ZnVuY3Rpb24gcihlKXtpZihIKGUsaC5Ub2tlbktpbmQuTkFNRSkpc3dpdGNoKGUudG9rZW4udmFsdWUpe2Nhc2UicXVlcnkiOmNhc2UibXV0YXRpb24iOmNhc2Uic3Vic2NyaXB0aW9uIjpjYXNlImZyYWdtZW50IjpyZXR1cm4gaShlKTtjYXNlInNjaGVtYSI6Y2FzZSJzY2FsYXIiOmNhc2UidHlwZSI6Y2FzZSJpbnRlcmZhY2UiOmNhc2UidW5pb24iOmNhc2UiZW51bSI6Y2FzZSJpbnB1dCI6Y2FzZSJleHRlbmQiOmNhc2UiZGlyZWN0aXZlIjpyZXR1cm4gTyhlKX1lbHNle2lmKEgoZSxoLlRva2VuS2luZC5CUkFDRV9MKSlyZXR1cm4gaShlKTtpZihGKGUpKXJldHVybiBPKGUpfXRocm93IEooZSl9ZnVuY3Rpb24gaShlKXtpZihIKGUsaC5Ub2tlbktpbmQuTkFNRSkpc3dpdGNoKGUudG9rZW4udmFsdWUpe2Nhc2UicXVlcnkiOmNhc2UibXV0YXRpb24iOmNhc2Uic3Vic2NyaXB0aW9uIjpyZXR1cm4gYShlKTtjYXNlImZyYWdtZW50IjpyZXR1cm4gZnVuY3Rpb24oZSl7dmFyIHQ9ZS50b2tlbjtyZXR1cm4gSyhlLCJmcmFnbWVudCIpLGUub3B0aW9ucy5leHBlcmltZW50YWxGcmFnbWVudFZhcmlhYmxlcz97a2luZDpvLktpbmQuRlJBR01FTlRfREVGSU5JVElPTixuYW1lOngoZSksdmFyaWFibGVEZWZpbml0aW9uczp1KGUpLHR5cGVDb25kaXRpb246KEsoZSwib24iKSxUKGUpKSxkaXJlY3RpdmVzOmsoZSwhMSksc2VsZWN0aW9uU2V0OnAoZSksbG9jOlYoZSx0KX06e2tpbmQ6by5LaW5kLkZSQUdNRU5UX0RFRklOSVRJT04sbmFtZTp4KGUpLHR5cGVDb25kaXRpb246KEsoZSwib24iKSxUKGUpKSxkaXJlY3RpdmVzOmsoZSwhMSksc2VsZWN0aW9uU2V0OnAoZSksbG9jOlYoZSx0KX19KGUpfWVsc2UgaWYoSChlLGguVG9rZW5LaW5kLkJSQUNFX0wpKXJldHVybiBhKGUpO3Rocm93IEooZSl9ZnVuY3Rpb24gYShlKXt2YXIgdD1lLnRva2VuO2lmKEgoZSxoLlRva2VuS2luZC5CUkFDRV9MKSlyZXR1cm57a2luZDpvLktpbmQuT1BFUkFUSU9OX0RFRklOSVRJT04sb3BlcmF0aW9uOiJxdWVyeSIsbmFtZTp2b2lkIDAsdmFyaWFibGVEZWZpbml0aW9uczpbXSxkaXJlY3RpdmVzOltdLHNlbGVjdGlvblNldDpwKGUpLGxvYzpWKGUsdCl9O3ZhciByPXMoZSksaT12b2lkIDA7cmV0dXJuIEgoZSxoLlRva2VuS2luZC5OQU1FKSYmKGk9bihlKSkse2tpbmQ6by5LaW5kLk9QRVJBVElPTl9ERUZJTklUSU9OLG9wZXJhdGlvbjpyLG5hbWU6aSx2YXJpYWJsZURlZmluaXRpb25zOnUoZSksZGlyZWN0aXZlczprKGUsITEpLHNlbGVjdGlvblNldDpwKGUpLGxvYzpWKGUsdCl9fWZ1bmN0aW9uIHMoZSl7dmFyIHQ9UShlLGguVG9rZW5LaW5kLk5BTUUpO3N3aXRjaCh0LnZhbHVlKXtjYXNlInF1ZXJ5IjpyZXR1cm4icXVlcnkiO2Nhc2UibXV0YXRpb24iOnJldHVybiJtdXRhdGlvbiI7Y2FzZSJzdWJzY3JpcHRpb24iOnJldHVybiJzdWJzY3JpcHRpb24ifXRocm93IEooZSx0KX1mdW5jdGlvbiB1KGUpe3JldHVybiBIKGUsaC5Ub2tlbktpbmQuUEFSRU5fTCk/WShlLGguVG9rZW5LaW5kLlBBUkVOX0wsYyxoLlRva2VuS2luZC5QQVJFTl9SKTpbXX1mdW5jdGlvbiBjKGUpe3ZhciB0PWUudG9rZW47cmV0dXJue2tpbmQ6by5LaW5kLlZBUklBQkxFX0RFRklOSVRJT04sdmFyaWFibGU6bChlKSx0eXBlOihRKGUsaC5Ub2tlbktpbmQuQ09MT04pLF8oZSkpLGRlZmF1bHRWYWx1ZTpXKGUsaC5Ub2tlbktpbmQuRVFVQUxTKT9DKGUsITApOnZvaWQgMCxsb2M6VihlLHQpfX1mdW5jdGlvbiBsKGUpe3ZhciB0PWUudG9rZW47cmV0dXJuIFEoZSxoLlRva2VuS2luZC5ET0xMQVIpLHtraW5kOm8uS2luZC5WQVJJQUJMRSxuYW1lOm4oZSksbG9jOlYoZSx0KX19ZnVuY3Rpb24gcChlKXt2YXIgdD1lLnRva2VuO3JldHVybntraW5kOm8uS2luZC5TRUxFQ1RJT05fU0VULHNlbGVjdGlvbnM6WShlLGguVG9rZW5LaW5kLkJSQUNFX0wsZCxoLlRva2VuS2luZC5CUkFDRV9SKSxsb2M6VihlLHQpfX1mdW5jdGlvbiBkKGUpe3JldHVybiBIKGUsaC5Ub2tlbktpbmQuU1BSRUFEKT9mdW5jdGlvbihlKXt2YXIgdD1lLnRva2VuO2lmKFEoZSxoLlRva2VuS2luZC5TUFJFQUQpLEgoZSxoLlRva2VuS2luZC5OQU1FKSYmIm9uIiE9PWUudG9rZW4udmFsdWUpcmV0dXJue2tpbmQ6by5LaW5kLkZSQUdNRU5UX1NQUkVBRCxuYW1lOngoZSksZGlyZWN0aXZlczprKGUsITEpLGxvYzpWKGUsdCl9O3ZhciBuPXZvaWQgMDtyZXR1cm4ib24iPT09ZS50b2tlbi52YWx1ZSYmKGUuYWR2YW5jZSgpLG49VChlKSkse2tpbmQ6by5LaW5kLklOTElORV9GUkFHTUVOVCx0eXBlQ29uZGl0aW9uOm4sZGlyZWN0aXZlczprKGUsITEpLHNlbGVjdGlvblNldDpwKGUpLGxvYzpWKGUsdCl9fShlKTpmdW5jdGlvbihlKXt2YXIgdD1lLnRva2VuLHI9bihlKSxpPXZvaWQgMCxhPXZvaWQgMDtyZXR1cm4gVyhlLGguVG9rZW5LaW5kLkNPTE9OKT8oaT1yLGE9bihlKSk6YT1yLHtraW5kOm8uS2luZC5GSUVMRCxhbGlhczppLG5hbWU6YSxhcmd1bWVudHM6eShlLCExKSxkaXJlY3RpdmVzOmsoZSwhMSksc2VsZWN0aW9uU2V0OkgoZSxoLlRva2VuS2luZC5CUkFDRV9MKT9wKGUpOnZvaWQgMCxsb2M6VihlLHQpfX0oZSl9ZnVuY3Rpb24geShlLHQpe3ZhciBuPXQ/Yjp2O3JldHVybiBIKGUsaC5Ub2tlbktpbmQuUEFSRU5fTCk/WShlLGguVG9rZW5LaW5kLlBBUkVOX0wsbixoLlRva2VuS2luZC5QQVJFTl9SKTpbXX1mdW5jdGlvbiB2KGUpe3ZhciB0PWUudG9rZW47cmV0dXJue2tpbmQ6by5LaW5kLkFSR1VNRU5ULG5hbWU6bihlKSx2YWx1ZTooUShlLGguVG9rZW5LaW5kLkNPTE9OKSxDKGUsITEpKSxsb2M6VihlLHQpfX1mdW5jdGlvbiBiKGUpe3ZhciB0PWUudG9rZW47cmV0dXJue2tpbmQ6by5LaW5kLkFSR1VNRU5ULG5hbWU6bihlKSx2YWx1ZTooUShlLGguVG9rZW5LaW5kLkNPTE9OKSxEKGUpKSxsb2M6VihlLHQpfX1mdW5jdGlvbiB4KGUpe2lmKCJvbiI9PT1lLnRva2VuLnZhbHVlKXRocm93IEooZSk7cmV0dXJuIG4oZSl9ZnVuY3Rpb24gQyhlLHQpe3ZhciBuPWUudG9rZW47c3dpdGNoKG4ua2luZCl7Y2FzZSBoLlRva2VuS2luZC5CUkFDS0VUX0w6cmV0dXJuIGZ1bmN0aW9uKGUsdCl7dmFyIG49ZS50b2tlbixyPXQ/RDp3O3JldHVybntraW5kOm8uS2luZC5MSVNULHZhbHVlczpmdW5jdGlvbihlLHQsbixyKXtRKGUsdCk7Zm9yKHZhciBpPVtdOyFXKGUscik7KWkucHVzaChuKGUpKTtyZXR1cm4gaX0oZSxoLlRva2VuS2luZC5CUkFDS0VUX0wscixoLlRva2VuS2luZC5CUkFDS0VUX1IpLGxvYzpWKGUsbil9fShlLHQpO2Nhc2UgaC5Ub2tlbktpbmQuQlJBQ0VfTDpyZXR1cm4gZnVuY3Rpb24oZSx0KXt2YXIgbj1lLnRva2VuO1EoZSxoLlRva2VuS2luZC5CUkFDRV9MKTtmb3IodmFyIHI9W107IVcoZSxoLlRva2VuS2luZC5CUkFDRV9SKTspci5wdXNoKFMoZSx0KSk7cmV0dXJue2tpbmQ6by5LaW5kLk9CSkVDVCxmaWVsZHM6cixsb2M6VihlLG4pfX0oZSx0KTtjYXNlIGguVG9rZW5LaW5kLklOVDpyZXR1cm4gZS5hZHZhbmNlKCkse2tpbmQ6by5LaW5kLklOVCx2YWx1ZTpuLnZhbHVlLGxvYzpWKGUsbil9O2Nhc2UgaC5Ub2tlbktpbmQuRkxPQVQ6cmV0dXJuIGUuYWR2YW5jZSgpLHtraW5kOm8uS2luZC5GTE9BVCx2YWx1ZTpuLnZhbHVlLGxvYzpWKGUsbil9O2Nhc2UgaC5Ub2tlbktpbmQuU1RSSU5HOmNhc2UgaC5Ub2tlbktpbmQuQkxPQ0tfU1RSSU5HOnJldHVybiBFKGUpO2Nhc2UgaC5Ub2tlbktpbmQuTkFNRTpyZXR1cm4idHJ1ZSI9PT1uLnZhbHVlfHwiZmFsc2UiPT09bi52YWx1ZT8oZS5hZHZhbmNlKCkse2tpbmQ6by5LaW5kLkJPT0xFQU4sdmFsdWU6InRydWUiPT09bi52YWx1ZSxsb2M6VihlLG4pfSk6Im51bGwiPT09bi52YWx1ZT8oZS5hZHZhbmNlKCkse2tpbmQ6by5LaW5kLk5VTEwsbG9jOlYoZSxuKX0pOihlLmFkdmFuY2UoKSx7a2luZDpvLktpbmQuRU5VTSx2YWx1ZTpuLnZhbHVlLGxvYzpWKGUsbil9KTtjYXNlIGguVG9rZW5LaW5kLkRPTExBUjppZighdClyZXR1cm4gbChlKX10aHJvdyBKKGUpfWZ1bmN0aW9uIEUoZSl7dmFyIHQ9ZS50b2tlbjtyZXR1cm4gZS5hZHZhbmNlKCkse2tpbmQ6by5LaW5kLlNUUklORyx2YWx1ZTp0LnZhbHVlLGJsb2NrOnQua2luZD09PWguVG9rZW5LaW5kLkJMT0NLX1NUUklORyxsb2M6VihlLHQpfX1mdW5jdGlvbiBEKGUpe3JldHVybiBDKGUsITApfWZ1bmN0aW9uIHcoZSl7cmV0dXJuIEMoZSwhMSl9ZnVuY3Rpb24gUyhlLHQpe3ZhciByPWUudG9rZW47cmV0dXJue2tpbmQ6by5LaW5kLk9CSkVDVF9GSUVMRCxuYW1lOm4oZSksdmFsdWU6KFEoZSxoLlRva2VuS2luZC5DT0xPTiksQyhlLHQpKSxsb2M6VihlLHIpfX1mdW5jdGlvbiBrKGUsdCl7Zm9yKHZhciBuPVtdO0goZSxoLlRva2VuS2luZC5BVCk7KW4ucHVzaChBKGUsdCkpO3JldHVybiBufWZ1bmN0aW9uIEEoZSx0KXt2YXIgcj1lLnRva2VuO3JldHVybiBRKGUsaC5Ub2tlbktpbmQuQVQpLHtraW5kOm8uS2luZC5ESVJFQ1RJVkUsbmFtZTpuKGUpLGFyZ3VtZW50czp5KGUsdCksbG9jOlYoZSxyKX19ZnVuY3Rpb24gXyhlKXt2YXIgdD1lLnRva2VuLG49dm9pZCAwO3JldHVybiBXKGUsaC5Ub2tlbktpbmQuQlJBQ0tFVF9MKT8obj1fKGUpLFEoZSxoLlRva2VuS2luZC5CUkFDS0VUX1IpLG49e2tpbmQ6by5LaW5kLkxJU1RfVFlQRSx0eXBlOm4sbG9jOlYoZSx0KX0pOm49VChlKSxXKGUsaC5Ub2tlbktpbmQuQkFORyk/e2tpbmQ6by5LaW5kLk5PTl9OVUxMX1RZUEUsdHlwZTpuLGxvYzpWKGUsdCl9Om59ZnVuY3Rpb24gVChlKXt2YXIgdD1lLnRva2VuO3JldHVybntraW5kOm8uS2luZC5OQU1FRF9UWVBFLG5hbWU6bihlKSxsb2M6VihlLHQpfX1mdW5jdGlvbiBPKGUpe3ZhciB0PUYoZSk/ZS5sb29rYWhlYWQoKTplLnRva2VuO2lmKHQua2luZD09PWguVG9rZW5LaW5kLk5BTUUpc3dpdGNoKHQudmFsdWUpe2Nhc2Uic2NoZW1hIjpyZXR1cm4gZnVuY3Rpb24oZSl7dmFyIHQ9ZS50b2tlbjtLKGUsInNjaGVtYSIpO3ZhciBuPWsoZSwhMCkscj1ZKGUsaC5Ub2tlbktpbmQuQlJBQ0VfTCxJLGguVG9rZW5LaW5kLkJSQUNFX1IpO3JldHVybntraW5kOm8uS2luZC5TQ0hFTUFfREVGSU5JVElPTixkaXJlY3RpdmVzOm4sb3BlcmF0aW9uVHlwZXM6cixsb2M6VihlLHQpfX0oZSk7Y2FzZSJzY2FsYXIiOnJldHVybiBmdW5jdGlvbihlKXt2YXIgdD1lLnRva2VuLHI9TihlKTtLKGUsInNjYWxhciIpO3ZhciBpPW4oZSksYT1rKGUsITApO3JldHVybntraW5kOm8uS2luZC5TQ0FMQVJfVFlQRV9ERUZJTklUSU9OLGRlc2NyaXB0aW9uOnIsbmFtZTppLGRpcmVjdGl2ZXM6YSxsb2M6VihlLHQpfX0oZSk7Y2FzZSJ0eXBlIjpyZXR1cm4gZnVuY3Rpb24oZSl7dmFyIHQ9ZS50b2tlbixyPU4oZSk7SyhlLCJ0eXBlIik7dmFyIGk9bihlKSxhPUwoZSkscz1rKGUsITApLHU9UChlKTtyZXR1cm57a2luZDpvLktpbmQuT0JKRUNUX1RZUEVfREVGSU5JVElPTixkZXNjcmlwdGlvbjpyLG5hbWU6aSxpbnRlcmZhY2VzOmEsZGlyZWN0aXZlczpzLGZpZWxkczp1LGxvYzpWKGUsdCl9fShlKTtjYXNlImludGVyZmFjZSI6cmV0dXJuIGZ1bmN0aW9uKGUpe3ZhciB0PWUudG9rZW4scj1OKGUpO0soZSwiaW50ZXJmYWNlIik7dmFyIGk9bihlKSxhPWsoZSwhMCkscz1QKGUpO3JldHVybntraW5kOm8uS2luZC5JTlRFUkZBQ0VfVFlQRV9ERUZJTklUSU9OLGRlc2NyaXB0aW9uOnIsbmFtZTppLGRpcmVjdGl2ZXM6YSxmaWVsZHM6cyxsb2M6VihlLHQpfX0oZSk7Y2FzZSJ1bmlvbiI6cmV0dXJuIGZ1bmN0aW9uKGUpe3ZhciB0PWUudG9rZW4scj1OKGUpO0soZSwidW5pb24iKTt2YXIgaT1uKGUpLGE9ayhlLCEwKSxzPUIoZSk7cmV0dXJue2tpbmQ6by5LaW5kLlVOSU9OX1RZUEVfREVGSU5JVElPTixkZXNjcmlwdGlvbjpyLG5hbWU6aSxkaXJlY3RpdmVzOmEsdHlwZXM6cyxsb2M6VihlLHQpfX0oZSk7Y2FzZSJlbnVtIjpyZXR1cm4gZnVuY3Rpb24oZSl7dmFyIHQ9ZS50b2tlbixyPU4oZSk7SyhlLCJlbnVtIik7dmFyIGk9bihlKSxhPWsoZSwhMCkscz0kKGUpO3JldHVybntraW5kOm8uS2luZC5FTlVNX1RZUEVfREVGSU5JVElPTixkZXNjcmlwdGlvbjpyLG5hbWU6aSxkaXJlY3RpdmVzOmEsdmFsdWVzOnMsbG9jOlYoZSx0KX19KGUpO2Nhc2UiaW5wdXQiOnJldHVybiBmdW5jdGlvbihlKXt2YXIgdD1lLnRva2VuLHI9TihlKTtLKGUsImlucHV0Iik7dmFyIGk9bihlKSxhPWsoZSwhMCkscz16KGUpO3JldHVybntraW5kOm8uS2luZC5JTlBVVF9PQkpFQ1RfVFlQRV9ERUZJTklUSU9OLGRlc2NyaXB0aW9uOnIsbmFtZTppLGRpcmVjdGl2ZXM6YSxmaWVsZHM6cyxsb2M6VihlLHQpfX0oZSk7Y2FzZSJleHRlbmQiOnJldHVybiBmdW5jdGlvbihlKXt2YXIgdD1lLmxvb2thaGVhZCgpO2lmKHQua2luZD09PWguVG9rZW5LaW5kLk5BTUUpc3dpdGNoKHQudmFsdWUpe2Nhc2Uic2NhbGFyIjpyZXR1cm4gZnVuY3Rpb24oZSl7dmFyIHQ9ZS50b2tlbjtLKGUsImV4dGVuZCIpLEsoZSwic2NhbGFyIik7dmFyIHI9bihlKSxpPWsoZSwhMCk7aWYoMD09PWkubGVuZ3RoKXRocm93IEooZSk7cmV0dXJue2tpbmQ6by5LaW5kLlNDQUxBUl9UWVBFX0VYVEVOU0lPTixuYW1lOnIsZGlyZWN0aXZlczppLGxvYzpWKGUsdCl9fShlKTtjYXNlInR5cGUiOnJldHVybiBmdW5jdGlvbihlKXt2YXIgdD1lLnRva2VuO0soZSwiZXh0ZW5kIiksSyhlLCJ0eXBlIik7dmFyIHI9bihlKSxpPUwoZSksYT1rKGUsITApLHM9UChlKTtpZigwPT09aS5sZW5ndGgmJjA9PT1hLmxlbmd0aCYmMD09PXMubGVuZ3RoKXRocm93IEooZSk7cmV0dXJue2tpbmQ6by5LaW5kLk9CSkVDVF9UWVBFX0VYVEVOU0lPTixuYW1lOnIsaW50ZXJmYWNlczppLGRpcmVjdGl2ZXM6YSxmaWVsZHM6cyxsb2M6VihlLHQpfX0oZSk7Y2FzZSJpbnRlcmZhY2UiOnJldHVybiBmdW5jdGlvbihlKXt2YXIgdD1lLnRva2VuO0soZSwiZXh0ZW5kIiksSyhlLCJpbnRlcmZhY2UiKTt2YXIgcj1uKGUpLGk9ayhlLCEwKSxhPVAoZSk7aWYoMD09PWkubGVuZ3RoJiYwPT09YS5sZW5ndGgpdGhyb3cgSihlKTtyZXR1cm57a2luZDpvLktpbmQuSU5URVJGQUNFX1RZUEVfRVhURU5TSU9OLG5hbWU6cixkaXJlY3RpdmVzOmksZmllbGRzOmEsbG9jOlYoZSx0KX19KGUpO2Nhc2UidW5pb24iOnJldHVybiBmdW5jdGlvbihlKXt2YXIgdD1lLnRva2VuO0soZSwiZXh0ZW5kIiksSyhlLCJ1bmlvbiIpO3ZhciByPW4oZSksaT1rKGUsITApLGE9QihlKTtpZigwPT09aS5sZW5ndGgmJjA9PT1hLmxlbmd0aCl0aHJvdyBKKGUpO3JldHVybntraW5kOm8uS2luZC5VTklPTl9UWVBFX0VYVEVOU0lPTixuYW1lOnIsZGlyZWN0aXZlczppLHR5cGVzOmEsbG9jOlYoZSx0KX19KGUpO2Nhc2UiZW51bSI6cmV0dXJuIGZ1bmN0aW9uKGUpe3ZhciB0PWUudG9rZW47SyhlLCJleHRlbmQiKSxLKGUsImVudW0iKTt2YXIgcj1uKGUpLGk9ayhlLCEwKSxhPSQoZSk7aWYoMD09PWkubGVuZ3RoJiYwPT09YS5sZW5ndGgpdGhyb3cgSihlKTtyZXR1cm57a2luZDpvLktpbmQuRU5VTV9UWVBFX0VYVEVOU0lPTixuYW1lOnIsZGlyZWN0aXZlczppLHZhbHVlczphLGxvYzpWKGUsdCl9fShlKTtjYXNlImlucHV0IjpyZXR1cm4gZnVuY3Rpb24oZSl7dmFyIHQ9ZS50b2tlbjtLKGUsImV4dGVuZCIpLEsoZSwiaW5wdXQiKTt2YXIgcj1uKGUpLGk9ayhlLCEwKSxhPXooZSk7aWYoMD09PWkubGVuZ3RoJiYwPT09YS5sZW5ndGgpdGhyb3cgSihlKTtyZXR1cm57a2luZDpvLktpbmQuSU5QVVRfT0JKRUNUX1RZUEVfRVhURU5TSU9OLG5hbWU6cixkaXJlY3RpdmVzOmksZmllbGRzOmEsbG9jOlYoZSx0KX19KGUpfXRocm93IEooZSx0KX0oZSk7Y2FzZSJkaXJlY3RpdmUiOnJldHVybiBmdW5jdGlvbihlKXt2YXIgdD1lLnRva2VuLHI9TihlKTtLKGUsImRpcmVjdGl2ZSIpLFEoZSxoLlRva2VuS2luZC5BVCk7dmFyIGk9bihlKSxhPWooZSk7SyhlLCJvbiIpO3ZhciBzPWZ1bmN0aW9uKGUpe1coZSxoLlRva2VuS2luZC5QSVBFKTt2YXIgdD1bXTtkb3t0LnB1c2goRyhlKSl9d2hpbGUoVyhlLGguVG9rZW5LaW5kLlBJUEUpKTtyZXR1cm4gdH0oZSk7cmV0dXJue2tpbmQ6by5LaW5kLkRJUkVDVElWRV9ERUZJTklUSU9OLGRlc2NyaXB0aW9uOnIsbmFtZTppLGFyZ3VtZW50czphLGxvY2F0aW9uczpzLGxvYzpWKGUsdCl9fShlKX10aHJvdyBKKGUsdCl9ZnVuY3Rpb24gRihlKXtyZXR1cm4gSChlLGguVG9rZW5LaW5kLlNUUklORyl8fEgoZSxoLlRva2VuS2luZC5CTE9DS19TVFJJTkcpfWZ1bmN0aW9uIE4oZSl7aWYoRihlKSlyZXR1cm4gRShlKX1mdW5jdGlvbiBJKGUpe3ZhciB0PWUudG9rZW4sbj1zKGUpO1EoZSxoLlRva2VuS2luZC5DT0xPTik7dmFyIHI9VChlKTtyZXR1cm57a2luZDpvLktpbmQuT1BFUkFUSU9OX1RZUEVfREVGSU5JVElPTixvcGVyYXRpb246bix0eXBlOnIsbG9jOlYoZSx0KX19ZnVuY3Rpb24gTChlKXt2YXIgdD1bXTtpZigiaW1wbGVtZW50cyI9PT1lLnRva2VuLnZhbHVlKXtlLmFkdmFuY2UoKSxXKGUsaC5Ub2tlbktpbmQuQU1QKTtkb3t0LnB1c2goVChlKSl9d2hpbGUoVyhlLGguVG9rZW5LaW5kLkFNUCl8fGUub3B0aW9ucy5hbGxvd0xlZ2FjeVNETEltcGxlbWVudHNJbnRlcmZhY2VzJiZIKGUsaC5Ub2tlbktpbmQuTkFNRSkpfXJldHVybiB0fWZ1bmN0aW9uIFAoZSl7cmV0dXJuIGUub3B0aW9ucy5hbGxvd0xlZ2FjeVNETEVtcHR5RmllbGRzJiZIKGUsaC5Ub2tlbktpbmQuQlJBQ0VfTCkmJmUubG9va2FoZWFkKCkua2luZD09PWguVG9rZW5LaW5kLkJSQUNFX1I/KGUuYWR2YW5jZSgpLGUuYWR2YW5jZSgpLFtdKTpIKGUsaC5Ub2tlbktpbmQuQlJBQ0VfTCk/WShlLGguVG9rZW5LaW5kLkJSQUNFX0wsTSxoLlRva2VuS2luZC5CUkFDRV9SKTpbXX1mdW5jdGlvbiBNKGUpe3ZhciB0PWUudG9rZW4scj1OKGUpLGk9bihlKSxhPWooZSk7UShlLGguVG9rZW5LaW5kLkNPTE9OKTt2YXIgcz1fKGUpLHU9ayhlLCEwKTtyZXR1cm57a2luZDpvLktpbmQuRklFTERfREVGSU5JVElPTixkZXNjcmlwdGlvbjpyLG5hbWU6aSxhcmd1bWVudHM6YSx0eXBlOnMsZGlyZWN0aXZlczp1LGxvYzpWKGUsdCl9fWZ1bmN0aW9uIGooZSl7cmV0dXJuIEgoZSxoLlRva2VuS2luZC5QQVJFTl9MKT9ZKGUsaC5Ub2tlbktpbmQuUEFSRU5fTCxSLGguVG9rZW5LaW5kLlBBUkVOX1IpOltdfWZ1bmN0aW9uIFIoZSl7dmFyIHQ9ZS50b2tlbixyPU4oZSksaT1uKGUpO1EoZSxoLlRva2VuS2luZC5DT0xPTik7dmFyIGE9XyhlKSxzPXZvaWQgMDtXKGUsaC5Ub2tlbktpbmQuRVFVQUxTKSYmKHM9RChlKSk7dmFyIHU9ayhlLCEwKTtyZXR1cm57a2luZDpvLktpbmQuSU5QVVRfVkFMVUVfREVGSU5JVElPTixkZXNjcmlwdGlvbjpyLG5hbWU6aSx0eXBlOmEsZGVmYXVsdFZhbHVlOnMsZGlyZWN0aXZlczp1LGxvYzpWKGUsdCl9fWZ1bmN0aW9uIEIoZSl7dmFyIHQ9W107aWYoVyhlLGguVG9rZW5LaW5kLkVRVUFMUykpe1coZSxoLlRva2VuS2luZC5QSVBFKTtkb3t0LnB1c2goVChlKSl9d2hpbGUoVyhlLGguVG9rZW5LaW5kLlBJUEUpKX1yZXR1cm4gdH1mdW5jdGlvbiAkKGUpe3JldHVybiBIKGUsaC5Ub2tlbktpbmQuQlJBQ0VfTCk/WShlLGguVG9rZW5LaW5kLkJSQUNFX0wsVSxoLlRva2VuS2luZC5CUkFDRV9SKTpbXX1mdW5jdGlvbiBVKGUpe3ZhciB0PWUudG9rZW4scj1OKGUpLGk9bihlKSxhPWsoZSwhMCk7cmV0dXJue2tpbmQ6by5LaW5kLkVOVU1fVkFMVUVfREVGSU5JVElPTixkZXNjcmlwdGlvbjpyLG5hbWU6aSxkaXJlY3RpdmVzOmEsbG9jOlYoZSx0KX19ZnVuY3Rpb24geihlKXtyZXR1cm4gSChlLGguVG9rZW5LaW5kLkJSQUNFX0wpP1koZSxoLlRva2VuS2luZC5CUkFDRV9MLFIsaC5Ub2tlbktpbmQuQlJBQ0VfUik6W119ZnVuY3Rpb24gRyhlKXt2YXIgdD1lLnRva2VuLHI9bihlKTtpZihnLkRpcmVjdGl2ZUxvY2F0aW9uLmhhc093blByb3BlcnR5KHIudmFsdWUpKXJldHVybiByO3Rocm93IEooZSx0KX1mdW5jdGlvbiBWKGUsdCl7aWYoIWUub3B0aW9ucy5ub0xvY2F0aW9uKXJldHVybiBuZXcgcSh0LGUubGFzdFRva2VuLGUuc291cmNlKX1mdW5jdGlvbiBxKGUsdCxuKXt0aGlzLnN0YXJ0PWUuc3RhcnQsdGhpcy5lbmQ9dC5lbmQsdGhpcy5zdGFydFRva2VuPWUsdGhpcy5lbmRUb2tlbj10LHRoaXMuc291cmNlPW59ZnVuY3Rpb24gSChlLHQpe3JldHVybiBlLnRva2VuLmtpbmQ9PT10fWZ1bmN0aW9uIFcoZSx0KXt2YXIgbj1lLnRva2VuLmtpbmQ9PT10O3JldHVybiBuJiZlLmFkdmFuY2UoKSxufWZ1bmN0aW9uIFEoZSx0KXt2YXIgbj1lLnRva2VuO2lmKG4ua2luZD09PXQpcmV0dXJuIGUuYWR2YW5jZSgpLG47dGhyb3coMCxmLnN5bnRheEVycm9yKShlLnNvdXJjZSxuLnN0YXJ0LCJFeHBlY3RlZCAiK3QrIiwgZm91bmQgIisoMCxoLmdldFRva2VuRGVzYykobikpfWZ1bmN0aW9uIEsoZSx0KXt2YXIgbj1lLnRva2VuO2lmKG4ua2luZD09PWguVG9rZW5LaW5kLk5BTUUmJm4udmFsdWU9PT10KXJldHVybiBlLmFkdmFuY2UoKSxuO3Rocm93KDAsZi5zeW50YXhFcnJvcikoZS5zb3VyY2Usbi5zdGFydCwnRXhwZWN0ZWQgIicrdCsnIiwgZm91bmQgJysoMCxoLmdldFRva2VuRGVzYykobikpfWZ1bmN0aW9uIEooZSx0KXt2YXIgbj10fHxlLnRva2VuO3JldHVybigwLGYuc3ludGF4RXJyb3IpKGUuc291cmNlLG4uc3RhcnQsIlVuZXhwZWN0ZWQgIisoMCxoLmdldFRva2VuRGVzYykobikpfWZ1bmN0aW9uIFkoZSx0LG4scil7UShlLHQpO2Zvcih2YXIgaT1bbihlKV07IVcoZSxyKTspaS5wdXNoKG4oZSkpO3JldHVybiBpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnBhcnNlPWZ1bmN0aW9uKGUsdCl7dmFyIG49InN0cmluZyI9PXR5cGVvZiBlP25ldyBtLlNvdXJjZShlKTplO2lmKCEobiBpbnN0YW5jZW9mIG0uU291cmNlKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJNdXN0IHByb3ZpZGUgU291cmNlLiBSZWNlaXZlZDogIitTdHJpbmcobikpO3JldHVybiBmdW5jdGlvbihlKXt2YXIgdD1lLnRva2VuO1EoZSxoLlRva2VuS2luZC5TT0YpO3ZhciBuPVtdO2Rve24ucHVzaChyKGUpKX13aGlsZSghVyhlLGguVG9rZW5LaW5kLkVPRikpO3JldHVybntraW5kOm8uS2luZC5ET0NVTUVOVCxkZWZpbml0aW9uczpuLGxvYzpWKGUsdCl9fSgoMCxoLmNyZWF0ZUxleGVyKShuLHR8fHt9KSl9LHQucGFyc2VWYWx1ZT1mdW5jdGlvbihlLHQpe3ZhciBuPSJzdHJpbmciPT10eXBlb2YgZT9uZXcgbS5Tb3VyY2UoZSk6ZSxyPSgwLGguY3JlYXRlTGV4ZXIpKG4sdHx8e30pO1EocixoLlRva2VuS2luZC5TT0YpO3ZhciBpPUMociwhMSk7cmV0dXJuIFEocixoLlRva2VuS2luZC5FT0YpLGl9LHQucGFyc2VUeXBlPWZ1bmN0aW9uKGUsdCl7dmFyIG49InN0cmluZyI9PXR5cGVvZiBlP25ldyBtLlNvdXJjZShlKTplLHI9KDAsaC5jcmVhdGVMZXhlcikobix0fHx7fSk7UShyLGguVG9rZW5LaW5kLlNPRik7dmFyIGk9XyhyKTtyZXR1cm4gUShyLGguVG9rZW5LaW5kLkVPRiksaX0sdC5wYXJzZUNvbnN0VmFsdWU9RCx0LnBhcnNlVHlwZVJlZmVyZW5jZT1fLHQucGFyc2VOYW1lZFR5cGU9VCxxLnByb3RvdHlwZS50b0pTT049cS5wcm90b3R5cGUuaW5zcGVjdD1mdW5jdGlvbigpe3JldHVybntzdGFydDp0aGlzLnN0YXJ0LGVuZDp0aGlzLmVuZH19fSk7dCh5KTt2YXIgdj1uKGZ1bmN0aW9uKGUsdCl7ZnVuY3Rpb24gbihlKXtyZXR1cm4gQm9vbGVhbihlJiYic3RyaW5nIj09dHlwZW9mIGUua2luZCl9ZnVuY3Rpb24gcihlLHQsbil7dmFyIHI9ZVt0XTtpZihyKXtpZighbiYmImZ1bmN0aW9uIj09dHlwZW9mIHIpcmV0dXJuIHI7dmFyIGk9bj9yLmxlYXZlOnIuZW50ZXI7aWYoImZ1bmN0aW9uIj09dHlwZW9mIGkpcmV0dXJuIGl9ZWxzZXt2YXIgbz1uP2UubGVhdmU6ZS5lbnRlcjtpZihvKXtpZigiZnVuY3Rpb24iPT10eXBlb2YgbylyZXR1cm4gbzt2YXIgYT1vW3RdO2lmKCJmdW5jdGlvbiI9PXR5cGVvZiBhKXJldHVybiBhfX19T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQudmlzaXQ9ZnVuY3Rpb24oZSx0KXt2YXIgYT1hcmd1bWVudHMubGVuZ3RoPjImJnZvaWQgMCE9PWFyZ3VtZW50c1syXT9hcmd1bWVudHNbMl06aSxzPXZvaWQgMCx1PUFycmF5LmlzQXJyYXkoZSksYz1bZV0sbD0tMSxwPVtdLGY9dm9pZCAwLGQ9dm9pZCAwLGg9dm9pZCAwLG09W10sZz1bXSx5PWU7ZG97dmFyIHY9KytsPT09Yy5sZW5ndGgsYj12JiYwIT09cC5sZW5ndGg7aWYodil7aWYoZD0wPT09Zy5sZW5ndGg/dm9pZCAwOm1bbS5sZW5ndGgtMV0sZj1oLGg9Zy5wb3AoKSxiKXtpZih1KWY9Zi5zbGljZSgpO2Vsc2V7dmFyIHg9e307Zm9yKHZhciBDIGluIGYpZi5oYXNPd25Qcm9wZXJ0eShDKSYmKHhbQ109ZltDXSk7Zj14fWZvcih2YXIgRT0wLEQ9MDtEPHAubGVuZ3RoO0QrKyl7dmFyIHc9cFtEXVswXSxTPXBbRF1bMV07dSYmKHctPUUpLHUmJm51bGw9PT1TPyhmLnNwbGljZSh3LDEpLEUrKyk6Zlt3XT1TfX1sPXMuaW5kZXgsYz1zLmtleXMscD1zLmVkaXRzLHU9cy5pbkFycmF5LHM9cy5wcmV2fWVsc2V7aWYoZD1oP3U/bDpjW2xdOnZvaWQgMCxudWxsPT09KGY9aD9oW2RdOnkpfHx2b2lkIDA9PT1mKWNvbnRpbnVlO2gmJm0ucHVzaChkKX12YXIgaz12b2lkIDA7aWYoIUFycmF5LmlzQXJyYXkoZikpe2lmKCFuKGYpKXRocm93IG5ldyBFcnJvcigiSW52YWxpZCBBU1QgTm9kZTogIitKU09OLnN0cmluZ2lmeShmKSk7dmFyIEE9cih0LGYua2luZCx2KTtpZihBKXtpZigoaz1BLmNhbGwodCxmLGQsaCxtLGcpKT09PW8pYnJlYWs7aWYoITE9PT1rKXtpZighdil7bS5wb3AoKTtjb250aW51ZX19ZWxzZSBpZih2b2lkIDAhPT1rJiYocC5wdXNoKFtkLGtdKSwhdikpe2lmKCFuKGspKXttLnBvcCgpO2NvbnRpbnVlfWY9a319fXZvaWQgMD09PWsmJmImJnAucHVzaChbZCxmXSksdj9tLnBvcCgpOihzPXtpbkFycmF5OnUsaW5kZXg6bCxrZXlzOmMsZWRpdHM6cCxwcmV2OnN9LHU9QXJyYXkuaXNBcnJheShmKSxjPXU/ZjphW2Yua2luZF18fFtdLGw9LTEscD1bXSxoJiZnLnB1c2goaCksaD1mKX13aGlsZSh2b2lkIDAhPT1zKTtyZXR1cm4gMCE9PXAubGVuZ3RoJiYoeT1wW3AubGVuZ3RoLTFdWzFdKSx5fSx0LnZpc2l0SW5QYXJhbGxlbD1mdW5jdGlvbihlKXt2YXIgdD1uZXcgQXJyYXkoZS5sZW5ndGgpO3JldHVybntlbnRlcjpmdW5jdGlvbihuKXtmb3IodmFyIGk9MDtpPGUubGVuZ3RoO2krKylpZighdFtpXSl7dmFyIGE9cihlW2ldLG4ua2luZCwhMSk7aWYoYSl7dmFyIHM9YS5hcHBseShlW2ldLGFyZ3VtZW50cyk7aWYoITE9PT1zKXRbaV09bjtlbHNlIGlmKHM9PT1vKXRbaV09bztlbHNlIGlmKHZvaWQgMCE9PXMpcmV0dXJuIHN9fX0sbGVhdmU6ZnVuY3Rpb24obil7Zm9yKHZhciBpPTA7aTxlLmxlbmd0aDtpKyspaWYodFtpXSl0W2ldPT09biYmKHRbaV09bnVsbCk7ZWxzZXt2YXIgYT1yKGVbaV0sbi5raW5kLCEwKTtpZihhKXt2YXIgcz1hLmFwcGx5KGVbaV0sYXJndW1lbnRzKTtpZihzPT09byl0W2ldPW87ZWxzZSBpZih2b2lkIDAhPT1zJiYhMSE9PXMpcmV0dXJuIHN9fX19fSx0LnZpc2l0V2l0aFR5cGVJbmZvPWZ1bmN0aW9uKGUsdCl7cmV0dXJue2VudGVyOmZ1bmN0aW9uKGkpe2UuZW50ZXIoaSk7dmFyIG89cih0LGkua2luZCwhMSk7aWYobyl7dmFyIGE9by5hcHBseSh0LGFyZ3VtZW50cyk7cmV0dXJuIHZvaWQgMCE9PWEmJihlLmxlYXZlKGkpLG4oYSkmJmUuZW50ZXIoYSkpLGF9fSxsZWF2ZTpmdW5jdGlvbihuKXt2YXIgaT1yKHQsbi5raW5kLCEwKSxvPXZvaWQgMDtyZXR1cm4gaSYmKG89aS5hcHBseSh0LGFyZ3VtZW50cykpLGUubGVhdmUobiksb319fSx0LmdldFZpc2l0Rm49cjt2YXIgaT10LlF1ZXJ5RG9jdW1lbnRLZXlzPXtOYW1lOltdLERvY3VtZW50OlsiZGVmaW5pdGlvbnMiXSxPcGVyYXRpb25EZWZpbml0aW9uOlsibmFtZSIsInZhcmlhYmxlRGVmaW5pdGlvbnMiLCJkaXJlY3RpdmVzIiwic2VsZWN0aW9uU2V0Il0sVmFyaWFibGVEZWZpbml0aW9uOlsidmFyaWFibGUiLCJ0eXBlIiwiZGVmYXVsdFZhbHVlIl0sVmFyaWFibGU6WyJuYW1lIl0sU2VsZWN0aW9uU2V0Olsic2VsZWN0aW9ucyJdLEZpZWxkOlsiYWxpYXMiLCJuYW1lIiwiYXJndW1lbnRzIiwiZGlyZWN0aXZlcyIsInNlbGVjdGlvblNldCJdLEFyZ3VtZW50OlsibmFtZSIsInZhbHVlIl0sRnJhZ21lbnRTcHJlYWQ6WyJuYW1lIiwiZGlyZWN0aXZlcyJdLElubGluZUZyYWdtZW50OlsidHlwZUNvbmRpdGlvbiIsImRpcmVjdGl2ZXMiLCJzZWxlY3Rpb25TZXQiXSxGcmFnbWVudERlZmluaXRpb246WyJuYW1lIiwidmFyaWFibGVEZWZpbml0aW9ucyIsInR5cGVDb25kaXRpb24iLCJkaXJlY3RpdmVzIiwic2VsZWN0aW9uU2V0Il0sSW50VmFsdWU6W10sRmxvYXRWYWx1ZTpbXSxTdHJpbmdWYWx1ZTpbXSxCb29sZWFuVmFsdWU6W10sTnVsbFZhbHVlOltdLEVudW1WYWx1ZTpbXSxMaXN0VmFsdWU6WyJ2YWx1ZXMiXSxPYmplY3RWYWx1ZTpbImZpZWxkcyJdLE9iamVjdEZpZWxkOlsibmFtZSIsInZhbHVlIl0sRGlyZWN0aXZlOlsibmFtZSIsImFyZ3VtZW50cyJdLE5hbWVkVHlwZTpbIm5hbWUiXSxMaXN0VHlwZTpbInR5cGUiXSxOb25OdWxsVHlwZTpbInR5cGUiXSxTY2hlbWFEZWZpbml0aW9uOlsiZGlyZWN0aXZlcyIsIm9wZXJhdGlvblR5cGVzIl0sT3BlcmF0aW9uVHlwZURlZmluaXRpb246WyJ0eXBlIl0sU2NhbGFyVHlwZURlZmluaXRpb246WyJkZXNjcmlwdGlvbiIsIm5hbWUiLCJkaXJlY3RpdmVzIl0sT2JqZWN0VHlwZURlZmluaXRpb246WyJkZXNjcmlwdGlvbiIsIm5hbWUiLCJpbnRlcmZhY2VzIiwiZGlyZWN0aXZlcyIsImZpZWxkcyJdLEZpZWxkRGVmaW5pdGlvbjpbImRlc2NyaXB0aW9uIiwibmFtZSIsImFyZ3VtZW50cyIsInR5cGUiLCJkaXJlY3RpdmVzIl0sSW5wdXRWYWx1ZURlZmluaXRpb246WyJkZXNjcmlwdGlvbiIsIm5hbWUiLCJ0eXBlIiwiZGVmYXVsdFZhbHVlIiwiZGlyZWN0aXZlcyJdLEludGVyZmFjZVR5cGVEZWZpbml0aW9uOlsiZGVzY3JpcHRpb24iLCJuYW1lIiwiZGlyZWN0aXZlcyIsImZpZWxkcyJdLFVuaW9uVHlwZURlZmluaXRpb246WyJkZXNjcmlwdGlvbiIsIm5hbWUiLCJkaXJlY3RpdmVzIiwidHlwZXMiXSxFbnVtVHlwZURlZmluaXRpb246WyJkZXNjcmlwdGlvbiIsIm5hbWUiLCJkaXJlY3RpdmVzIiwidmFsdWVzIl0sRW51bVZhbHVlRGVmaW5pdGlvbjpbImRlc2NyaXB0aW9uIiwibmFtZSIsImRpcmVjdGl2ZXMiXSxJbnB1dE9iamVjdFR5cGVEZWZpbml0aW9uOlsiZGVzY3JpcHRpb24iLCJuYW1lIiwiZGlyZWN0aXZlcyIsImZpZWxkcyJdLFNjYWxhclR5cGVFeHRlbnNpb246WyJuYW1lIiwiZGlyZWN0aXZlcyJdLE9iamVjdFR5cGVFeHRlbnNpb246WyJuYW1lIiwiaW50ZXJmYWNlcyIsImRpcmVjdGl2ZXMiLCJmaWVsZHMiXSxJbnRlcmZhY2VUeXBlRXh0ZW5zaW9uOlsibmFtZSIsImRpcmVjdGl2ZXMiLCJmaWVsZHMiXSxVbmlvblR5cGVFeHRlbnNpb246WyJuYW1lIiwiZGlyZWN0aXZlcyIsInR5cGVzIl0sRW51bVR5cGVFeHRlbnNpb246WyJuYW1lIiwiZGlyZWN0aXZlcyIsInZhbHVlcyJdLElucHV0T2JqZWN0VHlwZUV4dGVuc2lvbjpbIm5hbWUiLCJkaXJlY3RpdmVzIiwiZmllbGRzIl0sRGlyZWN0aXZlRGVmaW5pdGlvbjpbImRlc2NyaXB0aW9uIiwibmFtZSIsImFyZ3VtZW50cyIsImxvY2F0aW9ucyJdfSxvPXQuQlJFQUs9e319KTt0KHYpO3ZhciBiPW4oZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gcihbdC5kZXNjcmlwdGlvbixlKHQpXSwiXG4iKX19ZnVuY3Rpb24gcihlLHQpe3JldHVybiBlP2UuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBlfSkuam9pbih0fHwiIik6IiJ9ZnVuY3Rpb24gaShlKXtyZXR1cm4gZSYmMCE9PWUubGVuZ3RoPyJ7XG4iK2EocihlLCJcbiIpKSsiXG59IjoiIn1mdW5jdGlvbiBvKGUsdCxuKXtyZXR1cm4gdD9lK3QrKG58fCIiKToiIn1mdW5jdGlvbiBhKGUpe3JldHVybiBlJiYiICAiK2UucmVwbGFjZSgvXG4vZywiXG4gICIpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnByaW50PWZ1bmN0aW9uKGUpe3JldHVybigwLHYudmlzaXQpKGUse2xlYXZlOnN9KX07dmFyIHM9e05hbWU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUudmFsdWV9LFZhcmlhYmxlOmZ1bmN0aW9uKGUpe3JldHVybiIkIitlLm5hbWV9LERvY3VtZW50OmZ1bmN0aW9uKGUpe3JldHVybiByKGUuZGVmaW5pdGlvbnMsIlxuXG4iKSsiXG4ifSxPcGVyYXRpb25EZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3ZhciB0PWUub3BlcmF0aW9uLG49ZS5uYW1lLGk9bygiKCIscihlLnZhcmlhYmxlRGVmaW5pdGlvbnMsIiwgIiksIikiKSxhPXIoZS5kaXJlY3RpdmVzLCIgIikscz1lLnNlbGVjdGlvblNldDtyZXR1cm4gbnx8YXx8aXx8InF1ZXJ5IiE9PXQ/cihbdCxyKFtuLGldKSxhLHNdLCIgIik6c30sVmFyaWFibGVEZWZpbml0aW9uOmZ1bmN0aW9uKGUpe3JldHVybiBlLnZhcmlhYmxlKyI6ICIrZS50eXBlK28oIiA9ICIsZS5kZWZhdWx0VmFsdWUpfSxTZWxlY3Rpb25TZXQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGkoZS5zZWxlY3Rpb25zKX0sRmllbGQ6ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5hbGlhcyxuPWUubmFtZSxpPWUuYXJndW1lbnRzLGE9ZS5kaXJlY3RpdmVzLHM9ZS5zZWxlY3Rpb25TZXQ7cmV0dXJuIHIoW28oIiIsdCwiOiAiKStuK28oIigiLHIoaSwiLCAiKSwiKSIpLHIoYSwiICIpLHNdLCIgIil9LEFyZ3VtZW50OmZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWUrIjogIitlLnZhbHVlfSxGcmFnbWVudFNwcmVhZDpmdW5jdGlvbihlKXtyZXR1cm4iLi4uIitlLm5hbWUrbygiICIscihlLmRpcmVjdGl2ZXMsIiAiKSl9LElubGluZUZyYWdtZW50OmZ1bmN0aW9uKGUpe3ZhciB0PWUudHlwZUNvbmRpdGlvbixuPWUuZGlyZWN0aXZlcyxpPWUuc2VsZWN0aW9uU2V0O3JldHVybiByKFsiLi4uIixvKCJvbiAiLHQpLHIobiwiICIpLGldLCIgIil9LEZyYWdtZW50RGVmaW5pdGlvbjpmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLnR5cGVDb25kaXRpb24saT1lLnZhcmlhYmxlRGVmaW5pdGlvbnMsYT1lLmRpcmVjdGl2ZXMscz1lLnNlbGVjdGlvblNldDtyZXR1cm4iZnJhZ21lbnQgIit0K28oIigiLHIoaSwiLCAiKSwiKSIpKyIgb24gIituKyIgIitvKCIiLHIoYSwiICIpLCIgIikrc30sSW50VmFsdWU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUudmFsdWV9LEZsb2F0VmFsdWU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUudmFsdWV9LFN0cmluZ1ZhbHVlOmZ1bmN0aW9uKGUsdCl7dmFyIG49ZS52YWx1ZTtyZXR1cm4gZS5ibG9jaz9mdW5jdGlvbihlLHQpe3ZhciBuPWUucmVwbGFjZSgvIiIiL2csJ1xcIiIiJyk7cmV0dXJuIiAiIT09ZVswXSYmIlx0IiE9PWVbMF18fC0xIT09ZS5pbmRleE9mKCJcbiIpPyciIiJcbicrKHQ/bjphKG4pKSsnXG4iIiInOiciIiInK24ucmVwbGFjZSgvIiQvLCciXG4nKSsnIiIiJ30obiwiZGVzY3JpcHRpb24iPT09dCk6SlNPTi5zdHJpbmdpZnkobil9LEJvb2xlYW5WYWx1ZTpmdW5jdGlvbihlKXtyZXR1cm4gZS52YWx1ZT8idHJ1ZSI6ImZhbHNlIn0sTnVsbFZhbHVlOmZ1bmN0aW9uKCl7cmV0dXJuIm51bGwifSxFbnVtVmFsdWU6ZnVuY3Rpb24oZSl7cmV0dXJuIGUudmFsdWV9LExpc3RWYWx1ZTpmdW5jdGlvbihlKXtyZXR1cm4iWyIrcihlLnZhbHVlcywiLCAiKSsiXSJ9LE9iamVjdFZhbHVlOmZ1bmN0aW9uKGUpe3JldHVybiJ7IityKGUuZmllbGRzLCIsICIpKyJ9In0sT2JqZWN0RmllbGQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGUubmFtZSsiOiAiK2UudmFsdWV9LERpcmVjdGl2ZTpmdW5jdGlvbihlKXtyZXR1cm4iQCIrZS5uYW1lK28oIigiLHIoZS5hcmd1bWVudHMsIiwgIiksIikiKX0sTmFtZWRUeXBlOmZ1bmN0aW9uKGUpe3JldHVybiBlLm5hbWV9LExpc3RUeXBlOmZ1bmN0aW9uKGUpe3JldHVybiJbIitlLnR5cGUrIl0ifSxOb25OdWxsVHlwZTpmdW5jdGlvbihlKXtyZXR1cm4gZS50eXBlKyIhIn0sU2NoZW1hRGVmaW5pdGlvbjpmdW5jdGlvbihlKXt2YXIgdD1lLmRpcmVjdGl2ZXMsbj1lLm9wZXJhdGlvblR5cGVzO3JldHVybiByKFsic2NoZW1hIixyKHQsIiAiKSxpKG4pXSwiICIpfSxPcGVyYXRpb25UeXBlRGVmaW5pdGlvbjpmdW5jdGlvbihlKXtyZXR1cm4gZS5vcGVyYXRpb24rIjogIitlLnR5cGV9LFNjYWxhclR5cGVEZWZpbml0aW9uOm4oZnVuY3Rpb24oZSl7cmV0dXJuIHIoWyJzY2FsYXIiLGUubmFtZSxyKGUuZGlyZWN0aXZlcywiICIpXSwiICIpfSksT2JqZWN0VHlwZURlZmluaXRpb246bihmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLmludGVyZmFjZXMsYT1lLmRpcmVjdGl2ZXMscz1lLmZpZWxkcztyZXR1cm4gcihbInR5cGUiLHQsbygiaW1wbGVtZW50cyAiLHIobiwiICYgIikpLHIoYSwiICIpLGkocyldLCIgIil9KSxGaWVsZERlZmluaXRpb246bihmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLmFyZ3VtZW50cyxpPWUudHlwZSxhPWUuZGlyZWN0aXZlcztyZXR1cm4gdCtvKCIoIixyKG4sIiwgIiksIikiKSsiOiAiK2krbygiICIscihhLCIgIikpfSksSW5wdXRWYWx1ZURlZmluaXRpb246bihmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLnR5cGUsaT1lLmRlZmF1bHRWYWx1ZSxhPWUuZGlyZWN0aXZlcztyZXR1cm4gcihbdCsiOiAiK24sbygiPSAiLGkpLHIoYSwiICIpXSwiICIpfSksSW50ZXJmYWNlVHlwZURlZmluaXRpb246bihmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLmRpcmVjdGl2ZXMsbz1lLmZpZWxkcztyZXR1cm4gcihbImludGVyZmFjZSIsdCxyKG4sIiAiKSxpKG8pXSwiICIpfSksVW5pb25UeXBlRGVmaW5pdGlvbjpuKGZ1bmN0aW9uKGUpe3ZhciB0PWUubmFtZSxuPWUuZGlyZWN0aXZlcyxpPWUudHlwZXM7cmV0dXJuIHIoWyJ1bmlvbiIsdCxyKG4sIiAiKSxpJiYwIT09aS5sZW5ndGg/Ij0gIityKGksIiB8ICIpOiIiXSwiICIpfSksRW51bVR5cGVEZWZpbml0aW9uOm4oZnVuY3Rpb24oZSl7dmFyIHQ9ZS5uYW1lLG49ZS5kaXJlY3RpdmVzLG89ZS52YWx1ZXM7cmV0dXJuIHIoWyJlbnVtIix0LHIobiwiICIpLGkobyldLCIgIil9KSxFbnVtVmFsdWVEZWZpbml0aW9uOm4oZnVuY3Rpb24oZSl7cmV0dXJuIHIoW2UubmFtZSxyKGUuZGlyZWN0aXZlcywiICIpXSwiICIpfSksSW5wdXRPYmplY3RUeXBlRGVmaW5pdGlvbjpuKGZ1bmN0aW9uKGUpe3ZhciB0PWUubmFtZSxuPWUuZGlyZWN0aXZlcyxvPWUuZmllbGRzO3JldHVybiByKFsiaW5wdXQiLHQscihuLCIgIiksaShvKV0sIiAiKX0pLFNjYWxhclR5cGVFeHRlbnNpb246ZnVuY3Rpb24oZSl7cmV0dXJuIHIoWyJleHRlbmQgc2NhbGFyIixlLm5hbWUscihlLmRpcmVjdGl2ZXMsIiAiKV0sIiAiKX0sT2JqZWN0VHlwZUV4dGVuc2lvbjpmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLmludGVyZmFjZXMsYT1lLmRpcmVjdGl2ZXMscz1lLmZpZWxkcztyZXR1cm4gcihbImV4dGVuZCB0eXBlIix0LG8oImltcGxlbWVudHMgIixyKG4sIiAmICIpKSxyKGEsIiAiKSxpKHMpXSwiICIpfSxJbnRlcmZhY2VUeXBlRXh0ZW5zaW9uOmZ1bmN0aW9uKGUpe3ZhciB0PWUubmFtZSxuPWUuZGlyZWN0aXZlcyxvPWUuZmllbGRzO3JldHVybiByKFsiZXh0ZW5kIGludGVyZmFjZSIsdCxyKG4sIiAiKSxpKG8pXSwiICIpfSxVbmlvblR5cGVFeHRlbnNpb246ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5uYW1lLG49ZS5kaXJlY3RpdmVzLGk9ZS50eXBlcztyZXR1cm4gcihbImV4dGVuZCB1bmlvbiIsdCxyKG4sIiAiKSxpJiYwIT09aS5sZW5ndGg/Ij0gIityKGksIiB8ICIpOiIiXSwiICIpfSxFbnVtVHlwZUV4dGVuc2lvbjpmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLmRpcmVjdGl2ZXMsbz1lLnZhbHVlcztyZXR1cm4gcihbImV4dGVuZCBlbnVtIix0LHIobiwiICIpLGkobyldLCIgIil9LElucHV0T2JqZWN0VHlwZUV4dGVuc2lvbjpmdW5jdGlvbihlKXt2YXIgdD1lLm5hbWUsbj1lLmRpcmVjdGl2ZXMsbz1lLmZpZWxkcztyZXR1cm4gcihbImV4dGVuZCBpbnB1dCIsdCxyKG4sIiAiKSxpKG8pXSwiICIpfSxEaXJlY3RpdmVEZWZpbml0aW9uOm4oZnVuY3Rpb24oZSl7dmFyIHQ9ZS5uYW1lLG49ZS5hcmd1bWVudHMsaT1lLmxvY2F0aW9ucztyZXR1cm4iZGlyZWN0aXZlIEAiK3QrbygiKCIscihuLCIsICIpLCIpIikrIiBvbiAiK3IoaSwiIHwgIil9KX19KTt0KGIpO3ZhciB4PW4oZnVuY3Rpb24oZSx0KXtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsImdldExvY2F0aW9uIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gaS5nZXRMb2NhdGlvbn19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiS2luZCIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIG8uS2luZH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiY3JlYXRlTGV4ZXIiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBoLmNyZWF0ZUxleGVyfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJUb2tlbktpbmQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBoLlRva2VuS2luZH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwicGFyc2UiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB5LnBhcnNlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwYXJzZVZhbHVlIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4geS5wYXJzZVZhbHVlfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJwYXJzZVR5cGUiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB5LnBhcnNlVHlwZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwicHJpbnQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBiLnByaW50fX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJTb3VyY2UiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiBtLlNvdXJjZX19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidmlzaXQiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB2LnZpc2l0fX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJ2aXNpdEluUGFyYWxsZWwiLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB2LnZpc2l0SW5QYXJhbGxlbH19KSxPYmplY3QuZGVmaW5lUHJvcGVydHkodCwidmlzaXRXaXRoVHlwZUluZm8iLHtlbnVtZXJhYmxlOiEwLGdldDpmdW5jdGlvbigpe3JldHVybiB2LnZpc2l0V2l0aFR5cGVJbmZvfX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJnZXRWaXNpdEZuIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gdi5nZXRWaXNpdEZufX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJCUkVBSyIse2VudW1lcmFibGU6ITAsZ2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHYuQlJFQUt9fSksT2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIkRpcmVjdGl2ZUxvY2F0aW9uIix7ZW51bWVyYWJsZTohMCxnZXQ6ZnVuY3Rpb24oKXtyZXR1cm4gZy5EaXJlY3RpdmVMb2NhdGlvbn19KX0pO3JldHVybiB0KHgpLHtwYXJzZXJzOntncmFwaHFsOntwYXJzZTpmdW5jdGlvbih0KXt2YXIgbj14O3RyeXt2YXIgaT1mdW5jdGlvbihlLHQpe3RyeXtyZXR1cm4gZSh0LHthbGxvd0xlZ2FjeVNETEltcGxlbWVudHNJbnRlcmZhY2VzOiExfSl9Y2F0Y2gobil7cmV0dXJuIGUodCx7YWxsb3dMZWdhY3lTRExJbXBsZW1lbnRzSW50ZXJmYWNlczohMH0pfX0obi5wYXJzZSx0KTtyZXR1cm4gaS5jb21tZW50cz1mdW5jdGlvbihlKXtmb3IodmFyIHQ9W10sbj1lLmxvYy5zdGFydFRva2VuLm5leHQ7IjxFT0Y+IiE9PW4ua2luZDspIkNvbW1lbnQiPT09bi5raW5kJiYoT2JqZWN0LmFzc2lnbihuLHtjb2x1bW46bi5jb2x1bW4tMX0pLHQucHVzaChuKSksbj1uLm5leHQ7cmV0dXJuIHR9KGkpLGZ1bmN0aW9uIHQobil7aWYobiYmIm9iamVjdCI9PT1lKG4pKWZvcih2YXIgciBpbiBkZWxldGUgbi5zdGFydFRva2VuLGRlbGV0ZSBuLmVuZFRva2VuLGRlbGV0ZSBuLnByZXYsZGVsZXRlIG4ubmV4dCxuKXQobltyXSk7cmV0dXJuIG59KGkpLGl9Y2F0Y2goZSl7dGhyb3cgZSBpbnN0YW5jZW9mIGYuR3JhcGhRTEVycm9yP3IoZS5tZXNzYWdlLHtzdGFydDp7bGluZTplLmxvY2F0aW9uc1swXS5saW5lLGNvbHVtbjplLmxvY2F0aW9uc1swXS5jb2x1bW59fSk6ZX19LGFzdEZvcm1hdDoiZ3JhcGhxbCIsbG9jU3RhcnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlLnN0YXJ0P2Uuc3RhcnQ6ZS5sb2MmJmUubG9jLnN0YXJ0fSxsb2NFbmQ6ZnVuY3Rpb24oZSl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlLmVuZD9lLmVuZDplLmxvYyYmZS5sb2MuZW5kfX19fX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXt2YXIgZSx0LG4scixpLG8sYSxzLGE7cmV0dXJuIGQodGhpcyxmdW5jdGlvbih1KXtzd2l0Y2godS5sYWJlbCl7Y2FzZSAwOnJldHVybls0LG0uY2FsbChnLmRlbGF5LDEwMCldO2Nhc2UgMTpyZXR1cm4gdS5zZW50KCksWzQsbS5zZWxlY3QoeS5nZXRTZWxlY3RlZFNlc3Npb24pXTtjYXNlIDI6cmV0dXJuIGU9dS5zZW50KCksWzQsUy5zY2hlbWFGZXRjaGVyLmZldGNoKGUpXTtjYXNlIDM6dD11LnNlbnQoKS5zY2hlbWEsdS5sYWJlbD00O2Nhc2UgNDpyZXR1cm4gdS50cnlzLnB1c2goWzQsMTIsLDE0XSksKG49VC5wYXJzZShlLnF1ZXJ5KSxyPWIuZ2V0UXVlcnlGYWN0cyh0LG4pKT8oaT14LmZyb21KUyhyKSxvPXYuZGVmYXVsdChlLm9wZXJhdGlvbnMsZS5vcGVyYXRpb25OYW1lLGkub3BlcmF0aW9ucykseC5pcyhpLmdldCgidmFyaWFibGVUb1R5cGUiKSxlLnZhcmlhYmxlVG9UeXBlKT9bMyw2XTpbNCxtLnB1dChDLnNldFZhcmlhYmxlVG9UeXBlKGkuZ2V0KCJ2YXJpYWJsZVRvVHlwZSIpKSldKTpbMywxMF07Y2FzZSA1OnUuc2VudCgpLHUubGFiZWw9NjtjYXNlIDY6cmV0dXJuIHguaXMoaS5nZXQoIm9wZXJhdGlvbnMiKSxlLm9wZXJhdGlvbnMpP1szLDhdOls0LG0ucHV0KEMuc2V0T3BlcmF0aW9ucyhpLmdldCgib3BlcmF0aW9ucyIpKSldO2Nhc2UgNzp1LnNlbnQoKSx1LmxhYmVsPTg7Y2FzZSA4OnJldHVybiBvPT09ZS5vcGVyYXRpb25OYW1lP1szLDEwXTpbNCxtLnB1dChDLnNldE9wZXJhdGlvbk5hbWUobykpXTtjYXNlIDk6dS5zZW50KCksdS5sYWJlbD0xMDtjYXNlIDEwOnJldHVybiBhPV8uZ2V0UXVlcnlUeXBlcyhuKSxbNCxtLnB1dChDLnNldFF1ZXJ5VHlwZXMoYSkpXTtjYXNlIDExOnJldHVybiB1LnNlbnQoKSxbMywxNF07Y2FzZSAxMjpyZXR1cm4gcz11LnNlbnQoKSxhPV8uZ2V0UXVlcnlUeXBlcyhudWxsKSxbNCxtLnB1dChDLnNldFF1ZXJ5VHlwZXMoYSkpXTtjYXNlIDEzOnJldHVybiB1LnNlbnQoKSxbMywxNF07Y2FzZSAxNDpyZXR1cm5bMl19fSl9ZnVuY3Rpb24gaShlKXt2YXIgdCxuLHIsaT1lLnBheWxvYWQ7cmV0dXJuIGQodGhpcyxmdW5jdGlvbihlKXtzd2l0Y2goZS5sYWJlbCl7Y2FzZSAwOnJldHVybls0LG0uY2FsbChnLmRlbGF5LDEwMCldO2Nhc2UgMTpyZXR1cm4gZS5zZW50KCksbG9jYXRpb24uc2VhcmNoLmluY2x1ZGVzKCJxdWVyeSIpPyh0PUYucGFyc2UobG9jYXRpb24uc2VhcmNoKSwidW5kZWZpbmVkIiE9PXR5cGVvZiB0LnF1ZXJ5JiYobj1GLnN0cmluZ2lmeShmKHt9LHQse3F1ZXJ5OmkucXVlcnl9KSkscj0iIitsb2NhdGlvbi5vcmlnaW4rbG9jYXRpb24ucGF0aG5hbWUrIj8iK24sd2luZG93Lmhpc3RvcnkucmVwbGFjZVN0YXRlKHt9LGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJ0aXRsZSIpWzBdLmlubmVySFRNTCxyKSksWzJdKTpbMl19fSl9ZnVuY3Rpb24gbyhlKXt2YXIgdCxuLHIsaTtyZXR1cm4gZCh0aGlzLGZ1bmN0aW9uKG8pe3N3aXRjaChvLmxhYmVsKXtjYXNlIDA6cmV0dXJuIHQ9ZS5wYXlsb2FkLnBvc2l0aW9uLFs0LG0uc2VsZWN0KHkuZ2V0U2VsZWN0ZWRTZXNzaW9uKV07Y2FzZSAxOnJldHVybiBuPW8uc2VudCgpLG4ub3BlcmF0aW9ucz8oaT1uLm9wZXJhdGlvbnMudG9KUygpLGkuZm9yRWFjaChmdW5jdGlvbihlKXtlLmxvYyYmZS5sb2Muc3RhcnQ8PXQmJmUubG9jLmVuZD49dCYmKHI9ZS5uYW1lJiZlLm5hbWUudmFsdWUpfSkscj9bNCxtLnB1dChDLnJ1blF1ZXJ5KHIpKV06WzMsM10pOlszLDZdO2Nhc2UgMjpyZXR1cm4gby5zZW50KCksWzMsNV07Y2FzZSAzOnJldHVybls0LG0ucHV0KEMucnVuUXVlcnkoKSldO2Nhc2UgNDpvLnNlbnQoKSxvLmxhYmVsPTU7Y2FzZSA1OnJldHVyblszLDhdO2Nhc2UgNjpyZXR1cm5bNCxtLnB1dChDLnJ1blF1ZXJ5KCkpXTtjYXNlIDc6by5zZW50KCksby5sYWJlbD04O2Nhc2UgODpyZXR1cm5bMl19fSl9ZnVuY3Rpb24gYSgpe3ZhciBlLHQ7cmV0dXJuIGQodGhpcyxmdW5jdGlvbihuKXtzd2l0Y2gobi5sYWJlbCl7Y2FzZSAwOnJldHVybls0LG0uc2VsZWN0KHkuZ2V0U2VsZWN0ZWRTZXNzaW9uKV07Y2FzZSAxOnJldHVybiBlPW4uc2VudCgpLFs0LG0uc2VsZWN0KGsuZ2V0U2V0dGluZ3MpXTtjYXNlIDI6cmV0dXJuIHQ9bi5zZW50KCksWzIse2VuZHBvaW50OmUuZW5kcG9pbnQsaGVhZGVyczplLmhlYWRlcnMsY3JlZGVudGlhbHM6dFsicmVxdWVzdC5jcmVkZW50aWFscyJdfV19fSl9ZnVuY3Rpb24gcygpe3ZhciBlLHQsbixyLGk7cmV0dXJuIGQodGhpcyxmdW5jdGlvbihvKXtzd2l0Y2goby5sYWJlbCl7Y2FzZSAwOnJldHVybls0LGEoKV07Y2FzZSAxOmU9by5zZW50KCksby5sYWJlbD0yO2Nhc2UgMjpyZXR1cm4gby50cnlzLnB1c2goWzIsNiwsMTBdKSxbNCxTLnNjaGVtYUZldGNoZXIuZmV0Y2goZSldO2Nhc2UgMzpyZXR1cm4gby5zZW50KCksdD1tLnB1dCxuPUMuc2NoZW1hRmV0Y2hpbmdTdWNjZXNzLHI9W2UuZW5kcG9pbnQsbnVsbF0sWzQsbS5zZWxlY3QoeS5nZXRJc1BvbGxpbmdTY2hlbWEpXTtjYXNlIDQ6cmV0dXJuWzQsdC5hcHBseSh2b2lkIDAsW24uYXBwbHkodm9pZCAwLHIuY29uY2F0KFtvLnNlbnQoKV0pKV0pXTtjYXNlIDU6cmV0dXJuIG8uc2VudCgpLFszLDEwXTtjYXNlIDY6cmV0dXJuIGk9by5zZW50KCksWzQsbS5wdXQoQy5zY2hlbWFGZXRjaGluZ0Vycm9yKGUuZW5kcG9pbnQpKV07Y2FzZSA3OnJldHVybiBvLnNlbnQoKSxbNCxtLmNhbGwoZy5kZWxheSw1ZTMpXTtjYXNlIDg6cmV0dXJuIG8uc2VudCgpLFs0LG0ucHV0KEMuZmV0Y2hTY2hlbWEoKSldO2Nhc2UgOTpyZXR1cm4gby5zZW50KCksWzMsMTBdO2Nhc2UgMTA6cmV0dXJuWzJdfX0pfWZ1bmN0aW9uIHUoKXt2YXIgZSx0LG4scixpO3JldHVybiBkKHRoaXMsZnVuY3Rpb24obyl7c3dpdGNoKG8ubGFiZWwpe2Nhc2UgMDpyZXR1cm5bNCxhKCldO2Nhc2UgMTplPW8uc2VudCgpLG8ubGFiZWw9MjtjYXNlIDI6cmV0dXJuIG8udHJ5cy5wdXNoKFsyLDYsLDEwXSksWzQsUy5zY2hlbWFGZXRjaGVyLnJlZmV0Y2goZSldO2Nhc2UgMzpyZXR1cm4gby5zZW50KCksdD1tLnB1dCxuPUMuc2NoZW1hRmV0Y2hpbmdTdWNjZXNzLHI9W2UuZW5kcG9pbnQsbnVsbF0sWzQsbS5zZWxlY3QoeS5nZXRJc1BvbGxpbmdTY2hlbWEpXTtjYXNlIDQ6cmV0dXJuWzQsdC5hcHBseSh2b2lkIDAsW24uYXBwbHkodm9pZCAwLHIuY29uY2F0KFtvLnNlbnQoKV0pKV0pXTtjYXNlIDU6cmV0dXJuIG8uc2VudCgpLFszLDEwXTtjYXNlIDY6cmV0dXJuIGk9by5zZW50KCksWzQsbS5wdXQoQy5zY2hlbWFGZXRjaGluZ0Vycm9yKGUuZW5kcG9pbnQpKV07Y2FzZSA3OnJldHVybiBvLnNlbnQoKSxbNCxtLmNhbGwoZy5kZWxheSw1ZTMpXTtjYXNlIDg6cmV0dXJuIG8uc2VudCgpLFs0LG0ucHV0KEMucmVmZXRjaFNjaGVtYSgpKV07Y2FzZSA5OnJldHVybiBvLnNlbnQoKSxbMywxMF07Y2FzZSAxMDpyZXR1cm5bMl19fSl9ZnVuY3Rpb24gYygpe3ZhciBlLHQsbixyLGksbyxzLHU7cmV0dXJuIGQodGhpcyxmdW5jdGlvbihjKXtzd2l0Y2goYy5sYWJlbCl7Y2FzZSAwOnJldHVybls0LG0uc2VsZWN0KHkuZ2V0U2VsZWN0ZWRTZXNzaW9uKV07Y2FzZSAxOnJldHVybiBlPWMuc2VudCgpLFs0LGEoKV07Y2FzZSAyOnJldHVybiB0PWMuc2VudCgpLFs0LG0uc2VsZWN0KEEuZ2V0U2Vzc2lvbkRvY3NTdGF0ZSldO2Nhc2UgMzpyZXR1cm4gbj1jLnNlbnQoKSxbNCxTLnNjaGVtYUZldGNoZXIuZmV0Y2godCldO2Nhc2UgNDpyZXR1cm4gcj1jLnNlbnQoKSwoaT1yLnNjaGVtYSxvPXIudHJhY2luZ1N1cHBvcnRlZCwhaXx8aCYmaD09PWkpP1szLDddOihzPUUuZ2V0Um9vdE1hcChpKSx1PW4ubmF2U3RhY2subWFwKGZ1bmN0aW9uKGUpe3JldHVybiBFLmdldE5ld1N0YWNrKHMsaSxlKX0pLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gZX0pLFs0LG0ucHV0KEQuc2V0U3RhY2tzKGUuaWQsdSkpXSk7Y2FzZSA1OnJldHVybiBjLnNlbnQoKSxbNCxtLnB1dChDLnNldFRyYWNpbmdTdXBwb3J0ZWQobykpXTtjYXNlIDY6Yy5zZW50KCksaD1pLGMubGFiZWw9NztjYXNlIDc6cmV0dXJuWzJdfX0pfWZ1bmN0aW9uIGwoZSl7dmFyIHQsbixyLGksbyxhPWUucGF5bG9hZDtyZXR1cm4gZCh0aGlzLGZ1bmN0aW9uKGUpe3N3aXRjaChlLmxhYmVsKXtjYXNlIDA6cmV0dXJuIHQ9YS5zZXNzaW9uSWQsWzQsbS5zZWxlY3Qoay5nZXRTZWxlY3RlZFdvcmtzcGFjZSldO2Nhc2UgMTpyZXR1cm4gbj1lLnNlbnQoKSxyPW4uZ2V0SW4oWyJzZXNzaW9ucyIsdF0pLGk9bi5nZXQoImhpc3RvcnkiKSxvPWkudG9LZXllZFNlcSgpLmZpbmQoZnVuY3Rpb24oZSl7cmV0dXJuIHguaXMoZSxyKX0pLG8/WzMsM106WzQsbS5wdXQody5hZGRIaXN0b3J5SXRlbShyKSldO2Nhc2UgMjplLnNlbnQoKSxlLmxhYmVsPTM7Y2FzZSAzOnJldHVyblsyXX19KX1mdW5jdGlvbiBwKCl7dmFyIGUsdCxuLHI7cmV0dXJuIGQodGhpcyxmdW5jdGlvbihpKXtzd2l0Y2goaS5sYWJlbCl7Y2FzZSAwOnJldHVybls0LG0uc2VsZWN0KHkuZ2V0U2VsZWN0ZWRTZXNzaW9uKV07Y2FzZSAxOnJldHVybiBlPWkuc2VudCgpLnF1ZXJ5LFs0LG0uc2VsZWN0KGsuZ2V0U2V0dGluZ3MpXTtjYXNlIDI6dD1pLnNlbnQoKSxpLmxhYmVsPTM7Y2FzZSAzOnJldHVybiBpLnRyeXMucHVzaChbMyw1LCw2XSksbj1PLnByZXR0aWZ5KGUse3ByaW50V2lkdGg6dFsicHJldHRpZXIucHJpbnRXaWR0aCJdLHRhYldpZHRoOnRbInByZXR0aWVyLnRhYldpZHRoIl0sdXNlVGFiczp0WyJwcmV0dGllci51c2VUYWJzIl19KSxbNCxtLnB1dChDLmVkaXRRdWVyeShuKSldO2Nhc2UgNDpyZXR1cm4gaS5zZW50KCksWzMsNl07Y2FzZSA1OnJldHVybiByPWkuc2VudCgpLGNvbnNvbGUubG9nKHIpLFszLDZdO2Nhc2UgNjpyZXR1cm5bMl19fSl9dmFyIGY9ZnVuY3Rpb24oKXtyZXR1cm4gZj1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQsbj0xLHI9YXJndW1lbnRzLmxlbmd0aDtuPHI7bisrKXt0PWFyZ3VtZW50c1tuXTtmb3IodmFyIGkgaW4gdClPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxpKSYmKGVbaV09dFtpXSl9cmV0dXJuIGV9LGYuYXBwbHkodGhpcyxhcmd1bWVudHMpfSxkPWZ1bmN0aW9uKGUsdCl7ZnVuY3Rpb24gbihlKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIHIoW2UsdF0pfX1mdW5jdGlvbiByKG4pe2lmKGkpdGhyb3cgbmV3IFR5cGVFcnJvcigiR2VuZXJhdG9yIGlzIGFscmVhZHkgZXhlY3V0aW5nLiIpO2Zvcig7dTspdHJ5e2lmKGk9MSxvJiYoYT0yJm5bMF0/by5yZXR1cm46blswXT9vLnRocm93fHwoKGE9by5yZXR1cm4pJiZhLmNhbGwobyksMCk6by5uZXh0KSYmIShhPWEuY2FsbChvLG5bMV0pKS5kb25lKXJldHVybiBhO3N3aXRjaChvPTAsYSYmKG49WzImblswXSxhLnZhbHVlXSksblswXSl7Y2FzZSAwOmNhc2UgMTphPW47YnJlYWs7Y2FzZSA0OnJldHVybiB1LmxhYmVsKysse3ZhbHVlOm5bMV0sZG9uZTohMX07Y2FzZSA1OnUubGFiZWwrKyxvPW5bMV0sbj1bMF07Y29udGludWU7Y2FzZSA3Om49dS5vcHMucG9wKCksdS50cnlzLnBvcCgpO2NvbnRpbnVlO2RlZmF1bHQ6aWYoYT11LnRyeXMsIShhPWEubGVuZ3RoPjAmJmFbYS5sZW5ndGgtMV0pJiYoNj09PW5bMF18fDI9PT1uWzBdKSl7dT0wO2NvbnRpbnVlfWlmKDM9PT1uWzBdJiYoIWF8fG5bMV0+YVswXSYmblsxXTxhWzNdKSl7dS5sYWJlbD1uWzFdO2JyZWFrfWlmKDY9PT1uWzBdJiZ1LmxhYmVsPGFbMV0pe3UubGFiZWw9YVsxXSxhPW47YnJlYWt9aWYoYSYmdS5sYWJlbDxhWzJdKXt1LmxhYmVsPWFbMl0sdS5vcHMucHVzaChuKTticmVha31hWzJdJiZ1Lm9wcy5wb3AoKSx1LnRyeXMucG9wKCk7Y29udGludWV9bj10LmNhbGwoZSx1KX1jYXRjaChlKXtuPVs2LGVdLG89MH1maW5hbGx5e2k9YT0wfWlmKDUmblswXSl0aHJvdyBuWzFdO3JldHVybnt2YWx1ZTpuWzBdP25bMV06dm9pZCAwLGRvbmU6ITB9fXZhciBpLG8sYSxzLHU9e2xhYmVsOjAsc2VudDpmdW5jdGlvbigpe2lmKDEmYVswXSl0aHJvdyBhWzFdO3JldHVybiBhWzFdfSx0cnlzOltdLG9wczpbXX07cmV0dXJuIHM9e25leHQ6bigwKSx0aHJvdzpuKDEpLHJldHVybjpuKDIpfSwiZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmKHNbU3ltYm9sLml0ZXJhdG9yXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSksc307T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBoLG09big1NSksZz1uKDEwNCkseT1uKDEyKSx2PW4oNTExKSxiPW4oNTEyKSx4PW4oMTQpLEM9bigxNiksRT1uKDY2KSxEPW4oNjcpLHc9bigxMzEpLFM9big3Nyksaz1uKDE3KSxBPW4oNjgpLF89bigyNDUpLFQ9big3KSxPPW4oNjUpLEY9big1MTMpO3Quc2Vzc2lvbnNTYWdhcz1bbS50YWtlTGF0ZXN0KCJHRVRfUVVFUllfRkFDVFMiLE8uc2FmZWx5KHIpKSxtLnRha2VMYXRlc3QoIlNFVF9PUEVSQVRJT05fTkFNRSIsTy5zYWZlbHkocikpLG0udGFrZUV2ZXJ5KCJFRElUX1FVRVJZIixPLnNhZmVseShyKSksbS50YWtlRXZlcnkoIkVESVRfUVVFUlkiLE8uc2FmZWx5KGkpKSxtLnRha2VFdmVyeSgiUlVOX1FVRVJZX0FUX1BPU0lUSU9OIixPLnNhZmVseShvKSksbS50YWtlTGF0ZXN0KCJGRVRDSF9TQ0hFTUEiLE8uc2FmZWx5KHMpKSxtLnRha2VMYXRlc3QoIlJFRkVUQ0hfU0NIRU1BIixPLnNhZmVseSh1KSksbS50YWtlTGF0ZXN0KCJTQ0hFTUFfRkVUQ0hJTkdfU1VDQ0VTUyIsTy5zYWZlbHkoYykpLG0udGFrZUV2ZXJ5KCJRVUVSWV9TVUNDRVNTIixPLnNhZmVseShsKSksbS50YWtlTGF0ZXN0KCJQUkVUVElGWV9RVUVSWSIsTy5zYWZlbHkocCkpXX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXtpZihuJiYhKG4ubGVuZ3RoPDEpKXt2YXIgcj1uLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lJiZlLm5hbWUudmFsdWV9KTtpZih0JiYtMSE9PXIuaW5kZXhPZih0KSlyZXR1cm4gdDtpZih0JiZlKXt2YXIgaT1lLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS5uYW1lJiZlLm5hbWUudmFsdWV9KSxvPWkuaW5kZXhPZih0KTtpZigtMSE9PW8mJm88ci5sZW5ndGgpcmV0dXJuIHJbb119cmV0dXJuIHJbMF19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmRlZmF1bHQ9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dmFyIG49ZT9pKGUsdCk6bnVsbCxyPVtdO3JldHVybiB0LmRlZmluaXRpb25zLmZvckVhY2goZnVuY3Rpb24oZSl7Ik9wZXJhdGlvbkRlZmluaXRpb24iPT09ZS5raW5kJiZyLnB1c2goZSl9KSx7dmFyaWFibGVUb1R5cGU6bixvcGVyYXRpb25zOnJ9fWZ1bmN0aW9uIGkoZSx0KXt2YXIgbj1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybiB0LmRlZmluaXRpb25zLmZvckVhY2goZnVuY3Rpb24odCl7aWYoIk9wZXJhdGlvbkRlZmluaXRpb24iPT09dC5raW5kKXt2YXIgcj10LnZhcmlhYmxlRGVmaW5pdGlvbnM7ciYmci5mb3JFYWNoKGZ1bmN0aW9uKHQpe3ZhciByPXQudmFyaWFibGUsaT10LnR5cGUsYT1vLnR5cGVGcm9tQVNUKGUsaSk7YSYmKG5bci5uYW1lLnZhbHVlXT1hKX0pfX0pLG59T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPW4oNyk7dC5nZXRRdWVyeUZhY3RzPXIsdC5jb2xsZWN0VmFyaWFibGVzPWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtzd2l0Y2goZS5hcnJheUZvcm1hdCl7Y2FzZSJpbmRleCI6cmV0dXJuIGZ1bmN0aW9uKHQsbixyKXtyZXR1cm4gbnVsbD09PW4/W28odCxlKSwiWyIsciwiXSJdLmpvaW4oIiIpOltvKHQsZSksIlsiLG8ocixlKSwiXT0iLG8obixlKV0uam9pbigiIil9O2Nhc2UiYnJhY2tldCI6cmV0dXJuIGZ1bmN0aW9uKHQsbil7cmV0dXJuIG51bGw9PT1uP28odCxlKTpbbyh0LGUpLCJbXT0iLG8obixlKV0uam9pbigiIil9O2RlZmF1bHQ6cmV0dXJuIGZ1bmN0aW9uKHQsbil7cmV0dXJuIG51bGw9PT1uP28odCxlKTpbbyh0LGUpLCI9IixvKG4sZSldLmpvaW4oIiIpfX19ZnVuY3Rpb24gaShlKXt2YXIgdDtzd2l0Y2goZS5hcnJheUZvcm1hdCl7Y2FzZSJpbmRleCI6cmV0dXJuIGZ1bmN0aW9uKGUsbixyKXtpZih0PS9cWyhcZCopXF0kLy5leGVjKGUpLGU9ZS5yZXBsYWNlKC9cW1xkKlxdJC8sIiIpLCF0KXJldHVybiB2b2lkKHJbZV09bik7dm9pZCAwPT09cltlXSYmKHJbZV09e30pLHJbZV1bdFsxXV09bn07Y2FzZSJicmFja2V0IjpyZXR1cm4gZnVuY3Rpb24oZSxuLHIpe3JldHVybiB0PS8oXFtcXSkkLy5leGVjKGUpLGU9ZS5yZXBsYWNlKC9cW1xdJC8sIiIpLHQ/dm9pZCAwPT09cltlXT92b2lkKHJbZV09W25dKTp2b2lkKHJbZV09W10uY29uY2F0KHJbZV0sbikpOnZvaWQocltlXT1uKX07ZGVmYXVsdDpyZXR1cm4gZnVuY3Rpb24oZSx0LG4pe2lmKHZvaWQgMD09PW5bZV0pcmV0dXJuIHZvaWQobltlXT10KTtuW2VdPVtdLmNvbmNhdChuW2VdLHQpfX19ZnVuY3Rpb24gbyhlLHQpe3JldHVybiB0LmVuY29kZT90LnN0cmljdD9jKGUpOmVuY29kZVVSSUNvbXBvbmVudChlKTplfWZ1bmN0aW9uIGEoZSl7cmV0dXJuIEFycmF5LmlzQXJyYXkoZSk/ZS5zb3J0KCk6Im9iamVjdCI9PT10eXBlb2YgZT9hKE9iamVjdC5rZXlzKGUpKS5zb3J0KGZ1bmN0aW9uKGUsdCl7cmV0dXJuIE51bWJlcihlKS1OdW1iZXIodCl9KS5tYXAoZnVuY3Rpb24odCl7cmV0dXJuIGVbdF19KTplfWZ1bmN0aW9uIHMoZSl7dmFyIHQ9ZS5pbmRleE9mKCI/Iik7cmV0dXJuLTE9PT10PyIiOmUuc2xpY2UodCsxKX1mdW5jdGlvbiB1KGUsdCl7dD1sKHthcnJheUZvcm1hdDoibm9uZSJ9LHQpO3ZhciBuPWkodCkscj1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybiJzdHJpbmciIT09dHlwZW9mIGU/cjooZT1lLnRyaW0oKS5yZXBsYWNlKC9eWz8jJl0vLCIiKSk/KGUuc3BsaXQoIiYiKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWUucmVwbGFjZSgvXCsvZywiICIpLnNwbGl0KCI9IiksaT10LnNoaWZ0KCksbz10Lmxlbmd0aD4wP3Quam9pbigiPSIpOnZvaWQgMDtvPXZvaWQgMD09PW8/bnVsbDpwKG8pLG4ocChpKSxvLHIpfSksT2JqZWN0LmtleXMocikuc29ydCgpLnJlZHVjZShmdW5jdGlvbihlLHQpe3ZhciBuPXJbdF07cmV0dXJuIEJvb2xlYW4obikmJiJvYmplY3QiPT09dHlwZW9mIG4mJiFBcnJheS5pc0FycmF5KG4pP2VbdF09YShuKTplW3RdPW4sZX0sT2JqZWN0LmNyZWF0ZShudWxsKSkpOnJ9dmFyIGM9big1MTQpLGw9big1NCkscD1uKDUxNSk7dC5leHRyYWN0PXMsdC5wYXJzZT11LHQuc3RyaW5naWZ5PWZ1bmN0aW9uKGUsdCl7dD1sKHtlbmNvZGU6ITAsc3RyaWN0OiEwLGFycmF5Rm9ybWF0OiJub25lIn0sdCksITE9PT10LnNvcnQmJih0LnNvcnQ9ZnVuY3Rpb24oKXt9KTt2YXIgbj1yKHQpO3JldHVybiBlP09iamVjdC5rZXlzKGUpLnNvcnQodC5zb3J0KS5tYXAoZnVuY3Rpb24ocil7dmFyIGk9ZVtyXTtpZih2b2lkIDA9PT1pKXJldHVybiIiO2lmKG51bGw9PT1pKXJldHVybiBvKHIsdCk7aWYoQXJyYXkuaXNBcnJheShpKSl7dmFyIGE9W107cmV0dXJuIGkuc2xpY2UoKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZvaWQgMCE9PWUmJmEucHVzaChuKHIsZSxhLmxlbmd0aCkpfSksYS5qb2luKCImIil9cmV0dXJuIG8ocix0KSsiPSIrbyhpLHQpfSkuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBlLmxlbmd0aD4wfSkuam9pbigiJiIpOiIifSx0LnBhcnNlVXJsPWZ1bmN0aW9uKGUsdCl7cmV0dXJue3VybDplLnNwbGl0KCI/IilbMF18fCIiLHF1ZXJ5OnUocyhlKSx0KX19fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlKXtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KGUpLnJlcGxhY2UoL1shJygpKl0vZyxmdW5jdGlvbihlKXtyZXR1cm4iJSIrZS5jaGFyQ29kZUF0KDApLnRvU3RyaW5nKDE2KS50b1VwcGVyQ2FzZSgpfSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt0cnl7cmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudChlLmpvaW4oIiIpKX1jYXRjaChlKXt9aWYoMT09PWUubGVuZ3RoKXJldHVybiBlO3Q9dHx8MTt2YXIgbj1lLnNsaWNlKDAsdCksaT1lLnNsaWNlKHQpO3JldHVybiBBcnJheS5wcm90b3R5cGUuY29uY2F0LmNhbGwoW10scihuKSxyKGkpKX1mdW5jdGlvbiBpKGUpe3RyeXtyZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KGUpfWNhdGNoKGkpe2Zvcih2YXIgdD1lLm1hdGNoKGEpLG49MTtuPHQubGVuZ3RoO24rKyllPXIodCxuKS5qb2luKCIiKSx0PWUubWF0Y2goYSk7cmV0dXJuIGV9fWZ1bmN0aW9uIG8oZSl7Zm9yKHZhciB0PXsiJUZFJUZGIjoiXHVmZmZkXHVmZmZkIiwiJUZGJUZFIjoiXHVmZmZkXHVmZmZkIn0sbj1zLmV4ZWMoZSk7bjspe3RyeXt0W25bMF1dPWRlY29kZVVSSUNvbXBvbmVudChuWzBdKX1jYXRjaChlKXt2YXIgcj1pKG5bMF0pO3IhPT1uWzBdJiYodFtuWzBdXT1yKX1uPXMuZXhlYyhlKX10WyIlQzIiXT0iXHVmZmZkIjtmb3IodmFyIG89T2JqZWN0LmtleXModCksYT0wO2E8by5sZW5ndGg7YSsrKXt2YXIgdT1vW2FdO2U9ZS5yZXBsYWNlKG5ldyBSZWdFeHAodSwiZyIpLHRbdV0pfXJldHVybiBlfXZhciBhPW5ldyBSZWdFeHAoIiVbYS1mMC05XXsyfSIsImdpIikscz1uZXcgUmVnRXhwKCIoJVthLWYwLTldezJ9KSsiLCJnaSIpO2UuZXhwb3J0cz1mdW5jdGlvbihlKXtpZigic3RyaW5nIiE9PXR5cGVvZiBlKXRocm93IG5ldyBUeXBlRXJyb3IoIkV4cGVjdGVkIGBlbmNvZGVkVVJJYCB0byBiZSBvZiB0eXBlIGBzdHJpbmdgLCBnb3QgYCIrdHlwZW9mIGUrImAiKTt0cnl7cmV0dXJuIGU9ZS5yZXBsYWNlKC9cKy9nLCIgIiksZGVjb2RlVVJJQ29tcG9uZW50KGUpfWNhdGNoKHQpe3JldHVybiBvKGUpfX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3ZhciBlLHQsbixyO3JldHVybiBvKHRoaXMsZnVuY3Rpb24obyl7c3dpdGNoKG8ubGFiZWwpe2Nhc2UgMDpyZXR1cm5bNCxpKCldO2Nhc2UgMTpyZXR1cm4gZT1vLnNlbnQoKSxbNCxhLnNlbGVjdChzLmdldEVuZHBvaW50KV07Y2FzZSAyOnJldHVybiB0PW8uc2VudCgpLFs0LGZldGNoKCJodHRwczovL2FwaS5ncmFwaHFsYmluLmNvbS8iLHttZXRob2Q6InBvc3QiLGhlYWRlcnM6eyJDb250ZW50LVR5cGUiOiJhcHBsaWNhdGlvbi9qc29uIn0sYm9keTpKU09OLnN0cmluZ2lmeSh7cXVlcnk6IlxuICAgICAgICBtdXRhdGlvbiAoJHNlc3Npb246IFN0cmluZyEgJGVuZHBvaW50OiBTdHJpbmchKSB7XG4gICAgICAgICAgYWRkU2Vzc2lvbihzZXNzaW9uOiAkc2Vzc2lvbiBlbmRwb2ludDogJGVuZHBvaW50KSB7XG4gICAgICAgICAgICBpZFxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgIix2YXJpYWJsZXM6e3Nlc3Npb246SlNPTi5zdHJpbmdpZnkoZSksZW5kcG9pbnQ6dH19KX0pLnRoZW4oZnVuY3Rpb24oZSl7cmV0dXJuIGUuanNvbigpfSldO2Nhc2UgMzpyZXR1cm4gbj1vLnNlbnQoKSxyPSJodHRwczovL2dyYXBocWxiaW4uY29tL3YyLyIrbi5kYXRhLmFkZFNlc3Npb24uaWQsWzQsYS5wdXQodS5zZXRTaGFyZVVybChyKSldO2Nhc2UgNDpyZXR1cm4gby5zZW50KCksWzJdfX0pfWZ1bmN0aW9uIGkoKXt2YXIgZSx0LG4scjtyZXR1cm4gbyh0aGlzLGZ1bmN0aW9uKGkpe3N3aXRjaChpLmxhYmVsKXtjYXNlIDA6cmV0dXJuWzQsYS5zZWxlY3QoKV07Y2FzZSAxOnJldHVybiBlPWkuc2VudCgpLFs0LGEuc2VsZWN0KGwuZ2V0U2hhcmluZ1N0YXRlKV07Y2FzZSAyOnJldHVybiB0PWkuc2VudCgpLG49YygpLGU9ZS51cGRhdGUoIndvcmtzcGFjZXMiLGZ1bmN0aW9uKHQpe3JldHVybiB0LmZpbHRlcihmdW5jdGlvbih0LG4pe3JldHVybiBuPT09ZS5zZWxlY3RlZFdvcmtzcGFjZX0pfSkuc2V0KCJzZWxlY3RlZFdvcmtzcGFjZSIsbisifiIrZS5zZWxlY3RlZFdvcmtzcGFjZSkudXBkYXRlKCJ3b3Jrc3BhY2VzIixmdW5jdGlvbihlKXtyZXR1cm4gZS5tYXBLZXlzKGZ1bmN0aW9uKGUpe3JldHVybiBuKyJ+IitlfSl9KSxyPWUud29ya3NwYWNlcy5nZXQoZS5zZWxlY3RlZFdvcmtzcGFjZSkuc2Vzc2lvbnMuc2VsZWN0ZWRTZXNzaW9uSWQsdC5hbGxUYWJzfHwoZT1lLnVwZGF0ZUluKFsid29ya3NwYWNlcyIsZS5zZWxlY3RlZFdvcmtzcGFjZSwic2Vzc2lvbnMiLCJzZXNzaW9ucyJdLGZ1bmN0aW9uKGUpe3JldHVybiBlLmZpbHRlcihmdW5jdGlvbihlLHQpe3JldHVybiB0PT09cn0pfSkuc2V0SW4oWyJ3b3Jrc3BhY2VzIixlLnNlbGVjdGVkV29ya3NwYWNlLCJzZXNzaW9ucyIsInNlc3Npb25Db3VudCJdLDEpKSx0LmhlYWRlcnN8fChlPWUudXBkYXRlSW4oWyJ3b3Jrc3BhY2VzIixlLnNlbGVjdGVkV29ya3NwYWNlLCJzZXNzaW9ucyIsInNlc3Npb25zIl0sZnVuY3Rpb24oZSl7cmV0dXJuIGUubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnNldCgiaGVhZGVycyIsIiIpfSl9KSksdC5oaXN0b3J5fHwoZT1lLnNldEluKFsid29ya3NwYWNlcyIsZS5zZWxlY3RlZFdvcmtzcGFjZSwiaGlzdG9yeSJdLHAuTWFwKCkpKSxbMixlXX19KX12YXIgbz1mdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiByKFtlLHRdKX19ZnVuY3Rpb24gcihuKXtpZihpKXRocm93IG5ldyBUeXBlRXJyb3IoIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy4iKTtmb3IoO3U7KXRyeXtpZihpPTEsbyYmKGE9MiZuWzBdP28ucmV0dXJuOm5bMF0/by50aHJvd3x8KChhPW8ucmV0dXJuKSYmYS5jYWxsKG8pLDApOm8ubmV4dCkmJiEoYT1hLmNhbGwobyxuWzFdKSkuZG9uZSlyZXR1cm4gYTtzd2l0Y2gobz0wLGEmJihuPVsyJm5bMF0sYS52YWx1ZV0pLG5bMF0pe2Nhc2UgMDpjYXNlIDE6YT1uO2JyZWFrO2Nhc2UgNDpyZXR1cm4gdS5sYWJlbCsrLHt2YWx1ZTpuWzFdLGRvbmU6ITF9O2Nhc2UgNTp1LmxhYmVsKyssbz1uWzFdLG49WzBdO2NvbnRpbnVlO2Nhc2UgNzpuPXUub3BzLnBvcCgpLHUudHJ5cy5wb3AoKTtjb250aW51ZTtkZWZhdWx0OmlmKGE9dS50cnlzLCEoYT1hLmxlbmd0aD4wJiZhW2EubGVuZ3RoLTFdKSYmKDY9PT1uWzBdfHwyPT09blswXSkpe3U9MDtjb250aW51ZX1pZigzPT09blswXSYmKCFhfHxuWzFdPmFbMF0mJm5bMV08YVszXSkpe3UubGFiZWw9blsxXTticmVha31pZig2PT09blswXSYmdS5sYWJlbDxhWzFdKXt1LmxhYmVsPWFbMV0sYT1uO2JyZWFrfWlmKGEmJnUubGFiZWw8YVsyXSl7dS5sYWJlbD1hWzJdLHUub3BzLnB1c2gobik7YnJlYWt9YVsyXSYmdS5vcHMucG9wKCksdS50cnlzLnBvcCgpO2NvbnRpbnVlfW49dC5jYWxsKGUsdSl9Y2F0Y2goZSl7bj1bNixlXSxvPTB9ZmluYWxseXtpPWE9MH1pZig1Jm5bMF0pdGhyb3cgblsxXTtyZXR1cm57dmFsdWU6blswXT9uWzFdOnZvaWQgMCxkb25lOiEwfX12YXIgaSxvLGEscyx1PXtsYWJlbDowLHNlbnQ6ZnVuY3Rpb24oKXtpZigxJmFbMF0pdGhyb3cgYVsxXTtyZXR1cm4gYVsxXX0sdHJ5czpbXSxvcHM6W119O3JldHVybiBzPXtuZXh0Om4oMCksdGhyb3c6bigxKSxyZXR1cm46bigyKX0sImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJihzW1N5bWJvbC5pdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pLHN9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgYT1uKDU1KSxzPW4oMTIpLHU9bigxMzIpLGM9big2NCksbD1uKDI1NCkscD1uKDE0KSxmPW4oNjUpO3Quc2hhcmluZ1NhZ2FzPVthLnRha2VFdmVyeSgiU0hBUkUiLGYuc2FmZWx5KHIpKV19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gby5kZWJvdW5jZShmdW5jdGlvbigpe3ZhciB0PWUuZ2V0U3RhdGUoKTt0LnN0YXRlSW5qZWN0ZWR8fGxvY2FsU3RvcmFnZS5zZXRJdGVtKCJncmFwaHFsLXBsYXlncm91bmQiLEpTT04uc3RyaW5naWZ5KHQpKX0sMzAwLHt0cmFpbGluZzohMH0pfWZ1bmN0aW9uIGkoKXt0cnl7dmFyIGU9bG9jYWxTdG9yYWdlLmdldEl0ZW0oImdyYXBocWwtcGxheWdyb3VuZCIpO2lmKGUpe3ZhciB0PUpTT04ucGFyc2UoZSk7cmV0dXJuIGEuZGVzZXJpYWxpemVQZXJzaXN0ZWRTdGF0ZSh0KX19Y2F0Y2goZSl7fX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89big3NCksYT1uKDI1MCk7dC5zZXJpYWxpemVTdGF0ZT1yLHQuZGVzZXJpYWxpemVTdGF0ZT1pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBvKGUsdCl7aWYoIWUpdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKCJ0aGlzIGhhc24ndCBiZWVuIGluaXRpYWxpc2VkIC0gc3VwZXIoKSBoYXNuJ3QgYmVlbiBjYWxsZWQiKTtyZXR1cm4hdHx8Im9iamVjdCIhPT10eXBlb2YgdCYmImZ1bmN0aW9uIiE9PXR5cGVvZiB0P2U6dH1mdW5jdGlvbiBhKGUsdCl7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJTdXBlciBleHByZXNzaW9uIG11c3QgZWl0aGVyIGJlIG51bGwgb3IgYSBmdW5jdGlvbiwgbm90ICIrdHlwZW9mIHQpO2UucHJvdG90eXBlPU9iamVjdC5jcmVhdGUodCYmdC5wcm90b3R5cGUse2NvbnN0cnVjdG9yOnt2YWx1ZTplLGVudW1lcmFibGU6ITEsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfX0pLHQmJihPYmplY3Quc2V0UHJvdG90eXBlT2Y/T2JqZWN0LnNldFByb3RvdHlwZU9mKGUsdCk6ZS5fX3Byb3RvX189dCl9ZnVuY3Rpb24gcyhlKXtyZXR1cm4gZSgpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmJvZHlPcGVuQ2xhc3NOYW1lPXQucG9ydGFsQ2xhc3NOYW1lPXZvaWQgMDt2YXIgdT1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfSxjPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe2Zvcih2YXIgbj0wO248dC5sZW5ndGg7bisrKXt2YXIgcj10W25dO3IuZW51bWVyYWJsZT1yLmVudW1lcmFibGV8fCExLHIuY29uZmlndXJhYmxlPSEwLCJ2YWx1ZSJpbiByJiYoci53cml0YWJsZT0hMCksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsci5rZXkscil9fXJldHVybiBmdW5jdGlvbih0LG4scil7cmV0dXJuIG4mJmUodC5wcm90b3R5cGUsbiksciYmZSh0LHIpLHR9fSgpLGw9bigwKSxwPXIobCksZj1uKDMwKSxkPXIoZiksaD1uKDE4KSxtPXIoaCksZz1uKDUxOSkseT1yKGcpLHY9bigyNTYpLGI9ZnVuY3Rpb24oZSl7aWYoZSYmZS5fX2VzTW9kdWxlKXJldHVybiBlO3ZhciB0PXt9O2lmKG51bGwhPWUpZm9yKHZhciBuIGluIGUpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUsbikmJih0W25dPWVbbl0pO3JldHVybiB0LmRlZmF1bHQ9ZSx0fSh2KSx4PW4oMjU3KSxDPXIoeCksRT1uKDUyMyksRD10LnBvcnRhbENsYXNzTmFtZT0iUmVhY3RNb2RhbFBvcnRhbCIsdz10LmJvZHlPcGVuQ2xhc3NOYW1lPSJSZWFjdE1vZGFsX19Cb2R5LS1vcGVuIixTPXZvaWQgMCE9PWQuZGVmYXVsdC5jcmVhdGVQb3J0YWwsaz1TP2QuZGVmYXVsdC5jcmVhdGVQb3J0YWw6ZC5kZWZhdWx0LnVuc3RhYmxlX3JlbmRlclN1YnRyZWVJbnRvQ29udGFpbmVyLEE9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3ZhciBlLG4scixhO2kodGhpcyx0KTtmb3IodmFyIGM9YXJndW1lbnRzLmxlbmd0aCxsPUFycmF5KGMpLGY9MDtmPGM7ZisrKWxbZl09YXJndW1lbnRzW2ZdO3JldHVybiBuPXI9byh0aGlzLChlPXQuX19wcm90b19ffHxPYmplY3QuZ2V0UHJvdG90eXBlT2YodCkpLmNhbGwuYXBwbHkoZSxbdGhpc10uY29uY2F0KGwpKSksci5yZW1vdmVQb3J0YWw9ZnVuY3Rpb24oKXshUyYmZC5kZWZhdWx0LnVubW91bnRDb21wb25lbnRBdE5vZGUoci5ub2RlKSxzKHIucHJvcHMucGFyZW50U2VsZWN0b3IpLnJlbW92ZUNoaWxkKHIubm9kZSl9LHIucG9ydGFsUmVmPWZ1bmN0aW9uKGUpe3IucG9ydGFsPWV9LHIucmVuZGVyUG9ydGFsPWZ1bmN0aW9uKGUpe3ZhciBuPWsocixwLmRlZmF1bHQuY3JlYXRlRWxlbWVudCh5LmRlZmF1bHQsdSh7ZGVmYXVsdFN0eWxlczp0LmRlZmF1bHRTdHlsZXN9LGUpKSxyLm5vZGUpO3IucG9ydGFsUmVmKG4pfSxhPW4sbyhyLGEpfXJldHVybiBhKHQsZSksYyh0LFt7a2V5OiJjb21wb25lbnREaWRNb3VudCIsdmFsdWU6ZnVuY3Rpb24oKXtpZih4LmNhblVzZURPTSl7U3x8KHRoaXMubm9kZT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKSksdGhpcy5ub2RlLmNsYXNzTmFtZT10aGlzLnByb3BzLnBvcnRhbENsYXNzTmFtZTtzKHRoaXMucHJvcHMucGFyZW50U2VsZWN0b3IpLmFwcGVuZENoaWxkKHRoaXMubm9kZSksIVMmJnRoaXMucmVuZGVyUG9ydGFsKHRoaXMucHJvcHMpfX19LHtrZXk6ImdldFNuYXBzaG90QmVmb3JlVXBkYXRlIix2YWx1ZTpmdW5jdGlvbihlKXtyZXR1cm57cHJldlBhcmVudDpzKGUucGFyZW50U2VsZWN0b3IpLG5leHRQYXJlbnQ6cyh0aGlzLnByb3BzLnBhcmVudFNlbGVjdG9yKX19fSx7a2V5OiJjb21wb25lbnREaWRVcGRhdGUiLHZhbHVlOmZ1bmN0aW9uKGUsdCxuKXtpZih4LmNhblVzZURPTSl7dmFyIHI9dGhpcy5wcm9wcyxpPXIuaXNPcGVuLG89ci5wb3J0YWxDbGFzc05hbWU7aWYoZS5wb3J0YWxDbGFzc05hbWUhPT1vJiYodGhpcy5ub2RlLmNsYXNzTmFtZT1vKSxlLmlzT3Blbnx8aSl7dmFyIGE9bi5wcmV2UGFyZW50LHM9bi5uZXh0UGFyZW50O3MhPT1hJiYoYS5yZW1vdmVDaGlsZCh0aGlzLm5vZGUpLHMuYXBwZW5kQ2hpbGQodGhpcy5ub2RlKSksIVMmJnRoaXMucmVuZGVyUG9ydGFsKHRoaXMucHJvcHMpfX19fSx7a2V5OiJjb21wb25lbnRXaWxsVW5tb3VudCIsdmFsdWU6ZnVuY3Rpb24oKXtpZih4LmNhblVzZURPTSYmdGhpcy5ub2RlJiZ0aGlzLnBvcnRhbCl7dmFyIGU9dGhpcy5wb3J0YWwuc3RhdGUsdD1EYXRlLm5vdygpLG49ZS5pc09wZW4mJnRoaXMucHJvcHMuY2xvc2VUaW1lb3V0TVMmJihlLmNsb3Nlc0F0fHx0K3RoaXMucHJvcHMuY2xvc2VUaW1lb3V0TVMpO24/KGUuYmVmb3JlQ2xvc2V8fHRoaXMucG9ydGFsLmNsb3NlV2l0aFRpbWVvdXQoKSxzZXRUaW1lb3V0KHRoaXMucmVtb3ZlUG9ydGFsLG4tdCkpOnRoaXMucmVtb3ZlUG9ydGFsKCl9fX0se2tleToicmVuZGVyIix2YWx1ZTpmdW5jdGlvbigpe3JldHVybiB4LmNhblVzZURPTSYmUz8oIXRoaXMubm9kZSYmUyYmKHRoaXMubm9kZT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKSksayhwLmRlZmF1bHQuY3JlYXRlRWxlbWVudCh5LmRlZmF1bHQsdSh7cmVmOnRoaXMucG9ydGFsUmVmLGRlZmF1bHRTdHlsZXM6dC5kZWZhdWx0U3R5bGVzfSx0aGlzLnByb3BzKSksdGhpcy5ub2RlKSk6bnVsbH19XSxbe2tleToic2V0QXBwRWxlbWVudCIsdmFsdWU6ZnVuY3Rpb24oZSl7Yi5zZXRFbGVtZW50KGUpfX1dKSx0fShsLkNvbXBvbmVudCk7QS5wcm9wVHlwZXM9e2lzT3BlbjptLmRlZmF1bHQuYm9vbC5pc1JlcXVpcmVkLHN0eWxlOm0uZGVmYXVsdC5zaGFwZSh7Y29udGVudDptLmRlZmF1bHQub2JqZWN0LG92ZXJsYXk6bS5kZWZhdWx0Lm9iamVjdH0pLHBvcnRhbENsYXNzTmFtZTptLmRlZmF1bHQuc3RyaW5nLGJvZHlPcGVuQ2xhc3NOYW1lOm0uZGVmYXVsdC5zdHJpbmcsaHRtbE9wZW5DbGFzc05hbWU6bS5kZWZhdWx0LnN0cmluZyxjbGFzc05hbWU6bS5kZWZhdWx0Lm9uZU9mVHlwZShbbS5kZWZhdWx0LnN0cmluZyxtLmRlZmF1bHQuc2hhcGUoe2Jhc2U6bS5kZWZhdWx0LnN0cmluZy5pc1JlcXVpcmVkLGFmdGVyT3BlbjptLmRlZmF1bHQuc3RyaW5nLmlzUmVxdWlyZWQsYmVmb3JlQ2xvc2U6bS5kZWZhdWx0LnN0cmluZy5pc1JlcXVpcmVkfSldKSxvdmVybGF5Q2xhc3NOYW1lOm0uZGVmYXVsdC5vbmVPZlR5cGUoW20uZGVmYXVsdC5zdHJpbmcsbS5kZWZhdWx0LnNoYXBlKHtiYXNlOm0uZGVmYXVsdC5zdHJpbmcuaXNSZXF1aXJlZCxhZnRlck9wZW46bS5kZWZhdWx0LnN0cmluZy5pc1JlcXVpcmVkLGJlZm9yZUNsb3NlOm0uZGVmYXVsdC5zdHJpbmcuaXNSZXF1aXJlZH0pXSksYXBwRWxlbWVudDptLmRlZmF1bHQuaW5zdGFuY2VPZihDLmRlZmF1bHQpLG9uQWZ0ZXJPcGVuOm0uZGVmYXVsdC5mdW5jLG9uUmVxdWVzdENsb3NlOm0uZGVmYXVsdC5mdW5jLGNsb3NlVGltZW91dE1TOm0uZGVmYXVsdC5udW1iZXIsYXJpYUhpZGVBcHA6bS5kZWZhdWx0LmJvb2wsc2hvdWxkRm9jdXNBZnRlclJlbmRlcjptLmRlZmF1bHQuYm9vbCxzaG91bGRDbG9zZU9uT3ZlcmxheUNsaWNrOm0uZGVmYXVsdC5ib29sLHNob3VsZFJldHVybkZvY3VzQWZ0ZXJDbG9zZTptLmRlZmF1bHQuYm9vbCxwYXJlbnRTZWxlY3RvcjptLmRlZmF1bHQuZnVuYyxhcmlhOm0uZGVmYXVsdC5vYmplY3Qscm9sZTptLmRlZmF1bHQuc3RyaW5nLGNvbnRlbnRMYWJlbDptLmRlZmF1bHQuc3RyaW5nLHNob3VsZENsb3NlT25Fc2M6bS5kZWZhdWx0LmJvb2wsb3ZlcmxheVJlZjptLmRlZmF1bHQuZnVuYyxjb250ZW50UmVmOm0uZGVmYXVsdC5mdW5jfSxBLmRlZmF1bHRQcm9wcz17aXNPcGVuOiExLHBvcnRhbENsYXNzTmFtZTpELGJvZHlPcGVuQ2xhc3NOYW1lOncsYXJpYUhpZGVBcHA6ITAsY2xvc2VUaW1lb3V0TVM6MCxzaG91bGRGb2N1c0FmdGVyUmVuZGVyOiEwLHNob3VsZENsb3NlT25Fc2M6ITAsc2hvdWxkQ2xvc2VPbk92ZXJsYXlDbGljazohMCxzaG91bGRSZXR1cm5Gb2N1c0FmdGVyQ2xvc2U6ITAscGFyZW50U2VsZWN0b3I6ZnVuY3Rpb24oKXtyZXR1cm4gZG9jdW1lbnQuYm9keX19LEEuZGVmYXVsdFN0eWxlcz17b3ZlcmxheTp7cG9zaXRpb246ImZpeGVkIix0b3A6MCxsZWZ0OjAscmlnaHQ6MCxib3R0b206MCxiYWNrZ3JvdW5kQ29sb3I6InJnYmEoMjU1LCAyNTUsIDI1NSwgMC43NSkifSxjb250ZW50Ontwb3NpdGlvbjoiYWJzb2x1dGUiLHRvcDoiNDBweCIsbGVmdDoiNDBweCIscmlnaHQ6IjQwcHgiLGJvdHRvbToiNDBweCIsYm9yZGVyOiIxcHggc29saWQgI2NjYyIsYmFja2dyb3VuZDoiI2ZmZiIsb3ZlcmZsb3c6ImF1dG8iLFdlYmtpdE92ZXJmbG93U2Nyb2xsaW5nOiJ0b3VjaCIsYm9yZGVyUmFkaXVzOiI0cHgiLG91dGxpbmU6Im5vbmUiLHBhZGRpbmc6IjIwcHgifX0sKDAsRS5wb2x5ZmlsbCkoQSksdC5kZWZhdWx0PUF9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZihlJiZlLl9fZXNNb2R1bGUpcmV0dXJuIGU7dmFyIHQ9e307aWYobnVsbCE9ZSlmb3IodmFyIG4gaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxuKSYmKHRbbl09ZVtuXSk7cmV0dXJuIHQuZGVmYXVsdD1lLHR9ZnVuY3Rpb24gaShlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gbyhlLHQpe2lmKCEoZSBpbnN0YW5jZW9mIHQpKXRocm93IG5ldyBUeXBlRXJyb3IoIkNhbm5vdCBjYWxsIGEgY2xhc3MgYXMgYSBmdW5jdGlvbiIpfWZ1bmN0aW9uIGEoZSx0KXtpZighZSl0aHJvdyBuZXcgUmVmZXJlbmNlRXJyb3IoInRoaXMgaGFzbid0IGJlZW4gaW5pdGlhbGlzZWQgLSBzdXBlcigpIGhhc24ndCBiZWVuIGNhbGxlZCIpO3JldHVybiF0fHwib2JqZWN0IiE9PXR5cGVvZiB0JiYiZnVuY3Rpb24iIT09dHlwZW9mIHQ/ZTp0fWZ1bmN0aW9uIHMoZSx0KXtpZigiZnVuY3Rpb24iIT09dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIlN1cGVyIGV4cHJlc3Npb24gbXVzdCBlaXRoZXIgYmUgbnVsbCBvciBhIGZ1bmN0aW9uLCBub3QgIit0eXBlb2YgdCk7ZS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZSh0JiZ0LnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOmUsZW51bWVyYWJsZTohMSx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9fSksdCYmKE9iamVjdC5zZXRQcm90b3R5cGVPZj9PYmplY3Quc2V0UHJvdG90eXBlT2YoZSx0KTplLl9fcHJvdG9fXz10KX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHU9T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTE7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyl7dmFyIG49YXJndW1lbnRzW3RdO2Zvcih2YXIgciBpbiBuKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChuLHIpJiYoZVtyXT1uW3JdKX1yZXR1cm4gZX0sYz0iZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmInN5bWJvbCI9PT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiZlLmNvbnN0cnVjdG9yPT09U3ltYm9sJiZlIT09U3ltYm9sLnByb3RvdHlwZT8ic3ltYm9sIjp0eXBlb2YgZX0sbD1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXtmb3IodmFyIG49MDtuPHQubGVuZ3RoO24rKyl7dmFyIHI9dFtuXTtyLmVudW1lcmFibGU9ci5lbnVtZXJhYmxlfHwhMSxyLmNvbmZpZ3VyYWJsZT0hMCwidmFsdWUiaW4gciYmKHIud3JpdGFibGU9ITApLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIua2V5LHIpfX1yZXR1cm4gZnVuY3Rpb24odCxuLHIpe3JldHVybiBuJiZlKHQucHJvdG90eXBlLG4pLHImJmUodCxyKSx0fX0oKSxwPW4oMCksZj1pKHApLGQ9bigxOCksaD1pKGQpLG09big1MjApLGc9cihtKSx5PW4oNTIxKSx2PWkoeSksYj1uKDI1NikseD1yKGIpLEM9big1MjIpLEU9cihDKSxEPW4oMjU3KSx3PWkoRCksUz17b3ZlcmxheToiUmVhY3RNb2RhbF9fT3ZlcmxheSIsY29udGVudDoiUmVhY3RNb2RhbF9fQ29udGVudCJ9LGs9OSxBPTI3LF89MCxUPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoZSl7byh0aGlzLHQpO3ZhciBuPWEodGhpcywodC5fX3Byb3RvX198fE9iamVjdC5nZXRQcm90b3R5cGVPZih0KSkuY2FsbCh0aGlzLGUpKTtyZXR1cm4gbi5zZXRPdmVybGF5UmVmPWZ1bmN0aW9uKGUpe24ub3ZlcmxheT1lLG4ucHJvcHMub3ZlcmxheVJlZiYmbi5wcm9wcy5vdmVybGF5UmVmKGUpfSxuLnNldENvbnRlbnRSZWY9ZnVuY3Rpb24oZSl7bi5jb250ZW50PWUsbi5wcm9wcy5jb250ZW50UmVmJiZuLnByb3BzLmNvbnRlbnRSZWYoZSl9LG4uYWZ0ZXJDbG9zZT1mdW5jdGlvbigpe3ZhciBlPW4ucHJvcHMsdD1lLmFwcEVsZW1lbnQscj1lLmFyaWFIaWRlQXBwLGk9ZS5odG1sT3BlbkNsYXNzTmFtZSxvPWUuYm9keU9wZW5DbGFzc05hbWU7RS5yZW1vdmUoZG9jdW1lbnQuYm9keSxvKSxpJiZFLnJlbW92ZShkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaHRtbCIpWzBdLGkpLHImJl8+MCYmMD09PShfLT0xKSYmeC5zaG93KHQpLG4ucHJvcHMuc2hvdWxkRm9jdXNBZnRlclJlbmRlciYmKG4ucHJvcHMuc2hvdWxkUmV0dXJuRm9jdXNBZnRlckNsb3NlPyhnLnJldHVybkZvY3VzKCksZy50ZWFyZG93blNjb3BlZEZvY3VzKCkpOmcucG9wV2l0aG91dEZvY3VzKCkpfSxuLm9wZW49ZnVuY3Rpb24oKXtuLmJlZm9yZU9wZW4oKSxuLnN0YXRlLmFmdGVyT3BlbiYmbi5zdGF0ZS5iZWZvcmVDbG9zZT8oY2xlYXJUaW1lb3V0KG4uY2xvc2VUaW1lciksbi5zZXRTdGF0ZSh7YmVmb3JlQ2xvc2U6ITF9KSk6KG4ucHJvcHMuc2hvdWxkRm9jdXNBZnRlclJlbmRlciYmKGcuc2V0dXBTY29wZWRGb2N1cyhuLm5vZGUpLGcubWFya0ZvckZvY3VzTGF0ZXIoKSksbi5zZXRTdGF0ZSh7aXNPcGVuOiEwfSxmdW5jdGlvbigpe24uc2V0U3RhdGUoe2FmdGVyT3BlbjohMH0pLG4ucHJvcHMuaXNPcGVuJiZuLnByb3BzLm9uQWZ0ZXJPcGVuJiZuLnByb3BzLm9uQWZ0ZXJPcGVuKCl9KSl9LG4uY2xvc2U9ZnVuY3Rpb24oKXtuLnByb3BzLmNsb3NlVGltZW91dE1TPjA/bi5jbG9zZVdpdGhUaW1lb3V0KCk6bi5jbG9zZVdpdGhvdXRUaW1lb3V0KCl9LG4uZm9jdXNDb250ZW50PWZ1bmN0aW9uKCl7cmV0dXJuIG4uY29udGVudCYmIW4uY29udGVudEhhc0ZvY3VzKCkmJm4uY29udGVudC5mb2N1cygpfSxuLmNsb3NlV2l0aFRpbWVvdXQ9ZnVuY3Rpb24oKXt2YXIgZT1EYXRlLm5vdygpK24ucHJvcHMuY2xvc2VUaW1lb3V0TVM7bi5zZXRTdGF0ZSh7YmVmb3JlQ2xvc2U6ITAsY2xvc2VzQXQ6ZX0sZnVuY3Rpb24oKXtuLmNsb3NlVGltZXI9c2V0VGltZW91dChuLmNsb3NlV2l0aG91dFRpbWVvdXQsbi5zdGF0ZS5jbG9zZXNBdC1EYXRlLm5vdygpKX0pfSxuLmNsb3NlV2l0aG91dFRpbWVvdXQ9ZnVuY3Rpb24oKXtuLnNldFN0YXRlKHtiZWZvcmVDbG9zZTohMSxpc09wZW46ITEsYWZ0ZXJPcGVuOiExLGNsb3Nlc0F0Om51bGx9LG4uYWZ0ZXJDbG9zZSl9LG4uaGFuZGxlS2V5RG93bj1mdW5jdGlvbihlKXtlLmtleUNvZGU9PT1rJiYoMCx2LmRlZmF1bHQpKG4uY29udGVudCxlKSxuLnByb3BzLnNob3VsZENsb3NlT25Fc2MmJmUua2V5Q29kZT09PUEmJihlLnN0b3BQcm9wYWdhdGlvbigpLG4ucmVxdWVzdENsb3NlKGUpKX0sbi5oYW5kbGVPdmVybGF5T25DbGljaz1mdW5jdGlvbihlKXtudWxsPT09bi5zaG91bGRDbG9zZSYmKG4uc2hvdWxkQ2xvc2U9ITApLG4uc2hvdWxkQ2xvc2UmJm4ucHJvcHMuc2hvdWxkQ2xvc2VPbk92ZXJsYXlDbGljayYmKG4ub3duZXJIYW5kbGVzQ2xvc2UoKT9uLnJlcXVlc3RDbG9zZShlKTpuLmZvY3VzQ29udGVudCgpKSxuLnNob3VsZENsb3NlPW51bGx9LG4uaGFuZGxlQ29udGVudE9uTW91c2VVcD1mdW5jdGlvbigpe24uc2hvdWxkQ2xvc2U9ITF9LG4uaGFuZGxlT3ZlcmxheU9uTW91c2VEb3duPWZ1bmN0aW9uKGUpe24ucHJvcHMuc2hvdWxkQ2xvc2VPbk92ZXJsYXlDbGlja3x8ZS50YXJnZXQhPW4ub3ZlcmxheXx8ZS5wcmV2ZW50RGVmYXVsdCgpfSxuLmhhbmRsZUNvbnRlbnRPbkNsaWNrPWZ1bmN0aW9uKCl7bi5zaG91bGRDbG9zZT0hMX0sbi5oYW5kbGVDb250ZW50T25Nb3VzZURvd249ZnVuY3Rpb24oKXtuLnNob3VsZENsb3NlPSExfSxuLnJlcXVlc3RDbG9zZT1mdW5jdGlvbihlKXtyZXR1cm4gbi5vd25lckhhbmRsZXNDbG9zZSgpJiZuLnByb3BzLm9uUmVxdWVzdENsb3NlKGUpfSxuLm93bmVySGFuZGxlc0Nsb3NlPWZ1bmN0aW9uKCl7cmV0dXJuIG4ucHJvcHMub25SZXF1ZXN0Q2xvc2V9LG4uc2hvdWxkQmVDbG9zZWQ9ZnVuY3Rpb24oKXtyZXR1cm4hbi5zdGF0ZS5pc09wZW4mJiFuLnN0YXRlLmJlZm9yZUNsb3NlfSxuLmNvbnRlbnRIYXNGb2N1cz1mdW5jdGlvbigpe3JldHVybiBkb2N1bWVudC5hY3RpdmVFbGVtZW50PT09bi5jb250ZW50fHxuLmNvbnRlbnQuY29udGFpbnMoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCl9LG4uYnVpbGRDbGFzc05hbWU9ZnVuY3Rpb24oZSx0KXt2YXIgcj0ib2JqZWN0Ij09PSgidW5kZWZpbmVkIj09PXR5cGVvZiB0PyJ1bmRlZmluZWQiOmModCkpP3Q6e2Jhc2U6U1tlXSxhZnRlck9wZW46U1tlXSsiLS1hZnRlci1vcGVuIixiZWZvcmVDbG9zZTpTW2VdKyItLWJlZm9yZS1jbG9zZSJ9LGk9ci5iYXNlO3JldHVybiBuLnN0YXRlLmFmdGVyT3BlbiYmKGk9aSsiICIrci5hZnRlck9wZW4pLG4uc3RhdGUuYmVmb3JlQ2xvc2UmJihpPWkrIiAiK3IuYmVmb3JlQ2xvc2UpLCJzdHJpbmciPT09dHlwZW9mIHQmJnQ/aSsiICIrdDppfSxuLmFyaWFBdHRyaWJ1dGVzPWZ1bmN0aW9uKGUpe3JldHVybiBPYmplY3Qua2V5cyhlKS5yZWR1Y2UoZnVuY3Rpb24odCxuKXtyZXR1cm4gdFsiYXJpYS0iK25dPWVbbl0sdH0se30pfSxuLnN0YXRlPXthZnRlck9wZW46ITEsYmVmb3JlQ2xvc2U6ITF9LG4uc2hvdWxkQ2xvc2U9bnVsbCxuLm1vdmVGcm9tQ29udGVudFRvT3ZlcmxheT1udWxsLG59cmV0dXJuIHModCxlKSxsKHQsW3trZXk6ImNvbXBvbmVudERpZE1vdW50Iix2YWx1ZTpmdW5jdGlvbigpe3RoaXMucHJvcHMuaXNPcGVuJiZ0aGlzLm9wZW4oKX19LHtrZXk6ImNvbXBvbmVudERpZFVwZGF0ZSIsdmFsdWU6ZnVuY3Rpb24oZSx0KXt0aGlzLnByb3BzLmlzT3BlbiYmIWUuaXNPcGVuP3RoaXMub3BlbigpOiF0aGlzLnByb3BzLmlzT3BlbiYmZS5pc09wZW4mJnRoaXMuY2xvc2UoKSx0aGlzLnByb3BzLnNob3VsZEZvY3VzQWZ0ZXJSZW5kZXImJnRoaXMuc3RhdGUuaXNPcGVuJiYhdC5pc09wZW4mJnRoaXMuZm9jdXNDb250ZW50KCl9fSx7a2V5OiJjb21wb25lbnRXaWxsVW5tb3VudCIsdmFsdWU6ZnVuY3Rpb24oKXt0aGlzLmFmdGVyQ2xvc2UoKSxjbGVhclRpbWVvdXQodGhpcy5jbG9zZVRpbWVyKX19LHtrZXk6ImJlZm9yZU9wZW4iLHZhbHVlOmZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcyx0PWUuYXBwRWxlbWVudCxuPWUuYXJpYUhpZGVBcHAscj1lLmh0bWxPcGVuQ2xhc3NOYW1lLGk9ZS5ib2R5T3BlbkNsYXNzTmFtZTtFLmFkZChkb2N1bWVudC5ib2R5LGkpLHImJkUuYWRkKGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJodG1sIilbMF0sciksbiYmKF8rPTEseC5oaWRlKHQpKX19LHtrZXk6InJlbmRlciIsdmFsdWU6ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnByb3BzLHQ9ZS5jbGFzc05hbWUsbj1lLm92ZXJsYXlDbGFzc05hbWUscj1lLmRlZmF1bHRTdHlsZXMsaT10P3t9OnIuY29udGVudCxvPW4/e306ci5vdmVybGF5O3JldHVybiB0aGlzLnNob3VsZEJlQ2xvc2VkKCk/bnVsbDpmLmRlZmF1bHQuY3JlYXRlRWxlbWVudCgiZGl2Iix7cmVmOnRoaXMuc2V0T3ZlcmxheVJlZixjbGFzc05hbWU6dGhpcy5idWlsZENsYXNzTmFtZSgib3ZlcmxheSIsbiksc3R5bGU6dSh7fSxvLHRoaXMucHJvcHMuc3R5bGUub3ZlcmxheSksb25DbGljazp0aGlzLmhhbmRsZU92ZXJsYXlPbkNsaWNrLG9uTW91c2VEb3duOnRoaXMuaGFuZGxlT3ZlcmxheU9uTW91c2VEb3duLCJhcmlhLW1vZGFsIjoidHJ1ZSJ9LGYuZGVmYXVsdC5jcmVhdGVFbGVtZW50KCJkaXYiLHUoe3JlZjp0aGlzLnNldENvbnRlbnRSZWYsc3R5bGU6dSh7fSxpLHRoaXMucHJvcHMuc3R5bGUuY29udGVudCksY2xhc3NOYW1lOnRoaXMuYnVpbGRDbGFzc05hbWUoImNvbnRlbnQiLHQpLHRhYkluZGV4OiItMSIsb25LZXlEb3duOnRoaXMuaGFuZGxlS2V5RG93bixvbk1vdXNlRG93bjp0aGlzLmhhbmRsZUNvbnRlbnRPbk1vdXNlRG93bixvbk1vdXNlVXA6dGhpcy5oYW5kbGVDb250ZW50T25Nb3VzZVVwLG9uQ2xpY2s6dGhpcy5oYW5kbGVDb250ZW50T25DbGljayxyb2xlOnRoaXMucHJvcHMucm9sZSwiYXJpYS1sYWJlbCI6dGhpcy5wcm9wcy5jb250ZW50TGFiZWx9LHRoaXMuYXJpYUF0dHJpYnV0ZXModGhpcy5wcm9wcy5hcmlhfHx7fSkseyJkYXRhLXRlc3RpZCI6dGhpcy5wcm9wcy50ZXN0SWR9KSx0aGlzLnByb3BzLmNoaWxkcmVuKSl9fV0pLHR9KHAuQ29tcG9uZW50KTtULmRlZmF1bHRQcm9wcz17c3R5bGU6e292ZXJsYXk6e30sY29udGVudDp7fX0sZGVmYXVsdFN0eWxlczp7fX0sVC5wcm9wVHlwZXM9e2lzT3BlbjpoLmRlZmF1bHQuYm9vbC5pc1JlcXVpcmVkLGRlZmF1bHRTdHlsZXM6aC5kZWZhdWx0LnNoYXBlKHtjb250ZW50OmguZGVmYXVsdC5vYmplY3Qsb3ZlcmxheTpoLmRlZmF1bHQub2JqZWN0fSksc3R5bGU6aC5kZWZhdWx0LnNoYXBlKHtjb250ZW50OmguZGVmYXVsdC5vYmplY3Qsb3ZlcmxheTpoLmRlZmF1bHQub2JqZWN0fSksY2xhc3NOYW1lOmguZGVmYXVsdC5vbmVPZlR5cGUoW2guZGVmYXVsdC5zdHJpbmcsaC5kZWZhdWx0Lm9iamVjdF0pLG92ZXJsYXlDbGFzc05hbWU6aC5kZWZhdWx0Lm9uZU9mVHlwZShbaC5kZWZhdWx0LnN0cmluZyxoLmRlZmF1bHQub2JqZWN0XSksYm9keU9wZW5DbGFzc05hbWU6aC5kZWZhdWx0LnN0cmluZyxodG1sT3BlbkNsYXNzTmFtZTpoLmRlZmF1bHQuc3RyaW5nLGFyaWFIaWRlQXBwOmguZGVmYXVsdC5ib29sLGFwcEVsZW1lbnQ6aC5kZWZhdWx0Lmluc3RhbmNlT2Yody5kZWZhdWx0KSxvbkFmdGVyT3BlbjpoLmRlZmF1bHQuZnVuYyxvblJlcXVlc3RDbG9zZTpoLmRlZmF1bHQuZnVuYyxjbG9zZVRpbWVvdXRNUzpoLmRlZmF1bHQubnVtYmVyLHNob3VsZEZvY3VzQWZ0ZXJSZW5kZXI6aC5kZWZhdWx0LmJvb2wsc2hvdWxkQ2xvc2VPbk92ZXJsYXlDbGljazpoLmRlZmF1bHQuYm9vbCxzaG91bGRSZXR1cm5Gb2N1c0FmdGVyQ2xvc2U6aC5kZWZhdWx0LmJvb2wscm9sZTpoLmRlZmF1bHQuc3RyaW5nLGNvbnRlbnRMYWJlbDpoLmRlZmF1bHQuc3RyaW5nLGFyaWE6aC5kZWZhdWx0Lm9iamVjdCxjaGlsZHJlbjpoLmRlZmF1bHQubm9kZSxzaG91bGRDbG9zZU9uRXNjOmguZGVmYXVsdC5ib29sLG92ZXJsYXlSZWY6aC5kZWZhdWx0LmZ1bmMsY29udGVudFJlZjpoLmRlZmF1bHQuZnVuYyx0ZXN0SWQ6aC5kZWZhdWx0LnN0cmluZ30sdC5kZWZhdWx0PVQsZS5leHBvcnRzPXQuZGVmYXVsdH0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKCl7aD0hMH1mdW5jdGlvbiBpKCl7aWYoaCl7aWYoaD0hMSwhZClyZXR1cm47c2V0VGltZW91dChmdW5jdGlvbigpe2lmKCFkLmNvbnRhaW5zKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpKXsoKDAscC5kZWZhdWx0KShkKVswXXx8ZCkuZm9jdXMoKX19LDApfX1mdW5jdGlvbiBvKCl7Zi5wdXNoKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpfWZ1bmN0aW9uIGEoKXt2YXIgZT1udWxsO3RyeXtyZXR1cm4gdm9pZCgwIT09Zi5sZW5ndGgmJihlPWYucG9wKCksZS5mb2N1cygpKSl9Y2F0Y2godCl7Y29uc29sZS53YXJuKFsiWW91IHRyaWVkIHRvIHJldHVybiBmb2N1cyB0byIsZSwiYnV0IGl0IGlzIG5vdCBpbiB0aGUgRE9NIGFueW1vcmUiXS5qb2luKCIgIikpfX1mdW5jdGlvbiBzKCl7Zi5sZW5ndGg+MCYmZi5wb3AoKX1mdW5jdGlvbiB1KGUpe2Q9ZSx3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcj8od2luZG93LmFkZEV2ZW50TGlzdGVuZXIoImJsdXIiLHIsITEpLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoImZvY3VzIixpLCEwKSk6KHdpbmRvdy5hdHRhY2hFdmVudCgib25CbHVyIixyKSxkb2N1bWVudC5hdHRhY2hFdmVudCgib25Gb2N1cyIsaSkpfWZ1bmN0aW9uIGMoKXtkPW51bGwsd2luZG93LmFkZEV2ZW50TGlzdGVuZXI/KHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCJibHVyIixyKSxkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJmb2N1cyIsaSkpOih3aW5kb3cuZGV0YWNoRXZlbnQoIm9uQmx1ciIsciksZG9jdW1lbnQuZGV0YWNoRXZlbnQoIm9uRm9jdXMiLGkpKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5oYW5kbGVCbHVyPXIsdC5oYW5kbGVGb2N1cz1pLHQubWFya0ZvckZvY3VzTGF0ZXI9byx0LnJldHVybkZvY3VzPWEsdC5wb3BXaXRob3V0Rm9jdXM9cyx0LnNldHVwU2NvcGVkRm9jdXM9dSx0LnRlYXJkb3duU2NvcGVkRm9jdXM9Yzt2YXIgbD1uKDI1NSkscD1mdW5jdGlvbihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19KGwpLGY9W10sZD1udWxsLGg9ITF9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPSgwLG8uZGVmYXVsdCkoZSk7aWYoIW4ubGVuZ3RoKXJldHVybiB2b2lkIHQucHJldmVudERlZmF1bHQoKTt2YXIgcj10LnNoaWZ0S2V5LGk9blswXSxhPW5bbi5sZW5ndGgtMV07aWYoZT09PWRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpe2lmKCFyKXJldHVybjtzPWF9dmFyIHM7aWYoYSE9PWRvY3VtZW50LmFjdGl2ZUVsZW1lbnR8fHJ8fChzPWkpLGk9PT1kb2N1bWVudC5hY3RpdmVFbGVtZW50JiZyJiYocz1hKSxzKXJldHVybiB0LnByZXZlbnREZWZhdWx0KCksdm9pZCBzLmZvY3VzKCk7dmFyIHU9LyhcYkNocm9tZVxifFxiU2FmYXJpXGIpXC8vLmV4ZWMobmF2aWdhdG9yLnVzZXJBZ2VudCk7aWYobnVsbCE9dSYmIkNocm9tZSIhPXVbMV0mJm51bGw9PS9cYmlQb2RcYnxcYmlQYWRcYi9nLmV4ZWMobmF2aWdhdG9yLnVzZXJBZ2VudCkpe3ZhciBjPW4uaW5kZXhPZihkb2N1bWVudC5hY3RpdmVFbGVtZW50KTtjPi0xJiYoYys9cj8tMToxKSx0LnByZXZlbnREZWZhdWx0KCksbltjXS5mb2N1cygpfX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXI7dmFyIGk9bigyNTUpLG89ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShpKTtlLmV4cG9ydHM9dC5kZWZhdWx0fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXt9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuZHVtcENsYXNzTGlzdHM9cjt2YXIgaT17fSxvPXt9LGE9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZVt0XXx8KGVbdF09MCksZVt0XSs9MSx0fSxzPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGVbdF0mJihlW3RdLT0xKSx0fSx1PWZ1bmN0aW9uKGUsdCxuKXtuLmZvckVhY2goZnVuY3Rpb24obil7YSh0LG4pLGUuYWRkKG4pfSl9LGM9ZnVuY3Rpb24oZSx0LG4pe24uZm9yRWFjaChmdW5jdGlvbihuKXtzKHQsbiksMD09PXRbbl0mJmUucmVtb3ZlKG4pfSl9O3QuYWRkPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHUoZS5jbGFzc0xpc3QsImh0bWwiPT1lLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk/aTpvLHQuc3BsaXQoIiAiKSl9LHQucmVtb3ZlPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGMoZS5jbGFzc0xpc3QsImh0bWwiPT1lLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk/aTpvLHQuc3BsaXQoIiAiKSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXt2YXIgZT10aGlzLmNvbnN0cnVjdG9yLmdldERlcml2ZWRTdGF0ZUZyb21Qcm9wcyh0aGlzLnByb3BzLHRoaXMuc3RhdGUpO251bGwhPT1lJiZ2b2lkIDAhPT1lJiZ0aGlzLnNldFN0YXRlKGUpfWZ1bmN0aW9uIGkoZSl7ZnVuY3Rpb24gdCh0KXt2YXIgbj10aGlzLmNvbnN0cnVjdG9yLmdldERlcml2ZWRTdGF0ZUZyb21Qcm9wcyhlLHQpO3JldHVybiBudWxsIT09biYmdm9pZCAwIT09bj9uOm51bGx9dGhpcy5zZXRTdGF0ZSh0LmJpbmQodGhpcykpfWZ1bmN0aW9uIG8oZSx0KXt0cnl7dmFyIG49dGhpcy5wcm9wcyxyPXRoaXMuc3RhdGU7dGhpcy5wcm9wcz1lLHRoaXMuc3RhdGU9dCx0aGlzLl9fcmVhY3RJbnRlcm5hbFNuYXBzaG90RmxhZz0hMCx0aGlzLl9fcmVhY3RJbnRlcm5hbFNuYXBzaG90PXRoaXMuZ2V0U25hcHNob3RCZWZvcmVVcGRhdGUobixyKX1maW5hbGx5e3RoaXMucHJvcHM9bix0aGlzLnN0YXRlPXJ9fWZ1bmN0aW9uIGEoZSl7dmFyIHQ9ZS5wcm90b3R5cGU7aWYoIXR8fCF0LmlzUmVhY3RDb21wb25lbnQpdGhyb3cgbmV3IEVycm9yKCJDYW4gb25seSBwb2x5ZmlsbCBjbGFzcyBjb21wb25lbnRzIik7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiBlLmdldERlcml2ZWRTdGF0ZUZyb21Qcm9wcyYmImZ1bmN0aW9uIiE9PXR5cGVvZiB0LmdldFNuYXBzaG90QmVmb3JlVXBkYXRlKXJldHVybiBlO3ZhciBuPW51bGwsYT1udWxsLHM9bnVsbDtpZigiZnVuY3Rpb24iPT09dHlwZW9mIHQuY29tcG9uZW50V2lsbE1vdW50P249ImNvbXBvbmVudFdpbGxNb3VudCI6ImZ1bmN0aW9uIj09PXR5cGVvZiB0LlVOU0FGRV9jb21wb25lbnRXaWxsTW91bnQmJihuPSJVTlNBRkVfY29tcG9uZW50V2lsbE1vdW50IiksImZ1bmN0aW9uIj09PXR5cGVvZiB0LmNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHM/YT0iY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wcyI6ImZ1bmN0aW9uIj09PXR5cGVvZiB0LlVOU0FGRV9jb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzJiYoYT0iVU5TQUZFX2NvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHMiKSwiZnVuY3Rpb24iPT09dHlwZW9mIHQuY29tcG9uZW50V2lsbFVwZGF0ZT9zPSJjb21wb25lbnRXaWxsVXBkYXRlIjoiZnVuY3Rpb24iPT09dHlwZW9mIHQuVU5TQUZFX2NvbXBvbmVudFdpbGxVcGRhdGUmJihzPSJVTlNBRkVfY29tcG9uZW50V2lsbFVwZGF0ZSIpLG51bGwhPT1ufHxudWxsIT09YXx8bnVsbCE9PXMpe3ZhciB1PWUuZGlzcGxheU5hbWV8fGUubmFtZSxjPSJmdW5jdGlvbiI9PT10eXBlb2YgZS5nZXREZXJpdmVkU3RhdGVGcm9tUHJvcHM/ImdldERlcml2ZWRTdGF0ZUZyb21Qcm9wcygpIjoiZ2V0U25hcHNob3RCZWZvcmVVcGRhdGUoKSI7dGhyb3cgRXJyb3IoIlVuc2FmZSBsZWdhY3kgbGlmZWN5Y2xlcyB3aWxsIG5vdCBiZSBjYWxsZWQgZm9yIGNvbXBvbmVudHMgdXNpbmcgbmV3IGNvbXBvbmVudCBBUElzLlxuXG4iK3UrIiB1c2VzICIrYysiIGJ1dCBhbHNvIGNvbnRhaW5zIHRoZSBmb2xsb3dpbmcgbGVnYWN5IGxpZmVjeWNsZXM6IisobnVsbCE9PW4/IlxuICAiK246IiIpKyhudWxsIT09YT8iXG4gICIrYToiIikrKG51bGwhPT1zPyJcbiAgIitzOiIiKSsiXG5cblRoZSBhYm92ZSBsaWZlY3ljbGVzIHNob3VsZCBiZSByZW1vdmVkLiBMZWFybiBtb3JlIGFib3V0IHRoaXMgd2FybmluZyBoZXJlOlxuaHR0cHM6Ly9mYi5tZS9yZWFjdC1hc3luYy1jb21wb25lbnQtbGlmZWN5Y2xlLWhvb2tzIil9aWYoImZ1bmN0aW9uIj09PXR5cGVvZiBlLmdldERlcml2ZWRTdGF0ZUZyb21Qcm9wcyYmKHQuY29tcG9uZW50V2lsbE1vdW50PXIsdC5jb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzPWkpLCJmdW5jdGlvbiI9PT10eXBlb2YgdC5nZXRTbmFwc2hvdEJlZm9yZVVwZGF0ZSl7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0LmNvbXBvbmVudERpZFVwZGF0ZSl0aHJvdyBuZXcgRXJyb3IoIkNhbm5vdCBwb2x5ZmlsbCBnZXRTbmFwc2hvdEJlZm9yZVVwZGF0ZSgpIGZvciBjb21wb25lbnRzIHRoYXQgZG8gbm90IGRlZmluZSBjb21wb25lbnREaWRVcGRhdGUoKSBvbiB0aGUgcHJvdG90eXBlIik7dC5jb21wb25lbnRXaWxsVXBkYXRlPW87dmFyIGw9dC5jb21wb25lbnREaWRVcGRhdGU7dC5jb21wb25lbnREaWRVcGRhdGU9ZnVuY3Rpb24oZSx0LG4pe3ZhciByPXRoaXMuX19yZWFjdEludGVybmFsU25hcHNob3RGbGFnP3RoaXMuX19yZWFjdEludGVybmFsU25hcHNob3Q6bjtsLmNhbGwodGhpcyxlLHQscil9fXJldHVybiBlfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSxuLmQodCwicG9seWZpbGwiLGZ1bmN0aW9uKCl7cmV0dXJuIGF9KSxyLl9fc3VwcHJlc3NEZXByZWNhdGlvbldhcm5pbmc9ITAsaS5fX3N1cHByZXNzRGVwcmVjYXRpb25XYXJuaW5nPSEwLG8uX19zdXBwcmVzc0RlcHJlY2F0aW9uV2FybmluZz0hMH0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksZnVuY3Rpb24oZSxyKXtmdW5jdGlvbiBpKGUpe3JldHVybiJmdW5jdGlvbiI9PT10eXBlb2YgZX1mdW5jdGlvbiBvKGUpe3JldHVybiBlLmRpc3BsYXlOYW1lfHxlLm5hbWV8fCJDb21wb25lbnQifWZ1bmN0aW9uIGEoZSl7cmV0dXJuIGUmJiJzdHJpbmciPT09dHlwZW9mIGUuc3R5bGVkQ29tcG9uZW50SWR9ZnVuY3Rpb24gcyhlKXtyZXR1cm4gZS5yZXBsYWNlKEllLCItJDEiKS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoTGUsIi1tcy0iKX1mdW5jdGlvbiB1KGUsdCxuKXtpZihBcnJheS5pc0FycmF5KGUpKXtmb3IodmFyIHIsbz1bXSxzPTAsYz1lLmxlbmd0aDtzPGM7cys9MSludWxsIT09KHI9dShlW3NdLHQsbikpJiYoQXJyYXkuaXNBcnJheShyKT9vLnB1c2guYXBwbHkobyxyKTpvLnB1c2gocikpO3JldHVybiBvfXJldHVybiBNZShlKT9udWxsOmEoZSk/Ii4iK2Uuc3R5bGVkQ29tcG9uZW50SWQ6aShlKT90P3UoZSh0KSx0LG4pOmU6ZSBpbnN0YW5jZW9mIE5lP24/KGUuaW5qZWN0KG4pLGUuZ2V0TmFtZSgpKTplOnooZSk/UGUoZSk6ZS50b1N0cmluZygpfWZ1bmN0aW9uIGMoZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1BcnJheSh0PjE/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07cmV0dXJuIHUoaShlKXx8eihlKT9MKEcsW2VdLmNvbmNhdChuKSk6TChlLG4pKX1mdW5jdGlvbiBsKGUsdCl7dmFyIG49YXJndW1lbnRzLmxlbmd0aD4yJiZ2b2lkIDAhPT1hcmd1bWVudHNbMl0/YXJndW1lbnRzWzJdOlY7aWYoIU9iamVjdChULmlzVmFsaWRFbGVtZW50VHlwZSkodCkpdGhyb3cgbmV3IFEoMSxTdHJpbmcodCkpO3ZhciByPWZ1bmN0aW9uKCl7cmV0dXJuIGUodCxuLGMuYXBwbHkodm9pZCAwLGFyZ3VtZW50cykpfTtyZXR1cm4gci53aXRoQ29uZmlnPWZ1bmN0aW9uKHIpe3JldHVybiBsKGUsdCxSKHt9LG4scikpfSxyLmF0dHJzPWZ1bmN0aW9uKHIpe3JldHVybiBsKGUsdCxSKHt9LG4se2F0dHJzOlIoe30sbi5hdHRyc3x8VixyKX0pKX0scn1mdW5jdGlvbiBwKGUpe2Zvcih2YXIgdCxuPTB8ZS5sZW5ndGgscj0wfG4saT0wO24+PTQ7KXQ9MjU1JmUuY2hhckNvZGVBdChpKXwoMjU1JmUuY2hhckNvZGVBdCgrK2kpKTw8OHwoMjU1JmUuY2hhckNvZGVBdCgrK2kpKTw8MTZ8KDI1NSZlLmNoYXJDb2RlQXQoKytpKSk8PDI0LHQ9MTU0MDQ4MzQ3NyooNjU1MzUmdCkrKCgxNTQwNDgzNDc3Kih0Pj4+MTYpJjY1NTM1KTw8MTYpLHRePXQ+Pj4yNCx0PTE1NDA0ODM0NzcqKDY1NTM1JnQpKygoMTU0MDQ4MzQ3NyoodD4+PjE2KSY2NTUzNSk8PDE2KSxyPTE1NDA0ODM0NzcqKDY1NTM1JnIpKygoMTU0MDQ4MzQ3Nyoocj4+PjE2KSY2NTUzNSk8PDE2KV50LG4tPTQsKytpO3N3aXRjaChuKXtjYXNlIDM6cl49KDI1NSZlLmNoYXJDb2RlQXQoaSsyKSk8PDE2O2Nhc2UgMjpyXj0oMjU1JmUuY2hhckNvZGVBdChpKzEpKTw8ODtjYXNlIDE6cl49MjU1JmUuY2hhckNvZGVBdChpKSxyPTE1NDA0ODM0NzcqKDY1NTM1JnIpKygoMTU0MDQ4MzQ3Nyoocj4+PjE2KSY2NTUzNSk8PDE2KX1yZXR1cm4gcl49cj4+PjEzLCgocj0xNTQwNDgzNDc3Kig2NTUzNSZyKSsoKDE1NDA0ODM0NzcqKHI+Pj4xNikmNjU1MzUpPDwxNikpXnI+Pj4xNSk+Pj4wfWZ1bmN0aW9uIGYoZSl7dmFyIHQ9IiIsbj12b2lkIDA7Zm9yKG49ZTtuPmplO249TWF0aC5mbG9vcihuL2plKSl0PVJlKG4lamUpK3Q7cmV0dXJuIFJlKG4lamUpK3R9ZnVuY3Rpb24gZChlLHQpe2Zvcih2YXIgbj0wO248ZS5sZW5ndGg7bis9MSl7dmFyIHI9ZVtuXTtpZihBcnJheS5pc0FycmF5KHIpJiYhZChyKSlyZXR1cm4hMTtpZihpKHIpJiYhYShyKSlyZXR1cm4hMX1pZih2b2lkIDAhPT10KWZvcih2YXIgbyBpbiB0KXt2YXIgcz10W29dO2lmKGkocykpcmV0dXJuITF9cmV0dXJuITB9ZnVuY3Rpb24gaChlKXtyZXR1cm4gZS5yZXBsYWNlKEdlLCItIikucmVwbGFjZShWZSwiIil9ZnVuY3Rpb24gbShlKXtyZXR1cm4ic3RyaW5nIj09PXR5cGVvZiBlfWZ1bmN0aW9uIGcoZSl7cmV0dXJuIG0oZSk/InN0eWxlZC4iK2U6IlN0eWxlZCgiK28oZSkrIikifWZ1bmN0aW9uIHkoZSx0LG4pe2lmKCJzdHJpbmciIT09dHlwZW9mIHQpe3ZhciByPVplKHQpO3ImJnIhPT1ldCYmeShlLHIsbik7Zm9yKHZhciBpPXR0LmNvbmNhdChLZSh0KSxZZSh0KSksbz1XZVtlLiQkdHlwZW9mXXx8cWUsYT1XZVt0LiQkdHlwZW9mXXx8cWUscz1pLmxlbmd0aCx1PXZvaWQgMCxjPXZvaWQgMDtzLS07KWlmKGM9aVtzXSwhSGVbY10mJighbnx8IW5bY10pJiYoIWF8fCFhW2NdKSYmKCFvfHwhb1tjXSkmJih1PVhlKHQsYykpKXRyeXtRZShlLGMsdSl9Y2F0Y2goZSl7fXJldHVybiBlfXJldHVybiBlfWZ1bmN0aW9uIHYoZSl7cmV0dXJuISEoZSYmZS5wcm90b3R5cGUmJmUucHJvdG90eXBlLmlzUmVhY3RDb21wb25lbnQpfWZ1bmN0aW9uIGIoZSx0LG4pe3ZhciByPSJzdHJpbmciIT09dHlwZW9mIHQ/InNjIjpoKHQpLGk9KGN0W3JdfHwwKSsxO2N0W3JdPWk7dmFyIG89cisiLSIrZS5nZW5lcmF0ZU5hbWUocitpKTtyZXR1cm4gbj9uKyItIitvOm99ZnVuY3Rpb24geChlLHQsbil7dmFyIHI9YShlKSxpPSFtKGUpLHM9dC5kaXNwbGF5TmFtZSx1PXZvaWQgMD09PXM/ZyhlKTpzLGM9dC5jb21wb25lbnRJZCxsPXZvaWQgMD09PWM/YihVZSx0LmRpc3BsYXlOYW1lLHQucGFyZW50Q29tcG9uZW50SWQpOmMscD10LlBhcmVudENvbXBvbmVudCxmPXZvaWQgMD09PXA/bHQ6cCxkPXQuYXR0cnMsdj10LmRpc3BsYXlOYW1lJiZ0LmNvbXBvbmVudElkP2godC5kaXNwbGF5TmFtZSkrIi0iK3QuY29tcG9uZW50SWQ6dC5jb21wb25lbnRJZHx8bCxDPXImJmUuYXR0cnM/Uih7fSxlLmF0dHJzLGQpOmQsRT1uZXcgVWUocj9lLmNvbXBvbmVudFN0eWxlLnJ1bGVzLmNvbmNhdChuKTpuLEMsdiksRD1fLmEuZm9yd2FyZFJlZihmdW5jdGlvbihlLHQpe3JldHVybiBfLmEuY3JlYXRlRWxlbWVudChmLFIoe30sZSx7Zm9yd2FyZGVkQ2xhc3M6RCxmb3J3YXJkZWRSZWY6dH0pKX0pO3JldHVybiBELmF0dHJzPUMsRC5jb21wb25lbnRTdHlsZT1FLEQuZGlzcGxheU5hbWU9dSxELnN0eWxlZENvbXBvbmVudElkPXYsRC50YXJnZXQ9cj9lLnRhcmdldDplLEQud2l0aENvbXBvbmVudD1mdW5jdGlvbihlKXt2YXIgcj10LmNvbXBvbmVudElkLGk9JCh0LFsiY29tcG9uZW50SWQiXSksYT1yJiZyKyItIisobShlKT9lOmgobyhlKSkpO3JldHVybiB4KGUsUih7fSxpLHthdHRyczpDLGNvbXBvbmVudElkOmEsUGFyZW50Q29tcG9uZW50OmZ9KSxuKX0saSYmeShELGUse2F0dHJzOiEwLGNvbXBvbmVudFN0eWxlOiEwLGRpc3BsYXlOYW1lOiEwLHN0eWxlZENvbXBvbmVudElkOiEwLHRhcmdldDohMCx3YXJuVG9vTWFueUNsYXNzZXM6ITAsd2l0aENvbXBvbmVudDohMH0pLER9ZnVuY3Rpb24gQyhlKXtmb3IodmFyIHQ9YXJndW1lbnRzLmxlbmd0aCxuPUFycmF5KHQ+MT90LTE6MCkscj0xO3I8dDtyKyspbltyLTFdPWFyZ3VtZW50c1tyXTt2YXIgaT1jLmFwcGx5KHZvaWQgMCxbZV0uY29uY2F0KG4pKSxvPSJzYy1nbG9iYWwtIitwKEpTT04uc3RyaW5naWZ5KGkpKSxhPW5ldyBkdChpLG8pLHM9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe00odGhpcyx0KTt2YXIgbj1VKHRoaXMsZS5jYWxsKHRoaXMpKSxyPW4uY29uc3RydWN0b3IsaT1yLmdsb2JhbFN0eWxlLG89ci5zdHlsZWRDb21wb25lbnRJZDtyZXR1cm4gSCYmKHdpbmRvdy5zY0NHU0hNUkNhY2hlW29dPSh3aW5kb3cuc2NDR1NITVJDYWNoZVtvXXx8MCkrMSksbi5zdGF0ZT17Z2xvYmFsU3R5bGU6aSxzdHlsZWRDb21wb25lbnRJZDpvfSxufXJldHVybiBCKHQsZSksdC5wcm90b3R5cGUuY29tcG9uZW50RGlkTW91bnQ9ZnVuY3Rpb24oKXt9LHQucHJvdG90eXBlLmNvbXBvbmVudFdpbGxVbm1vdW50PWZ1bmN0aW9uKCl7d2luZG93LnNjQ0dTSE1SQ2FjaGVbdGhpcy5zdGF0ZS5zdHlsZWRDb21wb25lbnRJZF0mJih3aW5kb3cuc2NDR1NITVJDYWNoZVt0aGlzLnN0YXRlLnN0eWxlZENvbXBvbmVudElkXS09MSksMD09PXdpbmRvdy5zY0NHU0hNUkNhY2hlW3RoaXMuc3RhdGUuc3R5bGVkQ29tcG9uZW50SWRdJiZ0aGlzLnN0YXRlLmdsb2JhbFN0eWxlLnJlbW92ZVN0eWxlcyh0aGlzLnN0eWxlU2hlZXQpfSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzO3JldHVybiBfLmEuY3JlYXRlRWxlbWVudChzdCxudWxsLGZ1bmN0aW9uKHQpe2Uuc3R5bGVTaGVldD10fHxGZS5tYXN0ZXI7dmFyIG49ZS5zdGF0ZS5nbG9iYWxTdHlsZTtyZXR1cm4gbi5pc1N0YXRpYz8obi5yZW5kZXJTdHlsZXMoVyxlLnN0eWxlU2hlZXQpLG51bGwpOl8uYS5jcmVhdGVFbGVtZW50KHJ0LG51bGwsZnVuY3Rpb24odCl7dmFyIHI9ZS5jb25zdHJ1Y3Rvci5kZWZhdWx0UHJvcHMsaT1SKHt9LGUucHJvcHMpO3JldHVybiJ1bmRlZmluZWQiIT09dHlwZW9mIHQmJihpLnRoZW1lPXplKGUucHJvcHMsdCxyKSksbi5yZW5kZXJTdHlsZXMoaSxlLnN0eWxlU2hlZXQpLG51bGx9KX0pfSx0fShfLmEuQ29tcG9uZW50KTtyZXR1cm4gcy5nbG9iYWxTdHlsZT1hLHMuc3R5bGVkQ29tcG9uZW50SWQ9byxzfWZ1bmN0aW9uIEUoZSl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsbj1BcnJheSh0PjE/dC0xOjApLHI9MTtyPHQ7cisrKW5bci0xXT1hcmd1bWVudHNbcl07dmFyIGk9Yy5hcHBseSh2b2lkIDAsW2VdLmNvbmNhdChuKSksbz1mKHAoaHQoSlNPTi5zdHJpbmdpZnkoaSkpKSk7cmV0dXJuIG5ldyBOZShvLGllKGksbywiQGtleWZyYW1lcyIpKX1uLmQodCwiY3NzIixmdW5jdGlvbigpe3JldHVybiBjfSksbi5kKHQsImtleWZyYW1lcyIsZnVuY3Rpb24oKXtyZXR1cm4gRX0pLG4uZCh0LCJjcmVhdGVHbG9iYWxTdHlsZSIsZnVuY3Rpb24oKXtyZXR1cm4gQ30pLG4uZCh0LCJpc1N0eWxlZENvbXBvbmVudCIsZnVuY3Rpb24oKXtyZXR1cm4gYX0pLG4uZCh0LCJUaGVtZUNvbnN1bWVyIixmdW5jdGlvbigpe3JldHVybiBydH0pLG4uZCh0LCJUaGVtZVByb3ZpZGVyIixmdW5jdGlvbigpe3JldHVybiBpdH0pLG4uZCh0LCJ3aXRoVGhlbWUiLGZ1bmN0aW9uKCl7cmV0dXJuIG10fSksbi5kKHQsIlNlcnZlclN0eWxlU2hlZXQiLGZ1bmN0aW9uKCl7cmV0dXJuIG90fSksbi5kKHQsIlN0eWxlU2hlZXRNYW5hZ2VyIixmdW5jdGlvbigpe3JldHVybiB1dH0pLG4uZCh0LCJfX0RPX05PVF9VU0VfT1JfWU9VX1dJTExfQkVfSEFVTlRFRF9CWV9TUE9PS1lfR0hPU1RTIixmdW5jdGlvbigpe3JldHVybiBndH0pO3ZhciBEPW4oNTI1KSx3PW4ubihEKSxTPW4oNTI2KSxrPW4ubihTKSxBPW4oMCksXz1uLm4oQSksVD1uKDUyNyksTz0obi5uKFQpLG4oNTI5KSksRj1uKDE4KSxOPShuLm4oRiksbigzMCkpLEk9KG4ubihOKSxuKDUzMCkpLEw9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG49W2VbMF1dLHI9MCxpPXQubGVuZ3RoO3I8aTtyKz0xKW4ucHVzaCh0W3JdLGVbcisxXSk7cmV0dXJuIG59LFA9ImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJiJzeW1ib2wiPT09dHlwZW9mIFN5bWJvbC5pdGVyYXRvcj9mdW5jdGlvbihlKXtyZXR1cm4gdHlwZW9mIGV9OmZ1bmN0aW9uKGUpe3JldHVybiBlJiYiZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmZS5jb25zdHJ1Y3Rvcj09PVN5bWJvbCYmZSE9PVN5bWJvbC5wcm90b3R5cGU/InN5bWJvbCI6dHlwZW9mIGV9LE09ZnVuY3Rpb24oZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX0saj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXtmb3IodmFyIG49MDtuPHQubGVuZ3RoO24rKyl7dmFyIHI9dFtuXTtyLmVudW1lcmFibGU9ci5lbnVtZXJhYmxlfHwhMSxyLmNvbmZpZ3VyYWJsZT0hMCwidmFsdWUiaW4gciYmKHIud3JpdGFibGU9ITApLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIua2V5LHIpfX1yZXR1cm4gZnVuY3Rpb24odCxuLHIpe3JldHVybiBuJiZlKHQucHJvdG90eXBlLG4pLHImJmUodCxyKSx0fX0oKSxSPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0xO3Q8YXJndW1lbnRzLmxlbmd0aDt0Kyspe3ZhciBuPWFyZ3VtZW50c1t0XTtmb3IodmFyIHIgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobixyKSYmKGVbcl09bltyXSl9cmV0dXJuIGV9LEI9ZnVuY3Rpb24oZSx0KXtpZigiZnVuY3Rpb24iIT09dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIlN1cGVyIGV4cHJlc3Npb24gbXVzdCBlaXRoZXIgYmUgbnVsbCBvciBhIGZ1bmN0aW9uLCBub3QgIit0eXBlb2YgdCk7ZS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZSh0JiZ0LnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOmUsZW51bWVyYWJsZTohMSx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9fSksdCYmKE9iamVjdC5zZXRQcm90b3R5cGVPZj9PYmplY3Quc2V0UHJvdG90eXBlT2YoZSx0KTplLl9fcHJvdG9fXz10KX0sJD1mdW5jdGlvbihlLHQpe3ZhciBuPXt9O2Zvcih2YXIgciBpbiBlKXQuaW5kZXhPZihyKT49MHx8T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUscikmJihuW3JdPWVbcl0pO3JldHVybiBufSxVPWZ1bmN0aW9uKGUsdCl7aWYoIWUpdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKCJ0aGlzIGhhc24ndCBiZWVuIGluaXRpYWxpc2VkIC0gc3VwZXIoKSBoYXNuJ3QgYmVlbiBjYWxsZWQiKTtyZXR1cm4hdHx8Im9iamVjdCIhPT10eXBlb2YgdCYmImZ1bmN0aW9uIiE9PXR5cGVvZiB0P2U6dH0sej1mdW5jdGlvbihlKXtyZXR1cm4ib2JqZWN0Ij09PSgidW5kZWZpbmVkIj09PXR5cGVvZiBlPyJ1bmRlZmluZWQiOlAoZSkpJiZlLmNvbnN0cnVjdG9yPT09T2JqZWN0fSxHPU9iamVjdC5mcmVlemUoW10pLFY9T2JqZWN0LmZyZWV6ZSh7fSkscT0idW5kZWZpbmVkIiE9PXR5cGVvZiBlJiZPYmplY3Qoe05PREVfRU5WOiJwcm9kdWN0aW9uIixQVUJMSUNfVVJMOiIifSkuU0NfQVRUUnx8ImRhdGEtc3R5bGVkIixIPSJ1bmRlZmluZWQiIT09dHlwZW9mIHdpbmRvdyYmIkhUTUxFbGVtZW50ImluIHdpbmRvdyxXPXt9LFE9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChuKXtNKHRoaXMsdCk7Zm9yKHZhciByPWFyZ3VtZW50cy5sZW5ndGgsaT1BcnJheShyPjE/ci0xOjApLG89MTtvPHI7bysrKWlbby0xXT1hcmd1bWVudHNbb107dmFyIGEsYT1VKHRoaXMsZS5jYWxsKHRoaXMsIkFuIGVycm9yIG9jY3VycmVkLiBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3N0eWxlZC1jb21wb25lbnRzL3N0eWxlZC1jb21wb25lbnRzL2Jsb2IvbWFzdGVyL3NyYy91dGlscy9lcnJvcnMubWQjIituKyIgZm9yIG1vcmUgaW5mb3JtYXRpb24uICIrKGk/IkFkZGl0aW9uYWwgYXJndW1lbnRzOiAiK2kuam9pbigiLCAiKToiIikpKTtyZXR1cm4gVShhKX1yZXR1cm4gQih0LGUpLHR9KEVycm9yKSxLPS9eW15cU1xuXSo/XC9cKiBzYy1jb21wb25lbnQtaWQ6XHMqKFxTKylccytcKlwvL2dtLEo9ZnVuY3Rpb24oZSl7dmFyIHQ9IiIrKGV8fCIiKSxuPVtdO3JldHVybiB0LnJlcGxhY2UoSyxmdW5jdGlvbihlLHQscil7cmV0dXJuIG4ucHVzaCh7Y29tcG9uZW50SWQ6dCxtYXRjaEluZGV4OnJ9KSxlfSksbi5tYXAoZnVuY3Rpb24oZSxyKXt2YXIgaT1lLmNvbXBvbmVudElkLG89ZS5tYXRjaEluZGV4LGE9bltyKzFdO3JldHVybntjb21wb25lbnRJZDppLGNzc0Zyb21ET006YT90LnNsaWNlKG8sYS5tYXRjaEluZGV4KTp0LnNsaWNlKG8pfX0pfSxZPS9eXHMqXC9cLy4qJC9nbSxYPS8oJig/ISAqWyt+Pl0pKFteJntdW157XSspW14rfj5dKik/KFsrfj5dICopJi9nLFo9bmV3IHcuYSh7Z2xvYmFsOiExLGNhc2NhZGU6ITAsa2V5ZnJhbWU6ITEscHJlZml4OiExLGNvbXByZXNzOiExLHNlbWljb2xvbjohMH0pLGVlPW5ldyB3LmEoe2dsb2JhbDohMSxjYXNjYWRlOiEwLGtleWZyYW1lOiExLHByZWZpeDohMCxjb21wcmVzczohMSxzZW1pY29sb246ITF9KSx0ZT1bXSxuZT1mdW5jdGlvbihlKXtpZigtMj09PWUpe3ZhciB0PXRlO3JldHVybiB0ZT1bXSx0fX0scmU9aygpKGZ1bmN0aW9uKGUpe3RlLnB1c2goZSl9KTtlZS51c2UoW3JlLG5lXSksWi51c2UoW3JlLG5lXSk7dmFyIGllPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1hcmd1bWVudHMubGVuZ3RoPjMmJnZvaWQgMCE9PWFyZ3VtZW50c1szXT9hcmd1bWVudHNbM106IiYiLGk9ZS5qb2luKCIiKS5yZXBsYWNlKFksIiIpLG89KHQmJm4/bisiICIrdCsiIHsgIitpKyIgfSI6aSkucmVwbGFjZShYLCIkMSQzLiIrcisiJDIiKTtyZXR1cm4gZWUobnx8IXQ/IiI6dCxvKX0sb2U9ZnVuY3Rpb24oZSl7cmV0dXJuIFooIiIsZSl9LGFlPWZ1bmN0aW9uKCl7cmV0dXJuIG4ubmN9LHNlPWZ1bmN0aW9uKGUpe3ZhciB0PSExO3JldHVybiBmdW5jdGlvbigpe3R8fCh0PSEwLGUoKSl9fSx1ZT1mdW5jdGlvbihlLHQsbil7aWYobil7KGVbdF18fChlW3RdPU9iamVjdC5jcmVhdGUobnVsbCkpKVtuXT0hMH19LGNlPWZ1bmN0aW9uKGUsdCl7ZVt0XT1PYmplY3QuY3JlYXRlKG51bGwpfSxsZT1mdW5jdGlvbihlKXtyZXR1cm4gZnVuY3Rpb24odCxuKXtyZXR1cm4gdm9pZCAwIT09ZVt0XSYmZVt0XVtuXX19LHBlPWZ1bmN0aW9uKGUpe3ZhciB0PSIiO2Zvcih2YXIgbiBpbiBlKXQrPU9iamVjdC5rZXlzKGVbbl0pLmpvaW4oIiAiKSsiICI7cmV0dXJuIHQudHJpbSgpfSxmZT1mdW5jdGlvbihlKXt2YXIgdD1PYmplY3QuY3JlYXRlKG51bGwpO2Zvcih2YXIgbiBpbiBlKXRbbl09Uih7fSxlW25dKTtyZXR1cm4gdH0sZGU9ZnVuY3Rpb24oZSl7aWYoZS5zaGVldClyZXR1cm4gZS5zaGVldDtmb3IodmFyIHQ9ZG9jdW1lbnQuc3R5bGVTaGVldHMubGVuZ3RoLG49MDtuPHQ7bis9MSl7dmFyIHI9ZG9jdW1lbnQuc3R5bGVTaGVldHNbbl07aWYoci5vd25lck5vZGU9PT1lKXJldHVybiByfXRocm93IG5ldyBRKDEwKX0saGU9ZnVuY3Rpb24oZSx0LG4pe2lmKCF0KXJldHVybiExO3ZhciByPWUuY3NzUnVsZXMubGVuZ3RoO3RyeXtlLmluc2VydFJ1bGUodCxuPD1yP246cil9Y2F0Y2goZSl7cmV0dXJuITF9cmV0dXJuITB9LG1lPWZ1bmN0aW9uKGUsdCxuKXtmb3IodmFyIHI9dC1uLGk9dDtpPnI7aS09MSllLmRlbGV0ZVJ1bGUoaSl9LGdlPWZ1bmN0aW9uKGUpe3JldHVybiJcbi8qIHNjLWNvbXBvbmVudC1pZDogIitlKyIgKi9cbiJ9LHllPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPTAscj0wO3I8PXQ7cis9MSluKz1lW3JdO3JldHVybiBufSx2ZT1mdW5jdGlvbihlLHQsbil7dmFyIHI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic3R5bGUiKTtyLnNldEF0dHJpYnV0ZShxLCIiKSxyLnNldEF0dHJpYnV0ZSgiZGF0YS1zdHlsZWQtdmVyc2lvbiIsIjQuMC4wIik7dmFyIGk9YWUoKTtpZihpJiZyLnNldEF0dHJpYnV0ZSgibm9uY2UiLGkpLHIuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIiIpKSxlJiYhdCllLmFwcGVuZENoaWxkKHIpO2Vsc2V7aWYoIXR8fCFlfHwhdC5wYXJlbnROb2RlKXRocm93IG5ldyBRKDYpO3QucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUocixuP3Q6dC5uZXh0U2libGluZyl9cmV0dXJuIHJ9LGJlPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKG4pe3ZhciByPWFlKCk7cmV0dXJuIjxzdHlsZSAiK1tyJiYnbm9uY2U9IicrcisnIicscSsnPSInK3BlKHQpKyciJywnZGF0YS1zdHlsZWQtdmVyc2lvbj0iNC4wLjAiJyxuXS5maWx0ZXIoQm9vbGVhbikuam9pbigiICIpKyI+IitlKCkrIjwvc3R5bGU+In19LHhlPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIG4scj0obj17fSxuW3FdPXBlKHQpLG5bImRhdGEtc3R5bGVkLXZlcnNpb24iXT0iNC4wLjAiLG4pLGk9YWUoKTtyZXR1cm4gaSYmKHIubm9uY2U9aSksXy5hLmNyZWF0ZUVsZW1lbnQoInN0eWxlIixSKHt9LHIse2Rhbmdlcm91c2x5U2V0SW5uZXJIVE1MOntfX2h0bWw6ZSgpfX0pKX19LENlPWZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiBPYmplY3Qua2V5cyhlKX19LEVlPWZ1bmN0aW9uKGUsdCl7dmFyIG49T2JqZWN0LmNyZWF0ZShudWxsKSxyPU9iamVjdC5jcmVhdGUobnVsbCksaT1bXSxvPXZvaWQgMCE9PXQsYT0hMSxzPWZ1bmN0aW9uKGUpe3ZhciB0PXJbZV07cmV0dXJuIHZvaWQgMCE9PXQ/dDoocltlXT1pLmxlbmd0aCxpLnB1c2goMCksY2UobixlKSxyW2VdKX0sdT1mdW5jdGlvbihyLHUsYyl7Zm9yKHZhciBsPXMocikscD1kZShlKSxmPXllKGksbCksZD0wLGg9W10sbT11Lmxlbmd0aCxnPTA7ZzxtO2crPTEpe3ZhciB5PXVbZ10sdj1vO3YmJi0xIT09eS5pbmRleE9mKCJAaW1wb3J0Iik/aC5wdXNoKHkpOmhlKHAseSxmK2QpJiYodj0hMSxkKz0xKX1vJiZoLmxlbmd0aD4wJiYoYT0hMCx0KCkuaW5zZXJ0UnVsZXMocisiLWltcG9ydCIsaCkpLGlbbF0rPWQsdWUobixyLGMpfSxjPWZ1bmN0aW9uKHMpe3ZhciB1PXJbc107aWYodm9pZCAwIT09dSl7dmFyIGM9aVt1XSxsPWRlKGUpLHA9eWUoaSx1KS0xO21lKGwscCxjKSxpW3VdPTAsY2UobixzKSxvJiZhJiZ0KCkucmVtb3ZlUnVsZXMocysiLWltcG9ydCIpfX0sbD1mdW5jdGlvbigpe3ZhciB0PWRlKGUpLG49dC5jc3NSdWxlcyxvPSIiO2Zvcih2YXIgYSBpbiByKXtvKz1nZShhKTtmb3IodmFyIHM9clthXSx1PXllKGkscyksYz1pW3NdLGw9dS1jO2w8dTtsKz0xKXt2YXIgcD1uW2xdO3ZvaWQgMCE9PXAmJihvKz1wLmNzc1RleHQpfX1yZXR1cm4gb307cmV0dXJue2Nsb25lOmZ1bmN0aW9uKCl7dGhyb3cgbmV3IFEoNSl9LGNzczpsLGdldElkczpDZShyKSxoYXNOYW1lRm9ySWQ6bGUobiksaW5zZXJ0TWFya2VyOnMsaW5zZXJ0UnVsZXM6dSxyZW1vdmVSdWxlczpjLHNlYWxlZDohMSxzdHlsZVRhZzplLHRvRWxlbWVudDp4ZShsLG4pLHRvSFRNTDpiZShsLG4pfX0sRGU9ZnVuY3Rpb24gZSh0LG4pe3ZhciByPXZvaWQgMD09PXQ/T2JqZWN0LmNyZWF0ZShudWxsKTp0LGk9dm9pZCAwPT09bj9PYmplY3QuY3JlYXRlKG51bGwpOm4sbz1mdW5jdGlvbihlKXt2YXIgdD1pW2VdO3JldHVybiB2b2lkIDAhPT10P3Q6aVtlXT1bIiJdfSxhPWZ1bmN0aW9uKGUsdCxuKXtvKGUpWzBdKz10LmpvaW4oIiAiKSx1ZShyLGUsbil9LHM9ZnVuY3Rpb24oZSl7dmFyIHQ9aVtlXTt2b2lkIDAhPT10JiYodFswXT0iIixjZShyLGUpKX0sdT1mdW5jdGlvbigpe3ZhciBlPSIiO2Zvcih2YXIgdCBpbiBpKXt2YXIgbj1pW3RdWzBdO24mJihlKz1nZSh0KStuKX1yZXR1cm4gZX07cmV0dXJue2Nsb25lOmZ1bmN0aW9uKCl7dmFyIHQ9ZmUociksbj1PYmplY3QuY3JlYXRlKG51bGwpO2Zvcih2YXIgbyBpbiBpKW5bb109W2lbb11bMF1dO3JldHVybiBlKHQsbil9LGNzczp1LGdldElkczpDZShpKSxoYXNOYW1lRm9ySWQ6bGUociksaW5zZXJ0TWFya2VyOm8saW5zZXJ0UnVsZXM6YSxyZW1vdmVSdWxlczpzLHNlYWxlZDohMSxzdHlsZVRhZzpudWxsLHRvRWxlbWVudDp4ZSh1LHIpLHRvSFRNTDpiZSh1LHIpfX0sd2U9ZnVuY3Rpb24oZSx0LG4scixpKXtpZihIJiYhbil7dmFyIG89dmUoZSx0LHIpO3JldHVybiBFZShvLGkpfXJldHVybiBEZSgpfSxTZT1mdW5jdGlvbihlLHQsbixyKXt2YXIgaT1zZShmdW5jdGlvbigpe2Zvcih2YXIgcj0wLGk9bi5sZW5ndGg7cjxpO3IrPTEpe3ZhciBvPW5bcl0sYT1vLmNvbXBvbmVudElkLHM9by5jc3NGcm9tRE9NLHU9b2Uocyk7ZS5pbnNlcnRSdWxlcyhhLHUpfWZvcih2YXIgYz0wLGw9dC5sZW5ndGg7YzxsO2MrPTEpe3ZhciBwPXRbY107cC5wYXJlbnROb2RlJiZwLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQocCl9fSk7cmV0dXJuIHImJmkoKSxSKHt9LGUse2luc2VydE1hcmtlcjpmdW5jdGlvbih0KXtyZXR1cm4gaSgpLGUuaW5zZXJ0TWFya2VyKHQpfSxpbnNlcnRSdWxlczpmdW5jdGlvbih0LG4scil7cmV0dXJuIGkoKSxlLmluc2VydFJ1bGVzKHQsbixyKX0scmVtb3ZlUnVsZXM6ZnVuY3Rpb24odCl7cmV0dXJuIGkoKSxlLnJlbW92ZVJ1bGVzKHQpfX0pfSxrZT0vXHMrLyxBZT12b2lkIDA7QWU9SD8xZTM6LTE7dmFyIF9lLFRlPTAsT2U9dm9pZCAwLEZlPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3ZhciB0PXRoaXMsbj1hcmd1bWVudHMubGVuZ3RoPjAmJnZvaWQgMCE9PWFyZ3VtZW50c1swXT9hcmd1bWVudHNbMF06SD9kb2N1bWVudC5oZWFkOm51bGwscj1hcmd1bWVudHMubGVuZ3RoPjEmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXSYmYXJndW1lbnRzWzFdO00odGhpcyxlKSx0aGlzLmdldEltcG9ydFJ1bGVUYWc9ZnVuY3Rpb24oKXt2YXIgZT10LmltcG9ydFJ1bGVUYWc7aWYodm9pZCAwIT09ZSlyZXR1cm4gZTt2YXIgbj10LnRhZ3NbMF07cmV0dXJuIHQuaW1wb3J0UnVsZVRhZz13ZSh0LnRhcmdldCxuP24uc3R5bGVUYWc6bnVsbCx0LmZvcmNlU2VydmVyLCEwKX0sVGUrPTEsdGhpcy5pZD1UZSx0aGlzLmZvcmNlU2VydmVyPXIsdGhpcy50YXJnZXQ9cj9udWxsOm4sdGhpcy50YWdNYXA9e30sdGhpcy5kZWZlcnJlZD17fSx0aGlzLnJlaHlkcmF0ZWROYW1lcz17fSx0aGlzLmlnbm9yZVJlaHlkcmF0ZWROYW1lcz17fSx0aGlzLnRhZ3M9W10sdGhpcy5jYXBhY2l0eT0xLHRoaXMuY2xvbmVzPVtdfXJldHVybiBlLnByb3RvdHlwZS5yZWh5ZHJhdGU9ZnVuY3Rpb24oKXtpZighSHx8dGhpcy5mb3JjZVNlcnZlcilyZXR1cm4gdGhpczt2YXIgZT1bXSx0PVtdLG49ITEscj1kb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCJzdHlsZVsiK3ErJ11bZGF0YS1zdHlsZWQtdmVyc2lvbj0iNC4wLjAiXScpLGk9ci5sZW5ndGg7aWYoMD09PWkpcmV0dXJuIHRoaXM7Zm9yKHZhciBvPTA7bzxpO28rPTEpe3ZhciBhPXJbb107bnx8KG49ISFhLmdldEF0dHJpYnV0ZSgiZGF0YS1zdHlsZWQtc3RyZWFtZWQiKSk7Zm9yKHZhciBzPShhLmdldEF0dHJpYnV0ZShxKXx8IiIpLnRyaW0oKS5zcGxpdChrZSksdT1zLmxlbmd0aCxjPTA7Yzx1O2MrPTEpe3ZhciBsPXNbY107dGhpcy5yZWh5ZHJhdGVkTmFtZXNbbF09ITB9dC5wdXNoLmFwcGx5KHQsSihhLnRleHRDb250ZW50KSksZS5wdXNoKGEpfXZhciBwPXQubGVuZ3RoO2lmKDA9PT1wKXJldHVybiB0aGlzO3ZhciBmPXRoaXMubWFrZVRhZyhudWxsKSxkPVNlKGYsZSx0LG4pO3RoaXMuY2FwYWNpdHk9TWF0aC5tYXgoMSxBZS1wKSx0aGlzLnRhZ3MucHVzaChkKTtmb3IodmFyIGg9MDtoPHA7aCs9MSl0aGlzLnRhZ01hcFt0W2hdLmNvbXBvbmVudElkXT1kO3JldHVybiB0aGlzfSxlLnJlc2V0PWZ1bmN0aW9uKCl7dmFyIHQ9YXJndW1lbnRzLmxlbmd0aD4wJiZ2b2lkIDAhPT1hcmd1bWVudHNbMF0mJmFyZ3VtZW50c1swXTtPZT1uZXcgZSh2b2lkIDAsdCkucmVoeWRyYXRlKCl9LGUucHJvdG90eXBlLmNsb25lPWZ1bmN0aW9uKCl7dmFyIHQ9bmV3IGUodGhpcy50YXJnZXQsdGhpcy5mb3JjZVNlcnZlcik7cmV0dXJuIHRoaXMuY2xvbmVzLnB1c2godCksdC50YWdzPXRoaXMudGFncy5tYXAoZnVuY3Rpb24oZSl7Zm9yKHZhciBuPWUuZ2V0SWRzKCkscj1lLmNsb25lKCksaT0wO2k8bi5sZW5ndGg7aSs9MSl0LnRhZ01hcFtuW2ldXT1yO3JldHVybiByfSksdC5yZWh5ZHJhdGVkTmFtZXM9Uih7fSx0aGlzLnJlaHlkcmF0ZWROYW1lcyksdC5kZWZlcnJlZD1SKHt9LHRoaXMuZGVmZXJyZWQpLHR9LGUucHJvdG90eXBlLnNlYWxBbGxUYWdzPWZ1bmN0aW9uKCl7dGhpcy5jYXBhY2l0eT0xLHRoaXMudGFncy5mb3JFYWNoKGZ1bmN0aW9uKGUpe2Uuc2VhbGVkPSEwfSl9LGUucHJvdG90eXBlLm1ha2VUYWc9ZnVuY3Rpb24oZSl7dmFyIHQ9ZT9lLnN0eWxlVGFnOm51bGw7cmV0dXJuIHdlKHRoaXMudGFyZ2V0LHQsdGhpcy5mb3JjZVNlcnZlciwhMSx0aGlzLmdldEltcG9ydFJ1bGVUYWcpfSxlLnByb3RvdHlwZS5nZXRUYWdGb3JJZD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLnRhZ01hcFtlXTtpZih2b2lkIDAhPT10JiYhdC5zZWFsZWQpcmV0dXJuIHQ7dmFyIG49dGhpcy50YWdzW3RoaXMudGFncy5sZW5ndGgtMV07cmV0dXJuIHRoaXMuY2FwYWNpdHktPTEsMD09PXRoaXMuY2FwYWNpdHkmJih0aGlzLmNhcGFjaXR5PUFlLG49dGhpcy5tYWtlVGFnKG4pLHRoaXMudGFncy5wdXNoKG4pKSx0aGlzLnRhZ01hcFtlXT1ufSxlLnByb3RvdHlwZS5oYXNJZD1mdW5jdGlvbihlKXtyZXR1cm4gdm9pZCAwIT09dGhpcy50YWdNYXBbZV19LGUucHJvdG90eXBlLmhhc05hbWVGb3JJZD1mdW5jdGlvbihlLHQpe2lmKHZvaWQgMD09PXRoaXMuaWdub3JlUmVoeWRyYXRlZE5hbWVzW2VdJiZ0aGlzLnJlaHlkcmF0ZWROYW1lc1t0XSlyZXR1cm4hMDt2YXIgbj10aGlzLnRhZ01hcFtlXTtyZXR1cm4gdm9pZCAwIT09biYmbi5oYXNOYW1lRm9ySWQoZSx0KX0sZS5wcm90b3R5cGUuZGVmZXJyZWRJbmplY3Q9ZnVuY3Rpb24oZSx0KXtpZih2b2lkIDA9PT10aGlzLnRhZ01hcFtlXSl7Zm9yKHZhciBuPXRoaXMuY2xvbmVzLHI9MDtyPG4ubGVuZ3RoO3IrPTEpbltyXS5kZWZlcnJlZEluamVjdChlLHQpO3RoaXMuZ2V0VGFnRm9ySWQoZSkuaW5zZXJ0TWFya2VyKGUpLHRoaXMuZGVmZXJyZWRbZV09dH19LGUucHJvdG90eXBlLmluamVjdD1mdW5jdGlvbihlLHQsbil7Zm9yKHZhciByPXRoaXMuY2xvbmVzLGk9MDtpPHIubGVuZ3RoO2krPTEpcltpXS5pbmplY3QoZSx0LG4pO3ZhciBvPXRoaXMuZ2V0VGFnRm9ySWQoZSk7aWYodm9pZCAwIT09dGhpcy5kZWZlcnJlZFtlXSl7dmFyIGE9dGhpcy5kZWZlcnJlZFtlXS5jb25jYXQodCk7by5pbnNlcnRSdWxlcyhlLGEsbiksdGhpcy5kZWZlcnJlZFtlXT12b2lkIDB9ZWxzZSBvLmluc2VydFJ1bGVzKGUsdCxuKX0sZS5wcm90b3R5cGUucmVtb3ZlPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMudGFnTWFwW2VdO2lmKHZvaWQgMCE9PXQpe2Zvcih2YXIgbj10aGlzLmNsb25lcyxyPTA7cjxuLmxlbmd0aDtyKz0xKW5bcl0ucmVtb3ZlKGUpO3QucmVtb3ZlUnVsZXMoZSksdGhpcy5pZ25vcmVSZWh5ZHJhdGVkTmFtZXNbZV09ITAsdGhpcy5kZWZlcnJlZFtlXT12b2lkIDB9fSxlLnByb3RvdHlwZS50b0hUTUw9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy50YWdzLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS50b0hUTUwoKX0pLmpvaW4oIiIpfSxlLnByb3RvdHlwZS50b1JlYWN0RWxlbWVudHM9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmlkO3JldHVybiB0aGlzLnRhZ3MubWFwKGZ1bmN0aW9uKHQsbil7dmFyIHI9InNjLSIrZSsiLSIrbjtyZXR1cm4gT2JqZWN0KEEuY2xvbmVFbGVtZW50KSh0LnRvRWxlbWVudCgpLHtrZXk6cn0pfSl9LGooZSxudWxsLFt7a2V5OiJtYXN0ZXIiLGdldDpmdW5jdGlvbigpe3JldHVybiBPZXx8KE9lPShuZXcgZSkucmVoeWRyYXRlKCkpfX0se2tleToiaW5zdGFuY2UiLGdldDpmdW5jdGlvbigpe3JldHVybiBlLm1hc3Rlcn19XSksZX0oKSxOZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCxuKXt2YXIgcj10aGlzO00odGhpcyxlKSx0aGlzLmluamVjdD1mdW5jdGlvbihlKXtlLmhhc05hbWVGb3JJZChyLmlkLHIubmFtZSl8fGUuaW5qZWN0KHIuaWQsci5ydWxlcyxyLm5hbWUpfSx0aGlzLm5hbWU9dCx0aGlzLnJ1bGVzPW4sdGhpcy5pZD0ic2Mta2V5ZnJhbWVzLSIrdH1yZXR1cm4gZS5wcm90b3R5cGUuZ2V0TmFtZT1mdW5jdGlvbigpe3JldHVybiB0aGlzLm5hbWV9LGV9KCksSWU9LyhbQS1aXSkvZyxMZT0vXm1zLS8sUGU9ZnVuY3Rpb24gZSh0LG4pe3ZhciByPU9iamVjdC5rZXlzKHQpLmZpbHRlcihmdW5jdGlvbihlKXt2YXIgbj10W2VdO3JldHVybiB2b2lkIDAhPT1uJiZudWxsIT09biYmITEhPT1uJiYiIiE9PW59KS5tYXAoZnVuY3Rpb24obil7cmV0dXJuIHoodFtuXSk/ZSh0W25dLG4pOnMobikrIjogIit0W25dKyI7In0pLmpvaW4oIiAiKTtyZXR1cm4gbj9uKyIge1xuICAiK3IrIlxufSI6cn0sTWU9ZnVuY3Rpb24oZSl7cmV0dXJuIHZvaWQgMD09PWV8fG51bGw9PT1lfHwhMT09PWV8fCIiPT09ZX0samU9NTIsUmU9ZnVuY3Rpb24oZSl7cmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUoZSsoZT4yNT8zOTo5NykpfSxCZT0hMSwkZT1mdW5jdGlvbihlKXtyZXR1cm4gZihwKGUpKX0sVWU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQsbixyKXtpZihNKHRoaXMsZSksdGhpcy5ydWxlcz10LHRoaXMuaXNTdGF0aWM9IUJlJiZkKHQsbiksdGhpcy5jb21wb25lbnRJZD1yLCFGZS5tYXN0ZXIuaGFzSWQocikpe3ZhciBpPVtdO0ZlLm1hc3Rlci5kZWZlcnJlZEluamVjdChyLGkpfX1yZXR1cm4gZS5wcm90b3R5cGUuZ2VuZXJhdGVBbmRJbmplY3RTdHlsZXM9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLmlzU3RhdGljLHI9dGhpcy5jb21wb25lbnRJZCxpPXRoaXMubGFzdENsYXNzTmFtZTtpZihIJiZuJiZ2b2lkIDAhPT1pJiZ0Lmhhc05hbWVGb3JJZChyLGkpKXJldHVybiBpO3ZhciBvPXUodGhpcy5ydWxlcyxlLHQpLGE9JGUodGhpcy5jb21wb25lbnRJZCtvLmpvaW4oIiIpKTtyZXR1cm4gdC5oYXNOYW1lRm9ySWQocixhKXx8dC5pbmplY3QodGhpcy5jb21wb25lbnRJZCxpZShvLCIuIithLHZvaWQgMCxyKSxhKSx0aGlzLmxhc3RDbGFzc05hbWU9YSxhfSxlLmdlbmVyYXRlTmFtZT1mdW5jdGlvbihlKXtyZXR1cm4gJGUoZSl9LGV9KCksemU9ZnVuY3Rpb24oZSx0KXt2YXIgbj1hcmd1bWVudHMubGVuZ3RoPjImJnZvaWQgMCE9PWFyZ3VtZW50c1syXT9hcmd1bWVudHNbMl06VixyPSEhbiYmZS50aGVtZT09PW4udGhlbWU7cmV0dXJuIGUudGhlbWUmJiFyP2UudGhlbWU6dHx8bi50aGVtZX0sR2U9L1tbXF0uIyokPjwrfj18XjooKSwiJ2AtXSsvZyxWZT0vKF4tfC0kKS9nLHFlPXtjaGlsZENvbnRleHRUeXBlczohMCxjb250ZXh0VHlwZXM6ITAsZGVmYXVsdFByb3BzOiEwLGRpc3BsYXlOYW1lOiEwLGdldERlcml2ZWRTdGF0ZUZyb21Qcm9wczohMCxwcm9wVHlwZXM6ITAsdHlwZTohMH0sSGU9e25hbWU6ITAsbGVuZ3RoOiEwLHByb3RvdHlwZTohMCxjYWxsZXI6ITAsY2FsbGVlOiEwLGFyZ3VtZW50czohMCxhcml0eTohMH0sV2U9KF9lPXt9LF9lW1QuRm9yd2FyZFJlZl09eyQkdHlwZW9mOiEwLHJlbmRlcjohMH0sX2UpLFFlPU9iamVjdC5kZWZpbmVQcm9wZXJ0eSxLZT1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyxKZT1PYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzLFllPXZvaWQgMD09PUplP2Z1bmN0aW9uKCl7cmV0dXJuW119OkplLFhlPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IsWmU9T2JqZWN0LmdldFByb3RvdHlwZU9mLGV0PU9iamVjdC5wcm90b3R5cGUsdHQ9QXJyYXkucHJvdG90eXBlLG50PU9iamVjdChBLmNyZWF0ZUNvbnRleHQpKCkscnQ9bnQuQ29uc3VtZXIsaXQ9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChuKXtNKHRoaXMsdCk7dmFyIHI9VSh0aGlzLGUuY2FsbCh0aGlzLG4pKTtyZXR1cm4gci5nZXRDb250ZXh0PU9iamVjdChPLmEpKHIuZ2V0Q29udGV4dC5iaW5kKHIpKSxyLnJlbmRlcklubmVyPXIucmVuZGVySW5uZXIuYmluZChyKSxyfXJldHVybiBCKHQsZSksdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucHJvcHMuY2hpbGRyZW4/Xy5hLmNyZWF0ZUVsZW1lbnQobnQuQ29uc3VtZXIsbnVsbCx0aGlzLnJlbmRlcklubmVyKTpudWxsfSx0LnByb3RvdHlwZS5yZW5kZXJJbm5lcj1mdW5jdGlvbihlKXt2YXIgdD10aGlzLmdldENvbnRleHQodGhpcy5wcm9wcy50aGVtZSxlKTtyZXR1cm4gXy5hLmNyZWF0ZUVsZW1lbnQobnQuUHJvdmlkZXIse3ZhbHVlOnR9LF8uYS5DaGlsZHJlbi5vbmx5KHRoaXMucHJvcHMuY2hpbGRyZW4pKX0sdC5wcm90b3R5cGUuZ2V0VGhlbWU9ZnVuY3Rpb24oZSx0KXtpZihpKGUpKXtyZXR1cm4gZSh0KX1pZihudWxsPT09ZXx8QXJyYXkuaXNBcnJheShlKXx8Im9iamVjdCIhPT0oInVuZGVmaW5lZCI9PT10eXBlb2YgZT8idW5kZWZpbmVkIjpQKGUpKSl0aHJvdyBuZXcgUSg4KTtyZXR1cm4gUih7fSx0LGUpfSx0LnByb3RvdHlwZS5nZXRDb250ZXh0PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHRoaXMuZ2V0VGhlbWUoZSx0KX0sdH0oQS5Db21wb25lbnQpLG90PWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe00odGhpcyxlKSx0aGlzLm1hc3RlclNoZWV0PUZlLm1hc3Rlcix0aGlzLmluc3RhbmNlPXRoaXMubWFzdGVyU2hlZXQuY2xvbmUoKSx0aGlzLnNlYWxlZD0hMX1yZXR1cm4gZS5wcm90b3R5cGUuc2VhbD1mdW5jdGlvbigpe2lmKCF0aGlzLnNlYWxlZCl7dmFyIGU9dGhpcy5tYXN0ZXJTaGVldC5jbG9uZXMuaW5kZXhPZih0aGlzLmluc3RhbmNlKTt0aGlzLm1hc3RlclNoZWV0LmNsb25lcy5zcGxpY2UoZSwxKSx0aGlzLnNlYWxlZD0hMH19LGUucHJvdG90eXBlLmNvbGxlY3RTdHlsZXM9ZnVuY3Rpb24oZSl7aWYodGhpcy5zZWFsZWQpdGhyb3cgbmV3IFEoMik7cmV0dXJuIF8uYS5jcmVhdGVFbGVtZW50KHV0LHtzaGVldDp0aGlzLmluc3RhbmNlfSxlKX0sZS5wcm90b3R5cGUuZ2V0U3R5bGVUYWdzPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc2VhbCgpLHRoaXMuaW5zdGFuY2UudG9IVE1MKCl9LGUucHJvdG90eXBlLmdldFN0eWxlRWxlbWVudD1mdW5jdGlvbigpe3JldHVybiB0aGlzLnNlYWwoKSx0aGlzLmluc3RhbmNlLnRvUmVhY3RFbGVtZW50cygpfSxlLnByb3RvdHlwZS5pbnRlcmxlYXZlV2l0aE5vZGVTdHJlYW09ZnVuY3Rpb24oZSl7dGhyb3cgbmV3IFEoMyl9LGV9KCksYXQ9T2JqZWN0KEEuY3JlYXRlQ29udGV4dCkoKSxzdD1hdC5Db25zdW1lcix1dD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KG4pe00odGhpcyx0KTt2YXIgcj1VKHRoaXMsZS5jYWxsKHRoaXMsbikpO3JldHVybiByLmdldENvbnRleHQ9T2JqZWN0KE8uYSkoci5nZXRDb250ZXh0KSxyfXJldHVybiBCKHQsZSksdC5wcm90b3R5cGUuZ2V0Q29udGV4dD1mdW5jdGlvbihlLHQpe2lmKGUpcmV0dXJuIGU7aWYodClyZXR1cm4gbmV3IEZlKHQpO3Rocm93IG5ldyBRKDQpfSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnByb3BzLHQ9ZS5jaGlsZHJlbixuPWUuc2hlZXQscj1lLnRhcmdldCxpPXRoaXMuZ2V0Q29udGV4dChuLHIpO3JldHVybiBfLmEuY3JlYXRlRWxlbWVudChhdC5Qcm92aWRlcix7dmFsdWU6aX0sXy5hLkNoaWxkcmVuLm9ubHkodCkpfSx0fShBLkNvbXBvbmVudCksY3Q9e30sbHQ9KHNlKGZ1bmN0aW9uKCl7cmV0dXJuIGNvbnNvbGUud2FybignVGhlICJpbm5lclJlZiIgQVBJIGhhcyBiZWVuIHJlbW92ZWQgaW4gc3R5bGVkLWNvbXBvbmVudHMgdjQgaW4gZmF2b3Igb2YgUmVhY3QgMTYgcmVmIGZvcndhcmRpbmcsIHVzZSAicmVmIiBpbnN0ZWFkIGxpa2UgYSB0eXBpY2FsIGNvbXBvbmVudC4nKX0pLGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtNKHRoaXMsdCk7dmFyIG49VSh0aGlzLGUuY2FsbCh0aGlzKSk7cmV0dXJuIG4uYXR0cnM9e30sbi5yZW5kZXJPdXRlcj1uLnJlbmRlck91dGVyLmJpbmQobiksbi5yZW5kZXJJbm5lcj1uLnJlbmRlcklubmVyLmJpbmQobiksbn1yZXR1cm4gQih0LGUpLHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3JldHVybiBfLmEuY3JlYXRlRWxlbWVudChzdCxudWxsLHRoaXMucmVuZGVyT3V0ZXIpfSx0LnByb3RvdHlwZS5yZW5kZXJPdXRlcj1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5zdHlsZVNoZWV0PWUsXy5hLmNyZWF0ZUVsZW1lbnQocnQsbnVsbCx0aGlzLnJlbmRlcklubmVyKX0sdC5wcm90b3R5cGUucmVuZGVySW5uZXI9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5wcm9wcy5mb3J3YXJkZWRDbGFzcyxuPXQuY29tcG9uZW50U3R5bGUscj10LmRlZmF1bHRQcm9wcyxpPXQuc3R5bGVkQ29tcG9uZW50SWQsbz10LnRhcmdldCxhPXZvaWQgMDthPW4uaXNTdGF0aWM/dGhpcy5nZW5lcmF0ZUFuZEluamVjdFN0eWxlcyhWLHRoaXMucHJvcHMsdGhpcy5zdHlsZVNoZWV0KTp2b2lkIDAhPT1lP3RoaXMuZ2VuZXJhdGVBbmRJbmplY3RTdHlsZXMoemUodGhpcy5wcm9wcyxlLHIpLHRoaXMucHJvcHMsdGhpcy5zdHlsZVNoZWV0KTp0aGlzLmdlbmVyYXRlQW5kSW5qZWN0U3R5bGVzKHRoaXMucHJvcHMudGhlbWV8fFYsdGhpcy5wcm9wcyx0aGlzLnN0eWxlU2hlZXQpO3ZhciBzPXRoaXMucHJvcHMuYXN8fHRoaXMuYXR0cnMuYXN8fG8sdT1tKHMpLGM9Uih7fSx0aGlzLmF0dHJzKSxsPXZvaWQgMDtmb3IobCBpbiB0aGlzLnByb3BzKSJmb3J3YXJkZWRDbGFzcyIhPT1sJiYiYXMiIT09bCYmKCJmb3J3YXJkZWRSZWYiPT09bD9jLnJlZj10aGlzLnByb3BzW2xdOnUmJiFPYmplY3QoSS5hKShsKXx8KGNbbF09InN0eWxlIj09PWwmJmwgaW4gdGhpcy5hdHRycz9SKHt9LHRoaXMuYXR0cnNbbF0sdGhpcy5wcm9wc1tsXSk6dGhpcy5wcm9wc1tsXSkpO3JldHVybiBjLmNsYXNzTmFtZT1bdGhpcy5wcm9wcy5jbGFzc05hbWUsaSx0aGlzLmF0dHJzLmNsYXNzTmFtZSxhXS5maWx0ZXIoQm9vbGVhbikuam9pbigiICIpLE9iamVjdChBLmNyZWF0ZUVsZW1lbnQpKHMsYyl9LHQucHJvdG90eXBlLmJ1aWxkRXhlY3V0aW9uQ29udGV4dD1mdW5jdGlvbihlLHQsbil7dmFyIHI9Uih7fSx0LHt0aGVtZTplfSk7aWYodm9pZCAwPT09bilyZXR1cm4gcjt0aGlzLmF0dHJzPXt9O3ZhciBvPXZvaWQgMCxzPXZvaWQgMDtmb3IocyBpbiBuKW89bltzXSx0aGlzLmF0dHJzW3NdPSFpKG8pfHx2KG8pfHxhKG8pP286byhyKTtyZXR1cm4gUih7fSxyLHRoaXMuYXR0cnMpfSx0LnByb3RvdHlwZS5nZW5lcmF0ZUFuZEluamVjdFN0eWxlcz1mdW5jdGlvbihlLHQpe3ZhciBuPWFyZ3VtZW50cy5sZW5ndGg+MiYmdm9pZCAwIT09YXJndW1lbnRzWzJdP2FyZ3VtZW50c1syXTpGZS5tYXN0ZXIscj10LmZvcndhcmRlZENsYXNzLGk9ci5hdHRycyxvPXIuY29tcG9uZW50U3R5bGUsYT1yLndhcm5Ub29NYW55Q2xhc3NlcztpZihvLmlzU3RhdGljJiZ2b2lkIDA9PT1pKXJldHVybiBvLmdlbmVyYXRlQW5kSW5qZWN0U3R5bGVzKFYsbik7dmFyIHM9by5nZW5lcmF0ZUFuZEluamVjdFN0eWxlcyh0aGlzLmJ1aWxkRXhlY3V0aW9uQ29udGV4dChlLHQsdC5mb3J3YXJkZWRDbGFzcy5hdHRycyksbik7cmV0dXJuIGEmJmEocyksc30sdH0oQS5Db21wb25lbnQpKSxwdD1bImEiLCJhYmJyIiwiYWRkcmVzcyIsImFyZWEiLCJhcnRpY2xlIiwiYXNpZGUiLCJhdWRpbyIsImIiLCJiYXNlIiwiYmRpIiwiYmRvIiwiYmlnIiwiYmxvY2txdW90ZSIsImJvZHkiLCJiciIsImJ1dHRvbiIsImNhbnZhcyIsImNhcHRpb24iLCJjaXRlIiwiY29kZSIsImNvbCIsImNvbGdyb3VwIiwiZGF0YSIsImRhdGFsaXN0IiwiZGQiLCJkZWwiLCJkZXRhaWxzIiwiZGZuIiwiZGlhbG9nIiwiZGl2IiwiZGwiLCJkdCIsImVtIiwiZW1iZWQiLCJmaWVsZHNldCIsImZpZ2NhcHRpb24iLCJmaWd1cmUiLCJmb290ZXIiLCJmb3JtIiwiaDEiLCJoMiIsImgzIiwiaDQiLCJoNSIsImg2IiwiaGVhZCIsImhlYWRlciIsImhncm91cCIsImhyIiwiaHRtbCIsImkiLCJpZnJhbWUiLCJpbWciLCJpbnB1dCIsImlucyIsImtiZCIsImtleWdlbiIsImxhYmVsIiwibGVnZW5kIiwibGkiLCJsaW5rIiwibWFpbiIsIm1hcCIsIm1hcmsiLCJtYXJxdWVlIiwibWVudSIsIm1lbnVpdGVtIiwibWV0YSIsIm1ldGVyIiwibmF2Iiwibm9zY3JpcHQiLCJvYmplY3QiLCJvbCIsIm9wdGdyb3VwIiwib3B0aW9uIiwib3V0cHV0IiwicCIsInBhcmFtIiwicGljdHVyZSIsInByZSIsInByb2dyZXNzIiwicSIsInJwIiwicnQiLCJydWJ5IiwicyIsInNhbXAiLCJzY3JpcHQiLCJzZWN0aW9uIiwic2VsZWN0Iiwic21hbGwiLCJzb3VyY2UiLCJzcGFuIiwic3Ryb25nIiwic3R5bGUiLCJzdWIiLCJzdW1tYXJ5Iiwic3VwIiwidGFibGUiLCJ0Ym9keSIsInRkIiwidGV4dGFyZWEiLCJ0Zm9vdCIsInRoIiwidGhlYWQiLCJ0aW1lIiwidGl0bGUiLCJ0ciIsInRyYWNrIiwidSIsInVsIiwidmFyIiwidmlkZW8iLCJ3YnIiLCJjaXJjbGUiLCJjbGlwUGF0aCIsImRlZnMiLCJlbGxpcHNlIiwiZm9yZWlnbk9iamVjdCIsImciLCJpbWFnZSIsImxpbmUiLCJsaW5lYXJHcmFkaWVudCIsIm1hc2siLCJwYXRoIiwicGF0dGVybiIsInBvbHlnb24iLCJwb2x5bGluZSIsInJhZGlhbEdyYWRpZW50IiwicmVjdCIsInN0b3AiLCJzdmciLCJ0ZXh0IiwidHNwYW4iXSxmdD1mdW5jdGlvbihlKXtyZXR1cm4gbCh4LGUpfTtwdC5mb3JFYWNoKGZ1bmN0aW9uKGUpe2Z0W2VdPWZ0KGUpfSk7dmFyIGR0PWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0LG4pe00odGhpcyxlKSx0aGlzLnJ1bGVzPXQsdGhpcy5jb21wb25lbnRJZD1uLHRoaXMuaXNTdGF0aWM9ZCh0KSxGZS5tYXN0ZXIuaGFzSWQobil8fEZlLm1hc3Rlci5kZWZlcnJlZEluamVjdChuLFtdKX1yZXR1cm4gZS5wcm90b3R5cGUuY3JlYXRlU3R5bGVzPWZ1bmN0aW9uKGUsdCl7dmFyIG49dSh0aGlzLnJ1bGVzLGUsdCkscj1pZShuLCIiKTt0LmluamVjdCh0aGlzLmNvbXBvbmVudElkLHIpfSxlLnByb3RvdHlwZS5yZW1vdmVTdHlsZXM9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5jb21wb25lbnRJZDtlLmhhc0lkKHQpJiZlLnJlbW92ZSh0KX0sZS5wcm90b3R5cGUucmVuZGVyU3R5bGVzPWZ1bmN0aW9uKGUsdCl7dGhpcy5yZW1vdmVTdHlsZXModCksdGhpcy5jcmVhdGVTdHlsZXMoZSx0KX0sZX0oKTtIJiYod2luZG93LnNjQ0dTSE1SQ2FjaGU9e30pO3ZhciBodD1mdW5jdGlvbihlKXtyZXR1cm4gZS5yZXBsYWNlKC9cc3xcXG4vZywiIil9LG10PWZ1bmN0aW9uKGUpe3ZhciB0PV8uYS5mb3J3YXJkUmVmKGZ1bmN0aW9uKHQsbil7cmV0dXJuIF8uYS5jcmVhdGVFbGVtZW50KHJ0LG51bGwsZnVuY3Rpb24ocil7dmFyIGk9ZS5kZWZhdWx0UHJvcHMsbz16ZSh0LHIsaSk7cmV0dXJuIF8uYS5jcmVhdGVFbGVtZW50KGUsUih7fSx0LHt0aGVtZTpvLHJlZjpufSkpfSl9KTtyZXR1cm4geSh0LGUpLHQuZGlzcGxheU5hbWU9IldpdGhUaGVtZSgiK28oZSkrIikiLHR9LGd0PXtTdHlsZVNoZWV0OkZlfTt0LmRlZmF1bHQ9ZnR9LmNhbGwodCxuKDU2KSxuKDc5KShlKSl9LGZ1bmN0aW9uKGUsdCxuKXshZnVuY3Rpb24odCl7ZS5leHBvcnRzPXQobnVsbCl9KGZ1bmN0aW9uIGUodCl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIG4oZSx0LGksYyxsKXtmb3IodmFyIGQsaCxtPTAsZz0wLHk9MCxiPTAseD0wLEM9MCxFPTAsaz0wLEE9MCxfPTAsVD0wLEY9MCxJPTAsTD0wLFA9MCxNPTAsZWU9MCxfZT0wLE5lPTAsTGU9aS5sZW5ndGgsUGU9TGUtMSxNZT0iIixIZT0iIixXZT0iIixRZT0iIixLZT0iIixKZT0iIjtQPExlOyl7aWYoRT1pLmNoYXJDb2RlQXQoUCksUD09PVBlJiZnK2IreSttIT09MCYmKDAhPT1nJiYoRT1nPT09YWU/VzphZSksYj15PW09MCxMZSsrLFBlKyspLGcrYit5K209PT0wKXtpZihQPT09UGUmJihNPjAmJihIZT1IZS5yZXBsYWNlKGYsIiIpKSxIZS50cmltKCkubGVuZ3RoPjApKXtzd2l0Y2goRSl7Y2FzZSBZOmNhc2UgSzpjYXNlICQ6Y2FzZSBROmNhc2UgVzpicmVhaztkZWZhdWx0OkhlKz1pLmNoYXJBdChQKX1FPSR9aWYoMT09PWVlKXN3aXRjaChFKXtjYXNlIHo6Y2FzZSBVOmNhc2UgJDpjYXNlIG9lOmNhc2UgaWU6Y2FzZSBHOmNhc2UgVjpjYXNlIG5lOmVlPTA7Y2FzZSBLOmNhc2UgUTpjYXNlIFc6Y2FzZSBZOmJyZWFrO2RlZmF1bHQ6Zm9yKGVlPTAsTmU9UCx4PUUsUC0tLEU9JDtOZTxMZTspc3dpdGNoKGkuY2hhckNvZGVBdChOZSsrKSl7Y2FzZSBXOmNhc2UgUTpjYXNlICQ6KytQLEU9eCxOZT1MZTticmVhaztjYXNlIHJlOk0+MCYmKCsrUCxFPXgpO2Nhc2UgejpOZT1MZX19c3dpdGNoKEUpe2Nhc2Ugejpmb3IoeD0oSGU9SGUudHJpbSgpKS5jaGFyQ29kZUF0KDApLFQ9MSxOZT0rK1A7UDxMZTspe3N3aXRjaChFPWkuY2hhckNvZGVBdChQKSl7Y2FzZSB6OlQrKzticmVhaztjYXNlIFU6VC0tfWlmKDA9PT1UKWJyZWFrO1ArK31zd2l0Y2goV2U9aS5zdWJzdHJpbmcoTmUsUCkseD09PWxlJiYoeD0oSGU9SGUucmVwbGFjZShwLCIiKS50cmltKCkpLmNoYXJDb2RlQXQoMCkpLHgpe2Nhc2UgSjpzd2l0Y2goTT4wJiYoSGU9SGUucmVwbGFjZShmLCIiKSksQz1IZS5jaGFyQ29kZUF0KDEpKXtjYXNlIHhlOmNhc2UgaGU6Y2FzZSBtZTpjYXNlIFo6ZD10O2JyZWFrO2RlZmF1bHQ6ZD1GZX1pZihOZT0oV2U9bih0LGQsV2UsQyxsKzEpKS5sZW5ndGgsT2U+MCYmMD09PU5lJiYoTmU9SGUubGVuZ3RoKSxJZT4wJiYoZD1yKEZlLEhlLF9lKSxoPXUoJGUsV2UsZCx0LERlLEVlLE5lLEMsbCxjKSxIZT1kLmpvaW4oIiIpLHZvaWQgMCE9PWgmJjA9PT0oTmU9KFdlPWgudHJpbSgpKS5sZW5ndGgpJiYoQz0wLFdlPSIiKSksTmU+MClzd2l0Y2goQyl7Y2FzZSBtZTpIZT1IZS5yZXBsYWNlKE4scyk7Y2FzZSB4ZTpjYXNlIGhlOmNhc2UgWjpXZT1IZSsieyIrV2UrIn0iO2JyZWFrO2Nhc2UgZGU6V2U9KEhlPUhlLnJlcGxhY2UoRCwiJDEgJDIiKyh6ZT4wP0dlOiIiKSkpKyJ7IitXZSsifSIsV2U9MT09PWtlfHwyPT09a2UmJmEoIkAiK1dlLDMpPyJAIitqK1dlKyJAIitXZToiQCIrV2U7YnJlYWs7ZGVmYXVsdDpXZT1IZStXZSxjPT09Q2UmJihRZSs9V2UsV2U9IiIpfWVsc2UgV2U9IiI7YnJlYWs7ZGVmYXVsdDpXZT1uKHQscih0LEhlLF9lKSxXZSxjLGwrMSl9S2UrPVdlLEY9MCxlZT0wLEw9MCxNPTAsX2U9MCxJPTAsSGU9IiIsV2U9IiIsRT1pLmNoYXJDb2RlQXQoKytQKTticmVhaztjYXNlIFU6Y2FzZSAkOmlmKChOZT0oSGU9KE0+MD9IZS5yZXBsYWNlKGYsIiIpOkhlKS50cmltKCkpLmxlbmd0aCk+MSlzd2l0Y2goMD09PUwmJigoeD1IZS5jaGFyQ29kZUF0KDApKT09PVp8fHg+OTYmJng8MTIzKSYmKE5lPShIZT1IZS5yZXBsYWNlKCIgIiwiOiIpKS5sZW5ndGgpLEllPjAmJnZvaWQgMCE9PShoPXUoUmUsSGUsdCxlLERlLEVlLFFlLmxlbmd0aCxjLGwsYykpJiYwPT09KE5lPShIZT1oLnRyaW0oKSkubGVuZ3RoKSYmKEhlPSJcMFwwIiksKHg9SGUuY2hhckNvZGVBdCgwKSkrKEM9SGUuY2hhckNvZGVBdCgxKSkpe2Nhc2UgbGU6YnJlYWs7Y2FzZSB2ZTpjYXNlIGJlOkplKz1IZStpLmNoYXJBdChQKTticmVhaztkZWZhdWx0OmlmKEhlLmNoYXJDb2RlQXQoTmUtMSk9PT1yZSlicmVhaztRZSs9byhIZSx4LEMsSGUuY2hhckNvZGVBdCgyKSl9Rj0wLGVlPTAsTD0wLE09MCxfZT0wLEhlPSIiLEU9aS5jaGFyQ29kZUF0KCsrUCl9fXN3aXRjaChFKXtjYXNlIFE6Y2FzZSBXOmlmKGcrYit5K20rVGU9PT0wKXN3aXRjaChfKXtjYXNlIFY6Y2FzZSBpZTpjYXNlIG9lOmNhc2UgSjpjYXNlIGNlOmNhc2Ugc2U6Y2FzZSB0ZTpjYXNlIHVlOmNhc2UgYWU6Y2FzZSBaOmNhc2UgcmU6Y2FzZSBuZTpjYXNlICQ6Y2FzZSB6OmNhc2UgVTpicmVhaztkZWZhdWx0Okw+MCYmKGVlPTEpfWc9PT1hZT9nPTA6U2UrRj09PTAmJihNPTEsSGUrPSJcMCIpLEllKlVlPjAmJnUoamUsSGUsdCxlLERlLEVlLFFlLmxlbmd0aCxjLGwsYyksRWU9MSxEZSsrO2JyZWFrO2Nhc2UgJDpjYXNlIFU6aWYoZytiK3krbT09PTApe0VlKys7YnJlYWt9ZGVmYXVsdDpzd2l0Y2goRWUrKyxNZT1pLmNoYXJBdChQKSxFKXtjYXNlIEs6Y2FzZSBZOmlmKGIrbStnPT09MClzd2l0Y2goayl7Y2FzZSBuZTpjYXNlIHJlOmNhc2UgSzpjYXNlIFk6TWU9IiI7YnJlYWs7ZGVmYXVsdDpFIT09WSYmKE1lPSIgIil9YnJlYWs7Y2FzZSBsZTpNZT0iXFwwIjticmVhaztjYXNlIHBlOk1lPSJcXGYiO2JyZWFrO2Nhc2UgZmU6TWU9IlxcdiI7YnJlYWs7Y2FzZSBYOmIrZyttPT09MCYmU2U+MCYmKF9lPTEsTT0xLE1lPSJcZiIrTWUpO2JyZWFrO2Nhc2UgMTA4OmlmKGIrZyttK3dlPT09MCYmTD4wKXN3aXRjaChQLUwpe2Nhc2UgMjprPT09Z2UmJmkuY2hhckNvZGVBdChQLTMpPT09cmUmJih3ZT1rKTtjYXNlIDg6QT09PXllJiYod2U9QSl9YnJlYWs7Y2FzZSByZTpiK2crbT09PTAmJihMPVApO2JyZWFrO2Nhc2UgbmU6Zyt5K2IrbT09PTAmJihNPTEsTWUrPSJcciIpO2JyZWFrO2Nhc2Ugb2U6Y2FzZSBpZTowPT09ZyYmKGI9Yj09PUU/MDowPT09Yj9FOmIpO2JyZWFrO2Nhc2UgcTpiK2creT09PTAmJm0rKzticmVhaztjYXNlIEg6YitnK3k9PT0wJiZtLS07YnJlYWs7Y2FzZSBWOmIrZyttPT09MCYmeS0tO2JyZWFrO2Nhc2UgRzppZihiK2crbT09PTApe2lmKDA9PT1GKXN3aXRjaCgyKmsrMypBKXtjYXNlIDUzMzpicmVhaztkZWZhdWx0OlQ9MCxGPTF9eSsrfWJyZWFrO2Nhc2UgSjpnK3krYittK0wrST09PTAmJihJPTEpO2JyZWFrO2Nhc2UgdGU6Y2FzZSBhZTppZihiK20reT4wKWJyZWFrO3N3aXRjaChnKXtjYXNlIDA6c3dpdGNoKDIqRSszKmkuY2hhckNvZGVBdChQKzEpKXtjYXNlIDIzNTpnPWFlO2JyZWFrO2Nhc2UgMjIwOk5lPVAsZz10ZX1icmVhaztjYXNlIHRlOkU9PT1hZSYmaz09PXRlJiYoMzM9PT1pLmNoYXJDb2RlQXQoTmUrMikmJihRZSs9aS5zdWJzdHJpbmcoTmUsUCsxKSksTWU9IiIsZz0wKX19aWYoMD09PWcpe2lmKFNlK2IrbStJPT09MCYmYyE9PWRlJiZFIT09JClzd2l0Y2goRSl7Y2FzZSBuZTpjYXNlIGNlOmNhc2Ugc2U6Y2FzZSB1ZTpjYXNlIFY6Y2FzZSBHOmlmKDA9PT1GKXtzd2l0Y2goayl7Y2FzZSBLOmNhc2UgWTpjYXNlIFc6Y2FzZSBROk1lKz0iXDAiO2JyZWFrO2RlZmF1bHQ6TWU9IlwwIitNZSsoRT09PW5lPyIiOiJcMCIpfU09MX1lbHNlIHN3aXRjaChFKXtjYXNlIEc6Rj0rK1Q7YnJlYWs7Y2FzZSBWOjA9PShGPS0tVCkmJihNPTEsTWUrPSJcMCIpfWJyZWFrO2Nhc2UgSzpjYXNlIFk6c3dpdGNoKGspe2Nhc2UgbGU6Y2FzZSB6OmNhc2UgVTpjYXNlICQ6Y2FzZSBuZTpjYXNlIHBlOmNhc2UgSzpjYXNlIFk6Y2FzZSBXOmNhc2UgUTpicmVhaztkZWZhdWx0OjA9PT1GJiYoTT0xLE1lKz0iXDAiKX19SGUrPU1lLEUhPT1ZJiZFIT09SyYmKF89RSl9fUE9ayxrPUUsUCsrfWlmKE5lPVFlLmxlbmd0aCxPZT4wJiYwPT09TmUmJjA9PT1LZS5sZW5ndGgmJjA9PT10WzBdLmxlbmd0aD09MCYmKGMhPT1oZXx8MT09PXQubGVuZ3RoJiYoU2U+MD9WZTpxZSk9PT10WzBdKSYmKE5lPXQuam9pbigiLCIpLmxlbmd0aCsyKSxOZT4wKXtpZihkPTA9PT1TZSYmYyE9PWRlP2Z1bmN0aW9uKGUpe2Zvcih2YXIgdCxuLHI9MCxpPWUubGVuZ3RoLG89QXJyYXkoaSk7cjxpOysrcil7Zm9yKHZhciBhPWVbcl0uc3BsaXQodikscz0iIix1PTAsYz0wLGw9MCxwPTAsZD1hLmxlbmd0aDt1PGQ7Kyt1KWlmKCEoMD09PShjPShuPWFbdV0pLmxlbmd0aCkmJmQ+MSkpe2lmKGw9cy5jaGFyQ29kZUF0KHMubGVuZ3RoLTEpLHA9bi5jaGFyQ29kZUF0KDApLHQ9IiIsMCE9PXUpc3dpdGNoKGwpe2Nhc2UgdGU6Y2FzZSBjZTpjYXNlIHNlOmNhc2UgdWU6Y2FzZSBZOmNhc2UgRzpicmVhaztkZWZhdWx0OnQ9IiAifXN3aXRjaChwKXtjYXNlIFg6bj10K1ZlO2Nhc2UgY2U6Y2FzZSBzZTpjYXNlIHVlOmNhc2UgWTpjYXNlIFY6Y2FzZSBHOmJyZWFrO2Nhc2UgcTpuPXQrbitWZTticmVhaztjYXNlIHJlOnN3aXRjaCgyKm4uY2hhckNvZGVBdCgxKSszKm4uY2hhckNvZGVBdCgyKSl7Y2FzZSA1MzA6aWYoQWU+MCl7bj10K24uc3Vic3RyaW5nKDgsYy0xKTticmVha31kZWZhdWx0Oih1PDF8fGFbdS0xXS5sZW5ndGg8MSkmJihuPXQrVmUrbil9YnJlYWs7Y2FzZSBuZTp0PSIiO2RlZmF1bHQ6bj1jPjEmJm4uaW5kZXhPZigiOiIpPjA/dCtuLnJlcGxhY2UoTywiJDEiK1ZlKyIkMiIpOnQrbitWZX1zKz1ufW9bcl09cy5yZXBsYWNlKGYsIiIpLnRyaW0oKX1yZXR1cm4gb30odCk6dCxJZT4wJiZ2b2lkIDAhPT0oaD11KEJlLFFlLGQsZSxEZSxFZSxOZSxjLGwsYykpJiYwPT09KFFlPWgpLmxlbmd0aClyZXR1cm4gSmUrUWUrS2U7aWYoUWU9ZC5qb2luKCIsIikrInsiK1FlKyJ9IixrZSp3ZSE9MCl7c3dpdGNoKDIhPT1rZXx8YShRZSwyKXx8KHdlPTApLHdlKXtjYXNlIHllOlFlPVFlLnJlcGxhY2UoUywiOiIrUisiJDEiKStRZTticmVhaztjYXNlIGdlOlFlPVFlLnJlcGxhY2UodywiOjoiK2orImlucHV0LSQxIikrUWUucmVwbGFjZSh3LCI6OiIrUisiJDEiKStRZS5yZXBsYWNlKHcsIjoiK0IrImlucHV0LSQxIikrUWV9d2U9MH19cmV0dXJuIEplK1FlK0tlfWZ1bmN0aW9uIHIoZSx0LG4pe3ZhciByPXQudHJpbSgpLnNwbGl0KGIpLG89cixhPXIubGVuZ3RoLHM9ZS5sZW5ndGg7c3dpdGNoKHMpe2Nhc2UgMDpjYXNlIDE6Zm9yKHZhciB1PTAsYz0wPT09cz8iIjplWzBdKyIgIjt1PGE7Kyt1KW9bdV09aShjLG9bdV0sbixzKS50cmltKCk7YnJlYWs7ZGVmYXVsdDp1PTA7dmFyIGw9MDtmb3Iobz1bXTt1PGE7Kyt1KWZvcih2YXIgcD0wO3A8czsrK3Apb1tsKytdPWkoZVtwXSsiICIsclt1XSxuLHMpLnRyaW0oKX1yZXR1cm4gb31mdW5jdGlvbiBpKGUsdCxuLHIpe3ZhciBpPXQsbz1pLmNoYXJDb2RlQXQoMCk7c3dpdGNoKG88MzMmJihvPShpPWkudHJpbSgpKS5jaGFyQ29kZUF0KDApKSxvKXtjYXNlIFg6c3dpdGNoKFNlK3Ipe2Nhc2UgMDpjYXNlIDE6aWYoMD09PWUudHJpbSgpLmxlbmd0aClicmVhaztkZWZhdWx0OnJldHVybiBpLnJlcGxhY2UoeCwiJDEiK2UudHJpbSgpKX1icmVhaztjYXNlIHJlOnN3aXRjaChpLmNoYXJDb2RlQXQoMSkpe2Nhc2UgMTAzOmlmKEFlPjAmJlNlPjApcmV0dXJuIGkucmVwbGFjZShDLCIkMSIpLnJlcGxhY2UoeCwiJDEiK3FlKTticmVhaztkZWZhdWx0OnJldHVybiBlLnRyaW0oKStpLnJlcGxhY2UoeCwiJDEiK2UudHJpbSgpKX1kZWZhdWx0OmlmKG4qU2U+MCYmaS5pbmRleE9mKCJcZiIpPjApcmV0dXJuIGkucmVwbGFjZSh4LChlLmNoYXJDb2RlQXQoMCk9PT1yZT8iIjoiJDEiKStlLnRyaW0oKSl9cmV0dXJuIGUraX1mdW5jdGlvbiBvKGUsdCxuLHIpe3ZhciBpLHM9MCx1PWUrIjsiLGM9Mip0KzMqbis0KnI7aWYoOTQ0PT09YylyZXR1cm4gZnVuY3Rpb24oZSl7dmFyIHQ9ZS5sZW5ndGgsbj1lLmluZGV4T2YoIjoiLDkpKzEscj1lLnN1YnN0cmluZygwLG4pLnRyaW0oKSxpPWUuc3Vic3RyaW5nKG4sdC0xKS50cmltKCk7c3dpdGNoKGUuY2hhckNvZGVBdCg5KSp6ZSl7Y2FzZSAwOmJyZWFrO2Nhc2UgWjppZigxMTAhPT1lLmNoYXJDb2RlQXQoMTApKWJyZWFrO2RlZmF1bHQ6Zm9yKHZhciBvPWkuc3BsaXQoKGk9IiIsZykpLHM9MCxuPTAsdD1vLmxlbmd0aDtzPHQ7bj0wLCsrcyl7Zm9yKHZhciB1PW9bc10sYz11LnNwbGl0KHkpO3U9Y1tuXTspe3ZhciBsPXUuY2hhckNvZGVBdCgwKTtpZigxPT09emUmJihsPkomJmw8OTB8fGw+OTYmJmw8MTIzfHxsPT09ZWV8fGw9PT1aJiZ1LmNoYXJDb2RlQXQoMSkhPT1aKSlzd2l0Y2goaXNOYU4ocGFyc2VGbG9hdCh1KSkrKC0xIT09dS5pbmRleE9mKCIoIikpKXtjYXNlIDE6c3dpdGNoKHUpe2Nhc2UiaW5maW5pdGUiOmNhc2UiYWx0ZXJuYXRlIjpjYXNlImJhY2t3YXJkcyI6Y2FzZSJydW5uaW5nIjpjYXNlIm5vcm1hbCI6Y2FzZSJmb3J3YXJkcyI6Y2FzZSJib3RoIjpjYXNlIm5vbmUiOmNhc2UibGluZWFyIjpjYXNlImVhc2UiOmNhc2UiZWFzZS1pbiI6Y2FzZSJlYXNlLW91dCI6Y2FzZSJlYXNlLWluLW91dCI6Y2FzZSJwYXVzZWQiOmNhc2UicmV2ZXJzZSI6Y2FzZSJhbHRlcm5hdGUtcmV2ZXJzZSI6Y2FzZSJpbmhlcml0IjpjYXNlImluaXRpYWwiOmNhc2UidW5zZXQiOmNhc2Uic3RlcC1zdGFydCI6Y2FzZSJzdGVwLWVuZCI6YnJlYWs7ZGVmYXVsdDp1Kz1HZX19Y1tuKytdPXV9aSs9KDA9PT1zPyIiOiIsIikrYy5qb2luKCIgIil9fXJldHVybiBpPXIraSsiOyIsMT09PWtlfHwyPT09a2UmJmEoaSwxKT9qK2kraTppfSh1KTtpZigwPT09a2V8fDI9PT1rZSYmIWEodSwxKSlyZXR1cm4gdTtzd2l0Y2goYyl7Y2FzZSAxMDE1OnJldHVybiA5Nz09PXUuY2hhckNvZGVBdCgxMCk/ait1K3U6dTtjYXNlIDk1MTpyZXR1cm4gMTE2PT09dS5jaGFyQ29kZUF0KDMpP2ordSt1OnU7Y2FzZSA5NjM6cmV0dXJuIDExMD09PXUuY2hhckNvZGVBdCg1KT9qK3UrdTp1O2Nhc2UgMTAwOTppZigxMDAhPT11LmNoYXJDb2RlQXQoNCkpYnJlYWs7Y2FzZSA5Njk6Y2FzZSA5NDI6cmV0dXJuIGordSt1O2Nhc2UgOTc4OnJldHVybiBqK3UrUit1K3U7Y2FzZSAxMDE5OmNhc2UgOTgzOnJldHVybiBqK3UrUit1K0IrdSt1O2Nhc2UgODgzOnJldHVybiB1LmNoYXJDb2RlQXQoOCk9PT1aP2ordSt1OnU7Y2FzZSA5MzI6aWYodS5jaGFyQ29kZUF0KDQpPT09Wilzd2l0Y2godS5jaGFyQ29kZUF0KDUpKXtjYXNlIDEwMzpyZXR1cm4gaisiYm94LSIrdS5yZXBsYWNlKCItZ3JvdyIsIiIpK2ordStCK3UucmVwbGFjZSgiZ3JvdyIsInBvc2l0aXZlIikrdTtjYXNlIDExNTpyZXR1cm4gait1K0IrdS5yZXBsYWNlKCJzaHJpbmsiLCJuZWdhdGl2ZSIpK3U7Y2FzZSA5ODpyZXR1cm4gait1K0IrdS5yZXBsYWNlKCJiYXNpcyIsInByZWZlcnJlZC1zaXplIikrdX1yZXR1cm4gait1K0IrdSt1O2Nhc2UgOTY0OnJldHVybiBqK3UrQisiZmxleC0iK3UrdTtjYXNlIDEwMjM6aWYoOTkhPT11LmNoYXJDb2RlQXQoOCkpYnJlYWs7cmV0dXJuIGk9dS5zdWJzdHJpbmcodS5pbmRleE9mKCI6IiwxNSkpLnJlcGxhY2UoImZsZXgtIiwiIikucmVwbGFjZSgic3BhY2UtYmV0d2VlbiIsImp1c3RpZnkiKSxqKyJib3gtcGFjayIraStqK3UrQisiZmxleC1wYWNrIitpK3U7Y2FzZSAxMDA1OnJldHVybiBoLnRlc3QodSk/dS5yZXBsYWNlKGQsIjoiK2opK3UucmVwbGFjZShkLCI6IitSKSt1OnU7Y2FzZSAxZTM6c3dpdGNoKHM9KGk9dS5zdWJzdHJpbmcoMTMpLnRyaW0oKSkuaW5kZXhPZigiLSIpKzEsaS5jaGFyQ29kZUF0KDApK2kuY2hhckNvZGVBdChzKSl7Y2FzZSAyMjY6aT11LnJlcGxhY2UoRiwidGIiKTticmVhaztjYXNlIDIzMjppPXUucmVwbGFjZShGLCJ0Yi1ybCIpO2JyZWFrO2Nhc2UgMjIwOmk9dS5yZXBsYWNlKEYsImxyIik7YnJlYWs7ZGVmYXVsdDpyZXR1cm4gdX1yZXR1cm4gait1K0IraSt1O2Nhc2UgMTAxNzppZigtMT09PXUuaW5kZXhPZigic3RpY2t5Iiw5KSlyZXR1cm4gdTtjYXNlIDk3NTpzd2l0Y2gocz0odT1lKS5sZW5ndGgtMTAsYz0oaT0oMzM9PT11LmNoYXJDb2RlQXQocyk/dS5zdWJzdHJpbmcoMCxzKTp1KS5zdWJzdHJpbmcoZS5pbmRleE9mKCI6Iiw3KSsxKS50cmltKCkpLmNoYXJDb2RlQXQoMCkrKDB8aS5jaGFyQ29kZUF0KDcpKSl7Y2FzZSAyMDM6aWYoaS5jaGFyQ29kZUF0KDgpPDExMSlicmVhaztjYXNlIDExNTp1PXUucmVwbGFjZShpLGoraSkrIjsiK3U7YnJlYWs7Y2FzZSAyMDc6Y2FzZSAxMDI6dT11LnJlcGxhY2UoaSxqKyhjPjEwMj8iaW5saW5lLSI6IiIpKyJib3giKSsiOyIrdS5yZXBsYWNlKGksaitpKSsiOyIrdS5yZXBsYWNlKGksQitpKyJib3giKSsiOyIrdX1yZXR1cm4gdSsiOyI7Y2FzZSA5Mzg6aWYodS5jaGFyQ29kZUF0KDUpPT09Wilzd2l0Y2godS5jaGFyQ29kZUF0KDYpKXtjYXNlIDEwNTpyZXR1cm4gaT11LnJlcGxhY2UoIi1pdGVtcyIsIiIpLGordStqKyJib3gtIitpK0IrImZsZXgtIitpK3U7Y2FzZSAxMTU6cmV0dXJuIGordStCKyJmbGV4LWl0ZW0tIit1LnJlcGxhY2UoTCwiIikrdTtkZWZhdWx0OnJldHVybiBqK3UrQisiZmxleC1saW5lLXBhY2siK3UucmVwbGFjZSgiYWxpZ24tY29udGVudCIsIiIpLnJlcGxhY2UoTCwiIikrdX1icmVhaztjYXNlIDk3MzpjYXNlIDk4OTppZih1LmNoYXJDb2RlQXQoMykhPT1afHwxMjI9PT11LmNoYXJDb2RlQXQoNCkpYnJlYWs7Y2FzZSA5MzE6Y2FzZSA5NTM6aWYoITA9PT1NLnRlc3QoZSkpcmV0dXJuIDExNT09PShpPWUuc3Vic3RyaW5nKGUuaW5kZXhPZigiOiIpKzEpKS5jaGFyQ29kZUF0KDApP28oZS5yZXBsYWNlKCJzdHJldGNoIiwiZmlsbC1hdmFpbGFibGUiKSx0LG4scikucmVwbGFjZSgiOmZpbGwtYXZhaWxhYmxlIiwiOnN0cmV0Y2giKTp1LnJlcGxhY2UoaSxqK2kpK3UucmVwbGFjZShpLFIraS5yZXBsYWNlKCJmaWxsLSIsIiIpKSt1O2JyZWFrO2Nhc2UgOTYyOmlmKHU9ait1KygxMDI9PT11LmNoYXJDb2RlQXQoNSk/Qit1OiIiKSt1LG4rcj09PTIxMSYmMTA1PT09dS5jaGFyQ29kZUF0KDEzKSYmdS5pbmRleE9mKCJ0cmFuc2Zvcm0iLDEwKT4wKXJldHVybiB1LnN1YnN0cmluZygwLHUuaW5kZXhPZigiOyIsMjcpKzEpLnJlcGxhY2UobSwiJDEiK2orIiQyIikrdX1yZXR1cm4gdX1mdW5jdGlvbiBhKGUsdCl7dmFyIG49ZS5pbmRleE9mKDE9PT10PyI6IjoieyIpLHI9ZS5zdWJzdHJpbmcoMCwzIT09dD9uOjEwKSxpPWUuc3Vic3RyaW5nKG4rMSxlLmxlbmd0aC0xKTtyZXR1cm4gTGUoMiE9PXQ/cjpyLnJlcGxhY2UoUCwiJDEiKSxpLHQpfWZ1bmN0aW9uIHMoZSx0KXt2YXIgbj1vKHQsdC5jaGFyQ29kZUF0KDApLHQuY2hhckNvZGVBdCgxKSx0LmNoYXJDb2RlQXQoMikpO3JldHVybiBuIT09dCsiOyI/bi5yZXBsYWNlKEksIiBvciAoJDEpIikuc3Vic3RyaW5nKDQpOiIoIit0KyIpIn1mdW5jdGlvbiB1KGUsdCxuLHIsaSxvLGEscyx1LGMpe2Zvcih2YXIgcCxmPTAsZD10O2Y8SWU7KytmKXN3aXRjaChwPU5lW2ZdLmNhbGwobCxlLGQsbixyLGksbyxhLHMsdSxjKSl7Y2FzZSB2b2lkIDA6Y2FzZSExOmNhc2UhMDpjYXNlIG51bGw6YnJlYWs7ZGVmYXVsdDpkPXB9c3dpdGNoKGQpe2Nhc2Ugdm9pZCAwOmNhc2UhMTpjYXNlITA6Y2FzZSBudWxsOmNhc2UgdDpicmVhaztkZWZhdWx0OnJldHVybiBkfX1mdW5jdGlvbiBjKGUpe2Zvcih2YXIgdCBpbiBlKXt2YXIgbj1lW3RdO3N3aXRjaCh0KXtjYXNlImtleWZyYW1lIjp6ZT0wfG47YnJlYWs7Y2FzZSJnbG9iYWwiOkFlPTB8bjticmVhaztjYXNlImNhc2NhZGUiOlNlPTB8bjticmVhaztjYXNlImNvbXByZXNzIjpfZT0wfG47YnJlYWs7Y2FzZSJzZW1pY29sb24iOlRlPTB8bjticmVhaztjYXNlInByZXNlcnZlIjpPZT0wfG47YnJlYWs7Y2FzZSJwcmVmaXgiOkxlPW51bGwsbj8iZnVuY3Rpb24iIT10eXBlb2Ygbj9rZT0xOihrZT0yLExlPW4pOmtlPTB9fXJldHVybiBjfWZ1bmN0aW9uIGwodCxyKXtpZih2b2lkIDAhPT10aGlzJiZ0aGlzLmNvbnN0cnVjdG9yPT09bClyZXR1cm4gZSh0KTt2YXIgaT10LG89aS5jaGFyQ29kZUF0KDApO288MzMmJihvPShpPWkudHJpbSgpKS5jaGFyQ29kZUF0KDApKSx6ZT4wJiYoR2U9aS5yZXBsYWNlKEUsbz09PXE/IiI6Ii0iKSksbz0xLDE9PT1TZT9xZT1pOlZlPWk7dmFyIGEscz1bcWVdO0llPjAmJnZvaWQgMCE9PShhPXUoTWUscixzLHMsRGUsRWUsMCwwLDAsMCkpJiYic3RyaW5nIj09dHlwZW9mIGEmJihyPWEpO3ZhciBjPW4oRmUscyxyLDAsMCk7cmV0dXJuIEllPjAmJnZvaWQgMCE9PShhPXUoUGUsYyxzLHMsRGUsRWUsYy5sZW5ndGgsMCwwLDApKSYmInN0cmluZyIhPXR5cGVvZihjPWEpJiYobz0wKSxHZT0iIixxZT0iIixWZT0iIix3ZT0wLERlPTEsRWU9MSxfZSpvPT0wP2M6Yy5yZXBsYWNlKGYsIiIpLnJlcGxhY2UoaywiIikucmVwbGFjZShBLCIkMSIpLnJlcGxhY2UoXywiJDEiKS5yZXBsYWNlKFQsIiAiKX12YXIgcD0vXlwwKy9nLGY9L1tcMFxyXGZdL2csZD0vOiAqL2csaD0vem9vfGdyYS8sbT0vKFssOiBdKSh0cmFuc2Zvcm0pL2csZz0vLCtccyooPyFbXihdKlspXSkvZyx5PS8gK1xzKig/IVteKF0qWyldKS9nLHY9LyAqW1wwXSAqL2csYj0vLFxyKz8vZyx4PS8oW1x0XHJcbiBdKSpcZj8mL2csQz0vOmdsb2JhbFwoKCg/OlteXChcKVxbXF1dKnxcWy4qXF18XChbXlwoXCldKlwpKSopXCkvZyxFPS9cVysvZyxEPS9AKGtcdyspXHMqKFxTKilccyovLHc9Lzo6KHBsYWNlKS9nLFM9LzoocmVhZC1vbmx5KS9nLGs9L1xzKyg/PVt7XF07PTo+XSkvZyxBPS8oW1t9PTo+XSlccysvZyxfPS8oXHtbXntdKz8pOyg/PVx9KS9nLFQ9L1xzezIsfS9nLE89LyhbXlwoXSkoOispICovZyxGPS9bc3ZoXVx3Ky1bdGJscl17Mn0vLE49L1woXHMqKC4qKVxzKlwpL2csST0vKFtcc1xTXSo/KTsvZyxMPS8tc2VsZnxmbGV4LS9nLFA9L1teXSo/KDpbcnBdW2VsXWFbXHctXSspW15dKi8sTT0vc3RyZXRjaHw6XHMqXHcrXC0oPzpjb250ZXxhdmFpbCkvLGo9Ii13ZWJraXQtIixSPSItbW96LSIsQj0iLW1zLSIsJD01OSxVPTEyNSx6PTEyMyxHPTQwLFY9NDEscT05MSxIPTkzLFc9MTAsUT0xMyxLPTksSj02NCxZPTMyLFg9MzgsWj00NSxlZT05NSx0ZT00MixuZT00NCxyZT01OCxpZT0zOSxvZT0zNCxhZT00NyxzZT02Mix1ZT00MyxjZT0xMjYsbGU9MCxwZT0xMixmZT0xMSxkZT0xMDcsaGU9MTA5LG1lPTExNSxnZT0xMTIseWU9MTExLHZlPTE2OSxiZT0xNjMseGU9MTAwLENlPTExMixFZT0xLERlPTEsd2U9MCxTZT0xLGtlPTEsQWU9MSxfZT0wLFRlPTAsT2U9MCxGZT1bXSxOZT1bXSxJZT0wLExlPW51bGwsUGU9LTIsTWU9LTEsamU9MCxSZT0xLEJlPTIsJGU9MyxVZT0wLHplPTEsR2U9IiIsVmU9IiIscWU9IiI7cmV0dXJuIGwudXNlPWZ1bmN0aW9uIGUodCl7c3dpdGNoKHQpe2Nhc2Ugdm9pZCAwOmNhc2UgbnVsbDpJZT1OZS5sZW5ndGg9MDticmVhaztkZWZhdWx0OnN3aXRjaCh0LmNvbnN0cnVjdG9yKXtjYXNlIEFycmF5OmZvcih2YXIgbj0wLHI9dC5sZW5ndGg7bjxyOysrbillKHRbbl0pO2JyZWFrO2Nhc2UgRnVuY3Rpb246TmVbSWUrK109dDticmVhaztjYXNlIEJvb2xlYW46VWU9MHwhIXR9fXJldHVybiBlfSxsLnNldD1jLHZvaWQgMCE9PXQmJmModCksbH0pfSxmdW5jdGlvbihlLHQsbil7IWZ1bmN0aW9uKHQpe2UuZXhwb3J0cz10KCl9KGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO3JldHVybiBmdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe2lmKHQpdHJ5e2UodCsifSIpfWNhdGNoKGUpe319cmV0dXJuIGZ1bmN0aW9uKG4scixpLG8sYSxzLHUsYyxsLHApe3N3aXRjaChuKXtjYXNlIDE6aWYoMD09PWwmJjY0PT09ci5jaGFyQ29kZUF0KDApKXJldHVybiBlKHIrIjsiKSwiIjticmVhaztjYXNlIDI6aWYoMD09PWMpcmV0dXJuIHIrIi8qfCovIjticmVhaztjYXNlIDM6c3dpdGNoKGMpe2Nhc2UgMTAyOmNhc2UgMTEyOnJldHVybiBlKGlbMF0rciksIiI7ZGVmYXVsdDpyZXR1cm4gcisoMD09PXA/Ii8qfCovIjoiIil9Y2FzZS0yOnIuc3BsaXQoIi8qfCovfSIpLmZvckVhY2godCl9fX19KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9big1MjgpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7aWYoIm9iamVjdCI9PT10eXBlb2YgZSYmbnVsbCE9PWUpe3ZhciB0PWUuJCR0eXBlb2Y7c3dpdGNoKHQpe2Nhc2Ugbzpzd2l0Y2goZT1lLnR5cGUpe2Nhc2UgZjpjYXNlIHM6Y2FzZSBjOmNhc2UgdTpyZXR1cm4gZTtkZWZhdWx0OnN3aXRjaChlPWUmJmUuJCR0eXBlb2Ype2Nhc2UgcDpjYXNlIGQ6Y2FzZSBsOnJldHVybiBlO2RlZmF1bHQ6cmV0dXJuIHR9fWNhc2UgYTpyZXR1cm4gdH19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT0iZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmU3ltYm9sLmZvcixvPWk/U3ltYm9sLmZvcigicmVhY3QuZWxlbWVudCIpOjYwMTAzLGE9aT9TeW1ib2wuZm9yKCJyZWFjdC5wb3J0YWwiKTo2MDEwNixzPWk/U3ltYm9sLmZvcigicmVhY3QuZnJhZ21lbnQiKTo2MDEwNyx1PWk/U3ltYm9sLmZvcigicmVhY3Quc3RyaWN0X21vZGUiKTo2MDEwOCxjPWk/U3ltYm9sLmZvcigicmVhY3QucHJvZmlsZXIiKTo2MDExNCxsPWk/U3ltYm9sLmZvcigicmVhY3QucHJvdmlkZXIiKTo2MDEwOSxwPWk/U3ltYm9sLmZvcigicmVhY3QuY29udGV4dCIpOjYwMTEwLGY9aT9TeW1ib2wuZm9yKCJyZWFjdC5hc3luY19tb2RlIik6NjAxMTEsZD1pP1N5bWJvbC5mb3IoInJlYWN0LmZvcndhcmRfcmVmIik6NjAxMTIsaD1pP1N5bWJvbC5mb3IoInJlYWN0LnRpbWVvdXQiKTo2MDExMzt0LnR5cGVPZj1yLHQuQXN5bmNNb2RlPWYsdC5Db250ZXh0Q29uc3VtZXI9cCx0LkNvbnRleHRQcm92aWRlcj1sLHQuRWxlbWVudD1vLHQuRm9yd2FyZFJlZj1kLHQuRnJhZ21lbnQ9cyx0LlByb2ZpbGVyPWMsdC5Qb3J0YWw9YSx0LlN0cmljdE1vZGU9dSx0LmlzVmFsaWRFbGVtZW50VHlwZT1mdW5jdGlvbihlKXtyZXR1cm4ic3RyaW5nIj09PXR5cGVvZiBlfHwiZnVuY3Rpb24iPT09dHlwZW9mIGV8fGU9PT1zfHxlPT09Znx8ZT09PWN8fGU9PT11fHxlPT09aHx8Im9iamVjdCI9PT10eXBlb2YgZSYmbnVsbCE9PWUmJihlLiQkdHlwZW9mPT09bHx8ZS4kJHR5cGVvZj09PXB8fGUuJCR0eXBlb2Y9PT1kKX0sdC5pc0FzeW5jTW9kZT1mdW5jdGlvbihlKXtyZXR1cm4gcihlKT09PWZ9LHQuaXNDb250ZXh0Q29uc3VtZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIHIoZSk9PT1wfSx0LmlzQ29udGV4dFByb3ZpZGVyPWZ1bmN0aW9uKGUpe3JldHVybiByKGUpPT09bH0sdC5pc0VsZW1lbnQ9ZnVuY3Rpb24oZSl7cmV0dXJuIm9iamVjdCI9PT10eXBlb2YgZSYmbnVsbCE9PWUmJmUuJCR0eXBlb2Y9PT1vfSx0LmlzRm9yd2FyZFJlZj1mdW5jdGlvbihlKXtyZXR1cm4gcihlKT09PWR9LHQuaXNGcmFnbWVudD1mdW5jdGlvbihlKXtyZXR1cm4gcihlKT09PXN9LHQuaXNQcm9maWxlcj1mdW5jdGlvbihlKXtyZXR1cm4gcihlKT09PWN9LHQuaXNQb3J0YWw9ZnVuY3Rpb24oZSl7cmV0dXJuIHIoZSk9PT1hfSx0LmlzU3RyaWN0TW9kZT1mdW5jdGlvbihlKXtyZXR1cm4gcihlKT09PXV9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2b2lkIDA9PT10JiYodD1pKTt2YXIgbixyLG89W10sYT0hMSxzPWZ1bmN0aW9uKGUsbil7cmV0dXJuIHQoZSxvW25dKX07cmV0dXJuIGZ1bmN0aW9uKCl7Zm9yKHZhciB0PWFyZ3VtZW50cy5sZW5ndGgsaT1uZXcgQXJyYXkodCksdT0wO3U8dDt1KyspaVt1XT1hcmd1bWVudHNbdV07cmV0dXJuIGEmJm49PT10aGlzJiZpLmxlbmd0aD09PW8ubGVuZ3RoJiZpLmV2ZXJ5KHMpP3I6KHI9ZS5hcHBseSh0aGlzLGkpLGE9ITAsbj10aGlzLG89aSxyKX19dmFyIGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZT09PXR9O3QuYT1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNTMxKSxpPS9eKChjaGlsZHJlbnxkYW5nZXJvdXNseVNldElubmVySFRNTHxrZXl8cmVmfGF1dG9Gb2N1c3xkZWZhdWx0VmFsdWV8ZGVmYXVsdENoZWNrZWR8aW5uZXJIVE1MfHN1cHByZXNzQ29udGVudEVkaXRhYmxlV2FybmluZ3x2YWx1ZUxpbmt8YWNjZXB0fGFjY2VwdENoYXJzZXR8YWNjZXNzS2V5fGFjdGlvbnxhbGxvd3xhbGxvd0Z1bGxTY3JlZW58YWxsb3dUcmFuc3BhcmVuY3l8YWx0fGFzeW5jfGF1dG9Db21wbGV0ZXxhdXRvUGxheXxjYXB0dXJlfGNlbGxQYWRkaW5nfGNlbGxTcGFjaW5nfGNoYWxsZW5nZXxjaGFyU2V0fGNoZWNrZWR8Y2l0ZXxjbGFzc0lEfGNsYXNzTmFtZXxjb2xzfGNvbFNwYW58Y29udGVudHxjb250ZW50RWRpdGFibGV8Y29udGV4dE1lbnV8Y29udHJvbHN8Y29udHJvbHNMaXN0fGNvb3Jkc3xjcm9zc09yaWdpbnxkYXRhfGRhdGVUaW1lfGRlZmF1bHR8ZGVmZXJ8ZGlyfGRpc2FibGVkfGRvd25sb2FkfGRyYWdnYWJsZXxlbmNUeXBlfGZvcm18Zm9ybUFjdGlvbnxmb3JtRW5jVHlwZXxmb3JtTWV0aG9kfGZvcm1Ob1ZhbGlkYXRlfGZvcm1UYXJnZXR8ZnJhbWVCb3JkZXJ8aGVhZGVyc3xoZWlnaHR8aGlkZGVufGhpZ2h8aHJlZnxocmVmTGFuZ3xodG1sRm9yfGh0dHBFcXVpdnxpZHxpbnB1dE1vZGV8aW50ZWdyaXR5fGlzfGtleVBhcmFtc3xrZXlUeXBlfGtpbmR8bGFiZWx8bGFuZ3xsaXN0fGxvb3B8bG93fG1hcmdpbkhlaWdodHxtYXJnaW5XaWR0aHxtYXh8bWF4TGVuZ3RofG1lZGlhfG1lZGlhR3JvdXB8bWV0aG9kfG1pbnxtaW5MZW5ndGh8bXVsdGlwbGV8bXV0ZWR8bmFtZXxub25jZXxub1ZhbGlkYXRlfG9wZW58b3B0aW11bXxwYXR0ZXJufHBsYWNlaG9sZGVyfHBsYXlzSW5saW5lfHBvc3RlcnxwcmVsb2FkfHByb2ZpbGV8cmFkaW9Hcm91cHxyZWFkT25seXxyZWZlcnJlclBvbGljeXxyZWx8cmVxdWlyZWR8cmV2ZXJzZWR8cm9sZXxyb3dzfHJvd1NwYW58c2FuZGJveHxzY29wZXxzY29wZWR8c2Nyb2xsaW5nfHNlYW1sZXNzfHNlbGVjdGVkfHNoYXBlfHNpemV8c2l6ZXN8c2xvdHxzcGFufHNwZWxsQ2hlY2t8c3JjfHNyY0RvY3xzcmNMYW5nfHNyY1NldHxzdGFydHxzdGVwfHN0eWxlfHN1bW1hcnl8dGFiSW5kZXh8dGFyZ2V0fHRpdGxlfHR5cGV8dXNlTWFwfHZhbHVlfHdpZHRofHdtb2RlfHdyYXB8YWJvdXR8ZGF0YXR5cGV8aW5saXN0fHByZWZpeHxwcm9wZXJ0eXxyZXNvdXJjZXx0eXBlb2Z8dm9jYWJ8YXV0b0NhcGl0YWxpemV8YXV0b0NvcnJlY3R8YXV0b1NhdmV8Y29sb3J8aXRlbVByb3B8aXRlbVNjb3BlfGl0ZW1UeXBlfGl0ZW1JRHxpdGVtUmVmfHJlc3VsdHN8c2VjdXJpdHl8dW5zZWxlY3RhYmxlfGFjY2VudEhlaWdodHxhY2N1bXVsYXRlfGFkZGl0aXZlfGFsaWdubWVudEJhc2VsaW5lfGFsbG93UmVvcmRlcnxhbHBoYWJldGljfGFtcGxpdHVkZXxhcmFiaWNGb3JtfGFzY2VudHxhdHRyaWJ1dGVOYW1lfGF0dHJpYnV0ZVR5cGV8YXV0b1JldmVyc2V8YXppbXV0aHxiYXNlRnJlcXVlbmN5fGJhc2VsaW5lU2hpZnR8YmFzZVByb2ZpbGV8YmJveHxiZWdpbnxiaWFzfGJ5fGNhbGNNb2RlfGNhcEhlaWdodHxjbGlwfGNsaXBQYXRoVW5pdHN8Y2xpcFBhdGh8Y2xpcFJ1bGV8Y29sb3JJbnRlcnBvbGF0aW9ufGNvbG9ySW50ZXJwb2xhdGlvbkZpbHRlcnN8Y29sb3JQcm9maWxlfGNvbG9yUmVuZGVyaW5nfGNvbnRlbnRTY3JpcHRUeXBlfGNvbnRlbnRTdHlsZVR5cGV8Y3Vyc29yfGN4fGN5fGR8ZGVjZWxlcmF0ZXxkZXNjZW50fGRpZmZ1c2VDb25zdGFudHxkaXJlY3Rpb258ZGlzcGxheXxkaXZpc29yfGRvbWluYW50QmFzZWxpbmV8ZHVyfGR4fGR5fGVkZ2VNb2RlfGVsZXZhdGlvbnxlbmFibGVCYWNrZ3JvdW5kfGVuZHxleHBvbmVudHxleHRlcm5hbFJlc291cmNlc1JlcXVpcmVkfGZpbGx8ZmlsbE9wYWNpdHl8ZmlsbFJ1bGV8ZmlsdGVyfGZpbHRlclJlc3xmaWx0ZXJVbml0c3xmbG9vZENvbG9yfGZsb29kT3BhY2l0eXxmb2N1c2FibGV8Zm9udEZhbWlseXxmb250U2l6ZXxmb250U2l6ZUFkanVzdHxmb250U3RyZXRjaHxmb250U3R5bGV8Zm9udFZhcmlhbnR8Zm9udFdlaWdodHxmb3JtYXR8ZnJvbXxmcnxmeHxmeXxnMXxnMnxnbHlwaE5hbWV8Z2x5cGhPcmllbnRhdGlvbkhvcml6b250YWx8Z2x5cGhPcmllbnRhdGlvblZlcnRpY2FsfGdseXBoUmVmfGdyYWRpZW50VHJhbnNmb3JtfGdyYWRpZW50VW5pdHN8aGFuZ2luZ3xob3JpekFkdlh8aG9yaXpPcmlnaW5YfGlkZW9ncmFwaGljfGltYWdlUmVuZGVyaW5nfGlufGluMnxpbnRlcmNlcHR8a3xrMXxrMnxrM3xrNHxrZXJuZWxNYXRyaXh8a2VybmVsVW5pdExlbmd0aHxrZXJuaW5nfGtleVBvaW50c3xrZXlTcGxpbmVzfGtleVRpbWVzfGxlbmd0aEFkanVzdHxsZXR0ZXJTcGFjaW5nfGxpZ2h0aW5nQ29sb3J8bGltaXRpbmdDb25lQW5nbGV8bG9jYWx8bWFya2VyRW5kfG1hcmtlck1pZHxtYXJrZXJTdGFydHxtYXJrZXJIZWlnaHR8bWFya2VyVW5pdHN8bWFya2VyV2lkdGh8bWFza3xtYXNrQ29udGVudFVuaXRzfG1hc2tVbml0c3xtYXRoZW1hdGljYWx8bW9kZXxudW1PY3RhdmVzfG9mZnNldHxvcGFjaXR5fG9wZXJhdG9yfG9yZGVyfG9yaWVudHxvcmllbnRhdGlvbnxvcmlnaW58b3ZlcmZsb3d8b3ZlcmxpbmVQb3NpdGlvbnxvdmVybGluZVRoaWNrbmVzc3xwYW5vc2UxfHBhaW50T3JkZXJ8cGF0aExlbmd0aHxwYXR0ZXJuQ29udGVudFVuaXRzfHBhdHRlcm5UcmFuc2Zvcm18cGF0dGVyblVuaXRzfHBvaW50ZXJFdmVudHN8cG9pbnRzfHBvaW50c0F0WHxwb2ludHNBdFl8cG9pbnRzQXRafHByZXNlcnZlQWxwaGF8cHJlc2VydmVBc3BlY3RSYXRpb3xwcmltaXRpdmVVbml0c3xyfHJhZGl1c3xyZWZYfHJlZll8cmVuZGVyaW5nSW50ZW50fHJlcGVhdENvdW50fHJlcGVhdER1cnxyZXF1aXJlZEV4dGVuc2lvbnN8cmVxdWlyZWRGZWF0dXJlc3xyZXN0YXJ0fHJlc3VsdHxyb3RhdGV8cnh8cnl8c2NhbGV8c2VlZHxzaGFwZVJlbmRlcmluZ3xzbG9wZXxzcGFjaW5nfHNwZWN1bGFyQ29uc3RhbnR8c3BlY3VsYXJFeHBvbmVudHxzcGVlZHxzcHJlYWRNZXRob2R8c3RhcnRPZmZzZXR8c3RkRGV2aWF0aW9ufHN0ZW1ofHN0ZW12fHN0aXRjaFRpbGVzfHN0b3BDb2xvcnxzdG9wT3BhY2l0eXxzdHJpa2V0aHJvdWdoUG9zaXRpb258c3RyaWtldGhyb3VnaFRoaWNrbmVzc3xzdHJpbmd8c3Ryb2tlfHN0cm9rZURhc2hhcnJheXxzdHJva2VEYXNob2Zmc2V0fHN0cm9rZUxpbmVjYXB8c3Ryb2tlTGluZWpvaW58c3Ryb2tlTWl0ZXJsaW1pdHxzdHJva2VPcGFjaXR5fHN0cm9rZVdpZHRofHN1cmZhY2VTY2FsZXxzeXN0ZW1MYW5ndWFnZXx0YWJsZVZhbHVlc3x0YXJnZXRYfHRhcmdldFl8dGV4dEFuY2hvcnx0ZXh0RGVjb3JhdGlvbnx0ZXh0UmVuZGVyaW5nfHRleHRMZW5ndGh8dG98dHJhbnNmb3JtfHUxfHUyfHVuZGVybGluZVBvc2l0aW9ufHVuZGVybGluZVRoaWNrbmVzc3x1bmljb2RlfHVuaWNvZGVCaWRpfHVuaWNvZGVSYW5nZXx1bml0c1BlckVtfHZBbHBoYWJldGljfHZIYW5naW5nfHZJZGVvZ3JhcGhpY3x2TWF0aGVtYXRpY2FsfHZhbHVlc3x2ZWN0b3JFZmZlY3R8dmVyc2lvbnx2ZXJ0QWR2WXx2ZXJ0T3JpZ2luWHx2ZXJ0T3JpZ2luWXx2aWV3Qm94fHZpZXdUYXJnZXR8dmlzaWJpbGl0eXx3aWR0aHN8d29yZFNwYWNpbmd8d3JpdGluZ01vZGV8eHx4SGVpZ2h0fHgxfHgyfHhDaGFubmVsU2VsZWN0b3J8eGxpbmtBY3R1YXRlfHhsaW5rQXJjcm9sZXx4bGlua0hyZWZ8eGxpbmtSb2xlfHhsaW5rU2hvd3x4bGlua1RpdGxlfHhsaW5rVHlwZXx4bWxCYXNlfHhtbG5zfHhtbG5zWGxpbmt8eG1sTGFuZ3x4bWxTcGFjZXx5fHkxfHkyfHlDaGFubmVsU2VsZWN0b3J8enx6b29tQW5kUGFufGZvcnxjbGFzcyl8KG9uW0EtWl0uKil8KChkYXRhfGFyaWF8eCktLiopKSQvaSxvPU9iamVjdChyLmEpKGkudGVzdC5iaW5kKGkpKTt0LmE9b30sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PXt9O3JldHVybiBmdW5jdGlvbihuKXtyZXR1cm4gdm9pZCAwPT09dFtuXSYmKHRbbl09ZShuKSksdFtuXX19dC5hPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7KGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHIoZSx0KXt2YXIgbj10fHx3aW5kb3cubG9jYXRpb24uaHJlZjtlPWUucmVwbGFjZSgvW1xbXF1dL2csIlxcJCYiKTt2YXIgcj1uZXcgUmVnRXhwKCJbPyZdIitlKyIoPShbXiYjXSopfCZ8I3wkKSIpLGk9ci5leGVjKG4pO3JldHVybiBpJiZpWzJdP2RlY29kZVVSSUNvbXBvbmVudChpWzJdLnJlcGxhY2UoL1wrL2csIiAiKSk6bnVsbH1mdW5jdGlvbiBpKGUsdCl7cmV0dXJuIHUodGhpcyx2b2lkIDAsdm9pZCAwLGZ1bmN0aW9uKCl7dmFyIG4scixpO3JldHVybiBjKHRoaXMsZnVuY3Rpb24obyl7c3dpdGNoKG8ubGFiZWwpe2Nhc2UgMDpuPTAsby5sYWJlbD0xO2Nhc2UgMTpyZXR1cm4gbjxlLmxlbmd0aD8ocj1lW25dLFs0LHQocixuKV0pOlszLDRdO2Nhc2UgMjppZihpPW8uc2VudCgpKXJldHVyblsyLHJdO28ubGFiZWw9MztjYXNlIDM6cmV0dXJuIG4rKyxbMywxXTtjYXNlIDQ6cmV0dXJuWzIsbnVsbF19fSl9KX12YXIgbz1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGE9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfSxzPWZ1bmN0aW9uKCl7cmV0dXJuIHM9T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0LG49MSxyPWFyZ3VtZW50cy5sZW5ndGg7bjxyO24rKyl7dD1hcmd1bWVudHNbbl07Zm9yKHZhciBpIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsaSkmJihlW2ldPXRbaV0pfXJldHVybiBlfSxzLmFwcGx5KHRoaXMsYXJndW1lbnRzKX0sdT1mdW5jdGlvbihlLHQsbixyKXtyZXR1cm4gbmV3KG58fChuPVByb21pc2UpKShmdW5jdGlvbihpLG8pe2Z1bmN0aW9uIGEoZSl7dHJ5e3Uoci5uZXh0KGUpKX1jYXRjaChlKXtvKGUpfX1mdW5jdGlvbiBzKGUpe3RyeXt1KHIudGhyb3coZSkpfWNhdGNoKGUpe28oZSl9fWZ1bmN0aW9uIHUoZSl7ZS5kb25lP2koZS52YWx1ZSk6bmV3IG4oZnVuY3Rpb24odCl7dChlLnZhbHVlKX0pLnRoZW4oYSxzKX11KChyPXIuYXBwbHkoZSx0fHxbXSkpLm5leHQoKSl9KX0sYz1mdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiByKFtlLHRdKX19ZnVuY3Rpb24gcihuKXtpZihpKXRocm93IG5ldyBUeXBlRXJyb3IoIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy4iKTtmb3IoO3U7KXRyeXtpZihpPTEsbyYmKGE9MiZuWzBdP28ucmV0dXJuOm5bMF0/by50aHJvd3x8KChhPW8ucmV0dXJuKSYmYS5jYWxsKG8pLDApOm8ubmV4dCkmJiEoYT1hLmNhbGwobyxuWzFdKSkuZG9uZSlyZXR1cm4gYTtzd2l0Y2gobz0wLGEmJihuPVsyJm5bMF0sYS52YWx1ZV0pLG5bMF0pe2Nhc2UgMDpjYXNlIDE6YT1uO2JyZWFrO2Nhc2UgNDpyZXR1cm4gdS5sYWJlbCsrLHt2YWx1ZTpuWzFdLGRvbmU6ITF9O2Nhc2UgNTp1LmxhYmVsKyssbz1uWzFdLG49WzBdO2NvbnRpbnVlO2Nhc2UgNzpuPXUub3BzLnBvcCgpLHUudHJ5cy5wb3AoKTtjb250aW51ZTtkZWZhdWx0OmlmKGE9dS50cnlzLCEoYT1hLmxlbmd0aD4wJiZhW2EubGVuZ3RoLTFdKSYmKDY9PT1uWzBdfHwyPT09blswXSkpe3U9MDtjb250aW51ZX1pZigzPT09blswXSYmKCFhfHxuWzFdPmFbMF0mJm5bMV08YVszXSkpe3UubGFiZWw9blsxXTticmVha31pZig2PT09blswXSYmdS5sYWJlbDxhWzFdKXt1LmxhYmVsPWFbMV0sYT1uO2JyZWFrfWlmKGEmJnUubGFiZWw8YVsyXSl7dS5sYWJlbD1hWzJdLHUub3BzLnB1c2gobik7YnJlYWt9YVsyXSYmdS5vcHMucG9wKCksdS50cnlzLnBvcCgpO2NvbnRpbnVlfW49dC5jYWxsKGUsdSl9Y2F0Y2goZSl7bj1bNixlXSxvPTB9ZmluYWxseXtpPWE9MH1pZig1Jm5bMF0pdGhyb3cgblsxXTtyZXR1cm57dmFsdWU6blswXT9uWzFdOnZvaWQgMCxkb25lOiEwfX12YXIgaSxvLGEscyx1PXtsYWJlbDowLHNlbnQ6ZnVuY3Rpb24oKXtpZigxJmFbMF0pdGhyb3cgYVsxXTtyZXR1cm4gYVsxXX0sdHJ5czpbXSxvcHM6W119O3JldHVybiBzPXtuZXh0Om4oMCksdGhyb3c6bigxKSxyZXR1cm46bigyKX0sImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJihzW1N5bWJvbC5pdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pLHN9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbD1uKDApLHA9big1MzMpLGY9big3MTUpLGQ9big3MjIpLGg9big3NDgpLG09bigxKSxnPW4oMjU5KSx5PW4oMTQ3KSx2PW4oOSksYj1uKDE3KSx4PW4oMTUwKSxDPW4oNyksRT1mdW5jdGlvbih0KXtmdW5jdGlvbiBuKG4pe3ZhciByPXQuY2FsbCh0aGlzLG4pfHx0aGlzO3JldHVybiByLmhhbmRsZVVwZGF0ZVNlc3Npb25Db3VudD1mdW5jdGlvbigpe3IuZm9yY2VVcGRhdGUoKX0sci5nZXRQbGF5Z3JvdW5kUmVmPWZ1bmN0aW9uKGUpe3IucGxheWdyb3VuZD1lLCJmdW5jdGlvbiI9PT10eXBlb2Ygci5wcm9wcy5nZXRSZWYmJnIucHJvcHMuZ2V0UmVmKGUpfSxyLmhhbmRsZUNoYW5nZUNvbmZpZz1mdW5jdGlvbihlKXtyLnNldFN0YXRlKHtjb25maWdTdHJpbmc6ZX0pfSxyLmhhbmRsZVNhdmVDb25maWc9ZnVuY3Rpb24oKXsiZnVuY3Rpb24iPT09dHlwZW9mIHIucHJvcHMub25TYXZlQ29uZmlnJiZyLnByb3BzLm9uU2F2ZUNvbmZpZyhyLnN0YXRlLmNvbmZpZ1N0cmluZyl9LHIuaGFuZGxlU2VsZWN0RW52PWZ1bmN0aW9uKGUsdCl7dmFyIG49eS5nZXRBY3RpdmVFbmRwb2ludHMoci5wcm9wcy5jb25maWcsZSx0KSxpPW4uZW5kcG9pbnQsbz1uLnN1YnNjcmlwdGlvbkVuZHBvaW50LGE9bi5oZWFkZXJzO3Iuc2V0U3RhdGUoe2FjdGl2ZUVudjplLGVuZHBvaW50OmksaGVhZGVyczphLHN1YnNjcmlwdGlvbkVuZHBvaW50OnIubm9ybWFsaXplU3Vic2NyaXB0aW9uVXJsKGksbyksYWN0aXZlUHJvamVjdE5hbWU6dH0pfSxyLmhhbmRsZUNoYW5nZUVuZHBvaW50PWZ1bmN0aW9uKGUpe3Iuc2V0U3RhdGUoe2VuZHBvaW50OmV9KX0sci5oYW5kbGVDaGFuZ2VTdWJzY3JpcHRpb25zRW5kcG9pbnQ9ZnVuY3Rpb24oZSl7ci5zZXRTdGF0ZSh7c3Vic2NyaXB0aW9uRW5kcG9pbnQ6ZX0pfSxlLm09cixyLnN0YXRlPXIubWFwUHJvcHNUb1N0YXRlKG4pLHIucmVtb3ZlTG9hZGVyKCkscn1yZXR1cm4gbyhuLHQpLG4ucHJvdG90eXBlLm1hcFByb3BzVG9TdGF0ZT1mdW5jdGlvbihlKXt2YXIgdD0hIWUuY29uZmlnU3RyaW5nJiZ0aGlzLmlzQ29uZmlnWWFtbChlLmNvbmZpZ1N0cmluZyksbj10aGlzLmdldEluaXRpYWxBY3RpdmVFbnYoZS5jb25maWcpLGk9bi5hY3RpdmVFbnYsbz1uLnByb2plY3ROYW1lLGE9ZS5lbmRwb2ludHx8ZS5lbmRwb2ludFVybHx8cigiZW5kcG9pbnQiKXx8bG9jYXRpb24uaHJlZixzPXRoaXMuZXh0cmFjdEVuZHBvaW50QW5kSGVhZGVycyhhKTthPXMuZW5kcG9pbnQ7dmFyIHU9cy5oZWFkZXJzLGM9ZS5zdWJzY3JpcHRpb25FbmRwb2ludHx8cigic3Vic2NyaXB0aW9uRW5kcG9pbnQiKTtpZihlLmNvbmZpZ1N0cmluZyYmZS5jb25maWcmJmkpe3ZhciBsPXkuZ2V0QWN0aXZlRW5kcG9pbnRzKGUuY29uZmlnLGksbyk7YT1sLmVuZHBvaW50LGM9bC5zdWJzY3JpcHRpb25FbmRwb2ludCx1PWwuaGVhZGVyc31yZXR1cm4gYz10aGlzLm5vcm1hbGl6ZVN1YnNjcmlwdGlvblVybChhLGMpfHx2b2lkIDAse2VuZHBvaW50OnRoaXMuYWJzb2x1dGl6ZVVybChhKSxwbGF0Zm9ybVRva2VuOmUucGxhdGZvcm1Ub2tlbnx8bG9jYWxTdG9yYWdlLmdldEl0ZW0oInBsYXRmb3JtLXRva2VuIil8fHZvaWQgMCxzdWJzY3JpcHRpb25FbmRwb2ludDpjLGNvbmZpZ0lzWWFtbDp0LGNvbmZpZ1N0cmluZzplLmNvbmZpZ1N0cmluZyxhY3RpdmVFbnY6aSxhY3RpdmVQcm9qZWN0TmFtZTpvLGhlYWRlcnM6dX19LG4ucHJvdG90eXBlLmV4dHJhY3RFbmRwb2ludEFuZEhlYWRlcnM9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5zcGxpdCgiPyIpO2lmKDE9PT10Lmxlbmd0aClyZXR1cm57ZW5kcG9pbnQ6ZX07dHJ5e3ZhciBuPXIoImhlYWRlcnMiLGUpO2lmKG4pcmV0dXJue2hlYWRlcnM6SlNPTi5wYXJzZShuKSxlbmRwb2ludDp0WzBdfX1jYXRjaChlKXt9cmV0dXJue2VuZHBvaW50OnRbMF19fSxuLnByb3RvdHlwZS5yZW1vdmVMb2FkZXI9ZnVuY3Rpb24oKXt2YXIgZT1kb2N1bWVudC5nZXRFbGVtZW50QnlJZCgibG9hZGluZy13cmFwcGVyIik7ZSYmZS5yZW1vdmUoKX0sbi5wcm90b3R5cGUubm9ybWFsaXplU3Vic2NyaXB0aW9uVXJsPWZ1bmN0aW9uKGUsdCl7aWYodCl7aWYodC5zdGFydHNXaXRoKCIvIikpe3JldHVybiJ3cyIrKGUuaW5jbHVkZXMoImh0dHBzIil8fGxvY2F0aW9uLmhyZWYuaW5jbHVkZXMoImh0dHBzIik/InMiOiIiKSsiOi8vIitsb2NhdGlvbi5ob3N0K3R9cmV0dXJuIHQucmVwbGFjZSgvXmh0dHAvLCJ3cyIpfXJldHVybiB0aGlzLmdldEdyYXBoY29vbFN1YnNjcmlwdGlvbkVuZHBvaW50KGUpLnJlcGxhY2UoL15odHRwLywid3MiKX0sbi5wcm90b3R5cGUuZ2V0R3JhcGhjb29sU3Vic2NyaXB0aW9uRW5kcG9pbnQ9ZnVuY3Rpb24oZSl7cmV0dXJuIGUuaW5jbHVkZXMoImFwaS5ncmFwaC5jb29sIik/IndzczovL3N1YnNjcmlwdGlvbnMuZ3JhcGguY29vbC92MS8iK2Uuc3BsaXQoIi8iKS5zbGljZSgtMSlbMF06ZS5yZXBsYWNlKC9eaHR0cC8sIndzIil9LG4ucHJvdG90eXBlLmNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHM9ZnVuY3Rpb24oZSl7ZS5lbmRwb2ludD09PXRoaXMucHJvcHMuZW5kcG9pbnQmJmUuZW5kcG9pbnRVcmw9PT10aGlzLnByb3BzLmVuZHBvaW50VXJsJiZlLnN1YnNjcmlwdGlvbkVuZHBvaW50PT09dGhpcy5wcm9wcy5zdWJzY3JpcHRpb25FbmRwb2ludCYmZS5jb25maWdTdHJpbmc9PT10aGlzLnByb3BzLmNvbmZpZ1N0cmluZyYmZS5wbGF0Zm9ybVRva2VuPT09dGhpcy5wcm9wcy5wbGF0Zm9ybVRva2VuJiZlLmNvbmZpZz09PXRoaXMucHJvcHMuY29uZmlnfHwodGhpcy5zZXRTdGF0ZSh0aGlzLm1hcFByb3BzVG9TdGF0ZShlKSksdGhpcy5zZXRJbml0aWFsV29ya3NwYWNlKGUpKX0sbi5wcm90b3R5cGUuZ2V0SW5pdGlhbEFjdGl2ZUVudj1mdW5jdGlvbihlKXtpZihlKXtpZihlLmV4dGVuc2lvbnMmJmUuZXh0ZW5zaW9ucy5lbmRwb2ludHMpcmV0dXJue2FjdGl2ZUVudjpPYmplY3Qua2V5cyhlLmV4dGVuc2lvbnMuZW5kcG9pbnRzKVswXX07aWYoZS5wcm9qZWN0cyl7dmFyIHQ9T2JqZWN0LmtleXMoZS5wcm9qZWN0cylbMF0sbj1lLnByb2plY3RzW3RdO2lmKG4uZXh0ZW5zaW9ucyYmbi5leHRlbnNpb25zLmVuZHBvaW50cylyZXR1cm57YWN0aXZlRW52Ok9iamVjdC5rZXlzKG4uZXh0ZW5zaW9ucy5lbmRwb2ludHMpWzBdLHByb2plY3ROYW1lOnR9fX1yZXR1cm57fX0sbi5wcm90b3R5cGUuaXNDb25maWdZYW1sPWZ1bmN0aW9uKGUpe3RyeXtyZXR1cm4gZC5zYWZlTG9hZChlKSwhMH1jYXRjaChlKXt9cmV0dXJuITF9LG4ucHJvdG90eXBlLmFic29sdXRpemVVcmw9ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc3RhcnRzV2l0aCgiLyIpP2xvY2F0aW9uLm9yaWdpbitlOmV9LG4ucHJvdG90eXBlLmNvbXBvbmVudFdpbGxNb3VudD1mdW5jdGlvbigpe3ZhciBlPXIoInBsYXRmb3JtLXRva2VuIik7ZSYmZS5sZW5ndGg+MCYmKGxvY2FsU3RvcmFnZS5zZXRJdGVtKCJwbGF0Zm9ybS10b2tlbiIsZSksd2luZG93LmxvY2F0aW9uLnJlcGxhY2Uod2luZG93LmxvY2F0aW9uLm9yaWdpbit3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUpKX0sbi5wcm90b3R5cGUuY29tcG9uZW50RGlkTW91bnQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzO2lmKCIiPT09dGhpcy5zdGF0ZS5zdWJzY3JpcHRpb25FbmRwb2ludCYmdGhpcy51cGRhdGVTdWJzY3JpcHRpb25zVXJsKCksc2V0VGltZW91dChmdW5jdGlvbigpe2UucmVtb3ZlUGxheWdyb3VuZEluQ2xhc3MoKX0sNWUzKSx0aGlzLnNldEluaXRpYWxXb3Jrc3BhY2UoKSx0aGlzLnByb3BzLnRhYnMpdGhpcy5wcm9wcy5pbmplY3RUYWJzKHRoaXMucHJvcHMudGFicyk7ZWxzZXt2YXIgdD1yKCJxdWVyeSIpO2lmKHQpe3ZhciBuPXIoImVuZHBvaW50Iil8fHRoaXMuc3RhdGUuZW5kcG9pbnQ7dGhpcy5wcm9wcy5pbmplY3RUYWJzKFt7cXVlcnk6dCxlbmRwb2ludDpufV0pfWVsc2V7dmFyIGk9cigidGFicyIpO2lmKGkpdHJ5e3ZhciBvPUpTT04ucGFyc2UoaSk7dGhpcy5wcm9wcy5pbmplY3RUYWJzKG8pfWNhdGNoKGUpe319fXRoaXMucHJvcHMuc2NoZW1hJiYoInN0cmluZyI9PT10eXBlb2YgdGhpcy5wcm9wcy5zY2hlbWE/dGhpcy5zZXRTdGF0ZSh7c2NoZW1hOkMuYnVpbGRTY2hlbWEodGhpcy5wcm9wcy5zY2hlbWEpfSk6dGhpcy5zZXRTdGF0ZSh7c2NoZW1hOkMuYnVpbGRDbGllbnRTY2hlbWEodGhpcy5wcm9wcy5zY2hlbWEpfSkpfSxuLnByb3RvdHlwZS5zZXRJbml0aWFsV29ya3NwYWNlPWZ1bmN0aW9uKGUpe2lmKHZvaWQgMD09PWUmJihlPXRoaXMucHJvcHMpLGUuY29uZmlnKXt2YXIgdD10aGlzLmdldEluaXRpYWxBY3RpdmVFbnYoZS5jb25maWcpLG49eS5nZXRBY3RpdmVFbmRwb2ludHMoZS5jb25maWcsdC5hY3RpdmVFbnYsdC5wcm9qZWN0TmFtZSkscj1uLmVuZHBvaW50LGk9bi5zdWJzY3JpcHRpb25FbmRwb2ludHx8dGhpcy5ub3JtYWxpemVTdWJzY3JpcHRpb25VcmwocixuLnN1YnNjcmlwdGlvbkVuZHBvaW50KSxvPW4uaGVhZGVyczt0aGlzLnNldFN0YXRlKHtlbmRwb2ludDpyLHN1YnNjcmlwdGlvbkVuZHBvaW50OmksaGVhZGVyczpvLGFjdGl2ZUVudjp0LmFjdGl2ZUVudixhY3RpdmVQcm9qZWN0TmFtZTp0LnByb2plY3ROYW1lfSl9fSxuLnByb3RvdHlwZS5yZW1vdmVQbGF5Z3JvdW5kSW5DbGFzcz1mdW5jdGlvbigpe3ZhciBlPWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJyb290Iik7ZSYmZS5jbGFzc0xpc3QucmVtb3ZlKCJwbGF5Z3JvdW5kSW4iKX0sbi5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcy5zZXRUaXRsZT9sLmNyZWF0ZUVsZW1lbnQoZi5IZWxtZXQsbnVsbCxsLmNyZWF0ZUVsZW1lbnQoInRpdGxlIixudWxsLHRoaXMuZ2V0VGl0bGUoKSkpOm51bGwsdD10aGlzLnByb3BzLmhlYWRlcnN8fHt9LG49dGhpcy5zdGF0ZS5oZWFkZXJzfHx7fSxyPXMoe30sdCxuKSxpPXRoaXMucHJvcHMudGhlbWU7cmV0dXJuIGwuY3JlYXRlRWxlbWVudCgiZGl2IixudWxsLGUsbC5jcmVhdGVFbGVtZW50KG0uVGhlbWVQcm92aWRlcix7dGhlbWU6cyh7fSxtLnRoZW1lLHttb2RlOmksY29sb3VyczoiZGFyayI9PT1pP2cuZGFya0NvbG91cnM6Zy5saWdodENvbG91cnMsZWRpdG9yQ29sb3VyczpzKHt9LCJkYXJrIj09PWk/Zy5kYXJrRWRpdG9yQ29sb3VyczpnLmxpZ2h0RWRpdG9yQ29sb3Vycyx0aGlzLnByb3BzLmNvZGVUaGVtZSksc2V0dGluZ3M6dGhpcy5wcm9wcy5zZXR0aW5nc30pfSxsLmNyZWF0ZUVsZW1lbnQoQSxudWxsLHRoaXMucHJvcHMuY29uZmlnJiZ0aGlzLnN0YXRlLmFjdGl2ZUVudiYmbC5jcmVhdGVFbGVtZW50KGguZGVmYXVsdCx7Y29uZmlnOnRoaXMucHJvcHMuY29uZmlnLGZvbGRlck5hbWU6dGhpcy5wcm9wcy5mb2xkZXJOYW1lfHwiR3JhcGhRTCBBcHAiLHRoZW1lOmksYWN0aXZlRW52OnRoaXMuc3RhdGUuYWN0aXZlRW52LG9uU2VsZWN0RW52OnRoaXMuaGFuZGxlU2VsZWN0RW52LG9uTmV3V29ya3NwYWNlOnRoaXMucHJvcHMub25OZXdXb3Jrc3BhY2Usc2hvd05ld1dvcmtzcGFjZTpCb29sZWFuKHRoaXMucHJvcHMuc2hvd05ld1dvcmtzcGFjZSksaXNFbGVjdHJvbjpCb29sZWFuKHRoaXMucHJvcHMuaXNFbGVjdHJvbiksYWN0aXZlUHJvamVjdE5hbWU6dGhpcy5zdGF0ZS5hY3RpdmVQcm9qZWN0TmFtZSxjb25maWdQYXRoOnRoaXMucHJvcHMuY29uZmlnUGF0aH0pLGwuY3JlYXRlRWxlbWVudChwLmRlZmF1bHQse2VuZHBvaW50OnRoaXMuc3RhdGUuZW5kcG9pbnQsc2hhcmVFbmFibGVkOnRoaXMucHJvcHMuc2hhcmVFbmFibGVkLHN1YnNjcmlwdGlvbkVuZHBvaW50OnRoaXMuc3RhdGUuc3Vic2NyaXB0aW9uRW5kcG9pbnQsc2hhcmVVcmw6dGhpcy5zdGF0ZS5zaGFyZVVybCxvbkNoYW5nZUVuZHBvaW50OnRoaXMuaGFuZGxlQ2hhbmdlRW5kcG9pbnQsb25DaGFuZ2VTdWJzY3JpcHRpb25zRW5kcG9pbnQ6dGhpcy5oYW5kbGVDaGFuZ2VTdWJzY3JpcHRpb25zRW5kcG9pbnQsYWRtaW5BdXRoVG9rZW46dGhpcy5zdGF0ZS5wbGF0Zm9ybVRva2VuLGdldFJlZjp0aGlzLmdldFBsYXlncm91bmRSZWYsY29uZmlnOnRoaXMucHJvcHMuY29uZmlnLGNvbmZpZ1N0cmluZzp0aGlzLnN0YXRlLmNvbmZpZ1N0cmluZyxjb25maWdJc1lhbWw6dGhpcy5zdGF0ZS5jb25maWdJc1lhbWwsY2FuU2F2ZUNvbmZpZzpCb29sZWFuKHRoaXMucHJvcHMuY2FuU2F2ZUNvbmZpZyksb25DaGFuZ2VDb25maWc6dGhpcy5oYW5kbGVDaGFuZ2VDb25maWcsb25TYXZlQ29uZmlnOnRoaXMuaGFuZGxlU2F2ZUNvbmZpZyxvblVwZGF0ZVNlc3Npb25Db3VudDp0aGlzLmhhbmRsZVVwZGF0ZVNlc3Npb25Db3VudCxmaXhlZEVuZHBvaW50czpCb29sZWFuKHRoaXMuc3RhdGUuY29uZmlnU3RyaW5nKSxmaXhlZEVuZHBvaW50OnRoaXMucHJvcHMuZml4ZWRFbmRwb2ludCxoZWFkZXJzOnIsY29uZmlnUGF0aDp0aGlzLnByb3BzLmNvbmZpZ1BhdGgsd29ya3NwYWNlTmFtZTp0aGlzLnByb3BzLndvcmtzcGFjZU5hbWV8fHRoaXMuc3RhdGUuYWN0aXZlUHJvamVjdE5hbWUsY3JlYXRlQXBvbGxvTGluazp0aGlzLnByb3BzLmNyZWF0ZUFwb2xsb0xpbmssc2NoZW1hOnRoaXMuc3RhdGUuc2NoZW1hfSkpKSl9LG4ucHJvdG90eXBlLmdldFRpdGxlPWZ1bmN0aW9uKCl7aWYodGhpcy5zdGF0ZS5wbGF0Zm9ybVRva2VufHx0aGlzLnN0YXRlLmVuZHBvaW50LmluY2x1ZGVzKCJhcGkuZ3JhcGguY29vbCIpKXt2YXIgZT10aGlzLmdldFByb2plY3RJZCh0aGlzLnN0YXRlLmVuZHBvaW50KTtyZXR1cm4odGhpcy5zdGF0ZS5lbmRwb2ludC5pbmNsdWRlcygiYXBpLmdyYXBoLmNvb2wiKT8ic2hhcmVkIjoibG9jYWwiKSsiLyIrZSsiIC0gUGxheWdyb3VuZCJ9cmV0dXJuIlBsYXlncm91bmQgLSAiK3RoaXMuc3RhdGUuZW5kcG9pbnR9LG4ucHJvdG90eXBlLnVwZGF0ZVN1YnNjcmlwdGlvbnNVcmw9ZnVuY3Rpb24oKXtyZXR1cm4gdSh0aGlzLHZvaWQgMCx2b2lkIDAsZnVuY3Rpb24oKXt2YXIgZSx0LG49dGhpcztyZXR1cm4gYyh0aGlzLGZ1bmN0aW9uKHIpe3N3aXRjaChyLmxhYmVsKXtjYXNlIDA6cmV0dXJuIGU9dGhpcy5nZXRTdWJzY3JpcHRpb25zVXJsQ2FuZGlkYXRlZCh0aGlzLnN0YXRlLmVuZHBvaW50KSxbNCxpKGUsZnVuY3Rpb24oZSl7cmV0dXJuIG4ud3NFbmRwb2ludFZhbGlkKGUpfSldO2Nhc2UgMTpyZXR1cm4gdD1yLnNlbnQoKSx0JiZ0aGlzLnNldFN0YXRlKHtzdWJzY3JpcHRpb25FbmRwb2ludDp0fSksWzJdfX0pfSl9LG4ucHJvdG90eXBlLmdldFN1YnNjcmlwdGlvbnNVcmxDYW5kaWRhdGVkPWZ1bmN0aW9uKGUpe3ZhciB0PVtdO2lmKHQucHVzaChlLnJlcGxhY2UoImh0dHBzIiwid3NzIikucmVwbGFjZSgiaHR0cCIsIndzIikpLGUuaW5jbHVkZXMoImdyYXBoLmNvb2wiKSYmdC5wdXNoKCJ3c3M6Ly9zdWJzY3JpcHRpb25zLmdyYXBoLmNvb2wvdjEvIit0aGlzLmdldFByb2plY3RJZChlKSksZS5pbmNsdWRlcygiL3NpbXBsZS92MS8iKSl7dmFyIG49ZS5tYXRjaCgvaHR0cHM/OlwvXC8oLio/KVwvLyk7dC5wdXNoKCJ3czovLyIrblsxXSsiL3N1YnNjcmlwdGlvbnMvdjEvIit0aGlzLmdldFByb2plY3RJZChlKSl9cmV0dXJuIHR9LG4ucHJvdG90eXBlLndzRW5kcG9pbnRWYWxpZD1mdW5jdGlvbihlKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24odCl7dmFyIG49bmV3IFdlYlNvY2tldChlLCJncmFwaHFsLXdzIik7bi5hZGRFdmVudExpc3RlbmVyKCJvcGVuIixmdW5jdGlvbihlKXtuLnNlbmQoSlNPTi5zdHJpbmdpZnkoe3R5cGU6ImNvbm5lY3Rpb25faW5pdCJ9KSl9KSxuLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uKGUpeyJjb25uZWN0aW9uX2FjayI9PT1KU09OLnBhcnNlKGUuZGF0YSkudHlwZSYmdCghMCl9KSxuLmFkZEV2ZW50TGlzdGVuZXIoImVycm9yIixmdW5jdGlvbihlKXt0KCExKX0pLHNldFRpbWVvdXQoZnVuY3Rpb24oKXt0KCExKX0sMWUzKX0pfSxuLnByb3RvdHlwZS5nZXRQcm9qZWN0SWQ9ZnVuY3Rpb24oZSl7cmV0dXJuIGUuc3BsaXQoIi8iKS5zbGljZSgtMSlbMF19LG59KGwuQ29tcG9uZW50KSxEPWZ1bmN0aW9uKGUsdCl7cmV0dXJue3RoZW1lOnQudGhlbWV8fGIuZ2V0VGhlbWUoZSx0LnNldHRpbmdzKSxzZXR0aW5nczpiLmdldFNldHRpbmdzKGUpfX07dC5kZWZhdWx0PXYuY29ubmVjdChELHtpbmplY3RUYWJzOnguaW5qZWN0VGFic30pKEUpO3ZhciB3LFMsaz1tLmtleWZyYW1lcyh3fHwodz1hKFsiXG4gIGZyb20geyBcbiAgICBvcGFjaXR5OiAwO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgxMHB4KTtcbiAgfVxuICB0byB7IFxuICAgIG9wYWNpdHk6IDE7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKDApO1xuICB9XG4iXSxbIlxuICBmcm9tIHsgXG4gICAgb3BhY2l0eTogMDtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVkoMTBweCk7XG4gIH1cbiAgdG8geyBcbiAgICBvcGFjaXR5OiAxO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgwKTtcbiAgfVxuIl0pKSksQT1tLnN0eWxlZC5kaXYoU3x8KFM9YShbIlxuICBkaXNwbGF5OiBmbGV4O1xuICB3aWR0aDogMTAwJTtcbiAgb3BhY2l0eTogMDtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKDEwcHgpO1xuICBhbmltYXRpb246ICIsIiAwLjVzIGVhc2Utb3V0IGZvcndhcmRzIDAuMnM7XG4iXSxbIlxuICBkaXNwbGF5OiBmbGV4O1xuICB3aWR0aDogMTAwJTtcbiAgb3BhY2l0eTogMDtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKDEwcHgpO1xuICBhbmltYXRpb246ICIsIiAwLjVzIGVhc2Utb3V0IGZvcndhcmRzIDAuMnM7XG4iXSkpLGspfSkuY2FsbCh0LG4oMTEpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjsoZnVuY3Rpb24oZSl7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKSxpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX0sbz1mdW5jdGlvbihlLHQsbixyKXtyZXR1cm4gbmV3KG58fChuPVByb21pc2UpKShmdW5jdGlvbihpLG8pe2Z1bmN0aW9uIGEoZSl7dHJ5e3Uoci5uZXh0KGUpKX1jYXRjaChlKXtvKGUpfX1mdW5jdGlvbiBzKGUpe3RyeXt1KHIudGhyb3coZSkpfWNhdGNoKGUpe28oZSl9fWZ1bmN0aW9uIHUoZSl7ZS5kb25lP2koZS52YWx1ZSk6bmV3IG4oZnVuY3Rpb24odCl7dChlLnZhbHVlKX0pLnRoZW4oYSxzKX11KChyPXIuYXBwbHkoZSx0fHxbXSkpLm5leHQoKSl9KX0sYT1mdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiByKFtlLHRdKX19ZnVuY3Rpb24gcihuKXtpZihpKXRocm93IG5ldyBUeXBlRXJyb3IoIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy4iKTtmb3IoO3U7KXRyeXtpZihpPTEsbyYmKGE9MiZuWzBdP28ucmV0dXJuOm5bMF0/by50aHJvd3x8KChhPW8ucmV0dXJuKSYmYS5jYWxsKG8pLDApOm8ubmV4dCkmJiEoYT1hLmNhbGwobyxuWzFdKSkuZG9uZSlyZXR1cm4gYTtzd2l0Y2gobz0wLGEmJihuPVsyJm5bMF0sYS52YWx1ZV0pLG5bMF0pe2Nhc2UgMDpjYXNlIDE6YT1uO2JyZWFrO2Nhc2UgNDpyZXR1cm4gdS5sYWJlbCsrLHt2YWx1ZTpuWzFdLGRvbmU6ITF9O2Nhc2UgNTp1LmxhYmVsKyssbz1uWzFdLG49WzBdO2NvbnRpbnVlO2Nhc2UgNzpuPXUub3BzLnBvcCgpLHUudHJ5cy5wb3AoKTtjb250aW51ZTtkZWZhdWx0OmlmKGE9dS50cnlzLCEoYT1hLmxlbmd0aD4wJiZhW2EubGVuZ3RoLTFdKSYmKDY9PT1uWzBdfHwyPT09blswXSkpe3U9MDtjb250aW51ZX1pZigzPT09blswXSYmKCFhfHxuWzFdPmFbMF0mJm5bMV08YVszXSkpe3UubGFiZWw9blsxXTticmVha31pZig2PT09blswXSYmdS5sYWJlbDxhWzFdKXt1LmxhYmVsPWFbMV0sYT1uO2JyZWFrfWlmKGEmJnUubGFiZWw8YVsyXSl7dS5sYWJlbD1hWzJdLHUub3BzLnB1c2gobik7YnJlYWt9YVsyXSYmdS5vcHMucG9wKCksdS50cnlzLnBvcCgpO2NvbnRpbnVlfW49dC5jYWxsKGUsdSl9Y2F0Y2goZSl7bj1bNixlXSxvPTB9ZmluYWxseXtpPWE9MH1pZig1Jm5bMF0pdGhyb3cgblsxXTtyZXR1cm57dmFsdWU6blswXT9uWzFdOnZvaWQgMCxkb25lOiEwfX12YXIgaSxvLGEscyx1PXtsYWJlbDowLHNlbnQ6ZnVuY3Rpb24oKXtpZigxJmFbMF0pdGhyb3cgYVsxXTtyZXR1cm4gYVsxXX0sdHJ5czpbXSxvcHM6W119O3JldHVybiBzPXtuZXh0Om4oMCksdGhyb3c6bigxKSxyZXR1cm46bigyKX0sImZ1bmN0aW9uIj09PXR5cGVvZiBTeW1ib2wmJihzW1N5bWJvbC5pdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pLHN9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcz1uKDApLHU9big1MzQpO3QuR3JhcGhRTEVkaXRvcj11LmRlZmF1bHQ7dmFyIGM9big3MDApLGw9big3MDMpLHA9bigxKSxmPW4oNzA4KSxkPW4oNzA5KSxoPW4oNzEyKSxtPW4oNzEzKSxnPW4oOSkseT1uKDE2KSx2PW4oNzUpLGI9bigxNTApLHg9big4KSxDPW4oMTIpLEU9big5NyksRD1uKDc3KSx3PW4oMzAxKSxTPW4oMTcpLGs9big3MTQpLEE9big3NCksXz1uKDE0NyksVD1mdW5jdGlvbih0KXtmdW5jdGlvbiBuKG4pe3ZhciByPXQuY2FsbCh0aGlzLG4pfHx0aGlzO3JldHVybiByLmFwb2xsb0xpbmtzPXt9LHIub2JzZXJ2ZXJzPXt9LHIuZ3JhcGhpcWxDb21wb25lbnRzPVtdLHIuZ2V0U2NoZW1hPUEuZGVib3VuY2UoZnVuY3Rpb24oZSl7cmV0dXJuIHZvaWQgMD09PWUmJihlPXIucHJvcHMpLG8ocix2b2lkIDAsdm9pZCAwLGZ1bmN0aW9uKCl7dmFyIHQsbj10aGlzO3JldHVybiBhKHRoaXMsZnVuY3Rpb24ocil7cmV0dXJuIGUuc2NoZW1hP1syXToodGhpcy5tb3VudGVkJiZ0aGlzLnN0YXRlLnNjaGVtYSYmIWUuaXNQb2xsaW5nU2NoZW1hJiZ0aGlzLnNldFN0YXRlKHtzY2hlbWE6dm9pZCAwfSksdD0hMCx0aGlzLmJhY2tvZmYmJnRoaXMuYmFja29mZi5zdG9wKCksdGhpcy5iYWNrb2ZmPW5ldyBrLkJhY2tvZmYoZnVuY3Rpb24oKXtyZXR1cm4gbyhuLHZvaWQgMCx2b2lkIDAsZnVuY3Rpb24oKXtyZXR1cm4gYSh0aGlzLGZ1bmN0aW9uKG4pe3N3aXRjaChuLmxhYmVsKXtjYXNlIDA6cmV0dXJuIHQ/WzQsdGhpcy5zY2hlbWFHZXR0ZXIoZSldOlszLDJdO2Nhc2UgMTpyZXR1cm4gbi5zZW50KCksdD0hMSxbMyw0XTtjYXNlIDI6cmV0dXJuWzQsdGhpcy5zY2hlbWFHZXR0ZXIoKV07Y2FzZSAzOm4uc2VudCgpLG4ubGFiZWw9NDtjYXNlIDQ6cmV0dXJuWzJdfX0pfSl9KSx0aGlzLmJhY2tvZmYuc3RhcnQoKSxbMl0pfSl9KX0sNjAwLHt0cmFpbGluZzohMH0pLHIuaW5pdGlhbEluZGV4PS0xLHIubW91bnRlZD0hMSxyLmluaXRpYWxTY2hlbWFGZXRjaD0hMCxyLnNldFJlZj1mdW5jdGlvbihlLHQpe3IuZ3JhcGhpcWxDb21wb25lbnRzW2VdPXQ/dC5nZXRXcmFwcGVkSW5zdGFuY2UoKTp0fSxyLmNsb3NlVGFiPWZ1bmN0aW9uKCl7ci5wcm9wcy5jbG9zZVNlbGVjdGVkVGFiKCl9LHIubmV4dFRhYj1mdW5jdGlvbigpe3IucHJvcHMuc2VsZWN0TmV4dFRhYigpfSxyLnByZXZUYWI9ZnVuY3Rpb24oKXtyLnByb3BzLnNlbGVjdFByZXZUYWIoKX0sci5zd2l0Y2hUYWI9ZnVuY3Rpb24oZSl7ci5wcm9wcy5zZWxlY3RUYWJJbmRleChlKX0sci5oYW5kbGVTYXZlQ29uZmlnPWZ1bmN0aW9uKCl7ci5wcm9wcy5zYXZlQ29uZmlnKCksci5wcm9wcy5vblNhdmVDb25maWcoKX0sci5oYW5kbGVTYXZlU2V0dGluZ3M9ZnVuY3Rpb24oKXtyLnByb3BzLnNhdmVTZXR0aW5ncygpLHIucHJvcHMub25TYXZlU2V0dGluZ3MoKX0sci5jcmVhdGVTZXNzaW9uPWZ1bmN0aW9uKCl7ci5wcm9wcy5uZXdTZXNzaW9uKHIucHJvcHMuZW5kcG9pbnQsci5wcm9wcy5zZXR0aW5nc1siZWRpdG9yLnJldXNlSGVhZGVycyJdKX0sci5zdGF0ZT17c2NoZW1hOm4uc2NoZW1hfSxlLnA9ciwiZnVuY3Rpb24iPT09dHlwZW9mIHIucHJvcHMuZ2V0UmVmJiZyLnByb3BzLmdldFJlZihyKSxELnNldExpbmtDcmVhdG9yKG4uY3JlYXRlQXBvbGxvTGluayksci5nZXRTY2hlbWEoKSxELnNldFN1YnNjcmlwdGlvbkVuZHBvaW50KG4uc3Vic2NyaXB0aW9uRW5kcG9pbnQpLHJ9cmV0dXJuIHIobix0KSxuLnByb3RvdHlwZS5jb21wb25lbnRXaWxsTW91bnQ9ZnVuY3Rpb24oKXt0aGlzLnByb3BzLmluaXRTdGF0ZSh3LmdldFdvcmtzcGFjZUlkKHRoaXMucHJvcHMpLHRoaXMucHJvcHMuZW5kcG9pbnQpLHRoaXMucHJvcHMuc2V0Q29uZmlnU3RyaW5nKHRoaXMucHJvcHMuY29uZmlnU3RyaW5nKSx0aGlzLnByb3BzLmluamVjdEhlYWRlcnModGhpcy5wcm9wcy5oZWFkZXJzLHRoaXMucHJvcHMuZW5kcG9pbnQpfSxuLnByb3RvdHlwZS5jb21wb25lbnREaWRNb3VudD1mdW5jdGlvbigpe3RoaXMuaW5pdGlhbEluZGV4Pi0xJiZ0aGlzLnNldFN0YXRlKHtzZWxlY3RlZFNlc3Npb25JbmRleDp0aGlzLmluaXRpYWxJbmRleH0pLHRoaXMubW91bnRlZD0hMH0sbi5wcm90b3R5cGUuY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wcz1mdW5jdGlvbihlKXt2YXIgdD10aGlzO3RoaXMucHJvcHMuY3JlYXRlQXBvbGxvTGluayE9PWUuY3JlYXRlQXBvbGxvTGluayYmRC5zZXRMaW5rQ3JlYXRvcihlLmNyZWF0ZUFwb2xsb0xpbmspLGUuaGVhZGVycz09PXRoaXMucHJvcHMuaGVhZGVycyYmZS5lbmRwb2ludD09PXRoaXMucHJvcHMuZW5kcG9pbnQmJmUud29ya3NwYWNlTmFtZT09PXRoaXMucHJvcHMud29ya3NwYWNlTmFtZSYmZS5zZXNzaW9uSGVhZGVycz09PXRoaXMucHJvcHMuc2Vzc2lvbkhlYWRlcnMmJmUuc2Vzc2lvbkVuZHBvaW50PT09dGhpcy5wcm9wcy5zZXNzaW9uRW5kcG9pbnR8fHRoaXMuZ2V0U2NoZW1hKGUpLHRoaXMucHJvcHMuaXNSZWxvYWRpbmdTY2hlbWEmJiFlLmlzUmVsb2FkaW5nU2NoZW1hJiZzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dC5nZXRTY2hlbWEoZSl9KSx0aGlzLnByb3BzLmVuZHBvaW50PT09ZS5lbmRwb2ludCYmdGhpcy5wcm9wcy5jb25maWdQYXRoPT09ZS5jb25maWdQYXRoJiZlLndvcmtzcGFjZU5hbWU9PT10aGlzLnByb3BzLndvcmtzcGFjZU5hbWV8fHRoaXMucHJvcHMuaW5pdFN0YXRlKHcuZ2V0V29ya3NwYWNlSWQoZSksZS5lbmRwb2ludCksdGhpcy5wcm9wcy5zdWJzY3JpcHRpb25FbmRwb2ludCE9PWUuc3Vic2NyaXB0aW9uRW5kcG9pbnQmJkQuc2V0U3Vic2NyaXB0aW9uRW5kcG9pbnQoZS5zdWJzY3JpcHRpb25FbmRwb2ludCksZS5oZWFkZXJzIT09dGhpcy5wcm9wcy5oZWFkZXJzJiZ0aGlzLnByb3BzLmluamVjdEhlYWRlcnMoZS5oZWFkZXJzLGUuZW5kcG9pbnQpLGUuY29uZmlnU3RyaW5nIT09dGhpcy5wcm9wcy5jb25maWdTdHJpbmcmJnRoaXMucHJvcHMuc2V0Q29uZmlnU3RyaW5nKGUuY29uZmlnU3RyaW5nKSxlLnNjaGVtYSE9PXRoaXMucHJvcHMuc2NoZW1hJiZ0aGlzLnNldFN0YXRlKHtzY2hlbWE6ZS5zY2hlbWF9KX0sbi5wcm90b3R5cGUuc2NoZW1hR2V0dGVyPWZ1bmN0aW9uKGUpe3JldHVybiBvKHRoaXMsdm9pZCAwLHZvaWQgMCxmdW5jdGlvbigpe3ZhciB0LG4scixpLG8scyx1PXRoaXM7cmV0dXJuIGEodGhpcyxmdW5jdGlvbihhKXtzd2l0Y2goYS5sYWJlbCl7Y2FzZSAwOnQ9dGhpcy5wcm9wc3x8ZSxuPXQuc2Vzc2lvbkVuZHBvaW50fHx0LmVuZHBvaW50LHI9dGhpcy5zdGF0ZS5zY2hlbWEsYS5sYWJlbD0xO2Nhc2UgMTpyZXR1cm4gYS50cnlzLnB1c2goWzEsMywsNF0pLGk9e2VuZHBvaW50Om4saGVhZGVyczp0LnNlc3Npb25IZWFkZXJzJiZ0LnNlc3Npb25IZWFkZXJzLmxlbmd0aD4wP3Quc2Vzc2lvbkhlYWRlcnM6SlNPTi5zdHJpbmdpZnkodC5oZWFkZXJzKSxjcmVkZW50aWFsczp0LnNldHRpbmdzWyJyZXF1ZXN0LmNyZWRlbnRpYWxzIl19LFs0LEQuc2NoZW1hRmV0Y2hlci5mZXRjaChpKV07Y2FzZSAyOnJldHVybiBvPWEuc2VudCgpLEQuc2NoZW1hRmV0Y2hlci5zdWJzY3JpYmUoaSxmdW5jdGlvbihlKXtpLmVuZHBvaW50IT09dS5wcm9wcy5lbmRwb2ludCYmaS5lbmRwb2ludCE9PXUucHJvcHMuc2Vzc2lvbkVuZHBvaW50fHx1LnVwZGF0ZVNjaGVtYShyLGUsdCl9KSxvJiYodGhpcy51cGRhdGVTY2hlbWEocixvLnNjaGVtYSx0KSx0aGlzLmluaXRpYWxTY2hlbWFGZXRjaCYmKHRoaXMucHJvcHMuc2NoZW1hRmV0Y2hpbmdTdWNjZXNzKGkuZW5kcG9pbnQsby50cmFjaW5nU3VwcG9ydGVkLHQuaXNQb2xsaW5nU2NoZW1hKSx0aGlzLmluaXRpYWxTY2hlbWFGZXRjaD0hMSksdGhpcy5iYWNrb2ZmLnN0b3AoKSksWzMsNF07Y2FzZSAzOnJldHVybiBzPWEuc2VudCgpLGNvbnNvbGUuZXJyb3IocyksdGhpcy5wcm9wcy5zY2hlbWFGZXRjaGluZ0Vycm9yKG4scy5tZXNzYWdlKSxbMyw0XTtjYXNlIDQ6cmV0dXJuWzJdfX0pfSl9LG4ucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPW0udmVyc2lvbjtyZXR1cm4gd2luZG93LnZlcnNpb249ZSxzLmNyZWF0ZUVsZW1lbnQoTCx7Y2xhc3NOYW1lOiJwbGF5Z3JvdW5kIn0scy5jcmVhdGVFbGVtZW50KGMuZGVmYXVsdCx7b25OZXdTZXNzaW9uOnRoaXMuY3JlYXRlU2Vzc2lvbixpc0FwcDp0aGlzLnByb3BzLmlzQXBwfSkscy5jcmVhdGVFbGVtZW50KFAsbnVsbCxzLmNyZWF0ZUVsZW1lbnQoTSx7Y2xhc3NOYW1lOiJncmFwaGlxbC13cmFwcGVyIGFjdGl2ZSJ9LHRoaXMucHJvcHMuaXNDb25maWdUYWI/cy5jcmVhdGVFbGVtZW50KGQuR3JhcGhRTENvbmZpZ0VkaXRvcix7b25TYXZlOnRoaXMuaGFuZGxlU2F2ZUNvbmZpZyxpc1lhbWw6dGhpcy5wcm9wcy5jb25maWdJc1lhbWwsaXNDb25maWc6ITAscmVhZE9ubHk6IXRoaXMucHJvcHMuY2FuU2F2ZUNvbmZpZ30pOnRoaXMucHJvcHMuaXNTZXR0aW5nc1RhYj9zLmNyZWF0ZUVsZW1lbnQoZC5QbGF5Z3JvdW5kU2V0dGluZ3NFZGl0b3Ise29uU2F2ZTp0aGlzLmhhbmRsZVNhdmVTZXR0aW5nc30pOnRoaXMucHJvcHMuaXNGaWxlJiZ0aGlzLnByb3BzLmZpbGU/cy5jcmVhdGVFbGVtZW50KGguZGVmYXVsdCxudWxsKTpzLmNyZWF0ZUVsZW1lbnQodS5kZWZhdWx0LHtzaGFyZUVuYWJsZWQ6dGhpcy5wcm9wcy5zaGFyZUVuYWJsZWQsZml4ZWRFbmRwb2ludDp0aGlzLnByb3BzLmZpeGVkRW5kcG9pbnQsc2NoZW1hOnRoaXMuc3RhdGUuc2NoZW1hfSkpKSxzLmNyZWF0ZUVsZW1lbnQoZi5kZWZhdWx0LG51bGwpLHRoaXMucHJvcHMuaGlzdG9yeU9wZW4mJnRoaXMucmVuZGVySGlzdG9yeVBvcHVwKCkpfSxuLnByb3RvdHlwZS5yZW5kZXJIaXN0b3J5UG9wdXA9ZnVuY3Rpb24oKXtyZXR1cm4gcy5jcmVhdGVFbGVtZW50KGwuZGVmYXVsdCxudWxsKX0sbi5wcm90b3R5cGUudXBkYXRlU2NoZW1hPWZ1bmN0aW9uKGUsdCxuKXtpZihlIT09dCl7dmFyIHI9ZT9fLmNhY2hlZFByaW50U2NoZW1hKGUpOm51bGw7Xy5jYWNoZWRQcmludFNjaGVtYSh0KT09PXImJm4uaXNQb2xsaW5nU2NoZW1hfHx0aGlzLnNldFN0YXRlKHtzY2hlbWE6dH0pfX0sT2JqZWN0LmRlZmluZVByb3BlcnR5KG4ucHJvdG90eXBlLCJodHRwQXBpUHJlZml4Iix7Z2V0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucHJvcHMuZW5kcG9pbnQubWF0Y2goLyhodHRwcz86XC9cLy4qPylcLz8vKVsxXX0sZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITB9KSxuLmRlZmF1bHRQcm9wcz17c2hhcmVFbmFibGVkOiExfSxufShzLlB1cmVDb21wb25lbnQpO3QuUGxheWdyb3VuZD1UO3ZhciBPPXguY3JlYXRlU3RydWN0dXJlZFNlbGVjdG9yKHtpc0NvbmZpZ1RhYjpDLmdldElzQ29uZmlnVGFiLGlzU2V0dGluZ3NUYWI6Qy5nZXRJc1NldHRpbmdzVGFiLGlzRmlsZTpDLmdldElzRmlsZSxoaXN0b3J5T3BlbjpFLmdldEhpc3RvcnlPcGVuLGZpbGU6Qy5nZXRGaWxlLHNlc3Npb25IZWFkZXJzOkMuZ2V0SGVhZGVycyxzZXR0aW5nczpTLmdldFNldHRpbmdzLHNldHRpbmdzU3RyaW5nOlMuZ2V0U2V0dGluZ3NTdHJpbmcsaXNSZWxvYWRpbmdTY2hlbWE6Qy5nZXRJc1JlbG9hZGluZ1NjaGVtYSxpc1BvbGxpbmdTY2hlbWE6Qy5nZXRJc1BvbGxpbmdTY2hlbWEsc2Vzc2lvbkVuZHBvaW50OkMuZ2V0RW5kcG9pbnR9KTt0LmRlZmF1bHQ9Zy5jb25uZWN0KE8se3NlbGVjdFRhYkluZGV4Onkuc2VsZWN0VGFiSW5kZXgsc2VsZWN0TmV4dFRhYjp5LnNlbGVjdE5leHRUYWIsc2VsZWN0UHJldlRhYjp5LnNlbGVjdFByZXZUYWIsbmV3U2Vzc2lvbjp5Lm5ld1Nlc3Npb24sY2xvc2VTZWxlY3RlZFRhYjp5LmNsb3NlU2VsZWN0ZWRUYWIsaW5pdFN0YXRlOmIuaW5pdFN0YXRlLHNhdmVTZXR0aW5nczp5LnNhdmVTZXR0aW5ncyxzYXZlQ29uZmlnOnkuc2F2ZUNvbmZpZyxzZXRUcmFjaW5nU3VwcG9ydGVkOnkuc2V0VHJhY2luZ1N1cHBvcnRlZCxpbmplY3RIZWFkZXJzOnkuaW5qZWN0SGVhZGVycyxzZXRDb25maWdTdHJpbmc6di5zZXRDb25maWdTdHJpbmcsc2NoZW1hRmV0Y2hpbmdFcnJvcjp5LnNjaGVtYUZldGNoaW5nRXJyb3Isc2NoZW1hRmV0Y2hpbmdTdWNjZXNzOnkuc2NoZW1hRmV0Y2hpbmdTdWNjZXNzfSkoVCk7dmFyIEYsTixJLEw9cC5zdHlsZWQuZGl2KEZ8fChGPWkoWyJcbiAgZmxleDogMTtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcblxuICBoZWlnaHQ6IDEwMCU7XG4gIG1hcmdpbjogMDtcbiAgcGFkZGluZzogMDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgbWFyZ2luLXJpZ2h0OiAtMXB4ICFpbXBvcnRhbnQ7XG5cbiAgbGluZS1oZWlnaHQ6IDEuNTtcbiAgZm9udC1mYW1pbHk6ICdPcGVuIFNhbnMnLCBzYW5zLXNlcmlmO1xuICAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDtcbiAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbiAgbGV0dGVyLXNwYWNpbmc6IDAuNTNweDtcbiAgY29sb3I6IHJnYmEoMCwgMCwgMCwgMC44KTtcblxuICBhOmFjdGl2ZSxcbiAgYTpmb2N1cyxcbiAgYnV0dG9uOmZvY3VzLFxuICBpbnB1dDpmb2N1cyB7XG4gICAgb3V0bGluZTogbm9uZTtcbiAgfVxuIl0sWyJcbiAgZmxleDogMTtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcblxuICBoZWlnaHQ6IDEwMCU7XG4gIG1hcmdpbjogMDtcbiAgcGFkZGluZzogMDtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgbWFyZ2luLXJpZ2h0OiAtMXB4ICFpbXBvcnRhbnQ7XG5cbiAgbGluZS1oZWlnaHQ6IDEuNTtcbiAgZm9udC1mYW1pbHk6ICdPcGVuIFNhbnMnLCBzYW5zLXNlcmlmO1xuICAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDtcbiAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbiAgbGV0dGVyLXNwYWNpbmc6IDAuNTNweDtcbiAgY29sb3I6IHJnYmEoMCwgMCwgMCwgMC44KTtcblxuICBhOmFjdGl2ZSxcbiAgYTpmb2N1cyxcbiAgYnV0dG9uOmZvY3VzLFxuICBpbnB1dDpmb2N1cyB7XG4gICAgb3V0bGluZTogbm9uZTtcbiAgfVxuIl0pKSksUD1wLnN0eWxlZC5kaXYoTnx8KE49aShbIlxuICBoZWlnaHQ6IGNhbGMoMTAwdmggLSA1N3B4KTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBvdmVyZmxvdzogaGlkZGVuO1xuIl0sWyJcbiAgaGVpZ2h0OiBjYWxjKDEwMHZoIC0gNTdweCk7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiJdKSkpLE09cC5zdHlsZWQuZGl2KEl8fChJPWkoWyJcbiAgd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogMTAwJTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBvdmVyZmxvdzogaGlkZGVuO1xuICB2aXNpYmlsaXR5OiBoaWRkZW47XG4gICYuYWN0aXZlIHtcbiAgICB2aXNpYmlsaXR5OiB2aXNpYmxlO1xuICB9XG4iXSxbIlxuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4gIHZpc2liaWxpdHk6IGhpZGRlbjtcbiAgJi5hY3RpdmUge1xuICAgIHZpc2liaWxpdHk6IHZpc2libGU7XG4gIH1cbiJdKSkpfSkuY2FsbCh0LG4oMTEpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjsoZnVuY3Rpb24oZSl7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKSxpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX0sbz1mdW5jdGlvbihlLHQpe3ZhciBuPXt9O2Zvcih2YXIgciBpbiBlKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLHIpJiZ0LmluZGV4T2Yocik8MCYmKG5bcl09ZVtyXSk7aWYobnVsbCE9ZSYmImZ1bmN0aW9uIj09PXR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKWZvcih2YXIgaT0wLHI9T2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhlKTtpPHIubGVuZ3RoO2krKyl0LmluZGV4T2YocltpXSk8MCYmKG5bcltpXV09ZVtyW2ldXSk7cmV0dXJuIG59O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgYT1uKDApLHM9bigzMCksdT1uKDcpLGM9big1MzUpLGw9bigxMzMpLHA9bigzNyksZj1uKDYxMiksZD1uKDE0MiksaD1uKDYyNSksbT1uKDE0MyksZz1uKDYyOCkseT1uKDYzMiksdj1uKDYzNCksYj1uKDI4OSkseD1uKDI5MCksQz1uKDYzNSksRT1uKDYzNiksRD1uKDY0MCksdz1uKDEpLFM9big5KSxrPW4oOCksQT1uKDEyKSxfPW4oMTYpLFQ9ZnVuY3Rpb24odCl7ZnVuY3Rpb24gbigpe3ZhciBlPW51bGwhPT10JiZ0LmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpcztyZXR1cm4gZS5zZXRRdWVyeVZhcmlhYmxlc1JlZj1mdW5jdGlvbih0KXtlLnF1ZXJ5VmFyaWFibGVzUmVmPXR9LGUuc2V0SHR0cEhlYWRlcnNSZWY9ZnVuY3Rpb24odCl7ZS5odHRwSGVhZGVyc1JlZj10fSxlLnNldFF1ZXJ5UmVzaXplcj1mdW5jdGlvbih0KXtlLnF1ZXJ5UmVzaXplcj1zLmZpbmRET01Ob2RlKHQpfSxlLnNldFJlc3BvbnNlUmVzaXplcj1mdW5jdGlvbih0KXtlLnJlc3BvbnNlUmVzaXplcj1zLmZpbmRET01Ob2RlKHQpfSxlLnNldEVkaXRvckJhckNvbXBvbmVudD1mdW5jdGlvbih0KXtlLmVkaXRvckJhckNvbXBvbmVudD10fSxlLnNldFF1ZXJ5RWRpdG9yQ29tcG9uZW50PWZ1bmN0aW9uKHQpe2UucXVlcnlFZGl0b3JDb21wb25lbnQ9dH0sZS5zZXRWYXJpYWJsZUVkaXRvckNvbXBvbmVudD1mdW5jdGlvbih0KXtlLnZhcmlhYmxlRWRpdG9yQ29tcG9uZW50PXR9LGUuc2V0UmVzdWx0Q29tcG9uZW50PWZ1bmN0aW9uKHQpe2UucmVzdWx0Q29tcG9uZW50PXR9LGUuc2V0RG9jRXhwbG9yZXJSZWY9ZnVuY3Rpb24odCl7dCYmKGUuZG9jRXhwbG9yZXJDb21wb25lbnQ9dC5nZXRXcmFwcGVkSW5zdGFuY2UoKSl9LGUuc2V0R3JhcGhFeHBsb3JlclJlZj1mdW5jdGlvbih0KXt0JiYoZS5ncmFwaEV4cGxvcmVyQ29tcG9uZW50PXQuZ2V0V3JhcHBlZEluc3RhbmNlKCkpfSxlLnNldFNjaGVtYUV4cGxvcmVyUmVmPWZ1bmN0aW9uKHQpe3QmJihlLnNjaGVtYUV4cGxvcmVyQ29tcG9uZW50PXQuZ2V0V3JhcHBlZEluc3RhbmNlKCkpfSxlLnNldENvbnRhaW5lckNvbXBvbmVudD1mdW5jdGlvbih0KXtlLmNvbnRhaW5lckNvbXBvbmVudD10fSxlLmhhbmRsZUNsaWNrUmVmZXJlbmNlPWZ1bmN0aW9uKHQpe2UuZG9jRXhwbG9yZXJDb21wb25lbnQmJmUuZG9jRXhwbG9yZXJDb21wb25lbnQuc2hvd0RvY0Zyb21UeXBlKHQuZmllbGR8fHQpfSxlLnJ1blF1ZXJ5QXRDdXJzb3I9ZnVuY3Rpb24oKXtpZihlLnByb3BzLnF1ZXJ5UnVubmluZylyZXR1cm4gdm9pZCBlLnByb3BzLnN0b3BRdWVyeShlLnByb3BzLnNlc3Npb25JZCk7dmFyIHQ9ZS5xdWVyeUVkaXRvckNvbXBvbmVudC5nZXRDb2RlTWlycm9yKCk7aWYodC5oYXNGb2N1cygpKXt2YXIgbj10LmdldEN1cnNvcigpLHI9dC5pbmRleEZyb21Qb3Mobik7ZS5wcm9wcy5ydW5RdWVyeUF0UG9zaXRpb24ocil9fSxlLmhhbmRsZUhpbnRJbmZvcm1hdGlvblJlbmRlcj1mdW5jdGlvbih0KXt0LmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixlLm9uQ2xpY2tIaW50SW5mb3JtYXRpb24pO3ZhciBuO3QuYWRkRXZlbnRMaXN0ZW5lcigiRE9NTm9kZVJlbW92ZWQiLG49ZnVuY3Rpb24oKXt0LnJlbW92ZUV2ZW50TGlzdGVuZXIoIkRPTU5vZGVSZW1vdmVkIixuKSx0LnJlbW92ZUV2ZW50TGlzdGVuZXIoImNsaWNrIixlLm9uQ2xpY2tIaW50SW5mb3JtYXRpb24pfSl9LGUuaGFuZGxlUmVzaXplU3RhcnQ9ZnVuY3Rpb24odCl7aWYoZS5kaWRDbGlja0RyYWdCYXIodCkpe3QucHJldmVudERlZmF1bHQoKTt2YXIgbj10LmNsaWVudFgtYi5nZXRMZWZ0KHQudGFyZ2V0KSxyPWZ1bmN0aW9uKHQpe2lmKDA9PT10LmJ1dHRvbnMpcmV0dXJuIGkoKTt2YXIgcj1zLmZpbmRET01Ob2RlKGUuZWRpdG9yQmFyQ29tcG9uZW50KSxvPXQuY2xpZW50WC1iLmdldExlZnQociktbixhPXIuY2xpZW50V2lkdGgtbztlLnByb3BzLnNldEVkaXRvckZsZXgoby9hKX0saT1mdW5jdGlvbigpe2RvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNlbW92ZSIsciksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsaSkscj1udWxsLGk9bnVsbH07ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2Vtb3ZlIixyKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJtb3VzZXVwIixpKX19LGUuaGFuZGxlVHJhY2luZ1Jlc2l6ZVN0YXJ0PWZ1bmN0aW9uKHQpe3QucHJldmVudERlZmF1bHQoKTt2YXIgbj0hMSxyPWUucHJvcHMucmVzcG9uc2VUcmFjaW5nSGVpZ2h0LGk9dC5jbGllbnRZLWIuZ2V0VG9wKHQudGFyZ2V0KSxvPWZ1bmN0aW9uKHQpe2lmKDA9PT10LmJ1dHRvbnMpcmV0dXJuIGEoKTtuPSEwO3ZhciBvPXMuZmluZERPTU5vZGUoZS5lZGl0b3JCYXJDb21wb25lbnQpLHU9dC5jbGllbnRZLWIuZ2V0VG9wKG8pLWk7by5jbGllbnRIZWlnaHQtdTw2MD9lLnByb3BzLmNsb3NlVHJhY2luZyhyKTplLnByb3BzLm9wZW5UcmFjaW5nKHIpfSxhPWZ1bmN0aW9uKCl7bnx8ZS5wcm9wcy50b2dnbGVUcmFjaW5nKCksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2Vtb3ZlIixvKSxkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJtb3VzZXVwIixhKSxvPW51bGwsYT1udWxsfTtkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJtb3VzZW1vdmUiLG8pLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNldXAiLGEpfSxlLmhhbmRsZVZhcmlhYmxlUmVzaXplU3RhcnQ9ZnVuY3Rpb24odCl7dC5wcmV2ZW50RGVmYXVsdCgpO3ZhciBuPSExLHI9ZS5wcm9wcy52YXJpYWJsZUVkaXRvck9wZW4saT1lLnByb3BzLnZhcmlhYmxlRWRpdG9ySGVpZ2h0LG89dC5jbGllbnRZLWIuZ2V0VG9wKHQudGFyZ2V0KTtpZighcnx8dC50YXJnZXQhPT1lLnF1ZXJ5VmFyaWFibGVzUmVmJiZ0LnRhcmdldCE9PWUuaHR0cEhlYWRlcnNSZWYpe3ZhciBhPWZ1bmN0aW9uKHQpe2lmKDA9PT10LmJ1dHRvbnMpcmV0dXJuIHUoKTtuPSEwO3ZhciByPXMuZmluZERPTU5vZGUoZS5lZGl0b3JCYXJDb21wb25lbnQpLGE9dC5jbGllbnRZLWIuZ2V0VG9wKHIpLW8sYz1yLmNsaWVudEhlaWdodC1hO2M8NjA/ZS5wcm9wcy5jbG9zZVZhcmlhYmxlcyhpKTplLnByb3BzLm9wZW5WYXJpYWJsZXMoYyl9LHU9ZnVuY3Rpb24oKXtufHxlLnByb3BzLnRvZ2dsZVZhcmlhYmxlcygpLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNlbW92ZSIsYSksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsdSksYT1udWxsLHU9bnVsbH07ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2Vtb3ZlIixhKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJtb3VzZXVwIix1KX19LGUub25DbGlja0hpbnRJbmZvcm1hdGlvbj1mdW5jdGlvbih0KXtpZigidHlwZU5hbWUiPT09dC50YXJnZXQuY2xhc3NOYW1lKXt2YXIgbj10LnRhcmdldC5pbm5lckhUTUwscj1lLnByb3BzLnNjaGVtYTtpZihyKXt2YXIgaT1uLnJlcGxhY2UoL1tcXVxbIV0vZywiIiksbz1yLmdldFR5cGUoaSk7dS5pc05hbWVkVHlwZShvKSYmZS5kb2NFeHBsb3JlckNvbXBvbmVudC5zaG93RG9jRnJvbVR5cGUobyl9fX0sZX1yZXR1cm4gcihuLHQpLG4ucHJvdG90eXBlLmNvbXBvbmVudERpZE1vdW50PWZ1bmN0aW9uKCl7dGhpcy5jb2RlTWlycm9yU2l6ZXI9bmV3IGYuZGVmYXVsdCxlLmc9dGhpc30sbi5wcm90b3R5cGUuY29tcG9uZW50RGlkVXBkYXRlPWZ1bmN0aW9uKCl7dGhpcy5yZXN1bHRDb21wb25lbnQmJkJvb2xlYW4odGhpcy5wcm9wcy5zdWJzY3JpcHRpb25BY3RpdmUpJiYodGhpcy5yZXN1bHRDb21wb25lbnQuc2Nyb2xsVG9wPXRoaXMucmVzdWx0Q29tcG9uZW50LnNjcm9sbEhlaWdodCl9LG4ucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3JldHVybiBhLmNyZWF0ZUVsZW1lbnQocC5Db250YWluZXIse3NldFJlZjp0aGlzLnNldENvbnRhaW5lckNvbXBvbmVudH0sYS5jcmVhdGVFbGVtZW50KHAuZGVmYXVsdCxudWxsLGEuY3JlYXRlRWxlbWVudChkLmRlZmF1bHQse3NoYXJlRW5hYmxlZDp0aGlzLnByb3BzLnNoYXJlRW5hYmxlZCxmaXhlZEVuZHBvaW50OnRoaXMucHJvcHMuZml4ZWRFbmRwb2ludH0pLGEuY3JlYXRlRWxlbWVudChILHtyZWY6dGhpcy5zZXRFZGl0b3JCYXJDb21wb25lbnQsb25Nb3VzZURvd246dGhpcy5oYW5kbGVSZXNpemVTdGFydH0sYS5jcmVhdGVFbGVtZW50KGllLHtmbGV4OnRoaXMucHJvcHMuZWRpdG9yRmxleH0sYS5jcmVhdGVFbGVtZW50KGwuZGVmYXVsdCx7Z2V0UmVmOnRoaXMuc2V0UXVlcnlFZGl0b3JDb21wb25lbnQsc2NoZW1hOnRoaXMucHJvcHMuc2NoZW1hLG9uSGludEluZm9ybWF0aW9uUmVuZGVyOnRoaXMuaGFuZGxlSGludEluZm9ybWF0aW9uUmVuZGVyLG9uUnVuUXVlcnk6dGhpcy5ydW5RdWVyeUF0Q3Vyc29yLG9uQ2xpY2tSZWZlcmVuY2U6dGhpcy5oYW5kbGVDbGlja1JlZmVyZW5jZX0pLGEuY3JlYXRlRWxlbWVudChaLHtpc09wZW46dGhpcy5wcm9wcy52YXJpYWJsZUVkaXRvck9wZW4saGVpZ2h0OnRoaXMucHJvcHMudmFyaWFibGVFZGl0b3JIZWlnaHR9LGEuY3JlYXRlRWxlbWVudChlZSx7aXNPcGVuOnRoaXMucHJvcHMudmFyaWFibGVFZGl0b3JPcGVuLG9uTW91c2VEb3duOnRoaXMuaGFuZGxlVmFyaWFibGVSZXNpemVTdGFydH0sYS5jcmVhdGVFbGVtZW50KHRlLHtpc09wZW46dGhpcy5wcm9wcy5xdWVyeVZhcmlhYmxlc0FjdGl2ZSxyZWY6dGhpcy5zZXRRdWVyeVZhcmlhYmxlc1JlZixvbkNsaWNrOnRoaXMucHJvcHMub3BlblF1ZXJ5VmFyaWFibGVzfSwiUXVlcnkgVmFyaWFibGVzIiksYS5jcmVhdGVFbGVtZW50KHRlLHtpc09wZW46IXRoaXMucHJvcHMucXVlcnlWYXJpYWJsZXNBY3RpdmUscmVmOnRoaXMuc2V0SHR0cEhlYWRlcnNSZWYsb25DbGljazp0aGlzLnByb3BzLmNsb3NlUXVlcnlWYXJpYWJsZXN9LCJIVFRQIEhlYWRlcnMgIisodGhpcy5wcm9wcy5oZWFkZXJzQ291bnQmJnRoaXMucHJvcHMuaGVhZGVyc0NvdW50PjA/IigiK3RoaXMucHJvcHMuaGVhZGVyc0NvdW50KyIpIjoiIikpKSx0aGlzLnByb3BzLnF1ZXJ5VmFyaWFibGVzQWN0aXZlP2EuY3JlYXRlRWxlbWVudChoLlZhcmlhYmxlRWRpdG9yQ29tcG9uZW50LHtnZXRSZWY6dGhpcy5zZXRWYXJpYWJsZUVkaXRvckNvbXBvbmVudCxvbkhpbnRJbmZvcm1hdGlvblJlbmRlcjp0aGlzLnByb3BzLnF1ZXJ5VmFyaWFibGVzQWN0aXZlP3RoaXMuaGFuZGxlSGludEluZm9ybWF0aW9uUmVuZGVyOnZvaWQgMCxvblJ1blF1ZXJ5OnRoaXMucnVuUXVlcnlBdEN1cnNvcn0pOmEuY3JlYXRlRWxlbWVudChoLkhlYWRlcnNFZGl0b3JDb21wb25lbnQse2dldFJlZjp0aGlzLnNldFZhcmlhYmxlRWRpdG9yQ29tcG9uZW50LG9uSGludEluZm9ybWF0aW9uUmVuZGVyOnRoaXMucHJvcHMucXVlcnlWYXJpYWJsZXNBY3RpdmU/dGhpcy5oYW5kbGVIaW50SW5mb3JtYXRpb25SZW5kZXI6dm9pZCAwLG9uUnVuUXVlcnk6dGhpcy5ydW5RdWVyeUF0Q3Vyc29yfSkpLGEuY3JlYXRlRWxlbWVudChLLHtyZWY6dGhpcy5zZXRRdWVyeVJlc2l6ZXJ9KSksYS5jcmVhdGVFbGVtZW50KFcsbnVsbCxhLmNyZWF0ZUVsZW1lbnQoSix7cmVmOnRoaXMuc2V0UmVzcG9uc2VSZXNpemVyfSksYS5jcmVhdGVFbGVtZW50KGMuZGVmYXVsdCxudWxsKSx0aGlzLnByb3BzLnF1ZXJ5UnVubmluZyYmMD09PXRoaXMucHJvcHMucmVzcG9uc2VzLnNpemUmJmEuY3JlYXRlRWxlbWVudChtLmRlZmF1bHQsbnVsbCksYS5jcmVhdGVFbGVtZW50KGcuZGVmYXVsdCx7c2V0UmVmOnRoaXMuc2V0UmVzdWx0Q29tcG9uZW50fSksIXRoaXMucHJvcHMucXVlcnlSdW5uaW5nJiYoIXRoaXMucHJvcHMucmVzcG9uc2VzfHwwPT09dGhpcy5wcm9wcy5yZXNwb25zZXMuc2l6ZSkmJmEuY3JlYXRlRWxlbWVudChvZSxudWxsLCJIaXQgdGhlIFBsYXkgQnV0dG9uIHRvIGdldCBhIHJlc3BvbnNlIGhlcmUiKSx0aGlzLnByb3BzLnN1YnNjcmlwdGlvbkFjdGl2ZSYmYS5jcmVhdGVFbGVtZW50KGFlLG51bGwsIkxpc3RlbmluZyBcdTIwMjYiKSxhLmNyZWF0ZUVsZW1lbnQobmUse2lzT3Blbjp0aGlzLnByb3BzLnJlc3BvbnNlVHJhY2luZ09wZW4saGVpZ2h0OnRoaXMucHJvcHMucmVzcG9uc2VUcmFjaW5nSGVpZ2h0fSxhLmNyZWF0ZUVsZW1lbnQocmUse2lzT3Blbjp0aGlzLnByb3BzLnJlc3BvbnNlVHJhY2luZ09wZW4sb25Nb3VzZURvd246dGhpcy5oYW5kbGVUcmFjaW5nUmVzaXplU3RhcnR9LGEuY3JlYXRlRWxlbWVudCh0ZSx7aXNPcGVuOiExfSwiVHJhY2luZyIpKSxhLmNyZWF0ZUVsZW1lbnQoeS5kZWZhdWx0LHtvcGVuOnRoaXMucHJvcHMucmVzcG9uc2VUcmFjaW5nT3Blbn0pKSkpKSx0aGlzLmNvbnRhaW5lckNvbXBvbmVudCYmYS5jcmVhdGVFbGVtZW50KEMuZGVmYXVsdCx7bWF4V2lkdGg6dGhpcy5jb250YWluZXJDb21wb25lbnQub2Zmc2V0V2lkdGgtODZ9LGEuY3JlYXRlRWxlbWVudCh4LmRlZmF1bHQse2xhYmVsOiJEb2NzIixhY3RpdmVDb2xvcjoiZ3JlZW4iLHRhYldpZHRoOiI0OXB4In0sYS5jcmVhdGVFbGVtZW50KEQuZGVmYXVsdCx7c2NoZW1hOnRoaXMucHJvcHMuc2NoZW1hLHJlZjp0aGlzLnNldERvY0V4cGxvcmVyUmVmfSkpLGEuY3JlYXRlRWxlbWVudCh4LmRlZmF1bHQse2xhYmVsOiJTY2hlbWEiLGFjdGl2ZUNvbG9yOiJibHVlIix0YWJXaWR0aDoiNjVweCJ9LGEuY3JlYXRlRWxlbWVudChFLmRlZmF1bHQse3NjaGVtYTp0aGlzLnByb3BzLnNjaGVtYSxyZWY6dGhpcy5zZXRTY2hlbWFFeHBsb3JlclJlZixzZXNzaW9uSWQ6dGhpcy5wcm9wcy5zZXNzaW9uSWR9KSkpKX0sbi5wcm90b3R5cGUuYXV0b0NvbXBsZXRlTGVhZnM9ZnVuY3Rpb24oKXt2YXIgZT12LmZpbGxMZWFmcyh0aGlzLnByb3BzLnNjaGVtYSx0aGlzLnByb3BzLnF1ZXJ5KSx0PWUuaW5zZXJ0aW9ucyxuPWUucmVzdWx0O2lmKHQmJnQubGVuZ3RoPjApe3ZhciByPXRoaXMucXVlcnlFZGl0b3JDb21wb25lbnQuZ2V0Q29kZU1pcnJvcigpO3Iub3BlcmF0aW9uKGZ1bmN0aW9uKCl7dmFyIGU9ci5nZXRDdXJzb3IoKSxpPXIuaW5kZXhGcm9tUG9zKGUpO3Iuc2V0VmFsdWUobik7dmFyIG89MDt0cnl7dmFyIGE9dC5tYXAoZnVuY3Rpb24oZSl7dmFyIHQ9ZS5pbmRleCxuPWUuc3RyaW5nO3JldHVybiByLm1hcmtUZXh0KHIucG9zRnJvbUluZGV4KHQrbyksci5wb3NGcm9tSW5kZXgodCsobys9bi5sZW5ndGgpKSx7Y2xhc3NOYW1lOiJhdXRvSW5zZXJ0ZWRMZWFmIixjbGVhck9uRW50ZXI6ITAsdGl0bGU6IkF1dG9tYXRpY2FsbHkgYWRkZWQgbGVhZiBmaWVsZHMifSl9KTtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIGEuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gZS5jbGVhcigpfSl9LDdlMyl9Y2F0Y2goZSl7fXZhciBzPWk7dC5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWUuaW5kZXgsbj1lLnN0cmluZzt0PGkmJm4mJihzKz1uLmxlbmd0aCl9KSxyLnNldEN1cnNvcihyLnBvc0Zyb21JbmRleChzKSl9KX1yZXR1cm4gbn0sbi5wcm90b3R5cGUuZGlkQ2xpY2tEcmFnQmFyPWZ1bmN0aW9uKGUpe3JldHVybiBlLnRhcmdldD09PXRoaXMucXVlcnlSZXNpemVyfHxlLnRhcmdldD09PXRoaXMucmVzcG9uc2VSZXNpemVyfSxufShhLlB1cmVDb21wb25lbnQpLE89ay5jcmVhdGVTdHJ1Y3R1cmVkU2VsZWN0b3Ioe3F1ZXJ5UnVubmluZzpBLmdldFF1ZXJ5UnVubmluZyxyZXNwb25zZXM6QS5nZXRSZXNwb25zZXMsc3Vic2NyaXB0aW9uQWN0aXZlOkEuZ2V0U3Vic2NyaXB0aW9uQWN0aXZlLHZhcmlhYmxlRWRpdG9yT3BlbjpBLmdldFZhcmlhYmxlRWRpdG9yT3Blbix2YXJpYWJsZUVkaXRvckhlaWdodDpBLmdldFZhcmlhYmxlRWRpdG9ySGVpZ2h0LHJlc3BvbnNlVHJhY2luZ09wZW46QS5nZXRSZXNwb25zZVRyYWNpbmdPcGVuLHJlc3BvbnNlVHJhY2luZ0hlaWdodDpBLmdldFJlc3BvbnNlVHJhY2luZ0hlaWdodCxyZXNwb25zZUV4dGVuc2lvbnM6QS5nZXRSZXNwb25zZUV4dGVuc2lvbnMsY3VycmVudFF1ZXJ5U3RhcnRUaW1lOkEuZ2V0Q3VycmVudFF1ZXJ5U3RhcnRUaW1lLGN1cnJlbnRRdWVyeUVuZFRpbWU6QS5nZXRDdXJyZW50UXVlcnlFbmRUaW1lLHRyYWNpbmdTdXBwb3J0ZWQ6QS5nZXRUcmFjaW5nU3VwcG9ydGVkLGVkaXRvckZsZXg6QS5nZXRFZGl0b3JGbGV4LHF1ZXJ5VmFyaWFibGVzQWN0aXZlOkEuZ2V0UXVlcnlWYXJpYWJsZXNBY3RpdmUsaGVhZGVyczpBLmdldEhlYWRlcnMsb3BlcmF0aW9uczpBLmdldE9wZXJhdGlvbnMsb3BlcmF0aW9uTmFtZTpBLmdldE9wZXJhdGlvbk5hbWUsaGVhZGVyc0NvdW50OkEuZ2V0SGVhZGVyc0NvdW50LHNlc3Npb25JZDpBLmdldFNlbGVjdGVkU2Vzc2lvbklkRnJvbVJvb3R9KTt0LmRlZmF1bHQ9Uy5jb25uZWN0KE8se3VwZGF0ZVF1ZXJ5RmFjdHM6Xy51cGRhdGVRdWVyeUZhY3RzLHN0b3BRdWVyeTpfLnN0b3BRdWVyeSxydW5RdWVyeUF0UG9zaXRpb246Xy5ydW5RdWVyeUF0UG9zaXRpb24sb3BlblF1ZXJ5VmFyaWFibGVzOl8ub3BlblF1ZXJ5VmFyaWFibGVzLGNsb3NlUXVlcnlWYXJpYWJsZXM6Xy5jbG9zZVF1ZXJ5VmFyaWFibGVzLG9wZW5WYXJpYWJsZXM6Xy5vcGVuVmFyaWFibGVzLGNsb3NlVmFyaWFibGVzOl8uY2xvc2VWYXJpYWJsZXMsb3BlblRyYWNpbmc6Xy5vcGVuVHJhY2luZyxjbG9zZVRyYWNpbmc6Xy5jbG9zZVRyYWNpbmcsdG9nZ2xlVHJhY2luZzpfLnRvZ2dsZVRyYWNpbmcsc2V0RWRpdG9yRmxleDpfLnNldEVkaXRvckZsZXgsdG9nZ2xlVmFyaWFibGVzOl8udG9nZ2xlVmFyaWFibGVzLGZldGNoU2NoZW1hOl8uZmV0Y2hTY2hlbWF9LG51bGwse3dpdGhSZWY6ITB9KShUKTt2YXIgRixOLEksTCxQLE0saixSLEIsJCxVLHosRyxWLHEsSD13LnN0eWxlZC5kaXYoRnx8KEY9aShbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBmbGV4OiAxO1xuIl0sWyJcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IHJvdztcbiAgZmxleDogMTtcbiJdKSkpLFc9dy5zdHlsZWQuZGl2KE58fChOPWkoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgZmxleDogMTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBib3JkZXItbGVmdDogbm9uZTtcbiAgYmFja2dyb3VuZDogIiwiO1xuIl0sWyJcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgZmxleDogMTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBib3JkZXItbGVmdDogbm9uZTtcbiAgYmFja2dyb3VuZDogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnJlc3VsdEJhY2tncm91bmR9KSxRPXcuc3R5bGVkLmRpdihJfHwoST1pKFsiXG4gIHdpZHRoOiAxNXB4O1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMDtcbiAgYm90dG9tOiAwO1xuICBjdXJzb3I6IGNvbC1yZXNpemU7XG4iXSxbIlxuICB3aWR0aDogMTVweDtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB0b3A6IDA7XG4gIGJvdHRvbTogMDtcbiAgY3Vyc29yOiBjb2wtcmVzaXplO1xuIl0pKSksSz13LnN0eWxlZChRKShMfHwoTD1pKFsiXG4gIHJpZ2h0OiAwcHg7XG4iXSxbIlxuICByaWdodDogMHB4O1xuIl0pKSksSj13LnN0eWxlZChRKShQfHwoUD1pKFsiXG4gIGxlZnQ6IDBweDtcbiAgei1pbmRleDogMTtcbiJdLFsiXG4gIGxlZnQ6IDBweDtcbiAgei1pbmRleDogMTtcbiJdKSkpLFk9dy5zdHlsZWQoImRpdiIpKE18fChNPWkoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgYmFja2dyb3VuZDogIzBiMTkyNDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBoZWlnaHQ6ICIsIjtcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGJhY2tncm91bmQ6ICMwYjE5MjQ7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgaGVpZ2h0OiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzT3Blbj9lLmhlaWdodCsicHgiOiI0M3B4In0pLFg9dy5zdHlsZWQuZGl2KGp8fChqPWkoWyJcbiAgYmFja2dyb3VuZDogIzBiMTkyNDtcbiAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTtcbiAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgbGV0dGVyLXNwYWNpbmc6IDAuNTNweDtcbiAgbGluZS1oZWlnaHQ6IDE0cHg7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgcGFkZGluZzogMTRweCAxNHB4IDE1cHggMjFweDtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4iXSxbIlxuICBiYWNrZ3JvdW5kOiAjMGIxOTI0O1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICBmb250LXdlaWdodDogNjAwO1xuICBsZXR0ZXItc3BhY2luZzogMC41M3B4O1xuICBsaW5lLWhlaWdodDogMTRweDtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBwYWRkaW5nOiAxNHB4IDE0cHggMTVweCAyMXB4O1xuICB1c2VyLXNlbGVjdDogbm9uZTtcbiJdKSkpLFo9dy5zdHlsZWQoWSkoUnx8KFI9aShbIlxuICAuQ29kZU1pcnJvciB7XG4gICAgcGFkZGluZy1sZWZ0OiA0cHg7XG4gICAgd2lkdGg6IGNhbGMoMTAwJSAtIDRweCk7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4gIC5Db2RlTWlycm9yLWxpbmVzIHtcbiAgICBwYWRkaW5nOiAxMHB4IDAgMjBweCAwO1xuICB9XG4gIC5Db2RlTWlycm9yLWxpbmVudW1iZXJzIHtcbiAgICBiYWNrZ3JvdW5kOiAiLCI7XG4gIH1cbiJdLFsiXG4gIC5Db2RlTWlycm9yIHtcbiAgICBwYWRkaW5nLWxlZnQ6IDRweDtcbiAgICB3aWR0aDogY2FsYygxMDAlIC0gNHB4KTtcbiAgICBiYWNrZ3JvdW5kOiAiLCI7XG4gIH1cbiAgLkNvZGVNaXJyb3ItbGluZXMge1xuICAgIHBhZGRpbmc6IDEwcHggMCAyMHB4IDA7XG4gIH1cbiAgLkNvZGVNaXJyb3ItbGluZW51bWJlcnMge1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmxlZnREcmF3ZXJCYWNrZ3JvdW5kfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmxlZnREcmF3ZXJCYWNrZ3JvdW5kfSksZWU9dy5zdHlsZWQoZnVuY3Rpb24oZSl7dmFyIHQ9KGUuaXNPcGVuLG8oZSxbImlzT3BlbiJdKSk7cmV0dXJuIGEuY3JlYXRlRWxlbWVudChYLHQpfSkoQnx8KEI9aShbIlxuICBjdXJzb3I6ICIsIjtcbiAgYmFja2dyb3VuZDogIiwiO1xuIl0sWyJcbiAgY3Vyc29yOiAiLCI7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUuaXNPcGVuPyJyb3ctcmVzaXplIjoibi1yZXNpemUifSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmxlZnREcmF3ZXJCYWNrZ3JvdW5kfSksdGU9dy5zdHlsZWQoInNwYW4iKSgkfHwoJD1pKFsiXG4gIG1hcmdpbi1yaWdodDogMTBweDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBjb2xvcjogIiwiO1xuICAmOmxhc3QtY2hpbGQge1xuICAgIG1hcmdpbi1yaWdodDogMDtcbiAgfVxuIl0sWyJcbiAgbWFyZ2luLXJpZ2h0OiAxMHB4O1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGNvbG9yOiAiLCI7XG4gICY6bGFzdC1jaGlsZCB7XG4gICAgbWFyZ2luLXJpZ2h0OiAwO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzT3Blbj9lLnRoZW1lLmVkaXRvckNvbG91cnMuZHJhd2VyVGV4dDplLnRoZW1lLmVkaXRvckNvbG91cnMuZHJhd2VyVGV4dEluYWN0aXZlfSksbmU9dy5zdHlsZWQoWSkoVXx8KFU9aShbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSxbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMucmlnaHREcmF3ZXJCYWNrZ3JvdW5kfSkscmU9dy5zdHlsZWQoZnVuY3Rpb24oZSl7dmFyIHQ9KGUuaXNPcGVuLG8oZSxbImlzT3BlbiJdKSk7cmV0dXJuIGEuY3JlYXRlRWxlbWVudChYLHQpfSkoenx8KHo9aShbIlxuICB0ZXh0LWFsaWduOiByaWdodDtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBjdXJzb3I6ICIsIjtcbiAgY29sb3I6ICIsIjtcbiJdLFsiXG4gIHRleHQtYWxpZ246IHJpZ2h0O1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGN1cnNvcjogIiwiO1xuICBjb2xvcjogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnJpZ2h0RHJhd2VyQmFja2dyb3VuZH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUuaXNPcGVuPyJzLXJlc2l6ZSI6Im4tcmVzaXplIn0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5kcmF3ZXJUZXh0SW5hY3RpdmV9KSxpZT13LnN0eWxlZCgiZGl2IikoR3x8KEc9aShbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGZsZXg6ICIsIiAxIDAlO1xuICBib3JkZXItdG9wOiA4cHggc29saWQgIiwiO1xuIl0sWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBmbGV4OiAiLCIgMSAwJTtcbiAgYm9yZGVyLXRvcDogOHB4IHNvbGlkICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUuZmxleH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5yZXN1bHRCYWNrZ3JvdW5kfSksb2U9dy5zdHlsZWQuZGl2KFZ8fChWPWkoWyJcbiAgd2lkdGg6IDIzNXB4O1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogNTAlO1xuICBsZWZ0OiA1MCU7XG4gIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MCUpO1xuICBjb2xvcjogIiwiO1xuICBmb250LXNpemU6ICIsIjtcbiAgZm9udC1mYW1pbHk6ICdTb3VyY2UgQ29kZSBQcm8nLCAnQ29uc29sYXMnLCAnSW5jb25zb2xhdGEnLCAnRHJvaWQgU2FucyBNb25vJyxcbiAgICAnTW9uYWNvJywgbW9ub3NwYWNlO1xuICB0ZXh0LWFsaWduOiBjZW50ZXI7XG4gIGxldHRlci1zcGFjaW5nOiAwLjZweDtcbiJdLFsiXG4gIHdpZHRoOiAyMzVweDtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB0b3A6IDUwJTtcbiAgbGVmdDogNTAlO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNTAlKTtcbiAgY29sb3I6ICIsIjtcbiAgZm9udC1zaXplOiAiLCI7XG4gIGZvbnQtZmFtaWx5OiAnU291cmNlIENvZGUgUHJvJywgJ0NvbnNvbGFzJywgJ0luY29uc29sYXRhJywgJ0Ryb2lkIFNhbnMgTW9ubycsXG4gICAgJ01vbmFjbycsIG1vbm9zcGFjZTtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xuICBsZXR0ZXItc3BhY2luZzogMC42cHg7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMudGV4dEluYWN0aXZlfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5zbWFsbDE2fSksYWU9dy5zdHlsZWQuZGl2KHF8fChxPWkoWyJcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBib3R0b206IDA7XG4gIGNvbG9yOiAiLCI7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgZm9udC1zaXplOiAiLCI7XG4gIGZvbnQtZmFtaWx5OiAiLCI7XG4gIGxldHRlci1zcGFjaW5nOiAwLjZweDtcbiAgcGFkZGluZy1sZWZ0OiAyNHB4O1xuICBwYWRkaW5nLWJvdHRvbTogNjBweDtcbiJdLFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgYm90dG9tOiAwO1xuICBjb2xvcjogIiwiO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGZvbnQtc2l6ZTogIiwiO1xuICBmb250LWZhbWlseTogIiwiO1xuICBsZXR0ZXItc3BhY2luZzogMC42cHg7XG4gIHBhZGRpbmctbGVmdDogMjRweDtcbiAgcGFkZGluZy1ib3R0b206IDYwcHg7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMudGV4dH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5yZXN1bHRCYWNrZ3JvdW5kfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5zbWFsbDE2fSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zZXR0aW5nc1siZWRpdG9yLmZvbnRGYW1pbHkiXX0pfSkuY2FsbCh0LG4oMTEpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPW4oNTM2KSxzPW4oMSksdT1uKDkpLGM9bigxNiksbD1uKDgpLHA9bigxMiksZj1uKDI2MCksZD0hMCxoPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIG49ZS5jYWxsKHRoaXMsdCl8fHRoaXM7cmV0dXJuIG4uaGFuZGxlTW91c2VPdmVyPWZ1bmN0aW9uKGUpe24uc2V0U3RhdGUoe2hpZ2hsaWdodDplfSl9LG4uaGFuZGxlTW91c2VPdXQ9ZnVuY3Rpb24oKXtuLnNldFN0YXRlKHtoaWdobGlnaHQ6bnVsbH0pfSxuLmhhbmRsZU1vdXNlVXA9ZnVuY3Rpb24oZSl7bi5vbk9wdGlvblNlbGVjdGVkKGUpfSxuLm9uQ2xpY2s9ZnVuY3Rpb24oKXtuLnByb3BzLnF1ZXJ5UnVubmluZz9uLnByb3BzLnN0b3BRdWVyeShuLnByb3BzLnNlc3Npb25JZCk6bi5wcm9wcy5ydW5RdWVyeSgpfSxuLm9uT3B0aW9uU2VsZWN0ZWQ9ZnVuY3Rpb24oZSl7bi5zZXRTdGF0ZSh7b3B0aW9uc09wZW46ITF9KSxlJiZuLnByb3BzLnJ1blF1ZXJ5KGUubmFtZSYmZS5uYW1lLnZhbHVlKX0sbi5vbk9wdGlvbnNPcGVuPWZ1bmN0aW9uKGUpe3ZhciB0PSEwLHI9ZS50YXJnZXQ7bi5zZXRTdGF0ZSh7aGlnaGxpZ2h0Om51bGwsb3B0aW9uc09wZW46ITB9KTt2YXIgaT1mdW5jdGlvbihlKXtpZih0JiZlLnRhcmdldD09PXIpdD0hMTtlbHNlIGlmKGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNldXAiLGkpLGk9bnVsbCxyLnBhcmVudE5vZGUpe3ZhciBvPXIucGFyZW50Tm9kZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihlLnRhcmdldCkmTm9kZS5ET0NVTUVOVF9QT1NJVElPTl9DT05UQUlORURfQlk7b3x8bi5zZXRTdGF0ZSh7b3B0aW9uc09wZW46ITF9KSxkJiYobi5vbk9wdGlvblNlbGVjdGVkKG4ucHJvcHMub3BlcmF0aW9ucy5maW5kKGZ1bmN0aW9uKHQpe3JldHVybiB0Lm5hbWUudmFsdWU9PT1lLnRhcmdldC50ZXh0Q29udGVudH0pfHxuLnByb3BzLm9wZXJhdGlvbnNbMF0pLGQ9ITEpfX07ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsaSl9LG4uc3RhdGU9e29wdGlvbnNPcGVuOiExLGhpZ2hsaWdodDpudWxsfSxufXJldHVybiByKHQsZSksdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcyx0PXRoaXMucHJvcHMub3BlcmF0aW9ucyxuPXRoaXMuc3RhdGUub3B0aW9uc09wZW4scj10JiZ0Lmxlbmd0aD4xLGk9bnVsbDtpZihyJiZuKXt2YXIgcz10aGlzLnN0YXRlLmhpZ2hsaWdodDtpPW8uY3JlYXRlRWxlbWVudChFLG51bGwsby5jcmVhdGVFbGVtZW50KEQsbnVsbCx0Lm1hcChmdW5jdGlvbih0KXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGEuZGVmYXVsdCx7b3BlcmF0aW9uOnQsb25Nb3VzZU92ZXI6ZS5oYW5kbGVNb3VzZU92ZXIsb25Nb3VzZU91dDplLmhhbmRsZU1vdXNlT3V0LG9uTW91c2VVcDplLmhhbmRsZU1vdXNlVXAsaGlnaGxpZ2h0OnMsa2V5OnQubmFtZT90Lm5hbWUudmFsdWU6IioifSl9KSkpfXZhciB1OyF0aGlzLnByb3BzLnF1ZXJ5UnVubmluZyYmcnx8KHU9dGhpcy5vbkNsaWNrKTt2YXIgYzt0aGlzLnByb3BzLnF1ZXJ5UnVubmluZ3x8IXJ8fG58fChjPXRoaXMub25PcHRpb25zT3Blbik7dmFyIGw9dGhpcy5wcm9wcy5xdWVyeVJ1bm5pbmc/by5jcmVhdGVFbGVtZW50KCJyZWN0Iix7ZmlsbDoiI0ZGRkZGRiIseDoiMTAiLHk6IjEwIix3aWR0aDoiMTMiLGhlaWdodDoiMTMiLHJ4OiIxIn0pOm8uY3JlYXRlRWxlbWVudCgicGF0aCIse2Q6Ik0gMTEgOSBMIDI0IDE2IEwgMTEgMjMgeiJ9KTtyZXR1cm4gby5jcmVhdGVFbGVtZW50KHgsbnVsbCxvLmNyZWF0ZUVsZW1lbnQoQyx7aXNSdW5uaW5nOnRoaXMucHJvcHMucXVlcnlSdW5uaW5nLG9uTW91c2VEb3duOmMsb25DbGljazp1LHRpdGxlOiJFeGVjdXRlIFF1ZXJ5IChDdHJsLUVudGVyKSJ9LG8uY3JlYXRlRWxlbWVudCgic3ZnIix7d2lkdGg6IjM1IixoZWlnaHQ6IjM1Iix2aWV3Qm94Oih0aGlzLnByb3BzLnF1ZXJ5UnVubmluZz80OjMpKyIuNSw0LjUsMjQsMjQifSxsKSksaSl9LHR9KG8uQ29tcG9uZW50KSxtPWwuY3JlYXRlU3RydWN0dXJlZFNlbGVjdG9yKHtxdWVyeVJ1bm5pbmc6cC5nZXRRdWVyeVJ1bm5pbmcsb3BlcmF0aW9uczpwLmdldE9wZXJhdGlvbnMsc2Vzc2lvbklkOnAuZ2V0U2VsZWN0ZWRTZXNzaW9uSWRGcm9tUm9vdH0pO3QuZGVmYXVsdD11LmNvbm5lY3QobSx7cnVuUXVlcnk6Yy5ydW5RdWVyeSxzdG9wUXVlcnk6Yy5zdG9wUXVlcnl9KShmLnRvSlMoaCkpO3ZhciBnLHksdixiLHg9cy5zdHlsZWQuZGl2KGd8fChnPWkoWyJcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBsZWZ0OiAtNjJweDtcbiAgei1pbmRleDogNTtcbiAgdG9wOiAxNXB4O1xuICBtYXJnaW46IDAgMTRweCAwIDI4cHg7XG4iXSxbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIGxlZnQ6IC02MnB4O1xuICB6LWluZGV4OiA1O1xuICB0b3A6IDE1cHg7XG4gIG1hcmdpbjogMCAxNHB4IDAgMjhweDtcbiJdKSkpLEM9cy5zdHlsZWQoImRpdiIpKHl8fCh5PWkoWyJcbiAgd2lkdGg6IDYwcHg7XG4gIGhlaWdodDogNjBweDtcblxuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcblxuICBib3JkZXItcmFkaXVzOiAxMDAlO1xuICB0cmFuc2l0aW9uOiBiYWNrZ3JvdW5kLWNvbG9yIDEwMG1zO1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAiLCI7XG4gIGJvcmRlcjogNnB4IHNvbGlkICIsIjtcbiAgY3Vyc29yOiBwb2ludGVyO1xuXG4gIHN2ZyB7XG4gICAgZmlsbDogIiwiO1xuICB9XG5cbiAgJjpob3ZlciB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogIiwiO1xuICB9XG4iXSxbIlxuICB3aWR0aDogNjBweDtcbiAgaGVpZ2h0OiA2MHB4O1xuXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuXG4gIGJvcmRlci1yYWRpdXM6IDEwMCU7XG4gIHRyYW5zaXRpb246IGJhY2tncm91bmQtY29sb3IgMTAwbXM7XG4gIGJhY2tncm91bmQtY29sb3I6ICIsIjtcbiAgYm9yZGVyOiA2cHggc29saWQgIiwiO1xuICBjdXJzb3I6IHBvaW50ZXI7XG5cbiAgc3ZnIHtcbiAgICBmaWxsOiAiLCI7XG4gIH1cblxuICAmOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAiLCI7XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUuaXNSdW5uaW5nP2UudGhlbWUuZWRpdG9yQ29sb3Vycy5leGVjdXRlQnV0dG9uU3Vic2NyaXB0aW9uOmUudGhlbWUuZWRpdG9yQ29sb3Vycy5leGVjdXRlQnV0dG9ufSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmV4ZWN1dGVCdXR0b25Cb3JkZXJ9LGZ1bmN0aW9uKGUpe3JldHVybiJsaWdodCI9PT1lLnRoZW1lLm1vZGU/IndoaXRlIjoiaW5oZXJpdCJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzUnVubmluZz9lLnRoZW1lLmVkaXRvckNvbG91cnMuZXhlY3V0ZUJ1dHRvblN1YnNjcmlwdGlvbkhvdmVyOmUudGhlbWUuZWRpdG9yQ29sb3Vycy5leGVjdXRlQnV0dG9uSG92ZXJ9KSxFPXMuc3R5bGVkLmRpdih2fHwodj1pKFsiXG4gIGJhY2tncm91bmQ6ICNmZmY7XG4gIGJveC1zaGFkb3c6IDAgMCAwIDFweCByZ2JhKDAsIDAsIDAsIDAuMSksIDAgMnB4IDRweCByZ2JhKDAsIDAsIDAsIDAuMjUpO1xuICBwYWRkaW5nOiA4cHggMDtcbiAgbGVmdDogLTFweDtcbiAgbWFyZ2luOiAwO1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogNzhweDtcbiAgei1pbmRleDogMTAwO1xuXG4gICY6YmVmb3JlIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgYmFja2dyb3VuZDogd2hpdGU7XG4gICAgY29udGVudDogJyc7XG4gICAgdG9wOiAtNHB4O1xuICAgIGxlZnQ6IDM0cHg7XG4gICAgdHJhbnNmb3JtOiByb3RhdGUoNDVkZWcpO1xuICAgIHdpZHRoOiA4cHg7XG4gICAgaGVpZ2h0OiA4cHg7XG4gIH1cbiJdLFsiXG4gIGJhY2tncm91bmQ6ICNmZmY7XG4gIGJveC1zaGFkb3c6IDAgMCAwIDFweCByZ2JhKDAsIDAsIDAsIDAuMSksIDAgMnB4IDRweCByZ2JhKDAsIDAsIDAsIDAuMjUpO1xuICBwYWRkaW5nOiA4cHggMDtcbiAgbGVmdDogLTFweDtcbiAgbWFyZ2luOiAwO1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogNzhweDtcbiAgei1pbmRleDogMTAwO1xuXG4gICY6YmVmb3JlIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgYmFja2dyb3VuZDogd2hpdGU7XG4gICAgY29udGVudDogJyc7XG4gICAgdG9wOiAtNHB4O1xuICAgIGxlZnQ6IDM0cHg7XG4gICAgdHJhbnNmb3JtOiByb3RhdGUoNDVkZWcpO1xuICAgIHdpZHRoOiA4cHg7XG4gICAgaGVpZ2h0OiA4cHg7XG4gIH1cbiJdKSkpLEQ9cy5zdHlsZWQudWwoYnx8KGI9aShbIlxuICBtYXgtaGVpZ2h0OiAyNzBweDtcbiAgb3ZlcmZsb3c6IHNjcm9sbDtcblxuICBsaSB7XG4gICAgY3Vyc29yOiBwb2ludGVyO1xuICAgIGxpc3Qtc3R5bGU6IG5vbmU7XG4gICAgbWluLXdpZHRoOiAxMDBweDtcbiAgICBwYWRkaW5nOiAycHggMzBweCA0cHggMTBweDtcbiAgfVxuXG4gIGxpLnNlbGVjdGVkIHtcbiAgICBiYWNrZ3JvdW5kOiByZ2IoMzksIDE3NCwgOTYpO1xuICAgIGNvbG9yOiB3aGl0ZTtcbiAgfVxuIl0sWyJcbiAgbWF4LWhlaWdodDogMjcwcHg7XG4gIG92ZXJmbG93OiBzY3JvbGw7XG5cbiAgbGkge1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICBsaXN0LXN0eWxlOiBub25lO1xuICAgIG1pbi13aWR0aDogMTAwcHg7XG4gICAgcGFkZGluZzogMnB4IDMwcHggNHB4IDEwcHg7XG4gIH1cblxuICBsaS5zZWxlY3RlZCB7XG4gICAgYmFja2dyb3VuZDogcmdiKDM5LCAxNzQsIDk2KTtcbiAgICBjb2xvcjogd2hpdGU7XG4gIH1cbiJdKSkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPW4oMCksbz1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7dmFyIHQ9bnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzO3JldHVybiB0Lm9uTW91c2VPdmVyPWZ1bmN0aW9uKCl7dC5wcm9wcy5vbk1vdXNlT3Zlcih0LnByb3BzLm9wZXJhdGlvbil9LHQub25Nb3VzZVVwPWZ1bmN0aW9uKCl7dC5wcm9wcy5vbk1vdXNlVXAodC5wcm9wcy5vcGVyYXRpb24pfSx0fXJldHVybiByKHQsZSksdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7cmV0dXJuIGkuY3JlYXRlRWxlbWVudCgibGkiLHtrZXk6dGhpcy5wcm9wcy5vcGVyYXRpb24ubmFtZT90aGlzLnByb3BzLm9wZXJhdGlvbi5uYW1lLnZhbHVlOiIqIixjbGFzc05hbWU6dGhpcy5wcm9wcy5vcGVyYXRpb249PT10aGlzLnByb3BzLmhpZ2hsaWdodD8ic2VsZWN0ZWQiOiIiLG9uTW91c2VPdmVyOnRoaXMub25Nb3VzZU92ZXIsb25Nb3VzZU91dDp0aGlzLnByb3BzLm9uTW91c2VPdXQsb25Nb3VzZVVwOnRoaXMub25Nb3VzZVVwfSx0aGlzLnByb3BzLm9wZXJhdGlvbi5uYW1lP3RoaXMucHJvcHMub3BlcmF0aW9uLm5hbWUudmFsdWU6IjxVbm5hbWVkPiIpfSx0fShpLlB1cmVDb21wb25lbnQpO3QuZGVmYXVsdD1vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1uKDUzOCl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD1lLnRyaW0oKS50b0xvd2VyQ2FzZSgpO3JldHVybiF5LnRlc3QodCl8fCEhdi50ZXN0KHQpfWZ1bmN0aW9uIGkoZSl7dmFyIHQ9aC5wYXJzZShlLCEwKTtpZih0Lmhvc3RuYW1lJiYoIXQucHJvdG9jb2x8fGIuaW5kZXhPZih0LnByb3RvY29sKT49MCkpdHJ5e3QuaG9zdG5hbWU9bS50b0FTQ0lJKHQuaG9zdG5hbWUpfWNhdGNoKGUpe31yZXR1cm4gaC5lbmNvZGUoaC5mb3JtYXQodCkpfWZ1bmN0aW9uIG8oZSl7dmFyIHQ9aC5wYXJzZShlLCEwKTtpZih0Lmhvc3RuYW1lJiYoIXQucHJvdG9jb2x8fGIuaW5kZXhPZih0LnByb3RvY29sKT49MCkpdHJ5e3QuaG9zdG5hbWU9bS50b1VuaWNvZGUodC5ob3N0bmFtZSl9Y2F0Y2goZSl7fXJldHVybiBoLmRlY29kZShoLmZvcm1hdCh0KSl9ZnVuY3Rpb24gYShlLHQpe2lmKCEodGhpcyBpbnN0YW5jZW9mIGEpKXJldHVybiBuZXcgYShlLHQpO3R8fHMuaXNTdHJpbmcoZSl8fCh0PWV8fHt9LGU9ImRlZmF1bHQiKSx0aGlzLmlubGluZT1uZXcgZix0aGlzLmJsb2NrPW5ldyBwLHRoaXMuY29yZT1uZXcgbCx0aGlzLnJlbmRlcmVyPW5ldyBjLHRoaXMubGlua2lmeT1uZXcgZCx0aGlzLnZhbGlkYXRlTGluaz1yLHRoaXMubm9ybWFsaXplTGluaz1pLHRoaXMubm9ybWFsaXplTGlua1RleHQ9byx0aGlzLnV0aWxzPXMsdGhpcy5oZWxwZXJzPXMuYXNzaWduKHt9LHUpLHRoaXMub3B0aW9ucz17fSx0aGlzLmNvbmZpZ3VyZShlKSx0JiZ0aGlzLnNldCh0KX12YXIgcz1uKDQpLHU9big1NDgpLGM9big1NTIpLGw9big1NTMpLHA9big1NjEpLGY9big1NzUpLGQ9bigyNjcpLGg9big4OCksbT1uKDI3MSksZz17ZGVmYXVsdDpuKDU4OSksemVybzpuKDU5MCksY29tbW9ubWFyazpuKDU5MSl9LHk9L14odmJzY3JpcHR8amF2YXNjcmlwdHxmaWxlfGRhdGEpOi8sdj0vXmRhdGE6aW1hZ2VcLyhnaWZ8cG5nfGpwZWd8d2VicCk7LyxiPVsiaHR0cDoiLCJodHRwczoiLCJtYWlsdG86Il07YS5wcm90b3R5cGUuc2V0PWZ1bmN0aW9uKGUpe3JldHVybiBzLmFzc2lnbih0aGlzLm9wdGlvbnMsZSksdGhpc30sYS5wcm90b3R5cGUuY29uZmlndXJlPWZ1bmN0aW9uKGUpe3ZhciB0LG49dGhpcztpZihzLmlzU3RyaW5nKGUpJiYodD1lLCEoZT1nW3RdKSkpdGhyb3cgbmV3IEVycm9yKCdXcm9uZyBgbWFya2Rvd24taXRgIHByZXNldCAiJyt0KyciLCBjaGVjayBuYW1lJyk7aWYoIWUpdGhyb3cgbmV3IEVycm9yKCJXcm9uZyBgbWFya2Rvd24taXRgIHByZXNldCwgY2FuJ3QgYmUgZW1wdHkiKTtyZXR1cm4gZS5vcHRpb25zJiZuLnNldChlLm9wdGlvbnMpLGUuY29tcG9uZW50cyYmT2JqZWN0LmtleXMoZS5jb21wb25lbnRzKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe2UuY29tcG9uZW50c1t0XS5ydWxlcyYmblt0XS5ydWxlci5lbmFibGVPbmx5KGUuY29tcG9uZW50c1t0XS5ydWxlcyksZS5jb21wb25lbnRzW3RdLnJ1bGVzMiYmblt0XS5ydWxlcjIuZW5hYmxlT25seShlLmNvbXBvbmVudHNbdF0ucnVsZXMyKX0pLHRoaXN9LGEucHJvdG90eXBlLmVuYWJsZT1mdW5jdGlvbihlLHQpe3ZhciBuPVtdO0FycmF5LmlzQXJyYXkoZSl8fChlPVtlXSksWyJjb3JlIiwiYmxvY2siLCJpbmxpbmUiXS5mb3JFYWNoKGZ1bmN0aW9uKHQpe249bi5jb25jYXQodGhpc1t0XS5ydWxlci5lbmFibGUoZSwhMCkpfSx0aGlzKSxuPW4uY29uY2F0KHRoaXMuaW5saW5lLnJ1bGVyMi5lbmFibGUoZSwhMCkpO3ZhciByPWUuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBuLmluZGV4T2YoZSk8MH0pO2lmKHIubGVuZ3RoJiYhdCl0aHJvdyBuZXcgRXJyb3IoIk1hcmtkb3duSXQuIEZhaWxlZCB0byBlbmFibGUgdW5rbm93biBydWxlKHMpOiAiK3IpO3JldHVybiB0aGlzfSxhLnByb3RvdHlwZS5kaXNhYmxlPWZ1bmN0aW9uKGUsdCl7dmFyIG49W107QXJyYXkuaXNBcnJheShlKXx8KGU9W2VdKSxbImNvcmUiLCJibG9jayIsImlubGluZSJdLmZvckVhY2goZnVuY3Rpb24odCl7bj1uLmNvbmNhdCh0aGlzW3RdLnJ1bGVyLmRpc2FibGUoZSwhMCkpfSx0aGlzKSxuPW4uY29uY2F0KHRoaXMuaW5saW5lLnJ1bGVyMi5kaXNhYmxlKGUsITApKTt2YXIgcj1lLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gbi5pbmRleE9mKGUpPDB9KTtpZihyLmxlbmd0aCYmIXQpdGhyb3cgbmV3IEVycm9yKCJNYXJrZG93bkl0LiBGYWlsZWQgdG8gZGlzYWJsZSB1bmtub3duIHJ1bGUocyk6ICIrcik7cmV0dXJuIHRoaXN9LGEucHJvdG90eXBlLnVzZT1mdW5jdGlvbihlKXt2YXIgdD1bdGhpc10uY29uY2F0KEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywxKSk7cmV0dXJuIGUuYXBwbHkoZSx0KSx0aGlzfSxhLnByb3RvdHlwZS5wYXJzZT1mdW5jdGlvbihlLHQpe2lmKCJzdHJpbmciIT09dHlwZW9mIGUpdGhyb3cgbmV3IEVycm9yKCJJbnB1dCBkYXRhIHNob3VsZCBiZSBhIFN0cmluZyIpO3ZhciBuPW5ldyB0aGlzLmNvcmUuU3RhdGUoZSx0aGlzLHQpO3JldHVybiB0aGlzLmNvcmUucHJvY2VzcyhuKSxuLnRva2Vuc30sYS5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQ9dHx8e30sdGhpcy5yZW5kZXJlci5yZW5kZXIodGhpcy5wYXJzZShlLHQpLHRoaXMub3B0aW9ucyx0KX0sYS5wcm90b3R5cGUucGFyc2VJbmxpbmU9ZnVuY3Rpb24oZSx0KXt2YXIgbj1uZXcgdGhpcy5jb3JlLlN0YXRlKGUsdGhpcyx0KTtyZXR1cm4gbi5pbmxpbmVNb2RlPSEwLHRoaXMuY29yZS5wcm9jZXNzKG4pLG4udG9rZW5zfSxhLnByb3RvdHlwZS5yZW5kZXJJbmxpbmU9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdD10fHx7fSx0aGlzLnJlbmRlcmVyLnJlbmRlcih0aGlzLnBhcnNlSW5saW5lKGUsdCksdGhpcy5vcHRpb25zLHQpfSxlLmV4cG9ydHM9YX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0LG4scj1vW2VdO2lmKHIpcmV0dXJuIHI7Zm9yKHI9b1tlXT1bXSx0PTA7dDwxMjg7dCsrKW49U3RyaW5nLmZyb21DaGFyQ29kZSh0KSwvXlswLTlhLXpdJC9pLnRlc3Qobik/ci5wdXNoKG4pOnIucHVzaCgiJSIrKCIwIit0LnRvU3RyaW5nKDE2KS50b1VwcGVyQ2FzZSgpKS5zbGljZSgtMikpO2Zvcih0PTA7dDxlLmxlbmd0aDt0KyspcltlLmNoYXJDb2RlQXQodCldPWVbdF07cmV0dXJuIHJ9ZnVuY3Rpb24gaShlLHQsbil7dmFyIG8sYSxzLHUsYyxsPSIiO2Zvcigic3RyaW5nIiE9PXR5cGVvZiB0JiYobj10LHQ9aS5kZWZhdWx0Q2hhcnMpLCJ1bmRlZmluZWQiPT09dHlwZW9mIG4mJihuPSEwKSxjPXIodCksbz0wLGE9ZS5sZW5ndGg7bzxhO28rKylpZihzPWUuY2hhckNvZGVBdChvKSxuJiYzNz09PXMmJm8rMjxhJiYvXlswLTlhLWZdezJ9JC9pLnRlc3QoZS5zbGljZShvKzEsbyszKSkpbCs9ZS5zbGljZShvLG8rMyksbys9MjtlbHNlIGlmKHM8MTI4KWwrPWNbc107ZWxzZSBpZihzPj01NTI5NiYmczw9NTczNDMpe2lmKHM+PTU1Mjk2JiZzPD01NjMxOSYmbysxPGEmJih1PWUuY2hhckNvZGVBdChvKzEpKT49NTYzMjAmJnU8PTU3MzQzKXtsKz1lbmNvZGVVUklDb21wb25lbnQoZVtvXStlW28rMV0pLG8rKztjb250aW51ZX1sKz0iJUVGJUJGJUJEIn1lbHNlIGwrPWVuY29kZVVSSUNvbXBvbmVudChlW29dKTtyZXR1cm4gbH12YXIgbz17fTtpLmRlZmF1bHRDaGFycz0iOy8/OkAmPSskLC1fLiF+KicoKSMiLGkuY29tcG9uZW50Q2hhcnM9Ii1fLiF+KicoKSIsZS5leHBvcnRzPWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdCxuLHI9b1tlXTtpZihyKXJldHVybiByO2ZvcihyPW9bZV09W10sdD0wO3Q8MTI4O3QrKyluPVN0cmluZy5mcm9tQ2hhckNvZGUodCksci5wdXNoKG4pO2Zvcih0PTA7dDxlLmxlbmd0aDt0Kyspbj1lLmNoYXJDb2RlQXQodCkscltuXT0iJSIrKCIwIituLnRvU3RyaW5nKDE2KS50b1VwcGVyQ2FzZSgpKS5zbGljZSgtMik7cmV0dXJuIHJ9ZnVuY3Rpb24gaShlLHQpe3ZhciBuO3JldHVybiJzdHJpbmciIT09dHlwZW9mIHQmJih0PWkuZGVmYXVsdENoYXJzKSxuPXIodCksZS5yZXBsYWNlKC8oJVthLWYwLTldezJ9KSsvZ2ksZnVuY3Rpb24oZSl7dmFyIHQscixpLG8sYSxzLHUsYz0iIjtmb3IodD0wLHI9ZS5sZW5ndGg7dDxyO3QrPTMpaT1wYXJzZUludChlLnNsaWNlKHQrMSx0KzMpLDE2KSxpPDEyOD9jKz1uW2ldOjE5Mj09PSgyMjQmaSkmJnQrMzxyJiYxMjg9PT0oMTkyJihvPXBhcnNlSW50KGUuc2xpY2UodCs0LHQrNiksMTYpKSk/KHU9aTw8NiYxOTg0fDYzJm8sYys9dTwxMjg/Ilx1ZmZmZFx1ZmZmZCI6U3RyaW5nLmZyb21DaGFyQ29kZSh1KSx0Kz0zKToyMjQ9PT0oMjQwJmkpJiZ0KzY8ciYmKG89cGFyc2VJbnQoZS5zbGljZSh0KzQsdCs2KSwxNiksYT1wYXJzZUludChlLnNsaWNlKHQrNyx0KzkpLDE2KSwxMjg9PT0oMTkyJm8pJiYxMjg9PT0oMTkyJmEpKT8odT1pPDwxMiY2MTQ0MHxvPDw2JjQwMzJ8NjMmYSxjKz11PDIwNDh8fHU+PTU1Mjk2JiZ1PD01NzM0Mz8iXHVmZmZkXHVmZmZkXHVmZmZkIjpTdHJpbmcuZnJvbUNoYXJDb2RlKHUpLHQrPTYpOjI0MD09PSgyNDgmaSkmJnQrOTxyJiYobz1wYXJzZUludChlLnNsaWNlKHQrNCx0KzYpLDE2KSxhPXBhcnNlSW50KGUuc2xpY2UodCs3LHQrOSksMTYpLHM9cGFyc2VJbnQoZS5zbGljZSh0KzEwLHQrMTIpLDE2KSwxMjg9PT0oMTkyJm8pJiYxMjg9PT0oMTkyJmEpJiYxMjg9PT0oMTkyJnMpKT8odT1pPDwxOCYxODM1MDA4fG88PDEyJjI1ODA0OHxhPDw2JjQwMzJ8NjMmcyx1PDY1NTM2fHx1PjExMTQxMTE/Yys9Ilx1ZmZmZFx1ZmZmZFx1ZmZmZFx1ZmZmZCI6KHUtPTY1NTM2LGMrPVN0cmluZy5mcm9tQ2hhckNvZGUoNTUyOTYrKHU+PjEwKSw1NjMyMCsoMTAyMyZ1KSkpLHQrPTkpOmMrPSJcdWZmZmQiO3JldHVybiBjfSl9dmFyIG89e307aS5kZWZhdWx0Q2hhcnM9IjsvPzpAJj0rJCwjIixpLmNvbXBvbmVudENoYXJzPSIiLGUuZXhwb3J0cz1pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlKXt2YXIgdD0iIjtyZXR1cm4gdCs9ZS5wcm90b2NvbHx8IiIsdCs9ZS5zbGFzaGVzPyIvLyI6IiIsdCs9ZS5hdXRoP2UuYXV0aCsiQCI6IiIsZS5ob3N0bmFtZSYmLTEhPT1lLmhvc3RuYW1lLmluZGV4T2YoIjoiKT90Kz0iWyIrZS5ob3N0bmFtZSsiXSI6dCs9ZS5ob3N0bmFtZXx8IiIsdCs9ZS5wb3J0PyI6IitlLnBvcnQ6IiIsdCs9ZS5wYXRobmFtZXx8IiIsdCs9ZS5zZWFyY2h8fCIiLHQrPWUuaGFzaHx8IiJ9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXt0aGlzLnByb3RvY29sPW51bGwsdGhpcy5zbGFzaGVzPW51bGwsdGhpcy5hdXRoPW51bGwsdGhpcy5wb3J0PW51bGwsdGhpcy5ob3N0bmFtZT1udWxsLHRoaXMuaGFzaD1udWxsLHRoaXMuc2VhcmNoPW51bGwsdGhpcy5wYXRobmFtZT1udWxsfWZ1bmN0aW9uIGkoZSx0KXtpZihlJiZlIGluc3RhbmNlb2YgcilyZXR1cm4gZTt2YXIgbj1uZXcgcjtyZXR1cm4gbi5wYXJzZShlLHQpLG59dmFyIG89L14oW2EtejAtOS4rLV0rOikvaSxhPS86WzAtOV0qJC8scz0vXihcL1wvPyg/IVwvKVteXD9cc10qKShcP1teXHNdKik/JC8sdT1bIjwiLCI+IiwnIicsImAiLCIgIiwiXHIiLCJcbiIsIlx0Il0sYz1bInsiLCJ9IiwifCIsIlxcIiwiXiIsImAiXS5jb25jYXQodSksbD1bIiciXS5jb25jYXQoYykscD1bIiUiLCIvIiwiPyIsIjsiLCIjIl0uY29uY2F0KGwpLGY9WyIvIiwiPyIsIiMiXSxkPS9eWythLXowLTlBLVpfLV17MCw2M30kLyxoPS9eKFsrYS16MC05QS1aXy1dezAsNjN9KSguKikkLyxtPXtqYXZhc2NyaXB0OiEwLCJqYXZhc2NyaXB0OiI6ITB9LGc9e2h0dHA6ITAsaHR0cHM6ITAsZnRwOiEwLGdvcGhlcjohMCxmaWxlOiEwLCJodHRwOiI6ITAsImh0dHBzOiI6ITAsImZ0cDoiOiEwLCJnb3BoZXI6IjohMCwiZmlsZToiOiEwfTtyLnByb3RvdHlwZS5wYXJzZT1mdW5jdGlvbihlLHQpe3ZhciBuLHIsaSxhLHUsYz1lO2lmKGM9Yy50cmltKCksIXQmJjE9PT1lLnNwbGl0KCIjIikubGVuZ3RoKXt2YXIgbD1zLmV4ZWMoYyk7aWYobClyZXR1cm4gdGhpcy5wYXRobmFtZT1sWzFdLGxbMl0mJih0aGlzLnNlYXJjaD1sWzJdKSx0aGlzfXZhciB5PW8uZXhlYyhjKTtpZih5JiYoeT15WzBdLGk9eS50b0xvd2VyQ2FzZSgpLHRoaXMucHJvdG9jb2w9eSxjPWMuc3Vic3RyKHkubGVuZ3RoKSksKHR8fHl8fGMubWF0Y2goL15cL1wvW15AXC9dK0BbXkBcL10rLykpJiYoISh1PSIvLyI9PT1jLnN1YnN0cigwLDIpKXx8eSYmbVt5XXx8KGM9Yy5zdWJzdHIoMiksdGhpcy5zbGFzaGVzPSEwKSksIW1beV0mJih1fHx5JiYhZ1t5XSkpe3ZhciB2PS0xO2ZvcihuPTA7bjxmLmxlbmd0aDtuKyspLTEhPT0oYT1jLmluZGV4T2YoZltuXSkpJiYoLTE9PT12fHxhPHYpJiYodj1hKTt2YXIgYix4O2Zvcih4PS0xPT09dj9jLmxhc3RJbmRleE9mKCJAIik6Yy5sYXN0SW5kZXhPZigiQCIsdiksLTEhPT14JiYoYj1jLnNsaWNlKDAseCksYz1jLnNsaWNlKHgrMSksdGhpcy5hdXRoPWIpLHY9LTEsbj0wO248cC5sZW5ndGg7bisrKS0xIT09KGE9Yy5pbmRleE9mKHBbbl0pKSYmKC0xPT09dnx8YTx2KSYmKHY9YSk7LTE9PT12JiYodj1jLmxlbmd0aCksIjoiPT09Y1t2LTFdJiZ2LS07dmFyIEM9Yy5zbGljZSgwLHYpO2M9Yy5zbGljZSh2KSx0aGlzLnBhcnNlSG9zdChDKSx0aGlzLmhvc3RuYW1lPXRoaXMuaG9zdG5hbWV8fCIiO3ZhciBFPSJbIj09PXRoaXMuaG9zdG5hbWVbMF0mJiJdIj09PXRoaXMuaG9zdG5hbWVbdGhpcy5ob3N0bmFtZS5sZW5ndGgtMV07aWYoIUUpe3ZhciBEPXRoaXMuaG9zdG5hbWUuc3BsaXQoL1wuLyk7Zm9yKG49MCxyPUQubGVuZ3RoO248cjtuKyspe3ZhciB3PURbbl07aWYodyYmIXcubWF0Y2goZCkpe2Zvcih2YXIgUz0iIixrPTAsQT13Lmxlbmd0aDtrPEE7aysrKXcuY2hhckNvZGVBdChrKT4xMjc/Uys9IngiOlMrPXdba107aWYoIVMubWF0Y2goZCkpe3ZhciBfPUQuc2xpY2UoMCxuKSxUPUQuc2xpY2UobisxKSxPPXcubWF0Y2goaCk7TyYmKF8ucHVzaChPWzFdKSxULnVuc2hpZnQoT1syXSkpLFQubGVuZ3RoJiYoYz1ULmpvaW4oIi4iKStjKSx0aGlzLmhvc3RuYW1lPV8uam9pbigiLiIpO2JyZWFrfX19fXRoaXMuaG9zdG5hbWUubGVuZ3RoPjI1NSYmKHRoaXMuaG9zdG5hbWU9IiIpLEUmJih0aGlzLmhvc3RuYW1lPXRoaXMuaG9zdG5hbWUuc3Vic3RyKDEsdGhpcy5ob3N0bmFtZS5sZW5ndGgtMikpfXZhciBGPWMuaW5kZXhPZigiIyIpOy0xIT09RiYmKHRoaXMuaGFzaD1jLnN1YnN0cihGKSxjPWMuc2xpY2UoMCxGKSk7dmFyIE49Yy5pbmRleE9mKCI/Iik7cmV0dXJuLTEhPT1OJiYodGhpcy5zZWFyY2g9Yy5zdWJzdHIoTiksYz1jLnNsaWNlKDAsTikpLGMmJih0aGlzLnBhdGhuYW1lPWMpLGdbaV0mJnRoaXMuaG9zdG5hbWUmJiF0aGlzLnBhdGhuYW1lJiYodGhpcy5wYXRobmFtZT0iIiksdGhpc30sci5wcm90b3R5cGUucGFyc2VIb3N0PWZ1bmN0aW9uKGUpe3ZhciB0PWEuZXhlYyhlKTt0JiYodD10WzBdLCI6IiE9PXQmJih0aGlzLnBvcnQ9dC5zdWJzdHIoMSkpLGU9ZS5zdWJzdHIoMCxlLmxlbmd0aC10Lmxlbmd0aCkpLGUmJih0aGlzLmhvc3RuYW1lPWUpfSxlLmV4cG9ydHM9aX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt0LkFueT1uKDU0NCksdC5DYz1uKDU0NSksdC5DZj1uKDU0NiksdC5QPW4oMjYzKSx0Llo9big1NDcpfSxmdW5jdGlvbihlLHQpe2UuZXhwb3J0cz0vW1wwLVx1RDdGRlx1RTAwMC1cdUZGRkZdfFtcdUQ4MDAtXHVEQkZGXVtcdURDMDAtXHVERkZGXXxbXHVEODAwLVx1REJGRl0oPyFbXHVEQzAwLVx1REZGRl0pfCg/OlteXHVEODAwLVx1REJGRl18XilbXHVEQzAwLVx1REZGRl0vfSxmdW5jdGlvbihlLHQpe2UuZXhwb3J0cz0vW1wwLVx4MUZceDdGLVx4OUZdL30sZnVuY3Rpb24oZSx0KXtlLmV4cG9ydHM9L1tceEFEXHUwNjAwLVx1MDYwNVx1MDYxQ1x1MDZERFx1MDcwRlx1MDhFMlx1MTgwRVx1MjAwQi1cdTIwMEZcdTIwMkEtXHUyMDJFXHUyMDYwLVx1MjA2NFx1MjA2Ni1cdTIwNkZcdUZFRkZcdUZGRjktXHVGRkZCXXxcdUQ4MDRcdURDQkR8XHVEODJGW1x1RENBMC1cdURDQTNdfFx1RDgzNFtcdURENzMtXHVERDdBXXxcdURCNDBbXHVEQzAxXHVEQzIwLVx1REM3Rl0vfSxmdW5jdGlvbihlLHQpe2UuZXhwb3J0cz0vWyBceEEwXHUxNjgwXHUyMDAwLVx1MjAwQVx1MjAyRlx1MjA1Rlx1MzAwMF0vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3QucGFyc2VMaW5rTGFiZWw9big1NDkpLHQucGFyc2VMaW5rRGVzdGluYXRpb249big1NTApLHQucGFyc2VMaW5rVGl0bGU9big1NTEpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbil7dmFyIHIsaSxvLGEscz0tMSx1PWUucG9zTWF4LGM9ZS5wb3M7Zm9yKGUucG9zPXQrMSxyPTE7ZS5wb3M8dTspe2lmKDkzPT09KG89ZS5zcmMuY2hhckNvZGVBdChlLnBvcykpJiYwPT09LS1yKXtpPSEwO2JyZWFrfWlmKGE9ZS5wb3MsZS5tZC5pbmxpbmUuc2tpcFRva2VuKGUpLDkxPT09bylpZihhPT09ZS5wb3MtMSlyKys7ZWxzZSBpZihuKXJldHVybiBlLnBvcz1jLC0xfXJldHVybiBpJiYocz1lLnBvcyksZS5wb3M9YyxzfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDQpLmlzU3BhY2UsaT1uKDQpLnVuZXNjYXBlQWxsO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbil7dmFyIG8sYSxzPXQsdT17b2s6ITEscG9zOjAsbGluZXM6MCxzdHI6IiJ9O2lmKDYwPT09ZS5jaGFyQ29kZUF0KHQpKXtmb3IodCsrO3Q8bjspe2lmKDEwPT09KG89ZS5jaGFyQ29kZUF0KHQpKXx8cihvKSlyZXR1cm4gdTtpZig2Mj09PW8pcmV0dXJuIHUucG9zPXQrMSx1LnN0cj1pKGUuc2xpY2UocysxLHQpKSx1Lm9rPSEwLHU7OTI9PT1vJiZ0KzE8bj90Kz0yOnQrK31yZXR1cm4gdX1mb3IoYT0wO3Q8biYmMzIhPT0obz1lLmNoYXJDb2RlQXQodCkpJiYhKG88MzJ8fDEyNz09PW8pOylpZig5Mj09PW8mJnQrMTxuKXQrPTI7ZWxzZXtpZig0MD09PW8mJmErKyw0MT09PW8pe2lmKDA9PT1hKWJyZWFrO2EtLX10Kyt9cmV0dXJuIHM9PT10P3U6MCE9PWE/dToodS5zdHI9aShlLnNsaWNlKHMsdCkpLHUubGluZXM9MCx1LnBvcz10LHUub2s9ITAsdSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNCkudW5lc2NhcGVBbGw7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCxuKXt2YXIgaSxvLGE9MCxzPXQsdT17b2s6ITEscG9zOjAsbGluZXM6MCxzdHI6IiJ9O2lmKHQ+PW4pcmV0dXJuIHU7aWYoMzQhPT0obz1lLmNoYXJDb2RlQXQodCkpJiYzOSE9PW8mJjQwIT09bylyZXR1cm4gdTtmb3IodCsrLDQwPT09byYmKG89NDEpO3Q8bjspe2lmKChpPWUuY2hhckNvZGVBdCh0KSk9PT1vKXJldHVybiB1LnBvcz10KzEsdS5saW5lcz1hLHUuc3RyPXIoZS5zbGljZShzKzEsdCkpLHUub2s9ITAsdTsxMD09PWk/YSsrOjkyPT09aSYmdCsxPG4mJih0KyssMTA9PT1lLmNoYXJDb2RlQXQodCkmJmErKyksdCsrfXJldHVybiB1fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKCl7dGhpcy5ydWxlcz1pKHt9LHMpfXZhciBpPW4oNCkuYXNzaWduLG89big0KS51bmVzY2FwZUFsbCxhPW4oNCkuZXNjYXBlSHRtbCxzPXt9O3MuY29kZV9pbmxpbmU9ZnVuY3Rpb24oZSx0LG4scixpKXt2YXIgbz1lW3RdO3JldHVybiI8Y29kZSIraS5yZW5kZXJBdHRycyhvKSsiPiIrYShlW3RdLmNvbnRlbnQpKyI8L2NvZGU+In0scy5jb2RlX2Jsb2NrPWZ1bmN0aW9uKGUsdCxuLHIsaSl7dmFyIG89ZVt0XTtyZXR1cm4iPHByZSIraS5yZW5kZXJBdHRycyhvKSsiPjxjb2RlPiIrYShlW3RdLmNvbnRlbnQpKyI8L2NvZGU+PC9wcmU+XG4ifSxzLmZlbmNlPWZ1bmN0aW9uKGUsdCxuLHIsaSl7dmFyIHMsdSxjLGwscD1lW3RdLGY9cC5pbmZvP28ocC5pbmZvKS50cmltKCk6IiIsZD0iIjtyZXR1cm4gZiYmKGQ9Zi5zcGxpdCgvXHMrL2cpWzBdKSxzPW4uaGlnaGxpZ2h0P24uaGlnaGxpZ2h0KHAuY29udGVudCxkKXx8YShwLmNvbnRlbnQpOmEocC5jb250ZW50KSwwPT09cy5pbmRleE9mKCI8cHJlIik/cysiXG4iOmY/KHU9cC5hdHRySW5kZXgoImNsYXNzIiksYz1wLmF0dHJzP3AuYXR0cnMuc2xpY2UoKTpbXSx1PDA/Yy5wdXNoKFsiY2xhc3MiLG4ubGFuZ1ByZWZpeCtkXSk6Y1t1XVsxXSs9IiAiK24ubGFuZ1ByZWZpeCtkLGw9e2F0dHJzOmN9LCI8cHJlPjxjb2RlIitpLnJlbmRlckF0dHJzKGwpKyI+IitzKyI8L2NvZGU+PC9wcmU+XG4iKToiPHByZT48Y29kZSIraS5yZW5kZXJBdHRycyhwKSsiPiIrcysiPC9jb2RlPjwvcHJlPlxuIn0scy5pbWFnZT1mdW5jdGlvbihlLHQsbixyLGkpe3ZhciBvPWVbdF07cmV0dXJuIG8uYXR0cnNbby5hdHRySW5kZXgoImFsdCIpXVsxXT1pLnJlbmRlcklubGluZUFzVGV4dChvLmNoaWxkcmVuLG4sciksaS5yZW5kZXJUb2tlbihlLHQsbil9LHMuaGFyZGJyZWFrPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gbi54aHRtbE91dD8iPGJyIC8+XG4iOiI8YnI+XG4ifSxzLnNvZnRicmVhaz1mdW5jdGlvbihlLHQsbil7cmV0dXJuIG4uYnJlYWtzP24ueGh0bWxPdXQ/IjxiciAvPlxuIjoiPGJyPlxuIjoiXG4ifSxzLnRleHQ9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gYShlW3RdLmNvbnRlbnQpfSxzLmh0bWxfYmxvY2s9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZVt0XS5jb250ZW50fSxzLmh0bWxfaW5saW5lPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGVbdF0uY29udGVudH0sci5wcm90b3R5cGUucmVuZGVyQXR0cnM9ZnVuY3Rpb24oZSl7dmFyIHQsbixyO2lmKCFlLmF0dHJzKXJldHVybiIiO2ZvcihyPSIiLHQ9MCxuPWUuYXR0cnMubGVuZ3RoO3Q8bjt0Kyspcis9IiAiK2EoZS5hdHRyc1t0XVswXSkrJz0iJythKGUuYXR0cnNbdF1bMV0pKyciJztyZXR1cm4gcn0sci5wcm90b3R5cGUucmVuZGVyVG9rZW49ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGk9IiIsbz0hMSxhPWVbdF07cmV0dXJuIGEuaGlkZGVuPyIiOihhLmJsb2NrJiYtMSE9PWEubmVzdGluZyYmdCYmZVt0LTFdLmhpZGRlbiYmKGkrPSJcbiIpLGkrPSgtMT09PWEubmVzdGluZz8iPC8iOiI8IikrYS50YWcsaSs9dGhpcy5yZW5kZXJBdHRycyhhKSwwPT09YS5uZXN0aW5nJiZuLnhodG1sT3V0JiYoaSs9IiAvIiksYS5ibG9jayYmKG89ITAsMT09PWEubmVzdGluZyYmdCsxPGUubGVuZ3RoJiYocj1lW3QrMV0sImlubGluZSI9PT1yLnR5cGV8fHIuaGlkZGVuP289ITE6LTE9PT1yLm5lc3RpbmcmJnIudGFnPT09YS50YWcmJihvPSExKSkpLGkrPW8/Ij5cbiI6Ij4iKX0sci5wcm90b3R5cGUucmVuZGVySW5saW5lPWZ1bmN0aW9uKGUsdCxuKXtmb3IodmFyIHIsaT0iIixvPXRoaXMucnVsZXMsYT0wLHM9ZS5sZW5ndGg7YTxzO2ErKylyPWVbYV0udHlwZSwidW5kZWZpbmVkIiE9PXR5cGVvZiBvW3JdP2krPW9bcl0oZSxhLHQsbix0aGlzKTppKz10aGlzLnJlbmRlclRva2VuKGUsYSx0KTtyZXR1cm4gaX0sci5wcm90b3R5cGUucmVuZGVySW5saW5lQXNUZXh0PWZ1bmN0aW9uKGUsdCxuKXtmb3IodmFyIHI9IiIsaT0wLG89ZS5sZW5ndGg7aTxvO2krKykidGV4dCI9PT1lW2ldLnR5cGU/cis9ZVtpXS5jb250ZW50OiJpbWFnZSI9PT1lW2ldLnR5cGUmJihyKz10aGlzLnJlbmRlcklubGluZUFzVGV4dChlW2ldLmNoaWxkcmVuLHQsbikpO3JldHVybiByfSxyLnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbyxhPSIiLHM9dGhpcy5ydWxlcztmb3Iocj0wLGk9ZS5sZW5ndGg7cjxpO3IrKylvPWVbcl0udHlwZSwiaW5saW5lIj09PW8/YSs9dGhpcy5yZW5kZXJJbmxpbmUoZVtyXS5jaGlsZHJlbix0LG4pOiJ1bmRlZmluZWQiIT09dHlwZW9mIHNbb10/YSs9c1tlW3JdLnR5cGVdKGUscix0LG4sdGhpcyk6YSs9dGhpcy5yZW5kZXJUb2tlbihlLHIsdCxuKTtyZXR1cm4gYX0sZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3RoaXMucnVsZXI9bmV3IGk7Zm9yKHZhciBlPTA7ZTxvLmxlbmd0aDtlKyspdGhpcy5ydWxlci5wdXNoKG9bZV1bMF0sb1tlXVsxXSl9dmFyIGk9bigxMzQpLG89W1sibm9ybWFsaXplIixuKDU1NCldLFsiYmxvY2siLG4oNTU1KV0sWyJpbmxpbmUiLG4oNTU2KV0sWyJsaW5raWZ5IixuKDU1NyldLFsicmVwbGFjZW1lbnRzIixuKDU1OCldLFsic21hcnRxdW90ZXMiLG4oNTU5KV1dO3IucHJvdG90eXBlLnByb2Nlc3M9ZnVuY3Rpb24oZSl7dmFyIHQsbixyO2ZvcihyPXRoaXMucnVsZXIuZ2V0UnVsZXMoIiIpLHQ9MCxuPXIubGVuZ3RoO3Q8bjt0Kyspclt0XShlKX0sci5wcm90b3R5cGUuU3RhdGU9big1NjApLGUuZXhwb3J0cz1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPS9ccltcblx1MDA4NV0/fFtcdTI0MjRcdTIwMjhcdTAwODVdL2csaT0vXHUwMDAwL2c7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0O3Q9ZS5zcmMucmVwbGFjZShyLCJcbiIpLHQ9dC5yZXBsYWNlKGksIlx1ZmZmZCIpLGUuc3JjPXR9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlKXt2YXIgdDtlLmlubGluZU1vZGU/KHQ9bmV3IGUuVG9rZW4oImlubGluZSIsIiIsMCksdC5jb250ZW50PWUuc3JjLHQubWFwPVswLDFdLHQuY2hpbGRyZW49W10sZS50b2tlbnMucHVzaCh0KSk6ZS5tZC5ibG9jay5wYXJzZShlLnNyYyxlLm1kLGUuZW52LGUudG9rZW5zKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0LG4scixpPWUudG9rZW5zO2ZvcihuPTAscj1pLmxlbmd0aDtuPHI7bisrKXQ9aVtuXSwiaW5saW5lIj09PXQudHlwZSYmZS5tZC5pbmxpbmUucGFyc2UodC5jb250ZW50LGUubWQsZS5lbnYsdC5jaGlsZHJlbil9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuL148YVs+XHNdL2kudGVzdChlKX1mdW5jdGlvbiBpKGUpe3JldHVybi9ePFwvYVxzKj4vaS50ZXN0KGUpfXZhciBvPW4oNCkuYXJyYXlSZXBsYWNlQXQ7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0LG4sYSxzLHUsYyxsLHAsZixkLGgsbSxnLHksdixiLHgsQz1lLnRva2VucztpZihlLm1kLm9wdGlvbnMubGlua2lmeSlmb3Iobj0wLGE9Qy5sZW5ndGg7bjxhO24rKylpZigiaW5saW5lIj09PUNbbl0udHlwZSYmZS5tZC5saW5raWZ5LnByZXRlc3QoQ1tuXS5jb250ZW50KSlmb3Iocz1DW25dLmNoaWxkcmVuLGc9MCx0PXMubGVuZ3RoLTE7dD49MDt0LS0paWYoYz1zW3RdLCJsaW5rX2Nsb3NlIiE9PWMudHlwZSl7aWYoImh0bWxfaW5saW5lIj09PWMudHlwZSYmKHIoYy5jb250ZW50KSYmZz4wJiZnLS0saShjLmNvbnRlbnQpJiZnKyspLCEoZz4wKSYmInRleHQiPT09Yy50eXBlJiZlLm1kLmxpbmtpZnkudGVzdChjLmNvbnRlbnQpKXtmb3IoZj1jLmNvbnRlbnQseD1lLm1kLmxpbmtpZnkubWF0Y2goZiksbD1bXSxtPWMubGV2ZWwsaD0wLHA9MDtwPHgubGVuZ3RoO3ArKyl5PXhbcF0udXJsLHY9ZS5tZC5ub3JtYWxpemVMaW5rKHkpLGUubWQudmFsaWRhdGVMaW5rKHYpJiYoYj14W3BdLnRleHQsYj14W3BdLnNjaGVtYT8ibWFpbHRvOiIhPT14W3BdLnNjaGVtYXx8L15tYWlsdG86L2kudGVzdChiKT9lLm1kLm5vcm1hbGl6ZUxpbmtUZXh0KGIpOmUubWQubm9ybWFsaXplTGlua1RleHQoIm1haWx0bzoiK2IpLnJlcGxhY2UoL15tYWlsdG86LywiIik6ZS5tZC5ub3JtYWxpemVMaW5rVGV4dCgiaHR0cDovLyIrYikucmVwbGFjZSgvXmh0dHA6XC9cLy8sIiIpLGQ9eFtwXS5pbmRleCxkPmgmJih1PW5ldyBlLlRva2VuKCJ0ZXh0IiwiIiwwKSx1LmNvbnRlbnQ9Zi5zbGljZShoLGQpLHUubGV2ZWw9bSxsLnB1c2godSkpLHU9bmV3IGUuVG9rZW4oImxpbmtfb3BlbiIsImEiLDEpLHUuYXR0cnM9W1siaHJlZiIsdl1dLHUubGV2ZWw9bSsrLHUubWFya3VwPSJsaW5raWZ5Iix1LmluZm89ImF1dG8iLGwucHVzaCh1KSx1PW5ldyBlLlRva2VuKCJ0ZXh0IiwiIiwwKSx1LmNvbnRlbnQ9Yix1LmxldmVsPW0sbC5wdXNoKHUpLHU9bmV3IGUuVG9rZW4oImxpbmtfY2xvc2UiLCJhIiwtMSksdS5sZXZlbD0tLW0sdS5tYXJrdXA9ImxpbmtpZnkiLHUuaW5mbz0iYXV0byIsbC5wdXNoKHUpLGg9eFtwXS5sYXN0SW5kZXgpO2g8Zi5sZW5ndGgmJih1PW5ldyBlLlRva2VuKCJ0ZXh0IiwiIiwwKSx1LmNvbnRlbnQ9Zi5zbGljZShoKSx1LmxldmVsPW0sbC5wdXNoKHUpKSxDW25dLmNoaWxkcmVuPXM9byhzLHQsbCl9fWVsc2UgZm9yKHQtLTtzW3RdLmxldmVsIT09Yy5sZXZlbCYmImxpbmtfb3BlbiIhPT1zW3RdLnR5cGU7KXQtLX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybiBjW3QudG9Mb3dlckNhc2UoKV19ZnVuY3Rpb24gaShlKXt2YXIgdCxuLGk9MDtmb3IodD1lLmxlbmd0aC0xO3Q+PTA7dC0tKW49ZVt0XSwidGV4dCIhPT1uLnR5cGV8fGl8fChuLmNvbnRlbnQ9bi5jb250ZW50LnJlcGxhY2UodSxyKSksImxpbmtfb3BlbiI9PT1uLnR5cGUmJiJhdXRvIj09PW4uaW5mbyYmaS0tLCJsaW5rX2Nsb3NlIj09PW4udHlwZSYmImF1dG8iPT09bi5pbmZvJiZpKyt9ZnVuY3Rpb24gbyhlKXt2YXIgdCxuLHI9MDtmb3IodD1lLmxlbmd0aC0xO3Q+PTA7dC0tKW49ZVt0XSwidGV4dCIhPT1uLnR5cGV8fHJ8fGEudGVzdChuLmNvbnRlbnQpJiYobi5jb250ZW50PW4uY29udGVudC5yZXBsYWNlKC9cKy0vZywiXHhiMSIpLnJlcGxhY2UoL1wuezIsfS9nLCJcdTIwMjYiKS5yZXBsYWNlKC8oWz8hXSlcdTIwMjYvZywiJDEuLiIpLnJlcGxhY2UoLyhbPyFdKXs0LH0vZywiJDEkMSQxIikucmVwbGFjZSgvLHsyLH0vZywiLCIpLnJlcGxhY2UoLyhefFteLV0pLS0tKFteLV18JCkvZ20sIiQxXHUyMDE0JDIiKS5yZXBsYWNlKC8oXnxccyktLShcc3wkKS9nbSwiJDFcdTIwMTMkMiIpLnJlcGxhY2UoLyhefFteLVxzXSktLShbXi1cc118JCkvZ20sIiQxXHUyMDEzJDIiKSksImxpbmtfb3BlbiI9PT1uLnR5cGUmJiJhdXRvIj09PW4uaW5mbyYmci0tLCJsaW5rX2Nsb3NlIj09PW4udHlwZSYmImF1dG8iPT09bi5pbmZvJiZyKyt9dmFyIGE9L1wrLXxcLlwufFw/XD9cP1w/fCEhISF8LCx8LS0vLHM9L1woKGN8dG18cnxwKVwpL2ksdT0vXCgoY3x0bXxyfHApXCkvZ2ksYz17YzoiXHhhOSIscjoiXHhhZSIscDoiXHhhNyIsdG06Ilx1MjEyMiJ9O2UuZXhwb3J0cz1mdW5jdGlvbihlKXt2YXIgdDtpZihlLm1kLm9wdGlvbnMudHlwb2dyYXBoZXIpZm9yKHQ9ZS50b2tlbnMubGVuZ3RoLTE7dD49MDt0LS0pImlubGluZSI9PT1lLnRva2Vuc1t0XS50eXBlJiYocy50ZXN0KGUudG9rZW5zW3RdLmNvbnRlbnQpJiZpKGUudG9rZW5zW3RdLmNoaWxkcmVuKSxhLnRlc3QoZS50b2tlbnNbdF0uY29udGVudCkmJm8oZS50b2tlbnNbdF0uY2hpbGRyZW4pKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuIGUuc3Vic3RyKDAsdCkrbitlLnN1YnN0cih0KzEpfWZ1bmN0aW9uIGkoZSx0KXt2YXIgbixpLHUscCxmLGQsaCxtLGcseSx2LGIseCxDLEUsRCx3LFMsayxBLF87Zm9yKGs9W10sbj0wO248ZS5sZW5ndGg7bisrKXtmb3IoaT1lW25dLGg9ZVtuXS5sZXZlbCx3PWsubGVuZ3RoLTE7dz49MCYmIShrW3ddLmxldmVsPD1oKTt3LS0pO2lmKGsubGVuZ3RoPXcrMSwidGV4dCI9PT1pLnR5cGUpe3U9aS5jb250ZW50LGY9MCxkPXUubGVuZ3RoO2U6Zm9yKDtmPGQmJihjLmxhc3RJbmRleD1mLHA9Yy5leGVjKHUpKTspe2lmKEU9RD0hMCxmPXAuaW5kZXgrMSxTPSInIj09PXBbMF0sZz0zMixwLmluZGV4LTE+PTApZz11LmNoYXJDb2RlQXQocC5pbmRleC0xKTtlbHNlIGZvcih3PW4tMTt3Pj0wJiYoInNvZnRicmVhayIhPT1lW3ddLnR5cGUmJiJoYXJkYnJlYWsiIT09ZVt3XS50eXBlKTt3LS0paWYoInRleHQiPT09ZVt3XS50eXBlKXtnPWVbd10uY29udGVudC5jaGFyQ29kZUF0KGVbd10uY29udGVudC5sZW5ndGgtMSk7YnJlYWt9aWYoeT0zMixmPGQpeT11LmNoYXJDb2RlQXQoZik7ZWxzZSBmb3Iodz1uKzE7dzxlLmxlbmd0aCYmKCJzb2Z0YnJlYWsiIT09ZVt3XS50eXBlJiYiaGFyZGJyZWFrIiE9PWVbd10udHlwZSk7dysrKWlmKCJ0ZXh0Ij09PWVbd10udHlwZSl7eT1lW3ddLmNvbnRlbnQuY2hhckNvZGVBdCgwKTticmVha31pZih2PXMoZyl8fGEoU3RyaW5nLmZyb21DaGFyQ29kZShnKSksYj1zKHkpfHxhKFN0cmluZy5mcm9tQ2hhckNvZGUoeSkpLHg9byhnKSxDPW8oeSksQz9FPSExOmImJih4fHx2fHwoRT0hMSkpLHg/RD0hMTp2JiYoQ3x8Ynx8KEQ9ITEpKSwzND09PXkmJiciJz09PXBbMF0mJmc+PTQ4JiZnPD01NyYmKEQ9RT0hMSksRSYmRCYmKEU9ITEsRD1iKSxFfHxEKXtpZihEKWZvcih3PWsubGVuZ3RoLTE7dz49MCYmKG09a1t3XSwhKGtbd10ubGV2ZWw8aCkpO3ctLSlpZihtLnNpbmdsZT09PVMmJmtbd10ubGV2ZWw9PT1oKXttPWtbd10sUz8oQT10Lm1kLm9wdGlvbnMucXVvdGVzWzJdLF89dC5tZC5vcHRpb25zLnF1b3Rlc1szXSk6KEE9dC5tZC5vcHRpb25zLnF1b3Rlc1swXSxfPXQubWQub3B0aW9ucy5xdW90ZXNbMV0pLGkuY29udGVudD1yKGkuY29udGVudCxwLmluZGV4LF8pLGVbbS50b2tlbl0uY29udGVudD1yKGVbbS50b2tlbl0uY29udGVudCxtLnBvcyxBKSxmKz1fLmxlbmd0aC0xLG0udG9rZW49PT1uJiYoZis9QS5sZW5ndGgtMSksdT1pLmNvbnRlbnQsZD11Lmxlbmd0aCxrLmxlbmd0aD13O2NvbnRpbnVlIGV9RT9rLnB1c2goe3Rva2VuOm4scG9zOnAuaW5kZXgsc2luZ2xlOlMsbGV2ZWw6aH0pOkQmJlMmJihpLmNvbnRlbnQ9cihpLmNvbnRlbnQscC5pbmRleCxsKSl9ZWxzZSBTJiYoaS5jb250ZW50PXIoaS5jb250ZW50LHAuaW5kZXgsbCkpfX19fXZhciBvPW4oNCkuaXNXaGl0ZVNwYWNlLGE9big0KS5pc1B1bmN0Q2hhcixzPW4oNCkuaXNNZEFzY2lpUHVuY3QsdT0vWyciXS8sYz0vWyciXS9nLGw9Ilx1MjAxOSI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0O2lmKGUubWQub3B0aW9ucy50eXBvZ3JhcGhlcilmb3IodD1lLnRva2Vucy5sZW5ndGgtMTt0Pj0wO3QtLSkiaW5saW5lIj09PWUudG9rZW5zW3RdLnR5cGUmJnUudGVzdChlLnRva2Vuc1t0XS5jb250ZW50KSYmaShlLnRva2Vuc1t0XS5jaGlsZHJlbixlKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7dGhpcy5zcmM9ZSx0aGlzLmVudj1uLHRoaXMudG9rZW5zPVtdLHRoaXMuaW5saW5lTW9kZT0hMSx0aGlzLm1kPXR9dmFyIGk9bigxMzUpO3IucHJvdG90eXBlLlRva2VuPWksZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3RoaXMucnVsZXI9bmV3IGk7Zm9yKHZhciBlPTA7ZTxvLmxlbmd0aDtlKyspdGhpcy5ydWxlci5wdXNoKG9bZV1bMF0sb1tlXVsxXSx7YWx0OihvW2VdWzJdfHxbXSkuc2xpY2UoKX0pfXZhciBpPW4oMTM0KSxvPVtbInRhYmxlIixuKDU2MiksWyJwYXJhZ3JhcGgiLCJyZWZlcmVuY2UiXV0sWyJjb2RlIixuKDU2MyldLFsiZmVuY2UiLG4oNTY0KSxbInBhcmFncmFwaCIsInJlZmVyZW5jZSIsImJsb2NrcXVvdGUiLCJsaXN0Il1dLFsiYmxvY2txdW90ZSIsbig1NjUpLFsicGFyYWdyYXBoIiwicmVmZXJlbmNlIiwiYmxvY2txdW90ZSIsImxpc3QiXV0sWyJociIsbig1NjYpLFsicGFyYWdyYXBoIiwicmVmZXJlbmNlIiwiYmxvY2txdW90ZSIsImxpc3QiXV0sWyJsaXN0IixuKDU2NyksWyJwYXJhZ3JhcGgiLCJyZWZlcmVuY2UiLCJibG9ja3F1b3RlIl1dLFsicmVmZXJlbmNlIixuKDU2OCldLFsiaGVhZGluZyIsbig1NjkpLFsicGFyYWdyYXBoIiwicmVmZXJlbmNlIiwiYmxvY2txdW90ZSJdXSxbImxoZWFkaW5nIixuKDU3MCldLFsiaHRtbF9ibG9jayIsbig1NzEpLFsicGFyYWdyYXBoIiwicmVmZXJlbmNlIiwiYmxvY2txdW90ZSJdXSxbInBhcmFncmFwaCIsbig1NzMpXV07ci5wcm90b3R5cGUudG9rZW5pemU9ZnVuY3Rpb24oZSx0LG4pe2Zvcih2YXIgcixpPXRoaXMucnVsZXIuZ2V0UnVsZXMoIiIpLG89aS5sZW5ndGgsYT10LHM9ITEsdT1lLm1kLm9wdGlvbnMubWF4TmVzdGluZzthPG4mJihlLmxpbmU9YT1lLnNraXBFbXB0eUxpbmVzKGEpLCEoYT49bikpJiYhKGUuc0NvdW50W2FdPGUuYmxrSW5kZW50KTspe2lmKGUubGV2ZWw+PXUpe2UubGluZT1uO2JyZWFrfWZvcihyPTA7cjxvJiYhaVtyXShlLGEsbiwhMSk7cisrKTtlLnRpZ2h0PSFzLGUuaXNFbXB0eShlLmxpbmUtMSkmJihzPSEwKSwoYT1lLmxpbmUpPG4mJmUuaXNFbXB0eShhKSYmKHM9ITAsYSsrLGUubGluZT1hKX19LHIucHJvdG90eXBlLnBhcnNlPWZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpO2UmJihpPW5ldyB0aGlzLlN0YXRlKGUsdCxuLHIpLHRoaXMudG9rZW5pemUoaSxpLmxpbmUsaS5saW5lTWF4KSl9LHIucHJvdG90eXBlLlN0YXRlPW4oNTc0KSxlLmV4cG9ydHM9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dmFyIG49ZS5iTWFya3NbdF0rZS5ibGtJbmRlbnQscj1lLmVNYXJrc1t0XTtyZXR1cm4gZS5zcmMuc3Vic3RyKG4sci1uKX1mdW5jdGlvbiBpKGUpe3ZhciB0LG49W10scj0wLGk9ZS5sZW5ndGgsbz0wLGE9MCxzPSExLHU9MDtmb3IodD1lLmNoYXJDb2RlQXQocik7cjxpOyk5Nj09PXQ/cz8ocz0hMSx1PXIpOm8lMj09PTAmJihzPSEwLHU9cik6MTI0IT09dHx8byUyIT09MHx8c3x8KG4ucHVzaChlLnN1YnN0cmluZyhhLHIpKSxhPXIrMSksOTI9PT10P28rKzpvPTAscisrLHI9PT1pJiZzJiYocz0hMSxyPXUrMSksdD1lLmNoYXJDb2RlQXQocik7cmV0dXJuIG4ucHVzaChlLnN1YnN0cmluZyhhKSksbn12YXIgbz1uKDQpLmlzU3BhY2U7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCxuLGEpe3ZhciBzLHUsYyxsLHAsZixkLGgsbSxnLHksdjtpZih0KzI+bilyZXR1cm4hMTtpZihwPXQrMSxlLnNDb3VudFtwXTxlLmJsa0luZGVudClyZXR1cm4hMTtpZihlLnNDb3VudFtwXS1lLmJsa0luZGVudD49NClyZXR1cm4hMTtpZigoYz1lLmJNYXJrc1twXStlLnRTaGlmdFtwXSk+PWUuZU1hcmtzW3BdKXJldHVybiExO2lmKDEyNCE9PShzPWUuc3JjLmNoYXJDb2RlQXQoYysrKSkmJjQ1IT09cyYmNTghPT1zKXJldHVybiExO2Zvcig7YzxlLmVNYXJrc1twXTspe2lmKDEyNCE9PShzPWUuc3JjLmNoYXJDb2RlQXQoYykpJiY0NSE9PXMmJjU4IT09cyYmIW8ocykpcmV0dXJuITE7YysrfWZvcih1PXIoZSx0KzEpLGY9dS5zcGxpdCgifCIpLG09W10sbD0wO2w8Zi5sZW5ndGg7bCsrKXtpZighKGc9ZltsXS50cmltKCkpKXtpZigwPT09bHx8bD09PWYubGVuZ3RoLTEpY29udGludWU7cmV0dXJuITF9aWYoIS9eOj8tKzo/JC8udGVzdChnKSlyZXR1cm4hMTs1OD09PWcuY2hhckNvZGVBdChnLmxlbmd0aC0xKT9tLnB1c2goNTg9PT1nLmNoYXJDb2RlQXQoMCk/ImNlbnRlciI6InJpZ2h0Iik6NTg9PT1nLmNoYXJDb2RlQXQoMCk/bS5wdXNoKCJsZWZ0Iik6bS5wdXNoKCIiKX1pZih1PXIoZSx0KS50cmltKCksLTE9PT11LmluZGV4T2YoInwiKSlyZXR1cm4hMTtpZihlLnNDb3VudFt0XS1lLmJsa0luZGVudD49NClyZXR1cm4hMTtpZihmPWkodS5yZXBsYWNlKC9eXHx8XHwkL2csIiIpKSwoZD1mLmxlbmd0aCk+bS5sZW5ndGgpcmV0dXJuITE7aWYoYSlyZXR1cm4hMDtmb3IoaD1lLnB1c2goInRhYmxlX29wZW4iLCJ0YWJsZSIsMSksaC5tYXA9eT1bdCwwXSxoPWUucHVzaCgidGhlYWRfb3BlbiIsInRoZWFkIiwxKSxoLm1hcD1bdCx0KzFdLGg9ZS5wdXNoKCJ0cl9vcGVuIiwidHIiLDEpLGgubWFwPVt0LHQrMV0sbD0wO2w8Zi5sZW5ndGg7bCsrKWg9ZS5wdXNoKCJ0aF9vcGVuIiwidGgiLDEpLGgubWFwPVt0LHQrMV0sbVtsXSYmKGguYXR0cnM9W1sic3R5bGUiLCJ0ZXh0LWFsaWduOiIrbVtsXV1dKSxoPWUucHVzaCgiaW5saW5lIiwiIiwwKSxoLmNvbnRlbnQ9ZltsXS50cmltKCksaC5tYXA9W3QsdCsxXSxoLmNoaWxkcmVuPVtdLGg9ZS5wdXNoKCJ0aF9jbG9zZSIsInRoIiwtMSk7Zm9yKGg9ZS5wdXNoKCJ0cl9jbG9zZSIsInRyIiwtMSksaD1lLnB1c2goInRoZWFkX2Nsb3NlIiwidGhlYWQiLC0xKSxoPWUucHVzaCgidGJvZHlfb3BlbiIsInRib2R5IiwxKSxoLm1hcD12PVt0KzIsMF0scD10KzI7cDxuJiYhKGUuc0NvdW50W3BdPGUuYmxrSW5kZW50KSYmKHU9cihlLHApLnRyaW0oKSwtMSE9PXUuaW5kZXhPZigifCIpKSYmIShlLnNDb3VudFtwXS1lLmJsa0luZGVudD49NCk7cCsrKXtmb3IoZj1pKHUucmVwbGFjZSgvXlx8fFx8JC9nLCIiKSksaD1lLnB1c2goInRyX29wZW4iLCJ0ciIsMSksbD0wO2w8ZDtsKyspaD1lLnB1c2goInRkX29wZW4iLCJ0ZCIsMSksbVtsXSYmKGguYXR0cnM9W1sic3R5bGUiLCJ0ZXh0LWFsaWduOiIrbVtsXV1dKSxoPWUucHVzaCgiaW5saW5lIiwiIiwwKSxoLmNvbnRlbnQ9ZltsXT9mW2xdLnRyaW0oKToiIixoLmNoaWxkcmVuPVtdLGg9ZS5wdXNoKCJ0ZF9jbG9zZSIsInRkIiwtMSk7aD1lLnB1c2goInRyX2Nsb3NlIiwidHIiLC0xKX1yZXR1cm4gaD1lLnB1c2goInRib2R5X2Nsb3NlIiwidGJvZHkiLC0xKSxoPWUucHVzaCgidGFibGVfY2xvc2UiLCJ0YWJsZSIsLTEpLHlbMV09dlsxXT1wLGUubGluZT1wLCEwfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbztpZihlLnNDb3VudFt0XS1lLmJsa0luZGVudDw0KXJldHVybiExO2ZvcihpPXI9dCsxO3I8bjspaWYoZS5pc0VtcHR5KHIpKXIrKztlbHNle2lmKCEoZS5zQ291bnRbcl0tZS5ibGtJbmRlbnQ+PTQpKWJyZWFrO3IrKyxpPXJ9cmV0dXJuIGUubGluZT1pLG89ZS5wdXNoKCJjb2RlX2Jsb2NrIiwiY29kZSIsMCksby5jb250ZW50PWUuZ2V0TGluZXModCxpLDQrZS5ibGtJbmRlbnQsITApLG8ubWFwPVt0LGUubGluZV0sITB9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbixyKXt2YXIgaSxvLGEscyx1LGMsbCxwPSExLGY9ZS5iTWFya3NbdF0rZS50U2hpZnRbdF0sZD1lLmVNYXJrc1t0XTtpZihlLnNDb3VudFt0XS1lLmJsa0luZGVudD49NClyZXR1cm4hMTtpZihmKzM+ZClyZXR1cm4hMTtpZigxMjYhPT0oaT1lLnNyYy5jaGFyQ29kZUF0KGYpKSYmOTYhPT1pKXJldHVybiExO2lmKHU9ZixmPWUuc2tpcENoYXJzKGYsaSksKG89Zi11KTwzKXJldHVybiExO2lmKGw9ZS5zcmMuc2xpY2UodSxmKSxhPWUuc3JjLnNsaWNlKGYsZCksYS5pbmRleE9mKFN0cmluZy5mcm9tQ2hhckNvZGUoaSkpPj0wKXJldHVybiExO2lmKHIpcmV0dXJuITA7Zm9yKHM9dDshKCsrcz49bikmJihmPXU9ZS5iTWFya3Nbc10rZS50U2hpZnRbc10sZD1lLmVNYXJrc1tzXSwhKGY8ZCYmZS5zQ291bnRbc108ZS5ibGtJbmRlbnQpKTspaWYoZS5zcmMuY2hhckNvZGVBdChmKT09PWkmJiEoZS5zQ291bnRbc10tZS5ibGtJbmRlbnQ+PTQpJiYhKChmPWUuc2tpcENoYXJzKGYsaSkpLXU8bykmJiEoKGY9ZS5za2lwU3BhY2VzKGYpKTxkKSl7cD0hMDticmVha31yZXR1cm4gbz1lLnNDb3VudFt0XSxlLmxpbmU9cysocD8xOjApLGM9ZS5wdXNoKCJmZW5jZSIsImNvZGUiLDApLGMuaW5mbz1hLGMuY29udGVudD1lLmdldExpbmVzKHQrMSxzLG8sITApLGMubWFya3VwPWwsYy5tYXA9W3QsZS5saW5lXSwhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0KS5pc1NwYWNlO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbixpKXt2YXIgbyxhLHMsdSxjLGwscCxmLGQsaCxtLGcseSx2LGIseCxDLEUsRCx3LFM9ZS5saW5lTWF4LGs9ZS5iTWFya3NbdF0rZS50U2hpZnRbdF0sQT1lLmVNYXJrc1t0XTtpZihlLnNDb3VudFt0XS1lLmJsa0luZGVudD49NClyZXR1cm4hMTtpZig2MiE9PWUuc3JjLmNoYXJDb2RlQXQoaysrKSlyZXR1cm4hMTtpZihpKXJldHVybiEwO2Zvcih1PWQ9ZS5zQ291bnRbdF0ray0oZS5iTWFya3NbdF0rZS50U2hpZnRbdF0pLDMyPT09ZS5zcmMuY2hhckNvZGVBdChrKT8oaysrLHUrKyxkKyssbz0hMSx4PSEwKTo5PT09ZS5zcmMuY2hhckNvZGVBdChrKT8oeD0hMCwoZS5ic0NvdW50W3RdK2QpJTQ9PT0zPyhrKyssdSsrLGQrKyxvPSExKTpvPSEwKTp4PSExLGg9W2UuYk1hcmtzW3RdXSxlLmJNYXJrc1t0XT1rO2s8QSYmKGE9ZS5zcmMuY2hhckNvZGVBdChrKSxyKGEpKTspOT09PWE/ZCs9NC0oZCtlLmJzQ291bnRbdF0rKG8/MTowKSklNDpkKyssaysrO2ZvcihtPVtlLmJzQ291bnRbdF1dLGUuYnNDb3VudFt0XT1lLnNDb3VudFt0XSsxKyh4PzE6MCksbD1rPj1BLHY9W2Uuc0NvdW50W3RdXSxlLnNDb3VudFt0XT1kLXUsYj1bZS50U2hpZnRbdF1dLGUudFNoaWZ0W3RdPWstZS5iTWFya3NbdF0sRT1lLm1kLmJsb2NrLnJ1bGVyLmdldFJ1bGVzKCJibG9ja3F1b3RlIikseT1lLnBhcmVudFR5cGUsZS5wYXJlbnRUeXBlPSJibG9ja3F1b3RlIix3PSExLGY9dCsxO2Y8biYmKGUuc0NvdW50W2ZdPGUuYmxrSW5kZW50JiYodz0hMCksaz1lLmJNYXJrc1tmXStlLnRTaGlmdFtmXSxBPWUuZU1hcmtzW2ZdLCEoaz49QSkpO2YrKylpZig2MiE9PWUuc3JjLmNoYXJDb2RlQXQoaysrKXx8dyl7aWYobClicmVhaztmb3IoQz0hMSxzPTAsYz1FLmxlbmd0aDtzPGM7cysrKWlmKEVbc10oZSxmLG4sITApKXtDPSEwO2JyZWFrfWlmKEMpe2UubGluZU1heD1mLDAhPT1lLmJsa0luZGVudCYmKGgucHVzaChlLmJNYXJrc1tmXSksbS5wdXNoKGUuYnNDb3VudFtmXSksYi5wdXNoKGUudFNoaWZ0W2ZdKSx2LnB1c2goZS5zQ291bnRbZl0pLGUuc0NvdW50W2ZdLT1lLmJsa0luZGVudCk7YnJlYWt9aC5wdXNoKGUuYk1hcmtzW2ZdKSxtLnB1c2goZS5ic0NvdW50W2ZdKSxiLnB1c2goZS50U2hpZnRbZl0pLHYucHVzaChlLnNDb3VudFtmXSksZS5zQ291bnRbZl09LTF9ZWxzZXtmb3IodT1kPWUuc0NvdW50W2ZdK2stKGUuYk1hcmtzW2ZdK2UudFNoaWZ0W2ZdKSwzMj09PWUuc3JjLmNoYXJDb2RlQXQoayk/KGsrKyx1KyssZCsrLG89ITEseD0hMCk6OT09PWUuc3JjLmNoYXJDb2RlQXQoayk/KHg9ITAsKGUuYnNDb3VudFtmXStkKSU0PT09Mz8oaysrLHUrKyxkKyssbz0hMSk6bz0hMCk6eD0hMSxoLnB1c2goZS5iTWFya3NbZl0pLGUuYk1hcmtzW2ZdPWs7azxBJiYoYT1lLnNyYy5jaGFyQ29kZUF0KGspLHIoYSkpOyk5PT09YT9kKz00LShkK2UuYnNDb3VudFtmXSsobz8xOjApKSU0OmQrKyxrKys7bD1rPj1BLG0ucHVzaChlLmJzQ291bnRbZl0pLGUuYnNDb3VudFtmXT1lLnNDb3VudFtmXSsxKyh4PzE6MCksdi5wdXNoKGUuc0NvdW50W2ZdKSxlLnNDb3VudFtmXT1kLXUsYi5wdXNoKGUudFNoaWZ0W2ZdKSxlLnRTaGlmdFtmXT1rLWUuYk1hcmtzW2ZdfWZvcihnPWUuYmxrSW5kZW50LGUuYmxrSW5kZW50PTAsRD1lLnB1c2goImJsb2NrcXVvdGVfb3BlbiIsImJsb2NrcXVvdGUiLDEpLEQubWFya3VwPSI+IixELm1hcD1wPVt0LDBdLGUubWQuYmxvY2sudG9rZW5pemUoZSx0LGYpLEQ9ZS5wdXNoKCJibG9ja3F1b3RlX2Nsb3NlIiwiYmxvY2txdW90ZSIsLTEpLEQubWFya3VwPSI+IixlLmxpbmVNYXg9UyxlLnBhcmVudFR5cGU9eSxwWzFdPWUubGluZSxzPTA7czxiLmxlbmd0aDtzKyspZS5iTWFya3Nbcyt0XT1oW3NdLGUudFNoaWZ0W3MrdF09YltzXSxlLnNDb3VudFtzK3RdPXZbc10sZS5ic0NvdW50W3MrdF09bVtzXTtyZXR1cm4gZS5ibGtJbmRlbnQ9ZywhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0KS5pc1NwYWNlO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbixpKXt2YXIgbyxhLHMsdSxjPWUuYk1hcmtzW3RdK2UudFNoaWZ0W3RdLGw9ZS5lTWFya3NbdF07aWYoZS5zQ291bnRbdF0tZS5ibGtJbmRlbnQ+PTQpcmV0dXJuITE7aWYoNDIhPT0obz1lLnNyYy5jaGFyQ29kZUF0KGMrKykpJiY0NSE9PW8mJjk1IT09bylyZXR1cm4hMTtmb3IoYT0xO2M8bDspe2lmKChzPWUuc3JjLmNoYXJDb2RlQXQoYysrKSkhPT1vJiYhcihzKSlyZXR1cm4hMTtzPT09byYmYSsrfXJldHVybiEoYTwzKSYmKCEhaXx8KGUubGluZT10KzEsdT1lLnB1c2goImhyIiwiaHIiLDApLHUubWFwPVt0LGUubGluZV0sdS5tYXJrdXA9QXJyYXkoYSsxKS5qb2luKFN0cmluZy5mcm9tQ2hhckNvZGUobykpLCEwKSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2YXIgbixyLGksbztyZXR1cm4gcj1lLmJNYXJrc1t0XStlLnRTaGlmdFt0XSxpPWUuZU1hcmtzW3RdLG49ZS5zcmMuY2hhckNvZGVBdChyKyspLDQyIT09biYmNDUhPT1uJiY0MyE9PW4/LTE6cjxpJiYobz1lLnNyYy5jaGFyQ29kZUF0KHIpLCFhKG8pKT8tMTpyfWZ1bmN0aW9uIGkoZSx0KXt2YXIgbixyPWUuYk1hcmtzW3RdK2UudFNoaWZ0W3RdLGk9cixvPWUuZU1hcmtzW3RdO2lmKGkrMT49bylyZXR1cm4tMTtpZigobj1lLnNyYy5jaGFyQ29kZUF0KGkrKykpPDQ4fHxuPjU3KXJldHVybi0xO2Zvcig7Oyl7aWYoaT49bylyZXR1cm4tMTtuPWUuc3JjLmNoYXJDb2RlQXQoaSsrKTt7aWYoIShuPj00OCYmbjw9NTcpKXtpZig0MT09PW58fDQ2PT09bilicmVhaztyZXR1cm4tMX1pZihpLXI+PTEwKXJldHVybi0xfX1yZXR1cm4gaTxvJiYobj1lLnNyYy5jaGFyQ29kZUF0KGkpLCFhKG4pKT8tMTppfWZ1bmN0aW9uIG8oZSx0KXt2YXIgbixyLGk9ZS5sZXZlbCsyO2ZvcihuPXQrMixyPWUudG9rZW5zLmxlbmd0aC0yO248cjtuKyspZS50b2tlbnNbbl0ubGV2ZWw9PT1pJiYicGFyYWdyYXBoX29wZW4iPT09ZS50b2tlbnNbbl0udHlwZSYmKGUudG9rZW5zW24rMl0uaGlkZGVuPSEwLGUudG9rZW5zW25dLmhpZGRlbj0hMCxuKz0yKX12YXIgYT1uKDQpLmlzU3BhY2U7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCxuLGEpe3ZhciBzLHUsYyxsLHAsZixkLGgsbSxnLHksdixiLHgsQyxFLEQsdyxTLGssQSxfLFQsTyxGLE4sSSxMLFA9ITEsTT0hMDtpZihlLnNDb3VudFt0XS1lLmJsa0luZGVudD49NClyZXR1cm4hMTtpZihhJiYicGFyYWdyYXBoIj09PWUucGFyZW50VHlwZSYmZS50U2hpZnRbdF0+PWUuYmxrSW5kZW50JiYoUD0hMCksKFQ9aShlLHQpKT49MCl7aWYoZD0hMCxGPWUuYk1hcmtzW3RdK2UudFNoaWZ0W3RdLGI9TnVtYmVyKGUuc3JjLnN1YnN0cihGLFQtRi0xKSksUCYmMSE9PWIpcmV0dXJuITF9ZWxzZXtpZighKChUPXIoZSx0KSk+PTApKXJldHVybiExO2Q9ITF9aWYoUCYmZS5za2lwU3BhY2VzKFQpPj1lLmVNYXJrc1t0XSlyZXR1cm4hMTtpZih2PWUuc3JjLmNoYXJDb2RlQXQoVC0xKSxhKXJldHVybiEwO2Zvcih5PWUudG9rZW5zLmxlbmd0aCxkPyhMPWUucHVzaCgib3JkZXJlZF9saXN0X29wZW4iLCJvbCIsMSksMSE9PWImJihMLmF0dHJzPVtbInN0YXJ0IixiXV0pKTpMPWUucHVzaCgiYnVsbGV0X2xpc3Rfb3BlbiIsInVsIiwxKSxMLm1hcD1nPVt0LDBdLEwubWFya3VwPVN0cmluZy5mcm9tQ2hhckNvZGUodiksQz10LE89ITEsST1lLm1kLmJsb2NrLnJ1bGVyLmdldFJ1bGVzKCJsaXN0IiksUz1lLnBhcmVudFR5cGUsZS5wYXJlbnRUeXBlPSJsaXN0IjtDPG47KXtmb3IoXz1ULHg9ZS5lTWFya3NbQ10sZj1FPWUuc0NvdW50W0NdK1QtKGUuYk1hcmtzW3RdK2UudFNoaWZ0W3RdKTtfPHg7KXtpZig5PT09KHM9ZS5zcmMuY2hhckNvZGVBdChfKSkpRSs9NC0oRStlLmJzQ291bnRbQ10pJTQ7ZWxzZXtpZigzMiE9PXMpYnJlYWs7RSsrfV8rK31pZih1PV8scD11Pj14PzE6RS1mLHA+NCYmKHA9MSksbD1mK3AsTD1lLnB1c2goImxpc3RfaXRlbV9vcGVuIiwibGkiLDEpLEwubWFya3VwPVN0cmluZy5mcm9tQ2hhckNvZGUodiksTC5tYXA9aD1bdCwwXSxEPWUuYmxrSW5kZW50LEE9ZS50aWdodCxrPWUudFNoaWZ0W3RdLHc9ZS5zQ291bnRbdF0sZS5ibGtJbmRlbnQ9bCxlLnRpZ2h0PSEwLGUudFNoaWZ0W3RdPXUtZS5iTWFya3NbdF0sZS5zQ291bnRbdF09RSx1Pj14JiZlLmlzRW1wdHkodCsxKT9lLmxpbmU9TWF0aC5taW4oZS5saW5lKzIsbik6ZS5tZC5ibG9jay50b2tlbml6ZShlLHQsbiwhMCksZS50aWdodCYmIU98fChNPSExKSxPPWUubGluZS10PjEmJmUuaXNFbXB0eShlLmxpbmUtMSksZS5ibGtJbmRlbnQ9RCxlLnRTaGlmdFt0XT1rLGUuc0NvdW50W3RdPXcsZS50aWdodD1BLEw9ZS5wdXNoKCJsaXN0X2l0ZW1fY2xvc2UiLCJsaSIsLTEpLEwubWFya3VwPVN0cmluZy5mcm9tQ2hhckNvZGUodiksQz10PWUubGluZSxoWzFdPUMsdT1lLmJNYXJrc1t0XSxDPj1uKWJyZWFrO2lmKGUuc0NvdW50W0NdPGUuYmxrSW5kZW50KWJyZWFrO2ZvcihOPSExLGM9MCxtPUkubGVuZ3RoO2M8bTtjKyspaWYoSVtjXShlLEMsbiwhMCkpe049ITA7YnJlYWt9aWYoTilicmVhaztpZihkKXtpZigoVD1pKGUsQykpPDApYnJlYWt9ZWxzZSBpZigoVD1yKGUsQykpPDApYnJlYWs7aWYodiE9PWUuc3JjLmNoYXJDb2RlQXQoVC0xKSlicmVha31yZXR1cm4gTD1kP2UucHVzaCgib3JkZXJlZF9saXN0X2Nsb3NlIiwib2wiLC0xKTplLnB1c2goImJ1bGxldF9saXN0X2Nsb3NlIiwidWwiLC0xKSxMLm1hcmt1cD1TdHJpbmcuZnJvbUNoYXJDb2RlKHYpLGdbMV09QyxlLmxpbmU9QyxlLnBhcmVudFR5cGU9UyxNJiZvKGUseSksITB9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNCkubm9ybWFsaXplUmVmZXJlbmNlLGk9big0KS5pc1NwYWNlO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbixvKXt2YXIgYSxzLHUsYyxsLHAsZixkLGgsbSxnLHksdixiLHgsQyxFPTAsRD1lLmJNYXJrc1t0XStlLnRTaGlmdFt0XSx3PWUuZU1hcmtzW3RdLFM9dCsxO2lmKGUuc0NvdW50W3RdLWUuYmxrSW5kZW50Pj00KXJldHVybiExO2lmKDkxIT09ZS5zcmMuY2hhckNvZGVBdChEKSlyZXR1cm4hMTtmb3IoOysrRDx3OylpZig5Mz09PWUuc3JjLmNoYXJDb2RlQXQoRCkmJjkyIT09ZS5zcmMuY2hhckNvZGVBdChELTEpKXtpZihEKzE9PT13KXJldHVybiExO2lmKDU4IT09ZS5zcmMuY2hhckNvZGVBdChEKzEpKXJldHVybiExO2JyZWFrfWZvcihjPWUubGluZU1heCx4PWUubWQuYmxvY2sucnVsZXIuZ2V0UnVsZXMoInJlZmVyZW5jZSIpLG09ZS5wYXJlbnRUeXBlLGUucGFyZW50VHlwZT0icmVmZXJlbmNlIjtTPGMmJiFlLmlzRW1wdHkoUyk7UysrKWlmKCEoZS5zQ291bnRbU10tZS5ibGtJbmRlbnQ+MykmJiEoZS5zQ291bnRbU108MCkpe2ZvcihiPSExLHA9MCxmPXgubGVuZ3RoO3A8ZjtwKyspaWYoeFtwXShlLFMsYywhMCkpe2I9ITA7YnJlYWt9aWYoYilicmVha31mb3Iodj1lLmdldExpbmVzKHQsUyxlLmJsa0luZGVudCwhMSkudHJpbSgpLHc9di5sZW5ndGgsRD0xO0Q8dztEKyspe2lmKDkxPT09KGE9di5jaGFyQ29kZUF0KEQpKSlyZXR1cm4hMTtpZig5Mz09PWEpe2g9RDticmVha30xMD09PWE/RSsrOjkyPT09YSYmKytEPHcmJjEwPT09di5jaGFyQ29kZUF0KEQpJiZFKyt9aWYoaDwwfHw1OCE9PXYuY2hhckNvZGVBdChoKzEpKXJldHVybiExO2ZvcihEPWgrMjtEPHc7RCsrKWlmKDEwPT09KGE9di5jaGFyQ29kZUF0KEQpKSlFKys7ZWxzZSBpZighaShhKSlicmVhaztpZihnPWUubWQuaGVscGVycy5wYXJzZUxpbmtEZXN0aW5hdGlvbih2LEQsdyksIWcub2spcmV0dXJuITE7aWYobD1lLm1kLm5vcm1hbGl6ZUxpbmsoZy5zdHIpLCFlLm1kLnZhbGlkYXRlTGluayhsKSlyZXR1cm4hMTtmb3IoRD1nLnBvcyxFKz1nLmxpbmVzLHM9RCx1PUUseT1EO0Q8dztEKyspaWYoMTA9PT0oYT12LmNoYXJDb2RlQXQoRCkpKUUrKztlbHNlIGlmKCFpKGEpKWJyZWFrO2ZvcihnPWUubWQuaGVscGVycy5wYXJzZUxpbmtUaXRsZSh2LEQsdyksRDx3JiZ5IT09RCYmZy5vaz8oQz1nLnN0cixEPWcucG9zLEUrPWcubGluZXMpOihDPSIiLEQ9cyxFPXUpO0Q8dyYmKGE9di5jaGFyQ29kZUF0KEQpLGkoYSkpOylEKys7aWYoRDx3JiYxMCE9PXYuY2hhckNvZGVBdChEKSYmQylmb3IoQz0iIixEPXMsRT11O0Q8dyYmKGE9di5jaGFyQ29kZUF0KEQpLGkoYSkpOylEKys7cmV0dXJuIShEPHcmJjEwIT09di5jaGFyQ29kZUF0KEQpKSYmKCEhKGQ9cih2LnNsaWNlKDEsaCkpKSYmKCEhb3x8KCJ1bmRlZmluZWQiPT09dHlwZW9mIGUuZW52LnJlZmVyZW5jZXMmJihlLmVudi5yZWZlcmVuY2VzPXt9KSwidW5kZWZpbmVkIj09PXR5cGVvZiBlLmVudi5yZWZlcmVuY2VzW2RdJiYoZS5lbnYucmVmZXJlbmNlc1tkXT17dGl0bGU6QyxocmVmOmx9KSxlLnBhcmVudFR5cGU9bSxlLmxpbmU9dCtFKzEsITApKSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNCkuaXNTcGFjZTtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0LG4saSl7dmFyIG8sYSxzLHUsYz1lLmJNYXJrc1t0XStlLnRTaGlmdFt0XSxsPWUuZU1hcmtzW3RdO2lmKGUuc0NvdW50W3RdLWUuYmxrSW5kZW50Pj00KXJldHVybiExO2lmKDM1IT09KG89ZS5zcmMuY2hhckNvZGVBdChjKSl8fGM+PWwpcmV0dXJuITE7Zm9yKGE9MSxvPWUuc3JjLmNoYXJDb2RlQXQoKytjKTszNT09PW8mJmM8bCYmYTw9NjspYSsrLG89ZS5zcmMuY2hhckNvZGVBdCgrK2MpO3JldHVybiEoYT42fHxjPGwmJiFyKG8pKSYmKCEhaXx8KGw9ZS5za2lwU3BhY2VzQmFjayhsLGMpLHM9ZS5za2lwQ2hhcnNCYWNrKGwsMzUsYykscz5jJiZyKGUuc3JjLmNoYXJDb2RlQXQocy0xKSkmJihsPXMpLGUubGluZT10KzEsdT1lLnB1c2goImhlYWRpbmdfb3BlbiIsImgiK1N0cmluZyhhKSwxKSx1Lm1hcmt1cD0iIyMjIyMjIyMiLnNsaWNlKDAsYSksdS5tYXA9W3QsZS5saW5lXSx1PWUucHVzaCgiaW5saW5lIiwiIiwwKSx1LmNvbnRlbnQ9ZS5zcmMuc2xpY2UoYyxsKS50cmltKCksdS5tYXA9W3QsZS5saW5lXSx1LmNoaWxkcmVuPVtdLHU9ZS5wdXNoKCJoZWFkaW5nX2Nsb3NlIiwiaCIrU3RyaW5nKGEpLC0xKSx1Lm1hcmt1cD0iIyMjIyMjIyMiLnNsaWNlKDAsYSksITApKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpLG8sYSxzLHUsYyxsLHAsZixkPXQrMSxoPWUubWQuYmxvY2sucnVsZXIuZ2V0UnVsZXMoInBhcmFncmFwaCIpO2lmKGUuc0NvdW50W3RdLWUuYmxrSW5kZW50Pj00KXJldHVybiExO2ZvcihmPWUucGFyZW50VHlwZSxlLnBhcmVudFR5cGU9InBhcmFncmFwaCI7ZDxuJiYhZS5pc0VtcHR5KGQpO2QrKylpZighKGUuc0NvdW50W2RdLWUuYmxrSW5kZW50PjMpKXtpZihlLnNDb3VudFtkXT49ZS5ibGtJbmRlbnQmJih1PWUuYk1hcmtzW2RdK2UudFNoaWZ0W2RdLGM9ZS5lTWFya3NbZF0sdTxjJiYoNDU9PT0ocD1lLnNyYy5jaGFyQ29kZUF0KHUpKXx8NjE9PT1wKSYmKHU9ZS5za2lwQ2hhcnModSxwKSwodT1lLnNraXBTcGFjZXModSkpPj1jKSkpe2w9NjE9PT1wPzE6MjticmVha31pZighKGUuc0NvdW50W2RdPDApKXtmb3IoaT0hMSxvPTAsYT1oLmxlbmd0aDtvPGE7bysrKWlmKGhbb10oZSxkLG4sITApKXtpPSEwO2JyZWFrfWlmKGkpYnJlYWt9fXJldHVybiEhbCYmKHI9ZS5nZXRMaW5lcyh0LGQsZS5ibGtJbmRlbnQsITEpLnRyaW0oKSxlLmxpbmU9ZCsxLHM9ZS5wdXNoKCJoZWFkaW5nX29wZW4iLCJoIitTdHJpbmcobCksMSkscy5tYXJrdXA9U3RyaW5nLmZyb21DaGFyQ29kZShwKSxzLm1hcD1bdCxlLmxpbmVdLHM9ZS5wdXNoKCJpbmxpbmUiLCIiLDApLHMuY29udGVudD1yLHMubWFwPVt0LGUubGluZS0xXSxzLmNoaWxkcmVuPVtdLHM9ZS5wdXNoKCJoZWFkaW5nX2Nsb3NlIiwiaCIrU3RyaW5nKGwpLC0xKSxzLm1hcmt1cD1TdHJpbmcuZnJvbUNoYXJDb2RlKHApLGUucGFyZW50VHlwZT1mLCEwKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big1NzIpLGk9bigyNjQpLkhUTUxfT1BFTl9DTE9TRV9UQUdfUkUsbz1bWy9ePChzY3JpcHR8cHJlfHN0eWxlKSg/PShcc3w+fCQpKS9pLC88XC8oc2NyaXB0fHByZXxzdHlsZSk+L2ksITBdLFsvXjwhLS0vLC8tLT4vLCEwXSxbL148XD8vLC9cPz4vLCEwXSxbL148IVtBLVpdLywvPi8sITBdLFsvXjwhXFtDREFUQVxbLywvXF1cXT4vLCEwXSxbbmV3IFJlZ0V4cCgiXjwvPygiK3Iuam9pbigifCIpKyIpKD89KFxcc3wvPz58JCkpIiwiaSIpLC9eJC8sITBdLFtuZXcgUmVnRXhwKGkuc291cmNlKyJcXHMqJCIpLC9eJC8sITFdXTtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0LG4scil7dmFyIGksYSxzLHUsYz1lLmJNYXJrc1t0XStlLnRTaGlmdFt0XSxsPWUuZU1hcmtzW3RdO2lmKGUuc0NvdW50W3RdLWUuYmxrSW5kZW50Pj00KXJldHVybiExO2lmKCFlLm1kLm9wdGlvbnMuaHRtbClyZXR1cm4hMTtpZig2MCE9PWUuc3JjLmNoYXJDb2RlQXQoYykpcmV0dXJuITE7Zm9yKHU9ZS5zcmMuc2xpY2UoYyxsKSxpPTA7aTxvLmxlbmd0aCYmIW9baV1bMF0udGVzdCh1KTtpKyspO2lmKGk9PT1vLmxlbmd0aClyZXR1cm4hMTtpZihyKXJldHVybiBvW2ldWzJdO2lmKGE9dCsxLCFvW2ldWzFdLnRlc3QodSkpZm9yKDthPG4mJiEoZS5zQ291bnRbYV08ZS5ibGtJbmRlbnQpO2ErKylpZihjPWUuYk1hcmtzW2FdK2UudFNoaWZ0W2FdLGw9ZS5lTWFya3NbYV0sdT1lLnNyYy5zbGljZShjLGwpLG9baV1bMV0udGVzdCh1KSl7MCE9PXUubGVuZ3RoJiZhKys7YnJlYWt9cmV0dXJuIGUubGluZT1hLHM9ZS5wdXNoKCJodG1sX2Jsb2NrIiwiIiwwKSxzLm1hcD1bdCxhXSxzLmNvbnRlbnQ9ZS5nZXRMaW5lcyh0LGEsZS5ibGtJbmRlbnQsITApLCEwfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9WyJhZGRyZXNzIiwiYXJ0aWNsZSIsImFzaWRlIiwiYmFzZSIsImJhc2Vmb250IiwiYmxvY2txdW90ZSIsImJvZHkiLCJjYXB0aW9uIiwiY2VudGVyIiwiY29sIiwiY29sZ3JvdXAiLCJkZCIsImRldGFpbHMiLCJkaWFsb2ciLCJkaXIiLCJkaXYiLCJkbCIsImR0IiwiZmllbGRzZXQiLCJmaWdjYXB0aW9uIiwiZmlndXJlIiwiZm9vdGVyIiwiZm9ybSIsImZyYW1lIiwiZnJhbWVzZXQiLCJoMSIsImgyIiwiaDMiLCJoNCIsImg1IiwiaDYiLCJoZWFkIiwiaGVhZGVyIiwiaHIiLCJodG1sIiwiaWZyYW1lIiwibGVnZW5kIiwibGkiLCJsaW5rIiwibWFpbiIsIm1lbnUiLCJtZW51aXRlbSIsIm1ldGEiLCJuYXYiLCJub2ZyYW1lcyIsIm9sIiwib3B0Z3JvdXAiLCJvcHRpb24iLCJwIiwicGFyYW0iLCJzZWN0aW9uIiwic291cmNlIiwic3VtbWFyeSIsInRhYmxlIiwidGJvZHkiLCJ0ZCIsInRmb290IiwidGgiLCJ0aGVhZCIsInRpdGxlIiwidHIiLCJ0cmFjayIsInVsIl19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCl7dmFyIG4scixpLG8sYSxzLHU9dCsxLGM9ZS5tZC5ibG9jay5ydWxlci5nZXRSdWxlcygicGFyYWdyYXBoIiksbD1lLmxpbmVNYXg7Zm9yKHM9ZS5wYXJlbnRUeXBlLGUucGFyZW50VHlwZT0icGFyYWdyYXBoIjt1PGwmJiFlLmlzRW1wdHkodSk7dSsrKWlmKCEoZS5zQ291bnRbdV0tZS5ibGtJbmRlbnQ+MykmJiEoZS5zQ291bnRbdV08MCkpe2ZvcihyPSExLGk9MCxvPWMubGVuZ3RoO2k8bztpKyspaWYoY1tpXShlLHUsbCwhMCkpe3I9ITA7YnJlYWt9aWYocilicmVha31yZXR1cm4gbj1lLmdldExpbmVzKHQsdSxlLmJsa0luZGVudCwhMSkudHJpbSgpLGUubGluZT11LGE9ZS5wdXNoKCJwYXJhZ3JhcGhfb3BlbiIsInAiLDEpLGEubWFwPVt0LGUubGluZV0sYT1lLnB1c2goImlubGluZSIsIiIsMCksYS5jb250ZW50PW4sYS5tYXA9W3QsZS5saW5lXSxhLmNoaWxkcmVuPVtdLGE9ZS5wdXNoKCJwYXJhZ3JhcGhfY2xvc2UiLCJwIiwtMSksZS5wYXJlbnRUeXBlPXMsITB9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4scil7dmFyIGksYSxzLHUsYyxsLHAsZjtmb3IodGhpcy5zcmM9ZSx0aGlzLm1kPXQsdGhpcy5lbnY9bix0aGlzLnRva2Vucz1yLHRoaXMuYk1hcmtzPVtdLHRoaXMuZU1hcmtzPVtdLHRoaXMudFNoaWZ0PVtdLHRoaXMuc0NvdW50PVtdLHRoaXMuYnNDb3VudD1bXSx0aGlzLmJsa0luZGVudD0wLHRoaXMubGluZT0wLHRoaXMubGluZU1heD0wLHRoaXMudGlnaHQ9ITEsdGhpcy5kZEluZGVudD0tMSx0aGlzLnBhcmVudFR5cGU9InJvb3QiLHRoaXMubGV2ZWw9MCx0aGlzLnJlc3VsdD0iIixhPXRoaXMuc3JjLGY9ITEscz11PWw9cD0wLGM9YS5sZW5ndGg7dTxjO3UrKyl7aWYoaT1hLmNoYXJDb2RlQXQodSksIWYpe2lmKG8oaSkpe2wrKyw5PT09aT9wKz00LXAlNDpwKys7Y29udGludWV9Zj0hMH0xMCE9PWkmJnUhPT1jLTF8fCgxMCE9PWkmJnUrKyx0aGlzLmJNYXJrcy5wdXNoKHMpLHRoaXMuZU1hcmtzLnB1c2godSksdGhpcy50U2hpZnQucHVzaChsKSx0aGlzLnNDb3VudC5wdXNoKHApLHRoaXMuYnNDb3VudC5wdXNoKDApLGY9ITEsbD0wLHA9MCxzPXUrMSl9dGhpcy5iTWFya3MucHVzaChhLmxlbmd0aCksdGhpcy5lTWFya3MucHVzaChhLmxlbmd0aCksdGhpcy50U2hpZnQucHVzaCgwKSx0aGlzLnNDb3VudC5wdXNoKDApLHRoaXMuYnNDb3VudC5wdXNoKDApLHRoaXMubGluZU1heD10aGlzLmJNYXJrcy5sZW5ndGgtMX12YXIgaT1uKDEzNSksbz1uKDQpLmlzU3BhY2U7ci5wcm90b3R5cGUucHVzaD1mdW5jdGlvbihlLHQsbil7dmFyIHI9bmV3IGkoZSx0LG4pO3JldHVybiByLmJsb2NrPSEwLG48MCYmdGhpcy5sZXZlbC0tLHIubGV2ZWw9dGhpcy5sZXZlbCxuPjAmJnRoaXMubGV2ZWwrKyx0aGlzLnRva2Vucy5wdXNoKHIpLHJ9LHIucHJvdG90eXBlLmlzRW1wdHk9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuYk1hcmtzW2VdK3RoaXMudFNoaWZ0W2VdPj10aGlzLmVNYXJrc1tlXX0sci5wcm90b3R5cGUuc2tpcEVtcHR5TGluZXM9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PXRoaXMubGluZU1heDtlPHQmJiEodGhpcy5iTWFya3NbZV0rdGhpcy50U2hpZnRbZV08dGhpcy5lTWFya3NbZV0pO2UrKyk7cmV0dXJuIGV9LHIucHJvdG90eXBlLnNraXBTcGFjZXM9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0LG49dGhpcy5zcmMubGVuZ3RoO2U8biYmKHQ9dGhpcy5zcmMuY2hhckNvZGVBdChlKSxvKHQpKTtlKyspO3JldHVybiBlfSxyLnByb3RvdHlwZS5za2lwU3BhY2VzQmFjaz1mdW5jdGlvbihlLHQpe2lmKGU8PXQpcmV0dXJuIGU7Zm9yKDtlPnQ7KWlmKCFvKHRoaXMuc3JjLmNoYXJDb2RlQXQoLS1lKSkpcmV0dXJuIGUrMTtyZXR1cm4gZX0sci5wcm90b3R5cGUuc2tpcENoYXJzPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPXRoaXMuc3JjLmxlbmd0aDtlPG4mJnRoaXMuc3JjLmNoYXJDb2RlQXQoZSk9PT10O2UrKyk7cmV0dXJuIGV9LHIucHJvdG90eXBlLnNraXBDaGFyc0JhY2s9ZnVuY3Rpb24oZSx0LG4pe2lmKGU8PW4pcmV0dXJuIGU7Zm9yKDtlPm47KWlmKHQhPT10aGlzLnNyYy5jaGFyQ29kZUF0KC0tZSkpcmV0dXJuIGUrMTtyZXR1cm4gZX0sci5wcm90b3R5cGUuZ2V0TGluZXM9ZnVuY3Rpb24oZSx0LG4scil7dmFyIGksYSxzLHUsYyxsLHAsZj1lO2lmKGU+PXQpcmV0dXJuIiI7Zm9yKGw9bmV3IEFycmF5KHQtZSksaT0wO2Y8dDtmKyssaSsrKXtmb3IoYT0wLHA9dT10aGlzLmJNYXJrc1tmXSxjPWYrMTx0fHxyP3RoaXMuZU1hcmtzW2ZdKzE6dGhpcy5lTWFya3NbZl07dTxjJiZhPG47KXtpZihzPXRoaXMuc3JjLmNoYXJDb2RlQXQodSksbyhzKSk5PT09cz9hKz00LShhK3RoaXMuYnNDb3VudFtmXSklNDphKys7ZWxzZXtpZighKHUtcDx0aGlzLnRTaGlmdFtmXSkpYnJlYWs7YSsrfXUrK31sW2ldPWE+bj9uZXcgQXJyYXkoYS1uKzEpLmpvaW4oIiAiKSt0aGlzLnNyYy5zbGljZSh1LGMpOnRoaXMuc3JjLnNsaWNlKHUsYyl9cmV0dXJuIGwuam9pbigiIil9LHIucHJvdG90eXBlLlRva2VuPWksZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3ZhciBlO2Zvcih0aGlzLnJ1bGVyPW5ldyBpLGU9MDtlPG8ubGVuZ3RoO2UrKyl0aGlzLnJ1bGVyLnB1c2gob1tlXVswXSxvW2VdWzFdKTtmb3IodGhpcy5ydWxlcjI9bmV3IGksZT0wO2U8YS5sZW5ndGg7ZSsrKXRoaXMucnVsZXIyLnB1c2goYVtlXVswXSxhW2VdWzFdKX12YXIgaT1uKDEzNCksbz1bWyJ0ZXh0IixuKDU3NildLFsibmV3bGluZSIsbig1NzcpXSxbImVzY2FwZSIsbig1NzgpXSxbImJhY2t0aWNrcyIsbig1NzkpXSxbInN0cmlrZXRocm91Z2giLG4oMjY1KS50b2tlbml6ZV0sWyJlbXBoYXNpcyIsbigyNjYpLnRva2VuaXplXSxbImxpbmsiLG4oNTgwKV0sWyJpbWFnZSIsbig1ODEpXSxbImF1dG9saW5rIixuKDU4MildLFsiaHRtbF9pbmxpbmUiLG4oNTgzKV0sWyJlbnRpdHkiLG4oNTg0KV1dLGE9W1siYmFsYW5jZV9wYWlycyIsbig1ODUpXSxbInN0cmlrZXRocm91Z2giLG4oMjY1KS5wb3N0UHJvY2Vzc10sWyJlbXBoYXNpcyIsbigyNjYpLnBvc3RQcm9jZXNzXSxbInRleHRfY29sbGFwc2UiLG4oNTg2KV1dO3IucHJvdG90eXBlLnNraXBUb2tlbj1mdW5jdGlvbihlKXt2YXIgdCxuLHI9ZS5wb3MsaT10aGlzLnJ1bGVyLmdldFJ1bGVzKCIiKSxvPWkubGVuZ3RoLGE9ZS5tZC5vcHRpb25zLm1heE5lc3Rpbmcscz1lLmNhY2hlO2lmKCJ1bmRlZmluZWQiIT09dHlwZW9mIHNbcl0pcmV0dXJuIHZvaWQoZS5wb3M9c1tyXSk7aWYoZS5sZXZlbDxhKWZvcihuPTA7bjxvJiYoZS5sZXZlbCsrLHQ9aVtuXShlLCEwKSxlLmxldmVsLS0sIXQpO24rKyk7ZWxzZSBlLnBvcz1lLnBvc01heDt0fHxlLnBvcysrLHNbcl09ZS5wb3N9LHIucHJvdG90eXBlLnRva2VuaXplPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuLHI9dGhpcy5ydWxlci5nZXRSdWxlcygiIiksaT1yLmxlbmd0aCxvPWUucG9zTWF4LGE9ZS5tZC5vcHRpb25zLm1heE5lc3Rpbmc7ZS5wb3M8bzspe2lmKGUubGV2ZWw8YSlmb3Iobj0wO248aSYmISh0PXJbbl0oZSwhMSkpO24rKyk7aWYodCl7aWYoZS5wb3M+PW8pYnJlYWt9ZWxzZSBlLnBlbmRpbmcrPWUuc3JjW2UucG9zKytdfWUucGVuZGluZyYmZS5wdXNoUGVuZGluZygpfSxyLnByb3RvdHlwZS5wYXJzZT1mdW5jdGlvbihlLHQsbixyKXt2YXIgaSxvLGEscz1uZXcgdGhpcy5TdGF0ZShlLHQsbixyKTtmb3IodGhpcy50b2tlbml6ZShzKSxvPXRoaXMucnVsZXIyLmdldFJ1bGVzKCIiKSxhPW8ubGVuZ3RoLGk9MDtpPGE7aSsrKW9baV0ocyl9LHIucHJvdG90eXBlLlN0YXRlPW4oNTg3KSxlLmV4cG9ydHM9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3N3aXRjaChlKXtjYXNlIDEwOmNhc2UgMzM6Y2FzZSAzNTpjYXNlIDM2OmNhc2UgMzc6Y2FzZSAzODpjYXNlIDQyOmNhc2UgNDM6Y2FzZSA0NTpjYXNlIDU4OmNhc2UgNjA6Y2FzZSA2MTpjYXNlIDYyOmNhc2UgNjQ6Y2FzZSA5MTpjYXNlIDkyOmNhc2UgOTM6Y2FzZSA5NDpjYXNlIDk1OmNhc2UgOTY6Y2FzZSAxMjM6Y2FzZSAxMjU6Y2FzZSAxMjY6cmV0dXJuITA7ZGVmYXVsdDpyZXR1cm4hMX19ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuPWUucG9zO248ZS5wb3NNYXgmJiFyKGUuc3JjLmNoYXJDb2RlQXQobikpOyluKys7cmV0dXJuIG4hPT1lLnBvcyYmKHR8fChlLnBlbmRpbmcrPWUuc3JjLnNsaWNlKGUucG9zLG4pKSxlLnBvcz1uLCEwKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0KS5pc1NwYWNlO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQpe3ZhciBuLGksbz1lLnBvcztpZigxMCE9PWUuc3JjLmNoYXJDb2RlQXQobykpcmV0dXJuITE7Zm9yKG49ZS5wZW5kaW5nLmxlbmd0aC0xLGk9ZS5wb3NNYXgsdHx8KG4+PTAmJjMyPT09ZS5wZW5kaW5nLmNoYXJDb2RlQXQobik/bj49MSYmMzI9PT1lLnBlbmRpbmcuY2hhckNvZGVBdChuLTEpPyhlLnBlbmRpbmc9ZS5wZW5kaW5nLnJlcGxhY2UoLyArJC8sIiIpLGUucHVzaCgiaGFyZGJyZWFrIiwiYnIiLDApKTooZS5wZW5kaW5nPWUucGVuZGluZy5zbGljZSgwLC0xKSxlLnB1c2goInNvZnRicmVhayIsImJyIiwwKSk6ZS5wdXNoKCJzb2Z0YnJlYWsiLCJiciIsMCkpLG8rKztvPGkmJnIoZS5zcmMuY2hhckNvZGVBdChvKSk7KW8rKztyZXR1cm4gZS5wb3M9bywhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7Zm9yKHZhciByPW4oNCkuaXNTcGFjZSxpPVtdLG89MDtvPDI1NjtvKyspaS5wdXNoKDApOyJcXCFcIiMkJSYnKCkqKywuLzo7PD0+P0BbXV5fYHt8fX4tIi5zcGxpdCgiIikuZm9yRWFjaChmdW5jdGlvbihlKXtpW2UuY2hhckNvZGVBdCgwKV09MX0pLGUuZXhwb3J0cz1mdW5jdGlvbihlLHQpe3ZhciBuLG89ZS5wb3MsYT1lLnBvc01heDtpZig5MiE9PWUuc3JjLmNoYXJDb2RlQXQobykpcmV0dXJuITE7aWYoKytvPGEpe2lmKChuPWUuc3JjLmNoYXJDb2RlQXQobykpPDI1NiYmMCE9PWlbbl0pcmV0dXJuIHR8fChlLnBlbmRpbmcrPWUuc3JjW29dKSxlLnBvcys9MiwhMDtpZigxMD09PW4pe2Zvcih0fHxlLnB1c2goImhhcmRicmVhayIsImJyIiwwKSxvKys7bzxhJiYobj1lLnNyYy5jaGFyQ29kZUF0KG8pLHIobikpOylvKys7cmV0dXJuIGUucG9zPW8sITB9fXJldHVybiB0fHwoZS5wZW5kaW5nKz0iXFwiKSxlLnBvcysrLCEwfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0KXt2YXIgbixyLGksbyxhLHMsdT1lLnBvcztpZig5NiE9PWUuc3JjLmNoYXJDb2RlQXQodSkpcmV0dXJuITE7Zm9yKG49dSx1Kysscj1lLnBvc01heDt1PHImJjk2PT09ZS5zcmMuY2hhckNvZGVBdCh1KTspdSsrO2ZvcihpPWUuc3JjLnNsaWNlKG4sdSksbz1hPXU7LTEhPT0obz1lLnNyYy5pbmRleE9mKCJgIixhKSk7KXtmb3IoYT1vKzE7YTxyJiY5Nj09PWUuc3JjLmNoYXJDb2RlQXQoYSk7KWErKztpZihhLW89PT1pLmxlbmd0aClyZXR1cm4gdHx8KHM9ZS5wdXNoKCJjb2RlX2lubGluZSIsImNvZGUiLDApLHMubWFya3VwPWkscy5jb250ZW50PWUuc3JjLnNsaWNlKHUsbykucmVwbGFjZSgvWyBcbl0rL2csIiAiKS50cmltKCkpLGUucG9zPWEsITB9cmV0dXJuIHR8fChlLnBlbmRpbmcrPWkpLGUucG9zKz1pLmxlbmd0aCwhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0KS5ub3JtYWxpemVSZWZlcmVuY2UsaT1uKDQpLmlzU3BhY2U7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCl7dmFyIG4sbyxhLHMsdSxjLGwscCxmLGQsaD0iIixtPWUucG9zLGc9ZS5wb3NNYXgseT1lLnBvcyx2PSEwO2lmKDkxIT09ZS5zcmMuY2hhckNvZGVBdChlLnBvcykpcmV0dXJuITE7aWYodT1lLnBvcysxLChzPWUubWQuaGVscGVycy5wYXJzZUxpbmtMYWJlbChlLGUucG9zLCEwKSk8MClyZXR1cm4hMTtpZigoYz1zKzEpPGcmJjQwPT09ZS5zcmMuY2hhckNvZGVBdChjKSl7Zm9yKHY9ITEsYysrO2M8ZyYmKG89ZS5zcmMuY2hhckNvZGVBdChjKSxpKG8pfHwxMD09PW8pO2MrKyk7aWYoYz49ZylyZXR1cm4hMTtmb3IoeT1jLGw9ZS5tZC5oZWxwZXJzLnBhcnNlTGlua0Rlc3RpbmF0aW9uKGUuc3JjLGMsZS5wb3NNYXgpLGwub2smJihoPWUubWQubm9ybWFsaXplTGluayhsLnN0ciksZS5tZC52YWxpZGF0ZUxpbmsoaCk/Yz1sLnBvczpoPSIiKSx5PWM7YzxnJiYobz1lLnNyYy5jaGFyQ29kZUF0KGMpLGkobyl8fDEwPT09byk7YysrKTtpZihsPWUubWQuaGVscGVycy5wYXJzZUxpbmtUaXRsZShlLnNyYyxjLGUucG9zTWF4KSxjPGcmJnkhPT1jJiZsLm9rKWZvcihmPWwuc3RyLGM9bC5wb3M7YzxnJiYobz1lLnNyYy5jaGFyQ29kZUF0KGMpLGkobyl8fDEwPT09byk7YysrKTtlbHNlIGY9IiI7KGM+PWd8fDQxIT09ZS5zcmMuY2hhckNvZGVBdChjKSkmJih2PSEwKSxjKyt9aWYodil7aWYoInVuZGVmaW5lZCI9PT10eXBlb2YgZS5lbnYucmVmZXJlbmNlcylyZXR1cm4hMTtpZihjPGcmJjkxPT09ZS5zcmMuY2hhckNvZGVBdChjKT8oeT1jKzEsYz1lLm1kLmhlbHBlcnMucGFyc2VMaW5rTGFiZWwoZSxjKSxjPj0wP2E9ZS5zcmMuc2xpY2UoeSxjKyspOmM9cysxKTpjPXMrMSxhfHwoYT1lLnNyYy5zbGljZSh1LHMpKSwhKHA9ZS5lbnYucmVmZXJlbmNlc1tyKGEpXSkpcmV0dXJuIGUucG9zPW0sITE7aD1wLmhyZWYsZj1wLnRpdGxlfXJldHVybiB0fHwoZS5wb3M9dSxlLnBvc01heD1zLGQ9ZS5wdXNoKCJsaW5rX29wZW4iLCJhIiwxKSxkLmF0dHJzPW49W1siaHJlZiIsaF1dLGYmJm4ucHVzaChbInRpdGxlIixmXSksZS5tZC5pbmxpbmUudG9rZW5pemUoZSksZD1lLnB1c2goImxpbmtfY2xvc2UiLCJhIiwtMSkpLGUucG9zPWMsZS5wb3NNYXg9ZywhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9big0KS5ub3JtYWxpemVSZWZlcmVuY2UsaT1uKDQpLmlzU3BhY2U7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCl7dmFyIG4sbyxhLHMsdSxjLGwscCxmLGQsaCxtLGcseT0iIix2PWUucG9zLGI9ZS5wb3NNYXg7aWYoMzMhPT1lLnNyYy5jaGFyQ29kZUF0KGUucG9zKSlyZXR1cm4hMTtpZig5MSE9PWUuc3JjLmNoYXJDb2RlQXQoZS5wb3MrMSkpcmV0dXJuITE7aWYoYz1lLnBvcysyLCh1PWUubWQuaGVscGVycy5wYXJzZUxpbmtMYWJlbChlLGUucG9zKzEsITEpKTwwKXJldHVybiExO2lmKChsPXUrMSk8YiYmNDA9PT1lLnNyYy5jaGFyQ29kZUF0KGwpKXtmb3IobCsrO2w8YiYmKG89ZS5zcmMuY2hhckNvZGVBdChsKSxpKG8pfHwxMD09PW8pO2wrKyk7aWYobD49YilyZXR1cm4hMTtmb3IoZz1sLGY9ZS5tZC5oZWxwZXJzLnBhcnNlTGlua0Rlc3RpbmF0aW9uKGUuc3JjLGwsZS5wb3NNYXgpLGYub2smJih5PWUubWQubm9ybWFsaXplTGluayhmLnN0ciksZS5tZC52YWxpZGF0ZUxpbmsoeSk/bD1mLnBvczp5PSIiKSxnPWw7bDxiJiYobz1lLnNyYy5jaGFyQ29kZUF0KGwpLGkobyl8fDEwPT09byk7bCsrKTtpZihmPWUubWQuaGVscGVycy5wYXJzZUxpbmtUaXRsZShlLnNyYyxsLGUucG9zTWF4KSxsPGImJmchPT1sJiZmLm9rKWZvcihkPWYuc3RyLGw9Zi5wb3M7bDxiJiYobz1lLnNyYy5jaGFyQ29kZUF0KGwpLGkobyl8fDEwPT09byk7bCsrKTtlbHNlIGQ9IiI7aWYobD49Ynx8NDEhPT1lLnNyYy5jaGFyQ29kZUF0KGwpKXJldHVybiBlLnBvcz12LCExO2wrK31lbHNle2lmKCJ1bmRlZmluZWQiPT09dHlwZW9mIGUuZW52LnJlZmVyZW5jZXMpcmV0dXJuITE7aWYobDxiJiY5MT09PWUuc3JjLmNoYXJDb2RlQXQobCk/KGc9bCsxLGw9ZS5tZC5oZWxwZXJzLnBhcnNlTGlua0xhYmVsKGUsbCksbD49MD9zPWUuc3JjLnNsaWNlKGcsbCsrKTpsPXUrMSk6bD11KzEsc3x8KHM9ZS5zcmMuc2xpY2UoYyx1KSksIShwPWUuZW52LnJlZmVyZW5jZXNbcihzKV0pKXJldHVybiBlLnBvcz12LCExO3k9cC5ocmVmLGQ9cC50aXRsZX1yZXR1cm4gdHx8KGE9ZS5zcmMuc2xpY2UoYyx1KSxlLm1kLmlubGluZS5wYXJzZShhLGUubWQsZS5lbnYsbT1bXSksaD1lLnB1c2goImltYWdlIiwiaW1nIiwwKSxoLmF0dHJzPW49W1sic3JjIix5XSxbImFsdCIsIiJdXSxoLmNoaWxkcmVuPW0saC5jb250ZW50PWEsZCYmbi5wdXNoKFsidGl0bGUiLGRdKSksZS5wb3M9bCxlLnBvc01heD1iLCEwfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj0vXjwoW2EtekEtWjAtOS4hIyQlJicqK1wvPT9eX2B7fH1+LV0rQFthLXpBLVowLTldKD86W2EtekEtWjAtOS1dezAsNjF9W2EtekEtWjAtOV0pPyg/OlwuW2EtekEtWjAtOV0oPzpbYS16QS1aMC05LV17MCw2MX1bYS16QS1aMC05XSk/KSopPi8saT0vXjwoW2EtekEtWl1bYS16QS1aMC05Ky5cLV17MSwzMX0pOihbXjw+XHgwMC1ceDIwXSopPi87ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCl7dmFyIG4sbyxhLHMsdSxjLGw9ZS5wb3M7cmV0dXJuIDYwPT09ZS5zcmMuY2hhckNvZGVBdChsKSYmKG49ZS5zcmMuc2xpY2UobCksIShuLmluZGV4T2YoIj4iKTwwKSYmKGkudGVzdChuKT8obz1uLm1hdGNoKGkpLHM9b1swXS5zbGljZSgxLC0xKSx1PWUubWQubm9ybWFsaXplTGluayhzKSwhIWUubWQudmFsaWRhdGVMaW5rKHUpJiYodHx8KGM9ZS5wdXNoKCJsaW5rX29wZW4iLCJhIiwxKSxjLmF0dHJzPVtbImhyZWYiLHVdXSxjLm1hcmt1cD0iYXV0b2xpbmsiLGMuaW5mbz0iYXV0byIsYz1lLnB1c2goInRleHQiLCIiLDApLGMuY29udGVudD1lLm1kLm5vcm1hbGl6ZUxpbmtUZXh0KHMpLGM9ZS5wdXNoKCJsaW5rX2Nsb3NlIiwiYSIsLTEpLGMubWFya3VwPSJhdXRvbGluayIsYy5pbmZvPSJhdXRvIiksZS5wb3MrPW9bMF0ubGVuZ3RoLCEwKSk6ISFyLnRlc3QobikmJihhPW4ubWF0Y2gocikscz1hWzBdLnNsaWNlKDEsLTEpLHU9ZS5tZC5ub3JtYWxpemVMaW5rKCJtYWlsdG86IitzKSwhIWUubWQudmFsaWRhdGVMaW5rKHUpJiYodHx8KGM9ZS5wdXNoKCJsaW5rX29wZW4iLCJhIiwxKSxjLmF0dHJzPVtbImhyZWYiLHVdXSxjLm1hcmt1cD0iYXV0b2xpbmsiLGMuaW5mbz0iYXV0byIsYz1lLnB1c2goInRleHQiLCIiLDApLGMuY29udGVudD1lLm1kLm5vcm1hbGl6ZUxpbmtUZXh0KHMpLGM9ZS5wdXNoKCJsaW5rX2Nsb3NlIiwiYSIsLTEpLGMubWFya3VwPSJhdXRvbGluayIsYy5pbmZvPSJhdXRvIiksZS5wb3MrPWFbMF0ubGVuZ3RoLCEwKSkpKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD0zMnxlO3JldHVybiB0Pj05NyYmdDw9MTIyfXZhciBpPW4oMjY0KS5IVE1MX1RBR19SRTtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0KXt2YXIgbixvLGEscyx1PWUucG9zO3JldHVybiEhZS5tZC5vcHRpb25zLmh0bWwmJihhPWUucG9zTWF4LCEoNjAhPT1lLnNyYy5jaGFyQ29kZUF0KHUpfHx1KzI+PWEpJiYoISgzMyE9PShuPWUuc3JjLmNoYXJDb2RlQXQodSsxKSkmJjYzIT09biYmNDchPT1uJiYhcihuKSkmJighIShvPWUuc3JjLnNsaWNlKHUpLm1hdGNoKGkpKSYmKHR8fChzPWUucHVzaCgiaHRtbF9pbmxpbmUiLCIiLDApLHMuY29udGVudD1lLnNyYy5zbGljZSh1LHUrb1swXS5sZW5ndGgpKSxlLnBvcys9b1swXS5sZW5ndGgsITApKSkpfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDI2MSksaT1uKDQpLmhhcyxvPW4oNCkuaXNWYWxpZEVudGl0eUNvZGUsYT1uKDQpLmZyb21Db2RlUG9pbnQscz0vXiYjKCg/OnhbYS1mMC05XXsxLDh9fFswLTldezEsOH0pKTsvaSx1PS9eJihbYS16XVthLXowLTldezEsMzF9KTsvaTtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0KXt2YXIgbixjLGw9ZS5wb3MscD1lLnBvc01heDtpZigzOCE9PWUuc3JjLmNoYXJDb2RlQXQobCkpcmV0dXJuITE7aWYobCsxPHApaWYoMzU9PT1lLnNyYy5jaGFyQ29kZUF0KGwrMSkpe2lmKGM9ZS5zcmMuc2xpY2UobCkubWF0Y2gocykpcmV0dXJuIHR8fChuPSJ4Ij09PWNbMV1bMF0udG9Mb3dlckNhc2UoKT9wYXJzZUludChjWzFdLnNsaWNlKDEpLDE2KTpwYXJzZUludChjWzFdLDEwKSxlLnBlbmRpbmcrPWEobyhuKT9uOjY1NTMzKSksZS5wb3MrPWNbMF0ubGVuZ3RoLCEwfWVsc2UgaWYoKGM9ZS5zcmMuc2xpY2UobCkubWF0Y2godSkpJiZpKHIsY1sxXSkpcmV0dXJuIHR8fChlLnBlbmRpbmcrPXJbY1sxXV0pLGUucG9zKz1jWzBdLmxlbmd0aCwhMDtyZXR1cm4gdHx8KGUucGVuZGluZys9IiYiKSxlLnBvcysrLCEwfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9ZnVuY3Rpb24oZSl7dmFyIHQsbixyLGksbz1lLmRlbGltaXRlcnMsYT1lLmRlbGltaXRlcnMubGVuZ3RoO2Zvcih0PTA7dDxhO3QrKylpZihyPW9bdF0sci5jbG9zZSlmb3Iobj10LXIuanVtcC0xO24+PTA7KXtpZihpPW9bbl0saS5vcGVuJiZpLm1hcmtlcj09PXIubWFya2VyJiZpLmVuZDwwJiZpLmxldmVsPT09ci5sZXZlbCl7dmFyIHM9KGkuY2xvc2V8fHIub3BlbikmJiJ1bmRlZmluZWQiIT09dHlwZW9mIGkubGVuZ3RoJiYidW5kZWZpbmVkIiE9PXR5cGVvZiByLmxlbmd0aCYmKGkubGVuZ3RoK3IubGVuZ3RoKSUzPT09MDtpZighcyl7ci5qdW1wPXQtbixyLm9wZW49ITEsaS5lbmQ9dCxpLmp1bXA9MDticmVha319bi09aS5qdW1wKzF9fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9ZnVuY3Rpb24oZSl7dmFyIHQsbixyPTAsaT1lLnRva2VucyxvPWUudG9rZW5zLmxlbmd0aDtmb3IodD1uPTA7dDxvO3QrKylyKz1pW3RdLm5lc3RpbmcsaVt0XS5sZXZlbD1yLCJ0ZXh0Ij09PWlbdF0udHlwZSYmdCsxPG8mJiJ0ZXh0Ij09PWlbdCsxXS50eXBlP2lbdCsxXS5jb250ZW50PWlbdF0uY29udGVudCtpW3QrMV0uY29udGVudDoodCE9PW4mJihpW25dPWlbdF0pLG4rKyk7dCE9PW4mJihpLmxlbmd0aD1uKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbixyKXt0aGlzLnNyYz1lLHRoaXMuZW52PW4sdGhpcy5tZD10LHRoaXMudG9rZW5zPXIsdGhpcy5wb3M9MCx0aGlzLnBvc01heD10aGlzLnNyYy5sZW5ndGgsdGhpcy5sZXZlbD0wLHRoaXMucGVuZGluZz0iIix0aGlzLnBlbmRpbmdMZXZlbD0wLHRoaXMuY2FjaGU9e30sdGhpcy5kZWxpbWl0ZXJzPVtdfXZhciBpPW4oMTM1KSxvPW4oNCkuaXNXaGl0ZVNwYWNlLGE9big0KS5pc1B1bmN0Q2hhcixzPW4oNCkuaXNNZEFzY2lpUHVuY3Q7ci5wcm90b3R5cGUucHVzaFBlbmRpbmc9ZnVuY3Rpb24oKXt2YXIgZT1uZXcgaSgidGV4dCIsIiIsMCk7cmV0dXJuIGUuY29udGVudD10aGlzLnBlbmRpbmcsZS5sZXZlbD10aGlzLnBlbmRpbmdMZXZlbCx0aGlzLnRva2Vucy5wdXNoKGUpLHRoaXMucGVuZGluZz0iIixlfSxyLnByb3RvdHlwZS5wdXNoPWZ1bmN0aW9uKGUsdCxuKXt0aGlzLnBlbmRpbmcmJnRoaXMucHVzaFBlbmRpbmcoKTt2YXIgcj1uZXcgaShlLHQsbik7cmV0dXJuIG48MCYmdGhpcy5sZXZlbC0tLHIubGV2ZWw9dGhpcy5sZXZlbCxuPjAmJnRoaXMubGV2ZWwrKyx0aGlzLnBlbmRpbmdMZXZlbD10aGlzLmxldmVsLHRoaXMudG9rZW5zLnB1c2gocikscn0sci5wcm90b3R5cGUuc2NhbkRlbGltcz1mdW5jdGlvbihlLHQpe3ZhciBuLHIsaSx1LGMsbCxwLGYsZCxoPWUsbT0hMCxnPSEwLHk9dGhpcy5wb3NNYXgsdj10aGlzLnNyYy5jaGFyQ29kZUF0KGUpO2ZvcihuPWU+MD90aGlzLnNyYy5jaGFyQ29kZUF0KGUtMSk6MzI7aDx5JiZ0aGlzLnNyYy5jaGFyQ29kZUF0KGgpPT09djspaCsrO3JldHVybiBpPWgtZSxyPWg8eT90aGlzLnNyYy5jaGFyQ29kZUF0KGgpOjMyLHA9cyhuKXx8YShTdHJpbmcuZnJvbUNoYXJDb2RlKG4pKSxkPXMocil8fGEoU3RyaW5nLmZyb21DaGFyQ29kZShyKSksbD1vKG4pLGY9byhyKSxmP209ITE6ZCYmKGx8fHB8fChtPSExKSksbD9nPSExOnAmJihmfHxkfHwoZz0hMSkpLHQ/KHU9bSxjPWcpOih1PW0mJighZ3x8cCksYz1nJiYoIW18fGQpKSx7Y2FuX29wZW46dSxjYW5fY2xvc2U6YyxsZW5ndGg6aX19LHIucHJvdG90eXBlLlRva2VuPWksZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0PXt9O3Quc3JjX0FueT1uKDI2OCkuc291cmNlLHQuc3JjX0NjPW4oMjY5KS5zb3VyY2UsdC5zcmNfWj1uKDI3MCkuc291cmNlLHQuc3JjX1A9bigxMzYpLnNvdXJjZSx0LnNyY19aUENjPVt0LnNyY19aLHQuc3JjX1AsdC5zcmNfQ2NdLmpvaW4oInwiKSx0LnNyY19aQ2M9W3Quc3JjX1osdC5zcmNfQ2NdLmpvaW4oInwiKTtyZXR1cm4gdC5zcmNfcHNldWRvX2xldHRlcj0iKD86KD8hWz48XHVmZjVjXXwiK3Quc3JjX1pQQ2MrIikiK3Quc3JjX0FueSsiKSIsdC5zcmNfaXA0PSIoPzooMjVbMC01XXwyWzAtNF1bMC05XXxbMDFdP1swLTldWzAtOV0/KVxcLil7M30oMjVbMC01XXwyWzAtNF1bMC05XXxbMDFdP1swLTldWzAtOV0/KSIsdC5zcmNfYXV0aD0iKD86KD86KD8hIit0LnNyY19aQ2MrInxbQC9cXFtcXF0oKV0pLikrQCk/Iix0LnNyY19wb3J0PSIoPzo6KD86Nig/OlswLTRdXFxkezN9fDUoPzpbMC00XVxcZHsyfXw1KD86WzAtMl1cXGR8M1swLTVdKSkpfFsxLTVdP1xcZHsxLDR9KSk/Iix0LnNyY19ob3N0X3Rlcm1pbmF0b3I9Iig/PSR8Wz48XHVmZjVjXXwiK3Quc3JjX1pQQ2MrIikoPyEtfF98OlxcZHxcXC4tfFxcLig/ISR8Iit0LnNyY19aUENjKyIpKSIsdC5zcmNfcGF0aD0iKD86Wy8/I10oPzooPyEiK3Quc3JjX1pDYysifFs+PFx1ZmY1Y118WygpW1xcXXt9LixcIic/IVxcLV0pLnxcXFsoPzooPyEiK3Quc3JjX1pDYysifFxcXSkuKSpcXF18XFwoKD86KD8hIit0LnNyY19aQ2MrInxbKV0pLikqXFwpfFxceyg/Oig/ISIrdC5zcmNfWkNjKyd8W31dKS4pKlxcfXxcXCIoPzooPyEnK3Quc3JjX1pDYysnfFsiXSkuKStcXCJ8XFxcJyg/Oig/IScrdC5zcmNfWkNjKyJ8WyddKS4pK1xcJ3xcXCcoPz0iK3Quc3JjX3BzZXVkb19sZXR0ZXIrInxbLV0pLnxcXC57MiwzfVthLXpBLVowLTklL118XFwuKD8hIit0LnNyY19aQ2MrInxbLl0pLnwiKyhlJiZlWyItLS0iXT8iXFwtKD8hLS0oPzpbXi1dfCQpKSg/Oi0qKXwiOiJcXC0rfCIpKyJcXCwoPyEiK3Quc3JjX1pDYysiKS58XFwhKD8hIit0LnNyY19aQ2MrInxbIV0pLnxcXD8oPyEiK3Quc3JjX1pDYysifFs/XSkuKSt8XFwvKT8iLHQuc3JjX2VtYWlsX25hbWU9J1tcXC07OiY9XFwrXFwkLFxcIlxcLmEtekEtWjAtOV9dKycsdC5zcmNfeG49InhuLS1bYS16MC05XFwtXXsxLDU5fSIsdC5zcmNfZG9tYWluX3Jvb3Q9Iig/OiIrdC5zcmNfeG4rInwiK3Quc3JjX3BzZXVkb19sZXR0ZXIrInsxLDYzfSkiLHQuc3JjX2RvbWFpbj0iKD86Iit0LnNyY194bisifCg/OiIrdC5zcmNfcHNldWRvX2xldHRlcisiKXwoPzoiK3Quc3JjX3BzZXVkb19sZXR0ZXIrIig/Oi0oPyEtKXwiK3Quc3JjX3BzZXVkb19sZXR0ZXIrIil7MCw2MX0iK3Quc3JjX3BzZXVkb19sZXR0ZXIrIikpIix0LnNyY19ob3N0PSIoPzooPzooPzooPzoiK3Quc3JjX2RvbWFpbisiKVxcLikqIit0LnNyY19kb21haW4rIikpIix0LnRwbF9ob3N0X2Z1enp5PSIoPzoiK3Quc3JjX2lwNCsifCg/Oig/Oig/OiIrdC5zcmNfZG9tYWluKyIpXFwuKSsoPzolVExEUyUpKSkiLHQudHBsX2hvc3Rfbm9faXBfZnV6enk9Iig/Oig/Oig/OiIrdC5zcmNfZG9tYWluKyIpXFwuKSsoPzolVExEUyUpKSIsdC5zcmNfaG9zdF9zdHJpY3Q9dC5zcmNfaG9zdCt0LnNyY19ob3N0X3Rlcm1pbmF0b3IsdC50cGxfaG9zdF9mdXp6eV9zdHJpY3Q9dC50cGxfaG9zdF9mdXp6eSt0LnNyY19ob3N0X3Rlcm1pbmF0b3IsdC5zcmNfaG9zdF9wb3J0X3N0cmljdD10LnNyY19ob3N0K3Quc3JjX3BvcnQrdC5zcmNfaG9zdF90ZXJtaW5hdG9yLHQudHBsX2hvc3RfcG9ydF9mdXp6eV9zdHJpY3Q9dC50cGxfaG9zdF9mdXp6eSt0LnNyY19wb3J0K3Quc3JjX2hvc3RfdGVybWluYXRvcix0LnRwbF9ob3N0X3BvcnRfbm9faXBfZnV6enlfc3RyaWN0PXQudHBsX2hvc3Rfbm9faXBfZnV6enkrdC5zcmNfcG9ydCt0LnNyY19ob3N0X3Rlcm1pbmF0b3IsdC50cGxfaG9zdF9mdXp6eV90ZXN0PSJsb2NhbGhvc3R8d3d3XFwufFxcLlxcZHsxLDN9XFwufCg/OlxcLig/OiVUTERTJSkoPzoiK3Quc3JjX1pQQ2MrInw+fCQpKSIsdC50cGxfZW1haWxfZnV6enk9IihefFs+PFx1ZmY1Y118XFwofCIrdC5zcmNfWkNjKyIpKCIrdC5zcmNfZW1haWxfbmFtZSsiQCIrdC50cGxfaG9zdF9mdXp6eV9zdHJpY3QrIikiLHQudHBsX2xpbmtfZnV6enk9IihefCg/IVsuOi9cXC1fQF0pKD86WyQrPD0+XmB8XHVmZjVjXXwiK3Quc3JjX1pQQ2MrIikpKCg/IVskKzw9Pl5gfFx1ZmY1Y10pIit0LnRwbF9ob3N0X3BvcnRfZnV6enlfc3RyaWN0K3Quc3JjX3BhdGgrIikiLHQudHBsX2xpbmtfbm9faXBfZnV6enk9IihefCg/IVsuOi9cXC1fQF0pKD86WyQrPD0+XmB8XHVmZjVjXXwiK3Quc3JjX1pQQ2MrIikpKCg/IVskKzw9Pl5gfFx1ZmY1Y10pIit0LnRwbF9ob3N0X3BvcnRfbm9faXBfZnV6enlfc3RyaWN0K3Quc3JjX3BhdGgrIikiLHR9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz17b3B0aW9uczp7aHRtbDohMSx4aHRtbE91dDohMSxicmVha3M6ITEsbGFuZ1ByZWZpeDoibGFuZ3VhZ2UtIixsaW5raWZ5OiExLHR5cG9ncmFwaGVyOiExLHF1b3RlczoiXHUyMDFjXHUyMDFkXHUyMDE4XHUyMDE5IixoaWdobGlnaHQ6bnVsbCxtYXhOZXN0aW5nOjEwMH0sY29tcG9uZW50czp7Y29yZTp7fSxibG9jazp7fSxpbmxpbmU6e319fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9e29wdGlvbnM6e2h0bWw6ITEseGh0bWxPdXQ6ITEsYnJlYWtzOiExLGxhbmdQcmVmaXg6Imxhbmd1YWdlLSIsbGlua2lmeTohMSx0eXBvZ3JhcGhlcjohMSxxdW90ZXM6Ilx1MjAxY1x1MjAxZFx1MjAxOFx1MjAxOSIsaGlnaGxpZ2h0Om51bGwsbWF4TmVzdGluZzoyMH0sY29tcG9uZW50czp7Y29yZTp7cnVsZXM6WyJub3JtYWxpemUiLCJibG9jayIsImlubGluZSJdfSxibG9jazp7cnVsZXM6WyJwYXJhZ3JhcGgiXX0saW5saW5lOntydWxlczpbInRleHQiXSxydWxlczI6WyJiYWxhbmNlX3BhaXJzIiwidGV4dF9jb2xsYXBzZSJdfX19fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz17b3B0aW9uczp7aHRtbDohMCx4aHRtbE91dDohMCxicmVha3M6ITEsbGFuZ1ByZWZpeDoibGFuZ3VhZ2UtIixsaW5raWZ5OiExLHR5cG9ncmFwaGVyOiExLHF1b3RlczoiXHUyMDFjXHUyMDFkXHUyMDE4XHUyMDE5IixoaWdobGlnaHQ6bnVsbCxtYXhOZXN0aW5nOjIwfSxjb21wb25lbnRzOntjb3JlOntydWxlczpbIm5vcm1hbGl6ZSIsImJsb2NrIiwiaW5saW5lIl19LGJsb2NrOntydWxlczpbImJsb2NrcXVvdGUiLCJjb2RlIiwiZmVuY2UiLCJoZWFkaW5nIiwiaHIiLCJodG1sX2Jsb2NrIiwibGhlYWRpbmciLCJsaXN0IiwicmVmZXJlbmNlIiwicGFyYWdyYXBoIl19LGlubGluZTp7cnVsZXM6WyJhdXRvbGluayIsImJhY2t0aWNrcyIsImVtcGhhc2lzIiwiZW50aXR5IiwiZXNjYXBlIiwiaHRtbF9pbmxpbmUiLCJpbWFnZSIsImxpbmsiLCJuZXdsaW5lIiwidGV4dCJdLHJ1bGVzMjpbImJhbGFuY2VfcGFpcnMiLCJlbXBoYXNpcyIsInRleHRfY29sbGFwc2UiXX19fX0sZnVuY3Rpb24oZSx0LG4peyhmdW5jdGlvbih0KXshZnVuY3Rpb24odCl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIG4oZSl7dGhpcy50b2tlbnM9W10sdGhpcy50b2tlbnMubGlua3M9e30sdGhpcy5vcHRpb25zPWV8fGQuZGVmYXVsdHMsdGhpcy5ydWxlcz1oLm5vcm1hbCx0aGlzLm9wdGlvbnMuZ2ZtJiYodGhpcy5vcHRpb25zLnRhYmxlcz90aGlzLnJ1bGVzPWgudGFibGVzOnRoaXMucnVsZXM9aC5nZm0pfWZ1bmN0aW9uIHIoZSx0KXtpZih0aGlzLm9wdGlvbnM9dHx8ZC5kZWZhdWx0cyx0aGlzLmxpbmtzPWUsdGhpcy5ydWxlcz1tLm5vcm1hbCx0aGlzLnJlbmRlcmVyPXRoaXMub3B0aW9ucy5yZW5kZXJlcnx8bmV3IGksdGhpcy5yZW5kZXJlci5vcHRpb25zPXRoaXMub3B0aW9ucywhdGhpcy5saW5rcyl0aHJvdyBuZXcgRXJyb3IoIlRva2VucyBhcnJheSByZXF1aXJlcyBhIGBsaW5rc2AgcHJvcGVydHkuIik7dGhpcy5vcHRpb25zLmdmbT90aGlzLm9wdGlvbnMuYnJlYWtzP3RoaXMucnVsZXM9bS5icmVha3M6dGhpcy5ydWxlcz1tLmdmbTp0aGlzLm9wdGlvbnMucGVkYW50aWMmJih0aGlzLnJ1bGVzPW0ucGVkYW50aWMpfWZ1bmN0aW9uIGkoZSl7dGhpcy5vcHRpb25zPWV8fHt9fWZ1bmN0aW9uIG8oKXt9ZnVuY3Rpb24gYShlKXt0aGlzLnRva2Vucz1bXSx0aGlzLnRva2VuPW51bGwsdGhpcy5vcHRpb25zPWV8fGQuZGVmYXVsdHMsdGhpcy5vcHRpb25zLnJlbmRlcmVyPXRoaXMub3B0aW9ucy5yZW5kZXJlcnx8bmV3IGksdGhpcy5yZW5kZXJlcj10aGlzLm9wdGlvbnMucmVuZGVyZXIsdGhpcy5yZW5kZXJlci5vcHRpb25zPXRoaXMub3B0aW9uc31mdW5jdGlvbiBzKGUsdCl7cmV0dXJuIGUucmVwbGFjZSh0Py8mL2c6LyYoPyEjP1x3KzspL2csIiZhbXA7IikucmVwbGFjZSgvPC9nLCImbHQ7IikucmVwbGFjZSgvPi9nLCImZ3Q7IikucmVwbGFjZSgvIi9nLCImcXVvdDsiKS5yZXBsYWNlKC8nL2csIiYjMzk7Iil9ZnVuY3Rpb24gdShlKXtyZXR1cm4gZS5yZXBsYWNlKC8mKCMoPzpcZCspfCg/OiN4WzAtOUEtRmEtZl0rKXwoPzpcdyspKTs/L2dpLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQ9dC50b0xvd2VyQ2FzZSgpLCJjb2xvbiI9PT10PyI6IjoiIyI9PT10LmNoYXJBdCgwKT8ieCI9PT10LmNoYXJBdCgxKT9TdHJpbmcuZnJvbUNoYXJDb2RlKHBhcnNlSW50KHQuc3Vic3RyaW5nKDIpLDE2KSk6U3RyaW5nLmZyb21DaGFyQ29kZSgrdC5zdWJzdHJpbmcoMSkpOiIifSl9ZnVuY3Rpb24gYyhlLHQpe3JldHVybiBlPWUuc291cmNlLHQ9dHx8IiIse3JlcGxhY2U6ZnVuY3Rpb24odCxuKXtyZXR1cm4gbj1uLnNvdXJjZXx8bixuPW4ucmVwbGFjZSgvKF58W15cW10pXF4vZywiJDEiKSxlPWUucmVwbGFjZSh0LG4pLHRoaXN9LGdldFJlZ2V4OmZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBSZWdFeHAoZSx0KX19fWZ1bmN0aW9uIGwoZSx0KXtyZXR1cm4gZ1siICIrZV18fCgvXlteOl0rOlwvKlteXC9dKiQvLnRlc3QoZSk/Z1siICIrZV09ZSsiLyI6Z1siICIrZV09ZS5yZXBsYWNlKC9bXlwvXSokLywiIikpLGU9Z1siICIrZV0sIi8vIj09PXQuc2xpY2UoMCwyKT9lLnJlcGxhY2UoLzpbXHNcU10qLywiOiIpK3Q6Ii8iPT09dC5jaGFyQXQoMCk/ZS5yZXBsYWNlKC8oOlwvKlteXC9dKilbXHNcU10qLywiJDEiKSt0OmUrdH1mdW5jdGlvbiBwKCl7fWZ1bmN0aW9uIGYoZSl7Zm9yKHZhciB0LG4scj0xO3I8YXJndW1lbnRzLmxlbmd0aDtyKyspe3Q9YXJndW1lbnRzW3JdO2ZvcihuIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsbikmJihlW25dPXRbbl0pfXJldHVybiBlfWZ1bmN0aW9uIGQoZSx0LHIpe2lmKCJ1bmRlZmluZWQiPT09dHlwZW9mIGV8fG51bGw9PT1lKXRocm93IG5ldyBFcnJvcigibWFya2VkKCk6IGlucHV0IHBhcmFtZXRlciBpcyB1bmRlZmluZWQgb3IgbnVsbCIpO2lmKCJzdHJpbmciIT09dHlwZW9mIGUpdGhyb3cgbmV3IEVycm9yKCJtYXJrZWQoKTogaW5wdXQgcGFyYW1ldGVyIGlzIG9mIHR5cGUgIitPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZSkrIiwgc3RyaW5nIGV4cGVjdGVkIik7aWYocnx8ImZ1bmN0aW9uIj09PXR5cGVvZiB0KXtyfHwocj10LHQ9bnVsbCksdD1mKHt9LGQuZGVmYXVsdHMsdHx8e30pO3ZhciBpLG8sdT10LmhpZ2hsaWdodCxjPTA7dHJ5e2k9bi5sZXgoZSx0KX1jYXRjaChlKXtyZXR1cm4gcihlKX1vPWkubGVuZ3RoO3ZhciBsPWZ1bmN0aW9uKGUpe2lmKGUpcmV0dXJuIHQuaGlnaGxpZ2h0PXUscihlKTt2YXIgbjt0cnl7bj1hLnBhcnNlKGksdCl9Y2F0Y2godCl7ZT10fXJldHVybiB0LmhpZ2hsaWdodD11LGU/cihlKTpyKG51bGwsbil9O2lmKCF1fHx1Lmxlbmd0aDwzKXJldHVybiBsKCk7aWYoZGVsZXRlIHQuaGlnaGxpZ2h0LCFvKXJldHVybiBsKCk7Zm9yKDtjPGkubGVuZ3RoO2MrKykhZnVuY3Rpb24oZSl7ImNvZGUiIT09ZS50eXBlPy0tb3x8bCgpOnUoZS50ZXh0LGUubGFuZyxmdW5jdGlvbih0LG4pe3JldHVybiB0P2wodCk6bnVsbD09bnx8bj09PWUudGV4dD8tLW98fGwoKTooZS50ZXh0PW4sZS5lc2NhcGVkPSEwLHZvaWQoLS1vfHxsKCkpKX0pfShpW2NdKX1lbHNlIHRyeXtyZXR1cm4gdCYmKHQ9Zih7fSxkLmRlZmF1bHRzLHQpKSxhLnBhcnNlKG4ubGV4KGUsdCksdCl9Y2F0Y2goZSl7aWYoZS5tZXNzYWdlKz0iXG5QbGVhc2UgcmVwb3J0IHRoaXMgdG8gaHR0cHM6Ly9naXRodWIuY29tL21hcmtlZGpzL21hcmtlZC4iLCh0fHxkLmRlZmF1bHRzKS5zaWxlbnQpcmV0dXJuIjxwPkFuIGVycm9yIG9jY3VycmVkOjwvcD48cHJlPiIrcyhlLm1lc3NhZ2UrIiIsITApKyI8L3ByZT4iO3Rocm93IGV9fXZhciBoPXtuZXdsaW5lOi9eXG4rLyxjb2RlOi9eKCB7NH1bXlxuXStcbiopKy8sZmVuY2VzOnAsaHI6L14gezAsM30oKD86LSAqKXszLH18KD86XyAqKXszLH18KD86XCogKil7Myx9KSg/OlxuK3wkKS8saGVhZGluZzovXiAqKCN7MSw2fSkgKihbXlxuXSs/KSAqIyogKig/OlxuK3wkKS8sbnB0YWJsZTpwLGJsb2NrcXVvdGU6L14oIHswLDN9PiA/KHBhcmFncmFwaHxbXlxuXSopKD86XG58JCkpKy8sbGlzdDovXiggKikoYnVsbCkgW1xzXFNdKz8oPzpocnxkZWZ8XG57Mix9KD8hICkoPyFcMWJ1bGwgKVxuKnxccyokKS8saHRtbDovXiAqKD86Y29tbWVudCAqKD86XG58XHMqJCl8Y2xvc2VkICooPzpcbnsyLH18XHMqJCl8Y2xvc2luZyAqKD86XG57Mix9fFxzKiQpKS8sZGVmOi9eIHswLDN9XFsobGFiZWwpXF06ICpcbj8gKjw/KFteXHM+XSspPj8oPzooPzogK1xuPyAqfCAqXG4gKikodGl0bGUpKT8gKig/OlxuK3wkKS8sdGFibGU6cCxsaGVhZGluZzovXihbXlxuXSspXG4gKig9fC0pezIsfSAqKD86XG4rfCQpLyxwYXJhZ3JhcGg6L14oW15cbl0rKD86XG4/KD8haHJ8aGVhZGluZ3xsaGVhZGluZ3wgezAsM30+fHRhZylbXlxuXSspKykvLHRleHQ6L15bXlxuXSsvfTtoLl9sYWJlbD0vKD86XFxbXFtcXV18W15cW1xdXSkrLyxoLl90aXRsZT0vKD86Iig/OlxcInxbXiJdfCJbXiJcbl0qIikqInwnXG4/KD86W14nXG5dK1xuPykqJ3xcKFteKCldKlwpKS8saC5kZWY9YyhoLmRlZikucmVwbGFjZSgibGFiZWwiLGguX2xhYmVsKS5yZXBsYWNlKCJ0aXRsZSIsaC5fdGl0bGUpLmdldFJlZ2V4KCksaC5idWxsZXQ9Lyg/OlsqKy1dfFxkK1wuKS8saC5pdGVtPS9eKCAqKShidWxsKSBbXlxuXSooPzpcbig/IVwxYnVsbCApW15cbl0qKSovLGguaXRlbT1jKGguaXRlbSwiZ20iKS5yZXBsYWNlKC9idWxsL2csaC5idWxsZXQpLmdldFJlZ2V4KCksaC5saXN0PWMoaC5saXN0KS5yZXBsYWNlKC9idWxsL2csaC5idWxsZXQpLnJlcGxhY2UoImhyIiwiXFxuKyg/PVxcMT8oPzooPzotICopezMsfXwoPzpfICopezMsfXwoPzpcXCogKil7Myx9KSg/Olxcbit8JCkpIikucmVwbGFjZSgiZGVmIiwiXFxuKyg/PSIraC5kZWYuc291cmNlKyIpIikuZ2V0UmVnZXgoKSxoLl90YWc9Iig/ISg/OmF8ZW18c3Ryb25nfHNtYWxsfHN8Y2l0ZXxxfGRmbnxhYmJyfGRhdGF8dGltZXxjb2RlfHZhcnxzYW1wfGtiZHxzdWJ8c3VwfGl8Ynx1fG1hcmt8cnVieXxydHxycHxiZGl8YmRvfHNwYW58YnJ8d2JyfGluc3xkZWx8aW1nKVxcYilcXHcrKD8hOnxbXlxcd1xcc0BdKkApXFxiIixoLmh0bWw9YyhoLmh0bWwpLnJlcGxhY2UoImNvbW1lbnQiLC88IS0tW1xzXFNdKj8tLT4vKS5yZXBsYWNlKCJjbG9zZWQiLC88KHRhZylbXHNcU10rPzxcL1wxPi8pLnJlcGxhY2UoImNsb3NpbmciLC88dGFnKD86IlteIl0qInwnW14nXSonfFxzW14nIlwvPlxzXSopKj9cLz8+LykucmVwbGFjZSgvdGFnL2csaC5fdGFnKS5nZXRSZWdleCgpLGgucGFyYWdyYXBoPWMoaC5wYXJhZ3JhcGgpLnJlcGxhY2UoImhyIixoLmhyKS5yZXBsYWNlKCJoZWFkaW5nIixoLmhlYWRpbmcpLnJlcGxhY2UoImxoZWFkaW5nIixoLmxoZWFkaW5nKS5yZXBsYWNlKCJ0YWciLCI8IitoLl90YWcpLmdldFJlZ2V4KCksaC5ibG9ja3F1b3RlPWMoaC5ibG9ja3F1b3RlKS5yZXBsYWNlKCJwYXJhZ3JhcGgiLGgucGFyYWdyYXBoKS5nZXRSZWdleCgpLGgubm9ybWFsPWYoe30saCksaC5nZm09Zih7fSxoLm5vcm1hbCx7ZmVuY2VzOi9eICooYHszLH18fnszLH0pWyBcLl0qKFxTKyk/ICpcbihbXHNcU10qPylcbj8gKlwxICooPzpcbit8JCkvLHBhcmFncmFwaDovXi8saGVhZGluZzovXiAqKCN7MSw2fSkgKyhbXlxuXSs/KSAqIyogKig/OlxuK3wkKS99KSxoLmdmbS5wYXJhZ3JhcGg9YyhoLnBhcmFncmFwaCkucmVwbGFjZSgiKD8hIiwiKD8hIitoLmdmbS5mZW5jZXMuc291cmNlLnJlcGxhY2UoIlxcMSIsIlxcMiIpKyJ8IitoLmxpc3Quc291cmNlLnJlcGxhY2UoIlxcMSIsIlxcMyIpKyJ8IikuZ2V0UmVnZXgoKSxoLnRhYmxlcz1mKHt9LGguZ2ZtLHtucHRhYmxlOi9eICooXFMuKlx8LiopXG4gKihbLTpdKyAqXHxbLXwgOl0qKVxuKCg/Oi4qXHwuKig/OlxufCQpKSopXG4qLyx0YWJsZTovXiAqXHwoLispXG4gKlx8KCAqWy06XStbLXwgOl0qKVxuKCg/OiAqXHwuKig/OlxufCQpKSopXG4qL30pLG4ucnVsZXM9aCxuLmxleD1mdW5jdGlvbihlLHQpe3JldHVybiBuZXcgbih0KS5sZXgoZSl9LG4ucHJvdG90eXBlLmxleD1mdW5jdGlvbihlKXtyZXR1cm4gZT1lLnJlcGxhY2UoL1xyXG58XHIvZywiXG4iKS5yZXBsYWNlKC9cdC9nLCIgICAgIikucmVwbGFjZSgvXHUwMGEwL2csIiAiKS5yZXBsYWNlKC9cdTI0MjQvZywiXG4iKSx0aGlzLnRva2VuKGUsITApfSxuLnByb3RvdHlwZS50b2tlbj1mdW5jdGlvbihlLHQpe2U9ZS5yZXBsYWNlKC9eICskL2dtLCIiKTtmb3IodmFyIG4scixpLG8sYSxzLHUsYyxsLHAsZjtlOylpZigoaT10aGlzLnJ1bGVzLm5ld2xpbmUuZXhlYyhlKSkmJihlPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSxpWzBdLmxlbmd0aD4xJiZ0aGlzLnRva2Vucy5wdXNoKHt0eXBlOiJzcGFjZSJ9KSksaT10aGlzLnJ1bGVzLmNvZGUuZXhlYyhlKSllPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSxpPWlbMF0ucmVwbGFjZSgvXiB7NH0vZ20sIiIpLHRoaXMudG9rZW5zLnB1c2goe3R5cGU6ImNvZGUiLHRleHQ6dGhpcy5vcHRpb25zLnBlZGFudGljP2k6aS5yZXBsYWNlKC9cbiskLywiIil9KTtlbHNlIGlmKGk9dGhpcy5ydWxlcy5mZW5jZXMuZXhlYyhlKSllPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSx0aGlzLnRva2Vucy5wdXNoKHt0eXBlOiJjb2RlIixsYW5nOmlbMl0sdGV4dDppWzNdfHwiIn0pO2Vsc2UgaWYoaT10aGlzLnJ1bGVzLmhlYWRpbmcuZXhlYyhlKSllPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSx0aGlzLnRva2Vucy5wdXNoKHt0eXBlOiJoZWFkaW5nIixkZXB0aDppWzFdLmxlbmd0aCx0ZXh0OmlbMl19KTtlbHNlIGlmKHQmJihpPXRoaXMucnVsZXMubnB0YWJsZS5leGVjKGUpKSl7Zm9yKGU9ZS5zdWJzdHJpbmcoaVswXS5sZW5ndGgpLHM9e3R5cGU6InRhYmxlIixoZWFkZXI6aVsxXS5yZXBsYWNlKC9eICp8ICpcfCAqJC9nLCIiKS5zcGxpdCgvICpcfCAqLyksYWxpZ246aVsyXS5yZXBsYWNlKC9eICp8XHwgKiQvZywiIikuc3BsaXQoLyAqXHwgKi8pLGNlbGxzOmlbM10ucmVwbGFjZSgvXG4kLywiIikuc3BsaXQoIlxuIil9LGM9MDtjPHMuYWxpZ24ubGVuZ3RoO2MrKykvXiAqLSs6ICokLy50ZXN0KHMuYWxpZ25bY10pP3MuYWxpZ25bY109InJpZ2h0IjovXiAqOi0rOiAqJC8udGVzdChzLmFsaWduW2NdKT9zLmFsaWduW2NdPSJjZW50ZXIiOi9eICo6LSsgKiQvLnRlc3Qocy5hbGlnbltjXSk/cy5hbGlnbltjXT0ibGVmdCI6cy5hbGlnbltjXT1udWxsO2ZvcihjPTA7YzxzLmNlbGxzLmxlbmd0aDtjKyspcy5jZWxsc1tjXT1zLmNlbGxzW2NdLnNwbGl0KC8gKlx8ICovKTt0aGlzLnRva2Vucy5wdXNoKHMpfWVsc2UgaWYoaT10aGlzLnJ1bGVzLmhyLmV4ZWMoZSkpZT1lLnN1YnN0cmluZyhpWzBdLmxlbmd0aCksdGhpcy50b2tlbnMucHVzaCh7dHlwZToiaHIifSk7ZWxzZSBpZihpPXRoaXMucnVsZXMuYmxvY2txdW90ZS5leGVjKGUpKWU9ZS5zdWJzdHJpbmcoaVswXS5sZW5ndGgpLHRoaXMudG9rZW5zLnB1c2goe3R5cGU6ImJsb2NrcXVvdGVfc3RhcnQifSksaT1pWzBdLnJlcGxhY2UoL14gKj4gPy9nbSwiIiksdGhpcy50b2tlbihpLHQpLHRoaXMudG9rZW5zLnB1c2goe3R5cGU6ImJsb2NrcXVvdGVfZW5kIn0pO2Vsc2UgaWYoaT10aGlzLnJ1bGVzLmxpc3QuZXhlYyhlKSl7Zm9yKGU9ZS5zdWJzdHJpbmcoaVswXS5sZW5ndGgpLG89aVsyXSxmPW8ubGVuZ3RoPjEsdGhpcy50b2tlbnMucHVzaCh7dHlwZToibGlzdF9zdGFydCIsb3JkZXJlZDpmLHN0YXJ0OmY/K286IiJ9KSxpPWlbMF0ubWF0Y2godGhpcy5ydWxlcy5pdGVtKSxuPSExLHA9aS5sZW5ndGgsYz0wO2M8cDtjKyspcz1pW2NdLHU9cy5sZW5ndGgscz1zLnJlcGxhY2UoL14gKihbKistXXxcZCtcLikgKy8sIiIpLH5zLmluZGV4T2YoIlxuICIpJiYodS09cy5sZW5ndGgscz10aGlzLm9wdGlvbnMucGVkYW50aWM/cy5yZXBsYWNlKC9eIHsxLDR9L2dtLCIiKTpzLnJlcGxhY2UobmV3IFJlZ0V4cCgiXiB7MSwiK3UrIn0iLCJnbSIpLCIiKSksdGhpcy5vcHRpb25zLnNtYXJ0TGlzdHMmJmMhPT1wLTEmJihhPWguYnVsbGV0LmV4ZWMoaVtjKzFdKVswXSxvPT09YXx8by5sZW5ndGg+MSYmYS5sZW5ndGg+MXx8KGU9aS5zbGljZShjKzEpLmpvaW4oIlxuIikrZSxjPXAtMSkpLHI9bnx8L1xuXG4oPyFccyokKS8udGVzdChzKSxjIT09cC0xJiYobj0iXG4iPT09cy5jaGFyQXQocy5sZW5ndGgtMSkscnx8KHI9bikpLHRoaXMudG9rZW5zLnB1c2goe3R5cGU6cj8ibG9vc2VfaXRlbV9zdGFydCI6Imxpc3RfaXRlbV9zdGFydCJ9KSx0aGlzLnRva2VuKHMsITEpLHRoaXMudG9rZW5zLnB1c2goe3R5cGU6Imxpc3RfaXRlbV9lbmQifSk7dGhpcy50b2tlbnMucHVzaCh7dHlwZToibGlzdF9lbmQifSl9ZWxzZSBpZihpPXRoaXMucnVsZXMuaHRtbC5leGVjKGUpKWU9ZS5zdWJzdHJpbmcoaVswXS5sZW5ndGgpLHRoaXMudG9rZW5zLnB1c2goe3R5cGU6dGhpcy5vcHRpb25zLnNhbml0aXplPyJwYXJhZ3JhcGgiOiJodG1sIixwcmU6IXRoaXMub3B0aW9ucy5zYW5pdGl6ZXImJigicHJlIj09PWlbMV18fCJzY3JpcHQiPT09aVsxXXx8InN0eWxlIj09PWlbMV0pLHRleHQ6aVswXX0pO2Vsc2UgaWYodCYmKGk9dGhpcy5ydWxlcy5kZWYuZXhlYyhlKSkpZT1lLnN1YnN0cmluZyhpWzBdLmxlbmd0aCksaVszXSYmKGlbM109aVszXS5zdWJzdHJpbmcoMSxpWzNdLmxlbmd0aC0xKSksbD1pWzFdLnRvTG93ZXJDYXNlKCksdGhpcy50b2tlbnMubGlua3NbbF18fCh0aGlzLnRva2Vucy5saW5rc1tsXT17aHJlZjppWzJdLHRpdGxlOmlbM119KTtlbHNlIGlmKHQmJihpPXRoaXMucnVsZXMudGFibGUuZXhlYyhlKSkpe2ZvcihlPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSxzPXt0eXBlOiJ0YWJsZSIsaGVhZGVyOmlbMV0ucmVwbGFjZSgvXiAqfCAqXHwgKiQvZywiIikuc3BsaXQoLyAqXHwgKi8pLGFsaWduOmlbMl0ucmVwbGFjZSgvXiAqfFx8ICokL2csIiIpLnNwbGl0KC8gKlx8ICovKSxjZWxsczppWzNdLnJlcGxhY2UoLyg/OiAqXHwgKik/XG4kLywiIikuc3BsaXQoIlxuIil9LGM9MDtjPHMuYWxpZ24ubGVuZ3RoO2MrKykvXiAqLSs6ICokLy50ZXN0KHMuYWxpZ25bY10pP3MuYWxpZ25bY109InJpZ2h0IjovXiAqOi0rOiAqJC8udGVzdChzLmFsaWduW2NdKT9zLmFsaWduW2NdPSJjZW50ZXIiOi9eICo6LSsgKiQvLnRlc3Qocy5hbGlnbltjXSk/cy5hbGlnbltjXT0ibGVmdCI6cy5hbGlnbltjXT1udWxsO2ZvcihjPTA7YzxzLmNlbGxzLmxlbmd0aDtjKyspcy5jZWxsc1tjXT1zLmNlbGxzW2NdLnJlcGxhY2UoL14gKlx8ICp8ICpcfCAqJC9nLCIiKS5zcGxpdCgvICpcfCAqLyk7dGhpcy50b2tlbnMucHVzaChzKX1lbHNlIGlmKGk9dGhpcy5ydWxlcy5saGVhZGluZy5leGVjKGUpKWU9ZS5zdWJzdHJpbmcoaVswXS5sZW5ndGgpLHRoaXMudG9rZW5zLnB1c2goe3R5cGU6ImhlYWRpbmciLGRlcHRoOiI9Ij09PWlbMl0/MToyLHRleHQ6aVsxXX0pO2Vsc2UgaWYodCYmKGk9dGhpcy5ydWxlcy5wYXJhZ3JhcGguZXhlYyhlKSkpZT1lLnN1YnN0cmluZyhpWzBdLmxlbmd0aCksdGhpcy50b2tlbnMucHVzaCh7dHlwZToicGFyYWdyYXBoIix0ZXh0OiJcbiI9PT1pWzFdLmNoYXJBdChpWzFdLmxlbmd0aC0xKT9pWzFdLnNsaWNlKDAsLTEpOmlbMV19KTtlbHNlIGlmKGk9dGhpcy5ydWxlcy50ZXh0LmV4ZWMoZSkpZT1lLnN1YnN0cmluZyhpWzBdLmxlbmd0aCksdGhpcy50b2tlbnMucHVzaCh7dHlwZToidGV4dCIsdGV4dDppWzBdfSk7ZWxzZSBpZihlKXRocm93IG5ldyBFcnJvcigiSW5maW5pdGUgbG9vcCBvbiBieXRlOiAiK2UuY2hhckNvZGVBdCgwKSk7cmV0dXJuIHRoaXMudG9rZW5zfTt2YXIgbT17ZXNjYXBlOi9eXFwoW1xcYCp7fVxbXF0oKSMrXC0uIV8+XSkvLGF1dG9saW5rOi9ePChzY2hlbWU6W15cc1x4MDAtXHgxZjw+XSp8ZW1haWwpPi8sdXJsOnAsdGFnOi9ePCEtLVtcc1xTXSo/LS0+fF48XC8/W2EtekEtWjAtOVwtXSsoPzoiW14iXSoifCdbXiddKid8XHNbXjwnIj5cL1xzXSopKj9cLz8+LyxsaW5rOi9eIT9cWyhpbnNpZGUpXF1cKGhyZWZcKS8scmVmbGluazovXiE/XFsoaW5zaWRlKVxdXHMqXFsoW15cXV0qKVxdLyxub2xpbms6L14hP1xbKCg/OlxbW15cW1xdXSpcXXxcXFtcW1xdXXxbXlxbXF1dKSopXF0vLHN0cm9uZzovXl9fKFtcc1xTXSs/KV9fKD8hXyl8XlwqXCooW1xzXFNdKz8pXCpcKig/IVwqKS8sZW06L15fKFteXHNfXSg/OlteX118X18pKz9bXlxzX10pX1xifF5cKigoPzpcKlwqfFteKl0pKz8pXCooPyFcKikvLGNvZGU6L14oYCspXHMqKFtcc1xTXSo/W15gXT8pXHMqXDEoPyFgKS8sYnI6L14gezIsfVxuKD8hXHMqJCkvLGRlbDpwLHRleHQ6L15bXHNcU10rPyg/PVtcXDwhXFtgKl18XGJffCB7Mix9XG58JCkvfTttLl9zY2hlbWU9L1thLXpBLVpdW2EtekEtWjAtOSsuLV17MSwzMX0vLG0uX2VtYWlsPS9bYS16QS1aMC05LiEjJCUmJyorXC89P15fYHt8fX4tXSsoQClbYS16QS1aMC05XSg/OlthLXpBLVowLTktXXswLDYxfVthLXpBLVowLTldKT8oPzpcLlthLXpBLVowLTldKD86W2EtekEtWjAtOS1dezAsNjF9W2EtekEtWjAtOV0pPykrKD8hWy1fXSkvLG0uYXV0b2xpbms9YyhtLmF1dG9saW5rKS5yZXBsYWNlKCJzY2hlbWUiLG0uX3NjaGVtZSkucmVwbGFjZSgiZW1haWwiLG0uX2VtYWlsKS5nZXRSZWdleCgpLG0uX2luc2lkZT0vKD86XFtbXlxbXF1dKlxdfFxcW1xbXF1dfFteXFtcXV18XF0oPz1bXlxbXSpcXSkpKi8sbS5faHJlZj0vXHMqPD8oW1xzXFNdKj8pPj8oPzpccytbJyJdKFtcc1xTXSo/KVsnIl0pP1xzKi8sbS5saW5rPWMobS5saW5rKS5yZXBsYWNlKCJpbnNpZGUiLG0uX2luc2lkZSkucmVwbGFjZSgiaHJlZiIsbS5faHJlZikuZ2V0UmVnZXgoKSxtLnJlZmxpbms9YyhtLnJlZmxpbmspLnJlcGxhY2UoImluc2lkZSIsbS5faW5zaWRlKS5nZXRSZWdleCgpLG0ubm9ybWFsPWYoe30sbSksbS5wZWRhbnRpYz1mKHt9LG0ubm9ybWFsLHtzdHJvbmc6L15fXyg/PVxTKShbXHNcU10qP1xTKV9fKD8hXyl8XlwqXCooPz1cUykoW1xzXFNdKj9cUylcKlwqKD8hXCopLyxlbTovXl8oPz1cUykoW1xzXFNdKj9cUylfKD8hXyl8XlwqKD89XFMpKFtcc1xTXSo/XFMpXCooPyFcKikvfSksbS5nZm09Zih7fSxtLm5vcm1hbCx7ZXNjYXBlOmMobS5lc2NhcGUpLnJlcGxhY2UoIl0pIiwifnxdKSIpLmdldFJlZ2V4KCksdXJsOmMoL14oKD86ZnRwfGh0dHBzPyk6XC9cL3x3d3dcLikoPzpbYS16QS1aMC05XC1dK1wuPykrW15cczxdKnxeZW1haWwvKS5yZXBsYWNlKCJlbWFpbCIsbS5fZW1haWwpLmdldFJlZ2V4KCksX2JhY2twZWRhbDovKD86W14/IS4sOjsqX34oKSZdK3xcKFteKV0qXCl8Jig/IVthLXpBLVowLTldKzskKXxbPyEuLDo7Kl9+KV0rKD8hJCkpKy8sZGVsOi9efn4oPz1cUykoW1xzXFNdKj9cUyl+fi8sdGV4dDpjKG0udGV4dCkucmVwbGFjZSgiXXwiLCJ+XXwiKS5yZXBsYWNlKCJ8IiwifGh0dHBzPzovL3xmdHA6Ly98d3d3XFwufFthLXpBLVowLTkuISMkJSYnKisvPT9eX2B7XFx8fX4tXStAfCIpLmdldFJlZ2V4KCl9KSxtLmJyZWFrcz1mKHt9LG0uZ2ZtLHticjpjKG0uYnIpLnJlcGxhY2UoInsyLH0iLCIqIikuZ2V0UmVnZXgoKSx0ZXh0OmMobS5nZm0udGV4dCkucmVwbGFjZSgiezIsfSIsIioiKS5nZXRSZWdleCgpfSksci5ydWxlcz1tLHIub3V0cHV0PWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gbmV3IHIodCxuKS5vdXRwdXQoZSl9LHIucHJvdG90eXBlLm91dHB1dD1mdW5jdGlvbihlKXtmb3IodmFyIHQsbixyLGksbz0iIjtlOylpZihpPXRoaXMucnVsZXMuZXNjYXBlLmV4ZWMoZSkpZT1lLnN1YnN0cmluZyhpWzBdLmxlbmd0aCksbys9aVsxXTtlbHNlIGlmKGk9dGhpcy5ydWxlcy5hdXRvbGluay5leGVjKGUpKWU9ZS5zdWJzdHJpbmcoaVswXS5sZW5ndGgpLCJAIj09PWlbMl0/KG49cyh0aGlzLm1hbmdsZShpWzFdKSkscj0ibWFpbHRvOiIrbik6KG49cyhpWzFdKSxyPW4pLG8rPXRoaXMucmVuZGVyZXIubGluayhyLG51bGwsbik7ZWxzZSBpZih0aGlzLmluTGlua3x8IShpPXRoaXMucnVsZXMudXJsLmV4ZWMoZSkpKXtpZihpPXRoaXMucnVsZXMudGFnLmV4ZWMoZSkpIXRoaXMuaW5MaW5rJiYvXjxhIC9pLnRlc3QoaVswXSk/dGhpcy5pbkxpbms9ITA6dGhpcy5pbkxpbmsmJi9ePFwvYT4vaS50ZXN0KGlbMF0pJiYodGhpcy5pbkxpbms9ITEpLGU9ZS5zdWJzdHJpbmcoaVswXS5sZW5ndGgpLG8rPXRoaXMub3B0aW9ucy5zYW5pdGl6ZT90aGlzLm9wdGlvbnMuc2FuaXRpemVyP3RoaXMub3B0aW9ucy5zYW5pdGl6ZXIoaVswXSk6cyhpWzBdKTppWzBdO2Vsc2UgaWYoaT10aGlzLnJ1bGVzLmxpbmsuZXhlYyhlKSllPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSx0aGlzLmluTGluaz0hMCxvKz10aGlzLm91dHB1dExpbmsoaSx7aHJlZjppWzJdLHRpdGxlOmlbM119KSx0aGlzLmluTGluaz0hMTtlbHNlIGlmKChpPXRoaXMucnVsZXMucmVmbGluay5leGVjKGUpKXx8KGk9dGhpcy5ydWxlcy5ub2xpbmsuZXhlYyhlKSkpe2lmKGU9ZS5zdWJzdHJpbmcoaVswXS5sZW5ndGgpLHQ9KGlbMl18fGlbMV0pLnJlcGxhY2UoL1xzKy9nLCIgIiksISh0PXRoaXMubGlua3NbdC50b0xvd2VyQ2FzZSgpXSl8fCF0LmhyZWYpe28rPWlbMF0uY2hhckF0KDApLGU9aVswXS5zdWJzdHJpbmcoMSkrZTtjb250aW51ZX10aGlzLmluTGluaz0hMCxvKz10aGlzLm91dHB1dExpbmsoaSx0KSx0aGlzLmluTGluaz0hMX1lbHNlIGlmKGk9dGhpcy5ydWxlcy5zdHJvbmcuZXhlYyhlKSllPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSxvKz10aGlzLnJlbmRlcmVyLnN0cm9uZyh0aGlzLm91dHB1dChpWzJdfHxpWzFdKSk7ZWxzZSBpZihpPXRoaXMucnVsZXMuZW0uZXhlYyhlKSllPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSxvKz10aGlzLnJlbmRlcmVyLmVtKHRoaXMub3V0cHV0KGlbMl18fGlbMV0pKTtlbHNlIGlmKGk9dGhpcy5ydWxlcy5jb2RlLmV4ZWMoZSkpZT1lLnN1YnN0cmluZyhpWzBdLmxlbmd0aCksbys9dGhpcy5yZW5kZXJlci5jb2Rlc3BhbihzKGlbMl0udHJpbSgpLCEwKSk7ZWxzZSBpZihpPXRoaXMucnVsZXMuYnIuZXhlYyhlKSllPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSxvKz10aGlzLnJlbmRlcmVyLmJyKCk7ZWxzZSBpZihpPXRoaXMucnVsZXMuZGVsLmV4ZWMoZSkpZT1lLnN1YnN0cmluZyhpWzBdLmxlbmd0aCksbys9dGhpcy5yZW5kZXJlci5kZWwodGhpcy5vdXRwdXQoaVsxXSkpO2Vsc2UgaWYoaT10aGlzLnJ1bGVzLnRleHQuZXhlYyhlKSllPWUuc3Vic3RyaW5nKGlbMF0ubGVuZ3RoKSxvKz10aGlzLnJlbmRlcmVyLnRleHQocyh0aGlzLnNtYXJ0eXBhbnRzKGlbMF0pKSk7ZWxzZSBpZihlKXRocm93IG5ldyBFcnJvcigiSW5maW5pdGUgbG9vcCBvbiBieXRlOiAiK2UuY2hhckNvZGVBdCgwKSl9ZWxzZSBpWzBdPXRoaXMucnVsZXMuX2JhY2twZWRhbC5leGVjKGlbMF0pWzBdLGU9ZS5zdWJzdHJpbmcoaVswXS5sZW5ndGgpLCJAIj09PWlbMl0/KG49cyhpWzBdKSxyPSJtYWlsdG86IituKToobj1zKGlbMF0pLHI9Ind3dy4iPT09aVsxXT8iaHR0cDovLyIrbjpuKSxvKz10aGlzLnJlbmRlcmVyLmxpbmsocixudWxsLG4pO3JldHVybiBvfSxyLnByb3RvdHlwZS5vdXRwdXRMaW5rPWZ1bmN0aW9uKGUsdCl7dmFyIG49cyh0LmhyZWYpLHI9dC50aXRsZT9zKHQudGl0bGUpOm51bGw7cmV0dXJuIiEiIT09ZVswXS5jaGFyQXQoMCk/dGhpcy5yZW5kZXJlci5saW5rKG4scix0aGlzLm91dHB1dChlWzFdKSk6dGhpcy5yZW5kZXJlci5pbWFnZShuLHIscyhlWzFdKSl9LHIucHJvdG90eXBlLnNtYXJ0eXBhbnRzPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLm9wdGlvbnMuc21hcnR5cGFudHM/ZS5yZXBsYWNlKC8tLS0vZywiXHUyMDE0IikucmVwbGFjZSgvLS0vZywiXHUyMDEzIikucmVwbGFjZSgvKF58Wy1cdTIwMTRcLyhcW3siXHNdKScvZywiJDFcdTIwMTgiKS5yZXBsYWNlKC8nL2csIlx1MjAxOSIpLnJlcGxhY2UoLyhefFstXHUyMDE0XC8oXFt7XHUyMDE4XHNdKSIvZywiJDFcdTIwMWMiKS5yZXBsYWNlKC8iL2csIlx1MjAxZCIpLnJlcGxhY2UoL1wuezN9L2csIlx1MjAyNiIpOmV9LHIucHJvdG90eXBlLm1hbmdsZT1mdW5jdGlvbihlKXtpZighdGhpcy5vcHRpb25zLm1hbmdsZSlyZXR1cm4gZTtmb3IodmFyIHQsbj0iIixyPWUubGVuZ3RoLGk9MDtpPHI7aSsrKXQ9ZS5jaGFyQ29kZUF0KGkpLE1hdGgucmFuZG9tKCk+LjUmJih0PSJ4Iit0LnRvU3RyaW5nKDE2KSksbis9IiYjIit0KyI7IjtyZXR1cm4gbn0saS5wcm90b3R5cGUuY29kZT1mdW5jdGlvbihlLHQsbil7aWYodGhpcy5vcHRpb25zLmhpZ2hsaWdodCl7dmFyIHI9dGhpcy5vcHRpb25zLmhpZ2hsaWdodChlLHQpO251bGwhPXImJnIhPT1lJiYobj0hMCxlPXIpfXJldHVybiB0Pyc8cHJlPjxjb2RlIGNsYXNzPSInK3RoaXMub3B0aW9ucy5sYW5nUHJlZml4K3ModCwhMCkrJyI+Jysobj9lOnMoZSwhMCkpKyJcbjwvY29kZT48L3ByZT5cbiI6IjxwcmU+PGNvZGU+Iisobj9lOnMoZSwhMCkpKyJcbjwvY29kZT48L3ByZT4ifSxpLnByb3RvdHlwZS5ibG9ja3F1b3RlPWZ1bmN0aW9uKGUpe3JldHVybiI8YmxvY2txdW90ZT5cbiIrZSsiPC9ibG9ja3F1b3RlPlxuIn0saS5wcm90b3R5cGUuaHRtbD1mdW5jdGlvbihlKXtyZXR1cm4gZX0saS5wcm90b3R5cGUuaGVhZGluZz1mdW5jdGlvbihlLHQsbil7cmV0dXJuIjxoIit0KycgaWQ9IicrdGhpcy5vcHRpb25zLmhlYWRlclByZWZpeCtuLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvW15cd10rL2csIi0iKSsnIj4nK2UrIjwvaCIrdCsiPlxuIn0saS5wcm90b3R5cGUuaHI9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5vcHRpb25zLnhodG1sPyI8aHIvPlxuIjoiPGhyPlxuIn0saS5wcm90b3R5cGUubGlzdD1mdW5jdGlvbihlLHQsbil7dmFyIHI9dD8ib2wiOiJ1bCI7cmV0dXJuIjwiK3IrKHQmJjEhPT1uPycgc3RhcnQ9IicrbisnIic6IiIpKyI+XG4iK2UrIjwvIityKyI+XG4ifSxpLnByb3RvdHlwZS5saXN0aXRlbT1mdW5jdGlvbihlKXtyZXR1cm4iPGxpPiIrZSsiPC9saT5cbiJ9LGkucHJvdG90eXBlLnBhcmFncmFwaD1mdW5jdGlvbihlKXtyZXR1cm4iPHA+IitlKyI8L3A+XG4ifSxpLnByb3RvdHlwZS50YWJsZT1mdW5jdGlvbihlLHQpe3JldHVybiI8dGFibGU+XG48dGhlYWQ+XG4iK2UrIjwvdGhlYWQ+XG48dGJvZHk+XG4iK3QrIjwvdGJvZHk+XG48L3RhYmxlPlxuIn0saS5wcm90b3R5cGUudGFibGVyb3c9ZnVuY3Rpb24oZSl7cmV0dXJuIjx0cj5cbiIrZSsiPC90cj5cbiJ9LGkucHJvdG90eXBlLnRhYmxlY2VsbD1mdW5jdGlvbihlLHQpe3ZhciBuPXQuaGVhZGVyPyJ0aCI6InRkIjtyZXR1cm4odC5hbGlnbj8iPCIrbisnIHN0eWxlPSJ0ZXh0LWFsaWduOicrdC5hbGlnbisnIj4nOiI8IituKyI+IikrZSsiPC8iK24rIj5cbiJ9LGkucHJvdG90eXBlLnN0cm9uZz1mdW5jdGlvbihlKXtyZXR1cm4iPHN0cm9uZz4iK2UrIjwvc3Ryb25nPiJ9LGkucHJvdG90eXBlLmVtPWZ1bmN0aW9uKGUpe3JldHVybiI8ZW0+IitlKyI8L2VtPiJ9LGkucHJvdG90eXBlLmNvZGVzcGFuPWZ1bmN0aW9uKGUpe3JldHVybiI8Y29kZT4iK2UrIjwvY29kZT4ifSxpLnByb3RvdHlwZS5icj1mdW5jdGlvbigpe3JldHVybiB0aGlzLm9wdGlvbnMueGh0bWw/Ijxici8+IjoiPGJyPiJ9LGkucHJvdG90eXBlLmRlbD1mdW5jdGlvbihlKXtyZXR1cm4iPGRlbD4iK2UrIjwvZGVsPiJ9LGkucHJvdG90eXBlLmxpbms9ZnVuY3Rpb24oZSx0LG4pe2lmKHRoaXMub3B0aW9ucy5zYW5pdGl6ZSl7dHJ5e3ZhciByPWRlY29kZVVSSUNvbXBvbmVudCh1KGUpKS5yZXBsYWNlKC9bXlx3Ol0vZywiIikudG9Mb3dlckNhc2UoKX1jYXRjaChlKXtyZXR1cm4gbn1pZigwPT09ci5pbmRleE9mKCJqYXZhc2NyaXB0OiIpfHwwPT09ci5pbmRleE9mKCJ2YnNjcmlwdDoiKXx8MD09PXIuaW5kZXhPZigiZGF0YToiKSlyZXR1cm4gbn10aGlzLm9wdGlvbnMuYmFzZVVybCYmIXkudGVzdChlKSYmKGU9bCh0aGlzLm9wdGlvbnMuYmFzZVVybCxlKSk7dmFyIGk9JzxhIGhyZWY9IicrZSsnIic7cmV0dXJuIHQmJihpKz0nIHRpdGxlPSInK3QrJyInKSxpKz0iPiIrbisiPC9hPiJ9LGkucHJvdG90eXBlLmltYWdlPWZ1bmN0aW9uKGUsdCxuKXt0aGlzLm9wdGlvbnMuYmFzZVVybCYmIXkudGVzdChlKSYmKGU9bCh0aGlzLm9wdGlvbnMuYmFzZVVybCxlKSk7dmFyIHI9JzxpbWcgc3JjPSInK2UrJyIgYWx0PSInK24rJyInO3JldHVybiB0JiYocis9JyB0aXRsZT0iJyt0KyciJykscis9dGhpcy5vcHRpb25zLnhodG1sPyIvPiI6Ij4ifSxpLnByb3RvdHlwZS50ZXh0PWZ1bmN0aW9uKGUpe3JldHVybiBlfSxvLnByb3RvdHlwZS5zdHJvbmc9by5wcm90b3R5cGUuZW09by5wcm90b3R5cGUuY29kZXNwYW49by5wcm90b3R5cGUuZGVsPW8ucHJvdG90eXBlLnRleHQ9ZnVuY3Rpb24oZSl7cmV0dXJuIGV9LG8ucHJvdG90eXBlLmxpbms9by5wcm90b3R5cGUuaW1hZ2U9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiIiK259LG8ucHJvdG90eXBlLmJyPWZ1bmN0aW9uKCl7cmV0dXJuIiJ9LGEucGFyc2U9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gbmV3IGEodCkucGFyc2UoZSl9LGEucHJvdG90eXBlLnBhcnNlPWZ1bmN0aW9uKGUpe3RoaXMuaW5saW5lPW5ldyByKGUubGlua3MsdGhpcy5vcHRpb25zKSx0aGlzLmlubGluZVRleHQ9bmV3IHIoZS5saW5rcyxmKHt9LHRoaXMub3B0aW9ucyx7cmVuZGVyZXI6bmV3IG99KSksdGhpcy50b2tlbnM9ZS5yZXZlcnNlKCk7Zm9yKHZhciB0PSIiO3RoaXMubmV4dCgpOyl0Kz10aGlzLnRvaygpO3JldHVybiB0fSxhLnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMudG9rZW49dGhpcy50b2tlbnMucG9wKCl9LGEucHJvdG90eXBlLnBlZWs9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy50b2tlbnNbdGhpcy50b2tlbnMubGVuZ3RoLTFdfHwwfSxhLnByb3RvdHlwZS5wYXJzZVRleHQ9ZnVuY3Rpb24oKXtmb3IodmFyIGU9dGhpcy50b2tlbi50ZXh0OyJ0ZXh0Ij09PXRoaXMucGVlaygpLnR5cGU7KWUrPSJcbiIrdGhpcy5uZXh0KCkudGV4dDtyZXR1cm4gdGhpcy5pbmxpbmUub3V0cHV0KGUpfSxhLnByb3RvdHlwZS50b2s9ZnVuY3Rpb24oKXtzd2l0Y2godGhpcy50b2tlbi50eXBlKXtjYXNlInNwYWNlIjpyZXR1cm4iIjtjYXNlImhyIjpyZXR1cm4gdGhpcy5yZW5kZXJlci5ocigpO2Nhc2UiaGVhZGluZyI6cmV0dXJuIHRoaXMucmVuZGVyZXIuaGVhZGluZyh0aGlzLmlubGluZS5vdXRwdXQodGhpcy50b2tlbi50ZXh0KSx0aGlzLnRva2VuLmRlcHRoLHUodGhpcy5pbmxpbmVUZXh0Lm91dHB1dCh0aGlzLnRva2VuLnRleHQpKSk7Y2FzZSJjb2RlIjpyZXR1cm4gdGhpcy5yZW5kZXJlci5jb2RlKHRoaXMudG9rZW4udGV4dCx0aGlzLnRva2VuLmxhbmcsdGhpcy50b2tlbi5lc2NhcGVkKTtjYXNlInRhYmxlIjp2YXIgZSx0LG4scixpPSIiLG89IiI7Zm9yKG49IiIsZT0wO2U8dGhpcy50b2tlbi5oZWFkZXIubGVuZ3RoO2UrKyluKz10aGlzLnJlbmRlcmVyLnRhYmxlY2VsbCh0aGlzLmlubGluZS5vdXRwdXQodGhpcy50b2tlbi5oZWFkZXJbZV0pLHtoZWFkZXI6ITAsYWxpZ246dGhpcy50b2tlbi5hbGlnbltlXX0pO2ZvcihpKz10aGlzLnJlbmRlcmVyLnRhYmxlcm93KG4pLGU9MDtlPHRoaXMudG9rZW4uY2VsbHMubGVuZ3RoO2UrKyl7Zm9yKHQ9dGhpcy50b2tlbi5jZWxsc1tlXSxuPSIiLHI9MDtyPHQubGVuZ3RoO3IrKyluKz10aGlzLnJlbmRlcmVyLnRhYmxlY2VsbCh0aGlzLmlubGluZS5vdXRwdXQodFtyXSkse2hlYWRlcjohMSxhbGlnbjp0aGlzLnRva2VuLmFsaWduW3JdfSk7bys9dGhpcy5yZW5kZXJlci50YWJsZXJvdyhuKX1yZXR1cm4gdGhpcy5yZW5kZXJlci50YWJsZShpLG8pO2Nhc2UiYmxvY2txdW90ZV9zdGFydCI6Zm9yKG89IiI7ImJsb2NrcXVvdGVfZW5kIiE9PXRoaXMubmV4dCgpLnR5cGU7KW8rPXRoaXMudG9rKCk7cmV0dXJuIHRoaXMucmVuZGVyZXIuYmxvY2txdW90ZShvKTtjYXNlImxpc3Rfc3RhcnQiOm89IiI7Zm9yKHZhciBhPXRoaXMudG9rZW4ub3JkZXJlZCxzPXRoaXMudG9rZW4uc3RhcnQ7Imxpc3RfZW5kIiE9PXRoaXMubmV4dCgpLnR5cGU7KW8rPXRoaXMudG9rKCk7cmV0dXJuIHRoaXMucmVuZGVyZXIubGlzdChvLGEscyk7Y2FzZSJsaXN0X2l0ZW1fc3RhcnQiOmZvcihvPSIiOyJsaXN0X2l0ZW1fZW5kIiE9PXRoaXMubmV4dCgpLnR5cGU7KW8rPSJ0ZXh0Ij09PXRoaXMudG9rZW4udHlwZT90aGlzLnBhcnNlVGV4dCgpOnRoaXMudG9rKCk7cmV0dXJuIHRoaXMucmVuZGVyZXIubGlzdGl0ZW0obyk7Y2FzZSJsb29zZV9pdGVtX3N0YXJ0Ijpmb3Iobz0iIjsibGlzdF9pdGVtX2VuZCIhPT10aGlzLm5leHQoKS50eXBlOylvKz10aGlzLnRvaygpO3JldHVybiB0aGlzLnJlbmRlcmVyLmxpc3RpdGVtKG8pO2Nhc2UiaHRtbCI6dmFyIGM9dGhpcy50b2tlbi5wcmV8fHRoaXMub3B0aW9ucy5wZWRhbnRpYz90aGlzLnRva2VuLnRleHQ6dGhpcy5pbmxpbmUub3V0cHV0KHRoaXMudG9rZW4udGV4dCk7cmV0dXJuIHRoaXMucmVuZGVyZXIuaHRtbChjKTtjYXNlInBhcmFncmFwaCI6cmV0dXJuIHRoaXMucmVuZGVyZXIucGFyYWdyYXBoKHRoaXMuaW5saW5lLm91dHB1dCh0aGlzLnRva2VuLnRleHQpKTtjYXNlInRleHQiOnJldHVybiB0aGlzLnJlbmRlcmVyLnBhcmFncmFwaCh0aGlzLnBhcnNlVGV4dCgpKX19O3ZhciBnPXt9LHk9L14kfF5bYS16XVthLXowLTkrLi1dKjp8Xls/I10vaTtwLmV4ZWM9cCxkLm9wdGlvbnM9ZC5zZXRPcHRpb25zPWZ1bmN0aW9uKGUpe3JldHVybiBmKGQuZGVmYXVsdHMsZSksZH0sZC5kZWZhdWx0cz17Z2ZtOiEwLHRhYmxlczohMCxicmVha3M6ITEscGVkYW50aWM6ITEsc2FuaXRpemU6ITEsc2FuaXRpemVyOm51bGwsbWFuZ2xlOiEwLHNtYXJ0TGlzdHM6ITEsc2lsZW50OiExLGhpZ2hsaWdodDpudWxsLGxhbmdQcmVmaXg6ImxhbmctIixzbWFydHlwYW50czohMSxoZWFkZXJQcmVmaXg6IiIscmVuZGVyZXI6bmV3IGkseGh0bWw6ITEsYmFzZVVybDpudWxsfSxkLlBhcnNlcj1hLGQucGFyc2VyPWEucGFyc2UsZC5SZW5kZXJlcj1pLGQuVGV4dFJlbmRlcmVyPW8sZC5MZXhlcj1uLGQubGV4ZXI9bi5sZXgsZC5JbmxpbmVMZXhlcj1yLGQuaW5saW5lTGV4ZXI9ci5vdXRwdXQsZC5wYXJzZT1kLGUuZXhwb3J0cz1kfSh0aGlzfHwidW5kZWZpbmVkIiE9PXR5cGVvZiB3aW5kb3cmJndpbmRvdyl9KS5jYWxsKHQsbigxMSkpfSxmdW5jdGlvbihlLHQsbil7IWZ1bmN0aW9uKGUpe2UobigyKSl9KGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiB0KHQsaSxvLGEpe2Z1bmN0aW9uIHMoZSl7dmFyIG49dSh0LGkpO2lmKCFufHxuLnRvLmxpbmUtbi5mcm9tLmxpbmU8YylyZXR1cm4gbnVsbDtmb3IodmFyIHI9dC5maW5kTWFya3NBdChuLmZyb20pLG89MDtvPHIubGVuZ3RoOysrbylpZihyW29dLl9faXNGb2xkJiYiZm9sZCIhPT1hKXtpZighZSlyZXR1cm4gbnVsbDtuLmNsZWFyZWQ9ITAscltvXS5jbGVhcigpfXJldHVybiBufWlmKG8mJm8uY2FsbCl7dmFyIHU9bztvPW51bGx9ZWxzZSB2YXIgdT1yKHQsbywicmFuZ2VGaW5kZXIiKTsibnVtYmVyIj09dHlwZW9mIGkmJihpPWUuUG9zKGksMCkpO3ZhciBjPXIodCxvLCJtaW5Gb2xkU2l6ZSIpLGw9cyghMCk7aWYocih0LG8sInNjYW5VcCIpKWZvcig7IWwmJmkubGluZT50LmZpcnN0TGluZSgpOylpPWUuUG9zKGkubGluZS0xLDApLGw9cyghMSk7aWYobCYmIWwuY2xlYXJlZCYmInVuZm9sZCIhPT1hKXt2YXIgcD1uKHQsbyk7ZS5vbihwLCJtb3VzZWRvd24iLGZ1bmN0aW9uKHQpe2YuY2xlYXIoKSxlLmVfcHJldmVudERlZmF1bHQodCl9KTt2YXIgZj10Lm1hcmtUZXh0KGwuZnJvbSxsLnRvLHtyZXBsYWNlZFdpdGg6cCxjbGVhck9uRW50ZXI6cih0LG8sImNsZWFyT25FbnRlciIpLF9faXNGb2xkOiEwfSk7Zi5vbigiY2xlYXIiLGZ1bmN0aW9uKG4scil7ZS5zaWduYWwodCwidW5mb2xkIix0LG4scil9KSxlLnNpZ25hbCh0LCJmb2xkIix0LGwuZnJvbSxsLnRvKX19ZnVuY3Rpb24gbihlLHQpe3ZhciBuPXIoZSx0LCJ3aWRnZXQiKTtpZigic3RyaW5nIj09dHlwZW9mIG4pe3ZhciBpPWRvY3VtZW50LmNyZWF0ZVRleHROb2RlKG4pO249ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic3BhbiIpLG4uYXBwZW5kQ2hpbGQoaSksbi5jbGFzc05hbWU9IkNvZGVNaXJyb3ItZm9sZG1hcmtlciJ9ZWxzZSBuJiYobj1uLmNsb25lTm9kZSghMCkpO3JldHVybiBufWZ1bmN0aW9uIHIoZSx0LG4pe2lmKHQmJnZvaWQgMCE9PXRbbl0pcmV0dXJuIHRbbl07dmFyIHI9ZS5vcHRpb25zLmZvbGRPcHRpb25zO3JldHVybiByJiZ2b2lkIDAhPT1yW25dP3Jbbl06aVtuXX1lLm5ld0ZvbGRGdW5jdGlvbj1mdW5jdGlvbihlLG4pe3JldHVybiBmdW5jdGlvbihyLGkpe3QocixpLHtyYW5nZUZpbmRlcjplLHdpZGdldDpufSl9fSxlLmRlZmluZUV4dGVuc2lvbigiZm9sZENvZGUiLGZ1bmN0aW9uKGUsbixyKXt0KHRoaXMsZSxuLHIpfSksZS5kZWZpbmVFeHRlbnNpb24oImlzRm9sZGVkIixmdW5jdGlvbihlKXtmb3IodmFyIHQ9dGhpcy5maW5kTWFya3NBdChlKSxuPTA7bjx0Lmxlbmd0aDsrK24paWYodFtuXS5fX2lzRm9sZClyZXR1cm4hMH0pLGUuY29tbWFuZHMudG9nZ2xlRm9sZD1mdW5jdGlvbihlKXtlLmZvbGRDb2RlKGUuZ2V0Q3Vyc29yKCkpfSxlLmNvbW1hbmRzLmZvbGQ9ZnVuY3Rpb24oZSl7ZS5mb2xkQ29kZShlLmdldEN1cnNvcigpLG51bGwsImZvbGQiKX0sZS5jb21tYW5kcy51bmZvbGQ9ZnVuY3Rpb24oZSl7ZS5mb2xkQ29kZShlLmdldEN1cnNvcigpLG51bGwsInVuZm9sZCIpfSxlLmNvbW1hbmRzLmZvbGRBbGw9ZnVuY3Rpb24odCl7dC5vcGVyYXRpb24oZnVuY3Rpb24oKXtmb3IodmFyIG49dC5maXJzdExpbmUoKSxyPXQubGFzdExpbmUoKTtuPD1yO24rKyl0LmZvbGRDb2RlKGUuUG9zKG4sMCksbnVsbCwiZm9sZCIpfSl9LGUuY29tbWFuZHMudW5mb2xkQWxsPWZ1bmN0aW9uKHQpe3Qub3BlcmF0aW9uKGZ1bmN0aW9uKCl7Zm9yKHZhciBuPXQuZmlyc3RMaW5lKCkscj10Lmxhc3RMaW5lKCk7bjw9cjtuKyspdC5mb2xkQ29kZShlLlBvcyhuLDApLG51bGwsInVuZm9sZCIpfSl9LGUucmVnaXN0ZXJIZWxwZXIoImZvbGQiLCJjb21iaW5lIixmdW5jdGlvbigpe3ZhciBlPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywwKTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmb3IodmFyIHI9MDtyPGUubGVuZ3RoOysrcil7dmFyIGk9ZVtyXSh0LG4pO2lmKGkpcmV0dXJuIGl9fX0pLGUucmVnaXN0ZXJIZWxwZXIoImZvbGQiLCJhdXRvIixmdW5jdGlvbihlLHQpe2Zvcih2YXIgbj1lLmdldEhlbHBlcnModCwiZm9sZCIpLHI9MDtyPG4ubGVuZ3RoO3IrKyl7dmFyIGk9bltyXShlLHQpO2lmKGkpcmV0dXJuIGl9fSk7dmFyIGk9e3JhbmdlRmluZGVyOmUuZm9sZC5hdXRvLHdpZGdldDoiXHUyMTk0IixtaW5Gb2xkU2l6ZTowLHNjYW5VcDohMSxjbGVhck9uRW50ZXI6ITB9O2UuZGVmaW5lT3B0aW9uKCJmb2xkT3B0aW9ucyIsbnVsbCksZS5kZWZpbmVFeHRlbnNpb24oImZvbGRPcHRpb24iLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHIodGhpcyxlLHQpfSl9KX0sZnVuY3Rpb24oZSx0LG4peyFmdW5jdGlvbihlKXtlKG4oMiksbigzOCksbigzOSksbig2OSkpfShmdW5jdGlvbihlKXsidXNlIHN0cmljdCI7dmFyIHQ9W3trZXlzOiI8TGVmdD4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6ImgifSx7a2V5czoiPFJpZ2h0PiIsdHlwZToia2V5VG9LZXkiLHRvS2V5czoibCJ9LHtrZXlzOiI8VXA+Iix0eXBlOiJrZXlUb0tleSIsdG9LZXlzOiJrIn0se2tleXM6IjxEb3duPiIsdHlwZToia2V5VG9LZXkiLHRvS2V5czoiaiJ9LHtrZXlzOiI8U3BhY2U+Iix0eXBlOiJrZXlUb0tleSIsdG9LZXlzOiJsIn0se2tleXM6IjxCUz4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6ImgiLGNvbnRleHQ6Im5vcm1hbCJ9LHtrZXlzOiI8Qy1TcGFjZT4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6IlcifSx7a2V5czoiPEMtQlM+Iix0eXBlOiJrZXlUb0tleSIsdG9LZXlzOiJCIixjb250ZXh0OiJub3JtYWwifSx7a2V5czoiPFMtU3BhY2U+Iix0eXBlOiJrZXlUb0tleSIsdG9LZXlzOiJ3In0se2tleXM6IjxTLUJTPiIsdHlwZToia2V5VG9LZXkiLHRvS2V5czoiYiIsY29udGV4dDoibm9ybWFsIn0se2tleXM6IjxDLW4+Iix0eXBlOiJrZXlUb0tleSIsdG9LZXlzOiJqIn0se2tleXM6IjxDLXA+Iix0eXBlOiJrZXlUb0tleSIsdG9LZXlzOiJrIn0se2tleXM6IjxDLVs+Iix0eXBlOiJrZXlUb0tleSIsdG9LZXlzOiI8RXNjPiJ9LHtrZXlzOiI8Qy1jPiIsdHlwZToia2V5VG9LZXkiLHRvS2V5czoiPEVzYz4ifSx7a2V5czoiPEMtWz4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6IjxFc2M+Iixjb250ZXh0OiJpbnNlcnQifSx7a2V5czoiPEMtYz4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6IjxFc2M+Iixjb250ZXh0OiJpbnNlcnQifSx7a2V5czoicyIsdHlwZToia2V5VG9LZXkiLHRvS2V5czoiY2wiLGNvbnRleHQ6Im5vcm1hbCJ9LHtrZXlzOiJzIix0eXBlOiJrZXlUb0tleSIsdG9LZXlzOiJjIixjb250ZXh0OiJ2aXN1YWwifSx7a2V5czoiUyIsdHlwZToia2V5VG9LZXkiLHRvS2V5czoiY2MiLGNvbnRleHQ6Im5vcm1hbCJ9LHtrZXlzOiJTIix0eXBlOiJrZXlUb0tleSIsdG9LZXlzOiJWZE8iLGNvbnRleHQ6InZpc3VhbCJ9LHtrZXlzOiI8SG9tZT4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6IjAifSx7a2V5czoiPEVuZD4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6IiQifSx7a2V5czoiPFBhZ2VVcD4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6IjxDLWI+In0se2tleXM6IjxQYWdlRG93bj4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6IjxDLWY+In0se2tleXM6IjxDUj4iLHR5cGU6ImtleVRvS2V5Iix0b0tleXM6ImpeIixjb250ZXh0OiJub3JtYWwifSx7a2V5czoiPElucz4iLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJ0b2dnbGVPdmVyd3JpdGUiLGNvbnRleHQ6Imluc2VydCJ9LHtrZXlzOiJIIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZVRvVG9wTGluZSIsbW90aW9uQXJnczp7bGluZXdpc2U6ITAsdG9KdW1wbGlzdDohMH19LHtrZXlzOiJNIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZVRvTWlkZGxlTGluZSIsbW90aW9uQXJnczp7bGluZXdpc2U6ITAsdG9KdW1wbGlzdDohMH19LHtrZXlzOiJMIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZVRvQm90dG9tTGluZSIsbW90aW9uQXJnczp7bGluZXdpc2U6ITAsdG9KdW1wbGlzdDohMH19LHtrZXlzOiJoIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZUJ5Q2hhcmFjdGVycyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMX19LHtrZXlzOiJsIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZUJ5Q2hhcmFjdGVycyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMH19LHtrZXlzOiJqIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZUJ5TGluZXMiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITAsbGluZXdpc2U6ITB9fSx7a2V5czoiayIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVCeUxpbmVzIixtb3Rpb25BcmdzOntmb3J3YXJkOiExLGxpbmV3aXNlOiEwfX0se2tleXM6ImdqIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZUJ5RGlzcGxheUxpbmVzIixtb3Rpb25BcmdzOntmb3J3YXJkOiEwfX0se2tleXM6ImdrIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZUJ5RGlzcGxheUxpbmVzIixtb3Rpb25BcmdzOntmb3J3YXJkOiExfX0se2tleXM6InciLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlXb3JkcyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMCx3b3JkRW5kOiExfX0se2tleXM6IlciLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlXb3JkcyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMCx3b3JkRW5kOiExLGJpZ1dvcmQ6ITB9fSx7a2V5czoiZSIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVCeVdvcmRzIixtb3Rpb25BcmdzOntmb3J3YXJkOiEwLHdvcmRFbmQ6ITAsaW5jbHVzaXZlOiEwfX0se2tleXM6IkUiLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlXb3JkcyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMCx3b3JkRW5kOiEwLGJpZ1dvcmQ6ITAsaW5jbHVzaXZlOiEwfX0se2tleXM6ImIiLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlXb3JkcyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMSx3b3JkRW5kOiExfX0se2tleXM6IkIiLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlXb3JkcyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMSx3b3JkRW5kOiExLGJpZ1dvcmQ6ITB9fSx7a2V5czoiZ2UiLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlXb3JkcyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMSx3b3JkRW5kOiEwLGluY2x1c2l2ZTohMH19LHtrZXlzOiJnRSIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVCeVdvcmRzIixtb3Rpb25BcmdzOntmb3J3YXJkOiExLHdvcmRFbmQ6ITAsYmlnV29yZDohMCxpbmNsdXNpdmU6ITB9fSx7a2V5czoieyIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVCeVBhcmFncmFwaCIsbW90aW9uQXJnczp7Zm9yd2FyZDohMSx0b0p1bXBsaXN0OiEwfX0se2tleXM6In0iLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlQYXJhZ3JhcGgiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITAsdG9KdW1wbGlzdDohMH19LHtrZXlzOiIoIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZUJ5U2VudGVuY2UiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITF9fSx7a2V5czoiKSIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVCeVNlbnRlbmNlIixtb3Rpb25BcmdzOntmb3J3YXJkOiEwfX0se2tleXM6IjxDLWY+Iix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZUJ5UGFnZSIsbW90aW9uQXJnczp7Zm9yd2FyZDohMH19LHtrZXlzOiI8Qy1iPiIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVCeVBhZ2UiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITF9fSx7a2V5czoiPEMtZD4iLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlTY3JvbGwiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITAsZXhwbGljaXRSZXBlYXQ6ITB9fSx7a2V5czoiPEMtdT4iLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlTY3JvbGwiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITEsZXhwbGljaXRSZXBlYXQ6ITB9fSx7a2V5czoiZ2ciLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlVG9MaW5lT3JFZGdlT2ZEb2N1bWVudCIsbW90aW9uQXJnczp7Zm9yd2FyZDohMSxleHBsaWNpdFJlcGVhdDohMCxsaW5ld2lzZTohMCx0b0p1bXBsaXN0OiEwfX0se2tleXM6IkciLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlVG9MaW5lT3JFZGdlT2ZEb2N1bWVudCIsbW90aW9uQXJnczp7Zm9yd2FyZDohMCxleHBsaWNpdFJlcGVhdDohMCxsaW5ld2lzZTohMCx0b0p1bXBsaXN0OiEwfX0se2tleXM6IjAiLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlVG9TdGFydE9mTGluZSJ9LHtrZXlzOiJeIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZVRvRmlyc3ROb25XaGl0ZVNwYWNlQ2hhcmFjdGVyIn0se2tleXM6IisiLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlQnlMaW5lcyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMCx0b0ZpcnN0Q2hhcjohMH19LHtrZXlzOiItIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZUJ5TGluZXMiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITEsdG9GaXJzdENoYXI6ITB9fSx7a2V5czoiXyIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVCeUxpbmVzIixtb3Rpb25BcmdzOntmb3J3YXJkOiEwLHRvRmlyc3RDaGFyOiEwLHJlcGVhdE9mZnNldDotMX19LHtrZXlzOiIkIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZVRvRW9sIixtb3Rpb25BcmdzOntpbmNsdXNpdmU6ITB9fSx7a2V5czoiJSIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVUb01hdGNoZWRTeW1ib2wiLG1vdGlvbkFyZ3M6e2luY2x1c2l2ZTohMCx0b0p1bXBsaXN0OiEwfX0se2tleXM6ImY8Y2hhcmFjdGVyPiIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVUb0NoYXJhY3RlciIsbW90aW9uQXJnczp7Zm9yd2FyZDohMCxpbmNsdXNpdmU6ITB9fSx7a2V5czoiRjxjaGFyYWN0ZXI+Iix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZVRvQ2hhcmFjdGVyIixtb3Rpb25BcmdzOntmb3J3YXJkOiExfX0se2tleXM6InQ8Y2hhcmFjdGVyPiIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVUaWxsQ2hhcmFjdGVyIixtb3Rpb25BcmdzOntmb3J3YXJkOiEwLGluY2x1c2l2ZTohMH19LHtrZXlzOiJUPGNoYXJhY3Rlcj4iLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlVGlsbENoYXJhY3RlciIsbW90aW9uQXJnczp7Zm9yd2FyZDohMX19LHtrZXlzOiI7Iix0eXBlOiJtb3Rpb24iLG1vdGlvbjoicmVwZWF0TGFzdENoYXJhY3RlclNlYXJjaCIsbW90aW9uQXJnczp7Zm9yd2FyZDohMH19LHtrZXlzOiIsIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoicmVwZWF0TGFzdENoYXJhY3RlclNlYXJjaCIsbW90aW9uQXJnczp7Zm9yd2FyZDohMX19LHtrZXlzOiInPGNoYXJhY3Rlcj4iLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJnb1RvTWFyayIsbW90aW9uQXJnczp7dG9KdW1wbGlzdDohMCxsaW5ld2lzZTohMH19LHtrZXlzOiJgPGNoYXJhY3Rlcj4iLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJnb1RvTWFyayIsbW90aW9uQXJnczp7dG9KdW1wbGlzdDohMH19LHtrZXlzOiJdYCIsdHlwZToibW90aW9uIixtb3Rpb246Imp1bXBUb01hcmsiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITB9fSx7a2V5czoiW2AiLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJqdW1wVG9NYXJrIixtb3Rpb25BcmdzOntmb3J3YXJkOiExfX0se2tleXM6Il0nIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoianVtcFRvTWFyayIsbW90aW9uQXJnczp7Zm9yd2FyZDohMCxsaW5ld2lzZTohMH19LHtrZXlzOiJbJyIsdHlwZToibW90aW9uIixtb3Rpb246Imp1bXBUb01hcmsiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITEsbGluZXdpc2U6ITB9fSx7a2V5czoiXXAiLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJwYXN0ZSIsaXNFZGl0OiEwLGFjdGlvbkFyZ3M6e2FmdGVyOiEwLGlzRWRpdDohMCxtYXRjaEluZGVudDohMH19LHtrZXlzOiJbcCIsdHlwZToiYWN0aW9uIixhY3Rpb246InBhc3RlIixpc0VkaXQ6ITAsYWN0aW9uQXJnczp7YWZ0ZXI6ITEsaXNFZGl0OiEwLG1hdGNoSW5kZW50OiEwfX0se2tleXM6Il08Y2hhcmFjdGVyPiIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVUb1N5bWJvbCIsbW90aW9uQXJnczp7Zm9yd2FyZDohMCx0b0p1bXBsaXN0OiEwfX0se2tleXM6Ils8Y2hhcmFjdGVyPiIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVUb1N5bWJvbCIsbW90aW9uQXJnczp7Zm9yd2FyZDohMSx0b0p1bXBsaXN0OiEwfX0se2tleXM6InwiLHR5cGU6Im1vdGlvbiIsbW90aW9uOiJtb3ZlVG9Db2x1bW4ifSx7a2V5czoibyIsdHlwZToibW90aW9uIixtb3Rpb246Im1vdmVUb090aGVySGlnaGxpZ2h0ZWRFbmQiLGNvbnRleHQ6InZpc3VhbCJ9LHtrZXlzOiJPIix0eXBlOiJtb3Rpb24iLG1vdGlvbjoibW92ZVRvT3RoZXJIaWdobGlnaHRlZEVuZCIsbW90aW9uQXJnczp7c2FtZUxpbmU6ITB9LGNvbnRleHQ6InZpc3VhbCJ9LHtrZXlzOiJkIix0eXBlOiJvcGVyYXRvciIsb3BlcmF0b3I6ImRlbGV0ZSJ9LHtrZXlzOiJ5Iix0eXBlOiJvcGVyYXRvciIsb3BlcmF0b3I6InlhbmsifSx7a2V5czoiYyIsdHlwZToib3BlcmF0b3IiLG9wZXJhdG9yOiJjaGFuZ2UifSx7a2V5czoiPiIsdHlwZToib3BlcmF0b3IiLG9wZXJhdG9yOiJpbmRlbnQiLG9wZXJhdG9yQXJnczp7aW5kZW50UmlnaHQ6ITB9fSx7a2V5czoiPCIsdHlwZToib3BlcmF0b3IiLG9wZXJhdG9yOiJpbmRlbnQiLG9wZXJhdG9yQXJnczp7aW5kZW50UmlnaHQ6ITF9fSx7a2V5czoiZ34iLHR5cGU6Im9wZXJhdG9yIixvcGVyYXRvcjoiY2hhbmdlQ2FzZSJ9LHtrZXlzOiJndSIsdHlwZToib3BlcmF0b3IiLG9wZXJhdG9yOiJjaGFuZ2VDYXNlIixvcGVyYXRvckFyZ3M6e3RvTG93ZXI6ITB9LGlzRWRpdDohMH0se2tleXM6ImdVIix0eXBlOiJvcGVyYXRvciIsb3BlcmF0b3I6ImNoYW5nZUNhc2UiLG9wZXJhdG9yQXJnczp7dG9Mb3dlcjohMX0saXNFZGl0OiEwfSx7a2V5czoibiIsdHlwZToibW90aW9uIixtb3Rpb246ImZpbmROZXh0Iixtb3Rpb25BcmdzOntmb3J3YXJkOiEwLHRvSnVtcGxpc3Q6ITB9fSx7a2V5czoiTiIsdHlwZToibW90aW9uIixtb3Rpb246ImZpbmROZXh0Iixtb3Rpb25BcmdzOntmb3J3YXJkOiExLHRvSnVtcGxpc3Q6ITB9fSx7a2V5czoieCIsdHlwZToib3BlcmF0b3JNb3Rpb24iLG9wZXJhdG9yOiJkZWxldGUiLG1vdGlvbjoibW92ZUJ5Q2hhcmFjdGVycyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMH0sb3BlcmF0b3JNb3Rpb25BcmdzOnt2aXN1YWxMaW5lOiExfX0se2tleXM6IlgiLHR5cGU6Im9wZXJhdG9yTW90aW9uIixvcGVyYXRvcjoiZGVsZXRlIixtb3Rpb246Im1vdmVCeUNoYXJhY3RlcnMiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITF9LG9wZXJhdG9yTW90aW9uQXJnczp7dmlzdWFsTGluZTohMH19LHtrZXlzOiJEIix0eXBlOiJvcGVyYXRvck1vdGlvbiIsb3BlcmF0b3I6ImRlbGV0ZSIsbW90aW9uOiJtb3ZlVG9Fb2wiLG1vdGlvbkFyZ3M6e2luY2x1c2l2ZTohMH0sY29udGV4dDoibm9ybWFsIn0se2tleXM6IkQiLHR5cGU6Im9wZXJhdG9yIixvcGVyYXRvcjoiZGVsZXRlIixvcGVyYXRvckFyZ3M6e2xpbmV3aXNlOiEwfSxjb250ZXh0OiJ2aXN1YWwifSx7a2V5czoiWSIsdHlwZToib3BlcmF0b3JNb3Rpb24iLG9wZXJhdG9yOiJ5YW5rIixtb3Rpb246ImV4cGFuZFRvTGluZSIsbW90aW9uQXJnczp7bGluZXdpc2U6ITB9LGNvbnRleHQ6Im5vcm1hbCJ9LHtrZXlzOiJZIix0eXBlOiJvcGVyYXRvciIsb3BlcmF0b3I6InlhbmsiLG9wZXJhdG9yQXJnczp7bGluZXdpc2U6ITB9LGNvbnRleHQ6InZpc3VhbCJ9LHtrZXlzOiJDIix0eXBlOiJvcGVyYXRvck1vdGlvbiIsb3BlcmF0b3I6ImNoYW5nZSIsbW90aW9uOiJtb3ZlVG9Fb2wiLG1vdGlvbkFyZ3M6e2luY2x1c2l2ZTohMH0sY29udGV4dDoibm9ybWFsIn0se2tleXM6IkMiLHR5cGU6Im9wZXJhdG9yIixvcGVyYXRvcjoiY2hhbmdlIixvcGVyYXRvckFyZ3M6e2xpbmV3aXNlOiEwfSxjb250ZXh0OiJ2aXN1YWwifSx7a2V5czoifiIsdHlwZToib3BlcmF0b3JNb3Rpb24iLG9wZXJhdG9yOiJjaGFuZ2VDYXNlIixtb3Rpb246Im1vdmVCeUNoYXJhY3RlcnMiLG1vdGlvbkFyZ3M6e2ZvcndhcmQ6ITB9LG9wZXJhdG9yQXJnczp7c2hvdWxkTW92ZUN1cnNvcjohMH0sY29udGV4dDoibm9ybWFsIn0se2tleXM6In4iLHR5cGU6Im9wZXJhdG9yIixvcGVyYXRvcjoiY2hhbmdlQ2FzZSIsY29udGV4dDoidmlzdWFsIn0se2tleXM6IjxDLXc+Iix0eXBlOiJvcGVyYXRvck1vdGlvbiIsb3BlcmF0b3I6ImRlbGV0ZSIsbW90aW9uOiJtb3ZlQnlXb3JkcyIsbW90aW9uQXJnczp7Zm9yd2FyZDohMSx3b3JkRW5kOiExfSxjb250ZXh0OiJpbnNlcnQifSx7a2V5czoiPEMtaT4iLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJqdW1wTGlzdFdhbGsiLGFjdGlvbkFyZ3M6e2ZvcndhcmQ6ITB9fSx7a2V5czoiPEMtbz4iLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJqdW1wTGlzdFdhbGsiLGFjdGlvbkFyZ3M6e2ZvcndhcmQ6ITF9fSx7a2V5czoiPEMtZT4iLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJzY3JvbGwiLGFjdGlvbkFyZ3M6e2ZvcndhcmQ6ITAsbGluZXdpc2U6ITB9fSx7a2V5czoiPEMteT4iLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJzY3JvbGwiLGFjdGlvbkFyZ3M6e2ZvcndhcmQ6ITEsbGluZXdpc2U6ITB9fSx7a2V5czoiYSIsdHlwZToiYWN0aW9uIixhY3Rpb246ImVudGVySW5zZXJ0TW9kZSIsaXNFZGl0OiEwLGFjdGlvbkFyZ3M6e2luc2VydEF0OiJjaGFyQWZ0ZXIifSxjb250ZXh0OiJub3JtYWwifSx7a2V5czoiQSIsdHlwZToiYWN0aW9uIixhY3Rpb246ImVudGVySW5zZXJ0TW9kZSIsaXNFZGl0OiEwLGFjdGlvbkFyZ3M6e2luc2VydEF0OiJlb2wifSxjb250ZXh0OiJub3JtYWwifSx7a2V5czoiQSIsdHlwZToiYWN0aW9uIixhY3Rpb246ImVudGVySW5zZXJ0TW9kZSIsaXNFZGl0OiEwLGFjdGlvbkFyZ3M6e2luc2VydEF0OiJlbmRPZlNlbGVjdGVkQXJlYSJ9LGNvbnRleHQ6InZpc3VhbCJ9LHtrZXlzOiJpIix0eXBlOiJhY3Rpb24iLGFjdGlvbjoiZW50ZXJJbnNlcnRNb2RlIixpc0VkaXQ6ITAsYWN0aW9uQXJnczp7aW5zZXJ0QXQ6ImlucGxhY2UifSxjb250ZXh0OiJub3JtYWwifSx7a2V5czoiSSIsdHlwZToiYWN0aW9uIixhY3Rpb246ImVudGVySW5zZXJ0TW9kZSIsaXNFZGl0OiEwLGFjdGlvbkFyZ3M6e2luc2VydEF0OiJmaXJzdE5vbkJsYW5rIn0sY29udGV4dDoibm9ybWFsIn0se2tleXM6IkkiLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJlbnRlckluc2VydE1vZGUiLGlzRWRpdDohMCxhY3Rpb25BcmdzOntpbnNlcnRBdDoic3RhcnRPZlNlbGVjdGVkQXJlYSJ9LGNvbnRleHQ6InZpc3VhbCJ9LHtrZXlzOiJvIix0eXBlOiJhY3Rpb24iLGFjdGlvbjoibmV3TGluZUFuZEVudGVySW5zZXJ0TW9kZSIsaXNFZGl0OiEwLGludGVybGFjZUluc2VydFJlcGVhdDohMCxhY3Rpb25BcmdzOnthZnRlcjohMH0sY29udGV4dDoibm9ybWFsIn0se2tleXM6Ik8iLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJuZXdMaW5lQW5kRW50ZXJJbnNlcnRNb2RlIixpc0VkaXQ6ITAsaW50ZXJsYWNlSW5zZXJ0UmVwZWF0OiEwLGFjdGlvbkFyZ3M6e2FmdGVyOiExfSxjb250ZXh0OiJub3JtYWwifSx7a2V5czoidiIsdHlwZToiYWN0aW9uIixhY3Rpb246InRvZ2dsZVZpc3VhbE1vZGUifSx7a2V5czoiViIsdHlwZToiYWN0aW9uIixhY3Rpb246InRvZ2dsZVZpc3VhbE1vZGUiLGFjdGlvbkFyZ3M6e2xpbmV3aXNlOiEwfX0se2tleXM6IjxDLXY+Iix0eXBlOiJhY3Rpb24iLGFjdGlvbjoidG9nZ2xlVmlzdWFsTW9kZSIsYWN0aW9uQXJnczp7YmxvY2t3aXNlOiEwfX0se2tleXM6IjxDLXE+Iix0eXBlOiJhY3Rpb24iLGFjdGlvbjoidG9nZ2xlVmlzdWFsTW9kZSIsYWN0aW9uQXJnczp7YmxvY2t3aXNlOiEwfX0se2tleXM6Imd2Iix0eXBlOiJhY3Rpb24iLGFjdGlvbjoicmVzZWxlY3RMYXN0U2VsZWN0aW9uIn0se2tleXM6IkoiLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJqb2luTGluZXMiLGlzRWRpdDohMH0se2tleXM6InAiLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJwYXN0ZSIsaXNFZGl0OiEwLGFjdGlvbkFyZ3M6e2FmdGVyOiEwLGlzRWRpdDohMH19LHtrZXlzOiJQIix0eXBlOiJhY3Rpb24iLGFjdGlvbjoicGFzdGUiLGlzRWRpdDohMCxhY3Rpb25BcmdzOnthZnRlcjohMSxpc0VkaXQ6ITB9fSx7a2V5czoicjxjaGFyYWN0ZXI+Iix0eXBlOiJhY3Rpb24iLGFjdGlvbjoicmVwbGFjZSIsaXNFZGl0OiEwfSx7a2V5czoiQDxjaGFyYWN0ZXI+Iix0eXBlOiJhY3Rpb24iLGFjdGlvbjoicmVwbGF5TWFjcm8ifSx7a2V5czoicTxjaGFyYWN0ZXI+Iix0eXBlOiJhY3Rpb24iLGFjdGlvbjoiZW50ZXJNYWNyb1JlY29yZE1vZGUifSx7a2V5czoiUiIsdHlwZToiYWN0aW9uIixhY3Rpb246ImVudGVySW5zZXJ0TW9kZSIsaXNFZGl0OiEwLGFjdGlvbkFyZ3M6e3JlcGxhY2U6ITB9fSx7a2V5czoidSIsdHlwZToiYWN0aW9uIixhY3Rpb246InVuZG8iLGNvbnRleHQ6Im5vcm1hbCJ9LHtrZXlzOiJ1Iix0eXBlOiJvcGVyYXRvciIsb3BlcmF0b3I6ImNoYW5nZUNhc2UiLG9wZXJhdG9yQXJnczp7dG9Mb3dlcjohMH0sY29udGV4dDoidmlzdWFsIixpc0VkaXQ6ITB9LHtrZXlzOiJVIix0eXBlOiJvcGVyYXRvciIsb3BlcmF0b3I6ImNoYW5nZUNhc2UiLG9wZXJhdG9yQXJnczp7dG9Mb3dlcjohMX0sY29udGV4dDoidmlzdWFsIixpc0VkaXQ6ITB9LHtrZXlzOiI8Qy1yPiIsdHlwZToiYWN0aW9uIixhY3Rpb246InJlZG8ifSx7a2V5czoibTxjaGFyYWN0ZXI+Iix0eXBlOiJhY3Rpb24iLGFjdGlvbjoic2V0TWFyayJ9LHtrZXlzOiciPGNoYXJhY3Rlcj4nLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJzZXRSZWdpc3RlciJ9LHtrZXlzOiJ6eiIsdHlwZToiYWN0aW9uIixhY3Rpb246InNjcm9sbFRvQ3Vyc29yIixhY3Rpb25BcmdzOntwb3NpdGlvbjoiY2VudGVyIn19LHtrZXlzOiJ6LiIsdHlwZToiYWN0aW9uIixhY3Rpb246InNjcm9sbFRvQ3Vyc29yIixhY3Rpb25BcmdzOntwb3NpdGlvbjoiY2VudGVyIn0sbW90aW9uOiJtb3ZlVG9GaXJzdE5vbldoaXRlU3BhY2VDaGFyYWN0ZXIifSx7a2V5czoienQiLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJzY3JvbGxUb0N1cnNvciIsYWN0aW9uQXJnczp7cG9zaXRpb246InRvcCJ9fSx7a2V5czoiejxDUj4iLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJzY3JvbGxUb0N1cnNvciIsYWN0aW9uQXJnczp7cG9zaXRpb246InRvcCJ9LG1vdGlvbjoibW92ZVRvRmlyc3ROb25XaGl0ZVNwYWNlQ2hhcmFjdGVyIn0se2tleXM6InotIix0eXBlOiJhY3Rpb24iLGFjdGlvbjoic2Nyb2xsVG9DdXJzb3IiLGFjdGlvbkFyZ3M6e3Bvc2l0aW9uOiJib3R0b20ifX0se2tleXM6InpiIix0eXBlOiJhY3Rpb24iLGFjdGlvbjoic2Nyb2xsVG9DdXJzb3IiLGFjdGlvbkFyZ3M6e3Bvc2l0aW9uOiJib3R0b20ifSxtb3Rpb246Im1vdmVUb0ZpcnN0Tm9uV2hpdGVTcGFjZUNoYXJhY3RlciJ9LHtrZXlzOiIuIix0eXBlOiJhY3Rpb24iLGFjdGlvbjoicmVwZWF0TGFzdEVkaXQifSx7a2V5czoiPEMtYT4iLHR5cGU6ImFjdGlvbiIsYWN0aW9uOiJpbmNyZW1lbnROdW1iZXJUb2tlbiIsaXNFZGl0OiEwLGFjdGlvbkFyZ3M6e2luY3JlYXNlOiEwLGJhY2t0cmFjazohMX19LHtrZXlzOiI8Qy14PiIsdHlwZToiYWN0aW9uIixhY3Rpb246ImluY3JlbWVudE51bWJlclRva2VuIixpc0VkaXQ6ITAsYWN0aW9uQXJnczp7aW5jcmVhc2U6ITEsYmFja3RyYWNrOiExfX0se2tleXM6IjxDLXQ+Iix0eXBlOiJhY3Rpb24iLGFjdGlvbjoiaW5kZW50IixhY3Rpb25BcmdzOntpbmRlbnRSaWdodDohMH0sY29udGV4dDoiaW5zZXJ0In0se2tleXM6IjxDLWQ+Iix0eXBlOiJhY3Rpb24iLGFjdGlvbjoiaW5kZW50IixhY3Rpb25BcmdzOntpbmRlbnRSaWdodDohMX0sY29udGV4dDoiaW5zZXJ0In0se2tleXM6ImE8Y2hhcmFjdGVyPiIsdHlwZToibW90aW9uIixtb3Rpb246InRleHRPYmplY3RNYW5pcHVsYXRpb24ifSx7a2V5czoiaTxjaGFyYWN0ZXI+Iix0eXBlOiJtb3Rpb24iLG1vdGlvbjoidGV4dE9iamVjdE1hbmlwdWxhdGlvbiIsbW90aW9uQXJnczp7dGV4dE9iamVjdElubmVyOiEwfX0se2tleXM6Ii8iLHR5cGU6InNlYXJjaCIsc2VhcmNoQXJnczp7Zm9yd2FyZDohMCxxdWVyeVNyYzoicHJvbXB0Iix0b0p1bXBsaXN0OiEwfX0se2tleXM6Ij8iLHR5cGU6InNlYXJjaCIsc2VhcmNoQXJnczp7Zm9yd2FyZDohMSxxdWVyeVNyYzoicHJvbXB0Iix0b0p1bXBsaXN0OiEwfX0se2tleXM6IioiLHR5cGU6InNlYXJjaCIsc2VhcmNoQXJnczp7Zm9yd2FyZDohMCxxdWVyeVNyYzoid29yZFVuZGVyQ3Vyc29yIix3aG9sZVdvcmRPbmx5OiEwLHRvSnVtcGxpc3Q6ITB9fSx7a2V5czoiIyIsdHlwZToic2VhcmNoIixzZWFyY2hBcmdzOntmb3J3YXJkOiExLHF1ZXJ5U3JjOiJ3b3JkVW5kZXJDdXJzb3IiLHdob2xlV29yZE9ubHk6ITAsdG9KdW1wbGlzdDohMH19LHtrZXlzOiJnKiIsdHlwZToic2VhcmNoIixzZWFyY2hBcmdzOntmb3J3YXJkOiEwLHF1ZXJ5U3JjOiJ3b3JkVW5kZXJDdXJzb3IiLHRvSnVtcGxpc3Q6ITB9fSx7a2V5czoiZyMiLHR5cGU6InNlYXJjaCIsc2VhcmNoQXJnczp7Zm9yd2FyZDohMSxxdWVyeVNyYzoid29yZFVuZGVyQ3Vyc29yIix0b0p1bXBsaXN0OiEwfX0se2tleXM6IjoiLHR5cGU6ImV4In1dLG49W3tuYW1lOiJjb2xvcnNjaGVtZSIsc2hvcnROYW1lOiJjb2xvIn0se25hbWU6Im1hcCJ9LHtuYW1lOiJpbWFwIixzaG9ydE5hbWU6ImltIn0se25hbWU6Im5tYXAiLHNob3J0TmFtZToibm0ifSx7bmFtZToidm1hcCIsc2hvcnROYW1lOiJ2bSJ9LHtuYW1lOiJ1bm1hcCJ9LHtuYW1lOiJ3cml0ZSIsc2hvcnROYW1lOiJ3In0se25hbWU6InVuZG8iLHNob3J0TmFtZToidSJ9LHtuYW1lOiJyZWRvIixzaG9ydE5hbWU6InJlZCJ9LHtuYW1lOiJzZXQiLHNob3J0TmFtZToic2UifSx7bmFtZToic2V0IixzaG9ydE5hbWU6InNlIn0se25hbWU6InNldGxvY2FsIixzaG9ydE5hbWU6InNldGwifSx7bmFtZToic2V0Z2xvYmFsIixzaG9ydE5hbWU6InNldGcifSx7bmFtZToic29ydCIsc2hvcnROYW1lOiJzb3IifSx7bmFtZToic3Vic3RpdHV0ZSIsc2hvcnROYW1lOiJzIixwb3NzaWJseUFzeW5jOiEwfSx7bmFtZToibm9obHNlYXJjaCIsc2hvcnROYW1lOiJub2gifSx7bmFtZToieWFuayIsc2hvcnROYW1lOiJ5In0se25hbWU6ImRlbG1hcmtzIixzaG9ydE5hbWU6ImRlbG0ifSx7bmFtZToicmVnaXN0ZXJzIixzaG9ydE5hbWU6InJlZyIsZXhjbHVkZUZyb21Db21tYW5kSGlzdG9yeTohMH0se25hbWU6Imdsb2JhbCIsc2hvcnROYW1lOiJnIn1dLHI9ZS5Qb3M7ZS5WaW09ZnVuY3Rpb24oKXtmdW5jdGlvbiBpKHQpe3Quc2V0T3B0aW9uKCJkaXNhYmxlSW5wdXQiLCEwKSx0LnNldE9wdGlvbigic2hvd0N1cnNvcldoZW5TZWxlY3RpbmciLCExKSxlLnNpZ25hbCh0LCJ2aW0tbW9kZS1jaGFuZ2UiLHttb2RlOiJub3JtYWwifSksdC5vbigiY3Vyc29yQWN0aXZpdHkiLGN0KSxfKHQpLGUub24odC5nZXRJbnB1dEZpZWxkKCksInBhc3RlIixoKHQpKX1mdW5jdGlvbiBvKHQpe3Quc2V0T3B0aW9uKCJkaXNhYmxlSW5wdXQiLCExKSx0Lm9mZigiY3Vyc29yQWN0aXZpdHkiLGN0KSxlLm9mZih0LmdldElucHV0RmllbGQoKSwicGFzdGUiLGgodCkpLHQuc3RhdGUudmltPW51bGx9ZnVuY3Rpb24gYSh0LG4pe3RoaXM9PWUua2V5TWFwLnZpbSYmKGUucm1DbGFzcyh0LmdldFdyYXBwZXJFbGVtZW50KCksImNtLWZhdC1jdXJzb3IiKSwiY29udGVudGVkaXRhYmxlIj09dC5nZXRPcHRpb24oImlucHV0U3R5bGUiKSYmbnVsbCE9ZG9jdW1lbnQuYm9keS5zdHlsZS5jYXJldENvbG9yJiYocCh0KSx0LmdldElucHV0RmllbGQoKS5zdHlsZS5jYXJldENvbG9yPSIiKSksbiYmbi5hdHRhY2g9PXN8fG8odCl9ZnVuY3Rpb24gcyh0LG4pe3RoaXM9PWUua2V5TWFwLnZpbSYmKGUuYWRkQ2xhc3ModC5nZXRXcmFwcGVyRWxlbWVudCgpLCJjbS1mYXQtY3Vyc29yIiksImNvbnRlbnRlZGl0YWJsZSI9PXQuZ2V0T3B0aW9uKCJpbnB1dFN0eWxlIikmJm51bGwhPWRvY3VtZW50LmJvZHkuc3R5bGUuY2FyZXRDb2xvciYmKGwodCksdC5nZXRJbnB1dEZpZWxkKCkuc3R5bGUuY2FyZXRDb2xvcj0idHJhbnNwYXJlbnQiKSksbiYmbi5hdHRhY2g9PXN8fGkodCl9ZnVuY3Rpb24gdShlKXtmb3IodmFyIHQ9ZS5saXN0U2VsZWN0aW9ucygpLG49W10saT0wO2k8dC5sZW5ndGg7aSsrKXt2YXIgbz10W2ldO2lmKG8uZW1wdHkoKSlpZihvLmFuY2hvci5jaDxlLmdldExpbmUoby5hbmNob3IubGluZSkubGVuZ3RoKW4ucHVzaChlLm1hcmtUZXh0KG8uYW5jaG9yLHIoby5hbmNob3IubGluZSxvLmFuY2hvci5jaCsxKSx7Y2xhc3NOYW1lOiJjbS1mYXQtY3Vyc29yLW1hcmsifSkpO2Vsc2V7dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic3BhbiIpO2EudGV4dENvbnRlbnQ9Ilx4YTAiLGEuY2xhc3NOYW1lPSJjbS1mYXQtY3Vyc29yLW1hcmsiLG4ucHVzaChlLnNldEJvb2ttYXJrKG8uYW5jaG9yLHt3aWRnZXQ6YX0pKX19cmV0dXJuIG59ZnVuY3Rpb24gYyhlKXt2YXIgdD1lLnN0YXRlLmZhdEN1cnNvck1hcmtzO2lmKHQpZm9yKHZhciBuPTA7bjx0Lmxlbmd0aDtuKyspdFtuXS5jbGVhcigpO2Uuc3RhdGUuZmF0Q3Vyc29yTWFya3M9dShlKX1mdW5jdGlvbiBsKGUpe2Uuc3RhdGUuZmF0Q3Vyc29yTWFya3M9dShlKSxlLm9uKCJjdXJzb3JBY3Rpdml0eSIsYyl9ZnVuY3Rpb24gcChlKXt2YXIgdD1lLnN0YXRlLmZhdEN1cnNvck1hcmtzO2lmKHQpZm9yKHZhciBuPTA7bjx0Lmxlbmd0aDtuKyspdFtuXS5jbGVhcigpO2Uuc3RhdGUuZmF0Q3Vyc29yTWFya3M9bnVsbCxlLm9mZigiY3Vyc29yQWN0aXZpdHkiLGMpfWZ1bmN0aW9uIGYodCxuKXtpZihuKXtpZih0aGlzW3RdKXJldHVybiB0aGlzW3RdO3ZhciByPWQodCk7aWYoIXIpcmV0dXJuITE7dmFyIGk9ZS5WaW0uZmluZEtleShuLHIpO3JldHVybiJmdW5jdGlvbiI9PXR5cGVvZiBpJiZlLnNpZ25hbChuLCJ2aW0ta2V5cHJlc3MiLHIpLGl9fWZ1bmN0aW9uIGQoZSl7aWYoIiciPT1lLmNoYXJBdCgwKSlyZXR1cm4gZS5jaGFyQXQoMSk7dmFyIHQ9ZS5zcGxpdCgvLSg/ISQpLyksbj10W3QubGVuZ3RoLTFdO2lmKDE9PXQubGVuZ3RoJiYxPT10WzBdLmxlbmd0aClyZXR1cm4hMTtpZigyPT10Lmxlbmd0aCYmIlNoaWZ0Ij09dFswXSYmMT09bi5sZW5ndGgpcmV0dXJuITE7Zm9yKHZhciByPSExLGk9MDtpPHQubGVuZ3RoO2krKyl7dmFyIG89dFtpXTtvIGluIGd0P3RbaV09Z3Rbb106cj0hMCxvIGluIHl0JiYodFtpXT15dFtvXSl9cmV0dXJuISFyJiYoeChuKSYmKHRbdC5sZW5ndGgtMV09bi50b0xvd2VyQ2FzZSgpKSwiPCIrdC5qb2luKCItIikrIj4iKX1mdW5jdGlvbiBoKGUpe3ZhciB0PWUuc3RhdGUudmltO3JldHVybiB0Lm9uUGFzdGVGbnx8KHQub25QYXN0ZUZuPWZ1bmN0aW9uKCl7dC5pbnNlcnRNb2RlfHwoZS5zZXRDdXJzb3IoeihlLmdldEN1cnNvcigpLDAsMSkpLFB0LmVudGVySW5zZXJ0TW9kZShlLHt9LHQpKX0pLHQub25QYXN0ZUZufWZ1bmN0aW9uIG0oZSx0KXtmb3IodmFyIG49W10scj1lO3I8ZSt0O3IrKyluLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShyKSk7cmV0dXJuIG59ZnVuY3Rpb24gZyhlLHQpe3JldHVybiB0Pj1lLmZpcnN0TGluZSgpJiZ0PD1lLmxhc3RMaW5lKCl9ZnVuY3Rpb24geShlKXtyZXR1cm4vXlthLXpdJC8udGVzdChlKX1mdW5jdGlvbiB2KGUpe3JldHVybi0xIT0iKClbXXt9Ii5pbmRleE9mKGUpfWZ1bmN0aW9uIGIoZSl7cmV0dXJuIHZ0LnRlc3QoZSl9ZnVuY3Rpb24geChlKXtyZXR1cm4vXltBLVpdJC8udGVzdChlKX1mdW5jdGlvbiBDKGUpe3JldHVybi9eXHMqJC8udGVzdChlKX1mdW5jdGlvbiBFKGUpe3JldHVybi0xIT0iLj8hIi5pbmRleE9mKGUpfWZ1bmN0aW9uIEQoZSx0KXtmb3IodmFyIG49MDtuPHQubGVuZ3RoO24rKylpZih0W25dPT1lKXJldHVybiEwO3JldHVybiExfWZ1bmN0aW9uIHcoZSx0LG4scixpKXtpZih2b2lkIDA9PT10JiYhaSl0aHJvdyBFcnJvcigiZGVmYXVsdFZhbHVlIGlzIHJlcXVpcmVkIHVubGVzcyBjYWxsYmFjayBpcyBwcm92aWRlZCIpO2lmKG58fChuPSJzdHJpbmciKSxrdFtlXT17dHlwZTpuLGRlZmF1bHRWYWx1ZTp0LGNhbGxiYWNrOml9LHIpZm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspa3RbcltvXV09a3RbZV07dCYmUyhlLHQpfWZ1bmN0aW9uIFMoZSx0LG4scil7dmFyIGk9a3RbZV07cj1yfHx7fTt2YXIgbz1yLnNjb3BlO2lmKCFpKXJldHVybiBuZXcgRXJyb3IoIlVua25vd24gb3B0aW9uOiAiK2UpO2lmKCJib29sZWFuIj09aS50eXBlKXtpZih0JiYhMCE9PXQpcmV0dXJuIG5ldyBFcnJvcigiSW52YWxpZCBhcmd1bWVudDogIitlKyI9Iit0KTshMSE9PXQmJih0PSEwKX1pLmNhbGxiYWNrPygibG9jYWwiIT09byYmaS5jYWxsYmFjayh0LHZvaWQgMCksImdsb2JhbCIhPT1vJiZuJiZpLmNhbGxiYWNrKHQsbikpOigibG9jYWwiIT09byYmKGkudmFsdWU9ImJvb2xlYW4iPT1pLnR5cGU/ISF0OnQpLCJnbG9iYWwiIT09byYmbiYmKG4uc3RhdGUudmltLm9wdGlvbnNbZV09e3ZhbHVlOnR9KSl9ZnVuY3Rpb24gayhlLHQsbil7dmFyIHI9a3RbZV07bj1ufHx7fTt2YXIgaT1uLnNjb3BlO2lmKCFyKXJldHVybiBuZXcgRXJyb3IoIlVua25vd24gb3B0aW9uOiAiK2UpO3tpZighci5jYWxsYmFjayl7dmFyIG89Imdsb2JhbCIhPT1pJiZ0JiZ0LnN0YXRlLnZpbS5vcHRpb25zW2VdO3JldHVybihvfHwibG9jYWwiIT09aSYmcnx8e30pLnZhbHVlfXZhciBvPXQmJnIuY2FsbGJhY2sodm9pZCAwLHQpO2lmKCJnbG9iYWwiIT09aSYmdm9pZCAwIT09bylyZXR1cm4gbztpZigibG9jYWwiIT09aSlyZXR1cm4gci5jYWxsYmFjaygpfX1mdW5jdGlvbiBBKCl7dGhpcy5sYXRlc3RSZWdpc3Rlcj12b2lkIDAsdGhpcy5pc1BsYXlpbmc9ITEsdGhpcy5pc1JlY29yZGluZz0hMSx0aGlzLnJlcGxheVNlYXJjaFF1ZXJpZXM9W10sdGhpcy5vblJlY29yZGluZ0RvbmU9dm9pZCAwLHRoaXMubGFzdEluc2VydE1vZGVDaGFuZ2VzPV90KCl9ZnVuY3Rpb24gXyhlKXtyZXR1cm4gZS5zdGF0ZS52aW18fChlLnN0YXRlLnZpbT17aW5wdXRTdGF0ZTpuZXcgTyxsYXN0RWRpdElucHV0U3RhdGU6dm9pZCAwLGxhc3RFZGl0QWN0aW9uQ29tbWFuZDp2b2lkIDAsbGFzdEhQb3M6LTEsbGFzdEhTUG9zOi0xLGxhc3RNb3Rpb246bnVsbCxtYXJrczp7fSxmYWtlQ3Vyc29yOm51bGwsaW5zZXJ0TW9kZTohMSxpbnNlcnRNb2RlUmVwZWF0OnZvaWQgMCx2aXN1YWxNb2RlOiExLHZpc3VhbExpbmU6ITEsdmlzdWFsQmxvY2s6ITEsbGFzdFNlbGVjdGlvbjpudWxsLGxhc3RQYXN0ZWRUZXh0Om51bGwsc2VsOnt9LG9wdGlvbnM6e319KSxlLnN0YXRlLnZpbX1mdW5jdGlvbiBUKCl7VHQ9e3NlYXJjaFF1ZXJ5Om51bGwsc2VhcmNoSXNSZXZlcnNlZDohMSxsYXN0U3Vic3RpdHV0ZVJlcGxhY2VQYXJ0OnZvaWQgMCxqdW1wTGlzdDpBdCgpLG1hY3JvTW9kZVN0YXRlOm5ldyBBLGxhc3RDaGFyYWN0ZXJTZWFyY2g6e2luY3JlbWVudDowLGZvcndhcmQ6ITAsc2VsZWN0ZWRDaGFyYWN0ZXI6IiJ9LHJlZ2lzdGVyQ29udHJvbGxlcjpuZXcgTCh7fSksc2VhcmNoSGlzdG9yeUNvbnRyb2xsZXI6bmV3IFAsZXhDb21tYW5kSGlzdG9yeUNvbnRyb2xsZXI6bmV3IFB9O2Zvcih2YXIgZSBpbiBrdCl7dmFyIHQ9a3RbZV07dC52YWx1ZT10LmRlZmF1bHRWYWx1ZX19ZnVuY3Rpb24gTygpe3RoaXMucHJlZml4UmVwZWF0PVtdLHRoaXMubW90aW9uUmVwZWF0PVtdLHRoaXMub3BlcmF0b3I9bnVsbCx0aGlzLm9wZXJhdG9yQXJncz1udWxsLHRoaXMubW90aW9uPW51bGwsdGhpcy5tb3Rpb25BcmdzPW51bGwsdGhpcy5rZXlCdWZmZXI9W10sdGhpcy5yZWdpc3Rlck5hbWU9bnVsbH1mdW5jdGlvbiBGKHQsbil7dC5zdGF0ZS52aW0uaW5wdXRTdGF0ZT1uZXcgTyxlLnNpZ25hbCh0LCJ2aW0tY29tbWFuZC1kb25lIixuKX1mdW5jdGlvbiBOKGUsdCxuKXt0aGlzLmNsZWFyKCksdGhpcy5rZXlCdWZmZXI9W2V8fCIiXSx0aGlzLmluc2VydE1vZGVDaGFuZ2VzPVtdLHRoaXMuc2VhcmNoUXVlcmllcz1bXSx0aGlzLmxpbmV3aXNlPSEhdCx0aGlzLmJsb2Nrd2lzZT0hIW59ZnVuY3Rpb24gSShlLHQpe3ZhciBuPVR0LnJlZ2lzdGVyQ29udHJvbGxlci5yZWdpc3RlcnM7aWYoIWV8fDEhPWUubGVuZ3RoKXRocm93IEVycm9yKCJSZWdpc3RlciBuYW1lIG11c3QgYmUgMSBjaGFyYWN0ZXIiKTtpZihuW2VdKXRocm93IEVycm9yKCJSZWdpc3RlciBhbHJlYWR5IGRlZmluZWQgIitlKTtuW2VdPXQsU3QucHVzaChlKX1mdW5jdGlvbiBMKGUpe3RoaXMucmVnaXN0ZXJzPWUsdGhpcy51bm5hbWVkUmVnaXN0ZXI9ZVsnIiddPW5ldyBOLGVbIi4iXT1uZXcgTixlWyI6Il09bmV3IE4sZVsiLyJdPW5ldyBOfWZ1bmN0aW9uIFAoKXt0aGlzLmhpc3RvcnlCdWZmZXI9W10sdGhpcy5pdGVyYXRvcj0wLHRoaXMuaW5pdGlhbFByZWZpeD1udWxsfWZ1bmN0aW9uIE0oZSx0KXtJdFtlXT10fWZ1bmN0aW9uIGooZSx0KXtmb3IodmFyIG49W10scj0wO3I8dDtyKyspbi5wdXNoKGUpO3JldHVybiBufWZ1bmN0aW9uIFIoZSx0KXtMdFtlXT10fWZ1bmN0aW9uIEIoZSx0KXtQdFtlXT10fWZ1bmN0aW9uICQoZSx0LG4pe3ZhciBpPU1hdGgubWluKE1hdGgubWF4KGUuZmlyc3RMaW5lKCksdC5saW5lKSxlLmxhc3RMaW5lKCkpLG89ZWUoZSxpKS0xO289bj9vKzE6bzt2YXIgYT1NYXRoLm1pbihNYXRoLm1heCgwLHQuY2gpLG8pO3JldHVybiByKGksYSl9ZnVuY3Rpb24gVShlKXt2YXIgdD17fTtmb3IodmFyIG4gaW4gZSllLmhhc093blByb3BlcnR5KG4pJiYodFtuXT1lW25dKTtyZXR1cm4gdH1mdW5jdGlvbiB6KGUsdCxuKXtyZXR1cm4ib2JqZWN0Ij09PXR5cGVvZiB0JiYobj10LmNoLHQ9dC5saW5lKSxyKGUubGluZSt0LGUuY2grbil9ZnVuY3Rpb24gRyhlLHQpe3JldHVybntsaW5lOnQubGluZS1lLmxpbmUsY2g6dC5saW5lLWUubGluZX19ZnVuY3Rpb24gVihlLHQsbixyKXtmb3IodmFyIGksbz1bXSxhPVtdLHM9MDtzPHQubGVuZ3RoO3MrKyl7dmFyIHU9dFtzXTsiaW5zZXJ0Ij09biYmImluc2VydCIhPXUuY29udGV4dHx8dS5jb250ZXh0JiZ1LmNvbnRleHQhPW58fHIub3BlcmF0b3ImJiJhY3Rpb24iPT11LnR5cGV8fCEoaT1xKGUsdS5rZXlzKSl8fCgicGFydGlhbCI9PWkmJm8ucHVzaCh1KSwiZnVsbCI9PWkmJmEucHVzaCh1KSl9cmV0dXJue3BhcnRpYWw6by5sZW5ndGgmJm8sZnVsbDphLmxlbmd0aCYmYX19ZnVuY3Rpb24gcShlLHQpe2lmKCI8Y2hhcmFjdGVyPiI9PXQuc2xpY2UoLTExKSl7dmFyIG49dC5sZW5ndGgtMTEscj1lLnNsaWNlKDAsbiksaT10LnNsaWNlKDAsbik7cmV0dXJuIHI9PWkmJmUubGVuZ3RoPm4/ImZ1bGwiOjA9PWkuaW5kZXhPZihyKSYmInBhcnRpYWwifXJldHVybiBlPT10PyJmdWxsIjowPT10LmluZGV4T2YoZSkmJiJwYXJ0aWFsIn1mdW5jdGlvbiBIKGUpe3ZhciB0PS9eLiooPFtePl0rPikkLy5leGVjKGUpLG49dD90WzFdOmUuc2xpY2UoLTEpO2lmKG4ubGVuZ3RoPjEpc3dpdGNoKG4pe2Nhc2UiPENSPiI6bj0iXG4iO2JyZWFrO2Nhc2UiPFNwYWNlPiI6bj0iICI7YnJlYWs7ZGVmYXVsdDpuPSIifXJldHVybiBufWZ1bmN0aW9uIFcoZSx0LG4pe3JldHVybiBmdW5jdGlvbigpe2Zvcih2YXIgcj0wO3I8bjtyKyspdChlKX19ZnVuY3Rpb24gUShlKXtyZXR1cm4gcihlLmxpbmUsZS5jaCl9ZnVuY3Rpb24gSyhlLHQpe3JldHVybiBlLmNoPT10LmNoJiZlLmxpbmU9PXQubGluZX1mdW5jdGlvbiBKKGUsdCl7cmV0dXJuIGUubGluZTx0LmxpbmV8fGUubGluZT09dC5saW5lJiZlLmNoPHQuY2h9ZnVuY3Rpb24gWShlLHQpe3JldHVybiBhcmd1bWVudHMubGVuZ3RoPjImJih0PVkuYXBwbHkodm9pZCAwLEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywxKSkpLEooZSx0KT9lOnR9ZnVuY3Rpb24gWChlLHQpe3JldHVybiBhcmd1bWVudHMubGVuZ3RoPjImJih0PVguYXBwbHkodm9pZCAwLEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywxKSkpLEooZSx0KT90OmV9ZnVuY3Rpb24gWihlLHQsbil7dmFyIHI9SihlLHQpLGk9Sih0LG4pO3JldHVybiByJiZpfWZ1bmN0aW9uIGVlKGUsdCl7cmV0dXJuIGUuZ2V0TGluZSh0KS5sZW5ndGh9ZnVuY3Rpb24gdGUoZSl7cmV0dXJuIGUudHJpbT9lLnRyaW0oKTplLnJlcGxhY2UoL15ccyt8XHMrJC9nLCIiKX1mdW5jdGlvbiBuZShlKXtyZXR1cm4gZS5yZXBsYWNlKC8oWy4/KiskXFtcXVwvXFwoKXt9fFwtXSkvZywiXFwkMSIpfWZ1bmN0aW9uIHJlKGUsdCxuKXt2YXIgaT1lZShlLHQpLG89bmV3IEFycmF5KG4taSsxKS5qb2luKCIgIik7ZS5zZXRDdXJzb3Iocih0LGkpKSxlLnJlcGxhY2VSYW5nZShvLGUuZ2V0Q3Vyc29yKCkpfWZ1bmN0aW9uIGllKGUsdCl7dmFyIG49W10saT1lLmxpc3RTZWxlY3Rpb25zKCksbz1RKGUuY2xpcFBvcyh0KSksYT0hSyh0LG8pLHM9ZS5nZXRDdXJzb3IoImhlYWQiKSx1PWFlKGkscyksYz1LKGlbdV0uaGVhZCxpW3VdLmFuY2hvciksbD1pLmxlbmd0aC0xLHA9bC11PnU/bDowLGY9aVtwXS5hbmNob3IsZD1NYXRoLm1pbihmLmxpbmUsby5saW5lKSxoPU1hdGgubWF4KGYubGluZSxvLmxpbmUpLG09Zi5jaCxnPW8uY2gseT1pW3BdLmhlYWQuY2gtbSx2PWctbTt5PjAmJnY8PTA/KG0rKyxhfHxnLS0pOnk8MCYmdj49MD8obS0tLGN8fGcrKyk6eTwwJiYtMT09diYmKG0tLSxnKyspO2Zvcih2YXIgYj1kO2I8PWg7YisrKXt2YXIgeD17YW5jaG9yOm5ldyByKGIsbSksaGVhZDpuZXcgcihiLGcpfTtuLnB1c2goeCl9cmV0dXJuIGUuc2V0U2VsZWN0aW9ucyhuKSx0LmNoPWcsZi5jaD1tLGZ9ZnVuY3Rpb24gb2UoZSx0LG4pe2Zvcih2YXIgcj1bXSxpPTA7aTxuO2krKyl7dmFyIG89eih0LGksMCk7ci5wdXNoKHthbmNob3I6byxoZWFkOm99KX1lLnNldFNlbGVjdGlvbnMociwwKX1mdW5jdGlvbiBhZShlLHQsbil7Zm9yKHZhciByPTA7cjxlLmxlbmd0aDtyKyspe3ZhciBpPSJoZWFkIiE9biYmSyhlW3JdLmFuY2hvcix0KSxvPSJhbmNob3IiIT1uJiZLKGVbcl0uaGVhZCx0KTtpZihpfHxvKXJldHVybiByfXJldHVybi0xfWZ1bmN0aW9uIHNlKGUsdCl7dmFyIG49dC5sYXN0U2VsZWN0aW9uO3JldHVybiB0LnZpc3VhbE1vZGU/ZnVuY3Rpb24oKXt2YXIgdD1lLmxpc3RTZWxlY3Rpb25zKCksbj10WzBdLHI9dFt0Lmxlbmd0aC0xXTtyZXR1cm5bSihuLmFuY2hvcixuLmhlYWQpP24uYW5jaG9yOm4uaGVhZCxKKHIuYW5jaG9yLHIuaGVhZCk/ci5oZWFkOnIuYW5jaG9yXX0oKTpmdW5jdGlvbigpe3ZhciB0PWUuZ2V0Q3Vyc29yKCksaT1lLmdldEN1cnNvcigpLG89bi52aXN1YWxCbG9jaztpZihvKXt2YXIgYT1vLndpZHRoLHM9by5oZWlnaHQ7aT1yKHQubGluZStzLHQuY2grYSk7Zm9yKHZhciB1PVtdLGM9dC5saW5lO2M8aS5saW5lO2MrKyl7dmFyIGw9cihjLHQuY2gpLHA9cihjLGkuY2gpLGY9e2FuY2hvcjpsLGhlYWQ6cH07dS5wdXNoKGYpfWUuc2V0U2VsZWN0aW9ucyh1KX1lbHNle3ZhciBkPW4uYW5jaG9yTWFyay5maW5kKCksaD1uLmhlYWRNYXJrLmZpbmQoKSxtPWgubGluZS1kLmxpbmUsZz1oLmNoLWQuY2g7aT17bGluZTppLmxpbmUrbSxjaDptP2kuY2g6ZytpLmNofSxuLnZpc3VhbExpbmUmJih0PXIodC5saW5lLDApLGk9cihpLmxpbmUsZWUoZSxpLmxpbmUpKSksZS5zZXRTZWxlY3Rpb24odCxpKX1yZXR1cm5bdCxpXX0oKX1mdW5jdGlvbiB1ZShlLHQpe3ZhciBuPXQuc2VsLmFuY2hvcixyPXQuc2VsLmhlYWQ7dC5sYXN0UGFzdGVkVGV4dCYmKHI9ZS5wb3NGcm9tSW5kZXgoZS5pbmRleEZyb21Qb3MobikrdC5sYXN0UGFzdGVkVGV4dC5sZW5ndGgpLHQubGFzdFBhc3RlZFRleHQ9bnVsbCksdC5sYXN0U2VsZWN0aW9uPXthbmNob3JNYXJrOmUuc2V0Qm9va21hcmsobiksaGVhZE1hcms6ZS5zZXRCb29rbWFyayhyKSxhbmNob3I6UShuKSxoZWFkOlEociksdmlzdWFsTW9kZTp0LnZpc3VhbE1vZGUsdmlzdWFsTGluZTp0LnZpc3VhbExpbmUsdmlzdWFsQmxvY2s6dC52aXN1YWxCbG9ja319ZnVuY3Rpb24gY2UoZSx0LG4pe3ZhciBpLG89ZS5zdGF0ZS52aW0uc2VsLGE9by5oZWFkLHM9by5hbmNob3I7cmV0dXJuIEoobix0KSYmKGk9bixuPXQsdD1pKSxKKGEscyk/KGE9WSh0LGEpLHM9WChzLG4pKToocz1ZKHQscyksYT1YKGEsbiksYT16KGEsMCwtMSksLTE9PWEuY2gmJmEubGluZSE9ZS5maXJzdExpbmUoKSYmKGE9cihhLmxpbmUtMSxlZShlLGEubGluZS0xKSkpKSxbcyxhXX1mdW5jdGlvbiBsZShlLHQsbil7dmFyIHI9ZS5zdGF0ZS52aW07dD10fHxyLnNlbDt2YXIgbj1ufHxyLnZpc3VhbExpbmU/ImxpbmUiOnIudmlzdWFsQmxvY2s/ImJsb2NrIjoiY2hhciIsaT1wZShlLHQsbik7ZS5zZXRTZWxlY3Rpb25zKGkucmFuZ2VzLGkucHJpbWFyeSksbHQoZSl9ZnVuY3Rpb24gcGUoZSx0LG4saSl7dmFyIG89USh0LmhlYWQpLGE9USh0LmFuY2hvcik7aWYoImNoYXIiPT1uKXt2YXIgcz1pfHxKKHQuaGVhZCx0LmFuY2hvcik/MDoxLHU9Sih0LmhlYWQsdC5hbmNob3IpPzE6MDtyZXR1cm4gbz16KHQuaGVhZCwwLHMpLGE9eih0LmFuY2hvciwwLHUpLHtyYW5nZXM6W3thbmNob3I6YSxoZWFkOm99XSxwcmltYXJ5OjB9fWlmKCJsaW5lIj09bil7aWYoSih0LmhlYWQsdC5hbmNob3IpKW8uY2g9MCxhLmNoPWVlKGUsYS5saW5lKTtlbHNle2EuY2g9MDt2YXIgYz1lLmxhc3RMaW5lKCk7by5saW5lPmMmJihvLmxpbmU9Yyksby5jaD1lZShlLG8ubGluZSl9cmV0dXJue3Jhbmdlczpbe2FuY2hvcjphLGhlYWQ6b31dLHByaW1hcnk6MH19aWYoImJsb2NrIj09bil7Zm9yKHZhciBsPU1hdGgubWluKGEubGluZSxvLmxpbmUpLHA9TWF0aC5taW4oYS5jaCxvLmNoKSxmPU1hdGgubWF4KGEubGluZSxvLmxpbmUpLGQ9TWF0aC5tYXgoYS5jaCxvLmNoKSsxLGg9Zi1sKzEsbT1vLmxpbmU9PWw/MDpoLTEsZz1bXSx5PTA7eTxoO3krKylnLnB1c2goe2FuY2hvcjpyKGwreSxwKSxoZWFkOnIobCt5LGQpfSk7cmV0dXJue3JhbmdlczpnLHByaW1hcnk6bX19fWZ1bmN0aW9uIGZlKGUpe3ZhciB0PWUuZ2V0Q3Vyc29yKCJoZWFkIik7cmV0dXJuIDE9PWUuZ2V0U2VsZWN0aW9uKCkubGVuZ3RoJiYodD1ZKHQsZS5nZXRDdXJzb3IoImFuY2hvciIpKSksdH1mdW5jdGlvbiBkZSh0LG4pe3ZhciByPXQuc3RhdGUudmltOyExIT09biYmdC5zZXRDdXJzb3IoJCh0LHIuc2VsLmhlYWQpKSx1ZSh0LHIpLHIudmlzdWFsTW9kZT0hMSxyLnZpc3VhbExpbmU9ITEsci52aXN1YWxCbG9jaz0hMSxlLnNpZ25hbCh0LCJ2aW0tbW9kZS1jaGFuZ2UiLHttb2RlOiJub3JtYWwifSksci5mYWtlQ3Vyc29yJiZyLmZha2VDdXJzb3IuY2xlYXIoKX1mdW5jdGlvbiBoZShlLHQsbil7dmFyIHI9ZS5nZXRSYW5nZSh0LG4pO2lmKC9cblxzKiQvLnRlc3Qocikpe3ZhciBpPXIuc3BsaXQoIlxuIik7aS5wb3AoKTtmb3IodmFyIG8sbz1pLnBvcCgpO2kubGVuZ3RoPjAmJm8mJkMobyk7bz1pLnBvcCgpKW4ubGluZS0tLG4uY2g9MDtvPyhuLmxpbmUtLSxuLmNoPWVlKGUsbi5saW5lKSk6bi5jaD0wfX1mdW5jdGlvbiBtZShlLHQsbil7dC5jaD0wLG4uY2g9MCxuLmxpbmUrK31mdW5jdGlvbiBnZShlKXtpZighZSlyZXR1cm4gMDt2YXIgdD1lLnNlYXJjaCgvXFMvKTtyZXR1cm4tMT09dD9lLmxlbmd0aDp0fWZ1bmN0aW9uIHllKGUsdCxuLGksbyl7Zm9yKHZhciBhPWZlKGUpLHM9ZS5nZXRMaW5lKGEubGluZSksdT1hLmNoLGM9bz9idFswXTp4dFswXTshYyhzLmNoYXJBdCh1KSk7KWlmKCsrdT49cy5sZW5ndGgpcmV0dXJuIG51bGw7aT9jPXh0WzBdOihjPWJ0WzBdKShzLmNoYXJBdCh1KSl8fChjPWJ0WzFdKTtmb3IodmFyIGw9dSxwPXU7YyhzLmNoYXJBdChsKSkmJmw8cy5sZW5ndGg7KWwrKztmb3IoO2Mocy5jaGFyQXQocCkpJiZwPj0wOylwLS07aWYocCsrLHQpe2Zvcih2YXIgZj1sOy9ccy8udGVzdChzLmNoYXJBdChsKSkmJmw8cy5sZW5ndGg7KWwrKztpZihmPT1sKXtmb3IodmFyIGQ9cDsvXHMvLnRlc3Qocy5jaGFyQXQocC0xKSkmJnA+MDspcC0tO3B8fChwPWQpfX1yZXR1cm57c3RhcnQ6cihhLmxpbmUscCksZW5kOnIoYS5saW5lLGwpfX1mdW5jdGlvbiB2ZShlLHQsbil7Syh0LG4pfHxUdC5qdW1wTGlzdC5hZGQoZSx0LG4pfWZ1bmN0aW9uIGJlKGUsdCl7VHQubGFzdENoYXJhY3RlclNlYXJjaC5pbmNyZW1lbnQ9ZSxUdC5sYXN0Q2hhcmFjdGVyU2VhcmNoLmZvcndhcmQ9dC5mb3J3YXJkLFR0Lmxhc3RDaGFyYWN0ZXJTZWFyY2guc2VsZWN0ZWRDaGFyYWN0ZXI9dC5zZWxlY3RlZENoYXJhY3Rlcn1mdW5jdGlvbiB4ZShlLHQsbixpKXt2YXIgbz1RKGUuZ2V0Q3Vyc29yKCkpLGE9bj8xOi0xLHM9bj9lLmxpbmVDb3VudCgpOi0xLHU9by5jaCxjPW8ubGluZSxsPWUuZ2V0TGluZShjKSxwPXtsaW5lVGV4dDpsLG5leHRDaDpsLmNoYXJBdCh1KSxsYXN0Q2g6bnVsbCxpbmRleDp1LHN5bWI6aSxyZXZlcnNlU3ltYjoobj97IikiOiIoIiwifSI6InsifTp7IigiOiIpIiwieyI6In0ifSlbaV0sZm9yd2FyZDpuLGRlcHRoOjAsY3VyTW92ZVRocm91Z2g6ITF9LGY9TXRbaV07aWYoIWYpcmV0dXJuIG87dmFyIGQ9anRbZl0uaW5pdCxoPWp0W2ZdLmlzQ29tcGxldGU7Zm9yKGQmJmQocCk7YyE9PXMmJnQ7KXtpZihwLmluZGV4Kz1hLHAubmV4dENoPXAubGluZVRleHQuY2hhckF0KHAuaW5kZXgpLCFwLm5leHRDaCl7aWYoYys9YSxwLmxpbmVUZXh0PWUuZ2V0TGluZShjKXx8IiIsYT4wKXAuaW5kZXg9MDtlbHNle3ZhciBtPXAubGluZVRleHQubGVuZ3RoO3AuaW5kZXg9bT4wP20tMTowfXAubmV4dENoPXAubGluZVRleHQuY2hhckF0KHAuaW5kZXgpfWgocCkmJihvLmxpbmU9YyxvLmNoPXAuaW5kZXgsdC0tKX1yZXR1cm4gcC5uZXh0Q2h8fHAuY3VyTW92ZVRocm91Z2g/cihjLHAuaW5kZXgpOm99ZnVuY3Rpb24gQ2UoZSx0LG4scixpKXt2YXIgbz10LmxpbmUsYT10LmNoLHM9ZS5nZXRMaW5lKG8pLHU9bj8xOi0xLGM9cj94dDpidDtpZihpJiYiIj09cyl7aWYobys9dSxzPWUuZ2V0TGluZShvKSwhZyhlLG8pKXJldHVybiBudWxsO2E9bj8wOnMubGVuZ3RofWZvcig7Oyl7aWYoaSYmIiI9PXMpcmV0dXJue2Zyb206MCx0bzowLGxpbmU6b307Zm9yKHZhciBsPXU+MD9zLmxlbmd0aDotMSxwPWwsZj1sO2EhPWw7KXtmb3IodmFyIGQ9ITEsaD0wO2g8Yy5sZW5ndGgmJiFkOysraClpZihjW2hdKHMuY2hhckF0KGEpKSl7Zm9yKHA9YTthIT1sJiZjW2hdKHMuY2hhckF0KGEpKTspYSs9dTtpZihmPWEsZD1wIT1mLHA9PXQuY2gmJm89PXQubGluZSYmZj09cCt1KWNvbnRpbnVlO3JldHVybntmcm9tOk1hdGgubWluKHAsZisxKSx0bzpNYXRoLm1heChwLGYpLGxpbmU6b319ZHx8KGErPXUpfWlmKG8rPXUsIWcoZSxvKSlyZXR1cm4gbnVsbDtzPWUuZ2V0TGluZShvKSxhPXU+MD8wOnMubGVuZ3RofX1mdW5jdGlvbiBFZShlLHQsbixpLG8sYSl7dmFyIHM9USh0KSx1PVtdOyhpJiYhb3x8IWkmJm8pJiZuKys7Zm9yKHZhciBjPSEoaSYmbyksbD0wO2w8bjtsKyspe3ZhciBwPUNlKGUsdCxpLGEsYyk7aWYoIXApe3ZhciBmPWVlKGUsZS5sYXN0TGluZSgpKTt1LnB1c2goaT97bGluZTplLmxhc3RMaW5lKCksZnJvbTpmLHRvOmZ9OntsaW5lOjAsZnJvbTowLHRvOjB9KTticmVha311LnB1c2gocCksdD1yKHAubGluZSxpP3AudG8tMTpwLmZyb20pfXZhciBkPXUubGVuZ3RoIT1uLGg9dVswXSxtPXUucG9wKCk7cmV0dXJuIGkmJiFvPyhkfHxoLmZyb209PXMuY2gmJmgubGluZT09cy5saW5lfHwobT11LnBvcCgpKSxyKG0ubGluZSxtLmZyb20pKTppJiZvP3IobS5saW5lLG0udG8tMSk6IWkmJm8/KGR8fGgudG89PXMuY2gmJmgubGluZT09cy5saW5lfHwobT11LnBvcCgpKSxyKG0ubGluZSxtLnRvKSk6cihtLmxpbmUsbS5mcm9tKX1mdW5jdGlvbiBEZShlLHQsbixpKXtmb3IodmFyIG8sYT1lLmdldEN1cnNvcigpLHM9YS5jaCx1PTA7dTx0O3UrKyl7aWYoLTE9PShvPWtlKHMsZS5nZXRMaW5lKGEubGluZSksaSxuLCEwKSkpcmV0dXJuIG51bGw7cz1vfXJldHVybiByKGUuZ2V0Q3Vyc29yKCkubGluZSxvKX1mdW5jdGlvbiB3ZShlLHQpe3ZhciBuPWUuZ2V0Q3Vyc29yKCkubGluZTtyZXR1cm4gJChlLHIobix0LTEpKX1mdW5jdGlvbiBTZShlLHQsbixyKXtEKG4sd3QpJiYodC5tYXJrc1tuXSYmdC5tYXJrc1tuXS5jbGVhcigpLHQubWFya3Nbbl09ZS5zZXRCb29rbWFyayhyKSl9ZnVuY3Rpb24ga2UoZSx0LG4scixpKXt2YXIgbztyZXR1cm4gcj8tMT09KG89dC5pbmRleE9mKG4sZSsxKSl8fGl8fChvLT0xKTotMT09KG89dC5sYXN0SW5kZXhPZihuLGUtMSkpfHxpfHwobys9MSksb31mdW5jdGlvbiBBZShlLHQsbixpLG8pe2Z1bmN0aW9uIGEodCl7cmV0dXJuIWUuZ2V0TGluZSh0KX1mdW5jdGlvbiBzKGUsdCxuKXtyZXR1cm4gbj9hKGUpIT1hKGUrdCk6IWEoZSkmJmEoZSt0KX12YXIgdSxjLGw9dC5saW5lLHA9ZS5maXJzdExpbmUoKSxmPWUubGFzdExpbmUoKSxkPWw7aWYoaSl7Zm9yKDtwPD1kJiZkPD1mJiZuPjA7KXMoZCxpKSYmbi0tLGQrPWk7cmV0dXJuIG5ldyByKGQsMCl9dmFyIGg9ZS5zdGF0ZS52aW07aWYoaC52aXN1YWxMaW5lJiZzKGwsMSwhMCkpe3ZhciBtPWguc2VsLmFuY2hvcjtzKG0ubGluZSwtMSwhMCkmJihvJiZtLmxpbmU9PWx8fChsKz0xKSl9dmFyIGc9YShsKTtmb3IoZD1sO2Q8PWYmJm47ZCsrKXMoZCwxLCEwKSYmKG8mJmEoZCk9PWd8fG4tLSk7Zm9yKGM9bmV3IHIoZCwwKSxkPmYmJiFnP2c9ITA6bz0hMSxkPWw7ZD5wJiYobyYmYShkKSE9ZyYmZCE9bHx8IXMoZCwtMSwhMCkpO2QtLSk7cmV0dXJuIHU9bmV3IHIoZCwwKSx7c3RhcnQ6dSxlbmQ6Y319ZnVuY3Rpb24gX2UoZSx0LG4saSl7ZnVuY3Rpb24gbyhlLHQpe2lmKHQucG9zK3QuZGlyPDB8fHQucG9zK3QuZGlyPj10LmxpbmUubGVuZ3RoKXtpZih0LmxuKz10LmRpciwhZyhlLHQubG4pKXJldHVybiB0LmxpbmU9bnVsbCx0LmxuPW51bGwsdm9pZCh0LnBvcz1udWxsKTt0LmxpbmU9ZS5nZXRMaW5lKHQubG4pLHQucG9zPXQuZGlyPjA/MDp0LmxpbmUubGVuZ3RoLTF9ZWxzZSB0LnBvcys9dC5kaXJ9Zm9yKHZhciBhPXtsbjp0LmxpbmUscG9zOnQuY2h9O24+MDspYT1pPDA/ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9ZS5nZXRMaW5lKHQpLGE9e2xpbmU6aSxsbjp0LHBvczpuLGRpcjpyfSxzPXtsbjphLmxuLHBvczpudWxsfSx1PSIiPT09YS5saW5lO2ZvcihvKGUsYSk7bnVsbCE9PWEubGluZTspe2lmKCIiPT09YS5saW5lJiYhdSlyZXR1cm4gbnVsbCE9PXMucG9zP3M6e2xuOmEubG4scG9zOmEucG9zfTtpZihFKGEubGluZVthLnBvc10pJiZudWxsIT09cy5wb3MmJihhLmxuIT09cy5sbnx8YS5wb3MrMSE9PXMucG9zKSlyZXR1cm4gczsiIj09PWEubGluZXx8QyhhLmxpbmVbYS5wb3NdKXx8KHU9ITEscz17bG46YS5sbixwb3M6YS5wb3N9KSxvKGUsYSl9dmFyIGk9ZS5nZXRMaW5lKHMubG4pO3MucG9zPTA7Zm9yKHZhciBjPTA7YzxpLmxlbmd0aDsrK2MpaWYoIUMoaVtjXSkpe3MucG9zPWM7YnJlYWt9cmV0dXJuIHN9KGUsYS5sbixhLnBvcyxpKTpmdW5jdGlvbihlLHQsbixyKXt2YXIgaT1lLmdldExpbmUodCksYT0iIj09PWkscz17bGluZTppLGxuOnQscG9zOm4sZGlyOnJ9LHU9e2xuOnMubG4scG9zOnMucG9zfSxjPSIiPT09cy5saW5lO2ZvcihvKGUscyk7bnVsbCE9PXMubGluZTspe2lmKHUubG49cy5sbix1LnBvcz1zLnBvcywiIj09PXMubGluZSYmIWMpcmV0dXJue2xuOnMubG4scG9zOnMucG9zfTtpZihhJiYiIiE9PXMubGluZSYmIUMocy5saW5lW3MucG9zXSkpcmV0dXJue2xuOnMubG4scG9zOnMucG9zfTshRShzLmxpbmVbcy5wb3NdKXx8YXx8cy5wb3MhPT1zLmxpbmUubGVuZ3RoLTEmJiFDKHMubGluZVtzLnBvcysxXSl8fChhPSEwKSxvKGUscyl9dmFyIGk9ZS5nZXRMaW5lKHUubG4pO3UucG9zPTA7Zm9yKHZhciBsPWkubGVuZ3RoLTE7bD49MDstLWwpaWYoIUMoaVtsXSkpe3UucG9zPWw7YnJlYWt9cmV0dXJuIHV9KGUsYS5sbixhLnBvcyxpKSxuLS07cmV0dXJuIHIoYS5sbixhLnBvcyl9ZnVuY3Rpb24gVGUoZSx0LG4saSl7dmFyIG8sYSxzPXQsdT17IigiOi9bKCldLywiKSI6L1soKV0vLCJbIjovW1tcXV0vLCJdIjovW1tcXV0vLCJ7IjovW3t9XS8sIn0iOi9be31dL31bbl0sYz17IigiOiIoIiwiKSI6IigiLCJbIjoiWyIsIl0iOiJbIiwieyI6InsiLCJ9IjoieyJ9W25dLGw9ZS5nZXRMaW5lKHMubGluZSkuY2hhckF0KHMuY2gpLHA9bD09PWM/MTowO2lmKG89ZS5zY2FuRm9yQnJhY2tldChyKHMubGluZSxzLmNoK3ApLC0xLHZvaWQgMCx7YnJhY2tldFJlZ2V4OnV9KSxhPWUuc2NhbkZvckJyYWNrZXQocihzLmxpbmUscy5jaCtwKSwxLHZvaWQgMCx7YnJhY2tldFJlZ2V4OnV9KSwhb3x8IWEpcmV0dXJue3N0YXJ0OnMsZW5kOnN9O2lmKG89by5wb3MsYT1hLnBvcyxvLmxpbmU9PWEubGluZSYmby5jaD5hLmNofHxvLmxpbmU+YS5saW5lKXt2YXIgZj1vO289YSxhPWZ9cmV0dXJuIGk/YS5jaCs9MTpvLmNoKz0xLHtzdGFydDpvLGVuZDphfX1mdW5jdGlvbiBPZShlLHQsbixpKXt2YXIgbyxhLHMsdSxjPVEodCksbD1lLmdldExpbmUoYy5saW5lKSxwPWwuc3BsaXQoIiIpLGY9cC5pbmRleE9mKG4pO2lmKGMuY2g8Zj9jLmNoPWY6ZjxjLmNoJiZwW2MuY2hdPT1uJiYoYT1jLmNoLC0tYy5jaCkscFtjLmNoXSE9bnx8YSlmb3Iocz1jLmNoO3M+LTEmJiFvO3MtLSlwW3NdPT1uJiYobz1zKzEpO2Vsc2Ugbz1jLmNoKzE7aWYobyYmIWEpZm9yKHM9byx1PXAubGVuZ3RoO3M8dSYmIWE7cysrKXBbc109PW4mJihhPXMpO3JldHVybiBvJiZhPyhpJiYoLS1vLCsrYSkse3N0YXJ0OnIoYy5saW5lLG8pLGVuZDpyKGMubGluZSxhKX0pOntzdGFydDpjLGVuZDpjfX1mdW5jdGlvbiBGZSgpe31mdW5jdGlvbiBOZShlKXt2YXIgdD1lLnN0YXRlLnZpbTtyZXR1cm4gdC5zZWFyY2hTdGF0ZV98fCh0LnNlYXJjaFN0YXRlXz1uZXcgRmUpfWZ1bmN0aW9uIEllKGUsdCxuLHIsaSl7ZS5vcGVuRGlhbG9nP2Uub3BlbkRpYWxvZyh0LHIse2JvdHRvbTohMCx2YWx1ZTppLnZhbHVlLG9uS2V5RG93bjppLm9uS2V5RG93bixvbktleVVwOmkub25LZXlVcCxzZWxlY3RWYWx1ZU9uT3BlbjohMX0pOnIocHJvbXB0KG4sIiIpKX1mdW5jdGlvbiBMZShlKXtyZXR1cm4gTWUoZSwiLyIpfWZ1bmN0aW9uIFBlKGUpe3JldHVybiBqZShlLCIvIil9ZnVuY3Rpb24gTWUoZSx0KXt2YXIgbj1qZShlLHQpfHxbXTtpZighbi5sZW5ndGgpcmV0dXJuW107dmFyIHI9W107aWYoMD09PW5bMF0pe2Zvcih2YXIgaT0wO2k8bi5sZW5ndGg7aSsrKSJudW1iZXIiPT10eXBlb2YgbltpXSYmci5wdXNoKGUuc3Vic3RyaW5nKG5baV0rMSxuW2krMV0pKTtyZXR1cm4gcn19ZnVuY3Rpb24gamUoZSx0KXt0fHwodD0iLyIpO2Zvcih2YXIgbj0hMSxyPVtdLGk9MDtpPGUubGVuZ3RoO2krKyl7dmFyIG89ZS5jaGFyQXQoaSk7bnx8byE9dHx8ci5wdXNoKGkpLG49IW4mJiJcXCI9PW99cmV0dXJuIHJ9ZnVuY3Rpb24gUmUoZSl7Zm9yKHZhciB0PSJ8KCl7IixuPSJ9IixyPSExLGk9W10sbz0tMTtvPGUubGVuZ3RoO28rKyl7dmFyIGE9ZS5jaGFyQXQobyl8fCIiLHM9ZS5jaGFyQXQobysxKXx8IiIsdT1zJiYtMSE9dC5pbmRleE9mKHMpO3I/KCJcXCI9PT1hJiZ1fHxpLnB1c2goYSkscj0hMSk6IlxcIj09PWE/KHI9ITAscyYmLTEhPW4uaW5kZXhPZihzKSYmKHU9ITApLHUmJiJcXCIhPT1zfHxpLnB1c2goYSkpOihpLnB1c2goYSksdSYmIlxcIiE9PXMmJmkucHVzaCgiXFwiKSl9cmV0dXJuIGkuam9pbigiIil9ZnVuY3Rpb24gQmUoZSl7Zm9yKHZhciB0PSExLG49W10scj0tMTtyPGUubGVuZ3RoO3IrKyl7dmFyIGk9ZS5jaGFyQXQocil8fCIiLG89ZS5jaGFyQXQocisxKXx8IiI7UnRbaStvXT8obi5wdXNoKFJ0W2krb10pLHIrKyk6dD8obi5wdXNoKGkpLHQ9ITEpOiJcXCI9PT1pPyh0PSEwLGIobyl8fCIkIj09PW8/bi5wdXNoKCIkIik6Ii8iIT09byYmIlxcIiE9PW8mJm4ucHVzaCgiXFwiKSk6KCIkIj09PWkmJm4ucHVzaCgiJCIpLG4ucHVzaChpKSwiLyI9PT1vJiZuLnB1c2goIlxcIikpfXJldHVybiBuLmpvaW4oIiIpfWZ1bmN0aW9uICRlKHQpe2Zvcih2YXIgbj1uZXcgZS5TdHJpbmdTdHJlYW0odCkscj1bXTshbi5lb2woKTspe2Zvcig7bi5wZWVrKCkmJiJcXCIhPW4ucGVlaygpOylyLnB1c2gobi5uZXh0KCkpO3ZhciBpPSExO2Zvcih2YXIgbyBpbiBCdClpZihuLm1hdGNoKG8sITApKXtpPSEwLHIucHVzaChCdFtvXSk7YnJlYWt9aXx8ci5wdXNoKG4ubmV4dCgpKX1yZXR1cm4gci5qb2luKCIiKX1mdW5jdGlvbiBVZShlLHQsbil7aWYoVHQucmVnaXN0ZXJDb250cm9sbGVyLmdldFJlZ2lzdGVyKCIvIikuc2V0VGV4dChlKSxlIGluc3RhbmNlb2YgUmVnRXhwKXJldHVybiBlO3ZhciByLGksbz1QZShlKTtpZihvLmxlbmd0aCl7cj1lLnN1YnN0cmluZygwLG9bMF0pO2k9LTEhPWUuc3Vic3RyaW5nKG9bMF0pLmluZGV4T2YoImkiKX1lbHNlIHI9ZTtyZXR1cm4gcj8oaygicGNyZSIpfHwocj1SZShyKSksbiYmKHQ9L15bXkEtWl0qJC8udGVzdChyKSksbmV3IFJlZ0V4cChyLHR8fGk/ImkiOnZvaWQgMCkpOm51bGx9ZnVuY3Rpb24gemUoZSx0KXtlLm9wZW5Ob3RpZmljYXRpb24/ZS5vcGVuTm90aWZpY2F0aW9uKCc8c3BhbiBzdHlsZT0iY29sb3I6IHJlZCI+Jyt0KyI8L3NwYW4+Iix7Ym90dG9tOiEwLGR1cmF0aW9uOjVlM30pOmFsZXJ0KHQpfWZ1bmN0aW9uIEdlKGUsdCl7dmFyIG49JzxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogbW9ub3NwYWNlOyB3aGl0ZS1zcGFjZTogcHJlIj4nKyhlfHwiIikrJzxpbnB1dCB0eXBlPSJ0ZXh0Ij48L3NwYW4+JztyZXR1cm4gdCYmKG4rPScgPHNwYW4gc3R5bGU9ImNvbG9yOiAjODg4Ij4nK3QrIjwvc3Bhbj4iKSxufWZ1bmN0aW9uIFZlKGUsdCl7dmFyIG49KHQucHJlZml4fHwiIikrIiAiKyh0LmRlc2N8fCIiKTtJZShlLEdlKHQucHJlZml4LHQuZGVzYyksbix0Lm9uQ2xvc2UsdCl9ZnVuY3Rpb24gcWUoZSx0KXtpZihlIGluc3RhbmNlb2YgUmVnRXhwJiZ0IGluc3RhbmNlb2YgUmVnRXhwKXtmb3IodmFyIG49WyJnbG9iYWwiLCJtdWx0aWxpbmUiLCJpZ25vcmVDYXNlIiwic291cmNlIl0scj0wO3I8bi5sZW5ndGg7cisrKXt2YXIgaT1uW3JdO2lmKGVbaV0hPT10W2ldKXJldHVybiExfXJldHVybiEwfXJldHVybiExfWZ1bmN0aW9uIEhlKGUsdCxuLHIpe2lmKHQpe3ZhciBpPU5lKGUpLG89VWUodCwhIW4sISFyKTtpZihvKXJldHVybiBRZShlLG8pLHFlKG8saS5nZXRRdWVyeSgpKT9vOihpLnNldFF1ZXJ5KG8pLG8pfX1mdW5jdGlvbiBXZShlKXtpZigiXiI9PWUuc291cmNlLmNoYXJBdCgwKSl2YXIgdD0hMDtyZXR1cm57dG9rZW46ZnVuY3Rpb24obil7aWYodCYmIW4uc29sKCkpcmV0dXJuIHZvaWQgbi5za2lwVG9FbmQoKTt2YXIgcj1uLm1hdGNoKGUsITEpO2lmKHIpcmV0dXJuIDA9PXJbMF0ubGVuZ3RoPyhuLm5leHQoKSwic2VhcmNoaW5nIik6bi5zb2woKXx8KG4uYmFja1VwKDEpLGUuZXhlYyhuLm5leHQoKStyWzBdKSk/KG4ubWF0Y2goZSksInNlYXJjaGluZyIpOihuLm5leHQoKSxudWxsKTtmb3IoOyFuLmVvbCgpJiYobi5uZXh0KCksIW4ubWF0Y2goZSwhMSkpOyk7fSxxdWVyeTplfX1mdW5jdGlvbiBRZShlLHQpe3ZhciBuPU5lKGUpLHI9bi5nZXRPdmVybGF5KCk7ciYmdD09ci5xdWVyeXx8KHImJmUucmVtb3ZlT3ZlcmxheShyKSxyPVdlKHQpLGUuYWRkT3ZlcmxheShyKSxlLnNob3dNYXRjaGVzT25TY3JvbGxiYXImJihuLmdldFNjcm9sbGJhckFubm90YXRlKCkmJm4uZ2V0U2Nyb2xsYmFyQW5ub3RhdGUoKS5jbGVhcigpLG4uc2V0U2Nyb2xsYmFyQW5ub3RhdGUoZS5zaG93TWF0Y2hlc09uU2Nyb2xsYmFyKHQpKSksbi5zZXRPdmVybGF5KHIpKX1mdW5jdGlvbiBLZShlLHQsbixpKXtyZXR1cm4gdm9pZCAwPT09aSYmKGk9MSksZS5vcGVyYXRpb24oZnVuY3Rpb24oKXtmb3IodmFyIG89ZS5nZXRDdXJzb3IoKSxhPWUuZ2V0U2VhcmNoQ3Vyc29yKG4sbykscz0wO3M8aTtzKyspe3ZhciB1PWEuZmluZCh0KTtpZigwPT1zJiZ1JiZLKGEuZnJvbSgpLG8pJiYodT1hLmZpbmQodCkpLCF1JiYoYT1lLmdldFNlYXJjaEN1cnNvcihuLHQ/cihlLmxhc3RMaW5lKCkpOnIoZS5maXJzdExpbmUoKSwwKSksIWEuZmluZCh0KSkpcmV0dXJufXJldHVybiBhLmZyb20oKX0pfWZ1bmN0aW9uIEplKGUpe3ZhciB0PU5lKGUpO2UucmVtb3ZlT3ZlcmxheShOZShlKS5nZXRPdmVybGF5KCkpLHQuc2V0T3ZlcmxheShudWxsKSx0LmdldFNjcm9sbGJhckFubm90YXRlKCkmJih0LmdldFNjcm9sbGJhckFubm90YXRlKCkuY2xlYXIoKSx0LnNldFNjcm9sbGJhckFubm90YXRlKG51bGwpKX1mdW5jdGlvbiBZZShlLHQsbil7cmV0dXJuIm51bWJlciIhPXR5cGVvZiBlJiYoZT1lLmxpbmUpLHQgaW5zdGFuY2VvZiBBcnJheT9EKGUsdCk6bj9lPj10JiZlPD1uOmU9PXR9ZnVuY3Rpb24gWGUoZSl7dmFyIHQ9ZS5nZXRTY3JvbGxJbmZvKCksbj1lLmNvb3Jkc0NoYXIoe2xlZnQ6MCx0b3A6Nit0LnRvcH0sImxvY2FsIikscj10LmNsaWVudEhlaWdodC0xMCt0LnRvcCxpPWUuY29vcmRzQ2hhcih7bGVmdDowLHRvcDpyfSwibG9jYWwiKTtyZXR1cm57dG9wOm4ubGluZSxib3R0b206aS5saW5lfX1mdW5jdGlvbiBaZShlLHQsbil7aWYoIiciPT1uKXt2YXIgcj1lLmRvYy5oaXN0b3J5LmRvbmUsaT1yW3IubGVuZ3RoLTJdO3JldHVybiBpJiZpLnJhbmdlcyYmaS5yYW5nZXNbMF0uaGVhZH1pZigiLiI9PW4pe2lmKDA9PWUuZG9jLmhpc3RvcnkubGFzdE1vZFRpbWUpcmV0dXJuO3ZhciBvPWUuZG9jLmhpc3RvcnkuZG9uZS5maWx0ZXIoZnVuY3Rpb24oZSl7aWYodm9pZCAwIT09ZS5jaGFuZ2VzKXJldHVybiBlfSk7by5yZXZlcnNlKCk7cmV0dXJuIG9bMF0uY2hhbmdlc1swXS50b312YXIgYT10Lm1hcmtzW25dO3JldHVybiBhJiZhLmZpbmQoKX1mdW5jdGlvbiBldCh0LG4scixpLG8sYSxzLHUsYyl7ZnVuY3Rpb24gbCgpe3Qub3BlcmF0aW9uKGZ1bmN0aW9uKCl7Zm9yKDshbTspcCgpLGYoKTtkKCl9KX1mdW5jdGlvbiBwKCl7dmFyIGU9dC5nZXRSYW5nZShhLmZyb20oKSxhLnRvKCkpLG49ZS5yZXBsYWNlKHMsdSk7YS5yZXBsYWNlKG4pfWZ1bmN0aW9uIGYoKXtmb3IoO2EuZmluZE5leHQoKSYmWWUoYS5mcm9tKCksaSxvKTspaWYocnx8IWd8fGEuZnJvbSgpLmxpbmUhPWcubGluZSlyZXR1cm4gdC5zY3JvbGxJbnRvVmlldyhhLmZyb20oKSwzMCksdC5zZXRTZWxlY3Rpb24oYS5mcm9tKCksYS50bygpKSxnPWEuZnJvbSgpLHZvaWQobT0hMSk7bT0hMH1mdW5jdGlvbiBkKGUpe2lmKGUmJmUoKSx0LmZvY3VzKCksZyl7dC5zZXRDdXJzb3IoZyk7dmFyIG49dC5zdGF0ZS52aW07bi5leE1vZGU9ITEsbi5sYXN0SFBvcz1uLmxhc3RIU1Bvcz1nLmNofWMmJmMoKX1mdW5jdGlvbiBoKG4scixpKXtzd2l0Y2goZS5lX3N0b3AobiksZS5rZXlOYW1lKG4pKXtjYXNlIlkiOnAoKSxmKCk7YnJlYWs7Y2FzZSJOIjpmKCk7YnJlYWs7Y2FzZSJBIjp2YXIgbz1jO2M9dm9pZCAwLHQub3BlcmF0aW9uKGwpLGM9bzticmVhaztjYXNlIkwiOnAoKTtjYXNlIlEiOmNhc2UiRXNjIjpjYXNlIkN0cmwtQyI6Y2FzZSJDdHJsLVsiOmQoaSl9cmV0dXJuIG0mJmQoaSksITB9dC5zdGF0ZS52aW0uZXhNb2RlPSEwO3ZhciBtPSExLGc9YS5mcm9tKCk7cmV0dXJuIGYoKSxtP3ZvaWQgemUodCwiTm8gbWF0Y2hlcyBmb3IgIitzLnNvdXJjZSk6bj92b2lkIFZlKHQse3ByZWZpeDoicmVwbGFjZSB3aXRoIDxzdHJvbmc+Iit1KyI8L3N0cm9uZz4gKHkvbi9hL3EvbCkiLG9uS2V5RG93bjpofSk6KGwoKSx2b2lkKGMmJmMoKSkpfWZ1bmN0aW9uIHR0KHQpe3ZhciBuPXQuc3RhdGUudmltLHI9VHQubWFjcm9Nb2RlU3RhdGUsaT1UdC5yZWdpc3RlckNvbnRyb2xsZXIuZ2V0UmVnaXN0ZXIoIi4iKSxvPXIuaXNQbGF5aW5nLGE9ci5sYXN0SW5zZXJ0TW9kZUNoYW5nZXMscz1bXTtpZighbyl7Zm9yKHZhciB1PWEuaW5WaXN1YWxCbG9jayYmbi5sYXN0U2VsZWN0aW9uP24ubGFzdFNlbGVjdGlvbi52aXN1YWxCbG9jay5oZWlnaHQ6MSxjPWEuY2hhbmdlcyxzPVtdLGw9MDtsPGMubGVuZ3RoOylzLnB1c2goY1tsXSksY1tsXWluc3RhbmNlb2YgZnQ/bCsrOmwrPXU7YS5jaGFuZ2VzPXMsdC5vZmYoImNoYW5nZSIsdXQpLGUub2ZmKHQuZ2V0SW5wdXRGaWVsZCgpLCJrZXlkb3duIixkdCl9IW8mJm4uaW5zZXJ0TW9kZVJlcGVhdD4xJiYoaHQodCxuLG4uaW5zZXJ0TW9kZVJlcGVhdC0xLCEwKSxuLmxhc3RFZGl0SW5wdXRTdGF0ZS5yZXBlYXRPdmVycmlkZT1uLmluc2VydE1vZGVSZXBlYXQpLGRlbGV0ZSBuLmluc2VydE1vZGVSZXBlYXQsbi5pbnNlcnRNb2RlPSExLHQuc2V0Q3Vyc29yKHQuZ2V0Q3Vyc29yKCkubGluZSx0LmdldEN1cnNvcigpLmNoLTEpLHQuc2V0T3B0aW9uKCJrZXlNYXAiLCJ2aW0iKSx0LnNldE9wdGlvbigiZGlzYWJsZUlucHV0IiwhMCksdC50b2dnbGVPdmVyd3JpdGUoITEpLGkuc2V0VGV4dChhLmNoYW5nZXMuam9pbigiIikpLGUuc2lnbmFsKHQsInZpbS1tb2RlLWNoYW5nZSIse21vZGU6Im5vcm1hbCJ9KSxyLmlzUmVjb3JkaW5nJiZhdChyKX1mdW5jdGlvbiBudChlKXt0LnVuc2hpZnQoZSl9ZnVuY3Rpb24gcnQoZSx0LG4scixpKXt2YXIgbz17a2V5czplLHR5cGU6dH07b1t0XT1uLG9bdCsiQXJncyJdPXI7Zm9yKHZhciBhIGluIGkpb1thXT1pW2FdO250KG8pfWZ1bmN0aW9uIGl0KHQsbixyLGkpe3ZhciBvPVR0LnJlZ2lzdGVyQ29udHJvbGxlci5nZXRSZWdpc3RlcihpKTtpZigiOiI9PWkpcmV0dXJuIG8ua2V5QnVmZmVyWzBdJiZHdC5wcm9jZXNzQ29tbWFuZCh0LG8ua2V5QnVmZmVyWzBdKSx2b2lkKHIuaXNQbGF5aW5nPSExKTt2YXIgYT1vLmtleUJ1ZmZlcixzPTA7ci5pc1BsYXlpbmc9ITAsci5yZXBsYXlTZWFyY2hRdWVyaWVzPW8uc2VhcmNoUXVlcmllcy5zbGljZSgwKTtmb3IodmFyIHU9MDt1PGEubGVuZ3RoO3UrKylmb3IodmFyIGMsbCxwPWFbdV07cDspaWYoYz0vPFx3Ky0uKz8+fDxcdys+fC4vLmV4ZWMocCksbD1jWzBdLHA9cC5zdWJzdHJpbmcoYy5pbmRleCtsLmxlbmd0aCksZS5WaW0uaGFuZGxlS2V5KHQsbCwibWFjcm8iKSxuLmluc2VydE1vZGUpe3ZhciBmPW8uaW5zZXJ0TW9kZUNoYW5nZXNbcysrXS5jaGFuZ2VzO1R0Lm1hY3JvTW9kZVN0YXRlLmxhc3RJbnNlcnRNb2RlQ2hhbmdlcy5jaGFuZ2VzPWYsbXQodCxmLDEpLHR0KHQpfXIuaXNQbGF5aW5nPSExfWZ1bmN0aW9uIG90KGUsdCl7aWYoIWUuaXNQbGF5aW5nKXt2YXIgbj1lLmxhdGVzdFJlZ2lzdGVyLHI9VHQucmVnaXN0ZXJDb250cm9sbGVyLmdldFJlZ2lzdGVyKG4pO3ImJnIucHVzaFRleHQodCl9fWZ1bmN0aW9uIGF0KGUpe2lmKCFlLmlzUGxheWluZyl7dmFyIHQ9ZS5sYXRlc3RSZWdpc3RlcixuPVR0LnJlZ2lzdGVyQ29udHJvbGxlci5nZXRSZWdpc3Rlcih0KTtuJiZuLnB1c2hJbnNlcnRNb2RlQ2hhbmdlcyYmbi5wdXNoSW5zZXJ0TW9kZUNoYW5nZXMoZS5sYXN0SW5zZXJ0TW9kZUNoYW5nZXMpfX1mdW5jdGlvbiBzdChlLHQpe2lmKCFlLmlzUGxheWluZyl7dmFyIG49ZS5sYXRlc3RSZWdpc3RlcixyPVR0LnJlZ2lzdGVyQ29udHJvbGxlci5nZXRSZWdpc3RlcihuKTtyJiZyLnB1c2hTZWFyY2hRdWVyeSYmci5wdXNoU2VhcmNoUXVlcnkodCl9fWZ1bmN0aW9uIHV0KGUsdCl7dmFyIG49VHQubWFjcm9Nb2RlU3RhdGUscj1uLmxhc3RJbnNlcnRNb2RlQ2hhbmdlcztpZighbi5pc1BsYXlpbmcpZm9yKDt0Oyl7aWYoci5leHBlY3RDdXJzb3JBY3Rpdml0eUZvckNoYW5nZT0hMCwiK2lucHV0Ij09dC5vcmlnaW58fCJwYXN0ZSI9PXQub3JpZ2lufHx2b2lkIDA9PT10Lm9yaWdpbil7dmFyIGk9dC50ZXh0LmpvaW4oIlxuIik7ci5tYXliZVJlc2V0JiYoci5jaGFuZ2VzPVtdLHIubWF5YmVSZXNldD0hMSksZS5zdGF0ZS5vdmVyd3JpdGUmJiEvXG4vLnRlc3QoaSk/ci5jaGFuZ2VzLnB1c2goW2ldKTpyLmNoYW5nZXMucHVzaChpKX10PXQubmV4dH19ZnVuY3Rpb24gY3QoZSl7dmFyIHQ9ZS5zdGF0ZS52aW07aWYodC5pbnNlcnRNb2RlKXt2YXIgbj1UdC5tYWNyb01vZGVTdGF0ZTtpZihuLmlzUGxheWluZylyZXR1cm47dmFyIHI9bi5sYXN0SW5zZXJ0TW9kZUNoYW5nZXM7ci5leHBlY3RDdXJzb3JBY3Rpdml0eUZvckNoYW5nZT9yLmV4cGVjdEN1cnNvckFjdGl2aXR5Rm9yQ2hhbmdlPSExOnIubWF5YmVSZXNldD0hMH1lbHNlIGUuY3VyT3AuaXNWaW1PcHx8cHQoZSx0KTt0LnZpc3VhbE1vZGUmJmx0KGUpfWZ1bmN0aW9uIGx0KGUpe3ZhciB0PWUuc3RhdGUudmltLG49JChlLFEodC5zZWwuaGVhZCkpLHI9eihuLDAsMSk7dC5mYWtlQ3Vyc29yJiZ0LmZha2VDdXJzb3IuY2xlYXIoKSx0LmZha2VDdXJzb3I9ZS5tYXJrVGV4dChuLHIse2NsYXNzTmFtZToiY20tYW5pbWF0ZS1mYXQtY3Vyc29yIn0pfWZ1bmN0aW9uIHB0KHQsbil7dmFyIHI9dC5nZXRDdXJzb3IoImFuY2hvciIpLGk9dC5nZXRDdXJzb3IoImhlYWQiKTtpZihuLnZpc3VhbE1vZGUmJiF0LnNvbWV0aGluZ1NlbGVjdGVkKCk/ZGUodCwhMSk6bi52aXN1YWxNb2RlfHxuLmluc2VydE1vZGV8fCF0LnNvbWV0aGluZ1NlbGVjdGVkKCl8fChuLnZpc3VhbE1vZGU9ITAsbi52aXN1YWxMaW5lPSExLGUuc2lnbmFsKHQsInZpbS1tb2RlLWNoYW5nZSIse21vZGU6InZpc3VhbCJ9KSksbi52aXN1YWxNb2RlKXt2YXIgbz1KKGkscik/MDotMSxhPUooaSxyKT8tMTowO2k9eihpLDAsbykscj16KHIsMCxhKSxuLnNlbD17YW5jaG9yOnIsaGVhZDppfSxTZSh0LG4sIjwiLFkoaSxyKSksU2UodCxuLCI+IixYKGkscikpfWVsc2Ugbi5pbnNlcnRNb2RlfHwobi5sYXN0SFBvcz10LmdldEN1cnNvcigpLmNoKX1mdW5jdGlvbiBmdChlKXt0aGlzLmtleU5hbWU9ZX1mdW5jdGlvbiBkdCh0KXtmdW5jdGlvbiBuKCl7cmV0dXJuIGkubWF5YmVSZXNldCYmKGkuY2hhbmdlcz1bXSxpLm1heWJlUmVzZXQ9ITEpLGkuY2hhbmdlcy5wdXNoKG5ldyBmdChvKSksITB9dmFyIHI9VHQubWFjcm9Nb2RlU3RhdGUsaT1yLmxhc3RJbnNlcnRNb2RlQ2hhbmdlcyxvPWUua2V5TmFtZSh0KTtvJiYoLTE9PW8uaW5kZXhPZigiRGVsZXRlIikmJi0xPT1vLmluZGV4T2YoIkJhY2tzcGFjZSIpfHxlLmxvb2t1cEtleShvLCJ2aW0taW5zZXJ0IixuKSl9ZnVuY3Rpb24gaHQoZSx0LG4scil7ZnVuY3Rpb24gaSgpe3M/TnQucHJvY2Vzc0FjdGlvbihlLHQsdC5sYXN0RWRpdEFjdGlvbkNvbW1hbmQpOk50LmV2YWxJbnB1dChlLHQpfWZ1bmN0aW9uIG8obil7aWYoYS5sYXN0SW5zZXJ0TW9kZUNoYW5nZXMuY2hhbmdlcy5sZW5ndGg+MCl7bj10Lmxhc3RFZGl0QWN0aW9uQ29tbWFuZD9uOjE7dmFyIHI9YS5sYXN0SW5zZXJ0TW9kZUNoYW5nZXM7bXQoZSxyLmNoYW5nZXMsbil9fXZhciBhPVR0Lm1hY3JvTW9kZVN0YXRlO2EuaXNQbGF5aW5nPSEwO3ZhciBzPSEhdC5sYXN0RWRpdEFjdGlvbkNvbW1hbmQsdT10LmlucHV0U3RhdGU7aWYodC5pbnB1dFN0YXRlPXQubGFzdEVkaXRJbnB1dFN0YXRlLHMmJnQubGFzdEVkaXRBY3Rpb25Db21tYW5kLmludGVybGFjZUluc2VydFJlcGVhdClmb3IodmFyIGM9MDtjPG47YysrKWkoKSxvKDEpO2Vsc2Ugcnx8aSgpLG8obik7dC5pbnB1dFN0YXRlPXUsdC5pbnNlcnRNb2RlJiYhciYmdHQoZSksYS5pc1BsYXlpbmc9ITF9ZnVuY3Rpb24gbXQodCxuLHIpe2Z1bmN0aW9uIGkobil7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBuP2UuY29tbWFuZHNbbl0odCk6bih0KSwhMH12YXIgbz10LmdldEN1cnNvcigiaGVhZCIpLGE9VHQubWFjcm9Nb2RlU3RhdGUubGFzdEluc2VydE1vZGVDaGFuZ2VzLmluVmlzdWFsQmxvY2s7aWYoYSl7dmFyIHM9dC5zdGF0ZS52aW0sdT1zLmxhc3RTZWxlY3Rpb24sYz1HKHUuYW5jaG9yLHUuaGVhZCk7b2UodCxvLGMubGluZSsxKSxyPXQubGlzdFNlbGVjdGlvbnMoKS5sZW5ndGgsdC5zZXRDdXJzb3Iobyl9Zm9yKHZhciBsPTA7bDxyO2wrKyl7YSYmdC5zZXRDdXJzb3IoeihvLGwsMCkpO2Zvcih2YXIgcD0wO3A8bi5sZW5ndGg7cCsrKXt2YXIgZj1uW3BdO2lmKGYgaW5zdGFuY2VvZiBmdCllLmxvb2t1cEtleShmLmtleU5hbWUsInZpbS1pbnNlcnQiLGkpO2Vsc2UgaWYoInN0cmluZyI9PXR5cGVvZiBmKXt2YXIgZD10LmdldEN1cnNvcigpO3QucmVwbGFjZVJhbmdlKGYsZCxkKX1lbHNle3ZhciBoPXQuZ2V0Q3Vyc29yKCksbT16KGgsMCxmWzBdLmxlbmd0aCk7dC5yZXBsYWNlUmFuZ2UoZlswXSxoLG0pfX19YSYmdC5zZXRDdXJzb3IoeihvLDAsMSkpfWUuZGVmaW5lT3B0aW9uKCJ2aW1Nb2RlIiwhMSxmdW5jdGlvbih0LG4scil7biYmInZpbSIhPXQuZ2V0T3B0aW9uKCJrZXlNYXAiKT90LnNldE9wdGlvbigia2V5TWFwIiwidmltIik6IW4mJnIhPWUuSW5pdCYmL152aW0vLnRlc3QodC5nZXRPcHRpb24oImtleU1hcCIpKSYmdC5zZXRPcHRpb24oImtleU1hcCIsImRlZmF1bHQiKX0pO3ZhciBndD17U2hpZnQ6IlMiLEN0cmw6IkMiLEFsdDoiQSIsQ21kOiJEIixNb2Q6IkEifSx5dD17RW50ZXI6IkNSIixCYWNrc3BhY2U6IkJTIixEZWxldGU6IkRlbCIsSW5zZXJ0OiJJbnMifSx2dD0vW1xkXS8sYnQ9W2UuaXNXb3JkQ2hhcixmdW5jdGlvbih0KXtyZXR1cm4gdCYmIWUuaXNXb3JkQ2hhcih0KSYmIS9ccy8udGVzdCh0KX1dLHh0PVtmdW5jdGlvbihlKXtyZXR1cm4vXFMvLnRlc3QoZSl9XSxDdD1tKDY1LDI2KSxFdD1tKDk3LDI2KSxEdD1tKDQ4LDEwKSx3dD1bXS5jb25jYXQoQ3QsRXQsRHQsWyI8IiwiPiJdKSxTdD1bXS5jb25jYXQoQ3QsRXQsRHQsWyItIiwnIicsIi4iLCI6IiwiLyJdKSxrdD17fTt3KCJmaWxldHlwZSIsdm9pZCAwLCJzdHJpbmciLFsiZnQiXSxmdW5jdGlvbihlLHQpe2lmKHZvaWQgMCE9PXQpe2lmKHZvaWQgMD09PWUpe3ZhciBuPXQuZ2V0T3B0aW9uKCJtb2RlIik7cmV0dXJuIm51bGwiPT1uPyIiOm59dmFyIG49IiI9PWU/Im51bGwiOmU7dC5zZXRPcHRpb24oIm1vZGUiLG4pfX0pO3ZhciBBdD1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0LHMpe2Z1bmN0aW9uIHUodCl7dmFyIGk9KytyJW4sbz1hW2ldO28mJm8uY2xlYXIoKSxhW2ldPWUuc2V0Qm9va21hcmsodCl9dmFyIGM9ciVuLGw9YVtjXTtpZihsKXt2YXIgcD1sLmZpbmQoKTtwJiYhSyhwLHQpJiZ1KHQpfWVsc2UgdSh0KTt1KHMpLGk9ciwobz1yLW4rMSk8MCYmKG89MCl9ZnVuY3Rpb24gdChlLHQpe3IrPXQscj5pP3I9aTpyPG8mJihyPW8pO3ZhciBzPWFbKG4rciklbl07aWYocyYmIXMuZmluZCgpKXt2YXIgdSxjPXQ+MD8xOi0xLGw9ZS5nZXRDdXJzb3IoKTtkb3tpZihyKz1jLChzPWFbKG4rciklbl0pJiYodT1zLmZpbmQoKSkmJiFLKGwsdSkpYnJlYWt9d2hpbGUocjxpJiZyPm8pfXJldHVybiBzfXZhciBuPTEwMCxyPS0xLGk9MCxvPTAsYT1uZXcgQXJyYXkobik7cmV0dXJue2NhY2hlZEN1cnNvcjp2b2lkIDAsYWRkOmUsbW92ZTp0fX0sX3Q9ZnVuY3Rpb24oZSl7cmV0dXJuIGU/e2NoYW5nZXM6ZS5jaGFuZ2VzLGV4cGVjdEN1cnNvckFjdGl2aXR5Rm9yQ2hhbmdlOmUuZXhwZWN0Q3Vyc29yQWN0aXZpdHlGb3JDaGFuZ2V9OntjaGFuZ2VzOltdLGV4cGVjdEN1cnNvckFjdGl2aXR5Rm9yQ2hhbmdlOiExfX07QS5wcm90b3R5cGU9e2V4aXRNYWNyb1JlY29yZE1vZGU6ZnVuY3Rpb24oKXt2YXIgZT1UdC5tYWNyb01vZGVTdGF0ZTtlLm9uUmVjb3JkaW5nRG9uZSYmZS5vblJlY29yZGluZ0RvbmUoKSxlLm9uUmVjb3JkaW5nRG9uZT12b2lkIDAsZS5pc1JlY29yZGluZz0hMX0sZW50ZXJNYWNyb1JlY29yZE1vZGU6ZnVuY3Rpb24oZSx0KXt2YXIgbj1UdC5yZWdpc3RlckNvbnRyb2xsZXIuZ2V0UmVnaXN0ZXIodCk7biYmKG4uY2xlYXIoKSx0aGlzLmxhdGVzdFJlZ2lzdGVyPXQsZS5vcGVuRGlhbG9nJiYodGhpcy5vblJlY29yZGluZ0RvbmU9ZS5vcGVuRGlhbG9nKCIocmVjb3JkaW5nKVsiK3QrIl0iLG51bGwse2JvdHRvbTohMH0pKSx0aGlzLmlzUmVjb3JkaW5nPSEwKX19O3ZhciBUdCxPdCxGdD17YnVpbGRLZXlNYXA6ZnVuY3Rpb24oKXt9LGdldFJlZ2lzdGVyQ29udHJvbGxlcjpmdW5jdGlvbigpe3JldHVybiBUdC5yZWdpc3RlckNvbnRyb2xsZXJ9LHJlc2V0VmltR2xvYmFsU3RhdGVfOlQsZ2V0VmltR2xvYmFsU3RhdGVfOmZ1bmN0aW9uKCl7cmV0dXJuIFR0fSxtYXliZUluaXRWaW1TdGF0ZV86XyxzdXBwcmVzc0Vycm9yTG9nZ2luZzohMSxJbnNlcnRNb2RlS2V5OmZ0LG1hcDpmdW5jdGlvbihlLHQsbil7R3QubWFwKGUsdCxuKX0sdW5tYXA6ZnVuY3Rpb24oZSx0KXtHdC51bm1hcChlLHQpfSxzZXRPcHRpb246UyxnZXRPcHRpb246ayxkZWZpbmVPcHRpb246dyxkZWZpbmVFeDpmdW5jdGlvbihlLHQsbil7aWYodCl7aWYoMCE9PWUuaW5kZXhPZih0KSl0aHJvdyBuZXcgRXJyb3IoJyhWaW0uZGVmaW5lRXgpICInK3QrJyIgaXMgbm90IGEgcHJlZml4IG9mICInK2UrJyIsIGNvbW1hbmQgbm90IHJlZ2lzdGVyZWQnKX1lbHNlIHQ9ZTt6dFtlXT1uLEd0LmNvbW1hbmRNYXBfW3RdPXtuYW1lOmUsc2hvcnROYW1lOnQsdHlwZToiYXBpIn19LGhhbmRsZUtleTpmdW5jdGlvbihlLHQsbil7dmFyIHI9dGhpcy5maW5kS2V5KGUsdCxuKTtpZigiZnVuY3Rpb24iPT09dHlwZW9mIHIpcmV0dXJuIHIoKX0sZmluZEtleTpmdW5jdGlvbihuLHIsaSl7ZnVuY3Rpb24gbygpe3ZhciBlPVR0Lm1hY3JvTW9kZVN0YXRlO2lmKGUuaXNSZWNvcmRpbmcpe2lmKCJxIj09cilyZXR1cm4gZS5leGl0TWFjcm9SZWNvcmRNb2RlKCksRihuKSwhMDsibWFwcGluZyIhPWkmJm90KGUscil9fWZ1bmN0aW9uIGEoKXtpZigiPEVzYz4iPT1yKXJldHVybiBGKG4pLGMudmlzdWFsTW9kZT9kZShuKTpjLmluc2VydE1vZGUmJnR0KG4pLCEwfWZ1bmN0aW9uIHModCl7Zm9yKHZhciBpO3Q7KWk9LzxcdystLis/Pnw8XHcrPnwuLy5leGVjKHQpLHI9aVswXSx0PXQuc3Vic3RyaW5nKGkuaW5kZXgrci5sZW5ndGgpLGUuVmltLmhhbmRsZUtleShuLHIsIm1hcHBpbmciKX12YXIgdSxjPV8obik7cmV0dXJuIHU9Yy5pbnNlcnRNb2RlP2Z1bmN0aW9uKCl7aWYoYSgpKXJldHVybiEwO2Zvcih2YXIgZT1jLmlucHV0U3RhdGUua2V5QnVmZmVyPWMuaW5wdXRTdGF0ZS5rZXlCdWZmZXIrcixpPTE9PXIubGVuZ3RoLG89TnQubWF0Y2hDb21tYW5kKGUsdCxjLmlucHV0U3RhdGUsImluc2VydCIpO2UubGVuZ3RoPjEmJiJmdWxsIiE9by50eXBlOyl7dmFyIGU9Yy5pbnB1dFN0YXRlLmtleUJ1ZmZlcj1lLnNsaWNlKDEpLHM9TnQubWF0Y2hDb21tYW5kKGUsdCxjLmlucHV0U3RhdGUsImluc2VydCIpOyJub25lIiE9cy50eXBlJiYobz1zKX1pZigibm9uZSI9PW8udHlwZSlyZXR1cm4gRihuKSwhMTtpZigicGFydGlhbCI9PW8udHlwZSlyZXR1cm4gT3QmJndpbmRvdy5jbGVhclRpbWVvdXQoT3QpLE90PXdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7Yy5pbnNlcnRNb2RlJiZjLmlucHV0U3RhdGUua2V5QnVmZmVyJiZGKG4pfSxrKCJpbnNlcnRNb2RlRXNjS2V5c1RpbWVvdXQiKSksIWk7aWYoT3QmJndpbmRvdy5jbGVhclRpbWVvdXQoT3QpLGkpe2Zvcih2YXIgdT1uLmxpc3RTZWxlY3Rpb25zKCksbD0wO2w8dS5sZW5ndGg7bCsrKXt2YXIgcD11W2xdLmhlYWQ7bi5yZXBsYWNlUmFuZ2UoIiIseihwLDAsLShlLmxlbmd0aC0xKSkscCwiK2lucHV0Iil9VHQubWFjcm9Nb2RlU3RhdGUubGFzdEluc2VydE1vZGVDaGFuZ2VzLmNoYW5nZXMucG9wKCl9cmV0dXJuIEYobiksby5jb21tYW5kfSgpOmZ1bmN0aW9uKCl7aWYobygpfHxhKCkpcmV0dXJuITA7dmFyIGU9Yy5pbnB1dFN0YXRlLmtleUJ1ZmZlcj1jLmlucHV0U3RhdGUua2V5QnVmZmVyK3I7aWYoL15bMS05XVxkKiQvLnRlc3QoZSkpcmV0dXJuITA7dmFyIGk9L14oXGQqKSguKikkLy5leGVjKGUpO2lmKCFpKXJldHVybiBGKG4pLCExO3ZhciBzPWMudmlzdWFsTW9kZT8idmlzdWFsIjoibm9ybWFsIix1PU50Lm1hdGNoQ29tbWFuZChpWzJdfHxpWzFdLHQsYy5pbnB1dFN0YXRlLHMpO2lmKCJub25lIj09dS50eXBlKXJldHVybiBGKG4pLCExO2lmKCJwYXJ0aWFsIj09dS50eXBlKXJldHVybiEwO2MuaW5wdXRTdGF0ZS5rZXlCdWZmZXI9IiI7dmFyIGk9L14oXGQqKSguKikkLy5leGVjKGUpO3JldHVybiBpWzFdJiYiMCIhPWlbMV0mJmMuaW5wdXRTdGF0ZS5wdXNoUmVwZWF0RGlnaXQoaVsxXSksdS5jb21tYW5kfSgpLCExPT09dT9jLmluc2VydE1vZGV8fDEhPT1yLmxlbmd0aD92b2lkIDA6ZnVuY3Rpb24oKXtyZXR1cm4hMH06ITA9PT11P2Z1bmN0aW9uKCl7cmV0dXJuITB9OmZ1bmN0aW9uKCl7cmV0dXJuIG4ub3BlcmF0aW9uKGZ1bmN0aW9uKCl7bi5jdXJPcC5pc1ZpbU9wPSEwO3RyeXsia2V5VG9LZXkiPT11LnR5cGU/cyh1LnRvS2V5cyk6TnQucHJvY2Vzc0NvbW1hbmQobixjLHUpfWNhdGNoKHQpe3Rocm93IG4uc3RhdGUudmltPXZvaWQgMCxfKG4pLGUuVmltLnN1cHByZXNzRXJyb3JMb2dnaW5nfHxjb25zb2xlLmxvZyh0KSx0fXJldHVybiEwfSl9fSxoYW5kbGVFeDpmdW5jdGlvbihlLHQpe0d0LnByb2Nlc3NDb21tYW5kKGUsdCl9LGRlZmluZU1vdGlvbjpNLGRlZmluZUFjdGlvbjpCLGRlZmluZU9wZXJhdG9yOlIsbWFwQ29tbWFuZDpydCxfbWFwQ29tbWFuZDpudCxkZWZpbmVSZWdpc3RlcjpJLGV4aXRWaXN1YWxNb2RlOmRlLGV4aXRJbnNlcnRNb2RlOnR0fTtPLnByb3RvdHlwZS5wdXNoUmVwZWF0RGlnaXQ9ZnVuY3Rpb24oZSl7dGhpcy5vcGVyYXRvcj90aGlzLm1vdGlvblJlcGVhdD10aGlzLm1vdGlvblJlcGVhdC5jb25jYXQoZSk6dGhpcy5wcmVmaXhSZXBlYXQ9dGhpcy5wcmVmaXhSZXBlYXQuY29uY2F0KGUpfSxPLnByb3RvdHlwZS5nZXRSZXBlYXQ9ZnVuY3Rpb24oKXt2YXIgZT0wO3JldHVybih0aGlzLnByZWZpeFJlcGVhdC5sZW5ndGg+MHx8dGhpcy5tb3Rpb25SZXBlYXQubGVuZ3RoPjApJiYoZT0xLHRoaXMucHJlZml4UmVwZWF0Lmxlbmd0aD4wJiYoZSo9cGFyc2VJbnQodGhpcy5wcmVmaXhSZXBlYXQuam9pbigiIiksMTApKSx0aGlzLm1vdGlvblJlcGVhdC5sZW5ndGg+MCYmKGUqPXBhcnNlSW50KHRoaXMubW90aW9uUmVwZWF0LmpvaW4oIiIpLDEwKSkpLGV9LE4ucHJvdG90eXBlPXtzZXRUZXh0OmZ1bmN0aW9uKGUsdCxuKXt0aGlzLmtleUJ1ZmZlcj1bZXx8IiJdLHRoaXMubGluZXdpc2U9ISF0LHRoaXMuYmxvY2t3aXNlPSEhbn0scHVzaFRleHQ6ZnVuY3Rpb24oZSx0KXt0JiYodGhpcy5saW5ld2lzZXx8dGhpcy5rZXlCdWZmZXIucHVzaCgiXG4iKSx0aGlzLmxpbmV3aXNlPSEwKSx0aGlzLmtleUJ1ZmZlci5wdXNoKGUpfSxwdXNoSW5zZXJ0TW9kZUNoYW5nZXM6ZnVuY3Rpb24oZSl7dGhpcy5pbnNlcnRNb2RlQ2hhbmdlcy5wdXNoKF90KGUpKX0scHVzaFNlYXJjaFF1ZXJ5OmZ1bmN0aW9uKGUpe3RoaXMuc2VhcmNoUXVlcmllcy5wdXNoKGUpfSxjbGVhcjpmdW5jdGlvbigpe3RoaXMua2V5QnVmZmVyPVtdLHRoaXMuaW5zZXJ0TW9kZUNoYW5nZXM9W10sdGhpcy5zZWFyY2hRdWVyaWVzPVtdLHRoaXMubGluZXdpc2U9ITF9LHRvU3RyaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMua2V5QnVmZmVyLmpvaW4oIiIpfX0sTC5wcm90b3R5cGU9e3B1c2hUZXh0OmZ1bmN0aW9uKGUsdCxuLHIsaSl7ciYmIlxuIiE9PW4uY2hhckF0KG4ubGVuZ3RoLTEpJiYobis9IlxuIik7dmFyIG89dGhpcy5pc1ZhbGlkUmVnaXN0ZXIoZSk/dGhpcy5nZXRSZWdpc3RlcihlKTpudWxsO2lmKCFvKXtzd2l0Y2godCl7Y2FzZSJ5YW5rIjp0aGlzLnJlZ2lzdGVyc1swXT1uZXcgTihuLHIsaSk7YnJlYWs7Y2FzZSJkZWxldGUiOmNhc2UiY2hhbmdlIjotMT09bi5pbmRleE9mKCJcbiIpP3RoaXMucmVnaXN0ZXJzWyItIl09bmV3IE4obixyKToodGhpcy5zaGlmdE51bWVyaWNSZWdpc3RlcnNfKCksdGhpcy5yZWdpc3RlcnNbMV09bmV3IE4obixyKSl9cmV0dXJuIHZvaWQgdGhpcy51bm5hbWVkUmVnaXN0ZXIuc2V0VGV4dChuLHIsaSl9eChlKT9vLnB1c2hUZXh0KG4scik6by5zZXRUZXh0KG4scixpKSx0aGlzLnVubmFtZWRSZWdpc3Rlci5zZXRUZXh0KG8udG9TdHJpbmcoKSxyKX0sZ2V0UmVnaXN0ZXI6ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMuaXNWYWxpZFJlZ2lzdGVyKGUpPyhlPWUudG9Mb3dlckNhc2UoKSx0aGlzLnJlZ2lzdGVyc1tlXXx8KHRoaXMucmVnaXN0ZXJzW2VdPW5ldyBOKSx0aGlzLnJlZ2lzdGVyc1tlXSk6dGhpcy51bm5hbWVkUmVnaXN0ZXJ9LGlzVmFsaWRSZWdpc3RlcjpmdW5jdGlvbihlKXtyZXR1cm4gZSYmRChlLFN0KX0sc2hpZnROdW1lcmljUmVnaXN0ZXJzXzpmdW5jdGlvbigpe2Zvcih2YXIgZT05O2U+PTI7ZS0tKXRoaXMucmVnaXN0ZXJzW2VdPXRoaXMuZ2V0UmVnaXN0ZXIoIiIrKGUtMSkpfX0sUC5wcm90b3R5cGU9e25leHRNYXRjaDpmdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMuaGlzdG9yeUJ1ZmZlcixyPXQ/LTE6MTtudWxsPT09dGhpcy5pbml0aWFsUHJlZml4JiYodGhpcy5pbml0aWFsUHJlZml4PWUpO2Zvcih2YXIgaT10aGlzLml0ZXJhdG9yK3I7dD9pPj0wOmk8bi5sZW5ndGg7aSs9cilmb3IodmFyIG89bltpXSxhPTA7YTw9by5sZW5ndGg7YSsrKWlmKHRoaXMuaW5pdGlhbFByZWZpeD09by5zdWJzdHJpbmcoMCxhKSlyZXR1cm4gdGhpcy5pdGVyYXRvcj1pLG87cmV0dXJuIGk+PW4ubGVuZ3RoPyh0aGlzLml0ZXJhdG9yPW4ubGVuZ3RoLHRoaXMuaW5pdGlhbFByZWZpeCk6aTwwP2U6dm9pZCAwfSxwdXNoSW5wdXQ6ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5oaXN0b3J5QnVmZmVyLmluZGV4T2YoZSk7dD4tMSYmdGhpcy5oaXN0b3J5QnVmZmVyLnNwbGljZSh0LDEpLGUubGVuZ3RoJiZ0aGlzLmhpc3RvcnlCdWZmZXIucHVzaChlKX0scmVzZXQ6ZnVuY3Rpb24oKXt0aGlzLmluaXRpYWxQcmVmaXg9bnVsbCx0aGlzLml0ZXJhdG9yPXRoaXMuaGlzdG9yeUJ1ZmZlci5sZW5ndGh9fTt2YXIgTnQ9e21hdGNoQ29tbWFuZDpmdW5jdGlvbihlLHQsbixyKXt2YXIgaT1WKGUsdCxyLG4pO2lmKCFpLmZ1bGwmJiFpLnBhcnRpYWwpcmV0dXJue3R5cGU6Im5vbmUifTtpZighaS5mdWxsJiZpLnBhcnRpYWwpcmV0dXJue3R5cGU6InBhcnRpYWwifTtmb3IodmFyIG8sYT0wO2E8aS5mdWxsLmxlbmd0aDthKyspe3ZhciBzPWkuZnVsbFthXTtvfHwobz1zKX1pZigiPGNoYXJhY3Rlcj4iPT1vLmtleXMuc2xpY2UoLTExKSl7dmFyIHU9SChlKTtpZighdSlyZXR1cm57dHlwZToibm9uZSJ9O24uc2VsZWN0ZWRDaGFyYWN0ZXI9dX1yZXR1cm57dHlwZToiZnVsbCIsY29tbWFuZDpvfX0scHJvY2Vzc0NvbW1hbmQ6ZnVuY3Rpb24oZSx0LG4pe3N3aXRjaCh0LmlucHV0U3RhdGUucmVwZWF0T3ZlcnJpZGU9bi5yZXBlYXRPdmVycmlkZSxuLnR5cGUpe2Nhc2UibW90aW9uIjp0aGlzLnByb2Nlc3NNb3Rpb24oZSx0LG4pO2JyZWFrO2Nhc2Uib3BlcmF0b3IiOnRoaXMucHJvY2Vzc09wZXJhdG9yKGUsdCxuKTticmVhaztjYXNlIm9wZXJhdG9yTW90aW9uIjp0aGlzLnByb2Nlc3NPcGVyYXRvck1vdGlvbihlLHQsbik7YnJlYWs7Y2FzZSJhY3Rpb24iOnRoaXMucHJvY2Vzc0FjdGlvbihlLHQsbik7YnJlYWs7Y2FzZSJzZWFyY2giOnRoaXMucHJvY2Vzc1NlYXJjaChlLHQsbik7YnJlYWs7Y2FzZSJleCI6Y2FzZSJrZXlUb0V4Ijp0aGlzLnByb2Nlc3NFeChlLHQsbil9fSxwcm9jZXNzTW90aW9uOmZ1bmN0aW9uKGUsdCxuKXt0LmlucHV0U3RhdGUubW90aW9uPW4ubW90aW9uLHQuaW5wdXRTdGF0ZS5tb3Rpb25BcmdzPVUobi5tb3Rpb25BcmdzKSx0aGlzLmV2YWxJbnB1dChlLHQpfSxwcm9jZXNzT3BlcmF0b3I6ZnVuY3Rpb24oZSx0LG4pe3ZhciByPXQuaW5wdXRTdGF0ZTtpZihyLm9wZXJhdG9yKXtpZihyLm9wZXJhdG9yPT1uLm9wZXJhdG9yKXJldHVybiByLm1vdGlvbj0iZXhwYW5kVG9MaW5lIixyLm1vdGlvbkFyZ3M9e2xpbmV3aXNlOiEwfSx2b2lkIHRoaXMuZXZhbElucHV0KGUsdCk7RihlKX1yLm9wZXJhdG9yPW4ub3BlcmF0b3Isci5vcGVyYXRvckFyZ3M9VShuLm9wZXJhdG9yQXJncyksdC52aXN1YWxNb2RlJiZ0aGlzLmV2YWxJbnB1dChlLHQpfSxwcm9jZXNzT3BlcmF0b3JNb3Rpb246ZnVuY3Rpb24oZSx0LG4pe3ZhciByPXQudmlzdWFsTW9kZSxpPVUobi5vcGVyYXRvck1vdGlvbkFyZ3MpO2kmJnImJmkudmlzdWFsTGluZSYmKHQudmlzdWFsTGluZT0hMCksdGhpcy5wcm9jZXNzT3BlcmF0b3IoZSx0LG4pLHJ8fHRoaXMucHJvY2Vzc01vdGlvbihlLHQsbil9LHByb2Nlc3NBY3Rpb246ZnVuY3Rpb24oZSx0LG4pe3ZhciByPXQuaW5wdXRTdGF0ZSxpPXIuZ2V0UmVwZWF0KCksbz0hIWksYT1VKG4uYWN0aW9uQXJncyl8fHt9O3Iuc2VsZWN0ZWRDaGFyYWN0ZXImJihhLnNlbGVjdGVkQ2hhcmFjdGVyPXIuc2VsZWN0ZWRDaGFyYWN0ZXIpLG4ub3BlcmF0b3ImJnRoaXMucHJvY2Vzc09wZXJhdG9yKGUsdCxuKSxuLm1vdGlvbiYmdGhpcy5wcm9jZXNzTW90aW9uKGUsdCxuKSwobi5tb3Rpb258fG4ub3BlcmF0b3IpJiZ0aGlzLmV2YWxJbnB1dChlLHQpLGEucmVwZWF0PWl8fDEsYS5yZXBlYXRJc0V4cGxpY2l0PW8sYS5yZWdpc3Rlck5hbWU9ci5yZWdpc3Rlck5hbWUsRihlKSx0Lmxhc3RNb3Rpb249bnVsbCxuLmlzRWRpdCYmdGhpcy5yZWNvcmRMYXN0RWRpdCh0LHIsbiksUHRbbi5hY3Rpb25dKGUsYSx0KX0scHJvY2Vzc1NlYXJjaDpmdW5jdGlvbih0LG4scil7ZnVuY3Rpb24gaShlLGksbyl7VHQuc2VhcmNoSGlzdG9yeUNvbnRyb2xsZXIucHVzaElucHV0KGUpLFR0LnNlYXJjaEhpc3RvcnlDb250cm9sbGVyLnJlc2V0KCk7dHJ5e0hlKHQsZSxpLG8pfWNhdGNoKG4pe3JldHVybiB6ZSh0LCJJbnZhbGlkIHJlZ2V4OiAiK2UpLHZvaWQgRih0KX1OdC5wcm9jZXNzTW90aW9uKHQsbix7dHlwZToibW90aW9uIixtb3Rpb246ImZpbmROZXh0Iixtb3Rpb25BcmdzOntmb3J3YXJkOiEwLHRvSnVtcGxpc3Q6ci5zZWFyY2hBcmdzLnRvSnVtcGxpc3R9fSl9ZnVuY3Rpb24gbyhlKXt0LnNjcm9sbFRvKGYubGVmdCxmLnRvcCksaShlLCEwLCEwKTt2YXIgbj1UdC5tYWNyb01vZGVTdGF0ZTtuLmlzUmVjb3JkaW5nJiZzdChuLGUpfWZ1bmN0aW9uIGEobixyLGkpe3ZhciBvLGEscz1lLmtleU5hbWUobik7IlVwIj09c3x8IkRvd24iPT1zPyhvPSJVcCI9PXMsYT1uLnRhcmdldD9uLnRhcmdldC5zZWxlY3Rpb25FbmQ6MCxyPVR0LnNlYXJjaEhpc3RvcnlDb250cm9sbGVyLm5leHRNYXRjaChyLG8pfHwiIixpKHIpLGEmJm4udGFyZ2V0JiYobi50YXJnZXQuc2VsZWN0aW9uRW5kPW4udGFyZ2V0LnNlbGVjdGlvblN0YXJ0PU1hdGgubWluKGEsbi50YXJnZXQudmFsdWUubGVuZ3RoKSkpOiJMZWZ0IiE9cyYmIlJpZ2h0IiE9cyYmIkN0cmwiIT1zJiYiQWx0IiE9cyYmIlNoaWZ0IiE9cyYmVHQuc2VhcmNoSGlzdG9yeUNvbnRyb2xsZXIucmVzZXQoKTt2YXIgYzt0cnl7Yz1IZSh0LHIsITAsITApfWNhdGNoKG4pe31jP3Quc2Nyb2xsSW50b1ZpZXcoS2UodCwhdSxjKSwzMCk6KEplKHQpLHQuc2Nyb2xsVG8oZi5sZWZ0LGYudG9wKSl9ZnVuY3Rpb24gcyhuLHIsaSl7dmFyIG89ZS5rZXlOYW1lKG4pOyJFc2MiPT1vfHwiQ3RybC1DIj09b3x8IkN0cmwtWyI9PW98fCJCYWNrc3BhY2UiPT1vJiYiIj09cj8oVHQuc2VhcmNoSGlzdG9yeUNvbnRyb2xsZXIucHVzaElucHV0KHIpLFR0LnNlYXJjaEhpc3RvcnlDb250cm9sbGVyLnJlc2V0KCksSGUodCxwKSxKZSh0KSx0LnNjcm9sbFRvKGYubGVmdCxmLnRvcCksZS5lX3N0b3AobiksRih0KSxpKCksdC5mb2N1cygpKToiVXAiPT1vfHwiRG93biI9PW8/ZS5lX3N0b3Aobik6IkN0cmwtVSI9PW8mJihlLmVfc3RvcChuKSxpKCIiKSl9aWYodC5nZXRTZWFyY2hDdXJzb3Ipe3ZhciB1PXIuc2VhcmNoQXJncy5mb3J3YXJkLGM9ci5zZWFyY2hBcmdzLndob2xlV29yZE9ubHk7TmUodCkuc2V0UmV2ZXJzZWQoIXUpO3ZhciBsPXU/Ii8iOiI/IixwPU5lKHQpLmdldFF1ZXJ5KCksZj10LmdldFNjcm9sbEluZm8oKTtzd2l0Y2goci5zZWFyY2hBcmdzLnF1ZXJ5U3JjKXtjYXNlInByb21wdCI6dmFyIGQ9VHQubWFjcm9Nb2RlU3RhdGU7aWYoZC5pc1BsYXlpbmcpe3ZhciBoPWQucmVwbGF5U2VhcmNoUXVlcmllcy5zaGlmdCgpO2koaCwhMCwhMSl9ZWxzZSBWZSh0LHtvbkNsb3NlOm8scHJlZml4OmwsZGVzYzokdCxvbktleVVwOmEsb25LZXlEb3duOnN9KTticmVhaztjYXNlIndvcmRVbmRlckN1cnNvciI6dmFyIG09eWUodCwhMSwhMCwhMSwhMCksZz0hMDtpZihtfHwobT15ZSh0LCExLCEwLCExLCExKSxnPSExKSwhbSlyZXR1cm47dmFyIGg9dC5nZXRMaW5lKG0uc3RhcnQubGluZSkuc3Vic3RyaW5nKG0uc3RhcnQuY2gsbS5lbmQuY2gpO2g9ZyYmYz8iXFxiIitoKyJcXGIiOm5lKGgpLFR0Lmp1bXBMaXN0LmNhY2hlZEN1cnNvcj10LmdldEN1cnNvcigpLHQuc2V0Q3Vyc29yKG0uc3RhcnQpLGkoaCwhMCwhMSl9fX0scHJvY2Vzc0V4OmZ1bmN0aW9uKHQsbixyKXtmdW5jdGlvbiBpKGUpe1R0LmV4Q29tbWFuZEhpc3RvcnlDb250cm9sbGVyLnB1c2hJbnB1dChlKSxUdC5leENvbW1hbmRIaXN0b3J5Q29udHJvbGxlci5yZXNldCgpLEd0LnByb2Nlc3NDb21tYW5kKHQsZSl9ZnVuY3Rpb24gbyhuLHIsaSl7dmFyIG8sYSxzPWUua2V5TmFtZShuKTsoIkVzYyI9PXN8fCJDdHJsLUMiPT1zfHwiQ3RybC1bIj09c3x8IkJhY2tzcGFjZSI9PXMmJiIiPT1yKSYmKFR0LmV4Q29tbWFuZEhpc3RvcnlDb250cm9sbGVyLnB1c2hJbnB1dChyKSxUdC5leENvbW1hbmRIaXN0b3J5Q29udHJvbGxlci5yZXNldCgpLGUuZV9zdG9wKG4pLEYodCksaSgpLHQuZm9jdXMoKSksIlVwIj09c3x8IkRvd24iPT1zPyhlLmVfc3RvcChuKSxvPSJVcCI9PXMsYT1uLnRhcmdldD9uLnRhcmdldC5zZWxlY3Rpb25FbmQ6MCxyPVR0LmV4Q29tbWFuZEhpc3RvcnlDb250cm9sbGVyLm5leHRNYXRjaChyLG8pfHwiIixpKHIpLGEmJm4udGFyZ2V0JiYobi50YXJnZXQuc2VsZWN0aW9uRW5kPW4udGFyZ2V0LnNlbGVjdGlvblN0YXJ0PU1hdGgubWluKGEsbi50YXJnZXQudmFsdWUubGVuZ3RoKSkpOiJDdHJsLVUiPT1zPyhlLmVfc3RvcChuKSxpKCIiKSk6IkxlZnQiIT1zJiYiUmlnaHQiIT1zJiYiQ3RybCIhPXMmJiJBbHQiIT1zJiYiU2hpZnQiIT1zJiZUdC5leENvbW1hbmRIaXN0b3J5Q29udHJvbGxlci5yZXNldCgpfSJrZXlUb0V4Ij09ci50eXBlP0d0LnByb2Nlc3NDb21tYW5kKHQsci5leEFyZ3MuaW5wdXQpOm4udmlzdWFsTW9kZT9WZSh0LHtvbkNsb3NlOmkscHJlZml4OiI6Iix2YWx1ZToiJzwsJz4iLG9uS2V5RG93bjpvLHNlbGVjdFZhbHVlT25PcGVuOiExfSk6VmUodCx7b25DbG9zZTppLHByZWZpeDoiOiIsb25LZXlEb3duOm99KX0sZXZhbElucHV0OmZ1bmN0aW9uKGUsdCl7dmFyIG4saSxvLGE9dC5pbnB1dFN0YXRlLHM9YS5tb3Rpb24sdT1hLm1vdGlvbkFyZ3N8fHt9LGM9YS5vcGVyYXRvcixsPWEub3BlcmF0b3JBcmdzfHx7fSxwPWEucmVnaXN0ZXJOYW1lLGY9dC5zZWwsZD1RKHQudmlzdWFsTW9kZT8kKGUsZi5oZWFkKTplLmdldEN1cnNvcigiaGVhZCIpKSxoPVEodC52aXN1YWxNb2RlPyQoZSxmLmFuY2hvcik6ZS5nZXRDdXJzb3IoImFuY2hvciIpKSxtPVEoZCksZz1RKGgpO2lmKGMmJnRoaXMucmVjb3JkTGFzdEVkaXQodCxhKSxvPXZvaWQgMCE9PWEucmVwZWF0T3ZlcnJpZGU/YS5yZXBlYXRPdmVycmlkZTphLmdldFJlcGVhdCgpLG8+MCYmdS5leHBsaWNpdFJlcGVhdD91LnJlcGVhdElzRXhwbGljaXQ9ITA6KHUubm9SZXBlYXR8fCF1LmV4cGxpY2l0UmVwZWF0JiYwPT09bykmJihvPTEsdS5yZXBlYXRJc0V4cGxpY2l0PSExKSxhLnNlbGVjdGVkQ2hhcmFjdGVyJiYodS5zZWxlY3RlZENoYXJhY3Rlcj1sLnNlbGVjdGVkQ2hhcmFjdGVyPWEuc2VsZWN0ZWRDaGFyYWN0ZXIpLHUucmVwZWF0PW8sRihlKSxzKXt2YXIgeT1JdFtzXShlLGQsdSx0KTtpZih0Lmxhc3RNb3Rpb249SXRbc10sIXkpcmV0dXJuO2lmKHUudG9KdW1wbGlzdCl7dmFyIHY9VHQuanVtcExpc3QsYj12LmNhY2hlZEN1cnNvcjtiPyh2ZShlLGIseSksZGVsZXRlIHYuY2FjaGVkQ3Vyc29yKTp2ZShlLGQseSl9eSBpbnN0YW5jZW9mIEFycmF5PyhpPXlbMF0sbj15WzFdKTpuPXksbnx8KG49UShkKSksdC52aXN1YWxNb2RlPyh0LnZpc3VhbEJsb2NrJiZuLmNoPT09MS8wfHwobj0kKGUsbix0LnZpc3VhbEJsb2NrKSksaSYmKGk9JChlLGksITApKSxpPWl8fGcsZi5hbmNob3I9aSxmLmhlYWQ9bixsZShlKSxTZShlLHQsIjwiLEooaSxuKT9pOm4pLFNlKGUsdCwiPiIsSihpLG4pP246aSkpOmN8fChuPSQoZSxuKSxlLnNldEN1cnNvcihuLmxpbmUsbi5jaCkpfWlmKGMpe2lmKGwubGFzdFNlbCl7aT1nO3ZhciB4PWwubGFzdFNlbCxDPU1hdGguYWJzKHguaGVhZC5saW5lLXguYW5jaG9yLmxpbmUpLEU9TWF0aC5hYnMoeC5oZWFkLmNoLXguYW5jaG9yLmNoKTtuPXgudmlzdWFsTGluZT9yKGcubGluZStDLGcuY2gpOngudmlzdWFsQmxvY2s/cihnLmxpbmUrQyxnLmNoK0UpOnguaGVhZC5saW5lPT14LmFuY2hvci5saW5lP3IoZy5saW5lLGcuY2grRSk6cihnLmxpbmUrQyxnLmNoKSx0LnZpc3VhbE1vZGU9ITAsdC52aXN1YWxMaW5lPXgudmlzdWFsTGluZSx0LnZpc3VhbEJsb2NrPXgudmlzdWFsQmxvY2ssZj10LnNlbD17YW5jaG9yOmksaGVhZDpufSxsZShlKX1lbHNlIHQudmlzdWFsTW9kZSYmKGwubGFzdFNlbD17YW5jaG9yOlEoZi5hbmNob3IpLGhlYWQ6UShmLmhlYWQpLHZpc3VhbEJsb2NrOnQudmlzdWFsQmxvY2ssdmlzdWFsTGluZTp0LnZpc3VhbExpbmV9KTt2YXIgRCx3LFMsayxBO2lmKHQudmlzdWFsTW9kZSl7aWYoRD1ZKGYuaGVhZCxmLmFuY2hvciksdz1YKGYuaGVhZCxmLmFuY2hvciksUz10LnZpc3VhbExpbmV8fGwubGluZXdpc2Usaz10LnZpc3VhbEJsb2NrPyJibG9jayI6Uz8ibGluZSI6ImNoYXIiLEE9cGUoZSx7YW5jaG9yOkQsaGVhZDp3fSxrKSxTKXt2YXIgXz1BLnJhbmdlcztpZigiYmxvY2siPT1rKWZvcih2YXIgVD0wO1Q8Xy5sZW5ndGg7VCsrKV9bVF0uaGVhZC5jaD1lZShlLF9bVF0uaGVhZC5saW5lKTtlbHNlImxpbmUiPT1rJiYoX1swXS5oZWFkPXIoX1swXS5oZWFkLmxpbmUrMSwwKSl9fWVsc2V7aWYoRD1RKGl8fGcpLHc9UShufHxtKSxKKHcsRCkpe3ZhciBPPUQ7RD13LHc9T31TPXUubGluZXdpc2V8fGwubGluZXdpc2UsUz9tZShlLEQsdyk6dS5mb3J3YXJkJiZoZShlLEQsdyksaz0iY2hhciI7QT1wZShlLHthbmNob3I6RCxoZWFkOnd9LGssIXUuaW5jbHVzaXZlfHxTKX1lLnNldFNlbGVjdGlvbnMoQS5yYW5nZXMsQS5wcmltYXJ5KSx0Lmxhc3RNb3Rpb249bnVsbCxsLnJlcGVhdD1vLGwucmVnaXN0ZXJOYW1lPXAsbC5saW5ld2lzZT1TO3ZhciBOPUx0W2NdKGUsbCxBLnJhbmdlcyxnLG4pO3QudmlzdWFsTW9kZSYmZGUoZSxudWxsIT1OKSxOJiZlLnNldEN1cnNvcihOKX19LHJlY29yZExhc3RFZGl0OmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1UdC5tYWNyb01vZGVTdGF0ZTtyLmlzUGxheWluZ3x8KGUubGFzdEVkaXRJbnB1dFN0YXRlPXQsZS5sYXN0RWRpdEFjdGlvbkNvbW1hbmQ9bixyLmxhc3RJbnNlcnRNb2RlQ2hhbmdlcy5jaGFuZ2VzPVtdLHIubGFzdEluc2VydE1vZGVDaGFuZ2VzLmV4cGVjdEN1cnNvckFjdGl2aXR5Rm9yQ2hhbmdlPSExKX19LEl0PXttb3ZlVG9Ub3BMaW5lOmZ1bmN0aW9uKGUsdCxuKXt2YXIgaT1YZShlKS50b3Arbi5yZXBlYXQtMTtyZXR1cm4gcihpLGdlKGUuZ2V0TGluZShpKSkpfSxtb3ZlVG9NaWRkbGVMaW5lOmZ1bmN0aW9uKGUpe3ZhciB0PVhlKGUpLG49TWF0aC5mbG9vciguNSoodC50b3ArdC5ib3R0b20pKTtyZXR1cm4gcihuLGdlKGUuZ2V0TGluZShuKSkpfSxtb3ZlVG9Cb3R0b21MaW5lOmZ1bmN0aW9uKGUsdCxuKXt2YXIgaT1YZShlKS5ib3R0b20tbi5yZXBlYXQrMTtyZXR1cm4gcihpLGdlKGUuZ2V0TGluZShpKSkpfSxleHBhbmRUb0xpbmU6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiByKHQubGluZStuLnJlcGVhdC0xLDEvMCl9LGZpbmROZXh0OmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1OZShlKSxpPXIuZ2V0UXVlcnkoKTtpZihpKXt2YXIgbz0hbi5mb3J3YXJkO3JldHVybiBvPXIuaXNSZXZlcnNlZCgpPyFvOm8sUWUoZSxpKSxLZShlLG8saSxuLnJlcGVhdCl9fSxnb1RvTWFyazpmdW5jdGlvbihlLHQsbixyKXt2YXIgaT1aZShlLHIsbi5zZWxlY3RlZENoYXJhY3Rlcik7cmV0dXJuIGk/bi5saW5ld2lzZT97bGluZTppLmxpbmUsY2g6Z2UoZS5nZXRMaW5lKGkubGluZSkpfTppOm51bGx9LG1vdmVUb090aGVySGlnaGxpZ2h0ZWRFbmQ6ZnVuY3Rpb24oZSx0LG4saSl7aWYoaS52aXN1YWxCbG9jayYmbi5zYW1lTGluZSl7dmFyIG89aS5zZWw7cmV0dXJuWyQoZSxyKG8uYW5jaG9yLmxpbmUsby5oZWFkLmNoKSksJChlLHIoby5oZWFkLmxpbmUsby5hbmNob3IuY2gpKV19cmV0dXJuW2kuc2VsLmhlYWQsaS5zZWwuYW5jaG9yXX0sanVtcFRvTWFyazpmdW5jdGlvbihlLHQsbixpKXtmb3IodmFyIG89dCxhPTA7YTxuLnJlcGVhdDthKyspe3ZhciBzPW87Zm9yKHZhciB1IGluIGkubWFya3MpaWYoeSh1KSl7dmFyIGM9aS5tYXJrc1t1XS5maW5kKCksbD1uLmZvcndhcmQ/SihjLHMpOkoocyxjKTtpZighbCYmKCFuLmxpbmV3aXNlfHxjLmxpbmUhPXMubGluZSkpe3ZhciBwPUsocyxvKSxmPW4uZm9yd2FyZD9aKHMsYyxvKTpaKG8sYyxzKTsocHx8ZikmJihvPWMpfX19cmV0dXJuIG4ubGluZXdpc2UmJihvPXIoby5saW5lLGdlKGUuZ2V0TGluZShvLmxpbmUpKSkpLG99LG1vdmVCeUNoYXJhY3RlcnM6ZnVuY3Rpb24oZSx0LG4pe3ZhciBpPXQsbz1uLnJlcGVhdCxhPW4uZm9yd2FyZD9pLmNoK286aS5jaC1vO3JldHVybiByKGkubGluZSxhKX0sbW92ZUJ5TGluZXM6ZnVuY3Rpb24oZSx0LG4saSl7dmFyIG89dCxhPW8uY2g7c3dpdGNoKGkubGFzdE1vdGlvbil7Y2FzZSB0aGlzLm1vdmVCeUxpbmVzOmNhc2UgdGhpcy5tb3ZlQnlEaXNwbGF5TGluZXM6Y2FzZSB0aGlzLm1vdmVCeVNjcm9sbDpjYXNlIHRoaXMubW92ZVRvQ29sdW1uOmNhc2UgdGhpcy5tb3ZlVG9Fb2w6YT1pLmxhc3RIUG9zO2JyZWFrO2RlZmF1bHQ6aS5sYXN0SFBvcz1hfXZhciBzPW4ucmVwZWF0KyhuLnJlcGVhdE9mZnNldHx8MCksdT1uLmZvcndhcmQ/by5saW5lK3M6by5saW5lLXMsYz1lLmZpcnN0TGluZSgpLGw9ZS5sYXN0TGluZSgpO3JldHVybiB1PGMmJm8ubGluZT09Yz90aGlzLm1vdmVUb1N0YXJ0T2ZMaW5lKGUsdCxuLGkpOnU+bCYmby5saW5lPT1sP3RoaXMubW92ZVRvRW9sKGUsdCxuLGkpOihuLnRvRmlyc3RDaGFyJiYoYT1nZShlLmdldExpbmUodSkpLGkubGFzdEhQb3M9YSksaS5sYXN0SFNQb3M9ZS5jaGFyQ29vcmRzKHIodSxhKSwiZGl2IikubGVmdCxyKHUsYSkpfSxtb3ZlQnlEaXNwbGF5TGluZXM6ZnVuY3Rpb24oZSx0LG4saSl7dmFyIG89dDtzd2l0Y2goaS5sYXN0TW90aW9uKXtjYXNlIHRoaXMubW92ZUJ5RGlzcGxheUxpbmVzOmNhc2UgdGhpcy5tb3ZlQnlTY3JvbGw6Y2FzZSB0aGlzLm1vdmVCeUxpbmVzOmNhc2UgdGhpcy5tb3ZlVG9Db2x1bW46Y2FzZSB0aGlzLm1vdmVUb0VvbDpicmVhaztkZWZhdWx0OmkubGFzdEhTUG9zPWUuY2hhckNvb3JkcyhvLCJkaXYiKS5sZWZ0fXZhciBhPW4ucmVwZWF0LHM9ZS5maW5kUG9zVihvLG4uZm9yd2FyZD9hOi1hLCJsaW5lIixpLmxhc3RIU1Bvcyk7aWYocy5oaXRTaWRlKWlmKG4uZm9yd2FyZCl2YXIgdT1lLmNoYXJDb29yZHMocywiZGl2IiksYz17dG9wOnUudG9wKzgsbGVmdDppLmxhc3RIU1Bvc30scz1lLmNvb3Jkc0NoYXIoYywiZGl2Iik7ZWxzZXt2YXIgbD1lLmNoYXJDb29yZHMocihlLmZpcnN0TGluZSgpLDApLCJkaXYiKTtsLmxlZnQ9aS5sYXN0SFNQb3Mscz1lLmNvb3Jkc0NoYXIobCwiZGl2Iil9cmV0dXJuIGkubGFzdEhQb3M9cy5jaCxzfSxtb3ZlQnlQYWdlOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj10LGk9bi5yZXBlYXQ7cmV0dXJuIGUuZmluZFBvc1YocixuLmZvcndhcmQ/aTotaSwicGFnZSIpfSxtb3ZlQnlQYXJhZ3JhcGg6ZnVuY3Rpb24oZSx0LG4pe3ZhciByPW4uZm9yd2FyZD8xOi0xO3JldHVybiBBZShlLHQsbi5yZXBlYXQscil9LG1vdmVCeVNlbnRlbmNlOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj1uLmZvcndhcmQ/MTotMTtyZXR1cm4gX2UoZSx0LG4ucmVwZWF0LHIpfSxtb3ZlQnlTY3JvbGw6ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9ZS5nZXRTY3JvbGxJbmZvKCksbz1udWxsLGE9bi5yZXBlYXQ7YXx8KGE9aS5jbGllbnRIZWlnaHQvKDIqZS5kZWZhdWx0VGV4dEhlaWdodCgpKSk7dmFyIHM9ZS5jaGFyQ29vcmRzKHQsImxvY2FsIik7bi5yZXBlYXQ9YTt2YXIgbz1JdC5tb3ZlQnlEaXNwbGF5TGluZXMoZSx0LG4scik7aWYoIW8pcmV0dXJuIG51bGw7dmFyIHU9ZS5jaGFyQ29vcmRzKG8sImxvY2FsIik7cmV0dXJuIGUuc2Nyb2xsVG8obnVsbCxpLnRvcCt1LnRvcC1zLnRvcCksb30sbW92ZUJ5V29yZHM6ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBFZShlLHQsbi5yZXBlYXQsISFuLmZvcndhcmQsISFuLndvcmRFbmQsISFuLmJpZ1dvcmQpfSxtb3ZlVGlsbENoYXJhY3RlcjpmdW5jdGlvbihlLHQsbil7dmFyIHI9bi5yZXBlYXQsaT1EZShlLHIsbi5mb3J3YXJkLG4uc2VsZWN0ZWRDaGFyYWN0ZXIpLG89bi5mb3J3YXJkPy0xOjE7cmV0dXJuIGJlKG8sbiksaT8oaS5jaCs9byxpKTpudWxsfSxtb3ZlVG9DaGFyYWN0ZXI6ZnVuY3Rpb24oZSx0LG4pe3ZhciByPW4ucmVwZWF0O3JldHVybiBiZSgwLG4pLERlKGUscixuLmZvcndhcmQsbi5zZWxlY3RlZENoYXJhY3Rlcil8fHR9LG1vdmVUb1N5bWJvbDpmdW5jdGlvbihlLHQsbil7cmV0dXJuIHhlKGUsbi5yZXBlYXQsbi5mb3J3YXJkLG4uc2VsZWN0ZWRDaGFyYWN0ZXIpfHx0fSxtb3ZlVG9Db2x1bW46ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9bi5yZXBlYXQ7cmV0dXJuIHIubGFzdEhQb3M9aS0xLHIubGFzdEhTUG9zPWUuY2hhckNvb3Jkcyh0LCJkaXYiKS5sZWZ0LHdlKGUsaSl9LG1vdmVUb0VvbDpmdW5jdGlvbihlLHQsbixpKXt2YXIgbz10O2kubGFzdEhQb3M9MS8wO3ZhciBhPXIoby5saW5lK24ucmVwZWF0LTEsMS8wKSxzPWUuY2xpcFBvcyhhKTtyZXR1cm4gcy5jaC0tLGkubGFzdEhTUG9zPWUuY2hhckNvb3JkcyhzLCJkaXYiKS5sZWZ0LGF9LG1vdmVUb0ZpcnN0Tm9uV2hpdGVTcGFjZUNoYXJhY3RlcjpmdW5jdGlvbihlLHQpe3ZhciBuPXQ7cmV0dXJuIHIobi5saW5lLGdlKGUuZ2V0TGluZShuLmxpbmUpKSl9LG1vdmVUb01hdGNoZWRTeW1ib2w6ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4saT10LG89aS5saW5lLGE9aS5jaCxzPWUuZ2V0TGluZShvKTthPHMubGVuZ3RoO2ErKylpZigobj1zLmNoYXJBdChhKSkmJnYobikpe3ZhciB1PWUuZ2V0VG9rZW5UeXBlQXQocihvLGErMSkpO2lmKCJzdHJpbmciIT09dSYmImNvbW1lbnQiIT09dSlicmVha31pZihhPHMubGVuZ3RoKXtyZXR1cm4gZS5maW5kTWF0Y2hpbmdCcmFja2V0KHIobyxhKSkudG99cmV0dXJuIGl9LG1vdmVUb1N0YXJ0T2ZMaW5lOmZ1bmN0aW9uKGUsdCl7cmV0dXJuIHIodC5saW5lLDApfSxtb3ZlVG9MaW5lT3JFZGdlT2ZEb2N1bWVudDpmdW5jdGlvbihlLHQsbil7dmFyIGk9bi5mb3J3YXJkP2UubGFzdExpbmUoKTplLmZpcnN0TGluZSgpO3JldHVybiBuLnJlcGVhdElzRXhwbGljaXQmJihpPW4ucmVwZWF0LWUuZ2V0T3B0aW9uKCJmaXJzdExpbmVOdW1iZXIiKSkscihpLGdlKGUuZ2V0TGluZShpKSkpfSx0ZXh0T2JqZWN0TWFuaXB1bGF0aW9uOmZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpPXsiKCI6IikiLCIpIjoiKCIsInsiOiJ9IiwifSI6InsiLCJbIjoiXSIsIl0iOiJbIn0sbz17IiciOiEwLCciJzohMH0sYT1uLnNlbGVjdGVkQ2hhcmFjdGVyOyJiIj09YT9hPSIoIjoiQiI9PWEmJihhPSJ7Iik7dmFyIHMsdT0hbi50ZXh0T2JqZWN0SW5uZXI7aWYoaVthXSlzPVRlKGUsdCxhLHUpO2Vsc2UgaWYob1thXSlzPU9lKGUsdCxhLHUpO2Vsc2UgaWYoIlciPT09YSlzPXllKGUsdSwhMCwhMCk7ZWxzZSBpZigidyI9PT1hKXM9eWUoZSx1LCEwLCExKTtlbHNle2lmKCJwIiE9PWEpcmV0dXJuIG51bGw7aWYocz1BZShlLHQsbi5yZXBlYXQsMCx1KSxuLmxpbmV3aXNlPSEwLHIudmlzdWFsTW9kZSlyLnZpc3VhbExpbmV8fChyLnZpc3VhbExpbmU9ITApO2Vsc2V7dmFyIGM9ci5pbnB1dFN0YXRlLm9wZXJhdG9yQXJncztjJiYoYy5saW5ld2lzZT0hMCkscy5lbmQubGluZS0tfX1yZXR1cm4gZS5zdGF0ZS52aW0udmlzdWFsTW9kZT9jZShlLHMuc3RhcnQscy5lbmQpOltzLnN0YXJ0LHMuZW5kXX0scmVwZWF0TGFzdENoYXJhY3RlclNlYXJjaDpmdW5jdGlvbihlLHQsbil7dmFyIHI9VHQubGFzdENoYXJhY3RlclNlYXJjaCxpPW4ucmVwZWF0LG89bi5mb3J3YXJkPT09ci5mb3J3YXJkLGE9KHIuaW5jcmVtZW50PzE6MCkqKG8/LTE6MSk7ZS5tb3ZlSCgtYSwiY2hhciIpLG4uaW5jbHVzaXZlPSEhbzt2YXIgcz1EZShlLGksbyxyLnNlbGVjdGVkQ2hhcmFjdGVyKTtyZXR1cm4gcz8ocy5jaCs9YSxzKTooZS5tb3ZlSChhLCJjaGFyIiksdCl9fSxMdD17Y2hhbmdlOmZ1bmN0aW9uKHQsbixpKXt2YXIgbyxhLHM9dC5zdGF0ZS52aW07aWYoVHQubWFjcm9Nb2RlU3RhdGUubGFzdEluc2VydE1vZGVDaGFuZ2VzLmluVmlzdWFsQmxvY2s9cy52aXN1YWxCbG9jayxzLnZpc3VhbE1vZGUpe2E9dC5nZXRTZWxlY3Rpb24oKTt2YXIgdT1qKCIiLGkubGVuZ3RoKTt0LnJlcGxhY2VTZWxlY3Rpb25zKHUpLG89WShpWzBdLmhlYWQsaVswXS5hbmNob3IpfWVsc2V7dmFyIGM9aVswXS5hbmNob3IsbD1pWzBdLmhlYWQ7YT10LmdldFJhbmdlKGMsbCk7dmFyIHA9cy5sYXN0RWRpdElucHV0U3RhdGV8fHt9O2lmKCJtb3ZlQnlXb3JkcyI9PXAubW90aW9uJiYhQyhhKSl7dmFyIGY9L1xzKyQvLmV4ZWMoYSk7ZiYmcC5tb3Rpb25BcmdzJiZwLm1vdGlvbkFyZ3MuZm9yd2FyZCYmKGw9eihsLDAsLWZbMF0ubGVuZ3RoKSxhPWEuc2xpY2UoMCwtZlswXS5sZW5ndGgpKX12YXIgZD1uZXcgcihjLmxpbmUtMSxOdW1iZXIuTUFYX1ZBTFVFKSxoPXQuZmlyc3RMaW5lKCk9PXQubGFzdExpbmUoKTtsLmxpbmU+dC5sYXN0TGluZSgpJiZuLmxpbmV3aXNlJiYhaD90LnJlcGxhY2VSYW5nZSgiIixkLGwpOnQucmVwbGFjZVJhbmdlKCIiLGMsbCksbi5saW5ld2lzZSYmKGh8fCh0LnNldEN1cnNvcihkKSxlLmNvbW1hbmRzLm5ld2xpbmVBbmRJbmRlbnQodCkpLGMuY2g9TnVtYmVyLk1BWF9WQUxVRSksbz1jfVR0LnJlZ2lzdGVyQ29udHJvbGxlci5wdXNoVGV4dChuLnJlZ2lzdGVyTmFtZSwiY2hhbmdlIixhLG4ubGluZXdpc2UsaS5sZW5ndGg+MSksUHQuZW50ZXJJbnNlcnRNb2RlKHQse2hlYWQ6b30sdC5zdGF0ZS52aW0pfSxkZWxldGU6ZnVuY3Rpb24oZSx0LG4pe3ZhciBpLG8sYT1lLnN0YXRlLnZpbTtpZihhLnZpc3VhbEJsb2NrKXtvPWUuZ2V0U2VsZWN0aW9uKCk7dmFyIHM9aigiIixuLmxlbmd0aCk7ZS5yZXBsYWNlU2VsZWN0aW9ucyhzKSxpPW5bMF0uYW5jaG9yfWVsc2V7dmFyIHU9blswXS5hbmNob3IsYz1uWzBdLmhlYWQ7dC5saW5ld2lzZSYmYy5saW5lIT1lLmZpcnN0TGluZSgpJiZ1LmxpbmU9PWUubGFzdExpbmUoKSYmdS5saW5lPT1jLmxpbmUtMSYmKHUubGluZT09ZS5maXJzdExpbmUoKT91LmNoPTA6dT1yKHUubGluZS0xLGVlKGUsdS5saW5lLTEpKSksbz1lLmdldFJhbmdlKHUsYyksZS5yZXBsYWNlUmFuZ2UoIiIsdSxjKSxpPXUsdC5saW5ld2lzZSYmKGk9SXQubW92ZVRvRmlyc3ROb25XaGl0ZVNwYWNlQ2hhcmFjdGVyKGUsdSkpfXJldHVybiBUdC5yZWdpc3RlckNvbnRyb2xsZXIucHVzaFRleHQodC5yZWdpc3Rlck5hbWUsImRlbGV0ZSIsbyx0LmxpbmV3aXNlLGEudmlzdWFsQmxvY2spLCQoZSxpLGEuaW5zZXJ0TW9kZSl9LGluZGVudDpmdW5jdGlvbihlLHQsbil7dmFyIHI9ZS5zdGF0ZS52aW0saT1uWzBdLmFuY2hvci5saW5lLG89ci52aXN1YWxCbG9jaz9uW24ubGVuZ3RoLTFdLmFuY2hvci5saW5lOm5bMF0uaGVhZC5saW5lLGE9ci52aXN1YWxNb2RlP3QucmVwZWF0OjE7dC5saW5ld2lzZSYmby0tO2Zvcih2YXIgcz1pO3M8PW87cysrKWZvcih2YXIgdT0wO3U8YTt1KyspZS5pbmRlbnRMaW5lKHMsdC5pbmRlbnRSaWdodCk7cmV0dXJuIEl0Lm1vdmVUb0ZpcnN0Tm9uV2hpdGVTcGFjZUNoYXJhY3RlcihlLG5bMF0uYW5jaG9yKX0sY2hhbmdlQ2FzZTpmdW5jdGlvbihlLHQsbixyLGkpe2Zvcih2YXIgbz1lLmdldFNlbGVjdGlvbnMoKSxhPVtdLHM9dC50b0xvd2VyLHU9MDt1PG8ubGVuZ3RoO3UrKyl7dmFyIGM9b1t1XSxsPSIiO2lmKCEwPT09cylsPWMudG9Mb3dlckNhc2UoKTtlbHNlIGlmKCExPT09cylsPWMudG9VcHBlckNhc2UoKTtlbHNlIGZvcih2YXIgcD0wO3A8Yy5sZW5ndGg7cCsrKXt2YXIgZj1jLmNoYXJBdChwKTtsKz14KGYpP2YudG9Mb3dlckNhc2UoKTpmLnRvVXBwZXJDYXNlKCl9YS5wdXNoKGwpfXJldHVybiBlLnJlcGxhY2VTZWxlY3Rpb25zKGEpLHQuc2hvdWxkTW92ZUN1cnNvcj9pOiFlLnN0YXRlLnZpbS52aXN1YWxNb2RlJiZ0LmxpbmV3aXNlJiZuWzBdLmFuY2hvci5saW5lKzE9PW5bMF0uaGVhZC5saW5lP0l0Lm1vdmVUb0ZpcnN0Tm9uV2hpdGVTcGFjZUNoYXJhY3RlcihlLHIpOnQubGluZXdpc2U/cjpZKG5bMF0uYW5jaG9yLG5bMF0uaGVhZCl9LHlhbms6ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9ZS5zdGF0ZS52aW0sbz1lLmdldFNlbGVjdGlvbigpLGE9aS52aXN1YWxNb2RlP1koaS5zZWwuYW5jaG9yLGkuc2VsLmhlYWQsblswXS5oZWFkLG5bMF0uYW5jaG9yKTpyO3JldHVybiBUdC5yZWdpc3RlckNvbnRyb2xsZXIucHVzaFRleHQodC5yZWdpc3Rlck5hbWUsInlhbmsiLG8sdC5saW5ld2lzZSxpLnZpc3VhbEJsb2NrKSxhfX0sUHQ9e2p1bXBMaXN0V2FsazpmdW5jdGlvbihlLHQsbil7aWYoIW4udmlzdWFsTW9kZSl7dmFyIHI9dC5yZXBlYXQsaT10LmZvcndhcmQsbz1UdC5qdW1wTGlzdCxhPW8ubW92ZShlLGk/cjotcikscz1hP2EuZmluZCgpOnZvaWQgMDtzPXN8fGUuZ2V0Q3Vyc29yKCksZS5zZXRDdXJzb3Iocyl9fSxzY3JvbGw6ZnVuY3Rpb24oZSx0LG4pe2lmKCFuLnZpc3VhbE1vZGUpe3ZhciByPXQucmVwZWF0fHwxLGk9ZS5kZWZhdWx0VGV4dEhlaWdodCgpLG89ZS5nZXRTY3JvbGxJbmZvKCkudG9wLGE9aSpyLHM9dC5mb3J3YXJkP28rYTpvLWEsdT1RKGUuZ2V0Q3Vyc29yKCkpLGM9ZS5jaGFyQ29vcmRzKHUsImxvY2FsIik7aWYodC5mb3J3YXJkKXM+Yy50b3A/KHUubGluZSs9KHMtYy50b3ApL2ksdS5saW5lPU1hdGguY2VpbCh1LmxpbmUpLGUuc2V0Q3Vyc29yKHUpLGM9ZS5jaGFyQ29vcmRzKHUsImxvY2FsIiksZS5zY3JvbGxUbyhudWxsLGMudG9wKSk6ZS5zY3JvbGxUbyhudWxsLHMpO2Vsc2V7dmFyIGw9cytlLmdldFNjcm9sbEluZm8oKS5jbGllbnRIZWlnaHQ7bDxjLmJvdHRvbT8odS5saW5lLT0oYy5ib3R0b20tbCkvaSx1LmxpbmU9TWF0aC5mbG9vcih1LmxpbmUpLGUuc2V0Q3Vyc29yKHUpLGM9ZS5jaGFyQ29vcmRzKHUsImxvY2FsIiksZS5zY3JvbGxUbyhudWxsLGMuYm90dG9tLWUuZ2V0U2Nyb2xsSW5mbygpLmNsaWVudEhlaWdodCkpOmUuc2Nyb2xsVG8obnVsbCxzKX19fSxzY3JvbGxUb0N1cnNvcjpmdW5jdGlvbihlLHQpe3ZhciBuPWUuZ2V0Q3Vyc29yKCkubGluZSxpPWUuY2hhckNvb3JkcyhyKG4sMCksImxvY2FsIiksbz1lLmdldFNjcm9sbEluZm8oKS5jbGllbnRIZWlnaHQsYT1pLnRvcCxzPWkuYm90dG9tLWE7c3dpdGNoKHQucG9zaXRpb24pe2Nhc2UiY2VudGVyIjphPWEtby8yK3M7YnJlYWs7Y2FzZSJib3R0b20iOmE9YS1vK3N9ZS5zY3JvbGxUbyhudWxsLGEpfSxyZXBsYXlNYWNybzpmdW5jdGlvbihlLHQsbil7dmFyIHI9dC5zZWxlY3RlZENoYXJhY3RlcixpPXQucmVwZWF0LG89VHQubWFjcm9Nb2RlU3RhdGU7Zm9yKCJAIj09ciYmKHI9by5sYXRlc3RSZWdpc3Rlcik7aS0tOylpdChlLG4sbyxyKX0sZW50ZXJNYWNyb1JlY29yZE1vZGU6ZnVuY3Rpb24oZSx0KXt2YXIgbj1UdC5tYWNyb01vZGVTdGF0ZSxyPXQuc2VsZWN0ZWRDaGFyYWN0ZXI7VHQucmVnaXN0ZXJDb250cm9sbGVyLmlzVmFsaWRSZWdpc3RlcihyKSYmbi5lbnRlck1hY3JvUmVjb3JkTW9kZShlLHIpfSx0b2dnbGVPdmVyd3JpdGU6ZnVuY3Rpb24odCl7dC5zdGF0ZS5vdmVyd3JpdGU/KHQudG9nZ2xlT3ZlcndyaXRlKCExKSx0LnNldE9wdGlvbigia2V5TWFwIiwidmltLWluc2VydCIpLGUuc2lnbmFsKHQsInZpbS1tb2RlLWNoYW5nZSIse21vZGU6Imluc2VydCJ9KSk6KHQudG9nZ2xlT3ZlcndyaXRlKCEwKSx0LnNldE9wdGlvbigia2V5TWFwIiwidmltLXJlcGxhY2UiKSxlLnNpZ25hbCh0LCJ2aW0tbW9kZS1jaGFuZ2UiLHttb2RlOiJyZXBsYWNlIn0pKX0sZW50ZXJJbnNlcnRNb2RlOmZ1bmN0aW9uKHQsbixpKXtpZighdC5nZXRPcHRpb24oInJlYWRPbmx5Iikpe2kuaW5zZXJ0TW9kZT0hMCxpLmluc2VydE1vZGVSZXBlYXQ9biYmbi5yZXBlYXR8fDE7dmFyIG89bj9uLmluc2VydEF0Om51bGwsYT1pLnNlbCxzPW4uaGVhZHx8dC5nZXRDdXJzb3IoImhlYWQiKSx1PXQubGlzdFNlbGVjdGlvbnMoKS5sZW5ndGg7aWYoImVvbCI9PW8pcz1yKHMubGluZSxlZSh0LHMubGluZSkpO2Vsc2UgaWYoImNoYXJBZnRlciI9PW8pcz16KHMsMCwxKTtlbHNlIGlmKCJmaXJzdE5vbkJsYW5rIj09bylzPUl0Lm1vdmVUb0ZpcnN0Tm9uV2hpdGVTcGFjZUNoYXJhY3Rlcih0LHMpO2Vsc2UgaWYoInN0YXJ0T2ZTZWxlY3RlZEFyZWEiPT1vKWkudmlzdWFsQmxvY2s/KHM9cihNYXRoLm1pbihhLmhlYWQubGluZSxhLmFuY2hvci5saW5lKSxNYXRoLm1pbihhLmhlYWQuY2gsYS5hbmNob3IuY2gpKSx1PU1hdGguYWJzKGEuaGVhZC5saW5lLWEuYW5jaG9yLmxpbmUpKzEpOnM9YS5oZWFkLmxpbmU8YS5hbmNob3IubGluZT9hLmhlYWQ6cihhLmFuY2hvci5saW5lLDApO2Vsc2UgaWYoImVuZE9mU2VsZWN0ZWRBcmVhIj09bylpLnZpc3VhbEJsb2NrPyhzPXIoTWF0aC5taW4oYS5oZWFkLmxpbmUsYS5hbmNob3IubGluZSksTWF0aC5tYXgoYS5oZWFkLmNoKzEsYS5hbmNob3IuY2gpKSx1PU1hdGguYWJzKGEuaGVhZC5saW5lLWEuYW5jaG9yLmxpbmUpKzEpOnM9YS5oZWFkLmxpbmU+PWEuYW5jaG9yLmxpbmU/eihhLmhlYWQsMCwxKTpyKGEuYW5jaG9yLmxpbmUsMCk7ZWxzZSBpZigiaW5wbGFjZSI9PW8mJmkudmlzdWFsTW9kZSlyZXR1cm47dC5zZXRPcHRpb24oImRpc2FibGVJbnB1dCIsITEpLG4mJm4ucmVwbGFjZT8odC50b2dnbGVPdmVyd3JpdGUoITApLHQuc2V0T3B0aW9uKCJrZXlNYXAiLCJ2aW0tcmVwbGFjZSIpLGUuc2lnbmFsKHQsInZpbS1tb2RlLWNoYW5nZSIse21vZGU6InJlcGxhY2UifSkpOih0LnRvZ2dsZU92ZXJ3cml0ZSghMSksdC5zZXRPcHRpb24oImtleU1hcCIsInZpbS1pbnNlcnQiKSxlLnNpZ25hbCh0LCJ2aW0tbW9kZS1jaGFuZ2UiLHttb2RlOiJpbnNlcnQifSkpLFR0Lm1hY3JvTW9kZVN0YXRlLmlzUGxheWluZ3x8KHQub24oImNoYW5nZSIsdXQpLGUub24odC5nZXRJbnB1dEZpZWxkKCksImtleWRvd24iLGR0KSksaS52aXN1YWxNb2RlJiZkZSh0KSxvZSh0LHMsdSl9fSx0b2dnbGVWaXN1YWxNb2RlOmZ1bmN0aW9uKHQsbixpKXt2YXIgbyxhPW4ucmVwZWF0LHM9dC5nZXRDdXJzb3IoKTtpLnZpc3VhbE1vZGU/aS52aXN1YWxMaW5lXm4ubGluZXdpc2V8fGkudmlzdWFsQmxvY2tebi5ibG9ja3dpc2U/KGkudmlzdWFsTGluZT0hIW4ubGluZXdpc2UsaS52aXN1YWxCbG9jaz0hIW4uYmxvY2t3aXNlLGUuc2lnbmFsKHQsInZpbS1tb2RlLWNoYW5nZSIse21vZGU6InZpc3VhbCIsc3ViTW9kZTppLnZpc3VhbExpbmU/ImxpbmV3aXNlIjppLnZpc3VhbEJsb2NrPyJibG9ja3dpc2UiOiIifSksbGUodCkpOmRlKHQpOihpLnZpc3VhbE1vZGU9ITAsaS52aXN1YWxMaW5lPSEhbi5saW5ld2lzZSxpLnZpc3VhbEJsb2NrPSEhbi5ibG9ja3dpc2Usbz0kKHQscihzLmxpbmUscy5jaCthLTEpLCEwKSxpLnNlbD17YW5jaG9yOnMsaGVhZDpvfSxlLnNpZ25hbCh0LCJ2aW0tbW9kZS1jaGFuZ2UiLHttb2RlOiJ2aXN1YWwiLHN1Yk1vZGU6aS52aXN1YWxMaW5lPyJsaW5ld2lzZSI6aS52aXN1YWxCbG9jaz8iYmxvY2t3aXNlIjoiIn0pLGxlKHQpLFNlKHQsaSwiPCIsWShzLG8pKSxTZSh0LGksIj4iLFgocyxvKSkpfSxyZXNlbGVjdExhc3RTZWxlY3Rpb246ZnVuY3Rpb24odCxuLHIpe3ZhciBpPXIubGFzdFNlbGVjdGlvbjtpZihyLnZpc3VhbE1vZGUmJnVlKHQsciksaSl7dmFyIG89aS5hbmNob3JNYXJrLmZpbmQoKSxhPWkuaGVhZE1hcmsuZmluZCgpO2lmKCFvfHwhYSlyZXR1cm47ci5zZWw9e2FuY2hvcjpvLGhlYWQ6YX0sci52aXN1YWxNb2RlPSEwLHIudmlzdWFsTGluZT1pLnZpc3VhbExpbmUsci52aXN1YWxCbG9jaz1pLnZpc3VhbEJsb2NrLGxlKHQpLFNlKHQsciwiPCIsWShvLGEpKSxTZSh0LHIsIj4iLFgobyxhKSksZS5zaWduYWwodCwidmltLW1vZGUtY2hhbmdlIix7bW9kZToidmlzdWFsIixzdWJNb2RlOnIudmlzdWFsTGluZT8ibGluZXdpc2UiOnIudmlzdWFsQmxvY2s/ImJsb2Nrd2lzZSI6IiJ9KX19LGpvaW5MaW5lczpmdW5jdGlvbihlLHQsbil7dmFyIGksbztpZihuLnZpc3VhbE1vZGUpe2lmKGk9ZS5nZXRDdXJzb3IoImFuY2hvciIpLG89ZS5nZXRDdXJzb3IoImhlYWQiKSxKKG8saSkpe3ZhciBhPW87bz1pLGk9YX1vLmNoPWVlKGUsby5saW5lKS0xfWVsc2V7dmFyIHM9TWF0aC5tYXgodC5yZXBlYXQsMik7aT1lLmdldEN1cnNvcigpLG89JChlLHIoaS5saW5lK3MtMSwxLzApKX1mb3IodmFyIHU9MCxjPWkubGluZTtjPG8ubGluZTtjKyspe3U9ZWUoZSxpLmxpbmUpO3ZhciBhPXIoaS5saW5lKzEsZWUoZSxpLmxpbmUrMSkpLGw9ZS5nZXRSYW5nZShpLGEpO2w9bC5yZXBsYWNlKC9cblxzKi9nLCIgIiksZS5yZXBsYWNlUmFuZ2UobCxpLGEpfXZhciBwPXIoaS5saW5lLHUpO24udmlzdWFsTW9kZSYmZGUoZSwhMSksZS5zZXRDdXJzb3IocCl9LG5ld0xpbmVBbmRFbnRlckluc2VydE1vZGU6ZnVuY3Rpb24odCxuLGkpe2kuaW5zZXJ0TW9kZT0hMDt2YXIgbz1RKHQuZ2V0Q3Vyc29yKCkpO2lmKG8ubGluZSE9PXQuZmlyc3RMaW5lKCl8fG4uYWZ0ZXIpe28ubGluZT1uLmFmdGVyP28ubGluZTpvLmxpbmUtMSxvLmNoPWVlKHQsby5saW5lKSx0LnNldEN1cnNvcihvKTsoZS5jb21tYW5kcy5uZXdsaW5lQW5kSW5kZW50Q29udGludWVDb21tZW50fHxlLmNvbW1hbmRzLm5ld2xpbmVBbmRJbmRlbnQpKHQpfWVsc2UgdC5yZXBsYWNlUmFuZ2UoIlxuIixyKHQuZmlyc3RMaW5lKCksMCkpLHQuc2V0Q3Vyc29yKHQuZmlyc3RMaW5lKCksMCk7dGhpcy5lbnRlckluc2VydE1vZGUodCx7cmVwZWF0Om4ucmVwZWF0fSxpKX0scGFzdGU6ZnVuY3Rpb24oZSx0LG4pe3ZhciBpPVEoZS5nZXRDdXJzb3IoKSksbz1UdC5yZWdpc3RlckNvbnRyb2xsZXIuZ2V0UmVnaXN0ZXIodC5yZWdpc3Rlck5hbWUpLGE9by50b1N0cmluZygpO2lmKGEpe2lmKHQubWF0Y2hJbmRlbnQpe3ZhciBzPWUuZ2V0T3B0aW9uKCJ0YWJTaXplIiksdT1mdW5jdGlvbihlKXt2YXIgdD1lLnNwbGl0KCJcdCIpLmxlbmd0aC0xLG49ZS5zcGxpdCgiICIpLmxlbmd0aC0xO3JldHVybiB0KnMrMSpufSxjPWUuZ2V0TGluZShlLmdldEN1cnNvcigpLmxpbmUpLGw9dShjLm1hdGNoKC9eXHMqLylbMF0pLHA9YS5yZXBsYWNlKC9cbiQvLCIiKSxmPWEhPT1wLGQ9dShhLm1hdGNoKC9eXHMqLylbMF0pLGE9cC5yZXBsYWNlKC9eXHMqL2dtLGZ1bmN0aW9uKHQpe3ZhciBuPWwrKHUodCktZCk7aWYobjwwKXJldHVybiIiO2lmKGUuZ2V0T3B0aW9uKCJpbmRlbnRXaXRoVGFicyIpKXt2YXIgcj1NYXRoLmZsb29yKG4vcyk7cmV0dXJuIEFycmF5KHIrMSkuam9pbigiXHQiKX1yZXR1cm4gQXJyYXkobisxKS5qb2luKCIgIil9KTthKz1mPyJcbiI6IiJ9aWYodC5yZXBlYXQ+MSl2YXIgYT1BcnJheSh0LnJlcGVhdCsxKS5qb2luKGEpO3ZhciBoPW8ubGluZXdpc2UsbT1vLmJsb2Nrd2lzZTtpZihoKW4udmlzdWFsTW9kZT9hPW4udmlzdWFsTGluZT9hLnNsaWNlKDAsLTEpOiJcbiIrYS5zbGljZSgwLGEubGVuZ3RoLTEpKyJcbiI6dC5hZnRlcj8oYT0iXG4iK2Euc2xpY2UoMCxhLmxlbmd0aC0xKSxpLmNoPWVlKGUsaS5saW5lKSk6aS5jaD0wO2Vsc2V7aWYobSl7YT1hLnNwbGl0KCJcbiIpO2Zvcih2YXIgZz0wO2c8YS5sZW5ndGg7ZysrKWFbZ109IiI9PWFbZ10/IiAiOmFbZ119aS5jaCs9dC5hZnRlcj8xOjB9dmFyIHksdjtpZihuLnZpc3VhbE1vZGUpe24ubGFzdFBhc3RlZFRleHQ9YTt2YXIgYix4PXNlKGUsbiksQz14WzBdLEU9eFsxXSxEPWUuZ2V0U2VsZWN0aW9uKCksdz1lLmxpc3RTZWxlY3Rpb25zKCksUz1uZXcgQXJyYXkody5sZW5ndGgpLmpvaW4oIjEiKS5zcGxpdCgiMSIpO24ubGFzdFNlbGVjdGlvbiYmKGI9bi5sYXN0U2VsZWN0aW9uLmhlYWRNYXJrLmZpbmQoKSksVHQucmVnaXN0ZXJDb250cm9sbGVyLnVubmFtZWRSZWdpc3Rlci5zZXRUZXh0KEQpLG0/KGUucmVwbGFjZVNlbGVjdGlvbnMoUyksRT1yKEMubGluZSthLmxlbmd0aC0xLEMuY2gpLGUuc2V0Q3Vyc29yKEMpLGllKGUsRSksZS5yZXBsYWNlU2VsZWN0aW9ucyhhKSx5PUMpOm4udmlzdWFsQmxvY2s/KGUucmVwbGFjZVNlbGVjdGlvbnMoUyksZS5zZXRDdXJzb3IoQyksZS5yZXBsYWNlUmFuZ2UoYSxDLEMpLHk9Qyk6KGUucmVwbGFjZVJhbmdlKGEsQyxFKSx5PWUucG9zRnJvbUluZGV4KGUuaW5kZXhGcm9tUG9zKEMpK2EubGVuZ3RoLTEpKSxiJiYobi5sYXN0U2VsZWN0aW9uLmhlYWRNYXJrPWUuc2V0Qm9va21hcmsoYikpLGgmJih5LmNoPTApfWVsc2UgaWYobSl7ZS5zZXRDdXJzb3IoaSk7Zm9yKHZhciBnPTA7ZzxhLmxlbmd0aDtnKyspe3ZhciBrPWkubGluZStnO2s+ZS5sYXN0TGluZSgpJiZlLnJlcGxhY2VSYW5nZSgiXG4iLHIoaywwKSk7dmFyIEE9ZWUoZSxrKTtBPGkuY2gmJnJlKGUsayxpLmNoKX1lLnNldEN1cnNvcihpKSxpZShlLHIoaS5saW5lK2EubGVuZ3RoLTEsaS5jaCkpLGUucmVwbGFjZVNlbGVjdGlvbnMoYSkseT1pfWVsc2UgZS5yZXBsYWNlUmFuZ2UoYSxpKSxoJiZ0LmFmdGVyP3k9cihpLmxpbmUrMSxnZShlLmdldExpbmUoaS5saW5lKzEpKSk6aCYmIXQuYWZ0ZXI/eT1yKGkubGluZSxnZShlLmdldExpbmUoaS5saW5lKSkpOiFoJiZ0LmFmdGVyPyh2PWUuaW5kZXhGcm9tUG9zKGkpLHk9ZS5wb3NGcm9tSW5kZXgodithLmxlbmd0aC0xKSk6KHY9ZS5pbmRleEZyb21Qb3MoaSkseT1lLnBvc0Zyb21JbmRleCh2K2EubGVuZ3RoKSk7bi52aXN1YWxNb2RlJiZkZShlLCExKSxlLnNldEN1cnNvcih5KX19LHVuZG86ZnVuY3Rpb24odCxuKXt0Lm9wZXJhdGlvbihmdW5jdGlvbigpe1codCxlLmNvbW1hbmRzLnVuZG8sbi5yZXBlYXQpKCksdC5zZXRDdXJzb3IodC5nZXRDdXJzb3IoImFuY2hvciIpKX0pfSxyZWRvOmZ1bmN0aW9uKHQsbil7Vyh0LGUuY29tbWFuZHMucmVkbyxuLnJlcGVhdCkoKX0sc2V0UmVnaXN0ZXI6ZnVuY3Rpb24oZSx0LG4pe24uaW5wdXRTdGF0ZS5yZWdpc3Rlck5hbWU9dC5zZWxlY3RlZENoYXJhY3Rlcn0sc2V0TWFyazpmdW5jdGlvbihlLHQsbil7U2UoZSxuLHQuc2VsZWN0ZWRDaGFyYWN0ZXIsZS5nZXRDdXJzb3IoKSl9LHJlcGxhY2U6ZnVuY3Rpb24odCxuLGkpe3ZhciBvLGEscz1uLnNlbGVjdGVkQ2hhcmFjdGVyLHU9dC5nZXRDdXJzb3IoKSxjPXQubGlzdFNlbGVjdGlvbnMoKTtpZihpLnZpc3VhbE1vZGUpdT10LmdldEN1cnNvcigic3RhcnQiKSxhPXQuZ2V0Q3Vyc29yKCJlbmQiKTtlbHNle3ZhciBsPXQuZ2V0TGluZSh1LmxpbmUpO289dS5jaCtuLnJlcGVhdCxvPmwubGVuZ3RoJiYobz1sLmxlbmd0aCksYT1yKHUubGluZSxvKX1pZigiXG4iPT1zKWkudmlzdWFsTW9kZXx8dC5yZXBsYWNlUmFuZ2UoIiIsdSxhKSwoZS5jb21tYW5kcy5uZXdsaW5lQW5kSW5kZW50Q29udGludWVDb21tZW50fHxlLmNvbW1hbmRzLm5ld2xpbmVBbmRJbmRlbnQpKHQpO2Vsc2V7dmFyIHA9dC5nZXRSYW5nZSh1LGEpO2lmKHA9cC5yZXBsYWNlKC9bXlxuXS9nLHMpLGkudmlzdWFsQmxvY2spe3ZhciBmPW5ldyBBcnJheSh0LmdldE9wdGlvbigidGFiU2l6ZSIpKzEpLmpvaW4oIiAiKTtwPXQuZ2V0U2VsZWN0aW9uKCkscD1wLnJlcGxhY2UoL1x0L2csZikucmVwbGFjZSgvW15cbl0vZyxzKS5zcGxpdCgiXG4iKSx0LnJlcGxhY2VTZWxlY3Rpb25zKHApfWVsc2UgdC5yZXBsYWNlUmFuZ2UocCx1LGEpO2kudmlzdWFsTW9kZT8odT1KKGNbMF0uYW5jaG9yLGNbMF0uaGVhZCk/Y1swXS5hbmNob3I6Y1swXS5oZWFkLHQuc2V0Q3Vyc29yKHUpLGRlKHQsITEpKTp0LnNldEN1cnNvcih6KGEsMCwtMSkpfX0saW5jcmVtZW50TnVtYmVyVG9rZW46ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4saSxvLGEscz1lLmdldEN1cnNvcigpLHU9ZS5nZXRMaW5lKHMubGluZSksYz0vKC0/KSg/OigweCkoW1xkYS1mXSspfCgwYnwwfCkoXGQrKSkvZ2k7bnVsbCE9PShuPWMuZXhlYyh1KSkmJihpPW4uaW5kZXgsbz1pK25bMF0ubGVuZ3RoLCEocy5jaDxvKSk7KTtpZigodC5iYWNrdHJhY2t8fCEobzw9cy5jaCkpJiZuKXt2YXIgbD1uWzJdfHxuWzRdLHA9blszXXx8bls1XSxmPXQuaW5jcmVhc2U/MTotMSxkPXsiMGIiOjIsMDo4LCIiOjEwLCIweCI6MTZ9W2wudG9Mb3dlckNhc2UoKV07YT0ocGFyc2VJbnQoblsxXStwLGQpK2YqdC5yZXBlYXQpLnRvU3RyaW5nKGQpO3ZhciBoPWw/bmV3IEFycmF5KHAubGVuZ3RoLWEubGVuZ3RoKzErblsxXS5sZW5ndGgpLmpvaW4oIjAiKToiIjthPSItIj09PWEuY2hhckF0KDApPyItIitsK2grYS5zdWJzdHIoMSk6bCtoK2E7dmFyIG09cihzLmxpbmUsaSksZz1yKHMubGluZSxvKTtlLnJlcGxhY2VSYW5nZShhLG0sZyksZS5zZXRDdXJzb3IocihzLmxpbmUsaSthLmxlbmd0aC0xKSl9fSxyZXBlYXRMYXN0RWRpdDpmdW5jdGlvbihlLHQsbil7aWYobi5sYXN0RWRpdElucHV0U3RhdGUpe3ZhciByPXQucmVwZWF0O3ImJnQucmVwZWF0SXNFeHBsaWNpdD9uLmxhc3RFZGl0SW5wdXRTdGF0ZS5yZXBlYXRPdmVycmlkZT1yOnI9bi5sYXN0RWRpdElucHV0U3RhdGUucmVwZWF0T3ZlcnJpZGV8fHIsaHQoZSxuLHIsITEpfX0saW5kZW50OmZ1bmN0aW9uKGUsdCl7ZS5pbmRlbnRMaW5lKGUuZ2V0Q3Vyc29yKCkubGluZSx0LmluZGVudFJpZ2h0KX0sZXhpdEluc2VydE1vZGU6dHR9LE10PXsiKCI6ImJyYWNrZXQiLCIpIjoiYnJhY2tldCIsInsiOiJicmFja2V0IiwifSI6ImJyYWNrZXQiLCJbIjoic2VjdGlvbiIsIl0iOiJzZWN0aW9uIiwiKiI6ImNvbW1lbnQiLCIvIjoiY29tbWVudCIsbToibWV0aG9kIixNOiJtZXRob2QiLCIjIjoicHJlcHJvY2VzcyJ9LGp0PXticmFja2V0Ontpc0NvbXBsZXRlOmZ1bmN0aW9uKGUpe2lmKGUubmV4dENoPT09ZS5zeW1iKXtpZigrK2UuZGVwdGg+PTEpcmV0dXJuITB9ZWxzZSBlLm5leHRDaD09PWUucmV2ZXJzZVN5bWImJmUuZGVwdGgtLTtyZXR1cm4hMX19LHNlY3Rpb246e2luaXQ6ZnVuY3Rpb24oZSl7ZS5jdXJNb3ZlVGhyb3VnaD0hMCxlLnN5bWI9KGUuZm9yd2FyZD8iXSI6IlsiKT09PWUuc3ltYj8ieyI6In0ifSxpc0NvbXBsZXRlOmZ1bmN0aW9uKGUpe3JldHVybiAwPT09ZS5pbmRleCYmZS5uZXh0Q2g9PT1lLnN5bWJ9fSxjb21tZW50Ontpc0NvbXBsZXRlOmZ1bmN0aW9uKGUpe3ZhciB0PSIqIj09PWUubGFzdENoJiYiLyI9PT1lLm5leHRDaDtyZXR1cm4gZS5sYXN0Q2g9ZS5uZXh0Q2gsdH19LG1ldGhvZDp7aW5pdDpmdW5jdGlvbihlKXtlLnN5bWI9Im0iPT09ZS5zeW1iPyJ7IjoifSIsZS5yZXZlcnNlU3ltYj0ieyI9PT1lLnN5bWI/In0iOiJ7In0saXNDb21wbGV0ZTpmdW5jdGlvbihlKXtyZXR1cm4gZS5uZXh0Q2g9PT1lLnN5bWJ9fSxwcmVwcm9jZXNzOntpbml0OmZ1bmN0aW9uKGUpe2UuaW5kZXg9MH0saXNDb21wbGV0ZTpmdW5jdGlvbihlKXtpZigiIyI9PT1lLm5leHRDaCl7dmFyIHQ9ZS5saW5lVGV4dC5tYXRjaCgvIyhcdyspLylbMV07aWYoImVuZGlmIj09PXQpe2lmKGUuZm9yd2FyZCYmMD09PWUuZGVwdGgpcmV0dXJuITA7ZS5kZXB0aCsrfWVsc2UgaWYoImlmIj09PXQpe2lmKCFlLmZvcndhcmQmJjA9PT1lLmRlcHRoKXJldHVybiEwO2UuZGVwdGgtLX1pZigiZWxzZSI9PT10JiYwPT09ZS5kZXB0aClyZXR1cm4hMH1yZXR1cm4hMX19fTt3KCJwY3JlIiwhMCwiYm9vbGVhbiIpLEZlLnByb3RvdHlwZT17Z2V0UXVlcnk6ZnVuY3Rpb24oKXtyZXR1cm4gVHQucXVlcnl9LHNldFF1ZXJ5OmZ1bmN0aW9uKGUpe1R0LnF1ZXJ5PWV9LGdldE92ZXJsYXk6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5zZWFyY2hPdmVybGF5fSxzZXRPdmVybGF5OmZ1bmN0aW9uKGUpe3RoaXMuc2VhcmNoT3ZlcmxheT1lfSxpc1JldmVyc2VkOmZ1bmN0aW9uKCl7cmV0dXJuIFR0LmlzUmV2ZXJzZWR9LHNldFJldmVyc2VkOmZ1bmN0aW9uKGUpe1R0LmlzUmV2ZXJzZWQ9ZX0sZ2V0U2Nyb2xsYmFyQW5ub3RhdGU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5hbm5vdGF0ZX0sc2V0U2Nyb2xsYmFyQW5ub3RhdGU6ZnVuY3Rpb24oZSl7dGhpcy5hbm5vdGF0ZT1lfX07dmFyIFJ0PXsiXFxuIjoiXG4iLCJcXHIiOiJcciIsIlxcdCI6Ilx0In0sQnQ9eyJcXC8iOiIvIiwiXFxcXCI6IlxcIiwiXFxuIjoiXG4iLCJcXHIiOiJcciIsIlxcdCI6Ilx0In0sJHQ9IihKYXZhc2NyaXB0IHJlZ2V4cCkiLFV0PWZ1bmN0aW9uKCl7dGhpcy5idWlsZENvbW1hbmRNYXBfKCl9O1V0LnByb3RvdHlwZT17cHJvY2Vzc0NvbW1hbmQ6ZnVuY3Rpb24oZSx0LG4pe3ZhciByPXRoaXM7ZS5vcGVyYXRpb24oZnVuY3Rpb24oKXtlLmN1ck9wLmlzVmltT3A9ITAsci5fcHJvY2Vzc0NvbW1hbmQoZSx0LG4pfSl9LF9wcm9jZXNzQ29tbWFuZDpmdW5jdGlvbih0LG4scil7dmFyIGk9dC5zdGF0ZS52aW0sbz1UdC5yZWdpc3RlckNvbnRyb2xsZXIuZ2V0UmVnaXN0ZXIoIjoiKSxhPW8udG9TdHJpbmcoKTtpLnZpc3VhbE1vZGUmJmRlKHQpO3ZhciBzPW5ldyBlLlN0cmluZ1N0cmVhbShuKTtvLnNldFRleHQobik7dmFyIHU9cnx8e307dS5pbnB1dD1uO3RyeXt0aGlzLnBhcnNlSW5wdXRfKHQscyx1KX1jYXRjaChlKXt0aHJvdyB6ZSh0LGUpLGV9dmFyIGMsbDtpZih1LmNvbW1hbmROYW1lKXtpZihjPXRoaXMubWF0Y2hDb21tYW5kXyh1LmNvbW1hbmROYW1lKSl7aWYobD1jLm5hbWUsYy5leGNsdWRlRnJvbUNvbW1hbmRIaXN0b3J5JiZvLnNldFRleHQoYSksdGhpcy5wYXJzZUNvbW1hbmRBcmdzXyhzLHUsYyksImV4VG9LZXkiPT1jLnR5cGUpe2Zvcih2YXIgcD0wO3A8Yy50b0tleXMubGVuZ3RoO3ArKyllLlZpbS5oYW5kbGVLZXkodCxjLnRvS2V5c1twXSwibWFwcGluZyIpO3JldHVybn1pZigiZXhUb0V4Ij09Yy50eXBlKXJldHVybiB2b2lkIHRoaXMucHJvY2Vzc0NvbW1hbmQodCxjLnRvSW5wdXQpfX1lbHNlIHZvaWQgMCE9PXUubGluZSYmKGw9Im1vdmUiKTtpZighbClyZXR1cm4gdm9pZCB6ZSh0LCdOb3QgYW4gZWRpdG9yIGNvbW1hbmQgIjonK24rJyInKTt0cnl7enRbbF0odCx1KSxjJiZjLnBvc3NpYmx5QXN5bmN8fCF1LmNhbGxiYWNrfHx1LmNhbGxiYWNrKCl9Y2F0Y2goZSl7dGhyb3cgemUodCxlKSxlfX0scGFyc2VJbnB1dF86ZnVuY3Rpb24oZSx0LG4pe3QuZWF0V2hpbGUoIjoiKSx0LmVhdCgiJSIpPyhuLmxpbmU9ZS5maXJzdExpbmUoKSxuLmxpbmVFbmQ9ZS5sYXN0TGluZSgpKToobi5saW5lPXRoaXMucGFyc2VMaW5lU3BlY18oZSx0KSx2b2lkIDAhPT1uLmxpbmUmJnQuZWF0KCIsIikmJihuLmxpbmVFbmQ9dGhpcy5wYXJzZUxpbmVTcGVjXyhlLHQpKSk7dmFyIHI9dC5tYXRjaCgvXihcdyspLyk7cmV0dXJuIG4uY29tbWFuZE5hbWU9cj9yWzFdOnQubWF0Y2goLy4qLylbMF0sbn0scGFyc2VMaW5lU3BlY186ZnVuY3Rpb24oZSx0KXt2YXIgbj10Lm1hdGNoKC9eKFxkKykvKTtpZihuKXJldHVybiBwYXJzZUludChuWzFdLDEwKS0xO3N3aXRjaCh0Lm5leHQoKSl7Y2FzZSIuIjpyZXR1cm4gdGhpcy5wYXJzZUxpbmVTcGVjT2Zmc2V0Xyh0LGUuZ2V0Q3Vyc29yKCkubGluZSk7Y2FzZSIkIjpyZXR1cm4gdGhpcy5wYXJzZUxpbmVTcGVjT2Zmc2V0Xyh0LGUubGFzdExpbmUoKSk7Y2FzZSInIjp2YXIgcj10Lm5leHQoKSxpPVplKGUsZS5zdGF0ZS52aW0scik7aWYoIWkpdGhyb3cgbmV3IEVycm9yKCJNYXJrIG5vdCBzZXQiKTtyZXR1cm4gdGhpcy5wYXJzZUxpbmVTcGVjT2Zmc2V0Xyh0LGkubGluZSk7Y2FzZSItIjpjYXNlIisiOnJldHVybiB0LmJhY2tVcCgxKSx0aGlzLnBhcnNlTGluZVNwZWNPZmZzZXRfKHQsZS5nZXRDdXJzb3IoKS5saW5lKTtkZWZhdWx0OnJldHVybiB2b2lkIHQuYmFja1VwKDEpfX0scGFyc2VMaW5lU3BlY09mZnNldF86ZnVuY3Rpb24oZSx0KXt2YXIgbj1lLm1hdGNoKC9eKFsrLV0pPyhcZCspLyk7aWYobil7dmFyIHI9cGFyc2VJbnQoblsyXSwxMCk7Ii0iPT1uWzFdP3QtPXI6dCs9cn1yZXR1cm4gdH0scGFyc2VDb21tYW5kQXJnc186ZnVuY3Rpb24oZSx0LG4pe2lmKCFlLmVvbCgpKXt0LmFyZ1N0cmluZz1lLm1hdGNoKC8uKi8pWzBdO3ZhciByPW4uYXJnRGVsaW1pdGVyfHwvXHMrLyxpPXRlKHQuYXJnU3RyaW5nKS5zcGxpdChyKTtpLmxlbmd0aCYmaVswXSYmKHQuYXJncz1pKX19LG1hdGNoQ29tbWFuZF86ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PWUubGVuZ3RoO3Q+MDt0LS0pe3ZhciBuPWUuc3Vic3RyaW5nKDAsdCk7aWYodGhpcy5jb21tYW5kTWFwX1tuXSl7dmFyIHI9dGhpcy5jb21tYW5kTWFwX1tuXTtpZigwPT09ci5uYW1lLmluZGV4T2YoZSkpcmV0dXJuIHJ9fXJldHVybiBudWxsfSxidWlsZENvbW1hbmRNYXBfOmZ1bmN0aW9uKCl7dGhpcy5jb21tYW5kTWFwXz17fTtmb3IodmFyIGU9MDtlPG4ubGVuZ3RoO2UrKyl7dmFyIHQ9bltlXSxyPXQuc2hvcnROYW1lfHx0Lm5hbWU7dGhpcy5jb21tYW5kTWFwX1tyXT10fX0sbWFwOmZ1bmN0aW9uKGUsbixyKXtpZigiOiIhPWUmJiI6Ij09ZS5jaGFyQXQoMCkpe2lmKHIpdGhyb3cgRXJyb3IoIk1vZGUgbm90IHN1cHBvcnRlZCBmb3IgZXggbWFwcGluZ3MiKTt2YXIgaT1lLnN1YnN0cmluZygxKTsiOiIhPW4mJiI6Ij09bi5jaGFyQXQoMCk/dGhpcy5jb21tYW5kTWFwX1tpXT17bmFtZTppLHR5cGU6ImV4VG9FeCIsdG9JbnB1dDpuLnN1YnN0cmluZygxKSx1c2VyOiEwfTp0aGlzLmNvbW1hbmRNYXBfW2ldPXtuYW1lOmksdHlwZToiZXhUb0tleSIsdG9LZXlzOm4sdXNlcjohMH19ZWxzZSBpZigiOiIhPW4mJiI6Ij09bi5jaGFyQXQoMCkpe3ZhciBvPXtrZXlzOmUsdHlwZToia2V5VG9FeCIsZXhBcmdzOntpbnB1dDpuLnN1YnN0cmluZygxKX19O3ImJihvLmNvbnRleHQ9ciksdC51bnNoaWZ0KG8pfWVsc2V7dmFyIG89e2tleXM6ZSx0eXBlOiJrZXlUb0tleSIsdG9LZXlzOm59O3ImJihvLmNvbnRleHQ9ciksdC51bnNoaWZ0KG8pfX0sdW5tYXA6ZnVuY3Rpb24oZSxuKXtpZigiOiIhPWUmJiI6Ij09ZS5jaGFyQXQoMCkpe2lmKG4pdGhyb3cgRXJyb3IoIk1vZGUgbm90IHN1cHBvcnRlZCBmb3IgZXggbWFwcGluZ3MiKTt2YXIgcj1lLnN1YnN0cmluZygxKTtpZih0aGlzLmNvbW1hbmRNYXBfW3JdJiZ0aGlzLmNvbW1hbmRNYXBfW3JdLnVzZXIpcmV0dXJuIHZvaWQgZGVsZXRlIHRoaXMuY29tbWFuZE1hcF9bcl19ZWxzZSBmb3IodmFyIGk9ZSxvPTA7bzx0Lmxlbmd0aDtvKyspaWYoaT09dFtvXS5rZXlzJiZ0W29dLmNvbnRleHQ9PT1uKXJldHVybiB2b2lkIHQuc3BsaWNlKG8sMSk7dGhyb3cgRXJyb3IoIk5vIHN1Y2ggbWFwcGluZy4iKX19O3ZhciB6dD17Y29sb3JzY2hlbWU6ZnVuY3Rpb24oZSx0KXtpZighdC5hcmdzfHx0LmFyZ3MubGVuZ3RoPDEpcmV0dXJuIHZvaWQgemUoZSxlLmdldE9wdGlvbigidGhlbWUiKSk7ZS5zZXRPcHRpb24oInRoZW1lIix0LmFyZ3NbMF0pfSxtYXA6ZnVuY3Rpb24oZSx0LG4pe3ZhciByPXQuYXJncztpZighcnx8ci5sZW5ndGg8MilyZXR1cm4gdm9pZChlJiZ6ZShlLCJJbnZhbGlkIG1hcHBpbmc6ICIrdC5pbnB1dCkpO0d0Lm1hcChyWzBdLHJbMV0sbil9LGltYXA6ZnVuY3Rpb24oZSx0KXt0aGlzLm1hcChlLHQsImluc2VydCIpfSxubWFwOmZ1bmN0aW9uKGUsdCl7dGhpcy5tYXAoZSx0LCJub3JtYWwiKX0sdm1hcDpmdW5jdGlvbihlLHQpe3RoaXMubWFwKGUsdCwidmlzdWFsIil9LHVubWFwOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcj10LmFyZ3M7aWYoIXJ8fHIubGVuZ3RoPDEpcmV0dXJuIHZvaWQoZSYmemUoZSwiTm8gc3VjaCBtYXBwaW5nOiAiK3QuaW5wdXQpKTtHdC51bm1hcChyWzBdLG4pfSxtb3ZlOmZ1bmN0aW9uKGUsdCl7TnQucHJvY2Vzc0NvbW1hbmQoZSxlLnN0YXRlLnZpbSx7dHlwZToibW90aW9uIixtb3Rpb246Im1vdmVUb0xpbmVPckVkZ2VPZkRvY3VtZW50Iixtb3Rpb25BcmdzOntmb3J3YXJkOiExLGV4cGxpY2l0UmVwZWF0OiEwLGxpbmV3aXNlOiEwfSxyZXBlYXRPdmVycmlkZTp0LmxpbmUrMX0pfSxzZXQ6ZnVuY3Rpb24oZSx0KXt2YXIgbj10LmFyZ3Mscj10LnNldENmZ3x8e307aWYoIW58fG4ubGVuZ3RoPDEpcmV0dXJuIHZvaWQoZSYmemUoZSwiSW52YWxpZCBtYXBwaW5nOiAiK3QuaW5wdXQpKTt2YXIgaT1uWzBdLnNwbGl0KCI9Iiksbz1pWzBdLGE9aVsxXSxzPSExO2lmKCI/Ij09by5jaGFyQXQoby5sZW5ndGgtMSkpe2lmKGEpdGhyb3cgRXJyb3IoIlRyYWlsaW5nIGNoYXJhY3RlcnM6ICIrdC5hcmdTdHJpbmcpO289by5zdWJzdHJpbmcoMCxvLmxlbmd0aC0xKSxzPSEwfXZvaWQgMD09PWEmJiJubyI9PW8uc3Vic3RyaW5nKDAsMikmJihvPW8uc3Vic3RyaW5nKDIpLGE9ITEpO3ZhciB1PWt0W29dJiYiYm9vbGVhbiI9PWt0W29dLnR5cGU7aWYodSYmdm9pZCAwPT1hJiYoYT0hMCksIXUmJnZvaWQgMD09PWF8fHMpe3ZhciBjPWsobyxlLHIpO2MgaW5zdGFuY2VvZiBFcnJvcj96ZShlLGMubWVzc2FnZSk6ITA9PT1jfHwhMT09PWM/emUoZSwiICIrKGM/IiI6Im5vIikrbyk6emUoZSwiICAiK28rIj0iK2MpfWVsc2V7dmFyIGw9UyhvLGEsZSxyKTtsIGluc3RhbmNlb2YgRXJyb3ImJnplKGUsbC5tZXNzYWdlKX19LHNldGxvY2FsOmZ1bmN0aW9uKGUsdCl7dC5zZXRDZmc9e3Njb3BlOiJsb2NhbCJ9LHRoaXMuc2V0KGUsdCl9LHNldGdsb2JhbDpmdW5jdGlvbihlLHQpe3Quc2V0Q2ZnPXtzY29wZToiZ2xvYmFsIn0sdGhpcy5zZXQoZSx0KX0scmVnaXN0ZXJzOmZ1bmN0aW9uKGUsdCl7dmFyIG49dC5hcmdzLHI9VHQucmVnaXN0ZXJDb250cm9sbGVyLnJlZ2lzdGVycyxpPSItLS0tLS0tLS0tUmVnaXN0ZXJzLS0tLS0tLS0tLTxicj48YnI+IjtpZihuKXt2YXIgbztuPW4uam9pbigiIik7Zm9yKHZhciBhPTA7YTxuLmxlbmd0aDthKyspaWYobz1uLmNoYXJBdChhKSxUdC5yZWdpc3RlckNvbnRyb2xsZXIuaXNWYWxpZFJlZ2lzdGVyKG8pKXt2YXIgcz1yW29dfHxuZXcgTjtpKz0nIicrbysiICAgICIrcy50b1N0cmluZygpKyI8YnI+In19ZWxzZSBmb3IodmFyIG8gaW4gcil7dmFyIHU9cltvXS50b1N0cmluZygpO3UubGVuZ3RoJiYoaSs9JyInK28rIiAgICAiK3UrIjxicj4iKX16ZShlLGkpfSxzb3J0OmZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gaShlLHQpe2lmKGEpe3ZhciBuO249ZSxlPXQsdD1ufXMmJihlPWUudG9Mb3dlckNhc2UoKSx0PXQudG9Mb3dlckNhc2UoKSk7dmFyIHI9YyYmeS5leGVjKGUpLGk9YyYmeS5leGVjKHQpO3JldHVybiByPyhyPXBhcnNlSW50KChyWzFdK3JbMl0pLnRvTG93ZXJDYXNlKCksdiksaT1wYXJzZUludCgoaVsxXStpWzJdKS50b0xvd2VyQ2FzZSgpLHYpLHItaSk6ZTx0Py0xOjF9ZnVuY3Rpb24gbyhlLHQpe2lmKGEpe3ZhciBuO249ZSxlPXQsdD1ufXJldHVybiBzJiYoZVswXT1lWzBdLnRvTG93ZXJDYXNlKCksdFswXT10WzBdLnRvTG93ZXJDYXNlKCkpLGVbMF08dFswXT8tMToxfXZhciBhLHMsdSxjLGwscD1mdW5jdGlvbigpe2lmKG4uYXJnU3RyaW5nKXt2YXIgdD1uZXcgZS5TdHJpbmdTdHJlYW0obi5hcmdTdHJpbmcpO2lmKHQuZWF0KCIhIikmJihhPSEwKSx0LmVvbCgpKXJldHVybjtpZighdC5lYXRTcGFjZSgpKXJldHVybiJJbnZhbGlkIGFyZ3VtZW50cyI7dmFyIHI9dC5tYXRjaCgvKFtkaW51b3hdKyk/XHMqKFwvLitcLyk/XHMqLyk7aWYoIXImJiF0LmVvbCgpKXJldHVybiJJbnZhbGlkIGFyZ3VtZW50cyI7aWYoclsxXSl7cz0tMSE9clsxXS5pbmRleE9mKCJpIiksdT0tMSE9clsxXS5pbmRleE9mKCJ1Iik7dmFyIGk9LTEhPXJbMV0uaW5kZXhPZigiZCIpfHwtMSE9clsxXS5pbmRleE9mKCJuIikmJjEsbz0tMSE9clsxXS5pbmRleE9mKCJ4IikmJjEscD0tMSE9clsxXS5pbmRleE9mKCJvIikmJjE7aWYoaStvK3A+MSlyZXR1cm4iSW52YWxpZCBhcmd1bWVudHMiO2M9aSYmImRlY2ltYWwifHxvJiYiaGV4Inx8cCYmIm9jdGFsIn1yWzJdJiYobD1uZXcgUmVnRXhwKHJbMl0uc3Vic3RyKDEsclsyXS5sZW5ndGgtMikscz8iaSI6IiIpKX19KCk7aWYocClyZXR1cm4gdm9pZCB6ZSh0LHArIjogIituLmFyZ1N0cmluZyk7dmFyIGY9bi5saW5lfHx0LmZpcnN0TGluZSgpLGQ9bi5saW5lRW5kfHxuLmxpbmV8fHQubGFzdExpbmUoKTtpZihmIT1kKXt2YXIgaD1yKGYsMCksbT1yKGQsZWUodCxkKSksZz10LmdldFJhbmdlKGgsbSkuc3BsaXQoIlxuIikseT1sfHwoImRlY2ltYWwiPT1jPy8oLT8pKFtcZF0rKS86ImhleCI9PWM/LygtPykoPzoweCk/KFswLTlhLWZdKykvaToib2N0YWwiPT1jPy8oWzAtN10rKS86bnVsbCksdj0iZGVjaW1hbCI9PWM/MTA6ImhleCI9PWM/MTY6Im9jdGFsIj09Yz84Om51bGwsYj1bXSx4PVtdO2lmKGN8fGwpZm9yKHZhciBDPTA7QzxnLmxlbmd0aDtDKyspe3ZhciBFPWw/Z1tDXS5tYXRjaChsKTpudWxsO0UmJiIiIT1FWzBdP2IucHVzaChFKTohbCYmeS5leGVjKGdbQ10pP2IucHVzaChnW0NdKTp4LnB1c2goZ1tDXSl9ZWxzZSB4PWc7aWYoYi5zb3J0KGw/bzppKSxsKWZvcih2YXIgQz0wO0M8Yi5sZW5ndGg7QysrKWJbQ109YltDXS5pbnB1dDtlbHNlIGN8fHguc29ydChpKTtpZihnPWE/Yi5jb25jYXQoeCk6eC5jb25jYXQoYiksdSl7dmFyIEQsdz1nO2c9W107Zm9yKHZhciBDPTA7Qzx3Lmxlbmd0aDtDKyspd1tDXSE9RCYmZy5wdXNoKHdbQ10pLEQ9d1tDXX10LnJlcGxhY2VSYW5nZShnLmpvaW4oIlxuIiksaCxtKX19LGdsb2JhbDpmdW5jdGlvbihlLHQpe3ZhciBuPXQuYXJnU3RyaW5nO2lmKCFuKXJldHVybiB2b2lkIHplKGUsIlJlZ3VsYXIgRXhwcmVzc2lvbiBtaXNzaW5nIGZyb20gZ2xvYmFsIik7dmFyIHIsaT12b2lkIDAhPT10LmxpbmU/dC5saW5lOmUuZmlyc3RMaW5lKCksbz10LmxpbmVFbmR8fHQubGluZXx8ZS5sYXN0TGluZSgpLGE9TGUobikscz1uO2lmKGEubGVuZ3RoJiYocz1hWzBdLHI9YS5zbGljZSgxLGEubGVuZ3RoKS5qb2luKCIvIikpLHMpdHJ5e0hlKGUscywhMCwhMCl9Y2F0Y2godCl7cmV0dXJuIHZvaWQgemUoZSwiSW52YWxpZCByZWdleDogIitzKX1mb3IodmFyIHU9TmUoZSkuZ2V0UXVlcnkoKSxjPVtdLGw9IiIscD1pO3A8PW87cCsrKXt1LnRlc3QoZS5nZXRMaW5lKHApKSYmKGMucHVzaChwKzEpLGwrPWUuZ2V0TGluZShwKSsiPGJyPiIpfWlmKCFyKXJldHVybiB2b2lkIHplKGUsbCk7dmFyIGY9MCxkPWZ1bmN0aW9uKCl7aWYoZjxjLmxlbmd0aCl7dmFyIHQ9Y1tmXStyO0d0LnByb2Nlc3NDb21tYW5kKGUsdCx7Y2FsbGJhY2s6ZH0pfWYrK307ZCgpfSxzdWJzdGl0dXRlOmZ1bmN0aW9uKGUsdCl7aWYoIWUuZ2V0U2VhcmNoQ3Vyc29yKXRocm93IG5ldyBFcnJvcigiU2VhcmNoIGZlYXR1cmUgbm90IGF2YWlsYWJsZS4gUmVxdWlyZXMgc2VhcmNoY3Vyc29yLmpzIG9yIGFueSBvdGhlciBnZXRTZWFyY2hDdXJzb3IgaW1wbGVtZW50YXRpb24uIik7dmFyIG4saSxvLGEscz10LmFyZ1N0cmluZyx1PXM/TWUocyxzWzBdKTpbXSxjPSIiLGw9ITEscD0hMTtpZih1Lmxlbmd0aCluPXVbMF0sYz11WzFdLG4mJiIkIj09PW5bbi5sZW5ndGgtMV0mJihuPW4uc2xpY2UoMCxuLmxlbmd0aC0xKSsiXFxuIixjPWM/YysiXG4iOiJcbiIpLHZvaWQgMCE9PWMmJihjPWsoInBjcmUiKT8kZShjKTpCZShjKSxUdC5sYXN0U3Vic3RpdHV0ZVJlcGxhY2VQYXJ0PWMpLGk9dVsyXT91WzJdLnNwbGl0KCIgIik6W107ZWxzZSBpZihzJiZzLmxlbmd0aClyZXR1cm4gdm9pZCB6ZShlLCJTdWJzdGl0dXRpb25zIHNob3VsZCBiZSBvZiB0aGUgZm9ybSA6cy9wYXR0ZXJuL3JlcGxhY2UvIik7aWYoaSYmKG89aVswXSxhPXBhcnNlSW50KGlbMV0pLG8mJigtMSE9by5pbmRleE9mKCJjIikmJihsPSEwLG8ucmVwbGFjZSgiYyIsIiIpKSwtMSE9by5pbmRleE9mKCJnIikmJihwPSEwLG8ucmVwbGFjZSgiZyIsIiIpKSxuPW4ucmVwbGFjZSgvXC8vZywiXFwvIikrIi8iK28pKSxuKXRyeXtIZShlLG4sITAsITApfWNhdGNoKHQpe3JldHVybiB2b2lkIHplKGUsIkludmFsaWQgcmVnZXg6ICIrbil9aWYodm9pZCAwPT09KGM9Y3x8VHQubGFzdFN1YnN0aXR1dGVSZXBsYWNlUGFydCkpcmV0dXJuIHZvaWQgemUoZSwiTm8gcHJldmlvdXMgc3Vic3RpdHV0ZSByZWd1bGFyIGV4cHJlc3Npb24iKTt2YXIgZj1OZShlKSxkPWYuZ2V0UXVlcnkoKSxoPXZvaWQgMCE9PXQubGluZT90LmxpbmU6ZS5nZXRDdXJzb3IoKS5saW5lLG09dC5saW5lRW5kfHxoO2g9PWUuZmlyc3RMaW5lKCkmJm09PWUubGFzdExpbmUoKSYmKG09MS8wKSxhJiYoaD1tLG09aCthLTEpO3ZhciBnPSQoZSxyKGgsMCkpLHk9ZS5nZXRTZWFyY2hDdXJzb3IoZCxnKTtldChlLGwscCxoLG0seSxkLGMsdC5jYWxsYmFjayl9LHJlZG86ZS5jb21tYW5kcy5yZWRvLHVuZG86ZS5jb21tYW5kcy51bmRvLHdyaXRlOmZ1bmN0aW9uKHQpe2UuY29tbWFuZHMuc2F2ZT9lLmNvbW1hbmRzLnNhdmUodCk6dC5zYXZlJiZ0LnNhdmUoKX0sbm9obHNlYXJjaDpmdW5jdGlvbihlKXtKZShlKX0seWFuazpmdW5jdGlvbihlKXt2YXIgdD1RKGUuZ2V0Q3Vyc29yKCkpLG49dC5saW5lLHI9ZS5nZXRMaW5lKG4pO1R0LnJlZ2lzdGVyQ29udHJvbGxlci5wdXNoVGV4dCgiMCIsInlhbmsiLHIsITAsITApfSxkZWxtYXJrczpmdW5jdGlvbih0LG4pe2lmKCFuLmFyZ1N0cmluZ3x8IXRlKG4uYXJnU3RyaW5nKSlyZXR1cm4gdm9pZCB6ZSh0LCJBcmd1bWVudCByZXF1aXJlZCIpO2Zvcih2YXIgcj10LnN0YXRlLnZpbSxpPW5ldyBlLlN0cmluZ1N0cmVhbSh0ZShuLmFyZ1N0cmluZykpOyFpLmVvbCgpOyl7aS5lYXRTcGFjZSgpO3ZhciBvPWkucG9zO2lmKCFpLm1hdGNoKC9bYS16QS1aXS8sITEpKXJldHVybiB2b2lkIHplKHQsIkludmFsaWQgYXJndW1lbnQ6ICIrbi5hcmdTdHJpbmcuc3Vic3RyaW5nKG8pKTt2YXIgYT1pLm5leHQoKTtpZihpLm1hdGNoKCItIiwhMCkpe2lmKCFpLm1hdGNoKC9bYS16QS1aXS8sITEpKXJldHVybiB2b2lkIHplKHQsIkludmFsaWQgYXJndW1lbnQ6ICIrbi5hcmdTdHJpbmcuc3Vic3RyaW5nKG8pKTt2YXIgcz1hLHU9aS5uZXh0KCk7aWYoISh5KHMpJiZ5KHUpfHx4KHMpJiZ4KHUpKSlyZXR1cm4gdm9pZCB6ZSh0LCJJbnZhbGlkIGFyZ3VtZW50OiAiK3MrIi0iKTt2YXIgYz1zLmNoYXJDb2RlQXQoMCksbD11LmNoYXJDb2RlQXQoMCk7aWYoYz49bClyZXR1cm4gdm9pZCB6ZSh0LCJJbnZhbGlkIGFyZ3VtZW50OiAiK24uYXJnU3RyaW5nLnN1YnN0cmluZyhvKSk7Zm9yKHZhciBwPTA7cDw9bC1jO3ArKyl7dmFyIGY9U3RyaW5nLmZyb21DaGFyQ29kZShjK3ApO2RlbGV0ZSByLm1hcmtzW2ZdfX1lbHNlIGRlbGV0ZSByLm1hcmtzW2FdfX19LEd0PW5ldyBVdDtyZXR1cm4gZS5rZXlNYXAudmltPXthdHRhY2g6cyxkZXRhY2g6YSxjYWxsOmZ9LHcoImluc2VydE1vZGVFc2NLZXlzVGltZW91dCIsMjAwLCJudW1iZXIiKSxlLmtleU1hcFsidmltLWluc2VydCJdPXtmYWxsdGhyb3VnaDpbImRlZmF1bHQiXSxhdHRhY2g6cyxkZXRhY2g6YSxjYWxsOmZ9LGUua2V5TWFwWyJ2aW0tcmVwbGFjZSJdPXtCYWNrc3BhY2U6ImdvQ2hhckxlZnQiLGZhbGx0aHJvdWdoOlsidmltLWluc2VydCJdLGF0dGFjaDpzLGRldGFjaDphLGNhbGw6Zn0sVCgpLEZ0fSgpfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9bigyKSxpPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0ociksbz1uKDUwKTtpLmRlZmF1bHQucmVnaXN0ZXJIZWxwZXIoImhpbnQiLCJncmFwaHFsIixmdW5jdGlvbihlLHQpe3ZhciBuPXQuc2NoZW1hO2lmKG4pe3ZhciByPWUuZ2V0Q3Vyc29yKCksYT1lLmdldFRva2VuQXQocikscz0oMCxvLmdldEF1dG9jb21wbGV0ZVN1Z2dlc3Rpb25zKShuLGUuZ2V0VmFsdWUoKSxyLGEpLHU9bnVsbCE9PWEudHlwZSYmLyJ8XHcvLnRlc3QoYS5zdHJpbmdbMF0pP2Euc3RhcnQ6YS5lbmQsYz17bGlzdDpzLm1hcChmdW5jdGlvbihlKXtyZXR1cm57dGV4dDplLmxhYmVsLHR5cGU6U3RyaW5nKGUuZGV0YWlsKSxkZXNjcmlwdGlvbjplLmRvY3VtZW50YXRpb24saXNEZXByZWNhdGVkOmUuaXNEZXByZWNhdGVkLGRlcHJlY2F0aW9uUmVhc29uOmUuZGVwcmVjYXRpb25SZWFzb259fSksZnJvbTp7bGluZTpyLmxpbmUsY29sdW1uOnV9LHRvOntsaW5lOnIubGluZSxjb2x1bW46YS5lbmR9fTtyZXR1cm4gYyYmYy5saXN0JiZjLmxpc3QubGVuZ3RoPjAmJihjLmZyb209aS5kZWZhdWx0LlBvcyhjLmZyb20ubGluZSxjLmZyb20uY29sdW1uKSxjLnRvPWkuZGVmYXVsdC5Qb3MoYy50by5saW5lLGMudG8uY29sdW1uKSxpLmRlZmF1bHQuc2lnbmFsKGUsImhhc0NvbXBsZXRpb24iLGUsYyxhKSksY319KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0KXt2YXIgbj10aGlzO3IodGhpcyxlKSx0aGlzLmdldFN0YXJ0T2ZUb2tlbj1mdW5jdGlvbigpe3JldHVybiBuLl9zdGFydH0sdGhpcy5nZXRDdXJyZW50UG9zaXRpb249ZnVuY3Rpb24oKXtyZXR1cm4gbi5fcG9zfSx0aGlzLmVvbD1mdW5jdGlvbigpe3JldHVybiBuLl9zb3VyY2VUZXh0Lmxlbmd0aD09PW4uX3Bvc30sdGhpcy5zb2w9ZnVuY3Rpb24oKXtyZXR1cm4gMD09PW4uX3Bvc30sdGhpcy5wZWVrPWZ1bmN0aW9uKCl7cmV0dXJuIG4uX3NvdXJjZVRleHQuY2hhckF0KG4uX3Bvcyk/bi5fc291cmNlVGV4dC5jaGFyQXQobi5fcG9zKTpudWxsfSx0aGlzLm5leHQ9ZnVuY3Rpb24oKXt2YXIgZT1uLl9zb3VyY2VUZXh0LmNoYXJBdChuLl9wb3MpO3JldHVybiBuLl9wb3MrKyxlfSx0aGlzLmVhdD1mdW5jdGlvbihlKXtpZihuLl90ZXN0TmV4dENoYXJhY3RlcihlKSlyZXR1cm4gbi5fc3RhcnQ9bi5fcG9zLG4uX3BvcysrLG4uX3NvdXJjZVRleHQuY2hhckF0KG4uX3Bvcy0xKX0sdGhpcy5lYXRXaGlsZT1mdW5jdGlvbihlKXt2YXIgdD1uLl90ZXN0TmV4dENoYXJhY3RlcihlKSxyPSExO2Zvcih0JiYocj10LG4uX3N0YXJ0PW4uX3Bvcyk7dDspbi5fcG9zKyssdD1uLl90ZXN0TmV4dENoYXJhY3RlcihlKSxyPSEwO3JldHVybiByfSx0aGlzLmVhdFNwYWNlPWZ1bmN0aW9uKCl7cmV0dXJuIG4uZWF0V2hpbGUoL1tcc1x1MDBhMF0vKX0sdGhpcy5za2lwVG9FbmQ9ZnVuY3Rpb24oKXtuLl9wb3M9bi5fc291cmNlVGV4dC5sZW5ndGh9LHRoaXMuc2tpcFRvPWZ1bmN0aW9uKGUpe24uX3Bvcz1lfSx0aGlzLm1hdGNoPWZ1bmN0aW9uKGUpe3ZhciB0PSEoYXJndW1lbnRzLmxlbmd0aD4xJiZ2b2lkIDAhPT1hcmd1bWVudHNbMV0pfHxhcmd1bWVudHNbMV0scj1hcmd1bWVudHMubGVuZ3RoPjImJnZvaWQgMCE9PWFyZ3VtZW50c1syXSYmYXJndW1lbnRzWzJdLGk9bnVsbCxvPW51bGw7aWYoInN0cmluZyI9PT10eXBlb2YgZSl7bz1uZXcgUmVnRXhwKGUscj8iaSI6ImciKS50ZXN0KG4uX3NvdXJjZVRleHQuc3Vic3RyKG4uX3BvcyxlLmxlbmd0aCkpLGk9ZX1lbHNlIGUgaW5zdGFuY2VvZiBSZWdFeHAmJihvPW4uX3NvdXJjZVRleHQuc2xpY2Uobi5fcG9zKS5tYXRjaChlKSxpPW8mJm9bMF0pO3JldHVybiEobnVsbD09b3x8ISgic3RyaW5nIj09PXR5cGVvZiBlfHxvIGluc3RhbmNlb2YgQXJyYXkmJm4uX3NvdXJjZVRleHQuc3RhcnRzV2l0aChvWzBdLG4uX3BvcykpKSYmKHQmJihuLl9zdGFydD1uLl9wb3MsaSYmaS5sZW5ndGgmJihuLl9wb3MrPWkubGVuZ3RoKSksbyl9LHRoaXMuYmFja1VwPWZ1bmN0aW9uKGUpe24uX3Bvcy09ZX0sdGhpcy5jb2x1bW49ZnVuY3Rpb24oKXtyZXR1cm4gbi5fcG9zfSx0aGlzLmluZGVudGF0aW9uPWZ1bmN0aW9uKCl7dmFyIGU9bi5fc291cmNlVGV4dC5tYXRjaCgvXHMqLyksdD0wO2lmKGUmJjA9PT1lLmxlbmd0aClmb3IodmFyIHI9ZVswXSxpPTA7ci5sZW5ndGg+aTspOT09PXIuY2hhckNvZGVBdChpKT90Kz0yOnQrKyxpKys7cmV0dXJuIHR9LHRoaXMuY3VycmVudD1mdW5jdGlvbigpe3JldHVybiBuLl9zb3VyY2VUZXh0LnNsaWNlKG4uX3N0YXJ0LG4uX3Bvcyl9LHRoaXMuX3N0YXJ0PTAsdGhpcy5fcG9zPTAsdGhpcy5fc291cmNlVGV4dD10fXJldHVybiBlLnByb3RvdHlwZS5fdGVzdE5leHRDaGFyYWN0ZXI9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5fc291cmNlVGV4dC5jaGFyQXQodGhpcy5fcG9zKTtyZXR1cm4ic3RyaW5nIj09PXR5cGVvZiBlP3Q9PT1lOmUgaW5zdGFuY2VvZiBSZWdFeHA/ZS50ZXN0KHQpOmUodCl9LGV9KCk7dC5kZWZhdWx0PWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3ZhciBlPWFyZ3VtZW50cy5sZW5ndGg+MCYmdm9pZCAwIT09YXJndW1lbnRzWzBdP2FyZ3VtZW50c1swXTp7ZWF0V2hpdGVzcGFjZTpmdW5jdGlvbihlKXtyZXR1cm4gZS5lYXRXaGlsZShkLmlzSWdub3JlZCl9LGxleFJ1bGVzOmQuTGV4UnVsZXMscGFyc2VSdWxlczpkLlBhcnNlUnVsZXMsZWRpdG9yQ29uZmlnOnt9fTtyZXR1cm57c3RhcnRTdGF0ZTpmdW5jdGlvbigpe3ZhciB0PXtsZXZlbDowLHN0ZXA6MCxuYW1lOm51bGwsa2luZDpudWxsLHR5cGU6bnVsbCxydWxlOm51bGwsbmVlZHNTZXBlcmF0b3I6ITEscHJldlN0YXRlOm51bGx9O3JldHVybiBhKGUucGFyc2VSdWxlcyx0LCJEb2N1bWVudCIpLHR9LHRva2VuOmZ1bmN0aW9uKHQsbil7cmV0dXJuIGkodCxuLGUpfX19ZnVuY3Rpb24gaShlLHQsbil7dmFyIHI9bi5sZXhSdWxlcyxpPW4ucGFyc2VSdWxlcyxjPW4uZWF0V2hpdGVzcGFjZSxmPW4uZWRpdG9yQ29uZmlnO2lmKHQucnVsZSYmMD09PXQucnVsZS5sZW5ndGg/cyh0KTp0Lm5lZWRzQWR2YW5jZSYmKHQubmVlZHNBZHZhbmNlPSExLHUodCwhMCkpLGUuc29sKCkpe3ZhciBkPWYmJmYudGFiU2l6ZXx8Mjt0LmluZGVudExldmVsPU1hdGguZmxvb3IoZS5pbmRlbnRhdGlvbigpL2QpfWlmKGMoZSkpcmV0dXJuIndzIjt2YXIgbT1wKHIsZSk7aWYoIW0pcmV0dXJuIGUubWF0Y2goL1xTKy8pLGEoaCx0LCJJbnZhbGlkIiksImludmFsaWRjaGFyIjtpZigiQ29tbWVudCI9PT1tLmtpbmQpcmV0dXJuIGEoaCx0LCJDb21tZW50IiksImNvbW1lbnQiO3ZhciBnPW8oe30sdCk7aWYoIlB1bmN0dWF0aW9uIj09PW0ua2luZClpZigvXlt7KFtdLy50ZXN0KG0udmFsdWUpKXQubGV2ZWxzPSh0LmxldmVsc3x8W10pLmNvbmNhdCh0LmluZGVudExldmVsKzEpO2Vsc2UgaWYoL15bfSlcXV0vLnRlc3QobS52YWx1ZSkpe3ZhciB5PXQubGV2ZWxzPSh0LmxldmVsc3x8W10pLnNsaWNlKDAsLTEpO3QuaW5kZW50TGV2ZWwmJnkubGVuZ3RoPjAmJnlbeS5sZW5ndGgtMV08dC5pbmRlbnRMZXZlbCYmKHQuaW5kZW50TGV2ZWw9eVt5Lmxlbmd0aC0xXSl9Zm9yKDt0LnJ1bGU7KXt2YXIgdj0iZnVuY3Rpb24iPT09dHlwZW9mIHQucnVsZT8wPT09dC5zdGVwP3QucnVsZShtLGUpOm51bGw6dC5ydWxlW3Quc3RlcF07aWYodC5uZWVkc1NlcGVyYXRvciYmKHY9diYmdi5zZXBhcmF0b3IpLHYpe2lmKHYub2ZSdWxlJiYodj12Lm9mUnVsZSksInN0cmluZyI9PT10eXBlb2Ygdil7YShpLHQsdik7Y29udGludWV9aWYodi5tYXRjaCYmdi5tYXRjaChtKSlyZXR1cm4gdi51cGRhdGUmJnYudXBkYXRlKHQsbSksIlB1bmN0dWF0aW9uIj09PW0ua2luZD91KHQsITApOnQubmVlZHNBZHZhbmNlPSEwLHYuc3R5bGV9bCh0KX1yZXR1cm4gbyh0LGcpLGEoaCx0LCJJbnZhbGlkIiksImludmFsaWRjaGFyIn1mdW5jdGlvbiBvKGUsdCl7Zm9yKHZhciBuPU9iamVjdC5rZXlzKHQpLHI9MDtyPG4ubGVuZ3RoO3IrKyllW25bcl1dPXRbbltyXV07cmV0dXJuIGV9ZnVuY3Rpb24gYShlLHQsbil7aWYoIWVbbl0pdGhyb3cgbmV3IFR5cGVFcnJvcigiVW5rbm93biBydWxlOiAiK24pO3QucHJldlN0YXRlPWYoe30sdCksdC5raW5kPW4sdC5uYW1lPW51bGwsdC50eXBlPW51bGwsdC5ydWxlPWVbbl0sdC5zdGVwPTAsdC5uZWVkc1NlcGVyYXRvcj0hMX1mdW5jdGlvbiBzKGUpe2UucHJldlN0YXRlJiYoZS5raW5kPWUucHJldlN0YXRlLmtpbmQsZS5uYW1lPWUucHJldlN0YXRlLm5hbWUsZS50eXBlPWUucHJldlN0YXRlLnR5cGUsZS5ydWxlPWUucHJldlN0YXRlLnJ1bGUsZS5zdGVwPWUucHJldlN0YXRlLnN0ZXAsZS5uZWVkc1NlcGVyYXRvcj1lLnByZXZTdGF0ZS5uZWVkc1NlcGVyYXRvcixlLnByZXZTdGF0ZT1lLnByZXZTdGF0ZS5wcmV2U3RhdGUpfWZ1bmN0aW9uIHUoZSx0KXtpZihjKGUpKXtpZihlLnJ1bGUmJmUucnVsZVtlLnN0ZXBdLnNlcGFyYXRvcil7dmFyIG49ZS5ydWxlW2Uuc3RlcF0uc2VwYXJhdG9yO2lmKGUubmVlZHNTZXBlcmF0b3I9IWUubmVlZHNTZXBlcmF0b3IsIWUubmVlZHNTZXBlcmF0b3ImJm4ub2ZSdWxlKXJldHVybn1pZih0KXJldHVybn1mb3IoZS5uZWVkc1NlcGVyYXRvcj0hMSxlLnN0ZXArKztlLnJ1bGUmJiEoQXJyYXkuaXNBcnJheShlLnJ1bGUpJiZlLnN0ZXA8ZS5ydWxlLmxlbmd0aCk7KXMoZSksZS5ydWxlJiYoYyhlKT9lLnJ1bGUmJmUucnVsZVtlLnN0ZXBdLnNlcGFyYXRvciYmKGUubmVlZHNTZXBlcmF0b3I9IWUubmVlZHNTZXBlcmF0b3IpOihlLm5lZWRzU2VwZXJhdG9yPSExLGUuc3RlcCsrKSl9ZnVuY3Rpb24gYyhlKXtyZXR1cm4gQXJyYXkuaXNBcnJheShlLnJ1bGUpJiYic3RyaW5nIiE9PXR5cGVvZiBlLnJ1bGVbZS5zdGVwXSYmZS5ydWxlW2Uuc3RlcF0uaXNMaXN0fWZ1bmN0aW9uIGwoZSl7Zm9yKDtlLnJ1bGUmJighQXJyYXkuaXNBcnJheShlLnJ1bGUpfHwhZS5ydWxlW2Uuc3RlcF0ub2ZSdWxlKTspcyhlKTtlLnJ1bGUmJnUoZSwhMSl9ZnVuY3Rpb24gcChlLHQpe2Zvcih2YXIgbj1PYmplY3Qua2V5cyhlKSxyPTA7cjxuLmxlbmd0aDtyKyspe3ZhciBpPXQubWF0Y2goZVtuW3JdXSk7aWYoaSYmaSBpbnN0YW5jZW9mIEFycmF5KXJldHVybntraW5kOm5bcl0sdmFsdWU6aVswXX19fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgZj1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfTt0LmRlZmF1bHQ9cjt2YXIgZD1uKDI3NSksaD17SW52YWxpZDpbXSxDb21tZW50OltdfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXt2YXIgcj1pKGUsbiksYT12b2lkIDA7cmV0dXJuKDAsby52aXNpdCkodCx7ZW50ZXI6ZnVuY3Rpb24oZSl7aWYoISgiTmFtZSIhPT1lLmtpbmQmJmUubG9jJiZlLmxvYy5zdGFydDw9ciYmcjw9ZS5sb2MuZW5kKSlyZXR1cm4hMTthPWV9LGxlYXZlOmZ1bmN0aW9uKGUpe2lmKGUubG9jJiZlLmxvYy5zdGFydDw9ciYmcjw9ZS5sb2MuZW5kKXJldHVybiExfX0pLGF9ZnVuY3Rpb24gaShlLHQpe3ZhciBuPWUuc3BsaXQoIlxuIikuc2xpY2UoMCx0LmxpbmUpO3JldHVybiB0LmNoYXJhY3RlcituLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS5sZW5ndGgrMX0pLnJlZHVjZShmdW5jdGlvbihlLHQpe3JldHVybiBlK3R9LDApfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmdldEFTVE5vZGVBdFBvc2l0aW9uPXIsdC5wb2ludFRvT2Zmc2V0PWk7dmFyIG89KG4oMjc3KSxuKDcpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxyLG8pe3ZhciBhPW4oMTE3KSxzPWEuTm9VbnVzZWRGcmFnbWVudHMsdT1bc107aWYobyl7dmFyIGM9bigxMTYpLGw9Yy5Lbm93bkZyYWdtZW50TmFtZXM7dS5wdXNoKGwpfXZhciBwPWkuc3BlY2lmaWVkUnVsZXMuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiF1LnNvbWUoZnVuY3Rpb24odCl7cmV0dXJuIHQ9PT1lfSl9KSxmPW5ldyBpLlR5cGVJbmZvKGUpO3ImJkFycmF5LnByb3RvdHlwZS5wdXNoLmFwcGx5KHAscik7dmFyIGQ9KDAsaS52YWxpZGF0ZSkoZSx0LHAsZik7cmV0dXJuIGQubGVuZ3RoPjA/ZC5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuLTE9PT1lLm1lc3NhZ2UuaW5kZXhPZigiVW5rbm93biBkaXJlY3RpdmUiKXx8IShlLm5vZGVzJiZlLm5vZGVzWzBdJiZlLm5vZGVzWzBdLm5hbWUmJiJhcmd1bWVudHMiPT09ZS5ub2Rlc1swXS5uYW1lLnZhbHVlfHxlLm5vZGVzJiZlLm5vZGVzWzBdJiZlLm5vZGVzWzBdLm5hbWUmJmUubm9kZXNbMF0ubmFtZS52YWx1ZSYmImFyZ3VtZW50RGVmaW5pdGlvbnMiPT09ZS5ub2Rlc1swXS5uYW1lLnZhbHVlKX0pOltdfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LnZhbGlkYXRlV2l0aEN1c3RvbVJ1bGVzPXI7dmFyIGk9big3KX0sZnVuY3Rpb24oZSx0LG4pe2UuZXhwb3J0cz1uLnArInN0YXRpYy9tZWRpYS9HcmFwaFFMTGFuZ3VhZ2VTZXJ2aWNlLmpzLmZhMDcxMzhkLmZsb3cifSxmdW5jdGlvbihlLHQsbil7ZS5leHBvcnRzPW4ucCsic3RhdGljL21lZGlhL2F1dG9jb21wbGV0ZVV0aWxzLmpzLjRjZTdiYTE5LmZsb3cifSxmdW5jdGlvbihlLHQsbil7ZS5leHBvcnRzPW4ucCsic3RhdGljL21lZGlhL2dldEF1dG9jb21wbGV0ZVN1Z2dlc3Rpb25zLmpzLjVmNzM1YzdiLmZsb3cifSxmdW5jdGlvbihlLHQsbil7ZS5leHBvcnRzPW4ucCsic3RhdGljL21lZGlhL2dldERlZmluaXRpb24uanMuMGM0ODY2OGUuZmxvdyJ9LGZ1bmN0aW9uKGUsdCxuKXtlLmV4cG9ydHM9bi5wKyJzdGF0aWMvbWVkaWEvZ2V0RGlhZ25vc3RpY3MuanMuODg5YzBiMjcuZmxvdyJ9LGZ1bmN0aW9uKGUsdCxuKXtlLmV4cG9ydHM9bi5wKyJzdGF0aWMvbWVkaWEvZ2V0T3V0bGluZS5qcy40NThhMzUxOC5mbG93In0sZnVuY3Rpb24oZSx0LG4pe2UuZXhwb3J0cz1uLnArInN0YXRpYy9tZWRpYS9pbmRleC5qcy42NDEyMzBmNS5mbG93In0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDIpLGk9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShyKSxvPW4oNTApLGE9WyJlcnJvciIsIndhcm5pbmciLCJpbmZvcm1hdGlvbiIsImhpbnQiXSxzPXsiR3JhcGhRTDogVmFsaWRhdGlvbiI6InZhbGlkYXRpb24iLCJHcmFwaFFMOiBEZXByZWNhdGlvbiI6ImRlcHJlY2F0aW9uIiwiR3JhcGhRTDogU3ludGF4Ijoic3ludGF4In07aS5kZWZhdWx0LnJlZ2lzdGVySGVscGVyKCJsaW50IiwiZ3JhcGhxbCIsZnVuY3Rpb24oZSx0KXt2YXIgbj10LnNjaGVtYTtyZXR1cm4oMCxvLmdldERpYWdub3N0aWNzKShlLG4pLm1hcChmdW5jdGlvbihlKXtyZXR1cm57bWVzc2FnZTplLm1lc3NhZ2Usc2V2ZXJpdHk6YVtlLnNldmVyaXR5LTFdLHR5cGU6c1tlLnNvdXJjZV0sZnJvbTppLmRlZmF1bHQuUG9zKGUucmFuZ2Uuc3RhcnQubGluZSxlLnJhbmdlLnN0YXJ0LmNoYXJhY3RlciksdG86aS5kZWZhdWx0LlBvcyhlLnJhbmdlLmVuZC5saW5lLGUucmFuZ2UuZW5kLmNoYXJhY3Rlcil9fSl9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1mdW5jdGlvbiBpKGUsdCxuKXtvKGUsdCxuKSx1KGUsdCxuLHQudHlwZSl9ZnVuY3Rpb24gbyhlLHQsbil7dmFyIHI9dC5maWVsZERlZi5uYW1lOyJfXyIhPT1yLnNsaWNlKDAsMikmJihsKGUsdCxuLHQucGFyZW50VHlwZSksZChlLCIuIikpLGQoZSxyLCJmaWVsZC1uYW1lIixuLCgwLGIuZ2V0RmllbGRSZWZlcmVuY2UpKHQpKX1mdW5jdGlvbiBhKGUsdCxuKXtkKGUsIkAiK3QuZGlyZWN0aXZlRGVmLm5hbWUsImRpcmVjdGl2ZS1uYW1lIixuLCgwLGIuZ2V0RGlyZWN0aXZlUmVmZXJlbmNlKSh0KSl9ZnVuY3Rpb24gcyhlLHQsbil7dC5kaXJlY3RpdmVEZWY/YShlLHQsbik6dC5maWVsZERlZiYmbyhlLHQsbik7dmFyIHI9dC5hcmdEZWYubmFtZTtkKGUsIigiKSxkKGUsciwiYXJnLW5hbWUiLG4sKDAsYi5nZXRBcmd1bWVudFJlZmVyZW5jZSkodCkpLHUoZSx0LG4sdC5pbnB1dFR5cGUpLGQoZSwiKSIpfWZ1bmN0aW9uIHUoZSx0LG4scil7ZChlLCI6ICIpLGwoZSx0LG4scil9ZnVuY3Rpb24gYyhlLHQsbil7dmFyIHI9dC5lbnVtVmFsdWUubmFtZTtsKGUsdCxuLHQuaW5wdXRUeXBlKSxkKGUsIi4iKSxkKGUsciwiZW51bS12YWx1ZSIsbiwoMCxiLmdldEVudW1WYWx1ZVJlZmVyZW5jZSkodCkpfWZ1bmN0aW9uIGwoZSx0LG4scil7ciBpbnN0YW5jZW9mIGguR3JhcGhRTE5vbk51bGw/KGwoZSx0LG4sci5vZlR5cGUpLGQoZSwiISIpKTpyIGluc3RhbmNlb2YgaC5HcmFwaFFMTGlzdD8oZChlLCJbIiksbChlLHQsbixyLm9mVHlwZSksZChlLCJdIikpOmQoZSxyLm5hbWUsInR5cGUtbmFtZSIsbiwoMCxiLmdldFR5cGVSZWZlcmVuY2UpKHQscikpfWZ1bmN0aW9uIHAoZSx0LG4pe3ZhciByPW4uZGVzY3JpcHRpb247aWYocil7dmFyIGk9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7aS5jbGFzc05hbWU9ImluZm8tZGVzY3JpcHRpb24iLHQucmVuZGVyRGVzY3JpcHRpb24/aS5pbm5lckhUTUw9dC5yZW5kZXJEZXNjcmlwdGlvbihyKTppLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHIpKSxlLmFwcGVuZENoaWxkKGkpfWYoZSx0LG4pfWZ1bmN0aW9uIGYoZSx0LG4pe3ZhciByPW4uZGVwcmVjYXRpb25SZWFzb247aWYocil7dmFyIGk9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7aS5jbGFzc05hbWU9ImluZm8tZGVwcmVjYXRpb24iLHQucmVuZGVyRGVzY3JpcHRpb24/aS5pbm5lckhUTUw9dC5yZW5kZXJEZXNjcmlwdGlvbihyKTppLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHIpKTt2YXIgbz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzcGFuIik7by5jbGFzc05hbWU9ImluZm8tZGVwcmVjYXRpb24tbGFiZWwiLG8uYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIkRlcHJlY2F0ZWQ6ICIpKSxpLmluc2VydEJlZm9yZShvLGkuZmlyc3RDaGlsZCksZS5hcHBlbmRDaGlsZChpKX19ZnVuY3Rpb24gZChlLHQsbixyLGkpe2lmKG4pe3ZhciBvPXIub25DbGljayxhPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQobz8iYSI6InNwYW4iKTtvJiYoYS5ocmVmPSJqYXZhc2NyaXB0OnZvaWQgMCIsYS5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsZnVuY3Rpb24oZSl7byhpLGUpfSkpLGEuY2xhc3NOYW1lPW4sYS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSh0KSksZS5hcHBlbmRDaGlsZChhKX1lbHNlIGUuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUodCkpfXZhciBoPW4oNyksbT1uKDIpLGc9cihtKSx5PW4oMjgwKSx2PXIoeSksYj1uKDI4Mik7big2MDkpLGcuZGVmYXVsdC5yZWdpc3RlckhlbHBlcigiaW5mbyIsImdyYXBocWwiLGZ1bmN0aW9uKGUsdCl7aWYodC5zY2hlbWEmJmUuc3RhdGUpe3ZhciBuPWUuc3RhdGUscj1uLmtpbmQsbz1uLnN0ZXAsdT0oMCx2LmRlZmF1bHQpKHQuc2NoZW1hLGUuc3RhdGUpO2lmKCJGaWVsZCI9PT1yJiYwPT09byYmdS5maWVsZERlZnx8IkFsaWFzZWRGaWVsZCI9PT1yJiYyPT09byYmdS5maWVsZERlZil7dmFyIGY9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7cmV0dXJuIGkoZix1LHQpLHAoZix0LHUuZmllbGREZWYpLGZ9aWYoIkRpcmVjdGl2ZSI9PT1yJiYxPT09byYmdS5kaXJlY3RpdmVEZWYpe3ZhciBkPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpO3JldHVybiBhKGQsdSx0KSxwKGQsdCx1LmRpcmVjdGl2ZURlZiksZH1pZigiQXJndW1lbnQiPT09ciYmMD09PW8mJnUuYXJnRGVmKXt2YXIgaD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKTtyZXR1cm4gcyhoLHUsdCkscChoLHQsdS5hcmdEZWYpLGh9aWYoIkVudW1WYWx1ZSI9PT1yJiZ1LmVudW1WYWx1ZSYmdS5lbnVtVmFsdWUuZGVzY3JpcHRpb24pe3ZhciBtPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpO3JldHVybiBjKG0sdSx0KSxwKG0sdCx1LmVudW1WYWx1ZSksbX1pZigiTmFtZWRUeXBlIj09PXImJnUudHlwZSYmdS50eXBlLmRlc2NyaXB0aW9uKXt2YXIgZz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKTtyZXR1cm4gbChnLHUsdCx1LnR5cGUpLHAoZyx0LHUudHlwZSksZ319fSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm57b3B0aW9uczplIGluc3RhbmNlb2YgRnVuY3Rpb24/e3JlbmRlcjplfTohMD09PWU/e306ZX19ZnVuY3Rpb24gaShlKXt2YXIgdD1lLnN0YXRlLmluZm8ub3B0aW9ucztyZXR1cm4gdCYmdC5ob3ZlclRpbWV8fDUwMH1mdW5jdGlvbiBvKGUsdCl7dmFyIG49ZS5zdGF0ZS5pbmZvLHI9dC50YXJnZXR8fHQuc3JjRWxlbWVudDtpZigiU1BBTiI9PT1yLm5vZGVOYW1lJiZ2b2lkIDA9PT1uLmhvdmVyVGltZW91dCl7dmFyIG89ci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSxzPWkoZSk7bi5ob3ZlclRpbWVvdXQ9c2V0VGltZW91dChwLHMpO3ZhciB1PWZ1bmN0aW9uKCl7Y2xlYXJUaW1lb3V0KG4uaG92ZXJUaW1lb3V0KSxuLmhvdmVyVGltZW91dD1zZXRUaW1lb3V0KHAscyl9LGw9ZnVuY3Rpb24gdCgpe2MuZGVmYXVsdC5vZmYoZG9jdW1lbnQsIm1vdXNlbW92ZSIsdSksYy5kZWZhdWx0Lm9mZihlLmdldFdyYXBwZXJFbGVtZW50KCksIm1vdXNlb3V0Iix0KSxjbGVhclRpbWVvdXQobi5ob3ZlclRpbWVvdXQpLG4uaG92ZXJUaW1lb3V0PXZvaWQgMH0scD1mdW5jdGlvbigpe2MuZGVmYXVsdC5vZmYoZG9jdW1lbnQsIm1vdXNlbW92ZSIsdSksYy5kZWZhdWx0Lm9mZihlLmdldFdyYXBwZXJFbGVtZW50KCksIm1vdXNlb3V0IixsKSxuLmhvdmVyVGltZW91dD12b2lkIDAsYShlLG8pfTtjLmRlZmF1bHQub24oZG9jdW1lbnQsIm1vdXNlbW92ZSIsdSksYy5kZWZhdWx0Lm9uKGUuZ2V0V3JhcHBlckVsZW1lbnQoKSwibW91c2VvdXQiLGwpfX1mdW5jdGlvbiBhKGUsdCl7dmFyIG49ZS5jb29yZHNDaGFyKHtsZWZ0Oih0LmxlZnQrdC5yaWdodCkvMix0b3A6KHQudG9wK3QuYm90dG9tKS8yfSkscj1lLnN0YXRlLmluZm8saT1yLm9wdGlvbnMsbz1pLnJlbmRlcnx8ZS5nZXRIZWxwZXIobiwiaW5mbyIpO2lmKG8pe3ZhciBhPWUuZ2V0VG9rZW5BdChuLCEwKTtpZihhKXt2YXIgdT1vKGEsaSxlLG4pO3UmJnMoZSx0LHUpfX19ZnVuY3Rpb24gcyhlLHQsbil7dmFyIHI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7ci5jbGFzc05hbWU9IkNvZGVNaXJyb3ItaW5mbyIsci5hcHBlbmRDaGlsZChuKSxkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHIpO3ZhciBpPXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksbz1yLmN1cnJlbnRTdHlsZXx8d2luZG93LmdldENvbXB1dGVkU3R5bGUociksYT1pLnJpZ2h0LWkubGVmdCtwYXJzZUZsb2F0KG8ubWFyZ2luTGVmdCkrcGFyc2VGbG9hdChvLm1hcmdpblJpZ2h0KSxzPWkuYm90dG9tLWkudG9wK3BhcnNlRmxvYXQoby5tYXJnaW5Ub3ApK3BhcnNlRmxvYXQoby5tYXJnaW5Cb3R0b20pLHU9dC5ib3R0b207cz53aW5kb3cuaW5uZXJIZWlnaHQtdC5ib3R0b20tMTUmJnQudG9wPndpbmRvdy5pbm5lckhlaWdodC10LmJvdHRvbSYmKHU9dC50b3AtcyksdTwwJiYodT10LmJvdHRvbSk7dmFyIGw9TWF0aC5tYXgoMCx3aW5kb3cuaW5uZXJXaWR0aC1hLTE1KTtsPnQubGVmdCYmKGw9dC5sZWZ0KSxyLnN0eWxlLm9wYWNpdHk9MSxyLnN0eWxlLnRvcD11KyJweCIsci5zdHlsZS5sZWZ0PWwrInB4Ijt2YXIgcD12b2lkIDAsZj1mdW5jdGlvbigpe2NsZWFyVGltZW91dChwKX0sZD1mdW5jdGlvbigpe2NsZWFyVGltZW91dChwKSxwPXNldFRpbWVvdXQoaCwyMDApfSxoPWZ1bmN0aW9uKCl7Yy5kZWZhdWx0Lm9mZihyLCJtb3VzZW92ZXIiLGYpLGMuZGVmYXVsdC5vZmYociwibW91c2VvdXQiLGQpLGMuZGVmYXVsdC5vZmYoZS5nZXRXcmFwcGVyRWxlbWVudCgpLCJtb3VzZW91dCIsZCksci5zdHlsZS5vcGFjaXR5PyhyLnN0eWxlLm9wYWNpdHk9MCxzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7ci5wYXJlbnROb2RlJiZyLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQocil9LDYwMCkpOnIucGFyZW50Tm9kZSYmci5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHIpfTtjLmRlZmF1bHQub24ociwibW91c2VvdmVyIixmKSxjLmRlZmF1bHQub24ociwibW91c2VvdXQiLGQpLGMuZGVmYXVsdC5vbihlLmdldFdyYXBwZXJFbGVtZW50KCksIm1vdXNlb3V0IixkKX12YXIgdT1uKDIpLGM9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fSh1KTtjLmRlZmF1bHQuZGVmaW5lT3B0aW9uKCJpbmZvIiwhMSxmdW5jdGlvbihlLHQsbil7aWYobiYmbiE9PWMuZGVmYXVsdC5Jbml0KXt2YXIgaT1lLnN0YXRlLmluZm8ub25Nb3VzZU92ZXI7Yy5kZWZhdWx0Lm9mZihlLmdldFdyYXBwZXJFbGVtZW50KCksIm1vdXNlb3ZlciIsaSksY2xlYXJUaW1lb3V0KGUuc3RhdGUuaW5mby5ob3ZlclRpbWVvdXQpLGRlbGV0ZSBlLnN0YXRlLmluZm99aWYodCl7dmFyIGE9ZS5zdGF0ZS5pbmZvPXIodCk7YS5vbk1vdXNlT3Zlcj1vLmJpbmQobnVsbCxlKSxjLmRlZmF1bHQub24oZS5nZXRXcmFwcGVyRWxlbWVudCgpLCJtb3VzZW92ZXIiLGEub25Nb3VzZU92ZXIpfX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fXZhciBpPW4oMiksbz1yKGkpLGE9bigyODApLHM9cihhKSx1PW4oMjgyKTtuKDYxMSksby5kZWZhdWx0LnJlZ2lzdGVySGVscGVyKCJqdW1wIiwiZ3JhcGhxbCIsZnVuY3Rpb24oZSx0KXtpZih0LnNjaGVtYSYmdC5vbkNsaWNrJiZlLnN0YXRlKXt2YXIgbj1lLnN0YXRlLHI9bi5raW5kLGk9bi5zdGVwLG89KDAscy5kZWZhdWx0KSh0LnNjaGVtYSxuKTtyZXR1cm4iRmllbGQiPT09ciYmMD09PWkmJm8uZmllbGREZWZ8fCJBbGlhc2VkRmllbGQiPT09ciYmMj09PWkmJm8uZmllbGREZWY/KDAsdS5nZXRGaWVsZFJlZmVyZW5jZSkobyk6IkRpcmVjdGl2ZSI9PT1yJiYxPT09aSYmby5kaXJlY3RpdmVEZWY/KDAsdS5nZXREaXJlY3RpdmVSZWZlcmVuY2UpKG8pOiJBcmd1bWVudCI9PT1yJiYwPT09aSYmby5hcmdEZWY/KDAsdS5nZXRBcmd1bWVudFJlZmVyZW5jZSkobyk6IkVudW1WYWx1ZSI9PT1yJiZvLmVudW1WYWx1ZT8oMCx1LmdldEVudW1WYWx1ZVJlZmVyZW5jZSkobyk6Ik5hbWVkVHlwZSI9PT1yJiZvLnR5cGU/KDAsdS5nZXRUeXBlUmVmZXJlbmNlKShvKTp2b2lkIDB9fSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPXQudGFyZ2V0fHx0LnNyY0VsZW1lbnQ7aWYoIlNQQU4iPT09bi5ub2RlTmFtZSl7dmFyIHI9bi5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSxpPXtsZWZ0OihyLmxlZnQrci5yaWdodCkvMix0b3A6KHIudG9wK3IuYm90dG9tKS8yfTtlLnN0YXRlLmp1bXAuY3Vyc29yPWksZS5zdGF0ZS5qdW1wLmlzSG9sZGluZ01vZGlmaWVyJiZzKGUpfX1mdW5jdGlvbiBpKGUpe2lmKCFlLnN0YXRlLmp1bXAuaXNIb2xkaW5nTW9kaWZpZXImJmUuc3RhdGUuanVtcC5jdXJzb3IpcmV0dXJuIHZvaWQoZS5zdGF0ZS5qdW1wLmN1cnNvcj1udWxsKTtlLnN0YXRlLmp1bXAuaXNIb2xkaW5nTW9kaWZpZXImJmUuc3RhdGUuanVtcC5tYXJrZXImJnUoZSl9ZnVuY3Rpb24gbyhlLHQpe2lmKCFlLnN0YXRlLmp1bXAuaXNIb2xkaW5nTW9kaWZpZXImJmEodC5rZXkpKXtlLnN0YXRlLmp1bXAuaXNIb2xkaW5nTW9kaWZpZXI9ITAsZS5zdGF0ZS5qdW1wLmN1cnNvciYmcyhlKTt2YXIgbj1mdW5jdGlvbiBuKG8pe28uY29kZT09PXQuY29kZSYmKGUuc3RhdGUuanVtcC5pc0hvbGRpbmdNb2RpZmllcj0hMSxlLnN0YXRlLmp1bXAubWFya2VyJiZ1KGUpLGwuZGVmYXVsdC5vZmYoZG9jdW1lbnQsImtleXVwIixuKSxsLmRlZmF1bHQub2ZmKGRvY3VtZW50LCJjbGljayIsciksZS5vZmYoIm1vdXNlZG93biIsaSkpfSxyPWZ1bmN0aW9uKHQpe3ZhciBuPWUuc3RhdGUuanVtcC5kZXN0aW5hdGlvbjtuJiZlLnN0YXRlLmp1bXAub3B0aW9ucy5vbkNsaWNrKG4sdCl9LGk9ZnVuY3Rpb24odCxuKXtlLnN0YXRlLmp1bXAuZGVzdGluYXRpb24mJihuLmNvZGVtaXJyb3JJZ25vcmU9ITApfTtsLmRlZmF1bHQub24oZG9jdW1lbnQsImtleXVwIixuKSxsLmRlZmF1bHQub24oZG9jdW1lbnQsImNsaWNrIixyKSxlLm9uKCJtb3VzZWRvd24iLGkpfX1mdW5jdGlvbiBhKGUpe3JldHVybiBlPT09KHA/Ik1ldGEiOiJDb250cm9sIil9ZnVuY3Rpb24gcyhlKXtpZighZS5zdGF0ZS5qdW1wLm1hcmtlcil7dmFyIHQ9ZS5zdGF0ZS5qdW1wLmN1cnNvcixuPWUuY29vcmRzQ2hhcih0KSxyPWUuZ2V0VG9rZW5BdChuLCEwKSxpPWUuc3RhdGUuanVtcC5vcHRpb25zLG89aS5nZXREZXN0aW5hdGlvbnx8ZS5nZXRIZWxwZXIobiwianVtcCIpO2lmKG8pe3ZhciBhPW8ocixpLGUpO2lmKGEpe3ZhciBzPWUubWFya1RleHQoe2xpbmU6bi5saW5lLGNoOnIuc3RhcnR9LHtsaW5lOm4ubGluZSxjaDpyLmVuZH0se2NsYXNzTmFtZToiQ29kZU1pcnJvci1qdW1wLXRva2VuIn0pO2Uuc3RhdGUuanVtcC5tYXJrZXI9cyxlLnN0YXRlLmp1bXAuZGVzdGluYXRpb249YX19fX1mdW5jdGlvbiB1KGUpe3ZhciB0PWUuc3RhdGUuanVtcC5tYXJrZXI7ZS5zdGF0ZS5qdW1wLm1hcmtlcj1udWxsLGUuc3RhdGUuanVtcC5kZXN0aW5hdGlvbj1udWxsLHQuY2xlYXIoKX12YXIgYz1uKDIpLGw9ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fShjKTtsLmRlZmF1bHQuZGVmaW5lT3B0aW9uKCJqdW1wIiwhMSxmdW5jdGlvbihlLHQsbil7aWYobiYmbiE9PWwuZGVmYXVsdC5Jbml0KXt2YXIgYT1lLnN0YXRlLmp1bXAub25Nb3VzZU92ZXI7bC5kZWZhdWx0Lm9mZihlLmdldFdyYXBwZXJFbGVtZW50KCksIm1vdXNlb3ZlciIsYSk7dmFyIHM9ZS5zdGF0ZS5qdW1wLm9uTW91c2VPdXQ7bC5kZWZhdWx0Lm9mZihlLmdldFdyYXBwZXJFbGVtZW50KCksIm1vdXNlb3V0IixzKSxsLmRlZmF1bHQub2ZmKGRvY3VtZW50LCJrZXlkb3duIixlLnN0YXRlLmp1bXAub25LZXlEb3duKSxkZWxldGUgZS5zdGF0ZS5qdW1wfWlmKHQpe3ZhciB1PWUuc3RhdGUuanVtcD17b3B0aW9uczp0LG9uTW91c2VPdmVyOnIuYmluZChudWxsLGUpLG9uTW91c2VPdXQ6aS5iaW5kKG51bGwsZSksb25LZXlEb3duOm8uYmluZChudWxsLGUpfTtsLmRlZmF1bHQub24oZS5nZXRXcmFwcGVyRWxlbWVudCgpLCJtb3VzZW92ZXIiLHUub25Nb3VzZU92ZXIpLGwuZGVmYXVsdC5vbihlLmdldFdyYXBwZXJFbGVtZW50KCksIm1vdXNlb3V0Iix1Lm9uTW91c2VPdXQpLGwuZGVmYXVsdC5vbihkb2N1bWVudCwia2V5ZG93biIsdS5vbktleURvd24pfX0pO3ZhciBwPW5hdmlnYXRvciYmLTEhPT1uYXZpZ2F0b3IuYXBwVmVyc2lvbi5pbmRleE9mKCJNYWMiKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe2Zvcih2YXIgbj0wO248dC5sZW5ndGg7bisrKXt2YXIgcj10W25dO3IuZW51bWVyYWJsZT1yLmVudW1lcmFibGV8fCExLHIuY29uZmlndXJhYmxlPSEwLCJ2YWx1ZSJpbiByJiYoci53cml0YWJsZT0hMCksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsci5rZXkscil9fXJldHVybiBmdW5jdGlvbih0LG4scil7cmV0dXJuIG4mJmUodC5wcm90b3R5cGUsbiksciYmZSh0LHIpLHR9fSgpLG89ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7cih0aGlzLGUpLHRoaXMuc2l6ZXM9W119cmV0dXJuIGkoZSxbe2tleToidXBkYXRlU2l6ZXMiLHZhbHVlOmZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7ZS5mb3JFYWNoKGZ1bmN0aW9uKGUsbil7dmFyIHI9ZS5nZXRDbGllbnRIZWlnaHQoKTtuPD10LnNpemVzLmxlbmd0aCYmciE9PXQuc2l6ZXNbbl0mJmUuZ2V0Q29kZU1pcnJvcigpLnNldFNpemUoKSx0LnNpemVzW25dPXJ9KX19XSksZX0oKTt0LmRlZmF1bHQ9b30sZnVuY3Rpb24oZSx0KXtlLmV4cG9ydHM9ZnVuY3Rpb24oKXt2YXIgZT1kb2N1bWVudC5nZXRTZWxlY3Rpb24oKTtpZighZS5yYW5nZUNvdW50KXJldHVybiBmdW5jdGlvbigpe307Zm9yKHZhciB0PWRvY3VtZW50LmFjdGl2ZUVsZW1lbnQsbj1bXSxyPTA7cjxlLnJhbmdlQ291bnQ7cisrKW4ucHVzaChlLmdldFJhbmdlQXQocikpO3N3aXRjaCh0LnRhZ05hbWUudG9VcHBlckNhc2UoKSl7Y2FzZSJJTlBVVCI6Y2FzZSJURVhUQVJFQSI6dC5ibHVyKCk7YnJlYWs7ZGVmYXVsdDp0PW51bGx9cmV0dXJuIGUucmVtb3ZlQWxsUmFuZ2VzKCksZnVuY3Rpb24oKXsiQ2FyZXQiPT09ZS50eXBlJiZlLnJlbW92ZUFsbFJhbmdlcygpLGUucmFuZ2VDb3VudHx8bi5mb3JFYWNoKGZ1bmN0aW9uKHQpe2UuYWRkUmFuZ2UodCl9KSx0JiZ0LmZvY3VzKCl9fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPW4oMjQpLHM9big2MTUpLHU9big2MTYpLGM9bigzMDgpLGw9big2MTcpLHA9bigxKSxmPW4oOSksZD1uKDgpLGg9bigyNTQpLG09bigxMzIpLGc9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0KXt2YXIgbj1lLmNhbGwodGhpcyx0KXx8dGhpcztyZXR1cm4gbi5zaGFyZT1mdW5jdGlvbigpe24ucHJvcHMuc2hhcmUoKX0sbi5yZW5kZXJBdXRoU2hhcmluZ1dhcm5pbmc9ZnVuY3Rpb24oKXtyZXR1cm4gbi5wcm9wcy5pc1NoYXJpbmdBdXRob3JpemF0aW9uP28uY3JlYXRlRWxlbWVudChfLG51bGwpOm51bGx9LG4udG9nZ2xlVG9vbHRpcD1mdW5jdGlvbigpe24uc2V0U3RhdGUoZnVuY3Rpb24oZSl7cmV0dXJue29wZW46IWUub3Blbn19KX0sbi5zdGF0ZT17b3BlbjohMX0sbn1yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMuc3RhdGUub3Blbix0PXRoaXMucHJvcHMsbj10LmFsbFRhYnMscj10LmhlYWRlcnMsaT10Lmhpc3RvcnkscD10LnNoYXJlVXJsLGY9dC5yZXNoYXJlLGQ9dC50aGVtZTtyZXR1cm4gby5jcmVhdGVFbGVtZW50KE4sbnVsbCxvLmNyZWF0ZUVsZW1lbnQoTCxudWxsLG8uY3JlYXRlRWxlbWVudCgiZGl2Iix7b25DbGljazp0aGlzLnRvZ2dsZVRvb2x0aXB9LHRoaXMucHJvcHMuY2hpbGRyZW4pLGUmJm8uY3JlYXRlRWxlbWVudChQLG51bGwsby5jcmVhdGVFbGVtZW50KHUuZGVmYXVsdCx7b3BlbjplLG9uQ2xvc2U6dGhpcy50b2dnbGVUb29sdGlwLGFuY2hvck9yaWdpbjp7aG9yaXpvbnRhbDoicmlnaHQiLHZlcnRpY2FsOiJib3R0b20ifSxyZW5kZXJBZnRlckNvbnRlbnQ6dGhpcy5yZW5kZXJBdXRoU2hhcmluZ1dhcm5pbmd9LG8uY3JlYXRlRWxlbWVudCgiZGl2IixudWxsLG8uY3JlYXRlRWxlbWVudChNLG51bGwsby5jcmVhdGVFbGVtZW50KEkse29uQ2xpY2s6dGhpcy5wcm9wcy50b2dnbGVTaGFyZUFsbFRhYnN9LCJTaGFyZSBhbGwgdGFicyIsIiAiKSxvLmNyZWF0ZUVsZW1lbnQocy5kZWZhdWx0LHtjaGVja2VkOm4sb25DaGFuZ2U6dGhpcy5wcm9wcy50b2dnbGVTaGFyZUFsbFRhYnN9KSksby5jcmVhdGVFbGVtZW50KE0sbnVsbCxvLmNyZWF0ZUVsZW1lbnQoSSx7b25DbGljazp0aGlzLnByb3BzLnRvZ2dsZVNoYXJlSGVhZGVyc30sIkhUVFAgaGVhZGVycyIsIiAiKSxvLmNyZWF0ZUVsZW1lbnQocy5kZWZhdWx0LHtjaGVja2VkOnIsb25DaGFuZ2U6dGhpcy5wcm9wcy50b2dnbGVTaGFyZUhlYWRlcnN9KSksby5jcmVhdGVFbGVtZW50KE0sbnVsbCxvLmNyZWF0ZUVsZW1lbnQoSSx7b25DbGljazp0aGlzLnByb3BzLnRvZ2dsZVNoYXJlSGlzdG9yeX0sIkhpc3RvcnkiLCIgIiksby5jcmVhdGVFbGVtZW50KHMuZGVmYXVsdCx7Y2hlY2tlZDppLG9uQ2hhbmdlOnRoaXMucHJvcHMudG9nZ2xlU2hhcmVIaXN0b3J5fSkpLHAmJm8uY3JlYXRlRWxlbWVudChNLG51bGwsby5jcmVhdGVFbGVtZW50KFIse3ZhbHVlOnAsZGlzYWJsZWQ6ITB9KSxvLmNyZWF0ZUVsZW1lbnQoaixudWxsLG8uY3JlYXRlRWxlbWVudChsLmRlZmF1bHQse3RleHQ6cH0sby5jcmVhdGVFbGVtZW50KGEuU2hhcmVJY29uLHtjb2xvcjpkLmNvbG91cnMuZGFya0JsdWUzMCx3aWR0aDoyNSxoZWlnaHQ6MjUsdGl0bGU6IkNvcHkgVVJMIHRvIENsaXBib2FyZCJ9KSkpKSxvLmNyZWF0ZUVsZW1lbnQoTSxudWxsLG8uY3JlYXRlRWxlbWVudCgiZGl2IixudWxsKSxvLmNyZWF0ZUVsZW1lbnQoYy5CdXR0b24se2hpZGVBcnJvdzohMCxvbkNsaWNrOnRoaXMuc2hhcmV9LGYmJnA/IlJlc2hhcmUiOiJTaGFyZSIpKSkpKSkpfSx0fShvLkNvbXBvbmVudCkseT1kLmNyZWF0ZVN0cnVjdHVyZWRTZWxlY3Rvcih7aGlzdG9yeTpoLmdldFNoYXJpbmdIaXN0b3J5LGhlYWRlcnM6aC5nZXRTaGFyaW5nSGVhZGVycyxhbGxUYWJzOmguZ2V0U2hhcmluZ0FsbFRhYnMsc2hhcmVVcmw6aC5nZXRTaGFyZVVybH0pO3QuZGVmYXVsdD1wLndpdGhUaGVtZShmLmNvbm5lY3QoeSx7dG9nZ2xlU2hhcmVBbGxUYWJzOm0udG9nZ2xlU2hhcmVBbGxUYWJzLHRvZ2dsZVNoYXJlSGVhZGVyczptLnRvZ2dsZVNoYXJlSGVhZGVycyx0b2dnbGVTaGFyZUhpc3Rvcnk6bS50b2dnbGVTaGFyZUhpc3Rvcnksc2hhcmU6bS5zaGFyZX0pKGcpKTt2YXIgdixiLHgsQyxFLEQsdyxTLGssQSxfPWZ1bmN0aW9uKCl7cmV0dXJuIG8uY3JlYXRlRWxlbWVudChPLG51bGwsby5jcmVhdGVFbGVtZW50KEYsbnVsbCwiV2F0Y2ggb3V0ISIpLCJZb3VcdTIwMTlyZSBzaGFyaW5nIHlvdXIgIixvLmNyZWF0ZUVsZW1lbnQoImNvZGUiLG51bGwsIkF1dGhvcml6YXRpb24iKSwiIGhlYWRlciB3aXRoIHRoZSB3b3JsZCEiKX0sVD1wLmtleWZyYW1lcyh2fHwodj1pKFsiXG4gIDAlIHtcbiAgICB0cmFuc2Zvcm06IHNjYWxlKDEuMDQpO1xuICB9XG5cbiAgMTAwJSB7XG4gICAgdHJhbnNmb3JtOiBzY2FsZSgxKTtcbiAgfVxuIl0sWyJcbiAgMCUge1xuICAgIHRyYW5zZm9ybTogc2NhbGUoMS4wNCk7XG4gIH1cblxuICAxMDAlIHtcbiAgICB0cmFuc2Zvcm06IHNjYWxlKDEpO1xuICB9XG4iXSkpKSxPPXAuc3R5bGVkLmRpdihifHwoYj1pKFsiXG4gIHBhZGRpbmc6IDEycHggMTZweDtcbiAgbWFyZ2luLXRvcDogMTBweDtcblxuICBmb250LXNpemU6IDE0cHg7XG4gIGxldHRlci1zcGFjaW5nOiBub3JtYWw7XG5cbiAgY3Vyc29yOiBkZWZhdWx0O1xuICBib3JkZXItcmFkaXVzOiAycHg7XG4gIGJhY2tncm91bmQ6ICNmM2Y0ZjQ7XG4gIGJveC1zaGFkb3c6IDAgMXB4IDZweCAwIHJnYmEoMCwgMCwgMCwgMC4xNSk7XG5cbiAgYW5pbWF0aW9uOiAiLCIgMC43cyBlYXNlLWluLW91dCBpbmZpbml0ZSBhbHRlcm5hdGU7XG4iXSxbIlxuICBwYWRkaW5nOiAxMnB4IDE2cHg7XG4gIG1hcmdpbi10b3A6IDEwcHg7XG5cbiAgZm9udC1zaXplOiAxNHB4O1xuICBsZXR0ZXItc3BhY2luZzogbm9ybWFsO1xuXG4gIGN1cnNvcjogZGVmYXVsdDtcbiAgYm9yZGVyLXJhZGl1czogMnB4O1xuICBiYWNrZ3JvdW5kOiAjZjNmNGY0O1xuICBib3gtc2hhZG93OiAwIDFweCA2cHggMCByZ2JhKDAsIDAsIDAsIDAuMTUpO1xuXG4gIGFuaW1hdGlvbjogIiwiIDAuN3MgZWFzZS1pbi1vdXQgaW5maW5pdGUgYWx0ZXJuYXRlO1xuIl0pKSxUKSxGPXAuc3R5bGVkLmRpdih4fHwoeD1pKFsiXG4gIG1hcmdpbi1yaWdodDogM3B4O1xuICBtYXJnaW4tYm90dG9tOiAycHg7XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xuICBjb2xvcjogIzJhN2VkMjtcbiJdLFsiXG4gIG1hcmdpbi1yaWdodDogM3B4O1xuICBtYXJnaW4tYm90dG9tOiAycHg7XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xuICBjb2xvcjogIzJhN2VkMjtcbiJdKSkpLE49cC5zdHlsZWQuZGl2KEN8fChDPWkoWyJcbiAgei1pbmRleDogMTAwNTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBtYXJnaW4tbGVmdDogNnB4O1xuIl0sWyJcbiAgei1pbmRleDogMTAwNTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBtYXJnaW4tbGVmdDogNnB4O1xuIl0pKSksST1wLnN0eWxlZC5kaXYoRXx8KEU9aShbIlxuICBtYXJnaW4tcmlnaHQ6IDEwcHg7XG5cbiAgZm9udC1zaXplOiAiLCI7XG4gIGZvbnQtd2VpZ2h0OiAiLCI7XG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gIGxldHRlci1zcGFjaW5nOiAwLjUzcHg7XG5cbiAgY29sb3I6ICIsIjtcbiJdLFsiXG4gIG1hcmdpbi1yaWdodDogMTBweDtcblxuICBmb250LXNpemU6ICIsIjtcbiAgZm9udC13ZWlnaHQ6ICIsIjtcbiAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTtcbiAgbGV0dGVyLXNwYWNpbmc6IDAuNTNweDtcblxuICBjb2xvcjogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5mb250U21hbGx9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNpemVzLmZvbnRTZW1pQm9sZH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5kYXJrQmx1ZTUwfSksTD1wLnN0eWxlZC5kaXYoRHx8KEQ9aShbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGN1cnNvcjogcG9pbnRlcjtcbiJdLFsiXG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgY3Vyc29yOiBwb2ludGVyO1xuIl0pKSksUD1wLnN0eWxlZC5kaXYod3x8KHc9aShbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHJpZ2h0OiAwcHg7XG4iXSxbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHJpZ2h0OiAwcHg7XG4iXSkpKSxNPXAuc3R5bGVkLmRpdihTfHwoUz1pKFsiXG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgbWluLXdpZHRoOiAyNDVweDtcbiAgbWFyZ2luLXRvcDogIiwiO1xuXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcblxuICAmOmZpcnN0LWNoaWxkIHtcbiAgICBtYXJnaW4tdG9wOiAwO1xuICB9XG4iXSxbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG1pbi13aWR0aDogMjQ1cHg7XG4gIG1hcmdpbi10b3A6ICIsIjtcblxuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG5cbiAgJjpmaXJzdC1jaGlsZCB7XG4gICAgbWFyZ2luLXRvcDogMDtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5zbWFsbDE2fSksaj1wLnN0eWxlZC5kaXYoa3x8KGs9aShbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHJpZ2h0OiAwO1xuXG4gICY6aG92ZXIge1xuICAgIHN2ZyB7XG4gICAgICBmaWxsOiAiLCI7XG4gICAgfVxuICB9XG4iXSxbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHJpZ2h0OiAwO1xuXG4gICY6aG92ZXIge1xuICAgIHN2ZyB7XG4gICAgICBmaWxsOiAiLCI7XG4gICAgfVxuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMuZGFya0JsdWU2MH0pLFI9cC5zdHlsZWQuaW5wdXQoQXx8KEE9aShbIlxuICBkaXNwbGF5OiBibG9jaztcbiAgd2lkdGg6IDEwMCU7XG4gIHBhZGRpbmc6ICIsIiAiLCI7XG4gIHBhZGRpbmctcmlnaHQ6IDI1cHg7XG5cbiAgZm9udC13ZWlnaHQ6ICIsIjtcbiAgZm9udC1zaXplOiAiLCI7XG5cbiAgYm9yZGVyLXJhZGl1czogIiwiO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGNvbG9yOiAiLCI7XG4iXSxbIlxuICBkaXNwbGF5OiBibG9jaztcbiAgd2lkdGg6IDEwMCU7XG4gIHBhZGRpbmc6ICIsIiAiLCI7XG4gIHBhZGRpbmctcmlnaHQ6IDI1cHg7XG5cbiAgZm9udC13ZWlnaHQ6ICIsIjtcbiAgZm9udC1zaXplOiAiLCI7XG5cbiAgYm9yZGVyLXJhZGl1czogIiwiO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGNvbG9yOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNpemVzLnNtYWxsNn0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuc2l6ZXMuc21hbGwxMH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuc2l6ZXMuZm9udFNlbWlCb2xkfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5mb250VGlueX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuc2l6ZXMuc21hbGxSYWRpdXN9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMuZGFya0JsdWUxMH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5kYXJrQmx1ZX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPW4oMCksbz1uKDEpLGE9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5jaGVja2VkLG49ZS5vbkNoYW5nZSxyPWUuY2xhc3NOYW1lO3JldHVybiBpLmNyZWF0ZUVsZW1lbnQobCx7Y2xhc3NOYW1lOnIsb25DbGljazpufSxpLmNyZWF0ZUVsZW1lbnQocCx7dHlwZToiY2hlY2tib3giLGNoZWNrZWQ6dCxyZWFkT25seTohMH0pLGkuY3JlYXRlRWxlbWVudChmLHtjaGVja2VkOnR9KSl9O3QuZGVmYXVsdD1hO3ZhciBzLHUsYyxsPW8uc3R5bGVkLmRpdihzfHwocz1yKFsiXG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuXG4gIHdpZHRoOiAzOXB4O1xuICBoZWlnaHQ6IDIxcHg7XG4iXSxbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcblxuICB3aWR0aDogMzlweDtcbiAgaGVpZ2h0OiAyMXB4O1xuIl0pKSkscD1vLnN0eWxlZC5pbnB1dCh1fHwodT1yKFsiXG4gIGRpc3BsYXk6IG5vbmU7XG4iXSxbIlxuICBkaXNwbGF5OiBub25lO1xuIl0pKSksZj1vLnN0eWxlZCgiZGl2IikoY3x8KGM9cihbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMDtcbiAgbGVmdDogMDtcbiAgcmlnaHQ6IDA7XG4gIGJvdHRvbTogMDtcblxuICB0cmFuc2l0aW9uOiB0cmFuc2Zvcm0gNzBtcyBsaW5lYXI7XG4gIGJvcmRlci1yYWRpdXM6IDIzcHg7XG4gIGN1cnNvcjogcG9pbnRlcjtcblxuICBiYWNrZ3JvdW5kOiAiLCI7XG5cbiAgJjpiZWZvcmUge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICBjb250ZW50OiAnJztcbiAgICBoZWlnaHQ6IDIzcHg7XG4gICAgd2lkdGg6IDIzcHg7XG4gICAgbGVmdDogLTFweDtcbiAgICBib3R0b206IC0xcHg7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogd2hpdGU7XG4gICAgYm9yZGVyLXJhZGl1czogNTAlO1xuICAgIGJveC1zaGFkb3c6IDAgMXB4IDNweCByZ2JhKDAsIDAsIDAsIDAuMjUpO1xuICAgIHRyYW5zaXRpb246IHRyYW5zZm9ybSA3MG1zIGxpbmVhcjtcblxuICAgIHRyYW5zZm9ybTogIiwiO1xuICB9XG4iXSxbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMDtcbiAgbGVmdDogMDtcbiAgcmlnaHQ6IDA7XG4gIGJvdHRvbTogMDtcblxuICB0cmFuc2l0aW9uOiB0cmFuc2Zvcm0gNzBtcyBsaW5lYXI7XG4gIGJvcmRlci1yYWRpdXM6IDIzcHg7XG4gIGN1cnNvcjogcG9pbnRlcjtcblxuICBiYWNrZ3JvdW5kOiAiLCI7XG5cbiAgJjpiZWZvcmUge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICBjb250ZW50OiAnJztcbiAgICBoZWlnaHQ6IDIzcHg7XG4gICAgd2lkdGg6IDIzcHg7XG4gICAgbGVmdDogLTFweDtcbiAgICBib3R0b206IC0xcHg7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogd2hpdGU7XG4gICAgYm9yZGVyLXJhZGl1czogNTAlO1xuICAgIGJveC1zaGFkb3c6IDAgMXB4IDNweCByZ2JhKDAsIDAsIDAsIDAuMjUpO1xuICAgIHRyYW5zaXRpb246IHRyYW5zZm9ybSA3MG1zIGxpbmVhcjtcblxuICAgIHRyYW5zZm9ybTogIiwiO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmNoZWNrZWQ/ZS50aGVtZS5jb2xvdXJzLmdyZWVuOmUudGhlbWUuY29sb3Vycy5ibGFjazQwfSxmdW5jdGlvbihlKXtyZXR1cm4gZS5jaGVja2VkPyJ0cmFuc2xhdGVYKDE5cHgpIjoiIn0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9bigzMCkscz1uKDEpLHU9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3ZhciB0PW51bGwhPT1lJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpcztyZXR1cm4gdC5oYW5kbGVDbGlja091dHNpZGU9ZnVuY3Rpb24oZSl7aWYodC5wcm9wcy5vcGVuKXRyeXt2YXIgbj1hLmZpbmRET01Ob2RlKHQpO24mJm4uY29udGFpbnMoZS50YXJnZXQpfHwidW5kZWZpbmVkIj09PXR5cGVvZiB0LnByb3BzLm9uQ2xvc2V8fHQucHJvcHMub25DbG9zZShlKX1jYXRjaChlKXt9fSx0fXJldHVybiByKHQsZSksdC5wcm90b3R5cGUuY29tcG9uZW50RGlkTW91bnQ9ZnVuY3Rpb24oKXtkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJjbGljayIsdGhpcy5oYW5kbGVDbGlja091dHNpZGUsITApfSx0LnByb3RvdHlwZS5jb21wb25lbnRXaWxsVW5tb3VudD1mdW5jdGlvbigpe2RvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoImNsaWNrIix0aGlzLmhhbmRsZUNsaWNrT3V0c2lkZS5iaW5kKHRoaXMpLCEwKX0sdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcyx0PWUub3BlbixuPWUuY2hpbGRyZW4scj1lLnJlbmRlckFmdGVyQ29udGVudCxpPWUub25DbGljayxhPXRoaXMucHJvcHMuYW5jaG9yT3JpZ2luO3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoYix7dmlzaWJsZTp0LGFuY2hvclRvcDoidG9wIj09PWEudmVydGljYWwsYW5jaG9yQm90dG9tOiJib3R0b20iPT09YS52ZXJ0aWNhbCxhbmNob3JMZWZ0OiJsZWZ0Ij09PWEuaG9yaXpvbnRhbCxhbmNob3JSaWdodDoicmlnaHQiPT09YS5ob3Jpem9udGFsLGFuY2hvckNlbnRlcjoiY2VudGVyIj09PWEuaG9yaXpvbnRhbH0sby5jcmVhdGVFbGVtZW50KHgse29uQ2xpY2s6aX0sby5jcmVhdGVFbGVtZW50KEMsbnVsbCksbiksciYmcigpKX0sdC5kZWZhdWx0UHJvcHM9e2FuY2hvck9yaWdpbjp7dmVydGljYWw6InRvcCIsaG9yaXpvbnRhbDoiY2VudGVyIn19LHR9KG8uUHVyZUNvbXBvbmVudCk7dC5kZWZhdWx0PXU7dmFyIGMsbCxwLGYsZCxoLG0sZyx5LHYsYj1zLnN0eWxlZC5kaXYoZ3x8KGc9aShbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHotaW5kZXg6IDk5OTk7XG5cbiAgdGV4dC1hbGlnbjogbGVmdDtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGVYKC01MCUpO1xuXG4gIHRyYW5zaXRpb246IG9wYWNpdHkgZWFzZS1vdXQgMC4ycztcblxuICAiLCIgIiwiICIsIiAiLCIgIiwiICIsIjtcbiJdLFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgei1pbmRleDogOTk5OTtcblxuICB0ZXh0LWFsaWduOiBsZWZ0O1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTUwJSk7XG5cbiAgdHJhbnNpdGlvbjogb3BhY2l0eSBlYXNlLW91dCAwLjJzO1xuXG4gICIsIiAiLCIgIiwiICIsIiAiLCIgIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS52aXNpYmxlP3MuY3NzKGN8fChjPWkoWyJcbiAgICAgICAgICB2aXNpYmlsaXR5OiB2aXNpYmxlO1xuICAgICAgICAgIG9wYWNpdHk6IDE7XG4gICAgICAgICJdLFsiXG4gICAgICAgICAgdmlzaWJpbGl0eTogdmlzaWJsZTtcbiAgICAgICAgICBvcGFjaXR5OiAxO1xuICAgICAgICAiXSkpKTpzLmNzcyhsfHwobD1pKFsiXG4gICAgICAgICAgdmlzaWJpbGl0eTogaGlkZGVuO1xuICAgICAgICAgIG9wYWNpdHk6IDA7XG4gICAgICAgICJdLFsiXG4gICAgICAgICAgdmlzaWJpbGl0eTogaGlkZGVuO1xuICAgICAgICAgIG9wYWNpdHk6IDA7XG4gICAgICAgICJdKSkpfSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hbmNob3JUb3A/cy5jc3MocHx8KHA9aShbIlxuICAgICAgICBib3R0b206IDEwMCU7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDE2cHg7XG5cbiAgICAgICAgIiwiIHtcbiAgICAgICAgICBib3R0b206IC0xMHB4O1xuICAgICAgICB9XG4gICAgICAiXSxbIlxuICAgICAgICBib3R0b206IDEwMCU7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDE2cHg7XG5cbiAgICAgICAgIiwiIHtcbiAgICAgICAgICBib3R0b206IC0xMHB4O1xuICAgICAgICB9XG4gICAgICAiXSkpLEMpOiIifSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hbmNob3JCb3R0b20/cy5jc3MoZnx8KGY9aShbIlxuICAgICAgICB0b3A6IDEwMCU7XG4gICAgICAgIG1hcmdpbi10b3A6IDE2cHg7XG5cbiAgICAgICAgIiwiIHtcbiAgICAgICAgICB0b3A6IC0xMHB4O1xuICAgICAgICAgIGJvcmRlci13aWR0aDogMCAxMHB4IDEwcHggMTBweDtcbiAgICAgICAgICBib3JkZXItY29sb3I6ICIsIiB0cmFuc3BhcmVudFxuICAgICAgICAgICAgIiwiIHRyYW5zcGFyZW50O1xuICAgICAgICB9XG4gICAgICAiXSxbIlxuICAgICAgICB0b3A6IDEwMCU7XG4gICAgICAgIG1hcmdpbi10b3A6IDE2cHg7XG5cbiAgICAgICAgIiwiIHtcbiAgICAgICAgICB0b3A6IC0xMHB4O1xuICAgICAgICAgIGJvcmRlci13aWR0aDogMCAxMHB4IDEwcHggMTBweDtcbiAgICAgICAgICBib3JkZXItY29sb3I6ICIsIiB0cmFuc3BhcmVudFxuICAgICAgICAgICAgIiwiIHRyYW5zcGFyZW50O1xuICAgICAgICB9XG4gICAgICAiXSkpLEMsZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5wYWxlR3JleX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5wYWxlR3JleX0pOiIifSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hbmNob3JMZWZ0P3MuY3NzKGR8fChkPWkoWyJcbiAgICAgICAgbGVmdDogMDtcbiAgICAgICAgdHJhbnNmb3JtOiBub25lO1xuXG4gICAgICAgICIsIiB7XG4gICAgICAgICAgbGVmdDogMjVweDtcbiAgICAgICAgfVxuICAgICAgIl0sWyJcbiAgICAgICAgbGVmdDogMDtcbiAgICAgICAgdHJhbnNmb3JtOiBub25lO1xuXG4gICAgICAgICIsIiB7XG4gICAgICAgICAgbGVmdDogMjVweDtcbiAgICAgICAgfVxuICAgICAgIl0pKSxDKToiIn0sZnVuY3Rpb24oZSl7cmV0dXJuIGUuYW5jaG9yUmlnaHQ/cy5jc3MoaHx8KGg9aShbIlxuICAgICAgICByaWdodDogMDtcbiAgICAgICAgdHJhbnNmb3JtOiBub25lO1xuXG4gICAgICAgICIsIiB7XG4gICAgICAgICAgcmlnaHQ6IDI1cHg7XG4gICAgICAgIH1cbiAgICAgICJdLFsiXG4gICAgICAgIHJpZ2h0OiAwO1xuICAgICAgICB0cmFuc2Zvcm06IG5vbmU7XG5cbiAgICAgICAgIiwiIHtcbiAgICAgICAgICByaWdodDogMjVweDtcbiAgICAgICAgfVxuICAgICAgIl0pKSxDKToiIn0sZnVuY3Rpb24oZSl7cmV0dXJuIGUuYW5jaG9yQ2VudGVyP3MuY3NzKG18fChtPWkoWyJcbiAgICAgICAgbGVmdDogNTAlO1xuXG4gICAgICAgICIsIiB7XG4gICAgICAgICAgbGVmdDogY2FsYyg1MCUgLSAxMHB4KTtcbiAgICAgICAgfVxuICAgICAgIl0sWyJcbiAgICAgICAgbGVmdDogNTAlO1xuXG4gICAgICAgICIsIiB7XG4gICAgICAgICAgbGVmdDogY2FsYyg1MCUgLSAxMHB4KTtcbiAgICAgICAgfVxuICAgICAgIl0pKSxDKToiIn0pLHg9cy5zdHlsZWQuZGl2KHl8fCh5PWkoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcblxuICBwYWRkaW5nOiAiLCIgIiwiO1xuICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuXG4gIGJveC1zaGFkb3c6IDAgMXB4IDZweCAwIHJnYmEoMCwgMCwgMCwgMC4xNSk7XG4gIGJhY2tncm91bmQtY29sb3I6ICIsIjtcbiAgYm9yZGVyLXJhZGl1czogIiwiO1xuICBjb2xvcjogIiwiO1xuIl0sWyJcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcblxuICBwYWRkaW5nOiAiLCIgIiwiO1xuICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuXG4gIGJveC1zaGFkb3c6IDAgMXB4IDZweCAwIHJnYmEoMCwgMCwgMCwgMC4xNSk7XG4gIGJhY2tncm91bmQtY29sb3I6ICIsIjtcbiAgYm9yZGVyLXJhZGl1czogIiwiO1xuICBjb2xvcjogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5zbWFsbDEyfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5zbWFsbDE2fSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5jb2xvdXJzLnBhbGVHcmV5fSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5zbWFsbFJhZGl1c30sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5wYWxlVGV4dH0pLEM9cy5zdHlsZWQuZGl2KHZ8fCh2PWkoWyJcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB3aWR0aDogMDtcbiAgaGVpZ2h0OiAwO1xuXG4gIGJvcmRlci1zdHlsZTogc29saWQ7XG4gIGJvcmRlci13aWR0aDogMTBweCAxMHB4IDAgMTBweDtcbiAgYm9yZGVyLWNvbG9yOiAiLCIgdHJhbnNwYXJlbnQgdHJhbnNwYXJlbnRcbiAgICB0cmFuc3BhcmVudDtcbiJdLFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgd2lkdGg6IDA7XG4gIGhlaWdodDogMDtcblxuICBib3JkZXItc3R5bGU6IHNvbGlkO1xuICBib3JkZXItd2lkdGg6IDEwcHggMTBweCAwIDEwcHg7XG4gIGJvcmRlci1jb2xvcjogIiwiIHRyYW5zcGFyZW50IHRyYW5zcGFyZW50XG4gICAgdHJhbnNwYXJlbnQ7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMucGFsZUdyZXl9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPW4oMSkscz1uKDYxOCksdT1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe3ZhciBuPWUuY2FsbCh0aGlzLHQpfHx0aGlzO3JldHVybiBuLm9uQ29weT1mdW5jdGlvbigpe24uc2V0U3RhdGUoe2NvcGllZDohMH0pLG4uY29weVRpbWVyPXdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIG4uc2V0U3RhdGUoe2NvcGllZDohMX0pfSw1MDApfSxuLnN0YXRlPXtjb3BpZWQ6ITF9LG59cmV0dXJuIHIodCxlKSx0LnByb3RvdHlwZS5jb21wb25lbnRXaWxsVW5tb3VudD1mdW5jdGlvbigpe2NsZWFyVGltZW91dCh0aGlzLmNvcHlUaW1lcil9LHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMsdD1lLnRleHQsbj1lLmNvbG9yO3JldHVybiBvLmNyZWF0ZUVsZW1lbnQocyx7dGV4dDp0LG9uQ29weTp0aGlzLm9uQ29weX0sby5jcmVhdGVFbGVtZW50KHAsbnVsbCx0aGlzLnN0YXRlLmNvcGllZCYmby5jcmVhdGVFbGVtZW50KGYse2NvbG9yOm59LCJDb3BpZWQiKSx0aGlzLnByb3BzLmNoaWxkcmVuKSl9LHR9KG8uQ29tcG9uZW50KTt0LmRlZmF1bHQ9dTt2YXIgYyxsLHA9YS5zdHlsZWQuZGl2KGN8fChjPWkoWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuIl0sWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuIl0pKSksZj1hLnN0eWxlZC5kaXYobHx8KGw9aShbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogLTIwcHg7XG4gIGxlZnQ6IDUwJTtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgMCk7XG4gIGFuaW1hdGlvbjogY29weWluZyA3MDBtcyBsaW5lYXI7XG4gIGNvbG9yOiAiLCI7XG5cbiAgQGtleWZyYW1lcyBjb3B5aW5nIHtcbiAgICAwJSB7XG4gICAgICBvcGFjaXR5OiAwO1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgMCk7XG4gICAgfVxuXG4gICAgNTAlIHtcbiAgICAgIG9wYWNpdHk6IDE7XG4gICAgfVxuXG4gICAgMTAwJSB7XG4gICAgICBvcGFjaXR5OiAwO1xuICAgICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTUwcHgpO1xuICAgIH1cbiAgfVxuIl0sWyJcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB0b3A6IC0yMHB4O1xuICBsZWZ0OiA1MCU7XG4gIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIDApO1xuICBhbmltYXRpb246IGNvcHlpbmcgNzAwbXMgbGluZWFyO1xuICBjb2xvcjogIiwiO1xuXG4gIEBrZXlmcmFtZXMgY29weWluZyB7XG4gICAgMCUge1xuICAgICAgb3BhY2l0eTogMDtcbiAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIDApO1xuICAgIH1cblxuICAgIDUwJSB7XG4gICAgICBvcGFjaXR5OiAxO1xuICAgIH1cblxuICAgIDEwMCUge1xuICAgICAgb3BhY2l0eTogMDtcbiAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUsIC01MHB4KTtcbiAgICB9XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUuY29sb3I/ZS5jb2xvcjplLnRoZW1lLmNvbG91cnMuZGFya0JsdWUzMH0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNjE5KSxpPXIuQ29weVRvQ2xpcGJvYXJkO2kuQ29weVRvQ2xpcGJvYXJkPWksZS5leHBvcnRzPWl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmZS5fX2VzTW9kdWxlP2U6e2RlZmF1bHQ6ZX19ZnVuY3Rpb24gaShlLHQpe3ZhciBuPXt9O2Zvcih2YXIgciBpbiBlKXQuaW5kZXhPZihyKT49MHx8T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUscikmJihuW3JdPWVbcl0pO3JldHVybiBufWZ1bmN0aW9uIG8oZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBhKGUsdCl7aWYoIWUpdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKCJ0aGlzIGhhc24ndCBiZWVuIGluaXRpYWxpc2VkIC0gc3VwZXIoKSBoYXNuJ3QgYmVlbiBjYWxsZWQiKTtyZXR1cm4hdHx8Im9iamVjdCIhPT10eXBlb2YgdCYmImZ1bmN0aW9uIiE9PXR5cGVvZiB0P2U6dH1mdW5jdGlvbiBzKGUsdCl7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJTdXBlciBleHByZXNzaW9uIG11c3QgZWl0aGVyIGJlIG51bGwgb3IgYSBmdW5jdGlvbiwgbm90ICIrdHlwZW9mIHQpO2UucHJvdG90eXBlPU9iamVjdC5jcmVhdGUodCYmdC5wcm90b3R5cGUse2NvbnN0cnVjdG9yOnt2YWx1ZTplLGVudW1lcmFibGU6ITEsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfX0pLHQmJihPYmplY3Quc2V0UHJvdG90eXBlT2Y/T2JqZWN0LnNldFByb3RvdHlwZU9mKGUsdCk6ZS5fX3Byb3RvX189dCl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuQ29weVRvQ2xpcGJvYXJkPXZvaWQgMDt2YXIgdT1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfSxjPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe2Zvcih2YXIgbj0wO248dC5sZW5ndGg7bisrKXt2YXIgcj10W25dO3IuZW51bWVyYWJsZT1yLmVudW1lcmFibGV8fCExLHIuY29uZmlndXJhYmxlPSEwLCJ2YWx1ZSJpbiByJiYoci53cml0YWJsZT0hMCksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsci5rZXkscil9fXJldHVybiBmdW5jdGlvbih0LG4scil7cmV0dXJuIG4mJmUodC5wcm90b3R5cGUsbiksciYmZSh0LHIpLHR9fSgpLGw9bigwKSxwPXIobCksZj1uKDI4NCksZD1yKGYpOyh0LkNvcHlUb0NsaXBib2FyZD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7dmFyIGUsbixyLGk7byh0aGlzLHQpO2Zvcih2YXIgcz1hcmd1bWVudHMubGVuZ3RoLHU9QXJyYXkocyksYz0wO2M8cztjKyspdVtjXT1hcmd1bWVudHNbY107cmV0dXJuIG49cj1hKHRoaXMsKGU9dC5fX3Byb3RvX198fE9iamVjdC5nZXRQcm90b3R5cGVPZih0KSkuY2FsbC5hcHBseShlLFt0aGlzXS5jb25jYXQodSkpKSxyLm9uQ2xpY2s9ZnVuY3Rpb24oZSl7dmFyIHQ9ci5wcm9wcyxuPXQudGV4dCxpPXQub25Db3B5LG89dC5jaGlsZHJlbixhPXQub3B0aW9ucyxzPXAuZGVmYXVsdC5DaGlsZHJlbi5vbmx5KG8pLHU9KDAsZC5kZWZhdWx0KShuLGEpO2kmJmkobix1KSxzJiZzLnByb3BzJiYiZnVuY3Rpb24iPT09dHlwZW9mIHMucHJvcHMub25DbGljayYmcy5wcm9wcy5vbkNsaWNrKGUpfSxpPW4sYShyLGkpfXJldHVybiBzKHQsZSksYyh0LFt7a2V5OiJyZW5kZXIiLHZhbHVlOmZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcyx0PShlLnRleHQsZS5vbkNvcHksZS5vcHRpb25zLGUuY2hpbGRyZW4pLG49aShlLFsidGV4dCIsIm9uQ29weSIsIm9wdGlvbnMiLCJjaGlsZHJlbiJdKSxyPXAuZGVmYXVsdC5DaGlsZHJlbi5vbmx5KHQpO3JldHVybiBwLmRlZmF1bHQuY2xvbmVFbGVtZW50KHIsdSh7fSxuLHtvbkNsaWNrOnRoaXMub25DbGlja30pKX19XSksdH0ocC5kZWZhdWx0LlB1cmVDb21wb25lbnQpKS5kZWZhdWx0UHJvcHM9e29uQ29weTp2b2lkIDAsb3B0aW9uczp2b2lkIDB9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDApLGk9big2MjEpLG89big2MjMpLGE9big4KSxzPW4oMTIpLHU9big5KSxjPWZ1bmN0aW9uKGUpe3JldHVybiBlLmlzUG9sbGluZ1NjaGVtYT9yLmNyZWF0ZUVsZW1lbnQoby5kZWZhdWx0LHtpbnRlcnZhbDplLnNldHRpbmdzWyJzY2hlbWEucG9sbGluZy5pbnRlcnZhbCJdLG9uUmVsb2FkU2NoZW1hOmUub25SZWxvYWRTY2hlbWF9KTpyLmNyZWF0ZUVsZW1lbnQoaS5kZWZhdWx0LHtpc1JlbG9hZGluZ1NjaGVtYTplLmlzUmVsb2FkaW5nU2NoZW1hLG9uUmVsb2FkU2NoZW1hOmUub25SZWxvYWRTY2hlbWF9KX0sbD1hLmNyZWF0ZVN0cnVjdHVyZWRTZWxlY3Rvcih7aXNSZWxvYWRpbmdTY2hlbWE6cy5nZXRJc1JlbG9hZGluZ1NjaGVtYX0pO3QuZGVmYXVsdD11LmNvbm5lY3QobCkoYyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oMCksaT1uKDYyMiksbz1mdW5jdGlvbihlKXtyZXR1cm4gci5jcmVhdGVFbGVtZW50KGkuZGVmYXVsdCx7YW5pbWF0ZTplLmlzUmVsb2FkaW5nU2NoZW1hLG9uQ2xpY2s6ZS5vblJlbG9hZFNjaGVtYX0pfTt0LmRlZmF1bHQ9b30sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDApLG89bigxKSxhPW4oMjg1KSxzPWZ1bmN0aW9uKGUpe3JldHVybiBpLmNyZWF0ZUVsZW1lbnQodix7b25DbGljazplLm9uQ2xpY2ssdGl0bGU6IlJlbG9hZCBTY2hlbWEiLGRpc2FibGVkOmUuZGlzYWJsZWR9LGkuY3JlYXRlRWxlbWVudCh5LHt2aWV3Qm94OiIwIDAgMjAgMjAiLGRpc2FibGVkOmUuZGlzYWJsZWR9LGkuY3JlYXRlRWxlbWVudChiLHtjeDoiOS41IixjeToiMTAiLHI6IjYiLHN0cm9rZVdpZHRoOiIxLjUiLGZpbGw6Im5vbmUiLHN0cm9rZUxpbmVjYXA6InJvdW5kIixhbmltYXRlOmUuYW5pbWF0ZX0pLGkuY3JlYXRlRWxlbWVudCh4LHtkOiJNNC44MyA0Ljg2YTYuOTIgNi45MiAwIDAgMSAxMS4zIDIuOTdsLjQxLTEuMjNjLjEzLS40LjU2LS42Ljk1LS40Ny40LjEzLjYuNTYuNDcuOTVsLTEuMTMgMy4zM2EuNzYuNzYgMCAwIDEtLjcuNS43Mi43MiAwIDAgMS0uNDMtLjEybC0yLjg4LTEuOTJhLjc2Ljc2IDAgMCAxLS4yLTEuMDQuNzUuNzUgMCAwIDEgMS4wMy0uMmwxLjA2LjdBNS4zNCA1LjM0IDAgMCAwIDkuNzUgNC41YTUuNDQgNS40NCAwIDAgMC01LjY0IDUuMjIgNS40MiA1LjQyIDAgMCAwIDUuMjQgNS42MmMuNDEgMCAuNzQuMzYuNzIuNzhhLjc1Ljc1IDAgMCAxLS43NS43Mkg5LjNhNi45IDYuOSAwIDAgMS02LjY4LTcuMTggNi44OCA2Ljg4IDAgMCAxIDIuMjItNC44MXoiLGFuaW1hdGU6ZS5hbmltYXRlfSkpKX07dC5kZWZhdWx0PXM7dmFyIHUsYyxsLHAsZixkLGgsbT1vLmtleWZyYW1lcyh1fHwodT1yKFsiXG4wJSB7XG4gIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpO1xuICBzdHJva2UtZGFzaG9mZnNldDogNy45Mjtcbn1cblxuNTAlIHtcbiAgdHJhbnNmb3JtOiByb3RhdGUoNzIwZGVnKTtcbiAgc3Ryb2tlLWRhc2hvZmZzZXQ6IDM3LjY4O1xufVxuXG4xMDAlIHtcbiAgdHJhbnNmb3JtOiByb3RhdGUoMTA4MGRlZyk7XG4gIHN0cm9rZS1kYXNob2Zmc2V0OiA3LjkyO1xufVxuIl0sWyJcbjAlIHtcbiAgdHJhbnNmb3JtOiByb3RhdGUoMGRlZyk7XG4gIHN0cm9rZS1kYXNob2Zmc2V0OiA3LjkyO1xufVxuXG41MCUge1xuICB0cmFuc2Zvcm06IHJvdGF0ZSg3MjBkZWcpO1xuICBzdHJva2UtZGFzaG9mZnNldDogMzcuNjg7XG59XG5cbjEwMCUge1xuICB0cmFuc2Zvcm06IHJvdGF0ZSgxMDgwZGVnKTtcbiAgc3Ryb2tlLWRhc2hvZmZzZXQ6IDcuOTI7XG59XG4iXSkpKSxnPWZ1bmN0aW9uKGUpe3JldHVybiBvLmtleWZyYW1lcyhjfHwoYz1yKFsiXG4wJSB7XG4gIHRyYW5zZm9ybTogcm90YXRlKCIsImRlZyk7XG59XG5cbjEwMCUge1xuICB0cmFuc2Zvcm06IHJvdGF0ZSgiLCJkZWcpO1xufSJdLFsiXG4wJSB7XG4gIHRyYW5zZm9ybTogcm90YXRlKCIsImRlZyk7XG59XG5cbjEwMCUge1xuICB0cmFuc2Zvcm06IHJvdGF0ZSgiLCJkZWcpO1xufSJdKSksZS5hbmltYXRlPzA6MzYwLGUuYW5pbWF0ZT8zNjA6NzIwKX0seT1vLnN0eWxlZC5zdmcocHx8KHA9cihbIlxuICBmaWxsOiAiLCI7XG4gIHRyYW5zaXRpb246IDAuMXMgbGluZWFyIGFsbDtcbiAgIiwiO1xuIl0sWyJcbiAgZmlsbDogIiwiO1xuICB0cmFuc2l0aW9uOiAwLjFzIGxpbmVhciBhbGw7XG4gICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5pY29ufSxmdW5jdGlvbihlKXtyZXR1cm4gZS5kaXNhYmxlZD92b2lkIDA6by5jc3MobHx8KGw9cihbIlxuICAgICAgICAgICY6aG92ZXIge1xuICAgICAgICAgICAgZmlsbDogIiwiO1xuICAgICAgICAgIH1cbiAgICAgICAgIl0sWyJcbiAgICAgICAgICAmOmhvdmVyIHtcbiAgICAgICAgICAgIGZpbGw6ICIsIjtcbiAgICAgICAgICB9XG4gICAgICAgICJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5pY29uSG92ZXJ9KX0pLHY9by5zdHlsZWQoYS5kZWZhdWx0KShmfHwoZj1yKFsiXG4gIGN1cnNvcjogIiwiO1xuICB0cmFuc2Zvcm06IHJvdGF0ZVkoMTgwZGVnKTtcbiJdLFsiXG4gIGN1cnNvcjogIiwiO1xuICB0cmFuc2Zvcm06IHJvdGF0ZVkoMTgwZGVnKTtcbiJdKSksZnVuY3Rpb24oZSl7dmFyIHQ9ZS5kaXNhYmxlZDtyZXR1cm4gdm9pZCAwIT09dCYmdD8iYXV0byI6InBvaW50ZXIifSksYj1vLnN0eWxlZCgiY2lyY2xlIikoZHx8KGQ9cihbIlxuICBmaWxsOiBub25lO1xuICBzdHJva2U6ICIsIjtcbiAgc3Ryb2tlLWRhc2hhcnJheTogMzcuNjg7XG4gIHRyYW5zaXRpb246IG9wYWNpdHkgMC4zcyBlYXNlLWluLW91dDtcbiAgb3BhY2l0eTogIiwiO1xuICB0cmFuc2Zvcm0tb3JpZ2luOiA5LjVweCAxMHB4O1xuICBhbmltYXRpb246ICIsIiAycyBsaW5lYXIgIiwiO1xuIl0sWyJcbiAgZmlsbDogbm9uZTtcbiAgc3Ryb2tlOiAiLCI7XG4gIHN0cm9rZS1kYXNoYXJyYXk6IDM3LjY4O1xuICB0cmFuc2l0aW9uOiBvcGFjaXR5IDAuM3MgZWFzZS1pbi1vdXQ7XG4gIG9wYWNpdHk6ICIsIjtcbiAgdHJhbnNmb3JtLW9yaWdpbjogOS41cHggMTBweDtcbiAgYW5pbWF0aW9uOiAiLCIgMnMgbGluZWFyICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5pY29ufSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hbmltYXRlPzE6MH0sbSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hbmltYXRlPyJpbmZpbml0ZSI6IiJ9KSx4PW8uc3R5bGVkKCJwYXRoIikoaHx8KGg9cihbIlxuICB0cmFuc2l0aW9uOiBvcGFjaXR5IDAuM3MgZWFzZS1pbi1vdXQ7XG4gIG9wYWNpdHk6ICIsIjtcbiAgdHJhbnNmb3JtLW9yaWdpbjogOS41cHggMTBweDtcbiAgYW5pbWF0aW9uOiAiLCIgMC41cyBsaW5lYXI7XG4iXSxbIlxuICB0cmFuc2l0aW9uOiBvcGFjaXR5IDAuM3MgZWFzZS1pbi1vdXQ7XG4gIG9wYWNpdHk6ICIsIjtcbiAgdHJhbnNmb3JtLW9yaWdpbjogOS41cHggMTBweDtcbiAgYW5pbWF0aW9uOiAiLCIgMC41cyBsaW5lYXI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmFuaW1hdGU/MDoxfSxnKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDApLG89big2MjQpLGE9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0KXt2YXIgbj1lLmNhbGwodGhpcyx0KXx8dGhpcztyZXR1cm4gbi5zZXRXaW5kb3dWaXNpYmlsaXR5PWZ1bmN0aW9uKCl7InZpc2libGUiPT09ZG9jdW1lbnQudmlzaWJpbGl0eVN0YXRlJiZuLnNldFN0YXRlKHt3aW5kb3dWaXNpYmxlOiEwfSxuLnVwZGF0ZVBvbGxpbmcpLCJoaWRkZW4iPT09ZG9jdW1lbnQudmlzaWJpbGl0eVN0YXRlJiZuLnNldFN0YXRlKHt3aW5kb3dWaXNpYmxlOiExfSxuLnVwZGF0ZVBvbGxpbmcpfSxuLnVwZGF0ZVBvbGxpbmc9ZnVuY3Rpb24oZSl7dm9pZCAwPT09ZSYmKGU9bi5wcm9wcyksbi5jbGVhclRpbWVyKCksbi5zdGF0ZS53aW5kb3dWaXNpYmxlJiYobi50aW1lcj1zZXRJbnRlcnZhbChmdW5jdGlvbigpe3JldHVybiBlLm9uUmVsb2FkU2NoZW1hKCl9LGUuaW50ZXJ2YWwpKX0sbi5zdGF0ZT17d2luZG93VmlzaWJsZTohMH0sbn1yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLmNvbXBvbmVudERpZE1vdW50PWZ1bmN0aW9uKCl7dGhpcy51cGRhdGVQb2xsaW5nKCksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigidmlzaWJpbGl0eWNoYW5nZSIsdGhpcy5zZXRXaW5kb3dWaXNpYmlsaXR5KX0sdC5wcm90b3R5cGUuY29tcG9uZW50V2lsbFVubW91bnQ9ZnVuY3Rpb24oKXt0aGlzLmNsZWFyVGltZXIoKSxkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJ2aXNpYmlsaXR5Y2hhbmdlIix0aGlzLnNldFdpbmRvd1Zpc2liaWxpdHkpfSx0LnByb3RvdHlwZS5jb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzPWZ1bmN0aW9uKGUpe3RoaXMudXBkYXRlUG9sbGluZyhlKX0sdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7cmV0dXJuIGkuY3JlYXRlRWxlbWVudChvLmRlZmF1bHQse2FuaW1hdGU6dGhpcy5zdGF0ZS53aW5kb3dWaXNpYmxlfSl9LHQucHJvdG90eXBlLmNsZWFyVGltZXI9ZnVuY3Rpb24oKXt0aGlzLnRpbWVyJiYoY2xlYXJJbnRlcnZhbCh0aGlzLnRpbWVyKSx0aGlzLnRpbWVyPW51bGwpfSx0fShpLkNvbXBvbmVudCk7dC5kZWZhdWx0PWF9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigwKSxvPW4oMSksYT1uKDI4NSkscz1mdW5jdGlvbihlKXtyZXR1cm4gaS5jcmVhdGVFbGVtZW50KGQse29uQ2xpY2s6ZS5vbkNsaWNrLHRpdGxlOiJQb2xsaW5nIFNjaGVtYSJ9LGkuY3JlYXRlRWxlbWVudChoLHthbmltYXRlOmUuYW5pbWF0ZX0pKX07dC5kZWZhdWx0PXM7dmFyIHUsYyxsLHAsZj1vLmtleWZyYW1lcyh1fHwodT1yKFsiXG4wJSB7XG4gIGJveC1zaGFkb3c6IDAgMCAwIDAgcmdiYSgxMzksIDE0OSwgMTU2LCAwLjQpO1xufVxuNzAlIHtcbiAgYm94LXNoYWRvdzogMCAwIDAgMTBweCByZ2JhKDEzOSwgMTQ5LCAxNTYsIDApO1xufVxuMTAwJSB7XG4gIGJveC1zaGFkb3c6IDAgMCAwIDAgcmdiYSgxMzksIDE0OSwgMTU2LCAwKTtcbn1cbiJdLFsiXG4wJSB7XG4gIGJveC1zaGFkb3c6IDAgMCAwIDAgcmdiYSgxMzksIDE0OSwgMTU2LCAwLjQpO1xufVxuNzAlIHtcbiAgYm94LXNoYWRvdzogMCAwIDAgMTBweCByZ2JhKDEzOSwgMTQ5LCAxNTYsIDApO1xufVxuMTAwJSB7XG4gIGJveC1zaGFkb3c6IDAgMCAwIDAgcmdiYSgxMzksIDE0OSwgMTU2LCAwKTtcbn1cbiJdKSkpLGQ9by5zdHlsZWQoYS5kZWZhdWx0KShjfHwoYz1yKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuIl0sWyJcbiAgZGlzcGxheTogZmxleDtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4iXSkpKSxoPW8uc3R5bGVkLmRpdihwfHwocD1yKFsiXG4gIGRpc3BsYXk6IGJsb2NrO1xuICB3aWR0aDogOHB4O1xuICBoZWlnaHQ6IDhweDtcbiAgYm9yZGVyLXJhZGl1czogNTAlO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGJveC1zaGFkb3c6IDAgMCAwICIsIjtcbiAgIiwiO1xuIl0sWyJcbiAgZGlzcGxheTogYmxvY2s7XG4gIHdpZHRoOiA4cHg7XG4gIGhlaWdodDogOHB4O1xuICBib3JkZXItcmFkaXVzOiA1MCU7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgYm94LXNoYWRvdzogMCAwIDAgIiwiO1xuICAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMucG9sbGluZ0ljb259LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMucG9sbGluZ0ljb25TaGFkb3d9LGZ1bmN0aW9uKGUpe3JldHVybiBlLmFuaW1hdGU/by5jc3MobHx8KGw9cihbIlxuICAgICAgICAgIGFuaW1hdGlvbjogIiwiIDJzIGluZmluaXRlO1xuICAgICAgICAiXSxbIlxuICAgICAgICAgIGFuaW1hdGlvbjogIiwiIDJzIGluZmluaXRlO1xuICAgICAgICAiXSkpLGYpOnZvaWQgMH0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9bigyNzIpLHM9big5KSx1PW4oMTYpLGM9bigxMiksbD1uKDgpLHA9bigxKSxmPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIG49ZS5jYWxsKHRoaXMsdCl8fHRoaXM7cmV0dXJuIG4uX29uS2V5VXA9ZnVuY3Rpb24oZSx0KXt2YXIgcj10LmtleUNvZGU7KHI+PTY1JiZyPD05MHx8IXQuc2hpZnRLZXkmJnI+PTQ4JiZyPD01N3x8dC5zaGlmdEtleSYmMTg5PT09cnx8dC5zaGlmdEtleSYmMjIyPT09cikmJm4uZWRpdG9yLmV4ZWNDb21tYW5kKCJhdXRvY29tcGxldGUiKX0sbi5fb25FZGl0PWZ1bmN0aW9uKCl7bi5pZ25vcmVDaGFuZ2VFdmVudHx8KG4uY2FjaGVkVmFsdWU9bi5lZGl0b3IuZ2V0VmFsdWUoKSxuLnByb3BzLm9uQ2hhbmdlKG4uY2FjaGVkVmFsdWUpKX0sbi5fb25IYXNDb21wbGV0aW9uPWZ1bmN0aW9uKGUsdCl7YS5kZWZhdWx0KGUsdCxuLnByb3BzLm9uSGludEluZm9ybWF0aW9uUmVuZGVyKX0sbi5jYWNoZWRWYWx1ZT10LnZhbHVlfHwiIixuLnByb3BzLmdldFJlZiYmbi5wcm9wcy5nZXRSZWYobiksbn1yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLmNvbXBvbmVudERpZE1vdW50PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcyx0PW4oMik7bigxMzcpLG4oNjkpLG4oMTM4KSxuKDcwKSxuKDg5KSxuKDEzOSksbigzOCksbig5MCksbigzOSksbig5MSksbigyODYpLG4oMjg3KSxuKDI4OCksdGhpcy5lZGl0b3I9dCh0aGlzLl9ub2RlLHt2YWx1ZTp0aGlzLnByb3BzLnZhbHVlfHwiIixsaW5lTnVtYmVyczohMCx0YWJTaXplOjIsbW9kZToiZ3JhcGhxbC12YXJpYWJsZXMiLHRoZW1lOiJncmFwaGlxbCIsa2V5TWFwOiJzdWJsaW1lIixhdXRvQ2xvc2VCcmFja2V0czohMCxtYXRjaEJyYWNrZXRzOiEwLHNob3dDdXJzb3JXaGVuU2VsZWN0aW5nOiEwLHJlYWRPbmx5OiExLGZvbGRHdXR0ZXI6e21pbkZvbGRTaXplOjR9LGxpbnQ6e3ZhcmlhYmxlVG9UeXBlOnRoaXMucHJvcHMudmFyaWFibGVUb1R5cGU/dGhpcy5wcm9wcy52YXJpYWJsZVRvVHlwZS50b0pTKCk6dm9pZCAwfSxoaW50T3B0aW9uczp7dmFyaWFibGVUb1R5cGU6dGhpcy5wcm9wcy52YXJpYWJsZVRvVHlwZT90aGlzLnByb3BzLnZhcmlhYmxlVG9UeXBlLnRvSlMoKTp2b2lkIDAsY2xvc2VPblVuZm9jdXM6ITEsY29tcGxldGVTaW5nbGU6ITF9LGd1dHRlcnM6WyJDb2RlTWlycm9yLWxpbmVudW1iZXJzIiwiQ29kZU1pcnJvci1mb2xkZ3V0dGVyIl0sZXh0cmFLZXlzOnsiQ21kLVNwYWNlIjpmdW5jdGlvbigpe3JldHVybiBlLmVkaXRvci5zaG93SGludCh7Y29tcGxldGVTaW5nbGU6ITF9KX0sIkN0cmwtU3BhY2UiOmZ1bmN0aW9uKCl7cmV0dXJuIGUuZWRpdG9yLnNob3dIaW50KHtjb21wbGV0ZVNpbmdsZTohMX0pfSwiQWx0LVNwYWNlIjpmdW5jdGlvbigpe3JldHVybiBlLmVkaXRvci5zaG93SGludCh7Y29tcGxldGVTaW5nbGU6ITF9KX0sIlNoaWZ0LVNwYWNlIjpmdW5jdGlvbigpe3JldHVybiBlLmVkaXRvci5zaG93SGludCh7Y29tcGxldGVTaW5nbGU6ITF9KX0sIkNtZC1FbnRlciI6ZnVuY3Rpb24oKXtlLnByb3BzLm9uUnVuUXVlcnkmJmUucHJvcHMub25SdW5RdWVyeSgpfSwiQ3RybC1FbnRlciI6ZnVuY3Rpb24oKXtlLnByb3BzLm9uUnVuUXVlcnkmJmUucHJvcHMub25SdW5RdWVyeSgpfSwiU2hpZnQtQ3RybC1QIjpmdW5jdGlvbigpe2UucHJvcHMucHJldHRpZnlRdWVyeSYmZS5wcm9wcy5wcmV0dGlmeVF1ZXJ5KCl9LCJDbWQtRiI6ImZpbmRQZXJzaXN0ZW50IiwiQ3RybC1GIjoiZmluZFBlcnNpc3RlbnQiLCJDdHJsLUxlZnQiOiJnb1N1YndvcmRMZWZ0IiwiQ3RybC1SaWdodCI6ImdvU3Vid29yZFJpZ2h0IiwiQWx0LUxlZnQiOiJnb0dyb3VwTGVmdCIsIkFsdC1SaWdodCI6ImdvR3JvdXBSaWdodCJ9fSksdGhpcy5lZGl0b3Iub24oImNoYW5nZSIsdGhpcy5fb25FZGl0KSx0aGlzLmVkaXRvci5vbigia2V5dXAiLHRoaXMuX29uS2V5VXApLHRoaXMuZWRpdG9yLm9uKCJoYXNDb21wbGV0aW9uIix0aGlzLl9vbkhhc0NvbXBsZXRpb24pfSx0LnByb3RvdHlwZS5jb21wb25lbnREaWRVcGRhdGU9ZnVuY3Rpb24oZSl7dmFyIHQ9bigyKTt0aGlzLmlnbm9yZUNoYW5nZUV2ZW50PSEwLHRoaXMucHJvcHMudmFyaWFibGVUb1R5cGUhPT1lLnZhcmlhYmxlVG9UeXBlJiYodGhpcy5lZGl0b3Iub3B0aW9ucy5saW50LnZhcmlhYmxlVG9UeXBlPXRoaXMucHJvcHMudmFyaWFibGVUb1R5cGU/dGhpcy5wcm9wcy52YXJpYWJsZVRvVHlwZS50b0pTKCk6dm9pZCAwLHRoaXMuZWRpdG9yLm9wdGlvbnMuaGludE9wdGlvbnMudmFyaWFibGVUb1R5cGU9dGhpcy5wcm9wcy52YXJpYWJsZVRvVHlwZT90aGlzLnByb3BzLnZhcmlhYmxlVG9UeXBlLnRvSlMoKTp2b2lkIDAsdC5zaWduYWwodGhpcy5lZGl0b3IsImNoYW5nZSIsdGhpcy5lZGl0b3IpKSx0aGlzLnByb3BzLnZhbHVlIT09ZS52YWx1ZSYmdGhpcy5wcm9wcy52YWx1ZSE9PXRoaXMuY2FjaGVkVmFsdWUmJih0aGlzLmNhY2hlZFZhbHVlPXRoaXMucHJvcHMudmFsdWUsdGhpcy5lZGl0b3Iuc2V0VmFsdWUodGhpcy5wcm9wcy52YWx1ZSkpLHRoaXMuaWdub3JlQ2hhbmdlRXZlbnQ9ITF9LHQucHJvdG90eXBlLmNvbXBvbmVudFdpbGxVbm1vdW50PWZ1bmN0aW9uKCl7dGhpcy5lZGl0b3Iub2ZmKCJjaGFuZ2UiLHRoaXMuX29uRWRpdCksdGhpcy5lZGl0b3Iub2ZmKCJrZXl1cCIsdGhpcy5fb25LZXlVcCksdGhpcy5lZGl0b3Iub2ZmKCJoYXNDb21wbGV0aW9uIix0aGlzLl9vbkhhc0NvbXBsZXRpb24pLHRoaXMuZWRpdG9yPW51bGx9LHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXM7cmV0dXJuIG8uY3JlYXRlRWxlbWVudChnLHtyZWY6ZnVuY3Rpb24odCl7ZS5fbm9kZT10fX0pfSx0LnByb3RvdHlwZS5nZXRDb2RlTWlycm9yPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZWRpdG9yfSx0LnByb3RvdHlwZS5nZXRDbGllbnRIZWlnaHQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fbm9kZSYmdGhpcy5fbm9kZS5jbGllbnRIZWlnaHR9LHR9KG8uUHVyZUNvbXBvbmVudCksZD1sLmNyZWF0ZVN0cnVjdHVyZWRTZWxlY3Rvcih7dmFsdWU6Yy5nZXRWYXJpYWJsZXMsdmFyaWFibGVUb1R5cGU6Yy5nZXRWYXJpYWJsZVRvVHlwZX0pO3QuVmFyaWFibGVFZGl0b3JDb21wb25lbnQ9cy5jb25uZWN0KGQse29uQ2hhbmdlOnUuZWRpdFZhcmlhYmxlc30pKGYpO3ZhciBoPWwuY3JlYXRlU3RydWN0dXJlZFNlbGVjdG9yKHt2YWx1ZTpjLmdldEhlYWRlcnN9KTt0LkhlYWRlcnNFZGl0b3JDb21wb25lbnQ9cy5jb25uZWN0KGgse29uQ2hhbmdlOnUuZWRpdEhlYWRlcnN9KShmKTt2YXIgbSxnPXAuc3R5bGVkLmRpdihtfHwobT1pKFsiXG4gIGZsZXg6IDE7XG4gIGhlaWdodDogMTAwJTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuIl0sWyJcbiAgZmxleDogMTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4iXSkpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuKXt2YXIgcj1pKG4sYSh0LnN0cmluZykpO2lmKHIpe3ZhciBvPW51bGwhPT10LnR5cGUmJi8ifFx3Ly50ZXN0KHQuc3RyaW5nWzBdKT90LnN0YXJ0OnQuZW5kO3JldHVybntsaXN0OnIsZnJvbTp7bGluZTplLmxpbmUsY29sdW1uOm99LHRvOntsaW5lOmUubGluZSxjb2x1bW46dC5lbmR9fX19ZnVuY3Rpb24gaShlLHQpe3JldHVybiB0P28obyhlLm1hcChmdW5jdGlvbihlKXtyZXR1cm57cHJveGltaXR5OnMoYShlLnRleHQpLHQpLGVudHJ5OmV9fSksZnVuY3Rpb24oZSl7cmV0dXJuIGUucHJveGltaXR5PD0yfSksZnVuY3Rpb24oZSl7cmV0dXJuIWUuZW50cnkuaXNEZXByZWNhdGVkfSkuc29ydChmdW5jdGlvbihlLHQpe3JldHVybihlLmVudHJ5LmlzRGVwcmVjYXRlZD8xOjApLSh0LmVudHJ5LmlzRGVwcmVjYXRlZD8xOjApfHxlLnByb3hpbWl0eS10LnByb3hpbWl0eXx8ZS5lbnRyeS50ZXh0Lmxlbmd0aC10LmVudHJ5LnRleHQubGVuZ3RofSkubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLmVudHJ5fSk6byhlLGZ1bmN0aW9uKGUpe3JldHVybiFlLmlzRGVwcmVjYXRlZH0pfWZ1bmN0aW9uIG8oZSx0KXt2YXIgbj1lLmZpbHRlcih0KTtyZXR1cm4gMD09PW4ubGVuZ3RoP2U6bn1mdW5jdGlvbiBhKGUpe3JldHVybiBlLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvXFcvZywiIil9ZnVuY3Rpb24gcyhlLHQpe3ZhciBuPXUodCxlKTtyZXR1cm4gZS5sZW5ndGg+dC5sZW5ndGgmJihuLT1lLmxlbmd0aC10Lmxlbmd0aC0xLG4rPTA9PT1lLmluZGV4T2YodCk/MDouNSksbn1mdW5jdGlvbiB1KGUsdCl7dmFyIG49dm9pZCAwLHI9dm9pZCAwLGk9W10sbz1lLmxlbmd0aCxhPXQubGVuZ3RoO2ZvcihuPTA7bjw9bztuKyspaVtuXT1bbl07Zm9yKHI9MTtyPD1hO3IrKylpWzBdW3JdPXI7Zm9yKG49MTtuPD1vO24rKylmb3Iocj0xO3I8PWE7cisrKXt2YXIgcz1lW24tMV09PT10W3ItMV0/MDoxO2lbbl1bcl09TWF0aC5taW4oaVtuLTFdW3JdKzEsaVtuXVtyLTFdKzEsaVtuLTFdW3ItMV0rcyksbj4xJiZyPjEmJmVbbi0xXT09PXRbci0yXSYmZVtuLTJdPT09dFtyLTFdJiYoaVtuXVtyXT1NYXRoLm1pbihpW25dW3JdLGlbbi0yXVtyLTJdK3MpKX1yZXR1cm4gaVtvXVthXX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2PWUsYj1lLmxlbmd0aCx4PUM9RT0tMSxmKCksZCgpO3ZhciB0PWkoKTtyZXR1cm4gYygiRU9GIiksdH1mdW5jdGlvbiBpKCl7dmFyIGU9eCx0PVtdO2lmKGMoInsiKSwhcCgifSIpKXtkb3t0LnB1c2gobygpKX13aGlsZShwKCIsIikpO2MoIn0iKX1yZXR1cm57a2luZDoiT2JqZWN0IixzdGFydDplLGVuZDpFLG1lbWJlcnM6dH19ZnVuY3Rpb24gbygpe3ZhciBlPXgsdD0iU3RyaW5nIj09PXc/dSgpOm51bGw7YygiU3RyaW5nIiksYygiOiIpO3ZhciBuPXMoKTtyZXR1cm57a2luZDoiTWVtYmVyIixzdGFydDplLGVuZDpFLGtleTp0LHZhbHVlOm59fWZ1bmN0aW9uIGEoKXt2YXIgZT14LHQ9W107aWYoYygiWyIpLCFwKCJdIikpe2Rve3QucHVzaChzKCkpfXdoaWxlKHAoIiwiKSk7YygiXSIpfXJldHVybntraW5kOiJBcnJheSIsc3RhcnQ6ZSxlbmQ6RSx2YWx1ZXM6dH19ZnVuY3Rpb24gcygpe3N3aXRjaCh3KXtjYXNlIlsiOnJldHVybiBhKCk7Y2FzZSJ7IjpyZXR1cm4gaSgpO2Nhc2UiU3RyaW5nIjpjYXNlIk51bWJlciI6Y2FzZSJCb29sZWFuIjpjYXNlIk51bGwiOnZhciBlPXUoKTtyZXR1cm4gZCgpLGV9cmV0dXJuIGMoIlZhbHVlIil9ZnVuY3Rpb24gdSgpe3JldHVybntraW5kOncsc3RhcnQ6eCxlbmQ6Qyx2YWx1ZTpKU09OLnBhcnNlKHYuc2xpY2UoeCxDKSl9fWZ1bmN0aW9uIGMoZSl7aWYodz09PWUpcmV0dXJuIHZvaWQgZCgpO3ZhciB0PXZvaWQgMDtpZigiRU9GIj09PXcpdD0iW2VuZCBvZiBmaWxlXSI7ZWxzZSBpZihDLXg+MSl0PSJgIit2LnNsaWNlKHgsQykrImAiO2Vsc2V7dmFyIG49di5zbGljZSh4KS5tYXRjaCgvXi4rP1xiLyk7dD0iYCIrKG4/blswXTp2W3hdKSsiYCJ9dGhyb3cgbCgiRXhwZWN0ZWQgIitlKyIgYnV0IGZvdW5kICIrdCsiLiIpfWZ1bmN0aW9uIGwoZSl7cmV0dXJue21lc3NhZ2U6ZSxzdGFydDp4LGVuZDpDfX1mdW5jdGlvbiBwKGUpe2lmKHc9PT1lKXJldHVybiBkKCksITB9ZnVuY3Rpb24gZigpe0M8YiYmKEMrKyxEPUM9PT1iPzA6di5jaGFyQ29kZUF0KEMpKX1mdW5jdGlvbiBkKCl7Zm9yKEU9Qzs5PT09RHx8MTA9PT1EfHwxMz09PUR8fDMyPT09RDspZigpO2lmKDA9PT1EKXJldHVybiB2b2lkKHc9IkVPRiIpO3N3aXRjaCh4PUMsRCl7Y2FzZSAzNDpyZXR1cm4gdz0iU3RyaW5nIixoKCk7Y2FzZSA0NTpjYXNlIDQ4OmNhc2UgNDk6Y2FzZSA1MDpjYXNlIDUxOmNhc2UgNTI6Y2FzZSA1MzpjYXNlIDU0OmNhc2UgNTU6Y2FzZSA1NjpjYXNlIDU3OnJldHVybiB3PSJOdW1iZXIiLGcoKTtjYXNlIDEwMjppZigiZmFsc2UiIT09di5zbGljZSh4LHgrNSkpYnJlYWs7cmV0dXJuIEMrPTQsZigpLHZvaWQodz0iQm9vbGVhbiIpO2Nhc2UgMTEwOmlmKCJudWxsIiE9PXYuc2xpY2UoeCx4KzQpKWJyZWFrO3JldHVybiBDKz0zLGYoKSx2b2lkKHc9Ik51bGwiKTtjYXNlIDExNjppZigidHJ1ZSIhPT12LnNsaWNlKHgseCs0KSlicmVhaztyZXR1cm4gQys9MyxmKCksdm9pZCh3PSJCb29sZWFuIil9dz12W3hdLGYoKX1mdW5jdGlvbiBoKCl7Zm9yKGYoKTszNCE9PUQmJkQ+MzE7KWlmKDkyPT09RClzd2l0Y2goZigpLEQpe2Nhc2UgMzQ6Y2FzZSA0NzpjYXNlIDkyOmNhc2UgOTg6Y2FzZSAxMDI6Y2FzZSAxMTA6Y2FzZSAxMTQ6Y2FzZSAxMTY6ZigpO2JyZWFrO2Nhc2UgMTE3OmYoKSxtKCksbSgpLG0oKSxtKCk7YnJlYWs7ZGVmYXVsdDp0aHJvdyBsKCJCYWQgY2hhcmFjdGVyIGVzY2FwZSBzZXF1ZW5jZS4iKX1lbHNle2lmKEM9PT1iKXRocm93IGwoIlVudGVybWluYXRlZCBzdHJpbmcuIik7ZigpfWlmKDM0PT09RClyZXR1cm4gdm9pZCBmKCk7dGhyb3cgbCgiVW50ZXJtaW5hdGVkIHN0cmluZy4iKX1mdW5jdGlvbiBtKCl7aWYoRD49NDgmJkQ8PTU3fHxEPj02NSYmRDw9NzB8fEQ+PTk3JiZEPD0xMDIpcmV0dXJuIGYoKTt0aHJvdyBsKCJFeHBlY3RlZCBoZXhhZGVjaW1hbCBkaWdpdC4iKX1mdW5jdGlvbiBnKCl7NDU9PT1EJiZmKCksNDg9PT1EP2YoKTp5KCksNDY9PT1EJiYoZigpLHkoKSksNjkhPT1EJiYxMDEhPT1EfHwoZigpLDQzIT09RCYmNDUhPT1EfHxmKCkseSgpKX1mdW5jdGlvbiB5KCl7aWYoRDw0OHx8RD41Nyl0aHJvdyBsKCJFeHBlY3RlZCBkZWNpbWFsIGRpZ2l0LiIpO2Rve2YoKX13aGlsZShEPj00OCYmRDw9NTcpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmRlZmF1bHQ9cjt2YXIgdj12b2lkIDAsYj12b2lkIDAseD12b2lkIDAsQz12b2lkIDAsRT12b2lkIDAsRD12b2lkIDAsdz12b2lkIDB9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigwKSxvPW4oNjI5KSxhPW4oNjMwKSxzPW4oOSksdT1uKDgpLGM9bigxMiksbD1uKDEpLHA9big4NSksZj1uZXcgcC5SZXNwb25zZVJlY29yZCh7ZGF0ZToiIix0aW1lOm5ldyBEYXRlLHJlc3VsdElEOiJkZWZhdWx0LWlkIn0pLGQ9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5zZXRSZWYsbj1lLnJlc3BvbnNlcyxyPW4uZ2V0KDApfHxmLHM9bi5zaXplPjE7cmV0dXJuIGkuY3JlYXRlRWxlbWVudCh4LHtyZWY6dCxpc1N1YnNjcmlwdGlvbjpzfSxuLnNpemU8PTE/aS5jcmVhdGVFbGVtZW50KEMse2tleToiZmlyc3QiLGlzU3Vic2NyaXB0aW9uOnN9LG4uc2l6ZT4xJiZyLnRpbWUmJmkuY3JlYXRlRWxlbWVudChFLG51bGwsaS5jcmVhdGVFbGVtZW50KEQsbnVsbCxvLmRlZmF1bHQoci50aW1lKSkpLGkuY3JlYXRlRWxlbWVudCh3LHtpc1N1YnNjcmlwdGlvbjpzfSxpLmNyZWF0ZUVsZW1lbnQoYS5SZXN1bHRWaWV3ZXIse3ZhbHVlOnIuZGF0ZSxpc1N1YnNjcmlwdGlvbjpzfSkpKTpuLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gaS5jcmVhdGVFbGVtZW50KEMse2tleTplLnJlc3VsdElEfHxTdHJpbmcoZS50aW1lKSxpc1N1YnNjcmlwdGlvbjpzfSxuLnNpemU+MSYmZS50aW1lJiZpLmNyZWF0ZUVsZW1lbnQoRSxudWxsLGkuY3JlYXRlRWxlbWVudChELG51bGwsby5kZWZhdWx0KGUudGltZSkpKSxpLmNyZWF0ZUVsZW1lbnQodyx7aXNTdWJzY3JpcHRpb246bi5zaXplPjF9LGkuY3JlYXRlRWxlbWVudChhLlJlc3VsdFZpZXdlcix7dmFsdWU6ZS5kYXRlLGlzU3Vic2NyaXB0aW9uOnN9KSkpfSkpfSxoPXUuY3JlYXRlU3RydWN0dXJlZFNlbGVjdG9yKHtyZXNwb25zZXM6Yy5nZXRSZXNwb25zZXN9KTt0LmRlZmF1bHQ9cy5jb25uZWN0KGgpKGQpO3ZhciBtLGcseSx2LGIseD1sLnN0eWxlZCgiZGl2IikobXx8KG09cihbIlxuICBmbGV4OiAxO1xuICBoZWlnaHQ6ICIsIjtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBvdmVyZmxvdzogIiwiO1xuICBtYXgtaGVpZ2h0OiBub25lICFpbXBvcnRhbnQ7XG5cbiAgLmNtLXN0cmluZyB7XG4gICAgY29sb3I6IHJnYig0MSwgMTg1LCAxMTUpO1xuICB9XG5cbiAgLmNtLWRlZiB7XG4gICAgY29sb3I6IHJnYigyNDEsIDE0MywgMSk7XG4gIH1cblxuICAuY20tcHJvcGVydHkge1xuICAgIGNvbG9yOiByZ2IoNTEsIDE0NywgMjIwKTtcbiAgfVxuXG4gICY6Oi13ZWJraXQtc2Nyb2xsYmFyIHtcbiAgICBkaXNwbGF5OiBub25lO1xuICB9XG5cbiAgLkNvZGVNaXJyb3Ige1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgfVxuICAuQ29kZU1pcnJvci1ndXR0ZXJzIHtcbiAgICBjdXJzb3I6IGNvbC1yZXNpemU7XG4gIH1cbiAgLkNvZGVNaXJyb3ItZm9sZGd1dHRlcixcbiAgLkNvZGVNaXJyb3ItZm9sZGd1dHRlci1vcGVuOmFmdGVyLFxuICAuQ29kZU1pcnJvci1mb2xkZ3V0dGVyLWZvbGRlZDphZnRlciB7XG4gICAgcGFkZGluZy1sZWZ0OiAzcHg7XG4gIH1cbiJdLFsiXG4gIGZsZXg6IDE7XG4gIGhlaWdodDogIiwiO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG92ZXJmbG93OiAiLCI7XG4gIG1heC1oZWlnaHQ6IG5vbmUgIWltcG9ydGFudDtcblxuICAuY20tc3RyaW5nIHtcbiAgICBjb2xvcjogcmdiKDQxLCAxODUsIDExNSk7XG4gIH1cblxuICAuY20tZGVmIHtcbiAgICBjb2xvcjogcmdiKDI0MSwgMTQzLCAxKTtcbiAgfVxuXG4gIC5jbS1wcm9wZXJ0eSB7XG4gICAgY29sb3I6IHJnYig1MSwgMTQ3LCAyMjApO1xuICB9XG5cbiAgJjo6LXdlYmtpdC1zY3JvbGxiYXIge1xuICAgIGRpc3BsYXk6IG5vbmU7XG4gIH1cblxuICAuQ29kZU1pcnJvciB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4gIC5Db2RlTWlycm9yLWd1dHRlcnMge1xuICAgIGN1cnNvcjogY29sLXJlc2l6ZTtcbiAgfVxuICAuQ29kZU1pcnJvci1mb2xkZ3V0dGVyLFxuICAuQ29kZU1pcnJvci1mb2xkZ3V0dGVyLW9wZW46YWZ0ZXIsXG4gIC5Db2RlTWlycm9yLWZvbGRndXR0ZXItZm9sZGVkOmFmdGVyIHtcbiAgICBwYWRkaW5nLWxlZnQ6IDNweDtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS5pc1N1YnNjcmlwdGlvbj8iYXV0byI6IjEwMCUifSxmdW5jdGlvbihlKXtyZXR1cm4gZS5pc1N1YnNjcmlwdGlvbj8iYXV0byI6InZpc2libGUifSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnJlc3VsdEJhY2tncm91bmR9KSxDPWwuc3R5bGVkKCJkaXYiKShnfHwoZz1yKFsiXG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleDogMTtcbiAgaGVpZ2h0OiAiLCI7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICY6bm90KDpmaXJzdC1jaGlsZCk6bGFzdC1vZi10eXBlIHtcbiAgICBtYXJnaW4tYm90dG9tOiA0OHB4O1xuICB9XG4iXSxbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXg6IDE7XG4gIGhlaWdodDogIiwiO1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICAmOm5vdCg6Zmlyc3QtY2hpbGQpOmxhc3Qtb2YtdHlwZSB7XG4gICAgbWFyZ2luLWJvdHRvbTogNDhweDtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS5pc1N1YnNjcmlwdGlvbj8iYXV0byI6IjEwMCUifSksRT1sLnN0eWxlZC5kaXYoeXx8KHk9cihbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGhlaWdodDogMTdweDtcbiAgbWFyZ2luLXRvcDogMTJweDtcbiAgbWFyZ2luLWJvdHRvbTogNHB4O1xuICAmOmJlZm9yZSB7XG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgIHdpZHRoOiAxMDAlO1xuICAgIGNvbnRlbnQ6ICcnO1xuICAgIHRvcDogOXB4O1xuICAgIGxlZnQ6IDk1cHg7XG4gICAgYm9yZGVyLXRvcDogMXB4IHNvbGlkXG4gICAgICAiLCI7XG4gIH1cbiJdLFsiXG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgaGVpZ2h0OiAxN3B4O1xuICBtYXJnaW4tdG9wOiAxMnB4O1xuICBtYXJnaW4tYm90dG9tOiA0cHg7XG4gICY6YmVmb3JlIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgY29udGVudDogJyc7XG4gICAgdG9wOiA5cHg7XG4gICAgbGVmdDogOTVweDtcbiAgICBib3JkZXItdG9wOiAxcHggc29saWRcbiAgICAgICIsIjtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnN1YnNjcmlwdGlvblRpbWVCb2FkZXJUb3B9KSxEPWwuc3R5bGVkLmRpdih2fHwodj1yKFsiXG4gIGZvbnQtc2l6ZTogMTJweDtcbiAgY29sb3I6ICIsIjtcbiAgcGFkZGluZy1sZWZ0OiAxNXB4O1xuIl0sWyJcbiAgZm9udC1zaXplOiAxMnB4O1xuICBjb2xvcjogIiwiO1xuICBwYWRkaW5nLWxlZnQ6IDE1cHg7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuc3Vic2NyaXB0aW9uVGltZVRleHR9KSx3PWwuc3R5bGVkKCJkaXYiKShifHwoYj1yKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXg6IDE7XG4gIGhlaWdodDogIiwiO1xuICBwb3NpdGlvbjogIiwiO1xuIl0sWyJcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleDogMTtcbiAgaGVpZ2h0OiAiLCI7XG4gIHBvc2l0aW9uOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzU3Vic2NyaXB0aW9uPyJhdXRvIjoiMTAwJSJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzU3Vic2NyaXB0aW9uPyJyZWxhdGl2ZSI6InN0YXRpYyJ9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PW5ldyBEYXRlLG49TWF0aC5hYnMoZS5nZXRUaW1lKCktdC5nZXRUaW1lKCkpLHI9TWF0aC5mbG9vcihuLzg2NGU1KSxpPU1hdGguZmxvb3IobiU4NjRlNS8zNmU1KSxvPU1hdGgucm91bmQobiU4NjRlNSUzNmU1LzZlNCk7aWYocj4wKXJldHVybiByKyIgZGF5cyBhZ28iO2lmKGk+MClyZXR1cm4gaSsiIGggYWdvIjtpZihvPjApcmV0dXJuIG8rIiBtaW4gYWdvIjt2YXIgYT1NYXRoLnJvdW5kKG4vMWUzKTtyZXR1cm4gYSsiIHNlYyIrKGE+MT8icyI6IiIpKyIgYWdvIn1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5kZWZhdWx0PXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKSxpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPW4oMCksYT1uKDEpLHM9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3ZhciB0PW51bGwhPT1lJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpcztyZXR1cm4gdC5zZXRSZWY9ZnVuY3Rpb24oZSl7dC5ub2RlPWV9LHR9cmV0dXJuIHIodCxlKSx0LnByb3RvdHlwZS5jb21wb25lbnREaWRNb3VudD1mdW5jdGlvbigpe3ZhciBlPW4oMik7big4OSksbig3MCksbigzOSksbigyNzQpLG4oMzgpLG4oOTApLG4oOTEpLG4oNjMxKTt2YXIgdD1bXTt0aGlzLnByb3BzLmhpZGVHdXR0ZXJzfHx0LnB1c2goIkNvZGVNaXJyb3ItZm9sZGd1dHRlciIpO3ZhciByPXt9O3RoaXMucHJvcHMuaGlkZUd1dHRlcnN8fChyPXttaW5Gb2xkU2l6ZTo0fSk7dmFyIGk9dGhpcy5wcm9wcy52YWx1ZXx8IiI7dGhpcy52aWV3ZXI9ZSh0aGlzLm5vZGUse2xpbmVXcmFwcGluZzohMCx2YWx1ZTppLHJlYWRPbmx5OiEwLHRoZW1lOiJncmFwaGlxbCIsbW9kZToiZ3JhcGhxbC1yZXN1bHRzIixrZXlNYXA6InN1YmxpbWUiLGZvbGRHdXR0ZXI6cixndXR0ZXJzOnQsZXh0cmFLZXlzOnsiQ21kLUYiOiJmaW5kUGVyc2lzdGVudCIsIkN0cmwtRiI6ImZpbmRQZXJzaXN0ZW50IiwiQ3RybC1MZWZ0IjoiZ29TdWJ3b3JkTGVmdCIsIkN0cmwtUmlnaHQiOiJnb1N1YndvcmRSaWdodCIsIkFsdC1MZWZ0IjoiZ29Hcm91cExlZnQiLCJBbHQtUmlnaHQiOiJnb0dyb3VwUmlnaHQifX0pfSx0LnByb3RvdHlwZS5zaG91bGRDb21wb25lbnRVcGRhdGU9ZnVuY3Rpb24oZSl7cmV0dXJuIHRoaXMucHJvcHMudmFsdWUhPT1lLnZhbHVlfSx0LnByb3RvdHlwZS5jb21wb25lbnREaWRVcGRhdGU9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnByb3BzLnZhbHVlfHwiIjt0aGlzLnZpZXdlci5zZXRWYWx1ZShlKX0sdC5wcm90b3R5cGUuY29tcG9uZW50V2lsbFVubW91bnQ9ZnVuY3Rpb24oKXt0aGlzLnZpZXdlcj1udWxsfSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGMse3JlZjp0aGlzLnNldFJlZixpc1N1YnNjcmlwdGlvbjp0aGlzLnByb3BzLmlzU3Vic2NyaXB0aW9ufSl9LHQucHJvdG90eXBlLmdldENvZGVNaXJyb3I9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy52aWV3ZXJ9LHQucHJvdG90eXBlLmdldENsaWVudEhlaWdodD1mdW5jdGlvbigpe3JldHVybiB0aGlzLm5vZGUmJnRoaXMubm9kZS5jbGllbnRIZWlnaHR9LHR9KG8uQ29tcG9uZW50KTt0LlJlc3VsdFZpZXdlcj1zO3ZhciB1LGM9YS5zdHlsZWQoImRpdiIpKHV8fCh1PWkoWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4OiAxO1xuICBoZWlnaHQ6ICIsIjtcbiAgLkNvZGVNaXJyb3Ige1xuICAgIGhlaWdodDogIiwiO1xuICAgIHBvc2l0aW9uOiAiLCI7XG4gICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICBiYWNrZ3JvdW5kOiBub25lO1xuICAgIHBhZGRpbmctbGVmdDogMzhweDtcbiAgfVxuICAuQ29kZU1pcnJvci1jdXJzb3Ige1xuICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcbiAgfVxuICAuQ29kZU1pcnJvci1zY3JvbGwge1xuICAgIG92ZXJmbG93OiBhdXRvICFpbXBvcnRhbnQ7XG4gICAgbWF4LXdpZHRoOiA1MHZ3O1xuICAgIG1hcmdpbi1yaWdodDogMTBweDtcbiAgfVxuICAuY20tc3RyaW5nIHtcbiAgICBjb2xvcjogIiwiICFpbXBvcnRhbnQ7XG4gIH1cbiJdLFsiXG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleDogMTtcbiAgaGVpZ2h0OiAiLCI7XG4gIC5Db2RlTWlycm9yIHtcbiAgICBoZWlnaHQ6ICIsIjtcbiAgICBwb3NpdGlvbjogIiwiO1xuICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gICAgYmFja2dyb3VuZDogbm9uZTtcbiAgICBwYWRkaW5nLWxlZnQ6IDM4cHg7XG4gIH1cbiAgLkNvZGVNaXJyb3ItY3Vyc29yIHtcbiAgICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7XG4gIH1cbiAgLkNvZGVNaXJyb3Itc2Nyb2xsIHtcbiAgICBvdmVyZmxvdzogYXV0byAhaW1wb3J0YW50O1xuICAgIG1heC13aWR0aDogNTB2dztcbiAgICBtYXJnaW4tcmlnaHQ6IDEwcHg7XG4gIH1cbiAgLmNtLXN0cmluZyB7XG4gICAgY29sb3I6ICIsIiAhaW1wb3J0YW50O1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzU3Vic2NyaXB0aW9uPyJhdXRvIjoiMTAwJSJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzU3Vic2NyaXB0aW9uPyJhdXRvIjoiMTAwJSJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzU3Vic2NyaXB0aW9uPyJyZWxhdGl2ZSI6ImFic29sdXRlJSJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMucHJvcGVydHl9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dmFyIG49ZS5sZXZlbHM7cmV0dXJuKG4mJjAhPT1uLmxlbmd0aD9uW24ubGVuZ3RoLTFdLSh0aGlzLmVsZWN0cmljSW5wdXQudGVzdCh0KT8xOjApOmUuaW5kZW50TGV2ZWwpKnRoaXMuY29uZmlnLmluZGVudFVuaXR9dmFyIGk9bigyKSxvPWZ1bmN0aW9uKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX0oaSksYT1uKDcxKTtvLmRlZmF1bHQuZGVmaW5lTW9kZSgiZ3JhcGhxbC1yZXN1bHRzIixmdW5jdGlvbihlKXt2YXIgdD0oMCxhLm9ubGluZVBhcnNlcikoe2VhdFdoaXRlc3BhY2U6ZnVuY3Rpb24oZSl7cmV0dXJuIGUuZWF0U3BhY2UoKX0sbGV4UnVsZXM6cyxwYXJzZVJ1bGVzOnUsZWRpdG9yQ29uZmlnOnt0YWJTaXplOmUudGFiU2l6ZX19KTtyZXR1cm57Y29uZmlnOmUsc3RhcnRTdGF0ZTp0LnN0YXJ0U3RhdGUsdG9rZW46dC50b2tlbixpbmRlbnQ6cixlbGVjdHJpY0lucHV0Oi9eXHMqW31cXV0vLGZvbGQ6ImJyYWNlIixjbG9zZUJyYWNrZXRzOntwYWlyczonW117fSIiJyxleHBsb2RlOiJbXXt9In19fSk7dmFyIHM9e1B1bmN0dWF0aW9uOi9eXFt8XXxce3xcfXw6fCwvLE51bWJlcjovXi0/KD86MHwoPzpbMS05XVswLTldKikpKD86XC5bMC05XSopPyg/OltlRV1bKy1dP1swLTldKyk/LyxTdHJpbmc6L14iKD86W14iXFxdfFxcKD86InxcL3xcXHxifGZ8bnxyfHR8dVswLTlhLWZBLUZdezR9KSkqIj8vLEtleXdvcmQ6L150cnVlfGZhbHNlfG51bGwvfSx1PXtEb2N1bWVudDpbKDAsYS5wKSgieyIpLCgwLGEubGlzdCkoIkVudHJ5IiwoMCxhLnApKCIsIikpLCgwLGEucCkoIn0iKV0sRW50cnk6WygwLGEudCkoIlN0cmluZyIsImRlZiIpLCgwLGEucCkoIjoiKSwiVmFsdWUiXSxWYWx1ZTpmdW5jdGlvbihlKXtzd2l0Y2goZS5raW5kKXtjYXNlIk51bWJlciI6cmV0dXJuIk51bWJlclZhbHVlIjtjYXNlIlN0cmluZyI6cmV0dXJuIlN0cmluZ1ZhbHVlIjtjYXNlIlB1bmN0dWF0aW9uIjpzd2l0Y2goZS52YWx1ZSl7Y2FzZSJbIjpyZXR1cm4iTGlzdFZhbHVlIjtjYXNlInsiOnJldHVybiJPYmplY3RWYWx1ZSJ9cmV0dXJuIG51bGw7Y2FzZSJLZXl3b3JkIjpzd2l0Y2goZS52YWx1ZSl7Y2FzZSJ0cnVlIjpjYXNlImZhbHNlIjpyZXR1cm4iQm9vbGVhblZhbHVlIjtjYXNlIm51bGwiOnJldHVybiJOdWxsVmFsdWUifXJldHVybiBudWxsfX0sTnVtYmVyVmFsdWU6WygwLGEudCkoIk51bWJlciIsIm51bWJlciIpXSxTdHJpbmdWYWx1ZTpbKDAsYS50KSgiU3RyaW5nIiwic3RyaW5nIildLEJvb2xlYW5WYWx1ZTpbKDAsYS50KSgiS2V5d29yZCIsImJ1aWx0aW4iKV0sTnVsbFZhbHVlOlsoMCxhLnQpKCJLZXl3b3JkIiwia2V5d29yZCIpXSxMaXN0VmFsdWU6WygwLGEucCkoIlsiKSwoMCxhLmxpc3QpKCJWYWx1ZSIsKDAsYS5wKSgiLCIpKSwoMCxhLnApKCJdIildLE9iamVjdFZhbHVlOlsoMCxhLnApKCJ7IiksKDAsYS5saXN0KSgiT2JqZWN0RmllbGQiLCgwLGEucCkoIiwiKSksKDAsYS5wKSgifSIpXSxPYmplY3RGaWVsZDpbKDAsYS50KSgiU3RyaW5nIiwicHJvcGVydHkiKSwoMCxhLnApKCI6IiksIlZhbHVlIl19fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX0saT1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9big2MzMpLHM9big4NyksdT1uKDgpLGM9bigxMiksbD1uKDkpLHA9cy5kZWZhdWx0LmRpdih5fHwoeT1yKFsiXG4gIHBhZGRpbmctdG9wOiA2cHg7XG4gIHBhZGRpbmctbGVmdDogMjVweDtcbiAgcGFkZGluZy1yaWdodDogMjVweDtcbiAgY29sb3I6ICIsIjtcbiAgb3ZlcmZsb3c6IGF1dG87XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgaGVpZ2h0OiAxMDAlO1xuIl0sWyJcbiAgcGFkZGluZy10b3A6IDZweDtcbiAgcGFkZGluZy1sZWZ0OiAyNXB4O1xuICBwYWRkaW5nLXJpZ2h0OiAyNXB4O1xuICBjb2xvcjogIiwiO1xuICBvdmVyZmxvdzogYXV0bztcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBoZWlnaHQ6IDEwMCU7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMudGV4dH0pLGY9cy5kZWZhdWx0LmRpdih2fHwodj1yKFsiXG4gIGZvbnQtc2l6ZTogMTRweDtcbiJdLFsiXG4gIGZvbnQtc2l6ZTogMTRweDtcbiJdKSkpLGQ9cy5kZWZhdWx0LmRpdihifHwoYj1yKFsiXG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgY29sb3I6IHJnYmEoMjQxLCAxNDMsIDEsIDEpO1xuIl0sWyJcbiAgZm9udC1zaXplOiAxNHB4O1xuICBjb2xvcjogcmdiYSgyNDEsIDE0MywgMSwgMSk7XG4iXSkpKSxoPXMuZGVmYXVsdC5kaXYoeHx8KHg9cihbIlxuICBwYWRkaW5nLWxlZnQ6IDEwMHB4O1xuICBwYWRkaW5nLWJvdHRvbTogMTAwcHg7XG4gIHBhZGRpbmctdG9wOiAxNnB4O1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIG92ZXJmbG93OiBhdXRvO1xuICB0b3A6IDA7XG4gIGxlZnQ6IDA7XG4gIHdpZHRoOiBjYWxjKDEwMCUgKyAxMDBweCk7XG4gIGhlaWdodDogY2FsYygxMDAlICsgMTE2cHgpO1xuIl0sWyJcbiAgcGFkZGluZy1sZWZ0OiAxMDBweDtcbiAgcGFkZGluZy1ib3R0b206IDEwMHB4O1xuICBwYWRkaW5nLXRvcDogMTZweDtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBvdmVyZmxvdzogYXV0bztcbiAgdG9wOiAwO1xuICBsZWZ0OiAwO1xuICB3aWR0aDogY2FsYygxMDAlICsgMTAwcHgpO1xuICBoZWlnaHQ6IGNhbGMoMTAwJSArIDExNnB4KTtcbiJdKSkpLG09ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3JldHVybiBudWxsIT09ZSYmZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fHRoaXN9cmV0dXJuIGkodCxlKSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnByb3BzLHQ9ZS50cmFjaW5nLG49ZS50cmFjaW5nU3VwcG9ydGVkLHI9ZS5zdGFydFRpbWUsaT1lLmVuZFRpbWUscz1lLm9wZW4sdT10JiZyP01hdGguYWJzKG5ldyBEYXRlKHQuc3RhcnRUaW1lKS5nZXRUaW1lKCktci5nZXRUaW1lKCkpOjAsYz10JiZpP01hdGguYWJzKGkuZ2V0VGltZSgpLW5ldyBEYXRlKHQuZW5kVGltZSkuZ2V0VGltZSgpKTowLGw9MWU2KnU7cmV0dXJuIG8uY3JlYXRlRWxlbWVudChwLG51bGwsdCYmcz9vLmNyZWF0ZUVsZW1lbnQoaCxudWxsLG8uY3JlYXRlRWxlbWVudChhLmRlZmF1bHQse3BhdGg6WyJSZXF1ZXN0Il0sc3RhcnRPZmZzZXQ6MCxkdXJhdGlvbjpsfSksdC5leGVjdXRpb24ucmVzb2x2ZXJzLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGEuZGVmYXVsdCx7a2V5OmUucGF0aC5qb2luKCIuIikscGF0aDplLnBhdGgsc3RhcnRPZmZzZXQ6ZS5zdGFydE9mZnNldCtsLGR1cmF0aW9uOmUuZHVyYXRpb259KX0pLG8uY3JlYXRlRWxlbWVudChhLmRlZmF1bHQse3BhdGg6WyJSZXNwb25zZSJdLHN0YXJ0T2Zmc2V0OnQuZHVyYXRpb24rbCxkdXJhdGlvbjoxZTYqY30pKTpuP28uY3JlYXRlRWxlbWVudChmLG51bGwsdGhpcy5wcm9wcy5xdWVyeVJ1bm5pbmc/IlJ1bm5pbmcgcXVlcnkgLi4uIjoiUGxlYXNlIHJlLXJ1biB0aGUgcXVlcnkgdG8gc2hvdyB0cmFjaW5nIHJlc3VsdHMuIik6by5jcmVhdGVFbGVtZW50KGQsbnVsbCwiVGhpcyBHcmFwaFFMIHNlcnZlciBkb2Vzblx1MjAxOXQgc3VwcG9ydCB0cmFjaW5nLiBTZWUgdGhlIGZvbGxvd2luZyBwYWdlIGZvciBpbnN0cnVjdGlvbnM6IixvLmNyZWF0ZUVsZW1lbnQoImJyIixudWxsKSwiaHR0cHM6Ly9naXRodWIuY29tL2Fwb2xsb2dyYXBocWwvYXBvbGxvLXRyYWNpbmciKSl9LHR9KG8uUHVyZUNvbXBvbmVudCksZz11LmNyZWF0ZVN0cnVjdHVyZWRTZWxlY3Rvcih7dHJhY2luZzpjLmdldFRyYWNpbmcsc3RhcnRUaW1lOmMuZ2V0Q3VycmVudFF1ZXJ5U3RhcnRUaW1lLGVuZFRpbWU6Yy5nZXRDdXJyZW50UXVlcnlFbmRUaW1lLHRyYWNpbmdTdXBwb3J0ZWQ6Yy5nZXRUcmFjaW5nU3VwcG9ydGVkLHF1ZXJ5UnVubmluZzpjLmdldFF1ZXJ5UnVubmluZ30pO3QuZGVmYXVsdD1sLmNvbm5lY3QoZykobSk7dmFyIHksdixiLHh9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfSxpPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCk7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPW4oMCksYT1uKDg3KSxzPWEuZGVmYXVsdC5kaXYoZHx8KGQ9cihbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGZvbnQtc2l6ZTogMTJweDtcbiAgZGlzcGxheTogdGFibGU7XG4gIHBhZGRpbmctcmlnaHQ6IDI1cHg7XG5cbiAgY29sb3I6ICIsIjtcbiJdLFsiXG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgZm9udC1zaXplOiAxMnB4O1xuICBkaXNwbGF5OiB0YWJsZTtcbiAgcGFkZGluZy1yaWdodDogMjVweDtcblxuICBjb2xvcjogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnRleHR9KSx1PWEuZGVmYXVsdC5zcGFuKGh8fChoPXIoWyJcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIG1hcmdpbjogMCAxMHB4O1xuICBoZWlnaHQ6IDEuNXB4O1xuICBib3R0b206IDRweDtcblxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSxbIlxuICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgbWFyZ2luOiAwIDEwcHg7XG4gIGhlaWdodDogMS41cHg7XG4gIGJvdHRvbTogNHB4O1xuXG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy50ZXh0fSksYz1hLmRlZmF1bHQuc3BhbihtfHwobT1yKFsiXG4gIGZvbnQtc2l6ZTogMTBweDtcbiAgY29sb3I6ICIsIjtcbiJdLFsiXG4gIGZvbnQtc2l6ZTogMTBweDtcbiAgY29sb3I6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy50ZXh0SW5hY3RpdmV9KSxsPWEuZGVmYXVsdC5zcGFuKGd8fChnPXIoWyJcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBsZWZ0OiAwO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTEwMCUpO1xuICBkaXNwbGF5OiBpbmxpbmUtZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcblxuICB0ZXh0LWFsaWduOiByaWdodDtcbiJdLFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgbGVmdDogMDtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGVYKC0xMDAlKTtcbiAgZGlzcGxheTogaW5saW5lLWZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG5cbiAgdGV4dC1hbGlnbjogcmlnaHQ7XG4iXSkpKSxwPWEuZGVmYXVsdC5zcGFuKHl8fCh5PXIoWyJcbiAgbWFyZ2luLWxlZnQ6IDEwcHg7XG4iXSxbIlxuICBtYXJnaW4tbGVmdDogMTBweDtcbiJdKSkpLGY9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3ZhciB0PW51bGwhPT1lJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpcztyZXR1cm4gdC5zdGF0ZT17Y29sbGFwc2VkOiExfSx0fXJldHVybiBpKHQsZSksdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcyx0PWUucGF0aCxuPWUuc3RhcnRPZmZzZXQscj1lLmR1cmF0aW9uLGk9bi8xZTYsYT1yLzFlNjtyZXR1cm4gby5jcmVhdGVFbGVtZW50KHMse3N0eWxlOnt0cmFuc2Zvcm06InRyYW5zbGF0ZVgoIitpKyJweCkifX0sby5jcmVhdGVFbGVtZW50KGwsbnVsbCxvLmNyZWF0ZUVsZW1lbnQocCxudWxsLHQuc2xpY2UoLTIpLm1hcChmdW5jdGlvbihlLG4pe3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoInNwYW4iLHtzdHlsZTp7b3BhY2l0eTpuPT09dC5zbGljZSgtMikubGVuZ3RoLTE/MTouNn0sa2V5OmV9LChuPjA/Ii4iOiIiKStlKX0pKSksby5jcmVhdGVFbGVtZW50KHUse3N0eWxlOnt3aWR0aDpNYXRoLm1heChhLDMpfX0pLG8uY3JlYXRlRWxlbWVudChjLG51bGwsdGhpcy5wcmludER1cmF0aW9uKHIpKSl9LHQucHJvdG90eXBlLnByaW50RHVyYXRpb249ZnVuY3Rpb24oZSl7dmFyIHQ9TWF0aC5yb3VuZChlLzFlMyk7aWYodD4xZTMpe3JldHVybiBNYXRoLnJvdW5kKHQvMWUzKSsiIG1zIn1yZXR1cm4gdCsiIFx4YjVzIn0sdH0oby5Db21wb25lbnQpO3QuZGVmYXVsdD1mO3ZhciBkLGgsbSxnLHl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7dmFyIHI9W107aWYoIWUpcmV0dXJue2luc2VydGlvbnM6cixyZXN1bHQ6dH07dmFyIGM9dm9pZCAwO3RyeXtjPSgwLHUucGFyc2UpKHQpfWNhdGNoKGUpe3JldHVybntpbnNlcnRpb25zOnIscmVzdWx0OnR9fXZhciBsPW58fGkscD1uZXcgdS5UeXBlSW5mbyhlKTtyZXR1cm4oMCx1LnZpc2l0KShjLHtsZWF2ZTpmdW5jdGlvbihlKXtwLmxlYXZlKGUpfSxlbnRlcjpmdW5jdGlvbihlKXtpZihwLmVudGVyKGUpLCJGaWVsZCI9PT1lLmtpbmQmJiFlLnNlbGVjdGlvblNldCl7dmFyIG49cC5nZXRUeXBlKCksaT1vKG4sbCk7aWYoaSl7dmFyIGE9cyh0LGUubG9jLnN0YXJ0KTtyLnB1c2goe2luZGV4OmUubG9jLmVuZCxzdHJpbmc6IiAiKygwLHUucHJpbnQpKGkpLnJlcGxhY2UoL1xuL2csIlxuIithKX0pfX19fSkse2luc2VydGlvbnM6cixyZXN1bHQ6YSh0LHIpfX1mdW5jdGlvbiBpKGUpe2lmKCFlLmdldEZpZWxkcylyZXR1cm5bXTt2YXIgdD1lLmdldEZpZWxkcygpO2lmKHQuaWQpcmV0dXJuWyJpZCJdO2lmKHQuZWRnZXMpcmV0dXJuWyJlZGdlcyJdO2lmKHQubm9kZSlyZXR1cm5bIm5vZGUiXTt2YXIgbj1bXTtyZXR1cm4gT2JqZWN0LmtleXModCkuZm9yRWFjaChmdW5jdGlvbihlKXsoMCx1LmlzTGVhZlR5cGUpKHRbZV0udHlwZSkmJm4ucHVzaChlKX0pLG59ZnVuY3Rpb24gbyhlLHQpe3ZhciBuPSgwLHUuZ2V0TmFtZWRUeXBlKShlKTtpZihlJiYhKDAsdS5pc0xlYWZUeXBlKShlKSl7dmFyIHI9dChuKTtpZihBcnJheS5pc0FycmF5KHIpJiYwIT09ci5sZW5ndGgpcmV0dXJue2tpbmQ6IlNlbGVjdGlvblNldCIsc2VsZWN0aW9uczpyLm1hcChmdW5jdGlvbihlKXt2YXIgcj1uLmdldEZpZWxkcygpW2VdO3JldHVybntraW5kOiJGaWVsZCIsbmFtZTp7a2luZDoiTmFtZSIsdmFsdWU6ZX0sc2VsZWN0aW9uU2V0Om8ocj9yLnR5cGU6bnVsbCx0KX19KX19fWZ1bmN0aW9uIGEoZSx0KXtpZigwPT09dC5sZW5ndGgpcmV0dXJuIGU7dmFyIG49IiIscj0wO3JldHVybiB0LmZvckVhY2goZnVuY3Rpb24odCl7dmFyIGk9dC5pbmRleCxvPXQuc3RyaW5nO24rPWUuc2xpY2UocixpKStvLHI9aX0pLG4rPWUuc2xpY2Uocil9ZnVuY3Rpb24gcyhlLHQpe2Zvcih2YXIgbj10LHI9dDtuOyl7dmFyIGk9ZS5jaGFyQ29kZUF0KG4tMSk7aWYoMTA9PT1pfHwxMz09PWl8fDgyMzI9PT1pfHw4MjMzPT09aSlicmVhaztuLS0sOSE9PWkmJjExIT09aSYmMTIhPT1pJiYzMiE9PWkmJjE2MCE9PWkmJihyPW4pfXJldHVybiBlLnN1YnN0cmluZyhuLHIpfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmZpbGxMZWFmcz1yO3ZhciB1PW4oNyl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKSxpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX0sbz1mdW5jdGlvbigpe3JldHVybiBvPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPTEscj1hcmd1bWVudHMubGVuZ3RoO248cjtuKyspe3Q9YXJndW1lbnRzW25dO2Zvcih2YXIgaSBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LGkpJiYoZVtpXT10W2ldKX1yZXR1cm4gZX0sby5hcHBseSh0aGlzLGFyZ3VtZW50cyl9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgYT1uKDApLHM9big0MCksdT1uKDkpLGM9bigyOTEpLGw9bigyODkpLHA9big2NyksZj1uKDY4KSxkPW4oMTIpLGg9big4KSxtPW4oMSksZz1uKDI5MCkseT1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe3ZhciBuPWUuY2FsbCh0aGlzLHQpfHx0aGlzO3JldHVybiBuLmNsaWVudFg9MCxuLmNsaWVudFk9MCxuLnNldFdpZHRoPWZ1bmN0aW9uKGUpe3ZvaWQgMD09PWUmJihlPW4ucHJvcHMpLG4uYWN0aXZlQ29udGVudENvbXBvbmVudCYmbi5wcm9wcy5kb2NzLmRvY3NPcGVuJiZyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24oKXt2YXIgdD1uLmFjdGl2ZUNvbnRlbnRDb21wb25lbnQuZ2V0V2lkdGgoZSk7bi5wcm9wcy5jaGFuZ2VXaWR0aERvY3MoZS5zZXNzaW9uSWQsTWF0aC5taW4odCxuLnByb3BzLm1heFdpZHRoKSl9KX0sbi5zZXRBY3RpdmVDb250ZW50UmVmPWZ1bmN0aW9uKGUpe2UmJihuLmFjdGl2ZUNvbnRlbnRDb21wb25lbnQ9ZS5nZXRXcmFwcGVkSW5zdGFuY2UoKSl9LG4uc2V0UmVmPWZ1bmN0aW9uKGUpe24ucmVmPWV9LG4uc2hvd0RvY0Zyb21UeXBlPWZ1bmN0aW9uKGUpe24ucHJvcHMuc2V0RG9jc1Zpc2libGUobi5wcm9wcy5zZXNzaW9uSWQsITAsMCksbi5hY3RpdmVDb250ZW50Q29tcG9uZW50LnNob3dEb2NGcm9tVHlwZShlKX0sbi5zZXRDb250ZW50Q29udGFpbmVyUmVmPWZ1bmN0aW9uKGUpe24ucmVmQ29udGVudENvbnRhaW5lcj1lfSxuLmhhbmRsZVRhYkNsaWNrPWZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiBuLnByb3BzLmRvY3MuYWN0aXZlVGFiSWR4PT09ZT8obi5wcm9wcy5zZXREb2NzVmlzaWJsZShuLnByb3BzLnNlc3Npb25JZCwhMSksbi5zZXRXaWR0aCgpKTpuLnByb3BzLmRvY3MuYWN0aXZlVGFiSWR4IT09ZT8obi5wcm9wcy5zZXREb2NzVmlzaWJsZShuLnByb3BzLnNlc3Npb25JZCwhMSxuLnByb3BzLmRvY3MuYWN0aXZlVGFiSWR4KSxuLnByb3BzLnNldERvY3NWaXNpYmxlKG4ucHJvcHMuc2Vzc2lvbklkLCEwLGUpLG4uc2V0V2lkdGgoKSk6KG4ucHJvcHMuc2V0RG9jc1Zpc2libGUobi5wcm9wcy5zZXNzaW9uSWQsITAsZSksbi5zZXRXaWR0aCgpKX19LG4uaGFuZGxlS2V5RG93bj1mdW5jdGlvbihlKXtpZighKGUudGFyZ2V0IGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudHx8ZS5tZXRhS2V5fHxlLnNoaWZ0S2V5fHxlLmFsdEtleXx8ZS5jdHJsS2V5KSl7c3dpdGNoKGMoZSkpe2Nhc2UiZXNjIjpuLnByb3BzLmNoYW5nZUtleU1vdmUobi5wcm9wcy5zZXNzaW9uSWQsITApLGUucHJldmVudERlZmF1bHQoKSxuLnByb3BzLnNldERvY3NWaXNpYmxlKG4ucHJvcHMuc2Vzc2lvbklkLCExKX19fSxuLmhhbmRsZURvY3NSZXNpemVTdGFydD1mdW5jdGlvbihlKXtlLnByZXZlbnREZWZhdWx0KCk7dmFyIHQ9bi5wcm9wcy5kb2NzLmRvY3NXaWR0aCxyPWUuY2xpZW50WC1sLmdldExlZnQoZS50YXJnZXQpLGk9ZnVuY3Rpb24oZSl7aWYoMD09PWUuYnV0dG9ucylyZXR1cm4gbygpO3ZhciB0PW4ucmVmLGk9ZS5jbGllbnRYLWwuZ2V0TGVmdCh0KS1yLGE9dC5jbGllbnRXaWR0aC1pLHM9d2luZG93LmlubmVyV2lkdGgtNTAsdT1zPGE/czphO3U8MTAwP24ucHJvcHMuc2V0RG9jc1Zpc2libGUobi5wcm9wcy5zZXNzaW9uSWQsITEsbi5wcm9wcy5kb2NzLmFjdGl2ZVRhYklkeCk6KG4ucHJvcHMuc2V0RG9jc1Zpc2libGUobi5wcm9wcy5zZXNzaW9uSWQsITAsbi5wcm9wcy5kb2NzLmFjdGl2ZVRhYklkeCksbi5wcm9wcy5jaGFuZ2VXaWR0aERvY3Mobi5wcm9wcy5zZXNzaW9uSWQsdSkpfSxvPWZ1bmN0aW9uKCl7bi5wcm9wcy5kb2NzLmRvY3NPcGVufHxuLnByb3BzLmNoYW5nZVdpZHRoRG9jcyhuLnByb3BzLnNlc3Npb25JZCx0KSxkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJtb3VzZW1vdmUiLGkpLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNldXAiLG8pLGk9bnVsbCxvPW51bGx9O2RvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNlbW92ZSIsaSksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsbyl9LG4uaGFuZGxlTW91c2VNb3ZlPWZ1bmN0aW9uKGUpe24uY2xpZW50WD1lLmNsaWVudFgsbi5jbGllbnRZPWUuY2xpZW50WSxuLnByb3BzLmRvY3Mua2V5TW92ZSYmbi5jbGllbnRYIT09ZS5jbGllbnRYJiZuLmNsaWVudFkhPT1lLmNsaWVudFkmJm4ucHJvcHMuY2hhbmdlS2V5TW92ZShuLnByb3BzLnNlc3Npb25JZCwhMSl9LHdpbmRvdy5kPW4sbn1yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLmNvbXBvbmVudERpZFVwZGF0ZT1mdW5jdGlvbihlKXshZS5kb2NzLmFjdGl2ZVRhYklkeCYmdGhpcy5wcm9wcy5kb2NzLmFjdGl2ZVRhYklkeCYmdGhpcy5wcm9wcy5zZXREb2NzVmlzaWJsZSh0aGlzLnByb3BzLnNlc3Npb25JZCwhMCx0aGlzLnByb3BzLmRvY3MuYWN0aXZlVGFiSWR4KSxlLmFjdGl2ZVRhYklkeCYmIXRoaXMucHJvcHMuZG9jcy5hY3RpdmVUYWJJZHgmJnRoaXMucHJvcHMuc2V0RG9jc1Zpc2libGUodGhpcy5wcm9wcy5zZXNzaW9uSWQsITEpLHRoaXMuc2V0V2lkdGgoKSx0aGlzLnByb3BzLmRvY3MuYWN0aXZlVGFiSWR4IT09ZS5kb2NzLmFjdGl2ZVRhYklkeCYmdGhpcy5yZWZDb250ZW50Q29udGFpbmVyJiZ0aGlzLnJlZkNvbnRlbnRDb250YWluZXIuZm9jdXMoKX0sdC5wcm90b3R5cGUuY29tcG9uZW50RGlkTW91bnQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5wcm9wcy5kb2NzLmFjdGl2ZVRhYklkeHx8dGhpcy5wcm9wcy5zZXREb2NzVmlzaWJsZSh0aGlzLnByb3BzLnNlc3Npb25JZCwhMSksdGhpcy5zZXRXaWR0aCgpfSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLHQ9dGhpcy5wcm9wcy5kb2NzLG49dC5kb2NzT3BlbixyPXQuZG9jc1dpZHRoLGk9dC5hY3RpdmVUYWJJZHgscz17d2lkdGg6bj9yOjB9LHU9biYmYS5DaGlsZHJlbi50b0FycmF5KHRoaXMucHJvcHMuY2hpbGRyZW4pW2ldO3JldHVybiBhLmNyZWF0ZUVsZW1lbnQoayx7b3BlbjpuLHN0eWxlOnMscmVmOnRoaXMuc2V0UmVmfSxhLmNyZWF0ZUVsZW1lbnQoVCxudWxsLGEuQ2hpbGRyZW4udG9BcnJheSh0aGlzLnByb3BzLmNoaWxkcmVuKS5tYXAoZnVuY3Rpb24odCxuKXtyZXR1cm4gYS5jbG9uZUVsZW1lbnQodCxvKHt9LHQucHJvcHMse2tleTpuLG9uQ2xpY2s6ZS5oYW5kbGVUYWJDbGljayhuKSxhY3RpdmU6bj09PWl9KSl9KSksYS5jcmVhdGVFbGVtZW50KF8se29uTW91c2VEb3duOnRoaXMuaGFuZGxlRG9jc1Jlc2l6ZVN0YXJ0fSksYS5jcmVhdGVFbGVtZW50KE8se2luZGV4Oml9KSxhLmNyZWF0ZUVsZW1lbnQoQSx7b25LZXlEb3duOnRoaXMuaGFuZGxlS2V5RG93bixvbk1vdXNlTW92ZTp0aGlzLmhhbmRsZU1vdXNlTW92ZSx0YWJJbmRleDppLGNvbG9yOnUmJnUucHJvcHMuYWN0aXZlQ29sb3IscmVmOnRoaXMuc2V0Q29udGVudENvbnRhaW5lclJlZn0sdSYmYS5jbG9uZUVsZW1lbnQodS5wcm9wcy5jaGlsZHJlbixvKHt9LHUucHJvcHMse3JlZjp0aGlzLnNldEFjdGl2ZUNvbnRlbnRSZWYsc2V0V2lkdGg6dGhpcy5zZXRXaWR0aH0pKSkpfSx0fShhLkNvbXBvbmVudCksdj1mdW5jdGlvbihlKXtyZXR1cm4gcy5iaW5kQWN0aW9uQ3JlYXRvcnMoe2FkZFN0YWNrOnAuYWRkU3RhY2ssdG9nZ2xlRG9jczpwLnRvZ2dsZURvY3MsY2hhbmdlV2lkdGhEb2NzOnAuY2hhbmdlV2lkdGhEb2NzLGNoYW5nZUtleU1vdmU6cC5jaGFuZ2VLZXlNb3ZlLHNldERvY3NWaXNpYmxlOnAuc2V0RG9jc1Zpc2libGV9LGUpfSxiPWguY3JlYXRlU3RydWN0dXJlZFNlbGVjdG9yKHtkb2NzOmYuZ2V0U2Vzc2lvbkRvY3Msc2Vzc2lvbklkOmQuZ2V0U2VsZWN0ZWRTZXNzaW9uSWRGcm9tUm9vdH0pLHg9dS5jb25uZWN0KGIsdixudWxsLHt3aXRoUmVmOiEwfSkoeSk7eC5UYWI9Zy5kZWZhdWx0LHQuZGVmYXVsdD14O3ZhciBDLEUsRCx3LFMsaz1tLnN0eWxlZCgiZGl2IikoQ3x8KEM9aShbIlxuICBiYWNrZ3JvdW5kOiB3aGl0ZTtcbiAgb3V0bGluZTogbm9uZTtcbiAgYm94LXNoYWRvdzogMCAwIDhweCByZ2JhKDAsIDAsIDAsIDAuMTUpO1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHJpZ2h0OiAwcHg7XG4gIHotaW5kZXg6ICIsIjtcbiAgaGVpZ2h0OiAxMDAlO1xuICBmb250LWZhbWlseTogJ09wZW4gU2FucycsIHNhbnMtc2VyaWY7XG4gIC13ZWJraXQtZm9udC1zbW9vdGhpbmc6IGFudGlhbGlhc2VkO1xuICAuZG9jLXR5cGUtZGVzY3JpcHRpb24gcCB7XG4gICAgcGFkZGluZzogMTZweDtcbiAgICBmb250LXNpemU6IDE0cHg7XG4gIH1cbiAgLmZpZWxkLW5hbWUge1xuICAgIGNvbG9yOiAjMWY2MWEwO1xuICB9XG4gIC50eXBlLW5hbWUge1xuICAgIGNvbG9yOiByZ2IoMjQ1LCAxNjAsIDApO1xuICB9XG4gIC5hcmctbmFtZSB7XG4gICAgY29sb3I6ICMxZjYxYTk7XG4gIH1cbiAgY29kZSB7XG4gICAgZm9udC1mYW1pbHk6ICdTb3VyY2UgQ29kZSBQcm8nLCBtb25vc3BhY2U7XG4gICAgYm9yZGVyLXJhZGl1czogMnB4O1xuICAgIHBhZGRpbmc6IDFweCAycHg7XG4gICAgYmFja2dyb3VuZDogcmdiYSgwLCAwLCAwLCAwLjA2KTtcbiAgfVxuIl0sWyJcbiAgYmFja2dyb3VuZDogd2hpdGU7XG4gIG91dGxpbmU6IG5vbmU7XG4gIGJveC1zaGFkb3c6IDAgMCA4cHggcmdiYSgwLCAwLCAwLCAwLjE1KTtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICByaWdodDogMHB4O1xuICB6LWluZGV4OiAiLCI7XG4gIGhlaWdodDogMTAwJTtcbiAgZm9udC1mYW1pbHk6ICdPcGVuIFNhbnMnLCBzYW5zLXNlcmlmO1xuICAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDtcbiAgLmRvYy10eXBlLWRlc2NyaXB0aW9uIHAge1xuICAgIHBhZGRpbmc6IDE2cHg7XG4gICAgZm9udC1zaXplOiAxNHB4O1xuICB9XG4gIC5maWVsZC1uYW1lIHtcbiAgICBjb2xvcjogIzFmNjFhMDtcbiAgfVxuICAudHlwZS1uYW1lIHtcbiAgICBjb2xvcjogcmdiKDI0NSwgMTYwLCAwKTtcbiAgfVxuICAuYXJnLW5hbWUge1xuICAgIGNvbG9yOiAjMWY2MWE5O1xuICB9XG4gIGNvZGUge1xuICAgIGZvbnQtZmFtaWx5OiAnU291cmNlIENvZGUgUHJvJywgbW9ub3NwYWNlO1xuICAgIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgICBwYWRkaW5nOiAxcHggMnB4O1xuICAgIGJhY2tncm91bmQ6IHJnYmEoMCwgMCwgMCwgMC4wNik7XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUub3Blbj8yZTM6M30pLEE9bS5zdHlsZWQuZGl2KEV8fChFPWkoWyJcbiAgYmFja2dyb3VuZDogd2hpdGU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBsZXR0ZXItc3BhY2luZzogMC4zcHg7XG4gIGJveC1zaGFkb3c6IC0xcHggMXB4IDZweCAwIHJnYmEoMCwgMCwgMCwgMC4zKTtcbiAgb3V0bGluZTogbm9uZTtcbiAgJjo6YmVmb3JlIHtcbiAgICB0b3A6IDA7XG4gICAgYm90dG9tOiAwO1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgei1pbmRleDogMztcbiAgICBsZWZ0OiAwcHg7XG4gICAgY29udGVudDogJyc7XG4gICAgd2lkdGg6IDZweDtcbiAgfVxuIl0sWyJcbiAgYmFja2dyb3VuZDogd2hpdGU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBsZXR0ZXItc3BhY2luZzogMC4zcHg7XG4gIGJveC1zaGFkb3c6IC0xcHggMXB4IDZweCAwIHJnYmEoMCwgMCwgMCwgMC4zKTtcbiAgb3V0bGluZTogbm9uZTtcbiAgJjo6YmVmb3JlIHtcbiAgICB0b3A6IDA7XG4gICAgYm90dG9tOiAwO1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgei1pbmRleDogMztcbiAgICBsZWZ0OiAwcHg7XG4gICAgY29udGVudDogJyc7XG4gICAgd2lkdGg6IDZweDtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5jb2xvdXJzW2UuY29sb3JdfHwiIzNENTg2NiJ9KSxfPW0uc3R5bGVkLmRpdihEfHwoRD1pKFsiXG4gIGN1cnNvcjogY29sLXJlc2l6ZTtcbiAgb3V0bGluZTogbm9uZSAhaW1wb3J0YW50O1xuICBoZWlnaHQ6IDEwMCU7XG4gIGxlZnQ6IC01cHg7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiAwO1xuICBib3R0b206IDA7XG4gIHdpZHRoOiAxMHB4O1xuICB6LWluZGV4OiAxMDtcbiJdLFsiXG4gIGN1cnNvcjogY29sLXJlc2l6ZTtcbiAgb3V0bGluZTogbm9uZSAhaW1wb3J0YW50O1xuICBoZWlnaHQ6IDEwMCU7XG4gIGxlZnQ6IC01cHg7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiAwO1xuICBib3R0b206IDA7XG4gIHdpZHRoOiAxMHB4O1xuICB6LWluZGV4OiAxMDtcbiJdKSkpLFQ9bS5zdHlsZWQuZGl2KHd8fCh3PWkoWyJcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICBvdXRsaW5lOiBub25lICFpbXBvcnRhbnQ7XG4gIHotaW5kZXg6IDI7XG4gIGhlaWdodDogMDtcbiAgdG9wOiAxMjlweDtcbiJdLFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgb3V0bGluZTogbm9uZSAhaW1wb3J0YW50O1xuICB6LWluZGV4OiAyO1xuICBoZWlnaHQ6IDA7XG4gIHRvcDogMTI5cHg7XG4iXSkpKSxPPW0uc3R5bGVkLmRpdihTfHwoUz1pKFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiAwO1xuICBib3R0b206IDA7XG4gIGxlZnQ6IDA7XG4gIHdpZHRoOiAyMHB4O1xuICB6LWluZGV4OiAxO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbiAgY29udGVudDogJyc7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdLFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiAwO1xuICBib3R0b206IDA7XG4gIGxlZnQ6IDA7XG4gIHdpZHRoOiAyMHB4O1xuICB6LWluZGV4OiAxO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbiAgY29udGVudDogJyc7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIDA9PT1lLmluZGV4PyJsaW5lYXItZ3JhZGllbnQoXG5cdFx0dG8gcmlnaHQsXG5cdFx0cmdiYSgyNTUsIDI1NSwgMjU1LCAxKSAzMCUsXG5cdFx0cmdiYSgyNTUsIDI1NSwgMjU1LCAwKSkiOiJ0cmFuc3BhcmVudCJ9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDApLG89big0MCksYT1uKDkpLHM9big2NyksdT1uKDE0MyksYz1uKDM2KSxsPW4oMTIpLHA9big2OCksZj1uKDgpLGQ9bigyOTIpLGg9big2MzcpLG09big2MzgpLGc9big2MzkpLHk9bigxNyksdj1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe3ZhciBuPWUuY2FsbCh0aGlzLHQpfHx0aGlzO3JldHVybiBuLnNldFJlZj1mdW5jdGlvbihlKXtuLnJlZj1lfSx3aW5kb3cuZD1uLG59cmV0dXJuIHIodCxlKSx0LnByb3RvdHlwZS5jb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzPWZ1bmN0aW9uKGUpeyF0aGlzLnByb3BzLnNjaGVtYSYmZS5zY2hlbWEmJnRoaXMuc2V0V2lkdGgoZSl9LHQucHJvdG90eXBlLnNldFdpZHRoPWZ1bmN0aW9uKGUpe3ZvaWQgMD09PWUmJihlPXRoaXMucHJvcHMpLHRoaXMucHJvcHMuc2V0V2lkdGgoZSl9LHQucHJvdG90eXBlLmdldFdpZHRoPWZ1bmN0aW9uKGUpe3JldHVybiB2b2lkIDA9PT1lJiYoZT10aGlzLnByb3BzKSxlLmRvY3MuZG9jc1dpZHRofHxjLmNvbHVtbldpZHRofSx0LnByb3RvdHlwZS5jb21wb25lbnREaWRNb3VudD1mdW5jdGlvbigpe3RoaXMuc2V0V2lkdGgoKX0sdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGUsdD10aGlzLnByb3BzLG49dC5zY2hlbWEscj10LnNldHRpbmdzLG89dC5pc1BvbGxpbmdTY2hlbWE7cmV0dXJuIHZvaWQgMD09PW4/ZT1pLmNyZWF0ZUVsZW1lbnQodS5kZWZhdWx0LG51bGwpOm51bGw9PT1uJiYoZT1pLmNyZWF0ZUVsZW1lbnQoZC5FcnJvckNvbnRhaW5lcixudWxsLCJObyBTY2hlbWEgQXZhaWxhYmxlIikpLGkuY3JlYXRlRWxlbWVudChoLlNjaGVtYUV4cGxvcmVyQ29udGFpbmVyLHtyZWY6dGhpcy5zZXRSZWZ9LGU/aS5jcmVhdGVFbGVtZW50KGguU0RMQ29sdW1uLG51bGwsZSk6aS5jcmVhdGVFbGVtZW50KGguU0RMQ29sdW1uLHt3aWR0aDp0aGlzLnByb3BzLmRvY3MuZG9jc1dpZHRofHxjLmNvbHVtbldpZHRoLTF9LGkuY3JlYXRlRWxlbWVudChtLmRlZmF1bHQse3NjaGVtYTpufSksaS5jcmVhdGVFbGVtZW50KGcuZGVmYXVsdCx7c2NoZW1hOm4sc2V0dGluZ3M6cixpc1BvbGxpbmdTY2hlbWE6byx3aWR0aDp0aGlzLnByb3BzLmRvY3MuZG9jc1dpZHRofHxjLmNvbHVtbldpZHRofSkpKX0sdH0oaS5Db21wb25lbnQpLGI9ZnVuY3Rpb24oZSl7cmV0dXJuIG8uYmluZEFjdGlvbkNyZWF0b3JzKHt0b2dnbGVEb2NzOnMudG9nZ2xlRG9jcyxjaGFuZ2VXaWR0aERvY3M6cy5jaGFuZ2VXaWR0aERvY3Msc2V0RG9jc1Zpc2libGU6cy5zZXREb2NzVmlzaWJsZX0sZSl9LHg9Zi5jcmVhdGVTdHJ1Y3R1cmVkU2VsZWN0b3Ioe3NldHRpbmdzOnkuZ2V0U2V0dGluZ3MsZG9jczpwLmdldFNlc3Npb25Eb2NzLHNlc3Npb25JZDpsLmdldFNlbGVjdGVkU2Vzc2lvbklkRnJvbVJvb3QsaXNQb2xsaW5nU2NoZW1hOmwuZ2V0SXNQb2xsaW5nU2NoZW1hfSk7dC5kZWZhdWx0PWEuY29ubmVjdCh4LGIsbnVsbCx7d2l0aFJlZjohMH0pKHYpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPW4oMCksbz1uKDEpLGE9bigzNik7dC5TY2hlbWFFeHBsb3JlckNvbnRhaW5lcj1vLnN0eWxlZC5kaXYodXx8KHU9cihbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGhlaWdodDogMTAwJTtcbiAgd2lkdGg6IDEwMCU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGZsZXgtd3JhcDogd3JhcDtcbiAgYWxpZ24taXRlbXM6IHN0cmV0Y2g7XG4gIHBhZGRpbmc6IDBweCA4cHggOHB4IDhweDtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBmb250LWZhbWlseTogIiwiO1xuICBmb250LXNpemU6ICIsIjtcbiAgb3V0bGluZTogbm9uZSAhaW1wb3J0YW50O1xuIl0sWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBoZWlnaHQ6IDEwMCU7XG4gIHdpZHRoOiAxMDAlO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBmbGV4LXdyYXA6IHdyYXA7XG4gIGFsaWduLWl0ZW1zOiBzdHJldGNoO1xuICBwYWRkaW5nOiAwcHggOHB4IDhweCA4cHg7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgZm9udC1mYW1pbHk6ICIsIjtcbiAgZm9udC1zaXplOiAiLCI7XG4gIG91dGxpbmU6IG5vbmUgIWltcG9ydGFudDtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuImRhcmsiPT09ZS50aGVtZS5tb2RlP2UudGhlbWUuZWRpdG9yQ29sb3Vycy5lZGl0b3JCYWNrZ3JvdW5kOiJ3aGl0ZSJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNldHRpbmdzWyJlZGl0b3IuZm9udEZhbWlseSJdfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zZXR0aW5nc1siZWRpdG9yLmZvbnRTaXplIl0rInB4In0pO3ZhciBzPWZ1bmN0aW9uKGUpe3ZhciB0PWUuY2hpbGRyZW4sbj1lLndpZHRoLHI9dm9pZCAwPT09bj9hLmNvbHVtbldpZHRoOm47cmV0dXJuIGkuY3JlYXRlRWxlbWVudChsLHtzdHlsZTp7d2lkdGg6cn19LHQpfTt0LlNETENvbHVtbj1zO3ZhciB1LGMsbD1vLnN0eWxlZCgiZGl2IikoY3x8KGM9cihbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4OiAxIDAgYXV0bztcbiAgZmxleC1mbG93OiBjb2x1bW47XG4gIHBhZGRpbmctYm90dG9tOiAyMHB4O1xuICBib3JkZXItcmlnaHQ6IDFweCBzb2xpZCAiLCI7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4iXSxbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4OiAxIDAgYXV0bztcbiAgZmxleC1mbG93OiBjb2x1bW47XG4gIHBhZGRpbmctYm90dG9tOiAyMHB4O1xuICBib3JkZXItcmlnaHQ6IDFweCBzb2xpZCAiLCI7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMuYmxhY2sxMH0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9bigxKSxzPW4oMTQyKSx1PW4oMjkzKSxjPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIG49ZS5jYWxsKHRoaXMsdCl8fHRoaXM7cmV0dXJuIG4uaGFuZGxlQ2xpY2s9ZnVuY3Rpb24oZSl7aWYoIW4ubm9kZS5jb250YWlucyhlLnRhcmdldCkpcmV0dXJuIG4uc2V0U3RhdGUoe29wZW46ITF9KX0sbi5zaG93T3B0aW9ucz1mdW5jdGlvbigpe24uc2V0U3RhdGUoe29wZW46IW4uc3RhdGUub3Blbn0pfSxuLnByaW50U0RMPWZ1bmN0aW9uKCl7cmV0dXJuIHUuZG93bmxvYWRTY2hlbWEobi5wcm9wcy5zY2hlbWEsInNkbCIpfSxuLnByaW50SW50cm9zcGVjdGlvbj1mdW5jdGlvbigpe3JldHVybiB1LmRvd25sb2FkU2NoZW1hKG4ucHJvcHMuc2NoZW1hLCJqc29uIil9LG4uc2V0UmVmPWZ1bmN0aW9uKGUpe24ubm9kZT1lfSxuLnN0YXRlPXtvcGVuOiExfSxufXJldHVybiByKHQsZSksdC5wcm90b3R5cGUuY29tcG9uZW50V2lsbE1vdW50PWZ1bmN0aW9uKCl7ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2Vkb3duIix0aGlzLmhhbmRsZUNsaWNrLCExKX0sdC5wcm90b3R5cGUuY29tcG9uZW50V2lsbFVubW91bnQ9ZnVuY3Rpb24oKXtkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJtb3VzZWRvd24iLHRoaXMuaGFuZGxlQ2xpY2ssITEpfSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnN0YXRlLm9wZW47cmV0dXJuIG8uY3JlYXRlRWxlbWVudChtLHtyZWY6dGhpcy5zZXRSZWZ9LG8uY3JlYXRlRWxlbWVudCh5LG51bGwsIlNjaGVtYSIpLG8uY3JlYXRlRWxlbWVudChnLG51bGwsby5jcmVhdGVFbGVtZW50KHYse29uQ2xpY2s6dGhpcy5zaG93T3B0aW9ucyxvcGVuOmV9LCJEb3dubG9hZCIpLGUmJm8uY3JlYXRlRWxlbWVudChvLkZyYWdtZW50LG51bGwsby5jcmVhdGVFbGVtZW50KGIse29uQ2xpY2s6dGhpcy5wcmludEludHJvc3BlY3Rpb259LCJKU09OIiksby5jcmVhdGVFbGVtZW50KGIse29uQ2xpY2s6dGhpcy5wcmludFNETH0sIlNETCIpKSkpfSx0fShvLkNvbXBvbmVudCk7dC5kZWZhdWx0PWM7dmFyIGwscCxmLGQsaCxtPWEuc3R5bGVkLmRpdihsfHwobD1pKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gIGhlaWdodDogNjRweDtcbiAgd2lkdGg6IDEwMCU7XG4gIG1hcmdpbi1yaWdodDogMTA4cHg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogZmxleC1zdGFydDtcbiAgb3V0bGluZTogbm9uZTtcbiAgdXNlci1zZWxlY3Q6IG5vbmU7XG4iXSxbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBoZWlnaHQ6IDY0cHg7XG4gIHdpZHRoOiAxMDAlO1xuICBtYXJnaW4tcmlnaHQ6IDEwOHB4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGZsZXgtc3RhcnQ7XG4gIG91dGxpbmU6IG5vbmU7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuIl0pKSksZz1hLnN0eWxlZC5kaXYocHx8KHA9aShbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMTZweDtcbiAgcmlnaHQ6IDJlbTtcbiAgd2lkdGg6IDEwOHB4O1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LXdyYXA6IHdyYXA7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4iXSxbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMTZweDtcbiAgcmlnaHQ6IDJlbTtcbiAgd2lkdGg6IDEwOHB4O1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LXdyYXA6IHdyYXA7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4iXSkpKSx5PWEuc3R5bGVkLmRpdihmfHwoZj1pKFsiXG4gIGNvbG9yOiAiLCI7XG4gIGN1cnNvcjogZGVmYXVsdDtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBmb250LXdlaWdodDogNjAwO1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlICFpbXBvcnRhbnQ7XG4gIGZvbnQtZmFtaWx5OiAnT3BlbiBTYW5zJywgc2Fucy1zZXJpZiAhaW1wb3J0YW50O1xuICBsZXR0ZXItc3BhY2luZzogMXB4O1xuICB1c2VyLXNlbGVjdDogbm9uZSAhaW1wb3J0YW50O1xuICBwYWRkaW5nOiAxNnB4O1xuICBwYWRkaW5nLXJpZ2h0OiA1cHg7XG4iXSxbIlxuICBjb2xvcjogIiwiO1xuICBjdXJzb3I6IGRlZmF1bHQ7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZSAhaW1wb3J0YW50O1xuICBmb250LWZhbWlseTogJ09wZW4gU2FucycsIHNhbnMtc2VyaWYgIWltcG9ydGFudDtcbiAgbGV0dGVyLXNwYWNpbmc6IDFweDtcbiAgdXNlci1zZWxlY3Q6IG5vbmUgIWltcG9ydGFudDtcbiAgcGFkZGluZzogMTZweDtcbiAgcGFkZGluZy1yaWdodDogNXB4O1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4geChlKS50aXRsZX0pLHY9YS5zdHlsZWQocy5CdXR0b24pKGR8fChkPWkoWyJcbiAgZmxleDogMTtcbiAgY29sb3I6ICIsIjtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBoZWlnaHQ6IDMycHg7XG4gIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgJjpob3ZlciB7XG4gICAgY29sb3I6ICIsIjtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAiLCI7XG4gIH1cbiJdLFsiXG4gIGZsZXg6IDE7XG4gIGNvbG9yOiAiLCI7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgaGVpZ2h0OiAzMnB4O1xuICBib3JkZXItcmFkaXVzOiAycHg7XG4gICY6aG92ZXIge1xuICAgIGNvbG9yOiAiLCI7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogIiwiO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiB4KGUpLmRvd25sb2FkLnRleHR9LGZ1bmN0aW9uKGUpe3JldHVybiB4KGUpLmRvd25sb2FkLmJ1dHRvbn0sZnVuY3Rpb24oZSl7cmV0dXJuIHgoZSkuYnV0dG9uVGV4dEhvdmVyfSxmdW5jdGlvbihlKXtyZXR1cm4geChlKS5idXR0b25Ib3Zlcn0pLGI9YS5zdHlsZWQodikoaHx8KGg9aShbIlxuICB0ZXh0LWFsaWduOiBsZWZ0O1xuICB3aWR0aDogMTAwJTtcbiAgbWFyZ2luLWxlZnQ6IDBweDtcbiAgYm9yZGVyLXJhZGl1czogMHB4O1xuICB6LWluZGV4OiAyMDAwO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSxbIlxuICB0ZXh0LWFsaWduOiBsZWZ0O1xuICB3aWR0aDogMTAwJTtcbiAgbWFyZ2luLWxlZnQ6IDBweDtcbiAgYm9yZGVyLXJhZGl1czogMHB4O1xuICB6LWluZGV4OiAyMDAwO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiB4KGUpLmJ1dHRvbn0pLHg9ZnVuY3Rpb24oZSl7cmV0dXJuImRhcmsiPT09ZS50aGVtZS5tb2RlP3t0aXRsZToid2hpdGUiLHN1YnRpdGxlOiIjOEI5NTlDIixkb3dubG9hZDp7dGV4dDplLm9wZW4/IiM4Qjk1OUMiOiJ3aGl0ZSIsYnV0dG9uOmUudGhlbWUuY29sb3Vycy5kYXJrQmx1ZX0sYnV0dG9uVGV4dDoid2hpdGUiLGJ1dHRvbjplLnRoZW1lLmNvbG91cnMuZGFya0JsdWUsYnV0dG9uSG92ZXI6IiMyQjNDNDgiLGJ1dHRvblRleHRIb3Zlcjoid2hpdGUifTp7dGl0bGU6ZS50aGVtZS5jb2xvdXJzLmRhcmtCbHVlLHN1YnRpdGxlOiJyZ2JhKDYxLCA4OCwgMTAyLCAwLjUpIixkb3dubG9hZDp7dGV4dDplLm9wZW4/InJnYmEoNjEsIDg4LCAxMDIsIDAuNSkiOmUudGhlbWUuY29sb3Vycy5kYXJrQmx1ZSxidXR0b246IiNmNmY2ZjYifSxidXR0b25UZXh0OmUudGhlbWUuY29sb3Vycy5kYXJrQmx1ZSxidXR0b246IiNmNmY2ZjYiLGJ1dHRvbkhvdmVyOiIjRURFREVEIixidXR0b25UZXh0SG92ZXI6ZS50aGVtZS5jb2xvdXJzLmRhcmtCbHVlfX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7KGZ1bmN0aW9uKGUpe3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9big3KSxzPW4oMzcpLHU9bigxKSxjPW4oMjkzKSxsPWZ1bmN0aW9uKHQpe2Z1bmN0aW9uIGkoZSl7dmFyIG49dC5jYWxsKHRoaXMsZSl8fHRoaXM7cmV0dXJuIG4uaGFuZGxlU2Nyb2xsPWZ1bmN0aW9uKGUpe3JldHVybiBlLmRvYy5zY3JvbGxUb3A+MD9uLnNldFN0YXRlKHtvdmVyZmxvd1k6ITB9KTpuLnNldFN0YXRlKHtvdmVyZmxvd1k6ITF9KX0sbi5zZXRSZWY9ZnVuY3Rpb24oZSl7bi5ub2RlPWV9LG4uc3RhdGU9e292ZXJmbG93WTohMX0sbi5jYWNoZWRWYWx1ZT1lLnZhbHVlfHwiIixuLnByb3BzLmdldFJlZiYmbi5wcm9wcy5nZXRSZWYobiksbn1yZXR1cm4gcihpLHQpLGkucHJvdG90eXBlLmNvbXBvbmVudERpZE1vdW50PWZ1bmN0aW9uKCl7dmFyIHQ9bigyKTtuKDcwKSxuKDI3MyksbigyODMpO3ZhciByPVtdO3IucHVzaCgiQ29kZU1pcnJvci1saW5lbnVtYmVycyIpLHRoaXMuZWRpdG9yPXQodGhpcy5ub2RlLHthdXRvZm9jdXM6ITEsdmFsdWU6Yy5nZXRTREwodGhpcy5wcm9wcy5zY2hlbWEsdGhpcy5wcm9wcy5zZXR0aW5nc1sic2NoZW1hLmRpc2FibGVDb21tZW50cyJdKXx8IiIsbGluZU51bWJlcnM6ITEsc2hvd0N1cnNvcldoZW5TZWxlY3Rpbmc6ITEsdGFiU2l6ZToxLG1vZGU6ImdyYXBocWwiLHRoZW1lOiJncmFwaGlxbCIsa2V5TWFwOiJzdWJsaW1lIixyZWFkT25seTohMCxndXR0ZXJzOnJ9KSxlLmVkaXRvcj10aGlzLmVkaXRvcix0aGlzLmVkaXRvci5vbigic2Nyb2xsIix0aGlzLmhhbmRsZVNjcm9sbCksdGhpcy5lZGl0b3IucmVmcmVzaCgpfSxpLnByb3RvdHlwZS5jb21wb25lbnREaWRVcGRhdGU9ZnVuY3Rpb24oZSl7dmFyIHQ9bigyKTtpZigodGhpcy5wcm9wcy5zY2hlbWEmJmEucHJpbnRTY2hlbWEodGhpcy5wcm9wcy5zY2hlbWEpKSE9PShlLnNjaGVtYSYmYS5wcmludFNjaGVtYShlLnNjaGVtYSkpKXt2YXIgcj10aGlzLmVkaXRvci5nZXRTY3JvbGxJbmZvKCk7dGhpcy5jYWNoZWRWYWx1ZT1jLmdldFNETCh0aGlzLnByb3BzLnNjaGVtYSx0aGlzLnByb3BzLnNldHRpbmdzWyJzY2hlbWEuZGlzYWJsZUNvbW1lbnRzIl0pfHwiIix0aGlzLmVkaXRvci5zZXRWYWx1ZShjLmdldFNETCh0aGlzLnByb3BzLnNjaGVtYSx0aGlzLnByb3BzLnNldHRpbmdzWyJzY2hlbWEuZGlzYWJsZUNvbW1lbnRzIl0pKSx0aGlzLnByb3BzLmlzUG9sbGluZ1NjaGVtYSYmdGhpcy5lZGl0b3Iuc2Nyb2xsVG8oci5sZWZ0LHIudG9wKSx0LnNpZ25hbCh0aGlzLmVkaXRvciwiY2hhbmdlIix0aGlzLmVkaXRvcil9dGhpcy5wcm9wcy53aWR0aCE9PWUud2lkdGgmJnRoaXMuZWRpdG9yLnJlZnJlc2goKSx0aGlzLnByb3BzLnNldHRpbmdzWyJzY2hlbWEuZGlzYWJsZUNvbW1lbnRzIl0hPT1lLnNldHRpbmdzWyJzY2hlbWEuZGlzYWJsZUNvbW1lbnRzIl0mJnRoaXMuZWRpdG9yLnJlZnJlc2goKX0saS5wcm90b3R5cGUuY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wcz1mdW5jdGlvbihlKXt0aGlzLnByb3BzLnNlc3Npb25JZCE9PWUuc2Vzc2lvbklkJiZ0aGlzLmVkaXRvci5zY3JvbGxUbygwLDApfSxpLnByb3RvdHlwZS5jb21wb25lbnRXaWxsVW5tb3VudD1mdW5jdGlvbigpe3RoaXMuZWRpdG9yLm9mZigic2Nyb2xsIiksdGhpcy5lZGl0b3I9bnVsbH0saS5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5zdGF0ZS5vdmVyZmxvd1k7cmV0dXJuIG8uY3JlYXRlRWxlbWVudChzLmRlZmF1bHQsbnVsbCxlJiZvLmNyZWF0ZUVsZW1lbnQoaCxudWxsKSxvLmNyZWF0ZUVsZW1lbnQoZCx7cmVmOnRoaXMuc2V0UmVmfSkpfSxpLnByb3RvdHlwZS5nZXRDb2RlTWlycm9yPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZWRpdG9yfSxpLnByb3RvdHlwZS5nZXRDbGllbnRIZWlnaHQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5ub2RlJiZ0aGlzLm5vZGUuY2xpZW50SGVpZ2h0fSxpfShvLlB1cmVDb21wb25lbnQpO3QuZGVmYXVsdD1sO3ZhciBwLGYsZD11LnN0eWxlZC5kaXYocHx8KHA9aShbIlxuICBmbGV4OiAxO1xuICBoZWlnaHQ6IGF1dG87XG4gIG92ZXJmbG93LXg6IGhpZGRlbjtcbiAgb3ZlcmZsb3cteTogc2Nyb2xsO1xuICAuQ29kZU1pcnJvciB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICAgIHBhZGRpbmctbGVmdDogMjBweDtcbiAgfVxuIl0sWyJcbiAgZmxleDogMTtcbiAgaGVpZ2h0OiBhdXRvO1xuICBvdmVyZmxvdy14OiBoaWRkZW47XG4gIG92ZXJmbG93LXk6IHNjcm9sbDtcbiAgLkNvZGVNaXJyb3Ige1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgICBwYWRkaW5nLWxlZnQ6IDIwcHg7XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuImRhcmsiPT09ZS50aGVtZS5tb2RlP2UudGhlbWUuZWRpdG9yQ29sb3Vycy5lZGl0b3JCYWNrZ3JvdW5kOiJ3aGl0ZSJ9KSxoPXUuc3R5bGVkLmRpdihmfHwoZj1pKFsiXG4gIHBvc2l0aW9uOiBmaXhlZDtcbiAgdG9wOiAwO1xuICBsZWZ0OiAwO1xuICByaWdodDogMDtcbiAgaGVpZ2h0OiAxcHg7XG4gIGJveC1zaGFkb3c6IDBweCAxcHggM3B4IHJnYmEoMTcsIDE3LCAxNywgMC4xKTtcbiAgei1pbmRleDogMTAwMDtcbiJdLFsiXG4gIHBvc2l0aW9uOiBmaXhlZDtcbiAgdG9wOiAwO1xuICBsZWZ0OiAwO1xuICByaWdodDogMDtcbiAgaGVpZ2h0OiAxcHg7XG4gIGJveC1zaGFkb3c6IDBweCAxcHggM3B4IHJnYmEoMTcsIDE3LCAxNywgMC4xKTtcbiAgei1pbmRleDogMTAwMDtcbiJdKSkpfSkuY2FsbCh0LG4oMTEpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPW4oNDApLHM9big5KSx1PW4oMjkxKSxjPW4oNjQxKSxsPW4oMjk5KSxwPW4oNjcpLGY9bigxNDMpLGQ9bigzNiksaD1uKDY5NiksbT1uKDY2KSxnPW4oNjgpLHk9bigxMiksdj1uKDgpLGI9bigyOTIpLHg9bigxKSxDPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIG49ZS5jYWxsKHRoaXMsdCl8fHRoaXM7cmV0dXJuIG4uc2V0UmVmPWZ1bmN0aW9uKGUpe24ucmVmPWV9LG4uc2hvd0RvY0Zyb21UeXBlPWZ1bmN0aW9uKGUpe24ucHJvcHMuYWRkU3RhY2sobi5wcm9wcy5zZXNzaW9uSWQsZSwwLDApfSxuLmhhbmRsZVNlYXJjaD1mdW5jdGlvbihlKXtuLnNldFN0YXRlKHtzZWFyY2hWYWx1ZTplfSl9LG4uaGFuZGxlS2V5RG93bj1mdW5jdGlvbihlKXtpZighKGUudGFyZ2V0IGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudHx8ZS5tZXRhS2V5fHxlLnNoaWZ0S2V5fHxlLmFsdEtleXx8ZS5jdHJsS2V5KSl7ZS5wcmV2ZW50RGVmYXVsdCgpLG4ucHJvcHMuY2hhbmdlS2V5TW92ZShuLnByb3BzLnNlc3Npb25JZCwhMCk7dmFyIHQ9bi5wcm9wcy5kb2NzLm5hdlN0YWNrLmxlbmd0aD4wJiZuLnByb3BzLmRvY3MubmF2U3RhY2tbbi5wcm9wcy5kb2NzLm5hdlN0YWNrLmxlbmd0aC0xXSxyPW4ucHJvcHMuZG9jcy5uYXZTdGFjay5sZW5ndGg+MCYmbi5wcm9wcy5kb2NzLm5hdlN0YWNrW24ucHJvcHMuZG9jcy5uYXZTdGFjay5sZW5ndGgtMl0saT11KGUpO3N3aXRjaChpKXtjYXNlImVzYyI6bi5wcm9wcy5zZXREb2NzVmlzaWJsZShuLnByb3BzLnNlc3Npb25JZCwhMSk7YnJlYWs7Y2FzZSJsZWZ0IjpyJiZuLnByb3BzLmFkZFN0YWNrKG4ucHJvcHMuc2Vzc2lvbklkLHIuZmllbGQsci54LHIueSk7YnJlYWs7Y2FzZSJyaWdodCI6aWYodCl7dmFyIG89bS5zZXJpYWxpemUobi5wcm9wcy5zY2hlbWEsdC5maWVsZCksYT1tLmdldEVsZW1lbnQobywwKTthJiZuLnByb3BzLmFkZFN0YWNrKG4ucHJvcHMuc2Vzc2lvbklkLGEsdC54KzEsMCl9ZWxzZXt2YXIgbz1tLnNlcmlhbGl6ZVJvb3Qobi5wcm9wcy5zY2hlbWEpLHM9bS5nZXRFbGVtZW50Um9vdChvLDApO3MmJm4ucHJvcHMuYWRkU3RhY2sobi5wcm9wcy5zZXNzaW9uSWQscywwLDApfWJyZWFrO2Nhc2UidXAiOmNhc2UiZG93biI6aWYocil7dmFyIG89bS5zZXJpYWxpemUobi5wcm9wcy5zY2hlbWEsci5maWVsZCkscz1tLmdldEVsZW1lbnQobywidXAiPT09aT90LnktMTp0LnkrMSk7cyYmbi5wcm9wcy5hZGRTdGFjayhuLnByb3BzLnNlc3Npb25JZCxzLHQueCwidXAiPT09aT90LnktMTp0LnkrMSl9ZWxzZXt2YXIgbz1tLnNlcmlhbGl6ZVJvb3Qobi5wcm9wcy5zY2hlbWEpLGM9dD90Lnk6MCxzPW0uZ2V0RWxlbWVudFJvb3QobywidXAiPT09aT9jLTE6YysxKTtzJiZuLnByb3BzLmFkZFN0YWNrKG4ucHJvcHMuc2Vzc2lvbklkLHMsMCwidXAiPT09aT9jLTE6YysxKX19fX0sbi5zdGF0ZT17c2VhcmNoVmFsdWU6IiIsd2lkdGhNYXA6e319LHdpbmRvdy5kPW4sbn1yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLmNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHM9ZnVuY3Rpb24oZSl7KHRoaXMucHJvcHMuZG9jcy5uYXZTdGFjay5sZW5ndGghPT1lLmRvY3MubmF2U3RhY2subGVuZ3RofHx0aGlzLnByb3BzLmRvY3MubmF2U3RhY2suc2xpY2UoLTEpWzBdIT09ZS5kb2NzLm5hdlN0YWNrLnNsaWNlKC0xKVswXXx8IXRoaXMucHJvcHMuc2NoZW1hJiZlLnNjaGVtYSkmJnRoaXMuc2V0V2lkdGgoZSl9LHQucHJvdG90eXBlLnNldFdpZHRoPWZ1bmN0aW9uKGUpe3ZvaWQgMD09PWUmJihlPXRoaXMucHJvcHMpLHRoaXMucHJvcHMuc2V0V2lkdGgoZSl9LHQucHJvdG90eXBlLmdldFdpZHRoPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXM7cmV0dXJuIHZvaWQgMD09PWUmJihlPXRoaXMucHJvcHMpLFt0aGlzLnN0YXRlLndpZHRoTWFwLnJvb3R8fGQuY29sdW1uV2lkdGhdLmNvbmNhdChlLmRvY3MubmF2U3RhY2subWFwKGZ1bmN0aW9uKGUpe3JldHVybiB0LnN0YXRlLndpZHRoTWFwW2UuZmllbGQucGF0aF18fGQuY29sdW1uV2lkdGh9KSkucmVkdWNlKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIGUrdH0sMCl9LHQucHJvdG90eXBlLmNvbXBvbmVudERpZE1vdW50PWZ1bmN0aW9uKCl7dGhpcy5zZXRXaWR0aCgpfSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgZSx0PXRoaXMsbj10aGlzLnByb3BzLmRvY3MubmF2U3RhY2sscj10aGlzLnByb3BzLnNjaGVtYTtyZXR1cm4gdm9pZCAwPT09cj9lPW8uY3JlYXRlRWxlbWVudChmLmRlZmF1bHQsbnVsbCk6bnVsbD09PXImJihlPW8uY3JlYXRlRWxlbWVudChiLkVycm9yQ29udGFpbmVyLG51bGwsIk5vIFNjaGVtYSBBdmFpbGFibGUiKSksby5jcmVhdGVFbGVtZW50KFMse29uS2V5RG93bjp0aGlzLmhhbmRsZUtleURvd24sdGFiSW5kZXg6MCxyZWY6dGhpcy5zZXRSZWZ9LGUmJm8uY3JlYXRlRWxlbWVudChsLmRlZmF1bHQsbnVsbCxlKSwhZSYmciYmby5jcmVhdGVFbGVtZW50KGguZGVmYXVsdCx7c2NoZW1hOnIsd2lkdGg6dGhpcy5zdGF0ZS53aWR0aE1hcC5yb290fHxkLmNvbHVtbldpZHRoLTEsc2VhcmNoVmFsdWU6dGhpcy5zdGF0ZS5zZWFyY2hWYWx1ZSxoYW5kbGVTZWFyY2g6dGhpcy5oYW5kbGVTZWFyY2gsc2Vzc2lvbklkOnRoaXMucHJvcHMuc2Vzc2lvbklkfSksbi5tYXAoZnVuY3Rpb24oZSxuKXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGwuZGVmYXVsdCx7a2V5Om4sd2lkdGg6dC5zdGF0ZS53aWR0aE1hcFtlLmZpZWxkLnBhdGhdfHxkLmNvbHVtbldpZHRofSxvLmNyZWF0ZUVsZW1lbnQoYy5kZWZhdWx0LHtzY2hlbWE6cixmaWVsZDplLmZpZWxkLGxldmVsOm4rMSxzZXNzaW9uSWQ6dC5wcm9wcy5zZXNzaW9uSWR9KSl9KSl9LHR9KG8uQ29tcG9uZW50KSxFPWZ1bmN0aW9uKGUpe3JldHVybiBhLmJpbmRBY3Rpb25DcmVhdG9ycyh7YWRkU3RhY2s6cC5hZGRTdGFjayx0b2dnbGVEb2NzOnAudG9nZ2xlRG9jcyxjaGFuZ2VXaWR0aERvY3M6cC5jaGFuZ2VXaWR0aERvY3MsY2hhbmdlS2V5TW92ZTpwLmNoYW5nZUtleU1vdmUsc2V0RG9jc1Zpc2libGU6cC5zZXREb2NzVmlzaWJsZX0sZSl9LEQ9di5jcmVhdGVTdHJ1Y3R1cmVkU2VsZWN0b3Ioe2RvY3M6Zy5nZXRTZXNzaW9uRG9jcyxzZXNzaW9uSWQ6eS5nZXRTZWxlY3RlZFNlc3Npb25JZEZyb21Sb290fSk7dC5kZWZhdWx0PXMuY29ubmVjdChELEUsbnVsbCx7d2l0aFJlZjohMH0pKEMpO3ZhciB3LFM9eC5zdHlsZWQuZGl2KHd8fCh3PWkoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBoZWlnaHQ6IDEwMCU7XG4gIHdpZHRoOiAxMDAlO1xuICBvdmVyZmxvdy14OiBhdXRvO1xuICBvdmVyZmxvdy15OiBoaWRkZW47XG4gIG91dGxpbmU6IG5vbmUgIWltcG9ydGFudDtcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgaGVpZ2h0OiAxMDAlO1xuICB3aWR0aDogMTAwJTtcbiAgb3ZlcmZsb3cteDogYXV0bztcbiAgb3ZlcmZsb3cteTogaGlkZGVuO1xuICBvdXRsaW5lOiBub25lICFpbXBvcnRhbnQ7XG4iXSkpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPW4oNjQyKSxzPW4oNyksdT1uKDY0NCksYz1uKDUxKSxsPW4oNjkyKSxwPW4oNjkzKSxmPW4oNjk0KSxkPW4oNjk1KSxoPW4oNjYpLG09bigyOTgpLGc9bigxKSx5PWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXt2YXIgdD1udWxsIT09ZSYmZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fHRoaXM7cmV0dXJuIHQuc3RhdGU9e3Nob3dEZXByZWNhdGVkOiExfSx0LnNldFJlZj1mdW5jdGlvbihlKXt0LnJlZj1lfSx0fXJldHVybiByKHQsZSksdC5wcm90b3R5cGUuY29tcG9uZW50RGlkTW91bnQ9ZnVuY3Rpb24oKXt0aGlzLnNjcm9sbFRvUmlnaHQoKX0sdC5wcm90b3R5cGUuc2hvdWxkQ29tcG9uZW50VXBkYXRlPWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLnByb3BzLmZpZWxkIT09ZS5maWVsZCYmKHRoaXMuc2Nyb2xsVG9SaWdodCgpLCEwKX0sdC5wcm90b3R5cGUuc2Nyb2xsVG9SaWdodD1mdW5jdGlvbigpe3ZhciBlPXRoaXMucmVmLHQ9ZS5wYXJlbnROb2RlJiZlLnBhcmVudE5vZGUucGFyZW50Tm9kZTt4KHQsdC5zY3JvbGxXaWR0aCw1MCl9LHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMsdD10aGlzLnByb3BzLG49dC5zY2hlbWEscj10LmZpZWxkLGk9dC5sZXZlbCx1PXIudHlwZXx8cixnPWguc2VyaWFsaXplKG4scik7dT1oLmdldERlZXBlclR5cGUodSk7dmFyIHksdj1nLmZpZWxkcy5sZW5ndGgrZy5pbnRlcmZhY2VzLmxlbmd0aCxiPWcuZmllbGRzLmxlbmd0aCtnLmludGVyZmFjZXMubGVuZ3RoK2cuYXJncy5sZW5ndGg7cmV0dXJuIHk9dSBpbnN0YW5jZW9mIHMuR3JhcGhRTEludGVyZmFjZVR5cGU/ImludGVyZmFjZSI6dSBpbnN0YW5jZW9mIHMuR3JhcGhRTFVuaW9uVHlwZT8idW5pb24iOnUgaW5zdGFuY2VvZiBzLkdyYXBoUUxFbnVtVHlwZT8iZW51bSI6InR5cGUiLG8uY3JlYXRlRWxlbWVudCgiZGl2Iix7cmVmOnRoaXMuc2V0UmVmfSxvLmNyZWF0ZUVsZW1lbnQoQyxudWxsLG8uY3JlYXRlRWxlbWVudChjLmRlZmF1bHQse3R5cGU6cix4OmkseTotMSxjbGlja2FibGU6ITEsbGFzdEFjdGl2ZTohMX0pKSxvLmNyZWF0ZUVsZW1lbnQoRSx7Y2xhc3NOYW1lOiJkb2MtdHlwZS1kZXNjcmlwdGlvbiIsbWFya2Rvd246ci5kZXNjcmlwdGlvbnx8IiJ9KSxvLmNyZWF0ZUVsZW1lbnQobS5DYXRlZ29yeVRpdGxlLG51bGwseSsiIGRldGFpbHMiKSx1LmRlc2NyaXB0aW9uJiZ1LmRlc2NyaXB0aW9uLmxlbmd0aD4wJiZvLmNyZWF0ZUVsZW1lbnQoRSx7bWFya2Rvd246dS5kZXNjcmlwdGlvbnx8IiJ9KSx1IGluc3RhbmNlb2Ygcy5HcmFwaFFMU2NhbGFyVHlwZSYmby5jcmVhdGVFbGVtZW50KHAuZGVmYXVsdCx7dHlwZTp1fSksdSBpbnN0YW5jZW9mIHMuR3JhcGhRTEVudW1UeXBlJiZvLmNyZWF0ZUVsZW1lbnQoZi5kZWZhdWx0LHt0eXBlOnV9KSx1IGluc3RhbmNlb2Ygcy5HcmFwaFFMVW5pb25UeXBlJiZvLmNyZWF0ZUVsZW1lbnQoZC5kZWZhdWx0LHt0eXBlOnUsc2NoZW1hOm4sbGV2ZWw6aSxzZXNzaW9uSWQ6dGhpcy5wcm9wcy5zZXNzaW9uSWR9KSxnLmZpZWxkcyYmZy5maWVsZHMubGVuZ3RoPjAmJm8uY3JlYXRlRWxlbWVudChsLmRlZmF1bHQse3R5cGU6dSxmaWVsZHM6Zy5maWVsZHMsaW50ZXJmYWNlczpnLmludGVyZmFjZXMsbGV2ZWw6aSxzZXNzaW9uSWQ6dGhpcy5wcm9wcy5zZXNzaW9uSWR9KSxnLmFyZ3MmJmcuYXJncy5sZW5ndGg+MCYmby5jcmVhdGVFbGVtZW50KCJkaXYiLG51bGwsby5jcmVhdGVFbGVtZW50KG0uQ2F0ZWdvcnlUaXRsZSxudWxsLCJhcmd1bWVudHMiKSxnLmFyZ3MubWFwKGZ1bmN0aW9uKHQsbil7cmV0dXJuIG8uY3JlYXRlRWxlbWVudCgiZGl2Iix7a2V5OnQubmFtZX0sby5jcmVhdGVFbGVtZW50KCJkaXYiLG51bGwsby5jcmVhdGVFbGVtZW50KGEuZGVmYXVsdCx7YXJnOnQseDppLHk6bit2LHNlc3Npb25JZDplLnByb3BzLnNlc3Npb25JZH0pKSl9KSksZy5pbXBsZW1lbnRhdGlvbnMmJmcuaW1wbGVtZW50YXRpb25zLmxlbmd0aD4wJiZvLmNyZWF0ZUVsZW1lbnQoImRpdiIsbnVsbCxvLmNyZWF0ZUVsZW1lbnQobS5DYXRlZ29yeVRpdGxlLG51bGwsImltcGxlbWVudGF0aW9ucyIpLGcuaW1wbGVtZW50YXRpb25zLm1hcChmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoYy5kZWZhdWx0LHtrZXk6ZS5uYW1lLHR5cGU6ZSx4OmkseTp0K2IsY29sbGFwc2FibGU6ITAsbGFzdEFjdGl2ZTohMX0pfSkpKX0sdH0oby5Db21wb25lbnQpO3QuZGVmYXVsdD15O3ZhciB2LGIseD1mdW5jdGlvbiBlKHQsbixyKXtpZighKHI8PTApKXt2YXIgaT1uLXQuc2Nyb2xsTGVmdCxvPWkvcioxMDtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dC5zY3JvbGxMZWZ0PXQuc2Nyb2xsTGVmdCtvLHQuc2Nyb2xsTGVmdCE9PW4mJmUodCxuLHItMTApfSwxMCl9fSxDPWcuc3R5bGVkLmRpdih2fHwodj1pKFsiXG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgcGFkZGluZy10b3A6IDIwcHg7XG4gIHBhZGRpbmctYm90dG9tOiAxMHB4O1xuXG4gIC5kb2MtY2F0ZWdvcnktaXRlbSB7XG4gICAgZm9udC1zaXplOiAxNHB4O1xuICAgIGZvbnQtd2VpZ2h0OiA2MDA7XG4gICAgd29yZC13cmFwOiBicmVhay13b3JkO1xuICB9XG4gIC5kb2MtY2F0ZWdvcnktaXRlbSAuZmllbGQtbmFtZSB7XG4gICAgY29sb3I6ICNmMjVjNTQ7XG4gIH1cbiAgZGl2IHtcbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgICBwb2ludGVyLWV2ZW50czogbm9uZTtcbiAgfVxuIl0sWyJcbiAgYmFja2dyb3VuZDogIiwiO1xuICBwYWRkaW5nLXRvcDogMjBweDtcbiAgcGFkZGluZy1ib3R0b206IDEwcHg7XG5cbiAgLmRvYy1jYXRlZ29yeS1pdGVtIHtcbiAgICBmb250LXNpemU6IDE0cHg7XG4gICAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgICB3b3JkLXdyYXA6IGJyZWFrLXdvcmQ7XG4gIH1cbiAgLmRvYy1jYXRlZ29yeS1pdGVtIC5maWVsZC1uYW1lIHtcbiAgICBjb2xvcjogI2YyNWM1NDtcbiAgfVxuICBkaXYge1xuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xuICAgIHBvaW50ZXItZXZlbnRzOiBub25lO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMuYmxhY2swMn0pLEU9Zy5zdHlsZWQodS5kZWZhdWx0KShifHwoYj1pKFsiXG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgcGFkZGluZzogMCAxNnB4IDIwcHggMTZweDtcbiAgY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTtcbiJdLFsiXG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgcGFkZGluZzogMCAxNnB4IDIwcHggMTZweDtcbiAgY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTtcbiJdKSkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dmFyIHQ9ZS5hcmcsbj1lLnNob3dEZWZhdWx0VmFsdWUscj1lLngscz1lLnk7cmV0dXJuIGkuY3JlYXRlRWxlbWVudCgic3BhbiIsbnVsbCxpLmNyZWF0ZUVsZW1lbnQoYS5kZWZhdWx0LHt0eXBlOnQseDpyLHk6cyxsYXN0QWN0aXZlOiExLGFmdGVyTm9kZTp2b2lkIDAhPT10LmRlZmF1bHRWYWx1ZSYmITEhPT1uJiZpLmNyZWF0ZUVsZW1lbnQoInNwYW4iLG51bGwsIiA9ICIsaS5jcmVhdGVFbGVtZW50KCJzcGFuIix7Y2xhc3NOYW1lOiJhcmctZGVmYXVsdC12YWx1ZSJ9LG8ucHJpbnQoby5hc3RGcm9tVmFsdWUodC5kZWZhdWx0VmFsdWUsdC50eXBlKSkpKX0pKX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigwKSxvPW4oNyksYT1uKDUxKTt0LmRlZmF1bHQ9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PWUuYXJnLG49ZS5zaG93RGVmYXVsdFZhbHVlO3JldHVybiBhLmNyZWF0ZUVsZW1lbnQobCxudWxsLGEuY3JlYXRlRWxlbWVudCgic3BhbiIse2NsYXNzTmFtZToiYXJnLW5hbWUifSx0Lm5hbWUpLCI6ICIsYS5jcmVhdGVFbGVtZW50KCJzcGFuIix7Y2xhc3NOYW1lOiJ0eXBlLW5hbWUifSxpKHQudHlwZSkpLHZvaWQgMCE9PXQuZGVmYXVsdFZhbHVlJiYhMSE9PW4mJmEuY3JlYXRlRWxlbWVudCgic3BhbiIsbnVsbCwiID0gIixhLmNyZWF0ZUVsZW1lbnQoInNwYW4iLHtjbGFzc05hbWU6ImFyZy1kZWZhdWx0LXZhbHVlIn0scy5wcmludChzLmFzdEZyb21WYWx1ZSh0LmRlZmF1bHRWYWx1ZSx0LnR5cGUpKSkpKX1mdW5jdGlvbiBpKGUpe3JldHVybiBlIGluc3RhbmNlb2Ygcy5HcmFwaFFMTm9uTnVsbD9hLmNyZWF0ZUVsZW1lbnQoInNwYW4iLG51bGwsaShlLm9mVHlwZSksIiEiKTplIGluc3RhbmNlb2Ygcy5HcmFwaFFMTGlzdD9hLmNyZWF0ZUVsZW1lbnQoInNwYW4iLG51bGwsIlsiLGkoZS5vZlR5cGUpLCJdIik6YS5jcmVhdGVFbGVtZW50KCJzcGFuIixudWxsLGUubmFtZSl9dmFyIG89ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGE9bigwKSxzPW4oNyksdT1uKDEpO3QuZGVmYXVsdD1yO3ZhciBjLGw9dS5zdHlsZWQuZGl2KGN8fChjPW8oWyJcbiAgbWFyZ2luLWxlZnQ6IDE2cHg7XG4iXSxbIlxuICBtYXJnaW4tbGVmdDogMTZweDtcbiJdKSkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSx0KXtpZighKGUgaW5zdGFuY2VvZiB0KSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBvKGUsdCl7aWYoIWUpdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKCJ0aGlzIGhhc24ndCBiZWVuIGluaXRpYWxpc2VkIC0gc3VwZXIoKSBoYXNuJ3QgYmVlbiBjYWxsZWQiKTtyZXR1cm4hdHx8Im9iamVjdCIhPT10eXBlb2YgdCYmImZ1bmN0aW9uIiE9PXR5cGVvZiB0P2U6dH1mdW5jdGlvbiBhKGUsdCl7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0JiZudWxsIT09dCl0aHJvdyBuZXcgVHlwZUVycm9yKCJTdXBlciBleHByZXNzaW9uIG11c3QgZWl0aGVyIGJlIG51bGwgb3IgYSBmdW5jdGlvbiwgbm90ICIrdHlwZW9mIHQpO2UucHJvdG90eXBlPU9iamVjdC5jcmVhdGUodCYmdC5wcm90b3R5cGUse2NvbnN0cnVjdG9yOnt2YWx1ZTplLGVudW1lcmFibGU6ITEsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfX0pLHQmJihPYmplY3Quc2V0UHJvdG90eXBlT2Y/T2JqZWN0LnNldFByb3RvdHlwZU9mKGUsdCk6ZS5fX3Byb3RvX189dCl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBzPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe2Zvcih2YXIgbj0wO248dC5sZW5ndGg7bisrKXt2YXIgcj10W25dO3IuZW51bWVyYWJsZT1yLmVudW1lcmFibGV8fCExLHIuY29uZmlndXJhYmxlPSEwLCJ2YWx1ZSJpbiByJiYoci53cml0YWJsZT0hMCksT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsci5rZXkscil9fXJldHVybiBmdW5jdGlvbih0LG4scil7cmV0dXJuIG4mJmUodC5wcm90b3R5cGUsbiksciYmZSh0LHIpLHR9fSgpLHU9bigwKSxjPXIodSksbD1uKDE4KSxwPXIobCksZj1uKDY0NSksZD1yKGYpLGg9bmV3IGQuZGVmYXVsdCxtPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gaSh0aGlzLHQpLG8odGhpcywodC5fX3Byb3RvX198fE9iamVjdC5nZXRQcm90b3R5cGVPZih0KSkuYXBwbHkodGhpcyxhcmd1bWVudHMpKX1yZXR1cm4gYSh0LGUpLHModCxbe2tleToic2hvdWxkQ29tcG9uZW50VXBkYXRlIix2YWx1ZTpmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5wcm9wcy5tYXJrZG93biE9PWUubWFya2Rvd259fSx7a2V5OiJyZW5kZXIiLHZhbHVlOmZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcy5tYXJrZG93bjtyZXR1cm4gZT9jLmRlZmF1bHQuY3JlYXRlRWxlbWVudCgiZGl2Iix7Y2xhc3NOYW1lOnRoaXMucHJvcHMuY2xhc3NOYW1lLGRhbmdlcm91c2x5U2V0SW5uZXJIVE1MOntfX2h0bWw6aC5yZW5kZXIoZSl9fSk6Yy5kZWZhdWx0LmNyZWF0ZUVsZW1lbnQoImRpdiIsbnVsbCl9fV0pLHR9KGMuZGVmYXVsdC5Db21wb25lbnQpO20ucHJvcFR5cGVzPXttYXJrZG93bjpwLmRlZmF1bHQuc3RyaW5nLGNsYXNzTmFtZTpwLmRlZmF1bHQuc3RyaW5nfSx0LmRlZmF1bHQ9bX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9big2NDYpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dmFyIHQ9ZS50cmltKCkudG9Mb3dlckNhc2UoKTtyZXR1cm4heS50ZXN0KHQpfHwhIXYudGVzdCh0KX1mdW5jdGlvbiBpKGUpe3ZhciB0PWgucGFyc2UoZSwhMCk7aWYodC5ob3N0bmFtZSYmKCF0LnByb3RvY29sfHxiLmluZGV4T2YodC5wcm90b2NvbCk+PTApKXRyeXt0Lmhvc3RuYW1lPW0udG9BU0NJSSh0Lmhvc3RuYW1lKX1jYXRjaChlKXt9cmV0dXJuIGguZW5jb2RlKGguZm9ybWF0KHQpKX1mdW5jdGlvbiBvKGUpe3ZhciB0PWgucGFyc2UoZSwhMCk7aWYodC5ob3N0bmFtZSYmKCF0LnByb3RvY29sfHxiLmluZGV4T2YodC5wcm90b2NvbCk+PTApKXRyeXt0Lmhvc3RuYW1lPW0udG9Vbmljb2RlKHQuaG9zdG5hbWUpfWNhdGNoKGUpe31yZXR1cm4gaC5kZWNvZGUoaC5mb3JtYXQodCkpfWZ1bmN0aW9uIGEoZSx0KXtpZighKHRoaXMgaW5zdGFuY2VvZiBhKSlyZXR1cm4gbmV3IGEoZSx0KTt0fHxzLmlzU3RyaW5nKGUpfHwodD1lfHx7fSxlPSJkZWZhdWx0IiksdGhpcy5pbmxpbmU9bmV3IGYsdGhpcy5ibG9jaz1uZXcgcCx0aGlzLmNvcmU9bmV3IGwsdGhpcy5yZW5kZXJlcj1uZXcgYyx0aGlzLmxpbmtpZnk9bmV3IGQsdGhpcy52YWxpZGF0ZUxpbms9cix0aGlzLm5vcm1hbGl6ZUxpbms9aSx0aGlzLm5vcm1hbGl6ZUxpbmtUZXh0PW8sdGhpcy51dGlscz1zLHRoaXMuaGVscGVycz1zLmFzc2lnbih7fSx1KSx0aGlzLm9wdGlvbnM9e30sdGhpcy5jb25maWd1cmUoZSksdCYmdGhpcy5zZXQodCl9dmFyIHM9big1KSx1PW4oNjQ5KSxjPW4oNjUzKSxsPW4oNjU0KSxwPW4oNjYyKSxmPW4oNjc2KSxkPW4oMjY3KSxoPW4oODgpLG09bigyNzEpLGc9e2RlZmF1bHQ6big2ODkpLHplcm86big2OTApLGNvbW1vbm1hcms6big2OTEpfSx5PS9eKHZic2NyaXB0fGphdmFzY3JpcHR8ZmlsZXxkYXRhKTovLHY9L15kYXRhOmltYWdlXC8oZ2lmfHBuZ3xqcGVnfHdlYnApOy8sYj1bImh0dHA6IiwiaHR0cHM6IiwibWFpbHRvOiJdO2EucHJvdG90eXBlLnNldD1mdW5jdGlvbihlKXtyZXR1cm4gcy5hc3NpZ24odGhpcy5vcHRpb25zLGUpLHRoaXN9LGEucHJvdG90eXBlLmNvbmZpZ3VyZT1mdW5jdGlvbihlKXt2YXIgdCxuPXRoaXM7aWYocy5pc1N0cmluZyhlKSYmKHQ9ZSwhKGU9Z1t0XSkpKXRocm93IG5ldyBFcnJvcignV3JvbmcgYG1hcmtkb3duLWl0YCBwcmVzZXQgIicrdCsnIiwgY2hlY2sgbmFtZScpO2lmKCFlKXRocm93IG5ldyBFcnJvcigiV3JvbmcgYG1hcmtkb3duLWl0YCBwcmVzZXQsIGNhbid0IGJlIGVtcHR5Iik7cmV0dXJuIGUub3B0aW9ucyYmbi5zZXQoZS5vcHRpb25zKSxlLmNvbXBvbmVudHMmJk9iamVjdC5rZXlzKGUuY29tcG9uZW50cykuZm9yRWFjaChmdW5jdGlvbih0KXtlLmNvbXBvbmVudHNbdF0ucnVsZXMmJm5bdF0ucnVsZXIuZW5hYmxlT25seShlLmNvbXBvbmVudHNbdF0ucnVsZXMpLGUuY29tcG9uZW50c1t0XS5ydWxlczImJm5bdF0ucnVsZXIyLmVuYWJsZU9ubHkoZS5jb21wb25lbnRzW3RdLnJ1bGVzMil9KSx0aGlzfSxhLnByb3RvdHlwZS5lbmFibGU9ZnVuY3Rpb24oZSx0KXt2YXIgbj1bXTtBcnJheS5pc0FycmF5KGUpfHwoZT1bZV0pLFsiY29yZSIsImJsb2NrIiwiaW5saW5lIl0uZm9yRWFjaChmdW5jdGlvbih0KXtuPW4uY29uY2F0KHRoaXNbdF0ucnVsZXIuZW5hYmxlKGUsITApKX0sdGhpcyksbj1uLmNvbmNhdCh0aGlzLmlubGluZS5ydWxlcjIuZW5hYmxlKGUsITApKTt2YXIgcj1lLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gbi5pbmRleE9mKGUpPDB9KTtpZihyLmxlbmd0aCYmIXQpdGhyb3cgbmV3IEVycm9yKCJNYXJrZG93bkl0LiBGYWlsZWQgdG8gZW5hYmxlIHVua25vd24gcnVsZShzKTogIityKTtyZXR1cm4gdGhpc30sYS5wcm90b3R5cGUuZGlzYWJsZT1mdW5jdGlvbihlLHQpe3ZhciBuPVtdO0FycmF5LmlzQXJyYXkoZSl8fChlPVtlXSksWyJjb3JlIiwiYmxvY2siLCJpbmxpbmUiXS5mb3JFYWNoKGZ1bmN0aW9uKHQpe249bi5jb25jYXQodGhpc1t0XS5ydWxlci5kaXNhYmxlKGUsITApKX0sdGhpcyksbj1uLmNvbmNhdCh0aGlzLmlubGluZS5ydWxlcjIuZGlzYWJsZShlLCEwKSk7dmFyIHI9ZS5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIG4uaW5kZXhPZihlKTwwfSk7aWYoci5sZW5ndGgmJiF0KXRocm93IG5ldyBFcnJvcigiTWFya2Rvd25JdC4gRmFpbGVkIHRvIGRpc2FibGUgdW5rbm93biBydWxlKHMpOiAiK3IpO3JldHVybiB0aGlzfSxhLnByb3RvdHlwZS51c2U9ZnVuY3Rpb24oZSl7dmFyIHQ9W3RoaXNdLmNvbmNhdChBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMSkpO3JldHVybiBlLmFwcGx5KGUsdCksdGhpc30sYS5wcm90b3R5cGUucGFyc2U9ZnVuY3Rpb24oZSx0KXtpZigic3RyaW5nIiE9PXR5cGVvZiBlKXRocm93IG5ldyBFcnJvcigiSW5wdXQgZGF0YSBzaG91bGQgYmUgYSBTdHJpbmciKTt2YXIgbj1uZXcgdGhpcy5jb3JlLlN0YXRlKGUsdGhpcyx0KTtyZXR1cm4gdGhpcy5jb3JlLnByb2Nlc3Mobiksbi50b2tlbnN9LGEucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbihlLHQpe3JldHVybiB0PXR8fHt9LHRoaXMucmVuZGVyZXIucmVuZGVyKHRoaXMucGFyc2UoZSx0KSx0aGlzLm9wdGlvbnMsdCl9LGEucHJvdG90eXBlLnBhcnNlSW5saW5lPWZ1bmN0aW9uKGUsdCl7dmFyIG49bmV3IHRoaXMuY29yZS5TdGF0ZShlLHRoaXMsdCk7cmV0dXJuIG4uaW5saW5lTW9kZT0hMCx0aGlzLmNvcmUucHJvY2VzcyhuKSxuLnRva2Vuc30sYS5wcm90b3R5cGUucmVuZGVySW5saW5lPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQ9dHx8e30sdGhpcy5yZW5kZXJlci5yZW5kZXIodGhpcy5wYXJzZUlubGluZShlLHQpLHRoaXMub3B0aW9ucyx0KX0sZS5leHBvcnRzPWF9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dC5Bbnk9bigyNjgpLHQuQ2M9bigyNjkpLHQuQ2Y9big2NDgpLHQuUD1uKDEzNiksdC5aPW4oMjcwKX0sZnVuY3Rpb24oZSx0KXtlLmV4cG9ydHM9L1tceEFEXHUwNjAwLVx1MDYwNVx1MDYxQ1x1MDZERFx1MDcwRlx1MDhFMlx1MTgwRVx1MjAwQi1cdTIwMEZcdTIwMkEtXHUyMDJFXHUyMDYwLVx1MjA2NFx1MjA2Ni1cdTIwNkZcdUZFRkZcdUZGRjktXHVGRkZCXXxcdUQ4MDRcdURDQkR8XHVEODJGW1x1RENBMC1cdURDQTNdfFx1RDgzNFtcdURENzMtXHVERDdBXXxcdURCNDBbXHVEQzAxXHVEQzIwLVx1REM3Rl0vfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3QucGFyc2VMaW5rTGFiZWw9big2NTApLHQucGFyc2VMaW5rRGVzdGluYXRpb249big2NTEpLHQucGFyc2VMaW5rVGl0bGU9big2NTIpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbil7dmFyIHIsaSxvLGEscz0tMSx1PWUucG9zTWF4LGM9ZS5wb3M7Zm9yKGUucG9zPXQrMSxyPTE7ZS5wb3M8dTspe2lmKDkzPT09KG89ZS5zcmMuY2hhckNvZGVBdChlLnBvcykpJiYwPT09LS1yKXtpPSEwO2JyZWFrfWlmKGE9ZS5wb3MsZS5tZC5pbmxpbmUuc2tpcFRva2VuKGUpLDkxPT09bylpZihhPT09ZS5wb3MtMSlyKys7ZWxzZSBpZihuKXJldHVybiBlLnBvcz1jLC0xfXJldHVybiBpJiYocz1lLnBvcyksZS5wb3M9YyxzfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDUpLmlzU3BhY2UsaT1uKDUpLnVuZXNjYXBlQWxsO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbil7dmFyIG8sYSxzPXQsdT17b2s6ITEscG9zOjAsbGluZXM6MCxzdHI6IiJ9O2lmKDYwPT09ZS5jaGFyQ29kZUF0KHQpKXtmb3IodCsrO3Q8bjspe2lmKDEwPT09KG89ZS5jaGFyQ29kZUF0KHQpKXx8cihvKSlyZXR1cm4gdTtpZig2Mj09PW8pcmV0dXJuIHUucG9zPXQrMSx1LnN0cj1pKGUuc2xpY2UocysxLHQpKSx1Lm9rPSEwLHU7OTI9PT1vJiZ0KzE8bj90Kz0yOnQrK31yZXR1cm4gdX1mb3IoYT0wO3Q8biYmMzIhPT0obz1lLmNoYXJDb2RlQXQodCkpJiYhKG88MzJ8fDEyNz09PW8pOylpZig5Mj09PW8mJnQrMTxuKXQrPTI7ZWxzZXtpZig0MD09PW8mJmErKyw0MT09PW8pe2lmKDA9PT1hKWJyZWFrO2EtLX10Kyt9cmV0dXJuIHM9PT10P3U6MCE9PWE/dToodS5zdHI9aShlLnNsaWNlKHMsdCkpLHUubGluZXM9MCx1LnBvcz10LHUub2s9ITAsdSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNSkudW5lc2NhcGVBbGw7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCxuKXt2YXIgaSxvLGE9MCxzPXQsdT17b2s6ITEscG9zOjAsbGluZXM6MCxzdHI6IiJ9O2lmKHQ+PW4pcmV0dXJuIHU7aWYoMzQhPT0obz1lLmNoYXJDb2RlQXQodCkpJiYzOSE9PW8mJjQwIT09bylyZXR1cm4gdTtmb3IodCsrLDQwPT09byYmKG89NDEpO3Q8bjspe2lmKChpPWUuY2hhckNvZGVBdCh0KSk9PT1vKXJldHVybiB1LnBvcz10KzEsdS5saW5lcz1hLHUuc3RyPXIoZS5zbGljZShzKzEsdCkpLHUub2s9ITAsdTsxMD09PWk/YSsrOjkyPT09aSYmdCsxPG4mJih0KyssMTA9PT1lLmNoYXJDb2RlQXQodCkmJmErKyksdCsrfXJldHVybiB1fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKCl7dGhpcy5ydWxlcz1pKHt9LHMpfXZhciBpPW4oNSkuYXNzaWduLG89big1KS51bmVzY2FwZUFsbCxhPW4oNSkuZXNjYXBlSHRtbCxzPXt9O3MuY29kZV9pbmxpbmU9ZnVuY3Rpb24oZSx0LG4scixpKXt2YXIgbz1lW3RdO3JldHVybiI8Y29kZSIraS5yZW5kZXJBdHRycyhvKSsiPiIrYShlW3RdLmNvbnRlbnQpKyI8L2NvZGU+In0scy5jb2RlX2Jsb2NrPWZ1bmN0aW9uKGUsdCxuLHIsaSl7dmFyIG89ZVt0XTtyZXR1cm4iPHByZSIraS5yZW5kZXJBdHRycyhvKSsiPjxjb2RlPiIrYShlW3RdLmNvbnRlbnQpKyI8L2NvZGU+PC9wcmU+XG4ifSxzLmZlbmNlPWZ1bmN0aW9uKGUsdCxuLHIsaSl7dmFyIHMsdSxjLGwscD1lW3RdLGY9cC5pbmZvP28ocC5pbmZvKS50cmltKCk6IiIsZD0iIjtyZXR1cm4gZiYmKGQ9Zi5zcGxpdCgvXHMrL2cpWzBdKSxzPW4uaGlnaGxpZ2h0P24uaGlnaGxpZ2h0KHAuY29udGVudCxkKXx8YShwLmNvbnRlbnQpOmEocC5jb250ZW50KSwwPT09cy5pbmRleE9mKCI8cHJlIik/cysiXG4iOmY/KHU9cC5hdHRySW5kZXgoImNsYXNzIiksYz1wLmF0dHJzP3AuYXR0cnMuc2xpY2UoKTpbXSx1PDA/Yy5wdXNoKFsiY2xhc3MiLG4ubGFuZ1ByZWZpeCtkXSk6Y1t1XVsxXSs9IiAiK24ubGFuZ1ByZWZpeCtkLGw9e2F0dHJzOmN9LCI8cHJlPjxjb2RlIitpLnJlbmRlckF0dHJzKGwpKyI+IitzKyI8L2NvZGU+PC9wcmU+XG4iKToiPHByZT48Y29kZSIraS5yZW5kZXJBdHRycyhwKSsiPiIrcysiPC9jb2RlPjwvcHJlPlxuIn0scy5pbWFnZT1mdW5jdGlvbihlLHQsbixyLGkpe3ZhciBvPWVbdF07cmV0dXJuIG8uYXR0cnNbby5hdHRySW5kZXgoImFsdCIpXVsxXT1pLnJlbmRlcklubGluZUFzVGV4dChvLmNoaWxkcmVuLG4sciksaS5yZW5kZXJUb2tlbihlLHQsbil9LHMuaGFyZGJyZWFrPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gbi54aHRtbE91dD8iPGJyIC8+XG4iOiI8YnI+XG4ifSxzLnNvZnRicmVhaz1mdW5jdGlvbihlLHQsbil7cmV0dXJuIG4uYnJlYWtzP24ueGh0bWxPdXQ/IjxiciAvPlxuIjoiPGJyPlxuIjoiXG4ifSxzLnRleHQ9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gYShlW3RdLmNvbnRlbnQpfSxzLmh0bWxfYmxvY2s9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZVt0XS5jb250ZW50fSxzLmh0bWxfaW5saW5lPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIGVbdF0uY29udGVudH0sci5wcm90b3R5cGUucmVuZGVyQXR0cnM9ZnVuY3Rpb24oZSl7dmFyIHQsbixyO2lmKCFlLmF0dHJzKXJldHVybiIiO2ZvcihyPSIiLHQ9MCxuPWUuYXR0cnMubGVuZ3RoO3Q8bjt0Kyspcis9IiAiK2EoZS5hdHRyc1t0XVswXSkrJz0iJythKGUuYXR0cnNbdF1bMV0pKyciJztyZXR1cm4gcn0sci5wcm90b3R5cGUucmVuZGVyVG9rZW49ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGk9IiIsbz0hMSxhPWVbdF07cmV0dXJuIGEuaGlkZGVuPyIiOihhLmJsb2NrJiYtMSE9PWEubmVzdGluZyYmdCYmZVt0LTFdLmhpZGRlbiYmKGkrPSJcbiIpLGkrPSgtMT09PWEubmVzdGluZz8iPC8iOiI8IikrYS50YWcsaSs9dGhpcy5yZW5kZXJBdHRycyhhKSwwPT09YS5uZXN0aW5nJiZuLnhodG1sT3V0JiYoaSs9IiAvIiksYS5ibG9jayYmKG89ITAsMT09PWEubmVzdGluZyYmdCsxPGUubGVuZ3RoJiYocj1lW3QrMV0sImlubGluZSI9PT1yLnR5cGV8fHIuaGlkZGVuP289ITE6LTE9PT1yLm5lc3RpbmcmJnIudGFnPT09YS50YWcmJihvPSExKSkpLGkrPW8/Ij5cbiI6Ij4iKX0sci5wcm90b3R5cGUucmVuZGVySW5saW5lPWZ1bmN0aW9uKGUsdCxuKXtmb3IodmFyIHIsaT0iIixvPXRoaXMucnVsZXMsYT0wLHM9ZS5sZW5ndGg7YTxzO2ErKylyPWVbYV0udHlwZSwidW5kZWZpbmVkIiE9PXR5cGVvZiBvW3JdP2krPW9bcl0oZSxhLHQsbix0aGlzKTppKz10aGlzLnJlbmRlclRva2VuKGUsYSx0KTtyZXR1cm4gaX0sci5wcm90b3R5cGUucmVuZGVySW5saW5lQXNUZXh0PWZ1bmN0aW9uKGUsdCxuKXtmb3IodmFyIHI9IiIsaT0wLG89ZS5sZW5ndGg7aTxvO2krKykidGV4dCI9PT1lW2ldLnR5cGU/cis9ZVtpXS5jb250ZW50OiJpbWFnZSI9PT1lW2ldLnR5cGUmJihyKz10aGlzLnJlbmRlcklubGluZUFzVGV4dChlW2ldLmNoaWxkcmVuLHQsbikpO3JldHVybiByfSxyLnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbyxhPSIiLHM9dGhpcy5ydWxlcztmb3Iocj0wLGk9ZS5sZW5ndGg7cjxpO3IrKylvPWVbcl0udHlwZSwiaW5saW5lIj09PW8/YSs9dGhpcy5yZW5kZXJJbmxpbmUoZVtyXS5jaGlsZHJlbix0LG4pOiJ1bmRlZmluZWQiIT09dHlwZW9mIHNbb10/YSs9c1tlW3JdLnR5cGVdKGUscix0LG4sdGhpcyk6YSs9dGhpcy5yZW5kZXJUb2tlbihlLHIsdCxuKTtyZXR1cm4gYX0sZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3RoaXMucnVsZXI9bmV3IGk7Zm9yKHZhciBlPTA7ZTxvLmxlbmd0aDtlKyspdGhpcy5ydWxlci5wdXNoKG9bZV1bMF0sb1tlXVsxXSl9dmFyIGk9bigxNDQpLG89W1sibm9ybWFsaXplIixuKDY1NSldLFsiYmxvY2siLG4oNjU2KV0sWyJpbmxpbmUiLG4oNjU3KV0sWyJsaW5raWZ5IixuKDY1OCldLFsicmVwbGFjZW1lbnRzIixuKDY1OSldLFsic21hcnRxdW90ZXMiLG4oNjYwKV1dO3IucHJvdG90eXBlLnByb2Nlc3M9ZnVuY3Rpb24oZSl7dmFyIHQsbixyO2ZvcihyPXRoaXMucnVsZXIuZ2V0UnVsZXMoIiIpLHQ9MCxuPXIubGVuZ3RoO3Q8bjt0Kyspclt0XShlKX0sci5wcm90b3R5cGUuU3RhdGU9big2NjEpLGUuZXhwb3J0cz1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPS9ccltcblx1MDA4NV0/fFtcdTI0MjRcdTIwMjhcdTAwODVdL2csaT0vXHUwMDAwL2c7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0O3Q9ZS5zcmMucmVwbGFjZShyLCJcbiIpLHQ9dC5yZXBsYWNlKGksIlx1ZmZmZCIpLGUuc3JjPXR9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlKXt2YXIgdDtlLmlubGluZU1vZGU/KHQ9bmV3IGUuVG9rZW4oImlubGluZSIsIiIsMCksdC5jb250ZW50PWUuc3JjLHQubWFwPVswLDFdLHQuY2hpbGRyZW49W10sZS50b2tlbnMucHVzaCh0KSk6ZS5tZC5ibG9jay5wYXJzZShlLnNyYyxlLm1kLGUuZW52LGUudG9rZW5zKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0LG4scixpPWUudG9rZW5zO2ZvcihuPTAscj1pLmxlbmd0aDtuPHI7bisrKXQ9aVtuXSwiaW5saW5lIj09PXQudHlwZSYmZS5tZC5pbmxpbmUucGFyc2UodC5jb250ZW50LGUubWQsZS5lbnYsdC5jaGlsZHJlbil9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuL148YVs+XHNdL2kudGVzdChlKX1mdW5jdGlvbiBpKGUpe3JldHVybi9ePFwvYVxzKj4vaS50ZXN0KGUpfXZhciBvPW4oNSkuYXJyYXlSZXBsYWNlQXQ7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0LG4sYSxzLHUsYyxsLHAsZixkLGgsbSxnLHksdixiLHgsQz1lLnRva2VucztpZihlLm1kLm9wdGlvbnMubGlua2lmeSlmb3Iobj0wLGE9Qy5sZW5ndGg7bjxhO24rKylpZigiaW5saW5lIj09PUNbbl0udHlwZSYmZS5tZC5saW5raWZ5LnByZXRlc3QoQ1tuXS5jb250ZW50KSlmb3Iocz1DW25dLmNoaWxkcmVuLGc9MCx0PXMubGVuZ3RoLTE7dD49MDt0LS0paWYoYz1zW3RdLCJsaW5rX2Nsb3NlIiE9PWMudHlwZSl7aWYoImh0bWxfaW5saW5lIj09PWMudHlwZSYmKHIoYy5jb250ZW50KSYmZz4wJiZnLS0saShjLmNvbnRlbnQpJiZnKyspLCEoZz4wKSYmInRleHQiPT09Yy50eXBlJiZlLm1kLmxpbmtpZnkudGVzdChjLmNvbnRlbnQpKXtmb3IoZj1jLmNvbnRlbnQseD1lLm1kLmxpbmtpZnkubWF0Y2goZiksbD1bXSxtPWMubGV2ZWwsaD0wLHA9MDtwPHgubGVuZ3RoO3ArKyl5PXhbcF0udXJsLHY9ZS5tZC5ub3JtYWxpemVMaW5rKHkpLGUubWQudmFsaWRhdGVMaW5rKHYpJiYoYj14W3BdLnRleHQsYj14W3BdLnNjaGVtYT8ibWFpbHRvOiIhPT14W3BdLnNjaGVtYXx8L15tYWlsdG86L2kudGVzdChiKT9lLm1kLm5vcm1hbGl6ZUxpbmtUZXh0KGIpOmUubWQubm9ybWFsaXplTGlua1RleHQoIm1haWx0bzoiK2IpLnJlcGxhY2UoL15tYWlsdG86LywiIik6ZS5tZC5ub3JtYWxpemVMaW5rVGV4dCgiaHR0cDovLyIrYikucmVwbGFjZSgvXmh0dHA6XC9cLy8sIiIpLGQ9eFtwXS5pbmRleCxkPmgmJih1PW5ldyBlLlRva2VuKCJ0ZXh0IiwiIiwwKSx1LmNvbnRlbnQ9Zi5zbGljZShoLGQpLHUubGV2ZWw9bSxsLnB1c2godSkpLHU9bmV3IGUuVG9rZW4oImxpbmtfb3BlbiIsImEiLDEpLHUuYXR0cnM9W1siaHJlZiIsdl1dLHUubGV2ZWw9bSsrLHUubWFya3VwPSJsaW5raWZ5Iix1LmluZm89ImF1dG8iLGwucHVzaCh1KSx1PW5ldyBlLlRva2VuKCJ0ZXh0IiwiIiwwKSx1LmNvbnRlbnQ9Yix1LmxldmVsPW0sbC5wdXNoKHUpLHU9bmV3IGUuVG9rZW4oImxpbmtfY2xvc2UiLCJhIiwtMSksdS5sZXZlbD0tLW0sdS5tYXJrdXA9ImxpbmtpZnkiLHUuaW5mbz0iYXV0byIsbC5wdXNoKHUpLGg9eFtwXS5sYXN0SW5kZXgpO2g8Zi5sZW5ndGgmJih1PW5ldyBlLlRva2VuKCJ0ZXh0IiwiIiwwKSx1LmNvbnRlbnQ9Zi5zbGljZShoKSx1LmxldmVsPW0sbC5wdXNoKHUpKSxDW25dLmNoaWxkcmVuPXM9byhzLHQsbCl9fWVsc2UgZm9yKHQtLTtzW3RdLmxldmVsIT09Yy5sZXZlbCYmImxpbmtfb3BlbiIhPT1zW3RdLnR5cGU7KXQtLX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3JldHVybiBjW3QudG9Mb3dlckNhc2UoKV19ZnVuY3Rpb24gaShlKXt2YXIgdCxuLGk9MDtmb3IodD1lLmxlbmd0aC0xO3Q+PTA7dC0tKW49ZVt0XSwidGV4dCIhPT1uLnR5cGV8fGl8fChuLmNvbnRlbnQ9bi5jb250ZW50LnJlcGxhY2UodSxyKSksImxpbmtfb3BlbiI9PT1uLnR5cGUmJiJhdXRvIj09PW4uaW5mbyYmaS0tLCJsaW5rX2Nsb3NlIj09PW4udHlwZSYmImF1dG8iPT09bi5pbmZvJiZpKyt9ZnVuY3Rpb24gbyhlKXt2YXIgdCxuLHI9MDtmb3IodD1lLmxlbmd0aC0xO3Q+PTA7dC0tKW49ZVt0XSwidGV4dCIhPT1uLnR5cGV8fHJ8fGEudGVzdChuLmNvbnRlbnQpJiYobi5jb250ZW50PW4uY29udGVudC5yZXBsYWNlKC9cKy0vZywiXHhiMSIpLnJlcGxhY2UoL1wuezIsfS9nLCJcdTIwMjYiKS5yZXBsYWNlKC8oWz8hXSlcdTIwMjYvZywiJDEuLiIpLnJlcGxhY2UoLyhbPyFdKXs0LH0vZywiJDEkMSQxIikucmVwbGFjZSgvLHsyLH0vZywiLCIpLnJlcGxhY2UoLyhefFteLV0pLS0tKFteLV18JCkvZ20sIiQxXHUyMDE0JDIiKS5yZXBsYWNlKC8oXnxccyktLShcc3wkKS9nbSwiJDFcdTIwMTMkMiIpLnJlcGxhY2UoLyhefFteLVxzXSktLShbXi1cc118JCkvZ20sIiQxXHUyMDEzJDIiKSksImxpbmtfb3BlbiI9PT1uLnR5cGUmJiJhdXRvIj09PW4uaW5mbyYmci0tLCJsaW5rX2Nsb3NlIj09PW4udHlwZSYmImF1dG8iPT09bi5pbmZvJiZyKyt9dmFyIGE9L1wrLXxcLlwufFw/XD9cP1w/fCEhISF8LCx8LS0vLHM9L1woKGN8dG18cnxwKVwpL2ksdT0vXCgoY3x0bXxyfHApXCkvZ2ksYz17YzoiXHhhOSIscjoiXHhhZSIscDoiXHhhNyIsdG06Ilx1MjEyMiJ9O2UuZXhwb3J0cz1mdW5jdGlvbihlKXt2YXIgdDtpZihlLm1kLm9wdGlvbnMudHlwb2dyYXBoZXIpZm9yKHQ9ZS50b2tlbnMubGVuZ3RoLTE7dD49MDt0LS0pImlubGluZSI9PT1lLnRva2Vuc1t0XS50eXBlJiYocy50ZXN0KGUudG9rZW5zW3RdLmNvbnRlbnQpJiZpKGUudG9rZW5zW3RdLmNoaWxkcmVuKSxhLnRlc3QoZS50b2tlbnNbdF0uY29udGVudCkmJm8oZS50b2tlbnNbdF0uY2hpbGRyZW4pKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7cmV0dXJuIGUuc3Vic3RyKDAsdCkrbitlLnN1YnN0cih0KzEpfWZ1bmN0aW9uIGkoZSx0KXt2YXIgbixpLHUscCxmLGQsaCxtLGcseSx2LGIseCxDLEUsRCx3LFMsayxBLF87Zm9yKGs9W10sbj0wO248ZS5sZW5ndGg7bisrKXtmb3IoaT1lW25dLGg9ZVtuXS5sZXZlbCx3PWsubGVuZ3RoLTE7dz49MCYmIShrW3ddLmxldmVsPD1oKTt3LS0pO2lmKGsubGVuZ3RoPXcrMSwidGV4dCI9PT1pLnR5cGUpe3U9aS5jb250ZW50LGY9MCxkPXUubGVuZ3RoO2U6Zm9yKDtmPGQmJihjLmxhc3RJbmRleD1mLHA9Yy5leGVjKHUpKTspe2lmKEU9RD0hMCxmPXAuaW5kZXgrMSxTPSInIj09PXBbMF0sZz0zMixwLmluZGV4LTE+PTApZz11LmNoYXJDb2RlQXQocC5pbmRleC0xKTtlbHNlIGZvcih3PW4tMTt3Pj0wO3ctLSlpZigidGV4dCI9PT1lW3ddLnR5cGUpe2c9ZVt3XS5jb250ZW50LmNoYXJDb2RlQXQoZVt3XS5jb250ZW50Lmxlbmd0aC0xKTticmVha31pZih5PTMyLGY8ZCl5PXUuY2hhckNvZGVBdChmKTtlbHNlIGZvcih3PW4rMTt3PGUubGVuZ3RoO3crKylpZigidGV4dCI9PT1lW3ddLnR5cGUpe3k9ZVt3XS5jb250ZW50LmNoYXJDb2RlQXQoMCk7YnJlYWt9aWYodj1zKGcpfHxhKFN0cmluZy5mcm9tQ2hhckNvZGUoZykpLGI9cyh5KXx8YShTdHJpbmcuZnJvbUNoYXJDb2RlKHkpKSx4PW8oZyksQz1vKHkpLEM/RT0hMTpiJiYoeHx8dnx8KEU9ITEpKSx4P0Q9ITE6diYmKEN8fGJ8fChEPSExKSksMzQ9PT15JiYnIic9PT1wWzBdJiZnPj00OCYmZzw9NTcmJihEPUU9ITEpLEUmJkQmJihFPSExLEQ9YiksRXx8RCl7aWYoRClmb3Iodz1rLmxlbmd0aC0xO3c+PTAmJihtPWtbd10sIShrW3ddLmxldmVsPGgpKTt3LS0paWYobS5zaW5nbGU9PT1TJiZrW3ddLmxldmVsPT09aCl7bT1rW3ddLFM/KEE9dC5tZC5vcHRpb25zLnF1b3Rlc1syXSxfPXQubWQub3B0aW9ucy5xdW90ZXNbM10pOihBPXQubWQub3B0aW9ucy5xdW90ZXNbMF0sXz10Lm1kLm9wdGlvbnMucXVvdGVzWzFdKSxpLmNvbnRlbnQ9cihpLmNvbnRlbnQscC5pbmRleCxfKSxlW20udG9rZW5dLmNvbnRlbnQ9cihlW20udG9rZW5dLmNvbnRlbnQsbS5wb3MsQSksZis9Xy5sZW5ndGgtMSxtLnRva2VuPT09biYmKGYrPUEubGVuZ3RoLTEpLHU9aS5jb250ZW50LGQ9dS5sZW5ndGgsay5sZW5ndGg9dztjb250aW51ZSBlfUU/ay5wdXNoKHt0b2tlbjpuLHBvczpwLmluZGV4LHNpbmdsZTpTLGxldmVsOmh9KTpEJiZTJiYoaS5jb250ZW50PXIoaS5jb250ZW50LHAuaW5kZXgsbCkpfWVsc2UgUyYmKGkuY29udGVudD1yKGkuY29udGVudCxwLmluZGV4LGwpKX19fX12YXIgbz1uKDUpLmlzV2hpdGVTcGFjZSxhPW4oNSkuaXNQdW5jdENoYXIscz1uKDUpLmlzTWRBc2NpaVB1bmN0LHU9L1snIl0vLGM9L1snIl0vZyxsPSJcdTIwMTkiO2UuZXhwb3J0cz1mdW5jdGlvbihlKXt2YXIgdDtpZihlLm1kLm9wdGlvbnMudHlwb2dyYXBoZXIpZm9yKHQ9ZS50b2tlbnMubGVuZ3RoLTE7dD49MDt0LS0pImlubGluZSI9PT1lLnRva2Vuc1t0XS50eXBlJiZ1LnRlc3QoZS50b2tlbnNbdF0uY29udGVudCkmJmkoZS50b2tlbnNbdF0uY2hpbGRyZW4sZSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4pe3RoaXMuc3JjPWUsdGhpcy5lbnY9bix0aGlzLnRva2Vucz1bXSx0aGlzLmlubGluZU1vZGU9ITEsdGhpcy5tZD10fXZhciBpPW4oMTQ1KTtyLnByb3RvdHlwZS5Ub2tlbj1pLGUuZXhwb3J0cz1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXt0aGlzLnJ1bGVyPW5ldyBpO2Zvcih2YXIgZT0wO2U8by5sZW5ndGg7ZSsrKXRoaXMucnVsZXIucHVzaChvW2VdWzBdLG9bZV1bMV0se2FsdDoob1tlXVsyXXx8W10pLnNsaWNlKCl9KX12YXIgaT1uKDE0NCksbz1bWyJ0YWJsZSIsbig2NjMpLFsicGFyYWdyYXBoIiwicmVmZXJlbmNlIl1dLFsiY29kZSIsbig2NjQpXSxbImZlbmNlIixuKDY2NSksWyJwYXJhZ3JhcGgiLCJyZWZlcmVuY2UiLCJibG9ja3F1b3RlIiwibGlzdCJdXSxbImJsb2NrcXVvdGUiLG4oNjY2KSxbInBhcmFncmFwaCIsInJlZmVyZW5jZSIsImJsb2NrcXVvdGUiLCJsaXN0Il1dLFsiaHIiLG4oNjY3KSxbInBhcmFncmFwaCIsInJlZmVyZW5jZSIsImJsb2NrcXVvdGUiLCJsaXN0Il1dLFsibGlzdCIsbig2NjgpLFsicGFyYWdyYXBoIiwicmVmZXJlbmNlIiwiYmxvY2txdW90ZSJdXSxbInJlZmVyZW5jZSIsbig2NjkpXSxbImhlYWRpbmciLG4oNjcwKSxbInBhcmFncmFwaCIsInJlZmVyZW5jZSIsImJsb2NrcXVvdGUiXV0sWyJsaGVhZGluZyIsbig2NzEpXSxbImh0bWxfYmxvY2siLG4oNjcyKSxbInBhcmFncmFwaCIsInJlZmVyZW5jZSIsImJsb2NrcXVvdGUiXV0sWyJwYXJhZ3JhcGgiLG4oNjc0KV1dO3IucHJvdG90eXBlLnRva2VuaXplPWZ1bmN0aW9uKGUsdCxuKXtmb3IodmFyIHIsaT10aGlzLnJ1bGVyLmdldFJ1bGVzKCIiKSxvPWkubGVuZ3RoLGE9dCxzPSExLHU9ZS5tZC5vcHRpb25zLm1heE5lc3Rpbmc7YTxuJiYoZS5saW5lPWE9ZS5za2lwRW1wdHlMaW5lcyhhKSwhKGE+PW4pKSYmIShlLnNDb3VudFthXTxlLmJsa0luZGVudCk7KXtpZihlLmxldmVsPj11KXtlLmxpbmU9bjticmVha31mb3Iocj0wO3I8byYmIWlbcl0oZSxhLG4sITEpO3IrKyk7ZS50aWdodD0hcyxlLmlzRW1wdHkoZS5saW5lLTEpJiYocz0hMCksKGE9ZS5saW5lKTxuJiZlLmlzRW1wdHkoYSkmJihzPSEwLGErKyxlLmxpbmU9YSl9fSxyLnByb3RvdHlwZS5wYXJzZT1mdW5jdGlvbihlLHQsbixyKXt2YXIgaTtlJiYoaT1uZXcgdGhpcy5TdGF0ZShlLHQsbixyKSx0aGlzLnRva2VuaXplKGksaS5saW5lLGkubGluZU1heCkpfSxyLnByb3RvdHlwZS5TdGF0ZT1uKDY3NSksZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQpe3ZhciBuPWUuYk1hcmtzW3RdK2UuYmxrSW5kZW50LHI9ZS5lTWFya3NbdF07cmV0dXJuIGUuc3JjLnN1YnN0cihuLHItbil9ZnVuY3Rpb24gaShlKXt2YXIgdCxuPVtdLHI9MCxpPWUubGVuZ3RoLG89MCxhPTAscz0hMSx1PTA7Zm9yKHQ9ZS5jaGFyQ29kZUF0KHIpO3I8aTspOTY9PT10P3M/KHM9ITEsdT1yKTpvJTI9PT0wJiYocz0hMCx1PXIpOjEyNCE9PXR8fG8lMiE9PTB8fHN8fChuLnB1c2goZS5zdWJzdHJpbmcoYSxyKSksYT1yKzEpLDkyPT09dD9vKys6bz0wLHIrKyxyPT09aSYmcyYmKHM9ITEscj11KzEpLHQ9ZS5jaGFyQ29kZUF0KHIpO3JldHVybiBuLnB1c2goZS5zdWJzdHJpbmcoYSkpLG59dmFyIG89big1KS5pc1NwYWNlO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbixhKXt2YXIgcyx1LGMsbCxwLGYsZCxoLG0sZyx5LHY7aWYodCsyPm4pcmV0dXJuITE7aWYocD10KzEsZS5zQ291bnRbcF08ZS5ibGtJbmRlbnQpcmV0dXJuITE7aWYoZS5zQ291bnRbcF0tZS5ibGtJbmRlbnQ+PTQpcmV0dXJuITE7aWYoKGM9ZS5iTWFya3NbcF0rZS50U2hpZnRbcF0pPj1lLmVNYXJrc1twXSlyZXR1cm4hMTtpZigxMjQhPT0ocz1lLnNyYy5jaGFyQ29kZUF0KGMrKykpJiY0NSE9PXMmJjU4IT09cylyZXR1cm4hMTtmb3IoO2M8ZS5lTWFya3NbcF07KXtpZigxMjQhPT0ocz1lLnNyYy5jaGFyQ29kZUF0KGMpKSYmNDUhPT1zJiY1OCE9PXMmJiFvKHMpKXJldHVybiExO2MrK31mb3IodT1yKGUsdCsxKSxmPXUuc3BsaXQoInwiKSxtPVtdLGw9MDtsPGYubGVuZ3RoO2wrKyl7aWYoIShnPWZbbF0udHJpbSgpKSl7aWYoMD09PWx8fGw9PT1mLmxlbmd0aC0xKWNvbnRpbnVlO3JldHVybiExfWlmKCEvXjo/LSs6PyQvLnRlc3QoZykpcmV0dXJuITE7NTg9PT1nLmNoYXJDb2RlQXQoZy5sZW5ndGgtMSk/bS5wdXNoKDU4PT09Zy5jaGFyQ29kZUF0KDApPyJjZW50ZXIiOiJyaWdodCIpOjU4PT09Zy5jaGFyQ29kZUF0KDApP20ucHVzaCgibGVmdCIpOm0ucHVzaCgiIil9aWYodT1yKGUsdCkudHJpbSgpLC0xPT09dS5pbmRleE9mKCJ8IikpcmV0dXJuITE7aWYoZS5zQ291bnRbdF0tZS5ibGtJbmRlbnQ+PTQpcmV0dXJuITE7aWYoZj1pKHUucmVwbGFjZSgvXlx8fFx8JC9nLCIiKSksKGQ9Zi5sZW5ndGgpPm0ubGVuZ3RoKXJldHVybiExO2lmKGEpcmV0dXJuITA7Zm9yKGg9ZS5wdXNoKCJ0YWJsZV9vcGVuIiwidGFibGUiLDEpLGgubWFwPXk9W3QsMF0saD1lLnB1c2goInRoZWFkX29wZW4iLCJ0aGVhZCIsMSksaC5tYXA9W3QsdCsxXSxoPWUucHVzaCgidHJfb3BlbiIsInRyIiwxKSxoLm1hcD1bdCx0KzFdLGw9MDtsPGYubGVuZ3RoO2wrKyloPWUucHVzaCgidGhfb3BlbiIsInRoIiwxKSxoLm1hcD1bdCx0KzFdLG1bbF0mJihoLmF0dHJzPVtbInN0eWxlIiwidGV4dC1hbGlnbjoiK21bbF1dXSksaD1lLnB1c2goImlubGluZSIsIiIsMCksaC5jb250ZW50PWZbbF0udHJpbSgpLGgubWFwPVt0LHQrMV0saC5jaGlsZHJlbj1bXSxoPWUucHVzaCgidGhfY2xvc2UiLCJ0aCIsLTEpO2ZvcihoPWUucHVzaCgidHJfY2xvc2UiLCJ0ciIsLTEpLGg9ZS5wdXNoKCJ0aGVhZF9jbG9zZSIsInRoZWFkIiwtMSksaD1lLnB1c2goInRib2R5X29wZW4iLCJ0Ym9keSIsMSksaC5tYXA9dj1bdCsyLDBdLHA9dCsyO3A8biYmIShlLnNDb3VudFtwXTxlLmJsa0luZGVudCkmJih1PXIoZSxwKS50cmltKCksLTEhPT11LmluZGV4T2YoInwiKSkmJiEoZS5zQ291bnRbcF0tZS5ibGtJbmRlbnQ+PTQpO3ArKyl7Zm9yKGY9aSh1LnJlcGxhY2UoL15cfHxcfCQvZywiIikpLGg9ZS5wdXNoKCJ0cl9vcGVuIiwidHIiLDEpLGw9MDtsPGQ7bCsrKWg9ZS5wdXNoKCJ0ZF9vcGVuIiwidGQiLDEpLG1bbF0mJihoLmF0dHJzPVtbInN0eWxlIiwidGV4dC1hbGlnbjoiK21bbF1dXSksaD1lLnB1c2goImlubGluZSIsIiIsMCksaC5jb250ZW50PWZbbF0/ZltsXS50cmltKCk6IiIsaC5jaGlsZHJlbj1bXSxoPWUucHVzaCgidGRfY2xvc2UiLCJ0ZCIsLTEpO2g9ZS5wdXNoKCJ0cl9jbG9zZSIsInRyIiwtMSl9cmV0dXJuIGg9ZS5wdXNoKCJ0Ym9keV9jbG9zZSIsInRib2R5IiwtMSksaD1lLnB1c2goInRhYmxlX2Nsb3NlIiwidGFibGUiLC0xKSx5WzFdPXZbMV09cCxlLmxpbmU9cCwhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpLG87aWYoZS5zQ291bnRbdF0tZS5ibGtJbmRlbnQ8NClyZXR1cm4hMTtmb3IoaT1yPXQrMTtyPG47KWlmKGUuaXNFbXB0eShyKSlyKys7ZWxzZXtpZighKGUuc0NvdW50W3JdLWUuYmxrSW5kZW50Pj00KSlicmVhaztyKyssaT1yfXJldHVybiBlLmxpbmU9aSxvPWUucHVzaCgiY29kZV9ibG9jayIsImNvZGUiLDApLG8uY29udGVudD1lLmdldExpbmVzKHQsaSw0K2UuYmxrSW5kZW50LCEwKSxvLm1hcD1bdCxlLmxpbmVdLCEwfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0LG4scil7dmFyIGksbyxhLHMsdSxjLGwscD0hMSxmPWUuYk1hcmtzW3RdK2UudFNoaWZ0W3RdLGQ9ZS5lTWFya3NbdF07aWYoZS5zQ291bnRbdF0tZS5ibGtJbmRlbnQ+PTQpcmV0dXJuITE7aWYoZiszPmQpcmV0dXJuITE7aWYoMTI2IT09KGk9ZS5zcmMuY2hhckNvZGVBdChmKSkmJjk2IT09aSlyZXR1cm4hMTtpZih1PWYsZj1lLnNraXBDaGFycyhmLGkpLChvPWYtdSk8MylyZXR1cm4hMTtpZihsPWUuc3JjLnNsaWNlKHUsZiksYT1lLnNyYy5zbGljZShmLGQpLGEuaW5kZXhPZihTdHJpbmcuZnJvbUNoYXJDb2RlKGkpKT49MClyZXR1cm4hMTtpZihyKXJldHVybiEwO2ZvcihzPXQ7ISgrK3M+PW4pJiYoZj11PWUuYk1hcmtzW3NdK2UudFNoaWZ0W3NdLGQ9ZS5lTWFya3Nbc10sIShmPGQmJmUuc0NvdW50W3NdPGUuYmxrSW5kZW50KSk7KWlmKGUuc3JjLmNoYXJDb2RlQXQoZik9PT1pJiYhKGUuc0NvdW50W3NdLWUuYmxrSW5kZW50Pj00KSYmISgoZj1lLnNraXBDaGFycyhmLGkpKS11PG8pJiYhKChmPWUuc2tpcFNwYWNlcyhmKSk8ZCkpe3A9ITA7YnJlYWt9cmV0dXJuIG89ZS5zQ291bnRbdF0sZS5saW5lPXMrKHA/MTowKSxjPWUucHVzaCgiZmVuY2UiLCJjb2RlIiwwKSxjLmluZm89YSxjLmNvbnRlbnQ9ZS5nZXRMaW5lcyh0KzEscyxvLCEwKSxjLm1hcmt1cD1sLGMubWFwPVt0LGUubGluZV0sITB9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNSkuaXNTcGFjZTtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0LG4saSl7dmFyIG8sYSxzLHUsYyxsLHAsZixkLGgsbSxnLHksdixiLHgsQyxFLEQsdyxTPWUubGluZU1heCxrPWUuYk1hcmtzW3RdK2UudFNoaWZ0W3RdLEE9ZS5lTWFya3NbdF07aWYoZS5zQ291bnRbdF0tZS5ibGtJbmRlbnQ+PTQpcmV0dXJuITE7aWYoNjIhPT1lLnNyYy5jaGFyQ29kZUF0KGsrKykpcmV0dXJuITE7aWYoaSlyZXR1cm4hMDtmb3IodT1kPWUuc0NvdW50W3RdK2stKGUuYk1hcmtzW3RdK2UudFNoaWZ0W3RdKSwzMj09PWUuc3JjLmNoYXJDb2RlQXQoayk/KGsrKyx1KyssZCsrLG89ITEseD0hMCk6OT09PWUuc3JjLmNoYXJDb2RlQXQoayk/KHg9ITAsKGUuYnNDb3VudFt0XStkKSU0PT09Mz8oaysrLHUrKyxkKyssbz0hMSk6bz0hMCk6eD0hMSxoPVtlLmJNYXJrc1t0XV0sZS5iTWFya3NbdF09aztrPEEmJihhPWUuc3JjLmNoYXJDb2RlQXQoaykscihhKSk7KTk9PT1hP2QrPTQtKGQrZS5ic0NvdW50W3RdKyhvPzE6MCkpJTQ6ZCsrLGsrKztmb3IobT1bZS5ic0NvdW50W3RdXSxlLmJzQ291bnRbdF09ZS5zQ291bnRbdF0rMSsoeD8xOjApLGw9az49QSx2PVtlLnNDb3VudFt0XV0sZS5zQ291bnRbdF09ZC11LGI9W2UudFNoaWZ0W3RdXSxlLnRTaGlmdFt0XT1rLWUuYk1hcmtzW3RdLEU9ZS5tZC5ibG9jay5ydWxlci5nZXRSdWxlcygiYmxvY2txdW90ZSIpLHk9ZS5wYXJlbnRUeXBlLGUucGFyZW50VHlwZT0iYmxvY2txdW90ZSIsdz0hMSxmPXQrMTtmPG4mJihlLnNDb3VudFtmXTxlLmJsa0luZGVudCYmKHc9ITApLGs9ZS5iTWFya3NbZl0rZS50U2hpZnRbZl0sQT1lLmVNYXJrc1tmXSwhKGs+PUEpKTtmKyspaWYoNjIhPT1lLnNyYy5jaGFyQ29kZUF0KGsrKyl8fHcpe2lmKGwpYnJlYWs7Zm9yKEM9ITEscz0wLGM9RS5sZW5ndGg7czxjO3MrKylpZihFW3NdKGUsZixuLCEwKSl7Qz0hMDticmVha31pZihDKXtlLmxpbmVNYXg9ZiwwIT09ZS5ibGtJbmRlbnQmJihoLnB1c2goZS5iTWFya3NbZl0pLG0ucHVzaChlLmJzQ291bnRbZl0pLGIucHVzaChlLnRTaGlmdFtmXSksdi5wdXNoKGUuc0NvdW50W2ZdKSxlLnNDb3VudFtmXS09ZS5ibGtJbmRlbnQpO2JyZWFrfWgucHVzaChlLmJNYXJrc1tmXSksbS5wdXNoKGUuYnNDb3VudFtmXSksYi5wdXNoKGUudFNoaWZ0W2ZdKSx2LnB1c2goZS5zQ291bnRbZl0pLGUuc0NvdW50W2ZdPS0xfWVsc2V7Zm9yKHU9ZD1lLnNDb3VudFtmXStrLShlLmJNYXJrc1tmXStlLnRTaGlmdFtmXSksMzI9PT1lLnNyYy5jaGFyQ29kZUF0KGspPyhrKyssdSsrLGQrKyxvPSExLHg9ITApOjk9PT1lLnNyYy5jaGFyQ29kZUF0KGspPyh4PSEwLChlLmJzQ291bnRbZl0rZCklND09PTM/KGsrKyx1KyssZCsrLG89ITEpOm89ITApOng9ITEsaC5wdXNoKGUuYk1hcmtzW2ZdKSxlLmJNYXJrc1tmXT1rO2s8QSYmKGE9ZS5zcmMuY2hhckNvZGVBdChrKSxyKGEpKTspOT09PWE/ZCs9NC0oZCtlLmJzQ291bnRbZl0rKG8/MTowKSklNDpkKyssaysrO2w9az49QSxtLnB1c2goZS5ic0NvdW50W2ZdKSxlLmJzQ291bnRbZl09ZS5zQ291bnRbZl0rMSsoeD8xOjApLHYucHVzaChlLnNDb3VudFtmXSksZS5zQ291bnRbZl09ZC11LGIucHVzaChlLnRTaGlmdFtmXSksZS50U2hpZnRbZl09ay1lLmJNYXJrc1tmXX1mb3IoZz1lLmJsa0luZGVudCxlLmJsa0luZGVudD0wLEQ9ZS5wdXNoKCJibG9ja3F1b3RlX29wZW4iLCJibG9ja3F1b3RlIiwxKSxELm1hcmt1cD0iPiIsRC5tYXA9cD1bdCwwXSxlLm1kLmJsb2NrLnRva2VuaXplKGUsdCxmKSxEPWUucHVzaCgiYmxvY2txdW90ZV9jbG9zZSIsImJsb2NrcXVvdGUiLC0xKSxELm1hcmt1cD0iPiIsZS5saW5lTWF4PVMsZS5wYXJlbnRUeXBlPXkscFsxXT1lLmxpbmUscz0wO3M8Yi5sZW5ndGg7cysrKWUuYk1hcmtzW3MrdF09aFtzXSxlLnRTaGlmdFtzK3RdPWJbc10sZS5zQ291bnRbcyt0XT12W3NdLGUuYnNDb3VudFtzK3RdPW1bc107cmV0dXJuIGUuYmxrSW5kZW50PWcsITB9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNSkuaXNTcGFjZTtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0LG4saSl7dmFyIG8sYSxzLHUsYz1lLmJNYXJrc1t0XStlLnRTaGlmdFt0XSxsPWUuZU1hcmtzW3RdO2lmKGUuc0NvdW50W3RdLWUuYmxrSW5kZW50Pj00KXJldHVybiExO2lmKDQyIT09KG89ZS5zcmMuY2hhckNvZGVBdChjKyspKSYmNDUhPT1vJiY5NSE9PW8pcmV0dXJuITE7Zm9yKGE9MTtjPGw7KXtpZigocz1lLnNyYy5jaGFyQ29kZUF0KGMrKykpIT09byYmIXIocykpcmV0dXJuITE7cz09PW8mJmErK31yZXR1cm4hKGE8MykmJighIWl8fChlLmxpbmU9dCsxLHU9ZS5wdXNoKCJociIsImhyIiwwKSx1Lm1hcD1bdCxlLmxpbmVdLHUubWFya3VwPUFycmF5KGErMSkuam9pbihTdHJpbmcuZnJvbUNoYXJDb2RlKG8pKSwhMCkpfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dmFyIG4scixpLG87cmV0dXJuIHI9ZS5iTWFya3NbdF0rZS50U2hpZnRbdF0saT1lLmVNYXJrc1t0XSxuPWUuc3JjLmNoYXJDb2RlQXQocisrKSw0MiE9PW4mJjQ1IT09biYmNDMhPT1uPy0xOnI8aSYmKG89ZS5zcmMuY2hhckNvZGVBdChyKSwhYShvKSk/LTE6cn1mdW5jdGlvbiBpKGUsdCl7dmFyIG4scj1lLmJNYXJrc1t0XStlLnRTaGlmdFt0XSxpPXIsbz1lLmVNYXJrc1t0XTtpZihpKzE+PW8pcmV0dXJuLTE7aWYoKG49ZS5zcmMuY2hhckNvZGVBdChpKyspKTw0OHx8bj41NylyZXR1cm4tMTtmb3IoOzspe2lmKGk+PW8pcmV0dXJuLTE7bj1lLnNyYy5jaGFyQ29kZUF0KGkrKyk7e2lmKCEobj49NDgmJm48PTU3KSl7aWYoNDE9PT1ufHw0Nj09PW4pYnJlYWs7cmV0dXJuLTF9aWYoaS1yPj0xMClyZXR1cm4tMX19cmV0dXJuIGk8byYmKG49ZS5zcmMuY2hhckNvZGVBdChpKSwhYShuKSk/LTE6aX1mdW5jdGlvbiBvKGUsdCl7dmFyIG4scixpPWUubGV2ZWwrMjtmb3Iobj10KzIscj1lLnRva2Vucy5sZW5ndGgtMjtuPHI7bisrKWUudG9rZW5zW25dLmxldmVsPT09aSYmInBhcmFncmFwaF9vcGVuIj09PWUudG9rZW5zW25dLnR5cGUmJihlLnRva2Vuc1tuKzJdLmhpZGRlbj0hMCxlLnRva2Vuc1tuXS5oaWRkZW49ITAsbis9Mil9dmFyIGE9big1KS5pc1NwYWNlO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbixhKXt2YXIgcyx1LGMsbCxwLGYsZCxoLG0sZyx5LHYsYix4LEMsRSxELHcsUyxrLEEsXyxULE8sRixOLEksTCxQPSExLE09ITA7aWYoZS5zQ291bnRbdF0tZS5ibGtJbmRlbnQ+PTQpcmV0dXJuITE7aWYoYSYmInBhcmFncmFwaCI9PT1lLnBhcmVudFR5cGUmJmUudFNoaWZ0W3RdPj1lLmJsa0luZGVudCYmKFA9ITApLChUPWkoZSx0KSk+PTApe2lmKGQ9ITAsRj1lLmJNYXJrc1t0XStlLnRTaGlmdFt0XSxiPU51bWJlcihlLnNyYy5zdWJzdHIoRixULUYtMSkpLFAmJjEhPT1iKXJldHVybiExfWVsc2V7aWYoISgoVD1yKGUsdCkpPj0wKSlyZXR1cm4hMTtkPSExfWlmKFAmJmUuc2tpcFNwYWNlcyhUKT49ZS5lTWFya3NbdF0pcmV0dXJuITE7aWYodj1lLnNyYy5jaGFyQ29kZUF0KFQtMSksYSlyZXR1cm4hMDtmb3IoeT1lLnRva2Vucy5sZW5ndGgsZD8oTD1lLnB1c2goIm9yZGVyZWRfbGlzdF9vcGVuIiwib2wiLDEpLDEhPT1iJiYoTC5hdHRycz1bWyJzdGFydCIsYl1dKSk6TD1lLnB1c2goImJ1bGxldF9saXN0X29wZW4iLCJ1bCIsMSksTC5tYXA9Zz1bdCwwXSxMLm1hcmt1cD1TdHJpbmcuZnJvbUNoYXJDb2RlKHYpLEM9dCxPPSExLEk9ZS5tZC5ibG9jay5ydWxlci5nZXRSdWxlcygibGlzdCIpLFM9ZS5wYXJlbnRUeXBlLGUucGFyZW50VHlwZT0ibGlzdCI7QzxuOyl7Zm9yKF89VCx4PWUuZU1hcmtzW0NdLGY9RT1lLnNDb3VudFtDXStULShlLmJNYXJrc1t0XStlLnRTaGlmdFt0XSk7Xzx4Oyl7aWYoOT09PShzPWUuc3JjLmNoYXJDb2RlQXQoXykpKUUrPTQtKEUrZS5ic0NvdW50W0NdKSU0O2Vsc2V7aWYoMzIhPT1zKWJyZWFrO0UrK31fKyt9aWYodT1fLHA9dT49eD8xOkUtZixwPjQmJihwPTEpLGw9ZitwLEw9ZS5wdXNoKCJsaXN0X2l0ZW1fb3BlbiIsImxpIiwxKSxMLm1hcmt1cD1TdHJpbmcuZnJvbUNoYXJDb2RlKHYpLEwubWFwPWg9W3QsMF0sRD1lLmJsa0luZGVudCxBPWUudGlnaHQsaz1lLnRTaGlmdFt0XSx3PWUuc0NvdW50W3RdLGUuYmxrSW5kZW50PWwsZS50aWdodD0hMCxlLnRTaGlmdFt0XT11LWUuYk1hcmtzW3RdLGUuc0NvdW50W3RdPUUsdT49eCYmZS5pc0VtcHR5KHQrMSk/ZS5saW5lPU1hdGgubWluKGUubGluZSsyLG4pOmUubWQuYmxvY2sudG9rZW5pemUoZSx0LG4sITApLGUudGlnaHQmJiFPfHwoTT0hMSksTz1lLmxpbmUtdD4xJiZlLmlzRW1wdHkoZS5saW5lLTEpLGUuYmxrSW5kZW50PUQsZS50U2hpZnRbdF09ayxlLnNDb3VudFt0XT13LGUudGlnaHQ9QSxMPWUucHVzaCgibGlzdF9pdGVtX2Nsb3NlIiwibGkiLC0xKSxMLm1hcmt1cD1TdHJpbmcuZnJvbUNoYXJDb2RlKHYpLEM9dD1lLmxpbmUsaFsxXT1DLHU9ZS5iTWFya3NbdF0sQz49bilicmVhaztpZihlLnNDb3VudFtDXTxlLmJsa0luZGVudClicmVhaztmb3IoTj0hMSxjPTAsbT1JLmxlbmd0aDtjPG07YysrKWlmKElbY10oZSxDLG4sITApKXtOPSEwO2JyZWFrfWlmKE4pYnJlYWs7aWYoZCl7aWYoKFQ9aShlLEMpKTwwKWJyZWFrfWVsc2UgaWYoKFQ9cihlLEMpKTwwKWJyZWFrO2lmKHYhPT1lLnNyYy5jaGFyQ29kZUF0KFQtMSkpYnJlYWt9cmV0dXJuIEw9ZD9lLnB1c2goIm9yZGVyZWRfbGlzdF9jbG9zZSIsIm9sIiwtMSk6ZS5wdXNoKCJidWxsZXRfbGlzdF9jbG9zZSIsInVsIiwtMSksTC5tYXJrdXA9U3RyaW5nLmZyb21DaGFyQ29kZSh2KSxnWzFdPUMsZS5saW5lPUMsZS5wYXJlbnRUeXBlPVMsTSYmbyhlLHkpLCEwfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDUpLm5vcm1hbGl6ZVJlZmVyZW5jZSxpPW4oNSkuaXNTcGFjZTtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0LG4sbyl7dmFyIGEscyx1LGMsbCxwLGYsZCxoLG0sZyx5LHYsYix4LEMsRT0wLEQ9ZS5iTWFya3NbdF0rZS50U2hpZnRbdF0sdz1lLmVNYXJrc1t0XSxTPXQrMTtpZihlLnNDb3VudFt0XS1lLmJsa0luZGVudD49NClyZXR1cm4hMTtpZig5MSE9PWUuc3JjLmNoYXJDb2RlQXQoRCkpcmV0dXJuITE7Zm9yKDsrK0Q8dzspaWYoOTM9PT1lLnNyYy5jaGFyQ29kZUF0KEQpJiY5MiE9PWUuc3JjLmNoYXJDb2RlQXQoRC0xKSl7aWYoRCsxPT09dylyZXR1cm4hMTtpZig1OCE9PWUuc3JjLmNoYXJDb2RlQXQoRCsxKSlyZXR1cm4hMTticmVha31mb3IoYz1lLmxpbmVNYXgseD1lLm1kLmJsb2NrLnJ1bGVyLmdldFJ1bGVzKCJyZWZlcmVuY2UiKSxtPWUucGFyZW50VHlwZSxlLnBhcmVudFR5cGU9InJlZmVyZW5jZSI7UzxjJiYhZS5pc0VtcHR5KFMpO1MrKylpZighKGUuc0NvdW50W1NdLWUuYmxrSW5kZW50PjMpJiYhKGUuc0NvdW50W1NdPDApKXtmb3IoYj0hMSxwPTAsZj14Lmxlbmd0aDtwPGY7cCsrKWlmKHhbcF0oZSxTLGMsITApKXtiPSEwO2JyZWFrfWlmKGIpYnJlYWt9Zm9yKHY9ZS5nZXRMaW5lcyh0LFMsZS5ibGtJbmRlbnQsITEpLnRyaW0oKSx3PXYubGVuZ3RoLEQ9MTtEPHc7RCsrKXtpZig5MT09PShhPXYuY2hhckNvZGVBdChEKSkpcmV0dXJuITE7aWYoOTM9PT1hKXtoPUQ7YnJlYWt9MTA9PT1hP0UrKzo5Mj09PWEmJisrRDx3JiYxMD09PXYuY2hhckNvZGVBdChEKSYmRSsrfWlmKGg8MHx8NTghPT12LmNoYXJDb2RlQXQoaCsxKSlyZXR1cm4hMTtmb3IoRD1oKzI7RDx3O0QrKylpZigxMD09PShhPXYuY2hhckNvZGVBdChEKSkpRSsrO2Vsc2UgaWYoIWkoYSkpYnJlYWs7aWYoZz1lLm1kLmhlbHBlcnMucGFyc2VMaW5rRGVzdGluYXRpb24odixELHcpLCFnLm9rKXJldHVybiExO2lmKGw9ZS5tZC5ub3JtYWxpemVMaW5rKGcuc3RyKSwhZS5tZC52YWxpZGF0ZUxpbmsobCkpcmV0dXJuITE7Zm9yKEQ9Zy5wb3MsRSs9Zy5saW5lcyxzPUQsdT1FLHk9RDtEPHc7RCsrKWlmKDEwPT09KGE9di5jaGFyQ29kZUF0KEQpKSlFKys7ZWxzZSBpZighaShhKSlicmVhaztmb3IoZz1lLm1kLmhlbHBlcnMucGFyc2VMaW5rVGl0bGUodixELHcpLEQ8dyYmeSE9PUQmJmcub2s/KEM9Zy5zdHIsRD1nLnBvcyxFKz1nLmxpbmVzKTooQz0iIixEPXMsRT11KTtEPHcmJihhPXYuY2hhckNvZGVBdChEKSxpKGEpKTspRCsrO2lmKEQ8dyYmMTAhPT12LmNoYXJDb2RlQXQoRCkmJkMpZm9yKEM9IiIsRD1zLEU9dTtEPHcmJihhPXYuY2hhckNvZGVBdChEKSxpKGEpKTspRCsrO3JldHVybiEoRDx3JiYxMCE9PXYuY2hhckNvZGVBdChEKSkmJighIShkPXIodi5zbGljZSgxLGgpKSkmJighIW98fCgidW5kZWZpbmVkIj09PXR5cGVvZiBlLmVudi5yZWZlcmVuY2VzJiYoZS5lbnYucmVmZXJlbmNlcz17fSksInVuZGVmaW5lZCI9PT10eXBlb2YgZS5lbnYucmVmZXJlbmNlc1tkXSYmKGUuZW52LnJlZmVyZW5jZXNbZF09e3RpdGxlOkMsaHJlZjpsfSksZS5wYXJlbnRUeXBlPW0sZS5saW5lPXQrRSsxLCEwKSkpfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDUpLmlzU3BhY2U7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCxuLGkpe3ZhciBvLGEscyx1LGM9ZS5iTWFya3NbdF0rZS50U2hpZnRbdF0sbD1lLmVNYXJrc1t0XTtpZihlLnNDb3VudFt0XS1lLmJsa0luZGVudD49NClyZXR1cm4hMTtpZigzNSE9PShvPWUuc3JjLmNoYXJDb2RlQXQoYykpfHxjPj1sKXJldHVybiExO2ZvcihhPTEsbz1lLnNyYy5jaGFyQ29kZUF0KCsrYyk7MzU9PT1vJiZjPGwmJmE8PTY7KWErKyxvPWUuc3JjLmNoYXJDb2RlQXQoKytjKTtyZXR1cm4hKGE+Nnx8YzxsJiYhcihvKSkmJighIWl8fChsPWUuc2tpcFNwYWNlc0JhY2sobCxjKSxzPWUuc2tpcENoYXJzQmFjayhsLDM1LGMpLHM+YyYmcihlLnNyYy5jaGFyQ29kZUF0KHMtMSkpJiYobD1zKSxlLmxpbmU9dCsxLHU9ZS5wdXNoKCJoZWFkaW5nX29wZW4iLCJoIitTdHJpbmcoYSksMSksdS5tYXJrdXA9IiMjIyMjIyMjIi5zbGljZSgwLGEpLHUubWFwPVt0LGUubGluZV0sdT1lLnB1c2goImlubGluZSIsIiIsMCksdS5jb250ZW50PWUuc3JjLnNsaWNlKGMsbCkudHJpbSgpLHUubWFwPVt0LGUubGluZV0sdS5jaGlsZHJlbj1bXSx1PWUucHVzaCgiaGVhZGluZ19jbG9zZSIsImgiK1N0cmluZyhhKSwtMSksdS5tYXJrdXA9IiMjIyMjIyMjIi5zbGljZSgwLGEpLCEwKSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQsbil7dmFyIHIsaSxvLGEscyx1LGMsbCxwLGYsZD10KzEsaD1lLm1kLmJsb2NrLnJ1bGVyLmdldFJ1bGVzKCJwYXJhZ3JhcGgiKTtpZihlLnNDb3VudFt0XS1lLmJsa0luZGVudD49NClyZXR1cm4hMTtmb3IoZj1lLnBhcmVudFR5cGUsZS5wYXJlbnRUeXBlPSJwYXJhZ3JhcGgiO2Q8biYmIWUuaXNFbXB0eShkKTtkKyspaWYoIShlLnNDb3VudFtkXS1lLmJsa0luZGVudD4zKSl7aWYoZS5zQ291bnRbZF0+PWUuYmxrSW5kZW50JiYodT1lLmJNYXJrc1tkXStlLnRTaGlmdFtkXSxjPWUuZU1hcmtzW2RdLHU8YyYmKDQ1PT09KHA9ZS5zcmMuY2hhckNvZGVBdCh1KSl8fDYxPT09cCkmJih1PWUuc2tpcENoYXJzKHUscCksKHU9ZS5za2lwU3BhY2VzKHUpKT49YykpKXtsPTYxPT09cD8xOjI7YnJlYWt9aWYoIShlLnNDb3VudFtkXTwwKSl7Zm9yKGk9ITEsbz0wLGE9aC5sZW5ndGg7bzxhO28rKylpZihoW29dKGUsZCxuLCEwKSl7aT0hMDticmVha31pZihpKWJyZWFrfX1yZXR1cm4hIWwmJihyPWUuZ2V0TGluZXModCxkLGUuYmxrSW5kZW50LCExKS50cmltKCksZS5saW5lPWQrMSxzPWUucHVzaCgiaGVhZGluZ19vcGVuIiwiaCIrU3RyaW5nKGwpLDEpLHMubWFya3VwPVN0cmluZy5mcm9tQ2hhckNvZGUocCkscy5tYXA9W3QsZS5saW5lXSxzPWUucHVzaCgiaW5saW5lIiwiIiwwKSxzLmNvbnRlbnQ9cixzLm1hcD1bdCxlLmxpbmUtMV0scy5jaGlsZHJlbj1bXSxzPWUucHVzaCgiaGVhZGluZ19jbG9zZSIsImgiK1N0cmluZyhsKSwtMSkscy5tYXJrdXA9U3RyaW5nLmZyb21DaGFyQ29kZShwKSxlLnBhcmVudFR5cGU9ZiwhMCl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNjczKSxpPW4oMjk1KS5IVE1MX09QRU5fQ0xPU0VfVEFHX1JFLG89W1svXjwoc2NyaXB0fHByZXxzdHlsZSkoPz0oXHN8PnwkKSkvaSwvPFwvKHNjcmlwdHxwcmV8c3R5bGUpPi9pLCEwXSxbL148IS0tLywvLS0+LywhMF0sWy9ePFw/LywvXD8+LywhMF0sWy9ePCFbQS1aXS8sLz4vLCEwXSxbL148IVxbQ0RBVEFcWy8sL1xdXF0+LywhMF0sW25ldyBSZWdFeHAoIl48Lz8oIityLmpvaW4oInwiKSsiKSg/PShcXHN8Lz8+fCQpKSIsImkiKSwvXiQvLCEwXSxbbmV3IFJlZ0V4cChpLnNvdXJjZSsiXFxzKiQiKSwvXiQvLCExXV07ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpLGEscyx1LGM9ZS5iTWFya3NbdF0rZS50U2hpZnRbdF0sbD1lLmVNYXJrc1t0XTtpZihlLnNDb3VudFt0XS1lLmJsa0luZGVudD49NClyZXR1cm4hMTtpZighZS5tZC5vcHRpb25zLmh0bWwpcmV0dXJuITE7aWYoNjAhPT1lLnNyYy5jaGFyQ29kZUF0KGMpKXJldHVybiExO2Zvcih1PWUuc3JjLnNsaWNlKGMsbCksaT0wO2k8by5sZW5ndGgmJiFvW2ldWzBdLnRlc3QodSk7aSsrKTtpZihpPT09by5sZW5ndGgpcmV0dXJuITE7aWYocilyZXR1cm4gb1tpXVsyXTtpZihhPXQrMSwhb1tpXVsxXS50ZXN0KHUpKWZvcig7YTxuJiYhKGUuc0NvdW50W2FdPGUuYmxrSW5kZW50KTthKyspaWYoYz1lLmJNYXJrc1thXStlLnRTaGlmdFthXSxsPWUuZU1hcmtzW2FdLHU9ZS5zcmMuc2xpY2UoYyxsKSxvW2ldWzFdLnRlc3QodSkpezAhPT11Lmxlbmd0aCYmYSsrO2JyZWFrfXJldHVybiBlLmxpbmU9YSxzPWUucHVzaCgiaHRtbF9ibG9jayIsIiIsMCkscy5tYXA9W3QsYV0scy5jb250ZW50PWUuZ2V0TGluZXModCxhLGUuYmxrSW5kZW50LCEwKSwhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPVsiYWRkcmVzcyIsImFydGljbGUiLCJhc2lkZSIsImJhc2UiLCJiYXNlZm9udCIsImJsb2NrcXVvdGUiLCJib2R5IiwiY2FwdGlvbiIsImNlbnRlciIsImNvbCIsImNvbGdyb3VwIiwiZGQiLCJkZXRhaWxzIiwiZGlhbG9nIiwiZGlyIiwiZGl2IiwiZGwiLCJkdCIsImZpZWxkc2V0IiwiZmlnY2FwdGlvbiIsImZpZ3VyZSIsImZvb3RlciIsImZvcm0iLCJmcmFtZSIsImZyYW1lc2V0IiwiaDEiLCJoMiIsImgzIiwiaDQiLCJoNSIsImg2IiwiaGVhZCIsImhlYWRlciIsImhyIiwiaHRtbCIsImlmcmFtZSIsImxlZ2VuZCIsImxpIiwibGluayIsIm1haW4iLCJtZW51IiwibWVudWl0ZW0iLCJtZXRhIiwibmF2Iiwibm9mcmFtZXMiLCJvbCIsIm9wdGdyb3VwIiwib3B0aW9uIiwicCIsInBhcmFtIiwic2VjdGlvbiIsInNvdXJjZSIsInN1bW1hcnkiLCJ0YWJsZSIsInRib2R5IiwidGQiLCJ0Zm9vdCIsInRoIiwidGhlYWQiLCJ0aXRsZSIsInRyIiwidHJhY2siLCJ1bCJdfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQpe3ZhciBuLHIsaSxvLGEscyx1PXQrMSxjPWUubWQuYmxvY2sucnVsZXIuZ2V0UnVsZXMoInBhcmFncmFwaCIpLGw9ZS5saW5lTWF4O2ZvcihzPWUucGFyZW50VHlwZSxlLnBhcmVudFR5cGU9InBhcmFncmFwaCI7dTxsJiYhZS5pc0VtcHR5KHUpO3UrKylpZighKGUuc0NvdW50W3VdLWUuYmxrSW5kZW50PjMpJiYhKGUuc0NvdW50W3VdPDApKXtmb3Iocj0hMSxpPTAsbz1jLmxlbmd0aDtpPG87aSsrKWlmKGNbaV0oZSx1LGwsITApKXtyPSEwO2JyZWFrfWlmKHIpYnJlYWt9cmV0dXJuIG49ZS5nZXRMaW5lcyh0LHUsZS5ibGtJbmRlbnQsITEpLnRyaW0oKSxlLmxpbmU9dSxhPWUucHVzaCgicGFyYWdyYXBoX29wZW4iLCJwIiwxKSxhLm1hcD1bdCxlLmxpbmVdLGE9ZS5wdXNoKCJpbmxpbmUiLCIiLDApLGEuY29udGVudD1uLGEubWFwPVt0LGUubGluZV0sYS5jaGlsZHJlbj1bXSxhPWUucHVzaCgicGFyYWdyYXBoX2Nsb3NlIiwicCIsLTEpLGUucGFyZW50VHlwZT1zLCEwfX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuLHIpe3ZhciBpLGEscyx1LGMsbCxwLGY7Zm9yKHRoaXMuc3JjPWUsdGhpcy5tZD10LHRoaXMuZW52PW4sdGhpcy50b2tlbnM9cix0aGlzLmJNYXJrcz1bXSx0aGlzLmVNYXJrcz1bXSx0aGlzLnRTaGlmdD1bXSx0aGlzLnNDb3VudD1bXSx0aGlzLmJzQ291bnQ9W10sdGhpcy5ibGtJbmRlbnQ9MCx0aGlzLmxpbmU9MCx0aGlzLmxpbmVNYXg9MCx0aGlzLnRpZ2h0PSExLHRoaXMuZGRJbmRlbnQ9LTEsdGhpcy5wYXJlbnRUeXBlPSJyb290Iix0aGlzLmxldmVsPTAsdGhpcy5yZXN1bHQ9IiIsYT10aGlzLnNyYyxmPSExLHM9dT1sPXA9MCxjPWEubGVuZ3RoO3U8Yzt1Kyspe2lmKGk9YS5jaGFyQ29kZUF0KHUpLCFmKXtpZihvKGkpKXtsKyssOT09PWk/cCs9NC1wJTQ6cCsrO2NvbnRpbnVlfWY9ITB9MTAhPT1pJiZ1IT09Yy0xfHwoMTAhPT1pJiZ1KyssdGhpcy5iTWFya3MucHVzaChzKSx0aGlzLmVNYXJrcy5wdXNoKHUpLHRoaXMudFNoaWZ0LnB1c2gobCksdGhpcy5zQ291bnQucHVzaChwKSx0aGlzLmJzQ291bnQucHVzaCgwKSxmPSExLGw9MCxwPTAscz11KzEpfXRoaXMuYk1hcmtzLnB1c2goYS5sZW5ndGgpLHRoaXMuZU1hcmtzLnB1c2goYS5sZW5ndGgpLHRoaXMudFNoaWZ0LnB1c2goMCksdGhpcy5zQ291bnQucHVzaCgwKSx0aGlzLmJzQ291bnQucHVzaCgwKSx0aGlzLmxpbmVNYXg9dGhpcy5iTWFya3MubGVuZ3RoLTF9dmFyIGk9bigxNDUpLG89big1KS5pc1NwYWNlO3IucHJvdG90eXBlLnB1c2g9ZnVuY3Rpb24oZSx0LG4pe3ZhciByPW5ldyBpKGUsdCxuKTtyZXR1cm4gci5ibG9jaz0hMCxuPDAmJnRoaXMubGV2ZWwtLSxyLmxldmVsPXRoaXMubGV2ZWwsbj4wJiZ0aGlzLmxldmVsKyssdGhpcy50b2tlbnMucHVzaChyKSxyfSxyLnByb3RvdHlwZS5pc0VtcHR5PWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLmJNYXJrc1tlXSt0aGlzLnRTaGlmdFtlXT49dGhpcy5lTWFya3NbZV19LHIucHJvdG90eXBlLnNraXBFbXB0eUxpbmVzPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD10aGlzLmxpbmVNYXg7ZTx0JiYhKHRoaXMuYk1hcmtzW2VdK3RoaXMudFNoaWZ0W2VdPHRoaXMuZU1hcmtzW2VdKTtlKyspO3JldHVybiBlfSxyLnByb3RvdHlwZS5za2lwU3BhY2VzPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPXRoaXMuc3JjLmxlbmd0aDtlPG4mJih0PXRoaXMuc3JjLmNoYXJDb2RlQXQoZSksbyh0KSk7ZSsrKTtyZXR1cm4gZX0sci5wcm90b3R5cGUuc2tpcFNwYWNlc0JhY2s9ZnVuY3Rpb24oZSx0KXtpZihlPD10KXJldHVybiBlO2Zvcig7ZT50OylpZighbyh0aGlzLnNyYy5jaGFyQ29kZUF0KC0tZSkpKXJldHVybiBlKzE7cmV0dXJuIGV9LHIucHJvdG90eXBlLnNraXBDaGFycz1mdW5jdGlvbihlLHQpe2Zvcih2YXIgbj10aGlzLnNyYy5sZW5ndGg7ZTxuJiZ0aGlzLnNyYy5jaGFyQ29kZUF0KGUpPT09dDtlKyspO3JldHVybiBlfSxyLnByb3RvdHlwZS5za2lwQ2hhcnNCYWNrPWZ1bmN0aW9uKGUsdCxuKXtpZihlPD1uKXJldHVybiBlO2Zvcig7ZT5uOylpZih0IT09dGhpcy5zcmMuY2hhckNvZGVBdCgtLWUpKXJldHVybiBlKzE7cmV0dXJuIGV9LHIucHJvdG90eXBlLmdldExpbmVzPWZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpLGEscyx1LGMsbCxwLGY9ZTtpZihlPj10KXJldHVybiIiO2ZvcihsPW5ldyBBcnJheSh0LWUpLGk9MDtmPHQ7ZisrLGkrKyl7Zm9yKGE9MCxwPXU9dGhpcy5iTWFya3NbZl0sYz1mKzE8dHx8cj90aGlzLmVNYXJrc1tmXSsxOnRoaXMuZU1hcmtzW2ZdO3U8YyYmYTxuOyl7aWYocz10aGlzLnNyYy5jaGFyQ29kZUF0KHUpLG8ocykpOT09PXM/YSs9NC0oYSt0aGlzLmJzQ291bnRbZl0pJTQ6YSsrO2Vsc2V7aWYoISh1LXA8dGhpcy50U2hpZnRbZl0pKWJyZWFrO2ErK311Kyt9bFtpXT1hPm4/bmV3IEFycmF5KGEtbisxKS5qb2luKCIgIikrdGhpcy5zcmMuc2xpY2UodSxjKTp0aGlzLnNyYy5zbGljZSh1LGMpfXJldHVybiBsLmpvaW4oIiIpfSxyLnByb3RvdHlwZS5Ub2tlbj1pLGUuZXhwb3J0cz1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoKXt2YXIgZTtmb3IodGhpcy5ydWxlcj1uZXcgaSxlPTA7ZTxvLmxlbmd0aDtlKyspdGhpcy5ydWxlci5wdXNoKG9bZV1bMF0sb1tlXVsxXSk7Zm9yKHRoaXMucnVsZXIyPW5ldyBpLGU9MDtlPGEubGVuZ3RoO2UrKyl0aGlzLnJ1bGVyMi5wdXNoKGFbZV1bMF0sYVtlXVsxXSl9dmFyIGk9bigxNDQpLG89W1sidGV4dCIsbig2NzcpXSxbIm5ld2xpbmUiLG4oNjc4KV0sWyJlc2NhcGUiLG4oNjc5KV0sWyJiYWNrdGlja3MiLG4oNjgwKV0sWyJzdHJpa2V0aHJvdWdoIixuKDI5NikudG9rZW5pemVdLFsiZW1waGFzaXMiLG4oMjk3KS50b2tlbml6ZV0sWyJsaW5rIixuKDY4MSldLFsiaW1hZ2UiLG4oNjgyKV0sWyJhdXRvbGluayIsbig2ODMpXSxbImh0bWxfaW5saW5lIixuKDY4NCldLFsiZW50aXR5IixuKDY4NSldXSxhPVtbImJhbGFuY2VfcGFpcnMiLG4oNjg2KV0sWyJzdHJpa2V0aHJvdWdoIixuKDI5NikucG9zdFByb2Nlc3NdLFsiZW1waGFzaXMiLG4oMjk3KS5wb3N0UHJvY2Vzc10sWyJ0ZXh0X2NvbGxhcHNlIixuKDY4NyldXTtyLnByb3RvdHlwZS5za2lwVG9rZW49ZnVuY3Rpb24oZSl7dmFyIHQsbixyPWUucG9zLGk9dGhpcy5ydWxlci5nZXRSdWxlcygiIiksbz1pLmxlbmd0aCxhPWUubWQub3B0aW9ucy5tYXhOZXN0aW5nLHM9ZS5jYWNoZTtpZigidW5kZWZpbmVkIiE9PXR5cGVvZiBzW3JdKXJldHVybiB2b2lkKGUucG9zPXNbcl0pO2lmKGUubGV2ZWw8YSlmb3Iobj0wO248byYmKGUubGV2ZWwrKyx0PWlbbl0oZSwhMCksZS5sZXZlbC0tLCF0KTtuKyspO2Vsc2UgZS5wb3M9ZS5wb3NNYXg7dHx8ZS5wb3MrKyxzW3JdPWUucG9zfSxyLnByb3RvdHlwZS50b2tlbml6ZT1mdW5jdGlvbihlKXtmb3IodmFyIHQsbixyPXRoaXMucnVsZXIuZ2V0UnVsZXMoIiIpLGk9ci5sZW5ndGgsbz1lLnBvc01heCxhPWUubWQub3B0aW9ucy5tYXhOZXN0aW5nO2UucG9zPG87KXtpZihlLmxldmVsPGEpZm9yKG49MDtuPGkmJiEodD1yW25dKGUsITEpKTtuKyspO2lmKHQpe2lmKGUucG9zPj1vKWJyZWFrfWVsc2UgZS5wZW5kaW5nKz1lLnNyY1tlLnBvcysrXX1lLnBlbmRpbmcmJmUucHVzaFBlbmRpbmcoKX0sci5wcm90b3R5cGUucGFyc2U9ZnVuY3Rpb24oZSx0LG4scil7dmFyIGksbyxhLHM9bmV3IHRoaXMuU3RhdGUoZSx0LG4scik7Zm9yKHRoaXMudG9rZW5pemUocyksbz10aGlzLnJ1bGVyMi5nZXRSdWxlcygiIiksYT1vLmxlbmd0aCxpPTA7aTxhO2krKylvW2ldKHMpfSxyLnByb3RvdHlwZS5TdGF0ZT1uKDY4OCksZS5leHBvcnRzPXJ9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtzd2l0Y2goZSl7Y2FzZSAxMDpjYXNlIDMzOmNhc2UgMzU6Y2FzZSAzNjpjYXNlIDM3OmNhc2UgMzg6Y2FzZSA0MjpjYXNlIDQzOmNhc2UgNDU6Y2FzZSA1ODpjYXNlIDYwOmNhc2UgNjE6Y2FzZSA2MjpjYXNlIDY0OmNhc2UgOTE6Y2FzZSA5MjpjYXNlIDkzOmNhc2UgOTQ6Y2FzZSA5NTpjYXNlIDk2OmNhc2UgMTIzOmNhc2UgMTI1OmNhc2UgMTI2OnJldHVybiEwO2RlZmF1bHQ6cmV0dXJuITF9fWUuZXhwb3J0cz1mdW5jdGlvbihlLHQpe2Zvcih2YXIgbj1lLnBvcztuPGUucG9zTWF4JiYhcihlLnNyYy5jaGFyQ29kZUF0KG4pKTspbisrO3JldHVybiBuIT09ZS5wb3MmJih0fHwoZS5wZW5kaW5nKz1lLnNyYy5zbGljZShlLnBvcyxuKSksZS5wb3M9biwhMCl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNSkuaXNTcGFjZTtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0KXt2YXIgbixpLG89ZS5wb3M7aWYoMTAhPT1lLnNyYy5jaGFyQ29kZUF0KG8pKXJldHVybiExO2ZvcihuPWUucGVuZGluZy5sZW5ndGgtMSxpPWUucG9zTWF4LHR8fChuPj0wJiYzMj09PWUucGVuZGluZy5jaGFyQ29kZUF0KG4pP24+PTEmJjMyPT09ZS5wZW5kaW5nLmNoYXJDb2RlQXQobi0xKT8oZS5wZW5kaW5nPWUucGVuZGluZy5yZXBsYWNlKC8gKyQvLCIiKSxlLnB1c2goImhhcmRicmVhayIsImJyIiwwKSk6KGUucGVuZGluZz1lLnBlbmRpbmcuc2xpY2UoMCwtMSksZS5wdXNoKCJzb2Z0YnJlYWsiLCJiciIsMCkpOmUucHVzaCgic29mdGJyZWFrIiwiYnIiLDApKSxvKys7bzxpJiZyKGUuc3JjLmNoYXJDb2RlQXQobykpOylvKys7cmV0dXJuIGUucG9zPW8sITB9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Zvcih2YXIgcj1uKDUpLmlzU3BhY2UsaT1bXSxvPTA7bzwyNTY7bysrKWkucHVzaCgwKTsiXFwhXCIjJCUmJygpKissLi86Ozw9Pj9AW11eX2B7fH1+LSIuc3BsaXQoIiIpLmZvckVhY2goZnVuY3Rpb24oZSl7aVtlLmNoYXJDb2RlQXQoMCldPTF9KSxlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0KXt2YXIgbixvPWUucG9zLGE9ZS5wb3NNYXg7aWYoOTIhPT1lLnNyYy5jaGFyQ29kZUF0KG8pKXJldHVybiExO2lmKCsrbzxhKXtpZigobj1lLnNyYy5jaGFyQ29kZUF0KG8pKTwyNTYmJjAhPT1pW25dKXJldHVybiB0fHwoZS5wZW5kaW5nKz1lLnNyY1tvXSksZS5wb3MrPTIsITA7aWYoMTA9PT1uKXtmb3IodHx8ZS5wdXNoKCJoYXJkYnJlYWsiLCJiciIsMCksbysrO288YSYmKG49ZS5zcmMuY2hhckNvZGVBdChvKSxyKG4pKTspbysrO3JldHVybiBlLnBvcz1vLCEwfX1yZXR1cm4gdHx8KGUucGVuZGluZys9IlxcIiksZS5wb3MrKywhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCl7dmFyIG4scixpLG8sYSxzLHU9ZS5wb3M7aWYoOTYhPT1lLnNyYy5jaGFyQ29kZUF0KHUpKXJldHVybiExO2ZvcihuPXUsdSsrLHI9ZS5wb3NNYXg7dTxyJiY5Nj09PWUuc3JjLmNoYXJDb2RlQXQodSk7KXUrKztmb3IoaT1lLnNyYy5zbGljZShuLHUpLG89YT11Oy0xIT09KG89ZS5zcmMuaW5kZXhPZigiYCIsYSkpOyl7Zm9yKGE9bysxO2E8ciYmOTY9PT1lLnNyYy5jaGFyQ29kZUF0KGEpOylhKys7aWYoYS1vPT09aS5sZW5ndGgpcmV0dXJuIHR8fChzPWUucHVzaCgiY29kZV9pbmxpbmUiLCJjb2RlIiwwKSxzLm1hcmt1cD1pLHMuY29udGVudD1lLnNyYy5zbGljZSh1LG8pLnJlcGxhY2UoL1sgXG5dKy9nLCIgIikudHJpbSgpKSxlLnBvcz1hLCEwfXJldHVybiB0fHwoZS5wZW5kaW5nKz1pKSxlLnBvcys9aS5sZW5ndGgsITB9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNSkubm9ybWFsaXplUmVmZXJlbmNlLGk9big1KS5pc1NwYWNlO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQpe3ZhciBuLG8sYSxzLHUsYyxsLHAsZixkLGg9IiIsbT1lLnBvcyxnPWUucG9zTWF4LHk9ZS5wb3Msdj0hMDtpZig5MSE9PWUuc3JjLmNoYXJDb2RlQXQoZS5wb3MpKXJldHVybiExO2lmKHU9ZS5wb3MrMSwocz1lLm1kLmhlbHBlcnMucGFyc2VMaW5rTGFiZWwoZSxlLnBvcywhMCkpPDApcmV0dXJuITE7aWYoKGM9cysxKTxnJiY0MD09PWUuc3JjLmNoYXJDb2RlQXQoYykpe2Zvcih2PSExLGMrKztjPGcmJihvPWUuc3JjLmNoYXJDb2RlQXQoYyksaShvKXx8MTA9PT1vKTtjKyspO2lmKGM+PWcpcmV0dXJuITE7Zm9yKHk9YyxsPWUubWQuaGVscGVycy5wYXJzZUxpbmtEZXN0aW5hdGlvbihlLnNyYyxjLGUucG9zTWF4KSxsLm9rJiYoaD1lLm1kLm5vcm1hbGl6ZUxpbmsobC5zdHIpLGUubWQudmFsaWRhdGVMaW5rKGgpP2M9bC5wb3M6aD0iIikseT1jO2M8ZyYmKG89ZS5zcmMuY2hhckNvZGVBdChjKSxpKG8pfHwxMD09PW8pO2MrKyk7aWYobD1lLm1kLmhlbHBlcnMucGFyc2VMaW5rVGl0bGUoZS5zcmMsYyxlLnBvc01heCksYzxnJiZ5IT09YyYmbC5vaylmb3IoZj1sLnN0cixjPWwucG9zO2M8ZyYmKG89ZS5zcmMuY2hhckNvZGVBdChjKSxpKG8pfHwxMD09PW8pO2MrKyk7ZWxzZSBmPSIiOyhjPj1nfHw0MSE9PWUuc3JjLmNoYXJDb2RlQXQoYykpJiYodj0hMCksYysrfWlmKHYpe2lmKCJ1bmRlZmluZWQiPT09dHlwZW9mIGUuZW52LnJlZmVyZW5jZXMpcmV0dXJuITE7aWYoYzxnJiY5MT09PWUuc3JjLmNoYXJDb2RlQXQoYyk/KHk9YysxLGM9ZS5tZC5oZWxwZXJzLnBhcnNlTGlua0xhYmVsKGUsYyksYz49MD9hPWUuc3JjLnNsaWNlKHksYysrKTpjPXMrMSk6Yz1zKzEsYXx8KGE9ZS5zcmMuc2xpY2UodSxzKSksIShwPWUuZW52LnJlZmVyZW5jZXNbcihhKV0pKXJldHVybiBlLnBvcz1tLCExO2g9cC5ocmVmLGY9cC50aXRsZX1yZXR1cm4gdHx8KGUucG9zPXUsZS5wb3NNYXg9cyxkPWUucHVzaCgibGlua19vcGVuIiwiYSIsMSksZC5hdHRycz1uPVtbImhyZWYiLGhdXSxmJiZuLnB1c2goWyJ0aXRsZSIsZl0pLGUubWQuaW5saW5lLnRva2VuaXplKGUpLGQ9ZS5wdXNoKCJsaW5rX2Nsb3NlIiwiYSIsLTEpKSxlLnBvcz1jLGUucG9zTWF4PWcsITB9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNSkubm9ybWFsaXplUmVmZXJlbmNlLGk9big1KS5pc1NwYWNlO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQpe3ZhciBuLG8sYSxzLHUsYyxsLHAsZixkLGgsbSxnLHk9IiIsdj1lLnBvcyxiPWUucG9zTWF4O2lmKDMzIT09ZS5zcmMuY2hhckNvZGVBdChlLnBvcykpcmV0dXJuITE7aWYoOTEhPT1lLnNyYy5jaGFyQ29kZUF0KGUucG9zKzEpKXJldHVybiExO2lmKGM9ZS5wb3MrMiwodT1lLm1kLmhlbHBlcnMucGFyc2VMaW5rTGFiZWwoZSxlLnBvcysxLCExKSk8MClyZXR1cm4hMTtpZigobD11KzEpPGImJjQwPT09ZS5zcmMuY2hhckNvZGVBdChsKSl7Zm9yKGwrKztsPGImJihvPWUuc3JjLmNoYXJDb2RlQXQobCksaShvKXx8MTA9PT1vKTtsKyspO2lmKGw+PWIpcmV0dXJuITE7Zm9yKGc9bCxmPWUubWQuaGVscGVycy5wYXJzZUxpbmtEZXN0aW5hdGlvbihlLnNyYyxsLGUucG9zTWF4KSxmLm9rJiYoeT1lLm1kLm5vcm1hbGl6ZUxpbmsoZi5zdHIpLGUubWQudmFsaWRhdGVMaW5rKHkpP2w9Zi5wb3M6eT0iIiksZz1sO2w8YiYmKG89ZS5zcmMuY2hhckNvZGVBdChsKSxpKG8pfHwxMD09PW8pO2wrKyk7aWYoZj1lLm1kLmhlbHBlcnMucGFyc2VMaW5rVGl0bGUoZS5zcmMsbCxlLnBvc01heCksbDxiJiZnIT09bCYmZi5vaylmb3IoZD1mLnN0cixsPWYucG9zO2w8YiYmKG89ZS5zcmMuY2hhckNvZGVBdChsKSxpKG8pfHwxMD09PW8pO2wrKyk7ZWxzZSBkPSIiO2lmKGw+PWJ8fDQxIT09ZS5zcmMuY2hhckNvZGVBdChsKSlyZXR1cm4gZS5wb3M9diwhMTtsKyt9ZWxzZXtpZigidW5kZWZpbmVkIj09PXR5cGVvZiBlLmVudi5yZWZlcmVuY2VzKXJldHVybiExO2lmKGw8YiYmOTE9PT1lLnNyYy5jaGFyQ29kZUF0KGwpPyhnPWwrMSxsPWUubWQuaGVscGVycy5wYXJzZUxpbmtMYWJlbChlLGwpLGw+PTA/cz1lLnNyYy5zbGljZShnLGwrKyk6bD11KzEpOmw9dSsxLHN8fChzPWUuc3JjLnNsaWNlKGMsdSkpLCEocD1lLmVudi5yZWZlcmVuY2VzW3IocyldKSlyZXR1cm4gZS5wb3M9diwhMTt5PXAuaHJlZixkPXAudGl0bGV9cmV0dXJuIHR8fChhPWUuc3JjLnNsaWNlKGMsdSksZS5tZC5pbmxpbmUucGFyc2UoYSxlLm1kLGUuZW52LG09W10pLGg9ZS5wdXNoKCJpbWFnZSIsImltZyIsMCksaC5hdHRycz1uPVtbInNyYyIseV0sWyJhbHQiLCIiXV0saC5jaGlsZHJlbj1tLGguY29udGVudD1hLGQmJm4ucHVzaChbInRpdGxlIixkXSkpLGUucG9zPWwsZS5wb3NNYXg9YiwhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9L148KFthLXpBLVowLTkuISMkJSYnKitcLz0/Xl9ge3x9fi1dK0BbYS16QS1aMC05XSg/OlthLXpBLVowLTktXXswLDYxfVthLXpBLVowLTldKT8oPzpcLlthLXpBLVowLTldKD86W2EtekEtWjAtOS1dezAsNjF9W2EtekEtWjAtOV0pPykqKT4vLGk9L148KFthLXpBLVpdW2EtekEtWjAtOSsuXC1dezEsMzF9KTooW148Plx4MDAtXHgyMF0qKT4vO2UuZXhwb3J0cz1mdW5jdGlvbihlLHQpe3ZhciBuLG8sYSxzLHUsYyxsPWUucG9zO3JldHVybiA2MD09PWUuc3JjLmNoYXJDb2RlQXQobCkmJihuPWUuc3JjLnNsaWNlKGwpLCEobi5pbmRleE9mKCI+Iik8MCkmJihpLnRlc3Qobik/KG89bi5tYXRjaChpKSxzPW9bMF0uc2xpY2UoMSwtMSksdT1lLm1kLm5vcm1hbGl6ZUxpbmsocyksISFlLm1kLnZhbGlkYXRlTGluayh1KSYmKHR8fChjPWUucHVzaCgibGlua19vcGVuIiwiYSIsMSksYy5hdHRycz1bWyJocmVmIix1XV0sYy5tYXJrdXA9ImF1dG9saW5rIixjLmluZm89ImF1dG8iLGM9ZS5wdXNoKCJ0ZXh0IiwiIiwwKSxjLmNvbnRlbnQ9ZS5tZC5ub3JtYWxpemVMaW5rVGV4dChzKSxjPWUucHVzaCgibGlua19jbG9zZSIsImEiLC0xKSxjLm1hcmt1cD0iYXV0b2xpbmsiLGMuaW5mbz0iYXV0byIpLGUucG9zKz1vWzBdLmxlbmd0aCwhMCkpOiEhci50ZXN0KG4pJiYoYT1uLm1hdGNoKHIpLHM9YVswXS5zbGljZSgxLC0xKSx1PWUubWQubm9ybWFsaXplTGluaygibWFpbHRvOiIrcyksISFlLm1kLnZhbGlkYXRlTGluayh1KSYmKHR8fChjPWUucHVzaCgibGlua19vcGVuIiwiYSIsMSksYy5hdHRycz1bWyJocmVmIix1XV0sYy5tYXJrdXA9ImF1dG9saW5rIixjLmluZm89ImF1dG8iLGM9ZS5wdXNoKCJ0ZXh0IiwiIiwwKSxjLmNvbnRlbnQ9ZS5tZC5ub3JtYWxpemVMaW5rVGV4dChzKSxjPWUucHVzaCgibGlua19jbG9zZSIsImEiLC0xKSxjLm1hcmt1cD0iYXV0b2xpbmsiLGMuaW5mbz0iYXV0byIpLGUucG9zKz1hWzBdLmxlbmd0aCwhMCkpKSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dmFyIHQ9MzJ8ZTtyZXR1cm4gdD49OTcmJnQ8PTEyMn12YXIgaT1uKDI5NSkuSFRNTF9UQUdfUkU7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCl7dmFyIG4sbyxhLHMsdT1lLnBvcztyZXR1cm4hIWUubWQub3B0aW9ucy5odG1sJiYoYT1lLnBvc01heCwhKDYwIT09ZS5zcmMuY2hhckNvZGVBdCh1KXx8dSsyPj1hKSYmKCEoMzMhPT0obj1lLnNyYy5jaGFyQ29kZUF0KHUrMSkpJiY2MyE9PW4mJjQ3IT09biYmIXIobikpJiYoISEobz1lLnNyYy5zbGljZSh1KS5tYXRjaChpKSkmJih0fHwocz1lLnB1c2goImh0bWxfaW5saW5lIiwiIiwwKSxzLmNvbnRlbnQ9ZS5zcmMuc2xpY2UodSx1K29bMF0ubGVuZ3RoKSksZS5wb3MrPW9bMF0ubGVuZ3RoLCEwKSkpKX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9bigyOTQpLGk9big1KS5oYXMsbz1uKDUpLmlzVmFsaWRFbnRpdHlDb2RlLGE9big1KS5mcm9tQ29kZVBvaW50LHM9L14mIygoPzp4W2EtZjAtOV17MSw4fXxbMC05XXsxLDh9KSk7L2ksdT0vXiYoW2Etel1bYS16MC05XXsxLDMxfSk7L2k7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCl7dmFyIG4sYyxsPWUucG9zLHA9ZS5wb3NNYXg7aWYoMzghPT1lLnNyYy5jaGFyQ29kZUF0KGwpKXJldHVybiExO2lmKGwrMTxwKWlmKDM1PT09ZS5zcmMuY2hhckNvZGVBdChsKzEpKXtpZihjPWUuc3JjLnNsaWNlKGwpLm1hdGNoKHMpKXJldHVybiB0fHwobj0ieCI9PT1jWzFdWzBdLnRvTG93ZXJDYXNlKCk/cGFyc2VJbnQoY1sxXS5zbGljZSgxKSwxNik6cGFyc2VJbnQoY1sxXSwxMCksZS5wZW5kaW5nKz1hKG8obik/bjo2NTUzMykpLGUucG9zKz1jWzBdLmxlbmd0aCwhMH1lbHNlIGlmKChjPWUuc3JjLnNsaWNlKGwpLm1hdGNoKHUpKSYmaShyLGNbMV0pKXJldHVybiB0fHwoZS5wZW5kaW5nKz1yW2NbMV1dKSxlLnBvcys9Y1swXS5sZW5ndGgsITA7cmV0dXJuIHR8fChlLnBlbmRpbmcrPSImIiksZS5wb3MrKywhMH19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0LG4scixpLG89ZS5kZWxpbWl0ZXJzLGE9ZS5kZWxpbWl0ZXJzLmxlbmd0aDtmb3IodD0wO3Q8YTt0KyspaWYocj1vW3RdLHIuY2xvc2UpZm9yKG49dC1yLmp1bXAtMTtuPj0wOyl7aWYoaT1vW25dLGkub3BlbiYmaS5tYXJrZXI9PT1yLm1hcmtlciYmaS5lbmQ8MCYmaS5sZXZlbD09PXIubGV2ZWwpe3ZhciBzPShpLmNsb3NlfHxyLm9wZW4pJiYidW5kZWZpbmVkIiE9PXR5cGVvZiBpLmxlbmd0aCYmInVuZGVmaW5lZCIhPT10eXBlb2Ygci5sZW5ndGgmJihpLmxlbmd0aCtyLmxlbmd0aCklMz09PTA7aWYoIXMpe3IuanVtcD10LW4sci5vcGVuPSExLGkuZW5kPXQsaS5qdW1wPTA7YnJlYWt9fW4tPWkuanVtcCsxfX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZS5leHBvcnRzPWZ1bmN0aW9uKGUpe3ZhciB0LG4scj0wLGk9ZS50b2tlbnMsbz1lLnRva2Vucy5sZW5ndGg7Zm9yKHQ9bj0wO3Q8bzt0Kyspcis9aVt0XS5uZXN0aW5nLGlbdF0ubGV2ZWw9ciwidGV4dCI9PT1pW3RdLnR5cGUmJnQrMTxvJiYidGV4dCI9PT1pW3QrMV0udHlwZT9pW3QrMV0uY29udGVudD1pW3RdLmNvbnRlbnQraVt0KzFdLmNvbnRlbnQ6KHQhPT1uJiYoaVtuXT1pW3RdKSxuKyspO3QhPT1uJiYoaS5sZW5ndGg9bil9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0LG4scil7dGhpcy5zcmM9ZSx0aGlzLmVudj1uLHRoaXMubWQ9dCx0aGlzLnRva2Vucz1yLHRoaXMucG9zPTAsdGhpcy5wb3NNYXg9dGhpcy5zcmMubGVuZ3RoLHRoaXMubGV2ZWw9MCx0aGlzLnBlbmRpbmc9IiIsdGhpcy5wZW5kaW5nTGV2ZWw9MCx0aGlzLmNhY2hlPXt9LHRoaXMuZGVsaW1pdGVycz1bXX12YXIgaT1uKDE0NSksbz1uKDUpLmlzV2hpdGVTcGFjZSxhPW4oNSkuaXNQdW5jdENoYXIscz1uKDUpLmlzTWRBc2NpaVB1bmN0O3IucHJvdG90eXBlLnB1c2hQZW5kaW5nPWZ1bmN0aW9uKCl7dmFyIGU9bmV3IGkoInRleHQiLCIiLDApO3JldHVybiBlLmNvbnRlbnQ9dGhpcy5wZW5kaW5nLGUubGV2ZWw9dGhpcy5wZW5kaW5nTGV2ZWwsdGhpcy50b2tlbnMucHVzaChlKSx0aGlzLnBlbmRpbmc9IiIsZX0sci5wcm90b3R5cGUucHVzaD1mdW5jdGlvbihlLHQsbil7dGhpcy5wZW5kaW5nJiZ0aGlzLnB1c2hQZW5kaW5nKCk7dmFyIHI9bmV3IGkoZSx0LG4pO3JldHVybiBuPDAmJnRoaXMubGV2ZWwtLSxyLmxldmVsPXRoaXMubGV2ZWwsbj4wJiZ0aGlzLmxldmVsKyssdGhpcy5wZW5kaW5nTGV2ZWw9dGhpcy5sZXZlbCx0aGlzLnRva2Vucy5wdXNoKHIpLHJ9LHIucHJvdG90eXBlLnNjYW5EZWxpbXM9ZnVuY3Rpb24oZSx0KXt2YXIgbixyLGksdSxjLGwscCxmLGQsaD1lLG09ITAsZz0hMCx5PXRoaXMucG9zTWF4LHY9dGhpcy5zcmMuY2hhckNvZGVBdChlKTtmb3Iobj1lPjA/dGhpcy5zcmMuY2hhckNvZGVBdChlLTEpOjMyO2g8eSYmdGhpcy5zcmMuY2hhckNvZGVBdChoKT09PXY7KWgrKztyZXR1cm4gaT1oLWUscj1oPHk/dGhpcy5zcmMuY2hhckNvZGVBdChoKTozMixwPXMobil8fGEoU3RyaW5nLmZyb21DaGFyQ29kZShuKSksZD1zKHIpfHxhKFN0cmluZy5mcm9tQ2hhckNvZGUocikpLGw9byhuKSxmPW8ociksZj9tPSExOmQmJihsfHxwfHwobT0hMSkpLGw/Zz0hMTpwJiYoZnx8ZHx8KGc9ITEpKSx0Pyh1PW0sYz1nKToodT1tJiYoIWd8fHApLGM9ZyYmKCFtfHxkKSkse2Nhbl9vcGVuOnUsY2FuX2Nsb3NlOmMsbGVuZ3RoOml9fSxyLnByb3RvdHlwZS5Ub2tlbj1pLGUuZXhwb3J0cz1yfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz17b3B0aW9uczp7aHRtbDohMSx4aHRtbE91dDohMSxicmVha3M6ITEsbGFuZ1ByZWZpeDoibGFuZ3VhZ2UtIixsaW5raWZ5OiExLHR5cG9ncmFwaGVyOiExLHF1b3RlczoiXHUyMDFjXHUyMDFkXHUyMDE4XHUyMDE5IixoaWdobGlnaHQ6bnVsbCxtYXhOZXN0aW5nOjEwMH0sY29tcG9uZW50czp7Y29yZTp7fSxibG9jazp7fSxpbmxpbmU6e319fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtlLmV4cG9ydHM9e29wdGlvbnM6e2h0bWw6ITEseGh0bWxPdXQ6ITEsYnJlYWtzOiExLGxhbmdQcmVmaXg6Imxhbmd1YWdlLSIsbGlua2lmeTohMSx0eXBvZ3JhcGhlcjohMSxxdW90ZXM6Ilx1MjAxY1x1MjAxZFx1MjAxOFx1MjAxOSIsaGlnaGxpZ2h0Om51bGwsbWF4TmVzdGluZzoyMH0sY29tcG9uZW50czp7Y29yZTp7cnVsZXM6WyJub3JtYWxpemUiLCJibG9jayIsImlubGluZSJdfSxibG9jazp7cnVsZXM6WyJwYXJhZ3JhcGgiXX0saW5saW5lOntydWxlczpbInRleHQiXSxydWxlczI6WyJiYWxhbmNlX3BhaXJzIiwidGV4dF9jb2xsYXBzZSJdfX19fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2UuZXhwb3J0cz17b3B0aW9uczp7aHRtbDohMCx4aHRtbE91dDohMCxicmVha3M6ITEsbGFuZ1ByZWZpeDoibGFuZ3VhZ2UtIixsaW5raWZ5OiExLHR5cG9ncmFwaGVyOiExLHF1b3RlczoiXHUyMDFjXHUyMDFkXHUyMDE4XHUyMDE5IixoaWdobGlnaHQ6bnVsbCxtYXhOZXN0aW5nOjIwfSxjb21wb25lbnRzOntjb3JlOntydWxlczpbIm5vcm1hbGl6ZSIsImJsb2NrIiwiaW5saW5lIl19LGJsb2NrOntydWxlczpbImJsb2NrcXVvdGUiLCJjb2RlIiwiZmVuY2UiLCJoZWFkaW5nIiwiaHIiLCJodG1sX2Jsb2NrIiwibGhlYWRpbmciLCJsaXN0IiwicmVmZXJlbmNlIiwicGFyYWdyYXBoIl19LGlubGluZTp7cnVsZXM6WyJhdXRvbGluayIsImJhY2t0aWNrcyIsImVtcGhhc2lzIiwiZW50aXR5IiwiZXNjYXBlIiwiaHRtbF9pbmxpbmUiLCJpbWFnZSIsImxpbmsiLCJuZXdsaW5lIiwidGV4dCJdLHJ1bGVzMjpbImJhbGFuY2VfcGFpcnMiLCJlbXBoYXNpcyIsInRleHRfY29sbGFwc2UiXX19fX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDcpLG89bigwKSxhPW4oNTEpLHM9bigxKTt0LmRlZmF1bHQ9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS50eXBlLG49ZS5maWVsZHMscj1lLmludGVyZmFjZXMscz1lLmxldmVsLHU9bi5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIWUuaXNEZXByZWNhdGVkfSksYz1uLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4gZS5pc0RlcHJlY2F0ZWR9KSxsPXQgaW5zdGFuY2VvZiBpLkdyYXBoUUxJbnRlcmZhY2VUeXBlPyJpbnRlcmZhY2UgIjoidHlwZSI7cmV0dXJuIG8uY3JlYXRlRWxlbWVudChoLG51bGwsby5jcmVhdGVFbGVtZW50KG0sbnVsbCxvLmNyZWF0ZUVsZW1lbnQoInNwYW4iLHtjbGFzc05hbWU6ImZpZWxkLW5hbWUifSxsKSwiICIsby5jcmVhdGVFbGVtZW50KGcsbnVsbCx0Lm5hbWUpLCIgIiwwPT09ci5sZW5ndGgmJm8uY3JlYXRlRWxlbWVudChiLG51bGwsInsiKSksci5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KHkse2tleTplLm5hbWUsdHlwZTplLHg6cyx5OnQsY29sbGFwc2FibGU6ITAsYmVmb3JlTm9kZTpvLmNyZWF0ZUVsZW1lbnQoInNwYW4iLHtjbGFzc05hbWU6ImZpZWxkLW5hbWUifSwiaW1wbGVtZW50cyIpLGFmdGVyTm9kZTp0PT09ci5sZW5ndGgtMT9vLmNyZWF0ZUVsZW1lbnQoYixudWxsLCJ7Iik6bnVsbCxsYXN0QWN0aXZlOiExfSl9KSx1Lm1hcChmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoYS5kZWZhdWx0LHtrZXk6ZS5uYW1lLHR5cGU6ZSx4OnMseTp0K3IubGVuZ3RoLGNvbGxhcHNhYmxlOiEwLGxhc3RBY3RpdmU6ITF9KX0pLGMubGVuZ3RoPjAmJm8uY3JlYXRlRWxlbWVudCgiYnIiLG51bGwpLGMubWFwKGZ1bmN0aW9uKGUsdCl7cmV0dXJuIG8uY3JlYXRlRWxlbWVudCgiZGl2Iix7a2V5OmUubmFtZX0sby5jcmVhdGVFbGVtZW50KHYsbnVsbCwiIyBEZXByZWNhdGVkOiAiLGUuZGVwcmVjYXRpb25SZWFzb24pLG8uY3JlYXRlRWxlbWVudChhLmRlZmF1bHQse3R5cGU6ZSx4OnMseTp0K3UubGVuZ3RoK3IubGVuZ3RoLGNvbGxhcHNhYmxlOiEwLGxhc3RBY3RpdmU6ITF9KSl9KSxvLmNyZWF0ZUVsZW1lbnQobSxudWxsLG8uY3JlYXRlRWxlbWVudChiLG51bGwsIn0iKSkpfTt2YXIgdSxjLGwscCxmLGQsaD1zLnN0eWxlZC5kaXYodXx8KHU9cihbIlxuICBmb250LXNpemU6IDE0cHg7XG4gIG92ZXJmbG93OiBhdXRvO1xuICAuZG9jLWNhdGVnb3J5LWl0ZW0ge1xuICAgIHBhZGRpbmctbGVmdDogMzJweDtcbiAgfVxuIl0sWyJcbiAgZm9udC1zaXplOiAxNHB4O1xuICBvdmVyZmxvdzogYXV0bztcbiAgLmRvYy1jYXRlZ29yeS1pdGVtIHtcbiAgICBwYWRkaW5nLWxlZnQ6IDMycHg7XG4gIH1cbiJdKSkpLG09cy5zdHlsZWQuZGl2KGN8fChjPXIoWyJcbiAgcGFkZGluZzogNnB4IDE2cHg7XG4gIHdoaXRlLXNwYWNlOiBub3dyYXA7XG4iXSxbIlxuICBwYWRkaW5nOiA2cHggMTZweDtcbiAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiJdKSkpLGc9cy5zdHlsZWQuc3BhbihsfHwobD1yKFsiXG4gIGNvbG9yOiAjZjI1YzU0O1xuIl0sWyJcbiAgY29sb3I6ICNmMjVjNTQ7XG4iXSkpKSx5PXMuc3R5bGVkKGEuZGVmYXVsdCkocHx8KHA9cihbIlxuICBwYWRkaW5nLWxlZnQ6IDE2cHg7XG4gIC5maWVsZC1uYW1lIHtcbiAgICBjb2xvcjogcmdiKDI0NSwgMTYwLCAwKTtcbiAgfVxuICAudHlwZS1uYW1lIHtcbiAgICBjb2xvcjogI2YyNWM1NDtcbiAgfVxuIl0sWyJcbiAgcGFkZGluZy1sZWZ0OiAxNnB4O1xuICAuZmllbGQtbmFtZSB7XG4gICAgY29sb3I6IHJnYigyNDUsIDE2MCwgMCk7XG4gIH1cbiAgLnR5cGUtbmFtZSB7XG4gICAgY29sb3I6ICNmMjVjNTQ7XG4gIH1cbiJdKSkpLHY9cy5zdHlsZWQuc3BhbihmfHwoZj1yKFsiXG4gIGNvbG9yOiAiLCI7XG4gIHBhZGRpbmctcmlnaHQ6IDE2cHg7XG4gIHBhZGRpbmctbGVmdDogMzJweDtcbiJdLFsiXG4gIGNvbG9yOiAiLCI7XG4gIHBhZGRpbmctcmlnaHQ6IDE2cHg7XG4gIHBhZGRpbmctbGVmdDogMzJweDtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5ibGFjazUwfSksYj1zLnN0eWxlZC5zcGFuKGR8fChkPXIoWyJcbiAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgY29sb3I6ICIsIjtcbiJdLFsiXG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIGNvbG9yOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMuZGFya0JsdWU1MH0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDApLGk9bigxNDYpLG89ZnVuY3Rpb24oZSl7dmFyIHQ9ZS50eXBlO3JldHVybiByLmNyZWF0ZUVsZW1lbnQoaS5Eb2NUeXBlLHtjbGFzc05hbWU6ImRvYy10eXBlLXNjaGVtYSJ9LHIuY3JlYXRlRWxlbWVudCgic3BhbiIse2NsYXNzTmFtZToiZmllbGQtbmFtZSJ9LCJzY2FsYXIiKSwiICIsci5jcmVhdGVFbGVtZW50KCJzcGFuIix7Y2xhc3NOYW1lOiJ0eXBlLW5hbWUifSx0Lm5hbWUpKX07dC5kZWZhdWx0PW99LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigwKSxvPW4oMSksYT1uKDE0Nikscz1mdW5jdGlvbihlKXt2YXIgdD1lLnR5cGUsbj1lLnNkbFR5cGUscj1uP3QuX3ZhbHVlczp0LmdldFZhbHVlcygpLG89ci5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIGUuaXNEZXByZWNhdGVkfSk7cmV0dXJuIGkuY3JlYXRlRWxlbWVudChhLkRvY1R5cGUse2NsYXNzTmFtZToiZG9jLXR5cGUtc2NoZW1hIn0saS5jcmVhdGVFbGVtZW50KCJzcGFuIix7Y2xhc3NOYW1lOiJmaWVsZC1uYW1lIn0sImVudW0iKSwiICIsaS5jcmVhdGVFbGVtZW50KCJzcGFuIix7Y2xhc3NOYW1lOiJ0eXBlLW5hbWUifSx0Lm5hbWUpLCIgIixpLmNyZWF0ZUVsZW1lbnQoInNwYW4iLHtjbGFzc05hbWU6ImJyYWNlIn0sInsiKSxyLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4hZS5pc0RlcHJlY2F0ZWR9KS5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4gaS5jcmVhdGVFbGVtZW50KGwse2tleTplLm5hbWUsZmlyc3Q6MD09PXQsdmFsdWU6ZX0pfSksby5sZW5ndGg+MCYmaS5jcmVhdGVFbGVtZW50KCJiciIsbnVsbCksby5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4gaS5jcmVhdGVFbGVtZW50KGwse2ZpcnN0OjA9PT10LGtleTplLm5hbWUsdmFsdWU6ZSxpc0RlcHJlY2F0ZWQ6ITB9KX0pLGkuY3JlYXRlRWxlbWVudCgic3BhbiIse2NsYXNzTmFtZToiYnJhY2UifSwifSIpKX07dC5kZWZhdWx0PXM7dmFyIHUsYyxsPWZ1bmN0aW9uKGUpe3ZhciB0PWUudmFsdWUsbj1lLmlzRGVwcmVjYXRlZCxyPWUuZmlyc3Q7cmV0dXJuIGkuY3JlYXRlRWxlbWVudChwLHtmaXJzdDpyfSxpLmNyZWF0ZUVsZW1lbnQoImRpdiIse2NsYXNzTmFtZToiZmllbGQtbmFtZSJ9LHQubmFtZSksdC5kZXNjcmlwdGlvbiYmaS5jcmVhdGVFbGVtZW50KGYsbnVsbCx0LmRlc2NyaXB0aW9uKSxuJiZpLmNyZWF0ZUVsZW1lbnQoZixudWxsLCJEZXByZWNhdGVkOiAiLHQuZGVwcmVjYXRpb25SZWFzb24pKX0scD1vLnN0eWxlZCgiZGl2IikodXx8KHU9cihbIlxuICBtYXJnaW4tdG9wOiAiLCJweDtcbiAgLmZpZWxkLW5hbWUge1xuICAgIHBhZGRpbmc6IDAgMTZweDtcbiAgICBjb2xvcjogcmVkO1xuICB9XG4iXSxbIlxuICBtYXJnaW4tdG9wOiAiLCJweDtcbiAgLmZpZWxkLW5hbWUge1xuICAgIHBhZGRpbmc6IDAgMTZweDtcbiAgICBjb2xvcjogcmVkO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmZpcnN0PzA6Nn0pLGY9by5zdHlsZWQuZGl2KGN8fChjPXIoWyJcbiAgcGFkZGluZzogMCAxNnB4O1xuICBjb2xvcjogIiwiO1xuIl0sWyJcbiAgcGFkZGluZzogMCAxNnB4O1xuICBjb2xvcjogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5jb2xvdXJzLmJsYWNrNTB9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9big1MSksaT1uKDApLG89bigxNDYpLGE9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5zY2hlbWEsbj1lLnR5cGUsYT1lLmxldmVsLHM9ZS5zZXNzaW9uSWQsdT10LmdldFBvc3NpYmxlVHlwZXMobik7cmV0dXJuIGkuY3JlYXRlRWxlbWVudChvLkRvY1R5cGUse2NsYXNzTmFtZToiZG9jLXR5cGUtc2NoZW1hIn0saS5jcmVhdGVFbGVtZW50KCJzcGFuIix7Y2xhc3NOYW1lOiJmaWVsZC1uYW1lIn0sInVuaW9uIiksIiAiLGkuY3JlYXRlRWxlbWVudCgic3BhbiIse2NsYXNzTmFtZToidHlwZS1uYW1lIn0sbi5uYW1lKSwiID0gIix1Lm1hcChmdW5jdGlvbihlLHQpe3JldHVybiBpLmNyZWF0ZUVsZW1lbnQoci5kZWZhdWx0LHtrZXk6ZS5uYW1lLHR5cGU6ZSx4OmEseTp0KzEsY29sbGFwc2FibGU6ITAsc2Vzc2lvbklkOnMsbGFzdEFjdGl2ZTohMX0pfSkpfTt0LmRlZmF1bHQ9YX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPW4oMjk5KSxzPW4oNjk3KSx1PW4oNjk4KSxjPW4oMzAwKSxsPW4oMSkscD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7cmV0dXJuIG51bGwhPT1lJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpc31yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMsdD1lLnNlYXJjaFZhbHVlLG49ZS5zY2hlbWEscj1lLndpZHRoLGk9ZS5zZXNzaW9uSWQsbD1lLmhhbmRsZVNlYXJjaDtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGEuZGVmYXVsdCx7d2lkdGg6cixvdmVyZmxvdzohMX0sby5jcmVhdGVFbGVtZW50KGMuZGVmYXVsdCx7b25TZWFyY2g6bH0pLG8uY3JlYXRlRWxlbWVudChkLG51bGwsdCYmby5jcmVhdGVFbGVtZW50KHMuZGVmYXVsdCx7c2VhcmNoVmFsdWU6dCxzY2hlbWE6bixsZXZlbDowLHNlc3Npb25JZDppfSksIXQmJm8uY3JlYXRlRWxlbWVudCh1LmRlZmF1bHQse3NjaGVtYTpuLHNlc3Npb25JZDppfSkpKX0sdH0oby5QdXJlQ29tcG9uZW50KTt0LmRlZmF1bHQ9cDt2YXIgZixkPWwuc3R5bGVkLmRpdihmfHwoZj1pKFsiXG4gIG92ZXJmbG93OiBhdXRvO1xuIl0sWyJcbiAgb3ZlcmZsb3c6IGF1dG87XG4iXSkpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCl7dHJ5e3ZhciBuPXQucmVwbGFjZSgvW15fMC05QS1aYS16XS9nLGZ1bmN0aW9uKGUpe3JldHVybiJcXCIrZX0pO3JldHVybi0xIT09ZS5zZWFyY2gobmV3IFJlZ0V4cChuLCJpIikpfWNhdGNoKG4pe3JldHVybi0xIT09ZS50b0xvd2VyQ2FzZSgpLmluZGV4T2YodC50b0xvd2VyQ2FzZSgpKX19dmFyIGk9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKSxvPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBhPW4oMCkscz1uKDEpLHU9big1MSksYz1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7cmV0dXJuIG51bGwhPT1lJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpc31yZXR1cm4gaSh0LGUpLHQucHJvdG90eXBlLnNob3VsZENvbXBvbmVudFVwZGF0ZT1mdW5jdGlvbihlKXtyZXR1cm4gdGhpcy5wcm9wcy5zY2hlbWEhPT1lLnNjaGVtYXx8dGhpcy5wcm9wcy5zZWFyY2hWYWx1ZSE9PWUuc2VhcmNoVmFsdWV9LHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMubGV2ZWwsdD10aGlzLnByb3BzLnNlYXJjaFZhbHVlLG49dGhpcy5wcm9wcy53aXRoaW5UeXBlLGk9dGhpcy5wcm9wcy5zY2hlbWEsbz1bXSxzPVtdLGM9W10sbD1pLmdldFR5cGVNYXAoKSxmPU9iamVjdC5rZXlzKGwpO24mJihmPWYuZmlsdGVyKGZ1bmN0aW9uKGUpe3JldHVybiBlIT09bi5uYW1lfSksZi51bnNoaWZ0KG4ubmFtZSkpO2Zvcih2YXIgZD0wLGg9MCxtPWY7aDxtLmxlbmd0aDtoKyspe3ZhciBnPW1baF07aWYoImJyZWFrIj09PWZ1bmN0aW9uKGkpe2lmKG8ubGVuZ3RoK3MubGVuZ3RoK2MubGVuZ3RoPj0xMDApcmV0dXJuImJyZWFrIjt2YXIgcD1sW2ldO2lmKG4hPT1wJiZyKGksdCkmJnMucHVzaChhLmNyZWF0ZUVsZW1lbnQoImRpdiIse2NsYXNzTmFtZToiZG9jLWNhdGVnb3J5LWl0ZW0iLGtleTppfSxhLmNyZWF0ZUVsZW1lbnQodS5kZWZhdWx0LHt0eXBlOnAseDplLHk6ZCsrLGxhc3RBY3RpdmU6ITF9KSkpLHAuZ2V0RmllbGRzKXt2YXIgZj1wLmdldEZpZWxkcygpO09iamVjdC5rZXlzKGYpLmZvckVhY2goZnVuY3Rpb24ocyl7dmFyIGw9ZltzXTtsLnBhcmVudD1wO3ZhciBoO2lmKCFyKHMsdCkpe2lmKCFsLmFyZ3N8fCFsLmFyZ3MubGVuZ3RoKXJldHVybjtpZihoPWwuYXJncy5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIHIoZS5uYW1lLHQpfSksMD09PWgubGVuZ3RoKXJldHVybn12YXIgbT1hLmNyZWF0ZUVsZW1lbnQoImRpdiIse2NsYXNzTmFtZToiZG9jLWNhdGVnb3J5LWl0ZW0iLGtleTppKyIuIitzfSxhLmNyZWF0ZUVsZW1lbnQodS5kZWZhdWx0LHtrZXk6InR5cGUiLHR5cGU6bCx4OmUseTpkKyssc2hvd1BhcmVudE5hbWU6ITAsbGFzdEFjdGl2ZTohMX0pKTtuPT09cD9vLnB1c2gobSk6Yy5wdXNoKG0pfSl9fShnKSlicmVha31yZXR1cm4gby5sZW5ndGgrcy5sZW5ndGgrYy5sZW5ndGg9PT0wP2EuY3JlYXRlRWxlbWVudChwLG51bGwsIk5vIHJlc3VsdHMgZm91bmQuIik6biYmcy5sZW5ndGgrYy5sZW5ndGg+MD9hLmNyZWF0ZUVsZW1lbnQoImRpdiIsbnVsbCxvLGEuY3JlYXRlRWxlbWVudCgiZGl2Iix7Y2xhc3NOYW1lOiJkb2MtY2F0ZWdvcnkifSxhLmNyZWF0ZUVsZW1lbnQoImRpdiIse2NsYXNzTmFtZToiZG9jLWNhdGVnb3J5LXRpdGxlIn0sIm90aGVyIHJlc3VsdHMiKSxzLGMpKTphLmNyZWF0ZUVsZW1lbnQoImRpdiIsbnVsbCxvLHMsYyl9LHR9KGEuQ29tcG9uZW50KTt0LmRlZmF1bHQ9Yzt2YXIgbCxwPXMuc3R5bGVkLnNwYW4obHx8KGw9byhbIlxuICBkaXNwbGF5OiBibG9jaztcbiAgbWFyZ2luLXRvcDogMTZweDtcbiAgbWFyZ2luLWxlZnQ6IDE2cHg7XG4iXSxbIlxuICBkaXNwbGF5OiBibG9jaztcbiAgbWFyZ2luLXRvcDogMTZweDtcbiAgbWFyZ2luLWxlZnQ6IDE2cHg7XG4iXSkpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3ZhciB0PWUubmFtZSxuPWUuZmllbGRzLHI9ZS5vZmZzZXQ7cmV0dXJuIGEuY3JlYXRlRWxlbWVudCgiZGl2IixudWxsLGEuY3JlYXRlRWxlbWVudChjLkNhdGVnb3J5VGl0bGUsbnVsbCx0KSxuLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4hZS5pc0RlcHJlY2F0ZWR9KS5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4gYS5jcmVhdGVFbGVtZW50KHMuZGVmYXVsdCx7a2V5OmUubmFtZSx0eXBlOmUseDowLHk6cit0LGNvbGxhcHNhYmxlOiEwLGxhc3RBY3RpdmU6ITF9KX0pKX12YXIgaT1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLG89ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGE9bigwKSxzPW4oNTEpLHU9big2NiksYz1uKDI5OCksbD1uKDEpLHA9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3JldHVybiBudWxsIT09ZSYmZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fHRoaXN9cmV0dXJuIGkodCxlKSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnByb3BzLHQ9ZS5zY2hlbWEsbj1lLnNlc3Npb25JZCxpPXUuc2VyaWFsaXplUm9vdCh0KTtyZXR1cm4gYS5jcmVhdGVFbGVtZW50KGQse2NsYXNzTmFtZToiZG9jLXJvb3QifSxhLmNyZWF0ZUVsZW1lbnQocix7bmFtZToiUXVlcmllcyIsZmllbGRzOmkucXVlcmllcyxvZmZzZXQ6MCxzZXNzaW9uSWQ6bn0pLGkubXV0YXRpb25zLmxlbmd0aD4wJiZhLmNyZWF0ZUVsZW1lbnQocix7bmFtZToiTXV0YXRpb25zIixmaWVsZHM6aS5tdXRhdGlvbnMsb2Zmc2V0OmkucXVlcmllcy5sZW5ndGgsc2Vzc2lvbklkOm59KSxpLnN1YnNjcmlwdGlvbnMubGVuZ3RoPjAmJmEuY3JlYXRlRWxlbWVudChyLHtuYW1lOiJTdWJzY3JpcHRpb25zIixmaWVsZHM6aS5zdWJzY3JpcHRpb25zLG9mZnNldDppLnF1ZXJpZXMubGVuZ3RoK2kubXV0YXRpb25zLmxlbmd0aCxzZXNzaW9uSWQ6bn0pKX0sdH0oYS5QdXJlQ29tcG9uZW50KTt0LmRlZmF1bHQ9cDt2YXIgZixkPWwuc3R5bGVkLmRpdihmfHwoZj1vKFsiXG4gIHBhZGRpbmctbGVmdDogNnB4O1xuXG4gIC5kb2MtY2F0ZWdvcnktaXRlbSAuZmllbGQtbmFtZSB7XG4gICAgY29sb3I6ICNmMjVjNTQ7XG4gIH1cbiJdLFsiXG4gIHBhZGRpbmctbGVmdDogNnB4O1xuXG4gIC5kb2MtY2F0ZWdvcnktaXRlbSAuZmllbGQtbmFtZSB7XG4gICAgY29sb3I6ICNmMjVjNTQ7XG4gIH1cbiJdKSkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2YXIgbj12b2lkIDA7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIHI9dGhpcyxpPWFyZ3VtZW50cztjbGVhclRpbWVvdXQobiksbj1zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7bj1udWxsLHQuYXBwbHkocixpKX0sZSl9fU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KSx0LmRlZmF1bHQ9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPW4oMSkscz1uKDI0KSx1PW4oNzAxKSxjPW4oOSksbD1uKDgpLHA9bigxMiksZj1uKDE2KSxkPW4oMjQ2KSxoPWQuU29ydGFibGVFbGVtZW50KHUuZGVmYXVsdCksbT1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7dmFyIHQ9bnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzO3JldHVybiB0LnN0YXRlPXtzb3J0aW5nOiExfSx0Lm9uU29ydFN0YXJ0PWZ1bmN0aW9uKGUpe2UuaW5kZXg7dC5zZXRTdGF0ZSh7c29ydGluZzohMH0pfSx0Lm9uU29ydEVuZD1mdW5jdGlvbihlKXt2YXIgbj1lLm9sZEluZGV4LHI9ZS5uZXdJbmRleDt0LnByb3BzLnJlb3JkZXJUYWJzKG4sciksdC5zZXRTdGF0ZSh7c29ydGluZzohMX0pfSx0LmdldEhlbHBlckRpbWVuc2lvbnM9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5ub2RlLG49dC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtyZXR1cm57d2lkdGg6bi53aWR0aCxoZWlnaHQ6bi5oZWlnaHR9fSx0fXJldHVybiByKHQsZSksdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcyx0PWUuc2Vzc2lvbnMsbj1lLmlzQXBwLHI9ZS5zZWxlY3RlZFNlc3Npb25JZCxpPWUub25OZXdTZXNzaW9uLGE9dGhpcy5zdGF0ZS5zb3J0aW5nO3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoQyx7b25Tb3J0U3RhcnQ6dGhpcy5vblNvcnRTdGFydCxvblNvcnRFbmQ6dGhpcy5vblNvcnRFbmQsZ2V0SGVscGVyRGltZW5zaW9uczp0aGlzLmdldEhlbHBlckRpbWVuc2lvbnMsYXhpczoieCIsbG9ja0F4aXM6IngiLGxvY2tUb0NvbnRhaW5lckVkZ2VzOiEwLGRpc3RhbmNlOjEwLHRyYW5zaXRpb25EdXJhdGlvbjoyMDB9LG8uY3JlYXRlRWxlbWVudChFLHtpc0FwcDpufSx0Lm1hcChmdW5jdGlvbihlLHQpe3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoaCx7a2V5OmUuaWQsc2Vzc2lvbjplLHNlbGVjdGVkU2Vzc2lvbklkOnIsaW5kZXg6dH0pfSksby5jcmVhdGVFbGVtZW50KEQse29uQ2xpY2s6aSxzb3J0aW5nOmF9LG8uY3JlYXRlRWxlbWVudChzLkFkZEljb24se3dpZHRoOjM0LGhlaWdodDozNCxzdHJva2VXaWR0aDo0LHRpdGxlOiJPcGVucyBhIE5ldyBUYWIifSkpKSl9LHR9KG8uUHVyZUNvbXBvbmVudCksZz1sLmNyZWF0ZVN0cnVjdHVyZWRTZWxlY3Rvcih7c2Vzc2lvbnM6cC5nZXRTZXNzaW9uc0FycmF5LHNlbGVjdGVkU2Vzc2lvbklkOnAuZ2V0U2VsZWN0ZWRTZXNzaW9uSWRGcm9tUm9vdH0pO3QuZGVmYXVsdD1jLmNvbm5lY3QoZyx7cmVvcmRlclRhYnM6Zi5yZW9yZGVyVGFic30pKG0pO3ZhciB5LHYsYix4PWEuc3R5bGVkLmRpdih5fHwoeT1pKFsiXG4gIGNvbG9yOiB3aGl0ZTtcbiAgaGVpZ2h0OiA1N3B4O1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4gIC13ZWJraXQtYXBwLXJlZ2lvbjogZHJhZztcbiAgJjpob3ZlciB7XG4gICAgb3ZlcmZsb3cteDogb3ZlcmxheTtcbiAgfVxuIl0sWyJcbiAgY29sb3I6IHdoaXRlO1xuICBoZWlnaHQ6IDU3cHg7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgLXdlYmtpdC1hcHAtcmVnaW9uOiBkcmFnO1xuICAmOmhvdmVyIHtcbiAgICBvdmVyZmxvdy14OiBvdmVybGF5O1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuYmFja2dyb3VuZH0pLEM9ZC5Tb3J0YWJsZUNvbnRhaW5lcih4KSxFPWEuc3R5bGVkKCJkaXYiKSh2fHwodj1pKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIG1hcmdpbi10b3A6IDE2cHg7XG4gIHBhZGRpbmctbGVmdDogIiwiO1xuIl0sWyJcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgbWFyZ2luLXRvcDogMTZweDtcbiAgcGFkZGluZy1sZWZ0OiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzQXBwPyI0M3B4IjoiMCJ9KSxEPWEuc3R5bGVkKCJkaXYiKShifHwoYj1pKFsiXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIHZpc2liaWxpdHk6ICIsIlxuICBoZWlnaHQ6IDQzcHg7XG4gIHdpZHRoOiA0M3B4O1xuICBib3JkZXItcmFkaXVzOiAycHg7XG4gIGJvcmRlci1ib3R0b206IDJweCBzb2xpZCAiLCI7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIHN2ZyB7XG4gICAgc3Ryb2tlOiAiLCI7XG4gIH1cbiAgJjpob3ZlciB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4iXSxbIlxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICBkaXNwbGF5OiBmbGV4O1xuICB2aXNpYmlsaXR5OiAiLCJcbiAgaGVpZ2h0OiA0M3B4O1xuICB3aWR0aDogNDNweDtcbiAgYm9yZGVyLXJhZGl1czogMnB4O1xuICBib3JkZXItYm90dG9tOiAycHggc29saWQgIiwiO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBzdmcge1xuICAgIHN0cm9rZTogIiwiO1xuICB9XG4gICY6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS5zb3J0aW5nPyJoaWRkZW4iOiJ2aXNpYmxlIn0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5uYXZpZ2F0aW9uQmFyfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnRhYkluYWN0aXZlfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmljb259LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMudGFifSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKSxpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPW4oMCksYT1uKDI0KSxzPW4oOSksdT1uKDE2KSxjPW4oMSksbD1uKDcwMikscD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KHQpe3ZhciBuPWUuY2FsbCh0aGlzLHQpfHx0aGlzO3JldHVybiBuLnN0YXJ0RWRpdE5hbWU9ZnVuY3Rpb24oKXtuLnNldFN0YXRlKHtlZGl0aW5nTmFtZTohMH0pfSxuLnN0b3BFZGl0TmFtZT1mdW5jdGlvbigpe24uc2V0U3RhdGUoe2VkaXRpbmdOYW1lOiExfSl9LG4uaGFuZGxlS2V5RG93bj1mdW5jdGlvbihlKXsxMz09PWUua2V5Q29kZSYmbi5zZXRTdGF0ZSh7ZWRpdGluZ05hbWU6ITF9KX0sbi5oYW5kbGVNb3VzZU92ZXJDcm9zcz1mdW5jdGlvbigpe24uc2V0U3RhdGUoe292ZXJDcm9zczohMH0pfSxuLmhhbmRsZU1vdXNlT3V0Q3Jvc3M9ZnVuY3Rpb24oKXtuLnNldFN0YXRlKHtvdmVyQ3Jvc3M6ITF9KX0sbi5oYW5kbGVTZWxlY3RTZXNzaW9uPWZ1bmN0aW9uKCl7bi5wcm9wcy5zZWxlY3RUYWIobi5wcm9wcy5zZXNzaW9uLmlkKX0sbi5oYW5kbGVDbG9zZVNlc3Npb249ZnVuY3Rpb24oZSl7ZS5zdG9wUHJvcGFnYXRpb24oKSxuLnByb3BzLmNsb3NlVGFiKG4ucHJvcHMuc2Vzc2lvbi5pZCl9LG4uaGFuZGxlRWRpdE5hbWU9ZnVuY3Rpb24oZSl7bi5wcm9wcy5lZGl0TmFtZShlLnRhcmdldC52YWx1ZSl9LG4uc3RhdGU9e292ZXJDcm9zczohMSxlZGl0aW5nTmFtZTohMX0sbn1yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMsdD1lLnNlc3Npb24sbj1lLnNlbGVjdGVkU2Vzc2lvbklkLHI9dC5xdWVyeVR5cGVzLGk9dC5pZD09PW4scz10Lm5hbWV8fHQub3BlcmF0aW9uTmFtZXx8ci5maXJzdE9wZXJhdGlvbk5hbWV8fCJOZXcgVGFiIjtyZXR1cm4gby5jcmVhdGVFbGVtZW50KHcse2FjdGl2ZTppLG9uTW91c2VEb3duOnRoaXMuaGFuZGxlU2VsZWN0U2Vzc2lvbn0sby5jcmVhdGVFbGVtZW50KEEse2FjdGl2ZTppfSx0LnN1YnNjcmlwdGlvbkFjdGl2ZSYmby5jcmVhdGVFbGVtZW50KEksbnVsbCksby5jcmVhdGVFbGVtZW50KF8sbnVsbCxyLnF1ZXJ5JiZvLmNyZWF0ZUVsZW1lbnQoTyxudWxsLCJRIiksKHQuaXNTZXR0aW5nc1RhYnx8dC5pc0NvbmZpZ1RhYikmJm8uY3JlYXRlRWxlbWVudChPLG51bGwsby5jcmVhdGVFbGVtZW50KGEuU2V0dGluZ3NJY29uLHt3aWR0aDoxMixoZWlnaHQ6MTIsZmlsbDoid2hpdGUifSkpLHIubXV0YXRpb24mJm8uY3JlYXRlRWxlbWVudChGLG51bGwsIk0iKSxyLnN1YnNjcmlwdGlvbiYmby5jcmVhdGVFbGVtZW50KE4sbnVsbCwiUyIpKSksdGhpcy5zdGF0ZS5lZGl0aW5nTmFtZT9vLmNyZWF0ZUVsZW1lbnQoayx7dmFsdWU6dC5uYW1lfHwiIixvbkNoYW5nZTp0aGlzLmhhbmRsZUVkaXROYW1lLG9uQmx1cjp0aGlzLnN0b3BFZGl0TmFtZSxvbktleURvd246dGhpcy5oYW5kbGVLZXlEb3duLGF1dG9Gb2N1czohMH0pOm8uY3JlYXRlRWxlbWVudChTLHthY3RpdmU6aSxvbkRvdWJsZUNsaWNrOnRoaXMuc3RhcnRFZGl0TmFtZX0scyksby5jcmVhdGVFbGVtZW50KFAse2NsYXNzTmFtZToiY2xvc2UiLGFjdGl2ZTppLGhhc0NpcmNsZTp0LmlzRmlsZSYmdC5jaGFuZ2VkJiYhdGhpcy5zdGF0ZS5vdmVyQ3Jvc3Msb25DbGljazp0aGlzLmhhbmRsZUNsb3NlU2Vzc2lvbixvbk1vdXNlRW50ZXI6dGhpcy5oYW5kbGVNb3VzZU92ZXJDcm9zcyxvbk1vdXNlTGVhdmU6dGhpcy5oYW5kbGVNb3VzZU91dENyb3NzfSx0LmlzRmlsZSYmdC5jaGFuZ2VkJiYhdGhpcy5zdGF0ZS5vdmVyQ3Jvc3M/by5jcmVhdGVFbGVtZW50KEwsbnVsbCwiXHUyYjI0Iik6by5jcmVhdGVFbGVtZW50KGEuQ3Jvc3NJY29uLHt3aWR0aDoxMixoZWlnaHQ6MTEsc3Ryb2tlV2lkdGg6Nyx0aXRsZToiQ2xvc2UgVGFiIn0pKSl9LHR9KG8uUHVyZUNvbXBvbmVudCk7dC5kZWZhdWx0PXMuY29ubmVjdChudWxsLHtjbG9zZVRhYjp1LmNsb3NlVGFiLHNlbGVjdFRhYjp1LnNlbGVjdFRhYixlZGl0TmFtZTp1LmVkaXROYW1lfSkocCk7dmFyIGYsZCxoLG0sZyx5LHYsYix4LEMsRSxELHc9Yy5zdHlsZWQoImRpdiIpKGZ8fChmPWkoWyJcbiAgZmxleDogMCAwIGF1dG87XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGhlaWdodDogNDNweDtcbiAgcGFkZGluZzogMTBweDtcbiAgcGFkZGluZy10b3A6IDlweDtcbiAgbWFyZ2luLXJpZ2h0OiAxMHB4O1xuICBmb250LXNpemU6IDE0cHg7XG4gIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgYm9yZGVyLWJvdHRvbTogMnB4IHNvbGlkICIsIjtcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgYmFja2dyb3VuZDogIiwiO1xuICAmOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kOiAiLCI7XG4gICAgLmNsb3NlIHtcbiAgICAgIG9wYWNpdHk6IDE7XG4gICAgfVxuICB9XG4iXSxbIlxuICBmbGV4OiAwIDAgYXV0bztcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgaGVpZ2h0OiA0M3B4O1xuICBwYWRkaW5nOiAxMHB4O1xuICBwYWRkaW5nLXRvcDogOXB4O1xuICBtYXJnaW4tcmlnaHQ6IDEwcHg7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgYm9yZGVyLXJhZGl1czogMnB4O1xuICBib3JkZXItYm90dG9tOiAycHggc29saWQgIiwiO1xuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gICY6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgICAuY2xvc2Uge1xuICAgICAgb3BhY2l0eTogMTtcbiAgICB9XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5uYXZpZ2F0aW9uQmFyfSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hY3RpdmU/ZS50aGVtZS5lZGl0b3JDb2xvdXJzLnRhYjplLnRoZW1lLmVkaXRvckNvbG91cnMudGFiSW5hY3RpdmV9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMudGFifSksUz1jLnN0eWxlZCgiZGl2IikoZHx8KGQ9aShbIlxuICBvcGFjaXR5OiAiLCI7XG4gIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xuICBjb2xvcjogIiwiO1xuICBmb250LXNpemU6IDE0cHg7XG4gIG1hcmdpbi1sZWZ0OiAycHg7XG4gIGRpc3BsYXk6IGlubGluZTtcbiAgbGV0dGVyLXNwYWNpbmc6IDAuNTNweDtcbiJdLFsiXG4gIG9wYWNpdHk6ICIsIjtcbiAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XG4gIGNvbG9yOiAiLCI7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgbWFyZ2luLWxlZnQ6IDJweDtcbiAgZGlzcGxheTogaW5saW5lO1xuICBsZXR0ZXItc3BhY2luZzogMC41M3B4O1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hY3RpdmU/MTouNX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy50YWJUZXh0fSksaz1jLnN0eWxlZChsLmRlZmF1bHQpKGh8fChoPWkoWyJcbiAgaW5wdXQge1xuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xuICAgIGNvbG9yOiAiLCI7XG4gICAgZm9udC1zaXplOiAxNHB4O1xuICAgIG1hcmdpbi1sZWZ0OiAycHg7XG4gICAgZGlzcGxheTogaW5saW5lO1xuICAgIGxldHRlci1zcGFjaW5nOiAwLjUzcHg7XG4gIH1cbiJdLFsiXG4gIGlucHV0IHtcbiAgICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgICBjb2xvcjogIiwiO1xuICAgIGZvbnQtc2l6ZTogMTRweDtcbiAgICBtYXJnaW4tbGVmdDogMnB4O1xuICAgIGRpc3BsYXk6IGlubGluZTtcbiAgICBsZXR0ZXItc3BhY2luZzogMC41M3B4O1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMudGFiVGV4dH0pLEE9Yy5zdHlsZWQoImRpdiIpKG18fChtPWkoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgb3BhY2l0eTogIiwiO1xuIl0sWyJcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgb3BhY2l0eTogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hY3RpdmU/MTouNX0pLF89Yy5zdHlsZWQuZGl2KGd8fChnPWkoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgY29sb3I6IHdoaXRlO1xuIl0sWyJcbiAgZGlzcGxheTogZmxleDtcbiAgY29sb3I6IHdoaXRlO1xuIl0pKSksVD1jLnN0eWxlZC5kaXYoeXx8KHk9aShbIlxuICBoZWlnaHQ6IDIycHg7XG4gIHdpZHRoOiAyMnB4O1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgbWFyZ2luLXJpZ2h0OiA0cHg7XG4gIGZvbnQtc2l6ZTogMTJweDtcbiAgZm9udC13ZWlnaHQ6IDcwMDtcbiAgYm9yZGVyLXJhZGl1czogMnB4O1xuIl0sWyJcbiAgaGVpZ2h0OiAyMnB4O1xuICB3aWR0aDogMjJweDtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIG1hcmdpbi1yaWdodDogNHB4O1xuICBmb250LXNpemU6IDEycHg7XG4gIGZvbnQtd2VpZ2h0OiA3MDA7XG4gIGJvcmRlci1yYWRpdXM6IDJweDtcbiJdKSkpLE89Yy5zdHlsZWQoVCkodnx8KHY9aShbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSxbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMuYmx1ZX0pLEY9Yy5zdHlsZWQoVCkoYnx8KGI9aShbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSxbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMub3JhbmdlfSksTj1jLnN0eWxlZChUKSh4fHwoeD1pKFsiXG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdLFsiXG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5wdXJwbGV9KSxJPWMuc3R5bGVkLmRpdihDfHwoQz1pKFsiXG4gIHdpZHRoOiA3cHg7XG4gIGhlaWdodDogN3B4O1xuICBiYWNrZ3JvdW5kOiByZ2JhKDI0MiwgOTIsIDg0LCAxKTtcbiAgYm9yZGVyLXJhZGl1czogMTAwJTtcbiAgbWFyZ2luLXJpZ2h0OiAxMHB4O1xuIl0sWyJcbiAgd2lkdGg6IDdweDtcbiAgaGVpZ2h0OiA3cHg7XG4gIGJhY2tncm91bmQ6IHJnYmEoMjQyLCA5MiwgODQsIDEpO1xuICBib3JkZXItcmFkaXVzOiAxMDAlO1xuICBtYXJnaW4tcmlnaHQ6IDEwcHg7XG4iXSkpKSxMPWMuc3R5bGVkLmRpdihFfHwoRT1pKFsiXG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgdG9wOiAtMnB4O1xuICBmb250LXNpemU6IDlweDtcbiAgYmFja2dyb3VuZDogIiwiO1xuIl0sWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICB0b3A6IC0ycHg7XG4gIGZvbnQtc2l6ZTogOXB4O1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuY2lyY2xlfSksUD1jLnN0eWxlZCgiZGl2IikoRHx8KEQ9aShbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIG1hcmdpbi1sZWZ0OiAxMHB4O1xuICB0b3A6IDFweDtcbiAgaGVpZ2h0OiAxM3B4O1xuICB3aWR0aDogMTNweDtcbiAgb3BhY2l0eTogIiwiO1xuICBzdmcge1xuICAgIHN0cm9rZTogIiwiO1xuICB9XG4iXSxbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIG1hcmdpbi1sZWZ0OiAxMHB4O1xuICB0b3A6IDFweDtcbiAgaGVpZ2h0OiAxM3B4O1xuICB3aWR0aDogMTNweDtcbiAgb3BhY2l0eTogIiwiO1xuICBzdmcge1xuICAgIHN0cm9rZTogIiwiO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmFjdGl2ZXx8ZS5oYXNDaXJjbGU/MTowfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmljb259KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1mdW5jdGlvbiBpKGUsdCl7dmFyIG49e307Zm9yKHZhciByIGluIGUpdC5pbmRleE9mKHIpPj0wfHxPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxyKSYmKG5bcl09ZVtyXSk7cmV0dXJuIG59ZnVuY3Rpb24gbyhlLHQpe2lmKCEoZSBpbnN0YW5jZW9mIHQpKXRocm93IG5ldyBUeXBlRXJyb3IoIkNhbm5vdCBjYWxsIGEgY2xhc3MgYXMgYSBmdW5jdGlvbiIpfWZ1bmN0aW9uIGEoZSx0KXtpZighZSl0aHJvdyBuZXcgUmVmZXJlbmNlRXJyb3IoInRoaXMgaGFzbid0IGJlZW4gaW5pdGlhbGlzZWQgLSBzdXBlcigpIGhhc24ndCBiZWVuIGNhbGxlZCIpO3JldHVybiF0fHwib2JqZWN0IiE9PXR5cGVvZiB0JiYiZnVuY3Rpb24iIT09dHlwZW9mIHQ/ZTp0fWZ1bmN0aW9uIHMoZSx0KXtpZigiZnVuY3Rpb24iIT09dHlwZW9mIHQmJm51bGwhPT10KXRocm93IG5ldyBUeXBlRXJyb3IoIlN1cGVyIGV4cHJlc3Npb24gbXVzdCBlaXRoZXIgYmUgbnVsbCBvciBhIGZ1bmN0aW9uLCBub3QgIit0eXBlb2YgdCk7ZS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZSh0JiZ0LnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOmUsZW51bWVyYWJsZTohMSx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9fSksdCYmKE9iamVjdC5zZXRQcm90b3R5cGVPZj9PYmplY3Quc2V0UHJvdG90eXBlT2YoZSx0KTplLl9fcHJvdG9fXz10KX1PYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHU9T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTE7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyl7dmFyIG49YXJndW1lbnRzW3RdO2Zvcih2YXIgciBpbiBuKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChuLHIpJiYoZVtyXT1uW3JdKX1yZXR1cm4gZX0sYz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXtmb3IodmFyIG49MDtuPHQubGVuZ3RoO24rKyl7dmFyIHI9dFtuXTtyLmVudW1lcmFibGU9ci5lbnVtZXJhYmxlfHwhMSxyLmNvbmZpZ3VyYWJsZT0hMCwidmFsdWUiaW4gciYmKHIud3JpdGFibGU9ITApLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIua2V5LHIpfX1yZXR1cm4gZnVuY3Rpb24odCxuLHIpe3JldHVybiBuJiZlKHQucHJvdG90eXBlLG4pLHImJmUodCxyKSx0fX0oKSxsPW4oMCkscD1yKGwpLGY9bigxOCksZD1yKGYpLGg9e3Bvc2l0aW9uOiJhYnNvbHV0ZSIsdG9wOjAsbGVmdDowLHZpc2liaWxpdHk6ImhpZGRlbiIsaGVpZ2h0OjAsb3ZlcmZsb3c6InNjcm9sbCIsd2hpdGVTcGFjZToicHJlIn0sbT1bImV4dHJhV2lkdGgiLCJpbmplY3RTdHlsZXMiLCJpbnB1dENsYXNzTmFtZSIsImlucHV0UmVmIiwiaW5wdXRTdHlsZSIsIm1pbldpZHRoIiwib25BdXRvc2l6ZSIsInBsYWNlaG9sZGVySXNNaW5XaWR0aCJdLGc9ZnVuY3Rpb24oZSl7cmV0dXJuIG0uZm9yRWFjaChmdW5jdGlvbih0KXtyZXR1cm4gZGVsZXRlIGVbdF19KSxlfSx5PWZ1bmN0aW9uKGUsdCl7dC5zdHlsZS5mb250U2l6ZT1lLmZvbnRTaXplLHQuc3R5bGUuZm9udEZhbWlseT1lLmZvbnRGYW1pbHksdC5zdHlsZS5mb250V2VpZ2h0PWUuZm9udFdlaWdodCx0LnN0eWxlLmZvbnRTdHlsZT1lLmZvbnRTdHlsZSx0LnN0eWxlLmxldHRlclNwYWNpbmc9ZS5sZXR0ZXJTcGFjaW5nLHQuc3R5bGUudGV4dFRyYW5zZm9ybT1lLnRleHRUcmFuc2Zvcm19LHY9ISgidW5kZWZpbmVkIj09PXR5cGVvZiB3aW5kb3d8fCF3aW5kb3cubmF2aWdhdG9yKSYmL01TSUUgfFRyaWRlbnRcL3xFZGdlXC8vLnRlc3Qod2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQpLGI9ZnVuY3Rpb24oKXtyZXR1cm4gdj8iXyIrTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc3Vic3RyKDIsMTIpOnZvaWQgMH0seD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KGUpe28odGhpcyx0KTt2YXIgbj1hKHRoaXMsKHQuX19wcm90b19ffHxPYmplY3QuZ2V0UHJvdG90eXBlT2YodCkpLmNhbGwodGhpcyxlKSk7cmV0dXJuIG4uaW5wdXRSZWY9ZnVuY3Rpb24oZSl7bi5pbnB1dD1lLCJmdW5jdGlvbiI9PT10eXBlb2Ygbi5wcm9wcy5pbnB1dFJlZiYmbi5wcm9wcy5pbnB1dFJlZihlKX0sbi5wbGFjZUhvbGRlclNpemVyUmVmPWZ1bmN0aW9uKGUpe24ucGxhY2VIb2xkZXJTaXplcj1lfSxuLnNpemVyUmVmPWZ1bmN0aW9uKGUpe24uc2l6ZXI9ZX0sbi5zdGF0ZT17aW5wdXRXaWR0aDplLm1pbldpZHRoLGlucHV0SWQ6ZS5pZHx8YigpfSxufXJldHVybiBzKHQsZSksYyh0LFt7a2V5OiJjb21wb25lbnREaWRNb3VudCIsdmFsdWU6ZnVuY3Rpb24oKXt0aGlzLm1vdW50ZWQ9ITAsdGhpcy5jb3B5SW5wdXRTdHlsZXMoKSx0aGlzLnVwZGF0ZUlucHV0V2lkdGgoKX19LHtrZXk6ImNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHMiLHZhbHVlOmZ1bmN0aW9uKGUpe3ZhciB0PWUuaWQ7dCE9PXRoaXMucHJvcHMuaWQmJnRoaXMuc2V0U3RhdGUoe2lucHV0SWQ6dHx8YigpfSl9fSx7a2V5OiJjb21wb25lbnREaWRVcGRhdGUiLHZhbHVlOmZ1bmN0aW9uKGUsdCl7dC5pbnB1dFdpZHRoIT09dGhpcy5zdGF0ZS5pbnB1dFdpZHRoJiYiZnVuY3Rpb24iPT09dHlwZW9mIHRoaXMucHJvcHMub25BdXRvc2l6ZSYmdGhpcy5wcm9wcy5vbkF1dG9zaXplKHRoaXMuc3RhdGUuaW5wdXRXaWR0aCksdGhpcy51cGRhdGVJbnB1dFdpZHRoKCl9fSx7a2V5OiJjb21wb25lbnRXaWxsVW5tb3VudCIsdmFsdWU6ZnVuY3Rpb24oKXt0aGlzLm1vdW50ZWQ9ITF9fSx7a2V5OiJjb3B5SW5wdXRTdHlsZXMiLHZhbHVlOmZ1bmN0aW9uKCl7aWYodGhpcy5tb3VudGVkJiZ3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSl7dmFyIGU9dGhpcy5pbnB1dCYmd2luZG93LmdldENvbXB1dGVkU3R5bGUodGhpcy5pbnB1dCk7ZSYmKHkoZSx0aGlzLnNpemVyKSx0aGlzLnBsYWNlSG9sZGVyU2l6ZXImJnkoZSx0aGlzLnBsYWNlSG9sZGVyU2l6ZXIpKX19fSx7a2V5OiJ1cGRhdGVJbnB1dFdpZHRoIix2YWx1ZTpmdW5jdGlvbigpe2lmKHRoaXMubW91bnRlZCYmdGhpcy5zaXplciYmInVuZGVmaW5lZCIhPT10eXBlb2YgdGhpcy5zaXplci5zY3JvbGxXaWR0aCl7dmFyIGU9dm9pZCAwO2U9dGhpcy5wcm9wcy5wbGFjZWhvbGRlciYmKCF0aGlzLnByb3BzLnZhbHVlfHx0aGlzLnByb3BzLnZhbHVlJiZ0aGlzLnByb3BzLnBsYWNlaG9sZGVySXNNaW5XaWR0aCk/TWF0aC5tYXgodGhpcy5zaXplci5zY3JvbGxXaWR0aCx0aGlzLnBsYWNlSG9sZGVyU2l6ZXIuc2Nyb2xsV2lkdGgpKzI6dGhpcy5zaXplci5zY3JvbGxXaWR0aCsyO2UrPSJudW1iZXIiPT09dGhpcy5wcm9wcy50eXBlJiZ2b2lkIDA9PT10aGlzLnByb3BzLmV4dHJhV2lkdGg/MTY6cGFyc2VJbnQodGhpcy5wcm9wcy5leHRyYVdpZHRoKXx8MCxlPHRoaXMucHJvcHMubWluV2lkdGgmJihlPXRoaXMucHJvcHMubWluV2lkdGgpLGUhPT10aGlzLnN0YXRlLmlucHV0V2lkdGgmJnRoaXMuc2V0U3RhdGUoe2lucHV0V2lkdGg6ZX0pfX19LHtrZXk6ImdldElucHV0Iix2YWx1ZTpmdW5jdGlvbigpe3JldHVybiB0aGlzLmlucHV0fX0se2tleToiZm9jdXMiLHZhbHVlOmZ1bmN0aW9uKCl7dGhpcy5pbnB1dC5mb2N1cygpfX0se2tleToiYmx1ciIsdmFsdWU6ZnVuY3Rpb24oKXt0aGlzLmlucHV0LmJsdXIoKX19LHtrZXk6InNlbGVjdCIsdmFsdWU6ZnVuY3Rpb24oKXt0aGlzLmlucHV0LnNlbGVjdCgpfX0se2tleToicmVuZGVyU3R5bGVzIix2YWx1ZTpmdW5jdGlvbigpe3ZhciBlPXRoaXMucHJvcHMuaW5qZWN0U3R5bGVzO3JldHVybiB2JiZlP3AuZGVmYXVsdC5jcmVhdGVFbGVtZW50KCJzdHlsZSIse2Rhbmdlcm91c2x5U2V0SW5uZXJIVE1MOntfX2h0bWw6ImlucHV0IyIrdGhpcy5zdGF0ZS5pbnB1dElkKyI6Oi1tcy1jbGVhciB7ZGlzcGxheTogbm9uZTt9In19KTpudWxsfX0se2tleToicmVuZGVyIix2YWx1ZTpmdW5jdGlvbigpe3ZhciBlPVt0aGlzLnByb3BzLmRlZmF1bHRWYWx1ZSx0aGlzLnByb3BzLnZhbHVlLCIiXS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gbnVsbCE9PWUmJnZvaWQgMCE9PWU/ZTp0fSksdD11KHt9LHRoaXMucHJvcHMuc3R5bGUpO3QuZGlzcGxheXx8KHQuZGlzcGxheT0iaW5saW5lLWJsb2NrIik7dmFyIG49dSh7Ym94U2l6aW5nOiJjb250ZW50LWJveCIsd2lkdGg6dGhpcy5zdGF0ZS5pbnB1dFdpZHRoKyJweCJ9LHRoaXMucHJvcHMuaW5wdXRTdHlsZSkscj1pKHRoaXMucHJvcHMsW10pO3JldHVybiBnKHIpLHIuY2xhc3NOYW1lPXRoaXMucHJvcHMuaW5wdXRDbGFzc05hbWUsci5pZD10aGlzLnN0YXRlLmlucHV0SWQsci5zdHlsZT1uLHAuZGVmYXVsdC5jcmVhdGVFbGVtZW50KCJkaXYiLHtjbGFzc05hbWU6dGhpcy5wcm9wcy5jbGFzc05hbWUsc3R5bGU6dH0sdGhpcy5yZW5kZXJTdHlsZXMoKSxwLmRlZmF1bHQuY3JlYXRlRWxlbWVudCgiaW5wdXQiLHUoe30scix7cmVmOnRoaXMuaW5wdXRSZWZ9KSkscC5kZWZhdWx0LmNyZWF0ZUVsZW1lbnQoImRpdiIse3JlZjp0aGlzLnNpemVyUmVmLHN0eWxlOmh9LGUpLHRoaXMucHJvcHMucGxhY2Vob2xkZXI/cC5kZWZhdWx0LmNyZWF0ZUVsZW1lbnQoImRpdiIse3JlZjp0aGlzLnBsYWNlSG9sZGVyU2l6ZXJSZWYsc3R5bGU6aH0sdGhpcy5wcm9wcy5wbGFjZWhvbGRlcik6bnVsbCl9fV0pLHR9KGwuQ29tcG9uZW50KTt4LnByb3BUeXBlcz17Y2xhc3NOYW1lOmQuZGVmYXVsdC5zdHJpbmcsZGVmYXVsdFZhbHVlOmQuZGVmYXVsdC5hbnksZXh0cmFXaWR0aDpkLmRlZmF1bHQub25lT2ZUeXBlKFtkLmRlZmF1bHQubnVtYmVyLGQuZGVmYXVsdC5zdHJpbmddKSxpZDpkLmRlZmF1bHQuc3RyaW5nLGluamVjdFN0eWxlczpkLmRlZmF1bHQuYm9vbCxpbnB1dENsYXNzTmFtZTpkLmRlZmF1bHQuc3RyaW5nLGlucHV0UmVmOmQuZGVmYXVsdC5mdW5jLGlucHV0U3R5bGU6ZC5kZWZhdWx0Lm9iamVjdCxtaW5XaWR0aDpkLmRlZmF1bHQub25lT2ZUeXBlKFtkLmRlZmF1bHQubnVtYmVyLGQuZGVmYXVsdC5zdHJpbmddKSxvbkF1dG9zaXplOmQuZGVmYXVsdC5mdW5jLG9uQ2hhbmdlOmQuZGVmYXVsdC5mdW5jLHBsYWNlaG9sZGVyOmQuZGVmYXVsdC5zdHJpbmcscGxhY2Vob2xkZXJJc01pbldpZHRoOmQuZGVmYXVsdC5ib29sLHN0eWxlOmQuZGVmYXVsdC5vYmplY3QsdmFsdWU6ZC5kZWZhdWx0LmFueX0seC5kZWZhdWx0UHJvcHM9e21pbldpZHRoOjEsaW5qZWN0U3R5bGVzOiEwfSx0LmRlZmF1bHQ9eH0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPW4oMzA3KSxzPW4oNzA0KSx1PW4oNzA2KSxjPW4oMzYpLGw9bigxMzMpLHA9bigxKSxmPW4oOSksZD1uKDgpLGg9big3MDcpLG09big5NyksZz1uKDc1KSx5PW4oMTYpLHY9bigxMzEpLGI9bigzNykseD1uKDI0KSxDPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIG49ZS5jYWxsKHRoaXMsdCl8fHRoaXM7bi5oYW5kbGVDbGlja1VzZT1mdW5jdGlvbigpe3ZhciBlPW4ucHJvcHMuaXRlbXMsdD1lLmdldChuLnN0YXRlLnNlbGVjdGVkSXRlbUluZGV4KTtuLnByb3BzLmR1cGxpY2F0ZVNlc3Npb24odCksbi5wcm9wcy5jbG9zZUhpc3RvcnkoKX0sbi5oYW5kbGVJdGVtU2VsZWN0PWZ1bmN0aW9uKGUpe24uc2V0U3RhdGUoe3NlbGVjdGVkSXRlbUluZGV4OmV9KX0sbi5oYW5kbGVTZWxlY3RGaWx0ZXI9ZnVuY3Rpb24oZSl7bi5zZXRTdGF0ZSh7c2VsZWN0ZWRGaWx0ZXI6ZX0pfSxuLmhhbmRsZVNlYXJjaD1mdW5jdGlvbihlKXtuLnNldFN0YXRlKHtzZWFyY2hUZXJtOmV9KX07dmFyIHI9dC5pdGVtcy5rZXlTZXEoKS5maXJzdCgpfHwiIjtyZXR1cm4gbi5zdGF0ZT17c2VsZWN0ZWRGaWx0ZXI6IkhJU1RPUlkiLHNlbGVjdGVkSXRlbUluZGV4OnIsc2VhcmNoVGVybToiIn0sbn1yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMuc3RhdGUsdD1lLnNlYXJjaFRlcm0sbj1lLnNlbGVjdGVkRmlsdGVyLHI9dGhpcy5wcm9wcy5pdGVtcy5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuIlNUQVJSRUQiPT09bj9lLnN0YXJyZWQ6ISh0JiZ0Lmxlbmd0aD4wKXx8ZS5xdWVyeS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHQudG9Mb3dlckNhc2UoKSl9KSxpPXRoaXMucHJvcHMuaXRlbXMuZ2V0KHRoaXMuc3RhdGUuc2VsZWN0ZWRJdGVtSW5kZXgpO3JldHVybiBpPWkmJmkudG9KUz9pLnRvSlMoKTp2b2lkIDAsby5jcmVhdGVFbGVtZW50KGEse2lzT3Blbjp0aGlzLnByb3BzLmlzT3BlbixvblJlcXVlc3RDbG9zZTp0aGlzLnByb3BzLmNsb3NlSGlzdG9yeSxjb250ZW50TGFiZWw6IkdyYXBoaVFMIFNlc3Npb24gSGlzdG9yeSIsc3R5bGU6Yy5tb2RhbFN0eWxlfSxvLmNyZWF0ZUVsZW1lbnQoUCxudWxsLG8uY3JlYXRlRWxlbWVudChNLG51bGwsby5jcmVhdGVFbGVtZW50KHMuZGVmYXVsdCx7b25TZWxlY3RGaWx0ZXI6dGhpcy5oYW5kbGVTZWxlY3RGaWx0ZXIsc2VsZWN0ZWRGaWx0ZXI6dGhpcy5zdGF0ZS5zZWxlY3RlZEZpbHRlcixvblNlYXJjaDp0aGlzLmhhbmRsZVNlYXJjaH0pLG8uY3JlYXRlRWxlbWVudCh1LmRlZmF1bHQse2l0ZW1zOnIsc2VsZWN0ZWRJdGVtSW5kZXg6dGhpcy5zdGF0ZS5zZWxlY3RlZEl0ZW1JbmRleCxzZWFyY2hUZXJtOnRoaXMuc3RhdGUuc2VhcmNoVGVybSxvbkl0ZW1TZWxlY3Q6dGhpcy5oYW5kbGVJdGVtU2VsZWN0LG9uSXRlbVN0YXJUb2dnbGVkOnRoaXMucHJvcHMudG9nZ2xlSGlzdG9yeUl0ZW1TdGFycmluZ30pKSxCb29sZWFuKGkpP28uY3JlYXRlRWxlbWVudChqLG51bGwsby5jcmVhdGVFbGVtZW50KFIsbnVsbCxvLmNyZWF0ZUVsZW1lbnQoVSxudWxsKSxvLmNyZWF0ZUVsZW1lbnQoeix7b25DbGljazp0aGlzLmhhbmRsZUNsaWNrVXNlfSxvLmNyZWF0ZUVsZW1lbnQoRyxudWxsLCJVc2UiKSxvLmNyZWF0ZUVsZW1lbnQoeC5BcnJvd1JpZ2h0LHtjb2xvcjoid2hpdGUiLHdpZHRoOjEzLGhlaWdodDoxM30pKSksby5jcmVhdGVFbGVtZW50KFYsbnVsbCxvLmNyZWF0ZUVsZW1lbnQocSxudWxsLG8uY3JlYXRlRWxlbWVudChiLkNvbnRhaW5lcixudWxsLG8uY3JlYXRlRWxlbWVudChILG51bGwsby5jcmVhdGVFbGVtZW50KGwuUXVlcnlFZGl0b3Ise3ZhbHVlOmkucXVlcnl9KSkpKSkpOm8uY3JlYXRlRWxlbWVudChqLG51bGwsby5jcmVhdGVFbGVtZW50KEIsbnVsbCxvLmNyZWF0ZUVsZW1lbnQoJCxudWxsLCJObyBIaXN0b3J5IHlldCIpKSkpKX0sdH0oby5Db21wb25lbnQpLEU9ZC5jcmVhdGVTdHJ1Y3R1cmVkU2VsZWN0b3Ioe2l0ZW1zOmguZ2V0SGlzdG9yeSxpc09wZW46bS5nZXRIaXN0b3J5T3Blbn0pO3QuZGVmYXVsdD1mLmNvbm5lY3QoRSx7Y2xvc2VIaXN0b3J5OmcuY2xvc2VIaXN0b3J5LG9wZW5IaXN0b3J5Omcub3Blbkhpc3RvcnksZHVwbGljYXRlU2Vzc2lvbjp5LmR1cGxpY2F0ZVNlc3Npb24sdG9nZ2xlSGlzdG9yeUl0ZW1TdGFycmluZzp2LnRvZ2dsZUhpc3RvcnlJdGVtU3RhcnJpbmd9KShDKTt2YXIgRCx3LFMsayxBLF8sVCxPLEYsTixJLEwsUD1wLnN0eWxlZC5kaXYoRHx8KEQ9aShbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBtaW4taGVpZ2h0OiA1MDBweDtcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIG1pbi1oZWlnaHQ6IDUwMHB4O1xuIl0pKSksTT1wLnN0eWxlZC5kaXYod3x8KHc9aShbIlxuICBmbGV4OiAxO1xuXG4gIGJhY2tncm91bmQ6IHdoaXRlO1xuIl0sWyJcbiAgZmxleDogMTtcblxuICBiYWNrZ3JvdW5kOiB3aGl0ZTtcbiJdKSkpLGo9cC5zdHlsZWQuZGl2KFN8fChTPWkoWyJcbiAgZmxleDogMCAwIDQ2NHB4O1xuICB6LWluZGV4OiAyO1xuIl0sWyJcbiAgZmxleDogMCAwIDQ2NHB4O1xuICB6LWluZGV4OiAyO1xuIl0pKSksUj1wLnN0eWxlZC5kaXYoa3x8KGs9aShbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG5cbiAgcGFkZGluZy1sZWZ0OiAiLCI7XG4gIHBhZGRpbmctcmlnaHQ6ICIsIjtcbiAgcGFkZGluZy10b3A6IDIwcHg7XG4gIHBhZGRpbmctYm90dG9tOiAyMHB4O1xuXG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcblxuICBwYWRkaW5nLWxlZnQ6ICIsIjtcbiAgcGFkZGluZy1yaWdodDogIiwiO1xuICBwYWRkaW5nLXRvcDogMjBweDtcbiAgcGFkZGluZy1ib3R0b206IDIwcHg7XG5cbiAgYmFja2dyb3VuZDogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5tZWRpdW0yNX0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuc2l6ZXMubWVkaXVtMjV9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMucmVzdWx0QmFja2dyb3VuZH0pLEI9cC5zdHlsZWQuZGl2KEF8fChBPWkoWyJcbiAgaGVpZ2h0OiAxMDAlO1xuICBkaXNwbGF5OiBmbGV4O1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcblxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSxbIlxuICBoZWlnaHQ6IDEwMCU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuXG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5yZXN1bHRCYWNrZ3JvdW5kfSksJD1wLnN0eWxlZC5kaXYoX3x8KF89aShbIlxuICBmb250LXNpemU6IDE2cHg7XG4gIGNvbG9yOiAiLCI7XG4iXSxbIlxuICBmb250LXNpemU6IDE2cHg7XG4gIGNvbG9yOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMudGV4dH0pLFU9cC5zdHlsZWQuZGl2KFR8fChUPWkoWyJcbiAgZm9udC1zaXplOiAiLCI7XG4gIGZvbnQtd2VpZ2h0OiAiLCI7XG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gIGNvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDAuNCk7XG4iXSxbIlxuICBmb250LXNpemU6ICIsIjtcbiAgZm9udC13ZWlnaHQ6ICIsIjtcbiAgdGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTtcbiAgY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMC40KTtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuc2l6ZXMuZm9udFNtYWxsfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5mb250U2VtaUJvbGR9KSx6PXAuc3R5bGVkLmRpdihPfHwoTz1pKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG5cbiAgcGFkZGluZy10b3A6ICIsIjtcbiAgcGFkZGluZy1ib3R0b206ICIsIjtcbiAgcGFkZGluZy1sZWZ0OiAiLCI7XG4gIHBhZGRpbmctcmlnaHQ6ICIsIjtcblxuICBmb250LXNpemU6ICIsIjtcbiAgZm9udC13ZWlnaHQ6ICIsIjtcblxuICBib3JkZXItcmFkaXVzOiAiLCI7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgY3Vyc29yOiBwb2ludGVyO1xuIl0sWyJcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcblxuICBwYWRkaW5nLXRvcDogIiwiO1xuICBwYWRkaW5nLWJvdHRvbTogIiwiO1xuICBwYWRkaW5nLWxlZnQ6ICIsIjtcbiAgcGFkZGluZy1yaWdodDogIiwiO1xuXG4gIGZvbnQtc2l6ZTogIiwiO1xuICBmb250LXdlaWdodDogIiwiO1xuXG4gIGJvcmRlci1yYWRpdXM6ICIsIjtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBjdXJzb3I6IHBvaW50ZXI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNpemVzLnNtYWxsMTB9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNpemVzLnNtYWxsMTB9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNpemVzLnNtYWxsMTZ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNpemVzLnNtYWxsMTZ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNpemVzLmZvbnRTbWFsbH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuc2l6ZXMuZm9udFNlbWlCb2xkfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5zaXplcy5zbWFsbFJhZGl1c30sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5ncmVlbn0pLEc9cC5zdHlsZWQuZGl2KEZ8fChGPWkoWyJcbiAgbWFyZ2luLXJpZ2h0OiAiLCI7XG4gIGNvbG9yOiB3aGl0ZTtcbiJdLFsiXG4gIG1hcmdpbi1yaWdodDogIiwiO1xuICBjb2xvcjogd2hpdGU7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLnNpemVzLnNtYWxsNn0pLFY9cC5zdHlsZWQuZGl2KE58fChOPWkoWyJcbiAgaGVpZ2h0OiBjYWxjKDEwMCUgLSA4MXB4KTtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleDogMSAxIGF1dG87XG4iXSxbIlxuICBoZWlnaHQ6IGNhbGMoMTAwJSAtIDgxcHgpO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4OiAxIDEgYXV0bztcbiJdKSkpLHE9cC5zdHlsZWQoVikoSXx8KEk9aShbIlxuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXg6IDEgMSBhdXRvO1xuIl0sWyJcbiAgd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogMTAwJTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4OiAxIDEgYXV0bztcbiJdKSkpLEg9cC5zdHlsZWQuZGl2KEx8fChMPWkoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgZmxleDogMTtcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGZsZXg6IDE7XG4iXSkpKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDApLG89big3MDUpLGE9bigxKSxzPW4oMzAwKTt0LmRlZmF1bHQ9ZnVuY3Rpb24oZSl7cmV0dXJuIGkuY3JlYXRlRWxlbWVudChjLG51bGwsaS5jcmVhdGVFbGVtZW50KG8uZGVmYXVsdCx7b25TZWxlY3RGaWx0ZXI6ZS5vblNlbGVjdEZpbHRlcixzZWxlY3RlZEZpbHRlcjplLnNlbGVjdGVkRmlsdGVyfSksaS5jcmVhdGVFbGVtZW50KHMuZGVmYXVsdCx7cGxhY2Vob2xkZXI6IlNlYXJjaCB0aGUgaGlzdG9yeS4uLiIsb25TZWFyY2g6ZS5vblNlYXJjaCxjbGVhbjohMH0pKX07dmFyIHUsYz1hLnN0eWxlZC5kaXYodXx8KHU9cihbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIHBhZGRpbmc6IDE2cHg7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgcGFkZGluZzogMTZweDtcbiAgYmFja2dyb3VuZDogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5jb2xvdXJzLmJsYWNrMDJ9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgaT1uKDApLG89bigxKSxhPW4oMjQpLHM9ZnVuY3Rpb24oZSl7dmFyIHQ9ZS5zZWxlY3RlZEZpbHRlcixuPWUub25TZWxlY3RGaWx0ZXIscj1lLnRoZW1lO3JldHVybiBpLmNyZWF0ZUVsZW1lbnQocCxudWxsLGkuY3JlYXRlRWxlbWVudChmLHthY3RpdmU6IkhJU1RPUlkiPT09dCxvbkNsaWNrOmZ1bmN0aW9uKCl7cmV0dXJuIG4oIkhJU1RPUlkiKX19LGkuY3JlYXRlRWxlbWVudChhLkhpc3Rvcnkse2NvbG9yOiJISVNUT1JZIj09PXQ/ci5jb2xvdXJzLndoaXRlOnIuY29sb3Vycy5ibGFjazMwLHN0cm9rZVdpZHRoOjMsd2lkdGg6MjUsaGVpZ2h0OjI1fSksaS5jcmVhdGVFbGVtZW50KGQsbnVsbCwiSGlzdG9yeSIpKSxpLmNyZWF0ZUVsZW1lbnQoZix7YWN0aXZlOiJTVEFSUkVEIj09PXQsb25DbGljazpmdW5jdGlvbigpe3JldHVybiBuKCJTVEFSUkVEIil9fSxpLmNyZWF0ZUVsZW1lbnQoYS5TdGFyLHtjb2xvcjoiU1RBUlJFRCI9PT10P3IuY29sb3Vycy53aGl0ZTpyLmNvbG91cnMuYmxhY2szMCx3aWR0aDoxNixoZWlnaHQ6MTZ9KSxpLmNyZWF0ZUVsZW1lbnQoZCxudWxsLCJTdGFycmVkIikpKX07dC5kZWZhdWx0PW8ud2l0aFRoZW1lKHMpO3ZhciB1LGMsbCxwPW8uc3R5bGVkLmRpdih1fHwodT1yKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4iXSxbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuIl0pKSksZj1vLnN0eWxlZCgiZGl2IikoY3x8KGM9cihbIlxuICBib3gtc2l6aW5nOiBjb250ZW50LWJveDtcbiAgaGVpZ2h0OiAyNHB4O1xuICB6LWluZGV4OiAiLCI7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIG1hcmdpbjogMCAtMnB4O1xuICBwYWRkaW5nOiAiLCI7XG4gIGJhY2tncm91bmQ6ICIsIjtcblxuICBjb2xvcjogIiwiO1xuICBmb250LXNpemU6IDE0cHg7XG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuIl0sWyJcbiAgYm94LXNpemluZzogY29udGVudC1ib3g7XG4gIGhlaWdodDogMjRweDtcbiAgei1pbmRleDogIiwiO1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBtYXJnaW46IDAgLTJweDtcbiAgcGFkZGluZzogIiwiO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG5cbiAgY29sb3I6ICIsIjtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBmb250LXdlaWdodDogNjAwO1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICBib3JkZXItcmFkaXVzOiAycHg7XG4gIGN1cnNvcjogcG9pbnRlcjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUuYWN0aXZlPzI6MH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUuYWN0aXZlPyI3cHggOXB4IDhweCA5cHgiOiI1cHggMTNweCA2cHggMTNweCJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLmFjdGl2ZT9lLnRoZW1lLmNvbG91cnMuZ3JlZW46ZS50aGVtZS5jb2xvdXJzLmJsYWNrMDd9LGZ1bmN0aW9uKGUpe3JldHVybiBlLmFjdGl2ZT9lLnRoZW1lLmNvbG91cnMud2hpdGU6ZS50aGVtZS5jb2xvdXJzLmJsYWNrMzB9KSxkPW8uc3R5bGVkLnAobHx8KGw9cihbIlxuICBtYXJnaW4tbGVmdDogNnB4O1xuIl0sWyJcbiAgbWFyZ2luLWxlZnQ6IDZweDtcbiJdKSkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBpPW4oMCksbz1uKDI0KSxhPW4oMSk7dC5kZWZhdWx0PWEud2l0aFRoZW1lKGZ1bmN0aW9uKGUpe3ZhciB0PWUuaXRlbXMsbj1lLm9uSXRlbVNlbGVjdCxyPWUuc2VsZWN0ZWRJdGVtSW5kZXgsYT1lLm9uSXRlbVN0YXJUb2dnbGVkO2UudGhlbWU7cmV0dXJuIGkuY3JlYXRlRWxlbWVudCh5LG51bGwsdC5tYXAoZnVuY3Rpb24oZSx0KXtyZXR1cm4gaS5jcmVhdGVFbGVtZW50KHYse2tleTplLmlkLGFjdGl2ZTpyPT09dCxvbkNsaWNrOmZ1bmN0aW9uKCl7cmV0dXJuIG4odCl9fSxpLmNyZWF0ZUVsZW1lbnQoeCxudWxsLGkuY3JlYXRlRWxlbWVudChvLlN0YXIse29uQ2xpY2s6ZnVuY3Rpb24oKXtyZXR1cm4gYShlLmlkKX0sc3Ryb2tlOmUuc3RhcnJlZD92b2lkIDA6InJnYigyMjEsMTcxLDApIixmaWxsOmUuc3RhcnJlZD8icmdiKDIyMSwxNzEsMCkiOnZvaWQgMCxzdHJva2VXaWR0aDouNSx3aWR0aDoyNSxoZWlnaHQ6MjV9KSxpLmNyZWF0ZUVsZW1lbnQoYixudWxsLGkuY3JlYXRlRWxlbWVudChDLG51bGwsZS5vcGVyYXRpb25OYW1lfHxlLnF1ZXJ5VHlwZXMuZmlyc3RPcGVyYXRpb25OYW1lfHwiTmV3IFNlc3Npb24iKSxlLnF1ZXJ5VHlwZXMucXVlcnkmJmkuY3JlYXRlRWxlbWVudChELG51bGwsIlEiKSxlLnF1ZXJ5VHlwZXMubXV0YXRpb24mJmkuY3JlYXRlRWxlbWVudCh3LG51bGwsIk0iKSxlLnF1ZXJ5VHlwZXMuc3Vic2NyaXB0aW9uJiZpLmNyZWF0ZUVsZW1lbnQoUyxudWxsLCJTIikpKSxpLmNyZWF0ZUVsZW1lbnQoeCxudWxsLGUuZGF0ZSYmaS5jcmVhdGVFbGVtZW50KGssbnVsbCwiZnVuY3Rpb24iPT09dHlwZW9mIGUuZGF0ZS5nZXRNb250aCYmZS5kYXRlLmdldE1vbnRoKCkrMSwiLyIsZS5kYXRlLmdldERhdGUoKSwiLyIsZS5kYXRlLmdldEZ1bGxZZWFyKCkudG9TdHJpbmcoKS5zbGljZSgyLDQpKSkpfSkudG9BcnJheSgpLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZVsxXX0pKX0pO3ZhciBzLHUsYyxsLHAsZixkLGgsbSxnLHk9YS5zdHlsZWQuZGl2KHN8fChzPXIoWyJcbiAgb3ZlcmZsb3cteTogc2Nyb2xsO1xuICBtYXgtaGVpZ2h0OiBjYWxjKDEwMHZoIC0gMTIxcHgpO1xuIl0sWyJcbiAgb3ZlcmZsb3cteTogc2Nyb2xsO1xuICBtYXgtaGVpZ2h0OiBjYWxjKDEwMHZoIC0gMTIxcHgpO1xuIl0pKSksdj1hLnN0eWxlZCgiZGl2IikodXx8KHU9cihbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gIHBhZGRpbmc6IDI1cHggMjBweDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBib3JkZXItYm90dG9tOiAxcHggc29saWQ7XG4gIGJvcmRlci1jb2xvcjogIiwiO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSxbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gIHBhZGRpbmc6IDI1cHggMjBweDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBib3JkZXItYm90dG9tOiAxcHggc29saWQ7XG4gIGJvcmRlci1jb2xvcjogIiwiO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMuYmxhY2sxMH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUuYWN0aXZlP2UudGhlbWUuY29sb3Vycy5ibGFjazA0OmUudGhlbWUuY29sb3Vycy53aGl0ZX0pLGI9YS5zdHlsZWQuZGl2KGN8fChjPXIoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgbWFyZ2luLWxlZnQ6IDIwcHg7XG4iXSxbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBtYXJnaW4tbGVmdDogMjBweDtcbiJdKSkpLHg9YS5zdHlsZWQuZGl2KGx8fChsPXIoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4iXSkpKSxDPWEuc3R5bGVkLnAocHx8KHA9cihbIlxuICBmb250LXdlaWdodDogMzAwO1xuICBmb250LXNpemU6IDIwcHg7XG4gIG1hcmdpbi1yaWdodDogMTZweDtcbiJdLFsiXG4gIGZvbnQtd2VpZ2h0OiAzMDA7XG4gIGZvbnQtc2l6ZTogMjBweDtcbiAgbWFyZ2luLXJpZ2h0OiAxNnB4O1xuIl0pKSksRT1hLnN0eWxlZC5kaXYoZnx8KGY9cihbIlxuICBoZWlnaHQ6IDIxcHg7XG4gIHdpZHRoOiAyMXB4O1xuICBkaXNwbGF5OiBmbGV4O1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgbWFyZ2luLXJpZ2h0OiA0cHg7XG4gIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgZm9udC13ZWlnaHQ6IDcwMDtcbiAgZm9udC1zaXplOiAxMnB4O1xuICBjb2xvcjogIiwiO1xuIl0sWyJcbiAgaGVpZ2h0OiAyMXB4O1xuICB3aWR0aDogMjFweDtcbiAgZGlzcGxheTogZmxleDtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIG1hcmdpbi1yaWdodDogNHB4O1xuICBib3JkZXItcmFkaXVzOiAycHg7XG4gIGZvbnQtd2VpZ2h0OiA3MDA7XG4gIGZvbnQtc2l6ZTogMTJweDtcbiAgY29sb3I6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy53aGl0ZX0pLEQ9YS5zdHlsZWQoRSkoZHx8KGQ9cihbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSxbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMuYmx1ZX0pLHc9YS5zdHlsZWQoRSkoaHx8KGg9cihbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSxbIlxuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmNvbG91cnMub3JhbmdlfSksUz1hLnN0eWxlZChFKShtfHwobT1yKFsiXG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdLFsiXG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5wdXJwbGV9KSxrPWEuc3R5bGVkLnRpbWUoZ3x8KGc9cihbIlxuICBjb2xvcjogIiwiO1xuICBmb250LXNpemU6IDE0cHg7XG4gIG1hcmdpbi1sZWZ0OiAxNnB4O1xuIl0sWyJcbiAgY29sb3I6ICIsIjtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBtYXJnaW4tbGVmdDogMTZweDtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuY29sb3Vycy5ibGFjazQwfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oOCksaT1uKDE3KTt0LmdldEhpc3Rvcnk9ci5jcmVhdGVTZWxlY3RvcihbaS5nZXRTZWxlY3RlZFdvcmtzcGFjZV0sZnVuY3Rpb24oZSl7cmV0dXJuIGUuaGlzdG9yeX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9bigyNCkscz1uKDEpLHU9bigxNiksYz1uKDkpLGw9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCgpe3JldHVybiBudWxsIT09ZSYmZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fHRoaXN9cmV0dXJuIHIodCxlKSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGQsbnVsbCxvLmNyZWF0ZUVsZW1lbnQoaCxudWxsLG8uY3JlYXRlRWxlbWVudChhLlNldHRpbmdzSWNvbix7d2lkdGg6MjMsaGVpZ2h0OjIzLG9uQ2xpY2s6dGhpcy5wcm9wcy5vbkNsaWNrLHRpdGxlOiJTZXR0aW5ncyJ9KSkpfSx0fShvLkNvbXBvbmVudCk7dC5kZWZhdWx0PWMuY29ubmVjdChudWxsLHtvbkNsaWNrOnUub3BlblNldHRpbmdzVGFifSkobCk7dmFyIHAsZixkPXMuc3R5bGVkLmRpdihwfHwocD1pKFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgei1pbmRleDogMTAwNTtcbiAgcmlnaHQ6IDIwcHg7XG4gIHRvcDogMTdweDtcbiJdLFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgei1pbmRleDogMTAwNTtcbiAgcmlnaHQ6IDIwcHg7XG4gIHRvcDogMTdweDtcbiJdKSkpLGg9cy5zdHlsZWQuZGl2KGZ8fChmPWkoWyJcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBjdXJzb3I6IHBvaW50ZXI7XG5cbiAgc3ZnIHtcbiAgICBmaWxsOiAiLCI7XG4gICAgdHJhbnNpdGlvbjogMC4xcyBsaW5lYXIgZmlsbDtcbiAgfVxuXG4gICY6aG92ZXIge1xuICAgIHN2ZyB7XG4gICAgICBmaWxsOiAiLCI7XG4gICAgfVxuICB9XG4iXSxbIlxuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGN1cnNvcjogcG9pbnRlcjtcblxuICBzdmcge1xuICAgIGZpbGw6ICIsIjtcbiAgICB0cmFuc2l0aW9uOiAwLjFzIGxpbmVhciBmaWxsO1xuICB9XG5cbiAgJjpob3ZlciB7XG4gICAgc3ZnIHtcbiAgICAgIGZpbGw6ICIsIjtcbiAgICB9XG4gIH1cbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5pY29ufSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmljb25Ib3Zlcn0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9bigxKSxzPW4oMTQyKSx1PW4oNzEwKSxjPW4oOSksbD1uKDgpLHA9big5NyksZj1uKDc1KSxkPW4oMTYpLGg9bigxNyksbT1uKDM3KSxnPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXt2YXIgdD1udWxsIT09ZSYmZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fHRoaXM7cmV0dXJuIHQuaGFuZGxlS2V5ZG93bj1mdW5jdGlvbihlKXsicyI9PT1lLmtleSYmZS5tZXRhS2V5JiYoZS5wcmV2ZW50RGVmYXVsdCgpLHQucHJvcHMub25TYXZlKCkpfSx0fXJldHVybiByKHQsZSksdC5wcm90b3R5cGUuY29tcG9uZW50RGlkTW91bnQ9ZnVuY3Rpb24oKXt3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigia2V5ZG93biIsdGhpcy5oYW5kbGVLZXlkb3duLCEwKX0sdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcy5pc0NvbmZpZztyZXR1cm4gby5jcmVhdGVFbGVtZW50KG0uQ29udGFpbmVyLG51bGwsby5jcmVhdGVFbGVtZW50KEQsbnVsbCxvLmNyZWF0ZUVsZW1lbnQobS5kZWZhdWx0LG51bGwsby5jcmVhdGVFbGVtZW50KHUuQ29uZmlnRWRpdG9yLHt2YWx1ZTp0aGlzLnByb3BzLnZhbHVlLG9uRWRpdDp0aGlzLnByb3BzLm9uQ2hhbmdlLG9uUnVuUXVlcnk6dGhpcy5wcm9wcy5vblNhdmUsaXNZYW1sOnRoaXMucHJvcHMuaXNZYW1sLHJlYWRPbmx5OnRoaXMucHJvcHMucmVhZE9ubHl9KSxvLmNyZWF0ZUVsZW1lbnQoUyxudWxsLHdpbmRvdy52ZXJzaW9uKSksIXRoaXMucHJvcHMucmVhZE9ubHkmJm8uY3JlYXRlRWxlbWVudCh3LG51bGwsby5jcmVhdGVFbGVtZW50KHMuQnV0dG9uLHtvbkNsaWNrOnRoaXMucHJvcHMub25TYXZlfSwiU2F2ZSAiLGU/IkNvbmZpZyI6IlNldHRpbmdzIikpKSl9LHR9KG8uQ29tcG9uZW50KTt0LlNldHRpbmdzRWRpdG9yPWc7dmFyIHk9bC5jcmVhdGVTdHJ1Y3R1cmVkU2VsZWN0b3Ioe3ZhbHVlOmguZ2V0U2V0dGluZ3NTdHJpbmd9KSx2PWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIG49ZS5jYWxsKHRoaXMsdCl8fHRoaXM7cmV0dXJuIG4uaGFuZGxlQ2hhbmdlPWZ1bmN0aW9uKGUpe24uc2V0U3RhdGUoe3ZhbHVlOmV9KSxuLnByb3BzLmVkaXRTZXR0aW5ncygpfSxuLmhhbmRsZVNhdmU9ZnVuY3Rpb24oKXtuLnByb3BzLm9uU2F2ZShuLnN0YXRlLnZhbHVlKSxuLnByb3BzLnNhdmVTZXR0aW5ncygpfSxuLnN0YXRlPXt2YWx1ZTp0LnZhbHVlfSxufXJldHVybiByKHQsZSksdC5wcm90b3R5cGUuY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wcz1mdW5jdGlvbihlKXtlLnZhbHVlIT09dGhpcy5wcm9wcy52YWx1ZSYmdGhpcy5zZXRTdGF0ZSh7dmFsdWU6ZS52YWx1ZX0pfSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGcse3ZhbHVlOnRoaXMuc3RhdGUudmFsdWUsb25DaGFuZ2U6dGhpcy5oYW5kbGVDaGFuZ2Usb25TYXZlOnRoaXMuaGFuZGxlU2F2ZX0pfSx0fShvLkNvbXBvbmVudCk7dC5QbGF5Z3JvdW5kU2V0dGluZ3NFZGl0b3I9Yy5jb25uZWN0KHkse29uU2F2ZTpmLnNldFNldHRpbmdzU3RyaW5nLGVkaXRTZXR0aW5nczpkLmVkaXRTZXR0aW5ncyxzYXZlU2V0dGluZ3M6ZC5zYXZlU2V0dGluZ3N9KSh2KTt2YXIgYj1sLmNyZWF0ZVN0cnVjdHVyZWRTZWxlY3Rvcih7dmFsdWU6cC5nZXRDb25maWdTdHJpbmd9KTt0LkdyYXBoUUxDb25maWdFZGl0b3I9Yy5jb25uZWN0KGIse29uQ2hhbmdlOmYuc2V0Q29uZmlnU3RyaW5nfSkoZyk7dmFyIHgsQyxFLEQ9YS5zdHlsZWQuZGl2KHh8fCh4PWkoWyJcbiAgYmFja2dyb3VuZDogIiwiO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZmxvdzogY29sdW1uO1xuICBmbGV4OiAxIDEgMDtcblxuICAuQ29kZU1pcnJvciB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICAgIC5Db2RlTWlycm9yLWNvZGUge1xuICAgICAgY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMC43KTtcbiAgICB9XG4gICAgLmNtLWF0b20ge1xuICAgICAgY29sb3I6IHJnYmEoNDIsIDEyNiwgMjEwLCAxKTtcbiAgICB9XG4gIH1cbiJdLFsiXG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWZsb3c6IGNvbHVtbjtcbiAgZmxleDogMSAxIDA7XG5cbiAgLkNvZGVNaXJyb3Ige1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgICAuQ29kZU1pcnJvci1jb2RlIHtcbiAgICAgIGNvbG9yOiByZ2JhKDI1NSwgMjU1LCAyNTUsIDAuNyk7XG4gICAgfVxuICAgIC5jbS1hdG9tIHtcbiAgICAgIGNvbG9yOiByZ2JhKDQyLCAxMjYsIDIxMCwgMSk7XG4gICAgfVxuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMucmVzdWx0QmFja2dyb3VuZH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5yZXN1bHRCYWNrZ3JvdW5kfSksdz1hLnN0eWxlZC5kaXYoQ3x8KEM9aShbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMTZweDtcbiAgcmlnaHQ6IDE2cHg7XG4gIHotaW5kZXg6IDI7XG4iXSxbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMTZweDtcbiAgcmlnaHQ6IDE2cHg7XG4gIHotaW5kZXg6IDI7XG4iXSkpKSxTPWEuc3R5bGVkLnNwYW4oRXx8KEU9aShbIlxuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHJpZ2h0OiAyMHB4O1xuICBib3R0b206IDE3cHg7XG4gIGNvbG9yOiAiLCI7XG4gIGZvbnQtd2VpZ2h0OiA3MDA7XG4gIG1hcmdpbi1yaWdodDogMTRweDtcbiJdLFsiXG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgcmlnaHQ6IDIwcHg7XG4gIGJvdHRvbTogMTdweDtcbiAgY29sb3I6ICIsIjtcbiAgZm9udC13ZWlnaHQ6IDcwMDtcbiAgbWFyZ2luLXJpZ2h0OiAxNHB4O1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnRleHRJbmFjdGl2ZX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9bigzNykscz1uKDEpLHU9ZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdCh0KXt2YXIgbj1lLmNhbGwodGhpcyx0KXx8dGhpcztyZXR1cm4gbi5zZXROb2RlPWZ1bmN0aW9uKGUpe24ubm9kZT1lfSxuLm9uS2V5VXA9ZnVuY3Rpb24oZSx0KXt2YXIgcj10LmtleUNvZGU7KHI+PTY1JiZyPD05MHx8IXQuc2hpZnRLZXkmJnI+PTQ4JiZyPD01N3x8dC5zaGlmdEtleSYmMTg5PT09cnx8dC5zaGlmdEtleSYmMjIyPT09cikmJm4uZWRpdG9yLmV4ZWNDb21tYW5kKCJhdXRvY29tcGxldGUiKX0sbi5vbkVkaXQ9ZnVuY3Rpb24oKXtuLmlnbm9yZUNoYW5nZUV2ZW50fHwobi5jYWNoZWRWYWx1ZT1uLmVkaXRvci5nZXRWYWx1ZSgpLG4ucHJvcHMub25FZGl0JiZuLnByb3BzLm9uRWRpdChuLmNhY2hlZFZhbHVlKSl9LG4uY2FjaGVkVmFsdWU9dC52YWx1ZXx8IiIsbn1yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLmNvbXBvbmVudERpZE1vdW50PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcyx0PW4oMik7bigxMzcpLG4oNjkpLG4oMTM4KSxuKDcwKSxuKDg5KSxuKDEzOSksbigzOCksbig5MCksbigzOSksbig5MSksbig3MTEpLG4oMjg2KSxuKDI4NyksbigyODgpLHRoaXMuZWRpdG9yPXQodGhpcy5ub2RlLHt2YWx1ZTp0aGlzLnByb3BzLnZhbHVlfHwiIixsaW5lTnVtYmVyczohMCx0YWJTaXplOjIsbW9kZTp0aGlzLnByb3BzLmlzWWFtbD8ieWFtbCI6ImdyYXBocWwtdmFyaWFibGVzIix0aGVtZTp0aGlzLnByb3BzLmVkaXRvclRoZW1lfHwiZ3JhcGhpcWwiLGtleU1hcDoic3VibGltZSIsYXV0b0Nsb3NlQnJhY2tldHM6ITAsbWF0Y2hCcmFja2V0czohMCxzaG93Q3Vyc29yV2hlblNlbGVjdGluZzohMCxyZWFkT25seTohIXRoaXMucHJvcHMucmVhZE9ubHkmJiJub2N1cnNvciIsZm9sZEd1dHRlcjp7bWluRm9sZFNpemU6NH0sZ3V0dGVyczpbIkNvZGVNaXJyb3ItbGluZW51bWJlcnMiLCJDb2RlTWlycm9yLWZvbGRndXR0ZXIiXSxleHRyYUtleXM6eyJDbWQtU3BhY2UiOmZ1bmN0aW9uKCl7cmV0dXJuIGUuZWRpdG9yLnNob3dIaW50KHtjb21wbGV0ZVNpbmdsZTohMX0pfSwiQ3RybC1TcGFjZSI6ZnVuY3Rpb24oKXtyZXR1cm4gZS5lZGl0b3Iuc2hvd0hpbnQoe2NvbXBsZXRlU2luZ2xlOiExfSl9LCJBbHQtU3BhY2UiOmZ1bmN0aW9uKCl7cmV0dXJuIGUuZWRpdG9yLnNob3dIaW50KHtjb21wbGV0ZVNpbmdsZTohMX0pfSwiU2hpZnQtU3BhY2UiOmZ1bmN0aW9uKCl7cmV0dXJuIGUuZWRpdG9yLnNob3dIaW50KHtjb21wbGV0ZVNpbmdsZTohMX0pfSwiQ21kLUVudGVyIjpmdW5jdGlvbigpe2UucHJvcHMub25SdW5RdWVyeSYmZS5wcm9wcy5vblJ1blF1ZXJ5KCl9LCJDdHJsLUVudGVyIjpmdW5jdGlvbigpe2UucHJvcHMub25SdW5RdWVyeSYmZS5wcm9wcy5vblJ1blF1ZXJ5KCl9LCJTaGlmdC1DdHJsLVAiOmZ1bmN0aW9uKCl7ZS5wcm9wcy5vblByZXR0aWZ5UXVlcnkmJmUucHJvcHMub25QcmV0dGlmeVF1ZXJ5KCl9LCJDbWQtRiI6ImZpbmRQZXJzaXN0ZW50IiwiQ3RybC1GIjoiZmluZFBlcnNpc3RlbnQiLCJDdHJsLUxlZnQiOiJnb1N1YndvcmRMZWZ0IiwiQ3RybC1SaWdodCI6ImdvU3Vid29yZFJpZ2h0IiwiQWx0LUxlZnQiOiJnb0dyb3VwTGVmdCIsIkFsdC1SaWdodCI6ImdvR3JvdXBSaWdodCJ9fSksdGhpcy5lZGl0b3Iub24oImNoYW5nZSIsdGhpcy5vbkVkaXQpLHRoaXMuZWRpdG9yLm9uKCJrZXl1cCIsdGhpcy5vbktleVVwKX0sdC5wcm90b3R5cGUuY29tcG9uZW50RGlkVXBkYXRlPWZ1bmN0aW9uKGUpe3RoaXMuaWdub3JlQ2hhbmdlRXZlbnQ9ITAsdGhpcy5wcm9wcy52YWx1ZSE9PWUudmFsdWUmJnRoaXMucHJvcHMudmFsdWUhPT10aGlzLmNhY2hlZFZhbHVlJiYodGhpcy5jYWNoZWRWYWx1ZT10aGlzLnByb3BzLnZhbHVlLHRoaXMuZWRpdG9yLnNldFZhbHVlKHRoaXMucHJvcHMudmFsdWUpKSx0aGlzLmlnbm9yZUNoYW5nZUV2ZW50PSExfSx0LnByb3RvdHlwZS5jb21wb25lbnRXaWxsVW5tb3VudD1mdW5jdGlvbigpe3RoaXMuZWRpdG9yLm9mZigiY2hhbmdlIix0aGlzLm9uRWRpdCksdGhpcy5lZGl0b3Iub2ZmKCJrZXl1cCIsdGhpcy5vbktleVVwKSx0aGlzLmVkaXRvcj1udWxsfSx0LnByb3RvdHlwZS5yZW5kZXI9ZnVuY3Rpb24oKXtyZXR1cm4gby5jcmVhdGVFbGVtZW50KGEuZGVmYXVsdCxudWxsLG8uY3JlYXRlRWxlbWVudChsLHtyZWY6dGhpcy5zZXROb2RlfSkpfSx0LnByb3RvdHlwZS5nZXRDb2RlTWlycm9yPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZWRpdG9yfSx0LnByb3RvdHlwZS5nZXRDbGllbnRIZWlnaHQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5ub2RlJiZ0aGlzLm5vZGUuY2xpZW50SGVpZ2h0fSx0fShvLkNvbXBvbmVudCk7dC5Db25maWdFZGl0b3I9dTt2YXIgYyxsPXMuc3R5bGVkLmRpdihjfHwoYz1pKFsiXG4gIGZsZXg6IDE7XG4gIGhlaWdodDogMTAwJTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAuQ29kZU1pcnJvci1saW5lbnVtYmVycyB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4iXSxbIlxuICBmbGV4OiAxO1xuICBoZWlnaHQ6IDEwMCU7XG4gIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgLkNvZGVNaXJyb3ItbGluZW51bWJlcnMge1xuICAgIGJhY2tncm91bmQ6ICIsIjtcbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnJlc3VsdEJhY2tncm91bmR9KX0sZnVuY3Rpb24oZSx0LG4peyFmdW5jdGlvbihlKXtlKG4oMikpfShmdW5jdGlvbihlKXsidXNlIHN0cmljdCI7ZS5kZWZpbmVNb2RlKCJ5YW1sIixmdW5jdGlvbigpe3ZhciBlPVsidHJ1ZSIsImZhbHNlIiwib24iLCJvZmYiLCJ5ZXMiLCJubyJdLHQ9bmV3IFJlZ0V4cCgiXFxiKCgiK2Uuam9pbigiKXwoIikrIikpJCIsImkiKTtyZXR1cm57dG9rZW46ZnVuY3Rpb24oZSxuKXt2YXIgcj1lLnBlZWsoKSxpPW4uZXNjYXBlZDtpZihuLmVzY2FwZWQ9ITEsIiMiPT1yJiYoMD09ZS5wb3N8fC9ccy8udGVzdChlLnN0cmluZy5jaGFyQXQoZS5wb3MtMSkpKSlyZXR1cm4gZS5za2lwVG9FbmQoKSwiY29tbWVudCI7aWYoZS5tYXRjaCgvXignKFteJ118XFwuKSonP3wiKFteIl18XFwuKSoiPykvKSlyZXR1cm4ic3RyaW5nIjtpZihuLmxpdGVyYWwmJmUuaW5kZW50YXRpb24oKT5uLmtleUNvbClyZXR1cm4gZS5za2lwVG9FbmQoKSwic3RyaW5nIjtpZihuLmxpdGVyYWwmJihuLmxpdGVyYWw9ITEpLGUuc29sKCkpe2lmKG4ua2V5Q29sPTAsbi5wYWlyPSExLG4ucGFpclN0YXJ0PSExLGUubWF0Y2goLy0tLS8pKXJldHVybiJkZWYiO2lmKGUubWF0Y2goL1wuXC5cLi8pKXJldHVybiJkZWYiO2lmKGUubWF0Y2goL1xzKi1ccysvKSlyZXR1cm4ibWV0YSJ9aWYoZS5tYXRjaCgvXihce3xcfXxcW3xcXSkvKSlyZXR1cm4ieyI9PXI/bi5pbmxpbmVQYWlycysrOiJ9Ij09cj9uLmlubGluZVBhaXJzLS06IlsiPT1yP24uaW5saW5lTGlzdCsrOm4uaW5saW5lTGlzdC0tLCJtZXRhIjtpZihuLmlubGluZUxpc3Q+MCYmIWkmJiIsIj09cilyZXR1cm4gZS5uZXh0KCksIm1ldGEiO2lmKG4uaW5saW5lUGFpcnM+MCYmIWkmJiIsIj09cilyZXR1cm4gbi5rZXlDb2w9MCxuLnBhaXI9ITEsbi5wYWlyU3RhcnQ9ITEsZS5uZXh0KCksIm1ldGEiO2lmKG4ucGFpclN0YXJ0KXtpZihlLm1hdGNoKC9eXHMqKFx8fFw+KVxzKi8pKXJldHVybiBuLmxpdGVyYWw9ITAsIm1ldGEiO2lmKGUubWF0Y2goL15ccyooXCZ8XCopW2EtejAtOVwuXy1dK1xiL2kpKXJldHVybiJ2YXJpYWJsZS0yIjtpZigwPT1uLmlubGluZVBhaXJzJiZlLm1hdGNoKC9eXHMqLT9bMC05XC5cLF0rXHM/JC8pKXJldHVybiJudW1iZXIiO2lmKG4uaW5saW5lUGFpcnM+MCYmZS5tYXRjaCgvXlxzKi0/WzAtOVwuXCxdK1xzPyg/PSgsfH0pKS8pKXJldHVybiJudW1iZXIiO2lmKGUubWF0Y2godCkpcmV0dXJuImtleXdvcmQifXJldHVybiFuLnBhaXImJmUubWF0Y2goL15ccyooPzpbLFxbXF17fSYqIXw+JyIlQGBdW15ccyciOl18W14sXFtcXXt9IyYqIXw+JyIlQGBdKVteI10qPyg/PVxzKjooJHxccykpLyk/KG4ucGFpcj0hMCxuLmtleUNvbD1lLmluZGVudGF0aW9uKCksImF0b20iKTpuLnBhaXImJmUubWF0Y2goL146XHMqLyk/KG4ucGFpclN0YXJ0PSEwLCJtZXRhIik6KG4ucGFpclN0YXJ0PSExLG4uZXNjYXBlZD0iXFwiPT1yLGUubmV4dCgpLG51bGwpfSxzdGFydFN0YXRlOmZ1bmN0aW9uKCl7cmV0dXJue3BhaXI6ITEscGFpclN0YXJ0OiExLGtleUNvbDowLGlubGluZVBhaXJzOjAsaW5saW5lTGlzdDowLGxpdGVyYWw6ITEsZXNjYXBlZDohMX19LGxpbmVDb21tZW50OiIjIn19KSxlLmRlZmluZU1JTUUoInRleHQveC15YW1sIiwieWFtbCIpLGUuZGVmaW5lTUlNRSgidGV4dC95YW1sIiwieWFtbCIpfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oKXt2YXIgZT1mdW5jdGlvbih0LG4pe3JldHVybihlPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8e19fcHJvdG9fXzpbXX1pbnN0YW5jZW9mIEFycmF5JiZmdW5jdGlvbihlLHQpe2UuX19wcm90b19fPXR9fHxmdW5jdGlvbihlLHQpe2Zvcih2YXIgbiBpbiB0KXQuaGFzT3duUHJvcGVydHkobikmJihlW25dPXRbbl0pfSkodCxuKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKSxpPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZSwicmF3Iix7dmFsdWU6dH0pOmUucmF3PXQsZX07T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPW4oMCksYT1uKDEpLHM9bigxMzMpLHU9big4KSxjPW4oMTIpLGw9bigxNikscD1uKDM3KSxmPW4oOSksZD1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7cmV0dXJuIG51bGwhPT1lJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpc31yZXR1cm4gcih0LGUpLHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3JldHVybiBvLmNyZWF0ZUVsZW1lbnQocC5Db250YWluZXIsbnVsbCxvLmNyZWF0ZUVsZW1lbnQoeSxudWxsLG8uY3JlYXRlRWxlbWVudChwLmRlZmF1bHQsbnVsbCxvLmNyZWF0ZUVsZW1lbnQodixudWxsLG8uY3JlYXRlRWxlbWVudChzLlF1ZXJ5RWRpdG9yLHt2YWx1ZTp0aGlzLnByb3BzLnZhbHVlLG9uQ2hhbmdlOnRoaXMucHJvcHMub25DaGFuZ2V9KSkpKSl9LHR9KG8uQ29tcG9uZW50KSxoPXUuY3JlYXRlU3RydWN0dXJlZFNlbGVjdG9yKHt2YWx1ZTpjLmdldEZpbGV9KTt0LmRlZmF1bHQ9Zi5jb25uZWN0KGgse29uQ2hhbmdlOmwuZWRpdEZpbGV9KShkKTt2YXIgbSxnLHk9YS5zdHlsZWQuZGl2KG18fChtPWkoWyJcbiAgYmFja2dyb3VuZDogIiwiO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIC52YXJpYWJsZS1lZGl0b3Ige1xuICAgIGhlaWdodDogMTAwJSAhaW1wb3J0YW50O1xuICB9XG4gIC5Db2RlTWlycm9yIHtcbiAgICBiYWNrZ3JvdW5kOiBub25lICFpbXBvcnRhbnQ7XG4gICAgLkNvZGVNaXJyb3ItY29kZSB7XG4gICAgICBjb2xvcjogcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjcpO1xuICAgIH1cbiAgICAuY20tYXRvbSB7XG4gICAgICBjb2xvcjogcmdiYSg0MiwgMTI2LCAyMTAsIDEpO1xuICAgIH1cbiAgfVxuIl0sWyJcbiAgYmFja2dyb3VuZDogIiwiO1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIC52YXJpYWJsZS1lZGl0b3Ige1xuICAgIGhlaWdodDogMTAwJSAhaW1wb3J0YW50O1xuICB9XG4gIC5Db2RlTWlycm9yIHtcbiAgICBiYWNrZ3JvdW5kOiBub25lICFpbXBvcnRhbnQ7XG4gICAgLkNvZGVNaXJyb3ItY29kZSB7XG4gICAgICBjb2xvcjogcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjcpO1xuICAgIH1cbiAgICAuY20tYXRvbSB7XG4gICAgICBjb2xvcjogcmdiYSg0MiwgMTI2LCAyMTAsIDEpO1xuICAgIH1cbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnJlc3VsdEJhY2tncm91bmR9KSx2PWEuc3R5bGVkLmRpdihnfHwoZz1pKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGZsZXg6IDE7XG4iXSxbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBmbGV4OiAxO1xuIl0pKSl9LGZ1bmN0aW9uKGUsdCl7ZS5leHBvcnRzPXtuYW1lOiJncmFwaHFsLXBsYXlncm91bmQtcmVhY3QiLHZlcnNpb246IjEuNy4yMCIsbWFpbjoiLi9saWIvbGliLmpzIix0eXBpbmdzOiIuL2xpYi9saWIuZC50cyIsZGVzY3JpcHRpb246IkdyYXBoUUwgSURFIGZvciBiZXR0ZXIgZGV2ZWxvcG1lbnQgd29ya2Zsb3dzIChHcmFwaFFMIFN1YnNjcmlwdGlvbnMsIGludGVyYWN0aXZlIGRvY3MgJiBjb2xsYWJvcmF0aW9uKS4iLGNvbnRyaWJ1dG9yczpbIlRpbSBTdWNoYW5layA8dGltQGdyYXBoLmNvb2w+IiwiSm9oYW5uZXMgU2NoaWNrbGluZyA8am9oYW5uZXNAZ3JhcGguY29vbD4iLCJMdWthcyBIdXZhciA8bHVrYXNAaHV2YXIuY3o+Il0scmVwb3NpdG9yeTp7dHlwZToiZ2l0Iix1cmw6Imh0dHA6Ly9naXRodWIuY29tL2dyYXBoY29vbC9ncmFwaHFsLXBsYXlncm91bmQuZ2l0In0sbGljZW5zZToiTUlUIixzY3JpcHRzOntzdGFydDoibm9kZSBzY3JpcHRzL3N0YXJ0LmpzIiwic3RhcnQ6YW5hbHl6ZSI6IkFOQUxZWkVfQlVORExFPXRydWUgbm9kZSBzY3JpcHRzL3N0YXJ0LmpzIiwic3RhcnQ6Z3JhcGhxbC1iaW4iOiJBQ1RJVkVfQVBQPWdyYXBocWxiaW4gbm9kZSBzY3JpcHRzL3N0YXJ0LmpzIixwcmVwdWJsaXNoT25seToieWFybiBidWlsZCIsYnVpbGQ6InJpbXJhZiBkaXN0IGJ1aWxkIGRpc3QgJiYgeWFybiBidWlsZC1hcHAgJiYgeWFybiBidWlsZC1wYWNrYWdlIix0c2M6InRzYyAtcCB0c2NvbmZpZy5idWlsZC5qc29uIiwiYnVpbGQtcGFja2FnZSI6InJpbXJhZiBsaWIgYnVpbGQvZGlzdCAmJiBucG0gcnVuIHRzYyAmJiBiYWJlbCBsaWIgLWQgbGliICYmIGNwIC1yIC4vc3JjL2Fzc2V0cy8gLi9saWIvYXNzZXRzLyAmJiBjZCBsaWIgJiYgcmltcmFmICouanN4OyIsImJ1aWxkLWFwcCI6Im5vZGUgc2NyaXB0cy9idWlsZC5qcyIsdGVzdDoiamVzdCIsYnVuZGxlc2l6ZToiYnVuZGxlc2l6ZSIsYnVtcDoibnBtIHZlcnNpb24gcGF0Y2ggLS1uby1naXQtdGFnLXZlcnNpb24gJiYgZ2l0IGFkZCBwYWNrYWdlLmpzb24iLCJncmFwaHFsLWZha2VyIjoiZ3JhcGhxbC1mYWtlciAuL3Rlc3RzL3NjaGVtYS5mYWtlci5ncmFwaHFsIixsaW50Oid0c2xpbnQgInNyYy8qKi8qLnRzeyx4fSInLHByZWNvbW1pdDoibGludC1zdGFnZWQiLHByZXR0aWVyOiJwcmV0dGllciAtLXNpbmdsZS1xdW90ZSAtLW5vLXNlbWkgLS10cmFpbGluZy1jb21tYSBhbGwgLS13cml0ZSAqLnt0cyx0c3h9ICdzcmMvKiovKi57dHMsdHN4fScifSxmaWxlczpbImJ1aWxkIiwibGliIiwicGxheWdyb3VuZC5jc3MiXSxidW5kbGVzaXplOlt7cGF0aDoiYnVpbGQvc3RhdGljL2pzL2luZGV4LmpzIixtYXhTaXplOiI2NzQga0IifV0sZGV2RGVwZW5kZW5jaWVzOnsiQHR5cGVzL2RlYXN5bmMiOiIwLjEuMCIsIkB0eXBlcy9qZXN0IjoiMjIuMi4zIiwiQHR5cGVzL25vZGUiOiIxMC4xLjQiLCJAdHlwZXMvcmVhY3QiOiIxNi4zLjE0IiwiQHR5cGVzL3plbi1vYnNlcnZhYmxlIjoiXjAuNS4zIiwiYmFiZWwtY2xpIjoiNi4yNi4wIiwiYmFiZWwtY29yZSI6IjYuMjYuMyIsImJhYmVsLWxvYWRlciI6IjcuMS40IiwiYmFiZWwtcGx1Z2luLXN0eWxlZC1jb21wb25lbnRzIjoiXjEuOC4wIiwiYmFiZWwtcHJlc2V0LWVzMjAxNSI6IjYuMjQuMSIsImJhYmVsLXByZXNldC1lczIwMTYiOiI2LjI0LjEiLCJiYWJlbC1wcmVzZXQtcmVhY3QiOiI2LjI0LjEiLCJiYWJlbC1wcmVzZXQtc3RhZ2UtMyI6IjYuMjQuMSIsYnVuZGxlc2l6ZToiXjAuMTcuMCIsImNhc2Utc2Vuc2l0aXZlLXBhdGhzLXdlYnBhY2stcGx1Z2luIjoiMi4xLjIiLGNoYWxrOiIyLjQuMSIsImNvbm5lY3QtaGlzdG9yeS1hcGktZmFsbGJhY2siOiIxLjUuMCIsImNyb3NzLXNwYXduIjoiNi4wLjUiLCJjc3MtbG9hZGVyIjoiMC4yOC4xMSIsImRldGVjdC1wb3J0IjoiMS4yLjMiLGRvdGVudjoiNS4wLjEiLGVuenltZToiXjMuMy4wIiwiZW56eW1lLWFkYXB0ZXItcmVhY3QtMTYiOiJeMS4xLjEiLCJlbnp5bWUtdG8tanNvbiI6Il4zLjMuNCIsImV4dHJhY3QtdGV4dC13ZWJwYWNrLXBsdWdpbiI6IjMuMC4yIiwiZmlsZS1sb2FkZXIiOiIxLjEuMTEiLGZpbGVzaXplOiIzLjYuMSIsImZzLWV4dHJhIjoiNS4wLjAiLCJncmFwaHFsLXBsYXlncm91bmQtaHRtbCI6IjEuNS42IiwiZ3ppcC1zaXplIjoiNC4xLjAiLCJodG1sLXdlYnBhY2stcGx1Z2luIjoiMi4zMC4xIiwiaHR0cC1wcm94eS1taWRkbGV3YXJlIjoiMC4xNy40IixodXNreToiMC4xNC4zIixqZXN0OiIyMi4xLjQiLCJqZXN0LWxvY2Fsc3RvcmFnZS1tb2NrIjoiXjIuMi4wIiwianNvbi1sb2FkZXIiOiIwLjUuNyIsImxpbnQtc3RhZ2VkIjoiNi4xLjAiLCJub2RlLW5vb3AiOiIxLjAuMCIsIm9iamVjdC1hc3NpZ24iOiI0LjEuMSIscHJvbWlzZToiOC4wLjEiLCJyYXctbG9hZGVyIjoiMC41LjEiLCJyZWFjdC1kZXYtdXRpbHMiOiI1LjAuMSIsInJlY3Vyc2l2ZS1yZWFkZGlyIjoiMi4yLjIiLHJpbXJhZjoiMi42LjIiLCJzb3VyY2UtbWFwLWxvYWRlciI6IjAuMi4zIiwic3RyaXAtYW5zaSI6IjQuMC4wIiwic3R5bGUtbG9hZGVyIjoiMC4yMC4xIiwic3ZnLWlubGluZS1sb2FkZXIiOiIwLjguMCIsInN3LXByZWNhY2hlLXdlYnBhY2stcGx1Z2luIjoiMC4xMS41IiwidHMtbG9hZGVyIjoiMy40LjAiLHRzbGludDoiNS4xMC4wIiwidHNsaW50LWdyYXBoY29vbC1mcm9udGVuZCI6IjAuMC4zIiwidHNsaW50LWxvYWRlciI6IjMuNi4wIix0eXBlc2NyaXB0OiJeMy4wLjEiLCJ0eXBlc2NyaXB0LXN0eWxlZC1wbHVnaW4iOiJeMC4xMS4wIiwidXJsLWxvYWRlciI6IjAuNi4yIix3ZWJwYWNrOiIzLjEwLjAiLCJ3ZWJwYWNrLWRldi1zZXJ2ZXIiOiIyLjExLjEiLCJ3ZWJwYWNrLW1hbmlmZXN0LXBsdWdpbiI6IjEuMy4yIiwid2h5LWRpZC15b3UtdXBkYXRlIjoiMC4xLjEifSxkZXBlbmRlbmNpZXM6eyJAdHlwZXMvbHJ1LWNhY2hlIjoiXjQuMS4xIiwiYXBvbGxvLWxpbmsiOiJeMS4wLjciLCJhcG9sbG8tbGluay1odHRwIjoiXjEuMy4yIiwiYXBvbGxvLWxpbmstd3MiOiIxLjAuOCIsImNhbGN1bGF0ZS1zaXplIjoiXjEuMS4xIixjb2RlbWlycm9yOiJeNS4zOC4wIiwiY29kZW1pcnJvci1ncmFwaHFsIjoidGltc3VjaGFuZWsvY29kZW1pcnJvci1ncmFwaHFsI2RldGFpbHMtZml4IiwiY29weS10by1jbGlwYm9hcmQiOiJeMy4wLjgiLGNyeXB0aWxlczoiNC4xLjIiLGN1aWQ6Il4xLjMuOCIsZ3JhcGhpcWw6Il4wLjExLjIiLGdyYXBocWw6Il4wLjExLjciLGltbXV0YWJsZToiXjQuMC4wLXJjLjkiLCJpc29tb3JwaGljLWZldGNoIjoiXjIuMi4xIiwianMteWFtbCI6Il4zLjEwLjAiLCJqc29uLXN0YWJsZS1zdHJpbmdpZnkiOiJeMS4wLjEiLGtleWNvZGU6Il4yLjEuOSIsbG9kYXNoOiJeNC4xNy4xMSIsImxvZGFzaC5kZWJvdW5jZSI6Il40LjAuOCIsIm1hcmtkb3duLWl0IjoiXjguNC4xIixtYXJrZWQ6Il4wLjMuMTkiLHByZXR0aWVyOiJeMS4xMy4wIiwicHJvcC10eXBlcyI6Il4xNS42LjAiLCJxdWVyeS1zdHJpbmciOiI1IixyZWFjdDoiXjE2LjMuMSIsInJlYWN0LWFkZG9ucy1zaGFsbG93LWNvbXBhcmUiOiJeMTUuNi4yIiwicmVhY3QtY29kZW1pcnJvciI6Il4xLjAuMCIsInJlYWN0LWNvcHktdG8tY2xpcGJvYXJkIjoiXjUuMC4xIiwicmVhY3QtZGlzcGxheS1uYW1lIjoiXjAuMi4zIiwicmVhY3QtZG9tIjoiXjE2LjMuMSIsInJlYWN0LWhlbG1ldCI6Il41LjIuMCIsInJlYWN0LWlucHV0LWF1dG9zaXplIjoiXjIuMi4xIiwicmVhY3QtbW9kYWwiOiJeMy4xLjExIiwicmVhY3QtcmVkdXgiOiJeNS4wLjYiLCJyZWFjdC1yb3V0ZXItZG9tIjoiXjQuMi4yIiwicmVhY3Qtc29ydGFibGUtaG9jIjoiXjAuOC4zIiwicmVhY3QtdHJhbnNpdGlvbi1ncm91cCI6Il4yLjIuMSIsInJlYWN0LXZpcnR1YWxpemVkIjoiXjkuMTIuMCIscmVkdXg6Il4zLjcuMiIsInJlZHV4LWFjdGlvbnMiOiJeMi4yLjEiLCJyZWR1eC1pbW11dGFibGUiOiJeNC4wLjAiLCJyZWR1eC1sb2NhbHN0b3JhZ2UiOiJyYyIsInJlZHV4LWxvY2Fsc3RvcmFnZS1kZWJvdW5jZSI6Il4wLjEuMCIsInJlZHV4LWxvY2Fsc3RvcmFnZS1maWx0ZXIiOiJeMC4xLjEiLCJyZWR1eC1zYWdhIjoiXjAuMTYuMCIscmVzZWxlY3Q6Il4zLjAuMSIsInNlYW1sZXNzLWltbXV0YWJsZSI6Il43LjAuMSIsInN0eWxlZC1jb21wb25lbnRzIjoiXjQuMC4wIiwic3Vic2NyaXB0aW9ucy10cmFuc3BvcnQtd3MiOiJeMC45LjUiLCJ1dGlsaXR5LXR5cGVzIjoiXjEuMC4wIiwid2VicGFjay1idW5kbGUtYW5hbHl6ZXIiOiJeMi45LjIiLCJ6ZW4tb2JzZXJ2YWJsZSI6Il4wLjcuMSJ9LCJsaW50LXN0YWdlZCI6eyIqLnt0cyx0c3h9IjpbInByZXR0aWVyIC0tc2luZ2xlLXF1b3RlIC0tbm8tc2VtaSAtLXdyaXRlIiwidHNsaW50IiwiZ2l0IGFkZCJdLGdpdERpcjoiLi4vLi4vIn0samVzdDp7Y29sbGVjdENvdmVyYWdlRnJvbTpbInNyYy8qKi8qLnt0cyx0c3h9Il0sc2V0dXBGaWxlczpbIjxyb290RGlyPi9jb25maWcvcG9seWZpbGxzLmpzIl0sdGVzdFBhdGhJZ25vcmVQYXR0ZXJuczpbIjxyb290RGlyPlsvXFxcXF0oYnVpbGR8ZG9jc3xub2RlX21vZHVsZXMpWy9cXFxcXSJdLHRlc3RFbnZpcm9ubWVudDoibm9kZSIsdGVzdFVSTDoiaHR0cDovL2xvY2FsaG9zdCIsdHJhbnNmb3JtOnsiXi4rXFwuY3NzJCI6Ijxyb290RGlyPi9jb25maWcvamVzdC9jc3NUcmFuc2Zvcm0uanMiLCJeLitcXC50c3g/JCI6Ijxyb290RGlyPi9jb25maWcvamVzdC90eXBlc2NyaXB0VHJhbnNmb3JtLmpzIiwiXig/IS4qXFwuKGNzc3xqc29uKSQpIjoiPHJvb3REaXI+L2NvbmZpZy9qZXN0L2ZpbGVUcmFuc2Zvcm0uanMifSx0cmFuc2Zvcm1JZ25vcmVQYXR0ZXJuczpbIlsvXFxcXF1ub2RlX21vZHVsZXNbL1xcXFxdLitcXC4oanN8anN4KSQiXSxtb2R1bGVOYW1lTWFwcGVyOnsiXnJlYWN0LW5hdGl2ZSQiOiJyZWFjdC1uYXRpdmUtd2ViIn0sbW9kdWxlRmlsZUV4dGVuc2lvbnM6WyJ0cyIsInRzeCIsImpzIl0sdGVzdFJlZ2V4OiIoL19fdGVzdHNfXy8uKnxcXC4odGVzdHxzcGVjKSlcXC4odHN8dHN4fGpzKSQifX19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7dmFyIHI9ZnVuY3Rpb24oZSx0LG4scil7cmV0dXJuIG5ldyhufHwobj1Qcm9taXNlKSkoZnVuY3Rpb24oaSxvKXtmdW5jdGlvbiBhKGUpe3RyeXt1KHIubmV4dChlKSl9Y2F0Y2goZSl7byhlKX19ZnVuY3Rpb24gcyhlKXt0cnl7dShyLnRocm93KGUpKX1jYXRjaChlKXtvKGUpfX1mdW5jdGlvbiB1KGUpe2UuZG9uZT9pKGUudmFsdWUpOm5ldyBuKGZ1bmN0aW9uKHQpe3QoZS52YWx1ZSl9KS50aGVuKGEscyl9dSgocj1yLmFwcGx5KGUsdHx8W10pKS5uZXh0KCkpfSl9LGk9ZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gcihbZSx0XSl9fWZ1bmN0aW9uIHIobil7aWYoaSl0aHJvdyBuZXcgVHlwZUVycm9yKCJHZW5lcmF0b3IgaXMgYWxyZWFkeSBleGVjdXRpbmcuIik7Zm9yKDt1Oyl0cnl7aWYoaT0xLG8mJihhPTImblswXT9vLnJldHVybjpuWzBdP28udGhyb3d8fCgoYT1vLnJldHVybikmJmEuY2FsbChvKSwwKTpvLm5leHQpJiYhKGE9YS5jYWxsKG8sblsxXSkpLmRvbmUpcmV0dXJuIGE7c3dpdGNoKG89MCxhJiYobj1bMiZuWzBdLGEudmFsdWVdKSxuWzBdKXtjYXNlIDA6Y2FzZSAxOmE9bjticmVhaztjYXNlIDQ6cmV0dXJuIHUubGFiZWwrKyx7dmFsdWU6blsxXSxkb25lOiExfTtjYXNlIDU6dS5sYWJlbCsrLG89blsxXSxuPVswXTtjb250aW51ZTtjYXNlIDc6bj11Lm9wcy5wb3AoKSx1LnRyeXMucG9wKCk7Y29udGludWU7ZGVmYXVsdDppZihhPXUudHJ5cywhKGE9YS5sZW5ndGg+MCYmYVthLmxlbmd0aC0xXSkmJig2PT09blswXXx8Mj09PW5bMF0pKXt1PTA7Y29udGludWV9aWYoMz09PW5bMF0mJighYXx8blsxXT5hWzBdJiZuWzFdPGFbM10pKXt1LmxhYmVsPW5bMV07YnJlYWt9aWYoNj09PW5bMF0mJnUubGFiZWw8YVsxXSl7dS5sYWJlbD1hWzFdLGE9bjticmVha31pZihhJiZ1LmxhYmVsPGFbMl0pe3UubGFiZWw9YVsyXSx1Lm9wcy5wdXNoKG4pO2JyZWFrfWFbMl0mJnUub3BzLnBvcCgpLHUudHJ5cy5wb3AoKTtjb250aW51ZX1uPXQuY2FsbChlLHUpfWNhdGNoKGUpe249WzYsZV0sbz0wfWZpbmFsbHl7aT1hPTB9aWYoNSZuWzBdKXRocm93IG5bMV07cmV0dXJue3ZhbHVlOm5bMF0/blsxXTp2b2lkIDAsZG9uZTohMH19dmFyIGksbyxhLHMsdT17bGFiZWw6MCxzZW50OmZ1bmN0aW9uKCl7aWYoMSZhWzBdKXRocm93IGFbMV07cmV0dXJuIGFbMV19LHRyeXM6W10sb3BzOltdfTtyZXR1cm4gcz17bmV4dDpuKDApLHRocm93Om4oMSkscmV0dXJuOm4oMil9LCJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiYoc1tTeW1ib2wuaXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9KSxzfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89big3NCksYT1vLm1lbW9pemUoZnVuY3Rpb24oZSl7cmV0dXJuIGU8PTE/MTphKGUtMSkrYShlLTIpfSkscz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dmFyIHQ9dGhpczt0aGlzLmNvdW50PTEsdGhpcy5ydW5uaW5nPSEwLHRoaXMubWF4UmV0cmllcz0yMCx0aGlzLnN0b3A9ZnVuY3Rpb24oKXt0LnJ1bm5pbmc9ITEsY2xlYXJUaW1lb3V0KHQudGltZW91dCl9LHRoaXMuY2I9ZX1yZXR1cm4gZS5wcm90b3R5cGUuc3RhcnQ9ZnVuY3Rpb24oKXtyZXR1cm4gcih0aGlzLHZvaWQgMCx2b2lkIDAsZnVuY3Rpb24oKXt2YXIgZSx0PXRoaXM7cmV0dXJuIGkodGhpcyxmdW5jdGlvbihuKXtyZXR1cm4gZT1mdW5jdGlvbigpe3JldHVybiByKHQsdm9pZCAwLHZvaWQgMCxmdW5jdGlvbigpe3JldHVybiBpKHRoaXMsZnVuY3Rpb24odCl7c3dpdGNoKHQubGFiZWwpe2Nhc2UgMDpyZXR1cm5bNCx0aGlzLmNiKCldO2Nhc2UgMTpyZXR1cm4gdC5zZW50KCksdGhpcy5jb3VudCsrLHRoaXMucnVubmluZyYmdGhpcy5jb3VudDx0aGlzLm1heFJldHJpZXMmJih0aGlzLnRpbWVvdXQ9c2V0VGltZW91dChlLDFlMyoodGhpcy5jb3VudDwzPzU6YSh0aGlzLmNvdW50LTUpKSkpLFsyXX19KX0pfSxlKCksWzJdfSl9KX0sZX0oKTt0LkJhY2tvZmY9c30sZnVuY3Rpb24oZSx0LG4pe2Z1bmN0aW9uIHIoZSl7cmV0dXJuIGUmJmUuX19lc01vZHVsZT9lOntkZWZhdWx0OmV9fWZ1bmN0aW9uIGkoZSx0KXt2YXIgbj17fTtmb3IodmFyIHIgaW4gZSl0LmluZGV4T2Yocik+PTB8fE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLHIpJiYobltyXT1lW3JdKTtyZXR1cm4gbn1mdW5jdGlvbiBvKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9ZnVuY3Rpb24gYShlLHQpe2lmKCFlKXRocm93IG5ldyBSZWZlcmVuY2VFcnJvcigidGhpcyBoYXNuJ3QgYmVlbiBpbml0aWFsaXNlZCAtIHN1cGVyKCkgaGFzbid0IGJlZW4gY2FsbGVkIik7cmV0dXJuIXR8fCJvYmplY3QiIT09dHlwZW9mIHQmJiJmdW5jdGlvbiIhPT10eXBlb2YgdD9lOnR9ZnVuY3Rpb24gcyhlLHQpe2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgdCYmbnVsbCE9PXQpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3VwZXIgZXhwcmVzc2lvbiBtdXN0IGVpdGhlciBiZSBudWxsIG9yIGEgZnVuY3Rpb24sIG5vdCAiK3R5cGVvZiB0KTtlLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKHQmJnQucHJvdG90eXBlLHtjb25zdHJ1Y3Rvcjp7dmFsdWU6ZSxlbnVtZXJhYmxlOiExLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH19KSx0JiYoT2JqZWN0LnNldFByb3RvdHlwZU9mP09iamVjdC5zZXRQcm90b3R5cGVPZihlLHQpOmUuX19wcm90b19fPXQpfXQuX19lc01vZHVsZT0hMCx0LkhlbG1ldD12b2lkIDA7dmFyIHU9T2JqZWN0LmFzc2lnbnx8ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PTE7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyl7dmFyIG49YXJndW1lbnRzW3RdO2Zvcih2YXIgciBpbiBuKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChuLHIpJiYoZVtyXT1uW3JdKX1yZXR1cm4gZX0sYz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXtmb3IodmFyIG49MDtuPHQubGVuZ3RoO24rKyl7dmFyIHI9dFtuXTtyLmVudW1lcmFibGU9ci5lbnVtZXJhYmxlfHwhMSxyLmNvbmZpZ3VyYWJsZT0hMCwidmFsdWUiaW4gciYmKHIud3JpdGFibGU9ITApLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIua2V5LHIpfX1yZXR1cm4gZnVuY3Rpb24odCxuLHIpe3JldHVybiBuJiZlKHQucHJvdG90eXBlLG4pLHImJmUodCxyKSx0fX0oKSxsPW4oMCkscD1yKGwpLGY9bigxOCksZD1yKGYpLGg9big3MTYpLG09cihoKSxnPW4oNzE4KSx5PXIoZyksdj1uKDcyMSksYj1uKDMwMikseD1mdW5jdGlvbigpe3JldHVybiBudWxsfSxDPSgwLG0uZGVmYXVsdCkodi5yZWR1Y2VQcm9wc1RvU3RhdGUsdi5oYW5kbGVDbGllbnRTdGF0ZUNoYW5nZSx2Lm1hcFN0YXRlT25TZXJ2ZXIpKHgpLEU9ZnVuY3Rpb24oZSl7dmFyIHQsbjtyZXR1cm4gbj10PWZ1bmN0aW9uKHQpe2Z1bmN0aW9uIG4oKXtyZXR1cm4gbyh0aGlzLG4pLGEodGhpcyx0LmFwcGx5KHRoaXMsYXJndW1lbnRzKSl9cmV0dXJuIHMobix0KSxuLnByb3RvdHlwZS5zaG91bGRDb21wb25lbnRVcGRhdGU9ZnVuY3Rpb24oZSl7cmV0dXJuISgwLHkuZGVmYXVsdCkodGhpcy5wcm9wcyxlKX0sbi5wcm90b3R5cGUubWFwTmVzdGVkQ2hpbGRyZW5Ub1Byb3BzPWZ1bmN0aW9uKGUsdCl7aWYoIXQpcmV0dXJuIG51bGw7c3dpdGNoKGUudHlwZSl7Y2FzZSBiLlRBR19OQU1FUy5TQ1JJUFQ6Y2FzZSBiLlRBR19OQU1FUy5OT1NDUklQVDpyZXR1cm57aW5uZXJIVE1MOnR9O2Nhc2UgYi5UQUdfTkFNRVMuU1RZTEU6cmV0dXJue2Nzc1RleHQ6dH19dGhyb3cgbmV3IEVycm9yKCI8IitlLnR5cGUrIiAvPiBlbGVtZW50cyBhcmUgc2VsZi1jbG9zaW5nIGFuZCBjYW4gbm90IGNvbnRhaW4gY2hpbGRyZW4uIFJlZmVyIHRvIG91ciBBUEkgZm9yIG1vcmUgaW5mb3JtYXRpb24uIil9LG4ucHJvdG90eXBlLmZsYXR0ZW5BcnJheVR5cGVDaGlsZHJlbj1mdW5jdGlvbihlKXt2YXIgdCxuPWUuY2hpbGQscj1lLmFycmF5VHlwZUNoaWxkcmVuLGk9ZS5uZXdDaGlsZFByb3BzLG89ZS5uZXN0ZWRDaGlsZHJlbjtyZXR1cm4gdSh7fSxyLCh0PXt9LHRbbi50eXBlXT1bXS5jb25jYXQocltuLnR5cGVdfHxbXSxbdSh7fSxpLHRoaXMubWFwTmVzdGVkQ2hpbGRyZW5Ub1Byb3BzKG4sbykpXSksdCkpfSxuLnByb3RvdHlwZS5tYXBPYmplY3RUeXBlQ2hpbGRyZW49ZnVuY3Rpb24oZSl7dmFyIHQsbixyPWUuY2hpbGQsaT1lLm5ld1Byb3BzLG89ZS5uZXdDaGlsZFByb3BzLGE9ZS5uZXN0ZWRDaGlsZHJlbjtzd2l0Y2goci50eXBlKXtjYXNlIGIuVEFHX05BTUVTLlRJVExFOnJldHVybiB1KHt9LGksKHQ9e30sdFtyLnR5cGVdPWEsdC50aXRsZUF0dHJpYnV0ZXM9dSh7fSxvKSx0KSk7Y2FzZSBiLlRBR19OQU1FUy5CT0RZOnJldHVybiB1KHt9LGkse2JvZHlBdHRyaWJ1dGVzOnUoe30sbyl9KTtjYXNlIGIuVEFHX05BTUVTLkhUTUw6cmV0dXJuIHUoe30saSx7aHRtbEF0dHJpYnV0ZXM6dSh7fSxvKX0pfXJldHVybiB1KHt9LGksKG49e30sbltyLnR5cGVdPXUoe30sbyksbikpfSxuLnByb3RvdHlwZS5tYXBBcnJheVR5cGVDaGlsZHJlblRvUHJvcHM9ZnVuY3Rpb24oZSx0KXt2YXIgbj11KHt9LHQpO3JldHVybiBPYmplY3Qua2V5cyhlKS5mb3JFYWNoKGZ1bmN0aW9uKHQpe3ZhciByO249dSh7fSxuLChyPXt9LHJbdF09ZVt0XSxyKSl9KSxufSxuLnByb3RvdHlwZS53YXJuT25JbnZhbGlkQ2hpbGRyZW49ZnVuY3Rpb24oZSx0KXtyZXR1cm4hMH0sbi5wcm90b3R5cGUubWFwQ2hpbGRyZW5Ub1Byb3BzPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcyxyPXt9O3JldHVybiBwLmRlZmF1bHQuQ2hpbGRyZW4uZm9yRWFjaChlLGZ1bmN0aW9uKGUpe2lmKGUmJmUucHJvcHMpe3ZhciBvPWUucHJvcHMsYT1vLmNoaWxkcmVuLHM9aShvLFsiY2hpbGRyZW4iXSksdT0oMCx2LmNvbnZlcnRSZWFjdFByb3BzdG9IdG1sQXR0cmlidXRlcykocyk7c3dpdGNoKG4ud2Fybk9uSW52YWxpZENoaWxkcmVuKGUsYSksZS50eXBlKXtjYXNlIGIuVEFHX05BTUVTLkxJTks6Y2FzZSBiLlRBR19OQU1FUy5NRVRBOmNhc2UgYi5UQUdfTkFNRVMuTk9TQ1JJUFQ6Y2FzZSBiLlRBR19OQU1FUy5TQ1JJUFQ6Y2FzZSBiLlRBR19OQU1FUy5TVFlMRTpyPW4uZmxhdHRlbkFycmF5VHlwZUNoaWxkcmVuKHtjaGlsZDplLGFycmF5VHlwZUNoaWxkcmVuOnIsbmV3Q2hpbGRQcm9wczp1LG5lc3RlZENoaWxkcmVuOmF9KTticmVhaztkZWZhdWx0OnQ9bi5tYXBPYmplY3RUeXBlQ2hpbGRyZW4oe2NoaWxkOmUsbmV3UHJvcHM6dCxuZXdDaGlsZFByb3BzOnUsbmVzdGVkQ2hpbGRyZW46YX0pfX19KSx0PXRoaXMubWFwQXJyYXlUeXBlQ2hpbGRyZW5Ub1Byb3BzKHIsdCl9LG4ucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3ZhciB0PXRoaXMucHJvcHMsbj10LmNoaWxkcmVuLHI9aSh0LFsiY2hpbGRyZW4iXSksbz11KHt9LHIpO3JldHVybiBuJiYobz10aGlzLm1hcENoaWxkcmVuVG9Qcm9wcyhuLG8pKSxwLmRlZmF1bHQuY3JlYXRlRWxlbWVudChlLG8pfSxjKG4sbnVsbCxbe2tleToiY2FuVXNlRE9NIixzZXQ6ZnVuY3Rpb24odCl7ZS5jYW5Vc2VET009dH19XSksbn0ocC5kZWZhdWx0LkNvbXBvbmVudCksdC5wcm9wVHlwZXM9e2Jhc2U6ZC5kZWZhdWx0Lm9iamVjdCxib2R5QXR0cmlidXRlczpkLmRlZmF1bHQub2JqZWN0LGNoaWxkcmVuOmQuZGVmYXVsdC5vbmVPZlR5cGUoW2QuZGVmYXVsdC5hcnJheU9mKGQuZGVmYXVsdC5ub2RlKSxkLmRlZmF1bHQubm9kZV0pLGRlZmF1bHRUaXRsZTpkLmRlZmF1bHQuc3RyaW5nLGRlZmVyOmQuZGVmYXVsdC5ib29sLGVuY29kZVNwZWNpYWxDaGFyYWN0ZXJzOmQuZGVmYXVsdC5ib29sLGh0bWxBdHRyaWJ1dGVzOmQuZGVmYXVsdC5vYmplY3QsbGluazpkLmRlZmF1bHQuYXJyYXlPZihkLmRlZmF1bHQub2JqZWN0KSxtZXRhOmQuZGVmYXVsdC5hcnJheU9mKGQuZGVmYXVsdC5vYmplY3QpLG5vc2NyaXB0OmQuZGVmYXVsdC5hcnJheU9mKGQuZGVmYXVsdC5vYmplY3QpLG9uQ2hhbmdlQ2xpZW50U3RhdGU6ZC5kZWZhdWx0LmZ1bmMsc2NyaXB0OmQuZGVmYXVsdC5hcnJheU9mKGQuZGVmYXVsdC5vYmplY3QpLHN0eWxlOmQuZGVmYXVsdC5hcnJheU9mKGQuZGVmYXVsdC5vYmplY3QpLHRpdGxlOmQuZGVmYXVsdC5zdHJpbmcsdGl0bGVBdHRyaWJ1dGVzOmQuZGVmYXVsdC5vYmplY3QsdGl0bGVUZW1wbGF0ZTpkLmRlZmF1bHQuc3RyaW5nfSx0LmRlZmF1bHRQcm9wcz17ZGVmZXI6ITAsZW5jb2RlU3BlY2lhbENoYXJhY3RlcnM6ITB9LHQucGVlaz1lLnBlZWssdC5yZXdpbmQ9ZnVuY3Rpb24oKXt2YXIgdD1lLnJld2luZCgpO3JldHVybiB0fHwodD0oMCx2Lm1hcFN0YXRlT25TZXJ2ZXIpKHtiYXNlVGFnOltdLGJvZHlBdHRyaWJ1dGVzOnt9LGVuY29kZVNwZWNpYWxDaGFyYWN0ZXJzOiEwLGh0bWxBdHRyaWJ1dGVzOnt9LGxpbmtUYWdzOltdLG1ldGFUYWdzOltdLG5vc2NyaXB0VGFnczpbXSxzY3JpcHRUYWdzOltdLHN0eWxlVGFnczpbXSx0aXRsZToiIix0aXRsZUF0dHJpYnV0ZXM6e319KSksdH0sbn0oQyk7RS5yZW5kZXJTdGF0aWM9RS5yZXdpbmQsdC5IZWxtZXQ9RSx0LmRlZmF1bHQ9RX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX1mdW5jdGlvbiBpKGUsdCl7aWYoIShlIGluc3RhbmNlb2YgdCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9ZnVuY3Rpb24gbyhlLHQpe2lmKCFlKXRocm93IG5ldyBSZWZlcmVuY2VFcnJvcigidGhpcyBoYXNuJ3QgYmVlbiBpbml0aWFsaXNlZCAtIHN1cGVyKCkgaGFzbid0IGJlZW4gY2FsbGVkIik7cmV0dXJuIXR8fCJvYmplY3QiIT09dHlwZW9mIHQmJiJmdW5jdGlvbiIhPT10eXBlb2YgdD9lOnR9ZnVuY3Rpb24gYShlLHQpe2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgdCYmbnVsbCE9PXQpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3VwZXIgZXhwcmVzc2lvbiBtdXN0IGVpdGhlciBiZSBudWxsIG9yIGEgZnVuY3Rpb24sIG5vdCAiK3R5cGVvZiB0KTtlLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKHQmJnQucHJvdG90eXBlLHtjb25zdHJ1Y3Rvcjp7dmFsdWU6ZSxlbnVtZXJhYmxlOiExLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH19KSx0JiYoT2JqZWN0LnNldFByb3RvdHlwZU9mP09iamVjdC5zZXRQcm90b3R5cGVPZihlLHQpOmUuX19wcm90b19fPXQpfXZhciBzPW4oMCksdT1yKHMpLGM9bigyNTgpLGw9cihjKSxwPW4oNzE3KSxmPXIocCk7ZS5leHBvcnRzPWZ1bmN0aW9uKGUsdCxuKXtmdW5jdGlvbiByKGUpe3JldHVybiBlLmRpc3BsYXlOYW1lfHxlLm5hbWV8fCJDb21wb25lbnQifWlmKCJmdW5jdGlvbiIhPT10eXBlb2YgZSl0aHJvdyBuZXcgRXJyb3IoIkV4cGVjdGVkIHJlZHVjZVByb3BzVG9TdGF0ZSB0byBiZSBhIGZ1bmN0aW9uLiIpO2lmKCJmdW5jdGlvbiIhPT10eXBlb2YgdCl0aHJvdyBuZXcgRXJyb3IoIkV4cGVjdGVkIGhhbmRsZVN0YXRlQ2hhbmdlT25DbGllbnQgdG8gYmUgYSBmdW5jdGlvbi4iKTtpZigidW5kZWZpbmVkIiE9PXR5cGVvZiBuJiYiZnVuY3Rpb24iIT09dHlwZW9mIG4pdGhyb3cgbmV3IEVycm9yKCJFeHBlY3RlZCBtYXBTdGF0ZU9uU2VydmVyIHRvIGVpdGhlciBiZSB1bmRlZmluZWQgb3IgYSBmdW5jdGlvbi4iKTtyZXR1cm4gZnVuY3Rpb24oYyl7ZnVuY3Rpb24gcCgpe2g9ZShkLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZS5wcm9wc30pKSxtLmNhblVzZURPTT90KGgpOm4mJihoPW4oaCkpfWlmKCJmdW5jdGlvbiIhPT10eXBlb2YgYyl0aHJvdyBuZXcgRXJyb3IoIkV4cGVjdGVkIFdyYXBwZWRDb21wb25lbnQgdG8gYmUgYSBSZWFjdCBjb21wb25lbnQuIik7dmFyIGQ9W10saD12b2lkIDAsbT1mdW5jdGlvbihlKXtmdW5jdGlvbiB0KCl7cmV0dXJuIGkodGhpcyx0KSxvKHRoaXMsZS5hcHBseSh0aGlzLGFyZ3VtZW50cykpfXJldHVybiBhKHQsZSksdC5wZWVrPWZ1bmN0aW9uKCl7cmV0dXJuIGh9LHQucmV3aW5kPWZ1bmN0aW9uKCl7aWYodC5jYW5Vc2VET00pdGhyb3cgbmV3IEVycm9yKCJZb3UgbWF5IG9ubHkgY2FsbCByZXdpbmQoKSBvbiB0aGUgc2VydmVyLiBDYWxsIHBlZWsoKSB0byByZWFkIHRoZSBjdXJyZW50IHN0YXRlLiIpO3ZhciBlPWg7cmV0dXJuIGg9dm9pZCAwLGQ9W10sZX0sdC5wcm90b3R5cGUuc2hvdWxkQ29tcG9uZW50VXBkYXRlPWZ1bmN0aW9uKGUpe3JldHVybiEoMCxmLmRlZmF1bHQpKGUsdGhpcy5wcm9wcyl9LHQucHJvdG90eXBlLmNvbXBvbmVudFdpbGxNb3VudD1mdW5jdGlvbigpe2QucHVzaCh0aGlzKSxwKCl9LHQucHJvdG90eXBlLmNvbXBvbmVudERpZFVwZGF0ZT1mdW5jdGlvbigpe3AoKX0sdC5wcm90b3R5cGUuY29tcG9uZW50V2lsbFVubW91bnQ9ZnVuY3Rpb24oKXt2YXIgZT1kLmluZGV4T2YodGhpcyk7ZC5zcGxpY2UoZSwxKSxwKCl9LHQucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbigpe3JldHVybiB1LmRlZmF1bHQuY3JlYXRlRWxlbWVudChjLHRoaXMucHJvcHMpfSx0fShzLkNvbXBvbmVudCk7cmV0dXJuIG0uZGlzcGxheU5hbWU9IlNpZGVFZmZlY3QoIityKGMpKyIpIixtLmNhblVzZURPTT1sLmRlZmF1bHQuY2FuVXNlRE9NLG19fX0sZnVuY3Rpb24oZSx0KXtlLmV4cG9ydHM9ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9bj9uLmNhbGwocixlLHQpOnZvaWQgMDtpZih2b2lkIDAhPT1pKXJldHVybiEhaTtpZihlPT09dClyZXR1cm4hMDtpZigib2JqZWN0IiE9PXR5cGVvZiBlfHwhZXx8Im9iamVjdCIhPT10eXBlb2YgdHx8IXQpcmV0dXJuITE7dmFyIG89T2JqZWN0LmtleXMoZSksYT1PYmplY3Qua2V5cyh0KTtpZihvLmxlbmd0aCE9PWEubGVuZ3RoKXJldHVybiExO2Zvcih2YXIgcz1PYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmJpbmQodCksdT0wO3U8by5sZW5ndGg7dSsrKXt2YXIgYz1vW3VdO2lmKCFzKGMpKXJldHVybiExO3ZhciBsPWVbY10scD10W2NdO2lmKCExPT09KGk9bj9uLmNhbGwocixsLHAsYyk6dm9pZCAwKXx8dm9pZCAwPT09aSYmbCE9PXApcmV0dXJuITF9cmV0dXJuITB9fSxmdW5jdGlvbihlLHQsbil7ZnVuY3Rpb24gcihlKXtyZXR1cm4gbnVsbD09PWV8fHZvaWQgMD09PWV9ZnVuY3Rpb24gaShlKXtyZXR1cm4hKCFlfHwib2JqZWN0IiE9PXR5cGVvZiBlfHwibnVtYmVyIiE9PXR5cGVvZiBlLmxlbmd0aCkmJigiZnVuY3Rpb24iPT09dHlwZW9mIGUuY29weSYmImZ1bmN0aW9uIj09PXR5cGVvZiBlLnNsaWNlJiYhKGUubGVuZ3RoPjAmJiJudW1iZXIiIT09dHlwZW9mIGVbMF0pKX1mdW5jdGlvbiBvKGUsdCxuKXt2YXIgbyxsO2lmKHIoZSl8fHIodCkpcmV0dXJuITE7aWYoZS5wcm90b3R5cGUhPT10LnByb3RvdHlwZSlyZXR1cm4hMTtpZih1KGUpKXJldHVybiEhdSh0KSYmKGU9YS5jYWxsKGUpLHQ9YS5jYWxsKHQpLGMoZSx0LG4pKTtpZihpKGUpKXtpZighaSh0KSlyZXR1cm4hMTtpZihlLmxlbmd0aCE9PXQubGVuZ3RoKXJldHVybiExO2ZvcihvPTA7bzxlLmxlbmd0aDtvKyspaWYoZVtvXSE9PXRbb10pcmV0dXJuITE7cmV0dXJuITB9dHJ5e3ZhciBwPXMoZSksZj1zKHQpfWNhdGNoKGUpe3JldHVybiExfWlmKHAubGVuZ3RoIT1mLmxlbmd0aClyZXR1cm4hMTtmb3IocC5zb3J0KCksZi5zb3J0KCksbz1wLmxlbmd0aC0xO28+PTA7by0tKWlmKHBbb10hPWZbb10pcmV0dXJuITE7Zm9yKG89cC5sZW5ndGgtMTtvPj0wO28tLSlpZihsPXBbb10sIWMoZVtsXSx0W2xdLG4pKXJldHVybiExO3JldHVybiB0eXBlb2YgZT09PXR5cGVvZiB0fXZhciBhPUFycmF5LnByb3RvdHlwZS5zbGljZSxzPW4oNzE5KSx1PW4oNzIwKSxjPWUuZXhwb3J0cz1mdW5jdGlvbihlLHQsbil7cmV0dXJuIG58fChuPXt9KSxlPT09dHx8KGUgaW5zdGFuY2VvZiBEYXRlJiZ0IGluc3RhbmNlb2YgRGF0ZT9lLmdldFRpbWUoKT09PXQuZ2V0VGltZSgpOiFlfHwhdHx8Im9iamVjdCIhPXR5cGVvZiBlJiYib2JqZWN0IiE9dHlwZW9mIHQ/bi5zdHJpY3Q/ZT09PXQ6ZT09dDpvKGUsdCxuKSl9fSxmdW5jdGlvbihlLHQpe2Z1bmN0aW9uIG4oZSl7dmFyIHQ9W107Zm9yKHZhciBuIGluIGUpdC5wdXNoKG4pO3JldHVybiB0fXQ9ZS5leHBvcnRzPSJmdW5jdGlvbiI9PT10eXBlb2YgT2JqZWN0LmtleXM/T2JqZWN0LmtleXM6bix0LnNoaW09bn0sZnVuY3Rpb24oZSx0KXtmdW5jdGlvbiBuKGUpe3JldHVybiJbb2JqZWN0IEFyZ3VtZW50c10iPT1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZSl9ZnVuY3Rpb24gcihlKXtyZXR1cm4gZSYmIm9iamVjdCI9PXR5cGVvZiBlJiYibnVtYmVyIj09dHlwZW9mIGUubGVuZ3RoJiZPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSwiY2FsbGVlIikmJiFPYmplY3QucHJvdG90eXBlLnByb3BlcnR5SXNFbnVtZXJhYmxlLmNhbGwoZSwiY2FsbGVlIil8fCExfXZhciBpPSJbb2JqZWN0IEFyZ3VtZW50c10iPT1mdW5jdGlvbigpe3JldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoYXJndW1lbnRzKX0oKTt0PWUuZXhwb3J0cz1pP246cix0LnN1cHBvcnRlZD1uLHQudW5zdXBwb3J0ZWQ9cn0sZnVuY3Rpb24oZSx0LG4peyhmdW5jdGlvbihlKXtmdW5jdGlvbiByKGUpe3JldHVybiBlJiZlLl9fZXNNb2R1bGU/ZTp7ZGVmYXVsdDplfX10Ll9fZXNNb2R1bGU9ITAsdC53YXJuPXQucmVxdWVzdEFuaW1hdGlvbkZyYW1lPXQucmVkdWNlUHJvcHNUb1N0YXRlPXQubWFwU3RhdGVPblNlcnZlcj10LmhhbmRsZUNsaWVudFN0YXRlQ2hhbmdlPXQuY29udmVydFJlYWN0UHJvcHN0b0h0bWxBdHRyaWJ1dGVzPXZvaWQgMDt2YXIgaT0iZnVuY3Rpb24iPT09dHlwZW9mIFN5bWJvbCYmInN5bWJvbCI9PT10eXBlb2YgU3ltYm9sLml0ZXJhdG9yP2Z1bmN0aW9uKGUpe3JldHVybiB0eXBlb2YgZX06ZnVuY3Rpb24oZSl7cmV0dXJuIGUmJiJmdW5jdGlvbiI9PT10eXBlb2YgU3ltYm9sJiZlLmNvbnN0cnVjdG9yPT09U3ltYm9sJiZlIT09U3ltYm9sLnByb3RvdHlwZT8ic3ltYm9sIjp0eXBlb2YgZX0sbz1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfSxhPW4oMCkscz1yKGEpLHU9big1NCksYz1yKHUpLGw9bigzMDIpLHA9ZnVuY3Rpb24oZSl7cmV0dXJuITE9PT0oIShhcmd1bWVudHMubGVuZ3RoPjEmJnZvaWQgMCE9PWFyZ3VtZW50c1sxXSl8fGFyZ3VtZW50c1sxXSk/U3RyaW5nKGUpOlN0cmluZyhlKS5yZXBsYWNlKC8mL2csIiZhbXA7IikucmVwbGFjZSgvPC9nLCImbHQ7IikucmVwbGFjZSgvPi9nLCImZ3Q7IikucmVwbGFjZSgvIi9nLCImcXVvdDsiKS5yZXBsYWNlKC8nL2csIiYjeDI3OyIpfSxmPWZ1bmN0aW9uKGUpe3ZhciB0PXkoZSxsLlRBR19OQU1FUy5USVRMRSksbj15KGUsbC5IRUxNRVRfUFJPUFMuVElUTEVfVEVNUExBVEUpO2lmKG4mJnQpcmV0dXJuIG4ucmVwbGFjZSgvJXMvZyxmdW5jdGlvbigpe3JldHVybiB0fSk7dmFyIHI9eShlLGwuSEVMTUVUX1BST1BTLkRFRkFVTFRfVElUTEUpO3JldHVybiB0fHxyfHx2b2lkIDB9LGQ9ZnVuY3Rpb24oZSl7cmV0dXJuIHkoZSxsLkhFTE1FVF9QUk9QUy5PTl9DSEFOR0VfQ0xJRU5UX1NUQVRFKXx8ZnVuY3Rpb24oKXt9fSxoPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQuZmlsdGVyKGZ1bmN0aW9uKHQpe3JldHVybiJ1bmRlZmluZWQiIT09dHlwZW9mIHRbZV19KS5tYXAoZnVuY3Rpb24odCl7cmV0dXJuIHRbZV19KS5yZWR1Y2UoZnVuY3Rpb24oZSx0KXtyZXR1cm4gbyh7fSxlLHQpfSx7fSl9LG09ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdC5maWx0ZXIoZnVuY3Rpb24oZSl7cmV0dXJuInVuZGVmaW5lZCIhPT10eXBlb2YgZVtsLlRBR19OQU1FUy5CQVNFXX0pLm1hcChmdW5jdGlvbihlKXtyZXR1cm4gZVtsLlRBR19OQU1FUy5CQVNFXX0pLnJldmVyc2UoKS5yZWR1Y2UoZnVuY3Rpb24odCxuKXtpZighdC5sZW5ndGgpZm9yKHZhciByPU9iamVjdC5rZXlzKG4pLGk9MDtpPHIubGVuZ3RoO2krKyl7dmFyIG89cltpXSxhPW8udG9Mb3dlckNhc2UoKTtpZigtMSE9PWUuaW5kZXhPZihhKSYmblthXSlyZXR1cm4gdC5jb25jYXQobil9cmV0dXJuIHR9LFtdKX0sZz1mdW5jdGlvbihlLHQsbil7dmFyIHI9e307cmV0dXJuIG4uZmlsdGVyKGZ1bmN0aW9uKHQpe3JldHVybiEhQXJyYXkuaXNBcnJheSh0W2VdKXx8KCJ1bmRlZmluZWQiIT09dHlwZW9mIHRbZV0mJkQoIkhlbG1ldDogIitlKycgc2hvdWxkIGJlIG9mIHR5cGUgIkFycmF5Ii4gSW5zdGVhZCBmb3VuZCB0eXBlICInK2kodFtlXSkrJyInKSwhMSl9KS5tYXAoZnVuY3Rpb24odCl7cmV0dXJuIHRbZV19KS5yZXZlcnNlKCkucmVkdWNlKGZ1bmN0aW9uKGUsbil7dmFyIGk9e307bi5maWx0ZXIoZnVuY3Rpb24oZSl7Zm9yKHZhciBuPXZvaWQgMCxvPU9iamVjdC5rZXlzKGUpLGE9MDthPG8ubGVuZ3RoO2ErKyl7dmFyIHM9b1thXSx1PXMudG9Mb3dlckNhc2UoKTstMT09PXQuaW5kZXhPZih1KXx8bj09PWwuVEFHX1BST1BFUlRJRVMuUkVMJiYiY2Fub25pY2FsIj09PWVbbl0udG9Mb3dlckNhc2UoKXx8dT09PWwuVEFHX1BST1BFUlRJRVMuUkVMJiYic3R5bGVzaGVldCI9PT1lW3VdLnRvTG93ZXJDYXNlKCl8fChuPXUpLC0xPT09dC5pbmRleE9mKHMpfHxzIT09bC5UQUdfUFJPUEVSVElFUy5JTk5FUl9IVE1MJiZzIT09bC5UQUdfUFJPUEVSVElFUy5DU1NfVEVYVCYmcyE9PWwuVEFHX1BST1BFUlRJRVMuSVRFTV9QUk9QfHwobj1zKX1pZighbnx8IWVbbl0pcmV0dXJuITE7dmFyIGM9ZVtuXS50b0xvd2VyQ2FzZSgpO3JldHVybiByW25dfHwocltuXT17fSksaVtuXXx8KGlbbl09e30pLCFyW25dW2NdJiYoaVtuXVtjXT0hMCwhMCl9KS5yZXZlcnNlKCkuZm9yRWFjaChmdW5jdGlvbih0KXtyZXR1cm4gZS5wdXNoKHQpfSk7Zm9yKHZhciBvPU9iamVjdC5rZXlzKGkpLGE9MDthPG8ubGVuZ3RoO2ErKyl7dmFyIHM9b1thXSx1PSgwLGMuZGVmYXVsdCkoe30scltzXSxpW3NdKTtyW3NdPXV9cmV0dXJuIGV9LFtdKS5yZXZlcnNlKCl9LHk9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG49ZS5sZW5ndGgtMTtuPj0wO24tLSl7dmFyIHI9ZVtuXTtpZihyLmhhc093blByb3BlcnR5KHQpKXJldHVybiByW3RdfXJldHVybiBudWxsfSx2PWZ1bmN0aW9uKGUpe3JldHVybntiYXNlVGFnOm0oW2wuVEFHX1BST1BFUlRJRVMuSFJFRl0sZSksYm9keUF0dHJpYnV0ZXM6aChsLkFUVFJJQlVURV9OQU1FUy5CT0RZLGUpLGRlZmVyOnkoZSxsLkhFTE1FVF9QUk9QUy5ERUZFUiksZW5jb2RlOnkoZSxsLkhFTE1FVF9QUk9QUy5FTkNPREVfU1BFQ0lBTF9DSEFSQUNURVJTKSxodG1sQXR0cmlidXRlczpoKGwuQVRUUklCVVRFX05BTUVTLkhUTUwsZSksbGlua1RhZ3M6ZyhsLlRBR19OQU1FUy5MSU5LLFtsLlRBR19QUk9QRVJUSUVTLlJFTCxsLlRBR19QUk9QRVJUSUVTLkhSRUZdLGUpLG1ldGFUYWdzOmcobC5UQUdfTkFNRVMuTUVUQSxbbC5UQUdfUFJPUEVSVElFUy5OQU1FLGwuVEFHX1BST1BFUlRJRVMuQ0hBUlNFVCxsLlRBR19QUk9QRVJUSUVTLkhUVFBFUVVJVixsLlRBR19QUk9QRVJUSUVTLlBST1BFUlRZLGwuVEFHX1BST1BFUlRJRVMuSVRFTV9QUk9QXSxlKSxub3NjcmlwdFRhZ3M6ZyhsLlRBR19OQU1FUy5OT1NDUklQVCxbbC5UQUdfUFJPUEVSVElFUy5JTk5FUl9IVE1MXSxlKSxvbkNoYW5nZUNsaWVudFN0YXRlOmQoZSksc2NyaXB0VGFnczpnKGwuVEFHX05BTUVTLlNDUklQVCxbbC5UQUdfUFJPUEVSVElFUy5TUkMsbC5UQUdfUFJPUEVSVElFUy5JTk5FUl9IVE1MXSxlKSxzdHlsZVRhZ3M6ZyhsLlRBR19OQU1FUy5TVFlMRSxbbC5UQUdfUFJPUEVSVElFUy5DU1NfVEVYVF0sZSksdGl0bGU6ZihlKSx0aXRsZUF0dHJpYnV0ZXM6aChsLkFUVFJJQlVURV9OQU1FUy5USVRMRSxlKX19LGI9ZnVuY3Rpb24oKXt2YXIgZT1EYXRlLm5vdygpO3JldHVybiBmdW5jdGlvbih0KXt2YXIgbj1EYXRlLm5vdygpO24tZT4xNj8oZT1uLHQobikpOnNldFRpbWVvdXQoZnVuY3Rpb24oKXtiKHQpfSwwKX19KCkseD1mdW5jdGlvbihlKXtyZXR1cm4gY2xlYXJUaW1lb3V0KGUpfSxDPSJ1bmRlZmluZWQiIT09dHlwZW9mIHdpbmRvdz93aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lfHx3aW5kb3cud2Via2l0UmVxdWVzdEFuaW1hdGlvbkZyYW1lfHx3aW5kb3cubW96UmVxdWVzdEFuaW1hdGlvbkZyYW1lfHxiOmUucmVxdWVzdEFuaW1hdGlvbkZyYW1lfHxiLEU9InVuZGVmaW5lZCIhPT10eXBlb2Ygd2luZG93P3dpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZXx8d2luZG93LndlYmtpdENhbmNlbEFuaW1hdGlvbkZyYW1lfHx3aW5kb3cubW96Q2FuY2VsQW5pbWF0aW9uRnJhbWV8fHg6ZS5jYW5jZWxBbmltYXRpb25GcmFtZXx8eCxEPWZ1bmN0aW9uKGUpe3JldHVybiBjb25zb2xlJiYiZnVuY3Rpb24iPT09dHlwZW9mIGNvbnNvbGUud2FybiYmY29uc29sZS53YXJuKGUpfSx3PW51bGwsUz1mdW5jdGlvbihlKXt3JiZFKHcpLGUuZGVmZXI/dz1DKGZ1bmN0aW9uKCl7ayhlLGZ1bmN0aW9uKCl7dz1udWxsfSl9KTooayhlKSx3PW51bGwpfSxrPWZ1bmN0aW9uKGUsdCl7dmFyIG49ZS5iYXNlVGFnLHI9ZS5ib2R5QXR0cmlidXRlcyxpPWUuaHRtbEF0dHJpYnV0ZXMsbz1lLmxpbmtUYWdzLGE9ZS5tZXRhVGFncyxzPWUubm9zY3JpcHRUYWdzLHU9ZS5vbkNoYW5nZUNsaWVudFN0YXRlLGM9ZS5zY3JpcHRUYWdzLHA9ZS5zdHlsZVRhZ3MsZj1lLnRpdGxlLGQ9ZS50aXRsZUF0dHJpYnV0ZXM7VChsLlRBR19OQU1FUy5CT0RZLHIpLFQobC5UQUdfTkFNRVMuSFRNTCxpKSxfKGYsZCk7dmFyIGg9e2Jhc2VUYWc6TyhsLlRBR19OQU1FUy5CQVNFLG4pLGxpbmtUYWdzOk8obC5UQUdfTkFNRVMuTElOSyxvKSxtZXRhVGFnczpPKGwuVEFHX05BTUVTLk1FVEEsYSksbm9zY3JpcHRUYWdzOk8obC5UQUdfTkFNRVMuTk9TQ1JJUFQscyksc2NyaXB0VGFnczpPKGwuVEFHX05BTUVTLlNDUklQVCxjKSxzdHlsZVRhZ3M6TyhsLlRBR19OQU1FUy5TVFlMRSxwKX0sbT17fSxnPXt9O09iamVjdC5rZXlzKGgpLmZvckVhY2goZnVuY3Rpb24oZSl7dmFyIHQ9aFtlXSxuPXQubmV3VGFncyxyPXQub2xkVGFncztuLmxlbmd0aCYmKG1bZV09biksci5sZW5ndGgmJihnW2VdPWhbZV0ub2xkVGFncyl9KSx0JiZ0KCksdShlLG0sZyl9LEE9ZnVuY3Rpb24oZSl7cmV0dXJuIEFycmF5LmlzQXJyYXkoZSk/ZS5qb2luKCIiKTplfSxfPWZ1bmN0aW9uKGUsdCl7InVuZGVmaW5lZCIhPT10eXBlb2YgZSYmZG9jdW1lbnQudGl0bGUhPT1lJiYoZG9jdW1lbnQudGl0bGU9QShlKSksVChsLlRBR19OQU1FUy5USVRMRSx0KX0sVD1mdW5jdGlvbihlLHQpe3ZhciBuPWRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKGUpWzBdO2lmKG4pe2Zvcih2YXIgcj1uLmdldEF0dHJpYnV0ZShsLkhFTE1FVF9BVFRSSUJVVEUpLGk9cj9yLnNwbGl0KCIsIik6W10sbz1bXS5jb25jYXQoaSksYT1PYmplY3Qua2V5cyh0KSxzPTA7czxhLmxlbmd0aDtzKyspe3ZhciB1PWFbc10sYz10W3VdfHwiIjtuLmdldEF0dHJpYnV0ZSh1KSE9PWMmJm4uc2V0QXR0cmlidXRlKHUsYyksLTE9PT1pLmluZGV4T2YodSkmJmkucHVzaCh1KTt2YXIgcD1vLmluZGV4T2YodSk7LTEhPT1wJiZvLnNwbGljZShwLDEpfWZvcih2YXIgZj1vLmxlbmd0aC0xO2Y+PTA7Zi0tKW4ucmVtb3ZlQXR0cmlidXRlKG9bZl0pO2kubGVuZ3RoPT09by5sZW5ndGg/bi5yZW1vdmVBdHRyaWJ1dGUobC5IRUxNRVRfQVRUUklCVVRFKTpuLmdldEF0dHJpYnV0ZShsLkhFTE1FVF9BVFRSSUJVVEUpIT09YS5qb2luKCIsIikmJm4uc2V0QXR0cmlidXRlKGwuSEVMTUVUX0FUVFJJQlVURSxhLmpvaW4oIiwiKSl9fSxPPWZ1bmN0aW9uKGUsdCl7dmFyIG49ZG9jdW1lbnQuaGVhZHx8ZG9jdW1lbnQucXVlcnlTZWxlY3RvcihsLlRBR19OQU1FUy5IRUFEKSxyPW4ucXVlcnlTZWxlY3RvckFsbChlKyJbIitsLkhFTE1FVF9BVFRSSUJVVEUrIl0iKSxpPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHIpLG89W10sYT12b2lkIDA7cmV0dXJuIHQmJnQubGVuZ3RoJiZ0LmZvckVhY2goZnVuY3Rpb24odCl7dmFyIG49ZG9jdW1lbnQuY3JlYXRlRWxlbWVudChlKTtmb3IodmFyIHIgaW4gdClpZih0Lmhhc093blByb3BlcnR5KHIpKWlmKHI9PT1sLlRBR19QUk9QRVJUSUVTLklOTkVSX0hUTUwpbi5pbm5lckhUTUw9dC5pbm5lckhUTUw7ZWxzZSBpZihyPT09bC5UQUdfUFJPUEVSVElFUy5DU1NfVEVYVCluLnN0eWxlU2hlZXQ/bi5zdHlsZVNoZWV0LmNzc1RleHQ9dC5jc3NUZXh0Om4uYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUodC5jc3NUZXh0KSk7ZWxzZXt2YXIgcz0idW5kZWZpbmVkIj09PXR5cGVvZiB0W3JdPyIiOnRbcl07bi5zZXRBdHRyaWJ1dGUocixzKX1uLnNldEF0dHJpYnV0ZShsLkhFTE1FVF9BVFRSSUJVVEUsInRydWUiKSxpLnNvbWUoZnVuY3Rpb24oZSx0KXtyZXR1cm4gYT10LG4uaXNFcXVhbE5vZGUoZSl9KT9pLnNwbGljZShhLDEpOm8ucHVzaChuKX0pLGkuZm9yRWFjaChmdW5jdGlvbihlKXtyZXR1cm4gZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGUpfSksby5mb3JFYWNoKGZ1bmN0aW9uKGUpe3JldHVybiBuLmFwcGVuZENoaWxkKGUpfSkse29sZFRhZ3M6aSxuZXdUYWdzOm99fSxGPWZ1bmN0aW9uKGUpe3JldHVybiBPYmplY3Qua2V5cyhlKS5yZWR1Y2UoZnVuY3Rpb24odCxuKXt2YXIgcj0idW5kZWZpbmVkIiE9PXR5cGVvZiBlW25dP24rJz0iJytlW25dKyciJzoiIituO3JldHVybiB0P3QrIiAiK3I6cn0sIiIpfSxOPWZ1bmN0aW9uKGUsdCxuLHIpe3ZhciBpPUYobiksbz1BKHQpO3JldHVybiBpPyI8IitlKyIgIitsLkhFTE1FVF9BVFRSSUJVVEUrJz0idHJ1ZSIgJytpKyI+IitwKG8scikrIjwvIitlKyI+IjoiPCIrZSsiICIrbC5IRUxNRVRfQVRUUklCVVRFKyc9InRydWUiPicrcChvLHIpKyI8LyIrZSsiPiJ9LEk9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiB0LnJlZHVjZShmdW5jdGlvbih0LHIpe3ZhciBpPU9iamVjdC5rZXlzKHIpLmZpbHRlcihmdW5jdGlvbihlKXtyZXR1cm4hKGU9PT1sLlRBR19QUk9QRVJUSUVTLklOTkVSX0hUTUx8fGU9PT1sLlRBR19QUk9QRVJUSUVTLkNTU19URVhUKX0pLnJlZHVjZShmdW5jdGlvbihlLHQpe3ZhciBpPSJ1bmRlZmluZWQiPT09dHlwZW9mIHJbdF0/dDp0Kyc9IicrcChyW3RdLG4pKyciJztyZXR1cm4gZT9lKyIgIitpOml9LCIiKSxvPXIuaW5uZXJIVE1MfHxyLmNzc1RleHR8fCIiLGE9LTE9PT1sLlNFTEZfQ0xPU0lOR19UQUdTLmluZGV4T2YoZSk7cmV0dXJuIHQrIjwiK2UrIiAiK2wuSEVMTUVUX0FUVFJJQlVURSsnPSJ0cnVlIiAnK2krKGE/Ii8+IjoiPiIrbysiPC8iK2UrIj4iKX0sIiIpfSxMPWZ1bmN0aW9uKGUpe3ZhciB0PWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7fTtyZXR1cm4gT2JqZWN0LmtleXMoZSkucmVkdWNlKGZ1bmN0aW9uKHQsbil7cmV0dXJuIHRbbC5SRUFDVF9UQUdfTUFQW25dfHxuXT1lW25dLHR9LHQpfSxQPWZ1bmN0aW9uKGUpe3ZhciB0PWFyZ3VtZW50cy5sZW5ndGg+MSYmdm9pZCAwIT09YXJndW1lbnRzWzFdP2FyZ3VtZW50c1sxXTp7fTtyZXR1cm4gT2JqZWN0LmtleXMoZSkucmVkdWNlKGZ1bmN0aW9uKHQsbil7cmV0dXJuIHRbbC5IVE1MX1RBR19NQVBbbl18fG5dPWVbbl0sdH0sdCl9LE09ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGk9KHI9e2tleTp0fSxyW2wuSEVMTUVUX0FUVFJJQlVURV09ITAsciksbz1MKG4saSk7cmV0dXJuW3MuZGVmYXVsdC5jcmVhdGVFbGVtZW50KGwuVEFHX05BTUVTLlRJVExFLG8sdCldfSxqPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHQubWFwKGZ1bmN0aW9uKHQsbil7dmFyIHIsaT0ocj17a2V5Om59LHJbbC5IRUxNRVRfQVRUUklCVVRFXT0hMCxyKTtyZXR1cm4gT2JqZWN0LmtleXModCkuZm9yRWFjaChmdW5jdGlvbihlKXt2YXIgbj1sLlJFQUNUX1RBR19NQVBbZV18fGU7aWYobj09PWwuVEFHX1BST1BFUlRJRVMuSU5ORVJfSFRNTHx8bj09PWwuVEFHX1BST1BFUlRJRVMuQ1NTX1RFWFQpe3ZhciByPXQuaW5uZXJIVE1MfHx0LmNzc1RleHQ7aS5kYW5nZXJvdXNseVNldElubmVySFRNTD17X19odG1sOnJ9fWVsc2UgaVtuXT10W2VdfSkscy5kZWZhdWx0LmNyZWF0ZUVsZW1lbnQoZSxpKX0pfSxSPWZ1bmN0aW9uKGUsdCxuKXtzd2l0Y2goZSl7Y2FzZSBsLlRBR19OQU1FUy5USVRMRTpyZXR1cm57dG9Db21wb25lbnQ6ZnVuY3Rpb24oKXtyZXR1cm4gTSgwLHQudGl0bGUsdC50aXRsZUF0dHJpYnV0ZXMpfSx0b1N0cmluZzpmdW5jdGlvbigpe3JldHVybiBOKGUsdC50aXRsZSx0LnRpdGxlQXR0cmlidXRlcyxuKX19O2Nhc2UgbC5BVFRSSUJVVEVfTkFNRVMuQk9EWTpjYXNlIGwuQVRUUklCVVRFX05BTUVTLkhUTUw6cmV0dXJue3RvQ29tcG9uZW50OmZ1bmN0aW9uKCl7cmV0dXJuIEwodCl9LHRvU3RyaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIEYodCl9fTtkZWZhdWx0OnJldHVybnt0b0NvbXBvbmVudDpmdW5jdGlvbigpe3JldHVybiBqKGUsdCl9LHRvU3RyaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIEkoZSx0LG4pfX19fSxCPWZ1bmN0aW9uKGUpe3ZhciB0PWUuYmFzZVRhZyxuPWUuYm9keUF0dHJpYnV0ZXMscj1lLmVuY29kZSxpPWUuaHRtbEF0dHJpYnV0ZXMsbz1lLmxpbmtUYWdzLGE9ZS5tZXRhVGFncyxzPWUubm9zY3JpcHRUYWdzLHU9ZS5zY3JpcHRUYWdzLGM9ZS5zdHlsZVRhZ3MscD1lLnRpdGxlLGY9dm9pZCAwPT09cD8iIjpwLGQ9ZS50aXRsZUF0dHJpYnV0ZXM7cmV0dXJue2Jhc2U6UihsLlRBR19OQU1FUy5CQVNFLHQsciksYm9keUF0dHJpYnV0ZXM6UihsLkFUVFJJQlVURV9OQU1FUy5CT0RZLG4sciksaHRtbEF0dHJpYnV0ZXM6UihsLkFUVFJJQlVURV9OQU1FUy5IVE1MLGksciksbGluazpSKGwuVEFHX05BTUVTLkxJTkssbyxyKSxtZXRhOlIobC5UQUdfTkFNRVMuTUVUQSxhLHIpLG5vc2NyaXB0OlIobC5UQUdfTkFNRVMuTk9TQ1JJUFQscyxyKSxzY3JpcHQ6UihsLlRBR19OQU1FUy5TQ1JJUFQsdSxyKSxzdHlsZTpSKGwuVEFHX05BTUVTLlNUWUxFLGMsciksdGl0bGU6UihsLlRBR19OQU1FUy5USVRMRSx7dGl0bGU6Zix0aXRsZUF0dHJpYnV0ZXM6ZH0scil9fTt0LmNvbnZlcnRSZWFjdFByb3BzdG9IdG1sQXR0cmlidXRlcz1QLHQuaGFuZGxlQ2xpZW50U3RhdGVDaGFuZ2U9Uyx0Lm1hcFN0YXRlT25TZXJ2ZXI9Qix0LnJlZHVjZVByb3BzVG9TdGF0ZT12LHQucmVxdWVzdEFuaW1hdGlvbkZyYW1lPUMsdC53YXJuPUR9KS5jYWxsKHQsbigxMSkpfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oNzIzKTtlLmV4cG9ydHM9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiBmdW5jdGlvbigpe3Rocm93IG5ldyBFcnJvcigiRnVuY3Rpb24gIitlKyIgaXMgZGVwcmVjYXRlZCBhbmQgY2Fubm90IGJlIHVzZWQuIil9fXZhciBpPW4oNzI0KSxvPW4oNzQ3KTtlLmV4cG9ydHMuVHlwZT1uKDE1KSxlLmV4cG9ydHMuU2NoZW1hPW4oNTMpLGUuZXhwb3J0cy5GQUlMU0FGRV9TQ0hFTUE9bigxNDgpLGUuZXhwb3J0cy5KU09OX1NDSEVNQT1uKDMwNCksZS5leHBvcnRzLkNPUkVfU0NIRU1BPW4oMzAzKSxlLmV4cG9ydHMuREVGQVVMVF9TQUZFX1NDSEVNQT1uKDczKSxlLmV4cG9ydHMuREVGQVVMVF9GVUxMX1NDSEVNQT1uKDk4KSxlLmV4cG9ydHMubG9hZD1pLmxvYWQsZS5leHBvcnRzLmxvYWRBbGw9aS5sb2FkQWxsLGUuZXhwb3J0cy5zYWZlTG9hZD1pLnNhZmVMb2FkLGUuZXhwb3J0cy5zYWZlTG9hZEFsbD1pLnNhZmVMb2FkQWxsLGUuZXhwb3J0cy5kdW1wPW8uZHVtcCxlLmV4cG9ydHMuc2FmZUR1bXA9by5zYWZlRHVtcCxlLmV4cG9ydHMuWUFNTEV4Y2VwdGlvbj1uKDcyKSxlLmV4cG9ydHMuTUlOSU1BTF9TQ0hFTUE9bigxNDgpLGUuZXhwb3J0cy5TQUZFX1NDSEVNQT1uKDczKSxlLmV4cG9ydHMuREVGQVVMVF9TQ0hFTUE9big5OCksZS5leHBvcnRzLnNjYW49cigic2NhbiIpLGUuZXhwb3J0cy5wYXJzZT1yKCJwYXJzZSIpLGUuZXhwb3J0cy5jb21wb3NlPXIoImNvbXBvc2UiKSxlLmV4cG9ydHMuYWRkQ29uc3RydWN0b3I9cigiYWRkQ29uc3RydWN0b3IiKX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiAxMD09PWV8fDEzPT09ZX1mdW5jdGlvbiBpKGUpe3JldHVybiA5PT09ZXx8MzI9PT1lfWZ1bmN0aW9uIG8oZSl7cmV0dXJuIDk9PT1lfHwzMj09PWV8fDEwPT09ZXx8MTM9PT1lfWZ1bmN0aW9uIGEoZSl7cmV0dXJuIDQ0PT09ZXx8OTE9PT1lfHw5Mz09PWV8fDEyMz09PWV8fDEyNT09PWV9ZnVuY3Rpb24gcyhlKXt2YXIgdDtyZXR1cm4gNDg8PWUmJmU8PTU3P2UtNDg6KHQ9MzJ8ZSw5Nzw9dCYmdDw9MTAyP3QtOTcrMTA6LTEpfWZ1bmN0aW9uIHUoZSl7cmV0dXJuIDEyMD09PWU/MjoxMTc9PT1lPzQ6ODU9PT1lPzg6MH1mdW5jdGlvbiBjKGUpe3JldHVybiA0ODw9ZSYmZTw9NTc/ZS00ODotMX1mdW5jdGlvbiBsKGUpe3JldHVybiA0OD09PWU/IlwwIjo5Nz09PWU/Ilx4MDciOjk4PT09ZT8iXGIiOjExNj09PWU/Ilx0Ijo5PT09ZT8iXHQiOjExMD09PWU/IlxuIjoxMTg9PT1lPyJcdiI6MTAyPT09ZT8iXGYiOjExND09PWU/IlxyIjoxMDE9PT1lPyJceDFiIjozMj09PWU/IiAiOjM0PT09ZT8nIic6NDc9PT1lPyIvIjo5Mj09PWU/IlxcIjo3OD09PWU/Ilx4ODUiOjk1PT09ZT8iXHhhMCI6NzY9PT1lPyJcdTIwMjgiOjgwPT09ZT8iXHUyMDI5IjoiIn1mdW5jdGlvbiBwKGUpe3JldHVybiBlPD02NTUzNT9TdHJpbmcuZnJvbUNoYXJDb2RlKGUpOlN0cmluZy5mcm9tQ2hhckNvZGUoNTUyOTYrKGUtNjU1MzY+PjEwKSw1NjMyMCsoZS02NTUzNiYxMDIzKSl9ZnVuY3Rpb24gZihlLHQpe3RoaXMuaW5wdXQ9ZSx0aGlzLmZpbGVuYW1lPXQuZmlsZW5hbWV8fG51bGwsdGhpcy5zY2hlbWE9dC5zY2hlbWF8fFYsdGhpcy5vbldhcm5pbmc9dC5vbldhcm5pbmd8fG51bGwsdGhpcy5sZWdhY3k9dC5sZWdhY3l8fCExLHRoaXMuanNvbj10Lmpzb258fCExLHRoaXMubGlzdGVuZXI9dC5saXN0ZW5lcnx8bnVsbCx0aGlzLmltcGxpY2l0VHlwZXM9dGhpcy5zY2hlbWEuY29tcGlsZWRJbXBsaWNpdCx0aGlzLnR5cGVNYXA9dGhpcy5zY2hlbWEuY29tcGlsZWRUeXBlTWFwLHRoaXMubGVuZ3RoPWUubGVuZ3RoLHRoaXMucG9zaXRpb249MCx0aGlzLmxpbmU9MCx0aGlzLmxpbmVTdGFydD0wLHRoaXMubGluZUluZGVudD0wLHRoaXMuZG9jdW1lbnRzPVtdfWZ1bmN0aW9uIGQoZSx0KXtyZXR1cm4gbmV3IFUodCxuZXcgeihlLmZpbGVuYW1lLGUuaW5wdXQsZS5wb3NpdGlvbixlLmxpbmUsZS5wb3NpdGlvbi1lLmxpbmVTdGFydCkpfWZ1bmN0aW9uIGgoZSx0KXt0aHJvdyBkKGUsdCl9ZnVuY3Rpb24gbShlLHQpe2Uub25XYXJuaW5nJiZlLm9uV2FybmluZy5jYWxsKG51bGwsZChlLHQpKX1mdW5jdGlvbiBnKGUsdCxuLHIpe3ZhciBpLG8sYSxzO2lmKHQ8bil7aWYocz1lLmlucHV0LnNsaWNlKHQsbikscilmb3IoaT0wLG89cy5sZW5ndGg7aTxvO2krPTEpOT09PShhPXMuY2hhckNvZGVBdChpKSl8fDMyPD1hJiZhPD0xMTE0MTExfHxoKGUsImV4cGVjdGVkIHZhbGlkIEpTT04gY2hhcmFjdGVyIik7ZWxzZSBaLnRlc3QocykmJmgoZSwidGhlIHN0cmVhbSBjb250YWlucyBub24tcHJpbnRhYmxlIGNoYXJhY3RlcnMiKTtlLnJlc3VsdCs9c319ZnVuY3Rpb24geShlLHQsbixyKXt2YXIgaSxvLGEscztmb3IoJC5pc09iamVjdChuKXx8aChlLCJjYW5ub3QgbWVyZ2UgbWFwcGluZ3M7IHRoZSBwcm92aWRlZCBzb3VyY2Ugb2JqZWN0IGlzIHVuYWNjZXB0YWJsZSIpLGk9T2JqZWN0LmtleXMobiksYT0wLHM9aS5sZW5ndGg7YTxzO2ErPTEpbz1pW2FdLHEuY2FsbCh0LG8pfHwodFtvXT1uW29dLHJbb109ITApfWZ1bmN0aW9uIHYoZSx0LG4scixpLG8sYSxzKXt2YXIgdSxjO2lmKGk9U3RyaW5nKGkpLG51bGw9PT10JiYodD17fSksInRhZzp5YW1sLm9yZywyMDAyOm1lcmdlIj09PXIpaWYoQXJyYXkuaXNBcnJheShvKSlmb3IodT0wLGM9by5sZW5ndGg7dTxjO3UrPTEpeShlLHQsb1t1XSxuKTtlbHNlIHkoZSx0LG8sbik7ZWxzZSBlLmpzb258fHEuY2FsbChuLGkpfHwhcS5jYWxsKHQsaSl8fChlLmxpbmU9YXx8ZS5saW5lLGUucG9zaXRpb249c3x8ZS5wb3NpdGlvbixoKGUsImR1cGxpY2F0ZWQgbWFwcGluZyBrZXkiKSksdFtpXT1vLGRlbGV0ZSBuW2ldO3JldHVybiB0fWZ1bmN0aW9uIGIoZSl7dmFyIHQ7dD1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbiksMTA9PT10P2UucG9zaXRpb24rKzoxMz09PXQ/KGUucG9zaXRpb24rKywxMD09PWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKSYmZS5wb3NpdGlvbisrKTpoKGUsImEgbGluZSBicmVhayBpcyBleHBlY3RlZCIpLGUubGluZSs9MSxlLmxpbmVTdGFydD1lLnBvc2l0aW9ufWZ1bmN0aW9uIHgoZSx0LG4pe2Zvcih2YXIgbz0wLGE9ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24pOzAhPT1hOyl7Zm9yKDtpKGEpOylhPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pO2lmKHQmJjM1PT09YSlkb3thPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pfXdoaWxlKDEwIT09YSYmMTMhPT1hJiYwIT09YSk7aWYoIXIoYSkpYnJlYWs7Zm9yKGIoZSksYT1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbiksbysrLGUubGluZUluZGVudD0wOzMyPT09YTspZS5saW5lSW5kZW50KyssYT1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKX1yZXR1cm4tMSE9PW4mJjAhPT1vJiZlLmxpbmVJbmRlbnQ8biYmbShlLCJkZWZpY2llbnQgaW5kZW50YXRpb24iKSxvfWZ1bmN0aW9uIEMoZSl7dmFyIHQsbj1lLnBvc2l0aW9uO3JldHVybiEoNDUhPT0odD1lLmlucHV0LmNoYXJDb2RlQXQobikpJiY0NiE9PXR8fHQhPT1lLmlucHV0LmNoYXJDb2RlQXQobisxKXx8dCE9PWUuaW5wdXQuY2hhckNvZGVBdChuKzIpfHwobis9MywwIT09KHQ9ZS5pbnB1dC5jaGFyQ29kZUF0KG4pKSYmIW8odCkpKX1mdW5jdGlvbiBFKGUsdCl7MT09PXQ/ZS5yZXN1bHQrPSIgIjp0PjEmJihlLnJlc3VsdCs9JC5yZXBlYXQoIlxuIix0LTEpKX1mdW5jdGlvbiBEKGUsdCxuKXt2YXIgcyx1LGMsbCxwLGYsZCxoLG0seT1lLmtpbmQsdj1lLnJlc3VsdDtpZihtPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKSxvKG0pfHxhKG0pfHwzNT09PW18fDM4PT09bXx8NDI9PT1tfHwzMz09PW18fDEyND09PW18fDYyPT09bXx8Mzk9PT1tfHwzND09PW18fDM3PT09bXx8NjQ9PT1tfHw5Nj09PW0pcmV0dXJuITE7aWYoKDYzPT09bXx8NDU9PT1tKSYmKHU9ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24rMSksbyh1KXx8biYmYSh1KSkpcmV0dXJuITE7Zm9yKGUua2luZD0ic2NhbGFyIixlLnJlc3VsdD0iIixjPWw9ZS5wb3NpdGlvbixwPSExOzAhPT1tOyl7aWYoNTg9PT1tKXtpZih1PWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKzEpLG8odSl8fG4mJmEodSkpYnJlYWt9ZWxzZSBpZigzNT09PW0pe2lmKHM9ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24tMSksbyhzKSlicmVha31lbHNle2lmKGUucG9zaXRpb249PT1lLmxpbmVTdGFydCYmQyhlKXx8biYmYShtKSlicmVhaztpZihyKG0pKXtpZihmPWUubGluZSxkPWUubGluZVN0YXJ0LGg9ZS5saW5lSW5kZW50LHgoZSwhMSwtMSksZS5saW5lSW5kZW50Pj10KXtwPSEwLG09ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24pO2NvbnRpbnVlfWUucG9zaXRpb249bCxlLmxpbmU9ZixlLmxpbmVTdGFydD1kLGUubGluZUluZGVudD1oO2JyZWFrfX1wJiYoZyhlLGMsbCwhMSksRShlLGUubGluZS1mKSxjPWw9ZS5wb3NpdGlvbixwPSExKSxpKG0pfHwobD1lLnBvc2l0aW9uKzEpLG09ZS5pbnB1dC5jaGFyQ29kZUF0KCsrZS5wb3NpdGlvbil9cmV0dXJuIGcoZSxjLGwsITEpLCEhZS5yZXN1bHR8fChlLmtpbmQ9eSxlLnJlc3VsdD12LCExKX1mdW5jdGlvbiB3KGUsdCl7dmFyIG4saSxvO2lmKDM5IT09KG49ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24pKSlyZXR1cm4hMTtmb3IoZS5raW5kPSJzY2FsYXIiLGUucmVzdWx0PSIiLGUucG9zaXRpb24rKyxpPW89ZS5wb3NpdGlvbjswIT09KG49ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24pKTspaWYoMzk9PT1uKXtpZihnKGUsaSxlLnBvc2l0aW9uLCEwKSwzOSE9PShuPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pKSlyZXR1cm4hMDtpPWUucG9zaXRpb24sZS5wb3NpdGlvbisrLG89ZS5wb3NpdGlvbn1lbHNlIHIobik/KGcoZSxpLG8sITApLEUoZSx4KGUsITEsdCkpLGk9bz1lLnBvc2l0aW9uKTplLnBvc2l0aW9uPT09ZS5saW5lU3RhcnQmJkMoZSk/aChlLCJ1bmV4cGVjdGVkIGVuZCBvZiB0aGUgZG9jdW1lbnQgd2l0aGluIGEgc2luZ2xlIHF1b3RlZCBzY2FsYXIiKTooZS5wb3NpdGlvbisrLG89ZS5wb3NpdGlvbik7aChlLCJ1bmV4cGVjdGVkIGVuZCBvZiB0aGUgc3RyZWFtIHdpdGhpbiBhIHNpbmdsZSBxdW90ZWQgc2NhbGFyIil9ZnVuY3Rpb24gUyhlLHQpe3ZhciBuLGksbyxhLGMsbDtpZigzNCE9PShsPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKSkpcmV0dXJuITE7Zm9yKGUua2luZD0ic2NhbGFyIixlLnJlc3VsdD0iIixlLnBvc2l0aW9uKyssbj1pPWUucG9zaXRpb247MCE9PShsPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKSk7KXtpZigzND09PWwpcmV0dXJuIGcoZSxuLGUucG9zaXRpb24sITApLGUucG9zaXRpb24rKywhMDtpZig5Mj09PWwpe2lmKGcoZSxuLGUucG9zaXRpb24sITApLGw9ZS5pbnB1dC5jaGFyQ29kZUF0KCsrZS5wb3NpdGlvbikscihsKSl4KGUsITEsdCk7ZWxzZSBpZihsPDI1NiYmaWVbbF0pZS5yZXN1bHQrPW9lW2xdLGUucG9zaXRpb24rKztlbHNlIGlmKChjPXUobCkpPjApe2ZvcihvPWMsYT0wO28+MDtvLS0pbD1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKSwoYz1zKGwpKT49MD9hPShhPDw0KStjOmgoZSwiZXhwZWN0ZWQgaGV4YWRlY2ltYWwgY2hhcmFjdGVyIik7ZS5yZXN1bHQrPXAoYSksZS5wb3NpdGlvbisrfWVsc2UgaChlLCJ1bmtub3duIGVzY2FwZSBzZXF1ZW5jZSIpO249aT1lLnBvc2l0aW9ufWVsc2UgcihsKT8oZyhlLG4saSwhMCksRShlLHgoZSwhMSx0KSksbj1pPWUucG9zaXRpb24pOmUucG9zaXRpb249PT1lLmxpbmVTdGFydCYmQyhlKT9oKGUsInVuZXhwZWN0ZWQgZW5kIG9mIHRoZSBkb2N1bWVudCB3aXRoaW4gYSBkb3VibGUgcXVvdGVkIHNjYWxhciIpOihlLnBvc2l0aW9uKyssaT1lLnBvc2l0aW9uKX1oKGUsInVuZXhwZWN0ZWQgZW5kIG9mIHRoZSBzdHJlYW0gd2l0aGluIGEgZG91YmxlIHF1b3RlZCBzY2FsYXIiKX1mdW5jdGlvbiBrKGUsdCl7dmFyIG4scixpLGEscyx1LGMsbCxwLGYsZCxtPSEwLGc9ZS50YWcseT1lLmFuY2hvcixiPXt9O2lmKDkxPT09KGQ9ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24pKSlhPTkzLGM9ITEscj1bXTtlbHNle2lmKDEyMyE9PWQpcmV0dXJuITE7YT0xMjUsYz0hMCxyPXt9fWZvcihudWxsIT09ZS5hbmNob3ImJihlLmFuY2hvck1hcFtlLmFuY2hvcl09ciksZD1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKTswIT09ZDspe2lmKHgoZSwhMCx0KSwoZD1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbikpPT09YSlyZXR1cm4gZS5wb3NpdGlvbisrLGUudGFnPWcsZS5hbmNob3I9eSxlLmtpbmQ9Yz8ibWFwcGluZyI6InNlcXVlbmNlIixlLnJlc3VsdD1yLCEwO218fGgoZSwibWlzc2VkIGNvbW1hIGJldHdlZW4gZmxvdyBjb2xsZWN0aW9uIGVudHJpZXMiKSxwPWw9Zj1udWxsLHM9dT0hMSw2Mz09PWQmJihpPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKzEpLG8oaSkmJihzPXU9ITAsZS5wb3NpdGlvbisrLHgoZSwhMCx0KSkpLG49ZS5saW5lLEkoZSx0LEgsITEsITApLHA9ZS50YWcsbD1lLnJlc3VsdCx4KGUsITAsdCksZD1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbiksIXUmJmUubGluZSE9PW58fDU4IT09ZHx8KHM9ITAsZD1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKSx4KGUsITAsdCksSShlLHQsSCwhMSwhMCksZj1lLnJlc3VsdCksYz92KGUscixiLHAsbCxmKTpzP3IucHVzaCh2KGUsbnVsbCxiLHAsbCxmKSk6ci5wdXNoKGwpLHgoZSwhMCx0KSxkPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKSw0ND09PWQ/KG09ITAsZD1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKSk6bT0hMX1oKGUsInVuZXhwZWN0ZWQgZW5kIG9mIHRoZSBzdHJlYW0gd2l0aGluIGEgZmxvdyBjb2xsZWN0aW9uIil9ZnVuY3Rpb24gQShlLHQpe3ZhciBuLG8sYSxzLHU9SixsPSExLHA9ITEsZj10LGQ9MCxtPSExO2lmKDEyND09PShzPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKSkpbz0hMTtlbHNle2lmKDYyIT09cylyZXR1cm4hMTtvPSEwfWZvcihlLmtpbmQ9InNjYWxhciIsZS5yZXN1bHQ9IiI7MCE9PXM7KWlmKDQzPT09KHM9ZS5pbnB1dC5jaGFyQ29kZUF0KCsrZS5wb3NpdGlvbikpfHw0NT09PXMpSj09PXU/dT00Mz09PXM/WDpZOmgoZSwicmVwZWF0IG9mIGEgY2hvbXBpbmcgbW9kZSBpZGVudGlmaWVyIik7ZWxzZXtpZighKChhPWMocykpPj0wKSlicmVhazswPT09YT9oKGUsImJhZCBleHBsaWNpdCBpbmRlbnRhdGlvbiB3aWR0aCBvZiBhIGJsb2NrIHNjYWxhcjsgaXQgY2Fubm90IGJlIGxlc3MgdGhhbiBvbmUiKTpwP2goZSwicmVwZWF0IG9mIGFuIGluZGVudGF0aW9uIHdpZHRoIGlkZW50aWZpZXIiKTooZj10K2EtMSxwPSEwKX1pZihpKHMpKXtkb3tzPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pfXdoaWxlKGkocykpO2lmKDM1PT09cylkb3tzPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pfXdoaWxlKCFyKHMpJiYwIT09cyl9Zm9yKDswIT09czspe2ZvcihiKGUpLGUubGluZUluZGVudD0wLHM9ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24pOyghcHx8ZS5saW5lSW5kZW50PGYpJiYzMj09PXM7KWUubGluZUluZGVudCsrLHM9ZS5pbnB1dC5jaGFyQ29kZUF0KCsrZS5wb3NpdGlvbik7aWYoIXAmJmUubGluZUluZGVudD5mJiYoZj1lLmxpbmVJbmRlbnQpLHIocykpZCsrO2Vsc2V7aWYoZS5saW5lSW5kZW50PGYpe3U9PT1YP2UucmVzdWx0Kz0kLnJlcGVhdCgiXG4iLGw/MStkOmQpOnU9PT1KJiZsJiYoZS5yZXN1bHQrPSJcbiIpO2JyZWFrfWZvcihvP2kocyk/KG09ITAsZS5yZXN1bHQrPSQucmVwZWF0KCJcbiIsbD8xK2Q6ZCkpOm0/KG09ITEsZS5yZXN1bHQrPSQucmVwZWF0KCJcbiIsZCsxKSk6MD09PWQ/bCYmKGUucmVzdWx0Kz0iICIpOmUucmVzdWx0Kz0kLnJlcGVhdCgiXG4iLGQpOmUucmVzdWx0Kz0kLnJlcGVhdCgiXG4iLGw/MStkOmQpLGw9ITAscD0hMCxkPTAsbj1lLnBvc2l0aW9uOyFyKHMpJiYwIT09czspcz1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKTtnKGUsbixlLnBvc2l0aW9uLCExKX19cmV0dXJuITB9ZnVuY3Rpb24gXyhlLHQpe3ZhciBuLHIsaSxhPWUudGFnLHM9ZS5hbmNob3IsdT1bXSxjPSExO2ZvcihudWxsIT09ZS5hbmNob3ImJihlLmFuY2hvck1hcFtlLmFuY2hvcl09dSksaT1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbik7MCE9PWkmJjQ1PT09aSYmKHI9ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24rMSksbyhyKSk7KWlmKGM9ITAsZS5wb3NpdGlvbisrLHgoZSwhMCwtMSkmJmUubGluZUluZGVudDw9dCl1LnB1c2gobnVsbCksaT1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbik7ZWxzZSBpZihuPWUubGluZSxJKGUsdCxRLCExLCEwKSx1LnB1c2goZS5yZXN1bHQpLHgoZSwhMCwtMSksaT1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbiksKGUubGluZT09PW58fGUubGluZUluZGVudD50KSYmMCE9PWkpaChlLCJiYWQgaW5kZW50YXRpb24gb2YgYSBzZXF1ZW5jZSBlbnRyeSIpO2Vsc2UgaWYoZS5saW5lSW5kZW50PHQpYnJlYWs7cmV0dXJuISFjJiYoZS50YWc9YSxlLmFuY2hvcj1zLGUua2luZD0ic2VxdWVuY2UiLGUucmVzdWx0PXUsITApfWZ1bmN0aW9uIFQoZSx0LG4pe3ZhciByLGEscyx1LGMsbD1lLnRhZyxwPWUuYW5jaG9yLGY9e30sZD17fSxtPW51bGwsZz1udWxsLHk9bnVsbCxiPSExLEM9ITE7Zm9yKG51bGwhPT1lLmFuY2hvciYmKGUuYW5jaG9yTWFwW2UuYW5jaG9yXT1mKSxjPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKTswIT09Yzspe2lmKHI9ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24rMSkscz1lLmxpbmUsdT1lLnBvc2l0aW9uLDYzIT09YyYmNTghPT1jfHwhbyhyKSl7aWYoIUkoZSxuLFcsITEsITApKWJyZWFrO2lmKGUubGluZT09PXMpe2ZvcihjPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKTtpKGMpOyljPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pO2lmKDU4PT09YyljPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pLG8oYyl8fGgoZSwiYSB3aGl0ZXNwYWNlIGNoYXJhY3RlciBpcyBleHBlY3RlZCBhZnRlciB0aGUga2V5LXZhbHVlIHNlcGFyYXRvciB3aXRoaW4gYSBibG9jayBtYXBwaW5nIiksYiYmKHYoZSxmLGQsbSxnLG51bGwpLG09Zz15PW51bGwpLEM9ITAsYj0hMSxhPSExLG09ZS50YWcsZz1lLnJlc3VsdDtlbHNle2lmKCFDKXJldHVybiBlLnRhZz1sLGUuYW5jaG9yPXAsITA7aChlLCJjYW4gbm90IHJlYWQgYW4gaW1wbGljaXQgbWFwcGluZyBwYWlyOyBhIGNvbG9uIGlzIG1pc3NlZCIpfX1lbHNle2lmKCFDKXJldHVybiBlLnRhZz1sLGUuYW5jaG9yPXAsITA7aChlLCJjYW4gbm90IHJlYWQgYSBibG9jayBtYXBwaW5nIGVudHJ5OyBhIG11bHRpbGluZSBrZXkgbWF5IG5vdCBiZSBhbiBpbXBsaWNpdCBrZXkiKX19ZWxzZSA2Mz09PWM/KGImJih2KGUsZixkLG0sZyxudWxsKSxtPWc9eT1udWxsKSxDPSEwLGI9ITAsYT0hMCk6Yj8oYj0hMSxhPSEwKTpoKGUsImluY29tcGxldGUgZXhwbGljaXQgbWFwcGluZyBwYWlyOyBhIGtleSBub2RlIGlzIG1pc3NlZDsgb3IgZm9sbG93ZWQgYnkgYSBub24tdGFidWxhdGVkIGVtcHR5IGxpbmUiKSxlLnBvc2l0aW9uKz0xLGM9cjtpZigoZS5saW5lPT09c3x8ZS5saW5lSW5kZW50PnQpJiYoSShlLHQsSywhMCxhKSYmKGI/Zz1lLnJlc3VsdDp5PWUucmVzdWx0KSxifHwodihlLGYsZCxtLGcseSxzLHUpLG09Zz15PW51bGwpLHgoZSwhMCwtMSksYz1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbikpLGUubGluZUluZGVudD50JiYwIT09YyloKGUsImJhZCBpbmRlbnRhdGlvbiBvZiBhIG1hcHBpbmcgZW50cnkiKTtlbHNlIGlmKGUubGluZUluZGVudDx0KWJyZWFrfXJldHVybiBiJiZ2KGUsZixkLG0sZyxudWxsKSxDJiYoZS50YWc9bCxlLmFuY2hvcj1wLGUua2luZD0ibWFwcGluZyIsZS5yZXN1bHQ9ZiksQ31mdW5jdGlvbiBPKGUpe3ZhciB0LG4scixpLGE9ITEscz0hMTtpZigzMyE9PShpPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKSkpcmV0dXJuITE7aWYobnVsbCE9PWUudGFnJiZoKGUsImR1cGxpY2F0aW9uIG9mIGEgdGFnIHByb3BlcnR5IiksaT1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKSw2MD09PWk/KGE9ITAsaT1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKSk6MzM9PT1pPyhzPSEwLG49IiEhIixpPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pKTpuPSIhIix0PWUucG9zaXRpb24sYSl7ZG97aT1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKX13aGlsZSgwIT09aSYmNjIhPT1pKTtlLnBvc2l0aW9uPGUubGVuZ3RoPyhyPWUuaW5wdXQuc2xpY2UodCxlLnBvc2l0aW9uKSxpPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pKTpoKGUsInVuZXhwZWN0ZWQgZW5kIG9mIHRoZSBzdHJlYW0gd2l0aGluIGEgdmVyYmF0aW0gdGFnIil9ZWxzZXtmb3IoOzAhPT1pJiYhbyhpKTspMzM9PT1pJiYocz9oKGUsInRhZyBzdWZmaXggY2Fubm90IGNvbnRhaW4gZXhjbGFtYXRpb24gbWFya3MiKToobj1lLmlucHV0LnNsaWNlKHQtMSxlLnBvc2l0aW9uKzEpLG5lLnRlc3Qobil8fGgoZSwibmFtZWQgdGFnIGhhbmRsZSBjYW5ub3QgY29udGFpbiBzdWNoIGNoYXJhY3RlcnMiKSxzPSEwLHQ9ZS5wb3NpdGlvbisxKSksaT1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKTtyPWUuaW5wdXQuc2xpY2UodCxlLnBvc2l0aW9uKSx0ZS50ZXN0KHIpJiZoKGUsInRhZyBzdWZmaXggY2Fubm90IGNvbnRhaW4gZmxvdyBpbmRpY2F0b3IgY2hhcmFjdGVycyIpfXJldHVybiByJiYhcmUudGVzdChyKSYmaChlLCJ0YWcgbmFtZSBjYW5ub3QgY29udGFpbiBzdWNoIGNoYXJhY3RlcnM6ICIrciksYT9lLnRhZz1yOnEuY2FsbChlLnRhZ01hcCxuKT9lLnRhZz1lLnRhZ01hcFtuXStyOiIhIj09PW4/ZS50YWc9IiEiK3I6IiEhIj09PW4/ZS50YWc9InRhZzp5YW1sLm9yZywyMDAyOiIrcjpoKGUsJ3VuZGVjbGFyZWQgdGFnIGhhbmRsZSAiJytuKyciJyksITB9ZnVuY3Rpb24gRihlKXt2YXIgdCxuO2lmKDM4IT09KG49ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24pKSlyZXR1cm4hMTtmb3IobnVsbCE9PWUuYW5jaG9yJiZoKGUsImR1cGxpY2F0aW9uIG9mIGFuIGFuY2hvciBwcm9wZXJ0eSIpLG49ZS5pbnB1dC5jaGFyQ29kZUF0KCsrZS5wb3NpdGlvbiksdD1lLnBvc2l0aW9uOzAhPT1uJiYhbyhuKSYmIWEobik7KW49ZS5pbnB1dC5jaGFyQ29kZUF0KCsrZS5wb3NpdGlvbik7cmV0dXJuIGUucG9zaXRpb249PT10JiZoKGUsIm5hbWUgb2YgYW4gYW5jaG9yIG5vZGUgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIiKSxlLmFuY2hvcj1lLmlucHV0LnNsaWNlKHQsZS5wb3NpdGlvbiksITB9ZnVuY3Rpb24gTihlKXt2YXIgdCxuLHI7aWYoNDIhPT0ocj1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbikpKXJldHVybiExO2ZvcihyPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pLHQ9ZS5wb3NpdGlvbjswIT09ciYmIW8ocikmJiFhKHIpOylyPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pO3JldHVybiBlLnBvc2l0aW9uPT09dCYmaChlLCJuYW1lIG9mIGFuIGFsaWFzIG5vZGUgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIiKSxuPWUuaW5wdXQuc2xpY2UodCxlLnBvc2l0aW9uKSxlLmFuY2hvck1hcC5oYXNPd25Qcm9wZXJ0eShuKXx8aChlLCd1bmlkZW50aWZpZWQgYWxpYXMgIicrbisnIicpLGUucmVzdWx0PWUuYW5jaG9yTWFwW25dLHgoZSwhMCwtMSksITB9ZnVuY3Rpb24gSShlLHQsbixyLGkpe3ZhciBvLGEscyx1LGMsbCxwLGYsZD0xLG09ITEsZz0hMTtpZihudWxsIT09ZS5saXN0ZW5lciYmZS5saXN0ZW5lcigib3BlbiIsZSksZS50YWc9bnVsbCxlLmFuY2hvcj1udWxsLGUua2luZD1udWxsLGUucmVzdWx0PW51bGwsbz1hPXM9Sz09PW58fFE9PT1uLHImJngoZSwhMCwtMSkmJihtPSEwLGUubGluZUluZGVudD50P2Q9MTplLmxpbmVJbmRlbnQ9PT10P2Q9MDplLmxpbmVJbmRlbnQ8dCYmKGQ9LTEpKSwxPT09ZClmb3IoO08oZSl8fEYoZSk7KXgoZSwhMCwtMSk/KG09ITAscz1vLGUubGluZUluZGVudD50P2Q9MTplLmxpbmVJbmRlbnQ9PT10P2Q9MDplLmxpbmVJbmRlbnQ8dCYmKGQ9LTEpKTpzPSExO2lmKHMmJihzPW18fGkpLDEhPT1kJiZLIT09bnx8KHA9SD09PW58fFc9PT1uP3Q6dCsxLGY9ZS5wb3NpdGlvbi1lLmxpbmVTdGFydCwxPT09ZD9zJiYoXyhlLGYpfHxUKGUsZixwKSl8fGsoZSxwKT9nPSEwOihhJiZBKGUscCl8fHcoZSxwKXx8UyhlLHApP2c9ITA6TihlKT8oZz0hMCxudWxsPT09ZS50YWcmJm51bGw9PT1lLmFuY2hvcnx8aChlLCJhbGlhcyBub2RlIHNob3VsZCBub3QgaGF2ZSBhbnkgcHJvcGVydGllcyIpKTpEKGUscCxIPT09bikmJihnPSEwLG51bGw9PT1lLnRhZyYmKGUudGFnPSI/IikpLG51bGwhPT1lLmFuY2hvciYmKGUuYW5jaG9yTWFwW2UuYW5jaG9yXT1lLnJlc3VsdCkpOjA9PT1kJiYoZz1zJiZfKGUsZikpKSxudWxsIT09ZS50YWcmJiIhIiE9PWUudGFnKWlmKCI/Ij09PWUudGFnKXtmb3IodT0wLGM9ZS5pbXBsaWNpdFR5cGVzLmxlbmd0aDt1PGM7dSs9MSlpZihsPWUuaW1wbGljaXRUeXBlc1t1XSxsLnJlc29sdmUoZS5yZXN1bHQpKXtlLnJlc3VsdD1sLmNvbnN0cnVjdChlLnJlc3VsdCksZS50YWc9bC50YWcsbnVsbCE9PWUuYW5jaG9yJiYoZS5hbmNob3JNYXBbZS5hbmNob3JdPWUucmVzdWx0KTticmVha319ZWxzZSBxLmNhbGwoZS50eXBlTWFwW2Uua2luZHx8ImZhbGxiYWNrIl0sZS50YWcpPyhsPWUudHlwZU1hcFtlLmtpbmR8fCJmYWxsYmFjayJdW2UudGFnXSxudWxsIT09ZS5yZXN1bHQmJmwua2luZCE9PWUua2luZCYmaChlLCJ1bmFjY2VwdGFibGUgbm9kZSBraW5kIGZvciAhPCIrZS50YWcrJz4gdGFnOyBpdCBzaG91bGQgYmUgIicrbC5raW5kKyciLCBub3QgIicrZS5raW5kKyciJyksbC5yZXNvbHZlKGUucmVzdWx0KT8oZS5yZXN1bHQ9bC5jb25zdHJ1Y3QoZS5yZXN1bHQpLG51bGwhPT1lLmFuY2hvciYmKGUuYW5jaG9yTWFwW2UuYW5jaG9yXT1lLnJlc3VsdCkpOmgoZSwiY2Fubm90IHJlc29sdmUgYSBub2RlIHdpdGggITwiK2UudGFnKyI+IGV4cGxpY2l0IHRhZyIpKTpoKGUsInVua25vd24gdGFnICE8IitlLnRhZysiPiIpO3JldHVybiBudWxsIT09ZS5saXN0ZW5lciYmZS5saXN0ZW5lcigiY2xvc2UiLGUpLG51bGwhPT1lLnRhZ3x8bnVsbCE9PWUuYW5jaG9yfHxnfWZ1bmN0aW9uIEwoZSl7dmFyIHQsbixhLHMsdT1lLnBvc2l0aW9uLGM9ITE7Zm9yKGUudmVyc2lvbj1udWxsLGUuY2hlY2tMaW5lQnJlYWtzPWUubGVnYWN5LGUudGFnTWFwPXt9LGUuYW5jaG9yTWFwPXt9OzAhPT0ocz1lLmlucHV0LmNoYXJDb2RlQXQoZS5wb3NpdGlvbikpJiYoeChlLCEwLC0xKSxzPWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKSwhKGUubGluZUluZGVudD4wfHwzNyE9PXMpKTspe2ZvcihjPSEwLHM9ZS5pbnB1dC5jaGFyQ29kZUF0KCsrZS5wb3NpdGlvbiksdD1lLnBvc2l0aW9uOzAhPT1zJiYhbyhzKTspcz1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKTtmb3Iobj1lLmlucHV0LnNsaWNlKHQsZS5wb3NpdGlvbiksYT1bXSxuLmxlbmd0aDwxJiZoKGUsImRpcmVjdGl2ZSBuYW1lIG11c3Qgbm90IGJlIGxlc3MgdGhhbiBvbmUgY2hhcmFjdGVyIGluIGxlbmd0aCIpOzAhPT1zOyl7Zm9yKDtpKHMpOylzPWUuaW5wdXQuY2hhckNvZGVBdCgrK2UucG9zaXRpb24pO2lmKDM1PT09cyl7ZG97cz1lLmlucHV0LmNoYXJDb2RlQXQoKytlLnBvc2l0aW9uKX13aGlsZSgwIT09cyYmIXIocykpO2JyZWFrfWlmKHIocykpYnJlYWs7Zm9yKHQ9ZS5wb3NpdGlvbjswIT09cyYmIW8ocyk7KXM9ZS5pbnB1dC5jaGFyQ29kZUF0KCsrZS5wb3NpdGlvbik7YS5wdXNoKGUuaW5wdXQuc2xpY2UodCxlLnBvc2l0aW9uKSl9MCE9PXMmJmIoZSkscS5jYWxsKHNlLG4pP3NlW25dKGUsbixhKTptKGUsJ3Vua25vd24gZG9jdW1lbnQgZGlyZWN0aXZlICInK24rJyInKX1pZih4KGUsITAsLTEpLDA9PT1lLmxpbmVJbmRlbnQmJjQ1PT09ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24pJiY0NT09PWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKzEpJiY0NT09PWUuaW5wdXQuY2hhckNvZGVBdChlLnBvc2l0aW9uKzIpPyhlLnBvc2l0aW9uKz0zLHgoZSwhMCwtMSkpOmMmJmgoZSwiZGlyZWN0aXZlcyBlbmQgbWFyayBpcyBleHBlY3RlZCIpLEkoZSxlLmxpbmVJbmRlbnQtMSxLLCExLCEwKSx4KGUsITAsLTEpLGUuY2hlY2tMaW5lQnJlYWtzJiZlZS50ZXN0KGUuaW5wdXQuc2xpY2UodSxlLnBvc2l0aW9uKSkmJm0oZSwibm9uLUFTQ0lJIGxpbmUgYnJlYWtzIGFyZSBpbnRlcnByZXRlZCBhcyBjb250ZW50IiksZS5kb2N1bWVudHMucHVzaChlLnJlc3VsdCksZS5wb3NpdGlvbj09PWUubGluZVN0YXJ0JiZDKGUpKXJldHVybiB2b2lkKDQ2PT09ZS5pbnB1dC5jaGFyQ29kZUF0KGUucG9zaXRpb24pJiYoZS5wb3NpdGlvbis9Myx4KGUsITAsLTEpKSk7ZS5wb3NpdGlvbjxlLmxlbmd0aC0xJiZoKGUsImVuZCBvZiB0aGUgc3RyZWFtIG9yIGEgZG9jdW1lbnQgc2VwYXJhdG9yIGlzIGV4cGVjdGVkIil9ZnVuY3Rpb24gUChlLHQpe2U9U3RyaW5nKGUpLHQ9dHx8e30sMCE9PWUubGVuZ3RoJiYoMTAhPT1lLmNoYXJDb2RlQXQoZS5sZW5ndGgtMSkmJjEzIT09ZS5jaGFyQ29kZUF0KGUubGVuZ3RoLTEpJiYoZSs9IlxuIiksNjUyNzk9PT1lLmNoYXJDb2RlQXQoMCkmJihlPWUuc2xpY2UoMSkpKTt2YXIgbj1uZXcgZihlLHQpO2ZvcihuLmlucHV0Kz0iXDAiOzMyPT09bi5pbnB1dC5jaGFyQ29kZUF0KG4ucG9zaXRpb24pOyluLmxpbmVJbmRlbnQrPTEsbi5wb3NpdGlvbis9MTtmb3IoO24ucG9zaXRpb248bi5sZW5ndGgtMTspTChuKTtyZXR1cm4gbi5kb2N1bWVudHN9ZnVuY3Rpb24gTShlLHQsbil7dmFyIHIsaSxvPVAoZSxuKTtpZigiZnVuY3Rpb24iIT09dHlwZW9mIHQpcmV0dXJuIG87Zm9yKHI9MCxpPW8ubGVuZ3RoO3I8aTtyKz0xKXQob1tyXSl9ZnVuY3Rpb24gaihlLHQpe3ZhciBuPVAoZSx0KTtpZigwIT09bi5sZW5ndGgpe2lmKDE9PT1uLmxlbmd0aClyZXR1cm4gblswXTt0aHJvdyBuZXcgVSgiZXhwZWN0ZWQgYSBzaW5nbGUgZG9jdW1lbnQgaW4gdGhlIHN0cmVhbSwgYnV0IGZvdW5kIG1vcmUiKX19ZnVuY3Rpb24gUihlLHQsbil7aWYoImZ1bmN0aW9uIiE9PXR5cGVvZiB0KXJldHVybiBNKGUsJC5leHRlbmQoe3NjaGVtYTpHfSxuKSk7TShlLHQsJC5leHRlbmQoe3NjaGVtYTpHfSxuKSl9ZnVuY3Rpb24gQihlLHQpe3JldHVybiBqKGUsJC5leHRlbmQoe3NjaGVtYTpHfSx0KSl9Zm9yKHZhciAkPW4oNTIpLFU9big3Miksej1uKDcyNSksRz1uKDczKSxWPW4oOTgpLHE9T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eSxIPTEsVz0yLFE9MyxLPTQsSj0xLFk9MixYPTMsWj0vW1x4MDAtXHgwOFx4MEJceDBDXHgwRS1ceDFGXHg3Ri1ceDg0XHg4Ni1ceDlGXHVGRkZFXHVGRkZGXXxbXHVEODAwLVx1REJGRl0oPyFbXHVEQzAwLVx1REZGRl0pfCg/OlteXHVEODAwLVx1REJGRl18XilbXHVEQzAwLVx1REZGRl0vLGVlPS9bXHg4NVx1MjAyOFx1MjAyOV0vLHRlPS9bLFxbXF1ce1x9XS8sbmU9L14oPzohfCEhfCFbYS16XC1dKyEpJC9pLHJlPS9eKD86IXxbXixcW1xdXHtcfV0pKD86JVswLTlhLWZdezJ9fFswLTlhLXpcLSM7XC9cPzpAJj1cK1wkLF9cLiF+XConXChcKVxbXF1dKSokL2ksaWU9bmV3IEFycmF5KDI1Niksb2U9bmV3IEFycmF5KDI1NiksYWU9MDthZTwyNTY7YWUrKylpZVthZV09bChhZSk/MTowLG9lW2FlXT1sKGFlKTt2YXIgc2U9e1lBTUw6ZnVuY3Rpb24oZSx0LG4pe3ZhciByLGksbztudWxsIT09ZS52ZXJzaW9uJiZoKGUsImR1cGxpY2F0aW9uIG9mICVZQU1MIGRpcmVjdGl2ZSIpLDEhPT1uLmxlbmd0aCYmaChlLCJZQU1MIGRpcmVjdGl2ZSBhY2NlcHRzIGV4YWN0bHkgb25lIGFyZ3VtZW50Iikscj0vXihbMC05XSspXC4oWzAtOV0rKSQvLmV4ZWMoblswXSksbnVsbD09PXImJmgoZSwiaWxsLWZvcm1lZCBhcmd1bWVudCBvZiB0aGUgWUFNTCBkaXJlY3RpdmUiKSxpPXBhcnNlSW50KHJbMV0sMTApLG89cGFyc2VJbnQoclsyXSwxMCksMSE9PWkmJmgoZSwidW5hY2NlcHRhYmxlIFlBTUwgdmVyc2lvbiBvZiB0aGUgZG9jdW1lbnQiKSxlLnZlcnNpb249blswXSxlLmNoZWNrTGluZUJyZWFrcz1vPDIsMSE9PW8mJjIhPT1vJiZtKGUsInVuc3VwcG9ydGVkIFlBTUwgdmVyc2lvbiBvZiB0aGUgZG9jdW1lbnQiKX0sVEFHOmZ1bmN0aW9uKGUsdCxuKXt2YXIgcixpOzIhPT1uLmxlbmd0aCYmaChlLCJUQUcgZGlyZWN0aXZlIGFjY2VwdHMgZXhhY3RseSB0d28gYXJndW1lbnRzIikscj1uWzBdLGk9blsxXSxuZS50ZXN0KHIpfHxoKGUsImlsbC1mb3JtZWQgdGFnIGhhbmRsZSAoZmlyc3QgYXJndW1lbnQpIG9mIHRoZSBUQUcgZGlyZWN0aXZlIikscS5jYWxsKGUudGFnTWFwLHIpJiZoKGUsJ3RoZXJlIGlzIGEgcHJldmlvdXNseSBkZWNsYXJlZCBzdWZmaXggZm9yICInK3IrJyIgdGFnIGhhbmRsZScpLHJlLnRlc3QoaSl8fGgoZSwiaWxsLWZvcm1lZCB0YWcgcHJlZml4IChzZWNvbmQgYXJndW1lbnQpIG9mIHRoZSBUQUcgZGlyZWN0aXZlIiksZS50YWdNYXBbcl09aX19O2UuZXhwb3J0cy5sb2FkQWxsPU0sZS5leHBvcnRzLmxvYWQ9aixlLmV4cG9ydHMuc2FmZUxvYWRBbGw9UixlLmV4cG9ydHMuc2FmZUxvYWQ9Qn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUsdCxuLHIsaSl7dGhpcy5uYW1lPWUsdGhpcy5idWZmZXI9dCx0aGlzLnBvc2l0aW9uPW4sdGhpcy5saW5lPXIsdGhpcy5jb2x1bW49aX12YXIgaT1uKDUyKTtyLnByb3RvdHlwZS5nZXRTbmlwcGV0PWZ1bmN0aW9uKGUsdCl7dmFyIG4scixvLGEscztpZighdGhpcy5idWZmZXIpcmV0dXJuIG51bGw7Zm9yKGU9ZXx8NCx0PXR8fDc1LG49IiIscj10aGlzLnBvc2l0aW9uO3I+MCYmLTE9PT0iXDBcclxuXHg4NVx1MjAyOFx1MjAyOSIuaW5kZXhPZih0aGlzLmJ1ZmZlci5jaGFyQXQoci0xKSk7KWlmKHItPTEsdGhpcy5wb3NpdGlvbi1yPnQvMi0xKXtuPSIgLi4uICIscis9NTticmVha31mb3Iobz0iIixhPXRoaXMucG9zaXRpb247YTx0aGlzLmJ1ZmZlci5sZW5ndGgmJi0xPT09IlwwXHJcblx4ODVcdTIwMjhcdTIwMjkiLmluZGV4T2YodGhpcy5idWZmZXIuY2hhckF0KGEpKTspaWYoKGErPTEpLXRoaXMucG9zaXRpb24+dC8yLTEpe289IiAuLi4gIixhLT01O2JyZWFrfXJldHVybiBzPXRoaXMuYnVmZmVyLnNsaWNlKHIsYSksaS5yZXBlYXQoIiAiLGUpK24rcytvKyJcbiIraS5yZXBlYXQoIiAiLGUrdGhpcy5wb3NpdGlvbi1yK24ubGVuZ3RoKSsiXiJ9LHIucHJvdG90eXBlLnRvU3RyaW5nPWZ1bmN0aW9uKGUpe3ZhciB0LG49IiI7cmV0dXJuIHRoaXMubmFtZSYmKG4rPSdpbiAiJyt0aGlzLm5hbWUrJyIgJyksbis9ImF0IGxpbmUgIisodGhpcy5saW5lKzEpKyIsIGNvbHVtbiAiKyh0aGlzLmNvbHVtbisxKSxlfHwodD10aGlzLmdldFNuaXBwZXQoKSkmJihuKz0iOlxuIit0KSxufSxlLmV4cG9ydHM9cn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDE1KTtlLmV4cG9ydHM9bmV3IHIoInRhZzp5YW1sLm9yZywyMDAyOnN0ciIse2tpbmQ6InNjYWxhciIsY29uc3RydWN0OmZ1bmN0aW9uKGUpe3JldHVybiBudWxsIT09ZT9lOiIifX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPW4oMTUpO2UuZXhwb3J0cz1uZXcgcigidGFnOnlhbWwub3JnLDIwMDI6c2VxIix7a2luZDoic2VxdWVuY2UiLGNvbnN0cnVjdDpmdW5jdGlvbihlKXtyZXR1cm4gbnVsbCE9PWU/ZTpbXX19KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1uKDE1KTtlLmV4cG9ydHM9bmV3IHIoInRhZzp5YW1sLm9yZywyMDAyOm1hcCIse2tpbmQ6Im1hcHBpbmciLGNvbnN0cnVjdDpmdW5jdGlvbihlKXtyZXR1cm4gbnVsbCE9PWU/ZTp7fX19KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe2lmKG51bGw9PT1lKXJldHVybiEwO3ZhciB0PWUubGVuZ3RoO3JldHVybiAxPT09dCYmIn4iPT09ZXx8ND09PXQmJigibnVsbCI9PT1lfHwiTnVsbCI9PT1lfHwiTlVMTCI9PT1lKX1mdW5jdGlvbiBpKCl7cmV0dXJuIG51bGx9ZnVuY3Rpb24gbyhlKXtyZXR1cm4gbnVsbD09PWV9dmFyIGE9bigxNSk7ZS5leHBvcnRzPW5ldyBhKCJ0YWc6eWFtbC5vcmcsMjAwMjpudWxsIix7a2luZDoic2NhbGFyIixyZXNvbHZlOnIsY29uc3RydWN0OmkscHJlZGljYXRlOm8scmVwcmVzZW50OntjYW5vbmljYWw6ZnVuY3Rpb24oKXtyZXR1cm4ifiJ9LGxvd2VyY2FzZTpmdW5jdGlvbigpe3JldHVybiJudWxsIn0sdXBwZXJjYXNlOmZ1bmN0aW9uKCl7cmV0dXJuIk5VTEwifSxjYW1lbGNhc2U6ZnVuY3Rpb24oKXtyZXR1cm4iTnVsbCJ9fSxkZWZhdWx0U3R5bGU6Imxvd2VyY2FzZSJ9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe2lmKG51bGw9PT1lKXJldHVybiExO3ZhciB0PWUubGVuZ3RoO3JldHVybiA0PT09dCYmKCJ0cnVlIj09PWV8fCJUcnVlIj09PWV8fCJUUlVFIj09PWUpfHw1PT09dCYmKCJmYWxzZSI9PT1lfHwiRmFsc2UiPT09ZXx8IkZBTFNFIj09PWUpfWZ1bmN0aW9uIGkoZSl7cmV0dXJuInRydWUiPT09ZXx8IlRydWUiPT09ZXx8IlRSVUUiPT09ZX1mdW5jdGlvbiBvKGUpe3JldHVybiJbb2JqZWN0IEJvb2xlYW5dIj09PU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChlKX12YXIgYT1uKDE1KTtlLmV4cG9ydHM9bmV3IGEoInRhZzp5YW1sLm9yZywyMDAyOmJvb2wiLHtraW5kOiJzY2FsYXIiLHJlc29sdmU6cixjb25zdHJ1Y3Q6aSxwcmVkaWNhdGU6byxyZXByZXNlbnQ6e2xvd2VyY2FzZTpmdW5jdGlvbihlKXtyZXR1cm4gZT8idHJ1ZSI6ImZhbHNlIn0sdXBwZXJjYXNlOmZ1bmN0aW9uKGUpe3JldHVybiBlPyJUUlVFIjoiRkFMU0UifSxjYW1lbGNhc2U6ZnVuY3Rpb24oZSl7cmV0dXJuIGU/IlRydWUiOiJGYWxzZSJ9fSxkZWZhdWx0U3R5bGU6Imxvd2VyY2FzZSJ9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiA0ODw9ZSYmZTw9NTd8fDY1PD1lJiZlPD03MHx8OTc8PWUmJmU8PTEwMn1mdW5jdGlvbiBpKGUpe3JldHVybiA0ODw9ZSYmZTw9NTV9ZnVuY3Rpb24gbyhlKXtyZXR1cm4gNDg8PWUmJmU8PTU3fWZ1bmN0aW9uIGEoZSl7aWYobnVsbD09PWUpcmV0dXJuITE7dmFyIHQsbj1lLmxlbmd0aCxhPTAscz0hMTtpZighbilyZXR1cm4hMTtpZih0PWVbYV0sIi0iIT09dCYmIisiIT09dHx8KHQ9ZVsrK2FdKSwiMCI9PT10KXtpZihhKzE9PT1uKXJldHVybiEwO2lmKCJiIj09PSh0PWVbKythXSkpe2ZvcihhKys7YTxuO2ErKylpZigiXyIhPT0odD1lW2FdKSl7aWYoIjAiIT09dCYmIjEiIT09dClyZXR1cm4hMTtzPSEwfXJldHVybiBzJiYiXyIhPT10fWlmKCJ4Ij09PXQpe2ZvcihhKys7YTxuO2ErKylpZigiXyIhPT0odD1lW2FdKSl7aWYoIXIoZS5jaGFyQ29kZUF0KGEpKSlyZXR1cm4hMTtzPSEwfXJldHVybiBzJiYiXyIhPT10fWZvcig7YTxuO2ErKylpZigiXyIhPT0odD1lW2FdKSl7aWYoIWkoZS5jaGFyQ29kZUF0KGEpKSlyZXR1cm4hMTtzPSEwfXJldHVybiBzJiYiXyIhPT10fWlmKCJfIj09PXQpcmV0dXJuITE7Zm9yKDthPG47YSsrKWlmKCJfIiE9PSh0PWVbYV0pKXtpZigiOiI9PT10KWJyZWFrO2lmKCFvKGUuY2hhckNvZGVBdChhKSkpcmV0dXJuITE7cz0hMH1yZXR1cm4hKCFzfHwiXyI9PT10KSYmKCI6IiE9PXR8fC9eKDpbMC01XT9bMC05XSkrJC8udGVzdChlLnNsaWNlKGEpKSl9ZnVuY3Rpb24gcyhlKXt2YXIgdCxuLHI9ZSxpPTEsbz1bXTtyZXR1cm4tMSE9PXIuaW5kZXhPZigiXyIpJiYocj1yLnJlcGxhY2UoL18vZywiIikpLHQ9clswXSwiLSIhPT10JiYiKyIhPT10fHwoIi0iPT09dCYmKGk9LTEpLHI9ci5zbGljZSgxKSx0PXJbMF0pLCIwIj09PXI/MDoiMCI9PT10PyJiIj09PXJbMV0/aSpwYXJzZUludChyLnNsaWNlKDIpLDIpOiJ4Ij09PXJbMV0/aSpwYXJzZUludChyLDE2KTppKnBhcnNlSW50KHIsOCk6LTEhPT1yLmluZGV4T2YoIjoiKT8oci5zcGxpdCgiOiIpLmZvckVhY2goZnVuY3Rpb24oZSl7by51bnNoaWZ0KHBhcnNlSW50KGUsMTApKX0pLHI9MCxuPTEsby5mb3JFYWNoKGZ1bmN0aW9uKGUpe3IrPWUqbixuKj02MH0pLGkqcik6aSpwYXJzZUludChyLDEwKX1mdW5jdGlvbiB1KGUpe3JldHVybiJbb2JqZWN0IE51bWJlcl0iPT09T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGUpJiZlJTE9PT0wJiYhYy5pc05lZ2F0aXZlWmVybyhlKX12YXIgYz1uKDUyKSxsPW4oMTUpO2UuZXhwb3J0cz1uZXcgbCgidGFnOnlhbWwub3JnLDIwMDI6aW50Iix7a2luZDoic2NhbGFyIixyZXNvbHZlOmEsY29uc3RydWN0OnMscHJlZGljYXRlOnUscmVwcmVzZW50OntiaW5hcnk6ZnVuY3Rpb24oZSl7cmV0dXJuIGU+PTA/IjBiIitlLnRvU3RyaW5nKDIpOiItMGIiK2UudG9TdHJpbmcoMikuc2xpY2UoMSl9LG9jdGFsOmZ1bmN0aW9uKGUpe3JldHVybiBlPj0wPyIwIitlLnRvU3RyaW5nKDgpOiItMCIrZS50b1N0cmluZyg4KS5zbGljZSgxKX0sZGVjaW1hbDpmdW5jdGlvbihlKXtyZXR1cm4gZS50b1N0cmluZygxMCl9LGhleGFkZWNpbWFsOmZ1bmN0aW9uKGUpe3JldHVybiBlPj0wPyIweCIrZS50b1N0cmluZygxNikudG9VcHBlckNhc2UoKToiLTB4IitlLnRvU3RyaW5nKDE2KS50b1VwcGVyQ2FzZSgpLnNsaWNlKDEpfX0sZGVmYXVsdFN0eWxlOiJkZWNpbWFsIixzdHlsZUFsaWFzZXM6e2JpbmFyeTpbMiwiYmluIl0sb2N0YWw6WzgsIm9jdCJdLGRlY2ltYWw6WzEwLCJkZWMiXSxoZXhhZGVjaW1hbDpbMTYsImhleCJdfX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG51bGwhPT1lJiYhKCFjLnRlc3QoZSl8fCJfIj09PWVbZS5sZW5ndGgtMV0pfWZ1bmN0aW9uIGkoZSl7dmFyIHQsbixyLGk7cmV0dXJuIHQ9ZS5yZXBsYWNlKC9fL2csIiIpLnRvTG93ZXJDYXNlKCksbj0iLSI9PT10WzBdPy0xOjEsaT1bXSwiKy0iLmluZGV4T2YodFswXSk+PTAmJih0PXQuc2xpY2UoMSkpLCIuaW5mIj09PXQ/MT09PW4/TnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOk51bWJlci5ORUdBVElWRV9JTkZJTklUWToiLm5hbiI9PT10P05hTjp0LmluZGV4T2YoIjoiKT49MD8odC5zcGxpdCgiOiIpLmZvckVhY2goZnVuY3Rpb24oZSl7aS51bnNoaWZ0KHBhcnNlRmxvYXQoZSwxMCkpfSksdD0wLHI9MSxpLmZvckVhY2goZnVuY3Rpb24oZSl7dCs9ZSpyLHIqPTYwfSksbip0KTpuKnBhcnNlRmxvYXQodCwxMCl9ZnVuY3Rpb24gbyhlLHQpe3ZhciBuO2lmKGlzTmFOKGUpKXN3aXRjaCh0KXtjYXNlImxvd2VyY2FzZSI6cmV0dXJuIi5uYW4iO2Nhc2UidXBwZXJjYXNlIjpyZXR1cm4iLk5BTiI7Y2FzZSJjYW1lbGNhc2UiOnJldHVybiIuTmFOIn1lbHNlIGlmKE51bWJlci5QT1NJVElWRV9JTkZJTklUWT09PWUpc3dpdGNoKHQpe2Nhc2UibG93ZXJjYXNlIjpyZXR1cm4iLmluZiI7Y2FzZSJ1cHBlcmNhc2UiOnJldHVybiIuSU5GIjtjYXNlImNhbWVsY2FzZSI6cmV0dXJuIi5JbmYifWVsc2UgaWYoTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZPT09ZSlzd2l0Y2godCl7Y2FzZSJsb3dlcmNhc2UiOnJldHVybiItLmluZiI7Y2FzZSJ1cHBlcmNhc2UiOnJldHVybiItLklORiI7Y2FzZSJjYW1lbGNhc2UiOnJldHVybiItLkluZiJ9ZWxzZSBpZihzLmlzTmVnYXRpdmVaZXJvKGUpKXJldHVybiItMC4wIjtyZXR1cm4gbj1lLnRvU3RyaW5nKDEwKSxsLnRlc3Qobik/bi5yZXBsYWNlKCJlIiwiLmUiKTpufWZ1bmN0aW9uIGEoZSl7cmV0dXJuIltvYmplY3QgTnVtYmVyXSI9PT1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZSkmJihlJTEhPT0wfHxzLmlzTmVnYXRpdmVaZXJvKGUpKX12YXIgcz1uKDUyKSx1PW4oMTUpLGM9bmV3IFJlZ0V4cCgiXig/OlstK10/KD86MHxbMS05XVswLTlfXSopKD86XFwuWzAtOV9dKik/KD86W2VFXVstK10/WzAtOV0rKT98XFwuWzAtOV9dKyg/OltlRV1bLStdP1swLTldKyk/fFstK10/WzAtOV1bMC05X10qKD86OlswLTVdP1swLTldKStcXC5bMC05X10qfFstK10/XFwuKD86aW5mfEluZnxJTkYpfFxcLig/Om5hbnxOYU58TkFOKSkkIiksbD0vXlstK10/WzAtOV0rZS87ZS5leHBvcnRzPW5ldyB1KCJ0YWc6eWFtbC5vcmcsMjAwMjpmbG9hdCIse2tpbmQ6InNjYWxhciIscmVzb2x2ZTpyLGNvbnN0cnVjdDppLHByZWRpY2F0ZTphLHJlcHJlc2VudDpvLGRlZmF1bHRTdHlsZToibG93ZXJjYXNlIn0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7cmV0dXJuIG51bGwhPT1lJiYobnVsbCE9PXMuZXhlYyhlKXx8bnVsbCE9PXUuZXhlYyhlKSl9ZnVuY3Rpb24gaShlKXt2YXIgdCxuLHIsaSxvLGEsYyxsLHAsZixkPTAsaD1udWxsO2lmKHQ9cy5leGVjKGUpLG51bGw9PT10JiYodD11LmV4ZWMoZSkpLG51bGw9PT10KXRocm93IG5ldyBFcnJvcigiRGF0ZSByZXNvbHZlIGVycm9yIik7aWYobj0rdFsxXSxyPSt0WzJdLTEsaT0rdFszXSwhdFs0XSlyZXR1cm4gbmV3IERhdGUoRGF0ZS5VVEMobixyLGkpKTtpZihvPSt0WzRdLGE9K3RbNV0sYz0rdFs2XSx0WzddKXtmb3IoZD10WzddLnNsaWNlKDAsMyk7ZC5sZW5ndGg8MzspZCs9IjAiO2Q9K2R9cmV0dXJuIHRbOV0mJihsPSt0WzEwXSxwPSsodFsxMV18fDApLGg9NmU0Kig2MCpsK3ApLCItIj09PXRbOV0mJihoPS1oKSksZj1uZXcgRGF0ZShEYXRlLlVUQyhuLHIsaSxvLGEsYyxkKSksaCYmZi5zZXRUaW1lKGYuZ2V0VGltZSgpLWgpLGZ9ZnVuY3Rpb24gbyhlKXtyZXR1cm4gZS50b0lTT1N0cmluZygpfXZhciBhPW4oMTUpLHM9bmV3IFJlZ0V4cCgiXihbMC05XVswLTldWzAtOV1bMC05XSktKFswLTldWzAtOV0pLShbMC05XVswLTldKSQiKSx1PW5ldyBSZWdFeHAoIl4oWzAtOV1bMC05XVswLTldWzAtOV0pLShbMC05XVswLTldPyktKFswLTldWzAtOV0/KSg/OltUdF18WyBcXHRdKykoWzAtOV1bMC05XT8pOihbMC05XVswLTldKTooWzAtOV1bMC05XSkoPzpcXC4oWzAtOV0qKSk/KD86WyBcXHRdKihafChbLStdKShbMC05XVswLTldPykoPzo6KFswLTldWzAtOV0pKT8pKT8kIik7ZS5leHBvcnRzPW5ldyBhKCJ0YWc6eWFtbC5vcmcsMjAwMjp0aW1lc3RhbXAiLHtraW5kOiJzY2FsYXIiLHJlc29sdmU6cixjb25zdHJ1Y3Q6aSxpbnN0YW5jZU9mOkRhdGUscmVwcmVzZW50Om99KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiI8PCI9PT1lfHxudWxsPT09ZX12YXIgaT1uKDE1KTtlLmV4cG9ydHM9bmV3IGkoInRhZzp5YW1sLm9yZywyMDAyOm1lcmdlIix7a2luZDoic2NhbGFyIixyZXNvbHZlOnJ9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe2lmKG51bGw9PT1lKXJldHVybiExO3ZhciB0LG4scj0wLGk9ZS5sZW5ndGgsbz1jO2ZvcihuPTA7bjxpO24rKylpZighKCh0PW8uaW5kZXhPZihlLmNoYXJBdChuKSkpPjY0KSl7aWYodDwwKXJldHVybiExO3IrPTZ9cmV0dXJuIHIlOD09PTB9ZnVuY3Rpb24gaShlKXt2YXIgdCxuLHI9ZS5yZXBsYWNlKC9bXHJcbj1dL2csIiIpLGk9ci5sZW5ndGgsbz1jLGE9MCx1PVtdO2Zvcih0PTA7dDxpO3QrKyl0JTQ9PT0wJiZ0JiYodS5wdXNoKGE+PjE2JjI1NSksdS5wdXNoKGE+PjgmMjU1KSx1LnB1c2goMjU1JmEpKSxhPWE8PDZ8by5pbmRleE9mKHIuY2hhckF0KHQpKTtyZXR1cm4gbj1pJTQqNiwwPT09bj8odS5wdXNoKGE+PjE2JjI1NSksdS5wdXNoKGE+PjgmMjU1KSx1LnB1c2goMjU1JmEpKToxOD09PW4/KHUucHVzaChhPj4xMCYyNTUpLHUucHVzaChhPj4yJjI1NSkpOjEyPT09biYmdS5wdXNoKGE+PjQmMjU1KSxzP3MuZnJvbT9zLmZyb20odSk6bmV3IHModSk6dX1mdW5jdGlvbiBvKGUpe3ZhciB0LG4scj0iIixpPTAsbz1lLmxlbmd0aCxhPWM7Zm9yKHQ9MDt0PG87dCsrKXQlMz09PTAmJnQmJihyKz1hW2k+PjE4JjYzXSxyKz1hW2k+PjEyJjYzXSxyKz1hW2k+PjYmNjNdLHIrPWFbNjMmaV0pLGk9KGk8PDgpK2VbdF07cmV0dXJuIG49byUzLDA9PT1uPyhyKz1hW2k+PjE4JjYzXSxyKz1hW2k+PjEyJjYzXSxyKz1hW2k+PjYmNjNdLHIrPWFbNjMmaV0pOjI9PT1uPyhyKz1hW2k+PjEwJjYzXSxyKz1hW2k+PjQmNjNdLHIrPWFbaTw8MiY2M10scis9YVs2NF0pOjE9PT1uJiYocis9YVtpPj4yJjYzXSxyKz1hW2k8PDQmNjNdLHIrPWFbNjRdLHIrPWFbNjRdKSxyfWZ1bmN0aW9uIGEoZSl7cmV0dXJuIHMmJnMuaXNCdWZmZXIoZSl9dmFyIHM7dHJ5e3M9big3MzYpLkJ1ZmZlcn1jYXRjaChlKXt9dmFyIHU9bigxNSksYz0iQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLz1cblxyIjtlLmV4cG9ydHM9bmV3IHUoInRhZzp5YW1sLm9yZywyMDAyOmJpbmFyeSIse2tpbmQ6InNjYWxhciIscmVzb2x2ZTpyLGNvbnN0cnVjdDppLHByZWRpY2F0ZTphLHJlcHJlc2VudDpvfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7KGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHIoKXtyZXR1cm4gby5UWVBFRF9BUlJBWV9TVVBQT1JUPzIxNDc0ODM2NDc6MTA3Mzc0MTgyM31mdW5jdGlvbiBpKGUsdCl7aWYocigpPHQpdGhyb3cgbmV3IFJhbmdlRXJyb3IoIkludmFsaWQgdHlwZWQgYXJyYXkgbGVuZ3RoIik7cmV0dXJuIG8uVFlQRURfQVJSQVlfU1VQUE9SVD8oZT1uZXcgVWludDhBcnJheSh0KSxlLl9fcHJvdG9fXz1vLnByb3RvdHlwZSk6KG51bGw9PT1lJiYoZT1uZXcgbyh0KSksZS5sZW5ndGg9dCksZX1mdW5jdGlvbiBvKGUsdCxuKXtpZighby5UWVBFRF9BUlJBWV9TVVBQT1JUJiYhKHRoaXMgaW5zdGFuY2VvZiBvKSlyZXR1cm4gbmV3IG8oZSx0LG4pO2lmKCJudW1iZXIiPT09dHlwZW9mIGUpe2lmKCJzdHJpbmciPT09dHlwZW9mIHQpdGhyb3cgbmV3IEVycm9yKCJJZiBlbmNvZGluZyBpcyBzcGVjaWZpZWQgdGhlbiB0aGUgZmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIHN0cmluZyIpO3JldHVybiBjKHRoaXMsZSl9cmV0dXJuIGEodGhpcyxlLHQsbil9ZnVuY3Rpb24gYShlLHQsbixyKXtpZigibnVtYmVyIj09PXR5cGVvZiB0KXRocm93IG5ldyBUeXBlRXJyb3IoJyJ2YWx1ZSIgYXJndW1lbnQgbXVzdCBub3QgYmUgYSBudW1iZXInKTtyZXR1cm4idW5kZWZpbmVkIiE9PXR5cGVvZiBBcnJheUJ1ZmZlciYmdCBpbnN0YW5jZW9mIEFycmF5QnVmZmVyP2YoZSx0LG4scik6InN0cmluZyI9PT10eXBlb2YgdD9sKGUsdCxuKTpkKGUsdCl9ZnVuY3Rpb24gcyhlKXtpZigibnVtYmVyIiE9PXR5cGVvZiBlKXRocm93IG5ldyBUeXBlRXJyb3IoJyJzaXplIiBhcmd1bWVudCBtdXN0IGJlIGEgbnVtYmVyJyk7aWYoZTwwKXRocm93IG5ldyBSYW5nZUVycm9yKCcic2l6ZSIgYXJndW1lbnQgbXVzdCBub3QgYmUgbmVnYXRpdmUnKX1mdW5jdGlvbiB1KGUsdCxuLHIpe3JldHVybiBzKHQpLHQ8PTA/aShlLHQpOnZvaWQgMCE9PW4/InN0cmluZyI9PT10eXBlb2Ygcj9pKGUsdCkuZmlsbChuLHIpOmkoZSx0KS5maWxsKG4pOmkoZSx0KX1mdW5jdGlvbiBjKGUsdCl7aWYocyh0KSxlPWkoZSx0PDA/MDowfGgodCkpLCFvLlRZUEVEX0FSUkFZX1NVUFBPUlQpZm9yKHZhciBuPTA7bjx0OysrbillW25dPTA7cmV0dXJuIGV9ZnVuY3Rpb24gbChlLHQsbil7aWYoInN0cmluZyI9PT10eXBlb2YgbiYmIiIhPT1ufHwobj0idXRmOCIpLCFvLmlzRW5jb2RpbmcobikpdGhyb3cgbmV3IFR5cGVFcnJvcignImVuY29kaW5nIiBtdXN0IGJlIGEgdmFsaWQgc3RyaW5nIGVuY29kaW5nJyk7dmFyIHI9MHxnKHQsbik7ZT1pKGUscik7dmFyIGE9ZS53cml0ZSh0LG4pO3JldHVybiBhIT09ciYmKGU9ZS5zbGljZSgwLGEpKSxlfWZ1bmN0aW9uIHAoZSx0KXt2YXIgbj10Lmxlbmd0aDwwPzA6MHxoKHQubGVuZ3RoKTtlPWkoZSxuKTtmb3IodmFyIHI9MDtyPG47cis9MSllW3JdPTI1NSZ0W3JdO3JldHVybiBlfWZ1bmN0aW9uIGYoZSx0LG4scil7aWYodC5ieXRlTGVuZ3RoLG48MHx8dC5ieXRlTGVuZ3RoPG4pdGhyb3cgbmV3IFJhbmdlRXJyb3IoIidvZmZzZXQnIGlzIG91dCBvZiBib3VuZHMiKTtpZih0LmJ5dGVMZW5ndGg8bisocnx8MCkpdGhyb3cgbmV3IFJhbmdlRXJyb3IoIidsZW5ndGgnIGlzIG91dCBvZiBib3VuZHMiKTtyZXR1cm4gdD12b2lkIDA9PT1uJiZ2b2lkIDA9PT1yP25ldyBVaW50OEFycmF5KHQpOnZvaWQgMD09PXI/bmV3IFVpbnQ4QXJyYXkodCxuKTpuZXcgVWludDhBcnJheSh0LG4sciksby5UWVBFRF9BUlJBWV9TVVBQT1JUPyhlPXQsZS5fX3Byb3RvX189by5wcm90b3R5cGUpOmU9cChlLHQpLGV9ZnVuY3Rpb24gZChlLHQpe2lmKG8uaXNCdWZmZXIodCkpe3ZhciBuPTB8aCh0Lmxlbmd0aCk7cmV0dXJuIGU9aShlLG4pLDA9PT1lLmxlbmd0aD9lOih0LmNvcHkoZSwwLDAsbiksZSl9aWYodCl7aWYoInVuZGVmaW5lZCIhPT10eXBlb2YgQXJyYXlCdWZmZXImJnQuYnVmZmVyIGluc3RhbmNlb2YgQXJyYXlCdWZmZXJ8fCJsZW5ndGgiaW4gdClyZXR1cm4ibnVtYmVyIiE9PXR5cGVvZiB0Lmxlbmd0aHx8Syh0Lmxlbmd0aCk/aShlLDApOnAoZSx0KTtpZigiQnVmZmVyIj09PXQudHlwZSYmWCh0LmRhdGEpKXJldHVybiBwKGUsdC5kYXRhKX10aHJvdyBuZXcgVHlwZUVycm9yKCJGaXJzdCBhcmd1bWVudCBtdXN0IGJlIGEgc3RyaW5nLCBCdWZmZXIsIEFycmF5QnVmZmVyLCBBcnJheSwgb3IgYXJyYXktbGlrZSBvYmplY3QuIil9ZnVuY3Rpb24gaChlKXtpZihlPj1yKCkpdGhyb3cgbmV3IFJhbmdlRXJyb3IoIkF0dGVtcHQgdG8gYWxsb2NhdGUgQnVmZmVyIGxhcmdlciB0aGFuIG1heGltdW0gc2l6ZTogMHgiK3IoKS50b1N0cmluZygxNikrIiBieXRlcyIpO3JldHVybiAwfGV9ZnVuY3Rpb24gbShlKXtyZXR1cm4rZSE9ZSYmKGU9MCksby5hbGxvYygrZSl9ZnVuY3Rpb24gZyhlLHQpe2lmKG8uaXNCdWZmZXIoZSkpcmV0dXJuIGUubGVuZ3RoO2lmKCJ1bmRlZmluZWQiIT09dHlwZW9mIEFycmF5QnVmZmVyJiYiZnVuY3Rpb24iPT09dHlwZW9mIEFycmF5QnVmZmVyLmlzVmlldyYmKEFycmF5QnVmZmVyLmlzVmlldyhlKXx8ZSBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSlyZXR1cm4gZS5ieXRlTGVuZ3RoOyJzdHJpbmciIT09dHlwZW9mIGUmJihlPSIiK2UpO3ZhciBuPWUubGVuZ3RoO2lmKDA9PT1uKXJldHVybiAwO2Zvcih2YXIgcj0hMTs7KXN3aXRjaCh0KXtjYXNlImFzY2lpIjpjYXNlImxhdGluMSI6Y2FzZSJiaW5hcnkiOnJldHVybiBuO2Nhc2UidXRmOCI6Y2FzZSJ1dGYtOCI6Y2FzZSB2b2lkIDA6cmV0dXJuIFYoZSkubGVuZ3RoO2Nhc2UidWNzMiI6Y2FzZSJ1Y3MtMiI6Y2FzZSJ1dGYxNmxlIjpjYXNlInV0Zi0xNmxlIjpyZXR1cm4gMipuO2Nhc2UiaGV4IjpyZXR1cm4gbj4+PjE7Y2FzZSJiYXNlNjQiOnJldHVybiBXKGUpLmxlbmd0aDtkZWZhdWx0OmlmKHIpcmV0dXJuIFYoZSkubGVuZ3RoO3Q9KCIiK3QpLnRvTG93ZXJDYXNlKCkscj0hMH19ZnVuY3Rpb24geShlLHQsbil7dmFyIHI9ITE7aWYoKHZvaWQgMD09PXR8fHQ8MCkmJih0PTApLHQ+dGhpcy5sZW5ndGgpcmV0dXJuIiI7aWYoKHZvaWQgMD09PW58fG4+dGhpcy5sZW5ndGgpJiYobj10aGlzLmxlbmd0aCksbjw9MClyZXR1cm4iIjtpZihuPj4+PTAsdD4+Pj0wLG48PXQpcmV0dXJuIiI7Zm9yKGV8fChlPSJ1dGY4Iik7Oylzd2l0Y2goZSl7Y2FzZSJoZXgiOnJldHVybiBOKHRoaXMsdCxuKTtjYXNlInV0ZjgiOmNhc2UidXRmLTgiOnJldHVybiBfKHRoaXMsdCxuKTtjYXNlImFzY2lpIjpyZXR1cm4gTyh0aGlzLHQsbik7Y2FzZSJsYXRpbjEiOmNhc2UiYmluYXJ5IjpyZXR1cm4gRih0aGlzLHQsbik7Y2FzZSJiYXNlNjQiOnJldHVybiBBKHRoaXMsdCxuKTtjYXNlInVjczIiOmNhc2UidWNzLTIiOmNhc2UidXRmMTZsZSI6Y2FzZSJ1dGYtMTZsZSI6cmV0dXJuIEkodGhpcyx0LG4pO2RlZmF1bHQ6aWYocil0aHJvdyBuZXcgVHlwZUVycm9yKCJVbmtub3duIGVuY29kaW5nOiAiK2UpO2U9KGUrIiIpLnRvTG93ZXJDYXNlKCkscj0hMH19ZnVuY3Rpb24gdihlLHQsbil7dmFyIHI9ZVt0XTtlW3RdPWVbbl0sZVtuXT1yfWZ1bmN0aW9uIGIoZSx0LG4scixpKXtpZigwPT09ZS5sZW5ndGgpcmV0dXJuLTE7aWYoInN0cmluZyI9PT10eXBlb2Ygbj8ocj1uLG49MCk6bj4yMTQ3NDgzNjQ3P249MjE0NzQ4MzY0NzpuPC0yMTQ3NDgzNjQ4JiYobj0tMjE0NzQ4MzY0OCksbj0rbixpc05hTihuKSYmKG49aT8wOmUubGVuZ3RoLTEpLG48MCYmKG49ZS5sZW5ndGgrbiksbj49ZS5sZW5ndGgpe2lmKGkpcmV0dXJuLTE7bj1lLmxlbmd0aC0xfWVsc2UgaWYobjwwKXtpZighaSlyZXR1cm4tMTtuPTB9aWYoInN0cmluZyI9PT10eXBlb2YgdCYmKHQ9by5mcm9tKHQscikpLG8uaXNCdWZmZXIodCkpcmV0dXJuIDA9PT10Lmxlbmd0aD8tMTp4KGUsdCxuLHIsaSk7aWYoIm51bWJlciI9PT10eXBlb2YgdClyZXR1cm4gdCY9MjU1LG8uVFlQRURfQVJSQVlfU1VQUE9SVCYmImZ1bmN0aW9uIj09PXR5cGVvZiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mP2k/VWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKGUsdCxuKTpVaW50OEFycmF5LnByb3RvdHlwZS5sYXN0SW5kZXhPZi5jYWxsKGUsdCxuKTp4KGUsW3RdLG4scixpKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJ2YWwgbXVzdCBiZSBzdHJpbmcsIG51bWJlciBvciBCdWZmZXIiKX1mdW5jdGlvbiB4KGUsdCxuLHIsaSl7ZnVuY3Rpb24gbyhlLHQpe3JldHVybiAxPT09YT9lW3RdOmUucmVhZFVJbnQxNkJFKHQqYSl9dmFyIGE9MSxzPWUubGVuZ3RoLHU9dC5sZW5ndGg7aWYodm9pZCAwIT09ciYmKCJ1Y3MyIj09PShyPVN0cmluZyhyKS50b0xvd2VyQ2FzZSgpKXx8InVjcy0yIj09PXJ8fCJ1dGYxNmxlIj09PXJ8fCJ1dGYtMTZsZSI9PT1yKSl7aWYoZS5sZW5ndGg8Mnx8dC5sZW5ndGg8MilyZXR1cm4tMTthPTIscy89Mix1Lz0yLG4vPTJ9dmFyIGM7aWYoaSl7dmFyIGw9LTE7Zm9yKGM9bjtjPHM7YysrKWlmKG8oZSxjKT09PW8odCwtMT09PWw/MDpjLWwpKXtpZigtMT09PWwmJihsPWMpLGMtbCsxPT09dSlyZXR1cm4gbCphfWVsc2UtMSE9PWwmJihjLT1jLWwpLGw9LTF9ZWxzZSBmb3Iobit1PnMmJihuPXMtdSksYz1uO2M+PTA7Yy0tKXtmb3IodmFyIHA9ITAsZj0wO2Y8dTtmKyspaWYobyhlLGMrZikhPT1vKHQsZikpe3A9ITE7YnJlYWt9aWYocClyZXR1cm4gY31yZXR1cm4tMX1mdW5jdGlvbiBDKGUsdCxuLHIpe249TnVtYmVyKG4pfHwwO3ZhciBpPWUubGVuZ3RoLW47cj8ocj1OdW1iZXIocikpPmkmJihyPWkpOnI9aTt2YXIgbz10Lmxlbmd0aDtpZihvJTIhPT0wKXRocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgaGV4IHN0cmluZyIpO3I+by8yJiYocj1vLzIpO2Zvcih2YXIgYT0wO2E8cjsrK2Epe3ZhciBzPXBhcnNlSW50KHQuc3Vic3RyKDIqYSwyKSwxNik7aWYoaXNOYU4ocykpcmV0dXJuIGE7ZVtuK2FdPXN9cmV0dXJuIGF9ZnVuY3Rpb24gRShlLHQsbixyKXtyZXR1cm4gUShWKHQsZS5sZW5ndGgtbiksZSxuLHIpfWZ1bmN0aW9uIEQoZSx0LG4scil7cmV0dXJuIFEocSh0KSxlLG4scil9ZnVuY3Rpb24gdyhlLHQsbixyKXtyZXR1cm4gRChlLHQsbixyKX1mdW5jdGlvbiBTKGUsdCxuLHIpe3JldHVybiBRKFcodCksZSxuLHIpfWZ1bmN0aW9uIGsoZSx0LG4scil7cmV0dXJuIFEoSCh0LGUubGVuZ3RoLW4pLGUsbixyKX1mdW5jdGlvbiBBKGUsdCxuKXtyZXR1cm4gMD09PXQmJm49PT1lLmxlbmd0aD9KLmZyb21CeXRlQXJyYXkoZSk6Si5mcm9tQnl0ZUFycmF5KGUuc2xpY2UodCxuKSl9ZnVuY3Rpb24gXyhlLHQsbil7bj1NYXRoLm1pbihlLmxlbmd0aCxuKTtmb3IodmFyIHI9W10saT10O2k8bjspe3ZhciBvPWVbaV0sYT1udWxsLHM9bz4yMzk/NDpvPjIyMz8zOm8+MTkxPzI6MTtpZihpK3M8PW4pe3ZhciB1LGMsbCxwO3N3aXRjaChzKXtjYXNlIDE6bzwxMjgmJihhPW8pO2JyZWFrO2Nhc2UgMjp1PWVbaSsxXSwxMjg9PT0oMTkyJnUpJiYocD0oMzEmbyk8PDZ8NjMmdSk+MTI3JiYoYT1wKTticmVhaztjYXNlIDM6dT1lW2krMV0sYz1lW2krMl0sMTI4PT09KDE5MiZ1KSYmMTI4PT09KDE5MiZjKSYmKHA9KDE1Jm8pPDwxMnwoNjMmdSk8PDZ8NjMmYyk+MjA0NyYmKHA8NTUyOTZ8fHA+NTczNDMpJiYoYT1wKTticmVhaztjYXNlIDQ6dT1lW2krMV0sYz1lW2krMl0sbD1lW2krM10sMTI4PT09KDE5MiZ1KSYmMTI4PT09KDE5MiZjKSYmMTI4PT09KDE5MiZsKSYmKHA9KDE1Jm8pPDwxOHwoNjMmdSk8PDEyfCg2MyZjKTw8Nnw2MyZsKT42NTUzNSYmcDwxMTE0MTEyJiYoYT1wKX19bnVsbD09PWE/KGE9NjU1MzMscz0xKTphPjY1NTM1JiYoYS09NjU1MzYsci5wdXNoKGE+Pj4xMCYxMDIzfDU1Mjk2KSxhPTU2MzIwfDEwMjMmYSksci5wdXNoKGEpLGkrPXN9cmV0dXJuIFQocil9ZnVuY3Rpb24gVChlKXt2YXIgdD1lLmxlbmd0aDtpZih0PD1aKXJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZyxlKTtmb3IodmFyIG49IiIscj0wO3I8dDspbis9U3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShTdHJpbmcsZS5zbGljZShyLHIrPVopKTtyZXR1cm4gbn1mdW5jdGlvbiBPKGUsdCxuKXt2YXIgcj0iIjtuPU1hdGgubWluKGUubGVuZ3RoLG4pO2Zvcih2YXIgaT10O2k8bjsrK2kpcis9U3RyaW5nLmZyb21DaGFyQ29kZSgxMjcmZVtpXSk7cmV0dXJuIHJ9ZnVuY3Rpb24gRihlLHQsbil7dmFyIHI9IiI7bj1NYXRoLm1pbihlLmxlbmd0aCxuKTtmb3IodmFyIGk9dDtpPG47KytpKXIrPVN0cmluZy5mcm9tQ2hhckNvZGUoZVtpXSk7cmV0dXJuIHJ9ZnVuY3Rpb24gTihlLHQsbil7dmFyIHI9ZS5sZW5ndGg7KCF0fHx0PDApJiYodD0wKSwoIW58fG48MHx8bj5yKSYmKG49cik7Zm9yKHZhciBpPSIiLG89dDtvPG47KytvKWkrPUcoZVtvXSk7cmV0dXJuIGl9ZnVuY3Rpb24gSShlLHQsbil7Zm9yKHZhciByPWUuc2xpY2UodCxuKSxpPSIiLG89MDtvPHIubGVuZ3RoO28rPTIpaSs9U3RyaW5nLmZyb21DaGFyQ29kZShyW29dKzI1NipyW28rMV0pO3JldHVybiBpfWZ1bmN0aW9uIEwoZSx0LG4pe2lmKGUlMSE9PTB8fGU8MCl0aHJvdyBuZXcgUmFuZ2VFcnJvcigib2Zmc2V0IGlzIG5vdCB1aW50Iik7aWYoZSt0Pm4pdGhyb3cgbmV3IFJhbmdlRXJyb3IoIlRyeWluZyB0byBhY2Nlc3MgYmV5b25kIGJ1ZmZlciBsZW5ndGgiKX1mdW5jdGlvbiBQKGUsdCxuLHIsaSxhKXtpZighby5pc0J1ZmZlcihlKSl0aHJvdyBuZXcgVHlwZUVycm9yKCciYnVmZmVyIiBhcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyIGluc3RhbmNlJyk7aWYodD5pfHx0PGEpdGhyb3cgbmV3IFJhbmdlRXJyb3IoJyJ2YWx1ZSIgYXJndW1lbnQgaXMgb3V0IG9mIGJvdW5kcycpO2lmKG4rcj5lLmxlbmd0aCl0aHJvdyBuZXcgUmFuZ2VFcnJvcigiSW5kZXggb3V0IG9mIHJhbmdlIil9ZnVuY3Rpb24gTShlLHQsbixyKXt0PDAmJih0PTY1NTM1K3QrMSk7Zm9yKHZhciBpPTAsbz1NYXRoLm1pbihlLmxlbmd0aC1uLDIpO2k8bzsrK2kpZVtuK2ldPSh0JjI1NTw8OCoocj9pOjEtaSkpPj4+OCoocj9pOjEtaSl9ZnVuY3Rpb24gaihlLHQsbixyKXt0PDAmJih0PTQyOTQ5NjcyOTUrdCsxKTtmb3IodmFyIGk9MCxvPU1hdGgubWluKGUubGVuZ3RoLW4sNCk7aTxvOysraSllW24raV09dD4+PjgqKHI/aTozLWkpJjI1NX1mdW5jdGlvbiBSKGUsdCxuLHIsaSxvKXtpZihuK3I+ZS5sZW5ndGgpdGhyb3cgbmV3IFJhbmdlRXJyb3IoIkluZGV4IG91dCBvZiByYW5nZSIpO2lmKG48MCl0aHJvdyBuZXcgUmFuZ2VFcnJvcigiSW5kZXggb3V0IG9mIHJhbmdlIil9ZnVuY3Rpb24gQihlLHQsbixyLGkpe3JldHVybiBpfHxSKGUsdCxuLDQsMy40MDI4MjM0NjYzODUyODg2ZTM4LC0zLjQwMjgyMzQ2NjM4NTI4ODZlMzgpLFkud3JpdGUoZSx0LG4sciwyMyw0KSxuKzR9ZnVuY3Rpb24gJChlLHQsbixyLGkpe3JldHVybiBpfHxSKGUsdCxuLDgsMS43OTc2OTMxMzQ4NjIzMTU3ZTMwOCwtMS43OTc2OTMxMzQ4NjIzMTU3ZTMwOCksWS53cml0ZShlLHQsbixyLDUyLDgpLG4rOH1mdW5jdGlvbiBVKGUpe2lmKGU9eihlKS5yZXBsYWNlKGVlLCIiKSxlLmxlbmd0aDwyKXJldHVybiIiO2Zvcig7ZS5sZW5ndGglNCE9PTA7KWUrPSI9IjtyZXR1cm4gZX1mdW5jdGlvbiB6KGUpe3JldHVybiBlLnRyaW0/ZS50cmltKCk6ZS5yZXBsYWNlKC9eXHMrfFxzKyQvZywiIil9ZnVuY3Rpb24gRyhlKXtyZXR1cm4gZTwxNj8iMCIrZS50b1N0cmluZygxNik6ZS50b1N0cmluZygxNil9ZnVuY3Rpb24gVihlLHQpe3Q9dHx8MS8wO2Zvcih2YXIgbixyPWUubGVuZ3RoLGk9bnVsbCxvPVtdLGE9MDthPHI7KythKXtpZigobj1lLmNoYXJDb2RlQXQoYSkpPjU1Mjk1JiZuPDU3MzQ0KXtpZighaSl7aWYobj41NjMxOSl7KHQtPTMpPi0xJiZvLnB1c2goMjM5LDE5MSwxODkpO2NvbnRpbnVlfWlmKGErMT09PXIpeyh0LT0zKT4tMSYmby5wdXNoKDIzOSwxOTEsMTg5KTtjb250aW51ZX1pPW47Y29udGludWV9aWYobjw1NjMyMCl7KHQtPTMpPi0xJiZvLnB1c2goMjM5LDE5MSwxODkpLGk9bjtjb250aW51ZX1uPTY1NTM2KyhpLTU1Mjk2PDwxMHxuLTU2MzIwKX1lbHNlIGkmJih0LT0zKT4tMSYmby5wdXNoKDIzOSwxOTEsMTg5KTtpZihpPW51bGwsbjwxMjgpe2lmKCh0LT0xKTwwKWJyZWFrO28ucHVzaChuKX1lbHNlIGlmKG48MjA0OCl7aWYoKHQtPTIpPDApYnJlYWs7by5wdXNoKG4+PjZ8MTkyLDYzJm58MTI4KX1lbHNlIGlmKG48NjU1MzYpe2lmKCh0LT0zKTwwKWJyZWFrO28ucHVzaChuPj4xMnwyMjQsbj4+NiY2M3wxMjgsNjMmbnwxMjgpfWVsc2V7aWYoIShuPDExMTQxMTIpKXRocm93IG5ldyBFcnJvcigiSW52YWxpZCBjb2RlIHBvaW50Iik7aWYoKHQtPTQpPDApYnJlYWs7by5wdXNoKG4+PjE4fDI0MCxuPj4xMiY2M3wxMjgsbj4+NiY2M3wxMjgsNjMmbnwxMjgpfX1yZXR1cm4gb31mdW5jdGlvbiBxKGUpe2Zvcih2YXIgdD1bXSxuPTA7bjxlLmxlbmd0aDsrK24pdC5wdXNoKDI1NSZlLmNoYXJDb2RlQXQobikpO3JldHVybiB0fWZ1bmN0aW9uIEgoZSx0KXtmb3IodmFyIG4scixpLG89W10sYT0wO2E8ZS5sZW5ndGgmJiEoKHQtPTIpPDApOysrYSluPWUuY2hhckNvZGVBdChhKSxyPW4+PjgsaT1uJTI1NixvLnB1c2goaSksby5wdXNoKHIpO3JldHVybiBvfWZ1bmN0aW9uIFcoZSl7cmV0dXJuIEoudG9CeXRlQXJyYXkoVShlKSl9ZnVuY3Rpb24gUShlLHQsbixyKXtmb3IodmFyIGk9MDtpPHImJiEoaStuPj10Lmxlbmd0aHx8aT49ZS5sZW5ndGgpOysraSl0W2krbl09ZVtpXTtyZXR1cm4gaX1mdW5jdGlvbiBLKGUpe3JldHVybiBlIT09ZX12YXIgSj1uKDczNyksWT1uKDczOCksWD1uKDczOSk7dC5CdWZmZXI9byx0LlNsb3dCdWZmZXI9bSx0LklOU1BFQ1RfTUFYX0JZVEVTPTUwLG8uVFlQRURfQVJSQVlfU1VQUE9SVD12b2lkIDAhPT1lLlRZUEVEX0FSUkFZX1NVUFBPUlQ/ZS5UWVBFRF9BUlJBWV9TVVBQT1JUOmZ1bmN0aW9uKCl7dHJ5e3ZhciBlPW5ldyBVaW50OEFycmF5KDEpO3JldHVybiBlLl9fcHJvdG9fXz17X19wcm90b19fOlVpbnQ4QXJyYXkucHJvdG90eXBlLGZvbzpmdW5jdGlvbigpe3JldHVybiA0Mn19LDQyPT09ZS5mb28oKSYmImZ1bmN0aW9uIj09PXR5cGVvZiBlLnN1YmFycmF5JiYwPT09ZS5zdWJhcnJheSgxLDEpLmJ5dGVMZW5ndGh9Y2F0Y2goZSl7cmV0dXJuITF9fSgpLHQua01heExlbmd0aD1yKCksby5wb29sU2l6ZT04MTkyLG8uX2F1Z21lbnQ9ZnVuY3Rpb24oZSl7cmV0dXJuIGUuX19wcm90b19fPW8ucHJvdG90eXBlLGV9LG8uZnJvbT1mdW5jdGlvbihlLHQsbil7cmV0dXJuIGEobnVsbCxlLHQsbil9LG8uVFlQRURfQVJSQVlfU1VQUE9SVCYmKG8ucHJvdG90eXBlLl9fcHJvdG9fXz1VaW50OEFycmF5LnByb3RvdHlwZSxvLl9fcHJvdG9fXz1VaW50OEFycmF5LCJ1bmRlZmluZWQiIT09dHlwZW9mIFN5bWJvbCYmU3ltYm9sLnNwZWNpZXMmJm9bU3ltYm9sLnNwZWNpZXNdPT09byYmT2JqZWN0LmRlZmluZVByb3BlcnR5KG8sU3ltYm9sLnNwZWNpZXMse3ZhbHVlOm51bGwsY29uZmlndXJhYmxlOiEwfSkpLG8uYWxsb2M9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiB1KG51bGwsZSx0LG4pfSxvLmFsbG9jVW5zYWZlPWZ1bmN0aW9uKGUpe3JldHVybiBjKG51bGwsZSl9LG8uYWxsb2NVbnNhZmVTbG93PWZ1bmN0aW9uKGUpe3JldHVybiBjKG51bGwsZSl9LG8uaXNCdWZmZXI9ZnVuY3Rpb24oZSl7cmV0dXJuIShudWxsPT1lfHwhZS5faXNCdWZmZXIpfSxvLmNvbXBhcmU9ZnVuY3Rpb24oZSx0KXtpZighby5pc0J1ZmZlcihlKXx8IW8uaXNCdWZmZXIodCkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycyIpO2lmKGU9PT10KXJldHVybiAwO2Zvcih2YXIgbj1lLmxlbmd0aCxyPXQubGVuZ3RoLGk9MCxhPU1hdGgubWluKG4scik7aTxhOysraSlpZihlW2ldIT09dFtpXSl7bj1lW2ldLHI9dFtpXTticmVha31yZXR1cm4gbjxyPy0xOnI8bj8xOjB9LG8uaXNFbmNvZGluZz1mdW5jdGlvbihlKXtzd2l0Y2goU3RyaW5nKGUpLnRvTG93ZXJDYXNlKCkpe2Nhc2UiaGV4IjpjYXNlInV0ZjgiOmNhc2UidXRmLTgiOmNhc2UiYXNjaWkiOmNhc2UibGF0aW4xIjpjYXNlImJpbmFyeSI6Y2FzZSJiYXNlNjQiOmNhc2UidWNzMiI6Y2FzZSJ1Y3MtMiI6Y2FzZSJ1dGYxNmxlIjpjYXNlInV0Zi0xNmxlIjpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiExfX0sby5jb25jYXQ9ZnVuY3Rpb24oZSx0KXtpZighWChlKSl0aHJvdyBuZXcgVHlwZUVycm9yKCcibGlzdCIgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzJyk7aWYoMD09PWUubGVuZ3RoKXJldHVybiBvLmFsbG9jKDApO3ZhciBuO2lmKHZvaWQgMD09PXQpZm9yKHQ9MCxuPTA7bjxlLmxlbmd0aDsrK24pdCs9ZVtuXS5sZW5ndGg7dmFyIHI9by5hbGxvY1Vuc2FmZSh0KSxpPTA7Zm9yKG49MDtuPGUubGVuZ3RoOysrbil7dmFyIGE9ZVtuXTtpZighby5pc0J1ZmZlcihhKSl0aHJvdyBuZXcgVHlwZUVycm9yKCcibGlzdCIgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzJyk7YS5jb3B5KHIsaSksaSs9YS5sZW5ndGh9cmV0dXJuIHJ9LG8uYnl0ZUxlbmd0aD1nLG8ucHJvdG90eXBlLl9pc0J1ZmZlcj0hMCxvLnByb3RvdHlwZS5zd2FwMTY9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmxlbmd0aDtpZihlJTIhPT0wKXRocm93IG5ldyBSYW5nZUVycm9yKCJCdWZmZXIgc2l6ZSBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgMTYtYml0cyIpO2Zvcih2YXIgdD0wO3Q8ZTt0Kz0yKXYodGhpcyx0LHQrMSk7cmV0dXJuIHRoaXN9LG8ucHJvdG90eXBlLnN3YXAzMj1mdW5jdGlvbigpe3ZhciBlPXRoaXMubGVuZ3RoO2lmKGUlNCE9PTApdGhyb3cgbmV3IFJhbmdlRXJyb3IoIkJ1ZmZlciBzaXplIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAzMi1iaXRzIik7Zm9yKHZhciB0PTA7dDxlO3QrPTQpdih0aGlzLHQsdCszKSx2KHRoaXMsdCsxLHQrMik7cmV0dXJuIHRoaXN9LG8ucHJvdG90eXBlLnN3YXA2ND1mdW5jdGlvbigpe3ZhciBlPXRoaXMubGVuZ3RoO2lmKGUlOCE9PTApdGhyb3cgbmV3IFJhbmdlRXJyb3IoIkJ1ZmZlciBzaXplIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA2NC1iaXRzIik7Zm9yKHZhciB0PTA7dDxlO3QrPTgpdih0aGlzLHQsdCs3KSx2KHRoaXMsdCsxLHQrNiksdih0aGlzLHQrMix0KzUpLHYodGhpcyx0KzMsdCs0KTtyZXR1cm4gdGhpc30sby5wcm90b3R5cGUudG9TdHJpbmc9ZnVuY3Rpb24oKXt2YXIgZT0wfHRoaXMubGVuZ3RoO3JldHVybiAwPT09ZT8iIjowPT09YXJndW1lbnRzLmxlbmd0aD9fKHRoaXMsMCxlKTp5LmFwcGx5KHRoaXMsYXJndW1lbnRzKX0sby5wcm90b3R5cGUuZXF1YWxzPWZ1bmN0aW9uKGUpe2lmKCFvLmlzQnVmZmVyKGUpKXRocm93IG5ldyBUeXBlRXJyb3IoIkFyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXIiKTtyZXR1cm4gdGhpcz09PWV8fDA9PT1vLmNvbXBhcmUodGhpcyxlKX0sby5wcm90b3R5cGUuaW5zcGVjdD1mdW5jdGlvbigpe3ZhciBlPSIiLG49dC5JTlNQRUNUX01BWF9CWVRFUztyZXR1cm4gdGhpcy5sZW5ndGg+MCYmKGU9dGhpcy50b1N0cmluZygiaGV4IiwwLG4pLm1hdGNoKC8uezJ9L2cpLmpvaW4oIiAiKSx0aGlzLmxlbmd0aD5uJiYoZSs9IiAuLi4gIikpLCI8QnVmZmVyICIrZSsiPiJ9LG8ucHJvdG90eXBlLmNvbXBhcmU9ZnVuY3Rpb24oZSx0LG4scixpKXtpZighby5pc0J1ZmZlcihlKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJBcmd1bWVudCBtdXN0IGJlIGEgQnVmZmVyIik7aWYodm9pZCAwPT09dCYmKHQ9MCksdm9pZCAwPT09biYmKG49ZT9lLmxlbmd0aDowKSx2b2lkIDA9PT1yJiYocj0wKSx2b2lkIDA9PT1pJiYoaT10aGlzLmxlbmd0aCksdDwwfHxuPmUubGVuZ3RofHxyPDB8fGk+dGhpcy5sZW5ndGgpdGhyb3cgbmV3IFJhbmdlRXJyb3IoIm91dCBvZiByYW5nZSBpbmRleCIpO2lmKHI+PWkmJnQ+PW4pcmV0dXJuIDA7aWYocj49aSlyZXR1cm4tMTtpZih0Pj1uKXJldHVybiAxO2lmKHQ+Pj49MCxuPj4+PTAscj4+Pj0wLGk+Pj49MCx0aGlzPT09ZSlyZXR1cm4gMDtmb3IodmFyIGE9aS1yLHM9bi10LHU9TWF0aC5taW4oYSxzKSxjPXRoaXMuc2xpY2UocixpKSxsPWUuc2xpY2UodCxuKSxwPTA7cDx1OysrcClpZihjW3BdIT09bFtwXSl7YT1jW3BdLHM9bFtwXTticmVha31yZXR1cm4gYTxzPy0xOnM8YT8xOjB9LG8ucHJvdG90eXBlLmluY2x1ZGVzPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4tMSE9PXRoaXMuaW5kZXhPZihlLHQsbil9LG8ucHJvdG90eXBlLmluZGV4T2Y9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBiKHRoaXMsZSx0LG4sITApfSxvLnByb3RvdHlwZS5sYXN0SW5kZXhPZj1mdW5jdGlvbihlLHQsbil7cmV0dXJuIGIodGhpcyxlLHQsbiwhMSl9LG8ucHJvdG90eXBlLndyaXRlPWZ1bmN0aW9uKGUsdCxuLHIpe2lmKHZvaWQgMD09PXQpcj0idXRmOCIsbj10aGlzLmxlbmd0aCx0PTA7ZWxzZSBpZih2b2lkIDA9PT1uJiYic3RyaW5nIj09PXR5cGVvZiB0KXI9dCxuPXRoaXMubGVuZ3RoLHQ9MDtlbHNle2lmKCFpc0Zpbml0ZSh0KSl0aHJvdyBuZXcgRXJyb3IoIkJ1ZmZlci53cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXRbLCBsZW5ndGhdKSBpcyBubyBsb25nZXIgc3VwcG9ydGVkIik7dHw9MCxpc0Zpbml0ZShuKT8obnw9MCx2b2lkIDA9PT1yJiYocj0idXRmOCIpKToocj1uLG49dm9pZCAwKX12YXIgaT10aGlzLmxlbmd0aC10O2lmKCh2b2lkIDA9PT1ufHxuPmkpJiYobj1pKSxlLmxlbmd0aD4wJiYobjwwfHx0PDApfHx0PnRoaXMubGVuZ3RoKXRocm93IG5ldyBSYW5nZUVycm9yKCJBdHRlbXB0IHRvIHdyaXRlIG91dHNpZGUgYnVmZmVyIGJvdW5kcyIpO3J8fChyPSJ1dGY4Iik7Zm9yKHZhciBvPSExOzspc3dpdGNoKHIpe2Nhc2UiaGV4IjpyZXR1cm4gQyh0aGlzLGUsdCxuKTtjYXNlInV0ZjgiOmNhc2UidXRmLTgiOnJldHVybiBFKHRoaXMsZSx0LG4pO2Nhc2UiYXNjaWkiOnJldHVybiBEKHRoaXMsZSx0LG4pO2Nhc2UibGF0aW4xIjpjYXNlImJpbmFyeSI6cmV0dXJuIHcodGhpcyxlLHQsbik7Y2FzZSJiYXNlNjQiOnJldHVybiBTKHRoaXMsZSx0LG4pO2Nhc2UidWNzMiI6Y2FzZSJ1Y3MtMiI6Y2FzZSJ1dGYxNmxlIjpjYXNlInV0Zi0xNmxlIjpyZXR1cm4gayh0aGlzLGUsdCxuKTtkZWZhdWx0OmlmKG8pdGhyb3cgbmV3IFR5cGVFcnJvcigiVW5rbm93biBlbmNvZGluZzogIityKTtyPSgiIityKS50b0xvd2VyQ2FzZSgpLG89ITB9fSxvLnByb3RvdHlwZS50b0pTT049ZnVuY3Rpb24oKXtyZXR1cm57dHlwZToiQnVmZmVyIixkYXRhOkFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHRoaXMuX2Fycnx8dGhpcywwKX19O3ZhciBaPTQwOTY7by5wcm90b3R5cGUuc2xpY2U9ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLmxlbmd0aDtlPX5+ZSx0PXZvaWQgMD09PXQ/bjp+fnQsZTwwPyhlKz1uKTwwJiYoZT0wKTplPm4mJihlPW4pLHQ8MD8odCs9bik8MCYmKHQ9MCk6dD5uJiYodD1uKSx0PGUmJih0PWUpO3ZhciByO2lmKG8uVFlQRURfQVJSQVlfU1VQUE9SVClyPXRoaXMuc3ViYXJyYXkoZSx0KSxyLl9fcHJvdG9fXz1vLnByb3RvdHlwZTtlbHNle3ZhciBpPXQtZTtyPW5ldyBvKGksdm9pZCAwKTtmb3IodmFyIGE9MDthPGk7KythKXJbYV09dGhpc1thK2VdfXJldHVybiByfSxvLnByb3RvdHlwZS5yZWFkVUludExFPWZ1bmN0aW9uKGUsdCxuKXtlfD0wLHR8PTAsbnx8TChlLHQsdGhpcy5sZW5ndGgpO2Zvcih2YXIgcj10aGlzW2VdLGk9MSxvPTA7KytvPHQmJihpKj0yNTYpOylyKz10aGlzW2Urb10qaTtyZXR1cm4gcn0sby5wcm90b3R5cGUucmVhZFVJbnRCRT1mdW5jdGlvbihlLHQsbil7ZXw9MCx0fD0wLG58fEwoZSx0LHRoaXMubGVuZ3RoKTtmb3IodmFyIHI9dGhpc1tlKy0tdF0saT0xO3Q+MCYmKGkqPTI1Nik7KXIrPXRoaXNbZSstLXRdKmk7cmV0dXJuIHJ9LG8ucHJvdG90eXBlLnJlYWRVSW50OD1mdW5jdGlvbihlLHQpe3JldHVybiB0fHxMKGUsMSx0aGlzLmxlbmd0aCksdGhpc1tlXX0sby5wcm90b3R5cGUucmVhZFVJbnQxNkxFPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHR8fEwoZSwyLHRoaXMubGVuZ3RoKSx0aGlzW2VdfHRoaXNbZSsxXTw8OH0sby5wcm90b3R5cGUucmVhZFVJbnQxNkJFPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHR8fEwoZSwyLHRoaXMubGVuZ3RoKSx0aGlzW2VdPDw4fHRoaXNbZSsxXX0sby5wcm90b3R5cGUucmVhZFVJbnQzMkxFPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHR8fEwoZSw0LHRoaXMubGVuZ3RoKSwodGhpc1tlXXx0aGlzW2UrMV08PDh8dGhpc1tlKzJdPDwxNikrMTY3NzcyMTYqdGhpc1tlKzNdfSxvLnByb3RvdHlwZS5yZWFkVUludDMyQkU9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdHx8TChlLDQsdGhpcy5sZW5ndGgpLDE2Nzc3MjE2KnRoaXNbZV0rKHRoaXNbZSsxXTw8MTZ8dGhpc1tlKzJdPDw4fHRoaXNbZSszXSl9LG8ucHJvdG90eXBlLnJlYWRJbnRMRT1mdW5jdGlvbihlLHQsbil7ZXw9MCx0fD0wLG58fEwoZSx0LHRoaXMubGVuZ3RoKTtmb3IodmFyIHI9dGhpc1tlXSxpPTEsbz0wOysrbzx0JiYoaSo9MjU2KTspcis9dGhpc1tlK29dKmk7cmV0dXJuIGkqPTEyOCxyPj1pJiYoci09TWF0aC5wb3coMiw4KnQpKSxyfSxvLnByb3RvdHlwZS5yZWFkSW50QkU9ZnVuY3Rpb24oZSx0LG4pe2V8PTAsdHw9MCxufHxMKGUsdCx0aGlzLmxlbmd0aCk7Zm9yKHZhciByPXQsaT0xLG89dGhpc1tlKy0tcl07cj4wJiYoaSo9MjU2KTspbys9dGhpc1tlKy0tcl0qaTtyZXR1cm4gaSo9MTI4LG8+PWkmJihvLT1NYXRoLnBvdygyLDgqdCkpLG99LG8ucHJvdG90eXBlLnJlYWRJbnQ4PWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHR8fEwoZSwxLHRoaXMubGVuZ3RoKSwxMjgmdGhpc1tlXT8tMSooMjU1LXRoaXNbZV0rMSk6dGhpc1tlXX0sby5wcm90b3R5cGUucmVhZEludDE2TEU9ZnVuY3Rpb24oZSx0KXt0fHxMKGUsMix0aGlzLmxlbmd0aCk7dmFyIG49dGhpc1tlXXx0aGlzW2UrMV08PDg7cmV0dXJuIDMyNzY4Jm4/NDI5NDkwMTc2MHxuOm59LG8ucHJvdG90eXBlLnJlYWRJbnQxNkJFPWZ1bmN0aW9uKGUsdCl7dHx8TChlLDIsdGhpcy5sZW5ndGgpO3ZhciBuPXRoaXNbZSsxXXx0aGlzW2VdPDw4O3JldHVybiAzMjc2OCZuPzQyOTQ5MDE3NjB8bjpufSxvLnByb3RvdHlwZS5yZWFkSW50MzJMRT1mdW5jdGlvbihlLHQpe3JldHVybiB0fHxMKGUsNCx0aGlzLmxlbmd0aCksdGhpc1tlXXx0aGlzW2UrMV08PDh8dGhpc1tlKzJdPDwxNnx0aGlzW2UrM108PDI0fSxvLnByb3RvdHlwZS5yZWFkSW50MzJCRT1mdW5jdGlvbihlLHQpe3JldHVybiB0fHxMKGUsNCx0aGlzLmxlbmd0aCksdGhpc1tlXTw8MjR8dGhpc1tlKzFdPDwxNnx0aGlzW2UrMl08PDh8dGhpc1tlKzNdfSxvLnByb3RvdHlwZS5yZWFkRmxvYXRMRT1mdW5jdGlvbihlLHQpe3JldHVybiB0fHxMKGUsNCx0aGlzLmxlbmd0aCksWS5yZWFkKHRoaXMsZSwhMCwyMyw0KX0sby5wcm90b3R5cGUucmVhZEZsb2F0QkU9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gdHx8TChlLDQsdGhpcy5sZW5ndGgpLFkucmVhZCh0aGlzLGUsITEsMjMsNCl9LG8ucHJvdG90eXBlLnJlYWREb3VibGVMRT1mdW5jdGlvbihlLHQpe3JldHVybiB0fHxMKGUsOCx0aGlzLmxlbmd0aCksWS5yZWFkKHRoaXMsZSwhMCw1Miw4KX0sby5wcm90b3R5cGUucmVhZERvdWJsZUJFPWZ1bmN0aW9uKGUsdCl7cmV0dXJuIHR8fEwoZSw4LHRoaXMubGVuZ3RoKSxZLnJlYWQodGhpcyxlLCExLDUyLDgpfSxvLnByb3RvdHlwZS53cml0ZVVJbnRMRT1mdW5jdGlvbihlLHQsbixyKXtpZihlPStlLHR8PTAsbnw9MCwhcil7UCh0aGlzLGUsdCxuLE1hdGgucG93KDIsOCpuKS0xLDApfXZhciBpPTEsbz0wO2Zvcih0aGlzW3RdPTI1NSZlOysrbzxuJiYoaSo9MjU2KTspdGhpc1t0K29dPWUvaSYyNTU7cmV0dXJuIHQrbn0sby5wcm90b3R5cGUud3JpdGVVSW50QkU9ZnVuY3Rpb24oZSx0LG4scil7aWYoZT0rZSx0fD0wLG58PTAsIXIpe1AodGhpcyxlLHQsbixNYXRoLnBvdygyLDgqbiktMSwwKX12YXIgaT1uLTEsbz0xO2Zvcih0aGlzW3QraV09MjU1JmU7LS1pPj0wJiYobyo9MjU2KTspdGhpc1t0K2ldPWUvbyYyNTU7cmV0dXJuIHQrbn0sby5wcm90b3R5cGUud3JpdGVVSW50OD1mdW5jdGlvbihlLHQsbil7cmV0dXJuIGU9K2UsdHw9MCxufHxQKHRoaXMsZSx0LDEsMjU1LDApLG8uVFlQRURfQVJSQVlfU1VQUE9SVHx8KGU9TWF0aC5mbG9vcihlKSksdGhpc1t0XT0yNTUmZSx0KzF9LG8ucHJvdG90eXBlLndyaXRlVUludDE2TEU9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBlPStlLHR8PTAsbnx8UCh0aGlzLGUsdCwyLDY1NTM1LDApLG8uVFlQRURfQVJSQVlfU1VQUE9SVD8odGhpc1t0XT0yNTUmZSx0aGlzW3QrMV09ZT4+PjgpOk0odGhpcyxlLHQsITApLHQrMn0sby5wcm90b3R5cGUud3JpdGVVSW50MTZCRT1mdW5jdGlvbihlLHQsbil7cmV0dXJuIGU9K2UsdHw9MCxufHxQKHRoaXMsZSx0LDIsNjU1MzUsMCksby5UWVBFRF9BUlJBWV9TVVBQT1JUPyh0aGlzW3RdPWU+Pj44LHRoaXNbdCsxXT0yNTUmZSk6TSh0aGlzLGUsdCwhMSksdCsyfSxvLnByb3RvdHlwZS53cml0ZVVJbnQzMkxFPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZT0rZSx0fD0wLG58fFAodGhpcyxlLHQsNCw0Mjk0OTY3Mjk1LDApLG8uVFlQRURfQVJSQVlfU1VQUE9SVD8odGhpc1t0KzNdPWU+Pj4yNCx0aGlzW3QrMl09ZT4+PjE2LHRoaXNbdCsxXT1lPj4+OCx0aGlzW3RdPTI1NSZlKTpqKHRoaXMsZSx0LCEwKSx0KzR9LG8ucHJvdG90eXBlLndyaXRlVUludDMyQkU9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBlPStlLHR8PTAsbnx8UCh0aGlzLGUsdCw0LDQyOTQ5NjcyOTUsMCksby5UWVBFRF9BUlJBWV9TVVBQT1JUPyh0aGlzW3RdPWU+Pj4yNCx0aGlzW3QrMV09ZT4+PjE2LHRoaXNbdCsyXT1lPj4+OCx0aGlzW3QrM109MjU1JmUpOmoodGhpcyxlLHQsITEpLHQrNH0sby5wcm90b3R5cGUud3JpdGVJbnRMRT1mdW5jdGlvbihlLHQsbixyKXtpZihlPStlLHR8PTAsIXIpe3ZhciBpPU1hdGgucG93KDIsOCpuLTEpO1AodGhpcyxlLHQsbixpLTEsLWkpfXZhciBvPTAsYT0xLHM9MDtmb3IodGhpc1t0XT0yNTUmZTsrK288biYmKGEqPTI1Nik7KWU8MCYmMD09PXMmJjAhPT10aGlzW3Qrby0xXSYmKHM9MSksdGhpc1t0K29dPShlL2E+PjApLXMmMjU1O3JldHVybiB0K259LG8ucHJvdG90eXBlLndyaXRlSW50QkU9ZnVuY3Rpb24oZSx0LG4scil7aWYoZT0rZSx0fD0wLCFyKXt2YXIgaT1NYXRoLnBvdygyLDgqbi0xKTtQKHRoaXMsZSx0LG4saS0xLC1pKX12YXIgbz1uLTEsYT0xLHM9MDtmb3IodGhpc1t0K29dPTI1NSZlOy0tbz49MCYmKGEqPTI1Nik7KWU8MCYmMD09PXMmJjAhPT10aGlzW3QrbysxXSYmKHM9MSksdGhpc1t0K29dPShlL2E+PjApLXMmMjU1O3JldHVybiB0K259LG8ucHJvdG90eXBlLndyaXRlSW50OD1mdW5jdGlvbihlLHQsbil7cmV0dXJuIGU9K2UsdHw9MCxufHxQKHRoaXMsZSx0LDEsMTI3LC0xMjgpLG8uVFlQRURfQVJSQVlfU1VQUE9SVHx8KGU9TWF0aC5mbG9vcihlKSksZTwwJiYoZT0yNTUrZSsxKSx0aGlzW3RdPTI1NSZlLHQrMX0sby5wcm90b3R5cGUud3JpdGVJbnQxNkxFPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZT0rZSx0fD0wLG58fFAodGhpcyxlLHQsMiwzMjc2NywtMzI3NjgpLG8uVFlQRURfQVJSQVlfU1VQUE9SVD8odGhpc1t0XT0yNTUmZSx0aGlzW3QrMV09ZT4+PjgpOk0odGhpcyxlLHQsITApLHQrMn0sby5wcm90b3R5cGUud3JpdGVJbnQxNkJFPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZT0rZSx0fD0wLG58fFAodGhpcyxlLHQsMiwzMjc2NywtMzI3NjgpLG8uVFlQRURfQVJSQVlfU1VQUE9SVD8odGhpc1t0XT1lPj4+OCx0aGlzW3QrMV09MjU1JmUpOk0odGhpcyxlLHQsITEpLHQrMn0sby5wcm90b3R5cGUud3JpdGVJbnQzMkxFPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gZT0rZSx0fD0wLG58fFAodGhpcyxlLHQsNCwyMTQ3NDgzNjQ3LC0yMTQ3NDgzNjQ4KSxvLlRZUEVEX0FSUkFZX1NVUFBPUlQ/KHRoaXNbdF09MjU1JmUsdGhpc1t0KzFdPWU+Pj44LHRoaXNbdCsyXT1lPj4+MTYsdGhpc1t0KzNdPWU+Pj4yNCk6aih0aGlzLGUsdCwhMCksdCs0fSxvLnByb3RvdHlwZS53cml0ZUludDMyQkU9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBlPStlLHR8PTAsbnx8UCh0aGlzLGUsdCw0LDIxNDc0ODM2NDcsLTIxNDc0ODM2NDgpLGU8MCYmKGU9NDI5NDk2NzI5NStlKzEpLG8uVFlQRURfQVJSQVlfU1VQUE9SVD8odGhpc1t0XT1lPj4+MjQsdGhpc1t0KzFdPWU+Pj4xNix0aGlzW3QrMl09ZT4+PjgsdGhpc1t0KzNdPTI1NSZlKTpqKHRoaXMsZSx0LCExKSx0KzR9LG8ucHJvdG90eXBlLndyaXRlRmxvYXRMRT1mdW5jdGlvbihlLHQsbil7cmV0dXJuIEIodGhpcyxlLHQsITAsbil9LG8ucHJvdG90eXBlLndyaXRlRmxvYXRCRT1mdW5jdGlvbihlLHQsbil7cmV0dXJuIEIodGhpcyxlLHQsITEsbil9LG8ucHJvdG90eXBlLndyaXRlRG91YmxlTEU9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiAkKHRoaXMsZSx0LCEwLG4pfSxvLnByb3RvdHlwZS53cml0ZURvdWJsZUJFPWZ1bmN0aW9uKGUsdCxuKXtyZXR1cm4gJCh0aGlzLGUsdCwhMSxuKX0sby5wcm90b3R5cGUuY29weT1mdW5jdGlvbihlLHQsbixyKXtpZihufHwobj0wKSxyfHwwPT09cnx8KHI9dGhpcy5sZW5ndGgpLHQ+PWUubGVuZ3RoJiYodD1lLmxlbmd0aCksdHx8KHQ9MCkscj4wJiZyPG4mJihyPW4pLHI9PT1uKXJldHVybiAwO2lmKDA9PT1lLmxlbmd0aHx8MD09PXRoaXMubGVuZ3RoKXJldHVybiAwO2lmKHQ8MCl0aHJvdyBuZXcgUmFuZ2VFcnJvcigidGFyZ2V0U3RhcnQgb3V0IG9mIGJvdW5kcyIpO2lmKG48MHx8bj49dGhpcy5sZW5ndGgpdGhyb3cgbmV3IFJhbmdlRXJyb3IoInNvdXJjZVN0YXJ0IG91dCBvZiBib3VuZHMiKTtpZihyPDApdGhyb3cgbmV3IFJhbmdlRXJyb3IoInNvdXJjZUVuZCBvdXQgb2YgYm91bmRzIik7cj50aGlzLmxlbmd0aCYmKHI9dGhpcy5sZW5ndGgpLGUubGVuZ3RoLXQ8ci1uJiYocj1lLmxlbmd0aC10K24pO3ZhciBpLGE9ci1uO2lmKHRoaXM9PT1lJiZuPHQmJnQ8cilmb3IoaT1hLTE7aT49MDstLWkpZVtpK3RdPXRoaXNbaStuXTtlbHNlIGlmKGE8MWUzfHwhby5UWVBFRF9BUlJBWV9TVVBQT1JUKWZvcihpPTA7aTxhOysraSllW2krdF09dGhpc1tpK25dO2Vsc2UgVWludDhBcnJheS5wcm90b3R5cGUuc2V0LmNhbGwoZSx0aGlzLnN1YmFycmF5KG4sbithKSx0KTtyZXR1cm4gYX0sby5wcm90b3R5cGUuZmlsbD1mdW5jdGlvbihlLHQsbixyKXtpZigic3RyaW5nIj09PXR5cGVvZiBlKXtpZigic3RyaW5nIj09PXR5cGVvZiB0PyhyPXQsdD0wLG49dGhpcy5sZW5ndGgpOiJzdHJpbmciPT09dHlwZW9mIG4mJihyPW4sbj10aGlzLmxlbmd0aCksMT09PWUubGVuZ3RoKXt2YXIgaT1lLmNoYXJDb2RlQXQoMCk7aTwyNTYmJihlPWkpfWlmKHZvaWQgMCE9PXImJiJzdHJpbmciIT09dHlwZW9mIHIpdGhyb3cgbmV3IFR5cGVFcnJvcigiZW5jb2RpbmcgbXVzdCBiZSBhIHN0cmluZyIpO2lmKCJzdHJpbmciPT09dHlwZW9mIHImJiFvLmlzRW5jb2RpbmcocikpdGhyb3cgbmV3IFR5cGVFcnJvcigiVW5rbm93biBlbmNvZGluZzogIityKX1lbHNlIm51bWJlciI9PT10eXBlb2YgZSYmKGUmPTI1NSk7aWYodDwwfHx0aGlzLmxlbmd0aDx0fHx0aGlzLmxlbmd0aDxuKXRocm93IG5ldyBSYW5nZUVycm9yKCJPdXQgb2YgcmFuZ2UgaW5kZXgiKTtpZihuPD10KXJldHVybiB0aGlzO3Q+Pj49MCxuPXZvaWQgMD09PW4/dGhpcy5sZW5ndGg6bj4+PjAsZXx8KGU9MCk7dmFyIGE7aWYoIm51bWJlciI9PT10eXBlb2YgZSlmb3IoYT10O2E8bjsrK2EpdGhpc1thXT1lO2Vsc2V7dmFyIHM9by5pc0J1ZmZlcihlKT9lOlYobmV3IG8oZSxyKS50b1N0cmluZygpKSx1PXMubGVuZ3RoO2ZvcihhPTA7YTxuLXQ7KythKXRoaXNbYSt0XT1zW2EldV19cmV0dXJuIHRoaXN9O3ZhciBlZT0vW14rXC8wLTlBLVphLXotX10vZ30pLmNhbGwodCxuKDExKSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXt2YXIgdD1lLmxlbmd0aDtpZih0JTQ+MCl0aHJvdyBuZXcgRXJyb3IoIkludmFsaWQgc3RyaW5nLiBMZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDQiKTt2YXIgbj1lLmluZGV4T2YoIj0iKTtyZXR1cm4tMT09PW4mJihuPXQpLFtuLG49PT10PzA6NC1uJTRdfWZ1bmN0aW9uIGkoZSl7dmFyIHQ9cihlKSxuPXRbMF0saT10WzFdO3JldHVybiAzKihuK2kpLzQtaX1mdW5jdGlvbiBvKGUsdCxuKXtyZXR1cm4gMyoodCtuKS80LW59ZnVuY3Rpb24gYShlKXtmb3IodmFyIHQsbj1yKGUpLGk9blswXSxhPW5bMV0scz1uZXcgZihvKGUsaSxhKSksdT0wLGM9YT4wP2ktNDppLGw9MDtsPGM7bCs9NCl0PXBbZS5jaGFyQ29kZUF0KGwpXTw8MTh8cFtlLmNoYXJDb2RlQXQobCsxKV08PDEyfHBbZS5jaGFyQ29kZUF0KGwrMildPDw2fHBbZS5jaGFyQ29kZUF0KGwrMyldLHNbdSsrXT10Pj4xNiYyNTUsc1t1KytdPXQ+PjgmMjU1LHNbdSsrXT0yNTUmdDtyZXR1cm4gMj09PWEmJih0PXBbZS5jaGFyQ29kZUF0KGwpXTw8MnxwW2UuY2hhckNvZGVBdChsKzEpXT4+NCxzW3UrK109MjU1JnQpLDE9PT1hJiYodD1wW2UuY2hhckNvZGVBdChsKV08PDEwfHBbZS5jaGFyQ29kZUF0KGwrMSldPDw0fHBbZS5jaGFyQ29kZUF0KGwrMildPj4yLHNbdSsrXT10Pj44JjI1NSxzW3UrK109MjU1JnQpLHN9ZnVuY3Rpb24gcyhlKXtyZXR1cm4gbFtlPj4xOCY2M10rbFtlPj4xMiY2M10rbFtlPj42JjYzXStsWzYzJmVdfWZ1bmN0aW9uIHUoZSx0LG4pe2Zvcih2YXIgcixpPVtdLG89dDtvPG47bys9MylyPShlW29dPDwxNiYxNjcxMTY4MCkrKGVbbysxXTw8OCY2NTI4MCkrKDI1NSZlW28rMl0pLGkucHVzaChzKHIpKTtyZXR1cm4gaS5qb2luKCIiKX1mdW5jdGlvbiBjKGUpe2Zvcih2YXIgdCxuPWUubGVuZ3RoLHI9biUzLGk9W10sbz0wLGE9bi1yO288YTtvKz0xNjM4MylpLnB1c2godShlLG8sbysxNjM4Mz5hP2E6bysxNjM4MykpO3JldHVybiAxPT09cj8odD1lW24tMV0saS5wdXNoKGxbdD4+Ml0rbFt0PDw0JjYzXSsiPT0iKSk6Mj09PXImJih0PShlW24tMl08PDgpK2Vbbi0xXSxpLnB1c2gobFt0Pj4xMF0rbFt0Pj40JjYzXStsW3Q8PDImNjNdKyI9IikpLGkuam9pbigiIil9dC5ieXRlTGVuZ3RoPWksdC50b0J5dGVBcnJheT1hLHQuZnJvbUJ5dGVBcnJheT1jO2Zvcih2YXIgbD1bXSxwPVtdLGY9InVuZGVmaW5lZCIhPT10eXBlb2YgVWludDhBcnJheT9VaW50OEFycmF5OkFycmF5LGQ9IkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky8iLGg9MCxtPWQubGVuZ3RoO2g8bTsrK2gpbFtoXT1kW2hdLHBbZC5jaGFyQ29kZUF0KGgpXT1oO3BbIi0iLmNoYXJDb2RlQXQoMCldPTYyLHBbIl8iLmNoYXJDb2RlQXQoMCldPTYzfSxmdW5jdGlvbihlLHQpe3QucmVhZD1mdW5jdGlvbihlLHQsbixyLGkpe3ZhciBvLGEscz04Kmktci0xLHU9KDE8PHMpLTEsYz11Pj4xLGw9LTcscD1uP2ktMTowLGY9bj8tMToxLGQ9ZVt0K3BdO2ZvcihwKz1mLG89ZCYoMTw8LWwpLTEsZD4+PS1sLGwrPXM7bD4wO289MjU2Km8rZVt0K3BdLHArPWYsbC09OCk7Zm9yKGE9byYoMTw8LWwpLTEsbz4+PS1sLGwrPXI7bD4wO2E9MjU2KmErZVt0K3BdLHArPWYsbC09OCk7aWYoMD09PW8pbz0xLWM7ZWxzZXtpZihvPT09dSlyZXR1cm4gYT9OYU46MS8wKihkPy0xOjEpO2ErPU1hdGgucG93KDIsciksby09Y31yZXR1cm4oZD8tMToxKSphKk1hdGgucG93KDIsby1yKX0sdC53cml0ZT1mdW5jdGlvbihlLHQsbixyLGksbyl7dmFyIGEscyx1LGM9OCpvLWktMSxsPSgxPDxjKS0xLHA9bD4+MSxmPTIzPT09aT9NYXRoLnBvdygyLC0yNCktTWF0aC5wb3coMiwtNzcpOjAsZD1yPzA6by0xLGg9cj8xOi0xLG09dDwwfHwwPT09dCYmMS90PDA/MTowO2Zvcih0PU1hdGguYWJzKHQpLGlzTmFOKHQpfHx0PT09MS8wPyhzPWlzTmFOKHQpPzE6MCxhPWwpOihhPU1hdGguZmxvb3IoTWF0aC5sb2codCkvTWF0aC5MTjIpLHQqKHU9TWF0aC5wb3coMiwtYSkpPDEmJihhLS0sdSo9MiksdCs9YStwPj0xP2YvdTpmKk1hdGgucG93KDIsMS1wKSx0KnU+PTImJihhKyssdS89MiksYStwPj1sPyhzPTAsYT1sKTphK3A+PTE/KHM9KHQqdS0xKSpNYXRoLnBvdygyLGkpLGErPXApOihzPXQqTWF0aC5wb3coMixwLTEpKk1hdGgucG93KDIsaSksYT0wKSk7aT49ODtlW24rZF09MjU1JnMsZCs9aCxzLz0yNTYsaS09OCk7Zm9yKGE9YTw8aXxzLGMrPWk7Yz4wO2VbbitkXT0yNTUmYSxkKz1oLGEvPTI1NixjLT04KTtlW24rZC1oXXw9MTI4Km19fSxmdW5jdGlvbihlLHQpe3ZhciBuPXt9LnRvU3RyaW5nO2UuZXhwb3J0cz1BcnJheS5pc0FycmF5fHxmdW5jdGlvbihlKXtyZXR1cm4iW29iamVjdCBBcnJheV0iPT1uLmNhbGwoZSl9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7aWYobnVsbD09PWUpcmV0dXJuITA7dmFyIHQsbixyLGksbyx1PVtdLGM9ZTtmb3IodD0wLG49Yy5sZW5ndGg7dDxuO3QrPTEpe2lmKHI9Y1t0XSxvPSExLCJbb2JqZWN0IE9iamVjdF0iIT09cy5jYWxsKHIpKXJldHVybiExO2ZvcihpIGluIHIpaWYoYS5jYWxsKHIsaSkpe2lmKG8pcmV0dXJuITE7bz0hMH1pZighbylyZXR1cm4hMTtpZigtMSE9PXUuaW5kZXhPZihpKSlyZXR1cm4hMTt1LnB1c2goaSl9cmV0dXJuITB9ZnVuY3Rpb24gaShlKXtyZXR1cm4gbnVsbCE9PWU/ZTpbXX12YXIgbz1uKDE1KSxhPU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkscz1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO2UuZXhwb3J0cz1uZXcgbygidGFnOnlhbWwub3JnLDIwMDI6b21hcCIse2tpbmQ6InNlcXVlbmNlIixyZXNvbHZlOnIsY29uc3RydWN0Oml9KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe2lmKG51bGw9PT1lKXJldHVybiEwO3ZhciB0LG4scixpLG8scz1lO2ZvcihvPW5ldyBBcnJheShzLmxlbmd0aCksdD0wLG49cy5sZW5ndGg7dDxuO3QrPTEpe2lmKHI9c1t0XSwiW29iamVjdCBPYmplY3RdIiE9PWEuY2FsbChyKSlyZXR1cm4hMTtpZihpPU9iamVjdC5rZXlzKHIpLDEhPT1pLmxlbmd0aClyZXR1cm4hMTtvW3RdPVtpWzBdLHJbaVswXV1dfXJldHVybiEwfWZ1bmN0aW9uIGkoZSl7aWYobnVsbD09PWUpcmV0dXJuW107dmFyIHQsbixyLGksbyxhPWU7Zm9yKG89bmV3IEFycmF5KGEubGVuZ3RoKSx0PTAsbj1hLmxlbmd0aDt0PG47dCs9MSlyPWFbdF0saT1PYmplY3Qua2V5cyhyKSxvW3RdPVtpWzBdLHJbaVswXV1dO3JldHVybiBvfXZhciBvPW4oMTUpLGE9T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztlLmV4cG9ydHM9bmV3IG8oInRhZzp5YW1sLm9yZywyMDAyOnBhaXJzIix7a2luZDoic2VxdWVuY2UiLHJlc29sdmU6cixjb25zdHJ1Y3Q6aX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7aWYobnVsbD09PWUpcmV0dXJuITA7dmFyIHQsbj1lO2Zvcih0IGluIG4paWYoYS5jYWxsKG4sdCkmJm51bGwhPT1uW3RdKXJldHVybiExO3JldHVybiEwfWZ1bmN0aW9uIGkoZSl7cmV0dXJuIG51bGwhPT1lP2U6e319dmFyIG89bigxNSksYT1PYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5O2UuZXhwb3J0cz1uZXcgbygidGFnOnlhbWwub3JnLDIwMDI6c2V0Iix7a2luZDoibWFwcGluZyIscmVzb2x2ZTpyLGNvbnN0cnVjdDppfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcigpe3JldHVybiEwfWZ1bmN0aW9uIGkoKXt9ZnVuY3Rpb24gbygpe3JldHVybiIifWZ1bmN0aW9uIGEoZSl7cmV0dXJuInVuZGVmaW5lZCI9PT10eXBlb2YgZX12YXIgcz1uKDE1KTtlLmV4cG9ydHM9bmV3IHMoInRhZzp5YW1sLm9yZywyMDAyOmpzL3VuZGVmaW5lZCIse2tpbmQ6InNjYWxhciIscmVzb2x2ZTpyLGNvbnN0cnVjdDppLHByZWRpY2F0ZTphLHJlcHJlc2VudDpvfSl9LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlKXtpZihudWxsPT09ZSlyZXR1cm4hMTtpZigwPT09ZS5sZW5ndGgpcmV0dXJuITE7dmFyIHQ9ZSxuPS9cLyhbZ2ltXSopJC8uZXhlYyhlKSxyPSIiO2lmKCIvIj09PXRbMF0pe2lmKG4mJihyPW5bMV0pLHIubGVuZ3RoPjMpcmV0dXJuITE7aWYoIi8iIT09dFt0Lmxlbmd0aC1yLmxlbmd0aC0xXSlyZXR1cm4hMX1yZXR1cm4hMH1mdW5jdGlvbiBpKGUpe3ZhciB0PWUsbj0vXC8oW2dpbV0qKSQvLmV4ZWMoZSkscj0iIjtyZXR1cm4iLyI9PT10WzBdJiYobiYmKHI9blsxXSksdD10LnNsaWNlKDEsdC5sZW5ndGgtci5sZW5ndGgtMSkpLG5ldyBSZWdFeHAodCxyKX1mdW5jdGlvbiBvKGUpe3ZhciB0PSIvIitlLnNvdXJjZSsiLyI7cmV0dXJuIGUuZ2xvYmFsJiYodCs9ImciKSxlLm11bHRpbGluZSYmKHQrPSJtIiksZS5pZ25vcmVDYXNlJiYodCs9ImkiKSx0fWZ1bmN0aW9uIGEoZSl7cmV0dXJuIltvYmplY3QgUmVnRXhwXSI9PT1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZSl9dmFyIHM9bigxNSk7ZS5leHBvcnRzPW5ldyBzKCJ0YWc6eWFtbC5vcmcsMjAwMjpqcy9yZWdleHAiLHtraW5kOiJzY2FsYXIiLHJlc29sdmU6cixjb25zdHJ1Y3Q6aSxwcmVkaWNhdGU6YSxyZXByZXNlbnQ6b30pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7aWYobnVsbD09PWUpcmV0dXJuITE7dHJ5e3ZhciB0PSIoIitlKyIpIixuPXMucGFyc2UodCx7cmFuZ2U6ITB9KTtyZXR1cm4iUHJvZ3JhbSI9PT1uLnR5cGUmJjE9PT1uLmJvZHkubGVuZ3RoJiYiRXhwcmVzc2lvblN0YXRlbWVudCI9PT1uLmJvZHlbMF0udHlwZSYmKCJBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbiI9PT1uLmJvZHlbMF0uZXhwcmVzc2lvbi50eXBlfHwiRnVuY3Rpb25FeHByZXNzaW9uIj09PW4uYm9keVswXS5leHByZXNzaW9uLnR5cGUpfWNhdGNoKGUpe3JldHVybiExfX1mdW5jdGlvbiBpKGUpe3ZhciB0LG49IigiK2UrIikiLHI9cy5wYXJzZShuLHtyYW5nZTohMH0pLGk9W107aWYoIlByb2dyYW0iIT09ci50eXBlfHwxIT09ci5ib2R5Lmxlbmd0aHx8IkV4cHJlc3Npb25TdGF0ZW1lbnQiIT09ci5ib2R5WzBdLnR5cGV8fCJBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbiIhPT1yLmJvZHlbMF0uZXhwcmVzc2lvbi50eXBlJiYiRnVuY3Rpb25FeHByZXNzaW9uIiE9PXIuYm9keVswXS5leHByZXNzaW9uLnR5cGUpdGhyb3cgbmV3IEVycm9yKCJGYWlsZWQgdG8gcmVzb2x2ZSBmdW5jdGlvbiIpO3JldHVybiByLmJvZHlbMF0uZXhwcmVzc2lvbi5wYXJhbXMuZm9yRWFjaChmdW5jdGlvbihlKXtpLnB1c2goZS5uYW1lKX0pLHQ9ci5ib2R5WzBdLmV4cHJlc3Npb24uYm9keS5yYW5nZSxuZXcgRnVuY3Rpb24oaSxuLnNsaWNlKHRbMF0rMSx0WzFdLTEpKX1mdW5jdGlvbiBvKGUpe3JldHVybiBlLnRvU3RyaW5nKCl9ZnVuY3Rpb24gYShlKXtyZXR1cm4iW29iamVjdCBGdW5jdGlvbl0iPT09T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGUpfXZhciBzO3RyeXtzPW4oNzQ2KX1jYXRjaChlKXsidW5kZWZpbmVkIiE9PXR5cGVvZiB3aW5kb3cmJihzPXdpbmRvdy5lc3ByaW1hKX12YXIgdT1uKDE1KTtlLmV4cG9ydHM9bmV3IHUoInRhZzp5YW1sLm9yZywyMDAyOmpzL2Z1bmN0aW9uIix7a2luZDoic2NhbGFyIixyZXNvbHZlOnIsY29uc3RydWN0OmkscHJlZGljYXRlOmEscmVwcmVzZW50Om99KX0sZnVuY3Rpb24oZSx0LG4peyFmdW5jdGlvbih0LG4pe2UuZXhwb3J0cz1uKCl9KDAsZnVuY3Rpb24oKXtyZXR1cm4gZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChyKXtpZihuW3JdKXJldHVybiBuW3JdLmV4cG9ydHM7dmFyIGk9bltyXT17ZXhwb3J0czp7fSxpZDpyLGxvYWRlZDohMX07cmV0dXJuIGVbcl0uY2FsbChpLmV4cG9ydHMsaSxpLmV4cG9ydHMsdCksaS5sb2FkZWQ9ITAsaS5leHBvcnRzfXZhciBuPXt9O3JldHVybiB0Lm09ZSx0LmM9bix0LnA9IiIsdCgwKX0oW2Z1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcihlLHQsbil7dmFyIHI9bnVsbCxpPWZ1bmN0aW9uKGUsdCl7biYmbihlLHQpLHImJnIudmlzaXQoZSx0KX0sbz0iZnVuY3Rpb24iPT09dHlwZW9mIG4/aTpudWxsLGE9ITE7aWYodCl7YT0iYm9vbGVhbiI9PT10eXBlb2YgdC5jb21tZW50JiZ0LmNvbW1lbnQ7dmFyIGw9ImJvb2xlYW4iPT09dHlwZW9mIHQuYXR0YWNoQ29tbWVudCYmdC5hdHRhY2hDb21tZW50OyhhfHxsKSYmKHI9bmV3IHMuQ29tbWVudEhhbmRsZXIsci5hdHRhY2g9bCx0LmNvbW1lbnQ9ITAsbz1pKX12YXIgcD0hMTt0JiYic3RyaW5nIj09PXR5cGVvZiB0LnNvdXJjZVR5cGUmJihwPSJtb2R1bGUiPT09dC5zb3VyY2VUeXBlKTt2YXIgZjtmPXQmJiJib29sZWFuIj09PXR5cGVvZiB0LmpzeCYmdC5qc3g/bmV3IHUuSlNYUGFyc2VyKGUsdCxvKTpuZXcgYy5QYXJzZXIoZSx0LG8pO3ZhciBkPXA/Zi5wYXJzZU1vZHVsZSgpOmYucGFyc2VTY3JpcHQoKSxoPWQ7cmV0dXJuIGEmJnImJihoLmNvbW1lbnRzPXIuY29tbWVudHMpLGYuY29uZmlnLnRva2VucyYmKGgudG9rZW5zPWYudG9rZW5zKSxmLmNvbmZpZy50b2xlcmFudCYmKGguZXJyb3JzPWYuZXJyb3JIYW5kbGVyLmVycm9ycyksaH1mdW5jdGlvbiBpKGUsdCxuKXt2YXIgaT10fHx7fTtyZXR1cm4gaS5zb3VyY2VUeXBlPSJtb2R1bGUiLHIoZSxpLG4pfWZ1bmN0aW9uIG8oZSx0LG4pe3ZhciBpPXR8fHt9O3JldHVybiBpLnNvdXJjZVR5cGU9InNjcmlwdCIscihlLGksbil9ZnVuY3Rpb24gYShlLHQsbil7dmFyIHIsaT1uZXcgbC5Ub2tlbml6ZXIoZSx0KTtyPVtdO3RyeXtmb3IoOzspe3ZhciBvPWkuZ2V0TmV4dFRva2VuKCk7aWYoIW8pYnJlYWs7biYmKG89bihvKSksci5wdXNoKG8pfX1jYXRjaChlKXtpLmVycm9ySGFuZGxlci50b2xlcmF0ZShlKX1yZXR1cm4gaS5lcnJvckhhbmRsZXIudG9sZXJhbnQmJihyLmVycm9ycz1pLmVycm9ycygpKSxyfU9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcz1uKDEpLHU9bigzKSxjPW4oOCksbD1uKDE1KTt0LnBhcnNlPXIsdC5wYXJzZU1vZHVsZT1pLHQucGFyc2VTY3JpcHQ9byx0LnRva2VuaXplPWE7dmFyIHA9bigyKTt0LlN5bnRheD1wLlN5bnRheCx0LnZlcnNpb249IjQuMC4wIn0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9bigyKSxpPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMuYXR0YWNoPSExLHRoaXMuY29tbWVudHM9W10sdGhpcy5zdGFjaz1bXSx0aGlzLmxlYWRpbmc9W10sdGhpcy50cmFpbGluZz1bXX1yZXR1cm4gZS5wcm90b3R5cGUuaW5zZXJ0SW5uZXJDb21tZW50cz1mdW5jdGlvbihlLHQpe2lmKGUudHlwZT09PXIuU3ludGF4LkJsb2NrU3RhdGVtZW50JiYwPT09ZS5ib2R5Lmxlbmd0aCl7Zm9yKHZhciBuPVtdLGk9dGhpcy5sZWFkaW5nLmxlbmd0aC0xO2k+PTA7LS1pKXt2YXIgbz10aGlzLmxlYWRpbmdbaV07dC5lbmQub2Zmc2V0Pj1vLnN0YXJ0JiYobi51bnNoaWZ0KG8uY29tbWVudCksdGhpcy5sZWFkaW5nLnNwbGljZShpLDEpLHRoaXMudHJhaWxpbmcuc3BsaWNlKGksMSkpfW4ubGVuZ3RoJiYoZS5pbm5lckNvbW1lbnRzPW4pfX0sZS5wcm90b3R5cGUuZmluZFRyYWlsaW5nQ29tbWVudHM9ZnVuY3Rpb24oZSl7dmFyIHQ9W107aWYodGhpcy50cmFpbGluZy5sZW5ndGg+MCl7Zm9yKHZhciBuPXRoaXMudHJhaWxpbmcubGVuZ3RoLTE7bj49MDstLW4pe3ZhciByPXRoaXMudHJhaWxpbmdbbl07ci5zdGFydD49ZS5lbmQub2Zmc2V0JiZ0LnVuc2hpZnQoci5jb21tZW50KX1yZXR1cm4gdGhpcy50cmFpbGluZy5sZW5ndGg9MCx0fXZhciBpPXRoaXMuc3RhY2tbdGhpcy5zdGFjay5sZW5ndGgtMV07aWYoaSYmaS5ub2RlLnRyYWlsaW5nQ29tbWVudHMpe3ZhciBvPWkubm9kZS50cmFpbGluZ0NvbW1lbnRzWzBdO28mJm8ucmFuZ2VbMF0+PWUuZW5kLm9mZnNldCYmKHQ9aS5ub2RlLnRyYWlsaW5nQ29tbWVudHMsZGVsZXRlIGkubm9kZS50cmFpbGluZ0NvbW1lbnRzKX1yZXR1cm4gdH0sZS5wcm90b3R5cGUuZmluZExlYWRpbmdDb21tZW50cz1mdW5jdGlvbihlKXtmb3IodmFyIHQsbj1bXTt0aGlzLnN0YWNrLmxlbmd0aD4wOyl7dmFyIHI9dGhpcy5zdGFja1t0aGlzLnN0YWNrLmxlbmd0aC0xXTtpZighKHImJnIuc3RhcnQ+PWUuc3RhcnQub2Zmc2V0KSlicmVhazt0PXIubm9kZSx0aGlzLnN0YWNrLnBvcCgpfWlmKHQpe2Zvcih2YXIgaT10LmxlYWRpbmdDb21tZW50cz90LmxlYWRpbmdDb21tZW50cy5sZW5ndGg6MCxvPWktMTtvPj0wOy0tbyl7dmFyIGE9dC5sZWFkaW5nQ29tbWVudHNbb107YS5yYW5nZVsxXTw9ZS5zdGFydC5vZmZzZXQmJihuLnVuc2hpZnQoYSksdC5sZWFkaW5nQ29tbWVudHMuc3BsaWNlKG8sMSkpfXJldHVybiB0LmxlYWRpbmdDb21tZW50cyYmMD09PXQubGVhZGluZ0NvbW1lbnRzLmxlbmd0aCYmZGVsZXRlIHQubGVhZGluZ0NvbW1lbnRzLG59Zm9yKHZhciBvPXRoaXMubGVhZGluZy5sZW5ndGgtMTtvPj0wOy0tbyl7dmFyIHI9dGhpcy5sZWFkaW5nW29dO3Iuc3RhcnQ8PWUuc3RhcnQub2Zmc2V0JiYobi51bnNoaWZ0KHIuY29tbWVudCksdGhpcy5sZWFkaW5nLnNwbGljZShvLDEpKX1yZXR1cm4gbn0sZS5wcm90b3R5cGUudmlzaXROb2RlPWZ1bmN0aW9uKGUsdCl7aWYoIShlLnR5cGU9PT1yLlN5bnRheC5Qcm9ncmFtJiZlLmJvZHkubGVuZ3RoPjApKXt0aGlzLmluc2VydElubmVyQ29tbWVudHMoZSx0KTt2YXIgbj10aGlzLmZpbmRUcmFpbGluZ0NvbW1lbnRzKHQpLGk9dGhpcy5maW5kTGVhZGluZ0NvbW1lbnRzKHQpO2kubGVuZ3RoPjAmJihlLmxlYWRpbmdDb21tZW50cz1pKSxuLmxlbmd0aD4wJiYoZS50cmFpbGluZ0NvbW1lbnRzPW4pLHRoaXMuc3RhY2sucHVzaCh7bm9kZTplLHN0YXJ0OnQuc3RhcnQub2Zmc2V0fSl9fSxlLnByb3RvdHlwZS52aXNpdENvbW1lbnQ9ZnVuY3Rpb24oZSx0KXt2YXIgbj0iTCI9PT1lLnR5cGVbMF0/IkxpbmUiOiJCbG9jayIscj17dHlwZTpuLHZhbHVlOmUudmFsdWV9O2lmKGUucmFuZ2UmJihyLnJhbmdlPWUucmFuZ2UpLGUubG9jJiYoci5sb2M9ZS5sb2MpLHRoaXMuY29tbWVudHMucHVzaChyKSx0aGlzLmF0dGFjaCl7dmFyIGk9e2NvbW1lbnQ6e3R5cGU6bix2YWx1ZTplLnZhbHVlLHJhbmdlOlt0LnN0YXJ0Lm9mZnNldCx0LmVuZC5vZmZzZXRdfSxzdGFydDp0LnN0YXJ0Lm9mZnNldH07ZS5sb2MmJihpLmNvbW1lbnQubG9jPWUubG9jKSxlLnR5cGU9bix0aGlzLmxlYWRpbmcucHVzaChpKSx0aGlzLnRyYWlsaW5nLnB1c2goaSl9fSxlLnByb3RvdHlwZS52aXNpdD1mdW5jdGlvbihlLHQpeyJMaW5lQ29tbWVudCI9PT1lLnR5cGU/dGhpcy52aXNpdENvbW1lbnQoZSx0KToiQmxvY2tDb21tZW50Ij09PWUudHlwZT90aGlzLnZpc2l0Q29tbWVudChlLHQpOnRoaXMuYXR0YWNoJiZ0aGlzLnZpc2l0Tm9kZShlLHQpfSxlfSgpO3QuQ29tbWVudEhhbmRsZXI9aX0sZnVuY3Rpb24oZSx0KXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuU3ludGF4PXtBc3NpZ25tZW50RXhwcmVzc2lvbjoiQXNzaWdubWVudEV4cHJlc3Npb24iLEFzc2lnbm1lbnRQYXR0ZXJuOiJBc3NpZ25tZW50UGF0dGVybiIsQXJyYXlFeHByZXNzaW9uOiJBcnJheUV4cHJlc3Npb24iLEFycmF5UGF0dGVybjoiQXJyYXlQYXR0ZXJuIixBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbjoiQXJyb3dGdW5jdGlvbkV4cHJlc3Npb24iLEF3YWl0RXhwcmVzc2lvbjoiQXdhaXRFeHByZXNzaW9uIixCbG9ja1N0YXRlbWVudDoiQmxvY2tTdGF0ZW1lbnQiLEJpbmFyeUV4cHJlc3Npb246IkJpbmFyeUV4cHJlc3Npb24iLEJyZWFrU3RhdGVtZW50OiJCcmVha1N0YXRlbWVudCIsQ2FsbEV4cHJlc3Npb246IkNhbGxFeHByZXNzaW9uIixDYXRjaENsYXVzZToiQ2F0Y2hDbGF1c2UiLENsYXNzQm9keToiQ2xhc3NCb2R5IixDbGFzc0RlY2xhcmF0aW9uOiJDbGFzc0RlY2xhcmF0aW9uIixDbGFzc0V4cHJlc3Npb246IkNsYXNzRXhwcmVzc2lvbiIsQ29uZGl0aW9uYWxFeHByZXNzaW9uOiJDb25kaXRpb25hbEV4cHJlc3Npb24iLENvbnRpbnVlU3RhdGVtZW50OiJDb250aW51ZVN0YXRlbWVudCIsRG9XaGlsZVN0YXRlbWVudDoiRG9XaGlsZVN0YXRlbWVudCIsRGVidWdnZXJTdGF0ZW1lbnQ6IkRlYnVnZ2VyU3RhdGVtZW50IixFbXB0eVN0YXRlbWVudDoiRW1wdHlTdGF0ZW1lbnQiLEV4cG9ydEFsbERlY2xhcmF0aW9uOiJFeHBvcnRBbGxEZWNsYXJhdGlvbiIsRXhwb3J0RGVmYXVsdERlY2xhcmF0aW9uOiJFeHBvcnREZWZhdWx0RGVjbGFyYXRpb24iLEV4cG9ydE5hbWVkRGVjbGFyYXRpb246IkV4cG9ydE5hbWVkRGVjbGFyYXRpb24iLEV4cG9ydFNwZWNpZmllcjoiRXhwb3J0U3BlY2lmaWVyIixFeHByZXNzaW9uU3RhdGVtZW50OiJFeHByZXNzaW9uU3RhdGVtZW50IixGb3JTdGF0ZW1lbnQ6IkZvclN0YXRlbWVudCIsRm9yT2ZTdGF0ZW1lbnQ6IkZvck9mU3RhdGVtZW50IixGb3JJblN0YXRlbWVudDoiRm9ySW5TdGF0ZW1lbnQiLEZ1bmN0aW9uRGVjbGFyYXRpb246IkZ1bmN0aW9uRGVjbGFyYXRpb24iLEZ1bmN0aW9uRXhwcmVzc2lvbjoiRnVuY3Rpb25FeHByZXNzaW9uIixJZGVudGlmaWVyOiJJZGVudGlmaWVyIixJZlN0YXRlbWVudDoiSWZTdGF0ZW1lbnQiLEltcG9ydERlY2xhcmF0aW9uOiJJbXBvcnREZWNsYXJhdGlvbiIsSW1wb3J0RGVmYXVsdFNwZWNpZmllcjoiSW1wb3J0RGVmYXVsdFNwZWNpZmllciIsSW1wb3J0TmFtZXNwYWNlU3BlY2lmaWVyOiJJbXBvcnROYW1lc3BhY2VTcGVjaWZpZXIiLEltcG9ydFNwZWNpZmllcjoiSW1wb3J0U3BlY2lmaWVyIixMaXRlcmFsOiJMaXRlcmFsIixMYWJlbGVkU3RhdGVtZW50OiJMYWJlbGVkU3RhdGVtZW50IixMb2dpY2FsRXhwcmVzc2lvbjoiTG9naWNhbEV4cHJlc3Npb24iLE1lbWJlckV4cHJlc3Npb246Ik1lbWJlckV4cHJlc3Npb24iLE1ldGFQcm9wZXJ0eToiTWV0YVByb3BlcnR5IixNZXRob2REZWZpbml0aW9uOiJNZXRob2REZWZpbml0aW9uIixOZXdFeHByZXNzaW9uOiJOZXdFeHByZXNzaW9uIixPYmplY3RFeHByZXNzaW9uOiJPYmplY3RFeHByZXNzaW9uIixPYmplY3RQYXR0ZXJuOiJPYmplY3RQYXR0ZXJuIixQcm9ncmFtOiJQcm9ncmFtIixQcm9wZXJ0eToiUHJvcGVydHkiLFJlc3RFbGVtZW50OiJSZXN0RWxlbWVudCIsUmV0dXJuU3RhdGVtZW50OiJSZXR1cm5TdGF0ZW1lbnQiLFNlcXVlbmNlRXhwcmVzc2lvbjoiU2VxdWVuY2VFeHByZXNzaW9uIixTcHJlYWRFbGVtZW50OiJTcHJlYWRFbGVtZW50IixTdXBlcjoiU3VwZXIiLFN3aXRjaENhc2U6IlN3aXRjaENhc2UiLFN3aXRjaFN0YXRlbWVudDoiU3dpdGNoU3RhdGVtZW50IixUYWdnZWRUZW1wbGF0ZUV4cHJlc3Npb246IlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbiIsVGVtcGxhdGVFbGVtZW50OiJUZW1wbGF0ZUVsZW1lbnQiLFRlbXBsYXRlTGl0ZXJhbDoiVGVtcGxhdGVMaXRlcmFsIixUaGlzRXhwcmVzc2lvbjoiVGhpc0V4cHJlc3Npb24iLFRocm93U3RhdGVtZW50OiJUaHJvd1N0YXRlbWVudCIsVHJ5U3RhdGVtZW50OiJUcnlTdGF0ZW1lbnQiLFVuYXJ5RXhwcmVzc2lvbjoiVW5hcnlFeHByZXNzaW9uIixVcGRhdGVFeHByZXNzaW9uOiJVcGRhdGVFeHByZXNzaW9uIixWYXJpYWJsZURlY2xhcmF0aW9uOiJWYXJpYWJsZURlY2xhcmF0aW9uIixWYXJpYWJsZURlY2xhcmF0b3I6IlZhcmlhYmxlRGVjbGFyYXRvciIsV2hpbGVTdGF0ZW1lbnQ6IldoaWxlU3RhdGVtZW50IixXaXRoU3RhdGVtZW50OiJXaXRoU3RhdGVtZW50IixZaWVsZEV4cHJlc3Npb246IllpZWxkRXhwcmVzc2lvbiJ9fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSl7dmFyIHQ7c3dpdGNoKGUudHlwZSl7Y2FzZSBzLkpTWFN5bnRheC5KU1hJZGVudGlmaWVyOnQ9ZS5uYW1lO2JyZWFrO2Nhc2Ugcy5KU1hTeW50YXguSlNYTmFtZXNwYWNlZE5hbWU6dmFyIG49ZTt0PXIobi5uYW1lc3BhY2UpKyI6IityKG4ubmFtZSk7YnJlYWs7Y2FzZSBzLkpTWFN5bnRheC5KU1hNZW1iZXJFeHByZXNzaW9uOnZhciBpPWU7dD1yKGkub2JqZWN0KSsiLiIrcihpLnByb3BlcnR5KX1yZXR1cm4gdH12YXIgaT10aGlzJiZ0aGlzLl9fZXh0ZW5kc3x8ZnVuY3Rpb24oKXt2YXIgZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX07cmV0dXJuIGZ1bmN0aW9uKHQsbil7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9dH1lKHQsbiksdC5wcm90b3R5cGU9bnVsbD09PW4/T2JqZWN0LmNyZWF0ZShuKTooci5wcm90b3R5cGU9bi5wcm90b3R5cGUsbmV3IHIpfX0oKTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89big0KSxhPW4oNSkscz1uKDYpLHU9big3KSxjPW4oOCksbD1uKDEzKSxwPW4oMTQpO2wuVG9rZW5OYW1lWzEwMF09IkpTWElkZW50aWZpZXIiLGwuVG9rZW5OYW1lWzEwMV09IkpTWFRleHQiO3ZhciBmPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCxuLHIpe3JldHVybiBlLmNhbGwodGhpcyx0LG4scil8fHRoaXN9cmV0dXJuIGkodCxlKSx0LnByb3RvdHlwZS5wYXJzZVByaW1hcnlFeHByZXNzaW9uPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubWF0Y2goIjwiKT90aGlzLnBhcnNlSlNYUm9vdCgpOmUucHJvdG90eXBlLnBhcnNlUHJpbWFyeUV4cHJlc3Npb24uY2FsbCh0aGlzKX0sdC5wcm90b3R5cGUuc3RhcnRKU1g9ZnVuY3Rpb24oKXt0aGlzLnNjYW5uZXIuaW5kZXg9dGhpcy5zdGFydE1hcmtlci5pbmRleCx0aGlzLnNjYW5uZXIubGluZU51bWJlcj10aGlzLnN0YXJ0TWFya2VyLmxpbmUsdGhpcy5zY2FubmVyLmxpbmVTdGFydD10aGlzLnN0YXJ0TWFya2VyLmluZGV4LXRoaXMuc3RhcnRNYXJrZXIuY29sdW1ufSx0LnByb3RvdHlwZS5maW5pc2hKU1g9ZnVuY3Rpb24oKXt0aGlzLm5leHRUb2tlbigpfSx0LnByb3RvdHlwZS5yZWVudGVySlNYPWZ1bmN0aW9uKCl7dGhpcy5zdGFydEpTWCgpLHRoaXMuZXhwZWN0SlNYKCJ9IiksdGhpcy5jb25maWcudG9rZW5zJiZ0aGlzLnRva2Vucy5wb3AoKX0sdC5wcm90b3R5cGUuY3JlYXRlSlNYTm9kZT1mdW5jdGlvbigpe3JldHVybiB0aGlzLmNvbGxlY3RDb21tZW50cygpLHtpbmRleDp0aGlzLnNjYW5uZXIuaW5kZXgsbGluZTp0aGlzLnNjYW5uZXIubGluZU51bWJlcixjb2x1bW46dGhpcy5zY2FubmVyLmluZGV4LXRoaXMuc2Nhbm5lci5saW5lU3RhcnR9fSx0LnByb3RvdHlwZS5jcmVhdGVKU1hDaGlsZE5vZGU9ZnVuY3Rpb24oKXtyZXR1cm57aW5kZXg6dGhpcy5zY2FubmVyLmluZGV4LGxpbmU6dGhpcy5zY2FubmVyLmxpbmVOdW1iZXIsY29sdW1uOnRoaXMuc2Nhbm5lci5pbmRleC10aGlzLnNjYW5uZXIubGluZVN0YXJ0fX0sdC5wcm90b3R5cGUuc2NhblhIVE1MRW50aXR5PWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0iJiIsbj0hMCxyPSExLGk9ITEsYT0hMTshdGhpcy5zY2FubmVyLmVvZigpJiZuJiYhcjspe3ZhciBzPXRoaXMuc2Nhbm5lci5zb3VyY2VbdGhpcy5zY2FubmVyLmluZGV4XTtpZihzPT09ZSlicmVhaztpZihyPSI7Ij09PXMsdCs9cywrK3RoaXMuc2Nhbm5lci5pbmRleCwhcilzd2l0Y2godC5sZW5ndGgpe2Nhc2UgMjppPSIjIj09PXM7YnJlYWs7Y2FzZSAzOmkmJihhPSJ4Ij09PXMsbj1hfHxvLkNoYXJhY3Rlci5pc0RlY2ltYWxEaWdpdChzLmNoYXJDb2RlQXQoMCkpLGk9aSYmIWEpO2JyZWFrO2RlZmF1bHQ6bj1uJiYhKGkmJiFvLkNoYXJhY3Rlci5pc0RlY2ltYWxEaWdpdChzLmNoYXJDb2RlQXQoMCkpKSxuPW4mJiEoYSYmIW8uQ2hhcmFjdGVyLmlzSGV4RGlnaXQocy5jaGFyQ29kZUF0KDApKSl9fWlmKG4mJnImJnQubGVuZ3RoPjIpe3ZhciB1PXQuc3Vic3RyKDEsdC5sZW5ndGgtMik7aSYmdS5sZW5ndGg+MT90PVN0cmluZy5mcm9tQ2hhckNvZGUocGFyc2VJbnQodS5zdWJzdHIoMSksMTApKTphJiZ1Lmxlbmd0aD4yP3Q9U3RyaW5nLmZyb21DaGFyQ29kZShwYXJzZUludCgiMCIrdS5zdWJzdHIoMSksMTYpKTppfHxhfHwhcC5YSFRNTEVudGl0aWVzW3VdfHwodD1wLlhIVE1MRW50aXRpZXNbdV0pfXJldHVybiB0fSx0LnByb3RvdHlwZS5sZXhKU1g9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnNjYW5uZXIuc291cmNlLmNoYXJDb2RlQXQodGhpcy5zY2FubmVyLmluZGV4KTtpZig2MD09PWV8fDYyPT09ZXx8NDc9PT1lfHw1OD09PWV8fDYxPT09ZXx8MTIzPT09ZXx8MTI1PT09ZSl7dmFyIHQ9dGhpcy5zY2FubmVyLnNvdXJjZVt0aGlzLnNjYW5uZXIuaW5kZXgrK107cmV0dXJue3R5cGU6Nyx2YWx1ZTp0LGxpbmVOdW1iZXI6dGhpcy5zY2FubmVyLmxpbmVOdW1iZXIsbGluZVN0YXJ0OnRoaXMuc2Nhbm5lci5saW5lU3RhcnQsc3RhcnQ6dGhpcy5zY2FubmVyLmluZGV4LTEsZW5kOnRoaXMuc2Nhbm5lci5pbmRleH19aWYoMzQ9PT1lfHwzOT09PWUpe2Zvcih2YXIgbj10aGlzLnNjYW5uZXIuaW5kZXgscj10aGlzLnNjYW5uZXIuc291cmNlW3RoaXMuc2Nhbm5lci5pbmRleCsrXSxpPSIiOyF0aGlzLnNjYW5uZXIuZW9mKCk7KXt2YXIgYT10aGlzLnNjYW5uZXIuc291cmNlW3RoaXMuc2Nhbm5lci5pbmRleCsrXTtpZihhPT09cilicmVhaztpKz0iJiI9PT1hP3RoaXMuc2NhblhIVE1MRW50aXR5KHIpOmF9cmV0dXJue3R5cGU6OCx2YWx1ZTppLGxpbmVOdW1iZXI6dGhpcy5zY2FubmVyLmxpbmVOdW1iZXIsbGluZVN0YXJ0OnRoaXMuc2Nhbm5lci5saW5lU3RhcnQsc3RhcnQ6bixlbmQ6dGhpcy5zY2FubmVyLmluZGV4fX1pZig0Nj09PWUpe3ZhciBzPXRoaXMuc2Nhbm5lci5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLnNjYW5uZXIuaW5kZXgrMSksdT10aGlzLnNjYW5uZXIuc291cmNlLmNoYXJDb2RlQXQodGhpcy5zY2FubmVyLmluZGV4KzIpLHQ9NDY9PT1zJiY0Nj09PXU/Ii4uLiI6Ii4iLG49dGhpcy5zY2FubmVyLmluZGV4O3JldHVybiB0aGlzLnNjYW5uZXIuaW5kZXgrPXQubGVuZ3RoLHt0eXBlOjcsdmFsdWU6dCxsaW5lTnVtYmVyOnRoaXMuc2Nhbm5lci5saW5lTnVtYmVyLGxpbmVTdGFydDp0aGlzLnNjYW5uZXIubGluZVN0YXJ0LHN0YXJ0Om4sZW5kOnRoaXMuc2Nhbm5lci5pbmRleH19aWYoOTY9PT1lKXJldHVybnt0eXBlOjEwLHZhbHVlOiIiLGxpbmVOdW1iZXI6dGhpcy5zY2FubmVyLmxpbmVOdW1iZXIsbGluZVN0YXJ0OnRoaXMuc2Nhbm5lci5saW5lU3RhcnQsc3RhcnQ6dGhpcy5zY2FubmVyLmluZGV4LGVuZDp0aGlzLnNjYW5uZXIuaW5kZXh9O2lmKG8uQ2hhcmFjdGVyLmlzSWRlbnRpZmllclN0YXJ0KGUpJiY5MiE9PWUpe3ZhciBuPXRoaXMuc2Nhbm5lci5pbmRleDtmb3IoKyt0aGlzLnNjYW5uZXIuaW5kZXg7IXRoaXMuc2Nhbm5lci5lb2YoKTspe3ZhciBhPXRoaXMuc2Nhbm5lci5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLnNjYW5uZXIuaW5kZXgpO2lmKG8uQ2hhcmFjdGVyLmlzSWRlbnRpZmllclBhcnQoYSkmJjkyIT09YSkrK3RoaXMuc2Nhbm5lci5pbmRleDtlbHNle2lmKDQ1IT09YSlicmVhazsrK3RoaXMuc2Nhbm5lci5pbmRleH19cmV0dXJue3R5cGU6MTAwLHZhbHVlOnRoaXMuc2Nhbm5lci5zb3VyY2Uuc2xpY2Uobix0aGlzLnNjYW5uZXIuaW5kZXgpLGxpbmVOdW1iZXI6dGhpcy5zY2FubmVyLmxpbmVOdW1iZXIsbGluZVN0YXJ0OnRoaXMuc2Nhbm5lci5saW5lU3RhcnQsc3RhcnQ6bixlbmQ6dGhpcy5zY2FubmVyLmluZGV4fX1yZXR1cm4gdGhpcy5zY2FubmVyLmxleCgpfSx0LnByb3RvdHlwZS5uZXh0SlNYVG9rZW49ZnVuY3Rpb24oKXt0aGlzLmNvbGxlY3RDb21tZW50cygpLHRoaXMuc3RhcnRNYXJrZXIuaW5kZXg9dGhpcy5zY2FubmVyLmluZGV4LHRoaXMuc3RhcnRNYXJrZXIubGluZT10aGlzLnNjYW5uZXIubGluZU51bWJlcix0aGlzLnN0YXJ0TWFya2VyLmNvbHVtbj10aGlzLnNjYW5uZXIuaW5kZXgtdGhpcy5zY2FubmVyLmxpbmVTdGFydDt2YXIgZT10aGlzLmxleEpTWCgpO3JldHVybiB0aGlzLmxhc3RNYXJrZXIuaW5kZXg9dGhpcy5zY2FubmVyLmluZGV4LHRoaXMubGFzdE1hcmtlci5saW5lPXRoaXMuc2Nhbm5lci5saW5lTnVtYmVyLHRoaXMubGFzdE1hcmtlci5jb2x1bW49dGhpcy5zY2FubmVyLmluZGV4LXRoaXMuc2Nhbm5lci5saW5lU3RhcnQsdGhpcy5jb25maWcudG9rZW5zJiZ0aGlzLnRva2Vucy5wdXNoKHRoaXMuY29udmVydFRva2VuKGUpKSxlfSx0LnByb3RvdHlwZS5uZXh0SlNYVGV4dD1mdW5jdGlvbigpe3RoaXMuc3RhcnRNYXJrZXIuaW5kZXg9dGhpcy5zY2FubmVyLmluZGV4LHRoaXMuc3RhcnRNYXJrZXIubGluZT10aGlzLnNjYW5uZXIubGluZU51bWJlcix0aGlzLnN0YXJ0TWFya2VyLmNvbHVtbj10aGlzLnNjYW5uZXIuaW5kZXgtdGhpcy5zY2FubmVyLmxpbmVTdGFydDtmb3IodmFyIGU9dGhpcy5zY2FubmVyLmluZGV4LHQ9IiI7IXRoaXMuc2Nhbm5lci5lb2YoKTspe3ZhciBuPXRoaXMuc2Nhbm5lci5zb3VyY2VbdGhpcy5zY2FubmVyLmluZGV4XTtpZigieyI9PT1ufHwiPCI9PT1uKWJyZWFrOysrdGhpcy5zY2FubmVyLmluZGV4LHQrPW4sby5DaGFyYWN0ZXIuaXNMaW5lVGVybWluYXRvcihuLmNoYXJDb2RlQXQoMCkpJiYoKyt0aGlzLnNjYW5uZXIubGluZU51bWJlciwiXHIiPT09biYmIlxuIj09PXRoaXMuc2Nhbm5lci5zb3VyY2VbdGhpcy5zY2FubmVyLmluZGV4XSYmKyt0aGlzLnNjYW5uZXIuaW5kZXgsdGhpcy5zY2FubmVyLmxpbmVTdGFydD10aGlzLnNjYW5uZXIuaW5kZXgpfXRoaXMubGFzdE1hcmtlci5pbmRleD10aGlzLnNjYW5uZXIuaW5kZXgsdGhpcy5sYXN0TWFya2VyLmxpbmU9dGhpcy5zY2FubmVyLmxpbmVOdW1iZXIsdGhpcy5sYXN0TWFya2VyLmNvbHVtbj10aGlzLnNjYW5uZXIuaW5kZXgtdGhpcy5zY2FubmVyLmxpbmVTdGFydDt2YXIgcj17dHlwZToxMDEsdmFsdWU6dCxsaW5lTnVtYmVyOnRoaXMuc2Nhbm5lci5saW5lTnVtYmVyLGxpbmVTdGFydDp0aGlzLnNjYW5uZXIubGluZVN0YXJ0LHN0YXJ0OmUsZW5kOnRoaXMuc2Nhbm5lci5pbmRleH07cmV0dXJuIHQubGVuZ3RoPjAmJnRoaXMuY29uZmlnLnRva2VucyYmdGhpcy50b2tlbnMucHVzaCh0aGlzLmNvbnZlcnRUb2tlbihyKSkscn0sdC5wcm90b3R5cGUucGVla0pTWFRva2VuPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5zY2FubmVyLnNhdmVTdGF0ZSgpO3RoaXMuc2Nhbm5lci5zY2FuQ29tbWVudHMoKTt2YXIgdD10aGlzLmxleEpTWCgpO3JldHVybiB0aGlzLnNjYW5uZXIucmVzdG9yZVN0YXRlKGUpLHR9LHQucHJvdG90eXBlLmV4cGVjdEpTWD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLm5leHRKU1hUb2tlbigpOzc9PT10LnR5cGUmJnQudmFsdWU9PT1lfHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHQpfSx0LnByb3RvdHlwZS5tYXRjaEpTWD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLnBlZWtKU1hUb2tlbigpO3JldHVybiA3PT09dC50eXBlJiZ0LnZhbHVlPT09ZX0sdC5wcm90b3R5cGUucGFyc2VKU1hJZGVudGlmaWVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVKU1hOb2RlKCksdD10aGlzLm5leHRKU1hUb2tlbigpO3JldHVybiAxMDAhPT10LnR5cGUmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odCksdGhpcy5maW5hbGl6ZShlLG5ldyBhLkpTWElkZW50aWZpZXIodC52YWx1ZSkpfSx0LnByb3RvdHlwZS5wYXJzZUpTWEVsZW1lbnROYW1lPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVKU1hOb2RlKCksdD10aGlzLnBhcnNlSlNYSWRlbnRpZmllcigpO2lmKHRoaXMubWF0Y2hKU1goIjoiKSl7dmFyIG49dDt0aGlzLmV4cGVjdEpTWCgiOiIpO3ZhciByPXRoaXMucGFyc2VKU1hJZGVudGlmaWVyKCk7dD10aGlzLmZpbmFsaXplKGUsbmV3IGEuSlNYTmFtZXNwYWNlZE5hbWUobixyKSl9ZWxzZSBpZih0aGlzLm1hdGNoSlNYKCIuIikpZm9yKDt0aGlzLm1hdGNoSlNYKCIuIik7KXt2YXIgaT10O3RoaXMuZXhwZWN0SlNYKCIuIik7dmFyIG89dGhpcy5wYXJzZUpTWElkZW50aWZpZXIoKTt0PXRoaXMuZmluYWxpemUoZSxuZXcgYS5KU1hNZW1iZXJFeHByZXNzaW9uKGksbykpfXJldHVybiB0fSx0LnByb3RvdHlwZS5wYXJzZUpTWEF0dHJpYnV0ZU5hbWU9ZnVuY3Rpb24oKXt2YXIgZSx0PXRoaXMuY3JlYXRlSlNYTm9kZSgpLG49dGhpcy5wYXJzZUpTWElkZW50aWZpZXIoKTtpZih0aGlzLm1hdGNoSlNYKCI6Iikpe3ZhciByPW47dGhpcy5leHBlY3RKU1goIjoiKTt2YXIgaT10aGlzLnBhcnNlSlNYSWRlbnRpZmllcigpO2U9dGhpcy5maW5hbGl6ZSh0LG5ldyBhLkpTWE5hbWVzcGFjZWROYW1lKHIsaSkpfWVsc2UgZT1uO3JldHVybiBlfSx0LnByb3RvdHlwZS5wYXJzZUpTWFN0cmluZ0xpdGVyYWxBdHRyaWJ1dGU9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZUpTWE5vZGUoKSx0PXRoaXMubmV4dEpTWFRva2VuKCk7OCE9PXQudHlwZSYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0KTt2YXIgbj10aGlzLmdldFRva2VuUmF3KHQpO3JldHVybiB0aGlzLmZpbmFsaXplKGUsbmV3IHUuTGl0ZXJhbCh0LnZhbHVlLG4pKX0sdC5wcm90b3R5cGUucGFyc2VKU1hFeHByZXNzaW9uQXR0cmlidXRlPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVKU1hOb2RlKCk7dGhpcy5leHBlY3RKU1goInsiKSx0aGlzLmZpbmlzaEpTWCgpLHRoaXMubWF0Y2goIn0iKSYmdGhpcy50b2xlcmF0ZUVycm9yKCJKU1ggYXR0cmlidXRlcyBtdXN0IG9ubHkgYmUgYXNzaWduZWQgYSBub24tZW1wdHkgZXhwcmVzc2lvbiIpO3ZhciB0PXRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbigpO3JldHVybiB0aGlzLnJlZW50ZXJKU1goKSx0aGlzLmZpbmFsaXplKGUsbmV3IGEuSlNYRXhwcmVzc2lvbkNvbnRhaW5lcih0KSl9LHQucHJvdG90eXBlLnBhcnNlSlNYQXR0cmlidXRlVmFsdWU9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5tYXRjaEpTWCgieyIpP3RoaXMucGFyc2VKU1hFeHByZXNzaW9uQXR0cmlidXRlKCk6dGhpcy5tYXRjaEpTWCgiPCIpP3RoaXMucGFyc2VKU1hFbGVtZW50KCk6dGhpcy5wYXJzZUpTWFN0cmluZ0xpdGVyYWxBdHRyaWJ1dGUoKX0sdC5wcm90b3R5cGUucGFyc2VKU1hOYW1lVmFsdWVBdHRyaWJ1dGU9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZUpTWE5vZGUoKSx0PXRoaXMucGFyc2VKU1hBdHRyaWJ1dGVOYW1lKCksbj1udWxsO3JldHVybiB0aGlzLm1hdGNoSlNYKCI9IikmJih0aGlzLmV4cGVjdEpTWCgiPSIpLG49dGhpcy5wYXJzZUpTWEF0dHJpYnV0ZVZhbHVlKCkpLHRoaXMuZmluYWxpemUoZSxuZXcgYS5KU1hBdHRyaWJ1dGUodCxuKSl9LHQucHJvdG90eXBlLnBhcnNlSlNYU3ByZWFkQXR0cmlidXRlPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVKU1hOb2RlKCk7dGhpcy5leHBlY3RKU1goInsiKSx0aGlzLmV4cGVjdEpTWCgiLi4uIiksdGhpcy5maW5pc2hKU1goKTt2YXIgdD10aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24oKTtyZXR1cm4gdGhpcy5yZWVudGVySlNYKCksdGhpcy5maW5hbGl6ZShlLG5ldyBhLkpTWFNwcmVhZEF0dHJpYnV0ZSh0KSl9LHQucHJvdG90eXBlLnBhcnNlSlNYQXR0cmlidXRlcz1mdW5jdGlvbigpe2Zvcih2YXIgZT1bXTshdGhpcy5tYXRjaEpTWCgiLyIpJiYhdGhpcy5tYXRjaEpTWCgiPiIpOyl7dmFyIHQ9dGhpcy5tYXRjaEpTWCgieyIpP3RoaXMucGFyc2VKU1hTcHJlYWRBdHRyaWJ1dGUoKTp0aGlzLnBhcnNlSlNYTmFtZVZhbHVlQXR0cmlidXRlKCk7ZS5wdXNoKHQpfXJldHVybiBlfSx0LnByb3RvdHlwZS5wYXJzZUpTWE9wZW5pbmdFbGVtZW50PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVKU1hOb2RlKCk7dGhpcy5leHBlY3RKU1goIjwiKTt2YXIgdD10aGlzLnBhcnNlSlNYRWxlbWVudE5hbWUoKSxuPXRoaXMucGFyc2VKU1hBdHRyaWJ1dGVzKCkscj10aGlzLm1hdGNoSlNYKCIvIik7cmV0dXJuIHImJnRoaXMuZXhwZWN0SlNYKCIvIiksdGhpcy5leHBlY3RKU1goIj4iKSx0aGlzLmZpbmFsaXplKGUsbmV3IGEuSlNYT3BlbmluZ0VsZW1lbnQodCxyLG4pKX0sdC5wcm90b3R5cGUucGFyc2VKU1hCb3VuZGFyeUVsZW1lbnQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZUpTWE5vZGUoKTtpZih0aGlzLmV4cGVjdEpTWCgiPCIpLHRoaXMubWF0Y2hKU1goIi8iKSl7dGhpcy5leHBlY3RKU1goIi8iKTt2YXIgdD10aGlzLnBhcnNlSlNYRWxlbWVudE5hbWUoKTtyZXR1cm4gdGhpcy5leHBlY3RKU1goIj4iKSx0aGlzLmZpbmFsaXplKGUsbmV3IGEuSlNYQ2xvc2luZ0VsZW1lbnQodCkpfXZhciBuPXRoaXMucGFyc2VKU1hFbGVtZW50TmFtZSgpLHI9dGhpcy5wYXJzZUpTWEF0dHJpYnV0ZXMoKSxpPXRoaXMubWF0Y2hKU1goIi8iKTtyZXR1cm4gaSYmdGhpcy5leHBlY3RKU1goIi8iKSx0aGlzLmV4cGVjdEpTWCgiPiIpLHRoaXMuZmluYWxpemUoZSxuZXcgYS5KU1hPcGVuaW5nRWxlbWVudChuLGkscikpfSx0LnByb3RvdHlwZS5wYXJzZUpTWEVtcHR5RXhwcmVzc2lvbj1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlSlNYQ2hpbGROb2RlKCk7cmV0dXJuIHRoaXMuY29sbGVjdENvbW1lbnRzKCksdGhpcy5sYXN0TWFya2VyLmluZGV4PXRoaXMuc2Nhbm5lci5pbmRleCx0aGlzLmxhc3RNYXJrZXIubGluZT10aGlzLnNjYW5uZXIubGluZU51bWJlcix0aGlzLmxhc3RNYXJrZXIuY29sdW1uPXRoaXMuc2Nhbm5lci5pbmRleC10aGlzLnNjYW5uZXIubGluZVN0YXJ0LHRoaXMuZmluYWxpemUoZSxuZXcgYS5KU1hFbXB0eUV4cHJlc3Npb24pfSx0LnByb3RvdHlwZS5wYXJzZUpTWEV4cHJlc3Npb25Db250YWluZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZUpTWE5vZGUoKTt0aGlzLmV4cGVjdEpTWCgieyIpO3ZhciB0O3JldHVybiB0aGlzLm1hdGNoSlNYKCJ9Iik/KHQ9dGhpcy5wYXJzZUpTWEVtcHR5RXhwcmVzc2lvbigpLHRoaXMuZXhwZWN0SlNYKCJ9IikpOih0aGlzLmZpbmlzaEpTWCgpLHQ9dGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKCksdGhpcy5yZWVudGVySlNYKCkpLHRoaXMuZmluYWxpemUoZSxuZXcgYS5KU1hFeHByZXNzaW9uQ29udGFpbmVyKHQpKX0sdC5wcm90b3R5cGUucGFyc2VKU1hDaGlsZHJlbj1mdW5jdGlvbigpe2Zvcih2YXIgZT1bXTshdGhpcy5zY2FubmVyLmVvZigpOyl7dmFyIHQ9dGhpcy5jcmVhdGVKU1hDaGlsZE5vZGUoKSxuPXRoaXMubmV4dEpTWFRleHQoKTtpZihuLnN0YXJ0PG4uZW5kKXt2YXIgcj10aGlzLmdldFRva2VuUmF3KG4pLGk9dGhpcy5maW5hbGl6ZSh0LG5ldyBhLkpTWFRleHQobi52YWx1ZSxyKSk7ZS5wdXNoKGkpfWlmKCJ7IiE9PXRoaXMuc2Nhbm5lci5zb3VyY2VbdGhpcy5zY2FubmVyLmluZGV4XSlicmVhazt2YXIgbz10aGlzLnBhcnNlSlNYRXhwcmVzc2lvbkNvbnRhaW5lcigpO2UucHVzaChvKX1yZXR1cm4gZX0sdC5wcm90b3R5cGUucGFyc2VDb21wbGV4SlNYRWxlbWVudD1mdW5jdGlvbihlKXtmb3IodmFyIHQ9W107IXRoaXMuc2Nhbm5lci5lb2YoKTspe2UuY2hpbGRyZW49ZS5jaGlsZHJlbi5jb25jYXQodGhpcy5wYXJzZUpTWENoaWxkcmVuKCkpO3ZhciBuPXRoaXMuY3JlYXRlSlNYQ2hpbGROb2RlKCksaT10aGlzLnBhcnNlSlNYQm91bmRhcnlFbGVtZW50KCk7aWYoaS50eXBlPT09cy5KU1hTeW50YXguSlNYT3BlbmluZ0VsZW1lbnQpe3ZhciBvPWk7aWYoby5zZWxmQ2xvc2luZyl7dmFyIHU9dGhpcy5maW5hbGl6ZShuLG5ldyBhLkpTWEVsZW1lbnQobyxbXSxudWxsKSk7ZS5jaGlsZHJlbi5wdXNoKHUpfWVsc2UgdC5wdXNoKGUpLGU9e25vZGU6bixvcGVuaW5nOm8sY2xvc2luZzpudWxsLGNoaWxkcmVuOltdfX1pZihpLnR5cGU9PT1zLkpTWFN5bnRheC5KU1hDbG9zaW5nRWxlbWVudCl7ZS5jbG9zaW5nPWk7dmFyIGM9cihlLm9wZW5pbmcubmFtZSk7aWYoYyE9PXIoZS5jbG9zaW5nLm5hbWUpJiZ0aGlzLnRvbGVyYXRlRXJyb3IoIkV4cGVjdGVkIGNvcnJlc3BvbmRpbmcgSlNYIGNsb3NpbmcgdGFnIGZvciAlMCIsYyksISh0Lmxlbmd0aD4wKSlicmVhazt2YXIgdT10aGlzLmZpbmFsaXplKGUubm9kZSxuZXcgYS5KU1hFbGVtZW50KGUub3BlbmluZyxlLmNoaWxkcmVuLGUuY2xvc2luZykpO2U9dFt0Lmxlbmd0aC0xXSxlLmNoaWxkcmVuLnB1c2godSksdC5wb3AoKX19cmV0dXJuIGV9LHQucHJvdG90eXBlLnBhcnNlSlNYRWxlbWVudD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlSlNYTm9kZSgpLHQ9dGhpcy5wYXJzZUpTWE9wZW5pbmdFbGVtZW50KCksbj1bXSxyPW51bGw7aWYoIXQuc2VsZkNsb3Npbmcpe3ZhciBpPXRoaXMucGFyc2VDb21wbGV4SlNYRWxlbWVudCh7bm9kZTplLG9wZW5pbmc6dCxjbG9zaW5nOnIsY2hpbGRyZW46bn0pO249aS5jaGlsZHJlbixyPWkuY2xvc2luZ31yZXR1cm4gdGhpcy5maW5hbGl6ZShlLG5ldyBhLkpTWEVsZW1lbnQodCxuLHIpKX0sdC5wcm90b3R5cGUucGFyc2VKU1hSb290PWZ1bmN0aW9uKCl7dGhpcy5jb25maWcudG9rZW5zJiZ0aGlzLnRva2Vucy5wb3AoKSx0aGlzLnN0YXJ0SlNYKCk7dmFyIGU9dGhpcy5wYXJzZUpTWEVsZW1lbnQoKTtyZXR1cm4gdGhpcy5maW5pc2hKU1goKSxlfSx0LnByb3RvdHlwZS5pc1N0YXJ0T2ZFeHByZXNzaW9uPWZ1bmN0aW9uKCl7cmV0dXJuIGUucHJvdG90eXBlLmlzU3RhcnRPZkV4cHJlc3Npb24uY2FsbCh0aGlzKXx8dGhpcy5tYXRjaCgiPCIpfSx0fShjLlBhcnNlcik7dC5KU1hQYXJzZXI9Zn0sZnVuY3Rpb24oZSx0KXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBuPXtOb25Bc2NpaUlkZW50aWZpZXJTdGFydDovW1x4QUFceEI1XHhCQVx4QzAtXHhENlx4RDgtXHhGNlx4RjgtXHUwMkMxXHUwMkM2LVx1MDJEMVx1MDJFMC1cdTAyRTRcdTAyRUNcdTAyRUVcdTAzNzAtXHUwMzc0XHUwMzc2XHUwMzc3XHUwMzdBLVx1MDM3RFx1MDM3Rlx1MDM4Nlx1MDM4OC1cdTAzOEFcdTAzOENcdTAzOEUtXHUwM0ExXHUwM0EzLVx1MDNGNVx1MDNGNy1cdTA0ODFcdTA0OEEtXHUwNTJGXHUwNTMxLVx1MDU1Nlx1MDU1OVx1MDU2MS1cdTA1ODdcdTA1RDAtXHUwNUVBXHUwNUYwLVx1MDVGMlx1MDYyMC1cdTA2NEFcdTA2NkVcdTA2NkZcdTA2NzEtXHUwNkQzXHUwNkQ1XHUwNkU1XHUwNkU2XHUwNkVFXHUwNkVGXHUwNkZBLVx1MDZGQ1x1MDZGRlx1MDcxMFx1MDcxMi1cdTA3MkZcdTA3NEQtXHUwN0E1XHUwN0IxXHUwN0NBLVx1MDdFQVx1MDdGNFx1MDdGNVx1MDdGQVx1MDgwMC1cdTA4MTVcdTA4MUFcdTA4MjRcdTA4MjhcdTA4NDAtXHUwODU4XHUwOEEwLVx1MDhCNFx1MDkwNC1cdTA5MzlcdTA5M0RcdTA5NTBcdTA5NTgtXHUwOTYxXHUwOTcxLVx1MDk4MFx1MDk4NS1cdTA5OENcdTA5OEZcdTA5OTBcdTA5OTMtXHUwOUE4XHUwOUFBLVx1MDlCMFx1MDlCMlx1MDlCNi1cdTA5QjlcdTA5QkRcdTA5Q0VcdTA5RENcdTA5RERcdTA5REYtXHUwOUUxXHUwOUYwXHUwOUYxXHUwQTA1LVx1MEEwQVx1MEEwRlx1MEExMFx1MEExMy1cdTBBMjhcdTBBMkEtXHUwQTMwXHUwQTMyXHUwQTMzXHUwQTM1XHUwQTM2XHUwQTM4XHUwQTM5XHUwQTU5LVx1MEE1Q1x1MEE1RVx1MEE3Mi1cdTBBNzRcdTBBODUtXHUwQThEXHUwQThGLVx1MEE5MVx1MEE5My1cdTBBQThcdTBBQUEtXHUwQUIwXHUwQUIyXHUwQUIzXHUwQUI1LVx1MEFCOVx1MEFCRFx1MEFEMFx1MEFFMFx1MEFFMVx1MEFGOVx1MEIwNS1cdTBCMENcdTBCMEZcdTBCMTBcdTBCMTMtXHUwQjI4XHUwQjJBLVx1MEIzMFx1MEIzMlx1MEIzM1x1MEIzNS1cdTBCMzlcdTBCM0RcdTBCNUNcdTBCNURcdTBCNUYtXHUwQjYxXHUwQjcxXHUwQjgzXHUwQjg1LVx1MEI4QVx1MEI4RS1cdTBCOTBcdTBCOTItXHUwQjk1XHUwQjk5XHUwQjlBXHUwQjlDXHUwQjlFXHUwQjlGXHUwQkEzXHUwQkE0XHUwQkE4LVx1MEJBQVx1MEJBRS1cdTBCQjlcdTBCRDBcdTBDMDUtXHUwQzBDXHUwQzBFLVx1MEMxMFx1MEMxMi1cdTBDMjhcdTBDMkEtXHUwQzM5XHUwQzNEXHUwQzU4LVx1MEM1QVx1MEM2MFx1MEM2MVx1MEM4NS1cdTBDOENcdTBDOEUtXHUwQzkwXHUwQzkyLVx1MENBOFx1MENBQS1cdTBDQjNcdTBDQjUtXHUwQ0I5XHUwQ0JEXHUwQ0RFXHUwQ0UwXHUwQ0UxXHUwQ0YxXHUwQ0YyXHUwRDA1LVx1MEQwQ1x1MEQwRS1cdTBEMTBcdTBEMTItXHUwRDNBXHUwRDNEXHUwRDRFXHUwRDVGLVx1MEQ2MVx1MEQ3QS1cdTBEN0ZcdTBEODUtXHUwRDk2XHUwRDlBLVx1MERCMVx1MERCMy1cdTBEQkJcdTBEQkRcdTBEQzAtXHUwREM2XHUwRTAxLVx1MEUzMFx1MEUzMlx1MEUzM1x1MEU0MC1cdTBFNDZcdTBFODFcdTBFODJcdTBFODRcdTBFODdcdTBFODhcdTBFOEFcdTBFOERcdTBFOTQtXHUwRTk3XHUwRTk5LVx1MEU5Rlx1MEVBMS1cdTBFQTNcdTBFQTVcdTBFQTdcdTBFQUFcdTBFQUJcdTBFQUQtXHUwRUIwXHUwRUIyXHUwRUIzXHUwRUJEXHUwRUMwLVx1MEVDNFx1MEVDNlx1MEVEQy1cdTBFREZcdTBGMDBcdTBGNDAtXHUwRjQ3XHUwRjQ5LVx1MEY2Q1x1MEY4OC1cdTBGOENcdTEwMDAtXHUxMDJBXHUxMDNGXHUxMDUwLVx1MTA1NVx1MTA1QS1cdTEwNURcdTEwNjFcdTEwNjVcdTEwNjZcdTEwNkUtXHUxMDcwXHUxMDc1LVx1MTA4MVx1MTA4RVx1MTBBMC1cdTEwQzVcdTEwQzdcdTEwQ0RcdTEwRDAtXHUxMEZBXHUxMEZDLVx1MTI0OFx1MTI0QS1cdTEyNERcdTEyNTAtXHUxMjU2XHUxMjU4XHUxMjVBLVx1MTI1RFx1MTI2MC1cdTEyODhcdTEyOEEtXHUxMjhEXHUxMjkwLVx1MTJCMFx1MTJCMi1cdTEyQjVcdTEyQjgtXHUxMkJFXHUxMkMwXHUxMkMyLVx1MTJDNVx1MTJDOC1cdTEyRDZcdTEyRDgtXHUxMzEwXHUxMzEyLVx1MTMxNVx1MTMxOC1cdTEzNUFcdTEzODAtXHUxMzhGXHUxM0EwLVx1MTNGNVx1MTNGOC1cdTEzRkRcdTE0MDEtXHUxNjZDXHUxNjZGLVx1MTY3Rlx1MTY4MS1cdTE2OUFcdTE2QTAtXHUxNkVBXHUxNkVFLVx1MTZGOFx1MTcwMC1cdTE3MENcdTE3MEUtXHUxNzExXHUxNzIwLVx1MTczMVx1MTc0MC1cdTE3NTFcdTE3NjAtXHUxNzZDXHUxNzZFLVx1MTc3MFx1MTc4MC1cdTE3QjNcdTE3RDdcdTE3RENcdTE4MjAtXHUxODc3XHUxODgwLVx1MThBOFx1MThBQVx1MThCMC1cdTE4RjVcdTE5MDAtXHUxOTFFXHUxOTUwLVx1MTk2RFx1MTk3MC1cdTE5NzRcdTE5ODAtXHUxOUFCXHUxOUIwLVx1MTlDOVx1MUEwMC1cdTFBMTZcdTFBMjAtXHUxQTU0XHUxQUE3XHUxQjA1LVx1MUIzM1x1MUI0NS1cdTFCNEJcdTFCODMtXHUxQkEwXHUxQkFFXHUxQkFGXHUxQkJBLVx1MUJFNVx1MUMwMC1cdTFDMjNcdTFDNEQtXHUxQzRGXHUxQzVBLVx1MUM3RFx1MUNFOS1cdTFDRUNcdTFDRUUtXHUxQ0YxXHUxQ0Y1XHUxQ0Y2XHUxRDAwLVx1MURCRlx1MUUwMC1cdTFGMTVcdTFGMTgtXHUxRjFEXHUxRjIwLVx1MUY0NVx1MUY0OC1cdTFGNERcdTFGNTAtXHUxRjU3XHUxRjU5XHUxRjVCXHUxRjVEXHUxRjVGLVx1MUY3RFx1MUY4MC1cdTFGQjRcdTFGQjYtXHUxRkJDXHUxRkJFXHUxRkMyLVx1MUZDNFx1MUZDNi1cdTFGQ0NcdTFGRDAtXHUxRkQzXHUxRkQ2LVx1MUZEQlx1MUZFMC1cdTFGRUNcdTFGRjItXHUxRkY0XHUxRkY2LVx1MUZGQ1x1MjA3MVx1MjA3Rlx1MjA5MC1cdTIwOUNcdTIxMDJcdTIxMDdcdTIxMEEtXHUyMTEzXHUyMTE1XHUyMTE4LVx1MjExRFx1MjEyNFx1MjEyNlx1MjEyOFx1MjEyQS1cdTIxMzlcdTIxM0MtXHUyMTNGXHUyMTQ1LVx1MjE0OVx1MjE0RVx1MjE2MC1cdTIxODhcdTJDMDAtXHUyQzJFXHUyQzMwLVx1MkM1RVx1MkM2MC1cdTJDRTRcdTJDRUItXHUyQ0VFXHUyQ0YyXHUyQ0YzXHUyRDAwLVx1MkQyNVx1MkQyN1x1MkQyRFx1MkQzMC1cdTJENjdcdTJENkZcdTJEODAtXHUyRDk2XHUyREEwLVx1MkRBNlx1MkRBOC1cdTJEQUVcdTJEQjAtXHUyREI2XHUyREI4LVx1MkRCRVx1MkRDMC1cdTJEQzZcdTJEQzgtXHUyRENFXHUyREQwLVx1MkRENlx1MkREOC1cdTJEREVcdTMwMDUtXHUzMDA3XHUzMDIxLVx1MzAyOVx1MzAzMS1cdTMwMzVcdTMwMzgtXHUzMDNDXHUzMDQxLVx1MzA5Nlx1MzA5Qi1cdTMwOUZcdTMwQTEtXHUzMEZBXHUzMEZDLVx1MzBGRlx1MzEwNS1cdTMxMkRcdTMxMzEtXHUzMThFXHUzMUEwLVx1MzFCQVx1MzFGMC1cdTMxRkZcdTM0MDAtXHU0REI1XHU0RTAwLVx1OUZENVx1QTAwMC1cdUE0OENcdUE0RDAtXHVBNEZEXHVBNTAwLVx1QTYwQ1x1QTYxMC1cdUE2MUZcdUE2MkFcdUE2MkJcdUE2NDAtXHVBNjZFXHVBNjdGLVx1QTY5RFx1QTZBMC1cdUE2RUZcdUE3MTctXHVBNzFGXHVBNzIyLVx1QTc4OFx1QTc4Qi1cdUE3QURcdUE3QjAtXHVBN0I3XHVBN0Y3LVx1QTgwMVx1QTgwMy1cdUE4MDVcdUE4MDctXHVBODBBXHVBODBDLVx1QTgyMlx1QTg0MC1cdUE4NzNcdUE4ODItXHVBOEIzXHVBOEYyLVx1QThGN1x1QThGQlx1QThGRFx1QTkwQS1cdUE5MjVcdUE5MzAtXHVBOTQ2XHVBOTYwLVx1QTk3Q1x1QTk4NC1cdUE5QjJcdUE5Q0ZcdUE5RTAtXHVBOUU0XHVBOUU2LVx1QTlFRlx1QTlGQS1cdUE5RkVcdUFBMDAtXHVBQTI4XHVBQTQwLVx1QUE0Mlx1QUE0NC1cdUFBNEJcdUFBNjAtXHVBQTc2XHVBQTdBXHVBQTdFLVx1QUFBRlx1QUFCMVx1QUFCNVx1QUFCNlx1QUFCOS1cdUFBQkRcdUFBQzBcdUFBQzJcdUFBREItXHVBQUREXHVBQUUwLVx1QUFFQVx1QUFGMi1cdUFBRjRcdUFCMDEtXHVBQjA2XHVBQjA5LVx1QUIwRVx1QUIxMS1cdUFCMTZcdUFCMjAtXHVBQjI2XHVBQjI4LVx1QUIyRVx1QUIzMC1cdUFCNUFcdUFCNUMtXHVBQjY1XHVBQjcwLVx1QUJFMlx1QUMwMC1cdUQ3QTNcdUQ3QjAtXHVEN0M2XHVEN0NCLVx1RDdGQlx1RjkwMC1cdUZBNkRcdUZBNzAtXHVGQUQ5XHVGQjAwLVx1RkIwNlx1RkIxMy1cdUZCMTdcdUZCMURcdUZCMUYtXHVGQjI4XHVGQjJBLVx1RkIzNlx1RkIzOC1cdUZCM0NcdUZCM0VcdUZCNDBcdUZCNDFcdUZCNDNcdUZCNDRcdUZCNDYtXHVGQkIxXHVGQkQzLVx1RkQzRFx1RkQ1MC1cdUZEOEZcdUZEOTItXHVGREM3XHVGREYwLVx1RkRGQlx1RkU3MC1cdUZFNzRcdUZFNzYtXHVGRUZDXHVGRjIxLVx1RkYzQVx1RkY0MS1cdUZGNUFcdUZGNjYtXHVGRkJFXHVGRkMyLVx1RkZDN1x1RkZDQS1cdUZGQ0ZcdUZGRDItXHVGRkQ3XHVGRkRBLVx1RkZEQ118XHVEODAwW1x1REMwMC1cdURDMEJcdURDMEQtXHVEQzI2XHVEQzI4LVx1REMzQVx1REMzQ1x1REMzRFx1REMzRi1cdURDNERcdURDNTAtXHVEQzVEXHVEQzgwLVx1RENGQVx1REQ0MC1cdURENzRcdURFODAtXHVERTlDXHVERUEwLVx1REVEMFx1REYwMC1cdURGMUZcdURGMzAtXHVERjRBXHVERjUwLVx1REY3NVx1REY4MC1cdURGOURcdURGQTAtXHVERkMzXHVERkM4LVx1REZDRlx1REZEMS1cdURGRDVdfFx1RDgwMVtcdURDMDAtXHVEQzlEXHVERDAwLVx1REQyN1x1REQzMC1cdURENjNcdURFMDAtXHVERjM2XHVERjQwLVx1REY1NVx1REY2MC1cdURGNjddfFx1RDgwMltcdURDMDAtXHVEQzA1XHVEQzA4XHVEQzBBLVx1REMzNVx1REMzN1x1REMzOFx1REMzQ1x1REMzRi1cdURDNTVcdURDNjAtXHVEQzc2XHVEQzgwLVx1REM5RVx1RENFMC1cdURDRjJcdURDRjRcdURDRjVcdUREMDAtXHVERDE1XHVERDIwLVx1REQzOVx1REQ4MC1cdUREQjdcdUREQkVcdUREQkZcdURFMDBcdURFMTAtXHVERTEzXHVERTE1LVx1REUxN1x1REUxOS1cdURFMzNcdURFNjAtXHVERTdDXHVERTgwLVx1REU5Q1x1REVDMC1cdURFQzdcdURFQzktXHVERUU0XHVERjAwLVx1REYzNVx1REY0MC1cdURGNTVcdURGNjAtXHVERjcyXHVERjgwLVx1REY5MV18XHVEODAzW1x1REMwMC1cdURDNDhcdURDODAtXHVEQ0IyXHVEQ0MwLVx1RENGMl18XHVEODA0W1x1REMwMy1cdURDMzdcdURDODMtXHVEQ0FGXHVEQ0QwLVx1RENFOFx1REQwMy1cdUREMjZcdURENTAtXHVERDcyXHVERDc2XHVERDgzLVx1RERCMlx1RERDMS1cdUREQzRcdUREREFcdURERENcdURFMDAtXHVERTExXHVERTEzLVx1REUyQlx1REU4MC1cdURFODZcdURFODhcdURFOEEtXHVERThEXHVERThGLVx1REU5RFx1REU5Ri1cdURFQThcdURFQjAtXHVERURFXHVERjA1LVx1REYwQ1x1REYwRlx1REYxMFx1REYxMy1cdURGMjhcdURGMkEtXHVERjMwXHVERjMyXHVERjMzXHVERjM1LVx1REYzOVx1REYzRFx1REY1MFx1REY1RC1cdURGNjFdfFx1RDgwNVtcdURDODAtXHVEQ0FGXHVEQ0M0XHVEQ0M1XHVEQ0M3XHVERDgwLVx1RERBRVx1REREOC1cdUREREJcdURFMDAtXHVERTJGXHVERTQ0XHVERTgwLVx1REVBQVx1REYwMC1cdURGMTldfFx1RDgwNltcdURDQTAtXHVEQ0RGXHVEQ0ZGXHVERUMwLVx1REVGOF18XHVEODA4W1x1REMwMC1cdURGOTldfFx1RDgwOVtcdURDMDAtXHVEQzZFXHVEQzgwLVx1REQ0M118W1x1RDgwQ1x1RDg0MC1cdUQ4NjhcdUQ4NkEtXHVEODZDXHVEODZGLVx1RDg3Ml1bXHVEQzAwLVx1REZGRl18XHVEODBEW1x1REMwMC1cdURDMkVdfFx1RDgxMVtcdURDMDAtXHVERTQ2XXxcdUQ4MUFbXHVEQzAwLVx1REUzOFx1REU0MC1cdURFNUVcdURFRDAtXHVERUVEXHVERjAwLVx1REYyRlx1REY0MC1cdURGNDNcdURGNjMtXHVERjc3XHVERjdELVx1REY4Rl18XHVEODFCW1x1REYwMC1cdURGNDRcdURGNTBcdURGOTMtXHVERjlGXXxcdUQ4MkNbXHVEQzAwXHVEQzAxXXxcdUQ4MkZbXHVEQzAwLVx1REM2QVx1REM3MC1cdURDN0NcdURDODAtXHVEQzg4XHVEQzkwLVx1REM5OV18XHVEODM1W1x1REMwMC1cdURDNTRcdURDNTYtXHVEQzlDXHVEQzlFXHVEQzlGXHVEQ0EyXHVEQ0E1XHVEQ0E2XHVEQ0E5LVx1RENBQ1x1RENBRS1cdURDQjlcdURDQkJcdURDQkQtXHVEQ0MzXHVEQ0M1LVx1REQwNVx1REQwNy1cdUREMEFcdUREMEQtXHVERDE0XHVERDE2LVx1REQxQ1x1REQxRS1cdUREMzlcdUREM0ItXHVERDNFXHVERDQwLVx1REQ0NFx1REQ0Nlx1REQ0QS1cdURENTBcdURENTItXHVERUE1XHVERUE4LVx1REVDMFx1REVDMi1cdURFREFcdURFREMtXHVERUZBXHVERUZDLVx1REYxNFx1REYxNi1cdURGMzRcdURGMzYtXHVERjRFXHVERjUwLVx1REY2RVx1REY3MC1cdURGODhcdURGOEEtXHVERkE4XHVERkFBLVx1REZDMlx1REZDNC1cdURGQ0JdfFx1RDgzQVtcdURDMDAtXHVEQ0M0XXxcdUQ4M0JbXHVERTAwLVx1REUwM1x1REUwNS1cdURFMUZcdURFMjFcdURFMjJcdURFMjRcdURFMjdcdURFMjktXHVERTMyXHVERTM0LVx1REUzN1x1REUzOVx1REUzQlx1REU0Mlx1REU0N1x1REU0OVx1REU0Qlx1REU0RC1cdURFNEZcdURFNTFcdURFNTJcdURFNTRcdURFNTdcdURFNTlcdURFNUJcdURFNURcdURFNUZcdURFNjFcdURFNjJcdURFNjRcdURFNjctXHVERTZBXHVERTZDLVx1REU3Mlx1REU3NC1cdURFNzdcdURFNzktXHVERTdDXHVERTdFXHVERTgwLVx1REU4OVx1REU4Qi1cdURFOUJcdURFQTEtXHVERUEzXHVERUE1LVx1REVBOVx1REVBQi1cdURFQkJdfFx1RDg2OVtcdURDMDAtXHVERUQ2XHVERjAwLVx1REZGRl18XHVEODZEW1x1REMwMC1cdURGMzRcdURGNDAtXHVERkZGXXxcdUQ4NkVbXHVEQzAwLVx1REMxRFx1REMyMC1cdURGRkZdfFx1RDg3M1tcdURDMDAtXHVERUExXXxcdUQ4N0VbXHVEQzAwLVx1REUxRF0vLE5vbkFzY2lpSWRlbnRpZmllclBhcnQ6L1tceEFBXHhCNVx4QjdceEJBXHhDMC1ceEQ2XHhEOC1ceEY2XHhGOC1cdTAyQzFcdTAyQzYtXHUwMkQxXHUwMkUwLVx1MDJFNFx1MDJFQ1x1MDJFRVx1MDMwMC1cdTAzNzRcdTAzNzZcdTAzNzdcdTAzN0EtXHUwMzdEXHUwMzdGXHUwMzg2LVx1MDM4QVx1MDM4Q1x1MDM4RS1cdTAzQTFcdTAzQTMtXHUwM0Y1XHUwM0Y3LVx1MDQ4MVx1MDQ4My1cdTA0ODdcdTA0OEEtXHUwNTJGXHUwNTMxLVx1MDU1Nlx1MDU1OVx1MDU2MS1cdTA1ODdcdTA1OTEtXHUwNUJEXHUwNUJGXHUwNUMxXHUwNUMyXHUwNUM0XHUwNUM1XHUwNUM3XHUwNUQwLVx1MDVFQVx1MDVGMC1cdTA1RjJcdTA2MTAtXHUwNjFBXHUwNjIwLVx1MDY2OVx1MDY2RS1cdTA2RDNcdTA2RDUtXHUwNkRDXHUwNkRGLVx1MDZFOFx1MDZFQS1cdTA2RkNcdTA2RkZcdTA3MTAtXHUwNzRBXHUwNzRELVx1MDdCMVx1MDdDMC1cdTA3RjVcdTA3RkFcdTA4MDAtXHUwODJEXHUwODQwLVx1MDg1Qlx1MDhBMC1cdTA4QjRcdTA4RTMtXHUwOTYzXHUwOTY2LVx1MDk2Rlx1MDk3MS1cdTA5ODNcdTA5ODUtXHUwOThDXHUwOThGXHUwOTkwXHUwOTkzLVx1MDlBOFx1MDlBQS1cdTA5QjBcdTA5QjJcdTA5QjYtXHUwOUI5XHUwOUJDLVx1MDlDNFx1MDlDN1x1MDlDOFx1MDlDQi1cdTA5Q0VcdTA5RDdcdTA5RENcdTA5RERcdTA5REYtXHUwOUUzXHUwOUU2LVx1MDlGMVx1MEEwMS1cdTBBMDNcdTBBMDUtXHUwQTBBXHUwQTBGXHUwQTEwXHUwQTEzLVx1MEEyOFx1MEEyQS1cdTBBMzBcdTBBMzJcdTBBMzNcdTBBMzVcdTBBMzZcdTBBMzhcdTBBMzlcdTBBM0NcdTBBM0UtXHUwQTQyXHUwQTQ3XHUwQTQ4XHUwQTRCLVx1MEE0RFx1MEE1MVx1MEE1OS1cdTBBNUNcdTBBNUVcdTBBNjYtXHUwQTc1XHUwQTgxLVx1MEE4M1x1MEE4NS1cdTBBOERcdTBBOEYtXHUwQTkxXHUwQTkzLVx1MEFBOFx1MEFBQS1cdTBBQjBcdTBBQjJcdTBBQjNcdTBBQjUtXHUwQUI5XHUwQUJDLVx1MEFDNVx1MEFDNy1cdTBBQzlcdTBBQ0ItXHUwQUNEXHUwQUQwXHUwQUUwLVx1MEFFM1x1MEFFNi1cdTBBRUZcdTBBRjlcdTBCMDEtXHUwQjAzXHUwQjA1LVx1MEIwQ1x1MEIwRlx1MEIxMFx1MEIxMy1cdTBCMjhcdTBCMkEtXHUwQjMwXHUwQjMyXHUwQjMzXHUwQjM1LVx1MEIzOVx1MEIzQy1cdTBCNDRcdTBCNDdcdTBCNDhcdTBCNEItXHUwQjREXHUwQjU2XHUwQjU3XHUwQjVDXHUwQjVEXHUwQjVGLVx1MEI2M1x1MEI2Ni1cdTBCNkZcdTBCNzFcdTBCODJcdTBCODNcdTBCODUtXHUwQjhBXHUwQjhFLVx1MEI5MFx1MEI5Mi1cdTBCOTVcdTBCOTlcdTBCOUFcdTBCOUNcdTBCOUVcdTBCOUZcdTBCQTNcdTBCQTRcdTBCQTgtXHUwQkFBXHUwQkFFLVx1MEJCOVx1MEJCRS1cdTBCQzJcdTBCQzYtXHUwQkM4XHUwQkNBLVx1MEJDRFx1MEJEMFx1MEJEN1x1MEJFNi1cdTBCRUZcdTBDMDAtXHUwQzAzXHUwQzA1LVx1MEMwQ1x1MEMwRS1cdTBDMTBcdTBDMTItXHUwQzI4XHUwQzJBLVx1MEMzOVx1MEMzRC1cdTBDNDRcdTBDNDYtXHUwQzQ4XHUwQzRBLVx1MEM0RFx1MEM1NVx1MEM1Nlx1MEM1OC1cdTBDNUFcdTBDNjAtXHUwQzYzXHUwQzY2LVx1MEM2Rlx1MEM4MS1cdTBDODNcdTBDODUtXHUwQzhDXHUwQzhFLVx1MEM5MFx1MEM5Mi1cdTBDQThcdTBDQUEtXHUwQ0IzXHUwQ0I1LVx1MENCOVx1MENCQy1cdTBDQzRcdTBDQzYtXHUwQ0M4XHUwQ0NBLVx1MENDRFx1MENENVx1MENENlx1MENERVx1MENFMC1cdTBDRTNcdTBDRTYtXHUwQ0VGXHUwQ0YxXHUwQ0YyXHUwRDAxLVx1MEQwM1x1MEQwNS1cdTBEMENcdTBEMEUtXHUwRDEwXHUwRDEyLVx1MEQzQVx1MEQzRC1cdTBENDRcdTBENDYtXHUwRDQ4XHUwRDRBLVx1MEQ0RVx1MEQ1N1x1MEQ1Ri1cdTBENjNcdTBENjYtXHUwRDZGXHUwRDdBLVx1MEQ3Rlx1MEQ4Mlx1MEQ4M1x1MEQ4NS1cdTBEOTZcdTBEOUEtXHUwREIxXHUwREIzLVx1MERCQlx1MERCRFx1MERDMC1cdTBEQzZcdTBEQ0FcdTBEQ0YtXHUwREQ0XHUwREQ2XHUwREQ4LVx1MERERlx1MERFNi1cdTBERUZcdTBERjJcdTBERjNcdTBFMDEtXHUwRTNBXHUwRTQwLVx1MEU0RVx1MEU1MC1cdTBFNTlcdTBFODFcdTBFODJcdTBFODRcdTBFODdcdTBFODhcdTBFOEFcdTBFOERcdTBFOTQtXHUwRTk3XHUwRTk5LVx1MEU5Rlx1MEVBMS1cdTBFQTNcdTBFQTVcdTBFQTdcdTBFQUFcdTBFQUJcdTBFQUQtXHUwRUI5XHUwRUJCLVx1MEVCRFx1MEVDMC1cdTBFQzRcdTBFQzZcdTBFQzgtXHUwRUNEXHUwRUQwLVx1MEVEOVx1MEVEQy1cdTBFREZcdTBGMDBcdTBGMThcdTBGMTlcdTBGMjAtXHUwRjI5XHUwRjM1XHUwRjM3XHUwRjM5XHUwRjNFLVx1MEY0N1x1MEY0OS1cdTBGNkNcdTBGNzEtXHUwRjg0XHUwRjg2LVx1MEY5N1x1MEY5OS1cdTBGQkNcdTBGQzZcdTEwMDAtXHUxMDQ5XHUxMDUwLVx1MTA5RFx1MTBBMC1cdTEwQzVcdTEwQzdcdTEwQ0RcdTEwRDAtXHUxMEZBXHUxMEZDLVx1MTI0OFx1MTI0QS1cdTEyNERcdTEyNTAtXHUxMjU2XHUxMjU4XHUxMjVBLVx1MTI1RFx1MTI2MC1cdTEyODhcdTEyOEEtXHUxMjhEXHUxMjkwLVx1MTJCMFx1MTJCMi1cdTEyQjVcdTEyQjgtXHUxMkJFXHUxMkMwXHUxMkMyLVx1MTJDNVx1MTJDOC1cdTEyRDZcdTEyRDgtXHUxMzEwXHUxMzEyLVx1MTMxNVx1MTMxOC1cdTEzNUFcdTEzNUQtXHUxMzVGXHUxMzY5LVx1MTM3MVx1MTM4MC1cdTEzOEZcdTEzQTAtXHUxM0Y1XHUxM0Y4LVx1MTNGRFx1MTQwMS1cdTE2NkNcdTE2NkYtXHUxNjdGXHUxNjgxLVx1MTY5QVx1MTZBMC1cdTE2RUFcdTE2RUUtXHUxNkY4XHUxNzAwLVx1MTcwQ1x1MTcwRS1cdTE3MTRcdTE3MjAtXHUxNzM0XHUxNzQwLVx1MTc1M1x1MTc2MC1cdTE3NkNcdTE3NkUtXHUxNzcwXHUxNzcyXHUxNzczXHUxNzgwLVx1MTdEM1x1MTdEN1x1MTdEQ1x1MTdERFx1MTdFMC1cdTE3RTlcdTE4MEItXHUxODBEXHUxODEwLVx1MTgxOVx1MTgyMC1cdTE4NzdcdTE4ODAtXHUxOEFBXHUxOEIwLVx1MThGNVx1MTkwMC1cdTE5MUVcdTE5MjAtXHUxOTJCXHUxOTMwLVx1MTkzQlx1MTk0Ni1cdTE5NkRcdTE5NzAtXHUxOTc0XHUxOTgwLVx1MTlBQlx1MTlCMC1cdTE5QzlcdTE5RDAtXHUxOURBXHUxQTAwLVx1MUExQlx1MUEyMC1cdTFBNUVcdTFBNjAtXHUxQTdDXHUxQTdGLVx1MUE4OVx1MUE5MC1cdTFBOTlcdTFBQTdcdTFBQjAtXHUxQUJEXHUxQjAwLVx1MUI0Qlx1MUI1MC1cdTFCNTlcdTFCNkItXHUxQjczXHUxQjgwLVx1MUJGM1x1MUMwMC1cdTFDMzdcdTFDNDAtXHUxQzQ5XHUxQzRELVx1MUM3RFx1MUNEMC1cdTFDRDJcdTFDRDQtXHUxQ0Y2XHUxQ0Y4XHUxQ0Y5XHUxRDAwLVx1MURGNVx1MURGQy1cdTFGMTVcdTFGMTgtXHUxRjFEXHUxRjIwLVx1MUY0NVx1MUY0OC1cdTFGNERcdTFGNTAtXHUxRjU3XHUxRjU5XHUxRjVCXHUxRjVEXHUxRjVGLVx1MUY3RFx1MUY4MC1cdTFGQjRcdTFGQjYtXHUxRkJDXHUxRkJFXHUxRkMyLVx1MUZDNFx1MUZDNi1cdTFGQ0NcdTFGRDAtXHUxRkQzXHUxRkQ2LVx1MUZEQlx1MUZFMC1cdTFGRUNcdTFGRjItXHUxRkY0XHUxRkY2LVx1MUZGQ1x1MjAwQ1x1MjAwRFx1MjAzRlx1MjA0MFx1MjA1NFx1MjA3MVx1MjA3Rlx1MjA5MC1cdTIwOUNcdTIwRDAtXHUyMERDXHUyMEUxXHUyMEU1LVx1MjBGMFx1MjEwMlx1MjEwN1x1MjEwQS1cdTIxMTNcdTIxMTVcdTIxMTgtXHUyMTFEXHUyMTI0XHUyMTI2XHUyMTI4XHUyMTJBLVx1MjEzOVx1MjEzQy1cdTIxM0ZcdTIxNDUtXHUyMTQ5XHUyMTRFXHUyMTYwLVx1MjE4OFx1MkMwMC1cdTJDMkVcdTJDMzAtXHUyQzVFXHUyQzYwLVx1MkNFNFx1MkNFQi1cdTJDRjNcdTJEMDAtXHUyRDI1XHUyRDI3XHUyRDJEXHUyRDMwLVx1MkQ2N1x1MkQ2Rlx1MkQ3Ri1cdTJEOTZcdTJEQTAtXHUyREE2XHUyREE4LVx1MkRBRVx1MkRCMC1cdTJEQjZcdTJEQjgtXHUyREJFXHUyREMwLVx1MkRDNlx1MkRDOC1cdTJEQ0VcdTJERDAtXHUyREQ2XHUyREQ4LVx1MkRERVx1MkRFMC1cdTJERkZcdTMwMDUtXHUzMDA3XHUzMDIxLVx1MzAyRlx1MzAzMS1cdTMwMzVcdTMwMzgtXHUzMDNDXHUzMDQxLVx1MzA5Nlx1MzA5OS1cdTMwOUZcdTMwQTEtXHUzMEZBXHUzMEZDLVx1MzBGRlx1MzEwNS1cdTMxMkRcdTMxMzEtXHUzMThFXHUzMUEwLVx1MzFCQVx1MzFGMC1cdTMxRkZcdTM0MDAtXHU0REI1XHU0RTAwLVx1OUZENVx1QTAwMC1cdUE0OENcdUE0RDAtXHVBNEZEXHVBNTAwLVx1QTYwQ1x1QTYxMC1cdUE2MkJcdUE2NDAtXHVBNjZGXHVBNjc0LVx1QTY3RFx1QTY3Ri1cdUE2RjFcdUE3MTctXHVBNzFGXHVBNzIyLVx1QTc4OFx1QTc4Qi1cdUE3QURcdUE3QjAtXHVBN0I3XHVBN0Y3LVx1QTgyN1x1QTg0MC1cdUE4NzNcdUE4ODAtXHVBOEM0XHVBOEQwLVx1QThEOVx1QThFMC1cdUE4RjdcdUE4RkJcdUE4RkRcdUE5MDAtXHVBOTJEXHVBOTMwLVx1QTk1M1x1QTk2MC1cdUE5N0NcdUE5ODAtXHVBOUMwXHVBOUNGLVx1QTlEOVx1QTlFMC1cdUE5RkVcdUFBMDAtXHVBQTM2XHVBQTQwLVx1QUE0RFx1QUE1MC1cdUFBNTlcdUFBNjAtXHVBQTc2XHVBQTdBLVx1QUFDMlx1QUFEQi1cdUFBRERcdUFBRTAtXHVBQUVGXHVBQUYyLVx1QUFGNlx1QUIwMS1cdUFCMDZcdUFCMDktXHVBQjBFXHVBQjExLVx1QUIxNlx1QUIyMC1cdUFCMjZcdUFCMjgtXHVBQjJFXHVBQjMwLVx1QUI1QVx1QUI1Qy1cdUFCNjVcdUFCNzAtXHVBQkVBXHVBQkVDXHVBQkVEXHVBQkYwLVx1QUJGOVx1QUMwMC1cdUQ3QTNcdUQ3QjAtXHVEN0M2XHVEN0NCLVx1RDdGQlx1RjkwMC1cdUZBNkRcdUZBNzAtXHVGQUQ5XHVGQjAwLVx1RkIwNlx1RkIxMy1cdUZCMTdcdUZCMUQtXHVGQjI4XHVGQjJBLVx1RkIzNlx1RkIzOC1cdUZCM0NcdUZCM0VcdUZCNDBcdUZCNDFcdUZCNDNcdUZCNDRcdUZCNDYtXHVGQkIxXHVGQkQzLVx1RkQzRFx1RkQ1MC1cdUZEOEZcdUZEOTItXHVGREM3XHVGREYwLVx1RkRGQlx1RkUwMC1cdUZFMEZcdUZFMjAtXHVGRTJGXHVGRTMzXHVGRTM0XHVGRTRELVx1RkU0Rlx1RkU3MC1cdUZFNzRcdUZFNzYtXHVGRUZDXHVGRjEwLVx1RkYxOVx1RkYyMS1cdUZGM0FcdUZGM0ZcdUZGNDEtXHVGRjVBXHVGRjY2LVx1RkZCRVx1RkZDMi1cdUZGQzdcdUZGQ0EtXHVGRkNGXHVGRkQyLVx1RkZEN1x1RkZEQS1cdUZGRENdfFx1RDgwMFtcdURDMDAtXHVEQzBCXHVEQzBELVx1REMyNlx1REMyOC1cdURDM0FcdURDM0NcdURDM0RcdURDM0YtXHVEQzREXHVEQzUwLVx1REM1RFx1REM4MC1cdURDRkFcdURENDAtXHVERDc0XHVEREZEXHVERTgwLVx1REU5Q1x1REVBMC1cdURFRDBcdURFRTBcdURGMDAtXHVERjFGXHVERjMwLVx1REY0QVx1REY1MC1cdURGN0FcdURGODAtXHVERjlEXHVERkEwLVx1REZDM1x1REZDOC1cdURGQ0ZcdURGRDEtXHVERkQ1XXxcdUQ4MDFbXHVEQzAwLVx1REM5RFx1RENBMC1cdURDQTlcdUREMDAtXHVERDI3XHVERDMwLVx1REQ2M1x1REUwMC1cdURGMzZcdURGNDAtXHVERjU1XHVERjYwLVx1REY2N118XHVEODAyW1x1REMwMC1cdURDMDVcdURDMDhcdURDMEEtXHVEQzM1XHVEQzM3XHVEQzM4XHVEQzNDXHVEQzNGLVx1REM1NVx1REM2MC1cdURDNzZcdURDODAtXHVEQzlFXHVEQ0UwLVx1RENGMlx1RENGNFx1RENGNVx1REQwMC1cdUREMTVcdUREMjAtXHVERDM5XHVERDgwLVx1RERCN1x1RERCRVx1RERCRlx1REUwMC1cdURFMDNcdURFMDVcdURFMDZcdURFMEMtXHVERTEzXHVERTE1LVx1REUxN1x1REUxOS1cdURFMzNcdURFMzgtXHVERTNBXHVERTNGXHVERTYwLVx1REU3Q1x1REU4MC1cdURFOUNcdURFQzAtXHVERUM3XHVERUM5LVx1REVFNlx1REYwMC1cdURGMzVcdURGNDAtXHVERjU1XHVERjYwLVx1REY3Mlx1REY4MC1cdURGOTFdfFx1RDgwM1tcdURDMDAtXHVEQzQ4XHVEQzgwLVx1RENCMlx1RENDMC1cdURDRjJdfFx1RDgwNFtcdURDMDAtXHVEQzQ2XHVEQzY2LVx1REM2Rlx1REM3Ri1cdURDQkFcdURDRDAtXHVEQ0U4XHVEQ0YwLVx1RENGOVx1REQwMC1cdUREMzRcdUREMzYtXHVERDNGXHVERDUwLVx1REQ3M1x1REQ3Nlx1REQ4MC1cdUREQzRcdUREQ0EtXHVERENDXHVEREQwLVx1REREQVx1REREQ1x1REUwMC1cdURFMTFcdURFMTMtXHVERTM3XHVERTgwLVx1REU4Nlx1REU4OFx1REU4QS1cdURFOERcdURFOEYtXHVERTlEXHVERTlGLVx1REVBOFx1REVCMC1cdURFRUFcdURFRjAtXHVERUY5XHVERjAwLVx1REYwM1x1REYwNS1cdURGMENcdURGMEZcdURGMTBcdURGMTMtXHVERjI4XHVERjJBLVx1REYzMFx1REYzMlx1REYzM1x1REYzNS1cdURGMzlcdURGM0MtXHVERjQ0XHVERjQ3XHVERjQ4XHVERjRCLVx1REY0RFx1REY1MFx1REY1N1x1REY1RC1cdURGNjNcdURGNjYtXHVERjZDXHVERjcwLVx1REY3NF18XHVEODA1W1x1REM4MC1cdURDQzVcdURDQzdcdURDRDAtXHVEQ0Q5XHVERDgwLVx1RERCNVx1RERCOC1cdUREQzBcdURERDgtXHVEREREXHVERTAwLVx1REU0MFx1REU0NFx1REU1MC1cdURFNTlcdURFODAtXHVERUI3XHVERUMwLVx1REVDOVx1REYwMC1cdURGMTlcdURGMUQtXHVERjJCXHVERjMwLVx1REYzOV18XHVEODA2W1x1RENBMC1cdURDRTlcdURDRkZcdURFQzAtXHVERUY4XXxcdUQ4MDhbXHVEQzAwLVx1REY5OV18XHVEODA5W1x1REMwMC1cdURDNkVcdURDODAtXHVERDQzXXxbXHVEODBDXHVEODQwLVx1RDg2OFx1RDg2QS1cdUQ4NkNcdUQ4NkYtXHVEODcyXVtcdURDMDAtXHVERkZGXXxcdUQ4MERbXHVEQzAwLVx1REMyRV18XHVEODExW1x1REMwMC1cdURFNDZdfFx1RDgxQVtcdURDMDAtXHVERTM4XHVERTQwLVx1REU1RVx1REU2MC1cdURFNjlcdURFRDAtXHVERUVEXHVERUYwLVx1REVGNFx1REYwMC1cdURGMzZcdURGNDAtXHVERjQzXHVERjUwLVx1REY1OVx1REY2My1cdURGNzdcdURGN0QtXHVERjhGXXxcdUQ4MUJbXHVERjAwLVx1REY0NFx1REY1MC1cdURGN0VcdURGOEYtXHVERjlGXXxcdUQ4MkNbXHVEQzAwXHVEQzAxXXxcdUQ4MkZbXHVEQzAwLVx1REM2QVx1REM3MC1cdURDN0NcdURDODAtXHVEQzg4XHVEQzkwLVx1REM5OVx1REM5RFx1REM5RV18XHVEODM0W1x1REQ2NS1cdURENjlcdURENkQtXHVERDcyXHVERDdCLVx1REQ4Mlx1REQ4NS1cdUREOEJcdUREQUEtXHVEREFEXHVERTQyLVx1REU0NF18XHVEODM1W1x1REMwMC1cdURDNTRcdURDNTYtXHVEQzlDXHVEQzlFXHVEQzlGXHVEQ0EyXHVEQ0E1XHVEQ0E2XHVEQ0E5LVx1RENBQ1x1RENBRS1cdURDQjlcdURDQkJcdURDQkQtXHVEQ0MzXHVEQ0M1LVx1REQwNVx1REQwNy1cdUREMEFcdUREMEQtXHVERDE0XHVERDE2LVx1REQxQ1x1REQxRS1cdUREMzlcdUREM0ItXHVERDNFXHVERDQwLVx1REQ0NFx1REQ0Nlx1REQ0QS1cdURENTBcdURENTItXHVERUE1XHVERUE4LVx1REVDMFx1REVDMi1cdURFREFcdURFREMtXHVERUZBXHVERUZDLVx1REYxNFx1REYxNi1cdURGMzRcdURGMzYtXHVERjRFXHVERjUwLVx1REY2RVx1REY3MC1cdURGODhcdURGOEEtXHVERkE4XHVERkFBLVx1REZDMlx1REZDNC1cdURGQ0JcdURGQ0UtXHVERkZGXXxcdUQ4MzZbXHVERTAwLVx1REUzNlx1REUzQi1cdURFNkNcdURFNzVcdURFODRcdURFOUItXHVERTlGXHVERUExLVx1REVBRl18XHVEODNBW1x1REMwMC1cdURDQzRcdURDRDAtXHVEQ0Q2XXxcdUQ4M0JbXHVERTAwLVx1REUwM1x1REUwNS1cdURFMUZcdURFMjFcdURFMjJcdURFMjRcdURFMjdcdURFMjktXHVERTMyXHVERTM0LVx1REUzN1x1REUzOVx1REUzQlx1REU0Mlx1REU0N1x1REU0OVx1REU0Qlx1REU0RC1cdURFNEZcdURFNTFcdURFNTJcdURFNTRcdURFNTdcdURFNTlcdURFNUJcdURFNURcdURFNUZcdURFNjFcdURFNjJcdURFNjRcdURFNjctXHVERTZBXHVERTZDLVx1REU3Mlx1REU3NC1cdURFNzdcdURFNzktXHVERTdDXHVERTdFXHVERTgwLVx1REU4OVx1REU4Qi1cdURFOUJcdURFQTEtXHVERUEzXHVERUE1LVx1REVBOVx1REVBQi1cdURFQkJdfFx1RDg2OVtcdURDMDAtXHVERUQ2XHVERjAwLVx1REZGRl18XHVEODZEW1x1REMwMC1cdURGMzRcdURGNDAtXHVERkZGXXxcdUQ4NkVbXHVEQzAwLVx1REMxRFx1REMyMC1cdURGRkZdfFx1RDg3M1tcdURDMDAtXHVERUExXXxcdUQ4N0VbXHVEQzAwLVx1REUxRF18XHVEQjQwW1x1REQwMC1cdURERUZdL307dC5DaGFyYWN0ZXI9e2Zyb21Db2RlUG9pbnQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGU8NjU1MzY/U3RyaW5nLmZyb21DaGFyQ29kZShlKTpTdHJpbmcuZnJvbUNoYXJDb2RlKDU1Mjk2KyhlLTY1NTM2Pj4xMCkpK1N0cmluZy5mcm9tQ2hhckNvZGUoNTYzMjArKGUtNjU1MzYmMTAyMykpfSxpc1doaXRlU3BhY2U6ZnVuY3Rpb24oZSl7cmV0dXJuIDMyPT09ZXx8OT09PWV8fDExPT09ZXx8MTI9PT1lfHwxNjA9PT1lfHxlPj01NzYwJiZbNTc2MCw4MTkyLDgxOTMsODE5NCw4MTk1LDgxOTYsODE5Nyw4MTk4LDgxOTksODIwMCw4MjAxLDgyMDIsODIzOSw4Mjg3LDEyMjg4LDY1Mjc5XS5pbmRleE9mKGUpPj0wfSxpc0xpbmVUZXJtaW5hdG9yOmZ1bmN0aW9uKGUpe3JldHVybiAxMD09PWV8fDEzPT09ZXx8ODIzMj09PWV8fDgyMzM9PT1lfSxpc0lkZW50aWZpZXJTdGFydDpmdW5jdGlvbihlKXtyZXR1cm4gMzY9PT1lfHw5NT09PWV8fGU+PTY1JiZlPD05MHx8ZT49OTcmJmU8PTEyMnx8OTI9PT1lfHxlPj0xMjgmJm4uTm9uQXNjaWlJZGVudGlmaWVyU3RhcnQudGVzdCh0LkNoYXJhY3Rlci5mcm9tQ29kZVBvaW50KGUpKX0saXNJZGVudGlmaWVyUGFydDpmdW5jdGlvbihlKXtyZXR1cm4gMzY9PT1lfHw5NT09PWV8fGU+PTY1JiZlPD05MHx8ZT49OTcmJmU8PTEyMnx8ZT49NDgmJmU8PTU3fHw5Mj09PWV8fGU+PTEyOCYmbi5Ob25Bc2NpaUlkZW50aWZpZXJQYXJ0LnRlc3QodC5DaGFyYWN0ZXIuZnJvbUNvZGVQb2ludChlKSl9LGlzRGVjaW1hbERpZ2l0OmZ1bmN0aW9uKGUpe3JldHVybiBlPj00OCYmZTw9NTd9LGlzSGV4RGlnaXQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGU+PTQ4JiZlPD01N3x8ZT49NjUmJmU8PTcwfHxlPj05NyYmZTw9MTAyfSxpc09jdGFsRGlnaXQ6ZnVuY3Rpb24oZSl7cmV0dXJuIGU+PTQ4JiZlPD01NX19fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDYpLGk9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMudHlwZT1yLkpTWFN5bnRheC5KU1hDbG9zaW5nRWxlbWVudCx0aGlzLm5hbWU9ZX1yZXR1cm4gZX0oKTt0LkpTWENsb3NpbmdFbGVtZW50PWk7dmFyIG89ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxuKXt0aGlzLnR5cGU9ci5KU1hTeW50YXguSlNYRWxlbWVudCx0aGlzLm9wZW5pbmdFbGVtZW50PWUsdGhpcy5jaGlsZHJlbj10LHRoaXMuY2xvc2luZ0VsZW1lbnQ9bn1yZXR1cm4gZX0oKTt0LkpTWEVsZW1lbnQ9bzt2YXIgYT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXt0aGlzLnR5cGU9ci5KU1hTeW50YXguSlNYRW1wdHlFeHByZXNzaW9ufXJldHVybiBlfSgpO3QuSlNYRW1wdHlFeHByZXNzaW9uPWE7dmFyIHM9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMudHlwZT1yLkpTWFN5bnRheC5KU1hFeHByZXNzaW9uQ29udGFpbmVyLHRoaXMuZXhwcmVzc2lvbj1lfXJldHVybiBlfSgpO3QuSlNYRXhwcmVzc2lvbkNvbnRhaW5lcj1zO3ZhciB1PWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnR5cGU9ci5KU1hTeW50YXguSlNYSWRlbnRpZmllcix0aGlzLm5hbWU9ZX1yZXR1cm4gZX0oKTt0LkpTWElkZW50aWZpZXI9dTt2YXIgYz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnR5cGU9ci5KU1hTeW50YXguSlNYTWVtYmVyRXhwcmVzc2lvbix0aGlzLm9iamVjdD1lLHRoaXMucHJvcGVydHk9dH1yZXR1cm4gZX0oKTt0LkpTWE1lbWJlckV4cHJlc3Npb249Yzt2YXIgbD1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnR5cGU9ci5KU1hTeW50YXguSlNYQXR0cmlidXRlLHRoaXMubmFtZT1lLHRoaXMudmFsdWU9dH1yZXR1cm4gZX0oKTt0LkpTWEF0dHJpYnV0ZT1sO3ZhciBwPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLkpTWFN5bnRheC5KU1hOYW1lc3BhY2VkTmFtZSx0aGlzLm5hbWVzcGFjZT1lLHRoaXMubmFtZT10fXJldHVybiBlfSgpO3QuSlNYTmFtZXNwYWNlZE5hbWU9cDt2YXIgZj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0LG4pe3RoaXMudHlwZT1yLkpTWFN5bnRheC5KU1hPcGVuaW5nRWxlbWVudCx0aGlzLm5hbWU9ZSx0aGlzLnNlbGZDbG9zaW5nPXQsdGhpcy5hdHRyaWJ1dGVzPW59cmV0dXJuIGV9KCk7dC5KU1hPcGVuaW5nRWxlbWVudD1mO3ZhciBkPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnR5cGU9ci5KU1hTeW50YXguSlNYU3ByZWFkQXR0cmlidXRlLHRoaXMuYXJndW1lbnQ9ZX1yZXR1cm4gZX0oKTt0LkpTWFNwcmVhZEF0dHJpYnV0ZT1kO3ZhciBoPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLkpTWFN5bnRheC5KU1hUZXh0LHRoaXMudmFsdWU9ZSx0aGlzLnJhdz10fXJldHVybiBlfSgpO3QuSlNYVGV4dD1ofSxmdW5jdGlvbihlLHQpeyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5KU1hTeW50YXg9e0pTWEF0dHJpYnV0ZToiSlNYQXR0cmlidXRlIixKU1hDbG9zaW5nRWxlbWVudDoiSlNYQ2xvc2luZ0VsZW1lbnQiLEpTWEVsZW1lbnQ6IkpTWEVsZW1lbnQiLEpTWEVtcHR5RXhwcmVzc2lvbjoiSlNYRW1wdHlFeHByZXNzaW9uIixKU1hFeHByZXNzaW9uQ29udGFpbmVyOiJKU1hFeHByZXNzaW9uQ29udGFpbmVyIixKU1hJZGVudGlmaWVyOiJKU1hJZGVudGlmaWVyIixKU1hNZW1iZXJFeHByZXNzaW9uOiJKU1hNZW1iZXJFeHByZXNzaW9uIixKU1hOYW1lc3BhY2VkTmFtZToiSlNYTmFtZXNwYWNlZE5hbWUiLEpTWE9wZW5pbmdFbGVtZW50OiJKU1hPcGVuaW5nRWxlbWVudCIsSlNYU3ByZWFkQXR0cmlidXRlOiJKU1hTcHJlYWRBdHRyaWJ1dGUiLEpTWFRleHQ6IkpTWFRleHQifX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIHI9bigyKSxpPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnR5cGU9ci5TeW50YXguQXJyYXlFeHByZXNzaW9uLHRoaXMuZWxlbWVudHM9ZX1yZXR1cm4gZX0oKTt0LkFycmF5RXhwcmVzc2lvbj1pO3ZhciBvPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnR5cGU9ci5TeW50YXguQXJyYXlQYXR0ZXJuLHRoaXMuZWxlbWVudHM9ZX1yZXR1cm4gZX0oKTt0LkFycmF5UGF0dGVybj1vO3ZhciBhPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dGhpcy50eXBlPXIuU3ludGF4LkFycm93RnVuY3Rpb25FeHByZXNzaW9uLHRoaXMuaWQ9bnVsbCx0aGlzLnBhcmFtcz1lLHRoaXMuYm9keT10LHRoaXMuZ2VuZXJhdG9yPSExLHRoaXMuZXhwcmVzc2lvbj1uLHRoaXMuYXN5bmM9ITF9cmV0dXJuIGV9KCk7dC5BcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbj1hO3ZhciBzPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dGhpcy50eXBlPXIuU3ludGF4LkFzc2lnbm1lbnRFeHByZXNzaW9uLHRoaXMub3BlcmF0b3I9ZSx0aGlzLmxlZnQ9dCx0aGlzLnJpZ2h0PW59cmV0dXJuIGV9KCk7dC5Bc3NpZ25tZW50RXhwcmVzc2lvbj1zO3ZhciB1PWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLlN5bnRheC5Bc3NpZ25tZW50UGF0dGVybix0aGlzLmxlZnQ9ZSx0aGlzLnJpZ2h0PXR9cmV0dXJuIGV9KCk7dC5Bc3NpZ25tZW50UGF0dGVybj11O3ZhciBjPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dGhpcy50eXBlPXIuU3ludGF4LkFycm93RnVuY3Rpb25FeHByZXNzaW9uLHRoaXMuaWQ9bnVsbCx0aGlzLnBhcmFtcz1lLHRoaXMuYm9keT10LHRoaXMuZ2VuZXJhdG9yPSExLHRoaXMuZXhwcmVzc2lvbj1uLHRoaXMuYXN5bmM9ITB9cmV0dXJuIGV9KCk7dC5Bc3luY0Fycm93RnVuY3Rpb25FeHByZXNzaW9uPWM7dmFyIGw9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxuKXt0aGlzLnR5cGU9ci5TeW50YXguRnVuY3Rpb25EZWNsYXJhdGlvbix0aGlzLmlkPWUsdGhpcy5wYXJhbXM9dCx0aGlzLmJvZHk9bix0aGlzLmdlbmVyYXRvcj0hMSx0aGlzLmV4cHJlc3Npb249ITEsdGhpcy5hc3luYz0hMH1yZXR1cm4gZX0oKTt0LkFzeW5jRnVuY3Rpb25EZWNsYXJhdGlvbj1sO3ZhciBwPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dGhpcy50eXBlPXIuU3ludGF4LkZ1bmN0aW9uRXhwcmVzc2lvbix0aGlzLmlkPWUsdGhpcy5wYXJhbXM9dCx0aGlzLmJvZHk9bix0aGlzLmdlbmVyYXRvcj0hMSx0aGlzLmV4cHJlc3Npb249ITEsdGhpcy5hc3luYz0hMH1yZXR1cm4gZX0oKTt0LkFzeW5jRnVuY3Rpb25FeHByZXNzaW9uPXA7dmFyIGY9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMudHlwZT1yLlN5bnRheC5Bd2FpdEV4cHJlc3Npb24sdGhpcy5hcmd1bWVudD1lfXJldHVybiBlfSgpO3QuQXdhaXRFeHByZXNzaW9uPWY7dmFyIGQ9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxuKXt2YXIgaT0ifHwiPT09ZXx8IiYmIj09PWU7dGhpcy50eXBlPWk/ci5TeW50YXguTG9naWNhbEV4cHJlc3Npb246ci5TeW50YXguQmluYXJ5RXhwcmVzc2lvbix0aGlzLm9wZXJhdG9yPWUsdGhpcy5sZWZ0PXQsdGhpcy5yaWdodD1ufXJldHVybiBlfSgpO3QuQmluYXJ5RXhwcmVzc2lvbj1kO3ZhciBoPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnR5cGU9ci5TeW50YXguQmxvY2tTdGF0ZW1lbnQsdGhpcy5ib2R5PWV9cmV0dXJuIGV9KCk7dC5CbG9ja1N0YXRlbWVudD1oO3ZhciBtPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnR5cGU9ci5TeW50YXguQnJlYWtTdGF0ZW1lbnQsdGhpcy5sYWJlbD1lfXJldHVybiBlfSgpO3QuQnJlYWtTdGF0ZW1lbnQ9bTt2YXIgZz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnR5cGU9ci5TeW50YXguQ2FsbEV4cHJlc3Npb24sdGhpcy5jYWxsZWU9ZSx0aGlzLmFyZ3VtZW50cz10fXJldHVybiBlfSgpO3QuQ2FsbEV4cHJlc3Npb249Zzt2YXIgeT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnR5cGU9ci5TeW50YXguQ2F0Y2hDbGF1c2UsdGhpcy5wYXJhbT1lLHRoaXMuYm9keT10fXJldHVybiBlfSgpO3QuQ2F0Y2hDbGF1c2U9eTt2YXIgdj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy50eXBlPXIuU3ludGF4LkNsYXNzQm9keSx0aGlzLmJvZHk9ZX1yZXR1cm4gZX0oKTt0LkNsYXNzQm9keT12O3ZhciBiPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dGhpcy50eXBlPXIuU3ludGF4LkNsYXNzRGVjbGFyYXRpb24sdGhpcy5pZD1lLHRoaXMuc3VwZXJDbGFzcz10LHRoaXMuYm9keT1ufXJldHVybiBlfSgpO3QuQ2xhc3NEZWNsYXJhdGlvbj1iO3ZhciB4PWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dGhpcy50eXBlPXIuU3ludGF4LkNsYXNzRXhwcmVzc2lvbix0aGlzLmlkPWUsdGhpcy5zdXBlckNsYXNzPXQsdGhpcy5ib2R5PW59cmV0dXJuIGV9KCk7dC5DbGFzc0V4cHJlc3Npb249eDt2YXIgQz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnR5cGU9ci5TeW50YXguTWVtYmVyRXhwcmVzc2lvbix0aGlzLmNvbXB1dGVkPSEwLHRoaXMub2JqZWN0PWUsdGhpcy5wcm9wZXJ0eT10fXJldHVybiBlfSgpO3QuQ29tcHV0ZWRNZW1iZXJFeHByZXNzaW9uPUM7dmFyIEU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxuKXt0aGlzLnR5cGU9ci5TeW50YXguQ29uZGl0aW9uYWxFeHByZXNzaW9uLHRoaXMudGVzdD1lLHRoaXMuY29uc2VxdWVudD10LHRoaXMuYWx0ZXJuYXRlPW59cmV0dXJuIGV9KCk7dC5Db25kaXRpb25hbEV4cHJlc3Npb249RTt2YXIgRD1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy50eXBlPXIuU3ludGF4LkNvbnRpbnVlU3RhdGVtZW50LHRoaXMubGFiZWw9ZX1yZXR1cm4gZX0oKTt0LkNvbnRpbnVlU3RhdGVtZW50PUQ7dmFyIHc9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7dGhpcy50eXBlPXIuU3ludGF4LkRlYnVnZ2VyU3RhdGVtZW50fXJldHVybiBlfSgpO3QuRGVidWdnZXJTdGF0ZW1lbnQ9dzt2YXIgUz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnR5cGU9ci5TeW50YXguRXhwcmVzc2lvblN0YXRlbWVudCx0aGlzLmV4cHJlc3Npb249ZSx0aGlzLmRpcmVjdGl2ZT10fXJldHVybiBlfSgpO3QuRGlyZWN0aXZlPVM7dmFyIGs9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LkRvV2hpbGVTdGF0ZW1lbnQsdGhpcy5ib2R5PWUsdGhpcy50ZXN0PXR9cmV0dXJuIGV9KCk7dC5Eb1doaWxlU3RhdGVtZW50PWs7dmFyIEE9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7dGhpcy50eXBlPXIuU3ludGF4LkVtcHR5U3RhdGVtZW50fXJldHVybiBlfSgpO3QuRW1wdHlTdGF0ZW1lbnQ9QTt2YXIgXz1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy50eXBlPXIuU3ludGF4LkV4cG9ydEFsbERlY2xhcmF0aW9uLHRoaXMuc291cmNlPWV9cmV0dXJuIGV9KCk7dC5FeHBvcnRBbGxEZWNsYXJhdGlvbj1fO3ZhciBUPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnR5cGU9ci5TeW50YXguRXhwb3J0RGVmYXVsdERlY2xhcmF0aW9uLHRoaXMuZGVjbGFyYXRpb249ZX1yZXR1cm4gZX0oKTt0LkV4cG9ydERlZmF1bHREZWNsYXJhdGlvbj1UO3ZhciBPPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dGhpcy50eXBlPXIuU3ludGF4LkV4cG9ydE5hbWVkRGVjbGFyYXRpb24sdGhpcy5kZWNsYXJhdGlvbj1lLHRoaXMuc3BlY2lmaWVycz10LHRoaXMuc291cmNlPW59cmV0dXJuIGV9KCk7dC5FeHBvcnROYW1lZERlY2xhcmF0aW9uPU87dmFyIEY9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LkV4cG9ydFNwZWNpZmllcix0aGlzLmV4cG9ydGVkPXQsdGhpcy5sb2NhbD1lfXJldHVybiBlfSgpO3QuRXhwb3J0U3BlY2lmaWVyPUY7dmFyIE49ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMudHlwZT1yLlN5bnRheC5FeHByZXNzaW9uU3RhdGVtZW50LHRoaXMuZXhwcmVzc2lvbj1lfXJldHVybiBlfSgpO3QuRXhwcmVzc2lvblN0YXRlbWVudD1OO3ZhciBJPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dGhpcy50eXBlPXIuU3ludGF4LkZvckluU3RhdGVtZW50LHRoaXMubGVmdD1lLHRoaXMucmlnaHQ9dCx0aGlzLmJvZHk9bix0aGlzLmVhY2g9ITF9cmV0dXJuIGV9KCk7dC5Gb3JJblN0YXRlbWVudD1JO3ZhciBMPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dGhpcy50eXBlPXIuU3ludGF4LkZvck9mU3RhdGVtZW50LHRoaXMubGVmdD1lLHRoaXMucmlnaHQ9dCx0aGlzLmJvZHk9bn1yZXR1cm4gZX0oKTt0LkZvck9mU3RhdGVtZW50PUw7dmFyIFA9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxuLGkpe3RoaXMudHlwZT1yLlN5bnRheC5Gb3JTdGF0ZW1lbnQsdGhpcy5pbml0PWUsdGhpcy50ZXN0PXQsdGhpcy51cGRhdGU9bix0aGlzLmJvZHk9aX1yZXR1cm4gZX0oKTt0LkZvclN0YXRlbWVudD1QO3ZhciBNPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbixpKXt0aGlzLnR5cGU9ci5TeW50YXguRnVuY3Rpb25EZWNsYXJhdGlvbix0aGlzLmlkPWUsdGhpcy5wYXJhbXM9dCx0aGlzLmJvZHk9bix0aGlzLmdlbmVyYXRvcj1pLHRoaXMuZXhwcmVzc2lvbj0hMSx0aGlzLmFzeW5jPSExfXJldHVybiBlfSgpO3QuRnVuY3Rpb25EZWNsYXJhdGlvbj1NO3ZhciBqPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbixpKXt0aGlzLnR5cGU9ci5TeW50YXguRnVuY3Rpb25FeHByZXNzaW9uLHRoaXMuaWQ9ZSx0aGlzLnBhcmFtcz10LHRoaXMuYm9keT1uLHRoaXMuZ2VuZXJhdG9yPWksdGhpcy5leHByZXNzaW9uPSExLHRoaXMuYXN5bmM9ITF9cmV0dXJuIGV9KCk7dC5GdW5jdGlvbkV4cHJlc3Npb249ajt2YXIgUj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy50eXBlPXIuU3ludGF4LklkZW50aWZpZXIsdGhpcy5uYW1lPWV9cmV0dXJuIGV9KCk7dC5JZGVudGlmaWVyPVI7dmFyIEI9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxuKXt0aGlzLnR5cGU9ci5TeW50YXguSWZTdGF0ZW1lbnQsdGhpcy50ZXN0PWUsdGhpcy5jb25zZXF1ZW50PXQsdGhpcy5hbHRlcm5hdGU9bn1yZXR1cm4gZX0oKTt0LklmU3RhdGVtZW50PUI7dmFyICQ9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LkltcG9ydERlY2xhcmF0aW9uLHRoaXMuc3BlY2lmaWVycz1lLHRoaXMuc291cmNlPXR9cmV0dXJuIGV9KCk7dC5JbXBvcnREZWNsYXJhdGlvbj0kO3ZhciBVPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnR5cGU9ci5TeW50YXguSW1wb3J0RGVmYXVsdFNwZWNpZmllcix0aGlzLmxvY2FsPWV9cmV0dXJuIGV9KCk7dC5JbXBvcnREZWZhdWx0U3BlY2lmaWVyPVU7dmFyIHo9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMudHlwZT1yLlN5bnRheC5JbXBvcnROYW1lc3BhY2VTcGVjaWZpZXIsdGhpcy5sb2NhbD1lfXJldHVybiBlfSgpO3QuSW1wb3J0TmFtZXNwYWNlU3BlY2lmaWVyPXo7dmFyIEc9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LkltcG9ydFNwZWNpZmllcix0aGlzLmxvY2FsPWUsdGhpcy5pbXBvcnRlZD10fXJldHVybiBlfSgpO3QuSW1wb3J0U3BlY2lmaWVyPUc7dmFyIFY9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LkxhYmVsZWRTdGF0ZW1lbnQsdGhpcy5sYWJlbD1lLHRoaXMuYm9keT10fXJldHVybiBlfSgpO3QuTGFiZWxlZFN0YXRlbWVudD1WO3ZhciBxPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLlN5bnRheC5MaXRlcmFsLHRoaXMudmFsdWU9ZSx0aGlzLnJhdz10fXJldHVybiBlfSgpO3QuTGl0ZXJhbD1xO3ZhciBIPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLlN5bnRheC5NZXRhUHJvcGVydHksdGhpcy5tZXRhPWUsdGhpcy5wcm9wZXJ0eT10fXJldHVybiBlfSgpO3QuTWV0YVByb3BlcnR5PUg7dmFyIFc9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxuLGksbyl7dGhpcy50eXBlPXIuU3ludGF4Lk1ldGhvZERlZmluaXRpb24sdGhpcy5rZXk9ZSx0aGlzLmNvbXB1dGVkPXQsdGhpcy52YWx1ZT1uLHRoaXMua2luZD1pLHRoaXMuc3RhdGljPW99cmV0dXJuIGV9KCk7dC5NZXRob2REZWZpbml0aW9uPVc7dmFyIFE9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMudHlwZT1yLlN5bnRheC5Qcm9ncmFtLHRoaXMuYm9keT1lLHRoaXMuc291cmNlVHlwZT0ibW9kdWxlIn1yZXR1cm4gZX0oKTt0Lk1vZHVsZT1RO3ZhciBLPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLlN5bnRheC5OZXdFeHByZXNzaW9uLHRoaXMuY2FsbGVlPWUsdGhpcy5hcmd1bWVudHM9dH1yZXR1cm4gZX0oKTt0Lk5ld0V4cHJlc3Npb249Szt2YXIgSj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy50eXBlPXIuU3ludGF4Lk9iamVjdEV4cHJlc3Npb24sdGhpcy5wcm9wZXJ0aWVzPWV9cmV0dXJuIGV9KCk7dC5PYmplY3RFeHByZXNzaW9uPUo7dmFyIFk9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMudHlwZT1yLlN5bnRheC5PYmplY3RQYXR0ZXJuLHRoaXMucHJvcGVydGllcz1lfXJldHVybiBlfSgpO3QuT2JqZWN0UGF0dGVybj1ZO3ZhciBYPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbixpLG8sYSl7dGhpcy50eXBlPXIuU3ludGF4LlByb3BlcnR5LHRoaXMua2V5PXQsdGhpcy5jb21wdXRlZD1uLHRoaXMudmFsdWU9aSx0aGlzLmtpbmQ9ZSx0aGlzLm1ldGhvZD1vLHRoaXMuc2hvcnRoYW5kPWF9cmV0dXJuIGV9KCk7dC5Qcm9wZXJ0eT1YO3ZhciBaPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbixpKXt0aGlzLnR5cGU9ci5TeW50YXguTGl0ZXJhbCx0aGlzLnZhbHVlPWUsdGhpcy5yYXc9dCx0aGlzLnJlZ2V4PXtwYXR0ZXJuOm4sZmxhZ3M6aX19cmV0dXJuIGV9KCk7dC5SZWdleExpdGVyYWw9Wjt2YXIgZWU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMudHlwZT1yLlN5bnRheC5SZXN0RWxlbWVudCx0aGlzLmFyZ3VtZW50PWV9cmV0dXJuIGV9KCk7dC5SZXN0RWxlbWVudD1lZTt2YXIgdGU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUpe3RoaXMudHlwZT1yLlN5bnRheC5SZXR1cm5TdGF0ZW1lbnQsdGhpcy5hcmd1bWVudD1lfXJldHVybiBlfSgpO3QuUmV0dXJuU3RhdGVtZW50PXRlO3ZhciBuZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy50eXBlPXIuU3ludGF4LlByb2dyYW0sdGhpcy5ib2R5PWUsdGhpcy5zb3VyY2VUeXBlPSJzY3JpcHQifXJldHVybiBlfSgpO3QuU2NyaXB0PW5lO3ZhciByZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy50eXBlPXIuU3ludGF4LlNlcXVlbmNlRXhwcmVzc2lvbix0aGlzLmV4cHJlc3Npb25zPWV9cmV0dXJuIGV9KCk7dC5TZXF1ZW5jZUV4cHJlc3Npb249cmU7dmFyIGllPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlKXt0aGlzLnR5cGU9ci5TeW50YXguU3ByZWFkRWxlbWVudCx0aGlzLmFyZ3VtZW50PWV9cmV0dXJuIGV9KCk7dC5TcHJlYWRFbGVtZW50PWllO3ZhciBvZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnR5cGU9ci5TeW50YXguTWVtYmVyRXhwcmVzc2lvbix0aGlzLmNvbXB1dGVkPSExLHRoaXMub2JqZWN0PWUsdGhpcy5wcm9wZXJ0eT10fXJldHVybiBlfSgpO3QuU3RhdGljTWVtYmVyRXhwcmVzc2lvbj1vZTt2YXIgYWU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKCl7dGhpcy50eXBlPXIuU3ludGF4LlN1cGVyfXJldHVybiBlfSgpO3QuU3VwZXI9YWU7dmFyIHNlPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLlN5bnRheC5Td2l0Y2hDYXNlLHRoaXMudGVzdD1lLHRoaXMuY29uc2VxdWVudD10fXJldHVybiBlfSgpO3QuU3dpdGNoQ2FzZT1zZTt2YXIgdWU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LlN3aXRjaFN0YXRlbWVudCx0aGlzLmRpc2NyaW1pbmFudD1lLHRoaXMuY2FzZXM9dH1yZXR1cm4gZX0oKTt0LlN3aXRjaFN0YXRlbWVudD11ZTt2YXIgY2U9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbix0aGlzLnRhZz1lLHRoaXMucXVhc2k9dH1yZXR1cm4gZX0oKTt0LlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbj1jZTt2YXIgbGU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LlRlbXBsYXRlRWxlbWVudCx0aGlzLnZhbHVlPWUsdGhpcy50YWlsPXR9cmV0dXJuIGV9KCk7dC5UZW1wbGF0ZUVsZW1lbnQ9bGU7dmFyIHBlPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLlN5bnRheC5UZW1wbGF0ZUxpdGVyYWwsdGhpcy5xdWFzaXM9ZSx0aGlzLmV4cHJlc3Npb25zPXR9cmV0dXJuIGV9KCk7dC5UZW1wbGF0ZUxpdGVyYWw9cGU7dmFyIGZlPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMudHlwZT1yLlN5bnRheC5UaGlzRXhwcmVzc2lvbn1yZXR1cm4gZX0oKTt0LlRoaXNFeHByZXNzaW9uPWZlO3ZhciBkZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSl7dGhpcy50eXBlPXIuU3ludGF4LlRocm93U3RhdGVtZW50LHRoaXMuYXJndW1lbnQ9ZX1yZXR1cm4gZX0oKTt0LlRocm93U3RhdGVtZW50PWRlO3ZhciBoZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0LG4pe3RoaXMudHlwZT1yLlN5bnRheC5UcnlTdGF0ZW1lbnQsdGhpcy5ibG9jaz1lLHRoaXMuaGFuZGxlcj10LHRoaXMuZmluYWxpemVyPW59cmV0dXJuIGV9KCk7dC5UcnlTdGF0ZW1lbnQ9aGU7dmFyIG1lPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLlN5bnRheC5VbmFyeUV4cHJlc3Npb24sdGhpcy5vcGVyYXRvcj1lLHRoaXMuYXJndW1lbnQ9dCx0aGlzLnByZWZpeD0hMH1yZXR1cm4gZX0oKTt0LlVuYXJ5RXhwcmVzc2lvbj1tZTt2YXIgZ2U9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCxuKXt0aGlzLnR5cGU9ci5TeW50YXguVXBkYXRlRXhwcmVzc2lvbix0aGlzLm9wZXJhdG9yPWUsdGhpcy5hcmd1bWVudD10LHRoaXMucHJlZml4PW59cmV0dXJuIGV9KCk7dC5VcGRhdGVFeHByZXNzaW9uPWdlO3ZhciB5ZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnR5cGU9ci5TeW50YXguVmFyaWFibGVEZWNsYXJhdGlvbix0aGlzLmRlY2xhcmF0aW9ucz1lLHRoaXMua2luZD10fXJldHVybiBlfSgpO3QuVmFyaWFibGVEZWNsYXJhdGlvbj15ZTt2YXIgdmU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LlZhcmlhYmxlRGVjbGFyYXRvcix0aGlzLmlkPWUsdGhpcy5pbml0PXR9cmV0dXJuIGV9KCk7dC5WYXJpYWJsZURlY2xhcmF0b3I9dmU7dmFyIGJlPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQpe3RoaXMudHlwZT1yLlN5bnRheC5XaGlsZVN0YXRlbWVudCx0aGlzLnRlc3Q9ZSx0aGlzLmJvZHk9dH1yZXR1cm4gZX0oKTt0LldoaWxlU3RhdGVtZW50PWJlO3ZhciB4ZT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnR5cGU9ci5TeW50YXguV2l0aFN0YXRlbWVudCx0aGlzLm9iamVjdD1lLHRoaXMuYm9keT10fXJldHVybiBlfSgpO3QuV2l0aFN0YXRlbWVudD14ZTt2YXIgQ2U9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy50eXBlPXIuU3ludGF4LllpZWxkRXhwcmVzc2lvbix0aGlzLmFyZ3VtZW50PWUsdGhpcy5kZWxlZ2F0ZT10fXJldHVybiBlfSgpO3QuWWllbGRFeHByZXNzaW9uPUNlfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgcj1uKDkpLGk9bigxMCksbz1uKDExKSxhPW4oNykscz1uKDEyKSx1PW4oMiksYz1uKDEzKSxsPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZShlLHQsbil7dm9pZCAwPT09dCYmKHQ9e30pLHRoaXMuY29uZmlnPXtyYW5nZToiYm9vbGVhbiI9PT10eXBlb2YgdC5yYW5nZSYmdC5yYW5nZSxsb2M6ImJvb2xlYW4iPT09dHlwZW9mIHQubG9jJiZ0LmxvYyxzb3VyY2U6bnVsbCx0b2tlbnM6ImJvb2xlYW4iPT09dHlwZW9mIHQudG9rZW5zJiZ0LnRva2Vucyxjb21tZW50OiJib29sZWFuIj09PXR5cGVvZiB0LmNvbW1lbnQmJnQuY29tbWVudCx0b2xlcmFudDoiYm9vbGVhbiI9PT10eXBlb2YgdC50b2xlcmFudCYmdC50b2xlcmFudH0sdGhpcy5jb25maWcubG9jJiZ0LnNvdXJjZSYmbnVsbCE9PXQuc291cmNlJiYodGhpcy5jb25maWcuc291cmNlPVN0cmluZyh0LnNvdXJjZSkpLHRoaXMuZGVsZWdhdGU9bix0aGlzLmVycm9ySGFuZGxlcj1uZXcgaS5FcnJvckhhbmRsZXIsdGhpcy5lcnJvckhhbmRsZXIudG9sZXJhbnQ9dGhpcy5jb25maWcudG9sZXJhbnQsdGhpcy5zY2FubmVyPW5ldyBzLlNjYW5uZXIoZSx0aGlzLmVycm9ySGFuZGxlciksdGhpcy5zY2FubmVyLnRyYWNrQ29tbWVudD10aGlzLmNvbmZpZy5jb21tZW50LHRoaXMub3BlcmF0b3JQcmVjZWRlbmNlPXsiKSI6MCwiOyI6MCwiLCI6MCwiPSI6MCwiXSI6MCwifHwiOjEsIiYmIjoyLCJ8IjozLCJeIjo0LCImIjo1LCI9PSI6NiwiIT0iOjYsIj09PSI6NiwiIT09Ijo2LCI8Ijo3LCI+Ijo3LCI8PSI6NywiPj0iOjcsIjw8Ijo4LCI+PiI6OCwiPj4+Ijo4LCIrIjo5LCItIjo5LCIqIjoxMSwiLyI6MTEsIiUiOjExfSx0aGlzLmxvb2thaGVhZD17dHlwZToyLHZhbHVlOiIiLGxpbmVOdW1iZXI6dGhpcy5zY2FubmVyLmxpbmVOdW1iZXIsbGluZVN0YXJ0OjAsc3RhcnQ6MCxlbmQ6MH0sdGhpcy5oYXNMaW5lVGVybWluYXRvcj0hMSx0aGlzLmNvbnRleHQ9e2lzTW9kdWxlOiExLGF3YWl0OiExLGFsbG93SW46ITAsYWxsb3dTdHJpY3REaXJlY3RpdmU6ITAsYWxsb3dZaWVsZDohMCxmaXJzdENvdmVySW5pdGlhbGl6ZWROYW1lRXJyb3I6bnVsbCxpc0Fzc2lnbm1lbnRUYXJnZXQ6ITEsaXNCaW5kaW5nRWxlbWVudDohMSxpbkZ1bmN0aW9uQm9keTohMSxpbkl0ZXJhdGlvbjohMSxpblN3aXRjaDohMSxsYWJlbFNldDp7fSxzdHJpY3Q6ITF9LHRoaXMudG9rZW5zPVtdLHRoaXMuc3RhcnRNYXJrZXI9e2luZGV4OjAsbGluZTp0aGlzLnNjYW5uZXIubGluZU51bWJlcixjb2x1bW46MH0sdGhpcy5sYXN0TWFya2VyPXtpbmRleDowLGxpbmU6dGhpcy5zY2FubmVyLmxpbmVOdW1iZXIsY29sdW1uOjB9LHRoaXMubmV4dFRva2VuKCksdGhpcy5sYXN0TWFya2VyPXtpbmRleDp0aGlzLnNjYW5uZXIuaW5kZXgsbGluZTp0aGlzLnNjYW5uZXIubGluZU51bWJlcixjb2x1bW46dGhpcy5zY2FubmVyLmluZGV4LXRoaXMuc2Nhbm5lci5saW5lU3RhcnR9fXJldHVybiBlLnByb3RvdHlwZS50aHJvd0Vycm9yPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD1bXSxuPTE7bjxhcmd1bWVudHMubGVuZ3RoO24rKyl0W24tMV09YXJndW1lbnRzW25dO3ZhciBpPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywxKSxvPWUucmVwbGFjZSgvJShcZCkvZyxmdW5jdGlvbihlLHQpe3JldHVybiByLmFzc2VydCh0PGkubGVuZ3RoLCJNZXNzYWdlIHJlZmVyZW5jZSBtdXN0IGJlIGluIHJhbmdlIiksaVt0XX0pLGE9dGhpcy5sYXN0TWFya2VyLmluZGV4LHM9dGhpcy5sYXN0TWFya2VyLmxpbmUsdT10aGlzLmxhc3RNYXJrZXIuY29sdW1uKzE7dGhyb3cgdGhpcy5lcnJvckhhbmRsZXIuY3JlYXRlRXJyb3IoYSxzLHUsbyl9LGUucHJvdG90eXBlLnRvbGVyYXRlRXJyb3I9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PVtdLG49MTtuPGFyZ3VtZW50cy5sZW5ndGg7bisrKXRbbi0xXT1hcmd1bWVudHNbbl07dmFyIGk9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLDEpLG89ZS5yZXBsYWNlKC8lKFxkKS9nLGZ1bmN0aW9uKGUsdCl7cmV0dXJuIHIuYXNzZXJ0KHQ8aS5sZW5ndGgsIk1lc3NhZ2UgcmVmZXJlbmNlIG11c3QgYmUgaW4gcmFuZ2UiKSxpW3RdfSksYT10aGlzLmxhc3RNYXJrZXIuaW5kZXgscz10aGlzLnNjYW5uZXIubGluZU51bWJlcix1PXRoaXMubGFzdE1hcmtlci5jb2x1bW4rMTt0aGlzLmVycm9ySGFuZGxlci50b2xlcmF0ZUVycm9yKGEscyx1LG8pfSxlLnByb3RvdHlwZS51bmV4cGVjdGVkVG9rZW5FcnJvcj1mdW5jdGlvbihlLHQpe3ZhciBuLHI9dHx8by5NZXNzYWdlcy5VbmV4cGVjdGVkVG9rZW47aWYoZT8odHx8KHI9Mj09PWUudHlwZT9vLk1lc3NhZ2VzLlVuZXhwZWN0ZWRFT1M6Mz09PWUudHlwZT9vLk1lc3NhZ2VzLlVuZXhwZWN0ZWRJZGVudGlmaWVyOjY9PT1lLnR5cGU/by5NZXNzYWdlcy5VbmV4cGVjdGVkTnVtYmVyOjg9PT1lLnR5cGU/by5NZXNzYWdlcy5VbmV4cGVjdGVkU3RyaW5nOjEwPT09ZS50eXBlP28uTWVzc2FnZXMuVW5leHBlY3RlZFRlbXBsYXRlOm8uTWVzc2FnZXMuVW5leHBlY3RlZFRva2VuLDQ9PT1lLnR5cGUmJih0aGlzLnNjYW5uZXIuaXNGdXR1cmVSZXNlcnZlZFdvcmQoZS52YWx1ZSk/cj1vLk1lc3NhZ2VzLlVuZXhwZWN0ZWRSZXNlcnZlZDp0aGlzLmNvbnRleHQuc3RyaWN0JiZ0aGlzLnNjYW5uZXIuaXNTdHJpY3RNb2RlUmVzZXJ2ZWRXb3JkKGUudmFsdWUpJiYocj1vLk1lc3NhZ2VzLlN0cmljdFJlc2VydmVkV29yZCkpKSxuPWUudmFsdWUpOm49IklMTEVHQUwiLHI9ci5yZXBsYWNlKCIlMCIsbiksZSYmIm51bWJlciI9PT10eXBlb2YgZS5saW5lTnVtYmVyKXt2YXIgaT1lLnN0YXJ0LGE9ZS5saW5lTnVtYmVyLHM9dGhpcy5sYXN0TWFya2VyLmluZGV4LXRoaXMubGFzdE1hcmtlci5jb2x1bW4sdT1lLnN0YXJ0LXMrMTtyZXR1cm4gdGhpcy5lcnJvckhhbmRsZXIuY3JlYXRlRXJyb3IoaSxhLHUscil9dmFyIGk9dGhpcy5sYXN0TWFya2VyLmluZGV4LGE9dGhpcy5sYXN0TWFya2VyLmxpbmUsdT10aGlzLmxhc3RNYXJrZXIuY29sdW1uKzE7cmV0dXJuIHRoaXMuZXJyb3JIYW5kbGVyLmNyZWF0ZUVycm9yKGksYSx1LHIpfSxlLnByb3RvdHlwZS50aHJvd1VuZXhwZWN0ZWRUb2tlbj1mdW5jdGlvbihlLHQpe3Rocm93IHRoaXMudW5leHBlY3RlZFRva2VuRXJyb3IoZSx0KX0sZS5wcm90b3R5cGUudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW49ZnVuY3Rpb24oZSx0KXt0aGlzLmVycm9ySGFuZGxlci50b2xlcmF0ZSh0aGlzLnVuZXhwZWN0ZWRUb2tlbkVycm9yKGUsdCkpfSxlLnByb3RvdHlwZS5jb2xsZWN0Q29tbWVudHM9ZnVuY3Rpb24oKXtpZih0aGlzLmNvbmZpZy5jb21tZW50KXt2YXIgZT10aGlzLnNjYW5uZXIuc2NhbkNvbW1lbnRzKCk7aWYoZS5sZW5ndGg+MCYmdGhpcy5kZWxlZ2F0ZSlmb3IodmFyIHQ9MDt0PGUubGVuZ3RoOysrdCl7dmFyIG49ZVt0XSxyPXZvaWQgMDtyPXt0eXBlOm4ubXVsdGlMaW5lPyJCbG9ja0NvbW1lbnQiOiJMaW5lQ29tbWVudCIsdmFsdWU6dGhpcy5zY2FubmVyLnNvdXJjZS5zbGljZShuLnNsaWNlWzBdLG4uc2xpY2VbMV0pfSx0aGlzLmNvbmZpZy5yYW5nZSYmKHIucmFuZ2U9bi5yYW5nZSksdGhpcy5jb25maWcubG9jJiYoci5sb2M9bi5sb2MpO3ZhciBpPXtzdGFydDp7bGluZTpuLmxvYy5zdGFydC5saW5lLGNvbHVtbjpuLmxvYy5zdGFydC5jb2x1bW4sb2Zmc2V0Om4ucmFuZ2VbMF19LGVuZDp7bGluZTpuLmxvYy5lbmQubGluZSxjb2x1bW46bi5sb2MuZW5kLmNvbHVtbixvZmZzZXQ6bi5yYW5nZVsxXX19O3RoaXMuZGVsZWdhdGUocixpKX19ZWxzZSB0aGlzLnNjYW5uZXIuc2NhbkNvbW1lbnRzKCl9LGUucHJvdG90eXBlLmdldFRva2VuUmF3PWZ1bmN0aW9uKGUpe3JldHVybiB0aGlzLnNjYW5uZXIuc291cmNlLnNsaWNlKGUuc3RhcnQsZS5lbmQpfSxlLnByb3RvdHlwZS5jb252ZXJ0VG9rZW49ZnVuY3Rpb24oZSl7dmFyIHQ9e3R5cGU6Yy5Ub2tlbk5hbWVbZS50eXBlXSx2YWx1ZTp0aGlzLmdldFRva2VuUmF3KGUpfTtpZih0aGlzLmNvbmZpZy5yYW5nZSYmKHQucmFuZ2U9W2Uuc3RhcnQsZS5lbmRdKSx0aGlzLmNvbmZpZy5sb2MmJih0LmxvYz17c3RhcnQ6e2xpbmU6dGhpcy5zdGFydE1hcmtlci5saW5lLGNvbHVtbjp0aGlzLnN0YXJ0TWFya2VyLmNvbHVtbn0sZW5kOntsaW5lOnRoaXMuc2Nhbm5lci5saW5lTnVtYmVyLGNvbHVtbjp0aGlzLnNjYW5uZXIuaW5kZXgtdGhpcy5zY2FubmVyLmxpbmVTdGFydH19KSw5PT09ZS50eXBlKXt2YXIgbj1lLnBhdHRlcm4scj1lLmZsYWdzO3QucmVnZXg9e3BhdHRlcm46bixmbGFnczpyfX1yZXR1cm4gdH0sZS5wcm90b3R5cGUubmV4dFRva2VuPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5sb29rYWhlYWQ7dGhpcy5sYXN0TWFya2VyLmluZGV4PXRoaXMuc2Nhbm5lci5pbmRleCx0aGlzLmxhc3RNYXJrZXIubGluZT10aGlzLnNjYW5uZXIubGluZU51bWJlcix0aGlzLmxhc3RNYXJrZXIuY29sdW1uPXRoaXMuc2Nhbm5lci5pbmRleC10aGlzLnNjYW5uZXIubGluZVN0YXJ0LHRoaXMuY29sbGVjdENvbW1lbnRzKCksdGhpcy5zY2FubmVyLmluZGV4IT09dGhpcy5zdGFydE1hcmtlci5pbmRleCYmKHRoaXMuc3RhcnRNYXJrZXIuaW5kZXg9dGhpcy5zY2FubmVyLmluZGV4LHRoaXMuc3RhcnRNYXJrZXIubGluZT10aGlzLnNjYW5uZXIubGluZU51bWJlcix0aGlzLnN0YXJ0TWFya2VyLmNvbHVtbj10aGlzLnNjYW5uZXIuaW5kZXgtdGhpcy5zY2FubmVyLmxpbmVTdGFydCk7dmFyIHQ9dGhpcy5zY2FubmVyLmxleCgpO3JldHVybiB0aGlzLmhhc0xpbmVUZXJtaW5hdG9yPWUubGluZU51bWJlciE9PXQubGluZU51bWJlcix0JiZ0aGlzLmNvbnRleHQuc3RyaWN0JiYzPT09dC50eXBlJiZ0aGlzLnNjYW5uZXIuaXNTdHJpY3RNb2RlUmVzZXJ2ZWRXb3JkKHQudmFsdWUpJiYodC50eXBlPTQpLHRoaXMubG9va2FoZWFkPXQsdGhpcy5jb25maWcudG9rZW5zJiYyIT09dC50eXBlJiZ0aGlzLnRva2Vucy5wdXNoKHRoaXMuY29udmVydFRva2VuKHQpKSxlfSxlLnByb3RvdHlwZS5uZXh0UmVnZXhUb2tlbj1mdW5jdGlvbigpe3RoaXMuY29sbGVjdENvbW1lbnRzKCk7dmFyIGU9dGhpcy5zY2FubmVyLnNjYW5SZWdFeHAoKTtyZXR1cm4gdGhpcy5jb25maWcudG9rZW5zJiYodGhpcy50b2tlbnMucG9wKCksdGhpcy50b2tlbnMucHVzaCh0aGlzLmNvbnZlcnRUb2tlbihlKSkpLHRoaXMubG9va2FoZWFkPWUsdGhpcy5uZXh0VG9rZW4oKSxlfSxlLnByb3RvdHlwZS5jcmVhdGVOb2RlPWZ1bmN0aW9uKCl7cmV0dXJue2luZGV4OnRoaXMuc3RhcnRNYXJrZXIuaW5kZXgsbGluZTp0aGlzLnN0YXJ0TWFya2VyLmxpbmUsY29sdW1uOnRoaXMuc3RhcnRNYXJrZXIuY29sdW1ufX0sZS5wcm90b3R5cGUuc3RhcnROb2RlPWZ1bmN0aW9uKGUpe3JldHVybntpbmRleDplLnN0YXJ0LGxpbmU6ZS5saW5lTnVtYmVyLGNvbHVtbjplLnN0YXJ0LWUubGluZVN0YXJ0fX0sZS5wcm90b3R5cGUuZmluYWxpemU9ZnVuY3Rpb24oZSx0KXtpZih0aGlzLmNvbmZpZy5yYW5nZSYmKHQucmFuZ2U9W2UuaW5kZXgsdGhpcy5sYXN0TWFya2VyLmluZGV4XSksdGhpcy5jb25maWcubG9jJiYodC5sb2M9e3N0YXJ0OntsaW5lOmUubGluZSxjb2x1bW46ZS5jb2x1bW59LGVuZDp7bGluZTp0aGlzLmxhc3RNYXJrZXIubGluZSxjb2x1bW46dGhpcy5sYXN0TWFya2VyLmNvbHVtbn19LHRoaXMuY29uZmlnLnNvdXJjZSYmKHQubG9jLnNvdXJjZT10aGlzLmNvbmZpZy5zb3VyY2UpKSx0aGlzLmRlbGVnYXRlKXt2YXIgbj17c3RhcnQ6e2xpbmU6ZS5saW5lLGNvbHVtbjplLmNvbHVtbixvZmZzZXQ6ZS5pbmRleH0sZW5kOntsaW5lOnRoaXMubGFzdE1hcmtlci5saW5lLGNvbHVtbjp0aGlzLmxhc3RNYXJrZXIuY29sdW1uLG9mZnNldDp0aGlzLmxhc3RNYXJrZXIuaW5kZXh9fTt0aGlzLmRlbGVnYXRlKHQsbil9cmV0dXJuIHR9LGUucHJvdG90eXBlLmV4cGVjdD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLm5leHRUb2tlbigpOzc9PT10LnR5cGUmJnQudmFsdWU9PT1lfHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHQpfSxlLnByb3RvdHlwZS5leHBlY3RDb21tYVNlcGFyYXRvcj1mdW5jdGlvbigpe2lmKHRoaXMuY29uZmlnLnRvbGVyYW50KXt2YXIgZT10aGlzLmxvb2thaGVhZDs3PT09ZS50eXBlJiYiLCI9PT1lLnZhbHVlP3RoaXMubmV4dFRva2VuKCk6Nz09PWUudHlwZSYmIjsiPT09ZS52YWx1ZT8odGhpcy5uZXh0VG9rZW4oKSx0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKGUpKTp0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKGUsby5NZXNzYWdlcy5VbmV4cGVjdGVkVG9rZW4pfWVsc2UgdGhpcy5leHBlY3QoIiwiKX0sZS5wcm90b3R5cGUuZXhwZWN0S2V5d29yZD1mdW5jdGlvbihlKXt2YXIgdD10aGlzLm5leHRUb2tlbigpOzQ9PT10LnR5cGUmJnQudmFsdWU9PT1lfHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHQpfSxlLnByb3RvdHlwZS5tYXRjaD1mdW5jdGlvbihlKXtyZXR1cm4gNz09PXRoaXMubG9va2FoZWFkLnR5cGUmJnRoaXMubG9va2FoZWFkLnZhbHVlPT09ZX0sZS5wcm90b3R5cGUubWF0Y2hLZXl3b3JkPWZ1bmN0aW9uKGUpe3JldHVybiA0PT09dGhpcy5sb29rYWhlYWQudHlwZSYmdGhpcy5sb29rYWhlYWQudmFsdWU9PT1lfSxlLnByb3RvdHlwZS5tYXRjaENvbnRleHR1YWxLZXl3b3JkPWZ1bmN0aW9uKGUpe3JldHVybiAzPT09dGhpcy5sb29rYWhlYWQudHlwZSYmdGhpcy5sb29rYWhlYWQudmFsdWU9PT1lfSxlLnByb3RvdHlwZS5tYXRjaEFzc2lnbj1mdW5jdGlvbigpe2lmKDchPT10aGlzLmxvb2thaGVhZC50eXBlKXJldHVybiExO3ZhciBlPXRoaXMubG9va2FoZWFkLnZhbHVlO3JldHVybiI9Ij09PWV8fCIqPSI9PT1lfHwiKio9Ij09PWV8fCIvPSI9PT1lfHwiJT0iPT09ZXx8Iis9Ij09PWV8fCItPSI9PT1lfHwiPDw9Ij09PWV8fCI+Pj0iPT09ZXx8Ij4+Pj0iPT09ZXx8IiY9Ij09PWV8fCJePSI9PT1lfHwifD0iPT09ZX0sZS5wcm90b3R5cGUuaXNvbGF0ZUNvdmVyR3JhbW1hcj1mdW5jdGlvbihlKXt2YXIgdD10aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudCxuPXRoaXMuY29udGV4dC5pc0Fzc2lnbm1lbnRUYXJnZXQscj10aGlzLmNvbnRleHQuZmlyc3RDb3ZlckluaXRpYWxpemVkTmFtZUVycm9yO3RoaXMuY29udGV4dC5pc0JpbmRpbmdFbGVtZW50PSEwLHRoaXMuY29udGV4dC5pc0Fzc2lnbm1lbnRUYXJnZXQ9ITAsdGhpcy5jb250ZXh0LmZpcnN0Q292ZXJJbml0aWFsaXplZE5hbWVFcnJvcj1udWxsO3ZhciBpPWUuY2FsbCh0aGlzKTtyZXR1cm4gbnVsbCE9PXRoaXMuY29udGV4dC5maXJzdENvdmVySW5pdGlhbGl6ZWROYW1lRXJyb3ImJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odGhpcy5jb250ZXh0LmZpcnN0Q292ZXJJbml0aWFsaXplZE5hbWVFcnJvciksdGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQ9dCx0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0PW4sdGhpcy5jb250ZXh0LmZpcnN0Q292ZXJJbml0aWFsaXplZE5hbWVFcnJvcj1yLGl9LGUucHJvdG90eXBlLmluaGVyaXRDb3ZlckdyYW1tYXI9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQsbj10aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0LHI9dGhpcy5jb250ZXh0LmZpcnN0Q292ZXJJbml0aWFsaXplZE5hbWVFcnJvcjt0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMCx0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0PSEwLHRoaXMuY29udGV4dC5maXJzdENvdmVySW5pdGlhbGl6ZWROYW1lRXJyb3I9bnVsbDt2YXIgaT1lLmNhbGwodGhpcyk7cmV0dXJuIHRoaXMuY29udGV4dC5pc0JpbmRpbmdFbGVtZW50PXRoaXMuY29udGV4dC5pc0JpbmRpbmdFbGVtZW50JiZ0LHRoaXMuY29udGV4dC5pc0Fzc2lnbm1lbnRUYXJnZXQ9dGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldCYmbix0aGlzLmNvbnRleHQuZmlyc3RDb3ZlckluaXRpYWxpemVkTmFtZUVycm9yPXJ8fHRoaXMuY29udGV4dC5maXJzdENvdmVySW5pdGlhbGl6ZWROYW1lRXJyb3IsaX0sZS5wcm90b3R5cGUuY29uc3VtZVNlbWljb2xvbj1mdW5jdGlvbigpe3RoaXMubWF0Y2goIjsiKT90aGlzLm5leHRUb2tlbigpOnRoaXMuaGFzTGluZVRlcm1pbmF0b3J8fCgyPT09dGhpcy5sb29rYWhlYWQudHlwZXx8dGhpcy5tYXRjaCgifSIpfHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHRoaXMubG9va2FoZWFkKSx0aGlzLmxhc3RNYXJrZXIuaW5kZXg9dGhpcy5zdGFydE1hcmtlci5pbmRleCx0aGlzLmxhc3RNYXJrZXIubGluZT10aGlzLnN0YXJ0TWFya2VyLmxpbmUsdGhpcy5sYXN0TWFya2VyLmNvbHVtbj10aGlzLnN0YXJ0TWFya2VyLmNvbHVtbil9LGUucHJvdG90eXBlLnBhcnNlUHJpbWFyeUV4cHJlc3Npb249ZnVuY3Rpb24oKXt2YXIgZSx0LG4scj10aGlzLmNyZWF0ZU5vZGUoKTtzd2l0Y2godGhpcy5sb29rYWhlYWQudHlwZSl7Y2FzZSAzOih0aGlzLmNvbnRleHQuaXNNb2R1bGV8fHRoaXMuY29udGV4dC5hd2FpdCkmJiJhd2FpdCI9PT10aGlzLmxvb2thaGVhZC52YWx1ZSYmdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbih0aGlzLmxvb2thaGVhZCksZT10aGlzLm1hdGNoQXN5bmNGdW5jdGlvbigpP3RoaXMucGFyc2VGdW5jdGlvbkV4cHJlc3Npb24oKTp0aGlzLmZpbmFsaXplKHIsbmV3IGEuSWRlbnRpZmllcih0aGlzLm5leHRUb2tlbigpLnZhbHVlKSk7YnJlYWs7Y2FzZSA2OmNhc2UgODp0aGlzLmNvbnRleHQuc3RyaWN0JiZ0aGlzLmxvb2thaGVhZC5vY3RhbCYmdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbih0aGlzLmxvb2thaGVhZCxvLk1lc3NhZ2VzLlN0cmljdE9jdGFsTGl0ZXJhbCksdGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMSx0PXRoaXMubmV4dFRva2VuKCksbj10aGlzLmdldFRva2VuUmF3KHQpLGU9dGhpcy5maW5hbGl6ZShyLG5ldyBhLkxpdGVyYWwodC52YWx1ZSxuKSk7YnJlYWs7Y2FzZSAxOnRoaXMuY29udGV4dC5pc0Fzc2lnbm1lbnRUYXJnZXQ9ITEsdGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQ9ITEsdD10aGlzLm5leHRUb2tlbigpLG49dGhpcy5nZXRUb2tlblJhdyh0KSxlPXRoaXMuZmluYWxpemUocixuZXcgYS5MaXRlcmFsKCJ0cnVlIj09PXQudmFsdWUsbikpO2JyZWFrO2Nhc2UgNTp0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0PSExLHRoaXMuY29udGV4dC5pc0JpbmRpbmdFbGVtZW50PSExLHQ9dGhpcy5uZXh0VG9rZW4oKSxuPXRoaXMuZ2V0VG9rZW5SYXcodCksZT10aGlzLmZpbmFsaXplKHIsbmV3IGEuTGl0ZXJhbChudWxsLG4pKTticmVhaztjYXNlIDEwOmU9dGhpcy5wYXJzZVRlbXBsYXRlTGl0ZXJhbCgpO2JyZWFrO2Nhc2UgNzpzd2l0Y2godGhpcy5sb29rYWhlYWQudmFsdWUpe2Nhc2UiKCI6dGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQ9ITEsZT10aGlzLmluaGVyaXRDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUdyb3VwRXhwcmVzc2lvbik7YnJlYWs7Y2FzZSJbIjplPXRoaXMuaW5oZXJpdENvdmVyR3JhbW1hcih0aGlzLnBhcnNlQXJyYXlJbml0aWFsaXplcik7YnJlYWs7Y2FzZSJ7IjplPXRoaXMuaW5oZXJpdENvdmVyR3JhbW1hcih0aGlzLnBhcnNlT2JqZWN0SW5pdGlhbGl6ZXIpO2JyZWFrO2Nhc2UiLyI6Y2FzZSIvPSI6dGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMSx0aGlzLnNjYW5uZXIuaW5kZXg9dGhpcy5zdGFydE1hcmtlci5pbmRleCx0PXRoaXMubmV4dFJlZ2V4VG9rZW4oKSxuPXRoaXMuZ2V0VG9rZW5SYXcodCksZT10aGlzLmZpbmFsaXplKHIsbmV3IGEuUmVnZXhMaXRlcmFsKHQucmVnZXgsbix0LnBhdHRlcm4sdC5mbGFncykpO2JyZWFrO2RlZmF1bHQ6ZT10aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHRoaXMubmV4dFRva2VuKCkpfWJyZWFrO2Nhc2UgNDohdGhpcy5jb250ZXh0LnN0cmljdCYmdGhpcy5jb250ZXh0LmFsbG93WWllbGQmJnRoaXMubWF0Y2hLZXl3b3JkKCJ5aWVsZCIpP2U9dGhpcy5wYXJzZUlkZW50aWZpZXJOYW1lKCk6IXRoaXMuY29udGV4dC5zdHJpY3QmJnRoaXMubWF0Y2hLZXl3b3JkKCJsZXQiKT9lPXRoaXMuZmluYWxpemUocixuZXcgYS5JZGVudGlmaWVyKHRoaXMubmV4dFRva2VuKCkudmFsdWUpKToodGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMSx0aGlzLm1hdGNoS2V5d29yZCgiZnVuY3Rpb24iKT9lPXRoaXMucGFyc2VGdW5jdGlvbkV4cHJlc3Npb24oKTp0aGlzLm1hdGNoS2V5d29yZCgidGhpcyIpPyh0aGlzLm5leHRUb2tlbigpLGU9dGhpcy5maW5hbGl6ZShyLG5ldyBhLlRoaXNFeHByZXNzaW9uKSk6ZT10aGlzLm1hdGNoS2V5d29yZCgiY2xhc3MiKT90aGlzLnBhcnNlQ2xhc3NFeHByZXNzaW9uKCk6dGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0aGlzLm5leHRUb2tlbigpKSk7YnJlYWs7ZGVmYXVsdDplPXRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odGhpcy5uZXh0VG9rZW4oKSl9cmV0dXJuIGV9LGUucHJvdG90eXBlLnBhcnNlU3ByZWFkRWxlbWVudD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpO3RoaXMuZXhwZWN0KCIuLi4iKTt2YXIgdD10aGlzLmluaGVyaXRDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKTtyZXR1cm4gdGhpcy5maW5hbGl6ZShlLG5ldyBhLlNwcmVhZEVsZW1lbnQodCkpfSxlLnByb3RvdHlwZS5wYXJzZUFycmF5SW5pdGlhbGl6ZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKSx0PVtdO2Zvcih0aGlzLmV4cGVjdCgiWyIpOyF0aGlzLm1hdGNoKCJdIik7KWlmKHRoaXMubWF0Y2goIiwiKSl0aGlzLm5leHRUb2tlbigpLHQucHVzaChudWxsKTtlbHNlIGlmKHRoaXMubWF0Y2goIi4uLiIpKXt2YXIgbj10aGlzLnBhcnNlU3ByZWFkRWxlbWVudCgpO3RoaXMubWF0Y2goIl0iKXx8KHRoaXMuY29udGV4dC5pc0Fzc2lnbm1lbnRUYXJnZXQ9ITEsdGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQ9ITEsdGhpcy5leHBlY3QoIiwiKSksdC5wdXNoKG4pfWVsc2UgdC5wdXNoKHRoaXMuaW5oZXJpdENvdmVyR3JhbW1hcih0aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24pKSx0aGlzLm1hdGNoKCJdIil8fHRoaXMuZXhwZWN0KCIsIik7cmV0dXJuIHRoaXMuZXhwZWN0KCJdIiksdGhpcy5maW5hbGl6ZShlLG5ldyBhLkFycmF5RXhwcmVzc2lvbih0KSl9LGUucHJvdG90eXBlLnBhcnNlUHJvcGVydHlNZXRob2Q9ZnVuY3Rpb24oZSl7dGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMTt2YXIgdD10aGlzLmNvbnRleHQuc3RyaWN0LG49dGhpcy5jb250ZXh0LmFsbG93U3RyaWN0RGlyZWN0aXZlO3RoaXMuY29udGV4dC5hbGxvd1N0cmljdERpcmVjdGl2ZT1lLnNpbXBsZTt2YXIgcj10aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUZ1bmN0aW9uU291cmNlRWxlbWVudHMpO3JldHVybiB0aGlzLmNvbnRleHQuc3RyaWN0JiZlLmZpcnN0UmVzdHJpY3RlZCYmdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbihlLmZpcnN0UmVzdHJpY3RlZCxlLm1lc3NhZ2UpLHRoaXMuY29udGV4dC5zdHJpY3QmJmUuc3RyaWN0ZWQmJnRoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4oZS5zdHJpY3RlZCxlLm1lc3NhZ2UpLHRoaXMuY29udGV4dC5zdHJpY3Q9dCx0aGlzLmNvbnRleHQuYWxsb3dTdHJpY3REaXJlY3RpdmU9bixyfSxlLnByb3RvdHlwZS5wYXJzZVByb3BlcnR5TWV0aG9kRnVuY3Rpb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKSx0PXRoaXMuY29udGV4dC5hbGxvd1lpZWxkO3RoaXMuY29udGV4dC5hbGxvd1lpZWxkPSExO3ZhciBuPXRoaXMucGFyc2VGb3JtYWxQYXJhbWV0ZXJzKCkscj10aGlzLnBhcnNlUHJvcGVydHlNZXRob2Qobik7cmV0dXJuIHRoaXMuY29udGV4dC5hbGxvd1lpZWxkPXQsdGhpcy5maW5hbGl6ZShlLG5ldyBhLkZ1bmN0aW9uRXhwcmVzc2lvbihudWxsLG4ucGFyYW1zLHIsITEpKX0sZS5wcm90b3R5cGUucGFyc2VQcm9wZXJ0eU1ldGhvZEFzeW5jRnVuY3Rpb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKSx0PXRoaXMuY29udGV4dC5hbGxvd1lpZWxkLG49dGhpcy5jb250ZXh0LmF3YWl0O3RoaXMuY29udGV4dC5hbGxvd1lpZWxkPSExLHRoaXMuY29udGV4dC5hd2FpdD0hMDt2YXIgcj10aGlzLnBhcnNlRm9ybWFsUGFyYW1ldGVycygpLGk9dGhpcy5wYXJzZVByb3BlcnR5TWV0aG9kKHIpO3JldHVybiB0aGlzLmNvbnRleHQuYWxsb3dZaWVsZD10LHRoaXMuY29udGV4dC5hd2FpdD1uLHRoaXMuZmluYWxpemUoZSxuZXcgYS5Bc3luY0Z1bmN0aW9uRXhwcmVzc2lvbihudWxsLHIucGFyYW1zLGkpKX0sZS5wcm90b3R5cGUucGFyc2VPYmplY3RQcm9wZXJ0eUtleT1mdW5jdGlvbigpe3ZhciBlLHQ9dGhpcy5jcmVhdGVOb2RlKCksbj10aGlzLm5leHRUb2tlbigpO3N3aXRjaChuLnR5cGUpe2Nhc2UgODpjYXNlIDY6dGhpcy5jb250ZXh0LnN0cmljdCYmbi5vY3RhbCYmdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbihuLG8uTWVzc2FnZXMuU3RyaWN0T2N0YWxMaXRlcmFsKTt2YXIgcj10aGlzLmdldFRva2VuUmF3KG4pO2U9dGhpcy5maW5hbGl6ZSh0LG5ldyBhLkxpdGVyYWwobi52YWx1ZSxyKSk7YnJlYWs7Y2FzZSAzOmNhc2UgMTpjYXNlIDU6Y2FzZSA0OmU9dGhpcy5maW5hbGl6ZSh0LG5ldyBhLklkZW50aWZpZXIobi52YWx1ZSkpO2JyZWFrO2Nhc2UgNzoiWyI9PT1uLnZhbHVlPyhlPXRoaXMuaXNvbGF0ZUNvdmVyR3JhbW1hcih0aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24pLHRoaXMuZXhwZWN0KCJdIikpOmU9dGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbihuKTticmVhaztkZWZhdWx0OmU9dGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbihuKX1yZXR1cm4gZX0sZS5wcm90b3R5cGUuaXNQcm9wZXJ0eUtleT1mdW5jdGlvbihlLHQpe3JldHVybiBlLnR5cGU9PT11LlN5bnRheC5JZGVudGlmaWVyJiZlLm5hbWU9PT10fHxlLnR5cGU9PT11LlN5bnRheC5MaXRlcmFsJiZlLnZhbHVlPT09dH0sZS5wcm90b3R5cGUucGFyc2VPYmplY3RQcm9wZXJ0eT1mdW5jdGlvbihlKXt2YXIgdCxuPXRoaXMuY3JlYXRlTm9kZSgpLHI9dGhpcy5sb29rYWhlYWQsaT1udWxsLHM9bnVsbCx1PSExLGM9ITEsbD0hMSxwPSExO2lmKDM9PT1yLnR5cGUpe3ZhciBmPXIudmFsdWU7dGhpcy5uZXh0VG9rZW4oKSx1PXRoaXMubWF0Y2goIlsiKSxwPSF0aGlzLmhhc0xpbmVUZXJtaW5hdG9yJiYiYXN5bmMiPT09ZiYmIXRoaXMubWF0Y2goIjoiKSYmIXRoaXMubWF0Y2goIigiKSYmIXRoaXMubWF0Y2goIioiKSxpPXA/dGhpcy5wYXJzZU9iamVjdFByb3BlcnR5S2V5KCk6dGhpcy5maW5hbGl6ZShuLG5ldyBhLklkZW50aWZpZXIoZikpfWVsc2UgdGhpcy5tYXRjaCgiKiIpP3RoaXMubmV4dFRva2VuKCk6KHU9dGhpcy5tYXRjaCgiWyIpLGk9dGhpcy5wYXJzZU9iamVjdFByb3BlcnR5S2V5KCkpO3ZhciBkPXRoaXMucXVhbGlmaWVkUHJvcGVydHlOYW1lKHRoaXMubG9va2FoZWFkKTtpZigzPT09ci50eXBlJiYhcCYmImdldCI9PT1yLnZhbHVlJiZkKXQ9ImdldCIsdT10aGlzLm1hdGNoKCJbIiksaT10aGlzLnBhcnNlT2JqZWN0UHJvcGVydHlLZXkoKSx0aGlzLmNvbnRleHQuYWxsb3dZaWVsZD0hMSxzPXRoaXMucGFyc2VHZXR0ZXJNZXRob2QoKTtlbHNlIGlmKDM9PT1yLnR5cGUmJiFwJiYic2V0Ij09PXIudmFsdWUmJmQpdD0ic2V0Iix1PXRoaXMubWF0Y2goIlsiKSxpPXRoaXMucGFyc2VPYmplY3RQcm9wZXJ0eUtleSgpLHM9dGhpcy5wYXJzZVNldHRlck1ldGhvZCgpO2Vsc2UgaWYoNz09PXIudHlwZSYmIioiPT09ci52YWx1ZSYmZCl0PSJpbml0Iix1PXRoaXMubWF0Y2goIlsiKSxpPXRoaXMucGFyc2VPYmplY3RQcm9wZXJ0eUtleSgpLHM9dGhpcy5wYXJzZUdlbmVyYXRvck1ldGhvZCgpLGM9ITA7ZWxzZSBpZihpfHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHRoaXMubG9va2FoZWFkKSx0PSJpbml0Iix0aGlzLm1hdGNoKCI6IikmJiFwKSF1JiZ0aGlzLmlzUHJvcGVydHlLZXkoaSwiX19wcm90b19fIikmJihlLnZhbHVlJiZ0aGlzLnRvbGVyYXRlRXJyb3Ioby5NZXNzYWdlcy5EdXBsaWNhdGVQcm90b1Byb3BlcnR5KSxlLnZhbHVlPSEwKSx0aGlzLm5leHRUb2tlbigpLHM9dGhpcy5pbmhlcml0Q292ZXJHcmFtbWFyKHRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbik7ZWxzZSBpZih0aGlzLm1hdGNoKCIoIikpcz1wP3RoaXMucGFyc2VQcm9wZXJ0eU1ldGhvZEFzeW5jRnVuY3Rpb24oKTp0aGlzLnBhcnNlUHJvcGVydHlNZXRob2RGdW5jdGlvbigpLGM9ITA7ZWxzZSBpZigzPT09ci50eXBlKXt2YXIgZj10aGlzLmZpbmFsaXplKG4sbmV3IGEuSWRlbnRpZmllcihyLnZhbHVlKSk7aWYodGhpcy5tYXRjaCgiPSIpKXt0aGlzLmNvbnRleHQuZmlyc3RDb3ZlckluaXRpYWxpemVkTmFtZUVycm9yPXRoaXMubG9va2FoZWFkLHRoaXMubmV4dFRva2VuKCksbD0hMDt2YXIgaD10aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKTtzPXRoaXMuZmluYWxpemUobixuZXcgYS5Bc3NpZ25tZW50UGF0dGVybihmLGgpKX1lbHNlIGw9ITAscz1mfWVsc2UgdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0aGlzLm5leHRUb2tlbigpKTtyZXR1cm4gdGhpcy5maW5hbGl6ZShuLG5ldyBhLlByb3BlcnR5KHQsaSx1LHMsYyxsKSl9LGUucHJvdG90eXBlLnBhcnNlT2JqZWN0SW5pdGlhbGl6ZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKTt0aGlzLmV4cGVjdCgieyIpO2Zvcih2YXIgdD1bXSxuPXt2YWx1ZTohMX07IXRoaXMubWF0Y2goIn0iKTspdC5wdXNoKHRoaXMucGFyc2VPYmplY3RQcm9wZXJ0eShuKSksdGhpcy5tYXRjaCgifSIpfHx0aGlzLmV4cGVjdENvbW1hU2VwYXJhdG9yKCk7cmV0dXJuIHRoaXMuZXhwZWN0KCJ9IiksdGhpcy5maW5hbGl6ZShlLG5ldyBhLk9iamVjdEV4cHJlc3Npb24odCkpfSxlLnByb3RvdHlwZS5wYXJzZVRlbXBsYXRlSGVhZD1mdW5jdGlvbigpe3IuYXNzZXJ0KHRoaXMubG9va2FoZWFkLmhlYWQsIlRlbXBsYXRlIGxpdGVyYWwgbXVzdCBzdGFydCB3aXRoIGEgdGVtcGxhdGUgaGVhZCIpO3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpLHQ9dGhpcy5uZXh0VG9rZW4oKSxuPXQudmFsdWUsaT10LmNvb2tlZDtyZXR1cm4gdGhpcy5maW5hbGl6ZShlLG5ldyBhLlRlbXBsYXRlRWxlbWVudCh7cmF3Om4sY29va2VkOml9LHQudGFpbCkpfSxlLnByb3RvdHlwZS5wYXJzZVRlbXBsYXRlRWxlbWVudD1mdW5jdGlvbigpezEwIT09dGhpcy5sb29rYWhlYWQudHlwZSYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbigpO3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpLHQ9dGhpcy5uZXh0VG9rZW4oKSxuPXQudmFsdWUscj10LmNvb2tlZDtyZXR1cm4gdGhpcy5maW5hbGl6ZShlLG5ldyBhLlRlbXBsYXRlRWxlbWVudCh7cmF3Om4sY29va2VkOnJ9LHQudGFpbCkpfSxlLnByb3RvdHlwZS5wYXJzZVRlbXBsYXRlTGl0ZXJhbD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpLHQ9W10sbj1bXSxyPXRoaXMucGFyc2VUZW1wbGF0ZUhlYWQoKTtmb3Iobi5wdXNoKHIpOyFyLnRhaWw7KXQucHVzaCh0aGlzLnBhcnNlRXhwcmVzc2lvbigpKSxyPXRoaXMucGFyc2VUZW1wbGF0ZUVsZW1lbnQoKSxuLnB1c2gocik7cmV0dXJuIHRoaXMuZmluYWxpemUoZSxuZXcgYS5UZW1wbGF0ZUxpdGVyYWwobix0KSl9LGUucHJvdG90eXBlLnJlaW50ZXJwcmV0RXhwcmVzc2lvbkFzUGF0dGVybj1mdW5jdGlvbihlKXtzd2l0Y2goZS50eXBlKXtjYXNlIHUuU3ludGF4LklkZW50aWZpZXI6Y2FzZSB1LlN5bnRheC5NZW1iZXJFeHByZXNzaW9uOmNhc2UgdS5TeW50YXguUmVzdEVsZW1lbnQ6Y2FzZSB1LlN5bnRheC5Bc3NpZ25tZW50UGF0dGVybjpicmVhaztjYXNlIHUuU3ludGF4LlNwcmVhZEVsZW1lbnQ6ZS50eXBlPXUuU3ludGF4LlJlc3RFbGVtZW50LHRoaXMucmVpbnRlcnByZXRFeHByZXNzaW9uQXNQYXR0ZXJuKGUuYXJndW1lbnQpO2JyZWFrO2Nhc2UgdS5TeW50YXguQXJyYXlFeHByZXNzaW9uOmUudHlwZT11LlN5bnRheC5BcnJheVBhdHRlcm47Zm9yKHZhciB0PTA7dDxlLmVsZW1lbnRzLmxlbmd0aDt0KyspbnVsbCE9PWUuZWxlbWVudHNbdF0mJnRoaXMucmVpbnRlcnByZXRFeHByZXNzaW9uQXNQYXR0ZXJuKGUuZWxlbWVudHNbdF0pO2JyZWFrO2Nhc2UgdS5TeW50YXguT2JqZWN0RXhwcmVzc2lvbjplLnR5cGU9dS5TeW50YXguT2JqZWN0UGF0dGVybjtmb3IodmFyIHQ9MDt0PGUucHJvcGVydGllcy5sZW5ndGg7dCsrKXRoaXMucmVpbnRlcnByZXRFeHByZXNzaW9uQXNQYXR0ZXJuKGUucHJvcGVydGllc1t0XS52YWx1ZSk7YnJlYWs7Y2FzZSB1LlN5bnRheC5Bc3NpZ25tZW50RXhwcmVzc2lvbjplLnR5cGU9dS5TeW50YXguQXNzaWdubWVudFBhdHRlcm4sZGVsZXRlIGUub3BlcmF0b3IsdGhpcy5yZWludGVycHJldEV4cHJlc3Npb25Bc1BhdHRlcm4oZS5sZWZ0KX19LGUucHJvdG90eXBlLnBhcnNlR3JvdXBFeHByZXNzaW9uPWZ1bmN0aW9uKCl7dmFyIGU7aWYodGhpcy5leHBlY3QoIigiKSx0aGlzLm1hdGNoKCIpIikpdGhpcy5uZXh0VG9rZW4oKSx0aGlzLm1hdGNoKCI9PiIpfHx0aGlzLmV4cGVjdCgiPT4iKSxlPXt0eXBlOiJBcnJvd1BhcmFtZXRlclBsYWNlSG9sZGVyIixwYXJhbXM6W10sYXN5bmM6ITF9O2Vsc2V7dmFyIHQ9dGhpcy5sb29rYWhlYWQsbj1bXTtpZih0aGlzLm1hdGNoKCIuLi4iKSllPXRoaXMucGFyc2VSZXN0RWxlbWVudChuKSx0aGlzLmV4cGVjdCgiKSIpLHRoaXMubWF0Y2goIj0+Iil8fHRoaXMuZXhwZWN0KCI9PiIpLGU9e3R5cGU6IkFycm93UGFyYW1ldGVyUGxhY2VIb2xkZXIiLHBhcmFtczpbZV0sYXN5bmM6ITF9O2Vsc2V7dmFyIHI9ITE7aWYodGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQ9ITAsZT10aGlzLmluaGVyaXRDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKSx0aGlzLm1hdGNoKCIsIikpe3ZhciBpPVtdO2Zvcih0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0PSExLGkucHVzaChlKTsyIT09dGhpcy5sb29rYWhlYWQudHlwZSYmdGhpcy5tYXRjaCgiLCIpOyl7aWYodGhpcy5uZXh0VG9rZW4oKSx0aGlzLm1hdGNoKCIpIikpe3RoaXMubmV4dFRva2VuKCk7Zm9yKHZhciBvPTA7bzxpLmxlbmd0aDtvKyspdGhpcy5yZWludGVycHJldEV4cHJlc3Npb25Bc1BhdHRlcm4oaVtvXSk7cj0hMCxlPXt0eXBlOiJBcnJvd1BhcmFtZXRlclBsYWNlSG9sZGVyIixwYXJhbXM6aSxhc3luYzohMX19ZWxzZSBpZih0aGlzLm1hdGNoKCIuLi4iKSl7dGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnR8fHRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odGhpcy5sb29rYWhlYWQpLGkucHVzaCh0aGlzLnBhcnNlUmVzdEVsZW1lbnQobikpLHRoaXMuZXhwZWN0KCIpIiksdGhpcy5tYXRjaCgiPT4iKXx8dGhpcy5leHBlY3QoIj0+IiksdGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQ9ITE7Zm9yKHZhciBvPTA7bzxpLmxlbmd0aDtvKyspdGhpcy5yZWludGVycHJldEV4cHJlc3Npb25Bc1BhdHRlcm4oaVtvXSk7cj0hMCxlPXt0eXBlOiJBcnJvd1BhcmFtZXRlclBsYWNlSG9sZGVyIixwYXJhbXM6aSxhc3luYzohMX19ZWxzZSBpLnB1c2godGhpcy5pbmhlcml0Q292ZXJHcmFtbWFyKHRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbikpO2lmKHIpYnJlYWt9cnx8KGU9dGhpcy5maW5hbGl6ZSh0aGlzLnN0YXJ0Tm9kZSh0KSxuZXcgYS5TZXF1ZW5jZUV4cHJlc3Npb24oaSkpKX1pZighcil7aWYodGhpcy5leHBlY3QoIikiKSx0aGlzLm1hdGNoKCI9PiIpJiYoZS50eXBlPT09dS5TeW50YXguSWRlbnRpZmllciYmInlpZWxkIj09PWUubmFtZSYmKHI9ITAsZT17dHlwZToiQXJyb3dQYXJhbWV0ZXJQbGFjZUhvbGRlciIscGFyYW1zOltlXSxhc3luYzohMX0pLCFyKSl7aWYodGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnR8fHRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odGhpcy5sb29rYWhlYWQpLGUudHlwZT09PXUuU3ludGF4LlNlcXVlbmNlRXhwcmVzc2lvbilmb3IodmFyIG89MDtvPGUuZXhwcmVzc2lvbnMubGVuZ3RoO28rKyl0aGlzLnJlaW50ZXJwcmV0RXhwcmVzc2lvbkFzUGF0dGVybihlLmV4cHJlc3Npb25zW29dKTtlbHNlIHRoaXMucmVpbnRlcnByZXRFeHByZXNzaW9uQXNQYXR0ZXJuKGUpO2U9e3R5cGU6IkFycm93UGFyYW1ldGVyUGxhY2VIb2xkZXIiLHBhcmFtczplLnR5cGU9PT11LlN5bnRheC5TZXF1ZW5jZUV4cHJlc3Npb24/ZS5leHByZXNzaW9uczpbZV0sYXN5bmM6ITF9fXRoaXMuY29udGV4dC5pc0JpbmRpbmdFbGVtZW50PSExfX19cmV0dXJuIGV9LGUucHJvdG90eXBlLnBhcnNlQXJndW1lbnRzPWZ1bmN0aW9uKCl7dGhpcy5leHBlY3QoIigiKTt2YXIgZT1bXTtpZighdGhpcy5tYXRjaCgiKSIpKWZvcig7Oyl7dmFyIHQ9dGhpcy5tYXRjaCgiLi4uIik/dGhpcy5wYXJzZVNwcmVhZEVsZW1lbnQoKTp0aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKTtpZihlLnB1c2godCksdGhpcy5tYXRjaCgiKSIpKWJyZWFrO2lmKHRoaXMuZXhwZWN0Q29tbWFTZXBhcmF0b3IoKSx0aGlzLm1hdGNoKCIpIikpYnJlYWt9cmV0dXJuIHRoaXMuZXhwZWN0KCIpIiksZX0sZS5wcm90b3R5cGUuaXNJZGVudGlmaWVyTmFtZT1mdW5jdGlvbihlKXtyZXR1cm4gMz09PWUudHlwZXx8ND09PWUudHlwZXx8MT09PWUudHlwZXx8NT09PWUudHlwZX0sZS5wcm90b3R5cGUucGFyc2VJZGVudGlmaWVyTmFtZT1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpLHQ9dGhpcy5uZXh0VG9rZW4oKTtyZXR1cm4gdGhpcy5pc0lkZW50aWZpZXJOYW1lKHQpfHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHQpLHRoaXMuZmluYWxpemUoZSxuZXcgYS5JZGVudGlmaWVyKHQudmFsdWUpKX0sZS5wcm90b3R5cGUucGFyc2VOZXdFeHByZXNzaW9uPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCksdD10aGlzLnBhcnNlSWRlbnRpZmllck5hbWUoKTtyLmFzc2VydCgibmV3Ij09PXQubmFtZSwiTmV3IGV4cHJlc3Npb24gbXVzdCBzdGFydCB3aXRoIGBuZXdgIik7dmFyIG47aWYodGhpcy5tYXRjaCgiLiIpKWlmKHRoaXMubmV4dFRva2VuKCksMz09PXRoaXMubG9va2FoZWFkLnR5cGUmJnRoaXMuY29udGV4dC5pbkZ1bmN0aW9uQm9keSYmInRhcmdldCI9PT10aGlzLmxvb2thaGVhZC52YWx1ZSl7dmFyIGk9dGhpcy5wYXJzZUlkZW50aWZpZXJOYW1lKCk7bj1uZXcgYS5NZXRhUHJvcGVydHkodCxpKX1lbHNlIHRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odGhpcy5sb29rYWhlYWQpO2Vsc2V7dmFyIG89dGhpcy5pc29sYXRlQ292ZXJHcmFtbWFyKHRoaXMucGFyc2VMZWZ0SGFuZFNpZGVFeHByZXNzaW9uKSxzPXRoaXMubWF0Y2goIigiKT90aGlzLnBhcnNlQXJndW1lbnRzKCk6W107bj1uZXcgYS5OZXdFeHByZXNzaW9uKG8scyksdGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMX1yZXR1cm4gdGhpcy5maW5hbGl6ZShlLG4pfSxlLnByb3RvdHlwZS5wYXJzZUFzeW5jQXJndW1lbnQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24oKTtyZXR1cm4gdGhpcy5jb250ZXh0LmZpcnN0Q292ZXJJbml0aWFsaXplZE5hbWVFcnJvcj1udWxsLGV9LGUucHJvdG90eXBlLnBhcnNlQXN5bmNBcmd1bWVudHM9ZnVuY3Rpb24oKXt0aGlzLmV4cGVjdCgiKCIpO3ZhciBlPVtdO2lmKCF0aGlzLm1hdGNoKCIpIikpZm9yKDs7KXt2YXIgdD10aGlzLm1hdGNoKCIuLi4iKT90aGlzLnBhcnNlU3ByZWFkRWxlbWVudCgpOnRoaXMuaXNvbGF0ZUNvdmVyR3JhbW1hcih0aGlzLnBhcnNlQXN5bmNBcmd1bWVudCk7aWYoZS5wdXNoKHQpLHRoaXMubWF0Y2goIikiKSlicmVhaztpZih0aGlzLmV4cGVjdENvbW1hU2VwYXJhdG9yKCksdGhpcy5tYXRjaCgiKSIpKWJyZWFrfXJldHVybiB0aGlzLmV4cGVjdCgiKSIpLGV9LGUucHJvdG90eXBlLnBhcnNlTGVmdEhhbmRTaWRlRXhwcmVzc2lvbkFsbG93Q2FsbD1mdW5jdGlvbigpe3ZhciBlPXRoaXMubG9va2FoZWFkLHQ9dGhpcy5tYXRjaENvbnRleHR1YWxLZXl3b3JkKCJhc3luYyIpLG49dGhpcy5jb250ZXh0LmFsbG93SW47dGhpcy5jb250ZXh0LmFsbG93SW49ITA7dmFyIHI7Zm9yKHRoaXMubWF0Y2hLZXl3b3JkKCJzdXBlciIpJiZ0aGlzLmNvbnRleHQuaW5GdW5jdGlvbkJvZHk/KHI9dGhpcy5jcmVhdGVOb2RlKCksdGhpcy5uZXh0VG9rZW4oKSxyPXRoaXMuZmluYWxpemUocixuZXcgYS5TdXBlciksdGhpcy5tYXRjaCgiKCIpfHx0aGlzLm1hdGNoKCIuIil8fHRoaXMubWF0Y2goIlsiKXx8dGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0aGlzLmxvb2thaGVhZCkpOnI9dGhpcy5pbmhlcml0Q292ZXJHcmFtbWFyKHRoaXMubWF0Y2hLZXl3b3JkKCJuZXciKT90aGlzLnBhcnNlTmV3RXhwcmVzc2lvbjp0aGlzLnBhcnNlUHJpbWFyeUV4cHJlc3Npb24pOzspaWYodGhpcy5tYXRjaCgiLiIpKXt0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMSx0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0PSEwLHRoaXMuZXhwZWN0KCIuIik7dmFyIGk9dGhpcy5wYXJzZUlkZW50aWZpZXJOYW1lKCk7cj10aGlzLmZpbmFsaXplKHRoaXMuc3RhcnROb2RlKGUpLG5ldyBhLlN0YXRpY01lbWJlckV4cHJlc3Npb24ocixpKSl9ZWxzZSBpZih0aGlzLm1hdGNoKCIoIikpe3ZhciBvPXQmJmUubGluZU51bWJlcj09PXRoaXMubG9va2FoZWFkLmxpbmVOdW1iZXI7dGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQ9ITEsdGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMTt2YXIgcz1vP3RoaXMucGFyc2VBc3luY0FyZ3VtZW50cygpOnRoaXMucGFyc2VBcmd1bWVudHMoKTtpZihyPXRoaXMuZmluYWxpemUodGhpcy5zdGFydE5vZGUoZSksbmV3IGEuQ2FsbEV4cHJlc3Npb24ocixzKSksbyYmdGhpcy5tYXRjaCgiPT4iKSl7Zm9yKHZhciB1PTA7dTxzLmxlbmd0aDsrK3UpdGhpcy5yZWludGVycHJldEV4cHJlc3Npb25Bc1BhdHRlcm4oc1t1XSk7cj17dHlwZToiQXJyb3dQYXJhbWV0ZXJQbGFjZUhvbGRlciIscGFyYW1zOnMsYXN5bmM6ITB9fX1lbHNlIGlmKHRoaXMubWF0Y2goIlsiKSl7dGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQ9ITEsdGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMCx0aGlzLmV4cGVjdCgiWyIpO3ZhciBpPXRoaXMuaXNvbGF0ZUNvdmVyR3JhbW1hcih0aGlzLnBhcnNlRXhwcmVzc2lvbik7dGhpcy5leHBlY3QoIl0iKSxyPXRoaXMuZmluYWxpemUodGhpcy5zdGFydE5vZGUoZSksbmV3IGEuQ29tcHV0ZWRNZW1iZXJFeHByZXNzaW9uKHIsaSkpfWVsc2V7aWYoMTAhPT10aGlzLmxvb2thaGVhZC50eXBlfHwhdGhpcy5sb29rYWhlYWQuaGVhZClicmVhazt2YXIgYz10aGlzLnBhcnNlVGVtcGxhdGVMaXRlcmFsKCk7cj10aGlzLmZpbmFsaXplKHRoaXMuc3RhcnROb2RlKGUpLG5ldyBhLlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbihyLGMpKX1yZXR1cm4gdGhpcy5jb250ZXh0LmFsbG93SW49bixyfSxlLnByb3RvdHlwZS5wYXJzZVN1cGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCk7cmV0dXJuIHRoaXMuZXhwZWN0S2V5d29yZCgic3VwZXIiKSx0aGlzLm1hdGNoKCJbIil8fHRoaXMubWF0Y2goIi4iKXx8dGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0aGlzLmxvb2thaGVhZCksdGhpcy5maW5hbGl6ZShlLG5ldyBhLlN1cGVyKX0sZS5wcm90b3R5cGUucGFyc2VMZWZ0SGFuZFNpZGVFeHByZXNzaW9uPWZ1bmN0aW9uKCl7ci5hc3NlcnQodGhpcy5jb250ZXh0LmFsbG93SW4sImNhbGxlZSBvZiBuZXcgZXhwcmVzc2lvbiBhbHdheXMgYWxsb3cgaW4ga2V5d29yZC4iKTtmb3IodmFyIGU9dGhpcy5zdGFydE5vZGUodGhpcy5sb29rYWhlYWQpLHQ9dGhpcy5tYXRjaEtleXdvcmQoInN1cGVyIikmJnRoaXMuY29udGV4dC5pbkZ1bmN0aW9uQm9keT90aGlzLnBhcnNlU3VwZXIoKTp0aGlzLmluaGVyaXRDb3ZlckdyYW1tYXIodGhpcy5tYXRjaEtleXdvcmQoIm5ldyIpP3RoaXMucGFyc2VOZXdFeHByZXNzaW9uOnRoaXMucGFyc2VQcmltYXJ5RXhwcmVzc2lvbik7OylpZih0aGlzLm1hdGNoKCJbIikpe3RoaXMuY29udGV4dC5pc0JpbmRpbmdFbGVtZW50PSExLHRoaXMuY29udGV4dC5pc0Fzc2lnbm1lbnRUYXJnZXQ9ITAsdGhpcy5leHBlY3QoIlsiKTt2YXIgbj10aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUV4cHJlc3Npb24pO3RoaXMuZXhwZWN0KCJdIiksdD10aGlzLmZpbmFsaXplKGUsbmV3IGEuQ29tcHV0ZWRNZW1iZXJFeHByZXNzaW9uKHQsbikpfWVsc2UgaWYodGhpcy5tYXRjaCgiLiIpKXt0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMSx0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0PSEwLHRoaXMuZXhwZWN0KCIuIik7dmFyIG49dGhpcy5wYXJzZUlkZW50aWZpZXJOYW1lKCk7dD10aGlzLmZpbmFsaXplKGUsbmV3IGEuU3RhdGljTWVtYmVyRXhwcmVzc2lvbih0LG4pKX1lbHNle2lmKDEwIT09dGhpcy5sb29rYWhlYWQudHlwZXx8IXRoaXMubG9va2FoZWFkLmhlYWQpYnJlYWs7dmFyIGk9dGhpcy5wYXJzZVRlbXBsYXRlTGl0ZXJhbCgpO3Q9dGhpcy5maW5hbGl6ZShlLG5ldyBhLlRhZ2dlZFRlbXBsYXRlRXhwcmVzc2lvbih0LGkpKX1yZXR1cm4gdH0sZS5wcm90b3R5cGUucGFyc2VVcGRhdGVFeHByZXNzaW9uPWZ1bmN0aW9uKCl7dmFyIGUsdD10aGlzLmxvb2thaGVhZDtpZih0aGlzLm1hdGNoKCIrKyIpfHx0aGlzLm1hdGNoKCItLSIpKXt2YXIgbj10aGlzLnN0YXJ0Tm9kZSh0KSxyPXRoaXMubmV4dFRva2VuKCk7ZT10aGlzLmluaGVyaXRDb3ZlckdyYW1tYXIodGhpcy5wYXJzZVVuYXJ5RXhwcmVzc2lvbiksdGhpcy5jb250ZXh0LnN0cmljdCYmZS50eXBlPT09dS5TeW50YXguSWRlbnRpZmllciYmdGhpcy5zY2FubmVyLmlzUmVzdHJpY3RlZFdvcmQoZS5uYW1lKSYmdGhpcy50b2xlcmF0ZUVycm9yKG8uTWVzc2FnZXMuU3RyaWN0TEhTUHJlZml4KSx0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0fHx0aGlzLnRvbGVyYXRlRXJyb3Ioby5NZXNzYWdlcy5JbnZhbGlkTEhTSW5Bc3NpZ25tZW50KTt2YXIgaT0hMDtlPXRoaXMuZmluYWxpemUobixuZXcgYS5VcGRhdGVFeHByZXNzaW9uKHIudmFsdWUsZSxpKSksdGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMX1lbHNlIGlmKGU9dGhpcy5pbmhlcml0Q292ZXJHcmFtbWFyKHRoaXMucGFyc2VMZWZ0SGFuZFNpZGVFeHByZXNzaW9uQWxsb3dDYWxsKSwhdGhpcy5oYXNMaW5lVGVybWluYXRvciYmNz09PXRoaXMubG9va2FoZWFkLnR5cGUmJih0aGlzLm1hdGNoKCIrKyIpfHx0aGlzLm1hdGNoKCItLSIpKSl7dGhpcy5jb250ZXh0LnN0cmljdCYmZS50eXBlPT09dS5TeW50YXguSWRlbnRpZmllciYmdGhpcy5zY2FubmVyLmlzUmVzdHJpY3RlZFdvcmQoZS5uYW1lKSYmdGhpcy50b2xlcmF0ZUVycm9yKG8uTWVzc2FnZXMuU3RyaWN0TEhTUG9zdGZpeCksdGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldHx8dGhpcy50b2xlcmF0ZUVycm9yKG8uTWVzc2FnZXMuSW52YWxpZExIU0luQXNzaWdubWVudCksdGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMTt2YXIgcz10aGlzLm5leHRUb2tlbigpLnZhbHVlLGk9ITE7ZT10aGlzLmZpbmFsaXplKHRoaXMuc3RhcnROb2RlKHQpLG5ldyBhLlVwZGF0ZUV4cHJlc3Npb24ocyxlLGkpKX1yZXR1cm4gZX0sZS5wcm90b3R5cGUucGFyc2VBd2FpdEV4cHJlc3Npb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKTt0aGlzLm5leHRUb2tlbigpO3ZhciB0PXRoaXMucGFyc2VVbmFyeUV4cHJlc3Npb24oKTtyZXR1cm4gdGhpcy5maW5hbGl6ZShlLG5ldyBhLkF3YWl0RXhwcmVzc2lvbih0KSl9LGUucHJvdG90eXBlLnBhcnNlVW5hcnlFeHByZXNzaW9uPWZ1bmN0aW9uKCl7dmFyIGU7aWYodGhpcy5tYXRjaCgiKyIpfHx0aGlzLm1hdGNoKCItIil8fHRoaXMubWF0Y2goIn4iKXx8dGhpcy5tYXRjaCgiISIpfHx0aGlzLm1hdGNoS2V5d29yZCgiZGVsZXRlIil8fHRoaXMubWF0Y2hLZXl3b3JkKCJ2b2lkIil8fHRoaXMubWF0Y2hLZXl3b3JkKCJ0eXBlb2YiKSl7dmFyIHQ9dGhpcy5zdGFydE5vZGUodGhpcy5sb29rYWhlYWQpLG49dGhpcy5uZXh0VG9rZW4oKTtlPXRoaXMuaW5oZXJpdENvdmVyR3JhbW1hcih0aGlzLnBhcnNlVW5hcnlFeHByZXNzaW9uKSxlPXRoaXMuZmluYWxpemUodCxuZXcgYS5VbmFyeUV4cHJlc3Npb24obi52YWx1ZSxlKSksdGhpcy5jb250ZXh0LnN0cmljdCYmImRlbGV0ZSI9PT1lLm9wZXJhdG9yJiZlLmFyZ3VtZW50LnR5cGU9PT11LlN5bnRheC5JZGVudGlmaWVyJiZ0aGlzLnRvbGVyYXRlRXJyb3Ioby5NZXNzYWdlcy5TdHJpY3REZWxldGUpLHRoaXMuY29udGV4dC5pc0Fzc2lnbm1lbnRUYXJnZXQ9ITEsdGhpcy5jb250ZXh0LmlzQmluZGluZ0VsZW1lbnQ9ITF9ZWxzZSBlPXRoaXMuY29udGV4dC5hd2FpdCYmdGhpcy5tYXRjaENvbnRleHR1YWxLZXl3b3JkKCJhd2FpdCIpP3RoaXMucGFyc2VBd2FpdEV4cHJlc3Npb24oKTp0aGlzLnBhcnNlVXBkYXRlRXhwcmVzc2lvbigpO3JldHVybiBlfSxlLnByb3RvdHlwZS5wYXJzZUV4cG9uZW50aWF0aW9uRXhwcmVzc2lvbj1mdW5jdGlvbigpe3ZhciBlPXRoaXMubG9va2FoZWFkLHQ9dGhpcy5pbmhlcml0Q292ZXJHcmFtbWFyKHRoaXMucGFyc2VVbmFyeUV4cHJlc3Npb24pO2lmKHQudHlwZSE9PXUuU3ludGF4LlVuYXJ5RXhwcmVzc2lvbiYmdGhpcy5tYXRjaCgiKioiKSl7dGhpcy5uZXh0VG9rZW4oKSx0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0PSExLHRoaXMuY29udGV4dC5pc0JpbmRpbmdFbGVtZW50PSExO3ZhciBuPXQscj10aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUV4cG9uZW50aWF0aW9uRXhwcmVzc2lvbik7dD10aGlzLmZpbmFsaXplKHRoaXMuc3RhcnROb2RlKGUpLG5ldyBhLkJpbmFyeUV4cHJlc3Npb24oIioqIixuLHIpKX1yZXR1cm4gdH0sZS5wcm90b3R5cGUuYmluYXJ5UHJlY2VkZW5jZT1mdW5jdGlvbihlKXt2YXIgdD1lLnZhbHVlO3JldHVybiA3PT09ZS50eXBlP3RoaXMub3BlcmF0b3JQcmVjZWRlbmNlW3RdfHwwOjQ9PT1lLnR5cGUmJigiaW5zdGFuY2VvZiI9PT10fHx0aGlzLmNvbnRleHQuYWxsb3dJbiYmImluIj09PXQpPzc6MH0sZS5wcm90b3R5cGUucGFyc2VCaW5hcnlFeHByZXNzaW9uPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5sb29rYWhlYWQsdD10aGlzLmluaGVyaXRDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUV4cG9uZW50aWF0aW9uRXhwcmVzc2lvbiksbj10aGlzLmxvb2thaGVhZCxyPXRoaXMuYmluYXJ5UHJlY2VkZW5jZShuKTtpZihyPjApe3RoaXMubmV4dFRva2VuKCksdGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMTtmb3IodmFyIGk9W2UsdGhpcy5sb29rYWhlYWRdLG89dCxzPXRoaXMuaXNvbGF0ZUNvdmVyR3JhbW1hcih0aGlzLnBhcnNlRXhwb25lbnRpYXRpb25FeHByZXNzaW9uKSx1PVtvLG4udmFsdWUsc10sYz1bcl07Oyl7aWYoKHI9dGhpcy5iaW5hcnlQcmVjZWRlbmNlKHRoaXMubG9va2FoZWFkKSk8PTApYnJlYWs7Zm9yKDt1Lmxlbmd0aD4yJiZyPD1jW2MubGVuZ3RoLTFdOyl7cz11LnBvcCgpO3ZhciBsPXUucG9wKCk7Yy5wb3AoKSxvPXUucG9wKCksaS5wb3AoKTt2YXIgcD10aGlzLnN0YXJ0Tm9kZShpW2kubGVuZ3RoLTFdKTt1LnB1c2godGhpcy5maW5hbGl6ZShwLG5ldyBhLkJpbmFyeUV4cHJlc3Npb24obCxvLHMpKSl9dS5wdXNoKHRoaXMubmV4dFRva2VuKCkudmFsdWUpLGMucHVzaChyKSxpLnB1c2godGhpcy5sb29rYWhlYWQpLHUucHVzaCh0aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUV4cG9uZW50aWF0aW9uRXhwcmVzc2lvbikpfXZhciBmPXUubGVuZ3RoLTE7Zm9yKHQ9dVtmXSxpLnBvcCgpO2Y+MTspe3ZhciBwPXRoaXMuc3RhcnROb2RlKGkucG9wKCkpLGw9dVtmLTFdO3Q9dGhpcy5maW5hbGl6ZShwLG5ldyBhLkJpbmFyeUV4cHJlc3Npb24obCx1W2YtMl0sdCkpLGYtPTJ9fXJldHVybiB0fSxlLnByb3RvdHlwZS5wYXJzZUNvbmRpdGlvbmFsRXhwcmVzc2lvbj1mdW5jdGlvbigpe3ZhciBlPXRoaXMubG9va2FoZWFkLHQ9dGhpcy5pbmhlcml0Q292ZXJHcmFtbWFyKHRoaXMucGFyc2VCaW5hcnlFeHByZXNzaW9uKTtpZih0aGlzLm1hdGNoKCI/Iikpe3RoaXMubmV4dFRva2VuKCk7dmFyIG49dGhpcy5jb250ZXh0LmFsbG93SW47dGhpcy5jb250ZXh0LmFsbG93SW49ITA7dmFyIHI9dGhpcy5pc29sYXRlQ292ZXJHcmFtbWFyKHRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbik7dGhpcy5jb250ZXh0LmFsbG93SW49bix0aGlzLmV4cGVjdCgiOiIpO3ZhciBpPXRoaXMuaXNvbGF0ZUNvdmVyR3JhbW1hcih0aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24pO3Q9dGhpcy5maW5hbGl6ZSh0aGlzLnN0YXJ0Tm9kZShlKSxuZXcgYS5Db25kaXRpb25hbEV4cHJlc3Npb24odCxyLGkpKSx0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0PSExLHRoaXMuY29udGV4dC5pc0JpbmRpbmdFbGVtZW50PSExfXJldHVybiB0fSxlLnByb3RvdHlwZS5jaGVja1BhdHRlcm5QYXJhbT1mdW5jdGlvbihlLHQpe3N3aXRjaCh0LnR5cGUpe2Nhc2UgdS5TeW50YXguSWRlbnRpZmllcjp0aGlzLnZhbGlkYXRlUGFyYW0oZSx0LHQubmFtZSk7YnJlYWs7Y2FzZSB1LlN5bnRheC5SZXN0RWxlbWVudDp0aGlzLmNoZWNrUGF0dGVyblBhcmFtKGUsdC5hcmd1bWVudCk7YnJlYWs7Y2FzZSB1LlN5bnRheC5Bc3NpZ25tZW50UGF0dGVybjp0aGlzLmNoZWNrUGF0dGVyblBhcmFtKGUsdC5sZWZ0KTticmVhaztjYXNlIHUuU3ludGF4LkFycmF5UGF0dGVybjpmb3IodmFyIG49MDtuPHQuZWxlbWVudHMubGVuZ3RoO24rKyludWxsIT09dC5lbGVtZW50c1tuXSYmdGhpcy5jaGVja1BhdHRlcm5QYXJhbShlLHQuZWxlbWVudHNbbl0pO2JyZWFrO2Nhc2UgdS5TeW50YXguT2JqZWN0UGF0dGVybjpmb3IodmFyIG49MDtuPHQucHJvcGVydGllcy5sZW5ndGg7bisrKXRoaXMuY2hlY2tQYXR0ZXJuUGFyYW0oZSx0LnByb3BlcnRpZXNbbl0udmFsdWUpfWUuc2ltcGxlPWUuc2ltcGxlJiZ0IGluc3RhbmNlb2YgYS5JZGVudGlmaWVyfSxlLnByb3RvdHlwZS5yZWludGVycHJldEFzQ292ZXJGb3JtYWxzTGlzdD1mdW5jdGlvbihlKXt2YXIgdCxuPVtlXSxyPSExO3N3aXRjaChlLnR5cGUpe2Nhc2UgdS5TeW50YXguSWRlbnRpZmllcjpicmVhaztjYXNlIkFycm93UGFyYW1ldGVyUGxhY2VIb2xkZXIiOm49ZS5wYXJhbXMscj1lLmFzeW5jO2JyZWFrO2RlZmF1bHQ6cmV0dXJuIG51bGx9dD17c2ltcGxlOiEwLHBhcmFtU2V0Ont9fTtmb3IodmFyIGk9MDtpPG4ubGVuZ3RoOysraSl7dmFyIGE9bltpXTthLnR5cGU9PT11LlN5bnRheC5Bc3NpZ25tZW50UGF0dGVybj9hLnJpZ2h0LnR5cGU9PT11LlN5bnRheC5ZaWVsZEV4cHJlc3Npb24mJihhLnJpZ2h0LmFyZ3VtZW50JiZ0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHRoaXMubG9va2FoZWFkKSxhLnJpZ2h0LnR5cGU9dS5TeW50YXguSWRlbnRpZmllcixhLnJpZ2h0Lm5hbWU9InlpZWxkIixkZWxldGUgYS5yaWdodC5hcmd1bWVudCxkZWxldGUgYS5yaWdodC5kZWxlZ2F0ZSk6ciYmYS50eXBlPT09dS5TeW50YXguSWRlbnRpZmllciYmImF3YWl0Ij09PWEubmFtZSYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0aGlzLmxvb2thaGVhZCksdGhpcy5jaGVja1BhdHRlcm5QYXJhbSh0LGEpLG5baV09YX1pZih0aGlzLmNvbnRleHQuc3RyaWN0fHwhdGhpcy5jb250ZXh0LmFsbG93WWllbGQpZm9yKHZhciBpPTA7aTxuLmxlbmd0aDsrK2kpe3ZhciBhPW5baV07YS50eXBlPT09dS5TeW50YXguWWllbGRFeHByZXNzaW9uJiZ0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHRoaXMubG9va2FoZWFkKX1pZih0Lm1lc3NhZ2U9PT1vLk1lc3NhZ2VzLlN0cmljdFBhcmFtRHVwZSl7dmFyIHM9dGhpcy5jb250ZXh0LnN0cmljdD90LnN0cmljdGVkOnQuZmlyc3RSZXN0cmljdGVkO3RoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4ocyx0Lm1lc3NhZ2UpfXJldHVybntzaW1wbGU6dC5zaW1wbGUscGFyYW1zOm4sc3RyaWN0ZWQ6dC5zdHJpY3RlZCxmaXJzdFJlc3RyaWN0ZWQ6dC5maXJzdFJlc3RyaWN0ZWQsbWVzc2FnZTp0Lm1lc3NhZ2V9fSxlLnByb3RvdHlwZS5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uPWZ1bmN0aW9uKCl7dmFyIGU7aWYoIXRoaXMuY29udGV4dC5hbGxvd1lpZWxkJiZ0aGlzLm1hdGNoS2V5d29yZCgieWllbGQiKSllPXRoaXMucGFyc2VZaWVsZEV4cHJlc3Npb24oKTtlbHNle3ZhciB0PXRoaXMubG9va2FoZWFkLG49dDtpZihlPXRoaXMucGFyc2VDb25kaXRpb25hbEV4cHJlc3Npb24oKSwzPT09bi50eXBlJiZuLmxpbmVOdW1iZXI9PT10aGlzLmxvb2thaGVhZC5saW5lTnVtYmVyJiYiYXN5bmMiPT09bi52YWx1ZSYmKDM9PT10aGlzLmxvb2thaGVhZC50eXBlfHx0aGlzLm1hdGNoS2V5d29yZCgieWllbGQiKSkpe3ZhciByPXRoaXMucGFyc2VQcmltYXJ5RXhwcmVzc2lvbigpO3RoaXMucmVpbnRlcnByZXRFeHByZXNzaW9uQXNQYXR0ZXJuKHIpLGU9e3R5cGU6IkFycm93UGFyYW1ldGVyUGxhY2VIb2xkZXIiLHBhcmFtczpbcl0sYXN5bmM6ITB9fWlmKCJBcnJvd1BhcmFtZXRlclBsYWNlSG9sZGVyIj09PWUudHlwZXx8dGhpcy5tYXRjaCgiPT4iKSl7dGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMTt2YXIgaT1lLmFzeW5jLHM9dGhpcy5yZWludGVycHJldEFzQ292ZXJGb3JtYWxzTGlzdChlKTtpZihzKXt0aGlzLmhhc0xpbmVUZXJtaW5hdG9yJiZ0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKHRoaXMubG9va2FoZWFkKSx0aGlzLmNvbnRleHQuZmlyc3RDb3ZlckluaXRpYWxpemVkTmFtZUVycm9yPW51bGw7dmFyIGM9dGhpcy5jb250ZXh0LnN0cmljdCxsPXRoaXMuY29udGV4dC5hbGxvd1N0cmljdERpcmVjdGl2ZTt0aGlzLmNvbnRleHQuYWxsb3dTdHJpY3REaXJlY3RpdmU9cy5zaW1wbGU7dmFyIHA9dGhpcy5jb250ZXh0LmFsbG93WWllbGQsZj10aGlzLmNvbnRleHQuYXdhaXQ7dGhpcy5jb250ZXh0LmFsbG93WWllbGQ9ITAsdGhpcy5jb250ZXh0LmF3YWl0PWk7dmFyIGQ9dGhpcy5zdGFydE5vZGUodCk7dGhpcy5leHBlY3QoIj0+Iik7dmFyIGg9dm9pZCAwO2lmKHRoaXMubWF0Y2goInsiKSl7dmFyIG09dGhpcy5jb250ZXh0LmFsbG93SW47dGhpcy5jb250ZXh0LmFsbG93SW49ITAsaD10aGlzLnBhcnNlRnVuY3Rpb25Tb3VyY2VFbGVtZW50cygpLHRoaXMuY29udGV4dC5hbGxvd0luPW19ZWxzZSBoPXRoaXMuaXNvbGF0ZUNvdmVyR3JhbW1hcih0aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24pO3ZhciBnPWgudHlwZSE9PXUuU3ludGF4LkJsb2NrU3RhdGVtZW50O3RoaXMuY29udGV4dC5zdHJpY3QmJnMuZmlyc3RSZXN0cmljdGVkJiZ0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHMuZmlyc3RSZXN0cmljdGVkLHMubWVzc2FnZSksdGhpcy5jb250ZXh0LnN0cmljdCYmcy5zdHJpY3RlZCYmdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbihzLnN0cmljdGVkLHMubWVzc2FnZSksZT1pP3RoaXMuZmluYWxpemUoZCxuZXcgYS5Bc3luY0Fycm93RnVuY3Rpb25FeHByZXNzaW9uKHMucGFyYW1zLGgsZykpOnRoaXMuZmluYWxpemUoZCxuZXcgYS5BcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbihzLnBhcmFtcyxoLGcpKSx0aGlzLmNvbnRleHQuc3RyaWN0PWMsdGhpcy5jb250ZXh0LmFsbG93U3RyaWN0RGlyZWN0aXZlPWwsdGhpcy5jb250ZXh0LmFsbG93WWllbGQ9cCx0aGlzLmNvbnRleHQuYXdhaXQ9Zn19ZWxzZSBpZih0aGlzLm1hdGNoQXNzaWduKCkpe2lmKHRoaXMuY29udGV4dC5pc0Fzc2lnbm1lbnRUYXJnZXR8fHRoaXMudG9sZXJhdGVFcnJvcihvLk1lc3NhZ2VzLkludmFsaWRMSFNJbkFzc2lnbm1lbnQpLHRoaXMuY29udGV4dC5zdHJpY3QmJmUudHlwZT09PXUuU3ludGF4LklkZW50aWZpZXIpe3ZhciB5PWU7dGhpcy5zY2FubmVyLmlzUmVzdHJpY3RlZFdvcmQoeS5uYW1lKSYmdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbihuLG8uTWVzc2FnZXMuU3RyaWN0TEhTQXNzaWdubWVudCksdGhpcy5zY2FubmVyLmlzU3RyaWN0TW9kZVJlc2VydmVkV29yZCh5Lm5hbWUpJiZ0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKG4sby5NZXNzYWdlcy5TdHJpY3RSZXNlcnZlZFdvcmQpfXRoaXMubWF0Y2goIj0iKT90aGlzLnJlaW50ZXJwcmV0RXhwcmVzc2lvbkFzUGF0dGVybihlKToodGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldD0hMSx0aGlzLmNvbnRleHQuaXNCaW5kaW5nRWxlbWVudD0hMSksbj10aGlzLm5leHRUb2tlbigpO3ZhciB2PW4udmFsdWUsYj10aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKTtlPXRoaXMuZmluYWxpemUodGhpcy5zdGFydE5vZGUodCksbmV3IGEuQXNzaWdubWVudEV4cHJlc3Npb24odixlLGIpKSx0aGlzLmNvbnRleHQuZmlyc3RDb3ZlckluaXRpYWxpemVkTmFtZUVycm9yPW51bGx9fXJldHVybiBlfSxlLnByb3RvdHlwZS5wYXJzZUV4cHJlc3Npb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmxvb2thaGVhZCx0PXRoaXMuaXNvbGF0ZUNvdmVyR3JhbW1hcih0aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24pO2lmKHRoaXMubWF0Y2goIiwiKSl7dmFyIG49W107Zm9yKG4ucHVzaCh0KTsyIT09dGhpcy5sb29rYWhlYWQudHlwZSYmdGhpcy5tYXRjaCgiLCIpOyl0aGlzLm5leHRUb2tlbigpLG4ucHVzaCh0aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKSk7dD10aGlzLmZpbmFsaXplKHRoaXMuc3RhcnROb2RlKGUpLG5ldyBhLlNlcXVlbmNlRXhwcmVzc2lvbihuKSl9cmV0dXJuIHR9LGUucHJvdG90eXBlLnBhcnNlU3RhdGVtZW50TGlzdEl0ZW09ZnVuY3Rpb24oKXt2YXIgZTtpZih0aGlzLmNvbnRleHQuaXNBc3NpZ25tZW50VGFyZ2V0PSEwLHRoaXMuY29udGV4dC5pc0JpbmRpbmdFbGVtZW50PSEwLDQ9PT10aGlzLmxvb2thaGVhZC50eXBlKXN3aXRjaCh0aGlzLmxvb2thaGVhZC52YWx1ZSl7Y2FzZSJleHBvcnQiOnRoaXMuY29udGV4dC5pc01vZHVsZXx8dGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbih0aGlzLmxvb2thaGVhZCxvLk1lc3NhZ2VzLklsbGVnYWxFeHBvcnREZWNsYXJhdGlvbiksZT10aGlzLnBhcnNlRXhwb3J0RGVjbGFyYXRpb24oKTticmVhaztjYXNlImltcG9ydCI6dGhpcy5jb250ZXh0LmlzTW9kdWxlfHx0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKHRoaXMubG9va2FoZWFkLG8uTWVzc2FnZXMuSWxsZWdhbEltcG9ydERlY2xhcmF0aW9uKSxlPXRoaXMucGFyc2VJbXBvcnREZWNsYXJhdGlvbigpO2JyZWFrO2Nhc2UiY29uc3QiOmU9dGhpcy5wYXJzZUxleGljYWxEZWNsYXJhdGlvbih7aW5Gb3I6ITF9KTticmVhaztjYXNlImZ1bmN0aW9uIjplPXRoaXMucGFyc2VGdW5jdGlvbkRlY2xhcmF0aW9uKCk7YnJlYWs7Y2FzZSJjbGFzcyI6ZT10aGlzLnBhcnNlQ2xhc3NEZWNsYXJhdGlvbigpO2JyZWFrO2Nhc2UibGV0IjplPXRoaXMuaXNMZXhpY2FsRGVjbGFyYXRpb24oKT90aGlzLnBhcnNlTGV4aWNhbERlY2xhcmF0aW9uKHtpbkZvcjohMX0pOnRoaXMucGFyc2VTdGF0ZW1lbnQoKTticmVhaztkZWZhdWx0OmU9dGhpcy5wYXJzZVN0YXRlbWVudCgpfWVsc2UgZT10aGlzLnBhcnNlU3RhdGVtZW50KCk7cmV0dXJuIGV9LGUucHJvdG90eXBlLnBhcnNlQmxvY2s9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKTt0aGlzLmV4cGVjdCgieyIpO2Zvcih2YXIgdD1bXTs7KXtpZih0aGlzLm1hdGNoKCJ9IikpYnJlYWs7dC5wdXNoKHRoaXMucGFyc2VTdGF0ZW1lbnRMaXN0SXRlbSgpKX1yZXR1cm4gdGhpcy5leHBlY3QoIn0iKSx0aGlzLmZpbmFsaXplKGUsbmV3IGEuQmxvY2tTdGF0ZW1lbnQodCkpfSxlLnByb3RvdHlwZS5wYXJzZUxleGljYWxCaW5kaW5nPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5jcmVhdGVOb2RlKCkscj1bXSxpPXRoaXMucGFyc2VQYXR0ZXJuKHIsZSk7dGhpcy5jb250ZXh0LnN0cmljdCYmaS50eXBlPT09dS5TeW50YXguSWRlbnRpZmllciYmdGhpcy5zY2FubmVyLmlzUmVzdHJpY3RlZFdvcmQoaS5uYW1lKSYmdGhpcy50b2xlcmF0ZUVycm9yKG8uTWVzc2FnZXMuU3RyaWN0VmFyTmFtZSk7dmFyIHM9bnVsbDtyZXR1cm4iY29uc3QiPT09ZT90aGlzLm1hdGNoS2V5d29yZCgiaW4iKXx8dGhpcy5tYXRjaENvbnRleHR1YWxLZXl3b3JkKCJvZiIpfHwodGhpcy5tYXRjaCgiPSIpPyh0aGlzLm5leHRUb2tlbigpLHM9dGhpcy5pc29sYXRlQ292ZXJHcmFtbWFyKHRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbikpOnRoaXMudGhyb3dFcnJvcihvLk1lc3NhZ2VzLkRlY2xhcmF0aW9uTWlzc2luZ0luaXRpYWxpemVyLCJjb25zdCIpKTooIXQuaW5Gb3ImJmkudHlwZSE9PXUuU3ludGF4LklkZW50aWZpZXJ8fHRoaXMubWF0Y2goIj0iKSkmJih0aGlzLmV4cGVjdCgiPSIpLHM9dGhpcy5pc29sYXRlQ292ZXJHcmFtbWFyKHRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbikpLHRoaXMuZmluYWxpemUobixuZXcgYS5WYXJpYWJsZURlY2xhcmF0b3IoaSxzKSl9LGUucHJvdG90eXBlLnBhcnNlQmluZGluZ0xpc3Q9ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG49W3RoaXMucGFyc2VMZXhpY2FsQmluZGluZyhlLHQpXTt0aGlzLm1hdGNoKCIsIik7KXRoaXMubmV4dFRva2VuKCksbi5wdXNoKHRoaXMucGFyc2VMZXhpY2FsQmluZGluZyhlLHQpKTtyZXR1cm4gbn0sZS5wcm90b3R5cGUuaXNMZXhpY2FsRGVjbGFyYXRpb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnNjYW5uZXIuc2F2ZVN0YXRlKCk7dGhpcy5zY2FubmVyLnNjYW5Db21tZW50cygpO3ZhciB0PXRoaXMuc2Nhbm5lci5sZXgoKTtyZXR1cm4gdGhpcy5zY2FubmVyLnJlc3RvcmVTdGF0ZShlKSwzPT09dC50eXBlfHw3PT09dC50eXBlJiYiWyI9PT10LnZhbHVlfHw3PT09dC50eXBlJiYieyI9PT10LnZhbHVlfHw0PT09dC50eXBlJiYibGV0Ij09PXQudmFsdWV8fDQ9PT10LnR5cGUmJiJ5aWVsZCI9PT10LnZhbHVlfSxlLnByb3RvdHlwZS5wYXJzZUxleGljYWxEZWNsYXJhdGlvbj1mdW5jdGlvbihlKXt2YXIgdD10aGlzLmNyZWF0ZU5vZGUoKSxuPXRoaXMubmV4dFRva2VuKCkudmFsdWU7ci5hc3NlcnQoImxldCI9PT1ufHwiY29uc3QiPT09biwiTGV4aWNhbCBkZWNsYXJhdGlvbiBtdXN0IGJlIGVpdGhlciBsZXQgb3IgY29uc3QiKTt2YXIgaT10aGlzLnBhcnNlQmluZGluZ0xpc3QobixlKTtyZXR1cm4gdGhpcy5jb25zdW1lU2VtaWNvbG9uKCksdGhpcy5maW5hbGl6ZSh0LG5ldyBhLlZhcmlhYmxlRGVjbGFyYXRpb24oaSxuKSl9LGUucHJvdG90eXBlLnBhcnNlQmluZGluZ1Jlc3RFbGVtZW50PWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5jcmVhdGVOb2RlKCk7dGhpcy5leHBlY3QoIi4uLiIpO3ZhciByPXRoaXMucGFyc2VQYXR0ZXJuKGUsdCk7cmV0dXJuIHRoaXMuZmluYWxpemUobixuZXcgYS5SZXN0RWxlbWVudChyKSl9LGUucHJvdG90eXBlLnBhcnNlQXJyYXlQYXR0ZXJuPWZ1bmN0aW9uKGUsdCl7dmFyIG49dGhpcy5jcmVhdGVOb2RlKCk7dGhpcy5leHBlY3QoIlsiKTtmb3IodmFyIHI9W107IXRoaXMubWF0Y2goIl0iKTspaWYodGhpcy5tYXRjaCgiLCIpKXRoaXMubmV4dFRva2VuKCksci5wdXNoKG51bGwpO2Vsc2V7aWYodGhpcy5tYXRjaCgiLi4uIikpe3IucHVzaCh0aGlzLnBhcnNlQmluZGluZ1Jlc3RFbGVtZW50KGUsdCkpO2JyZWFrfXIucHVzaCh0aGlzLnBhcnNlUGF0dGVybldpdGhEZWZhdWx0KGUsdCkpLHRoaXMubWF0Y2goIl0iKXx8dGhpcy5leHBlY3QoIiwiKX1yZXR1cm4gdGhpcy5leHBlY3QoIl0iKSx0aGlzLmZpbmFsaXplKG4sbmV3IGEuQXJyYXlQYXR0ZXJuKHIpKX0sZS5wcm90b3R5cGUucGFyc2VQcm9wZXJ0eVBhdHRlcm49ZnVuY3Rpb24oZSx0KXt2YXIgbixyLGk9dGhpcy5jcmVhdGVOb2RlKCksbz0hMSxzPSExO2lmKDM9PT10aGlzLmxvb2thaGVhZC50eXBlKXt2YXIgdT10aGlzLmxvb2thaGVhZDtuPXRoaXMucGFyc2VWYXJpYWJsZUlkZW50aWZpZXIoKTt2YXIgYz10aGlzLmZpbmFsaXplKGksbmV3IGEuSWRlbnRpZmllcih1LnZhbHVlKSk7aWYodGhpcy5tYXRjaCgiPSIpKXtlLnB1c2godSkscz0hMCx0aGlzLm5leHRUb2tlbigpO3ZhciBsPXRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbigpO3I9dGhpcy5maW5hbGl6ZSh0aGlzLnN0YXJ0Tm9kZSh1KSxuZXcgYS5Bc3NpZ25tZW50UGF0dGVybihjLGwpKX1lbHNlIHRoaXMubWF0Y2goIjoiKT8odGhpcy5leHBlY3QoIjoiKSxyPXRoaXMucGFyc2VQYXR0ZXJuV2l0aERlZmF1bHQoZSx0KSk6KGUucHVzaCh1KSxzPSEwLHI9Yyl9ZWxzZSBvPXRoaXMubWF0Y2goIlsiKSxuPXRoaXMucGFyc2VPYmplY3RQcm9wZXJ0eUtleSgpLHRoaXMuZXhwZWN0KCI6Iikscj10aGlzLnBhcnNlUGF0dGVybldpdGhEZWZhdWx0KGUsdCk7cmV0dXJuIHRoaXMuZmluYWxpemUoaSxuZXcgYS5Qcm9wZXJ0eSgiaW5pdCIsbixvLHIsITEscykpfSxlLnByb3RvdHlwZS5wYXJzZU9iamVjdFBhdHRlcm49ZnVuY3Rpb24oZSx0KXt2YXIgbj10aGlzLmNyZWF0ZU5vZGUoKSxyPVtdO2Zvcih0aGlzLmV4cGVjdCgieyIpOyF0aGlzLm1hdGNoKCJ9Iik7KXIucHVzaCh0aGlzLnBhcnNlUHJvcGVydHlQYXR0ZXJuKGUsdCkpLHRoaXMubWF0Y2goIn0iKXx8dGhpcy5leHBlY3QoIiwiKTtyZXR1cm4gdGhpcy5leHBlY3QoIn0iKSx0aGlzLmZpbmFsaXplKG4sbmV3IGEuT2JqZWN0UGF0dGVybihyKSl9LGUucHJvdG90eXBlLnBhcnNlUGF0dGVybj1mdW5jdGlvbihlLHQpe3ZhciBuO3JldHVybiB0aGlzLm1hdGNoKCJbIik/bj10aGlzLnBhcnNlQXJyYXlQYXR0ZXJuKGUsdCk6dGhpcy5tYXRjaCgieyIpP249dGhpcy5wYXJzZU9iamVjdFBhdHRlcm4oZSx0KTooIXRoaXMubWF0Y2hLZXl3b3JkKCJsZXQiKXx8ImNvbnN0IiE9PXQmJiJsZXQiIT09dHx8dGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbih0aGlzLmxvb2thaGVhZCxvLk1lc3NhZ2VzLkxldEluTGV4aWNhbEJpbmRpbmcpLGUucHVzaCh0aGlzLmxvb2thaGVhZCksbj10aGlzLnBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHQpKSxufSxlLnByb3RvdHlwZS5wYXJzZVBhdHRlcm5XaXRoRGVmYXVsdD1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXMubG9va2FoZWFkLHI9dGhpcy5wYXJzZVBhdHRlcm4oZSx0KTtpZih0aGlzLm1hdGNoKCI9Iikpe3RoaXMubmV4dFRva2VuKCk7dmFyIGk9dGhpcy5jb250ZXh0LmFsbG93WWllbGQ7dGhpcy5jb250ZXh0LmFsbG93WWllbGQ9ITA7dmFyIG89dGhpcy5pc29sYXRlQ292ZXJHcmFtbWFyKHRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbik7dGhpcy5jb250ZXh0LmFsbG93WWllbGQ9aSxyPXRoaXMuZmluYWxpemUodGhpcy5zdGFydE5vZGUobiksbmV3IGEuQXNzaWdubWVudFBhdHRlcm4ocixvKSl9cmV0dXJuIHJ9LGUucHJvdG90eXBlLnBhcnNlVmFyaWFibGVJZGVudGlmaWVyPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuY3JlYXRlTm9kZSgpLG49dGhpcy5uZXh0VG9rZW4oKTtyZXR1cm4gND09PW4udHlwZSYmInlpZWxkIj09PW4udmFsdWU/dGhpcy5jb250ZXh0LnN0cmljdD90aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKG4sby5NZXNzYWdlcy5TdHJpY3RSZXNlcnZlZFdvcmQpOnRoaXMuY29udGV4dC5hbGxvd1lpZWxkfHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKG4pOjMhPT1uLnR5cGU/dGhpcy5jb250ZXh0LnN0cmljdCYmND09PW4udHlwZSYmdGhpcy5zY2FubmVyLmlzU3RyaWN0TW9kZVJlc2VydmVkV29yZChuLnZhbHVlKT90aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKG4sby5NZXNzYWdlcy5TdHJpY3RSZXNlcnZlZFdvcmQpOih0aGlzLmNvbnRleHQuc3RyaWN0fHwibGV0IiE9PW4udmFsdWV8fCJ2YXIiIT09ZSkmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4obik6KHRoaXMuY29udGV4dC5pc01vZHVsZXx8dGhpcy5jb250ZXh0LmF3YWl0KSYmMz09PW4udHlwZSYmImF3YWl0Ij09PW4udmFsdWUmJnRoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4obiksdGhpcy5maW5hbGl6ZSh0LG5ldyBhLklkZW50aWZpZXIobi52YWx1ZSkpfSxlLnByb3RvdHlwZS5wYXJzZVZhcmlhYmxlRGVjbGFyYXRpb249ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5jcmVhdGVOb2RlKCksbj1bXSxyPXRoaXMucGFyc2VQYXR0ZXJuKG4sInZhciIpO3RoaXMuY29udGV4dC5zdHJpY3QmJnIudHlwZT09PXUuU3ludGF4LklkZW50aWZpZXImJnRoaXMuc2Nhbm5lci5pc1Jlc3RyaWN0ZWRXb3JkKHIubmFtZSkmJnRoaXMudG9sZXJhdGVFcnJvcihvLk1lc3NhZ2VzLlN0cmljdFZhck5hbWUpO3ZhciBpPW51bGw7cmV0dXJuIHRoaXMubWF0Y2goIj0iKT8odGhpcy5uZXh0VG9rZW4oKSxpPXRoaXMuaXNvbGF0ZUNvdmVyR3JhbW1hcih0aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24pKTpyLnR5cGU9PT11LlN5bnRheC5JZGVudGlmaWVyfHxlLmluRm9yfHx0aGlzLmV4cGVjdCgiPSIpLHRoaXMuZmluYWxpemUodCxuZXcgYS5WYXJpYWJsZURlY2xhcmF0b3IocixpKSl9LGUucHJvdG90eXBlLnBhcnNlVmFyaWFibGVEZWNsYXJhdGlvbkxpc3Q9ZnVuY3Rpb24oZSl7dmFyIHQ9e2luRm9yOmUuaW5Gb3J9LG49W107Zm9yKG4ucHVzaCh0aGlzLnBhcnNlVmFyaWFibGVEZWNsYXJhdGlvbih0KSk7dGhpcy5tYXRjaCgiLCIpOyl0aGlzLm5leHRUb2tlbigpLG4ucHVzaCh0aGlzLnBhcnNlVmFyaWFibGVEZWNsYXJhdGlvbih0KSk7cmV0dXJuIG59LGUucHJvdG90eXBlLnBhcnNlVmFyaWFibGVTdGF0ZW1lbnQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKTt0aGlzLmV4cGVjdEtleXdvcmQoInZhciIpO3ZhciB0PXRoaXMucGFyc2VWYXJpYWJsZURlY2xhcmF0aW9uTGlzdCh7aW5Gb3I6ITF9KTtyZXR1cm4gdGhpcy5jb25zdW1lU2VtaWNvbG9uKCksdGhpcy5maW5hbGl6ZShlLG5ldyBhLlZhcmlhYmxlRGVjbGFyYXRpb24odCwidmFyIikpfSxlLnByb3RvdHlwZS5wYXJzZUVtcHR5U3RhdGVtZW50PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCk7cmV0dXJuIHRoaXMuZXhwZWN0KCI7IiksdGhpcy5maW5hbGl6ZShlLG5ldyBhLkVtcHR5U3RhdGVtZW50KX0sZS5wcm90b3R5cGUucGFyc2VFeHByZXNzaW9uU3RhdGVtZW50PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCksdD10aGlzLnBhcnNlRXhwcmVzc2lvbigpO3JldHVybiB0aGlzLmNvbnN1bWVTZW1pY29sb24oKSx0aGlzLmZpbmFsaXplKGUsbmV3IGEuRXhwcmVzc2lvblN0YXRlbWVudCh0KSl9LGUucHJvdG90eXBlLnBhcnNlSWZDbGF1c2U9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5jb250ZXh0LnN0cmljdCYmdGhpcy5tYXRjaEtleXdvcmQoImZ1bmN0aW9uIikmJnRoaXMudG9sZXJhdGVFcnJvcihvLk1lc3NhZ2VzLlN0cmljdEZ1bmN0aW9uKSx0aGlzLnBhcnNlU3RhdGVtZW50KCl9LGUucHJvdG90eXBlLnBhcnNlSWZTdGF0ZW1lbnQ9ZnVuY3Rpb24oKXt2YXIgZSx0PXRoaXMuY3JlYXRlTm9kZSgpLG49bnVsbDt0aGlzLmV4cGVjdEtleXdvcmQoImlmIiksdGhpcy5leHBlY3QoIigiKTt2YXIgcj10aGlzLnBhcnNlRXhwcmVzc2lvbigpO3JldHVybiF0aGlzLm1hdGNoKCIpIikmJnRoaXMuY29uZmlnLnRvbGVyYW50Pyh0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKHRoaXMubmV4dFRva2VuKCkpLGU9dGhpcy5maW5hbGl6ZSh0aGlzLmNyZWF0ZU5vZGUoKSxuZXcgYS5FbXB0eVN0YXRlbWVudCkpOih0aGlzLmV4cGVjdCgiKSIpLGU9dGhpcy5wYXJzZUlmQ2xhdXNlKCksdGhpcy5tYXRjaEtleXdvcmQoImVsc2UiKSYmKHRoaXMubmV4dFRva2VuKCksbj10aGlzLnBhcnNlSWZDbGF1c2UoKSkpLHRoaXMuZmluYWxpemUodCxuZXcgYS5JZlN0YXRlbWVudChyLGUsbikpfSxlLnByb3RvdHlwZS5wYXJzZURvV2hpbGVTdGF0ZW1lbnQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKTt0aGlzLmV4cGVjdEtleXdvcmQoImRvIik7dmFyIHQ9dGhpcy5jb250ZXh0LmluSXRlcmF0aW9uO3RoaXMuY29udGV4dC5pbkl0ZXJhdGlvbj0hMDt2YXIgbj10aGlzLnBhcnNlU3RhdGVtZW50KCk7dGhpcy5jb250ZXh0LmluSXRlcmF0aW9uPXQsdGhpcy5leHBlY3RLZXl3b3JkKCJ3aGlsZSIpLHRoaXMuZXhwZWN0KCIoIik7dmFyIHI9dGhpcy5wYXJzZUV4cHJlc3Npb24oKTtyZXR1cm4hdGhpcy5tYXRjaCgiKSIpJiZ0aGlzLmNvbmZpZy50b2xlcmFudD90aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKHRoaXMubmV4dFRva2VuKCkpOih0aGlzLmV4cGVjdCgiKSIpLHRoaXMubWF0Y2goIjsiKSYmdGhpcy5uZXh0VG9rZW4oKSksdGhpcy5maW5hbGl6ZShlLG5ldyBhLkRvV2hpbGVTdGF0ZW1lbnQobixyKSl9LGUucHJvdG90eXBlLnBhcnNlV2hpbGVTdGF0ZW1lbnQ9ZnVuY3Rpb24oKXt2YXIgZSx0PXRoaXMuY3JlYXRlTm9kZSgpO3RoaXMuZXhwZWN0S2V5d29yZCgid2hpbGUiKSx0aGlzLmV4cGVjdCgiKCIpO3ZhciBuPXRoaXMucGFyc2VFeHByZXNzaW9uKCk7aWYoIXRoaXMubWF0Y2goIikiKSYmdGhpcy5jb25maWcudG9sZXJhbnQpdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbih0aGlzLm5leHRUb2tlbigpKSxlPXRoaXMuZmluYWxpemUodGhpcy5jcmVhdGVOb2RlKCksbmV3IGEuRW1wdHlTdGF0ZW1lbnQpO2Vsc2V7dGhpcy5leHBlY3QoIikiKTt2YXIgcj10aGlzLmNvbnRleHQuaW5JdGVyYXRpb247dGhpcy5jb250ZXh0LmluSXRlcmF0aW9uPSEwLGU9dGhpcy5wYXJzZVN0YXRlbWVudCgpLHRoaXMuY29udGV4dC5pbkl0ZXJhdGlvbj1yfXJldHVybiB0aGlzLmZpbmFsaXplKHQsbmV3IGEuV2hpbGVTdGF0ZW1lbnQobixlKSl9LGUucHJvdG90eXBlLnBhcnNlRm9yU3RhdGVtZW50PWZ1bmN0aW9uKCl7dmFyIGUsdCxuPW51bGwscj1udWxsLGk9bnVsbCxzPSEwLGM9dGhpcy5jcmVhdGVOb2RlKCk7aWYodGhpcy5leHBlY3RLZXl3b3JkKCJmb3IiKSx0aGlzLmV4cGVjdCgiKCIpLHRoaXMubWF0Y2goIjsiKSl0aGlzLm5leHRUb2tlbigpO2Vsc2UgaWYodGhpcy5tYXRjaEtleXdvcmQoInZhciIpKXtuPXRoaXMuY3JlYXRlTm9kZSgpLHRoaXMubmV4dFRva2VuKCk7dmFyIGw9dGhpcy5jb250ZXh0LmFsbG93SW47dGhpcy5jb250ZXh0LmFsbG93SW49ITE7dmFyIHA9dGhpcy5wYXJzZVZhcmlhYmxlRGVjbGFyYXRpb25MaXN0KHtpbkZvcjohMH0pO2lmKHRoaXMuY29udGV4dC5hbGxvd0luPWwsMT09PXAubGVuZ3RoJiZ0aGlzLm1hdGNoS2V5d29yZCgiaW4iKSl7dmFyIGY9cFswXTtmLmluaXQmJihmLmlkLnR5cGU9PT11LlN5bnRheC5BcnJheVBhdHRlcm58fGYuaWQudHlwZT09PXUuU3ludGF4Lk9iamVjdFBhdHRlcm58fHRoaXMuY29udGV4dC5zdHJpY3QpJiZ0aGlzLnRvbGVyYXRlRXJyb3Ioby5NZXNzYWdlcy5Gb3JJbk9mTG9vcEluaXRpYWxpemVyLCJmb3ItaW4iKSxuPXRoaXMuZmluYWxpemUobixuZXcgYS5WYXJpYWJsZURlY2xhcmF0aW9uKHAsInZhciIpKSx0aGlzLm5leHRUb2tlbigpLGU9bix0PXRoaXMucGFyc2VFeHByZXNzaW9uKCksbj1udWxsfWVsc2UgMT09PXAubGVuZ3RoJiZudWxsPT09cFswXS5pbml0JiZ0aGlzLm1hdGNoQ29udGV4dHVhbEtleXdvcmQoIm9mIik/KG49dGhpcy5maW5hbGl6ZShuLG5ldyBhLlZhcmlhYmxlRGVjbGFyYXRpb24ocCwidmFyIikpLHRoaXMubmV4dFRva2VuKCksZT1uLHQ9dGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKCksbj1udWxsLHM9ITEpOihuPXRoaXMuZmluYWxpemUobixuZXcgYS5WYXJpYWJsZURlY2xhcmF0aW9uKHAsInZhciIpKSx0aGlzLmV4cGVjdCgiOyIpKX1lbHNlIGlmKHRoaXMubWF0Y2hLZXl3b3JkKCJjb25zdCIpfHx0aGlzLm1hdGNoS2V5d29yZCgibGV0Iikpe249dGhpcy5jcmVhdGVOb2RlKCk7dmFyIGQ9dGhpcy5uZXh0VG9rZW4oKS52YWx1ZTtpZih0aGlzLmNvbnRleHQuc3RyaWN0fHwiaW4iIT09dGhpcy5sb29rYWhlYWQudmFsdWUpe3ZhciBsPXRoaXMuY29udGV4dC5hbGxvd0luO3RoaXMuY29udGV4dC5hbGxvd0luPSExO3ZhciBwPXRoaXMucGFyc2VCaW5kaW5nTGlzdChkLHtpbkZvcjohMH0pO3RoaXMuY29udGV4dC5hbGxvd0luPWwsMT09PXAubGVuZ3RoJiZudWxsPT09cFswXS5pbml0JiZ0aGlzLm1hdGNoS2V5d29yZCgiaW4iKT8obj10aGlzLmZpbmFsaXplKG4sbmV3IGEuVmFyaWFibGVEZWNsYXJhdGlvbihwLGQpKSx0aGlzLm5leHRUb2tlbigpLGU9bix0PXRoaXMucGFyc2VFeHByZXNzaW9uKCksbj1udWxsKToxPT09cC5sZW5ndGgmJm51bGw9PT1wWzBdLmluaXQmJnRoaXMubWF0Y2hDb250ZXh0dWFsS2V5d29yZCgib2YiKT8obj10aGlzLmZpbmFsaXplKG4sbmV3IGEuVmFyaWFibGVEZWNsYXJhdGlvbihwLGQpKSx0aGlzLm5leHRUb2tlbigpLGU9bix0PXRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbigpLG49bnVsbCxzPSExKToodGhpcy5jb25zdW1lU2VtaWNvbG9uKCksbj10aGlzLmZpbmFsaXplKG4sbmV3IGEuVmFyaWFibGVEZWNsYXJhdGlvbihwLGQpKSl9ZWxzZSBuPXRoaXMuZmluYWxpemUobixuZXcgYS5JZGVudGlmaWVyKGQpKSx0aGlzLm5leHRUb2tlbigpLGU9bix0PXRoaXMucGFyc2VFeHByZXNzaW9uKCksbj1udWxsfWVsc2V7dmFyIGg9dGhpcy5sb29rYWhlYWQsbD10aGlzLmNvbnRleHQuYWxsb3dJbjtpZih0aGlzLmNvbnRleHQuYWxsb3dJbj0hMSxuPXRoaXMuaW5oZXJpdENvdmVyR3JhbW1hcih0aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24pLHRoaXMuY29udGV4dC5hbGxvd0luPWwsdGhpcy5tYXRjaEtleXdvcmQoImluIikpdGhpcy5jb250ZXh0LmlzQXNzaWdubWVudFRhcmdldCYmbi50eXBlIT09dS5TeW50YXguQXNzaWdubWVudEV4cHJlc3Npb258fHRoaXMudG9sZXJhdGVFcnJvcihvLk1lc3NhZ2VzLkludmFsaWRMSFNJbkZvckluKSx0aGlzLm5leHRUb2tlbigpLHRoaXMucmVpbnRlcnByZXRFeHByZXNzaW9uQXNQYXR0ZXJuKG4pLGU9bix0PXRoaXMucGFyc2VFeHByZXNzaW9uKCksbj1udWxsO2Vsc2UgaWYodGhpcy5tYXRjaENvbnRleHR1YWxLZXl3b3JkKCJvZiIpKXRoaXMuY29udGV4dC5pc0Fzc2lnbm1lbnRUYXJnZXQmJm4udHlwZSE9PXUuU3ludGF4LkFzc2lnbm1lbnRFeHByZXNzaW9ufHx0aGlzLnRvbGVyYXRlRXJyb3Ioby5NZXNzYWdlcy5JbnZhbGlkTEhTSW5Gb3JMb29wKSx0aGlzLm5leHRUb2tlbigpLHRoaXMucmVpbnRlcnByZXRFeHByZXNzaW9uQXNQYXR0ZXJuKG4pLGU9bix0PXRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbigpLG49bnVsbCxzPSExO2Vsc2V7aWYodGhpcy5tYXRjaCgiLCIpKXtmb3IodmFyIG09W25dO3RoaXMubWF0Y2goIiwiKTspdGhpcy5uZXh0VG9rZW4oKSxtLnB1c2godGhpcy5pc29sYXRlQ292ZXJHcmFtbWFyKHRoaXMucGFyc2VBc3NpZ25tZW50RXhwcmVzc2lvbikpO249dGhpcy5maW5hbGl6ZSh0aGlzLnN0YXJ0Tm9kZShoKSxuZXcgYS5TZXF1ZW5jZUV4cHJlc3Npb24obSkpfXRoaXMuZXhwZWN0KCI7Iil9fSJ1bmRlZmluZWQiPT09dHlwZW9mIGUmJih0aGlzLm1hdGNoKCI7Iil8fChyPXRoaXMucGFyc2VFeHByZXNzaW9uKCkpLHRoaXMuZXhwZWN0KCI7IiksdGhpcy5tYXRjaCgiKSIpfHwoaT10aGlzLnBhcnNlRXhwcmVzc2lvbigpKSk7dmFyIGc7aWYoIXRoaXMubWF0Y2goIikiKSYmdGhpcy5jb25maWcudG9sZXJhbnQpdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbih0aGlzLm5leHRUb2tlbigpKSxnPXRoaXMuZmluYWxpemUodGhpcy5jcmVhdGVOb2RlKCksbmV3IGEuRW1wdHlTdGF0ZW1lbnQpO2Vsc2V7dGhpcy5leHBlY3QoIikiKTt2YXIgeT10aGlzLmNvbnRleHQuaW5JdGVyYXRpb247dGhpcy5jb250ZXh0LmluSXRlcmF0aW9uPSEwLGc9dGhpcy5pc29sYXRlQ292ZXJHcmFtbWFyKHRoaXMucGFyc2VTdGF0ZW1lbnQpLHRoaXMuY29udGV4dC5pbkl0ZXJhdGlvbj15fXJldHVybiJ1bmRlZmluZWQiPT09dHlwZW9mIGU/dGhpcy5maW5hbGl6ZShjLG5ldyBhLkZvclN0YXRlbWVudChuLHIsaSxnKSk6cz90aGlzLmZpbmFsaXplKGMsbmV3IGEuRm9ySW5TdGF0ZW1lbnQoZSx0LGcpKTp0aGlzLmZpbmFsaXplKGMsbmV3IGEuRm9yT2ZTdGF0ZW1lbnQoZSx0LGcpKX0sZS5wcm90b3R5cGUucGFyc2VDb250aW51ZVN0YXRlbWVudD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpO3RoaXMuZXhwZWN0S2V5d29yZCgiY29udGludWUiKTt2YXIgdD1udWxsO2lmKDM9PT10aGlzLmxvb2thaGVhZC50eXBlJiYhdGhpcy5oYXNMaW5lVGVybWluYXRvcil7dmFyIG49dGhpcy5wYXJzZVZhcmlhYmxlSWRlbnRpZmllcigpO3Q9bjt2YXIgcj0iJCIrbi5uYW1lO09iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLmNvbnRleHQubGFiZWxTZXQscil8fHRoaXMudGhyb3dFcnJvcihvLk1lc3NhZ2VzLlVua25vd25MYWJlbCxuLm5hbWUpfXJldHVybiB0aGlzLmNvbnN1bWVTZW1pY29sb24oKSxudWxsIT09dHx8dGhpcy5jb250ZXh0LmluSXRlcmF0aW9ufHx0aGlzLnRocm93RXJyb3Ioby5NZXNzYWdlcy5JbGxlZ2FsQ29udGludWUpLHRoaXMuZmluYWxpemUoZSxuZXcgYS5Db250aW51ZVN0YXRlbWVudCh0KSl9LGUucHJvdG90eXBlLnBhcnNlQnJlYWtTdGF0ZW1lbnQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKTt0aGlzLmV4cGVjdEtleXdvcmQoImJyZWFrIik7dmFyIHQ9bnVsbDtpZigzPT09dGhpcy5sb29rYWhlYWQudHlwZSYmIXRoaXMuaGFzTGluZVRlcm1pbmF0b3Ipe3ZhciBuPXRoaXMucGFyc2VWYXJpYWJsZUlkZW50aWZpZXIoKSxyPSIkIituLm5hbWU7T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRoaXMuY29udGV4dC5sYWJlbFNldCxyKXx8dGhpcy50aHJvd0Vycm9yKG8uTWVzc2FnZXMuVW5rbm93bkxhYmVsLG4ubmFtZSksdD1ufXJldHVybiB0aGlzLmNvbnN1bWVTZW1pY29sb24oKSxudWxsIT09dHx8dGhpcy5jb250ZXh0LmluSXRlcmF0aW9ufHx0aGlzLmNvbnRleHQuaW5Td2l0Y2h8fHRoaXMudGhyb3dFcnJvcihvLk1lc3NhZ2VzLklsbGVnYWxCcmVhayksdGhpcy5maW5hbGl6ZShlLG5ldyBhLkJyZWFrU3RhdGVtZW50KHQpKX0sZS5wcm90b3R5cGUucGFyc2VSZXR1cm5TdGF0ZW1lbnQ9ZnVuY3Rpb24oKXt0aGlzLmNvbnRleHQuaW5GdW5jdGlvbkJvZHl8fHRoaXMudG9sZXJhdGVFcnJvcihvLk1lc3NhZ2VzLklsbGVnYWxSZXR1cm4pO3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpO3RoaXMuZXhwZWN0S2V5d29yZCgicmV0dXJuIik7dmFyIHQ9IXRoaXMubWF0Y2goIjsiKSYmIXRoaXMubWF0Y2goIn0iKSYmIXRoaXMuaGFzTGluZVRlcm1pbmF0b3ImJjIhPT10aGlzLmxvb2thaGVhZC50eXBlLG49dD90aGlzLnBhcnNlRXhwcmVzc2lvbigpOm51bGw7cmV0dXJuIHRoaXMuY29uc3VtZVNlbWljb2xvbigpLHRoaXMuZmluYWxpemUoZSxuZXcgYS5SZXR1cm5TdGF0ZW1lbnQobikpfSxlLnByb3RvdHlwZS5wYXJzZVdpdGhTdGF0ZW1lbnQ9ZnVuY3Rpb24oKXt0aGlzLmNvbnRleHQuc3RyaWN0JiZ0aGlzLnRvbGVyYXRlRXJyb3Ioby5NZXNzYWdlcy5TdHJpY3RNb2RlV2l0aCk7dmFyIGUsdD10aGlzLmNyZWF0ZU5vZGUoKTt0aGlzLmV4cGVjdEtleXdvcmQoIndpdGgiKSx0aGlzLmV4cGVjdCgiKCIpO3ZhciBuPXRoaXMucGFyc2VFeHByZXNzaW9uKCk7cmV0dXJuIXRoaXMubWF0Y2goIikiKSYmdGhpcy5jb25maWcudG9sZXJhbnQ/KHRoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4odGhpcy5uZXh0VG9rZW4oKSksZT10aGlzLmZpbmFsaXplKHRoaXMuY3JlYXRlTm9kZSgpLG5ldyBhLkVtcHR5U3RhdGVtZW50KSk6KHRoaXMuZXhwZWN0KCIpIiksZT10aGlzLnBhcnNlU3RhdGVtZW50KCkpLHRoaXMuZmluYWxpemUodCxuZXcgYS5XaXRoU3RhdGVtZW50KG4sZSkpfSxlLnByb3RvdHlwZS5wYXJzZVN3aXRjaENhc2U9ZnVuY3Rpb24oKXt2YXIgZSx0PXRoaXMuY3JlYXRlTm9kZSgpO3RoaXMubWF0Y2hLZXl3b3JkKCJkZWZhdWx0Iik/KHRoaXMubmV4dFRva2VuKCksZT1udWxsKToodGhpcy5leHBlY3RLZXl3b3JkKCJjYXNlIiksZT10aGlzLnBhcnNlRXhwcmVzc2lvbigpKSx0aGlzLmV4cGVjdCgiOiIpO2Zvcih2YXIgbj1bXTs7KXtpZih0aGlzLm1hdGNoKCJ9Iil8fHRoaXMubWF0Y2hLZXl3b3JkKCJkZWZhdWx0Iil8fHRoaXMubWF0Y2hLZXl3b3JkKCJjYXNlIikpYnJlYWs7bi5wdXNoKHRoaXMucGFyc2VTdGF0ZW1lbnRMaXN0SXRlbSgpKX1yZXR1cm4gdGhpcy5maW5hbGl6ZSh0LG5ldyBhLlN3aXRjaENhc2UoZSxuKSl9LGUucHJvdG90eXBlLnBhcnNlU3dpdGNoU3RhdGVtZW50PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCk7dGhpcy5leHBlY3RLZXl3b3JkKCJzd2l0Y2giKSx0aGlzLmV4cGVjdCgiKCIpO3ZhciB0PXRoaXMucGFyc2VFeHByZXNzaW9uKCk7dGhpcy5leHBlY3QoIikiKTt2YXIgbj10aGlzLmNvbnRleHQuaW5Td2l0Y2g7dGhpcy5jb250ZXh0LmluU3dpdGNoPSEwO3ZhciByPVtdLGk9ITE7Zm9yKHRoaXMuZXhwZWN0KCJ7Iik7Oyl7aWYodGhpcy5tYXRjaCgifSIpKWJyZWFrO3ZhciBzPXRoaXMucGFyc2VTd2l0Y2hDYXNlKCk7bnVsbD09PXMudGVzdCYmKGkmJnRoaXMudGhyb3dFcnJvcihvLk1lc3NhZ2VzLk11bHRpcGxlRGVmYXVsdHNJblN3aXRjaCksaT0hMCksci5wdXNoKHMpfXJldHVybiB0aGlzLmV4cGVjdCgifSIpLHRoaXMuY29udGV4dC5pblN3aXRjaD1uLHRoaXMuZmluYWxpemUoZSxuZXcgYS5Td2l0Y2hTdGF0ZW1lbnQodCxyKSl9LGUucHJvdG90eXBlLnBhcnNlTGFiZWxsZWRTdGF0ZW1lbnQ9ZnVuY3Rpb24oKXt2YXIgZSx0PXRoaXMuY3JlYXRlTm9kZSgpLG49dGhpcy5wYXJzZUV4cHJlc3Npb24oKTtpZihuLnR5cGU9PT11LlN5bnRheC5JZGVudGlmaWVyJiZ0aGlzLm1hdGNoKCI6Iikpe3RoaXMubmV4dFRva2VuKCk7dmFyIHI9bixpPSIkIityLm5hbWU7T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRoaXMuY29udGV4dC5sYWJlbFNldCxpKSYmdGhpcy50aHJvd0Vycm9yKG8uTWVzc2FnZXMuUmVkZWNsYXJhdGlvbiwiTGFiZWwiLHIubmFtZSksdGhpcy5jb250ZXh0LmxhYmVsU2V0W2ldPSEwO3ZhciBzPXZvaWQgMDtpZih0aGlzLm1hdGNoS2V5d29yZCgiY2xhc3MiKSl0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKHRoaXMubG9va2FoZWFkKSxzPXRoaXMucGFyc2VDbGFzc0RlY2xhcmF0aW9uKCk7ZWxzZSBpZih0aGlzLm1hdGNoS2V5d29yZCgiZnVuY3Rpb24iKSl7dmFyIGM9dGhpcy5sb29rYWhlYWQsbD10aGlzLnBhcnNlRnVuY3Rpb25EZWNsYXJhdGlvbigpO3RoaXMuY29udGV4dC5zdHJpY3Q/dGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbihjLG8uTWVzc2FnZXMuU3RyaWN0RnVuY3Rpb24pOmwuZ2VuZXJhdG9yJiZ0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKGMsby5NZXNzYWdlcy5HZW5lcmF0b3JJbkxlZ2FjeUNvbnRleHQpLHM9bH1lbHNlIHM9dGhpcy5wYXJzZVN0YXRlbWVudCgpO2RlbGV0ZSB0aGlzLmNvbnRleHQubGFiZWxTZXRbaV0sZT1uZXcgYS5MYWJlbGVkU3RhdGVtZW50KHIscyl9ZWxzZSB0aGlzLmNvbnN1bWVTZW1pY29sb24oKSxlPW5ldyBhLkV4cHJlc3Npb25TdGF0ZW1lbnQobik7cmV0dXJuIHRoaXMuZmluYWxpemUodCxlKX0sZS5wcm90b3R5cGUucGFyc2VUaHJvd1N0YXRlbWVudD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpO3RoaXMuZXhwZWN0S2V5d29yZCgidGhyb3ciKSx0aGlzLmhhc0xpbmVUZXJtaW5hdG9yJiZ0aGlzLnRocm93RXJyb3Ioby5NZXNzYWdlcy5OZXdsaW5lQWZ0ZXJUaHJvdyk7dmFyIHQ9dGhpcy5wYXJzZUV4cHJlc3Npb24oKTtyZXR1cm4gdGhpcy5jb25zdW1lU2VtaWNvbG9uKCksdGhpcy5maW5hbGl6ZShlLG5ldyBhLlRocm93U3RhdGVtZW50KHQpKX0sZS5wcm90b3R5cGUucGFyc2VDYXRjaENsYXVzZT1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpO3RoaXMuZXhwZWN0S2V5d29yZCgiY2F0Y2giKSx0aGlzLmV4cGVjdCgiKCIpLHRoaXMubWF0Y2goIikiKSYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0aGlzLmxvb2thaGVhZCk7Zm9yKHZhciB0PVtdLG49dGhpcy5wYXJzZVBhdHRlcm4odCkscj17fSxpPTA7aTx0Lmxlbmd0aDtpKyspe3ZhciBzPSIkIit0W2ldLnZhbHVlO09iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChyLHMpJiZ0aGlzLnRvbGVyYXRlRXJyb3Ioby5NZXNzYWdlcy5EdXBsaWNhdGVCaW5kaW5nLHRbaV0udmFsdWUpLHJbc109ITB9dGhpcy5jb250ZXh0LnN0cmljdCYmbi50eXBlPT09dS5TeW50YXguSWRlbnRpZmllciYmdGhpcy5zY2FubmVyLmlzUmVzdHJpY3RlZFdvcmQobi5uYW1lKSYmdGhpcy50b2xlcmF0ZUVycm9yKG8uTWVzc2FnZXMuU3RyaWN0Q2F0Y2hWYXJpYWJsZSksdGhpcy5leHBlY3QoIikiKTt2YXIgYz10aGlzLnBhcnNlQmxvY2soKTtyZXR1cm4gdGhpcy5maW5hbGl6ZShlLG5ldyBhLkNhdGNoQ2xhdXNlKG4sYykpfSxlLnByb3RvdHlwZS5wYXJzZUZpbmFsbHlDbGF1c2U9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5leHBlY3RLZXl3b3JkKCJmaW5hbGx5IiksdGhpcy5wYXJzZUJsb2NrKCl9LGUucHJvdG90eXBlLnBhcnNlVHJ5U3RhdGVtZW50PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCk7dGhpcy5leHBlY3RLZXl3b3JkKCJ0cnkiKTt2YXIgdD10aGlzLnBhcnNlQmxvY2soKSxuPXRoaXMubWF0Y2hLZXl3b3JkKCJjYXRjaCIpP3RoaXMucGFyc2VDYXRjaENsYXVzZSgpOm51bGwscj10aGlzLm1hdGNoS2V5d29yZCgiZmluYWxseSIpP3RoaXMucGFyc2VGaW5hbGx5Q2xhdXNlKCk6bnVsbDtyZXR1cm4gbnx8cnx8dGhpcy50aHJvd0Vycm9yKG8uTWVzc2FnZXMuTm9DYXRjaE9yRmluYWxseSksdGhpcy5maW5hbGl6ZShlLG5ldyBhLlRyeVN0YXRlbWVudCh0LG4scikpfSxlLnByb3RvdHlwZS5wYXJzZURlYnVnZ2VyU3RhdGVtZW50PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCk7cmV0dXJuIHRoaXMuZXhwZWN0S2V5d29yZCgiZGVidWdnZXIiKSx0aGlzLmNvbnN1bWVTZW1pY29sb24oKSx0aGlzLmZpbmFsaXplKGUsbmV3IGEuRGVidWdnZXJTdGF0ZW1lbnQpfSxlLnByb3RvdHlwZS5wYXJzZVN0YXRlbWVudD1mdW5jdGlvbigpe3ZhciBlO3N3aXRjaCh0aGlzLmxvb2thaGVhZC50eXBlKXtjYXNlIDE6Y2FzZSA1OmNhc2UgNjpjYXNlIDg6Y2FzZSAxMDpjYXNlIDk6ZT10aGlzLnBhcnNlRXhwcmVzc2lvblN0YXRlbWVudCgpO2JyZWFrO2Nhc2UgNzp2YXIgdD10aGlzLmxvb2thaGVhZC52YWx1ZTtlPSJ7Ij09PXQ/dGhpcy5wYXJzZUJsb2NrKCk6IigiPT09dD90aGlzLnBhcnNlRXhwcmVzc2lvblN0YXRlbWVudCgpOiI7Ij09PXQ/dGhpcy5wYXJzZUVtcHR5U3RhdGVtZW50KCk6dGhpcy5wYXJzZUV4cHJlc3Npb25TdGF0ZW1lbnQoKTticmVhaztjYXNlIDM6ZT10aGlzLm1hdGNoQXN5bmNGdW5jdGlvbigpP3RoaXMucGFyc2VGdW5jdGlvbkRlY2xhcmF0aW9uKCk6dGhpcy5wYXJzZUxhYmVsbGVkU3RhdGVtZW50KCk7YnJlYWs7Y2FzZSA0OnN3aXRjaCh0aGlzLmxvb2thaGVhZC52YWx1ZSl7Y2FzZSJicmVhayI6ZT10aGlzLnBhcnNlQnJlYWtTdGF0ZW1lbnQoKTticmVhaztjYXNlImNvbnRpbnVlIjplPXRoaXMucGFyc2VDb250aW51ZVN0YXRlbWVudCgpO2JyZWFrO2Nhc2UiZGVidWdnZXIiOmU9dGhpcy5wYXJzZURlYnVnZ2VyU3RhdGVtZW50KCk7YnJlYWs7Y2FzZSJkbyI6ZT10aGlzLnBhcnNlRG9XaGlsZVN0YXRlbWVudCgpO2JyZWFrO2Nhc2UiZm9yIjplPXRoaXMucGFyc2VGb3JTdGF0ZW1lbnQoKTticmVhaztjYXNlImZ1bmN0aW9uIjplPXRoaXMucGFyc2VGdW5jdGlvbkRlY2xhcmF0aW9uKCk7YnJlYWs7Y2FzZSJpZiI6ZT10aGlzLnBhcnNlSWZTdGF0ZW1lbnQoKTticmVhaztjYXNlInJldHVybiI6ZT10aGlzLnBhcnNlUmV0dXJuU3RhdGVtZW50KCk7YnJlYWs7Y2FzZSJzd2l0Y2giOmU9dGhpcy5wYXJzZVN3aXRjaFN0YXRlbWVudCgpO2JyZWFrO2Nhc2UidGhyb3ciOmU9dGhpcy5wYXJzZVRocm93U3RhdGVtZW50KCk7YnJlYWs7Y2FzZSJ0cnkiOmU9dGhpcy5wYXJzZVRyeVN0YXRlbWVudCgpO2JyZWFrO2Nhc2UidmFyIjplPXRoaXMucGFyc2VWYXJpYWJsZVN0YXRlbWVudCgpO2JyZWFrO2Nhc2Uid2hpbGUiOmU9dGhpcy5wYXJzZVdoaWxlU3RhdGVtZW50KCk7YnJlYWs7Y2FzZSJ3aXRoIjplPXRoaXMucGFyc2VXaXRoU3RhdGVtZW50KCk7YnJlYWs7ZGVmYXVsdDplPXRoaXMucGFyc2VFeHByZXNzaW9uU3RhdGVtZW50KCl9YnJlYWs7ZGVmYXVsdDplPXRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odGhpcy5sb29rYWhlYWQpfXJldHVybiBlfSxlLnByb3RvdHlwZS5wYXJzZUZ1bmN0aW9uU291cmNlRWxlbWVudHM9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKTt0aGlzLmV4cGVjdCgieyIpO3ZhciB0PXRoaXMucGFyc2VEaXJlY3RpdmVQcm9sb2d1ZXMoKSxuPXRoaXMuY29udGV4dC5sYWJlbFNldCxyPXRoaXMuY29udGV4dC5pbkl0ZXJhdGlvbixpPXRoaXMuY29udGV4dC5pblN3aXRjaCxvPXRoaXMuY29udGV4dC5pbkZ1bmN0aW9uQm9keTtmb3IodGhpcy5jb250ZXh0LmxhYmVsU2V0PXt9LHRoaXMuY29udGV4dC5pbkl0ZXJhdGlvbj0hMSx0aGlzLmNvbnRleHQuaW5Td2l0Y2g9ITEsdGhpcy5jb250ZXh0LmluRnVuY3Rpb25Cb2R5PSEwOzIhPT10aGlzLmxvb2thaGVhZC50eXBlJiYhdGhpcy5tYXRjaCgifSIpOyl0LnB1c2godGhpcy5wYXJzZVN0YXRlbWVudExpc3RJdGVtKCkpO3JldHVybiB0aGlzLmV4cGVjdCgifSIpLHRoaXMuY29udGV4dC5sYWJlbFNldD1uLHRoaXMuY29udGV4dC5pbkl0ZXJhdGlvbj1yLHRoaXMuY29udGV4dC5pblN3aXRjaD1pLHRoaXMuY29udGV4dC5pbkZ1bmN0aW9uQm9keT1vLHRoaXMuZmluYWxpemUoZSxuZXcgYS5CbG9ja1N0YXRlbWVudCh0KSl9LGUucHJvdG90eXBlLnZhbGlkYXRlUGFyYW09ZnVuY3Rpb24oZSx0LG4pe3ZhciByPSIkIituO3RoaXMuY29udGV4dC5zdHJpY3Q/KHRoaXMuc2Nhbm5lci5pc1Jlc3RyaWN0ZWRXb3JkKG4pJiYoZS5zdHJpY3RlZD10LGUubWVzc2FnZT1vLk1lc3NhZ2VzLlN0cmljdFBhcmFtTmFtZSksT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGUucGFyYW1TZXQscikmJihlLnN0cmljdGVkPXQsZS5tZXNzYWdlPW8uTWVzc2FnZXMuU3RyaWN0UGFyYW1EdXBlKSk6ZS5maXJzdFJlc3RyaWN0ZWR8fCh0aGlzLnNjYW5uZXIuaXNSZXN0cmljdGVkV29yZChuKT8oZS5maXJzdFJlc3RyaWN0ZWQ9dCxlLm1lc3NhZ2U9by5NZXNzYWdlcy5TdHJpY3RQYXJhbU5hbWUpOnRoaXMuc2Nhbm5lci5pc1N0cmljdE1vZGVSZXNlcnZlZFdvcmQobik/KGUuZmlyc3RSZXN0cmljdGVkPXQsZS5tZXNzYWdlPW8uTWVzc2FnZXMuU3RyaWN0UmVzZXJ2ZWRXb3JkKTpPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZS5wYXJhbVNldCxyKSYmKGUuc3RyaWN0ZWQ9dCxlLm1lc3NhZ2U9by5NZXNzYWdlcy5TdHJpY3RQYXJhbUR1cGUpKSwiZnVuY3Rpb24iPT09dHlwZW9mIE9iamVjdC5kZWZpbmVQcm9wZXJ0eT9PYmplY3QuZGVmaW5lUHJvcGVydHkoZS5wYXJhbVNldCxyLHt2YWx1ZTohMCxlbnVtZXJhYmxlOiEwLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pOmUucGFyYW1TZXRbcl09ITB9LGUucHJvdG90eXBlLnBhcnNlUmVzdEVsZW1lbnQ9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5jcmVhdGVOb2RlKCk7dGhpcy5leHBlY3QoIi4uLiIpO3ZhciBuPXRoaXMucGFyc2VQYXR0ZXJuKGUpO3JldHVybiB0aGlzLm1hdGNoKCI9IikmJnRoaXMudGhyb3dFcnJvcihvLk1lc3NhZ2VzLkRlZmF1bHRSZXN0UGFyYW1ldGVyKSx0aGlzLm1hdGNoKCIpIil8fHRoaXMudGhyb3dFcnJvcihvLk1lc3NhZ2VzLlBhcmFtZXRlckFmdGVyUmVzdFBhcmFtZXRlciksdGhpcy5maW5hbGl6ZSh0LG5ldyBhLlJlc3RFbGVtZW50KG4pKX0sZS5wcm90b3R5cGUucGFyc2VGb3JtYWxQYXJhbWV0ZXI9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0PVtdLG49dGhpcy5tYXRjaCgiLi4uIik/dGhpcy5wYXJzZVJlc3RFbGVtZW50KHQpOnRoaXMucGFyc2VQYXR0ZXJuV2l0aERlZmF1bHQodCkscj0wO3I8dC5sZW5ndGg7cisrKXRoaXMudmFsaWRhdGVQYXJhbShlLHRbcl0sdFtyXS52YWx1ZSk7ZS5zaW1wbGU9ZS5zaW1wbGUmJm4gaW5zdGFuY2VvZiBhLklkZW50aWZpZXIsZS5wYXJhbXMucHVzaChuKX0sZS5wcm90b3R5cGUucGFyc2VGb3JtYWxQYXJhbWV0ZXJzPWZ1bmN0aW9uKGUpe3ZhciB0O2lmKHQ9e3NpbXBsZTohMCxwYXJhbXM6W10sZmlyc3RSZXN0cmljdGVkOmV9LHRoaXMuZXhwZWN0KCIoIiksIXRoaXMubWF0Y2goIikiKSlmb3IodC5wYXJhbVNldD17fTsyIT09dGhpcy5sb29rYWhlYWQudHlwZSYmKHRoaXMucGFyc2VGb3JtYWxQYXJhbWV0ZXIodCksIXRoaXMubWF0Y2goIikiKSkmJih0aGlzLmV4cGVjdCgiLCIpLCF0aGlzLm1hdGNoKCIpIikpOyk7cmV0dXJuIHRoaXMuZXhwZWN0KCIpIikse3NpbXBsZTp0LnNpbXBsZSxwYXJhbXM6dC5wYXJhbXMsc3RyaWN0ZWQ6dC5zdHJpY3RlZCxmaXJzdFJlc3RyaWN0ZWQ6dC5maXJzdFJlc3RyaWN0ZWQsbWVzc2FnZTp0Lm1lc3NhZ2V9fSxlLnByb3RvdHlwZS5tYXRjaEFzeW5jRnVuY3Rpb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLm1hdGNoQ29udGV4dHVhbEtleXdvcmQoImFzeW5jIik7aWYoZSl7dmFyIHQ9dGhpcy5zY2FubmVyLnNhdmVTdGF0ZSgpO3RoaXMuc2Nhbm5lci5zY2FuQ29tbWVudHMoKTt2YXIgbj10aGlzLnNjYW5uZXIubGV4KCk7dGhpcy5zY2FubmVyLnJlc3RvcmVTdGF0ZSh0KSxlPXQubGluZU51bWJlcj09PW4ubGluZU51bWJlciYmND09PW4udHlwZSYmImZ1bmN0aW9uIj09PW4udmFsdWV9cmV0dXJuIGV9LGUucHJvdG90eXBlLnBhcnNlRnVuY3Rpb25EZWNsYXJhdGlvbj1mdW5jdGlvbihlKXt2YXIgdD10aGlzLmNyZWF0ZU5vZGUoKSxuPXRoaXMubWF0Y2hDb250ZXh0dWFsS2V5d29yZCgiYXN5bmMiKTtuJiZ0aGlzLm5leHRUb2tlbigpLHRoaXMuZXhwZWN0S2V5d29yZCgiZnVuY3Rpb24iKTt2YXIgcj0hbiYmdGhpcy5tYXRjaCgiKiIpO3ImJnRoaXMubmV4dFRva2VuKCk7dmFyIGkscz1udWxsLHU9bnVsbDtpZighZXx8IXRoaXMubWF0Y2goIigiKSl7dmFyIGM9dGhpcy5sb29rYWhlYWQ7cz10aGlzLnBhcnNlVmFyaWFibGVJZGVudGlmaWVyKCksdGhpcy5jb250ZXh0LnN0cmljdD90aGlzLnNjYW5uZXIuaXNSZXN0cmljdGVkV29yZChjLnZhbHVlKSYmdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbihjLG8uTWVzc2FnZXMuU3RyaWN0RnVuY3Rpb25OYW1lKTp0aGlzLnNjYW5uZXIuaXNSZXN0cmljdGVkV29yZChjLnZhbHVlKT8odT1jLGk9by5NZXNzYWdlcy5TdHJpY3RGdW5jdGlvbk5hbWUpOnRoaXMuc2Nhbm5lci5pc1N0cmljdE1vZGVSZXNlcnZlZFdvcmQoYy52YWx1ZSkmJih1PWMsaT1vLk1lc3NhZ2VzLlN0cmljdFJlc2VydmVkV29yZCl9dmFyIGw9dGhpcy5jb250ZXh0LmF3YWl0LHA9dGhpcy5jb250ZXh0LmFsbG93WWllbGQ7dGhpcy5jb250ZXh0LmF3YWl0PW4sdGhpcy5jb250ZXh0LmFsbG93WWllbGQ9IXI7dmFyIGY9dGhpcy5wYXJzZUZvcm1hbFBhcmFtZXRlcnModSksZD1mLnBhcmFtcyxoPWYuc3RyaWN0ZWQ7dT1mLmZpcnN0UmVzdHJpY3RlZCxmLm1lc3NhZ2UmJihpPWYubWVzc2FnZSk7dmFyIG09dGhpcy5jb250ZXh0LnN0cmljdCxnPXRoaXMuY29udGV4dC5hbGxvd1N0cmljdERpcmVjdGl2ZTt0aGlzLmNvbnRleHQuYWxsb3dTdHJpY3REaXJlY3RpdmU9Zi5zaW1wbGU7dmFyIHk9dGhpcy5wYXJzZUZ1bmN0aW9uU291cmNlRWxlbWVudHMoKTtyZXR1cm4gdGhpcy5jb250ZXh0LnN0cmljdCYmdSYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih1LGkpLHRoaXMuY29udGV4dC5zdHJpY3QmJmgmJnRoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4oaCxpKSx0aGlzLmNvbnRleHQuc3RyaWN0PW0sdGhpcy5jb250ZXh0LmFsbG93U3RyaWN0RGlyZWN0aXZlPWcsdGhpcy5jb250ZXh0LmF3YWl0PWwsdGhpcy5jb250ZXh0LmFsbG93WWllbGQ9cCxuP3RoaXMuZmluYWxpemUodCxuZXcgYS5Bc3luY0Z1bmN0aW9uRGVjbGFyYXRpb24ocyxkLHkpKTp0aGlzLmZpbmFsaXplKHQsbmV3IGEuRnVuY3Rpb25EZWNsYXJhdGlvbihzLGQseSxyKSl9LGUucHJvdG90eXBlLnBhcnNlRnVuY3Rpb25FeHByZXNzaW9uPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCksdD10aGlzLm1hdGNoQ29udGV4dHVhbEtleXdvcmQoImFzeW5jIik7dCYmdGhpcy5uZXh0VG9rZW4oKSx0aGlzLmV4cGVjdEtleXdvcmQoImZ1bmN0aW9uIik7dmFyIG49IXQmJnRoaXMubWF0Y2goIioiKTtuJiZ0aGlzLm5leHRUb2tlbigpO3ZhciByLGkscz1udWxsLHU9dGhpcy5jb250ZXh0LmF3YWl0LGM9dGhpcy5jb250ZXh0LmFsbG93WWllbGQ7aWYodGhpcy5jb250ZXh0LmF3YWl0PXQsdGhpcy5jb250ZXh0LmFsbG93WWllbGQ9IW4sIXRoaXMubWF0Y2goIigiKSl7dmFyIGw9dGhpcy5sb29rYWhlYWQ7cz10aGlzLmNvbnRleHQuc3RyaWN0fHxufHwhdGhpcy5tYXRjaEtleXdvcmQoInlpZWxkIik/dGhpcy5wYXJzZVZhcmlhYmxlSWRlbnRpZmllcigpOnRoaXMucGFyc2VJZGVudGlmaWVyTmFtZSgpLHRoaXMuY29udGV4dC5zdHJpY3Q/dGhpcy5zY2FubmVyLmlzUmVzdHJpY3RlZFdvcmQobC52YWx1ZSkmJnRoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4obCxvLk1lc3NhZ2VzLlN0cmljdEZ1bmN0aW9uTmFtZSk6dGhpcy5zY2FubmVyLmlzUmVzdHJpY3RlZFdvcmQobC52YWx1ZSk/KGk9bCxyPW8uTWVzc2FnZXMuU3RyaWN0RnVuY3Rpb25OYW1lKTp0aGlzLnNjYW5uZXIuaXNTdHJpY3RNb2RlUmVzZXJ2ZWRXb3JkKGwudmFsdWUpJiYoaT1sLHI9by5NZXNzYWdlcy5TdHJpY3RSZXNlcnZlZFdvcmQpfXZhciBwPXRoaXMucGFyc2VGb3JtYWxQYXJhbWV0ZXJzKGkpLGY9cC5wYXJhbXMsZD1wLnN0cmljdGVkO2k9cC5maXJzdFJlc3RyaWN0ZWQscC5tZXNzYWdlJiYocj1wLm1lc3NhZ2UpO3ZhciBoPXRoaXMuY29udGV4dC5zdHJpY3QsbT10aGlzLmNvbnRleHQuYWxsb3dTdHJpY3REaXJlY3RpdmU7dGhpcy5jb250ZXh0LmFsbG93U3RyaWN0RGlyZWN0aXZlPXAuc2ltcGxlO3ZhciBnPXRoaXMucGFyc2VGdW5jdGlvblNvdXJjZUVsZW1lbnRzKCk7cmV0dXJuIHRoaXMuY29udGV4dC5zdHJpY3QmJmkmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4oaSxyKSx0aGlzLmNvbnRleHQuc3RyaWN0JiZkJiZ0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKGQsciksdGhpcy5jb250ZXh0LnN0cmljdD1oLHRoaXMuY29udGV4dC5hbGxvd1N0cmljdERpcmVjdGl2ZT1tLHRoaXMuY29udGV4dC5hd2FpdD11LHRoaXMuY29udGV4dC5hbGxvd1lpZWxkPWMsdD90aGlzLmZpbmFsaXplKGUsbmV3IGEuQXN5bmNGdW5jdGlvbkV4cHJlc3Npb24ocyxmLGcpKTp0aGlzLmZpbmFsaXplKGUsbmV3IGEuRnVuY3Rpb25FeHByZXNzaW9uKHMsZixnLG4pKX0sZS5wcm90b3R5cGUucGFyc2VEaXJlY3RpdmU9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmxvb2thaGVhZCx0PXRoaXMuY3JlYXRlTm9kZSgpLG49dGhpcy5wYXJzZUV4cHJlc3Npb24oKSxyPW4udHlwZT09PXUuU3ludGF4LkxpdGVyYWw/dGhpcy5nZXRUb2tlblJhdyhlKS5zbGljZSgxLC0xKTpudWxsO3JldHVybiB0aGlzLmNvbnN1bWVTZW1pY29sb24oKSx0aGlzLmZpbmFsaXplKHQscj9uZXcgYS5EaXJlY3RpdmUobixyKTpuZXcgYS5FeHByZXNzaW9uU3RhdGVtZW50KG4pKX0sZS5wcm90b3R5cGUucGFyc2VEaXJlY3RpdmVQcm9sb2d1ZXM9ZnVuY3Rpb24oKXtmb3IodmFyIGU9bnVsbCx0PVtdOzspe3ZhciBuPXRoaXMubG9va2FoZWFkO2lmKDghPT1uLnR5cGUpYnJlYWs7dmFyIHI9dGhpcy5wYXJzZURpcmVjdGl2ZSgpO3QucHVzaChyKTt2YXIgaT1yLmRpcmVjdGl2ZTtpZigic3RyaW5nIiE9PXR5cGVvZiBpKWJyZWFrOyJ1c2Ugc3RyaWN0Ij09PWk/KHRoaXMuY29udGV4dC5zdHJpY3Q9ITAsZSYmdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbihlLG8uTWVzc2FnZXMuU3RyaWN0T2N0YWxMaXRlcmFsKSx0aGlzLmNvbnRleHQuYWxsb3dTdHJpY3REaXJlY3RpdmV8fHRoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4obixvLk1lc3NhZ2VzLklsbGVnYWxMYW5ndWFnZU1vZGVEaXJlY3RpdmUpKTohZSYmbi5vY3RhbCYmKGU9bil9cmV0dXJuIHR9LGUucHJvdG90eXBlLnF1YWxpZmllZFByb3BlcnR5TmFtZT1mdW5jdGlvbihlKXtzd2l0Y2goZS50eXBlKXtjYXNlIDM6Y2FzZSA4OmNhc2UgMTpjYXNlIDU6Y2FzZSA2OmNhc2UgNDpyZXR1cm4hMDtjYXNlIDc6cmV0dXJuIlsiPT09ZS52YWx1ZX1yZXR1cm4hMX0sZS5wcm90b3R5cGUucGFyc2VHZXR0ZXJNZXRob2Q9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKSx0PXRoaXMuY29udGV4dC5hbGxvd1lpZWxkO3RoaXMuY29udGV4dC5hbGxvd1lpZWxkPSExO3ZhciBuPXRoaXMucGFyc2VGb3JtYWxQYXJhbWV0ZXJzKCk7bi5wYXJhbXMubGVuZ3RoPjAmJnRoaXMudG9sZXJhdGVFcnJvcihvLk1lc3NhZ2VzLkJhZEdldHRlckFyaXR5KTt2YXIgcj10aGlzLnBhcnNlUHJvcGVydHlNZXRob2Qobik7cmV0dXJuIHRoaXMuY29udGV4dC5hbGxvd1lpZWxkPXQsdGhpcy5maW5hbGl6ZShlLG5ldyBhLkZ1bmN0aW9uRXhwcmVzc2lvbihudWxsLG4ucGFyYW1zLHIsITEpKX0sZS5wcm90b3R5cGUucGFyc2VTZXR0ZXJNZXRob2Q9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKSx0PXRoaXMuY29udGV4dC5hbGxvd1lpZWxkO3RoaXMuY29udGV4dC5hbGxvd1lpZWxkPSExO3ZhciBuPXRoaXMucGFyc2VGb3JtYWxQYXJhbWV0ZXJzKCk7MSE9PW4ucGFyYW1zLmxlbmd0aD90aGlzLnRvbGVyYXRlRXJyb3Ioby5NZXNzYWdlcy5CYWRTZXR0ZXJBcml0eSk6bi5wYXJhbXNbMF1pbnN0YW5jZW9mIGEuUmVzdEVsZW1lbnQmJnRoaXMudG9sZXJhdGVFcnJvcihvLk1lc3NhZ2VzLkJhZFNldHRlclJlc3RQYXJhbWV0ZXIpO3ZhciByPXRoaXMucGFyc2VQcm9wZXJ0eU1ldGhvZChuKTtyZXR1cm4gdGhpcy5jb250ZXh0LmFsbG93WWllbGQ9dCx0aGlzLmZpbmFsaXplKGUsbmV3IGEuRnVuY3Rpb25FeHByZXNzaW9uKG51bGwsbi5wYXJhbXMsciwhMSkpfSxlLnByb3RvdHlwZS5wYXJzZUdlbmVyYXRvck1ldGhvZD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpLHQ9dGhpcy5jb250ZXh0LmFsbG93WWllbGQ7dGhpcy5jb250ZXh0LmFsbG93WWllbGQ9ITA7dmFyIG49dGhpcy5wYXJzZUZvcm1hbFBhcmFtZXRlcnMoKTt0aGlzLmNvbnRleHQuYWxsb3dZaWVsZD0hMTt2YXIgcj10aGlzLnBhcnNlUHJvcGVydHlNZXRob2Qobik7cmV0dXJuIHRoaXMuY29udGV4dC5hbGxvd1lpZWxkPXQsdGhpcy5maW5hbGl6ZShlLG5ldyBhLkZ1bmN0aW9uRXhwcmVzc2lvbihudWxsLG4ucGFyYW1zLHIsITApKX0sZS5wcm90b3R5cGUuaXNTdGFydE9mRXhwcmVzc2lvbj1mdW5jdGlvbigpe3ZhciBlPSEwLHQ9dGhpcy5sb29rYWhlYWQudmFsdWU7c3dpdGNoKHRoaXMubG9va2FoZWFkLnR5cGUpe2Nhc2UgNzplPSJbIj09PXR8fCIoIj09PXR8fCJ7Ij09PXR8fCIrIj09PXR8fCItIj09PXR8fCIhIj09PXR8fCJ+Ij09PXR8fCIrKyI9PT10fHwiLS0iPT09dHx8Ii8iPT09dHx8Ii89Ij09PXQ7YnJlYWs7Y2FzZSA0OmU9ImNsYXNzIj09PXR8fCJkZWxldGUiPT09dHx8ImZ1bmN0aW9uIj09PXR8fCJsZXQiPT09dHx8Im5ldyI9PT10fHwic3VwZXIiPT09dHx8InRoaXMiPT09dHx8InR5cGVvZiI9PT10fHwidm9pZCI9PT10fHwieWllbGQiPT09dH1yZXR1cm4gZX0sZS5wcm90b3R5cGUucGFyc2VZaWVsZEV4cHJlc3Npb249ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKTt0aGlzLmV4cGVjdEtleXdvcmQoInlpZWxkIik7dmFyIHQ9bnVsbCxuPSExO2lmKCF0aGlzLmhhc0xpbmVUZXJtaW5hdG9yKXt2YXIgcj10aGlzLmNvbnRleHQuYWxsb3dZaWVsZDt0aGlzLmNvbnRleHQuYWxsb3dZaWVsZD0hMSxuPXRoaXMubWF0Y2goIioiKSxuPyh0aGlzLm5leHRUb2tlbigpLHQ9dGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKCkpOnRoaXMuaXNTdGFydE9mRXhwcmVzc2lvbigpJiYodD10aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24oKSksdGhpcy5jb250ZXh0LmFsbG93WWllbGQ9cn1yZXR1cm4gdGhpcy5maW5hbGl6ZShlLG5ldyBhLllpZWxkRXhwcmVzc2lvbih0LG4pKX0sZS5wcm90b3R5cGUucGFyc2VDbGFzc0VsZW1lbnQ9ZnVuY3Rpb24oZSl7dmFyIHQ9dGhpcy5sb29rYWhlYWQsbj10aGlzLmNyZWF0ZU5vZGUoKSxyPSIiLGk9bnVsbCxzPW51bGwsdT0hMSxjPSExLGw9ITEscD0hMTtpZih0aGlzLm1hdGNoKCIqIikpdGhpcy5uZXh0VG9rZW4oKTtlbHNle3U9dGhpcy5tYXRjaCgiWyIpLGk9dGhpcy5wYXJzZU9iamVjdFByb3BlcnR5S2V5KCk7aWYoInN0YXRpYyI9PT1pLm5hbWUmJih0aGlzLnF1YWxpZmllZFByb3BlcnR5TmFtZSh0aGlzLmxvb2thaGVhZCl8fHRoaXMubWF0Y2goIioiKSkmJih0PXRoaXMubG9va2FoZWFkLGw9ITAsdT10aGlzLm1hdGNoKCJbIiksdGhpcy5tYXRjaCgiKiIpP3RoaXMubmV4dFRva2VuKCk6aT10aGlzLnBhcnNlT2JqZWN0UHJvcGVydHlLZXkoKSksMz09PXQudHlwZSYmIXRoaXMuaGFzTGluZVRlcm1pbmF0b3ImJiJhc3luYyI9PT10LnZhbHVlKXt2YXIgZj10aGlzLmxvb2thaGVhZC52YWx1ZTsiOiIhPT1mJiYiKCIhPT1mJiYiKiIhPT1mJiYocD0hMCx0PXRoaXMubG9va2FoZWFkLGk9dGhpcy5wYXJzZU9iamVjdFByb3BlcnR5S2V5KCksMz09PXQudHlwZSYmKCJnZXQiPT09dC52YWx1ZXx8InNldCI9PT10LnZhbHVlP3RoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4odCk6ImNvbnN0cnVjdG9yIj09PXQudmFsdWUmJnRoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4odCxvLk1lc3NhZ2VzLkNvbnN0cnVjdG9ySXNBc3luYykpKX19dmFyIGQ9dGhpcy5xdWFsaWZpZWRQcm9wZXJ0eU5hbWUodGhpcy5sb29rYWhlYWQpO3JldHVybiAzPT09dC50eXBlPyJnZXQiPT09dC52YWx1ZSYmZD8ocj0iZ2V0Iix1PXRoaXMubWF0Y2goIlsiKSxpPXRoaXMucGFyc2VPYmplY3RQcm9wZXJ0eUtleSgpLHRoaXMuY29udGV4dC5hbGxvd1lpZWxkPSExLHM9dGhpcy5wYXJzZUdldHRlck1ldGhvZCgpKToic2V0Ij09PXQudmFsdWUmJmQmJihyPSJzZXQiLHU9dGhpcy5tYXRjaCgiWyIpLGk9dGhpcy5wYXJzZU9iamVjdFByb3BlcnR5S2V5KCkscz10aGlzLnBhcnNlU2V0dGVyTWV0aG9kKCkpOjc9PT10LnR5cGUmJiIqIj09PXQudmFsdWUmJmQmJihyPSJpbml0Iix1PXRoaXMubWF0Y2goIlsiKSxpPXRoaXMucGFyc2VPYmplY3RQcm9wZXJ0eUtleSgpLHM9dGhpcy5wYXJzZUdlbmVyYXRvck1ldGhvZCgpLGM9ITApLCFyJiZpJiZ0aGlzLm1hdGNoKCIoIikmJihyPSJpbml0IixzPXA/dGhpcy5wYXJzZVByb3BlcnR5TWV0aG9kQXN5bmNGdW5jdGlvbigpOnRoaXMucGFyc2VQcm9wZXJ0eU1ldGhvZEZ1bmN0aW9uKCksYz0hMCkscnx8dGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0aGlzLmxvb2thaGVhZCksImluaXQiPT09ciYmKHI9Im1ldGhvZCIpLHV8fChsJiZ0aGlzLmlzUHJvcGVydHlLZXkoaSwicHJvdG90eXBlIikmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odCxvLk1lc3NhZ2VzLlN0YXRpY1Byb3RvdHlwZSksIWwmJnRoaXMuaXNQcm9wZXJ0eUtleShpLCJjb25zdHJ1Y3RvciIpJiYoKCJtZXRob2QiIT09cnx8IWN8fHMmJnMuZ2VuZXJhdG9yKSYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0LG8uTWVzc2FnZXMuQ29uc3RydWN0b3JTcGVjaWFsTWV0aG9kKSxlLnZhbHVlP3RoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odCxvLk1lc3NhZ2VzLkR1cGxpY2F0ZUNvbnN0cnVjdG9yKTplLnZhbHVlPSEwLHI9ImNvbnN0cnVjdG9yIikpLHRoaXMuZmluYWxpemUobixuZXcgYS5NZXRob2REZWZpbml0aW9uKGksdSxzLHIsbCkpfSxlLnByb3RvdHlwZS5wYXJzZUNsYXNzRWxlbWVudExpc3Q9ZnVuY3Rpb24oKXt2YXIgZT1bXSx0PXt2YWx1ZTohMX07Zm9yKHRoaXMuZXhwZWN0KCJ7Iik7IXRoaXMubWF0Y2goIn0iKTspdGhpcy5tYXRjaCgiOyIpP3RoaXMubmV4dFRva2VuKCk6ZS5wdXNoKHRoaXMucGFyc2VDbGFzc0VsZW1lbnQodCkpO3JldHVybiB0aGlzLmV4cGVjdCgifSIpLGV9LGUucHJvdG90eXBlLnBhcnNlQ2xhc3NCb2R5PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCksdD10aGlzLnBhcnNlQ2xhc3NFbGVtZW50TGlzdCgpO3JldHVybiB0aGlzLmZpbmFsaXplKGUsbmV3IGEuQ2xhc3NCb2R5KHQpKX0sZS5wcm90b3R5cGUucGFyc2VDbGFzc0RlY2xhcmF0aW9uPWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuY3JlYXRlTm9kZSgpLG49dGhpcy5jb250ZXh0LnN0cmljdDt0aGlzLmNvbnRleHQuc3RyaWN0PSEwLHRoaXMuZXhwZWN0S2V5d29yZCgiY2xhc3MiKTt2YXIgcj1lJiYzIT09dGhpcy5sb29rYWhlYWQudHlwZT9udWxsOnRoaXMucGFyc2VWYXJpYWJsZUlkZW50aWZpZXIoKSxpPW51bGw7dGhpcy5tYXRjaEtleXdvcmQoImV4dGVuZHMiKSYmKHRoaXMubmV4dFRva2VuKCksaT10aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUxlZnRIYW5kU2lkZUV4cHJlc3Npb25BbGxvd0NhbGwpKTt2YXIgbz10aGlzLnBhcnNlQ2xhc3NCb2R5KCk7cmV0dXJuIHRoaXMuY29udGV4dC5zdHJpY3Q9bix0aGlzLmZpbmFsaXplKHQsbmV3IGEuQ2xhc3NEZWNsYXJhdGlvbihyLGksbykpfSxlLnByb3RvdHlwZS5wYXJzZUNsYXNzRXhwcmVzc2lvbj1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpLHQ9dGhpcy5jb250ZXh0LnN0cmljdDt0aGlzLmNvbnRleHQuc3RyaWN0PSEwLHRoaXMuZXhwZWN0S2V5d29yZCgiY2xhc3MiKTt2YXIgbj0zPT09dGhpcy5sb29rYWhlYWQudHlwZT90aGlzLnBhcnNlVmFyaWFibGVJZGVudGlmaWVyKCk6bnVsbCxyPW51bGw7dGhpcy5tYXRjaEtleXdvcmQoImV4dGVuZHMiKSYmKHRoaXMubmV4dFRva2VuKCkscj10aGlzLmlzb2xhdGVDb3ZlckdyYW1tYXIodGhpcy5wYXJzZUxlZnRIYW5kU2lkZUV4cHJlc3Npb25BbGxvd0NhbGwpKTt2YXIgaT10aGlzLnBhcnNlQ2xhc3NCb2R5KCk7cmV0dXJuIHRoaXMuY29udGV4dC5zdHJpY3Q9dCx0aGlzLmZpbmFsaXplKGUsbmV3IGEuQ2xhc3NFeHByZXNzaW9uKG4scixpKSl9LGUucHJvdG90eXBlLnBhcnNlTW9kdWxlPWZ1bmN0aW9uKCl7dGhpcy5jb250ZXh0LnN0cmljdD0hMCx0aGlzLmNvbnRleHQuaXNNb2R1bGU9ITA7Zm9yKHZhciBlPXRoaXMuY3JlYXRlTm9kZSgpLHQ9dGhpcy5wYXJzZURpcmVjdGl2ZVByb2xvZ3VlcygpOzIhPT10aGlzLmxvb2thaGVhZC50eXBlOyl0LnB1c2godGhpcy5wYXJzZVN0YXRlbWVudExpc3RJdGVtKCkpO3JldHVybiB0aGlzLmZpbmFsaXplKGUsbmV3IGEuTW9kdWxlKHQpKX0sZS5wcm90b3R5cGUucGFyc2VTY3JpcHQ9ZnVuY3Rpb24oKXtmb3IodmFyIGU9dGhpcy5jcmVhdGVOb2RlKCksdD10aGlzLnBhcnNlRGlyZWN0aXZlUHJvbG9ndWVzKCk7MiE9PXRoaXMubG9va2FoZWFkLnR5cGU7KXQucHVzaCh0aGlzLnBhcnNlU3RhdGVtZW50TGlzdEl0ZW0oKSk7cmV0dXJuIHRoaXMuZmluYWxpemUoZSxuZXcgYS5TY3JpcHQodCkpfSxlLnByb3RvdHlwZS5wYXJzZU1vZHVsZVNwZWNpZmllcj1mdW5jdGlvbigpe3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpOzghPT10aGlzLmxvb2thaGVhZC50eXBlJiZ0aGlzLnRocm93RXJyb3Ioby5NZXNzYWdlcy5JbnZhbGlkTW9kdWxlU3BlY2lmaWVyKTt2YXIgdD10aGlzLm5leHRUb2tlbigpLG49dGhpcy5nZXRUb2tlblJhdyh0KTtyZXR1cm4gdGhpcy5maW5hbGl6ZShlLG5ldyBhLkxpdGVyYWwodC52YWx1ZSxuKSl9LGUucHJvdG90eXBlLnBhcnNlSW1wb3J0U3BlY2lmaWVyPWZ1bmN0aW9uKCl7dmFyIGUsdCxuPXRoaXMuY3JlYXRlTm9kZSgpO3JldHVybiAzPT09dGhpcy5sb29rYWhlYWQudHlwZT8oZT10aGlzLnBhcnNlVmFyaWFibGVJZGVudGlmaWVyKCksdD1lLHRoaXMubWF0Y2hDb250ZXh0dWFsS2V5d29yZCgiYXMiKSYmKHRoaXMubmV4dFRva2VuKCksdD10aGlzLnBhcnNlVmFyaWFibGVJZGVudGlmaWVyKCkpKTooZT10aGlzLnBhcnNlSWRlbnRpZmllck5hbWUoKSx0PWUsdGhpcy5tYXRjaENvbnRleHR1YWxLZXl3b3JkKCJhcyIpPyh0aGlzLm5leHRUb2tlbigpLHQ9dGhpcy5wYXJzZVZhcmlhYmxlSWRlbnRpZmllcigpKTp0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHRoaXMubmV4dFRva2VuKCkpKSx0aGlzLmZpbmFsaXplKG4sbmV3IGEuSW1wb3J0U3BlY2lmaWVyKHQsZSkpfSxlLnByb3RvdHlwZS5wYXJzZU5hbWVkSW1wb3J0cz1mdW5jdGlvbigpe3RoaXMuZXhwZWN0KCJ7Iik7Zm9yKHZhciBlPVtdOyF0aGlzLm1hdGNoKCJ9Iik7KWUucHVzaCh0aGlzLnBhcnNlSW1wb3J0U3BlY2lmaWVyKCkpLHRoaXMubWF0Y2goIn0iKXx8dGhpcy5leHBlY3QoIiwiKTtyZXR1cm4gdGhpcy5leHBlY3QoIn0iKSxlfSxlLnByb3RvdHlwZS5wYXJzZUltcG9ydERlZmF1bHRTcGVjaWZpZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKSx0PXRoaXMucGFyc2VJZGVudGlmaWVyTmFtZSgpO3JldHVybiB0aGlzLmZpbmFsaXplKGUsbmV3IGEuSW1wb3J0RGVmYXVsdFNwZWNpZmllcih0KSl9LGUucHJvdG90eXBlLnBhcnNlSW1wb3J0TmFtZXNwYWNlU3BlY2lmaWVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCk7dGhpcy5leHBlY3QoIioiKSx0aGlzLm1hdGNoQ29udGV4dHVhbEtleXdvcmQoImFzIil8fHRoaXMudGhyb3dFcnJvcihvLk1lc3NhZ2VzLk5vQXNBZnRlckltcG9ydE5hbWVzcGFjZSksdGhpcy5uZXh0VG9rZW4oKTt2YXIgdD10aGlzLnBhcnNlSWRlbnRpZmllck5hbWUoKTtyZXR1cm4gdGhpcy5maW5hbGl6ZShlLG5ldyBhLkltcG9ydE5hbWVzcGFjZVNwZWNpZmllcih0KSl9LGUucHJvdG90eXBlLnBhcnNlSW1wb3J0RGVjbGFyYXRpb249ZnVuY3Rpb24oKXt0aGlzLmNvbnRleHQuaW5GdW5jdGlvbkJvZHkmJnRoaXMudGhyb3dFcnJvcihvLk1lc3NhZ2VzLklsbGVnYWxJbXBvcnREZWNsYXJhdGlvbik7dmFyIGU9dGhpcy5jcmVhdGVOb2RlKCk7dGhpcy5leHBlY3RLZXl3b3JkKCJpbXBvcnQiKTt2YXIgdCxuPVtdO2lmKDg9PT10aGlzLmxvb2thaGVhZC50eXBlKXQ9dGhpcy5wYXJzZU1vZHVsZVNwZWNpZmllcigpO2Vsc2V7aWYodGhpcy5tYXRjaCgieyIpP249bi5jb25jYXQodGhpcy5wYXJzZU5hbWVkSW1wb3J0cygpKTp0aGlzLm1hdGNoKCIqIik/bi5wdXNoKHRoaXMucGFyc2VJbXBvcnROYW1lc3BhY2VTcGVjaWZpZXIoKSk6dGhpcy5pc0lkZW50aWZpZXJOYW1lKHRoaXMubG9va2FoZWFkKSYmIXRoaXMubWF0Y2hLZXl3b3JkKCJkZWZhdWx0Iik/KG4ucHVzaCh0aGlzLnBhcnNlSW1wb3J0RGVmYXVsdFNwZWNpZmllcigpKSx0aGlzLm1hdGNoKCIsIikmJih0aGlzLm5leHRUb2tlbigpLHRoaXMubWF0Y2goIioiKT9uLnB1c2godGhpcy5wYXJzZUltcG9ydE5hbWVzcGFjZVNwZWNpZmllcigpKTp0aGlzLm1hdGNoKCJ7Iik/bj1uLmNvbmNhdCh0aGlzLnBhcnNlTmFtZWRJbXBvcnRzKCkpOnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4odGhpcy5sb29rYWhlYWQpKSk6dGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbih0aGlzLm5leHRUb2tlbigpKSwhdGhpcy5tYXRjaENvbnRleHR1YWxLZXl3b3JkKCJmcm9tIikpe3ZhciByPXRoaXMubG9va2FoZWFkLnZhbHVlP28uTWVzc2FnZXMuVW5leHBlY3RlZFRva2VuOm8uTWVzc2FnZXMuTWlzc2luZ0Zyb21DbGF1c2U7dGhpcy50aHJvd0Vycm9yKHIsdGhpcy5sb29rYWhlYWQudmFsdWUpfXRoaXMubmV4dFRva2VuKCksdD10aGlzLnBhcnNlTW9kdWxlU3BlY2lmaWVyKCl9cmV0dXJuIHRoaXMuY29uc3VtZVNlbWljb2xvbigpLHRoaXMuZmluYWxpemUoZSxuZXcgYS5JbXBvcnREZWNsYXJhdGlvbihuLHQpKX0sZS5wcm90b3R5cGUucGFyc2VFeHBvcnRTcGVjaWZpZXI9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmNyZWF0ZU5vZGUoKSx0PXRoaXMucGFyc2VJZGVudGlmaWVyTmFtZSgpLG49dDtyZXR1cm4gdGhpcy5tYXRjaENvbnRleHR1YWxLZXl3b3JkKCJhcyIpJiYodGhpcy5uZXh0VG9rZW4oKSxuPXRoaXMucGFyc2VJZGVudGlmaWVyTmFtZSgpKSx0aGlzLmZpbmFsaXplKGUsbmV3IGEuRXhwb3J0U3BlY2lmaWVyKHQsbikpfSxlLnByb3RvdHlwZS5wYXJzZUV4cG9ydERlY2xhcmF0aW9uPWZ1bmN0aW9uKCl7dGhpcy5jb250ZXh0LmluRnVuY3Rpb25Cb2R5JiZ0aGlzLnRocm93RXJyb3Ioby5NZXNzYWdlcy5JbGxlZ2FsRXhwb3J0RGVjbGFyYXRpb24pO3ZhciBlPXRoaXMuY3JlYXRlTm9kZSgpO3RoaXMuZXhwZWN0S2V5d29yZCgiZXhwb3J0Iik7dmFyIHQ7aWYodGhpcy5tYXRjaEtleXdvcmQoImRlZmF1bHQiKSlpZih0aGlzLm5leHRUb2tlbigpLHRoaXMubWF0Y2hLZXl3b3JkKCJmdW5jdGlvbiIpKXt2YXIgbj10aGlzLnBhcnNlRnVuY3Rpb25EZWNsYXJhdGlvbighMCk7dD10aGlzLmZpbmFsaXplKGUsbmV3IGEuRXhwb3J0RGVmYXVsdERlY2xhcmF0aW9uKG4pKX1lbHNlIGlmKHRoaXMubWF0Y2hLZXl3b3JkKCJjbGFzcyIpKXt2YXIgbj10aGlzLnBhcnNlQ2xhc3NEZWNsYXJhdGlvbighMCk7dD10aGlzLmZpbmFsaXplKGUsbmV3IGEuRXhwb3J0RGVmYXVsdERlY2xhcmF0aW9uKG4pKX1lbHNlIGlmKHRoaXMubWF0Y2hDb250ZXh0dWFsS2V5d29yZCgiYXN5bmMiKSl7dmFyIG49dGhpcy5tYXRjaEFzeW5jRnVuY3Rpb24oKT90aGlzLnBhcnNlRnVuY3Rpb25EZWNsYXJhdGlvbighMCk6dGhpcy5wYXJzZUFzc2lnbm1lbnRFeHByZXNzaW9uKCk7dD10aGlzLmZpbmFsaXplKGUsbmV3IGEuRXhwb3J0RGVmYXVsdERlY2xhcmF0aW9uKG4pKX1lbHNle3RoaXMubWF0Y2hDb250ZXh0dWFsS2V5d29yZCgiZnJvbSIpJiZ0aGlzLnRocm93RXJyb3Ioby5NZXNzYWdlcy5VbmV4cGVjdGVkVG9rZW4sdGhpcy5sb29rYWhlYWQudmFsdWUpO3ZhciBuPXRoaXMubWF0Y2goInsiKT90aGlzLnBhcnNlT2JqZWN0SW5pdGlhbGl6ZXIoKTp0aGlzLm1hdGNoKCJbIik/dGhpcy5wYXJzZUFycmF5SW5pdGlhbGl6ZXIoKTp0aGlzLnBhcnNlQXNzaWdubWVudEV4cHJlc3Npb24oKTt0aGlzLmNvbnN1bWVTZW1pY29sb24oKSx0PXRoaXMuZmluYWxpemUoZSxuZXcgYS5FeHBvcnREZWZhdWx0RGVjbGFyYXRpb24obikpfWVsc2UgaWYodGhpcy5tYXRjaCgiKiIpKXtpZih0aGlzLm5leHRUb2tlbigpLCF0aGlzLm1hdGNoQ29udGV4dHVhbEtleXdvcmQoImZyb20iKSl7dmFyIHI9dGhpcy5sb29rYWhlYWQudmFsdWU/by5NZXNzYWdlcy5VbmV4cGVjdGVkVG9rZW46by5NZXNzYWdlcy5NaXNzaW5nRnJvbUNsYXVzZTt0aGlzLnRocm93RXJyb3Iocix0aGlzLmxvb2thaGVhZC52YWx1ZSl9dGhpcy5uZXh0VG9rZW4oKTt2YXIgaT10aGlzLnBhcnNlTW9kdWxlU3BlY2lmaWVyKCk7dGhpcy5jb25zdW1lU2VtaWNvbG9uKCksdD10aGlzLmZpbmFsaXplKGUsbmV3IGEuRXhwb3J0QWxsRGVjbGFyYXRpb24oaSkpfWVsc2UgaWYoND09PXRoaXMubG9va2FoZWFkLnR5cGUpe3ZhciBuPXZvaWQgMDtzd2l0Y2godGhpcy5sb29rYWhlYWQudmFsdWUpe2Nhc2UibGV0IjpjYXNlImNvbnN0IjpuPXRoaXMucGFyc2VMZXhpY2FsRGVjbGFyYXRpb24oe2luRm9yOiExfSk7YnJlYWs7Y2FzZSJ2YXIiOmNhc2UiY2xhc3MiOmNhc2UiZnVuY3Rpb24iOm49dGhpcy5wYXJzZVN0YXRlbWVudExpc3RJdGVtKCk7YnJlYWs7ZGVmYXVsdDp0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHRoaXMubG9va2FoZWFkKX10PXRoaXMuZmluYWxpemUoZSxuZXcgYS5FeHBvcnROYW1lZERlY2xhcmF0aW9uKG4sW10sbnVsbCkpfWVsc2UgaWYodGhpcy5tYXRjaEFzeW5jRnVuY3Rpb24oKSl7dmFyIG49dGhpcy5wYXJzZUZ1bmN0aW9uRGVjbGFyYXRpb24oKTt0PXRoaXMuZmluYWxpemUoZSxuZXcgYS5FeHBvcnROYW1lZERlY2xhcmF0aW9uKG4sW10sbnVsbCkpfWVsc2V7dmFyIHM9W10sdT1udWxsLGM9ITE7Zm9yKHRoaXMuZXhwZWN0KCJ7Iik7IXRoaXMubWF0Y2goIn0iKTspYz1jfHx0aGlzLm1hdGNoS2V5d29yZCgiZGVmYXVsdCIpLHMucHVzaCh0aGlzLnBhcnNlRXhwb3J0U3BlY2lmaWVyKCkpLHRoaXMubWF0Y2goIn0iKXx8dGhpcy5leHBlY3QoIiwiKTtpZih0aGlzLmV4cGVjdCgifSIpLHRoaXMubWF0Y2hDb250ZXh0dWFsS2V5d29yZCgiZnJvbSIpKXRoaXMubmV4dFRva2VuKCksdT10aGlzLnBhcnNlTW9kdWxlU3BlY2lmaWVyKCksdGhpcy5jb25zdW1lU2VtaWNvbG9uKCk7ZWxzZSBpZihjKXt2YXIgcj10aGlzLmxvb2thaGVhZC52YWx1ZT9vLk1lc3NhZ2VzLlVuZXhwZWN0ZWRUb2tlbjpvLk1lc3NhZ2VzLk1pc3NpbmdGcm9tQ2xhdXNlO3RoaXMudGhyb3dFcnJvcihyLHRoaXMubG9va2FoZWFkLnZhbHVlKX1lbHNlIHRoaXMuY29uc3VtZVNlbWljb2xvbigpO3Q9dGhpcy5maW5hbGl6ZShlLG5ldyBhLkV4cG9ydE5hbWVkRGVjbGFyYXRpb24obnVsbCxzLHUpKX1yZXR1cm4gdH0sZX0oKTt0LlBhcnNlcj1sfSxmdW5jdGlvbihlLHQpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBuKGUsdCl7aWYoIWUpdGhyb3cgbmV3IEVycm9yKCJBU1NFUlQ6ICIrdCl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuYXNzZXJ0PW59LGZ1bmN0aW9uKGUsdCl7InVzZSBzdHJpY3QiO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoKXt0aGlzLmVycm9ycz1bXSx0aGlzLnRvbGVyYW50PSExfXJldHVybiBlLnByb3RvdHlwZS5yZWNvcmRFcnJvcj1mdW5jdGlvbihlKXt0aGlzLmVycm9ycy5wdXNoKGUpfSxlLnByb3RvdHlwZS50b2xlcmF0ZT1mdW5jdGlvbihlKXtpZighdGhpcy50b2xlcmFudCl0aHJvdyBlO3RoaXMucmVjb3JkRXJyb3IoZSl9LGUucHJvdG90eXBlLmNvbnN0cnVjdEVycm9yPWZ1bmN0aW9uKGUsdCl7dmFyIG49bmV3IEVycm9yKGUpO3RyeXt0aHJvdyBufWNhdGNoKGUpe09iamVjdC5jcmVhdGUmJk9iamVjdC5kZWZpbmVQcm9wZXJ0eSYmKG49T2JqZWN0LmNyZWF0ZShlKSxPYmplY3QuZGVmaW5lUHJvcGVydHkobiwiY29sdW1uIix7dmFsdWU6dH0pKX1yZXR1cm4gbn0sZS5wcm90b3R5cGUuY3JlYXRlRXJyb3I9ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9IkxpbmUgIit0KyI6ICIrcixvPXRoaXMuY29uc3RydWN0RXJyb3IoaSxuKTtyZXR1cm4gby5pbmRleD1lLG8ubGluZU51bWJlcj10LG8uZGVzY3JpcHRpb249cixvfSxlLnByb3RvdHlwZS50aHJvd0Vycm9yPWZ1bmN0aW9uKGUsdCxuLHIpe3Rocm93IHRoaXMuY3JlYXRlRXJyb3IoZSx0LG4scil9LGUucHJvdG90eXBlLnRvbGVyYXRlRXJyb3I9ZnVuY3Rpb24oZSx0LG4scil7dmFyIGk9dGhpcy5jcmVhdGVFcnJvcihlLHQsbixyKTtpZighdGhpcy50b2xlcmFudCl0aHJvdyBpO3RoaXMucmVjb3JkRXJyb3IoaSl9LGV9KCk7dC5FcnJvckhhbmRsZXI9bn0sZnVuY3Rpb24oZSx0KXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pLHQuTWVzc2FnZXM9e0JhZEdldHRlckFyaXR5OiJHZXR0ZXIgbXVzdCBub3QgaGF2ZSBhbnkgZm9ybWFsIHBhcmFtZXRlcnMiLEJhZFNldHRlckFyaXR5OiJTZXR0ZXIgbXVzdCBoYXZlIGV4YWN0bHkgb25lIGZvcm1hbCBwYXJhbWV0ZXIiLEJhZFNldHRlclJlc3RQYXJhbWV0ZXI6IlNldHRlciBmdW5jdGlvbiBhcmd1bWVudCBtdXN0IG5vdCBiZSBhIHJlc3QgcGFyYW1ldGVyIixDb25zdHJ1Y3RvcklzQXN5bmM6IkNsYXNzIGNvbnN0cnVjdG9yIG1heSBub3QgYmUgYW4gYXN5bmMgbWV0aG9kIixDb25zdHJ1Y3RvclNwZWNpYWxNZXRob2Q6IkNsYXNzIGNvbnN0cnVjdG9yIG1heSBub3QgYmUgYW4gYWNjZXNzb3IiLERlY2xhcmF0aW9uTWlzc2luZ0luaXRpYWxpemVyOiJNaXNzaW5nIGluaXRpYWxpemVyIGluICUwIGRlY2xhcmF0aW9uIixEZWZhdWx0UmVzdFBhcmFtZXRlcjoiVW5leHBlY3RlZCB0b2tlbiA9IixEdXBsaWNhdGVCaW5kaW5nOiJEdXBsaWNhdGUgYmluZGluZyAlMCIsRHVwbGljYXRlQ29uc3RydWN0b3I6IkEgY2xhc3MgbWF5IG9ubHkgaGF2ZSBvbmUgY29uc3RydWN0b3IiLER1cGxpY2F0ZVByb3RvUHJvcGVydHk6IkR1cGxpY2F0ZSBfX3Byb3RvX18gZmllbGRzIGFyZSBub3QgYWxsb3dlZCBpbiBvYmplY3QgbGl0ZXJhbHMiLEZvckluT2ZMb29wSW5pdGlhbGl6ZXI6IiUwIGxvb3AgdmFyaWFibGUgZGVjbGFyYXRpb24gbWF5IG5vdCBoYXZlIGFuIGluaXRpYWxpemVyIixHZW5lcmF0b3JJbkxlZ2FjeUNvbnRleHQ6IkdlbmVyYXRvciBkZWNsYXJhdGlvbnMgYXJlIG5vdCBhbGxvd2VkIGluIGxlZ2FjeSBjb250ZXh0cyIsSWxsZWdhbEJyZWFrOiJJbGxlZ2FsIGJyZWFrIHN0YXRlbWVudCIsSWxsZWdhbENvbnRpbnVlOiJJbGxlZ2FsIGNvbnRpbnVlIHN0YXRlbWVudCIsSWxsZWdhbEV4cG9ydERlY2xhcmF0aW9uOiJVbmV4cGVjdGVkIHRva2VuIixJbGxlZ2FsSW1wb3J0RGVjbGFyYXRpb246IlVuZXhwZWN0ZWQgdG9rZW4iLElsbGVnYWxMYW5ndWFnZU1vZGVEaXJlY3RpdmU6IklsbGVnYWwgJ3VzZSBzdHJpY3QnIGRpcmVjdGl2ZSBpbiBmdW5jdGlvbiB3aXRoIG5vbi1zaW1wbGUgcGFyYW1ldGVyIGxpc3QiLElsbGVnYWxSZXR1cm46IklsbGVnYWwgcmV0dXJuIHN0YXRlbWVudCIsSW52YWxpZEVzY2FwZWRSZXNlcnZlZFdvcmQ6IktleXdvcmQgbXVzdCBub3QgY29udGFpbiBlc2NhcGVkIGNoYXJhY3RlcnMiLEludmFsaWRIZXhFc2NhcGVTZXF1ZW5jZToiSW52YWxpZCBoZXhhZGVjaW1hbCBlc2NhcGUgc2VxdWVuY2UiLEludmFsaWRMSFNJbkFzc2lnbm1lbnQ6IkludmFsaWQgbGVmdC1oYW5kIHNpZGUgaW4gYXNzaWdubWVudCIsSW52YWxpZExIU0luRm9ySW46IkludmFsaWQgbGVmdC1oYW5kIHNpZGUgaW4gZm9yLWluIixJbnZhbGlkTEhTSW5Gb3JMb29wOiJJbnZhbGlkIGxlZnQtaGFuZCBzaWRlIGluIGZvci1sb29wIixJbnZhbGlkTW9kdWxlU3BlY2lmaWVyOiJVbmV4cGVjdGVkIHRva2VuIixJbnZhbGlkUmVnRXhwOiJJbnZhbGlkIHJlZ3VsYXIgZXhwcmVzc2lvbiIsTGV0SW5MZXhpY2FsQmluZGluZzoibGV0IGlzIGRpc2FsbG93ZWQgYXMgYSBsZXhpY2FsbHkgYm91bmQgbmFtZSIsTWlzc2luZ0Zyb21DbGF1c2U6IlVuZXhwZWN0ZWQgdG9rZW4iLE11bHRpcGxlRGVmYXVsdHNJblN3aXRjaDoiTW9yZSB0aGFuIG9uZSBkZWZhdWx0IGNsYXVzZSBpbiBzd2l0Y2ggc3RhdGVtZW50IixOZXdsaW5lQWZ0ZXJUaHJvdzoiSWxsZWdhbCBuZXdsaW5lIGFmdGVyIHRocm93IixOb0FzQWZ0ZXJJbXBvcnROYW1lc3BhY2U6IlVuZXhwZWN0ZWQgdG9rZW4iLE5vQ2F0Y2hPckZpbmFsbHk6Ik1pc3NpbmcgY2F0Y2ggb3IgZmluYWxseSBhZnRlciB0cnkiLFBhcmFtZXRlckFmdGVyUmVzdFBhcmFtZXRlcjoiUmVzdCBwYXJhbWV0ZXIgbXVzdCBiZSBsYXN0IGZvcm1hbCBwYXJhbWV0ZXIiLFJlZGVjbGFyYXRpb246IiUwICclMScgaGFzIGFscmVhZHkgYmVlbiBkZWNsYXJlZCIsU3RhdGljUHJvdG90eXBlOiJDbGFzc2VzIG1heSBub3QgaGF2ZSBzdGF0aWMgcHJvcGVydHkgbmFtZWQgcHJvdG90eXBlIixTdHJpY3RDYXRjaFZhcmlhYmxlOiJDYXRjaCB2YXJpYWJsZSBtYXkgbm90IGJlIGV2YWwgb3IgYXJndW1lbnRzIGluIHN0cmljdCBtb2RlIixTdHJpY3REZWxldGU6IkRlbGV0ZSBvZiBhbiB1bnF1YWxpZmllZCBpZGVudGlmaWVyIGluIHN0cmljdCBtb2RlLiIsU3RyaWN0RnVuY3Rpb246IkluIHN0cmljdCBtb2RlIGNvZGUsIGZ1bmN0aW9ucyBjYW4gb25seSBiZSBkZWNsYXJlZCBhdCB0b3AgbGV2ZWwgb3IgaW5zaWRlIGEgYmxvY2siLFN0cmljdEZ1bmN0aW9uTmFtZToiRnVuY3Rpb24gbmFtZSBtYXkgbm90IGJlIGV2YWwgb3IgYXJndW1lbnRzIGluIHN0cmljdCBtb2RlIixTdHJpY3RMSFNBc3NpZ25tZW50OiJBc3NpZ25tZW50IHRvIGV2YWwgb3IgYXJndW1lbnRzIGlzIG5vdCBhbGxvd2VkIGluIHN0cmljdCBtb2RlIixTdHJpY3RMSFNQb3N0Zml4OiJQb3N0Zml4IGluY3JlbWVudC9kZWNyZW1lbnQgbWF5IG5vdCBoYXZlIGV2YWwgb3IgYXJndW1lbnRzIG9wZXJhbmQgaW4gc3RyaWN0IG1vZGUiLFN0cmljdExIU1ByZWZpeDoiUHJlZml4IGluY3JlbWVudC9kZWNyZW1lbnQgbWF5IG5vdCBoYXZlIGV2YWwgb3IgYXJndW1lbnRzIG9wZXJhbmQgaW4gc3RyaWN0IG1vZGUiLFN0cmljdE1vZGVXaXRoOiJTdHJpY3QgbW9kZSBjb2RlIG1heSBub3QgaW5jbHVkZSBhIHdpdGggc3RhdGVtZW50IixTdHJpY3RPY3RhbExpdGVyYWw6Ik9jdGFsIGxpdGVyYWxzIGFyZSBub3QgYWxsb3dlZCBpbiBzdHJpY3QgbW9kZS4iLFN0cmljdFBhcmFtRHVwZToiU3RyaWN0IG1vZGUgZnVuY3Rpb24gbWF5IG5vdCBoYXZlIGR1cGxpY2F0ZSBwYXJhbWV0ZXIgbmFtZXMiLFN0cmljdFBhcmFtTmFtZToiUGFyYW1ldGVyIG5hbWUgZXZhbCBvciBhcmd1bWVudHMgaXMgbm90IGFsbG93ZWQgaW4gc3RyaWN0IG1vZGUiLFN0cmljdFJlc2VydmVkV29yZDoiVXNlIG9mIGZ1dHVyZSByZXNlcnZlZCB3b3JkIGluIHN0cmljdCBtb2RlIixTdHJpY3RWYXJOYW1lOiJWYXJpYWJsZSBuYW1lIG1heSBub3QgYmUgZXZhbCBvciBhcmd1bWVudHMgaW4gc3RyaWN0IG1vZGUiLFRlbXBsYXRlT2N0YWxMaXRlcmFsOiJPY3RhbCBsaXRlcmFscyBhcmUgbm90IGFsbG93ZWQgaW4gdGVtcGxhdGUgc3RyaW5ncy4iLFVuZXhwZWN0ZWRFT1M6IlVuZXhwZWN0ZWQgZW5kIG9mIGlucHV0IixVbmV4cGVjdGVkSWRlbnRpZmllcjoiVW5leHBlY3RlZCBpZGVudGlmaWVyIixVbmV4cGVjdGVkTnVtYmVyOiJVbmV4cGVjdGVkIG51bWJlciIsVW5leHBlY3RlZFJlc2VydmVkOiJVbmV4cGVjdGVkIHJlc2VydmVkIHdvcmQiLFVuZXhwZWN0ZWRTdHJpbmc6IlVuZXhwZWN0ZWQgc3RyaW5nIixVbmV4cGVjdGVkVGVtcGxhdGU6IlVuZXhwZWN0ZWQgcXVhc2kgJTAiLFVuZXhwZWN0ZWRUb2tlbjoiVW5leHBlY3RlZCB0b2tlbiAlMCIsVW5leHBlY3RlZFRva2VuSWxsZWdhbDoiVW5leHBlY3RlZCB0b2tlbiBJTExFR0FMIixVbmtub3duTGFiZWw6IlVuZGVmaW5lZCBsYWJlbCAnJTAnIixVbnRlcm1pbmF0ZWRSZWdFeHA6IkludmFsaWQgcmVndWxhciBleHByZXNzaW9uOiBtaXNzaW5nIC8ifX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiByKGUpe3JldHVybiIwMTIzNDU2Nzg5YWJjZGVmIi5pbmRleE9mKGUudG9Mb3dlckNhc2UoKSl9ZnVuY3Rpb24gaShlKXtyZXR1cm4iMDEyMzQ1NjciLmluZGV4T2YoZSl9T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciBvPW4oOSksYT1uKDQpLHM9bigxMSksdT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUoZSx0KXt0aGlzLnNvdXJjZT1lLHRoaXMuZXJyb3JIYW5kbGVyPXQsdGhpcy50cmFja0NvbW1lbnQ9ITEsdGhpcy5sZW5ndGg9ZS5sZW5ndGgsdGhpcy5pbmRleD0wLHRoaXMubGluZU51bWJlcj1lLmxlbmd0aD4wPzE6MCx0aGlzLmxpbmVTdGFydD0wLHRoaXMuY3VybHlTdGFjaz1bXX1yZXR1cm4gZS5wcm90b3R5cGUuc2F2ZVN0YXRlPWZ1bmN0aW9uKCl7cmV0dXJue2luZGV4OnRoaXMuaW5kZXgsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsbGluZVN0YXJ0OnRoaXMubGluZVN0YXJ0fX0sZS5wcm90b3R5cGUucmVzdG9yZVN0YXRlPWZ1bmN0aW9uKGUpe3RoaXMuaW5kZXg9ZS5pbmRleCx0aGlzLmxpbmVOdW1iZXI9ZS5saW5lTnVtYmVyLHRoaXMubGluZVN0YXJ0PWUubGluZVN0YXJ0fSxlLnByb3RvdHlwZS5lb2Y9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5pbmRleD49dGhpcy5sZW5ndGh9LGUucHJvdG90eXBlLnRocm93VW5leHBlY3RlZFRva2VuPWZ1bmN0aW9uKGUpe3JldHVybiB2b2lkIDA9PT1lJiYoZT1zLk1lc3NhZ2VzLlVuZXhwZWN0ZWRUb2tlbklsbGVnYWwpLHRoaXMuZXJyb3JIYW5kbGVyLnRocm93RXJyb3IodGhpcy5pbmRleCx0aGlzLmxpbmVOdW1iZXIsdGhpcy5pbmRleC10aGlzLmxpbmVTdGFydCsxLGUpfSxlLnByb3RvdHlwZS50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbj1mdW5jdGlvbihlKXt2b2lkIDA9PT1lJiYoZT1zLk1lc3NhZ2VzLlVuZXhwZWN0ZWRUb2tlbklsbGVnYWwpLHRoaXMuZXJyb3JIYW5kbGVyLnRvbGVyYXRlRXJyb3IodGhpcy5pbmRleCx0aGlzLmxpbmVOdW1iZXIsdGhpcy5pbmRleC10aGlzLmxpbmVTdGFydCsxLGUpfSxlLnByb3RvdHlwZS5za2lwU2luZ2xlTGluZUNvbW1lbnQ9ZnVuY3Rpb24oZSl7dmFyIHQsbixyPVtdO2Zvcih0aGlzLnRyYWNrQ29tbWVudCYmKHI9W10sdD10aGlzLmluZGV4LWUsbj17c3RhcnQ6e2xpbmU6dGhpcy5saW5lTnVtYmVyLGNvbHVtbjp0aGlzLmluZGV4LXRoaXMubGluZVN0YXJ0LWV9LGVuZDp7fX0pOyF0aGlzLmVvZigpOyl7dmFyIGk9dGhpcy5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLmluZGV4KTtpZigrK3RoaXMuaW5kZXgsYS5DaGFyYWN0ZXIuaXNMaW5lVGVybWluYXRvcihpKSl7aWYodGhpcy50cmFja0NvbW1lbnQpe24uZW5kPXtsaW5lOnRoaXMubGluZU51bWJlcixjb2x1bW46dGhpcy5pbmRleC10aGlzLmxpbmVTdGFydC0xfTt2YXIgbz17bXVsdGlMaW5lOiExLHNsaWNlOlt0K2UsdGhpcy5pbmRleC0xXSxyYW5nZTpbdCx0aGlzLmluZGV4LTFdLGxvYzpufTtyLnB1c2gobyl9cmV0dXJuIDEzPT09aSYmMTA9PT10aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpJiYrK3RoaXMuaW5kZXgsKyt0aGlzLmxpbmVOdW1iZXIsdGhpcy5saW5lU3RhcnQ9dGhpcy5pbmRleCxyfX1pZih0aGlzLnRyYWNrQ29tbWVudCl7bi5lbmQ9e2xpbmU6dGhpcy5saW5lTnVtYmVyLGNvbHVtbjp0aGlzLmluZGV4LXRoaXMubGluZVN0YXJ0fTt2YXIgbz17bXVsdGlMaW5lOiExLHNsaWNlOlt0K2UsdGhpcy5pbmRleF0scmFuZ2U6W3QsdGhpcy5pbmRleF0sbG9jOm59O3IucHVzaChvKX1yZXR1cm4gcn0sZS5wcm90b3R5cGUuc2tpcE11bHRpTGluZUNvbW1lbnQ9ZnVuY3Rpb24oKXt2YXIgZSx0LG49W107Zm9yKHRoaXMudHJhY2tDb21tZW50JiYobj1bXSxlPXRoaXMuaW5kZXgtMix0PXtzdGFydDp7bGluZTp0aGlzLmxpbmVOdW1iZXIsY29sdW1uOnRoaXMuaW5kZXgtdGhpcy5saW5lU3RhcnQtMn0sZW5kOnt9fSk7IXRoaXMuZW9mKCk7KXt2YXIgcj10aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpO2lmKGEuQ2hhcmFjdGVyLmlzTGluZVRlcm1pbmF0b3IocikpMTM9PT1yJiYxMD09PXRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCsxKSYmKyt0aGlzLmluZGV4LCsrdGhpcy5saW5lTnVtYmVyLCsrdGhpcy5pbmRleCx0aGlzLmxpbmVTdGFydD10aGlzLmluZGV4O2Vsc2UgaWYoNDI9PT1yKXtpZig0Nz09PXRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCsxKSl7aWYodGhpcy5pbmRleCs9Mix0aGlzLnRyYWNrQ29tbWVudCl7dC5lbmQ9e2xpbmU6dGhpcy5saW5lTnVtYmVyLGNvbHVtbjp0aGlzLmluZGV4LXRoaXMubGluZVN0YXJ0fTt2YXIgaT17bXVsdGlMaW5lOiEwLHNsaWNlOltlKzIsdGhpcy5pbmRleC0yXSxyYW5nZTpbZSx0aGlzLmluZGV4XSxsb2M6dH07bi5wdXNoKGkpfXJldHVybiBufSsrdGhpcy5pbmRleH1lbHNlKyt0aGlzLmluZGV4fWlmKHRoaXMudHJhY2tDb21tZW50KXt0LmVuZD17bGluZTp0aGlzLmxpbmVOdW1iZXIsY29sdW1uOnRoaXMuaW5kZXgtdGhpcy5saW5lU3RhcnR9O3ZhciBpPXttdWx0aUxpbmU6ITAsc2xpY2U6W2UrMix0aGlzLmluZGV4XSxyYW5nZTpbZSx0aGlzLmluZGV4XSxsb2M6dH07bi5wdXNoKGkpfXJldHVybiB0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKCksbn0sZS5wcm90b3R5cGUuc2NhbkNvbW1lbnRzPWZ1bmN0aW9uKCl7dmFyIGU7dGhpcy50cmFja0NvbW1lbnQmJihlPVtdKTtmb3IodmFyIHQ9MD09PXRoaXMuaW5kZXg7IXRoaXMuZW9mKCk7KXt2YXIgbj10aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpO2lmKGEuQ2hhcmFjdGVyLmlzV2hpdGVTcGFjZShuKSkrK3RoaXMuaW5kZXg7ZWxzZSBpZihhLkNoYXJhY3Rlci5pc0xpbmVUZXJtaW5hdG9yKG4pKSsrdGhpcy5pbmRleCwxMz09PW4mJjEwPT09dGhpcy5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLmluZGV4KSYmKyt0aGlzLmluZGV4LCsrdGhpcy5saW5lTnVtYmVyLHRoaXMubGluZVN0YXJ0PXRoaXMuaW5kZXgsdD0hMDtlbHNlIGlmKDQ3PT09bilpZig0Nz09PShuPXRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCsxKSkpe3RoaXMuaW5kZXgrPTI7dmFyIHI9dGhpcy5za2lwU2luZ2xlTGluZUNvbW1lbnQoMik7dGhpcy50cmFja0NvbW1lbnQmJihlPWUuY29uY2F0KHIpKSx0PSEwfWVsc2V7aWYoNDIhPT1uKWJyZWFrO3RoaXMuaW5kZXgrPTI7dmFyIHI9dGhpcy5za2lwTXVsdGlMaW5lQ29tbWVudCgpO3RoaXMudHJhY2tDb21tZW50JiYoZT1lLmNvbmNhdChyKSl9ZWxzZSBpZih0JiY0NT09PW4pe2lmKDQ1IT09dGhpcy5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLmluZGV4KzEpfHw2MiE9PXRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCsyKSlicmVhazt0aGlzLmluZGV4Kz0zO3ZhciByPXRoaXMuc2tpcFNpbmdsZUxpbmVDb21tZW50KDMpO3RoaXMudHJhY2tDb21tZW50JiYoZT1lLmNvbmNhdChyKSl9ZWxzZXtpZig2MCE9PW4pYnJlYWs7aWYoIiEtLSIhPT10aGlzLnNvdXJjZS5zbGljZSh0aGlzLmluZGV4KzEsdGhpcy5pbmRleCs0KSlicmVhazt0aGlzLmluZGV4Kz00O3ZhciByPXRoaXMuc2tpcFNpbmdsZUxpbmVDb21tZW50KDQpO3RoaXMudHJhY2tDb21tZW50JiYoZT1lLmNvbmNhdChyKSl9fXJldHVybiBlfSxlLnByb3RvdHlwZS5pc0Z1dHVyZVJlc2VydmVkV29yZD1mdW5jdGlvbihlKXtzd2l0Y2goZSl7Y2FzZSJlbnVtIjpjYXNlImV4cG9ydCI6Y2FzZSJpbXBvcnQiOmNhc2Uic3VwZXIiOnJldHVybiEwO2RlZmF1bHQ6cmV0dXJuITF9fSxlLnByb3RvdHlwZS5pc1N0cmljdE1vZGVSZXNlcnZlZFdvcmQ9ZnVuY3Rpb24oZSl7c3dpdGNoKGUpe2Nhc2UiaW1wbGVtZW50cyI6Y2FzZSJpbnRlcmZhY2UiOmNhc2UicGFja2FnZSI6Y2FzZSJwcml2YXRlIjpjYXNlInByb3RlY3RlZCI6Y2FzZSJwdWJsaWMiOmNhc2Uic3RhdGljIjpjYXNlInlpZWxkIjpjYXNlImxldCI6cmV0dXJuITA7ZGVmYXVsdDpyZXR1cm4hMX19LGUucHJvdG90eXBlLmlzUmVzdHJpY3RlZFdvcmQ9ZnVuY3Rpb24oZSl7cmV0dXJuImV2YWwiPT09ZXx8ImFyZ3VtZW50cyI9PT1lfSxlLnByb3RvdHlwZS5pc0tleXdvcmQ9ZnVuY3Rpb24oZSl7c3dpdGNoKGUubGVuZ3RoKXtjYXNlIDI6cmV0dXJuImlmIj09PWV8fCJpbiI9PT1lfHwiZG8iPT09ZTtjYXNlIDM6cmV0dXJuInZhciI9PT1lfHwiZm9yIj09PWV8fCJuZXciPT09ZXx8InRyeSI9PT1lfHwibGV0Ij09PWU7Y2FzZSA0OnJldHVybiJ0aGlzIj09PWV8fCJlbHNlIj09PWV8fCJjYXNlIj09PWV8fCJ2b2lkIj09PWV8fCJ3aXRoIj09PWV8fCJlbnVtIj09PWU7Y2FzZSA1OnJldHVybiJ3aGlsZSI9PT1lfHwiYnJlYWsiPT09ZXx8ImNhdGNoIj09PWV8fCJ0aHJvdyI9PT1lfHwiY29uc3QiPT09ZXx8InlpZWxkIj09PWV8fCJjbGFzcyI9PT1lfHwic3VwZXIiPT09ZTtjYXNlIDY6cmV0dXJuInJldHVybiI9PT1lfHwidHlwZW9mIj09PWV8fCJkZWxldGUiPT09ZXx8InN3aXRjaCI9PT1lfHwiZXhwb3J0Ij09PWV8fCJpbXBvcnQiPT09ZTtjYXNlIDc6cmV0dXJuImRlZmF1bHQiPT09ZXx8ImZpbmFsbHkiPT09ZXx8ImV4dGVuZHMiPT09ZTtjYXNlIDg6cmV0dXJuImZ1bmN0aW9uIj09PWV8fCJjb250aW51ZSI9PT1lfHwiZGVidWdnZXIiPT09ZTtjYXNlIDEwOnJldHVybiJpbnN0YW5jZW9mIj09PWU7ZGVmYXVsdDpyZXR1cm4hMX19LGUucHJvdG90eXBlLmNvZGVQb2ludEF0PWZ1bmN0aW9uKGUpe3ZhciB0PXRoaXMuc291cmNlLmNoYXJDb2RlQXQoZSk7aWYodD49NTUyOTYmJnQ8PTU2MzE5KXt2YXIgbj10aGlzLnNvdXJjZS5jaGFyQ29kZUF0KGUrMSk7aWYobj49NTYzMjAmJm48PTU3MzQzKXt0PTEwMjQqKHQtNTUyOTYpK24tNTYzMjArNjU1MzZ9fXJldHVybiB0fSxlLnByb3RvdHlwZS5zY2FuSGV4RXNjYXBlPWZ1bmN0aW9uKGUpe2Zvcih2YXIgdD0idSI9PT1lPzQ6MixuPTAsaT0wO2k8dDsrK2kpe2lmKHRoaXMuZW9mKCl8fCFhLkNoYXJhY3Rlci5pc0hleERpZ2l0KHRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCkpKXJldHVybiBudWxsO249MTYqbityKHRoaXMuc291cmNlW3RoaXMuaW5kZXgrK10pfXJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKG4pfSxlLnByb3RvdHlwZS5zY2FuVW5pY29kZUNvZGVQb2ludEVzY2FwZT1mdW5jdGlvbigpe3ZhciBlPXRoaXMuc291cmNlW3RoaXMuaW5kZXhdLHQ9MDtmb3IoIn0iPT09ZSYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbigpOyF0aGlzLmVvZigpJiYoZT10aGlzLnNvdXJjZVt0aGlzLmluZGV4KytdLGEuQ2hhcmFjdGVyLmlzSGV4RGlnaXQoZS5jaGFyQ29kZUF0KDApKSk7KXQ9MTYqdCtyKGUpO3JldHVybih0PjExMTQxMTF8fCJ9IiE9PWUpJiZ0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKCksYS5DaGFyYWN0ZXIuZnJvbUNvZGVQb2ludCh0KX0sZS5wcm90b3R5cGUuZ2V0SWRlbnRpZmllcj1mdW5jdGlvbigpe2Zvcih2YXIgZT10aGlzLmluZGV4Kys7IXRoaXMuZW9mKCk7KXt2YXIgdD10aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpO2lmKDkyPT09dClyZXR1cm4gdGhpcy5pbmRleD1lLHRoaXMuZ2V0Q29tcGxleElkZW50aWZpZXIoKTtpZih0Pj01NTI5NiYmdDw1NzM0MylyZXR1cm4gdGhpcy5pbmRleD1lLHRoaXMuZ2V0Q29tcGxleElkZW50aWZpZXIoKTtpZighYS5DaGFyYWN0ZXIuaXNJZGVudGlmaWVyUGFydCh0KSlicmVhazsrK3RoaXMuaW5kZXh9cmV0dXJuIHRoaXMuc291cmNlLnNsaWNlKGUsdGhpcy5pbmRleCl9LGUucHJvdG90eXBlLmdldENvbXBsZXhJZGVudGlmaWVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5jb2RlUG9pbnRBdCh0aGlzLmluZGV4KSx0PWEuQ2hhcmFjdGVyLmZyb21Db2RlUG9pbnQoZSk7dGhpcy5pbmRleCs9dC5sZW5ndGg7dmFyIG47Zm9yKDkyPT09ZSYmKDExNyE9PXRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCkmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4oKSwrK3RoaXMuaW5kZXgsInsiPT09dGhpcy5zb3VyY2VbdGhpcy5pbmRleF0/KCsrdGhpcy5pbmRleCxuPXRoaXMuc2NhblVuaWNvZGVDb2RlUG9pbnRFc2NhcGUoKSk6bnVsbCE9PShuPXRoaXMuc2NhbkhleEVzY2FwZSgidSIpKSYmIlxcIiE9PW4mJmEuQ2hhcmFjdGVyLmlzSWRlbnRpZmllclN0YXJ0KG4uY2hhckNvZGVBdCgwKSl8fHRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4oKSx0PW4pOyF0aGlzLmVvZigpJiYoZT10aGlzLmNvZGVQb2ludEF0KHRoaXMuaW5kZXgpLGEuQ2hhcmFjdGVyLmlzSWRlbnRpZmllclBhcnQoZSkpOyluPWEuQ2hhcmFjdGVyLmZyb21Db2RlUG9pbnQoZSksdCs9bix0aGlzLmluZGV4Kz1uLmxlbmd0aCw5Mj09PWUmJih0PXQuc3Vic3RyKDAsdC5sZW5ndGgtMSksMTE3IT09dGhpcy5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLmluZGV4KSYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbigpLCsrdGhpcy5pbmRleCwieyI9PT10aGlzLnNvdXJjZVt0aGlzLmluZGV4XT8oKyt0aGlzLmluZGV4LG49dGhpcy5zY2FuVW5pY29kZUNvZGVQb2ludEVzY2FwZSgpKTpudWxsIT09KG49dGhpcy5zY2FuSGV4RXNjYXBlKCJ1IikpJiYiXFwiIT09biYmYS5DaGFyYWN0ZXIuaXNJZGVudGlmaWVyUGFydChuLmNoYXJDb2RlQXQoMCkpfHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKCksdCs9bik7cmV0dXJuIHR9LGUucHJvdG90eXBlLm9jdGFsVG9EZWNpbWFsPWZ1bmN0aW9uKGUpe3ZhciB0PSIwIiE9PWUsbj1pKGUpO3JldHVybiF0aGlzLmVvZigpJiZhLkNoYXJhY3Rlci5pc09jdGFsRGlnaXQodGhpcy5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLmluZGV4KSkmJih0PSEwLG49OCpuK2kodGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXSksIjAxMjMiLmluZGV4T2YoZSk+PTAmJiF0aGlzLmVvZigpJiZhLkNoYXJhY3Rlci5pc09jdGFsRGlnaXQodGhpcy5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLmluZGV4KSkmJihuPTgqbitpKHRoaXMuc291cmNlW3RoaXMuaW5kZXgrK10pKSkse2NvZGU6bixvY3RhbDp0fX0sZS5wcm90b3R5cGUuc2NhbklkZW50aWZpZXI9ZnVuY3Rpb24oKXt2YXIgZSx0PXRoaXMuaW5kZXgsbj05Mj09PXRoaXMuc291cmNlLmNoYXJDb2RlQXQodCk/dGhpcy5nZXRDb21wbGV4SWRlbnRpZmllcigpOnRoaXMuZ2V0SWRlbnRpZmllcigpO2lmKDMhPT0oZT0xPT09bi5sZW5ndGg/Mzp0aGlzLmlzS2V5d29yZChuKT80OiJudWxsIj09PW4/NToidHJ1ZSI9PT1ufHwiZmFsc2UiPT09bj8xOjMpJiZ0K24ubGVuZ3RoIT09dGhpcy5pbmRleCl7dmFyIHI9dGhpcy5pbmRleDt0aGlzLmluZGV4PXQsdGhpcy50b2xlcmF0ZVVuZXhwZWN0ZWRUb2tlbihzLk1lc3NhZ2VzLkludmFsaWRFc2NhcGVkUmVzZXJ2ZWRXb3JkKSx0aGlzLmluZGV4PXJ9cmV0dXJue3R5cGU6ZSx2YWx1ZTpuLGxpbmVOdW1iZXI6dGhpcy5saW5lTnVtYmVyLGxpbmVTdGFydDp0aGlzLmxpbmVTdGFydCxzdGFydDp0LGVuZDp0aGlzLmluZGV4fX0sZS5wcm90b3R5cGUuc2NhblB1bmN0dWF0b3I9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLmluZGV4LHQ9dGhpcy5zb3VyY2VbdGhpcy5pbmRleF07c3dpdGNoKHQpe2Nhc2UiKCI6Y2FzZSJ7IjoieyI9PT10JiZ0aGlzLmN1cmx5U3RhY2sucHVzaCgieyIpLCsrdGhpcy5pbmRleDticmVhaztjYXNlIi4iOisrdGhpcy5pbmRleCwiLiI9PT10aGlzLnNvdXJjZVt0aGlzLmluZGV4XSYmIi4iPT09dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsxXSYmKHRoaXMuaW5kZXgrPTIsdD0iLi4uIik7YnJlYWs7Y2FzZSJ9IjorK3RoaXMuaW5kZXgsdGhpcy5jdXJseVN0YWNrLnBvcCgpO2JyZWFrO2Nhc2UiKSI6Y2FzZSI7IjpjYXNlIiwiOmNhc2UiWyI6Y2FzZSJdIjpjYXNlIjoiOmNhc2UiPyI6Y2FzZSJ+IjorK3RoaXMuaW5kZXg7YnJlYWs7ZGVmYXVsdDp0PXRoaXMuc291cmNlLnN1YnN0cih0aGlzLmluZGV4LDQpLCI+Pj49Ij09PXQ/dGhpcy5pbmRleCs9NDoodD10LnN1YnN0cigwLDMpLCI9PT0iPT09dHx8IiE9PSI9PT10fHwiPj4+Ij09PXR8fCI8PD0iPT09dHx8Ij4+PSI9PT10fHwiKio9Ij09PXQ/dGhpcy5pbmRleCs9MzoodD10LnN1YnN0cigwLDIpLCImJiI9PT10fHwifHwiPT09dHx8Ij09Ij09PXR8fCIhPSI9PT10fHwiKz0iPT09dHx8Ii09Ij09PXR8fCIqPSI9PT10fHwiLz0iPT09dHx8IisrIj09PXR8fCItLSI9PT10fHwiPDwiPT09dHx8Ij4+Ij09PXR8fCImPSI9PT10fHwifD0iPT09dHx8Il49Ij09PXR8fCIlPSI9PT10fHwiPD0iPT09dHx8Ij49Ij09PXR8fCI9PiI9PT10fHwiKioiPT09dD90aGlzLmluZGV4Kz0yOih0PXRoaXMuc291cmNlW3RoaXMuaW5kZXhdLCI8Pj0hKy0qJSZ8Xi8iLmluZGV4T2YodCk+PTAmJisrdGhpcy5pbmRleCkpKX1yZXR1cm4gdGhpcy5pbmRleD09PWUmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4oKSx7dHlwZTo3LHZhbHVlOnQsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsbGluZVN0YXJ0OnRoaXMubGluZVN0YXJ0LHN0YXJ0OmUsZW5kOnRoaXMuaW5kZXh9fSxlLnByb3RvdHlwZS5zY2FuSGV4TGl0ZXJhbD1mdW5jdGlvbihlKXtmb3IodmFyIHQ9IiI7IXRoaXMuZW9mKCkmJmEuQ2hhcmFjdGVyLmlzSGV4RGlnaXQodGhpcy5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLmluZGV4KSk7KXQrPXRoaXMuc291cmNlW3RoaXMuaW5kZXgrK107cmV0dXJuIDA9PT10Lmxlbmd0aCYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbigpLGEuQ2hhcmFjdGVyLmlzSWRlbnRpZmllclN0YXJ0KHRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCkpJiZ0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKCkse3R5cGU6Nix2YWx1ZTpwYXJzZUludCgiMHgiK3QsMTYpLGxpbmVOdW1iZXI6dGhpcy5saW5lTnVtYmVyLGxpbmVTdGFydDp0aGlzLmxpbmVTdGFydCxzdGFydDplLGVuZDp0aGlzLmluZGV4fX0sZS5wcm90b3R5cGUuc2NhbkJpbmFyeUxpdGVyYWw9ZnVuY3Rpb24oZSl7Zm9yKHZhciB0LG49IiI7IXRoaXMuZW9mKCkmJigiMCI9PT0odD10aGlzLnNvdXJjZVt0aGlzLmluZGV4XSl8fCIxIj09PXQpOyluKz10aGlzLnNvdXJjZVt0aGlzLmluZGV4KytdO3JldHVybiAwPT09bi5sZW5ndGgmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4oKSx0aGlzLmVvZigpfHwodD10aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpLChhLkNoYXJhY3Rlci5pc0lkZW50aWZpZXJTdGFydCh0KXx8YS5DaGFyYWN0ZXIuaXNEZWNpbWFsRGlnaXQodCkpJiZ0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKCkpLHt0eXBlOjYsdmFsdWU6cGFyc2VJbnQobiwyKSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixsaW5lU3RhcnQ6dGhpcy5saW5lU3RhcnQsc3RhcnQ6ZSxlbmQ6dGhpcy5pbmRleH19LGUucHJvdG90eXBlLnNjYW5PY3RhbExpdGVyYWw9ZnVuY3Rpb24oZSx0KXt2YXIgbj0iIixyPSExO2ZvcihhLkNoYXJhY3Rlci5pc09jdGFsRGlnaXQoZS5jaGFyQ29kZUF0KDApKT8ocj0hMCxuPSIwIit0aGlzLnNvdXJjZVt0aGlzLmluZGV4KytdKTorK3RoaXMuaW5kZXg7IXRoaXMuZW9mKCkmJmEuQ2hhcmFjdGVyLmlzT2N0YWxEaWdpdCh0aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpKTspbis9dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXTtyZXR1cm4gcnx8MCE9PW4ubGVuZ3RofHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKCksKGEuQ2hhcmFjdGVyLmlzSWRlbnRpZmllclN0YXJ0KHRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCkpfHxhLkNoYXJhY3Rlci5pc0RlY2ltYWxEaWdpdCh0aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpKSkmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4oKSx7dHlwZTo2LHZhbHVlOnBhcnNlSW50KG4sOCksb2N0YWw6cixsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixsaW5lU3RhcnQ6dGhpcy5saW5lU3RhcnQsc3RhcnQ6dCxlbmQ6dGhpcy5pbmRleH19LGUucHJvdG90eXBlLmlzSW1wbGljaXRPY3RhbExpdGVyYWw9ZnVuY3Rpb24oKXtmb3IodmFyIGU9dGhpcy5pbmRleCsxO2U8dGhpcy5sZW5ndGg7KytlKXt2YXIgdD10aGlzLnNvdXJjZVtlXTtpZigiOCI9PT10fHwiOSI9PT10KXJldHVybiExO2lmKCFhLkNoYXJhY3Rlci5pc09jdGFsRGlnaXQodC5jaGFyQ29kZUF0KDApKSlyZXR1cm4hMH1yZXR1cm4hMH0sZS5wcm90b3R5cGUuc2Nhbk51bWVyaWNMaXRlcmFsPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5pbmRleCx0PXRoaXMuc291cmNlW2VdO28uYXNzZXJ0KGEuQ2hhcmFjdGVyLmlzRGVjaW1hbERpZ2l0KHQuY2hhckNvZGVBdCgwKSl8fCIuIj09PXQsIk51bWVyaWMgbGl0ZXJhbCBtdXN0IHN0YXJ0IHdpdGggYSBkZWNpbWFsIGRpZ2l0IG9yIGEgZGVjaW1hbCBwb2ludCIpO3ZhciBuPSIiO2lmKCIuIiE9PXQpe2lmKG49dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXSx0PXRoaXMuc291cmNlW3RoaXMuaW5kZXhdLCIwIj09PW4pe2lmKCJ4Ij09PXR8fCJYIj09PXQpcmV0dXJuKyt0aGlzLmluZGV4LHRoaXMuc2NhbkhleExpdGVyYWwoZSk7aWYoImIiPT09dHx8IkIiPT09dClyZXR1cm4rK3RoaXMuaW5kZXgsdGhpcy5zY2FuQmluYXJ5TGl0ZXJhbChlKTtpZigibyI9PT10fHwiTyI9PT10KXJldHVybiB0aGlzLnNjYW5PY3RhbExpdGVyYWwodCxlKTtpZih0JiZhLkNoYXJhY3Rlci5pc09jdGFsRGlnaXQodC5jaGFyQ29kZUF0KDApKSYmdGhpcy5pc0ltcGxpY2l0T2N0YWxMaXRlcmFsKCkpcmV0dXJuIHRoaXMuc2Nhbk9jdGFsTGl0ZXJhbCh0LGUpfWZvcig7YS5DaGFyYWN0ZXIuaXNEZWNpbWFsRGlnaXQodGhpcy5zb3VyY2UuY2hhckNvZGVBdCh0aGlzLmluZGV4KSk7KW4rPXRoaXMuc291cmNlW3RoaXMuaW5kZXgrK107dD10aGlzLnNvdXJjZVt0aGlzLmluZGV4XX1pZigiLiI9PT10KXtmb3Iobis9dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXTthLkNoYXJhY3Rlci5pc0RlY2ltYWxEaWdpdCh0aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpKTspbis9dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXTt0PXRoaXMuc291cmNlW3RoaXMuaW5kZXhdfWlmKCJlIj09PXR8fCJFIj09PXQpaWYobis9dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXSx0PXRoaXMuc291cmNlW3RoaXMuaW5kZXhdLCIrIiE9PXQmJiItIiE9PXR8fChuKz10aGlzLnNvdXJjZVt0aGlzLmluZGV4KytdKSxhLkNoYXJhY3Rlci5pc0RlY2ltYWxEaWdpdCh0aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpKSlmb3IoO2EuQ2hhcmFjdGVyLmlzRGVjaW1hbERpZ2l0KHRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCkpOyluKz10aGlzLnNvdXJjZVt0aGlzLmluZGV4KytdO2Vsc2UgdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbigpO3JldHVybiBhLkNoYXJhY3Rlci5pc0lkZW50aWZpZXJTdGFydCh0aGlzLnNvdXJjZS5jaGFyQ29kZUF0KHRoaXMuaW5kZXgpKSYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbigpLHt0eXBlOjYsdmFsdWU6cGFyc2VGbG9hdChuKSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixsaW5lU3RhcnQ6dGhpcy5saW5lU3RhcnQsc3RhcnQ6ZSxlbmQ6dGhpcy5pbmRleH19LGUucHJvdG90eXBlLnNjYW5TdHJpbmdMaXRlcmFsPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5pbmRleCx0PXRoaXMuc291cmNlW2VdO28uYXNzZXJ0KCInIj09PXR8fCciJz09PXQsIlN0cmluZyBsaXRlcmFsIG11c3Qgc3RhcnRzIHdpdGggYSBxdW90ZSIpLCsrdGhpcy5pbmRleDtmb3IodmFyIG49ITEscj0iIjshdGhpcy5lb2YoKTspe3ZhciBpPXRoaXMuc291cmNlW3RoaXMuaW5kZXgrK107aWYoaT09PXQpe3Q9IiI7YnJlYWt9aWYoIlxcIj09PWkpaWYoKGk9dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXSkmJmEuQ2hhcmFjdGVyLmlzTGluZVRlcm1pbmF0b3IoaS5jaGFyQ29kZUF0KDApKSkrK3RoaXMubGluZU51bWJlciwiXHIiPT09aSYmIlxuIj09PXRoaXMuc291cmNlW3RoaXMuaW5kZXhdJiYrK3RoaXMuaW5kZXgsdGhpcy5saW5lU3RhcnQ9dGhpcy5pbmRleDtlbHNlIHN3aXRjaChpKXtjYXNlInUiOmlmKCJ7Ij09PXRoaXMuc291cmNlW3RoaXMuaW5kZXhdKSsrdGhpcy5pbmRleCxyKz10aGlzLnNjYW5Vbmljb2RlQ29kZVBvaW50RXNjYXBlKCk7ZWxzZXt2YXIgdT10aGlzLnNjYW5IZXhFc2NhcGUoaSk7bnVsbD09PXUmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4oKSxyKz11fWJyZWFrO2Nhc2UieCI6dmFyIGM9dGhpcy5zY2FuSGV4RXNjYXBlKGkpO251bGw9PT1jJiZ0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHMuTWVzc2FnZXMuSW52YWxpZEhleEVzY2FwZVNlcXVlbmNlKSxyKz1jO2JyZWFrO2Nhc2UibiI6cis9IlxuIjticmVhaztjYXNlInIiOnIrPSJcciI7YnJlYWs7Y2FzZSJ0IjpyKz0iXHQiO2JyZWFrO2Nhc2UiYiI6cis9IlxiIjticmVhaztjYXNlImYiOnIrPSJcZiI7YnJlYWs7Y2FzZSJ2IjpyKz0iXHYiO2JyZWFrO2Nhc2UiOCI6Y2FzZSI5IjpyKz1pLHRoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4oKTticmVhaztkZWZhdWx0OmlmKGkmJmEuQ2hhcmFjdGVyLmlzT2N0YWxEaWdpdChpLmNoYXJDb2RlQXQoMCkpKXt2YXIgbD10aGlzLm9jdGFsVG9EZWNpbWFsKGkpO249bC5vY3RhbHx8bixyKz1TdHJpbmcuZnJvbUNoYXJDb2RlKGwuY29kZSl9ZWxzZSByKz1pfWVsc2V7aWYoYS5DaGFyYWN0ZXIuaXNMaW5lVGVybWluYXRvcihpLmNoYXJDb2RlQXQoMCkpKWJyZWFrO3IrPWl9fXJldHVybiIiIT09dCYmKHRoaXMuaW5kZXg9ZSx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKCkpLHt0eXBlOjgsdmFsdWU6cixvY3RhbDpuLGxpbmVOdW1iZXI6dGhpcy5saW5lTnVtYmVyLGxpbmVTdGFydDp0aGlzLmxpbmVTdGFydCxzdGFydDplLGVuZDp0aGlzLmluZGV4fX0sZS5wcm90b3R5cGUuc2NhblRlbXBsYXRlPWZ1bmN0aW9uKCl7dmFyIGU9IiIsdD0hMSxuPXRoaXMuaW5kZXgscj0iYCI9PT10aGlzLnNvdXJjZVtuXSxpPSExLG89Mjtmb3IoKyt0aGlzLmluZGV4OyF0aGlzLmVvZigpOyl7dmFyIHU9dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXTtpZigiYCI9PT11KXtvPTEsaT0hMCx0PSEwO2JyZWFrfWlmKCIkIj09PXUpe2lmKCJ7Ij09PXRoaXMuc291cmNlW3RoaXMuaW5kZXhdKXt0aGlzLmN1cmx5U3RhY2sucHVzaCgiJHsiKSwrK3RoaXMuaW5kZXgsdD0hMDticmVha31lKz11fWVsc2UgaWYoIlxcIj09PXUpaWYodT10aGlzLnNvdXJjZVt0aGlzLmluZGV4KytdLGEuQ2hhcmFjdGVyLmlzTGluZVRlcm1pbmF0b3IodS5jaGFyQ29kZUF0KDApKSkrK3RoaXMubGluZU51bWJlciwiXHIiPT09dSYmIlxuIj09PXRoaXMuc291cmNlW3RoaXMuaW5kZXhdJiYrK3RoaXMuaW5kZXgsdGhpcy5saW5lU3RhcnQ9dGhpcy5pbmRleDtlbHNlIHN3aXRjaCh1KXtjYXNlIm4iOmUrPSJcbiI7YnJlYWs7Y2FzZSJyIjplKz0iXHIiO2JyZWFrO2Nhc2UidCI6ZSs9Ilx0IjticmVhaztjYXNlInUiOmlmKCJ7Ij09PXRoaXMuc291cmNlW3RoaXMuaW5kZXhdKSsrdGhpcy5pbmRleCxlKz10aGlzLnNjYW5Vbmljb2RlQ29kZVBvaW50RXNjYXBlKCk7ZWxzZXt2YXIgYz10aGlzLmluZGV4LGw9dGhpcy5zY2FuSGV4RXNjYXBlKHUpO251bGwhPT1sP2UrPWw6KHRoaXMuaW5kZXg9YyxlKz11KX1icmVhaztjYXNlIngiOnZhciBwPXRoaXMuc2NhbkhleEVzY2FwZSh1KTtudWxsPT09cCYmdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbihzLk1lc3NhZ2VzLkludmFsaWRIZXhFc2NhcGVTZXF1ZW5jZSksZSs9cDticmVhaztjYXNlImIiOmUrPSJcYiI7YnJlYWs7Y2FzZSJmIjplKz0iXGYiO2JyZWFrO2Nhc2UidiI6ZSs9Ilx2IjticmVhaztkZWZhdWx0OiIwIj09PXU/KGEuQ2hhcmFjdGVyLmlzRGVjaW1hbERpZ2l0KHRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCkpJiZ0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHMuTWVzc2FnZXMuVGVtcGxhdGVPY3RhbExpdGVyYWwpLGUrPSJcMCIpOmEuQ2hhcmFjdGVyLmlzT2N0YWxEaWdpdCh1LmNoYXJDb2RlQXQoMCkpP3RoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4ocy5NZXNzYWdlcy5UZW1wbGF0ZU9jdGFsTGl0ZXJhbCk6ZSs9dX1lbHNlIGEuQ2hhcmFjdGVyLmlzTGluZVRlcm1pbmF0b3IodS5jaGFyQ29kZUF0KDApKT8oKyt0aGlzLmxpbmVOdW1iZXIsIlxyIj09PXUmJiJcbiI9PT10aGlzLnNvdXJjZVt0aGlzLmluZGV4XSYmKyt0aGlzLmluZGV4LHRoaXMubGluZVN0YXJ0PXRoaXMuaW5kZXgsZSs9IlxuIik6ZSs9dX1yZXR1cm4gdHx8dGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbigpLHJ8fHRoaXMuY3VybHlTdGFjay5wb3AoKSx7dHlwZToxMCx2YWx1ZTp0aGlzLnNvdXJjZS5zbGljZShuKzEsdGhpcy5pbmRleC1vKSxjb29rZWQ6ZSxoZWFkOnIsdGFpbDppLGxpbmVOdW1iZXI6dGhpcy5saW5lTnVtYmVyLGxpbmVTdGFydDp0aGlzLmxpbmVTdGFydCxzdGFydDpuLGVuZDp0aGlzLmluZGV4fX0sZS5wcm90b3R5cGUudGVzdFJlZ0V4cD1mdW5jdGlvbihlLHQpe3ZhciBuPWUscj10aGlzO3QuaW5kZXhPZigidSIpPj0wJiYobj1uLnJlcGxhY2UoL1xcdVx7KFswLTlhLWZBLUZdKylcfXxcXHUoW2EtZkEtRjAtOV17NH0pL2csZnVuY3Rpb24oZSx0LG4pe3ZhciBpPXBhcnNlSW50KHR8fG4sMTYpO3JldHVybiBpPjExMTQxMTEmJnIudGhyb3dVbmV4cGVjdGVkVG9rZW4ocy5NZXNzYWdlcy5JbnZhbGlkUmVnRXhwKSxpPD02NTUzNT9TdHJpbmcuZnJvbUNoYXJDb2RlKGkpOiJcdWZmZmYifSkucmVwbGFjZSgvW1x1RDgwMC1cdURCRkZdW1x1REMwMC1cdURGRkZdL2csIlx1ZmZmZiIpKTt0cnl7UmVnRXhwKG4pfWNhdGNoKGUpe3RoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4ocy5NZXNzYWdlcy5JbnZhbGlkUmVnRXhwKX10cnl7cmV0dXJuIG5ldyBSZWdFeHAoZSx0KX1jYXRjaChlKXtyZXR1cm4gbnVsbH19LGUucHJvdG90eXBlLnNjYW5SZWdFeHBCb2R5PWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5zb3VyY2VbdGhpcy5pbmRleF07by5hc3NlcnQoIi8iPT09ZSwiUmVndWxhciBleHByZXNzaW9uIGxpdGVyYWwgbXVzdCBzdGFydCB3aXRoIGEgc2xhc2giKTtmb3IodmFyIHQ9dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXSxuPSExLHI9ITE7IXRoaXMuZW9mKCk7KWlmKGU9dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXSx0Kz1lLCJcXCI9PT1lKWU9dGhpcy5zb3VyY2VbdGhpcy5pbmRleCsrXSxhLkNoYXJhY3Rlci5pc0xpbmVUZXJtaW5hdG9yKGUuY2hhckNvZGVBdCgwKSkmJnRoaXMudGhyb3dVbmV4cGVjdGVkVG9rZW4ocy5NZXNzYWdlcy5VbnRlcm1pbmF0ZWRSZWdFeHApLHQrPWU7ZWxzZSBpZihhLkNoYXJhY3Rlci5pc0xpbmVUZXJtaW5hdG9yKGUuY2hhckNvZGVBdCgwKSkpdGhpcy50aHJvd1VuZXhwZWN0ZWRUb2tlbihzLk1lc3NhZ2VzLlVudGVybWluYXRlZFJlZ0V4cCk7ZWxzZSBpZihuKSJdIj09PWUmJihuPSExKTtlbHNle2lmKCIvIj09PWUpe3I9ITA7YnJlYWt9IlsiPT09ZSYmKG49ITApfXJldHVybiByfHx0aGlzLnRocm93VW5leHBlY3RlZFRva2VuKHMuTWVzc2FnZXMuVW50ZXJtaW5hdGVkUmVnRXhwKSx0LnN1YnN0cigxLHQubGVuZ3RoLTIpfSxlLnByb3RvdHlwZS5zY2FuUmVnRXhwRmxhZ3M9ZnVuY3Rpb24oKXtmb3IodmFyIGU9IiIsdD0iIjshdGhpcy5lb2YoKTspe3ZhciBuPXRoaXMuc291cmNlW3RoaXMuaW5kZXhdO2lmKCFhLkNoYXJhY3Rlci5pc0lkZW50aWZpZXJQYXJ0KG4uY2hhckNvZGVBdCgwKSkpYnJlYWs7aWYoKyt0aGlzLmluZGV4LCJcXCIhPT1ufHx0aGlzLmVvZigpKXQrPW4sZSs9bjtlbHNlIGlmKCJ1Ij09PShuPXRoaXMuc291cmNlW3RoaXMuaW5kZXhdKSl7Kyt0aGlzLmluZGV4O3ZhciByPXRoaXMuaW5kZXgsaT10aGlzLnNjYW5IZXhFc2NhcGUoInUiKTtpZihudWxsIT09aSlmb3IodCs9aSxlKz0iXFx1IjtyPHRoaXMuaW5kZXg7KytyKWUrPXRoaXMuc291cmNlW3JdO2Vsc2UgdGhpcy5pbmRleD1yLHQrPSJ1IixlKz0iXFx1Ijt0aGlzLnRvbGVyYXRlVW5leHBlY3RlZFRva2VuKCl9ZWxzZSBlKz0iXFwiLHRoaXMudG9sZXJhdGVVbmV4cGVjdGVkVG9rZW4oKX1yZXR1cm4gdH0sZS5wcm90b3R5cGUuc2NhblJlZ0V4cD1mdW5jdGlvbigpe3ZhciBlPXRoaXMuaW5kZXgsdD10aGlzLnNjYW5SZWdFeHBCb2R5KCksbj10aGlzLnNjYW5SZWdFeHBGbGFncygpO3JldHVybnt0eXBlOjksdmFsdWU6IiIscGF0dGVybjp0LGZsYWdzOm4scmVnZXg6dGhpcy50ZXN0UmVnRXhwKHQsbiksbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsbGluZVN0YXJ0OnRoaXMubGluZVN0YXJ0LHN0YXJ0OmUsZW5kOnRoaXMuaW5kZXh9fSxlLnByb3RvdHlwZS5sZXg9ZnVuY3Rpb24oKXtpZih0aGlzLmVvZigpKXJldHVybnt0eXBlOjIsdmFsdWU6IiIsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsbGluZVN0YXJ0OnRoaXMubGluZVN0YXJ0LHN0YXJ0OnRoaXMuaW5kZXgsZW5kOnRoaXMuaW5kZXh9O3ZhciBlPXRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCk7cmV0dXJuIGEuQ2hhcmFjdGVyLmlzSWRlbnRpZmllclN0YXJ0KGUpP3RoaXMuc2NhbklkZW50aWZpZXIoKTo0MD09PWV8fDQxPT09ZXx8NTk9PT1lP3RoaXMuc2NhblB1bmN0dWF0b3IoKTozOT09PWV8fDM0PT09ZT90aGlzLnNjYW5TdHJpbmdMaXRlcmFsKCk6NDY9PT1lP2EuQ2hhcmFjdGVyLmlzRGVjaW1hbERpZ2l0KHRoaXMuc291cmNlLmNoYXJDb2RlQXQodGhpcy5pbmRleCsxKSk/dGhpcy5zY2FuTnVtZXJpY0xpdGVyYWwoKTp0aGlzLnNjYW5QdW5jdHVhdG9yKCk6YS5DaGFyYWN0ZXIuaXNEZWNpbWFsRGlnaXQoZSk/dGhpcy5zY2FuTnVtZXJpY0xpdGVyYWwoKTo5Nj09PWV8fDEyNT09PWUmJiIkeyI9PT10aGlzLmN1cmx5U3RhY2tbdGhpcy5jdXJseVN0YWNrLmxlbmd0aC0xXT90aGlzLnNjYW5UZW1wbGF0ZSgpOmU+PTU1Mjk2JiZlPDU3MzQzJiZhLkNoYXJhY3Rlci5pc0lkZW50aWZpZXJTdGFydCh0aGlzLmNvZGVQb2ludEF0KHRoaXMuaW5kZXgpKT90aGlzLnNjYW5JZGVudGlmaWVyKCk6dGhpcy5zY2FuUHVuY3R1YXRvcigpfSxlfSgpO3QuU2Nhbm5lcj11fSxmdW5jdGlvbihlLHQpeyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5Ub2tlbk5hbWU9e30sdC5Ub2tlbk5hbWVbMV09IkJvb2xlYW4iLHQuVG9rZW5OYW1lWzJdPSI8ZW5kPiIsdC5Ub2tlbk5hbWVbM109IklkZW50aWZpZXIiLHQuVG9rZW5OYW1lWzRdPSJLZXl3b3JkIix0LlRva2VuTmFtZVs1XT0iTnVsbCIsdC5Ub2tlbk5hbWVbNl09Ik51bWVyaWMiLHQuVG9rZW5OYW1lWzddPSJQdW5jdHVhdG9yIix0LlRva2VuTmFtZVs4XT0iU3RyaW5nIix0LlRva2VuTmFtZVs5XT0iUmVndWxhckV4cHJlc3Npb24iLHQuVG9rZW5OYW1lWzEwXT0iVGVtcGxhdGUifSxmdW5jdGlvbihlLHQpeyJ1c2Ugc3RyaWN0IjtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSksdC5YSFRNTEVudGl0aWVzPXtxdW90OiciJyxhbXA6IiYiLGFwb3M6IiciLGd0OiI+IixuYnNwOiJceGEwIixpZXhjbDoiXHhhMSIsY2VudDoiXHhhMiIscG91bmQ6Ilx4YTMiLGN1cnJlbjoiXHhhNCIseWVuOiJceGE1IixicnZiYXI6Ilx4YTYiLHNlY3Q6Ilx4YTciLHVtbDoiXHhhOCIsY29weToiXHhhOSIsb3JkZjoiXHhhYSIsbGFxdW86Ilx4YWIiLG5vdDoiXHhhYyIsc2h5OiJceGFkIixyZWc6Ilx4YWUiLG1hY3I6Ilx4YWYiLGRlZzoiXHhiMCIscGx1c21uOiJceGIxIixzdXAyOiJceGIyIixzdXAzOiJceGIzIixhY3V0ZToiXHhiNCIsbWljcm86Ilx4YjUiLHBhcmE6Ilx4YjYiLG1pZGRvdDoiXHhiNyIsY2VkaWw6Ilx4YjgiLHN1cDE6Ilx4YjkiLG9yZG06Ilx4YmEiLHJhcXVvOiJceGJiIixmcmFjMTQ6Ilx4YmMiLGZyYWMxMjoiXHhiZCIsZnJhYzM0OiJceGJlIixpcXVlc3Q6Ilx4YmYiLEFncmF2ZToiXHhjMCIsQWFjdXRlOiJceGMxIixBY2lyYzoiXHhjMiIsQXRpbGRlOiJceGMzIixBdW1sOiJceGM0IixBcmluZzoiXHhjNSIsQUVsaWc6Ilx4YzYiLENjZWRpbDoiXHhjNyIsRWdyYXZlOiJceGM4IixFYWN1dGU6Ilx4YzkiLEVjaXJjOiJceGNhIixFdW1sOiJceGNiIixJZ3JhdmU6Ilx4Y2MiLElhY3V0ZToiXHhjZCIsSWNpcmM6Ilx4Y2UiLEl1bWw6Ilx4Y2YiLEVUSDoiXHhkMCIsTnRpbGRlOiJceGQxIixPZ3JhdmU6Ilx4ZDIiLE9hY3V0ZToiXHhkMyIsT2NpcmM6Ilx4ZDQiLE90aWxkZToiXHhkNSIsT3VtbDoiXHhkNiIsdGltZXM6Ilx4ZDciLE9zbGFzaDoiXHhkOCIsVWdyYXZlOiJceGQ5IixVYWN1dGU6Ilx4ZGEiLFVjaXJjOiJceGRiIixVdW1sOiJceGRjIixZYWN1dGU6Ilx4ZGQiLFRIT1JOOiJceGRlIixzemxpZzoiXHhkZiIsYWdyYXZlOiJceGUwIixhYWN1dGU6Ilx4ZTEiLGFjaXJjOiJceGUyIixhdGlsZGU6Ilx4ZTMiLGF1bWw6Ilx4ZTQiLGFyaW5nOiJceGU1IixhZWxpZzoiXHhlNiIsY2NlZGlsOiJceGU3IixlZ3JhdmU6Ilx4ZTgiLGVhY3V0ZToiXHhlOSIsZWNpcmM6Ilx4ZWEiLGV1bWw6Ilx4ZWIiLGlncmF2ZToiXHhlYyIsaWFjdXRlOiJceGVkIixpY2lyYzoiXHhlZSIsaXVtbDoiXHhlZiIsZXRoOiJceGYwIixudGlsZGU6Ilx4ZjEiLG9ncmF2ZToiXHhmMiIsb2FjdXRlOiJceGYzIixvY2lyYzoiXHhmNCIsb3RpbGRlOiJceGY1IixvdW1sOiJceGY2IixkaXZpZGU6Ilx4ZjciLG9zbGFzaDoiXHhmOCIsdWdyYXZlOiJceGY5Iix1YWN1dGU6Ilx4ZmEiLHVjaXJjOiJceGZiIix1dW1sOiJceGZjIix5YWN1dGU6Ilx4ZmQiLHRob3JuOiJceGZlIix5dW1sOiJceGZmIixPRWxpZzoiXHUwMTUyIixvZWxpZzoiXHUwMTUzIixTY2Fyb246Ilx1MDE2MCIsc2Nhcm9uOiJcdTAxNjEiLFl1bWw6Ilx1MDE3OCIsZm5vZjoiXHUwMTkyIixjaXJjOiJcdTAyYzYiLHRpbGRlOiJcdTAyZGMiLEFscGhhOiJcdTAzOTEiLEJldGE6Ilx1MDM5MiIsR2FtbWE6Ilx1MDM5MyIsRGVsdGE6Ilx1MDM5NCIsRXBzaWxvbjoiXHUwMzk1IixaZXRhOiJcdTAzOTYiLEV0YToiXHUwMzk3IixUaGV0YToiXHUwMzk4IixJb3RhOiJcdTAzOTkiLEthcHBhOiJcdTAzOWEiLExhbWJkYToiXHUwMzliIixNdToiXHUwMzljIixOdToiXHUwMzlkIixYaToiXHUwMzllIixPbWljcm9uOiJcdTAzOWYiLFBpOiJcdTAzYTAiLFJobzoiXHUwM2ExIixTaWdtYToiXHUwM2EzIixUYXU6Ilx1MDNhNCIsVXBzaWxvbjoiXHUwM2E1IixQaGk6Ilx1MDNhNiIsQ2hpOiJcdTAzYTciLFBzaToiXHUwM2E4IixPbWVnYToiXHUwM2E5IixhbHBoYToiXHUwM2IxIixiZXRhOiJcdTAzYjIiLGdhbW1hOiJcdTAzYjMiLGRlbHRhOiJcdTAzYjQiLGVwc2lsb246Ilx1MDNiNSIsemV0YToiXHUwM2I2IixldGE6Ilx1MDNiNyIsdGhldGE6Ilx1MDNiOCIsaW90YToiXHUwM2I5IixrYXBwYToiXHUwM2JhIixsYW1iZGE6Ilx1MDNiYiIsbXU6Ilx1MDNiYyIsbnU6Ilx1MDNiZCIseGk6Ilx1MDNiZSIsb21pY3JvbjoiXHUwM2JmIixwaToiXHUwM2MwIixyaG86Ilx1MDNjMSIsc2lnbWFmOiJcdTAzYzIiLHNpZ21hOiJcdTAzYzMiLHRhdToiXHUwM2M0Iix1cHNpbG9uOiJcdTAzYzUiLHBoaToiXHUwM2M2IixjaGk6Ilx1MDNjNyIscHNpOiJcdTAzYzgiLG9tZWdhOiJcdTAzYzkiLHRoZXRhc3ltOiJcdTAzZDEiLHVwc2loOiJcdTAzZDIiLHBpdjoiXHUwM2Q2IixlbnNwOiJcdTIwMDIiLGVtc3A6Ilx1MjAwMyIsdGhpbnNwOiJcdTIwMDkiLHp3bmo6Ilx1MjAwYyIsendqOiJcdTIwMGQiLGxybToiXHUyMDBlIixybG06Ilx1MjAwZiIsbmRhc2g6Ilx1MjAxMyIsbWRhc2g6Ilx1MjAxNCIsbHNxdW86Ilx1MjAxOCIscnNxdW86Ilx1MjAxOSIsc2JxdW86Ilx1MjAxYSIsbGRxdW86Ilx1MjAxYyIscmRxdW86Ilx1MjAxZCIsYmRxdW86Ilx1MjAxZSIsZGFnZ2VyOiJcdTIwMjAiLERhZ2dlcjoiXHUyMDIxIixidWxsOiJcdTIwMjIiLGhlbGxpcDoiXHUyMDI2IixwZXJtaWw6Ilx1MjAzMCIscHJpbWU6Ilx1MjAzMiIsUHJpbWU6Ilx1MjAzMyIsbHNhcXVvOiJcdTIwMzkiLHJzYXF1bzoiXHUyMDNhIixvbGluZToiXHUyMDNlIixmcmFzbDoiXHUyMDQ0IixldXJvOiJcdTIwYWMiLGltYWdlOiJcdTIxMTEiLHdlaWVycDoiXHUyMTE4IixyZWFsOiJcdTIxMWMiLHRyYWRlOiJcdTIxMjIiLGFsZWZzeW06Ilx1MjEzNSIsbGFycjoiXHUyMTkwIix1YXJyOiJcdTIxOTEiLHJhcnI6Ilx1MjE5MiIsZGFycjoiXHUyMTkzIixoYXJyOiJcdTIxOTQiLGNyYXJyOiJcdTIxYjUiLGxBcnI6Ilx1MjFkMCIsdUFycjoiXHUyMWQxIixyQXJyOiJcdTIxZDIiLGRBcnI6Ilx1MjFkMyIsaEFycjoiXHUyMWQ0Iixmb3JhbGw6Ilx1MjIwMCIscGFydDoiXHUyMjAyIixleGlzdDoiXHUyMjAzIixlbXB0eToiXHUyMjA1IixuYWJsYToiXHUyMjA3Iixpc2luOiJcdTIyMDgiLG5vdGluOiJcdTIyMDkiLG5pOiJcdTIyMGIiLHByb2Q6Ilx1MjIwZiIsc3VtOiJcdTIyMTEiLG1pbnVzOiJcdTIyMTIiLGxvd2FzdDoiXHUyMjE3IixyYWRpYzoiXHUyMjFhIixwcm9wOiJcdTIyMWQiLGluZmluOiJcdTIyMWUiLGFuZzoiXHUyMjIwIixhbmQ6Ilx1MjIyNyIsb3I6Ilx1MjIyOCIsY2FwOiJcdTIyMjkiLGN1cDoiXHUyMjJhIixpbnQ6Ilx1MjIyYiIsdGhlcmU0OiJcdTIyMzQiLHNpbToiXHUyMjNjIixjb25nOiJcdTIyNDUiLGFzeW1wOiJcdTIyNDgiLG5lOiJcdTIyNjAiLGVxdWl2OiJcdTIyNjEiLGxlOiJcdTIyNjQiLGdlOiJcdTIyNjUiLHN1YjoiXHUyMjgyIixzdXA6Ilx1MjI4MyIsbnN1YjoiXHUyMjg0IixzdWJlOiJcdTIyODYiLHN1cGU6Ilx1MjI4NyIsb3BsdXM6Ilx1MjI5NSIsb3RpbWVzOiJcdTIyOTciLHBlcnA6Ilx1MjJhNSIsc2RvdDoiXHUyMmM1IixsY2VpbDoiXHUyMzA4IixyY2VpbDoiXHUyMzA5IixsZmxvb3I6Ilx1MjMwYSIscmZsb29yOiJcdTIzMGIiLGxvejoiXHUyNWNhIixzcGFkZXM6Ilx1MjY2MCIsY2x1YnM6Ilx1MjY2MyIsaGVhcnRzOiJcdTI2NjUiLGRpYW1zOiJcdTI2NjYiLGxhbmc6Ilx1MjdlOCIscmFuZzoiXHUyN2U5In19LGZ1bmN0aW9uKGUsdCxuKXsidXNlIHN0cmljdCI7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsIl9fZXNNb2R1bGUiLHt2YWx1ZTohMH0pO3ZhciByPW4oMTApLGk9bigxMiksbz1uKDEzKSxhPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSgpe3RoaXMudmFsdWVzPVtdLHRoaXMuY3VybHk9dGhpcy5wYXJlbj0tMX1yZXR1cm4gZS5wcm90b3R5cGUuYmVmb3JlRnVuY3Rpb25FeHByZXNzaW9uPWZ1bmN0aW9uKGUpe3JldHVyblsiKCIsInsiLCJbIiwiaW4iLCJ0eXBlb2YiLCJpbnN0YW5jZW9mIiwibmV3IiwicmV0dXJuIiwiY2FzZSIsImRlbGV0ZSIsInRocm93Iiwidm9pZCIsIj0iLCIrPSIsIi09IiwiKj0iLCIqKj0iLCIvPSIsIiU9IiwiPDw9IiwiPj49IiwiPj4+PSIsIiY9IiwifD0iLCJePSIsIiwiLCIrIiwiLSIsIioiLCIqKiIsIi8iLCIlIiwiKysiLCItLSIsIjw8IiwiPj4iLCI+Pj4iLCImIiwifCIsIl4iLCIhIiwifiIsIiYmIiwifHwiLCI/IiwiOiIsIj09PSIsIj09IiwiPj0iLCI8PSIsIjwiLCI+IiwiIT0iLCIhPT0iXS5pbmRleE9mKGUpPj0wfSxlLnByb3RvdHlwZS5pc1JlZ2V4U3RhcnQ9ZnVuY3Rpb24oKXt2YXIgZT10aGlzLnZhbHVlc1t0aGlzLnZhbHVlcy5sZW5ndGgtMV0sdD1udWxsIT09ZTtzd2l0Y2goZSl7Y2FzZSJ0aGlzIjpjYXNlIl0iOnQ9ITE7YnJlYWs7Y2FzZSIpIjp2YXIgbj10aGlzLnZhbHVlc1t0aGlzLnBhcmVuLTFdO3Q9ImlmIj09PW58fCJ3aGlsZSI9PT1ufHwiZm9yIj09PW58fCJ3aXRoIj09PW47YnJlYWs7Y2FzZSJ9IjppZih0PSExLCJmdW5jdGlvbiI9PT10aGlzLnZhbHVlc1t0aGlzLmN1cmx5LTNdKXt2YXIgcj10aGlzLnZhbHVlc1t0aGlzLmN1cmx5LTRdO3Q9ISFyJiYhdGhpcy5iZWZvcmVGdW5jdGlvbkV4cHJlc3Npb24ocil9ZWxzZSBpZigiZnVuY3Rpb24iPT09dGhpcy52YWx1ZXNbdGhpcy5jdXJseS00XSl7dmFyIHI9dGhpcy52YWx1ZXNbdGhpcy5jdXJseS01XTt0PSFyfHwhdGhpcy5iZWZvcmVGdW5jdGlvbkV4cHJlc3Npb24ocil9fXJldHVybiB0fSxlLnByb3RvdHlwZS5wdXNoPWZ1bmN0aW9uKGUpezc9PT1lLnR5cGV8fDQ9PT1lLnR5cGU/KCJ7Ij09PWUudmFsdWU/dGhpcy5jdXJseT10aGlzLnZhbHVlcy5sZW5ndGg6IigiPT09ZS52YWx1ZSYmKHRoaXMucGFyZW49dGhpcy52YWx1ZXMubGVuZ3RoKSx0aGlzLnZhbHVlcy5wdXNoKGUudmFsdWUpKTp0aGlzLnZhbHVlcy5wdXNoKG51bGwpfSxlfSgpLHM9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKGUsdCl7dGhpcy5lcnJvckhhbmRsZXI9bmV3IHIuRXJyb3JIYW5kbGVyLHRoaXMuZXJyb3JIYW5kbGVyLnRvbGVyYW50PSEhdCYmKCJib29sZWFuIj09PXR5cGVvZiB0LnRvbGVyYW50JiZ0LnRvbGVyYW50KSx0aGlzLnNjYW5uZXI9bmV3IGkuU2Nhbm5lcihlLHRoaXMuZXJyb3JIYW5kbGVyKSx0aGlzLnNjYW5uZXIudHJhY2tDb21tZW50PSEhdCYmKCJib29sZWFuIj09PXR5cGVvZiB0LmNvbW1lbnQmJnQuY29tbWVudCksdGhpcy50cmFja1JhbmdlPSEhdCYmKCJib29sZWFuIj09PXR5cGVvZiB0LnJhbmdlJiZ0LnJhbmdlKSx0aGlzLnRyYWNrTG9jPSEhdCYmKCJib29sZWFuIj09PXR5cGVvZiB0LmxvYyYmdC5sb2MpLHRoaXMuYnVmZmVyPVtdLHRoaXMucmVhZGVyPW5ldyBhfXJldHVybiBlLnByb3RvdHlwZS5lcnJvcnM9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5lcnJvckhhbmRsZXIuZXJyb3JzfSxlLnByb3RvdHlwZS5nZXROZXh0VG9rZW49ZnVuY3Rpb24oKXtpZigwPT09dGhpcy5idWZmZXIubGVuZ3RoKXt2YXIgZT10aGlzLnNjYW5uZXIuc2NhbkNvbW1lbnRzKCk7aWYodGhpcy5zY2FubmVyLnRyYWNrQ29tbWVudClmb3IodmFyIHQ9MDt0PGUubGVuZ3RoOysrdCl7dmFyIG49ZVt0XSxyPXRoaXMuc2Nhbm5lci5zb3VyY2Uuc2xpY2Uobi5zbGljZVswXSxuLnNsaWNlWzFdKSxpPXt0eXBlOm4ubXVsdGlMaW5lPyJCbG9ja0NvbW1lbnQiOiJMaW5lQ29tbWVudCIsdmFsdWU6cn07dGhpcy50cmFja1JhbmdlJiYoaS5yYW5nZT1uLnJhbmdlKSx0aGlzLnRyYWNrTG9jJiYoaS5sb2M9bi5sb2MpLHRoaXMuYnVmZmVyLnB1c2goaSl9aWYoIXRoaXMuc2Nhbm5lci5lb2YoKSl7dmFyIGE9dm9pZCAwO3RoaXMudHJhY2tMb2MmJihhPXtzdGFydDp7bGluZTp0aGlzLnNjYW5uZXIubGluZU51bWJlcixjb2x1bW46dGhpcy5zY2FubmVyLmluZGV4LXRoaXMuc2Nhbm5lci5saW5lU3RhcnR9LGVuZDp7fX0pO3ZhciBzPSIvIj09PXRoaXMuc2Nhbm5lci5zb3VyY2VbdGhpcy5zY2FubmVyLmluZGV4XSYmdGhpcy5yZWFkZXIuaXNSZWdleFN0YXJ0KCksdT1zP3RoaXMuc2Nhbm5lci5zY2FuUmVnRXhwKCk6dGhpcy5zY2FubmVyLmxleCgpO3RoaXMucmVhZGVyLnB1c2godSk7dmFyIGM9e3R5cGU6by5Ub2tlbk5hbWVbdS50eXBlXSx2YWx1ZTp0aGlzLnNjYW5uZXIuc291cmNlLnNsaWNlKHUuc3RhcnQsdS5lbmQpfTtpZih0aGlzLnRyYWNrUmFuZ2UmJihjLnJhbmdlPVt1LnN0YXJ0LHUuZW5kXSksdGhpcy50cmFja0xvYyYmKGEuZW5kPXtsaW5lOnRoaXMuc2Nhbm5lci5saW5lTnVtYmVyLGNvbHVtbjp0aGlzLnNjYW5uZXIuaW5kZXgtdGhpcy5zY2FubmVyLmxpbmVTdGFydH0sYy5sb2M9YSksOT09PXUudHlwZSl7dmFyIGw9dS5wYXR0ZXJuLHA9dS5mbGFncztjLnJlZ2V4PXtwYXR0ZXJuOmwsZmxhZ3M6cH19dGhpcy5idWZmZXIucHVzaChjKX19cmV0dXJuIHRoaXMuYnVmZmVyLnNoaWZ0KCl9LGV9KCk7dC5Ub2tlbml6ZXI9c31dKX0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHIoZSx0KXt2YXIgbixyLGksbyxhLHMsdTtpZihudWxsPT09dClyZXR1cm57fTtmb3Iobj17fSxyPU9iamVjdC5rZXlzKHQpLGk9MCxvPXIubGVuZ3RoO2k8bztpKz0xKWE9cltpXSxzPVN0cmluZyh0W2FdKSwiISEiPT09YS5zbGljZSgwLDIpJiYoYT0idGFnOnlhbWwub3JnLDIwMDI6IithLnNsaWNlKDIpKSx1PWUuY29tcGlsZWRUeXBlTWFwLmZhbGxiYWNrW2FdLHUmJlAuY2FsbCh1LnN0eWxlQWxpYXNlcyxzKSYmKHM9dS5zdHlsZUFsaWFzZXNbc10pLG5bYV09cztyZXR1cm4gbn1mdW5jdGlvbiBpKGUpe3ZhciB0LG4scjtpZih0PWUudG9TdHJpbmcoMTYpLnRvVXBwZXJDYXNlKCksZTw9MjU1KW49IngiLHI9MjtlbHNlIGlmKGU8PTY1NTM1KW49InUiLHI9NDtlbHNle2lmKCEoZTw9NDI5NDk2NzI5NSkpdGhyb3cgbmV3IEYoImNvZGUgcG9pbnQgd2l0aGluIGEgc3RyaW5nIG1heSBub3QgYmUgZ3JlYXRlciB0aGFuIDB4RkZGRkZGRkYiKTtuPSJVIixyPTh9cmV0dXJuIlxcIituK08ucmVwZWF0KCIwIixyLXQubGVuZ3RoKSt0fWZ1bmN0aW9uIG8oZSl7dGhpcy5zY2hlbWE9ZS5zY2hlbWF8fE4sdGhpcy5pbmRlbnQ9TWF0aC5tYXgoMSxlLmluZGVudHx8MiksdGhpcy5za2lwSW52YWxpZD1lLnNraXBJbnZhbGlkfHwhMSx0aGlzLmZsb3dMZXZlbD1PLmlzTm90aGluZyhlLmZsb3dMZXZlbCk/LTE6ZS5mbG93TGV2ZWwsdGhpcy5zdHlsZU1hcD1yKHRoaXMuc2NoZW1hLGUuc3R5bGVzfHxudWxsKSx0aGlzLnNvcnRLZXlzPWUuc29ydEtleXN8fCExLHRoaXMubGluZVdpZHRoPWUubGluZVdpZHRofHw4MCx0aGlzLm5vUmVmcz1lLm5vUmVmc3x8ITEsdGhpcy5ub0NvbXBhdE1vZGU9ZS5ub0NvbXBhdE1vZGV8fCExLHRoaXMuY29uZGVuc2VGbG93PWUuY29uZGVuc2VGbG93fHwhMSx0aGlzLmltcGxpY2l0VHlwZXM9dGhpcy5zY2hlbWEuY29tcGlsZWRJbXBsaWNpdCx0aGlzLmV4cGxpY2l0VHlwZXM9dGhpcy5zY2hlbWEuY29tcGlsZWRFeHBsaWNpdCx0aGlzLnRhZz1udWxsLHRoaXMucmVzdWx0PSIiLHRoaXMuZHVwbGljYXRlcz1bXSx0aGlzLnVzZWREdXBsaWNhdGVzPW51bGx9ZnVuY3Rpb24gYShlLHQpe2Zvcih2YXIgbixyPU8ucmVwZWF0KCIgIix0KSxpPTAsbz0tMSxhPSIiLHM9ZS5sZW5ndGg7aTxzOylvPWUuaW5kZXhPZigiXG4iLGkpLC0xPT09bz8obj1lLnNsaWNlKGkpLGk9cyk6KG49ZS5zbGljZShpLG8rMSksaT1vKzEpLG4ubGVuZ3RoJiYiXG4iIT09biYmKGErPXIpLGErPW47cmV0dXJuIGF9ZnVuY3Rpb24gcyhlLHQpe3JldHVybiJcbiIrTy5yZXBlYXQoIiAiLGUuaW5kZW50KnQpfWZ1bmN0aW9uIHUoZSx0KXt2YXIgbixyLGk7Zm9yKG49MCxyPWUuaW1wbGljaXRUeXBlcy5sZW5ndGg7bjxyO24rPTEpaWYoaT1lLmltcGxpY2l0VHlwZXNbbl0saS5yZXNvbHZlKHQpKXJldHVybiEwO3JldHVybiExfWZ1bmN0aW9uIGMoZSl7cmV0dXJuIGU9PT1SfHxlPT09TX1mdW5jdGlvbiBsKGUpe3JldHVybiAzMjw9ZSYmZTw9MTI2fHwxNjE8PWUmJmU8PTU1Mjk1JiY4MjMyIT09ZSYmODIzMyE9PWV8fDU3MzQ0PD1lJiZlPD02NTUzMyYmNjUyNzkhPT1lfHw2NTUzNjw9ZSYmZTw9MTExNDExMX1mdW5jdGlvbiBwKGUpe3JldHVybiBsKGUpJiY2NTI3OSE9PWUmJmUhPT1IJiZlIT09WCYmZSE9PVomJmUhPT10ZSYmZSE9PXJlJiZlIT09USYmZSE9PVV9ZnVuY3Rpb24gZihlKXtyZXR1cm4gbChlKSYmNjUyNzkhPT1lJiYhYyhlKSYmZSE9PVcmJmUhPT1KJiZlIT09USYmZSE9PUgmJmUhPT1YJiZlIT09WiYmZSE9PXRlJiZlIT09cmUmJmUhPT1VJiZlIT09RyYmZSE9PXEmJmUhPT1CJiZlIT09bmUmJmUhPT1LJiZlIT09ViYmZSE9PSQmJmUhPT16JiZlIT09WSYmZSE9PWVlfWZ1bmN0aW9uIGQoZSx0LG4scixpKXt2YXIgbyxhLHM9ITEsdT0hMSxkPS0xIT09cixoPS0xLG09ZihlLmNoYXJDb2RlQXQoMCkpJiYhYyhlLmNoYXJDb2RlQXQoZS5sZW5ndGgtMSkpO2lmKHQpZm9yKG89MDtvPGUubGVuZ3RoO28rKyl7aWYoYT1lLmNoYXJDb2RlQXQobyksIWwoYSkpcmV0dXJuIGxlO209bSYmcChhKX1lbHNle2ZvcihvPTA7bzxlLmxlbmd0aDtvKyspe2lmKChhPWUuY2hhckNvZGVBdChvKSk9PT1qKXM9ITAsZCYmKHU9dXx8by1oLTE+ciYmIiAiIT09ZVtoKzFdLGg9byk7ZWxzZSBpZighbChhKSlyZXR1cm4gbGU7bT1tJiZwKGEpfXU9dXx8ZCYmby1oLTE+ciYmIiAiIT09ZVtoKzFdfXJldHVybiBzfHx1PyIgIj09PWVbMF0mJm4+OT9sZTp1P2NlOnVlOm0mJiFpKGUpP2FlOnNlfWZ1bmN0aW9uIGgoZSx0LG4scil7ZS5kdW1wPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gaSh0KXtyZXR1cm4gdShlLHQpfWlmKDA9PT10Lmxlbmd0aClyZXR1cm4iJyciO2lmKCFlLm5vQ29tcGF0TW9kZSYmLTEhPT1vZS5pbmRleE9mKHQpKXJldHVybiInIit0KyInIjt2YXIgbz1lLmluZGVudCpNYXRoLm1heCgxLG4pLHM9LTE9PT1lLmxpbmVXaWR0aD8tMTpNYXRoLm1heChNYXRoLm1pbihlLmxpbmVXaWR0aCw0MCksZS5saW5lV2lkdGgtbyksYz1yfHxlLmZsb3dMZXZlbD4tMSYmbj49ZS5mbG93TGV2ZWw7c3dpdGNoKGQodCxjLGUuaW5kZW50LHMsaSkpe2Nhc2UgYWU6cmV0dXJuIHQ7Y2FzZSBzZTpyZXR1cm4iJyIrdC5yZXBsYWNlKC8nL2csIicnIikrIiciO2Nhc2UgdWU6cmV0dXJuInwiK20odCxlLmluZGVudCkrZyhhKHQsbykpO2Nhc2UgY2U6cmV0dXJuIj4iK20odCxlLmluZGVudCkrZyhhKHkodCxzKSxvKSk7Y2FzZSBsZTpyZXR1cm4nIicrYih0KSsnIic7ZGVmYXVsdDp0aHJvdyBuZXcgRigiaW1wb3NzaWJsZSBlcnJvcjogaW52YWxpZCBzY2FsYXIgc3R5bGUiKX19KCl9ZnVuY3Rpb24gbShlLHQpe3ZhciBuPSIgIj09PWVbMF0/U3RyaW5nKHQpOiIiLHI9IlxuIj09PWVbZS5sZW5ndGgtMV07cmV0dXJuIG4rKCFyfHwiXG4iIT09ZVtlLmxlbmd0aC0yXSYmIlxuIiE9PWU/cj8iIjoiLSI6IisiKSsiXG4ifWZ1bmN0aW9uIGcoZSl7cmV0dXJuIlxuIj09PWVbZS5sZW5ndGgtMV0/ZS5zbGljZSgwLC0xKTplfWZ1bmN0aW9uIHkoZSx0KXtmb3IodmFyIG4scixpPS8oXG4rKShbXlxuXSopL2csbz1mdW5jdGlvbigpe3ZhciBuPWUuaW5kZXhPZigiXG4iKTtyZXR1cm4gbj0tMSE9PW4/bjplLmxlbmd0aCxpLmxhc3RJbmRleD1uLHYoZS5zbGljZSgwLG4pLHQpfSgpLGE9IlxuIj09PWVbMF18fCIgIj09PWVbMF07cj1pLmV4ZWMoZSk7KXt2YXIgcz1yWzFdLHU9clsyXTtuPSIgIj09PXVbMF0sbys9cysoYXx8bnx8IiI9PT11PyIiOiJcbiIpK3YodSx0KSxhPW59cmV0dXJuIG99ZnVuY3Rpb24gdihlLHQpe2lmKCIiPT09ZXx8IiAiPT09ZVswXSlyZXR1cm4gZTtmb3IodmFyIG4scixpPS8gW14gXS9nLG89MCxhPTAscz0wLHU9IiI7bj1pLmV4ZWMoZSk7KXM9bi5pbmRleCxzLW8+dCYmKHI9YT5vP2E6cyx1Kz0iXG4iK2Uuc2xpY2UobyxyKSxvPXIrMSksYT1zO3JldHVybiB1Kz0iXG4iLGUubGVuZ3RoLW8+dCYmYT5vP3UrPWUuc2xpY2UobyxhKSsiXG4iK2Uuc2xpY2UoYSsxKTp1Kz1lLnNsaWNlKG8pLHUuc2xpY2UoMSl9ZnVuY3Rpb24gYihlKXtmb3IodmFyIHQsbixyLG89IiIsYT0wO2E8ZS5sZW5ndGg7YSsrKXQ9ZS5jaGFyQ29kZUF0KGEpLHQ+PTU1Mjk2JiZ0PD01NjMxOSYmKG49ZS5jaGFyQ29kZUF0KGErMSkpPj01NjMyMCYmbjw9NTczNDM/KG8rPWkoMTAyNCoodC01NTI5Nikrbi01NjMyMCs2NTUzNiksYSsrKToocj1pZVt0XSxvKz0hciYmbCh0KT9lW2FdOnJ8fGkodCkpO3JldHVybiBvfWZ1bmN0aW9uIHgoZSx0LG4pe3ZhciByLGksbz0iIixhPWUudGFnO2ZvcihyPTAsaT1uLmxlbmd0aDtyPGk7cis9MSlTKGUsdCxuW3JdLCExLCExKSYmKDAhPT1yJiYobys9IiwiKyhlLmNvbmRlbnNlRmxvdz8iIjoiICIpKSxvKz1lLmR1bXApO2UudGFnPWEsZS5kdW1wPSJbIitvKyJdIn1mdW5jdGlvbiBDKGUsdCxuLHIpe3ZhciBpLG8sYT0iIix1PWUudGFnO2ZvcihpPTAsbz1uLmxlbmd0aDtpPG87aSs9MSlTKGUsdCsxLG5baV0sITAsITApJiYociYmMD09PWl8fChhKz1zKGUsdCkpLGUuZHVtcCYmaj09PWUuZHVtcC5jaGFyQ29kZUF0KDApP2ErPSItIjphKz0iLSAiLGErPWUuZHVtcCk7ZS50YWc9dSxlLmR1bXA9YXx8IltdIn1mdW5jdGlvbiBFKGUsdCxuKXt2YXIgcixpLG8sYSxzLHU9IiIsYz1lLnRhZyxsPU9iamVjdC5rZXlzKG4pO2ZvcihyPTAsaT1sLmxlbmd0aDtyPGk7cis9MSlzPWUuY29uZGVuc2VGbG93PyciJzoiIiwwIT09ciYmKHMrPSIsICIpLG89bFtyXSxhPW5bb10sUyhlLHQsbywhMSwhMSkmJihlLmR1bXAubGVuZ3RoPjEwMjQmJihzKz0iPyAiKSxzKz1lLmR1bXArKGUuY29uZGVuc2VGbG93PyciJzoiIikrIjoiKyhlLmNvbmRlbnNlRmxvdz8iIjoiICIpLFMoZSx0LGEsITEsITEpJiYocys9ZS5kdW1wLHUrPXMpKTtlLnRhZz1jLGUuZHVtcD0ieyIrdSsifSJ9ZnVuY3Rpb24gRChlLHQsbixyKXt2YXIgaSxvLGEsdSxjLGwscD0iIixmPWUudGFnLGQ9T2JqZWN0LmtleXMobik7aWYoITA9PT1lLnNvcnRLZXlzKWQuc29ydCgpO2Vsc2UgaWYoImZ1bmN0aW9uIj09PXR5cGVvZiBlLnNvcnRLZXlzKWQuc29ydChlLnNvcnRLZXlzKTtlbHNlIGlmKGUuc29ydEtleXMpdGhyb3cgbmV3IEYoInNvcnRLZXlzIG11c3QgYmUgYSBib29sZWFuIG9yIGEgZnVuY3Rpb24iKTtmb3IoaT0wLG89ZC5sZW5ndGg7aTxvO2krPTEpbD0iIixyJiYwPT09aXx8KGwrPXMoZSx0KSksYT1kW2ldLHU9blthXSxTKGUsdCsxLGEsITAsITAsITApJiYoYz1udWxsIT09ZS50YWcmJiI/IiE9PWUudGFnfHxlLmR1bXAmJmUuZHVtcC5sZW5ndGg+MTAyNCxjJiYoZS5kdW1wJiZqPT09ZS5kdW1wLmNoYXJDb2RlQXQoMCk/bCs9Ij8iOmwrPSI/ICIpLGwrPWUuZHVtcCxjJiYobCs9cyhlLHQpKSxTKGUsdCsxLHUsITAsYykmJihlLmR1bXAmJmo9PT1lLmR1bXAuY2hhckNvZGVBdCgwKT9sKz0iOiI6bCs9IjogIixsKz1lLmR1bXAscCs9bCkpO2UudGFnPWYsZS5kdW1wPXB8fCJ7fSJ9ZnVuY3Rpb24gdyhlLHQsbil7dmFyIHIsaSxvLGEscyx1O2ZvcihpPW4/ZS5leHBsaWNpdFR5cGVzOmUuaW1wbGljaXRUeXBlcyxvPTAsYT1pLmxlbmd0aDtvPGE7bys9MSlpZihzPWlbb10sKHMuaW5zdGFuY2VPZnx8cy5wcmVkaWNhdGUpJiYoIXMuaW5zdGFuY2VPZnx8Im9iamVjdCI9PT10eXBlb2YgdCYmdCBpbnN0YW5jZW9mIHMuaW5zdGFuY2VPZikmJighcy5wcmVkaWNhdGV8fHMucHJlZGljYXRlKHQpKSl7aWYoZS50YWc9bj9zLnRhZzoiPyIscy5yZXByZXNlbnQpe2lmKHU9ZS5zdHlsZU1hcFtzLnRhZ118fHMuZGVmYXVsdFN0eWxlLCJbb2JqZWN0IEZ1bmN0aW9uXSI9PT1MLmNhbGwocy5yZXByZXNlbnQpKXI9cy5yZXByZXNlbnQodCx1KTtlbHNle2lmKCFQLmNhbGwocy5yZXByZXNlbnQsdSkpdGhyb3cgbmV3IEYoIiE8IitzLnRhZysnPiB0YWcgcmVzb2x2ZXIgYWNjZXB0cyBub3QgIicrdSsnIiBzdHlsZScpO3I9cy5yZXByZXNlbnRbdV0odCx1KX1lLmR1bXA9cn1yZXR1cm4hMH1yZXR1cm4hMX1mdW5jdGlvbiBTKGUsdCxuLHIsaSxvKXtlLnRhZz1udWxsLGUuZHVtcD1uLHcoZSxuLCExKXx8dyhlLG4sITApO3ZhciBhPUwuY2FsbChlLmR1bXApO3ImJihyPWUuZmxvd0xldmVsPDB8fGUuZmxvd0xldmVsPnQpO3ZhciBzLHUsYz0iW29iamVjdCBPYmplY3RdIj09PWF8fCJbb2JqZWN0IEFycmF5XSI9PT1hO2lmKGMmJihzPWUuZHVwbGljYXRlcy5pbmRleE9mKG4pLHU9LTEhPT1zKSwobnVsbCE9PWUudGFnJiYiPyIhPT1lLnRhZ3x8dXx8MiE9PWUuaW5kZW50JiZ0PjApJiYoaT0hMSksdSYmZS51c2VkRHVwbGljYXRlc1tzXSllLmR1bXA9IipyZWZfIitzO2Vsc2V7aWYoYyYmdSYmIWUudXNlZER1cGxpY2F0ZXNbc10mJihlLnVzZWREdXBsaWNhdGVzW3NdPSEwKSwiW29iamVjdCBPYmplY3RdIj09PWEpciYmMCE9PU9iamVjdC5rZXlzKGUuZHVtcCkubGVuZ3RoPyhEKGUsdCxlLmR1bXAsaSksdSYmKGUuZHVtcD0iJnJlZl8iK3MrZS5kdW1wKSk6KEUoZSx0LGUuZHVtcCksdSYmKGUuZHVtcD0iJnJlZl8iK3MrIiAiK2UuZHVtcCkpO2Vsc2UgaWYoIltvYmplY3QgQXJyYXldIj09PWEpciYmMCE9PWUuZHVtcC5sZW5ndGg/KEMoZSx0LGUuZHVtcCxpKSx1JiYoZS5kdW1wPSImcmVmXyIrcytlLmR1bXApKTooeChlLHQsZS5kdW1wKSx1JiYoZS5kdW1wPSImcmVmXyIrcysiICIrZS5kdW1wKSk7ZWxzZXtpZigiW29iamVjdCBTdHJpbmddIiE9PWEpe2lmKGUuc2tpcEludmFsaWQpcmV0dXJuITE7dGhyb3cgbmV3IEYoInVuYWNjZXB0YWJsZSBraW5kIG9mIGFuIG9iamVjdCB0byBkdW1wICIrYSl9Ij8iIT09ZS50YWcmJmgoZSxlLmR1bXAsdCxvKX1udWxsIT09ZS50YWcmJiI/IiE9PWUudGFnJiYoZS5kdW1wPSIhPCIrZS50YWcrIj4gIitlLmR1bXApfXJldHVybiEwfWZ1bmN0aW9uIGsoZSx0KXt2YXIgbixyLGk9W10sbz1bXTtmb3IoQShlLGksbyksbj0wLHI9by5sZW5ndGg7bjxyO24rPTEpdC5kdXBsaWNhdGVzLnB1c2goaVtvW25dXSk7dC51c2VkRHVwbGljYXRlcz1uZXcgQXJyYXkocil9ZnVuY3Rpb24gQShlLHQsbil7dmFyIHIsaSxvO2lmKG51bGwhPT1lJiYib2JqZWN0Ij09PXR5cGVvZiBlKWlmKC0xIT09KGk9dC5pbmRleE9mKGUpKSktMT09PW4uaW5kZXhPZihpKSYmbi5wdXNoKGkpO2Vsc2UgaWYodC5wdXNoKGUpLEFycmF5LmlzQXJyYXkoZSkpZm9yKGk9MCxvPWUubGVuZ3RoO2k8bztpKz0xKUEoZVtpXSx0LG4pO2Vsc2UgZm9yKHI9T2JqZWN0LmtleXMoZSksaT0wLG89ci5sZW5ndGg7aTxvO2krPTEpQShlW3JbaV1dLHQsbil9ZnVuY3Rpb24gXyhlLHQpe3Q9dHx8e307dmFyIG49bmV3IG8odCk7cmV0dXJuIG4ubm9SZWZzfHxrKGUsbiksUyhuLDAsZSwhMCwhMCk/bi5kdW1wKyJcbiI6IiJ9ZnVuY3Rpb24gVChlLHQpe3JldHVybiBfKGUsTy5leHRlbmQoe3NjaGVtYTpJfSx0KSl9dmFyIE89big1MiksRj1uKDcyKSxOPW4oOTgpLEk9big3MyksTD1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLFA9T2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eSxNPTksaj0xMCxSPTMyLEI9MzMsJD0zNCxVPTM1LHo9MzcsRz0zOCxWPTM5LHE9NDIsSD00NCxXPTQ1LFE9NTgsSz02MixKPTYzLFk9NjQsWD05MSxaPTkzLGVlPTk2LHRlPTEyMyxuZT0xMjQscmU9MTI1LGllPXt9O2llWzBdPSJcXDAiLGllWzddPSJcXGEiLGllWzhdPSJcXGIiLGllWzldPSJcXHQiLGllWzEwXT0iXFxuIixpZVsxMV09IlxcdiIsaWVbMTJdPSJcXGYiLGllWzEzXT0iXFxyIixpZVsyN109IlxcZSIsaWVbMzRdPSdcXCInLGllWzkyXT0iXFxcXCIsaWVbMTMzXT0iXFxOIixpZVsxNjBdPSJcXF8iLGllWzgyMzJdPSJcXEwiLGllWzgyMzNdPSJcXFAiO3ZhciBvZT1bInkiLCJZIiwieWVzIiwiWWVzIiwiWUVTIiwib24iLCJPbiIsIk9OIiwibiIsIk4iLCJubyIsIk5vIiwiTk8iLCJvZmYiLCJPZmYiLCJPRkYiXSxhZT0xLHNlPTIsdWU9MyxjZT00LGxlPTU7ZS5leHBvcnRzLmR1bXA9XyxlLmV4cG9ydHMuc2FmZUR1bXA9VH0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1mdW5jdGlvbigpe3ZhciBlPWZ1bmN0aW9uKHQsbil7cmV0dXJuKGU9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKGUsdCl7ZS5fX3Byb3RvX189dH18fGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciBuIGluIHQpdC5oYXNPd25Qcm9wZXJ0eShuKSYmKGVbbl09dFtuXSl9KSh0LG4pfTtyZXR1cm4gZnVuY3Rpb24odCxuKXtmdW5jdGlvbiByKCl7dGhpcy5jb25zdHJ1Y3Rvcj10fWUodCxuKSx0LnByb3RvdHlwZT1udWxsPT09bj9PYmplY3QuY3JlYXRlKG4pOihyLnByb3RvdHlwZT1uLnByb3RvdHlwZSxuZXcgcil9fSgpLGk9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5P09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJyYXciLHt2YWx1ZTp0fSk6ZS5yYXc9dCxlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIG89bigwKSxhPW4oNzQ5KSxzPW4oMjQpLHU9bigxKSxjPW4oMTQ3KSxsPW4oOCkscD1uKDkpLGY9bigxNyksZD1uKDMwMSksaD1uKDE2KSxtPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gbnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzfXJldHVybiByKHQsZSksdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcyx0PXRoaXMucHJvcHMsbj10LmNvbmZpZyxyPXQuZm9sZGVyTmFtZSxpPXQub25OZXdXb3Jrc3BhY2UsYT10LmlzRWxlY3Ryb24sdT1uLmV4dGVuc2lvbnMmJm4uZXh0ZW5zaW9ucy5lbmRwb2ludHMsYz1uLnByb2plY3RzO3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoUyxudWxsLG8uY3JlYXRlRWxlbWVudChrLHtpc0VsZWN0cm9uOmF9LG8uY3JlYXRlRWxlbWVudChfLG51bGwsby5jcmVhdGVFbGVtZW50KEEsbnVsbCxyKSxvLmNyZWF0ZUVsZW1lbnQocy5TZXR0aW5nc0ljb24se3dpZHRoOjE4LGhlaWdodDoxOCxvbkNsaWNrOnRoaXMucHJvcHMub3BlbkNvbmZpZ1RhYix0aXRsZToiUHJvamVjdCBzZXR0aW5ncyJ9KSksdSYmdGhpcy5yZW5kZXJFbmRwb2ludHModSksYyYmT2JqZWN0LmtleXMoYykubWFwKGZ1bmN0aW9uKHQpe3ZhciBuPWNbdF0scj1uLmV4dGVuc2lvbnMmJm4uZXh0ZW5zaW9ucy5lbmRwb2ludHM7cmV0dXJuIHI/by5jcmVhdGVFbGVtZW50KFQse2tleTp0fSxvLmNyZWF0ZUVsZW1lbnQoTyxudWxsLHQpLGUucmVuZGVyRW5kcG9pbnRzKHIsdCkpOm51bGx9KSksYSYmby5jcmVhdGVFbGVtZW50KEYsbnVsbCxvLmNyZWF0ZUVsZW1lbnQoTix7b25DbGljazppfSxvLmNyZWF0ZUVsZW1lbnQocy5BZGRGdWxsSWNvbix7d2lkdGg6MTQsaGVpZ2h0OjE0LHN0cm9rZVdpZHRoOjZ9KSwiTkVXIFdPUktTUEFDRSIpKSl9LHQucHJvdG90eXBlLnJlbmRlckVuZHBvaW50cz1mdW5jdGlvbihlLHQpe3ZhciBuPXRoaXM7cmV0dXJuIE9iamVjdC5rZXlzKGUpLm1hcChmdW5jdGlvbihyKXt2YXIgaT1jLmdldEVuZHBvaW50RnJvbUVuZHBvaW50Q29uZmlnKGVbcl0pLmVuZHBvaW50LHM9bi5wcm9wcy5jb3VudHMuZ2V0KGQuZ2V0V29ya3NwYWNlSWQoe2VuZHBvaW50OmksY29uZmlnUGF0aDpuLnByb3BzLmNvbmZpZ1BhdGgsd29ya3NwYWNlTmFtZTp0fSkpfHwxO3JldHVybiBvLmNyZWF0ZUVsZW1lbnQoYS5kZWZhdWx0LHtrZXk6cixlbnY6cixvblNlbGVjdEVudjpuLnByb3BzLm9uU2VsZWN0RW52LGFjdGl2ZUVudjpuLnByb3BzLmFjdGl2ZUVudixjb3VudDpzLGRlZXA6Qm9vbGVhbih0KSxwcm9qZWN0TmFtZTp0LGFjdGl2ZVByb2plY3ROYW1lOm4ucHJvcHMuYWN0aXZlUHJvamVjdE5hbWV9KX0pfSx0fShvLkNvbXBvbmVudCksZz1sLmNyZWF0ZVN0cnVjdHVyZWRTZWxlY3Rvcih7Y291bnRzOmYuZ2V0U2Vzc2lvbkNvdW50c30pO3QuZGVmYXVsdD1wLmNvbm5lY3QoZyx7b3BlbkNvbmZpZ1RhYjpoLm9wZW5Db25maWdUYWJ9KShtKTt2YXIgeSx2LGIseCxDLEUsRCx3LFM9dS5zdHlsZWQuZGl2KHl8fCh5PWkoWyJcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGZsZXgtYmFzaXM6IDIyMnB4O1xuICBjb2xvcjogIiwiO1xuICBib3JkZXItcmlnaHQ6IDZweCBzb2xpZCAiLCI7XG4iXSxbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgZmxleC1iYXNpczogMjIycHg7XG4gIGNvbG9yOiAiLCI7XG4gIGJvcmRlci1yaWdodDogNnB4IHNvbGlkICIsIjtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5zaWRlYmFyfSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnRleHR9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuYmFja2dyb3VuZH0pLGs9dS5zdHlsZWQuZGl2KHZ8fCh2PWkoWyJcbiAgLXdlYmtpdC1hcHAtcmVnaW9uOiBkcmFnO1xuICBwYWRkaW5nLXRvcDogIiwicHg7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdLFsiXG4gIC13ZWJraXQtYXBwLXJlZ2lvbjogZHJhZztcbiAgcGFkZGluZy10b3A6ICIsInB4O1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmlzRWxlY3Ryb24/NDg6MjB9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuc2lkZWJhclRvcH0pLEE9dS5zdHlsZWQuZGl2KGJ8fChiPWkoWyJcbiAgZm9udC1zaXplOiAxNnB4O1xuICBmb250LXdlaWdodDogNjAwO1xuICBjb2xvcjogIiwiO1xuICB3b3JkLWJyZWFrOiBicmVhay13b3JkO1xuIl0sWyJcbiAgZm9udC1zaXplOiAxNnB4O1xuICBmb250LXdlaWdodDogNjAwO1xuICBjb2xvcjogIiwiO1xuICB3b3JkLWJyZWFrOiBicmVhay13b3JkO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnRleHR9KSxfPXUuc3R5bGVkLmRpdih4fHwoeD1pKFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogc3BhY2UtZXZlbmx5O1xuICBtYXJnaW46IDAgMTVweCAyMHB4IDE1cHg7XG4gIHN2ZyB7XG4gICAgbWluLXdpZHRoOiAxOHB4O1xuICAgIG1pbi1oZWlnaHQ6IDE4cHg7XG4gICAgY3Vyc29yOiBwb2ludGVyO1xuICAgIGZpbGw6ICIsIjtcbiAgICB0cmFuc2l0aW9uOiAwLjFzIGxpbmVhciBmaWxsO1xuICB9XG4gICY6aG92ZXIge1xuICAgIHN2ZyB7XG4gICAgICBmaWxsOiAiLCI7XG4gICAgfVxuICB9XG4iXSxbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWV2ZW5seTtcbiAgbWFyZ2luOiAwIDE1cHggMjBweCAxNXB4O1xuICBzdmcge1xuICAgIG1pbi13aWR0aDogMThweDtcbiAgICBtaW4taGVpZ2h0OiAxOHB4O1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICBmaWxsOiAiLCI7XG4gICAgdHJhbnNpdGlvbjogMC4xcyBsaW5lYXIgZmlsbDtcbiAgfVxuICAmOmhvdmVyIHtcbiAgICBzdmcge1xuICAgICAgZmlsbDogIiwiO1xuICAgIH1cbiAgfVxuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLmljb259LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuaWNvbkhvdmVyfSksVD11LnN0eWxlZC5kaXYoQ3x8KEM9aShbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICAmICsgJiB7XG4gICAgbWFyZ2luLXRvcDogMTJweDtcbiAgfVxuICAmOmxhc3QtY2hpbGQge1xuICAgIG1hcmdpbi1ib3R0b206IDMycHg7XG4gIH1cbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICYgKyAmIHtcbiAgICBtYXJnaW4tdG9wOiAxMnB4O1xuICB9XG4gICY6bGFzdC1jaGlsZCB7XG4gICAgbWFyZ2luLWJvdHRvbTogMzJweDtcbiAgfVxuIl0pKSksTz11LnN0eWxlZC5kaXYoRXx8KEU9aShbIlxuICBmb250LXNpemU6IDE0cHg7XG4gIGNvbG9yOiAiLCI7XG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIGxldHRlci1zcGFjaW5nOiAwLjUzcHg7XG4gIG1hcmdpbjogMCAxMHB4IDZweCAzMHB4O1xuICB3b3JkLWJyZWFrOiBicmVhay13b3JkO1xuIl0sWyJcbiAgZm9udC1zaXplOiAxNHB4O1xuICBjb2xvcjogIiwiO1xuICBmb250LXdlaWdodDogNjAwO1xuICBsZXR0ZXItc3BhY2luZzogMC41M3B4O1xuICBtYXJnaW46IDAgMTBweCA2cHggMzBweDtcbiAgd29yZC1icmVhazogYnJlYWstd29yZDtcbiJdKSksZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy50ZXh0fSksRj11LnN0eWxlZC5kaXYoRHx8KEQ9aShbIlxuICBkaXNwbGF5OiBmbGV4O1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgbWFyZ2luOiAzMnB4IDA7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiJdLFsiXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBtYXJnaW46IDMycHggMDtcbiAgYmFja2dyb3VuZDogIiwiO1xuIl0pKSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnNpZGViYXJCb3R0b219KSxOPXUuc3R5bGVkLmJ1dHRvbih3fHwodz1pKFsiXG4gIHBhZGRpbmc6IDEwcHg7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGJvcmRlci1yYWRpdXM6IDJweDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBmb250LXNpemU6IDE0cHg7XG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIGxldHRlci1zcGFjaW5nOiAwLjUzcHg7XG4gIGNvbG9yOiAiLCI7XG4gIGJhY2tncm91bmQtY29sb3I6ICIsIjtcbiAgdHJhbnNpdGlvbjogMC4xcyBsaW5lYXIgYWxsO1xuICAmOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAiLCI7XG4gIH1cbiAgaSB7XG4gICAgbWFyZ2luLXJpZ2h0OiA2cHg7XG4gIH1cbiAgc3ZnIHtcbiAgICBtaW4td2lkdGg6IDE4cHg7XG4gICAgbWluLWhlaWdodDogMThweDtcbiAgICBzdHJva2U6ICIsIjtcbiAgfVxuIl0sWyJcbiAgcGFkZGluZzogMTBweDtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgYm9yZGVyLXJhZGl1czogMnB4O1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgbGV0dGVyLXNwYWNpbmc6IDAuNTNweDtcbiAgY29sb3I6ICIsIjtcbiAgYmFja2dyb3VuZC1jb2xvcjogIiwiO1xuICB0cmFuc2l0aW9uOiAwLjFzIGxpbmVhciBhbGw7XG4gICY6aG92ZXIge1xuICAgIGJhY2tncm91bmQtY29sb3I6ICIsIjtcbiAgfVxuICBpIHtcbiAgICBtYXJnaW4tcmlnaHQ6IDZweDtcbiAgfVxuICBzdmcge1xuICAgIG1pbi13aWR0aDogMThweDtcbiAgICBtaW4taGVpZ2h0OiAxOHB4O1xuICAgIHN0cm9rZTogIiwiO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuYnV0dG9uV29ya3NwYWNlVGV4dH0sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy5idXR0b25Xb3Jrc3BhY2V9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuYnV0dG9uV29ya3NwYWNlSG92ZXJ9LGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuYnV0dG9uV29ya3NwYWNlVGV4dH0pfSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbihlLHQpe3JldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydHk/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsInJhdyIse3ZhbHVlOnR9KTplLnJhdz10LGV9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9bigxKSxzPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXt2YXIgdD1udWxsIT09ZSYmZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fHRoaXM7cmV0dXJuIHQuc2VsZWN0RW5kcG9pbnQ9ZnVuY3Rpb24oKXt0LnByb3BzLm9uU2VsZWN0RW52KHQucHJvcHMuZW52LHQucHJvcHMucHJvamVjdE5hbWUpfSx0fXJldHVybiByKHQsZSksdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIGU9dGhpcy5wcm9wcyx0PWUuZW52LG49ZS5hY3RpdmVFbnYscj1lLmNvdW50LGk9ZS5kZWVwLGE9ZS5hY3RpdmVQcm9qZWN0TmFtZSxzPWUucHJvamVjdE5hbWUsdT1uPT09dCYmYT09PXM7cmV0dXJuIG8uY3JlYXRlRWxlbWVudChsLHthY3RpdmU6dSxkZWVwOmksb25DbGljazp0aGlzLnNlbGVjdEVuZHBvaW50fSxvLmNyZWF0ZUVsZW1lbnQoInNwYW4iLG51bGwsdCksby5jcmVhdGVFbGVtZW50KHAse2FjdGl2ZTp1fSxyKSl9LHR9KG8uQ29tcG9uZW50KTt0LmRlZmF1bHQ9czt2YXIgdSxjLGw9YS5zdHlsZWQoImRpdiIpKHV8fCh1PWkoWyJcbiAgcGFkZGluZzogMTBweCAxMHB4IDEwcHggIiwiO1xuICB3b3JkLWJyZWFrOiBicmVhay13b3JkO1xuICBmb250LXdlaWdodDogNjAwO1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGZvbnQtc2l6ZTogMTJweDtcbiAgZGlzcGxheTogZmxleDtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBiYWNrZ3JvdW5kOiAiLCI7XG4gIGJvcmRlci1sZWZ0OiA0cHggc29saWRcbiAgICAiLCI7XG4gIGJvcmRlci1yYWRpdXM6IDJweDtcblxuICAmOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kOiAiLCI7XG4gIH1cbiJdLFsiXG4gIHBhZGRpbmc6IDEwcHggMTBweCAxMHB4ICIsIjtcbiAgd29yZC1icmVhazogYnJlYWstd29yZDtcbiAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBmb250LXNpemU6IDEycHg7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgYmFja2dyb3VuZDogIiwiO1xuICBib3JkZXItbGVmdDogNHB4IHNvbGlkXG4gICAgIiwiO1xuICBib3JkZXItcmFkaXVzOiAycHg7XG5cbiAgJjpob3ZlciB7XG4gICAgYmFja2dyb3VuZDogIiwiO1xuICB9XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLmRlZXA/IjQzcHgiOiIzOHB4In0sZnVuY3Rpb24oZSl7cmV0dXJuIGUuYWN0aXZlP2UudGhlbWUuZWRpdG9yQ29sb3Vycy5zaWRlYmFySXRlbUFjdGl2ZToidHJhbnNwYXJlbnQifSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hY3RpdmU/ZS50aGVtZS5lZGl0b3JDb2xvdXJzLnNpZGViYXJJdGVtU2lkZToidHJhbnNwYXJlbnQifSxmdW5jdGlvbihlKXtyZXR1cm4gZS50aGVtZS5lZGl0b3JDb2xvdXJzLnNpZGViYXJJdGVtQWN0aXZlfSkscD1hLnN0eWxlZCgiZGl2IikoY3x8KGM9aShbIlxuICBib3JkZXItcmFkaXVzOiA2cHg7XG4gIG1pbi13aWR0aDogMThweDtcbiAgbWluLWhlaWdodDogMThweDtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGZvbnQtc2l6ZTogMTFweDtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgY29sb3I6ICIsIjtcbiAgb3BhY2l0eTogIiwiO1xuICB0cmFuc2l0aW9uOiAwLjFzIGxpbmVhciBhbGw7XG4iXSxbIlxuICBib3JkZXItcmFkaXVzOiA2cHg7XG4gIG1pbi13aWR0aDogMThweDtcbiAgbWluLWhlaWdodDogMThweDtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGZvbnQtc2l6ZTogMTFweDtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG4gIGJhY2tncm91bmQ6ICIsIjtcbiAgY29sb3I6ICIsIjtcbiAgb3BhY2l0eTogIiwiO1xuICB0cmFuc2l0aW9uOiAwLjFzIGxpbmVhciBhbGw7XG4iXSkpLGZ1bmN0aW9uKGUpe3JldHVybiBlLnRoZW1lLmVkaXRvckNvbG91cnMuc2lkZWJhckl0ZW1TZXNzaW9uc30sZnVuY3Rpb24oZSl7cmV0dXJuIGUudGhlbWUuZWRpdG9yQ29sb3Vycy50ZXh0fSxmdW5jdGlvbihlKXtyZXR1cm4gZS5hY3RpdmU/MTouNn0pfSxmdW5jdGlvbihlLHQpe30sLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLGZ1bmN0aW9uKGUsdCxuKXtuKDMwOSksZS5leHBvcnRzPW4oNzk1KX0sZnVuY3Rpb24oZSx0LG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1PYmplY3QuYXNzaWdufHxmdW5jdGlvbihlKXtmb3IodmFyIHQ9MTt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKXt2YXIgbj1hcmd1bWVudHNbdF07Zm9yKHZhciByIGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4scikmJihlW3JdPW5bcl0pfXJldHVybiBlfTtPYmplY3QuZGVmaW5lUHJvcGVydHkodCwiX19lc01vZHVsZSIse3ZhbHVlOiEwfSk7dmFyIGk9bigwKSxvPW4oMzApLGE9big3OTYpO24oNzUwKSx3aW5kb3cuR3JhcGhRTFBsYXlncm91bmQ9e2luaXQ6ZnVuY3Rpb24oZSx0KXtvLnJlbmRlcihpLmNyZWF0ZUVsZW1lbnQoYS5kZWZhdWx0LHIoe3NldFRpdGxlOiEwLHNob3dOZXdXb3Jrc3BhY2U6ITF9LHQpKSxlKX19fSxmdW5jdGlvbihlLHQsbil7InVzZSBzdHJpY3QiO3ZhciByPWZ1bmN0aW9uKCl7dmFyIGU9ZnVuY3Rpb24odCxuKXtyZXR1cm4oZT1PYmplY3Quc2V0UHJvdG90eXBlT2Z8fHtfX3Byb3RvX186W119aW5zdGFuY2VvZiBBcnJheSYmZnVuY3Rpb24oZSx0KXtlLl9fcHJvdG9fXz10fXx8ZnVuY3Rpb24oZSx0KXtmb3IodmFyIG4gaW4gdCl0Lmhhc093blByb3BlcnR5KG4pJiYoZVtuXT10W25dKX0pKHQsbil9O3JldHVybiBmdW5jdGlvbih0LG4pe2Z1bmN0aW9uIHIoKXt0aGlzLmNvbnN0cnVjdG9yPXR9ZSh0LG4pLHQucHJvdG90eXBlPW51bGw9PT1uP09iamVjdC5jcmVhdGUobik6KHIucHJvdG90eXBlPW4ucHJvdG90eXBlLG5ldyByKX19KCksaT1mdW5jdGlvbigpe3JldHVybiBpPU9iamVjdC5hc3NpZ258fGZ1bmN0aW9uKGUpe2Zvcih2YXIgdCxuPTEscj1hcmd1bWVudHMubGVuZ3RoO248cjtuKyspe3Q9YXJndW1lbnRzW25dO2Zvcih2YXIgaSBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LGkpJiYoZVtpXT10W2ldKX1yZXR1cm4gZX0saS5hcHBseSh0aGlzLGFyZ3VtZW50cyl9O09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LCJfX2VzTW9kdWxlIix7dmFsdWU6ITB9KTt2YXIgbz1uKDApLGE9big5KSxzPW4oMzU2KSx1PW4oMTcpLGM9big3NSksbD1uKDUzMikscD1zLmRlZmF1bHQoKSxmPWZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoKXtyZXR1cm4gbnVsbCE9PWUmJmUuYXBwbHkodGhpcyxhcmd1bWVudHMpfHx0aGlzfXJldHVybiByKHQsZSksdC5wcm90b3R5cGUuY29tcG9uZW50RGlkTW91bnQ9ZnVuY3Rpb24oKXt2YXIgZT11LmdldFNldHRpbmdzKHAuZ2V0U3RhdGUoKSksdD1pKHt9LGUsdGhpcy5wcm9wcy5zZXR0aW5ncyksbj1KU09OLnN0cmluZ2lmeSh0LG51bGwsMik7cC5kaXNwYXRjaChjLnNldFNldHRpbmdzU3RyaW5nKG4pKX0sdC5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uKCl7cmV0dXJuIG8uY3JlYXRlRWxlbWVudChhLlByb3ZpZGVyLHtzdG9yZTpwfSxvLmNyZWF0ZUVsZW1lbnQobC5kZWZhdWx0LHRoaXMucHJvcHMpKX0sdH0oby5Db21wb25lbnQpO3QuZGVmYXVsdD1mfV0pOw==\"")
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/playground/playground.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/playground/playground.go
deleted file mode 100644
index 3fcc61fbdf7..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/playground/playground.go
+++ /dev/null
@@ -1,186 +0,0 @@
-//go:generate packr
-
-// Package playground is a http.Handler hosting the GraphQL Playground application.
-package playground
-
-import (
- "html/template"
- "net/http"
- "path"
- "strings"
-
- "github.com/gobuffalo/packr"
-)
-
-const (
- playgroundTemplate = "playgroundTemplate"
-
- contentTypeHeader = "Content-Type"
- contentTypeImagePNG = "image/png"
- contentTypeTextHTML = "text/html"
- contentTypeTextCSS = "text/css"
- contentTypeTextJavascript = "text/javascript"
-
- cssFile = "playground.css"
- jsFile = "playground.js"
- faviconFile = "favicon.png"
- logoFile = "logo.png"
-)
-
-// Config is the configuration Object to instruct ConfigureHandlers on how to setup all the http Handlers for the playground
-type Config struct {
- // PathPrefix is a prefix you intend to put in front of all handlers
- PathPrefix string
- // PlaygroundPath is the Path where the playground website should be hosted
- PlaygroundPath string
- // GraphqlEndpointPath is the Path where the http Handler for synchronous (Query,Mutation) GraphQL requests should be hosted
- GraphqlEndpointPath string
- // GraphQLSubscriptionEndpointPath is the Path where the http Handler for asynchronous (Subscription) GraphQL requests should be hosted
- GraphQLSubscriptionEndpointPath string
-}
-
-type playgroundTemplateData struct {
- CssURL string
- JsURL string
- FavIconURL string
- LogoURL string
- EndpointURL string
- SubscriptionEndpointURL string
-}
-
-type fileConfig struct {
- name string
- url string
- contentType string
-}
-
-// HandlerConfig is the configuration Object for playground http Handlers
-type HandlerConfig struct {
- // Path is where the handler should be hosted
- Path string
- // Handler is the http.HandlerFunc that should be hosted on the corresponding Path
- Handler http.HandlerFunc
-}
-
-// Handlers is an array of HandlerConfig
-// The playground expects that you make all assigned Handlers available on the corresponding Path
-type Handlers []HandlerConfig
-
-func (h *Handlers) add(path string, handler http.HandlerFunc) {
- *h = append(*h, HandlerConfig{
- Path: path,
- Handler: handler,
- })
-}
-
-// Playground manages the configuration of all HTTP handlers responsible for serving the GraphQL Playground
-type Playground struct {
- cfg Config
- box packr.Box
- files []fileConfig
- data playgroundTemplateData
-}
-
-// New creates a Playground for given Config
-func New(config Config) *Playground {
- prepareURL := func(file string) string {
- return strings.TrimPrefix(path.Join(config.PlaygroundPath, file), "/")
- }
-
- data := playgroundTemplateData{
- CssURL: prepareURL(cssFile),
- JsURL: prepareURL(jsFile),
- FavIconURL: prepareURL(faviconFile),
- LogoURL: prepareURL(logoFile),
- EndpointURL: config.GraphqlEndpointPath,
- SubscriptionEndpointURL: config.GraphQLSubscriptionEndpointPath,
- }
-
- files := []fileConfig{
- {
- name: cssFile,
- url: path.Join(config.PathPrefix, config.PlaygroundPath, cssFile),
- contentType: contentTypeTextCSS,
- },
- {
- name: jsFile,
- url: path.Join(config.PathPrefix, config.PlaygroundPath, jsFile),
- contentType: contentTypeTextJavascript,
- },
- {
- name: faviconFile,
- url: path.Join(config.PathPrefix, config.PlaygroundPath, faviconFile),
- contentType: contentTypeImagePNG,
- },
- {
- name: logoFile,
- url: path.Join(config.PathPrefix, config.PlaygroundPath, logoFile),
- contentType: contentTypeImagePNG,
- },
- }
-
- return &Playground{
- cfg: config,
- box: packr.NewBox("./files"),
- files: files,
- data: data,
- }
-}
-
-// Handlers configures and returns all Handlers for the Playground
-func (p *Playground) Handlers() (handlers Handlers, err error) {
- handlers = make(Handlers, 0, len(p.files)+1)
-
- if err = p.configurePlaygroundHandler(&handlers); err != nil {
- return
- }
-
- for _, file := range p.files {
- if err = p.configureFileHandler(&handlers, file); err != nil {
- return
- }
- }
-
- return
-}
-
-func (p *Playground) configurePlaygroundHandler(handlers *Handlers) (err error) {
- playgroundHTML, err := p.box.FindString("playground.html")
- if err != nil {
- return
- }
- templates, err := template.New(playgroundTemplate).Parse(playgroundHTML)
- if err != nil {
- return
- }
-
- playgroundURL := path.Join(p.cfg.PathPrefix, p.cfg.PlaygroundPath)
- if strings.HasSuffix(p.cfg.PlaygroundPath, "/") || (p.cfg.PlaygroundPath == "" && strings.HasSuffix(p.cfg.PathPrefix, "/")) {
- playgroundURL += "/"
- }
-
- handlers.add(playgroundURL, func(writer http.ResponseWriter, request *http.Request) {
- writer.Header().Add(contentTypeHeader, contentTypeTextHTML)
-
- if err := templates.ExecuteTemplate(writer, playgroundTemplate, p.data); err != nil {
- writer.WriteHeader(http.StatusInternalServerError)
- _, _ = writer.Write([]byte(err.Error()))
- }
- })
-
- return nil
-}
-
-func (p *Playground) configureFileHandler(handlers *Handlers, file fileConfig) error {
- data, err := p.box.Find(file.name)
- if err != nil {
- return err
- }
-
- handlers.add(file.url, func(writer http.ResponseWriter, request *http.Request) {
- writer.Header().Add(contentTypeHeader, file.contentType)
- _, _ = writer.Write(data)
- })
-
- return nil
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/pool/bytesbuffer.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/pool/bytesbuffer.go
deleted file mode 100644
index 0d0086eedbf..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/pool/bytesbuffer.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package pool
-
-import (
- "bytes"
- "sync"
-)
-
-var (
- BytesBuffer = bytesBufferPool{
- pool: sync.Pool{
- New: func() interface{} {
- return bytes.NewBuffer(make([]byte, 0, 1024))
- },
- },
- }
-)
-
-type bytesBufferPool struct {
- pool sync.Pool
-}
-
-func (b *bytesBufferPool) Get() *bytes.Buffer {
- return b.pool.Get().(*bytes.Buffer)
-}
-
-func (b *bytesBufferPool) Put(buf *bytes.Buffer) {
- buf.Reset()
- b.pool.Put(buf)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/pool/hash64.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/pool/hash64.go
deleted file mode 100644
index 64154bf2138..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/pool/hash64.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package pool
-
-import (
- "hash"
- "sync"
-
- "github.com/cespare/xxhash"
-)
-
-var (
- Hash64 = hash64Pool{
- pool: sync.Pool{
- New: func() interface{} {
- return xxhash.New()
- },
- },
- }
-)
-
-type hash64Pool struct {
- pool sync.Pool
-}
-
-func (b *hash64Pool) Get() hash.Hash64 {
- return b.pool.Get().(hash.Hash64)
-}
-
-func (b *hash64Pool) Put(hash64 hash.Hash64) {
- hash64.Reset()
- b.pool.Put(hash64)
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/datasourceinput.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/datasourceinput.go
deleted file mode 100644
index 75f43b3606b..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/datasourceinput.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package postprocess
-
-import (
- "strconv"
- "strings"
-
- "github.com/jensneuse/graphql-go-tools/pkg/engine/plan"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
-)
-
-type ProcessDataSource struct{}
-
-func (d *ProcessDataSource) Process(pre plan.Plan) plan.Plan {
- switch t := pre.(type) {
- case *plan.SynchronousResponsePlan:
- d.traverseNode(t.Response.Data)
- case *plan.StreamingResponsePlan:
- d.traverseNode(t.Response.InitialResponse.Data)
- for i := range t.Response.Patches {
- d.traverseFetch(t.Response.Patches[i].Fetch)
- d.traverseNode(t.Response.Patches[i].Value)
- }
- case *plan.SubscriptionResponsePlan:
- d.traverseTrigger(&t.Response.Trigger)
- d.traverseNode(t.Response.Response.Data)
- }
- return pre
-}
-
-func (d *ProcessDataSource) traverseNode(node resolve.Node) {
- switch n := node.(type) {
- case *resolve.Object:
- d.traverseFetch(n.Fetch)
- for i := range n.Fields {
- d.traverseNode(n.Fields[i].Value)
- }
- case *resolve.Array:
- d.traverseNode(n.Item)
- }
-}
-
-func (d *ProcessDataSource) traverseFetch(fetch resolve.Fetch) {
- if fetch == nil {
- return
- }
- switch f := fetch.(type) {
- case *resolve.SingleFetch:
- d.traverseSingleFetch(f)
- case *resolve.ParallelFetch:
- for i := range f.Fetches {
- d.traverseSingleFetch(f.Fetches[i])
- }
- }
-}
-
-func (d *ProcessDataSource) traverseTrigger(trigger *resolve.GraphQLSubscriptionTrigger) {
- d.resolveInputTemplate(trigger.Variables,trigger.Input,&trigger.InputTemplate)
- trigger.Input = ""
- trigger.Variables = nil
-}
-
-func (d *ProcessDataSource) traverseSingleFetch(fetch *resolve.SingleFetch) {
- d.resolveInputTemplate(fetch.Variables,fetch.Input,&fetch.InputTemplate)
- fetch.Input = ""
- fetch.Variables = nil
-}
-
-func (d *ProcessDataSource) resolveInputTemplate(variables resolve.Variables, input string, template *resolve.InputTemplate) {
-
- if input == "" {
- return
- }
-
- if !strings.Contains(input, "$$") {
- template.Segments = append(template.Segments, resolve.TemplateSegment{
- SegmentType: resolve.StaticSegmentType,
- Data: []byte(input),
- })
- return
- }
-
- segments := strings.Split(input, "$$")
-
- isVariable := false
- for _, seg := range segments {
- switch {
- case isVariable:
- i, _ := strconv.Atoi(seg)
- variableTemplateSegment := (variables)[i].TemplateSegment()
- template.Segments = append(template.Segments, variableTemplateSegment)
- isVariable = false
- default:
- template.Segments = append(template.Segments, resolve.TemplateSegment{
- SegmentType: resolve.StaticSegmentType,
- Data: []byte(seg),
- })
- isVariable = true
- }
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/defer.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/defer.go
deleted file mode 100644
index df149c4491e..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/defer.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package postprocess
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/engine/plan"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type ProcessDefer struct {
- objects []*resolve.Object
- out *plan.StreamingResponsePlan
- updated bool
-}
-
-func (p *ProcessDefer) Process(pre plan.Plan) plan.Plan {
-
- p.out = nil
- p.updated = false
- p.objects = p.objects[:0]
-
- switch in := pre.(type) {
- case *plan.SynchronousResponsePlan:
- return p.synchronousResponse(in)
- case *plan.StreamingResponsePlan:
- return p.processStreamingResponsePlan(in)
- default:
- return pre
- }
-}
-
-func (p *ProcessDefer) processStreamingResponsePlan(in *plan.StreamingResponsePlan) plan.Plan {
- p.out = in
- for i := range p.out.Response.Patches {
- p.traverseNode(p.out.Response.Patches[i].Value)
- }
- p.traverseNode(p.out.Response.InitialResponse.Data)
- return p.out
-}
-
-func (p *ProcessDefer) synchronousResponse(pre *plan.SynchronousResponsePlan) plan.Plan {
- p.out = &plan.StreamingResponsePlan{
- FlushInterval: pre.FlushInterval,
- Response: resolve.GraphQLStreamingResponse{
- InitialResponse: pre.Response,
- FlushInterval: pre.FlushInterval,
- },
- }
- p.traverseNode(p.out.Response.InitialResponse.Data)
- if p.updated {
- return p.out
- }
- return pre
-}
-
-func (p *ProcessDefer) traverseNode(node resolve.Node) {
-
- switch n := node.(type) {
- case *resolve.Object:
- p.objects = append(p.objects, n)
- for i := range n.Fields {
- if n.Fields[i].Defer != nil {
- p.updated = true
- patchIndex, ok := p.createPatch(n, i)
- if !ok {
- continue
- }
- n.Fields[i].Defer = nil
- n.Fields[i].Value = &resolve.Null{
- Defer: resolve.Defer{
- Enabled: true,
- PatchIndex: patchIndex,
- },
- }
- p.traverseNode(p.out.Response.Patches[patchIndex].Value)
- } else {
- p.traverseNode(n.Fields[i].Value)
- }
- }
- p.objects = p.objects[:len(p.objects)-1]
- case *resolve.Array:
- p.traverseNode(n.Item)
- }
-}
-
-func (p *ProcessDefer) createPatch(object *resolve.Object, field int) (int, bool) {
- oldValue := object.Fields[field].Value
- var patch *resolve.GraphQLResponsePatch
- if object.Fields[field].HasBuffer && !p.bufferUsedOnNonDeferField(object, field, object.Fields[field].BufferID) {
- patchFetch, ok := p.processFieldSetBuffer(object, field)
- if !ok {
- return 0, false
- }
- patch = &resolve.GraphQLResponsePatch{
- Value: oldValue,
- Fetch: &patchFetch,
- Operation: literal.REPLACE,
- }
- object.Fields[field].HasBuffer = false
- object.Fields[field].BufferID = 0
- } else {
- patch = &resolve.GraphQLResponsePatch{
- Value: oldValue,
- Operation: literal.REPLACE,
- }
- }
- p.out.Response.Patches = append(p.out.Response.Patches, patch)
- patchIndex := len(p.out.Response.Patches) - 1
- return patchIndex, true
-}
-
-func (p *ProcessDefer) bufferUsedOnNonDeferField(object *resolve.Object, field, bufferID int) bool {
- for i := range object.Fields {
- if object.Fields[i].BufferID != bufferID {
- continue
- }
- if i == field {
- continue // skip currently evaluated field
- }
- if object.Fields[i].Defer == nil {
- return true
- }
- }
- return false
-}
-
-func (p *ProcessDefer) processFieldSetBuffer(object *resolve.Object, field int) (patchFetch resolve.SingleFetch, ok bool) {
- id := object.Fields[field].BufferID
- if p.objects[len(p.objects)-1].Fetch == nil {
- return patchFetch, false
- }
- switch fetch := p.objects[len(p.objects)-1].Fetch.(type) {
- case *resolve.SingleFetch:
- if fetch.BufferId != id {
- return patchFetch, false
- }
- patchFetch = *fetch
- patchFetch.BufferId = 0
- p.objects[len(p.objects)-1].Fetch = nil
- return patchFetch, true
- case *resolve.ParallelFetch:
- for k := range fetch.Fetches {
- if id == fetch.Fetches[k].BufferId {
- patchFetch = *fetch.Fetches[k]
- patchFetch.BufferId = 0
- fetch.Fetches = append(fetch.Fetches[:k], fetch.Fetches[k+1:]...)
- if len(fetch.Fetches) == 1 {
- p.objects[len(p.objects)-1].Fetch = fetch.Fetches[0]
- }
- return patchFetch, true
- }
- }
- }
- return patchFetch, false
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/postprocess.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/postprocess.go
deleted file mode 100644
index f814c055e94..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/postprocess.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package postprocess
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/engine/plan"
-)
-
-type PostProcessor interface {
- Process(pre plan.Plan) plan.Plan
-}
-
-type Processor struct {
- postProcessors []PostProcessor
-}
-
-func DefaultProcessor() *Processor {
- return &Processor{
- []PostProcessor{
- &ProcessDefer{},
- &ProcessStream{},
- &ProcessDataSource{},
- },
- }
-}
-
-func (p *Processor) Process(pre plan.Plan) (post plan.Plan) {
- post = pre
- for i := range p.postProcessors {
- post = p.postProcessors[i].Process(post)
- }
- return
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/stream.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/stream.go
deleted file mode 100644
index f346aa17ebb..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/postprocess/stream.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package postprocess
-
-import (
- "github.com/jensneuse/graphql-go-tools/pkg/engine/plan"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/lexer/literal"
-)
-
-type ProcessStream struct {
- out *plan.StreamingResponsePlan
- didUpdate bool
-}
-
-func (p *ProcessStream) Process(pre plan.Plan) plan.Plan {
-
- p.out = nil
- p.didUpdate = false
-
- switch in := pre.(type) {
- case *plan.SynchronousResponsePlan:
- return p.processSynchronousPlan(in)
- case *plan.StreamingResponsePlan:
- return p.processStreamingResponsePlan(in)
- default:
- return pre
- }
-}
-
-func (p *ProcessStream) processStreamingResponsePlan(in *plan.StreamingResponsePlan) plan.Plan {
- p.out = in
- for i := range p.out.Response.Patches {
- p.traverseNode(p.out.Response.Patches[i].Value)
- }
- p.traverseNode(p.out.Response.InitialResponse.Data)
- return p.out
-}
-
-func (p *ProcessStream) processSynchronousPlan(in *plan.SynchronousResponsePlan) plan.Plan {
- p.out = &plan.StreamingResponsePlan{
- FlushInterval: in.FlushInterval,
- Response: resolve.GraphQLStreamingResponse{
- InitialResponse: in.Response,
- FlushInterval: in.FlushInterval,
- },
- }
- p.traverseNode(in.Response.Data)
- if p.didUpdate {
- return p.out
- }
- return in
-}
-
-func (p *ProcessStream) traverseNode(node resolve.Node) {
- switch n := node.(type) {
- case *resolve.Object:
- for i := range n.Fields {
- if n.Fields[i].Stream != nil {
- switch array := n.Fields[i].Value.(type) {
- case *resolve.Array:
- array.Stream.Enabled = true
- array.Stream.InitialBatchSize = n.Fields[i].Stream.InitialBatchSize
- n.Fields[i].Stream = nil
- }
- }
- p.traverseNode(n.Fields[i].Value)
- }
- case *resolve.Array:
- if n.Stream.Enabled {
- p.didUpdate = true
- patch := &resolve.GraphQLResponsePatch{
- Value: n.Item,
- Operation: literal.ADD,
- }
- if n.Stream.InitialBatchSize == 0 {
- n.Item = nil
- }
- p.out.Response.Patches = append(p.out.Response.Patches, patch)
- n.Stream.PatchIndex = len(p.out.Response.Patches) - 1
-
- p.traverseNode(p.out.Response.Patches[n.Stream.PatchIndex].Value)
-
- return
- }
- p.traverseNode(n.Item)
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/context.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/context.go
deleted file mode 100644
index 88cf62f3139..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/context.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package subscription
-
-import (
- "context"
-)
-
-type subscriptionCancellations map[string]context.CancelFunc
-
-func (sc subscriptionCancellations) Add(id string) context.Context {
- ctx, cancelFunc := context.WithCancel(context.Background())
- sc[id] = cancelFunc
- return ctx
-}
-
-func (sc subscriptionCancellations) Cancel(id string) (ok bool) {
- cancelFunc, ok := sc[id]
- if !ok {
- return false
- }
-
- cancelFunc()
- delete(sc, id)
- return true
-}
-
-func (sc subscriptionCancellations) CancelAll() {
- for _, cancelFunc := range sc {
- cancelFunc()
- }
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/executor_v1.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/executor_v1.go
deleted file mode 100644
index 15d83659330..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/executor_v1.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package subscription
-
-import (
- "context"
- "sync"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/execution"
-)
-
-type ExecutorV1Pool struct {
- ExecutionHandler *execution.Handler
- executorPool *sync.Pool
-}
-
-func NewExecutorV1Pool(executionHandler *execution.Handler) *ExecutorV1Pool {
- return &ExecutorV1Pool{
- ExecutionHandler: executionHandler,
- executorPool: &sync.Pool{
- New: func() interface{} {
- return &ExecutorV1{}
- },
- },
- }
-}
-
-func (e *ExecutorV1Pool) Get(payload []byte) (Executor, error) {
- engineExecutor, node, executionContext, err := e.ExecutionHandler.Handle(payload, []byte(""))
- if err != nil {
- return nil, err
- }
-
- executor := e.executorPool.Get().(*ExecutorV1)
- executor.engineExecutor = engineExecutor
- executor.rootNode = node
- executor.executionContext = executionContext
-
- return executor, nil
-}
-
-func (e *ExecutorV1Pool) Put(executor Executor) error {
- executor.Reset()
- e.executorPool.Put(executor)
- return nil
-}
-
-type ExecutorV1 struct {
- engineExecutor *execution.Executor
- rootNode execution.RootNode
- executionContext execution.Context
-}
-
-func (e *ExecutorV1) Execute(writer resolve.FlushWriter) error {
- return e.engineExecutor.Execute(e.executionContext, e.rootNode, writer)
-}
-
-func (e *ExecutorV1) OperationType() ast.OperationType {
- return e.rootNode.OperationType()
-}
-
-func (e *ExecutorV1) SetContext(context context.Context) {
- e.executionContext.Context = context
-}
-
-func (e *ExecutorV1) Reset() {
- e.engineExecutor = nil
- e.rootNode = nil
- e.executionContext = execution.Context{}
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/executor_v2.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/executor_v2.go
deleted file mode 100644
index 81d977efa2d..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/executor_v2.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package subscription
-
-import (
- "bytes"
- "context"
- "sync"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/graphql"
-)
-
-type ExecutorV2Pool struct {
- engine *graphql.ExecutionEngineV2
- executorPool *sync.Pool
-}
-
-func NewExecutorV2Pool(engine *graphql.ExecutionEngineV2) *ExecutorV2Pool {
- return &ExecutorV2Pool{
- engine: engine,
- executorPool: &sync.Pool{
- New: func() interface{} {
- return &ExecutorV2{}
- },
- },
- }
-}
-
-func (e *ExecutorV2Pool) Get(payload []byte) (Executor, error) {
- operation := graphql.Request{}
- err := graphql.UnmarshalRequest(bytes.NewReader(payload), &operation)
- if err != nil {
- return nil, err
- }
-
- return &ExecutorV2{
- engine: e.engine,
- operation: &operation,
- context: context.Background(),
- }, nil
-}
-
-func (e *ExecutorV2Pool) Put(executor Executor) error {
- executor.Reset()
- e.executorPool.Put(executor)
- return nil
-}
-
-type ExecutorV2 struct {
- engine *graphql.ExecutionEngineV2
- operation *graphql.Request
- context context.Context
-}
-
-func (e *ExecutorV2) Execute(writer resolve.FlushWriter) error {
- return e.engine.Execute(e.context, e.operation, writer)
-}
-
-func (e *ExecutorV2) OperationType() ast.OperationType {
- opType, err := e.operation.OperationType()
- if err != nil {
- return ast.OperationTypeUnknown
- }
-
- return ast.OperationType(opType)
-}
-
-func (e *ExecutorV2) SetContext(context context.Context) {
- e.context = context
-}
-
-func (e *ExecutorV2) Reset() {
- e.engine = nil
- e.operation = nil
- e.context = context.Background()
-}
diff --git a/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/handler.go b/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/handler.go
deleted file mode 100644
index 9b9ffc1d3d9..00000000000
--- a/vendor/github.com/jensneuse/graphql-go-tools/pkg/subscription/handler.go
+++ /dev/null
@@ -1,427 +0,0 @@
-package subscription
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "strings"
- "sync"
- "time"
-
- "github.com/jensneuse/abstractlogger"
-
- "github.com/jensneuse/graphql-go-tools/pkg/ast"
- "github.com/jensneuse/graphql-go-tools/pkg/engine/resolve"
- "github.com/jensneuse/graphql-go-tools/pkg/graphql"
-)
-
-const (
- MessageTypeConnectionInit = "connection_init"
- MessageTypeConnectionAck = "connection_ack"
- MessageTypeConnectionError = "connection_error"
- MessageTypeConnectionTerminate = "connection_terminate"
- MessageTypeConnectionKeepAlive = "ka"
- MessageTypeStart = "start"
- MessageTypeStop = "stop"
- MessageTypeData = "data"
- MessageTypeError = "error"
- MessageTypeComplete = "complete"
-
- DefaultKeepAliveInterval = "15s"
- DefaultSubscriptionUpdateInterval = "1s"
-)
-
-// Message defines the actual subscription message wich will be passed from client to server and vice versa.
-type Message struct {
- Id string `json:"id"`
- Type string `json:"type"`
- Payload json.RawMessage `json:"payload"`
-}
-
-// client provides an interface which can be implemented by any possible subscription client like websockets, mqtt, etc.
-type Client interface {
- // ReadFromClient will invoke a read operation from the client connection.
- ReadFromClient() (*Message, error)
- // WriteToClient will invoke a write operation to the client connection.
- WriteToClient(Message) error
- // IsConnected will indicate if a connection is still established.
- IsConnected() bool
- // Disconnect will close the connection between server and client.
- Disconnect() error
-}
-
-// ExecutorPool is an abstraction for creating executors
-type ExecutorPool interface {
- Get(payload []byte) (Executor, error)
- Put(executor Executor) error
-}
-
-// Executor is an abstraction for executing a GraphQL engine
-type Executor interface {
- Execute(writer resolve.FlushWriter) error
- OperationType() ast.OperationType
- SetContext(context context.Context)
- Reset()
-}
-
-// Handler is the actual subscription handler which will keep track on how to handle messages coming from the client.
-type Handler struct {
- logger abstractlogger.Logger
- // client will hold the subscription client implementation.
- client Client
- // keepAliveInterval is the actual interval on which the server send keep alive messages to the client.
- keepAliveInterval time.Duration
- // subscriptionUpdateInterval is the actual interval on which the server sends subscription updates to the client.
- subscriptionUpdateInterval time.Duration
- // subCancellations is map containing the cancellation functions to every active subscription.
- subCancellations subscriptionCancellations
- // executorPool is responsible to create and hold executors.
- executorPool ExecutorPool
- // bufferPool will hold buffers.
- bufferPool *sync.Pool
-}
-
-// NewHandler creates a new subscription handler.
-func NewHandler(logger abstractlogger.Logger, client Client, executorPool ExecutorPool) (*Handler, error) {
- keepAliveInterval, err := time.ParseDuration(DefaultKeepAliveInterval)
- if err != nil {
- return nil, err
- }
-
- subscriptionUpdateInterval, err := time.ParseDuration(DefaultSubscriptionUpdateInterval)
- if err != nil {
- return nil, err
- }
-
- return &Handler{
- logger: logger,
- client: client,
- keepAliveInterval: keepAliveInterval,
- subscriptionUpdateInterval: subscriptionUpdateInterval,
- subCancellations: subscriptionCancellations{},
- executorPool: executorPool,
- bufferPool: &sync.Pool{
- New: func() interface{} {
- writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024)))
- return &writer
- },
- },
- }, nil
-}
-
-// Handle will handle the subscritpion connection.
-func (h *Handler) Handle(ctx context.Context) {
- defer func() {
- h.subCancellations.CancelAll()
- }()
-
- for {
- if !h.client.IsConnected() {
- h.logger.Debug("subscription.Handler.Handle()",
- abstractlogger.String("message", "client has disconnected"),
- )
-
- return
- }
-
- message, err := h.client.ReadFromClient()
- if err != nil {
- h.logger.Error("subscription.Handler.Handle()",
- abstractlogger.Error(err),
- abstractlogger.Any("message", message),
- )
-
- h.handleConnectionError("could not read message from client")
- } else if message != nil {
- switch message.Type {
- case MessageTypeConnectionInit:
- h.handleInit()
- go h.handleKeepAlive(ctx)
- case MessageTypeStart:
- h.handleStart(message.Id, message.Payload)
- case MessageTypeStop:
- h.handleStop(message.Id)
- case MessageTypeConnectionTerminate:
- h.handleConnectionTerminate()
- return
- }
- }
-
- select {
- case <-ctx.Done():
- return
- default:
- continue
- }
- }
-}
-
-// ChangeKeepAliveInterval can be used to change the keep alive interval.
-func (h *Handler) ChangeKeepAliveInterval(d time.Duration) {
- h.keepAliveInterval = d
-}
-
-// ChangeSubscriptionUpdateInterval can be used to change the update interval.
-func (h *Handler) ChangeSubscriptionUpdateInterval(d time.Duration) {
- h.subscriptionUpdateInterval = d
-}
-
-// handleInit will handle an init message.
-func (h *Handler) handleInit() {
- ackMessage := Message{
- Type: MessageTypeConnectionAck,
- }
-
- err := h.client.WriteToClient(ackMessage)
- if err != nil {
- h.logger.Error("subscription.Handler.handleInit()",
- abstractlogger.Error(err),
- )
- }
-}
-
-// handleStart will handle s start message.
-func (h *Handler) handleStart(id string, payload []byte) {
- executor, err := h.executorPool.Get(payload)
- if err != nil {
- h.logger.Error("subscription.Handler.handleStart()",
- abstractlogger.Error(err),
- )
-
- h.handleError(id, cleanErrorMessage(err))
- return
- }
-
- if executor.OperationType() == ast.OperationTypeSubscription {
- ctx := h.subCancellations.Add(id)
- go h.startSubscription(ctx, id, executor)
- return
- }
-
- go h.handleNonSubscriptionOperation(id, executor)
-}
-
-// handleNonSubscriptionOperation will handle a non-subscription operation like a query or a mutation.
-func (h *Handler) handleNonSubscriptionOperation(id string, executor Executor) {
- defer func() {
- err := h.executorPool.Put(executor)
- if err != nil {
- h.logger.Error("subscription.Handle.handleNonSubscriptionOperation()",
- abstractlogger.Error(err),
- )
- }
- }()
-
- buf := h.bufferPool.Get().(*graphql.EngineResultWriter)
- buf.Reset()
-
- defer h.bufferPool.Put(buf)
-
- //err := executor.Execute(executionContext, node, buf)
- err := executor.Execute(buf)
- if err != nil {
- h.logger.Error("subscription.Handle.handleNonSubscriptionOperation()",
- abstractlogger.Error(err),
- )
-
- h.handleError(id, err.Error())
- return
- }
-
- h.logger.Debug("subscription.Handle.handleNonSubscriptionOperation()",
- abstractlogger.ByteString("execution_result", buf.Bytes()),
- )
-
- h.sendData(id, buf.Bytes())
- h.sendComplete(id)
-}
-
-// startSubscription will invoke the actual subscription.
-func (h *Handler) startSubscription(ctx context.Context, id string, executor Executor) {
- defer func() {
- err := h.executorPool.Put(executor)
- if err != nil {
- h.logger.Error("subscription.Handle.startSubscription()",
- abstractlogger.Error(err),
- )
- }
- }()
-
- executor.SetContext(ctx)
- buf := h.bufferPool.Get().(*graphql.EngineResultWriter)
- buf.Reset()
-
- defer h.bufferPool.Put(buf)
-
- h.executeSubscription(buf, id, executor)
-
- for {
- buf.Reset()
- select {
- case <-ctx.Done():
- return
- case <-time.After(h.subscriptionUpdateInterval):
- h.executeSubscription(buf, id, executor)
- }
- }
-
-}
-
-// executeSubscription will keep execution the subscription until it ends.
-func (h *Handler) executeSubscription(buf *graphql.EngineResultWriter, id string, executor Executor) {
- //err := executor.Execute(ctx, node, buf)
- err := executor.Execute(buf)
- if err != nil {
- h.logger.Error("subscription.Handle.executeSubscription()",
- abstractlogger.Error(err),
- )
-
- h.handleError(id, err)
- return
- }
-
- h.logger.Debug("subscription.Handle.executeSubscription()",
- abstractlogger.ByteString("execution_result", buf.Bytes()),
- )
-
- h.sendData(id, buf.Bytes())
-}
-
-// handleStop will handle a stop message,
-func (h *Handler) handleStop(id string) {
- h.subCancellations.Cancel(id)
- h.sendComplete(id)
-}
-
-// sendData will send a data message to the client.
-func (h *Handler) sendData(id string, responseData []byte) {
- dataMessage := Message{
- Id: id,
- Type: MessageTypeData,
- Payload: responseData,
- }
-
- err := h.client.WriteToClient(dataMessage)
- if err != nil {
- h.logger.Error("subscription.Handler.sendData()",
- abstractlogger.Error(err),
- )
- }
-}
-
-//nolint
-// sendComplete will send a complete message to the client.
-func (h *Handler) sendComplete(id string) {
- completeMessage := Message{
- Id: id,
- Type: MessageTypeComplete,
- Payload: nil,
- }
-
- err := h.client.WriteToClient(completeMessage)
- if err != nil {
- h.logger.Error("subscription.Handler.sendComplete()",
- abstractlogger.Error(err),
- )
- }
-}
-
-// handleConnectionTerminate will handle a comnnection terminate message.
-func (h *Handler) handleConnectionTerminate() {
- err := h.client.Disconnect()
- if err != nil {
- h.logger.Error("subscription.Handler.handleConnectionTerminate()",
- abstractlogger.Error(err),
- )
- }
-}
-
-// handleKeepAlive will handle the keep alive loop.
-func (h *Handler) handleKeepAlive(ctx context.Context) {
- for {
- select {
- case <-ctx.Done():
- return
- case <-time.After(h.keepAliveInterval):
- h.sendKeepAlive()
- }
- }
-}
-
-// sendKeepAlive will send a keep alive message to the client.
-func (h *Handler) sendKeepAlive() {
- keepAliveMessage := Message{
- Type: MessageTypeConnectionKeepAlive,
- }
-
- err := h.client.WriteToClient(keepAliveMessage)
- if err != nil {
- h.logger.Error("subscription.Handler.sendKeepAlive()",
- abstractlogger.Error(err),
- )
- }
-}
-
-// handleConnectionError will handle a connection error message.
-func (h *Handler) handleConnectionError(errorPayload interface{}) {
- payloadBytes, err := json.Marshal(errorPayload)
- if err != nil {
- h.logger.Error("subscription.Handler.handleConnectionError()",
- abstractlogger.Error(err),
- abstractlogger.Any("errorPayload", errorPayload),
- )
- }
-
- connectionErrorMessage := Message{
- Type: MessageTypeConnectionError,
- Payload: payloadBytes,
- }
-
- err = h.client.WriteToClient(connectionErrorMessage)
- if err != nil {
- h.logger.Error("subscription.Handler.handleConnectionError()",
- abstractlogger.Error(err),
- )
-
- err := h.client.Disconnect()
- if err != nil {
- h.logger.Error("subscription.Handler.handleError()",
- abstractlogger.Error(err),
- )
- }
- }
-}
-
-// handleError will handle an error message.
-func (h *Handler) handleError(id string, errorPayload interface{}) {
- payloadBytes, err := json.Marshal(errorPayload)
- if err != nil {
- h.logger.Error("subscription.Handler.handleError()",
- abstractlogger.Error(err),
- abstractlogger.Any("errorPayload", errorPayload),
- )
- }
-
- errorMessage := Message{
- Id: id,
- Type: MessageTypeError,
- Payload: payloadBytes,
- }
-
- err = h.client.WriteToClient(errorMessage)
- if err != nil {
- h.logger.Error("subscription.Handler.handleError()",
- abstractlogger.Error(err),
- )
- }
-}
-
-// ActiveSubscriptions will return the actual number of active subscriptions for that client.
-func (h *Handler) ActiveSubscriptions() int {
- return len(h.subCancellations)
-}
-
-func cleanErrorMessage(err error) string {
- errMsg := strings.TrimPrefix(err.Error(), "external: ")
- return errMsg
-}
diff --git a/vendor/github.com/jensneuse/pipeline/LICENSE b/vendor/github.com/jensneuse/pipeline/LICENSE
deleted file mode 100644
index f56d926b9e1..00000000000
--- a/vendor/github.com/jensneuse/pipeline/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2020 Jens Neuse
-
-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.
diff --git a/vendor/github.com/jensneuse/pipeline/pkg/pipe/pipeline.go b/vendor/github.com/jensneuse/pipeline/pkg/pipe/pipeline.go
deleted file mode 100644
index 5b618ba445a..00000000000
--- a/vendor/github.com/jensneuse/pipeline/pkg/pipe/pipeline.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// package pipe initializes, configures and runs a pipeline
-package pipe
-
-import (
- "bytes"
- "encoding/json"
- "github.com/jensneuse/pipeline/pkg/step"
- "io"
-)
-
-// Step is a pipeline step which takes an io.Reader as well as an io.Writer as arguments
-// The previous (or first) pipeline step will pipe its result to the reader of the next (or final) pipeline step.
-// The step is expected to write its result to the writer so that the next (or final) step can proceed doing its work.
-type Step interface {
- Invoke(reader io.Reader, writer io.Writer) error
-}
-
-// Config is the Configuration Object to setup all steps
-type Config struct {
- Steps []StepConfig `json:"steps"`
-}
-
-// StepConfig is the object to hold the kind and config of each step
-type StepConfig struct {
- Kind string `json:"kind"`
- Config json.RawMessage `json:"config"`
-}
-
-// Pipeline holds all steps and executes them on after each other
-type Pipeline struct {
- Steps []Step
-}
-
-// FromConfig takes a StepConfig in JSON format and creates an executable Pipeline from it
-func (p *Pipeline) FromConfig(reader io.Reader) error {
- var config Config
- err := json.NewDecoder(reader).Decode(&config)
- if err != nil {
- return err
- }
- for i := range config.Steps {
- var next Step
- switch config.Steps[i].Kind {
- case "JSON":
- next, err = step.UnmarshalJsonStep(bytes.NewReader(config.Steps[i].Config))
- case "HTTP":
- next, err = step.UnmarshalHttpStep(bytes.NewReader(config.Steps[i].Config))
- case "NOOP":
- next = step.NoOpStep{}
- }
- if err != nil {
- return err
- }
- p.Steps = append(p.Steps, next)
- }
- return nil
-}
-
-// Run starts the pipeline
-// It takes the input from the reader and pipes it into the first step
-// The result written to the writer of the last step will be emitted to the writer passed to Run
-func (p *Pipeline) Run (reader io.Reader,writer io.Writer) error {
-
- readBuf := bytes.Buffer{}
- writeBuf := bytes.Buffer{}
-
- _,err := readBuf.ReadFrom(reader)
- if err != nil {
- return err
- }
-
- for i := range p.Steps {
- err = p.Steps[i].Invoke(&readBuf,&writeBuf)
- if err != nil {
- return err
- }
- readBuf.Reset()
- _,err = writeBuf.WriteTo(&readBuf)
- if err != nil {
- return err
- }
- writeBuf.Reset()
- }
-
- _,err = readBuf.WriteTo(writer)
- return err
-}
\ No newline at end of file
diff --git a/vendor/github.com/jensneuse/pipeline/pkg/step/http.go b/vendor/github.com/jensneuse/pipeline/pkg/step/http.go
deleted file mode 100644
index 05964f8c61a..00000000000
--- a/vendor/github.com/jensneuse/pipeline/pkg/step/http.go
+++ /dev/null
@@ -1,118 +0,0 @@
-package step
-
-import (
- "bytes"
- "encoding/json"
- "io"
- "io/ioutil"
- "net/http"
- "time"
-)
-
-type HttpStep struct {
- DefaultTimeout time.Duration `json:"default_timeout"`
- DefaultMethod string `json:"default_method"`
-}
-
-func UnmarshalHttpStep(reader io.Reader) (HttpStep, error) {
- var step HttpStep
- err := json.NewDecoder(reader).Decode(&step)
- return step, err
-}
-
-func NewHTTP(defaultTimeout time.Duration, defaultMethod string) HttpStep {
- return HttpStep{
- DefaultTimeout: defaultTimeout,
- DefaultMethod: defaultMethod,
- }
-}
-
-type HttpStepInput struct {
- Timeout time.Duration `json:"timeout"`
- Method string `json:"method"`
- URL string `json:"url"`
- Body map[string]interface{} `json:"body"`
- Header http.Header `json:"header"`
-}
-
-type HttpStepOutput struct {
- StatusCode int `json:"status_code"`
- Header http.Header `json:"header"`
- Body map[string]interface{} `json:"body"`
-}
-
-func (h HttpStep) Invoke(reader io.Reader, writer io.Writer) error {
- var config HttpStepInput
- err := json.NewDecoder(reader).Decode(&config)
- if err != nil {
- return err
- }
-
- client := h.client(config)
- req, err := h.request(config)
- if err != nil {
- return err
- }
-
- res, err := client.Do(req)
- if err != nil {
- return err
- }
-
- defer res.Body.Close()
-
- var out HttpStepOutput
- out.StatusCode = res.StatusCode
- out.Header = res.Header
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return err
- }
- err = json.Unmarshal(body, &out.Body)
- if err != nil {
- return err
- }
- return json.NewEncoder(writer).Encode(out)
-}
-
-func (h *HttpStep) client(config HttpStepInput) http.Client {
-
- timeout := h.DefaultTimeout
- if config.Timeout != 0 {
- timeout = config.Timeout
- }
-
- return http.Client{
- Timeout: timeout,
- }
-}
-
-func (h *HttpStep) request(config HttpStepInput) (*http.Request, error) {
- method := h.DefaultMethod
- if config.Method != "" {
- method = config.Method
- }
-
- url := config.URL
-
- var body io.Reader
- if config.Body != nil {
- buf := &bytes.Buffer{}
- err := json.NewEncoder(buf).Encode(config.Body)
- if err != nil {
- return nil, err
- }
- body = buf
- }
-
- req, err := http.NewRequest(method, url, body)
- if err != nil {
- return nil, err
- }
-
- if config.Header != nil {
- req.Header = config.Header
- }
-
- return req, nil
-}
diff --git a/vendor/github.com/jensneuse/pipeline/pkg/step/json.go b/vendor/github.com/jensneuse/pipeline/pkg/step/json.go
deleted file mode 100644
index 3060e258538..00000000000
--- a/vendor/github.com/jensneuse/pipeline/pkg/step/json.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package step
-
-import (
- "encoding/json"
- "github.com/Masterminds/sprig"
- "io"
- "io/ioutil"
- "text/template"
-)
-
-type JsonStep struct {
- Template string `json:"template"`
- tmpl *template.Template
-}
-
-func UnmarshalJsonStep(reader io.Reader) (JsonStep, error) {
- var step JsonStep
- step.tmpl = template.New("")
- step.tmpl.Funcs(sprig.TxtFuncMap())
- err := json.NewDecoder(reader).Decode(&step)
- if err != nil {
- return step, err
- }
-
- step.tmpl, err = step.tmpl.Parse(step.Template)
- return step, err
-}
-
-func NewJSON(tmpl string) (step JsonStep,err error) {
- step.Template = tmpl
- step.tmpl = template.New("")
- step.tmpl.Funcs(sprig.TxtFuncMap())
- step.tmpl, err = step.tmpl.Parse(step.Template)
- return step, err
-}
-
-func (j JsonStep) Invoke(reader io.Reader, writer io.Writer) error {
- data, err := ioutil.ReadAll(reader)
- if err != nil {
- return err
- }
-
- var in interface{}
-
- err = json.Unmarshal(data, &in)
- if err != nil {
- return err
- }
-
- return j.tmpl.Execute(writer, in)
-}
diff --git a/vendor/github.com/jensneuse/pipeline/pkg/step/noop.go b/vendor/github.com/jensneuse/pipeline/pkg/step/noop.go
deleted file mode 100644
index a95b0f21d1d..00000000000
--- a/vendor/github.com/jensneuse/pipeline/pkg/step/noop.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package step
-
-import "io"
-
-// NoOpStep is a step that does nothing but copy from the reader to the writer.
-// It's good e.g. for testing purposes where you simply want to check the functionality of the pipeline itself.
-type NoOpStep struct {}
-
-func (n NoOpStep) Invoke(reader io.Reader, writer io.Writer) error {
- _,err := io.Copy(writer,reader)
- return err
-}
-
diff --git a/vendor/github.com/jensneuse/pipeline/pkg/step/step.go b/vendor/github.com/jensneuse/pipeline/pkg/step/step.go
deleted file mode 100644
index d309f7f02e5..00000000000
--- a/vendor/github.com/jensneuse/pipeline/pkg/step/step.go
+++ /dev/null
@@ -1,2 +0,0 @@
-// package step holds all possible steps to create pipelines
-package step
diff --git a/vendor/github.com/joho/godotenv/.gitignore b/vendor/github.com/joho/godotenv/.gitignore
deleted file mode 100644
index e43b0f98895..00000000000
--- a/vendor/github.com/joho/godotenv/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.DS_Store
diff --git a/vendor/github.com/joho/godotenv/.travis.yml b/vendor/github.com/joho/godotenv/.travis.yml
deleted file mode 100644
index f0db1adcdb1..00000000000
--- a/vendor/github.com/joho/godotenv/.travis.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-language: go
-
-go:
- - 1.x
-
-os:
- - linux
- - osx
diff --git a/vendor/github.com/joho/godotenv/LICENCE b/vendor/github.com/joho/godotenv/LICENCE
deleted file mode 100644
index e7ddd51be90..00000000000
--- a/vendor/github.com/joho/godotenv/LICENCE
+++ /dev/null
@@ -1,23 +0,0 @@
-Copyright (c) 2013 John Barton
-
-MIT License
-
-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.
-
diff --git a/vendor/github.com/joho/godotenv/README.md b/vendor/github.com/joho/godotenv/README.md
deleted file mode 100644
index 4e8fcf2e9cd..00000000000
--- a/vendor/github.com/joho/godotenv/README.md
+++ /dev/null
@@ -1,163 +0,0 @@
-# GoDotEnv [![Build Status](https://travis-ci.org/joho/godotenv.svg?branch=master)](https://travis-ci.org/joho/godotenv) [![Build status](https://ci.appveyor.com/api/projects/status/9v40vnfvvgde64u4?svg=true)](https://ci.appveyor.com/project/joho/godotenv) [![Go Report Card](https://goreportcard.com/badge/github.com/joho/godotenv)](https://goreportcard.com/report/github.com/joho/godotenv)
-
-A Go (golang) port of the Ruby dotenv project (which loads env vars from a .env file)
-
-From the original Library:
-
-> Storing configuration in the environment is one of the tenets of a twelve-factor app. Anything that is likely to change between deployment environments–such as resource handles for databases or credentials for external services–should be extracted from the code into environment variables.
->
-> But it is not always practical to set environment variables on development machines or continuous integration servers where multiple projects are run. Dotenv load variables from a .env file into ENV when the environment is bootstrapped.
-
-It can be used as a library (for loading in env for your own daemons etc) or as a bin command.
-
-There is test coverage and CI for both linuxish and windows environments, but I make no guarantees about the bin version working on windows.
-
-## Installation
-
-As a library
-
-```shell
-go get github.com/joho/godotenv
-```
-
-or if you want to use it as a bin command
-```shell
-go get github.com/joho/godotenv/cmd/godotenv
-```
-
-## Usage
-
-Add your application configuration to your `.env` file in the root of your project:
-
-```shell
-S3_BUCKET=YOURS3BUCKET
-SECRET_KEY=YOURSECRETKEYGOESHERE
-```
-
-Then in your Go app you can do something like
-
-```go
-package main
-
-import (
- "github.com/joho/godotenv"
- "log"
- "os"
-)
-
-func main() {
- err := godotenv.Load()
- if err != nil {
- log.Fatal("Error loading .env file")
- }
-
- s3Bucket := os.Getenv("S3_BUCKET")
- secretKey := os.Getenv("SECRET_KEY")
-
- // now do something with s3 or whatever
-}
-```
-
-If you're even lazier than that, you can just take advantage of the autoload package which will read in `.env` on import
-
-```go
-import _ "github.com/joho/godotenv/autoload"
-```
-
-While `.env` in the project root is the default, you don't have to be constrained, both examples below are 100% legit
-
-```go
-_ = godotenv.Load("somerandomfile")
-_ = godotenv.Load("filenumberone.env", "filenumbertwo.env")
-```
-
-If you want to be really fancy with your env file you can do comments and exports (below is a valid env file)
-
-```shell
-# I am a comment and that is OK
-SOME_VAR=someval
-FOO=BAR # comments at line end are OK too
-export BAR=BAZ
-```
-
-Or finally you can do YAML(ish) style
-
-```yaml
-FOO: bar
-BAR: baz
-```
-
-as a final aside, if you don't want godotenv munging your env you can just get a map back instead
-
-```go
-var myEnv map[string]string
-myEnv, err := godotenv.Read()
-
-s3Bucket := myEnv["S3_BUCKET"]
-```
-
-... or from an `io.Reader` instead of a local file
-
-```go
-reader := getRemoteFile()
-myEnv, err := godotenv.Parse(reader)
-```
-
-... or from a `string` if you so desire
-
-```go
-content := getRemoteFileContent()
-myEnv, err := godotenv.Unmarshal(content)
-```
-
-### Command Mode
-
-Assuming you've installed the command as above and you've got `$GOPATH/bin` in your `$PATH`
-
-```
-godotenv -f /some/path/to/.env some_command with some args
-```
-
-If you don't specify `-f` it will fall back on the default of loading `.env` in `PWD`
-
-### Writing Env Files
-
-Godotenv can also write a map representing the environment to a correctly-formatted and escaped file
-
-```go
-env, err := godotenv.Unmarshal("KEY=value")
-err := godotenv.Write(env, "./.env")
-```
-
-... or to a string
-
-```go
-env, err := godotenv.Unmarshal("KEY=value")
-content, err := godotenv.Marshal(env)
-```
-
-## Contributing
-
-Contributions are most welcome! The parser itself is pretty stupidly naive and I wouldn't be surprised if it breaks with edge cases.
-
-*code changes without tests will not be accepted*
-
-1. Fork it
-2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Commit your changes (`git commit -am 'Added some feature'`)
-4. Push to the branch (`git push origin my-new-feature`)
-5. Create new Pull Request
-
-## Releases
-
-Releases should follow [Semver](http://semver.org/) though the first couple of releases are `v1` and `v1.1`.
-
-Use [annotated tags for all releases](https://github.com/joho/godotenv/issues/30). Example `git tag -a v1.2.1`
-
-## CI
-
-Linux: [![Build Status](https://travis-ci.org/joho/godotenv.svg?branch=master)](https://travis-ci.org/joho/godotenv) Windows: [![Build status](https://ci.appveyor.com/api/projects/status/9v40vnfvvgde64u4)](https://ci.appveyor.com/project/joho/godotenv)
-
-## Who?
-
-The original library [dotenv](https://github.com/bkeepers/dotenv) was written by [Brandon Keepers](http://opensoul.org/), and this port was done by [John Barton](https://johnbarton.co/) based off the tests/fixtures in the original library.
diff --git a/vendor/github.com/joho/godotenv/godotenv.go b/vendor/github.com/joho/godotenv/godotenv.go
deleted file mode 100644
index 29b436c77c0..00000000000
--- a/vendor/github.com/joho/godotenv/godotenv.go
+++ /dev/null
@@ -1,346 +0,0 @@
-// Package godotenv is a go port of the ruby dotenv library (https://github.com/bkeepers/dotenv)
-//
-// Examples/readme can be found on the github page at https://github.com/joho/godotenv
-//
-// The TL;DR is that you make a .env file that looks something like
-//
-// SOME_ENV_VAR=somevalue
-//
-// and then in your go code you can call
-//
-// godotenv.Load()
-//
-// and all the env vars declared in .env will be available through os.Getenv("SOME_ENV_VAR")
-package godotenv
-
-import (
- "bufio"
- "errors"
- "fmt"
- "io"
- "os"
- "os/exec"
- "regexp"
- "sort"
- "strings"
-)
-
-const doubleQuoteSpecialChars = "\\\n\r\"!$`"
-
-// Load will read your env file(s) and load them into ENV for this process.
-//
-// Call this function as close as possible to the start of your program (ideally in main)
-//
-// If you call Load without any args it will default to loading .env in the current path
-//
-// You can otherwise tell it which files to load (there can be more than one) like
-//
-// godotenv.Load("fileone", "filetwo")
-//
-// It's important to note that it WILL NOT OVERRIDE an env variable that already exists - consider the .env file to set dev vars or sensible defaults
-func Load(filenames ...string) (err error) {
- filenames = filenamesOrDefault(filenames)
-
- for _, filename := range filenames {
- err = loadFile(filename, false)
- if err != nil {
- return // return early on a spazout
- }
- }
- return
-}
-
-// Overload will read your env file(s) and load them into ENV for this process.
-//
-// Call this function as close as possible to the start of your program (ideally in main)
-//
-// If you call Overload without any args it will default to loading .env in the current path
-//
-// You can otherwise tell it which files to load (there can be more than one) like
-//
-// godotenv.Overload("fileone", "filetwo")
-//
-// It's important to note this WILL OVERRIDE an env variable that already exists - consider the .env file to forcefilly set all vars.
-func Overload(filenames ...string) (err error) {
- filenames = filenamesOrDefault(filenames)
-
- for _, filename := range filenames {
- err = loadFile(filename, true)
- if err != nil {
- return // return early on a spazout
- }
- }
- return
-}
-
-// Read all env (with same file loading semantics as Load) but return values as
-// a map rather than automatically writing values into env
-func Read(filenames ...string) (envMap map[string]string, err error) {
- filenames = filenamesOrDefault(filenames)
- envMap = make(map[string]string)
-
- for _, filename := range filenames {
- individualEnvMap, individualErr := readFile(filename)
-
- if individualErr != nil {
- err = individualErr
- return // return early on a spazout
- }
-
- for key, value := range individualEnvMap {
- envMap[key] = value
- }
- }
-
- return
-}
-
-// Parse reads an env file from io.Reader, returning a map of keys and values.
-func Parse(r io.Reader) (envMap map[string]string, err error) {
- envMap = make(map[string]string)
-
- var lines []string
- scanner := bufio.NewScanner(r)
- for scanner.Scan() {
- lines = append(lines, scanner.Text())
- }
-
- if err = scanner.Err(); err != nil {
- return
- }
-
- for _, fullLine := range lines {
- if !isIgnoredLine(fullLine) {
- var key, value string
- key, value, err = parseLine(fullLine, envMap)
-
- if err != nil {
- return
- }
- envMap[key] = value
- }
- }
- return
-}
-
-//Unmarshal reads an env file from a string, returning a map of keys and values.
-func Unmarshal(str string) (envMap map[string]string, err error) {
- return Parse(strings.NewReader(str))
-}
-
-// Exec loads env vars from the specified filenames (empty map falls back to default)
-// then executes the cmd specified.
-//
-// Simply hooks up os.Stdin/err/out to the command and calls Run()
-//
-// If you want more fine grained control over your command it's recommended
-// that you use `Load()` or `Read()` and the `os/exec` package yourself.
-func Exec(filenames []string, cmd string, cmdArgs []string) error {
- Load(filenames...)
-
- command := exec.Command(cmd, cmdArgs...)
- command.Stdin = os.Stdin
- command.Stdout = os.Stdout
- command.Stderr = os.Stderr
- return command.Run()
-}
-
-// Write serializes the given environment and writes it to a file
-func Write(envMap map[string]string, filename string) error {
- content, error := Marshal(envMap)
- if error != nil {
- return error
- }
- file, error := os.Create(filename)
- if error != nil {
- return error
- }
- _, err := file.WriteString(content)
- return err
-}
-
-// Marshal outputs the given environment as a dotenv-formatted environment file.
-// Each line is in the format: KEY="VALUE" where VALUE is backslash-escaped.
-func Marshal(envMap map[string]string) (string, error) {
- lines := make([]string, 0, len(envMap))
- for k, v := range envMap {
- lines = append(lines, fmt.Sprintf(`%s="%s"`, k, doubleQuoteEscape(v)))
- }
- sort.Strings(lines)
- return strings.Join(lines, "\n"), nil
-}
-
-func filenamesOrDefault(filenames []string) []string {
- if len(filenames) == 0 {
- return []string{".env"}
- }
- return filenames
-}
-
-func loadFile(filename string, overload bool) error {
- envMap, err := readFile(filename)
- if err != nil {
- return err
- }
-
- currentEnv := map[string]bool{}
- rawEnv := os.Environ()
- for _, rawEnvLine := range rawEnv {
- key := strings.Split(rawEnvLine, "=")[0]
- currentEnv[key] = true
- }
-
- for key, value := range envMap {
- if !currentEnv[key] || overload {
- os.Setenv(key, value)
- }
- }
-
- return nil
-}
-
-func readFile(filename string) (envMap map[string]string, err error) {
- file, err := os.Open(filename)
- if err != nil {
- return
- }
- defer file.Close()
-
- return Parse(file)
-}
-
-func parseLine(line string, envMap map[string]string) (key string, value string, err error) {
- if len(line) == 0 {
- err = errors.New("zero length string")
- return
- }
-
- // ditch the comments (but keep quoted hashes)
- if strings.Contains(line, "#") {
- segmentsBetweenHashes := strings.Split(line, "#")
- quotesAreOpen := false
- var segmentsToKeep []string
- for _, segment := range segmentsBetweenHashes {
- if strings.Count(segment, "\"") == 1 || strings.Count(segment, "'") == 1 {
- if quotesAreOpen {
- quotesAreOpen = false
- segmentsToKeep = append(segmentsToKeep, segment)
- } else {
- quotesAreOpen = true
- }
- }
-
- if len(segmentsToKeep) == 0 || quotesAreOpen {
- segmentsToKeep = append(segmentsToKeep, segment)
- }
- }
-
- line = strings.Join(segmentsToKeep, "#")
- }
-
- firstEquals := strings.Index(line, "=")
- firstColon := strings.Index(line, ":")
- splitString := strings.SplitN(line, "=", 2)
- if firstColon != -1 && (firstColon < firstEquals || firstEquals == -1) {
- //this is a yaml-style line
- splitString = strings.SplitN(line, ":", 2)
- }
-
- if len(splitString) != 2 {
- err = errors.New("Can't separate key from value")
- return
- }
-
- // Parse the key
- key = splitString[0]
- if strings.HasPrefix(key, "export") {
- key = strings.TrimPrefix(key, "export")
- }
- key = strings.Trim(key, " ")
-
- // Parse the value
- value = parseValue(splitString[1], envMap)
- return
-}
-
-func parseValue(value string, envMap map[string]string) string {
-
- // trim
- value = strings.Trim(value, " ")
-
- // check if we've got quoted values or possible escapes
- if len(value) > 1 {
- rs := regexp.MustCompile(`\A'(.*)'\z`)
- singleQuotes := rs.FindStringSubmatch(value)
-
- rd := regexp.MustCompile(`\A"(.*)"\z`)
- doubleQuotes := rd.FindStringSubmatch(value)
-
- if singleQuotes != nil || doubleQuotes != nil {
- // pull the quotes off the edges
- value = value[1 : len(value)-1]
- }
-
- if doubleQuotes != nil {
- // expand newlines
- escapeRegex := regexp.MustCompile(`\\.`)
- value = escapeRegex.ReplaceAllStringFunc(value, func(match string) string {
- c := strings.TrimPrefix(match, `\`)
- switch c {
- case "n":
- return "\n"
- case "r":
- return "\r"
- default:
- return match
- }
- })
- // unescape characters
- e := regexp.MustCompile(`\\([^$])`)
- value = e.ReplaceAllString(value, "$1")
- }
-
- if singleQuotes == nil {
- value = expandVariables(value, envMap)
- }
- }
-
- return value
-}
-
-func expandVariables(v string, m map[string]string) string {
- r := regexp.MustCompile(`(\\)?(\$)(\()?\{?([A-Z0-9_]+)?\}?`)
-
- return r.ReplaceAllStringFunc(v, func(s string) string {
- submatch := r.FindStringSubmatch(s)
-
- if submatch == nil {
- return s
- }
- if submatch[1] == "\\" || submatch[2] == "(" {
- return submatch[0][1:]
- } else if submatch[4] != "" {
- return m[submatch[4]]
- }
- return s
- })
-}
-
-func isIgnoredLine(line string) bool {
- trimmedLine := strings.Trim(line, " \n\t")
- return len(trimmedLine) == 0 || strings.HasPrefix(trimmedLine, "#")
-}
-
-func doubleQuoteEscape(line string) string {
- for _, c := range doubleQuoteSpecialChars {
- toReplace := "\\" + string(c)
- if c == '\n' {
- toReplace = `\n`
- }
- if c == '\r' {
- toReplace = `\r`
- }
- line = strings.Replace(line, string(c), toReplace, -1)
- }
- return line
-}
diff --git a/vendor/github.com/justinas/alice/.travis.yml b/vendor/github.com/justinas/alice/.travis.yml
deleted file mode 100644
index dc6bea671b0..00000000000
--- a/vendor/github.com/justinas/alice/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: go
-
-matrix:
- include:
- - go: 1.0.x
- - go: 1.1.x
- - go: 1.2.x
- - go: 1.3.x
- - go: 1.4.x
- - go: 1.5.x
- - go: 1.6.x
- - go: 1.7.x
- - go: 1.8.x
- - go: 1.9.x
- - go: tip
- allow_failures:
- - go: tip
diff --git a/vendor/github.com/justinas/alice/LICENSE b/vendor/github.com/justinas/alice/LICENSE
deleted file mode 100644
index 0d0d352ecc3..00000000000
--- a/vendor/github.com/justinas/alice/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Justinas Stankevicius
-
-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.
diff --git a/vendor/github.com/justinas/alice/README.md b/vendor/github.com/justinas/alice/README.md
deleted file mode 100644
index e4f9157c0e4..00000000000
--- a/vendor/github.com/justinas/alice/README.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# Alice
-
-[![GoDoc](https://godoc.org/github.com/golang/gddo?status.svg)](http://godoc.org/github.com/justinas/alice)
-[![Build Status](https://travis-ci.org/justinas/alice.svg?branch=master)](https://travis-ci.org/justinas/alice)
-[![Coverage](http://gocover.io/_badge/github.com/justinas/alice)](http://gocover.io/github.com/justinas/alice)
-
-Alice provides a convenient way to chain
-your HTTP middleware functions and the app handler.
-
-In short, it transforms
-
-```go
-Middleware1(Middleware2(Middleware3(App)))
-```
-
-to
-
-```go
-alice.New(Middleware1, Middleware2, Middleware3).Then(App)
-```
-
-### Why?
-
-None of the other middleware chaining solutions
-behaves exactly like Alice.
-Alice is as minimal as it gets:
-in essence, it's just a for loop that does the wrapping for you.
-
-Check out [this blog post](http://justinas.org/alice-painless-middleware-chaining-for-go/)
-for explanation how Alice is different from other chaining solutions.
-
-### Usage
-
-Your middleware constructors should have the form of
-
-```go
-func (http.Handler) http.Handler
-```
-
-Some middleware provide this out of the box.
-For ones that don't, it's trivial to write one yourself.
-
-```go
-func myStripPrefix(h http.Handler) http.Handler {
- return http.StripPrefix("/old", h)
-}
-```
-
-This complete example shows the full power of Alice.
-
-```go
-package main
-
-import (
- "net/http"
- "time"
-
- "github.com/throttled/throttled"
- "github.com/justinas/alice"
- "github.com/justinas/nosurf"
-)
-
-func timeoutHandler(h http.Handler) http.Handler {
- return http.TimeoutHandler(h, 1*time.Second, "timed out")
-}
-
-func myApp(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte("Hello world!"))
-}
-
-func main() {
- th := throttled.Interval(throttled.PerSec(10), 1, &throttled.VaryBy{Path: true}, 50)
- myHandler := http.HandlerFunc(myApp)
-
- chain := alice.New(th.Throttle, timeoutHandler, nosurf.NewPure).Then(myHandler)
- http.ListenAndServe(":8000", chain)
-}
-```
-
-Here, the request will pass [throttled](https://github.com/PuerkitoBio/throttled) first,
-then an http.TimeoutHandler we've set up,
-then [nosurf](https://github.com/justinas/nosurf)
-and will finally reach our handler.
-
-Note that Alice makes **no guarantees** for
-how one or another piece of middleware will behave.
-Once it passes the execution to the outer layer of middleware,
-it has no saying in whether middleware will execute the inner handlers.
-This is intentional behavior.
-
-Alice works with Go 1.0 and higher.
-
-### Contributing
-
-0. Find an issue that bugs you / open a new one.
-1. Discuss.
-2. Branch off, commit, test.
-3. Make a pull request / attach the commits to the issue.
diff --git a/vendor/github.com/justinas/alice/chain.go b/vendor/github.com/justinas/alice/chain.go
deleted file mode 100644
index da0e2b58061..00000000000
--- a/vendor/github.com/justinas/alice/chain.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Package alice provides a convenient way to chain http handlers.
-package alice
-
-import "net/http"
-
-// A constructor for a piece of middleware.
-// Some middleware use this constructor out of the box,
-// so in most cases you can just pass somepackage.New
-type Constructor func(http.Handler) http.Handler
-
-// Chain acts as a list of http.Handler constructors.
-// Chain is effectively immutable:
-// once created, it will always hold
-// the same set of constructors in the same order.
-type Chain struct {
- constructors []Constructor
-}
-
-// New creates a new chain,
-// memorizing the given list of middleware constructors.
-// New serves no other function,
-// constructors are only called upon a call to Then().
-func New(constructors ...Constructor) Chain {
- return Chain{append(([]Constructor)(nil), constructors...)}
-}
-
-// Then chains the middleware and returns the final http.Handler.
-// New(m1, m2, m3).Then(h)
-// is equivalent to:
-// m1(m2(m3(h)))
-// When the request comes in, it will be passed to m1, then m2, then m3
-// and finally, the given handler
-// (assuming every middleware calls the following one).
-//
-// A chain can be safely reused by calling Then() several times.
-// stdStack := alice.New(ratelimitHandler, csrfHandler)
-// indexPipe = stdStack.Then(indexHandler)
-// authPipe = stdStack.Then(authHandler)
-// Note that constructors are called on every call to Then()
-// and thus several instances of the same middleware will be created
-// when a chain is reused in this way.
-// For proper middleware, this should cause no problems.
-//
-// Then() treats nil as http.DefaultServeMux.
-func (c Chain) Then(h http.Handler) http.Handler {
- if h == nil {
- h = http.DefaultServeMux
- }
-
- for i := range c.constructors {
- h = c.constructors[len(c.constructors)-1-i](h)
- }
-
- return h
-}
-
-// ThenFunc works identically to Then, but takes
-// a HandlerFunc instead of a Handler.
-//
-// The following two statements are equivalent:
-// c.Then(http.HandlerFunc(fn))
-// c.ThenFunc(fn)
-//
-// ThenFunc provides all the guarantees of Then.
-func (c Chain) ThenFunc(fn http.HandlerFunc) http.Handler {
- if fn == nil {
- return c.Then(nil)
- }
- return c.Then(fn)
-}
-
-// Append extends a chain, adding the specified constructors
-// as the last ones in the request flow.
-//
-// Append returns a new chain, leaving the original one untouched.
-//
-// stdChain := alice.New(m1, m2)
-// extChain := stdChain.Append(m3, m4)
-// // requests in stdChain go m1 -> m2
-// // requests in extChain go m1 -> m2 -> m3 -> m4
-func (c Chain) Append(constructors ...Constructor) Chain {
- newCons := make([]Constructor, 0, len(c.constructors)+len(constructors))
- newCons = append(newCons, c.constructors...)
- newCons = append(newCons, constructors...)
-
- return Chain{newCons}
-}
-
-// Extend extends a chain by adding the specified chain
-// as the last one in the request flow.
-//
-// Extend returns a new chain, leaving the original one untouched.
-//
-// stdChain := alice.New(m1, m2)
-// ext1Chain := alice.New(m3, m4)
-// ext2Chain := stdChain.Extend(ext1Chain)
-// // requests in stdChain go m1 -> m2
-// // requests in ext1Chain go m3 -> m4
-// // requests in ext2Chain go m1 -> m2 -> m3 -> m4
-//
-// Another example:
-// aHtmlAfterNosurf := alice.New(m2)
-// aHtml := alice.New(m1, func(h http.Handler) http.Handler {
-// csrf := nosurf.New(h)
-// csrf.SetFailureHandler(aHtmlAfterNosurf.ThenFunc(csrfFail))
-// return csrf
-// }).Extend(aHtmlAfterNosurf)
-// // requests to aHtml hitting nosurfs success handler go m1 -> nosurf -> m2 -> target-handler
-// // requests to aHtml hitting nosurfs failure handler go m1 -> nosurf -> m2 -> csrfFail
-func (c Chain) Extend(chain Chain) Chain {
- return c.Append(chain.constructors...)
-}
diff --git a/vendor/github.com/kelseyhightower/envconfig/.travis.yml b/vendor/github.com/kelseyhightower/envconfig/.travis.yml
deleted file mode 100644
index 04b97aed616..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/.travis.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-language: go
-
-go:
- - 1.4.x
- - 1.5.x
- - 1.6.x
- - 1.7.x
- - 1.8.x
- - 1.9.x
- - 1.10.x
- - 1.11.x
- - 1.12.x
- - tip
diff --git a/vendor/github.com/kelseyhightower/envconfig/LICENSE b/vendor/github.com/kelseyhightower/envconfig/LICENSE
deleted file mode 100644
index 4bfa7a84d81..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2013 Kelsey Hightower
-
-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.
diff --git a/vendor/github.com/kelseyhightower/envconfig/MAINTAINERS b/vendor/github.com/kelseyhightower/envconfig/MAINTAINERS
deleted file mode 100644
index 6527a9f2cc2..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/MAINTAINERS
+++ /dev/null
@@ -1,2 +0,0 @@
-Kelsey Hightower kelsey.hightower@gmail.com github.com/kelseyhightower
-Travis Parker travis.parker@gmail.com github.com/teepark
diff --git a/vendor/github.com/kelseyhightower/envconfig/README.md b/vendor/github.com/kelseyhightower/envconfig/README.md
deleted file mode 100644
index 33408d645e4..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/README.md
+++ /dev/null
@@ -1,192 +0,0 @@
-# envconfig
-
-[![Build Status](https://travis-ci.org/kelseyhightower/envconfig.svg)](https://travis-ci.org/kelseyhightower/envconfig)
-
-```Go
-import "github.com/kelseyhightower/envconfig"
-```
-
-## Documentation
-
-See [godoc](http://godoc.org/github.com/kelseyhightower/envconfig)
-
-## Usage
-
-Set some environment variables:
-
-```Bash
-export MYAPP_DEBUG=false
-export MYAPP_PORT=8080
-export MYAPP_USER=Kelsey
-export MYAPP_RATE="0.5"
-export MYAPP_TIMEOUT="3m"
-export MYAPP_USERS="rob,ken,robert"
-export MYAPP_COLORCODES="red:1,green:2,blue:3"
-```
-
-Write some code:
-
-```Go
-package main
-
-import (
- "fmt"
- "log"
- "time"
-
- "github.com/kelseyhightower/envconfig"
-)
-
-type Specification struct {
- Debug bool
- Port int
- User string
- Users []string
- Rate float32
- Timeout time.Duration
- ColorCodes map[string]int
-}
-
-func main() {
- var s Specification
- err := envconfig.Process("myapp", &s)
- if err != nil {
- log.Fatal(err.Error())
- }
- format := "Debug: %v\nPort: %d\nUser: %s\nRate: %f\nTimeout: %s\n"
- _, err = fmt.Printf(format, s.Debug, s.Port, s.User, s.Rate, s.Timeout)
- if err != nil {
- log.Fatal(err.Error())
- }
-
- fmt.Println("Users:")
- for _, u := range s.Users {
- fmt.Printf(" %s\n", u)
- }
-
- fmt.Println("Color codes:")
- for k, v := range s.ColorCodes {
- fmt.Printf(" %s: %d\n", k, v)
- }
-}
-```
-
-Results:
-
-```Bash
-Debug: false
-Port: 8080
-User: Kelsey
-Rate: 0.500000
-Timeout: 3m0s
-Users:
- rob
- ken
- robert
-Color codes:
- red: 1
- green: 2
- blue: 3
-```
-
-## Struct Tag Support
-
-Envconfig supports the use of struct tags to specify alternate, default, and required
-environment variables.
-
-For example, consider the following struct:
-
-```Go
-type Specification struct {
- ManualOverride1 string `envconfig:"manual_override_1"`
- DefaultVar string `default:"foobar"`
- RequiredVar string `required:"true"`
- IgnoredVar string `ignored:"true"`
- AutoSplitVar string `split_words:"true"`
- RequiredAndAutoSplitVar string `required:"true" split_words:"true"`
-}
-```
-
-Envconfig has automatic support for CamelCased struct elements when the
-`split_words:"true"` tag is supplied. Without this tag, `AutoSplitVar` above
-would look for an environment variable called `MYAPP_AUTOSPLITVAR`. With the
-setting applied it will look for `MYAPP_AUTO_SPLIT_VAR`. Note that numbers
-will get globbed into the previous word. If the setting does not do the
-right thing, you may use a manual override.
-
-Envconfig will process value for `ManualOverride1` by populating it with the
-value for `MYAPP_MANUAL_OVERRIDE_1`. Without this struct tag, it would have
-instead looked up `MYAPP_MANUALOVERRIDE1`. With the `split_words:"true"` tag
-it would have looked up `MYAPP_MANUAL_OVERRIDE1`.
-
-```Bash
-export MYAPP_MANUAL_OVERRIDE_1="this will be the value"
-
-# export MYAPP_MANUALOVERRIDE1="and this will not"
-```
-
-If envconfig can't find an environment variable value for `MYAPP_DEFAULTVAR`,
-it will populate it with "foobar" as a default value.
-
-If envconfig can't find an environment variable value for `MYAPP_REQUIREDVAR`,
-it will return an error when asked to process the struct. If
-`MYAPP_REQUIREDVAR` is present but empty, envconfig will not return an error.
-
-If envconfig can't find an environment variable in the form `PREFIX_MYVAR`, and there
-is a struct tag defined, it will try to populate your variable with an environment
-variable that directly matches the envconfig tag in your struct definition:
-
-```shell
-export SERVICE_HOST=127.0.0.1
-export MYAPP_DEBUG=true
-```
-```Go
-type Specification struct {
- ServiceHost string `envconfig:"SERVICE_HOST"`
- Debug bool
-}
-```
-
-Envconfig won't process a field with the "ignored" tag set to "true", even if a corresponding
-environment variable is set.
-
-## Supported Struct Field Types
-
-envconfig supports these struct field types:
-
- * string
- * int8, int16, int32, int64
- * bool
- * float32, float64
- * slices of any supported type
- * maps (keys and values of any supported type)
- * [encoding.TextUnmarshaler](https://golang.org/pkg/encoding/#TextUnmarshaler)
- * [encoding.BinaryUnmarshaler](https://golang.org/pkg/encoding/#BinaryUnmarshaler)
- * [time.Duration](https://golang.org/pkg/time/#Duration)
-
-Embedded structs using these fields are also supported.
-
-## Custom Decoders
-
-Any field whose type (or pointer-to-type) implements `envconfig.Decoder` can
-control its own deserialization:
-
-```Bash
-export DNS_SERVER=8.8.8.8
-```
-
-```Go
-type IPDecoder net.IP
-
-func (ipd *IPDecoder) Decode(value string) error {
- *ipd = IPDecoder(net.ParseIP(value))
- return nil
-}
-
-type DNSConfig struct {
- Address IPDecoder `envconfig:"DNS_SERVER"`
-}
-```
-
-Also, envconfig will use a `Set(string) error` method like from the
-[flag.Value](https://godoc.org/flag#Value) interface if implemented.
diff --git a/vendor/github.com/kelseyhightower/envconfig/doc.go b/vendor/github.com/kelseyhightower/envconfig/doc.go
deleted file mode 100644
index f28561cd1cb..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/doc.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2013 Kelsey Hightower. All rights reserved.
-// Use of this source code is governed by the MIT License that can be found in
-// the LICENSE file.
-
-// Package envconfig implements decoding of environment variables based on a user
-// defined specification. A typical use is using environment variables for
-// configuration settings.
-package envconfig
diff --git a/vendor/github.com/kelseyhightower/envconfig/env_os.go b/vendor/github.com/kelseyhightower/envconfig/env_os.go
deleted file mode 100644
index eba07a6c613..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/env_os.go
+++ /dev/null
@@ -1,7 +0,0 @@
-// +build appengine go1.5
-
-package envconfig
-
-import "os"
-
-var lookupEnv = os.LookupEnv
diff --git a/vendor/github.com/kelseyhightower/envconfig/env_syscall.go b/vendor/github.com/kelseyhightower/envconfig/env_syscall.go
deleted file mode 100644
index 42545400807..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/env_syscall.go
+++ /dev/null
@@ -1,7 +0,0 @@
-// +build !appengine,!go1.5
-
-package envconfig
-
-import "syscall"
-
-var lookupEnv = syscall.Getenv
diff --git a/vendor/github.com/kelseyhightower/envconfig/envconfig.go b/vendor/github.com/kelseyhightower/envconfig/envconfig.go
deleted file mode 100644
index 3f16108db8a..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/envconfig.go
+++ /dev/null
@@ -1,382 +0,0 @@
-// Copyright (c) 2013 Kelsey Hightower. All rights reserved.
-// Use of this source code is governed by the MIT License that can be found in
-// the LICENSE file.
-
-package envconfig
-
-import (
- "encoding"
- "errors"
- "fmt"
- "os"
- "reflect"
- "regexp"
- "strconv"
- "strings"
- "time"
-)
-
-// ErrInvalidSpecification indicates that a specification is of the wrong type.
-var ErrInvalidSpecification = errors.New("specification must be a struct pointer")
-
-var gatherRegexp = regexp.MustCompile("([^A-Z]+|[A-Z]+[^A-Z]+|[A-Z]+)")
-var acronymRegexp = regexp.MustCompile("([A-Z]+)([A-Z][^A-Z]+)")
-
-// A ParseError occurs when an environment variable cannot be converted to
-// the type required by a struct field during assignment.
-type ParseError struct {
- KeyName string
- FieldName string
- TypeName string
- Value string
- Err error
-}
-
-// Decoder has the same semantics as Setter, but takes higher precedence.
-// It is provided for historical compatibility.
-type Decoder interface {
- Decode(value string) error
-}
-
-// Setter is implemented by types can self-deserialize values.
-// Any type that implements flag.Value also implements Setter.
-type Setter interface {
- Set(value string) error
-}
-
-func (e *ParseError) Error() string {
- return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s. details: %[5]s", e.KeyName, e.FieldName, e.Value, e.TypeName, e.Err)
-}
-
-// varInfo maintains information about the configuration variable
-type varInfo struct {
- Name string
- Alt string
- Key string
- Field reflect.Value
- Tags reflect.StructTag
-}
-
-// GatherInfo gathers information about the specified struct
-func gatherInfo(prefix string, spec interface{}) ([]varInfo, error) {
- s := reflect.ValueOf(spec)
-
- if s.Kind() != reflect.Ptr {
- return nil, ErrInvalidSpecification
- }
- s = s.Elem()
- if s.Kind() != reflect.Struct {
- return nil, ErrInvalidSpecification
- }
- typeOfSpec := s.Type()
-
- // over allocate an info array, we will extend if needed later
- infos := make([]varInfo, 0, s.NumField())
- for i := 0; i < s.NumField(); i++ {
- f := s.Field(i)
- ftype := typeOfSpec.Field(i)
- if !f.CanSet() || isTrue(ftype.Tag.Get("ignored")) {
- continue
- }
-
- for f.Kind() == reflect.Ptr {
- if f.IsNil() {
- if f.Type().Elem().Kind() != reflect.Struct {
- // nil pointer to a non-struct: leave it alone
- break
- }
- // nil pointer to struct: create a zero instance
- f.Set(reflect.New(f.Type().Elem()))
- }
- f = f.Elem()
- }
-
- // Capture information about the config variable
- info := varInfo{
- Name: ftype.Name,
- Field: f,
- Tags: ftype.Tag,
- Alt: strings.ToUpper(ftype.Tag.Get("envconfig")),
- }
-
- // Default to the field name as the env var name (will be upcased)
- info.Key = info.Name
-
- // Best effort to un-pick camel casing as separate words
- if isTrue(ftype.Tag.Get("split_words")) {
- words := gatherRegexp.FindAllStringSubmatch(ftype.Name, -1)
- if len(words) > 0 {
- var name []string
- for _, words := range words {
- if m := acronymRegexp.FindStringSubmatch(words[0]); len(m) == 3 {
- name = append(name, m[1], m[2])
- } else {
- name = append(name, words[0])
- }
- }
-
- info.Key = strings.Join(name, "_")
- }
- }
- if info.Alt != "" {
- info.Key = info.Alt
- }
- if prefix != "" {
- info.Key = fmt.Sprintf("%s_%s", prefix, info.Key)
- }
- info.Key = strings.ToUpper(info.Key)
- infos = append(infos, info)
-
- if f.Kind() == reflect.Struct {
- // honor Decode if present
- if decoderFrom(f) == nil && setterFrom(f) == nil && textUnmarshaler(f) == nil && binaryUnmarshaler(f) == nil {
- innerPrefix := prefix
- if !ftype.Anonymous {
- innerPrefix = info.Key
- }
-
- embeddedPtr := f.Addr().Interface()
- embeddedInfos, err := gatherInfo(innerPrefix, embeddedPtr)
- if err != nil {
- return nil, err
- }
- infos = append(infos[:len(infos)-1], embeddedInfos...)
-
- continue
- }
- }
- }
- return infos, nil
-}
-
-// CheckDisallowed checks that no environment variables with the prefix are set
-// that we don't know how or want to parse. This is likely only meaningful with
-// a non-empty prefix.
-func CheckDisallowed(prefix string, spec interface{}) error {
- infos, err := gatherInfo(prefix, spec)
- if err != nil {
- return err
- }
-
- vars := make(map[string]struct{})
- for _, info := range infos {
- vars[info.Key] = struct{}{}
- }
-
- if prefix != "" {
- prefix = strings.ToUpper(prefix) + "_"
- }
-
- for _, env := range os.Environ() {
- if !strings.HasPrefix(env, prefix) {
- continue
- }
- v := strings.SplitN(env, "=", 2)[0]
- if _, found := vars[v]; !found {
- return fmt.Errorf("unknown environment variable %s", v)
- }
- }
-
- return nil
-}
-
-// Process populates the specified struct based on environment variables
-func Process(prefix string, spec interface{}) error {
- infos, err := gatherInfo(prefix, spec)
-
- for _, info := range infos {
-
- // `os.Getenv` cannot differentiate between an explicitly set empty value
- // and an unset value. `os.LookupEnv` is preferred to `syscall.Getenv`,
- // but it is only available in go1.5 or newer. We're using Go build tags
- // here to use os.LookupEnv for >=go1.5
- value, ok := lookupEnv(info.Key)
- if !ok && info.Alt != "" {
- value, ok = lookupEnv(info.Alt)
- }
-
- def := info.Tags.Get("default")
- if def != "" && !ok {
- value = def
- }
-
- req := info.Tags.Get("required")
- if !ok && def == "" {
- if isTrue(req) {
- key := info.Key
- if info.Alt != "" {
- key = info.Alt
- }
- return fmt.Errorf("required key %s missing value", key)
- }
- continue
- }
-
- err = processField(value, info.Field)
- if err != nil {
- return &ParseError{
- KeyName: info.Key,
- FieldName: info.Name,
- TypeName: info.Field.Type().String(),
- Value: value,
- Err: err,
- }
- }
- }
-
- return err
-}
-
-// MustProcess is the same as Process but panics if an error occurs
-func MustProcess(prefix string, spec interface{}) {
- if err := Process(prefix, spec); err != nil {
- panic(err)
- }
-}
-
-func processField(value string, field reflect.Value) error {
- typ := field.Type()
-
- decoder := decoderFrom(field)
- if decoder != nil {
- return decoder.Decode(value)
- }
- // look for Set method if Decode not defined
- setter := setterFrom(field)
- if setter != nil {
- return setter.Set(value)
- }
-
- if t := textUnmarshaler(field); t != nil {
- return t.UnmarshalText([]byte(value))
- }
-
- if b := binaryUnmarshaler(field); b != nil {
- return b.UnmarshalBinary([]byte(value))
- }
-
- if typ.Kind() == reflect.Ptr {
- typ = typ.Elem()
- if field.IsNil() {
- field.Set(reflect.New(typ))
- }
- field = field.Elem()
- }
-
- switch typ.Kind() {
- case reflect.String:
- field.SetString(value)
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- var (
- val int64
- err error
- )
- if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" {
- var d time.Duration
- d, err = time.ParseDuration(value)
- val = int64(d)
- } else {
- val, err = strconv.ParseInt(value, 0, typ.Bits())
- }
- if err != nil {
- return err
- }
-
- field.SetInt(val)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- val, err := strconv.ParseUint(value, 0, typ.Bits())
- if err != nil {
- return err
- }
- field.SetUint(val)
- case reflect.Bool:
- val, err := strconv.ParseBool(value)
- if err != nil {
- return err
- }
- field.SetBool(val)
- case reflect.Float32, reflect.Float64:
- val, err := strconv.ParseFloat(value, typ.Bits())
- if err != nil {
- return err
- }
- field.SetFloat(val)
- case reflect.Slice:
- sl := reflect.MakeSlice(typ, 0, 0)
- if typ.Elem().Kind() == reflect.Uint8 {
- sl = reflect.ValueOf([]byte(value))
- } else if len(strings.TrimSpace(value)) != 0 {
- vals := strings.Split(value, ",")
- sl = reflect.MakeSlice(typ, len(vals), len(vals))
- for i, val := range vals {
- err := processField(val, sl.Index(i))
- if err != nil {
- return err
- }
- }
- }
- field.Set(sl)
- case reflect.Map:
- mp := reflect.MakeMap(typ)
- if len(strings.TrimSpace(value)) != 0 {
- pairs := strings.Split(value, ",")
- for _, pair := range pairs {
- kvpair := strings.Split(pair, ":")
- if len(kvpair) != 2 {
- return fmt.Errorf("invalid map item: %q", pair)
- }
- k := reflect.New(typ.Key()).Elem()
- err := processField(kvpair[0], k)
- if err != nil {
- return err
- }
- v := reflect.New(typ.Elem()).Elem()
- err = processField(kvpair[1], v)
- if err != nil {
- return err
- }
- mp.SetMapIndex(k, v)
- }
- }
- field.Set(mp)
- }
-
- return nil
-}
-
-func interfaceFrom(field reflect.Value, fn func(interface{}, *bool)) {
- // it may be impossible for a struct field to fail this check
- if !field.CanInterface() {
- return
- }
- var ok bool
- fn(field.Interface(), &ok)
- if !ok && field.CanAddr() {
- fn(field.Addr().Interface(), &ok)
- }
-}
-
-func decoderFrom(field reflect.Value) (d Decoder) {
- interfaceFrom(field, func(v interface{}, ok *bool) { d, *ok = v.(Decoder) })
- return d
-}
-
-func setterFrom(field reflect.Value) (s Setter) {
- interfaceFrom(field, func(v interface{}, ok *bool) { s, *ok = v.(Setter) })
- return s
-}
-
-func textUnmarshaler(field reflect.Value) (t encoding.TextUnmarshaler) {
- interfaceFrom(field, func(v interface{}, ok *bool) { t, *ok = v.(encoding.TextUnmarshaler) })
- return t
-}
-
-func binaryUnmarshaler(field reflect.Value) (b encoding.BinaryUnmarshaler) {
- interfaceFrom(field, func(v interface{}, ok *bool) { b, *ok = v.(encoding.BinaryUnmarshaler) })
- return b
-}
-
-func isTrue(s string) bool {
- b, _ := strconv.ParseBool(s)
- return b
-}
diff --git a/vendor/github.com/kelseyhightower/envconfig/go.mod b/vendor/github.com/kelseyhightower/envconfig/go.mod
deleted file mode 100644
index 1561d1e4e04..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/kelseyhightower/envconfig
diff --git a/vendor/github.com/kelseyhightower/envconfig/usage.go b/vendor/github.com/kelseyhightower/envconfig/usage.go
deleted file mode 100644
index 1e6d0a8f367..00000000000
--- a/vendor/github.com/kelseyhightower/envconfig/usage.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) 2016 Kelsey Hightower and others. All rights reserved.
-// Use of this source code is governed by the MIT License that can be found in
-// the LICENSE file.
-
-package envconfig
-
-import (
- "encoding"
- "fmt"
- "io"
- "os"
- "reflect"
- "strconv"
- "strings"
- "text/tabwriter"
- "text/template"
-)
-
-const (
- // DefaultListFormat constant to use to display usage in a list format
- DefaultListFormat = `This application is configured via the environment. The following environment
-variables can be used:
-{{range .}}
-{{usage_key .}}
- [description] {{usage_description .}}
- [type] {{usage_type .}}
- [default] {{usage_default .}}
- [required] {{usage_required .}}{{end}}
-`
- // DefaultTableFormat constant to use to display usage in a tabular format
- DefaultTableFormat = `This application is configured via the environment. The following environment
-variables can be used:
-
-KEY TYPE DEFAULT REQUIRED DESCRIPTION
-{{range .}}{{usage_key .}} {{usage_type .}} {{usage_default .}} {{usage_required .}} {{usage_description .}}
-{{end}}`
-)
-
-var (
- decoderType = reflect.TypeOf((*Decoder)(nil)).Elem()
- setterType = reflect.TypeOf((*Setter)(nil)).Elem()
- textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
- binaryUnmarshalerType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
-)
-
-func implementsInterface(t reflect.Type) bool {
- return t.Implements(decoderType) ||
- reflect.PtrTo(t).Implements(decoderType) ||
- t.Implements(setterType) ||
- reflect.PtrTo(t).Implements(setterType) ||
- t.Implements(textUnmarshalerType) ||
- reflect.PtrTo(t).Implements(textUnmarshalerType) ||
- t.Implements(binaryUnmarshalerType) ||
- reflect.PtrTo(t).Implements(binaryUnmarshalerType)
-}
-
-// toTypeDescription converts Go types into a human readable description
-func toTypeDescription(t reflect.Type) string {
- switch t.Kind() {
- case reflect.Array, reflect.Slice:
- if t.Elem().Kind() == reflect.Uint8 {
- return "String"
- }
- return fmt.Sprintf("Comma-separated list of %s", toTypeDescription(t.Elem()))
- case reflect.Map:
- return fmt.Sprintf(
- "Comma-separated list of %s:%s pairs",
- toTypeDescription(t.Key()),
- toTypeDescription(t.Elem()),
- )
- case reflect.Ptr:
- return toTypeDescription(t.Elem())
- case reflect.Struct:
- if implementsInterface(t) && t.Name() != "" {
- return t.Name()
- }
- return ""
- case reflect.String:
- name := t.Name()
- if name != "" && name != "string" {
- return name
- }
- return "String"
- case reflect.Bool:
- name := t.Name()
- if name != "" && name != "bool" {
- return name
- }
- return "True or False"
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- name := t.Name()
- if name != "" && !strings.HasPrefix(name, "int") {
- return name
- }
- return "Integer"
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- name := t.Name()
- if name != "" && !strings.HasPrefix(name, "uint") {
- return name
- }
- return "Unsigned Integer"
- case reflect.Float32, reflect.Float64:
- name := t.Name()
- if name != "" && !strings.HasPrefix(name, "float") {
- return name
- }
- return "Float"
- }
- return fmt.Sprintf("%+v", t)
-}
-
-// Usage writes usage information to stdout using the default header and table format
-func Usage(prefix string, spec interface{}) error {
- // The default is to output the usage information as a table
- // Create tabwriter instance to support table output
- tabs := tabwriter.NewWriter(os.Stdout, 1, 0, 4, ' ', 0)
-
- err := Usagef(prefix, spec, tabs, DefaultTableFormat)
- tabs.Flush()
- return err
-}
-
-// Usagef writes usage information to the specified io.Writer using the specifed template specification
-func Usagef(prefix string, spec interface{}, out io.Writer, format string) error {
-
- // Specify the default usage template functions
- functions := template.FuncMap{
- "usage_key": func(v varInfo) string { return v.Key },
- "usage_description": func(v varInfo) string { return v.Tags.Get("desc") },
- "usage_type": func(v varInfo) string { return toTypeDescription(v.Field.Type()) },
- "usage_default": func(v varInfo) string { return v.Tags.Get("default") },
- "usage_required": func(v varInfo) (string, error) {
- req := v.Tags.Get("required")
- if req != "" {
- reqB, err := strconv.ParseBool(req)
- if err != nil {
- return "", err
- }
- if reqB {
- req = "true"
- }
- }
- return req, nil
- },
- }
-
- tmpl, err := template.New("envconfig").Funcs(functions).Parse(format)
- if err != nil {
- return err
- }
-
- return Usaget(prefix, spec, out, tmpl)
-}
-
-// Usaget writes usage information to the specified io.Writer using the specified template
-func Usaget(prefix string, spec interface{}, out io.Writer, tmpl *template.Template) error {
- // gather first
- infos, err := gatherInfo(prefix, spec)
- if err != nil {
- return err
- }
-
- return tmpl.Execute(out, infos)
-}
diff --git a/vendor/github.com/klauspost/compress/LICENSE b/vendor/github.com/klauspost/compress/LICENSE
deleted file mode 100644
index 1eb75ef68e4..00000000000
--- a/vendor/github.com/klauspost/compress/LICENSE
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright (c) 2012 The Go Authors. All rights reserved.
-Copyright (c) 2019 Klaus Post. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/klauspost/compress/flate/deflate.go b/vendor/github.com/klauspost/compress/flate/deflate.go
deleted file mode 100644
index 25dbe3e15f4..00000000000
--- a/vendor/github.com/klauspost/compress/flate/deflate.go
+++ /dev/null
@@ -1,821 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Copyright (c) 2015 Klaus Post
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-import (
- "fmt"
- "io"
- "math"
-)
-
-const (
- NoCompression = 0
- BestSpeed = 1
- BestCompression = 9
- DefaultCompression = -1
-
- // HuffmanOnly disables Lempel-Ziv match searching and only performs Huffman
- // entropy encoding. This mode is useful in compressing data that has
- // already been compressed with an LZ style algorithm (e.g. Snappy or LZ4)
- // that lacks an entropy encoder. Compression gains are achieved when
- // certain bytes in the input stream occur more frequently than others.
- //
- // Note that HuffmanOnly produces a compressed output that is
- // RFC 1951 compliant. That is, any valid DEFLATE decompressor will
- // continue to be able to decompress this output.
- HuffmanOnly = -2
- ConstantCompression = HuffmanOnly // compatibility alias.
-
- logWindowSize = 15
- windowSize = 1 << logWindowSize
- windowMask = windowSize - 1
- logMaxOffsetSize = 15 // Standard DEFLATE
- minMatchLength = 4 // The smallest match that the compressor looks for
- maxMatchLength = 258 // The longest match for the compressor
- minOffsetSize = 1 // The shortest offset that makes any sense
-
- // The maximum number of tokens we put into a single flat block, just too
- // stop things from getting too large.
- maxFlateBlockTokens = 1 << 14
- maxStoreBlockSize = 65535
- hashBits = 17 // After 17 performance degrades
- hashSize = 1 << hashBits
- hashMask = (1 << hashBits) - 1
- hashShift = (hashBits + minMatchLength - 1) / minMatchLength
- maxHashOffset = 1 << 24
-
- skipNever = math.MaxInt32
-
- debugDeflate = false
-)
-
-type compressionLevel struct {
- good, lazy, nice, chain, fastSkipHashing, level int
-}
-
-// Compression levels have been rebalanced from zlib deflate defaults
-// to give a bigger spread in speed and compression.
-// See https://blog.klauspost.com/rebalancing-deflate-compression-levels/
-var levels = []compressionLevel{
- {}, // 0
- // Level 1-6 uses specialized algorithm - values not used
- {0, 0, 0, 0, 0, 1},
- {0, 0, 0, 0, 0, 2},
- {0, 0, 0, 0, 0, 3},
- {0, 0, 0, 0, 0, 4},
- {0, 0, 0, 0, 0, 5},
- {0, 0, 0, 0, 0, 6},
- // Levels 7-9 use increasingly more lazy matching
- // and increasingly stringent conditions for "good enough".
- {8, 8, 24, 16, skipNever, 7},
- {10, 16, 24, 64, skipNever, 8},
- {32, 258, 258, 4096, skipNever, 9},
-}
-
-// advancedState contains state for the advanced levels, with bigger hash tables, etc.
-type advancedState struct {
- // deflate state
- length int
- offset int
- maxInsertIndex int
-
- // Input hash chains
- // hashHead[hashValue] contains the largest inputIndex with the specified hash value
- // If hashHead[hashValue] is within the current window, then
- // hashPrev[hashHead[hashValue] & windowMask] contains the previous index
- // with the same hash value.
- chainHead int
- hashHead [hashSize]uint32
- hashPrev [windowSize]uint32
- hashOffset int
-
- // input window: unprocessed data is window[index:windowEnd]
- index int
- hashMatch [maxMatchLength + minMatchLength]uint32
-
- hash uint32
- ii uint16 // position of last match, intended to overflow to reset.
-}
-
-type compressor struct {
- compressionLevel
-
- w *huffmanBitWriter
-
- // compression algorithm
- fill func(*compressor, []byte) int // copy data to window
- step func(*compressor) // process window
-
- window []byte
- windowEnd int
- blockStart int // window index where current tokens start
- err error
-
- // queued output tokens
- tokens tokens
- fast fastEnc
- state *advancedState
-
- sync bool // requesting flush
- byteAvailable bool // if true, still need to process window[index-1].
-}
-
-func (d *compressor) fillDeflate(b []byte) int {
- s := d.state
- if s.index >= 2*windowSize-(minMatchLength+maxMatchLength) {
- // shift the window by windowSize
- copy(d.window[:], d.window[windowSize:2*windowSize])
- s.index -= windowSize
- d.windowEnd -= windowSize
- if d.blockStart >= windowSize {
- d.blockStart -= windowSize
- } else {
- d.blockStart = math.MaxInt32
- }
- s.hashOffset += windowSize
- if s.hashOffset > maxHashOffset {
- delta := s.hashOffset - 1
- s.hashOffset -= delta
- s.chainHead -= delta
- // Iterate over slices instead of arrays to avoid copying
- // the entire table onto the stack (Issue #18625).
- for i, v := range s.hashPrev[:] {
- if int(v) > delta {
- s.hashPrev[i] = uint32(int(v) - delta)
- } else {
- s.hashPrev[i] = 0
- }
- }
- for i, v := range s.hashHead[:] {
- if int(v) > delta {
- s.hashHead[i] = uint32(int(v) - delta)
- } else {
- s.hashHead[i] = 0
- }
- }
- }
- }
- n := copy(d.window[d.windowEnd:], b)
- d.windowEnd += n
- return n
-}
-
-func (d *compressor) writeBlock(tok *tokens, index int, eof bool) error {
- if index > 0 || eof {
- var window []byte
- if d.blockStart <= index {
- window = d.window[d.blockStart:index]
- }
- d.blockStart = index
- d.w.writeBlock(tok, eof, window)
- return d.w.err
- }
- return nil
-}
-
-// writeBlockSkip writes the current block and uses the number of tokens
-// to determine if the block should be stored on no matches, or
-// only huffman encoded.
-func (d *compressor) writeBlockSkip(tok *tokens, index int, eof bool) error {
- if index > 0 || eof {
- if d.blockStart <= index {
- window := d.window[d.blockStart:index]
- // If we removed less than a 64th of all literals
- // we huffman compress the block.
- if int(tok.n) > len(window)-int(tok.n>>6) {
- d.w.writeBlockHuff(eof, window, d.sync)
- } else {
- // Write a dynamic huffman block.
- d.w.writeBlockDynamic(tok, eof, window, d.sync)
- }
- } else {
- d.w.writeBlock(tok, eof, nil)
- }
- d.blockStart = index
- return d.w.err
- }
- return nil
-}
-
-// fillWindow will fill the current window with the supplied
-// dictionary and calculate all hashes.
-// This is much faster than doing a full encode.
-// Should only be used after a start/reset.
-func (d *compressor) fillWindow(b []byte) {
- // Do not fill window if we are in store-only or huffman mode.
- if d.level <= 0 {
- return
- }
- if d.fast != nil {
- // encode the last data, but discard the result
- if len(b) > maxMatchOffset {
- b = b[len(b)-maxMatchOffset:]
- }
- d.fast.Encode(&d.tokens, b)
- d.tokens.Reset()
- return
- }
- s := d.state
- // If we are given too much, cut it.
- if len(b) > windowSize {
- b = b[len(b)-windowSize:]
- }
- // Add all to window.
- n := copy(d.window[d.windowEnd:], b)
-
- // Calculate 256 hashes at the time (more L1 cache hits)
- loops := (n + 256 - minMatchLength) / 256
- for j := 0; j < loops; j++ {
- startindex := j * 256
- end := startindex + 256 + minMatchLength - 1
- if end > n {
- end = n
- }
- tocheck := d.window[startindex:end]
- dstSize := len(tocheck) - minMatchLength + 1
-
- if dstSize <= 0 {
- continue
- }
-
- dst := s.hashMatch[:dstSize]
- bulkHash4(tocheck, dst)
- var newH uint32
- for i, val := range dst {
- di := i + startindex
- newH = val & hashMask
- // Get previous value with the same hash.
- // Our chain should point to the previous value.
- s.hashPrev[di&windowMask] = s.hashHead[newH]
- // Set the head of the hash chain to us.
- s.hashHead[newH] = uint32(di + s.hashOffset)
- }
- s.hash = newH
- }
- // Update window information.
- d.windowEnd += n
- s.index = n
-}
-
-// Try to find a match starting at index whose length is greater than prevSize.
-// We only look at chainCount possibilities before giving up.
-// pos = s.index, prevHead = s.chainHead-s.hashOffset, prevLength=minMatchLength-1, lookahead
-func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
- minMatchLook := maxMatchLength
- if lookahead < minMatchLook {
- minMatchLook = lookahead
- }
-
- win := d.window[0 : pos+minMatchLook]
-
- // We quit when we get a match that's at least nice long
- nice := len(win) - pos
- if d.nice < nice {
- nice = d.nice
- }
-
- // If we've got a match that's good enough, only look in 1/4 the chain.
- tries := d.chain
- length = prevLength
- if length >= d.good {
- tries >>= 2
- }
-
- wEnd := win[pos+length]
- wPos := win[pos:]
- minIndex := pos - windowSize
-
- for i := prevHead; tries > 0; tries-- {
- if wEnd == win[i+length] {
- n := matchLen(win[i:i+minMatchLook], wPos)
-
- if n > length && (n > minMatchLength || pos-i <= 4096) {
- length = n
- offset = pos - i
- ok = true
- if n >= nice {
- // The match is good enough that we don't try to find a better one.
- break
- }
- wEnd = win[pos+n]
- }
- }
- if i == minIndex {
- // hashPrev[i & windowMask] has already been overwritten, so stop now.
- break
- }
- i = int(d.state.hashPrev[i&windowMask]) - d.state.hashOffset
- if i < minIndex || i < 0 {
- break
- }
- }
- return
-}
-
-func (d *compressor) writeStoredBlock(buf []byte) error {
- if d.w.writeStoredHeader(len(buf), false); d.w.err != nil {
- return d.w.err
- }
- d.w.writeBytes(buf)
- return d.w.err
-}
-
-// hash4 returns a hash representation of the first 4 bytes
-// of the supplied slice.
-// The caller must ensure that len(b) >= 4.
-func hash4(b []byte) uint32 {
- b = b[:4]
- return hash4u(uint32(b[3])|uint32(b[2])<<8|uint32(b[1])<<16|uint32(b[0])<<24, hashBits)
-}
-
-// bulkHash4 will compute hashes using the same
-// algorithm as hash4
-func bulkHash4(b []byte, dst []uint32) {
- if len(b) < 4 {
- return
- }
- hb := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
- dst[0] = hash4u(hb, hashBits)
- end := len(b) - 4 + 1
- for i := 1; i < end; i++ {
- hb = (hb << 8) | uint32(b[i+3])
- dst[i] = hash4u(hb, hashBits)
- }
-}
-
-func (d *compressor) initDeflate() {
- d.window = make([]byte, 2*windowSize)
- d.byteAvailable = false
- d.err = nil
- if d.state == nil {
- return
- }
- s := d.state
- s.index = 0
- s.hashOffset = 1
- s.length = minMatchLength - 1
- s.offset = 0
- s.hash = 0
- s.chainHead = -1
-}
-
-// deflateLazy is the same as deflate, but with d.fastSkipHashing == skipNever,
-// meaning it always has lazy matching on.
-func (d *compressor) deflateLazy() {
- s := d.state
- // Sanity enables additional runtime tests.
- // It's intended to be used during development
- // to supplement the currently ad-hoc unit tests.
- const sanity = debugDeflate
-
- if d.windowEnd-s.index < minMatchLength+maxMatchLength && !d.sync {
- return
- }
-
- s.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
- if s.index < s.maxInsertIndex {
- s.hash = hash4(d.window[s.index : s.index+minMatchLength])
- }
-
- for {
- if sanity && s.index > d.windowEnd {
- panic("index > windowEnd")
- }
- lookahead := d.windowEnd - s.index
- if lookahead < minMatchLength+maxMatchLength {
- if !d.sync {
- return
- }
- if sanity && s.index > d.windowEnd {
- panic("index > windowEnd")
- }
- if lookahead == 0 {
- // Flush current output block if any.
- if d.byteAvailable {
- // There is still one pending token that needs to be flushed
- d.tokens.AddLiteral(d.window[s.index-1])
- d.byteAvailable = false
- }
- if d.tokens.n > 0 {
- if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
- return
- }
- d.tokens.Reset()
- }
- return
- }
- }
- if s.index < s.maxInsertIndex {
- // Update the hash
- s.hash = hash4(d.window[s.index : s.index+minMatchLength])
- ch := s.hashHead[s.hash&hashMask]
- s.chainHead = int(ch)
- s.hashPrev[s.index&windowMask] = ch
- s.hashHead[s.hash&hashMask] = uint32(s.index + s.hashOffset)
- }
- prevLength := s.length
- prevOffset := s.offset
- s.length = minMatchLength - 1
- s.offset = 0
- minIndex := s.index - windowSize
- if minIndex < 0 {
- minIndex = 0
- }
-
- if s.chainHead-s.hashOffset >= minIndex && lookahead > prevLength && prevLength < d.lazy {
- if newLength, newOffset, ok := d.findMatch(s.index, s.chainHead-s.hashOffset, minMatchLength-1, lookahead); ok {
- s.length = newLength
- s.offset = newOffset
- }
- }
- if prevLength >= minMatchLength && s.length <= prevLength {
- // There was a match at the previous step, and the current match is
- // not better. Output the previous match.
- d.tokens.AddMatch(uint32(prevLength-3), uint32(prevOffset-minOffsetSize))
-
- // Insert in the hash table all strings up to the end of the match.
- // index and index-1 are already inserted. If there is not enough
- // lookahead, the last two strings are not inserted into the hash
- // table.
- var newIndex int
- newIndex = s.index + prevLength - 1
- // Calculate missing hashes
- end := newIndex
- if end > s.maxInsertIndex {
- end = s.maxInsertIndex
- }
- end += minMatchLength - 1
- startindex := s.index + 1
- if startindex > s.maxInsertIndex {
- startindex = s.maxInsertIndex
- }
- tocheck := d.window[startindex:end]
- dstSize := len(tocheck) - minMatchLength + 1
- if dstSize > 0 {
- dst := s.hashMatch[:dstSize]
- bulkHash4(tocheck, dst)
- var newH uint32
- for i, val := range dst {
- di := i + startindex
- newH = val & hashMask
- // Get previous value with the same hash.
- // Our chain should point to the previous value.
- s.hashPrev[di&windowMask] = s.hashHead[newH]
- // Set the head of the hash chain to us.
- s.hashHead[newH] = uint32(di + s.hashOffset)
- }
- s.hash = newH
- }
-
- s.index = newIndex
- d.byteAvailable = false
- s.length = minMatchLength - 1
- if d.tokens.n == maxFlateBlockTokens {
- // The block includes the current character
- if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
- return
- }
- d.tokens.Reset()
- }
- } else {
- // Reset, if we got a match this run.
- if s.length >= minMatchLength {
- s.ii = 0
- }
- // We have a byte waiting. Emit it.
- if d.byteAvailable {
- s.ii++
- d.tokens.AddLiteral(d.window[s.index-1])
- if d.tokens.n == maxFlateBlockTokens {
- if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
- return
- }
- d.tokens.Reset()
- }
- s.index++
-
- // If we have a long run of no matches, skip additional bytes
- // Resets when s.ii overflows after 64KB.
- if s.ii > 31 {
- n := int(s.ii >> 5)
- for j := 0; j < n; j++ {
- if s.index >= d.windowEnd-1 {
- break
- }
-
- d.tokens.AddLiteral(d.window[s.index-1])
- if d.tokens.n == maxFlateBlockTokens {
- if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
- return
- }
- d.tokens.Reset()
- }
- s.index++
- }
- // Flush last byte
- d.tokens.AddLiteral(d.window[s.index-1])
- d.byteAvailable = false
- // s.length = minMatchLength - 1 // not needed, since s.ii is reset above, so it should never be > minMatchLength
- if d.tokens.n == maxFlateBlockTokens {
- if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
- return
- }
- d.tokens.Reset()
- }
- }
- } else {
- s.index++
- d.byteAvailable = true
- }
- }
- }
-}
-
-func (d *compressor) store() {
- if d.windowEnd > 0 && (d.windowEnd == maxStoreBlockSize || d.sync) {
- d.err = d.writeStoredBlock(d.window[:d.windowEnd])
- d.windowEnd = 0
- }
-}
-
-// fillWindow will fill the buffer with data for huffman-only compression.
-// The number of bytes copied is returned.
-func (d *compressor) fillBlock(b []byte) int {
- n := copy(d.window[d.windowEnd:], b)
- d.windowEnd += n
- return n
-}
-
-// storeHuff will compress and store the currently added data,
-// if enough has been accumulated or we at the end of the stream.
-// Any error that occurred will be in d.err
-func (d *compressor) storeHuff() {
- if d.windowEnd < len(d.window) && !d.sync || d.windowEnd == 0 {
- return
- }
- d.w.writeBlockHuff(false, d.window[:d.windowEnd], d.sync)
- d.err = d.w.err
- d.windowEnd = 0
-}
-
-// storeFast will compress and store the currently added data,
-// if enough has been accumulated or we at the end of the stream.
-// Any error that occurred will be in d.err
-func (d *compressor) storeFast() {
- // We only compress if we have maxStoreBlockSize.
- if d.windowEnd < len(d.window) {
- if !d.sync {
- return
- }
- // Handle extremely small sizes.
- if d.windowEnd < 128 {
- if d.windowEnd == 0 {
- return
- }
- if d.windowEnd <= 32 {
- d.err = d.writeStoredBlock(d.window[:d.windowEnd])
- } else {
- d.w.writeBlockHuff(false, d.window[:d.windowEnd], true)
- d.err = d.w.err
- }
- d.tokens.Reset()
- d.windowEnd = 0
- d.fast.Reset()
- return
- }
- }
-
- d.fast.Encode(&d.tokens, d.window[:d.windowEnd])
- // If we made zero matches, store the block as is.
- if d.tokens.n == 0 {
- d.err = d.writeStoredBlock(d.window[:d.windowEnd])
- // If we removed less than 1/16th, huffman compress the block.
- } else if int(d.tokens.n) > d.windowEnd-(d.windowEnd>>4) {
- d.w.writeBlockHuff(false, d.window[:d.windowEnd], d.sync)
- d.err = d.w.err
- } else {
- d.w.writeBlockDynamic(&d.tokens, false, d.window[:d.windowEnd], d.sync)
- d.err = d.w.err
- }
- d.tokens.Reset()
- d.windowEnd = 0
-}
-
-// write will add input byte to the stream.
-// Unless an error occurs all bytes will be consumed.
-func (d *compressor) write(b []byte) (n int, err error) {
- if d.err != nil {
- return 0, d.err
- }
- n = len(b)
- for len(b) > 0 {
- d.step(d)
- b = b[d.fill(d, b):]
- if d.err != nil {
- return 0, d.err
- }
- }
- return n, d.err
-}
-
-func (d *compressor) syncFlush() error {
- d.sync = true
- if d.err != nil {
- return d.err
- }
- d.step(d)
- if d.err == nil {
- d.w.writeStoredHeader(0, false)
- d.w.flush()
- d.err = d.w.err
- }
- d.sync = false
- return d.err
-}
-
-func (d *compressor) init(w io.Writer, level int) (err error) {
- d.w = newHuffmanBitWriter(w)
-
- switch {
- case level == NoCompression:
- d.window = make([]byte, maxStoreBlockSize)
- d.fill = (*compressor).fillBlock
- d.step = (*compressor).store
- case level == ConstantCompression:
- d.w.logNewTablePenalty = 4
- d.window = make([]byte, maxStoreBlockSize)
- d.fill = (*compressor).fillBlock
- d.step = (*compressor).storeHuff
- case level == DefaultCompression:
- level = 5
- fallthrough
- case level >= 1 && level <= 6:
- d.w.logNewTablePenalty = 6
- d.fast = newFastEnc(level)
- d.window = make([]byte, maxStoreBlockSize)
- d.fill = (*compressor).fillBlock
- d.step = (*compressor).storeFast
- case 7 <= level && level <= 9:
- d.w.logNewTablePenalty = 10
- d.state = &advancedState{}
- d.compressionLevel = levels[level]
- d.initDeflate()
- d.fill = (*compressor).fillDeflate
- d.step = (*compressor).deflateLazy
- default:
- return fmt.Errorf("flate: invalid compression level %d: want value in range [-2, 9]", level)
- }
- d.level = level
- return nil
-}
-
-// reset the state of the compressor.
-func (d *compressor) reset(w io.Writer) {
- d.w.reset(w)
- d.sync = false
- d.err = nil
- // We only need to reset a few things for Snappy.
- if d.fast != nil {
- d.fast.Reset()
- d.windowEnd = 0
- d.tokens.Reset()
- return
- }
- switch d.compressionLevel.chain {
- case 0:
- // level was NoCompression or ConstantCompresssion.
- d.windowEnd = 0
- default:
- s := d.state
- s.chainHead = -1
- for i := range s.hashHead {
- s.hashHead[i] = 0
- }
- for i := range s.hashPrev {
- s.hashPrev[i] = 0
- }
- s.hashOffset = 1
- s.index, d.windowEnd = 0, 0
- d.blockStart, d.byteAvailable = 0, false
- d.tokens.Reset()
- s.length = minMatchLength - 1
- s.offset = 0
- s.hash = 0
- s.ii = 0
- s.maxInsertIndex = 0
- }
-}
-
-func (d *compressor) close() error {
- if d.err != nil {
- return d.err
- }
- d.sync = true
- d.step(d)
- if d.err != nil {
- return d.err
- }
- if d.w.writeStoredHeader(0, true); d.w.err != nil {
- return d.w.err
- }
- d.w.flush()
- d.w.reset(nil)
- return d.w.err
-}
-
-// NewWriter returns a new Writer compressing data at the given level.
-// Following zlib, levels range from 1 (BestSpeed) to 9 (BestCompression);
-// higher levels typically run slower but compress more.
-// Level 0 (NoCompression) does not attempt any compression; it only adds the
-// necessary DEFLATE framing.
-// Level -1 (DefaultCompression) uses the default compression level.
-// Level -2 (ConstantCompression) will use Huffman compression only, giving
-// a very fast compression for all types of input, but sacrificing considerable
-// compression efficiency.
-//
-// If level is in the range [-2, 9] then the error returned will be nil.
-// Otherwise the error returned will be non-nil.
-func NewWriter(w io.Writer, level int) (*Writer, error) {
- var dw Writer
- if err := dw.d.init(w, level); err != nil {
- return nil, err
- }
- return &dw, nil
-}
-
-// NewWriterDict is like NewWriter but initializes the new
-// Writer with a preset dictionary. The returned Writer behaves
-// as if the dictionary had been written to it without producing
-// any compressed output. The compressed data written to w
-// can only be decompressed by a Reader initialized with the
-// same dictionary.
-func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) {
- zw, err := NewWriter(w, level)
- if err != nil {
- return nil, err
- }
- zw.d.fillWindow(dict)
- zw.dict = append(zw.dict, dict...) // duplicate dictionary for Reset method.
- return zw, err
-}
-
-// A Writer takes data written to it and writes the compressed
-// form of that data to an underlying writer (see NewWriter).
-type Writer struct {
- d compressor
- dict []byte
-}
-
-// Write writes data to w, which will eventually write the
-// compressed form of data to its underlying writer.
-func (w *Writer) Write(data []byte) (n int, err error) {
- return w.d.write(data)
-}
-
-// Flush flushes any pending data to the underlying writer.
-// It is useful mainly in compressed network protocols, to ensure that
-// a remote reader has enough data to reconstruct a packet.
-// Flush does not return until the data has been written.
-// Calling Flush when there is no pending data still causes the Writer
-// to emit a sync marker of at least 4 bytes.
-// If the underlying writer returns an error, Flush returns that error.
-//
-// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
-func (w *Writer) Flush() error {
- // For more about flushing:
- // http://www.bolet.org/~pornin/deflate-flush.html
- return w.d.syncFlush()
-}
-
-// Close flushes and closes the writer.
-func (w *Writer) Close() error {
- return w.d.close()
-}
-
-// Reset discards the writer's state and makes it equivalent to
-// the result of NewWriter or NewWriterDict called with dst
-// and w's level and dictionary.
-func (w *Writer) Reset(dst io.Writer) {
- if len(w.dict) > 0 {
- // w was created with NewWriterDict
- w.d.reset(dst)
- if dst != nil {
- w.d.fillWindow(w.dict)
- }
- } else {
- // w was created with NewWriter
- w.d.reset(dst)
- }
-}
-
-// ResetDict discards the writer's state and makes it equivalent to
-// the result of NewWriter or NewWriterDict called with dst
-// and w's level, but sets a specific dictionary.
-func (w *Writer) ResetDict(dst io.Writer, dict []byte) {
- w.dict = dict
- w.d.reset(dst)
- w.d.fillWindow(w.dict)
-}
diff --git a/vendor/github.com/klauspost/compress/flate/dict_decoder.go b/vendor/github.com/klauspost/compress/flate/dict_decoder.go
deleted file mode 100644
index 71c75a065ea..00000000000
--- a/vendor/github.com/klauspost/compress/flate/dict_decoder.go
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-// dictDecoder implements the LZ77 sliding dictionary as used in decompression.
-// LZ77 decompresses data through sequences of two forms of commands:
-//
-// * Literal insertions: Runs of one or more symbols are inserted into the data
-// stream as is. This is accomplished through the writeByte method for a
-// single symbol, or combinations of writeSlice/writeMark for multiple symbols.
-// Any valid stream must start with a literal insertion if no preset dictionary
-// is used.
-//
-// * Backward copies: Runs of one or more symbols are copied from previously
-// emitted data. Backward copies come as the tuple (dist, length) where dist
-// determines how far back in the stream to copy from and length determines how
-// many bytes to copy. Note that it is valid for the length to be greater than
-// the distance. Since LZ77 uses forward copies, that situation is used to
-// perform a form of run-length encoding on repeated runs of symbols.
-// The writeCopy and tryWriteCopy are used to implement this command.
-//
-// For performance reasons, this implementation performs little to no sanity
-// checks about the arguments. As such, the invariants documented for each
-// method call must be respected.
-type dictDecoder struct {
- hist []byte // Sliding window history
-
- // Invariant: 0 <= rdPos <= wrPos <= len(hist)
- wrPos int // Current output position in buffer
- rdPos int // Have emitted hist[:rdPos] already
- full bool // Has a full window length been written yet?
-}
-
-// init initializes dictDecoder to have a sliding window dictionary of the given
-// size. If a preset dict is provided, it will initialize the dictionary with
-// the contents of dict.
-func (dd *dictDecoder) init(size int, dict []byte) {
- *dd = dictDecoder{hist: dd.hist}
-
- if cap(dd.hist) < size {
- dd.hist = make([]byte, size)
- }
- dd.hist = dd.hist[:size]
-
- if len(dict) > len(dd.hist) {
- dict = dict[len(dict)-len(dd.hist):]
- }
- dd.wrPos = copy(dd.hist, dict)
- if dd.wrPos == len(dd.hist) {
- dd.wrPos = 0
- dd.full = true
- }
- dd.rdPos = dd.wrPos
-}
-
-// histSize reports the total amount of historical data in the dictionary.
-func (dd *dictDecoder) histSize() int {
- if dd.full {
- return len(dd.hist)
- }
- return dd.wrPos
-}
-
-// availRead reports the number of bytes that can be flushed by readFlush.
-func (dd *dictDecoder) availRead() int {
- return dd.wrPos - dd.rdPos
-}
-
-// availWrite reports the available amount of output buffer space.
-func (dd *dictDecoder) availWrite() int {
- return len(dd.hist) - dd.wrPos
-}
-
-// writeSlice returns a slice of the available buffer to write data to.
-//
-// This invariant will be kept: len(s) <= availWrite()
-func (dd *dictDecoder) writeSlice() []byte {
- return dd.hist[dd.wrPos:]
-}
-
-// writeMark advances the writer pointer by cnt.
-//
-// This invariant must be kept: 0 <= cnt <= availWrite()
-func (dd *dictDecoder) writeMark(cnt int) {
- dd.wrPos += cnt
-}
-
-// writeByte writes a single byte to the dictionary.
-//
-// This invariant must be kept: 0 < availWrite()
-func (dd *dictDecoder) writeByte(c byte) {
- dd.hist[dd.wrPos] = c
- dd.wrPos++
-}
-
-// writeCopy copies a string at a given (dist, length) to the output.
-// This returns the number of bytes copied and may be less than the requested
-// length if the available space in the output buffer is too small.
-//
-// This invariant must be kept: 0 < dist <= histSize()
-func (dd *dictDecoder) writeCopy(dist, length int) int {
- dstBase := dd.wrPos
- dstPos := dstBase
- srcPos := dstPos - dist
- endPos := dstPos + length
- if endPos > len(dd.hist) {
- endPos = len(dd.hist)
- }
-
- // Copy non-overlapping section after destination position.
- //
- // This section is non-overlapping in that the copy length for this section
- // is always less than or equal to the backwards distance. This can occur
- // if a distance refers to data that wraps-around in the buffer.
- // Thus, a backwards copy is performed here; that is, the exact bytes in
- // the source prior to the copy is placed in the destination.
- if srcPos < 0 {
- srcPos += len(dd.hist)
- dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:])
- srcPos = 0
- }
-
- // Copy possibly overlapping section before destination position.
- //
- // This section can overlap if the copy length for this section is larger
- // than the backwards distance. This is allowed by LZ77 so that repeated
- // strings can be succinctly represented using (dist, length) pairs.
- // Thus, a forwards copy is performed here; that is, the bytes copied is
- // possibly dependent on the resulting bytes in the destination as the copy
- // progresses along. This is functionally equivalent to the following:
- //
- // for i := 0; i < endPos-dstPos; i++ {
- // dd.hist[dstPos+i] = dd.hist[srcPos+i]
- // }
- // dstPos = endPos
- //
- for dstPos < endPos {
- dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos])
- }
-
- dd.wrPos = dstPos
- return dstPos - dstBase
-}
-
-// tryWriteCopy tries to copy a string at a given (distance, length) to the
-// output. This specialized version is optimized for short distances.
-//
-// This method is designed to be inlined for performance reasons.
-//
-// This invariant must be kept: 0 < dist <= histSize()
-func (dd *dictDecoder) tryWriteCopy(dist, length int) int {
- dstPos := dd.wrPos
- endPos := dstPos + length
- if dstPos < dist || endPos > len(dd.hist) {
- return 0
- }
- dstBase := dstPos
- srcPos := dstPos - dist
-
- // Copy possibly overlapping section before destination position.
-loop:
- dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos])
- if dstPos < endPos {
- goto loop // Avoid for-loop so that this function can be inlined
- }
-
- dd.wrPos = dstPos
- return dstPos - dstBase
-}
-
-// readFlush returns a slice of the historical buffer that is ready to be
-// emitted to the user. The data returned by readFlush must be fully consumed
-// before calling any other dictDecoder methods.
-func (dd *dictDecoder) readFlush() []byte {
- toRead := dd.hist[dd.rdPos:dd.wrPos]
- dd.rdPos = dd.wrPos
- if dd.wrPos == len(dd.hist) {
- dd.wrPos, dd.rdPos = 0, 0
- dd.full = true
- }
- return toRead
-}
diff --git a/vendor/github.com/klauspost/compress/flate/fast_encoder.go b/vendor/github.com/klauspost/compress/flate/fast_encoder.go
deleted file mode 100644
index 6d4c1e98bc5..00000000000
--- a/vendor/github.com/klauspost/compress/flate/fast_encoder.go
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright 2011 The Snappy-Go Authors. All rights reserved.
-// Modified for deflate by Klaus Post (c) 2015.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-import (
- "fmt"
- "math/bits"
-)
-
-type fastEnc interface {
- Encode(dst *tokens, src []byte)
- Reset()
-}
-
-func newFastEnc(level int) fastEnc {
- switch level {
- case 1:
- return &fastEncL1{fastGen: fastGen{cur: maxStoreBlockSize}}
- case 2:
- return &fastEncL2{fastGen: fastGen{cur: maxStoreBlockSize}}
- case 3:
- return &fastEncL3{fastGen: fastGen{cur: maxStoreBlockSize}}
- case 4:
- return &fastEncL4{fastGen: fastGen{cur: maxStoreBlockSize}}
- case 5:
- return &fastEncL5{fastGen: fastGen{cur: maxStoreBlockSize}}
- case 6:
- return &fastEncL6{fastGen: fastGen{cur: maxStoreBlockSize}}
- default:
- panic("invalid level specified")
- }
-}
-
-const (
- tableBits = 15 // Bits used in the table
- tableSize = 1 << tableBits // Size of the table
- tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32.
- baseMatchOffset = 1 // The smallest match offset
- baseMatchLength = 3 // The smallest match length per the RFC section 3.2.5
- maxMatchOffset = 1 << 15 // The largest match offset
-
- bTableBits = 17 // Bits used in the big tables
- bTableSize = 1 << bTableBits // Size of the table
- allocHistory = maxStoreBlockSize * 10 // Size to preallocate for history.
- bufferReset = (1 << 31) - allocHistory - maxStoreBlockSize - 1 // Reset the buffer offset when reaching this.
-)
-
-const (
- prime3bytes = 506832829
- prime4bytes = 2654435761
- prime5bytes = 889523592379
- prime6bytes = 227718039650203
- prime7bytes = 58295818150454627
- prime8bytes = 0xcf1bbcdcb7a56463
-)
-
-func load32(b []byte, i int) uint32 {
- // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
- b = b[i:]
- b = b[:4]
- return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
-}
-
-func load64(b []byte, i int) uint64 {
- // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
- b = b[i:]
- b = b[:8]
- return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
- uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
-}
-
-func load3232(b []byte, i int32) uint32 {
- // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
- b = b[i:]
- b = b[:4]
- return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
-}
-
-func load6432(b []byte, i int32) uint64 {
- // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
- b = b[i:]
- b = b[:8]
- return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
- uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
-}
-
-func hash(u uint32) uint32 {
- return (u * 0x1e35a7bd) >> tableShift
-}
-
-type tableEntry struct {
- offset int32
-}
-
-// fastGen maintains the table for matches,
-// and the previous byte block for level 2.
-// This is the generic implementation.
-type fastGen struct {
- hist []byte
- cur int32
-}
-
-func (e *fastGen) addBlock(src []byte) int32 {
- // check if we have space already
- if len(e.hist)+len(src) > cap(e.hist) {
- if cap(e.hist) == 0 {
- e.hist = make([]byte, 0, allocHistory)
- } else {
- if cap(e.hist) < maxMatchOffset*2 {
- panic("unexpected buffer size")
- }
- // Move down
- offset := int32(len(e.hist)) - maxMatchOffset
- copy(e.hist[0:maxMatchOffset], e.hist[offset:])
- e.cur += offset
- e.hist = e.hist[:maxMatchOffset]
- }
- }
- s := int32(len(e.hist))
- e.hist = append(e.hist, src...)
- return s
-}
-
-// hash4 returns the hash of u to fit in a hash table with h bits.
-// Preferably h should be a constant and should always be <32.
-func hash4u(u uint32, h uint8) uint32 {
- return (u * prime4bytes) >> ((32 - h) & 31)
-}
-
-type tableEntryPrev struct {
- Cur tableEntry
- Prev tableEntry
-}
-
-// hash4x64 returns the hash of the lowest 4 bytes of u to fit in a hash table with h bits.
-// Preferably h should be a constant and should always be <32.
-func hash4x64(u uint64, h uint8) uint32 {
- return (uint32(u) * prime4bytes) >> ((32 - h) & 31)
-}
-
-// hash7 returns the hash of the lowest 7 bytes of u to fit in a hash table with h bits.
-// Preferably h should be a constant and should always be <64.
-func hash7(u uint64, h uint8) uint32 {
- return uint32(((u << (64 - 56)) * prime7bytes) >> ((64 - h) & 63))
-}
-
-// hash8 returns the hash of u to fit in a hash table with h bits.
-// Preferably h should be a constant and should always be <64.
-func hash8(u uint64, h uint8) uint32 {
- return uint32((u * prime8bytes) >> ((64 - h) & 63))
-}
-
-// hash6 returns the hash of the lowest 6 bytes of u to fit in a hash table with h bits.
-// Preferably h should be a constant and should always be <64.
-func hash6(u uint64, h uint8) uint32 {
- return uint32(((u << (64 - 48)) * prime6bytes) >> ((64 - h) & 63))
-}
-
-// matchlen will return the match length between offsets and t in src.
-// The maximum length returned is maxMatchLength - 4.
-// It is assumed that s > t, that t >=0 and s < len(src).
-func (e *fastGen) matchlen(s, t int32, src []byte) int32 {
- if debugDecode {
- if t >= s {
- panic(fmt.Sprint("t >=s:", t, s))
- }
- if int(s) >= len(src) {
- panic(fmt.Sprint("s >= len(src):", s, len(src)))
- }
- if t < 0 {
- panic(fmt.Sprint("t < 0:", t))
- }
- if s-t > maxMatchOffset {
- panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
- }
- }
- s1 := int(s) + maxMatchLength - 4
- if s1 > len(src) {
- s1 = len(src)
- }
-
- // Extend the match to be as long as possible.
- return int32(matchLen(src[s:s1], src[t:]))
-}
-
-// matchlenLong will return the match length between offsets and t in src.
-// It is assumed that s > t, that t >=0 and s < len(src).
-func (e *fastGen) matchlenLong(s, t int32, src []byte) int32 {
- if debugDecode {
- if t >= s {
- panic(fmt.Sprint("t >=s:", t, s))
- }
- if int(s) >= len(src) {
- panic(fmt.Sprint("s >= len(src):", s, len(src)))
- }
- if t < 0 {
- panic(fmt.Sprint("t < 0:", t))
- }
- if s-t > maxMatchOffset {
- panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")"))
- }
- }
- // Extend the match to be as long as possible.
- return int32(matchLen(src[s:], src[t:]))
-}
-
-// Reset the encoding table.
-func (e *fastGen) Reset() {
- if cap(e.hist) < allocHistory {
- e.hist = make([]byte, 0, allocHistory)
- }
- // We offset current position so everything will be out of reach.
- // If we are above the buffer reset it will be cleared anyway since len(hist) == 0.
- if e.cur <= bufferReset {
- e.cur += maxMatchOffset + int32(len(e.hist))
- }
- e.hist = e.hist[:0]
-}
-
-// matchLen returns the maximum length.
-// 'a' must be the shortest of the two.
-func matchLen(a, b []byte) int {
- b = b[:len(a)]
- var checked int
- if len(a) > 4 {
- // Try 4 bytes first
- if diff := load32(a, 0) ^ load32(b, 0); diff != 0 {
- return bits.TrailingZeros32(diff) >> 3
- }
- // Switch to 8 byte matching.
- checked = 4
- a = a[4:]
- b = b[4:]
- for len(a) >= 8 {
- b = b[:len(a)]
- if diff := load64(a, 0) ^ load64(b, 0); diff != 0 {
- return checked + (bits.TrailingZeros64(diff) >> 3)
- }
- checked += 8
- a = a[8:]
- b = b[8:]
- }
- }
- b = b[:len(a)]
- for i := range a {
- if a[i] != b[i] {
- return int(i) + checked
- }
- }
- return len(a) + checked
-}
diff --git a/vendor/github.com/klauspost/compress/flate/gen_inflate.go b/vendor/github.com/klauspost/compress/flate/gen_inflate.go
deleted file mode 100644
index c74a95fe7f6..00000000000
--- a/vendor/github.com/klauspost/compress/flate/gen_inflate.go
+++ /dev/null
@@ -1,274 +0,0 @@
-// +build generate
-
-//go:generate go run $GOFILE && gofmt -w inflate_gen.go
-
-package main
-
-import (
- "os"
- "strings"
-)
-
-func main() {
- f, err := os.Create("inflate_gen.go")
- if err != nil {
- panic(err)
- }
- defer f.Close()
- types := []string{"*bytes.Buffer", "*bytes.Reader", "*bufio.Reader", "*strings.Reader"}
- names := []string{"BytesBuffer", "BytesReader", "BufioReader", "StringsReader"}
- imports := []string{"bytes", "bufio", "io", "strings", "math/bits"}
- f.WriteString(`// Code generated by go generate gen_inflate.go. DO NOT EDIT.
-
-package flate
-
-import (
-`)
-
- for _, imp := range imports {
- f.WriteString("\t\"" + imp + "\"\n")
- }
- f.WriteString(")\n\n")
-
- template := `
-
-// Decode a single Huffman block from f.
-// hl and hd are the Huffman states for the lit/length values
-// and the distance values, respectively. If hd == nil, using the
-// fixed distance encoding associated with fixed Huffman blocks.
-func (f *decompressor) $FUNCNAME$() {
- const (
- stateInit = iota // Zero value must be stateInit
- stateDict
- )
- fr := f.r.($TYPE$)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
-
- switch f.stepState {
- case stateInit:
- goto readLiteral
- case stateDict:
- goto copyHistory
- }
-
-readLiteral:
- // Read literal and/or (length, distance) according to RFC section 3.2.3.
- {
- var v int
- {
- // Inlined v, err := f.huffSym(f.hl)
- // Since a huffmanDecoder can be empty or be composed of a degenerate tree
- // with single element, huffSym must error on these two edge cases. In both
- // cases, the chunks slice will be 0 for the invalid sequence, leading it
- // satisfy the n == 0 check below.
- n := uint(f.hl.maxRead)
- // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
- // but is smart enough to keep local variables in registers, so use nb and b,
- // inline call to moreBits and reassign b,nb back to f on return.
- nb, b := f.nb, f.b
- for {
- for nb < n {
- c, err := fr.ReadByte()
- if err != nil {
- f.b = b
- f.nb = nb
- f.err = noEOF(err)
- return
- }
- f.roffset++
- b |= uint32(c) << (nb & 31)
- nb += 8
- }
- chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
- n = uint(chunk & huffmanCountMask)
- if n > huffmanChunkBits {
- chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask]
- n = uint(chunk & huffmanCountMask)
- }
- if n <= nb {
- if n == 0 {
- f.b = b
- f.nb = nb
- if debugDecode {
- fmt.Println("huffsym: n==0")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- f.b = b >> (n & 31)
- f.nb = nb - n
- v = int(chunk >> huffmanValueShift)
- break
- }
- }
- }
-
- var n uint // number of bits extra
- var length int
- var err error
- switch {
- case v < 256:
- f.dict.writeByte(byte(v))
- if f.dict.availWrite() == 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).$FUNCNAME$
- f.stepState = stateInit
- return
- }
- goto readLiteral
- case v == 256:
- f.finishBlock()
- return
- // otherwise, reference to older data
- case v < 265:
- length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
- case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
- for f.nb < n {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits n>0:", err)
- }
- f.err = err
- return
- }
- }
- length += int(f.b & uint32(1<>= n
- f.nb -= n
- }
-
- var dist int
- if f.hd == nil {
- for f.nb < 5 {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb<5:", err)
- }
- f.err = err
- return
- }
- }
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
- f.b >>= 5
- f.nb -= 5
- } else {
- if dist, err = f.huffSym(f.hd); err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
- }
- f.err = err
- return
- }
- }
-
- switch {
- case dist < 4:
- dist++
- case dist < maxNumDist:
- nb := uint(dist-2) >> 1
- // have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
- for f.nb < nb {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb>= nb
- f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
- default:
- if debugDecode {
- fmt.Println("dist too big:", dist, maxNumDist)
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- // No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
- if debugDecode {
- fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- f.copyLen, f.copyDist = length, dist
- goto copyHistory
- }
-
-copyHistory:
- // Perform a backwards copy according to RFC section 3.2.3.
- {
- cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
- if cnt == 0 {
- cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
- }
- f.copyLen -= cnt
-
- if f.dict.availWrite() == 0 || f.copyLen > 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).$FUNCNAME$ // We need to continue this work
- f.stepState = stateDict
- return
- }
- goto readLiteral
- }
-}
-
-`
- for i, t := range types {
- s := strings.Replace(template, "$FUNCNAME$", "huffman"+names[i], -1)
- s = strings.Replace(s, "$TYPE$", t, -1)
- f.WriteString(s)
- }
- f.WriteString("func (f *decompressor) huffmanBlockDecoder() func() {\n")
- f.WriteString("\tswitch f.r.(type) {\n")
- for i, t := range types {
- f.WriteString("\t\tcase " + t + ":\n")
- f.WriteString("\t\t\treturn f.huffman" + names[i] + "\n")
- }
- f.WriteString("\t\tdefault:\n")
- f.WriteString("\t\t\treturn f.huffmanBlockGeneric")
- f.WriteString("\t}\n}\n")
-}
diff --git a/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go
deleted file mode 100644
index 53fe1d06e25..00000000000
--- a/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go
+++ /dev/null
@@ -1,911 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-import (
- "io"
-)
-
-const (
- // The largest offset code.
- offsetCodeCount = 30
-
- // The special code used to mark the end of a block.
- endBlockMarker = 256
-
- // The first length code.
- lengthCodesStart = 257
-
- // The number of codegen codes.
- codegenCodeCount = 19
- badCode = 255
-
- // bufferFlushSize indicates the buffer size
- // after which bytes are flushed to the writer.
- // Should preferably be a multiple of 6, since
- // we accumulate 6 bytes between writes to the buffer.
- bufferFlushSize = 240
-
- // bufferSize is the actual output byte buffer size.
- // It must have additional headroom for a flush
- // which can contain up to 8 bytes.
- bufferSize = bufferFlushSize + 8
-)
-
-// The number of extra bits needed by length code X - LENGTH_CODES_START.
-var lengthExtraBits = [32]int8{
- /* 257 */ 0, 0, 0,
- /* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
- /* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
- /* 280 */ 4, 5, 5, 5, 5, 0,
-}
-
-// The length indicated by length code X - LENGTH_CODES_START.
-var lengthBase = [32]uint8{
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 10,
- 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
- 64, 80, 96, 112, 128, 160, 192, 224, 255,
-}
-
-// offset code word extra bits.
-var offsetExtraBits = [64]int8{
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
- 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
- 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
- /* extended window */
- 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20,
-}
-
-var offsetBase = [64]uint32{
- /* normal deflate */
- 0x000000, 0x000001, 0x000002, 0x000003, 0x000004,
- 0x000006, 0x000008, 0x00000c, 0x000010, 0x000018,
- 0x000020, 0x000030, 0x000040, 0x000060, 0x000080,
- 0x0000c0, 0x000100, 0x000180, 0x000200, 0x000300,
- 0x000400, 0x000600, 0x000800, 0x000c00, 0x001000,
- 0x001800, 0x002000, 0x003000, 0x004000, 0x006000,
-
- /* extended window */
- 0x008000, 0x00c000, 0x010000, 0x018000, 0x020000,
- 0x030000, 0x040000, 0x060000, 0x080000, 0x0c0000,
- 0x100000, 0x180000, 0x200000, 0x300000,
-}
-
-// The odd order in which the codegen code sizes are written.
-var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
-
-type huffmanBitWriter struct {
- // writer is the underlying writer.
- // Do not use it directly; use the write method, which ensures
- // that Write errors are sticky.
- writer io.Writer
-
- // Data waiting to be written is bytes[0:nbytes]
- // and then the low nbits of bits.
- bits uint64
- nbits uint16
- nbytes uint8
- literalEncoding *huffmanEncoder
- offsetEncoding *huffmanEncoder
- codegenEncoding *huffmanEncoder
- err error
- lastHeader int
- // Set between 0 (reused block can be up to 2x the size)
- logNewTablePenalty uint
- lastHuffMan bool
- bytes [256]byte
- literalFreq [lengthCodesStart + 32]uint16
- offsetFreq [32]uint16
- codegenFreq [codegenCodeCount]uint16
-
- // codegen must have an extra space for the final symbol.
- codegen [literalCount + offsetCodeCount + 1]uint8
-}
-
-// Huffman reuse.
-//
-// The huffmanBitWriter supports reusing huffman tables and thereby combining block sections.
-//
-// This is controlled by several variables:
-//
-// If lastHeader is non-zero the Huffman table can be reused.
-// This also indicates that a Huffman table has been generated that can output all
-// possible symbols.
-// It also indicates that an EOB has not yet been emitted, so if a new tabel is generated
-// an EOB with the previous table must be written.
-//
-// If lastHuffMan is set, a table for outputting literals has been generated and offsets are invalid.
-//
-// An incoming block estimates the output size of a new table using a 'fresh' by calculating the
-// optimal size and adding a penalty in 'logNewTablePenalty'.
-// A Huffman table is not optimal, which is why we add a penalty, and generating a new table
-// is slower both for compression and decompression.
-
-func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
- return &huffmanBitWriter{
- writer: w,
- literalEncoding: newHuffmanEncoder(literalCount),
- codegenEncoding: newHuffmanEncoder(codegenCodeCount),
- offsetEncoding: newHuffmanEncoder(offsetCodeCount),
- }
-}
-
-func (w *huffmanBitWriter) reset(writer io.Writer) {
- w.writer = writer
- w.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil
- w.lastHeader = 0
- w.lastHuffMan = false
-}
-
-func (w *huffmanBitWriter) canReuse(t *tokens) (offsets, lits bool) {
- offsets, lits = true, true
- a := t.offHist[:offsetCodeCount]
- b := w.offsetFreq[:len(a)]
- for i := range a {
- if b[i] == 0 && a[i] != 0 {
- offsets = false
- break
- }
- }
-
- a = t.extraHist[:literalCount-256]
- b = w.literalFreq[256:literalCount]
- b = b[:len(a)]
- for i := range a {
- if b[i] == 0 && a[i] != 0 {
- lits = false
- break
- }
- }
- if lits {
- a = t.litHist[:]
- b = w.literalFreq[:len(a)]
- for i := range a {
- if b[i] == 0 && a[i] != 0 {
- lits = false
- break
- }
- }
- }
- return
-}
-
-func (w *huffmanBitWriter) flush() {
- if w.err != nil {
- w.nbits = 0
- return
- }
- if w.lastHeader > 0 {
- // We owe an EOB
- w.writeCode(w.literalEncoding.codes[endBlockMarker])
- w.lastHeader = 0
- }
- n := w.nbytes
- for w.nbits != 0 {
- w.bytes[n] = byte(w.bits)
- w.bits >>= 8
- if w.nbits > 8 { // Avoid underflow
- w.nbits -= 8
- } else {
- w.nbits = 0
- }
- n++
- }
- w.bits = 0
- w.write(w.bytes[:n])
- w.nbytes = 0
-}
-
-func (w *huffmanBitWriter) write(b []byte) {
- if w.err != nil {
- return
- }
- _, w.err = w.writer.Write(b)
-}
-
-func (w *huffmanBitWriter) writeBits(b int32, nb uint16) {
- w.bits |= uint64(b) << (w.nbits & 63)
- w.nbits += nb
- if w.nbits >= 48 {
- w.writeOutBits()
- }
-}
-
-func (w *huffmanBitWriter) writeBytes(bytes []byte) {
- if w.err != nil {
- return
- }
- n := w.nbytes
- if w.nbits&7 != 0 {
- w.err = InternalError("writeBytes with unfinished bits")
- return
- }
- for w.nbits != 0 {
- w.bytes[n] = byte(w.bits)
- w.bits >>= 8
- w.nbits -= 8
- n++
- }
- if n != 0 {
- w.write(w.bytes[:n])
- }
- w.nbytes = 0
- w.write(bytes)
-}
-
-// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
-// the literal and offset lengths arrays (which are concatenated into a single
-// array). This method generates that run-length encoding.
-//
-// The result is written into the codegen array, and the frequencies
-// of each code is written into the codegenFreq array.
-// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
-// information. Code badCode is an end marker
-//
-// numLiterals The number of literals in literalEncoding
-// numOffsets The number of offsets in offsetEncoding
-// litenc, offenc The literal and offset encoder to use
-func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, litEnc, offEnc *huffmanEncoder) {
- for i := range w.codegenFreq {
- w.codegenFreq[i] = 0
- }
- // Note that we are using codegen both as a temporary variable for holding
- // a copy of the frequencies, and as the place where we put the result.
- // This is fine because the output is always shorter than the input used
- // so far.
- codegen := w.codegen[:] // cache
- // Copy the concatenated code sizes to codegen. Put a marker at the end.
- cgnl := codegen[:numLiterals]
- for i := range cgnl {
- cgnl[i] = uint8(litEnc.codes[i].len)
- }
-
- cgnl = codegen[numLiterals : numLiterals+numOffsets]
- for i := range cgnl {
- cgnl[i] = uint8(offEnc.codes[i].len)
- }
- codegen[numLiterals+numOffsets] = badCode
-
- size := codegen[0]
- count := 1
- outIndex := 0
- for inIndex := 1; size != badCode; inIndex++ {
- // INVARIANT: We have seen "count" copies of size that have not yet
- // had output generated for them.
- nextSize := codegen[inIndex]
- if nextSize == size {
- count++
- continue
- }
- // We need to generate codegen indicating "count" of size.
- if size != 0 {
- codegen[outIndex] = size
- outIndex++
- w.codegenFreq[size]++
- count--
- for count >= 3 {
- n := 6
- if n > count {
- n = count
- }
- codegen[outIndex] = 16
- outIndex++
- codegen[outIndex] = uint8(n - 3)
- outIndex++
- w.codegenFreq[16]++
- count -= n
- }
- } else {
- for count >= 11 {
- n := 138
- if n > count {
- n = count
- }
- codegen[outIndex] = 18
- outIndex++
- codegen[outIndex] = uint8(n - 11)
- outIndex++
- w.codegenFreq[18]++
- count -= n
- }
- if count >= 3 {
- // count >= 3 && count <= 10
- codegen[outIndex] = 17
- outIndex++
- codegen[outIndex] = uint8(count - 3)
- outIndex++
- w.codegenFreq[17]++
- count = 0
- }
- }
- count--
- for ; count >= 0; count-- {
- codegen[outIndex] = size
- outIndex++
- w.codegenFreq[size]++
- }
- // Set up invariant for next time through the loop.
- size = nextSize
- count = 1
- }
- // Marker indicating the end of the codegen.
- codegen[outIndex] = badCode
-}
-
-func (w *huffmanBitWriter) codegens() int {
- numCodegens := len(w.codegenFreq)
- for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
- numCodegens--
- }
- return numCodegens
-}
-
-func (w *huffmanBitWriter) headerSize() (size, numCodegens int) {
- numCodegens = len(w.codegenFreq)
- for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
- numCodegens--
- }
- return 3 + 5 + 5 + 4 + (3 * numCodegens) +
- w.codegenEncoding.bitLength(w.codegenFreq[:]) +
- int(w.codegenFreq[16])*2 +
- int(w.codegenFreq[17])*3 +
- int(w.codegenFreq[18])*7, numCodegens
-}
-
-// dynamicSize returns the size of dynamically encoded data in bits.
-func (w *huffmanBitWriter) dynamicReuseSize(litEnc, offEnc *huffmanEncoder) (size int) {
- size = litEnc.bitLength(w.literalFreq[:]) +
- offEnc.bitLength(w.offsetFreq[:])
- return size
-}
-
-// dynamicSize returns the size of dynamically encoded data in bits.
-func (w *huffmanBitWriter) dynamicSize(litEnc, offEnc *huffmanEncoder, extraBits int) (size, numCodegens int) {
- header, numCodegens := w.headerSize()
- size = header +
- litEnc.bitLength(w.literalFreq[:]) +
- offEnc.bitLength(w.offsetFreq[:]) +
- extraBits
- return size, numCodegens
-}
-
-// extraBitSize will return the number of bits that will be written
-// as "extra" bits on matches.
-func (w *huffmanBitWriter) extraBitSize() int {
- total := 0
- for i, n := range w.literalFreq[257:literalCount] {
- total += int(n) * int(lengthExtraBits[i&31])
- }
- for i, n := range w.offsetFreq[:offsetCodeCount] {
- total += int(n) * int(offsetExtraBits[i&31])
- }
- return total
-}
-
-// fixedSize returns the size of dynamically encoded data in bits.
-func (w *huffmanBitWriter) fixedSize(extraBits int) int {
- return 3 +
- fixedLiteralEncoding.bitLength(w.literalFreq[:]) +
- fixedOffsetEncoding.bitLength(w.offsetFreq[:]) +
- extraBits
-}
-
-// storedSize calculates the stored size, including header.
-// The function returns the size in bits and whether the block
-// fits inside a single block.
-func (w *huffmanBitWriter) storedSize(in []byte) (int, bool) {
- if in == nil {
- return 0, false
- }
- if len(in) <= maxStoreBlockSize {
- return (len(in) + 5) * 8, true
- }
- return 0, false
-}
-
-func (w *huffmanBitWriter) writeCode(c hcode) {
- // The function does not get inlined if we "& 63" the shift.
- w.bits |= uint64(c.code) << w.nbits
- w.nbits += c.len
- if w.nbits >= 48 {
- w.writeOutBits()
- }
-}
-
-// writeOutBits will write bits to the buffer.
-func (w *huffmanBitWriter) writeOutBits() {
- bits := w.bits
- w.bits >>= 48
- w.nbits -= 48
- n := w.nbytes
- w.bytes[n] = byte(bits)
- w.bytes[n+1] = byte(bits >> 8)
- w.bytes[n+2] = byte(bits >> 16)
- w.bytes[n+3] = byte(bits >> 24)
- w.bytes[n+4] = byte(bits >> 32)
- w.bytes[n+5] = byte(bits >> 40)
- n += 6
- if n >= bufferFlushSize {
- if w.err != nil {
- n = 0
- return
- }
- w.write(w.bytes[:n])
- n = 0
- }
- w.nbytes = n
-}
-
-// Write the header of a dynamic Huffman block to the output stream.
-//
-// numLiterals The number of literals specified in codegen
-// numOffsets The number of offsets specified in codegen
-// numCodegens The number of codegens used in codegen
-func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) {
- if w.err != nil {
- return
- }
- var firstBits int32 = 4
- if isEof {
- firstBits = 5
- }
- w.writeBits(firstBits, 3)
- w.writeBits(int32(numLiterals-257), 5)
- w.writeBits(int32(numOffsets-1), 5)
- w.writeBits(int32(numCodegens-4), 4)
-
- for i := 0; i < numCodegens; i++ {
- value := uint(w.codegenEncoding.codes[codegenOrder[i]].len)
- w.writeBits(int32(value), 3)
- }
-
- i := 0
- for {
- var codeWord = uint32(w.codegen[i])
- i++
- if codeWord == badCode {
- break
- }
- w.writeCode(w.codegenEncoding.codes[codeWord])
-
- switch codeWord {
- case 16:
- w.writeBits(int32(w.codegen[i]), 2)
- i++
- case 17:
- w.writeBits(int32(w.codegen[i]), 3)
- i++
- case 18:
- w.writeBits(int32(w.codegen[i]), 7)
- i++
- }
- }
-}
-
-// writeStoredHeader will write a stored header.
-// If the stored block is only used for EOF,
-// it is replaced with a fixed huffman block.
-func (w *huffmanBitWriter) writeStoredHeader(length int, isEof bool) {
- if w.err != nil {
- return
- }
- if w.lastHeader > 0 {
- // We owe an EOB
- w.writeCode(w.literalEncoding.codes[endBlockMarker])
- w.lastHeader = 0
- }
-
- // To write EOF, use a fixed encoding block. 10 bits instead of 5 bytes.
- if length == 0 && isEof {
- w.writeFixedHeader(isEof)
- // EOB: 7 bits, value: 0
- w.writeBits(0, 7)
- w.flush()
- return
- }
-
- var flag int32
- if isEof {
- flag = 1
- }
- w.writeBits(flag, 3)
- w.flush()
- w.writeBits(int32(length), 16)
- w.writeBits(int32(^uint16(length)), 16)
-}
-
-func (w *huffmanBitWriter) writeFixedHeader(isEof bool) {
- if w.err != nil {
- return
- }
- if w.lastHeader > 0 {
- // We owe an EOB
- w.writeCode(w.literalEncoding.codes[endBlockMarker])
- w.lastHeader = 0
- }
-
- // Indicate that we are a fixed Huffman block
- var value int32 = 2
- if isEof {
- value = 3
- }
- w.writeBits(value, 3)
-}
-
-// writeBlock will write a block of tokens with the smallest encoding.
-// The original input can be supplied, and if the huffman encoded data
-// is larger than the original bytes, the data will be written as a
-// stored block.
-// If the input is nil, the tokens will always be Huffman encoded.
-func (w *huffmanBitWriter) writeBlock(tokens *tokens, eof bool, input []byte) {
- if w.err != nil {
- return
- }
-
- tokens.AddEOB()
- if w.lastHeader > 0 {
- // We owe an EOB
- w.writeCode(w.literalEncoding.codes[endBlockMarker])
- w.lastHeader = 0
- }
- numLiterals, numOffsets := w.indexTokens(tokens, false)
- w.generate(tokens)
- var extraBits int
- storedSize, storable := w.storedSize(input)
- if storable {
- extraBits = w.extraBitSize()
- }
-
- // Figure out smallest code.
- // Fixed Huffman baseline.
- var literalEncoding = fixedLiteralEncoding
- var offsetEncoding = fixedOffsetEncoding
- var size = w.fixedSize(extraBits)
-
- // Dynamic Huffman?
- var numCodegens int
-
- // Generate codegen and codegenFrequencies, which indicates how to encode
- // the literalEncoding and the offsetEncoding.
- w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
- w.codegenEncoding.generate(w.codegenFreq[:], 7)
- dynamicSize, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, extraBits)
-
- if dynamicSize < size {
- size = dynamicSize
- literalEncoding = w.literalEncoding
- offsetEncoding = w.offsetEncoding
- }
-
- // Stored bytes?
- if storable && storedSize < size {
- w.writeStoredHeader(len(input), eof)
- w.writeBytes(input)
- return
- }
-
- // Huffman.
- if literalEncoding == fixedLiteralEncoding {
- w.writeFixedHeader(eof)
- } else {
- w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
- }
-
- // Write the tokens.
- w.writeTokens(tokens.Slice(), literalEncoding.codes, offsetEncoding.codes)
-}
-
-// writeBlockDynamic encodes a block using a dynamic Huffman table.
-// This should be used if the symbols used have a disproportionate
-// histogram distribution.
-// If input is supplied and the compression savings are below 1/16th of the
-// input size the block is stored.
-func (w *huffmanBitWriter) writeBlockDynamic(tokens *tokens, eof bool, input []byte, sync bool) {
- if w.err != nil {
- return
- }
-
- sync = sync || eof
- if sync {
- tokens.AddEOB()
- }
-
- // We cannot reuse pure huffman table, and must mark as EOF.
- if (w.lastHuffMan || eof) && w.lastHeader > 0 {
- // We will not try to reuse.
- w.writeCode(w.literalEncoding.codes[endBlockMarker])
- w.lastHeader = 0
- w.lastHuffMan = false
- }
- if !sync {
- tokens.Fill()
- }
- numLiterals, numOffsets := w.indexTokens(tokens, !sync)
-
- var size int
- // Check if we should reuse.
- if w.lastHeader > 0 {
- // Estimate size for using a new table.
- // Use the previous header size as the best estimate.
- newSize := w.lastHeader + tokens.EstimatedBits()
- newSize += newSize >> w.logNewTablePenalty
-
- // The estimated size is calculated as an optimal table.
- // We add a penalty to make it more realistic and re-use a bit more.
- reuseSize := w.dynamicReuseSize(w.literalEncoding, w.offsetEncoding) + w.extraBitSize()
-
- // Check if a new table is better.
- if newSize < reuseSize {
- // Write the EOB we owe.
- w.writeCode(w.literalEncoding.codes[endBlockMarker])
- size = newSize
- w.lastHeader = 0
- } else {
- size = reuseSize
- }
- // Check if we get a reasonable size decrease.
- if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) {
- w.writeStoredHeader(len(input), eof)
- w.writeBytes(input)
- w.lastHeader = 0
- return
- }
- }
-
- // We want a new block/table
- if w.lastHeader == 0 {
- w.generate(tokens)
- // Generate codegen and codegenFrequencies, which indicates how to encode
- // the literalEncoding and the offsetEncoding.
- w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
- w.codegenEncoding.generate(w.codegenFreq[:], 7)
- var numCodegens int
- size, numCodegens = w.dynamicSize(w.literalEncoding, w.offsetEncoding, w.extraBitSize())
- // Store bytes, if we don't get a reasonable improvement.
- if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) {
- w.writeStoredHeader(len(input), eof)
- w.writeBytes(input)
- w.lastHeader = 0
- return
- }
-
- // Write Huffman table.
- w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
- w.lastHeader, _ = w.headerSize()
- w.lastHuffMan = false
- }
-
- if sync {
- w.lastHeader = 0
- }
- // Write the tokens.
- w.writeTokens(tokens.Slice(), w.literalEncoding.codes, w.offsetEncoding.codes)
-}
-
-// indexTokens indexes a slice of tokens, and updates
-// literalFreq and offsetFreq, and generates literalEncoding
-// and offsetEncoding.
-// The number of literal and offset tokens is returned.
-func (w *huffmanBitWriter) indexTokens(t *tokens, filled bool) (numLiterals, numOffsets int) {
- copy(w.literalFreq[:], t.litHist[:])
- copy(w.literalFreq[256:], t.extraHist[:])
- copy(w.offsetFreq[:], t.offHist[:offsetCodeCount])
-
- if t.n == 0 {
- return
- }
- if filled {
- return maxNumLit, maxNumDist
- }
- // get the number of literals
- numLiterals = len(w.literalFreq)
- for w.literalFreq[numLiterals-1] == 0 {
- numLiterals--
- }
- // get the number of offsets
- numOffsets = len(w.offsetFreq)
- for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 {
- numOffsets--
- }
- if numOffsets == 0 {
- // We haven't found a single match. If we want to go with the dynamic encoding,
- // we should count at least one offset to be sure that the offset huffman tree could be encoded.
- w.offsetFreq[0] = 1
- numOffsets = 1
- }
- return
-}
-
-func (w *huffmanBitWriter) generate(t *tokens) {
- w.literalEncoding.generate(w.literalFreq[:literalCount], 15)
- w.offsetEncoding.generate(w.offsetFreq[:offsetCodeCount], 15)
-}
-
-// writeTokens writes a slice of tokens to the output.
-// codes for literal and offset encoding must be supplied.
-func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) {
- if w.err != nil {
- return
- }
- if len(tokens) == 0 {
- return
- }
-
- // Only last token should be endBlockMarker.
- var deferEOB bool
- if tokens[len(tokens)-1] == endBlockMarker {
- tokens = tokens[:len(tokens)-1]
- deferEOB = true
- }
-
- // Create slices up to the next power of two to avoid bounds checks.
- lits := leCodes[:256]
- offs := oeCodes[:32]
- lengths := leCodes[lengthCodesStart:]
- lengths = lengths[:32]
- for _, t := range tokens {
- if t < matchType {
- w.writeCode(lits[t.literal()])
- continue
- }
-
- // Write the length
- length := t.length()
- lengthCode := lengthCode(length)
- if false {
- w.writeCode(lengths[lengthCode&31])
- } else {
- // inlined
- c := lengths[lengthCode&31]
- w.bits |= uint64(c.code) << (w.nbits & 63)
- w.nbits += c.len
- if w.nbits >= 48 {
- w.writeOutBits()
- }
- }
-
- extraLengthBits := uint16(lengthExtraBits[lengthCode&31])
- if extraLengthBits > 0 {
- extraLength := int32(length - lengthBase[lengthCode&31])
- w.writeBits(extraLength, extraLengthBits)
- }
- // Write the offset
- offset := t.offset()
- offsetCode := offsetCode(offset)
- if false {
- w.writeCode(offs[offsetCode&31])
- } else {
- // inlined
- c := offs[offsetCode&31]
- w.bits |= uint64(c.code) << (w.nbits & 63)
- w.nbits += c.len
- if w.nbits >= 48 {
- w.writeOutBits()
- }
- }
- extraOffsetBits := uint16(offsetExtraBits[offsetCode&63])
- if extraOffsetBits > 0 {
- extraOffset := int32(offset - offsetBase[offsetCode&63])
- w.writeBits(extraOffset, extraOffsetBits)
- }
- }
- if deferEOB {
- w.writeCode(leCodes[endBlockMarker])
- }
-}
-
-// huffOffset is a static offset encoder used for huffman only encoding.
-// It can be reused since we will not be encoding offset values.
-var huffOffset *huffmanEncoder
-
-func init() {
- w := newHuffmanBitWriter(nil)
- w.offsetFreq[0] = 1
- huffOffset = newHuffmanEncoder(offsetCodeCount)
- huffOffset.generate(w.offsetFreq[:offsetCodeCount], 15)
-}
-
-// writeBlockHuff encodes a block of bytes as either
-// Huffman encoded literals or uncompressed bytes if the
-// results only gains very little from compression.
-func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte, sync bool) {
- if w.err != nil {
- return
- }
-
- // Clear histogram
- for i := range w.literalFreq[:] {
- w.literalFreq[i] = 0
- }
- if !w.lastHuffMan {
- for i := range w.offsetFreq[:] {
- w.offsetFreq[i] = 0
- }
- }
-
- // Add everything as literals
- // We have to estimate the header size.
- // Assume header is around 70 bytes:
- // https://stackoverflow.com/a/25454430
- const guessHeaderSizeBits = 70 * 8
- estBits, estExtra := histogramSize(input, w.literalFreq[:], !eof && !sync)
- estBits += w.lastHeader + 15
- if w.lastHeader == 0 {
- estBits += guessHeaderSizeBits
- }
- estBits += estBits >> w.logNewTablePenalty
-
- // Store bytes, if we don't get a reasonable improvement.
- ssize, storable := w.storedSize(input)
- if storable && ssize < estBits {
- w.writeStoredHeader(len(input), eof)
- w.writeBytes(input)
- return
- }
-
- if w.lastHeader > 0 {
- reuseSize := w.literalEncoding.bitLength(w.literalFreq[:256])
- estBits += estExtra
-
- if estBits < reuseSize {
- // We owe an EOB
- w.writeCode(w.literalEncoding.codes[endBlockMarker])
- w.lastHeader = 0
- }
- }
-
- const numLiterals = endBlockMarker + 1
- const numOffsets = 1
- if w.lastHeader == 0 {
- w.literalFreq[endBlockMarker] = 1
- w.literalEncoding.generate(w.literalFreq[:numLiterals], 15)
-
- // Generate codegen and codegenFrequencies, which indicates how to encode
- // the literalEncoding and the offsetEncoding.
- w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, huffOffset)
- w.codegenEncoding.generate(w.codegenFreq[:], 7)
- numCodegens := w.codegens()
-
- // Huffman.
- w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
- w.lastHuffMan = true
- w.lastHeader, _ = w.headerSize()
- }
-
- encoding := w.literalEncoding.codes[:257]
- for _, t := range input {
- // Bitwriting inlined, ~30% speedup
- c := encoding[t]
- w.bits |= uint64(c.code) << ((w.nbits) & 63)
- w.nbits += c.len
- if w.nbits >= 48 {
- bits := w.bits
- w.bits >>= 48
- w.nbits -= 48
- n := w.nbytes
- w.bytes[n] = byte(bits)
- w.bytes[n+1] = byte(bits >> 8)
- w.bytes[n+2] = byte(bits >> 16)
- w.bytes[n+3] = byte(bits >> 24)
- w.bytes[n+4] = byte(bits >> 32)
- w.bytes[n+5] = byte(bits >> 40)
- n += 6
- if n >= bufferFlushSize {
- if w.err != nil {
- n = 0
- return
- }
- w.write(w.bytes[:n])
- n = 0
- }
- w.nbytes = n
- }
- }
- if eof || sync {
- w.writeCode(encoding[endBlockMarker])
- w.lastHeader = 0
- w.lastHuffMan = false
- }
-}
diff --git a/vendor/github.com/klauspost/compress/flate/huffman_code.go b/vendor/github.com/klauspost/compress/flate/huffman_code.go
deleted file mode 100644
index 4c39a301871..00000000000
--- a/vendor/github.com/klauspost/compress/flate/huffman_code.go
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-import (
- "math"
- "math/bits"
-)
-
-const (
- maxBitsLimit = 16
- // number of valid literals
- literalCount = 286
-)
-
-// hcode is a huffman code with a bit code and bit length.
-type hcode struct {
- code, len uint16
-}
-
-type huffmanEncoder struct {
- codes []hcode
- freqcache []literalNode
- bitCount [17]int32
-}
-
-type literalNode struct {
- literal uint16
- freq uint16
-}
-
-// A levelInfo describes the state of the constructed tree for a given depth.
-type levelInfo struct {
- // Our level. for better printing
- level int32
-
- // The frequency of the last node at this level
- lastFreq int32
-
- // The frequency of the next character to add to this level
- nextCharFreq int32
-
- // The frequency of the next pair (from level below) to add to this level.
- // Only valid if the "needed" value of the next lower level is 0.
- nextPairFreq int32
-
- // The number of chains remaining to generate for this level before moving
- // up to the next level
- needed int32
-}
-
-// set sets the code and length of an hcode.
-func (h *hcode) set(code uint16, length uint16) {
- h.len = length
- h.code = code
-}
-
-func reverseBits(number uint16, bitLength byte) uint16 {
- return bits.Reverse16(number << ((16 - bitLength) & 15))
-}
-
-func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxUint16} }
-
-func newHuffmanEncoder(size int) *huffmanEncoder {
- // Make capacity to next power of two.
- c := uint(bits.Len32(uint32(size - 1)))
- return &huffmanEncoder{codes: make([]hcode, size, 1<= 3
-// The cases of 0, 1, and 2 literals are handled by special case code.
-//
-// list An array of the literals with non-zero frequencies
-// and their associated frequencies. The array is in order of increasing
-// frequency, and has as its last element a special element with frequency
-// MaxInt32
-// maxBits The maximum number of bits that should be used to encode any literal.
-// Must be less than 16.
-// return An integer array in which array[i] indicates the number of literals
-// that should be encoded in i bits.
-func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
- if maxBits >= maxBitsLimit {
- panic("flate: maxBits too large")
- }
- n := int32(len(list))
- list = list[0 : n+1]
- list[n] = maxNode()
-
- // The tree can't have greater depth than n - 1, no matter what. This
- // saves a little bit of work in some small cases
- if maxBits > n-1 {
- maxBits = n - 1
- }
-
- // Create information about each of the levels.
- // A bogus "Level 0" whose sole purpose is so that
- // level1.prev.needed==0. This makes level1.nextPairFreq
- // be a legitimate value that never gets chosen.
- var levels [maxBitsLimit]levelInfo
- // leafCounts[i] counts the number of literals at the left
- // of ancestors of the rightmost node at level i.
- // leafCounts[i][j] is the number of literals at the left
- // of the level j ancestor.
- var leafCounts [maxBitsLimit][maxBitsLimit]int32
-
- for level := int32(1); level <= maxBits; level++ {
- // For every level, the first two items are the first two characters.
- // We initialize the levels as if we had already figured this out.
- levels[level] = levelInfo{
- level: level,
- lastFreq: int32(list[1].freq),
- nextCharFreq: int32(list[2].freq),
- nextPairFreq: int32(list[0].freq) + int32(list[1].freq),
- }
- leafCounts[level][level] = 2
- if level == 1 {
- levels[level].nextPairFreq = math.MaxInt32
- }
- }
-
- // We need a total of 2*n - 2 items at top level and have already generated 2.
- levels[maxBits].needed = 2*n - 4
-
- level := maxBits
- for {
- l := &levels[level]
- if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
- // We've run out of both leafs and pairs.
- // End all calculations for this level.
- // To make sure we never come back to this level or any lower level,
- // set nextPairFreq impossibly large.
- l.needed = 0
- levels[level+1].nextPairFreq = math.MaxInt32
- level++
- continue
- }
-
- prevFreq := l.lastFreq
- if l.nextCharFreq < l.nextPairFreq {
- // The next item on this row is a leaf node.
- n := leafCounts[level][level] + 1
- l.lastFreq = l.nextCharFreq
- // Lower leafCounts are the same of the previous node.
- leafCounts[level][level] = n
- e := list[n]
- if e.literal < math.MaxUint16 {
- l.nextCharFreq = int32(e.freq)
- } else {
- l.nextCharFreq = math.MaxInt32
- }
- } else {
- // The next item on this row is a pair from the previous row.
- // nextPairFreq isn't valid until we generate two
- // more values in the level below
- l.lastFreq = l.nextPairFreq
- // Take leaf counts from the lower level, except counts[level] remains the same.
- copy(leafCounts[level][:level], leafCounts[level-1][:level])
- levels[l.level-1].needed = 2
- }
-
- if l.needed--; l.needed == 0 {
- // We've done everything we need to do for this level.
- // Continue calculating one level up. Fill in nextPairFreq
- // of that level with the sum of the two nodes we've just calculated on
- // this level.
- if l.level == maxBits {
- // All done!
- break
- }
- levels[l.level+1].nextPairFreq = prevFreq + l.lastFreq
- level++
- } else {
- // If we stole from below, move down temporarily to replenish it.
- for levels[level-1].needed > 0 {
- level--
- }
- }
- }
-
- // Somethings is wrong if at the end, the top level is null or hasn't used
- // all of the leaves.
- if leafCounts[maxBits][maxBits] != n {
- panic("leafCounts[maxBits][maxBits] != n")
- }
-
- bitCount := h.bitCount[:maxBits+1]
- bits := 1
- counts := &leafCounts[maxBits]
- for level := maxBits; level > 0; level-- {
- // chain.leafCount gives the number of literals requiring at least "bits"
- // bits to encode.
- bitCount[bits] = counts[level] - counts[level-1]
- bits++
- }
- return bitCount
-}
-
-// Look at the leaves and assign them a bit count and an encoding as specified
-// in RFC 1951 3.2.2
-func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) {
- code := uint16(0)
- for n, bits := range bitCount {
- code <<= 1
- if n == 0 || bits == 0 {
- continue
- }
- // The literals list[len(list)-bits] .. list[len(list)-bits]
- // are encoded using "bits" bits, and get the values
- // code, code + 1, .... The code values are
- // assigned in literal order (not frequency order).
- chunk := list[len(list)-int(bits):]
-
- sortByLiteral(chunk)
- for _, node := range chunk {
- h.codes[node.literal] = hcode{code: reverseBits(code, uint8(n)), len: uint16(n)}
- code++
- }
- list = list[0 : len(list)-int(bits)]
- }
-}
-
-// Update this Huffman Code object to be the minimum code for the specified frequency count.
-//
-// freq An array of frequencies, in which frequency[i] gives the frequency of literal i.
-// maxBits The maximum number of bits to use for any literal.
-func (h *huffmanEncoder) generate(freq []uint16, maxBits int32) {
- if h.freqcache == nil {
- // Allocate a reusable buffer with the longest possible frequency table.
- // Possible lengths are codegenCodeCount, offsetCodeCount and literalCount.
- // The largest of these is literalCount, so we allocate for that case.
- h.freqcache = make([]literalNode, literalCount+1)
- }
- list := h.freqcache[:len(freq)+1]
- // Number of non-zero literals
- count := 0
- // Set list to be the set of all non-zero literals and their frequencies
- for i, f := range freq {
- if f != 0 {
- list[count] = literalNode{uint16(i), f}
- count++
- } else {
- list[count] = literalNode{}
- h.codes[i].len = 0
- }
- }
- list[len(freq)] = literalNode{}
-
- list = list[:count]
- if count <= 2 {
- // Handle the small cases here, because they are awkward for the general case code. With
- // two or fewer literals, everything has bit length 1.
- for i, node := range list {
- // "list" is in order of increasing literal value.
- h.codes[node.literal].set(uint16(i), 1)
- }
- return
- }
- sortByFreq(list)
-
- // Get the number of literals for each bit count
- bitCount := h.bitCounts(list, maxBits)
- // And do the assignment
- h.assignEncodingAndSize(bitCount, list)
-}
-
-func atLeastOne(v float32) float32 {
- if v < 1 {
- return 1
- }
- return v
-}
-
-// histogramSize accumulates a histogram of b in h.
-// An estimated size in bits is returned.
-// Unassigned values are assigned '1' in the histogram.
-// len(h) must be >= 256, and h's elements must be all zeroes.
-func histogramSize(b []byte, h []uint16, fill bool) (int, int) {
- h = h[:256]
- for _, t := range b {
- h[t]++
- }
- invTotal := 1.0 / float32(len(b))
- shannon := float32(0.0)
- var extra float32
- if fill {
- oneBits := atLeastOne(-mFastLog2(invTotal))
- for i, v := range h[:] {
- if v > 0 {
- n := float32(v)
- shannon += atLeastOne(-mFastLog2(n*invTotal)) * n
- } else {
- h[i] = 1
- extra += oneBits
- }
- }
- } else {
- for _, v := range h[:] {
- if v > 0 {
- n := float32(v)
- shannon += atLeastOne(-mFastLog2(n*invTotal)) * n
- }
- }
- }
-
- return int(shannon + 0.99), int(extra + 0.99)
-}
diff --git a/vendor/github.com/klauspost/compress/flate/huffman_sortByFreq.go b/vendor/github.com/klauspost/compress/flate/huffman_sortByFreq.go
deleted file mode 100644
index 20778029900..00000000000
--- a/vendor/github.com/klauspost/compress/flate/huffman_sortByFreq.go
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-// Sort sorts data.
-// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
-// data.Less and data.Swap. The sort is not guaranteed to be stable.
-func sortByFreq(data []literalNode) {
- n := len(data)
- quickSortByFreq(data, 0, n, maxDepth(n))
-}
-
-func quickSortByFreq(data []literalNode, a, b, maxDepth int) {
- for b-a > 12 { // Use ShellSort for slices <= 12 elements
- if maxDepth == 0 {
- heapSort(data, a, b)
- return
- }
- maxDepth--
- mlo, mhi := doPivotByFreq(data, a, b)
- // Avoiding recursion on the larger subproblem guarantees
- // a stack depth of at most lg(b-a).
- if mlo-a < b-mhi {
- quickSortByFreq(data, a, mlo, maxDepth)
- a = mhi // i.e., quickSortByFreq(data, mhi, b)
- } else {
- quickSortByFreq(data, mhi, b, maxDepth)
- b = mlo // i.e., quickSortByFreq(data, a, mlo)
- }
- }
- if b-a > 1 {
- // Do ShellSort pass with gap 6
- // It could be written in this simplified form cause b-a <= 12
- for i := a + 6; i < b; i++ {
- if data[i].freq == data[i-6].freq && data[i].literal < data[i-6].literal || data[i].freq < data[i-6].freq {
- data[i], data[i-6] = data[i-6], data[i]
- }
- }
- insertionSortByFreq(data, a, b)
- }
-}
-
-// siftDownByFreq implements the heap property on data[lo, hi).
-// first is an offset into the array where the root of the heap lies.
-func siftDownByFreq(data []literalNode, lo, hi, first int) {
- root := lo
- for {
- child := 2*root + 1
- if child >= hi {
- break
- }
- if child+1 < hi && (data[first+child].freq == data[first+child+1].freq && data[first+child].literal < data[first+child+1].literal || data[first+child].freq < data[first+child+1].freq) {
- child++
- }
- if data[first+root].freq == data[first+child].freq && data[first+root].literal > data[first+child].literal || data[first+root].freq > data[first+child].freq {
- return
- }
- data[first+root], data[first+child] = data[first+child], data[first+root]
- root = child
- }
-}
-func doPivotByFreq(data []literalNode, lo, hi int) (midlo, midhi int) {
- m := int(uint(lo+hi) >> 1) // Written like this to avoid integer overflow.
- if hi-lo > 40 {
- // Tukey's ``Ninther,'' median of three medians of three.
- s := (hi - lo) / 8
- medianOfThreeSortByFreq(data, lo, lo+s, lo+2*s)
- medianOfThreeSortByFreq(data, m, m-s, m+s)
- medianOfThreeSortByFreq(data, hi-1, hi-1-s, hi-1-2*s)
- }
- medianOfThreeSortByFreq(data, lo, m, hi-1)
-
- // Invariants are:
- // data[lo] = pivot (set up by ChoosePivot)
- // data[lo < i < a] < pivot
- // data[a <= i < b] <= pivot
- // data[b <= i < c] unexamined
- // data[c <= i < hi-1] > pivot
- // data[hi-1] >= pivot
- pivot := lo
- a, c := lo+1, hi-1
-
- for ; a < c && (data[a].freq == data[pivot].freq && data[a].literal < data[pivot].literal || data[a].freq < data[pivot].freq); a++ {
- }
- b := a
- for {
- for ; b < c && (data[pivot].freq == data[b].freq && data[pivot].literal > data[b].literal || data[pivot].freq > data[b].freq); b++ { // data[b] <= pivot
- }
- for ; b < c && (data[pivot].freq == data[c-1].freq && data[pivot].literal < data[c-1].literal || data[pivot].freq < data[c-1].freq); c-- { // data[c-1] > pivot
- }
- if b >= c {
- break
- }
- // data[b] > pivot; data[c-1] <= pivot
- data[b], data[c-1] = data[c-1], data[b]
- b++
- c--
- }
- // If hi-c<3 then there are duplicates (by property of median of nine).
- // Let's be a bit more conservative, and set border to 5.
- protect := hi-c < 5
- if !protect && hi-c < (hi-lo)/4 {
- // Lets test some points for equality to pivot
- dups := 0
- if data[pivot].freq == data[hi-1].freq && data[pivot].literal > data[hi-1].literal || data[pivot].freq > data[hi-1].freq { // data[hi-1] = pivot
- data[c], data[hi-1] = data[hi-1], data[c]
- c++
- dups++
- }
- if data[b-1].freq == data[pivot].freq && data[b-1].literal > data[pivot].literal || data[b-1].freq > data[pivot].freq { // data[b-1] = pivot
- b--
- dups++
- }
- // m-lo = (hi-lo)/2 > 6
- // b-lo > (hi-lo)*3/4-1 > 8
- // ==> m < b ==> data[m] <= pivot
- if data[m].freq == data[pivot].freq && data[m].literal > data[pivot].literal || data[m].freq > data[pivot].freq { // data[m] = pivot
- data[m], data[b-1] = data[b-1], data[m]
- b--
- dups++
- }
- // if at least 2 points are equal to pivot, assume skewed distribution
- protect = dups > 1
- }
- if protect {
- // Protect against a lot of duplicates
- // Add invariant:
- // data[a <= i < b] unexamined
- // data[b <= i < c] = pivot
- for {
- for ; a < b && (data[b-1].freq == data[pivot].freq && data[b-1].literal > data[pivot].literal || data[b-1].freq > data[pivot].freq); b-- { // data[b] == pivot
- }
- for ; a < b && (data[a].freq == data[pivot].freq && data[a].literal < data[pivot].literal || data[a].freq < data[pivot].freq); a++ { // data[a] < pivot
- }
- if a >= b {
- break
- }
- // data[a] == pivot; data[b-1] < pivot
- data[a], data[b-1] = data[b-1], data[a]
- a++
- b--
- }
- }
- // Swap pivot into middle
- data[pivot], data[b-1] = data[b-1], data[pivot]
- return b - 1, c
-}
-
-// Insertion sort
-func insertionSortByFreq(data []literalNode, a, b int) {
- for i := a + 1; i < b; i++ {
- for j := i; j > a && (data[j].freq == data[j-1].freq && data[j].literal < data[j-1].literal || data[j].freq < data[j-1].freq); j-- {
- data[j], data[j-1] = data[j-1], data[j]
- }
- }
-}
-
-// quickSortByFreq, loosely following Bentley and McIlroy,
-// ``Engineering a Sort Function,'' SP&E November 1993.
-
-// medianOfThreeSortByFreq moves the median of the three values data[m0], data[m1], data[m2] into data[m1].
-func medianOfThreeSortByFreq(data []literalNode, m1, m0, m2 int) {
- // sort 3 elements
- if data[m1].freq == data[m0].freq && data[m1].literal < data[m0].literal || data[m1].freq < data[m0].freq {
- data[m1], data[m0] = data[m0], data[m1]
- }
- // data[m0] <= data[m1]
- if data[m2].freq == data[m1].freq && data[m2].literal < data[m1].literal || data[m2].freq < data[m1].freq {
- data[m2], data[m1] = data[m1], data[m2]
- // data[m0] <= data[m2] && data[m1] < data[m2]
- if data[m1].freq == data[m0].freq && data[m1].literal < data[m0].literal || data[m1].freq < data[m0].freq {
- data[m1], data[m0] = data[m0], data[m1]
- }
- }
- // now data[m0] <= data[m1] <= data[m2]
-}
diff --git a/vendor/github.com/klauspost/compress/flate/huffman_sortByLiteral.go b/vendor/github.com/klauspost/compress/flate/huffman_sortByLiteral.go
deleted file mode 100644
index 93f1aea109e..00000000000
--- a/vendor/github.com/klauspost/compress/flate/huffman_sortByLiteral.go
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-// Sort sorts data.
-// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
-// data.Less and data.Swap. The sort is not guaranteed to be stable.
-func sortByLiteral(data []literalNode) {
- n := len(data)
- quickSort(data, 0, n, maxDepth(n))
-}
-
-func quickSort(data []literalNode, a, b, maxDepth int) {
- for b-a > 12 { // Use ShellSort for slices <= 12 elements
- if maxDepth == 0 {
- heapSort(data, a, b)
- return
- }
- maxDepth--
- mlo, mhi := doPivot(data, a, b)
- // Avoiding recursion on the larger subproblem guarantees
- // a stack depth of at most lg(b-a).
- if mlo-a < b-mhi {
- quickSort(data, a, mlo, maxDepth)
- a = mhi // i.e., quickSort(data, mhi, b)
- } else {
- quickSort(data, mhi, b, maxDepth)
- b = mlo // i.e., quickSort(data, a, mlo)
- }
- }
- if b-a > 1 {
- // Do ShellSort pass with gap 6
- // It could be written in this simplified form cause b-a <= 12
- for i := a + 6; i < b; i++ {
- if data[i].literal < data[i-6].literal {
- data[i], data[i-6] = data[i-6], data[i]
- }
- }
- insertionSort(data, a, b)
- }
-}
-func heapSort(data []literalNode, a, b int) {
- first := a
- lo := 0
- hi := b - a
-
- // Build heap with greatest element at top.
- for i := (hi - 1) / 2; i >= 0; i-- {
- siftDown(data, i, hi, first)
- }
-
- // Pop elements, largest first, into end of data.
- for i := hi - 1; i >= 0; i-- {
- data[first], data[first+i] = data[first+i], data[first]
- siftDown(data, lo, i, first)
- }
-}
-
-// siftDown implements the heap property on data[lo, hi).
-// first is an offset into the array where the root of the heap lies.
-func siftDown(data []literalNode, lo, hi, first int) {
- root := lo
- for {
- child := 2*root + 1
- if child >= hi {
- break
- }
- if child+1 < hi && data[first+child].literal < data[first+child+1].literal {
- child++
- }
- if data[first+root].literal > data[first+child].literal {
- return
- }
- data[first+root], data[first+child] = data[first+child], data[first+root]
- root = child
- }
-}
-func doPivot(data []literalNode, lo, hi int) (midlo, midhi int) {
- m := int(uint(lo+hi) >> 1) // Written like this to avoid integer overflow.
- if hi-lo > 40 {
- // Tukey's ``Ninther,'' median of three medians of three.
- s := (hi - lo) / 8
- medianOfThree(data, lo, lo+s, lo+2*s)
- medianOfThree(data, m, m-s, m+s)
- medianOfThree(data, hi-1, hi-1-s, hi-1-2*s)
- }
- medianOfThree(data, lo, m, hi-1)
-
- // Invariants are:
- // data[lo] = pivot (set up by ChoosePivot)
- // data[lo < i < a] < pivot
- // data[a <= i < b] <= pivot
- // data[b <= i < c] unexamined
- // data[c <= i < hi-1] > pivot
- // data[hi-1] >= pivot
- pivot := lo
- a, c := lo+1, hi-1
-
- for ; a < c && data[a].literal < data[pivot].literal; a++ {
- }
- b := a
- for {
- for ; b < c && data[pivot].literal > data[b].literal; b++ { // data[b] <= pivot
- }
- for ; b < c && data[pivot].literal < data[c-1].literal; c-- { // data[c-1] > pivot
- }
- if b >= c {
- break
- }
- // data[b] > pivot; data[c-1] <= pivot
- data[b], data[c-1] = data[c-1], data[b]
- b++
- c--
- }
- // If hi-c<3 then there are duplicates (by property of median of nine).
- // Let's be a bit more conservative, and set border to 5.
- protect := hi-c < 5
- if !protect && hi-c < (hi-lo)/4 {
- // Lets test some points for equality to pivot
- dups := 0
- if data[pivot].literal > data[hi-1].literal { // data[hi-1] = pivot
- data[c], data[hi-1] = data[hi-1], data[c]
- c++
- dups++
- }
- if data[b-1].literal > data[pivot].literal { // data[b-1] = pivot
- b--
- dups++
- }
- // m-lo = (hi-lo)/2 > 6
- // b-lo > (hi-lo)*3/4-1 > 8
- // ==> m < b ==> data[m] <= pivot
- if data[m].literal > data[pivot].literal { // data[m] = pivot
- data[m], data[b-1] = data[b-1], data[m]
- b--
- dups++
- }
- // if at least 2 points are equal to pivot, assume skewed distribution
- protect = dups > 1
- }
- if protect {
- // Protect against a lot of duplicates
- // Add invariant:
- // data[a <= i < b] unexamined
- // data[b <= i < c] = pivot
- for {
- for ; a < b && data[b-1].literal > data[pivot].literal; b-- { // data[b] == pivot
- }
- for ; a < b && data[a].literal < data[pivot].literal; a++ { // data[a] < pivot
- }
- if a >= b {
- break
- }
- // data[a] == pivot; data[b-1] < pivot
- data[a], data[b-1] = data[b-1], data[a]
- a++
- b--
- }
- }
- // Swap pivot into middle
- data[pivot], data[b-1] = data[b-1], data[pivot]
- return b - 1, c
-}
-
-// Insertion sort
-func insertionSort(data []literalNode, a, b int) {
- for i := a + 1; i < b; i++ {
- for j := i; j > a && data[j].literal < data[j-1].literal; j-- {
- data[j], data[j-1] = data[j-1], data[j]
- }
- }
-}
-
-// maxDepth returns a threshold at which quicksort should switch
-// to heapsort. It returns 2*ceil(lg(n+1)).
-func maxDepth(n int) int {
- var depth int
- for i := n; i > 0; i >>= 1 {
- depth++
- }
- return depth * 2
-}
-
-// medianOfThree moves the median of the three values data[m0], data[m1], data[m2] into data[m1].
-func medianOfThree(data []literalNode, m1, m0, m2 int) {
- // sort 3 elements
- if data[m1].literal < data[m0].literal {
- data[m1], data[m0] = data[m0], data[m1]
- }
- // data[m0] <= data[m1]
- if data[m2].literal < data[m1].literal {
- data[m2], data[m1] = data[m1], data[m2]
- // data[m0] <= data[m2] && data[m1] < data[m2]
- if data[m1].literal < data[m0].literal {
- data[m1], data[m0] = data[m0], data[m1]
- }
- }
- // now data[m0] <= data[m1] <= data[m2]
-}
diff --git a/vendor/github.com/klauspost/compress/flate/inflate.go b/vendor/github.com/klauspost/compress/flate/inflate.go
deleted file mode 100644
index 3e4259f157b..00000000000
--- a/vendor/github.com/klauspost/compress/flate/inflate.go
+++ /dev/null
@@ -1,1001 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package flate implements the DEFLATE compressed data format, described in
-// RFC 1951. The gzip and zlib packages implement access to DEFLATE-based file
-// formats.
-package flate
-
-import (
- "bufio"
- "fmt"
- "io"
- "math/bits"
- "strconv"
- "sync"
-)
-
-const (
- maxCodeLen = 16 // max length of Huffman code
- maxCodeLenMask = 15 // mask for max length of Huffman code
- // The next three numbers come from the RFC section 3.2.7, with the
- // additional proviso in section 3.2.5 which implies that distance codes
- // 30 and 31 should never occur in compressed data.
- maxNumLit = 286
- maxNumDist = 30
- numCodes = 19 // number of codes in Huffman meta-code
-
- debugDecode = false
-)
-
-// Initialize the fixedHuffmanDecoder only once upon first use.
-var fixedOnce sync.Once
-var fixedHuffmanDecoder huffmanDecoder
-
-// A CorruptInputError reports the presence of corrupt input at a given offset.
-type CorruptInputError int64
-
-func (e CorruptInputError) Error() string {
- return "flate: corrupt input before offset " + strconv.FormatInt(int64(e), 10)
-}
-
-// An InternalError reports an error in the flate code itself.
-type InternalError string
-
-func (e InternalError) Error() string { return "flate: internal error: " + string(e) }
-
-// A ReadError reports an error encountered while reading input.
-//
-// Deprecated: No longer returned.
-type ReadError struct {
- Offset int64 // byte offset where error occurred
- Err error // error returned by underlying Read
-}
-
-func (e *ReadError) Error() string {
- return "flate: read error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error()
-}
-
-// A WriteError reports an error encountered while writing output.
-//
-// Deprecated: No longer returned.
-type WriteError struct {
- Offset int64 // byte offset where error occurred
- Err error // error returned by underlying Write
-}
-
-func (e *WriteError) Error() string {
- return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error()
-}
-
-// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to
-// to switch to a new underlying Reader. This permits reusing a ReadCloser
-// instead of allocating a new one.
-type Resetter interface {
- // Reset discards any buffered data and resets the Resetter as if it was
- // newly initialized with the given reader.
- Reset(r io.Reader, dict []byte) error
-}
-
-// The data structure for decoding Huffman tables is based on that of
-// zlib. There is a lookup table of a fixed bit width (huffmanChunkBits),
-// For codes smaller than the table width, there are multiple entries
-// (each combination of trailing bits has the same value). For codes
-// larger than the table width, the table contains a link to an overflow
-// table. The width of each entry in the link table is the maximum code
-// size minus the chunk width.
-//
-// Note that you can do a lookup in the table even without all bits
-// filled. Since the extra bits are zero, and the DEFLATE Huffman codes
-// have the property that shorter codes come before longer ones, the
-// bit length estimate in the result is a lower bound on the actual
-// number of bits.
-//
-// See the following:
-// http://www.gzip.org/algorithm.txt
-
-// chunk & 15 is number of bits
-// chunk >> 4 is value, including table link
-
-const (
- huffmanChunkBits = 9
- huffmanNumChunks = 1 << huffmanChunkBits
- huffmanCountMask = 15
- huffmanValueShift = 4
-)
-
-type huffmanDecoder struct {
- maxRead int // the maximum number of bits we can read and not overread
- chunks *[huffmanNumChunks]uint16 // chunks as described above
- links [][]uint16 // overflow links
- linkMask uint32 // mask the width of the link table
-}
-
-// Initialize Huffman decoding tables from array of code lengths.
-// Following this function, h is guaranteed to be initialized into a complete
-// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a
-// degenerate case where the tree has only a single symbol with length 1. Empty
-// trees are permitted.
-func (h *huffmanDecoder) init(lengths []int) bool {
- // Sanity enables additional runtime tests during Huffman
- // table construction. It's intended to be used during
- // development to supplement the currently ad-hoc unit tests.
- const sanity = false
-
- if h.chunks == nil {
- h.chunks = &[huffmanNumChunks]uint16{}
- }
- if h.maxRead != 0 {
- *h = huffmanDecoder{chunks: h.chunks, links: h.links}
- }
-
- // Count number of codes of each length,
- // compute maxRead and max length.
- var count [maxCodeLen]int
- var min, max int
- for _, n := range lengths {
- if n == 0 {
- continue
- }
- if min == 0 || n < min {
- min = n
- }
- if n > max {
- max = n
- }
- count[n&maxCodeLenMask]++
- }
-
- // Empty tree. The decompressor.huffSym function will fail later if the tree
- // is used. Technically, an empty tree is only valid for the HDIST tree and
- // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree
- // is guaranteed to fail since it will attempt to use the tree to decode the
- // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is
- // guaranteed to fail later since the compressed data section must be
- // composed of at least one symbol (the end-of-block marker).
- if max == 0 {
- return true
- }
-
- code := 0
- var nextcode [maxCodeLen]int
- for i := min; i <= max; i++ {
- code <<= 1
- nextcode[i&maxCodeLenMask] = code
- code += count[i&maxCodeLenMask]
- }
-
- // Check that the coding is complete (i.e., that we've
- // assigned all 2-to-the-max possible bit sequences).
- // Exception: To be compatible with zlib, we also need to
- // accept degenerate single-code codings. See also
- // TestDegenerateHuffmanCoding.
- if code != 1< huffmanChunkBits {
- numLinks := 1 << (uint(max) - huffmanChunkBits)
- h.linkMask = uint32(numLinks - 1)
-
- // create link tables
- link := nextcode[huffmanChunkBits+1] >> 1
- if cap(h.links) < huffmanNumChunks-link {
- h.links = make([][]uint16, huffmanNumChunks-link)
- } else {
- h.links = h.links[:huffmanNumChunks-link]
- }
- for j := uint(link); j < huffmanNumChunks; j++ {
- reverse := int(bits.Reverse16(uint16(j)))
- reverse >>= uint(16 - huffmanChunkBits)
- off := j - uint(link)
- if sanity && h.chunks[reverse] != 0 {
- panic("impossible: overwriting existing chunk")
- }
- h.chunks[reverse] = uint16(off<>= uint(16 - n)
- if n <= huffmanChunkBits {
- for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
- // We should never need to overwrite
- // an existing chunk. Also, 0 is
- // never a valid chunk, because the
- // lower 4 "count" bits should be
- // between 1 and 15.
- if sanity && h.chunks[off] != 0 {
- panic("impossible: overwriting existing chunk")
- }
- h.chunks[off] = chunk
- }
- } else {
- j := reverse & (huffmanNumChunks - 1)
- if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
- // Longer codes should have been
- // associated with a link table above.
- panic("impossible: not an indirect chunk")
- }
- value := h.chunks[j] >> huffmanValueShift
- linktab := h.links[value]
- reverse >>= huffmanChunkBits
- for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
- if sanity && linktab[off] != 0 {
- panic("impossible: overwriting existing chunk")
- }
- linktab[off] = chunk
- }
- }
- }
-
- if sanity {
- // Above we've sanity checked that we never overwrote
- // an existing entry. Here we additionally check that
- // we filled the tables completely.
- for i, chunk := range h.chunks {
- if chunk == 0 {
- // As an exception, in the degenerate
- // single-code case, we allow odd
- // chunks to be missing.
- if code == 1 && i%2 == 1 {
- continue
- }
- panic("impossible: missing chunk")
- }
- }
- for _, linktab := range h.links {
- for _, chunk := range linktab {
- if chunk == 0 {
- panic("impossible: missing chunk")
- }
- }
- }
- }
-
- return true
-}
-
-// The actual read interface needed by NewReader.
-// If the passed in io.Reader does not also have ReadByte,
-// the NewReader will introduce its own buffering.
-type Reader interface {
- io.Reader
- io.ByteReader
-}
-
-// Decompress state.
-type decompressor struct {
- // Input source.
- r Reader
- roffset int64
-
- // Huffman decoders for literal/length, distance.
- h1, h2 huffmanDecoder
-
- // Length arrays used to define Huffman codes.
- bits *[maxNumLit + maxNumDist]int
- codebits *[numCodes]int
-
- // Output history, buffer.
- dict dictDecoder
-
- // Next step in the decompression,
- // and decompression state.
- step func(*decompressor)
- stepState int
- err error
- toRead []byte
- hl, hd *huffmanDecoder
- copyLen int
- copyDist int
-
- // Temporary buffer (avoids repeated allocation).
- buf [4]byte
-
- // Input bits, in top of b.
- b uint32
-
- nb uint
- final bool
-}
-
-func (f *decompressor) nextBlock() {
- for f.nb < 1+2 {
- if f.err = f.moreBits(); f.err != nil {
- return
- }
- }
- f.final = f.b&1 == 1
- f.b >>= 1
- typ := f.b & 3
- f.b >>= 2
- f.nb -= 1 + 2
- switch typ {
- case 0:
- f.dataBlock()
- case 1:
- // compressed, fixed Huffman tables
- f.hl = &fixedHuffmanDecoder
- f.hd = nil
- f.huffmanBlockDecoder()()
- case 2:
- // compressed, dynamic Huffman tables
- if f.err = f.readHuffman(); f.err != nil {
- break
- }
- f.hl = &f.h1
- f.hd = &f.h2
- f.huffmanBlockDecoder()()
- default:
- // 3 is reserved.
- if debugDecode {
- fmt.Println("reserved data block encountered")
- }
- f.err = CorruptInputError(f.roffset)
- }
-}
-
-func (f *decompressor) Read(b []byte) (int, error) {
- for {
- if len(f.toRead) > 0 {
- n := copy(b, f.toRead)
- f.toRead = f.toRead[n:]
- if len(f.toRead) == 0 {
- return n, f.err
- }
- return n, nil
- }
- if f.err != nil {
- return 0, f.err
- }
- f.step(f)
- if f.err != nil && len(f.toRead) == 0 {
- f.toRead = f.dict.readFlush() // Flush what's left in case of error
- }
- }
-}
-
-// Support the io.WriteTo interface for io.Copy and friends.
-func (f *decompressor) WriteTo(w io.Writer) (int64, error) {
- total := int64(0)
- flushed := false
- for {
- if len(f.toRead) > 0 {
- n, err := w.Write(f.toRead)
- total += int64(n)
- if err != nil {
- f.err = err
- return total, err
- }
- if n != len(f.toRead) {
- return total, io.ErrShortWrite
- }
- f.toRead = f.toRead[:0]
- }
- if f.err != nil && flushed {
- if f.err == io.EOF {
- return total, nil
- }
- return total, f.err
- }
- if f.err == nil {
- f.step(f)
- }
- if len(f.toRead) == 0 && f.err != nil && !flushed {
- f.toRead = f.dict.readFlush() // Flush what's left in case of error
- flushed = true
- }
- }
-}
-
-func (f *decompressor) Close() error {
- if f.err == io.EOF {
- return nil
- }
- return f.err
-}
-
-// RFC 1951 section 3.2.7.
-// Compression with dynamic Huffman codes
-
-var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
-
-func (f *decompressor) readHuffman() error {
- // HLIT[5], HDIST[5], HCLEN[4].
- for f.nb < 5+5+4 {
- if err := f.moreBits(); err != nil {
- return err
- }
- }
- nlit := int(f.b&0x1F) + 257
- if nlit > maxNumLit {
- if debugDecode {
- fmt.Println("nlit > maxNumLit", nlit)
- }
- return CorruptInputError(f.roffset)
- }
- f.b >>= 5
- ndist := int(f.b&0x1F) + 1
- if ndist > maxNumDist {
- if debugDecode {
- fmt.Println("ndist > maxNumDist", ndist)
- }
- return CorruptInputError(f.roffset)
- }
- f.b >>= 5
- nclen := int(f.b&0xF) + 4
- // numCodes is 19, so nclen is always valid.
- f.b >>= 4
- f.nb -= 5 + 5 + 4
-
- // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
- for i := 0; i < nclen; i++ {
- for f.nb < 3 {
- if err := f.moreBits(); err != nil {
- return err
- }
- }
- f.codebits[codeOrder[i]] = int(f.b & 0x7)
- f.b >>= 3
- f.nb -= 3
- }
- for i := nclen; i < len(codeOrder); i++ {
- f.codebits[codeOrder[i]] = 0
- }
- if !f.h1.init(f.codebits[0:]) {
- if debugDecode {
- fmt.Println("init codebits failed")
- }
- return CorruptInputError(f.roffset)
- }
-
- // HLIT + 257 code lengths, HDIST + 1 code lengths,
- // using the code length Huffman code.
- for i, n := 0, nlit+ndist; i < n; {
- x, err := f.huffSym(&f.h1)
- if err != nil {
- return err
- }
- if x < 16 {
- // Actual length.
- f.bits[i] = x
- i++
- continue
- }
- // Repeat previous length or zero.
- var rep int
- var nb uint
- var b int
- switch x {
- default:
- return InternalError("unexpected length code")
- case 16:
- rep = 3
- nb = 2
- if i == 0 {
- if debugDecode {
- fmt.Println("i==0")
- }
- return CorruptInputError(f.roffset)
- }
- b = f.bits[i-1]
- case 17:
- rep = 3
- nb = 3
- b = 0
- case 18:
- rep = 11
- nb = 7
- b = 0
- }
- for f.nb < nb {
- if err := f.moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits:", err)
- }
- return err
- }
- }
- rep += int(f.b & uint32(1<>= nb
- f.nb -= nb
- if i+rep > n {
- if debugDecode {
- fmt.Println("i+rep > n", i, rep, n)
- }
- return CorruptInputError(f.roffset)
- }
- for j := 0; j < rep; j++ {
- f.bits[i] = b
- i++
- }
- }
-
- if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
- if debugDecode {
- fmt.Println("init2 failed")
- }
- return CorruptInputError(f.roffset)
- }
-
- // As an optimization, we can initialize the maxRead bits to read at a time
- // for the HLIT tree to the length of the EOB marker since we know that
- // every block must terminate with one. This preserves the property that
- // we never read any extra bytes after the end of the DEFLATE stream.
- if f.h1.maxRead < f.bits[endBlockMarker] {
- f.h1.maxRead = f.bits[endBlockMarker]
- }
- if !f.final {
- // If not the final block, the smallest block possible is
- // a predefined table, BTYPE=01, with a single EOB marker.
- // This will take up 3 + 7 bits.
- f.h1.maxRead += 10
- }
-
- return nil
-}
-
-// Decode a single Huffman block from f.
-// hl and hd are the Huffman states for the lit/length values
-// and the distance values, respectively. If hd == nil, using the
-// fixed distance encoding associated with fixed Huffman blocks.
-func (f *decompressor) huffmanBlockGeneric() {
- const (
- stateInit = iota // Zero value must be stateInit
- stateDict
- )
-
- switch f.stepState {
- case stateInit:
- goto readLiteral
- case stateDict:
- goto copyHistory
- }
-
-readLiteral:
- // Read literal and/or (length, distance) according to RFC section 3.2.3.
- {
- var v int
- {
- // Inlined v, err := f.huffSym(f.hl)
- // Since a huffmanDecoder can be empty or be composed of a degenerate tree
- // with single element, huffSym must error on these two edge cases. In both
- // cases, the chunks slice will be 0 for the invalid sequence, leading it
- // satisfy the n == 0 check below.
- n := uint(f.hl.maxRead)
- // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
- // but is smart enough to keep local variables in registers, so use nb and b,
- // inline call to moreBits and reassign b,nb back to f on return.
- nb, b := f.nb, f.b
- for {
- for nb < n {
- c, err := f.r.ReadByte()
- if err != nil {
- f.b = b
- f.nb = nb
- f.err = noEOF(err)
- return
- }
- f.roffset++
- b |= uint32(c) << (nb & 31)
- nb += 8
- }
- chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
- n = uint(chunk & huffmanCountMask)
- if n > huffmanChunkBits {
- chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask]
- n = uint(chunk & huffmanCountMask)
- }
- if n <= nb {
- if n == 0 {
- f.b = b
- f.nb = nb
- if debugDecode {
- fmt.Println("huffsym: n==0")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- f.b = b >> (n & 31)
- f.nb = nb - n
- v = int(chunk >> huffmanValueShift)
- break
- }
- }
- }
-
- var n uint // number of bits extra
- var length int
- var err error
- switch {
- case v < 256:
- f.dict.writeByte(byte(v))
- if f.dict.availWrite() == 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanBlockGeneric
- f.stepState = stateInit
- return
- }
- goto readLiteral
- case v == 256:
- f.finishBlock()
- return
- // otherwise, reference to older data
- case v < 265:
- length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
- case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
- for f.nb < n {
- if err = f.moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits n>0:", err)
- }
- f.err = err
- return
- }
- }
- length += int(f.b & uint32(1<>= n
- f.nb -= n
- }
-
- var dist int
- if f.hd == nil {
- for f.nb < 5 {
- if err = f.moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb<5:", err)
- }
- f.err = err
- return
- }
- }
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
- f.b >>= 5
- f.nb -= 5
- } else {
- if dist, err = f.huffSym(f.hd); err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
- }
- f.err = err
- return
- }
- }
-
- switch {
- case dist < 4:
- dist++
- case dist < maxNumDist:
- nb := uint(dist-2) >> 1
- // have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
- for f.nb < nb {
- if err = f.moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb>= nb
- f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
- default:
- if debugDecode {
- fmt.Println("dist too big:", dist, maxNumDist)
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- // No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
- if debugDecode {
- fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- f.copyLen, f.copyDist = length, dist
- goto copyHistory
- }
-
-copyHistory:
- // Perform a backwards copy according to RFC section 3.2.3.
- {
- cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
- if cnt == 0 {
- cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
- }
- f.copyLen -= cnt
-
- if f.dict.availWrite() == 0 || f.copyLen > 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanBlockGeneric // We need to continue this work
- f.stepState = stateDict
- return
- }
- goto readLiteral
- }
-}
-
-// Copy a single uncompressed data block from input to output.
-func (f *decompressor) dataBlock() {
- // Uncompressed.
- // Discard current half-byte.
- left := (f.nb) & 7
- f.nb -= left
- f.b >>= left
-
- offBytes := f.nb >> 3
- // Unfilled values will be overwritten.
- f.buf[0] = uint8(f.b)
- f.buf[1] = uint8(f.b >> 8)
- f.buf[2] = uint8(f.b >> 16)
- f.buf[3] = uint8(f.b >> 24)
-
- f.roffset += int64(offBytes)
- f.nb, f.b = 0, 0
-
- // Length then ones-complement of length.
- nr, err := io.ReadFull(f.r, f.buf[offBytes:4])
- f.roffset += int64(nr)
- if err != nil {
- f.err = noEOF(err)
- return
- }
- n := uint16(f.buf[0]) | uint16(f.buf[1])<<8
- nn := uint16(f.buf[2]) | uint16(f.buf[3])<<8
- if nn != ^n {
- if debugDecode {
- ncomp := ^n
- fmt.Println("uint16(nn) != uint16(^n)", nn, ncomp)
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- if n == 0 {
- f.toRead = f.dict.readFlush()
- f.finishBlock()
- return
- }
-
- f.copyLen = int(n)
- f.copyData()
-}
-
-// copyData copies f.copyLen bytes from the underlying reader into f.hist.
-// It pauses for reads when f.hist is full.
-func (f *decompressor) copyData() {
- buf := f.dict.writeSlice()
- if len(buf) > f.copyLen {
- buf = buf[:f.copyLen]
- }
-
- cnt, err := io.ReadFull(f.r, buf)
- f.roffset += int64(cnt)
- f.copyLen -= cnt
- f.dict.writeMark(cnt)
- if err != nil {
- f.err = noEOF(err)
- return
- }
-
- if f.dict.availWrite() == 0 || f.copyLen > 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).copyData
- return
- }
- f.finishBlock()
-}
-
-func (f *decompressor) finishBlock() {
- if f.final {
- if f.dict.availRead() > 0 {
- f.toRead = f.dict.readFlush()
- }
- f.err = io.EOF
- }
- f.step = (*decompressor).nextBlock
-}
-
-// noEOF returns err, unless err == io.EOF, in which case it returns io.ErrUnexpectedEOF.
-func noEOF(e error) error {
- if e == io.EOF {
- return io.ErrUnexpectedEOF
- }
- return e
-}
-
-func (f *decompressor) moreBits() error {
- c, err := f.r.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
-}
-
-// Read the next Huffman-encoded symbol from f according to h.
-func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
- // Since a huffmanDecoder can be empty or be composed of a degenerate tree
- // with single element, huffSym must error on these two edge cases. In both
- // cases, the chunks slice will be 0 for the invalid sequence, leading it
- // satisfy the n == 0 check below.
- n := uint(h.maxRead)
- // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
- // but is smart enough to keep local variables in registers, so use nb and b,
- // inline call to moreBits and reassign b,nb back to f on return.
- nb, b := f.nb, f.b
- for {
- for nb < n {
- c, err := f.r.ReadByte()
- if err != nil {
- f.b = b
- f.nb = nb
- return 0, noEOF(err)
- }
- f.roffset++
- b |= uint32(c) << (nb & 31)
- nb += 8
- }
- chunk := h.chunks[b&(huffmanNumChunks-1)]
- n = uint(chunk & huffmanCountMask)
- if n > huffmanChunkBits {
- chunk = h.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&h.linkMask]
- n = uint(chunk & huffmanCountMask)
- }
- if n <= nb {
- if n == 0 {
- f.b = b
- f.nb = nb
- if debugDecode {
- fmt.Println("huffsym: n==0")
- }
- f.err = CorruptInputError(f.roffset)
- return 0, f.err
- }
- f.b = b >> (n & 31)
- f.nb = nb - n
- return int(chunk >> huffmanValueShift), nil
- }
- }
-}
-
-func makeReader(r io.Reader) Reader {
- if rr, ok := r.(Reader); ok {
- return rr
- }
- return bufio.NewReader(r)
-}
-
-func fixedHuffmanDecoderInit() {
- fixedOnce.Do(func() {
- // These come from the RFC section 3.2.6.
- var bits [288]int
- for i := 0; i < 144; i++ {
- bits[i] = 8
- }
- for i := 144; i < 256; i++ {
- bits[i] = 9
- }
- for i := 256; i < 280; i++ {
- bits[i] = 7
- }
- for i := 280; i < 288; i++ {
- bits[i] = 8
- }
- fixedHuffmanDecoder.init(bits[:])
- })
-}
-
-func (f *decompressor) Reset(r io.Reader, dict []byte) error {
- *f = decompressor{
- r: makeReader(r),
- bits: f.bits,
- codebits: f.codebits,
- h1: f.h1,
- h2: f.h2,
- dict: f.dict,
- step: (*decompressor).nextBlock,
- }
- f.dict.init(maxMatchOffset, dict)
- return nil
-}
-
-// NewReader returns a new ReadCloser that can be used
-// to read the uncompressed version of r.
-// If r does not also implement io.ByteReader,
-// the decompressor may read more data than necessary from r.
-// It is the caller's responsibility to call Close on the ReadCloser
-// when finished reading.
-//
-// The ReadCloser returned by NewReader also implements Resetter.
-func NewReader(r io.Reader) io.ReadCloser {
- fixedHuffmanDecoderInit()
-
- var f decompressor
- f.r = makeReader(r)
- f.bits = new([maxNumLit + maxNumDist]int)
- f.codebits = new([numCodes]int)
- f.step = (*decompressor).nextBlock
- f.dict.init(maxMatchOffset, nil)
- return &f
-}
-
-// NewReaderDict is like NewReader but initializes the reader
-// with a preset dictionary. The returned Reader behaves as if
-// the uncompressed data stream started with the given dictionary,
-// which has already been read. NewReaderDict is typically used
-// to read data compressed by NewWriterDict.
-//
-// The ReadCloser returned by NewReader also implements Resetter.
-func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
- fixedHuffmanDecoderInit()
-
- var f decompressor
- f.r = makeReader(r)
- f.bits = new([maxNumLit + maxNumDist]int)
- f.codebits = new([numCodes]int)
- f.step = (*decompressor).nextBlock
- f.dict.init(maxMatchOffset, dict)
- return &f
-}
diff --git a/vendor/github.com/klauspost/compress/flate/inflate_gen.go b/vendor/github.com/klauspost/compress/flate/inflate_gen.go
deleted file mode 100644
index 397dc1b1a13..00000000000
--- a/vendor/github.com/klauspost/compress/flate/inflate_gen.go
+++ /dev/null
@@ -1,922 +0,0 @@
-// Code generated by go generate gen_inflate.go. DO NOT EDIT.
-
-package flate
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "math/bits"
- "strings"
-)
-
-// Decode a single Huffman block from f.
-// hl and hd are the Huffman states for the lit/length values
-// and the distance values, respectively. If hd == nil, using the
-// fixed distance encoding associated with fixed Huffman blocks.
-func (f *decompressor) huffmanBytesBuffer() {
- const (
- stateInit = iota // Zero value must be stateInit
- stateDict
- )
- fr := f.r.(*bytes.Buffer)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
-
- switch f.stepState {
- case stateInit:
- goto readLiteral
- case stateDict:
- goto copyHistory
- }
-
-readLiteral:
- // Read literal and/or (length, distance) according to RFC section 3.2.3.
- {
- var v int
- {
- // Inlined v, err := f.huffSym(f.hl)
- // Since a huffmanDecoder can be empty or be composed of a degenerate tree
- // with single element, huffSym must error on these two edge cases. In both
- // cases, the chunks slice will be 0 for the invalid sequence, leading it
- // satisfy the n == 0 check below.
- n := uint(f.hl.maxRead)
- // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
- // but is smart enough to keep local variables in registers, so use nb and b,
- // inline call to moreBits and reassign b,nb back to f on return.
- nb, b := f.nb, f.b
- for {
- for nb < n {
- c, err := fr.ReadByte()
- if err != nil {
- f.b = b
- f.nb = nb
- f.err = noEOF(err)
- return
- }
- f.roffset++
- b |= uint32(c) << (nb & 31)
- nb += 8
- }
- chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
- n = uint(chunk & huffmanCountMask)
- if n > huffmanChunkBits {
- chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask]
- n = uint(chunk & huffmanCountMask)
- }
- if n <= nb {
- if n == 0 {
- f.b = b
- f.nb = nb
- if debugDecode {
- fmt.Println("huffsym: n==0")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- f.b = b >> (n & 31)
- f.nb = nb - n
- v = int(chunk >> huffmanValueShift)
- break
- }
- }
- }
-
- var n uint // number of bits extra
- var length int
- var err error
- switch {
- case v < 256:
- f.dict.writeByte(byte(v))
- if f.dict.availWrite() == 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanBytesBuffer
- f.stepState = stateInit
- return
- }
- goto readLiteral
- case v == 256:
- f.finishBlock()
- return
- // otherwise, reference to older data
- case v < 265:
- length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
- case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
- for f.nb < n {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits n>0:", err)
- }
- f.err = err
- return
- }
- }
- length += int(f.b & uint32(1<>= n
- f.nb -= n
- }
-
- var dist int
- if f.hd == nil {
- for f.nb < 5 {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb<5:", err)
- }
- f.err = err
- return
- }
- }
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
- f.b >>= 5
- f.nb -= 5
- } else {
- if dist, err = f.huffSym(f.hd); err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
- }
- f.err = err
- return
- }
- }
-
- switch {
- case dist < 4:
- dist++
- case dist < maxNumDist:
- nb := uint(dist-2) >> 1
- // have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
- for f.nb < nb {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb>= nb
- f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
- default:
- if debugDecode {
- fmt.Println("dist too big:", dist, maxNumDist)
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- // No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
- if debugDecode {
- fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- f.copyLen, f.copyDist = length, dist
- goto copyHistory
- }
-
-copyHistory:
- // Perform a backwards copy according to RFC section 3.2.3.
- {
- cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
- if cnt == 0 {
- cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
- }
- f.copyLen -= cnt
-
- if f.dict.availWrite() == 0 || f.copyLen > 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanBytesBuffer // We need to continue this work
- f.stepState = stateDict
- return
- }
- goto readLiteral
- }
-}
-
-// Decode a single Huffman block from f.
-// hl and hd are the Huffman states for the lit/length values
-// and the distance values, respectively. If hd == nil, using the
-// fixed distance encoding associated with fixed Huffman blocks.
-func (f *decompressor) huffmanBytesReader() {
- const (
- stateInit = iota // Zero value must be stateInit
- stateDict
- )
- fr := f.r.(*bytes.Reader)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
-
- switch f.stepState {
- case stateInit:
- goto readLiteral
- case stateDict:
- goto copyHistory
- }
-
-readLiteral:
- // Read literal and/or (length, distance) according to RFC section 3.2.3.
- {
- var v int
- {
- // Inlined v, err := f.huffSym(f.hl)
- // Since a huffmanDecoder can be empty or be composed of a degenerate tree
- // with single element, huffSym must error on these two edge cases. In both
- // cases, the chunks slice will be 0 for the invalid sequence, leading it
- // satisfy the n == 0 check below.
- n := uint(f.hl.maxRead)
- // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
- // but is smart enough to keep local variables in registers, so use nb and b,
- // inline call to moreBits and reassign b,nb back to f on return.
- nb, b := f.nb, f.b
- for {
- for nb < n {
- c, err := fr.ReadByte()
- if err != nil {
- f.b = b
- f.nb = nb
- f.err = noEOF(err)
- return
- }
- f.roffset++
- b |= uint32(c) << (nb & 31)
- nb += 8
- }
- chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
- n = uint(chunk & huffmanCountMask)
- if n > huffmanChunkBits {
- chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask]
- n = uint(chunk & huffmanCountMask)
- }
- if n <= nb {
- if n == 0 {
- f.b = b
- f.nb = nb
- if debugDecode {
- fmt.Println("huffsym: n==0")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- f.b = b >> (n & 31)
- f.nb = nb - n
- v = int(chunk >> huffmanValueShift)
- break
- }
- }
- }
-
- var n uint // number of bits extra
- var length int
- var err error
- switch {
- case v < 256:
- f.dict.writeByte(byte(v))
- if f.dict.availWrite() == 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanBytesReader
- f.stepState = stateInit
- return
- }
- goto readLiteral
- case v == 256:
- f.finishBlock()
- return
- // otherwise, reference to older data
- case v < 265:
- length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
- case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
- for f.nb < n {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits n>0:", err)
- }
- f.err = err
- return
- }
- }
- length += int(f.b & uint32(1<>= n
- f.nb -= n
- }
-
- var dist int
- if f.hd == nil {
- for f.nb < 5 {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb<5:", err)
- }
- f.err = err
- return
- }
- }
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
- f.b >>= 5
- f.nb -= 5
- } else {
- if dist, err = f.huffSym(f.hd); err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
- }
- f.err = err
- return
- }
- }
-
- switch {
- case dist < 4:
- dist++
- case dist < maxNumDist:
- nb := uint(dist-2) >> 1
- // have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
- for f.nb < nb {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb>= nb
- f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
- default:
- if debugDecode {
- fmt.Println("dist too big:", dist, maxNumDist)
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- // No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
- if debugDecode {
- fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- f.copyLen, f.copyDist = length, dist
- goto copyHistory
- }
-
-copyHistory:
- // Perform a backwards copy according to RFC section 3.2.3.
- {
- cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
- if cnt == 0 {
- cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
- }
- f.copyLen -= cnt
-
- if f.dict.availWrite() == 0 || f.copyLen > 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanBytesReader // We need to continue this work
- f.stepState = stateDict
- return
- }
- goto readLiteral
- }
-}
-
-// Decode a single Huffman block from f.
-// hl and hd are the Huffman states for the lit/length values
-// and the distance values, respectively. If hd == nil, using the
-// fixed distance encoding associated with fixed Huffman blocks.
-func (f *decompressor) huffmanBufioReader() {
- const (
- stateInit = iota // Zero value must be stateInit
- stateDict
- )
- fr := f.r.(*bufio.Reader)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
-
- switch f.stepState {
- case stateInit:
- goto readLiteral
- case stateDict:
- goto copyHistory
- }
-
-readLiteral:
- // Read literal and/or (length, distance) according to RFC section 3.2.3.
- {
- var v int
- {
- // Inlined v, err := f.huffSym(f.hl)
- // Since a huffmanDecoder can be empty or be composed of a degenerate tree
- // with single element, huffSym must error on these two edge cases. In both
- // cases, the chunks slice will be 0 for the invalid sequence, leading it
- // satisfy the n == 0 check below.
- n := uint(f.hl.maxRead)
- // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
- // but is smart enough to keep local variables in registers, so use nb and b,
- // inline call to moreBits and reassign b,nb back to f on return.
- nb, b := f.nb, f.b
- for {
- for nb < n {
- c, err := fr.ReadByte()
- if err != nil {
- f.b = b
- f.nb = nb
- f.err = noEOF(err)
- return
- }
- f.roffset++
- b |= uint32(c) << (nb & 31)
- nb += 8
- }
- chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
- n = uint(chunk & huffmanCountMask)
- if n > huffmanChunkBits {
- chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask]
- n = uint(chunk & huffmanCountMask)
- }
- if n <= nb {
- if n == 0 {
- f.b = b
- f.nb = nb
- if debugDecode {
- fmt.Println("huffsym: n==0")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- f.b = b >> (n & 31)
- f.nb = nb - n
- v = int(chunk >> huffmanValueShift)
- break
- }
- }
- }
-
- var n uint // number of bits extra
- var length int
- var err error
- switch {
- case v < 256:
- f.dict.writeByte(byte(v))
- if f.dict.availWrite() == 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanBufioReader
- f.stepState = stateInit
- return
- }
- goto readLiteral
- case v == 256:
- f.finishBlock()
- return
- // otherwise, reference to older data
- case v < 265:
- length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
- case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
- for f.nb < n {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits n>0:", err)
- }
- f.err = err
- return
- }
- }
- length += int(f.b & uint32(1<>= n
- f.nb -= n
- }
-
- var dist int
- if f.hd == nil {
- for f.nb < 5 {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb<5:", err)
- }
- f.err = err
- return
- }
- }
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
- f.b >>= 5
- f.nb -= 5
- } else {
- if dist, err = f.huffSym(f.hd); err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
- }
- f.err = err
- return
- }
- }
-
- switch {
- case dist < 4:
- dist++
- case dist < maxNumDist:
- nb := uint(dist-2) >> 1
- // have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
- for f.nb < nb {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb>= nb
- f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
- default:
- if debugDecode {
- fmt.Println("dist too big:", dist, maxNumDist)
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- // No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
- if debugDecode {
- fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- f.copyLen, f.copyDist = length, dist
- goto copyHistory
- }
-
-copyHistory:
- // Perform a backwards copy according to RFC section 3.2.3.
- {
- cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
- if cnt == 0 {
- cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
- }
- f.copyLen -= cnt
-
- if f.dict.availWrite() == 0 || f.copyLen > 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanBufioReader // We need to continue this work
- f.stepState = stateDict
- return
- }
- goto readLiteral
- }
-}
-
-// Decode a single Huffman block from f.
-// hl and hd are the Huffman states for the lit/length values
-// and the distance values, respectively. If hd == nil, using the
-// fixed distance encoding associated with fixed Huffman blocks.
-func (f *decompressor) huffmanStringsReader() {
- const (
- stateInit = iota // Zero value must be stateInit
- stateDict
- )
- fr := f.r.(*strings.Reader)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
-
- switch f.stepState {
- case stateInit:
- goto readLiteral
- case stateDict:
- goto copyHistory
- }
-
-readLiteral:
- // Read literal and/or (length, distance) according to RFC section 3.2.3.
- {
- var v int
- {
- // Inlined v, err := f.huffSym(f.hl)
- // Since a huffmanDecoder can be empty or be composed of a degenerate tree
- // with single element, huffSym must error on these two edge cases. In both
- // cases, the chunks slice will be 0 for the invalid sequence, leading it
- // satisfy the n == 0 check below.
- n := uint(f.hl.maxRead)
- // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
- // but is smart enough to keep local variables in registers, so use nb and b,
- // inline call to moreBits and reassign b,nb back to f on return.
- nb, b := f.nb, f.b
- for {
- for nb < n {
- c, err := fr.ReadByte()
- if err != nil {
- f.b = b
- f.nb = nb
- f.err = noEOF(err)
- return
- }
- f.roffset++
- b |= uint32(c) << (nb & 31)
- nb += 8
- }
- chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
- n = uint(chunk & huffmanCountMask)
- if n > huffmanChunkBits {
- chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask]
- n = uint(chunk & huffmanCountMask)
- }
- if n <= nb {
- if n == 0 {
- f.b = b
- f.nb = nb
- if debugDecode {
- fmt.Println("huffsym: n==0")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- f.b = b >> (n & 31)
- f.nb = nb - n
- v = int(chunk >> huffmanValueShift)
- break
- }
- }
- }
-
- var n uint // number of bits extra
- var length int
- var err error
- switch {
- case v < 256:
- f.dict.writeByte(byte(v))
- if f.dict.availWrite() == 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanStringsReader
- f.stepState = stateInit
- return
- }
- goto readLiteral
- case v == 256:
- f.finishBlock()
- return
- // otherwise, reference to older data
- case v < 265:
- length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
- case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
- for f.nb < n {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits n>0:", err)
- }
- f.err = err
- return
- }
- }
- length += int(f.b & uint32(1<>= n
- f.nb -= n
- }
-
- var dist int
- if f.hd == nil {
- for f.nb < 5 {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb<5:", err)
- }
- f.err = err
- return
- }
- }
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
- f.b >>= 5
- f.nb -= 5
- } else {
- if dist, err = f.huffSym(f.hd); err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
- }
- f.err = err
- return
- }
- }
-
- switch {
- case dist < 4:
- dist++
- case dist < maxNumDist:
- nb := uint(dist-2) >> 1
- // have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
- for f.nb < nb {
- if err = moreBits(); err != nil {
- if debugDecode {
- fmt.Println("morebits f.nb>= nb
- f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
- default:
- if debugDecode {
- fmt.Println("dist too big:", dist, maxNumDist)
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- // No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
- if debugDecode {
- fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
-
- f.copyLen, f.copyDist = length, dist
- goto copyHistory
- }
-
-copyHistory:
- // Perform a backwards copy according to RFC section 3.2.3.
- {
- cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
- if cnt == 0 {
- cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
- }
- f.copyLen -= cnt
-
- if f.dict.availWrite() == 0 || f.copyLen > 0 {
- f.toRead = f.dict.readFlush()
- f.step = (*decompressor).huffmanStringsReader // We need to continue this work
- f.stepState = stateDict
- return
- }
- goto readLiteral
- }
-}
-
-func (f *decompressor) huffmanBlockDecoder() func() {
- switch f.r.(type) {
- case *bytes.Buffer:
- return f.huffmanBytesBuffer
- case *bytes.Reader:
- return f.huffmanBytesReader
- case *bufio.Reader:
- return f.huffmanBufioReader
- case *strings.Reader:
- return f.huffmanStringsReader
- default:
- return f.huffmanBlockGeneric
- }
-}
diff --git a/vendor/github.com/klauspost/compress/flate/level1.go b/vendor/github.com/klauspost/compress/flate/level1.go
deleted file mode 100644
index 1e5eea3968a..00000000000
--- a/vendor/github.com/klauspost/compress/flate/level1.go
+++ /dev/null
@@ -1,179 +0,0 @@
-package flate
-
-import "fmt"
-
-// fastGen maintains the table for matches,
-// and the previous byte block for level 2.
-// This is the generic implementation.
-type fastEncL1 struct {
- fastGen
- table [tableSize]tableEntry
-}
-
-// EncodeL1 uses a similar algorithm to level 1
-func (e *fastEncL1) Encode(dst *tokens, src []byte) {
- const (
- inputMargin = 12 - 1
- minNonLiteralBlockSize = 1 + 1 + inputMargin
- )
- if debugDeflate && e.cur < 0 {
- panic(fmt.Sprint("e.cur < 0: ", e.cur))
- }
-
- // Protect against e.cur wraparound.
- for e.cur >= bufferReset {
- if len(e.hist) == 0 {
- for i := range e.table[:] {
- e.table[i] = tableEntry{}
- }
- e.cur = maxMatchOffset
- break
- }
- // Shift down everything in the table that isn't already too far away.
- minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
- for i := range e.table[:] {
- v := e.table[i].offset
- if v <= minOff {
- v = 0
- } else {
- v = v - e.cur + maxMatchOffset
- }
- e.table[i].offset = v
- }
- e.cur = maxMatchOffset
- }
-
- s := e.addBlock(src)
-
- // This check isn't in the Snappy implementation, but there, the caller
- // instead of the callee handles this case.
- if len(src) < minNonLiteralBlockSize {
- // We do not fill the token table.
- // This will be picked up by caller.
- dst.n = uint16(len(src))
- return
- }
-
- // Override src
- src = e.hist
- nextEmit := s
-
- // sLimit is when to stop looking for offset/length copies. The inputMargin
- // lets us use a fast path for emitLiteral in the main loop, while we are
- // looking for copies.
- sLimit := int32(len(src) - inputMargin)
-
- // nextEmit is where in src the next emitLiteral should start from.
- cv := load3232(src, s)
-
- for {
- const skipLog = 5
- const doEvery = 2
-
- nextS := s
- var candidate tableEntry
- for {
- nextHash := hash(cv)
- candidate = e.table[nextHash]
- nextS = s + doEvery + (s-nextEmit)>>skipLog
- if nextS > sLimit {
- goto emitRemainder
- }
-
- now := load6432(src, nextS)
- e.table[nextHash] = tableEntry{offset: s + e.cur}
- nextHash = hash(uint32(now))
-
- offset := s - (candidate.offset - e.cur)
- if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) {
- e.table[nextHash] = tableEntry{offset: nextS + e.cur}
- break
- }
-
- // Do one right away...
- cv = uint32(now)
- s = nextS
- nextS++
- candidate = e.table[nextHash]
- now >>= 8
- e.table[nextHash] = tableEntry{offset: s + e.cur}
-
- offset = s - (candidate.offset - e.cur)
- if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) {
- e.table[nextHash] = tableEntry{offset: nextS + e.cur}
- break
- }
- cv = uint32(now)
- s = nextS
- }
-
- // A 4-byte match has been found. We'll later see if more than 4 bytes
- // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
- // them as literal bytes.
- for {
- // Invariant: we have a 4-byte match at s, and no need to emit any
- // literal bytes prior to s.
-
- // Extend the 4-byte match as long as possible.
- t := candidate.offset - e.cur
- l := e.matchlenLong(s+4, t+4, src) + 4
-
- // Extend backwards
- for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
- s--
- t--
- l++
- }
- if nextEmit < s {
- emitLiteral(dst, src[nextEmit:s])
- }
-
- // Save the match found
- dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
- s += l
- nextEmit = s
- if nextS >= s {
- s = nextS + 1
- }
- if s >= sLimit {
- // Index first pair after match end.
- if int(s+l+4) < len(src) {
- cv := load3232(src, s)
- e.table[hash(cv)] = tableEntry{offset: s + e.cur}
- }
- goto emitRemainder
- }
-
- // We could immediately start working at s now, but to improve
- // compression we first update the hash table at s-2 and at s. If
- // another emitCopy is not our next move, also calculate nextHash
- // at s+1. At least on GOARCH=amd64, these three hash calculations
- // are faster as one load64 call (with some shifts) instead of
- // three load32 calls.
- x := load6432(src, s-2)
- o := e.cur + s - 2
- prevHash := hash(uint32(x))
- e.table[prevHash] = tableEntry{offset: o}
- x >>= 16
- currHash := hash(uint32(x))
- candidate = e.table[currHash]
- e.table[currHash] = tableEntry{offset: o + 2}
-
- offset := s - (candidate.offset - e.cur)
- if offset > maxMatchOffset || uint32(x) != load3232(src, candidate.offset-e.cur) {
- cv = uint32(x >> 8)
- s++
- break
- }
- }
- }
-
-emitRemainder:
- if int(nextEmit) < len(src) {
- // If nothing was added, don't encode literals.
- if dst.n == 0 {
- return
- }
- emitLiteral(dst, src[nextEmit:])
- }
-}
diff --git a/vendor/github.com/klauspost/compress/flate/level2.go b/vendor/github.com/klauspost/compress/flate/level2.go
deleted file mode 100644
index 5b986a1944e..00000000000
--- a/vendor/github.com/klauspost/compress/flate/level2.go
+++ /dev/null
@@ -1,205 +0,0 @@
-package flate
-
-import "fmt"
-
-// fastGen maintains the table for matches,
-// and the previous byte block for level 2.
-// This is the generic implementation.
-type fastEncL2 struct {
- fastGen
- table [bTableSize]tableEntry
-}
-
-// EncodeL2 uses a similar algorithm to level 1, but is capable
-// of matching across blocks giving better compression at a small slowdown.
-func (e *fastEncL2) Encode(dst *tokens, src []byte) {
- const (
- inputMargin = 12 - 1
- minNonLiteralBlockSize = 1 + 1 + inputMargin
- )
-
- if debugDeflate && e.cur < 0 {
- panic(fmt.Sprint("e.cur < 0: ", e.cur))
- }
-
- // Protect against e.cur wraparound.
- for e.cur >= bufferReset {
- if len(e.hist) == 0 {
- for i := range e.table[:] {
- e.table[i] = tableEntry{}
- }
- e.cur = maxMatchOffset
- break
- }
- // Shift down everything in the table that isn't already too far away.
- minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
- for i := range e.table[:] {
- v := e.table[i].offset
- if v <= minOff {
- v = 0
- } else {
- v = v - e.cur + maxMatchOffset
- }
- e.table[i].offset = v
- }
- e.cur = maxMatchOffset
- }
-
- s := e.addBlock(src)
-
- // This check isn't in the Snappy implementation, but there, the caller
- // instead of the callee handles this case.
- if len(src) < minNonLiteralBlockSize {
- // We do not fill the token table.
- // This will be picked up by caller.
- dst.n = uint16(len(src))
- return
- }
-
- // Override src
- src = e.hist
- nextEmit := s
-
- // sLimit is when to stop looking for offset/length copies. The inputMargin
- // lets us use a fast path for emitLiteral in the main loop, while we are
- // looking for copies.
- sLimit := int32(len(src) - inputMargin)
-
- // nextEmit is where in src the next emitLiteral should start from.
- cv := load3232(src, s)
- for {
- // When should we start skipping if we haven't found matches in a long while.
- const skipLog = 5
- const doEvery = 2
-
- nextS := s
- var candidate tableEntry
- for {
- nextHash := hash4u(cv, bTableBits)
- s = nextS
- nextS = s + doEvery + (s-nextEmit)>>skipLog
- if nextS > sLimit {
- goto emitRemainder
- }
- candidate = e.table[nextHash]
- now := load6432(src, nextS)
- e.table[nextHash] = tableEntry{offset: s + e.cur}
- nextHash = hash4u(uint32(now), bTableBits)
-
- offset := s - (candidate.offset - e.cur)
- if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) {
- e.table[nextHash] = tableEntry{offset: nextS + e.cur}
- break
- }
-
- // Do one right away...
- cv = uint32(now)
- s = nextS
- nextS++
- candidate = e.table[nextHash]
- now >>= 8
- e.table[nextHash] = tableEntry{offset: s + e.cur}
-
- offset = s - (candidate.offset - e.cur)
- if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) {
- break
- }
- cv = uint32(now)
- }
-
- // A 4-byte match has been found. We'll later see if more than 4 bytes
- // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
- // them as literal bytes.
-
- // Call emitCopy, and then see if another emitCopy could be our next
- // move. Repeat until we find no match for the input immediately after
- // what was consumed by the last emitCopy call.
- //
- // If we exit this loop normally then we need to call emitLiteral next,
- // though we don't yet know how big the literal will be. We handle that
- // by proceeding to the next iteration of the main loop. We also can
- // exit this loop via goto if we get close to exhausting the input.
- for {
- // Invariant: we have a 4-byte match at s, and no need to emit any
- // literal bytes prior to s.
-
- // Extend the 4-byte match as long as possible.
- t := candidate.offset - e.cur
- l := e.matchlenLong(s+4, t+4, src) + 4
-
- // Extend backwards
- for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
- s--
- t--
- l++
- }
- if nextEmit < s {
- emitLiteral(dst, src[nextEmit:s])
- }
-
- dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
- s += l
- nextEmit = s
- if nextS >= s {
- s = nextS + 1
- }
-
- if s >= sLimit {
- // Index first pair after match end.
- if int(s+l+4) < len(src) {
- cv := load3232(src, s)
- e.table[hash4u(cv, bTableBits)] = tableEntry{offset: s + e.cur}
- }
- goto emitRemainder
- }
-
- // Store every second hash in-between, but offset by 1.
- for i := s - l + 2; i < s-5; i += 7 {
- x := load6432(src, int32(i))
- nextHash := hash4u(uint32(x), bTableBits)
- e.table[nextHash] = tableEntry{offset: e.cur + i}
- // Skip one
- x >>= 16
- nextHash = hash4u(uint32(x), bTableBits)
- e.table[nextHash] = tableEntry{offset: e.cur + i + 2}
- // Skip one
- x >>= 16
- nextHash = hash4u(uint32(x), bTableBits)
- e.table[nextHash] = tableEntry{offset: e.cur + i + 4}
- }
-
- // We could immediately start working at s now, but to improve
- // compression we first update the hash table at s-2 to s. If
- // another emitCopy is not our next move, also calculate nextHash
- // at s+1. At least on GOARCH=amd64, these three hash calculations
- // are faster as one load64 call (with some shifts) instead of
- // three load32 calls.
- x := load6432(src, s-2)
- o := e.cur + s - 2
- prevHash := hash4u(uint32(x), bTableBits)
- prevHash2 := hash4u(uint32(x>>8), bTableBits)
- e.table[prevHash] = tableEntry{offset: o}
- e.table[prevHash2] = tableEntry{offset: o + 1}
- currHash := hash4u(uint32(x>>16), bTableBits)
- candidate = e.table[currHash]
- e.table[currHash] = tableEntry{offset: o + 2}
-
- offset := s - (candidate.offset - e.cur)
- if offset > maxMatchOffset || uint32(x>>16) != load3232(src, candidate.offset-e.cur) {
- cv = uint32(x >> 24)
- s++
- break
- }
- }
- }
-
-emitRemainder:
- if int(nextEmit) < len(src) {
- // If nothing was added, don't encode literals.
- if dst.n == 0 {
- return
- }
-
- emitLiteral(dst, src[nextEmit:])
- }
-}
diff --git a/vendor/github.com/klauspost/compress/flate/level3.go b/vendor/github.com/klauspost/compress/flate/level3.go
deleted file mode 100644
index c22b4244a5c..00000000000
--- a/vendor/github.com/klauspost/compress/flate/level3.go
+++ /dev/null
@@ -1,229 +0,0 @@
-package flate
-
-import "fmt"
-
-// fastEncL3
-type fastEncL3 struct {
- fastGen
- table [tableSize]tableEntryPrev
-}
-
-// Encode uses a similar algorithm to level 2, will check up to two candidates.
-func (e *fastEncL3) Encode(dst *tokens, src []byte) {
- const (
- inputMargin = 8 - 1
- minNonLiteralBlockSize = 1 + 1 + inputMargin
- )
-
- if debugDeflate && e.cur < 0 {
- panic(fmt.Sprint("e.cur < 0: ", e.cur))
- }
-
- // Protect against e.cur wraparound.
- for e.cur >= bufferReset {
- if len(e.hist) == 0 {
- for i := range e.table[:] {
- e.table[i] = tableEntryPrev{}
- }
- e.cur = maxMatchOffset
- break
- }
- // Shift down everything in the table that isn't already too far away.
- minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
- for i := range e.table[:] {
- v := e.table[i]
- if v.Cur.offset <= minOff {
- v.Cur.offset = 0
- } else {
- v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset
- }
- if v.Prev.offset <= minOff {
- v.Prev.offset = 0
- } else {
- v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset
- }
- e.table[i] = v
- }
- e.cur = maxMatchOffset
- }
-
- s := e.addBlock(src)
-
- // Skip if too small.
- if len(src) < minNonLiteralBlockSize {
- // We do not fill the token table.
- // This will be picked up by caller.
- dst.n = uint16(len(src))
- return
- }
-
- // Override src
- src = e.hist
- nextEmit := s
-
- // sLimit is when to stop looking for offset/length copies. The inputMargin
- // lets us use a fast path for emitLiteral in the main loop, while we are
- // looking for copies.
- sLimit := int32(len(src) - inputMargin)
-
- // nextEmit is where in src the next emitLiteral should start from.
- cv := load3232(src, s)
- for {
- const skipLog = 6
- nextS := s
- var candidate tableEntry
- for {
- nextHash := hash(cv)
- s = nextS
- nextS = s + 1 + (s-nextEmit)>>skipLog
- if nextS > sLimit {
- goto emitRemainder
- }
- candidates := e.table[nextHash]
- now := load3232(src, nextS)
-
- // Safe offset distance until s + 4...
- minOffset := e.cur + s - (maxMatchOffset - 4)
- e.table[nextHash] = tableEntryPrev{Prev: candidates.Cur, Cur: tableEntry{offset: s + e.cur}}
-
- // Check both candidates
- candidate = candidates.Cur
- if candidate.offset < minOffset {
- cv = now
- // Previous will also be invalid, we have nothing.
- continue
- }
-
- if cv == load3232(src, candidate.offset-e.cur) {
- if candidates.Prev.offset < minOffset || cv != load3232(src, candidates.Prev.offset-e.cur) {
- break
- }
- // Both match and are valid, pick longest.
- offset := s - (candidate.offset - e.cur)
- o2 := s - (candidates.Prev.offset - e.cur)
- l1, l2 := matchLen(src[s+4:], src[s-offset+4:]), matchLen(src[s+4:], src[s-o2+4:])
- if l2 > l1 {
- candidate = candidates.Prev
- }
- break
- } else {
- // We only check if value mismatches.
- // Offset will always be invalid in other cases.
- candidate = candidates.Prev
- if candidate.offset > minOffset && cv == load3232(src, candidate.offset-e.cur) {
- break
- }
- }
- cv = now
- }
-
- // Call emitCopy, and then see if another emitCopy could be our next
- // move. Repeat until we find no match for the input immediately after
- // what was consumed by the last emitCopy call.
- //
- // If we exit this loop normally then we need to call emitLiteral next,
- // though we don't yet know how big the literal will be. We handle that
- // by proceeding to the next iteration of the main loop. We also can
- // exit this loop via goto if we get close to exhausting the input.
- for {
- // Invariant: we have a 4-byte match at s, and no need to emit any
- // literal bytes prior to s.
-
- // Extend the 4-byte match as long as possible.
- //
- t := candidate.offset - e.cur
- l := e.matchlenLong(s+4, t+4, src) + 4
-
- // Extend backwards
- for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
- s--
- t--
- l++
- }
- if nextEmit < s {
- emitLiteral(dst, src[nextEmit:s])
- }
-
- dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
- s += l
- nextEmit = s
- if nextS >= s {
- s = nextS + 1
- }
-
- if s >= sLimit {
- t += l
- // Index first pair after match end.
- if int(t+4) < len(src) && t > 0 {
- cv := load3232(src, t)
- nextHash := hash(cv)
- e.table[nextHash] = tableEntryPrev{
- Prev: e.table[nextHash].Cur,
- Cur: tableEntry{offset: e.cur + t},
- }
- }
- goto emitRemainder
- }
-
- // We could immediately start working at s now, but to improve
- // compression we first update the hash table at s-3 to s.
- x := load6432(src, s-3)
- prevHash := hash(uint32(x))
- e.table[prevHash] = tableEntryPrev{
- Prev: e.table[prevHash].Cur,
- Cur: tableEntry{offset: e.cur + s - 3},
- }
- x >>= 8
- prevHash = hash(uint32(x))
-
- e.table[prevHash] = tableEntryPrev{
- Prev: e.table[prevHash].Cur,
- Cur: tableEntry{offset: e.cur + s - 2},
- }
- x >>= 8
- prevHash = hash(uint32(x))
-
- e.table[prevHash] = tableEntryPrev{
- Prev: e.table[prevHash].Cur,
- Cur: tableEntry{offset: e.cur + s - 1},
- }
- x >>= 8
- currHash := hash(uint32(x))
- candidates := e.table[currHash]
- cv = uint32(x)
- e.table[currHash] = tableEntryPrev{
- Prev: candidates.Cur,
- Cur: tableEntry{offset: s + e.cur},
- }
-
- // Check both candidates
- candidate = candidates.Cur
- minOffset := e.cur + s - (maxMatchOffset - 4)
-
- if candidate.offset > minOffset && cv != load3232(src, candidate.offset-e.cur) {
- // We only check if value mismatches.
- // Offset will always be invalid in other cases.
- candidate = candidates.Prev
- if candidate.offset > minOffset && cv == load3232(src, candidate.offset-e.cur) {
- offset := s - (candidate.offset - e.cur)
- if offset <= maxMatchOffset {
- continue
- }
- }
- }
- cv = uint32(x >> 8)
- s++
- break
- }
- }
-
-emitRemainder:
- if int(nextEmit) < len(src) {
- // If nothing was added, don't encode literals.
- if dst.n == 0 {
- return
- }
-
- emitLiteral(dst, src[nextEmit:])
- }
-}
diff --git a/vendor/github.com/klauspost/compress/flate/level4.go b/vendor/github.com/klauspost/compress/flate/level4.go
deleted file mode 100644
index e62f0c02b1e..00000000000
--- a/vendor/github.com/klauspost/compress/flate/level4.go
+++ /dev/null
@@ -1,212 +0,0 @@
-package flate
-
-import "fmt"
-
-type fastEncL4 struct {
- fastGen
- table [tableSize]tableEntry
- bTable [tableSize]tableEntry
-}
-
-func (e *fastEncL4) Encode(dst *tokens, src []byte) {
- const (
- inputMargin = 12 - 1
- minNonLiteralBlockSize = 1 + 1 + inputMargin
- )
- if debugDeflate && e.cur < 0 {
- panic(fmt.Sprint("e.cur < 0: ", e.cur))
- }
- // Protect against e.cur wraparound.
- for e.cur >= bufferReset {
- if len(e.hist) == 0 {
- for i := range e.table[:] {
- e.table[i] = tableEntry{}
- }
- for i := range e.bTable[:] {
- e.bTable[i] = tableEntry{}
- }
- e.cur = maxMatchOffset
- break
- }
- // Shift down everything in the table that isn't already too far away.
- minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
- for i := range e.table[:] {
- v := e.table[i].offset
- if v <= minOff {
- v = 0
- } else {
- v = v - e.cur + maxMatchOffset
- }
- e.table[i].offset = v
- }
- for i := range e.bTable[:] {
- v := e.bTable[i].offset
- if v <= minOff {
- v = 0
- } else {
- v = v - e.cur + maxMatchOffset
- }
- e.bTable[i].offset = v
- }
- e.cur = maxMatchOffset
- }
-
- s := e.addBlock(src)
-
- // This check isn't in the Snappy implementation, but there, the caller
- // instead of the callee handles this case.
- if len(src) < minNonLiteralBlockSize {
- // We do not fill the token table.
- // This will be picked up by caller.
- dst.n = uint16(len(src))
- return
- }
-
- // Override src
- src = e.hist
- nextEmit := s
-
- // sLimit is when to stop looking for offset/length copies. The inputMargin
- // lets us use a fast path for emitLiteral in the main loop, while we are
- // looking for copies.
- sLimit := int32(len(src) - inputMargin)
-
- // nextEmit is where in src the next emitLiteral should start from.
- cv := load6432(src, s)
- for {
- const skipLog = 6
- const doEvery = 1
-
- nextS := s
- var t int32
- for {
- nextHashS := hash4x64(cv, tableBits)
- nextHashL := hash7(cv, tableBits)
-
- s = nextS
- nextS = s + doEvery + (s-nextEmit)>>skipLog
- if nextS > sLimit {
- goto emitRemainder
- }
- // Fetch a short+long candidate
- sCandidate := e.table[nextHashS]
- lCandidate := e.bTable[nextHashL]
- next := load6432(src, nextS)
- entry := tableEntry{offset: s + e.cur}
- e.table[nextHashS] = entry
- e.bTable[nextHashL] = entry
-
- t = lCandidate.offset - e.cur
- if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.offset-e.cur) {
- // We got a long match. Use that.
- break
- }
-
- t = sCandidate.offset - e.cur
- if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) {
- // Found a 4 match...
- lCandidate = e.bTable[hash7(next, tableBits)]
-
- // If the next long is a candidate, check if we should use that instead...
- lOff := nextS - (lCandidate.offset - e.cur)
- if lOff < maxMatchOffset && load3232(src, lCandidate.offset-e.cur) == uint32(next) {
- l1, l2 := matchLen(src[s+4:], src[t+4:]), matchLen(src[nextS+4:], src[nextS-lOff+4:])
- if l2 > l1 {
- s = nextS
- t = lCandidate.offset - e.cur
- }
- }
- break
- }
- cv = next
- }
-
- // A 4-byte match has been found. We'll later see if more than 4 bytes
- // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
- // them as literal bytes.
-
- // Extend the 4-byte match as long as possible.
- l := e.matchlenLong(s+4, t+4, src) + 4
-
- // Extend backwards
- for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
- s--
- t--
- l++
- }
- if nextEmit < s {
- emitLiteral(dst, src[nextEmit:s])
- }
- if debugDeflate {
- if t >= s {
- panic("s-t")
- }
- if (s - t) > maxMatchOffset {
- panic(fmt.Sprintln("mmo", t))
- }
- if l < baseMatchLength {
- panic("bml")
- }
- }
-
- dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
- s += l
- nextEmit = s
- if nextS >= s {
- s = nextS + 1
- }
-
- if s >= sLimit {
- // Index first pair after match end.
- if int(s+8) < len(src) {
- cv := load6432(src, s)
- e.table[hash4x64(cv, tableBits)] = tableEntry{offset: s + e.cur}
- e.bTable[hash7(cv, tableBits)] = tableEntry{offset: s + e.cur}
- }
- goto emitRemainder
- }
-
- // Store every 3rd hash in-between
- if true {
- i := nextS
- if i < s-1 {
- cv := load6432(src, i)
- t := tableEntry{offset: i + e.cur}
- t2 := tableEntry{offset: t.offset + 1}
- e.bTable[hash7(cv, tableBits)] = t
- e.bTable[hash7(cv>>8, tableBits)] = t2
- e.table[hash4u(uint32(cv>>8), tableBits)] = t2
-
- i += 3
- for ; i < s-1; i += 3 {
- cv := load6432(src, i)
- t := tableEntry{offset: i + e.cur}
- t2 := tableEntry{offset: t.offset + 1}
- e.bTable[hash7(cv, tableBits)] = t
- e.bTable[hash7(cv>>8, tableBits)] = t2
- e.table[hash4u(uint32(cv>>8), tableBits)] = t2
- }
- }
- }
-
- // We could immediately start working at s now, but to improve
- // compression we first update the hash table at s-1 and at s.
- x := load6432(src, s-1)
- o := e.cur + s - 1
- prevHashS := hash4x64(x, tableBits)
- prevHashL := hash7(x, tableBits)
- e.table[prevHashS] = tableEntry{offset: o}
- e.bTable[prevHashL] = tableEntry{offset: o}
- cv = x >> 8
- }
-
-emitRemainder:
- if int(nextEmit) < len(src) {
- // If nothing was added, don't encode literals.
- if dst.n == 0 {
- return
- }
-
- emitLiteral(dst, src[nextEmit:])
- }
-}
diff --git a/vendor/github.com/klauspost/compress/flate/level5.go b/vendor/github.com/klauspost/compress/flate/level5.go
deleted file mode 100644
index d513f1ffd37..00000000000
--- a/vendor/github.com/klauspost/compress/flate/level5.go
+++ /dev/null
@@ -1,279 +0,0 @@
-package flate
-
-import "fmt"
-
-type fastEncL5 struct {
- fastGen
- table [tableSize]tableEntry
- bTable [tableSize]tableEntryPrev
-}
-
-func (e *fastEncL5) Encode(dst *tokens, src []byte) {
- const (
- inputMargin = 12 - 1
- minNonLiteralBlockSize = 1 + 1 + inputMargin
- )
- if debugDeflate && e.cur < 0 {
- panic(fmt.Sprint("e.cur < 0: ", e.cur))
- }
-
- // Protect against e.cur wraparound.
- for e.cur >= bufferReset {
- if len(e.hist) == 0 {
- for i := range e.table[:] {
- e.table[i] = tableEntry{}
- }
- for i := range e.bTable[:] {
- e.bTable[i] = tableEntryPrev{}
- }
- e.cur = maxMatchOffset
- break
- }
- // Shift down everything in the table that isn't already too far away.
- minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
- for i := range e.table[:] {
- v := e.table[i].offset
- if v <= minOff {
- v = 0
- } else {
- v = v - e.cur + maxMatchOffset
- }
- e.table[i].offset = v
- }
- for i := range e.bTable[:] {
- v := e.bTable[i]
- if v.Cur.offset <= minOff {
- v.Cur.offset = 0
- v.Prev.offset = 0
- } else {
- v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset
- if v.Prev.offset <= minOff {
- v.Prev.offset = 0
- } else {
- v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset
- }
- }
- e.bTable[i] = v
- }
- e.cur = maxMatchOffset
- }
-
- s := e.addBlock(src)
-
- // This check isn't in the Snappy implementation, but there, the caller
- // instead of the callee handles this case.
- if len(src) < minNonLiteralBlockSize {
- // We do not fill the token table.
- // This will be picked up by caller.
- dst.n = uint16(len(src))
- return
- }
-
- // Override src
- src = e.hist
- nextEmit := s
-
- // sLimit is when to stop looking for offset/length copies. The inputMargin
- // lets us use a fast path for emitLiteral in the main loop, while we are
- // looking for copies.
- sLimit := int32(len(src) - inputMargin)
-
- // nextEmit is where in src the next emitLiteral should start from.
- cv := load6432(src, s)
- for {
- const skipLog = 6
- const doEvery = 1
-
- nextS := s
- var l int32
- var t int32
- for {
- nextHashS := hash4x64(cv, tableBits)
- nextHashL := hash7(cv, tableBits)
-
- s = nextS
- nextS = s + doEvery + (s-nextEmit)>>skipLog
- if nextS > sLimit {
- goto emitRemainder
- }
- // Fetch a short+long candidate
- sCandidate := e.table[nextHashS]
- lCandidate := e.bTable[nextHashL]
- next := load6432(src, nextS)
- entry := tableEntry{offset: s + e.cur}
- e.table[nextHashS] = entry
- eLong := &e.bTable[nextHashL]
- eLong.Cur, eLong.Prev = entry, eLong.Cur
-
- nextHashS = hash4x64(next, tableBits)
- nextHashL = hash7(next, tableBits)
-
- t = lCandidate.Cur.offset - e.cur
- if s-t < maxMatchOffset {
- if uint32(cv) == load3232(src, lCandidate.Cur.offset-e.cur) {
- // Store the next match
- e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
- eLong := &e.bTable[nextHashL]
- eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
-
- t2 := lCandidate.Prev.offset - e.cur
- if s-t2 < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
- l = e.matchlen(s+4, t+4, src) + 4
- ml1 := e.matchlen(s+4, t2+4, src) + 4
- if ml1 > l {
- t = t2
- l = ml1
- break
- }
- }
- break
- }
- t = lCandidate.Prev.offset - e.cur
- if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
- // Store the next match
- e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
- eLong := &e.bTable[nextHashL]
- eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
- break
- }
- }
-
- t = sCandidate.offset - e.cur
- if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) {
- // Found a 4 match...
- l = e.matchlen(s+4, t+4, src) + 4
- lCandidate = e.bTable[nextHashL]
- // Store the next match
-
- e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
- eLong := &e.bTable[nextHashL]
- eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
-
- // If the next long is a candidate, use that...
- t2 := lCandidate.Cur.offset - e.cur
- if nextS-t2 < maxMatchOffset {
- if load3232(src, lCandidate.Cur.offset-e.cur) == uint32(next) {
- ml := e.matchlen(nextS+4, t2+4, src) + 4
- if ml > l {
- t = t2
- s = nextS
- l = ml
- break
- }
- }
- // If the previous long is a candidate, use that...
- t2 = lCandidate.Prev.offset - e.cur
- if nextS-t2 < maxMatchOffset && load3232(src, lCandidate.Prev.offset-e.cur) == uint32(next) {
- ml := e.matchlen(nextS+4, t2+4, src) + 4
- if ml > l {
- t = t2
- s = nextS
- l = ml
- break
- }
- }
- }
- break
- }
- cv = next
- }
-
- // A 4-byte match has been found. We'll later see if more than 4 bytes
- // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
- // them as literal bytes.
-
- // Extend the 4-byte match as long as possible.
- if l == 0 {
- l = e.matchlenLong(s+4, t+4, src) + 4
- } else if l == maxMatchLength {
- l += e.matchlenLong(s+l, t+l, src)
- }
- // Extend backwards
- for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
- s--
- t--
- l++
- }
- if nextEmit < s {
- emitLiteral(dst, src[nextEmit:s])
- }
- if debugDeflate {
- if t >= s {
- panic(fmt.Sprintln("s-t", s, t))
- }
- if (s - t) > maxMatchOffset {
- panic(fmt.Sprintln("mmo", s-t))
- }
- if l < baseMatchLength {
- panic("bml")
- }
- }
-
- dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
- s += l
- nextEmit = s
- if nextS >= s {
- s = nextS + 1
- }
-
- if s >= sLimit {
- goto emitRemainder
- }
-
- // Store every 3rd hash in-between.
- if true {
- const hashEvery = 3
- i := s - l + 1
- if i < s-1 {
- cv := load6432(src, i)
- t := tableEntry{offset: i + e.cur}
- e.table[hash4x64(cv, tableBits)] = t
- eLong := &e.bTable[hash7(cv, tableBits)]
- eLong.Cur, eLong.Prev = t, eLong.Cur
-
- // Do an long at i+1
- cv >>= 8
- t = tableEntry{offset: t.offset + 1}
- eLong = &e.bTable[hash7(cv, tableBits)]
- eLong.Cur, eLong.Prev = t, eLong.Cur
-
- // We only have enough bits for a short entry at i+2
- cv >>= 8
- t = tableEntry{offset: t.offset + 1}
- e.table[hash4x64(cv, tableBits)] = t
-
- // Skip one - otherwise we risk hitting 's'
- i += 4
- for ; i < s-1; i += hashEvery {
- cv := load6432(src, i)
- t := tableEntry{offset: i + e.cur}
- t2 := tableEntry{offset: t.offset + 1}
- eLong := &e.bTable[hash7(cv, tableBits)]
- eLong.Cur, eLong.Prev = t, eLong.Cur
- e.table[hash4u(uint32(cv>>8), tableBits)] = t2
- }
- }
- }
-
- // We could immediately start working at s now, but to improve
- // compression we first update the hash table at s-1 and at s.
- x := load6432(src, s-1)
- o := e.cur + s - 1
- prevHashS := hash4x64(x, tableBits)
- prevHashL := hash7(x, tableBits)
- e.table[prevHashS] = tableEntry{offset: o}
- eLong := &e.bTable[prevHashL]
- eLong.Cur, eLong.Prev = tableEntry{offset: o}, eLong.Cur
- cv = x >> 8
- }
-
-emitRemainder:
- if int(nextEmit) < len(src) {
- // If nothing was added, don't encode literals.
- if dst.n == 0 {
- return
- }
-
- emitLiteral(dst, src[nextEmit:])
- }
-}
diff --git a/vendor/github.com/klauspost/compress/flate/level6.go b/vendor/github.com/klauspost/compress/flate/level6.go
deleted file mode 100644
index a52c80ea456..00000000000
--- a/vendor/github.com/klauspost/compress/flate/level6.go
+++ /dev/null
@@ -1,282 +0,0 @@
-package flate
-
-import "fmt"
-
-type fastEncL6 struct {
- fastGen
- table [tableSize]tableEntry
- bTable [tableSize]tableEntryPrev
-}
-
-func (e *fastEncL6) Encode(dst *tokens, src []byte) {
- const (
- inputMargin = 12 - 1
- minNonLiteralBlockSize = 1 + 1 + inputMargin
- )
- if debugDeflate && e.cur < 0 {
- panic(fmt.Sprint("e.cur < 0: ", e.cur))
- }
-
- // Protect against e.cur wraparound.
- for e.cur >= bufferReset {
- if len(e.hist) == 0 {
- for i := range e.table[:] {
- e.table[i] = tableEntry{}
- }
- for i := range e.bTable[:] {
- e.bTable[i] = tableEntryPrev{}
- }
- e.cur = maxMatchOffset
- break
- }
- // Shift down everything in the table that isn't already too far away.
- minOff := e.cur + int32(len(e.hist)) - maxMatchOffset
- for i := range e.table[:] {
- v := e.table[i].offset
- if v <= minOff {
- v = 0
- } else {
- v = v - e.cur + maxMatchOffset
- }
- e.table[i].offset = v
- }
- for i := range e.bTable[:] {
- v := e.bTable[i]
- if v.Cur.offset <= minOff {
- v.Cur.offset = 0
- v.Prev.offset = 0
- } else {
- v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset
- if v.Prev.offset <= minOff {
- v.Prev.offset = 0
- } else {
- v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset
- }
- }
- e.bTable[i] = v
- }
- e.cur = maxMatchOffset
- }
-
- s := e.addBlock(src)
-
- // This check isn't in the Snappy implementation, but there, the caller
- // instead of the callee handles this case.
- if len(src) < minNonLiteralBlockSize {
- // We do not fill the token table.
- // This will be picked up by caller.
- dst.n = uint16(len(src))
- return
- }
-
- // Override src
- src = e.hist
- nextEmit := s
-
- // sLimit is when to stop looking for offset/length copies. The inputMargin
- // lets us use a fast path for emitLiteral in the main loop, while we are
- // looking for copies.
- sLimit := int32(len(src) - inputMargin)
-
- // nextEmit is where in src the next emitLiteral should start from.
- cv := load6432(src, s)
- // Repeat MUST be > 1 and within range
- repeat := int32(1)
- for {
- const skipLog = 7
- const doEvery = 1
-
- nextS := s
- var l int32
- var t int32
- for {
- nextHashS := hash4x64(cv, tableBits)
- nextHashL := hash7(cv, tableBits)
- s = nextS
- nextS = s + doEvery + (s-nextEmit)>>skipLog
- if nextS > sLimit {
- goto emitRemainder
- }
- // Fetch a short+long candidate
- sCandidate := e.table[nextHashS]
- lCandidate := e.bTable[nextHashL]
- next := load6432(src, nextS)
- entry := tableEntry{offset: s + e.cur}
- e.table[nextHashS] = entry
- eLong := &e.bTable[nextHashL]
- eLong.Cur, eLong.Prev = entry, eLong.Cur
-
- // Calculate hashes of 'next'
- nextHashS = hash4x64(next, tableBits)
- nextHashL = hash7(next, tableBits)
-
- t = lCandidate.Cur.offset - e.cur
- if s-t < maxMatchOffset {
- if uint32(cv) == load3232(src, lCandidate.Cur.offset-e.cur) {
- // Long candidate matches at least 4 bytes.
-
- // Store the next match
- e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
- eLong := &e.bTable[nextHashL]
- eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
-
- // Check the previous long candidate as well.
- t2 := lCandidate.Prev.offset - e.cur
- if s-t2 < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
- l = e.matchlen(s+4, t+4, src) + 4
- ml1 := e.matchlen(s+4, t2+4, src) + 4
- if ml1 > l {
- t = t2
- l = ml1
- break
- }
- }
- break
- }
- // Current value did not match, but check if previous long value does.
- t = lCandidate.Prev.offset - e.cur
- if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) {
- // Store the next match
- e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
- eLong := &e.bTable[nextHashL]
- eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
- break
- }
- }
-
- t = sCandidate.offset - e.cur
- if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) {
- // Found a 4 match...
- l = e.matchlen(s+4, t+4, src) + 4
-
- // Look up next long candidate (at nextS)
- lCandidate = e.bTable[nextHashL]
-
- // Store the next match
- e.table[nextHashS] = tableEntry{offset: nextS + e.cur}
- eLong := &e.bTable[nextHashL]
- eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur
-
- // Check repeat at s + repOff
- const repOff = 1
- t2 := s - repeat + repOff
- if load3232(src, t2) == uint32(cv>>(8*repOff)) {
- ml := e.matchlen(s+4+repOff, t2+4, src) + 4
- if ml > l {
- t = t2
- l = ml
- s += repOff
- // Not worth checking more.
- break
- }
- }
-
- // If the next long is a candidate, use that...
- t2 = lCandidate.Cur.offset - e.cur
- if nextS-t2 < maxMatchOffset {
- if load3232(src, lCandidate.Cur.offset-e.cur) == uint32(next) {
- ml := e.matchlen(nextS+4, t2+4, src) + 4
- if ml > l {
- t = t2
- s = nextS
- l = ml
- // This is ok, but check previous as well.
- }
- }
- // If the previous long is a candidate, use that...
- t2 = lCandidate.Prev.offset - e.cur
- if nextS-t2 < maxMatchOffset && load3232(src, lCandidate.Prev.offset-e.cur) == uint32(next) {
- ml := e.matchlen(nextS+4, t2+4, src) + 4
- if ml > l {
- t = t2
- s = nextS
- l = ml
- break
- }
- }
- }
- break
- }
- cv = next
- }
-
- // A 4-byte match has been found. We'll later see if more than 4 bytes
- // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
- // them as literal bytes.
-
- // Extend the 4-byte match as long as possible.
- if l == 0 {
- l = e.matchlenLong(s+4, t+4, src) + 4
- } else if l == maxMatchLength {
- l += e.matchlenLong(s+l, t+l, src)
- }
-
- // Extend backwards
- for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
- s--
- t--
- l++
- }
- if nextEmit < s {
- emitLiteral(dst, src[nextEmit:s])
- }
- if false {
- if t >= s {
- panic(fmt.Sprintln("s-t", s, t))
- }
- if (s - t) > maxMatchOffset {
- panic(fmt.Sprintln("mmo", s-t))
- }
- if l < baseMatchLength {
- panic("bml")
- }
- }
-
- dst.AddMatchLong(l, uint32(s-t-baseMatchOffset))
- repeat = s - t
- s += l
- nextEmit = s
- if nextS >= s {
- s = nextS + 1
- }
-
- if s >= sLimit {
- // Index after match end.
- for i := nextS + 1; i < int32(len(src))-8; i += 2 {
- cv := load6432(src, i)
- e.table[hash4x64(cv, tableBits)] = tableEntry{offset: i + e.cur}
- eLong := &e.bTable[hash7(cv, tableBits)]
- eLong.Cur, eLong.Prev = tableEntry{offset: i + e.cur}, eLong.Cur
- }
- goto emitRemainder
- }
-
- // Store every long hash in-between and every second short.
- if true {
- for i := nextS + 1; i < s-1; i += 2 {
- cv := load6432(src, i)
- t := tableEntry{offset: i + e.cur}
- t2 := tableEntry{offset: t.offset + 1}
- eLong := &e.bTable[hash7(cv, tableBits)]
- eLong2 := &e.bTable[hash7(cv>>8, tableBits)]
- e.table[hash4x64(cv, tableBits)] = t
- eLong.Cur, eLong.Prev = t, eLong.Cur
- eLong2.Cur, eLong2.Prev = t2, eLong2.Cur
- }
- }
-
- // We could immediately start working at s now, but to improve
- // compression we first update the hash table at s-1 and at s.
- cv = load6432(src, s)
- }
-
-emitRemainder:
- if int(nextEmit) < len(src) {
- // If nothing was added, don't encode literals.
- if dst.n == 0 {
- return
- }
-
- emitLiteral(dst, src[nextEmit:])
- }
-}
diff --git a/vendor/github.com/klauspost/compress/flate/stateless.go b/vendor/github.com/klauspost/compress/flate/stateless.go
deleted file mode 100644
index 53e89912463..00000000000
--- a/vendor/github.com/klauspost/compress/flate/stateless.go
+++ /dev/null
@@ -1,297 +0,0 @@
-package flate
-
-import (
- "io"
- "math"
- "sync"
-)
-
-const (
- maxStatelessBlock = math.MaxInt16
- // dictionary will be taken from maxStatelessBlock, so limit it.
- maxStatelessDict = 8 << 10
-
- slTableBits = 13
- slTableSize = 1 << slTableBits
- slTableShift = 32 - slTableBits
-)
-
-type statelessWriter struct {
- dst io.Writer
- closed bool
-}
-
-func (s *statelessWriter) Close() error {
- if s.closed {
- return nil
- }
- s.closed = true
- // Emit EOF block
- return StatelessDeflate(s.dst, nil, true, nil)
-}
-
-func (s *statelessWriter) Write(p []byte) (n int, err error) {
- err = StatelessDeflate(s.dst, p, false, nil)
- if err != nil {
- return 0, err
- }
- return len(p), nil
-}
-
-func (s *statelessWriter) Reset(w io.Writer) {
- s.dst = w
- s.closed = false
-}
-
-// NewStatelessWriter will do compression but without maintaining any state
-// between Write calls.
-// There will be no memory kept between Write calls,
-// but compression and speed will be suboptimal.
-// Because of this, the size of actual Write calls will affect output size.
-func NewStatelessWriter(dst io.Writer) io.WriteCloser {
- return &statelessWriter{dst: dst}
-}
-
-// bitWriterPool contains bit writers that can be reused.
-var bitWriterPool = sync.Pool{
- New: func() interface{} {
- return newHuffmanBitWriter(nil)
- },
-}
-
-// StatelessDeflate allows to compress directly to a Writer without retaining state.
-// When returning everything will be flushed.
-// Up to 8KB of an optional dictionary can be given which is presumed to presumed to precede the block.
-// Longer dictionaries will be truncated and will still produce valid output.
-// Sending nil dictionary is perfectly fine.
-func StatelessDeflate(out io.Writer, in []byte, eof bool, dict []byte) error {
- var dst tokens
- bw := bitWriterPool.Get().(*huffmanBitWriter)
- bw.reset(out)
- defer func() {
- // don't keep a reference to our output
- bw.reset(nil)
- bitWriterPool.Put(bw)
- }()
- if eof && len(in) == 0 {
- // Just write an EOF block.
- // Could be faster...
- bw.writeStoredHeader(0, true)
- bw.flush()
- return bw.err
- }
-
- // Truncate dict
- if len(dict) > maxStatelessDict {
- dict = dict[len(dict)-maxStatelessDict:]
- }
-
- for len(in) > 0 {
- todo := in
- if len(todo) > maxStatelessBlock-len(dict) {
- todo = todo[:maxStatelessBlock-len(dict)]
- }
- in = in[len(todo):]
- uncompressed := todo
- if len(dict) > 0 {
- // combine dict and source
- bufLen := len(todo) + len(dict)
- combined := make([]byte, bufLen)
- copy(combined, dict)
- copy(combined[len(dict):], todo)
- todo = combined
- }
- // Compress
- statelessEnc(&dst, todo, int16(len(dict)))
- isEof := eof && len(in) == 0
-
- if dst.n == 0 {
- bw.writeStoredHeader(len(uncompressed), isEof)
- if bw.err != nil {
- return bw.err
- }
- bw.writeBytes(uncompressed)
- } else if int(dst.n) > len(uncompressed)-len(uncompressed)>>4 {
- // If we removed less than 1/16th, huffman compress the block.
- bw.writeBlockHuff(isEof, uncompressed, len(in) == 0)
- } else {
- bw.writeBlockDynamic(&dst, isEof, uncompressed, len(in) == 0)
- }
- if len(in) > 0 {
- // Retain a dict if we have more
- dict = todo[len(todo)-maxStatelessDict:]
- dst.Reset()
- }
- if bw.err != nil {
- return bw.err
- }
- }
- if !eof {
- // Align, only a stored block can do that.
- bw.writeStoredHeader(0, false)
- }
- bw.flush()
- return bw.err
-}
-
-func hashSL(u uint32) uint32 {
- return (u * 0x1e35a7bd) >> slTableShift
-}
-
-func load3216(b []byte, i int16) uint32 {
- // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
- b = b[i:]
- b = b[:4]
- return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
-}
-
-func load6416(b []byte, i int16) uint64 {
- // Help the compiler eliminate bounds checks on the read so it can be done in a single read.
- b = b[i:]
- b = b[:8]
- return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
- uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
-}
-
-func statelessEnc(dst *tokens, src []byte, startAt int16) {
- const (
- inputMargin = 12 - 1
- minNonLiteralBlockSize = 1 + 1 + inputMargin
- )
-
- type tableEntry struct {
- offset int16
- }
-
- var table [slTableSize]tableEntry
-
- // This check isn't in the Snappy implementation, but there, the caller
- // instead of the callee handles this case.
- if len(src)-int(startAt) < minNonLiteralBlockSize {
- // We do not fill the token table.
- // This will be picked up by caller.
- dst.n = 0
- return
- }
- // Index until startAt
- if startAt > 0 {
- cv := load3232(src, 0)
- for i := int16(0); i < startAt; i++ {
- table[hashSL(cv)] = tableEntry{offset: i}
- cv = (cv >> 8) | (uint32(src[i+4]) << 24)
- }
- }
-
- s := startAt + 1
- nextEmit := startAt
- // sLimit is when to stop looking for offset/length copies. The inputMargin
- // lets us use a fast path for emitLiteral in the main loop, while we are
- // looking for copies.
- sLimit := int16(len(src) - inputMargin)
-
- // nextEmit is where in src the next emitLiteral should start from.
- cv := load3216(src, s)
-
- for {
- const skipLog = 5
- const doEvery = 2
-
- nextS := s
- var candidate tableEntry
- for {
- nextHash := hashSL(cv)
- candidate = table[nextHash]
- nextS = s + doEvery + (s-nextEmit)>>skipLog
- if nextS > sLimit || nextS <= 0 {
- goto emitRemainder
- }
-
- now := load6416(src, nextS)
- table[nextHash] = tableEntry{offset: s}
- nextHash = hashSL(uint32(now))
-
- if cv == load3216(src, candidate.offset) {
- table[nextHash] = tableEntry{offset: nextS}
- break
- }
-
- // Do one right away...
- cv = uint32(now)
- s = nextS
- nextS++
- candidate = table[nextHash]
- now >>= 8
- table[nextHash] = tableEntry{offset: s}
-
- if cv == load3216(src, candidate.offset) {
- table[nextHash] = tableEntry{offset: nextS}
- break
- }
- cv = uint32(now)
- s = nextS
- }
-
- // A 4-byte match has been found. We'll later see if more than 4 bytes
- // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
- // them as literal bytes.
- for {
- // Invariant: we have a 4-byte match at s, and no need to emit any
- // literal bytes prior to s.
-
- // Extend the 4-byte match as long as possible.
- t := candidate.offset
- l := int16(matchLen(src[s+4:], src[t+4:]) + 4)
-
- // Extend backwards
- for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
- s--
- t--
- l++
- }
- if nextEmit < s {
- emitLiteral(dst, src[nextEmit:s])
- }
-
- // Save the match found
- dst.AddMatchLong(int32(l), uint32(s-t-baseMatchOffset))
- s += l
- nextEmit = s
- if nextS >= s {
- s = nextS + 1
- }
- if s >= sLimit {
- goto emitRemainder
- }
-
- // We could immediately start working at s now, but to improve
- // compression we first update the hash table at s-2 and at s. If
- // another emitCopy is not our next move, also calculate nextHash
- // at s+1. At least on GOARCH=amd64, these three hash calculations
- // are faster as one load64 call (with some shifts) instead of
- // three load32 calls.
- x := load6416(src, s-2)
- o := s - 2
- prevHash := hashSL(uint32(x))
- table[prevHash] = tableEntry{offset: o}
- x >>= 16
- currHash := hashSL(uint32(x))
- candidate = table[currHash]
- table[currHash] = tableEntry{offset: o + 2}
-
- if uint32(x) != load3216(src, candidate.offset) {
- cv = uint32(x >> 8)
- s++
- break
- }
- }
- }
-
-emitRemainder:
- if int(nextEmit) < len(src) {
- // If nothing was added, don't encode literals.
- if dst.n == 0 {
- return
- }
- emitLiteral(dst, src[nextEmit:])
- }
-}
diff --git a/vendor/github.com/klauspost/compress/flate/token.go b/vendor/github.com/klauspost/compress/flate/token.go
deleted file mode 100644
index f9abf606d67..00000000000
--- a/vendor/github.com/klauspost/compress/flate/token.go
+++ /dev/null
@@ -1,375 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package flate
-
-import (
- "bytes"
- "encoding/binary"
- "fmt"
- "io"
- "math"
-)
-
-const (
- // 2 bits: type 0 = literal 1=EOF 2=Match 3=Unused
- // 8 bits: xlength = length - MIN_MATCH_LENGTH
- // 22 bits xoffset = offset - MIN_OFFSET_SIZE, or literal
- lengthShift = 22
- offsetMask = 1<maxnumlit
- offHist [32]uint16 // offset codes
- litHist [256]uint16 // codes 0->255
- n uint16 // Must be able to contain maxStoreBlockSize
- tokens [maxStoreBlockSize + 1]token
-}
-
-func (t *tokens) Reset() {
- if t.n == 0 {
- return
- }
- t.n = 0
- t.nLits = 0
- for i := range t.litHist[:] {
- t.litHist[i] = 0
- }
- for i := range t.extraHist[:] {
- t.extraHist[i] = 0
- }
- for i := range t.offHist[:] {
- t.offHist[i] = 0
- }
-}
-
-func (t *tokens) Fill() {
- if t.n == 0 {
- return
- }
- for i, v := range t.litHist[:] {
- if v == 0 {
- t.litHist[i] = 1
- t.nLits++
- }
- }
- for i, v := range t.extraHist[:literalCount-256] {
- if v == 0 {
- t.nLits++
- t.extraHist[i] = 1
- }
- }
- for i, v := range t.offHist[:offsetCodeCount] {
- if v == 0 {
- t.offHist[i] = 1
- }
- }
-}
-
-func indexTokens(in []token) tokens {
- var t tokens
- t.indexTokens(in)
- return t
-}
-
-func (t *tokens) indexTokens(in []token) {
- t.Reset()
- for _, tok := range in {
- if tok < matchType {
- t.AddLiteral(tok.literal())
- continue
- }
- t.AddMatch(uint32(tok.length()), tok.offset())
- }
-}
-
-// emitLiteral writes a literal chunk and returns the number of bytes written.
-func emitLiteral(dst *tokens, lit []byte) {
- ol := int(dst.n)
- for i, v := range lit {
- dst.tokens[(i+ol)&maxStoreBlockSize] = token(v)
- dst.litHist[v]++
- }
- dst.n += uint16(len(lit))
- dst.nLits += len(lit)
-}
-
-func (t *tokens) AddLiteral(lit byte) {
- t.tokens[t.n] = token(lit)
- t.litHist[lit]++
- t.n++
- t.nLits++
-}
-
-// from https://stackoverflow.com/a/28730362
-func mFastLog2(val float32) float32 {
- ux := int32(math.Float32bits(val))
- log2 := (float32)(((ux >> 23) & 255) - 128)
- ux &= -0x7f800001
- ux += 127 << 23
- uval := math.Float32frombits(uint32(ux))
- log2 += ((-0.34484843)*uval+2.02466578)*uval - 0.67487759
- return log2
-}
-
-// EstimatedBits will return an minimum size estimated by an *optimal*
-// compression of the block.
-// The size of the block
-func (t *tokens) EstimatedBits() int {
- shannon := float32(0)
- bits := int(0)
- nMatches := 0
- if t.nLits > 0 {
- invTotal := 1.0 / float32(t.nLits)
- for _, v := range t.litHist[:] {
- if v > 0 {
- n := float32(v)
- shannon += -mFastLog2(n*invTotal) * n
- }
- }
- // Just add 15 for EOB
- shannon += 15
- for i, v := range t.extraHist[1 : literalCount-256] {
- if v > 0 {
- n := float32(v)
- shannon += -mFastLog2(n*invTotal) * n
- bits += int(lengthExtraBits[i&31]) * int(v)
- nMatches += int(v)
- }
- }
- }
- if nMatches > 0 {
- invTotal := 1.0 / float32(nMatches)
- for i, v := range t.offHist[:offsetCodeCount] {
- if v > 0 {
- n := float32(v)
- shannon += -mFastLog2(n*invTotal) * n
- bits += int(offsetExtraBits[i&31]) * int(v)
- }
- }
- }
- return int(shannon) + bits
-}
-
-// AddMatch adds a match to the tokens.
-// This function is very sensitive to inlining and right on the border.
-func (t *tokens) AddMatch(xlength uint32, xoffset uint32) {
- if debugDeflate {
- if xlength >= maxMatchLength+baseMatchLength {
- panic(fmt.Errorf("invalid length: %v", xlength))
- }
- if xoffset >= maxMatchOffset+baseMatchOffset {
- panic(fmt.Errorf("invalid offset: %v", xoffset))
- }
- }
- t.nLits++
- lengthCode := lengthCodes1[uint8(xlength)] & 31
- t.tokens[t.n] = token(matchType | xlength<= maxMatchOffset+baseMatchOffset {
- panic(fmt.Errorf("invalid offset: %v", xoffset))
- }
- }
- oc := offsetCode(xoffset) & 31
- for xlength > 0 {
- xl := xlength
- if xl > 258 {
- // We need to have at least baseMatchLength left over for next loop.
- xl = 258 - baseMatchLength
- }
- xlength -= xl
- xl -= 3
- t.nLits++
- lengthCode := lengthCodes1[uint8(xl)] & 31
- t.tokens[t.n] = token(matchType | uint32(xl)<> lengthShift) }
-
-// The code is never more than 8 bits, but is returned as uint32 for convenience.
-func lengthCode(len uint8) uint32 { return uint32(lengthCodes[len]) }
-
-// Returns the offset code corresponding to a specific offset
-func offsetCode(off uint32) uint32 {
- if false {
- if off < uint32(len(offsetCodes)) {
- return offsetCodes[off&255]
- } else if off>>7 < uint32(len(offsetCodes)) {
- return offsetCodes[(off>>7)&255] + 14
- } else {
- return offsetCodes[(off>>14)&255] + 28
- }
- }
- if off < uint32(len(offsetCodes)) {
- return offsetCodes[uint8(off)]
- }
- return offsetCodes14[uint8(off>>7)]
-}
diff --git a/vendor/github.com/klauspost/compress/gzip/gunzip.go b/vendor/github.com/klauspost/compress/gzip/gunzip.go
deleted file mode 100644
index 568b5d4fb8b..00000000000
--- a/vendor/github.com/klauspost/compress/gzip/gunzip.go
+++ /dev/null
@@ -1,344 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package gzip implements reading and writing of gzip format compressed files,
-// as specified in RFC 1952.
-package gzip
-
-import (
- "bufio"
- "encoding/binary"
- "errors"
- "hash/crc32"
- "io"
- "time"
-
- "github.com/klauspost/compress/flate"
-)
-
-const (
- gzipID1 = 0x1f
- gzipID2 = 0x8b
- gzipDeflate = 8
- flagText = 1 << 0
- flagHdrCrc = 1 << 1
- flagExtra = 1 << 2
- flagName = 1 << 3
- flagComment = 1 << 4
-)
-
-var (
- // ErrChecksum is returned when reading GZIP data that has an invalid checksum.
- ErrChecksum = errors.New("gzip: invalid checksum")
- // ErrHeader is returned when reading GZIP data that has an invalid header.
- ErrHeader = errors.New("gzip: invalid header")
-)
-
-var le = binary.LittleEndian
-
-// noEOF converts io.EOF to io.ErrUnexpectedEOF.
-func noEOF(err error) error {
- if err == io.EOF {
- return io.ErrUnexpectedEOF
- }
- return err
-}
-
-// The gzip file stores a header giving metadata about the compressed file.
-// That header is exposed as the fields of the Writer and Reader structs.
-//
-// Strings must be UTF-8 encoded and may only contain Unicode code points
-// U+0001 through U+00FF, due to limitations of the GZIP file format.
-type Header struct {
- Comment string // comment
- Extra []byte // "extra data"
- ModTime time.Time // modification time
- Name string // file name
- OS byte // operating system type
-}
-
-// A Reader is an io.Reader that can be read to retrieve
-// uncompressed data from a gzip-format compressed file.
-//
-// In general, a gzip file can be a concatenation of gzip files,
-// each with its own header. Reads from the Reader
-// return the concatenation of the uncompressed data of each.
-// Only the first header is recorded in the Reader fields.
-//
-// Gzip files store a length and checksum of the uncompressed data.
-// The Reader will return a ErrChecksum when Read
-// reaches the end of the uncompressed data if it does not
-// have the expected length or checksum. Clients should treat data
-// returned by Read as tentative until they receive the io.EOF
-// marking the end of the data.
-type Reader struct {
- Header // valid after NewReader or Reader.Reset
- r flate.Reader
- decompressor io.ReadCloser
- digest uint32 // CRC-32, IEEE polynomial (section 8)
- size uint32 // Uncompressed size (section 2.3.1)
- buf [512]byte
- err error
- multistream bool
-}
-
-// NewReader creates a new Reader reading the given reader.
-// If r does not also implement io.ByteReader,
-// the decompressor may read more data than necessary from r.
-//
-// It is the caller's responsibility to call Close on the Reader when done.
-//
-// The Reader.Header fields will be valid in the Reader returned.
-func NewReader(r io.Reader) (*Reader, error) {
- z := new(Reader)
- if err := z.Reset(r); err != nil {
- return nil, err
- }
- return z, nil
-}
-
-// Reset discards the Reader z's state and makes it equivalent to the
-// result of its original state from NewReader, but reading from r instead.
-// This permits reusing a Reader rather than allocating a new one.
-func (z *Reader) Reset(r io.Reader) error {
- *z = Reader{
- decompressor: z.decompressor,
- multistream: true,
- }
- if rr, ok := r.(flate.Reader); ok {
- z.r = rr
- } else {
- z.r = bufio.NewReader(r)
- }
- z.Header, z.err = z.readHeader()
- return z.err
-}
-
-// Multistream controls whether the reader supports multistream files.
-//
-// If enabled (the default), the Reader expects the input to be a sequence
-// of individually gzipped data streams, each with its own header and
-// trailer, ending at EOF. The effect is that the concatenation of a sequence
-// of gzipped files is treated as equivalent to the gzip of the concatenation
-// of the sequence. This is standard behavior for gzip readers.
-//
-// Calling Multistream(false) disables this behavior; disabling the behavior
-// can be useful when reading file formats that distinguish individual gzip
-// data streams or mix gzip data streams with other data streams.
-// In this mode, when the Reader reaches the end of the data stream,
-// Read returns io.EOF. If the underlying reader implements io.ByteReader,
-// it will be left positioned just after the gzip stream.
-// To start the next stream, call z.Reset(r) followed by z.Multistream(false).
-// If there is no next stream, z.Reset(r) will return io.EOF.
-func (z *Reader) Multistream(ok bool) {
- z.multistream = ok
-}
-
-// readString reads a NUL-terminated string from z.r.
-// It treats the bytes read as being encoded as ISO 8859-1 (Latin-1) and
-// will output a string encoded using UTF-8.
-// This method always updates z.digest with the data read.
-func (z *Reader) readString() (string, error) {
- var err error
- needConv := false
- for i := 0; ; i++ {
- if i >= len(z.buf) {
- return "", ErrHeader
- }
- z.buf[i], err = z.r.ReadByte()
- if err != nil {
- return "", err
- }
- if z.buf[i] > 0x7f {
- needConv = true
- }
- if z.buf[i] == 0 {
- // Digest covers the NUL terminator.
- z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:i+1])
-
- // Strings are ISO 8859-1, Latin-1 (RFC 1952, section 2.3.1).
- if needConv {
- s := make([]rune, 0, i)
- for _, v := range z.buf[:i] {
- s = append(s, rune(v))
- }
- return string(s), nil
- }
- return string(z.buf[:i]), nil
- }
- }
-}
-
-// readHeader reads the GZIP header according to section 2.3.1.
-// This method does not set z.err.
-func (z *Reader) readHeader() (hdr Header, err error) {
- if _, err = io.ReadFull(z.r, z.buf[:10]); err != nil {
- // RFC 1952, section 2.2, says the following:
- // A gzip file consists of a series of "members" (compressed data sets).
- //
- // Other than this, the specification does not clarify whether a
- // "series" is defined as "one or more" or "zero or more". To err on the
- // side of caution, Go interprets this to mean "zero or more".
- // Thus, it is okay to return io.EOF here.
- return hdr, err
- }
- if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
- return hdr, ErrHeader
- }
- flg := z.buf[3]
- hdr.ModTime = time.Unix(int64(le.Uint32(z.buf[4:8])), 0)
- // z.buf[8] is XFL and is currently ignored.
- hdr.OS = z.buf[9]
- z.digest = crc32.ChecksumIEEE(z.buf[:10])
-
- if flg&flagExtra != 0 {
- if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil {
- return hdr, noEOF(err)
- }
- z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:2])
- data := make([]byte, le.Uint16(z.buf[:2]))
- if _, err = io.ReadFull(z.r, data); err != nil {
- return hdr, noEOF(err)
- }
- z.digest = crc32.Update(z.digest, crc32.IEEETable, data)
- hdr.Extra = data
- }
-
- var s string
- if flg&flagName != 0 {
- if s, err = z.readString(); err != nil {
- return hdr, err
- }
- hdr.Name = s
- }
-
- if flg&flagComment != 0 {
- if s, err = z.readString(); err != nil {
- return hdr, err
- }
- hdr.Comment = s
- }
-
- if flg&flagHdrCrc != 0 {
- if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil {
- return hdr, noEOF(err)
- }
- digest := le.Uint16(z.buf[:2])
- if digest != uint16(z.digest) {
- return hdr, ErrHeader
- }
- }
-
- z.digest = 0
- if z.decompressor == nil {
- z.decompressor = flate.NewReader(z.r)
- } else {
- z.decompressor.(flate.Resetter).Reset(z.r, nil)
- }
- return hdr, nil
-}
-
-// Read implements io.Reader, reading uncompressed bytes from its underlying Reader.
-func (z *Reader) Read(p []byte) (n int, err error) {
- if z.err != nil {
- return 0, z.err
- }
-
- n, z.err = z.decompressor.Read(p)
- z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n])
- z.size += uint32(n)
- if z.err != io.EOF {
- // In the normal case we return here.
- return n, z.err
- }
-
- // Finished file; check checksum and size.
- if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil {
- z.err = noEOF(err)
- return n, z.err
- }
- digest := le.Uint32(z.buf[:4])
- size := le.Uint32(z.buf[4:8])
- if digest != z.digest || size != z.size {
- z.err = ErrChecksum
- return n, z.err
- }
- z.digest, z.size = 0, 0
-
- // File is ok; check if there is another.
- if !z.multistream {
- return n, io.EOF
- }
- z.err = nil // Remove io.EOF
-
- if _, z.err = z.readHeader(); z.err != nil {
- return n, z.err
- }
-
- // Read from next file, if necessary.
- if n > 0 {
- return n, nil
- }
- return z.Read(p)
-}
-
-// Support the io.WriteTo interface for io.Copy and friends.
-func (z *Reader) WriteTo(w io.Writer) (int64, error) {
- total := int64(0)
- crcWriter := crc32.NewIEEE()
- for {
- if z.err != nil {
- if z.err == io.EOF {
- return total, nil
- }
- return total, z.err
- }
-
- // We write both to output and digest.
- mw := io.MultiWriter(w, crcWriter)
- n, err := z.decompressor.(io.WriterTo).WriteTo(mw)
- total += n
- z.size += uint32(n)
- if err != nil {
- z.err = err
- return total, z.err
- }
-
- // Finished file; check checksum + size.
- if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- z.err = err
- return total, err
- }
- z.digest = crcWriter.Sum32()
- digest := le.Uint32(z.buf[:4])
- size := le.Uint32(z.buf[4:8])
- if digest != z.digest || size != z.size {
- z.err = ErrChecksum
- return total, z.err
- }
- z.digest, z.size = 0, 0
-
- // File is ok; check if there is another.
- if !z.multistream {
- return total, nil
- }
- crcWriter.Reset()
- z.err = nil // Remove io.EOF
-
- if _, z.err = z.readHeader(); z.err != nil {
- if z.err == io.EOF {
- return total, nil
- }
- return total, z.err
- }
- }
-}
-
-// Close closes the Reader. It does not close the underlying io.Reader.
-// In order for the GZIP checksum to be verified, the reader must be
-// fully consumed until the io.EOF.
-func (z *Reader) Close() error { return z.decompressor.Close() }
diff --git a/vendor/github.com/klauspost/compress/gzip/gzip.go b/vendor/github.com/klauspost/compress/gzip/gzip.go
deleted file mode 100644
index 26203851bdf..00000000000
--- a/vendor/github.com/klauspost/compress/gzip/gzip.go
+++ /dev/null
@@ -1,269 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gzip
-
-import (
- "errors"
- "fmt"
- "hash/crc32"
- "io"
-
- "github.com/klauspost/compress/flate"
-)
-
-// These constants are copied from the flate package, so that code that imports
-// "compress/gzip" does not also have to import "compress/flate".
-const (
- NoCompression = flate.NoCompression
- BestSpeed = flate.BestSpeed
- BestCompression = flate.BestCompression
- DefaultCompression = flate.DefaultCompression
- ConstantCompression = flate.ConstantCompression
- HuffmanOnly = flate.HuffmanOnly
-
- // StatelessCompression will do compression but without maintaining any state
- // between Write calls.
- // There will be no memory kept between Write calls,
- // but compression and speed will be suboptimal.
- // Because of this, the size of actual Write calls will affect output size.
- StatelessCompression = -3
-)
-
-// A Writer is an io.WriteCloser.
-// Writes to a Writer are compressed and written to w.
-type Writer struct {
- Header // written at first call to Write, Flush, or Close
- w io.Writer
- level int
- err error
- compressor *flate.Writer
- digest uint32 // CRC-32, IEEE polynomial (section 8)
- size uint32 // Uncompressed size (section 2.3.1)
- wroteHeader bool
- closed bool
- buf [10]byte
-}
-
-// NewWriter returns a new Writer.
-// Writes to the returned writer are compressed and written to w.
-//
-// It is the caller's responsibility to call Close on the WriteCloser when done.
-// Writes may be buffered and not flushed until Close.
-//
-// Callers that wish to set the fields in Writer.Header must do so before
-// the first call to Write, Flush, or Close.
-func NewWriter(w io.Writer) *Writer {
- z, _ := NewWriterLevel(w, DefaultCompression)
- return z
-}
-
-// NewWriterLevel is like NewWriter but specifies the compression level instead
-// of assuming DefaultCompression.
-//
-// The compression level can be DefaultCompression, NoCompression, or any
-// integer value between BestSpeed and BestCompression inclusive. The error
-// returned will be nil if the level is valid.
-func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
- if level < StatelessCompression || level > BestCompression {
- return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
- }
- z := new(Writer)
- z.init(w, level)
- return z, nil
-}
-
-func (z *Writer) init(w io.Writer, level int) {
- compressor := z.compressor
- if level != StatelessCompression {
- if compressor != nil {
- compressor.Reset(w)
- }
- }
-
- *z = Writer{
- Header: Header{
- OS: 255, // unknown
- },
- w: w,
- level: level,
- compressor: compressor,
- }
-}
-
-// Reset discards the Writer z's state and makes it equivalent to the
-// result of its original state from NewWriter or NewWriterLevel, but
-// writing to w instead. This permits reusing a Writer rather than
-// allocating a new one.
-func (z *Writer) Reset(w io.Writer) {
- z.init(w, z.level)
-}
-
-// writeBytes writes a length-prefixed byte slice to z.w.
-func (z *Writer) writeBytes(b []byte) error {
- if len(b) > 0xffff {
- return errors.New("gzip.Write: Extra data is too large")
- }
- le.PutUint16(z.buf[:2], uint16(len(b)))
- _, err := z.w.Write(z.buf[:2])
- if err != nil {
- return err
- }
- _, err = z.w.Write(b)
- return err
-}
-
-// writeString writes a UTF-8 string s in GZIP's format to z.w.
-// GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
-func (z *Writer) writeString(s string) (err error) {
- // GZIP stores Latin-1 strings; error if non-Latin-1; convert if non-ASCII.
- needconv := false
- for _, v := range s {
- if v == 0 || v > 0xff {
- return errors.New("gzip.Write: non-Latin-1 header string")
- }
- if v > 0x7f {
- needconv = true
- }
- }
- if needconv {
- b := make([]byte, 0, len(s))
- for _, v := range s {
- b = append(b, byte(v))
- }
- _, err = z.w.Write(b)
- } else {
- _, err = io.WriteString(z.w, s)
- }
- if err != nil {
- return err
- }
- // GZIP strings are NUL-terminated.
- z.buf[0] = 0
- _, err = z.w.Write(z.buf[:1])
- return err
-}
-
-// Write writes a compressed form of p to the underlying io.Writer. The
-// compressed bytes are not necessarily flushed until the Writer is closed.
-func (z *Writer) Write(p []byte) (int, error) {
- if z.err != nil {
- return 0, z.err
- }
- var n int
- // Write the GZIP header lazily.
- if !z.wroteHeader {
- z.wroteHeader = true
- z.buf[0] = gzipID1
- z.buf[1] = gzipID2
- z.buf[2] = gzipDeflate
- z.buf[3] = 0
- if z.Extra != nil {
- z.buf[3] |= 0x04
- }
- if z.Name != "" {
- z.buf[3] |= 0x08
- }
- if z.Comment != "" {
- z.buf[3] |= 0x10
- }
- le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix()))
- if z.level == BestCompression {
- z.buf[8] = 2
- } else if z.level == BestSpeed {
- z.buf[8] = 4
- } else {
- z.buf[8] = 0
- }
- z.buf[9] = z.OS
- n, z.err = z.w.Write(z.buf[:10])
- if z.err != nil {
- return n, z.err
- }
- if z.Extra != nil {
- z.err = z.writeBytes(z.Extra)
- if z.err != nil {
- return n, z.err
- }
- }
- if z.Name != "" {
- z.err = z.writeString(z.Name)
- if z.err != nil {
- return n, z.err
- }
- }
- if z.Comment != "" {
- z.err = z.writeString(z.Comment)
- if z.err != nil {
- return n, z.err
- }
- }
-
- if z.compressor == nil && z.level != StatelessCompression {
- z.compressor, _ = flate.NewWriter(z.w, z.level)
- }
- }
- z.size += uint32(len(p))
- z.digest = crc32.Update(z.digest, crc32.IEEETable, p)
- if z.level == StatelessCompression {
- return len(p), flate.StatelessDeflate(z.w, p, false, nil)
- }
- n, z.err = z.compressor.Write(p)
- return n, z.err
-}
-
-// Flush flushes any pending compressed data to the underlying writer.
-//
-// It is useful mainly in compressed network protocols, to ensure that
-// a remote reader has enough data to reconstruct a packet. Flush does
-// not return until the data has been written. If the underlying
-// writer returns an error, Flush returns that error.
-//
-// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
-func (z *Writer) Flush() error {
- if z.err != nil {
- return z.err
- }
- if z.closed || z.level == StatelessCompression {
- return nil
- }
- if !z.wroteHeader {
- z.Write(nil)
- if z.err != nil {
- return z.err
- }
- }
- z.err = z.compressor.Flush()
- return z.err
-}
-
-// Close closes the Writer, flushing any unwritten data to the underlying
-// io.Writer, but does not close the underlying io.Writer.
-func (z *Writer) Close() error {
- if z.err != nil {
- return z.err
- }
- if z.closed {
- return nil
- }
- z.closed = true
- if !z.wroteHeader {
- z.Write(nil)
- if z.err != nil {
- return z.err
- }
- }
- if z.level == StatelessCompression {
- z.err = flate.StatelessDeflate(z.w, nil, true, nil)
- } else {
- z.err = z.compressor.Close()
- }
- if z.err != nil {
- return z.err
- }
- le.PutUint32(z.buf[:4], z.digest)
- le.PutUint32(z.buf[4:8], z.size)
- _, z.err = z.w.Write(z.buf[:8])
- return z.err
-}
diff --git a/vendor/github.com/klauspost/compress/zlib/reader.go b/vendor/github.com/klauspost/compress/zlib/reader.go
deleted file mode 100644
index d9091e83112..00000000000
--- a/vendor/github.com/klauspost/compress/zlib/reader.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package zlib implements reading and writing of zlib format compressed data,
-as specified in RFC 1950.
-
-The implementation provides filters that uncompress during reading
-and compress during writing. For example, to write compressed data
-to a buffer:
-
- var b bytes.Buffer
- w := zlib.NewWriter(&b)
- w.Write([]byte("hello, world\n"))
- w.Close()
-
-and to read that data back:
-
- r, err := zlib.NewReader(&b)
- io.Copy(os.Stdout, r)
- r.Close()
-*/
-package zlib
-
-import (
- "bufio"
- "errors"
- "hash"
- "hash/adler32"
- "io"
-
- "github.com/klauspost/compress/flate"
-)
-
-const zlibDeflate = 8
-
-var (
- // ErrChecksum is returned when reading ZLIB data that has an invalid checksum.
- ErrChecksum = errors.New("zlib: invalid checksum")
- // ErrDictionary is returned when reading ZLIB data that has an invalid dictionary.
- ErrDictionary = errors.New("zlib: invalid dictionary")
- // ErrHeader is returned when reading ZLIB data that has an invalid header.
- ErrHeader = errors.New("zlib: invalid header")
-)
-
-type reader struct {
- r flate.Reader
- decompressor io.ReadCloser
- digest hash.Hash32
- err error
- scratch [4]byte
-}
-
-// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to
-// to switch to a new underlying Reader. This permits reusing a ReadCloser
-// instead of allocating a new one.
-type Resetter interface {
- // Reset discards any buffered data and resets the Resetter as if it was
- // newly initialized with the given reader.
- Reset(r io.Reader, dict []byte) error
-}
-
-// NewReader creates a new ReadCloser.
-// Reads from the returned ReadCloser read and decompress data from r.
-// If r does not implement io.ByteReader, the decompressor may read more
-// data than necessary from r.
-// It is the caller's responsibility to call Close on the ReadCloser when done.
-//
-// The ReadCloser returned by NewReader also implements Resetter.
-func NewReader(r io.Reader) (io.ReadCloser, error) {
- return NewReaderDict(r, nil)
-}
-
-// NewReaderDict is like NewReader but uses a preset dictionary.
-// NewReaderDict ignores the dictionary if the compressed data does not refer to it.
-// If the compressed data refers to a different dictionary, NewReaderDict returns ErrDictionary.
-//
-// The ReadCloser returned by NewReaderDict also implements Resetter.
-func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
- z := new(reader)
- err := z.Reset(r, dict)
- if err != nil {
- return nil, err
- }
- return z, nil
-}
-
-func (z *reader) Read(p []byte) (int, error) {
- if z.err != nil {
- return 0, z.err
- }
-
- var n int
- n, z.err = z.decompressor.Read(p)
- z.digest.Write(p[0:n])
- if z.err != io.EOF {
- // In the normal case we return here.
- return n, z.err
- }
-
- // Finished file; check checksum.
- if _, err := io.ReadFull(z.r, z.scratch[0:4]); err != nil {
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- }
- z.err = err
- return n, z.err
- }
- // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
- checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
- if checksum != z.digest.Sum32() {
- z.err = ErrChecksum
- return n, z.err
- }
- return n, io.EOF
-}
-
-// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
-// In order for the ZLIB checksum to be verified, the reader must be
-// fully consumed until the io.EOF.
-func (z *reader) Close() error {
- if z.err != nil && z.err != io.EOF {
- return z.err
- }
- z.err = z.decompressor.Close()
- return z.err
-}
-
-func (z *reader) Reset(r io.Reader, dict []byte) error {
- *z = reader{decompressor: z.decompressor, digest: z.digest}
- if fr, ok := r.(flate.Reader); ok {
- z.r = fr
- } else {
- z.r = bufio.NewReader(r)
- }
-
- // Read the header (RFC 1950 section 2.2.).
- _, z.err = io.ReadFull(z.r, z.scratch[0:2])
- if z.err != nil {
- if z.err == io.EOF {
- z.err = io.ErrUnexpectedEOF
- }
- return z.err
- }
- h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
- if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
- z.err = ErrHeader
- return z.err
- }
- haveDict := z.scratch[1]&0x20 != 0
- if haveDict {
- _, z.err = io.ReadFull(z.r, z.scratch[0:4])
- if z.err != nil {
- if z.err == io.EOF {
- z.err = io.ErrUnexpectedEOF
- }
- return z.err
- }
- checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
- if checksum != adler32.Checksum(dict) {
- z.err = ErrDictionary
- return z.err
- }
- }
-
- if z.decompressor == nil {
- if haveDict {
- z.decompressor = flate.NewReaderDict(z.r, dict)
- } else {
- z.decompressor = flate.NewReader(z.r)
- }
- } else {
- z.decompressor.(flate.Resetter).Reset(z.r, dict)
- }
-
- if z.digest != nil {
- z.digest.Reset()
- } else {
- z.digest = adler32.New()
- }
- return nil
-}
diff --git a/vendor/github.com/klauspost/compress/zlib/writer.go b/vendor/github.com/klauspost/compress/zlib/writer.go
deleted file mode 100644
index 605816ba4f3..00000000000
--- a/vendor/github.com/klauspost/compress/zlib/writer.go
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package zlib
-
-import (
- "fmt"
- "hash"
- "hash/adler32"
- "io"
-
- "github.com/klauspost/compress/flate"
-)
-
-// These constants are copied from the flate package, so that code that imports
-// "compress/zlib" does not also have to import "compress/flate".
-const (
- NoCompression = flate.NoCompression
- BestSpeed = flate.BestSpeed
- BestCompression = flate.BestCompression
- DefaultCompression = flate.DefaultCompression
- ConstantCompression = flate.ConstantCompression
- HuffmanOnly = flate.HuffmanOnly
-)
-
-// A Writer takes data written to it and writes the compressed
-// form of that data to an underlying writer (see NewWriter).
-type Writer struct {
- w io.Writer
- level int
- dict []byte
- compressor *flate.Writer
- digest hash.Hash32
- err error
- scratch [4]byte
- wroteHeader bool
-}
-
-// NewWriter creates a new Writer.
-// Writes to the returned Writer are compressed and written to w.
-//
-// It is the caller's responsibility to call Close on the WriteCloser when done.
-// Writes may be buffered and not flushed until Close.
-func NewWriter(w io.Writer) *Writer {
- z, _ := NewWriterLevelDict(w, DefaultCompression, nil)
- return z
-}
-
-// NewWriterLevel is like NewWriter but specifies the compression level instead
-// of assuming DefaultCompression.
-//
-// The compression level can be DefaultCompression, NoCompression, HuffmanOnly
-// or any integer value between BestSpeed and BestCompression inclusive.
-// The error returned will be nil if the level is valid.
-func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
- return NewWriterLevelDict(w, level, nil)
-}
-
-// NewWriterLevelDict is like NewWriterLevel but specifies a dictionary to
-// compress with.
-//
-// The dictionary may be nil. If not, its contents should not be modified until
-// the Writer is closed.
-func NewWriterLevelDict(w io.Writer, level int, dict []byte) (*Writer, error) {
- if level < HuffmanOnly || level > BestCompression {
- return nil, fmt.Errorf("zlib: invalid compression level: %d", level)
- }
- return &Writer{
- w: w,
- level: level,
- dict: dict,
- }, nil
-}
-
-// Reset clears the state of the Writer z such that it is equivalent to its
-// initial state from NewWriterLevel or NewWriterLevelDict, but instead writing
-// to w.
-func (z *Writer) Reset(w io.Writer) {
- z.w = w
- // z.level and z.dict left unchanged.
- if z.compressor != nil {
- z.compressor.Reset(w)
- }
- if z.digest != nil {
- z.digest.Reset()
- }
- z.err = nil
- z.scratch = [4]byte{}
- z.wroteHeader = false
-}
-
-// writeHeader writes the ZLIB header.
-func (z *Writer) writeHeader() (err error) {
- z.wroteHeader = true
- // ZLIB has a two-byte header (as documented in RFC 1950).
- // The first four bits is the CINFO (compression info), which is 7 for the default deflate window size.
- // The next four bits is the CM (compression method), which is 8 for deflate.
- z.scratch[0] = 0x78
- // The next two bits is the FLEVEL (compression level). The four values are:
- // 0=fastest, 1=fast, 2=default, 3=best.
- // The next bit, FDICT, is set if a dictionary is given.
- // The final five FCHECK bits form a mod-31 checksum.
- switch z.level {
- case -2, 0, 1:
- z.scratch[1] = 0 << 6
- case 2, 3, 4, 5:
- z.scratch[1] = 1 << 6
- case 6, -1:
- z.scratch[1] = 2 << 6
- case 7, 8, 9:
- z.scratch[1] = 3 << 6
- default:
- panic("unreachable")
- }
- if z.dict != nil {
- z.scratch[1] |= 1 << 5
- }
- z.scratch[1] += uint8(31 - (uint16(z.scratch[0])<<8+uint16(z.scratch[1]))%31)
- if _, err = z.w.Write(z.scratch[0:2]); err != nil {
- return err
- }
- if z.dict != nil {
- // The next four bytes are the Adler-32 checksum of the dictionary.
- checksum := adler32.Checksum(z.dict)
- z.scratch[0] = uint8(checksum >> 24)
- z.scratch[1] = uint8(checksum >> 16)
- z.scratch[2] = uint8(checksum >> 8)
- z.scratch[3] = uint8(checksum >> 0)
- if _, err = z.w.Write(z.scratch[0:4]); err != nil {
- return err
- }
- }
- if z.compressor == nil {
- // Initialize deflater unless the Writer is being reused
- // after a Reset call.
- z.compressor, err = flate.NewWriterDict(z.w, z.level, z.dict)
- if err != nil {
- return err
- }
- z.digest = adler32.New()
- }
- return nil
-}
-
-// Write writes a compressed form of p to the underlying io.Writer. The
-// compressed bytes are not necessarily flushed until the Writer is closed or
-// explicitly flushed.
-func (z *Writer) Write(p []byte) (n int, err error) {
- if !z.wroteHeader {
- z.err = z.writeHeader()
- }
- if z.err != nil {
- return 0, z.err
- }
- if len(p) == 0 {
- return 0, nil
- }
- n, err = z.compressor.Write(p)
- if err != nil {
- z.err = err
- return
- }
- z.digest.Write(p)
- return
-}
-
-// Flush flushes the Writer to its underlying io.Writer.
-func (z *Writer) Flush() error {
- if !z.wroteHeader {
- z.err = z.writeHeader()
- }
- if z.err != nil {
- return z.err
- }
- z.err = z.compressor.Flush()
- return z.err
-}
-
-// Close closes the Writer, flushing any unwritten data to the underlying
-// io.Writer, but does not close the underlying io.Writer.
-func (z *Writer) Close() error {
- if !z.wroteHeader {
- z.err = z.writeHeader()
- }
- if z.err != nil {
- return z.err
- }
- z.err = z.compressor.Close()
- if z.err != nil {
- return z.err
- }
- checksum := z.digest.Sum32()
- // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
- z.scratch[0] = uint8(checksum >> 24)
- z.scratch[1] = uint8(checksum >> 16)
- z.scratch[2] = uint8(checksum >> 8)
- z.scratch[3] = uint8(checksum >> 0)
- _, z.err = z.w.Write(z.scratch[0:4])
- return z.err
-}
diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE b/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
deleted file mode 100644
index 14127cd831e..00000000000
--- a/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
+++ /dev/null
@@ -1,9 +0,0 @@
-(The MIT License)
-
-Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de)
-
-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.
diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
deleted file mode 100644
index 195333e51d4..00000000000
--- a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Windows Terminal Sequences
-
-This library allow for enabling Windows terminal color support for Go.
-
-See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details.
-
-## Usage
-
-```go
-import (
- "syscall"
-
- sequences "github.com/konsorten/go-windows-terminal-sequences"
-)
-
-func main() {
- sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true)
-}
-
-```
-
-## Authors
-
-The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
-
-We thank all the authors who provided code to this library:
-
-* Felix Kollmann
-* Nicolas Perraut
-
-## License
-
-(The MIT License)
-
-Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de)
-
-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.
diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod
deleted file mode 100644
index 716c6131256..00000000000
--- a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/konsorten/go-windows-terminal-sequences
diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
deleted file mode 100644
index ef18d8f9787..00000000000
--- a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// +build windows
-
-package sequences
-
-import (
- "syscall"
- "unsafe"
-)
-
-var (
- kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll")
- setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode")
-)
-
-func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
- const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4
-
- var mode uint32
- err := syscall.GetConsoleMode(syscall.Stdout, &mode)
- if err != nil {
- return err
- }
-
- if enable {
- mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
- } else {
- mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING
- }
-
- ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode))
- if ret == 0 {
- return err
- }
-
- return nil
-}
diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
deleted file mode 100644
index df61a6f2f6f..00000000000
--- a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build linux darwin
-
-package sequences
-
-import (
- "fmt"
-)
-
-func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error {
- return fmt.Errorf("windows only package")
-}
diff --git a/vendor/github.com/lonelycode/go-uuid/CONTRIBUTORS b/vendor/github.com/lonelycode/go-uuid/CONTRIBUTORS
deleted file mode 100644
index b382a04eda9..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/CONTRIBUTORS
+++ /dev/null
@@ -1 +0,0 @@
-Paul Borman
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/LICENSE b/vendor/github.com/lonelycode/go-uuid/uuid/LICENSE
deleted file mode 100644
index 5dc68268d90..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2009,2014 Google Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/dce.go b/vendor/github.com/lonelycode/go-uuid/uuid/dce.go
deleted file mode 100644
index 50a0f2d0992..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/dce.go
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "encoding/binary"
- "fmt"
- "os"
-)
-
-// A Domain represents a Version 2 domain
-type Domain byte
-
-// Domain constants for DCE Security (Version 2) UUIDs.
-const (
- Person = Domain(0)
- Group = Domain(1)
- Org = Domain(2)
-)
-
-// NewDCESecurity returns a DCE Security (Version 2) UUID.
-//
-// The domain should be one of Person, Group or Org.
-// On a POSIX system the id should be the users UID for the Person
-// domain and the users GID for the Group. The meaning of id for
-// the domain Org or on non-POSIX systems is site defined.
-//
-// For a given domain/id pair the same token may be returned for up to
-// 7 minutes and 10 seconds.
-func NewDCESecurity(domain Domain, id uint32) UUID {
- uuid := NewUUID()
- if uuid != nil {
- uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
- uuid[9] = byte(domain)
- binary.BigEndian.PutUint32(uuid[0:], id)
- }
- return uuid
-}
-
-// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
-// domain with the id returned by os.Getuid.
-//
-// NewDCEPerson(Person, uint32(os.Getuid()))
-func NewDCEPerson() UUID {
- return NewDCESecurity(Person, uint32(os.Getuid()))
-}
-
-// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
-// domain with the id returned by os.Getgid.
-//
-// NewDCEGroup(Group, uint32(os.Getgid()))
-func NewDCEGroup() UUID {
- return NewDCESecurity(Group, uint32(os.Getgid()))
-}
-
-// Domain returns the domain for a Version 2 UUID or false.
-func (uuid UUID) Domain() (Domain, bool) {
- if v, _ := uuid.Version(); v != 2 {
- return 0, false
- }
- return Domain(uuid[9]), true
-}
-
-// Id returns the id for a Version 2 UUID or false.
-func (uuid UUID) Id() (uint32, bool) {
- if v, _ := uuid.Version(); v != 2 {
- return 0, false
- }
- return binary.BigEndian.Uint32(uuid[0:4]), true
-}
-
-func (d Domain) String() string {
- switch d {
- case Person:
- return "Person"
- case Group:
- return "Group"
- case Org:
- return "Org"
- }
- return fmt.Sprintf("Domain%d", int(d))
-}
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/doc.go b/vendor/github.com/lonelycode/go-uuid/uuid/doc.go
deleted file mode 100644
index d8bd013e689..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/doc.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// The uuid package generates and inspects UUIDs.
-//
-// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services.
-package uuid
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/hash.go b/vendor/github.com/lonelycode/go-uuid/uuid/hash.go
deleted file mode 100644
index cdd4192fd9b..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/hash.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "crypto/md5"
- "crypto/sha1"
- "hash"
-)
-
-// Well known Name Space IDs and UUIDs
-var (
- NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
- NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
- NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
- NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
- NIL = Parse("00000000-0000-0000-0000-000000000000")
-)
-
-// NewHash returns a new UUID dervied from the hash of space concatenated with
-// data generated by h. The hash should be at least 16 byte in length. The
-// first 16 bytes of the hash are used to form the UUID. The version of the
-// UUID will be the lower 4 bits of version. NewHash is used to implement
-// NewMD5 and NewSHA1.
-func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
- h.Reset()
- h.Write(space)
- h.Write([]byte(data))
- s := h.Sum(nil)
- uuid := make([]byte, 16)
- copy(uuid, s)
- uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
- uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
- return uuid
-}
-
-// NewMD5 returns a new MD5 (Version 3) UUID based on the
-// supplied name space and data.
-//
-// NewHash(md5.New(), space, data, 3)
-func NewMD5(space UUID, data []byte) UUID {
- return NewHash(md5.New(), space, data, 3)
-}
-
-// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
-// supplied name space and data.
-//
-// NewHash(sha1.New(), space, data, 5)
-func NewSHA1(space UUID, data []byte) UUID {
- return NewHash(sha1.New(), space, data, 5)
-}
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/json.go b/vendor/github.com/lonelycode/go-uuid/uuid/json.go
deleted file mode 100644
index 760580a504f..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/json.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2014 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import "errors"
-
-func (u UUID) MarshalJSON() ([]byte, error) {
- if len(u) == 0 {
- return []byte(`""`), nil
- }
- return []byte(`"` + u.String() + `"`), nil
-}
-
-func (u *UUID) UnmarshalJSON(data []byte) error {
- if len(data) == 0 || string(data) == `""` {
- return nil
- }
- if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
- return errors.New("invalid UUID format")
- }
- data = data[1 : len(data)-1]
- uu := Parse(string(data))
- if uu == nil {
- return errors.New("invalid UUID format")
- }
- *u = uu
- return nil
-}
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/node.go b/vendor/github.com/lonelycode/go-uuid/uuid/node.go
deleted file mode 100644
index dd0a8ac189a..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/node.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import "net"
-
-var (
- interfaces []net.Interface // cached list of interfaces
- ifname string // name of interface being used
- nodeID []byte // hardware for version 1 UUIDs
-)
-
-// NodeInterface returns the name of the interface from which the NodeID was
-// derived. The interface "user" is returned if the NodeID was set by
-// SetNodeID.
-func NodeInterface() string {
- return ifname
-}
-
-// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
-// If name is "" then the first usable interface found will be used or a random
-// Node ID will be generated. If a named interface cannot be found then false
-// is returned.
-//
-// SetNodeInterface never fails when name is "".
-func SetNodeInterface(name string) bool {
- if interfaces == nil {
- var err error
- interfaces, err = net.Interfaces()
- if err != nil && name != "" {
- return false
- }
- }
-
- for _, ifs := range interfaces {
- if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
- if setNodeID(ifs.HardwareAddr) {
- ifname = ifs.Name
- return true
- }
- }
- }
-
- // We found no interfaces with a valid hardware address. If name
- // does not specify a specific interface generate a random Node ID
- // (section 4.1.6)
- if name == "" {
- if nodeID == nil {
- nodeID = make([]byte, 6)
- }
- randomBits(nodeID)
- return true
- }
- return false
-}
-
-// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
-// if not already set.
-func NodeID() []byte {
- if nodeID == nil {
- SetNodeInterface("")
- }
- nid := make([]byte, 6)
- copy(nid, nodeID)
- return nid
-}
-
-// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
-// of id are used. If id is less than 6 bytes then false is returned and the
-// Node ID is not set.
-func SetNodeID(id []byte) bool {
- if setNodeID(id) {
- ifname = "user"
- return true
- }
- return false
-}
-
-func setNodeID(id []byte) bool {
- if len(id) < 6 {
- return false
- }
- if nodeID == nil {
- nodeID = make([]byte, 6)
- }
- copy(nodeID, id)
- return true
-}
-
-// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
-// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
-func (uuid UUID) NodeID() []byte {
- if len(uuid) != 16 {
- return nil
- }
- node := make([]byte, 6)
- copy(node, uuid[10:])
- return node
-}
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/time.go b/vendor/github.com/lonelycode/go-uuid/uuid/time.go
deleted file mode 100644
index 7ebc9bef109..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/time.go
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2014 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "encoding/binary"
- "sync"
- "time"
-)
-
-// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
-// 1582.
-type Time int64
-
-const (
- lillian = 2299160 // Julian day of 15 Oct 1582
- unix = 2440587 // Julian day of 1 Jan 1970
- epoch = unix - lillian // Days between epochs
- g1582 = epoch * 86400 // seconds between epochs
- g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
-)
-
-var (
- mu sync.Mutex
- lasttime uint64 // last time we returned
- clock_seq uint16 // clock sequence for this run
-
- timeNow = time.Now // for testing
-)
-
-// UnixTime converts t the number of seconds and nanoseconds using the Unix
-// epoch of 1 Jan 1970.
-func (t Time) UnixTime() (sec, nsec int64) {
- sec = int64(t - g1582ns100)
- nsec = (sec % 10000000) * 100
- sec /= 10000000
- return sec, nsec
-}
-
-// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
-// clock sequence as well as adjusting the clock sequence as needed. An error
-// is returned if the current time cannot be determined.
-func GetTime() (Time, uint16, error) {
- defer mu.Unlock()
- mu.Lock()
- return getTime()
-}
-
-func getTime() (Time, uint16, error) {
- t := timeNow()
-
- // If we don't have a clock sequence already, set one.
- if clock_seq == 0 {
- setClockSequence(-1)
- }
- now := uint64(t.UnixNano()/100) + g1582ns100
-
- // If time has gone backwards with this clock sequence then we
- // increment the clock sequence
- if now <= lasttime {
- clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000
- }
- lasttime = now
- return Time(now), clock_seq, nil
-}
-
-// ClockSequence returns the current clock sequence, generating one if not
-// already set. The clock sequence is only used for Version 1 UUIDs.
-//
-// The uuid package does not use global static storage for the clock sequence or
-// the last time a UUID was generated. Unless SetClockSequence a new random
-// clock sequence is generated the first time a clock sequence is requested by
-// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated
-// for
-func ClockSequence() int {
- defer mu.Unlock()
- mu.Lock()
- return clockSequence()
-}
-
-func clockSequence() int {
- if clock_seq == 0 {
- setClockSequence(-1)
- }
- return int(clock_seq & 0x3fff)
-}
-
-// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
-// -1 causes a new sequence to be generated.
-func SetClockSequence(seq int) {
- defer mu.Unlock()
- mu.Lock()
- setClockSequence(seq)
-}
-
-func setClockSequence(seq int) {
- if seq == -1 {
- var b [2]byte
- randomBits(b[:]) // clock sequence
- seq = int(b[0])<<8 | int(b[1])
- }
- old_seq := clock_seq
- clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant
- if old_seq != clock_seq {
- lasttime = 0
- }
-}
-
-// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
-// uuid. It returns false if uuid is not valid. The time is only well defined
-// for version 1 and 2 UUIDs.
-func (uuid UUID) Time() (Time, bool) {
- if len(uuid) != 16 {
- return 0, false
- }
- time := int64(binary.BigEndian.Uint32(uuid[0:4]))
- time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
- time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
- return Time(time), true
-}
-
-// ClockSequence returns the clock sequence encoded in uuid. It returns false
-// if uuid is not valid. The clock sequence is only well defined for version 1
-// and 2 UUIDs.
-func (uuid UUID) ClockSequence() (int, bool) {
- if len(uuid) != 16 {
- return 0, false
- }
- return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true
-}
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/util.go b/vendor/github.com/lonelycode/go-uuid/uuid/util.go
deleted file mode 100644
index de40b102c4b..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/util.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "io"
-)
-
-// randomBits completely fills slice b with random data.
-func randomBits(b []byte) {
- if _, err := io.ReadFull(rander, b); err != nil {
- panic(err.Error()) // rand should never fail
- }
-}
-
-// xvalues returns the value of a byte as a hexadecimal digit or 255.
-var xvalues = []byte{
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
- 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-}
-
-// xtob converts the the first two hex bytes of x into a byte.
-func xtob(x string) (byte, bool) {
- b1 := xvalues[x[0]]
- b2 := xvalues[x[1]]
- return (b1 << 4) | b2, b1 != 255 && b2 != 255
-}
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/uuid.go b/vendor/github.com/lonelycode/go-uuid/uuid/uuid.go
deleted file mode 100644
index 2920fae6326..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/uuid.go
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "bytes"
- "crypto/rand"
- "fmt"
- "io"
- "strings"
-)
-
-// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
-// 4122.
-type UUID []byte
-
-// A Version represents a UUIDs version.
-type Version byte
-
-// A Variant represents a UUIDs variant.
-type Variant byte
-
-// Constants returned by Variant.
-const (
- Invalid = Variant(iota) // Invalid UUID
- RFC4122 // The variant specified in RFC4122
- Reserved // Reserved, NCS backward compatibility.
- Microsoft // Reserved, Microsoft Corporation backward compatibility.
- Future // Reserved for future definition.
-)
-
-var rander = rand.Reader // random function
-
-// New returns a new random (version 4) UUID as a string. It is a convenience
-// function for NewRandom().String().
-func New() string {
- return NewRandom().String()
-}
-
-// Parse decodes s into a UUID or returns nil. Both the UUID form of
-// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
-// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
-func Parse(s string) UUID {
- if len(s) == 36+9 {
- if strings.ToLower(s[:9]) != "urn:uuid:" {
- return nil
- }
- s = s[9:]
- } else if len(s) != 36 {
- return nil
- }
- if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
- return nil
- }
- uuid := make([]byte, 16)
- for i, x := range []int{
- 0, 2, 4, 6,
- 9, 11,
- 14, 16,
- 19, 21,
- 24, 26, 28, 30, 32, 34} {
- if v, ok := xtob(s[x:]); !ok {
- return nil
- } else {
- uuid[i] = v
- }
- }
- return uuid
-}
-
-// Equal returns true if uuid1 and uuid2 are equal.
-func Equal(uuid1, uuid2 UUID) bool {
- return bytes.Equal(uuid1, uuid2)
-}
-
-// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-// , or "" if uuid is invalid.
-func (uuid UUID) String() string {
- if uuid == nil || len(uuid) != 16 {
- return ""
- }
- b := []byte(uuid)
- return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
- b[:4], b[4:6], b[6:8], b[8:10], b[10:])
-}
-
-// URN returns the RFC 2141 URN form of uuid,
-// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
-func (uuid UUID) URN() string {
- if uuid == nil || len(uuid) != 16 {
- return ""
- }
- b := []byte(uuid)
- return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x",
- b[:4], b[4:6], b[6:8], b[8:10], b[10:])
-}
-
-// Variant returns the variant encoded in uuid. It returns Invalid if
-// uuid is invalid.
-func (uuid UUID) Variant() Variant {
- if len(uuid) != 16 {
- return Invalid
- }
- switch {
- case (uuid[8] & 0xc0) == 0x80:
- return RFC4122
- case (uuid[8] & 0xe0) == 0xc0:
- return Microsoft
- case (uuid[8] & 0xe0) == 0xe0:
- return Future
- default:
- return Reserved
- }
- panic("unreachable")
-}
-
-// Version returns the verison of uuid. It returns false if uuid is not
-// valid.
-func (uuid UUID) Version() (Version, bool) {
- if len(uuid) != 16 {
- return 0, false
- }
- return Version(uuid[6] >> 4), true
-}
-
-func (v Version) String() string {
- if v > 15 {
- return fmt.Sprintf("BAD_VERSION_%d", v)
- }
- return fmt.Sprintf("VERSION_%d", v)
-}
-
-func (v Variant) String() string {
- switch v {
- case RFC4122:
- return "RFC4122"
- case Reserved:
- return "Reserved"
- case Microsoft:
- return "Microsoft"
- case Future:
- return "Future"
- case Invalid:
- return "Invalid"
- }
- return fmt.Sprintf("BadVariant%d", int(v))
-}
-
-// SetRand sets the random number generator to r, which implents io.Reader.
-// If r.Read returns an error when the package requests random data then
-// a panic will be issued.
-//
-// Calling SetRand with nil sets the random number generator to the default
-// generator.
-func SetRand(r io.Reader) {
- if r == nil {
- rander = rand.Reader
- return
- }
- rander = r
-}
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/version1.go b/vendor/github.com/lonelycode/go-uuid/uuid/version1.go
deleted file mode 100644
index 0127eacfab8..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/version1.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-import (
- "encoding/binary"
-)
-
-// NewUUID returns a Version 1 UUID based on the current NodeID and clock
-// sequence, and the current time. If the NodeID has not been set by SetNodeID
-// or SetNodeInterface then it will be set automatically. If the NodeID cannot
-// be set NewUUID returns nil. If clock sequence has not been set by
-// SetClockSequence then it will be set automatically. If GetTime fails to
-// return the current NewUUID returns nil.
-func NewUUID() UUID {
- if nodeID == nil {
- SetNodeInterface("")
- }
-
- now, seq, err := GetTime()
- if err != nil {
- return nil
- }
-
- uuid := make([]byte, 16)
-
- time_low := uint32(now & 0xffffffff)
- time_mid := uint16((now >> 32) & 0xffff)
- time_hi := uint16((now >> 48) & 0x0fff)
- time_hi |= 0x1000 // Version 1
-
- binary.BigEndian.PutUint32(uuid[0:], time_low)
- binary.BigEndian.PutUint16(uuid[4:], time_mid)
- binary.BigEndian.PutUint16(uuid[6:], time_hi)
- binary.BigEndian.PutUint16(uuid[8:], seq)
- copy(uuid[10:], nodeID)
-
- return uuid
-}
diff --git a/vendor/github.com/lonelycode/go-uuid/uuid/version4.go b/vendor/github.com/lonelycode/go-uuid/uuid/version4.go
deleted file mode 100644
index b3d4a368dd0..00000000000
--- a/vendor/github.com/lonelycode/go-uuid/uuid/version4.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package uuid
-
-// Random returns a Random (Version 4) UUID or panics.
-//
-// The strength of the UUIDs is based on the strength of the crypto/rand
-// package.
-//
-// A note about uniqueness derived from from the UUID Wikipedia entry:
-//
-// Randomly generated UUIDs have 122 random bits. One's annual risk of being
-// hit by a meteorite is estimated to be one chance in 17 billion, that
-// means the probability is about 0.00000000006 (6 × 10−11),
-// equivalent to the odds of creating a few tens of trillions of UUIDs in a
-// year and having one duplicate.
-func NewRandom() UUID {
- uuid := make([]byte, 16)
- randomBits([]byte(uuid))
- uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
- uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
- return uuid
-}
diff --git a/vendor/github.com/lonelycode/osin/.gitignore b/vendor/github.com/lonelycode/osin/.gitignore
deleted file mode 100644
index a795e154a1e..00000000000
--- a/vendor/github.com/lonelycode/osin/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.exe
-/src
diff --git a/vendor/github.com/lonelycode/osin/.travis.yml b/vendor/github.com/lonelycode/osin/.travis.yml
deleted file mode 100644
index 57bd4a76e87..00000000000
--- a/vendor/github.com/lonelycode/osin/.travis.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-language: go
-
-go:
- - 1.1
- - 1.2
- - 1.3
- - tip
diff --git a/vendor/github.com/lonelycode/osin/CHANGELOG b/vendor/github.com/lonelycode/osin/CHANGELOG
deleted file mode 100644
index 05eeb174509..00000000000
--- a/vendor/github.com/lonelycode/osin/CHANGELOG
+++ /dev/null
@@ -1,19 +0,0 @@
-2014-06-25
-==========
-* BREAKING CHANGES:
- - Storage interface has 2 new methods, Clone and Close, to better support storages
- that need to clone / close in each connection (mgo)
- - Client was changed to be an interface instead of an struct. Because of that,
- the Storage interface also had to change, as interface is already a pointer.
-
- - HOW TO FIX YOUR CODE:
- + In your Storage, add a Clone function returning itself, and a do nothing Close.
- + In your Storage, replace all *osin.Client with osin.Client (remove the pointer reference)
- + If you used the osin.Client struct directly in your code, change it to osin.DefaultClient,
- which is a struct with the same fields that implements the interface.
- + Change all accesses using osin.Client to use the methods instead of the fields directly.
- + You MUST defer Response.Close in all your http handlers, otherwise some
- Storages may not clean correctly.
-
- resp := server.NewResponse()
- defer resp.Close()
diff --git a/vendor/github.com/lonelycode/osin/LICENSE b/vendor/github.com/lonelycode/osin/LICENSE
deleted file mode 100644
index 864c570e72e..00000000000
--- a/vendor/github.com/lonelycode/osin/LICENSE
+++ /dev/null
@@ -1,9 +0,0 @@
-Copyright (c) 2013, Rangel Reale
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-Neither the name of the SIB IT nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/vendor/github.com/lonelycode/osin/README.md b/vendor/github.com/lonelycode/osin/README.md
deleted file mode 100644
index d680f98eae6..00000000000
--- a/vendor/github.com/lonelycode/osin/README.md
+++ /dev/null
@@ -1,93 +0,0 @@
-OSIN
-====
-
-Golang OAuth2 server library
-----------------------------
-
-OSIN is an OAuth2 server library for the Go language, as specified at
-http://tools.ietf.org/html/rfc6749 and http://tools.ietf.org/html/draft-ietf-oauth-v2-10.
-
-Using it, you can build your own OAuth2 authentication service.
-
-The library implements the majority of the specification, like authorization and token endpoints, and authorization code, implicit, resource owner and client credentials grant types.
-
-### Dependencies
-
-* go-uuid (http://code.google.com/p/go-uuid)
-
-### Example Server
-
-````go
-import "github.com/RangelReale/osin"
-
-// TestStorage implements the "osin.Storage" interface
-server := osin.NewServer(osin.NewServerConfig(), &TestStorage{})
-
-// Authorization code endpoint
-http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
- resp := server.NewResponse()
- defer resp.Close()
-
- if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {
-
- // HANDLE LOGIN PAGE HERE
-
- ar.Authorized = true
- server.FinishAuthorizeRequest(resp, r, ar)
- }
- osin.OutputJSON(resp, w, r)
-})
-
-// Access token endpoint
-http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
- resp := server.NewResponse()
- defer resp.Close()
-
- if ar := server.HandleAccessRequest(resp, r); ar != nil {
- ar.Authorized = true
- server.FinishAccessRequest(resp, r, ar)
- }
- osin.OutputJSON(resp, w, r)
-})
-
-http.ListenAndServe(":14000", nil)
-````
-
-### Example Access
-
-Open in your web browser:
-
-````
-http://localhost:14000/authorize?response_type=code&client_id=1234&redirect_url=http%3A%2F%2Flocalhost%3A14000%2Fappauth%2Fcode
-````
-
-### License
-
-The code is licensed using "New BSD" license.
-
-### Author
-
-Rangel Reale
-rangelreale@gmail.com
-
-### Changes
-
-2014-06-25
-==========
-* BREAKING CHANGES:
- - Storage interface has 2 new methods, Clone and Close, to better support storages
- that need to clone / close in each connection (mgo)
- - Client was changed to be an interface instead of an struct. Because of that,
- the Storage interface also had to change, as interface is already a pointer.
-
- - HOW TO FIX YOUR CODE:
- + In your Storage, add a Clone function returning itself, and a do nothing Close.
- + In your Storage, replace all *osin.Client with osin.Client (remove the pointer reference)
- + If you used the osin.Client struct directly in your code, change it to osin.DefaultClient,
- which is a struct with the same fields that implements the interface.
- + Change all accesses using osin.Client to use the methods instead of the fields directly.
- + You MUST defer Response.Close in all your http handlers, otherwise some
- Storages may not clean correctly.
-
- resp := server.NewResponse()
- defer resp.Close()
diff --git a/vendor/github.com/lonelycode/osin/access.go b/vendor/github.com/lonelycode/osin/access.go
deleted file mode 100644
index 596cb50ef39..00000000000
--- a/vendor/github.com/lonelycode/osin/access.go
+++ /dev/null
@@ -1,501 +0,0 @@
-package osin
-
-import (
- "encoding/json"
- "errors"
- "net/http"
- "time"
-)
-
-// AccessRequestType is the type for OAuth param `grant_type`
-type AccessRequestType string
-
-const (
- AUTHORIZATION_CODE AccessRequestType = "authorization_code"
- REFRESH_TOKEN = "refresh_token"
- PASSWORD = "password"
- CLIENT_CREDENTIALS = "client_credentials"
- ASSERTION = "assertion"
- IMPLICIT = "__implicit"
-)
-
-// AccessRequest is a request for access tokens
-type AccessRequest struct {
- Type AccessRequestType
- Code string
- Client Client `json:",omitempty"`
- AuthorizeData *AuthorizeData `json:",omitempty"`
- AccessData *AccessData `json:",omitempty"`
-
- // Force finish to use this access data, to allow access data reuse
- ForceAccessData *AccessData
- RedirectUri string
- Scope string
- Username string
- Password string
- AssertionType string
- Assertion string
-
- // Set if request is authorized
- Authorized bool
-
- // Token expiration in seconds. Change if different from default
- Expiration int32
-
- // Set if a refresh token should be generated
- GenerateRefresh bool
-
- // Data to be passed to storage. Not used by the library.
- UserData interface{}
-
- // HttpRequest *http.Request for special use
- HttpRequest *http.Request
-}
-
-// AccessData represents an access grant (tokens, expiration, client, etc)
-type AccessData struct {
- // Client information
- Client Client `json:",omitempty"`
-
- // Authorize data, for authorization code
- AuthorizeData *AuthorizeData `json:",omitempty"`
-
- // Previous access data, for refresh token
- AccessData *AccessData `json:",omitempty"`
-
- // Access token
- AccessToken string
-
- // Refresh Token. Can be blank
- RefreshToken string
-
- // Token expiration in seconds
- ExpiresIn int32
-
- // Requested scope
- Scope string
-
- // Redirect Uri from request
- RedirectUri string
-
- // Date created
- CreatedAt time.Time
-
- // Data to be passed to storage. Not used by the library.
- UserData interface{} `json:",omitempty"`
-}
-
-type accessData AccessData
-
-func (c *AccessData) UnmarshalJSON(b []byte) error {
- newAccessData := accessData{}
- newAccessData.Client = new(DefaultClient)
- var err error
-
- if err = json.Unmarshal(b, &newAccessData); err == nil {
- *c = AccessData(newAccessData)
- return nil
- }
- return nil
-}
-
-// IsExpired returns true if access expired
-func (d *AccessData) IsExpired() bool {
- return d.CreatedAt.Add(time.Duration(d.ExpiresIn) * time.Second).Before(time.Now())
-}
-
-// ExpireAt returns the expiration date
-func (d *AccessData) ExpireAt() time.Time {
- return d.CreatedAt.Add(time.Duration(d.ExpiresIn) * time.Second)
-}
-
-// AccessTokenGen generates access tokens
-type AccessTokenGen interface {
- GenerateAccessToken(data *AccessData, generaterefresh bool) (accesstoken string, refreshtoken string, err error)
-}
-
-// HandleAccessRequest is the http.HandlerFunc for handling access token requests
-func (s *Server) HandleAccessRequest(w *Response, r *http.Request) *AccessRequest {
- // Only allow GET or POST
- if r.Method == "GET" {
- if !s.Config.AllowGetAccessRequest {
- w.SetError(E_INVALID_REQUEST, "")
- w.InternalError = errors.New("Request must be POST")
- return nil
- }
- } else if r.Method != "POST" {
- w.SetError(E_INVALID_REQUEST, "")
- w.InternalError = errors.New("Request must be POST")
- return nil
- }
-
- err := r.ParseForm()
- if err != nil {
- w.SetError(E_INVALID_REQUEST, "")
- w.InternalError = err
- return nil
- }
-
- grantType := AccessRequestType(r.Form.Get("grant_type"))
- if s.Config.AllowedAccessTypes.Exists(grantType) {
- switch grantType {
- case AUTHORIZATION_CODE:
- return s.handleAuthorizationCodeRequest(w, r)
- case REFRESH_TOKEN:
- return s.handleRefreshTokenRequest(w, r)
- case PASSWORD:
- return s.handlePasswordRequest(w, r)
- case CLIENT_CREDENTIALS:
- return s.handleClientCredentialsRequest(w, r)
- case ASSERTION:
- return s.handleAssertionRequest(w, r)
- }
- }
-
- w.SetError(E_UNSUPPORTED_GRANT_TYPE, "")
- return nil
-}
-
-func (s *Server) handleAuthorizationCodeRequest(w *Response, r *http.Request) *AccessRequest {
- // get client authentication
- auth := getClientAuth(w, r, s.Config.AllowClientSecretInParams)
- if auth == nil {
- return nil
- }
-
- // generate access token
- ret := &AccessRequest{
- Type: AUTHORIZATION_CODE,
- Code: r.Form.Get("code"),
- RedirectUri: r.Form.Get("redirect_uri"),
- GenerateRefresh: true,
- Expiration: s.Config.AccessExpiration,
- HttpRequest: r,
- }
-
- // "code" is required
- if ret.Code == "" {
- w.SetError(E_INVALID_GRANT, "")
- return nil
- }
-
- // must have a valid client
- if ret.Client = getClient(auth, w.Storage, w); ret.Client == nil {
- return nil
- }
-
- // must be a valid authorization code
- var err error
- ret.AuthorizeData, err = w.Storage.LoadAuthorize(ret.Code)
- if err != nil {
- w.SetError(E_INVALID_GRANT, "")
- w.InternalError = err
- return nil
- }
- if ret.AuthorizeData == nil {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- if ret.AuthorizeData.Client == nil {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- if ret.AuthorizeData.Client.GetRedirectUri() == "" {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- if ret.AuthorizeData.IsExpired() {
- w.SetError(E_INVALID_GRANT, "")
- return nil
- }
-
- // code must be from the client
- if ret.AuthorizeData.Client.GetId() != ret.Client.GetId() {
- w.SetError(E_INVALID_GRANT, "")
- return nil
- }
-
- // check redirect uri
- if ret.RedirectUri == "" {
- ret.RedirectUri = FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator)
- }
- if err = ValidateUriList(ret.Client.GetRedirectUri(), ret.RedirectUri, s.Config.RedirectUriSeparator); err != nil {
- w.SetError(E_INVALID_REQUEST, "")
- w.InternalError = err
- return nil
- }
- if ret.AuthorizeData.RedirectUri != ret.RedirectUri {
- w.SetError(E_INVALID_REQUEST, "")
- w.InternalError = errors.New("Redirect uri is different")
- return nil
- }
-
- // set rest of data
- ret.Scope = ret.AuthorizeData.Scope
- ret.UserData = ret.AuthorizeData.UserData
-
- return ret
-}
-
-func (s *Server) handleRefreshTokenRequest(w *Response, r *http.Request) *AccessRequest {
- // get client authentication
- auth := getClientAuth(w, r, s.Config.AllowClientSecretInParams)
- if auth == nil {
- return nil
- }
-
- // generate access token
- ret := &AccessRequest{
- Type: REFRESH_TOKEN,
- Code: r.Form.Get("refresh_token"),
- Scope: r.Form.Get("scope"),
- GenerateRefresh: true,
- Expiration: s.Config.AccessExpiration,
- HttpRequest: r,
- }
-
- // "refresh_token" is required
- if ret.Code == "" {
- w.SetError(E_INVALID_GRANT, "")
- return nil
- }
-
- // must have a valid client
- if ret.Client = getClient(auth, w.Storage, w); ret.Client == nil {
- return nil
- }
-
- // must be a valid refresh code
- var err error
- ret.AccessData, err = w.Storage.LoadRefresh(ret.Code)
- if err != nil {
- w.SetError(E_INVALID_GRANT, "")
- w.InternalError = err
- return nil
- }
- if ret.AccessData == nil {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- if ret.AccessData.Client == nil {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- if ret.AccessData.Client.GetRedirectUri() == "" {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
-
- // client must be the same as the previous token
- if ret.AccessData.Client.GetId() != ret.Client.GetId() {
- w.SetError(E_INVALID_CLIENT, "")
- w.InternalError = errors.New("Client id must be the same from previous token")
- return nil
-
- }
-
- // set rest of data
- ret.RedirectUri = ret.AccessData.RedirectUri
- ret.UserData = ret.AccessData.UserData
- if ret.Scope == "" {
- ret.Scope = ret.AccessData.Scope
- }
-
- return ret
-}
-
-func (s *Server) handlePasswordRequest(w *Response, r *http.Request) *AccessRequest {
- // get client authentication
- auth := getClientAuth(w, r, s.Config.AllowClientSecretInParams)
- if auth == nil {
- return nil
- }
-
- // generate access token
- ret := &AccessRequest{
- Type: PASSWORD,
- Username: r.Form.Get("username"),
- Password: r.Form.Get("password"),
- Scope: r.Form.Get("scope"),
- GenerateRefresh: true,
- Expiration: s.Config.AccessExpiration,
- HttpRequest: r,
- }
-
- // "username" and "password" is required
- if ret.Username == "" || ret.Password == "" {
- w.SetError(E_INVALID_GRANT, "")
- return nil
- }
-
- // must have a valid client
- if ret.Client = getClient(auth, w.Storage, w); ret.Client == nil {
- return nil
- }
-
- // set redirect uri
- ret.RedirectUri = FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator)
-
- return ret
-}
-
-func (s *Server) handleClientCredentialsRequest(w *Response, r *http.Request) *AccessRequest {
- // get client authentication
- auth := getClientAuth(w, r, s.Config.AllowClientSecretInParams)
- if auth == nil {
- return nil
- }
-
- // generate access token
- ret := &AccessRequest{
- Type: CLIENT_CREDENTIALS,
- Scope: r.Form.Get("scope"),
- GenerateRefresh: false,
- Expiration: s.Config.AccessExpiration,
- HttpRequest: r,
- }
-
- // must have a valid client
- if ret.Client = getClient(auth, w.Storage, w); ret.Client == nil {
- return nil
- }
-
- // set redirect uri
- ret.RedirectUri = FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator)
-
- return ret
-}
-
-func (s *Server) handleAssertionRequest(w *Response, r *http.Request) *AccessRequest {
- // get client authentication
- auth := getClientAuth(w, r, s.Config.AllowClientSecretInParams)
- if auth == nil {
- return nil
- }
-
- // generate access token
- ret := &AccessRequest{
- Type: ASSERTION,
- Scope: r.Form.Get("scope"),
- AssertionType: r.Form.Get("assertion_type"),
- Assertion: r.Form.Get("assertion"),
- GenerateRefresh: false, // assertion should NOT generate a refresh token, per the RFC
- Expiration: s.Config.AccessExpiration,
- HttpRequest: r,
- }
-
- // "assertion_type" and "assertion" is required
- if ret.AssertionType == "" || ret.Assertion == "" {
- w.SetError(E_INVALID_GRANT, "")
- return nil
- }
-
- // must have a valid client
- if ret.Client = getClient(auth, w.Storage, w); ret.Client == nil {
- return nil
- }
-
- // set redirect uri
- ret.RedirectUri = FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator)
-
- return ret
-}
-
-func (s *Server) FinishAccessRequest(w *Response, r *http.Request, ar *AccessRequest) {
- // don't process if is already an error
- if w.IsError {
- return
- }
- redirectUri := r.Form.Get("redirect_uri")
- // Get redirect uri from AccessRequest if it's there (e.g., refresh token request)
- if ar.RedirectUri != "" {
- redirectUri = ar.RedirectUri
- }
- if ar.Authorized {
- var ret *AccessData
- var err error
-
- if ar.ForceAccessData == nil {
- // generate access token
- ret = &AccessData{
- Client: ar.Client,
- AuthorizeData: ar.AuthorizeData,
- AccessData: ar.AccessData,
- RedirectUri: redirectUri,
- CreatedAt: time.Now(),
- ExpiresIn: ar.Expiration,
- UserData: ar.UserData,
- Scope: ar.Scope,
- }
-
- // generate access token
- ret.AccessToken, ret.RefreshToken, err = s.AccessTokenGen.GenerateAccessToken(ret, ar.GenerateRefresh)
- if err != nil {
- w.SetError(E_SERVER_ERROR, "")
- w.InternalError = err
- return
- }
- } else {
- ret = ar.ForceAccessData
- }
-
- // save access token
- if err = w.Storage.SaveAccess(ret); err != nil {
- w.SetError(E_SERVER_ERROR, "")
- w.InternalError = err
- return
- }
-
- // remove authorization token
- if ret.AuthorizeData != nil {
- w.Storage.RemoveAuthorize(ret.AuthorizeData.Code)
- }
-
- // remove previous access token
- if ret.AccessData != nil {
- if ret.AccessData.RefreshToken != "" {
- w.Storage.RemoveRefresh(ret.AccessData.RefreshToken)
- }
- w.Storage.RemoveAccess(ret.AccessData.AccessToken)
- }
-
- // output data
- w.Output["access_token"] = ret.AccessToken
- w.Output["token_type"] = s.Config.TokenType
- w.Output["expires_in"] = ret.ExpiresIn
- if ret.RefreshToken != "" {
- w.Output["refresh_token"] = ret.RefreshToken
- }
- if ar.Scope != "" {
- w.Output["scope"] = ar.Scope
- }
- } else {
- w.SetError(E_ACCESS_DENIED, "")
- }
-}
-
-// Helper Functions
-
-// getClient looks up and authenticates the basic auth using the given
-// storage. Sets an error on the response if auth fails or a server error occurs.
-func getClient(auth *BasicAuth, storage Storage, w *Response) Client {
- client, err := storage.GetClient(auth.Username)
- if err != nil {
- w.SetError(E_SERVER_ERROR, "")
- w.InternalError = err
- return nil
- }
- if client == nil {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- if client.GetSecret() != auth.Password {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- if client.GetRedirectUri() == "" {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- return client
-}
diff --git a/vendor/github.com/lonelycode/osin/authorize.go b/vendor/github.com/lonelycode/osin/authorize.go
deleted file mode 100644
index 901f2a275ec..00000000000
--- a/vendor/github.com/lonelycode/osin/authorize.go
+++ /dev/null
@@ -1,315 +0,0 @@
-package osin
-
-import (
- "net/http"
- "net/url"
- "encoding/json"
- "time"
-)
-
-// AuthorizeRequestType is the type for OAuth param `response_type`
-type AuthorizeRequestType string
-
-const (
- CODE AuthorizeRequestType = "code"
- TOKEN = "token"
-)
-
-// Authorize request information
-type AuthorizeRequest struct {
- Type AuthorizeRequestType
- Client Client
- Scope string
- RedirectUri string
- State string
-
- // Set if request is authorized
- Authorized bool
-
- // Token expiration in seconds. Change if different from default.
- // If type = TOKEN, this expiration will be for the ACCESS token.
- Expiration int32
-
- // Data to be passed to storage. Not used by the library.
- UserData interface{}
-
- // HttpRequest *http.Request for special use
- HttpRequest *http.Request
-}
-
-// Authorization data
-type AuthorizeData struct {
- // Client information
- Client Client `json:",omitempty"`
-
- // Authorization code
- Code string
-
- // Token expiration in seconds
- ExpiresIn int32
-
- // Requested scope
- Scope string
-
- // Redirect Uri from request
- RedirectUri string
-
- // State data from request
- State string
-
- // Date created
- CreatedAt time.Time
-
- // Data to be passed to storage. Not used by the library.
- UserData interface{} `json:",omitempty"`
-}
-
-type authorizeData AuthorizeData
-func (c* AuthorizeData) UnmarshalJSON(b []byte) error {
- newAuthData := authorizeData{}
- newAuthData.Client = new(DefaultClient)
- // var code, scope, redirect, state string
- // var expires int32
- // var createdAt time.Time
- // var userData interface{}
- var err error
-
- if err = json.Unmarshal(b, &newAuthData); err == nil {
- *c = AuthorizeData(newAuthData)
- return nil
- }
-
- // if err = json.Unmarshal(b, &code); err == nil {
- // c.Code = code
- // return nil
- // }
- // if err = json.Unmarshal(b, &client); err == nil {
- // c.Client = client
- // return nil
- // }
- // if err = json.Unmarshal(b, &expires); err == nil {
- // c.ExpiresIn = expires
- // return nil
- // }
- // if err = json.Unmarshal(b, &scope); err == nil {
- // c.Scope = scope
- // return nil
- // }
- // if err = json.Unmarshal(b, &redirect); err == nil {
- // c.RedirectUri = redirect
- // return nil
- // }
- // if err = json.Unmarshal(b, &state); err == nil {
- // c.State = state
- // return nil
- // }
- // if err = json.Unmarshal(b, &createdAt); err == nil {
- // c.CreatedAt = createdAt
- // return nil
- // }
- // if err = json.Unmarshal(b, &userData); err == nil {
- // c.UserData = userData
- // return nil
- // }
-
- return nil
-}
-
-// IsExpired is true if authorization expired
-func (d *AuthorizeData) IsExpired() bool {
- return d.CreatedAt.Add(time.Duration(d.ExpiresIn) * time.Second).Before(time.Now())
-}
-
-// ExpireAt returns the expiration date
-func (d *AuthorizeData) ExpireAt() time.Time {
- return d.CreatedAt.Add(time.Duration(d.ExpiresIn) * time.Second)
-}
-
-// AuthorizeTokenGen is the token generator interface
-type AuthorizeTokenGen interface {
- GenerateAuthorizeToken(data *AuthorizeData) (string, error)
-}
-
-// HandleAuthorizeRequest is the main http.HandlerFunc for handling
-// authorization requests
-func (s *Server) HandleAuthorizeRequest(w *Response, r *http.Request) *AuthorizeRequest {
- r.ParseForm()
-
- requestType := AuthorizeRequestType(r.Form.Get("response_type"))
- if s.Config.AllowedAuthorizeTypes.Exists(requestType) {
- switch requestType {
- case CODE:
- return s.handleCodeRequest(w, r)
- case TOKEN:
- return s.handleTokenRequest(w, r)
- }
- }
-
- w.SetError(E_UNSUPPORTED_RESPONSE_TYPE, "")
- return nil
-}
-
-func (s *Server) handleCodeRequest(w *Response, r *http.Request) *AuthorizeRequest {
- // create the authorization request
- unescapedUri, err := url.QueryUnescape(r.Form.Get("redirect_uri"))
- if err != nil {
- unescapedUri = ""
- }
- ret := &AuthorizeRequest{
- Type: CODE,
- State: r.Form.Get("state"),
- Scope: r.Form.Get("scope"),
- RedirectUri: unescapedUri,
- Authorized: false,
- Expiration: s.Config.AuthorizationExpiration,
- HttpRequest: r,
- }
-
- // must have a valid client
- ret.Client, err = w.Storage.GetClient(r.Form.Get("client_id"))
- if err != nil {
- w.SetErrorState(E_SERVER_ERROR, "", ret.State)
- w.InternalError = err
- return nil
- }
- if ret.Client == nil {
- w.SetErrorState(E_UNAUTHORIZED_CLIENT, "", ret.State)
- return nil
- }
- if ret.Client.GetRedirectUri() == "" {
- w.SetErrorState(E_UNAUTHORIZED_CLIENT, "", ret.State)
- return nil
- }
-
- // force redirect response to client redirecturl first
- w.SetRedirect(FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator))
-
- // check redirect uri
- if ret.RedirectUri == "" {
- ret.RedirectUri = FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator)
- }
- if err = ValidateUriList(ret.Client.GetRedirectUri(), ret.RedirectUri, s.Config.RedirectUriSeparator); err != nil {
- w.SetErrorState(E_INVALID_REQUEST, "", ret.State)
- w.InternalError = err
- return nil
- }
-
- return ret
-}
-
-func (s *Server) handleTokenRequest(w *Response, r *http.Request) *AuthorizeRequest {
- // create the authorization request
- unescapedUri, err := url.QueryUnescape(r.Form.Get("redirect_uri"))
- if err != nil {
- unescapedUri = ""
- }
- ret := &AuthorizeRequest{
- Type: TOKEN,
- State: r.Form.Get("state"),
- Scope: r.Form.Get("scope"),
- RedirectUri: unescapedUri,
- Authorized: false,
- // this type will generate a token directly, use access token expiration instead.
- Expiration: s.Config.AccessExpiration,
- HttpRequest: r,
- }
-
- // must have a valid client
- ret.Client, err = w.Storage.GetClient(r.Form.Get("client_id"))
- if err != nil {
- w.SetErrorState(E_SERVER_ERROR, "", ret.State)
- w.InternalError = err
- return nil
- }
- if ret.Client == nil {
- w.SetErrorState(E_UNAUTHORIZED_CLIENT, "", ret.State)
- return nil
- }
- if ret.Client.GetRedirectUri() == "" {
- w.SetErrorState(E_UNAUTHORIZED_CLIENT, "", ret.State)
- return nil
- }
-
- // force redirect response to client redirecturl first
- w.SetRedirect(FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator))
-
- // check redirect uri
- if ret.RedirectUri == "" {
- ret.RedirectUri = FirstUri(ret.Client.GetRedirectUri(), s.Config.RedirectUriSeparator)
- }
- if err = ValidateUriList(ret.Client.GetRedirectUri(), ret.RedirectUri, s.Config.RedirectUriSeparator); err != nil {
- w.SetErrorState(E_INVALID_REQUEST, "", ret.State)
- w.InternalError = err
- return nil
- }
-
- return ret
-}
-
-func (s *Server) FinishAuthorizeRequest(w *Response, r *http.Request, ar *AuthorizeRequest) {
- // don't process if is already an error
- if w.IsError {
- return
- }
-
- // force redirect response
- w.SetRedirect(ar.RedirectUri)
-
- if ar.Authorized {
- if ar.Type == TOKEN {
- w.SetRedirectFragment(true)
-
- // generate token directly
- ret := &AccessRequest{
- Type: IMPLICIT,
- Code: "",
- Client: ar.Client,
- RedirectUri: ar.RedirectUri,
- Scope: ar.Scope,
- GenerateRefresh: false, // per the RFC, should NOT generate a refresh token in this case
- Authorized: true,
- Expiration: ar.Expiration,
- UserData: ar.UserData,
- }
-
- s.FinishAccessRequest(w, r, ret)
- if ar.State != "" && w.InternalError == nil {
- w.Output["state"] = ar.State
- }
- } else {
- // generate authorization token
- ret := &AuthorizeData{
- Client: ar.Client,
- CreatedAt: time.Now(),
- ExpiresIn: ar.Expiration,
- RedirectUri: ar.RedirectUri,
- State: ar.State,
- Scope: ar.Scope,
- UserData: ar.UserData,
- }
-
- // generate token code
- code, err := s.AuthorizeTokenGen.GenerateAuthorizeToken(ret)
- if err != nil {
- w.SetErrorState(E_SERVER_ERROR, "", ar.State)
- w.InternalError = err
- return
- }
- ret.Code = code
-
- // save authorization token
- if err = w.Storage.SaveAuthorize(ret); err != nil {
- w.SetErrorState(E_SERVER_ERROR, "", ar.State)
- w.InternalError = err
- return
- }
-
- // redirect with code
- w.Output["code"] = ret.Code
- w.Output["state"] = ret.State
- }
- } else {
- // redirect with error
- w.SetErrorState(E_ACCESS_DENIED, "", ar.State)
- }
-}
diff --git a/vendor/github.com/lonelycode/osin/client.go b/vendor/github.com/lonelycode/osin/client.go
deleted file mode 100644
index 48264ba5f76..00000000000
--- a/vendor/github.com/lonelycode/osin/client.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package osin
-
-// Client information
-type Client interface {
- // Client id
- GetId() string
-
- // Client secret
- GetSecret() string
-
- // Base client uri
- GetRedirectUri() string
-
- // Data to be passed to storage. Not used by the library.
- GetUserData() interface{}
-
- // Data to be passed to storage. Not used by the library.
- GetPolicyID() string
-}
-
-// DefaultClient stores all data in struct variables
-type DefaultClient struct {
- Id string
- Secret string
- RedirectUri string
- UserData interface{} `json:",omitempty"`
-}
-
-func (d *DefaultClient) GetId() string {
- return d.Id
-}
-
-func (d *DefaultClient) GetSecret() string {
- return d.Secret
-}
-
-func (d *DefaultClient) GetRedirectUri() string {
- return d.RedirectUri
-}
-
-func (d *DefaultClient) GetUserData() interface{} {
- return d.UserData
-}
-
-func (d *DefaultClient) GetPolicyID() string {
- return ""
-}
-
-func (d *DefaultClient) CopyFrom(client Client) {
- d.Id = client.GetId()
- d.Secret = client.GetSecret()
- d.RedirectUri = client.GetRedirectUri()
- d.UserData = client.GetUserData()
-}
diff --git a/vendor/github.com/lonelycode/osin/config.go b/vendor/github.com/lonelycode/osin/config.go
deleted file mode 100644
index e38db012f0d..00000000000
--- a/vendor/github.com/lonelycode/osin/config.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package osin
-
-// AllowedAuthorizeType is a collection of allowed auth request types
-type AllowedAuthorizeType []AuthorizeRequestType
-
-// Exists returns true if the auth type exists in the list
-func (t AllowedAuthorizeType) Exists(rt AuthorizeRequestType) bool {
- for _, k := range t {
- if k == rt {
- return true
- }
- }
- return false
-}
-
-// AllowedAccessType is a collection of allowed access request types
-type AllowedAccessType []AccessRequestType
-
-// Exists returns true if the access type exists in the list
-func (t AllowedAccessType) Exists(rt AccessRequestType) bool {
- for _, k := range t {
- if k == rt {
- return true
- }
- }
- return false
-}
-
-// ServerConfig contains server configuration information
-type ServerConfig struct {
- // Authorization token expiration in seconds (default 5 minutes)
- AuthorizationExpiration int32
-
- // Access token expiration in seconds (default 1 hour)
- AccessExpiration int32
-
- // Token type to return
- TokenType string
-
- // List of allowed authorize types (only CODE by default)
- AllowedAuthorizeTypes AllowedAuthorizeType
-
- // List of allowed access types (only AUTHORIZATION_CODE by default)
- AllowedAccessTypes AllowedAccessType
-
- // HTTP status code to return for errors - default 200
- // Only used if response was created from server
- ErrorStatusCode int
-
- // If true allows client secret also in params, else only in
- // Authorization header - default false
- AllowClientSecretInParams bool
-
- // If true allows access request using GET, else only POST - default false
- AllowGetAccessRequest bool
-
- // Separator to support multiple URIs in Client.GetRedirectUri().
- // If blank (the default), don't allow multiple URIs.
- RedirectUriSeparator string
-}
-
-// NewServerConfig returns a new ServerConfig with default configuration
-func NewServerConfig() *ServerConfig {
- return &ServerConfig{
- AuthorizationExpiration: 250,
- AccessExpiration: 3600,
- TokenType: "bearer",
- AllowedAuthorizeTypes: AllowedAuthorizeType{CODE},
- AllowedAccessTypes: AllowedAccessType{AUTHORIZATION_CODE},
- ErrorStatusCode: 200,
- AllowClientSecretInParams: false,
- AllowGetAccessRequest: false,
- }
-}
diff --git a/vendor/github.com/lonelycode/osin/error.go b/vendor/github.com/lonelycode/osin/error.go
deleted file mode 100644
index a32f3ab90b7..00000000000
--- a/vendor/github.com/lonelycode/osin/error.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package osin
-
-type DefaultErrorId string
-
-const (
- E_INVALID_REQUEST string = "invalid_request"
- E_UNAUTHORIZED_CLIENT = "unauthorized_client"
- E_ACCESS_DENIED = "access_denied"
- E_UNSUPPORTED_RESPONSE_TYPE = "unsupported_response_type"
- E_INVALID_SCOPE = "invalid_scope"
- E_SERVER_ERROR = "server_error"
- E_TEMPORARILY_UNAVAILABLE = "temporarily_unavailable"
- E_UNSUPPORTED_GRANT_TYPE = "unsupported_grant_type"
- E_INVALID_GRANT = "invalid_grant"
- E_INVALID_CLIENT = "invalid_client"
-)
-
-var (
- deferror *DefaultErrors = NewDefaultErrors()
-)
-
-// Default errors and messages
-type DefaultErrors struct {
- errormap map[string]string
-}
-
-// NewDefaultErrors initializes OAuth2 error codes and descriptions.
-// http://tools.ietf.org/html/rfc6749#section-4.1.2.1
-// http://tools.ietf.org/html/rfc6749#section-4.2.2.1
-// http://tools.ietf.org/html/rfc6749#section-5.2
-// http://tools.ietf.org/html/rfc6749#section-7.2
-func NewDefaultErrors() *DefaultErrors {
- r := &DefaultErrors{errormap: make(map[string]string)}
- r.errormap[E_INVALID_REQUEST] = "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed."
- r.errormap[E_UNAUTHORIZED_CLIENT] = "The client is not authorized to request a token using this method."
- r.errormap[E_ACCESS_DENIED] = "The resource owner or authorization server denied the request."
- r.errormap[E_UNSUPPORTED_RESPONSE_TYPE] = "The authorization server does not support obtaining a token using this method."
- r.errormap[E_INVALID_SCOPE] = "The requested scope is invalid, unknown, or malformed."
- r.errormap[E_SERVER_ERROR] = "The authorization server encountered an unexpected condition that prevented it from fulfilling the request."
- r.errormap[E_TEMPORARILY_UNAVAILABLE] = "The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server."
- r.errormap[E_UNSUPPORTED_GRANT_TYPE] = "The authorization grant type is not supported by the authorization server."
- r.errormap[E_INVALID_GRANT] = "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."
- r.errormap[E_INVALID_CLIENT] = "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)."
- return r
-}
-
-func (e *DefaultErrors) Get(id string) string {
- if m, ok := e.errormap[id]; ok {
- return m
- }
- return id
-}
diff --git a/vendor/github.com/lonelycode/osin/info.go b/vendor/github.com/lonelycode/osin/info.go
deleted file mode 100644
index d6e24425871..00000000000
--- a/vendor/github.com/lonelycode/osin/info.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package osin
-
-import (
- "net/http"
- "time"
-)
-
-// InfoRequest is a request for information about some AccessData
-type InfoRequest struct {
- Code string // Code to look up
- AccessData *AccessData // AccessData associated with Code
-}
-
-// HandleInfoRequest is an http.HandlerFunc for server information
-// NOT an RFC specification.
-func (s *Server) HandleInfoRequest(w *Response, r *http.Request) *InfoRequest {
- r.ParseForm()
- bearer := CheckBearerAuth(r)
-
- // generate info request
- ret := &InfoRequest{
- Code: bearer.Code,
- }
-
- if ret.Code == "" {
- w.SetError(E_INVALID_REQUEST, "")
- return nil
- }
-
- var err error
-
- // load access data
- ret.AccessData, err = w.Storage.LoadAccess(ret.Code)
- if err != nil {
- w.SetError(E_INVALID_REQUEST, "")
- w.InternalError = err
- return nil
- }
- if ret.AccessData == nil {
- w.SetError(E_INVALID_REQUEST, "")
- return nil
- }
- if ret.AccessData.Client == nil {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- if ret.AccessData.Client.GetRedirectUri() == "" {
- w.SetError(E_UNAUTHORIZED_CLIENT, "")
- return nil
- }
- if ret.AccessData.IsExpired() {
- w.SetError(E_INVALID_GRANT, "")
- return nil
- }
-
- return ret
-}
-
-// FinishInfoRequest finalizes the request handled by HandleInfoRequest
-func (s *Server) FinishInfoRequest(w *Response, r *http.Request, ir *InfoRequest) {
- // don't process if is already an error
- if w.IsError {
- return
- }
-
- // output data
- w.Output["client_id"] = ir.AccessData.Client.GetId()
- w.Output["access_token"] = ir.AccessData.AccessToken
- w.Output["token_type"] = s.Config.TokenType
- w.Output["expires_in"] = ir.AccessData.CreatedAt.Add(time.Duration(ir.AccessData.ExpiresIn)*time.Second).Sub(time.Now()) / time.Second
- if ir.AccessData.RefreshToken != "" {
- w.Output["refresh_token"] = ir.AccessData.RefreshToken
- }
- if ir.AccessData.Scope != "" {
- w.Output["scope"] = ir.AccessData.Scope
- }
-}
diff --git a/vendor/github.com/lonelycode/osin/response.go b/vendor/github.com/lonelycode/osin/response.go
deleted file mode 100644
index 299ec963b25..00000000000
--- a/vendor/github.com/lonelycode/osin/response.go
+++ /dev/null
@@ -1,133 +0,0 @@
-package osin
-
-import (
- "errors"
- "fmt"
- "net/http"
- "net/url"
-)
-
-// Data for response output
-type ResponseData map[string]interface{}
-
-// Response type enum
-type ResponseType int
-
-const (
- DATA ResponseType = iota
- REDIRECT
-)
-
-// Server response
-type Response struct {
- Type ResponseType
- StatusCode int
- StatusText string
- ErrorStatusCode int
- URL string
- Output ResponseData
- Headers http.Header
- IsError bool
- InternalError error
- RedirectInFragment bool
-
- // Storage to use in this response - required
- Storage Storage
-}
-
-func NewResponse(storage Storage) *Response {
- r := &Response{
- Type: DATA,
- StatusCode: 200,
- ErrorStatusCode: 200,
- Output: make(ResponseData),
- Headers: make(http.Header),
- IsError: false,
- Storage: storage.Clone(),
- }
- r.Headers.Add("Cache-Control", "no-store")
- return r
-}
-
-// SetError sets an error id and description on the Response
-// state and uri are left blank
-func (r *Response) SetError(id string, description string) {
- r.SetErrorUri(id, description, "", "")
-}
-
-// SetErrorState sets an error id, description, and state on the Response
-// uri is left blank
-func (r *Response) SetErrorState(id string, description string, state string) {
- r.SetErrorUri(id, description, "", state)
-}
-
-// SetErrorUri sets an error id, description, state, and uri on the Response
-func (r *Response) SetErrorUri(id string, description string, uri string, state string) {
- // get default error message
- if description == "" {
- description = deferror.Get(id)
- }
-
- // set error parameters
- r.IsError = true
- r.StatusCode = r.ErrorStatusCode
- if r.StatusCode != 200 {
- r.StatusText = description
- } else {
- r.StatusText = ""
- }
- r.Output = make(ResponseData) // clear output
- r.Output["error"] = id
- r.Output["error_description"] = description
- if uri != "" {
- r.Output["error_uri"] = uri
- }
- if state != "" {
- r.Output["state"] = state
- }
-}
-
-// SetErrorUri changes the response to redirect to the given url
-func (r *Response) SetRedirect(url string) {
- // set redirect parameters
- r.Type = REDIRECT
- r.URL = url
-}
-
-// SetRedirectFragment sets redirect values to be passed in fragment instead of as query parameters
-func (r *Response) SetRedirectFragment(f bool) {
- r.RedirectInFragment = f
-}
-
-// GetRedirectUrl returns the redirect url with all query string parameters
-func (r *Response) GetRedirectUrl() (string, error) {
- if r.Type != REDIRECT {
- return "", errors.New("Not a redirect response")
- }
-
- u, err := url.Parse(r.URL)
- if err != nil {
- return "", err
- }
-
- // add parameters
- q := u.Query()
- for n, v := range r.Output {
- q.Set(n, fmt.Sprint(v))
- }
- if r.RedirectInFragment {
- u.RawQuery = ""
- u.Fragment, err = url.QueryUnescape(q.Encode())
- if err != nil {
- return "", err
- }
- } else {
- u.RawQuery = q.Encode()
- }
-
- return u.String(), nil
-}
-
-func (r *Response) Close() {
- r.Storage.Close()
-}
diff --git a/vendor/github.com/lonelycode/osin/response_json.go b/vendor/github.com/lonelycode/osin/response_json.go
deleted file mode 100644
index f86210a98b6..00000000000
--- a/vendor/github.com/lonelycode/osin/response_json.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package osin
-
-import (
- "encoding/json"
- "net/http"
-)
-
-// OutputJSON encodes the Response to JSON and writes to the http.ResponseWriter
-func OutputJSON(rs *Response, w http.ResponseWriter, r *http.Request) error {
- // Add headers
- for i, k := range rs.Headers {
- for _, v := range k {
- w.Header().Add(i, v)
- }
- }
-
- if rs.Type == REDIRECT {
- // Output redirect with parameters
- u, err := rs.GetRedirectUrl()
- if err != nil {
- return err
- }
- w.Header().Add("Location", u)
- w.WriteHeader(302)
- } else {
- // Output json
- w.Header().Add("Content-Type", "application/json")
- w.WriteHeader(rs.StatusCode)
-
- encoder := json.NewEncoder(w)
- err := encoder.Encode(rs.Output)
- if err != nil {
- return err
- }
- }
- return nil
-}
diff --git a/vendor/github.com/lonelycode/osin/server.go b/vendor/github.com/lonelycode/osin/server.go
deleted file mode 100644
index 4ebac260dee..00000000000
--- a/vendor/github.com/lonelycode/osin/server.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package osin
-
-import (
- "net/http"
-)
-
-// Server is an OAuth2 implementation
-type Server struct {
- Config *ServerConfig
- Storage Storage
- AuthorizeTokenGen AuthorizeTokenGen
- AccessTokenGen AccessTokenGen
-}
-
-// NewServer creates a new server instance
-func NewServer(config *ServerConfig, storage Storage) *Server {
- return &Server{
- Config: config,
- Storage: storage,
- AuthorizeTokenGen: &AuthorizeTokenGenDefault{},
- AccessTokenGen: &AccessTokenGenDefault{},
- }
-}
-
-// NewResponse creates a new response for the server
-func (s *Server) NewResponse() *Response {
- r := &Response{
- Type: DATA,
- StatusCode: 200,
- ErrorStatusCode: 200,
- Output: make(ResponseData),
- Headers: make(http.Header),
- IsError: false,
- Storage: s.Storage.Clone(),
- }
- r.Headers.Add("Cache-Control", "no-store")
- r.ErrorStatusCode = s.Config.ErrorStatusCode
- return r
-}
diff --git a/vendor/github.com/lonelycode/osin/storage.go b/vendor/github.com/lonelycode/osin/storage.go
deleted file mode 100644
index d3dea967cc8..00000000000
--- a/vendor/github.com/lonelycode/osin/storage.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package osin
-
-import ()
-
-// Storage interface
-type Storage interface {
- // Clone the storage if needed. For example, using mgo, you can clone the session with session.Clone
- // to avoid concurrent access problems.
- // This is to avoid cloning the connection at each method access.
- // Can return itself if not a problem.
- Clone() Storage
-
- // Close the resources the Storage potentially holds (using Clone for example)
- Close()
-
- // GetClient loads the client by id (client_id)
- GetClient(id string) (Client, error)
-
- // SaveAuthorize saves authorize data.
- SaveAuthorize(*AuthorizeData) error
-
- // LoadAuthorize looks up AuthorizeData by a code.
- // Client information MUST be loaded together.
- // Optionally can return error if expired.
- LoadAuthorize(code string) (*AuthorizeData, error)
-
- // RemoveAuthorize revokes or deletes the authorization code.
- RemoveAuthorize(code string) error
-
- // SaveAccess writes AccessData.
- // If RefreshToken is not blank, it must save in a way that can be loaded using LoadRefresh.
- SaveAccess(*AccessData) error
-
- // LoadAccess retrieves access data by token. Client information MUST be loaded together.
- // AuthorizeData and AccessData DON'T NEED to be loaded if not easily available.
- // Optionally can return error if expired.
- LoadAccess(token string) (*AccessData, error)
-
- // RemoveAccess revokes or deletes an AccessData.
- RemoveAccess(token string) error
-
- // LoadRefresh retrieves refresh AccessData. Client information MUST be loaded together.
- // AuthorizeData and AccessData DON'T NEED to be loaded if not easily available.
- // Optionally can return error if expired.
- LoadRefresh(token string) (*AccessData, error)
-
- // RemoveRefresh revokes or deletes refresh AccessData.
- RemoveRefresh(token string) error
-}
diff --git a/vendor/github.com/lonelycode/osin/tokengen.go b/vendor/github.com/lonelycode/osin/tokengen.go
deleted file mode 100644
index a580a4c9cac..00000000000
--- a/vendor/github.com/lonelycode/osin/tokengen.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package osin
-
-import (
- "encoding/base64"
- "strings"
-
- "github.com/lonelycode/go-uuid/uuid"
-)
-
-// AuthorizeTokenGenDefault is the default authorization token generator
-type AuthorizeTokenGenDefault struct {
-}
-
-func removePadding(token string) string {
- return strings.TrimRight(token, "=")
-}
-
-// GenerateAuthorizeToken generates a base64-encoded UUID code
-func (a *AuthorizeTokenGenDefault) GenerateAuthorizeToken(data *AuthorizeData) (ret string, err error) {
- token := uuid.NewRandom()
- return removePadding(base64.URLEncoding.EncodeToString([]byte(token))), nil
-}
-
-// AccessTokenGenDefault is the default authorization token generator
-type AccessTokenGenDefault struct {
-}
-
-// GenerateAccessToken generates base64-encoded UUID access and refresh tokens
-func (a *AccessTokenGenDefault) GenerateAccessToken(data *AccessData, generaterefresh bool) (accesstoken string, refreshtoken string, err error) {
- token := uuid.NewRandom()
- accesstoken = removePadding(base64.URLEncoding.EncodeToString([]byte(token)))
-
- if generaterefresh {
- rtoken := uuid.NewRandom()
- refreshtoken = removePadding(base64.URLEncoding.EncodeToString([]byte(rtoken)))
- }
- return
-}
diff --git a/vendor/github.com/lonelycode/osin/urivalidate.go b/vendor/github.com/lonelycode/osin/urivalidate.go
deleted file mode 100644
index d2268c2363a..00000000000
--- a/vendor/github.com/lonelycode/osin/urivalidate.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package osin
-
-import (
- "errors"
- "fmt"
- "net/url"
- "strings"
-)
-
-// error returned when validation don't match
-type UriValidationError string
-
-func (e UriValidationError) Error() string {
- return string(e)
-}
-
-// ValidateUriList validates that redirectUri is contained in baseUriList.
-// baseUriList may be a string separated by separator.
-// If separator is blank, validate only 1 URI.
-func ValidateUriList(baseUriList string, redirectUri string, separator string) error {
- // make a list of uris
- var slist []string
- if separator != "" {
- slist = strings.Split(baseUriList, separator)
- } else {
- slist = make([]string, 0)
- slist = append(slist, baseUriList)
- }
-
- for _, sitem := range slist {
- err := ValidateUri(sitem, redirectUri)
- // validated, return no error
- if err == nil {
- return nil
- }
-
- // if there was an error that is not a validation error, return it
- if _, iok := err.(UriValidationError); !iok {
- return err
- }
- }
-
- return UriValidationError(fmt.Sprintf("urls don't validate: %s / %s\n", baseUriList, redirectUri))
-}
-
-// ValidateUri validates that redirectUri is contained in baseUri
-func ValidateUri(baseUri string, redirectUri string) error {
- if baseUri == "" || redirectUri == "" {
- return errors.New("urls cannot be blank.")
- }
-
- // parse base url
- base, err := url.Parse(baseUri)
- if err != nil {
- return err
- }
-
- // parse passed url
- redirect, err := url.Parse(redirectUri)
- if err != nil {
- return err
- }
-
- // must not have fragment
- if base.Fragment != "" || redirect.Fragment != "" {
- return errors.New("url must not include fragment.")
- }
-
- // check if urls match
- if base.Scheme == redirect.Scheme && base.Host == redirect.Host && len(redirect.Path) >= len(base.Path) && strings.HasPrefix(redirect.Path, base.Path) {
- return nil
- }
-
- return UriValidationError(fmt.Sprintf("urls don't validate: %s / %s\n", baseUri, redirectUri))
-}
-
-// Returns the first uri from an uri list
-func FirstUri(baseUriList string, separator string) string {
- if separator != "" {
- slist := strings.Split(baseUriList, separator)
- if len(slist) > 0 {
- return slist[0]
- }
- } else {
- return baseUriList
- }
-
- return ""
-}
diff --git a/vendor/github.com/lonelycode/osin/util.go b/vendor/github.com/lonelycode/osin/util.go
deleted file mode 100644
index c10f5355229..00000000000
--- a/vendor/github.com/lonelycode/osin/util.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package osin
-
-import (
- "encoding/base64"
- "errors"
- "net/http"
- "strings"
-)
-
-// Parse basic authentication header
-type BasicAuth struct {
- Username string
- Password string
-}
-
-// Parse bearer authentication header
-type BearerAuth struct {
- Code string
-}
-
-// Return authorization header data
-func CheckBasicAuth(r *http.Request) (*BasicAuth, error) {
- if r.Header.Get("Authorization") == "" {
- return nil, nil
- }
-
- s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
- if len(s) != 2 || s[0] != "Basic" {
- return nil, errors.New("Invalid authorization header")
- }
-
- b, err := base64.StdEncoding.DecodeString(s[1])
- if err != nil {
- return nil, err
- }
- pair := strings.SplitN(string(b), ":", 2)
- if len(pair) != 2 {
- return nil, errors.New("Invalid authorization message")
- }
-
- return &BasicAuth{Username: pair[0], Password: pair[1]}, nil
-}
-
-// Return "Bearer" token from request. The header has precedence over query string.
-func CheckBearerAuth(r *http.Request) *BearerAuth {
- authHeader := r.Header.Get("Authorization")
- authForm := r.Form.Get("code")
- if authHeader == "" && authForm == "" {
- return nil
- }
- token := authForm
- if authHeader != "" {
- s := strings.SplitN(authHeader, " ", 2)
- if (len(s) != 2 || s[0] != "Bearer") && token == "" {
- return nil
- }
- token = s[1]
- }
- return &BearerAuth{Code: token}
-}
-
-// getClientAuth checks client basic authentication in params if allowed,
-// otherwise gets it from the header.
-// Sets an error on the response if no auth is present or a server error occurs.
-func getClientAuth(w *Response, r *http.Request, allowQueryParams bool) *BasicAuth {
-
- if allowQueryParams {
- // Allow for auth without password
- if _, hasSecret := r.Form["client_secret"]; hasSecret {
- auth := &BasicAuth{
- Username: r.Form.Get("client_id"),
- Password: r.Form.Get("client_secret"),
- }
- if auth.Username != "" {
- return auth
- }
- }
- }
-
- auth, err := CheckBasicAuth(r)
- if err != nil {
- w.SetError(E_INVALID_REQUEST, "")
- w.InternalError = err
- return nil
- }
- if auth == nil {
- w.SetError(E_INVALID_REQUEST, "")
- w.InternalError = errors.New("Client authentication not sent")
- return nil
- }
- return auth
-}
diff --git a/vendor/github.com/mattn/go-colorable/.travis.yml b/vendor/github.com/mattn/go-colorable/.travis.yml
deleted file mode 100644
index 98db8f060bd..00000000000
--- a/vendor/github.com/mattn/go-colorable/.travis.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-language: go
-go:
- - tip
-
-before_install:
- - go get github.com/mattn/goveralls
- - go get golang.org/x/tools/cmd/cover
-script:
- - $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw
diff --git a/vendor/github.com/mattn/go-colorable/LICENSE b/vendor/github.com/mattn/go-colorable/LICENSE
deleted file mode 100644
index 91b5cef30eb..00000000000
--- a/vendor/github.com/mattn/go-colorable/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 Yasuhiro Matsumoto
-
-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.
diff --git a/vendor/github.com/mattn/go-colorable/README.md b/vendor/github.com/mattn/go-colorable/README.md
deleted file mode 100644
index 56729a92ca6..00000000000
--- a/vendor/github.com/mattn/go-colorable/README.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# go-colorable
-
-[![Godoc Reference](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
-[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable)
-[![Coverage Status](https://coveralls.io/repos/github/mattn/go-colorable/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-colorable?branch=master)
-[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)
-
-Colorable writer for windows.
-
-For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
-This package is possible to handle escape sequence for ansi color on windows.
-
-## Too Bad!
-
-![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
-
-
-## So Good!
-
-![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
-
-## Usage
-
-```go
-logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
-logrus.SetOutput(colorable.NewColorableStdout())
-
-logrus.Info("succeeded")
-logrus.Warn("not correct")
-logrus.Error("something error")
-logrus.Fatal("panic")
-```
-
-You can compile above code on non-windows OSs.
-
-## Installation
-
-```
-$ go get github.com/mattn/go-colorable
-```
-
-# License
-
-MIT
-
-# Author
-
-Yasuhiro Matsumoto (a.k.a mattn)
diff --git a/vendor/github.com/mattn/go-colorable/colorable_appengine.go b/vendor/github.com/mattn/go-colorable/colorable_appengine.go
deleted file mode 100644
index 0b0aef83700..00000000000
--- a/vendor/github.com/mattn/go-colorable/colorable_appengine.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// +build appengine
-
-package colorable
-
-import (
- "io"
- "os"
-
- _ "github.com/mattn/go-isatty"
-)
-
-// NewColorable returns new instance of Writer which handles escape sequence.
-func NewColorable(file *os.File) io.Writer {
- if file == nil {
- panic("nil passed instead of *os.File to NewColorable()")
- }
-
- return file
-}
-
-// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
-func NewColorableStdout() io.Writer {
- return os.Stdout
-}
-
-// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
-func NewColorableStderr() io.Writer {
- return os.Stderr
-}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go
deleted file mode 100644
index 3fb771dcca2..00000000000
--- a/vendor/github.com/mattn/go-colorable/colorable_others.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// +build !windows
-// +build !appengine
-
-package colorable
-
-import (
- "io"
- "os"
-
- _ "github.com/mattn/go-isatty"
-)
-
-// NewColorable returns new instance of Writer which handles escape sequence.
-func NewColorable(file *os.File) io.Writer {
- if file == nil {
- panic("nil passed instead of *os.File to NewColorable()")
- }
-
- return file
-}
-
-// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
-func NewColorableStdout() io.Writer {
- return os.Stdout
-}
-
-// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
-func NewColorableStderr() io.Writer {
- return os.Stderr
-}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go
deleted file mode 100644
index 1bd628f25c0..00000000000
--- a/vendor/github.com/mattn/go-colorable/colorable_windows.go
+++ /dev/null
@@ -1,1005 +0,0 @@
-// +build windows
-// +build !appengine
-
-package colorable
-
-import (
- "bytes"
- "io"
- "math"
- "os"
- "strconv"
- "strings"
- "syscall"
- "unsafe"
-
- "github.com/mattn/go-isatty"
-)
-
-const (
- foregroundBlue = 0x1
- foregroundGreen = 0x2
- foregroundRed = 0x4
- foregroundIntensity = 0x8
- foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
- backgroundBlue = 0x10
- backgroundGreen = 0x20
- backgroundRed = 0x40
- backgroundIntensity = 0x80
- backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
-)
-
-const (
- genericRead = 0x80000000
- genericWrite = 0x40000000
-)
-
-const (
- consoleTextmodeBuffer = 0x1
-)
-
-type wchar uint16
-type short int16
-type dword uint32
-type word uint16
-
-type coord struct {
- x short
- y short
-}
-
-type smallRect struct {
- left short
- top short
- right short
- bottom short
-}
-
-type consoleScreenBufferInfo struct {
- size coord
- cursorPosition coord
- attributes word
- window smallRect
- maximumWindowSize coord
-}
-
-type consoleCursorInfo struct {
- size dword
- visible int32
-}
-
-var (
- kernel32 = syscall.NewLazyDLL("kernel32.dll")
- procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
- procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
- procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
- procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
- procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
- procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
- procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
- procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
- procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer")
-)
-
-// Writer provides colorable Writer to the console
-type Writer struct {
- out io.Writer
- handle syscall.Handle
- althandle syscall.Handle
- oldattr word
- oldpos coord
- rest bytes.Buffer
-}
-
-// NewColorable returns new instance of Writer which handles escape sequence from File.
-func NewColorable(file *os.File) io.Writer {
- if file == nil {
- panic("nil passed instead of *os.File to NewColorable()")
- }
-
- if isatty.IsTerminal(file.Fd()) {
- var csbi consoleScreenBufferInfo
- handle := syscall.Handle(file.Fd())
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
- }
- return file
-}
-
-// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
-func NewColorableStdout() io.Writer {
- return NewColorable(os.Stdout)
-}
-
-// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
-func NewColorableStderr() io.Writer {
- return NewColorable(os.Stderr)
-}
-
-var color256 = map[int]int{
- 0: 0x000000,
- 1: 0x800000,
- 2: 0x008000,
- 3: 0x808000,
- 4: 0x000080,
- 5: 0x800080,
- 6: 0x008080,
- 7: 0xc0c0c0,
- 8: 0x808080,
- 9: 0xff0000,
- 10: 0x00ff00,
- 11: 0xffff00,
- 12: 0x0000ff,
- 13: 0xff00ff,
- 14: 0x00ffff,
- 15: 0xffffff,
- 16: 0x000000,
- 17: 0x00005f,
- 18: 0x000087,
- 19: 0x0000af,
- 20: 0x0000d7,
- 21: 0x0000ff,
- 22: 0x005f00,
- 23: 0x005f5f,
- 24: 0x005f87,
- 25: 0x005faf,
- 26: 0x005fd7,
- 27: 0x005fff,
- 28: 0x008700,
- 29: 0x00875f,
- 30: 0x008787,
- 31: 0x0087af,
- 32: 0x0087d7,
- 33: 0x0087ff,
- 34: 0x00af00,
- 35: 0x00af5f,
- 36: 0x00af87,
- 37: 0x00afaf,
- 38: 0x00afd7,
- 39: 0x00afff,
- 40: 0x00d700,
- 41: 0x00d75f,
- 42: 0x00d787,
- 43: 0x00d7af,
- 44: 0x00d7d7,
- 45: 0x00d7ff,
- 46: 0x00ff00,
- 47: 0x00ff5f,
- 48: 0x00ff87,
- 49: 0x00ffaf,
- 50: 0x00ffd7,
- 51: 0x00ffff,
- 52: 0x5f0000,
- 53: 0x5f005f,
- 54: 0x5f0087,
- 55: 0x5f00af,
- 56: 0x5f00d7,
- 57: 0x5f00ff,
- 58: 0x5f5f00,
- 59: 0x5f5f5f,
- 60: 0x5f5f87,
- 61: 0x5f5faf,
- 62: 0x5f5fd7,
- 63: 0x5f5fff,
- 64: 0x5f8700,
- 65: 0x5f875f,
- 66: 0x5f8787,
- 67: 0x5f87af,
- 68: 0x5f87d7,
- 69: 0x5f87ff,
- 70: 0x5faf00,
- 71: 0x5faf5f,
- 72: 0x5faf87,
- 73: 0x5fafaf,
- 74: 0x5fafd7,
- 75: 0x5fafff,
- 76: 0x5fd700,
- 77: 0x5fd75f,
- 78: 0x5fd787,
- 79: 0x5fd7af,
- 80: 0x5fd7d7,
- 81: 0x5fd7ff,
- 82: 0x5fff00,
- 83: 0x5fff5f,
- 84: 0x5fff87,
- 85: 0x5fffaf,
- 86: 0x5fffd7,
- 87: 0x5fffff,
- 88: 0x870000,
- 89: 0x87005f,
- 90: 0x870087,
- 91: 0x8700af,
- 92: 0x8700d7,
- 93: 0x8700ff,
- 94: 0x875f00,
- 95: 0x875f5f,
- 96: 0x875f87,
- 97: 0x875faf,
- 98: 0x875fd7,
- 99: 0x875fff,
- 100: 0x878700,
- 101: 0x87875f,
- 102: 0x878787,
- 103: 0x8787af,
- 104: 0x8787d7,
- 105: 0x8787ff,
- 106: 0x87af00,
- 107: 0x87af5f,
- 108: 0x87af87,
- 109: 0x87afaf,
- 110: 0x87afd7,
- 111: 0x87afff,
- 112: 0x87d700,
- 113: 0x87d75f,
- 114: 0x87d787,
- 115: 0x87d7af,
- 116: 0x87d7d7,
- 117: 0x87d7ff,
- 118: 0x87ff00,
- 119: 0x87ff5f,
- 120: 0x87ff87,
- 121: 0x87ffaf,
- 122: 0x87ffd7,
- 123: 0x87ffff,
- 124: 0xaf0000,
- 125: 0xaf005f,
- 126: 0xaf0087,
- 127: 0xaf00af,
- 128: 0xaf00d7,
- 129: 0xaf00ff,
- 130: 0xaf5f00,
- 131: 0xaf5f5f,
- 132: 0xaf5f87,
- 133: 0xaf5faf,
- 134: 0xaf5fd7,
- 135: 0xaf5fff,
- 136: 0xaf8700,
- 137: 0xaf875f,
- 138: 0xaf8787,
- 139: 0xaf87af,
- 140: 0xaf87d7,
- 141: 0xaf87ff,
- 142: 0xafaf00,
- 143: 0xafaf5f,
- 144: 0xafaf87,
- 145: 0xafafaf,
- 146: 0xafafd7,
- 147: 0xafafff,
- 148: 0xafd700,
- 149: 0xafd75f,
- 150: 0xafd787,
- 151: 0xafd7af,
- 152: 0xafd7d7,
- 153: 0xafd7ff,
- 154: 0xafff00,
- 155: 0xafff5f,
- 156: 0xafff87,
- 157: 0xafffaf,
- 158: 0xafffd7,
- 159: 0xafffff,
- 160: 0xd70000,
- 161: 0xd7005f,
- 162: 0xd70087,
- 163: 0xd700af,
- 164: 0xd700d7,
- 165: 0xd700ff,
- 166: 0xd75f00,
- 167: 0xd75f5f,
- 168: 0xd75f87,
- 169: 0xd75faf,
- 170: 0xd75fd7,
- 171: 0xd75fff,
- 172: 0xd78700,
- 173: 0xd7875f,
- 174: 0xd78787,
- 175: 0xd787af,
- 176: 0xd787d7,
- 177: 0xd787ff,
- 178: 0xd7af00,
- 179: 0xd7af5f,
- 180: 0xd7af87,
- 181: 0xd7afaf,
- 182: 0xd7afd7,
- 183: 0xd7afff,
- 184: 0xd7d700,
- 185: 0xd7d75f,
- 186: 0xd7d787,
- 187: 0xd7d7af,
- 188: 0xd7d7d7,
- 189: 0xd7d7ff,
- 190: 0xd7ff00,
- 191: 0xd7ff5f,
- 192: 0xd7ff87,
- 193: 0xd7ffaf,
- 194: 0xd7ffd7,
- 195: 0xd7ffff,
- 196: 0xff0000,
- 197: 0xff005f,
- 198: 0xff0087,
- 199: 0xff00af,
- 200: 0xff00d7,
- 201: 0xff00ff,
- 202: 0xff5f00,
- 203: 0xff5f5f,
- 204: 0xff5f87,
- 205: 0xff5faf,
- 206: 0xff5fd7,
- 207: 0xff5fff,
- 208: 0xff8700,
- 209: 0xff875f,
- 210: 0xff8787,
- 211: 0xff87af,
- 212: 0xff87d7,
- 213: 0xff87ff,
- 214: 0xffaf00,
- 215: 0xffaf5f,
- 216: 0xffaf87,
- 217: 0xffafaf,
- 218: 0xffafd7,
- 219: 0xffafff,
- 220: 0xffd700,
- 221: 0xffd75f,
- 222: 0xffd787,
- 223: 0xffd7af,
- 224: 0xffd7d7,
- 225: 0xffd7ff,
- 226: 0xffff00,
- 227: 0xffff5f,
- 228: 0xffff87,
- 229: 0xffffaf,
- 230: 0xffffd7,
- 231: 0xffffff,
- 232: 0x080808,
- 233: 0x121212,
- 234: 0x1c1c1c,
- 235: 0x262626,
- 236: 0x303030,
- 237: 0x3a3a3a,
- 238: 0x444444,
- 239: 0x4e4e4e,
- 240: 0x585858,
- 241: 0x626262,
- 242: 0x6c6c6c,
- 243: 0x767676,
- 244: 0x808080,
- 245: 0x8a8a8a,
- 246: 0x949494,
- 247: 0x9e9e9e,
- 248: 0xa8a8a8,
- 249: 0xb2b2b2,
- 250: 0xbcbcbc,
- 251: 0xc6c6c6,
- 252: 0xd0d0d0,
- 253: 0xdadada,
- 254: 0xe4e4e4,
- 255: 0xeeeeee,
-}
-
-// `\033]0;TITLESTR\007`
-func doTitleSequence(er *bytes.Reader) error {
- var c byte
- var err error
-
- c, err = er.ReadByte()
- if err != nil {
- return err
- }
- if c != '0' && c != '2' {
- return nil
- }
- c, err = er.ReadByte()
- if err != nil {
- return err
- }
- if c != ';' {
- return nil
- }
- title := make([]byte, 0, 80)
- for {
- c, err = er.ReadByte()
- if err != nil {
- return err
- }
- if c == 0x07 || c == '\n' {
- break
- }
- title = append(title, c)
- }
- if len(title) > 0 {
- title8, err := syscall.UTF16PtrFromString(string(title))
- if err == nil {
- procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
- }
- }
- return nil
-}
-
-// returns Atoi(s) unless s == "" in which case it returns def
-func atoiWithDefault(s string, def int) (int, error) {
- if s == "" {
- return def, nil
- }
- return strconv.Atoi(s)
-}
-
-// Write writes data on console
-func (w *Writer) Write(data []byte) (n int, err error) {
- var csbi consoleScreenBufferInfo
- procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
-
- handle := w.handle
-
- var er *bytes.Reader
- if w.rest.Len() > 0 {
- var rest bytes.Buffer
- w.rest.WriteTo(&rest)
- w.rest.Reset()
- rest.Write(data)
- er = bytes.NewReader(rest.Bytes())
- } else {
- er = bytes.NewReader(data)
- }
- var bw [1]byte
-loop:
- for {
- c1, err := er.ReadByte()
- if err != nil {
- break loop
- }
- if c1 != 0x1b {
- bw[0] = c1
- w.out.Write(bw[:])
- continue
- }
- c2, err := er.ReadByte()
- if err != nil {
- break loop
- }
-
- switch c2 {
- case '>':
- continue
- case ']':
- w.rest.WriteByte(c1)
- w.rest.WriteByte(c2)
- er.WriteTo(&w.rest)
- if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 {
- break loop
- }
- er = bytes.NewReader(w.rest.Bytes()[2:])
- err := doTitleSequence(er)
- if err != nil {
- break loop
- }
- w.rest.Reset()
- continue
- // https://github.com/mattn/go-colorable/issues/27
- case '7':
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- w.oldpos = csbi.cursorPosition
- continue
- case '8':
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
- continue
- case 0x5b:
- // execute part after switch
- default:
- continue
- }
-
- w.rest.WriteByte(c1)
- w.rest.WriteByte(c2)
- er.WriteTo(&w.rest)
-
- var buf bytes.Buffer
- var m byte
- for i, c := range w.rest.Bytes()[2:] {
- if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
- m = c
- er = bytes.NewReader(w.rest.Bytes()[2+i+1:])
- w.rest.Reset()
- break
- }
- buf.Write([]byte(string(c)))
- }
- if m == 0 {
- break loop
- }
-
- switch m {
- case 'A':
- n, err = atoiWithDefault(buf.String(), 1)
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.y -= short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'B':
- n, err = atoiWithDefault(buf.String(), 1)
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.y += short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'C':
- n, err = atoiWithDefault(buf.String(), 1)
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x += short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'D':
- n, err = atoiWithDefault(buf.String(), 1)
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x -= short(n)
- if csbi.cursorPosition.x < 0 {
- csbi.cursorPosition.x = 0
- }
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'E':
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x = 0
- csbi.cursorPosition.y += short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'F':
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x = 0
- csbi.cursorPosition.y -= short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'G':
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- if n < 1 {
- n = 1
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x = short(n - 1)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'H', 'f':
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- if buf.Len() > 0 {
- token := strings.Split(buf.String(), ";")
- switch len(token) {
- case 1:
- n1, err := strconv.Atoi(token[0])
- if err != nil {
- continue
- }
- csbi.cursorPosition.y = short(n1 - 1)
- case 2:
- n1, err := strconv.Atoi(token[0])
- if err != nil {
- continue
- }
- n2, err := strconv.Atoi(token[1])
- if err != nil {
- continue
- }
- csbi.cursorPosition.x = short(n2 - 1)
- csbi.cursorPosition.y = short(n1 - 1)
- }
- } else {
- csbi.cursorPosition.y = 0
- }
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'J':
- n := 0
- if buf.Len() > 0 {
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- }
- var count, written dword
- var cursor coord
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- switch n {
- case 0:
- cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
- count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
- case 1:
- cursor = coord{x: csbi.window.left, y: csbi.window.top}
- count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x)
- case 2:
- cursor = coord{x: csbi.window.left, y: csbi.window.top}
- count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
- }
- procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- case 'K':
- n := 0
- if buf.Len() > 0 {
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- var cursor coord
- var count, written dword
- switch n {
- case 0:
- cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
- count = dword(csbi.size.x - csbi.cursorPosition.x)
- case 1:
- cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
- count = dword(csbi.size.x - csbi.cursorPosition.x)
- case 2:
- cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
- count = dword(csbi.size.x)
- }
- procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- case 'X':
- n := 0
- if buf.Len() > 0 {
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- var cursor coord
- var written dword
- cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
- procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- case 'm':
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- attr := csbi.attributes
- cs := buf.String()
- if cs == "" {
- procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr))
- continue
- }
- token := strings.Split(cs, ";")
- for i := 0; i < len(token); i++ {
- ns := token[i]
- if n, err = strconv.Atoi(ns); err == nil {
- switch {
- case n == 0 || n == 100:
- attr = w.oldattr
- case 1 <= n && n <= 5:
- attr |= foregroundIntensity
- case n == 7:
- attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
- case n == 22 || n == 25:
- attr |= foregroundIntensity
- case n == 27:
- attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
- case 30 <= n && n <= 37:
- attr &= backgroundMask
- if (n-30)&1 != 0 {
- attr |= foregroundRed
- }
- if (n-30)&2 != 0 {
- attr |= foregroundGreen
- }
- if (n-30)&4 != 0 {
- attr |= foregroundBlue
- }
- case n == 38: // set foreground color.
- if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
- if n256, err := strconv.Atoi(token[i+2]); err == nil {
- if n256foreAttr == nil {
- n256setup()
- }
- attr &= backgroundMask
- attr |= n256foreAttr[n256]
- i += 2
- }
- } else if len(token) == 5 && token[i+1] == "2" {
- var r, g, b int
- r, _ = strconv.Atoi(token[i+2])
- g, _ = strconv.Atoi(token[i+3])
- b, _ = strconv.Atoi(token[i+4])
- i += 4
- if r > 127 {
- attr |= foregroundRed
- }
- if g > 127 {
- attr |= foregroundGreen
- }
- if b > 127 {
- attr |= foregroundBlue
- }
- } else {
- attr = attr & (w.oldattr & backgroundMask)
- }
- case n == 39: // reset foreground color.
- attr &= backgroundMask
- attr |= w.oldattr & foregroundMask
- case 40 <= n && n <= 47:
- attr &= foregroundMask
- if (n-40)&1 != 0 {
- attr |= backgroundRed
- }
- if (n-40)&2 != 0 {
- attr |= backgroundGreen
- }
- if (n-40)&4 != 0 {
- attr |= backgroundBlue
- }
- case n == 48: // set background color.
- if i < len(token)-2 && token[i+1] == "5" {
- if n256, err := strconv.Atoi(token[i+2]); err == nil {
- if n256backAttr == nil {
- n256setup()
- }
- attr &= foregroundMask
- attr |= n256backAttr[n256]
- i += 2
- }
- } else if len(token) == 5 && token[i+1] == "2" {
- var r, g, b int
- r, _ = strconv.Atoi(token[i+2])
- g, _ = strconv.Atoi(token[i+3])
- b, _ = strconv.Atoi(token[i+4])
- i += 4
- if r > 127 {
- attr |= backgroundRed
- }
- if g > 127 {
- attr |= backgroundGreen
- }
- if b > 127 {
- attr |= backgroundBlue
- }
- } else {
- attr = attr & (w.oldattr & foregroundMask)
- }
- case n == 49: // reset foreground color.
- attr &= foregroundMask
- attr |= w.oldattr & backgroundMask
- case 90 <= n && n <= 97:
- attr = (attr & backgroundMask)
- attr |= foregroundIntensity
- if (n-90)&1 != 0 {
- attr |= foregroundRed
- }
- if (n-90)&2 != 0 {
- attr |= foregroundGreen
- }
- if (n-90)&4 != 0 {
- attr |= foregroundBlue
- }
- case 100 <= n && n <= 107:
- attr = (attr & foregroundMask)
- attr |= backgroundIntensity
- if (n-100)&1 != 0 {
- attr |= backgroundRed
- }
- if (n-100)&2 != 0 {
- attr |= backgroundGreen
- }
- if (n-100)&4 != 0 {
- attr |= backgroundBlue
- }
- }
- procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr))
- }
- }
- case 'h':
- var ci consoleCursorInfo
- cs := buf.String()
- if cs == "5>" {
- procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- ci.visible = 0
- procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- } else if cs == "?25" {
- procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- ci.visible = 1
- procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- } else if cs == "?1049" {
- if w.althandle == 0 {
- h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0)
- w.althandle = syscall.Handle(h)
- if w.althandle != 0 {
- handle = w.althandle
- }
- }
- }
- case 'l':
- var ci consoleCursorInfo
- cs := buf.String()
- if cs == "5>" {
- procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- ci.visible = 1
- procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- } else if cs == "?25" {
- procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- ci.visible = 0
- procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- } else if cs == "?1049" {
- if w.althandle != 0 {
- syscall.CloseHandle(w.althandle)
- w.althandle = 0
- handle = w.handle
- }
- }
- case 's':
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- w.oldpos = csbi.cursorPosition
- case 'u':
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
- }
- }
-
- return len(data), nil
-}
-
-type consoleColor struct {
- rgb int
- red bool
- green bool
- blue bool
- intensity bool
-}
-
-func (c consoleColor) foregroundAttr() (attr word) {
- if c.red {
- attr |= foregroundRed
- }
- if c.green {
- attr |= foregroundGreen
- }
- if c.blue {
- attr |= foregroundBlue
- }
- if c.intensity {
- attr |= foregroundIntensity
- }
- return
-}
-
-func (c consoleColor) backgroundAttr() (attr word) {
- if c.red {
- attr |= backgroundRed
- }
- if c.green {
- attr |= backgroundGreen
- }
- if c.blue {
- attr |= backgroundBlue
- }
- if c.intensity {
- attr |= backgroundIntensity
- }
- return
-}
-
-var color16 = []consoleColor{
- {0x000000, false, false, false, false},
- {0x000080, false, false, true, false},
- {0x008000, false, true, false, false},
- {0x008080, false, true, true, false},
- {0x800000, true, false, false, false},
- {0x800080, true, false, true, false},
- {0x808000, true, true, false, false},
- {0xc0c0c0, true, true, true, false},
- {0x808080, false, false, false, true},
- {0x0000ff, false, false, true, true},
- {0x00ff00, false, true, false, true},
- {0x00ffff, false, true, true, true},
- {0xff0000, true, false, false, true},
- {0xff00ff, true, false, true, true},
- {0xffff00, true, true, false, true},
- {0xffffff, true, true, true, true},
-}
-
-type hsv struct {
- h, s, v float32
-}
-
-func (a hsv) dist(b hsv) float32 {
- dh := a.h - b.h
- switch {
- case dh > 0.5:
- dh = 1 - dh
- case dh < -0.5:
- dh = -1 - dh
- }
- ds := a.s - b.s
- dv := a.v - b.v
- return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
-}
-
-func toHSV(rgb int) hsv {
- r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
- float32((rgb&0x00FF00)>>8)/256.0,
- float32(rgb&0x0000FF)/256.0
- min, max := minmax3f(r, g, b)
- h := max - min
- if h > 0 {
- if max == r {
- h = (g - b) / h
- if h < 0 {
- h += 6
- }
- } else if max == g {
- h = 2 + (b-r)/h
- } else {
- h = 4 + (r-g)/h
- }
- }
- h /= 6.0
- s := max - min
- if max != 0 {
- s /= max
- }
- v := max
- return hsv{h: h, s: s, v: v}
-}
-
-type hsvTable []hsv
-
-func toHSVTable(rgbTable []consoleColor) hsvTable {
- t := make(hsvTable, len(rgbTable))
- for i, c := range rgbTable {
- t[i] = toHSV(c.rgb)
- }
- return t
-}
-
-func (t hsvTable) find(rgb int) consoleColor {
- hsv := toHSV(rgb)
- n := 7
- l := float32(5.0)
- for i, p := range t {
- d := hsv.dist(p)
- if d < l {
- l, n = d, i
- }
- }
- return color16[n]
-}
-
-func minmax3f(a, b, c float32) (min, max float32) {
- if a < b {
- if b < c {
- return a, c
- } else if a < c {
- return a, b
- } else {
- return c, b
- }
- } else {
- if a < c {
- return b, c
- } else if b < c {
- return b, a
- } else {
- return c, a
- }
- }
-}
-
-var n256foreAttr []word
-var n256backAttr []word
-
-func n256setup() {
- n256foreAttr = make([]word, 256)
- n256backAttr = make([]word, 256)
- t := toHSVTable(color16)
- for i, rgb := range color256 {
- c := t.find(rgb)
- n256foreAttr[i] = c.foregroundAttr()
- n256backAttr[i] = c.backgroundAttr()
- }
-}
diff --git a/vendor/github.com/mattn/go-colorable/go.mod b/vendor/github.com/mattn/go-colorable/go.mod
deleted file mode 100644
index ef3ca9d4c31..00000000000
--- a/vendor/github.com/mattn/go-colorable/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/mattn/go-colorable
-
-require github.com/mattn/go-isatty v0.0.8
diff --git a/vendor/github.com/mattn/go-colorable/go.sum b/vendor/github.com/mattn/go-colorable/go.sum
deleted file mode 100644
index 2c12960ec73..00000000000
--- a/vendor/github.com/mattn/go-colorable/go.sum
+++ /dev/null
@@ -1,4 +0,0 @@
-github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
-github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go
deleted file mode 100644
index 95f2c6be257..00000000000
--- a/vendor/github.com/mattn/go-colorable/noncolorable.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package colorable
-
-import (
- "bytes"
- "io"
-)
-
-// NonColorable holds writer but removes escape sequence.
-type NonColorable struct {
- out io.Writer
-}
-
-// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
-func NewNonColorable(w io.Writer) io.Writer {
- return &NonColorable{out: w}
-}
-
-// Write writes data on console
-func (w *NonColorable) Write(data []byte) (n int, err error) {
- er := bytes.NewReader(data)
- var bw [1]byte
-loop:
- for {
- c1, err := er.ReadByte()
- if err != nil {
- break loop
- }
- if c1 != 0x1b {
- bw[0] = c1
- w.out.Write(bw[:])
- continue
- }
- c2, err := er.ReadByte()
- if err != nil {
- break loop
- }
- if c2 != 0x5b {
- continue
- }
-
- var buf bytes.Buffer
- for {
- c, err := er.ReadByte()
- if err != nil {
- break loop
- }
- if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
- break
- }
- buf.Write([]byte(string(c)))
- }
- }
-
- return len(data), nil
-}
diff --git a/vendor/github.com/mattn/go-isatty/.travis.yml b/vendor/github.com/mattn/go-isatty/.travis.yml
deleted file mode 100644
index 5597e026ddf..00000000000
--- a/vendor/github.com/mattn/go-isatty/.travis.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-language: go
-go:
- - tip
-
-os:
- - linux
- - osx
-
-before_install:
- - go get github.com/mattn/goveralls
- - go get golang.org/x/tools/cmd/cover
-script:
- - $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5
diff --git a/vendor/github.com/mattn/go-isatty/LICENSE b/vendor/github.com/mattn/go-isatty/LICENSE
deleted file mode 100644
index 65dc692b6b1..00000000000
--- a/vendor/github.com/mattn/go-isatty/LICENSE
+++ /dev/null
@@ -1,9 +0,0 @@
-Copyright (c) Yasuhiro MATSUMOTO
-
-MIT License (Expat)
-
-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.
diff --git a/vendor/github.com/mattn/go-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md
deleted file mode 100644
index 1e69004bb03..00000000000
--- a/vendor/github.com/mattn/go-isatty/README.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# go-isatty
-
-[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty)
-[![Build Status](https://travis-ci.org/mattn/go-isatty.svg?branch=master)](https://travis-ci.org/mattn/go-isatty)
-[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master)
-[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty)
-
-isatty for golang
-
-## Usage
-
-```go
-package main
-
-import (
- "fmt"
- "github.com/mattn/go-isatty"
- "os"
-)
-
-func main() {
- if isatty.IsTerminal(os.Stdout.Fd()) {
- fmt.Println("Is Terminal")
- } else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
- fmt.Println("Is Cygwin/MSYS2 Terminal")
- } else {
- fmt.Println("Is Not Terminal")
- }
-}
-```
-
-## Installation
-
-```
-$ go get github.com/mattn/go-isatty
-```
-
-## License
-
-MIT
-
-## Author
-
-Yasuhiro Matsumoto (a.k.a mattn)
-
-## Thanks
-
-* k-takata: base idea for IsCygwinTerminal
-
- https://github.com/k-takata/go-iscygpty
diff --git a/vendor/github.com/mattn/go-isatty/doc.go b/vendor/github.com/mattn/go-isatty/doc.go
deleted file mode 100644
index 17d4f90ebcc..00000000000
--- a/vendor/github.com/mattn/go-isatty/doc.go
+++ /dev/null
@@ -1,2 +0,0 @@
-// Package isatty implements interface to isatty
-package isatty
diff --git a/vendor/github.com/mattn/go-isatty/go.mod b/vendor/github.com/mattn/go-isatty/go.mod
deleted file mode 100644
index f310320c33f..00000000000
--- a/vendor/github.com/mattn/go-isatty/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/mattn/go-isatty
-
-require golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
diff --git a/vendor/github.com/mattn/go-isatty/go.sum b/vendor/github.com/mattn/go-isatty/go.sum
deleted file mode 100644
index 426c8973c0e..00000000000
--- a/vendor/github.com/mattn/go-isatty/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
diff --git a/vendor/github.com/mattn/go-isatty/isatty_android.go b/vendor/github.com/mattn/go-isatty/isatty_android.go
deleted file mode 100644
index d3567cb5bf2..00000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_android.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// +build android
-
-package isatty
-
-import (
- "syscall"
- "unsafe"
-)
-
-const ioctlReadTermios = syscall.TCGETS
-
-// IsTerminal return true if the file descriptor is terminal.
-func IsTerminal(fd uintptr) bool {
- var termios syscall.Termios
- _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
- return err == 0
-}
-
-// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go
deleted file mode 100644
index 07e93039dbe..00000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// +build darwin freebsd openbsd netbsd dragonfly
-// +build !appengine
-
-package isatty
-
-import (
- "syscall"
- "unsafe"
-)
-
-const ioctlReadTermios = syscall.TIOCGETA
-
-// IsTerminal return true if the file descriptor is terminal.
-func IsTerminal(fd uintptr) bool {
- var termios syscall.Termios
- _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
- return err == 0
-}
-
-// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go
deleted file mode 100644
index ff714a37615..00000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_others.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// +build appengine js nacl
-
-package isatty
-
-// IsTerminal returns true if the file descriptor is terminal which
-// is always false on js and appengine classic which is a sandboxed PaaS.
-func IsTerminal(fd uintptr) bool {
- return false
-}
-
-// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go
deleted file mode 100644
index bdd5c79a07f..00000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_solaris.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// +build solaris
-// +build !appengine
-
-package isatty
-
-import (
- "golang.org/x/sys/unix"
-)
-
-// IsTerminal returns true if the given file descriptor is a terminal.
-// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
-func IsTerminal(fd uintptr) bool {
- var termio unix.Termio
- err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
- return err == nil
-}
-
-// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go
deleted file mode 100644
index 453b025d0df..00000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// +build linux aix
-// +build !appengine
-// +build !android
-
-package isatty
-
-import "golang.org/x/sys/unix"
-
-// IsTerminal return true if the file descriptor is terminal.
-func IsTerminal(fd uintptr) bool {
- _, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
- return err == nil
-}
-
-// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go
deleted file mode 100644
index af51cbcaa48..00000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_windows.go
+++ /dev/null
@@ -1,94 +0,0 @@
-// +build windows
-// +build !appengine
-
-package isatty
-
-import (
- "strings"
- "syscall"
- "unicode/utf16"
- "unsafe"
-)
-
-const (
- fileNameInfo uintptr = 2
- fileTypePipe = 3
-)
-
-var (
- kernel32 = syscall.NewLazyDLL("kernel32.dll")
- procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
- procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
- procGetFileType = kernel32.NewProc("GetFileType")
-)
-
-func init() {
- // Check if GetFileInformationByHandleEx is available.
- if procGetFileInformationByHandleEx.Find() != nil {
- procGetFileInformationByHandleEx = nil
- }
-}
-
-// IsTerminal return true if the file descriptor is terminal.
-func IsTerminal(fd uintptr) bool {
- var st uint32
- r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
- return r != 0 && e == 0
-}
-
-// Check pipe name is used for cygwin/msys2 pty.
-// Cygwin/MSYS2 PTY has a name like:
-// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
-func isCygwinPipeName(name string) bool {
- token := strings.Split(name, "-")
- if len(token) < 5 {
- return false
- }
-
- if token[0] != `\msys` && token[0] != `\cygwin` {
- return false
- }
-
- if token[1] == "" {
- return false
- }
-
- if !strings.HasPrefix(token[2], "pty") {
- return false
- }
-
- if token[3] != `from` && token[3] != `to` {
- return false
- }
-
- if token[4] != "master" {
- return false
- }
-
- return true
-}
-
-// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
-// terminal.
-func IsCygwinTerminal(fd uintptr) bool {
- if procGetFileInformationByHandleEx == nil {
- return false
- }
-
- // Cygwin/msys's pty is a pipe.
- ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
- if ft != fileTypePipe || e != 0 {
- return false
- }
-
- var buf [2 + syscall.MAX_PATH]uint16
- r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
- 4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
- uintptr(len(buf)*2), 0, 0)
- if r == 0 || e != 0 {
- return false
- }
-
- l := *(*uint32)(unsafe.Pointer(&buf))
- return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
-}
diff --git a/vendor/github.com/mavricknz/asn1-ber/LICENSE b/vendor/github.com/mavricknz/asn1-ber/LICENSE
deleted file mode 100644
index 74487567632..00000000000
--- a/vendor/github.com/mavricknz/asn1-ber/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2012 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/mavricknz/asn1-ber/Makefile b/vendor/github.com/mavricknz/asn1-ber/Makefile
deleted file mode 100644
index 1e44d521ed9..00000000000
--- a/vendor/github.com/mavricknz/asn1-ber/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include $(GOROOT)/src/Make.inc
-
-TARG=github.com/hsoj/asn1-ber
-GOFILES=\
- ber.go\
-
-include $(GOROOT)/src/Make.pkg
diff --git a/vendor/github.com/mavricknz/asn1-ber/README b/vendor/github.com/mavricknz/asn1-ber/README
deleted file mode 100644
index bb785a06fcf..00000000000
--- a/vendor/github.com/mavricknz/asn1-ber/README
+++ /dev/null
@@ -1,14 +0,0 @@
-ASN1 BER Encoding / Decoding Library for the GO programming language.
-
-Required Librarys:
- None
-
-Working:
- Very basic encoding / decoding needed for LDAP protocol
-
-Tests Implemented:
- None
-
-TODO:
- Fix all encoding / decoding to conform to ASN1 BER spec
- Implement Tests / Benchmarks
diff --git a/vendor/github.com/mavricknz/asn1-ber/ber.go b/vendor/github.com/mavricknz/asn1-ber/ber.go
deleted file mode 100644
index 9ba309cc04e..00000000000
--- a/vendor/github.com/mavricknz/asn1-ber/ber.go
+++ /dev/null
@@ -1,440 +0,0 @@
-package ber
-
-import (
- "bytes"
- "fmt"
- "io"
- "reflect"
-)
-
-type Packet struct {
- ClassType uint8
- TagType uint8
- Tag uint8
- Value interface{}
- Data *bytes.Buffer
- Children []*Packet
- Description string
-}
-
-const (
- TagEOC = 0x00
- TagBoolean = 0x01
- TagInteger = 0x02
- TagBitString = 0x03
- TagOctetString = 0x04
- TagNULL = 0x05
- TagObjectIdentifier = 0x06
- TagObjectDescriptor = 0x07
- TagExternal = 0x08
- TagRealFloat = 0x09
- TagEnumerated = 0x0a
- TagEmbeddedPDV = 0x0b
- TagUTF8String = 0x0c
- TagRelativeOID = 0x0d
- TagSequence = 0x10
- TagSet = 0x11
- TagNumericString = 0x12
- TagPrintableString = 0x13
- TagT61String = 0x14
- TagVideotexString = 0x15
- TagIA5String = 0x16
- TagUTCTime = 0x17
- TagGeneralizedTime = 0x18
- TagGraphicString = 0x19
- TagVisibleString = 0x1a
- TagGeneralString = 0x1b
- TagUniversalString = 0x1c
- TagCharacterString = 0x1d
- TagBMPString = 0x1e
- TagBitmask = 0x1f // xxx11111b
-)
-
-var TagMap = map[uint8]string{
- TagEOC: "EOC (End-of-Content)",
- TagBoolean: "Boolean",
- TagInteger: "Integer",
- TagBitString: "Bit String",
- TagOctetString: "Octet String",
- TagNULL: "NULL",
- TagObjectIdentifier: "Object Identifier",
- TagObjectDescriptor: "Object Descriptor",
- TagExternal: "External",
- TagRealFloat: "Real (float)",
- TagEnumerated: "Enumerated",
- TagEmbeddedPDV: "Embedded PDV",
- TagUTF8String: "UTF8 String",
- TagRelativeOID: "Relative-OID",
- TagSequence: "Sequence and Sequence of",
- TagSet: "Set and Set OF",
- TagNumericString: "Numeric String",
- TagPrintableString: "Printable String",
- TagT61String: "T61 String",
- TagVideotexString: "Videotex String",
- TagIA5String: "IA5 String",
- TagUTCTime: "UTC Time",
- TagGeneralizedTime: "Generalized Time",
- TagGraphicString: "Graphic String",
- TagVisibleString: "Visible String",
- TagGeneralString: "General String",
- TagUniversalString: "Universal String",
- TagCharacterString: "Character String",
- TagBMPString: "BMP String",
-}
-
-const (
- ClassUniversal = 0 // 00xxxxxxb
- ClassApplication = 64 // 01xxxxxxb
- ClassContext = 128 // 10xxxxxxb
- ClassPrivate = 192 // 11xxxxxxb
- ClassBitmask = 192 // 11xxxxxxb
-)
-
-var ClassMap = map[uint8]string{
- ClassUniversal: "Universal",
- ClassApplication: "Application",
- ClassContext: "Context",
- ClassPrivate: "Private",
-}
-
-const (
- TypePrimative = 0 // xx0xxxxxb
- TypeConstructed = 32 // xx1xxxxxb
- TypeBitmask = 32 // xx1xxxxxb
-)
-
-var TypeMap = map[uint8]string{
- TypePrimative: "Primative",
- TypeConstructed: "Constructed",
-}
-
-var Debug bool = false
-
-func PrintBytes(buf []byte, indent string) {
- data_lines := make([]string, (len(buf)/30)+1)
- num_lines := make([]string, (len(buf)/30)+1)
-
- for i, b := range buf {
- data_lines[i/30] += fmt.Sprintf("%02x ", b)
- num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100)
- }
-
- for i := 0; i < len(data_lines); i++ {
- fmt.Print(indent + data_lines[i] + "\n")
- fmt.Print(indent + num_lines[i] + "\n\n")
- }
-}
-
-func PrintPacket(p *Packet) {
- printPacket(p, 0, false)
-}
-
-func printPacket(p *Packet, indent int, printBytes bool) {
- indent_str := ""
- for len(indent_str) != indent {
- indent_str += " "
- }
-
- class_str := ClassMap[p.ClassType]
- tagtype_str := TypeMap[p.TagType]
- tag_str := fmt.Sprintf("0x%02X", p.Tag)
-
- if p.ClassType == ClassUniversal {
- tag_str = TagMap[p.Tag]
- }
-
- value := fmt.Sprint(p.Value)
- description := ""
- if p.Description != "" {
- description = p.Description + ": "
- }
-
- fmt.Printf("%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value)
-
- if printBytes {
- PrintBytes(p.Bytes(), indent_str)
- }
-
- for _, child := range p.Children {
- printPacket(child, indent+1, printBytes)
- }
-}
-
-func resizeBuffer(in []byte, new_size uint64) (out []byte) {
- out = make([]byte, new_size)
- copy(out, in)
- return
-}
-
-func readBytes(reader io.Reader, buf []byte) error {
- idx := 0
- buflen := len(buf)
- for idx < buflen {
- n, err := reader.Read(buf[idx:])
- if err != nil {
- return err
- }
- idx += n
- }
- return nil
-}
-
-func ReadPacket(reader io.Reader) (*Packet, error) {
- buf := make([]byte, 2)
- err := readBytes(reader, buf)
- if err != nil {
- return nil, err
- }
- idx := uint64(2)
- datalen := uint64(buf[1])
- if Debug {
- fmt.Printf("Read: datalen = %d len(buf) = %d ", datalen, len(buf))
- for _, b := range buf {
- fmt.Printf("%02X ", b)
- }
- fmt.Printf("\n")
- }
- if datalen&128 != 0 {
- a := datalen - 128
- idx += a
- buf = resizeBuffer(buf, 2+a)
- err := readBytes(reader, buf[2:])
- if err != nil {
- return nil, err
- }
- datalen = DecodeInteger(buf[2 : 2+a])
- if Debug {
- fmt.Printf("Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len(buf))
- for _, b := range buf {
- fmt.Printf("%02X ", b)
- }
- fmt.Printf("\n")
- }
- }
-
- buf = resizeBuffer(buf, idx+datalen)
- err = readBytes(reader, buf[idx:])
- if err != nil {
- return nil, err
- }
-
- if Debug {
- fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len(buf), idx, datalen, idx+datalen)
- for _, b := range buf {
- fmt.Printf("%02X ", b)
- }
- }
-
- p := DecodePacket(buf)
- return p, nil
-}
-
-func DecodeString(data []byte) (ret string) {
- for _, c := range data {
- ret += fmt.Sprintf("%c", c)
- }
- return
-}
-
-func DecodeInteger(data []byte) (ret uint64) {
- for _, i := range data {
- ret = ret * 256
- ret = ret + uint64(i)
- }
- return
-}
-
-func EncodeInteger(val uint64) []byte {
- var out bytes.Buffer
- found := false
- shift := uint(56)
- mask := uint64(0xFF00000000000000)
- for mask > 0 {
- if !found && (val&mask != 0) {
- found = true
- }
- if found || (shift == 0) {
- out.Write([]byte{byte((val & mask) >> shift)})
- }
- shift -= 8
- mask = mask >> 8
- }
- return out.Bytes()
-}
-
-func DecodePacket(data []byte) *Packet {
- p, _ := decodePacket(data)
- return p
-}
-
-func decodePacket(data []byte) (*Packet, []byte) {
- if Debug {
- fmt.Printf("decodePacket: enter %d\n", len(data))
- }
- p := new(Packet)
- p.ClassType = data[0] & ClassBitmask
- p.TagType = data[0] & TypeBitmask
- p.Tag = data[0] & TagBitmask
-
- datalen := DecodeInteger(data[1:2])
- datapos := uint64(2)
- if datalen&128 != 0 {
- datalen -= 128
- datapos += datalen
- datalen = DecodeInteger(data[2 : 2+datalen])
- }
-
- p.Data = new(bytes.Buffer)
- p.Children = make([]*Packet, 0, 2)
- p.Value = nil
-
- value_data := data[datapos : datapos+datalen]
-
- if p.TagType == TypeConstructed {
- for len(value_data) != 0 {
- var child *Packet
- child, value_data = decodePacket(value_data)
- p.AppendChild(child)
- }
- } else if p.ClassType == ClassUniversal {
- p.Data.Write(data[datapos : datapos+datalen])
- switch p.Tag {
- case TagEOC:
- case TagBoolean:
- val := DecodeInteger(value_data)
- p.Value = val != 0
- case TagInteger:
- p.Value = DecodeInteger(value_data)
- case TagBitString:
- case TagOctetString:
- p.Value = value_data
- case TagNULL:
- case TagObjectIdentifier:
- case TagObjectDescriptor:
- case TagExternal:
- case TagRealFloat:
- case TagEnumerated:
- p.Value = DecodeInteger(value_data)
- case TagEmbeddedPDV:
- case TagUTF8String:
- case TagRelativeOID:
- case TagSequence:
- case TagSet:
- case TagNumericString:
- case TagPrintableString:
- p.Value = DecodeString(value_data)
- case TagT61String:
- case TagVideotexString:
- case TagIA5String:
- case TagUTCTime:
- case TagGeneralizedTime:
- case TagGraphicString:
- case TagVisibleString:
- case TagGeneralString:
- case TagUniversalString:
- case TagCharacterString:
- case TagBMPString:
- }
- } else {
- p.Data.Write(data[datapos : datapos+datalen])
- }
-
- return p, data[datapos+datalen:]
-}
-
-func (p *Packet) DataLength() uint64 {
- return uint64(p.Data.Len())
-}
-
-func (p *Packet) Bytes() []byte {
- var out bytes.Buffer
- out.Write([]byte{p.ClassType | p.TagType | p.Tag})
- packet_length := EncodeInteger(p.DataLength())
- if p.DataLength() > 127 || len(packet_length) > 1 {
- out.Write([]byte{byte(len(packet_length) | 128)})
- out.Write(packet_length)
- } else {
- out.Write(packet_length)
- }
- out.Write(p.Data.Bytes())
- return out.Bytes()
-}
-
-func (p *Packet) AppendChild(child *Packet) {
- p.Data.Write(child.Bytes())
- if len(p.Children) == cap(p.Children) {
- newChildren := make([]*Packet, cap(p.Children)*2)
- copy(newChildren, p.Children)
- p.Children = newChildren[0:len(p.Children)]
- }
- p.Children = p.Children[0 : len(p.Children)+1]
- p.Children[len(p.Children)-1] = child
-}
-
-func Encode(ClassType, TagType, Tag uint8, Value interface{}, Description string) *Packet {
- p := new(Packet)
- p.ClassType = ClassType
- p.TagType = TagType
- p.Tag = Tag
- p.Data = new(bytes.Buffer)
- p.Children = make([]*Packet, 0, 2)
- p.Value = Value
- p.Description = Description
-
- if Value != nil {
- v := reflect.ValueOf(Value)
-
- if ClassType == ClassUniversal {
- switch Tag {
- case TagOctetString:
- sv, ok := v.Interface().(string)
- if ok {
- p.Data.Write([]byte(sv))
- }
- }
- }
- }
-
- return p
-}
-
-func NewSequence(Description string) *Packet {
- return Encode(ClassUniversal, TypePrimative, TagSequence, nil, Description)
-}
-
-func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet {
- intValue := 0
- if Value {
- // an older LDAP server expects 0xFF
- intValue = 0xFF
- }
-
- p := Encode(ClassType, TagType, Tag, nil, Description)
- p.Value = Value
- p.Data.Write(EncodeInteger(uint64(intValue)))
- return p
-}
-
-func NewInteger(ClassType, TagType, Tag uint8, Value uint64, Description string) *Packet {
- p := Encode(ClassType, TagType, Tag, nil, Description)
- p.Value = Value
- p.Data.Write(EncodeInteger(Value))
- return p
-}
-
-func NewString(ClassType, TagType, Tag uint8, Value, Description string) *Packet {
- p := Encode(ClassType, TagType, Tag, nil, Description)
- p.Value = Value
- p.Data.Write([]byte(Value))
- return p
-}
-
-
-func (p *Packet) ValueString() string {
- if str, ok := p.Value.(string); ok {
- return str
- } else if bytes, ok := p.Value.([]byte); ok {
- return string(bytes)
- }
- return ""
-}
diff --git a/vendor/github.com/mavricknz/ldap/LICENCE b/vendor/github.com/mavricknz/ldap/LICENCE
deleted file mode 100644
index 0f2498b1939..00000000000
--- a/vendor/github.com/mavricknz/ldap/LICENCE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2012 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/vendor/github.com/mavricknz/ldap/Makefile b/vendor/github.com/mavricknz/ldap/Makefile
deleted file mode 100644
index ec5ffe7e889..00000000000
--- a/vendor/github.com/mavricknz/ldap/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include $(GOROOT)/src/Make.inc
-
-TARG=github.com/hsoj/ldap
-GOFILES=\
- bind.go\
- conn.go\
- control.go\
- filter.go\
- ldap.go\
- search.go\
-
-include $(GOROOT)/src/Make.pkg
diff --git a/vendor/github.com/mavricknz/ldap/README b/vendor/github.com/mavricknz/ldap/README
deleted file mode 100644
index 68c8c1de08c..00000000000
--- a/vendor/github.com/mavricknz/ldap/README
+++ /dev/null
@@ -1,38 +0,0 @@
-Basic LDAP v3 functionality for the GO programming language.
-
-Most features are used in the test files. ldaplocal_test.go tests
-most new features.
-
-Required Librarys:
- github.com/mavricknz/asn1-ber
-
-Working:
- Connecting to LDAP server
- Binding to LDAP server
- Searching for entries
- Compiling string filters to LDAP filters
- Paging Search Results
- Mulitple internal goroutines to handle network traffic
- Makes library goroutine safe
- Can perform multiple search requests at the same time and return
- the results to the proper goroutine. All requests are blocking
- requests, so the goroutine does not need special handling
- Request Controls - MatchedValuesRequest, PermissiveModifyRequest,
- ManageDsaITRequest, SubtreeDeleteRequest, Paging, ServerSideSort
-
-Tests Implemented:
- Filter Compile / Decompile
- Local OpenDJ Tests for most Operations
-
-Experimental:
- LDIF Reader - LDIF entries only (~16k entries/sec)
- Some limited documentation
-
-TODO:
- LDIF Reader - mods/adds/deletes/...
- Test to not depend on initial Directory setup
- Do something with binary attributes.
- FilterExtensibleMatch Decode
- Modify DN Requests / Responses
- Implement Tests / Benchmarks
- Timeouts (connect Go 1.1?), Timeout Operations.
\ No newline at end of file
diff --git a/vendor/github.com/mavricknz/ldap/abandon.go b/vendor/github.com/mavricknz/ldap/abandon.go
deleted file mode 100644
index a7d3d59d15c..00000000000
--- a/vendor/github.com/mavricknz/ldap/abandon.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ldap
-
-import (
- "fmt"
- "github.com/mavricknz/asn1-ber"
-)
-
-// Will return an error. Normally due to closed connection.
-func (l *LDAPConnection) Abandon(abandonMessageID uint64) error {
- messageID, ok := l.nextMessageID()
- if !ok {
- return NewLDAPError(ErrorClosing, "MessageID channel is closed.")
- }
-
- encodedAbandon := ber.NewInteger(ber.ClassApplication, ber.TypePrimative, ApplicationAbandonRequest, abandonMessageID, ApplicationMap[ApplicationAbandonRequest])
-
- packet, err := requestBuildPacket(messageID, encodedAbandon, nil)
- if err != nil {
- return err
- }
-
- if l.Debug {
- ber.PrintPacket(packet)
- }
-
- channel, err := l.sendMessage(packet)
-
- if err != nil {
- return err
- }
-
- if channel == nil {
- return NewLDAPError(ErrorNetwork, "Could not send message")
- }
-
- defer l.finishMessage(messageID)
- if l.Debug {
- fmt.Printf("%d: NOT waiting Abandon for response\n", messageID)
- }
-
- // success
- return nil
-}
diff --git a/vendor/github.com/mavricknz/ldap/add.go b/vendor/github.com/mavricknz/ldap/add.go
deleted file mode 100644
index 96f03166d18..00000000000
--- a/vendor/github.com/mavricknz/ldap/add.go
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ldap
-
-import (
- "fmt"
- "github.com/mavricknz/asn1-ber"
-)
-
-type AddRequest struct {
- Entry *Entry
- Controls []Control
-}
-
-func (req *AddRequest) RecordType() uint8 {
- return AddRecord
-}
-
-func (l *LDAPConnection) Add(req *AddRequest) error {
- messageID, ok := l.nextMessageID()
- if !ok {
- return NewLDAPError(ErrorClosing, "messageID channel is closed.")
- }
-
- encodedAdd, err := encodeAddRequest(req)
- if err != nil {
- return err
- }
-
- packet, err := requestBuildPacket(messageID, encodedAdd, req.Controls)
- if err != nil {
- return err
- }
-
- return l.sendReqRespPacket(messageID, packet)
-}
-
-/*
- AddRequest ::= [APPLICATION 8] SEQUENCE {
- entry LDAPDN,
- attributes AttributeList }
-
- AttributeList ::= SEQUENCE OF attribute Attribute
-
- Attribute ::= SEQUENCE {
- type AttributeDescription,
- vals SET OF value AttributeValue } // vals is not empty
-*/
-func encodeAddRequest(addReq *AddRequest) (*ber.Packet, error) {
- addPacket := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, ApplicationMap[ApplicationAddRequest])
- addPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, addReq.Entry.DN, "LDAP DN"))
-
- attributeList := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeList")
-
- for _, attr := range addReq.Entry.Attributes {
- attribute := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attribute")
- attribute.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, attr.Name, "Attribute Desc"))
- if len(attr.Values) == 0 {
- return nil, NewLDAPError(ErrorEncoding, "attribute "+attr.Name+" had no values.")
- }
- valuesSet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "Attribute Value Set")
- for _, val := range attr.Values {
- valuesSet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, val, "AttributeValue"))
- }
- attribute.AppendChild(valuesSet)
- attributeList.AppendChild(attribute)
- }
- addPacket.AppendChild(attributeList)
- return addPacket, nil
-}
-
-func (req *AddRequest) Bytes() []byte {
- encoded, _ := encodeAddRequest(req)
- return encoded.Bytes()
-}
-
-func NewAddRequest(dn string) (req *AddRequest) {
- req = &AddRequest{Entry: NewEntry(dn), Controls: make([]Control, 0)}
- return
-}
-
-func (req *AddRequest) AddAttribute(attr *EntryAttribute) {
- req.Entry.AddAttributeValues(attr.Name, attr.Values)
-}
-
-func (req *AddRequest) AddAttributes(attrs []EntryAttribute) {
- for _, attr := range attrs {
- req.Entry.AddAttributeValues(attr.Name, attr.Values)
- }
-}
-
-// DumpAddRequest - Basic LDIF "like" dump for testing, no formating, etc
-func (addReq *AddRequest) String() (dump string) {
- dump = fmt.Sprintf("dn: %s\n", addReq.Entry.DN)
- for _, attr := range addReq.Entry.Attributes {
- for _, val := range attr.Values {
- dump += fmt.Sprintf("%s: %s\n", attr.Name, val)
- }
- }
- dump += fmt.Sprintf("\n")
- return
-}
-
-func (req *AddRequest) AddControl(control Control) {
- if req.Controls == nil {
- req.Controls = make([]Control, 0)
- }
- req.Controls = append(req.Controls, control)
-}
diff --git a/vendor/github.com/mavricknz/ldap/bind.go b/vendor/github.com/mavricknz/ldap/bind.go
deleted file mode 100644
index beae4e015ed..00000000000
--- a/vendor/github.com/mavricknz/ldap/bind.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// File contains Bind functionality
-package ldap
-
-import (
- "github.com/mavricknz/asn1-ber"
-)
-
-/*
-Simple bind to the server. If using a timeout you should close the connection
-on a bind failure.
-*/
-func (l *LDAPConnection) Bind(username, password string) error {
- messageID, ok := l.nextMessageID()
- if !ok {
- return NewLDAPError(ErrorClosing, "MessageID channel is closed.")
- }
-
- encodedBind := encodeSimpleBindRequest(username, password)
-
- packet, err := requestBuildPacket(messageID, encodedBind, nil)
- if err != nil {
- return err
- }
-
- return l.sendReqRespPacket(messageID, packet)
-
-}
-
-func encodeSimpleBindRequest(username, password string) (bindRequest *ber.Packet) {
- bindRequest = ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
- bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, 3, "Version"))
- bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, username, "User Name"))
- bindRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimative, 0, password, "Password"))
- return
-}
diff --git a/vendor/github.com/mavricknz/ldap/compare.go b/vendor/github.com/mavricknz/ldap/compare.go
deleted file mode 100644
index 4699ea036e9..00000000000
--- a/vendor/github.com/mavricknz/ldap/compare.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ldap
-
-import (
- "github.com/mavricknz/asn1-ber"
-)
-
-/*
-CompareRequest ::= [APPLICATION 14] SEQUENCE {
- entry LDAPDN,
- ava AttributeValueAssertion }
-
-AttributeValueAssertion ::= SEQUENCE {
- attributeDesc AttributeDescription,
- assertionValue AssertionValue }
-*/
-
-type CompareRequest struct {
- DN string
- Name string
- Value string
- Controls []Control
-}
-
-func (l *LDAPConnection) Compare(req *CompareRequest) (bool, error) {
- messageID, ok := l.nextMessageID()
- if !ok {
- return false, NewLDAPError(ErrorClosing, "MessageID channel is closed.")
- }
-
- encodedCompare, err := encodeCompareRequest(req)
- if err != nil {
- return false, err
- }
-
- packet, err := requestBuildPacket(messageID, encodedCompare, req.Controls)
- if err != nil {
- return false, err
- }
-
- // CompareTrue = 6, CompareFalse = 5
- // returns an "Error"
- err = l.sendReqRespPacket(messageID, packet)
- if lerr, ok := err.(*LDAPError); ok {
- return lerr.ResultCode == LDAPResultCompareTrue, nil
- } else {
- return false, err
- }
- //return l.sendReqRespPacket(messageID, packet)
-}
-
-func encodeCompareRequest(req *CompareRequest) (*ber.Packet, error) {
- p := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationCompareRequest, nil, ApplicationMap[ApplicationCompareRequest])
- p.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, req.DN, "LDAP DN"))
- ava, err := encodeItem([]string{req.Name, "=", req.Value})
- if err != nil {
- return nil, err
- }
- p.AppendChild(ava)
- return p, nil
-}
-
-func NewCompareRequest(dn, name, value string) (req *CompareRequest) {
- req = &CompareRequest{DN: dn, Name: name, Value: value, Controls: make([]Control, 0)}
- return
-}
diff --git a/vendor/github.com/mavricknz/ldap/conn.go b/vendor/github.com/mavricknz/ldap/conn.go
deleted file mode 100644
index 85ac80b2c9d..00000000000
--- a/vendor/github.com/mavricknz/ldap/conn.go
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This package provides LDAP client functions.
-package ldap
-
-import (
- "crypto/tls"
- "fmt"
- "github.com/mavricknz/asn1-ber"
- "net"
- "os"
- "sync"
- "time"
-)
-
-// An interface for a network dialing method compatible with net.Dial()
-type Dialable interface {
- Dial(string, string) (net.Conn, error)
-}
-
-// An interface for a network dialing method compatible with net.DialTimeout()
-type TimedDialable interface {
- DialTimeout(string, string, time.Duration) (net.Conn, error)
-}
-
-// Converts a net.Dial() compatible function to Dialable
-type Dialer func(string, string) (net.Conn, error)
-
-// Converts a net.DialTimeout() compatible function to TimedDialable
-type TimedDialer func(string, string, time.Duration) (net.Conn, error)
-
-func (fn Dialer) Dial(n, a string) (net.Conn, error) {
- return fn(n, a)
-}
-
-func (fn TimedDialer) Dial(n, a string) (net.Conn, error) {
- return fn(n, a, 0)
-}
-
-func (fn TimedDialer) DialTimeout(n, a string, t time.Duration) (net.Conn, error) {
- return fn(n, a, t)
-}
-
-// Conn - LDAP Connection and also pre/post connect configuation
-// IsTLS bool // default false
-// IsSSL bool // default false
-// Debug bool // default false
-// NetworkConnectTimeout time.Duration // default 0 no timeout
-// ReadTimeout time.Duration // default 0 no timeout
-// AbandonMessageOnReadTimeout bool // send abandon on a ReadTimeout (not for searches yet)
-// Addr string // default empty
-// Dialer Dialable // default nil, optional network dialer to use (net.Dial()/net.DialTimeout() by default)
-//
-// A minimal connection...
-// ldap := NewLDAPConnection("localhost",389)
-// err := ldap.Connect() // Connects the existing connection, or returns an error
-type LDAPConnection struct {
- IsTLS bool
- IsSSL bool
- Debug bool
-
- Addr string
- NetworkConnectTimeout time.Duration
- ReadTimeout time.Duration
- AbandonMessageOnReadTimeout bool
-
- TlsConfig *tls.Config
-
- Dialer Dialable
-
- conn net.Conn
- chanResults map[uint64]chan *ber.Packet
- lockChanResults sync.RWMutex
- chanProcessMessage chan *messagePacket
- closeLock sync.RWMutex
- chanMessageID chan uint64
- connected bool
-}
-
-// Connect connects using information in LDAPConnection.
-// LDAPConnection should be populated with connection information.
-func (l *LDAPConnection) Connect() error {
- l.chanResults = map[uint64]chan *ber.Packet{}
- l.chanProcessMessage = make(chan *messagePacket)
- l.chanMessageID = make(chan uint64)
-
- if l.conn == nil {
- var c net.Conn
- var err error
-
- if l.Dialer == nil {
- if l.NetworkConnectTimeout > 0 {
- l.Dialer = TimedDialer(net.DialTimeout)
- } else {
- l.Dialer = Dialer(net.Dial)
- }
- }
-
- switch dialer := l.Dialer.(type) {
- case TimedDialable:
- c, err = dialer.DialTimeout("tcp", l.Addr, l.NetworkConnectTimeout)
- case Dialable:
- c, err = dialer.Dial("tcp", l.Addr)
- }
-
- if err != nil {
- return err
- }
-
- if l.IsSSL {
- tlsConn := tls.Client(c, l.TlsConfig)
- err = tlsConn.Handshake()
- if err != nil {
- return err
- }
- l.conn = tlsConn
- } else {
- l.conn = c
- }
- }
- l.start()
- l.connected = true
- if l.IsTLS {
- err := l.startTLS()
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-// NewConn returns a new basic connection. Should start connection via
-// Connect
-func NewLDAPConnection(server string, port uint16) *LDAPConnection {
- return &LDAPConnection{
- Addr: fmt.Sprintf("%s:%d", server, port),
- }
-}
-
-func NewLDAPTLSConnection(server string, port uint16, tlsConfig *tls.Config) *LDAPConnection {
- return &LDAPConnection{
- Addr: fmt.Sprintf("%s:%d", server, port),
- IsTLS: true,
- TlsConfig: tlsConfig,
- }
-}
-
-func NewLDAPSSLConnection(server string, port uint16, tlsConfig *tls.Config) *LDAPConnection {
- return &LDAPConnection{
- Addr: fmt.Sprintf("%s:%d", server, port),
- IsSSL: true,
- TlsConfig: tlsConfig,
- }
-}
-
-func (l *LDAPConnection) start() {
- go l.reader()
- go l.processMessages()
-}
-
-// Close closes the connection.
-func (l *LDAPConnection) Close() error {
- if l.Debug {
- fmt.Println("Starting Close().")
- }
- l.sendProcessMessage(&messagePacket{Op: MessageQuit})
- return nil
-}
-
-// Returns the next available messageID
-func (l *LDAPConnection) nextMessageID() (messageID uint64, ok bool) {
- messageID, ok = <-l.chanMessageID
- if l.Debug {
- fmt.Printf("MessageID: %d, ok: %v\n", messageID, ok)
- }
- return
-}
-
-// StartTLS sends the command to start a TLS session and then creates a new TLS Client
-func (l *LDAPConnection) startTLS() error {
- messageID, ok := l.nextMessageID()
- if !ok {
- return NewLDAPError(ErrorClosing, "MessageID channel is closed.")
- }
-
- if l.IsSSL {
- return NewLDAPError(ErrorNetwork, "Already encrypted")
- }
-
- tlsRequest := encodeTLSRequest()
- packet, err := requestBuildPacket(messageID, tlsRequest, nil)
-
- if err != nil {
- return err
- }
-
- err = l.sendReqRespPacket(messageID, packet)
- if err != nil {
- return err
- }
-
- conn := tls.Client(l.conn, l.TlsConfig)
- err = conn.Handshake()
- if err != nil {
- return err
- }
- l.IsSSL = true
- l.conn = conn
-
- return nil
-}
-
-func encodeTLSRequest() (tlsRequest *ber.Packet) {
- tlsRequest = ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS")
- tlsRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimative, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command"))
- return
-}
-
-const (
- MessageQuit = 0
- MessageRequest = 1
- MessageResponse = 2
- MessageFinish = 3
-)
-
-type messagePacket struct {
- Op int
- MessageID uint64
- Packet *ber.Packet
- Channel chan *ber.Packet
-}
-
-func (l *LDAPConnection) getNewResultChannel(message_id uint64) (out chan *ber.Packet, err error) {
- // as soon as a channel is requested add to chanResults to never miss
- // on cleanup.
- l.lockChanResults.Lock()
- defer l.lockChanResults.Unlock()
-
- if l.chanResults == nil {
- return nil, NewLDAPError(ErrorClosing, "Connection closing/closed")
- }
-
- if _, ok := l.chanResults[message_id]; ok {
- errStr := fmt.Sprintf("chanResults already allocated, message_id: %d", message_id)
- return nil, NewLDAPError(ErrorUnknown, errStr)
- }
-
- out = make(chan *ber.Packet, ResultChanBufferSize)
- l.chanResults[message_id] = out
- return
-}
-
-func (l *LDAPConnection) sendMessage(p *ber.Packet) (out chan *ber.Packet, err error) {
- message_id := p.Children[0].Value.(uint64)
- // sendProcessMessage may not process a message on shutdown
- // getNewResultChannel adds id/chan to chan results
- out, err = l.getNewResultChannel(message_id)
- if err != nil {
- return
- }
- if l.Debug {
- fmt.Printf("sendMessage-> message_id: %d, out: %v\n", message_id, out)
- }
-
- message_packet := &messagePacket{Op: MessageRequest, MessageID: message_id, Packet: p, Channel: out}
- l.sendProcessMessage(message_packet)
- return
-}
-
-func (l *LDAPConnection) processMessages() {
- defer l.closeAllChannels()
- defer func() {
- // Close all channels, connection and quit.
- // Use closeLock to stop MessageRequests
- // and l.connected to stop any future MessageRequests.
- l.closeLock.Lock()
- defer l.closeLock.Unlock()
- l.connected = false
- // will shutdown reader.
- l.conn.Close()
- }()
- var message_id uint64 = 1
- var message_packet *messagePacket
-
- for {
- select {
- case l.chanMessageID <- message_id:
- message_id++
- case message_packet = <-l.chanProcessMessage:
- switch message_packet.Op {
- case MessageQuit:
- if l.Debug {
- fmt.Printf("Shutting down\n")
- }
- return
- case MessageRequest:
- // Add to message list and write to network
- if l.Debug {
- fmt.Printf("Sending message %d\n", message_packet.MessageID)
- }
- buf := message_packet.Packet.Bytes()
- for len(buf) > 0 {
- n, err := l.conn.Write(buf)
- if err != nil {
- if l.Debug {
- fmt.Printf("Error Sending Message: %s\n", err)
- }
- return
- }
- if n == len(buf) {
- break
- }
- buf = buf[n:]
- }
- case MessageFinish:
- // Remove from message list
- if l.Debug {
- fmt.Printf("Finished message %d\n", message_packet.MessageID)
- }
- l.lockChanResults.Lock()
- delete(l.chanResults, message_packet.MessageID)
- l.lockChanResults.Unlock()
- }
- }
- }
-}
-
-func (l *LDAPConnection) closeAllChannels() {
- l.lockChanResults.Lock()
- defer l.lockChanResults.Unlock()
- for MessageID, Channel := range l.chanResults {
- if l.Debug {
- fmt.Printf("Closing channel for MessageID %d\n", MessageID)
- }
- close(Channel)
- delete(l.chanResults, MessageID)
- }
- l.chanResults = nil
-
- close(l.chanMessageID)
- l.chanMessageID = nil
-
- close(l.chanProcessMessage)
- l.chanProcessMessage = nil
-}
-
-func (l *LDAPConnection) finishMessage(MessageID uint64) {
- message_packet := &messagePacket{Op: MessageFinish, MessageID: MessageID}
- l.sendProcessMessage(message_packet)
-}
-
-func (l *LDAPConnection) reader() {
- defer l.Close()
- for {
- p, err := ber.ReadPacket(l.conn)
- if err != nil {
- if l.Debug {
- fmt.Printf("ldap.reader: %s\n", err)
- }
- return
- }
-
- addLDAPDescriptions(p)
-
- message_id := p.Children[0].Value.(uint64)
- message_packet := &messagePacket{Op: MessageResponse, MessageID: message_id, Packet: p}
-
- l.readerToChanResults(message_packet)
- }
-}
-
-func (l *LDAPConnection) readerToChanResults(message_packet *messagePacket) {
- defer func() {
- if r := recover(); r != nil {
- fmt.Fprintln(os.Stderr, "Recovered in readerToChanResults", r)
- }
- }()
- if l.Debug {
- fmt.Printf("Receiving message %d\n", message_packet.MessageID)
- }
-
- // very small chance on disconnect to write to a closed channel as
- // lockChanResults is unlocked immediately hence defer above.
- // Don't lock while sending to chanResult below as that can block and hold
- // the lock.
- l.lockChanResults.RLock()
- chanResult, ok := l.chanResults[message_packet.MessageID]
- l.lockChanResults.RUnlock()
-
- if !ok {
- if l.Debug {
- fmt.Printf("Message Result chan not found (possible Abandon), MessageID: %d\n", message_packet.MessageID)
- }
- } else {
- // chanResult is a buffered channel of ResultChanBufferSize
- chanResult <- message_packet.Packet
- }
-}
-
-func (l *LDAPConnection) sendProcessMessage(message *messagePacket) {
- go func() {
- // multiple senders can queue on l.chanProcessMessage
- // but block on shutdown.
- l.closeLock.RLock()
- defer l.closeLock.RUnlock()
- if l.connected {
- l.chanProcessMessage <- message
- }
- }()
-}
diff --git a/vendor/github.com/mavricknz/ldap/control.go b/vendor/github.com/mavricknz/ldap/control.go
deleted file mode 100644
index bc082651afa..00000000000
--- a/vendor/github.com/mavricknz/ldap/control.go
+++ /dev/null
@@ -1,689 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This package provides LDAP client functions.
-package ldap
-
-import (
- "fmt"
- "github.com/mavricknz/asn1-ber"
-)
-
-const (
- ControlTypeMatchedValuesRequest = "1.2.826.0.1.3344810.2.3"
- ControlTypePermissiveModifyRequest = "1.2.840.113556.1.4.1413"
- ControlTypePaging = "1.2.840.113556.1.4.319"
- ControlTypeManageDsaITRequest = "2.16.840.1.113730.3.4.2"
- ControlTypeSubtreeDeleteRequest = "1.2.840.113556.1.4.805"
- ControlTypeNoOpRequest = "1.3.6.1.4.1.4203.1.10.2"
- ControlTypeServerSideSortRequest = "1.2.840.113556.1.4.473"
- ControlTypeServerSideSortResponse = "1.2.840.113556.1.4.474"
- ControlTypeVlvRequest = "2.16.840.1.113730.3.4.9"
- ControlTypeVlvResponse = "2.16.840.1.113730.3.4.10"
-
-//1.2.840.113556.1.4.473
-//1.3.6.1.1.12
-//1.3.6.1.1.13.1
-//1.3.6.1.1.13.2
-//1.3.6.1.4.1.26027.1.5.2
-//1.3.6.1.4.1.42.2.27.8.5.1
-//1.3.6.1.4.1.42.2.27.9.5.2
-//1.3.6.1.4.1.42.2.27.9.5.8
-//1.3.6.1.4.1.4203.1.10.1
-//1.3.6.1.4.1.7628.5.101.1
-//2.16.840.1.113730.3.4.12
-//2.16.840.1.113730.3.4.16
-//2.16.840.1.113730.3.4.17
-//2.16.840.1.113730.3.4.18
-//2.16.840.1.113730.3.4.19
-//2.16.840.1.113730.3.4.3
-//2.16.840.1.113730.3.4.4
-//2.16.840.1.113730.3.4.5
-//
-)
-
-var ControlTypeMap = map[string]string{
- ControlTypeMatchedValuesRequest: "MatchedValuesRequest",
- ControlTypePermissiveModifyRequest: "PermissiveModifyRequest",
- ControlTypePaging: "Paging",
- ControlTypeManageDsaITRequest: "ManageDsaITRequest",
- ControlTypeSubtreeDeleteRequest: "SubtreeDeleteRequest",
- ControlTypeNoOpRequest: "NoOpRequest",
- ControlTypeServerSideSortRequest: "ServerSideSortRequest",
- ControlTypeServerSideSortResponse: "ServerSideSortResponse",
- ControlTypeVlvRequest: "VlvRequest",
- ControlTypeVlvResponse: "VlvResponse",
-}
-
-var ControlDecodeMap = map[string]func(p *ber.Packet) (Control, error){
- ControlTypeServerSideSortResponse: NewControlServerSideSortResponse,
- ControlTypePaging: NewControlPagingFromPacket,
- ControlTypeVlvResponse: NewControlVlvResponse,
-}
-
-// Control Interface
-type Control interface {
- Encode() (*ber.Packet, error)
- GetControlType() string
- String() string
-}
-
-type ControlString struct {
- ControlType string
- Criticality bool
- ControlValue string
-}
-
-func NewControlStringFromPacket(p *ber.Packet) (Control, error) {
- controlType, criticality, value := decodeControlTypeAndCrit(p)
- c := new(ControlString)
- c.ControlType = controlType
- c.Criticality = criticality
- c.ControlValue = value.ValueString()
- return c, nil
-}
-
-func (c *ControlString) GetControlType() string {
- return c.ControlType
-}
-
-func (c *ControlString) Encode() (p *ber.Packet, err error) {
- p = ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
- p.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")"))
- if c.Criticality {
- p.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimative, ber.TagBoolean, c.Criticality, "Criticality"))
- }
- if len(c.ControlValue) != 0 {
- p.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, c.ControlValue, "Control Value"))
- }
- return p, nil
-}
-
-func (c *ControlString) String() string {
- return fmt.Sprintf("Control Type: %s (%q) Criticality: %t Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue)
-}
-
-type ControlPaging struct {
- PagingSize uint32
- Cookie []byte
-}
-
-func NewControlPaging(PagingSize uint32) *ControlPaging {
- return &ControlPaging{PagingSize: PagingSize}
-}
-
-func NewControlPagingFromPacket(p *ber.Packet) (Control, error) {
- _, _, value := decodeControlTypeAndCrit(p)
- value.Description += " (Paging)"
- c := new(ControlPaging)
-
- if value.Value != nil {
- value_children := ber.DecodePacket(value.Data.Bytes())
- value.Data.Truncate(0)
- value.Value = nil
- value.AppendChild(value_children)
- }
- value = value.Children[0]
- value.Description = "Search Control Value"
- value.Children[0].Description = "Paging Size"
- value.Children[1].Description = "Cookie"
- c.PagingSize = uint32(value.Children[0].Value.(uint64))
- c.Cookie = value.Children[1].Data.Bytes()
- value.Children[1].Value = c.Cookie
- return c, nil
-}
-
-func (c *ControlPaging) GetControlType() string {
- return ControlTypePaging
-}
-
-func (c *ControlPaging) Encode() (p *ber.Packet, err error) {
- p = ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
- p.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")"))
-
- p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, nil, "Control Value (Paging)")
- seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value")
- seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, uint64(c.PagingSize), "Paging Size"))
- cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, nil, "Cookie")
- cookie.Value = c.Cookie
- cookie.Data.Write(c.Cookie)
- seq.AppendChild(cookie)
- p2.AppendChild(seq)
-
- p.AppendChild(p2)
- return p, nil
-}
-
-func (c *ControlPaging) String() string {
- return fmt.Sprintf(
- "Control Type: %s (%q) Criticality: %t PagingSize: %d Cookie: %q",
- ControlTypeMap[ControlTypePaging],
- ControlTypePaging,
- false,
- c.PagingSize,
- c.Cookie)
-}
-
-func (c *ControlPaging) SetCookie(Cookie []byte) {
- c.Cookie = Cookie
-}
-
-func FindControl(controls []Control, controlType string) (position int, control Control) {
- for pos, c := range controls {
- if c.GetControlType() == controlType {
- return pos, c
- }
- }
- return -1, nil
-}
-
-func ReplaceControl(controls []Control, control Control) (oldControl Control) {
- ControlType := control.GetControlType()
- pos, c := FindControl(controls, ControlType)
- if c != nil {
- controls[pos] = control
- return c
- }
- controls = append(controls, control)
- return control
-}
-
-///*
-//Control ::= SEQUENCE {
-// controlType LDAPOID,
-// criticality BOOLEAN DEFAULT FALSE,
-// controlValue OCTET STRING OPTIONAL }
-//*/
-//// DecodeControl - Decode Response controls.
-//func DecodeControl(p *ber.Packet) Control {
-// controlType, criticality, value := decodeControlTypeAndCrit(p)
-
-// /* Special cases */
-// switch controlType {
-// case ControlTypePaging:
-// value.Description += " (Paging)"
-// c := new(ControlPaging)
-// if value.Value != nil {
-// value_children := ber.DecodePacket(value.Data.Bytes())
-// value.Data.Truncate(0)
-// value.Value = nil
-// value.AppendChild(value_children)
-// }
-// value = value.Children[0]
-// value.Description = "Search Control Value"
-// value.Children[0].Description = "Paging Size"
-// value.Children[1].Description = "Cookie"
-// c.PagingSize = uint32(value.Children[0].Value.(uint64))
-// c.Cookie = value.Children[1].Data.Bytes()
-// value.Children[1].Value = c.Cookie
-// return c
-// }
-// c := new(ControlString)
-// c.ControlType = controlType
-// c.Criticality = criticality
-// c.ControlValue = value.ValueString()
-// return c
-//}
-
-func decodeControlTypeAndCrit(p *ber.Packet) (controlType string, criticality bool, value *ber.Packet) {
- controlType = p.Children[0].ValueString()
- p.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")"
- criticality = false
- if len(p.Children) == 3 {
- criticality = p.Children[1].Value.(bool)
- p.Children[1].Description = "Criticality"
- value = p.Children[2]
- } else {
- value = p.Children[1]
- }
- value.Description = "Control Value"
- return
-}
-
-func NewControlString(ControlType string, Criticality bool, ControlValue string) *ControlString {
- return &ControlString{
- ControlType: ControlType,
- Criticality: Criticality,
- ControlValue: ControlValue,
- }
-}
-
-func encodeControls(Controls []Control) (*ber.Packet, error) {
- p := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls")
- for _, control := range Controls {
- pack, err := control.Encode()
- if err != nil {
- return nil, err
- }
- p.AppendChild(pack)
- }
- return p, nil
-}
-
-/************************/
-/* MatchedValuesRequest */
-/************************/
-
-func NewControlPermissiveModifyRequest(criticality bool) *ControlString {
- return NewControlString(ControlTypePermissiveModifyRequest, criticality, "")
-}
-
-/***************/
-/* ManageDsaITRequest */
-/***************/
-
-func NewControlManageDsaITRequest(criticality bool) *ControlString {
- return NewControlString(ControlTypeManageDsaITRequest, criticality, "")
-}
-
-/************************/
-/* SubtreeDeleteRequest */
-/************************/
-
-func NewControlSubtreeDeleteRequest(criticality bool) *ControlString {
- return NewControlString(ControlTypeSubtreeDeleteRequest, criticality, "")
-}
-
-/***************/
-/* NoOpRequest */
-/***************/
-
-func NewControlNoOpRequest() *ControlString {
- return NewControlString(ControlTypeNoOpRequest, true, "")
-}
-
-/************************/
-/* MatchedValuesRequest */
-/************************/
-
-type ControlMatchedValuesRequest struct {
- Criticality bool
- Filter string
-}
-
-func NewControlMatchedValuesRequest(criticality bool, filter string) *ControlMatchedValuesRequest {
- return &ControlMatchedValuesRequest{criticality, filter}
-}
-
-func (c *ControlMatchedValuesRequest) Decode(p *ber.Packet) (*Control, error) {
- return nil, NewLDAPError(ErrorDecoding, "Decode of Control unsupported.")
-}
-
-func (c *ControlMatchedValuesRequest) GetControlType() string {
- return ControlTypeMatchedValuesRequest
-}
-
-func (c *ControlMatchedValuesRequest) Encode() (p *ber.Packet, err error) {
- p = ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "ControlMatchedValuesRequest")
- p.AppendChild(
- ber.NewString(ber.ClassUniversal, ber.TypePrimative,
- ber.TagOctetString, ControlTypeMatchedValuesRequest,
- "Control Type ("+ControlTypeMap[ControlTypeMatchedValuesRequest]+")"))
- if c.Criticality {
- p.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimative, ber.TagBoolean, c.Criticality, "Criticality"))
- }
- octetString := ber.Encode(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, nil, "Octet String")
- simpleFilterSeq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "SimpleFilterItem")
- filterPacket, err := filterParse(c.Filter)
- if err != nil {
- return nil, err
- }
- simpleFilterSeq.AppendChild(filterPacket)
- octetString.AppendChild(simpleFilterSeq)
- p.AppendChild(octetString)
- return p, nil
-}
-
-func (c *ControlMatchedValuesRequest) String() string {
- return fmt.Sprintf(
- "Control Type: %s (%q) Criticality: %t Filter: %s",
- ControlTypeMap[ControlTypeMatchedValuesRequest],
- ControlTypeMatchedValuesRequest,
- c.Criticality,
- c.Filter,
- )
-}
-
-/*************************/
-/* ServerSideSortRequest */
-/*************************/
-
-/*
-SortKeyList ::= SEQUENCE OF SEQUENCE {
- attributeType AttributeDescription,
- orderingRule [0] MatchingRuleId OPTIONAL,
- reverseOrder [1] BOOLEAN DEFAULT FALSE }
-
-*/
-
-type ServerSideSortAttrRuleOrder struct {
- AttributeName string
- OrderingRule string
- ReverseOrder bool
-}
-
-type ControlServerSideSortRequest struct {
- SortKeyList []ServerSideSortAttrRuleOrder
- Criticality bool
-}
-
-func NewControlServerSideSortRequest(sortKeyList []ServerSideSortAttrRuleOrder, criticality bool) *ControlServerSideSortRequest {
- return &ControlServerSideSortRequest{sortKeyList, criticality}
-}
-
-func (c *ControlServerSideSortRequest) Decode(p *ber.Packet) (*Control, error) {
- return nil, NewLDAPError(ErrorDecoding, "Decode of Control unsupported.")
-}
-
-func (c *ControlServerSideSortRequest) GetControlType() string {
- return ControlTypeServerSideSortRequest
-}
-
-func (c *ControlServerSideSortRequest) Encode() (p *ber.Packet, err error) {
- p = ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "ControlServerSideSortRequest")
- p.AppendChild(
- ber.NewString(ber.ClassUniversal, ber.TypePrimative,
- ber.TagOctetString, ControlTypeServerSideSortRequest,
- "Control Type ("+ControlTypeMap[ControlTypeServerSideSortRequest]+")"))
- if c.Criticality {
- p.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimative, ber.TagBoolean, c.Criticality, "Criticality"))
- }
- octetString := ber.Encode(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, nil, "Octet String")
- seqSortKeyLists := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "SortKeyLists")
-
- for _, sortKey := range c.SortKeyList {
- seqKey := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "SortKey")
- seqKey.AppendChild(
- ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, sortKey.AttributeName, "AttributeDescription"),
- )
- if len(sortKey.OrderingRule) > 0 {
- seqKey.AppendChild(
- ber.NewString(ber.ClassUniversal, ber.TypePrimative, 0, sortKey.OrderingRule, "OrderingRule"),
- )
- }
- seqKey.AppendChild(
- ber.NewBoolean(ber.ClassUniversal, ber.TypePrimative, 1, sortKey.ReverseOrder, "ReverseOrder"),
- )
- seqSortKeyLists.AppendChild(seqKey)
- }
- octetString.AppendChild(seqSortKeyLists)
- p.AppendChild(octetString)
- return p, nil
-}
-
-func (c *ControlServerSideSortRequest) String() string {
- ctext := fmt.Sprintf(
- "Control Type: %s (%q) Criticality: %t, SortKeys: ",
- ControlTypeMap[ControlTypeServerSideSortRequest],
- ControlTypeServerSideSortRequest,
- c.Criticality,
- )
- for _, sortKey := range c.SortKeyList {
- ctext += fmt.Sprintf("[%s,%s,%t]", sortKey.AttributeName, sortKey.OrderingRule, sortKey.ReverseOrder)
- }
- return ctext
-}
-
-/*************************/
-/* VlvRequest */
-/*************************/
-
-var VlvDebug bool
-
-type VlvOffSet struct {
- Offset int32
- ContentCount int32
-}
-
-/*
- VirtualListViewRequest ::= SEQUENCE {
- beforeCount INTEGER (0..maxInt),
- afterCount INTEGER (0..maxInt),
- target CHOICE {
- byOffset [0] SEQUENCE {
- offset INTEGER (1 .. maxInt),
- contentCount INTEGER (0 .. maxInt) },
- greaterThanOrEqual [1] AssertionValue },
- contextID OCTET STRING OPTIONAL }
-*/
-type ControlVlvRequest struct {
- Criticality bool
- BeforeCount int32
- AfterCount int32
- ByOffset *VlvOffSet
- GreaterThanOrEqual string
- ContextID []byte
-}
-
-func (c *ControlVlvRequest) Encode() (*ber.Packet, error) {
- p := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "ControlVlvRequest")
- p.AppendChild(
- ber.NewString(ber.ClassUniversal, ber.TypePrimative,
- ber.TagOctetString, ControlTypeVlvRequest,
- "Control Type ("+ControlTypeMap[ControlTypeVlvRequest]+")"))
- if c.Criticality {
- p.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimative, ber.TagBoolean, c.Criticality, "Criticality"))
- }
- octetString := ber.Encode(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, nil, "Octet String")
-
- vlvSeq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "VirtualListViewRequest")
- beforeCount := ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, uint64(c.BeforeCount), "BeforeCount")
- afterCount := ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, uint64(c.AfterCount), "AfterCount")
- var target *ber.Packet
- switch {
- case c.ByOffset != nil:
- target = ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "ByOffset")
- offset := ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, uint64(c.ByOffset.Offset), "Offset")
- contentCount := ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, uint64(c.ByOffset.ContentCount), "ContentCount")
- target.AppendChild(offset)
- target.AppendChild(contentCount)
- case len(c.GreaterThanOrEqual) > 0:
- // TODO incorrect for some values, binary?
- target = ber.NewString(ber.ClassContext, ber.TypePrimative, 1, c.GreaterThanOrEqual, "GreaterThanOrEqual")
- }
- if target == nil {
- return nil, NewLDAPError(ErrorEncoding, "VLV target equal to nil")
- }
- vlvSeq.AppendChild(beforeCount)
- vlvSeq.AppendChild(afterCount)
- vlvSeq.AppendChild(target)
-
- if len(c.ContextID) > 0 {
- contextID := ber.NewString(ber.ClassUniversal, ber.TypePrimative,
- ber.TagOctetString, string(c.ContextID), "ContextID")
- vlvSeq.AppendChild(contextID)
- }
-
- octetString.AppendChild(vlvSeq)
- p.AppendChild(octetString)
-
- if VlvDebug {
- ber.PrintPacket(p)
- }
-
- return p, nil
-
-}
-
-func (c *ControlVlvRequest) GetControlType() string {
- return ControlTypeMap[ControlTypeVlvRequest]
-}
-
-func (c *ControlVlvRequest) String() string {
- ctext := fmt.Sprintf(
- "Control Type: %s (%q) Criticality: %t, BeforeCount: %d, AfterCount: %d"+
- ", ByOffset.Offset: %d, ByOffset.ContentCount: %d, GreaterThanOrEqual: %s",
- ControlTypeMap[ControlTypeVlvRequest],
- ControlTypeVlvRequest,
- c.Criticality, c.BeforeCount, c.AfterCount, c.ByOffset.Offset,
- c.ByOffset.ContentCount, c.GreaterThanOrEqual,
- )
- return ctext
-}
-
-/***********************************/
-/* RESPONSE CONTROLS */
-/***********************************/
-
-/**************************/
-/* ServerSideSortResponse */
-/**************************/
-
-type ControlServerSideSortResponse struct {
- AttributeName string // Optional
- Criticality bool
- Err error
-}
-
-//SortResult ::= SEQUENCE {
-// sortResult ENUMERATED {
-// success (0), -- results are sorted
-// operationsError (1), -- server internal failure
-// timeLimitExceeded (3), -- timelimit reached before
-// -- sorting was completed
-// strongAuthRequired (8), -- refused to return sorted
-// -- results via insecure
-// -- protocol
-// adminLimitExceeded (11), -- too many matching entries
-// -- for the server to sort
-// noSuchAttribute (16), -- unrecognized attribute
-// -- type in sort key
-// inappropriateMatching (18), -- unrecognized or
-// -- inappropriate matching
-// -- rule in sort key
-// insufficientAccessRights (50), -- refused to return sorted
-// -- results to this client
-// busy (51), -- too busy to process
-// unwillingToPerform (53), -- unable to sort
-// other (80)
-// },
-// attributeType [0] AttributeDescription OPTIONAL }
-func NewControlServerSideSortResponse(p *ber.Packet) (Control, error) {
- c := new(ControlServerSideSortResponse)
- _, criticality, value := decodeControlTypeAndCrit(p)
- c.Criticality = criticality
-
- if value.Value != nil {
- sortResult := ber.DecodePacket(value.Data.Bytes())
- value.Data.Truncate(0)
- value.Value = nil
- value.AppendChild(sortResult)
- }
-
- value = value.Children[0]
- value.Description = "ServerSideSortResponse Control Value"
-
- value.Children[0].Description = "SortResult"
- errNum := uint8(value.Children[0].Value.(uint64))
- c.Err = NewLDAPError(errNum, "")
-
- if len(value.Children) == 2 {
- value.Children[1].Description = "Attribute Name"
- c.AttributeName = value.Children[1].ValueString()
- value.Children[1].Value = c.AttributeName
- }
- return c, nil
-}
-
-func (c *ControlServerSideSortResponse) Encode() (p *ber.Packet, err error) {
- return nil, NewLDAPError(ErrorEncoding, "Encode of Control unsupported.")
-}
-
-func (c *ControlServerSideSortResponse) GetControlType() string {
- return ControlTypeServerSideSortResponse
-}
-
-func (c *ControlServerSideSortResponse) String() string {
- return fmt.Sprintf("Control Type: %s (%q) Criticality: %t, AttributeName: %s, ErrorValue: %d",
- ControlTypeMap[ControlTypeServerSideSortResponse],
- ControlTypeServerSideSortResponse,
- c.Criticality,
- c.AttributeName,
- c.Err.(*LDAPError).ResultCode,
- )
-}
-
-/***************/
-/* VlvResponse */
-/***************/
-
-type ControlVlvResponse struct {
- Criticality bool
- TargetPosition uint64
- ContentCount uint64
- Err error // VirtualListViewResult
- ContextID string
-}
-
-/*
- VirtualListViewResponse ::= SEQUENCE {
- targetPosition INTEGER (0 .. maxInt),
- contentCount INTEGER (0 .. maxInt),
- virtualListViewResult ENUMERATED {
- success (0),
- operationsError (1),
- protocolError (3),
- unwillingToPerform (53),
- insufficientAccessRights (50),
- timeLimitExceeded (3),
- adminLimitExceeded (11),
- innapropriateMatching (18),
- sortControlMissing (60),
- offsetRangeError (61),
- other(80),
- ... },
- contextID OCTET STRING OPTIONAL }
-*/
-func NewControlVlvResponse(p *ber.Packet) (Control, error) {
- c := new(ControlVlvResponse)
- _, criticality, value := decodeControlTypeAndCrit(p)
- c.Criticality = criticality
-
- if value.Value != nil {
- vlvResult := ber.DecodePacket(value.Data.Bytes())
- value.Data.Truncate(0)
- value.Value = nil
- value.AppendChild(vlvResult)
- }
-
- value = value.Children[0]
- value.Description = "VlvResponse Control Value"
-
- value.Children[0].Description = "TargetPosition"
- value.Children[1].Description = "ContentCount"
- value.Children[2].Description = "VirtualListViewResult/Err"
-
- c.TargetPosition = value.Children[0].Value.(uint64)
- c.ContentCount = value.Children[1].Value.(uint64)
-
- errNum := uint8(value.Children[2].Value.(uint64))
- c.Err = NewLDAPError(errNum, "")
-
- if len(value.Children) == 4 {
- value.Children[3].Description = "ContextID"
- c.ContextID = value.Children[3].ValueString()
- }
-
- return c, nil
-}
-
-func (c *ControlVlvResponse) Encode() (p *ber.Packet, err error) {
- return nil, NewLDAPError(ErrorEncoding, "Encode of Control unsupported.")
-}
-
-func (c *ControlVlvResponse) GetControlType() string {
- return ControlTypeVlvResponse
-}
-
-func (c *ControlVlvResponse) String() string {
- return fmt.Sprintf("Control Type: %s (%q) Criticality: %t, TargetPosition: %d, ContentCount: %d, ErrorValue: %d, ContextID: %s",
- ControlTypeMap[ControlTypeVlvResponse],
- ControlTypeVlvResponse,
- c.Criticality,
- c.TargetPosition,
- c.ContentCount,
- c.Err.(*LDAPError).ResultCode,
- c.ContextID,
- )
-}
diff --git a/vendor/github.com/mavricknz/ldap/delete.go b/vendor/github.com/mavricknz/ldap/delete.go
deleted file mode 100644
index 9af113ee541..00000000000
--- a/vendor/github.com/mavricknz/ldap/delete.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ldap
-
-import (
- "github.com/mavricknz/asn1-ber"
-)
-
-type DeleteRequest struct {
- DN string
- Controls []Control
-}
-
-func (req *DeleteRequest) RecordType() uint8 {
- return DeleteRecord
-}
-
-/*
-Simple delete
-*/
-
-func (l *LDAPConnection) Delete(delReq *DeleteRequest) (error error) {
- messageID, ok := l.nextMessageID()
- if !ok {
- return NewLDAPError(ErrorClosing, "MessageID channel is closed.")
- }
- encodedDelete := ber.NewString(ber.ClassApplication, ber.TypePrimative, ApplicationDelRequest, delReq.DN, ApplicationMap[ApplicationDelRequest])
-
- packet, err := requestBuildPacket(messageID, encodedDelete, delReq.Controls)
- if err != nil {
- return err
- }
-
- return l.sendReqRespPacket(messageID, packet)
-}
-
-func NewDeleteRequest(dn string) (delReq *DeleteRequest) {
- delReq = &DeleteRequest{DN: dn, Controls: make([]Control, 0)}
- return
-}
-
-// TDDO make generic for mod/del/search via interface.
-func (delReq *DeleteRequest) AddControl(control Control) {
- if delReq.Controls == nil {
- delReq.Controls = make([]Control, 0)
- }
- delReq.Controls = append(delReq.Controls, control)
-}
diff --git a/vendor/github.com/mavricknz/ldap/entry.go b/vendor/github.com/mavricknz/ldap/entry.go
deleted file mode 100644
index 9c3e7bfd9ae..00000000000
--- a/vendor/github.com/mavricknz/ldap/entry.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// File contains Entry structures and functions
-package ldap
-
-import (
- "strings"
-)
-
-type Entry struct {
- DN string
- Attributes []*EntryAttribute
-}
-
-type EntryAttribute struct {
- Name string
- Values []string
-}
-
-func (req *Entry) RecordType() uint8 {
- return EntryRecord
-}
-
-func NewEntry(dn string) *Entry {
- entry := &Entry{DN: dn}
- entry.Attributes = make([]*EntryAttribute, 0)
- return entry
-}
-
-// AddAttributeValue - Add a single Attr value
-// no check is done for duplicate values.
-func (e *Entry) AddAttributeValue(attributeName, value string) {
- index := e.GetAttributeIndex(attributeName)
- if index == -1 {
- eAttr := EntryAttribute{Name: attributeName, Values: []string{value}}
- e.Attributes = append(e.Attributes, &eAttr)
- } else {
- e.Attributes[index].Values = append(e.Attributes[index].Values, value)
- }
-}
-
-// AddAttributeValues - Add via a name and slice of values
-// no check is done for duplicate values.
-func (e *Entry) AddAttributeValues(attributeName string, values []string) {
- index := e.GetAttributeIndex(attributeName)
- if index == -1 {
- eAttr := &EntryAttribute{Name: attributeName, Values: values}
- e.Attributes = append(e.Attributes, eAttr)
- } else {
- e.Attributes[index].Values = append(e.Attributes[index].Values, values...)
- }
-}
-
-func (e *Entry) GetAttributeValues(attributeName string) []string {
- attributeName = strings.ToLower(attributeName)
- for _, attr := range e.Attributes {
- if strings.ToLower(attr.Name) == attributeName {
- return attr.Values
- }
- }
- return []string{}
-}
-
-// GetAttributeValue - returning an empty string is a bad idea
-// some directory servers will return empty attr values (Sunone).
-// Just asking for trouble.
-func (e *Entry) GetAttributeValue(attributeName string) string {
- values := e.GetAttributeValues(attributeName)
- if len(values) == 0 {
- return ""
- }
- return values[0]
-}
-
-func (e *Entry) GetAttributeIndex(Attribute string) int {
- Attribute = strings.ToLower(Attribute)
- for i, attr := range e.Attributes {
- if strings.ToLower(attr.Name) == Attribute {
- return i
- }
- }
- return -1
-}
-
-// TODO: Proper LDIF writer, currently just for testing...
-func (e *Entry) String() string {
- ldif := "dn: " + e.DN + "\n"
- for _, attr := range e.Attributes {
- for _, val := range attr.Values {
- ldif += attr.Name + ": " + val + "\n"
- }
- }
- return ldif
-}
diff --git a/vendor/github.com/mavricknz/ldap/filter.go b/vendor/github.com/mavricknz/ldap/filter.go
deleted file mode 100644
index 00e1b0adaa6..00000000000
--- a/vendor/github.com/mavricknz/ldap/filter.go
+++ /dev/null
@@ -1,498 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// File contains a filter compiler/decompiler
-
-// Influenced by Perl LDAP and OpenDJ, esp regex's.
-
-/*
-An LDAP search filter is defined in Section 4.5.1 of [RFC4511]
- Filter ::= CHOICE {
- and [0] SET SIZE (1..MAX) OF filter Filter,
- or [1] SET SIZE (1..MAX) OF filter Filter,
- not [2] Filter,
- equalityMatch [3] AttributeValueAssertion,
- substrings [4] SubstringFilter,
- greaterOrEqual [5] AttributeValueAssertion,
- lessOrEqual [6] AttributeValueAssertion,
- present [7] AttributeDescription,
- approxMatch [8] AttributeValueAssertion,
- extensibleMatch [9] MatchingRuleAssertion }
-
- SubstringFilter ::= SEQUENCE {
- type AttributeDescription,
- -- initial and final can occur at most once
- substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
- initial [0] AssertionValue,
- any [1] AssertionValue,
- final [2] AssertionValue } }
-
- AttributeValueAssertion ::= SEQUENCE {
- attributeDesc AttributeDescription,
- assertionValue AssertionValue }
-
- MatchingRuleAssertion ::= SEQUENCE {
- matchingRule [1] MatchingRuleId OPTIONAL,
- type [2] AttributeDescription OPTIONAL,
- matchValue [3] AssertionValue,
- dnAttributes [4] BOOLEAN DEFAULT FALSE }
-
- AttributeDescription ::= LDAPString
- -- Constrained to
- -- [RFC4512]
-
- AttributeValue ::= OCTET STRING
-
- MatchingRuleId ::= LDAPString
-
- AssertionValue ::= OCTET STRING
-
- LDAPString ::= OCTET STRING -- UTF-8 encoded,
- -- [Unicode] characters
-*/
-package ldap
-
-import (
- "encoding/hex"
- "fmt"
- "github.com/mavricknz/asn1-ber"
- "regexp"
-)
-
-const (
- FilterAnd = 0
- FilterOr = 1
- FilterNot = 2
- FilterEqualityMatch = 3
- FilterSubstrings = 4
- FilterGreaterOrEqual = 5
- FilterLessOrEqual = 6
- FilterPresent = 7
- FilterApproxMatch = 8
- FilterExtensibleMatch = 9
-)
-
-var FilterMap = map[uint64]string{
- FilterAnd: "And",
- FilterOr: "Or",
- FilterNot: "Not",
- FilterEqualityMatch: "Equality Match",
- FilterSubstrings: "Substrings",
- FilterGreaterOrEqual: "Greater Or Equal",
- FilterLessOrEqual: "Less Or Equal",
- FilterPresent: "Present",
- FilterApproxMatch: "Approx Match",
- FilterExtensibleMatch: "Extensible Match",
-}
-
-const (
- FilterSubstringsInitial = 0
- FilterSubstringsAny = 1
- FilterSubstringsFinal = 2
-)
-
-var FilterSubstringsMap = map[uint64]string{
- FilterSubstringsInitial: "Substrings Initial",
- FilterSubstringsAny: "Substrings Any",
- FilterSubstringsFinal: "Substrings Final",
-}
-
-const (
- TagMatchingRule = 1
- TagMatchingType = 2
- TagMatchValue = 3
- TagMatchDnAttributes = 4
-)
-
-const (
- FilterItem = 256
-)
-
-var FilterComponent = map[string]uint64{
- "&": FilterAnd,
- "|": FilterOr,
- "!": FilterNot,
- "=": FilterEqualityMatch,
- ">=": FilterGreaterOrEqual,
- "<=": FilterLessOrEqual,
- "~=": FilterApproxMatch,
-}
-
-var opRegex *regexp.Regexp
-var endRegex *regexp.Regexp
-var itemRegex *regexp.Regexp
-var unescapedWildCardRegex *regexp.Regexp
-var wildCardSearchRegex *regexp.Regexp
-var unescapeFilterRegex *regexp.Regexp
-var escapeFilterRegex *regexp.Regexp
-
-var FilterDebug bool = false
-
-func init() {
- opRegex = regexp.MustCompile(`^\(\s*([&!|])\s*`)
- endRegex = regexp.MustCompile(`^\)\s*`)
- itemRegex = regexp.MustCompile(
- `^\(\s*([-;.:\d\w]*[-;\d\w])\s*([:~<>]?=)((?:\\.|[^\\()]+)*)\)\s*`)
- unescapedWildCardRegex = regexp.MustCompile(`^(\\.|[^\\*]+)*\*`)
- wildCardSearchRegex = regexp.MustCompile(`^((\\.|[^\\*]+)*)\*`)
- unescapeFilterRegex = regexp.MustCompile(`\\([\da-fA-F]{2}|[()\\*])`)
- escapeFilterRegex = regexp.MustCompile(`([\\\(\)\*\0-\37\177-\377])`)
-}
-
-func CompileFilter(filter string) (*ber.Packet, error) {
- if len(filter) == 0 {
- return nil, NewLDAPError(ErrorFilterCompile, "Filter of zero length")
- }
- if filter[0] != '(' {
- return nil, NewLDAPError(ErrorFilterCompile, "Filter does not start with '('")
- }
- return filterParse(filter)
-}
-
-func filterParse(filter string) (*ber.Packet, error) {
- var err error
- var pTmp1 *ber.Packet
- pos := 0
- bracketCount := 0
-
- p := make([]*ber.Packet, 0, 5)
-
- // Simple non recursive method to create ber packets.
- // If its an Op "&|!" then push onto the stack
- // If its a filter expression (item) then add as a child
- // if its an ending ) pop the stack adding as child to above.
- // plus special cases of course.
-
- for {
- if matches := opRegex.FindStringSubmatch(filter[pos:]); len(matches) != 0 {
- pos += len(matches[0])
- pTmp1, err = filterEncode(FilterComponent[matches[1]], nil)
- if err != nil {
- return nil, err
- }
- p = append(p, pTmp1)
- bracketCount++
- continue
- } else if matches := endRegex.FindStringSubmatch(filter[pos:]); len(matches) != 0 {
- if bracketCount <= 0 {
- return nil, NewLDAPError(ErrorFilterCompile,
- "Finished compiling filter with extra at end :"+
- fmt.Sprint(filter[pos:]))
- }
- bracketCount--
- pos += len(matches[0])
- pTmp1 = p[len(p)-1] // copy last *ber (sequence of values)
- if len(p) > 1 { // not root of "tree"
- p[len(p)-2].AppendChild(pTmp1) // add as child to previous op
- p = p[:len(p)-1] // pop stack
- }
- continue
- } else if matches := itemRegex.FindStringSubmatch(filter[pos:]); len(matches) != 0 {
- pos += len(matches[0])
- pTmp1, err = filterEncode(FilterItem, matches[1:4])
- if err != nil {
- return nil, err
- }
- if len(p) == 0 { // case (attr=yyyy)
- p = append(p, pTmp1)
- } else {
- p[len(p)-1].AppendChild(pTmp1)
- }
- continue
- }
- break
- }
- //if len(p) > 0 {
- // ber.PrintPacket(p[0])
- //}
- if len(filter[pos:]) > 0 {
- return nil, NewLDAPError(ErrorFilterCompile, filter+" : Error compiling filter, invalid filter : "+fmt.Sprint(filter[pos:]))
- }
- return p[0], nil
-}
-
-func filterEncode(opType uint64, value []string) (*ber.Packet, error) {
- var p *ber.Packet = nil
- var err error
-
- // condense and/or/not into one case.
- switch opType {
- case FilterAnd, FilterOr, FilterNot:
- if FilterDebug {
- fmt.Println(FilterMap[opType])
- }
- p = ber.Encode(ber.ClassContext, ber.TypeConstructed, uint8(opType), nil, FilterMap[opType])
- case FilterItem:
- if FilterDebug {
- fmt.Println("FilterItem")
- }
- p, err = encodeItem(value)
- }
- return p, err
-}
-
-func encodeItem(attrOpVal []string) (*ber.Packet, error) {
- attr, op, val := attrOpVal[0], attrOpVal[1], attrOpVal[2]
- if FilterDebug {
- fmt.Println(attr, op, val)
- }
-
- if op == ":=" {
- return encodeExtensibleMatch(attr, val)
- }
-
- if op == "=" {
- if val == "*" { // simple present
- p := ber.NewString(ber.ClassContext, ber.TypePrimative, FilterPresent, attr, FilterMap[FilterPresent])
- return p, nil
- } else if unescapedWildCardRegex.Match([]byte(val)) {
- // TODO ADD escaping.
- return encodeSubStringMatch(attr, val)
- }
- }
-
- p, _ := AttributeValueAssertion(attr, op, val)
- return p, nil
-}
-
-/*
-substrings [4] SubstringFilter,
-
-SubstringFilter ::= SEQUENCE {
- type AttributeDescription,
- -- initial and final can occur at most once
- substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
- initial [0] AssertionValue,
- any [1] AssertionValue,
- final [2] AssertionValue } }
-*/
-
-func encodeSubStringMatch(attr, value string) (*ber.Packet, error) {
- p := ber.Encode(ber.ClassContext, ber.TypeConstructed,
- FilterSubstrings, nil, FilterMap[FilterSubstrings])
- p.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, attr, "type"))
- seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "substrings")
-
- pos := 0
-
- for {
- matches := wildCardSearchRegex.FindStringSubmatch(value[pos:])
- if FilterDebug {
- fmt.Println(matches)
- }
-
- // not match found return error
-
- if matches == nil && pos == 0 {
- if FilterDebug {
- fmt.Println("Did not match filter")
- }
- return nil, NewLDAPError(ErrorFilterCompile, "Did not match filter.")
- }
- // attr=*XXX
- if len(matches) == 0 {
- break
- }
- // initial
- if pos == 0 && len(matches[1]) > 0 {
- if FilterDebug {
- fmt.Println("initial : " + matches[1])
- }
- seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimative, FilterSubstringsInitial, UnescapeFilterValue(matches[1]), "initial"))
- }
- // past initial but not end
- if pos > 0 && len(matches) > 1 && len(matches[1]) > 0 {
- if FilterDebug {
- fmt.Println("any : " + matches[1])
- }
- seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimative, FilterSubstringsAny, UnescapeFilterValue(matches[1]), "any"))
- }
-
- pos += len(matches[0])
- if pos == len(value) {
- break
- }
- }
- if len(value[pos:]) > 0 {
- if FilterDebug {
- fmt.Println("final : " + value[pos:])
- }
- seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimative, FilterSubstringsFinal, UnescapeFilterValue(value[pos:]), "final"))
- }
- p.AppendChild(seq)
- if FilterDebug {
- fmt.Println(hex.Dump(p.Bytes()))
- }
- return p, nil
-}
-
-/*
-extensibleMatch [9] MatchingRuleAssertion
-
-MatchingRuleAssertion ::= SEQUENCE {
- matchingRule [1] MatchingRuleId OPTIONAL,
- type [2] AttributeDescription OPTIONAL,
- matchValue [3] AssertionValue,
- dnAttributes [4] BOOLEAN DEFAULT FALSE }
-*/
-
-func encodeExtensibleMatch(attr, value string) (*ber.Packet, error) {
- //TODO make cacheable
- extenseRegex := regexp.MustCompile(`^([-;\d\w]*)(:dn)?(:(\w+|[.\d]+))?$`)
- p := ber.Encode(ber.ClassContext, ber.TypeConstructed,
- FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch])
- if matches := extenseRegex.FindStringSubmatch(attr); len(matches) != 0 {
- if FilterDebug {
- fmt.Println(matches)
- }
- rtype := matches[1]
- dn := matches[2]
- rule := matches[4]
-
- if len(rule) > 0 {
- prule := ber.NewString(ber.ClassContext, ber.TypePrimative, TagMatchingRule, rule, "matchingRule")
- p.AppendChild(prule)
- }
- if len(rtype) > 0 {
- ptype := ber.NewString(ber.ClassContext, ber.TypePrimative, TagMatchingType, rtype, "type")
- p.AppendChild(ptype)
- }
- pval := ber.NewString(ber.ClassContext, ber.TypePrimative, TagMatchValue, UnescapeFilterValue(value), "matchValue")
- p.AppendChild(pval)
- if len(dn) > 0 {
- pdn := ber.NewBoolean(ber.ClassContext, ber.TypePrimative, TagMatchDnAttributes, true, "dnAttributes")
- p.AppendChild(pdn)
- }
- } else {
- return nil, NewLDAPError(ErrorFilterCompile,
- "Invalid Extensible attr : "+attr)
- }
- if FilterDebug {
- fmt.Println(hex.Dump(p.Bytes()))
- }
- return p, nil
-}
-
-func DecompileFilter(packet *ber.Packet) (ret string, err error) {
- defer func() {
- if r := recover(); r != nil {
- err = NewLDAPError(ErrorFilterDecompile, "Error decompiling filter")
- }
- }()
- ret = "("
- err = nil
- child_str := ""
-
- switch packet.Tag {
- case FilterAnd:
- ret += "&"
- for _, child := range packet.Children {
- child_str, err = DecompileFilter(child)
- if err != nil {
- return
- }
- ret += child_str
- }
- case FilterOr:
- ret += "|"
- for _, child := range packet.Children {
- child_str, err = DecompileFilter(child)
- if err != nil {
- return
- }
- ret += child_str
- }
- case FilterNot:
- ret += "!"
- child_str, err = DecompileFilter(packet.Children[0])
- if err != nil {
- return
- }
- ret += child_str
-
- case FilterSubstrings:
- ret += ber.DecodeString(packet.Children[0].Data.Bytes())
- ret += "="
- switch packet.Children[1].Children[0].Tag {
- case FilterSubstringsInitial:
- ret += ber.DecodeString(packet.Children[1].Children[0].Data.Bytes()) + "*"
- case FilterSubstringsAny:
- ret += "*" + ber.DecodeString(packet.Children[1].Children[0].Data.Bytes()) + "*"
- case FilterSubstringsFinal:
- ret += "*" + ber.DecodeString(packet.Children[1].Children[0].Data.Bytes())
- }
- case FilterEqualityMatch:
- ret += ber.DecodeString(packet.Children[0].Data.Bytes())
- ret += "="
- ret += ber.DecodeString(packet.Children[1].Data.Bytes())
- case FilterGreaterOrEqual:
- ret += ber.DecodeString(packet.Children[0].Data.Bytes())
- ret += ">="
- ret += ber.DecodeString(packet.Children[1].Data.Bytes())
- case FilterLessOrEqual:
- ret += ber.DecodeString(packet.Children[0].Data.Bytes())
- ret += "<="
- ret += ber.DecodeString(packet.Children[1].Data.Bytes())
- case FilterPresent:
- ret += ber.DecodeString(packet.Data.Bytes())
- ret += "=*"
- case FilterApproxMatch:
- ret += ber.DecodeString(packet.Children[0].Data.Bytes())
- ret += "~="
- ret += ber.DecodeString(packet.Children[1].Data.Bytes())
- case FilterExtensibleMatch:
- // TODO
- }
-
- ret += ")"
- return
-}
-
-func UnescapeFilterValue(filter string) string {
- // regex wil only match \[)*\] or \xx x=a-fA-F
- repl := unescapeFilterRegex.ReplaceAllFunc(
- []byte(filter),
- func(match []byte) []byte {
- // \( \) \\ \*
- if len(match) == 2 {
- return []byte{match[1]}
- }
- // had issues with Decode, TODO fix to use Decode?.
- res, _ := hex.DecodeString(string(match[1:]))
- return res
- },
- )
- return string(repl)
-}
-
-func EscapeFilterValue(filter string) string {
- repl := escapeFilterRegex.ReplaceAllFunc(
- []byte(filter),
- func(match []byte) []byte {
- if len(match) == 2 {
- return []byte(fmt.Sprintf("\\%02x", match[1]))
- }
- return []byte(fmt.Sprintf("\\%02x", match[0]))
- },
- )
- return string(repl)
-}
-
-func AttributeValueAssertion(attr, op, value string) (*ber.Packet, error) {
- filterComp, ok := FilterComponent[op]
- if !ok {
- return nil, NewLDAPError(ErrorEncoding, "Invalid Assertion Op.")
- }
-
- // AttributeValueAssertion seq of the right op.
- p := ber.Encode(ber.ClassContext, ber.TypeConstructed,
- uint8(filterComp), nil, FilterMap[filterComp])
- p.AppendChild(
- ber.NewString(ber.ClassUniversal, ber.TypePrimative,
- ber.TagOctetString, attr, "Attribute"))
- p.AppendChild(
- ber.NewString(ber.ClassUniversal, ber.TypePrimative,
- ber.TagOctetString, UnescapeFilterValue(value), "Value"))
- return p, nil
-}
diff --git a/vendor/github.com/mavricknz/ldap/ldap.go b/vendor/github.com/mavricknz/ldap/ldap.go
deleted file mode 100644
index 39b85402e6e..00000000000
--- a/vendor/github.com/mavricknz/ldap/ldap.go
+++ /dev/null
@@ -1,344 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This package provides LDAP client functions.
-package ldap
-
-import (
- "fmt"
- "github.com/mavricknz/asn1-ber"
- "io/ioutil"
- "time"
-)
-
-// LDAP Application Codes
-const (
- ApplicationBindRequest = 0
- ApplicationBindResponse = 1
- ApplicationUnbindRequest = 2
- ApplicationSearchRequest = 3
- ApplicationSearchResultEntry = 4
- ApplicationSearchResultDone = 5
- ApplicationModifyRequest = 6
- ApplicationModifyResponse = 7
- ApplicationAddRequest = 8
- ApplicationAddResponse = 9
- ApplicationDelRequest = 10
- ApplicationDelResponse = 11
- ApplicationModifyDNRequest = 12
- ApplicationModifyDNResponse = 13
- ApplicationCompareRequest = 14
- ApplicationCompareResponse = 15
- ApplicationAbandonRequest = 16
- ApplicationSearchResultReference = 19
- ApplicationExtendedRequest = 23
- ApplicationExtendedResponse = 24
-)
-
-var ApplicationMap = map[uint8]string{
- ApplicationBindRequest: "Bind Request",
- ApplicationBindResponse: "Bind Response",
- ApplicationUnbindRequest: "Unbind Request",
- ApplicationSearchRequest: "Search Request",
- ApplicationSearchResultEntry: "Search Result Entry",
- ApplicationSearchResultDone: "Search Result Done",
- ApplicationModifyRequest: "Modify Request",
- ApplicationModifyResponse: "Modify Response",
- ApplicationAddRequest: "Add Request",
- ApplicationAddResponse: "Add Response",
- ApplicationDelRequest: "Del Request",
- ApplicationDelResponse: "Del Response",
- ApplicationModifyDNRequest: "Modify DN Request",
- ApplicationModifyDNResponse: "Modify DN Response",
- ApplicationCompareRequest: "Compare Request",
- ApplicationCompareResponse: "Compare Response",
- ApplicationAbandonRequest: "Abandon Request",
- ApplicationSearchResultReference: "Search Result Reference",
- ApplicationExtendedRequest: "Extended Request",
- ApplicationExtendedResponse: "Extended Response",
-}
-
-// LDAP Result Codes
-const (
- LDAPResultSuccess = 0
- LDAPResultOperationsError = 1
- LDAPResultProtocolError = 2
- LDAPResultTimeLimitExceeded = 3
- LDAPResultSizeLimitExceeded = 4
- LDAPResultCompareFalse = 5
- LDAPResultCompareTrue = 6
- LDAPResultAuthMethodNotSupported = 7
- LDAPResultStrongAuthRequired = 8
- LDAPResultReferral = 10
- LDAPResultAdminLimitExceeded = 11
- LDAPResultUnavailableCriticalExtension = 12
- LDAPResultConfidentialityRequired = 13
- LDAPResultSaslBindInProgress = 14
- LDAPResultNoSuchAttribute = 16
- LDAPResultUndefinedAttributeType = 17
- LDAPResultInappropriateMatching = 18
- LDAPResultConstraintViolation = 19
- LDAPResultAttributeOrValueExists = 20
- LDAPResultInvalidAttributeSyntax = 21
- LDAPResultNoSuchObject = 32
- LDAPResultAliasProblem = 33
- LDAPResultInvalidDNSyntax = 34
- LDAPResultAliasDereferencingProblem = 36
- LDAPResultInappropriateAuthentication = 48
- LDAPResultInvalidCredentials = 49
- LDAPResultInsufficientAccessRights = 50
- LDAPResultBusy = 51
- LDAPResultUnavailable = 52
- LDAPResultUnwillingToPerform = 53
- LDAPResultLoopDetect = 54
- LDAPResultNamingViolation = 64
- LDAPResultObjectClassViolation = 65
- LDAPResultNotAllowedOnNonLeaf = 66
- LDAPResultNotAllowedOnRDN = 67
- LDAPResultEntryAlreadyExists = 68
- LDAPResultObjectClassModsProhibited = 69
- LDAPResultAffectsMultipleDSAs = 71
- LDAPResultOther = 80
-
- ErrorNetwork = 201
- ErrorFilterCompile = 202
- ErrorFilterDecompile = 203
- ErrorDebugging = 204
- ErrorEncoding = 205
- ErrorDecoding = 206
- ErrorMissingControl = 207
- ErrorInvalidArgument = 208
- ErrorLDIFRead = 209
- ErrorLDIFWrite = 210
- ErrorClosing = 211
- ErrorUnknown = 212
-)
-
-const (
- DefaultTimeout = 60 * time.Minute
- ResultChanBufferSize = 5 // buffer items in each chanResults default: 5
-)
-
-var LDAPResultCodeMap = map[uint8]string{
- LDAPResultSuccess: "Success",
- LDAPResultOperationsError: "Operations Error",
- LDAPResultProtocolError: "Protocol Error",
- LDAPResultTimeLimitExceeded: "Time Limit Exceeded",
- LDAPResultSizeLimitExceeded: "Size Limit Exceeded",
- LDAPResultCompareFalse: "Compare False",
- LDAPResultCompareTrue: "Compare True",
- LDAPResultAuthMethodNotSupported: "Auth Method Not Supported",
- LDAPResultStrongAuthRequired: "Strong Auth Required",
- LDAPResultReferral: "Referral",
- LDAPResultAdminLimitExceeded: "Admin Limit Exceeded",
- LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension",
- LDAPResultConfidentialityRequired: "Confidentiality Required",
- LDAPResultSaslBindInProgress: "Sasl Bind In Progress",
- LDAPResultNoSuchAttribute: "No Such Attribute",
- LDAPResultUndefinedAttributeType: "Undefined Attribute Type",
- LDAPResultInappropriateMatching: "Inappropriate Matching",
- LDAPResultConstraintViolation: "Constraint Violation",
- LDAPResultAttributeOrValueExists: "Attribute Or Value Exists",
- LDAPResultInvalidAttributeSyntax: "Invalid Attribute Syntax",
- LDAPResultNoSuchObject: "No Such Object",
- LDAPResultAliasProblem: "Alias Problem",
- LDAPResultInvalidDNSyntax: "Invalid DN Syntax",
- LDAPResultAliasDereferencingProblem: "Alias Dereferencing Problem",
- LDAPResultInappropriateAuthentication: "Inappropriate Authentication",
- LDAPResultInvalidCredentials: "Invalid Credentials",
- LDAPResultInsufficientAccessRights: "Insufficient Access Rights",
- LDAPResultBusy: "Busy",
- LDAPResultUnavailable: "Unavailable",
- LDAPResultUnwillingToPerform: "Unwilling To Perform",
- LDAPResultLoopDetect: "Loop Detect",
- LDAPResultNamingViolation: "Naming Violation",
- LDAPResultObjectClassViolation: "Object Class Violation",
- LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf",
- LDAPResultNotAllowedOnRDN: "Not Allowed On RDN",
- LDAPResultEntryAlreadyExists: "Entry Already Exists",
- LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited",
- LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs",
- LDAPResultOther: "Other",
-
- ErrorNetwork: "ErrorNetwork",
- ErrorFilterCompile: "ErrorFilterCompile",
- ErrorFilterDecompile: "ErrorFilterDecompile",
- ErrorDebugging: "ErrorDebugging",
- ErrorEncoding: "ErrorEncoding",
- ErrorDecoding: "ErrorDecoding",
- ErrorMissingControl: "ErrorMissingControl",
- ErrorInvalidArgument: "ErrorInvalidArgument",
- ErrorLDIFRead: "ErrorLDIFRead",
- ErrorClosing: "ErrorClosing",
-}
-
-// Adds descriptions to an LDAP Response packet for debugging
-func addLDAPDescriptions(packet *ber.Packet) (err error) {
- defer func() {
- if r := recover(); r != nil {
- err = NewLDAPError(ErrorDebugging, "Cannot process packet to add descriptions")
- }
- }()
- packet.Description = "LDAP Response"
- packet.Children[0].Description = "Message ID"
-
- application := packet.Children[1].Tag
- packet.Children[1].Description = ApplicationMap[application]
-
- switch application {
- case ApplicationBindRequest:
- addRequestDescriptions(packet)
- case ApplicationBindResponse:
- addDefaultLDAPResponseDescriptions(packet)
- case ApplicationUnbindRequest:
- addRequestDescriptions(packet)
- case ApplicationSearchRequest:
- addRequestDescriptions(packet)
- case ApplicationSearchResultEntry:
- packet.Children[1].Children[0].Description = "Object Name"
- packet.Children[1].Children[1].Description = "Attributes"
- for _, child := range packet.Children[1].Children[1].Children {
- child.Description = "Attribute"
- child.Children[0].Description = "Attribute Name"
- child.Children[1].Description = "Attribute Values"
- for _, grandchild := range child.Children[1].Children {
- grandchild.Description = "Attribute Value"
- }
- }
- if len(packet.Children) == 3 {
- addControlDescriptions(packet.Children[2])
- }
- case ApplicationSearchResultDone:
- addDefaultLDAPResponseDescriptions(packet)
- case ApplicationModifyRequest:
- addRequestDescriptions(packet)
- case ApplicationModifyResponse:
- case ApplicationAddRequest:
- addRequestDescriptions(packet)
- case ApplicationAddResponse:
- case ApplicationDelRequest:
- addRequestDescriptions(packet)
- case ApplicationDelResponse:
- case ApplicationModifyDNRequest:
- addRequestDescriptions(packet)
- case ApplicationModifyDNResponse:
- case ApplicationCompareRequest:
- addRequestDescriptions(packet)
- case ApplicationCompareResponse:
- case ApplicationAbandonRequest:
- addRequestDescriptions(packet)
- case ApplicationSearchResultReference:
- case ApplicationExtendedRequest:
- addRequestDescriptions(packet)
- case ApplicationExtendedResponse:
- }
-
- return nil
-}
-
-func addControlDescriptions(packet *ber.Packet) {
- packet.Description = "Controls"
- for _, child := range packet.Children {
- child.Description = "Control"
- child.Children[0].Description = "Control Type (" + ControlTypeMap[child.Children[0].ValueString()] + ")"
- value := child.Children[1]
- if len(child.Children) == 3 {
- child.Children[1].Description = "Criticality"
- value = child.Children[2]
- }
- value.Description = "Control Value"
-
- switch child.Children[0].ValueString() {
- case ControlTypePaging:
- value.Description += " (Paging)"
- if value.Value != nil {
- value_children := ber.DecodePacket(value.Data.Bytes())
- value.Data.Truncate(0)
- value.Value = nil
- value_children.Children[1].Value = value_children.Children[1].Data.Bytes()
- value.AppendChild(value_children)
- }
- value.Children[0].Description = "Real Search Control Value"
- value.Children[0].Children[0].Description = "Paging Size"
- value.Children[0].Children[1].Description = "Cookie"
- }
- }
-}
-
-func addRequestDescriptions(packet *ber.Packet) {
- packet.Description = "LDAP Request"
- packet.Children[0].Description = "Message ID"
- packet.Children[1].Description = ApplicationMap[packet.Children[1].Tag]
- if len(packet.Children) == 3 {
- addControlDescriptions(packet.Children[2])
- }
-}
-
-func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
- resultCode := packet.Children[1].Children[0].Value.(uint64)
- packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[uint8(resultCode)] + ")"
- packet.Children[1].Children[1].Description = "Matched DN"
- packet.Children[1].Children[2].Description = "Error Message"
- if len(packet.Children[1].Children) > 3 {
- packet.Children[1].Children[3].Description = "Referral"
- }
- if len(packet.Children) == 3 {
- addControlDescriptions(packet.Children[2])
- }
-}
-
-func DebugBinaryFile(FileName string) error {
- file, err := ioutil.ReadFile(FileName)
- if err != nil {
- return err
- }
- ber.PrintBytes(file, "")
- packet := ber.DecodePacket(file)
- addLDAPDescriptions(packet)
- ber.PrintPacket(packet)
-
- return nil
-}
-
-type LDAPError struct {
- sText string
- ResultCode uint8
-}
-
-func (e *LDAPError) Error() string {
- return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.sText)
-}
-
-func (e *LDAPError) Status() string {
- return e.sText
-}
-
-func NewLDAPError(resultCode uint8, sText string) error {
- return &LDAPError{ResultCode: resultCode, sText: sText}
-}
-
-func getLDAPResultCode(p *ber.Packet) (code uint8, description string) {
- if len(p.Children) >= 2 {
- response := p.Children[1]
- if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed {
- switch {
- case len(response.Children) == 3:
- code = uint8(response.Children[0].Value.(uint64))
- description = response.Children[2].ValueString()
- return
- case len(response.Children) == 4 && response.Children[0].Value.(uint64) == uint64(LDAPResultReferral):
- response = response.Children[3]
- if response.ClassType == ber.ClassContext && response.TagType == ber.TypeConstructed && len(response.Children) == 1 {
- code = uint8(LDAPResultReferral)
- description = response.Children[0].ValueString()
- return
- }
- }
- }
- }
-
- code = ErrorNetwork
- description = "Invalid packet format"
- return
-}
diff --git a/vendor/github.com/mavricknz/ldap/ldif.go b/vendor/github.com/mavricknz/ldap/ldif.go
deleted file mode 100644
index 5a87bb98702..00000000000
--- a/vendor/github.com/mavricknz/ldap/ldif.go
+++ /dev/null
@@ -1,343 +0,0 @@
-package ldap
-
-import (
- "bufio"
- "bytes"
- "encoding/base64"
- "fmt"
- "io"
- "log"
- "regexp"
- "strings"
-)
-
-const (
- AddRecord = 0
- ModifyRecord = 1
- ModDnRecord = 2
- ModRdnRecord = 3
- DeleteRecord = 4
- EntryRecord = 255
-)
-
-var LDIFDebug bool = false
-
-var attrValueSep []byte = []byte{':'}
-var versionRegex *regexp.Regexp
-var charsetRegex *regexp.Regexp
-
-var stdBase64 *base64.Encoding
-
-func init() {
- versionRegex = regexp.MustCompile(`^version:\s+(\d+)`)
- charsetRegex = regexp.MustCompile(`^charset:\s+([^ ]+)`)
- stdBase64 = base64.StdEncoding
-}
-
-type LDIFRecord interface {
- RecordType() uint8
-}
-
-type LDIFReader struct {
- Version string
- Charset string
- Reader *bufio.Reader
-
- NoMoreEntries bool
- EntryCount uint64
- LineCount uint64
-}
-
-func NewLDIFReader(reader io.Reader) (*LDIFReader, error) {
- lr := &LDIFReader{Reader: bufio.NewReader(reader)}
- return lr, nil
-}
-
-func (lr *LDIFReader) ReadLDIFEntry() (LDIFRecord, error) {
- if lr.NoMoreEntries {
- return nil, nil
- }
- ldiflines, err := lr.readLDIFEntryIntoSlice()
- if err != nil {
- return nil, err
- }
- if ldiflines == nil {
- return nil, nil
- }
-
- if bytes.EqualFold(ldiflines[0][0:7], []byte("version")) {
- lr.Version = string(versionRegex.Find(ldiflines[0]))
- return lr.ReadLDIFEntry()
- }
- if bytes.EqualFold(ldiflines[0][0:7], []byte("charset")) {
- lr.Charset = string(charsetRegex.Find(ldiflines[0]))
- return lr.ReadLDIFEntry()
- }
- return sliceToLDIFRecord(ldiflines)
-}
-
-func sliceToLDIFRecord(lines [][]byte) (LDIFRecord, error) {
- var dn string
- var dataLineStart int // better name, after dn/controls/changetype
- controls := make([]Control, 0)
- recordtype := EntryRecord
-LINES:
- for i, line := range lines {
- attrName, value, _, err := findAttrAndValue(line)
- if err != nil {
- return nil, err
- }
- switch {
- case i == 0 && bytes.EqualFold(attrName, []byte("dn")):
- dn = string(value)
- continue LINES
- case i == 0 && !bytes.EqualFold(attrName, []byte("dn")):
- return nil, NewLDAPError(ErrorLDIFRead, "'dn:' not at the start of line in LDIF record")
- case bytes.EqualFold(attrName, []byte("changetype")):
- switch strings.ToLower(string(value)) {
- // check the record type, if one.
- case "add":
- recordtype = AddRecord
- case "modify":
- recordtype = ModifyRecord
- case "moddn":
- recordtype = ModDnRecord
- case "modrdn":
- recordtype = ModRdnRecord
- case "delete":
- recordtype = DeleteRecord
-
- }
- continue LINES
- case bytes.EqualFold(attrName, []byte("control")):
- //TODO handle controls
- continue LINES
- }
- dataLineStart = i
- break
- }
- // TODO - add the missing record types
- unsupportedError := NewLDAPError(ErrorLDIFRead, "Unsupported LDIF record type")
- switch recordtype {
- case AddRecord:
- addEntry, err := ldifLinesToEntryRecord(dn, lines[dataLineStart:])
- if err != nil {
- return nil, err
- }
- addRequest := AddRequest{Entry: addEntry, Controls: controls}
- if LDIFDebug {
- log.Printf("dn: %s, changetype: %d, datastart: %d\n", dn, AddRecord, dataLineStart)
- }
- return &addRequest, nil
- case ModifyRecord:
- if LDIFDebug {
- log.Printf("dn: %s, changetype: %d, datastart: %d\n", dn, ModifyRecord, dataLineStart)
- }
- modRequest, err := ldifLinesToModifyRecord(dn, lines[dataLineStart:])
- if err != nil {
- return nil, err
- }
- modRequest.Controls = controls
- return modRequest, nil
- case ModDnRecord:
- if LDIFDebug {
- log.Printf("dn: %s, changetype: %d, datastart: %d\n", dn, ModDnRecord, dataLineStart)
- }
- return nil, unsupportedError
- case ModRdnRecord:
- if LDIFDebug {
- log.Printf("dn: %s, changetype: %d, datastart: %d\n", dn, ModRdnRecord, dataLineStart)
- }
- return nil, unsupportedError
- case DeleteRecord:
- if LDIFDebug {
- log.Printf("dn: %s, changetype: %d, datastart: %d\n", dn, DeleteRecord, dataLineStart)
- }
- deleteRequest := NewDeleteRequest(dn)
- for _, control := range controls {
- deleteRequest.AddControl(control)
- }
- return deleteRequest, nil
- case EntryRecord:
- if LDIFDebug {
- log.Printf("dn: %s, changetype: %d, datastart: %d\n", dn, EntryRecord, dataLineStart)
- }
- return ldifLinesToEntryRecord(dn, lines[dataLineStart:])
- }
- return nil, NewLDAPError(ErrorLDIFRead, "Unkown LDIF record type")
-}
-
-func ldifLinesToModifyRecord(dn string, lines [][]byte) (*ModifyRequest, error) {
- modReq := NewModifyRequest(dn)
- var currentModType uint8
- var currentAttrName string
- var newMod *Mod
-
- isNewMod := true
-
- for _, line := range lines {
- bAttr, bValue, sep, err := findAttrAndValue(line)
- if err != nil {
- return nil, err
- }
- if sep {
- if newMod == nil {
- return nil, NewLDAPError(ErrorLDIFRead, "Misplaced '-'?")
- }
- modReq.AddMod(newMod)
- isNewMod = true
- continue
- }
- attrOrOpLower := strings.ToLower(string(bAttr))
- if isNewMod { // current line should be "operation: attr"
- switch {
- case attrOrOpLower == "add":
- currentModType = ModAdd
- case attrOrOpLower == "delete":
- currentModType = ModDelete
- case attrOrOpLower == "replace":
- currentModType = ModReplace
- case attrOrOpLower == "increment":
- currentModType = ModIncrement
- case true:
- return nil, NewLDAPError(ErrorLDIFRead, "Expecting Modtype, not found.")
- }
- currentAttrName = string(bValue)
- isNewMod = false
- newMod = NewMod(currentModType, currentAttrName, nil)
- } else {
- attrName := string(bAttr)
- if currentAttrName != attrName {
- return nil, NewLDAPError(ErrorLDIFRead,
- fmt.Sprintf("AttrName mismatch %s != %s", currentAttrName, attrName))
- }
- attrValue := string(bValue)
- // could check for empty values but some servers accept them
- newMod.Modification.Values = append(newMod.Modification.Values, attrValue)
- }
- }
- if isNewMod == false {
- modReq.AddMod(newMod)
- }
- return modReq, nil
-}
-
-func ldifLinesToEntryRecord(dn string, lines [][]byte) (*Entry, error) {
- entry := NewEntry(dn)
- for _, line := range lines {
- bAttr, bValue, separator, err := findAttrAndValue(line)
- if err != nil {
- return nil, err
- }
- if separator {
- continue // -
- }
- attributeName := string(bAttr)
- entry.AddAttributeValue(attributeName, string(bValue))
- //log.Printf("processed: %s: %s\n", attr, string(bValue))
- }
- //fmt.Println(entry)
- return entry, nil
-}
-
-func findAttrAndValue(line []byte) (attr []byte, value []byte, separator bool, err error) {
- var valueStart int
- colonLoc := bytes.Index(line, attrValueSep)
- base64 := false
- if line[0] == '-' {
- separator = true
- return
- }
- // find the location of first ':'
- if colonLoc == -1 {
- return nil, nil, false, NewLDAPError(ErrorLDIFRead, ": not found in LDIF attr line.")
- } else if line[colonLoc+1] == ':' { // base64 attr
- valueStart = colonLoc + 2
- if line[colonLoc+2] == ' ' {
- valueStart = colonLoc + 3
- }
- base64 = true
- } else { // normal
- valueStart = colonLoc + 1
- if line[colonLoc+1] == ' ' { // accomidate attr:value
- valueStart = colonLoc + 2
- }
- }
-
- attr = line[:colonLoc]
-
- if base64 {
- value, err = decodeBase64(line[valueStart:])
- if err != nil {
- return nil, nil, false, NewLDAPError(ErrorLDIFRead, "Error decoding base64 value")
- }
- } else {
- value = line[valueStart:]
- }
- if LDIFDebug {
- log.Printf("findAttrAndValue: attr: [%s]", attr)
- log.Printf("findAttrAndValue:value: [%s]", string(value))
- }
- return
-}
-
-func (lr *LDIFReader) readLDIFEntryIntoSlice() ([][]byte, error) {
- entry := make([][]byte, 0, 10)
- linecount := -1
-ENTRY:
- for {
- line, err := lr.Reader.ReadBytes('\n')
- // fmt.Printf("len=%d, err=%v, %s", len(line), err, line)
- if err != nil {
- if err == io.EOF {
- lr.NoMoreEntries = true
- if len(entry) == 0 {
- return nil, nil
- }
- break
- }
- return nil, err
- }
- lr.LineCount++
- if line[0] == '\n' || (line[0] == '\r' && line[1] == '\n') {
- if len(entry) == 0 {
- continue ENTRY
- }
- break
- }
- if line[0] == '#' { // comments
- continue ENTRY
- }
- if line[0] == ' ' || line[0] == '\t' { // continuation
- if line[len(line)-2] == '\r' {
- entry[linecount] = append(entry[linecount], line[1:len(line)-2]...) // strip two bytes
- } else {
- entry[linecount] = append(entry[linecount], line[1:len(line)-1]...)
- }
- continue ENTRY
- }
- linecount++
- if line[len(line)-2] == '\r' {
- entry = append(entry, line[:len(line)-2]) // strip two bytes
- } else {
- entry = append(entry, line[:len(line)-1])
- }
- if err != nil {
- break ENTRY
- }
- }
- //for i, line := range entry {
- // fmt.Println(i)
- // fmt.Println(hex.Dump(line))
- //}
- return entry, nil
-}
-
-func decodeBase64(encodedBytes []byte) ([]byte, error) {
- decodedValue := make([]byte, stdBase64.DecodedLen(len(encodedBytes)))
- count, err := stdBase64.Decode(decodedValue, encodedBytes)
- if err != nil || count == 0 {
- return nil, NewLDAPError(ErrorLDIFRead, "Error decoding base64 value")
- }
- return decodedValue[:count], nil
-}
diff --git a/vendor/github.com/mavricknz/ldap/ldifWriter.go b/vendor/github.com/mavricknz/ldap/ldifWriter.go
deleted file mode 100644
index bcdf893d4d5..00000000000
--- a/vendor/github.com/mavricknz/ldap/ldifWriter.go
+++ /dev/null
@@ -1,223 +0,0 @@
-package ldap
-
-import (
- "bufio"
- "bytes"
- "encoding/base64"
- "io"
- "strings"
-)
-
-var changetype = "changetype"
-var ldifSep string = ":"
-var lineSep string = "\n"
-
-type LDIFWriter struct {
- Writer *bufio.Writer
- EncAsBinary func(string) bool
- LineCount uint64
- recordCount uint64
-}
-
-func NewLDIFWriter(writer io.Writer) (*LDIFWriter, error) {
- lw := &LDIFWriter{
- Writer: bufio.NewWriter(writer),
- EncAsBinary: IsBinary,
- }
- return lw, nil
-}
-
-func (lw *LDIFWriter) WriteLDIFRecord(record LDIFRecord) error {
- // TODO: Controls for all.
- if record == nil {
- return NewLDAPError(ErrorLDIFWrite, "nil record")
- }
- switch record.RecordType() {
- case AddRecord:
- rec := record.(*AddRequest)
- if err := lw.writeDN(rec.Entry.DN); err != nil {
- return err
- }
- if err := lw.writeAttrLine(changetype, "add"); err != nil {
- return err
- }
- if err := lw.writeEntry(rec.Entry); err != nil {
- return err
- }
-
- case ModifyRecord:
- rec := record.(*ModifyRequest)
- if err := lw.writeDN(rec.DN); err != nil {
- return err
- }
- if err := lw.writeAttrLine(changetype, "modify"); err != nil {
- return err
- }
- if err := lw.writeMods(rec.Mods); err != nil {
- return err
- }
-
- case ModDnRecord:
- //TODO
- case ModRdnRecord:
- //TODO
- case DeleteRecord:
- rec := record.(*DeleteRequest)
-
- if err := lw.writeDN(rec.DN); err != nil {
- return err
- }
- if err := lw.writeAttrLine(changetype, "delete"); err != nil {
- return err
- }
-
- case EntryRecord:
- rec := record.(*Entry)
- if err := lw.writeDN(rec.DN); err != nil {
- return err
- }
- if err := lw.writeEntry(rec); err != nil {
- return err
- }
-
- }
- // blank line between records.
- if _, werr := lw.Writer.WriteString(lineSep); werr != nil {
- return werr
- }
-
- lw.Writer.Flush()
- return nil
-}
-
-func (lw *LDIFWriter) writeDN(DN string) (err error) {
- // TODO need canonical DN?
- if len(DN) == 0 {
- return NewLDAPError(ErrorLDIFWrite, "DN has zero length.")
- }
- if err := lw.writeAttrLine("dn", DN); err != nil {
- return err
- }
- return
-}
-
-func (lw *LDIFWriter) writeEntry(e *Entry) error {
- for _, attr := range e.Attributes {
- for _, val := range attr.Values {
- if lw.EncAsBinary(attr.Name) || NeedsBase64Encoding(val) {
- if err := lw.writeEncAttr(attr.Name, val); err != nil {
- return err
- }
- } else {
- if err := lw.writeAttrLine(attr.Name, val); err != nil {
- return err
- }
- }
- }
- }
- return nil
-}
-
-func (lw *LDIFWriter) writeEncAttr(attrName, val string) error {
- _, werr := lw.Writer.WriteString(attrName + ldifSep + ldifSep + " ")
- if werr != nil {
- return werr
- }
- _, werr = lw.Writer.WriteString(toBase64(val))
- if werr != nil {
- return werr
- }
- _, werr = lw.Writer.WriteString(lineSep)
- if werr != nil {
- return werr
- }
- return nil
-}
-
-func NeedsBase64Encoding(val string) bool {
- // zero len
- if len(val) == 0 {
- return false
- }
- // starts with a space, a colon, or a less than
- if val[0] == ' ' || val[0] == ':' || val[0] == '<' {
- return true
- }
- // final char is a space.
- if len(val) > 1 && strings.HasSuffix(val, " ") {
- return true
- }
-
- sl := len(val)
- for i := 0; i < sl; i++ {
- // outside ascii
- if val[i] > 127 || val[i] < 0 {
- return true
- }
- switch val[i] {
- case 0, 10, 14: // null, new line, carriage return
- return true
- }
- }
- return false
-}
-
-func (lw *LDIFWriter) writeMods(mods []Mod) error {
- for _, mod := range mods {
- if err := lw.writeAttrLine(ModMap[mod.ModOperation], mod.Modification.Name); err != nil {
- return err
- }
- for _, val := range mod.Modification.Values {
- if err := lw.writeAttrLine(mod.Modification.Name, val); err != nil {
- return err
- }
- }
- _, werr := lw.Writer.WriteString("-\n")
- if werr != nil {
- return werr
- }
- }
- return nil
-}
-
-func (lw *LDIFWriter) writeAttrLine(attrName, value string) error {
- _, werr := lw.Writer.WriteString(attrName)
- if werr != nil {
- return werr
- }
- _, werr = lw.Writer.WriteString(ldifSep)
- if werr != nil {
- return werr
- }
- _, werr = lw.Writer.WriteString(" ")
- if werr != nil {
- return werr
- }
- _, werr = lw.Writer.WriteString(value)
- if werr != nil {
- return werr
- }
- _, werr = lw.Writer.WriteString(lineSep)
- if werr != nil {
- return werr
- }
- return nil
-}
-
-func toBase64(data string) string {
- var buf bytes.Buffer
- encoder := base64.NewEncoder(base64.StdEncoding, &buf)
- encoder.Write([]byte(data))
- encoder.Close()
- return buf.String()
-}
-
-func IsBinary(attrName string) (isBinary bool) {
- if strings.Contains(strings.ToLower(attrName), ";binary") {
- return true
- }
- if strings.Contains(strings.ToLower(attrName), "jpegphoto") {
- return true
- }
- return
-}
diff --git a/vendor/github.com/mavricknz/ldap/matchingRule.go b/vendor/github.com/mavricknz/ldap/matchingRule.go
deleted file mode 100644
index ed02631979a..00000000000
--- a/vendor/github.com/mavricknz/ldap/matchingRule.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This package provides LDAP MatchingRule functions.
-package ldap
-
-// At the moment just helper values for ServerSideSorting.
-const (
- MatchingRule_numericStringOrderingMatch = "2.5.13.9" // 1.3.6.1.4.1.1466.115.121.1.36
- MatchingRule_numericStringMatch = "2.5.13.8" // 1.3.6.1.4.1.1466.115.121.1.36
- MatchingRule_caseExactSubstringsMatch = "2.5.13.7" // 1.3.6.1.4.1.1466.115.121.1.58
- MatchingRule_caseExactOrderingMatch = "2.5.13.6" // 1.3.6.1.4.1.1466.115.121.1.15
- MatchingRule_caseExactMatch = "2.5.13.5" // 1.3.6.1.4.1.1466.115.121.1.15
- MatchingRule_caseIgnoreSubstringsMatch = "2.5.13.4" // 1.3.6.1.4.1.1466.115.121.1.58
- MatchingRule_keywordMatch = "2.5.13.33" // 1.3.6.1.4.1.1466.115.121.1.15
- MatchingRule_wordMatch = "2.5.13.32" // 1.3.6.1.4.1.1466.115.121.1.15
- MatchingRule_directoryStringFirstComponentMatch = "2.5.13.31" // 1.3.6.1.4.1.1466.115.121.1.15
- MatchingRule_objectIdentifierFirstComponentMatch = "2.5.13.30" // 1.3.6.1.4.1.1466.115.121.1.38
- MatchingRule_caseIgnoreOrderingMatch = "2.5.13.3" // 1.3.6.1.4.1.1466.115.121.1.15
- MatchingRule_integerFirstComponentMatch = "2.5.13.29" // 1.3.6.1.4.1.1466.115.121.1.27
- MatchingRule_generalizedTimeOrderingMatch = "2.5.13.28" // 1.3.6.1.4.1.1466.115.121.1.24
- MatchingRule_generalizedTimeMatch = "2.5.13.27" // 1.3.6.1.4.1.1466.115.121.1.24
- MatchingRule_protocolInformationMatch = "2.5.13.24" // 1.3.6.1.4.1.1466.115.121.1.42
- MatchingRule_uniqueMemberMatch = "2.5.13.23" // 1.3.6.1.4.1.1466.115.121.1.34
- MatchingRule_presentationAddressMatch = "2.5.13.22" // 1.3.6.1.4.1.1466.115.121.1.43
- MatchingRule_telephoneNumberSubstringsMatch = "2.5.13.21" // 1.3.6.1.4.1.1466.115.121.1.58
- MatchingRule_telephoneNumberMatch = "2.5.13.20" // 1.3.6.1.4.1.1466.115.121.1.50
- MatchingRule_caseIgnoreMatch = "2.5.13.2" // 1.3.6.1.4.1.1466.115.121.1.15
- MatchingRule_octetStringSubstringsMatch = "2.5.13.19" // 1.3.6.1.4.1.1466.115.121.1.58
- MatchingRule_octetStringOrderingMatch = "2.5.13.18" // 1.3.6.1.4.1.1466.115.121.1.40
- MatchingRule_octetStringMatch = "2.5.13.17" // 1.3.6.1.4.1.1466.115.121.1.40
- MatchingRule_bitStringMatch = "2.5.13.16" // 1.3.6.1.4.1.1466.115.121.1.6
- MatchingRule_integerOrderingMatch = "2.5.13.15" // 1.3.6.1.4.1.1466.115.121.1.27
- MatchingRule_integerMatch = "2.5.13.14" // 1.3.6.1.4.1.1466.115.121.1.27
- MatchingRule_booleanMatch = "2.5.13.13" // 1.3.6.1.4.1.1466.115.121.1.7
- MatchingRule_caseIgnoreListSubstringsMatch = "2.5.13.12" // 1.3.6.1.4.1.1466.115.121.1.58
- MatchingRule_caseIgnoreListMatch = "2.5.13.11" // 1.3.6.1.4.1.1466.115.121.1.41
- MatchingRule_numericStringSubstringsMatch = "2.5.13.10" // 1.3.6.1.4.1.1466.115.121.1.58
- MatchingRule_distinguishedNameMatch = "2.5.13.1" // 1.3.6.1.4.1.1466.115.121.1.12
- MatchingRule_objectIdentifierMatch = "2.5.13.0" // 1.3.6.1.4.1.1466.115.121.1.38
- MatchingRule_authPasswordMatch = "1.3.6.1.4.1.4203.1.2.3" // 1.3.6.1.4.1.4203.1.1.2 DESC 'authentication password matching rule'
- MatchingRule_authPasswordExactMatch = "1.3.6.1.4.1.4203.1.2.2" // 1.3.6.1.4.1.4203.1.1.2 DESC 'authentication password exact matching rule'
- MatchingRule_caseExactIA5SubstringsMatch = "1.3.6.1.4.1.26027.1.4.902" // 1.3.6.1.4.1.1466.115.121.1.58
- MatchingRule_partialDateAndTimeMatchingRule = "1.3.6.1.4.1.26027.1.4.7" // 1.3.6.1.4.1.1466.115.121.1.24
- MatchingRule_relativeTimeLTOrderingMatch = "1.3.6.1.4.1.26027.1.4.6" // 1.3.6.1.4.1.1466.115.121.1.24
- MatchingRule_relativeTimeGTOrderingMatch = "1.3.6.1.4.1.26027.1.4.5" // 1.3.6.1.4.1.1466.115.121.1.24
- MatchingRule_historicalCsnOrderingMatch = "1.3.6.1.4.1.26027.1.4.4" // 1.3.6.1.4.1.1466.115.121.1.40
- MatchingRule_ds_mr_user_password_equality = "1.3.6.1.4.1.26027.1.4.3" // 1.3.6.1.4.1.26027.1.3.1 DESC 'user password matching rule'
- MatchingRule_ds_mr_user_password_exact = "1.3.6.1.4.1.26027.1.4.2" // 1.3.6.1.4.1.26027.1.3.1 DESC 'user password exact matching rule'
- MatchingRule_ds_mr_double_metaphone_approx = "1.3.6.1.4.1.26027.1.4.1" // 1.3.6.1.4.1.26027.1.3.1 DESC 'Double Metaphone Approximate Match'
- MatchingRule_caseIgnoreIA5SubstringsMatch = "1.3.6.1.4.1.1466.109.114.3" // 1.3.6.1.4.1.1466.115.121.1.58
- MatchingRule_caseIgnoreIA5Match = "1.3.6.1.4.1.1466.109.114.2" // 1.3.6.1.4.1.1466.115.121.1.26
- MatchingRule_caseExactIA5Match = "1.3.6.1.4.1.1466.109.114.1" // 1.3.6.1.4.1.1466.115.121.1.26
- MatchingRule_uuidOrderingMatch = "1.3.6.1.1.16.3" // 1.3.6.1.1.16.1
- MatchingRule_uuidMatch = "1.3.6.1.1.16.2" // 1.3.6.1.1.16.1
-)
diff --git a/vendor/github.com/mavricknz/ldap/moddn.go b/vendor/github.com/mavricknz/ldap/moddn.go
deleted file mode 100644
index 23cc5559edd..00000000000
--- a/vendor/github.com/mavricknz/ldap/moddn.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ldap
-
-import (
- "github.com/mavricknz/asn1-ber"
-)
-
-//ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
-//entry LDAPDN,
-//newrdn RelativeLDAPDN,
-//deleteoldrdn BOOLEAN,
-//newSuperior [0] LDAPDN OPTIONAL }
-//
-//ModifyDNResponse ::= [APPLICATION 13] LDAPResult
-
-type ModDnRequest struct {
- DN string
- NewRDN string
- DeleteOldDn bool
- NewSuperiorDN string
- Controls []Control
-}
-
-//Untested.
-func (l *LDAPConnection) ModDn(req *ModDnRequest) error {
- messageID, ok := l.nextMessageID()
- if !ok {
- return NewLDAPError(ErrorClosing, "MessageID channel is closed.")
- }
-
- encodedModDn := encodeModDnRequest(req)
-
- packet, err := requestBuildPacket(messageID, encodedModDn, req.Controls)
- if err != nil {
- return err
- }
-
- return l.sendReqRespPacket(messageID, packet)
-}
-
-func encodeModDnRequest(req *ModDnRequest) (p *ber.Packet) {
- p = ber.Encode(ber.ClassApplication, ber.TypeConstructed,
- ApplicationModifyDNRequest, nil, ApplicationMap[ApplicationModifyDNRequest])
- p.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, req.DN, "LDAPDN"))
- p.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, req.NewRDN, "NewRDN"))
- p.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimative, ber.TagBoolean, req.DeleteOldDn, "deleteoldrdn"))
- if len(req.NewSuperiorDN) > 0 {
- p.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimative,
- ber.TagEOC, req.NewSuperiorDN, "NewSuperiorDN"))
- }
- return
-}
diff --git a/vendor/github.com/mavricknz/ldap/modify.go b/vendor/github.com/mavricknz/ldap/modify.go
deleted file mode 100644
index 3b828ff75db..00000000000
--- a/vendor/github.com/mavricknz/ldap/modify.go
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ldap
-
-import (
- "fmt"
- "github.com/mavricknz/asn1-ber"
-)
-
-const (
- ModAdd = 0
- ModDelete = 1
- ModReplace = 2
- ModIncrement = 3
-)
-
-var ModMap map[uint8]string = map[uint8]string{
- ModAdd: "add",
- ModDelete: "delete",
- ModReplace: "replace",
- ModIncrement: "increment",
-}
-
-/* Reuse search struct, should Values be a [][]byte
-type EntryAttribute struct {
- Name string
- Values []string
-}
-*/
-type Mod struct {
- ModOperation uint8
- Modification EntryAttribute
-}
-
-type ModifyRequest struct {
- DN string
- Mods []Mod
- Controls []Control
-}
-
-func (req *ModifyRequest) RecordType() uint8 {
- return ModifyRecord
-}
-
-/* Example...
-func modifyTest(l *ldap.Conn){
- var modDNs []string = []string{"cn=test,ou=People,dc=example,dc=com"}
- var modAttrs []string = []string{"cn"}
- var modValues []string = []string{"aaa", "bbb", "ccc"}
- modreq := ldap.NewModifyRequest(modDNs[0])
- mod := ldap.NewMod(ldap.ModAdd, modAttrs[0], modValues)
- modreq.AddMod(mod)
- err := l.Modify(modreq)
- if err != nil {
- fmt.Printf("Modify : %s : result = %d\n",modDNs[0],err.ResultCode)
- return
- }
- fmt.Printf("Modify Success")
-}
-
- ModifyRequest ::= [APPLICATION 6] SEQUENCE {
- object LDAPDN,
- changes SEQUENCE OF change SEQUENCE {
- operation ENUMERATED {
- add (0),
- delete (1),
- replace (2),
- ... },
- modification PartialAttribute } }
-*/
-func (l *LDAPConnection) Modify(modReq *ModifyRequest) error {
- messageID, ok := l.nextMessageID()
- if !ok {
- return NewLDAPError(ErrorClosing, "MessageID channel is closed.")
- }
- encodedModify := encodeModifyRequest(modReq)
-
- packet, err := requestBuildPacket(messageID, encodedModify, modReq.Controls)
- if err != nil {
- return err
- }
-
- return l.sendReqRespPacket(messageID, packet)
-}
-
-func (req *ModifyRequest) Bytes() []byte {
- return encodeModifyRequest(req).Bytes()
-}
-
-func encodeModifyRequest(req *ModifyRequest) (p *ber.Packet) {
- modpacket := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, ApplicationMap[ApplicationModifyRequest])
- modpacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, req.DN, "LDAP DN"))
- seqOfChanges := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
- for _, mod := range req.Mods {
- modification := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Modification")
- op := ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagEnumerated, uint64(mod.ModOperation), "Modify Op ("+ModMap[mod.ModOperation]+")")
- modification.AppendChild(op)
- partAttr := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute")
-
- partAttr.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, mod.Modification.Name, "AttributeDescription"))
- valuesSet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "Attribute Value Set")
- for _, val := range mod.Modification.Values {
- value := ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, val, "AttributeValue")
- valuesSet.AppendChild(value)
- }
- partAttr.AppendChild(valuesSet)
- modification.AppendChild(partAttr)
- seqOfChanges.AppendChild(modification)
- }
- modpacket.AppendChild(seqOfChanges)
-
- return modpacket
-}
-
-func NewModifyRequest(dn string) (req *ModifyRequest) {
- req = &ModifyRequest{
- DN: dn,
- Mods: make([]Mod, 0),
- Controls: make([]Control, 0),
- }
- return
-}
-
-// Basic LDIF dump, no formating, etc
-func (req *ModifyRequest) String() (dump string) {
- dump = fmt.Sprintf("dn: %s\n", req.DN)
- dump = fmt.Sprintf("changetype: modify\n")
- for _, mod := range req.Mods {
- dump += mod.DumpMod()
- }
- return
-}
-
-// Basic LDIF dump, no formating, etc
-func (mod *Mod) DumpMod() (dump string) {
- dump += fmt.Sprintf("%s: %s\n", ModMap[mod.ModOperation], mod.Modification.Name)
- for _, val := range mod.Modification.Values {
- dump += fmt.Sprintf("%s: %s\n", mod.Modification.Name, val)
- }
- dump += "-\n"
- return dump
-}
-
-func NewMod(modType uint8, attr string, values []string) (mod *Mod) {
- if values == nil {
- values = []string{}
- }
- partEntryAttr := EntryAttribute{Name: attr, Values: values}
- mod = &Mod{ModOperation: modType, Modification: partEntryAttr}
- return
-}
-
-func (req *ModifyRequest) AddMod(mod *Mod) {
- req.Mods = append(req.Mods, *mod)
-}
-
-func (req *ModifyRequest) AddMods(mods []Mod) {
- req.Mods = append(req.Mods, mods...)
-}
-
-func (req *ModifyRequest) AddControl(control Control) {
- if req.Controls == nil {
- req.Controls = make([]Control, 0)
- }
- req.Controls = append(req.Controls, control)
-}
diff --git a/vendor/github.com/mavricknz/ldap/request.go b/vendor/github.com/mavricknz/ldap/request.go
deleted file mode 100644
index 269d9a36e32..00000000000
--- a/vendor/github.com/mavricknz/ldap/request.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ldap
-
-import (
- "fmt"
- "github.com/mavricknz/asn1-ber"
- "time"
-)
-
-// messageID - messageID obtained from Conn.nextMessageID()
-// opPacket - the operation BER encoded Packet e.g. Search/Modify/Delete/Compare
-// controls - the controls to add to the Request
-// returns the BER encoded LDAP request or an Error
-func requestBuildPacket(messageID uint64, opPacket *ber.Packet, controls []Control) (p *ber.Packet, err error) {
-
- p = ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
- p.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, messageID, "MessageID"))
- p.AppendChild(opPacket)
-
- if controls != nil && len(controls) > 0 {
- cPacket, err := encodeControls(controls)
- if err != nil {
- return nil, err
- }
- p.AppendChild(cPacket)
- }
- return
-}
-
-func (l *LDAPConnection) sendReqRespPacket(messageID uint64, packet *ber.Packet) error {
-
- if l.Debug {
- ber.PrintPacket(packet)
- }
-
- channel, err := l.sendMessage(packet)
-
- if err != nil {
- return err
- }
-
- if channel == nil {
- return NewLDAPError(ErrorNetwork, "Could not send message")
- }
-
- defer l.finishMessage(messageID)
- if l.Debug {
- fmt.Printf("%d: waiting for response\n", messageID)
- }
-
- var responsePacket *ber.Packet = nil
- var ok bool
-
- // If a timeout is set then use it, else use default.
- timeout := l.ReadTimeout
- if uint64(timeout) == 0 {
- timeout = DefaultTimeout
- }
- select {
- case responsePacket, ok = <-channel:
- if !ok {
- return NewLDAPError(ErrorClosing, "Response Channel Closed")
- }
- case <-time.After(timeout):
- if l.AbandonMessageOnReadTimeout {
- err = l.Abandon(messageID)
- if err != nil {
- return NewLDAPError(ErrorNetwork,
- "Timeout waiting for Message and error on Abandon")
- }
- }
- return NewLDAPError(ErrorNetwork, "Timeout waiting for Message")
- }
-
- if l.Debug {
- fmt.Printf("%d: got response %p\n", messageID, responsePacket)
- }
-
- if responsePacket == nil {
- return NewLDAPError(ErrorNetwork, "Could not retrieve message")
- }
-
- if l.Debug {
- if err := addLDAPDescriptions(responsePacket); err != nil {
- return err
- }
- ber.PrintPacket(responsePacket)
- }
-
- result_code, result_description := getLDAPResultCode(responsePacket)
-
- if result_code != 0 {
- return NewLDAPError(result_code, result_description)
- }
-
- if l.Debug {
- fmt.Printf("%d: returning\n", messageID)
- }
- return nil
-}
diff --git a/vendor/github.com/mavricknz/ldap/search.go b/vendor/github.com/mavricknz/ldap/search.go
deleted file mode 100644
index 0d9015f8e33..00000000000
--- a/vendor/github.com/mavricknz/ldap/search.go
+++ /dev/null
@@ -1,384 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// File contains Search functionality
-package ldap
-
-import (
- "fmt"
- "github.com/mavricknz/asn1-ber"
- "log"
-)
-
-const (
- ScopeBaseObject = 0
- ScopeSingleLevel = 1
- ScopeWholeSubtree = 2
-)
-
-var ScopeMap = map[int]string{
- ScopeBaseObject: "Base Object",
- ScopeSingleLevel: "Single Level",
- ScopeWholeSubtree: "Whole Subtree",
-}
-
-const (
- NeverDerefAliases = 0
- DerefInSearching = 1
- DerefFindingBaseObj = 2
- DerefAlways = 3
-)
-
-const (
- SearchResultEntry = ApplicationSearchResultEntry
- SearchResultReference = ApplicationSearchResultReference
- SearchResultDone = ApplicationSearchResultDone
-)
-
-var DerefMap = map[int]string{
- NeverDerefAliases: "NeverDerefAliases",
- DerefInSearching: "DerefInSearching",
- DerefFindingBaseObj: "DerefFindingBaseObj",
- DerefAlways: "DerefAlways",
-}
-
-type SearchResult struct {
- Entries []*Entry
- Referrals []string
- Controls []Control
-}
-
-type DiscreteSearchResult struct {
- SearchResultType uint8
- Entry *Entry
- Referrals []string
- Controls []Control
-}
-
-type ConnectionInfo struct {
- Conn *LDAPConnection
- MessageID uint64
-}
-
-type SearchResultHandler interface {
- ProcessDiscreteResult(*DiscreteSearchResult, *ConnectionInfo) (bool, error)
-}
-
-// SearchRequest passed to Search functions.
-type SearchRequest struct {
- BaseDN string
- Scope int
- DerefAliases int
- SizeLimit int
- TimeLimit int
- TypesOnly bool
- Filter string
- Attributes []string
- Controls []Control
-}
-
-//NewSimpleSearchRequest only requires four parameters and defaults the
-//other returned SearchRequest values to typical values...
-//
-// DerefAliases: NeverDerefAliases
-// SizeLimit: 0
-// TimeLimit: 0
-// TypesOnly: false
-// Controls: nil
-func NewSimpleSearchRequest(
- BaseDN string,
- Scope int,
- Filter string,
- Attributes []string,
-) *SearchRequest {
- return &SearchRequest{
- BaseDN: BaseDN,
- Scope: Scope,
- DerefAliases: NeverDerefAliases,
- SizeLimit: 0,
- TimeLimit: 0,
- TypesOnly: false,
- Filter: Filter,
- Attributes: Attributes,
- Controls: nil,
- }
-}
-
-func NewSearchRequest(
- BaseDN string,
- Scope, DerefAliases, SizeLimit, TimeLimit int,
- TypesOnly bool,
- Filter string,
- Attributes []string,
- Controls []Control,
-) *SearchRequest {
- return &SearchRequest{
- BaseDN: BaseDN,
- Scope: Scope,
- DerefAliases: DerefAliases,
- SizeLimit: SizeLimit,
- TimeLimit: TimeLimit,
- TypesOnly: TypesOnly,
- Filter: Filter,
- Attributes: Attributes,
- Controls: Controls,
- }
-}
-
-//SearchWithPaging adds a paging control to the the searchRequest, with a size of pagingSize.
-//It combines all the paged results into the returned SearchResult. It is a helper function for
-//use with servers that require paging for certain result sizes (AD?).
-//
-//It is NOT an efficent way to process huge result sets i.e. it doesn't process on a pageSize
-//number of entries, it returns the combined result.
-func (l *LDAPConnection) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
- pagingControl := NewControlPaging(pagingSize)
- searchRequest.AddControl(pagingControl)
- allResults := new(SearchResult)
-
- for i := 0; ; i++ {
- searchResult := new(SearchResult)
- err := l.SearchWithHandler(searchRequest, searchResult, nil)
- if err != nil {
- return allResults, err
- }
-
- allResults.Entries = append(allResults.Entries, searchResult.Entries...)
- allResults.Referrals = append(allResults.Referrals, searchResult.Referrals...)
- allResults.Controls = append(allResults.Controls, searchResult.Controls...)
-
- _, pagingResponsePacket := FindControl(searchResult.Controls, ControlTypePaging)
- // If initial result and no paging control then server doesn't support paging
- if pagingResponsePacket == nil && i == 0 {
- if l.Debug {
- fmt.Println("Requested paging but no control returned, control unsupported.")
- }
- return allResults, nil
- } else if pagingResponsePacket == nil {
- return allResults, NewLDAPError(ErrorMissingControl, "Expected paging Control, it was not found.")
- }
- pagingControl.SetCookie(pagingResponsePacket.(*ControlPaging).Cookie)
- if len(pagingControl.Cookie) == 0 {
- break
- }
- }
- return allResults, nil
-}
-
-//ProcessDiscreteResult handles an individual result from a server. Member of the
-//SearchResultHandler interface. Results are placed into a SearchResult.
-func (sr *SearchResult) ProcessDiscreteResult(dsr *DiscreteSearchResult, connInfo *ConnectionInfo) (stopProcessing bool, err error) {
- switch dsr.SearchResultType {
- case SearchResultEntry:
- sr.Entries = append(sr.Entries, dsr.Entry)
- case SearchResultDone:
- if dsr.Controls != nil {
- sr.Controls = append(sr.Controls, dsr.Controls...)
- }
- case SearchResultReference:
- sr.Referrals = append(sr.Referrals, dsr.Referrals...)
- }
- return false, nil
-}
-
-//Search is a blocking search. nil error on success.
-func (l *LDAPConnection) Search(searchRequest *SearchRequest) (*SearchResult, error) {
- result := &SearchResult{
- Entries: make([]*Entry, 0),
- Referrals: make([]string, 0),
- Controls: make([]Control, 0)}
-
- err := l.SearchWithHandler(searchRequest, result, nil)
- if err != nil {
- return result, err
- }
- return result, nil
-}
-
-func encodeSearchRequest(req *SearchRequest) (*ber.Packet, error) {
- searchRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request")
- searchRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, req.BaseDN, "Base DN"))
- searchRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagEnumerated, uint64(req.Scope), "Scope"))
- searchRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagEnumerated, uint64(req.DerefAliases), "Deref Aliases"))
- searchRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, uint64(req.SizeLimit), "Size Limit"))
- searchRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimative, ber.TagInteger, uint64(req.TimeLimit), "Time Limit"))
- searchRequest.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimative, ber.TagBoolean, req.TypesOnly, "Types Only"))
- filterPacket, err := CompileFilter(req.Filter)
- if err != nil {
- return nil, err
- }
- searchRequest.AppendChild(filterPacket)
- attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
- for _, attribute := range req.Attributes {
- attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimative, ber.TagOctetString, attribute, "Attribute"))
- }
- searchRequest.AppendChild(attributesPacket)
- return searchRequest, nil
-}
-
-//AddControl adds the provided control to a SearchRequest
-func (req *SearchRequest) AddControl(control Control) {
- if req.Controls == nil {
- req.Controls = make([]Control, 0)
- }
- req.Controls = append(req.Controls, control)
-}
-
-// SearchResult decoded to Entry,Controls,Referral
-func decodeSearchResponse(packet *ber.Packet) (discreteSearchResult *DiscreteSearchResult, err error) {
- discreteSearchResult = new(DiscreteSearchResult)
- switch packet.Children[1].Tag {
- case SearchResultEntry:
- discreteSearchResult.SearchResultType = SearchResultEntry
- entry := new(Entry)
- entry.DN = packet.Children[1].Children[0].ValueString()
- for _, child := range packet.Children[1].Children[1].Children {
- attr := new(EntryAttribute)
- attr.Name = child.Children[0].ValueString()
- for _, value := range child.Children[1].Children {
- attr.Values = append(attr.Values, value.ValueString())
- }
- entry.Attributes = append(entry.Attributes, attr)
- }
- discreteSearchResult.Entry = entry
- return discreteSearchResult, nil
- case SearchResultDone:
- discreteSearchResult.SearchResultType = SearchResultDone
- result_code, result_description := getLDAPResultCode(packet)
- if result_code != 0 {
- return discreteSearchResult, NewLDAPError(result_code, result_description)
- }
-
- if len(packet.Children) == 3 {
- controls := make([]Control, 0)
- for _, child := range packet.Children[2].Children {
- // child.Children[0].ValueString() = control oid
- decodeFunc, present := ControlDecodeMap[child.Children[0].ValueString()]
- if present {
- c, _ := decodeFunc(child)
- controls = append(controls, c)
- } else {
- // not fatal but definately a warning
- log.Println("Couldn't decode Control : " + child.Children[0].ValueString())
- }
- }
- discreteSearchResult.Controls = controls
- }
- return discreteSearchResult, nil
- case SearchResultReference:
- discreteSearchResult.SearchResultType = SearchResultReference
- for ref := range packet.Children[1].Children {
- discreteSearchResult.Referrals = append(discreteSearchResult.Referrals, packet.Children[1].Children[ref].ValueString())
- }
- return discreteSearchResult, nil
- }
- return nil, NewLDAPError(ErrorDecoding, "Couldn't decode search result.")
-}
-
-func sendError(errChannel chan<- error, err error) error {
- if errChannel != nil {
- go func() {
- errChannel <- err
- }()
- }
- return err
-}
-
-//SearchWithHandler is the workhorse. Sends requests, decodes results and passes
-//on to SearchResultHandlers to process.
-// SearchResultHandler, an interface, implemeneted by SearchResult.
-// Handles the discreteSearchResults. Can provide own implemented to work on
-// a result by result basis.
-// errorChan - if nil then blocking, else error returned via channel upon completion.
-// returns error if blocking.
-func (l *LDAPConnection) SearchWithHandler(
- searchRequest *SearchRequest, resultHandler SearchResultHandler, errorChan chan<- error,
-) error {
- messageID, ok := l.nextMessageID()
- if !ok {
- err := NewLDAPError(ErrorClosing, "MessageID channel is closed.")
- return sendError(errorChan, err)
- }
-
- searchPacket, err := encodeSearchRequest(searchRequest)
-
- if err != nil {
- return sendError(errorChan, err)
- }
-
- packet, err := requestBuildPacket(messageID, searchPacket, searchRequest.Controls)
- if err != nil {
- return sendError(errorChan, err)
- }
-
- if l.Debug {
- ber.PrintPacket(packet)
- }
-
- channel, err := l.sendMessage(packet)
-
- if err != nil {
- return sendError(errorChan, err)
- }
- if channel == nil {
- err = NewLDAPError(ErrorNetwork, "Could not send message")
- return sendError(errorChan, err)
- }
- defer l.finishMessage(messageID)
-
- connectionInfo := &ConnectionInfo{
- Conn: l,
- MessageID: messageID,
- }
-
- for {
- if l.Debug {
- fmt.Printf("%d: waiting for response\n", messageID)
- }
- packet, ok = <-channel
-
- if l.Debug {
- fmt.Printf("%d: got response %p, %v\n", messageID, packet, ok)
- }
-
- if !ok {
- return NewLDAPError(ErrorClosing, "Response Channel Closed")
- }
-
- if packet == nil {
- err = NewLDAPError(ErrorNetwork, "Could not retrieve message")
- return sendError(errorChan, err)
- }
-
- if l.Debug {
- if err := addLDAPDescriptions(packet); err != nil {
- return sendError(errorChan, err)
- }
- ber.PrintPacket(packet)
- }
-
- discreteSearchResult, err := decodeSearchResponse(packet)
-
- if err != nil {
- return sendError(errorChan, err)
- }
-
- stop, err := resultHandler.ProcessDiscreteResult(discreteSearchResult, connectionInfo)
- if err != nil {
- return sendError(errorChan, err)
- }
-
- if discreteSearchResult.SearchResultType == SearchResultDone || stop {
- break
- }
- }
- return sendError(errorChan, nil)
-}
-
-func (sr *SearchResult) String() (dump string) {
- for _, entry := range sr.Entries {
- dump = fmt.Sprint(entry)
- }
- return
-}
diff --git a/vendor/github.com/mgutz/ansi/.gitignore b/vendor/github.com/mgutz/ansi/.gitignore
deleted file mode 100644
index 9ed3b07cefe..00000000000
--- a/vendor/github.com/mgutz/ansi/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.test
diff --git a/vendor/github.com/mgutz/ansi/LICENSE b/vendor/github.com/mgutz/ansi/LICENSE
deleted file mode 100644
index 06ce0c3b51f..00000000000
--- a/vendor/github.com/mgutz/ansi/LICENSE
+++ /dev/null
@@ -1,9 +0,0 @@
-The MIT License (MIT)
-Copyright (c) 2013 Mario L. Gutierrez
-
-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.
-
diff --git a/vendor/github.com/mgutz/ansi/README.md b/vendor/github.com/mgutz/ansi/README.md
deleted file mode 100644
index 8f8e20b7e47..00000000000
--- a/vendor/github.com/mgutz/ansi/README.md
+++ /dev/null
@@ -1,121 +0,0 @@
-# ansi
-
-Package ansi is a small, fast library to create ANSI colored strings and codes.
-
-## Install
-
-Get it
-
-```sh
-go get -u github.com/mgutz/ansi
-```
-
-## Example
-
-```go
-import "github.com/mgutz/ansi"
-
-// colorize a string, SLOW
-msg := ansi.Color("foo", "red+b:white")
-
-// create a FAST closure function to avoid computation of ANSI code
-phosphorize := ansi.ColorFunc("green+h:black")
-msg = phosphorize("Bring back the 80s!")
-msg2 := phospohorize("Look, I'm a CRT!")
-
-// cache escape codes and build strings manually
-lime := ansi.ColorCode("green+h:black")
-reset := ansi.ColorCode("reset")
-
-fmt.Println(lime, "Bring back the 80s!", reset)
-```
-
-Other examples
-
-```go
-Color(s, "red") // red
-Color(s, "red+b") // red bold
-Color(s, "red+B") // red blinking
-Color(s, "red+u") // red underline
-Color(s, "red+bh") // red bold bright
-Color(s, "red:white") // red on white
-Color(s, "red+b:white+h") // red bold on white bright
-Color(s, "red+B:white+h") // red blink on white bright
-Color(s, "off") // turn off ansi codes
-```
-
-To view color combinations, from project directory in terminal.
-
-```sh
-go test
-```
-
-## Style format
-
-```go
-"foregroundColor+attributes:backgroundColor+attributes"
-```
-
-Colors
-
-* black
-* red
-* green
-* yellow
-* blue
-* magenta
-* cyan
-* white
-* 0...255 (256 colors)
-
-Foreground Attributes
-
-* B = Blink
-* b = bold
-* h = high intensity (bright)
-* i = inverse
-* s = strikethrough
-* u = underline
-
-Background Attributes
-
-* h = high intensity (bright)
-
-## Constants
-
-* ansi.Reset
-* ansi.DefaultBG
-* ansi.DefaultFG
-* ansi.Black
-* ansi.Red
-* ansi.Green
-* ansi.Yellow
-* ansi.Blue
-* ansi.Magenta
-* ansi.Cyan
-* ansi.White
-* ansi.LightBlack
-* ansi.LightRed
-* ansi.LightGreen
-* ansi.LightYellow
-* ansi.LightBlue
-* ansi.LightMagenta
-* ansi.LightCyan
-* ansi.LightWhite
-
-## References
-
-Wikipedia ANSI escape codes [Colors](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors)
-
-General [tips and formatting](http://misc.flogisoft.com/bash/tip_colors_and_formatting)
-
-What about support on Windows? Use [colorable by mattn](https://github.com/mattn/go-colorable).
-Ansi and colorable are used by [logxi](https://github.com/mgutz/logxi) to support logging in
-color on Windows.
-
-## MIT License
-
-Copyright (c) 2013 Mario Gutierrez mario@mgutz.com
-
-See the file LICENSE for copying permission.
-
diff --git a/vendor/github.com/mgutz/ansi/ansi.go b/vendor/github.com/mgutz/ansi/ansi.go
deleted file mode 100644
index dc0413649e5..00000000000
--- a/vendor/github.com/mgutz/ansi/ansi.go
+++ /dev/null
@@ -1,285 +0,0 @@
-package ansi
-
-import (
- "bytes"
- "fmt"
- "strconv"
- "strings"
-)
-
-const (
- black = iota
- red
- green
- yellow
- blue
- magenta
- cyan
- white
- defaultt = 9
-
- normalIntensityFG = 30
- highIntensityFG = 90
- normalIntensityBG = 40
- highIntensityBG = 100
-
- start = "\033["
- bold = "1;"
- blink = "5;"
- underline = "4;"
- inverse = "7;"
- strikethrough = "9;"
-
- // Reset is the ANSI reset escape sequence
- Reset = "\033[0m"
- // DefaultBG is the default background
- DefaultBG = "\033[49m"
- // DefaultFG is the default foreground
- DefaultFG = "\033[39m"
-)
-
-// Black FG
-var Black string
-
-// Red FG
-var Red string
-
-// Green FG
-var Green string
-
-// Yellow FG
-var Yellow string
-
-// Blue FG
-var Blue string
-
-// Magenta FG
-var Magenta string
-
-// Cyan FG
-var Cyan string
-
-// White FG
-var White string
-
-// LightBlack FG
-var LightBlack string
-
-// LightRed FG
-var LightRed string
-
-// LightGreen FG
-var LightGreen string
-
-// LightYellow FG
-var LightYellow string
-
-// LightBlue FG
-var LightBlue string
-
-// LightMagenta FG
-var LightMagenta string
-
-// LightCyan FG
-var LightCyan string
-
-// LightWhite FG
-var LightWhite string
-
-var (
- plain = false
- // Colors maps common color names to their ANSI color code.
- Colors = map[string]int{
- "black": black,
- "red": red,
- "green": green,
- "yellow": yellow,
- "blue": blue,
- "magenta": magenta,
- "cyan": cyan,
- "white": white,
- "default": defaultt,
- }
-)
-
-func init() {
- for i := 0; i < 256; i++ {
- Colors[strconv.Itoa(i)] = i
- }
-
- Black = ColorCode("black")
- Red = ColorCode("red")
- Green = ColorCode("green")
- Yellow = ColorCode("yellow")
- Blue = ColorCode("blue")
- Magenta = ColorCode("magenta")
- Cyan = ColorCode("cyan")
- White = ColorCode("white")
- LightBlack = ColorCode("black+h")
- LightRed = ColorCode("red+h")
- LightGreen = ColorCode("green+h")
- LightYellow = ColorCode("yellow+h")
- LightBlue = ColorCode("blue+h")
- LightMagenta = ColorCode("magenta+h")
- LightCyan = ColorCode("cyan+h")
- LightWhite = ColorCode("white+h")
-}
-
-// ColorCode returns the ANSI color color code for style.
-func ColorCode(style string) string {
- return colorCode(style).String()
-}
-
-// Gets the ANSI color code for a style.
-func colorCode(style string) *bytes.Buffer {
- buf := bytes.NewBufferString("")
- if plain || style == "" {
- return buf
- }
- if style == "reset" {
- buf.WriteString(Reset)
- return buf
- } else if style == "off" {
- return buf
- }
-
- foregroundBackground := strings.Split(style, ":")
- foreground := strings.Split(foregroundBackground[0], "+")
- fgKey := foreground[0]
- fg := Colors[fgKey]
- fgStyle := ""
- if len(foreground) > 1 {
- fgStyle = foreground[1]
- }
-
- bg, bgStyle := "", ""
-
- if len(foregroundBackground) > 1 {
- background := strings.Split(foregroundBackground[1], "+")
- bg = background[0]
- if len(background) > 1 {
- bgStyle = background[1]
- }
- }
-
- buf.WriteString(start)
- base := normalIntensityFG
- if len(fgStyle) > 0 {
- if strings.Contains(fgStyle, "b") {
- buf.WriteString(bold)
- }
- if strings.Contains(fgStyle, "B") {
- buf.WriteString(blink)
- }
- if strings.Contains(fgStyle, "u") {
- buf.WriteString(underline)
- }
- if strings.Contains(fgStyle, "i") {
- buf.WriteString(inverse)
- }
- if strings.Contains(fgStyle, "s") {
- buf.WriteString(strikethrough)
- }
- if strings.Contains(fgStyle, "h") {
- base = highIntensityFG
- }
- }
-
- // if 256-color
- n, err := strconv.Atoi(fgKey)
- if err == nil {
- fmt.Fprintf(buf, "38;5;%d;", n)
- } else {
- fmt.Fprintf(buf, "%d;", base+fg)
- }
-
- base = normalIntensityBG
- if len(bg) > 0 {
- if strings.Contains(bgStyle, "h") {
- base = highIntensityBG
- }
- // if 256-color
- n, err := strconv.Atoi(bg)
- if err == nil {
- fmt.Fprintf(buf, "48;5;%d;", n)
- } else {
- fmt.Fprintf(buf, "%d;", base+Colors[bg])
- }
- }
-
- // remove last ";"
- buf.Truncate(buf.Len() - 1)
- buf.WriteRune('m')
- return buf
-}
-
-// Color colors a string based on the ANSI color code for style.
-func Color(s, style string) string {
- if plain || len(style) < 1 {
- return s
- }
- buf := colorCode(style)
- buf.WriteString(s)
- buf.WriteString(Reset)
- return buf.String()
-}
-
-// ColorFunc creates a closure to avoid computation ANSI color code.
-func ColorFunc(style string) func(string) string {
- if style == "" {
- return func(s string) string {
- return s
- }
- }
- color := ColorCode(style)
- return func(s string) string {
- if plain || s == "" {
- return s
- }
- buf := bytes.NewBufferString(color)
- buf.WriteString(s)
- buf.WriteString(Reset)
- result := buf.String()
- return result
- }
-}
-
-// DisableColors disables ANSI color codes. The default is false (colors are on).
-func DisableColors(disable bool) {
- plain = disable
- if plain {
- Black = ""
- Red = ""
- Green = ""
- Yellow = ""
- Blue = ""
- Magenta = ""
- Cyan = ""
- White = ""
- LightBlack = ""
- LightRed = ""
- LightGreen = ""
- LightYellow = ""
- LightBlue = ""
- LightMagenta = ""
- LightCyan = ""
- LightWhite = ""
- } else {
- Black = ColorCode("black")
- Red = ColorCode("red")
- Green = ColorCode("green")
- Yellow = ColorCode("yellow")
- Blue = ColorCode("blue")
- Magenta = ColorCode("magenta")
- Cyan = ColorCode("cyan")
- White = ColorCode("white")
- LightBlack = ColorCode("black+h")
- LightRed = ColorCode("red+h")
- LightGreen = ColorCode("green+h")
- LightYellow = ColorCode("yellow+h")
- LightBlue = ColorCode("blue+h")
- LightMagenta = ColorCode("magenta+h")
- LightCyan = ColorCode("cyan+h")
- LightWhite = ColorCode("white+h")
- }
-}
diff --git a/vendor/github.com/mgutz/ansi/doc.go b/vendor/github.com/mgutz/ansi/doc.go
deleted file mode 100644
index 43c217e11d3..00000000000
--- a/vendor/github.com/mgutz/ansi/doc.go
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-Package ansi is a small, fast library to create ANSI colored strings and codes.
-
-Installation
-
- # this installs the color viewer and the package
- go get -u github.com/mgutz/ansi/cmd/ansi-mgutz
-
-Example
-
- // colorize a string, SLOW
- msg := ansi.Color("foo", "red+b:white")
-
- // create a closure to avoid recalculating ANSI code compilation
- phosphorize := ansi.ColorFunc("green+h:black")
- msg = phosphorize("Bring back the 80s!")
- msg2 := phospohorize("Look, I'm a CRT!")
-
- // cache escape codes and build strings manually
- lime := ansi.ColorCode("green+h:black")
- reset := ansi.ColorCode("reset")
-
- fmt.Println(lime, "Bring back the 80s!", reset)
-
-Other examples
-
- Color(s, "red") // red
- Color(s, "red+b") // red bold
- Color(s, "red+B") // red blinking
- Color(s, "red+u") // red underline
- Color(s, "red+bh") // red bold bright
- Color(s, "red:white") // red on white
- Color(s, "red+b:white+h") // red bold on white bright
- Color(s, "red+B:white+h") // red blink on white bright
-
-To view color combinations, from terminal
-
- ansi-mgutz
-
-Style format
-
- "foregroundColor+attributes:backgroundColor+attributes"
-
-Colors
-
- black
- red
- green
- yellow
- blue
- magenta
- cyan
- white
-
-Attributes
-
- b = bold foreground
- B = Blink foreground
- u = underline foreground
- h = high intensity (bright) foreground, background
- i = inverse
-
-Wikipedia ANSI escape codes [Colors](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors)
-*/
-package ansi
diff --git a/vendor/github.com/mgutz/ansi/print.go b/vendor/github.com/mgutz/ansi/print.go
deleted file mode 100644
index 806f436bb3a..00000000000
--- a/vendor/github.com/mgutz/ansi/print.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package ansi
-
-import (
- "fmt"
- "sort"
-
- colorable "github.com/mattn/go-colorable"
-)
-
-// PrintStyles prints all style combinations to the terminal.
-func PrintStyles() {
- // for compatibility with Windows, not needed for *nix
- stdout := colorable.NewColorableStdout()
-
- bgColors := []string{
- "",
- ":black",
- ":red",
- ":green",
- ":yellow",
- ":blue",
- ":magenta",
- ":cyan",
- ":white",
- }
-
- keys := make([]string, 0, len(Colors))
- for k := range Colors {
- keys = append(keys, k)
- }
-
- sort.Sort(sort.StringSlice(keys))
-
- for _, fg := range keys {
- for _, bg := range bgColors {
- fmt.Fprintln(stdout, padColor(fg, []string{"" + bg, "+b" + bg, "+bh" + bg, "+u" + bg}))
- fmt.Fprintln(stdout, padColor(fg, []string{"+s" + bg, "+i" + bg}))
- fmt.Fprintln(stdout, padColor(fg, []string{"+uh" + bg, "+B" + bg, "+Bb" + bg /* backgrounds */, "" + bg + "+h"}))
- fmt.Fprintln(stdout, padColor(fg, []string{"+b" + bg + "+h", "+bh" + bg + "+h", "+u" + bg + "+h", "+uh" + bg + "+h"}))
- }
- }
-}
-
-func pad(s string, length int) string {
- for len(s) < length {
- s += " "
- }
- return s
-}
-
-func padColor(color string, styles []string) string {
- buffer := ""
- for _, style := range styles {
- buffer += Color(pad(color+style, 20), color+style)
- }
- return buffer
-}
diff --git a/vendor/github.com/miekg/dns/.codecov.yml b/vendor/github.com/miekg/dns/.codecov.yml
deleted file mode 100644
index f91e5c1fe57..00000000000
--- a/vendor/github.com/miekg/dns/.codecov.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-coverage:
- status:
- project:
- default:
- target: 40%
- threshold: null
- patch: false
- changes: false
diff --git a/vendor/github.com/miekg/dns/.gitignore b/vendor/github.com/miekg/dns/.gitignore
deleted file mode 100644
index 776cd950c25..00000000000
--- a/vendor/github.com/miekg/dns/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-*.6
-tags
-test.out
-a.out
diff --git a/vendor/github.com/miekg/dns/.travis.yml b/vendor/github.com/miekg/dns/.travis.yml
deleted file mode 100644
index 18259374e51..00000000000
--- a/vendor/github.com/miekg/dns/.travis.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-language: go
-sudo: false
-
-go:
- - 1.10.x
- - 1.11.x
- - tip
-
-before_install:
- # don't use the miekg/dns when testing forks
- - mkdir -p $GOPATH/src/github.com/miekg
- - ln -s $TRAVIS_BUILD_DIR $GOPATH/src/github.com/miekg/ || true
-
-script:
- - go test -race -v -bench=. -coverprofile=coverage.txt -covermode=atomic ./...
-
-after_success:
- - bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/github.com/miekg/dns/AUTHORS b/vendor/github.com/miekg/dns/AUTHORS
deleted file mode 100644
index 1965683525a..00000000000
--- a/vendor/github.com/miekg/dns/AUTHORS
+++ /dev/null
@@ -1 +0,0 @@
-Miek Gieben
diff --git a/vendor/github.com/miekg/dns/CONTRIBUTORS b/vendor/github.com/miekg/dns/CONTRIBUTORS
deleted file mode 100644
index 5903779d81f..00000000000
--- a/vendor/github.com/miekg/dns/CONTRIBUTORS
+++ /dev/null
@@ -1,10 +0,0 @@
-Alex A. Skinner
-Andrew Tunnell-Jones
-Ask Bjørn Hansen
-Dave Cheney
-Dusty Wilson
-Marek Majkowski
-Peter van Dijk
-Omri Bahumi
-Alex Sergeyev
-James Hartig
diff --git a/vendor/github.com/miekg/dns/COPYRIGHT b/vendor/github.com/miekg/dns/COPYRIGHT
deleted file mode 100644
index 35702b10e87..00000000000
--- a/vendor/github.com/miekg/dns/COPYRIGHT
+++ /dev/null
@@ -1,9 +0,0 @@
-Copyright 2009 The Go Authors. All rights reserved. Use of this source code
-is governed by a BSD-style license that can be found in the LICENSE file.
-Extensions of the original work are copyright (c) 2011 Miek Gieben
-
-Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is
-governed by a BSD-style license that can be found in the LICENSE file.
-
-Copyright 2014 CloudFlare. All rights reserved. Use of this source code is
-governed by a BSD-style license that can be found in the LICENSE file.
diff --git a/vendor/github.com/miekg/dns/Gopkg.lock b/vendor/github.com/miekg/dns/Gopkg.lock
deleted file mode 100644
index 686632207a1..00000000000
--- a/vendor/github.com/miekg/dns/Gopkg.lock
+++ /dev/null
@@ -1,57 +0,0 @@
-# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
-
-
-[[projects]]
- branch = "master"
- digest = "1:6914c49eed986dfb8dffb33516fa129c49929d4d873f41e073c83c11c372b870"
- name = "golang.org/x/crypto"
- packages = [
- "ed25519",
- "ed25519/internal/edwards25519",
- ]
- pruneopts = ""
- revision = "e3636079e1a4c1f337f212cc5cd2aca108f6c900"
-
-[[projects]]
- branch = "master"
- digest = "1:08e41d63f8dac84d83797368b56cf0b339e42d0224e5e56668963c28aec95685"
- name = "golang.org/x/net"
- packages = [
- "bpf",
- "context",
- "internal/iana",
- "internal/socket",
- "ipv4",
- "ipv6",
- ]
- pruneopts = ""
- revision = "4dfa2610cdf3b287375bbba5b8f2a14d3b01d8de"
-
-[[projects]]
- branch = "master"
- digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
- name = "golang.org/x/sync"
- packages = ["errgroup"]
- pruneopts = ""
- revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
-
-[[projects]]
- branch = "master"
- digest = "1:149a432fabebb8221a80f77731b1cd63597197ded4f14af606ebe3a0959004ec"
- name = "golang.org/x/sys"
- packages = ["unix"]
- pruneopts = ""
- revision = "e4b3c5e9061176387e7cea65e4dc5853801f3fb7"
-
-[solve-meta]
- analyzer-name = "dep"
- analyzer-version = 1
- input-imports = [
- "golang.org/x/crypto/ed25519",
- "golang.org/x/net/ipv4",
- "golang.org/x/net/ipv6",
- "golang.org/x/sync/errgroup",
- "golang.org/x/sys/unix",
- ]
- solver-name = "gps-cdcl"
- solver-version = 1
diff --git a/vendor/github.com/miekg/dns/Gopkg.toml b/vendor/github.com/miekg/dns/Gopkg.toml
deleted file mode 100644
index 85e6ff31b22..00000000000
--- a/vendor/github.com/miekg/dns/Gopkg.toml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-# Gopkg.toml example
-#
-# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
-# for detailed Gopkg.toml documentation.
-#
-# required = ["github.com/user/thing/cmd/thing"]
-# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
-#
-# [[constraint]]
-# name = "github.com/user/project"
-# version = "1.0.0"
-#
-# [[constraint]]
-# name = "github.com/user/project2"
-# branch = "dev"
-# source = "github.com/myfork/project2"
-#
-# [[override]]
-# name = "github.com/x/y"
-# version = "2.4.0"
-
-
-[[constraint]]
- branch = "master"
- name = "golang.org/x/crypto"
-
-[[constraint]]
- branch = "master"
- name = "golang.org/x/net"
-
-[[constraint]]
- branch = "master"
- name = "golang.org/x/sys"
-
-[[constraint]]
- branch = "master"
- name = "golang.org/x/sync"
diff --git a/vendor/github.com/miekg/dns/LICENSE b/vendor/github.com/miekg/dns/LICENSE
deleted file mode 100644
index 5763fa7fe5d..00000000000
--- a/vendor/github.com/miekg/dns/LICENSE
+++ /dev/null
@@ -1,32 +0,0 @@
-Extensions of the original work are copyright (c) 2011 Miek Gieben
-
-As this is fork of the official Go code the same license applies:
-
-Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/vendor/github.com/miekg/dns/Makefile.fuzz b/vendor/github.com/miekg/dns/Makefile.fuzz
deleted file mode 100644
index dc158c4acee..00000000000
--- a/vendor/github.com/miekg/dns/Makefile.fuzz
+++ /dev/null
@@ -1,33 +0,0 @@
-# Makefile for fuzzing
-#
-# Use go-fuzz and needs the tools installed.
-# See https://blog.cloudflare.com/dns-parser-meet-go-fuzzer/
-#
-# Installing go-fuzz:
-# $ make -f Makefile.fuzz get
-# Installs:
-# * github.com/dvyukov/go-fuzz/go-fuzz
-# * get github.com/dvyukov/go-fuzz/go-fuzz-build
-
-all: build
-
-.PHONY: build
-build:
- go-fuzz-build -tags fuzz github.com/miekg/dns
-
-.PHONY: build-newrr
-build-newrr:
- go-fuzz-build -func FuzzNewRR -tags fuzz github.com/miekg/dns
-
-.PHONY: fuzz
-fuzz:
- go-fuzz -bin=dns-fuzz.zip -workdir=fuzz
-
-.PHONY: get
-get:
- go get github.com/dvyukov/go-fuzz/go-fuzz
- go get github.com/dvyukov/go-fuzz/go-fuzz-build
-
-.PHONY: clean
-clean:
- rm *-fuzz.zip
diff --git a/vendor/github.com/miekg/dns/Makefile.release b/vendor/github.com/miekg/dns/Makefile.release
deleted file mode 100644
index 8fb748e8aae..00000000000
--- a/vendor/github.com/miekg/dns/Makefile.release
+++ /dev/null
@@ -1,52 +0,0 @@
-# Makefile for releasing.
-#
-# The release is controlled from version.go. The version found there is
-# used to tag the git repo, we're not building any artifects so there is nothing
-# to upload to github.
-#
-# * Up the version in version.go
-# * Run: make -f Makefile.release release
-# * will *commit* your change with 'Release $VERSION'
-# * push to github
-#
-
-define GO
-//+build ignore
-
-package main
-
-import (
- "fmt"
-
- "github.com/miekg/dns"
-)
-
-func main() {
- fmt.Println(dns.Version.String())
-}
-endef
-
-$(file > version_release.go,$(GO))
-VERSION:=$(shell go run version_release.go)
-TAG="v$(VERSION)"
-
-all:
- @echo Use the \'release\' target to start a release $(VERSION)
- rm -f version_release.go
-
-.PHONY: release
-release: commit push
- @echo Released $(VERSION)
- rm -f version_release.go
-
-.PHONY: commit
-commit:
- @echo Committing release $(VERSION)
- git commit -am"Release $(VERSION)"
- git tag $(TAG)
-
-.PHONY: push
-push:
- @echo Pushing release $(VERSION) to master
- git push --tags
- git push
diff --git a/vendor/github.com/miekg/dns/README.md b/vendor/github.com/miekg/dns/README.md
deleted file mode 100644
index 7f1aaa5de42..00000000000
--- a/vendor/github.com/miekg/dns/README.md
+++ /dev/null
@@ -1,172 +0,0 @@
-[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns)
-[![Code Coverage](https://img.shields.io/codecov/c/github/miekg/dns/master.svg)](https://codecov.io/github/miekg/dns?branch=master)
-[![Go Report Card](https://goreportcard.com/badge/github.com/miekg/dns)](https://goreportcard.com/report/miekg/dns)
-[![](https://godoc.org/github.com/miekg/dns?status.svg)](https://godoc.org/github.com/miekg/dns)
-
-# Alternative (more granular) approach to a DNS library
-
-> Less is more.
-
-Complete and usable DNS library. All widely used Resource Records are supported, including the
-DNSSEC types. It follows a lean and mean philosophy. If there is stuff you should know as a DNS
-programmer there isn't a convenience function for it. Server side and client side programming is
-supported, i.e. you can build servers and resolvers with it.
-
-We try to keep the "master" branch as sane as possible and at the bleeding edge of standards,
-avoiding breaking changes wherever reasonable. We support the last two versions of Go.
-
-# Goals
-
-* KISS;
-* Fast;
-* Small API. If it's easy to code in Go, don't make a function for it.
-
-# Users
-
-A not-so-up-to-date-list-that-may-be-actually-current:
-
-* https://github.com/coredns/coredns
-* https://cloudflare.com
-* https://github.com/abh/geodns
-* http://www.statdns.com/
-* http://www.dnsinspect.com/
-* https://github.com/chuangbo/jianbing-dictionary-dns
-* http://www.dns-lg.com/
-* https://github.com/fcambus/rrda
-* https://github.com/kenshinx/godns
-* https://github.com/skynetservices/skydns
-* https://github.com/hashicorp/consul
-* https://github.com/DevelopersPL/godnsagent
-* https://github.com/duedil-ltd/discodns
-* https://github.com/StalkR/dns-reverse-proxy
-* https://github.com/tianon/rawdns
-* https://mesosphere.github.io/mesos-dns/
-* https://pulse.turbobytes.com/
-* https://play.google.com/store/apps/details?id=com.turbobytes.dig
-* https://github.com/fcambus/statzone
-* https://github.com/benschw/dns-clb-go
-* https://github.com/corny/dnscheck for http://public-dns.info/
-* https://namesmith.io
-* https://github.com/miekg/unbound
-* https://github.com/miekg/exdns
-* https://dnslookup.org
-* https://github.com/looterz/grimd
-* https://github.com/phamhongviet/serf-dns
-* https://github.com/mehrdadrad/mylg
-* https://github.com/bamarni/dockness
-* https://github.com/fffaraz/microdns
-* http://kelda.io
-* https://github.com/ipdcode/hades (JD.COM)
-* https://github.com/StackExchange/dnscontrol/
-* https://www.dnsperf.com/
-* https://dnssectest.net/
-* https://dns.apebits.com
-* https://github.com/oif/apex
-* https://github.com/jedisct1/dnscrypt-proxy
-* https://github.com/jedisct1/rpdns
-* https://github.com/xor-gate/sshfp
-* https://github.com/rs/dnstrace
-* https://blitiri.com.ar/p/dnss ([github mirror](https://github.com/albertito/dnss))
-* https://github.com/semihalev/sdns
-
-Send pull request if you want to be listed here.
-
-# Features
-
-* UDP/TCP queries, IPv4 and IPv6;
-* RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported;
-* Fast:
- * Reply speed around ~ 80K qps (faster hardware results in more qps);
- * Parsing RRs ~ 100K RR/s, that's 5M records in about 50 seconds;
-* Server side programming (mimicking the net/http package);
-* Client side programming;
-* DNSSEC: signing, validating and key generation for DSA, RSA, ECDSA and Ed25519;
-* EDNS0, NSID, Cookies;
-* AXFR/IXFR;
-* TSIG, SIG(0);
-* DNS over TLS: optional encrypted connection between client and server;
-* DNS name compression;
-* Depends only on the standard library.
-
-Have fun!
-
-Miek Gieben - 2010-2012 -
-
-# Building
-
-Building is done with the `go` tool. If you have setup your GOPATH correctly, the following should
-work:
-
- go get github.com/miekg/dns
- go build github.com/miekg/dns
-
-## Examples
-
-A short "how to use the API" is at the beginning of doc.go (this also will show
-when you call `godoc github.com/miekg/dns`).
-
-Example programs can be found in the `github.com/miekg/exdns` repository.
-
-## Supported RFCs
-
-*all of them*
-
-* 103{4,5} - DNS standard
-* 1348 - NSAP record (removed the record)
-* 1982 - Serial Arithmetic
-* 1876 - LOC record
-* 1995 - IXFR
-* 1996 - DNS notify
-* 2136 - DNS Update (dynamic updates)
-* 2181 - RRset definition - there is no RRset type though, just []RR
-* 2537 - RSAMD5 DNS keys
-* 2065 - DNSSEC (updated in later RFCs)
-* 2671 - EDNS record
-* 2782 - SRV record
-* 2845 - TSIG record
-* 2915 - NAPTR record
-* 2929 - DNS IANA Considerations
-* 3110 - RSASHA1 DNS keys
-* 3225 - DO bit (DNSSEC OK)
-* 340{1,2,3} - NAPTR record
-* 3445 - Limiting the scope of (DNS)KEY
-* 3597 - Unknown RRs
-* 403{3,4,5} - DNSSEC + validation functions
-* 4255 - SSHFP record
-* 4343 - Case insensitivity
-* 4408 - SPF record
-* 4509 - SHA256 Hash in DS
-* 4592 - Wildcards in the DNS
-* 4635 - HMAC SHA TSIG
-* 4701 - DHCID
-* 4892 - id.server
-* 5001 - NSID
-* 5155 - NSEC3 record
-* 5205 - HIP record
-* 5702 - SHA2 in the DNS
-* 5936 - AXFR
-* 5966 - TCP implementation recommendations
-* 6605 - ECDSA
-* 6725 - IANA Registry Update
-* 6742 - ILNP DNS
-* 6840 - Clarifications and Implementation Notes for DNS Security
-* 6844 - CAA record
-* 6891 - EDNS0 update
-* 6895 - DNS IANA considerations
-* 6975 - Algorithm Understanding in DNSSEC
-* 7043 - EUI48/EUI64 records
-* 7314 - DNS (EDNS) EXPIRE Option
-* 7477 - CSYNC RR
-* 7828 - edns-tcp-keepalive EDNS0 Option
-* 7553 - URI record
-* 7858 - DNS over TLS: Initiation and Performance Considerations
-* 7871 - EDNS0 Client Subnet
-* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies)
-* 8080 - EdDSA for DNSSEC
-
-## Loosely based upon
-
-* `ldns`
-* `NSD`
-* `Net::DNS`
-* `GRONG`
diff --git a/vendor/github.com/miekg/dns/client.go b/vendor/github.com/miekg/dns/client.go
deleted file mode 100644
index 63ced2bd064..00000000000
--- a/vendor/github.com/miekg/dns/client.go
+++ /dev/null
@@ -1,577 +0,0 @@
-package dns
-
-// A client implementation.
-
-import (
- "bytes"
- "context"
- "crypto/tls"
- "encoding/binary"
- "fmt"
- "io"
- "io/ioutil"
- "net"
- "net/http"
- "strings"
- "time"
-)
-
-const (
- dnsTimeout time.Duration = 2 * time.Second
- tcpIdleTimeout time.Duration = 8 * time.Second
-
- dohMimeType = "application/dns-message"
-)
-
-// A Conn represents a connection to a DNS server.
-type Conn struct {
- net.Conn // a net.Conn holding the connection
- UDPSize uint16 // minimum receive buffer for UDP messages
- TsigSecret map[string]string // secret(s) for Tsig map[], zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
- tsigRequestMAC string
-}
-
-// A Client defines parameters for a DNS client.
-type Client struct {
- Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
- UDPSize uint16 // minimum receive buffer for UDP messages
- TLSConfig *tls.Config // TLS connection configuration
- Dialer *net.Dialer // a net.Dialer used to set local address, timeouts and more
- // Timeout is a cumulative timeout for dial, write and read, defaults to 0 (disabled) - overrides DialTimeout, ReadTimeout,
- // WriteTimeout when non-zero. Can be overridden with net.Dialer.Timeout (see Client.ExchangeWithDialer and
- // Client.Dialer) or context.Context.Deadline (see the deprecated ExchangeContext)
- Timeout time.Duration
- DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds, or net.Dialer.Timeout if expiring earlier - overridden by Timeout when that value is non-zero
- ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
- WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
- HTTPClient *http.Client // The http.Client to use for DNS-over-HTTPS
- TsigSecret map[string]string // secret(s) for Tsig map[], zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
- SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
- group singleflight
-}
-
-// Exchange performs a synchronous UDP query. It sends the message m to the address
-// contained in a and waits for a reply. Exchange does not retry a failed query, nor
-// will it fall back to TCP in case of truncation.
-// See client.Exchange for more information on setting larger buffer sizes.
-func Exchange(m *Msg, a string) (r *Msg, err error) {
- client := Client{Net: "udp"}
- r, _, err = client.Exchange(m, a)
- return r, err
-}
-
-func (c *Client) dialTimeout() time.Duration {
- if c.Timeout != 0 {
- return c.Timeout
- }
- if c.DialTimeout != 0 {
- return c.DialTimeout
- }
- return dnsTimeout
-}
-
-func (c *Client) readTimeout() time.Duration {
- if c.ReadTimeout != 0 {
- return c.ReadTimeout
- }
- return dnsTimeout
-}
-
-func (c *Client) writeTimeout() time.Duration {
- if c.WriteTimeout != 0 {
- return c.WriteTimeout
- }
- return dnsTimeout
-}
-
-// Dial connects to the address on the named network.
-func (c *Client) Dial(address string) (conn *Conn, err error) {
- // create a new dialer with the appropriate timeout
- var d net.Dialer
- if c.Dialer == nil {
- d = net.Dialer{Timeout: c.getTimeoutForRequest(c.dialTimeout())}
- } else {
- d = *c.Dialer
- }
-
- network := c.Net
- if network == "" {
- network = "udp"
- }
-
- useTLS := strings.HasPrefix(network, "tcp") && strings.HasSuffix(network, "-tls")
-
- conn = new(Conn)
- if useTLS {
- network = strings.TrimSuffix(network, "-tls")
-
- conn.Conn, err = tls.DialWithDialer(&d, network, address, c.TLSConfig)
- } else {
- conn.Conn, err = d.Dial(network, address)
- }
- if err != nil {
- return nil, err
- }
-
- return conn, nil
-}
-
-// Exchange performs a synchronous query. It sends the message m to the address
-// contained in a and waits for a reply. Basic use pattern with a *dns.Client:
-//
-// c := new(dns.Client)
-// in, rtt, err := c.Exchange(message, "127.0.0.1:53")
-//
-// Exchange does not retry a failed query, nor will it fall back to TCP in
-// case of truncation.
-// It is up to the caller to create a message that allows for larger responses to be
-// returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger
-// buffer, see SetEdns0. Messages without an OPT RR will fallback to the historic limit
-// of 512 bytes
-// To specify a local address or a timeout, the caller has to set the `Client.Dialer`
-// attribute appropriately
-func (c *Client) Exchange(m *Msg, address string) (r *Msg, rtt time.Duration, err error) {
- if !c.SingleInflight {
- if c.Net == "https" {
- // TODO(tmthrgd): pipe timeouts into exchangeDOH
- return c.exchangeDOH(context.TODO(), m, address)
- }
-
- return c.exchange(m, address)
- }
-
- t := "nop"
- if t1, ok := TypeToString[m.Question[0].Qtype]; ok {
- t = t1
- }
- cl := "nop"
- if cl1, ok := ClassToString[m.Question[0].Qclass]; ok {
- cl = cl1
- }
- r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
- if c.Net == "https" {
- // TODO(tmthrgd): pipe timeouts into exchangeDOH
- return c.exchangeDOH(context.TODO(), m, address)
- }
-
- return c.exchange(m, address)
- })
- if r != nil && shared {
- r = r.Copy()
- }
- return r, rtt, err
-}
-
-func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
- var co *Conn
-
- co, err = c.Dial(a)
-
- if err != nil {
- return nil, 0, err
- }
- defer co.Close()
-
- opt := m.IsEdns0()
- // If EDNS0 is used use that for size.
- if opt != nil && opt.UDPSize() >= MinMsgSize {
- co.UDPSize = opt.UDPSize()
- }
- // Otherwise use the client's configured UDP size.
- if opt == nil && c.UDPSize >= MinMsgSize {
- co.UDPSize = c.UDPSize
- }
-
- co.TsigSecret = c.TsigSecret
- t := time.Now()
- // write with the appropriate write timeout
- co.SetWriteDeadline(t.Add(c.getTimeoutForRequest(c.writeTimeout())))
- if err = co.WriteMsg(m); err != nil {
- return nil, 0, err
- }
-
- co.SetReadDeadline(time.Now().Add(c.getTimeoutForRequest(c.readTimeout())))
- r, err = co.ReadMsg()
- if err == nil && r.Id != m.Id {
- err = ErrId
- }
- rtt = time.Since(t)
- return r, rtt, err
-}
-
-func (c *Client) exchangeDOH(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
- p, err := m.Pack()
- if err != nil {
- return nil, 0, err
- }
-
- req, err := http.NewRequest(http.MethodPost, a, bytes.NewReader(p))
- if err != nil {
- return nil, 0, err
- }
-
- req.Header.Set("Content-Type", dohMimeType)
- req.Header.Set("Accept", dohMimeType)
-
- hc := http.DefaultClient
- if c.HTTPClient != nil {
- hc = c.HTTPClient
- }
-
- if ctx != context.Background() && ctx != context.TODO() {
- req = req.WithContext(ctx)
- }
-
- t := time.Now()
-
- resp, err := hc.Do(req)
- if err != nil {
- return nil, 0, err
- }
- defer closeHTTPBody(resp.Body)
-
- if resp.StatusCode != http.StatusOK {
- return nil, 0, fmt.Errorf("dns: server returned HTTP %d error: %q", resp.StatusCode, resp.Status)
- }
-
- if ct := resp.Header.Get("Content-Type"); ct != dohMimeType {
- return nil, 0, fmt.Errorf("dns: unexpected Content-Type %q; expected %q", ct, dohMimeType)
- }
-
- p, err = ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, 0, err
- }
-
- rtt = time.Since(t)
-
- r = new(Msg)
- if err := r.Unpack(p); err != nil {
- return r, 0, err
- }
-
- // TODO: TSIG? Is it even supported over DoH?
-
- return r, rtt, nil
-}
-
-func closeHTTPBody(r io.ReadCloser) error {
- io.Copy(ioutil.Discard, io.LimitReader(r, 8<<20))
- return r.Close()
-}
-
-// ReadMsg reads a message from the connection co.
-// If the received message contains a TSIG record the transaction signature
-// is verified. This method always tries to return the message, however if an
-// error is returned there are no guarantees that the returned message is a
-// valid representation of the packet read.
-func (co *Conn) ReadMsg() (*Msg, error) {
- p, err := co.ReadMsgHeader(nil)
- if err != nil {
- return nil, err
- }
-
- m := new(Msg)
- if err := m.Unpack(p); err != nil {
- // If an error was returned, we still want to allow the user to use
- // the message, but naively they can just check err if they don't want
- // to use an erroneous message
- return m, err
- }
- if t := m.IsTsig(); t != nil {
- if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
- return m, ErrSecret
- }
- // Need to work on the original message p, as that was used to calculate the tsig.
- err = TsigVerify(p, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
- }
- return m, err
-}
-
-// ReadMsgHeader reads a DNS message, parses and populates hdr (when hdr is not nil).
-// Returns message as a byte slice to be parsed with Msg.Unpack later on.
-// Note that error handling on the message body is not possible as only the header is parsed.
-func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
- var (
- p []byte
- n int
- err error
- )
-
- switch t := co.Conn.(type) {
- case *net.TCPConn, *tls.Conn:
- r := t.(io.Reader)
-
- // First two bytes specify the length of the entire message.
- l, err := tcpMsgLen(r)
- if err != nil {
- return nil, err
- }
- p = make([]byte, l)
- n, err = tcpRead(r, p)
- default:
- if co.UDPSize > MinMsgSize {
- p = make([]byte, co.UDPSize)
- } else {
- p = make([]byte, MinMsgSize)
- }
- n, err = co.Read(p)
- }
-
- if err != nil {
- return nil, err
- } else if n < headerSize {
- return nil, ErrShortRead
- }
-
- p = p[:n]
- if hdr != nil {
- dh, _, err := unpackMsgHdr(p, 0)
- if err != nil {
- return nil, err
- }
- *hdr = dh
- }
- return p, err
-}
-
-// tcpMsgLen is a helper func to read first two bytes of stream as uint16 packet length.
-func tcpMsgLen(t io.Reader) (int, error) {
- p := []byte{0, 0}
- n, err := t.Read(p)
- if err != nil {
- return 0, err
- }
-
- // As seen with my local router/switch, returns 1 byte on the above read,
- // resulting a a ShortRead. Just write it out (instead of loop) and read the
- // other byte.
- if n == 1 {
- n1, err := t.Read(p[1:])
- if err != nil {
- return 0, err
- }
- n += n1
- }
-
- if n != 2 {
- return 0, ErrShortRead
- }
- l := binary.BigEndian.Uint16(p)
- if l == 0 {
- return 0, ErrShortRead
- }
- return int(l), nil
-}
-
-// tcpRead calls TCPConn.Read enough times to fill allocated buffer.
-func tcpRead(t io.Reader, p []byte) (int, error) {
- n, err := t.Read(p)
- if err != nil {
- return n, err
- }
- for n < len(p) {
- j, err := t.Read(p[n:])
- if err != nil {
- return n, err
- }
- n += j
- }
- return n, err
-}
-
-// Read implements the net.Conn read method.
-func (co *Conn) Read(p []byte) (n int, err error) {
- if co.Conn == nil {
- return 0, ErrConnEmpty
- }
- if len(p) < 2 {
- return 0, io.ErrShortBuffer
- }
- switch t := co.Conn.(type) {
- case *net.TCPConn, *tls.Conn:
- r := t.(io.Reader)
-
- l, err := tcpMsgLen(r)
- if err != nil {
- return 0, err
- }
- if l > len(p) {
- return int(l), io.ErrShortBuffer
- }
- return tcpRead(r, p[:l])
- }
- // UDP connection
- n, err = co.Conn.Read(p)
- if err != nil {
- return n, err
- }
- return n, err
-}
-
-// WriteMsg sends a message through the connection co.
-// If the message m contains a TSIG record the transaction
-// signature is calculated.
-func (co *Conn) WriteMsg(m *Msg) (err error) {
- var out []byte
- if t := m.IsTsig(); t != nil {
- mac := ""
- if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
- return ErrSecret
- }
- out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
- // Set for the next read, although only used in zone transfers
- co.tsigRequestMAC = mac
- } else {
- out, err = m.Pack()
- }
- if err != nil {
- return err
- }
- if _, err = co.Write(out); err != nil {
- return err
- }
- return nil
-}
-
-// Write implements the net.Conn Write method.
-func (co *Conn) Write(p []byte) (n int, err error) {
- switch t := co.Conn.(type) {
- case *net.TCPConn, *tls.Conn:
- w := t.(io.Writer)
-
- lp := len(p)
- if lp < 2 {
- return 0, io.ErrShortBuffer
- }
- if lp > MaxMsgSize {
- return 0, &Error{err: "message too large"}
- }
- l := make([]byte, 2, lp+2)
- binary.BigEndian.PutUint16(l, uint16(lp))
- p = append(l, p...)
- n, err := io.Copy(w, bytes.NewReader(p))
- return int(n), err
- }
- n, err = co.Conn.Write(p)
- return n, err
-}
-
-// Return the appropriate timeout for a specific request
-func (c *Client) getTimeoutForRequest(timeout time.Duration) time.Duration {
- var requestTimeout time.Duration
- if c.Timeout != 0 {
- requestTimeout = c.Timeout
- } else {
- requestTimeout = timeout
- }
- // net.Dialer.Timeout has priority if smaller than the timeouts computed so
- // far
- if c.Dialer != nil && c.Dialer.Timeout != 0 {
- if c.Dialer.Timeout < requestTimeout {
- requestTimeout = c.Dialer.Timeout
- }
- }
- return requestTimeout
-}
-
-// Dial connects to the address on the named network.
-func Dial(network, address string) (conn *Conn, err error) {
- conn = new(Conn)
- conn.Conn, err = net.Dial(network, address)
- if err != nil {
- return nil, err
- }
- return conn, nil
-}
-
-// ExchangeContext performs a synchronous UDP query, like Exchange. It
-// additionally obeys deadlines from the passed Context.
-func ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, err error) {
- client := Client{Net: "udp"}
- r, _, err = client.ExchangeContext(ctx, m, a)
- // ignorint rtt to leave the original ExchangeContext API unchanged, but
- // this function will go away
- return r, err
-}
-
-// ExchangeConn performs a synchronous query. It sends the message m via the connection
-// c and waits for a reply. The connection c is not closed by ExchangeConn.
-// This function is going away, but can easily be mimicked:
-//
-// co := &dns.Conn{Conn: c} // c is your net.Conn
-// co.WriteMsg(m)
-// in, _ := co.ReadMsg()
-// co.Close()
-//
-func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
- println("dns: ExchangeConn: this function is deprecated")
- co := new(Conn)
- co.Conn = c
- if err = co.WriteMsg(m); err != nil {
- return nil, err
- }
- r, err = co.ReadMsg()
- if err == nil && r.Id != m.Id {
- err = ErrId
- }
- return r, err
-}
-
-// DialTimeout acts like Dial but takes a timeout.
-func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
- client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}}
- conn, err = client.Dial(address)
- if err != nil {
- return nil, err
- }
- return conn, nil
-}
-
-// DialWithTLS connects to the address on the named network with TLS.
-func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, err error) {
- if !strings.HasSuffix(network, "-tls") {
- network += "-tls"
- }
- client := Client{Net: network, TLSConfig: tlsConfig}
- conn, err = client.Dial(address)
-
- if err != nil {
- return nil, err
- }
- return conn, nil
-}
-
-// DialTimeoutWithTLS acts like DialWithTLS but takes a timeout.
-func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout time.Duration) (conn *Conn, err error) {
- if !strings.HasSuffix(network, "-tls") {
- network += "-tls"
- }
- client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}, TLSConfig: tlsConfig}
- conn, err = client.Dial(address)
- if err != nil {
- return nil, err
- }
- return conn, nil
-}
-
-// ExchangeContext acts like Exchange, but honors the deadline on the provided
-// context, if present. If there is both a context deadline and a configured
-// timeout on the client, the earliest of the two takes effect.
-func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
- if !c.SingleInflight && c.Net == "https" {
- return c.exchangeDOH(ctx, m, a)
- }
-
- var timeout time.Duration
- if deadline, ok := ctx.Deadline(); !ok {
- timeout = 0
- } else {
- timeout = time.Until(deadline)
- }
- // not passing the context to the underlying calls, as the API does not support
- // context. For timeouts you should set up Client.Dialer and call Client.Exchange.
- // TODO(tmthrgd): this is a race condition
- c.Dialer = &net.Dialer{Timeout: timeout}
- return c.Exchange(m, a)
-}
diff --git a/vendor/github.com/miekg/dns/clientconfig.go b/vendor/github.com/miekg/dns/clientconfig.go
deleted file mode 100644
index f13cfa30cb5..00000000000
--- a/vendor/github.com/miekg/dns/clientconfig.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package dns
-
-import (
- "bufio"
- "io"
- "os"
- "strconv"
- "strings"
-)
-
-// ClientConfig wraps the contents of the /etc/resolv.conf file.
-type ClientConfig struct {
- Servers []string // servers to use
- Search []string // suffixes to append to local name
- Port string // what port to use
- Ndots int // number of dots in name to trigger absolute lookup
- Timeout int // seconds before giving up on packet
- Attempts int // lost packets before giving up on server, not used in the package dns
-}
-
-// ClientConfigFromFile parses a resolv.conf(5) like file and returns
-// a *ClientConfig.
-func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
- file, err := os.Open(resolvconf)
- if err != nil {
- return nil, err
- }
- defer file.Close()
- return ClientConfigFromReader(file)
-}
-
-// ClientConfigFromReader works like ClientConfigFromFile but takes an io.Reader as argument
-func ClientConfigFromReader(resolvconf io.Reader) (*ClientConfig, error) {
- c := new(ClientConfig)
- scanner := bufio.NewScanner(resolvconf)
- c.Servers = make([]string, 0)
- c.Search = make([]string, 0)
- c.Port = "53"
- c.Ndots = 1
- c.Timeout = 5
- c.Attempts = 2
-
- for scanner.Scan() {
- if err := scanner.Err(); err != nil {
- return nil, err
- }
- line := scanner.Text()
- f := strings.Fields(line)
- if len(f) < 1 {
- continue
- }
- switch f[0] {
- case "nameserver": // add one name server
- if len(f) > 1 {
- // One more check: make sure server name is
- // just an IP address. Otherwise we need DNS
- // to look it up.
- name := f[1]
- c.Servers = append(c.Servers, name)
- }
-
- case "domain": // set search path to just this domain
- if len(f) > 1 {
- c.Search = make([]string, 1)
- c.Search[0] = f[1]
- } else {
- c.Search = make([]string, 0)
- }
-
- case "search": // set search path to given servers
- c.Search = make([]string, len(f)-1)
- for i := 0; i < len(c.Search); i++ {
- c.Search[i] = f[i+1]
- }
-
- case "options": // magic options
- for i := 1; i < len(f); i++ {
- s := f[i]
- switch {
- case len(s) >= 6 && s[:6] == "ndots:":
- n, _ := strconv.Atoi(s[6:])
- if n < 0 {
- n = 0
- } else if n > 15 {
- n = 15
- }
- c.Ndots = n
- case len(s) >= 8 && s[:8] == "timeout:":
- n, _ := strconv.Atoi(s[8:])
- if n < 1 {
- n = 1
- }
- c.Timeout = n
- case len(s) >= 9 && s[:9] == "attempts:":
- n, _ := strconv.Atoi(s[9:])
- if n < 1 {
- n = 1
- }
- c.Attempts = n
- case s == "rotate":
- /* not imp */
- }
- }
- }
- }
- return c, nil
-}
-
-// NameList returns all of the names that should be queried based on the
-// config. It is based off of go's net/dns name building, but it does not
-// check the length of the resulting names.
-func (c *ClientConfig) NameList(name string) []string {
- // if this domain is already fully qualified, no append needed.
- if IsFqdn(name) {
- return []string{name}
- }
-
- // Check to see if the name has more labels than Ndots. Do this before making
- // the domain fully qualified.
- hasNdots := CountLabel(name) > c.Ndots
- // Make the domain fully qualified.
- name = Fqdn(name)
-
- // Make a list of names based off search.
- names := []string{}
-
- // If name has enough dots, try that first.
- if hasNdots {
- names = append(names, name)
- }
- for _, s := range c.Search {
- names = append(names, Fqdn(name+s))
- }
- // If we didn't have enough dots, try after suffixes.
- if !hasNdots {
- names = append(names, name)
- }
- return names
-}
diff --git a/vendor/github.com/miekg/dns/dane.go b/vendor/github.com/miekg/dns/dane.go
deleted file mode 100644
index 8c4a14ef190..00000000000
--- a/vendor/github.com/miekg/dns/dane.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package dns
-
-import (
- "crypto/sha256"
- "crypto/sha512"
- "crypto/x509"
- "encoding/hex"
- "errors"
-)
-
-// CertificateToDANE converts a certificate to a hex string as used in the TLSA or SMIMEA records.
-func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
- switch matchingType {
- case 0:
- switch selector {
- case 0:
- return hex.EncodeToString(cert.Raw), nil
- case 1:
- return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
- }
- case 1:
- h := sha256.New()
- switch selector {
- case 0:
- h.Write(cert.Raw)
- return hex.EncodeToString(h.Sum(nil)), nil
- case 1:
- h.Write(cert.RawSubjectPublicKeyInfo)
- return hex.EncodeToString(h.Sum(nil)), nil
- }
- case 2:
- h := sha512.New()
- switch selector {
- case 0:
- h.Write(cert.Raw)
- return hex.EncodeToString(h.Sum(nil)), nil
- case 1:
- h.Write(cert.RawSubjectPublicKeyInfo)
- return hex.EncodeToString(h.Sum(nil)), nil
- }
- }
- return "", errors.New("dns: bad MatchingType or Selector")
-}
diff --git a/vendor/github.com/miekg/dns/defaults.go b/vendor/github.com/miekg/dns/defaults.go
deleted file mode 100644
index 14e18b0b38f..00000000000
--- a/vendor/github.com/miekg/dns/defaults.go
+++ /dev/null
@@ -1,288 +0,0 @@
-package dns
-
-import (
- "errors"
- "net"
- "strconv"
-)
-
-const hexDigit = "0123456789abcdef"
-
-// Everything is assumed in ClassINET.
-
-// SetReply creates a reply message from a request message.
-func (dns *Msg) SetReply(request *Msg) *Msg {
- dns.Id = request.Id
- dns.Response = true
- dns.Opcode = request.Opcode
- if dns.Opcode == OpcodeQuery {
- dns.RecursionDesired = request.RecursionDesired // Copy rd bit
- dns.CheckingDisabled = request.CheckingDisabled // Copy cd bit
- }
- dns.Rcode = RcodeSuccess
- if len(request.Question) > 0 {
- dns.Question = make([]Question, 1)
- dns.Question[0] = request.Question[0]
- }
- return dns
-}
-
-// SetQuestion creates a question message, it sets the Question
-// section, generates an Id and sets the RecursionDesired (RD)
-// bit to true.
-func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
- dns.Id = Id()
- dns.RecursionDesired = true
- dns.Question = make([]Question, 1)
- dns.Question[0] = Question{z, t, ClassINET}
- return dns
-}
-
-// SetNotify creates a notify message, it sets the Question
-// section, generates an Id and sets the Authoritative (AA)
-// bit to true.
-func (dns *Msg) SetNotify(z string) *Msg {
- dns.Opcode = OpcodeNotify
- dns.Authoritative = true
- dns.Id = Id()
- dns.Question = make([]Question, 1)
- dns.Question[0] = Question{z, TypeSOA, ClassINET}
- return dns
-}
-
-// SetRcode creates an error message suitable for the request.
-func (dns *Msg) SetRcode(request *Msg, rcode int) *Msg {
- dns.SetReply(request)
- dns.Rcode = rcode
- return dns
-}
-
-// SetRcodeFormatError creates a message with FormError set.
-func (dns *Msg) SetRcodeFormatError(request *Msg) *Msg {
- dns.Rcode = RcodeFormatError
- dns.Opcode = OpcodeQuery
- dns.Response = true
- dns.Authoritative = false
- dns.Id = request.Id
- return dns
-}
-
-// SetUpdate makes the message a dynamic update message. It
-// sets the ZONE section to: z, TypeSOA, ClassINET.
-func (dns *Msg) SetUpdate(z string) *Msg {
- dns.Id = Id()
- dns.Response = false
- dns.Opcode = OpcodeUpdate
- dns.Compress = false // BIND9 cannot handle compression
- dns.Question = make([]Question, 1)
- dns.Question[0] = Question{z, TypeSOA, ClassINET}
- return dns
-}
-
-// SetIxfr creates message for requesting an IXFR.
-func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg {
- dns.Id = Id()
- dns.Question = make([]Question, 1)
- dns.Ns = make([]RR, 1)
- s := new(SOA)
- s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
- s.Serial = serial
- s.Ns = ns
- s.Mbox = mbox
- dns.Question[0] = Question{z, TypeIXFR, ClassINET}
- dns.Ns[0] = s
- return dns
-}
-
-// SetAxfr creates message for requesting an AXFR.
-func (dns *Msg) SetAxfr(z string) *Msg {
- dns.Id = Id()
- dns.Question = make([]Question, 1)
- dns.Question[0] = Question{z, TypeAXFR, ClassINET}
- return dns
-}
-
-// SetTsig appends a TSIG RR to the message.
-// This is only a skeleton TSIG RR that is added as the last RR in the
-// additional section. The Tsig is calculated when the message is being send.
-func (dns *Msg) SetTsig(z, algo string, fudge uint16, timesigned int64) *Msg {
- t := new(TSIG)
- t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
- t.Algorithm = algo
- t.Fudge = fudge
- t.TimeSigned = uint64(timesigned)
- t.OrigId = dns.Id
- dns.Extra = append(dns.Extra, t)
- return dns
-}
-
-// SetEdns0 appends a EDNS0 OPT RR to the message.
-// TSIG should always the last RR in a message.
-func (dns *Msg) SetEdns0(udpsize uint16, do bool) *Msg {
- e := new(OPT)
- e.Hdr.Name = "."
- e.Hdr.Rrtype = TypeOPT
- e.SetUDPSize(udpsize)
- if do {
- e.SetDo()
- }
- dns.Extra = append(dns.Extra, e)
- return dns
-}
-
-// IsTsig checks if the message has a TSIG record as the last record
-// in the additional section. It returns the TSIG record found or nil.
-func (dns *Msg) IsTsig() *TSIG {
- if len(dns.Extra) > 0 {
- if dns.Extra[len(dns.Extra)-1].Header().Rrtype == TypeTSIG {
- return dns.Extra[len(dns.Extra)-1].(*TSIG)
- }
- }
- return nil
-}
-
-// IsEdns0 checks if the message has a EDNS0 (OPT) record, any EDNS0
-// record in the additional section will do. It returns the OPT record
-// found or nil.
-func (dns *Msg) IsEdns0() *OPT {
- // EDNS0 is at the end of the additional section, start there.
- // We might want to change this to *only* look at the last two
- // records. So we see TSIG and/or OPT - this a slightly bigger
- // change though.
- for i := len(dns.Extra) - 1; i >= 0; i-- {
- if dns.Extra[i].Header().Rrtype == TypeOPT {
- return dns.Extra[i].(*OPT)
- }
- }
- return nil
-}
-
-// IsDomainName checks if s is a valid domain name, it returns the number of
-// labels and true, when a domain name is valid. Note that non fully qualified
-// domain name is considered valid, in this case the last label is counted in
-// the number of labels. When false is returned the number of labels is not
-// defined. Also note that this function is extremely liberal; almost any
-// string is a valid domain name as the DNS is 8 bit protocol. It checks if each
-// label fits in 63 characters, but there is no length check for the entire
-// string s. I.e. a domain name longer than 255 characters is considered valid.
-func IsDomainName(s string) (labels int, ok bool) {
- _, labels, err := packDomainName(s, nil, 0, nil, false)
- return labels, err == nil
-}
-
-// IsSubDomain checks if child is indeed a child of the parent. If child and parent
-// are the same domain true is returned as well.
-func IsSubDomain(parent, child string) bool {
- // Entire child is contained in parent
- return CompareDomainName(parent, child) == CountLabel(parent)
-}
-
-// IsMsg sanity checks buf and returns an error if it isn't a valid DNS packet.
-// The checking is performed on the binary payload.
-func IsMsg(buf []byte) error {
- // Header
- if len(buf) < 12 {
- return errors.New("dns: bad message header")
- }
- // Header: Opcode
- // TODO(miek): more checks here, e.g. check all header bits.
- return nil
-}
-
-// IsFqdn checks if a domain name is fully qualified.
-func IsFqdn(s string) bool {
- l := len(s)
- if l == 0 {
- return false
- }
- return s[l-1] == '.'
-}
-
-// IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181.
-// This means the RRs need to have the same type, name, and class. Returns true
-// if the RR set is valid, otherwise false.
-func IsRRset(rrset []RR) bool {
- if len(rrset) == 0 {
- return false
- }
- if len(rrset) == 1 {
- return true
- }
- rrHeader := rrset[0].Header()
- rrType := rrHeader.Rrtype
- rrClass := rrHeader.Class
- rrName := rrHeader.Name
-
- for _, rr := range rrset[1:] {
- curRRHeader := rr.Header()
- if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName {
- // Mismatch between the records, so this is not a valid rrset for
- //signing/verifying
- return false
- }
- }
-
- return true
-}
-
-// Fqdn return the fully qualified domain name from s.
-// If s is already fully qualified, it behaves as the identity function.
-func Fqdn(s string) string {
- if IsFqdn(s) {
- return s
- }
- return s + "."
-}
-
-// Copied from the official Go code.
-
-// ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
-// address suitable for reverse DNS (PTR) record lookups or an error if it fails
-// to parse the IP address.
-func ReverseAddr(addr string) (arpa string, err error) {
- ip := net.ParseIP(addr)
- if ip == nil {
- return "", &Error{err: "unrecognized address: " + addr}
- }
- if ip.To4() != nil {
- return strconv.Itoa(int(ip[15])) + "." + strconv.Itoa(int(ip[14])) + "." + strconv.Itoa(int(ip[13])) + "." +
- strconv.Itoa(int(ip[12])) + ".in-addr.arpa.", nil
- }
- // Must be IPv6
- buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
- // Add it, in reverse, to the buffer
- for i := len(ip) - 1; i >= 0; i-- {
- v := ip[i]
- buf = append(buf, hexDigit[v&0xF])
- buf = append(buf, '.')
- buf = append(buf, hexDigit[v>>4])
- buf = append(buf, '.')
- }
- // Append "ip6.arpa." and return (buf already has the final .)
- buf = append(buf, "ip6.arpa."...)
- return string(buf), nil
-}
-
-// String returns the string representation for the type t.
-func (t Type) String() string {
- if t1, ok := TypeToString[uint16(t)]; ok {
- return t1
- }
- return "TYPE" + strconv.Itoa(int(t))
-}
-
-// String returns the string representation for the class c.
-func (c Class) String() string {
- if s, ok := ClassToString[uint16(c)]; ok {
- // Only emit mnemonics when they are unambiguous, specically ANY is in both.
- if _, ok := StringToType[s]; !ok {
- return s
- }
- }
- return "CLASS" + strconv.Itoa(int(c))
-}
-
-// String returns the string representation for the name n.
-func (n Name) String() string {
- return sprintName(string(n))
-}
diff --git a/vendor/github.com/miekg/dns/dns.go b/vendor/github.com/miekg/dns/dns.go
deleted file mode 100644
index e7557f51a81..00000000000
--- a/vendor/github.com/miekg/dns/dns.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package dns
-
-import "strconv"
-
-const (
- year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
- defaultTtl = 3600 // Default internal TTL.
-
- // DefaultMsgSize is the standard default for messages larger than 512 bytes.
- DefaultMsgSize = 4096
- // MinMsgSize is the minimal size of a DNS packet.
- MinMsgSize = 512
- // MaxMsgSize is the largest possible DNS packet.
- MaxMsgSize = 65535
-)
-
-// Error represents a DNS error.
-type Error struct{ err string }
-
-func (e *Error) Error() string {
- if e == nil {
- return "dns: "
- }
- return "dns: " + e.err
-}
-
-// An RR represents a resource record.
-type RR interface {
- // Header returns the header of an resource record. The header contains
- // everything up to the rdata.
- Header() *RR_Header
- // String returns the text representation of the resource record.
- String() string
-
- // copy returns a copy of the RR
- copy() RR
- // len returns the length (in octets) of the uncompressed RR in wire format.
- len() int
- // pack packs an RR into wire format.
- pack([]byte, int, map[string]int, bool) (int, error)
-}
-
-// RR_Header is the header all DNS resource records share.
-type RR_Header struct {
- Name string `dns:"cdomain-name"`
- Rrtype uint16
- Class uint16
- Ttl uint32
- Rdlength uint16 // Length of data after header.
-}
-
-// Header returns itself. This is here to make RR_Header implements the RR interface.
-func (h *RR_Header) Header() *RR_Header { return h }
-
-// Just to implement the RR interface.
-func (h *RR_Header) copy() RR { return nil }
-
-func (h *RR_Header) String() string {
- var s string
-
- if h.Rrtype == TypeOPT {
- s = ";"
- // and maybe other things
- }
-
- s += sprintName(h.Name) + "\t"
- s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
- s += Class(h.Class).String() + "\t"
- s += Type(h.Rrtype).String() + "\t"
- return s
-}
-
-func (h *RR_Header) len() int {
- l := len(h.Name) + 1
- l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2)
- return l
-}
-
-// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
-func (rr *RFC3597) ToRFC3597(r RR) error {
- buf := make([]byte, r.len()*2)
- off, err := PackRR(r, buf, 0, nil, false)
- if err != nil {
- return err
- }
- buf = buf[:off]
- if int(r.Header().Rdlength) > off {
- return ErrBuf
- }
-
- rfc3597, _, err := unpackRFC3597(*r.Header(), buf, off-int(r.Header().Rdlength))
- if err != nil {
- return err
- }
- *rr = *rfc3597.(*RFC3597)
- return nil
-}
diff --git a/vendor/github.com/miekg/dns/dnssec.go b/vendor/github.com/miekg/dns/dnssec.go
deleted file mode 100644
index 26b512e7da5..00000000000
--- a/vendor/github.com/miekg/dns/dnssec.go
+++ /dev/null
@@ -1,801 +0,0 @@
-package dns
-
-import (
- "bytes"
- "crypto"
- "crypto/dsa"
- "crypto/ecdsa"
- "crypto/elliptic"
- _ "crypto/md5"
- "crypto/rand"
- "crypto/rsa"
- _ "crypto/sha1"
- _ "crypto/sha256"
- _ "crypto/sha512"
- "encoding/asn1"
- "encoding/binary"
- "encoding/hex"
- "math/big"
- "sort"
- "strings"
- "time"
-
- "golang.org/x/crypto/ed25519"
-)
-
-// DNSSEC encryption algorithm codes.
-const (
- _ uint8 = iota
- RSAMD5
- DH
- DSA
- _ // Skip 4, RFC 6725, section 2.1
- RSASHA1
- DSANSEC3SHA1
- RSASHA1NSEC3SHA1
- RSASHA256
- _ // Skip 9, RFC 6725, section 2.1
- RSASHA512
- _ // Skip 11, RFC 6725, section 2.1
- ECCGOST
- ECDSAP256SHA256
- ECDSAP384SHA384
- ED25519
- ED448
- INDIRECT uint8 = 252
- PRIVATEDNS uint8 = 253 // Private (experimental keys)
- PRIVATEOID uint8 = 254
-)
-
-// AlgorithmToString is a map of algorithm IDs to algorithm names.
-var AlgorithmToString = map[uint8]string{
- RSAMD5: "RSAMD5",
- DH: "DH",
- DSA: "DSA",
- RSASHA1: "RSASHA1",
- DSANSEC3SHA1: "DSA-NSEC3-SHA1",
- RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
- RSASHA256: "RSASHA256",
- RSASHA512: "RSASHA512",
- ECCGOST: "ECC-GOST",
- ECDSAP256SHA256: "ECDSAP256SHA256",
- ECDSAP384SHA384: "ECDSAP384SHA384",
- ED25519: "ED25519",
- ED448: "ED448",
- INDIRECT: "INDIRECT",
- PRIVATEDNS: "PRIVATEDNS",
- PRIVATEOID: "PRIVATEOID",
-}
-
-// StringToAlgorithm is the reverse of AlgorithmToString.
-var StringToAlgorithm = reverseInt8(AlgorithmToString)
-
-// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
-var AlgorithmToHash = map[uint8]crypto.Hash{
- RSAMD5: crypto.MD5, // Deprecated in RFC 6725
- DSA: crypto.SHA1,
- RSASHA1: crypto.SHA1,
- RSASHA1NSEC3SHA1: crypto.SHA1,
- RSASHA256: crypto.SHA256,
- ECDSAP256SHA256: crypto.SHA256,
- ECDSAP384SHA384: crypto.SHA384,
- RSASHA512: crypto.SHA512,
- ED25519: crypto.Hash(0),
-}
-
-// DNSSEC hashing algorithm codes.
-const (
- _ uint8 = iota
- SHA1 // RFC 4034
- SHA256 // RFC 4509
- GOST94 // RFC 5933
- SHA384 // Experimental
- SHA512 // Experimental
-)
-
-// HashToString is a map of hash IDs to names.
-var HashToString = map[uint8]string{
- SHA1: "SHA1",
- SHA256: "SHA256",
- GOST94: "GOST94",
- SHA384: "SHA384",
- SHA512: "SHA512",
-}
-
-// StringToHash is a map of names to hash IDs.
-var StringToHash = reverseInt8(HashToString)
-
-// DNSKEY flag values.
-const (
- SEP = 1
- REVOKE = 1 << 7
- ZONE = 1 << 8
-)
-
-// The RRSIG needs to be converted to wireformat with some of the rdata (the signature) missing.
-type rrsigWireFmt struct {
- TypeCovered uint16
- Algorithm uint8
- Labels uint8
- OrigTtl uint32
- Expiration uint32
- Inception uint32
- KeyTag uint16
- SignerName string `dns:"domain-name"`
- /* No Signature */
-}
-
-// Used for converting DNSKEY's rdata to wirefmt.
-type dnskeyWireFmt struct {
- Flags uint16
- Protocol uint8
- Algorithm uint8
- PublicKey string `dns:"base64"`
- /* Nothing is left out */
-}
-
-func divRoundUp(a, b int) int {
- return (a + b - 1) / b
-}
-
-// KeyTag calculates the keytag (or key-id) of the DNSKEY.
-func (k *DNSKEY) KeyTag() uint16 {
- if k == nil {
- return 0
- }
- var keytag int
- switch k.Algorithm {
- case RSAMD5:
- // Look at the bottom two bytes of the modules, which the last
- // item in the pubkey. We could do this faster by looking directly
- // at the base64 values. But I'm lazy.
- modulus, _ := fromBase64([]byte(k.PublicKey))
- if len(modulus) > 1 {
- x := binary.BigEndian.Uint16(modulus[len(modulus)-2:])
- keytag = int(x)
- }
- default:
- keywire := new(dnskeyWireFmt)
- keywire.Flags = k.Flags
- keywire.Protocol = k.Protocol
- keywire.Algorithm = k.Algorithm
- keywire.PublicKey = k.PublicKey
- wire := make([]byte, DefaultMsgSize)
- n, err := packKeyWire(keywire, wire)
- if err != nil {
- return 0
- }
- wire = wire[:n]
- for i, v := range wire {
- if i&1 != 0 {
- keytag += int(v) // must be larger than uint32
- } else {
- keytag += int(v) << 8
- }
- }
- keytag += keytag >> 16 & 0xFFFF
- keytag &= 0xFFFF
- }
- return uint16(keytag)
-}
-
-// ToDS converts a DNSKEY record to a DS record.
-func (k *DNSKEY) ToDS(h uint8) *DS {
- if k == nil {
- return nil
- }
- ds := new(DS)
- ds.Hdr.Name = k.Hdr.Name
- ds.Hdr.Class = k.Hdr.Class
- ds.Hdr.Rrtype = TypeDS
- ds.Hdr.Ttl = k.Hdr.Ttl
- ds.Algorithm = k.Algorithm
- ds.DigestType = h
- ds.KeyTag = k.KeyTag()
-
- keywire := new(dnskeyWireFmt)
- keywire.Flags = k.Flags
- keywire.Protocol = k.Protocol
- keywire.Algorithm = k.Algorithm
- keywire.PublicKey = k.PublicKey
- wire := make([]byte, DefaultMsgSize)
- n, err := packKeyWire(keywire, wire)
- if err != nil {
- return nil
- }
- wire = wire[:n]
-
- owner := make([]byte, 255)
- off, err1 := PackDomainName(strings.ToLower(k.Hdr.Name), owner, 0, nil, false)
- if err1 != nil {
- return nil
- }
- owner = owner[:off]
- // RFC4034:
- // digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
- // "|" denotes concatenation
- // DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
-
- var hash crypto.Hash
- switch h {
- case SHA1:
- hash = crypto.SHA1
- case SHA256:
- hash = crypto.SHA256
- case SHA384:
- hash = crypto.SHA384
- case SHA512:
- hash = crypto.SHA512
- default:
- return nil
- }
-
- s := hash.New()
- s.Write(owner)
- s.Write(wire)
- ds.Digest = hex.EncodeToString(s.Sum(nil))
- return ds
-}
-
-// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
-func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
- c := &CDNSKEY{DNSKEY: *k}
- c.Hdr = k.Hdr
- c.Hdr.Rrtype = TypeCDNSKEY
- return c
-}
-
-// ToCDS converts a DS record to a CDS record.
-func (d *DS) ToCDS() *CDS {
- c := &CDS{DS: *d}
- c.Hdr = d.Hdr
- c.Hdr.Rrtype = TypeCDS
- return c
-}
-
-// Sign signs an RRSet. The signature needs to be filled in with the values:
-// Inception, Expiration, KeyTag, SignerName and Algorithm. The rest is copied
-// from the RRset. Sign returns a non-nill error when the signing went OK.
-// There is no check if RRSet is a proper (RFC 2181) RRSet. If OrigTTL is non
-// zero, it is used as-is, otherwise the TTL of the RRset is used as the
-// OrigTTL.
-func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
- if k == nil {
- return ErrPrivKey
- }
- // s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set
- if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
- return ErrKey
- }
-
- rr.Hdr.Rrtype = TypeRRSIG
- rr.Hdr.Name = rrset[0].Header().Name
- rr.Hdr.Class = rrset[0].Header().Class
- if rr.OrigTtl == 0 { // If set don't override
- rr.OrigTtl = rrset[0].Header().Ttl
- }
- rr.TypeCovered = rrset[0].Header().Rrtype
- rr.Labels = uint8(CountLabel(rrset[0].Header().Name))
-
- if strings.HasPrefix(rrset[0].Header().Name, "*") {
- rr.Labels-- // wildcard, remove from label count
- }
-
- sigwire := new(rrsigWireFmt)
- sigwire.TypeCovered = rr.TypeCovered
- sigwire.Algorithm = rr.Algorithm
- sigwire.Labels = rr.Labels
- sigwire.OrigTtl = rr.OrigTtl
- sigwire.Expiration = rr.Expiration
- sigwire.Inception = rr.Inception
- sigwire.KeyTag = rr.KeyTag
- // For signing, lowercase this name
- sigwire.SignerName = strings.ToLower(rr.SignerName)
-
- // Create the desired binary blob
- signdata := make([]byte, DefaultMsgSize)
- n, err := packSigWire(sigwire, signdata)
- if err != nil {
- return err
- }
- signdata = signdata[:n]
- wire, err := rawSignatureData(rrset, rr)
- if err != nil {
- return err
- }
-
- hash, ok := AlgorithmToHash[rr.Algorithm]
- if !ok {
- return ErrAlg
- }
-
- switch rr.Algorithm {
- case ED25519:
- // ed25519 signs the raw message and performs hashing internally.
- // All other supported signature schemes operate over the pre-hashed
- // message, and thus ed25519 must be handled separately here.
- //
- // The raw message is passed directly into sign and crypto.Hash(0) is
- // used to signal to the crypto.Signer that the data has not been hashed.
- signature, err := sign(k, append(signdata, wire...), crypto.Hash(0), rr.Algorithm)
- if err != nil {
- return err
- }
-
- rr.Signature = toBase64(signature)
- default:
- h := hash.New()
- h.Write(signdata)
- h.Write(wire)
-
- signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
- if err != nil {
- return err
- }
-
- rr.Signature = toBase64(signature)
- }
-
- return nil
-}
-
-func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) {
- signature, err := k.Sign(rand.Reader, hashed, hash)
- if err != nil {
- return nil, err
- }
-
- switch alg {
- case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
- return signature, nil
-
- case ECDSAP256SHA256, ECDSAP384SHA384:
- ecdsaSignature := &struct {
- R, S *big.Int
- }{}
- if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil {
- return nil, err
- }
-
- var intlen int
- switch alg {
- case ECDSAP256SHA256:
- intlen = 32
- case ECDSAP384SHA384:
- intlen = 48
- }
-
- signature := intToBytes(ecdsaSignature.R, intlen)
- signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
- return signature, nil
-
- // There is no defined interface for what a DSA backed crypto.Signer returns
- case DSA, DSANSEC3SHA1:
- // t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
- // signature := []byte{byte(t)}
- // signature = append(signature, intToBytes(r1, 20)...)
- // signature = append(signature, intToBytes(s1, 20)...)
- // rr.Signature = signature
-
- case ED25519:
- return signature, nil
- }
-
- return nil, ErrAlg
-}
-
-// Verify validates an RRSet with the signature and key. This is only the
-// cryptographic test, the signature validity period must be checked separately.
-// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
-func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
- // First the easy checks
- if !IsRRset(rrset) {
- return ErrRRset
- }
- if rr.KeyTag != k.KeyTag() {
- return ErrKey
- }
- if rr.Hdr.Class != k.Hdr.Class {
- return ErrKey
- }
- if rr.Algorithm != k.Algorithm {
- return ErrKey
- }
- if strings.ToLower(rr.SignerName) != strings.ToLower(k.Hdr.Name) {
- return ErrKey
- }
- if k.Protocol != 3 {
- return ErrKey
- }
-
- // IsRRset checked that we have at least one RR and that the RRs in
- // the set have consistent type, class, and name. Also check that type and
- // class matches the RRSIG record.
- if rrset[0].Header().Class != rr.Hdr.Class {
- return ErrRRset
- }
- if rrset[0].Header().Rrtype != rr.TypeCovered {
- return ErrRRset
- }
-
- // RFC 4035 5.3.2. Reconstructing the Signed Data
- // Copy the sig, except the rrsig data
- sigwire := new(rrsigWireFmt)
- sigwire.TypeCovered = rr.TypeCovered
- sigwire.Algorithm = rr.Algorithm
- sigwire.Labels = rr.Labels
- sigwire.OrigTtl = rr.OrigTtl
- sigwire.Expiration = rr.Expiration
- sigwire.Inception = rr.Inception
- sigwire.KeyTag = rr.KeyTag
- sigwire.SignerName = strings.ToLower(rr.SignerName)
- // Create the desired binary blob
- signeddata := make([]byte, DefaultMsgSize)
- n, err := packSigWire(sigwire, signeddata)
- if err != nil {
- return err
- }
- signeddata = signeddata[:n]
- wire, err := rawSignatureData(rrset, rr)
- if err != nil {
- return err
- }
-
- sigbuf := rr.sigBuf() // Get the binary signature data
- if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
- // TODO(miek)
- // remove the domain name and assume its ours?
- }
-
- hash, ok := AlgorithmToHash[rr.Algorithm]
- if !ok {
- return ErrAlg
- }
-
- switch rr.Algorithm {
- case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, RSAMD5:
- // TODO(mg): this can be done quicker, ie. cache the pubkey data somewhere??
- pubkey := k.publicKeyRSA() // Get the key
- if pubkey == nil {
- return ErrKey
- }
-
- h := hash.New()
- h.Write(signeddata)
- h.Write(wire)
- return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
-
- case ECDSAP256SHA256, ECDSAP384SHA384:
- pubkey := k.publicKeyECDSA()
- if pubkey == nil {
- return ErrKey
- }
-
- // Split sigbuf into the r and s coordinates
- r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
- s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
-
- h := hash.New()
- h.Write(signeddata)
- h.Write(wire)
- if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
- return nil
- }
- return ErrSig
-
- case ED25519:
- pubkey := k.publicKeyED25519()
- if pubkey == nil {
- return ErrKey
- }
-
- if ed25519.Verify(pubkey, append(signeddata, wire...), sigbuf) {
- return nil
- }
- return ErrSig
-
- default:
- return ErrAlg
- }
-}
-
-// ValidityPeriod uses RFC1982 serial arithmetic to calculate
-// if a signature period is valid. If t is the zero time, the
-// current time is taken other t is. Returns true if the signature
-// is valid at the given time, otherwise returns false.
-func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
- var utc int64
- if t.IsZero() {
- utc = time.Now().UTC().Unix()
- } else {
- utc = t.UTC().Unix()
- }
- modi := (int64(rr.Inception) - utc) / year68
- mode := (int64(rr.Expiration) - utc) / year68
- ti := int64(rr.Inception) + modi*year68
- te := int64(rr.Expiration) + mode*year68
- return ti <= utc && utc <= te
-}
-
-// Return the signatures base64 encodedig sigdata as a byte slice.
-func (rr *RRSIG) sigBuf() []byte {
- sigbuf, err := fromBase64([]byte(rr.Signature))
- if err != nil {
- return nil
- }
- return sigbuf
-}
-
-// publicKeyRSA returns the RSA public key from a DNSKEY record.
-func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
- keybuf, err := fromBase64([]byte(k.PublicKey))
- if err != nil {
- return nil
- }
-
- if len(keybuf) < 1+1+64 {
- // Exponent must be at least 1 byte and modulus at least 64
- return nil
- }
-
- // RFC 2537/3110, section 2. RSA Public KEY Resource Records
- // Length is in the 0th byte, unless its zero, then it
- // it in bytes 1 and 2 and its a 16 bit number
- explen := uint16(keybuf[0])
- keyoff := 1
- if explen == 0 {
- explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
- keyoff = 3
- }
-
- if explen > 4 || explen == 0 || keybuf[keyoff] == 0 {
- // Exponent larger than supported by the crypto package,
- // empty, or contains prohibited leading zero.
- return nil
- }
-
- modoff := keyoff + int(explen)
- modlen := len(keybuf) - modoff
- if modlen < 64 || modlen > 512 || keybuf[modoff] == 0 {
- // Modulus is too small, large, or contains prohibited leading zero.
- return nil
- }
-
- pubkey := new(rsa.PublicKey)
-
- expo := uint64(0)
- for i := 0; i < int(explen); i++ {
- expo <<= 8
- expo |= uint64(keybuf[keyoff+i])
- }
- if expo > 1<<31-1 {
- // Larger exponent than supported by the crypto package.
- return nil
- }
- pubkey.E = int(expo)
-
- pubkey.N = big.NewInt(0)
- pubkey.N.SetBytes(keybuf[modoff:])
-
- return pubkey
-}
-
-// publicKeyECDSA returns the Curve public key from the DNSKEY record.
-func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey {
- keybuf, err := fromBase64([]byte(k.PublicKey))
- if err != nil {
- return nil
- }
- pubkey := new(ecdsa.PublicKey)
- switch k.Algorithm {
- case ECDSAP256SHA256:
- pubkey.Curve = elliptic.P256()
- if len(keybuf) != 64 {
- // wrongly encoded key
- return nil
- }
- case ECDSAP384SHA384:
- pubkey.Curve = elliptic.P384()
- if len(keybuf) != 96 {
- // Wrongly encoded key
- return nil
- }
- }
- pubkey.X = big.NewInt(0)
- pubkey.X.SetBytes(keybuf[:len(keybuf)/2])
- pubkey.Y = big.NewInt(0)
- pubkey.Y.SetBytes(keybuf[len(keybuf)/2:])
- return pubkey
-}
-
-func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey {
- keybuf, err := fromBase64([]byte(k.PublicKey))
- if err != nil {
- return nil
- }
- if len(keybuf) < 22 {
- return nil
- }
- t, keybuf := int(keybuf[0]), keybuf[1:]
- size := 64 + t*8
- q, keybuf := keybuf[:20], keybuf[20:]
- if len(keybuf) != 3*size {
- return nil
- }
- p, keybuf := keybuf[:size], keybuf[size:]
- g, y := keybuf[:size], keybuf[size:]
- pubkey := new(dsa.PublicKey)
- pubkey.Parameters.Q = big.NewInt(0).SetBytes(q)
- pubkey.Parameters.P = big.NewInt(0).SetBytes(p)
- pubkey.Parameters.G = big.NewInt(0).SetBytes(g)
- pubkey.Y = big.NewInt(0).SetBytes(y)
- return pubkey
-}
-
-func (k *DNSKEY) publicKeyED25519() ed25519.PublicKey {
- keybuf, err := fromBase64([]byte(k.PublicKey))
- if err != nil {
- return nil
- }
- if len(keybuf) != ed25519.PublicKeySize {
- return nil
- }
- return keybuf
-}
-
-type wireSlice [][]byte
-
-func (p wireSlice) Len() int { return len(p) }
-func (p wireSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-func (p wireSlice) Less(i, j int) bool {
- _, ioff, _ := UnpackDomainName(p[i], 0)
- _, joff, _ := UnpackDomainName(p[j], 0)
- return bytes.Compare(p[i][ioff+10:], p[j][joff+10:]) < 0
-}
-
-// Return the raw signature data.
-func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
- wires := make(wireSlice, len(rrset))
- for i, r := range rrset {
- r1 := r.copy()
- r1.Header().Ttl = s.OrigTtl
- labels := SplitDomainName(r1.Header().Name)
- // 6.2. Canonical RR Form. (4) - wildcards
- if len(labels) > int(s.Labels) {
- // Wildcard
- r1.Header().Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "."
- }
- // RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase
- r1.Header().Name = strings.ToLower(r1.Header().Name)
- // 6.2. Canonical RR Form. (3) - domain rdata to lowercase.
- // NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
- // HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
- // SRV, DNAME, A6
- //
- // RFC 6840 - Clarifications and Implementation Notes for DNS Security (DNSSEC):
- // Section 6.2 of [RFC4034] also erroneously lists HINFO as a record
- // that needs conversion to lowercase, and twice at that. Since HINFO
- // records contain no domain names, they are not subject to case
- // conversion.
- switch x := r1.(type) {
- case *NS:
- x.Ns = strings.ToLower(x.Ns)
- case *MD:
- x.Md = strings.ToLower(x.Md)
- case *MF:
- x.Mf = strings.ToLower(x.Mf)
- case *CNAME:
- x.Target = strings.ToLower(x.Target)
- case *SOA:
- x.Ns = strings.ToLower(x.Ns)
- x.Mbox = strings.ToLower(x.Mbox)
- case *MB:
- x.Mb = strings.ToLower(x.Mb)
- case *MG:
- x.Mg = strings.ToLower(x.Mg)
- case *MR:
- x.Mr = strings.ToLower(x.Mr)
- case *PTR:
- x.Ptr = strings.ToLower(x.Ptr)
- case *MINFO:
- x.Rmail = strings.ToLower(x.Rmail)
- x.Email = strings.ToLower(x.Email)
- case *MX:
- x.Mx = strings.ToLower(x.Mx)
- case *RP:
- x.Mbox = strings.ToLower(x.Mbox)
- x.Txt = strings.ToLower(x.Txt)
- case *AFSDB:
- x.Hostname = strings.ToLower(x.Hostname)
- case *RT:
- x.Host = strings.ToLower(x.Host)
- case *SIG:
- x.SignerName = strings.ToLower(x.SignerName)
- case *PX:
- x.Map822 = strings.ToLower(x.Map822)
- x.Mapx400 = strings.ToLower(x.Mapx400)
- case *NAPTR:
- x.Replacement = strings.ToLower(x.Replacement)
- case *KX:
- x.Exchanger = strings.ToLower(x.Exchanger)
- case *SRV:
- x.Target = strings.ToLower(x.Target)
- case *DNAME:
- x.Target = strings.ToLower(x.Target)
- }
- // 6.2. Canonical RR Form. (5) - origTTL
- wire := make([]byte, r1.len()+1) // +1 to be safe(r)
- off, err1 := PackRR(r1, wire, 0, nil, false)
- if err1 != nil {
- return nil, err1
- }
- wire = wire[:off]
- wires[i] = wire
- }
- sort.Sort(wires)
- for i, wire := range wires {
- if i > 0 && bytes.Equal(wire, wires[i-1]) {
- continue
- }
- buf = append(buf, wire...)
- }
- return buf, nil
-}
-
-func packSigWire(sw *rrsigWireFmt, msg []byte) (int, error) {
- // copied from zmsg.go RRSIG packing
- off, err := packUint16(sw.TypeCovered, msg, 0)
- if err != nil {
- return off, err
- }
- off, err = packUint8(sw.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(sw.Labels, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(sw.OrigTtl, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(sw.Expiration, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(sw.Inception, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(sw.KeyTag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(sw.SignerName, msg, off, nil, false)
- if err != nil {
- return off, err
- }
- return off, nil
-}
-
-func packKeyWire(dw *dnskeyWireFmt, msg []byte) (int, error) {
- // copied from zmsg.go DNSKEY packing
- off, err := packUint16(dw.Flags, msg, 0)
- if err != nil {
- return off, err
- }
- off, err = packUint8(dw.Protocol, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(dw.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringBase64(dw.PublicKey, msg, off)
- if err != nil {
- return off, err
- }
- return off, nil
-}
diff --git a/vendor/github.com/miekg/dns/dnssec_keygen.go b/vendor/github.com/miekg/dns/dnssec_keygen.go
deleted file mode 100644
index 33e913ac527..00000000000
--- a/vendor/github.com/miekg/dns/dnssec_keygen.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package dns
-
-import (
- "crypto"
- "crypto/dsa"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "crypto/rsa"
- "math/big"
-
- "golang.org/x/crypto/ed25519"
-)
-
-// Generate generates a DNSKEY of the given bit size.
-// The public part is put inside the DNSKEY record.
-// The Algorithm in the key must be set as this will define
-// what kind of DNSKEY will be generated.
-// The ECDSA algorithms imply a fixed keysize, in that case
-// bits should be set to the size of the algorithm.
-func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) {
- switch k.Algorithm {
- case DSA, DSANSEC3SHA1:
- if bits != 1024 {
- return nil, ErrKeySize
- }
- case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
- if bits < 512 || bits > 4096 {
- return nil, ErrKeySize
- }
- case RSASHA512:
- if bits < 1024 || bits > 4096 {
- return nil, ErrKeySize
- }
- case ECDSAP256SHA256:
- if bits != 256 {
- return nil, ErrKeySize
- }
- case ECDSAP384SHA384:
- if bits != 384 {
- return nil, ErrKeySize
- }
- case ED25519:
- if bits != 256 {
- return nil, ErrKeySize
- }
- }
-
- switch k.Algorithm {
- case DSA, DSANSEC3SHA1:
- params := new(dsa.Parameters)
- if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
- return nil, err
- }
- priv := new(dsa.PrivateKey)
- priv.PublicKey.Parameters = *params
- err := dsa.GenerateKey(priv, rand.Reader)
- if err != nil {
- return nil, err
- }
- k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
- return priv, nil
- case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
- priv, err := rsa.GenerateKey(rand.Reader, bits)
- if err != nil {
- return nil, err
- }
- k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
- return priv, nil
- case ECDSAP256SHA256, ECDSAP384SHA384:
- var c elliptic.Curve
- switch k.Algorithm {
- case ECDSAP256SHA256:
- c = elliptic.P256()
- case ECDSAP384SHA384:
- c = elliptic.P384()
- }
- priv, err := ecdsa.GenerateKey(c, rand.Reader)
- if err != nil {
- return nil, err
- }
- k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
- return priv, nil
- case ED25519:
- pub, priv, err := ed25519.GenerateKey(rand.Reader)
- if err != nil {
- return nil, err
- }
- k.setPublicKeyED25519(pub)
- return priv, nil
- default:
- return nil, ErrAlg
- }
-}
-
-// Set the public key (the value E and N)
-func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool {
- if _E == 0 || _N == nil {
- return false
- }
- buf := exponentToBuf(_E)
- buf = append(buf, _N.Bytes()...)
- k.PublicKey = toBase64(buf)
- return true
-}
-
-// Set the public key for Elliptic Curves
-func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool {
- if _X == nil || _Y == nil {
- return false
- }
- var intlen int
- switch k.Algorithm {
- case ECDSAP256SHA256:
- intlen = 32
- case ECDSAP384SHA384:
- intlen = 48
- }
- k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen))
- return true
-}
-
-// Set the public key for DSA
-func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
- if _Q == nil || _P == nil || _G == nil || _Y == nil {
- return false
- }
- buf := dsaToBuf(_Q, _P, _G, _Y)
- k.PublicKey = toBase64(buf)
- return true
-}
-
-// Set the public key for Ed25519
-func (k *DNSKEY) setPublicKeyED25519(_K ed25519.PublicKey) bool {
- if _K == nil {
- return false
- }
- k.PublicKey = toBase64(_K)
- return true
-}
-
-// Set the public key (the values E and N) for RSA
-// RFC 3110: Section 2. RSA Public KEY Resource Records
-func exponentToBuf(_E int) []byte {
- var buf []byte
- i := big.NewInt(int64(_E)).Bytes()
- if len(i) < 256 {
- buf = make([]byte, 1, 1+len(i))
- buf[0] = uint8(len(i))
- } else {
- buf = make([]byte, 3, 3+len(i))
- buf[0] = 0
- buf[1] = uint8(len(i) >> 8)
- buf[2] = uint8(len(i))
- }
- buf = append(buf, i...)
- return buf
-}
-
-// Set the public key for X and Y for Curve. The two
-// values are just concatenated.
-func curveToBuf(_X, _Y *big.Int, intlen int) []byte {
- buf := intToBytes(_X, intlen)
- buf = append(buf, intToBytes(_Y, intlen)...)
- return buf
-}
-
-// Set the public key for X and Y for Curve. The two
-// values are just concatenated.
-func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte {
- t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8)
- buf := []byte{byte(t)}
- buf = append(buf, intToBytes(_Q, 20)...)
- buf = append(buf, intToBytes(_P, 64+t*8)...)
- buf = append(buf, intToBytes(_G, 64+t*8)...)
- buf = append(buf, intToBytes(_Y, 64+t*8)...)
- return buf
-}
diff --git a/vendor/github.com/miekg/dns/dnssec_keyscan.go b/vendor/github.com/miekg/dns/dnssec_keyscan.go
deleted file mode 100644
index 5e654223011..00000000000
--- a/vendor/github.com/miekg/dns/dnssec_keyscan.go
+++ /dev/null
@@ -1,352 +0,0 @@
-package dns
-
-import (
- "bufio"
- "crypto"
- "crypto/dsa"
- "crypto/ecdsa"
- "crypto/rsa"
- "io"
- "math/big"
- "strconv"
- "strings"
-
- "golang.org/x/crypto/ed25519"
-)
-
-// NewPrivateKey returns a PrivateKey by parsing the string s.
-// s should be in the same form of the BIND private key files.
-func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
- if s == "" || s[len(s)-1] != '\n' { // We need a closing newline
- return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
- }
- return k.ReadPrivateKey(strings.NewReader(s), "")
-}
-
-// ReadPrivateKey reads a private key from the io.Reader q. The string file is
-// only used in error reporting.
-// The public key must be known, because some cryptographic algorithms embed
-// the public inside the privatekey.
-func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) {
- m, err := parseKey(q, file)
- if m == nil {
- return nil, err
- }
- if _, ok := m["private-key-format"]; !ok {
- return nil, ErrPrivKey
- }
- if m["private-key-format"] != "v1.2" && m["private-key-format"] != "v1.3" {
- return nil, ErrPrivKey
- }
- // TODO(mg): check if the pubkey matches the private key
- algo, err := strconv.ParseUint(strings.SplitN(m["algorithm"], " ", 2)[0], 10, 8)
- if err != nil {
- return nil, ErrPrivKey
- }
- switch uint8(algo) {
- case DSA:
- priv, err := readPrivateKeyDSA(m)
- if err != nil {
- return nil, err
- }
- pub := k.publicKeyDSA()
- if pub == nil {
- return nil, ErrKey
- }
- priv.PublicKey = *pub
- return priv, nil
- case RSAMD5:
- fallthrough
- case RSASHA1:
- fallthrough
- case RSASHA1NSEC3SHA1:
- fallthrough
- case RSASHA256:
- fallthrough
- case RSASHA512:
- priv, err := readPrivateKeyRSA(m)
- if err != nil {
- return nil, err
- }
- pub := k.publicKeyRSA()
- if pub == nil {
- return nil, ErrKey
- }
- priv.PublicKey = *pub
- return priv, nil
- case ECCGOST:
- return nil, ErrPrivKey
- case ECDSAP256SHA256:
- fallthrough
- case ECDSAP384SHA384:
- priv, err := readPrivateKeyECDSA(m)
- if err != nil {
- return nil, err
- }
- pub := k.publicKeyECDSA()
- if pub == nil {
- return nil, ErrKey
- }
- priv.PublicKey = *pub
- return priv, nil
- case ED25519:
- return readPrivateKeyED25519(m)
- default:
- return nil, ErrPrivKey
- }
-}
-
-// Read a private key (file) string and create a public key. Return the private key.
-func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
- p := new(rsa.PrivateKey)
- p.Primes = []*big.Int{nil, nil}
- for k, v := range m {
- switch k {
- case "modulus", "publicexponent", "privateexponent", "prime1", "prime2":
- v1, err := fromBase64([]byte(v))
- if err != nil {
- return nil, err
- }
- switch k {
- case "modulus":
- p.PublicKey.N = big.NewInt(0)
- p.PublicKey.N.SetBytes(v1)
- case "publicexponent":
- i := big.NewInt(0)
- i.SetBytes(v1)
- p.PublicKey.E = int(i.Int64()) // int64 should be large enough
- case "privateexponent":
- p.D = big.NewInt(0)
- p.D.SetBytes(v1)
- case "prime1":
- p.Primes[0] = big.NewInt(0)
- p.Primes[0].SetBytes(v1)
- case "prime2":
- p.Primes[1] = big.NewInt(0)
- p.Primes[1].SetBytes(v1)
- }
- case "exponent1", "exponent2", "coefficient":
- // not used in Go (yet)
- case "created", "publish", "activate":
- // not used in Go (yet)
- }
- }
- return p, nil
-}
-
-func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) {
- p := new(dsa.PrivateKey)
- p.X = big.NewInt(0)
- for k, v := range m {
- switch k {
- case "private_value(x)":
- v1, err := fromBase64([]byte(v))
- if err != nil {
- return nil, err
- }
- p.X.SetBytes(v1)
- case "created", "publish", "activate":
- /* not used in Go (yet) */
- }
- }
- return p, nil
-}
-
-func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) {
- p := new(ecdsa.PrivateKey)
- p.D = big.NewInt(0)
- // TODO: validate that the required flags are present
- for k, v := range m {
- switch k {
- case "privatekey":
- v1, err := fromBase64([]byte(v))
- if err != nil {
- return nil, err
- }
- p.D.SetBytes(v1)
- case "created", "publish", "activate":
- /* not used in Go (yet) */
- }
- }
- return p, nil
-}
-
-func readPrivateKeyED25519(m map[string]string) (ed25519.PrivateKey, error) {
- var p ed25519.PrivateKey
- // TODO: validate that the required flags are present
- for k, v := range m {
- switch k {
- case "privatekey":
- p1, err := fromBase64([]byte(v))
- if err != nil {
- return nil, err
- }
- if len(p1) != ed25519.SeedSize {
- return nil, ErrPrivKey
- }
- p = ed25519.NewKeyFromSeed(p1)
- case "created", "publish", "activate":
- /* not used in Go (yet) */
- }
- }
- return p, nil
-}
-
-// parseKey reads a private key from r. It returns a map[string]string,
-// with the key-value pairs, or an error when the file is not correct.
-func parseKey(r io.Reader, file string) (map[string]string, error) {
- m := make(map[string]string)
- var k string
-
- c := newKLexer(r)
-
- for l, ok := c.Next(); ok; l, ok = c.Next() {
- // It should alternate
- switch l.value {
- case zKey:
- k = l.token
- case zValue:
- if k == "" {
- return nil, &ParseError{file, "no private key seen", l}
- }
-
- m[strings.ToLower(k)] = l.token
- k = ""
- }
- }
-
- // Surface any read errors from r.
- if err := c.Err(); err != nil {
- return nil, &ParseError{file: file, err: err.Error()}
- }
-
- return m, nil
-}
-
-type klexer struct {
- br io.ByteReader
-
- readErr error
-
- line int
- column int
-
- key bool
-
- eol bool // end-of-line
-}
-
-func newKLexer(r io.Reader) *klexer {
- br, ok := r.(io.ByteReader)
- if !ok {
- br = bufio.NewReaderSize(r, 1024)
- }
-
- return &klexer{
- br: br,
-
- line: 1,
-
- key: true,
- }
-}
-
-func (kl *klexer) Err() error {
- if kl.readErr == io.EOF {
- return nil
- }
-
- return kl.readErr
-}
-
-// readByte returns the next byte from the input
-func (kl *klexer) readByte() (byte, bool) {
- if kl.readErr != nil {
- return 0, false
- }
-
- c, err := kl.br.ReadByte()
- if err != nil {
- kl.readErr = err
- return 0, false
- }
-
- // delay the newline handling until the next token is delivered,
- // fixes off-by-one errors when reporting a parse error.
- if kl.eol {
- kl.line++
- kl.column = 0
- kl.eol = false
- }
-
- if c == '\n' {
- kl.eol = true
- } else {
- kl.column++
- }
-
- return c, true
-}
-
-func (kl *klexer) Next() (lex, bool) {
- var (
- l lex
-
- str strings.Builder
-
- commt bool
- )
-
- for x, ok := kl.readByte(); ok; x, ok = kl.readByte() {
- l.line, l.column = kl.line, kl.column
-
- switch x {
- case ':':
- if commt || !kl.key {
- break
- }
-
- kl.key = false
-
- // Next token is a space, eat it
- kl.readByte()
-
- l.value = zKey
- l.token = str.String()
- return l, true
- case ';':
- commt = true
- case '\n':
- if commt {
- // Reset a comment
- commt = false
- }
-
- kl.key = true
-
- l.value = zValue
- l.token = str.String()
- return l, true
- default:
- if commt {
- break
- }
-
- str.WriteByte(x)
- }
- }
-
- if kl.readErr != nil && kl.readErr != io.EOF {
- // Don't return any tokens after a read error occurs.
- return lex{value: zEOF}, false
- }
-
- if str.Len() > 0 {
- // Send remainder
- l.value = zValue
- l.token = str.String()
- return l, true
- }
-
- return lex{value: zEOF}, false
-}
diff --git a/vendor/github.com/miekg/dns/dnssec_privkey.go b/vendor/github.com/miekg/dns/dnssec_privkey.go
deleted file mode 100644
index 0c65be17bc6..00000000000
--- a/vendor/github.com/miekg/dns/dnssec_privkey.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package dns
-
-import (
- "crypto"
- "crypto/dsa"
- "crypto/ecdsa"
- "crypto/rsa"
- "math/big"
- "strconv"
-
- "golang.org/x/crypto/ed25519"
-)
-
-const format = "Private-key-format: v1.3\n"
-
-// PrivateKeyString converts a PrivateKey to a string. This string has the same
-// format as the private-key-file of BIND9 (Private-key-format: v1.3).
-// It needs some info from the key (the algorithm), so its a method of the DNSKEY
-// It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey
-func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
- algorithm := strconv.Itoa(int(r.Algorithm))
- algorithm += " (" + AlgorithmToString[r.Algorithm] + ")"
-
- switch p := p.(type) {
- case *rsa.PrivateKey:
- modulus := toBase64(p.PublicKey.N.Bytes())
- e := big.NewInt(int64(p.PublicKey.E))
- publicExponent := toBase64(e.Bytes())
- privateExponent := toBase64(p.D.Bytes())
- prime1 := toBase64(p.Primes[0].Bytes())
- prime2 := toBase64(p.Primes[1].Bytes())
- // Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
- // and from: http://code.google.com/p/go/issues/detail?id=987
- one := big.NewInt(1)
- p1 := big.NewInt(0).Sub(p.Primes[0], one)
- q1 := big.NewInt(0).Sub(p.Primes[1], one)
- exp1 := big.NewInt(0).Mod(p.D, p1)
- exp2 := big.NewInt(0).Mod(p.D, q1)
- coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
-
- exponent1 := toBase64(exp1.Bytes())
- exponent2 := toBase64(exp2.Bytes())
- coefficient := toBase64(coeff.Bytes())
-
- return format +
- "Algorithm: " + algorithm + "\n" +
- "Modulus: " + modulus + "\n" +
- "PublicExponent: " + publicExponent + "\n" +
- "PrivateExponent: " + privateExponent + "\n" +
- "Prime1: " + prime1 + "\n" +
- "Prime2: " + prime2 + "\n" +
- "Exponent1: " + exponent1 + "\n" +
- "Exponent2: " + exponent2 + "\n" +
- "Coefficient: " + coefficient + "\n"
-
- case *ecdsa.PrivateKey:
- var intlen int
- switch r.Algorithm {
- case ECDSAP256SHA256:
- intlen = 32
- case ECDSAP384SHA384:
- intlen = 48
- }
- private := toBase64(intToBytes(p.D, intlen))
- return format +
- "Algorithm: " + algorithm + "\n" +
- "PrivateKey: " + private + "\n"
-
- case *dsa.PrivateKey:
- T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
- prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
- subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
- base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
- priv := toBase64(intToBytes(p.X, 20))
- pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
- return format +
- "Algorithm: " + algorithm + "\n" +
- "Prime(p): " + prime + "\n" +
- "Subprime(q): " + subprime + "\n" +
- "Base(g): " + base + "\n" +
- "Private_value(x): " + priv + "\n" +
- "Public_value(y): " + pub + "\n"
-
- case ed25519.PrivateKey:
- private := toBase64(p.Seed())
- return format +
- "Algorithm: " + algorithm + "\n" +
- "PrivateKey: " + private + "\n"
-
- default:
- return ""
- }
-}
diff --git a/vendor/github.com/miekg/dns/doc.go b/vendor/github.com/miekg/dns/doc.go
deleted file mode 100644
index 0389d7248ef..00000000000
--- a/vendor/github.com/miekg/dns/doc.go
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
-Package dns implements a full featured interface to the Domain Name System.
-Server- and client-side programming is supported.
-The package allows complete control over what is sent out to the DNS. The package
-API follows the less-is-more principle, by presenting a small, clean interface.
-
-The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
-TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
-Note that domain names MUST be fully qualified, before sending them, unqualified
-names in a message will result in a packing failure.
-
-Resource records are native types. They are not stored in wire format.
-Basic usage pattern for creating a new resource record:
-
- r := new(dns.MX)
- r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX,
- Class: dns.ClassINET, Ttl: 3600}
- r.Preference = 10
- r.Mx = "mx.miek.nl."
-
-Or directly from a string:
-
- mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
-
-Or when the default origin (.) and TTL (3600) and class (IN) suit you:
-
- mx, err := dns.NewRR("miek.nl MX 10 mx.miek.nl")
-
-Or even:
-
- mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
-
-In the DNS messages are exchanged, these messages contain resource
-records (sets). Use pattern for creating a message:
-
- m := new(dns.Msg)
- m.SetQuestion("miek.nl.", dns.TypeMX)
-
-Or when not certain if the domain name is fully qualified:
-
- m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX)
-
-The message m is now a message with the question section set to ask
-the MX records for the miek.nl. zone.
-
-The following is slightly more verbose, but more flexible:
-
- m1 := new(dns.Msg)
- m1.Id = dns.Id()
- m1.RecursionDesired = true
- m1.Question = make([]dns.Question, 1)
- m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
-
-After creating a message it can be sent.
-Basic use pattern for synchronous querying the DNS at a
-server configured on 127.0.0.1 and port 53:
-
- c := new(dns.Client)
- in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
-
-Suppressing multiple outstanding queries (with the same question, type and
-class) is as easy as setting:
-
- c.SingleInflight = true
-
-More advanced options are available using a net.Dialer and the corresponding API.
-For example it is possible to set a timeout, or to specify a source IP address
-and port to use for the connection:
-
- c := new(dns.Client)
- laddr := net.UDPAddr{
- IP: net.ParseIP("[::1]"),
- Port: 12345,
- Zone: "",
- }
- c.Dialer := &net.Dialer{
- Timeout: 200 * time.Millisecond,
- LocalAddr: &laddr,
- }
- in, rtt, err := c.Exchange(m1, "8.8.8.8:53")
-
-If these "advanced" features are not needed, a simple UDP query can be sent,
-with:
-
- in, err := dns.Exchange(m1, "127.0.0.1:53")
-
-When this functions returns you will get dns message. A dns message consists
-out of four sections.
-The question section: in.Question, the answer section: in.Answer,
-the authority section: in.Ns and the additional section: in.Extra.
-
-Each of these sections (except the Question section) contain a []RR. Basic
-use pattern for accessing the rdata of a TXT RR as the first RR in
-the Answer section:
-
- if t, ok := in.Answer[0].(*dns.TXT); ok {
- // do something with t.Txt
- }
-
-Domain Name and TXT Character String Representations
-
-Both domain names and TXT character strings are converted to presentation
-form both when unpacked and when converted to strings.
-
-For TXT character strings, tabs, carriage returns and line feeds will be
-converted to \t, \r and \n respectively. Back slashes and quotations marks
-will be escaped. Bytes below 32 and above 127 will be converted to \DDD
-form.
-
-For domain names, in addition to the above rules brackets, periods,
-spaces, semicolons and the at symbol are escaped.
-
-DNSSEC
-
-DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It
-uses public key cryptography to sign resource records. The
-public keys are stored in DNSKEY records and the signatures in RRSIG records.
-
-Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit
-to a request.
-
- m := new(dns.Msg)
- m.SetEdns0(4096, true)
-
-Signature generation, signature verification and key generation are all supported.
-
-DYNAMIC UPDATES
-
-Dynamic updates reuses the DNS message format, but renames three of
-the sections. Question is Zone, Answer is Prerequisite, Authority is
-Update, only the Additional is not renamed. See RFC 2136 for the gory details.
-
-You can set a rather complex set of rules for the existence of absence of
-certain resource records or names in a zone to specify if resource records
-should be added or removed. The table from RFC 2136 supplemented with the Go
-DNS function shows which functions exist to specify the prerequisites.
-
- 3.2.4 - Table Of Metavalues Used In Prerequisite Section
-
- CLASS TYPE RDATA Meaning Function
- --------------------------------------------------------------
- ANY ANY empty Name is in use dns.NameUsed
- ANY rrset empty RRset exists (value indep) dns.RRsetUsed
- NONE ANY empty Name is not in use dns.NameNotUsed
- NONE rrset empty RRset does not exist dns.RRsetNotUsed
- zone rrset rr RRset exists (value dep) dns.Used
-
-The prerequisite section can also be left empty.
-If you have decided on the prerequisites you can tell what RRs should
-be added or deleted. The next table shows the options you have and
-what functions to call.
-
- 3.4.2.6 - Table Of Metavalues Used In Update Section
-
- CLASS TYPE RDATA Meaning Function
- ---------------------------------------------------------------
- ANY ANY empty Delete all RRsets from name dns.RemoveName
- ANY rrset empty Delete an RRset dns.RemoveRRset
- NONE rrset rr Delete an RR from RRset dns.Remove
- zone rrset rr Add to an RRset dns.Insert
-
-TRANSACTION SIGNATURE
-
-An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
-The supported algorithms include: HmacMD5, HmacSHA1, HmacSHA256 and HmacSHA512.
-
-Basic use pattern when querying with a TSIG name "axfr." (note that these key names
-must be fully qualified - as they are domain names) and the base64 secret
-"so6ZGir4GPAqINNh9U5c3A==":
-
-If an incoming message contains a TSIG record it MUST be the last record in
-the additional section (RFC2845 3.2). This means that you should make the
-call to SetTsig last, right before executing the query. If you make any
-changes to the RRset after calling SetTsig() the signature will be incorrect.
-
- c := new(dns.Client)
- c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
- m := new(dns.Msg)
- m.SetQuestion("miek.nl.", dns.TypeMX)
- m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
- ...
- // When sending the TSIG RR is calculated and filled in before sending
-
-When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
-TSIG, this is the basic use pattern. In this example we request an AXFR for
-miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
-and using the server 176.58.119.54:
-
- t := new(dns.Transfer)
- m := new(dns.Msg)
- t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
- m.SetAxfr("miek.nl.")
- m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
- c, err := t.In(m, "176.58.119.54:53")
- for r := range c { ... }
-
-You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
-If something is not correct an error is returned.
-
-Basic use pattern validating and replying to a message that has TSIG set.
-
- server := &dns.Server{Addr: ":53", Net: "udp"}
- server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
- go server.ListenAndServe()
- dns.HandleFunc(".", handleRequest)
-
- func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
- m := new(dns.Msg)
- m.SetReply(r)
- if r.IsTsig() != nil {
- if w.TsigStatus() == nil {
- // *Msg r has an TSIG record and it was validated
- m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
- } else {
- // *Msg r has an TSIG records and it was not valided
- }
- }
- w.WriteMsg(m)
- }
-
-PRIVATE RRS
-
-RFC 6895 sets aside a range of type codes for private use. This range
-is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
-can be used, before requesting an official type code from IANA.
-
-see http://miek.nl/2014/September/21/idn-and-private-rr-in-go-dns/ for more
-information.
-
-EDNS0
-
-EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated
-by RFC 6891. It defines an new RR type, the OPT RR, which is then completely
-abused.
-Basic use pattern for creating an (empty) OPT RR:
-
- o := new(dns.OPT)
- o.Hdr.Name = "." // MUST be the root zone, per definition.
- o.Hdr.Rrtype = dns.TypeOPT
-
-The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891)
-interfaces. Currently only a few have been standardized: EDNS0_NSID
-(RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note
-that these options may be combined in an OPT RR.
-Basic use pattern for a server to check if (and which) options are set:
-
- // o is a dns.OPT
- for _, s := range o.Option {
- switch e := s.(type) {
- case *dns.EDNS0_NSID:
- // do stuff with e.Nsid
- case *dns.EDNS0_SUBNET:
- // access e.Family, e.Address, etc.
- }
- }
-
-SIG(0)
-
-From RFC 2931:
-
- SIG(0) provides protection for DNS transactions and requests ....
- ... protection for glue records, DNS requests, protection for message headers
- on requests and responses, and protection of the overall integrity of a response.
-
-It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared
-secret approach in TSIG.
-Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and
-RSASHA512.
-
-Signing subsequent messages in multi-message sessions is not implemented.
-*/
-package dns
diff --git a/vendor/github.com/miekg/dns/duplicate.go b/vendor/github.com/miekg/dns/duplicate.go
deleted file mode 100644
index 6372e8a194f..00000000000
--- a/vendor/github.com/miekg/dns/duplicate.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package dns
-
-//go:generate go run duplicate_generate.go
-
-// IsDuplicate checks of r1 and r2 are duplicates of each other, excluding the TTL.
-// So this means the header data is equal *and* the RDATA is the same. Return true
-// is so, otherwise false.
-// It's is a protocol violation to have identical RRs in a message.
-func IsDuplicate(r1, r2 RR) bool {
- if r1.Header().Class != r2.Header().Class {
- return false
- }
- if r1.Header().Rrtype != r2.Header().Rrtype {
- return false
- }
- if !isDulicateName(r1.Header().Name, r2.Header().Name) {
- return false
- }
- // ignore TTL
-
- return isDuplicateRdata(r1, r2)
-}
-
-// isDulicateName checks if the domain names s1 and s2 are equal.
-func isDulicateName(s1, s2 string) bool { return equal(s1, s2) }
diff --git a/vendor/github.com/miekg/dns/edns.go b/vendor/github.com/miekg/dns/edns.go
deleted file mode 100644
index 18d054139b2..00000000000
--- a/vendor/github.com/miekg/dns/edns.go
+++ /dev/null
@@ -1,630 +0,0 @@
-package dns
-
-import (
- "encoding/binary"
- "encoding/hex"
- "errors"
- "fmt"
- "net"
- "strconv"
-)
-
-// EDNS0 Option codes.
-const (
- EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
- EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
- EDNS0NSID = 0x3 // nsid (See RFC 5001)
- EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
- EDNS0DHU = 0x6 // DS Hash Understood
- EDNS0N3U = 0x7 // NSEC3 Hash Understood
- EDNS0SUBNET = 0x8 // client-subnet (See RFC 7871)
- EDNS0EXPIRE = 0x9 // EDNS0 expire
- EDNS0COOKIE = 0xa // EDNS0 Cookie
- EDNS0TCPKEEPALIVE = 0xb // EDNS0 tcp keep alive (See RFC 7828)
- EDNS0PADDING = 0xc // EDNS0 padding (See RFC 7830)
- EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (See RFC 6891)
- EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (See RFC 6891)
- _DO = 1 << 15 // DNSSEC OK
-)
-
-// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
-// See RFC 6891.
-type OPT struct {
- Hdr RR_Header
- Option []EDNS0 `dns:"opt"`
-}
-
-func (rr *OPT) String() string {
- s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
- if rr.Do() {
- s += "flags: do; "
- } else {
- s += "flags: ; "
- }
- s += "udp: " + strconv.Itoa(int(rr.UDPSize()))
-
- for _, o := range rr.Option {
- switch o.(type) {
- case *EDNS0_NSID:
- s += "\n; NSID: " + o.String()
- h, e := o.pack()
- var r string
- if e == nil {
- for _, c := range h {
- r += "(" + string(c) + ")"
- }
- s += " " + r
- }
- case *EDNS0_SUBNET:
- s += "\n; SUBNET: " + o.String()
- case *EDNS0_COOKIE:
- s += "\n; COOKIE: " + o.String()
- case *EDNS0_UL:
- s += "\n; UPDATE LEASE: " + o.String()
- case *EDNS0_LLQ:
- s += "\n; LONG LIVED QUERIES: " + o.String()
- case *EDNS0_DAU:
- s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String()
- case *EDNS0_DHU:
- s += "\n; DS HASH UNDERSTOOD: " + o.String()
- case *EDNS0_N3U:
- s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
- case *EDNS0_LOCAL:
- s += "\n; LOCAL OPT: " + o.String()
- case *EDNS0_PADDING:
- s += "\n; PADDING: " + o.String()
- }
- }
- return s
-}
-
-func (rr *OPT) len() int {
- l := rr.Hdr.len()
- for i := 0; i < len(rr.Option); i++ {
- l += 4 // Account for 2-byte option code and 2-byte option length.
- lo, _ := rr.Option[i].pack()
- l += len(lo)
- }
- return l
-}
-
-// return the old value -> delete SetVersion?
-
-// Version returns the EDNS version used. Only zero is defined.
-func (rr *OPT) Version() uint8 {
- return uint8(rr.Hdr.Ttl & 0x00FF0000 >> 16)
-}
-
-// SetVersion sets the version of EDNS. This is usually zero.
-func (rr *OPT) SetVersion(v uint8) {
- rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | uint32(v)<<16
-}
-
-// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
-func (rr *OPT) ExtendedRcode() int {
- return int(rr.Hdr.Ttl&0xFF000000>>24) + 15
-}
-
-// SetExtendedRcode sets the EDNS extended RCODE field.
-func (rr *OPT) SetExtendedRcode(v uint8) {
- if v < RcodeBadVers { // Smaller than 16.. Use the 4 bits you have!
- return
- }
- rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | uint32(v-15)<<24
-}
-
-// UDPSize returns the UDP buffer size.
-func (rr *OPT) UDPSize() uint16 {
- return rr.Hdr.Class
-}
-
-// SetUDPSize sets the UDP buffer size.
-func (rr *OPT) SetUDPSize(size uint16) {
- rr.Hdr.Class = size
-}
-
-// Do returns the value of the DO (DNSSEC OK) bit.
-func (rr *OPT) Do() bool {
- return rr.Hdr.Ttl&_DO == _DO
-}
-
-// SetDo sets the DO (DNSSEC OK) bit.
-// If we pass an argument, set the DO bit to that value.
-// It is possible to pass 2 or more arguments. Any arguments after the 1st is silently ignored.
-func (rr *OPT) SetDo(do ...bool) {
- if len(do) == 1 {
- if do[0] {
- rr.Hdr.Ttl |= _DO
- } else {
- rr.Hdr.Ttl &^= _DO
- }
- } else {
- rr.Hdr.Ttl |= _DO
- }
-}
-
-// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.
-type EDNS0 interface {
- // Option returns the option code for the option.
- Option() uint16
- // pack returns the bytes of the option data.
- pack() ([]byte, error)
- // unpack sets the data as found in the buffer. Is also sets
- // the length of the slice as the length of the option data.
- unpack([]byte) error
- // String returns the string representation of the option.
- String() string
-}
-
-// EDNS0_NSID option is used to retrieve a nameserver
-// identifier. When sending a request Nsid must be set to the empty string
-// The identifier is an opaque string encoded as hex.
-// Basic use pattern for creating an nsid option:
-//
-// o := new(dns.OPT)
-// o.Hdr.Name = "."
-// o.Hdr.Rrtype = dns.TypeOPT
-// e := new(dns.EDNS0_NSID)
-// e.Code = dns.EDNS0NSID
-// e.Nsid = "AA"
-// o.Option = append(o.Option, e)
-type EDNS0_NSID struct {
- Code uint16 // Always EDNS0NSID
- Nsid string // This string needs to be hex encoded
-}
-
-func (e *EDNS0_NSID) pack() ([]byte, error) {
- h, err := hex.DecodeString(e.Nsid)
- if err != nil {
- return nil, err
- }
- return h, nil
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID } // Option returns the option code.
-func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
-func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
-
-// EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
-// an idea of where the client lives. See RFC 7871. It can then give back a different
-// answer depending on the location or network topology.
-// Basic use pattern for creating an subnet option:
-//
-// o := new(dns.OPT)
-// o.Hdr.Name = "."
-// o.Hdr.Rrtype = dns.TypeOPT
-// e := new(dns.EDNS0_SUBNET)
-// e.Code = dns.EDNS0SUBNET
-// e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
-// e.SourceNetmask = 32 // 32 for IPV4, 128 for IPv6
-// e.SourceScope = 0
-// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
-// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
-// o.Option = append(o.Option, e)
-//
-// This code will parse all the available bits when unpacking (up to optlen).
-// When packing it will apply SourceNetmask. If you need more advanced logic,
-// patches welcome and good luck.
-type EDNS0_SUBNET struct {
- Code uint16 // Always EDNS0SUBNET
- Family uint16 // 1 for IP, 2 for IP6
- SourceNetmask uint8
- SourceScope uint8
- Address net.IP
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_SUBNET) Option() uint16 { return EDNS0SUBNET }
-
-func (e *EDNS0_SUBNET) pack() ([]byte, error) {
- b := make([]byte, 4)
- binary.BigEndian.PutUint16(b[0:], e.Family)
- b[2] = e.SourceNetmask
- b[3] = e.SourceScope
- switch e.Family {
- case 0:
- // "dig" sets AddressFamily to 0 if SourceNetmask is also 0
- // We might don't need to complain either
- if e.SourceNetmask != 0 {
- return nil, errors.New("dns: bad address family")
- }
- case 1:
- if e.SourceNetmask > net.IPv4len*8 {
- return nil, errors.New("dns: bad netmask")
- }
- if len(e.Address.To4()) != net.IPv4len {
- return nil, errors.New("dns: bad address")
- }
- ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
- needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
- b = append(b, ip[:needLength]...)
- case 2:
- if e.SourceNetmask > net.IPv6len*8 {
- return nil, errors.New("dns: bad netmask")
- }
- if len(e.Address) != net.IPv6len {
- return nil, errors.New("dns: bad address")
- }
- ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
- needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
- b = append(b, ip[:needLength]...)
- default:
- return nil, errors.New("dns: bad address family")
- }
- return b, nil
-}
-
-func (e *EDNS0_SUBNET) unpack(b []byte) error {
- if len(b) < 4 {
- return ErrBuf
- }
- e.Family = binary.BigEndian.Uint16(b)
- e.SourceNetmask = b[2]
- e.SourceScope = b[3]
- switch e.Family {
- case 0:
- // "dig" sets AddressFamily to 0 if SourceNetmask is also 0
- // It's okay to accept such a packet
- if e.SourceNetmask != 0 {
- return errors.New("dns: bad address family")
- }
- e.Address = net.IPv4(0, 0, 0, 0)
- case 1:
- if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
- return errors.New("dns: bad netmask")
- }
- addr := make([]byte, net.IPv4len)
- for i := 0; i < net.IPv4len && 4+i < len(b); i++ {
- addr[i] = b[4+i]
- }
- e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
- case 2:
- if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
- return errors.New("dns: bad netmask")
- }
- addr := make([]byte, net.IPv6len)
- for i := 0; i < net.IPv6len && 4+i < len(b); i++ {
- addr[i] = b[4+i]
- }
- e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4],
- addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
- addr[11], addr[12], addr[13], addr[14], addr[15]}
- default:
- return errors.New("dns: bad address family")
- }
- return nil
-}
-
-func (e *EDNS0_SUBNET) String() (s string) {
- if e.Address == nil {
- s = ""
- } else if e.Address.To4() != nil {
- s = e.Address.String()
- } else {
- s = "[" + e.Address.String() + "]"
- }
- s += "/" + strconv.Itoa(int(e.SourceNetmask)) + "/" + strconv.Itoa(int(e.SourceScope))
- return
-}
-
-// The EDNS0_COOKIE option is used to add a DNS Cookie to a message.
-//
-// o := new(dns.OPT)
-// o.Hdr.Name = "."
-// o.Hdr.Rrtype = dns.TypeOPT
-// e := new(dns.EDNS0_COOKIE)
-// e.Code = dns.EDNS0COOKIE
-// e.Cookie = "24a5ac.."
-// o.Option = append(o.Option, e)
-//
-// The Cookie field consists out of a client cookie (RFC 7873 Section 4), that is
-// always 8 bytes. It may then optionally be followed by the server cookie. The server
-// cookie is of variable length, 8 to a maximum of 32 bytes. In other words:
-//
-// cCookie := o.Cookie[:16]
-// sCookie := o.Cookie[16:]
-//
-// There is no guarantee that the Cookie string has a specific length.
-type EDNS0_COOKIE struct {
- Code uint16 // Always EDNS0COOKIE
- Cookie string // Hex-encoded cookie data
-}
-
-func (e *EDNS0_COOKIE) pack() ([]byte, error) {
- h, err := hex.DecodeString(e.Cookie)
- if err != nil {
- return nil, err
- }
- return h, nil
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_COOKIE) Option() uint16 { return EDNS0COOKIE }
-func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil }
-func (e *EDNS0_COOKIE) String() string { return e.Cookie }
-
-// The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
-// an expiration on an update RR. This is helpful for clients that cannot clean
-// up after themselves. This is a draft RFC and more information can be found at
-// http://files.dns-sd.org/draft-sekar-dns-ul.txt
-//
-// o := new(dns.OPT)
-// o.Hdr.Name = "."
-// o.Hdr.Rrtype = dns.TypeOPT
-// e := new(dns.EDNS0_UL)
-// e.Code = dns.EDNS0UL
-// e.Lease = 120 // in seconds
-// o.Option = append(o.Option, e)
-type EDNS0_UL struct {
- Code uint16 // Always EDNS0UL
- Lease uint32
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
-func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) }
-
-// Copied: http://golang.org/src/pkg/net/dnsmsg.go
-func (e *EDNS0_UL) pack() ([]byte, error) {
- b := make([]byte, 4)
- binary.BigEndian.PutUint32(b, e.Lease)
- return b, nil
-}
-
-func (e *EDNS0_UL) unpack(b []byte) error {
- if len(b) < 4 {
- return ErrBuf
- }
- e.Lease = binary.BigEndian.Uint32(b)
- return nil
-}
-
-// EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
-// Implemented for completeness, as the EDNS0 type code is assigned.
-type EDNS0_LLQ struct {
- Code uint16 // Always EDNS0LLQ
- Version uint16
- Opcode uint16
- Error uint16
- Id uint64
- LeaseLife uint32
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ }
-
-func (e *EDNS0_LLQ) pack() ([]byte, error) {
- b := make([]byte, 18)
- binary.BigEndian.PutUint16(b[0:], e.Version)
- binary.BigEndian.PutUint16(b[2:], e.Opcode)
- binary.BigEndian.PutUint16(b[4:], e.Error)
- binary.BigEndian.PutUint64(b[6:], e.Id)
- binary.BigEndian.PutUint32(b[14:], e.LeaseLife)
- return b, nil
-}
-
-func (e *EDNS0_LLQ) unpack(b []byte) error {
- if len(b) < 18 {
- return ErrBuf
- }
- e.Version = binary.BigEndian.Uint16(b[0:])
- e.Opcode = binary.BigEndian.Uint16(b[2:])
- e.Error = binary.BigEndian.Uint16(b[4:])
- e.Id = binary.BigEndian.Uint64(b[6:])
- e.LeaseLife = binary.BigEndian.Uint32(b[14:])
- return nil
-}
-
-func (e *EDNS0_LLQ) String() string {
- s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
- " " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(uint64(e.Id), 10) +
- " " + strconv.FormatUint(uint64(e.LeaseLife), 10)
- return s
-}
-
-// EDNS0_DUA implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975.
-type EDNS0_DAU struct {
- Code uint16 // Always EDNS0DAU
- AlgCode []uint8
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_DAU) Option() uint16 { return EDNS0DAU }
-func (e *EDNS0_DAU) pack() ([]byte, error) { return e.AlgCode, nil }
-func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = b; return nil }
-
-func (e *EDNS0_DAU) String() string {
- s := ""
- for i := 0; i < len(e.AlgCode); i++ {
- if a, ok := AlgorithmToString[e.AlgCode[i]]; ok {
- s += " " + a
- } else {
- s += " " + strconv.Itoa(int(e.AlgCode[i]))
- }
- }
- return s
-}
-
-// EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975.
-type EDNS0_DHU struct {
- Code uint16 // Always EDNS0DHU
- AlgCode []uint8
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_DHU) Option() uint16 { return EDNS0DHU }
-func (e *EDNS0_DHU) pack() ([]byte, error) { return e.AlgCode, nil }
-func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = b; return nil }
-
-func (e *EDNS0_DHU) String() string {
- s := ""
- for i := 0; i < len(e.AlgCode); i++ {
- if a, ok := HashToString[e.AlgCode[i]]; ok {
- s += " " + a
- } else {
- s += " " + strconv.Itoa(int(e.AlgCode[i]))
- }
- }
- return s
-}
-
-// EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975.
-type EDNS0_N3U struct {
- Code uint16 // Always EDNS0N3U
- AlgCode []uint8
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_N3U) Option() uint16 { return EDNS0N3U }
-func (e *EDNS0_N3U) pack() ([]byte, error) { return e.AlgCode, nil }
-func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = b; return nil }
-
-func (e *EDNS0_N3U) String() string {
- // Re-use the hash map
- s := ""
- for i := 0; i < len(e.AlgCode); i++ {
- if a, ok := HashToString[e.AlgCode[i]]; ok {
- s += " " + a
- } else {
- s += " " + strconv.Itoa(int(e.AlgCode[i]))
- }
- }
- return s
-}
-
-// EDNS0_EXPIRE implementes the EDNS0 option as described in RFC 7314.
-type EDNS0_EXPIRE struct {
- Code uint16 // Always EDNS0EXPIRE
- Expire uint32
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
-func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
-
-func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
- b := make([]byte, 4)
- b[0] = byte(e.Expire >> 24)
- b[1] = byte(e.Expire >> 16)
- b[2] = byte(e.Expire >> 8)
- b[3] = byte(e.Expire)
- return b, nil
-}
-
-func (e *EDNS0_EXPIRE) unpack(b []byte) error {
- if len(b) < 4 {
- return ErrBuf
- }
- e.Expire = binary.BigEndian.Uint32(b)
- return nil
-}
-
-// The EDNS0_LOCAL option is used for local/experimental purposes. The option
-// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
-// (RFC6891), although any unassigned code can actually be used. The content of
-// the option is made available in Data, unaltered.
-// Basic use pattern for creating a local option:
-//
-// o := new(dns.OPT)
-// o.Hdr.Name = "."
-// o.Hdr.Rrtype = dns.TypeOPT
-// e := new(dns.EDNS0_LOCAL)
-// e.Code = dns.EDNS0LOCALSTART
-// e.Data = []byte{72, 82, 74}
-// o.Option = append(o.Option, e)
-type EDNS0_LOCAL struct {
- Code uint16
- Data []byte
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
-func (e *EDNS0_LOCAL) String() string {
- return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
-}
-
-func (e *EDNS0_LOCAL) pack() ([]byte, error) {
- b := make([]byte, len(e.Data))
- copied := copy(b, e.Data)
- if copied != len(e.Data) {
- return nil, ErrBuf
- }
- return b, nil
-}
-
-func (e *EDNS0_LOCAL) unpack(b []byte) error {
- e.Data = make([]byte, len(b))
- copied := copy(e.Data, b)
- if copied != len(b) {
- return ErrBuf
- }
- return nil
-}
-
-// EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep
-// the TCP connection alive. See RFC 7828.
-type EDNS0_TCP_KEEPALIVE struct {
- Code uint16 // Always EDNSTCPKEEPALIVE
- Length uint16 // the value 0 if the TIMEOUT is omitted, the value 2 if it is present;
- Timeout uint16 // an idle timeout value for the TCP connection, specified in units of 100 milliseconds, encoded in network byte order.
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE }
-
-func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) {
- if e.Timeout != 0 && e.Length != 2 {
- return nil, errors.New("dns: timeout specified but length is not 2")
- }
- if e.Timeout == 0 && e.Length != 0 {
- return nil, errors.New("dns: timeout not specified but length is not 0")
- }
- b := make([]byte, 4+e.Length)
- binary.BigEndian.PutUint16(b[0:], e.Code)
- binary.BigEndian.PutUint16(b[2:], e.Length)
- if e.Length == 2 {
- binary.BigEndian.PutUint16(b[4:], e.Timeout)
- }
- return b, nil
-}
-
-func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error {
- if len(b) < 4 {
- return ErrBuf
- }
- e.Length = binary.BigEndian.Uint16(b[2:4])
- if e.Length != 0 && e.Length != 2 {
- return errors.New("dns: length mismatch, want 0/2 but got " + strconv.FormatUint(uint64(e.Length), 10))
- }
- if e.Length == 2 {
- if len(b) < 6 {
- return ErrBuf
- }
- e.Timeout = binary.BigEndian.Uint16(b[4:6])
- }
- return nil
-}
-
-func (e *EDNS0_TCP_KEEPALIVE) String() (s string) {
- s = "use tcp keep-alive"
- if e.Length == 0 {
- s += ", timeout omitted"
- } else {
- s += fmt.Sprintf(", timeout %dms", e.Timeout*100)
- }
- return
-}
-
-// EDNS0_PADDING option is used to add padding to a request/response. The default
-// value of padding SHOULD be 0x0 but other values MAY be used, for instance if
-// compression is applied before encryption which may break signatures.
-type EDNS0_PADDING struct {
- Padding []byte
-}
-
-// Option implements the EDNS0 interface.
-func (e *EDNS0_PADDING) Option() uint16 { return EDNS0PADDING }
-func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil }
-func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = b; return nil }
-func (e *EDNS0_PADDING) String() string { return fmt.Sprintf("%0X", e.Padding) }
diff --git a/vendor/github.com/miekg/dns/format.go b/vendor/github.com/miekg/dns/format.go
deleted file mode 100644
index 3f5303c2013..00000000000
--- a/vendor/github.com/miekg/dns/format.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package dns
-
-import (
- "net"
- "reflect"
- "strconv"
-)
-
-// NumField returns the number of rdata fields r has.
-func NumField(r RR) int {
- return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header
-}
-
-// Field returns the rdata field i as a string. Fields are indexed starting from 1.
-// RR types that holds slice data, for instance the NSEC type bitmap will return a single
-// string where the types are concatenated using a space.
-// Accessing non existing fields will cause a panic.
-func Field(r RR, i int) string {
- if i == 0 {
- return ""
- }
- d := reflect.ValueOf(r).Elem().Field(i)
- switch k := d.Kind(); k {
- case reflect.String:
- return d.String()
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return strconv.FormatInt(d.Int(), 10)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return strconv.FormatUint(d.Uint(), 10)
- case reflect.Slice:
- switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
- case `dns:"a"`:
- // TODO(miek): Hmm store this as 16 bytes
- if d.Len() < net.IPv6len {
- return net.IPv4(byte(d.Index(0).Uint()),
- byte(d.Index(1).Uint()),
- byte(d.Index(2).Uint()),
- byte(d.Index(3).Uint())).String()
- }
- return net.IPv4(byte(d.Index(12).Uint()),
- byte(d.Index(13).Uint()),
- byte(d.Index(14).Uint()),
- byte(d.Index(15).Uint())).String()
- case `dns:"aaaa"`:
- return net.IP{
- byte(d.Index(0).Uint()),
- byte(d.Index(1).Uint()),
- byte(d.Index(2).Uint()),
- byte(d.Index(3).Uint()),
- byte(d.Index(4).Uint()),
- byte(d.Index(5).Uint()),
- byte(d.Index(6).Uint()),
- byte(d.Index(7).Uint()),
- byte(d.Index(8).Uint()),
- byte(d.Index(9).Uint()),
- byte(d.Index(10).Uint()),
- byte(d.Index(11).Uint()),
- byte(d.Index(12).Uint()),
- byte(d.Index(13).Uint()),
- byte(d.Index(14).Uint()),
- byte(d.Index(15).Uint()),
- }.String()
- case `dns:"nsec"`:
- if d.Len() == 0 {
- return ""
- }
- s := Type(d.Index(0).Uint()).String()
- for i := 1; i < d.Len(); i++ {
- s += " " + Type(d.Index(i).Uint()).String()
- }
- return s
- default:
- // if it does not have a tag its a string slice
- fallthrough
- case `dns:"txt"`:
- if d.Len() == 0 {
- return ""
- }
- s := d.Index(0).String()
- for i := 1; i < d.Len(); i++ {
- s += " " + d.Index(i).String()
- }
- return s
- }
- }
- return ""
-}
diff --git a/vendor/github.com/miekg/dns/fuzz.go b/vendor/github.com/miekg/dns/fuzz.go
deleted file mode 100644
index a8a09184d40..00000000000
--- a/vendor/github.com/miekg/dns/fuzz.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// +build fuzz
-
-package dns
-
-func Fuzz(data []byte) int {
- msg := new(Msg)
-
- if err := msg.Unpack(data); err != nil {
- return 0
- }
- if _, err := msg.Pack(); err != nil {
- return 0
- }
-
- return 1
-}
-
-func FuzzNewRR(data []byte) int {
- if _, err := NewRR(string(data)); err != nil {
- return 0
- }
- return 1
-}
diff --git a/vendor/github.com/miekg/dns/generate.go b/vendor/github.com/miekg/dns/generate.go
deleted file mode 100644
index 97bc39f58a8..00000000000
--- a/vendor/github.com/miekg/dns/generate.go
+++ /dev/null
@@ -1,242 +0,0 @@
-package dns
-
-import (
- "bytes"
- "fmt"
- "io"
- "strconv"
- "strings"
-)
-
-// Parse the $GENERATE statement as used in BIND9 zones.
-// See http://www.zytrax.com/books/dns/ch8/generate.html for instance.
-// We are called after '$GENERATE '. After which we expect:
-// * the range (12-24/2)
-// * lhs (ownername)
-// * [[ttl][class]]
-// * type
-// * rhs (rdata)
-// But we are lazy here, only the range is parsed *all* occurrences
-// of $ after that are interpreted.
-func (zp *ZoneParser) generate(l lex) (RR, bool) {
- token := l.token
- step := 1
- if i := strings.IndexByte(token, '/'); i >= 0 {
- if i+1 == len(token) {
- return zp.setParseError("bad step in $GENERATE range", l)
- }
-
- s, err := strconv.Atoi(token[i+1:])
- if err != nil || s <= 0 {
- return zp.setParseError("bad step in $GENERATE range", l)
- }
-
- step = s
- token = token[:i]
- }
-
- sx := strings.SplitN(token, "-", 2)
- if len(sx) != 2 {
- return zp.setParseError("bad start-stop in $GENERATE range", l)
- }
-
- start, err := strconv.Atoi(sx[0])
- if err != nil {
- return zp.setParseError("bad start in $GENERATE range", l)
- }
-
- end, err := strconv.Atoi(sx[1])
- if err != nil {
- return zp.setParseError("bad stop in $GENERATE range", l)
- }
- if end < 0 || start < 0 || end < start {
- return zp.setParseError("bad range in $GENERATE range", l)
- }
-
- zp.c.Next() // _BLANK
-
- // Create a complete new string, which we then parse again.
- var s string
- for l, ok := zp.c.Next(); ok; l, ok = zp.c.Next() {
- if l.err {
- return zp.setParseError("bad data in $GENERATE directive", l)
- }
- if l.value == zNewline {
- break
- }
-
- s += l.token
- }
-
- r := &generateReader{
- s: s,
-
- cur: start,
- start: start,
- end: end,
- step: step,
-
- file: zp.file,
- lex: &l,
- }
- zp.sub = NewZoneParser(r, zp.origin, zp.file)
- zp.sub.includeDepth, zp.sub.includeAllowed = zp.includeDepth, zp.includeAllowed
- zp.sub.SetDefaultTTL(defaultTtl)
- return zp.subNext()
-}
-
-type generateReader struct {
- s string
- si int
-
- cur int
- start int
- end int
- step int
-
- mod bytes.Buffer
-
- escape bool
-
- eof bool
-
- file string
- lex *lex
-}
-
-func (r *generateReader) parseError(msg string, end int) *ParseError {
- r.eof = true // Make errors sticky.
-
- l := *r.lex
- l.token = r.s[r.si-1 : end]
- l.column += r.si // l.column starts one zBLANK before r.s
-
- return &ParseError{r.file, msg, l}
-}
-
-func (r *generateReader) Read(p []byte) (int, error) {
- // NewZLexer, through NewZoneParser, should use ReadByte and
- // not end up here.
-
- panic("not implemented")
-}
-
-func (r *generateReader) ReadByte() (byte, error) {
- if r.eof {
- return 0, io.EOF
- }
- if r.mod.Len() > 0 {
- return r.mod.ReadByte()
- }
-
- if r.si >= len(r.s) {
- r.si = 0
- r.cur += r.step
-
- r.eof = r.cur > r.end || r.cur < 0
- return '\n', nil
- }
-
- si := r.si
- r.si++
-
- switch r.s[si] {
- case '\\':
- if r.escape {
- r.escape = false
- return '\\', nil
- }
-
- r.escape = true
- return r.ReadByte()
- case '$':
- if r.escape {
- r.escape = false
- return '$', nil
- }
-
- mod := "%d"
-
- if si >= len(r.s)-1 {
- // End of the string
- fmt.Fprintf(&r.mod, mod, r.cur)
- return r.mod.ReadByte()
- }
-
- if r.s[si+1] == '$' {
- r.si++
- return '$', nil
- }
-
- var offset int
-
- // Search for { and }
- if r.s[si+1] == '{' {
- // Modifier block
- sep := strings.Index(r.s[si+2:], "}")
- if sep < 0 {
- return 0, r.parseError("bad modifier in $GENERATE", len(r.s))
- }
-
- var errMsg string
- mod, offset, errMsg = modToPrintf(r.s[si+2 : si+2+sep])
- if errMsg != "" {
- return 0, r.parseError(errMsg, si+3+sep)
- }
- if r.start+offset < 0 || r.end+offset > 1<<31-1 {
- return 0, r.parseError("bad offset in $GENERATE", si+3+sep)
- }
-
- r.si += 2 + sep // Jump to it
- }
-
- fmt.Fprintf(&r.mod, mod, r.cur+offset)
- return r.mod.ReadByte()
- default:
- if r.escape { // Pretty useless here
- r.escape = false
- return r.ReadByte()
- }
-
- return r.s[si], nil
- }
-}
-
-// Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
-func modToPrintf(s string) (string, int, string) {
- // Modifier is { offset [ ,width [ ,base ] ] } - provide default
- // values for optional width and type, if necessary.
- var offStr, widthStr, base string
- switch xs := strings.Split(s, ","); len(xs) {
- case 1:
- offStr, widthStr, base = xs[0], "0", "d"
- case 2:
- offStr, widthStr, base = xs[0], xs[1], "d"
- case 3:
- offStr, widthStr, base = xs[0], xs[1], xs[2]
- default:
- return "", 0, "bad modifier in $GENERATE"
- }
-
- switch base {
- case "o", "d", "x", "X":
- default:
- return "", 0, "bad base in $GENERATE"
- }
-
- offset, err := strconv.Atoi(offStr)
- if err != nil {
- return "", 0, "bad offset in $GENERATE"
- }
-
- width, err := strconv.Atoi(widthStr)
- if err != nil || width < 0 || width > 255 {
- return "", 0, "bad width in $GENERATE"
- }
-
- if width == 0 {
- return "%" + base, offset, ""
- }
-
- return "%0" + widthStr + base, offset, ""
-}
diff --git a/vendor/github.com/miekg/dns/labels.go b/vendor/github.com/miekg/dns/labels.go
deleted file mode 100644
index 577fc59d2cc..00000000000
--- a/vendor/github.com/miekg/dns/labels.go
+++ /dev/null
@@ -1,191 +0,0 @@
-package dns
-
-// Holds a bunch of helper functions for dealing with labels.
-
-// SplitDomainName splits a name string into it's labels.
-// www.miek.nl. returns []string{"www", "miek", "nl"}
-// .www.miek.nl. returns []string{"", "www", "miek", "nl"},
-// The root label (.) returns nil. Note that using
-// strings.Split(s) will work in most cases, but does not handle
-// escaped dots (\.) for instance.
-// s must be a syntactically valid domain name, see IsDomainName.
-func SplitDomainName(s string) (labels []string) {
- if len(s) == 0 {
- return nil
- }
- fqdnEnd := 0 // offset of the final '.' or the length of the name
- idx := Split(s)
- begin := 0
- if s[len(s)-1] == '.' {
- fqdnEnd = len(s) - 1
- } else {
- fqdnEnd = len(s)
- }
-
- switch len(idx) {
- case 0:
- return nil
- case 1:
- // no-op
- default:
- end := 0
- for i := 1; i < len(idx); i++ {
- end = idx[i]
- labels = append(labels, s[begin:end-1])
- begin = end
- }
- }
-
- labels = append(labels, s[begin:fqdnEnd])
- return labels
-}
-
-// CompareDomainName compares the names s1 and s2 and
-// returns how many labels they have in common starting from the *right*.
-// The comparison stops at the first inequality. The names are downcased
-// before the comparison.
-//
-// www.miek.nl. and miek.nl. have two labels in common: miek and nl
-// www.miek.nl. and www.bla.nl. have one label in common: nl
-//
-// s1 and s2 must be syntactically valid domain names.
-func CompareDomainName(s1, s2 string) (n int) {
- // the first check: root label
- if s1 == "." || s2 == "." {
- return 0
- }
-
- l1 := Split(s1)
- l2 := Split(s2)
-
- j1 := len(l1) - 1 // end
- i1 := len(l1) - 2 // start
- j2 := len(l2) - 1
- i2 := len(l2) - 2
- // the second check can be done here: last/only label
- // before we fall through into the for-loop below
- if equal(s1[l1[j1]:], s2[l2[j2]:]) {
- n++
- } else {
- return
- }
- for {
- if i1 < 0 || i2 < 0 {
- break
- }
- if equal(s1[l1[i1]:l1[j1]], s2[l2[i2]:l2[j2]]) {
- n++
- } else {
- break
- }
- j1--
- i1--
- j2--
- i2--
- }
- return
-}
-
-// CountLabel counts the the number of labels in the string s.
-// s must be a syntactically valid domain name.
-func CountLabel(s string) (labels int) {
- if s == "." {
- return
- }
- off := 0
- end := false
- for {
- off, end = NextLabel(s, off)
- labels++
- if end {
- return
- }
- }
-}
-
-// Split splits a name s into its label indexes.
-// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
-// The root name (.) returns nil. Also see SplitDomainName.
-// s must be a syntactically valid domain name.
-func Split(s string) []int {
- if s == "." {
- return nil
- }
- idx := make([]int, 1, 3)
- off := 0
- end := false
-
- for {
- off, end = NextLabel(s, off)
- if end {
- return idx
- }
- idx = append(idx, off)
- }
-}
-
-// NextLabel returns the index of the start of the next label in the
-// string s starting at offset.
-// The bool end is true when the end of the string has been reached.
-// Also see PrevLabel.
-func NextLabel(s string, offset int) (i int, end bool) {
- quote := false
- for i = offset; i < len(s)-1; i++ {
- switch s[i] {
- case '\\':
- quote = !quote
- default:
- quote = false
- case '.':
- if quote {
- quote = !quote
- continue
- }
- return i + 1, false
- }
- }
- return i + 1, true
-}
-
-// PrevLabel returns the index of the label when starting from the right and
-// jumping n labels to the left.
-// The bool start is true when the start of the string has been overshot.
-// Also see NextLabel.
-func PrevLabel(s string, n int) (i int, start bool) {
- if n == 0 {
- return len(s), false
- }
- lab := Split(s)
- if lab == nil {
- return 0, true
- }
- if n > len(lab) {
- return 0, true
- }
- return lab[len(lab)-n], false
-}
-
-// equal compares a and b while ignoring case. It returns true when equal otherwise false.
-func equal(a, b string) bool {
- // might be lifted into API function.
- la := len(a)
- lb := len(b)
- if la != lb {
- return false
- }
-
- for i := la - 1; i >= 0; i-- {
- ai := a[i]
- bi := b[i]
- if ai >= 'A' && ai <= 'Z' {
- ai |= 'a' - 'A'
- }
- if bi >= 'A' && bi <= 'Z' {
- bi |= 'a' - 'A'
- }
- if ai != bi {
- return false
- }
- }
- return true
-}
diff --git a/vendor/github.com/miekg/dns/listen_go111.go b/vendor/github.com/miekg/dns/listen_go111.go
deleted file mode 100644
index fad195cfeb4..00000000000
--- a/vendor/github.com/miekg/dns/listen_go111.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// +build go1.11
-// +build aix darwin dragonfly freebsd linux netbsd openbsd
-
-package dns
-
-import (
- "context"
- "net"
- "syscall"
-
- "golang.org/x/sys/unix"
-)
-
-const supportsReusePort = true
-
-func reuseportControl(network, address string, c syscall.RawConn) error {
- var opErr error
- err := c.Control(func(fd uintptr) {
- opErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
- })
- if err != nil {
- return err
- }
-
- return opErr
-}
-
-func listenTCP(network, addr string, reuseport bool) (net.Listener, error) {
- var lc net.ListenConfig
- if reuseport {
- lc.Control = reuseportControl
- }
-
- return lc.Listen(context.Background(), network, addr)
-}
-
-func listenUDP(network, addr string, reuseport bool) (net.PacketConn, error) {
- var lc net.ListenConfig
- if reuseport {
- lc.Control = reuseportControl
- }
-
- return lc.ListenPacket(context.Background(), network, addr)
-}
diff --git a/vendor/github.com/miekg/dns/listen_go_not111.go b/vendor/github.com/miekg/dns/listen_go_not111.go
deleted file mode 100644
index b9201417abe..00000000000
--- a/vendor/github.com/miekg/dns/listen_go_not111.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// +build !go1.11 !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
-
-package dns
-
-import "net"
-
-const supportsReusePort = false
-
-func listenTCP(network, addr string, reuseport bool) (net.Listener, error) {
- if reuseport {
- // TODO(tmthrgd): return an error?
- }
-
- return net.Listen(network, addr)
-}
-
-func listenUDP(network, addr string, reuseport bool) (net.PacketConn, error) {
- if reuseport {
- // TODO(tmthrgd): return an error?
- }
-
- return net.ListenPacket(network, addr)
-}
diff --git a/vendor/github.com/miekg/dns/msg.go b/vendor/github.com/miekg/dns/msg.go
deleted file mode 100644
index 47ac6cf2813..00000000000
--- a/vendor/github.com/miekg/dns/msg.go
+++ /dev/null
@@ -1,1181 +0,0 @@
-// DNS packet assembly, see RFC 1035. Converting from - Unpack() -
-// and to - Pack() - wire format.
-// All the packers and unpackers take a (msg []byte, off int)
-// and return (off1 int, ok bool). If they return ok==false, they
-// also return off1==len(msg), so that the next unpacker will
-// also fail. This lets us avoid checks of ok until the end of a
-// packing sequence.
-
-package dns
-
-//go:generate go run msg_generate.go
-//go:generate go run compress_generate.go
-
-import (
- crand "crypto/rand"
- "encoding/binary"
- "fmt"
- "math/big"
- "math/rand"
- "strconv"
- "sync"
-)
-
-const (
- maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
- maxDomainNameWireOctets = 255 // See RFC 1035 section 2.3.4
-)
-
-// Errors defined in this package.
-var (
- ErrAlg error = &Error{err: "bad algorithm"} // ErrAlg indicates an error with the (DNSSEC) algorithm.
- ErrAuth error = &Error{err: "bad authentication"} // ErrAuth indicates an error in the TSIG authentication.
- ErrBuf error = &Error{err: "buffer size too small"} // ErrBuf indicates that the buffer used is too small for the message.
- ErrConnEmpty error = &Error{err: "conn has no connection"} // ErrConnEmpty indicates a connection is being used before it is initialized.
- ErrExtendedRcode error = &Error{err: "bad extended rcode"} // ErrExtendedRcode ...
- ErrFqdn error = &Error{err: "domain must be fully qualified"} // ErrFqdn indicates that a domain name does not have a closing dot.
- ErrId error = &Error{err: "id mismatch"} // ErrId indicates there is a mismatch with the message's ID.
- ErrKeyAlg error = &Error{err: "bad key algorithm"} // ErrKeyAlg indicates that the algorithm in the key is not valid.
- ErrKey error = &Error{err: "bad key"}
- ErrKeySize error = &Error{err: "bad key size"}
- ErrLongDomain error = &Error{err: fmt.Sprintf("domain name exceeded %d wire-format octets", maxDomainNameWireOctets)}
- ErrNoSig error = &Error{err: "no signature found"}
- ErrPrivKey error = &Error{err: "bad private key"}
- ErrRcode error = &Error{err: "bad rcode"}
- ErrRdata error = &Error{err: "bad rdata"}
- ErrRRset error = &Error{err: "bad rrset"}
- ErrSecret error = &Error{err: "no secrets defined"}
- ErrShortRead error = &Error{err: "short read"}
- ErrSig error = &Error{err: "bad signature"} // ErrSig indicates that a signature can not be cryptographically validated.
- ErrSoa error = &Error{err: "no SOA"} // ErrSOA indicates that no SOA RR was seen when doing zone transfers.
- ErrTime error = &Error{err: "bad time"} // ErrTime indicates a timing error in TSIG authentication.
- ErrTruncated error = &Error{err: "failed to unpack truncated message"} // ErrTruncated indicates that we failed to unpack a truncated message. We unpacked as much as we had so Msg can still be used, if desired.
-)
-
-// Id by default, returns a 16 bits random number to be used as a
-// message id. The random provided should be good enough. This being a
-// variable the function can be reassigned to a custom function.
-// For instance, to make it return a static value:
-//
-// dns.Id = func() uint16 { return 3 }
-var Id = id
-
-var (
- idLock sync.Mutex
- idRand *rand.Rand
-)
-
-// id returns a 16 bits random number to be used as a
-// message id. The random provided should be good enough.
-func id() uint16 {
- idLock.Lock()
-
- if idRand == nil {
- // This (partially) works around
- // https://github.com/golang/go/issues/11833 by only
- // seeding idRand upon the first call to id.
-
- var seed int64
- var buf [8]byte
-
- if _, err := crand.Read(buf[:]); err == nil {
- seed = int64(binary.LittleEndian.Uint64(buf[:]))
- } else {
- seed = rand.Int63()
- }
-
- idRand = rand.New(rand.NewSource(seed))
- }
-
- // The call to idRand.Uint32 must be within the
- // mutex lock because *rand.Rand is not safe for
- // concurrent use.
- //
- // There is no added performance overhead to calling
- // idRand.Uint32 inside a mutex lock over just
- // calling rand.Uint32 as the global math/rand rng
- // is internally protected by a sync.Mutex.
- id := uint16(idRand.Uint32())
-
- idLock.Unlock()
- return id
-}
-
-// MsgHdr is a a manually-unpacked version of (id, bits).
-type MsgHdr struct {
- Id uint16
- Response bool
- Opcode int
- Authoritative bool
- Truncated bool
- RecursionDesired bool
- RecursionAvailable bool
- Zero bool
- AuthenticatedData bool
- CheckingDisabled bool
- Rcode int
-}
-
-// Msg contains the layout of a DNS message.
-type Msg struct {
- MsgHdr
- Compress bool `json:"-"` // If true, the message will be compressed when converted to wire format.
- Question []Question // Holds the RR(s) of the question section.
- Answer []RR // Holds the RR(s) of the answer section.
- Ns []RR // Holds the RR(s) of the authority section.
- Extra []RR // Holds the RR(s) of the additional section.
-}
-
-// ClassToString is a maps Classes to strings for each CLASS wire type.
-var ClassToString = map[uint16]string{
- ClassINET: "IN",
- ClassCSNET: "CS",
- ClassCHAOS: "CH",
- ClassHESIOD: "HS",
- ClassNONE: "NONE",
- ClassANY: "ANY",
-}
-
-// OpcodeToString maps Opcodes to strings.
-var OpcodeToString = map[int]string{
- OpcodeQuery: "QUERY",
- OpcodeIQuery: "IQUERY",
- OpcodeStatus: "STATUS",
- OpcodeNotify: "NOTIFY",
- OpcodeUpdate: "UPDATE",
-}
-
-// RcodeToString maps Rcodes to strings.
-var RcodeToString = map[int]string{
- RcodeSuccess: "NOERROR",
- RcodeFormatError: "FORMERR",
- RcodeServerFailure: "SERVFAIL",
- RcodeNameError: "NXDOMAIN",
- RcodeNotImplemented: "NOTIMPL",
- RcodeRefused: "REFUSED",
- RcodeYXDomain: "YXDOMAIN", // See RFC 2136
- RcodeYXRrset: "YXRRSET",
- RcodeNXRrset: "NXRRSET",
- RcodeNotAuth: "NOTAUTH",
- RcodeNotZone: "NOTZONE",
- RcodeBadSig: "BADSIG", // Also known as RcodeBadVers, see RFC 6891
- // RcodeBadVers: "BADVERS",
- RcodeBadKey: "BADKEY",
- RcodeBadTime: "BADTIME",
- RcodeBadMode: "BADMODE",
- RcodeBadName: "BADNAME",
- RcodeBadAlg: "BADALG",
- RcodeBadTrunc: "BADTRUNC",
- RcodeBadCookie: "BADCOOKIE",
-}
-
-// Domain names are a sequence of counted strings
-// split at the dots. They end with a zero-length string.
-
-// PackDomainName packs a domain name s into msg[off:].
-// If compression is wanted compress must be true and the compression
-// map needs to hold a mapping between domain names and offsets
-// pointing into msg.
-func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
- off1, _, err = packDomainName(s, msg, off, compression, compress)
- return
-}
-
-func packDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, labels int, err error) {
- // special case if msg == nil
- lenmsg := 256
- if msg != nil {
- lenmsg = len(msg)
- }
- ls := len(s)
- if ls == 0 { // Ok, for instance when dealing with update RR without any rdata.
- return off, 0, nil
- }
- // If not fully qualified, error out, but only if msg == nil #ugly
- switch {
- case msg == nil:
- if s[ls-1] != '.' {
- s += "."
- ls++
- }
- case msg != nil:
- if s[ls-1] != '.' {
- return lenmsg, 0, ErrFqdn
- }
- }
- // Each dot ends a segment of the name.
- // We trade each dot byte for a length byte.
- // Except for escaped dots (\.), which are normal dots.
- // There is also a trailing zero.
-
- // Compression
- nameoffset := -1
- pointer := -1
- // Emit sequence of counted strings, chopping at dots.
- begin := 0
- bs := []byte(s)
- roBs, bsFresh, escapedDot := s, true, false
- for i := 0; i < ls; i++ {
- if bs[i] == '\\' {
- for j := i; j < ls-1; j++ {
- bs[j] = bs[j+1]
- }
- ls--
- if off+1 > lenmsg {
- return lenmsg, labels, ErrBuf
- }
- // check for \DDD
- if i+2 < ls && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
- bs[i] = dddToByte(bs[i:])
- for j := i + 1; j < ls-2; j++ {
- bs[j] = bs[j+2]
- }
- ls -= 2
- }
- escapedDot = bs[i] == '.'
- bsFresh = false
- continue
- }
-
- if bs[i] == '.' {
- if i > 0 && bs[i-1] == '.' && !escapedDot {
- // two dots back to back is not legal
- return lenmsg, labels, ErrRdata
- }
- if i-begin >= 1<<6 { // top two bits of length must be clear
- return lenmsg, labels, ErrRdata
- }
- // off can already (we're in a loop) be bigger than len(msg)
- // this happens when a name isn't fully qualified
- if off+1 > lenmsg {
- return lenmsg, labels, ErrBuf
- }
- if msg != nil {
- msg[off] = byte(i - begin)
- }
- offset := off
- off++
- for j := begin; j < i; j++ {
- if off+1 > lenmsg {
- return lenmsg, labels, ErrBuf
- }
- if msg != nil {
- msg[off] = bs[j]
- }
- off++
- }
- if compress && !bsFresh {
- roBs = string(bs)
- bsFresh = true
- }
- // Don't try to compress '.'
- // We should only compress when compress it true, but we should also still pick
- // up names that can be used for *future* compression(s).
- if compression != nil && roBs[begin:] != "." {
- if p, ok := compression[roBs[begin:]]; !ok {
- // Only offsets smaller than this can be used.
- if offset < maxCompressionOffset {
- compression[roBs[begin:]] = offset
- }
- } else {
- // The first hit is the longest matching dname
- // keep the pointer offset we get back and store
- // the offset of the current name, because that's
- // where we need to insert the pointer later
-
- // If compress is true, we're allowed to compress this dname
- if pointer == -1 && compress {
- pointer = p // Where to point to
- nameoffset = offset // Where to point from
- break
- }
- }
- }
- labels++
- begin = i + 1
- }
- escapedDot = false
- }
- // Root label is special
- if len(bs) == 1 && bs[0] == '.' {
- return off, labels, nil
- }
- // If we did compression and we find something add the pointer here
- if pointer != -1 {
- // Clear the msg buffer after the pointer location, otherwise
- // packDataNsec writes the wrong data to msg.
- tainted := msg[nameoffset:off]
- for i := range tainted {
- tainted[i] = 0
- }
- // We have two bytes (14 bits) to put the pointer in
- // if msg == nil, we will never do compression
- binary.BigEndian.PutUint16(msg[nameoffset:], uint16(pointer^0xC000))
- off = nameoffset + 1
- goto End
- }
- if msg != nil && off < len(msg) {
- msg[off] = 0
- }
-End:
- off++
- return off, labels, nil
-}
-
-// Unpack a domain name.
-// In addition to the simple sequences of counted strings above,
-// domain names are allowed to refer to strings elsewhere in the
-// packet, to avoid repeating common suffixes when returning
-// many entries in a single domain. The pointers are marked
-// by a length byte with the top two bits set. Ignoring those
-// two bits, that byte and the next give a 14 bit offset from msg[0]
-// where we should pick up the trail.
-// Note that if we jump elsewhere in the packet,
-// we return off1 == the offset after the first pointer we found,
-// which is where the next record will start.
-// In theory, the pointers are only allowed to jump backward.
-// We let them jump anywhere and stop jumping after a while.
-
-// UnpackDomainName unpacks a domain name into a string.
-func UnpackDomainName(msg []byte, off int) (string, int, error) {
- s := make([]byte, 0, 64)
- off1 := 0
- lenmsg := len(msg)
- maxLen := maxDomainNameWireOctets
- ptr := 0 // number of pointers followed
-Loop:
- for {
- if off >= lenmsg {
- return "", lenmsg, ErrBuf
- }
- c := int(msg[off])
- off++
- switch c & 0xC0 {
- case 0x00:
- if c == 0x00 {
- // end of name
- break Loop
- }
- // literal string
- if off+c > lenmsg {
- return "", lenmsg, ErrBuf
- }
- for j := off; j < off+c; j++ {
- switch b := msg[j]; b {
- case '.', '(', ')', ';', ' ', '@':
- fallthrough
- case '"', '\\':
- s = append(s, '\\', b)
- // presentation-format \X escapes add an extra byte
- maxLen++
- default:
- if b < 32 || b >= 127 { // unprintable, use \DDD
- var buf [3]byte
- bufs := strconv.AppendInt(buf[:0], int64(b), 10)
- s = append(s, '\\')
- for i := len(bufs); i < 3; i++ {
- s = append(s, '0')
- }
- s = append(s, bufs...)
- // presentation-format \DDD escapes add 3 extra bytes
- maxLen += 3
- } else {
- s = append(s, b)
- }
- }
- }
- s = append(s, '.')
- off += c
- case 0xC0:
- // pointer to somewhere else in msg.
- // remember location after first ptr,
- // since that's how many bytes we consumed.
- // also, don't follow too many pointers --
- // maybe there's a loop.
- if off >= lenmsg {
- return "", lenmsg, ErrBuf
- }
- c1 := msg[off]
- off++
- if ptr == 0 {
- off1 = off
- }
- if ptr++; ptr > 10 {
- return "", lenmsg, &Error{err: "too many compression pointers"}
- }
- // pointer should guarantee that it advances and points forwards at least
- // but the condition on previous three lines guarantees that it's
- // at least loop-free
- off = (c^0xC0)<<8 | int(c1)
- default:
- // 0x80 and 0x40 are reserved
- return "", lenmsg, ErrRdata
- }
- }
- if ptr == 0 {
- off1 = off
- }
- if len(s) == 0 {
- s = []byte(".")
- } else if len(s) >= maxLen {
- // error if the name is too long, but don't throw it away
- return string(s), lenmsg, ErrLongDomain
- }
- return string(s), off1, nil
-}
-
-func packTxt(txt []string, msg []byte, offset int, tmp []byte) (int, error) {
- if len(txt) == 0 {
- if offset >= len(msg) {
- return offset, ErrBuf
- }
- msg[offset] = 0
- return offset, nil
- }
- var err error
- for i := range txt {
- if len(txt[i]) > len(tmp) {
- return offset, ErrBuf
- }
- offset, err = packTxtString(txt[i], msg, offset, tmp)
- if err != nil {
- return offset, err
- }
- }
- return offset, nil
-}
-
-func packTxtString(s string, msg []byte, offset int, tmp []byte) (int, error) {
- lenByteOffset := offset
- if offset >= len(msg) || len(s) > len(tmp) {
- return offset, ErrBuf
- }
- offset++
- bs := tmp[:len(s)]
- copy(bs, s)
- for i := 0; i < len(bs); i++ {
- if len(msg) <= offset {
- return offset, ErrBuf
- }
- if bs[i] == '\\' {
- i++
- if i == len(bs) {
- break
- }
- // check for \DDD
- if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
- msg[offset] = dddToByte(bs[i:])
- i += 2
- } else {
- msg[offset] = bs[i]
- }
- } else {
- msg[offset] = bs[i]
- }
- offset++
- }
- l := offset - lenByteOffset - 1
- if l > 255 {
- return offset, &Error{err: "string exceeded 255 bytes in txt"}
- }
- msg[lenByteOffset] = byte(l)
- return offset, nil
-}
-
-func packOctetString(s string, msg []byte, offset int, tmp []byte) (int, error) {
- if offset >= len(msg) || len(s) > len(tmp) {
- return offset, ErrBuf
- }
- bs := tmp[:len(s)]
- copy(bs, s)
- for i := 0; i < len(bs); i++ {
- if len(msg) <= offset {
- return offset, ErrBuf
- }
- if bs[i] == '\\' {
- i++
- if i == len(bs) {
- break
- }
- // check for \DDD
- if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
- msg[offset] = dddToByte(bs[i:])
- i += 2
- } else {
- msg[offset] = bs[i]
- }
- } else {
- msg[offset] = bs[i]
- }
- offset++
- }
- return offset, nil
-}
-
-func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
- off = off0
- var s string
- for off < len(msg) && err == nil {
- s, off, err = unpackString(msg, off)
- if err == nil {
- ss = append(ss, s)
- }
- }
- return
-}
-
-// Helpers for dealing with escaped bytes
-func isDigit(b byte) bool { return b >= '0' && b <= '9' }
-
-func dddToByte(s []byte) byte {
- return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
-}
-
-func dddStringToByte(s string) byte {
- return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
-}
-
-// Helper function for packing and unpacking
-func intToBytes(i *big.Int, length int) []byte {
- buf := i.Bytes()
- if len(buf) < length {
- b := make([]byte, length)
- copy(b[length-len(buf):], buf)
- return b
- }
- return buf
-}
-
-// PackRR packs a resource record rr into msg[off:].
-// See PackDomainName for documentation about the compression.
-func PackRR(rr RR, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
- if rr == nil {
- return len(msg), &Error{err: "nil rr"}
- }
-
- off1, err = rr.pack(msg, off, compression, compress)
- if err != nil {
- return len(msg), err
- }
- // TODO(miek): Not sure if this is needed? If removed we can remove rawmsg.go as well.
- if rawSetRdlength(msg, off, off1) {
- return off1, nil
- }
- return off, ErrRdata
-}
-
-// UnpackRR unpacks msg[off:] into an RR.
-func UnpackRR(msg []byte, off int) (rr RR, off1 int, err error) {
- h, off, msg, err := unpackHeader(msg, off)
- if err != nil {
- return nil, len(msg), err
- }
-
- return UnpackRRWithHeader(h, msg, off)
-}
-
-// UnpackRRWithHeader unpacks the record type specific payload given an existing
-// RR_Header.
-func UnpackRRWithHeader(h RR_Header, msg []byte, off int) (rr RR, off1 int, err error) {
- end := off + int(h.Rdlength)
-
- if fn, known := typeToUnpack[h.Rrtype]; !known {
- rr, off, err = unpackRFC3597(h, msg, off)
- } else {
- rr, off, err = fn(h, msg, off)
- }
- if off != end {
- return &h, end, &Error{err: "bad rdlength"}
- }
- return rr, off, err
-}
-
-// unpackRRslice unpacks msg[off:] into an []RR.
-// If we cannot unpack the whole array, then it will return nil
-func unpackRRslice(l int, msg []byte, off int) (dst1 []RR, off1 int, err error) {
- var r RR
- // Don't pre-allocate, l may be under attacker control
- var dst []RR
- for i := 0; i < l; i++ {
- off1 := off
- r, off, err = UnpackRR(msg, off)
- if err != nil {
- off = len(msg)
- break
- }
- // If offset does not increase anymore, l is a lie
- if off1 == off {
- l = i
- break
- }
- dst = append(dst, r)
- }
- if err != nil && off == len(msg) {
- dst = nil
- }
- return dst, off, err
-}
-
-// Convert a MsgHdr to a string, with dig-like headers:
-//
-//;; opcode: QUERY, status: NOERROR, id: 48404
-//
-//;; flags: qr aa rd ra;
-func (h *MsgHdr) String() string {
- if h == nil {
- return " MsgHdr"
- }
-
- s := ";; opcode: " + OpcodeToString[h.Opcode]
- s += ", status: " + RcodeToString[h.Rcode]
- s += ", id: " + strconv.Itoa(int(h.Id)) + "\n"
-
- s += ";; flags:"
- if h.Response {
- s += " qr"
- }
- if h.Authoritative {
- s += " aa"
- }
- if h.Truncated {
- s += " tc"
- }
- if h.RecursionDesired {
- s += " rd"
- }
- if h.RecursionAvailable {
- s += " ra"
- }
- if h.Zero { // Hmm
- s += " z"
- }
- if h.AuthenticatedData {
- s += " ad"
- }
- if h.CheckingDisabled {
- s += " cd"
- }
-
- s += ";"
- return s
-}
-
-// Pack packs a Msg: it is converted to to wire format.
-// If the dns.Compress is true the message will be in compressed wire format.
-func (dns *Msg) Pack() (msg []byte, err error) {
- return dns.PackBuffer(nil)
-}
-
-// PackBuffer packs a Msg, using the given buffer buf. If buf is too small a new buffer is allocated.
-func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
- var compression map[string]int
- if dns.Compress {
- compression = make(map[string]int) // Compression pointer mappings.
- }
- return dns.packBufferWithCompressionMap(buf, compression)
-}
-
-// packBufferWithCompressionMap packs a Msg, using the given buffer buf.
-func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression map[string]int) (msg []byte, err error) {
- // We use a similar function in tsig.go's stripTsig.
-
- var dh Header
-
- if dns.Rcode < 0 || dns.Rcode > 0xFFF {
- return nil, ErrRcode
- }
- if dns.Rcode > 0xF {
- // Regular RCODE field is 4 bits
- opt := dns.IsEdns0()
- if opt == nil {
- return nil, ErrExtendedRcode
- }
- opt.SetExtendedRcode(uint8(dns.Rcode >> 4))
- }
-
- // Convert convenient Msg into wire-like Header.
- dh.Id = dns.Id
- dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode&0xF)
- if dns.Response {
- dh.Bits |= _QR
- }
- if dns.Authoritative {
- dh.Bits |= _AA
- }
- if dns.Truncated {
- dh.Bits |= _TC
- }
- if dns.RecursionDesired {
- dh.Bits |= _RD
- }
- if dns.RecursionAvailable {
- dh.Bits |= _RA
- }
- if dns.Zero {
- dh.Bits |= _Z
- }
- if dns.AuthenticatedData {
- dh.Bits |= _AD
- }
- if dns.CheckingDisabled {
- dh.Bits |= _CD
- }
-
- // Prepare variable sized arrays.
- question := dns.Question
- answer := dns.Answer
- ns := dns.Ns
- extra := dns.Extra
-
- dh.Qdcount = uint16(len(question))
- dh.Ancount = uint16(len(answer))
- dh.Nscount = uint16(len(ns))
- dh.Arcount = uint16(len(extra))
-
- // We need the uncompressed length here, because we first pack it and then compress it.
- msg = buf
- uncompressedLen := compressedLen(dns, false)
- if packLen := uncompressedLen + 1; len(msg) < packLen {
- msg = make([]byte, packLen)
- }
-
- // Pack it in: header and then the pieces.
- off := 0
- off, err = dh.pack(msg, off, compression, dns.Compress)
- if err != nil {
- return nil, err
- }
- for i := 0; i < len(question); i++ {
- off, err = question[i].pack(msg, off, compression, dns.Compress)
- if err != nil {
- return nil, err
- }
- }
- for i := 0; i < len(answer); i++ {
- off, err = PackRR(answer[i], msg, off, compression, dns.Compress)
- if err != nil {
- return nil, err
- }
- }
- for i := 0; i < len(ns); i++ {
- off, err = PackRR(ns[i], msg, off, compression, dns.Compress)
- if err != nil {
- return nil, err
- }
- }
- for i := 0; i < len(extra); i++ {
- off, err = PackRR(extra[i], msg, off, compression, dns.Compress)
- if err != nil {
- return nil, err
- }
- }
- return msg[:off], nil
-}
-
-// Unpack unpacks a binary message to a Msg structure.
-func (dns *Msg) Unpack(msg []byte) (err error) {
- var (
- dh Header
- off int
- )
- if dh, off, err = unpackMsgHdr(msg, off); err != nil {
- return err
- }
-
- dns.Id = dh.Id
- dns.Response = dh.Bits&_QR != 0
- dns.Opcode = int(dh.Bits>>11) & 0xF
- dns.Authoritative = dh.Bits&_AA != 0
- dns.Truncated = dh.Bits&_TC != 0
- dns.RecursionDesired = dh.Bits&_RD != 0
- dns.RecursionAvailable = dh.Bits&_RA != 0
- dns.Zero = dh.Bits&_Z != 0
- dns.AuthenticatedData = dh.Bits&_AD != 0
- dns.CheckingDisabled = dh.Bits&_CD != 0
- dns.Rcode = int(dh.Bits & 0xF)
-
- // If we are at the end of the message we should return *just* the
- // header. This can still be useful to the caller. 9.9.9.9 sends these
- // when responding with REFUSED for instance.
- if off == len(msg) {
- // reset sections before returning
- dns.Question, dns.Answer, dns.Ns, dns.Extra = nil, nil, nil, nil
- return nil
- }
-
- // Qdcount, Ancount, Nscount, Arcount can't be trusted, as they are
- // attacker controlled. This means we can't use them to pre-allocate
- // slices.
- dns.Question = nil
- for i := 0; i < int(dh.Qdcount); i++ {
- off1 := off
- var q Question
- q, off, err = unpackQuestion(msg, off)
- if err != nil {
- // Even if Truncated is set, we only will set ErrTruncated if we
- // actually got the questions
- return err
- }
- if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
- dh.Qdcount = uint16(i)
- break
- }
- dns.Question = append(dns.Question, q)
- }
-
- dns.Answer, off, err = unpackRRslice(int(dh.Ancount), msg, off)
- // The header counts might have been wrong so we need to update it
- dh.Ancount = uint16(len(dns.Answer))
- if err == nil {
- dns.Ns, off, err = unpackRRslice(int(dh.Nscount), msg, off)
- }
- // The header counts might have been wrong so we need to update it
- dh.Nscount = uint16(len(dns.Ns))
- if err == nil {
- dns.Extra, off, err = unpackRRslice(int(dh.Arcount), msg, off)
- }
- // The header counts might have been wrong so we need to update it
- dh.Arcount = uint16(len(dns.Extra))
-
- if off != len(msg) {
- // TODO(miek) make this an error?
- // use PackOpt to let people tell how detailed the error reporting should be?
- // println("dns: extra bytes in dns packet", off, "<", len(msg))
- } else if dns.Truncated {
- // Whether we ran into a an error or not, we want to return that it
- // was truncated
- err = ErrTruncated
- }
- return err
-}
-
-// Convert a complete message to a string with dig-like output.
-func (dns *Msg) String() string {
- if dns == nil {
- return " MsgHdr"
- }
- s := dns.MsgHdr.String() + " "
- s += "QUERY: " + strconv.Itoa(len(dns.Question)) + ", "
- s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
- s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", "
- s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
- if len(dns.Question) > 0 {
- s += "\n;; QUESTION SECTION:\n"
- for i := 0; i < len(dns.Question); i++ {
- s += dns.Question[i].String() + "\n"
- }
- }
- if len(dns.Answer) > 0 {
- s += "\n;; ANSWER SECTION:\n"
- for i := 0; i < len(dns.Answer); i++ {
- if dns.Answer[i] != nil {
- s += dns.Answer[i].String() + "\n"
- }
- }
- }
- if len(dns.Ns) > 0 {
- s += "\n;; AUTHORITY SECTION:\n"
- for i := 0; i < len(dns.Ns); i++ {
- if dns.Ns[i] != nil {
- s += dns.Ns[i].String() + "\n"
- }
- }
- }
- if len(dns.Extra) > 0 {
- s += "\n;; ADDITIONAL SECTION:\n"
- for i := 0; i < len(dns.Extra); i++ {
- if dns.Extra[i] != nil {
- s += dns.Extra[i].String() + "\n"
- }
- }
- }
- return s
-}
-
-// Len returns the message length when in (un)compressed wire format.
-// If dns.Compress is true compression it is taken into account. Len()
-// is provided to be a faster way to get the size of the resulting packet,
-// than packing it, measuring the size and discarding the buffer.
-func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) }
-
-func compressedLenWithCompressionMap(dns *Msg, compression map[string]int) int {
- l := 12 // Message header is always 12 bytes
- for _, r := range dns.Question {
- compressionLenHelper(compression, r.Name, l)
- l += r.len()
- }
- l += compressionLenSlice(l, compression, dns.Answer)
- l += compressionLenSlice(l, compression, dns.Ns)
- l += compressionLenSlice(l, compression, dns.Extra)
- return l
-}
-
-// compressedLen returns the message length when in compressed wire format
-// when compress is true, otherwise the uncompressed length is returned.
-func compressedLen(dns *Msg, compress bool) int {
- // We always return one more than needed.
- if compress {
- compression := map[string]int{}
- return compressedLenWithCompressionMap(dns, compression)
- }
- l := 12 // Message header is always 12 bytes
-
- for _, r := range dns.Question {
- l += r.len()
- }
- for _, r := range dns.Answer {
- if r != nil {
- l += r.len()
- }
- }
- for _, r := range dns.Ns {
- if r != nil {
- l += r.len()
- }
- }
- for _, r := range dns.Extra {
- if r != nil {
- l += r.len()
- }
- }
-
- return l
-}
-
-func compressionLenSlice(lenp int, c map[string]int, rs []RR) int {
- initLen := lenp
- for _, r := range rs {
- if r == nil {
- continue
- }
- // TmpLen is to track len of record at 14bits boudaries
- tmpLen := lenp
-
- x := r.len()
- // track this length, and the global length in len, while taking compression into account for both.
- k, ok, _ := compressionLenSearch(c, r.Header().Name)
- if ok {
- // Size of x is reduced by k, but we add 1 since k includes the '.' and label descriptor take 2 bytes
- // so, basically x:= x - k - 1 + 2
- x += 1 - k
- }
-
- tmpLen += compressionLenHelper(c, r.Header().Name, tmpLen)
- k, ok, _ = compressionLenSearchType(c, r)
- if ok {
- x += 1 - k
- }
- lenp += x
- tmpLen = lenp
- tmpLen += compressionLenHelperType(c, r, tmpLen)
-
- }
- return lenp - initLen
-}
-
-// Put the parts of the name in the compression map, return the size in bytes added in payload
-func compressionLenHelper(c map[string]int, s string, currentLen int) int {
- if currentLen > maxCompressionOffset {
- // We won't be able to add any label that could be re-used later anyway
- return 0
- }
- if _, ok := c[s]; ok {
- return 0
- }
- initLen := currentLen
- pref := ""
- prev := s
- lbs := Split(s)
- for j := 0; j < len(lbs); j++ {
- pref = s[lbs[j]:]
- currentLen += len(prev) - len(pref)
- prev = pref
- if _, ok := c[pref]; !ok {
- // If first byte label is within the first 14bits, it might be re-used later
- if currentLen < maxCompressionOffset {
- c[pref] = currentLen
- }
- } else {
- added := currentLen - initLen
- if j > 0 {
- // We added a new PTR
- added += 2
- }
- return added
- }
- }
- return currentLen - initLen
-}
-
-// Look for each part in the compression map and returns its length,
-// keep on searching so we get the longest match.
-// Will return the size of compression found, whether a match has been
-// found and the size of record if added in payload
-func compressionLenSearch(c map[string]int, s string) (int, bool, int) {
- off := 0
- end := false
- if s == "" { // don't bork on bogus data
- return 0, false, 0
- }
- fullSize := 0
- for {
- if _, ok := c[s[off:]]; ok {
- return len(s[off:]), true, fullSize + off
- }
- if end {
- break
- }
- // Each label descriptor takes 2 bytes, add it
- fullSize += 2
- off, end = NextLabel(s, off)
- }
- return 0, false, fullSize + len(s)
-}
-
-// Copy returns a new RR which is a deep-copy of r.
-func Copy(r RR) RR { r1 := r.copy(); return r1 }
-
-// Len returns the length (in octets) of the uncompressed RR in wire format.
-func Len(r RR) int { return r.len() }
-
-// Copy returns a new *Msg which is a deep-copy of dns.
-func (dns *Msg) Copy() *Msg { return dns.CopyTo(new(Msg)) }
-
-// CopyTo copies the contents to the provided message using a deep-copy and returns the copy.
-func (dns *Msg) CopyTo(r1 *Msg) *Msg {
- r1.MsgHdr = dns.MsgHdr
- r1.Compress = dns.Compress
-
- if len(dns.Question) > 0 {
- r1.Question = make([]Question, len(dns.Question))
- copy(r1.Question, dns.Question) // TODO(miek): Question is an immutable value, ok to do a shallow-copy
- }
-
- rrArr := make([]RR, len(dns.Answer)+len(dns.Ns)+len(dns.Extra))
- var rri int
-
- if len(dns.Answer) > 0 {
- rrbegin := rri
- for i := 0; i < len(dns.Answer); i++ {
- rrArr[rri] = dns.Answer[i].copy()
- rri++
- }
- r1.Answer = rrArr[rrbegin:rri:rri]
- }
-
- if len(dns.Ns) > 0 {
- rrbegin := rri
- for i := 0; i < len(dns.Ns); i++ {
- rrArr[rri] = dns.Ns[i].copy()
- rri++
- }
- r1.Ns = rrArr[rrbegin:rri:rri]
- }
-
- if len(dns.Extra) > 0 {
- rrbegin := rri
- for i := 0; i < len(dns.Extra); i++ {
- rrArr[rri] = dns.Extra[i].copy()
- rri++
- }
- r1.Extra = rrArr[rrbegin:rri:rri]
- }
-
- return r1
-}
-
-func (q *Question) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := PackDomainName(q.Name, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- off, err = packUint16(q.Qtype, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(q.Qclass, msg, off)
- if err != nil {
- return off, err
- }
- return off, nil
-}
-
-func unpackQuestion(msg []byte, off int) (Question, int, error) {
- var (
- q Question
- err error
- )
- q.Name, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return q, off, err
- }
- if off == len(msg) {
- return q, off, nil
- }
- q.Qtype, off, err = unpackUint16(msg, off)
- if err != nil {
- return q, off, err
- }
- if off == len(msg) {
- return q, off, nil
- }
- q.Qclass, off, err = unpackUint16(msg, off)
- if off == len(msg) {
- return q, off, nil
- }
- return q, off, err
-}
-
-func (dh *Header) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := packUint16(dh.Id, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(dh.Bits, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(dh.Qdcount, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(dh.Ancount, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(dh.Nscount, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(dh.Arcount, msg, off)
- return off, err
-}
-
-func unpackMsgHdr(msg []byte, off int) (Header, int, error) {
- var (
- dh Header
- err error
- )
- dh.Id, off, err = unpackUint16(msg, off)
- if err != nil {
- return dh, off, err
- }
- dh.Bits, off, err = unpackUint16(msg, off)
- if err != nil {
- return dh, off, err
- }
- dh.Qdcount, off, err = unpackUint16(msg, off)
- if err != nil {
- return dh, off, err
- }
- dh.Ancount, off, err = unpackUint16(msg, off)
- if err != nil {
- return dh, off, err
- }
- dh.Nscount, off, err = unpackUint16(msg, off)
- if err != nil {
- return dh, off, err
- }
- dh.Arcount, off, err = unpackUint16(msg, off)
- return dh, off, err
-}
diff --git a/vendor/github.com/miekg/dns/msg_helpers.go b/vendor/github.com/miekg/dns/msg_helpers.go
deleted file mode 100644
index 81fc2b1be31..00000000000
--- a/vendor/github.com/miekg/dns/msg_helpers.go
+++ /dev/null
@@ -1,633 +0,0 @@
-package dns
-
-import (
- "encoding/base32"
- "encoding/base64"
- "encoding/binary"
- "encoding/hex"
- "net"
- "strings"
-)
-
-// helper functions called from the generated zmsg.go
-
-// These function are named after the tag to help pack/unpack, if there is no tag it is the name
-// of the type they pack/unpack (string, int, etc). We prefix all with unpackData or packData, so packDataA or
-// packDataDomainName.
-
-func unpackDataA(msg []byte, off int) (net.IP, int, error) {
- if off+net.IPv4len > len(msg) {
- return nil, len(msg), &Error{err: "overflow unpacking a"}
- }
- a := append(make(net.IP, 0, net.IPv4len), msg[off:off+net.IPv4len]...)
- off += net.IPv4len
- return a, off, nil
-}
-
-func packDataA(a net.IP, msg []byte, off int) (int, error) {
- // It must be a slice of 4, even if it is 16, we encode only the first 4
- if off+net.IPv4len > len(msg) {
- return len(msg), &Error{err: "overflow packing a"}
- }
- switch len(a) {
- case net.IPv4len, net.IPv6len:
- copy(msg[off:], a.To4())
- off += net.IPv4len
- case 0:
- // Allowed, for dynamic updates.
- default:
- return len(msg), &Error{err: "overflow packing a"}
- }
- return off, nil
-}
-
-func unpackDataAAAA(msg []byte, off int) (net.IP, int, error) {
- if off+net.IPv6len > len(msg) {
- return nil, len(msg), &Error{err: "overflow unpacking aaaa"}
- }
- aaaa := append(make(net.IP, 0, net.IPv6len), msg[off:off+net.IPv6len]...)
- off += net.IPv6len
- return aaaa, off, nil
-}
-
-func packDataAAAA(aaaa net.IP, msg []byte, off int) (int, error) {
- if off+net.IPv6len > len(msg) {
- return len(msg), &Error{err: "overflow packing aaaa"}
- }
-
- switch len(aaaa) {
- case net.IPv6len:
- copy(msg[off:], aaaa)
- off += net.IPv6len
- case 0:
- // Allowed, dynamic updates.
- default:
- return len(msg), &Error{err: "overflow packing aaaa"}
- }
- return off, nil
-}
-
-// unpackHeader unpacks an RR header, returning the offset to the end of the header and a
-// re-sliced msg according to the expected length of the RR.
-func unpackHeader(msg []byte, off int) (rr RR_Header, off1 int, truncmsg []byte, err error) {
- hdr := RR_Header{}
- if off == len(msg) {
- return hdr, off, msg, nil
- }
-
- hdr.Name, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return hdr, len(msg), msg, err
- }
- hdr.Rrtype, off, err = unpackUint16(msg, off)
- if err != nil {
- return hdr, len(msg), msg, err
- }
- hdr.Class, off, err = unpackUint16(msg, off)
- if err != nil {
- return hdr, len(msg), msg, err
- }
- hdr.Ttl, off, err = unpackUint32(msg, off)
- if err != nil {
- return hdr, len(msg), msg, err
- }
- hdr.Rdlength, off, err = unpackUint16(msg, off)
- if err != nil {
- return hdr, len(msg), msg, err
- }
- msg, err = truncateMsgFromRdlength(msg, off, hdr.Rdlength)
- return hdr, off, msg, err
-}
-
-// pack packs an RR header, returning the offset to the end of the header.
-// See PackDomainName for documentation about the compression.
-func (hdr RR_Header) pack(msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
- if off == len(msg) {
- return off, nil
- }
-
- off, err = PackDomainName(hdr.Name, msg, off, compression, compress)
- if err != nil {
- return len(msg), err
- }
- off, err = packUint16(hdr.Rrtype, msg, off)
- if err != nil {
- return len(msg), err
- }
- off, err = packUint16(hdr.Class, msg, off)
- if err != nil {
- return len(msg), err
- }
- off, err = packUint32(hdr.Ttl, msg, off)
- if err != nil {
- return len(msg), err
- }
- off, err = packUint16(hdr.Rdlength, msg, off)
- if err != nil {
- return len(msg), err
- }
- return off, nil
-}
-
-// helper helper functions.
-
-// truncateMsgFromRdLength truncates msg to match the expected length of the RR.
-// Returns an error if msg is smaller than the expected size.
-func truncateMsgFromRdlength(msg []byte, off int, rdlength uint16) (truncmsg []byte, err error) {
- lenrd := off + int(rdlength)
- if lenrd > len(msg) {
- return msg, &Error{err: "overflowing header size"}
- }
- return msg[:lenrd], nil
-}
-
-var base32HexNoPadEncoding = base32.HexEncoding.WithPadding(base32.NoPadding)
-
-func fromBase32(s []byte) (buf []byte, err error) {
- for i, b := range s {
- if b >= 'a' && b <= 'z' {
- s[i] = b - 32
- }
- }
- buflen := base32HexNoPadEncoding.DecodedLen(len(s))
- buf = make([]byte, buflen)
- n, err := base32HexNoPadEncoding.Decode(buf, s)
- buf = buf[:n]
- return
-}
-
-func toBase32(b []byte) string {
- return base32HexNoPadEncoding.EncodeToString(b)
-}
-
-func fromBase64(s []byte) (buf []byte, err error) {
- buflen := base64.StdEncoding.DecodedLen(len(s))
- buf = make([]byte, buflen)
- n, err := base64.StdEncoding.Decode(buf, s)
- buf = buf[:n]
- return
-}
-
-func toBase64(b []byte) string { return base64.StdEncoding.EncodeToString(b) }
-
-// dynamicUpdate returns true if the Rdlength is zero.
-func noRdata(h RR_Header) bool { return h.Rdlength == 0 }
-
-func unpackUint8(msg []byte, off int) (i uint8, off1 int, err error) {
- if off+1 > len(msg) {
- return 0, len(msg), &Error{err: "overflow unpacking uint8"}
- }
- return uint8(msg[off]), off + 1, nil
-}
-
-func packUint8(i uint8, msg []byte, off int) (off1 int, err error) {
- if off+1 > len(msg) {
- return len(msg), &Error{err: "overflow packing uint8"}
- }
- msg[off] = byte(i)
- return off + 1, nil
-}
-
-func unpackUint16(msg []byte, off int) (i uint16, off1 int, err error) {
- if off+2 > len(msg) {
- return 0, len(msg), &Error{err: "overflow unpacking uint16"}
- }
- return binary.BigEndian.Uint16(msg[off:]), off + 2, nil
-}
-
-func packUint16(i uint16, msg []byte, off int) (off1 int, err error) {
- if off+2 > len(msg) {
- return len(msg), &Error{err: "overflow packing uint16"}
- }
- binary.BigEndian.PutUint16(msg[off:], i)
- return off + 2, nil
-}
-
-func unpackUint32(msg []byte, off int) (i uint32, off1 int, err error) {
- if off+4 > len(msg) {
- return 0, len(msg), &Error{err: "overflow unpacking uint32"}
- }
- return binary.BigEndian.Uint32(msg[off:]), off + 4, nil
-}
-
-func packUint32(i uint32, msg []byte, off int) (off1 int, err error) {
- if off+4 > len(msg) {
- return len(msg), &Error{err: "overflow packing uint32"}
- }
- binary.BigEndian.PutUint32(msg[off:], i)
- return off + 4, nil
-}
-
-func unpackUint48(msg []byte, off int) (i uint64, off1 int, err error) {
- if off+6 > len(msg) {
- return 0, len(msg), &Error{err: "overflow unpacking uint64 as uint48"}
- }
- // Used in TSIG where the last 48 bits are occupied, so for now, assume a uint48 (6 bytes)
- i = uint64(uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 |
- uint64(msg[off+4])<<8 | uint64(msg[off+5]))
- off += 6
- return i, off, nil
-}
-
-func packUint48(i uint64, msg []byte, off int) (off1 int, err error) {
- if off+6 > len(msg) {
- return len(msg), &Error{err: "overflow packing uint64 as uint48"}
- }
- msg[off] = byte(i >> 40)
- msg[off+1] = byte(i >> 32)
- msg[off+2] = byte(i >> 24)
- msg[off+3] = byte(i >> 16)
- msg[off+4] = byte(i >> 8)
- msg[off+5] = byte(i)
- off += 6
- return off, nil
-}
-
-func unpackUint64(msg []byte, off int) (i uint64, off1 int, err error) {
- if off+8 > len(msg) {
- return 0, len(msg), &Error{err: "overflow unpacking uint64"}
- }
- return binary.BigEndian.Uint64(msg[off:]), off + 8, nil
-}
-
-func packUint64(i uint64, msg []byte, off int) (off1 int, err error) {
- if off+8 > len(msg) {
- return len(msg), &Error{err: "overflow packing uint64"}
- }
- binary.BigEndian.PutUint64(msg[off:], i)
- off += 8
- return off, nil
-}
-
-func unpackString(msg []byte, off int) (string, int, error) {
- if off+1 > len(msg) {
- return "", off, &Error{err: "overflow unpacking txt"}
- }
- l := int(msg[off])
- if off+l+1 > len(msg) {
- return "", off, &Error{err: "overflow unpacking txt"}
- }
- var s strings.Builder
- s.Grow(l)
- for _, b := range msg[off+1 : off+1+l] {
- switch {
- case b == '"' || b == '\\':
- s.WriteByte('\\')
- s.WriteByte(b)
- case b < ' ' || b > '~': // unprintable
- writeEscapedByte(&s, b)
- default:
- s.WriteByte(b)
- }
- }
- off += 1 + l
- return s.String(), off, nil
-}
-
-func packString(s string, msg []byte, off int) (int, error) {
- txtTmp := make([]byte, 256*4+1)
- off, err := packTxtString(s, msg, off, txtTmp)
- if err != nil {
- return len(msg), err
- }
- return off, nil
-}
-
-func unpackStringBase32(msg []byte, off, end int) (string, int, error) {
- if end > len(msg) {
- return "", len(msg), &Error{err: "overflow unpacking base32"}
- }
- s := toBase32(msg[off:end])
- return s, end, nil
-}
-
-func packStringBase32(s string, msg []byte, off int) (int, error) {
- b32, err := fromBase32([]byte(s))
- if err != nil {
- return len(msg), err
- }
- if off+len(b32) > len(msg) {
- return len(msg), &Error{err: "overflow packing base32"}
- }
- copy(msg[off:off+len(b32)], b32)
- off += len(b32)
- return off, nil
-}
-
-func unpackStringBase64(msg []byte, off, end int) (string, int, error) {
- // Rest of the RR is base64 encoded value, so we don't need an explicit length
- // to be set. Thus far all RR's that have base64 encoded fields have those as their
- // last one. What we do need is the end of the RR!
- if end > len(msg) {
- return "", len(msg), &Error{err: "overflow unpacking base64"}
- }
- s := toBase64(msg[off:end])
- return s, end, nil
-}
-
-func packStringBase64(s string, msg []byte, off int) (int, error) {
- b64, err := fromBase64([]byte(s))
- if err != nil {
- return len(msg), err
- }
- if off+len(b64) > len(msg) {
- return len(msg), &Error{err: "overflow packing base64"}
- }
- copy(msg[off:off+len(b64)], b64)
- off += len(b64)
- return off, nil
-}
-
-func unpackStringHex(msg []byte, off, end int) (string, int, error) {
- // Rest of the RR is hex encoded value, so we don't need an explicit length
- // to be set. NSEC and TSIG have hex fields with a length field.
- // What we do need is the end of the RR!
- if end > len(msg) {
- return "", len(msg), &Error{err: "overflow unpacking hex"}
- }
-
- s := hex.EncodeToString(msg[off:end])
- return s, end, nil
-}
-
-func packStringHex(s string, msg []byte, off int) (int, error) {
- h, err := hex.DecodeString(s)
- if err != nil {
- return len(msg), err
- }
- if off+len(h) > len(msg) {
- return len(msg), &Error{err: "overflow packing hex"}
- }
- copy(msg[off:off+len(h)], h)
- off += len(h)
- return off, nil
-}
-
-func unpackStringTxt(msg []byte, off int) ([]string, int, error) {
- txt, off, err := unpackTxt(msg, off)
- if err != nil {
- return nil, len(msg), err
- }
- return txt, off, nil
-}
-
-func packStringTxt(s []string, msg []byte, off int) (int, error) {
- txtTmp := make([]byte, 256*4+1) // If the whole string consists out of \DDD we need this many.
- off, err := packTxt(s, msg, off, txtTmp)
- if err != nil {
- return len(msg), err
- }
- return off, nil
-}
-
-func unpackDataOpt(msg []byte, off int) ([]EDNS0, int, error) {
- var edns []EDNS0
-Option:
- code := uint16(0)
- if off+4 > len(msg) {
- return nil, len(msg), &Error{err: "overflow unpacking opt"}
- }
- code = binary.BigEndian.Uint16(msg[off:])
- off += 2
- optlen := binary.BigEndian.Uint16(msg[off:])
- off += 2
- if off+int(optlen) > len(msg) {
- return nil, len(msg), &Error{err: "overflow unpacking opt"}
- }
- switch code {
- case EDNS0NSID:
- e := new(EDNS0_NSID)
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- case EDNS0SUBNET:
- e := new(EDNS0_SUBNET)
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- case EDNS0COOKIE:
- e := new(EDNS0_COOKIE)
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- case EDNS0UL:
- e := new(EDNS0_UL)
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- case EDNS0LLQ:
- e := new(EDNS0_LLQ)
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- case EDNS0DAU:
- e := new(EDNS0_DAU)
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- case EDNS0DHU:
- e := new(EDNS0_DHU)
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- case EDNS0N3U:
- e := new(EDNS0_N3U)
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- case EDNS0PADDING:
- e := new(EDNS0_PADDING)
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- default:
- e := new(EDNS0_LOCAL)
- e.Code = code
- if err := e.unpack(msg[off : off+int(optlen)]); err != nil {
- return nil, len(msg), err
- }
- edns = append(edns, e)
- off += int(optlen)
- }
-
- if off < len(msg) {
- goto Option
- }
-
- return edns, off, nil
-}
-
-func packDataOpt(options []EDNS0, msg []byte, off int) (int, error) {
- for _, el := range options {
- b, err := el.pack()
- if err != nil || off+3 > len(msg) {
- return len(msg), &Error{err: "overflow packing opt"}
- }
- binary.BigEndian.PutUint16(msg[off:], el.Option()) // Option code
- binary.BigEndian.PutUint16(msg[off+2:], uint16(len(b))) // Length
- off += 4
- if off+len(b) > len(msg) {
- copy(msg[off:], b)
- off = len(msg)
- continue
- }
- // Actual data
- copy(msg[off:off+len(b)], b)
- off += len(b)
- }
- return off, nil
-}
-
-func unpackStringOctet(msg []byte, off int) (string, int, error) {
- s := string(msg[off:])
- return s, len(msg), nil
-}
-
-func packStringOctet(s string, msg []byte, off int) (int, error) {
- txtTmp := make([]byte, 256*4+1)
- off, err := packOctetString(s, msg, off, txtTmp)
- if err != nil {
- return len(msg), err
- }
- return off, nil
-}
-
-func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
- var nsec []uint16
- length, window, lastwindow := 0, 0, -1
- for off < len(msg) {
- if off+2 > len(msg) {
- return nsec, len(msg), &Error{err: "overflow unpacking nsecx"}
- }
- window = int(msg[off])
- length = int(msg[off+1])
- off += 2
- if window <= lastwindow {
- // RFC 4034: Blocks are present in the NSEC RR RDATA in
- // increasing numerical order.
- return nsec, len(msg), &Error{err: "out of order NSEC block"}
- }
- if length == 0 {
- // RFC 4034: Blocks with no types present MUST NOT be included.
- return nsec, len(msg), &Error{err: "empty NSEC block"}
- }
- if length > 32 {
- return nsec, len(msg), &Error{err: "NSEC block too long"}
- }
- if off+length > len(msg) {
- return nsec, len(msg), &Error{err: "overflowing NSEC block"}
- }
-
- // Walk the bytes in the window and extract the type bits
- for j := 0; j < length; j++ {
- b := msg[off+j]
- // Check the bits one by one, and set the type
- if b&0x80 == 0x80 {
- nsec = append(nsec, uint16(window*256+j*8+0))
- }
- if b&0x40 == 0x40 {
- nsec = append(nsec, uint16(window*256+j*8+1))
- }
- if b&0x20 == 0x20 {
- nsec = append(nsec, uint16(window*256+j*8+2))
- }
- if b&0x10 == 0x10 {
- nsec = append(nsec, uint16(window*256+j*8+3))
- }
- if b&0x8 == 0x8 {
- nsec = append(nsec, uint16(window*256+j*8+4))
- }
- if b&0x4 == 0x4 {
- nsec = append(nsec, uint16(window*256+j*8+5))
- }
- if b&0x2 == 0x2 {
- nsec = append(nsec, uint16(window*256+j*8+6))
- }
- if b&0x1 == 0x1 {
- nsec = append(nsec, uint16(window*256+j*8+7))
- }
- }
- off += length
- lastwindow = window
- }
- return nsec, off, nil
-}
-
-func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
- if len(bitmap) == 0 {
- return off, nil
- }
- var lastwindow, lastlength uint16
- for j := 0; j < len(bitmap); j++ {
- t := bitmap[j]
- window := t / 256
- length := (t-window*256)/8 + 1
- if window > lastwindow && lastlength != 0 { // New window, jump to the new offset
- off += int(lastlength) + 2
- lastlength = 0
- }
- if window < lastwindow || length < lastlength {
- return len(msg), &Error{err: "nsec bits out of order"}
- }
- if off+2+int(length) > len(msg) {
- return len(msg), &Error{err: "overflow packing nsec"}
- }
- // Setting the window #
- msg[off] = byte(window)
- // Setting the octets length
- msg[off+1] = byte(length)
- // Setting the bit value for the type in the right octet
- msg[off+1+int(length)] |= byte(1 << (7 - t%8))
- lastwindow, lastlength = window, length
- }
- off += int(lastlength) + 2
- return off, nil
-}
-
-func unpackDataDomainNames(msg []byte, off, end int) ([]string, int, error) {
- var (
- servers []string
- s string
- err error
- )
- if end > len(msg) {
- return nil, len(msg), &Error{err: "overflow unpacking domain names"}
- }
- for off < end {
- s, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return servers, len(msg), err
- }
- servers = append(servers, s)
- }
- return servers, off, nil
-}
-
-func packDataDomainNames(names []string, msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- var err error
- for j := 0; j < len(names); j++ {
- off, err = PackDomainName(names[j], msg, off, compression, false && compress)
- if err != nil {
- return len(msg), err
- }
- }
- return off, nil
-}
diff --git a/vendor/github.com/miekg/dns/nsecx.go b/vendor/github.com/miekg/dns/nsecx.go
deleted file mode 100644
index 9b908c44786..00000000000
--- a/vendor/github.com/miekg/dns/nsecx.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package dns
-
-import (
- "crypto/sha1"
- "hash"
- "strings"
-)
-
-type saltWireFmt struct {
- Salt string `dns:"size-hex"`
-}
-
-// HashName hashes a string (label) according to RFC 5155. It returns the hashed string in uppercase.
-func HashName(label string, ha uint8, iter uint16, salt string) string {
- saltwire := new(saltWireFmt)
- saltwire.Salt = salt
- wire := make([]byte, DefaultMsgSize)
- n, err := packSaltWire(saltwire, wire)
- if err != nil {
- return ""
- }
- wire = wire[:n]
- name := make([]byte, 255)
- off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
- if err != nil {
- return ""
- }
- name = name[:off]
- var s hash.Hash
- switch ha {
- case SHA1:
- s = sha1.New()
- default:
- return ""
- }
-
- // k = 0
- s.Write(name)
- s.Write(wire)
- nsec3 := s.Sum(nil)
- // k > 0
- for k := uint16(0); k < iter; k++ {
- s.Reset()
- s.Write(nsec3)
- s.Write(wire)
- nsec3 = s.Sum(nsec3[:0])
- }
- return toBase32(nsec3)
-}
-
-// Cover returns true if a name is covered by the NSEC3 record
-func (rr *NSEC3) Cover(name string) bool {
- nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
- owner := strings.ToUpper(rr.Hdr.Name)
- labelIndices := Split(owner)
- if len(labelIndices) < 2 {
- return false
- }
- ownerHash := owner[:labelIndices[1]-1]
- ownerZone := owner[labelIndices[1]:]
- if !IsSubDomain(ownerZone, strings.ToUpper(name)) { // name is outside owner zone
- return false
- }
-
- nextHash := rr.NextDomain
- if ownerHash == nextHash { // empty interval
- return false
- }
- if ownerHash > nextHash { // end of zone
- if nameHash > ownerHash { // covered since there is nothing after ownerHash
- return true
- }
- return nameHash < nextHash // if nameHash is before beginning of zone it is covered
- }
- if nameHash < ownerHash { // nameHash is before ownerHash, not covered
- return false
- }
- return nameHash < nextHash // if nameHash is before nextHash is it covered (between ownerHash and nextHash)
-}
-
-// Match returns true if a name matches the NSEC3 record
-func (rr *NSEC3) Match(name string) bool {
- nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
- owner := strings.ToUpper(rr.Hdr.Name)
- labelIndices := Split(owner)
- if len(labelIndices) < 2 {
- return false
- }
- ownerHash := owner[:labelIndices[1]-1]
- ownerZone := owner[labelIndices[1]:]
- if !IsSubDomain(ownerZone, strings.ToUpper(name)) { // name is outside owner zone
- return false
- }
- if ownerHash == nameHash {
- return true
- }
- return false
-}
-
-func packSaltWire(sw *saltWireFmt, msg []byte) (int, error) {
- off, err := packStringHex(sw.Salt, msg, 0)
- if err != nil {
- return off, err
- }
- return off, nil
-}
diff --git a/vendor/github.com/miekg/dns/privaterr.go b/vendor/github.com/miekg/dns/privaterr.go
deleted file mode 100644
index 74544a74e50..00000000000
--- a/vendor/github.com/miekg/dns/privaterr.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package dns
-
-import (
- "fmt"
- "strings"
-)
-
-// PrivateRdata is an interface used for implementing "Private Use" RR types, see
-// RFC 6895. This allows one to experiment with new RR types, without requesting an
-// official type code. Also see dns.PrivateHandle and dns.PrivateHandleRemove.
-type PrivateRdata interface {
- // String returns the text presentaton of the Rdata of the Private RR.
- String() string
- // Parse parses the Rdata of the private RR.
- Parse([]string) error
- // Pack is used when packing a private RR into a buffer.
- Pack([]byte) (int, error)
- // Unpack is used when unpacking a private RR from a buffer.
- // TODO(miek): diff. signature than Pack, see edns0.go for instance.
- Unpack([]byte) (int, error)
- // Copy copies the Rdata.
- Copy(PrivateRdata) error
- // Len returns the length in octets of the Rdata.
- Len() int
-}
-
-// PrivateRR represents an RR that uses a PrivateRdata user-defined type.
-// It mocks normal RRs and implements dns.RR interface.
-type PrivateRR struct {
- Hdr RR_Header
- Data PrivateRdata
-}
-
-func mkPrivateRR(rrtype uint16) *PrivateRR {
- // Panics if RR is not an instance of PrivateRR.
- rrfunc, ok := TypeToRR[rrtype]
- if !ok {
- panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
- }
-
- anyrr := rrfunc()
- switch rr := anyrr.(type) {
- case *PrivateRR:
- return rr
- }
- panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr))
-}
-
-// Header return the RR header of r.
-func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
-
-func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
-
-// Private len and copy parts to satisfy RR interface.
-func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }
-func (r *PrivateRR) copy() RR {
- // make new RR like this:
- rr := mkPrivateRR(r.Hdr.Rrtype)
- rr.Hdr = r.Hdr
-
- err := r.Data.Copy(rr.Data)
- if err != nil {
- panic("dns: got value that could not be used to copy Private rdata")
- }
- return rr
-}
-func (r *PrivateRR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := r.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- n, err := r.Data.Pack(msg[off:])
- if err != nil {
- return len(msg), err
- }
- off += n
- r.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-// PrivateHandle registers a private resource record type. It requires
-// string and numeric representation of private RR type and generator function as argument.
-func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
- rtypestr = strings.ToUpper(rtypestr)
-
- TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
- TypeToString[rtype] = rtypestr
- StringToType[rtypestr] = rtype
-
- typeToUnpack[rtype] = func(h RR_Header, msg []byte, off int) (RR, int, error) {
- if noRdata(h) {
- return &h, off, nil
- }
- var err error
-
- rr := mkPrivateRR(h.Rrtype)
- rr.Hdr = h
-
- off1, err := rr.Data.Unpack(msg[off:])
- off += off1
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
- }
-
- setPrivateRR := func(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := mkPrivateRR(h.Rrtype)
- rr.Hdr = h
-
- var l lex
- text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
- Fetch:
- for {
- // TODO(miek): we could also be returning _QUOTE, this might or might not
- // be an issue (basically parsing TXT becomes hard)
- switch l, _ = c.Next(); l.value {
- case zNewline, zEOF:
- break Fetch
- case zString:
- text = append(text, l.token)
- }
- }
-
- err := rr.Data.Parse(text)
- if err != nil {
- return nil, &ParseError{f, err.Error(), l}, ""
- }
-
- return rr, nil, ""
- }
-
- typeToparserFunc[rtype] = parserFunc{setPrivateRR, true}
-}
-
-// PrivateHandleRemove removes definitions required to support private RR type.
-func PrivateHandleRemove(rtype uint16) {
- rtypestr, ok := TypeToString[rtype]
- if ok {
- delete(TypeToRR, rtype)
- delete(TypeToString, rtype)
- delete(typeToparserFunc, rtype)
- delete(StringToType, rtypestr)
- delete(typeToUnpack, rtype)
- }
-}
diff --git a/vendor/github.com/miekg/dns/rawmsg.go b/vendor/github.com/miekg/dns/rawmsg.go
deleted file mode 100644
index 6e21fba7e1f..00000000000
--- a/vendor/github.com/miekg/dns/rawmsg.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package dns
-
-import "encoding/binary"
-
-// rawSetRdlength sets the rdlength in the header of
-// the RR. The offset 'off' must be positioned at the
-// start of the header of the RR, 'end' must be the
-// end of the RR.
-func rawSetRdlength(msg []byte, off, end int) bool {
- l := len(msg)
-Loop:
- for {
- if off+1 > l {
- return false
- }
- c := int(msg[off])
- off++
- switch c & 0xC0 {
- case 0x00:
- if c == 0x00 {
- // End of the domainname
- break Loop
- }
- if off+c > l {
- return false
- }
- off += c
-
- case 0xC0:
- // pointer, next byte included, ends domainname
- off++
- break Loop
- }
- }
- // The domainname has been seen, we at the start of the fixed part in the header.
- // Type is 2 bytes, class is 2 bytes, ttl 4 and then 2 bytes for the length.
- off += 2 + 2 + 4
- if off+2 > l {
- return false
- }
- //off+1 is the end of the header, 'end' is the end of the rr
- //so 'end' - 'off+2' is the length of the rdata
- rdatalen := end - (off + 2)
- if rdatalen > 0xFFFF {
- return false
- }
- binary.BigEndian.PutUint16(msg[off:], uint16(rdatalen))
- return true
-}
diff --git a/vendor/github.com/miekg/dns/reverse.go b/vendor/github.com/miekg/dns/reverse.go
deleted file mode 100644
index f6e7a47a6e8..00000000000
--- a/vendor/github.com/miekg/dns/reverse.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package dns
-
-// StringToType is the reverse of TypeToString, needed for string parsing.
-var StringToType = reverseInt16(TypeToString)
-
-// StringToClass is the reverse of ClassToString, needed for string parsing.
-var StringToClass = reverseInt16(ClassToString)
-
-// StringToOpcode is a map of opcodes to strings.
-var StringToOpcode = reverseInt(OpcodeToString)
-
-// StringToRcode is a map of rcodes to strings.
-var StringToRcode = reverseInt(RcodeToString)
-
-// Reverse a map
-func reverseInt8(m map[uint8]string) map[string]uint8 {
- n := make(map[string]uint8, len(m))
- for u, s := range m {
- n[s] = u
- }
- return n
-}
-
-func reverseInt16(m map[uint16]string) map[string]uint16 {
- n := make(map[string]uint16, len(m))
- for u, s := range m {
- n[s] = u
- }
- return n
-}
-
-func reverseInt(m map[int]string) map[string]int {
- n := make(map[string]int, len(m))
- for u, s := range m {
- n[s] = u
- }
- return n
-}
diff --git a/vendor/github.com/miekg/dns/sanitize.go b/vendor/github.com/miekg/dns/sanitize.go
deleted file mode 100644
index cac15787adf..00000000000
--- a/vendor/github.com/miekg/dns/sanitize.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package dns
-
-// Dedup removes identical RRs from rrs. It preserves the original ordering.
-// The lowest TTL of any duplicates is used in the remaining one. Dedup modifies
-// rrs.
-// m is used to store the RRs temporary. If it is nil a new map will be allocated.
-func Dedup(rrs []RR, m map[string]RR) []RR {
-
- if m == nil {
- m = make(map[string]RR)
- }
- // Save the keys, so we don't have to call normalizedString twice.
- keys := make([]*string, 0, len(rrs))
-
- for _, r := range rrs {
- key := normalizedString(r)
- keys = append(keys, &key)
- if _, ok := m[key]; ok {
- // Shortest TTL wins.
- if m[key].Header().Ttl > r.Header().Ttl {
- m[key].Header().Ttl = r.Header().Ttl
- }
- continue
- }
-
- m[key] = r
- }
- // If the length of the result map equals the amount of RRs we got,
- // it means they were all different. We can then just return the original rrset.
- if len(m) == len(rrs) {
- return rrs
- }
-
- j := 0
- for i, r := range rrs {
- // If keys[i] lives in the map, we should copy and remove it.
- if _, ok := m[*keys[i]]; ok {
- delete(m, *keys[i])
- rrs[j] = r
- j++
- }
-
- if len(m) == 0 {
- break
- }
- }
-
- return rrs[:j]
-}
-
-// normalizedString returns a normalized string from r. The TTL
-// is removed and the domain name is lowercased. We go from this:
-// DomainNameTTLCLASSTYPERDATA to:
-// lowercasenameCLASSTYPE...
-func normalizedString(r RR) string {
- // A string Go DNS makes has: domainnameTTL...
- b := []byte(r.String())
-
- // find the first non-escaped tab, then another, so we capture where the TTL lives.
- esc := false
- ttlStart, ttlEnd := 0, 0
- for i := 0; i < len(b) && ttlEnd == 0; i++ {
- switch {
- case b[i] == '\\':
- esc = !esc
- case b[i] == '\t' && !esc:
- if ttlStart == 0 {
- ttlStart = i
- continue
- }
- if ttlEnd == 0 {
- ttlEnd = i
- }
- case b[i] >= 'A' && b[i] <= 'Z' && !esc:
- b[i] += 32
- default:
- esc = false
- }
- }
-
- // remove TTL.
- copy(b[ttlStart:], b[ttlEnd:])
- cut := ttlEnd - ttlStart
- return string(b[:len(b)-cut])
-}
diff --git a/vendor/github.com/miekg/dns/scan.go b/vendor/github.com/miekg/dns/scan.go
deleted file mode 100644
index 61ace121e5c..00000000000
--- a/vendor/github.com/miekg/dns/scan.go
+++ /dev/null
@@ -1,1331 +0,0 @@
-package dns
-
-import (
- "bufio"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "strconv"
- "strings"
-)
-
-const maxTok = 2048 // Largest token we can return.
-
-// The maximum depth of $INCLUDE directives supported by the
-// ZoneParser API.
-const maxIncludeDepth = 7
-
-// Tokinize a RFC 1035 zone file. The tokenizer will normalize it:
-// * Add ownernames if they are left blank;
-// * Suppress sequences of spaces;
-// * Make each RR fit on one line (_NEWLINE is send as last)
-// * Handle comments: ;
-// * Handle braces - anywhere.
-const (
- // Zonefile
- zEOF = iota
- zString
- zBlank
- zQuote
- zNewline
- zRrtpe
- zOwner
- zClass
- zDirOrigin // $ORIGIN
- zDirTTL // $TTL
- zDirInclude // $INCLUDE
- zDirGenerate // $GENERATE
-
- // Privatekey file
- zValue
- zKey
-
- zExpectOwnerDir // Ownername
- zExpectOwnerBl // Whitespace after the ownername
- zExpectAny // Expect rrtype, ttl or class
- zExpectAnyNoClass // Expect rrtype or ttl
- zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS
- zExpectAnyNoTTL // Expect rrtype or class
- zExpectAnyNoTTLBl // Whitespace after _EXPECT_ANY_NOTTL
- zExpectRrtype // Expect rrtype
- zExpectRrtypeBl // Whitespace BEFORE rrtype
- zExpectRdata // The first element of the rdata
- zExpectDirTTLBl // Space after directive $TTL
- zExpectDirTTL // Directive $TTL
- zExpectDirOriginBl // Space after directive $ORIGIN
- zExpectDirOrigin // Directive $ORIGIN
- zExpectDirIncludeBl // Space after directive $INCLUDE
- zExpectDirInclude // Directive $INCLUDE
- zExpectDirGenerate // Directive $GENERATE
- zExpectDirGenerateBl // Space after directive $GENERATE
-)
-
-// ParseError is a parsing error. It contains the parse error and the location in the io.Reader
-// where the error occurred.
-type ParseError struct {
- file string
- err string
- lex lex
-}
-
-func (e *ParseError) Error() (s string) {
- if e.file != "" {
- s = e.file + ": "
- }
- s += "dns: " + e.err + ": " + strconv.QuoteToASCII(e.lex.token) + " at line: " +
- strconv.Itoa(e.lex.line) + ":" + strconv.Itoa(e.lex.column)
- return
-}
-
-type lex struct {
- token string // text of the token
- err bool // when true, token text has lexer error
- value uint8 // value: zString, _BLANK, etc.
- torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
- line int // line in the file
- column int // column in the file
- comment string // any comment text seen
-}
-
-// Token holds the token that are returned when a zone file is parsed.
-type Token struct {
- // The scanned resource record when error is not nil.
- RR
- // When an error occurred, this has the error specifics.
- Error *ParseError
- // A potential comment positioned after the RR and on the same line.
- Comment string
-}
-
-// ttlState describes the state necessary to fill in an omitted RR TTL
-type ttlState struct {
- ttl uint32 // ttl is the current default TTL
- isByDirective bool // isByDirective indicates whether ttl was set by a $TTL directive
-}
-
-// NewRR reads the RR contained in the string s. Only the first RR is
-// returned. If s contains no records, NewRR will return nil with no
-// error.
-//
-// The class defaults to IN and TTL defaults to 3600. The full zone
-// file syntax like $TTL, $ORIGIN, etc. is supported.
-//
-// All fields of the returned RR are set, except RR.Header().Rdlength
-// which is set to 0.
-func NewRR(s string) (RR, error) {
- if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
- return ReadRR(strings.NewReader(s+"\n"), "")
- }
- return ReadRR(strings.NewReader(s), "")
-}
-
-// ReadRR reads the RR contained in r.
-//
-// The string file is used in error reporting and to resolve relative
-// $INCLUDE directives.
-//
-// See NewRR for more documentation.
-func ReadRR(r io.Reader, file string) (RR, error) {
- zp := NewZoneParser(r, ".", file)
- zp.SetDefaultTTL(defaultTtl)
- zp.SetIncludeAllowed(true)
- rr, _ := zp.Next()
- return rr, zp.Err()
-}
-
-// ParseZone reads a RFC 1035 style zonefile from r. It returns
-// *Tokens on the returned channel, each consisting of either a
-// parsed RR and optional comment or a nil RR and an error. The
-// channel is closed by ParseZone when the end of r is reached.
-//
-// The string file is used in error reporting and to resolve relative
-// $INCLUDE directives. The string origin is used as the initial
-// origin, as if the file would start with an $ORIGIN directive.
-//
-// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all
-// supported.
-//
-// Basic usage pattern when reading from a string (z) containing the
-// zone data:
-//
-// for x := range dns.ParseZone(strings.NewReader(z), "", "") {
-// if x.Error != nil {
-// // log.Println(x.Error)
-// } else {
-// // Do something with x.RR
-// }
-// }
-//
-// Comments specified after an RR (and on the same line!) are
-// returned too:
-//
-// foo. IN A 10.0.0.1 ; this is a comment
-//
-// The text "; this is comment" is returned in Token.Comment.
-// Comments inside the RR are returned concatenated along with the
-// RR. Comments on a line by themselves are discarded.
-//
-// To prevent memory leaks it is important to always fully drain the
-// returned channel. If an error occurs, it will always be the last
-// Token sent on the channel.
-//
-// Deprecated: New users should prefer the ZoneParser API.
-func ParseZone(r io.Reader, origin, file string) chan *Token {
- t := make(chan *Token, 10000)
- go parseZone(r, origin, file, t)
- return t
-}
-
-func parseZone(r io.Reader, origin, file string, t chan *Token) {
- defer close(t)
-
- zp := NewZoneParser(r, origin, file)
- zp.SetIncludeAllowed(true)
-
- for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
- t <- &Token{RR: rr, Comment: zp.Comment()}
- }
-
- if err := zp.Err(); err != nil {
- pe, ok := err.(*ParseError)
- if !ok {
- pe = &ParseError{file: file, err: err.Error()}
- }
-
- t <- &Token{Error: pe}
- }
-}
-
-// ZoneParser is a parser for an RFC 1035 style zonefile.
-//
-// Each parsed RR in the zone is returned sequentially from Next. An
-// optional comment can be retrieved with Comment.
-//
-// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all
-// supported. Although $INCLUDE is disabled by default.
-//
-// Basic usage pattern when reading from a string (z) containing the
-// zone data:
-//
-// zp := NewZoneParser(strings.NewReader(z), "", "")
-//
-// for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
-// // Do something with rr
-// }
-//
-// if err := zp.Err(); err != nil {
-// // log.Println(err)
-// }
-//
-// Comments specified after an RR (and on the same line!) are
-// returned too:
-//
-// foo. IN A 10.0.0.1 ; this is a comment
-//
-// The text "; this is comment" is returned from Comment. Comments inside
-// the RR are returned concatenated along with the RR. Comments on a line
-// by themselves are discarded.
-type ZoneParser struct {
- c *zlexer
-
- parseErr *ParseError
-
- origin string
- file string
-
- defttl *ttlState
-
- h RR_Header
-
- // sub is used to parse $INCLUDE files and $GENERATE directives.
- // Next, by calling subNext, forwards the resulting RRs from this
- // sub parser to the calling code.
- sub *ZoneParser
- osFile *os.File
-
- com string
-
- includeDepth uint8
-
- includeAllowed bool
-}
-
-// NewZoneParser returns an RFC 1035 style zonefile parser that reads
-// from r.
-//
-// The string file is used in error reporting and to resolve relative
-// $INCLUDE directives. The string origin is used as the initial
-// origin, as if the file would start with an $ORIGIN directive.
-func NewZoneParser(r io.Reader, origin, file string) *ZoneParser {
- var pe *ParseError
- if origin != "" {
- origin = Fqdn(origin)
- if _, ok := IsDomainName(origin); !ok {
- pe = &ParseError{file, "bad initial origin name", lex{}}
- }
- }
-
- return &ZoneParser{
- c: newZLexer(r),
-
- parseErr: pe,
-
- origin: origin,
- file: file,
- }
-}
-
-// SetDefaultTTL sets the parsers default TTL to ttl.
-func (zp *ZoneParser) SetDefaultTTL(ttl uint32) {
- zp.defttl = &ttlState{ttl, false}
-}
-
-// SetIncludeAllowed controls whether $INCLUDE directives are
-// allowed. $INCLUDE directives are not supported by default.
-//
-// The $INCLUDE directive will open and read from a user controlled
-// file on the system. Even if the file is not a valid zonefile, the
-// contents of the file may be revealed in error messages, such as:
-//
-// /etc/passwd: dns: not a TTL: "root:x:0:0:root:/root:/bin/bash" at line: 1:31
-// /etc/shadow: dns: not a TTL: "root:$6$::0:99999:7:::" at line: 1:125
-func (zp *ZoneParser) SetIncludeAllowed(v bool) {
- zp.includeAllowed = v
-}
-
-// Err returns the first non-EOF error that was encountered by the
-// ZoneParser.
-func (zp *ZoneParser) Err() error {
- if zp.parseErr != nil {
- return zp.parseErr
- }
-
- if zp.sub != nil {
- if err := zp.sub.Err(); err != nil {
- return err
- }
- }
-
- return zp.c.Err()
-}
-
-func (zp *ZoneParser) setParseError(err string, l lex) (RR, bool) {
- zp.parseErr = &ParseError{zp.file, err, l}
- return nil, false
-}
-
-// Comment returns an optional text comment that occurred alongside
-// the RR.
-func (zp *ZoneParser) Comment() string {
- return zp.com
-}
-
-func (zp *ZoneParser) subNext() (RR, bool) {
- if rr, ok := zp.sub.Next(); ok {
- zp.com = zp.sub.com
- return rr, true
- }
-
- if zp.sub.osFile != nil {
- zp.sub.osFile.Close()
- zp.sub.osFile = nil
- }
-
- if zp.sub.Err() != nil {
- // We have errors to surface.
- return nil, false
- }
-
- zp.sub = nil
- return zp.Next()
-}
-
-// Next advances the parser to the next RR in the zonefile and
-// returns the (RR, true). It will return (nil, false) when the
-// parsing stops, either by reaching the end of the input or an
-// error. After Next returns (nil, false), the Err method will return
-// any error that occurred during parsing.
-func (zp *ZoneParser) Next() (RR, bool) {
- zp.com = ""
-
- if zp.parseErr != nil {
- return nil, false
- }
- if zp.sub != nil {
- return zp.subNext()
- }
-
- // 6 possible beginnings of a line (_ is a space):
- //
- // 0. zRRTYPE -> all omitted until the rrtype
- // 1. zOwner _ zRrtype -> class/ttl omitted
- // 2. zOwner _ zString _ zRrtype -> class omitted
- // 3. zOwner _ zString _ zClass _ zRrtype -> ttl/class
- // 4. zOwner _ zClass _ zRrtype -> ttl omitted
- // 5. zOwner _ zClass _ zString _ zRrtype -> class/ttl (reversed)
- //
- // After detecting these, we know the zRrtype so we can jump to functions
- // handling the rdata for each of these types.
-
- st := zExpectOwnerDir // initial state
- h := &zp.h
-
- for l, ok := zp.c.Next(); ok; l, ok = zp.c.Next() {
- // zlexer spotted an error already
- if l.err {
- return zp.setParseError(l.token, l)
- }
-
- switch st {
- case zExpectOwnerDir:
- // We can also expect a directive, like $TTL or $ORIGIN
- if zp.defttl != nil {
- h.Ttl = zp.defttl.ttl
- }
-
- h.Class = ClassINET
-
- switch l.value {
- case zNewline:
- st = zExpectOwnerDir
- case zOwner:
- name, ok := toAbsoluteName(l.token, zp.origin)
- if !ok {
- return zp.setParseError("bad owner name", l)
- }
-
- h.Name = name
-
- st = zExpectOwnerBl
- case zDirTTL:
- st = zExpectDirTTLBl
- case zDirOrigin:
- st = zExpectDirOriginBl
- case zDirInclude:
- st = zExpectDirIncludeBl
- case zDirGenerate:
- st = zExpectDirGenerateBl
- case zRrtpe:
- h.Rrtype = l.torc
-
- st = zExpectRdata
- case zClass:
- h.Class = l.torc
-
- st = zExpectAnyNoClassBl
- case zBlank:
- // Discard, can happen when there is nothing on the
- // line except the RR type
- case zString:
- ttl, ok := stringToTTL(l.token)
- if !ok {
- return zp.setParseError("not a TTL", l)
- }
-
- h.Ttl = ttl
-
- if zp.defttl == nil || !zp.defttl.isByDirective {
- zp.defttl = &ttlState{ttl, false}
- }
-
- st = zExpectAnyNoTTLBl
- default:
- return zp.setParseError("syntax error at beginning", l)
- }
- case zExpectDirIncludeBl:
- if l.value != zBlank {
- return zp.setParseError("no blank after $INCLUDE-directive", l)
- }
-
- st = zExpectDirInclude
- case zExpectDirInclude:
- if l.value != zString {
- return zp.setParseError("expecting $INCLUDE value, not this...", l)
- }
-
- neworigin := zp.origin // There may be optionally a new origin set after the filename, if not use current one
- switch l, _ := zp.c.Next(); l.value {
- case zBlank:
- l, _ := zp.c.Next()
- if l.value == zString {
- name, ok := toAbsoluteName(l.token, zp.origin)
- if !ok {
- return zp.setParseError("bad origin name", l)
- }
-
- neworigin = name
- }
- case zNewline, zEOF:
- // Ok
- default:
- return zp.setParseError("garbage after $INCLUDE", l)
- }
-
- if !zp.includeAllowed {
- return zp.setParseError("$INCLUDE directive not allowed", l)
- }
- if zp.includeDepth >= maxIncludeDepth {
- return zp.setParseError("too deeply nested $INCLUDE", l)
- }
-
- // Start with the new file
- includePath := l.token
- if !filepath.IsAbs(includePath) {
- includePath = filepath.Join(filepath.Dir(zp.file), includePath)
- }
-
- r1, e1 := os.Open(includePath)
- if e1 != nil {
- var as string
- if !filepath.IsAbs(l.token) {
- as = fmt.Sprintf(" as `%s'", includePath)
- }
-
- msg := fmt.Sprintf("failed to open `%s'%s: %v", l.token, as, e1)
- return zp.setParseError(msg, l)
- }
-
- zp.sub = NewZoneParser(r1, neworigin, includePath)
- zp.sub.defttl, zp.sub.includeDepth, zp.sub.osFile = zp.defttl, zp.includeDepth+1, r1
- zp.sub.SetIncludeAllowed(true)
- return zp.subNext()
- case zExpectDirTTLBl:
- if l.value != zBlank {
- return zp.setParseError("no blank after $TTL-directive", l)
- }
-
- st = zExpectDirTTL
- case zExpectDirTTL:
- if l.value != zString {
- return zp.setParseError("expecting $TTL value, not this...", l)
- }
-
- if e, _ := slurpRemainder(zp.c, zp.file); e != nil {
- zp.parseErr = e
- return nil, false
- }
-
- ttl, ok := stringToTTL(l.token)
- if !ok {
- return zp.setParseError("expecting $TTL value, not this...", l)
- }
-
- zp.defttl = &ttlState{ttl, true}
-
- st = zExpectOwnerDir
- case zExpectDirOriginBl:
- if l.value != zBlank {
- return zp.setParseError("no blank after $ORIGIN-directive", l)
- }
-
- st = zExpectDirOrigin
- case zExpectDirOrigin:
- if l.value != zString {
- return zp.setParseError("expecting $ORIGIN value, not this...", l)
- }
-
- if e, _ := slurpRemainder(zp.c, zp.file); e != nil {
- zp.parseErr = e
- return nil, false
- }
-
- name, ok := toAbsoluteName(l.token, zp.origin)
- if !ok {
- return zp.setParseError("bad origin name", l)
- }
-
- zp.origin = name
-
- st = zExpectOwnerDir
- case zExpectDirGenerateBl:
- if l.value != zBlank {
- return zp.setParseError("no blank after $GENERATE-directive", l)
- }
-
- st = zExpectDirGenerate
- case zExpectDirGenerate:
- if l.value != zString {
- return zp.setParseError("expecting $GENERATE value, not this...", l)
- }
-
- return zp.generate(l)
- case zExpectOwnerBl:
- if l.value != zBlank {
- return zp.setParseError("no blank after owner", l)
- }
-
- st = zExpectAny
- case zExpectAny:
- switch l.value {
- case zRrtpe:
- if zp.defttl == nil {
- return zp.setParseError("missing TTL with no previous value", l)
- }
-
- h.Rrtype = l.torc
-
- st = zExpectRdata
- case zClass:
- h.Class = l.torc
-
- st = zExpectAnyNoClassBl
- case zString:
- ttl, ok := stringToTTL(l.token)
- if !ok {
- return zp.setParseError("not a TTL", l)
- }
-
- h.Ttl = ttl
-
- if zp.defttl == nil || !zp.defttl.isByDirective {
- zp.defttl = &ttlState{ttl, false}
- }
-
- st = zExpectAnyNoTTLBl
- default:
- return zp.setParseError("expecting RR type, TTL or class, not this...", l)
- }
- case zExpectAnyNoClassBl:
- if l.value != zBlank {
- return zp.setParseError("no blank before class", l)
- }
-
- st = zExpectAnyNoClass
- case zExpectAnyNoTTLBl:
- if l.value != zBlank {
- return zp.setParseError("no blank before TTL", l)
- }
-
- st = zExpectAnyNoTTL
- case zExpectAnyNoTTL:
- switch l.value {
- case zClass:
- h.Class = l.torc
-
- st = zExpectRrtypeBl
- case zRrtpe:
- h.Rrtype = l.torc
-
- st = zExpectRdata
- default:
- return zp.setParseError("expecting RR type or class, not this...", l)
- }
- case zExpectAnyNoClass:
- switch l.value {
- case zString:
- ttl, ok := stringToTTL(l.token)
- if !ok {
- return zp.setParseError("not a TTL", l)
- }
-
- h.Ttl = ttl
-
- if zp.defttl == nil || !zp.defttl.isByDirective {
- zp.defttl = &ttlState{ttl, false}
- }
-
- st = zExpectRrtypeBl
- case zRrtpe:
- h.Rrtype = l.torc
-
- st = zExpectRdata
- default:
- return zp.setParseError("expecting RR type or TTL, not this...", l)
- }
- case zExpectRrtypeBl:
- if l.value != zBlank {
- return zp.setParseError("no blank before RR type", l)
- }
-
- st = zExpectRrtype
- case zExpectRrtype:
- if l.value != zRrtpe {
- return zp.setParseError("unknown RR type", l)
- }
-
- h.Rrtype = l.torc
-
- st = zExpectRdata
- case zExpectRdata:
- r, e, c1 := setRR(*h, zp.c, zp.origin, zp.file)
- if e != nil {
- // If e.lex is nil than we have encounter a unknown RR type
- // in that case we substitute our current lex token
- if e.lex.token == "" && e.lex.value == 0 {
- e.lex = l // Uh, dirty
- }
-
- zp.parseErr = e
- return nil, false
- }
-
- zp.com = c1
- return r, true
- }
- }
-
- // If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
- // is not an error, because an empty zone file is still a zone file.
- return nil, false
-}
-
-type zlexer struct {
- br io.ByteReader
-
- readErr error
-
- line int
- column int
-
- com string
-
- l lex
-
- brace int
- quote bool
- space bool
- commt bool
- rrtype bool
- owner bool
-
- nextL bool
-
- eol bool // end-of-line
-}
-
-func newZLexer(r io.Reader) *zlexer {
- br, ok := r.(io.ByteReader)
- if !ok {
- br = bufio.NewReaderSize(r, 1024)
- }
-
- return &zlexer{
- br: br,
-
- line: 1,
-
- owner: true,
- }
-}
-
-func (zl *zlexer) Err() error {
- if zl.readErr == io.EOF {
- return nil
- }
-
- return zl.readErr
-}
-
-// readByte returns the next byte from the input
-func (zl *zlexer) readByte() (byte, bool) {
- if zl.readErr != nil {
- return 0, false
- }
-
- c, err := zl.br.ReadByte()
- if err != nil {
- zl.readErr = err
- return 0, false
- }
-
- // delay the newline handling until the next token is delivered,
- // fixes off-by-one errors when reporting a parse error.
- if zl.eol {
- zl.line++
- zl.column = 0
- zl.eol = false
- }
-
- if c == '\n' {
- zl.eol = true
- } else {
- zl.column++
- }
-
- return c, true
-}
-
-func (zl *zlexer) Next() (lex, bool) {
- l := &zl.l
- if zl.nextL {
- zl.nextL = false
- return *l, true
- }
- if l.err {
- // Parsing errors should be sticky.
- return lex{value: zEOF}, false
- }
-
- var (
- str [maxTok]byte // Hold string text
- com [maxTok]byte // Hold comment text
-
- stri int // Offset in str (0 means empty)
- comi int // Offset in com (0 means empty)
-
- escape bool
- )
-
- if zl.com != "" {
- comi = copy(com[:], zl.com)
- zl.com = ""
- }
-
- for x, ok := zl.readByte(); ok; x, ok = zl.readByte() {
- l.line, l.column = zl.line, zl.column
- l.comment = ""
-
- if stri >= len(str) {
- l.token = "token length insufficient for parsing"
- l.err = true
- return *l, true
- }
- if comi >= len(com) {
- l.token = "comment length insufficient for parsing"
- l.err = true
- return *l, true
- }
-
- switch x {
- case ' ', '\t':
- if escape || zl.quote {
- // Inside quotes or escaped this is legal.
- str[stri] = x
- stri++
-
- escape = false
- break
- }
-
- if zl.commt {
- com[comi] = x
- comi++
- break
- }
-
- var retL lex
- if stri == 0 {
- // Space directly in the beginning, handled in the grammar
- } else if zl.owner {
- // If we have a string and its the first, make it an owner
- l.value = zOwner
- l.token = string(str[:stri])
-
- // escape $... start with a \ not a $, so this will work
- switch strings.ToUpper(l.token) {
- case "$TTL":
- l.value = zDirTTL
- case "$ORIGIN":
- l.value = zDirOrigin
- case "$INCLUDE":
- l.value = zDirInclude
- case "$GENERATE":
- l.value = zDirGenerate
- }
-
- retL = *l
- } else {
- l.value = zString
- l.token = string(str[:stri])
-
- if !zl.rrtype {
- tokenUpper := strings.ToUpper(l.token)
- if t, ok := StringToType[tokenUpper]; ok {
- l.value = zRrtpe
- l.torc = t
-
- zl.rrtype = true
- } else if strings.HasPrefix(tokenUpper, "TYPE") {
- t, ok := typeToInt(l.token)
- if !ok {
- l.token = "unknown RR type"
- l.err = true
- return *l, true
- }
-
- l.value = zRrtpe
- l.torc = t
-
- zl.rrtype = true
- }
-
- if t, ok := StringToClass[tokenUpper]; ok {
- l.value = zClass
- l.torc = t
- } else if strings.HasPrefix(tokenUpper, "CLASS") {
- t, ok := classToInt(l.token)
- if !ok {
- l.token = "unknown class"
- l.err = true
- return *l, true
- }
-
- l.value = zClass
- l.torc = t
- }
- }
-
- retL = *l
- }
-
- zl.owner = false
-
- if !zl.space {
- zl.space = true
-
- l.value = zBlank
- l.token = " "
-
- if retL == (lex{}) {
- return *l, true
- }
-
- zl.nextL = true
- }
-
- if retL != (lex{}) {
- return retL, true
- }
- case ';':
- if escape || zl.quote {
- // Inside quotes or escaped this is legal.
- str[stri] = x
- stri++
-
- escape = false
- break
- }
-
- zl.commt = true
- zl.com = ""
-
- if comi > 1 {
- // A newline was previously seen inside a comment that
- // was inside braces and we delayed adding it until now.
- com[comi] = ' ' // convert newline to space
- comi++
- }
-
- com[comi] = ';'
- comi++
-
- if stri > 0 {
- zl.com = string(com[:comi])
-
- l.value = zString
- l.token = string(str[:stri])
- return *l, true
- }
- case '\r':
- escape = false
-
- if zl.quote {
- str[stri] = x
- stri++
- }
-
- // discard if outside of quotes
- case '\n':
- escape = false
-
- // Escaped newline
- if zl.quote {
- str[stri] = x
- stri++
- break
- }
-
- if zl.commt {
- // Reset a comment
- zl.commt = false
- zl.rrtype = false
-
- // If not in a brace this ends the comment AND the RR
- if zl.brace == 0 {
- zl.owner = true
-
- l.value = zNewline
- l.token = "\n"
- l.comment = string(com[:comi])
- return *l, true
- }
-
- zl.com = string(com[:comi])
- break
- }
-
- if zl.brace == 0 {
- // If there is previous text, we should output it here
- var retL lex
- if stri != 0 {
- l.value = zString
- l.token = string(str[:stri])
-
- if !zl.rrtype {
- tokenUpper := strings.ToUpper(l.token)
- if t, ok := StringToType[tokenUpper]; ok {
- zl.rrtype = true
-
- l.value = zRrtpe
- l.torc = t
- }
- }
-
- retL = *l
- }
-
- l.value = zNewline
- l.token = "\n"
- l.comment = zl.com
-
- zl.com = ""
- zl.rrtype = false
- zl.owner = true
-
- if retL != (lex{}) {
- zl.nextL = true
- return retL, true
- }
-
- return *l, true
- }
- case '\\':
- // comments do not get escaped chars, everything is copied
- if zl.commt {
- com[comi] = x
- comi++
- break
- }
-
- // something already escaped must be in string
- if escape {
- str[stri] = x
- stri++
-
- escape = false
- break
- }
-
- // something escaped outside of string gets added to string
- str[stri] = x
- stri++
-
- escape = true
- case '"':
- if zl.commt {
- com[comi] = x
- comi++
- break
- }
-
- if escape {
- str[stri] = x
- stri++
-
- escape = false
- break
- }
-
- zl.space = false
-
- // send previous gathered text and the quote
- var retL lex
- if stri != 0 {
- l.value = zString
- l.token = string(str[:stri])
-
- retL = *l
- }
-
- // send quote itself as separate token
- l.value = zQuote
- l.token = "\""
-
- zl.quote = !zl.quote
-
- if retL != (lex{}) {
- zl.nextL = true
- return retL, true
- }
-
- return *l, true
- case '(', ')':
- if zl.commt {
- com[comi] = x
- comi++
- break
- }
-
- if escape || zl.quote {
- // Inside quotes or escaped this is legal.
- str[stri] = x
- stri++
-
- escape = false
- break
- }
-
- switch x {
- case ')':
- zl.brace--
-
- if zl.brace < 0 {
- l.token = "extra closing brace"
- l.err = true
- return *l, true
- }
- case '(':
- zl.brace++
- }
- default:
- escape = false
-
- if zl.commt {
- com[comi] = x
- comi++
- break
- }
-
- str[stri] = x
- stri++
-
- zl.space = false
- }
- }
-
- if zl.readErr != nil && zl.readErr != io.EOF {
- // Don't return any tokens after a read error occurs.
- return lex{value: zEOF}, false
- }
-
- var retL lex
- if stri > 0 {
- // Send remainder of str
- l.value = zString
- l.token = string(str[:stri])
- retL = *l
-
- if comi <= 0 {
- return retL, true
- }
- }
-
- if comi > 0 {
- // Send remainder of com
- l.value = zNewline
- l.token = "\n"
- l.comment = string(com[:comi])
-
- if retL != (lex{}) {
- zl.nextL = true
- return retL, true
- }
-
- return *l, true
- }
-
- if zl.brace != 0 {
- l.comment = "" // in case there was left over string and comment
- l.token = "unbalanced brace"
- l.err = true
- return *l, true
- }
-
- return lex{value: zEOF}, false
-}
-
-// Extract the class number from CLASSxx
-func classToInt(token string) (uint16, bool) {
- offset := 5
- if len(token) < offset+1 {
- return 0, false
- }
- class, err := strconv.ParseUint(token[offset:], 10, 16)
- if err != nil {
- return 0, false
- }
- return uint16(class), true
-}
-
-// Extract the rr number from TYPExxx
-func typeToInt(token string) (uint16, bool) {
- offset := 4
- if len(token) < offset+1 {
- return 0, false
- }
- typ, err := strconv.ParseUint(token[offset:], 10, 16)
- if err != nil {
- return 0, false
- }
- return uint16(typ), true
-}
-
-// stringToTTL parses things like 2w, 2m, etc, and returns the time in seconds.
-func stringToTTL(token string) (uint32, bool) {
- s := uint32(0)
- i := uint32(0)
- for _, c := range token {
- switch c {
- case 's', 'S':
- s += i
- i = 0
- case 'm', 'M':
- s += i * 60
- i = 0
- case 'h', 'H':
- s += i * 60 * 60
- i = 0
- case 'd', 'D':
- s += i * 60 * 60 * 24
- i = 0
- case 'w', 'W':
- s += i * 60 * 60 * 24 * 7
- i = 0
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- i *= 10
- i += uint32(c) - '0'
- default:
- return 0, false
- }
- }
- return s + i, true
-}
-
-// Parse LOC records' [.][mM] into a
-// mantissa exponent format. Token should contain the entire
-// string (i.e. no spaces allowed)
-func stringToCm(token string) (e, m uint8, ok bool) {
- if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' {
- token = token[0 : len(token)-1]
- }
- s := strings.SplitN(token, ".", 2)
- var meters, cmeters, val int
- var err error
- switch len(s) {
- case 2:
- if cmeters, err = strconv.Atoi(s[1]); err != nil {
- return
- }
- fallthrough
- case 1:
- if meters, err = strconv.Atoi(s[0]); err != nil {
- return
- }
- case 0:
- // huh?
- return 0, 0, false
- }
- ok = true
- if meters > 0 {
- e = 2
- val = meters
- } else {
- e = 0
- val = cmeters
- }
- for val > 10 {
- e++
- val /= 10
- }
- if e > 9 {
- ok = false
- }
- m = uint8(val)
- return
-}
-
-func toAbsoluteName(name, origin string) (absolute string, ok bool) {
- // check for an explicit origin reference
- if name == "@" {
- // require a nonempty origin
- if origin == "" {
- return "", false
- }
- return origin, true
- }
-
- // require a valid domain name
- _, ok = IsDomainName(name)
- if !ok || name == "" {
- return "", false
- }
-
- // check if name is already absolute
- if name[len(name)-1] == '.' {
- return name, true
- }
-
- // require a nonempty origin
- if origin == "" {
- return "", false
- }
- return appendOrigin(name, origin), true
-}
-
-func appendOrigin(name, origin string) string {
- if origin == "." {
- return name + origin
- }
- return name + "." + origin
-}
-
-// LOC record helper function
-func locCheckNorth(token string, latitude uint32) (uint32, bool) {
- switch token {
- case "n", "N":
- return LOC_EQUATOR + latitude, true
- case "s", "S":
- return LOC_EQUATOR - latitude, true
- }
- return latitude, false
-}
-
-// LOC record helper function
-func locCheckEast(token string, longitude uint32) (uint32, bool) {
- switch token {
- case "e", "E":
- return LOC_EQUATOR + longitude, true
- case "w", "W":
- return LOC_EQUATOR - longitude, true
- }
- return longitude, false
-}
-
-// "Eat" the rest of the "line". Return potential comments
-func slurpRemainder(c *zlexer, f string) (*ParseError, string) {
- l, _ := c.Next()
- com := ""
- switch l.value {
- case zBlank:
- l, _ = c.Next()
- com = l.comment
- if l.value != zNewline && l.value != zEOF {
- return &ParseError{f, "garbage after rdata", l}, ""
- }
- case zNewline:
- com = l.comment
- case zEOF:
- default:
- return &ParseError{f, "garbage after rdata", l}, ""
- }
- return nil, com
-}
-
-// Parse a 64 bit-like ipv6 address: "0014:4fff:ff20:ee64"
-// Used for NID and L64 record.
-func stringToNodeID(l lex) (uint64, *ParseError) {
- if len(l.token) < 19 {
- return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
- }
- // There must be three colons at fixes postitions, if not its a parse error
- if l.token[4] != ':' && l.token[9] != ':' && l.token[14] != ':' {
- return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
- }
- s := l.token[0:4] + l.token[5:9] + l.token[10:14] + l.token[15:19]
- u, err := strconv.ParseUint(s, 16, 64)
- if err != nil {
- return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
- }
- return u, nil
-}
diff --git a/vendor/github.com/miekg/dns/scan_rr.go b/vendor/github.com/miekg/dns/scan_rr.go
deleted file mode 100644
index 935d22c3ff8..00000000000
--- a/vendor/github.com/miekg/dns/scan_rr.go
+++ /dev/null
@@ -1,2209 +0,0 @@
-package dns
-
-import (
- "encoding/base64"
- "net"
- "strconv"
- "strings"
-)
-
-type parserFunc struct {
- // Func defines the function that parses the tokens and returns the RR
- // or an error. The last string contains any comments in the line as
- // they returned by the lexer as well.
- Func func(h RR_Header, c *zlexer, origin string, file string) (RR, *ParseError, string)
- // Signals if the RR ending is of variable length, like TXT or records
- // that have Hexadecimal or Base64 as their last element in the Rdata. Records
- // that have a fixed ending or for instance A, AAAA, SOA and etc.
- Variable bool
-}
-
-// Parse the rdata of each rrtype.
-// All data from the channel c is either zString or zBlank.
-// After the rdata there may come a zBlank and then a zNewline
-// or immediately a zNewline. If this is not the case we flag
-// an *ParseError: garbage after rdata.
-func setRR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- parserfunc, ok := typeToparserFunc[h.Rrtype]
- if ok {
- r, e, cm := parserfunc.Func(h, c, o, f)
- if parserfunc.Variable {
- return r, e, cm
- }
- if e != nil {
- return nil, e, ""
- }
- e, cm = slurpRemainder(c, f)
- if e != nil {
- return nil, e, ""
- }
- return r, nil, cm
- }
- // RFC3957 RR (Unknown RR handling)
- return setRFC3597(h, c, o, f)
-}
-
-// A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces)
-// or an error
-func endingToString(c *zlexer, errstr, f string) (string, *ParseError, string) {
- s := ""
- l, _ := c.Next() // zString
- for l.value != zNewline && l.value != zEOF {
- if l.err {
- return s, &ParseError{f, errstr, l}, ""
- }
- switch l.value {
- case zString:
- s += l.token
- case zBlank: // Ok
- default:
- return "", &ParseError{f, errstr, l}, ""
- }
- l, _ = c.Next()
- }
- return s, nil, l.comment
-}
-
-// A remainder of the rdata with embedded spaces, split on unquoted whitespace
-// and return the parsed string slice or an error
-func endingToTxtSlice(c *zlexer, errstr, f string) ([]string, *ParseError, string) {
- // Get the remaining data until we see a zNewline
- l, _ := c.Next()
- if l.err {
- return nil, &ParseError{f, errstr, l}, ""
- }
-
- // Build the slice
- s := make([]string, 0)
- quote := false
- empty := false
- for l.value != zNewline && l.value != zEOF {
- if l.err {
- return nil, &ParseError{f, errstr, l}, ""
- }
- switch l.value {
- case zString:
- empty = false
- if len(l.token) > 255 {
- // split up tokens that are larger than 255 into 255-chunks
- sx := []string{}
- p, i := 0, 255
- for {
- if i <= len(l.token) {
- sx = append(sx, l.token[p:i])
- } else {
- sx = append(sx, l.token[p:])
- break
-
- }
- p, i = p+255, i+255
- }
- s = append(s, sx...)
- break
- }
-
- s = append(s, l.token)
- case zBlank:
- if quote {
- // zBlank can only be seen in between txt parts.
- return nil, &ParseError{f, errstr, l}, ""
- }
- case zQuote:
- if empty && quote {
- s = append(s, "")
- }
- quote = !quote
- empty = true
- default:
- return nil, &ParseError{f, errstr, l}, ""
- }
- l, _ = c.Next()
- }
- if quote {
- return nil, &ParseError{f, errstr, l}, ""
- }
- return s, nil, l.comment
-}
-
-func setA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(A)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- rr.A = net.ParseIP(l.token)
- if rr.A == nil || l.err {
- return nil, &ParseError{f, "bad A A", l}, ""
- }
- return rr, nil, ""
-}
-
-func setAAAA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(AAAA)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- rr.AAAA = net.ParseIP(l.token)
- if rr.AAAA == nil || l.err {
- return nil, &ParseError{f, "bad AAAA AAAA", l}, ""
- }
- return rr, nil, ""
-}
-
-func setNS(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(NS)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Ns = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad NS Ns", l}, ""
- }
- rr.Ns = name
- return rr, nil, ""
-}
-
-func setPTR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(PTR)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Ptr = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad PTR Ptr", l}, ""
- }
- rr.Ptr = name
- return rr, nil, ""
-}
-
-func setNSAPPTR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(NSAPPTR)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Ptr = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad NSAP-PTR Ptr", l}, ""
- }
- rr.Ptr = name
- return rr, nil, ""
-}
-
-func setRP(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(RP)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Mbox = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- mbox, mboxOk := toAbsoluteName(l.token, o)
- if l.err || !mboxOk {
- return nil, &ParseError{f, "bad RP Mbox", l}, ""
- }
- rr.Mbox = mbox
-
- c.Next() // zBlank
- l, _ = c.Next()
- rr.Txt = l.token
-
- txt, txtOk := toAbsoluteName(l.token, o)
- if l.err || !txtOk {
- return nil, &ParseError{f, "bad RP Txt", l}, ""
- }
- rr.Txt = txt
-
- return rr, nil, ""
-}
-
-func setMR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(MR)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Mr = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad MR Mr", l}, ""
- }
- rr.Mr = name
- return rr, nil, ""
-}
-
-func setMB(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(MB)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Mb = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad MB Mb", l}, ""
- }
- rr.Mb = name
- return rr, nil, ""
-}
-
-func setMG(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(MG)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Mg = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad MG Mg", l}, ""
- }
- rr.Mg = name
- return rr, nil, ""
-}
-
-func setHINFO(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(HINFO)
- rr.Hdr = h
-
- chunks, e, c1 := endingToTxtSlice(c, "bad HINFO Fields", f)
- if e != nil {
- return nil, e, c1
- }
-
- if ln := len(chunks); ln == 0 {
- return rr, nil, ""
- } else if ln == 1 {
- // Can we split it?
- if out := strings.Fields(chunks[0]); len(out) > 1 {
- chunks = out
- } else {
- chunks = append(chunks, "")
- }
- }
-
- rr.Cpu = chunks[0]
- rr.Os = strings.Join(chunks[1:], " ")
-
- return rr, nil, ""
-}
-
-func setMINFO(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(MINFO)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Rmail = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- rmail, rmailOk := toAbsoluteName(l.token, o)
- if l.err || !rmailOk {
- return nil, &ParseError{f, "bad MINFO Rmail", l}, ""
- }
- rr.Rmail = rmail
-
- c.Next() // zBlank
- l, _ = c.Next()
- rr.Email = l.token
-
- email, emailOk := toAbsoluteName(l.token, o)
- if l.err || !emailOk {
- return nil, &ParseError{f, "bad MINFO Email", l}, ""
- }
- rr.Email = email
-
- return rr, nil, ""
-}
-
-func setMF(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(MF)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Mf = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad MF Mf", l}, ""
- }
- rr.Mf = name
- return rr, nil, ""
-}
-
-func setMD(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(MD)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Md = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad MD Md", l}, ""
- }
- rr.Md = name
- return rr, nil, ""
-}
-
-func setMX(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(MX)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad MX Pref", l}, ""
- }
- rr.Preference = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Mx = l.token
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad MX Mx", l}, ""
- }
- rr.Mx = name
-
- return rr, nil, ""
-}
-
-func setRT(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(RT)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil {
- return nil, &ParseError{f, "bad RT Preference", l}, ""
- }
- rr.Preference = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Host = l.token
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad RT Host", l}, ""
- }
- rr.Host = name
-
- return rr, nil, ""
-}
-
-func setAFSDB(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(AFSDB)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad AFSDB Subtype", l}, ""
- }
- rr.Subtype = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Hostname = l.token
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad AFSDB Hostname", l}, ""
- }
- rr.Hostname = name
- return rr, nil, ""
-}
-
-func setX25(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(X25)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- if l.err {
- return nil, &ParseError{f, "bad X25 PSDNAddress", l}, ""
- }
- rr.PSDNAddress = l.token
- return rr, nil, ""
-}
-
-func setKX(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(KX)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad KX Pref", l}, ""
- }
- rr.Preference = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Exchanger = l.token
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad KX Exchanger", l}, ""
- }
- rr.Exchanger = name
- return rr, nil, ""
-}
-
-func setCNAME(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(CNAME)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Target = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad CNAME Target", l}, ""
- }
- rr.Target = name
- return rr, nil, ""
-}
-
-func setDNAME(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(DNAME)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Target = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad DNAME Target", l}, ""
- }
- rr.Target = name
- return rr, nil, ""
-}
-
-func setSOA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(SOA)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.Ns = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- ns, nsOk := toAbsoluteName(l.token, o)
- if l.err || !nsOk {
- return nil, &ParseError{f, "bad SOA Ns", l}, ""
- }
- rr.Ns = ns
-
- c.Next() // zBlank
- l, _ = c.Next()
- rr.Mbox = l.token
-
- mbox, mboxOk := toAbsoluteName(l.token, o)
- if l.err || !mboxOk {
- return nil, &ParseError{f, "bad SOA Mbox", l}, ""
- }
- rr.Mbox = mbox
-
- c.Next() // zBlank
-
- var (
- v uint32
- ok bool
- )
- for i := 0; i < 5; i++ {
- l, _ = c.Next()
- if l.err {
- return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
- }
- if j, e := strconv.ParseUint(l.token, 10, 32); e != nil {
- if i == 0 {
- // Serial must be a number
- return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
- }
- // We allow other fields to be unitful duration strings
- if v, ok = stringToTTL(l.token); !ok {
- return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
-
- }
- } else {
- v = uint32(j)
- }
- switch i {
- case 0:
- rr.Serial = v
- c.Next() // zBlank
- case 1:
- rr.Refresh = v
- c.Next() // zBlank
- case 2:
- rr.Retry = v
- c.Next() // zBlank
- case 3:
- rr.Expire = v
- c.Next() // zBlank
- case 4:
- rr.Minttl = v
- }
- }
- return rr, nil, ""
-}
-
-func setSRV(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(SRV)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad SRV Priority", l}, ""
- }
- rr.Priority = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- i, e = strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad SRV Weight", l}, ""
- }
- rr.Weight = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- i, e = strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad SRV Port", l}, ""
- }
- rr.Port = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Target = l.token
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad SRV Target", l}, ""
- }
- rr.Target = name
- return rr, nil, ""
-}
-
-func setNAPTR(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(NAPTR)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad NAPTR Order", l}, ""
- }
- rr.Order = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- i, e = strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad NAPTR Preference", l}, ""
- }
- rr.Preference = uint16(i)
-
- // Flags
- c.Next() // zBlank
- l, _ = c.Next() // _QUOTE
- if l.value != zQuote {
- return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
- }
- l, _ = c.Next() // Either String or Quote
- if l.value == zString {
- rr.Flags = l.token
- l, _ = c.Next() // _QUOTE
- if l.value != zQuote {
- return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
- }
- } else if l.value == zQuote {
- rr.Flags = ""
- } else {
- return nil, &ParseError{f, "bad NAPTR Flags", l}, ""
- }
-
- // Service
- c.Next() // zBlank
- l, _ = c.Next() // _QUOTE
- if l.value != zQuote {
- return nil, &ParseError{f, "bad NAPTR Service", l}, ""
- }
- l, _ = c.Next() // Either String or Quote
- if l.value == zString {
- rr.Service = l.token
- l, _ = c.Next() // _QUOTE
- if l.value != zQuote {
- return nil, &ParseError{f, "bad NAPTR Service", l}, ""
- }
- } else if l.value == zQuote {
- rr.Service = ""
- } else {
- return nil, &ParseError{f, "bad NAPTR Service", l}, ""
- }
-
- // Regexp
- c.Next() // zBlank
- l, _ = c.Next() // _QUOTE
- if l.value != zQuote {
- return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
- }
- l, _ = c.Next() // Either String or Quote
- if l.value == zString {
- rr.Regexp = l.token
- l, _ = c.Next() // _QUOTE
- if l.value != zQuote {
- return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
- }
- } else if l.value == zQuote {
- rr.Regexp = ""
- } else {
- return nil, &ParseError{f, "bad NAPTR Regexp", l}, ""
- }
-
- // After quote no space??
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Replacement = l.token
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad NAPTR Replacement", l}, ""
- }
- rr.Replacement = name
- return rr, nil, ""
-}
-
-func setTALINK(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(TALINK)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.PreviousName = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- previousName, previousNameOk := toAbsoluteName(l.token, o)
- if l.err || !previousNameOk {
- return nil, &ParseError{f, "bad TALINK PreviousName", l}, ""
- }
- rr.PreviousName = previousName
-
- c.Next() // zBlank
- l, _ = c.Next()
- rr.NextName = l.token
-
- nextName, nextNameOk := toAbsoluteName(l.token, o)
- if l.err || !nextNameOk {
- return nil, &ParseError{f, "bad TALINK NextName", l}, ""
- }
- rr.NextName = nextName
-
- return rr, nil, ""
-}
-
-func setLOC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(LOC)
- rr.Hdr = h
- // Non zero defaults for LOC record, see RFC 1876, Section 3.
- rr.HorizPre = 165 // 10000
- rr.VertPre = 162 // 10
- rr.Size = 18 // 1
- ok := false
-
- // North
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
- i, e := strconv.ParseUint(l.token, 10, 32)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad LOC Latitude", l}, ""
- }
- rr.Latitude = 1000 * 60 * 60 * uint32(i)
-
- c.Next() // zBlank
- // Either number, 'N' or 'S'
- l, _ = c.Next()
- if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
- goto East
- }
- i, e = strconv.ParseUint(l.token, 10, 32)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad LOC Latitude minutes", l}, ""
- }
- rr.Latitude += 1000 * 60 * uint32(i)
-
- c.Next() // zBlank
- l, _ = c.Next()
- if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err {
- return nil, &ParseError{f, "bad LOC Latitude seconds", l}, ""
- } else {
- rr.Latitude += uint32(1000 * i)
- }
- c.Next() // zBlank
- // Either number, 'N' or 'S'
- l, _ = c.Next()
- if rr.Latitude, ok = locCheckNorth(l.token, rr.Latitude); ok {
- goto East
- }
- // If still alive, flag an error
- return nil, &ParseError{f, "bad LOC Latitude North/South", l}, ""
-
-East:
- // East
- c.Next() // zBlank
- l, _ = c.Next()
- if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
- return nil, &ParseError{f, "bad LOC Longitude", l}, ""
- } else {
- rr.Longitude = 1000 * 60 * 60 * uint32(i)
- }
- c.Next() // zBlank
- // Either number, 'E' or 'W'
- l, _ = c.Next()
- if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
- goto Altitude
- }
- if i, e := strconv.ParseUint(l.token, 10, 32); e != nil || l.err {
- return nil, &ParseError{f, "bad LOC Longitude minutes", l}, ""
- } else {
- rr.Longitude += 1000 * 60 * uint32(i)
- }
- c.Next() // zBlank
- l, _ = c.Next()
- if i, e := strconv.ParseFloat(l.token, 32); e != nil || l.err {
- return nil, &ParseError{f, "bad LOC Longitude seconds", l}, ""
- } else {
- rr.Longitude += uint32(1000 * i)
- }
- c.Next() // zBlank
- // Either number, 'E' or 'W'
- l, _ = c.Next()
- if rr.Longitude, ok = locCheckEast(l.token, rr.Longitude); ok {
- goto Altitude
- }
- // If still alive, flag an error
- return nil, &ParseError{f, "bad LOC Longitude East/West", l}, ""
-
-Altitude:
- c.Next() // zBlank
- l, _ = c.Next()
- if len(l.token) == 0 || l.err {
- return nil, &ParseError{f, "bad LOC Altitude", l}, ""
- }
- if l.token[len(l.token)-1] == 'M' || l.token[len(l.token)-1] == 'm' {
- l.token = l.token[0 : len(l.token)-1]
- }
- if i, e := strconv.ParseFloat(l.token, 32); e != nil {
- return nil, &ParseError{f, "bad LOC Altitude", l}, ""
- } else {
- rr.Altitude = uint32(i*100.0 + 10000000.0 + 0.5)
- }
-
- // And now optionally the other values
- l, _ = c.Next()
- count := 0
- for l.value != zNewline && l.value != zEOF {
- switch l.value {
- case zString:
- switch count {
- case 0: // Size
- e, m, ok := stringToCm(l.token)
- if !ok {
- return nil, &ParseError{f, "bad LOC Size", l}, ""
- }
- rr.Size = e&0x0f | m<<4&0xf0
- case 1: // HorizPre
- e, m, ok := stringToCm(l.token)
- if !ok {
- return nil, &ParseError{f, "bad LOC HorizPre", l}, ""
- }
- rr.HorizPre = e&0x0f | m<<4&0xf0
- case 2: // VertPre
- e, m, ok := stringToCm(l.token)
- if !ok {
- return nil, &ParseError{f, "bad LOC VertPre", l}, ""
- }
- rr.VertPre = e&0x0f | m<<4&0xf0
- }
- count++
- case zBlank:
- // Ok
- default:
- return nil, &ParseError{f, "bad LOC Size, HorizPre or VertPre", l}, ""
- }
- l, _ = c.Next()
- }
- return rr, nil, ""
-}
-
-func setHIP(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(HIP)
- rr.Hdr = h
-
- // HitLength is not represented
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- i, e := strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad HIP PublicKeyAlgorithm", l}, ""
- }
- rr.PublicKeyAlgorithm = uint8(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- if len(l.token) == 0 || l.err {
- return nil, &ParseError{f, "bad HIP Hit", l}, ""
- }
- rr.Hit = l.token // This can not contain spaces, see RFC 5205 Section 6.
- rr.HitLength = uint8(len(rr.Hit)) / 2
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- if len(l.token) == 0 || l.err {
- return nil, &ParseError{f, "bad HIP PublicKey", l}, ""
- }
- rr.PublicKey = l.token // This cannot contain spaces
- rr.PublicKeyLength = uint16(base64.StdEncoding.DecodedLen(len(rr.PublicKey)))
-
- // RendezvousServers (if any)
- l, _ = c.Next()
- var xs []string
- for l.value != zNewline && l.value != zEOF {
- switch l.value {
- case zString:
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad HIP RendezvousServers", l}, ""
- }
- xs = append(xs, name)
- case zBlank:
- // Ok
- default:
- return nil, &ParseError{f, "bad HIP RendezvousServers", l}, ""
- }
- l, _ = c.Next()
- }
- rr.RendezvousServers = xs
- return rr, nil, l.comment
-}
-
-func setCERT(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(CERT)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- if v, ok := StringToCertType[l.token]; ok {
- rr.Type = v
- } else if i, e := strconv.ParseUint(l.token, 10, 16); e != nil {
- return nil, &ParseError{f, "bad CERT Type", l}, ""
- } else {
- rr.Type = uint16(i)
- }
- c.Next() // zBlank
- l, _ = c.Next() // zString
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad CERT KeyTag", l}, ""
- }
- rr.KeyTag = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next() // zString
- if v, ok := StringToAlgorithm[l.token]; ok {
- rr.Algorithm = v
- } else if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
- return nil, &ParseError{f, "bad CERT Algorithm", l}, ""
- } else {
- rr.Algorithm = uint8(i)
- }
- s, e1, c1 := endingToString(c, "bad CERT Certificate", f)
- if e1 != nil {
- return nil, e1, c1
- }
- rr.Certificate = s
- return rr, nil, c1
-}
-
-func setOPENPGPKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(OPENPGPKEY)
- rr.Hdr = h
-
- s, e, c1 := endingToString(c, "bad OPENPGPKEY PublicKey", f)
- if e != nil {
- return nil, e, c1
- }
- rr.PublicKey = s
- return rr, nil, c1
-}
-
-func setCSYNC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(CSYNC)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
- j, e := strconv.ParseUint(l.token, 10, 32)
- if e != nil {
- // Serial must be a number
- return nil, &ParseError{f, "bad CSYNC serial", l}, ""
- }
- rr.Serial = uint32(j)
-
- c.Next() // zBlank
-
- l, _ = c.Next()
- j, e = strconv.ParseUint(l.token, 10, 16)
- if e != nil {
- // Serial must be a number
- return nil, &ParseError{f, "bad CSYNC flags", l}, ""
- }
- rr.Flags = uint16(j)
-
- rr.TypeBitMap = make([]uint16, 0)
- var (
- k uint16
- ok bool
- )
- l, _ = c.Next()
- for l.value != zNewline && l.value != zEOF {
- switch l.value {
- case zBlank:
- // Ok
- case zString:
- tokenUpper := strings.ToUpper(l.token)
- if k, ok = StringToType[tokenUpper]; !ok {
- if k, ok = typeToInt(l.token); !ok {
- return nil, &ParseError{f, "bad CSYNC TypeBitMap", l}, ""
- }
- }
- rr.TypeBitMap = append(rr.TypeBitMap, k)
- default:
- return nil, &ParseError{f, "bad CSYNC TypeBitMap", l}, ""
- }
- l, _ = c.Next()
- }
- return rr, nil, l.comment
-}
-
-func setSIG(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- r, e, s := setRRSIG(h, c, o, f)
- if r != nil {
- return &SIG{*r.(*RRSIG)}, e, s
- }
- return nil, e, s
-}
-
-func setRRSIG(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(RRSIG)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- tokenUpper := strings.ToUpper(l.token)
- if t, ok := StringToType[tokenUpper]; !ok {
- if strings.HasPrefix(tokenUpper, "TYPE") {
- t, ok = typeToInt(l.token)
- if !ok {
- return nil, &ParseError{f, "bad RRSIG Typecovered", l}, ""
- }
- rr.TypeCovered = t
- } else {
- return nil, &ParseError{f, "bad RRSIG Typecovered", l}, ""
- }
- } else {
- rr.TypeCovered = t
- }
-
- c.Next() // zBlank
- l, _ = c.Next()
- i, err := strconv.ParseUint(l.token, 10, 8)
- if err != nil || l.err {
- return nil, &ParseError{f, "bad RRSIG Algorithm", l}, ""
- }
- rr.Algorithm = uint8(i)
-
- c.Next() // zBlank
- l, _ = c.Next()
- i, err = strconv.ParseUint(l.token, 10, 8)
- if err != nil || l.err {
- return nil, &ParseError{f, "bad RRSIG Labels", l}, ""
- }
- rr.Labels = uint8(i)
-
- c.Next() // zBlank
- l, _ = c.Next()
- i, err = strconv.ParseUint(l.token, 10, 32)
- if err != nil || l.err {
- return nil, &ParseError{f, "bad RRSIG OrigTtl", l}, ""
- }
- rr.OrigTtl = uint32(i)
-
- c.Next() // zBlank
- l, _ = c.Next()
- if i, err := StringToTime(l.token); err != nil {
- // Try to see if all numeric and use it as epoch
- if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
- // TODO(miek): error out on > MAX_UINT32, same below
- rr.Expiration = uint32(i)
- } else {
- return nil, &ParseError{f, "bad RRSIG Expiration", l}, ""
- }
- } else {
- rr.Expiration = i
- }
-
- c.Next() // zBlank
- l, _ = c.Next()
- if i, err := StringToTime(l.token); err != nil {
- if i, err := strconv.ParseInt(l.token, 10, 64); err == nil {
- rr.Inception = uint32(i)
- } else {
- return nil, &ParseError{f, "bad RRSIG Inception", l}, ""
- }
- } else {
- rr.Inception = i
- }
-
- c.Next() // zBlank
- l, _ = c.Next()
- i, err = strconv.ParseUint(l.token, 10, 16)
- if err != nil || l.err {
- return nil, &ParseError{f, "bad RRSIG KeyTag", l}, ""
- }
- rr.KeyTag = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next()
- rr.SignerName = l.token
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad RRSIG SignerName", l}, ""
- }
- rr.SignerName = name
-
- s, e, c1 := endingToString(c, "bad RRSIG Signature", f)
- if e != nil {
- return nil, e, c1
- }
- rr.Signature = s
-
- return rr, nil, c1
-}
-
-func setNSEC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(NSEC)
- rr.Hdr = h
-
- l, _ := c.Next()
- rr.NextDomain = l.token
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad NSEC NextDomain", l}, ""
- }
- rr.NextDomain = name
-
- rr.TypeBitMap = make([]uint16, 0)
- var (
- k uint16
- ok bool
- )
- l, _ = c.Next()
- for l.value != zNewline && l.value != zEOF {
- switch l.value {
- case zBlank:
- // Ok
- case zString:
- tokenUpper := strings.ToUpper(l.token)
- if k, ok = StringToType[tokenUpper]; !ok {
- if k, ok = typeToInt(l.token); !ok {
- return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, ""
- }
- }
- rr.TypeBitMap = append(rr.TypeBitMap, k)
- default:
- return nil, &ParseError{f, "bad NSEC TypeBitMap", l}, ""
- }
- l, _ = c.Next()
- }
- return rr, nil, l.comment
-}
-
-func setNSEC3(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(NSEC3)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- i, e := strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad NSEC3 Hash", l}, ""
- }
- rr.Hash = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad NSEC3 Flags", l}, ""
- }
- rr.Flags = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad NSEC3 Iterations", l}, ""
- }
- rr.Iterations = uint16(i)
- c.Next()
- l, _ = c.Next()
- if len(l.token) == 0 || l.err {
- return nil, &ParseError{f, "bad NSEC3 Salt", l}, ""
- }
- if l.token != "-" {
- rr.SaltLength = uint8(len(l.token)) / 2
- rr.Salt = l.token
- }
-
- c.Next()
- l, _ = c.Next()
- if len(l.token) == 0 || l.err {
- return nil, &ParseError{f, "bad NSEC3 NextDomain", l}, ""
- }
- rr.HashLength = 20 // Fix for NSEC3 (sha1 160 bits)
- rr.NextDomain = l.token
-
- rr.TypeBitMap = make([]uint16, 0)
- var (
- k uint16
- ok bool
- )
- l, _ = c.Next()
- for l.value != zNewline && l.value != zEOF {
- switch l.value {
- case zBlank:
- // Ok
- case zString:
- tokenUpper := strings.ToUpper(l.token)
- if k, ok = StringToType[tokenUpper]; !ok {
- if k, ok = typeToInt(l.token); !ok {
- return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, ""
- }
- }
- rr.TypeBitMap = append(rr.TypeBitMap, k)
- default:
- return nil, &ParseError{f, "bad NSEC3 TypeBitMap", l}, ""
- }
- l, _ = c.Next()
- }
- return rr, nil, l.comment
-}
-
-func setNSEC3PARAM(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(NSEC3PARAM)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad NSEC3PARAM Hash", l}, ""
- }
- rr.Hash = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad NSEC3PARAM Flags", l}, ""
- }
- rr.Flags = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad NSEC3PARAM Iterations", l}, ""
- }
- rr.Iterations = uint16(i)
- c.Next()
- l, _ = c.Next()
- if l.token != "-" {
- rr.SaltLength = uint8(len(l.token))
- rr.Salt = l.token
- }
- return rr, nil, ""
-}
-
-func setEUI48(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(EUI48)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- if len(l.token) != 17 || l.err {
- return nil, &ParseError{f, "bad EUI48 Address", l}, ""
- }
- addr := make([]byte, 12)
- dash := 0
- for i := 0; i < 10; i += 2 {
- addr[i] = l.token[i+dash]
- addr[i+1] = l.token[i+1+dash]
- dash++
- if l.token[i+1+dash] != '-' {
- return nil, &ParseError{f, "bad EUI48 Address", l}, ""
- }
- }
- addr[10] = l.token[15]
- addr[11] = l.token[16]
-
- i, e := strconv.ParseUint(string(addr), 16, 48)
- if e != nil {
- return nil, &ParseError{f, "bad EUI48 Address", l}, ""
- }
- rr.Address = i
- return rr, nil, ""
-}
-
-func setEUI64(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(EUI64)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- if len(l.token) != 23 || l.err {
- return nil, &ParseError{f, "bad EUI64 Address", l}, ""
- }
- addr := make([]byte, 16)
- dash := 0
- for i := 0; i < 14; i += 2 {
- addr[i] = l.token[i+dash]
- addr[i+1] = l.token[i+1+dash]
- dash++
- if l.token[i+1+dash] != '-' {
- return nil, &ParseError{f, "bad EUI64 Address", l}, ""
- }
- }
- addr[14] = l.token[21]
- addr[15] = l.token[22]
-
- i, e := strconv.ParseUint(string(addr), 16, 64)
- if e != nil {
- return nil, &ParseError{f, "bad EUI68 Address", l}, ""
- }
- rr.Address = uint64(i)
- return rr, nil, ""
-}
-
-func setSSHFP(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(SSHFP)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad SSHFP Algorithm", l}, ""
- }
- rr.Algorithm = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad SSHFP Type", l}, ""
- }
- rr.Type = uint8(i)
- c.Next() // zBlank
- s, e1, c1 := endingToString(c, "bad SSHFP Fingerprint", f)
- if e1 != nil {
- return nil, e1, c1
- }
- rr.FingerPrint = s
- return rr, nil, ""
-}
-
-func setDNSKEYs(h RR_Header, c *zlexer, o, f, typ string) (RR, *ParseError, string) {
- rr := new(DNSKEY)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad " + typ + " Flags", l}, ""
- }
- rr.Flags = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next() // zString
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad " + typ + " Protocol", l}, ""
- }
- rr.Protocol = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next() // zString
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
- }
- rr.Algorithm = uint8(i)
- s, e1, c1 := endingToString(c, "bad "+typ+" PublicKey", f)
- if e1 != nil {
- return nil, e1, c1
- }
- rr.PublicKey = s
- return rr, nil, c1
-}
-
-func setKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- r, e, s := setDNSKEYs(h, c, o, f, "KEY")
- if r != nil {
- return &KEY{*r.(*DNSKEY)}, e, s
- }
- return nil, e, s
-}
-
-func setDNSKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- r, e, s := setDNSKEYs(h, c, o, f, "DNSKEY")
- return r, e, s
-}
-
-func setCDNSKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- r, e, s := setDNSKEYs(h, c, o, f, "CDNSKEY")
- if r != nil {
- return &CDNSKEY{*r.(*DNSKEY)}, e, s
- }
- return nil, e, s
-}
-
-func setRKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(RKEY)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad RKEY Flags", l}, ""
- }
- rr.Flags = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next() // zString
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad RKEY Protocol", l}, ""
- }
- rr.Protocol = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next() // zString
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad RKEY Algorithm", l}, ""
- }
- rr.Algorithm = uint8(i)
- s, e1, c1 := endingToString(c, "bad RKEY PublicKey", f)
- if e1 != nil {
- return nil, e1, c1
- }
- rr.PublicKey = s
- return rr, nil, c1
-}
-
-func setEID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(EID)
- rr.Hdr = h
- s, e, c1 := endingToString(c, "bad EID Endpoint", f)
- if e != nil {
- return nil, e, c1
- }
- rr.Endpoint = s
- return rr, nil, c1
-}
-
-func setNIMLOC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(NIMLOC)
- rr.Hdr = h
- s, e, c1 := endingToString(c, "bad NIMLOC Locator", f)
- if e != nil {
- return nil, e, c1
- }
- rr.Locator = s
- return rr, nil, c1
-}
-
-func setGPOS(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(GPOS)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- _, e := strconv.ParseFloat(l.token, 64)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad GPOS Longitude", l}, ""
- }
- rr.Longitude = l.token
- c.Next() // zBlank
- l, _ = c.Next()
- _, e = strconv.ParseFloat(l.token, 64)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad GPOS Latitude", l}, ""
- }
- rr.Latitude = l.token
- c.Next() // zBlank
- l, _ = c.Next()
- _, e = strconv.ParseFloat(l.token, 64)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad GPOS Altitude", l}, ""
- }
- rr.Altitude = l.token
- return rr, nil, ""
-}
-
-func setDSs(h RR_Header, c *zlexer, o, f, typ string) (RR, *ParseError, string) {
- rr := new(DS)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad " + typ + " KeyTag", l}, ""
- }
- rr.KeyTag = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next()
- if i, e = strconv.ParseUint(l.token, 10, 8); e != nil {
- tokenUpper := strings.ToUpper(l.token)
- i, ok := StringToAlgorithm[tokenUpper]
- if !ok || l.err {
- return nil, &ParseError{f, "bad " + typ + " Algorithm", l}, ""
- }
- rr.Algorithm = i
- } else {
- rr.Algorithm = uint8(i)
- }
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad " + typ + " DigestType", l}, ""
- }
- rr.DigestType = uint8(i)
- s, e1, c1 := endingToString(c, "bad "+typ+" Digest", f)
- if e1 != nil {
- return nil, e1, c1
- }
- rr.Digest = s
- return rr, nil, c1
-}
-
-func setDS(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- r, e, s := setDSs(h, c, o, f, "DS")
- return r, e, s
-}
-
-func setDLV(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- r, e, s := setDSs(h, c, o, f, "DLV")
- if r != nil {
- return &DLV{*r.(*DS)}, e, s
- }
- return nil, e, s
-}
-
-func setCDS(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- r, e, s := setDSs(h, c, o, f, "CDS")
- if r != nil {
- return &CDS{*r.(*DS)}, e, s
- }
- return nil, e, s
-}
-
-func setTA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(TA)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad TA KeyTag", l}, ""
- }
- rr.KeyTag = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next()
- if i, e := strconv.ParseUint(l.token, 10, 8); e != nil {
- tokenUpper := strings.ToUpper(l.token)
- i, ok := StringToAlgorithm[tokenUpper]
- if !ok || l.err {
- return nil, &ParseError{f, "bad TA Algorithm", l}, ""
- }
- rr.Algorithm = i
- } else {
- rr.Algorithm = uint8(i)
- }
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad TA DigestType", l}, ""
- }
- rr.DigestType = uint8(i)
- s, err, c1 := endingToString(c, "bad TA Digest", f)
- if err != nil {
- return nil, err, c1
- }
- rr.Digest = s
- return rr, nil, c1
-}
-
-func setTLSA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(TLSA)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- i, e := strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad TLSA Usage", l}, ""
- }
- rr.Usage = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad TLSA Selector", l}, ""
- }
- rr.Selector = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad TLSA MatchingType", l}, ""
- }
- rr.MatchingType = uint8(i)
- // So this needs be e2 (i.e. different than e), because...??t
- s, e2, c1 := endingToString(c, "bad TLSA Certificate", f)
- if e2 != nil {
- return nil, e2, c1
- }
- rr.Certificate = s
- return rr, nil, c1
-}
-
-func setSMIMEA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(SMIMEA)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- i, e := strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad SMIMEA Usage", l}, ""
- }
- rr.Usage = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad SMIMEA Selector", l}, ""
- }
- rr.Selector = uint8(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 8)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad SMIMEA MatchingType", l}, ""
- }
- rr.MatchingType = uint8(i)
- // So this needs be e2 (i.e. different than e), because...??t
- s, e2, c1 := endingToString(c, "bad SMIMEA Certificate", f)
- if e2 != nil {
- return nil, e2, c1
- }
- rr.Certificate = s
- return rr, nil, c1
-}
-
-func setRFC3597(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(RFC3597)
- rr.Hdr = h
-
- l, _ := c.Next()
- if l.token != "\\#" {
- return nil, &ParseError{f, "bad RFC3597 Rdata", l}, ""
- }
-
- c.Next() // zBlank
- l, _ = c.Next()
- rdlength, e := strconv.Atoi(l.token)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad RFC3597 Rdata ", l}, ""
- }
-
- s, e1, c1 := endingToString(c, "bad RFC3597 Rdata", f)
- if e1 != nil {
- return nil, e1, c1
- }
- if rdlength*2 != len(s) {
- return nil, &ParseError{f, "bad RFC3597 Rdata", l}, ""
- }
- rr.Rdata = s
- return rr, nil, c1
-}
-
-func setSPF(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(SPF)
- rr.Hdr = h
-
- s, e, c1 := endingToTxtSlice(c, "bad SPF Txt", f)
- if e != nil {
- return nil, e, ""
- }
- rr.Txt = s
- return rr, nil, c1
-}
-
-func setAVC(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(AVC)
- rr.Hdr = h
-
- s, e, c1 := endingToTxtSlice(c, "bad AVC Txt", f)
- if e != nil {
- return nil, e, ""
- }
- rr.Txt = s
- return rr, nil, c1
-}
-
-func setTXT(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(TXT)
- rr.Hdr = h
-
- // no zBlank reading here, because all this rdata is TXT
- s, e, c1 := endingToTxtSlice(c, "bad TXT Txt", f)
- if e != nil {
- return nil, e, ""
- }
- rr.Txt = s
- return rr, nil, c1
-}
-
-// identical to setTXT
-func setNINFO(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(NINFO)
- rr.Hdr = h
-
- s, e, c1 := endingToTxtSlice(c, "bad NINFO ZSData", f)
- if e != nil {
- return nil, e, ""
- }
- rr.ZSData = s
- return rr, nil, c1
-}
-
-func setURI(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(URI)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad URI Priority", l}, ""
- }
- rr.Priority = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next()
- i, e = strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad URI Weight", l}, ""
- }
- rr.Weight = uint16(i)
-
- c.Next() // zBlank
- s, err, c1 := endingToTxtSlice(c, "bad URI Target", f)
- if err != nil {
- return nil, err, ""
- }
- if len(s) != 1 {
- return nil, &ParseError{f, "bad URI Target", l}, ""
- }
- rr.Target = s[0]
- return rr, nil, c1
-}
-
-func setDHCID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- // awesome record to parse!
- rr := new(DHCID)
- rr.Hdr = h
-
- s, e, c1 := endingToString(c, "bad DHCID Digest", f)
- if e != nil {
- return nil, e, c1
- }
- rr.Digest = s
- return rr, nil, c1
-}
-
-func setNID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(NID)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad NID Preference", l}, ""
- }
- rr.Preference = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next() // zString
- u, err := stringToNodeID(l)
- if err != nil || l.err {
- return nil, err, ""
- }
- rr.NodeID = u
- return rr, nil, ""
-}
-
-func setL32(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(L32)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad L32 Preference", l}, ""
- }
- rr.Preference = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Locator32 = net.ParseIP(l.token)
- if rr.Locator32 == nil || l.err {
- return nil, &ParseError{f, "bad L32 Locator", l}, ""
- }
- return rr, nil, ""
-}
-
-func setLP(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(LP)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad LP Preference", l}, ""
- }
- rr.Preference = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Fqdn = l.token
- name, nameOk := toAbsoluteName(l.token, o)
- if l.err || !nameOk {
- return nil, &ParseError{f, "bad LP Fqdn", l}, ""
- }
- rr.Fqdn = name
-
- return rr, nil, ""
-}
-
-func setL64(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(L64)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad L64 Preference", l}, ""
- }
- rr.Preference = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next() // zString
- u, err := stringToNodeID(l)
- if err != nil || l.err {
- return nil, err, ""
- }
- rr.Locator64 = u
- return rr, nil, ""
-}
-
-func setUID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(UID)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 32)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad UID Uid", l}, ""
- }
- rr.Uid = uint32(i)
- return rr, nil, ""
-}
-
-func setGID(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(GID)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 32)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad GID Gid", l}, ""
- }
- rr.Gid = uint32(i)
- return rr, nil, ""
-}
-
-func setUINFO(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(UINFO)
- rr.Hdr = h
-
- s, e, c1 := endingToTxtSlice(c, "bad UINFO Uinfo", f)
- if e != nil {
- return nil, e, c1
- }
- if ln := len(s); ln == 0 {
- return rr, nil, c1
- }
- rr.Uinfo = s[0] // silently discard anything after the first character-string
- return rr, nil, c1
-}
-
-func setPX(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(PX)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, ""
- }
-
- i, e := strconv.ParseUint(l.token, 10, 16)
- if e != nil || l.err {
- return nil, &ParseError{f, "bad PX Preference", l}, ""
- }
- rr.Preference = uint16(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Map822 = l.token
- map822, map822Ok := toAbsoluteName(l.token, o)
- if l.err || !map822Ok {
- return nil, &ParseError{f, "bad PX Map822", l}, ""
- }
- rr.Map822 = map822
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- rr.Mapx400 = l.token
- mapx400, mapx400Ok := toAbsoluteName(l.token, o)
- if l.err || !mapx400Ok {
- return nil, &ParseError{f, "bad PX Mapx400", l}, ""
- }
- rr.Mapx400 = mapx400
-
- return rr, nil, ""
-}
-
-func setCAA(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(CAA)
- rr.Hdr = h
-
- l, _ := c.Next()
- if len(l.token) == 0 { // dynamic update rr.
- return rr, nil, l.comment
- }
-
- i, err := strconv.ParseUint(l.token, 10, 8)
- if err != nil || l.err {
- return nil, &ParseError{f, "bad CAA Flag", l}, ""
- }
- rr.Flag = uint8(i)
-
- c.Next() // zBlank
- l, _ = c.Next() // zString
- if l.value != zString {
- return nil, &ParseError{f, "bad CAA Tag", l}, ""
- }
- rr.Tag = l.token
-
- c.Next() // zBlank
- s, e, c1 := endingToTxtSlice(c, "bad CAA Value", f)
- if e != nil {
- return nil, e, ""
- }
- if len(s) != 1 {
- return nil, &ParseError{f, "bad CAA Value", l}, ""
- }
- rr.Value = s[0]
- return rr, nil, c1
-}
-
-func setTKEY(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
- rr := new(TKEY)
- rr.Hdr = h
-
- l, _ := c.Next()
-
- // Algorithm
- if l.value != zString {
- return nil, &ParseError{f, "bad TKEY algorithm", l}, ""
- }
- rr.Algorithm = l.token
- c.Next() // zBlank
-
- // Get the key length and key values
- l, _ = c.Next()
- i, err := strconv.ParseUint(l.token, 10, 8)
- if err != nil || l.err {
- return nil, &ParseError{f, "bad TKEY key length", l}, ""
- }
- rr.KeySize = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next()
- if l.value != zString {
- return nil, &ParseError{f, "bad TKEY key", l}, ""
- }
- rr.Key = l.token
- c.Next() // zBlank
-
- // Get the otherdata length and string data
- l, _ = c.Next()
- i, err = strconv.ParseUint(l.token, 10, 8)
- if err != nil || l.err {
- return nil, &ParseError{f, "bad TKEY otherdata length", l}, ""
- }
- rr.OtherLen = uint16(i)
- c.Next() // zBlank
- l, _ = c.Next()
- if l.value != zString {
- return nil, &ParseError{f, "bad TKEY otherday", l}, ""
- }
- rr.OtherData = l.token
-
- return rr, nil, ""
-}
-
-var typeToparserFunc = map[uint16]parserFunc{
- TypeAAAA: {setAAAA, false},
- TypeAFSDB: {setAFSDB, false},
- TypeA: {setA, false},
- TypeCAA: {setCAA, true},
- TypeCDS: {setCDS, true},
- TypeCDNSKEY: {setCDNSKEY, true},
- TypeCERT: {setCERT, true},
- TypeCNAME: {setCNAME, false},
- TypeCSYNC: {setCSYNC, true},
- TypeDHCID: {setDHCID, true},
- TypeDLV: {setDLV, true},
- TypeDNAME: {setDNAME, false},
- TypeKEY: {setKEY, true},
- TypeDNSKEY: {setDNSKEY, true},
- TypeDS: {setDS, true},
- TypeEID: {setEID, true},
- TypeEUI48: {setEUI48, false},
- TypeEUI64: {setEUI64, false},
- TypeGID: {setGID, false},
- TypeGPOS: {setGPOS, false},
- TypeHINFO: {setHINFO, true},
- TypeHIP: {setHIP, true},
- TypeKX: {setKX, false},
- TypeL32: {setL32, false},
- TypeL64: {setL64, false},
- TypeLOC: {setLOC, true},
- TypeLP: {setLP, false},
- TypeMB: {setMB, false},
- TypeMD: {setMD, false},
- TypeMF: {setMF, false},
- TypeMG: {setMG, false},
- TypeMINFO: {setMINFO, false},
- TypeMR: {setMR, false},
- TypeMX: {setMX, false},
- TypeNAPTR: {setNAPTR, false},
- TypeNID: {setNID, false},
- TypeNIMLOC: {setNIMLOC, true},
- TypeNINFO: {setNINFO, true},
- TypeNSAPPTR: {setNSAPPTR, false},
- TypeNSEC3PARAM: {setNSEC3PARAM, false},
- TypeNSEC3: {setNSEC3, true},
- TypeNSEC: {setNSEC, true},
- TypeNS: {setNS, false},
- TypeOPENPGPKEY: {setOPENPGPKEY, true},
- TypePTR: {setPTR, false},
- TypePX: {setPX, false},
- TypeSIG: {setSIG, true},
- TypeRKEY: {setRKEY, true},
- TypeRP: {setRP, false},
- TypeRRSIG: {setRRSIG, true},
- TypeRT: {setRT, false},
- TypeSMIMEA: {setSMIMEA, true},
- TypeSOA: {setSOA, false},
- TypeSPF: {setSPF, true},
- TypeAVC: {setAVC, true},
- TypeSRV: {setSRV, false},
- TypeSSHFP: {setSSHFP, true},
- TypeTALINK: {setTALINK, false},
- TypeTA: {setTA, true},
- TypeTLSA: {setTLSA, true},
- TypeTXT: {setTXT, true},
- TypeUID: {setUID, false},
- TypeUINFO: {setUINFO, true},
- TypeURI: {setURI, true},
- TypeX25: {setX25, false},
- TypeTKEY: {setTKEY, true},
-}
diff --git a/vendor/github.com/miekg/dns/serve_mux.go b/vendor/github.com/miekg/dns/serve_mux.go
deleted file mode 100644
index ae304db530a..00000000000
--- a/vendor/github.com/miekg/dns/serve_mux.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package dns
-
-import (
- "strings"
- "sync"
-)
-
-// ServeMux is an DNS request multiplexer. It matches the zone name of
-// each incoming request against a list of registered patterns add calls
-// the handler for the pattern that most closely matches the zone name.
-//
-// ServeMux is DNSSEC aware, meaning that queries for the DS record are
-// redirected to the parent zone (if that is also registered), otherwise
-// the child gets the query.
-//
-// ServeMux is also safe for concurrent access from multiple goroutines.
-//
-// The zero ServeMux is empty and ready for use.
-type ServeMux struct {
- z map[string]Handler
- m sync.RWMutex
-}
-
-// NewServeMux allocates and returns a new ServeMux.
-func NewServeMux() *ServeMux {
- return new(ServeMux)
-}
-
-// DefaultServeMux is the default ServeMux used by Serve.
-var DefaultServeMux = NewServeMux()
-
-func (mux *ServeMux) match(q string, t uint16) Handler {
- mux.m.RLock()
- defer mux.m.RUnlock()
- if mux.z == nil {
- return nil
- }
-
- var handler Handler
-
- // TODO(tmthrgd): Once https://go-review.googlesource.com/c/go/+/137575
- // lands in a go release, replace the following with strings.ToLower.
- var sb strings.Builder
- for i := 0; i < len(q); i++ {
- c := q[i]
- if !(c >= 'A' && c <= 'Z') {
- continue
- }
-
- sb.Grow(len(q))
- sb.WriteString(q[:i])
-
- for ; i < len(q); i++ {
- c := q[i]
- if c >= 'A' && c <= 'Z' {
- c += 'a' - 'A'
- }
-
- sb.WriteByte(c)
- }
-
- q = sb.String()
- break
- }
-
- for off, end := 0, false; !end; off, end = NextLabel(q, off) {
- if h, ok := mux.z[q[off:]]; ok {
- if t != TypeDS {
- return h
- }
- // Continue for DS to see if we have a parent too, if so delegate to the parent
- handler = h
- }
- }
-
- // Wildcard match, if we have found nothing try the root zone as a last resort.
- if h, ok := mux.z["."]; ok {
- return h
- }
-
- return handler
-}
-
-// Handle adds a handler to the ServeMux for pattern.
-func (mux *ServeMux) Handle(pattern string, handler Handler) {
- if pattern == "" {
- panic("dns: invalid pattern " + pattern)
- }
- mux.m.Lock()
- if mux.z == nil {
- mux.z = make(map[string]Handler)
- }
- mux.z[Fqdn(pattern)] = handler
- mux.m.Unlock()
-}
-
-// HandleFunc adds a handler function to the ServeMux for pattern.
-func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
- mux.Handle(pattern, HandlerFunc(handler))
-}
-
-// HandleRemove deregisters the handler specific for pattern from the ServeMux.
-func (mux *ServeMux) HandleRemove(pattern string) {
- if pattern == "" {
- panic("dns: invalid pattern " + pattern)
- }
- mux.m.Lock()
- delete(mux.z, Fqdn(pattern))
- mux.m.Unlock()
-}
-
-// ServeDNS dispatches the request to the handler whose pattern most
-// closely matches the request message.
-//
-// ServeDNS is DNSSEC aware, meaning that queries for the DS record
-// are redirected to the parent zone (if that is also registered),
-// otherwise the child gets the query.
-//
-// If no handler is found, or there is no question, a standard SERVFAIL
-// message is returned
-func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
- var h Handler
- if len(req.Question) >= 1 { // allow more than one question
- h = mux.match(req.Question[0].Name, req.Question[0].Qtype)
- }
-
- if h != nil {
- h.ServeDNS(w, req)
- } else {
- HandleFailed(w, req)
- }
-}
-
-// Handle registers the handler with the given pattern
-// in the DefaultServeMux. The documentation for
-// ServeMux explains how patterns are matched.
-func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
-
-// HandleRemove deregisters the handle with the given pattern
-// in the DefaultServeMux.
-func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
-
-// HandleFunc registers the handler function with the given pattern
-// in the DefaultServeMux.
-func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
- DefaultServeMux.HandleFunc(pattern, handler)
-}
diff --git a/vendor/github.com/miekg/dns/server.go b/vendor/github.com/miekg/dns/server.go
deleted file mode 100644
index 4b4ec33c8d1..00000000000
--- a/vendor/github.com/miekg/dns/server.go
+++ /dev/null
@@ -1,829 +0,0 @@
-// DNS server implementation.
-
-package dns
-
-import (
- "bytes"
- "context"
- "crypto/tls"
- "encoding/binary"
- "errors"
- "io"
- "net"
- "strings"
- "sync"
- "sync/atomic"
- "time"
-)
-
-// Default maximum number of TCP queries before we close the socket.
-const maxTCPQueries = 128
-
-// The maximum number of idle workers.
-//
-// This controls the maximum number of workers that are allowed to stay
-// idle waiting for incoming requests before being torn down.
-//
-// If this limit is reached, the server will just keep spawning new
-// workers (goroutines) for each incoming request. In this case, each
-// worker will only be used for a single request.
-const maxIdleWorkersCount = 10000
-
-// The maximum length of time a worker may idle for before being destroyed.
-const idleWorkerTimeout = 10 * time.Second
-
-// aLongTimeAgo is a non-zero time, far in the past, used for
-// immediate cancelation of network operations.
-var aLongTimeAgo = time.Unix(1, 0)
-
-// Handler is implemented by any value that implements ServeDNS.
-type Handler interface {
- ServeDNS(w ResponseWriter, r *Msg)
-}
-
-// The HandlerFunc type is an adapter to allow the use of
-// ordinary functions as DNS handlers. If f is a function
-// with the appropriate signature, HandlerFunc(f) is a
-// Handler object that calls f.
-type HandlerFunc func(ResponseWriter, *Msg)
-
-// ServeDNS calls f(w, r).
-func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
- f(w, r)
-}
-
-// A ResponseWriter interface is used by an DNS handler to
-// construct an DNS response.
-type ResponseWriter interface {
- // LocalAddr returns the net.Addr of the server
- LocalAddr() net.Addr
- // RemoteAddr returns the net.Addr of the client that sent the current request.
- RemoteAddr() net.Addr
- // WriteMsg writes a reply back to the client.
- WriteMsg(*Msg) error
- // Write writes a raw buffer back to the client.
- Write([]byte) (int, error)
- // Close closes the connection.
- Close() error
- // TsigStatus returns the status of the Tsig.
- TsigStatus() error
- // TsigTimersOnly sets the tsig timers only boolean.
- TsigTimersOnly(bool)
- // Hijack lets the caller take over the connection.
- // After a call to Hijack(), the DNS package will not do anything with the connection.
- Hijack()
-}
-
-// A ConnectionStater interface is used by a DNS Handler to access TLS connection state
-// when available.
-type ConnectionStater interface {
- ConnectionState() *tls.ConnectionState
-}
-
-type response struct {
- msg []byte
- hijacked bool // connection has been hijacked by handler
- tsigTimersOnly bool
- tsigStatus error
- tsigRequestMAC string
- tsigSecret map[string]string // the tsig secrets
- udp *net.UDPConn // i/o connection if UDP was used
- tcp net.Conn // i/o connection if TCP was used
- udpSession *SessionUDP // oob data to get egress interface right
- writer Writer // writer to output the raw DNS bits
- wg *sync.WaitGroup // for gracefull shutdown
-}
-
-// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
-func HandleFailed(w ResponseWriter, r *Msg) {
- m := new(Msg)
- m.SetRcode(r, RcodeServerFailure)
- // does not matter if this write fails
- w.WriteMsg(m)
-}
-
-// ListenAndServe Starts a server on address and network specified Invoke handler
-// for incoming queries.
-func ListenAndServe(addr string, network string, handler Handler) error {
- server := &Server{Addr: addr, Net: network, Handler: handler}
- return server.ListenAndServe()
-}
-
-// ListenAndServeTLS acts like http.ListenAndServeTLS, more information in
-// http://golang.org/pkg/net/http/#ListenAndServeTLS
-func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
- cert, err := tls.LoadX509KeyPair(certFile, keyFile)
- if err != nil {
- return err
- }
-
- config := tls.Config{
- Certificates: []tls.Certificate{cert},
- }
-
- server := &Server{
- Addr: addr,
- Net: "tcp-tls",
- TLSConfig: &config,
- Handler: handler,
- }
-
- return server.ListenAndServe()
-}
-
-// ActivateAndServe activates a server with a listener from systemd,
-// l and p should not both be non-nil.
-// If both l and p are not nil only p will be used.
-// Invoke handler for incoming queries.
-func ActivateAndServe(l net.Listener, p net.PacketConn, handler Handler) error {
- server := &Server{Listener: l, PacketConn: p, Handler: handler}
- return server.ActivateAndServe()
-}
-
-// Writer writes raw DNS messages; each call to Write should send an entire message.
-type Writer interface {
- io.Writer
-}
-
-// Reader reads raw DNS messages; each call to ReadTCP or ReadUDP should return an entire message.
-type Reader interface {
- // ReadTCP reads a raw message from a TCP connection. Implementations may alter
- // connection properties, for example the read-deadline.
- ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error)
- // ReadUDP reads a raw message from a UDP connection. Implementations may alter
- // connection properties, for example the read-deadline.
- ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
-}
-
-// defaultReader is an adapter for the Server struct that implements the Reader interface
-// using the readTCP and readUDP func of the embedded Server.
-type defaultReader struct {
- *Server
-}
-
-func (dr *defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
- return dr.readTCP(conn, timeout)
-}
-
-func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
- return dr.readUDP(conn, timeout)
-}
-
-// DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader.
-// Implementations should never return a nil Reader.
-type DecorateReader func(Reader) Reader
-
-// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
-// Implementations should never return a nil Writer.
-type DecorateWriter func(Writer) Writer
-
-// A Server defines parameters for running an DNS server.
-type Server struct {
- // Address to listen on, ":dns" if empty.
- Addr string
- // if "tcp" or "tcp-tls" (DNS over TLS) it will invoke a TCP listener, otherwise an UDP one
- Net string
- // TCP Listener to use, this is to aid in systemd's socket activation.
- Listener net.Listener
- // TLS connection configuration
- TLSConfig *tls.Config
- // UDP "Listener" to use, this is to aid in systemd's socket activation.
- PacketConn net.PacketConn
- // Handler to invoke, dns.DefaultServeMux if nil.
- Handler Handler
- // Default buffer size to use to read incoming UDP messages. If not set
- // it defaults to MinMsgSize (512 B).
- UDPSize int
- // The net.Conn.SetReadTimeout value for new connections, defaults to 2 * time.Second.
- ReadTimeout time.Duration
- // The net.Conn.SetWriteTimeout value for new connections, defaults to 2 * time.Second.
- WriteTimeout time.Duration
- // TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
- IdleTimeout func() time.Duration
- // Secret(s) for Tsig map[]. The zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2).
- TsigSecret map[string]string
- // Unsafe instructs the server to disregard any sanity checks and directly hand the message to
- // the handler. It will specifically not check if the query has the QR bit not set.
- Unsafe bool
- // If NotifyStartedFunc is set it is called once the server has started listening.
- NotifyStartedFunc func()
- // DecorateReader is optional, allows customization of the process that reads raw DNS messages.
- DecorateReader DecorateReader
- // DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
- DecorateWriter DecorateWriter
- // Maximum number of TCP queries before we close the socket. Default is maxTCPQueries (unlimited if -1).
- MaxTCPQueries int
- // Whether to set the SO_REUSEPORT socket option, allowing multiple listeners to be bound to a single address.
- // It is only supported on go1.11+ and when using ListenAndServe.
- ReusePort bool
-
- // UDP packet or TCP connection queue
- queue chan *response
- // Workers count
- workersCount int32
-
- // Shutdown handling
- lock sync.RWMutex
- started bool
- shutdown chan struct{}
- conns map[net.Conn]struct{}
-
- // A pool for UDP message buffers.
- udpPool sync.Pool
-}
-
-func (srv *Server) isStarted() bool {
- srv.lock.RLock()
- started := srv.started
- srv.lock.RUnlock()
- return started
-}
-
-func (srv *Server) worker(w *response) {
- srv.serve(w)
-
- for {
- count := atomic.LoadInt32(&srv.workersCount)
- if count > maxIdleWorkersCount {
- return
- }
- if atomic.CompareAndSwapInt32(&srv.workersCount, count, count+1) {
- break
- }
- }
-
- defer atomic.AddInt32(&srv.workersCount, -1)
-
- inUse := false
- timeout := time.NewTimer(idleWorkerTimeout)
- defer timeout.Stop()
-LOOP:
- for {
- select {
- case w, ok := <-srv.queue:
- if !ok {
- break LOOP
- }
- inUse = true
- srv.serve(w)
- case <-timeout.C:
- if !inUse {
- break LOOP
- }
- inUse = false
- timeout.Reset(idleWorkerTimeout)
- }
- }
-}
-
-func (srv *Server) spawnWorker(w *response) {
- select {
- case srv.queue <- w:
- default:
- go srv.worker(w)
- }
-}
-
-func makeUDPBuffer(size int) func() interface{} {
- return func() interface{} {
- return make([]byte, size)
- }
-}
-
-func (srv *Server) init() {
- srv.queue = make(chan *response)
-
- srv.shutdown = make(chan struct{})
- srv.conns = make(map[net.Conn]struct{})
-
- if srv.UDPSize == 0 {
- srv.UDPSize = MinMsgSize
- }
-
- srv.udpPool.New = makeUDPBuffer(srv.UDPSize)
-}
-
-func unlockOnce(l sync.Locker) func() {
- var once sync.Once
- return func() { once.Do(l.Unlock) }
-}
-
-// ListenAndServe starts a nameserver on the configured address in *Server.
-func (srv *Server) ListenAndServe() error {
- unlock := unlockOnce(&srv.lock)
- srv.lock.Lock()
- defer unlock()
-
- if srv.started {
- return &Error{err: "server already started"}
- }
-
- addr := srv.Addr
- if addr == "" {
- addr = ":domain"
- }
-
- srv.init()
- defer close(srv.queue)
-
- switch srv.Net {
- case "tcp", "tcp4", "tcp6":
- l, err := listenTCP(srv.Net, addr, srv.ReusePort)
- if err != nil {
- return err
- }
- srv.Listener = l
- srv.started = true
- unlock()
- return srv.serveTCP(l)
- case "tcp-tls", "tcp4-tls", "tcp6-tls":
- if srv.TLSConfig == nil || (len(srv.TLSConfig.Certificates) == 0 && srv.TLSConfig.GetCertificate == nil) {
- return errors.New("dns: neither Certificates nor GetCertificate set in Config")
- }
- network := strings.TrimSuffix(srv.Net, "-tls")
- l, err := listenTCP(network, addr, srv.ReusePort)
- if err != nil {
- return err
- }
- l = tls.NewListener(l, srv.TLSConfig)
- srv.Listener = l
- srv.started = true
- unlock()
- return srv.serveTCP(l)
- case "udp", "udp4", "udp6":
- l, err := listenUDP(srv.Net, addr, srv.ReusePort)
- if err != nil {
- return err
- }
- u := l.(*net.UDPConn)
- if e := setUDPSocketOptions(u); e != nil {
- return e
- }
- srv.PacketConn = l
- srv.started = true
- unlock()
- return srv.serveUDP(u)
- }
- return &Error{err: "bad network"}
-}
-
-// ActivateAndServe starts a nameserver with the PacketConn or Listener
-// configured in *Server. Its main use is to start a server from systemd.
-func (srv *Server) ActivateAndServe() error {
- unlock := unlockOnce(&srv.lock)
- srv.lock.Lock()
- defer unlock()
-
- if srv.started {
- return &Error{err: "server already started"}
- }
-
- srv.init()
- defer close(srv.queue)
-
- pConn := srv.PacketConn
- l := srv.Listener
- if pConn != nil {
- // Check PacketConn interface's type is valid and value
- // is not nil
- if t, ok := pConn.(*net.UDPConn); ok && t != nil {
- if e := setUDPSocketOptions(t); e != nil {
- return e
- }
- srv.started = true
- unlock()
- return srv.serveUDP(t)
- }
- }
- if l != nil {
- srv.started = true
- unlock()
- return srv.serveTCP(l)
- }
- return &Error{err: "bad listeners"}
-}
-
-// Shutdown shuts down a server. After a call to Shutdown, ListenAndServe and
-// ActivateAndServe will return.
-func (srv *Server) Shutdown() error {
- return srv.ShutdownContext(context.Background())
-}
-
-// ShutdownContext shuts down a server. After a call to ShutdownContext,
-// ListenAndServe and ActivateAndServe will return.
-//
-// A context.Context may be passed to limit how long to wait for connections
-// to terminate.
-func (srv *Server) ShutdownContext(ctx context.Context) error {
- srv.lock.Lock()
- if !srv.started {
- srv.lock.Unlock()
- return &Error{err: "server not started"}
- }
-
- srv.started = false
-
- if srv.PacketConn != nil {
- srv.PacketConn.SetReadDeadline(aLongTimeAgo) // Unblock reads
- }
-
- if srv.Listener != nil {
- srv.Listener.Close()
- }
-
- for rw := range srv.conns {
- rw.SetReadDeadline(aLongTimeAgo) // Unblock reads
- }
-
- srv.lock.Unlock()
-
- if testShutdownNotify != nil {
- testShutdownNotify.Broadcast()
- }
-
- var ctxErr error
- select {
- case <-srv.shutdown:
- case <-ctx.Done():
- ctxErr = ctx.Err()
- }
-
- if srv.PacketConn != nil {
- srv.PacketConn.Close()
- }
-
- return ctxErr
-}
-
-var testShutdownNotify *sync.Cond
-
-// getReadTimeout is a helper func to use system timeout if server did not intend to change it.
-func (srv *Server) getReadTimeout() time.Duration {
- rtimeout := dnsTimeout
- if srv.ReadTimeout != 0 {
- rtimeout = srv.ReadTimeout
- }
- return rtimeout
-}
-
-// serveTCP starts a TCP listener for the server.
-func (srv *Server) serveTCP(l net.Listener) error {
- defer l.Close()
-
- if srv.NotifyStartedFunc != nil {
- srv.NotifyStartedFunc()
- }
-
- var wg sync.WaitGroup
- defer func() {
- wg.Wait()
- close(srv.shutdown)
- }()
-
- for srv.isStarted() {
- rw, err := l.Accept()
- if err != nil {
- if !srv.isStarted() {
- return nil
- }
- if neterr, ok := err.(net.Error); ok && neterr.Temporary() {
- continue
- }
- return err
- }
- srv.lock.Lock()
- // Track the connection to allow unblocking reads on shutdown.
- srv.conns[rw] = struct{}{}
- srv.lock.Unlock()
- wg.Add(1)
- srv.spawnWorker(&response{
- tsigSecret: srv.TsigSecret,
- tcp: rw,
- wg: &wg,
- })
- }
-
- return nil
-}
-
-// serveUDP starts a UDP listener for the server.
-func (srv *Server) serveUDP(l *net.UDPConn) error {
- defer l.Close()
-
- if srv.NotifyStartedFunc != nil {
- srv.NotifyStartedFunc()
- }
-
- reader := Reader(&defaultReader{srv})
- if srv.DecorateReader != nil {
- reader = srv.DecorateReader(reader)
- }
-
- var wg sync.WaitGroup
- defer func() {
- wg.Wait()
- close(srv.shutdown)
- }()
-
- rtimeout := srv.getReadTimeout()
- // deadline is not used here
- for srv.isStarted() {
- m, s, err := reader.ReadUDP(l, rtimeout)
- if err != nil {
- if !srv.isStarted() {
- return nil
- }
- if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
- continue
- }
- return err
- }
- if len(m) < headerSize {
- if cap(m) == srv.UDPSize {
- srv.udpPool.Put(m[:srv.UDPSize])
- }
- continue
- }
- wg.Add(1)
- srv.spawnWorker(&response{
- msg: m,
- tsigSecret: srv.TsigSecret,
- udp: l,
- udpSession: s,
- wg: &wg,
- })
- }
-
- return nil
-}
-
-func (srv *Server) serve(w *response) {
- if srv.DecorateWriter != nil {
- w.writer = srv.DecorateWriter(w)
- } else {
- w.writer = w
- }
-
- if w.udp != nil {
- // serve UDP
- srv.serveDNS(w)
-
- w.wg.Done()
- return
- }
-
- defer func() {
- if !w.hijacked {
- w.Close()
- }
-
- srv.lock.Lock()
- delete(srv.conns, w.tcp)
- srv.lock.Unlock()
-
- w.wg.Done()
- }()
-
- reader := Reader(&defaultReader{srv})
- if srv.DecorateReader != nil {
- reader = srv.DecorateReader(reader)
- }
-
- idleTimeout := tcpIdleTimeout
- if srv.IdleTimeout != nil {
- idleTimeout = srv.IdleTimeout()
- }
-
- timeout := srv.getReadTimeout()
-
- limit := srv.MaxTCPQueries
- if limit == 0 {
- limit = maxTCPQueries
- }
-
- for q := 0; (q < limit || limit == -1) && srv.isStarted(); q++ {
- var err error
- w.msg, err = reader.ReadTCP(w.tcp, timeout)
- if err != nil {
- // TODO(tmthrgd): handle error
- break
- }
- srv.serveDNS(w)
- if w.tcp == nil {
- break // Close() was called
- }
- if w.hijacked {
- break // client will call Close() themselves
- }
- // The first read uses the read timeout, the rest use the
- // idle timeout.
- timeout = idleTimeout
- }
-}
-
-func (srv *Server) disposeBuffer(w *response) {
- if w.udp != nil && cap(w.msg) == srv.UDPSize {
- srv.udpPool.Put(w.msg[:srv.UDPSize])
- }
- w.msg = nil
-}
-
-func (srv *Server) serveDNS(w *response) {
- req := new(Msg)
- err := req.Unpack(w.msg)
- if err != nil { // Send a FormatError back
- x := new(Msg)
- x.SetRcodeFormatError(req)
- w.WriteMsg(x)
- }
- if err != nil || !srv.Unsafe && req.Response {
- srv.disposeBuffer(w)
- return
- }
-
- w.tsigStatus = nil
- if w.tsigSecret != nil {
- if t := req.IsTsig(); t != nil {
- if secret, ok := w.tsigSecret[t.Hdr.Name]; ok {
- w.tsigStatus = TsigVerify(w.msg, secret, "", false)
- } else {
- w.tsigStatus = ErrSecret
- }
- w.tsigTimersOnly = false
- w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
- }
- }
-
- srv.disposeBuffer(w)
-
- handler := srv.Handler
- if handler == nil {
- handler = DefaultServeMux
- }
-
- handler.ServeDNS(w, req) // Writes back to the client
-}
-
-func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
- // If we race with ShutdownContext, the read deadline may
- // have been set in the distant past to unblock the read
- // below. We must not override it, otherwise we may block
- // ShutdownContext.
- srv.lock.RLock()
- if srv.started {
- conn.SetReadDeadline(time.Now().Add(timeout))
- }
- srv.lock.RUnlock()
-
- l := make([]byte, 2)
- n, err := conn.Read(l)
- if err != nil || n != 2 {
- if err != nil {
- return nil, err
- }
- return nil, ErrShortRead
- }
- length := binary.BigEndian.Uint16(l)
- if length == 0 {
- return nil, ErrShortRead
- }
- m := make([]byte, int(length))
- n, err = conn.Read(m[:int(length)])
- if err != nil || n == 0 {
- if err != nil {
- return nil, err
- }
- return nil, ErrShortRead
- }
- i := n
- for i < int(length) {
- j, err := conn.Read(m[i:int(length)])
- if err != nil {
- return nil, err
- }
- i += j
- }
- n = i
- m = m[:n]
- return m, nil
-}
-
-func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
- srv.lock.RLock()
- if srv.started {
- // See the comment in readTCP above.
- conn.SetReadDeadline(time.Now().Add(timeout))
- }
- srv.lock.RUnlock()
-
- m := srv.udpPool.Get().([]byte)
- n, s, err := ReadFromSessionUDP(conn, m)
- if err != nil {
- srv.udpPool.Put(m)
- return nil, nil, err
- }
- m = m[:n]
- return m, s, nil
-}
-
-// WriteMsg implements the ResponseWriter.WriteMsg method.
-func (w *response) WriteMsg(m *Msg) (err error) {
- var data []byte
- if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check)
- if t := m.IsTsig(); t != nil {
- data, w.tsigRequestMAC, err = TsigGenerate(m, w.tsigSecret[t.Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly)
- if err != nil {
- return err
- }
- _, err = w.writer.Write(data)
- return err
- }
- }
- data, err = m.Pack()
- if err != nil {
- return err
- }
- _, err = w.writer.Write(data)
- return err
-}
-
-// Write implements the ResponseWriter.Write method.
-func (w *response) Write(m []byte) (int, error) {
- switch {
- case w.udp != nil:
- n, err := WriteToSessionUDP(w.udp, m, w.udpSession)
- return n, err
- case w.tcp != nil:
- lm := len(m)
- if lm < 2 {
- return 0, io.ErrShortBuffer
- }
- if lm > MaxMsgSize {
- return 0, &Error{err: "message too large"}
- }
- l := make([]byte, 2, 2+lm)
- binary.BigEndian.PutUint16(l, uint16(lm))
- m = append(l, m...)
-
- n, err := io.Copy(w.tcp, bytes.NewReader(m))
- return int(n), err
- default:
- panic("dns: Write called after Close")
- }
-}
-
-// LocalAddr implements the ResponseWriter.LocalAddr method.
-func (w *response) LocalAddr() net.Addr {
- switch {
- case w.udp != nil:
- return w.udp.LocalAddr()
- case w.tcp != nil:
- return w.tcp.LocalAddr()
- default:
- panic("dns: LocalAddr called after Close")
- }
-}
-
-// RemoteAddr implements the ResponseWriter.RemoteAddr method.
-func (w *response) RemoteAddr() net.Addr {
- switch {
- case w.udpSession != nil:
- return w.udpSession.RemoteAddr()
- case w.tcp != nil:
- return w.tcp.RemoteAddr()
- default:
- panic("dns: RemoteAddr called after Close")
- }
-}
-
-// TsigStatus implements the ResponseWriter.TsigStatus method.
-func (w *response) TsigStatus() error { return w.tsigStatus }
-
-// TsigTimersOnly implements the ResponseWriter.TsigTimersOnly method.
-func (w *response) TsigTimersOnly(b bool) { w.tsigTimersOnly = b }
-
-// Hijack implements the ResponseWriter.Hijack method.
-func (w *response) Hijack() { w.hijacked = true }
-
-// Close implements the ResponseWriter.Close method
-func (w *response) Close() error {
- // Can't close the udp conn, as that is actually the listener.
- if w.tcp != nil {
- e := w.tcp.Close()
- w.tcp = nil
- return e
- }
- return nil
-}
-
-// ConnectionState() implements the ConnectionStater.ConnectionState() interface.
-func (w *response) ConnectionState() *tls.ConnectionState {
- type tlsConnectionStater interface {
- ConnectionState() tls.ConnectionState
- }
- if v, ok := w.tcp.(tlsConnectionStater); ok {
- t := v.ConnectionState()
- return &t
- }
- return nil
-}
diff --git a/vendor/github.com/miekg/dns/sig0.go b/vendor/github.com/miekg/dns/sig0.go
deleted file mode 100644
index 07c2acb196c..00000000000
--- a/vendor/github.com/miekg/dns/sig0.go
+++ /dev/null
@@ -1,217 +0,0 @@
-package dns
-
-import (
- "crypto"
- "crypto/dsa"
- "crypto/ecdsa"
- "crypto/rsa"
- "encoding/binary"
- "math/big"
- "strings"
- "time"
-)
-
-// Sign signs a dns.Msg. It fills the signature with the appropriate data.
-// The SIG record should have the SignerName, KeyTag, Algorithm, Inception
-// and Expiration set.
-func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
- if k == nil {
- return nil, ErrPrivKey
- }
- if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
- return nil, ErrKey
- }
- rr.Header().Rrtype = TypeSIG
- rr.Header().Class = ClassANY
- rr.Header().Ttl = 0
- rr.Header().Name = "."
- rr.OrigTtl = 0
- rr.TypeCovered = 0
- rr.Labels = 0
-
- buf := make([]byte, m.Len()+rr.len())
- mbuf, err := m.PackBuffer(buf)
- if err != nil {
- return nil, err
- }
- if &buf[0] != &mbuf[0] {
- return nil, ErrBuf
- }
- off, err := PackRR(rr, buf, len(mbuf), nil, false)
- if err != nil {
- return nil, err
- }
- buf = buf[:off:cap(buf)]
-
- hash, ok := AlgorithmToHash[rr.Algorithm]
- if !ok {
- return nil, ErrAlg
- }
-
- hasher := hash.New()
- // Write SIG rdata
- hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
- // Write message
- hasher.Write(buf[:len(mbuf)])
-
- signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm)
- if err != nil {
- return nil, err
- }
-
- rr.Signature = toBase64(signature)
-
- buf = append(buf, signature...)
- if len(buf) > int(^uint16(0)) {
- return nil, ErrBuf
- }
- // Adjust sig data length
- rdoff := len(mbuf) + 1 + 2 + 2 + 4
- rdlen := binary.BigEndian.Uint16(buf[rdoff:])
- rdlen += uint16(len(signature))
- binary.BigEndian.PutUint16(buf[rdoff:], rdlen)
- // Adjust additional count
- adc := binary.BigEndian.Uint16(buf[10:])
- adc++
- binary.BigEndian.PutUint16(buf[10:], adc)
- return buf, nil
-}
-
-// Verify validates the message buf using the key k.
-// It's assumed that buf is a valid message from which rr was unpacked.
-func (rr *SIG) Verify(k *KEY, buf []byte) error {
- if k == nil {
- return ErrKey
- }
- if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
- return ErrKey
- }
-
- var hash crypto.Hash
- switch rr.Algorithm {
- case DSA, RSASHA1:
- hash = crypto.SHA1
- case RSASHA256, ECDSAP256SHA256:
- hash = crypto.SHA256
- case ECDSAP384SHA384:
- hash = crypto.SHA384
- case RSASHA512:
- hash = crypto.SHA512
- default:
- return ErrAlg
- }
- hasher := hash.New()
-
- buflen := len(buf)
- qdc := binary.BigEndian.Uint16(buf[4:])
- anc := binary.BigEndian.Uint16(buf[6:])
- auc := binary.BigEndian.Uint16(buf[8:])
- adc := binary.BigEndian.Uint16(buf[10:])
- offset := 12
- var err error
- for i := uint16(0); i < qdc && offset < buflen; i++ {
- _, offset, err = UnpackDomainName(buf, offset)
- if err != nil {
- return err
- }
- // Skip past Type and Class
- offset += 2 + 2
- }
- for i := uint16(1); i < anc+auc+adc && offset < buflen; i++ {
- _, offset, err = UnpackDomainName(buf, offset)
- if err != nil {
- return err
- }
- // Skip past Type, Class and TTL
- offset += 2 + 2 + 4
- if offset+1 >= buflen {
- continue
- }
- rdlen := binary.BigEndian.Uint16(buf[offset:])
- offset += 2
- offset += int(rdlen)
- }
- if offset >= buflen {
- return &Error{err: "overflowing unpacking signed message"}
- }
-
- // offset should be just prior to SIG
- bodyend := offset
- // owner name SHOULD be root
- _, offset, err = UnpackDomainName(buf, offset)
- if err != nil {
- return err
- }
- // Skip Type, Class, TTL, RDLen
- offset += 2 + 2 + 4 + 2
- sigstart := offset
- // Skip Type Covered, Algorithm, Labels, Original TTL
- offset += 2 + 1 + 1 + 4
- if offset+4+4 >= buflen {
- return &Error{err: "overflow unpacking signed message"}
- }
- expire := binary.BigEndian.Uint32(buf[offset:])
- offset += 4
- incept := binary.BigEndian.Uint32(buf[offset:])
- offset += 4
- now := uint32(time.Now().Unix())
- if now < incept || now > expire {
- return ErrTime
- }
- // Skip key tag
- offset += 2
- var signername string
- signername, offset, err = UnpackDomainName(buf, offset)
- if err != nil {
- return err
- }
- // If key has come from the DNS name compression might
- // have mangled the case of the name
- if strings.ToLower(signername) != strings.ToLower(k.Header().Name) {
- return &Error{err: "signer name doesn't match key name"}
- }
- sigend := offset
- hasher.Write(buf[sigstart:sigend])
- hasher.Write(buf[:10])
- hasher.Write([]byte{
- byte((adc - 1) << 8),
- byte(adc - 1),
- })
- hasher.Write(buf[12:bodyend])
-
- hashed := hasher.Sum(nil)
- sig := buf[sigend:]
- switch k.Algorithm {
- case DSA:
- pk := k.publicKeyDSA()
- sig = sig[1:]
- r := big.NewInt(0)
- r.SetBytes(sig[:len(sig)/2])
- s := big.NewInt(0)
- s.SetBytes(sig[len(sig)/2:])
- if pk != nil {
- if dsa.Verify(pk, hashed, r, s) {
- return nil
- }
- return ErrSig
- }
- case RSASHA1, RSASHA256, RSASHA512:
- pk := k.publicKeyRSA()
- if pk != nil {
- return rsa.VerifyPKCS1v15(pk, hash, hashed, sig)
- }
- case ECDSAP256SHA256, ECDSAP384SHA384:
- pk := k.publicKeyECDSA()
- r := big.NewInt(0)
- r.SetBytes(sig[:len(sig)/2])
- s := big.NewInt(0)
- s.SetBytes(sig[len(sig)/2:])
- if pk != nil {
- if ecdsa.Verify(pk, hashed, r, s) {
- return nil
- }
- return ErrSig
- }
- }
- return ErrKeyAlg
-}
diff --git a/vendor/github.com/miekg/dns/singleinflight.go b/vendor/github.com/miekg/dns/singleinflight.go
deleted file mode 100644
index 9573c7d0b8c..00000000000
--- a/vendor/github.com/miekg/dns/singleinflight.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Adapted for dns package usage by Miek Gieben.
-
-package dns
-
-import "sync"
-import "time"
-
-// call is an in-flight or completed singleflight.Do call
-type call struct {
- wg sync.WaitGroup
- val *Msg
- rtt time.Duration
- err error
- dups int
-}
-
-// singleflight represents a class of work and forms a namespace in
-// which units of work can be executed with duplicate suppression.
-type singleflight struct {
- sync.Mutex // protects m
- m map[string]*call // lazily initialized
-}
-
-// Do executes and returns the results of the given function, making
-// sure that only one execution is in-flight for a given key at a
-// time. If a duplicate comes in, the duplicate caller waits for the
-// original to complete and receives the same results.
-// The return value shared indicates whether v was given to multiple callers.
-func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v *Msg, rtt time.Duration, err error, shared bool) {
- g.Lock()
- if g.m == nil {
- g.m = make(map[string]*call)
- }
- if c, ok := g.m[key]; ok {
- c.dups++
- g.Unlock()
- c.wg.Wait()
- return c.val, c.rtt, c.err, true
- }
- c := new(call)
- c.wg.Add(1)
- g.m[key] = c
- g.Unlock()
-
- c.val, c.rtt, c.err = fn()
- c.wg.Done()
-
- g.Lock()
- delete(g.m, key)
- g.Unlock()
-
- return c.val, c.rtt, c.err, c.dups > 0
-}
diff --git a/vendor/github.com/miekg/dns/smimea.go b/vendor/github.com/miekg/dns/smimea.go
deleted file mode 100644
index 4e7ded4b386..00000000000
--- a/vendor/github.com/miekg/dns/smimea.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package dns
-
-import (
- "crypto/sha256"
- "crypto/x509"
- "encoding/hex"
-)
-
-// Sign creates a SMIMEA record from an SSL certificate.
-func (r *SMIMEA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
- r.Hdr.Rrtype = TypeSMIMEA
- r.Usage = uint8(usage)
- r.Selector = uint8(selector)
- r.MatchingType = uint8(matchingType)
-
- r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
- if err != nil {
- return err
- }
- return nil
-}
-
-// Verify verifies a SMIMEA record against an SSL certificate. If it is OK
-// a nil error is returned.
-func (r *SMIMEA) Verify(cert *x509.Certificate) error {
- c, err := CertificateToDANE(r.Selector, r.MatchingType, cert)
- if err != nil {
- return err // Not also ErrSig?
- }
- if r.Certificate == c {
- return nil
- }
- return ErrSig // ErrSig, really?
-}
-
-// SMIMEAName returns the ownername of a SMIMEA resource record as per the
-// format specified in RFC 'draft-ietf-dane-smime-12' Section 2 and 3
-func SMIMEAName(email, domain string) (string, error) {
- hasher := sha256.New()
- hasher.Write([]byte(email))
-
- // RFC Section 3: "The local-part is hashed using the SHA2-256
- // algorithm with the hash truncated to 28 octets and
- // represented in its hexadecimal representation to become the
- // left-most label in the prepared domain name"
- return hex.EncodeToString(hasher.Sum(nil)[:28]) + "." + "_smimecert." + domain, nil
-}
diff --git a/vendor/github.com/miekg/dns/tlsa.go b/vendor/github.com/miekg/dns/tlsa.go
deleted file mode 100644
index 431e2fb5afc..00000000000
--- a/vendor/github.com/miekg/dns/tlsa.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package dns
-
-import (
- "crypto/x509"
- "net"
- "strconv"
-)
-
-// Sign creates a TLSA record from an SSL certificate.
-func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
- r.Hdr.Rrtype = TypeTLSA
- r.Usage = uint8(usage)
- r.Selector = uint8(selector)
- r.MatchingType = uint8(matchingType)
-
- r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
- if err != nil {
- return err
- }
- return nil
-}
-
-// Verify verifies a TLSA record against an SSL certificate. If it is OK
-// a nil error is returned.
-func (r *TLSA) Verify(cert *x509.Certificate) error {
- c, err := CertificateToDANE(r.Selector, r.MatchingType, cert)
- if err != nil {
- return err // Not also ErrSig?
- }
- if r.Certificate == c {
- return nil
- }
- return ErrSig // ErrSig, really?
-}
-
-// TLSAName returns the ownername of a TLSA resource record as per the
-// rules specified in RFC 6698, Section 3.
-func TLSAName(name, service, network string) (string, error) {
- if !IsFqdn(name) {
- return "", ErrFqdn
- }
- p, err := net.LookupPort(network, service)
- if err != nil {
- return "", err
- }
- return "_" + strconv.Itoa(p) + "._" + network + "." + name, nil
-}
diff --git a/vendor/github.com/miekg/dns/tsig.go b/vendor/github.com/miekg/dns/tsig.go
deleted file mode 100644
index 4837b4ab1fd..00000000000
--- a/vendor/github.com/miekg/dns/tsig.go
+++ /dev/null
@@ -1,386 +0,0 @@
-package dns
-
-import (
- "crypto/hmac"
- "crypto/md5"
- "crypto/sha1"
- "crypto/sha256"
- "crypto/sha512"
- "encoding/binary"
- "encoding/hex"
- "hash"
- "strconv"
- "strings"
- "time"
-)
-
-// HMAC hashing codes. These are transmitted as domain names.
-const (
- HmacMD5 = "hmac-md5.sig-alg.reg.int."
- HmacSHA1 = "hmac-sha1."
- HmacSHA256 = "hmac-sha256."
- HmacSHA512 = "hmac-sha512."
-)
-
-// TSIG is the RR the holds the transaction signature of a message.
-// See RFC 2845 and RFC 4635.
-type TSIG struct {
- Hdr RR_Header
- Algorithm string `dns:"domain-name"`
- TimeSigned uint64 `dns:"uint48"`
- Fudge uint16
- MACSize uint16
- MAC string `dns:"size-hex:MACSize"`
- OrigId uint16
- Error uint16
- OtherLen uint16
- OtherData string `dns:"size-hex:OtherLen"`
-}
-
-// TSIG has no official presentation format, but this will suffice.
-
-func (rr *TSIG) String() string {
- s := "\n;; TSIG PSEUDOSECTION:\n"
- s += rr.Hdr.String() +
- " " + rr.Algorithm +
- " " + tsigTimeToString(rr.TimeSigned) +
- " " + strconv.Itoa(int(rr.Fudge)) +
- " " + strconv.Itoa(int(rr.MACSize)) +
- " " + strings.ToUpper(rr.MAC) +
- " " + strconv.Itoa(int(rr.OrigId)) +
- " " + strconv.Itoa(int(rr.Error)) + // BIND prints NOERROR
- " " + strconv.Itoa(int(rr.OtherLen)) +
- " " + rr.OtherData
- return s
-}
-
-// The following values must be put in wireformat, so that the MAC can be calculated.
-// RFC 2845, section 3.4.2. TSIG Variables.
-type tsigWireFmt struct {
- // From RR_Header
- Name string `dns:"domain-name"`
- Class uint16
- Ttl uint32
- // Rdata of the TSIG
- Algorithm string `dns:"domain-name"`
- TimeSigned uint64 `dns:"uint48"`
- Fudge uint16
- // MACSize, MAC and OrigId excluded
- Error uint16
- OtherLen uint16
- OtherData string `dns:"size-hex:OtherLen"`
-}
-
-// If we have the MAC use this type to convert it to wiredata. Section 3.4.3. Request MAC
-type macWireFmt struct {
- MACSize uint16
- MAC string `dns:"size-hex:MACSize"`
-}
-
-// 3.3. Time values used in TSIG calculations
-type timerWireFmt struct {
- TimeSigned uint64 `dns:"uint48"`
- Fudge uint16
-}
-
-// TsigGenerate fills out the TSIG record attached to the message.
-// The message should contain
-// a "stub" TSIG RR with the algorithm, key name (owner name of the RR),
-// time fudge (defaults to 300 seconds) and the current time
-// The TSIG MAC is saved in that Tsig RR.
-// When TsigGenerate is called for the first time requestMAC is set to the empty string and
-// timersOnly is false.
-// If something goes wrong an error is returned, otherwise it is nil.
-func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
- if m.IsTsig() == nil {
- panic("dns: TSIG not last RR in additional")
- }
- // If we barf here, the caller is to blame
- rawsecret, err := fromBase64([]byte(secret))
- if err != nil {
- return nil, "", err
- }
-
- rr := m.Extra[len(m.Extra)-1].(*TSIG)
- m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
- mbuf, err := m.Pack()
- if err != nil {
- return nil, "", err
- }
- buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
-
- t := new(TSIG)
- var h hash.Hash
- switch strings.ToLower(rr.Algorithm) {
- case HmacMD5:
- h = hmac.New(md5.New, []byte(rawsecret))
- case HmacSHA1:
- h = hmac.New(sha1.New, []byte(rawsecret))
- case HmacSHA256:
- h = hmac.New(sha256.New, []byte(rawsecret))
- case HmacSHA512:
- h = hmac.New(sha512.New, []byte(rawsecret))
- default:
- return nil, "", ErrKeyAlg
- }
- h.Write(buf)
- t.MAC = hex.EncodeToString(h.Sum(nil))
- t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
-
- t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0}
- t.Fudge = rr.Fudge
- t.TimeSigned = rr.TimeSigned
- t.Algorithm = rr.Algorithm
- t.OrigId = m.Id
-
- tbuf := make([]byte, t.len())
- if off, err := PackRR(t, tbuf, 0, nil, false); err == nil {
- tbuf = tbuf[:off] // reset to actual size used
- } else {
- return nil, "", err
- }
- mbuf = append(mbuf, tbuf...)
- // Update the ArCount directly in the buffer.
- binary.BigEndian.PutUint16(mbuf[10:], uint16(len(m.Extra)+1))
-
- return mbuf, t.MAC, nil
-}
-
-// TsigVerify verifies the TSIG on a message.
-// If the signature does not validate err contains the
-// error, otherwise it is nil.
-func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
- rawsecret, err := fromBase64([]byte(secret))
- if err != nil {
- return err
- }
- // Strip the TSIG from the incoming msg
- stripped, tsig, err := stripTsig(msg)
- if err != nil {
- return err
- }
-
- msgMAC, err := hex.DecodeString(tsig.MAC)
- if err != nil {
- return err
- }
-
- buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
-
- // Fudge factor works both ways. A message can arrive before it was signed because
- // of clock skew.
- now := uint64(time.Now().Unix())
- ti := now - tsig.TimeSigned
- if now < tsig.TimeSigned {
- ti = tsig.TimeSigned - now
- }
- if uint64(tsig.Fudge) < ti {
- return ErrTime
- }
-
- var h hash.Hash
- switch strings.ToLower(tsig.Algorithm) {
- case HmacMD5:
- h = hmac.New(md5.New, rawsecret)
- case HmacSHA1:
- h = hmac.New(sha1.New, rawsecret)
- case HmacSHA256:
- h = hmac.New(sha256.New, rawsecret)
- case HmacSHA512:
- h = hmac.New(sha512.New, rawsecret)
- default:
- return ErrKeyAlg
- }
- h.Write(buf)
- if !hmac.Equal(h.Sum(nil), msgMAC) {
- return ErrSig
- }
- return nil
-}
-
-// Create a wiredata buffer for the MAC calculation.
-func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte {
- var buf []byte
- if rr.TimeSigned == 0 {
- rr.TimeSigned = uint64(time.Now().Unix())
- }
- if rr.Fudge == 0 {
- rr.Fudge = 300 // Standard (RFC) default.
- }
-
- // Replace message ID in header with original ID from TSIG
- binary.BigEndian.PutUint16(msgbuf[0:2], rr.OrigId)
-
- if requestMAC != "" {
- m := new(macWireFmt)
- m.MACSize = uint16(len(requestMAC) / 2)
- m.MAC = requestMAC
- buf = make([]byte, len(requestMAC)) // long enough
- n, _ := packMacWire(m, buf)
- buf = buf[:n]
- }
-
- tsigvar := make([]byte, DefaultMsgSize)
- if timersOnly {
- tsig := new(timerWireFmt)
- tsig.TimeSigned = rr.TimeSigned
- tsig.Fudge = rr.Fudge
- n, _ := packTimerWire(tsig, tsigvar)
- tsigvar = tsigvar[:n]
- } else {
- tsig := new(tsigWireFmt)
- tsig.Name = strings.ToLower(rr.Hdr.Name)
- tsig.Class = ClassANY
- tsig.Ttl = rr.Hdr.Ttl
- tsig.Algorithm = strings.ToLower(rr.Algorithm)
- tsig.TimeSigned = rr.TimeSigned
- tsig.Fudge = rr.Fudge
- tsig.Error = rr.Error
- tsig.OtherLen = rr.OtherLen
- tsig.OtherData = rr.OtherData
- n, _ := packTsigWire(tsig, tsigvar)
- tsigvar = tsigvar[:n]
- }
-
- if requestMAC != "" {
- x := append(buf, msgbuf...)
- buf = append(x, tsigvar...)
- } else {
- buf = append(msgbuf, tsigvar...)
- }
- return buf
-}
-
-// Strip the TSIG from the raw message.
-func stripTsig(msg []byte) ([]byte, *TSIG, error) {
- // Copied from msg.go's Unpack() Header, but modified.
- var (
- dh Header
- err error
- )
- off, tsigoff := 0, 0
-
- if dh, off, err = unpackMsgHdr(msg, off); err != nil {
- return nil, nil, err
- }
- if dh.Arcount == 0 {
- return nil, nil, ErrNoSig
- }
-
- // Rcode, see msg.go Unpack()
- if int(dh.Bits&0xF) == RcodeNotAuth {
- return nil, nil, ErrAuth
- }
-
- for i := 0; i < int(dh.Qdcount); i++ {
- _, off, err = unpackQuestion(msg, off)
- if err != nil {
- return nil, nil, err
- }
- }
-
- _, off, err = unpackRRslice(int(dh.Ancount), msg, off)
- if err != nil {
- return nil, nil, err
- }
- _, off, err = unpackRRslice(int(dh.Nscount), msg, off)
- if err != nil {
- return nil, nil, err
- }
-
- rr := new(TSIG)
- var extra RR
- for i := 0; i < int(dh.Arcount); i++ {
- tsigoff = off
- extra, off, err = UnpackRR(msg, off)
- if err != nil {
- return nil, nil, err
- }
- if extra.Header().Rrtype == TypeTSIG {
- rr = extra.(*TSIG)
- // Adjust Arcount.
- arcount := binary.BigEndian.Uint16(msg[10:])
- binary.BigEndian.PutUint16(msg[10:], arcount-1)
- break
- }
- }
- if rr == nil {
- return nil, nil, ErrNoSig
- }
- return msg[:tsigoff], rr, nil
-}
-
-// Translate the TSIG time signed into a date. There is no
-// need for RFC1982 calculations as this date is 48 bits.
-func tsigTimeToString(t uint64) string {
- ti := time.Unix(int64(t), 0).UTC()
- return ti.Format("20060102150405")
-}
-
-func packTsigWire(tw *tsigWireFmt, msg []byte) (int, error) {
- // copied from zmsg.go TSIG packing
- // RR_Header
- off, err := PackDomainName(tw.Name, msg, 0, nil, false)
- if err != nil {
- return off, err
- }
- off, err = packUint16(tw.Class, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(tw.Ttl, msg, off)
- if err != nil {
- return off, err
- }
-
- off, err = PackDomainName(tw.Algorithm, msg, off, nil, false)
- if err != nil {
- return off, err
- }
- off, err = packUint48(tw.TimeSigned, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(tw.Fudge, msg, off)
- if err != nil {
- return off, err
- }
-
- off, err = packUint16(tw.Error, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(tw.OtherLen, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(tw.OtherData, msg, off)
- if err != nil {
- return off, err
- }
- return off, nil
-}
-
-func packMacWire(mw *macWireFmt, msg []byte) (int, error) {
- off, err := packUint16(mw.MACSize, msg, 0)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(mw.MAC, msg, off)
- if err != nil {
- return off, err
- }
- return off, nil
-}
-
-func packTimerWire(tw *timerWireFmt, msg []byte) (int, error) {
- off, err := packUint48(tw.TimeSigned, msg, 0)
- if err != nil {
- return off, err
- }
- off, err = packUint16(tw.Fudge, msg, off)
- if err != nil {
- return off, err
- }
- return off, nil
-}
diff --git a/vendor/github.com/miekg/dns/types.go b/vendor/github.com/miekg/dns/types.go
deleted file mode 100644
index 115f2c7bd0e..00000000000
--- a/vendor/github.com/miekg/dns/types.go
+++ /dev/null
@@ -1,1383 +0,0 @@
-package dns
-
-import (
- "fmt"
- "net"
- "strconv"
- "strings"
- "time"
-)
-
-type (
- // Type is a DNS type.
- Type uint16
- // Class is a DNS class.
- Class uint16
- // Name is a DNS domain name.
- Name string
-)
-
-// Packet formats
-
-// Wire constants and supported types.
-const (
- // valid RR_Header.Rrtype and Question.qtype
-
- TypeNone uint16 = 0
- TypeA uint16 = 1
- TypeNS uint16 = 2
- TypeMD uint16 = 3
- TypeMF uint16 = 4
- TypeCNAME uint16 = 5
- TypeSOA uint16 = 6
- TypeMB uint16 = 7
- TypeMG uint16 = 8
- TypeMR uint16 = 9
- TypeNULL uint16 = 10
- TypePTR uint16 = 12
- TypeHINFO uint16 = 13
- TypeMINFO uint16 = 14
- TypeMX uint16 = 15
- TypeTXT uint16 = 16
- TypeRP uint16 = 17
- TypeAFSDB uint16 = 18
- TypeX25 uint16 = 19
- TypeISDN uint16 = 20
- TypeRT uint16 = 21
- TypeNSAPPTR uint16 = 23
- TypeSIG uint16 = 24
- TypeKEY uint16 = 25
- TypePX uint16 = 26
- TypeGPOS uint16 = 27
- TypeAAAA uint16 = 28
- TypeLOC uint16 = 29
- TypeNXT uint16 = 30
- TypeEID uint16 = 31
- TypeNIMLOC uint16 = 32
- TypeSRV uint16 = 33
- TypeATMA uint16 = 34
- TypeNAPTR uint16 = 35
- TypeKX uint16 = 36
- TypeCERT uint16 = 37
- TypeDNAME uint16 = 39
- TypeOPT uint16 = 41 // EDNS
- TypeDS uint16 = 43
- TypeSSHFP uint16 = 44
- TypeRRSIG uint16 = 46
- TypeNSEC uint16 = 47
- TypeDNSKEY uint16 = 48
- TypeDHCID uint16 = 49
- TypeNSEC3 uint16 = 50
- TypeNSEC3PARAM uint16 = 51
- TypeTLSA uint16 = 52
- TypeSMIMEA uint16 = 53
- TypeHIP uint16 = 55
- TypeNINFO uint16 = 56
- TypeRKEY uint16 = 57
- TypeTALINK uint16 = 58
- TypeCDS uint16 = 59
- TypeCDNSKEY uint16 = 60
- TypeOPENPGPKEY uint16 = 61
- TypeCSYNC uint16 = 62
- TypeSPF uint16 = 99
- TypeUINFO uint16 = 100
- TypeUID uint16 = 101
- TypeGID uint16 = 102
- TypeUNSPEC uint16 = 103
- TypeNID uint16 = 104
- TypeL32 uint16 = 105
- TypeL64 uint16 = 106
- TypeLP uint16 = 107
- TypeEUI48 uint16 = 108
- TypeEUI64 uint16 = 109
- TypeURI uint16 = 256
- TypeCAA uint16 = 257
- TypeAVC uint16 = 258
-
- TypeTKEY uint16 = 249
- TypeTSIG uint16 = 250
-
- // valid Question.Qtype only
- TypeIXFR uint16 = 251
- TypeAXFR uint16 = 252
- TypeMAILB uint16 = 253
- TypeMAILA uint16 = 254
- TypeANY uint16 = 255
-
- TypeTA uint16 = 32768
- TypeDLV uint16 = 32769
- TypeReserved uint16 = 65535
-
- // valid Question.Qclass
- ClassINET = 1
- ClassCSNET = 2
- ClassCHAOS = 3
- ClassHESIOD = 4
- ClassNONE = 254
- ClassANY = 255
-
- // Message Response Codes, see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
- RcodeSuccess = 0 // NoError - No Error [DNS]
- RcodeFormatError = 1 // FormErr - Format Error [DNS]
- RcodeServerFailure = 2 // ServFail - Server Failure [DNS]
- RcodeNameError = 3 // NXDomain - Non-Existent Domain [DNS]
- RcodeNotImplemented = 4 // NotImp - Not Implemented [DNS]
- RcodeRefused = 5 // Refused - Query Refused [DNS]
- RcodeYXDomain = 6 // YXDomain - Name Exists when it should not [DNS Update]
- RcodeYXRrset = 7 // YXRRSet - RR Set Exists when it should not [DNS Update]
- RcodeNXRrset = 8 // NXRRSet - RR Set that should exist does not [DNS Update]
- RcodeNotAuth = 9 // NotAuth - Server Not Authoritative for zone [DNS Update]
- RcodeNotZone = 10 // NotZone - Name not contained in zone [DNS Update/TSIG]
- RcodeBadSig = 16 // BADSIG - TSIG Signature Failure [TSIG]
- RcodeBadVers = 16 // BADVERS - Bad OPT Version [EDNS0]
- RcodeBadKey = 17 // BADKEY - Key not recognized [TSIG]
- RcodeBadTime = 18 // BADTIME - Signature out of time window [TSIG]
- RcodeBadMode = 19 // BADMODE - Bad TKEY Mode [TKEY]
- RcodeBadName = 20 // BADNAME - Duplicate key name [TKEY]
- RcodeBadAlg = 21 // BADALG - Algorithm not supported [TKEY]
- RcodeBadTrunc = 22 // BADTRUNC - Bad Truncation [TSIG]
- RcodeBadCookie = 23 // BADCOOKIE - Bad/missing Server Cookie [DNS Cookies]
-
- // Message Opcodes. There is no 3.
- OpcodeQuery = 0
- OpcodeIQuery = 1
- OpcodeStatus = 2
- OpcodeNotify = 4
- OpcodeUpdate = 5
-)
-
-// Header is the wire format for the DNS packet header.
-type Header struct {
- Id uint16
- Bits uint16
- Qdcount, Ancount, Nscount, Arcount uint16
-}
-
-const (
- headerSize = 12
-
- // Header.Bits
- _QR = 1 << 15 // query/response (response=1)
- _AA = 1 << 10 // authoritative
- _TC = 1 << 9 // truncated
- _RD = 1 << 8 // recursion desired
- _RA = 1 << 7 // recursion available
- _Z = 1 << 6 // Z
- _AD = 1 << 5 // authticated data
- _CD = 1 << 4 // checking disabled
-)
-
-// Various constants used in the LOC RR, See RFC 1887.
-const (
- LOC_EQUATOR = 1 << 31 // RFC 1876, Section 2.
- LOC_PRIMEMERIDIAN = 1 << 31 // RFC 1876, Section 2.
- LOC_HOURS = 60 * 1000
- LOC_DEGREES = 60 * LOC_HOURS
- LOC_ALTITUDEBASE = 100000
-)
-
-// Different Certificate Types, see RFC 4398, Section 2.1
-const (
- CertPKIX = 1 + iota
- CertSPKI
- CertPGP
- CertIPIX
- CertISPKI
- CertIPGP
- CertACPKIX
- CertIACPKIX
- CertURI = 253
- CertOID = 254
-)
-
-// CertTypeToString converts the Cert Type to its string representation.
-// See RFC 4398 and RFC 6944.
-var CertTypeToString = map[uint16]string{
- CertPKIX: "PKIX",
- CertSPKI: "SPKI",
- CertPGP: "PGP",
- CertIPIX: "IPIX",
- CertISPKI: "ISPKI",
- CertIPGP: "IPGP",
- CertACPKIX: "ACPKIX",
- CertIACPKIX: "IACPKIX",
- CertURI: "URI",
- CertOID: "OID",
-}
-
-// StringToCertType is the reverseof CertTypeToString.
-var StringToCertType = reverseInt16(CertTypeToString)
-
-//go:generate go run types_generate.go
-
-// Question holds a DNS question. There can be multiple questions in the
-// question section of a message. Usually there is just one.
-type Question struct {
- Name string `dns:"cdomain-name"` // "cdomain-name" specifies encoding (and may be compressed)
- Qtype uint16
- Qclass uint16
-}
-
-func (q *Question) len() int {
- return len(q.Name) + 1 + 2 + 2
-}
-
-func (q *Question) String() (s string) {
- // prefix with ; (as in dig)
- s = ";" + sprintName(q.Name) + "\t"
- s += Class(q.Qclass).String() + "\t"
- s += " " + Type(q.Qtype).String()
- return s
-}
-
-// ANY is a wildcard record. See RFC 1035, Section 3.2.3. ANY
-// is named "*" there.
-type ANY struct {
- Hdr RR_Header
- // Does not have any rdata
-}
-
-func (rr *ANY) String() string { return rr.Hdr.String() }
-
-// CNAME RR. See RFC 1034.
-type CNAME struct {
- Hdr RR_Header
- Target string `dns:"cdomain-name"`
-}
-
-func (rr *CNAME) String() string { return rr.Hdr.String() + sprintName(rr.Target) }
-
-// HINFO RR. See RFC 1034.
-type HINFO struct {
- Hdr RR_Header
- Cpu string
- Os string
-}
-
-func (rr *HINFO) String() string {
- return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os})
-}
-
-// MB RR. See RFC 1035.
-type MB struct {
- Hdr RR_Header
- Mb string `dns:"cdomain-name"`
-}
-
-func (rr *MB) String() string { return rr.Hdr.String() + sprintName(rr.Mb) }
-
-// MG RR. See RFC 1035.
-type MG struct {
- Hdr RR_Header
- Mg string `dns:"cdomain-name"`
-}
-
-func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) }
-
-// MINFO RR. See RFC 1035.
-type MINFO struct {
- Hdr RR_Header
- Rmail string `dns:"cdomain-name"`
- Email string `dns:"cdomain-name"`
-}
-
-func (rr *MINFO) String() string {
- return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email)
-}
-
-// MR RR. See RFC 1035.
-type MR struct {
- Hdr RR_Header
- Mr string `dns:"cdomain-name"`
-}
-
-func (rr *MR) String() string {
- return rr.Hdr.String() + sprintName(rr.Mr)
-}
-
-// MF RR. See RFC 1035.
-type MF struct {
- Hdr RR_Header
- Mf string `dns:"cdomain-name"`
-}
-
-func (rr *MF) String() string {
- return rr.Hdr.String() + sprintName(rr.Mf)
-}
-
-// MD RR. See RFC 1035.
-type MD struct {
- Hdr RR_Header
- Md string `dns:"cdomain-name"`
-}
-
-func (rr *MD) String() string {
- return rr.Hdr.String() + sprintName(rr.Md)
-}
-
-// MX RR. See RFC 1035.
-type MX struct {
- Hdr RR_Header
- Preference uint16
- Mx string `dns:"cdomain-name"`
-}
-
-func (rr *MX) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
-}
-
-// AFSDB RR. See RFC 1183.
-type AFSDB struct {
- Hdr RR_Header
- Subtype uint16
- Hostname string `dns:"domain-name"`
-}
-
-func (rr *AFSDB) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
-}
-
-// X25 RR. See RFC 1183, Section 3.1.
-type X25 struct {
- Hdr RR_Header
- PSDNAddress string
-}
-
-func (rr *X25) String() string {
- return rr.Hdr.String() + rr.PSDNAddress
-}
-
-// RT RR. See RFC 1183, Section 3.3.
-type RT struct {
- Hdr RR_Header
- Preference uint16
- Host string `dns:"cdomain-name"`
-}
-
-func (rr *RT) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
-}
-
-// NS RR. See RFC 1035.
-type NS struct {
- Hdr RR_Header
- Ns string `dns:"cdomain-name"`
-}
-
-func (rr *NS) String() string {
- return rr.Hdr.String() + sprintName(rr.Ns)
-}
-
-// PTR RR. See RFC 1035.
-type PTR struct {
- Hdr RR_Header
- Ptr string `dns:"cdomain-name"`
-}
-
-func (rr *PTR) String() string {
- return rr.Hdr.String() + sprintName(rr.Ptr)
-}
-
-// RP RR. See RFC 1138, Section 2.2.
-type RP struct {
- Hdr RR_Header
- Mbox string `dns:"domain-name"`
- Txt string `dns:"domain-name"`
-}
-
-func (rr *RP) String() string {
- return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
-}
-
-// SOA RR. See RFC 1035.
-type SOA struct {
- Hdr RR_Header
- Ns string `dns:"cdomain-name"`
- Mbox string `dns:"cdomain-name"`
- Serial uint32
- Refresh uint32
- Retry uint32
- Expire uint32
- Minttl uint32
-}
-
-func (rr *SOA) String() string {
- return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) +
- " " + strconv.FormatInt(int64(rr.Serial), 10) +
- " " + strconv.FormatInt(int64(rr.Refresh), 10) +
- " " + strconv.FormatInt(int64(rr.Retry), 10) +
- " " + strconv.FormatInt(int64(rr.Expire), 10) +
- " " + strconv.FormatInt(int64(rr.Minttl), 10)
-}
-
-// TXT RR. See RFC 1035.
-type TXT struct {
- Hdr RR_Header
- Txt []string `dns:"txt"`
-}
-
-func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
-
-func sprintName(s string) string {
- var dst strings.Builder
- dst.Grow(len(s))
- for i := 0; i < len(s); {
- if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
- dst.WriteString(s[i : i+2])
- i += 2
- continue
- }
-
- b, n := nextByte(s, i)
- switch {
- case n == 0:
- i++ // dangling back slash
- case b == '.':
- dst.WriteByte('.')
- default:
- writeDomainNameByte(&dst, b)
- }
- i += n
- }
- return dst.String()
-}
-
-func sprintTxtOctet(s string) string {
- var dst strings.Builder
- dst.Grow(2 + len(s))
- dst.WriteByte('"')
- for i := 0; i < len(s); {
- if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
- dst.WriteString(s[i : i+2])
- i += 2
- continue
- }
-
- b, n := nextByte(s, i)
- switch {
- case n == 0:
- i++ // dangling back slash
- case b == '.':
- dst.WriteByte('.')
- case b < ' ' || b > '~':
- writeEscapedByte(&dst, b)
- default:
- dst.WriteByte(b)
- }
- i += n
- }
- dst.WriteByte('"')
- return dst.String()
-}
-
-func sprintTxt(txt []string) string {
- var out strings.Builder
- for i, s := range txt {
- out.Grow(3 + len(s))
- if i > 0 {
- out.WriteString(` "`)
- } else {
- out.WriteByte('"')
- }
- for j := 0; j < len(s); {
- b, n := nextByte(s, j)
- if n == 0 {
- break
- }
- writeTXTStringByte(&out, b)
- j += n
- }
- out.WriteByte('"')
- }
- return out.String()
-}
-
-func writeDomainNameByte(s *strings.Builder, b byte) {
- switch b {
- case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
- s.WriteByte('\\')
- s.WriteByte(b)
- default:
- writeTXTStringByte(s, b)
- }
-}
-
-func writeTXTStringByte(s *strings.Builder, b byte) {
- switch {
- case b == '"' || b == '\\':
- s.WriteByte('\\')
- s.WriteByte(b)
- case b < ' ' || b > '~':
- writeEscapedByte(s, b)
- default:
- s.WriteByte(b)
- }
-}
-
-func writeEscapedByte(s *strings.Builder, b byte) {
- var buf [3]byte
- bufs := strconv.AppendInt(buf[:0], int64(b), 10)
- s.WriteByte('\\')
- for i := len(bufs); i < 3; i++ {
- s.WriteByte('0')
- }
- s.Write(bufs)
-}
-
-func nextByte(s string, offset int) (byte, int) {
- if offset >= len(s) {
- return 0, 0
- }
- if s[offset] != '\\' {
- // not an escape sequence
- return s[offset], 1
- }
- switch len(s) - offset {
- case 1: // dangling escape
- return 0, 0
- case 2, 3: // too short to be \ddd
- default: // maybe \ddd
- if isDigit(s[offset+1]) && isDigit(s[offset+2]) && isDigit(s[offset+3]) {
- return dddStringToByte(s[offset+1:]), 4
- }
- }
- // not \ddd, just an RFC 1035 "quoted" character
- return s[offset+1], 2
-}
-
-// SPF RR. See RFC 4408, Section 3.1.1.
-type SPF struct {
- Hdr RR_Header
- Txt []string `dns:"txt"`
-}
-
-func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
-
-// AVC RR. See https://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template.
-type AVC struct {
- Hdr RR_Header
- Txt []string `dns:"txt"`
-}
-
-func (rr *AVC) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
-
-// SRV RR. See RFC 2782.
-type SRV struct {
- Hdr RR_Header
- Priority uint16
- Weight uint16
- Port uint16
- Target string `dns:"domain-name"`
-}
-
-func (rr *SRV) String() string {
- return rr.Hdr.String() +
- strconv.Itoa(int(rr.Priority)) + " " +
- strconv.Itoa(int(rr.Weight)) + " " +
- strconv.Itoa(int(rr.Port)) + " " + sprintName(rr.Target)
-}
-
-// NAPTR RR. See RFC 2915.
-type NAPTR struct {
- Hdr RR_Header
- Order uint16
- Preference uint16
- Flags string
- Service string
- Regexp string
- Replacement string `dns:"domain-name"`
-}
-
-func (rr *NAPTR) String() string {
- return rr.Hdr.String() +
- strconv.Itoa(int(rr.Order)) + " " +
- strconv.Itoa(int(rr.Preference)) + " " +
- "\"" + rr.Flags + "\" " +
- "\"" + rr.Service + "\" " +
- "\"" + rr.Regexp + "\" " +
- rr.Replacement
-}
-
-// CERT RR. See RFC 4398.
-type CERT struct {
- Hdr RR_Header
- Type uint16
- KeyTag uint16
- Algorithm uint8
- Certificate string `dns:"base64"`
-}
-
-func (rr *CERT) String() string {
- var (
- ok bool
- certtype, algorithm string
- )
- if certtype, ok = CertTypeToString[rr.Type]; !ok {
- certtype = strconv.Itoa(int(rr.Type))
- }
- if algorithm, ok = AlgorithmToString[rr.Algorithm]; !ok {
- algorithm = strconv.Itoa(int(rr.Algorithm))
- }
- return rr.Hdr.String() + certtype +
- " " + strconv.Itoa(int(rr.KeyTag)) +
- " " + algorithm +
- " " + rr.Certificate
-}
-
-// DNAME RR. See RFC 2672.
-type DNAME struct {
- Hdr RR_Header
- Target string `dns:"domain-name"`
-}
-
-func (rr *DNAME) String() string {
- return rr.Hdr.String() + sprintName(rr.Target)
-}
-
-// A RR. See RFC 1035.
-type A struct {
- Hdr RR_Header
- A net.IP `dns:"a"`
-}
-
-func (rr *A) String() string {
- if rr.A == nil {
- return rr.Hdr.String()
- }
- return rr.Hdr.String() + rr.A.String()
-}
-
-// AAAA RR. See RFC 3596.
-type AAAA struct {
- Hdr RR_Header
- AAAA net.IP `dns:"aaaa"`
-}
-
-func (rr *AAAA) String() string {
- if rr.AAAA == nil {
- return rr.Hdr.String()
- }
- return rr.Hdr.String() + rr.AAAA.String()
-}
-
-// PX RR. See RFC 2163.
-type PX struct {
- Hdr RR_Header
- Preference uint16
- Map822 string `dns:"domain-name"`
- Mapx400 string `dns:"domain-name"`
-}
-
-func (rr *PX) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400)
-}
-
-// GPOS RR. See RFC 1712.
-type GPOS struct {
- Hdr RR_Header
- Longitude string
- Latitude string
- Altitude string
-}
-
-func (rr *GPOS) String() string {
- return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
-}
-
-// LOC RR. See RFC RFC 1876.
-type LOC struct {
- Hdr RR_Header
- Version uint8
- Size uint8
- HorizPre uint8
- VertPre uint8
- Latitude uint32
- Longitude uint32
- Altitude uint32
-}
-
-// cmToM takes a cm value expressed in RFC1876 SIZE mantissa/exponent
-// format and returns a string in m (two decimals for the cm)
-func cmToM(m, e uint8) string {
- if e < 2 {
- if e == 1 {
- m *= 10
- }
-
- return fmt.Sprintf("0.%02d", m)
- }
-
- s := fmt.Sprintf("%d", m)
- for e > 2 {
- s += "0"
- e--
- }
- return s
-}
-
-func (rr *LOC) String() string {
- s := rr.Hdr.String()
-
- lat := rr.Latitude
- ns := "N"
- if lat > LOC_EQUATOR {
- lat = lat - LOC_EQUATOR
- } else {
- ns = "S"
- lat = LOC_EQUATOR - lat
- }
- h := lat / LOC_DEGREES
- lat = lat % LOC_DEGREES
- m := lat / LOC_HOURS
- lat = lat % LOC_HOURS
- s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, float64(lat)/1000, ns)
-
- lon := rr.Longitude
- ew := "E"
- if lon > LOC_PRIMEMERIDIAN {
- lon = lon - LOC_PRIMEMERIDIAN
- } else {
- ew = "W"
- lon = LOC_PRIMEMERIDIAN - lon
- }
- h = lon / LOC_DEGREES
- lon = lon % LOC_DEGREES
- m = lon / LOC_HOURS
- lon = lon % LOC_HOURS
- s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, float64(lon)/1000, ew)
-
- var alt = float64(rr.Altitude) / 100
- alt -= LOC_ALTITUDEBASE
- if rr.Altitude%100 != 0 {
- s += fmt.Sprintf("%.2fm ", alt)
- } else {
- s += fmt.Sprintf("%.0fm ", alt)
- }
-
- s += cmToM(rr.Size&0xf0>>4, rr.Size&0x0f) + "m "
- s += cmToM(rr.HorizPre&0xf0>>4, rr.HorizPre&0x0f) + "m "
- s += cmToM(rr.VertPre&0xf0>>4, rr.VertPre&0x0f) + "m"
-
- return s
-}
-
-// SIG RR. See RFC 2535. The SIG RR is identical to RRSIG and nowadays only used for SIG(0), See RFC 2931.
-type SIG struct {
- RRSIG
-}
-
-// RRSIG RR. See RFC 4034 and RFC 3755.
-type RRSIG struct {
- Hdr RR_Header
- TypeCovered uint16
- Algorithm uint8
- Labels uint8
- OrigTtl uint32
- Expiration uint32
- Inception uint32
- KeyTag uint16
- SignerName string `dns:"domain-name"`
- Signature string `dns:"base64"`
-}
-
-func (rr *RRSIG) String() string {
- s := rr.Hdr.String()
- s += Type(rr.TypeCovered).String()
- s += " " + strconv.Itoa(int(rr.Algorithm)) +
- " " + strconv.Itoa(int(rr.Labels)) +
- " " + strconv.FormatInt(int64(rr.OrigTtl), 10) +
- " " + TimeToString(rr.Expiration) +
- " " + TimeToString(rr.Inception) +
- " " + strconv.Itoa(int(rr.KeyTag)) +
- " " + sprintName(rr.SignerName) +
- " " + rr.Signature
- return s
-}
-
-// NSEC RR. See RFC 4034 and RFC 3755.
-type NSEC struct {
- Hdr RR_Header
- NextDomain string `dns:"domain-name"`
- TypeBitMap []uint16 `dns:"nsec"`
-}
-
-func (rr *NSEC) String() string {
- s := rr.Hdr.String() + sprintName(rr.NextDomain)
- for i := 0; i < len(rr.TypeBitMap); i++ {
- s += " " + Type(rr.TypeBitMap[i]).String()
- }
- return s
-}
-
-func (rr *NSEC) len() int {
- l := rr.Hdr.len() + len(rr.NextDomain) + 1
- lastwindow := uint32(2 ^ 32 + 1)
- for _, t := range rr.TypeBitMap {
- window := t / 256
- if uint32(window) != lastwindow {
- l += 1 + 32
- }
- lastwindow = uint32(window)
- }
- return l
-}
-
-// DLV RR. See RFC 4431.
-type DLV struct{ DS }
-
-// CDS RR. See RFC 7344.
-type CDS struct{ DS }
-
-// DS RR. See RFC 4034 and RFC 3658.
-type DS struct {
- Hdr RR_Header
- KeyTag uint16
- Algorithm uint8
- DigestType uint8
- Digest string `dns:"hex"`
-}
-
-func (rr *DS) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
- " " + strconv.Itoa(int(rr.Algorithm)) +
- " " + strconv.Itoa(int(rr.DigestType)) +
- " " + strings.ToUpper(rr.Digest)
-}
-
-// KX RR. See RFC 2230.
-type KX struct {
- Hdr RR_Header
- Preference uint16
- Exchanger string `dns:"domain-name"`
-}
-
-func (rr *KX) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
- " " + sprintName(rr.Exchanger)
-}
-
-// TA RR. See http://www.watson.org/~weiler/INI1999-19.pdf.
-type TA struct {
- Hdr RR_Header
- KeyTag uint16
- Algorithm uint8
- DigestType uint8
- Digest string `dns:"hex"`
-}
-
-func (rr *TA) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
- " " + strconv.Itoa(int(rr.Algorithm)) +
- " " + strconv.Itoa(int(rr.DigestType)) +
- " " + strings.ToUpper(rr.Digest)
-}
-
-// TALINK RR. See https://www.iana.org/assignments/dns-parameters/TALINK/talink-completed-template.
-type TALINK struct {
- Hdr RR_Header
- PreviousName string `dns:"domain-name"`
- NextName string `dns:"domain-name"`
-}
-
-func (rr *TALINK) String() string {
- return rr.Hdr.String() +
- sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
-}
-
-// SSHFP RR. See RFC RFC 4255.
-type SSHFP struct {
- Hdr RR_Header
- Algorithm uint8
- Type uint8
- FingerPrint string `dns:"hex"`
-}
-
-func (rr *SSHFP) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) +
- " " + strconv.Itoa(int(rr.Type)) +
- " " + strings.ToUpper(rr.FingerPrint)
-}
-
-// KEY RR. See RFC RFC 2535.
-type KEY struct {
- DNSKEY
-}
-
-// CDNSKEY RR. See RFC 7344.
-type CDNSKEY struct {
- DNSKEY
-}
-
-// DNSKEY RR. See RFC 4034 and RFC 3755.
-type DNSKEY struct {
- Hdr RR_Header
- Flags uint16
- Protocol uint8
- Algorithm uint8
- PublicKey string `dns:"base64"`
-}
-
-func (rr *DNSKEY) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
- " " + strconv.Itoa(int(rr.Protocol)) +
- " " + strconv.Itoa(int(rr.Algorithm)) +
- " " + rr.PublicKey
-}
-
-// RKEY RR. See https://www.iana.org/assignments/dns-parameters/RKEY/rkey-completed-template.
-type RKEY struct {
- Hdr RR_Header
- Flags uint16
- Protocol uint8
- Algorithm uint8
- PublicKey string `dns:"base64"`
-}
-
-func (rr *RKEY) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
- " " + strconv.Itoa(int(rr.Protocol)) +
- " " + strconv.Itoa(int(rr.Algorithm)) +
- " " + rr.PublicKey
-}
-
-// NSAPPTR RR. See RFC 1348.
-type NSAPPTR struct {
- Hdr RR_Header
- Ptr string `dns:"domain-name"`
-}
-
-func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) }
-
-// NSEC3 RR. See RFC 5155.
-type NSEC3 struct {
- Hdr RR_Header
- Hash uint8
- Flags uint8
- Iterations uint16
- SaltLength uint8
- Salt string `dns:"size-hex:SaltLength"`
- HashLength uint8
- NextDomain string `dns:"size-base32:HashLength"`
- TypeBitMap []uint16 `dns:"nsec"`
-}
-
-func (rr *NSEC3) String() string {
- s := rr.Hdr.String()
- s += strconv.Itoa(int(rr.Hash)) +
- " " + strconv.Itoa(int(rr.Flags)) +
- " " + strconv.Itoa(int(rr.Iterations)) +
- " " + saltToString(rr.Salt) +
- " " + rr.NextDomain
- for i := 0; i < len(rr.TypeBitMap); i++ {
- s += " " + Type(rr.TypeBitMap[i]).String()
- }
- return s
-}
-
-func (rr *NSEC3) len() int {
- l := rr.Hdr.len() + 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1
- lastwindow := uint32(2 ^ 32 + 1)
- for _, t := range rr.TypeBitMap {
- window := t / 256
- if uint32(window) != lastwindow {
- l += 1 + 32
- }
- lastwindow = uint32(window)
- }
- return l
-}
-
-// NSEC3PARAM RR. See RFC 5155.
-type NSEC3PARAM struct {
- Hdr RR_Header
- Hash uint8
- Flags uint8
- Iterations uint16
- SaltLength uint8
- Salt string `dns:"size-hex:SaltLength"`
-}
-
-func (rr *NSEC3PARAM) String() string {
- s := rr.Hdr.String()
- s += strconv.Itoa(int(rr.Hash)) +
- " " + strconv.Itoa(int(rr.Flags)) +
- " " + strconv.Itoa(int(rr.Iterations)) +
- " " + saltToString(rr.Salt)
- return s
-}
-
-// TKEY RR. See RFC 2930.
-type TKEY struct {
- Hdr RR_Header
- Algorithm string `dns:"domain-name"`
- Inception uint32
- Expiration uint32
- Mode uint16
- Error uint16
- KeySize uint16
- Key string `dns:"size-hex:KeySize"`
- OtherLen uint16
- OtherData string `dns:"size-hex:OtherLen"`
-}
-
-// TKEY has no official presentation format, but this will suffice.
-func (rr *TKEY) String() string {
- s := "\n;; TKEY PSEUDOSECTION:\n"
- s += rr.Hdr.String() + " " + rr.Algorithm + " " +
- strconv.Itoa(int(rr.KeySize)) + " " + rr.Key + " " +
- strconv.Itoa(int(rr.OtherLen)) + " " + rr.OtherData
- return s
-}
-
-// RFC3597 represents an unknown/generic RR. See RFC 3597.
-type RFC3597 struct {
- Hdr RR_Header
- Rdata string `dns:"hex"`
-}
-
-func (rr *RFC3597) String() string {
- // Let's call it a hack
- s := rfc3597Header(rr.Hdr)
-
- s += "\\# " + strconv.Itoa(len(rr.Rdata)/2) + " " + rr.Rdata
- return s
-}
-
-func rfc3597Header(h RR_Header) string {
- var s string
-
- s += sprintName(h.Name) + "\t"
- s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
- s += "CLASS" + strconv.Itoa(int(h.Class)) + "\t"
- s += "TYPE" + strconv.Itoa(int(h.Rrtype)) + "\t"
- return s
-}
-
-// URI RR. See RFC 7553.
-type URI struct {
- Hdr RR_Header
- Priority uint16
- Weight uint16
- Target string `dns:"octet"`
-}
-
-func (rr *URI) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
- " " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
-}
-
-// DHCID RR. See RFC 4701.
-type DHCID struct {
- Hdr RR_Header
- Digest string `dns:"base64"`
-}
-
-func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest }
-
-// TLSA RR. See RFC 6698.
-type TLSA struct {
- Hdr RR_Header
- Usage uint8
- Selector uint8
- MatchingType uint8
- Certificate string `dns:"hex"`
-}
-
-func (rr *TLSA) String() string {
- return rr.Hdr.String() +
- strconv.Itoa(int(rr.Usage)) +
- " " + strconv.Itoa(int(rr.Selector)) +
- " " + strconv.Itoa(int(rr.MatchingType)) +
- " " + rr.Certificate
-}
-
-// SMIMEA RR. See RFC 8162.
-type SMIMEA struct {
- Hdr RR_Header
- Usage uint8
- Selector uint8
- MatchingType uint8
- Certificate string `dns:"hex"`
-}
-
-func (rr *SMIMEA) String() string {
- s := rr.Hdr.String() +
- strconv.Itoa(int(rr.Usage)) +
- " " + strconv.Itoa(int(rr.Selector)) +
- " " + strconv.Itoa(int(rr.MatchingType))
-
- // Every Nth char needs a space on this output. If we output
- // this as one giant line, we can't read it can in because in some cases
- // the cert length overflows scan.maxTok (2048).
- sx := splitN(rr.Certificate, 1024) // conservative value here
- s += " " + strings.Join(sx, " ")
- return s
-}
-
-// HIP RR. See RFC 8005.
-type HIP struct {
- Hdr RR_Header
- HitLength uint8
- PublicKeyAlgorithm uint8
- PublicKeyLength uint16
- Hit string `dns:"size-hex:HitLength"`
- PublicKey string `dns:"size-base64:PublicKeyLength"`
- RendezvousServers []string `dns:"domain-name"`
-}
-
-func (rr *HIP) String() string {
- s := rr.Hdr.String() +
- strconv.Itoa(int(rr.PublicKeyAlgorithm)) +
- " " + rr.Hit +
- " " + rr.PublicKey
- for _, d := range rr.RendezvousServers {
- s += " " + sprintName(d)
- }
- return s
-}
-
-// NINFO RR. See https://www.iana.org/assignments/dns-parameters/NINFO/ninfo-completed-template.
-type NINFO struct {
- Hdr RR_Header
- ZSData []string `dns:"txt"`
-}
-
-func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) }
-
-// NID RR. See RFC RFC 6742.
-type NID struct {
- Hdr RR_Header
- Preference uint16
- NodeID uint64
-}
-
-func (rr *NID) String() string {
- s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
- node := fmt.Sprintf("%0.16x", rr.NodeID)
- s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
- return s
-}
-
-// L32 RR, See RFC 6742.
-type L32 struct {
- Hdr RR_Header
- Preference uint16
- Locator32 net.IP `dns:"a"`
-}
-
-func (rr *L32) String() string {
- if rr.Locator32 == nil {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
- }
- return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
- " " + rr.Locator32.String()
-}
-
-// L64 RR, See RFC 6742.
-type L64 struct {
- Hdr RR_Header
- Preference uint16
- Locator64 uint64
-}
-
-func (rr *L64) String() string {
- s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
- node := fmt.Sprintf("%0.16X", rr.Locator64)
- s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
- return s
-}
-
-// LP RR. See RFC 6742.
-type LP struct {
- Hdr RR_Header
- Preference uint16
- Fqdn string `dns:"domain-name"`
-}
-
-func (rr *LP) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
-}
-
-// EUI48 RR. See RFC 7043.
-type EUI48 struct {
- Hdr RR_Header
- Address uint64 `dns:"uint48"`
-}
-
-func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) }
-
-// EUI64 RR. See RFC 7043.
-type EUI64 struct {
- Hdr RR_Header
- Address uint64
-}
-
-func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) }
-
-// CAA RR. See RFC 6844.
-type CAA struct {
- Hdr RR_Header
- Flag uint8
- Tag string
- Value string `dns:"octet"`
-}
-
-func (rr *CAA) String() string {
- return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
-}
-
-// UID RR. Deprecated, IANA-Reserved.
-type UID struct {
- Hdr RR_Header
- Uid uint32
-}
-
-func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) }
-
-// GID RR. Deprecated, IANA-Reserved.
-type GID struct {
- Hdr RR_Header
- Gid uint32
-}
-
-func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) }
-
-// UINFO RR. Deprecated, IANA-Reserved.
-type UINFO struct {
- Hdr RR_Header
- Uinfo string
-}
-
-func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
-
-// EID RR. See http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt.
-type EID struct {
- Hdr RR_Header
- Endpoint string `dns:"hex"`
-}
-
-func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) }
-
-// NIMLOC RR. See http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt.
-type NIMLOC struct {
- Hdr RR_Header
- Locator string `dns:"hex"`
-}
-
-func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) }
-
-// OPENPGPKEY RR. See RFC 7929.
-type OPENPGPKEY struct {
- Hdr RR_Header
- PublicKey string `dns:"base64"`
-}
-
-func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey }
-
-// CSYNC RR. See RFC 7477.
-type CSYNC struct {
- Hdr RR_Header
- Serial uint32
- Flags uint16
- TypeBitMap []uint16 `dns:"nsec"`
-}
-
-func (rr *CSYNC) String() string {
- s := rr.Hdr.String() + strconv.FormatInt(int64(rr.Serial), 10) + " " + strconv.Itoa(int(rr.Flags))
-
- for i := 0; i < len(rr.TypeBitMap); i++ {
- s += " " + Type(rr.TypeBitMap[i]).String()
- }
- return s
-}
-
-func (rr *CSYNC) len() int {
- l := rr.Hdr.len() + 4 + 2
- lastwindow := uint32(2 ^ 32 + 1)
- for _, t := range rr.TypeBitMap {
- window := t / 256
- if uint32(window) != lastwindow {
- l += 1 + 32
- }
- lastwindow = uint32(window)
- }
- return l
-}
-
-// TimeToString translates the RRSIG's incep. and expir. times to the
-// string representation used when printing the record.
-// It takes serial arithmetic (RFC 1982) into account.
-func TimeToString(t uint32) string {
- mod := (int64(t)-time.Now().Unix())/year68 - 1
- if mod < 0 {
- mod = 0
- }
- ti := time.Unix(int64(t)-mod*year68, 0).UTC()
- return ti.Format("20060102150405")
-}
-
-// StringToTime translates the RRSIG's incep. and expir. times from
-// string values like "20110403154150" to an 32 bit integer.
-// It takes serial arithmetic (RFC 1982) into account.
-func StringToTime(s string) (uint32, error) {
- t, err := time.Parse("20060102150405", s)
- if err != nil {
- return 0, err
- }
- mod := t.Unix()/year68 - 1
- if mod < 0 {
- mod = 0
- }
- return uint32(t.Unix() - mod*year68), nil
-}
-
-// saltToString converts a NSECX salt to uppercase and returns "-" when it is empty.
-func saltToString(s string) string {
- if len(s) == 0 {
- return "-"
- }
- return strings.ToUpper(s)
-}
-
-func euiToString(eui uint64, bits int) (hex string) {
- switch bits {
- case 64:
- hex = fmt.Sprintf("%16.16x", eui)
- hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
- "-" + hex[8:10] + "-" + hex[10:12] + "-" + hex[12:14] + "-" + hex[14:16]
- case 48:
- hex = fmt.Sprintf("%12.12x", eui)
- hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
- "-" + hex[8:10] + "-" + hex[10:12]
- }
- return
-}
-
-// copyIP returns a copy of ip.
-func copyIP(ip net.IP) net.IP {
- p := make(net.IP, len(ip))
- copy(p, ip)
- return p
-}
-
-// SplitN splits a string into N sized string chunks.
-// This might become an exported function once.
-func splitN(s string, n int) []string {
- if len(s) < n {
- return []string{s}
- }
- sx := []string{}
- p, i := 0, n
- for {
- if i <= len(s) {
- sx = append(sx, s[p:i])
- } else {
- sx = append(sx, s[p:])
- break
-
- }
- p, i = p+n, i+n
- }
-
- return sx
-}
diff --git a/vendor/github.com/miekg/dns/udp.go b/vendor/github.com/miekg/dns/udp.go
deleted file mode 100644
index a4826ee2ffd..00000000000
--- a/vendor/github.com/miekg/dns/udp.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// +build !windows
-
-package dns
-
-import (
- "net"
-
- "golang.org/x/net/ipv4"
- "golang.org/x/net/ipv6"
-)
-
-// This is the required size of the OOB buffer to pass to ReadMsgUDP.
-var udpOOBSize = func() int {
- // We can't know whether we'll get an IPv4 control message or an
- // IPv6 control message ahead of time. To get around this, we size
- // the buffer equal to the largest of the two.
-
- oob4 := ipv4.NewControlMessage(ipv4.FlagDst | ipv4.FlagInterface)
- oob6 := ipv6.NewControlMessage(ipv6.FlagDst | ipv6.FlagInterface)
-
- if len(oob4) > len(oob6) {
- return len(oob4)
- }
-
- return len(oob6)
-}()
-
-// SessionUDP holds the remote address and the associated
-// out-of-band data.
-type SessionUDP struct {
- raddr *net.UDPAddr
- context []byte
-}
-
-// RemoteAddr returns the remote network address.
-func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
-
-// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
-// net.UDPAddr.
-func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
- oob := make([]byte, udpOOBSize)
- n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
- if err != nil {
- return n, nil, err
- }
- return n, &SessionUDP{raddr, oob[:oobn]}, err
-}
-
-// WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr.
-func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
- oob := correctSource(session.context)
- n, _, err := conn.WriteMsgUDP(b, oob, session.raddr)
- return n, err
-}
-
-func setUDPSocketOptions(conn *net.UDPConn) error {
- // Try setting the flags for both families and ignore the errors unless they
- // both error.
- err6 := ipv6.NewPacketConn(conn).SetControlMessage(ipv6.FlagDst|ipv6.FlagInterface, true)
- err4 := ipv4.NewPacketConn(conn).SetControlMessage(ipv4.FlagDst|ipv4.FlagInterface, true)
- if err6 != nil && err4 != nil {
- return err4
- }
- return nil
-}
-
-// parseDstFromOOB takes oob data and returns the destination IP.
-func parseDstFromOOB(oob []byte) net.IP {
- // Start with IPv6 and then fallback to IPv4
- // TODO(fastest963): Figure out a way to prefer one or the other. Looking at
- // the lvl of the header for a 0 or 41 isn't cross-platform.
- cm6 := new(ipv6.ControlMessage)
- if cm6.Parse(oob) == nil && cm6.Dst != nil {
- return cm6.Dst
- }
- cm4 := new(ipv4.ControlMessage)
- if cm4.Parse(oob) == nil && cm4.Dst != nil {
- return cm4.Dst
- }
- return nil
-}
-
-// correctSource takes oob data and returns new oob data with the Src equal to the Dst
-func correctSource(oob []byte) []byte {
- dst := parseDstFromOOB(oob)
- if dst == nil {
- return nil
- }
- // If the dst is definitely an IPv6, then use ipv6's ControlMessage to
- // respond otherwise use ipv4's because ipv6's marshal ignores ipv4
- // addresses.
- if dst.To4() == nil {
- cm := new(ipv6.ControlMessage)
- cm.Src = dst
- oob = cm.Marshal()
- } else {
- cm := new(ipv4.ControlMessage)
- cm.Src = dst
- oob = cm.Marshal()
- }
- return oob
-}
diff --git a/vendor/github.com/miekg/dns/udp_windows.go b/vendor/github.com/miekg/dns/udp_windows.go
deleted file mode 100644
index 6778c3c6cfe..00000000000
--- a/vendor/github.com/miekg/dns/udp_windows.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// +build windows
-
-package dns
-
-import "net"
-
-// SessionUDP holds the remote address
-type SessionUDP struct {
- raddr *net.UDPAddr
-}
-
-// RemoteAddr returns the remote network address.
-func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
-
-// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
-// net.UDPAddr.
-// TODO(fastest963): Once go1.10 is released, use ReadMsgUDP.
-func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
- n, raddr, err := conn.ReadFrom(b)
- if err != nil {
- return n, nil, err
- }
- session := &SessionUDP{raddr.(*net.UDPAddr)}
- return n, session, err
-}
-
-// WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr.
-// TODO(fastest963): Once go1.10 is released, use WriteMsgUDP.
-func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
- n, err := conn.WriteTo(b, session.raddr)
- return n, err
-}
-
-// TODO(fastest963): Once go1.10 is released and we can use *MsgUDP methods
-// use the standard method in udp.go for these.
-func setUDPSocketOptions(*net.UDPConn) error { return nil }
-func parseDstFromOOB([]byte, net.IP) net.IP { return nil }
diff --git a/vendor/github.com/miekg/dns/update.go b/vendor/github.com/miekg/dns/update.go
deleted file mode 100644
index e90c5c968ec..00000000000
--- a/vendor/github.com/miekg/dns/update.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package dns
-
-// NameUsed sets the RRs in the prereq section to
-// "Name is in use" RRs. RFC 2136 section 2.4.4.
-func (u *Msg) NameUsed(rr []RR) {
- if u.Answer == nil {
- u.Answer = make([]RR, 0, len(rr))
- }
- for _, r := range rr {
- u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
- }
-}
-
-// NameNotUsed sets the RRs in the prereq section to
-// "Name is in not use" RRs. RFC 2136 section 2.4.5.
-func (u *Msg) NameNotUsed(rr []RR) {
- if u.Answer == nil {
- u.Answer = make([]RR, 0, len(rr))
- }
- for _, r := range rr {
- u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}})
- }
-}
-
-// Used sets the RRs in the prereq section to
-// "RRset exists (value dependent -- with rdata)" RRs. RFC 2136 section 2.4.2.
-func (u *Msg) Used(rr []RR) {
- if len(u.Question) == 0 {
- panic("dns: empty question section")
- }
- if u.Answer == nil {
- u.Answer = make([]RR, 0, len(rr))
- }
- for _, r := range rr {
- r.Header().Class = u.Question[0].Qclass
- u.Answer = append(u.Answer, r)
- }
-}
-
-// RRsetUsed sets the RRs in the prereq section to
-// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
-func (u *Msg) RRsetUsed(rr []RR) {
- if u.Answer == nil {
- u.Answer = make([]RR, 0, len(rr))
- }
- for _, r := range rr {
- u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
- }
-}
-
-// RRsetNotUsed sets the RRs in the prereq section to
-// "RRset does not exist" RRs. RFC 2136 section 2.4.3.
-func (u *Msg) RRsetNotUsed(rr []RR) {
- if u.Answer == nil {
- u.Answer = make([]RR, 0, len(rr))
- }
- for _, r := range rr {
- u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}})
- }
-}
-
-// Insert creates a dynamic update packet that adds an complete RRset, see RFC 2136 section 2.5.1.
-func (u *Msg) Insert(rr []RR) {
- if len(u.Question) == 0 {
- panic("dns: empty question section")
- }
- if u.Ns == nil {
- u.Ns = make([]RR, 0, len(rr))
- }
- for _, r := range rr {
- r.Header().Class = u.Question[0].Qclass
- u.Ns = append(u.Ns, r)
- }
-}
-
-// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
-func (u *Msg) RemoveRRset(rr []RR) {
- if u.Ns == nil {
- u.Ns = make([]RR, 0, len(rr))
- }
- for _, r := range rr {
- u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
- }
-}
-
-// RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3
-func (u *Msg) RemoveName(rr []RR) {
- if u.Ns == nil {
- u.Ns = make([]RR, 0, len(rr))
- }
- for _, r := range rr {
- u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}})
- }
-}
-
-// Remove creates a dynamic update packet deletes RR from a RRSset, see RFC 2136 section 2.5.4
-func (u *Msg) Remove(rr []RR) {
- if u.Ns == nil {
- u.Ns = make([]RR, 0, len(rr))
- }
- for _, r := range rr {
- r.Header().Class = ClassNONE
- r.Header().Ttl = 0
- u.Ns = append(u.Ns, r)
- }
-}
diff --git a/vendor/github.com/miekg/dns/version.go b/vendor/github.com/miekg/dns/version.go
deleted file mode 100644
index 0b0e9b6d831..00000000000
--- a/vendor/github.com/miekg/dns/version.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package dns
-
-import "fmt"
-
-// Version is current version of this library.
-var Version = V{1, 0, 14}
-
-// V holds the version of this library.
-type V struct {
- Major, Minor, Patch int
-}
-
-func (v V) String() string {
- return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
-}
diff --git a/vendor/github.com/miekg/dns/xfr.go b/vendor/github.com/miekg/dns/xfr.go
deleted file mode 100644
index 5d0ff5c8a27..00000000000
--- a/vendor/github.com/miekg/dns/xfr.go
+++ /dev/null
@@ -1,260 +0,0 @@
-package dns
-
-import (
- "fmt"
- "time"
-)
-
-// Envelope is used when doing a zone transfer with a remote server.
-type Envelope struct {
- RR []RR // The set of RRs in the answer section of the xfr reply message.
- Error error // If something went wrong, this contains the error.
-}
-
-// A Transfer defines parameters that are used during a zone transfer.
-type Transfer struct {
- *Conn
- DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
- ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
- WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
- TsigSecret map[string]string // Secret(s) for Tsig map[], zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
- tsigTimersOnly bool
-}
-
-// Think we need to away to stop the transfer
-
-// In performs an incoming transfer with the server in a.
-// If you would like to set the source IP, or some other attribute
-// of a Dialer for a Transfer, you can do so by specifying the attributes
-// in the Transfer.Conn:
-//
-// d := net.Dialer{LocalAddr: transfer_source}
-// con, err := d.Dial("tcp", master)
-// dnscon := &dns.Conn{Conn:con}
-// transfer = &dns.Transfer{Conn: dnscon}
-// channel, err := transfer.In(message, master)
-//
-func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
- timeout := dnsTimeout
- if t.DialTimeout != 0 {
- timeout = t.DialTimeout
- }
- if t.Conn == nil {
- t.Conn, err = DialTimeout("tcp", a, timeout)
- if err != nil {
- return nil, err
- }
- }
- if err := t.WriteMsg(q); err != nil {
- return nil, err
- }
- env = make(chan *Envelope)
- go func() {
- if q.Question[0].Qtype == TypeAXFR {
- go t.inAxfr(q, env)
- return
- }
- if q.Question[0].Qtype == TypeIXFR {
- go t.inIxfr(q, env)
- return
- }
- }()
- return env, nil
-}
-
-func (t *Transfer) inAxfr(q *Msg, c chan *Envelope) {
- first := true
- defer t.Close()
- defer close(c)
- timeout := dnsTimeout
- if t.ReadTimeout != 0 {
- timeout = t.ReadTimeout
- }
- for {
- t.Conn.SetReadDeadline(time.Now().Add(timeout))
- in, err := t.ReadMsg()
- if err != nil {
- c <- &Envelope{nil, err}
- return
- }
- if q.Id != in.Id {
- c <- &Envelope{in.Answer, ErrId}
- return
- }
- if first {
- if in.Rcode != RcodeSuccess {
- c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
- return
- }
- if !isSOAFirst(in) {
- c <- &Envelope{in.Answer, ErrSoa}
- return
- }
- first = !first
- // only one answer that is SOA, receive more
- if len(in.Answer) == 1 {
- t.tsigTimersOnly = true
- c <- &Envelope{in.Answer, nil}
- continue
- }
- }
-
- if !first {
- t.tsigTimersOnly = true // Subsequent envelopes use this.
- if isSOALast(in) {
- c <- &Envelope{in.Answer, nil}
- return
- }
- c <- &Envelope{in.Answer, nil}
- }
- }
-}
-
-func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) {
- serial := uint32(0) // The first serial seen is the current server serial
- axfr := true
- n := 0
- qser := q.Ns[0].(*SOA).Serial
- defer t.Close()
- defer close(c)
- timeout := dnsTimeout
- if t.ReadTimeout != 0 {
- timeout = t.ReadTimeout
- }
- for {
- t.SetReadDeadline(time.Now().Add(timeout))
- in, err := t.ReadMsg()
- if err != nil {
- c <- &Envelope{nil, err}
- return
- }
- if q.Id != in.Id {
- c <- &Envelope{in.Answer, ErrId}
- return
- }
- if in.Rcode != RcodeSuccess {
- c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
- return
- }
- if n == 0 {
- // Check if the returned answer is ok
- if !isSOAFirst(in) {
- c <- &Envelope{in.Answer, ErrSoa}
- return
- }
- // This serial is important
- serial = in.Answer[0].(*SOA).Serial
- // Check if there are no changes in zone
- if qser >= serial {
- c <- &Envelope{in.Answer, nil}
- return
- }
- }
- // Now we need to check each message for SOA records, to see what we need to do
- t.tsigTimersOnly = true
- for _, rr := range in.Answer {
- if v, ok := rr.(*SOA); ok {
- if v.Serial == serial {
- n++
- // quit if it's a full axfr or the the servers' SOA is repeated the third time
- if axfr && n == 2 || n == 3 {
- c <- &Envelope{in.Answer, nil}
- return
- }
- } else if axfr {
- // it's an ixfr
- axfr = false
- }
- }
- }
- c <- &Envelope{in.Answer, nil}
- }
-}
-
-// Out performs an outgoing transfer with the client connecting in w.
-// Basic use pattern:
-//
-// ch := make(chan *dns.Envelope)
-// tr := new(dns.Transfer)
-// go tr.Out(w, r, ch)
-// ch <- &dns.Envelope{RR: []dns.RR{soa, rr1, rr2, rr3, soa}}
-// close(ch)
-// w.Hijack()
-// // w.Close() // Client closes connection
-//
-// The server is responsible for sending the correct sequence of RRs through the
-// channel ch.
-func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
- for x := range ch {
- r := new(Msg)
- // Compress?
- r.SetReply(q)
- r.Authoritative = true
- // assume it fits TODO(miek): fix
- r.Answer = append(r.Answer, x.RR...)
- if err := w.WriteMsg(r); err != nil {
- return err
- }
- }
- w.TsigTimersOnly(true)
- return nil
-}
-
-// ReadMsg reads a message from the transfer connection t.
-func (t *Transfer) ReadMsg() (*Msg, error) {
- m := new(Msg)
- p := make([]byte, MaxMsgSize)
- n, err := t.Read(p)
- if err != nil && n == 0 {
- return nil, err
- }
- p = p[:n]
- if err := m.Unpack(p); err != nil {
- return nil, err
- }
- if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
- if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
- return m, ErrSecret
- }
- // Need to work on the original message p, as that was used to calculate the tsig.
- err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
- t.tsigRequestMAC = ts.MAC
- }
- return m, err
-}
-
-// WriteMsg writes a message through the transfer connection t.
-func (t *Transfer) WriteMsg(m *Msg) (err error) {
- var out []byte
- if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
- if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
- return ErrSecret
- }
- out, t.tsigRequestMAC, err = TsigGenerate(m, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
- } else {
- out, err = m.Pack()
- }
- if err != nil {
- return err
- }
- if _, err = t.Write(out); err != nil {
- return err
- }
- return nil
-}
-
-func isSOAFirst(in *Msg) bool {
- if len(in.Answer) > 0 {
- return in.Answer[0].Header().Rrtype == TypeSOA
- }
- return false
-}
-
-func isSOALast(in *Msg) bool {
- if len(in.Answer) > 0 {
- return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
- }
- return false
-}
-
-const errXFR = "bad xfr rcode: %d"
diff --git a/vendor/github.com/miekg/dns/zcompress.go b/vendor/github.com/miekg/dns/zcompress.go
deleted file mode 100644
index 6391a3501fc..00000000000
--- a/vendor/github.com/miekg/dns/zcompress.go
+++ /dev/null
@@ -1,152 +0,0 @@
-// Code generated by "go run compress_generate.go"; DO NOT EDIT.
-
-package dns
-
-func compressionLenHelperType(c map[string]int, r RR, initLen int) int {
- currentLen := initLen
- switch x := r.(type) {
- case *AFSDB:
- currentLen -= len(x.Hostname) + 1
- currentLen += compressionLenHelper(c, x.Hostname, currentLen)
- case *CNAME:
- currentLen -= len(x.Target) + 1
- currentLen += compressionLenHelper(c, x.Target, currentLen)
- case *DNAME:
- currentLen -= len(x.Target) + 1
- currentLen += compressionLenHelper(c, x.Target, currentLen)
- case *HIP:
- for i := range x.RendezvousServers {
- currentLen -= len(x.RendezvousServers[i]) + 1
- }
- for i := range x.RendezvousServers {
- currentLen += compressionLenHelper(c, x.RendezvousServers[i], currentLen)
- }
- case *KX:
- currentLen -= len(x.Exchanger) + 1
- currentLen += compressionLenHelper(c, x.Exchanger, currentLen)
- case *LP:
- currentLen -= len(x.Fqdn) + 1
- currentLen += compressionLenHelper(c, x.Fqdn, currentLen)
- case *MB:
- currentLen -= len(x.Mb) + 1
- currentLen += compressionLenHelper(c, x.Mb, currentLen)
- case *MD:
- currentLen -= len(x.Md) + 1
- currentLen += compressionLenHelper(c, x.Md, currentLen)
- case *MF:
- currentLen -= len(x.Mf) + 1
- currentLen += compressionLenHelper(c, x.Mf, currentLen)
- case *MG:
- currentLen -= len(x.Mg) + 1
- currentLen += compressionLenHelper(c, x.Mg, currentLen)
- case *MINFO:
- currentLen -= len(x.Rmail) + 1
- currentLen += compressionLenHelper(c, x.Rmail, currentLen)
- currentLen -= len(x.Email) + 1
- currentLen += compressionLenHelper(c, x.Email, currentLen)
- case *MR:
- currentLen -= len(x.Mr) + 1
- currentLen += compressionLenHelper(c, x.Mr, currentLen)
- case *MX:
- currentLen -= len(x.Mx) + 1
- currentLen += compressionLenHelper(c, x.Mx, currentLen)
- case *NAPTR:
- currentLen -= len(x.Replacement) + 1
- currentLen += compressionLenHelper(c, x.Replacement, currentLen)
- case *NS:
- currentLen -= len(x.Ns) + 1
- currentLen += compressionLenHelper(c, x.Ns, currentLen)
- case *NSAPPTR:
- currentLen -= len(x.Ptr) + 1
- currentLen += compressionLenHelper(c, x.Ptr, currentLen)
- case *NSEC:
- currentLen -= len(x.NextDomain) + 1
- currentLen += compressionLenHelper(c, x.NextDomain, currentLen)
- case *PTR:
- currentLen -= len(x.Ptr) + 1
- currentLen += compressionLenHelper(c, x.Ptr, currentLen)
- case *PX:
- currentLen -= len(x.Map822) + 1
- currentLen += compressionLenHelper(c, x.Map822, currentLen)
- currentLen -= len(x.Mapx400) + 1
- currentLen += compressionLenHelper(c, x.Mapx400, currentLen)
- case *RP:
- currentLen -= len(x.Mbox) + 1
- currentLen += compressionLenHelper(c, x.Mbox, currentLen)
- currentLen -= len(x.Txt) + 1
- currentLen += compressionLenHelper(c, x.Txt, currentLen)
- case *RRSIG:
- currentLen -= len(x.SignerName) + 1
- currentLen += compressionLenHelper(c, x.SignerName, currentLen)
- case *RT:
- currentLen -= len(x.Host) + 1
- currentLen += compressionLenHelper(c, x.Host, currentLen)
- case *SIG:
- currentLen -= len(x.SignerName) + 1
- currentLen += compressionLenHelper(c, x.SignerName, currentLen)
- case *SOA:
- currentLen -= len(x.Ns) + 1
- currentLen += compressionLenHelper(c, x.Ns, currentLen)
- currentLen -= len(x.Mbox) + 1
- currentLen += compressionLenHelper(c, x.Mbox, currentLen)
- case *SRV:
- currentLen -= len(x.Target) + 1
- currentLen += compressionLenHelper(c, x.Target, currentLen)
- case *TALINK:
- currentLen -= len(x.PreviousName) + 1
- currentLen += compressionLenHelper(c, x.PreviousName, currentLen)
- currentLen -= len(x.NextName) + 1
- currentLen += compressionLenHelper(c, x.NextName, currentLen)
- case *TKEY:
- currentLen -= len(x.Algorithm) + 1
- currentLen += compressionLenHelper(c, x.Algorithm, currentLen)
- case *TSIG:
- currentLen -= len(x.Algorithm) + 1
- currentLen += compressionLenHelper(c, x.Algorithm, currentLen)
- }
- return currentLen - initLen
-}
-
-func compressionLenSearchType(c map[string]int, r RR) (int, bool, int) {
- switch x := r.(type) {
- case *CNAME:
- k1, ok1, sz1 := compressionLenSearch(c, x.Target)
- return k1, ok1, sz1
- case *MB:
- k1, ok1, sz1 := compressionLenSearch(c, x.Mb)
- return k1, ok1, sz1
- case *MD:
- k1, ok1, sz1 := compressionLenSearch(c, x.Md)
- return k1, ok1, sz1
- case *MF:
- k1, ok1, sz1 := compressionLenSearch(c, x.Mf)
- return k1, ok1, sz1
- case *MG:
- k1, ok1, sz1 := compressionLenSearch(c, x.Mg)
- return k1, ok1, sz1
- case *MINFO:
- k1, ok1, sz1 := compressionLenSearch(c, x.Rmail)
- k2, ok2, sz2 := compressionLenSearch(c, x.Email)
- return k1 + k2, ok1 && ok2, sz1 + sz2
- case *MR:
- k1, ok1, sz1 := compressionLenSearch(c, x.Mr)
- return k1, ok1, sz1
- case *MX:
- k1, ok1, sz1 := compressionLenSearch(c, x.Mx)
- return k1, ok1, sz1
- case *NS:
- k1, ok1, sz1 := compressionLenSearch(c, x.Ns)
- return k1, ok1, sz1
- case *PTR:
- k1, ok1, sz1 := compressionLenSearch(c, x.Ptr)
- return k1, ok1, sz1
- case *RT:
- k1, ok1, sz1 := compressionLenSearch(c, x.Host)
- return k1, ok1, sz1
- case *SOA:
- k1, ok1, sz1 := compressionLenSearch(c, x.Ns)
- k2, ok2, sz2 := compressionLenSearch(c, x.Mbox)
- return k1 + k2, ok1 && ok2, sz1 + sz2
- }
- return 0, false, 0
-}
diff --git a/vendor/github.com/miekg/dns/zduplicate.go b/vendor/github.com/miekg/dns/zduplicate.go
deleted file mode 100644
index ba9863b233f..00000000000
--- a/vendor/github.com/miekg/dns/zduplicate.go
+++ /dev/null
@@ -1,943 +0,0 @@
-// Code generated by "go run duplicate_generate.go"; DO NOT EDIT.
-
-package dns
-
-// isDuplicateRdata calls the rdata specific functions
-func isDuplicateRdata(r1, r2 RR) bool {
- switch r1.Header().Rrtype {
- case TypeA:
- return isDuplicateA(r1.(*A), r2.(*A))
- case TypeAAAA:
- return isDuplicateAAAA(r1.(*AAAA), r2.(*AAAA))
- case TypeAFSDB:
- return isDuplicateAFSDB(r1.(*AFSDB), r2.(*AFSDB))
- case TypeAVC:
- return isDuplicateAVC(r1.(*AVC), r2.(*AVC))
- case TypeCAA:
- return isDuplicateCAA(r1.(*CAA), r2.(*CAA))
- case TypeCERT:
- return isDuplicateCERT(r1.(*CERT), r2.(*CERT))
- case TypeCNAME:
- return isDuplicateCNAME(r1.(*CNAME), r2.(*CNAME))
- case TypeCSYNC:
- return isDuplicateCSYNC(r1.(*CSYNC), r2.(*CSYNC))
- case TypeDHCID:
- return isDuplicateDHCID(r1.(*DHCID), r2.(*DHCID))
- case TypeDNAME:
- return isDuplicateDNAME(r1.(*DNAME), r2.(*DNAME))
- case TypeDNSKEY:
- return isDuplicateDNSKEY(r1.(*DNSKEY), r2.(*DNSKEY))
- case TypeDS:
- return isDuplicateDS(r1.(*DS), r2.(*DS))
- case TypeEID:
- return isDuplicateEID(r1.(*EID), r2.(*EID))
- case TypeEUI48:
- return isDuplicateEUI48(r1.(*EUI48), r2.(*EUI48))
- case TypeEUI64:
- return isDuplicateEUI64(r1.(*EUI64), r2.(*EUI64))
- case TypeGID:
- return isDuplicateGID(r1.(*GID), r2.(*GID))
- case TypeGPOS:
- return isDuplicateGPOS(r1.(*GPOS), r2.(*GPOS))
- case TypeHINFO:
- return isDuplicateHINFO(r1.(*HINFO), r2.(*HINFO))
- case TypeHIP:
- return isDuplicateHIP(r1.(*HIP), r2.(*HIP))
- case TypeKX:
- return isDuplicateKX(r1.(*KX), r2.(*KX))
- case TypeL32:
- return isDuplicateL32(r1.(*L32), r2.(*L32))
- case TypeL64:
- return isDuplicateL64(r1.(*L64), r2.(*L64))
- case TypeLOC:
- return isDuplicateLOC(r1.(*LOC), r2.(*LOC))
- case TypeLP:
- return isDuplicateLP(r1.(*LP), r2.(*LP))
- case TypeMB:
- return isDuplicateMB(r1.(*MB), r2.(*MB))
- case TypeMD:
- return isDuplicateMD(r1.(*MD), r2.(*MD))
- case TypeMF:
- return isDuplicateMF(r1.(*MF), r2.(*MF))
- case TypeMG:
- return isDuplicateMG(r1.(*MG), r2.(*MG))
- case TypeMINFO:
- return isDuplicateMINFO(r1.(*MINFO), r2.(*MINFO))
- case TypeMR:
- return isDuplicateMR(r1.(*MR), r2.(*MR))
- case TypeMX:
- return isDuplicateMX(r1.(*MX), r2.(*MX))
- case TypeNAPTR:
- return isDuplicateNAPTR(r1.(*NAPTR), r2.(*NAPTR))
- case TypeNID:
- return isDuplicateNID(r1.(*NID), r2.(*NID))
- case TypeNIMLOC:
- return isDuplicateNIMLOC(r1.(*NIMLOC), r2.(*NIMLOC))
- case TypeNINFO:
- return isDuplicateNINFO(r1.(*NINFO), r2.(*NINFO))
- case TypeNS:
- return isDuplicateNS(r1.(*NS), r2.(*NS))
- case TypeNSAPPTR:
- return isDuplicateNSAPPTR(r1.(*NSAPPTR), r2.(*NSAPPTR))
- case TypeNSEC:
- return isDuplicateNSEC(r1.(*NSEC), r2.(*NSEC))
- case TypeNSEC3:
- return isDuplicateNSEC3(r1.(*NSEC3), r2.(*NSEC3))
- case TypeNSEC3PARAM:
- return isDuplicateNSEC3PARAM(r1.(*NSEC3PARAM), r2.(*NSEC3PARAM))
- case TypeOPENPGPKEY:
- return isDuplicateOPENPGPKEY(r1.(*OPENPGPKEY), r2.(*OPENPGPKEY))
- case TypePTR:
- return isDuplicatePTR(r1.(*PTR), r2.(*PTR))
- case TypePX:
- return isDuplicatePX(r1.(*PX), r2.(*PX))
- case TypeRKEY:
- return isDuplicateRKEY(r1.(*RKEY), r2.(*RKEY))
- case TypeRP:
- return isDuplicateRP(r1.(*RP), r2.(*RP))
- case TypeRRSIG:
- return isDuplicateRRSIG(r1.(*RRSIG), r2.(*RRSIG))
- case TypeRT:
- return isDuplicateRT(r1.(*RT), r2.(*RT))
- case TypeSMIMEA:
- return isDuplicateSMIMEA(r1.(*SMIMEA), r2.(*SMIMEA))
- case TypeSOA:
- return isDuplicateSOA(r1.(*SOA), r2.(*SOA))
- case TypeSPF:
- return isDuplicateSPF(r1.(*SPF), r2.(*SPF))
- case TypeSRV:
- return isDuplicateSRV(r1.(*SRV), r2.(*SRV))
- case TypeSSHFP:
- return isDuplicateSSHFP(r1.(*SSHFP), r2.(*SSHFP))
- case TypeTA:
- return isDuplicateTA(r1.(*TA), r2.(*TA))
- case TypeTALINK:
- return isDuplicateTALINK(r1.(*TALINK), r2.(*TALINK))
- case TypeTKEY:
- return isDuplicateTKEY(r1.(*TKEY), r2.(*TKEY))
- case TypeTLSA:
- return isDuplicateTLSA(r1.(*TLSA), r2.(*TLSA))
- case TypeTSIG:
- return isDuplicateTSIG(r1.(*TSIG), r2.(*TSIG))
- case TypeTXT:
- return isDuplicateTXT(r1.(*TXT), r2.(*TXT))
- case TypeUID:
- return isDuplicateUID(r1.(*UID), r2.(*UID))
- case TypeUINFO:
- return isDuplicateUINFO(r1.(*UINFO), r2.(*UINFO))
- case TypeURI:
- return isDuplicateURI(r1.(*URI), r2.(*URI))
- case TypeX25:
- return isDuplicateX25(r1.(*X25), r2.(*X25))
- }
- return false
-}
-
-// isDuplicate() functions
-
-func isDuplicateA(r1, r2 *A) bool {
- if len(r1.A) != len(r2.A) {
- return false
- }
- for i := 0; i < len(r1.A); i++ {
- if r1.A[i] != r2.A[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateAAAA(r1, r2 *AAAA) bool {
- if len(r1.AAAA) != len(r2.AAAA) {
- return false
- }
- for i := 0; i < len(r1.AAAA); i++ {
- if r1.AAAA[i] != r2.AAAA[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateAFSDB(r1, r2 *AFSDB) bool {
- if r1.Subtype != r2.Subtype {
- return false
- }
- if !isDulicateName(r1.Hostname, r2.Hostname) {
- return false
- }
- return true
-}
-
-func isDuplicateAVC(r1, r2 *AVC) bool {
- if len(r1.Txt) != len(r2.Txt) {
- return false
- }
- for i := 0; i < len(r1.Txt); i++ {
- if r1.Txt[i] != r2.Txt[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateCAA(r1, r2 *CAA) bool {
- if r1.Flag != r2.Flag {
- return false
- }
- if r1.Tag != r2.Tag {
- return false
- }
- if r1.Value != r2.Value {
- return false
- }
- return true
-}
-
-func isDuplicateCERT(r1, r2 *CERT) bool {
- if r1.Type != r2.Type {
- return false
- }
- if r1.KeyTag != r2.KeyTag {
- return false
- }
- if r1.Algorithm != r2.Algorithm {
- return false
- }
- if r1.Certificate != r2.Certificate {
- return false
- }
- return true
-}
-
-func isDuplicateCNAME(r1, r2 *CNAME) bool {
- if !isDulicateName(r1.Target, r2.Target) {
- return false
- }
- return true
-}
-
-func isDuplicateCSYNC(r1, r2 *CSYNC) bool {
- if r1.Serial != r2.Serial {
- return false
- }
- if r1.Flags != r2.Flags {
- return false
- }
- if len(r1.TypeBitMap) != len(r2.TypeBitMap) {
- return false
- }
- for i := 0; i < len(r1.TypeBitMap); i++ {
- if r1.TypeBitMap[i] != r2.TypeBitMap[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateDHCID(r1, r2 *DHCID) bool {
- if r1.Digest != r2.Digest {
- return false
- }
- return true
-}
-
-func isDuplicateDNAME(r1, r2 *DNAME) bool {
- if !isDulicateName(r1.Target, r2.Target) {
- return false
- }
- return true
-}
-
-func isDuplicateDNSKEY(r1, r2 *DNSKEY) bool {
- if r1.Flags != r2.Flags {
- return false
- }
- if r1.Protocol != r2.Protocol {
- return false
- }
- if r1.Algorithm != r2.Algorithm {
- return false
- }
- if r1.PublicKey != r2.PublicKey {
- return false
- }
- return true
-}
-
-func isDuplicateDS(r1, r2 *DS) bool {
- if r1.KeyTag != r2.KeyTag {
- return false
- }
- if r1.Algorithm != r2.Algorithm {
- return false
- }
- if r1.DigestType != r2.DigestType {
- return false
- }
- if r1.Digest != r2.Digest {
- return false
- }
- return true
-}
-
-func isDuplicateEID(r1, r2 *EID) bool {
- if r1.Endpoint != r2.Endpoint {
- return false
- }
- return true
-}
-
-func isDuplicateEUI48(r1, r2 *EUI48) bool {
- if r1.Address != r2.Address {
- return false
- }
- return true
-}
-
-func isDuplicateEUI64(r1, r2 *EUI64) bool {
- if r1.Address != r2.Address {
- return false
- }
- return true
-}
-
-func isDuplicateGID(r1, r2 *GID) bool {
- if r1.Gid != r2.Gid {
- return false
- }
- return true
-}
-
-func isDuplicateGPOS(r1, r2 *GPOS) bool {
- if r1.Longitude != r2.Longitude {
- return false
- }
- if r1.Latitude != r2.Latitude {
- return false
- }
- if r1.Altitude != r2.Altitude {
- return false
- }
- return true
-}
-
-func isDuplicateHINFO(r1, r2 *HINFO) bool {
- if r1.Cpu != r2.Cpu {
- return false
- }
- if r1.Os != r2.Os {
- return false
- }
- return true
-}
-
-func isDuplicateHIP(r1, r2 *HIP) bool {
- if r1.HitLength != r2.HitLength {
- return false
- }
- if r1.PublicKeyAlgorithm != r2.PublicKeyAlgorithm {
- return false
- }
- if r1.PublicKeyLength != r2.PublicKeyLength {
- return false
- }
- if r1.Hit != r2.Hit {
- return false
- }
- if r1.PublicKey != r2.PublicKey {
- return false
- }
- if len(r1.RendezvousServers) != len(r2.RendezvousServers) {
- return false
- }
- for i := 0; i < len(r1.RendezvousServers); i++ {
- if !isDulicateName(r1.RendezvousServers[i], r2.RendezvousServers[i]) {
- return false
- }
- }
- return true
-}
-
-func isDuplicateKX(r1, r2 *KX) bool {
- if r1.Preference != r2.Preference {
- return false
- }
- if !isDulicateName(r1.Exchanger, r2.Exchanger) {
- return false
- }
- return true
-}
-
-func isDuplicateL32(r1, r2 *L32) bool {
- if r1.Preference != r2.Preference {
- return false
- }
- if len(r1.Locator32) != len(r2.Locator32) {
- return false
- }
- for i := 0; i < len(r1.Locator32); i++ {
- if r1.Locator32[i] != r2.Locator32[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateL64(r1, r2 *L64) bool {
- if r1.Preference != r2.Preference {
- return false
- }
- if r1.Locator64 != r2.Locator64 {
- return false
- }
- return true
-}
-
-func isDuplicateLOC(r1, r2 *LOC) bool {
- if r1.Version != r2.Version {
- return false
- }
- if r1.Size != r2.Size {
- return false
- }
- if r1.HorizPre != r2.HorizPre {
- return false
- }
- if r1.VertPre != r2.VertPre {
- return false
- }
- if r1.Latitude != r2.Latitude {
- return false
- }
- if r1.Longitude != r2.Longitude {
- return false
- }
- if r1.Altitude != r2.Altitude {
- return false
- }
- return true
-}
-
-func isDuplicateLP(r1, r2 *LP) bool {
- if r1.Preference != r2.Preference {
- return false
- }
- if !isDulicateName(r1.Fqdn, r2.Fqdn) {
- return false
- }
- return true
-}
-
-func isDuplicateMB(r1, r2 *MB) bool {
- if !isDulicateName(r1.Mb, r2.Mb) {
- return false
- }
- return true
-}
-
-func isDuplicateMD(r1, r2 *MD) bool {
- if !isDulicateName(r1.Md, r2.Md) {
- return false
- }
- return true
-}
-
-func isDuplicateMF(r1, r2 *MF) bool {
- if !isDulicateName(r1.Mf, r2.Mf) {
- return false
- }
- return true
-}
-
-func isDuplicateMG(r1, r2 *MG) bool {
- if !isDulicateName(r1.Mg, r2.Mg) {
- return false
- }
- return true
-}
-
-func isDuplicateMINFO(r1, r2 *MINFO) bool {
- if !isDulicateName(r1.Rmail, r2.Rmail) {
- return false
- }
- if !isDulicateName(r1.Email, r2.Email) {
- return false
- }
- return true
-}
-
-func isDuplicateMR(r1, r2 *MR) bool {
- if !isDulicateName(r1.Mr, r2.Mr) {
- return false
- }
- return true
-}
-
-func isDuplicateMX(r1, r2 *MX) bool {
- if r1.Preference != r2.Preference {
- return false
- }
- if !isDulicateName(r1.Mx, r2.Mx) {
- return false
- }
- return true
-}
-
-func isDuplicateNAPTR(r1, r2 *NAPTR) bool {
- if r1.Order != r2.Order {
- return false
- }
- if r1.Preference != r2.Preference {
- return false
- }
- if r1.Flags != r2.Flags {
- return false
- }
- if r1.Service != r2.Service {
- return false
- }
- if r1.Regexp != r2.Regexp {
- return false
- }
- if !isDulicateName(r1.Replacement, r2.Replacement) {
- return false
- }
- return true
-}
-
-func isDuplicateNID(r1, r2 *NID) bool {
- if r1.Preference != r2.Preference {
- return false
- }
- if r1.NodeID != r2.NodeID {
- return false
- }
- return true
-}
-
-func isDuplicateNIMLOC(r1, r2 *NIMLOC) bool {
- if r1.Locator != r2.Locator {
- return false
- }
- return true
-}
-
-func isDuplicateNINFO(r1, r2 *NINFO) bool {
- if len(r1.ZSData) != len(r2.ZSData) {
- return false
- }
- for i := 0; i < len(r1.ZSData); i++ {
- if r1.ZSData[i] != r2.ZSData[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateNS(r1, r2 *NS) bool {
- if !isDulicateName(r1.Ns, r2.Ns) {
- return false
- }
- return true
-}
-
-func isDuplicateNSAPPTR(r1, r2 *NSAPPTR) bool {
- if !isDulicateName(r1.Ptr, r2.Ptr) {
- return false
- }
- return true
-}
-
-func isDuplicateNSEC(r1, r2 *NSEC) bool {
- if !isDulicateName(r1.NextDomain, r2.NextDomain) {
- return false
- }
- if len(r1.TypeBitMap) != len(r2.TypeBitMap) {
- return false
- }
- for i := 0; i < len(r1.TypeBitMap); i++ {
- if r1.TypeBitMap[i] != r2.TypeBitMap[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateNSEC3(r1, r2 *NSEC3) bool {
- if r1.Hash != r2.Hash {
- return false
- }
- if r1.Flags != r2.Flags {
- return false
- }
- if r1.Iterations != r2.Iterations {
- return false
- }
- if r1.SaltLength != r2.SaltLength {
- return false
- }
- if r1.Salt != r2.Salt {
- return false
- }
- if r1.HashLength != r2.HashLength {
- return false
- }
- if r1.NextDomain != r2.NextDomain {
- return false
- }
- if len(r1.TypeBitMap) != len(r2.TypeBitMap) {
- return false
- }
- for i := 0; i < len(r1.TypeBitMap); i++ {
- if r1.TypeBitMap[i] != r2.TypeBitMap[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateNSEC3PARAM(r1, r2 *NSEC3PARAM) bool {
- if r1.Hash != r2.Hash {
- return false
- }
- if r1.Flags != r2.Flags {
- return false
- }
- if r1.Iterations != r2.Iterations {
- return false
- }
- if r1.SaltLength != r2.SaltLength {
- return false
- }
- if r1.Salt != r2.Salt {
- return false
- }
- return true
-}
-
-func isDuplicateOPENPGPKEY(r1, r2 *OPENPGPKEY) bool {
- if r1.PublicKey != r2.PublicKey {
- return false
- }
- return true
-}
-
-func isDuplicatePTR(r1, r2 *PTR) bool {
- if !isDulicateName(r1.Ptr, r2.Ptr) {
- return false
- }
- return true
-}
-
-func isDuplicatePX(r1, r2 *PX) bool {
- if r1.Preference != r2.Preference {
- return false
- }
- if !isDulicateName(r1.Map822, r2.Map822) {
- return false
- }
- if !isDulicateName(r1.Mapx400, r2.Mapx400) {
- return false
- }
- return true
-}
-
-func isDuplicateRKEY(r1, r2 *RKEY) bool {
- if r1.Flags != r2.Flags {
- return false
- }
- if r1.Protocol != r2.Protocol {
- return false
- }
- if r1.Algorithm != r2.Algorithm {
- return false
- }
- if r1.PublicKey != r2.PublicKey {
- return false
- }
- return true
-}
-
-func isDuplicateRP(r1, r2 *RP) bool {
- if !isDulicateName(r1.Mbox, r2.Mbox) {
- return false
- }
- if !isDulicateName(r1.Txt, r2.Txt) {
- return false
- }
- return true
-}
-
-func isDuplicateRRSIG(r1, r2 *RRSIG) bool {
- if r1.TypeCovered != r2.TypeCovered {
- return false
- }
- if r1.Algorithm != r2.Algorithm {
- return false
- }
- if r1.Labels != r2.Labels {
- return false
- }
- if r1.OrigTtl != r2.OrigTtl {
- return false
- }
- if r1.Expiration != r2.Expiration {
- return false
- }
- if r1.Inception != r2.Inception {
- return false
- }
- if r1.KeyTag != r2.KeyTag {
- return false
- }
- if !isDulicateName(r1.SignerName, r2.SignerName) {
- return false
- }
- if r1.Signature != r2.Signature {
- return false
- }
- return true
-}
-
-func isDuplicateRT(r1, r2 *RT) bool {
- if r1.Preference != r2.Preference {
- return false
- }
- if !isDulicateName(r1.Host, r2.Host) {
- return false
- }
- return true
-}
-
-func isDuplicateSMIMEA(r1, r2 *SMIMEA) bool {
- if r1.Usage != r2.Usage {
- return false
- }
- if r1.Selector != r2.Selector {
- return false
- }
- if r1.MatchingType != r2.MatchingType {
- return false
- }
- if r1.Certificate != r2.Certificate {
- return false
- }
- return true
-}
-
-func isDuplicateSOA(r1, r2 *SOA) bool {
- if !isDulicateName(r1.Ns, r2.Ns) {
- return false
- }
- if !isDulicateName(r1.Mbox, r2.Mbox) {
- return false
- }
- if r1.Serial != r2.Serial {
- return false
- }
- if r1.Refresh != r2.Refresh {
- return false
- }
- if r1.Retry != r2.Retry {
- return false
- }
- if r1.Expire != r2.Expire {
- return false
- }
- if r1.Minttl != r2.Minttl {
- return false
- }
- return true
-}
-
-func isDuplicateSPF(r1, r2 *SPF) bool {
- if len(r1.Txt) != len(r2.Txt) {
- return false
- }
- for i := 0; i < len(r1.Txt); i++ {
- if r1.Txt[i] != r2.Txt[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateSRV(r1, r2 *SRV) bool {
- if r1.Priority != r2.Priority {
- return false
- }
- if r1.Weight != r2.Weight {
- return false
- }
- if r1.Port != r2.Port {
- return false
- }
- if !isDulicateName(r1.Target, r2.Target) {
- return false
- }
- return true
-}
-
-func isDuplicateSSHFP(r1, r2 *SSHFP) bool {
- if r1.Algorithm != r2.Algorithm {
- return false
- }
- if r1.Type != r2.Type {
- return false
- }
- if r1.FingerPrint != r2.FingerPrint {
- return false
- }
- return true
-}
-
-func isDuplicateTA(r1, r2 *TA) bool {
- if r1.KeyTag != r2.KeyTag {
- return false
- }
- if r1.Algorithm != r2.Algorithm {
- return false
- }
- if r1.DigestType != r2.DigestType {
- return false
- }
- if r1.Digest != r2.Digest {
- return false
- }
- return true
-}
-
-func isDuplicateTALINK(r1, r2 *TALINK) bool {
- if !isDulicateName(r1.PreviousName, r2.PreviousName) {
- return false
- }
- if !isDulicateName(r1.NextName, r2.NextName) {
- return false
- }
- return true
-}
-
-func isDuplicateTKEY(r1, r2 *TKEY) bool {
- if !isDulicateName(r1.Algorithm, r2.Algorithm) {
- return false
- }
- if r1.Inception != r2.Inception {
- return false
- }
- if r1.Expiration != r2.Expiration {
- return false
- }
- if r1.Mode != r2.Mode {
- return false
- }
- if r1.Error != r2.Error {
- return false
- }
- if r1.KeySize != r2.KeySize {
- return false
- }
- if r1.Key != r2.Key {
- return false
- }
- if r1.OtherLen != r2.OtherLen {
- return false
- }
- if r1.OtherData != r2.OtherData {
- return false
- }
- return true
-}
-
-func isDuplicateTLSA(r1, r2 *TLSA) bool {
- if r1.Usage != r2.Usage {
- return false
- }
- if r1.Selector != r2.Selector {
- return false
- }
- if r1.MatchingType != r2.MatchingType {
- return false
- }
- if r1.Certificate != r2.Certificate {
- return false
- }
- return true
-}
-
-func isDuplicateTSIG(r1, r2 *TSIG) bool {
- if !isDulicateName(r1.Algorithm, r2.Algorithm) {
- return false
- }
- if r1.TimeSigned != r2.TimeSigned {
- return false
- }
- if r1.Fudge != r2.Fudge {
- return false
- }
- if r1.MACSize != r2.MACSize {
- return false
- }
- if r1.MAC != r2.MAC {
- return false
- }
- if r1.OrigId != r2.OrigId {
- return false
- }
- if r1.Error != r2.Error {
- return false
- }
- if r1.OtherLen != r2.OtherLen {
- return false
- }
- if r1.OtherData != r2.OtherData {
- return false
- }
- return true
-}
-
-func isDuplicateTXT(r1, r2 *TXT) bool {
- if len(r1.Txt) != len(r2.Txt) {
- return false
- }
- for i := 0; i < len(r1.Txt); i++ {
- if r1.Txt[i] != r2.Txt[i] {
- return false
- }
- }
- return true
-}
-
-func isDuplicateUID(r1, r2 *UID) bool {
- if r1.Uid != r2.Uid {
- return false
- }
- return true
-}
-
-func isDuplicateUINFO(r1, r2 *UINFO) bool {
- if r1.Uinfo != r2.Uinfo {
- return false
- }
- return true
-}
-
-func isDuplicateURI(r1, r2 *URI) bool {
- if r1.Priority != r2.Priority {
- return false
- }
- if r1.Weight != r2.Weight {
- return false
- }
- if r1.Target != r2.Target {
- return false
- }
- return true
-}
-
-func isDuplicateX25(r1, r2 *X25) bool {
- if r1.PSDNAddress != r2.PSDNAddress {
- return false
- }
- return true
-}
diff --git a/vendor/github.com/miekg/dns/zmsg.go b/vendor/github.com/miekg/dns/zmsg.go
deleted file mode 100644
index 1a68f74da25..00000000000
--- a/vendor/github.com/miekg/dns/zmsg.go
+++ /dev/null
@@ -1,3615 +0,0 @@
-// Code generated by "go run msg_generate.go"; DO NOT EDIT.
-
-package dns
-
-// pack*() functions
-
-func (rr *A) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packDataA(rr.A, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *AAAA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packDataAAAA(rr.AAAA, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *AFSDB) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Subtype, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Hostname, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *ANY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *AVC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packStringTxt(rr.Txt, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *CAA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint8(rr.Flag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packString(rr.Tag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringOctet(rr.Value, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *CDNSKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Flags, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Protocol, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringBase64(rr.PublicKey, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *CDS) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.KeyTag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.DigestType, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.Digest, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *CERT) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Type, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.KeyTag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringBase64(rr.Certificate, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *CNAME) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Target, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *CSYNC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint32(rr.Serial, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Flags, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packDataNsec(rr.TypeBitMap, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *DHCID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packStringBase64(rr.Digest, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *DLV) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.KeyTag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.DigestType, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.Digest, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *DNAME) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Target, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *DNSKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Flags, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Protocol, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringBase64(rr.PublicKey, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *DS) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.KeyTag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.DigestType, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.Digest, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *EID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packStringHex(rr.Endpoint, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *EUI48) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint48(rr.Address, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *EUI64) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint64(rr.Address, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *GID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint32(rr.Gid, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *GPOS) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packString(rr.Longitude, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packString(rr.Latitude, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packString(rr.Altitude, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *HINFO) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packString(rr.Cpu, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packString(rr.Os, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *HIP) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint8(rr.HitLength, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.PublicKeyAlgorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.PublicKeyLength, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.Hit, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringBase64(rr.PublicKey, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packDataDomainNames(rr.RendezvousServers, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *KEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Flags, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Protocol, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringBase64(rr.PublicKey, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *KX) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Preference, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Exchanger, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *L32) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Preference, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packDataA(rr.Locator32, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *L64) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Preference, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint64(rr.Locator64, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *LOC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint8(rr.Version, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Size, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.HorizPre, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.VertPre, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Latitude, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Longitude, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Altitude, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *LP) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Preference, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Fqdn, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *MB) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Mb, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *MD) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Md, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *MF) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Mf, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *MG) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Mg, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *MINFO) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Rmail, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Email, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *MR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Mr, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *MX) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Preference, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Mx, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *NAPTR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Order, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Preference, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packString(rr.Flags, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packString(rr.Service, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packString(rr.Regexp, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Replacement, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *NID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Preference, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint64(rr.NodeID, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *NIMLOC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packStringHex(rr.Locator, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *NINFO) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packStringTxt(rr.ZSData, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *NS) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Ns, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *NSAPPTR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Ptr, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *NSEC) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.NextDomain, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- off, err = packDataNsec(rr.TypeBitMap, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *NSEC3) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint8(rr.Hash, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Flags, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Iterations, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.SaltLength, msg, off)
- if err != nil {
- return off, err
- }
- // Only pack salt if value is not "-", i.e. empty
- if rr.Salt != "-" {
- off, err = packStringHex(rr.Salt, msg, off)
- if err != nil {
- return off, err
- }
- }
- off, err = packUint8(rr.HashLength, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringBase32(rr.NextDomain, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packDataNsec(rr.TypeBitMap, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *NSEC3PARAM) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint8(rr.Hash, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Flags, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Iterations, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.SaltLength, msg, off)
- if err != nil {
- return off, err
- }
- // Only pack salt if value is not "-", i.e. empty
- if rr.Salt != "-" {
- off, err = packStringHex(rr.Salt, msg, off)
- if err != nil {
- return off, err
- }
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *OPENPGPKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packStringBase64(rr.PublicKey, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *OPT) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packDataOpt(rr.Option, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *PTR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Ptr, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *PX) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Preference, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Map822, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Mapx400, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *RFC3597) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packStringHex(rr.Rdata, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *RKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Flags, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Protocol, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringBase64(rr.PublicKey, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *RP) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Mbox, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Txt, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *RRSIG) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.TypeCovered, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Labels, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.OrigTtl, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Expiration, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Inception, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.KeyTag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.SignerName, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- off, err = packStringBase64(rr.Signature, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *RT) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Preference, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Host, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *SIG) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.TypeCovered, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Labels, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.OrigTtl, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Expiration, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Inception, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.KeyTag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.SignerName, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- off, err = packStringBase64(rr.Signature, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *SMIMEA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint8(rr.Usage, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Selector, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.MatchingType, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.Certificate, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *SOA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Ns, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Mbox, msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Serial, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Refresh, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Retry, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Expire, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Minttl, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *SPF) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packStringTxt(rr.Txt, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *SRV) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Priority, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Weight, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Port, msg, off)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.Target, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *SSHFP) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Type, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.FingerPrint, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *TA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.KeyTag, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Algorithm, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.DigestType, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.Digest, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *TALINK) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.PreviousName, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- off, err = PackDomainName(rr.NextName, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *TKEY) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Algorithm, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Inception, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint32(rr.Expiration, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Mode, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Error, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.KeySize, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.Key, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.OtherLen, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.OtherData, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *TLSA) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint8(rr.Usage, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.Selector, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint8(rr.MatchingType, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.Certificate, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *TSIG) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = PackDomainName(rr.Algorithm, msg, off, compression, false)
- if err != nil {
- return off, err
- }
- off, err = packUint48(rr.TimeSigned, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Fudge, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.MACSize, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.MAC, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.OrigId, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Error, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.OtherLen, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringHex(rr.OtherData, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *TXT) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packStringTxt(rr.Txt, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *UID) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint32(rr.Uid, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *UINFO) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packString(rr.Uinfo, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *URI) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packUint16(rr.Priority, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packUint16(rr.Weight, msg, off)
- if err != nil {
- return off, err
- }
- off, err = packStringOctet(rr.Target, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-func (rr *X25) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
- off, err := rr.Hdr.pack(msg, off, compression, compress)
- if err != nil {
- return off, err
- }
- headerEnd := off
- off, err = packString(rr.PSDNAddress, msg, off)
- if err != nil {
- return off, err
- }
- rr.Header().Rdlength = uint16(off - headerEnd)
- return off, nil
-}
-
-// unpack*() functions
-
-func unpackA(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(A)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.A, off, err = unpackDataA(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackAAAA(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(AAAA)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.AAAA, off, err = unpackDataAAAA(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackAFSDB(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(AFSDB)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Subtype, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Hostname, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackANY(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(ANY)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- return rr, off, err
-}
-
-func unpackAVC(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(AVC)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Txt, off, err = unpackStringTxt(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackCAA(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(CAA)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Flag, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Tag, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Value, off, err = unpackStringOctet(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackCDNSKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(CDNSKEY)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Flags, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Protocol, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackCDS(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(CDS)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.KeyTag, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.DigestType, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackCERT(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(CERT)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Type, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.KeyTag, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Certificate, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackCNAME(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(CNAME)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Target, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackCSYNC(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(CSYNC)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Serial, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Flags, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackDHCID(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(DHCID)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Digest, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackDLV(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(DLV)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.KeyTag, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.DigestType, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackDNAME(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(DNAME)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Target, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackDNSKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(DNSKEY)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Flags, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Protocol, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackDS(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(DS)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.KeyTag, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.DigestType, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackEID(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(EID)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Endpoint, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackEUI48(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(EUI48)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Address, off, err = unpackUint48(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackEUI64(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(EUI64)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Address, off, err = unpackUint64(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackGID(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(GID)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Gid, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackGPOS(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(GPOS)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Longitude, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Latitude, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Altitude, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackHINFO(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(HINFO)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Cpu, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Os, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackHIP(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(HIP)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.HitLength, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.PublicKeyAlgorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.PublicKeyLength, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Hit, off, err = unpackStringHex(msg, off, off+int(rr.HitLength))
- if err != nil {
- return rr, off, err
- }
- rr.PublicKey, off, err = unpackStringBase64(msg, off, off+int(rr.PublicKeyLength))
- if err != nil {
- return rr, off, err
- }
- rr.RendezvousServers, off, err = unpackDataDomainNames(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(KEY)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Flags, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Protocol, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackKX(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(KX)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Preference, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Exchanger, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackL32(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(L32)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Preference, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Locator32, off, err = unpackDataA(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackL64(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(L64)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Preference, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Locator64, off, err = unpackUint64(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackLOC(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(LOC)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Version, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Size, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.HorizPre, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.VertPre, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Latitude, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Longitude, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Altitude, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackLP(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(LP)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Preference, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Fqdn, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackMB(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(MB)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Mb, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackMD(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(MD)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Md, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackMF(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(MF)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Mf, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackMG(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(MG)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Mg, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackMINFO(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(MINFO)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Rmail, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Email, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackMR(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(MR)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Mr, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackMX(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(MX)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Preference, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Mx, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackNAPTR(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(NAPTR)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Order, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Preference, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Flags, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Service, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Regexp, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Replacement, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackNID(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(NID)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Preference, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.NodeID, off, err = unpackUint64(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackNIMLOC(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(NIMLOC)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Locator, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackNINFO(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(NINFO)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.ZSData, off, err = unpackStringTxt(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackNS(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(NS)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Ns, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackNSAPPTR(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(NSAPPTR)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Ptr, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackNSEC(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(NSEC)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.NextDomain, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackNSEC3(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(NSEC3)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Hash, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Flags, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Iterations, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.SaltLength, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Salt, off, err = unpackStringHex(msg, off, off+int(rr.SaltLength))
- if err != nil {
- return rr, off, err
- }
- rr.HashLength, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.NextDomain, off, err = unpackStringBase32(msg, off, off+int(rr.HashLength))
- if err != nil {
- return rr, off, err
- }
- rr.TypeBitMap, off, err = unpackDataNsec(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackNSEC3PARAM(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(NSEC3PARAM)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Hash, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Flags, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Iterations, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.SaltLength, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Salt, off, err = unpackStringHex(msg, off, off+int(rr.SaltLength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackOPENPGPKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(OPENPGPKEY)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackOPT(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(OPT)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Option, off, err = unpackDataOpt(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackPTR(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(PTR)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Ptr, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackPX(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(PX)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Preference, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Map822, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Mapx400, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackRFC3597(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(RFC3597)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Rdata, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackRKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(RKEY)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Flags, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Protocol, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.PublicKey, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackRP(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(RP)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Mbox, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Txt, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackRRSIG(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(RRSIG)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.TypeCovered, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Labels, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.OrigTtl, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Expiration, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Inception, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.KeyTag, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.SignerName, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Signature, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackRT(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(RT)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Preference, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Host, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackSIG(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(SIG)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.TypeCovered, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Labels, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.OrigTtl, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Expiration, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Inception, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.KeyTag, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.SignerName, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Signature, off, err = unpackStringBase64(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackSMIMEA(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(SMIMEA)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Usage, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Selector, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.MatchingType, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Certificate, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackSOA(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(SOA)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Ns, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Mbox, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Serial, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Refresh, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Retry, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Expire, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Minttl, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackSPF(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(SPF)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Txt, off, err = unpackStringTxt(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackSRV(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(SRV)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Priority, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Weight, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Port, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Target, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackSSHFP(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(SSHFP)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Type, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.FingerPrint, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackTA(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(TA)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.KeyTag, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Algorithm, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.DigestType, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Digest, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackTALINK(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(TALINK)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.PreviousName, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.NextName, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackTKEY(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(TKEY)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Algorithm, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Inception, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Expiration, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Mode, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Error, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.KeySize, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Key, off, err = unpackStringHex(msg, off, off+int(rr.KeySize))
- if err != nil {
- return rr, off, err
- }
- rr.OtherLen, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.OtherData, off, err = unpackStringHex(msg, off, off+int(rr.OtherLen))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackTLSA(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(TLSA)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Usage, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Selector, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.MatchingType, off, err = unpackUint8(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Certificate, off, err = unpackStringHex(msg, off, rdStart+int(rr.Hdr.Rdlength))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackTSIG(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(TSIG)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Algorithm, off, err = UnpackDomainName(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.TimeSigned, off, err = unpackUint48(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Fudge, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.MACSize, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.MAC, off, err = unpackStringHex(msg, off, off+int(rr.MACSize))
- if err != nil {
- return rr, off, err
- }
- rr.OrigId, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Error, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.OtherLen, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.OtherData, off, err = unpackStringHex(msg, off, off+int(rr.OtherLen))
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackTXT(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(TXT)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Txt, off, err = unpackStringTxt(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackUID(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(UID)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Uid, off, err = unpackUint32(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackUINFO(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(UINFO)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Uinfo, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackURI(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(URI)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.Priority, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Weight, off, err = unpackUint16(msg, off)
- if err != nil {
- return rr, off, err
- }
- if off == len(msg) {
- return rr, off, nil
- }
- rr.Target, off, err = unpackStringOctet(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-func unpackX25(h RR_Header, msg []byte, off int) (RR, int, error) {
- rr := new(X25)
- rr.Hdr = h
- if noRdata(h) {
- return rr, off, nil
- }
- var err error
- rdStart := off
- _ = rdStart
-
- rr.PSDNAddress, off, err = unpackString(msg, off)
- if err != nil {
- return rr, off, err
- }
- return rr, off, err
-}
-
-var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){
- TypeA: unpackA,
- TypeAAAA: unpackAAAA,
- TypeAFSDB: unpackAFSDB,
- TypeANY: unpackANY,
- TypeAVC: unpackAVC,
- TypeCAA: unpackCAA,
- TypeCDNSKEY: unpackCDNSKEY,
- TypeCDS: unpackCDS,
- TypeCERT: unpackCERT,
- TypeCNAME: unpackCNAME,
- TypeCSYNC: unpackCSYNC,
- TypeDHCID: unpackDHCID,
- TypeDLV: unpackDLV,
- TypeDNAME: unpackDNAME,
- TypeDNSKEY: unpackDNSKEY,
- TypeDS: unpackDS,
- TypeEID: unpackEID,
- TypeEUI48: unpackEUI48,
- TypeEUI64: unpackEUI64,
- TypeGID: unpackGID,
- TypeGPOS: unpackGPOS,
- TypeHINFO: unpackHINFO,
- TypeHIP: unpackHIP,
- TypeKEY: unpackKEY,
- TypeKX: unpackKX,
- TypeL32: unpackL32,
- TypeL64: unpackL64,
- TypeLOC: unpackLOC,
- TypeLP: unpackLP,
- TypeMB: unpackMB,
- TypeMD: unpackMD,
- TypeMF: unpackMF,
- TypeMG: unpackMG,
- TypeMINFO: unpackMINFO,
- TypeMR: unpackMR,
- TypeMX: unpackMX,
- TypeNAPTR: unpackNAPTR,
- TypeNID: unpackNID,
- TypeNIMLOC: unpackNIMLOC,
- TypeNINFO: unpackNINFO,
- TypeNS: unpackNS,
- TypeNSAPPTR: unpackNSAPPTR,
- TypeNSEC: unpackNSEC,
- TypeNSEC3: unpackNSEC3,
- TypeNSEC3PARAM: unpackNSEC3PARAM,
- TypeOPENPGPKEY: unpackOPENPGPKEY,
- TypeOPT: unpackOPT,
- TypePTR: unpackPTR,
- TypePX: unpackPX,
- TypeRKEY: unpackRKEY,
- TypeRP: unpackRP,
- TypeRRSIG: unpackRRSIG,
- TypeRT: unpackRT,
- TypeSIG: unpackSIG,
- TypeSMIMEA: unpackSMIMEA,
- TypeSOA: unpackSOA,
- TypeSPF: unpackSPF,
- TypeSRV: unpackSRV,
- TypeSSHFP: unpackSSHFP,
- TypeTA: unpackTA,
- TypeTALINK: unpackTALINK,
- TypeTKEY: unpackTKEY,
- TypeTLSA: unpackTLSA,
- TypeTSIG: unpackTSIG,
- TypeTXT: unpackTXT,
- TypeUID: unpackUID,
- TypeUINFO: unpackUINFO,
- TypeURI: unpackURI,
- TypeX25: unpackX25,
-}
diff --git a/vendor/github.com/miekg/dns/ztypes.go b/vendor/github.com/miekg/dns/ztypes.go
deleted file mode 100644
index 965753b11b2..00000000000
--- a/vendor/github.com/miekg/dns/ztypes.go
+++ /dev/null
@@ -1,863 +0,0 @@
-// Code generated by "go run types_generate.go"; DO NOT EDIT.
-
-package dns
-
-import (
- "encoding/base64"
- "net"
-)
-
-// TypeToRR is a map of constructors for each RR type.
-var TypeToRR = map[uint16]func() RR{
- TypeA: func() RR { return new(A) },
- TypeAAAA: func() RR { return new(AAAA) },
- TypeAFSDB: func() RR { return new(AFSDB) },
- TypeANY: func() RR { return new(ANY) },
- TypeAVC: func() RR { return new(AVC) },
- TypeCAA: func() RR { return new(CAA) },
- TypeCDNSKEY: func() RR { return new(CDNSKEY) },
- TypeCDS: func() RR { return new(CDS) },
- TypeCERT: func() RR { return new(CERT) },
- TypeCNAME: func() RR { return new(CNAME) },
- TypeCSYNC: func() RR { return new(CSYNC) },
- TypeDHCID: func() RR { return new(DHCID) },
- TypeDLV: func() RR { return new(DLV) },
- TypeDNAME: func() RR { return new(DNAME) },
- TypeDNSKEY: func() RR { return new(DNSKEY) },
- TypeDS: func() RR { return new(DS) },
- TypeEID: func() RR { return new(EID) },
- TypeEUI48: func() RR { return new(EUI48) },
- TypeEUI64: func() RR { return new(EUI64) },
- TypeGID: func() RR { return new(GID) },
- TypeGPOS: func() RR { return new(GPOS) },
- TypeHINFO: func() RR { return new(HINFO) },
- TypeHIP: func() RR { return new(HIP) },
- TypeKEY: func() RR { return new(KEY) },
- TypeKX: func() RR { return new(KX) },
- TypeL32: func() RR { return new(L32) },
- TypeL64: func() RR { return new(L64) },
- TypeLOC: func() RR { return new(LOC) },
- TypeLP: func() RR { return new(LP) },
- TypeMB: func() RR { return new(MB) },
- TypeMD: func() RR { return new(MD) },
- TypeMF: func() RR { return new(MF) },
- TypeMG: func() RR { return new(MG) },
- TypeMINFO: func() RR { return new(MINFO) },
- TypeMR: func() RR { return new(MR) },
- TypeMX: func() RR { return new(MX) },
- TypeNAPTR: func() RR { return new(NAPTR) },
- TypeNID: func() RR { return new(NID) },
- TypeNIMLOC: func() RR { return new(NIMLOC) },
- TypeNINFO: func() RR { return new(NINFO) },
- TypeNS: func() RR { return new(NS) },
- TypeNSAPPTR: func() RR { return new(NSAPPTR) },
- TypeNSEC: func() RR { return new(NSEC) },
- TypeNSEC3: func() RR { return new(NSEC3) },
- TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
- TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
- TypeOPT: func() RR { return new(OPT) },
- TypePTR: func() RR { return new(PTR) },
- TypePX: func() RR { return new(PX) },
- TypeRKEY: func() RR { return new(RKEY) },
- TypeRP: func() RR { return new(RP) },
- TypeRRSIG: func() RR { return new(RRSIG) },
- TypeRT: func() RR { return new(RT) },
- TypeSIG: func() RR { return new(SIG) },
- TypeSMIMEA: func() RR { return new(SMIMEA) },
- TypeSOA: func() RR { return new(SOA) },
- TypeSPF: func() RR { return new(SPF) },
- TypeSRV: func() RR { return new(SRV) },
- TypeSSHFP: func() RR { return new(SSHFP) },
- TypeTA: func() RR { return new(TA) },
- TypeTALINK: func() RR { return new(TALINK) },
- TypeTKEY: func() RR { return new(TKEY) },
- TypeTLSA: func() RR { return new(TLSA) },
- TypeTSIG: func() RR { return new(TSIG) },
- TypeTXT: func() RR { return new(TXT) },
- TypeUID: func() RR { return new(UID) },
- TypeUINFO: func() RR { return new(UINFO) },
- TypeURI: func() RR { return new(URI) },
- TypeX25: func() RR { return new(X25) },
-}
-
-// TypeToString is a map of strings for each RR type.
-var TypeToString = map[uint16]string{
- TypeA: "A",
- TypeAAAA: "AAAA",
- TypeAFSDB: "AFSDB",
- TypeANY: "ANY",
- TypeATMA: "ATMA",
- TypeAVC: "AVC",
- TypeAXFR: "AXFR",
- TypeCAA: "CAA",
- TypeCDNSKEY: "CDNSKEY",
- TypeCDS: "CDS",
- TypeCERT: "CERT",
- TypeCNAME: "CNAME",
- TypeCSYNC: "CSYNC",
- TypeDHCID: "DHCID",
- TypeDLV: "DLV",
- TypeDNAME: "DNAME",
- TypeDNSKEY: "DNSKEY",
- TypeDS: "DS",
- TypeEID: "EID",
- TypeEUI48: "EUI48",
- TypeEUI64: "EUI64",
- TypeGID: "GID",
- TypeGPOS: "GPOS",
- TypeHINFO: "HINFO",
- TypeHIP: "HIP",
- TypeISDN: "ISDN",
- TypeIXFR: "IXFR",
- TypeKEY: "KEY",
- TypeKX: "KX",
- TypeL32: "L32",
- TypeL64: "L64",
- TypeLOC: "LOC",
- TypeLP: "LP",
- TypeMAILA: "MAILA",
- TypeMAILB: "MAILB",
- TypeMB: "MB",
- TypeMD: "MD",
- TypeMF: "MF",
- TypeMG: "MG",
- TypeMINFO: "MINFO",
- TypeMR: "MR",
- TypeMX: "MX",
- TypeNAPTR: "NAPTR",
- TypeNID: "NID",
- TypeNIMLOC: "NIMLOC",
- TypeNINFO: "NINFO",
- TypeNS: "NS",
- TypeNSEC: "NSEC",
- TypeNSEC3: "NSEC3",
- TypeNSEC3PARAM: "NSEC3PARAM",
- TypeNULL: "NULL",
- TypeNXT: "NXT",
- TypeNone: "None",
- TypeOPENPGPKEY: "OPENPGPKEY",
- TypeOPT: "OPT",
- TypePTR: "PTR",
- TypePX: "PX",
- TypeRKEY: "RKEY",
- TypeRP: "RP",
- TypeRRSIG: "RRSIG",
- TypeRT: "RT",
- TypeReserved: "Reserved",
- TypeSIG: "SIG",
- TypeSMIMEA: "SMIMEA",
- TypeSOA: "SOA",
- TypeSPF: "SPF",
- TypeSRV: "SRV",
- TypeSSHFP: "SSHFP",
- TypeTA: "TA",
- TypeTALINK: "TALINK",
- TypeTKEY: "TKEY",
- TypeTLSA: "TLSA",
- TypeTSIG: "TSIG",
- TypeTXT: "TXT",
- TypeUID: "UID",
- TypeUINFO: "UINFO",
- TypeUNSPEC: "UNSPEC",
- TypeURI: "URI",
- TypeX25: "X25",
- TypeNSAPPTR: "NSAP-PTR",
-}
-
-func (rr *A) Header() *RR_Header { return &rr.Hdr }
-func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
-func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
-func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
-func (rr *AVC) Header() *RR_Header { return &rr.Hdr }
-func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
-func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
-func (rr *CDS) Header() *RR_Header { return &rr.Hdr }
-func (rr *CERT) Header() *RR_Header { return &rr.Hdr }
-func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
-func (rr *CSYNC) Header() *RR_Header { return &rr.Hdr }
-func (rr *DHCID) Header() *RR_Header { return &rr.Hdr }
-func (rr *DLV) Header() *RR_Header { return &rr.Hdr }
-func (rr *DNAME) Header() *RR_Header { return &rr.Hdr }
-func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr }
-func (rr *DS) Header() *RR_Header { return &rr.Hdr }
-func (rr *EID) Header() *RR_Header { return &rr.Hdr }
-func (rr *EUI48) Header() *RR_Header { return &rr.Hdr }
-func (rr *EUI64) Header() *RR_Header { return &rr.Hdr }
-func (rr *GID) Header() *RR_Header { return &rr.Hdr }
-func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
-func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
-func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
-func (rr *KEY) Header() *RR_Header { return &rr.Hdr }
-func (rr *KX) Header() *RR_Header { return &rr.Hdr }
-func (rr *L32) Header() *RR_Header { return &rr.Hdr }
-func (rr *L64) Header() *RR_Header { return &rr.Hdr }
-func (rr *LOC) Header() *RR_Header { return &rr.Hdr }
-func (rr *LP) Header() *RR_Header { return &rr.Hdr }
-func (rr *MB) Header() *RR_Header { return &rr.Hdr }
-func (rr *MD) Header() *RR_Header { return &rr.Hdr }
-func (rr *MF) Header() *RR_Header { return &rr.Hdr }
-func (rr *MG) Header() *RR_Header { return &rr.Hdr }
-func (rr *MINFO) Header() *RR_Header { return &rr.Hdr }
-func (rr *MR) Header() *RR_Header { return &rr.Hdr }
-func (rr *MX) Header() *RR_Header { return &rr.Hdr }
-func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr }
-func (rr *NID) Header() *RR_Header { return &rr.Hdr }
-func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr }
-func (rr *NINFO) Header() *RR_Header { return &rr.Hdr }
-func (rr *NS) Header() *RR_Header { return &rr.Hdr }
-func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
-func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
-func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
-func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
-func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
-func (rr *OPT) Header() *RR_Header { return &rr.Hdr }
-func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
-func (rr *PX) Header() *RR_Header { return &rr.Hdr }
-func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr }
-func (rr *RKEY) Header() *RR_Header { return &rr.Hdr }
-func (rr *RP) Header() *RR_Header { return &rr.Hdr }
-func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
-func (rr *RT) Header() *RR_Header { return &rr.Hdr }
-func (rr *SIG) Header() *RR_Header { return &rr.Hdr }
-func (rr *SMIMEA) Header() *RR_Header { return &rr.Hdr }
-func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
-func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
-func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
-func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
-func (rr *TA) Header() *RR_Header { return &rr.Hdr }
-func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
-func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
-func (rr *TLSA) Header() *RR_Header { return &rr.Hdr }
-func (rr *TSIG) Header() *RR_Header { return &rr.Hdr }
-func (rr *TXT) Header() *RR_Header { return &rr.Hdr }
-func (rr *UID) Header() *RR_Header { return &rr.Hdr }
-func (rr *UINFO) Header() *RR_Header { return &rr.Hdr }
-func (rr *URI) Header() *RR_Header { return &rr.Hdr }
-func (rr *X25) Header() *RR_Header { return &rr.Hdr }
-
-// len() functions
-func (rr *A) len() int {
- l := rr.Hdr.len()
- l += net.IPv4len // A
- return l
-}
-func (rr *AAAA) len() int {
- l := rr.Hdr.len()
- l += net.IPv6len // AAAA
- return l
-}
-func (rr *AFSDB) len() int {
- l := rr.Hdr.len()
- l += 2 // Subtype
- l += len(rr.Hostname) + 1
- return l
-}
-func (rr *ANY) len() int {
- l := rr.Hdr.len()
- return l
-}
-func (rr *AVC) len() int {
- l := rr.Hdr.len()
- for _, x := range rr.Txt {
- l += len(x) + 1
- }
- return l
-}
-func (rr *CAA) len() int {
- l := rr.Hdr.len()
- l++ // Flag
- l += len(rr.Tag) + 1
- l += len(rr.Value)
- return l
-}
-func (rr *CERT) len() int {
- l := rr.Hdr.len()
- l += 2 // Type
- l += 2 // KeyTag
- l++ // Algorithm
- l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
- return l
-}
-func (rr *CNAME) len() int {
- l := rr.Hdr.len()
- l += len(rr.Target) + 1
- return l
-}
-func (rr *DHCID) len() int {
- l := rr.Hdr.len()
- l += base64.StdEncoding.DecodedLen(len(rr.Digest))
- return l
-}
-func (rr *DNAME) len() int {
- l := rr.Hdr.len()
- l += len(rr.Target) + 1
- return l
-}
-func (rr *DNSKEY) len() int {
- l := rr.Hdr.len()
- l += 2 // Flags
- l++ // Protocol
- l++ // Algorithm
- l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
- return l
-}
-func (rr *DS) len() int {
- l := rr.Hdr.len()
- l += 2 // KeyTag
- l++ // Algorithm
- l++ // DigestType
- l += len(rr.Digest)/2 + 1
- return l
-}
-func (rr *EID) len() int {
- l := rr.Hdr.len()
- l += len(rr.Endpoint)/2 + 1
- return l
-}
-func (rr *EUI48) len() int {
- l := rr.Hdr.len()
- l += 6 // Address
- return l
-}
-func (rr *EUI64) len() int {
- l := rr.Hdr.len()
- l += 8 // Address
- return l
-}
-func (rr *GID) len() int {
- l := rr.Hdr.len()
- l += 4 // Gid
- return l
-}
-func (rr *GPOS) len() int {
- l := rr.Hdr.len()
- l += len(rr.Longitude) + 1
- l += len(rr.Latitude) + 1
- l += len(rr.Altitude) + 1
- return l
-}
-func (rr *HINFO) len() int {
- l := rr.Hdr.len()
- l += len(rr.Cpu) + 1
- l += len(rr.Os) + 1
- return l
-}
-func (rr *HIP) len() int {
- l := rr.Hdr.len()
- l++ // HitLength
- l++ // PublicKeyAlgorithm
- l += 2 // PublicKeyLength
- l += len(rr.Hit) / 2
- l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
- for _, x := range rr.RendezvousServers {
- l += len(x) + 1
- }
- return l
-}
-func (rr *KX) len() int {
- l := rr.Hdr.len()
- l += 2 // Preference
- l += len(rr.Exchanger) + 1
- return l
-}
-func (rr *L32) len() int {
- l := rr.Hdr.len()
- l += 2 // Preference
- l += net.IPv4len // Locator32
- return l
-}
-func (rr *L64) len() int {
- l := rr.Hdr.len()
- l += 2 // Preference
- l += 8 // Locator64
- return l
-}
-func (rr *LOC) len() int {
- l := rr.Hdr.len()
- l++ // Version
- l++ // Size
- l++ // HorizPre
- l++ // VertPre
- l += 4 // Latitude
- l += 4 // Longitude
- l += 4 // Altitude
- return l
-}
-func (rr *LP) len() int {
- l := rr.Hdr.len()
- l += 2 // Preference
- l += len(rr.Fqdn) + 1
- return l
-}
-func (rr *MB) len() int {
- l := rr.Hdr.len()
- l += len(rr.Mb) + 1
- return l
-}
-func (rr *MD) len() int {
- l := rr.Hdr.len()
- l += len(rr.Md) + 1
- return l
-}
-func (rr *MF) len() int {
- l := rr.Hdr.len()
- l += len(rr.Mf) + 1
- return l
-}
-func (rr *MG) len() int {
- l := rr.Hdr.len()
- l += len(rr.Mg) + 1
- return l
-}
-func (rr *MINFO) len() int {
- l := rr.Hdr.len()
- l += len(rr.Rmail) + 1
- l += len(rr.Email) + 1
- return l
-}
-func (rr *MR) len() int {
- l := rr.Hdr.len()
- l += len(rr.Mr) + 1
- return l
-}
-func (rr *MX) len() int {
- l := rr.Hdr.len()
- l += 2 // Preference
- l += len(rr.Mx) + 1
- return l
-}
-func (rr *NAPTR) len() int {
- l := rr.Hdr.len()
- l += 2 // Order
- l += 2 // Preference
- l += len(rr.Flags) + 1
- l += len(rr.Service) + 1
- l += len(rr.Regexp) + 1
- l += len(rr.Replacement) + 1
- return l
-}
-func (rr *NID) len() int {
- l := rr.Hdr.len()
- l += 2 // Preference
- l += 8 // NodeID
- return l
-}
-func (rr *NIMLOC) len() int {
- l := rr.Hdr.len()
- l += len(rr.Locator)/2 + 1
- return l
-}
-func (rr *NINFO) len() int {
- l := rr.Hdr.len()
- for _, x := range rr.ZSData {
- l += len(x) + 1
- }
- return l
-}
-func (rr *NS) len() int {
- l := rr.Hdr.len()
- l += len(rr.Ns) + 1
- return l
-}
-func (rr *NSAPPTR) len() int {
- l := rr.Hdr.len()
- l += len(rr.Ptr) + 1
- return l
-}
-func (rr *NSEC3PARAM) len() int {
- l := rr.Hdr.len()
- l++ // Hash
- l++ // Flags
- l += 2 // Iterations
- l++ // SaltLength
- l += len(rr.Salt) / 2
- return l
-}
-func (rr *OPENPGPKEY) len() int {
- l := rr.Hdr.len()
- l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
- return l
-}
-func (rr *PTR) len() int {
- l := rr.Hdr.len()
- l += len(rr.Ptr) + 1
- return l
-}
-func (rr *PX) len() int {
- l := rr.Hdr.len()
- l += 2 // Preference
- l += len(rr.Map822) + 1
- l += len(rr.Mapx400) + 1
- return l
-}
-func (rr *RFC3597) len() int {
- l := rr.Hdr.len()
- l += len(rr.Rdata)/2 + 1
- return l
-}
-func (rr *RKEY) len() int {
- l := rr.Hdr.len()
- l += 2 // Flags
- l++ // Protocol
- l++ // Algorithm
- l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
- return l
-}
-func (rr *RP) len() int {
- l := rr.Hdr.len()
- l += len(rr.Mbox) + 1
- l += len(rr.Txt) + 1
- return l
-}
-func (rr *RRSIG) len() int {
- l := rr.Hdr.len()
- l += 2 // TypeCovered
- l++ // Algorithm
- l++ // Labels
- l += 4 // OrigTtl
- l += 4 // Expiration
- l += 4 // Inception
- l += 2 // KeyTag
- l += len(rr.SignerName) + 1
- l += base64.StdEncoding.DecodedLen(len(rr.Signature))
- return l
-}
-func (rr *RT) len() int {
- l := rr.Hdr.len()
- l += 2 // Preference
- l += len(rr.Host) + 1
- return l
-}
-func (rr *SMIMEA) len() int {
- l := rr.Hdr.len()
- l++ // Usage
- l++ // Selector
- l++ // MatchingType
- l += len(rr.Certificate)/2 + 1
- return l
-}
-func (rr *SOA) len() int {
- l := rr.Hdr.len()
- l += len(rr.Ns) + 1
- l += len(rr.Mbox) + 1
- l += 4 // Serial
- l += 4 // Refresh
- l += 4 // Retry
- l += 4 // Expire
- l += 4 // Minttl
- return l
-}
-func (rr *SPF) len() int {
- l := rr.Hdr.len()
- for _, x := range rr.Txt {
- l += len(x) + 1
- }
- return l
-}
-func (rr *SRV) len() int {
- l := rr.Hdr.len()
- l += 2 // Priority
- l += 2 // Weight
- l += 2 // Port
- l += len(rr.Target) + 1
- return l
-}
-func (rr *SSHFP) len() int {
- l := rr.Hdr.len()
- l++ // Algorithm
- l++ // Type
- l += len(rr.FingerPrint)/2 + 1
- return l
-}
-func (rr *TA) len() int {
- l := rr.Hdr.len()
- l += 2 // KeyTag
- l++ // Algorithm
- l++ // DigestType
- l += len(rr.Digest)/2 + 1
- return l
-}
-func (rr *TALINK) len() int {
- l := rr.Hdr.len()
- l += len(rr.PreviousName) + 1
- l += len(rr.NextName) + 1
- return l
-}
-func (rr *TKEY) len() int {
- l := rr.Hdr.len()
- l += len(rr.Algorithm) + 1
- l += 4 // Inception
- l += 4 // Expiration
- l += 2 // Mode
- l += 2 // Error
- l += 2 // KeySize
- l += len(rr.Key) / 2
- l += 2 // OtherLen
- l += len(rr.OtherData) / 2
- return l
-}
-func (rr *TLSA) len() int {
- l := rr.Hdr.len()
- l++ // Usage
- l++ // Selector
- l++ // MatchingType
- l += len(rr.Certificate)/2 + 1
- return l
-}
-func (rr *TSIG) len() int {
- l := rr.Hdr.len()
- l += len(rr.Algorithm) + 1
- l += 6 // TimeSigned
- l += 2 // Fudge
- l += 2 // MACSize
- l += len(rr.MAC) / 2
- l += 2 // OrigId
- l += 2 // Error
- l += 2 // OtherLen
- l += len(rr.OtherData) / 2
- return l
-}
-func (rr *TXT) len() int {
- l := rr.Hdr.len()
- for _, x := range rr.Txt {
- l += len(x) + 1
- }
- return l
-}
-func (rr *UID) len() int {
- l := rr.Hdr.len()
- l += 4 // Uid
- return l
-}
-func (rr *UINFO) len() int {
- l := rr.Hdr.len()
- l += len(rr.Uinfo) + 1
- return l
-}
-func (rr *URI) len() int {
- l := rr.Hdr.len()
- l += 2 // Priority
- l += 2 // Weight
- l += len(rr.Target)
- return l
-}
-func (rr *X25) len() int {
- l := rr.Hdr.len()
- l += len(rr.PSDNAddress) + 1
- return l
-}
-
-// copy() functions
-func (rr *A) copy() RR {
- return &A{rr.Hdr, copyIP(rr.A)}
-}
-func (rr *AAAA) copy() RR {
- return &AAAA{rr.Hdr, copyIP(rr.AAAA)}
-}
-func (rr *AFSDB) copy() RR {
- return &AFSDB{rr.Hdr, rr.Subtype, rr.Hostname}
-}
-func (rr *ANY) copy() RR {
- return &ANY{rr.Hdr}
-}
-func (rr *AVC) copy() RR {
- Txt := make([]string, len(rr.Txt))
- copy(Txt, rr.Txt)
- return &AVC{rr.Hdr, Txt}
-}
-func (rr *CAA) copy() RR {
- return &CAA{rr.Hdr, rr.Flag, rr.Tag, rr.Value}
-}
-func (rr *CERT) copy() RR {
- return &CERT{rr.Hdr, rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
-}
-func (rr *CNAME) copy() RR {
- return &CNAME{rr.Hdr, rr.Target}
-}
-func (rr *CSYNC) copy() RR {
- TypeBitMap := make([]uint16, len(rr.TypeBitMap))
- copy(TypeBitMap, rr.TypeBitMap)
- return &CSYNC{rr.Hdr, rr.Serial, rr.Flags, TypeBitMap}
-}
-func (rr *DHCID) copy() RR {
- return &DHCID{rr.Hdr, rr.Digest}
-}
-func (rr *DNAME) copy() RR {
- return &DNAME{rr.Hdr, rr.Target}
-}
-func (rr *DNSKEY) copy() RR {
- return &DNSKEY{rr.Hdr, rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
-}
-func (rr *DS) copy() RR {
- return &DS{rr.Hdr, rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
-}
-func (rr *EID) copy() RR {
- return &EID{rr.Hdr, rr.Endpoint}
-}
-func (rr *EUI48) copy() RR {
- return &EUI48{rr.Hdr, rr.Address}
-}
-func (rr *EUI64) copy() RR {
- return &EUI64{rr.Hdr, rr.Address}
-}
-func (rr *GID) copy() RR {
- return &GID{rr.Hdr, rr.Gid}
-}
-func (rr *GPOS) copy() RR {
- return &GPOS{rr.Hdr, rr.Longitude, rr.Latitude, rr.Altitude}
-}
-func (rr *HINFO) copy() RR {
- return &HINFO{rr.Hdr, rr.Cpu, rr.Os}
-}
-func (rr *HIP) copy() RR {
- RendezvousServers := make([]string, len(rr.RendezvousServers))
- copy(RendezvousServers, rr.RendezvousServers)
- return &HIP{rr.Hdr, rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
-}
-func (rr *KX) copy() RR {
- return &KX{rr.Hdr, rr.Preference, rr.Exchanger}
-}
-func (rr *L32) copy() RR {
- return &L32{rr.Hdr, rr.Preference, copyIP(rr.Locator32)}
-}
-func (rr *L64) copy() RR {
- return &L64{rr.Hdr, rr.Preference, rr.Locator64}
-}
-func (rr *LOC) copy() RR {
- return &LOC{rr.Hdr, rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
-}
-func (rr *LP) copy() RR {
- return &LP{rr.Hdr, rr.Preference, rr.Fqdn}
-}
-func (rr *MB) copy() RR {
- return &MB{rr.Hdr, rr.Mb}
-}
-func (rr *MD) copy() RR {
- return &MD{rr.Hdr, rr.Md}
-}
-func (rr *MF) copy() RR {
- return &MF{rr.Hdr, rr.Mf}
-}
-func (rr *MG) copy() RR {
- return &MG{rr.Hdr, rr.Mg}
-}
-func (rr *MINFO) copy() RR {
- return &MINFO{rr.Hdr, rr.Rmail, rr.Email}
-}
-func (rr *MR) copy() RR {
- return &MR{rr.Hdr, rr.Mr}
-}
-func (rr *MX) copy() RR {
- return &MX{rr.Hdr, rr.Preference, rr.Mx}
-}
-func (rr *NAPTR) copy() RR {
- return &NAPTR{rr.Hdr, rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
-}
-func (rr *NID) copy() RR {
- return &NID{rr.Hdr, rr.Preference, rr.NodeID}
-}
-func (rr *NIMLOC) copy() RR {
- return &NIMLOC{rr.Hdr, rr.Locator}
-}
-func (rr *NINFO) copy() RR {
- ZSData := make([]string, len(rr.ZSData))
- copy(ZSData, rr.ZSData)
- return &NINFO{rr.Hdr, ZSData}
-}
-func (rr *NS) copy() RR {
- return &NS{rr.Hdr, rr.Ns}
-}
-func (rr *NSAPPTR) copy() RR {
- return &NSAPPTR{rr.Hdr, rr.Ptr}
-}
-func (rr *NSEC) copy() RR {
- TypeBitMap := make([]uint16, len(rr.TypeBitMap))
- copy(TypeBitMap, rr.TypeBitMap)
- return &NSEC{rr.Hdr, rr.NextDomain, TypeBitMap}
-}
-func (rr *NSEC3) copy() RR {
- TypeBitMap := make([]uint16, len(rr.TypeBitMap))
- copy(TypeBitMap, rr.TypeBitMap)
- return &NSEC3{rr.Hdr, rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap}
-}
-func (rr *NSEC3PARAM) copy() RR {
- return &NSEC3PARAM{rr.Hdr, rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
-}
-func (rr *OPENPGPKEY) copy() RR {
- return &OPENPGPKEY{rr.Hdr, rr.PublicKey}
-}
-func (rr *OPT) copy() RR {
- Option := make([]EDNS0, len(rr.Option))
- copy(Option, rr.Option)
- return &OPT{rr.Hdr, Option}
-}
-func (rr *PTR) copy() RR {
- return &PTR{rr.Hdr, rr.Ptr}
-}
-func (rr *PX) copy() RR {
- return &PX{rr.Hdr, rr.Preference, rr.Map822, rr.Mapx400}
-}
-func (rr *RFC3597) copy() RR {
- return &RFC3597{rr.Hdr, rr.Rdata}
-}
-func (rr *RKEY) copy() RR {
- return &RKEY{rr.Hdr, rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
-}
-func (rr *RP) copy() RR {
- return &RP{rr.Hdr, rr.Mbox, rr.Txt}
-}
-func (rr *RRSIG) copy() RR {
- return &RRSIG{rr.Hdr, rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
-}
-func (rr *RT) copy() RR {
- return &RT{rr.Hdr, rr.Preference, rr.Host}
-}
-func (rr *SMIMEA) copy() RR {
- return &SMIMEA{rr.Hdr, rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
-}
-func (rr *SOA) copy() RR {
- return &SOA{rr.Hdr, rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
-}
-func (rr *SPF) copy() RR {
- Txt := make([]string, len(rr.Txt))
- copy(Txt, rr.Txt)
- return &SPF{rr.Hdr, Txt}
-}
-func (rr *SRV) copy() RR {
- return &SRV{rr.Hdr, rr.Priority, rr.Weight, rr.Port, rr.Target}
-}
-func (rr *SSHFP) copy() RR {
- return &SSHFP{rr.Hdr, rr.Algorithm, rr.Type, rr.FingerPrint}
-}
-func (rr *TA) copy() RR {
- return &TA{rr.Hdr, rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
-}
-func (rr *TALINK) copy() RR {
- return &TALINK{rr.Hdr, rr.PreviousName, rr.NextName}
-}
-func (rr *TKEY) copy() RR {
- return &TKEY{rr.Hdr, rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
-}
-func (rr *TLSA) copy() RR {
- return &TLSA{rr.Hdr, rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
-}
-func (rr *TSIG) copy() RR {
- return &TSIG{rr.Hdr, rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
-}
-func (rr *TXT) copy() RR {
- Txt := make([]string, len(rr.Txt))
- copy(Txt, rr.Txt)
- return &TXT{rr.Hdr, Txt}
-}
-func (rr *UID) copy() RR {
- return &UID{rr.Hdr, rr.Uid}
-}
-func (rr *UINFO) copy() RR {
- return &UINFO{rr.Hdr, rr.Uinfo}
-}
-func (rr *URI) copy() RR {
- return &URI{rr.Hdr, rr.Priority, rr.Weight, rr.Target}
-}
-func (rr *X25) copy() RR {
- return &X25{rr.Hdr, rr.PSDNAddress}
-}
diff --git a/vendor/github.com/mitchellh/copystructure/.travis.yml b/vendor/github.com/mitchellh/copystructure/.travis.yml
deleted file mode 100644
index d7b9589ab11..00000000000
--- a/vendor/github.com/mitchellh/copystructure/.travis.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-language: go
-
-go:
- - 1.7
- - tip
-
-script:
- - go test
-
-matrix:
- allow_failures:
- - go: tip
diff --git a/vendor/github.com/mitchellh/copystructure/LICENSE b/vendor/github.com/mitchellh/copystructure/LICENSE
deleted file mode 100644
index 22985159044..00000000000
--- a/vendor/github.com/mitchellh/copystructure/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Mitchell Hashimoto
-
-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.
diff --git a/vendor/github.com/mitchellh/copystructure/README.md b/vendor/github.com/mitchellh/copystructure/README.md
deleted file mode 100644
index bcb8c8d2cb9..00000000000
--- a/vendor/github.com/mitchellh/copystructure/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# copystructure
-
-copystructure is a Go library for deep copying values in Go.
-
-This allows you to copy Go values that may contain reference values
-such as maps, slices, or pointers, and copy their data as well instead
-of just their references.
-
-## Installation
-
-Standard `go get`:
-
-```
-$ go get github.com/mitchellh/copystructure
-```
-
-## Usage & Example
-
-For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/copystructure).
-
-The `Copy` function has examples associated with it there.
diff --git a/vendor/github.com/mitchellh/copystructure/copier_time.go b/vendor/github.com/mitchellh/copystructure/copier_time.go
deleted file mode 100644
index db6a6aa1a1f..00000000000
--- a/vendor/github.com/mitchellh/copystructure/copier_time.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package copystructure
-
-import (
- "reflect"
- "time"
-)
-
-func init() {
- Copiers[reflect.TypeOf(time.Time{})] = timeCopier
-}
-
-func timeCopier(v interface{}) (interface{}, error) {
- // Just... copy it.
- return v.(time.Time), nil
-}
diff --git a/vendor/github.com/mitchellh/copystructure/copystructure.go b/vendor/github.com/mitchellh/copystructure/copystructure.go
deleted file mode 100644
index 140435255e1..00000000000
--- a/vendor/github.com/mitchellh/copystructure/copystructure.go
+++ /dev/null
@@ -1,548 +0,0 @@
-package copystructure
-
-import (
- "errors"
- "reflect"
- "sync"
-
- "github.com/mitchellh/reflectwalk"
-)
-
-// Copy returns a deep copy of v.
-func Copy(v interface{}) (interface{}, error) {
- return Config{}.Copy(v)
-}
-
-// CopierFunc is a function that knows how to deep copy a specific type.
-// Register these globally with the Copiers variable.
-type CopierFunc func(interface{}) (interface{}, error)
-
-// Copiers is a map of types that behave specially when they are copied.
-// If a type is found in this map while deep copying, this function
-// will be called to copy it instead of attempting to copy all fields.
-//
-// The key should be the type, obtained using: reflect.TypeOf(value with type).
-//
-// It is unsafe to write to this map after Copies have started. If you
-// are writing to this map while also copying, wrap all modifications to
-// this map as well as to Copy in a mutex.
-var Copiers map[reflect.Type]CopierFunc = make(map[reflect.Type]CopierFunc)
-
-// Must is a helper that wraps a call to a function returning
-// (interface{}, error) and panics if the error is non-nil. It is intended
-// for use in variable initializations and should only be used when a copy
-// error should be a crashing case.
-func Must(v interface{}, err error) interface{} {
- if err != nil {
- panic("copy error: " + err.Error())
- }
-
- return v
-}
-
-var errPointerRequired = errors.New("Copy argument must be a pointer when Lock is true")
-
-type Config struct {
- // Lock any types that are a sync.Locker and are not a mutex while copying.
- // If there is an RLocker method, use that to get the sync.Locker.
- Lock bool
-
- // Copiers is a map of types associated with a CopierFunc. Use the global
- // Copiers map if this is nil.
- Copiers map[reflect.Type]CopierFunc
-}
-
-func (c Config) Copy(v interface{}) (interface{}, error) {
- if c.Lock && reflect.ValueOf(v).Kind() != reflect.Ptr {
- return nil, errPointerRequired
- }
-
- w := new(walker)
- if c.Lock {
- w.useLocks = true
- }
-
- if c.Copiers == nil {
- c.Copiers = Copiers
- }
-
- err := reflectwalk.Walk(v, w)
- if err != nil {
- return nil, err
- }
-
- // Get the result. If the result is nil, then we want to turn it
- // into a typed nil if we can.
- result := w.Result
- if result == nil {
- val := reflect.ValueOf(v)
- result = reflect.Indirect(reflect.New(val.Type())).Interface()
- }
-
- return result, nil
-}
-
-// Return the key used to index interfaces types we've seen. Store the number
-// of pointers in the upper 32bits, and the depth in the lower 32bits. This is
-// easy to calculate, easy to match a key with our current depth, and we don't
-// need to deal with initializing and cleaning up nested maps or slices.
-func ifaceKey(pointers, depth int) uint64 {
- return uint64(pointers)<<32 | uint64(depth)
-}
-
-type walker struct {
- Result interface{}
-
- depth int
- ignoreDepth int
- vals []reflect.Value
- cs []reflect.Value
-
- // This stores the number of pointers we've walked over, indexed by depth.
- ps []int
-
- // If an interface is indirected by a pointer, we need to know the type of
- // interface to create when creating the new value. Store the interface
- // types here, indexed by both the walk depth and the number of pointers
- // already seen at that depth. Use ifaceKey to calculate the proper uint64
- // value.
- ifaceTypes map[uint64]reflect.Type
-
- // any locks we've taken, indexed by depth
- locks []sync.Locker
- // take locks while walking the structure
- useLocks bool
-}
-
-func (w *walker) Enter(l reflectwalk.Location) error {
- w.depth++
-
- // ensure we have enough elements to index via w.depth
- for w.depth >= len(w.locks) {
- w.locks = append(w.locks, nil)
- }
-
- for len(w.ps) < w.depth+1 {
- w.ps = append(w.ps, 0)
- }
-
- return nil
-}
-
-func (w *walker) Exit(l reflectwalk.Location) error {
- locker := w.locks[w.depth]
- w.locks[w.depth] = nil
- if locker != nil {
- defer locker.Unlock()
- }
-
- // clear out pointers and interfaces as we exit the stack
- w.ps[w.depth] = 0
-
- for k := range w.ifaceTypes {
- mask := uint64(^uint32(0))
- if k&mask == uint64(w.depth) {
- delete(w.ifaceTypes, k)
- }
- }
-
- w.depth--
- if w.ignoreDepth > w.depth {
- w.ignoreDepth = 0
- }
-
- if w.ignoring() {
- return nil
- }
-
- switch l {
- case reflectwalk.Array:
- fallthrough
- case reflectwalk.Map:
- fallthrough
- case reflectwalk.Slice:
- w.replacePointerMaybe()
-
- // Pop map off our container
- w.cs = w.cs[:len(w.cs)-1]
- case reflectwalk.MapValue:
- // Pop off the key and value
- mv := w.valPop()
- mk := w.valPop()
- m := w.cs[len(w.cs)-1]
-
- // If mv is the zero value, SetMapIndex deletes the key form the map,
- // or in this case never adds it. We need to create a properly typed
- // zero value so that this key can be set.
- if !mv.IsValid() {
- mv = reflect.Zero(m.Elem().Type().Elem())
- }
- m.Elem().SetMapIndex(mk, mv)
- case reflectwalk.ArrayElem:
- // Pop off the value and the index and set it on the array
- v := w.valPop()
- i := w.valPop().Interface().(int)
- if v.IsValid() {
- a := w.cs[len(w.cs)-1]
- ae := a.Elem().Index(i) // storing array as pointer on stack - so need Elem() call
- if ae.CanSet() {
- ae.Set(v)
- }
- }
- case reflectwalk.SliceElem:
- // Pop off the value and the index and set it on the slice
- v := w.valPop()
- i := w.valPop().Interface().(int)
- if v.IsValid() {
- s := w.cs[len(w.cs)-1]
- se := s.Elem().Index(i)
- if se.CanSet() {
- se.Set(v)
- }
- }
- case reflectwalk.Struct:
- w.replacePointerMaybe()
-
- // Remove the struct from the container stack
- w.cs = w.cs[:len(w.cs)-1]
- case reflectwalk.StructField:
- // Pop off the value and the field
- v := w.valPop()
- f := w.valPop().Interface().(reflect.StructField)
- if v.IsValid() {
- s := w.cs[len(w.cs)-1]
- sf := reflect.Indirect(s).FieldByName(f.Name)
-
- if sf.CanSet() {
- sf.Set(v)
- }
- }
- case reflectwalk.WalkLoc:
- // Clear out the slices for GC
- w.cs = nil
- w.vals = nil
- }
-
- return nil
-}
-
-func (w *walker) Map(m reflect.Value) error {
- if w.ignoring() {
- return nil
- }
- w.lock(m)
-
- // Create the map. If the map itself is nil, then just make a nil map
- var newMap reflect.Value
- if m.IsNil() {
- newMap = reflect.New(m.Type())
- } else {
- newMap = wrapPtr(reflect.MakeMap(m.Type()))
- }
-
- w.cs = append(w.cs, newMap)
- w.valPush(newMap)
- return nil
-}
-
-func (w *walker) MapElem(m, k, v reflect.Value) error {
- return nil
-}
-
-func (w *walker) PointerEnter(v bool) error {
- if v {
- w.ps[w.depth]++
- }
- return nil
-}
-
-func (w *walker) PointerExit(v bool) error {
- if v {
- w.ps[w.depth]--
- }
- return nil
-}
-
-func (w *walker) Interface(v reflect.Value) error {
- if !v.IsValid() {
- return nil
- }
- if w.ifaceTypes == nil {
- w.ifaceTypes = make(map[uint64]reflect.Type)
- }
-
- w.ifaceTypes[ifaceKey(w.ps[w.depth], w.depth)] = v.Type()
- return nil
-}
-
-func (w *walker) Primitive(v reflect.Value) error {
- if w.ignoring() {
- return nil
- }
- w.lock(v)
-
- // IsValid verifies the v is non-zero and CanInterface verifies
- // that we're allowed to read this value (unexported fields).
- var newV reflect.Value
- if v.IsValid() && v.CanInterface() {
- newV = reflect.New(v.Type())
- newV.Elem().Set(v)
- }
-
- w.valPush(newV)
- w.replacePointerMaybe()
- return nil
-}
-
-func (w *walker) Slice(s reflect.Value) error {
- if w.ignoring() {
- return nil
- }
- w.lock(s)
-
- var newS reflect.Value
- if s.IsNil() {
- newS = reflect.New(s.Type())
- } else {
- newS = wrapPtr(reflect.MakeSlice(s.Type(), s.Len(), s.Cap()))
- }
-
- w.cs = append(w.cs, newS)
- w.valPush(newS)
- return nil
-}
-
-func (w *walker) SliceElem(i int, elem reflect.Value) error {
- if w.ignoring() {
- return nil
- }
-
- // We don't write the slice here because elem might still be
- // arbitrarily complex. Just record the index and continue on.
- w.valPush(reflect.ValueOf(i))
-
- return nil
-}
-
-func (w *walker) Array(a reflect.Value) error {
- if w.ignoring() {
- return nil
- }
- w.lock(a)
-
- newA := reflect.New(a.Type())
-
- w.cs = append(w.cs, newA)
- w.valPush(newA)
- return nil
-}
-
-func (w *walker) ArrayElem(i int, elem reflect.Value) error {
- if w.ignoring() {
- return nil
- }
-
- // We don't write the array here because elem might still be
- // arbitrarily complex. Just record the index and continue on.
- w.valPush(reflect.ValueOf(i))
-
- return nil
-}
-
-func (w *walker) Struct(s reflect.Value) error {
- if w.ignoring() {
- return nil
- }
- w.lock(s)
-
- var v reflect.Value
- if c, ok := Copiers[s.Type()]; ok {
- // We have a Copier for this struct, so we use that copier to
- // get the copy, and we ignore anything deeper than this.
- w.ignoreDepth = w.depth
-
- dup, err := c(s.Interface())
- if err != nil {
- return err
- }
-
- // We need to put a pointer to the value on the value stack,
- // so allocate a new pointer and set it.
- v = reflect.New(s.Type())
- reflect.Indirect(v).Set(reflect.ValueOf(dup))
- } else {
- // No copier, we copy ourselves and allow reflectwalk to guide
- // us deeper into the structure for copying.
- v = reflect.New(s.Type())
- }
-
- // Push the value onto the value stack for setting the struct field,
- // and add the struct itself to the containers stack in case we walk
- // deeper so that its own fields can be modified.
- w.valPush(v)
- w.cs = append(w.cs, v)
-
- return nil
-}
-
-func (w *walker) StructField(f reflect.StructField, v reflect.Value) error {
- if w.ignoring() {
- return nil
- }
-
- // If PkgPath is non-empty, this is a private (unexported) field.
- // We do not set this unexported since the Go runtime doesn't allow us.
- if f.PkgPath != "" {
- return reflectwalk.SkipEntry
- }
-
- // Push the field onto the stack, we'll handle it when we exit
- // the struct field in Exit...
- w.valPush(reflect.ValueOf(f))
- return nil
-}
-
-// ignore causes the walker to ignore any more values until we exit this on
-func (w *walker) ignore() {
- w.ignoreDepth = w.depth
-}
-
-func (w *walker) ignoring() bool {
- return w.ignoreDepth > 0 && w.depth >= w.ignoreDepth
-}
-
-func (w *walker) pointerPeek() bool {
- return w.ps[w.depth] > 0
-}
-
-func (w *walker) valPop() reflect.Value {
- result := w.vals[len(w.vals)-1]
- w.vals = w.vals[:len(w.vals)-1]
-
- // If we're out of values, that means we popped everything off. In
- // this case, we reset the result so the next pushed value becomes
- // the result.
- if len(w.vals) == 0 {
- w.Result = nil
- }
-
- return result
-}
-
-func (w *walker) valPush(v reflect.Value) {
- w.vals = append(w.vals, v)
-
- // If we haven't set the result yet, then this is the result since
- // it is the first (outermost) value we're seeing.
- if w.Result == nil && v.IsValid() {
- w.Result = v.Interface()
- }
-}
-
-func (w *walker) replacePointerMaybe() {
- // Determine the last pointer value. If it is NOT a pointer, then
- // we need to push that onto the stack.
- if !w.pointerPeek() {
- w.valPush(reflect.Indirect(w.valPop()))
- return
- }
-
- v := w.valPop()
-
- // If the expected type is a pointer to an interface of any depth,
- // such as *interface{}, **interface{}, etc., then we need to convert
- // the value "v" from *CONCRETE to *interface{} so types match for
- // Set.
- //
- // Example if v is type *Foo where Foo is a struct, v would become
- // *interface{} instead. This only happens if we have an interface expectation
- // at this depth.
- //
- // For more info, see GH-16
- if iType, ok := w.ifaceTypes[ifaceKey(w.ps[w.depth], w.depth)]; ok && iType.Kind() == reflect.Interface {
- y := reflect.New(iType) // Create *interface{}
- y.Elem().Set(reflect.Indirect(v)) // Assign "Foo" to interface{} (dereferenced)
- v = y // v is now typed *interface{} (where *v = Foo)
- }
-
- for i := 1; i < w.ps[w.depth]; i++ {
- if iType, ok := w.ifaceTypes[ifaceKey(w.ps[w.depth]-i, w.depth)]; ok {
- iface := reflect.New(iType).Elem()
- iface.Set(v)
- v = iface
- }
-
- p := reflect.New(v.Type())
- p.Elem().Set(v)
- v = p
- }
-
- w.valPush(v)
-}
-
-// if this value is a Locker, lock it and add it to the locks slice
-func (w *walker) lock(v reflect.Value) {
- if !w.useLocks {
- return
- }
-
- if !v.IsValid() || !v.CanInterface() {
- return
- }
-
- type rlocker interface {
- RLocker() sync.Locker
- }
-
- var locker sync.Locker
-
- // We can't call Interface() on a value directly, since that requires
- // a copy. This is OK, since the pointer to a value which is a sync.Locker
- // is also a sync.Locker.
- if v.Kind() == reflect.Ptr {
- switch l := v.Interface().(type) {
- case rlocker:
- // don't lock a mutex directly
- if _, ok := l.(*sync.RWMutex); !ok {
- locker = l.RLocker()
- }
- case sync.Locker:
- locker = l
- }
- } else if v.CanAddr() {
- switch l := v.Addr().Interface().(type) {
- case rlocker:
- // don't lock a mutex directly
- if _, ok := l.(*sync.RWMutex); !ok {
- locker = l.RLocker()
- }
- case sync.Locker:
- locker = l
- }
- }
-
- // still no callable locker
- if locker == nil {
- return
- }
-
- // don't lock a mutex directly
- switch locker.(type) {
- case *sync.Mutex, *sync.RWMutex:
- return
- }
-
- locker.Lock()
- w.locks[w.depth] = locker
-}
-
-// wrapPtr is a helper that takes v and always make it *v. copystructure
-// stores things internally as pointers until the last moment before unwrapping
-func wrapPtr(v reflect.Value) reflect.Value {
- if !v.IsValid() {
- return v
- }
- vPtr := reflect.New(v.Type())
- vPtr.Elem().Set(v)
- return vPtr
-}
diff --git a/vendor/github.com/mitchellh/copystructure/go.mod b/vendor/github.com/mitchellh/copystructure/go.mod
deleted file mode 100644
index d01864309b4..00000000000
--- a/vendor/github.com/mitchellh/copystructure/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/mitchellh/copystructure
-
-require github.com/mitchellh/reflectwalk v1.0.0
diff --git a/vendor/github.com/mitchellh/copystructure/go.sum b/vendor/github.com/mitchellh/copystructure/go.sum
deleted file mode 100644
index be572456190..00000000000
--- a/vendor/github.com/mitchellh/copystructure/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
diff --git a/vendor/github.com/mitchellh/go-homedir/LICENSE b/vendor/github.com/mitchellh/go-homedir/LICENSE
deleted file mode 100644
index f9c841a51e0..00000000000
--- a/vendor/github.com/mitchellh/go-homedir/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2013 Mitchell Hashimoto
-
-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.
diff --git a/vendor/github.com/mitchellh/go-homedir/README.md b/vendor/github.com/mitchellh/go-homedir/README.md
deleted file mode 100644
index d70706d5b35..00000000000
--- a/vendor/github.com/mitchellh/go-homedir/README.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# go-homedir
-
-This is a Go library for detecting the user's home directory without
-the use of cgo, so the library can be used in cross-compilation environments.
-
-Usage is incredibly simple, just call `homedir.Dir()` to get the home directory
-for a user, and `homedir.Expand()` to expand the `~` in a path to the home
-directory.
-
-**Why not just use `os/user`?** The built-in `os/user` package requires
-cgo on Darwin systems. This means that any Go code that uses that package
-cannot cross compile. But 99% of the time the use for `os/user` is just to
-retrieve the home directory, which we can do for the current user without
-cgo. This library does that, enabling cross-compilation.
diff --git a/vendor/github.com/mitchellh/go-homedir/go.mod b/vendor/github.com/mitchellh/go-homedir/go.mod
deleted file mode 100644
index 7efa09a0432..00000000000
--- a/vendor/github.com/mitchellh/go-homedir/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/mitchellh/go-homedir
diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go
deleted file mode 100644
index 25378537ead..00000000000
--- a/vendor/github.com/mitchellh/go-homedir/homedir.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package homedir
-
-import (
- "bytes"
- "errors"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strconv"
- "strings"
- "sync"
-)
-
-// DisableCache will disable caching of the home directory. Caching is enabled
-// by default.
-var DisableCache bool
-
-var homedirCache string
-var cacheLock sync.RWMutex
-
-// Dir returns the home directory for the executing user.
-//
-// This uses an OS-specific method for discovering the home directory.
-// An error is returned if a home directory cannot be detected.
-func Dir() (string, error) {
- if !DisableCache {
- cacheLock.RLock()
- cached := homedirCache
- cacheLock.RUnlock()
- if cached != "" {
- return cached, nil
- }
- }
-
- cacheLock.Lock()
- defer cacheLock.Unlock()
-
- var result string
- var err error
- if runtime.GOOS == "windows" {
- result, err = dirWindows()
- } else {
- // Unix-like system, so just assume Unix
- result, err = dirUnix()
- }
-
- if err != nil {
- return "", err
- }
- homedirCache = result
- return result, nil
-}
-
-// Expand expands the path to include the home directory if the path
-// is prefixed with `~`. If it isn't prefixed with `~`, the path is
-// returned as-is.
-func Expand(path string) (string, error) {
- if len(path) == 0 {
- return path, nil
- }
-
- if path[0] != '~' {
- return path, nil
- }
-
- if len(path) > 1 && path[1] != '/' && path[1] != '\\' {
- return "", errors.New("cannot expand user-specific home dir")
- }
-
- dir, err := Dir()
- if err != nil {
- return "", err
- }
-
- return filepath.Join(dir, path[1:]), nil
-}
-
-// Reset clears the cache, forcing the next call to Dir to re-detect
-// the home directory. This generally never has to be called, but can be
-// useful in tests if you're modifying the home directory via the HOME
-// env var or something.
-func Reset() {
- cacheLock.Lock()
- defer cacheLock.Unlock()
- homedirCache = ""
-}
-
-func dirUnix() (string, error) {
- homeEnv := "HOME"
- if runtime.GOOS == "plan9" {
- // On plan9, env vars are lowercase.
- homeEnv = "home"
- }
-
- // First prefer the HOME environmental variable
- if home := os.Getenv(homeEnv); home != "" {
- return home, nil
- }
-
- var stdout bytes.Buffer
-
- // If that fails, try OS specific commands
- if runtime.GOOS == "darwin" {
- cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`)
- cmd.Stdout = &stdout
- if err := cmd.Run(); err == nil {
- result := strings.TrimSpace(stdout.String())
- if result != "" {
- return result, nil
- }
- }
- } else {
- cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
- cmd.Stdout = &stdout
- if err := cmd.Run(); err != nil {
- // If the error is ErrNotFound, we ignore it. Otherwise, return it.
- if err != exec.ErrNotFound {
- return "", err
- }
- } else {
- if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
- // username:password:uid:gid:gecos:home:shell
- passwdParts := strings.SplitN(passwd, ":", 7)
- if len(passwdParts) > 5 {
- return passwdParts[5], nil
- }
- }
- }
- }
-
- // If all else fails, try the shell
- stdout.Reset()
- cmd := exec.Command("sh", "-c", "cd && pwd")
- cmd.Stdout = &stdout
- if err := cmd.Run(); err != nil {
- return "", err
- }
-
- result := strings.TrimSpace(stdout.String())
- if result == "" {
- return "", errors.New("blank output when reading home directory")
- }
-
- return result, nil
-}
-
-func dirWindows() (string, error) {
- // First prefer the HOME environmental variable
- if home := os.Getenv("HOME"); home != "" {
- return home, nil
- }
-
- // Prefer standard environment variable USERPROFILE
- if home := os.Getenv("USERPROFILE"); home != "" {
- return home, nil
- }
-
- drive := os.Getenv("HOMEDRIVE")
- path := os.Getenv("HOMEPATH")
- home := drive + path
- if drive == "" || path == "" {
- return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank")
- }
-
- return home, nil
-}
diff --git a/vendor/github.com/mitchellh/mapstructure/.travis.yml b/vendor/github.com/mitchellh/mapstructure/.travis.yml
deleted file mode 100644
index b122a8e3d9f..00000000000
--- a/vendor/github.com/mitchellh/mapstructure/.travis.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-language: go
-
-go:
- - "1.11.x"
- - tip
-
-script:
- - go test
- - go test -bench . -benchmem
diff --git a/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md b/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md
deleted file mode 100644
index 0a21e2cd1b0..00000000000
--- a/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md
+++ /dev/null
@@ -1,40 +0,0 @@
-## 1.2.2
-
-* Do not add unsettable (unexported) values to the unused metadata key
- or "remain" value. [GH-150]
-
-## 1.2.1
-
-* Go modules checksum mismatch fix
-
-## 1.2.0
-
-* Added support to capture unused values in a field using the `",remain"` value
- in the mapstructure tag. There is an example to showcase usage.
-* Added `DecoderConfig` option to always squash embedded structs
-* `json.Number` can decode into `uint` types
-* Empty slices are preserved and not replaced with nil slices
-* Fix panic that can occur in when decoding a map into a nil slice of structs
-* Improved package documentation for godoc
-
-## 1.1.2
-
-* Fix error when decode hook decodes interface implementation into interface
- type. [GH-140]
-
-## 1.1.1
-
-* Fix panic that can happen in `decodePtr`
-
-## 1.1.0
-
-* Added `StringToIPHookFunc` to convert `string` to `net.IP` and `net.IPNet` [GH-133]
-* Support struct to struct decoding [GH-137]
-* If source map value is nil, then destination map value is nil (instead of empty)
-* If source slice value is nil, then destination slice value is nil (instead of empty)
-* If source pointer is nil, then destination pointer is set to nil (instead of
- allocated zero value of type)
-
-## 1.0.0
-
-* Initial tagged stable release.
diff --git a/vendor/github.com/mitchellh/mapstructure/LICENSE b/vendor/github.com/mitchellh/mapstructure/LICENSE
deleted file mode 100644
index f9c841a51e0..00000000000
--- a/vendor/github.com/mitchellh/mapstructure/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2013 Mitchell Hashimoto
-
-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.
diff --git a/vendor/github.com/mitchellh/mapstructure/README.md b/vendor/github.com/mitchellh/mapstructure/README.md
deleted file mode 100644
index 0018dc7d9f9..00000000000
--- a/vendor/github.com/mitchellh/mapstructure/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# mapstructure [![Godoc](https://godoc.org/github.com/mitchellh/mapstructure?status.svg)](https://godoc.org/github.com/mitchellh/mapstructure)
-
-mapstructure is a Go library for decoding generic map values to structures
-and vice versa, while providing helpful error handling.
-
-This library is most useful when decoding values from some data stream (JSON,
-Gob, etc.) where you don't _quite_ know the structure of the underlying data
-until you read a part of it. You can therefore read a `map[string]interface{}`
-and use this library to decode it into the proper underlying native Go
-structure.
-
-## Installation
-
-Standard `go get`:
-
-```
-$ go get github.com/mitchellh/mapstructure
-```
-
-## Usage & Example
-
-For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure).
-
-The `Decode` function has examples associated with it there.
-
-## But Why?!
-
-Go offers fantastic standard libraries for decoding formats such as JSON.
-The standard method is to have a struct pre-created, and populate that struct
-from the bytes of the encoded format. This is great, but the problem is if
-you have configuration or an encoding that changes slightly depending on
-specific fields. For example, consider this JSON:
-
-```json
-{
- "type": "person",
- "name": "Mitchell"
-}
-```
-
-Perhaps we can't populate a specific structure without first reading
-the "type" field from the JSON. We could always do two passes over the
-decoding of the JSON (reading the "type" first, and the rest later).
-However, it is much simpler to just decode this into a `map[string]interface{}`
-structure, read the "type" key, then use something like this library
-to decode it into the proper structure.
diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
deleted file mode 100644
index 1f0abc65ab7..00000000000
--- a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
+++ /dev/null
@@ -1,217 +0,0 @@
-package mapstructure
-
-import (
- "errors"
- "fmt"
- "net"
- "reflect"
- "strconv"
- "strings"
- "time"
-)
-
-// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
-// it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
-func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
- // Create variables here so we can reference them with the reflect pkg
- var f1 DecodeHookFuncType
- var f2 DecodeHookFuncKind
-
- // Fill in the variables into this interface and the rest is done
- // automatically using the reflect package.
- potential := []interface{}{f1, f2}
-
- v := reflect.ValueOf(h)
- vt := v.Type()
- for _, raw := range potential {
- pt := reflect.ValueOf(raw).Type()
- if vt.ConvertibleTo(pt) {
- return v.Convert(pt).Interface()
- }
- }
-
- return nil
-}
-
-// DecodeHookExec executes the given decode hook. This should be used
-// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
-// that took reflect.Kind instead of reflect.Type.
-func DecodeHookExec(
- raw DecodeHookFunc,
- from reflect.Type, to reflect.Type,
- data interface{}) (interface{}, error) {
- switch f := typedDecodeHook(raw).(type) {
- case DecodeHookFuncType:
- return f(from, to, data)
- case DecodeHookFuncKind:
- return f(from.Kind(), to.Kind(), data)
- default:
- return nil, errors.New("invalid decode hook signature")
- }
-}
-
-// ComposeDecodeHookFunc creates a single DecodeHookFunc that
-// automatically composes multiple DecodeHookFuncs.
-//
-// The composed funcs are called in order, with the result of the
-// previous transformation.
-func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
- return func(
- f reflect.Type,
- t reflect.Type,
- data interface{}) (interface{}, error) {
- var err error
- for _, f1 := range fs {
- data, err = DecodeHookExec(f1, f, t, data)
- if err != nil {
- return nil, err
- }
-
- // Modify the from kind to be correct with the new data
- f = nil
- if val := reflect.ValueOf(data); val.IsValid() {
- f = val.Type()
- }
- }
-
- return data, nil
- }
-}
-
-// StringToSliceHookFunc returns a DecodeHookFunc that converts
-// string to []string by splitting on the given sep.
-func StringToSliceHookFunc(sep string) DecodeHookFunc {
- return func(
- f reflect.Kind,
- t reflect.Kind,
- data interface{}) (interface{}, error) {
- if f != reflect.String || t != reflect.Slice {
- return data, nil
- }
-
- raw := data.(string)
- if raw == "" {
- return []string{}, nil
- }
-
- return strings.Split(raw, sep), nil
- }
-}
-
-// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
-// strings to time.Duration.
-func StringToTimeDurationHookFunc() DecodeHookFunc {
- return func(
- f reflect.Type,
- t reflect.Type,
- data interface{}) (interface{}, error) {
- if f.Kind() != reflect.String {
- return data, nil
- }
- if t != reflect.TypeOf(time.Duration(5)) {
- return data, nil
- }
-
- // Convert it by parsing
- return time.ParseDuration(data.(string))
- }
-}
-
-// StringToIPHookFunc returns a DecodeHookFunc that converts
-// strings to net.IP
-func StringToIPHookFunc() DecodeHookFunc {
- return func(
- f reflect.Type,
- t reflect.Type,
- data interface{}) (interface{}, error) {
- if f.Kind() != reflect.String {
- return data, nil
- }
- if t != reflect.TypeOf(net.IP{}) {
- return data, nil
- }
-
- // Convert it by parsing
- ip := net.ParseIP(data.(string))
- if ip == nil {
- return net.IP{}, fmt.Errorf("failed parsing ip %v", data)
- }
-
- return ip, nil
- }
-}
-
-// StringToIPNetHookFunc returns a DecodeHookFunc that converts
-// strings to net.IPNet
-func StringToIPNetHookFunc() DecodeHookFunc {
- return func(
- f reflect.Type,
- t reflect.Type,
- data interface{}) (interface{}, error) {
- if f.Kind() != reflect.String {
- return data, nil
- }
- if t != reflect.TypeOf(net.IPNet{}) {
- return data, nil
- }
-
- // Convert it by parsing
- _, net, err := net.ParseCIDR(data.(string))
- return net, err
- }
-}
-
-// StringToTimeHookFunc returns a DecodeHookFunc that converts
-// strings to time.Time.
-func StringToTimeHookFunc(layout string) DecodeHookFunc {
- return func(
- f reflect.Type,
- t reflect.Type,
- data interface{}) (interface{}, error) {
- if f.Kind() != reflect.String {
- return data, nil
- }
- if t != reflect.TypeOf(time.Time{}) {
- return data, nil
- }
-
- // Convert it by parsing
- return time.Parse(layout, data.(string))
- }
-}
-
-// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
-// the decoder.
-//
-// Note that this is significantly different from the WeaklyTypedInput option
-// of the DecoderConfig.
-func WeaklyTypedHook(
- f reflect.Kind,
- t reflect.Kind,
- data interface{}) (interface{}, error) {
- dataVal := reflect.ValueOf(data)
- switch t {
- case reflect.String:
- switch f {
- case reflect.Bool:
- if dataVal.Bool() {
- return "1", nil
- }
- return "0", nil
- case reflect.Float32:
- return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
- case reflect.Int:
- return strconv.FormatInt(dataVal.Int(), 10), nil
- case reflect.Slice:
- dataType := dataVal.Type()
- elemKind := dataType.Elem().Kind()
- if elemKind == reflect.Uint8 {
- return string(dataVal.Interface().([]uint8)), nil
- }
- case reflect.Uint:
- return strconv.FormatUint(dataVal.Uint(), 10), nil
- }
- }
-
- return data, nil
-}
diff --git a/vendor/github.com/mitchellh/mapstructure/error.go b/vendor/github.com/mitchellh/mapstructure/error.go
deleted file mode 100644
index 47a99e5af3f..00000000000
--- a/vendor/github.com/mitchellh/mapstructure/error.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package mapstructure
-
-import (
- "errors"
- "fmt"
- "sort"
- "strings"
-)
-
-// Error implements the error interface and can represents multiple
-// errors that occur in the course of a single decode.
-type Error struct {
- Errors []string
-}
-
-func (e *Error) Error() string {
- points := make([]string, len(e.Errors))
- for i, err := range e.Errors {
- points[i] = fmt.Sprintf("* %s", err)
- }
-
- sort.Strings(points)
- return fmt.Sprintf(
- "%d error(s) decoding:\n\n%s",
- len(e.Errors), strings.Join(points, "\n"))
-}
-
-// WrappedErrors implements the errwrap.Wrapper interface to make this
-// return value more useful with the errwrap and go-multierror libraries.
-func (e *Error) WrappedErrors() []error {
- if e == nil {
- return nil
- }
-
- result := make([]error, len(e.Errors))
- for i, e := range e.Errors {
- result[i] = errors.New(e)
- }
-
- return result
-}
-
-func appendErrors(errors []string, err error) []string {
- switch e := err.(type) {
- case *Error:
- return append(errors, e.Errors...)
- default:
- return append(errors, e.Error())
- }
-}
diff --git a/vendor/github.com/mitchellh/mapstructure/go.mod b/vendor/github.com/mitchellh/mapstructure/go.mod
deleted file mode 100644
index a03ae973088..00000000000
--- a/vendor/github.com/mitchellh/mapstructure/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/mitchellh/mapstructure
-
-go 1.14
diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go
deleted file mode 100644
index daea3318e03..00000000000
--- a/vendor/github.com/mitchellh/mapstructure/mapstructure.go
+++ /dev/null
@@ -1,1309 +0,0 @@
-// Package mapstructure exposes functionality to convert one arbitrary
-// Go type into another, typically to convert a map[string]interface{}
-// into a native Go structure.
-//
-// The Go structure can be arbitrarily complex, containing slices,
-// other structs, etc. and the decoder will properly decode nested
-// maps and so on into the proper structures in the native Go struct.
-// See the examples to see what the decoder is capable of.
-//
-// The simplest function to start with is Decode.
-//
-// Field Tags
-//
-// When decoding to a struct, mapstructure will use the field name by
-// default to perform the mapping. For example, if a struct has a field
-// "Username" then mapstructure will look for a key in the source value
-// of "username" (case insensitive).
-//
-// type User struct {
-// Username string
-// }
-//
-// You can change the behavior of mapstructure by using struct tags.
-// The default struct tag that mapstructure looks for is "mapstructure"
-// but you can customize it using DecoderConfig.
-//
-// Renaming Fields
-//
-// To rename the key that mapstructure looks for, use the "mapstructure"
-// tag and set a value directly. For example, to change the "username" example
-// above to "user":
-//
-// type User struct {
-// Username string `mapstructure:"user"`
-// }
-//
-// Embedded Structs and Squashing
-//
-// Embedded structs are treated as if they're another field with that name.
-// By default, the two structs below are equivalent when decoding with
-// mapstructure:
-//
-// type Person struct {
-// Name string
-// }
-//
-// type Friend struct {
-// Person
-// }
-//
-// type Friend struct {
-// Person Person
-// }
-//
-// This would require an input that looks like below:
-//
-// map[string]interface{}{
-// "person": map[string]interface{}{"name": "alice"},
-// }
-//
-// If your "person" value is NOT nested, then you can append ",squash" to
-// your tag value and mapstructure will treat it as if the embedded struct
-// were part of the struct directly. Example:
-//
-// type Friend struct {
-// Person `mapstructure:",squash"`
-// }
-//
-// Now the following input would be accepted:
-//
-// map[string]interface{}{
-// "name": "alice",
-// }
-//
-// DecoderConfig has a field that changes the behavior of mapstructure
-// to always squash embedded structs.
-//
-// Remainder Values
-//
-// If there are any unmapped keys in the source value, mapstructure by
-// default will silently ignore them. You can error by setting ErrorUnused
-// in DecoderConfig. If you're using Metadata you can also maintain a slice
-// of the unused keys.
-//
-// You can also use the ",remain" suffix on your tag to collect all unused
-// values in a map. The field with this tag MUST be a map type and should
-// probably be a "map[string]interface{}" or "map[interface{}]interface{}".
-// See example below:
-//
-// type Friend struct {
-// Name string
-// Other map[string]interface{} `mapstructure:",remain"`
-// }
-//
-// Given the input below, Other would be populated with the other
-// values that weren't used (everything but "name"):
-//
-// map[string]interface{}{
-// "name": "bob",
-// "address": "123 Maple St.",
-// }
-//
-// Other Configuration
-//
-// mapstructure is highly configurable. See the DecoderConfig struct
-// for other features and options that are supported.
-package mapstructure
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "reflect"
- "sort"
- "strconv"
- "strings"
-)
-
-// DecodeHookFunc is the callback function that can be used for
-// data transformations. See "DecodeHook" in the DecoderConfig
-// struct.
-//
-// The type should be DecodeHookFuncType or DecodeHookFuncKind.
-// Either is accepted. Types are a superset of Kinds (Types can return
-// Kinds) and are generally a richer thing to use, but Kinds are simpler
-// if you only need those.
-//
-// The reason DecodeHookFunc is multi-typed is for backwards compatibility:
-// we started with Kinds and then realized Types were the better solution,
-// but have a promise to not break backwards compat so we now support
-// both.
-type DecodeHookFunc interface{}
-
-// DecodeHookFuncType is a DecodeHookFunc which has complete information about
-// the source and target types.
-type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error)
-
-// DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the
-// source and target types.
-type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error)
-
-// DecoderConfig is the configuration that is used to create a new decoder
-// and allows customization of various aspects of decoding.
-type DecoderConfig struct {
- // DecodeHook, if set, will be called before any decoding and any
- // type conversion (if WeaklyTypedInput is on). This lets you modify
- // the values before they're set down onto the resulting struct.
- //
- // If an error is returned, the entire decode will fail with that
- // error.
- DecodeHook DecodeHookFunc
-
- // If ErrorUnused is true, then it is an error for there to exist
- // keys in the original map that were unused in the decoding process
- // (extra keys).
- ErrorUnused bool
-
- // ZeroFields, if set to true, will zero fields before writing them.
- // For example, a map will be emptied before decoded values are put in
- // it. If this is false, a map will be merged.
- ZeroFields bool
-
- // If WeaklyTypedInput is true, the decoder will make the following
- // "weak" conversions:
- //
- // - bools to string (true = "1", false = "0")
- // - numbers to string (base 10)
- // - bools to int/uint (true = 1, false = 0)
- // - strings to int/uint (base implied by prefix)
- // - int to bool (true if value != 0)
- // - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F,
- // FALSE, false, False. Anything else is an error)
- // - empty array = empty map and vice versa
- // - negative numbers to overflowed uint values (base 10)
- // - slice of maps to a merged map
- // - single values are converted to slices if required. Each
- // element is weakly decoded. For example: "4" can become []int{4}
- // if the target type is an int slice.
- //
- WeaklyTypedInput bool
-
- // Squash will squash embedded structs. A squash tag may also be
- // added to an individual struct field using a tag. For example:
- //
- // type Parent struct {
- // Child `mapstructure:",squash"`
- // }
- Squash bool
-
- // Metadata is the struct that will contain extra metadata about
- // the decoding. If this is nil, then no metadata will be tracked.
- Metadata *Metadata
-
- // Result is a pointer to the struct that will contain the decoded
- // value.
- Result interface{}
-
- // The tag name that mapstructure reads for field names. This
- // defaults to "mapstructure"
- TagName string
-}
-
-// A Decoder takes a raw interface value and turns it into structured
-// data, keeping track of rich error information along the way in case
-// anything goes wrong. Unlike the basic top-level Decode method, you can
-// more finely control how the Decoder behaves using the DecoderConfig
-// structure. The top-level Decode method is just a convenience that sets
-// up the most basic Decoder.
-type Decoder struct {
- config *DecoderConfig
-}
-
-// Metadata contains information about decoding a structure that
-// is tedious or difficult to get otherwise.
-type Metadata struct {
- // Keys are the keys of the structure which were successfully decoded
- Keys []string
-
- // Unused is a slice of keys that were found in the raw value but
- // weren't decoded since there was no matching field in the result interface
- Unused []string
-}
-
-// Decode takes an input structure and uses reflection to translate it to
-// the output structure. output must be a pointer to a map or struct.
-func Decode(input interface{}, output interface{}) error {
- config := &DecoderConfig{
- Metadata: nil,
- Result: output,
- }
-
- decoder, err := NewDecoder(config)
- if err != nil {
- return err
- }
-
- return decoder.Decode(input)
-}
-
-// WeakDecode is the same as Decode but is shorthand to enable
-// WeaklyTypedInput. See DecoderConfig for more info.
-func WeakDecode(input, output interface{}) error {
- config := &DecoderConfig{
- Metadata: nil,
- Result: output,
- WeaklyTypedInput: true,
- }
-
- decoder, err := NewDecoder(config)
- if err != nil {
- return err
- }
-
- return decoder.Decode(input)
-}
-
-// DecodeMetadata is the same as Decode, but is shorthand to
-// enable metadata collection. See DecoderConfig for more info.
-func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error {
- config := &DecoderConfig{
- Metadata: metadata,
- Result: output,
- }
-
- decoder, err := NewDecoder(config)
- if err != nil {
- return err
- }
-
- return decoder.Decode(input)
-}
-
-// WeakDecodeMetadata is the same as Decode, but is shorthand to
-// enable both WeaklyTypedInput and metadata collection. See
-// DecoderConfig for more info.
-func WeakDecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error {
- config := &DecoderConfig{
- Metadata: metadata,
- Result: output,
- WeaklyTypedInput: true,
- }
-
- decoder, err := NewDecoder(config)
- if err != nil {
- return err
- }
-
- return decoder.Decode(input)
-}
-
-// NewDecoder returns a new decoder for the given configuration. Once
-// a decoder has been returned, the same configuration must not be used
-// again.
-func NewDecoder(config *DecoderConfig) (*Decoder, error) {
- val := reflect.ValueOf(config.Result)
- if val.Kind() != reflect.Ptr {
- return nil, errors.New("result must be a pointer")
- }
-
- val = val.Elem()
- if !val.CanAddr() {
- return nil, errors.New("result must be addressable (a pointer)")
- }
-
- if config.Metadata != nil {
- if config.Metadata.Keys == nil {
- config.Metadata.Keys = make([]string, 0)
- }
-
- if config.Metadata.Unused == nil {
- config.Metadata.Unused = make([]string, 0)
- }
- }
-
- if config.TagName == "" {
- config.TagName = "mapstructure"
- }
-
- result := &Decoder{
- config: config,
- }
-
- return result, nil
-}
-
-// Decode decodes the given raw interface to the target pointer specified
-// by the configuration.
-func (d *Decoder) Decode(input interface{}) error {
- return d.decode("", input, reflect.ValueOf(d.config.Result).Elem())
-}
-
-// Decodes an unknown data type into a specific reflection value.
-func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error {
- var inputVal reflect.Value
- if input != nil {
- inputVal = reflect.ValueOf(input)
-
- // We need to check here if input is a typed nil. Typed nils won't
- // match the "input == nil" below so we check that here.
- if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() {
- input = nil
- }
- }
-
- if input == nil {
- // If the data is nil, then we don't set anything, unless ZeroFields is set
- // to true.
- if d.config.ZeroFields {
- outVal.Set(reflect.Zero(outVal.Type()))
-
- if d.config.Metadata != nil && name != "" {
- d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
- }
- }
- return nil
- }
-
- if !inputVal.IsValid() {
- // If the input value is invalid, then we just set the value
- // to be the zero value.
- outVal.Set(reflect.Zero(outVal.Type()))
- if d.config.Metadata != nil && name != "" {
- d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
- }
- return nil
- }
-
- if d.config.DecodeHook != nil {
- // We have a DecodeHook, so let's pre-process the input.
- var err error
- input, err = DecodeHookExec(
- d.config.DecodeHook,
- inputVal.Type(), outVal.Type(), input)
- if err != nil {
- return fmt.Errorf("error decoding '%s': %s", name, err)
- }
- }
-
- var err error
- outputKind := getKind(outVal)
- switch outputKind {
- case reflect.Bool:
- err = d.decodeBool(name, input, outVal)
- case reflect.Interface:
- err = d.decodeBasic(name, input, outVal)
- case reflect.String:
- err = d.decodeString(name, input, outVal)
- case reflect.Int:
- err = d.decodeInt(name, input, outVal)
- case reflect.Uint:
- err = d.decodeUint(name, input, outVal)
- case reflect.Float32:
- err = d.decodeFloat(name, input, outVal)
- case reflect.Struct:
- err = d.decodeStruct(name, input, outVal)
- case reflect.Map:
- err = d.decodeMap(name, input, outVal)
- case reflect.Ptr:
- err = d.decodePtr(name, input, outVal)
- case reflect.Slice:
- err = d.decodeSlice(name, input, outVal)
- case reflect.Array:
- err = d.decodeArray(name, input, outVal)
- case reflect.Func:
- err = d.decodeFunc(name, input, outVal)
- default:
- // If we reached this point then we weren't able to decode it
- return fmt.Errorf("%s: unsupported type: %s", name, outputKind)
- }
-
- // If we reached here, then we successfully decoded SOMETHING, so
- // mark the key as used if we're tracking metainput.
- if d.config.Metadata != nil && name != "" {
- d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
- }
-
- return err
-}
-
-// This decodes a basic type (bool, int, string, etc.) and sets the
-// value to "data" of that type.
-func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error {
- if val.IsValid() && val.Elem().IsValid() {
- return d.decode(name, data, val.Elem())
- }
-
- dataVal := reflect.ValueOf(data)
-
- // If the input data is a pointer, and the assigned type is the dereference
- // of that exact pointer, then indirect it so that we can assign it.
- // Example: *string to string
- if dataVal.Kind() == reflect.Ptr && dataVal.Type().Elem() == val.Type() {
- dataVal = reflect.Indirect(dataVal)
- }
-
- if !dataVal.IsValid() {
- dataVal = reflect.Zero(val.Type())
- }
-
- dataValType := dataVal.Type()
- if !dataValType.AssignableTo(val.Type()) {
- return fmt.Errorf(
- "'%s' expected type '%s', got '%s'",
- name, val.Type(), dataValType)
- }
-
- val.Set(dataVal)
- return nil
-}
-
-func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error {
- dataVal := reflect.Indirect(reflect.ValueOf(data))
- dataKind := getKind(dataVal)
-
- converted := true
- switch {
- case dataKind == reflect.String:
- val.SetString(dataVal.String())
- case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
- if dataVal.Bool() {
- val.SetString("1")
- } else {
- val.SetString("0")
- }
- case dataKind == reflect.Int && d.config.WeaklyTypedInput:
- val.SetString(strconv.FormatInt(dataVal.Int(), 10))
- case dataKind == reflect.Uint && d.config.WeaklyTypedInput:
- val.SetString(strconv.FormatUint(dataVal.Uint(), 10))
- case dataKind == reflect.Float32 && d.config.WeaklyTypedInput:
- val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64))
- case dataKind == reflect.Slice && d.config.WeaklyTypedInput,
- dataKind == reflect.Array && d.config.WeaklyTypedInput:
- dataType := dataVal.Type()
- elemKind := dataType.Elem().Kind()
- switch elemKind {
- case reflect.Uint8:
- var uints []uint8
- if dataKind == reflect.Array {
- uints = make([]uint8, dataVal.Len(), dataVal.Len())
- for i := range uints {
- uints[i] = dataVal.Index(i).Interface().(uint8)
- }
- } else {
- uints = dataVal.Interface().([]uint8)
- }
- val.SetString(string(uints))
- default:
- converted = false
- }
- default:
- converted = false
- }
-
- if !converted {
- return fmt.Errorf(
- "'%s' expected type '%s', got unconvertible type '%s'",
- name, val.Type(), dataVal.Type())
- }
-
- return nil
-}
-
-func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error {
- dataVal := reflect.Indirect(reflect.ValueOf(data))
- dataKind := getKind(dataVal)
- dataType := dataVal.Type()
-
- switch {
- case dataKind == reflect.Int:
- val.SetInt(dataVal.Int())
- case dataKind == reflect.Uint:
- val.SetInt(int64(dataVal.Uint()))
- case dataKind == reflect.Float32:
- val.SetInt(int64(dataVal.Float()))
- case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
- if dataVal.Bool() {
- val.SetInt(1)
- } else {
- val.SetInt(0)
- }
- case dataKind == reflect.String && d.config.WeaklyTypedInput:
- i, err := strconv.ParseInt(dataVal.String(), 0, val.Type().Bits())
- if err == nil {
- val.SetInt(i)
- } else {
- return fmt.Errorf("cannot parse '%s' as int: %s", name, err)
- }
- case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number":
- jn := data.(json.Number)
- i, err := jn.Int64()
- if err != nil {
- return fmt.Errorf(
- "error decoding json.Number into %s: %s", name, err)
- }
- val.SetInt(i)
- default:
- return fmt.Errorf(
- "'%s' expected type '%s', got unconvertible type '%s'",
- name, val.Type(), dataVal.Type())
- }
-
- return nil
-}
-
-func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error {
- dataVal := reflect.Indirect(reflect.ValueOf(data))
- dataKind := getKind(dataVal)
- dataType := dataVal.Type()
-
- switch {
- case dataKind == reflect.Int:
- i := dataVal.Int()
- if i < 0 && !d.config.WeaklyTypedInput {
- return fmt.Errorf("cannot parse '%s', %d overflows uint",
- name, i)
- }
- val.SetUint(uint64(i))
- case dataKind == reflect.Uint:
- val.SetUint(dataVal.Uint())
- case dataKind == reflect.Float32:
- f := dataVal.Float()
- if f < 0 && !d.config.WeaklyTypedInput {
- return fmt.Errorf("cannot parse '%s', %f overflows uint",
- name, f)
- }
- val.SetUint(uint64(f))
- case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
- if dataVal.Bool() {
- val.SetUint(1)
- } else {
- val.SetUint(0)
- }
- case dataKind == reflect.String && d.config.WeaklyTypedInput:
- i, err := strconv.ParseUint(dataVal.String(), 0, val.Type().Bits())
- if err == nil {
- val.SetUint(i)
- } else {
- return fmt.Errorf("cannot parse '%s' as uint: %s", name, err)
- }
- case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number":
- jn := data.(json.Number)
- i, err := jn.Int64()
- if err != nil {
- return fmt.Errorf(
- "error decoding json.Number into %s: %s", name, err)
- }
- if i < 0 && !d.config.WeaklyTypedInput {
- return fmt.Errorf("cannot parse '%s', %d overflows uint",
- name, i)
- }
- val.SetUint(uint64(i))
- default:
- return fmt.Errorf(
- "'%s' expected type '%s', got unconvertible type '%s'",
- name, val.Type(), dataVal.Type())
- }
-
- return nil
-}
-
-func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error {
- dataVal := reflect.Indirect(reflect.ValueOf(data))
- dataKind := getKind(dataVal)
-
- switch {
- case dataKind == reflect.Bool:
- val.SetBool(dataVal.Bool())
- case dataKind == reflect.Int && d.config.WeaklyTypedInput:
- val.SetBool(dataVal.Int() != 0)
- case dataKind == reflect.Uint && d.config.WeaklyTypedInput:
- val.SetBool(dataVal.Uint() != 0)
- case dataKind == reflect.Float32 && d.config.WeaklyTypedInput:
- val.SetBool(dataVal.Float() != 0)
- case dataKind == reflect.String && d.config.WeaklyTypedInput:
- b, err := strconv.ParseBool(dataVal.String())
- if err == nil {
- val.SetBool(b)
- } else if dataVal.String() == "" {
- val.SetBool(false)
- } else {
- return fmt.Errorf("cannot parse '%s' as bool: %s", name, err)
- }
- default:
- return fmt.Errorf(
- "'%s' expected type '%s', got unconvertible type '%s'",
- name, val.Type(), dataVal.Type())
- }
-
- return nil
-}
-
-func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error {
- dataVal := reflect.Indirect(reflect.ValueOf(data))
- dataKind := getKind(dataVal)
- dataType := dataVal.Type()
-
- switch {
- case dataKind == reflect.Int:
- val.SetFloat(float64(dataVal.Int()))
- case dataKind == reflect.Uint:
- val.SetFloat(float64(dataVal.Uint()))
- case dataKind == reflect.Float32:
- val.SetFloat(dataVal.Float())
- case dataKind == reflect.Bool && d.config.WeaklyTypedInput:
- if dataVal.Bool() {
- val.SetFloat(1)
- } else {
- val.SetFloat(0)
- }
- case dataKind == reflect.String && d.config.WeaklyTypedInput:
- f, err := strconv.ParseFloat(dataVal.String(), val.Type().Bits())
- if err == nil {
- val.SetFloat(f)
- } else {
- return fmt.Errorf("cannot parse '%s' as float: %s", name, err)
- }
- case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number":
- jn := data.(json.Number)
- i, err := jn.Float64()
- if err != nil {
- return fmt.Errorf(
- "error decoding json.Number into %s: %s", name, err)
- }
- val.SetFloat(i)
- default:
- return fmt.Errorf(
- "'%s' expected type '%s', got unconvertible type '%s'",
- name, val.Type(), dataVal.Type())
- }
-
- return nil
-}
-
-func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error {
- valType := val.Type()
- valKeyType := valType.Key()
- valElemType := valType.Elem()
-
- // By default we overwrite keys in the current map
- valMap := val
-
- // If the map is nil or we're purposely zeroing fields, make a new map
- if valMap.IsNil() || d.config.ZeroFields {
- // Make a new map to hold our result
- mapType := reflect.MapOf(valKeyType, valElemType)
- valMap = reflect.MakeMap(mapType)
- }
-
- // Check input type and based on the input type jump to the proper func
- dataVal := reflect.Indirect(reflect.ValueOf(data))
- switch dataVal.Kind() {
- case reflect.Map:
- return d.decodeMapFromMap(name, dataVal, val, valMap)
-
- case reflect.Struct:
- return d.decodeMapFromStruct(name, dataVal, val, valMap)
-
- case reflect.Array, reflect.Slice:
- if d.config.WeaklyTypedInput {
- return d.decodeMapFromSlice(name, dataVal, val, valMap)
- }
-
- fallthrough
-
- default:
- return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
- }
-}
-
-func (d *Decoder) decodeMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
- // Special case for BC reasons (covered by tests)
- if dataVal.Len() == 0 {
- val.Set(valMap)
- return nil
- }
-
- for i := 0; i < dataVal.Len(); i++ {
- err := d.decode(
- fmt.Sprintf("%s[%d]", name, i),
- dataVal.Index(i).Interface(), val)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
- valType := val.Type()
- valKeyType := valType.Key()
- valElemType := valType.Elem()
-
- // Accumulate errors
- errors := make([]string, 0)
-
- // If the input data is empty, then we just match what the input data is.
- if dataVal.Len() == 0 {
- if dataVal.IsNil() {
- if !val.IsNil() {
- val.Set(dataVal)
- }
- } else {
- // Set to empty allocated value
- val.Set(valMap)
- }
-
- return nil
- }
-
- for _, k := range dataVal.MapKeys() {
- fieldName := fmt.Sprintf("%s[%s]", name, k)
-
- // First decode the key into the proper type
- currentKey := reflect.Indirect(reflect.New(valKeyType))
- if err := d.decode(fieldName, k.Interface(), currentKey); err != nil {
- errors = appendErrors(errors, err)
- continue
- }
-
- // Next decode the data into the proper type
- v := dataVal.MapIndex(k).Interface()
- currentVal := reflect.Indirect(reflect.New(valElemType))
- if err := d.decode(fieldName, v, currentVal); err != nil {
- errors = appendErrors(errors, err)
- continue
- }
-
- valMap.SetMapIndex(currentKey, currentVal)
- }
-
- // Set the built up map to the value
- val.Set(valMap)
-
- // If we had errors, return those
- if len(errors) > 0 {
- return &Error{errors}
- }
-
- return nil
-}
-
-func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
- typ := dataVal.Type()
- for i := 0; i < typ.NumField(); i++ {
- // Get the StructField first since this is a cheap operation. If the
- // field is unexported, then ignore it.
- f := typ.Field(i)
- if f.PkgPath != "" {
- continue
- }
-
- // Next get the actual value of this field and verify it is assignable
- // to the map value.
- v := dataVal.Field(i)
- if !v.Type().AssignableTo(valMap.Type().Elem()) {
- return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem())
- }
-
- tagValue := f.Tag.Get(d.config.TagName)
- tagParts := strings.Split(tagValue, ",")
-
- // Determine the name of the key in the map
- keyName := f.Name
- if tagParts[0] != "" {
- if tagParts[0] == "-" {
- continue
- }
- keyName = tagParts[0]
- }
-
- // If Squash is set in the config, we squash the field down.
- squash := d.config.Squash && v.Kind() == reflect.Struct
- // If "squash" is specified in the tag, we squash the field down.
- if !squash {
- for _, tag := range tagParts[1:] {
- if tag == "squash" {
- squash = true
- break
- }
- }
- if squash && v.Kind() != reflect.Struct {
- return fmt.Errorf("cannot squash non-struct type '%s'", v.Type())
- }
- }
-
- switch v.Kind() {
- // this is an embedded struct, so handle it differently
- case reflect.Struct:
- x := reflect.New(v.Type())
- x.Elem().Set(v)
-
- vType := valMap.Type()
- vKeyType := vType.Key()
- vElemType := vType.Elem()
- mType := reflect.MapOf(vKeyType, vElemType)
- vMap := reflect.MakeMap(mType)
-
- err := d.decode(keyName, x.Interface(), vMap)
- if err != nil {
- return err
- }
-
- if squash {
- for _, k := range vMap.MapKeys() {
- valMap.SetMapIndex(k, vMap.MapIndex(k))
- }
- } else {
- valMap.SetMapIndex(reflect.ValueOf(keyName), vMap)
- }
-
- default:
- valMap.SetMapIndex(reflect.ValueOf(keyName), v)
- }
- }
-
- if val.CanAddr() {
- val.Set(valMap)
- }
-
- return nil
-}
-
-func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error {
- // If the input data is nil, then we want to just set the output
- // pointer to be nil as well.
- isNil := data == nil
- if !isNil {
- switch v := reflect.Indirect(reflect.ValueOf(data)); v.Kind() {
- case reflect.Chan,
- reflect.Func,
- reflect.Interface,
- reflect.Map,
- reflect.Ptr,
- reflect.Slice:
- isNil = v.IsNil()
- }
- }
- if isNil {
- if !val.IsNil() && val.CanSet() {
- nilValue := reflect.New(val.Type()).Elem()
- val.Set(nilValue)
- }
-
- return nil
- }
-
- // Create an element of the concrete (non pointer) type and decode
- // into that. Then set the value of the pointer to this type.
- valType := val.Type()
- valElemType := valType.Elem()
- if val.CanSet() {
- realVal := val
- if realVal.IsNil() || d.config.ZeroFields {
- realVal = reflect.New(valElemType)
- }
-
- if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {
- return err
- }
-
- val.Set(realVal)
- } else {
- if err := d.decode(name, data, reflect.Indirect(val)); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error {
- // Create an element of the concrete (non pointer) type and decode
- // into that. Then set the value of the pointer to this type.
- dataVal := reflect.Indirect(reflect.ValueOf(data))
- if val.Type() != dataVal.Type() {
- return fmt.Errorf(
- "'%s' expected type '%s', got unconvertible type '%s'",
- name, val.Type(), dataVal.Type())
- }
- val.Set(dataVal)
- return nil
-}
-
-func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error {
- dataVal := reflect.Indirect(reflect.ValueOf(data))
- dataValKind := dataVal.Kind()
- valType := val.Type()
- valElemType := valType.Elem()
- sliceType := reflect.SliceOf(valElemType)
-
- // If we have a non array/slice type then we first attempt to convert.
- if dataValKind != reflect.Array && dataValKind != reflect.Slice {
- if d.config.WeaklyTypedInput {
- switch {
- // Slice and array we use the normal logic
- case dataValKind == reflect.Slice, dataValKind == reflect.Array:
- break
-
- // Empty maps turn into empty slices
- case dataValKind == reflect.Map:
- if dataVal.Len() == 0 {
- val.Set(reflect.MakeSlice(sliceType, 0, 0))
- return nil
- }
- // Create slice of maps of other sizes
- return d.decodeSlice(name, []interface{}{data}, val)
-
- case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8:
- return d.decodeSlice(name, []byte(dataVal.String()), val)
-
- // All other types we try to convert to the slice type
- // and "lift" it into it. i.e. a string becomes a string slice.
- default:
- // Just re-try this function with data as a slice.
- return d.decodeSlice(name, []interface{}{data}, val)
- }
- }
-
- return fmt.Errorf(
- "'%s': source data must be an array or slice, got %s", name, dataValKind)
- }
-
- // If the input value is nil, then don't allocate since empty != nil
- if dataVal.IsNil() {
- return nil
- }
-
- valSlice := val
- if valSlice.IsNil() || d.config.ZeroFields {
- // Make a new slice to hold our result, same size as the original data.
- valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
- }
-
- // Accumulate any errors
- errors := make([]string, 0)
-
- for i := 0; i < dataVal.Len(); i++ {
- currentData := dataVal.Index(i).Interface()
- for valSlice.Len() <= i {
- valSlice = reflect.Append(valSlice, reflect.Zero(valElemType))
- }
- currentField := valSlice.Index(i)
-
- fieldName := fmt.Sprintf("%s[%d]", name, i)
- if err := d.decode(fieldName, currentData, currentField); err != nil {
- errors = appendErrors(errors, err)
- }
- }
-
- // Finally, set the value to the slice we built up
- val.Set(valSlice)
-
- // If there were errors, we return those
- if len(errors) > 0 {
- return &Error{errors}
- }
-
- return nil
-}
-
-func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) error {
- dataVal := reflect.Indirect(reflect.ValueOf(data))
- dataValKind := dataVal.Kind()
- valType := val.Type()
- valElemType := valType.Elem()
- arrayType := reflect.ArrayOf(valType.Len(), valElemType)
-
- valArray := val
-
- if valArray.Interface() == reflect.Zero(valArray.Type()).Interface() || d.config.ZeroFields {
- // Check input type
- if dataValKind != reflect.Array && dataValKind != reflect.Slice {
- if d.config.WeaklyTypedInput {
- switch {
- // Empty maps turn into empty arrays
- case dataValKind == reflect.Map:
- if dataVal.Len() == 0 {
- val.Set(reflect.Zero(arrayType))
- return nil
- }
-
- // All other types we try to convert to the array type
- // and "lift" it into it. i.e. a string becomes a string array.
- default:
- // Just re-try this function with data as a slice.
- return d.decodeArray(name, []interface{}{data}, val)
- }
- }
-
- return fmt.Errorf(
- "'%s': source data must be an array or slice, got %s", name, dataValKind)
-
- }
- if dataVal.Len() > arrayType.Len() {
- return fmt.Errorf(
- "'%s': expected source data to have length less or equal to %d, got %d", name, arrayType.Len(), dataVal.Len())
-
- }
-
- // Make a new array to hold our result, same size as the original data.
- valArray = reflect.New(arrayType).Elem()
- }
-
- // Accumulate any errors
- errors := make([]string, 0)
-
- for i := 0; i < dataVal.Len(); i++ {
- currentData := dataVal.Index(i).Interface()
- currentField := valArray.Index(i)
-
- fieldName := fmt.Sprintf("%s[%d]", name, i)
- if err := d.decode(fieldName, currentData, currentField); err != nil {
- errors = appendErrors(errors, err)
- }
- }
-
- // Finally, set the value to the array we built up
- val.Set(valArray)
-
- // If there were errors, we return those
- if len(errors) > 0 {
- return &Error{errors}
- }
-
- return nil
-}
-
-func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error {
- dataVal := reflect.Indirect(reflect.ValueOf(data))
-
- // If the type of the value to write to and the data match directly,
- // then we just set it directly instead of recursing into the structure.
- if dataVal.Type() == val.Type() {
- val.Set(dataVal)
- return nil
- }
-
- dataValKind := dataVal.Kind()
- switch dataValKind {
- case reflect.Map:
- return d.decodeStructFromMap(name, dataVal, val)
-
- case reflect.Struct:
- // Not the most efficient way to do this but we can optimize later if
- // we want to. To convert from struct to struct we go to map first
- // as an intermediary.
- m := make(map[string]interface{})
- mval := reflect.Indirect(reflect.ValueOf(&m))
- if err := d.decodeMapFromStruct(name, dataVal, mval, mval); err != nil {
- return err
- }
-
- result := d.decodeStructFromMap(name, mval, val)
- return result
-
- default:
- return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
- }
-}
-
-func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) error {
- dataValType := dataVal.Type()
- if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface {
- return fmt.Errorf(
- "'%s' needs a map with string keys, has '%s' keys",
- name, dataValType.Key().Kind())
- }
-
- dataValKeys := make(map[reflect.Value]struct{})
- dataValKeysUnused := make(map[interface{}]struct{})
- for _, dataValKey := range dataVal.MapKeys() {
- dataValKeys[dataValKey] = struct{}{}
- dataValKeysUnused[dataValKey.Interface()] = struct{}{}
- }
-
- errors := make([]string, 0)
-
- // This slice will keep track of all the structs we'll be decoding.
- // There can be more than one struct if there are embedded structs
- // that are squashed.
- structs := make([]reflect.Value, 1, 5)
- structs[0] = val
-
- // Compile the list of all the fields that we're going to be decoding
- // from all the structs.
- type field struct {
- field reflect.StructField
- val reflect.Value
- }
-
- // remainField is set to a valid field set with the "remain" tag if
- // we are keeping track of remaining values.
- var remainField *field
-
- fields := []field{}
- for len(structs) > 0 {
- structVal := structs[0]
- structs = structs[1:]
-
- structType := structVal.Type()
-
- for i := 0; i < structType.NumField(); i++ {
- fieldType := structType.Field(i)
- fieldKind := fieldType.Type.Kind()
-
- // If "squash" is specified in the tag, we squash the field down.
- squash := d.config.Squash && fieldKind == reflect.Struct
- remain := false
-
- // We always parse the tags cause we're looking for other tags too
- tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
- for _, tag := range tagParts[1:] {
- if tag == "squash" {
- squash = true
- break
- }
-
- if tag == "remain" {
- remain = true
- break
- }
- }
-
- if squash {
- if fieldKind != reflect.Struct {
- errors = appendErrors(errors,
- fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldKind))
- } else {
- structs = append(structs, structVal.FieldByName(fieldType.Name))
- }
- continue
- }
-
- // Build our field
- fieldCurrent := field{fieldType, structVal.Field(i)}
- if remain {
- remainField = &fieldCurrent
- } else {
- // Normal struct field, store it away
- fields = append(fields, field{fieldType, structVal.Field(i)})
- }
- }
- }
-
- // for fieldType, field := range fields {
- for _, f := range fields {
- field, fieldValue := f.field, f.val
- fieldName := field.Name
-
- tagValue := field.Tag.Get(d.config.TagName)
- tagValue = strings.SplitN(tagValue, ",", 2)[0]
- if tagValue != "" {
- fieldName = tagValue
- }
-
- rawMapKey := reflect.ValueOf(fieldName)
- rawMapVal := dataVal.MapIndex(rawMapKey)
- if !rawMapVal.IsValid() {
- // Do a slower search by iterating over each key and
- // doing case-insensitive search.
- for dataValKey := range dataValKeys {
- mK, ok := dataValKey.Interface().(string)
- if !ok {
- // Not a string key
- continue
- }
-
- if strings.EqualFold(mK, fieldName) {
- rawMapKey = dataValKey
- rawMapVal = dataVal.MapIndex(dataValKey)
- break
- }
- }
-
- if !rawMapVal.IsValid() {
- // There was no matching key in the map for the value in
- // the struct. Just ignore.
- continue
- }
- }
-
- if !fieldValue.IsValid() {
- // This should never happen
- panic("field is not valid")
- }
-
- // If we can't set the field, then it is unexported or something,
- // and we just continue onwards.
- if !fieldValue.CanSet() {
- continue
- }
-
- // Delete the key we're using from the unused map so we stop tracking
- delete(dataValKeysUnused, rawMapKey.Interface())
-
- // If the name is empty string, then we're at the root, and we
- // don't dot-join the fields.
- if name != "" {
- fieldName = fmt.Sprintf("%s.%s", name, fieldName)
- }
-
- if err := d.decode(fieldName, rawMapVal.Interface(), fieldValue); err != nil {
- errors = appendErrors(errors, err)
- }
- }
-
- // If we have a "remain"-tagged field and we have unused keys then
- // we put the unused keys directly into the remain field.
- if remainField != nil && len(dataValKeysUnused) > 0 {
- // Build a map of only the unused values
- remain := map[interface{}]interface{}{}
- for key := range dataValKeysUnused {
- remain[key] = dataVal.MapIndex(reflect.ValueOf(key)).Interface()
- }
-
- // Decode it as-if we were just decoding this map onto our map.
- if err := d.decodeMap(name, remain, remainField.val); err != nil {
- errors = appendErrors(errors, err)
- }
-
- // Set the map to nil so we have none so that the next check will
- // not error (ErrorUnused)
- dataValKeysUnused = nil
- }
-
- if d.config.ErrorUnused && len(dataValKeysUnused) > 0 {
- keys := make([]string, 0, len(dataValKeysUnused))
- for rawKey := range dataValKeysUnused {
- keys = append(keys, rawKey.(string))
- }
- sort.Strings(keys)
-
- err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", "))
- errors = appendErrors(errors, err)
- }
-
- if len(errors) > 0 {
- return &Error{errors}
- }
-
- // Add the unused keys to the list of unused keys if we're tracking metadata
- if d.config.Metadata != nil {
- for rawKey := range dataValKeysUnused {
- key := rawKey.(string)
- if name != "" {
- key = fmt.Sprintf("%s.%s", name, key)
- }
-
- d.config.Metadata.Unused = append(d.config.Metadata.Unused, key)
- }
- }
-
- return nil
-}
-
-func getKind(val reflect.Value) reflect.Kind {
- kind := val.Kind()
-
- switch {
- case kind >= reflect.Int && kind <= reflect.Int64:
- return reflect.Int
- case kind >= reflect.Uint && kind <= reflect.Uint64:
- return reflect.Uint
- case kind >= reflect.Float32 && kind <= reflect.Float64:
- return reflect.Float32
- default:
- return kind
- }
-}
diff --git a/vendor/github.com/mitchellh/reflectwalk/.travis.yml b/vendor/github.com/mitchellh/reflectwalk/.travis.yml
deleted file mode 100644
index 4f2ee4d9733..00000000000
--- a/vendor/github.com/mitchellh/reflectwalk/.travis.yml
+++ /dev/null
@@ -1 +0,0 @@
-language: go
diff --git a/vendor/github.com/mitchellh/reflectwalk/LICENSE b/vendor/github.com/mitchellh/reflectwalk/LICENSE
deleted file mode 100644
index f9c841a51e0..00000000000
--- a/vendor/github.com/mitchellh/reflectwalk/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2013 Mitchell Hashimoto
-
-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.
diff --git a/vendor/github.com/mitchellh/reflectwalk/README.md b/vendor/github.com/mitchellh/reflectwalk/README.md
deleted file mode 100644
index ac82cd2e159..00000000000
--- a/vendor/github.com/mitchellh/reflectwalk/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# reflectwalk
-
-reflectwalk is a Go library for "walking" a value in Go using reflection,
-in the same way a directory tree can be "walked" on the filesystem. Walking
-a complex structure can allow you to do manipulations on unknown structures
-such as those decoded from JSON.
diff --git a/vendor/github.com/mitchellh/reflectwalk/go.mod b/vendor/github.com/mitchellh/reflectwalk/go.mod
deleted file mode 100644
index 52bb7c469e9..00000000000
--- a/vendor/github.com/mitchellh/reflectwalk/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/mitchellh/reflectwalk
diff --git a/vendor/github.com/mitchellh/reflectwalk/location.go b/vendor/github.com/mitchellh/reflectwalk/location.go
deleted file mode 100644
index 6a7f176117f..00000000000
--- a/vendor/github.com/mitchellh/reflectwalk/location.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package reflectwalk
-
-//go:generate stringer -type=Location location.go
-
-type Location uint
-
-const (
- None Location = iota
- Map
- MapKey
- MapValue
- Slice
- SliceElem
- Array
- ArrayElem
- Struct
- StructField
- WalkLoc
-)
diff --git a/vendor/github.com/mitchellh/reflectwalk/location_string.go b/vendor/github.com/mitchellh/reflectwalk/location_string.go
deleted file mode 100644
index 70760cf4c70..00000000000
--- a/vendor/github.com/mitchellh/reflectwalk/location_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Code generated by "stringer -type=Location location.go"; DO NOT EDIT.
-
-package reflectwalk
-
-import "fmt"
-
-const _Location_name = "NoneMapMapKeyMapValueSliceSliceElemArrayArrayElemStructStructFieldWalkLoc"
-
-var _Location_index = [...]uint8{0, 4, 7, 13, 21, 26, 35, 40, 49, 55, 66, 73}
-
-func (i Location) String() string {
- if i >= Location(len(_Location_index)-1) {
- return fmt.Sprintf("Location(%d)", i)
- }
- return _Location_name[_Location_index[i]:_Location_index[i+1]]
-}
diff --git a/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go b/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go
deleted file mode 100644
index d7ab7b6d782..00000000000
--- a/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go
+++ /dev/null
@@ -1,401 +0,0 @@
-// reflectwalk is a package that allows you to "walk" complex structures
-// similar to how you may "walk" a filesystem: visiting every element one
-// by one and calling callback functions allowing you to handle and manipulate
-// those elements.
-package reflectwalk
-
-import (
- "errors"
- "reflect"
-)
-
-// PrimitiveWalker implementations are able to handle primitive values
-// within complex structures. Primitive values are numbers, strings,
-// booleans, funcs, chans.
-//
-// These primitive values are often members of more complex
-// structures (slices, maps, etc.) that are walkable by other interfaces.
-type PrimitiveWalker interface {
- Primitive(reflect.Value) error
-}
-
-// InterfaceWalker implementations are able to handle interface values as they
-// are encountered during the walk.
-type InterfaceWalker interface {
- Interface(reflect.Value) error
-}
-
-// MapWalker implementations are able to handle individual elements
-// found within a map structure.
-type MapWalker interface {
- Map(m reflect.Value) error
- MapElem(m, k, v reflect.Value) error
-}
-
-// SliceWalker implementations are able to handle slice elements found
-// within complex structures.
-type SliceWalker interface {
- Slice(reflect.Value) error
- SliceElem(int, reflect.Value) error
-}
-
-// ArrayWalker implementations are able to handle array elements found
-// within complex structures.
-type ArrayWalker interface {
- Array(reflect.Value) error
- ArrayElem(int, reflect.Value) error
-}
-
-// StructWalker is an interface that has methods that are called for
-// structs when a Walk is done.
-type StructWalker interface {
- Struct(reflect.Value) error
- StructField(reflect.StructField, reflect.Value) error
-}
-
-// EnterExitWalker implementations are notified before and after
-// they walk deeper into complex structures (into struct fields,
-// into slice elements, etc.)
-type EnterExitWalker interface {
- Enter(Location) error
- Exit(Location) error
-}
-
-// PointerWalker implementations are notified when the value they're
-// walking is a pointer or not. Pointer is called for _every_ value whether
-// it is a pointer or not.
-type PointerWalker interface {
- PointerEnter(bool) error
- PointerExit(bool) error
-}
-
-// SkipEntry can be returned from walk functions to skip walking
-// the value of this field. This is only valid in the following functions:
-//
-// - Struct: skips all fields from being walked
-// - StructField: skips walking the struct value
-//
-var SkipEntry = errors.New("skip this entry")
-
-// Walk takes an arbitrary value and an interface and traverses the
-// value, calling callbacks on the interface if they are supported.
-// The interface should implement one or more of the walker interfaces
-// in this package, such as PrimitiveWalker, StructWalker, etc.
-func Walk(data, walker interface{}) (err error) {
- v := reflect.ValueOf(data)
- ew, ok := walker.(EnterExitWalker)
- if ok {
- err = ew.Enter(WalkLoc)
- }
-
- if err == nil {
- err = walk(v, walker)
- }
-
- if ok && err == nil {
- err = ew.Exit(WalkLoc)
- }
-
- return
-}
-
-func walk(v reflect.Value, w interface{}) (err error) {
- // Determine if we're receiving a pointer and if so notify the walker.
- // The logic here is convoluted but very important (tests will fail if
- // almost any part is changed). I will try to explain here.
- //
- // First, we check if the value is an interface, if so, we really need
- // to check the interface's VALUE to see whether it is a pointer.
- //
- // Check whether the value is then a pointer. If so, then set pointer
- // to true to notify the user.
- //
- // If we still have a pointer or an interface after the indirections, then
- // we unwrap another level
- //
- // At this time, we also set "v" to be the dereferenced value. This is
- // because once we've unwrapped the pointer we want to use that value.
- pointer := false
- pointerV := v
-
- for {
- if pointerV.Kind() == reflect.Interface {
- if iw, ok := w.(InterfaceWalker); ok {
- if err = iw.Interface(pointerV); err != nil {
- return
- }
- }
-
- pointerV = pointerV.Elem()
- }
-
- if pointerV.Kind() == reflect.Ptr {
- pointer = true
- v = reflect.Indirect(pointerV)
- }
- if pw, ok := w.(PointerWalker); ok {
- if err = pw.PointerEnter(pointer); err != nil {
- return
- }
-
- defer func(pointer bool) {
- if err != nil {
- return
- }
-
- err = pw.PointerExit(pointer)
- }(pointer)
- }
-
- if pointer {
- pointerV = v
- }
- pointer = false
-
- // If we still have a pointer or interface we have to indirect another level.
- switch pointerV.Kind() {
- case reflect.Ptr, reflect.Interface:
- continue
- }
- break
- }
-
- // We preserve the original value here because if it is an interface
- // type, we want to pass that directly into the walkPrimitive, so that
- // we can set it.
- originalV := v
- if v.Kind() == reflect.Interface {
- v = v.Elem()
- }
-
- k := v.Kind()
- if k >= reflect.Int && k <= reflect.Complex128 {
- k = reflect.Int
- }
-
- switch k {
- // Primitives
- case reflect.Bool, reflect.Chan, reflect.Func, reflect.Int, reflect.String, reflect.Invalid:
- err = walkPrimitive(originalV, w)
- return
- case reflect.Map:
- err = walkMap(v, w)
- return
- case reflect.Slice:
- err = walkSlice(v, w)
- return
- case reflect.Struct:
- err = walkStruct(v, w)
- return
- case reflect.Array:
- err = walkArray(v, w)
- return
- default:
- panic("unsupported type: " + k.String())
- }
-}
-
-func walkMap(v reflect.Value, w interface{}) error {
- ew, ewok := w.(EnterExitWalker)
- if ewok {
- ew.Enter(Map)
- }
-
- if mw, ok := w.(MapWalker); ok {
- if err := mw.Map(v); err != nil {
- return err
- }
- }
-
- for _, k := range v.MapKeys() {
- kv := v.MapIndex(k)
-
- if mw, ok := w.(MapWalker); ok {
- if err := mw.MapElem(v, k, kv); err != nil {
- return err
- }
- }
-
- ew, ok := w.(EnterExitWalker)
- if ok {
- ew.Enter(MapKey)
- }
-
- if err := walk(k, w); err != nil {
- return err
- }
-
- if ok {
- ew.Exit(MapKey)
- ew.Enter(MapValue)
- }
-
- if err := walk(kv, w); err != nil {
- return err
- }
-
- if ok {
- ew.Exit(MapValue)
- }
- }
-
- if ewok {
- ew.Exit(Map)
- }
-
- return nil
-}
-
-func walkPrimitive(v reflect.Value, w interface{}) error {
- if pw, ok := w.(PrimitiveWalker); ok {
- return pw.Primitive(v)
- }
-
- return nil
-}
-
-func walkSlice(v reflect.Value, w interface{}) (err error) {
- ew, ok := w.(EnterExitWalker)
- if ok {
- ew.Enter(Slice)
- }
-
- if sw, ok := w.(SliceWalker); ok {
- if err := sw.Slice(v); err != nil {
- return err
- }
- }
-
- for i := 0; i < v.Len(); i++ {
- elem := v.Index(i)
-
- if sw, ok := w.(SliceWalker); ok {
- if err := sw.SliceElem(i, elem); err != nil {
- return err
- }
- }
-
- ew, ok := w.(EnterExitWalker)
- if ok {
- ew.Enter(SliceElem)
- }
-
- if err := walk(elem, w); err != nil {
- return err
- }
-
- if ok {
- ew.Exit(SliceElem)
- }
- }
-
- ew, ok = w.(EnterExitWalker)
- if ok {
- ew.Exit(Slice)
- }
-
- return nil
-}
-
-func walkArray(v reflect.Value, w interface{}) (err error) {
- ew, ok := w.(EnterExitWalker)
- if ok {
- ew.Enter(Array)
- }
-
- if aw, ok := w.(ArrayWalker); ok {
- if err := aw.Array(v); err != nil {
- return err
- }
- }
-
- for i := 0; i < v.Len(); i++ {
- elem := v.Index(i)
-
- if aw, ok := w.(ArrayWalker); ok {
- if err := aw.ArrayElem(i, elem); err != nil {
- return err
- }
- }
-
- ew, ok := w.(EnterExitWalker)
- if ok {
- ew.Enter(ArrayElem)
- }
-
- if err := walk(elem, w); err != nil {
- return err
- }
-
- if ok {
- ew.Exit(ArrayElem)
- }
- }
-
- ew, ok = w.(EnterExitWalker)
- if ok {
- ew.Exit(Array)
- }
-
- return nil
-}
-
-func walkStruct(v reflect.Value, w interface{}) (err error) {
- ew, ewok := w.(EnterExitWalker)
- if ewok {
- ew.Enter(Struct)
- }
-
- skip := false
- if sw, ok := w.(StructWalker); ok {
- err = sw.Struct(v)
- if err == SkipEntry {
- skip = true
- err = nil
- }
- if err != nil {
- return
- }
- }
-
- if !skip {
- vt := v.Type()
- for i := 0; i < vt.NumField(); i++ {
- sf := vt.Field(i)
- f := v.FieldByIndex([]int{i})
-
- if sw, ok := w.(StructWalker); ok {
- err = sw.StructField(sf, f)
-
- // SkipEntry just pretends this field doesn't even exist
- if err == SkipEntry {
- continue
- }
-
- if err != nil {
- return
- }
- }
-
- ew, ok := w.(EnterExitWalker)
- if ok {
- ew.Enter(StructField)
- }
-
- err = walk(f, w)
- if err != nil {
- return
- }
-
- if ok {
- ew.Exit(StructField)
- }
- }
- }
-
- if ewok {
- ew.Exit(Struct)
- }
-
- return nil
-}
diff --git a/vendor/github.com/nats-io/jwt/.gitignore b/vendor/github.com/nats-io/jwt/.gitignore
deleted file mode 100644
index 7117a67811d..00000000000
--- a/vendor/github.com/nats-io/jwt/.gitignore
+++ /dev/null
@@ -1,16 +0,0 @@
-# Binaries for programs and plugins
-*.exe
-*.exe~
-*.dll
-*.so
-*.dylib
-
-# Test binary, build with `go test -c`
-*.test
-
-# Output of the go coverage tool, specifically when used with LiteIDE
-*.out
-
-# IDE Files
-.vscode
-.idea/
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/jwt/.travis.yml b/vendor/github.com/nats-io/jwt/.travis.yml
deleted file mode 100644
index 50e27a6b68a..00000000000
--- a/vendor/github.com/nats-io/jwt/.travis.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-language: go
-sudo: false
-go:
-- 1.13.x
-- 1.12.x
-
-install:
-- go get -t ./...
-- go get github.com/mattn/goveralls
-- go get github.com/wadey/gocovmerge
-- go get -u honnef.co/go/tools/cmd/staticcheck
-- go get -u github.com/client9/misspell/cmd/misspell
-
-before_script:
-- $(exit $(go fmt ./... | wc -l))
-- go vet ./...
-- misspell -error -locale US .
-- staticcheck ./...
-
-script:
-- go test -v -race ./...
-- if [[ "$TRAVIS_GO_VERSION" =~ 1.12 ]]; then ./scripts/cov.sh TRAVIS; fi
diff --git a/vendor/github.com/nats-io/jwt/LICENSE b/vendor/github.com/nats-io/jwt/LICENSE
deleted file mode 100644
index 261eeb9e9f8..00000000000
--- a/vendor/github.com/nats-io/jwt/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/nats-io/jwt/Makefile b/vendor/github.com/nats-io/jwt/Makefile
deleted file mode 100644
index 95e468e15b9..00000000000
--- a/vendor/github.com/nats-io/jwt/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-.PHONY: test cover
-
-build:
- go build
-
-test:
- gofmt -s -w *.go
- goimports -w *.go
- go vet ./...
- go test -v
- go test -v --race
- staticcheck ./...
-
-fmt:
- gofmt -w -s *.go
-
-cover:
- go test -v -covermode=count -coverprofile=coverage.out
- go tool cover -html=coverage.out
diff --git a/vendor/github.com/nats-io/jwt/README.md b/vendor/github.com/nats-io/jwt/README.md
deleted file mode 100644
index d3cb88ac283..00000000000
--- a/vendor/github.com/nats-io/jwt/README.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# JWT
-A [JWT](https://jwt.io/) implementation that uses [nkeys](https://github.com/nats-io/nkeys) to digitally sign JWT tokens.
-Nkeys use [Ed25519](https://ed25519.cr.yp.to/) to provide authentication of JWT claims.
-
-
-[![License Apache 2](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
-[![ReportCard](http://goreportcard.com/badge/nats-io/jwt)](http://goreportcard.com/report/nats-io/jwt)
-[![Build Status](https://travis-ci.org/nats-io/jwt.svg?branch=master)](http://travis-ci.org/nats-io/jwt)
-[![GoDoc](http://godoc.org/github.com/nats-io/jwt?status.png)](http://godoc.org/github.com/nats-io/jwt)
-[![Coverage Status](https://coveralls.io/repos/github/nats-io/jwt/badge.svg?branch=master&t=NmEFup)](https://coveralls.io/github/nats-io/jwt?branch=master)
-
-```go
-// Need a private key to sign the claim, nkeys makes it easy to create
-kp, err := nkeys.CreateAccount()
-if err != nil {
- t.Fatal("unable to create account key", err)
-}
-
-pk, err := kp.PublicKey()
-if err != nil {
- t.Fatal("error getting public key", err)
-}
-
-// create a new claim
-claims := NewAccountClaims(pk)
-claims.Expires = time.Now().Add(time.Duration(time.Hour)).Unix()
-
-
-// add details by modifying claims.Account
-
-// serialize the claim to a JWT token
-token, err := claims.Encode(kp)
-if err != nil {
- t.Fatal("error encoding token", err)
-}
-
-// on the receiving side, decode the token
-c, err := DecodeAccountClaims(token)
-if err != nil {
- t.Fatal(err)
-}
-
-// if the token was decoded, it means that it
-// validated and it wasn't tampered. the remaining and
-// required test is to insure the issuer is trusted
-pk, err := kp.PublicKey()
-if err != nil {
- t.Fatalf("unable to read public key: %v", err)
-}
-
-if c.Issuer != pk {
- t.Fatalf("the public key is not trusted")
-}
-```
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/jwt/ReleaseNotes.md b/vendor/github.com/nats-io/jwt/ReleaseNotes.md
deleted file mode 100644
index 500965eaf1d..00000000000
--- a/vendor/github.com/nats-io/jwt/ReleaseNotes.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Release Notes
-
-## 0.3.0
-
-* Removed revocation claims in favor of timestamp-based revocation maps in account and export claims.
diff --git a/vendor/github.com/nats-io/jwt/account_claims.go b/vendor/github.com/nats-io/jwt/account_claims.go
deleted file mode 100644
index 945bd98792f..00000000000
--- a/vendor/github.com/nats-io/jwt/account_claims.go
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright 2018-2019 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "errors"
- "sort"
- "time"
-
- "github.com/nats-io/nkeys"
-)
-
-// NoLimit is used to indicate a limit field is unlimited in value.
-const NoLimit = -1
-
-// OperatorLimits are used to limit access by an account
-type OperatorLimits struct {
- Subs int64 `json:"subs,omitempty"` // Max number of subscriptions
- Conn int64 `json:"conn,omitempty"` // Max number of active connections
- LeafNodeConn int64 `json:"leaf,omitempty"` // Max number of active leaf node connections
- Imports int64 `json:"imports,omitempty"` // Max number of imports
- Exports int64 `json:"exports,omitempty"` // Max number of exports
- Data int64 `json:"data,omitempty"` // Max number of bytes
- Payload int64 `json:"payload,omitempty"` // Max message payload
- WildcardExports bool `json:"wildcards,omitempty"` // Are wildcards allowed in exports
-}
-
-// IsEmpty returns true if all of the limits are 0/false.
-func (o *OperatorLimits) IsEmpty() bool {
- return *o == OperatorLimits{}
-}
-
-// IsUnlimited returns true if all limits are
-func (o *OperatorLimits) IsUnlimited() bool {
- return *o == OperatorLimits{NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, true}
-}
-
-// Validate checks that the operator limits contain valid values
-func (o *OperatorLimits) Validate(vr *ValidationResults) {
- // negative values mean unlimited, so all numbers are valid
-}
-
-// Account holds account specific claims data
-type Account struct {
- Imports Imports `json:"imports,omitempty"`
- Exports Exports `json:"exports,omitempty"`
- Identities []Identity `json:"identity,omitempty"`
- Limits OperatorLimits `json:"limits,omitempty"`
- SigningKeys StringList `json:"signing_keys,omitempty"`
- Revocations RevocationList `json:"revocations,omitempty"`
-}
-
-// Validate checks if the account is valid, based on the wrapper
-func (a *Account) Validate(acct *AccountClaims, vr *ValidationResults) {
- a.Imports.Validate(acct.Subject, vr)
- a.Exports.Validate(vr)
- a.Limits.Validate(vr)
-
- for _, i := range a.Identities {
- i.Validate(vr)
- }
-
- if !a.Limits.IsEmpty() && a.Limits.Imports >= 0 && int64(len(a.Imports)) > a.Limits.Imports {
- vr.AddError("the account contains more imports than allowed by the operator")
- }
-
- // Check Imports and Exports for limit violations.
- if a.Limits.Imports != NoLimit {
- if int64(len(a.Imports)) > a.Limits.Imports {
- vr.AddError("the account contains more imports than allowed by the operator")
- }
- }
- if a.Limits.Exports != NoLimit {
- if int64(len(a.Exports)) > a.Limits.Exports {
- vr.AddError("the account contains more exports than allowed by the operator")
- }
- // Check for wildcard restrictions
- if !a.Limits.WildcardExports {
- for _, ex := range a.Exports {
- if ex.Subject.HasWildCards() {
- vr.AddError("the account contains wildcard exports that are not allowed by the operator")
- }
- }
- }
- }
-
- for _, k := range a.SigningKeys {
- if !nkeys.IsValidPublicAccountKey(k) {
- vr.AddError("%s is not an account public key", k)
- }
- }
-}
-
-// AccountClaims defines the body of an account JWT
-type AccountClaims struct {
- ClaimsData
- Account `json:"nats,omitempty"`
-}
-
-// NewAccountClaims creates a new account JWT
-func NewAccountClaims(subject string) *AccountClaims {
- if subject == "" {
- return nil
- }
- c := &AccountClaims{}
- // Set to unlimited to start. We do it this way so we get compiler
- // errors if we add to the OperatorLimits.
- c.Limits = OperatorLimits{NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, true}
- c.Subject = subject
- return c
-}
-
-// Encode converts account claims into a JWT string
-func (a *AccountClaims) Encode(pair nkeys.KeyPair) (string, error) {
- if !nkeys.IsValidPublicAccountKey(a.Subject) {
- return "", errors.New("expected subject to be account public key")
- }
- sort.Sort(a.Exports)
- sort.Sort(a.Imports)
- a.ClaimsData.Type = AccountClaim
- return a.ClaimsData.Encode(pair, a)
-}
-
-// DecodeAccountClaims decodes account claims from a JWT string
-func DecodeAccountClaims(token string) (*AccountClaims, error) {
- v := AccountClaims{}
- if err := Decode(token, &v); err != nil {
- return nil, err
- }
- return &v, nil
-}
-
-func (a *AccountClaims) String() string {
- return a.ClaimsData.String(a)
-}
-
-// Payload pulls the accounts specific payload out of the claims
-func (a *AccountClaims) Payload() interface{} {
- return &a.Account
-}
-
-// Validate checks the accounts contents
-func (a *AccountClaims) Validate(vr *ValidationResults) {
- a.ClaimsData.Validate(vr)
- a.Account.Validate(a, vr)
-
- if nkeys.IsValidPublicAccountKey(a.ClaimsData.Issuer) {
- if len(a.Identities) > 0 {
- vr.AddWarning("self-signed account JWTs shouldn't contain identity proofs")
- }
- if !a.Limits.IsEmpty() {
- vr.AddWarning("self-signed account JWTs shouldn't contain operator limits")
- }
- }
-}
-
-// ExpectedPrefixes defines the types that can encode an account jwt, account and operator
-func (a *AccountClaims) ExpectedPrefixes() []nkeys.PrefixByte {
- return []nkeys.PrefixByte{nkeys.PrefixByteAccount, nkeys.PrefixByteOperator}
-}
-
-// Claims returns the accounts claims data
-func (a *AccountClaims) Claims() *ClaimsData {
- return &a.ClaimsData
-}
-
-// DidSign checks the claims against the account's public key and its signing keys
-func (a *AccountClaims) DidSign(op Claims) bool {
- if op != nil {
- issuer := op.Claims().Issuer
- if issuer == a.Subject {
- return true
- }
- return a.SigningKeys.Contains(issuer)
- }
- return false
-}
-
-// Revoke enters a revocation by publickey using time.Now().
-func (a *AccountClaims) Revoke(pubKey string) {
- a.RevokeAt(pubKey, time.Now())
-}
-
-// RevokeAt enters a revocation by publickey and timestamp into this export
-// If there is already a revocation for this public key that is newer, it is kept.
-func (a *AccountClaims) RevokeAt(pubKey string, timestamp time.Time) {
- if a.Revocations == nil {
- a.Revocations = RevocationList{}
- }
-
- a.Revocations.Revoke(pubKey, timestamp)
-}
-
-// ClearRevocation removes any revocation for the public key
-func (a *AccountClaims) ClearRevocation(pubKey string) {
- a.Revocations.ClearRevocation(pubKey)
-}
-
-// IsRevokedAt checks if the public key is in the revoked list with a timestamp later than
-// the one passed in. Generally this method is called with time.Now() but other time's can
-// be used for testing.
-func (a *AccountClaims) IsRevokedAt(pubKey string, timestamp time.Time) bool {
- return a.Revocations.IsRevoked(pubKey, timestamp)
-}
-
-// IsRevoked checks if the public key is in the revoked list with time.Now()
-func (a *AccountClaims) IsRevoked(pubKey string) bool {
- return a.Revocations.IsRevoked(pubKey, time.Now())
-}
diff --git a/vendor/github.com/nats-io/jwt/activation_claims.go b/vendor/github.com/nats-io/jwt/activation_claims.go
deleted file mode 100644
index 99228a75f96..00000000000
--- a/vendor/github.com/nats-io/jwt/activation_claims.go
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2018 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "crypto/sha256"
- "encoding/base32"
- "errors"
- "fmt"
- "strings"
-
- "github.com/nats-io/nkeys"
-)
-
-// Activation defines the custom parts of an activation claim
-type Activation struct {
- ImportSubject Subject `json:"subject,omitempty"`
- ImportType ExportType `json:"type,omitempty"`
- Limits
-}
-
-// IsService returns true if an Activation is for a service
-func (a *Activation) IsService() bool {
- return a.ImportType == Service
-}
-
-// IsStream returns true if an Activation is for a stream
-func (a *Activation) IsStream() bool {
- return a.ImportType == Stream
-}
-
-// Validate checks the exports and limits in an activation JWT
-func (a *Activation) Validate(vr *ValidationResults) {
- if !a.IsService() && !a.IsStream() {
- vr.AddError("invalid export type: %q", a.ImportType)
- }
-
- if a.IsService() {
- if a.ImportSubject.HasWildCards() {
- vr.AddError("services cannot have wildcard subject: %q", a.ImportSubject)
- }
- }
-
- a.ImportSubject.Validate(vr)
- a.Limits.Validate(vr)
-}
-
-// ActivationClaims holds the data specific to an activation JWT
-type ActivationClaims struct {
- ClaimsData
- Activation `json:"nats,omitempty"`
- // IssuerAccount stores the public key for the account the issuer represents.
- // When set, the claim was issued by a signing key.
- IssuerAccount string `json:"issuer_account,omitempty"`
-}
-
-// NewActivationClaims creates a new activation claim with the provided sub
-func NewActivationClaims(subject string) *ActivationClaims {
- if subject == "" {
- return nil
- }
- ac := &ActivationClaims{}
- ac.Subject = subject
- return ac
-}
-
-// Encode turns an activation claim into a JWT strimg
-func (a *ActivationClaims) Encode(pair nkeys.KeyPair) (string, error) {
- if !nkeys.IsValidPublicAccountKey(a.ClaimsData.Subject) {
- return "", errors.New("expected subject to be an account")
- }
- a.ClaimsData.Type = ActivationClaim
- return a.ClaimsData.Encode(pair, a)
-}
-
-// DecodeActivationClaims tries to create an activation claim from a JWT string
-func DecodeActivationClaims(token string) (*ActivationClaims, error) {
- v := ActivationClaims{}
- if err := Decode(token, &v); err != nil {
- return nil, err
- }
- return &v, nil
-}
-
-// Payload returns the activation specific part of the JWT
-func (a *ActivationClaims) Payload() interface{} {
- return a.Activation
-}
-
-// Validate checks the claims
-func (a *ActivationClaims) Validate(vr *ValidationResults) {
- a.ClaimsData.Validate(vr)
- a.Activation.Validate(vr)
- if a.IssuerAccount != "" && !nkeys.IsValidPublicAccountKey(a.IssuerAccount) {
- vr.AddError("account_id is not an account public key")
- }
-}
-
-// ExpectedPrefixes defines the types that can sign an activation jwt, account and oeprator
-func (a *ActivationClaims) ExpectedPrefixes() []nkeys.PrefixByte {
- return []nkeys.PrefixByte{nkeys.PrefixByteAccount, nkeys.PrefixByteOperator}
-}
-
-// Claims returns the generic part of the JWT
-func (a *ActivationClaims) Claims() *ClaimsData {
- return &a.ClaimsData
-}
-
-func (a *ActivationClaims) String() string {
- return a.ClaimsData.String(a)
-}
-
-// HashID returns a hash of the claims that can be used to identify it.
-// The hash is calculated by creating a string with
-// issuerPubKey.subjectPubKey. and constructing the sha-256 hash and base32 encoding that.
-// is the exported subject, minus any wildcards, so foo.* becomes foo.
-// the one special case is that if the export start with "*" or is ">" the "_"
-func (a *ActivationClaims) HashID() (string, error) {
-
- if a.Issuer == "" || a.Subject == "" || a.ImportSubject == "" {
- return "", fmt.Errorf("not enough data in the activaion claims to create a hash")
- }
-
- subject := cleanSubject(string(a.ImportSubject))
- base := fmt.Sprintf("%s.%s.%s", a.Issuer, a.Subject, subject)
- h := sha256.New()
- h.Write([]byte(base))
- sha := h.Sum(nil)
- hash := base32.StdEncoding.EncodeToString(sha)
-
- return hash, nil
-}
-
-func cleanSubject(subject string) string {
- split := strings.Split(subject, ".")
- cleaned := ""
-
- for i, tok := range split {
- if tok == "*" || tok == ">" {
- if i == 0 {
- cleaned = "_"
- break
- }
-
- cleaned = strings.Join(split[:i], ".")
- break
- }
- }
- if cleaned == "" {
- cleaned = subject
- }
- return cleaned
-}
diff --git a/vendor/github.com/nats-io/jwt/claims.go b/vendor/github.com/nats-io/jwt/claims.go
deleted file mode 100644
index d402bcc5821..00000000000
--- a/vendor/github.com/nats-io/jwt/claims.go
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright 2018-2019 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "crypto/sha512"
- "encoding/base32"
- "encoding/base64"
- "encoding/json"
- "errors"
- "fmt"
- "strings"
- "time"
-
- "github.com/nats-io/nkeys"
-)
-
-// ClaimType is used to indicate the type of JWT being stored in a Claim
-type ClaimType string
-
-const (
- // AccountClaim is the type of an Account JWT
- AccountClaim = "account"
- //ActivationClaim is the type of an activation JWT
- ActivationClaim = "activation"
- //UserClaim is the type of an user JWT
- UserClaim = "user"
- //ServerClaim is the type of an server JWT
- ServerClaim = "server"
- //ClusterClaim is the type of an cluster JWT
- ClusterClaim = "cluster"
- //OperatorClaim is the type of an operator JWT
- OperatorClaim = "operator"
-)
-
-// Claims is a JWT claims
-type Claims interface {
- Claims() *ClaimsData
- Encode(kp nkeys.KeyPair) (string, error)
- ExpectedPrefixes() []nkeys.PrefixByte
- Payload() interface{}
- String() string
- Validate(vr *ValidationResults)
- Verify(payload string, sig []byte) bool
-}
-
-// ClaimsData is the base struct for all claims
-type ClaimsData struct {
- Audience string `json:"aud,omitempty"`
- Expires int64 `json:"exp,omitempty"`
- ID string `json:"jti,omitempty"`
- IssuedAt int64 `json:"iat,omitempty"`
- Issuer string `json:"iss,omitempty"`
- Name string `json:"name,omitempty"`
- NotBefore int64 `json:"nbf,omitempty"`
- Subject string `json:"sub,omitempty"`
- Tags TagList `json:"tags,omitempty"`
- Type ClaimType `json:"type,omitempty"`
-}
-
-// Prefix holds the prefix byte for an NKey
-type Prefix struct {
- nkeys.PrefixByte
-}
-
-func encodeToString(d []byte) string {
- return base64.RawURLEncoding.EncodeToString(d)
-}
-
-func decodeString(s string) ([]byte, error) {
- return base64.RawURLEncoding.DecodeString(s)
-}
-
-func serialize(v interface{}) (string, error) {
- j, err := json.Marshal(v)
- if err != nil {
- return "", err
- }
- return encodeToString(j), nil
-}
-
-func (c *ClaimsData) doEncode(header *Header, kp nkeys.KeyPair, claim Claims) (string, error) {
- if header == nil {
- return "", errors.New("header is required")
- }
-
- if kp == nil {
- return "", errors.New("keypair is required")
- }
-
- if c.Subject == "" {
- return "", errors.New("subject is not set")
- }
-
- h, err := serialize(header)
- if err != nil {
- return "", err
- }
-
- issuerBytes, err := kp.PublicKey()
- if err != nil {
- return "", err
- }
-
- prefixes := claim.ExpectedPrefixes()
- if prefixes != nil {
- ok := false
- for _, p := range prefixes {
- switch p {
- case nkeys.PrefixByteAccount:
- if nkeys.IsValidPublicAccountKey(issuerBytes) {
- ok = true
- }
- case nkeys.PrefixByteOperator:
- if nkeys.IsValidPublicOperatorKey(issuerBytes) {
- ok = true
- }
- case nkeys.PrefixByteServer:
- if nkeys.IsValidPublicServerKey(issuerBytes) {
- ok = true
- }
- case nkeys.PrefixByteCluster:
- if nkeys.IsValidPublicClusterKey(issuerBytes) {
- ok = true
- }
- case nkeys.PrefixByteUser:
- if nkeys.IsValidPublicUserKey(issuerBytes) {
- ok = true
- }
- }
- }
- if !ok {
- return "", fmt.Errorf("unable to validate expected prefixes - %v", prefixes)
- }
- }
-
- c.Issuer = string(issuerBytes)
- c.IssuedAt = time.Now().UTC().Unix()
-
- c.ID, err = c.hash()
- if err != nil {
- return "", err
- }
-
- payload, err := serialize(claim)
- if err != nil {
- return "", err
- }
-
- sig, err := kp.Sign([]byte(payload))
- if err != nil {
- return "", err
- }
- eSig := encodeToString(sig)
- return fmt.Sprintf("%s.%s.%s", h, payload, eSig), nil
-}
-
-func (c *ClaimsData) hash() (string, error) {
- j, err := json.Marshal(c)
- if err != nil {
- return "", err
- }
- h := sha512.New512_256()
- h.Write(j)
- return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(h.Sum(nil)), nil
-}
-
-// Encode encodes a claim into a JWT token. The claim is signed with the
-// provided nkey's private key
-func (c *ClaimsData) Encode(kp nkeys.KeyPair, payload Claims) (string, error) {
- return c.doEncode(&Header{TokenTypeJwt, AlgorithmNkey}, kp, payload)
-}
-
-// Returns a JSON representation of the claim
-func (c *ClaimsData) String(claim interface{}) string {
- j, err := json.MarshalIndent(claim, "", " ")
- if err != nil {
- return ""
- }
- return string(j)
-}
-
-func parseClaims(s string, target Claims) error {
- h, err := decodeString(s)
- if err != nil {
- return err
- }
- return json.Unmarshal(h, &target)
-}
-
-// Verify verifies that the encoded payload was signed by the
-// provided public key. Verify is called automatically with
-// the claims portion of the token and the public key in the claim.
-// Client code need to insure that the public key in the
-// claim is trusted.
-func (c *ClaimsData) Verify(payload string, sig []byte) bool {
- // decode the public key
- kp, err := nkeys.FromPublicKey(c.Issuer)
- if err != nil {
- return false
- }
- if err := kp.Verify([]byte(payload), sig); err != nil {
- return false
- }
- return true
-}
-
-// Validate checks a claim to make sure it is valid. Validity checks
-// include expiration and not before constraints.
-func (c *ClaimsData) Validate(vr *ValidationResults) {
- now := time.Now().UTC().Unix()
- if c.Expires > 0 && now > c.Expires {
- vr.AddTimeCheck("claim is expired")
- }
-
- if c.NotBefore > 0 && c.NotBefore > now {
- vr.AddTimeCheck("claim is not yet valid")
- }
-}
-
-// IsSelfSigned returns true if the claims issuer is the subject
-func (c *ClaimsData) IsSelfSigned() bool {
- return c.Issuer == c.Subject
-}
-
-// Decode takes a JWT string decodes it and validates it
-// and return the embedded Claims. If the token header
-// doesn't match the expected algorithm, or the claim is
-// not valid or verification fails an error is returned.
-func Decode(token string, target Claims) error {
- // must have 3 chunks
- chunks := strings.Split(token, ".")
- if len(chunks) != 3 {
- return errors.New("expected 3 chunks")
- }
-
- _, err := parseHeaders(chunks[0])
- if err != nil {
- return err
- }
-
- if err := parseClaims(chunks[1], target); err != nil {
- return err
- }
-
- sig, err := decodeString(chunks[2])
- if err != nil {
- return err
- }
-
- if !target.Verify(chunks[1], sig) {
- return errors.New("claim failed signature verification")
- }
-
- prefixes := target.ExpectedPrefixes()
- if prefixes != nil {
- ok := false
- issuer := target.Claims().Issuer
- for _, p := range prefixes {
- switch p {
- case nkeys.PrefixByteAccount:
- if nkeys.IsValidPublicAccountKey(issuer) {
- ok = true
- }
- case nkeys.PrefixByteOperator:
- if nkeys.IsValidPublicOperatorKey(issuer) {
- ok = true
- }
- case nkeys.PrefixByteServer:
- if nkeys.IsValidPublicServerKey(issuer) {
- ok = true
- }
- case nkeys.PrefixByteCluster:
- if nkeys.IsValidPublicClusterKey(issuer) {
- ok = true
- }
- case nkeys.PrefixByteUser:
- if nkeys.IsValidPublicUserKey(issuer) {
- ok = true
- }
- }
- }
- if !ok {
- return fmt.Errorf("unable to validate expected prefixes - %v", prefixes)
- }
- }
-
- return nil
-}
diff --git a/vendor/github.com/nats-io/jwt/cluster_claims.go b/vendor/github.com/nats-io/jwt/cluster_claims.go
deleted file mode 100644
index bbfcf06f286..00000000000
--- a/vendor/github.com/nats-io/jwt/cluster_claims.go
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2018 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "errors"
-
- "github.com/nats-io/nkeys"
-)
-
-// Cluster stores the cluster specific elements of a cluster JWT
-type Cluster struct {
- Trust []string `json:"identity,omitempty"`
- Accounts []string `json:"accts,omitempty"`
- AccountURL string `json:"accturl,omitempty"`
- OperatorURL string `json:"opurl,omitempty"`
-}
-
-// Validate checks the cluster and permissions for a cluster JWT
-func (c *Cluster) Validate(vr *ValidationResults) {
- // fixme validate cluster data
-}
-
-// ClusterClaims defines the data in a cluster JWT
-type ClusterClaims struct {
- ClaimsData
- Cluster `json:"nats,omitempty"`
-}
-
-// NewClusterClaims creates a new cluster JWT with the specified subject/public key
-func NewClusterClaims(subject string) *ClusterClaims {
- if subject == "" {
- return nil
- }
- c := &ClusterClaims{}
- c.Subject = subject
- return c
-}
-
-// Encode tries to turn the cluster claims into a JWT string
-func (c *ClusterClaims) Encode(pair nkeys.KeyPair) (string, error) {
- if !nkeys.IsValidPublicClusterKey(c.Subject) {
- return "", errors.New("expected subject to be a cluster public key")
- }
- c.ClaimsData.Type = ClusterClaim
- return c.ClaimsData.Encode(pair, c)
-}
-
-// DecodeClusterClaims tries to parse cluster claims from a JWT string
-func DecodeClusterClaims(token string) (*ClusterClaims, error) {
- v := ClusterClaims{}
- if err := Decode(token, &v); err != nil {
- return nil, err
- }
- return &v, nil
-}
-
-func (c *ClusterClaims) String() string {
- return c.ClaimsData.String(c)
-}
-
-// Payload returns the cluster specific data
-func (c *ClusterClaims) Payload() interface{} {
- return &c.Cluster
-}
-
-// Validate checks the generic and cluster data in the cluster claims
-func (c *ClusterClaims) Validate(vr *ValidationResults) {
- c.ClaimsData.Validate(vr)
- c.Cluster.Validate(vr)
-}
-
-// ExpectedPrefixes defines the types that can encode a cluster JWT, operator or cluster
-func (c *ClusterClaims) ExpectedPrefixes() []nkeys.PrefixByte {
- return []nkeys.PrefixByte{nkeys.PrefixByteOperator, nkeys.PrefixByteCluster}
-}
-
-// Claims returns the generic data
-func (c *ClusterClaims) Claims() *ClaimsData {
- return &c.ClaimsData
-}
diff --git a/vendor/github.com/nats-io/jwt/creds_utils.go b/vendor/github.com/nats-io/jwt/creds_utils.go
deleted file mode 100644
index bb913dc1661..00000000000
--- a/vendor/github.com/nats-io/jwt/creds_utils.go
+++ /dev/null
@@ -1,203 +0,0 @@
-package jwt
-
-import (
- "bytes"
- "errors"
- "fmt"
- "regexp"
- "strings"
-
- "github.com/nats-io/nkeys"
-)
-
-// DecorateJWT returns a decorated JWT that describes the kind of JWT
-func DecorateJWT(jwtString string) ([]byte, error) {
- gc, err := DecodeGeneric(jwtString)
- if err != nil {
- return nil, err
- }
- return formatJwt(string(gc.Type), jwtString)
-}
-
-func formatJwt(kind string, jwtString string) ([]byte, error) {
- templ := `-----BEGIN NATS %s JWT-----
-%s
-------END NATS %s JWT------
-
-`
- w := bytes.NewBuffer(nil)
- kind = strings.ToUpper(kind)
- _, err := fmt.Fprintf(w, templ, kind, jwtString, kind)
- if err != nil {
- return nil, err
- }
- return w.Bytes(), nil
-}
-
-// DecorateSeed takes a seed and returns a string that wraps
-// the seed in the form:
-// ************************* IMPORTANT *************************
-// NKEY Seed printed below can be used sign and prove identity.
-// NKEYs are sensitive and should be treated as secrets.
-//
-// -----BEGIN USER NKEY SEED-----
-// SUAIO3FHUX5PNV2LQIIP7TZ3N4L7TX3W53MQGEIVYFIGA635OZCKEYHFLM
-// ------END USER NKEY SEED------
-func DecorateSeed(seed []byte) ([]byte, error) {
- w := bytes.NewBuffer(nil)
- ts := bytes.TrimSpace(seed)
- pre := string(ts[0:2])
- kind := ""
- switch pre {
- case "SU":
- kind = "USER"
- case "SA":
- kind = "ACCOUNT"
- case "SO":
- kind = "OPERATOR"
- default:
- return nil, errors.New("seed is not an operator, account or user seed")
- }
- header := `************************* IMPORTANT *************************
-NKEY Seed printed below can be used to sign and prove identity.
-NKEYs are sensitive and should be treated as secrets.
-
------BEGIN %s NKEY SEED-----
-`
- _, err := fmt.Fprintf(w, header, kind)
- if err != nil {
- return nil, err
- }
- w.Write(ts)
-
- footer := `
-------END %s NKEY SEED------
-
-*************************************************************
-`
- _, err = fmt.Fprintf(w, footer, kind)
- if err != nil {
- return nil, err
- }
- return w.Bytes(), nil
-}
-
-var userConfigRE = regexp.MustCompile(`\s*(?:(?:[-]{3,}[^\n]*[-]{3,}\n)(.+)(?:\n\s*[-]{3,}[^\n]*[-]{3,}\n))`)
-
-// An user config file looks like this:
-// -----BEGIN NATS USER JWT-----
-// eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5...
-// ------END NATS USER JWT------
-//
-// ************************* IMPORTANT *************************
-// NKEY Seed printed below can be used sign and prove identity.
-// NKEYs are sensitive and should be treated as secrets.
-//
-// -----BEGIN USER NKEY SEED-----
-// SUAIO3FHUX5PNV2LQIIP7TZ3N4L7TX3W53MQGEIVYFIGA635OZCKEYHFLM
-// ------END USER NKEY SEED------
-
-// FormatUserConfig returns a decorated file with a decorated JWT and decorated seed
-func FormatUserConfig(jwtString string, seed []byte) ([]byte, error) {
- gc, err := DecodeGeneric(jwtString)
- if err != nil {
- return nil, err
- }
- if gc.Type != UserClaim {
- return nil, fmt.Errorf("%q cannot be serialized as a user config", string(gc.Type))
- }
-
- w := bytes.NewBuffer(nil)
-
- jd, err := formatJwt(string(gc.Type), jwtString)
- if err != nil {
- return nil, err
- }
- _, err = w.Write(jd)
- if err != nil {
- return nil, err
- }
- if !bytes.HasPrefix(bytes.TrimSpace(seed), []byte("SU")) {
- return nil, fmt.Errorf("nkey seed is not an user seed")
- }
-
- d, err := DecorateSeed(seed)
- if err != nil {
- return nil, err
- }
- _, err = w.Write(d)
- if err != nil {
- return nil, err
- }
-
- return w.Bytes(), nil
-}
-
-// ParseDecoratedJWT takes a creds file and returns the JWT portion.
-func ParseDecoratedJWT(contents []byte) (string, error) {
- items := userConfigRE.FindAllSubmatch(contents, -1)
- if len(items) == 0 {
- return string(contents), nil
- }
- // First result should be the user JWT.
- // We copy here so that if the file contained a seed file too we wipe appropriately.
- raw := items[0][1]
- tmp := make([]byte, len(raw))
- copy(tmp, raw)
- return string(tmp), nil
-}
-
-// ParseDecoratedNKey takes a creds file, finds the NKey portion and creates a
-// key pair from it.
-func ParseDecoratedNKey(contents []byte) (nkeys.KeyPair, error) {
- var seed []byte
-
- items := userConfigRE.FindAllSubmatch(contents, -1)
- if len(items) > 1 {
- seed = items[1][1]
- } else {
- lines := bytes.Split(contents, []byte("\n"))
- for _, line := range lines {
- if bytes.HasPrefix(bytes.TrimSpace(line), []byte("SO")) ||
- bytes.HasPrefix(bytes.TrimSpace(line), []byte("SA")) ||
- bytes.HasPrefix(bytes.TrimSpace(line), []byte("SU")) {
- seed = line
- break
- }
- }
- }
- if seed == nil {
- return nil, errors.New("no nkey seed found")
- }
- if !bytes.HasPrefix(seed, []byte("SO")) &&
- !bytes.HasPrefix(seed, []byte("SA")) &&
- !bytes.HasPrefix(seed, []byte("SU")) {
- return nil, errors.New("doesn't contain a seed nkey")
- }
- kp, err := nkeys.FromSeed(seed)
- if err != nil {
- return nil, err
- }
- return kp, nil
-}
-
-// ParseDecoratedUserNKey takes a creds file, finds the NKey portion and creates a
-// key pair from it. Similar to ParseDecoratedNKey but fails for non-user keys.
-func ParseDecoratedUserNKey(contents []byte) (nkeys.KeyPair, error) {
- nk, err := ParseDecoratedNKey(contents)
- if err != nil {
- return nil, err
- }
- seed, err := nk.Seed()
- if err != nil {
- return nil, err
- }
- if !bytes.HasPrefix(seed, []byte("SU")) {
- return nil, errors.New("doesn't contain an user seed nkey")
- }
- kp, err := nkeys.FromSeed(seed)
- if err != nil {
- return nil, err
- }
- return kp, nil
-}
diff --git a/vendor/github.com/nats-io/jwt/exports.go b/vendor/github.com/nats-io/jwt/exports.go
deleted file mode 100644
index 5578f98829c..00000000000
--- a/vendor/github.com/nats-io/jwt/exports.go
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2018-2019 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "fmt"
- "time"
-)
-
-// ResponseType is used to store an export response type
-type ResponseType string
-
-const (
- // ResponseTypeSingleton is used for a service that sends a single response only
- ResponseTypeSingleton = "Singleton"
-
- // ResponseTypeStream is used for a service that will send multiple responses
- ResponseTypeStream = "Stream"
-
- // ResponseTypeChunked is used for a service that sends a single response in chunks (so not quite a stream)
- ResponseTypeChunked = "Chunked"
-)
-
-// ServiceLatency is used when observing and exported service for
-// latency measurements.
-// Sampling 1-100, represents sampling rate, defaults to 100.
-// Results is the subject where the latency metrics are published.
-// A metric will be defined by the nats-server's ServiceLatency. Time durations
-// are in nanoseconds.
-// see https://github.com/nats-io/nats-server/blob/master/server/accounts.go#L524
-// e.g.
-// {
-// "app": "dlc22",
-// "start": "2019-09-16T21:46:23.636869585-07:00",
-// "svc": 219732,
-// "nats": {
-// "req": 320415,
-// "resp": 228268,
-// "sys": 0
-// },
-// "total": 768415
-// }
-//
-type ServiceLatency struct {
- Sampling int `json:"sampling,omitempty"`
- Results Subject `json:"results"`
-}
-
-func (sl *ServiceLatency) Validate(vr *ValidationResults) {
- if sl.Sampling < 1 || sl.Sampling > 100 {
- vr.AddError("sampling percentage needs to be between 1-100")
- }
- sl.Results.Validate(vr)
- if sl.Results.HasWildCards() {
- vr.AddError("results subject can not contain wildcards")
- }
-}
-
-// Export represents a single export
-type Export struct {
- Name string `json:"name,omitempty"`
- Subject Subject `json:"subject,omitempty"`
- Type ExportType `json:"type,omitempty"`
- TokenReq bool `json:"token_req,omitempty"`
- Revocations RevocationList `json:"revocations,omitempty"`
- ResponseType ResponseType `json:"response_type,omitempty"`
- Latency *ServiceLatency `json:"service_latency,omitempty"`
-}
-
-// IsService returns true if an export is for a service
-func (e *Export) IsService() bool {
- return e.Type == Service
-}
-
-// IsStream returns true if an export is for a stream
-func (e *Export) IsStream() bool {
- return e.Type == Stream
-}
-
-// IsSingleResponse returns true if an export has a single response
-// or no resopnse type is set, also checks that the type is service
-func (e *Export) IsSingleResponse() bool {
- return e.Type == Service && (e.ResponseType == ResponseTypeSingleton || e.ResponseType == "")
-}
-
-// IsChunkedResponse returns true if an export has a chunked response
-func (e *Export) IsChunkedResponse() bool {
- return e.Type == Service && e.ResponseType == ResponseTypeChunked
-}
-
-// IsStreamResponse returns true if an export has a chunked response
-func (e *Export) IsStreamResponse() bool {
- return e.Type == Service && e.ResponseType == ResponseTypeStream
-}
-
-// Validate appends validation issues to the passed in results list
-func (e *Export) Validate(vr *ValidationResults) {
- if !e.IsService() && !e.IsStream() {
- vr.AddError("invalid export type: %q", e.Type)
- }
- if e.IsService() && !e.IsSingleResponse() && !e.IsChunkedResponse() && !e.IsStreamResponse() {
- vr.AddError("invalid response type for service: %q", e.ResponseType)
- }
- if e.IsStream() && e.ResponseType != "" {
- vr.AddError("invalid response type for stream: %q", e.ResponseType)
- }
- if e.Latency != nil {
- if !e.IsService() {
- vr.AddError("latency tracking only permitted for services")
- }
- e.Latency.Validate(vr)
- }
- e.Subject.Validate(vr)
-}
-
-// Revoke enters a revocation by publickey using time.Now().
-func (e *Export) Revoke(pubKey string) {
- e.RevokeAt(pubKey, time.Now())
-}
-
-// RevokeAt enters a revocation by publickey and timestamp into this export
-// If there is already a revocation for this public key that is newer, it is kept.
-func (e *Export) RevokeAt(pubKey string, timestamp time.Time) {
- if e.Revocations == nil {
- e.Revocations = RevocationList{}
- }
-
- e.Revocations.Revoke(pubKey, timestamp)
-}
-
-// ClearRevocation removes any revocation for the public key
-func (e *Export) ClearRevocation(pubKey string) {
- e.Revocations.ClearRevocation(pubKey)
-}
-
-// IsRevokedAt checks if the public key is in the revoked list with a timestamp later than
-// the one passed in. Generally this method is called with time.Now() but other time's can
-// be used for testing.
-func (e *Export) IsRevokedAt(pubKey string, timestamp time.Time) bool {
- return e.Revocations.IsRevoked(pubKey, timestamp)
-}
-
-// IsRevoked checks if the public key is in the revoked list with time.Now()
-func (e *Export) IsRevoked(pubKey string) bool {
- return e.Revocations.IsRevoked(pubKey, time.Now())
-}
-
-// Exports is a slice of exports
-type Exports []*Export
-
-// Add appends exports to the list
-func (e *Exports) Add(i ...*Export) {
- *e = append(*e, i...)
-}
-
-func isContainedIn(kind ExportType, subjects []Subject, vr *ValidationResults) {
- m := make(map[string]string)
- for i, ns := range subjects {
- for j, s := range subjects {
- if i == j {
- continue
- }
- if ns.IsContainedIn(s) {
- str := string(s)
- _, ok := m[str]
- if !ok {
- m[str] = string(ns)
- }
- }
- }
- }
-
- if len(m) != 0 {
- for k, v := range m {
- var vi ValidationIssue
- vi.Blocking = true
- vi.Description = fmt.Sprintf("%s export subject %q already exports %q", kind, k, v)
- vr.Add(&vi)
- }
- }
-}
-
-// Validate calls validate on all of the exports
-func (e *Exports) Validate(vr *ValidationResults) error {
- var serviceSubjects []Subject
- var streamSubjects []Subject
-
- for _, v := range *e {
- if v.IsService() {
- serviceSubjects = append(serviceSubjects, v.Subject)
- } else {
- streamSubjects = append(streamSubjects, v.Subject)
- }
- v.Validate(vr)
- }
-
- isContainedIn(Service, serviceSubjects, vr)
- isContainedIn(Stream, streamSubjects, vr)
-
- return nil
-}
-
-// HasExportContainingSubject checks if the export list has an export with the provided subject
-func (e *Exports) HasExportContainingSubject(subject Subject) bool {
- for _, s := range *e {
- if subject.IsContainedIn(s.Subject) {
- return true
- }
- }
- return false
-}
-
-func (e Exports) Len() int {
- return len(e)
-}
-
-func (e Exports) Swap(i, j int) {
- e[i], e[j] = e[j], e[i]
-}
-
-func (e Exports) Less(i, j int) bool {
- return e[i].Subject < e[j].Subject
-}
diff --git a/vendor/github.com/nats-io/jwt/genericlaims.go b/vendor/github.com/nats-io/jwt/genericlaims.go
deleted file mode 100644
index 94cd86e0add..00000000000
--- a/vendor/github.com/nats-io/jwt/genericlaims.go
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2018 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import "github.com/nats-io/nkeys"
-
-// GenericClaims can be used to read a JWT as a map for any non-generic fields
-type GenericClaims struct {
- ClaimsData
- Data map[string]interface{} `json:"nats,omitempty"`
-}
-
-// NewGenericClaims creates a map-based Claims
-func NewGenericClaims(subject string) *GenericClaims {
- if subject == "" {
- return nil
- }
- c := GenericClaims{}
- c.Subject = subject
- c.Data = make(map[string]interface{})
- return &c
-}
-
-// DecodeGeneric takes a JWT string and decodes it into a ClaimsData and map
-func DecodeGeneric(token string) (*GenericClaims, error) {
- v := GenericClaims{}
- if err := Decode(token, &v); err != nil {
- return nil, err
- }
- return &v, nil
-}
-
-// Claims returns the standard part of the generic claim
-func (gc *GenericClaims) Claims() *ClaimsData {
- return &gc.ClaimsData
-}
-
-// Payload returns the custom part of the claims data
-func (gc *GenericClaims) Payload() interface{} {
- return &gc.Data
-}
-
-// Encode takes a generic claims and creates a JWT string
-func (gc *GenericClaims) Encode(pair nkeys.KeyPair) (string, error) {
- return gc.ClaimsData.Encode(pair, gc)
-}
-
-// Validate checks the generic part of the claims data
-func (gc *GenericClaims) Validate(vr *ValidationResults) {
- gc.ClaimsData.Validate(vr)
-}
-
-func (gc *GenericClaims) String() string {
- return gc.ClaimsData.String(gc)
-}
-
-// ExpectedPrefixes returns the types allowed to encode a generic JWT, which is nil for all
-func (gc *GenericClaims) ExpectedPrefixes() []nkeys.PrefixByte {
- return nil
-}
diff --git a/vendor/github.com/nats-io/jwt/go.mod b/vendor/github.com/nats-io/jwt/go.mod
deleted file mode 100644
index a780dde9c60..00000000000
--- a/vendor/github.com/nats-io/jwt/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/nats-io/jwt
-
-require github.com/nats-io/nkeys v0.1.3
diff --git a/vendor/github.com/nats-io/jwt/go.sum b/vendor/github.com/nats-io/jwt/go.sum
deleted file mode 100644
index 9baf67f5ae2..00000000000
--- a/vendor/github.com/nats-io/jwt/go.sum
+++ /dev/null
@@ -1,9 +0,0 @@
-github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k=
-github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/vendor/github.com/nats-io/jwt/header.go b/vendor/github.com/nats-io/jwt/header.go
deleted file mode 100644
index 27c65811592..00000000000
--- a/vendor/github.com/nats-io/jwt/header.go
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2018-2019 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "encoding/json"
- "fmt"
- "strings"
-)
-
-const (
- // Version is semantic version.
- Version = "0.3.2"
-
- // TokenTypeJwt is the JWT token type supported JWT tokens
- // encoded and decoded by this library
- TokenTypeJwt = "jwt"
-
- // AlgorithmNkey is the algorithm supported by JWT tokens
- // encoded and decoded by this library
- AlgorithmNkey = "ed25519"
-)
-
-// Header is a JWT Jose Header
-type Header struct {
- Type string `json:"typ"`
- Algorithm string `json:"alg"`
-}
-
-// Parses a header JWT token
-func parseHeaders(s string) (*Header, error) {
- h, err := decodeString(s)
- if err != nil {
- return nil, err
- }
- header := Header{}
- if err := json.Unmarshal(h, &header); err != nil {
- return nil, err
- }
-
- if err := header.Valid(); err != nil {
- return nil, err
- }
- return &header, nil
-}
-
-// Valid validates the Header. It returns nil if the Header is
-// a JWT header, and the algorithm used is the NKEY algorithm.
-func (h *Header) Valid() error {
- if TokenTypeJwt != strings.ToLower(h.Type) {
- return fmt.Errorf("not supported type %q", h.Type)
- }
-
- if AlgorithmNkey != strings.ToLower(h.Algorithm) {
- return fmt.Errorf("unexpected %q algorithm", h.Algorithm)
- }
- return nil
-}
diff --git a/vendor/github.com/nats-io/jwt/imports.go b/vendor/github.com/nats-io/jwt/imports.go
deleted file mode 100644
index 8cd974796e9..00000000000
--- a/vendor/github.com/nats-io/jwt/imports.go
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2018-2019 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "io/ioutil"
- "net/http"
- "net/url"
- "time"
-)
-
-// Import describes a mapping from another account into this one
-type Import struct {
- Name string `json:"name,omitempty"`
- // Subject field in an import is always from the perspective of the
- // initial publisher - in the case of a stream it is the account owning
- // the stream (the exporter), and in the case of a service it is the
- // account making the request (the importer).
- Subject Subject `json:"subject,omitempty"`
- Account string `json:"account,omitempty"`
- Token string `json:"token,omitempty"`
- // To field in an import is always from the perspective of the subscriber
- // in the case of a stream it is the client of the stream (the importer),
- // from the perspective of a service, it is the subscription waiting for
- // requests (the exporter). If the field is empty, it will default to the
- // value in the Subject field.
- To Subject `json:"to,omitempty"`
- Type ExportType `json:"type,omitempty"`
-}
-
-// IsService returns true if the import is of type service
-func (i *Import) IsService() bool {
- return i.Type == Service
-}
-
-// IsStream returns true if the import is of type stream
-func (i *Import) IsStream() bool {
- return i.Type == Stream
-}
-
-// Validate checks if an import is valid for the wrapping account
-func (i *Import) Validate(actPubKey string, vr *ValidationResults) {
- if !i.IsService() && !i.IsStream() {
- vr.AddError("invalid import type: %q", i.Type)
- }
-
- if i.Account == "" {
- vr.AddWarning("account to import from is not specified")
- }
-
- i.Subject.Validate(vr)
-
- if i.IsService() && i.Subject.HasWildCards() {
- vr.AddError("services cannot have wildcard subject: %q", i.Subject)
- }
- if i.IsStream() && i.To.HasWildCards() {
- vr.AddError("streams cannot have wildcard to subject: %q", i.Subject)
- }
-
- var act *ActivationClaims
-
- if i.Token != "" {
- // Check to see if its an embedded JWT or a URL.
- if url, err := url.Parse(i.Token); err == nil && url.Scheme != "" {
- c := &http.Client{Timeout: 5 * time.Second}
- resp, err := c.Get(url.String())
- if err != nil {
- vr.AddWarning("import %s contains an unreachable token URL %q", i.Subject, i.Token)
- }
-
- if resp != nil {
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- vr.AddWarning("import %s contains an unreadable token URL %q", i.Subject, i.Token)
- } else {
- act, err = DecodeActivationClaims(string(body))
- if err != nil {
- vr.AddWarning("import %s contains a url %q with an invalid activation token", i.Subject, i.Token)
- }
- }
- }
- } else {
- var err error
- act, err = DecodeActivationClaims(i.Token)
- if err != nil {
- vr.AddWarning("import %q contains an invalid activation token", i.Subject)
- }
- }
- }
-
- if act != nil {
- if act.Issuer != i.Account {
- vr.AddWarning("activation token doesn't match account for import %q", i.Subject)
- }
-
- if act.ClaimsData.Subject != actPubKey {
- vr.AddWarning("activation token doesn't match account it is being included in, %q", i.Subject)
- }
- } else {
- vr.AddWarning("no activation provided for import %s", i.Subject)
- }
-
-}
-
-// Imports is a list of import structs
-type Imports []*Import
-
-// Validate checks if an import is valid for the wrapping account
-func (i *Imports) Validate(acctPubKey string, vr *ValidationResults) {
- toSet := make(map[Subject]bool, len(*i))
- for _, v := range *i {
- if v.Type == Service {
- if _, ok := toSet[v.To]; ok {
- vr.AddError("Duplicate To subjects for %q", v.To)
- }
- toSet[v.To] = true
- }
- v.Validate(acctPubKey, vr)
- }
-}
-
-// Add is a simple way to add imports
-func (i *Imports) Add(a ...*Import) {
- *i = append(*i, a...)
-}
-
-func (i Imports) Len() int {
- return len(i)
-}
-
-func (i Imports) Swap(j, k int) {
- i[j], i[k] = i[k], i[j]
-}
-
-func (i Imports) Less(j, k int) bool {
- return i[j].Subject < i[k].Subject
-}
diff --git a/vendor/github.com/nats-io/jwt/operator_claims.go b/vendor/github.com/nats-io/jwt/operator_claims.go
deleted file mode 100644
index 6a99597bc94..00000000000
--- a/vendor/github.com/nats-io/jwt/operator_claims.go
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright 2018 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "errors"
- "fmt"
- "net/url"
- "strings"
-
- "github.com/nats-io/nkeys"
-)
-
-// Operator specific claims
-type Operator struct {
- // Slice of real identies (like websites) that can be used to identify the operator.
- Identities []Identity `json:"identity,omitempty"`
- // Slice of other operator NKeys that can be used to sign on behalf of the main
- // operator identity.
- SigningKeys StringList `json:"signing_keys,omitempty"`
- // AccountServerURL is a partial URL like "https://host.domain.org:/jwt/v1"
- // tools will use the prefix and build queries by appending /accounts/
- // or /operator to the path provided. Note this assumes that the account server
- // can handle requests in a nats-account-server compatible way. See
- // https://github.com/nats-io/nats-account-server.
- AccountServerURL string `json:"account_server_url,omitempty"`
- // A list of NATS urls (tls://host:port) where tools can connect to the server
- // using proper credentials.
- OperatorServiceURLs StringList `json:"operator_service_urls,omitempty"`
-}
-
-// Validate checks the validity of the operators contents
-func (o *Operator) Validate(vr *ValidationResults) {
- if err := o.validateAccountServerURL(); err != nil {
- vr.AddError(err.Error())
- }
-
- for _, v := range o.validateOperatorServiceURLs() {
- if v != nil {
- vr.AddError(v.Error())
- }
- }
-
- for _, i := range o.Identities {
- i.Validate(vr)
- }
-
- for _, k := range o.SigningKeys {
- if !nkeys.IsValidPublicOperatorKey(k) {
- vr.AddError("%s is not an operator public key", k)
- }
- }
-}
-
-func (o *Operator) validateAccountServerURL() error {
- if o.AccountServerURL != "" {
- // We don't care what kind of URL it is so long as it parses
- // and has a protocol. The account server may impose additional
- // constraints on the type of URLs that it is able to notify to
- u, err := url.Parse(o.AccountServerURL)
- if err != nil {
- return fmt.Errorf("error parsing account server url: %v", err)
- }
- if u.Scheme == "" {
- return fmt.Errorf("account server url %q requires a protocol", o.AccountServerURL)
- }
- }
- return nil
-}
-
-// ValidateOperatorServiceURL returns an error if the URL is not a valid NATS or TLS url.
-func ValidateOperatorServiceURL(v string) error {
- // should be possible for the service url to not be expressed
- if v == "" {
- return nil
- }
- u, err := url.Parse(v)
- if err != nil {
- return fmt.Errorf("error parsing operator service url %q: %v", v, err)
- }
-
- if u.User != nil {
- return fmt.Errorf("operator service url %q - credentials are not supported", v)
- }
-
- if u.Path != "" {
- return fmt.Errorf("operator service url %q - paths are not supported", v)
- }
-
- lcs := strings.ToLower(u.Scheme)
- switch lcs {
- case "nats":
- return nil
- case "tls":
- return nil
- default:
- return fmt.Errorf("operator service url %q - protocol not supported (only 'nats' or 'tls' only)", v)
- }
-}
-
-func (o *Operator) validateOperatorServiceURLs() []error {
- var errors []error
- for _, v := range o.OperatorServiceURLs {
- if v != "" {
- if err := ValidateOperatorServiceURL(v); err != nil {
- errors = append(errors, err)
- }
- }
- }
- return errors
-}
-
-// OperatorClaims define the data for an operator JWT
-type OperatorClaims struct {
- ClaimsData
- Operator `json:"nats,omitempty"`
-}
-
-// NewOperatorClaims creates a new operator claim with the specified subject, which should be an operator public key
-func NewOperatorClaims(subject string) *OperatorClaims {
- if subject == "" {
- return nil
- }
- c := &OperatorClaims{}
- c.Subject = subject
- return c
-}
-
-// DidSign checks the claims against the operator's public key and its signing keys
-func (oc *OperatorClaims) DidSign(op Claims) bool {
- if op == nil {
- return false
- }
- issuer := op.Claims().Issuer
- if issuer == oc.Subject {
- return true
- }
- return oc.SigningKeys.Contains(issuer)
-}
-
-// Deprecated: AddSigningKey, use claim.SigningKeys.Add()
-func (oc *OperatorClaims) AddSigningKey(pk string) {
- oc.SigningKeys.Add(pk)
-}
-
-// Encode the claims into a JWT string
-func (oc *OperatorClaims) Encode(pair nkeys.KeyPair) (string, error) {
- if !nkeys.IsValidPublicOperatorKey(oc.Subject) {
- return "", errors.New("expected subject to be an operator public key")
- }
- err := oc.validateAccountServerURL()
- if err != nil {
- return "", err
- }
- oc.ClaimsData.Type = OperatorClaim
- return oc.ClaimsData.Encode(pair, oc)
-}
-
-// DecodeOperatorClaims tries to create an operator claims from a JWt string
-func DecodeOperatorClaims(token string) (*OperatorClaims, error) {
- v := OperatorClaims{}
- if err := Decode(token, &v); err != nil {
- return nil, err
- }
- return &v, nil
-}
-
-func (oc *OperatorClaims) String() string {
- return oc.ClaimsData.String(oc)
-}
-
-// Payload returns the operator specific data for an operator JWT
-func (oc *OperatorClaims) Payload() interface{} {
- return &oc.Operator
-}
-
-// Validate the contents of the claims
-func (oc *OperatorClaims) Validate(vr *ValidationResults) {
- oc.ClaimsData.Validate(vr)
- oc.Operator.Validate(vr)
-}
-
-// ExpectedPrefixes defines the nkey types that can sign operator claims, operator
-func (oc *OperatorClaims) ExpectedPrefixes() []nkeys.PrefixByte {
- return []nkeys.PrefixByte{nkeys.PrefixByteOperator}
-}
-
-// Claims returns the generic claims data
-func (oc *OperatorClaims) Claims() *ClaimsData {
- return &oc.ClaimsData
-}
diff --git a/vendor/github.com/nats-io/jwt/revocation_list.go b/vendor/github.com/nats-io/jwt/revocation_list.go
deleted file mode 100644
index fb1d8367160..00000000000
--- a/vendor/github.com/nats-io/jwt/revocation_list.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package jwt
-
-import (
- "time"
-)
-
-// RevocationList is used to store a mapping of public keys to unix timestamps
-type RevocationList map[string]int64
-
-// Revoke enters a revocation by publickey and timestamp into this export
-// If there is already a revocation for this public key that is newer, it is kept.
-func (r RevocationList) Revoke(pubKey string, timestamp time.Time) {
- newTS := timestamp.Unix()
- if ts, ok := r[pubKey]; ok && ts > newTS {
- return
- }
-
- r[pubKey] = newTS
-}
-
-// ClearRevocation removes any revocation for the public key
-func (r RevocationList) ClearRevocation(pubKey string) {
- delete(r, pubKey)
-}
-
-// IsRevoked checks if the public key is in the revoked list with a timestamp later than
-// the one passed in. Generally this method is called with time.Now() but other time's can
-// be used for testing.
-func (r RevocationList) IsRevoked(pubKey string, timestamp time.Time) bool {
- ts, ok := r[pubKey]
- return ok && ts > timestamp.Unix()
-}
diff --git a/vendor/github.com/nats-io/jwt/server_claims.go b/vendor/github.com/nats-io/jwt/server_claims.go
deleted file mode 100644
index c18f167ff58..00000000000
--- a/vendor/github.com/nats-io/jwt/server_claims.go
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2018 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "errors"
-
- "github.com/nats-io/nkeys"
-)
-
-// Server defines the custom part of a server jwt
-type Server struct {
- Permissions
- Cluster string `json:"cluster,omitempty"`
-}
-
-// Validate checks the cluster and permissions for a server JWT
-func (s *Server) Validate(vr *ValidationResults) {
- if s.Cluster == "" {
- vr.AddError("servers can't contain an empty cluster")
- }
-}
-
-// ServerClaims defines the data in a server JWT
-type ServerClaims struct {
- ClaimsData
- Server `json:"nats,omitempty"`
-}
-
-// NewServerClaims creates a new server JWT with the specified subject/public key
-func NewServerClaims(subject string) *ServerClaims {
- if subject == "" {
- return nil
- }
- c := &ServerClaims{}
- c.Subject = subject
- return c
-}
-
-// Encode tries to turn the server claims into a JWT string
-func (s *ServerClaims) Encode(pair nkeys.KeyPair) (string, error) {
- if !nkeys.IsValidPublicServerKey(s.Subject) {
- return "", errors.New("expected subject to be a server public key")
- }
- s.ClaimsData.Type = ServerClaim
- return s.ClaimsData.Encode(pair, s)
-}
-
-// DecodeServerClaims tries to parse server claims from a JWT string
-func DecodeServerClaims(token string) (*ServerClaims, error) {
- v := ServerClaims{}
- if err := Decode(token, &v); err != nil {
- return nil, err
- }
- return &v, nil
-}
-
-func (s *ServerClaims) String() string {
- return s.ClaimsData.String(s)
-}
-
-// Payload returns the server specific data
-func (s *ServerClaims) Payload() interface{} {
- return &s.Server
-}
-
-// Validate checks the generic and server data in the server claims
-func (s *ServerClaims) Validate(vr *ValidationResults) {
- s.ClaimsData.Validate(vr)
- s.Server.Validate(vr)
-}
-
-// ExpectedPrefixes defines the types that can encode a server JWT, operator or cluster
-func (s *ServerClaims) ExpectedPrefixes() []nkeys.PrefixByte {
- return []nkeys.PrefixByte{nkeys.PrefixByteOperator, nkeys.PrefixByteCluster}
-}
-
-// Claims returns the generic data
-func (s *ServerClaims) Claims() *ClaimsData {
- return &s.ClaimsData
-}
diff --git a/vendor/github.com/nats-io/jwt/types.go b/vendor/github.com/nats-io/jwt/types.go
deleted file mode 100644
index a1f09fd9b6b..00000000000
--- a/vendor/github.com/nats-io/jwt/types.go
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright 2018-2019 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "encoding/json"
- "fmt"
- "net"
- "strings"
- "time"
-)
-
-// ExportType defines the type of import/export.
-type ExportType int
-
-const (
- // Unknown is used if we don't know the type
- Unknown ExportType = iota
- // Stream defines the type field value for a stream "stream"
- Stream
- // Service defines the type field value for a service "service"
- Service
-)
-
-func (t ExportType) String() string {
- switch t {
- case Stream:
- return "stream"
- case Service:
- return "service"
- }
- return "unknown"
-}
-
-// MarshalJSON marshals the enum as a quoted json string
-func (t *ExportType) MarshalJSON() ([]byte, error) {
- switch *t {
- case Stream:
- return []byte("\"stream\""), nil
- case Service:
- return []byte("\"service\""), nil
- }
- return nil, fmt.Errorf("unknown export type")
-}
-
-// UnmarshalJSON unmashals a quoted json string to the enum value
-func (t *ExportType) UnmarshalJSON(b []byte) error {
- var j string
- err := json.Unmarshal(b, &j)
- if err != nil {
- return err
- }
- switch j {
- case "stream":
- *t = Stream
- return nil
- case "service":
- *t = Service
- return nil
- }
- return fmt.Errorf("unknown export type")
-}
-
-// Subject is a string that represents a NATS subject
-type Subject string
-
-// Validate checks that a subject string is valid, ie not empty and without spaces
-func (s Subject) Validate(vr *ValidationResults) {
- v := string(s)
- if v == "" {
- vr.AddError("subject cannot be empty")
- }
- if strings.Contains(v, " ") {
- vr.AddError("subject %q cannot have spaces", v)
- }
-}
-
-// HasWildCards is used to check if a subject contains a > or *
-func (s Subject) HasWildCards() bool {
- v := string(s)
- return strings.HasSuffix(v, ".>") ||
- strings.Contains(v, ".*.") ||
- strings.HasSuffix(v, ".*") ||
- strings.HasPrefix(v, "*.") ||
- v == "*" ||
- v == ">"
-}
-
-// IsContainedIn does a simple test to see if the subject is contained in another subject
-func (s Subject) IsContainedIn(other Subject) bool {
- otherArray := strings.Split(string(other), ".")
- myArray := strings.Split(string(s), ".")
-
- if len(myArray) > len(otherArray) && otherArray[len(otherArray)-1] != ">" {
- return false
- }
-
- if len(myArray) < len(otherArray) {
- return false
- }
-
- for ind, tok := range otherArray {
- myTok := myArray[ind]
-
- if ind == len(otherArray)-1 && tok == ">" {
- return true
- }
-
- if tok != myTok && tok != "*" {
- return false
- }
- }
-
- return true
-}
-
-// NamedSubject is the combination of a subject and a name for it
-type NamedSubject struct {
- Name string `json:"name,omitempty"`
- Subject Subject `json:"subject,omitempty"`
-}
-
-// Validate checks the subject
-func (ns *NamedSubject) Validate(vr *ValidationResults) {
- ns.Subject.Validate(vr)
-}
-
-// TimeRange is used to represent a start and end time
-type TimeRange struct {
- Start string `json:"start,omitempty"`
- End string `json:"end,omitempty"`
-}
-
-// Validate checks the values in a time range struct
-func (tr *TimeRange) Validate(vr *ValidationResults) {
- format := "15:04:05"
-
- if tr.Start == "" {
- vr.AddError("time ranges start must contain a start")
- } else {
- _, err := time.Parse(format, tr.Start)
- if err != nil {
- vr.AddError("start in time range is invalid %q", tr.Start)
- }
- }
-
- if tr.End == "" {
- vr.AddError("time ranges end must contain an end")
- } else {
- _, err := time.Parse(format, tr.End)
- if err != nil {
- vr.AddError("end in time range is invalid %q", tr.End)
- }
- }
-}
-
-// Limits are used to control acccess for users and importing accounts
-// Src is a comma separated list of CIDR specifications
-type Limits struct {
- Max int64 `json:"max,omitempty"`
- Payload int64 `json:"payload,omitempty"`
- Src string `json:"src,omitempty"`
- Times []TimeRange `json:"times,omitempty"`
-}
-
-// Validate checks the values in a limit struct
-func (l *Limits) Validate(vr *ValidationResults) {
- if l.Max < 0 {
- vr.AddError("limits cannot contain a negative maximum, %d", l.Max)
- }
- if l.Payload < 0 {
- vr.AddError("limits cannot contain a negative payload, %d", l.Payload)
- }
-
- if l.Src != "" {
- elements := strings.Split(l.Src, ",")
-
- for _, cidr := range elements {
- cidr = strings.TrimSpace(cidr)
- _, ipNet, err := net.ParseCIDR(cidr)
- if err != nil || ipNet == nil {
- vr.AddError("invalid cidr %q in user src limits", cidr)
- }
- }
- }
-
- if l.Times != nil && len(l.Times) > 0 {
- for _, t := range l.Times {
- t.Validate(vr)
- }
- }
-}
-
-// Permission defines allow/deny subjects
-type Permission struct {
- Allow StringList `json:"allow,omitempty"`
- Deny StringList `json:"deny,omitempty"`
-}
-
-// Validate the allow, deny elements of a permission
-func (p *Permission) Validate(vr *ValidationResults) {
- for _, subj := range p.Allow {
- Subject(subj).Validate(vr)
- }
- for _, subj := range p.Deny {
- Subject(subj).Validate(vr)
- }
-}
-
-// ResponsePermission can be used to allow responses to any reply subject
-// that is received on a valid subscription.
-type ResponsePermission struct {
- MaxMsgs int `json:"max"`
- Expires time.Duration `json:"ttl"`
-}
-
-// Validate the response permission.
-func (p *ResponsePermission) Validate(vr *ValidationResults) {
- // Any values can be valid for now.
-}
-
-// Permissions are used to restrict subject access, either on a user or for everyone on a server by default
-type Permissions struct {
- Pub Permission `json:"pub,omitempty"`
- Sub Permission `json:"sub,omitempty"`
- Resp *ResponsePermission `json:"resp,omitempty"`
-}
-
-// Validate the pub and sub fields in the permissions list
-func (p *Permissions) Validate(vr *ValidationResults) {
- p.Pub.Validate(vr)
- p.Sub.Validate(vr)
- if p.Resp != nil {
- p.Resp.Validate(vr)
- }
-}
-
-// StringList is a wrapper for an array of strings
-type StringList []string
-
-// Contains returns true if the list contains the string
-func (u *StringList) Contains(p string) bool {
- for _, t := range *u {
- if t == p {
- return true
- }
- }
- return false
-}
-
-// Add appends 1 or more strings to a list
-func (u *StringList) Add(p ...string) {
- for _, v := range p {
- if !u.Contains(v) && v != "" {
- *u = append(*u, v)
- }
- }
-}
-
-// Remove removes 1 or more strings from a list
-func (u *StringList) Remove(p ...string) {
- for _, v := range p {
- for i, t := range *u {
- if t == v {
- a := *u
- *u = append(a[:i], a[i+1:]...)
- break
- }
- }
- }
-}
-
-// TagList is a unique array of lower case strings
-// All tag list methods lower case the strings in the arguments
-type TagList []string
-
-// Contains returns true if the list contains the tags
-func (u *TagList) Contains(p string) bool {
- p = strings.ToLower(p)
- for _, t := range *u {
- if t == p {
- return true
- }
- }
- return false
-}
-
-// Add appends 1 or more tags to a list
-func (u *TagList) Add(p ...string) {
- for _, v := range p {
- v = strings.ToLower(v)
- if !u.Contains(v) && v != "" {
- *u = append(*u, v)
- }
- }
-}
-
-// Remove removes 1 or more tags from a list
-func (u *TagList) Remove(p ...string) {
- for _, v := range p {
- v = strings.ToLower(v)
- for i, t := range *u {
- if t == v {
- a := *u
- *u = append(a[:i], a[i+1:]...)
- break
- }
- }
- }
-}
-
-// Identity is used to associate an account or operator with a real entity
-type Identity struct {
- ID string `json:"id,omitempty"`
- Proof string `json:"proof,omitempty"`
-}
-
-// Validate checks the values in an Identity
-func (u *Identity) Validate(vr *ValidationResults) {
- //Fixme identity validation
-}
diff --git a/vendor/github.com/nats-io/jwt/user_claims.go b/vendor/github.com/nats-io/jwt/user_claims.go
deleted file mode 100644
index 0ec1da3f9cc..00000000000
--- a/vendor/github.com/nats-io/jwt/user_claims.go
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2018-2019 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "errors"
-
- "github.com/nats-io/nkeys"
-)
-
-// User defines the user specific data in a user JWT
-type User struct {
- Permissions
- Limits
-}
-
-// Validate checks the permissions and limits in a User jwt
-func (u *User) Validate(vr *ValidationResults) {
- u.Permissions.Validate(vr)
- u.Limits.Validate(vr)
-}
-
-// UserClaims defines a user JWT
-type UserClaims struct {
- ClaimsData
- User `json:"nats,omitempty"`
- // IssuerAccount stores the public key for the account the issuer represents.
- // When set, the claim was issued by a signing key.
- IssuerAccount string `json:"issuer_account,omitempty"`
-}
-
-// NewUserClaims creates a user JWT with the specific subject/public key
-func NewUserClaims(subject string) *UserClaims {
- if subject == "" {
- return nil
- }
- c := &UserClaims{}
- c.Subject = subject
- return c
-}
-
-// Encode tries to turn the user claims into a JWT string
-func (u *UserClaims) Encode(pair nkeys.KeyPair) (string, error) {
- if !nkeys.IsValidPublicUserKey(u.Subject) {
- return "", errors.New("expected subject to be user public key")
- }
- u.ClaimsData.Type = UserClaim
- return u.ClaimsData.Encode(pair, u)
-}
-
-// DecodeUserClaims tries to parse a user claims from a JWT string
-func DecodeUserClaims(token string) (*UserClaims, error) {
- v := UserClaims{}
- if err := Decode(token, &v); err != nil {
- return nil, err
- }
- return &v, nil
-}
-
-// Validate checks the generic and specific parts of the user jwt
-func (u *UserClaims) Validate(vr *ValidationResults) {
- u.ClaimsData.Validate(vr)
- u.User.Validate(vr)
- if u.IssuerAccount != "" && !nkeys.IsValidPublicAccountKey(u.IssuerAccount) {
- vr.AddError("account_id is not an account public key")
- }
-}
-
-// ExpectedPrefixes defines the types that can encode a user JWT, account
-func (u *UserClaims) ExpectedPrefixes() []nkeys.PrefixByte {
- return []nkeys.PrefixByte{nkeys.PrefixByteAccount}
-}
-
-// Claims returns the generic data from a user jwt
-func (u *UserClaims) Claims() *ClaimsData {
- return &u.ClaimsData
-}
-
-// Payload returns the user specific data from a user JWT
-func (u *UserClaims) Payload() interface{} {
- return &u.User
-}
-
-func (u *UserClaims) String() string {
- return u.ClaimsData.String(u)
-}
diff --git a/vendor/github.com/nats-io/jwt/validation.go b/vendor/github.com/nats-io/jwt/validation.go
deleted file mode 100644
index c87a9922d18..00000000000
--- a/vendor/github.com/nats-io/jwt/validation.go
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2018 The NATS Authors
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package jwt
-
-import (
- "errors"
- "fmt"
-)
-
-// ValidationIssue represents an issue during JWT validation, it may or may not be a blocking error
-type ValidationIssue struct {
- Description string
- Blocking bool
- TimeCheck bool
-}
-
-func (ve *ValidationIssue) Error() string {
- return ve.Description
-}
-
-// ValidationResults is a list of ValidationIssue pointers
-type ValidationResults struct {
- Issues []*ValidationIssue
-}
-
-// CreateValidationResults creates an empty list of validation issues
-func CreateValidationResults() *ValidationResults {
- issues := []*ValidationIssue{}
- return &ValidationResults{
- Issues: issues,
- }
-}
-
-//Add appends an issue to the list
-func (v *ValidationResults) Add(vi *ValidationIssue) {
- v.Issues = append(v.Issues, vi)
-}
-
-// AddError creates a new validation error and adds it to the list
-func (v *ValidationResults) AddError(format string, args ...interface{}) {
- v.Add(&ValidationIssue{
- Description: fmt.Sprintf(format, args...),
- Blocking: true,
- TimeCheck: false,
- })
-}
-
-// AddTimeCheck creates a new validation issue related to a time check and adds it to the list
-func (v *ValidationResults) AddTimeCheck(format string, args ...interface{}) {
- v.Add(&ValidationIssue{
- Description: fmt.Sprintf(format, args...),
- Blocking: false,
- TimeCheck: true,
- })
-}
-
-// AddWarning creates a new validation warning and adds it to the list
-func (v *ValidationResults) AddWarning(format string, args ...interface{}) {
- v.Add(&ValidationIssue{
- Description: fmt.Sprintf(format, args...),
- Blocking: false,
- TimeCheck: false,
- })
-}
-
-// IsBlocking returns true if the list contains a blocking error
-func (v *ValidationResults) IsBlocking(includeTimeChecks bool) bool {
- for _, i := range v.Issues {
- if i.Blocking {
- return true
- }
-
- if includeTimeChecks && i.TimeCheck {
- return true
- }
- }
- return false
-}
-
-// IsEmpty returns true if the list is empty
-func (v *ValidationResults) IsEmpty() bool {
- return len(v.Issues) == 0
-}
-
-// Errors returns only blocking issues as errors
-func (v *ValidationResults) Errors() []error {
- var errs []error
- for _, v := range v.Issues {
- if v.Blocking {
- errs = append(errs, errors.New(v.Description))
- }
- }
- return errs
-}
diff --git a/vendor/github.com/nats-io/nats.go/.gitignore b/vendor/github.com/nats-io/nats.go/.gitignore
deleted file mode 100644
index a9977fce5d0..00000000000
--- a/vendor/github.com/nats-io/nats.go/.gitignore
+++ /dev/null
@@ -1,42 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-
-# Emacs
-*~
-\#*\#
-.\#*
-
-# vi/vim
-.??*.swp
-
-# Mac
-.DS_Store
-
-# Eclipse
-.project
-.settings/
-
-# bin
-
-# Goland
-.idea
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/nats.go/.travis.yml b/vendor/github.com/nats-io/nats.go/.travis.yml
deleted file mode 100644
index 2594b74ea14..00000000000
--- a/vendor/github.com/nats-io/nats.go/.travis.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-language: go
-sudo: false
-go:
-- 1.12.x
-- 1.11.x
-env:
-- GO111MODULE=off
-go_import_path: github.com/nats-io/nats.go
-install:
-- go get -t ./...
-- go get github.com/nats-io/nats-server
-- go get github.com/mattn/goveralls
-- go get github.com/wadey/gocovmerge
-- go get -u honnef.co/go/tools/cmd/staticcheck
-- go get -u github.com/client9/misspell/cmd/misspell
-before_script:
-- $(exit $(go fmt ./... | wc -l))
-- go vet ./...
-- find . -type f -name "*.go" | xargs misspell -error -locale US
-- staticcheck ./...
-script:
-- go test -i -race ./...
-- if [[ "$TRAVIS_GO_VERSION" =~ 1.12 ]]; then ./scripts/cov.sh TRAVIS; else go test -race -v -p=1 ./... --failfast; fi
diff --git a/vendor/github.com/nats-io/nats.go/GOVERNANCE.md b/vendor/github.com/nats-io/nats.go/GOVERNANCE.md
deleted file mode 100644
index 1d5a7be3e51..00000000000
--- a/vendor/github.com/nats-io/nats.go/GOVERNANCE.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# NATS Go Client Governance
-
-NATS Go Client (go-nats) is part of the NATS project and is subject to the [NATS Governance](https://github.com/nats-io/nats-general/blob/master/GOVERNANCE.md).
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/nats.go/LICENSE b/vendor/github.com/nats-io/nats.go/LICENSE
deleted file mode 100644
index 261eeb9e9f8..00000000000
--- a/vendor/github.com/nats-io/nats.go/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/nats-io/nats.go/MAINTAINERS.md b/vendor/github.com/nats-io/nats.go/MAINTAINERS.md
deleted file mode 100644
index 323faa8ef56..00000000000
--- a/vendor/github.com/nats-io/nats.go/MAINTAINERS.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Maintainers
-
-Maintainership is on a per project basis.
-
-### Core-maintainers
- - Derek Collison [@derekcollison](https://github.com/derekcollison)
- - Ivan Kozlovic [@kozlovic](https://github.com/kozlovic)
-
-### Maintainers
- - Waldemar Quevedo [@wallyqs](https://github.com/wallyqs)
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/nats.go/README.md b/vendor/github.com/nats-io/nats.go/README.md
deleted file mode 100644
index 83cbbd27d46..00000000000
--- a/vendor/github.com/nats-io/nats.go/README.md
+++ /dev/null
@@ -1,403 +0,0 @@
-# NATS - Go Client
-A [Go](http://golang.org) client for the [NATS messaging system](https://nats.io).
-
-[![License Apache 2](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
-[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fnats-io%2Fgo-nats.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fnats-io%2Fgo-nats?ref=badge_shield)
-[![Go Report Card](https://goreportcard.com/badge/github.com/nats-io/nats.go)](https://goreportcard.com/report/github.com/nats-io/nats.go) [![Build Status](https://travis-ci.org/nats-io/nats.go.svg?branch=master)](http://travis-ci.org/nats-io/nats.go) [![GoDoc](https://godoc.org/github.com/nats-io/nats.go?status.svg)](http://godoc.org/github.com/nats-io/nats.go) [![Coverage Status](https://coveralls.io/repos/nats-io/nats.go/badge.svg?branch=master)](https://coveralls.io/r/nats-io/nats.go?branch=master)
-
-## Installation
-
-```bash
-# Go client
-go get github.com/nats-io/nats.go/
-
-# Server
-go get github.com/nats-io/nats-server
-```
-
-When using or transitioning to Go modules support:
-
-```bash
-# Go client latest or explicit version
-go get github.com/nats-io/nats.go/@latest
-go get github.com/nats-io/nats.go/@v1.9.1
-
-# For latest NATS Server, add /v2 at the end
-go get github.com/nats-io/nats-server/v2
-
-# NATS Server v1 is installed otherwise
-# go get github.com/nats-io/nats-server
-```
-
-## Basic Usage
-
-```go
-import nats "github.com/nats-io/nats.go"
-
-// Connect to a server
-nc, _ := nats.Connect(nats.DefaultURL)
-
-// Simple Publisher
-nc.Publish("foo", []byte("Hello World"))
-
-// Simple Async Subscriber
-nc.Subscribe("foo", func(m *nats.Msg) {
- fmt.Printf("Received a message: %s\n", string(m.Data))
-})
-
-// Responding to a request message
-nc.Subscribe("request", func(m *nats.Msg) {
- m.Respond([]byte("answer is 42"))
-})
-
-// Simple Sync Subscriber
-sub, err := nc.SubscribeSync("foo")
-m, err := sub.NextMsg(timeout)
-
-// Channel Subscriber
-ch := make(chan *nats.Msg, 64)
-sub, err := nc.ChanSubscribe("foo", ch)
-msg := <- ch
-
-// Unsubscribe
-sub.Unsubscribe()
-
-// Drain
-sub.Drain()
-
-// Requests
-msg, err := nc.Request("help", []byte("help me"), 10*time.Millisecond)
-
-// Replies
-nc.Subscribe("help", func(m *nats.Msg) {
- nc.Publish(m.Reply, []byte("I can help!"))
-})
-
-// Drain connection (Preferred for responders)
-// Close() not needed if this is called.
-nc.Drain()
-
-// Close connection
-nc.Close()
-```
-
-## Encoded Connections
-
-```go
-
-nc, _ := nats.Connect(nats.DefaultURL)
-c, _ := nats.NewEncodedConn(nc, nats.JSON_ENCODER)
-defer c.Close()
-
-// Simple Publisher
-c.Publish("foo", "Hello World")
-
-// Simple Async Subscriber
-c.Subscribe("foo", func(s string) {
- fmt.Printf("Received a message: %s\n", s)
-})
-
-// EncodedConn can Publish any raw Go type using the registered Encoder
-type person struct {
- Name string
- Address string
- Age int
-}
-
-// Go type Subscriber
-c.Subscribe("hello", func(p *person) {
- fmt.Printf("Received a person: %+v\n", p)
-})
-
-me := &person{Name: "derek", Age: 22, Address: "140 New Montgomery Street, San Francisco, CA"}
-
-// Go type Publisher
-c.Publish("hello", me)
-
-// Unsubscribe
-sub, err := c.Subscribe("foo", nil)
-// ...
-sub.Unsubscribe()
-
-// Requests
-var response string
-err = c.Request("help", "help me", &response, 10*time.Millisecond)
-if err != nil {
- fmt.Printf("Request failed: %v\n", err)
-}
-
-// Replying
-c.Subscribe("help", func(subj, reply string, msg string) {
- c.Publish(reply, "I can help!")
-})
-
-// Close connection
-c.Close();
-```
-
-## New Authentication (Nkeys and User Credentials)
-This requires server with version >= 2.0.0
-
-NATS servers have a new security and authentication mechanism to authenticate with user credentials and Nkeys.
-The simplest form is to use the helper method UserCredentials(credsFilepath).
-```go
-nc, err := nats.Connect(url, nats.UserCredentials("user.creds"))
-```
-
-The helper methods creates two callback handlers to present the user JWT and sign the nonce challenge from the server.
-The core client library never has direct access to your private key and simply performs the callback for signing the server challenge.
-The helper will load and wipe and erase memory it uses for each connect or reconnect.
-
-The helper also can take two entries, one for the JWT and one for the NKey seed file.
-```go
-nc, err := nats.Connect(url, nats.UserCredentials("user.jwt", "user.nk"))
-```
-
-You can also set the callback handlers directly and manage challenge signing directly.
-```go
-nc, err := nats.Connect(url, nats.UserJWT(jwtCB, sigCB))
-```
-
-Bare Nkeys are also supported. The nkey seed should be in a read only file, e.g. seed.txt
-```bash
-> cat seed.txt
-# This is my seed nkey!
-SUAGMJH5XLGZKQQWAWKRZJIGMOU4HPFUYLXJMXOO5NLFEO2OOQJ5LPRDPM
-```
-
-This is a helper function which will load and decode and do the proper signing for the server nonce.
-It will clear memory in between invocations.
-You can choose to use the low level option and provide the public key and a signature callback on your own.
-
-```go
-opt, err := nats.NkeyOptionFromSeed("seed.txt")
-nc, err := nats.Connect(serverUrl, opt)
-
-// Direct
-nc, err := nats.Connect(serverUrl, nats.Nkey(pubNkey, sigCB))
-```
-
-## TLS
-
-```go
-// tls as a scheme will enable secure connections by default. This will also verify the server name.
-nc, err := nats.Connect("tls://nats.demo.io:4443")
-
-// If you are using a self-signed certificate, you need to have a tls.Config with RootCAs setup.
-// We provide a helper method to make this case easier.
-nc, err = nats.Connect("tls://localhost:4443", nats.RootCAs("./configs/certs/ca.pem"))
-
-// If the server requires client certificate, there is an helper function for that too:
-cert := nats.ClientCert("./configs/certs/client-cert.pem", "./configs/certs/client-key.pem")
-nc, err = nats.Connect("tls://localhost:4443", cert)
-
-// You can also supply a complete tls.Config
-
-certFile := "./configs/certs/client-cert.pem"
-keyFile := "./configs/certs/client-key.pem"
-cert, err := tls.LoadX509KeyPair(certFile, keyFile)
-if err != nil {
- t.Fatalf("error parsing X509 certificate/key pair: %v", err)
-}
-
-config := &tls.Config{
- ServerName: opts.Host,
- Certificates: []tls.Certificate{cert},
- RootCAs: pool,
- MinVersion: tls.VersionTLS12,
-}
-
-nc, err = nats.Connect("nats://localhost:4443", nats.Secure(config))
-if err != nil {
- t.Fatalf("Got an error on Connect with Secure Options: %+v\n", err)
-}
-
-```
-
-## Using Go Channels (netchan)
-
-```go
-nc, _ := nats.Connect(nats.DefaultURL)
-ec, _ := nats.NewEncodedConn(nc, nats.JSON_ENCODER)
-defer ec.Close()
-
-type person struct {
- Name string
- Address string
- Age int
-}
-
-recvCh := make(chan *person)
-ec.BindRecvChan("hello", recvCh)
-
-sendCh := make(chan *person)
-ec.BindSendChan("hello", sendCh)
-
-me := &person{Name: "derek", Age: 22, Address: "140 New Montgomery Street"}
-
-// Send via Go channels
-sendCh <- me
-
-// Receive via Go channels
-who := <- recvCh
-```
-
-## Wildcard Subscriptions
-
-```go
-
-// "*" matches any token, at any level of the subject.
-nc.Subscribe("foo.*.baz", func(m *Msg) {
- fmt.Printf("Msg received on [%s] : %s\n", m.Subject, string(m.Data));
-})
-
-nc.Subscribe("foo.bar.*", func(m *Msg) {
- fmt.Printf("Msg received on [%s] : %s\n", m.Subject, string(m.Data));
-})
-
-// ">" matches any length of the tail of a subject, and can only be the last token
-// E.g. 'foo.>' will match 'foo.bar', 'foo.bar.baz', 'foo.foo.bar.bax.22'
-nc.Subscribe("foo.>", func(m *Msg) {
- fmt.Printf("Msg received on [%s] : %s\n", m.Subject, string(m.Data));
-})
-
-// Matches all of the above
-nc.Publish("foo.bar.baz", []byte("Hello World"))
-
-```
-
-## Queue Groups
-
-```go
-// All subscriptions with the same queue name will form a queue group.
-// Each message will be delivered to only one subscriber per queue group,
-// using queuing semantics. You can have as many queue groups as you wish.
-// Normal subscribers will continue to work as expected.
-
-nc.QueueSubscribe("foo", "job_workers", func(_ *Msg) {
- received += 1;
-})
-
-```
-
-## Advanced Usage
-
-```go
-
-// Flush connection to server, returns when all messages have been processed.
-nc.Flush()
-fmt.Println("All clear!")
-
-// FlushTimeout specifies a timeout value as well.
-err := nc.FlushTimeout(1*time.Second)
-if err != nil {
- fmt.Println("All clear!")
-} else {
- fmt.Println("Flushed timed out!")
-}
-
-// Auto-unsubscribe after MAX_WANTED messages received
-const MAX_WANTED = 10
-sub, err := nc.Subscribe("foo")
-sub.AutoUnsubscribe(MAX_WANTED)
-
-// Multiple connections
-nc1 := nats.Connect("nats://host1:4222")
-nc2 := nats.Connect("nats://host2:4222")
-
-nc1.Subscribe("foo", func(m *Msg) {
- fmt.Printf("Received a message: %s\n", string(m.Data))
-})
-
-nc2.Publish("foo", []byte("Hello World!"));
-
-```
-
-## Clustered Usage
-
-```go
-
-var servers = "nats://localhost:1222, nats://localhost:1223, nats://localhost:1224"
-
-nc, err := nats.Connect(servers)
-
-// Optionally set ReconnectWait and MaxReconnect attempts.
-// This example means 10 seconds total per backend.
-nc, err = nats.Connect(servers, nats.MaxReconnects(5), nats.ReconnectWait(2 * time.Second))
-
-// Optionally disable randomization of the server pool
-nc, err = nats.Connect(servers, nats.DontRandomize())
-
-// Setup callbacks to be notified on disconnects, reconnects and connection closed.
-nc, err = nats.Connect(servers,
- nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
- fmt.Printf("Got disconnected! Reason: %q\n", err)
- }),
- nats.ReconnectHandler(func(nc *nats.Conn) {
- fmt.Printf("Got reconnected to %v!\n", nc.ConnectedUrl())
- }),
- nats.ClosedHandler(func(nc *nats.Conn) {
- fmt.Printf("Connection closed. Reason: %q\n", nc.LastError())
- })
-)
-
-// When connecting to a mesh of servers with auto-discovery capabilities,
-// you may need to provide a username/password or token in order to connect
-// to any server in that mesh when authentication is required.
-// Instead of providing the credentials in the initial URL, you will use
-// new option setters:
-nc, err = nats.Connect("nats://localhost:4222", nats.UserInfo("foo", "bar"))
-
-// For token based authentication:
-nc, err = nats.Connect("nats://localhost:4222", nats.Token("S3cretT0ken"))
-
-// You can even pass the two at the same time in case one of the server
-// in the mesh requires token instead of user name and password.
-nc, err = nats.Connect("nats://localhost:4222",
- nats.UserInfo("foo", "bar"),
- nats.Token("S3cretT0ken"))
-
-// Note that if credentials are specified in the initial URLs, they take
-// precedence on the credentials specified through the options.
-// For instance, in the connect call below, the client library will use
-// the user "my" and password "pwd" to connect to localhost:4222, however,
-// it will use username "foo" and password "bar" when (re)connecting to
-// a different server URL that it got as part of the auto-discovery.
-nc, err = nats.Connect("nats://my:pwd@localhost:4222", nats.UserInfo("foo", "bar"))
-
-```
-
-## Context support (+Go 1.7)
-
-```go
-ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
-defer cancel()
-
-nc, err := nats.Connect(nats.DefaultURL)
-
-// Request with context
-msg, err := nc.RequestWithContext(ctx, "foo", []byte("bar"))
-
-// Synchronous subscriber with context
-sub, err := nc.SubscribeSync("foo")
-msg, err := sub.NextMsgWithContext(ctx)
-
-// Encoded Request with context
-c, err := nats.NewEncodedConn(nc, nats.JSON_ENCODER)
-type request struct {
- Message string `json:"message"`
-}
-type response struct {
- Code int `json:"code"`
-}
-req := &request{Message: "Hello"}
-resp := &response{}
-err := c.RequestWithContext(ctx, "foo", req, resp)
-```
-
-## License
-
-Unless otherwise noted, the NATS source files are distributed
-under the Apache Version 2.0 license found in the LICENSE file.
-
-[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fnats-io%2Fgo-nats.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fnats-io%2Fgo-nats?ref=badge_large)
diff --git a/vendor/github.com/nats-io/nats.go/TODO.md b/vendor/github.com/nats-io/nats.go/TODO.md
deleted file mode 100644
index 213aaeca868..00000000000
--- a/vendor/github.com/nats-io/nats.go/TODO.md
+++ /dev/null
@@ -1,26 +0,0 @@
-
-- [ ] Better constructors, options handling
-- [ ] Functions for callback settings after connection created.
-- [ ] Better options for subscriptions. Slow Consumer state settable, Go routines vs Inline.
-- [ ] Move off of channels for subscribers, use syncPool linkedLists, etc with highwater.
-- [ ] Test for valid subjects on publish and subscribe?
-- [ ] SyncSubscriber and Next for EncodedConn
-- [ ] Fast Publisher?
-- [ ] pooling for structs used? leaky bucket?
-- [ ] Timeout 0 should work as no timeout
-- [x] Ping timer
-- [x] Name in Connect for gnatsd
-- [x] Asynchronous error handling
-- [x] Parser rewrite
-- [x] Reconnect
-- [x] Hide Lock
-- [x] Easier encoder interface
-- [x] QueueSubscribeSync
-- [x] Make nats specific errors prefixed with 'nats:'
-- [x] API test for closed connection
-- [x] TLS/SSL
-- [x] Stats collection
-- [x] Disconnect detection
-- [x] Optimized Publish (coalescing)
-- [x] Do Examples via Go style
-- [x] Standardized Errors
diff --git a/vendor/github.com/nats-io/nats.go/context.go b/vendor/github.com/nats-io/nats.go/context.go
deleted file mode 100644
index c921d6be7eb..00000000000
--- a/vendor/github.com/nats-io/nats.go/context.go
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2016-2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build go1.7
-
-// A Go client for the NATS messaging system (https://nats.io).
-package nats
-
-import (
- "context"
- "reflect"
-)
-
-// RequestWithContext takes a context, a subject and payload
-// in bytes and request expecting a single response.
-func (nc *Conn) RequestWithContext(ctx context.Context, subj string, data []byte) (*Msg, error) {
- if ctx == nil {
- return nil, ErrInvalidContext
- }
- if nc == nil {
- return nil, ErrInvalidConnection
- }
- // Check whether the context is done already before making
- // the request.
- if ctx.Err() != nil {
- return nil, ctx.Err()
- }
-
- nc.mu.Lock()
- // If user wants the old style.
- if nc.Opts.UseOldRequestStyle {
- nc.mu.Unlock()
- return nc.oldRequestWithContext(ctx, subj, data)
- }
-
- mch, token, err := nc.createNewRequestAndSend(subj, data)
- if err != nil {
- return nil, err
- }
-
- var ok bool
- var msg *Msg
-
- select {
- case msg, ok = <-mch:
- if !ok {
- return nil, ErrConnectionClosed
- }
- case <-ctx.Done():
- nc.mu.Lock()
- delete(nc.respMap, token)
- nc.mu.Unlock()
- return nil, ctx.Err()
- }
-
- return msg, nil
-}
-
-// oldRequestWithContext utilizes inbox and subscription per request.
-func (nc *Conn) oldRequestWithContext(ctx context.Context, subj string, data []byte) (*Msg, error) {
- inbox := NewInbox()
- ch := make(chan *Msg, RequestChanLen)
-
- s, err := nc.subscribe(inbox, _EMPTY_, nil, ch, true)
- if err != nil {
- return nil, err
- }
- s.AutoUnsubscribe(1)
- defer s.Unsubscribe()
-
- err = nc.PublishRequest(subj, inbox, data)
- if err != nil {
- return nil, err
- }
-
- return s.NextMsgWithContext(ctx)
-}
-
-// NextMsgWithContext takes a context and returns the next message
-// available to a synchronous subscriber, blocking until it is delivered
-// or context gets canceled.
-func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
- if ctx == nil {
- return nil, ErrInvalidContext
- }
- if s == nil {
- return nil, ErrBadSubscription
- }
- if ctx.Err() != nil {
- return nil, ctx.Err()
- }
-
- s.mu.Lock()
- err := s.validateNextMsgState()
- if err != nil {
- s.mu.Unlock()
- return nil, err
- }
-
- // snapshot
- mch := s.mch
- s.mu.Unlock()
-
- var ok bool
- var msg *Msg
-
- // If something is available right away, let's optimize that case.
- select {
- case msg, ok = <-mch:
- if !ok {
- return nil, s.getNextMsgErr()
- }
- if err := s.processNextMsgDelivered(msg); err != nil {
- return nil, err
- } else {
- return msg, nil
- }
- default:
- }
-
- select {
- case msg, ok = <-mch:
- if !ok {
- return nil, s.getNextMsgErr()
- }
- if err := s.processNextMsgDelivered(msg); err != nil {
- return nil, err
- }
- case <-ctx.Done():
- return nil, ctx.Err()
- }
-
- return msg, nil
-}
-
-// FlushWithContext will allow a context to control the duration
-// of a Flush() call. This context should be non-nil and should
-// have a deadline set. We will return an error if none is present.
-func (nc *Conn) FlushWithContext(ctx context.Context) error {
- if nc == nil {
- return ErrInvalidConnection
- }
- if ctx == nil {
- return ErrInvalidContext
- }
- _, ok := ctx.Deadline()
- if !ok {
- return ErrNoDeadlineContext
- }
-
- nc.mu.Lock()
- if nc.isClosed() {
- nc.mu.Unlock()
- return ErrConnectionClosed
- }
- // Create a buffered channel to prevent chan send to block
- // in processPong()
- ch := make(chan struct{}, 1)
- nc.sendPing(ch)
- nc.mu.Unlock()
-
- var err error
-
- select {
- case _, ok := <-ch:
- if !ok {
- err = ErrConnectionClosed
- } else {
- close(ch)
- }
- case <-ctx.Done():
- err = ctx.Err()
- }
-
- if err != nil {
- nc.removeFlushEntry(ch)
- }
-
- return err
-}
-
-// RequestWithContext will create an Inbox and perform a Request
-// using the provided cancellation context with the Inbox reply
-// for the data v. A response will be decoded into the vPtrResponse.
-func (c *EncodedConn) RequestWithContext(ctx context.Context, subject string, v interface{}, vPtr interface{}) error {
- if ctx == nil {
- return ErrInvalidContext
- }
-
- b, err := c.Enc.Encode(subject, v)
- if err != nil {
- return err
- }
- m, err := c.Conn.RequestWithContext(ctx, subject, b)
- if err != nil {
- return err
- }
- if reflect.TypeOf(vPtr) == emptyMsgType {
- mPtr := vPtr.(*Msg)
- *mPtr = *m
- } else {
- err := c.Enc.Decode(m.Subject, m.Data, vPtr)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
diff --git a/vendor/github.com/nats-io/nats.go/enc.go b/vendor/github.com/nats-io/nats.go/enc.go
deleted file mode 100644
index 0ed71a2c74e..00000000000
--- a/vendor/github.com/nats-io/nats.go/enc.go
+++ /dev/null
@@ -1,269 +0,0 @@
-// Copyright 2012-2019 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package nats
-
-import (
- "errors"
- "fmt"
- "reflect"
- "sync"
- "time"
-
- // Default Encoders
- "github.com/nats-io/nats.go/encoders/builtin"
-)
-
-// Encoder interface is for all register encoders
-type Encoder interface {
- Encode(subject string, v interface{}) ([]byte, error)
- Decode(subject string, data []byte, vPtr interface{}) error
-}
-
-var encMap map[string]Encoder
-var encLock sync.Mutex
-
-// Indexed names into the Registered Encoders.
-const (
- JSON_ENCODER = "json"
- GOB_ENCODER = "gob"
- DEFAULT_ENCODER = "default"
-)
-
-func init() {
- encMap = make(map[string]Encoder)
- // Register json, gob and default encoder
- RegisterEncoder(JSON_ENCODER, &builtin.JsonEncoder{})
- RegisterEncoder(GOB_ENCODER, &builtin.GobEncoder{})
- RegisterEncoder(DEFAULT_ENCODER, &builtin.DefaultEncoder{})
-}
-
-// EncodedConn are the preferred way to interface with NATS. They wrap a bare connection to
-// a nats server and have an extendable encoder system that will encode and decode messages
-// from raw Go types.
-type EncodedConn struct {
- Conn *Conn
- Enc Encoder
-}
-
-// NewEncodedConn will wrap an existing Connection and utilize the appropriate registered
-// encoder.
-func NewEncodedConn(c *Conn, encType string) (*EncodedConn, error) {
- if c == nil {
- return nil, errors.New("nats: Nil Connection")
- }
- if c.IsClosed() {
- return nil, ErrConnectionClosed
- }
- ec := &EncodedConn{Conn: c, Enc: EncoderForType(encType)}
- if ec.Enc == nil {
- return nil, fmt.Errorf("no encoder registered for '%s'", encType)
- }
- return ec, nil
-}
-
-// RegisterEncoder will register the encType with the given Encoder. Useful for customization.
-func RegisterEncoder(encType string, enc Encoder) {
- encLock.Lock()
- defer encLock.Unlock()
- encMap[encType] = enc
-}
-
-// EncoderForType will return the registered Encoder for the encType.
-func EncoderForType(encType string) Encoder {
- encLock.Lock()
- defer encLock.Unlock()
- return encMap[encType]
-}
-
-// Publish publishes the data argument to the given subject. The data argument
-// will be encoded using the associated encoder.
-func (c *EncodedConn) Publish(subject string, v interface{}) error {
- b, err := c.Enc.Encode(subject, v)
- if err != nil {
- return err
- }
- return c.Conn.publish(subject, _EMPTY_, b)
-}
-
-// PublishRequest will perform a Publish() expecting a response on the
-// reply subject. Use Request() for automatically waiting for a response
-// inline.
-func (c *EncodedConn) PublishRequest(subject, reply string, v interface{}) error {
- b, err := c.Enc.Encode(subject, v)
- if err != nil {
- return err
- }
- return c.Conn.publish(subject, reply, b)
-}
-
-// Request will create an Inbox and perform a Request() call
-// with the Inbox reply for the data v. A response will be
-// decoded into the vPtr Response.
-func (c *EncodedConn) Request(subject string, v interface{}, vPtr interface{}, timeout time.Duration) error {
- b, err := c.Enc.Encode(subject, v)
- if err != nil {
- return err
- }
- m, err := c.Conn.Request(subject, b, timeout)
- if err != nil {
- return err
- }
- if reflect.TypeOf(vPtr) == emptyMsgType {
- mPtr := vPtr.(*Msg)
- *mPtr = *m
- } else {
- err = c.Enc.Decode(m.Subject, m.Data, vPtr)
- }
- return err
-}
-
-// Handler is a specific callback used for Subscribe. It is generalized to
-// an interface{}, but we will discover its format and arguments at runtime
-// and perform the correct callback, including de-marshaling JSON strings
-// back into the appropriate struct based on the signature of the Handler.
-//
-// Handlers are expected to have one of four signatures.
-//
-// type person struct {
-// Name string `json:"name,omitempty"`
-// Age uint `json:"age,omitempty"`
-// }
-//
-// handler := func(m *Msg)
-// handler := func(p *person)
-// handler := func(subject string, o *obj)
-// handler := func(subject, reply string, o *obj)
-//
-// These forms allow a callback to request a raw Msg ptr, where the processing
-// of the message from the wire is untouched. Process a JSON representation
-// and demarshal it into the given struct, e.g. person.
-// There are also variants where the callback wants either the subject, or the
-// subject and the reply subject.
-type Handler interface{}
-
-// Dissect the cb Handler's signature
-func argInfo(cb Handler) (reflect.Type, int) {
- cbType := reflect.TypeOf(cb)
- if cbType.Kind() != reflect.Func {
- panic("nats: Handler needs to be a func")
- }
- numArgs := cbType.NumIn()
- if numArgs == 0 {
- return nil, numArgs
- }
- return cbType.In(numArgs - 1), numArgs
-}
-
-var emptyMsgType = reflect.TypeOf(&Msg{})
-
-// Subscribe will create a subscription on the given subject and process incoming
-// messages using the specified Handler. The Handler should be a func that matches
-// a signature from the description of Handler from above.
-func (c *EncodedConn) Subscribe(subject string, cb Handler) (*Subscription, error) {
- return c.subscribe(subject, _EMPTY_, cb)
-}
-
-// QueueSubscribe will create a queue subscription on the given subject and process
-// incoming messages using the specified Handler. The Handler should be a func that
-// matches a signature from the description of Handler from above.
-func (c *EncodedConn) QueueSubscribe(subject, queue string, cb Handler) (*Subscription, error) {
- return c.subscribe(subject, queue, cb)
-}
-
-// Internal implementation that all public functions will use.
-func (c *EncodedConn) subscribe(subject, queue string, cb Handler) (*Subscription, error) {
- if cb == nil {
- return nil, errors.New("nats: Handler required for EncodedConn Subscription")
- }
- argType, numArgs := argInfo(cb)
- if argType == nil {
- return nil, errors.New("nats: Handler requires at least one argument")
- }
-
- cbValue := reflect.ValueOf(cb)
- wantsRaw := (argType == emptyMsgType)
-
- natsCB := func(m *Msg) {
- var oV []reflect.Value
- if wantsRaw {
- oV = []reflect.Value{reflect.ValueOf(m)}
- } else {
- var oPtr reflect.Value
- if argType.Kind() != reflect.Ptr {
- oPtr = reflect.New(argType)
- } else {
- oPtr = reflect.New(argType.Elem())
- }
- if err := c.Enc.Decode(m.Subject, m.Data, oPtr.Interface()); err != nil {
- if c.Conn.Opts.AsyncErrorCB != nil {
- c.Conn.ach.push(func() {
- c.Conn.Opts.AsyncErrorCB(c.Conn, m.Sub, errors.New("nats: Got an error trying to unmarshal: "+err.Error()))
- })
- }
- return
- }
- if argType.Kind() != reflect.Ptr {
- oPtr = reflect.Indirect(oPtr)
- }
-
- // Callback Arity
- switch numArgs {
- case 1:
- oV = []reflect.Value{oPtr}
- case 2:
- subV := reflect.ValueOf(m.Subject)
- oV = []reflect.Value{subV, oPtr}
- case 3:
- subV := reflect.ValueOf(m.Subject)
- replyV := reflect.ValueOf(m.Reply)
- oV = []reflect.Value{subV, replyV, oPtr}
- }
-
- }
- cbValue.Call(oV)
- }
-
- return c.Conn.subscribe(subject, queue, natsCB, nil, false)
-}
-
-// FlushTimeout allows a Flush operation to have an associated timeout.
-func (c *EncodedConn) FlushTimeout(timeout time.Duration) (err error) {
- return c.Conn.FlushTimeout(timeout)
-}
-
-// Flush will perform a round trip to the server and return when it
-// receives the internal reply.
-func (c *EncodedConn) Flush() error {
- return c.Conn.Flush()
-}
-
-// Close will close the connection to the server. This call will release
-// all blocking calls, such as Flush(), etc.
-func (c *EncodedConn) Close() {
- c.Conn.Close()
-}
-
-// Drain will put a connection into a drain state. All subscriptions will
-// immediately be put into a drain state. Upon completion, the publishers
-// will be drained and can not publish any additional messages. Upon draining
-// of the publishers, the connection will be closed. Use the ClosedCB()
-// option to know when the connection has moved from draining to closed.
-func (c *EncodedConn) Drain() error {
- return c.Conn.Drain()
-}
-
-// LastError reports the last error encountered via the Connection.
-func (c *EncodedConn) LastError() error {
- return c.Conn.err
-}
diff --git a/vendor/github.com/nats-io/nats.go/encoders/builtin/default_enc.go b/vendor/github.com/nats-io/nats.go/encoders/builtin/default_enc.go
deleted file mode 100644
index 46d918eea64..00000000000
--- a/vendor/github.com/nats-io/nats.go/encoders/builtin/default_enc.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2012-2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package builtin
-
-import (
- "bytes"
- "fmt"
- "reflect"
- "strconv"
- "unsafe"
-)
-
-// DefaultEncoder implementation for EncodedConn.
-// This encoder will leave []byte and string untouched, but will attempt to
-// turn numbers into appropriate strings that can be decoded. It will also
-// propely encoded and decode bools. If will encode a struct, but if you want
-// to properly handle structures you should use JsonEncoder.
-type DefaultEncoder struct {
- // Empty
-}
-
-var trueB = []byte("true")
-var falseB = []byte("false")
-var nilB = []byte("")
-
-// Encode
-func (je *DefaultEncoder) Encode(subject string, v interface{}) ([]byte, error) {
- switch arg := v.(type) {
- case string:
- bytes := *(*[]byte)(unsafe.Pointer(&arg))
- return bytes, nil
- case []byte:
- return arg, nil
- case bool:
- if arg {
- return trueB, nil
- } else {
- return falseB, nil
- }
- case nil:
- return nilB, nil
- default:
- var buf bytes.Buffer
- fmt.Fprintf(&buf, "%+v", arg)
- return buf.Bytes(), nil
- }
-}
-
-// Decode
-func (je *DefaultEncoder) Decode(subject string, data []byte, vPtr interface{}) error {
- // Figure out what it's pointing to...
- sData := *(*string)(unsafe.Pointer(&data))
- switch arg := vPtr.(type) {
- case *string:
- *arg = sData
- return nil
- case *[]byte:
- *arg = data
- return nil
- case *int:
- n, err := strconv.ParseInt(sData, 10, 64)
- if err != nil {
- return err
- }
- *arg = int(n)
- return nil
- case *int32:
- n, err := strconv.ParseInt(sData, 10, 64)
- if err != nil {
- return err
- }
- *arg = int32(n)
- return nil
- case *int64:
- n, err := strconv.ParseInt(sData, 10, 64)
- if err != nil {
- return err
- }
- *arg = int64(n)
- return nil
- case *float32:
- n, err := strconv.ParseFloat(sData, 32)
- if err != nil {
- return err
- }
- *arg = float32(n)
- return nil
- case *float64:
- n, err := strconv.ParseFloat(sData, 64)
- if err != nil {
- return err
- }
- *arg = float64(n)
- return nil
- case *bool:
- b, err := strconv.ParseBool(sData)
- if err != nil {
- return err
- }
- *arg = b
- return nil
- default:
- vt := reflect.TypeOf(arg).Elem()
- return fmt.Errorf("nats: Default Encoder can't decode to type %s", vt)
- }
-}
diff --git a/vendor/github.com/nats-io/nats.go/encoders/builtin/gob_enc.go b/vendor/github.com/nats-io/nats.go/encoders/builtin/gob_enc.go
deleted file mode 100644
index 632bcbd395d..00000000000
--- a/vendor/github.com/nats-io/nats.go/encoders/builtin/gob_enc.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2013-2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package builtin
-
-import (
- "bytes"
- "encoding/gob"
-)
-
-// GobEncoder is a Go specific GOB Encoder implementation for EncodedConn.
-// This encoder will use the builtin encoding/gob to Marshal
-// and Unmarshal most types, including structs.
-type GobEncoder struct {
- // Empty
-}
-
-// FIXME(dlc) - This could probably be more efficient.
-
-// Encode
-func (ge *GobEncoder) Encode(subject string, v interface{}) ([]byte, error) {
- b := new(bytes.Buffer)
- enc := gob.NewEncoder(b)
- if err := enc.Encode(v); err != nil {
- return nil, err
- }
- return b.Bytes(), nil
-}
-
-// Decode
-func (ge *GobEncoder) Decode(subject string, data []byte, vPtr interface{}) (err error) {
- dec := gob.NewDecoder(bytes.NewBuffer(data))
- err = dec.Decode(vPtr)
- return
-}
diff --git a/vendor/github.com/nats-io/nats.go/encoders/builtin/json_enc.go b/vendor/github.com/nats-io/nats.go/encoders/builtin/json_enc.go
deleted file mode 100644
index c9670f3131d..00000000000
--- a/vendor/github.com/nats-io/nats.go/encoders/builtin/json_enc.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2012-2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package builtin
-
-import (
- "encoding/json"
- "strings"
-)
-
-// JsonEncoder is a JSON Encoder implementation for EncodedConn.
-// This encoder will use the builtin encoding/json to Marshal
-// and Unmarshal most types, including structs.
-type JsonEncoder struct {
- // Empty
-}
-
-// Encode
-func (je *JsonEncoder) Encode(subject string, v interface{}) ([]byte, error) {
- b, err := json.Marshal(v)
- if err != nil {
- return nil, err
- }
- return b, nil
-}
-
-// Decode
-func (je *JsonEncoder) Decode(subject string, data []byte, vPtr interface{}) (err error) {
- switch arg := vPtr.(type) {
- case *string:
- // If they want a string and it is a JSON string, strip quotes
- // This allows someone to send a struct but receive as a plain string
- // This cast should be efficient for Go 1.3 and beyond.
- str := string(data)
- if strings.HasPrefix(str, `"`) && strings.HasSuffix(str, `"`) {
- *arg = str[1 : len(str)-1]
- } else {
- *arg = str
- }
- case *[]byte:
- *arg = data
- default:
- err = json.Unmarshal(data, arg)
- }
- return
-}
diff --git a/vendor/github.com/nats-io/nats.go/go.mod b/vendor/github.com/nats-io/nats.go/go.mod
deleted file mode 100644
index f82ceee6dfc..00000000000
--- a/vendor/github.com/nats-io/nats.go/go.mod
+++ /dev/null
@@ -1,7 +0,0 @@
-module github.com/nats-io/nats.go
-
-require (
- github.com/nats-io/jwt v0.3.0
- github.com/nats-io/nkeys v0.1.0
- github.com/nats-io/nuid v1.0.1
-)
diff --git a/vendor/github.com/nats-io/nats.go/go.sum b/vendor/github.com/nats-io/nats.go/go.sum
deleted file mode 100644
index 0cd4f64847b..00000000000
--- a/vendor/github.com/nats-io/nats.go/go.sum
+++ /dev/null
@@ -1,13 +0,0 @@
-github.com/nats-io/jwt v0.3.0 h1:xdnzwFETV++jNc4W1mw//qFyJGb2ABOombmZJQS4+Qo=
-github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
-github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4=
-github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/vendor/github.com/nats-io/nats.go/nats.go b/vendor/github.com/nats-io/nats.go/nats.go
deleted file mode 100644
index 911df590e09..00000000000
--- a/vendor/github.com/nats-io/nats.go/nats.go
+++ /dev/null
@@ -1,4157 +0,0 @@
-// Copyright 2012-2019 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// A Go client for the NATS messaging system (https://nats.io).
-package nats
-
-import (
- "bufio"
- "bytes"
- "crypto/tls"
- "crypto/x509"
- "encoding/base64"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "math/rand"
- "net"
- "net/url"
- "os"
- "path/filepath"
- "runtime"
- "strconv"
- "strings"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/nats-io/jwt"
- "github.com/nats-io/nats.go/util"
- "github.com/nats-io/nkeys"
- "github.com/nats-io/nuid"
-)
-
-// Default Constants
-const (
- Version = "1.9.1"
- DefaultURL = "nats://127.0.0.1:4222"
- DefaultPort = 4222
- DefaultMaxReconnect = 60
- DefaultReconnectWait = 2 * time.Second
- DefaultTimeout = 2 * time.Second
- DefaultPingInterval = 2 * time.Minute
- DefaultMaxPingOut = 2
- DefaultMaxChanLen = 8192 // 8k
- DefaultReconnectBufSize = 8 * 1024 * 1024 // 8MB
- RequestChanLen = 8
- DefaultDrainTimeout = 30 * time.Second
- LangString = "go"
-)
-
-const (
- // STALE_CONNECTION is for detection and proper handling of stale connections.
- STALE_CONNECTION = "stale connection"
-
- // PERMISSIONS_ERR is for when nats server subject authorization has failed.
- PERMISSIONS_ERR = "permissions violation"
-
- // AUTHORIZATION_ERR is for when nats server user authorization has failed.
- AUTHORIZATION_ERR = "authorization violation"
-
- // AUTHENTICATION_EXPIRED_ERR is for when nats server user authorization has expired.
- AUTHENTICATION_EXPIRED_ERR = "user authentication expired"
-)
-
-// Errors
-var (
- ErrConnectionClosed = errors.New("nats: connection closed")
- ErrConnectionDraining = errors.New("nats: connection draining")
- ErrDrainTimeout = errors.New("nats: draining connection timed out")
- ErrConnectionReconnecting = errors.New("nats: connection reconnecting")
- ErrSecureConnRequired = errors.New("nats: secure connection required")
- ErrSecureConnWanted = errors.New("nats: secure connection not available")
- ErrBadSubscription = errors.New("nats: invalid subscription")
- ErrTypeSubscription = errors.New("nats: invalid subscription type")
- ErrBadSubject = errors.New("nats: invalid subject")
- ErrBadQueueName = errors.New("nats: invalid queue name")
- ErrSlowConsumer = errors.New("nats: slow consumer, messages dropped")
- ErrTimeout = errors.New("nats: timeout")
- ErrBadTimeout = errors.New("nats: timeout invalid")
- ErrAuthorization = errors.New("nats: authorization violation")
- ErrAuthExpired = errors.New("nats: authentication expired")
- ErrNoServers = errors.New("nats: no servers available for connection")
- ErrJsonParse = errors.New("nats: connect message, json parse error")
- ErrChanArg = errors.New("nats: argument needs to be a channel type")
- ErrMaxPayload = errors.New("nats: maximum payload exceeded")
- ErrMaxMessages = errors.New("nats: maximum messages delivered")
- ErrSyncSubRequired = errors.New("nats: illegal call on an async subscription")
- ErrMultipleTLSConfigs = errors.New("nats: multiple tls.Configs not allowed")
- ErrNoInfoReceived = errors.New("nats: protocol exception, INFO not received")
- ErrReconnectBufExceeded = errors.New("nats: outbound buffer limit exceeded")
- ErrInvalidConnection = errors.New("nats: invalid connection")
- ErrInvalidMsg = errors.New("nats: invalid message or message nil")
- ErrInvalidArg = errors.New("nats: invalid argument")
- ErrInvalidContext = errors.New("nats: invalid context")
- ErrNoDeadlineContext = errors.New("nats: context requires a deadline")
- ErrNoEchoNotSupported = errors.New("nats: no echo option not supported by this server")
- ErrClientIDNotSupported = errors.New("nats: client ID not supported by this server")
- ErrUserButNoSigCB = errors.New("nats: user callback defined without a signature handler")
- ErrNkeyButNoSigCB = errors.New("nats: nkey defined without a signature handler")
- ErrNoUserCB = errors.New("nats: user callback not defined")
- ErrNkeyAndUser = errors.New("nats: user callback and nkey defined")
- ErrNkeysNotSupported = errors.New("nats: nkeys not supported by the server")
- ErrStaleConnection = errors.New("nats: " + STALE_CONNECTION)
- ErrTokenAlreadySet = errors.New("nats: token and token handler both set")
- ErrMsgNotBound = errors.New("nats: message is not bound to subscription/connection")
- ErrMsgNoReply = errors.New("nats: message does not have a reply")
-)
-
-func init() {
- rand.Seed(time.Now().UnixNano())
-}
-
-// GetDefaultOptions returns default configuration options for the client.
-func GetDefaultOptions() Options {
- return Options{
- AllowReconnect: true,
- MaxReconnect: DefaultMaxReconnect,
- ReconnectWait: DefaultReconnectWait,
- Timeout: DefaultTimeout,
- PingInterval: DefaultPingInterval,
- MaxPingsOut: DefaultMaxPingOut,
- SubChanLen: DefaultMaxChanLen,
- ReconnectBufSize: DefaultReconnectBufSize,
- DrainTimeout: DefaultDrainTimeout,
- }
-}
-
-// DEPRECATED: Use GetDefaultOptions() instead.
-// DefaultOptions is not safe for use by multiple clients.
-// For details see #308.
-var DefaultOptions = GetDefaultOptions()
-
-// Status represents the state of the connection.
-type Status int
-
-const (
- DISCONNECTED = Status(iota)
- CONNECTED
- CLOSED
- RECONNECTING
- CONNECTING
- DRAINING_SUBS
- DRAINING_PUBS
-)
-
-// ConnHandler is used for asynchronous events such as
-// disconnected and closed connections.
-type ConnHandler func(*Conn)
-
-// ConnErrHandler is used to process asynchronous events like
-// disconnected connection with the error (if any).
-type ConnErrHandler func(*Conn, error)
-
-// ErrHandler is used to process asynchronous errors encountered
-// while processing inbound messages.
-type ErrHandler func(*Conn, *Subscription, error)
-
-// UserJWTHandler is used to fetch and return the account signed
-// JWT for this user.
-type UserJWTHandler func() (string, error)
-
-// SignatureHandler is used to sign a nonce from the server while
-// authenticating with nkeys. The user should sign the nonce and
-// return the raw signature. The client will base64 encode this to
-// send to the server.
-type SignatureHandler func([]byte) ([]byte, error)
-
-// AuthTokenHandler is used to generate a new token.
-type AuthTokenHandler func() string
-
-// asyncCB is used to preserve order for async callbacks.
-type asyncCB struct {
- f func()
- next *asyncCB
-}
-
-type asyncCallbacksHandler struct {
- mu sync.Mutex
- cond *sync.Cond
- head *asyncCB
- tail *asyncCB
-}
-
-// Option is a function on the options for a connection.
-type Option func(*Options) error
-
-// CustomDialer can be used to specify any dialer, not necessarily
-// a *net.Dialer.
-type CustomDialer interface {
- Dial(network, address string) (net.Conn, error)
-}
-
-// Options can be used to create a customized connection.
-type Options struct {
-
- // Url represents a single NATS server url to which the client
- // will be connecting. If the Servers option is also set, it
- // then becomes the first server in the Servers array.
- Url string
-
- // Servers is a configured set of servers which this client
- // will use when attempting to connect.
- Servers []string
-
- // NoRandomize configures whether we will randomize the
- // server pool.
- NoRandomize bool
-
- // NoEcho configures whether the server will echo back messages
- // that are sent on this connection if we also have matching subscriptions.
- // Note this is supported on servers >= version 1.2. Proto 1 or greater.
- NoEcho bool
-
- // Name is an optional name label which will be sent to the server
- // on CONNECT to identify the client.
- Name string
-
- // Verbose signals the server to send an OK ack for commands
- // successfully processed by the server.
- Verbose bool
-
- // Pedantic signals the server whether it should be doing further
- // validation of subjects.
- Pedantic bool
-
- // Secure enables TLS secure connections that skip server
- // verification by default. NOT RECOMMENDED.
- Secure bool
-
- // TLSConfig is a custom TLS configuration to use for secure
- // transports.
- TLSConfig *tls.Config
-
- // AllowReconnect enables reconnection logic to be used when we
- // encounter a disconnect from the current server.
- AllowReconnect bool
-
- // MaxReconnect sets the number of reconnect attempts that will be
- // tried before giving up. If negative, then it will never give up
- // trying to reconnect.
- MaxReconnect int
-
- // ReconnectWait sets the time to backoff after attempting a reconnect
- // to a server that we were already connected to previously.
- ReconnectWait time.Duration
-
- // Timeout sets the timeout for a Dial operation on a connection.
- Timeout time.Duration
-
- // DrainTimeout sets the timeout for a Drain Operation to complete.
- DrainTimeout time.Duration
-
- // FlusherTimeout is the maximum time to wait for write operations
- // to the underlying connection to complete (including the flusher loop).
- FlusherTimeout time.Duration
-
- // PingInterval is the period at which the client will be sending ping
- // commands to the server, disabled if 0 or negative.
- PingInterval time.Duration
-
- // MaxPingsOut is the maximum number of pending ping commands that can
- // be awaiting a response before raising an ErrStaleConnection error.
- MaxPingsOut int
-
- // ClosedCB sets the closed handler that is called when a client will
- // no longer be connected.
- ClosedCB ConnHandler
-
- // DisconnectedCB sets the disconnected handler that is called
- // whenever the connection is disconnected.
- // Will not be called if DisconnectedErrCB is set
- // DEPRECATED. Use DisconnectedErrCB which passes error that caused
- // the disconnect event.
- DisconnectedCB ConnHandler
-
- // DisconnectedErrCB sets the disconnected error handler that is called
- // whenever the connection is disconnected.
- // Disconnected error could be nil, for instance when user explicitly closes the connection.
- // DisconnectedCB will not be called if DisconnectedErrCB is set
- DisconnectedErrCB ConnErrHandler
-
- // ReconnectedCB sets the reconnected handler called whenever
- // the connection is successfully reconnected.
- ReconnectedCB ConnHandler
-
- // DiscoveredServersCB sets the callback that is invoked whenever a new
- // server has joined the cluster.
- DiscoveredServersCB ConnHandler
-
- // AsyncErrorCB sets the async error handler (e.g. slow consumer errors)
- AsyncErrorCB ErrHandler
-
- // ReconnectBufSize is the size of the backing bufio during reconnect.
- // Once this has been exhausted publish operations will return an error.
- ReconnectBufSize int
-
- // SubChanLen is the size of the buffered channel used between the socket
- // Go routine and the message delivery for SyncSubscriptions.
- // NOTE: This does not affect AsyncSubscriptions which are
- // dictated by PendingLimits()
- SubChanLen int
-
- // UserJWT sets the callback handler that will fetch a user's JWT.
- UserJWT UserJWTHandler
-
- // Nkey sets the public nkey that will be used to authenticate
- // when connecting to the server. UserJWT and Nkey are mutually exclusive
- // and if defined, UserJWT will take precedence.
- Nkey string
-
- // SignatureCB designates the function used to sign the nonce
- // presented from the server.
- SignatureCB SignatureHandler
-
- // User sets the username to be used when connecting to the server.
- User string
-
- // Password sets the password to be used when connecting to a server.
- Password string
-
- // Token sets the token to be used when connecting to a server.
- Token string
-
- // TokenHandler designates the function used to generate the token to be used when connecting to a server.
- TokenHandler AuthTokenHandler
-
- // Dialer allows a custom net.Dialer when forming connections.
- // DEPRECATED: should use CustomDialer instead.
- Dialer *net.Dialer
-
- // CustomDialer allows to specify a custom dialer (not necessarily
- // a *net.Dialer).
- CustomDialer CustomDialer
-
- // UseOldRequestStyle forces the old method of Requests that utilize
- // a new Inbox and a new Subscription for each request.
- UseOldRequestStyle bool
-
- // NoCallbacksAfterClientClose allows preventing the invocation of
- // callbacks after Close() is called. Client won't receive notifications
- // when Close is invoked by user code. Default is to invoke the callbacks.
- NoCallbacksAfterClientClose bool
-}
-
-const (
- // Scratch storage for assembling protocol headers
- scratchSize = 512
-
- // The size of the bufio reader/writer on top of the socket.
- defaultBufSize = 32768
-
- // The buffered size of the flush "kick" channel
- flushChanSize = 1
-
- // Default server pool size
- srvPoolSize = 4
-
- // NUID size
- nuidSize = 22
-
- // Default port used if none is specified in given URL(s)
- defaultPortString = "4222"
-)
-
-// A Conn represents a bare connection to a nats-server.
-// It can send and receive []byte payloads.
-// The connection is safe to use in multiple Go routines concurrently.
-type Conn struct {
- // Keep all members for which we use atomic at the beginning of the
- // struct and make sure they are all 64bits (or use padding if necessary).
- // atomic.* functions crash on 32bit machines if operand is not aligned
- // at 64bit. See https://github.com/golang/go/issues/599
- Statistics
- mu sync.RWMutex
- // Opts holds the configuration of the Conn.
- // Modifying the configuration of a running Conn is a race.
- Opts Options
- wg sync.WaitGroup
- srvPool []*srv
- current *srv
- urls map[string]struct{} // Keep track of all known URLs (used by processInfo)
- conn net.Conn
- bw *bufio.Writer
- pending *bytes.Buffer
- fch chan struct{}
- info serverInfo
- ssid int64
- subsMu sync.RWMutex
- subs map[int64]*Subscription
- ach *asyncCallbacksHandler
- pongs []chan struct{}
- scratch [scratchSize]byte
- status Status
- initc bool // true if the connection is performing the initial connect
- err error
- ps *parseState
- ptmr *time.Timer
- pout int
- ar bool // abort reconnect
-
- // New style response handler
- respSub string // The wildcard subject
- respScanf string // The scanf template to extract mux token
- respMux *Subscription // A single response subscription
- respMap map[string]chan *Msg // Request map for the response msg channels
- respSetup sync.Once // Ensures response subscription occurs once
- respRand *rand.Rand // Used for generating suffix
-}
-
-// A Subscription represents interest in a given subject.
-type Subscription struct {
- mu sync.Mutex
- sid int64
-
- // Subject that represents this subscription. This can be different
- // than the received subject inside a Msg if this is a wildcard.
- Subject string
-
- // Optional queue group name. If present, all subscriptions with the
- // same name will form a distributed queue, and each message will
- // only be processed by one member of the group.
- Queue string
-
- delivered uint64
- max uint64
- conn *Conn
- mcb MsgHandler
- mch chan *Msg
- closed bool
- sc bool
- connClosed bool
-
- // Type of Subscription
- typ SubscriptionType
-
- // Async linked list
- pHead *Msg
- pTail *Msg
- pCond *sync.Cond
-
- // Pending stats, async subscriptions, high-speed etc.
- pMsgs int
- pBytes int
- pMsgsMax int
- pBytesMax int
- pMsgsLimit int
- pBytesLimit int
- dropped int
-}
-
-// Msg is a structure used by Subscribers and PublishMsg().
-type Msg struct {
- Subject string
- Reply string
- Data []byte
- Sub *Subscription
- next *Msg
- barrier *barrierInfo
-}
-
-type barrierInfo struct {
- refs int64
- f func()
-}
-
-// Tracks various stats received and sent on this connection,
-// including counts for messages and bytes.
-type Statistics struct {
- InMsgs uint64
- OutMsgs uint64
- InBytes uint64
- OutBytes uint64
- Reconnects uint64
-}
-
-// Tracks individual backend servers.
-type srv struct {
- url *url.URL
- didConnect bool
- reconnects int
- lastAttempt time.Time
- lastErr error
- isImplicit bool
- tlsName string
-}
-
-type serverInfo struct {
- Id string `json:"server_id"`
- Host string `json:"host"`
- Port uint `json:"port"`
- Version string `json:"version"`
- AuthRequired bool `json:"auth_required"`
- TLSRequired bool `json:"tls_required"`
- MaxPayload int64 `json:"max_payload"`
- ConnectURLs []string `json:"connect_urls,omitempty"`
- Proto int `json:"proto,omitempty"`
- CID uint64 `json:"client_id,omitempty"`
- Nonce string `json:"nonce,omitempty"`
-}
-
-const (
- // clientProtoZero is the original client protocol from 2009.
- // http://nats.io/documentation/internals/nats-protocol/
- /* clientProtoZero */ _ = iota
- // clientProtoInfo signals a client can receive more then the original INFO block.
- // This can be used to update clients on other cluster members, etc.
- clientProtoInfo
-)
-
-type connectInfo struct {
- Verbose bool `json:"verbose"`
- Pedantic bool `json:"pedantic"`
- UserJWT string `json:"jwt,omitempty"`
- Nkey string `json:"nkey,omitempty"`
- Signature string `json:"sig,omitempty"`
- User string `json:"user,omitempty"`
- Pass string `json:"pass,omitempty"`
- Token string `json:"auth_token,omitempty"`
- TLS bool `json:"tls_required"`
- Name string `json:"name"`
- Lang string `json:"lang"`
- Version string `json:"version"`
- Protocol int `json:"protocol"`
- Echo bool `json:"echo"`
-}
-
-// MsgHandler is a callback function that processes messages delivered to
-// asynchronous subscribers.
-type MsgHandler func(msg *Msg)
-
-// Connect will attempt to connect to the NATS system.
-// The url can contain username/password semantics. e.g. nats://derek:pass@localhost:4222
-// Comma separated arrays are also supported, e.g. urlA, urlB.
-// Options start with the defaults but can be overridden.
-func Connect(url string, options ...Option) (*Conn, error) {
- opts := GetDefaultOptions()
- opts.Servers = processUrlString(url)
- for _, opt := range options {
- if opt != nil {
- if err := opt(&opts); err != nil {
- return nil, err
- }
- }
- }
- return opts.Connect()
-}
-
-// Options that can be passed to Connect.
-
-// Name is an Option to set the client name.
-func Name(name string) Option {
- return func(o *Options) error {
- o.Name = name
- return nil
- }
-}
-
-// Secure is an Option to enable TLS secure connections that skip server verification by default.
-// Pass a TLS Configuration for proper TLS.
-// NOTE: This should NOT be used in a production setting.
-func Secure(tls ...*tls.Config) Option {
- return func(o *Options) error {
- o.Secure = true
- // Use of variadic just simplifies testing scenarios. We only take the first one.
- if len(tls) > 1 {
- return ErrMultipleTLSConfigs
- }
- if len(tls) == 1 {
- o.TLSConfig = tls[0]
- }
- return nil
- }
-}
-
-// RootCAs is a helper option to provide the RootCAs pool from a list of filenames.
-// If Secure is not already set this will set it as well.
-func RootCAs(file ...string) Option {
- return func(o *Options) error {
- pool := x509.NewCertPool()
- for _, f := range file {
- rootPEM, err := ioutil.ReadFile(f)
- if err != nil || rootPEM == nil {
- return fmt.Errorf("nats: error loading or parsing rootCA file: %v", err)
- }
- ok := pool.AppendCertsFromPEM(rootPEM)
- if !ok {
- return fmt.Errorf("nats: failed to parse root certificate from %q", f)
- }
- }
- if o.TLSConfig == nil {
- o.TLSConfig = &tls.Config{MinVersion: tls.VersionTLS12}
- }
- o.TLSConfig.RootCAs = pool
- o.Secure = true
- return nil
- }
-}
-
-// ClientCert is a helper option to provide the client certificate from a file.
-// If Secure is not already set this will set it as well.
-func ClientCert(certFile, keyFile string) Option {
- return func(o *Options) error {
- cert, err := tls.LoadX509KeyPair(certFile, keyFile)
- if err != nil {
- return fmt.Errorf("nats: error loading client certificate: %v", err)
- }
- cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
- if err != nil {
- return fmt.Errorf("nats: error parsing client certificate: %v", err)
- }
- if o.TLSConfig == nil {
- o.TLSConfig = &tls.Config{MinVersion: tls.VersionTLS12}
- }
- o.TLSConfig.Certificates = []tls.Certificate{cert}
- o.Secure = true
- return nil
- }
-}
-
-// NoReconnect is an Option to turn off reconnect behavior.
-func NoReconnect() Option {
- return func(o *Options) error {
- o.AllowReconnect = false
- return nil
- }
-}
-
-// DontRandomize is an Option to turn off randomizing the server pool.
-func DontRandomize() Option {
- return func(o *Options) error {
- o.NoRandomize = true
- return nil
- }
-}
-
-// NoEcho is an Option to turn off messages echoing back from a server.
-// Note this is supported on servers >= version 1.2. Proto 1 or greater.
-func NoEcho() Option {
- return func(o *Options) error {
- o.NoEcho = true
- return nil
- }
-}
-
-// ReconnectWait is an Option to set the wait time between reconnect attempts.
-func ReconnectWait(t time.Duration) Option {
- return func(o *Options) error {
- o.ReconnectWait = t
- return nil
- }
-}
-
-// MaxReconnects is an Option to set the maximum number of reconnect attempts.
-func MaxReconnects(max int) Option {
- return func(o *Options) error {
- o.MaxReconnect = max
- return nil
- }
-}
-
-// PingInterval is an Option to set the period for client ping commands.
-func PingInterval(t time.Duration) Option {
- return func(o *Options) error {
- o.PingInterval = t
- return nil
- }
-}
-
-// MaxPingsOutstanding is an Option to set the maximum number of ping requests
-// that can go un-answered by the server before closing the connection.
-func MaxPingsOutstanding(max int) Option {
- return func(o *Options) error {
- o.MaxPingsOut = max
- return nil
- }
-}
-
-// ReconnectBufSize sets the buffer size of messages kept while busy reconnecting.
-func ReconnectBufSize(size int) Option {
- return func(o *Options) error {
- o.ReconnectBufSize = size
- return nil
- }
-}
-
-// Timeout is an Option to set the timeout for Dial on a connection.
-func Timeout(t time.Duration) Option {
- return func(o *Options) error {
- o.Timeout = t
- return nil
- }
-}
-
-// FlusherTimeout is an Option to set the write (and flush) timeout on a connection.
-func FlusherTimeout(t time.Duration) Option {
- return func(o *Options) error {
- o.FlusherTimeout = t
- return nil
- }
-}
-
-// DrainTimeout is an Option to set the timeout for draining a connection.
-func DrainTimeout(t time.Duration) Option {
- return func(o *Options) error {
- o.DrainTimeout = t
- return nil
- }
-}
-
-// DisconnectErrHandler is an Option to set the disconnected error handler.
-func DisconnectErrHandler(cb ConnErrHandler) Option {
- return func(o *Options) error {
- o.DisconnectedErrCB = cb
- return nil
- }
-}
-
-// DisconnectHandler is an Option to set the disconnected handler.
-// DEPRECATED: Use DisconnectErrHandler.
-func DisconnectHandler(cb ConnHandler) Option {
- return func(o *Options) error {
- o.DisconnectedCB = cb
- return nil
- }
-}
-
-// ReconnectHandler is an Option to set the reconnected handler.
-func ReconnectHandler(cb ConnHandler) Option {
- return func(o *Options) error {
- o.ReconnectedCB = cb
- return nil
- }
-}
-
-// ClosedHandler is an Option to set the closed handler.
-func ClosedHandler(cb ConnHandler) Option {
- return func(o *Options) error {
- o.ClosedCB = cb
- return nil
- }
-}
-
-// DiscoveredServersHandler is an Option to set the new servers handler.
-func DiscoveredServersHandler(cb ConnHandler) Option {
- return func(o *Options) error {
- o.DiscoveredServersCB = cb
- return nil
- }
-}
-
-// ErrorHandler is an Option to set the async error handler.
-func ErrorHandler(cb ErrHandler) Option {
- return func(o *Options) error {
- o.AsyncErrorCB = cb
- return nil
- }
-}
-
-// UserInfo is an Option to set the username and password to
-// use when not included directly in the URLs.
-func UserInfo(user, password string) Option {
- return func(o *Options) error {
- o.User = user
- o.Password = password
- return nil
- }
-}
-
-// Token is an Option to set the token to use
-// when a token is not included directly in the URLs
-// and when a token handler is not provided.
-func Token(token string) Option {
- return func(o *Options) error {
- if o.TokenHandler != nil {
- return ErrTokenAlreadySet
- }
- o.Token = token
- return nil
- }
-}
-
-// TokenHandler is an Option to set the token handler to use
-// when a token is not included directly in the URLs
-// and when a token is not set.
-func TokenHandler(cb AuthTokenHandler) Option {
- return func(o *Options) error {
- if o.Token != "" {
- return ErrTokenAlreadySet
- }
- o.TokenHandler = cb
- return nil
- }
-}
-
-// UserCredentials is a convenience function that takes a filename
-// for a user's JWT and a filename for the user's private Nkey seed.
-func UserCredentials(userOrChainedFile string, seedFiles ...string) Option {
- userCB := func() (string, error) {
- return userFromFile(userOrChainedFile)
- }
- var keyFile string
- if len(seedFiles) > 0 {
- keyFile = seedFiles[0]
- } else {
- keyFile = userOrChainedFile
- }
- sigCB := func(nonce []byte) ([]byte, error) {
- return sigHandler(nonce, keyFile)
- }
- return UserJWT(userCB, sigCB)
-}
-
-// UserJWT will set the callbacks to retrieve the user's JWT and
-// the signature callback to sign the server nonce. This an the Nkey
-// option are mutually exclusive.
-func UserJWT(userCB UserJWTHandler, sigCB SignatureHandler) Option {
- return func(o *Options) error {
- if userCB == nil {
- return ErrNoUserCB
- }
- if sigCB == nil {
- return ErrUserButNoSigCB
- }
- o.UserJWT = userCB
- o.SignatureCB = sigCB
- return nil
- }
-}
-
-// Nkey will set the public Nkey and the signature callback to
-// sign the server nonce.
-func Nkey(pubKey string, sigCB SignatureHandler) Option {
- return func(o *Options) error {
- o.Nkey = pubKey
- o.SignatureCB = sigCB
- if pubKey != "" && sigCB == nil {
- return ErrNkeyButNoSigCB
- }
- return nil
- }
-}
-
-// SyncQueueLen will set the maximum queue len for the internal
-// channel used for SubscribeSync().
-func SyncQueueLen(max int) Option {
- return func(o *Options) error {
- o.SubChanLen = max
- return nil
- }
-}
-
-// Dialer is an Option to set the dialer which will be used when
-// attempting to establish a connection.
-// DEPRECATED: Should use CustomDialer instead.
-func Dialer(dialer *net.Dialer) Option {
- return func(o *Options) error {
- o.Dialer = dialer
- return nil
- }
-}
-
-// SetCustomDialer is an Option to set a custom dialer which will be
-// used when attempting to establish a connection. If both Dialer
-// and CustomDialer are specified, CustomDialer takes precedence.
-func SetCustomDialer(dialer CustomDialer) Option {
- return func(o *Options) error {
- o.CustomDialer = dialer
- return nil
- }
-}
-
-// UseOldRequestStyle is an Option to force usage of the old Request style.
-func UseOldRequestStyle() Option {
- return func(o *Options) error {
- o.UseOldRequestStyle = true
- return nil
- }
-}
-
-// NoCallbacksAfterClientClose is an Option to disable callbacks when user code
-// calls Close(). If close is initiated by any other condition, callbacks
-// if any will be invoked.
-func NoCallbacksAfterClientClose() Option {
- return func(o *Options) error {
- o.NoCallbacksAfterClientClose = true
- return nil
- }
-}
-
-// Handler processing
-
-// SetDisconnectHandler will set the disconnect event handler.
-// DEPRECATED: Use SetDisconnectErrHandler
-func (nc *Conn) SetDisconnectHandler(dcb ConnHandler) {
- if nc == nil {
- return
- }
- nc.mu.Lock()
- defer nc.mu.Unlock()
- nc.Opts.DisconnectedCB = dcb
-}
-
-// SetDisconnectErrHandler will set the disconnect event handler.
-func (nc *Conn) SetDisconnectErrHandler(dcb ConnErrHandler) {
- if nc == nil {
- return
- }
- nc.mu.Lock()
- defer nc.mu.Unlock()
- nc.Opts.DisconnectedErrCB = dcb
-}
-
-// SetReconnectHandler will set the reconnect event handler.
-func (nc *Conn) SetReconnectHandler(rcb ConnHandler) {
- if nc == nil {
- return
- }
- nc.mu.Lock()
- defer nc.mu.Unlock()
- nc.Opts.ReconnectedCB = rcb
-}
-
-// SetDiscoveredServersHandler will set the discovered servers handler.
-func (nc *Conn) SetDiscoveredServersHandler(dscb ConnHandler) {
- if nc == nil {
- return
- }
- nc.mu.Lock()
- defer nc.mu.Unlock()
- nc.Opts.DiscoveredServersCB = dscb
-}
-
-// SetClosedHandler will set the reconnect event handler.
-func (nc *Conn) SetClosedHandler(cb ConnHandler) {
- if nc == nil {
- return
- }
- nc.mu.Lock()
- defer nc.mu.Unlock()
- nc.Opts.ClosedCB = cb
-}
-
-// SetErrorHandler will set the async error handler.
-func (nc *Conn) SetErrorHandler(cb ErrHandler) {
- if nc == nil {
- return
- }
- nc.mu.Lock()
- defer nc.mu.Unlock()
- nc.Opts.AsyncErrorCB = cb
-}
-
-// Process the url string argument to Connect.
-// Return an array of urls, even if only one.
-func processUrlString(url string) []string {
- urls := strings.Split(url, ",")
- for i, s := range urls {
- urls[i] = strings.TrimSpace(s)
- }
- return urls
-}
-
-// Connect will attempt to connect to a NATS server with multiple options.
-func (o Options) Connect() (*Conn, error) {
- nc := &Conn{Opts: o}
-
- // Some default options processing.
- if nc.Opts.MaxPingsOut == 0 {
- nc.Opts.MaxPingsOut = DefaultMaxPingOut
- }
- // Allow old default for channel length to work correctly.
- if nc.Opts.SubChanLen == 0 {
- nc.Opts.SubChanLen = DefaultMaxChanLen
- }
- // Default ReconnectBufSize
- if nc.Opts.ReconnectBufSize == 0 {
- nc.Opts.ReconnectBufSize = DefaultReconnectBufSize
- }
- // Ensure that Timeout is not 0
- if nc.Opts.Timeout == 0 {
- nc.Opts.Timeout = DefaultTimeout
- }
-
- // Check first for user jwt callback being defined and nkey.
- if nc.Opts.UserJWT != nil && nc.Opts.Nkey != "" {
- return nil, ErrNkeyAndUser
- }
-
- // Check if we have an nkey but no signature callback defined.
- if nc.Opts.Nkey != "" && nc.Opts.SignatureCB == nil {
- return nil, ErrNkeyButNoSigCB
- }
-
- // Allow custom Dialer for connecting using DialTimeout by default
- if nc.Opts.Dialer == nil {
- nc.Opts.Dialer = &net.Dialer{
- Timeout: nc.Opts.Timeout,
- }
- }
-
- if err := nc.setupServerPool(); err != nil {
- return nil, err
- }
-
- // Create the async callback handler.
- nc.ach = &asyncCallbacksHandler{}
- nc.ach.cond = sync.NewCond(&nc.ach.mu)
-
- if err := nc.connect(); err != nil {
- return nil, err
- }
-
- // Spin up the async cb dispatcher on success
- go nc.ach.asyncCBDispatcher()
-
- return nc, nil
-}
-
-const (
- _CRLF_ = "\r\n"
- _EMPTY_ = ""
- _SPC_ = " "
- _PUB_P_ = "PUB "
-)
-
-const (
- _OK_OP_ = "+OK"
- _ERR_OP_ = "-ERR"
- _PONG_OP_ = "PONG"
- _INFO_OP_ = "INFO"
-)
-
-const (
- conProto = "CONNECT %s" + _CRLF_
- pingProto = "PING" + _CRLF_
- pongProto = "PONG" + _CRLF_
- subProto = "SUB %s %s %d" + _CRLF_
- unsubProto = "UNSUB %d %s" + _CRLF_
- okProto = _OK_OP_ + _CRLF_
-)
-
-// Return the currently selected server
-func (nc *Conn) currentServer() (int, *srv) {
- for i, s := range nc.srvPool {
- if s == nil {
- continue
- }
- if s == nc.current {
- return i, s
- }
- }
- return -1, nil
-}
-
-// Pop the current server and put onto the end of the list. Select head of list as long
-// as number of reconnect attempts under MaxReconnect.
-func (nc *Conn) selectNextServer() (*srv, error) {
- i, s := nc.currentServer()
- if i < 0 {
- return nil, ErrNoServers
- }
- sp := nc.srvPool
- num := len(sp)
- copy(sp[i:num-1], sp[i+1:num])
- maxReconnect := nc.Opts.MaxReconnect
- if maxReconnect < 0 || s.reconnects < maxReconnect {
- nc.srvPool[num-1] = s
- } else {
- nc.srvPool = sp[0 : num-1]
- }
- if len(nc.srvPool) <= 0 {
- nc.current = nil
- return nil, ErrNoServers
- }
- nc.current = nc.srvPool[0]
- return nc.srvPool[0], nil
-}
-
-// Will assign the correct server to nc.current
-func (nc *Conn) pickServer() error {
- nc.current = nil
- if len(nc.srvPool) <= 0 {
- return ErrNoServers
- }
-
- for _, s := range nc.srvPool {
- if s != nil {
- nc.current = s
- return nil
- }
- }
- return ErrNoServers
-}
-
-const tlsScheme = "tls"
-
-// Create the server pool using the options given.
-// We will place a Url option first, followed by any
-// Server Options. We will randomize the server pool unless
-// the NoRandomize flag is set.
-func (nc *Conn) setupServerPool() error {
- nc.srvPool = make([]*srv, 0, srvPoolSize)
- nc.urls = make(map[string]struct{}, srvPoolSize)
-
- // Create srv objects from each url string in nc.Opts.Servers
- // and add them to the pool.
- for _, urlString := range nc.Opts.Servers {
- if err := nc.addURLToPool(urlString, false, false); err != nil {
- return err
- }
- }
-
- // Randomize if allowed to
- if !nc.Opts.NoRandomize {
- nc.shufflePool()
- }
-
- // Normally, if this one is set, Options.Servers should not be,
- // but we always allowed that, so continue to do so.
- if nc.Opts.Url != _EMPTY_ {
- // Add to the end of the array
- if err := nc.addURLToPool(nc.Opts.Url, false, false); err != nil {
- return err
- }
- // Then swap it with first to guarantee that Options.Url is tried first.
- last := len(nc.srvPool) - 1
- if last > 0 {
- nc.srvPool[0], nc.srvPool[last] = nc.srvPool[last], nc.srvPool[0]
- }
- } else if len(nc.srvPool) <= 0 {
- // Place default URL if pool is empty.
- if err := nc.addURLToPool(DefaultURL, false, false); err != nil {
- return err
- }
- }
-
- // Check for Scheme hint to move to TLS mode.
- for _, srv := range nc.srvPool {
- if srv.url.Scheme == tlsScheme {
- // FIXME(dlc), this is for all in the pool, should be case by case.
- nc.Opts.Secure = true
- if nc.Opts.TLSConfig == nil {
- nc.Opts.TLSConfig = &tls.Config{MinVersion: tls.VersionTLS12}
- }
- }
- }
-
- return nc.pickServer()
-}
-
-// Helper function to return scheme
-func (nc *Conn) connScheme() string {
- if nc.Opts.Secure {
- return tlsScheme
- }
- return "nats"
-}
-
-// Return true iff u.Hostname() is an IP address.
-func hostIsIP(u *url.URL) bool {
- return net.ParseIP(u.Hostname()) != nil
-}
-
-// addURLToPool adds an entry to the server pool
-func (nc *Conn) addURLToPool(sURL string, implicit, saveTLSName bool) error {
- if !strings.Contains(sURL, "://") {
- sURL = fmt.Sprintf("%s://%s", nc.connScheme(), sURL)
- }
- var (
- u *url.URL
- err error
- )
- for i := 0; i < 2; i++ {
- u, err = url.Parse(sURL)
- if err != nil {
- return err
- }
- if u.Port() != "" {
- break
- }
- // In case given URL is of the form "localhost:", just add
- // the port number at the end, otherwise, add ":4222".
- if sURL[len(sURL)-1] != ':' {
- sURL += ":"
- }
- sURL += defaultPortString
- }
-
- var tlsName string
- if implicit {
- curl := nc.current.url
- // Check to see if we do not have a url.User but current connected
- // url does. If so copy over.
- if u.User == nil && curl.User != nil {
- u.User = curl.User
- }
- // We are checking to see if we have a secure connection and are
- // adding an implicit server that just has an IP. If so we will remember
- // the current hostname we are connected to.
- if saveTLSName && hostIsIP(u) {
- tlsName = curl.Hostname()
- }
- }
-
- s := &srv{url: u, isImplicit: implicit, tlsName: tlsName}
- nc.srvPool = append(nc.srvPool, s)
- nc.urls[u.Host] = struct{}{}
- return nil
-}
-
-// shufflePool swaps randomly elements in the server pool
-func (nc *Conn) shufflePool() {
- if len(nc.srvPool) <= 1 {
- return
- }
- source := rand.NewSource(time.Now().UnixNano())
- r := rand.New(source)
- for i := range nc.srvPool {
- j := r.Intn(i + 1)
- nc.srvPool[i], nc.srvPool[j] = nc.srvPool[j], nc.srvPool[i]
- }
-}
-
-func (nc *Conn) newBuffer() *bufio.Writer {
- var w io.Writer = nc.conn
- if nc.Opts.FlusherTimeout > 0 {
- w = &timeoutWriter{conn: nc.conn, timeout: nc.Opts.FlusherTimeout}
- }
- return bufio.NewWriterSize(w, defaultBufSize)
-}
-
-// createConn will connect to the server and wrap the appropriate
-// bufio structures. It will do the right thing when an existing
-// connection is in place.
-func (nc *Conn) createConn() (err error) {
- if nc.Opts.Timeout < 0 {
- return ErrBadTimeout
- }
- if _, cur := nc.currentServer(); cur == nil {
- return ErrNoServers
- } else {
- cur.lastAttempt = time.Now()
- }
-
- // We will auto-expand host names if they resolve to multiple IPs
- hosts := []string{}
- u := nc.current.url
-
- if net.ParseIP(u.Hostname()) == nil {
- addrs, _ := net.LookupHost(u.Hostname())
- for _, addr := range addrs {
- hosts = append(hosts, net.JoinHostPort(addr, u.Port()))
- }
- }
- // Fall back to what we were given.
- if len(hosts) == 0 {
- hosts = append(hosts, u.Host)
- }
-
- // CustomDialer takes precedence. If not set, use Opts.Dialer which
- // is set to a default *net.Dialer (in Connect()) if not explicitly
- // set by the user.
- dialer := nc.Opts.CustomDialer
- if dialer == nil {
- // We will copy and shorten the timeout if we have multiple hosts to try.
- copyDialer := *nc.Opts.Dialer
- copyDialer.Timeout = copyDialer.Timeout / time.Duration(len(hosts))
- dialer = ©Dialer
- }
-
- if len(hosts) > 1 && !nc.Opts.NoRandomize {
- rand.Shuffle(len(hosts), func(i, j int) {
- hosts[i], hosts[j] = hosts[j], hosts[i]
- })
- }
- for _, host := range hosts {
- nc.conn, err = dialer.Dial("tcp", host)
- if err == nil {
- break
- }
- }
- if err != nil {
- return err
- }
-
- // No clue why, but this stalls and kills performance on Mac (Mavericks).
- // https://code.google.com/p/go/issues/detail?id=6930
- //if ip, ok := nc.conn.(*net.TCPConn); ok {
- // ip.SetReadBuffer(defaultBufSize)
- //}
-
- if nc.pending != nil && nc.bw != nil {
- // Move to pending buffer.
- nc.bw.Flush()
- }
- nc.bw = nc.newBuffer()
- return nil
-}
-
-// makeTLSConn will wrap an existing Conn using TLS
-func (nc *Conn) makeTLSConn() error {
- // Allow the user to configure their own tls.Config structure.
- var tlsCopy *tls.Config
- if nc.Opts.TLSConfig != nil {
- tlsCopy = util.CloneTLSConfig(nc.Opts.TLSConfig)
- } else {
- tlsCopy = &tls.Config{}
- }
- // If its blank we will override it with the current host
- if tlsCopy.ServerName == _EMPTY_ {
- if nc.current.tlsName != _EMPTY_ {
- tlsCopy.ServerName = nc.current.tlsName
- } else {
- h, _, _ := net.SplitHostPort(nc.current.url.Host)
- tlsCopy.ServerName = h
- }
- }
- nc.conn = tls.Client(nc.conn, tlsCopy)
- conn := nc.conn.(*tls.Conn)
- if err := conn.Handshake(); err != nil {
- return err
- }
- nc.bw = nc.newBuffer()
- return nil
-}
-
-// waitForExits will wait for all socket watcher Go routines to
-// be shutdown before proceeding.
-func (nc *Conn) waitForExits() {
- // Kick old flusher forcefully.
- select {
- case nc.fch <- struct{}{}:
- default:
- }
-
- // Wait for any previous go routines.
- nc.wg.Wait()
-}
-
-// Report the connected server's Url
-func (nc *Conn) ConnectedUrl() string {
- if nc == nil {
- return _EMPTY_
- }
-
- nc.mu.RLock()
- defer nc.mu.RUnlock()
-
- if nc.status != CONNECTED {
- return _EMPTY_
- }
- return nc.current.url.String()
-}
-
-// ConnectedAddr returns the connected server's IP
-func (nc *Conn) ConnectedAddr() string {
- if nc == nil {
- return _EMPTY_
- }
-
- nc.mu.RLock()
- defer nc.mu.RUnlock()
-
- if nc.status != CONNECTED {
- return _EMPTY_
- }
- return nc.conn.RemoteAddr().String()
-}
-
-// Report the connected server's Id
-func (nc *Conn) ConnectedServerId() string {
- if nc == nil {
- return _EMPTY_
- }
-
- nc.mu.RLock()
- defer nc.mu.RUnlock()
-
- if nc.status != CONNECTED {
- return _EMPTY_
- }
- return nc.info.Id
-}
-
-// Low level setup for structs, etc
-func (nc *Conn) setup() {
- nc.subs = make(map[int64]*Subscription)
- nc.pongs = make([]chan struct{}, 0, 8)
-
- nc.fch = make(chan struct{}, flushChanSize)
-
- // Setup scratch outbound buffer for PUB
- pub := nc.scratch[:len(_PUB_P_)]
- copy(pub, _PUB_P_)
-}
-
-// Process a connected connection and initialize properly.
-func (nc *Conn) processConnectInit() error {
-
- // Set our deadline for the whole connect process
- nc.conn.SetDeadline(time.Now().Add(nc.Opts.Timeout))
- defer nc.conn.SetDeadline(time.Time{})
-
- // Set our status to connecting.
- nc.status = CONNECTING
-
- // Process the INFO protocol received from the server
- err := nc.processExpectedInfo()
- if err != nil {
- return err
- }
-
- // Send the CONNECT protocol along with the initial PING protocol.
- // Wait for the PONG response (or any error that we get from the server).
- err = nc.sendConnect()
- if err != nil {
- return err
- }
-
- // Reset the number of PING sent out
- nc.pout = 0
-
- // Start or reset Timer
- if nc.Opts.PingInterval > 0 {
- if nc.ptmr == nil {
- nc.ptmr = time.AfterFunc(nc.Opts.PingInterval, nc.processPingTimer)
- } else {
- nc.ptmr.Reset(nc.Opts.PingInterval)
- }
- }
-
- // Start the readLoop and flusher go routines, we will wait on both on a reconnect event.
- nc.wg.Add(2)
- go nc.readLoop()
- go nc.flusher()
-
- return nil
-}
-
-// Main connect function. Will connect to the nats-server
-func (nc *Conn) connect() error {
- var returnedErr error
-
- // Create actual socket connection
- // For first connect we walk all servers in the pool and try
- // to connect immediately.
- nc.mu.Lock()
- nc.initc = true
- // The pool may change inside the loop iteration due to INFO protocol.
- for i := 0; i < len(nc.srvPool); i++ {
- nc.current = nc.srvPool[i]
-
- if err := nc.createConn(); err == nil {
- // This was moved out of processConnectInit() because
- // that function is now invoked from doReconnect() too.
- nc.setup()
-
- err = nc.processConnectInit()
-
- if err == nil {
- nc.srvPool[i].didConnect = true
- nc.srvPool[i].reconnects = 0
- nc.current.lastErr = nil
- returnedErr = nil
- break
- } else {
- returnedErr = err
- nc.mu.Unlock()
- nc.close(DISCONNECTED, false, err)
- nc.mu.Lock()
- nc.current = nil
- }
- } else {
- // Cancel out default connection refused, will trigger the
- // No servers error conditional
- if strings.Contains(err.Error(), "connection refused") {
- returnedErr = nil
- }
- }
- }
- nc.initc = false
- if returnedErr == nil && nc.status != CONNECTED {
- returnedErr = ErrNoServers
- }
- nc.mu.Unlock()
- return returnedErr
-}
-
-// This will check to see if the connection should be
-// secure. This can be dictated from either end and should
-// only be called after the INIT protocol has been received.
-func (nc *Conn) checkForSecure() error {
- // Check to see if we need to engage TLS
- o := nc.Opts
-
- // Check for mismatch in setups
- if o.Secure && !nc.info.TLSRequired {
- return ErrSecureConnWanted
- } else if nc.info.TLSRequired && !o.Secure {
- // Switch to Secure since server needs TLS.
- o.Secure = true
- }
-
- // Need to rewrap with bufio
- if o.Secure {
- if err := nc.makeTLSConn(); err != nil {
- return err
- }
- }
- return nil
-}
-
-// processExpectedInfo will look for the expected first INFO message
-// sent when a connection is established. The lock should be held entering.
-func (nc *Conn) processExpectedInfo() error {
-
- c := &control{}
-
- // Read the protocol
- err := nc.readOp(c)
- if err != nil {
- return err
- }
-
- // The nats protocol should send INFO first always.
- if c.op != _INFO_OP_ {
- return ErrNoInfoReceived
- }
-
- // Parse the protocol
- if err := nc.processInfo(c.args); err != nil {
- return err
- }
-
- if nc.Opts.Nkey != "" && nc.info.Nonce == "" {
- return ErrNkeysNotSupported
- }
-
- return nc.checkForSecure()
-}
-
-// Sends a protocol control message by queuing into the bufio writer
-// and kicking the flush Go routine. These writes are protected.
-func (nc *Conn) sendProto(proto string) {
- nc.mu.Lock()
- nc.bw.WriteString(proto)
- nc.kickFlusher()
- nc.mu.Unlock()
-}
-
-// Generate a connect protocol message, issuing user/password if
-// applicable. The lock is assumed to be held upon entering.
-func (nc *Conn) connectProto() (string, error) {
- o := nc.Opts
- var nkey, sig, user, pass, token, ujwt string
- u := nc.current.url.User
- if u != nil {
- // if no password, assume username is authToken
- if _, ok := u.Password(); !ok {
- token = u.Username()
- } else {
- user = u.Username()
- pass, _ = u.Password()
- }
- } else {
- // Take from options (possibly all empty strings)
- user = o.User
- pass = o.Password
- token = o.Token
- nkey = o.Nkey
- }
-
- // Look for user jwt.
- if o.UserJWT != nil {
- if jwt, err := o.UserJWT(); err != nil {
- return _EMPTY_, err
- } else {
- ujwt = jwt
- }
- if nkey != _EMPTY_ {
- return _EMPTY_, ErrNkeyAndUser
- }
- }
-
- if ujwt != _EMPTY_ || nkey != _EMPTY_ {
- if o.SignatureCB == nil {
- if ujwt == _EMPTY_ {
- return _EMPTY_, ErrNkeyButNoSigCB
- }
- return _EMPTY_, ErrUserButNoSigCB
- }
- sigraw, err := o.SignatureCB([]byte(nc.info.Nonce))
- if err != nil {
- return _EMPTY_, err
- }
- sig = base64.RawURLEncoding.EncodeToString(sigraw)
- }
-
- if nc.Opts.TokenHandler != nil {
- if token != _EMPTY_ {
- return _EMPTY_, ErrTokenAlreadySet
- }
- token = nc.Opts.TokenHandler()
- }
-
- cinfo := connectInfo{o.Verbose, o.Pedantic, ujwt, nkey, sig, user, pass, token,
- o.Secure, o.Name, LangString, Version, clientProtoInfo, !o.NoEcho}
-
- b, err := json.Marshal(cinfo)
- if err != nil {
- return _EMPTY_, ErrJsonParse
- }
-
- // Check if NoEcho is set and we have a server that supports it.
- if o.NoEcho && nc.info.Proto < 1 {
- return _EMPTY_, ErrNoEchoNotSupported
- }
-
- return fmt.Sprintf(conProto, b), nil
-}
-
-// normalizeErr removes the prefix -ERR, trim spaces and remove the quotes.
-func normalizeErr(line string) string {
- s := strings.TrimSpace(strings.TrimPrefix(line, _ERR_OP_))
- s = strings.TrimLeft(strings.TrimRight(s, "'"), "'")
- return s
-}
-
-// Send a connect protocol message to the server, issue user/password if
-// applicable. Will wait for a flush to return from the server for error
-// processing.
-func (nc *Conn) sendConnect() error {
- // Construct the CONNECT protocol string
- cProto, err := nc.connectProto()
- if err != nil {
- return err
- }
-
- // Write the protocol into the buffer
- _, err = nc.bw.WriteString(cProto)
- if err != nil {
- return err
- }
-
- // Add to the buffer the PING protocol
- _, err = nc.bw.WriteString(pingProto)
- if err != nil {
- return err
- }
-
- // Flush the buffer
- err = nc.bw.Flush()
- if err != nil {
- return err
- }
-
- // We don't want to read more than we need here, otherwise
- // we would need to transfer the excess read data to the readLoop.
- // Since in normal situations we just are looking for a PONG\r\n,
- // reading byte-by-byte here is ok.
- proto, err := nc.readProto()
- if err != nil {
- return err
- }
-
- // If opts.Verbose is set, handle +OK
- if nc.Opts.Verbose && proto == okProto {
- // Read the rest now...
- proto, err = nc.readProto()
- if err != nil {
- return err
- }
- }
-
- // We expect a PONG
- if proto != pongProto {
- // But it could be something else, like -ERR
-
- // Since we no longer use ReadLine(), trim the trailing "\r\n"
- proto = strings.TrimRight(proto, "\r\n")
-
- // If it's a server error...
- if strings.HasPrefix(proto, _ERR_OP_) {
- // Remove -ERR, trim spaces and quotes, and convert to lower case.
- proto = normalizeErr(proto)
-
- // Check if this is an auth error
- if authErr := checkAuthError(strings.ToLower(proto)); authErr != nil {
- // This will schedule an async error if we are in reconnect,
- // and keep track of the auth error for the current server.
- // If we have got the same error twice, this sets nc.ar to true to
- // indicate that the reconnect should be aborted (will be checked
- // in doReconnect()).
- nc.processAuthError(authErr)
- }
-
- return errors.New("nats: " + proto)
- }
-
- // Notify that we got an unexpected protocol.
- return fmt.Errorf("nats: expected '%s', got '%s'", _PONG_OP_, proto)
- }
-
- // This is where we are truly connected.
- nc.status = CONNECTED
-
- return nil
-}
-
-// reads a protocol one byte at a time.
-func (nc *Conn) readProto() (string, error) {
- var (
- _buf = [10]byte{}
- buf = _buf[:0]
- b = [1]byte{}
- protoEnd = byte('\n')
- )
- for {
- if _, err := nc.conn.Read(b[:1]); err != nil {
- // Do not report EOF error
- if err == io.EOF {
- return string(buf), nil
- }
- return "", err
- }
- buf = append(buf, b[0])
- if b[0] == protoEnd {
- return string(buf), nil
- }
- }
-}
-
-// A control protocol line.
-type control struct {
- op, args string
-}
-
-// Read a control line and process the intended op.
-func (nc *Conn) readOp(c *control) error {
- br := bufio.NewReaderSize(nc.conn, defaultBufSize)
- line, err := br.ReadString('\n')
- if err != nil {
- return err
- }
- parseControl(line, c)
- return nil
-}
-
-// Parse a control line from the server.
-func parseControl(line string, c *control) {
- toks := strings.SplitN(line, _SPC_, 2)
- if len(toks) == 1 {
- c.op = strings.TrimSpace(toks[0])
- c.args = _EMPTY_
- } else if len(toks) == 2 {
- c.op, c.args = strings.TrimSpace(toks[0]), strings.TrimSpace(toks[1])
- } else {
- c.op = _EMPTY_
- }
-}
-
-// flushReconnectPending will push the pending items that were
-// gathered while we were in a RECONNECTING state to the socket.
-func (nc *Conn) flushReconnectPendingItems() {
- if nc.pending == nil {
- return
- }
- if nc.pending.Len() > 0 {
- nc.bw.Write(nc.pending.Bytes())
- }
-}
-
-// Stops the ping timer if set.
-// Connection lock is held on entry.
-func (nc *Conn) stopPingTimer() {
- if nc.ptmr != nil {
- nc.ptmr.Stop()
- }
-}
-
-// Try to reconnect using the option parameters.
-// This function assumes we are allowed to reconnect.
-func (nc *Conn) doReconnect(err error) {
- // We want to make sure we have the other watchers shutdown properly
- // here before we proceed past this point.
- nc.waitForExits()
-
- // FIXME(dlc) - We have an issue here if we have
- // outstanding flush points (pongs) and they were not
- // sent out, but are still in the pipe.
-
- // Hold the lock manually and release where needed below,
- // can't do defer here.
- nc.mu.Lock()
-
- // Clear any queued pongs, e.g. pending flush calls.
- nc.clearPendingFlushCalls()
-
- // Clear any errors.
- nc.err = nil
- // Perform appropriate callback if needed for a disconnect.
- // DisconnectedErrCB has priority over deprecated DisconnectedCB
- if nc.Opts.DisconnectedErrCB != nil {
- nc.ach.push(func() { nc.Opts.DisconnectedErrCB(nc, err) })
- } else if nc.Opts.DisconnectedCB != nil {
- nc.ach.push(func() { nc.Opts.DisconnectedCB(nc) })
- }
-
- // This is used to wait on go routines exit if we start them in the loop
- // but an error occurs after that.
- waitForGoRoutines := false
-
- for len(nc.srvPool) > 0 {
- cur, err := nc.selectNextServer()
- if err != nil {
- nc.err = err
- break
- }
-
- sleepTime := int64(0)
-
- // Sleep appropriate amount of time before the
- // connection attempt if connecting to same server
- // we just got disconnected from..
- if time.Since(cur.lastAttempt) < nc.Opts.ReconnectWait {
- sleepTime = int64(nc.Opts.ReconnectWait - time.Since(cur.lastAttempt))
- }
-
- // On Windows, createConn() will take more than a second when no
- // server is running at that address. So it could be that the
- // time elapsed between reconnect attempts is always > than
- // the set option. Release the lock to give a chance to a parallel
- // nc.Close() to break the loop.
- nc.mu.Unlock()
- if sleepTime <= 0 {
- runtime.Gosched()
- } else {
- time.Sleep(time.Duration(sleepTime))
- }
- // If the readLoop, etc.. go routines were started, wait for them to complete.
- if waitForGoRoutines {
- nc.waitForExits()
- waitForGoRoutines = false
- }
- nc.mu.Lock()
-
- // Check if we have been closed first.
- if nc.isClosed() {
- break
- }
-
- // Mark that we tried a reconnect
- cur.reconnects++
-
- // Try to create a new connection
- err = nc.createConn()
-
- // Not yet connected, retry...
- // Continue to hold the lock
- if err != nil {
- nc.err = nil
- continue
- }
-
- // We are reconnected
- nc.Reconnects++
-
- // Process connect logic
- if nc.err = nc.processConnectInit(); nc.err != nil {
- // Check if we should abort reconnect. If so, break out
- // of the loop and connection will be closed.
- if nc.ar {
- break
- }
- nc.status = RECONNECTING
- // Reset the buffered writer to the pending buffer
- // (was set to a buffered writer on nc.conn in createConn)
- nc.bw.Reset(nc.pending)
- continue
- }
-
- // Clear possible lastErr under the connection lock after
- // a successful processConnectInit().
- nc.current.lastErr = nil
-
- // Clear out server stats for the server we connected to..
- cur.didConnect = true
- cur.reconnects = 0
-
- // Send existing subscription state
- nc.resendSubscriptions()
-
- // Now send off and clear pending buffer
- nc.flushReconnectPendingItems()
-
- // Flush the buffer
- nc.err = nc.bw.Flush()
- if nc.err != nil {
- nc.status = RECONNECTING
- // Reset the buffered writer to the pending buffer (bytes.Buffer).
- nc.bw.Reset(nc.pending)
- // Stop the ping timer (if set)
- nc.stopPingTimer()
- // Since processConnectInit() returned without error, the
- // go routines were started, so wait for them to return
- // on the next iteration (after releasing the lock).
- waitForGoRoutines = true
- continue
- }
-
- // Done with the pending buffer
- nc.pending = nil
-
- // This is where we are truly connected.
- nc.status = CONNECTED
-
- // Queue up the reconnect callback.
- if nc.Opts.ReconnectedCB != nil {
- nc.ach.push(func() { nc.Opts.ReconnectedCB(nc) })
- }
-
- // Release lock here, we will return below.
- nc.mu.Unlock()
-
- // Make sure to flush everything
- nc.Flush()
-
- return
- }
-
- // Call into close.. We have no servers left..
- if nc.err == nil {
- nc.err = ErrNoServers
- }
- nc.mu.Unlock()
- nc.close(CLOSED, true, nil)
-}
-
-// processOpErr handles errors from reading or parsing the protocol.
-// The lock should not be held entering this function.
-func (nc *Conn) processOpErr(err error) {
- nc.mu.Lock()
- if nc.isConnecting() || nc.isClosed() || nc.isReconnecting() {
- nc.mu.Unlock()
- return
- }
-
- if nc.Opts.AllowReconnect && nc.status == CONNECTED {
- // Set our new status
- nc.status = RECONNECTING
- // Stop ping timer if set
- nc.stopPingTimer()
- if nc.conn != nil {
- nc.bw.Flush()
- nc.conn.Close()
- nc.conn = nil
- }
-
- // Create pending buffer before reconnecting.
- nc.pending = new(bytes.Buffer)
- nc.bw.Reset(nc.pending)
-
- go nc.doReconnect(err)
- nc.mu.Unlock()
- return
- }
-
- nc.status = DISCONNECTED
- nc.err = err
- nc.mu.Unlock()
- nc.close(CLOSED, true, nil)
-}
-
-// dispatch is responsible for calling any async callbacks
-func (ac *asyncCallbacksHandler) asyncCBDispatcher() {
- for {
- ac.mu.Lock()
- // Protect for spurious wakeups. We should get out of the
- // wait only if there is an element to pop from the list.
- for ac.head == nil {
- ac.cond.Wait()
- }
- cur := ac.head
- ac.head = cur.next
- if cur == ac.tail {
- ac.tail = nil
- }
- ac.mu.Unlock()
-
- // This signals that the dispatcher has been closed and all
- // previous callbacks have been dispatched.
- if cur.f == nil {
- return
- }
- // Invoke callback outside of handler's lock
- cur.f()
- }
-}
-
-// Add the given function to the tail of the list and
-// signals the dispatcher.
-func (ac *asyncCallbacksHandler) push(f func()) {
- ac.pushOrClose(f, false)
-}
-
-// Signals that we are closing...
-func (ac *asyncCallbacksHandler) close() {
- ac.pushOrClose(nil, true)
-}
-
-// Add the given function to the tail of the list and
-// signals the dispatcher.
-func (ac *asyncCallbacksHandler) pushOrClose(f func(), close bool) {
- ac.mu.Lock()
- defer ac.mu.Unlock()
- // Make sure that library is not calling push with nil function,
- // since this is used to notify the dispatcher that it should stop.
- if !close && f == nil {
- panic("pushing a nil callback")
- }
- cb := &asyncCB{f: f}
- if ac.tail != nil {
- ac.tail.next = cb
- } else {
- ac.head = cb
- }
- ac.tail = cb
- if close {
- ac.cond.Broadcast()
- } else {
- ac.cond.Signal()
- }
-}
-
-// readLoop() will sit on the socket reading and processing the
-// protocol from the server. It will dispatch appropriately based
-// on the op type.
-func (nc *Conn) readLoop() {
- // Release the wait group on exit
- defer nc.wg.Done()
-
- // Create a parseState if needed.
- nc.mu.Lock()
- if nc.ps == nil {
- nc.ps = &parseState{}
- }
- nc.mu.Unlock()
-
- // Stack based buffer.
- b := make([]byte, defaultBufSize)
-
- for {
- // ps is thread safe, so RLock is okay
- nc.mu.RLock()
- sb := nc.isClosed() || nc.isReconnecting()
- if sb {
- nc.ps = &parseState{}
- }
- conn := nc.conn
- nc.mu.RUnlock()
-
- if sb || conn == nil {
- break
- }
-
- n, err := conn.Read(b)
- if err != nil {
- nc.processOpErr(err)
- break
- }
- if err := nc.parse(b[:n]); err != nil {
- nc.processOpErr(err)
- break
- }
- }
- // Clear the parseState here..
- nc.mu.Lock()
- nc.ps = nil
- nc.mu.Unlock()
-}
-
-// waitForMsgs waits on the conditional shared with readLoop and processMsg.
-// It is used to deliver messages to asynchronous subscribers.
-func (nc *Conn) waitForMsgs(s *Subscription) {
- var closed bool
- var delivered, max uint64
-
- // Used to account for adjustments to sub.pBytes when we wrap back around.
- msgLen := -1
-
- for {
- s.mu.Lock()
- // Do accounting for last msg delivered here so we only lock once
- // and drain state trips after callback has returned.
- if msgLen >= 0 {
- s.pMsgs--
- s.pBytes -= msgLen
- msgLen = -1
- }
-
- if s.pHead == nil && !s.closed {
- s.pCond.Wait()
- }
- // Pop the msg off the list
- m := s.pHead
- if m != nil {
- s.pHead = m.next
- if s.pHead == nil {
- s.pTail = nil
- }
- if m.barrier != nil {
- s.mu.Unlock()
- if atomic.AddInt64(&m.barrier.refs, -1) == 0 {
- m.barrier.f()
- }
- continue
- }
- msgLen = len(m.Data)
- }
- mcb := s.mcb
- max = s.max
- closed = s.closed
- if !s.closed {
- s.delivered++
- delivered = s.delivered
- }
- s.mu.Unlock()
-
- if closed {
- break
- }
-
- // Deliver the message.
- if m != nil && (max == 0 || delivered <= max) {
- mcb(m)
- }
- // If we have hit the max for delivered msgs, remove sub.
- if max > 0 && delivered >= max {
- nc.mu.Lock()
- nc.removeSub(s)
- nc.mu.Unlock()
- break
- }
- }
- // Check for barrier messages
- s.mu.Lock()
- for m := s.pHead; m != nil; m = s.pHead {
- if m.barrier != nil {
- s.mu.Unlock()
- if atomic.AddInt64(&m.barrier.refs, -1) == 0 {
- m.barrier.f()
- }
- s.mu.Lock()
- }
- s.pHead = m.next
- }
- s.mu.Unlock()
-}
-
-// processMsg is called by parse and will place the msg on the
-// appropriate channel/pending queue for processing. If the channel is full,
-// or the pending queue is over the pending limits, the connection is
-// considered a slow consumer.
-func (nc *Conn) processMsg(data []byte) {
- // Don't lock the connection to avoid server cutting us off if the
- // flusher is holding the connection lock, trying to send to the server
- // that is itself trying to send data to us.
- nc.subsMu.RLock()
-
- // Stats
- atomic.AddUint64(&nc.InMsgs, 1)
- atomic.AddUint64(&nc.InBytes, uint64(len(data)))
-
- sub := nc.subs[nc.ps.ma.sid]
- if sub == nil {
- nc.subsMu.RUnlock()
- return
- }
-
- // Copy them into string
- subj := string(nc.ps.ma.subject)
- reply := string(nc.ps.ma.reply)
-
- // Doing message create outside of the sub's lock to reduce contention.
- // It's possible that we end-up not using the message, but that's ok.
-
- // FIXME(dlc): Need to copy, should/can do COW?
- msgPayload := make([]byte, len(data))
- copy(msgPayload, data)
-
- // FIXME(dlc): Should we recycle these containers?
- m := &Msg{Data: msgPayload, Subject: subj, Reply: reply, Sub: sub}
-
- sub.mu.Lock()
-
- // Subscription internal stats (applicable only for non ChanSubscription's)
- if sub.typ != ChanSubscription {
- sub.pMsgs++
- if sub.pMsgs > sub.pMsgsMax {
- sub.pMsgsMax = sub.pMsgs
- }
- sub.pBytes += len(m.Data)
- if sub.pBytes > sub.pBytesMax {
- sub.pBytesMax = sub.pBytes
- }
-
- // Check for a Slow Consumer
- if (sub.pMsgsLimit > 0 && sub.pMsgs > sub.pMsgsLimit) ||
- (sub.pBytesLimit > 0 && sub.pBytes > sub.pBytesLimit) {
- goto slowConsumer
- }
- }
-
- // We have two modes of delivery. One is the channel, used by channel
- // subscribers and syncSubscribers, the other is a linked list for async.
- if sub.mch != nil {
- select {
- case sub.mch <- m:
- default:
- goto slowConsumer
- }
- } else {
- // Push onto the async pList
- if sub.pHead == nil {
- sub.pHead = m
- sub.pTail = m
- sub.pCond.Signal()
- } else {
- sub.pTail.next = m
- sub.pTail = m
- }
- }
-
- // Clear SlowConsumer status.
- sub.sc = false
-
- sub.mu.Unlock()
- nc.subsMu.RUnlock()
- return
-
-slowConsumer:
- sub.dropped++
- sc := !sub.sc
- sub.sc = true
- // Undo stats from above
- if sub.typ != ChanSubscription {
- sub.pMsgs--
- sub.pBytes -= len(m.Data)
- }
- sub.mu.Unlock()
- nc.subsMu.RUnlock()
- if sc {
- // Now we need connection's lock and we may end-up in the situation
- // that we were trying to avoid, except that in this case, the client
- // is already experiencing client-side slow consumer situation.
- nc.mu.Lock()
- nc.err = ErrSlowConsumer
- if nc.Opts.AsyncErrorCB != nil {
- nc.ach.push(func() { nc.Opts.AsyncErrorCB(nc, sub, ErrSlowConsumer) })
- }
- nc.mu.Unlock()
- }
-}
-
-// processPermissionsViolation is called when the server signals a subject
-// permissions violation on either publish or subscribe.
-func (nc *Conn) processPermissionsViolation(err string) {
- nc.mu.Lock()
- // create error here so we can pass it as a closure to the async cb dispatcher.
- e := errors.New("nats: " + err)
- nc.err = e
- if nc.Opts.AsyncErrorCB != nil {
- nc.ach.push(func() { nc.Opts.AsyncErrorCB(nc, nil, e) })
- }
- nc.mu.Unlock()
-}
-
-// processAuthError generally processing for auth errors. We want to do retries
-// unless we get the same error again. This allows us for instance to swap credentials
-// and have the app reconnect, but if nothing is changing we should bail.
-// This function will return true if the connection should be closed, false otherwise.
-// Connection lock is held on entry
-func (nc *Conn) processAuthError(err error) bool {
- nc.err = err
- if !nc.initc && nc.Opts.AsyncErrorCB != nil {
- nc.ach.push(func() { nc.Opts.AsyncErrorCB(nc, nil, err) })
- }
- // We should give up if we tried twice on this server and got the
- // same error.
- if nc.current.lastErr == err {
- nc.ar = true
- } else {
- nc.current.lastErr = err
- }
- return nc.ar
-}
-
-// flusher is a separate Go routine that will process flush requests for the write
-// bufio. This allows coalescing of writes to the underlying socket.
-func (nc *Conn) flusher() {
- // Release the wait group
- defer nc.wg.Done()
-
- // snapshot the bw and conn since they can change from underneath of us.
- nc.mu.Lock()
- bw := nc.bw
- conn := nc.conn
- fch := nc.fch
- nc.mu.Unlock()
-
- if conn == nil || bw == nil {
- return
- }
-
- for {
- if _, ok := <-fch; !ok {
- return
- }
- nc.mu.Lock()
-
- // Check to see if we should bail out.
- if !nc.isConnected() || nc.isConnecting() || bw != nc.bw || conn != nc.conn {
- nc.mu.Unlock()
- return
- }
- if bw.Buffered() > 0 {
- if err := bw.Flush(); err != nil {
- if nc.err == nil {
- nc.err = err
- }
- }
- }
- nc.mu.Unlock()
- }
-}
-
-// processPing will send an immediate pong protocol response to the
-// server. The server uses this mechanism to detect dead clients.
-func (nc *Conn) processPing() {
- nc.sendProto(pongProto)
-}
-
-// processPong is used to process responses to the client's ping
-// messages. We use pings for the flush mechanism as well.
-func (nc *Conn) processPong() {
- var ch chan struct{}
-
- nc.mu.Lock()
- if len(nc.pongs) > 0 {
- ch = nc.pongs[0]
- nc.pongs = nc.pongs[1:]
- }
- nc.pout = 0
- nc.mu.Unlock()
- if ch != nil {
- ch <- struct{}{}
- }
-}
-
-// processOK is a placeholder for processing OK messages.
-func (nc *Conn) processOK() {
- // do nothing
-}
-
-// processInfo is used to parse the info messages sent
-// from the server.
-// This function may update the server pool.
-func (nc *Conn) processInfo(info string) error {
- if info == _EMPTY_ {
- return nil
- }
- ncInfo := serverInfo{}
- if err := json.Unmarshal([]byte(info), &ncInfo); err != nil {
- return err
- }
-
- // Copy content into connection's info structure.
- nc.info = ncInfo
- // The array could be empty/not present on initial connect,
- // if advertise is disabled on that server, or servers that
- // did not include themselves in the async INFO protocol.
- // If empty, do not remove the implicit servers from the pool.
- if len(ncInfo.ConnectURLs) == 0 {
- return nil
- }
- // Note about pool randomization: when the pool was first created,
- // it was randomized (if allowed). We keep the order the same (removing
- // implicit servers that are no longer sent to us). New URLs are sent
- // to us in no specific order so don't need extra randomization.
- hasNew := false
- // This is what we got from the server we are connected to.
- urls := nc.info.ConnectURLs
- // Transform that to a map for easy lookups
- tmp := make(map[string]struct{}, len(urls))
- for _, curl := range urls {
- tmp[curl] = struct{}{}
- }
- // Walk the pool and removed the implicit servers that are no longer in the
- // given array/map
- sp := nc.srvPool
- for i := 0; i < len(sp); i++ {
- srv := sp[i]
- curl := srv.url.Host
- // Check if this URL is in the INFO protocol
- _, inInfo := tmp[curl]
- // Remove from the temp map so that at the end we are left with only
- // new (or restarted) servers that need to be added to the pool.
- delete(tmp, curl)
- // Keep servers that were set through Options, but also the one that
- // we are currently connected to (even if it is a discovered server).
- if !srv.isImplicit || srv.url == nc.current.url {
- continue
- }
- if !inInfo {
- // Remove from server pool. Keep current order.
- copy(sp[i:], sp[i+1:])
- nc.srvPool = sp[:len(sp)-1]
- sp = nc.srvPool
- i--
- }
- }
- // Figure out if we should save off the current non-IP hostname if we encounter a bare IP.
- saveTLS := nc.current != nil && !hostIsIP(nc.current.url)
-
- // If there are any left in the tmp map, these are new (or restarted) servers
- // and need to be added to the pool.
- for curl := range tmp {
- // Before adding, check if this is a new (as in never seen) URL.
- // This is used to figure out if we invoke the DiscoveredServersCB
- if _, present := nc.urls[curl]; !present {
- hasNew = true
- }
- nc.addURLToPool(fmt.Sprintf("%s://%s", nc.connScheme(), curl), true, saveTLS)
- }
- if hasNew && !nc.initc && nc.Opts.DiscoveredServersCB != nil {
- nc.ach.push(func() { nc.Opts.DiscoveredServersCB(nc) })
- }
-
- return nil
-}
-
-// processAsyncInfo does the same than processInfo, but is called
-// from the parser. Calls processInfo under connection's lock
-// protection.
-func (nc *Conn) processAsyncInfo(info []byte) {
- nc.mu.Lock()
- // Ignore errors, we will simply not update the server pool...
- nc.processInfo(string(info))
- nc.mu.Unlock()
-}
-
-// LastError reports the last error encountered via the connection.
-// It can be used reliably within ClosedCB in order to find out reason
-// why connection was closed for example.
-func (nc *Conn) LastError() error {
- if nc == nil {
- return ErrInvalidConnection
- }
- nc.mu.RLock()
- err := nc.err
- nc.mu.RUnlock()
- return err
-}
-
-// Check if the given error string is an auth error, and if so returns
-// the corresponding ErrXXX error, nil otherwise
-func checkAuthError(e string) error {
- if strings.HasPrefix(e, AUTHORIZATION_ERR) {
- return ErrAuthorization
- }
- if strings.HasPrefix(e, AUTHENTICATION_EXPIRED_ERR) {
- return ErrAuthExpired
- }
- return nil
-}
-
-// processErr processes any error messages from the server and
-// sets the connection's lastError.
-func (nc *Conn) processErr(ie string) {
- // Trim, remove quotes
- ne := normalizeErr(ie)
- // convert to lower case.
- e := strings.ToLower(ne)
-
- close := false
-
- // FIXME(dlc) - process Slow Consumer signals special.
- if e == STALE_CONNECTION {
- nc.processOpErr(ErrStaleConnection)
- } else if strings.HasPrefix(e, PERMISSIONS_ERR) {
- nc.processPermissionsViolation(ne)
- } else if authErr := checkAuthError(e); authErr != nil {
- nc.mu.Lock()
- close = nc.processAuthError(authErr)
- nc.mu.Unlock()
- } else {
- close = true
- nc.mu.Lock()
- nc.err = errors.New("nats: " + ne)
- nc.mu.Unlock()
- }
- if close {
- nc.close(CLOSED, true, nil)
- }
-}
-
-// kickFlusher will send a bool on a channel to kick the
-// flush Go routine to flush data to the server.
-func (nc *Conn) kickFlusher() {
- if nc.bw != nil {
- select {
- case nc.fch <- struct{}{}:
- default:
- }
- }
-}
-
-// Publish publishes the data argument to the given subject. The data
-// argument is left untouched and needs to be correctly interpreted on
-// the receiver.
-func (nc *Conn) Publish(subj string, data []byte) error {
- return nc.publish(subj, _EMPTY_, data)
-}
-
-// PublishMsg publishes the Msg structure, which includes the
-// Subject, an optional Reply and an optional Data field.
-func (nc *Conn) PublishMsg(m *Msg) error {
- if m == nil {
- return ErrInvalidMsg
- }
- return nc.publish(m.Subject, m.Reply, m.Data)
-}
-
-// PublishRequest will perform a Publish() excpecting a response on the
-// reply subject. Use Request() for automatically waiting for a response
-// inline.
-func (nc *Conn) PublishRequest(subj, reply string, data []byte) error {
- return nc.publish(subj, reply, data)
-}
-
-// Used for handrolled itoa
-const digits = "0123456789"
-
-// publish is the internal function to publish messages to a nats-server.
-// Sends a protocol data message by queuing into the bufio writer
-// and kicking the flush go routine. These writes should be protected.
-func (nc *Conn) publish(subj, reply string, data []byte) error {
- if nc == nil {
- return ErrInvalidConnection
- }
- if subj == "" {
- return ErrBadSubject
- }
- nc.mu.Lock()
-
- if nc.isClosed() {
- nc.mu.Unlock()
- return ErrConnectionClosed
- }
-
- if nc.isDrainingPubs() {
- nc.mu.Unlock()
- return ErrConnectionDraining
- }
-
- // Proactively reject payloads over the threshold set by server.
- msgSize := int64(len(data))
- if msgSize > nc.info.MaxPayload {
- nc.mu.Unlock()
- return ErrMaxPayload
- }
-
- // Check if we are reconnecting, and if so check if
- // we have exceeded our reconnect outbound buffer limits.
- if nc.isReconnecting() {
- // Flush to underlying buffer.
- nc.bw.Flush()
- // Check if we are over
- if nc.pending.Len() >= nc.Opts.ReconnectBufSize {
- nc.mu.Unlock()
- return ErrReconnectBufExceeded
- }
- }
-
- msgh := nc.scratch[:len(_PUB_P_)]
- msgh = append(msgh, subj...)
- msgh = append(msgh, ' ')
- if reply != "" {
- msgh = append(msgh, reply...)
- msgh = append(msgh, ' ')
- }
-
- // We could be smarter here, but simple loop is ok,
- // just avoid strconv in fast path
- // FIXME(dlc) - Find a better way here.
- // msgh = strconv.AppendInt(msgh, int64(len(data)), 10)
-
- var b [12]byte
- var i = len(b)
- if len(data) > 0 {
- for l := len(data); l > 0; l /= 10 {
- i -= 1
- b[i] = digits[l%10]
- }
- } else {
- i -= 1
- b[i] = digits[0]
- }
-
- msgh = append(msgh, b[i:]...)
- msgh = append(msgh, _CRLF_...)
-
- _, err := nc.bw.Write(msgh)
- if err == nil {
- _, err = nc.bw.Write(data)
- }
- if err == nil {
- _, err = nc.bw.WriteString(_CRLF_)
- }
- if err != nil {
- nc.mu.Unlock()
- return err
- }
-
- nc.OutMsgs++
- nc.OutBytes += uint64(len(data))
-
- if len(nc.fch) == 0 {
- nc.kickFlusher()
- }
- nc.mu.Unlock()
- return nil
-}
-
-// respHandler is the global response handler. It will look up
-// the appropriate channel based on the last token and place
-// the message on the channel if possible.
-func (nc *Conn) respHandler(m *Msg) {
- nc.mu.Lock()
-
- // Just return if closed.
- if nc.isClosed() {
- nc.mu.Unlock()
- return
- }
-
- var mch chan *Msg
-
- // Grab mch
- rt := nc.respToken(m.Subject)
- if rt != _EMPTY_ {
- mch = nc.respMap[rt]
- // Delete the key regardless, one response only.
- delete(nc.respMap, rt)
- } else if len(nc.respMap) == 1 {
- // If the server has rewritten the subject, the response token (rt)
- // will not match (could be the case with JetStream). If that is the
- // case and there is a single entry, use that.
- for k, v := range nc.respMap {
- mch = v
- delete(nc.respMap, k)
- break
- }
- }
- nc.mu.Unlock()
-
- // Don't block, let Request timeout instead, mch is
- // buffered and we should delete the key before a
- // second response is processed.
- select {
- case mch <- m:
- default:
- return
- }
-}
-
-// Create the response subscription we will use for all
-// new style responses. This will be on an _INBOX with an
-// additional terminal token. The subscription will be on
-// a wildcard. Caller is responsible for ensuring this is
-// only called once.
-func (nc *Conn) createRespMux(respSub string) error {
- s, err := nc.Subscribe(respSub, nc.respHandler)
- if err != nil {
- return err
- }
- nc.mu.Lock()
- nc.respScanf = strings.Replace(respSub, "*", "%s", -1)
- nc.respMux = s
- nc.mu.Unlock()
- return nil
-}
-
-// Helper to setup and send new request style requests. Return the chan to receive the response.
-func (nc *Conn) createNewRequestAndSend(subj string, data []byte) (chan *Msg, string, error) {
- // Do setup for the new style if needed.
- if nc.respMap == nil {
- nc.initNewResp()
- }
- // Create new literal Inbox and map to a chan msg.
- mch := make(chan *Msg, RequestChanLen)
- respInbox := nc.newRespInbox()
- token := respInbox[respInboxPrefixLen:]
- nc.respMap[token] = mch
- createSub := nc.respMux == nil
- ginbox := nc.respSub
- nc.mu.Unlock()
-
- if createSub {
- // Make sure scoped subscription is setup only once.
- var err error
- nc.respSetup.Do(func() { err = nc.createRespMux(ginbox) })
- if err != nil {
- return nil, token, err
- }
- }
-
- if err := nc.PublishRequest(subj, respInbox, data); err != nil {
- return nil, token, err
- }
-
- return mch, token, nil
-}
-
-// Request will send a request payload and deliver the response message,
-// or an error, including a timeout if no message was received properly.
-func (nc *Conn) Request(subj string, data []byte, timeout time.Duration) (*Msg, error) {
- if nc == nil {
- return nil, ErrInvalidConnection
- }
-
- nc.mu.Lock()
- // If user wants the old style.
- if nc.Opts.UseOldRequestStyle {
- nc.mu.Unlock()
- return nc.oldRequest(subj, data, timeout)
- }
-
- mch, token, err := nc.createNewRequestAndSend(subj, data)
- if err != nil {
- return nil, err
- }
-
- t := globalTimerPool.Get(timeout)
- defer globalTimerPool.Put(t)
-
- var ok bool
- var msg *Msg
-
- select {
- case msg, ok = <-mch:
- if !ok {
- return nil, ErrConnectionClosed
- }
- case <-t.C:
- nc.mu.Lock()
- delete(nc.respMap, token)
- nc.mu.Unlock()
- return nil, ErrTimeout
- }
-
- return msg, nil
-}
-
-// oldRequest will create an Inbox and perform a Request() call
-// with the Inbox reply and return the first reply received.
-// This is optimized for the case of multiple responses.
-func (nc *Conn) oldRequest(subj string, data []byte, timeout time.Duration) (*Msg, error) {
- inbox := NewInbox()
- ch := make(chan *Msg, RequestChanLen)
-
- s, err := nc.subscribe(inbox, _EMPTY_, nil, ch, false)
- if err != nil {
- return nil, err
- }
- s.AutoUnsubscribe(1)
- defer s.Unsubscribe()
-
- err = nc.PublishRequest(subj, inbox, data)
- if err != nil {
- return nil, err
- }
- return s.NextMsg(timeout)
-}
-
-// InboxPrefix is the prefix for all inbox subjects.
-const (
- InboxPrefix = "_INBOX."
- inboxPrefixLen = len(InboxPrefix)
- respInboxPrefixLen = inboxPrefixLen + nuidSize + 1
- replySuffixLen = 8 // Gives us 62^8
- rdigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- base = 62
-)
-
-// NewInbox will return an inbox string which can be used for directed replies from
-// subscribers. These are guaranteed to be unique, but can be shared and subscribed
-// to by others.
-func NewInbox() string {
- var b [inboxPrefixLen + nuidSize]byte
- pres := b[:inboxPrefixLen]
- copy(pres, InboxPrefix)
- ns := b[inboxPrefixLen:]
- copy(ns, nuid.Next())
- return string(b[:])
-}
-
-// Function to init new response structures.
-func (nc *Conn) initNewResp() {
- // _INBOX wildcard
- nc.respSub = fmt.Sprintf("%s.*", NewInbox())
- nc.respMap = make(map[string]chan *Msg)
- nc.respRand = rand.New(rand.NewSource(time.Now().UnixNano()))
-}
-
-// newRespInbox creates a new literal response subject
-// that will trigger the mux subscription handler.
-// Lock should be held.
-func (nc *Conn) newRespInbox() string {
- if nc.respMap == nil {
- nc.initNewResp()
- }
- var b [respInboxPrefixLen + replySuffixLen]byte
- pres := b[:respInboxPrefixLen]
- copy(pres, nc.respSub)
- rn := nc.respRand.Int63()
- for i, l := respInboxPrefixLen, rn; i < len(b); i++ {
- b[i] = rdigits[l%base]
- l /= base
- }
- return string(b[:])
-}
-
-// NewRespInbox is the new format used for _INBOX.
-func (nc *Conn) NewRespInbox() string {
- nc.mu.Lock()
- s := nc.newRespInbox()
- nc.mu.Unlock()
- return s
-}
-
-// respToken will return the last token of a literal response inbox
-// which we use for the message channel lookup. This needs to do a
-// scan to protect itself against the server changing the subject.
-// Lock should be held.
-func (nc *Conn) respToken(respInbox string) string {
- var token string
- n, err := fmt.Sscanf(respInbox, nc.respScanf, &token)
- if err != nil || n != 1 {
- return ""
- }
- return token
-}
-
-// Subscribe will express interest in the given subject. The subject
-// can have wildcards (partial:*, full:>). Messages will be delivered
-// to the associated MsgHandler.
-func (nc *Conn) Subscribe(subj string, cb MsgHandler) (*Subscription, error) {
- return nc.subscribe(subj, _EMPTY_, cb, nil, false)
-}
-
-// ChanSubscribe will express interest in the given subject and place
-// all messages received on the channel.
-// You should not close the channel until sub.Unsubscribe() has been called.
-func (nc *Conn) ChanSubscribe(subj string, ch chan *Msg) (*Subscription, error) {
- return nc.subscribe(subj, _EMPTY_, nil, ch, false)
-}
-
-// ChanQueueSubscribe will express interest in the given subject.
-// All subscribers with the same queue name will form the queue group
-// and only one member of the group will be selected to receive any given message,
-// which will be placed on the channel.
-// You should not close the channel until sub.Unsubscribe() has been called.
-// Note: This is the same than QueueSubscribeSyncWithChan.
-func (nc *Conn) ChanQueueSubscribe(subj, group string, ch chan *Msg) (*Subscription, error) {
- return nc.subscribe(subj, group, nil, ch, false)
-}
-
-// SubscribeSync will express interest on the given subject. Messages will
-// be received synchronously using Subscription.NextMsg().
-func (nc *Conn) SubscribeSync(subj string) (*Subscription, error) {
- if nc == nil {
- return nil, ErrInvalidConnection
- }
- mch := make(chan *Msg, nc.Opts.SubChanLen)
- s, e := nc.subscribe(subj, _EMPTY_, nil, mch, true)
- return s, e
-}
-
-// QueueSubscribe creates an asynchronous queue subscriber on the given subject.
-// All subscribers with the same queue name will form the queue group and
-// only one member of the group will be selected to receive any given
-// message asynchronously.
-func (nc *Conn) QueueSubscribe(subj, queue string, cb MsgHandler) (*Subscription, error) {
- return nc.subscribe(subj, queue, cb, nil, false)
-}
-
-// QueueSubscribeSync creates a synchronous queue subscriber on the given
-// subject. All subscribers with the same queue name will form the queue
-// group and only one member of the group will be selected to receive any
-// given message synchronously using Subscription.NextMsg().
-func (nc *Conn) QueueSubscribeSync(subj, queue string) (*Subscription, error) {
- mch := make(chan *Msg, nc.Opts.SubChanLen)
- s, e := nc.subscribe(subj, queue, nil, mch, true)
- return s, e
-}
-
-// QueueSubscribeSyncWithChan will express interest in the given subject.
-// All subscribers with the same queue name will form the queue group
-// and only one member of the group will be selected to receive any given message,
-// which will be placed on the channel.
-// You should not close the channel until sub.Unsubscribe() has been called.
-// Note: This is the same than ChanQueueSubscribe.
-func (nc *Conn) QueueSubscribeSyncWithChan(subj, queue string, ch chan *Msg) (*Subscription, error) {
- return nc.subscribe(subj, queue, nil, ch, false)
-}
-
-// badSubject will do quick test on whether a subject is acceptable.
-// Spaces are not allowed and all tokens should be > 0 in len.
-func badSubject(subj string) bool {
- if strings.ContainsAny(subj, " \t\r\n") {
- return true
- }
- tokens := strings.Split(subj, ".")
- for _, t := range tokens {
- if len(t) == 0 {
- return true
- }
- }
- return false
-}
-
-// badQueue will check a queue name for whitespace.
-func badQueue(qname string) bool {
- return strings.ContainsAny(qname, " \t\r\n")
-}
-
-// subscribe is the internal subscribe function that indicates interest in a subject.
-func (nc *Conn) subscribe(subj, queue string, cb MsgHandler, ch chan *Msg, isSync bool) (*Subscription, error) {
- if nc == nil {
- return nil, ErrInvalidConnection
- }
- if badSubject(subj) {
- return nil, ErrBadSubject
- }
- if queue != "" && badQueue(queue) {
- return nil, ErrBadQueueName
- }
- nc.mu.Lock()
- // ok here, but defer is generally expensive
- defer nc.mu.Unlock()
-
- // Check for some error conditions.
- if nc.isClosed() {
- return nil, ErrConnectionClosed
- }
- if nc.isDraining() {
- return nil, ErrConnectionDraining
- }
-
- if cb == nil && ch == nil {
- return nil, ErrBadSubscription
- }
-
- sub := &Subscription{Subject: subj, Queue: queue, mcb: cb, conn: nc}
- // Set pending limits.
- sub.pMsgsLimit = DefaultSubPendingMsgsLimit
- sub.pBytesLimit = DefaultSubPendingBytesLimit
-
- // If we have an async callback, start up a sub specific
- // Go routine to deliver the messages.
- if cb != nil {
- sub.typ = AsyncSubscription
- sub.pCond = sync.NewCond(&sub.mu)
- go nc.waitForMsgs(sub)
- } else if !isSync {
- sub.typ = ChanSubscription
- sub.mch = ch
- } else { // Sync Subscription
- sub.typ = SyncSubscription
- sub.mch = ch
- }
-
- nc.subsMu.Lock()
- nc.ssid++
- sub.sid = nc.ssid
- nc.subs[sub.sid] = sub
- nc.subsMu.Unlock()
-
- // We will send these for all subs when we reconnect
- // so that we can suppress here if reconnecting.
- if !nc.isReconnecting() {
- fmt.Fprintf(nc.bw, subProto, subj, queue, sub.sid)
- // Kick flusher if needed.
- if len(nc.fch) == 0 {
- nc.kickFlusher()
- }
- }
-
- return sub, nil
-}
-
-// NumSubscriptions returns active number of subscriptions.
-func (nc *Conn) NumSubscriptions() int {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return len(nc.subs)
-}
-
-// Lock for nc should be held here upon entry
-func (nc *Conn) removeSub(s *Subscription) {
- nc.subsMu.Lock()
- delete(nc.subs, s.sid)
- nc.subsMu.Unlock()
- s.mu.Lock()
- defer s.mu.Unlock()
- // Release callers on NextMsg for SyncSubscription only
- if s.mch != nil && s.typ == SyncSubscription {
- close(s.mch)
- }
- s.mch = nil
-
- // Mark as invalid
- s.closed = true
- if s.pCond != nil {
- s.pCond.Broadcast()
- }
-}
-
-// SubscriptionType is the type of the Subscription.
-type SubscriptionType int
-
-// The different types of subscription types.
-const (
- AsyncSubscription = SubscriptionType(iota)
- SyncSubscription
- ChanSubscription
- NilSubscription
-)
-
-// Type returns the type of Subscription.
-func (s *Subscription) Type() SubscriptionType {
- if s == nil {
- return NilSubscription
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- return s.typ
-}
-
-// IsValid returns a boolean indicating whether the subscription
-// is still active. This will return false if the subscription has
-// already been closed.
-func (s *Subscription) IsValid() bool {
- if s == nil {
- return false
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- return s.conn != nil && !s.closed
-}
-
-// Drain will remove interest but continue callbacks until all messages
-// have been processed.
-func (s *Subscription) Drain() error {
- if s == nil {
- return ErrBadSubscription
- }
- s.mu.Lock()
- conn := s.conn
- s.mu.Unlock()
- if conn == nil {
- return ErrBadSubscription
- }
- return conn.unsubscribe(s, 0, true)
-}
-
-// Unsubscribe will remove interest in the given subject.
-func (s *Subscription) Unsubscribe() error {
- if s == nil {
- return ErrBadSubscription
- }
- s.mu.Lock()
- conn := s.conn
- closed := s.closed
- s.mu.Unlock()
- if conn == nil || conn.IsClosed() {
- return ErrConnectionClosed
- }
- if closed {
- return ErrBadSubscription
- }
- if conn.IsDraining() {
- return ErrConnectionDraining
- }
- return conn.unsubscribe(s, 0, false)
-}
-
-// checkDrained will watch for a subscription to be fully drained
-// and then remove it.
-func (nc *Conn) checkDrained(sub *Subscription) {
- if nc == nil || sub == nil {
- return
- }
-
- // This allows us to know that whatever we have in the client pending
- // is correct and the server will not send additional information.
- nc.Flush()
-
- // Once we are here we just wait for Pending to reach 0 or
- // any other state to exit this go routine.
- for {
- // check connection is still valid.
- if nc.IsClosed() {
- return
- }
-
- // Check subscription state
- sub.mu.Lock()
- conn := sub.conn
- closed := sub.closed
- pMsgs := sub.pMsgs
- sub.mu.Unlock()
-
- if conn == nil || closed || pMsgs == 0 {
- nc.mu.Lock()
- nc.removeSub(sub)
- nc.mu.Unlock()
- return
- }
-
- time.Sleep(100 * time.Millisecond)
- }
-}
-
-// AutoUnsubscribe will issue an automatic Unsubscribe that is
-// processed by the server when max messages have been received.
-// This can be useful when sending a request to an unknown number
-// of subscribers.
-func (s *Subscription) AutoUnsubscribe(max int) error {
- if s == nil {
- return ErrBadSubscription
- }
- s.mu.Lock()
- conn := s.conn
- closed := s.closed
- s.mu.Unlock()
- if conn == nil || closed {
- return ErrBadSubscription
- }
- return conn.unsubscribe(s, max, false)
-}
-
-// unsubscribe performs the low level unsubscribe to the server.
-// Use Subscription.Unsubscribe()
-func (nc *Conn) unsubscribe(sub *Subscription, max int, drainMode bool) error {
- nc.mu.Lock()
- // ok here, but defer is expensive
- defer nc.mu.Unlock()
- defer nc.kickFlusher()
-
- if nc.isClosed() {
- return ErrConnectionClosed
- }
-
- nc.subsMu.RLock()
- s := nc.subs[sub.sid]
- nc.subsMu.RUnlock()
- // Already unsubscribed
- if s == nil {
- return nil
- }
-
- maxStr := _EMPTY_
- if max > 0 {
- s.max = uint64(max)
- maxStr = strconv.Itoa(max)
- } else if !drainMode {
- nc.removeSub(s)
- }
-
- if drainMode {
- go nc.checkDrained(sub)
- }
-
- // We will send these for all subs when we reconnect
- // so that we can suppress here.
- if !nc.isReconnecting() {
- fmt.Fprintf(nc.bw, unsubProto, s.sid, maxStr)
- }
- return nil
-}
-
-// NextMsg will return the next message available to a synchronous subscriber
-// or block until one is available. An error is returned if the subscription is invalid (ErrBadSubscription),
-// the connection is closed (ErrConnectionClosed), or the timeout is reached (ErrTimeout).
-func (s *Subscription) NextMsg(timeout time.Duration) (*Msg, error) {
- if s == nil {
- return nil, ErrBadSubscription
- }
-
- s.mu.Lock()
- err := s.validateNextMsgState()
- if err != nil {
- s.mu.Unlock()
- return nil, err
- }
-
- // snapshot
- mch := s.mch
- s.mu.Unlock()
-
- var ok bool
- var msg *Msg
-
- // If something is available right away, let's optimize that case.
- select {
- case msg, ok = <-mch:
- if !ok {
- return nil, s.getNextMsgErr()
- }
- if err := s.processNextMsgDelivered(msg); err != nil {
- return nil, err
- } else {
- return msg, nil
- }
- default:
- }
-
- // If we are here a message was not immediately available, so lets loop
- // with a timeout.
-
- t := globalTimerPool.Get(timeout)
- defer globalTimerPool.Put(t)
-
- select {
- case msg, ok = <-mch:
- if !ok {
- return nil, s.getNextMsgErr()
- }
- if err := s.processNextMsgDelivered(msg); err != nil {
- return nil, err
- }
- case <-t.C:
- return nil, ErrTimeout
- }
-
- return msg, nil
-}
-
-// validateNextMsgState checks whether the subscription is in a valid
-// state to call NextMsg and be delivered another message synchronously.
-// This should be called while holding the lock.
-func (s *Subscription) validateNextMsgState() error {
- if s.connClosed {
- return ErrConnectionClosed
- }
- if s.mch == nil {
- if s.max > 0 && s.delivered >= s.max {
- return ErrMaxMessages
- } else if s.closed {
- return ErrBadSubscription
- }
- }
- if s.mcb != nil {
- return ErrSyncSubRequired
- }
- if s.sc {
- s.sc = false
- return ErrSlowConsumer
- }
-
- return nil
-}
-
-// This is called when the sync channel has been closed.
-// The error returned will be either connection or subscription
-// closed depending on what caused NextMsg() to fail.
-func (s *Subscription) getNextMsgErr() error {
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.connClosed {
- return ErrConnectionClosed
- }
- return ErrBadSubscription
-}
-
-// processNextMsgDelivered takes a message and applies the needed
-// accounting to the stats from the subscription, returning an
-// error in case we have the maximum number of messages have been
-// delivered already. It should not be called while holding the lock.
-func (s *Subscription) processNextMsgDelivered(msg *Msg) error {
- s.mu.Lock()
- nc := s.conn
- max := s.max
-
- // Update some stats.
- s.delivered++
- delivered := s.delivered
- if s.typ == SyncSubscription {
- s.pMsgs--
- s.pBytes -= len(msg.Data)
- }
- s.mu.Unlock()
-
- if max > 0 {
- if delivered > max {
- return ErrMaxMessages
- }
- // Remove subscription if we have reached max.
- if delivered == max {
- nc.mu.Lock()
- nc.removeSub(s)
- nc.mu.Unlock()
- }
- }
-
- return nil
-}
-
-// Queued returns the number of queued messages in the client for this subscription.
-// DEPRECATED: Use Pending()
-func (s *Subscription) QueuedMsgs() (int, error) {
- m, _, err := s.Pending()
- return int(m), err
-}
-
-// Pending returns the number of queued messages and queued bytes in the client for this subscription.
-func (s *Subscription) Pending() (int, int, error) {
- if s == nil {
- return -1, -1, ErrBadSubscription
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.conn == nil || s.closed {
- return -1, -1, ErrBadSubscription
- }
- if s.typ == ChanSubscription {
- return -1, -1, ErrTypeSubscription
- }
- return s.pMsgs, s.pBytes, nil
-}
-
-// MaxPending returns the maximum number of queued messages and queued bytes seen so far.
-func (s *Subscription) MaxPending() (int, int, error) {
- if s == nil {
- return -1, -1, ErrBadSubscription
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.conn == nil || s.closed {
- return -1, -1, ErrBadSubscription
- }
- if s.typ == ChanSubscription {
- return -1, -1, ErrTypeSubscription
- }
- return s.pMsgsMax, s.pBytesMax, nil
-}
-
-// ClearMaxPending resets the maximums seen so far.
-func (s *Subscription) ClearMaxPending() error {
- if s == nil {
- return ErrBadSubscription
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.conn == nil || s.closed {
- return ErrBadSubscription
- }
- if s.typ == ChanSubscription {
- return ErrTypeSubscription
- }
- s.pMsgsMax, s.pBytesMax = 0, 0
- return nil
-}
-
-// Pending Limits
-const (
- DefaultSubPendingMsgsLimit = 65536
- DefaultSubPendingBytesLimit = 65536 * 1024
-)
-
-// PendingLimits returns the current limits for this subscription.
-// If no error is returned, a negative value indicates that the
-// given metric is not limited.
-func (s *Subscription) PendingLimits() (int, int, error) {
- if s == nil {
- return -1, -1, ErrBadSubscription
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.conn == nil || s.closed {
- return -1, -1, ErrBadSubscription
- }
- if s.typ == ChanSubscription {
- return -1, -1, ErrTypeSubscription
- }
- return s.pMsgsLimit, s.pBytesLimit, nil
-}
-
-// SetPendingLimits sets the limits for pending msgs and bytes for this subscription.
-// Zero is not allowed. Any negative value means that the given metric is not limited.
-func (s *Subscription) SetPendingLimits(msgLimit, bytesLimit int) error {
- if s == nil {
- return ErrBadSubscription
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.conn == nil || s.closed {
- return ErrBadSubscription
- }
- if s.typ == ChanSubscription {
- return ErrTypeSubscription
- }
- if msgLimit == 0 || bytesLimit == 0 {
- return ErrInvalidArg
- }
- s.pMsgsLimit, s.pBytesLimit = msgLimit, bytesLimit
- return nil
-}
-
-// Delivered returns the number of delivered messages for this subscription.
-func (s *Subscription) Delivered() (int64, error) {
- if s == nil {
- return -1, ErrBadSubscription
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.conn == nil || s.closed {
- return -1, ErrBadSubscription
- }
- return int64(s.delivered), nil
-}
-
-// Dropped returns the number of known dropped messages for this subscription.
-// This will correspond to messages dropped by violations of PendingLimits. If
-// the server declares the connection a SlowConsumer, this number may not be
-// valid.
-func (s *Subscription) Dropped() (int, error) {
- if s == nil {
- return -1, ErrBadSubscription
- }
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.conn == nil || s.closed {
- return -1, ErrBadSubscription
- }
- return s.dropped, nil
-}
-
-// Respond allows a convenient way to respond to requests in service based subscriptions.
-func (m *Msg) Respond(data []byte) error {
- if m == nil || m.Sub == nil {
- return ErrMsgNotBound
- }
- if m.Reply == "" {
- return ErrMsgNoReply
- }
- m.Sub.mu.Lock()
- nc := m.Sub.conn
- m.Sub.mu.Unlock()
- // No need to check the connection here since the call to publish will do all the checking.
- return nc.Publish(m.Reply, data)
-}
-
-// FIXME: This is a hack
-// removeFlushEntry is needed when we need to discard queued up responses
-// for our pings as part of a flush call. This happens when we have a flush
-// call outstanding and we call close.
-func (nc *Conn) removeFlushEntry(ch chan struct{}) bool {
- nc.mu.Lock()
- defer nc.mu.Unlock()
- if nc.pongs == nil {
- return false
- }
- for i, c := range nc.pongs {
- if c == ch {
- nc.pongs[i] = nil
- return true
- }
- }
- return false
-}
-
-// The lock must be held entering this function.
-func (nc *Conn) sendPing(ch chan struct{}) {
- nc.pongs = append(nc.pongs, ch)
- nc.bw.WriteString(pingProto)
- // Flush in place.
- nc.bw.Flush()
-}
-
-// This will fire periodically and send a client origin
-// ping to the server. Will also check that we have received
-// responses from the server.
-func (nc *Conn) processPingTimer() {
- nc.mu.Lock()
-
- if nc.status != CONNECTED {
- nc.mu.Unlock()
- return
- }
-
- // Check for violation
- nc.pout++
- if nc.pout > nc.Opts.MaxPingsOut {
- nc.mu.Unlock()
- nc.processOpErr(ErrStaleConnection)
- return
- }
-
- nc.sendPing(nil)
- nc.ptmr.Reset(nc.Opts.PingInterval)
- nc.mu.Unlock()
-}
-
-// FlushTimeout allows a Flush operation to have an associated timeout.
-func (nc *Conn) FlushTimeout(timeout time.Duration) (err error) {
- if nc == nil {
- return ErrInvalidConnection
- }
- if timeout <= 0 {
- return ErrBadTimeout
- }
-
- nc.mu.Lock()
- if nc.isClosed() {
- nc.mu.Unlock()
- return ErrConnectionClosed
- }
- t := globalTimerPool.Get(timeout)
- defer globalTimerPool.Put(t)
-
- // Create a buffered channel to prevent chan send to block
- // in processPong() if this code here times out just when
- // PONG was received.
- ch := make(chan struct{}, 1)
- nc.sendPing(ch)
- nc.mu.Unlock()
-
- select {
- case _, ok := <-ch:
- if !ok {
- err = ErrConnectionClosed
- } else {
- close(ch)
- }
- case <-t.C:
- err = ErrTimeout
- }
-
- if err != nil {
- nc.removeFlushEntry(ch)
- }
- return
-}
-
-// Flush will perform a round trip to the server and return when it
-// receives the internal reply.
-func (nc *Conn) Flush() error {
- return nc.FlushTimeout(60 * time.Second)
-}
-
-// Buffered will return the number of bytes buffered to be sent to the server.
-// FIXME(dlc) take into account disconnected state.
-func (nc *Conn) Buffered() (int, error) {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- if nc.isClosed() || nc.bw == nil {
- return -1, ErrConnectionClosed
- }
- return nc.bw.Buffered(), nil
-}
-
-// resendSubscriptions will send our subscription state back to the
-// server. Used in reconnects
-func (nc *Conn) resendSubscriptions() {
- // Since we are going to send protocols to the server, we don't want to
- // be holding the subsMu lock (which is used in processMsg). So copy
- // the subscriptions in a temporary array.
- nc.subsMu.RLock()
- subs := make([]*Subscription, 0, len(nc.subs))
- for _, s := range nc.subs {
- subs = append(subs, s)
- }
- nc.subsMu.RUnlock()
- for _, s := range subs {
- adjustedMax := uint64(0)
- s.mu.Lock()
- if s.max > 0 {
- if s.delivered < s.max {
- adjustedMax = s.max - s.delivered
- }
- // adjustedMax could be 0 here if the number of delivered msgs
- // reached the max, if so unsubscribe.
- if adjustedMax == 0 {
- s.mu.Unlock()
- fmt.Fprintf(nc.bw, unsubProto, s.sid, _EMPTY_)
- continue
- }
- }
- s.mu.Unlock()
-
- fmt.Fprintf(nc.bw, subProto, s.Subject, s.Queue, s.sid)
- if adjustedMax > 0 {
- maxStr := strconv.Itoa(int(adjustedMax))
- fmt.Fprintf(nc.bw, unsubProto, s.sid, maxStr)
- }
- }
-}
-
-// This will clear any pending flush calls and release pending calls.
-// Lock is assumed to be held by the caller.
-func (nc *Conn) clearPendingFlushCalls() {
- // Clear any queued pongs, e.g. pending flush calls.
- for _, ch := range nc.pongs {
- if ch != nil {
- close(ch)
- }
- }
- nc.pongs = nil
-}
-
-// This will clear any pending Request calls.
-// Lock is assumed to be held by the caller.
-func (nc *Conn) clearPendingRequestCalls() {
- if nc.respMap == nil {
- return
- }
- for key, ch := range nc.respMap {
- if ch != nil {
- close(ch)
- delete(nc.respMap, key)
- }
- }
-}
-
-// Low level close call that will do correct cleanup and set
-// desired status. Also controls whether user defined callbacks
-// will be triggered. The lock should not be held entering this
-// function. This function will handle the locking manually.
-func (nc *Conn) close(status Status, doCBs bool, err error) {
- nc.mu.Lock()
- if nc.isClosed() {
- nc.status = status
- nc.mu.Unlock()
- return
- }
- nc.status = CLOSED
-
- // Kick the Go routines so they fall out.
- nc.kickFlusher()
- nc.mu.Unlock()
-
- nc.mu.Lock()
-
- // Clear any queued pongs, e.g. pending flush calls.
- nc.clearPendingFlushCalls()
-
- // Clear any queued and blocking Requests.
- nc.clearPendingRequestCalls()
-
- // Stop ping timer if set.
- nc.stopPingTimer()
- nc.ptmr = nil
-
- // Need to close and set tcp conn to nil if reconnect loop has stopped,
- // otherwise we would incorrectly invoke Disconnect handler (if set)
- // down below.
- if nc.ar && nc.conn != nil {
- nc.conn.Close()
- nc.conn = nil
- } else if nc.conn != nil {
- // Go ahead and make sure we have flushed the outbound
- nc.bw.Flush()
- defer nc.conn.Close()
- }
-
- // Close sync subscriber channels and release any
- // pending NextMsg() calls.
- nc.subsMu.Lock()
- for _, s := range nc.subs {
- s.mu.Lock()
-
- // Release callers on NextMsg for SyncSubscription only
- if s.mch != nil && s.typ == SyncSubscription {
- close(s.mch)
- }
- s.mch = nil
- // Mark as invalid, for signaling to deliverMsgs
- s.closed = true
- // Mark connection closed in subscription
- s.connClosed = true
- // If we have an async subscription, signals it to exit
- if s.typ == AsyncSubscription && s.pCond != nil {
- s.pCond.Signal()
- }
-
- s.mu.Unlock()
- }
- nc.subs = nil
- nc.subsMu.Unlock()
-
- nc.status = status
-
- // Perform appropriate callback if needed for a disconnect.
- if doCBs {
- if nc.conn != nil {
- if nc.Opts.DisconnectedErrCB != nil {
- nc.ach.push(func() { nc.Opts.DisconnectedErrCB(nc, err) })
- } else if nc.Opts.DisconnectedCB != nil {
- nc.ach.push(func() { nc.Opts.DisconnectedCB(nc) })
- }
- }
- if nc.Opts.ClosedCB != nil {
- nc.ach.push(func() { nc.Opts.ClosedCB(nc) })
- }
- nc.ach.close()
- }
- nc.mu.Unlock()
-}
-
-// Close will close the connection to the server. This call will release
-// all blocking calls, such as Flush() and NextMsg()
-func (nc *Conn) Close() {
- if nc != nil {
- nc.close(CLOSED, !nc.Opts.NoCallbacksAfterClientClose, nil)
- }
-}
-
-// IsClosed tests if a Conn has been closed.
-func (nc *Conn) IsClosed() bool {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.isClosed()
-}
-
-// IsReconnecting tests if a Conn is reconnecting.
-func (nc *Conn) IsReconnecting() bool {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.isReconnecting()
-}
-
-// IsConnected tests if a Conn is connected.
-func (nc *Conn) IsConnected() bool {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.isConnected()
-}
-
-// drainConnection will run in a separate Go routine and will
-// flush all publishes and drain all active subscriptions.
-func (nc *Conn) drainConnection() {
- // Snapshot subs list.
- nc.mu.Lock()
- subs := make([]*Subscription, 0, len(nc.subs))
- for _, s := range nc.subs {
- subs = append(subs, s)
- }
- errCB := nc.Opts.AsyncErrorCB
- drainWait := nc.Opts.DrainTimeout
- nc.mu.Unlock()
-
- // for pushing errors with context.
- pushErr := func(err error) {
- nc.mu.Lock()
- nc.err = err
- if errCB != nil {
- nc.ach.push(func() { errCB(nc, nil, err) })
- }
- nc.mu.Unlock()
- }
-
- // Do subs first
- for _, s := range subs {
- if err := s.Drain(); err != nil {
- // We will notify about these but continue.
- pushErr(err)
- }
- }
-
- // Wait for the subscriptions to drop to zero.
- timeout := time.Now().Add(drainWait)
- for time.Now().Before(timeout) {
- if nc.NumSubscriptions() == 0 {
- break
- }
- time.Sleep(10 * time.Millisecond)
- }
-
- // Check if we timed out.
- if nc.NumSubscriptions() != 0 {
- pushErr(ErrDrainTimeout)
- }
-
- // Flip State
- nc.mu.Lock()
- nc.status = DRAINING_PUBS
- nc.mu.Unlock()
-
- // Do publish drain via Flush() call.
- err := nc.Flush()
- if err != nil {
- pushErr(err)
- nc.close(CLOSED, true, nil)
- return
- }
-
- // Move to closed state.
- nc.close(CLOSED, true, nil)
-}
-
-// Drain will put a connection into a drain state. All subscriptions will
-// immediately be put into a drain state. Upon completion, the publishers
-// will be drained and can not publish any additional messages. Upon draining
-// of the publishers, the connection will be closed. Use the ClosedCB()
-// option to know when the connection has moved from draining to closed.
-func (nc *Conn) Drain() error {
- nc.mu.Lock()
- defer nc.mu.Unlock()
-
- if nc.isClosed() {
- return ErrConnectionClosed
- }
- if nc.isConnecting() || nc.isReconnecting() {
- return ErrConnectionReconnecting
- }
- if nc.isDraining() {
- return nil
- }
-
- nc.status = DRAINING_SUBS
- go nc.drainConnection()
- return nil
-}
-
-// IsDraining tests if a Conn is in the draining state.
-func (nc *Conn) IsDraining() bool {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.isDraining()
-}
-
-// caller must lock
-func (nc *Conn) getServers(implicitOnly bool) []string {
- poolSize := len(nc.srvPool)
- var servers = make([]string, 0)
- for i := 0; i < poolSize; i++ {
- if implicitOnly && !nc.srvPool[i].isImplicit {
- continue
- }
- url := nc.srvPool[i].url
- servers = append(servers, fmt.Sprintf("%s://%s", url.Scheme, url.Host))
- }
- return servers
-}
-
-// Servers returns the list of known server urls, including additional
-// servers discovered after a connection has been established. If
-// authentication is enabled, use UserInfo or Token when connecting with
-// these urls.
-func (nc *Conn) Servers() []string {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.getServers(false)
-}
-
-// DiscoveredServers returns only the server urls that have been discovered
-// after a connection has been established. If authentication is enabled,
-// use UserInfo or Token when connecting with these urls.
-func (nc *Conn) DiscoveredServers() []string {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.getServers(true)
-}
-
-// Status returns the current state of the connection.
-func (nc *Conn) Status() Status {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.status
-}
-
-// Test if Conn has been closed Lock is assumed held.
-func (nc *Conn) isClosed() bool {
- return nc.status == CLOSED
-}
-
-// Test if Conn is in the process of connecting
-func (nc *Conn) isConnecting() bool {
- return nc.status == CONNECTING
-}
-
-// Test if Conn is being reconnected.
-func (nc *Conn) isReconnecting() bool {
- return nc.status == RECONNECTING
-}
-
-// Test if Conn is connected or connecting.
-func (nc *Conn) isConnected() bool {
- return nc.status == CONNECTED || nc.isDraining()
-}
-
-// Test if Conn is in the draining state.
-func (nc *Conn) isDraining() bool {
- return nc.status == DRAINING_SUBS || nc.status == DRAINING_PUBS
-}
-
-// Test if Conn is in the draining state for pubs.
-func (nc *Conn) isDrainingPubs() bool {
- return nc.status == DRAINING_PUBS
-}
-
-// Stats will return a race safe copy of the Statistics section for the connection.
-func (nc *Conn) Stats() Statistics {
- // Stats are updated either under connection's mu or with atomic operations
- // for inbound stats in processMsg().
- nc.mu.Lock()
- stats := Statistics{
- InMsgs: atomic.LoadUint64(&nc.InMsgs),
- InBytes: atomic.LoadUint64(&nc.InBytes),
- OutMsgs: nc.OutMsgs,
- OutBytes: nc.OutBytes,
- Reconnects: nc.Reconnects,
- }
- nc.mu.Unlock()
- return stats
-}
-
-// MaxPayload returns the size limit that a message payload can have.
-// This is set by the server configuration and delivered to the client
-// upon connect.
-func (nc *Conn) MaxPayload() int64 {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.info.MaxPayload
-}
-
-// AuthRequired will return if the connected server requires authorization.
-func (nc *Conn) AuthRequired() bool {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.info.AuthRequired
-}
-
-// TLSRequired will return if the connected server requires TLS connections.
-func (nc *Conn) TLSRequired() bool {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- return nc.info.TLSRequired
-}
-
-// Barrier schedules the given function `f` to all registered asynchronous
-// subscriptions.
-// Only the last subscription to see this barrier will invoke the function.
-// If no subscription is registered at the time of this call, `f()` is invoked
-// right away.
-// ErrConnectionClosed is returned if the connection is closed prior to
-// the call.
-func (nc *Conn) Barrier(f func()) error {
- nc.mu.Lock()
- if nc.isClosed() {
- nc.mu.Unlock()
- return ErrConnectionClosed
- }
- nc.subsMu.Lock()
- // Need to figure out how many non chan subscriptions there are
- numSubs := 0
- for _, sub := range nc.subs {
- if sub.typ == AsyncSubscription {
- numSubs++
- }
- }
- if numSubs == 0 {
- nc.subsMu.Unlock()
- nc.mu.Unlock()
- f()
- return nil
- }
- barrier := &barrierInfo{refs: int64(numSubs), f: f}
- for _, sub := range nc.subs {
- sub.mu.Lock()
- if sub.mch == nil {
- msg := &Msg{barrier: barrier}
- // Push onto the async pList
- if sub.pTail != nil {
- sub.pTail.next = msg
- } else {
- sub.pHead = msg
- sub.pCond.Signal()
- }
- sub.pTail = msg
- }
- sub.mu.Unlock()
- }
- nc.subsMu.Unlock()
- nc.mu.Unlock()
- return nil
-}
-
-// GetClientID returns the client ID assigned by the server to which
-// the client is currently connected to. Note that the value may change if
-// the client reconnects.
-// This function returns ErrNoClientIDReturned if the server is of a
-// version prior to 1.2.0.
-func (nc *Conn) GetClientID() (uint64, error) {
- nc.mu.RLock()
- defer nc.mu.RUnlock()
- if nc.isClosed() {
- return 0, ErrConnectionClosed
- }
- if nc.info.CID == 0 {
- return 0, ErrClientIDNotSupported
- }
- return nc.info.CID, nil
-}
-
-// NkeyOptionFromSeed will load an nkey pair from a seed file.
-// It will return the NKey Option and will handle
-// signing of nonce challenges from the server. It will take
-// care to not hold keys in memory and to wipe memory.
-func NkeyOptionFromSeed(seedFile string) (Option, error) {
- kp, err := nkeyPairFromSeedFile(seedFile)
- if err != nil {
- return nil, err
- }
- // Wipe our key on exit.
- defer kp.Wipe()
-
- pub, err := kp.PublicKey()
- if err != nil {
- return nil, err
- }
- if !nkeys.IsValidPublicUserKey(pub) {
- return nil, fmt.Errorf("nats: Not a valid nkey user seed")
- }
- sigCB := func(nonce []byte) ([]byte, error) {
- return sigHandler(nonce, seedFile)
- }
- return Nkey(string(pub), sigCB), nil
-}
-
-// Just wipe slice with 'x', for clearing contents of creds or nkey seed file.
-func wipeSlice(buf []byte) {
- for i := range buf {
- buf[i] = 'x'
- }
-}
-
-func userFromFile(userFile string) (string, error) {
- path, err := expandPath(userFile)
- if err != nil {
- return _EMPTY_, fmt.Errorf("nats: %v", err)
- }
-
- contents, err := ioutil.ReadFile(path)
- if err != nil {
- return _EMPTY_, fmt.Errorf("nats: %v", err)
- }
- defer wipeSlice(contents)
- return jwt.ParseDecoratedJWT(contents)
-}
-
-func homeDir() (string, error) {
- if runtime.GOOS == "windows" {
- homeDrive, homePath := os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH")
- userProfile := os.Getenv("USERPROFILE")
-
- var home string
- if homeDrive == "" || homePath == "" {
- if userProfile == "" {
- return _EMPTY_, errors.New("nats: failed to get home dir, require %HOMEDRIVE% and %HOMEPATH% or %USERPROFILE%")
- }
- home = userProfile
- } else {
- home = filepath.Join(homeDrive, homePath)
- }
-
- return home, nil
- }
-
- home := os.Getenv("HOME")
- if home == "" {
- return _EMPTY_, errors.New("nats: failed to get home dir, require $HOME")
- }
- return home, nil
-}
-
-func expandPath(p string) (string, error) {
- p = os.ExpandEnv(p)
-
- if !strings.HasPrefix(p, "~") {
- return p, nil
- }
-
- home, err := homeDir()
- if err != nil {
- return _EMPTY_, err
- }
-
- return filepath.Join(home, p[1:]), nil
-}
-
-func nkeyPairFromSeedFile(seedFile string) (nkeys.KeyPair, error) {
- contents, err := ioutil.ReadFile(seedFile)
- if err != nil {
- return nil, fmt.Errorf("nats: %v", err)
- }
- defer wipeSlice(contents)
- return jwt.ParseDecoratedNKey(contents)
-}
-
-// Sign authentication challenges from the server.
-// Do not keep private seed in memory.
-func sigHandler(nonce []byte, seedFile string) ([]byte, error) {
- kp, err := nkeyPairFromSeedFile(seedFile)
- if err != nil {
- return nil, err
- }
- // Wipe our key on exit.
- defer kp.Wipe()
-
- sig, _ := kp.Sign(nonce)
- return sig, nil
-}
-
-type timeoutWriter struct {
- timeout time.Duration
- conn net.Conn
- err error
-}
-
-// Write implements the io.Writer interface.
-func (tw *timeoutWriter) Write(p []byte) (int, error) {
- if tw.err != nil {
- return 0, tw.err
- }
-
- var n int
- tw.conn.SetWriteDeadline(time.Now().Add(tw.timeout))
- n, tw.err = tw.conn.Write(p)
- tw.conn.SetWriteDeadline(time.Time{})
- return n, tw.err
-}
diff --git a/vendor/github.com/nats-io/nats.go/netchan.go b/vendor/github.com/nats-io/nats.go/netchan.go
deleted file mode 100644
index fd86d065584..00000000000
--- a/vendor/github.com/nats-io/nats.go/netchan.go
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2013-2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package nats
-
-import (
- "errors"
- "reflect"
-)
-
-// This allows the functionality for network channels by binding send and receive Go chans
-// to subjects and optionally queue groups.
-// Data will be encoded and decoded via the EncodedConn and its associated encoders.
-
-// BindSendChan binds a channel for send operations to NATS.
-func (c *EncodedConn) BindSendChan(subject string, channel interface{}) error {
- chVal := reflect.ValueOf(channel)
- if chVal.Kind() != reflect.Chan {
- return ErrChanArg
- }
- go chPublish(c, chVal, subject)
- return nil
-}
-
-// Publish all values that arrive on the channel until it is closed or we
-// encounter an error.
-func chPublish(c *EncodedConn, chVal reflect.Value, subject string) {
- for {
- val, ok := chVal.Recv()
- if !ok {
- // Channel has most likely been closed.
- return
- }
- if e := c.Publish(subject, val.Interface()); e != nil {
- // Do this under lock.
- c.Conn.mu.Lock()
- defer c.Conn.mu.Unlock()
-
- if c.Conn.Opts.AsyncErrorCB != nil {
- // FIXME(dlc) - Not sure this is the right thing to do.
- // FIXME(ivan) - If the connection is not yet closed, try to schedule the callback
- if c.Conn.isClosed() {
- go c.Conn.Opts.AsyncErrorCB(c.Conn, nil, e)
- } else {
- c.Conn.ach.push(func() { c.Conn.Opts.AsyncErrorCB(c.Conn, nil, e) })
- }
- }
- return
- }
- }
-}
-
-// BindRecvChan binds a channel for receive operations from NATS.
-func (c *EncodedConn) BindRecvChan(subject string, channel interface{}) (*Subscription, error) {
- return c.bindRecvChan(subject, _EMPTY_, channel)
-}
-
-// BindRecvQueueChan binds a channel for queue-based receive operations from NATS.
-func (c *EncodedConn) BindRecvQueueChan(subject, queue string, channel interface{}) (*Subscription, error) {
- return c.bindRecvChan(subject, queue, channel)
-}
-
-// Internal function to bind receive operations for a channel.
-func (c *EncodedConn) bindRecvChan(subject, queue string, channel interface{}) (*Subscription, error) {
- chVal := reflect.ValueOf(channel)
- if chVal.Kind() != reflect.Chan {
- return nil, ErrChanArg
- }
- argType := chVal.Type().Elem()
-
- cb := func(m *Msg) {
- var oPtr reflect.Value
- if argType.Kind() != reflect.Ptr {
- oPtr = reflect.New(argType)
- } else {
- oPtr = reflect.New(argType.Elem())
- }
- if err := c.Enc.Decode(m.Subject, m.Data, oPtr.Interface()); err != nil {
- c.Conn.err = errors.New("nats: Got an error trying to unmarshal: " + err.Error())
- if c.Conn.Opts.AsyncErrorCB != nil {
- c.Conn.ach.push(func() { c.Conn.Opts.AsyncErrorCB(c.Conn, m.Sub, c.Conn.err) })
- }
- return
- }
- if argType.Kind() != reflect.Ptr {
- oPtr = reflect.Indirect(oPtr)
- }
- // This is a bit hacky, but in this instance we may be trying to send to a closed channel.
- // and the user does not know when it is safe to close the channel.
- defer func() {
- // If we have panicked, recover and close the subscription.
- if r := recover(); r != nil {
- m.Sub.Unsubscribe()
- }
- }()
- // Actually do the send to the channel.
- chVal.Send(oPtr)
- }
-
- return c.Conn.subscribe(subject, queue, cb, nil, false)
-}
diff --git a/vendor/github.com/nats-io/nats.go/parser.go b/vendor/github.com/nats-io/nats.go/parser.go
deleted file mode 100644
index a4b3ea0ea75..00000000000
--- a/vendor/github.com/nats-io/nats.go/parser.go
+++ /dev/null
@@ -1,481 +0,0 @@
-// Copyright 2012-2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package nats
-
-import (
- "fmt"
-)
-
-type msgArg struct {
- subject []byte
- reply []byte
- sid int64
- size int
-}
-
-const MAX_CONTROL_LINE_SIZE = 1024
-
-type parseState struct {
- state int
- as int
- drop int
- ma msgArg
- argBuf []byte
- msgBuf []byte
- scratch [MAX_CONTROL_LINE_SIZE]byte
-}
-
-const (
- OP_START = iota
- OP_PLUS
- OP_PLUS_O
- OP_PLUS_OK
- OP_MINUS
- OP_MINUS_E
- OP_MINUS_ER
- OP_MINUS_ERR
- OP_MINUS_ERR_SPC
- MINUS_ERR_ARG
- OP_M
- OP_MS
- OP_MSG
- OP_MSG_SPC
- MSG_ARG
- MSG_PAYLOAD
- MSG_END
- OP_P
- OP_PI
- OP_PIN
- OP_PING
- OP_PO
- OP_PON
- OP_PONG
- OP_I
- OP_IN
- OP_INF
- OP_INFO
- OP_INFO_SPC
- INFO_ARG
-)
-
-// parse is the fast protocol parser engine.
-func (nc *Conn) parse(buf []byte) error {
- var i int
- var b byte
-
- // Move to loop instead of range syntax to allow jumping of i
- for i = 0; i < len(buf); i++ {
- b = buf[i]
-
- switch nc.ps.state {
- case OP_START:
- switch b {
- case 'M', 'm':
- nc.ps.state = OP_M
- case 'P', 'p':
- nc.ps.state = OP_P
- case '+':
- nc.ps.state = OP_PLUS
- case '-':
- nc.ps.state = OP_MINUS
- case 'I', 'i':
- nc.ps.state = OP_I
- default:
- goto parseErr
- }
- case OP_M:
- switch b {
- case 'S', 's':
- nc.ps.state = OP_MS
- default:
- goto parseErr
- }
- case OP_MS:
- switch b {
- case 'G', 'g':
- nc.ps.state = OP_MSG
- default:
- goto parseErr
- }
- case OP_MSG:
- switch b {
- case ' ', '\t':
- nc.ps.state = OP_MSG_SPC
- default:
- goto parseErr
- }
- case OP_MSG_SPC:
- switch b {
- case ' ', '\t':
- continue
- default:
- nc.ps.state = MSG_ARG
- nc.ps.as = i
- }
- case MSG_ARG:
- switch b {
- case '\r':
- nc.ps.drop = 1
- case '\n':
- var arg []byte
- if nc.ps.argBuf != nil {
- arg = nc.ps.argBuf
- } else {
- arg = buf[nc.ps.as : i-nc.ps.drop]
- }
- if err := nc.processMsgArgs(arg); err != nil {
- return err
- }
- nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, MSG_PAYLOAD
-
- // jump ahead with the index. If this overruns
- // what is left we fall out and process split
- // buffer.
- i = nc.ps.as + nc.ps.ma.size - 1
- default:
- if nc.ps.argBuf != nil {
- nc.ps.argBuf = append(nc.ps.argBuf, b)
- }
- }
- case MSG_PAYLOAD:
- if nc.ps.msgBuf != nil {
- if len(nc.ps.msgBuf) >= nc.ps.ma.size {
- nc.processMsg(nc.ps.msgBuf)
- nc.ps.argBuf, nc.ps.msgBuf, nc.ps.state = nil, nil, MSG_END
- } else {
- // copy as much as we can to the buffer and skip ahead.
- toCopy := nc.ps.ma.size - len(nc.ps.msgBuf)
- avail := len(buf) - i
-
- if avail < toCopy {
- toCopy = avail
- }
-
- if toCopy > 0 {
- start := len(nc.ps.msgBuf)
- // This is needed for copy to work.
- nc.ps.msgBuf = nc.ps.msgBuf[:start+toCopy]
- copy(nc.ps.msgBuf[start:], buf[i:i+toCopy])
- // Update our index
- i = (i + toCopy) - 1
- } else {
- nc.ps.msgBuf = append(nc.ps.msgBuf, b)
- }
- }
- } else if i-nc.ps.as >= nc.ps.ma.size {
- nc.processMsg(buf[nc.ps.as:i])
- nc.ps.argBuf, nc.ps.msgBuf, nc.ps.state = nil, nil, MSG_END
- }
- case MSG_END:
- switch b {
- case '\n':
- nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, OP_START
- default:
- continue
- }
- case OP_PLUS:
- switch b {
- case 'O', 'o':
- nc.ps.state = OP_PLUS_O
- default:
- goto parseErr
- }
- case OP_PLUS_O:
- switch b {
- case 'K', 'k':
- nc.ps.state = OP_PLUS_OK
- default:
- goto parseErr
- }
- case OP_PLUS_OK:
- switch b {
- case '\n':
- nc.processOK()
- nc.ps.drop, nc.ps.state = 0, OP_START
- }
- case OP_MINUS:
- switch b {
- case 'E', 'e':
- nc.ps.state = OP_MINUS_E
- default:
- goto parseErr
- }
- case OP_MINUS_E:
- switch b {
- case 'R', 'r':
- nc.ps.state = OP_MINUS_ER
- default:
- goto parseErr
- }
- case OP_MINUS_ER:
- switch b {
- case 'R', 'r':
- nc.ps.state = OP_MINUS_ERR
- default:
- goto parseErr
- }
- case OP_MINUS_ERR:
- switch b {
- case ' ', '\t':
- nc.ps.state = OP_MINUS_ERR_SPC
- default:
- goto parseErr
- }
- case OP_MINUS_ERR_SPC:
- switch b {
- case ' ', '\t':
- continue
- default:
- nc.ps.state = MINUS_ERR_ARG
- nc.ps.as = i
- }
- case MINUS_ERR_ARG:
- switch b {
- case '\r':
- nc.ps.drop = 1
- case '\n':
- var arg []byte
- if nc.ps.argBuf != nil {
- arg = nc.ps.argBuf
- nc.ps.argBuf = nil
- } else {
- arg = buf[nc.ps.as : i-nc.ps.drop]
- }
- nc.processErr(string(arg))
- nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, OP_START
- default:
- if nc.ps.argBuf != nil {
- nc.ps.argBuf = append(nc.ps.argBuf, b)
- }
- }
- case OP_P:
- switch b {
- case 'I', 'i':
- nc.ps.state = OP_PI
- case 'O', 'o':
- nc.ps.state = OP_PO
- default:
- goto parseErr
- }
- case OP_PO:
- switch b {
- case 'N', 'n':
- nc.ps.state = OP_PON
- default:
- goto parseErr
- }
- case OP_PON:
- switch b {
- case 'G', 'g':
- nc.ps.state = OP_PONG
- default:
- goto parseErr
- }
- case OP_PONG:
- switch b {
- case '\n':
- nc.processPong()
- nc.ps.drop, nc.ps.state = 0, OP_START
- }
- case OP_PI:
- switch b {
- case 'N', 'n':
- nc.ps.state = OP_PIN
- default:
- goto parseErr
- }
- case OP_PIN:
- switch b {
- case 'G', 'g':
- nc.ps.state = OP_PING
- default:
- goto parseErr
- }
- case OP_PING:
- switch b {
- case '\n':
- nc.processPing()
- nc.ps.drop, nc.ps.state = 0, OP_START
- }
- case OP_I:
- switch b {
- case 'N', 'n':
- nc.ps.state = OP_IN
- default:
- goto parseErr
- }
- case OP_IN:
- switch b {
- case 'F', 'f':
- nc.ps.state = OP_INF
- default:
- goto parseErr
- }
- case OP_INF:
- switch b {
- case 'O', 'o':
- nc.ps.state = OP_INFO
- default:
- goto parseErr
- }
- case OP_INFO:
- switch b {
- case ' ', '\t':
- nc.ps.state = OP_INFO_SPC
- default:
- goto parseErr
- }
- case OP_INFO_SPC:
- switch b {
- case ' ', '\t':
- continue
- default:
- nc.ps.state = INFO_ARG
- nc.ps.as = i
- }
- case INFO_ARG:
- switch b {
- case '\r':
- nc.ps.drop = 1
- case '\n':
- var arg []byte
- if nc.ps.argBuf != nil {
- arg = nc.ps.argBuf
- nc.ps.argBuf = nil
- } else {
- arg = buf[nc.ps.as : i-nc.ps.drop]
- }
- nc.processAsyncInfo(arg)
- nc.ps.drop, nc.ps.as, nc.ps.state = 0, i+1, OP_START
- default:
- if nc.ps.argBuf != nil {
- nc.ps.argBuf = append(nc.ps.argBuf, b)
- }
- }
- default:
- goto parseErr
- }
- }
- // Check for split buffer scenarios
- if (nc.ps.state == MSG_ARG || nc.ps.state == MINUS_ERR_ARG || nc.ps.state == INFO_ARG) && nc.ps.argBuf == nil {
- nc.ps.argBuf = nc.ps.scratch[:0]
- nc.ps.argBuf = append(nc.ps.argBuf, buf[nc.ps.as:i-nc.ps.drop]...)
- // FIXME, check max len
- }
- // Check for split msg
- if nc.ps.state == MSG_PAYLOAD && nc.ps.msgBuf == nil {
- // We need to clone the msgArg if it is still referencing the
- // read buffer and we are not able to process the msg.
- if nc.ps.argBuf == nil {
- nc.cloneMsgArg()
- }
-
- // If we will overflow the scratch buffer, just create a
- // new buffer to hold the split message.
- if nc.ps.ma.size > cap(nc.ps.scratch)-len(nc.ps.argBuf) {
- lrem := len(buf[nc.ps.as:])
-
- nc.ps.msgBuf = make([]byte, lrem, nc.ps.ma.size)
- copy(nc.ps.msgBuf, buf[nc.ps.as:])
- } else {
- nc.ps.msgBuf = nc.ps.scratch[len(nc.ps.argBuf):len(nc.ps.argBuf)]
- nc.ps.msgBuf = append(nc.ps.msgBuf, (buf[nc.ps.as:])...)
- }
- }
-
- return nil
-
-parseErr:
- return fmt.Errorf("nats: Parse Error [%d]: '%s'", nc.ps.state, buf[i:])
-}
-
-// cloneMsgArg is used when the split buffer scenario has the pubArg in the existing read buffer, but
-// we need to hold onto it into the next read.
-func (nc *Conn) cloneMsgArg() {
- nc.ps.argBuf = nc.ps.scratch[:0]
- nc.ps.argBuf = append(nc.ps.argBuf, nc.ps.ma.subject...)
- nc.ps.argBuf = append(nc.ps.argBuf, nc.ps.ma.reply...)
- nc.ps.ma.subject = nc.ps.argBuf[:len(nc.ps.ma.subject)]
- if nc.ps.ma.reply != nil {
- nc.ps.ma.reply = nc.ps.argBuf[len(nc.ps.ma.subject):]
- }
-}
-
-const argsLenMax = 4
-
-func (nc *Conn) processMsgArgs(arg []byte) error {
- // Unroll splitArgs to avoid runtime/heap issues
- a := [argsLenMax][]byte{}
- args := a[:0]
- start := -1
- for i, b := range arg {
- switch b {
- case ' ', '\t', '\r', '\n':
- if start >= 0 {
- args = append(args, arg[start:i])
- start = -1
- }
- default:
- if start < 0 {
- start = i
- }
- }
- }
- if start >= 0 {
- args = append(args, arg[start:])
- }
-
- switch len(args) {
- case 3:
- nc.ps.ma.subject = args[0]
- nc.ps.ma.sid = parseInt64(args[1])
- nc.ps.ma.reply = nil
- nc.ps.ma.size = int(parseInt64(args[2]))
- case 4:
- nc.ps.ma.subject = args[0]
- nc.ps.ma.sid = parseInt64(args[1])
- nc.ps.ma.reply = args[2]
- nc.ps.ma.size = int(parseInt64(args[3]))
- default:
- return fmt.Errorf("nats: processMsgArgs Parse Error: '%s'", arg)
- }
- if nc.ps.ma.sid < 0 {
- return fmt.Errorf("nats: processMsgArgs Bad or Missing Sid: '%s'", arg)
- }
- if nc.ps.ma.size < 0 {
- return fmt.Errorf("nats: processMsgArgs Bad or Missing Size: '%s'", arg)
- }
- return nil
-}
-
-// Ascii numbers 0-9
-const (
- ascii_0 = 48
- ascii_9 = 57
-)
-
-// parseInt64 expects decimal positive numbers. We
-// return -1 to signal error
-func parseInt64(d []byte) (n int64) {
- if len(d) == 0 {
- return -1
- }
- for _, dec := range d {
- if dec < ascii_0 || dec > ascii_9 {
- return -1
- }
- n = n*10 + (int64(dec) - ascii_0)
- }
- return n
-}
diff --git a/vendor/github.com/nats-io/nats.go/timer.go b/vendor/github.com/nats-io/nats.go/timer.go
deleted file mode 100644
index 1216762d422..00000000000
--- a/vendor/github.com/nats-io/nats.go/timer.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2017-2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package nats
-
-import (
- "sync"
- "time"
-)
-
-// global pool of *time.Timer's. can be used by multiple goroutines concurrently.
-var globalTimerPool timerPool
-
-// timerPool provides GC-able pooling of *time.Timer's.
-// can be used by multiple goroutines concurrently.
-type timerPool struct {
- p sync.Pool
-}
-
-// Get returns a timer that completes after the given duration.
-func (tp *timerPool) Get(d time.Duration) *time.Timer {
- if t, _ := tp.p.Get().(*time.Timer); t != nil {
- t.Reset(d)
- return t
- }
-
- return time.NewTimer(d)
-}
-
-// Put pools the given timer.
-//
-// There is no need to call t.Stop() before calling Put.
-//
-// Put will try to stop the timer before pooling. If the
-// given timer already expired, Put will read the unreceived
-// value if there is one.
-func (tp *timerPool) Put(t *time.Timer) {
- if !t.Stop() {
- select {
- case <-t.C:
- default:
- }
- }
-
- tp.p.Put(t)
-}
diff --git a/vendor/github.com/nats-io/nats.go/util/tls.go b/vendor/github.com/nats-io/nats.go/util/tls.go
deleted file mode 100644
index 53ff9aa2b48..00000000000
--- a/vendor/github.com/nats-io/nats.go/util/tls.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2017-2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build go1.8
-
-package util
-
-import "crypto/tls"
-
-// CloneTLSConfig returns a copy of c.
-func CloneTLSConfig(c *tls.Config) *tls.Config {
- if c == nil {
- return &tls.Config{}
- }
-
- return c.Clone()
-}
diff --git a/vendor/github.com/nats-io/nats.go/util/tls_go17.go b/vendor/github.com/nats-io/nats.go/util/tls_go17.go
deleted file mode 100644
index fd646d31b95..00000000000
--- a/vendor/github.com/nats-io/nats.go/util/tls_go17.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016-2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build go1.7,!go1.8
-
-package util
-
-import (
- "crypto/tls"
-)
-
-// CloneTLSConfig returns a copy of c. Only the exported fields are copied.
-// This is temporary, until this is provided by the language.
-// https://go-review.googlesource.com/#/c/28075/
-func CloneTLSConfig(c *tls.Config) *tls.Config {
- return &tls.Config{
- Rand: c.Rand,
- Time: c.Time,
- Certificates: c.Certificates,
- NameToCertificate: c.NameToCertificate,
- GetCertificate: c.GetCertificate,
- RootCAs: c.RootCAs,
- NextProtos: c.NextProtos,
- ServerName: c.ServerName,
- ClientAuth: c.ClientAuth,
- ClientCAs: c.ClientCAs,
- InsecureSkipVerify: c.InsecureSkipVerify,
- CipherSuites: c.CipherSuites,
- PreferServerCipherSuites: c.PreferServerCipherSuites,
- SessionTicketsDisabled: c.SessionTicketsDisabled,
- SessionTicketKey: c.SessionTicketKey,
- ClientSessionCache: c.ClientSessionCache,
- MinVersion: c.MinVersion,
- MaxVersion: c.MaxVersion,
- CurvePreferences: c.CurvePreferences,
- DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
- Renegotiation: c.Renegotiation,
- }
-}
diff --git a/vendor/github.com/nats-io/nkeys/.gitignore b/vendor/github.com/nats-io/nkeys/.gitignore
deleted file mode 100644
index 9dca5eb4b3c..00000000000
--- a/vendor/github.com/nats-io/nkeys/.gitignore
+++ /dev/null
@@ -1,15 +0,0 @@
-# Binaries for programs and plugins
-*.exe
-*.dll
-*.so
-*.dylib
-build/
-
-# Test binary, build with `go test -c`
-*.test
-
-# Output of the go coverage tool, specifically when used with LiteIDE
-*.out
-
-# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
-.glide/
diff --git a/vendor/github.com/nats-io/nkeys/.goreleaser.yml b/vendor/github.com/nats-io/nkeys/.goreleaser.yml
deleted file mode 100644
index 6df08becf4a..00000000000
--- a/vendor/github.com/nats-io/nkeys/.goreleaser.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-project_name: nkeys
-release:
- github:
- owner: nats-io
- name: nkeys
- name_template: '{{.Tag}}'
- draft: true
-builds:
- - main: ./nk/main.go
- ldflags: "-X main.Version={{.Tag}}_{{.Commit}}"
- binary: nk
- goos:
- - linux
- - darwin
- goarch:
- - amd64
-
-
-dist: build
-
-archive:
- wrap_in_directory: true
- name_template: '{{ .ProjectName }}-v{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm
- }}v{{ .Arm }}{{ end }}'
- format: zip
-
-checksum:
- name_template: '{{ .ProjectName }}-v{{ .Version }}-checksums.txt'
-
-snapshot:
- name_template: 'dev'
-
-nfpm:
- formats:
- - deb
- bindir: /usr/local/bin
- description: NKeys utility cli program
- vendor: nats-io
diff --git a/vendor/github.com/nats-io/nkeys/.travis.yml b/vendor/github.com/nats-io/nkeys/.travis.yml
deleted file mode 100644
index 7df27cbe35d..00000000000
--- a/vendor/github.com/nats-io/nkeys/.travis.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-language: go
-sudo: false
-go:
-- 1.12.x
-- 1.11.x
-
-install:
-- go get -t ./...
-- go get github.com/mattn/goveralls
-- go get -u honnef.co/go/tools/cmd/staticcheck
-- go get -u github.com/client9/misspell/cmd/misspell
-
-before_script:
-- $(exit $(go fmt ./... | wc -l))
-- go vet ./...
-- misspell -error -locale US .
-- staticcheck ./...
-
-script:
-- go test -v
-- go test -v --race
-- go test -v -covermode=count -coverprofile=coverage.out
-- $HOME/gopath/bin/goveralls -coverprofile coverage.out -service travis-ci
-
-#deploy:
-#- provider: script
-# skip_cleanup: true
-# script: curl -sL http://git.io/goreleaser | bash
-# on:
-# tags: true
-# condition: $TRAVIS_OS_NAME = linux
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/nkeys/GOVERNANCE.md b/vendor/github.com/nats-io/nkeys/GOVERNANCE.md
deleted file mode 100644
index 744d3bc2b55..00000000000
--- a/vendor/github.com/nats-io/nkeys/GOVERNANCE.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# NATS NKEYS Governance
-
-NATS NKEYS is part of the NATS project and is subject to the [NATS Governance](https://github.com/nats-io/nats-general/blob/master/GOVERNANCE.md).
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/nkeys/LICENSE b/vendor/github.com/nats-io/nkeys/LICENSE
deleted file mode 100644
index 261eeb9e9f8..00000000000
--- a/vendor/github.com/nats-io/nkeys/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/nats-io/nkeys/MAINTAINERS.md b/vendor/github.com/nats-io/nkeys/MAINTAINERS.md
deleted file mode 100644
index 6d0ed3e31f9..00000000000
--- a/vendor/github.com/nats-io/nkeys/MAINTAINERS.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Maintainers
-
-Maintainership is on a per project basis.
-
-### Core-maintainers
- - Derek Collison [@derekcollison](https://github.com/derekcollison)
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/nkeys/README.md b/vendor/github.com/nats-io/nkeys/README.md
deleted file mode 100644
index 8b787cc3b59..00000000000
--- a/vendor/github.com/nats-io/nkeys/README.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# NKEYS
-
-[![License Apache 2](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
-[![ReportCard](http://goreportcard.com/badge/nats-io/nkeys)](http://goreportcard.com/report/nats-io/nkeys)
-[![Build Status](https://travis-ci.org/nats-io/nkeys.svg?branch=master)](http://travis-ci.org/nats-io/nkeys)
-[![GoDoc](http://godoc.org/github.com/nats-io/nkeys?status.svg)](http://godoc.org/github.com/nats-io/nkeys)
-[![Coverage Status](https://coveralls.io/repos/github/nats-io/nkeys/badge.svg?branch=master&service=github)](https://coveralls.io/github/nats-io/nkeys?branch=master)
-[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fnats-io%2Fnkeys.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fnats-io%2Fnkeys?ref=badge_shield)
-
-A public-key signature system based on [Ed25519](https://ed25519.cr.yp.to/) for the NATS ecosystem.
-
-## About
-
-The NATS ecosystem will be moving to [Ed25519](https://ed25519.cr.yp.to/) keys for identity, authentication and authorization for entities such as Accounts, Users, Servers and Clusters.
-
-Ed25519 is fast and resistant to side channel attacks. Generation of a seed key is all that is needed to be stored and kept safe, as the seed can generate both the public and private keys.
-
-The NATS system will utilize Ed25519 keys, meaning that NATS systems will never store or even have access to any private keys. Authentication will utilize a random challenge response mechanism.
-
-Dealing with 32 byte and 64 byte raw keys can be challenging. NKEYS is designed to formulate keys in a much friendlier fashion and references work done in cryptocurrencies, specifically [Stellar](https://www.stellar.org/). Bitcoin and others used a form of Base58 (or Base58Check) to encode raw keys. Stellar utilized a more traditional Base32 with a CRC16 and a version or prefix byte. NKEYS utilizes a similar format where the prefix will be 1 byte for public and private keys and will be 2 bytes for seeds. The base32 encoding of these prefixes will yield friendly human readable prefixes, e.g. '**N**' = server, '**C**' = cluster, '**O**' = operator, '**A**' = account, and '**U**' = user. '**P**' is used for private keys. For seeds, the first encoded prefix is '**S**', and the second character will be the type for the public key, e.g. "**SU**" is a seed for a user key pair, "**SA**" is a seed for an account key pair.
-
-## Installation
-
-Use the `go` command:
-
- $ go get github.com/nats-io/nkeys
-
-## nk - Command Line Utility
-
-Located under the nk [directory](https://github.com/nats-io/nkeys/tree/master/nk).
-
-## Basic API Usage
-```go
-
-// Create a new User KeyPair
-user, _ := nkeys.CreateUser()
-
-// Sign some data with a full key pair user.
-data := []byte("Hello World")
-sig, _ := user.Sign(data)
-
-// Verify the signature.
-err = user.Verify(data, sig)
-
-// Access the seed, the only thing that needs to be stored and kept safe.
-// seed = "SUAKYRHVIOREXV7EUZTBHUHL7NUMHPMAS7QMDU3GTIUWEI5LDNOXD43IZY"
-seed, _ := user.Seed()
-
-// Access the public key which can be shared.
-// publicKey = "UD466L6EBCM3YY5HEGHJANNTN4LSKTSUXTH7RILHCKEQMQHTBNLHJJXT"
-publicKey, _ := user.PublicKey()
-
-// Create a full User who can sign and verify from a private seed.
-user, _ = nkeys.FromSeed(seed)
-
-// Create a User who can only verify signatures via a public key.
-user, _ = nkeys.FromPublicKey(publicKey)
-
-// Create a User KeyPair with our own random data.
-var rawSeed [32]byte
-_, err := io.ReadFull(rand.Reader, rawSeed[:]) // Or some other random source.
-user2, _ := nkeys.FromRawSeed(PrefixByteUser, rawSeed)
-
-```
-
-## License
-
-Unless otherwise noted, the NATS source files are distributed
-under the Apache Version 2.0 license found in the LICENSE file.
-
-
-[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fnats-io%2Fnkeys.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fnats-io%2Fnkeys?ref=badge_large)
diff --git a/vendor/github.com/nats-io/nkeys/TODO.md b/vendor/github.com/nats-io/nkeys/TODO.md
deleted file mode 100644
index 2649c9e59b9..00000000000
--- a/vendor/github.com/nats-io/nkeys/TODO.md
+++ /dev/null
@@ -1,5 +0,0 @@
-
-# General
-
-- [ ] Child key derivation
-- [ ] Hardware support, e.g. YubiHSM
diff --git a/vendor/github.com/nats-io/nkeys/crc16.go b/vendor/github.com/nats-io/nkeys/crc16.go
deleted file mode 100644
index c3356cf93ea..00000000000
--- a/vendor/github.com/nats-io/nkeys/crc16.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package nkeys
-
-import (
- "errors"
-)
-
-// An implementation of crc16 according to CCITT standards for XMODEM.
-
-// ErrInvalidChecksum indicates a failed verification.
-var ErrInvalidChecksum = errors.New("nkeys: invalid checksum")
-
-var crc16tab = [256]uint16{
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
- 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
- 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
- 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
- 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
- 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
- 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
- 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
- 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
- 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
- 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
- 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
- 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
- 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
- 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
- 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
- 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
- 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
- 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
- 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
- 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
- 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
- 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
-}
-
-// crc16 returns the 2-byte crc for the data provided.
-func crc16(data []byte) uint16 {
- var crc uint16
- for _, b := range data {
- crc = ((crc << 8) & 0xffff) ^ crc16tab[((crc>>8)^uint16(b))&0x00FF]
- }
- return crc
-}
-
-// validate will check the calculated crc16 checksum for data against the expected.
-func validate(data []byte, expected uint16) error {
- if crc16(data) != expected {
- return ErrInvalidChecksum
- }
- return nil
-}
diff --git a/vendor/github.com/nats-io/nkeys/go.mod b/vendor/github.com/nats-io/nkeys/go.mod
deleted file mode 100644
index 34cad74872c..00000000000
--- a/vendor/github.com/nats-io/nkeys/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/nats-io/nkeys
-
-require golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
diff --git a/vendor/github.com/nats-io/nkeys/go.sum b/vendor/github.com/nats-io/nkeys/go.sum
deleted file mode 100644
index b75b87f0559..00000000000
--- a/vendor/github.com/nats-io/nkeys/go.sum
+++ /dev/null
@@ -1,7 +0,0 @@
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/vendor/github.com/nats-io/nkeys/keypair.go b/vendor/github.com/nats-io/nkeys/keypair.go
deleted file mode 100644
index acd86743d6c..00000000000
--- a/vendor/github.com/nats-io/nkeys/keypair.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package nkeys
-
-import (
- "bytes"
- "crypto/rand"
- "io"
-
- "golang.org/x/crypto/ed25519"
-)
-
-// kp is the internal struct for a kepypair using seed.
-type kp struct {
- seed []byte
-}
-
-// CreatePair will create a KeyPair based on the rand entropy and a type/prefix byte. rand can be nil.
-func CreatePair(prefix PrefixByte) (KeyPair, error) {
- var rawSeed [32]byte
-
- _, err := io.ReadFull(rand.Reader, rawSeed[:])
- if err != nil {
- return nil, err
- }
-
- seed, err := EncodeSeed(prefix, rawSeed[:])
- if err != nil {
- return nil, err
- }
- return &kp{seed}, nil
-}
-
-// rawSeed will return the raw, decoded 64 byte seed.
-func (pair *kp) rawSeed() ([]byte, error) {
- _, raw, err := DecodeSeed(pair.seed)
- return raw, err
-}
-
-// keys will return a 32 byte public key and a 64 byte private key utilizing the seed.
-func (pair *kp) keys() (ed25519.PublicKey, ed25519.PrivateKey, error) {
- raw, err := pair.rawSeed()
- if err != nil {
- return nil, nil, err
- }
- return ed25519.GenerateKey(bytes.NewReader(raw))
-}
-
-// Wipe will randomize the contents of the seed key
-func (pair *kp) Wipe() {
- io.ReadFull(rand.Reader, pair.seed)
- pair.seed = nil
-}
-
-// Seed will return the encoded seed.
-func (pair *kp) Seed() ([]byte, error) {
- return pair.seed, nil
-}
-
-// PublicKey will return the encoded public key associated with the KeyPair.
-// All KeyPairs have a public key.
-func (pair *kp) PublicKey() (string, error) {
- public, raw, err := DecodeSeed(pair.seed)
- if err != nil {
- return "", err
- }
- pub, _, err := ed25519.GenerateKey(bytes.NewReader(raw))
- if err != nil {
- return "", err
- }
- pk, err := Encode(public, pub)
- if err != nil {
- return "", err
- }
- return string(pk), nil
-}
-
-// PrivateKey will return the encoded private key for KeyPair.
-func (pair *kp) PrivateKey() ([]byte, error) {
- _, priv, err := pair.keys()
- if err != nil {
- return nil, err
- }
- return Encode(PrefixBytePrivate, priv)
-}
-
-// Sign will sign the input with KeyPair's private key.
-func (pair *kp) Sign(input []byte) ([]byte, error) {
- _, priv, err := pair.keys()
- if err != nil {
- return nil, err
- }
- return ed25519.Sign(priv, input), nil
-}
-
-// Verify will verify the input against a signature utilizing the public key.
-func (pair *kp) Verify(input []byte, sig []byte) error {
- pub, _, err := pair.keys()
- if err != nil {
- return err
- }
- if !ed25519.Verify(pub, input, sig) {
- return ErrInvalidSignature
- }
- return nil
-}
diff --git a/vendor/github.com/nats-io/nkeys/main.go b/vendor/github.com/nats-io/nkeys/main.go
deleted file mode 100644
index 2ea3f904535..00000000000
--- a/vendor/github.com/nats-io/nkeys/main.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2018-2019 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package nkeys is an Ed25519 based public-key signature system that simplifies keys and seeds
-// and performs signing and verification.
-package nkeys
-
-import (
- "errors"
-)
-
-// Version is our current version
-const Version = "0.1.3"
-
-// Errors
-var (
- ErrInvalidPrefixByte = errors.New("nkeys: invalid prefix byte")
- ErrInvalidKey = errors.New("nkeys: invalid key")
- ErrInvalidPublicKey = errors.New("nkeys: invalid public key")
- ErrInvalidSeedLen = errors.New("nkeys: invalid seed length")
- ErrInvalidSeed = errors.New("nkeys: invalid seed")
- ErrInvalidEncoding = errors.New("nkeys: invalid encoded key")
- ErrInvalidSignature = errors.New("nkeys: signature verification failed")
- ErrCannotSign = errors.New("nkeys: can not sign, no private key available")
- ErrPublicKeyOnly = errors.New("nkeys: no seed or private key available")
- ErrIncompatibleKey = errors.New("nkeys: incompatible key")
-)
-
-// KeyPair provides the central interface to nkeys.
-type KeyPair interface {
- Seed() ([]byte, error)
- PublicKey() (string, error)
- PrivateKey() ([]byte, error)
- Sign(input []byte) ([]byte, error)
- Verify(input []byte, sig []byte) error
- Wipe()
-}
-
-// CreateUser will create a User typed KeyPair.
-func CreateUser() (KeyPair, error) {
- return CreatePair(PrefixByteUser)
-}
-
-// CreateAccount will create an Account typed KeyPair.
-func CreateAccount() (KeyPair, error) {
- return CreatePair(PrefixByteAccount)
-}
-
-// CreateServer will create a Server typed KeyPair.
-func CreateServer() (KeyPair, error) {
- return CreatePair(PrefixByteServer)
-}
-
-// CreateCluster will create a Cluster typed KeyPair.
-func CreateCluster() (KeyPair, error) {
- return CreatePair(PrefixByteCluster)
-}
-
-// CreateOperator will create an Operator typed KeyPair.
-func CreateOperator() (KeyPair, error) {
- return CreatePair(PrefixByteOperator)
-}
-
-// FromPublicKey will create a KeyPair capable of verifying signatures.
-func FromPublicKey(public string) (KeyPair, error) {
- raw, err := decode([]byte(public))
- if err != nil {
- return nil, err
- }
- pre := PrefixByte(raw[0])
- if err := checkValidPublicPrefixByte(pre); err != nil {
- return nil, ErrInvalidPublicKey
- }
- return &pub{pre, raw[1:]}, nil
-}
-
-// FromSeed will create a KeyPair capable of signing and verifying signatures.
-func FromSeed(seed []byte) (KeyPair, error) {
- _, _, err := DecodeSeed(seed)
- if err != nil {
- return nil, err
- }
- copy := append([]byte{}, seed...)
- return &kp{copy}, nil
-}
-
-// FromRawSeed will create a KeyPair from the raw 32 byte seed for a given type.
-func FromRawSeed(prefix PrefixByte, rawSeed []byte) (KeyPair, error) {
- seed, err := EncodeSeed(prefix, rawSeed)
- if err != nil {
- return nil, err
- }
- return &kp{seed}, nil
-}
diff --git a/vendor/github.com/nats-io/nkeys/public.go b/vendor/github.com/nats-io/nkeys/public.go
deleted file mode 100644
index cb7927a6789..00000000000
--- a/vendor/github.com/nats-io/nkeys/public.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package nkeys
-
-import (
- "crypto/rand"
- "io"
-
- "golang.org/x/crypto/ed25519"
-)
-
-// A KeyPair from a public key capable of verifying only.
-type pub struct {
- pre PrefixByte
- pub ed25519.PublicKey
-}
-
-// PublicKey will return the encoded public key associated with the KeyPair.
-// All KeyPairs have a public key.
-func (p *pub) PublicKey() (string, error) {
- pk, err := Encode(p.pre, p.pub)
- if err != nil {
- return "", err
- }
- return string(pk), nil
-}
-
-// Seed will return an error since this is not available for public key only KeyPairs.
-func (p *pub) Seed() ([]byte, error) {
- return nil, ErrPublicKeyOnly
-}
-
-// PrivateKey will return an error since this is not available for public key only KeyPairs.
-func (p *pub) PrivateKey() ([]byte, error) {
- return nil, ErrPublicKeyOnly
-}
-
-// Sign will return an error since this is not available for public key only KeyPairs.
-func (p *pub) Sign(input []byte) ([]byte, error) {
- return nil, ErrCannotSign
-}
-
-// Verify will verify the input against a signature utilizing the public key.
-func (p *pub) Verify(input []byte, sig []byte) error {
- if !ed25519.Verify(p.pub, input, sig) {
- return ErrInvalidSignature
- }
- return nil
-}
-
-// Wipe will randomize the public key and erase the pre byte.
-func (p *pub) Wipe() {
- p.pre = '0'
- io.ReadFull(rand.Reader, p.pub)
-}
diff --git a/vendor/github.com/nats-io/nkeys/strkey.go b/vendor/github.com/nats-io/nkeys/strkey.go
deleted file mode 100644
index 324ea638f9d..00000000000
--- a/vendor/github.com/nats-io/nkeys/strkey.go
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright 2018 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package nkeys
-
-import (
- "bytes"
- "encoding/base32"
- "encoding/binary"
- "golang.org/x/crypto/ed25519"
-)
-
-// PrefixByte is a lead byte representing the type.
-type PrefixByte byte
-
-const (
- // PrefixByteSeed is the version byte used for encoded NATS Seeds
- PrefixByteSeed PrefixByte = 18 << 3 // Base32-encodes to 'S...'
-
- // PrefixBytePrivate is the version byte used for encoded NATS Private keys
- PrefixBytePrivate PrefixByte = 15 << 3 // Base32-encodes to 'P...'
-
- // PrefixByteServer is the version byte used for encoded NATS Servers
- PrefixByteServer PrefixByte = 13 << 3 // Base32-encodes to 'N...'
-
- // PrefixByteCluster is the version byte used for encoded NATS Clusters
- PrefixByteCluster PrefixByte = 2 << 3 // Base32-encodes to 'C...'
-
- // PrefixByteOperator is the version byte used for encoded NATS Operators
- PrefixByteOperator PrefixByte = 14 << 3 // Base32-encodes to 'O...'
-
- // PrefixByteAccount is the version byte used for encoded NATS Accounts
- PrefixByteAccount PrefixByte = 0 // Base32-encodes to 'A...'
-
- // PrefixByteUser is the version byte used for encoded NATS Users
- PrefixByteUser PrefixByte = 20 << 3 // Base32-encodes to 'U...'
-
- // PrefixByteUnknown is for unknown prefixes.
- PrefixByteUnknown PrefixByte = 23 << 3 // Base32-encodes to 'X...'
-)
-
-// Set our encoding to not include padding '=='
-var b32Enc = base32.StdEncoding.WithPadding(base32.NoPadding)
-
-// Encode will encode a raw key or seed with the prefix and crc16 and then base32 encoded.
-func Encode(prefix PrefixByte, src []byte) ([]byte, error) {
- if err := checkValidPrefixByte(prefix); err != nil {
- return nil, err
- }
-
- var raw bytes.Buffer
-
- // write prefix byte
- if err := raw.WriteByte(byte(prefix)); err != nil {
- return nil, err
- }
-
- // write payload
- if _, err := raw.Write(src); err != nil {
- return nil, err
- }
-
- // Calculate and write crc16 checksum
- err := binary.Write(&raw, binary.LittleEndian, crc16(raw.Bytes()))
- if err != nil {
- return nil, err
- }
-
- data := raw.Bytes()
- buf := make([]byte, b32Enc.EncodedLen(len(data)))
- b32Enc.Encode(buf, data)
- return buf[:], nil
-}
-
-// EncodeSeed will encode a raw key with the prefix and then seed prefix and crc16 and then base32 encoded.
-func EncodeSeed(public PrefixByte, src []byte) ([]byte, error) {
- if err := checkValidPublicPrefixByte(public); err != nil {
- return nil, err
- }
-
- if len(src) != ed25519.SeedSize {
- return nil, ErrInvalidSeedLen
- }
-
- // In order to make this human printable for both bytes, we need to do a little
- // bit manipulation to setup for base32 encoding which takes 5 bits at a time.
- b1 := byte(PrefixByteSeed) | (byte(public) >> 5)
- b2 := (byte(public) & 31) << 3 // 31 = 00011111
-
- var raw bytes.Buffer
-
- raw.WriteByte(b1)
- raw.WriteByte(b2)
-
- // write payload
- if _, err := raw.Write(src); err != nil {
- return nil, err
- }
-
- // Calculate and write crc16 checksum
- err := binary.Write(&raw, binary.LittleEndian, crc16(raw.Bytes()))
- if err != nil {
- return nil, err
- }
-
- data := raw.Bytes()
- buf := make([]byte, b32Enc.EncodedLen(len(data)))
- b32Enc.Encode(buf, data)
- return buf, nil
-}
-
-// IsValidEncoding will tell you if the encoding is a valid key.
-func IsValidEncoding(src []byte) bool {
- _, err := decode(src)
- return err == nil
-}
-
-// decode will decode the base32 and check crc16 and the prefix for validity.
-func decode(src []byte) ([]byte, error) {
- raw := make([]byte, b32Enc.DecodedLen(len(src)))
- n, err := b32Enc.Decode(raw, src)
- if err != nil {
- return nil, err
- }
- raw = raw[:n]
-
- if len(raw) < 4 {
- return nil, ErrInvalidEncoding
- }
-
- var crc uint16
- checksum := bytes.NewReader(raw[len(raw)-2:])
- if err := binary.Read(checksum, binary.LittleEndian, &crc); err != nil {
- return nil, err
- }
-
- // ensure checksum is valid
- if err := validate(raw[0:len(raw)-2], crc); err != nil {
- return nil, err
- }
-
- return raw[:len(raw)-2], nil
-}
-
-// Decode will decode the base32 string and check crc16 and enforce the prefix is what is expected.
-func Decode(expectedPrefix PrefixByte, src []byte) ([]byte, error) {
- if err := checkValidPrefixByte(expectedPrefix); err != nil {
- return nil, err
- }
- raw, err := decode(src)
- if err != nil {
- return nil, err
- }
- if prefix := PrefixByte(raw[0]); prefix != expectedPrefix {
- return nil, ErrInvalidPrefixByte
- }
- return raw[1:], nil
-}
-
-// DecodeSeed will decode the base32 string and check crc16 and enforce the prefix is a seed
-// and the subsequent type is a valid type.
-func DecodeSeed(src []byte) (PrefixByte, []byte, error) {
- raw, err := decode(src)
- if err != nil {
- return PrefixByteSeed, nil, err
- }
- // Need to do the reverse here to get back to internal representation.
- b1 := raw[0] & 248 // 248 = 11111000
- b2 := (raw[0]&7)<<5 | ((raw[1] & 248) >> 3) // 7 = 00000111
-
- if PrefixByte(b1) != PrefixByteSeed {
- return PrefixByteSeed, nil, ErrInvalidSeed
- }
- if checkValidPublicPrefixByte(PrefixByte(b2)) != nil {
- return PrefixByteSeed, nil, ErrInvalidSeed
- }
- return PrefixByte(b2), raw[2:], nil
-}
-
-// Prefix returns PrefixBytes of its input
-func Prefix(src string) PrefixByte {
- b, err := decode([]byte(src))
- if err != nil {
- return PrefixByteUnknown
- }
- prefix := PrefixByte(b[0])
- err = checkValidPrefixByte(prefix)
- if err == nil {
- return prefix
- }
- // Might be a seed.
- b1 := b[0] & 248
- if PrefixByte(b1) == PrefixByteSeed {
- return PrefixByteSeed
- }
- return PrefixByteUnknown
-}
-
-// IsValidPublicKey will decode and verify that the string is a valid encoded public key.
-func IsValidPublicKey(src string) bool {
- b, err := decode([]byte(src))
- if err != nil {
- return false
- }
- if prefix := PrefixByte(b[0]); checkValidPublicPrefixByte(prefix) != nil {
- return false
- }
- return true
-}
-
-// IsValidPublicUserKey will decode and verify the string is a valid encoded Public User Key.
-func IsValidPublicUserKey(src string) bool {
- _, err := Decode(PrefixByteUser, []byte(src))
- return err == nil
-}
-
-// IsValidPublicAccountKey will decode and verify the string is a valid encoded Public Account Key.
-func IsValidPublicAccountKey(src string) bool {
- _, err := Decode(PrefixByteAccount, []byte(src))
- return err == nil
-}
-
-// IsValidPublicServerKey will decode and verify the string is a valid encoded Public Server Key.
-func IsValidPublicServerKey(src string) bool {
- _, err := Decode(PrefixByteServer, []byte(src))
- return err == nil
-}
-
-// IsValidPublicClusterKey will decode and verify the string is a valid encoded Public Cluster Key.
-func IsValidPublicClusterKey(src string) bool {
- _, err := Decode(PrefixByteCluster, []byte(src))
- return err == nil
-}
-
-// IsValidPublicOperatorKey will decode and verify the string is a valid encoded Public Operator Key.
-func IsValidPublicOperatorKey(src string) bool {
- _, err := Decode(PrefixByteOperator, []byte(src))
- return err == nil
-}
-
-// checkValidPrefixByte returns an error if the provided value
-// is not one of the defined valid prefix byte constants.
-func checkValidPrefixByte(prefix PrefixByte) error {
- switch prefix {
- case PrefixByteOperator, PrefixByteServer, PrefixByteCluster,
- PrefixByteAccount, PrefixByteUser, PrefixByteSeed, PrefixBytePrivate:
- return nil
- }
- return ErrInvalidPrefixByte
-}
-
-// checkValidPublicPrefixByte returns an error if the provided value
-// is not one of the public defined valid prefix byte constants.
-func checkValidPublicPrefixByte(prefix PrefixByte) error {
- switch prefix {
- case PrefixByteServer, PrefixByteCluster, PrefixByteOperator, PrefixByteAccount, PrefixByteUser:
- return nil
- }
- return ErrInvalidPrefixByte
-}
-
-func (p PrefixByte) String() string {
- switch p {
- case PrefixByteOperator:
- return "operator"
- case PrefixByteServer:
- return "server"
- case PrefixByteCluster:
- return "cluster"
- case PrefixByteAccount:
- return "account"
- case PrefixByteUser:
- return "user"
- case PrefixByteSeed:
- return "seed"
- case PrefixBytePrivate:
- return "private"
- }
- return "unknown"
-}
-
-// CompatibleKeyPair returns an error if the KeyPair doesn't match expected PrefixByte(s)
-func CompatibleKeyPair(kp KeyPair, expected ...PrefixByte) error {
- pk, err := kp.PublicKey()
- if err != nil {
- return err
- }
- pkType := Prefix(pk)
- for _, k := range expected {
- if pkType == k {
- return nil
- }
- }
-
- return ErrIncompatibleKey
-}
diff --git a/vendor/github.com/nats-io/nuid/.gitignore b/vendor/github.com/nats-io/nuid/.gitignore
deleted file mode 100644
index daf913b1b34..00000000000
--- a/vendor/github.com/nats-io/nuid/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-*.prof
diff --git a/vendor/github.com/nats-io/nuid/.travis.yml b/vendor/github.com/nats-io/nuid/.travis.yml
deleted file mode 100644
index 52be726578e..00000000000
--- a/vendor/github.com/nats-io/nuid/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: go
-sudo: false
-go:
-- 1.9.x
-- 1.10.x
-
-install:
-- go get -t ./...
-- go get github.com/mattn/goveralls
-
-script:
-- go fmt ./...
-- go vet ./...
-- go test -v
-- go test -v --race
-- go test -v -covermode=count -coverprofile=coverage.out
-- $HOME/gopath/bin/goveralls -coverprofile coverage.out -service travis-ci
diff --git a/vendor/github.com/nats-io/nuid/GOVERNANCE.md b/vendor/github.com/nats-io/nuid/GOVERNANCE.md
deleted file mode 100644
index 01aee70d409..00000000000
--- a/vendor/github.com/nats-io/nuid/GOVERNANCE.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# NATS NUID Governance
-
-NATS NUID is part of the NATS project and is subject to the [NATS Governance](https://github.com/nats-io/nats-general/blob/master/GOVERNANCE.md).
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/nuid/LICENSE b/vendor/github.com/nats-io/nuid/LICENSE
deleted file mode 100644
index 261eeb9e9f8..00000000000
--- a/vendor/github.com/nats-io/nuid/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/nats-io/nuid/MAINTAINERS.md b/vendor/github.com/nats-io/nuid/MAINTAINERS.md
deleted file mode 100644
index 6d0ed3e31f9..00000000000
--- a/vendor/github.com/nats-io/nuid/MAINTAINERS.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Maintainers
-
-Maintainership is on a per project basis.
-
-### Core-maintainers
- - Derek Collison [@derekcollison](https://github.com/derekcollison)
\ No newline at end of file
diff --git a/vendor/github.com/nats-io/nuid/README.md b/vendor/github.com/nats-io/nuid/README.md
deleted file mode 100644
index 16e539485c4..00000000000
--- a/vendor/github.com/nats-io/nuid/README.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# NUID
-
-[![License Apache 2](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
-[![ReportCard](http://goreportcard.com/badge/nats-io/nuid)](http://goreportcard.com/report/nats-io/nuid)
-[![Build Status](https://travis-ci.org/nats-io/nuid.svg?branch=master)](http://travis-ci.org/nats-io/nuid)
-[![Release](https://img.shields.io/badge/release-v1.0.1-1eb0fc.svg)](https://github.com/nats-io/nuid/releases/tag/v1.0.1)
-[![GoDoc](http://godoc.org/github.com/nats-io/nuid?status.png)](http://godoc.org/github.com/nats-io/nuid)
-[![Coverage Status](https://coveralls.io/repos/github/nats-io/nuid/badge.svg?branch=master)](https://coveralls.io/github/nats-io/nuid?branch=master)
-
-A highly performant unique identifier generator.
-
-## Installation
-
-Use the `go` command:
-
- $ go get github.com/nats-io/nuid
-
-## Basic Usage
-```go
-
-// Utilize the global locked instance
-nuid := nuid.Next()
-
-// Create an instance, these are not locked.
-n := nuid.New()
-nuid = n.Next()
-
-// Generate a new crypto/rand seeded prefix.
-// Generally not needed, happens automatically.
-n.RandomizePrefix()
-```
-
-## Performance
-NUID needs to be very fast to generate and be truly unique, all while being entropy pool friendly.
-NUID uses 12 bytes of crypto generated data (entropy draining), and 10 bytes of pseudo-random
-sequential data that increments with a pseudo-random increment.
-
-Total length of a NUID string is 22 bytes of base 62 ascii text, so 62^22 or
-2707803647802660400290261537185326956544 possibilities.
-
-NUID can generate identifiers as fast as 60ns, or ~16 million per second. There is an associated
-benchmark you can use to test performance on your own hardware.
-
-## License
-
-Unless otherwise noted, the NATS source files are distributed
-under the Apache Version 2.0 license found in the LICENSE file.
diff --git a/vendor/github.com/nats-io/nuid/nuid.go b/vendor/github.com/nats-io/nuid/nuid.go
deleted file mode 100644
index 8134c764675..00000000000
--- a/vendor/github.com/nats-io/nuid/nuid.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2016-2019 The NATS Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// A unique identifier generator that is high performance, very fast, and tries to be entropy pool friendly.
-package nuid
-
-import (
- "crypto/rand"
- "fmt"
- "math"
- "math/big"
- "sync"
- "time"
-
- prand "math/rand"
-)
-
-// NUID needs to be very fast to generate and truly unique, all while being entropy pool friendly.
-// We will use 12 bytes of crypto generated data (entropy draining), and 10 bytes of sequential data
-// that is started at a pseudo random number and increments with a pseudo-random increment.
-// Total is 22 bytes of base 62 ascii text :)
-
-// Version of the library
-const Version = "1.0.1"
-
-const (
- digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- base = 62
- preLen = 12
- seqLen = 10
- maxSeq = int64(839299365868340224) // base^seqLen == 62^10
- minInc = int64(33)
- maxInc = int64(333)
- totalLen = preLen + seqLen
-)
-
-type NUID struct {
- pre []byte
- seq int64
- inc int64
-}
-
-type lockedNUID struct {
- sync.Mutex
- *NUID
-}
-
-// Global NUID
-var globalNUID *lockedNUID
-
-// Seed sequential random with crypto or math/random and current time
-// and generate crypto prefix.
-func init() {
- r, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
- if err != nil {
- prand.Seed(time.Now().UnixNano())
- } else {
- prand.Seed(r.Int64())
- }
- globalNUID = &lockedNUID{NUID: New()}
- globalNUID.RandomizePrefix()
-}
-
-// New will generate a new NUID and properly initialize the prefix, sequential start, and sequential increment.
-func New() *NUID {
- n := &NUID{
- seq: prand.Int63n(maxSeq),
- inc: minInc + prand.Int63n(maxInc-minInc),
- pre: make([]byte, preLen),
- }
- n.RandomizePrefix()
- return n
-}
-
-// Generate the next NUID string from the global locked NUID instance.
-func Next() string {
- globalNUID.Lock()
- nuid := globalNUID.Next()
- globalNUID.Unlock()
- return nuid
-}
-
-// Generate the next NUID string.
-func (n *NUID) Next() string {
- // Increment and capture.
- n.seq += n.inc
- if n.seq >= maxSeq {
- n.RandomizePrefix()
- n.resetSequential()
- }
- seq := n.seq
-
- // Copy prefix
- var b [totalLen]byte
- bs := b[:preLen]
- copy(bs, n.pre)
-
- // copy in the seq in base62.
- for i, l := len(b), seq; i > preLen; l /= base {
- i -= 1
- b[i] = digits[l%base]
- }
- return string(b[:])
-}
-
-// Resets the sequential portion of the NUID.
-func (n *NUID) resetSequential() {
- n.seq = prand.Int63n(maxSeq)
- n.inc = minInc + prand.Int63n(maxInc-minInc)
-}
-
-// Generate a new prefix from crypto/rand.
-// This call *can* drain entropy and will be called automatically when we exhaust the sequential range.
-// Will panic if it gets an error from rand.Int()
-func (n *NUID) RandomizePrefix() {
- var cb [preLen]byte
- cbs := cb[:]
- if nb, err := rand.Read(cbs); nb != preLen || err != nil {
- panic(fmt.Sprintf("nuid: failed generating crypto random number: %v\n", err))
- }
-
- for i := 0; i < preLen; i++ {
- n.pre[i] = digits[int(cbs[i])%base]
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/.travis.yml b/vendor/github.com/newrelic/go-agent/.travis.yml
deleted file mode 100644
index 93038523e30..00000000000
--- a/vendor/github.com/newrelic/go-agent/.travis.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-language: go
-go_import_path: github.com/newrelic/go-agent
-
-matrix:
- include:
- - go: "1.3"
- - go: "1.4"
- - go: "1.5"
- - go: "1.6"
- - go: "1.7"
- - go: "1.8"
- - go: "1.9"
- - go: "1.10"
- - go: "1.11"
- - go: "1.12"
- - go: "1.13"
- - go: "1.13"
- env: INTEGRATION=_integrations/nrawssdk
- - go: "1.13"
- env: INTEGRATION=_integrations/nrecho
- - go: "1.13"
- env: INTEGRATION=_integrations/nrgin/v1
- - go: "1.13"
- env: INTEGRATION=_integrations/nrgorilla/v1
- - go: "1.13"
- env: INTEGRATION=_integrations/nrlogrus
- - go: "1.13"
- env: INTEGRATION=_integrations/nrlogxi/v1
- - go: "1.13"
- env: INTEGRATION=_integrations/nrpkgerrors
- - go: "1.13"
- env: INTEGRATION=_integrations/nrlambda
- - go: "1.13"
- env: INTEGRATION=_integrations/nrmysql
- - go: "1.13"
- env: INTEGRATION=_integrations/nrpq
- - go: "1.13"
- env: INTEGRATION=_integrations/nrsqlite3
- - go: "1.13"
- env: INTEGRATION=_integrations/nrgrpc
- - go: "1.13"
- env: INTEGRATION=_integrations/nrmicro
- - go: "1.13"
- env: INTEGRATION=_integrations/nrnats
- - go: "1.13"
- env: INTEGRATION=_integrations/nrstan
- - go: "1.13"
- env: INTEGRATION=_integrations/logcontext
- - go: "1.13"
- env: INTEGRATION=_integrations/nrzap
- - go: "1.13"
- env: INTEGRATION=_integrations/nrhttprouter
-
-# Skip the install step. Don't `go get` dependencies.
-install: true
-
-script:
- - bash build-script.sh
diff --git a/vendor/github.com/newrelic/go-agent/CHANGELOG.md b/vendor/github.com/newrelic/go-agent/CHANGELOG.md
deleted file mode 100644
index b4284507ced..00000000000
--- a/vendor/github.com/newrelic/go-agent/CHANGELOG.md
+++ /dev/null
@@ -1,824 +0,0 @@
-## ChangeLog
-
-## 2.13.0
-
-### New Features
-
-* Added support for [HttpRouter](https://github.com/julienschmidt/httprouter) in
- the new [_integrations/nrhttprouter](http://godoc.org/github.com/newrelic/go-agent/_integrations/nrhttprouter) package. This package allows you to easily instrument inbound requests through the HttpRouter framework.
-
- * [Documentation](http://godoc.org/github.com/newrelic/go-agent/_integrations/nrhttprouter)
- * [Example](_integrations/nrhttprouter/example/main.go)
-
-* Added support for [github.com/uber-go/zap](https://github.com/uber-go/zap) in
- the new
- [_integrations/nrzap](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrzap)
- package. This package allows you to send agent log messages to `zap`.
-
-## 2.12.0
-
-### New Features
-
-* Added new methods to expose `Transaction` details:
-
- * `Transaction.GetTraceMetadata()` returns a
- [TraceMetadata](https://godoc.org/github.com/newrelic/go-agent#TraceMetadata)
- which contains distributed tracing identifiers.
-
- * `Transaction.GetLinkingMetadata()` returns a
- [LinkingMetadata](https://godoc.org/github.com/newrelic/go-agent#LinkingMetadata)
- which contains the fields needed to link data to a trace or entity.
-
-* Added a new plugin for the [Logrus logging
- framework](https://github.com/sirupsen/logrus) with the new
- [_integrations/logcontext/nrlogrusplugin](https://github.com/newrelic/go-agent/go-agent/tree/master/_integrations/logcontext/nrlogrusplugin)
- package. This plugin leverages the new `GetTraceMetadata` and
- `GetLinkingMetadata` above to decorate logs.
-
- To enable, set your log's formatter to the `nrlogrusplugin.ContextFormatter{}`
-
- ```go
- logger := logrus.New()
- logger.SetFormatter(nrlogrusplugin.ContextFormatter{})
- ```
-
- The logger will now look for a `newrelic.Transaction` inside its context and
- decorate logs accordingly. Therefore, the Transaction must be added to the
- context and passed to the logger. For example, this logging call
-
- ```go
- logger.Info("Hello New Relic!")
- ```
-
- must be transformed to include the context, such as:
-
- ```go
- ctx := newrelic.NewContext(context.Background(), txn)
- logger.WithContext(ctx).Info("Hello New Relic!")
- ```
-
- For full documentation see the
- [godocs](https://godoc.org/github.com/newrelic/go-agent/_integrations/logcontext/nrlogrusplugin)
- or view the
- [example](https://github.com/newrelic/go-agent/blob/master/_integrations/logcontext/nrlogrusplugin/example/main.go).
-
-* Added support for [NATS](https://github.com/nats-io/nats.go) and [NATS Streaming](https://github.com/nats-io/stan.go)
-monitoring with the new [_integrations/nrnats](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrnats) and
-[_integrations/nrstan](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrstan) packages. These packages
-support instrumentation of publishers and subscribers.
-
- * [NATS Example](https://github.com/newrelic/go-agent/blob/master/_integrations/nrnats/examples/main.go)
- * [NATS Streaming Example](https://github.com/newrelic/go-agent/blob/master/_integrations/nrstan/examples/main.go)
-
-* Enables ability to migrate to [Configurable Security Policies (CSP)](https://docs.newrelic.com/docs/agents/manage-apm-agents/configuration/enable-configurable-security-policies) on a per agent basis for accounts already using [High Security Mode (HSM)](https://docs.newrelic.com/docs/agents/manage-apm-agents/configuration/high-security-mode).
- * Previously, if CSP was configured for an account, New Relic would not allow an agent to connect without the `security_policies_token`. This led to agents not being able to connect during the period between when CSP was enabled for an account and when each agent is configured with the correct token.
- * With this change, when both HSM and CSP are enabled for an account, an agent (this version or later) can successfully connect with either `high_security: true` or the appropriate `security_policies_token` configured - allowing the agent to continue to connect after CSP is configured on the account but before the appropriate `security_policies_token` is configured for each agent.
-
-## 2.11.0
-
-### New Features
-
-* Added support for [Micro](https://github.com/micro/go-micro) monitoring with the new
-[_integrations/nrmicro](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrmicro)
-package. This package supports instrumentation for servers, clients, publishers, and subscribers.
-
- * [Server Example](https://github.com/newrelic/go-agent/blob/master/_integrations/nrmicro/example/server/server.go)
- * [Client Example](https://github.com/newrelic/go-agent/blob/master/_integrations/nrmicro/example/client/client.go)
- * [Publisher and Subscriber Example](https://github.com/newrelic/go-agent/blob/master/_integrations/nrmicro/example/pubsub/main.go)
- * [Full godocs Documentation](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrmicro)
-
-* Added support for creating static `WebRequest` instances manually via the `NewStaticWebRequest` function. This can be useful when you want to create a web transaction but don't have an `http.Request` object. Here's an example of creating a static `WebRequest` and using it to mark a transaction as a web transaction:
- ```go
- hdrs := http.Headers{}
- u, _ := url.Parse("http://example.com")
- webReq := newrelic.NewStaticWebRequest(hdrs, u, "GET", newrelic.TransportHTTP)
- txn := app.StartTransaction("My-Transaction", nil, nil)
- txn.SetWebRequest(webReq)
- ```
-
-## 2.10.0
-
-### New Features
-
-* Added support for custom events when using
- [nrlambda](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlambda).
- Example Lambda handler which creates custom event:
-
- ```go
- func handler(ctx context.Context) {
- if txn := newrelic.FromContext(ctx); nil != txn {
- txn.Application().RecordCustomEvent("myEvent", map[string]interface{}{
- "zip": "zap",
- })
- }
- fmt.Println("hello world!")
- }
- ```
-
-## 2.9.0
-
-### New Features
-
-* Added support for [gRPC](https://github.com/grpc/grpc-go) monitoring with the new
-[_integrations/nrgrpc](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrgrpc)
-package. This package supports instrumentation for servers and clients.
-
- * [Server Example](https://github.com/newrelic/go-agent/blob/master/_integrations/nrgrpc/example/server/server.go)
- * [Client Example](https://github.com/newrelic/go-agent/blob/master/_integrations/nrgrpc/example/client/client.go)
-
-* Added new
- [ExternalSegment](https://godoc.org/github.com/newrelic/go-agent#ExternalSegment)
- fields `Host`, `Procedure`, and `Library`. These optional fields are
- automatically populated from the segment's `URL` or `Request` if unset. Use
- them if you don't have access to a request or URL but still want useful external
- metrics, transaction segment attributes, and span attributes.
- * `Host` is used for external metrics, transaction trace segment names, and
- span event names. The host of segment's `Request` or `URL` is the default.
- * `Procedure` is used for transaction breakdown metrics. If set, it should be
- set to the remote procedure being called. The HTTP method of the segment's `Request` is the default.
- * `Library` is used for external metrics and the `"component"` span attribute.
- If set, it should be set to the framework making the call. `"http"` is the default.
-
- With the addition of these new fields, external transaction breakdown metrics
- are changed: `External/myhost.com/all` will now report as
- `External/myhost.com/http/GET` (provided the HTTP method is `GET`).
-
-* HTTP Response codes below `100`, except `0` and `5`, are now recorded as
- errors. This is to support `gRPC` status codes. If you start seeing
- new status code errors that you would like to ignore, add them to
- `Config.ErrorCollector.IgnoreStatusCodes` or your server side configuration
- settings.
-
-* Improve [logrus](https://github.com/sirupsen/logrus) support by introducing
- [nrlogrus.Transform](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlogrus#Transform),
- a function which allows you to turn a
- [logrus.Logger](https://godoc.org/github.com/sirupsen/logrus#Logger) instance into a
- [newrelic.Logger](https://godoc.org/github.com/newrelic/go-agent#Logger).
- Example use:
-
- ```go
- l := logrus.New()
- l.SetLevel(logrus.DebugLevel)
- cfg := newrelic.NewConfig("Your Application Name", "__YOUR_NEW_RELIC_LICENSE_KEY__")
- cfg.Logger = nrlogrus.Transform(l)
- ```
-
- As a result of this change, the
- [nrlogrus](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlogrus)
- package requires [logrus](https://github.com/sirupsen/logrus) version `v1.1.0`
- and above.
-
-## 2.8.1
-
-### Bug Fixes
-
-* Removed `nrmysql.NewConnector` since
- [go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) has not yet
- released `mysql.NewConnector`.
-
-## 2.8.0
-
-### New Features
-
-* Introduce support for databases using
- [database/sql](https://golang.org/pkg/database/sql/). This new functionality
- allows you to instrument MySQL, PostgreSQL, and SQLite calls without manually
- creating
- [DatastoreSegment](https://godoc.org/github.com/newrelic/go-agent#DatastoreSegment)s.
-
- | Database Library Supported | Integration Package |
- | ------------- | ------------- |
- | [go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) | [_integrations/nrmysql](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrmysql) |
- | [lib/pq](https://github.com/lib/pq) | [_integrations/nrpq](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrpq) |
- | [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) | [_integrations/nrsqlite3](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrsqlite3) |
-
- Using these database integration packages is easy! First replace the driver
- with our integration version:
-
- ```go
- import (
- // import our integration package in place of "github.com/go-sql-driver/mysql"
- _ "github.com/newrelic/go-agent/_integrations/nrmysql"
- )
-
- func main() {
- // open "nrmysql" in place of "mysql"
- db, err := sql.Open("nrmysql", "user@unix(/path/to/socket)/dbname")
- }
- ```
-
- Second, use the `ExecContext`, `QueryContext`, and `QueryRowContext` methods of
- [sql.DB](https://golang.org/pkg/database/sql/#DB),
- [sql.Conn](https://golang.org/pkg/database/sql/#Conn),
- [sql.Tx](https://golang.org/pkg/database/sql/#Tx), and
- [sql.Stmt](https://golang.org/pkg/database/sql/#Stmt) and provide a
- transaction-containing context. Calls to `Exec`, `Query`, and `QueryRow` do not
- get instrumented.
-
- ```go
- ctx := newrelic.NewContext(context.Background(), txn)
- row := db.QueryRowContext(ctx, "SELECT count(*) from tables")
- ```
-
- If you are using a [database/sql](https://golang.org/pkg/database/sql/) database
- not listed above, you can write your own instrumentation for it using
- [InstrumentSQLConnector](https://godoc.org/github.com/newrelic/go-agent#InstrumentSQLConnector),
- [InstrumentSQLDriver](https://godoc.org/github.com/newrelic/go-agent#InstrumentSQLDriver),
- and
- [SQLDriverSegmentBuilder](https://godoc.org/github.com/newrelic/go-agent#SQLDriverSegmentBuilder).
- The integration packages act as examples of how to do this.
-
- For more information, see the [Go agent documentation on instrumenting datastore segments](https://docs.newrelic.com/docs/agents/go-agent/instrumentation/instrument-go-segments#go-datastore-segments).
-
-### Bug Fixes
-
-* The [http.RoundTripper](https://golang.org/pkg/net/http/#RoundTripper) returned
- by [NewRoundTripper](https://godoc.org/github.com/newrelic/go-agent#NewRoundTripper)
- no longer modifies the request. Our thanks to @jlordiales for the contribution.
-
-## 2.7.0
-
-### New Features
-
-* Added support for server side configuration. Server side configuration allows
- you to set the following configuration settings in the New Relic APM UI:
-
- * `Config.TransactionTracer.Enabled`
- * `Config.ErrorCollector.Enabled`
- * `Config.CrossApplicationTracer.Enabled`
- * `Config.TransactionTracer.Threshold`
- * `Config.TransactionTracer.StackTraceThreshold`
- * `Config.ErrorCollector.IgnoreStatusCodes`
-
- For more information see the [server side configuration documentation](https://docs.newrelic.com/docs/agents/manage-apm-agents/configuration/server-side-agent-configuration).
-
-* Added support for AWS Lambda functions in the new
- [nrlambda](_integrations/nrlambda)
- package. Please email if you are interested in
- learning more or previewing New Relic Lambda monitoring. This instrumentation
- package requires `aws-lambda-go` version
- [v1.9.0](https://github.com/aws/aws-lambda-go/releases) and above.
-
- * [documentation](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlambda)
- * [working example](_integrations/nrlambda/example/main.go)
-
-## 2.6.0
-
-### New Features
-
-* Added support for async: the ability to instrument multiple concurrent
- goroutines, or goroutines that access or manipulate the same Transaction.
-
- The new `Transaction.NewGoroutine() Transaction` method allows
- transactions to create segments in multiple goroutines!
-
- `NewGoroutine` returns a new reference to the `Transaction`. This must be
- called any time you are passing the `Transaction` to another goroutine which
- makes segments. Each segment-creating goroutine must have its own `Transaction`
- reference. It does not matter if you call this before or after the other
- goroutine has started.
-
- All `Transaction` methods can be used in any `Transaction` reference. The
- `Transaction` will end when `End()` is called in any goroutine.
-
- Example passing a new `Transaction` reference directly to another goroutine:
-
- ```go
- go func(txn newrelic.Transaction) {
- defer newrelic.StartSegment(txn, "async").End()
- time.Sleep(100 * time.Millisecond)
- }(txn.NewGoroutine())
- ```
-
- Example passing a new `Transaction` reference on a channel to another
- goroutine:
-
- ```go
- ch := make(chan newrelic.Transaction)
- go func() {
- txn := <-ch
- defer newrelic.StartSegment(txn, "async").End()
- time.Sleep(100 * time.Millisecond)
- }()
- ch <- txn.NewGoroutine()
- ```
-
-* Added integration support for
- [`aws-sdk-go`](https://github.com/aws/aws-sdk-go) and
- [`aws-sdk-go-v2`](https://github.com/aws/aws-sdk-go-v2).
-
- When using these SDKs, a segment will be created for each out going request.
- For DynamoDB calls, these will be Datastore segments and for all others they
- will be External segments.
- * [v1 Documentation](http://godoc.org/github.com/newrelic/go-agent/_integrations/nrawssdk/v1)
- * [v2 Documentation](http://godoc.org/github.com/newrelic/go-agent/_integrations/nrawssdk/v2)
-
-* Added span event and transaction trace segment attribute configuration. You
- may control which attributes are captured in span events and transaction trace
- segments using the `Config.SpanEvents.Attributes` and
- `Config.TransactionTracer.Segments.Attributes` settings. For example, if you
- want to disable the collection of `"db.statement"` in your span events, modify
- your config like this:
-
- ```go
- cfg.SpanEvents.Attributes.Exclude = append(cfg.SpanEvents.Attributes.Exclude,
- newrelic.SpanAttributeDBStatement)
- ```
-
- To disable the collection of all attributes from your transaction trace
- segments, modify your config like this:
-
- ```go
- cfg.TransactionTracer.Segments.Attributes.Enabled = false
- ```
-
-### Bug Fixes
-
-* Fixed a bug that would prevent External Segments from being created under
- certain error conditions related to Cross Application Tracing.
-
-### Miscellaneous
-
-* Improved linking between Cross Application Transaction Traces in the APM UI.
- When `Config.CrossApplicationTracer.Enabled = true`, External segments in the
- Transaction Traces details will now link to the downstream Transaction Trace
- if there is one. Additionally, the segment name will now include the name of
- the downstream application and the name of the downstream transaction.
-
-* Update attribute names of Datastore and External segments on Transaction
- Traces to be in line with attribute names on Spans. Specifically:
- * `"uri"` => `"http.url"`
- * `"query"` => `"db.statement"`
- * `"database_name"` => `"db.instance"`
- * `"host"` => `"peer.hostname"`
- * `"port_path_or_id"` + `"host"` => `"peer.address"`
-
-## 2.5.0
-
-* Added support for [New Relic Browser](https://docs.newrelic.com/docs/browser)
- using the new `BrowserTimingHeader` method on the
- [`Transaction`](https://godoc.org/github.com/newrelic/go-agent#Transaction)
- which returns a
- [BrowserTimingHeader](https://godoc.org/github.com/newrelic/go-agent#BrowserTimingHeader).
- The New Relic Browser JavaScript code measures page load timing, also known as
- real user monitoring. The Pro version of this feature measures AJAX requests,
- single-page applications, JavaScript errors, and much more! Example use:
-
-```go
-func browser(w http.ResponseWriter, r *http.Request) {
- hdr, err := w.(newrelic.Transaction).BrowserTimingHeader()
- if nil != err {
- log.Printf("unable to create browser timing header: %v", err)
- }
- // BrowserTimingHeader() will always return a header whose methods can
- // be safely called.
- if js := hdr.WithTags(); js != nil {
- w.Write(js)
- }
- io.WriteString(w, "browser header page")
-}
-```
-
-* The Go agent now collects an attribute named `request.uri` on Transaction
- Traces, Transaction Events, Error Traces, and Error Events. `request.uri`
- will never contain user, password, query parameters, or fragment. To prevent
- the request's URL from being collected in any data, modify your `Config` like
- this:
-
-```go
-cfg.Attributes.Exclude = append(cfg.Attributes.Exclude, newrelic.AttributeRequestURI)
-```
-
-## 2.4.0
-
-* Introduced `Transaction.Application` method which returns the `Application`
- that started the `Transaction`. This method is useful since it may prevent
- having to pass the `Application` to code that already has access to the
- `Transaction`. Example use:
-
-```go
-txn.Application().RecordCustomEvent("customerOrder", map[string]interface{}{
- "numItems": 2,
- "totalPrice": 13.75,
-})
-```
-
-* The `Transaction.AddAttribute` method no longer accepts `nil` values since
- our backend ignores them.
-
-## 2.3.0
-
-* Added support for [Echo](https://echo.labstack.com) in the new `nrecho`
- package.
- * [Documentation](http://godoc.org/github.com/newrelic/go-agent/_integrations/nrecho)
- * [Example](_integrations/nrecho/example/main.go)
-
-* Introduced `Transaction.SetWebResponse(http.ResponseWriter)` method which sets
- the transaction's response writer. After calling this method, the
- `Transaction` may be used in place of the `http.ResponseWriter` to intercept
- the response code. This method is useful when the `http.ResponseWriter` is
- not available at the beginning of the transaction (if so, it can be given as a
- parameter to `Application.StartTransaction`). This method will return a
- reference to the transaction which implements the combination of
- `http.CloseNotifier`, `http.Flusher`, `http.Hijacker`, and `io.ReaderFrom`
- implemented by the ResponseWriter. Example:
-
-```go
-func setResponseDemo(txn newrelic.Transaction) {
- recorder := httptest.NewRecorder()
- txn = txn.SetWebResponse(recorder)
- txn.WriteHeader(200)
- fmt.Println("response code recorded:", recorder.Code)
-}
-```
-
-* The `Transaction`'s `http.ResponseWriter` methods may now be called safely if
- a `http.ResponseWriter` has not been set. This allows you to add a response code
- to the transaction without using a `http.ResponseWriter`. Example:
-
-```go
-func transactionWithResponseCode(app newrelic.Application) {
- txn := app.StartTransaction("hasResponseCode", nil, nil)
- defer txn.End()
- txn.WriteHeader(200) // Safe!
-}
-```
-
-* The agent now collects environment variables prefixed by
- `NEW_RELIC_METADATA_`. Some of these may be added
- Transaction events to provide context between your Kubernetes cluster and your
- services. For details on the benefits (currently in beta) see [this blog
- post](https://blog.newrelic.com/engineering/monitoring-application-performance-in-kubernetes/)
-
-* The agent now collects the `KUBERNETES_SERVICE_HOST` environment variable to
- detect when the application is running on Kubernetes.
-
-* The agent now collects the fully qualified domain name of the host and
- local IP addresses for improved linking with our infrastructure product.
-
-## 2.2.0
-
-* The `Transaction` parameter to
-[NewRoundTripper](https://godoc.org/github.com/newrelic/go-agent#NewRoundTripper)
-and
-[StartExternalSegment](https://godoc.org/github.com/newrelic/go-agent#StartExternalSegment)
-is now optional: If it is `nil`, then a `Transaction` will be looked for in the
-request's context (using
-[FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext)).
-Passing a `nil` transaction is **STRONGLY** recommended when using
-[NewRoundTripper](https://godoc.org/github.com/newrelic/go-agent#NewRoundTripper)
-since it allows one `http.Client.Transport` to be used for multiple
-transactions. Example use:
-
-```go
-client := &http.Client{}
-client.Transport = newrelic.NewRoundTripper(nil, client.Transport)
-request, _ := http.NewRequest("GET", "http://example.com", nil)
-request = newrelic.RequestWithTransactionContext(request, txn)
-resp, err := client.Do(request)
-```
-
-* Introduced `Transaction.SetWebRequest(WebRequest)` method which marks the
-transaction as a web transaction. If the `WebRequest` parameter is non-nil,
-`SetWebRequest` will collect details on request attributes, url, and method.
-This method is useful if you don't have access to the request at the beginning
-of the transaction, or if your request is not an `*http.Request` (just add
-methods to your request that satisfy
-[WebRequest](https://godoc.org/github.com/newrelic/go-agent#WebRequest)). To
-use an `*http.Request` as the parameter, use the
-[NewWebRequest](https://godoc.org/github.com/newrelic/go-agent#NewWebRequest)
-transformation function. Example:
-
-```go
-var request *http.Request = getInboundRequest()
-txn.SetWebRequest(newrelic.NewWebRequest(request))
-```
-
-* Fixed `Debug` in `nrlogrus` package. Previous versions of the New Relic Go Agent incorrectly
-logged to Info level instead of Debug. This has now been fixed. Thanks to @paddycarey for catching this.
-
-* [nrgin.Transaction](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrgin/v1#Transaction)
-may now be called with either a `context.Context` or a `*gin.Context`. If you were passing a `*gin.Context`
-around your functions as a `context.Context`, you may access the Transaction by calling either
-[nrgin.Transaction](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrgin/v1#Transaction)
-or [FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext).
-These functions now work nicely together.
-For example, [FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext) will return the `Transaction`
-added by [nrgin.Middleware](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrgin/v1#Middleware).
-Thanks to @rodriguezgustavo for the suggestion.
-
-## 2.1.0
-
-* The Go Agent now supports distributed tracing.
-
- Distributed tracing lets you see the path that a request takes as it travels through your distributed system. By
- showing the distributed activity through a unified view, you can troubleshoot and understand a complex system better
- than ever before.
-
- Distributed tracing is available with an APM Pro or equivalent subscription. To see a complete distributed trace, you
- need to enable the feature on a set of neighboring services. Enabling distributed tracing changes the behavior of
- some New Relic features, so carefully consult the
- [transition guide](https://docs.newrelic.com/docs/transition-guide-distributed-tracing) before you enable this
- feature.
-
- To enable distributed tracing, set the following fields in your config. Note that distributed tracing and cross
- application tracing cannot be used simultaneously.
-
-```
- config := newrelic.NewConfig("Your Application Name", "__YOUR_NEW_RELIC_LICENSE_KEY__")
- config.CrossApplicationTracer.Enabled = false
- config.DistributedTracer.Enabled = true
-```
-
- Please refer to the
- [distributed tracing section of the guide](GUIDE.md#distributed-tracing)
- for more detail on how to ensure you get the most out of the Go agent's distributed tracing support.
-
-* Added functions [NewContext](https://godoc.org/github.com/newrelic/go-agent#NewContext)
- and [FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext)
- for adding and retrieving the Transaction from a Context. Handlers
- instrumented by
- [WrapHandle](https://godoc.org/github.com/newrelic/go-agent#WrapHandle),
- [WrapHandleFunc](https://godoc.org/github.com/newrelic/go-agent#WrapHandleFunc),
- and [nrgorilla.InstrumentRoutes](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrgorilla/v1#InstrumentRoutes)
- may use [FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext)
- on the request's context to access the Transaction.
- Thanks to @caarlos0 for the contribution! Though [NewContext](https://godoc.org/github.com/newrelic/go-agent#NewContext)
- and [FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext)
- require Go 1.7+ (when [context](https://golang.org/pkg/context/) was added),
- [RequestWithTransactionContext](https://godoc.org/github.com/newrelic/go-agent#RequestWithTransactionContext) is always exported so that it can be used in all framework and library
- instrumentation.
-
-## 2.0.0
-
-* The `End()` functions defined on the `Segment`, `DatastoreSegment`, and
- `ExternalSegment` types now receive the segment as a pointer, rather than as
- a value. This prevents unexpected behaviour when a call to `End()` is
- deferred before one or more fields are changed on the segment.
-
- In practice, this is likely to only affect this pattern:
-
- ```go
- defer newrelic.DatastoreSegment{
- // ...
- }.End()
- ```
-
- Instead, you will now need to separate the literal from the deferred call:
-
- ```go
- ds := newrelic.DatastoreSegment{
- // ...
- }
- defer ds.End()
- ```
-
- When creating custom and external segments, we recommend using
- [`newrelic.StartSegment()`](https://godoc.org/github.com/newrelic/go-agent#StartSegment)
- and
- [`newrelic.StartExternalSegment()`](https://godoc.org/github.com/newrelic/go-agent#StartExternalSegment),
- respectively.
-
-* Added GoDoc badge to README. Thanks to @mrhwick for the contribution!
-
-* `Config.UseTLS` configuration setting has been removed to increase security.
- TLS will now always be used in communication with New Relic Servers.
-
-## 1.11.0
-
-* We've closed the Issues tab on GitHub. Please visit our
- [support site](https://support.newrelic.com) to get timely help with any
- problems you're having, or to report issues.
-
-* Added support for Cross Application Tracing (CAT). Please refer to the
- [CAT section of the guide](GUIDE.md#cross-application-tracing)
- for more detail on how to ensure you get the most out of the Go agent's new
- CAT support.
-
-* The agent now collects additional metadata when running within Amazon Web
- Services, Google Cloud Platform, Microsoft Azure, and Pivotal Cloud Foundry.
- This information is used to provide an enhanced experience when the agent is
- deployed on those platforms.
-
-## 1.10.0
-
-* Added new `RecordCustomMetric` method to [Application](https://godoc.org/github.com/newrelic/go-agent#Application).
- This functionality can be used to track averages or counters without using
- custom events.
- * [Custom Metric Documentation](https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-data/collect-custom-metrics)
-
-* Fixed import needed for logrus. The import Sirupsen/logrus had been renamed to sirupsen/logrus.
- Thanks to @alfred-landrum for spotting this.
-
-* Added [ErrorAttributer](https://godoc.org/github.com/newrelic/go-agent#ErrorAttributer),
- an optional interface that can be implemented by errors provided to
- `Transaction.NoticeError` to attach additional attributes. These attributes are
- subject to attribute configuration.
-
-* Added [Error](https://godoc.org/github.com/newrelic/go-agent#Error), a type
- that allows direct control of error fields. Example use:
-
-```go
-txn.NoticeError(newrelic.Error{
- // Message is returned by the Error() method.
- Message: "error message: something went very wrong",
- Class: "errors are aggregated by class",
- Attributes: map[string]interface{}{
- "important_number": 97232,
- "relevant_string": "zap",
- },
-})
-```
-
-* Updated license to address scope of usage.
-
-## 1.9.0
-
-* Added support for [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin)
- in the new `nrgin` package.
- * [Documentation](http://godoc.org/github.com/newrelic/go-agent/_integrations/nrgin/v1)
- * [Example](examples/_gin/main.go)
-
-## 1.8.0
-
-* Fixed incorrect metric rule application when the metric rule is flagged to
- terminate and matches but the name is unchanged.
-
-* `Segment.End()`, `DatastoreSegment.End()`, and `ExternalSegment.End()` methods now return an
- error which may be helpful in diagnosing situations where segment data is unexpectedly missing.
-
-## 1.7.0
-
-* Added support for [gorilla/mux](http://github.com/gorilla/mux) in the new `nrgorilla`
- package.
- * [Documentation](http://godoc.org/github.com/newrelic/go-agent/_integrations/nrgorilla/v1)
- * [Example](examples/_gorilla/main.go)
-
-## 1.6.0
-
-* Added support for custom error messages and stack traces. Errors provided
- to `Transaction.NoticeError` will now be checked to see if
- they implement [ErrorClasser](https://godoc.org/github.com/newrelic/go-agent#ErrorClasser)
- and/or [StackTracer](https://godoc.org/github.com/newrelic/go-agent#StackTracer).
- Thanks to @fgrosse for this proposal.
-
-* Added support for [pkg/errors](https://github.com/pkg/errors). Thanks to
- @fgrosse for this work.
- * [documentation](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrpkgerrors)
- * [example](https://github.com/newrelic/go-agent/blob/master/_integrations/nrpkgerrors/nrpkgerrors.go)
-
-* Fixed tests for Go 1.8.
-
-## 1.5.0
-
-* Added support for Windows. Thanks to @ianomad and @lvxv for the contributions.
-
-* The number of heap objects allocated is recorded in the
- `Memory/Heap/AllocatedObjects` metric. This will soon be displayed on the "Go
- runtime" page.
-
-* If the [DatastoreSegment](https://godoc.org/github.com/newrelic/go-agent#DatastoreSegment)
- fields `Host` and `PortPathOrID` are not provided, they will no longer appear
- as `"unknown"` in transaction traces and slow query traces.
-
-* Stack traces will now be nicely aligned in the APM UI.
-
-## 1.4.0
-
-* Added support for slow query traces. Slow datastore segments will now
- generate slow query traces viewable on the datastore tab. These traces include
- a stack trace and help you to debug slow datastore activity.
- [Slow Query Documentation](https://docs.newrelic.com/docs/apm/applications-menu/monitoring/viewing-slow-query-details)
-
-* Added new
-[DatastoreSegment](https://godoc.org/github.com/newrelic/go-agent#DatastoreSegment)
-fields `ParameterizedQuery`, `QueryParameters`, `Host`, `PortPathOrID`, and
-`DatabaseName`. These fields will be shown in transaction traces and in slow
-query traces.
-
-## 1.3.0
-
-* Breaking Change: Added a timeout parameter to the `Application.Shutdown` method.
-
-## 1.2.0
-
-* Added support for instrumenting short-lived processes:
- * The new `Application.Shutdown` method allows applications to report
- data to New Relic without waiting a full minute.
- * The new `Application.WaitForConnection` method allows your process to
- defer instrumentation until the application is connected and ready to
- gather data.
- * Full documentation here: [application.go](application.go)
- * Example short-lived process: [examples/short-lived-process/main.go](examples/short-lived-process/main.go)
-
-* Error metrics are no longer created when `ErrorCollector.Enabled = false`.
-
-* Added support for [github.com/mgutz/logxi](github.com/mgutz/logxi). See
- [_integrations/nrlogxi/v1/nrlogxi.go](_integrations/nrlogxi/v1/nrlogxi.go).
-
-* Fixed bug where Transaction Trace thresholds based upon Apdex were not being
- applied to background transactions.
-
-## 1.1.0
-
-* Added support for Transaction Traces.
-
-* Stack trace filenames have been shortened: Any thing preceding the first
- `/src/` is now removed.
-
-## 1.0.0
-
-* Removed `BetaToken` from the `Config` structure.
-
-* Breaking Datastore Change: `datastore` package contents moved to top level
- `newrelic` package. `datastore.MySQL` has become `newrelic.DatastoreMySQL`.
-
-* Breaking Attributes Change: `attributes` package contents moved to top
- level `newrelic` package. `attributes.ResponseCode` has become
- `newrelic.AttributeResponseCode`. Some attribute name constants have been
- shortened.
-
-* Added "runtime.NumCPU" to the environment tab. Thanks sergeylanzman for the
- contribution.
-
-* Prefixed the environment tab values "Compiler", "GOARCH", "GOOS", and
- "Version" with "runtime.".
-
-## 0.8.0
-
-* Breaking Segments API Changes: The segments API has been rewritten with the
- goal of being easier to use and to avoid nil Transaction checks. See:
-
- * [segments.go](segments.go)
- * [examples/server/main.go](examples/server/main.go)
- * [GUIDE.md#segments](GUIDE.md#segments)
-
-* Updated LICENSE.txt with contribution information.
-
-## 0.7.1
-
-* Fixed a bug causing the `Config` to fail to serialize into JSON when the
- `Transport` field was populated.
-
-## 0.7.0
-
-* Eliminated `api`, `version`, and `log` packages. `Version`, `Config`,
- `Application`, and `Transaction` now live in the top level `newrelic` package.
- If you imported the `attributes` or `datastore` packages then you will need
- to remove `api` from the import path.
-
-* Breaking Logging Changes
-
-Logging is no longer controlled though a single global. Instead, logging is
-configured on a per-application basis with the new `Config.Logger` field. The
-logger is an interface described in [log.go](log.go). See
-[GUIDE.md#logging](GUIDE.md#logging).
-
-## 0.6.1
-
-* No longer create "GC/System/Pauses" metric if no GC pauses happened.
-
-## 0.6.0
-
-* Introduced beta token to support our beta program.
-
-* Rename `Config.Development` to `Config.Enabled` (and change boolean
- direction).
-
-* Fixed a bug where exclusive time could be incorrect if segments were not
- ended.
-
-* Fix unit tests broken in 1.6.
-
-* In `Config.Enabled = false` mode, the license must be the proper length or empty.
-
-* Added runtime statistics for CPU/memory usage, garbage collection, and number
- of goroutines.
-
-## 0.5.0
-
-* Added segment timing methods to `Transaction`. These methods must only be
- used in a single goroutine.
-
-* The license length check will not be performed in `Development` mode.
-
-* Rename `SetLogFile` to `SetFile` to reduce redundancy.
-
-* Added `DebugEnabled` logging guard to reduce overhead.
-
-* `Transaction` now implements an `Ignore` method which will prevent
- any of the transaction's data from being recorded.
-
-* `Transaction` now implements a subset of the interfaces
- `http.CloseNotifier`, `http.Flusher`, `http.Hijacker`, and `io.ReaderFrom`
- to match the behavior of its wrapped `http.ResponseWriter`.
-
-* Changed project name from `go-sdk` to `go-agent`.
-
-## 0.4.0
-
-* Queue time support added: if the inbound request contains an
-`"X-Request-Start"` or `"X-Queue-Start"` header with a unix timestamp, the
-agent will report queue time metrics. Queue time will appear on the
-application overview chart. The timestamp may fractional seconds,
-milliseconds, or microseconds: the agent will deduce the correct units.
diff --git a/vendor/github.com/newrelic/go-agent/CONTRIBUTING.md b/vendor/github.com/newrelic/go-agent/CONTRIBUTING.md
deleted file mode 100644
index d04bd5e7fae..00000000000
--- a/vendor/github.com/newrelic/go-agent/CONTRIBUTING.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Contributing
-
-You are welcome to send pull requests to us. By doing so you agree that you are
-granting New Relic a non-exclusive, non-revokable, no-cost license to use the
-code, algorithms, patents, and ideas in that code in our products if we so
-choose. You also agree the code is provided as-is and you provide no warranties
-as to its fitness or correctness for any purpose.
-
-* [LICENSE.txt](LICENSE.txt)
diff --git a/vendor/github.com/newrelic/go-agent/GETTING_STARTED.md b/vendor/github.com/newrelic/go-agent/GETTING_STARTED.md
deleted file mode 100644
index 5d13ed14ac0..00000000000
--- a/vendor/github.com/newrelic/go-agent/GETTING_STARTED.md
+++ /dev/null
@@ -1,144 +0,0 @@
-# Getting Started
-
-Follow these steps to instrument your application. More information is
-available in the [GUIDE.md](GUIDE.md).
-
-## Step 0: Installation
-
-The New Relic Go agent is a Go library with no dependencies. Install it the same way
-you would install any other Go library. The simplest way is to run:
-
-```
-go get github.com/newrelic/go-agent
-```
-
-Then import the `github.com/newrelic/go-agent` package in your application.
-
-## Step 1: Create an Application
-
-In your `main` function, or an `init` block, create an
-[Application](https://godoc.org/github.com/newrelic/go-agent#Application) using
-a [Config](https://godoc.org/github.com/newrelic/go-agent#Config).
-[Application](https://godoc.org/github.com/newrelic/go-agent#Application) is the
-starting point for all instrumentation.
-
-```go
-func main() {
- // Create a Config:
- config := newrelic.NewConfig("Your Application Name", "__YOUR_NEW_RELIC_LICENSE_KEY__")
- // Modify the Config to add logging or alter agent behavior:
- config.Logger = NewLogger(os.Stdout)
- // Then create an Application:
- app, err := newrelic.NewApplication(config)
- // If an application could not be created then err will reveal why.
- if err != nil {
- fmt.Println("unable to create New Relic Application", err)
- }
- // Now use the app to instrument everything!
-}
-```
-
-Now start your application, and within minutes it will appear in the New Relic
-UI. Your application in New Relic won't contain much data (until we complete
-the steps below!), but you will already be able to see a
-[Go runtime](https://docs.newrelic.com/docs/agents/go-agent/features/go-runtime-page-troubleshoot-performance-problems)
-page that shows goroutine counts, garbage collection, memory, and CPU usage.
-
-## Step 2: Instrument Requests Using Transactions
-
-[Transactions](https://godoc.org/github.com/newrelic/go-agent#Transaction) are
-used to time inbound requests and background tasks. Use them to see your
-application's throughput and response time. The instrumentation strategy
-depends on the framework you're using:
-
-#### Standard HTTP Library
-
-If you are using the standard library `http` package, use
-[WrapHandle](https://godoc.org/github.com/newrelic/go-agent#WrapHandle) and
-[WrapHandleFunc](https://godoc.org/github.com/newrelic/go-agent#WrapHandleFunc).
-As an example, the following code:
-
-```go
-http.HandleFunc("/users", usersHandler)
-```
-Can be instrumented like this:
-```go
-http.HandleFunc(newrelic.WrapHandleFunc(app, "/users", usersHandler))
-```
-
-[Full Example Application](./examples/server/main.go)
-
-#### Popular Web Framework
-
-If you are using a popular framework, then there may be an integration package
-designed to instrument it. [List of New Relic Go agent integration packages](./README.md#integrations).
-
-#### Manual Transactions
-
-If you aren't using the `http` standard library package or an
-integration package supported framework, you can create transactions
-directly using the application's `StartTransaction` method:
-
-```go
-func myHandler(rw http.ResponseWriter, req *http.Request) {
- // The response writer and request parameters are optional. If your
- // request is not an *http.Request, try using Transaction.SetWebRequest
- // with a custom newrelic.WebRequest. If the request parameter is nil
- // then the transaction is considered a background task.
- txn := app.StartTransaction("myHandler", rw, req)
- defer txn.End()
-}
-```
-
-Be sure to use a limited set of unique names to ensure that transactions are
-grouped usefully. Don't use dynamic URLs!
-
-[More information about transactions](GUIDE.md#transactions)
-
-## Step 3: Instrument Segments
-
-Segments show you where the time in your transactions is being spent. There are
-three types of segments:
-[Segment](https://godoc.org/github.com/newrelic/go-agent#Segment),
-[ExternalSegment](https://godoc.org/github.com/newrelic/go-agent#ExternalSegment),
-and
-[DatastoreSegment](https://godoc.org/github.com/newrelic/go-agent#DatastoreSegment).
-
-Creating a segment requires access to the transaction. You can pass the
-transaction around your functions as an explicit transaction parameter or inside
-a [context.Context](https://golang.org/pkg/context/#Context). Functions
-[FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext) and
-[NewContext](https://godoc.org/github.com/newrelic/go-agent#NewContext) make it
-easy to store and retrieve the transaction from a context.
-
-You may not even need to add the transaction to the context:
-[WrapHandle](https://godoc.org/github.com/newrelic/go-agent#WrapHandle) and
-[WrapHandleFunc](https://godoc.org/github.com/newrelic/go-agent#WrapHandleFunc)
-add the transaction to the request's context automatically.
-
-```go
-func instrumentMe(ctx context.Context) {
- txn := newrelic.FromContext(ctx)
- segment := newrelic.StartSegment(txn, "instrumentMe")
- time.Sleep(1 * time.Second)
- segment.End()
-}
-
-func myHandler(w http.ResponseWriter, r *http.Request) {
- instrumentMe(r.Context())
-}
-
-func main() {
- cfg := newrelic.NewConfig("My App", "__YOUR_NEW_RELIC_LICENSE_KEY__")
- app, _ := newrelic.NewApplication(cfg)
- http.HandleFunc(newrelic.WrapHandleFunc(app, "/handler", myHandler))
-}
-```
-
-[More information about segments](GUIDE.md#segments)
-
-## Extra Credit
-
-Read our [GUIDE.md](GUIDE.md) and the
-[godocs](https://godoc.org/github.com/newrelic/go-agent) to learn more about
-what else you can do with the Go Agent.
diff --git a/vendor/github.com/newrelic/go-agent/GUIDE.md b/vendor/github.com/newrelic/go-agent/GUIDE.md
deleted file mode 100644
index 94af8531f06..00000000000
--- a/vendor/github.com/newrelic/go-agent/GUIDE.md
+++ /dev/null
@@ -1,715 +0,0 @@
-# New Relic Go Agent Guide
-
-* [Installation](#installation)
-* [Config and Application](#config-and-application)
-* [Logging](#logging)
-* [Transactions](#transactions)
-* [Segments](#segments)
- * [Datastore Segments](#datastore-segments)
- * [External Segments](#external-segments)
-* [Attributes](#attributes)
-* [Tracing](#tracing)
- * [Distributed Tracing](#distributed-tracing)
- * [Cross-Application Tracing](#cross-application-tracing)
- * [Tracing instrumentation](#tracing-instrumentation)
- * [Getting Tracing Instrumentation Out-of-the-Box](#getting-tracing-instrumentation-out-of-the-box)
- * [Manually Implementing Distributed Tracing](#manually-implementing-distributed-tracing)
-* [Distributed Tracing](#distributed-tracing)
-* [Custom Metrics](#custom-metrics)
-* [Custom Events](#custom-events)
-* [Request Queuing](#request-queuing)
-* [Error Reporting](#error-reporting)
- * [NoticeError](#noticeerror)
- * [Advanced NoticeError Use](#advanced-noticeerror-use)
- * [Panics](#panics)
- * [Error Response Codes](#error-response-codes)
-* [Naming Transactions and Metrics](#naming-transactions-and-metrics)
-* [Browser](#browser)
-* [For More Help](#for-more-help)
-
-## Installation
-
-Installing the Go Agent is the same as installing any other Go library. The
-simplest way is to run:
-
-```
-go get github.com/newrelic/go-agent
-```
-
-Then import the `github.com/newrelic/go-agent` package in your application.
-
-## Config and Application
-
-* [config.go](config.go)
-* [application.go](application.go)
-
-In your `main` function or in an `init` block:
-
-```go
-config := newrelic.NewConfig("Your Application Name", "__YOUR_NEW_RELIC_LICENSE_KEY__")
-app, err := newrelic.NewApplication(config)
-```
-
-Find your application in the New Relic UI. Click on it to see the Go runtime
-page that shows information about goroutine counts, garbage collection, memory,
-and CPU usage.
-
-If you are working in a development environment or running unit tests, you may
-not want the Go Agent to spawn goroutines or report to New Relic. You're in
-luck! Set the config's `Enabled` field to false. This makes the license key
-optional.
-
-```go
-config := newrelic.NewConfig("Your Application Name", "")
-config.Enabled = false
-app, err := newrelic.NewApplication(config)
-```
-
-## Logging
-
-The agent's logging system is designed to be easily extensible. By default, no
-logging will occur. To enable logging, assign the `Config.Logger` field to
-something implementing the
-[Logger](https://godoc.org/github.com/newrelic/go-agent#Logger) interface. Two
-[Logger](https://godoc.org/github.com/newrelic/go-agent#Logger) implementations
-are included:
-[NewLogger](https://godoc.org/github.com/newrelic/go-agent#NewLogger), which
-logs at info level, and
-[NewDebugLogger](https://godoc.org/github.com/newrelic/go-agent#NewDebugLogger)
-which logs at debug level.
-
-To log at debug level to standard out, set:
-
-```go
-cfg.Logger = newrelic.NewDebugLogger(os.Stdout)
-```
-
-To log at info level to a file, set:
-
-```go
-w, err := os.OpenFile("my_log_file", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
-if nil == err {
- cfg.Logger = newrelic.NewLogger(w)
-}
-```
-
-Popular logging libraries `logrus` and `logxi` are supported by integration packages:
-
-* [_integrations/nrlogrus](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlogrus)
-* [_integrations/nrlogxi/v1](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlogxi/v1)
-
-## Transactions
-
-* [transaction.go](transaction.go)
-* [Naming Transactions](#naming-transactions-and-metrics)
-* [More info on Transactions](https://docs.newrelic.com/docs/apm/applications-menu/monitoring/transactions-page)
-
-Transactions time requests and background tasks. Each transaction should only
-be used in a single goroutine. Start a new transaction when you spawn a new
-goroutine.
-
-The simplest way to create transactions is to use
-`Application.StartTransaction` and `Transaction.End`.
-
-```go
-txn := app.StartTransaction("transactionName", responseWriter, request)
-defer txn.End()
-```
-
-If the response writer is provided when calling `StartTransaction`, you can
-then use `txn.WriteHeader` as a drop in replacement for the standard library's
-[`http.ResponseWriter.WriteHeader`](https://golang.org/pkg/net/http/#ResponseWriter)
-function. We strongly recommend doing so, as this both enables cross-application
-tracing support and ensures that attributes are added to the
-Transaction event capturing the response size and status code.
-
-The response writer and request parameters are optional. Leave them `nil` to
-instrument a background task.
-
-```go
-txn := app.StartTransaction("backgroundTask", nil, nil)
-defer txn.End()
-```
-
-The transaction has helpful methods like `NoticeError` and `SetName`.
-See more in [transaction.go](transaction.go).
-
-If you are using [`http.ServeMux`](https://golang.org/pkg/net/http/#ServeMux),
-use `WrapHandle` and `WrapHandleFunc`. These wrappers automatically start and
-end transactions with the request and response writer. See
-[instrumentation.go](instrumentation.go).
-
-```go
-http.HandleFunc(newrelic.WrapHandleFunc(app, "/users", usersHandler))
-```
-
-To access the transaction in your handler, use type assertion on the response
-writer passed to the handler.
-
-```go
-func myHandler(w http.ResponseWriter, r *http.Request) {
- if txn, ok := w.(newrelic.Transaction); ok {
- txn.NoticeError(errors.New("my error message"))
- }
-}
-```
-
-## Segments
-
-* [segments.go](segments.go)
-
-Find out where the time in your transactions is being spent! Each transaction
-should only track segments in a single goroutine.
-
-`Segment` is used to instrument functions, methods, and blocks of code. A
-segment begins when its `StartTime` field is populated, and finishes when its
-`End` method is called.
-
-```go
-segment := newrelic.Segment{}
-segment.Name = "mySegmentName"
-segment.StartTime = newrelic.StartSegmentNow(txn)
-// ... code you want to time here ...
-segment.End()
-```
-
-`StartSegment` is a convenient helper. It creates a segment and starts it:
-
-```go
-segment := newrelic.StartSegment(txn, "mySegmentName")
-// ... code you want to time here ...
-segment.End()
-```
-
-Timing a function is easy using `StartSegment` and `defer`. Just add the
-following line to the beginning of that function:
-
-```go
-defer newrelic.StartSegment(txn, "mySegmentName").End()
-```
-
-Segments may be nested. The segment being ended must be the most recently
-started segment.
-
-```go
-s1 := newrelic.StartSegment(txn, "outerSegment")
-s2 := newrelic.StartSegment(txn, "innerSegment")
-// s2 must be ended before s1
-s2.End()
-s1.End()
-```
-
-A zero value segment may safely be ended. Therefore, the following code
-is safe even if the conditional fails:
-
-```go
-var s newrelic.Segment
-if txn, ok := w.(newrelic.Transaction); ok {
- s.StartTime = newrelic.StartSegmentNow(txn),
-}
-// ... code you wish to time here ...
-s.End()
-```
-
-### Datastore Segments
-
-Datastore segments appear in the transaction "Breakdown table" and in the
-"Databases" page.
-
-* [More info on Databases page](https://docs.newrelic.com/docs/apm/applications-menu/monitoring/databases-slow-queries-page)
-
-Datastore segments are instrumented using
-[DatastoreSegment](https://godoc.org/github.com/newrelic/go-agent#DatastoreSegment).
-Just like basic segments, datastore segments begin when the `StartTime` field
-is populated and finish when the `End` method is called. Here is an example:
-
-```go
-s := newrelic.DatastoreSegment{
- // Product is the datastore type. See the constants in
- // https://github.com/newrelic/go-agent/blob/master/datastore.go. Product
- // is one of the fields primarily responsible for the grouping of Datastore
- // metrics.
- Product: newrelic.DatastoreMySQL,
- // Collection is the table or group being operated upon in the datastore,
- // e.g. "users_table". This becomes the db.collection attribute on Span
- // events and Transaction Trace segments. Collection is one of the fields
- // primarily responsible for the grouping of Datastore metrics.
- Collection: "users_table",
- // Operation is the relevant action, e.g. "SELECT" or "GET". Operation is
- // one of the fields primarily responsible for the grouping of Datastore
- // metrics.
- Operation: "SELECT",
-}
-s.StartTime = newrelic.StartSegmentNow(txn)
-// ... make the datastore call
-s.End()
-```
-
-This may be combined into a single line when instrumenting a datastore call
-that spans an entire function call:
-
-```go
-s := newrelic.DatastoreSegment{
- StartTime: newrelic.StartSegmentNow(txn),
- Product: newrelic.DatastoreMySQL,
- Collection: "my_table",
- Operation: "SELECT",
-}
-defer s.End()
-```
-
-If you are using the standard library's
-[database/sql](https://golang.org/pkg/database/sql/) package with
-[MySQL](https://github.com/go-sql-driver/mysql),
-[PostgreSQL](https://github.com/lib/pq), or
-[SQLite](https://github.com/mattn/go-sqlite3) then you can avoid creating
-DatastoreSegments by hand by using an integration package:
-
-* [_integrations/nrpq](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrpq)
-* [_integrations/nrmysql](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrmysql)
-* [_integrations/nrsqlite3](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrsqlite3)
-
-### External Segments
-
-External segments appear in the transaction "Breakdown table" and in the
-"External services" page. Version 1.11.0 of the Go Agent adds support for
-cross-application tracing (CAT), which will result in external segments also
-appearing in the "Service maps" page and being linked in transaction traces when
-both sides of the request have traces. Version 2.1.0 of the Go Agent adds
-support for distributed tracing, which lets you see the path a request takes as
-it travels through distributed APM apps.
-
-* [More info on External Services page](https://docs.newrelic.com/docs/apm/applications-menu/monitoring/external-services-page)
-* [More info on Cross-Application Tracing](https://docs.newrelic.com/docs/apm/transactions/cross-application-traces/introduction-cross-application-traces)
-* [More info on Distributed Tracing](https://docs.newrelic.com/docs/apm/distributed-tracing/getting-started/introduction-distributed-tracing)
-
-External segments are instrumented using `ExternalSegment`. There are three
-ways to use this functionality:
-
-1. Using `StartExternalSegment` to create an `ExternalSegment` before the
- request is sent, and then calling `ExternalSegment.End` when the external
- request is complete.
-
- For CAT support to operate, an `http.Request` must be provided to
- `StartExternalSegment`, and the `ExternalSegment.Response` field must be set
- before `ExternalSegment.End` is called or deferred.
-
- For example:
-
- ```go
- func external(txn newrelic.Transaction, req *http.Request) (*http.Response, error) {
- s := newrelic.StartExternalSegment(txn, req)
- response, err := http.DefaultClient.Do(req)
- s.Response = response
- s.End()
- return response, err
- }
- ```
-
- If the transaction is `nil` then `StartExternalSegment` will look for a
- transaction in the request's context using
- [FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext).
-
-2. Using `NewRoundTripper` to get a
- [`http.RoundTripper`](https://golang.org/pkg/net/http/#RoundTripper) that
- will automatically instrument all requests made via
- [`http.Client`](https://golang.org/pkg/net/http/#Client) instances that use
- that round tripper as their `Transport`. This option results in CAT support,
- provided the Go Agent is version 1.11.0, and in distributed tracing support,
- provided the Go Agent is version 2.1.0. `NewRoundTripper` can be called
- with a `nil` or non-`nil` transaction: If the transaction is `nil`, the
- round tripper will look for a transaction in the request's context
- using [FromContext](https://godoc.org/github.com/newrelic/go-agent#FromContext).
- This pattern is **strongly** recommended, since it allows the round tripper
- to be used in a client shared between multiple transactions.
-
- For example:
-
- ```go
- client := &http.Client{}
- client.Transport = newrelic.NewRoundTripper(nil, client.Transport)
- request, _ := http.NewRequest("GET", "http://example.com", nil)
- request = newrelic.RequestWithTransactionContext(request, txn)
- resp, err := client.Do(request)
- ```
-
- If transaction is non-`nil`, the round tripper returned **must** only be
- used in the same goroutine as the transaction.
-
-3. Directly creating an `ExternalSegment` via a struct literal with an explicit
- `URL` or `Request`, and then calling `ExternalSegment.End`. This option does
- not support CAT, and may be removed or changed in a future major version of
- the Go Agent. As a result, we suggest using one of the other options above
- wherever possible.
-
- For example:
-
- ```go
- func external(txn newrelic.Transaction, url string) (*http.Response, error) {
- es := newrelic.ExternalSegment{
- StartTime: newrelic.StartSegmentNow(txn),
- URL: url,
- }
- defer es.End()
-
- return http.Get(url)
- }
- ```
-
-## Attributes
-
-Attributes add context to errors and allow you to filter performance data
-in Insights.
-
-You may add them using the `Transaction.AddAttribute` method.
-
-```go
-txn.AddAttribute("key", "value")
-txn.AddAttribute("product", "widget")
-txn.AddAttribute("price", 19.99)
-txn.AddAttribute("importantCustomer", true)
-```
-
-* [More info on Custom Attributes](https://docs.newrelic.com/docs/insights/new-relic-insights/decorating-events/insights-custom-attributes)
-
-Some attributes are recorded automatically. These are called agent attributes.
-They are listed here:
-
-* [attributes.go](attributes.go)
-
-To disable one of these agents attributes, `AttributeResponseCode` for
-example, modify the config like this:
-
-```go
-config.Attributes.Exclude = append(config.Attributes.Exclude, newrelic.AttributeResponseCode)
-```
-
-* [More info on Agent Attributes](https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-metrics/agent-attributes)
-
-## Tracing
-
-New Relic's [distributed
-tracing](https://docs.newrelic.com/docs/apm/distributed-tracing/getting-started/introduction-distributed-tracing)
-is the next generation of the previous cross-application tracing feature. Compared to
-cross-application tracing, distributed tracing gives more detail about cross-service activity and provides more
-complete end-to-end visibility. This section discusses distributed tracing and cross-application tracing in turn.
-
-### Distributed Tracing
-
-New Relic's [distributed
-tracing](https://docs.newrelic.com/docs/apm/distributed-tracing/getting-started/introduction-distributed-tracing)
-feature lets you see the path that a request takes as it travels through distributed APM
-apps, which is vital for applications implementing a service-oriented or
-microservices architecture. Support for distributed tracing was added in
-version 2.1.0 of the Go Agent.
-
-The config's `DistributedTracer.Enabled` field has to be set. When true, the
-agent will add distributed tracing headers in outbound requests, and scan
-incoming requests for distributed tracing headers. Distributed tracing will
-override cross-application tracing.
-
-```go
-config.DistributedTracer.Enabled = true
-```
-
-### Cross-Application Tracing
-
-New Relic's
-[cross-application tracing](https://docs.newrelic.com/docs/apm/transactions/cross-application-traces/introduction-cross-application-traces)
-feature, or CAT for short, links transactions between applications in APM to
-help identify performance problems within your service-oriented architecture.
-Support for CAT was added in version 1.11.0 of the Go Agent.
-
-As CAT uses HTTP headers to track requests across applications, the Go Agent
-needs to be able to access and modify request and response headers both for
-incoming and outgoing requests.
-
-### Tracing Instrumentation
-
-Both distributed tracing and cross-application tracing work by propagating
-[header information](https://docs.newrelic.com/docs/apm/distributed-tracing/getting-started/how-new-relic-distributed-tracing-works#headers)
-from service to service in a request path. In many scenarios, the Go Agent offers tracing instrumentation
-out-of-the-box, for both distributed tracing and cross-application tracing. For other scenarios customers may implement
-distributed tracing based on the examples provided in this guide.
-
-#### Getting Tracing Instrumentation Out-of-the-Box
-
-The Go Agent automatically creates and propagates tracing header information
-for each of the following scenarios:
-
-1. Using `WrapHandle` or `WrapHandleFunc` to instrument a server that
- uses [`http.ServeMux`](https://golang.org/pkg/net/http/#ServeMux)
- ([Example](examples/server/main.go)).
-
-2. Using either of the Go Agent's [Gin](_integrations/nrgin/v1) or
- [Gorilla](_integrations/nrgorilla/v1) integration
- ([Gin Example](_integrations/nrgin/v1/example/main.go), [Gorilla Example](_integrations/nrgorilla/v1/example/main.go)).
-.
-
-3. Using another framework or [`http.Server`](https://golang.org/pkg/net/http/#Server) while ensuring that:
-
- 1. All calls to `StartTransaction` include the response writer and
- request, and
- 2. `Transaction.WriteHeader` is used instead of calling `WriteHeader`
- directly on the response writer, as described in the
- [transactions section of this guide](#transactions)
- ([Example](examples/server-http/main.go)).
-
-4. Using `NewRoundTripper`, as described in the
- [external segments section of this guide](#external-segments)
- ([Example](examples/client-round-tripper/main.go)).
-
-5. Using the call `StartExternalSegment` and providing an `http.Request`, as
- described in the [external segments section of this guide](#external-segments)
- ([Example](examples/client/main.go)).
-
-#### Manually Implementing Distributed Tracing
-
-Consider [manual instrumentation](https://docs.newrelic.com/docs/apm/distributed-tracing/enable-configure/enable-distributed-tracing#agent-apis)
-for services not instrumented automatically by the Go Agent. In such scenarios, the
-calling service has to generate a distributed trace payload:
-
-```go
-p := callingTxn.CreateDistributedTracePayload()
-```
-
-This payload has to be added to the call to the destination service, which in turn
-invokes the call for accepting the payload:
-
-```go
-calledTxn.AcceptDistributedTracePayload(newrelic.TransportOther, p)
-```
-
-A complete example can be found
-[here](examples/custom-instrumentation/main.go).
-
-
-## Custom Metrics
-
-* [More info on Custom Metrics](https://docs.newrelic.com/docs/agents/go-agent/instrumentation/create-custom-metrics-go)
-
-You may [create custom metrics](https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-data/collect-custom-metrics)
-via the `RecordCustomMetric` method.
-
-```go
-app.RecordCustomMetric(
- "CustomMetricName", // Name of your metric
- 132, // Value
-)
-```
-
-**Note:** The Go Agent will automatically prepend the metric name you pass to
-`RecordCustomMetric` (`"CustomMetricName"` above) with the string `Custom/`.
-This means the above code would produce a metric named
-`Custom/CustomMetricName`. You'll also want to read over the
-[Naming Transactions and Metrics](#naming-transactions-and-metrics) section below for
-advice on coming up with appropriate metric names.
-
-## Custom Events
-
-You may track arbitrary events using custom Insights events.
-
-```go
-app.RecordCustomEvent("MyEventType", map[string]interface{}{
- "myString": "hello",
- "myFloat": 0.603,
- "myInt": 123,
- "myBool": true,
-})
-```
-
-## Request Queuing
-
-If you are running a load balancer or reverse web proxy then you may configure
-it to add a `X-Queue-Start` header with a Unix timestamp. This will create a
-band on the application overview chart showing queue time.
-
-* [More info on Request Queuing](https://docs.newrelic.com/docs/apm/applications-menu/features/request-queuing-tracking-front-end-time)
-
-## Error Reporting
-
-The Go Agent captures errors in three different ways:
-
-1. [the Transaction.NoticeError method](#noticeerror)
-2. [panics recovered in defer Transaction.End](#panics)
-3. [error response status codes recorded with Transaction.WriteHeader](#error-response-codes)
-
-### NoticeError
-
-You may track errors using the `Transaction.NoticeError` method. The easiest
-way to get started with `NoticeError` is to use errors based on
-[Go's standard error interface](https://blog.golang.org/error-handling-and-go).
-
-```go
-txn.NoticeError(errors.New("my error message"))
-```
-
-`NoticeError` will work with *any* sort of object that implements Go's standard
-error type interface -- not just `errorStrings` created via `errors.New`.
-
-If you're interested in sending more than an error *message* to New Relic, the
-Go Agent also offers a `newrelic.Error` struct.
-
-```go
-txn.NoticeError(newrelic.Error{
- Message: "my error message",
- Class: "IdentifierForError",
- Attributes: map[string]interface{}{
- "important_number": 97232,
- "relevant_string": "zap",
- },
-})
-```
-
-Using the `newrelic.Error` struct requires you to manually marshal your error
-data into the `Message`, `Class`, and `Attributes` fields. However, there's two
-**advantages** to using the `newrelic.Error` struct.
-
-First, by setting an error `Class`, New Relic will be able to aggregate errors
-in the *Error Analytics* section of APM. Second, the `Attributes` field allows
-you to send through key/value pairs with additional error debugging information
-(also exposed in the *Error Analytics* section of APM).
-
-### Advanced NoticeError Use
-
-You're not limited to using Go's built-in error type or the provided
-`newrelic.Error` struct. The Go Agent provides three error interfaces
-
-```go
-type StackTracer interface {
- StackTrace() []uintptr
-}
-
-type ErrorClasser interface {
- ErrorClass() string
-}
-
-type ErrorAttributer interface {
- ErrorAttributes() map[string]interface{}
-}
-```
-
-If you implement any of these on your own error structs, the `txn.NoticeError`
-method will recognize these methods and use their return values to provide error
-information.
-
-For example, you could implement a custom error struct named `MyErrorWithClass`
-
-```go
-type MyErrorWithClass struct {
-
-}
-```
-
-Then, you could implement both an `Error` method (per Go's standard `error`
-interface) and an `ErrorClass` method (per the Go Agent `ErrorClasser`
-interface) for this struct.
-
-```go
-func (e MyErrorWithClass) Error() string { return "A hard coded error message" }
-
-// ErrorClass implements the ErrorClasser interface.
-func (e MyErrorWithClass) ErrorClass() string { return "MyErrorClassForAggregation" }
-```
-
-Finally, you'd use your new error by creating a new instance of your struct and
-passing it to the `NoticeError` method
-
-```go
-txn.NoticeError(MyErrorWithClass{})
-```
-
-While this is an oversimplified example, these interfaces give you a great deal
-of control over what error information is available for your application.
-
-### Panics
-
-When the Transaction is ended using `defer`, the Transaction will recover any
-panic that occurs, record it as an error, and re-throw it. As a result, panics
-may appear to be originating from `Transaction.End`.
-
-```go
-func unstableTask(app newrelic.Application) {
- txn := app.StartTransaction("unstableTask", nil, nil)
- defer txn.End()
-
- // This panic will be recorded as an error.
- panic("something went wrong")
-}
-```
-
-### Error Response Codes
-
-Since the
-[Transaction](https://godoc.org/github.com/newrelic/go-agent#Transaction)
-implements
-[http.ResponseWriter](https://golang.org/pkg/net/http/#ResponseWriter), you can
-use `Transaction.WriteHeader` to record the response status code. The
-transaction will record an error if the status code is above 400 or below 100
-and not in the ignored status codes configuration list. The ignored status
-codes list is configured by the `Config.ErrorCollector.IgnoreStatusCodes` field
-or within the New Relic UI if your application has server side configuration
-enabled.
-
-As a result, using `Transaction.NoticeError` in situations where your code is
-returning an erroneous status code may result in redundant errors.
-`NoticeError` is not affected by the ignored status codes configuration list.
-
-## Naming Transactions and Metrics
-
-You'll want to think carefully about how you name your transactions and custom
-metrics. If your program creates too many unique names, you may end up with a
-[Metric Grouping Issue (or MGI)](https://docs.newrelic.com/docs/agents/manage-apm-agents/troubleshooting/metric-grouping-issues).
-
-MGIs occur when the granularity of names is too fine, resulting in hundreds or
-thousands of uniquely identified metrics and transactions. One common cause of
-MGIs is relying on the full URL name for metric naming in web transactions. A
-few major code paths may generate many different full URL paths to unique
-documents, articles, page, etc. If the unique element of the URL path is
-included in the metric name, each of these common paths will have its own unique
-metric name.
-
-## Browser
-
-To enable support for
-[New Relic Browser](https://docs.newrelic.com/docs/browser), your HTML pages
-must include a JavaScript snippet that will load the Browser agent and
-configure it with the correct application name. This snippet is available via
-the `Transaction.BrowserTimingHeader` method. Include the byte slice returned
-by `Transaction.BrowserTimingHeader().WithTags()` as early as possible in the
-`` section of your HTML after any ` ` tags.
-
-```go
-func indexHandler(w http.ResponseWriter, req *http.Request) {
- io.WriteString(w, "")
- // The New Relic browser javascript should be placed as high in the
- // HTML as possible. We suggest including it immediately after the
- // opening tag and any tags.
- if txn := FromContext(req.Context()); nil != txn {
- hdr, err := txn.BrowserTimingHeader()
- if nil != err {
- log.Printf("unable to create browser timing header: %v", err)
- }
- // BrowserTimingHeader() will always return a header whose methods can
- // be safely called.
- if js := hdr.WithTags(); js != nil {
- w.Write(js)
- }
- }
- io.WriteString(w, "browser header page")
-}
-```
-
-
-## For More Help
-
-There's a variety of places online to learn more about the Go Agent.
-
-[The New Relic docs site](https://docs.newrelic.com/docs/agents/go-agent/get-started/introduction-new-relic-go)
-contains a number of useful code samples and more context about how to use the Go Agent.
-
-[New Relic's discussion forums](https://discuss.newrelic.com) have a dedicated
-public forum [for the Go Agent](https://discuss.newrelic.com/c/support-products-agents/go-agent).
-
-When in doubt, [the New Relic support site](https://support.newrelic.com/) is
-the best place to get started troubleshooting an agent issue.
diff --git a/vendor/github.com/newrelic/go-agent/LICENSE.txt b/vendor/github.com/newrelic/go-agent/LICENSE.txt
deleted file mode 100644
index aaa718c66bd..00000000000
--- a/vendor/github.com/newrelic/go-agent/LICENSE.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-Copyright (c) 2008-2019 New Relic, Inc. All rights reserved.
-
-Certain inventions disclosed in this file may be claimed within
-patents owned or patent applications filed by New Relic, Inc. or third
-parties.
-
-Subject to the terms of this notice, New Relic grants you a
-nonexclusive, nontransferable license, without the right to
-sublicense, to (a) install and execute one copy of these files on any
-number of workstations owned or controlled by you and (b) distribute
-verbatim copies of these files to third parties. As a condition to the
-foregoing grant, you must provide this notice along with each copy you
-distribute and you must not remove, alter, or obscure this notice. All
-other use, reproduction, modification, distribution, or other
-exploitation of these files is strictly prohibited, except as may be set
-forth in a separate written license agreement between you and New
-Relic. The terms of any such license agreement will control over this
-notice. The license stated above will be automatically terminated and
-revoked if you exceed its scope or violate any of the terms of this
-notice.
-
-This License does not grant permission to use the trade names,
-trademarks, service marks, or product names of New Relic, except as
-required for reasonable and customary use in describing the origin of
-this file and reproducing the content of this notice. You may not
-mark or brand this file with any trade name, trademarks, service
-marks, or product names other than the original brand (if any)
-provided by New Relic.
-
-Unless otherwise expressly agreed by New Relic in a separate written
-license agreement, these files are provided AS IS, WITHOUT WARRANTY OF
-ANY KIND, including without any implied warranties of MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE, or NON-INFRINGEMENT. As a
-condition to your use of these files, you are solely responsible for
-such use. New Relic will have no liability to you for direct,
-indirect, consequential, incidental, special, or punitive damages or
-for lost profits or data.
diff --git a/vendor/github.com/newrelic/go-agent/README.md b/vendor/github.com/newrelic/go-agent/README.md
deleted file mode 100644
index 479eb554d39..00000000000
--- a/vendor/github.com/newrelic/go-agent/README.md
+++ /dev/null
@@ -1,90 +0,0 @@
-# New Relic Go Agent [![GoDoc](https://godoc.org/github.com/newrelic/go-agent?status.svg)](https://godoc.org/github.com/newrelic/go-agent)
-
-## Description
-
-The New Relic Go Agent allows you to monitor your Go applications with New
-Relic. It helps you track transactions, outbound requests, database calls, and
-other parts of your Go application's behavior and provides a running overview of
-garbage collection, goroutine activity, and memory use.
-
-All pull requests will be reviewed by the New Relic product team. Any questions or issues should be directed to our [support
-site](http://support.newrelic.com/) or our [community
-forum](https://discuss.newrelic.com).
-
-## Requirements
-
-Go 1.3+ is required, due to the use of http.Client's Timeout field.
-
-Linux, OS X, and Windows (Vista, Server 2008 and later) are supported.
-
-## Integrations
-
-The following [_integration packages](https://godoc.org/github.com/newrelic/go-agent/_integrations)
-extend the base [newrelic](https://godoc.org/github.com/newrelic/go-agent) package
-to support the following frameworks and libraries.
-Frameworks and databases which don't have an integration package may still be
-instrumented using the [newrelic](https://godoc.org/github.com/newrelic/go-agent)
-package primitives. Specifically, more information about instrumenting your database using
-these primitives can be found
-[here](https://github.com/newrelic/go-agent/blob/master/GUIDE.md#datastore-segments).
-
-
-
-| Project | Integration Package | |
-| ------------- | ------------- | - |
-| [aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) | [_integrations/nrawssdk/v1](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrawssdk/v1) | Instrument outbound calls made using Go AWS SDK |
-| [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | [_integrations/nrawssdk/v2](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrawssdk/v2) | Instrument outbound calls made using Go AWS SDK v2 |
-| [labstack/echo](https://github.com/labstack/echo) | [_integrations/nrecho](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrecho) | Instrument inbound requests through the Echo framework |
-| [gin-gonic/gin](https://github.com/gin-gonic/gin) | [_integrations/nrgin/v1](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrgin/v1) | Instrument inbound requests through the Gin framework |
-| [gorilla/mux](https://github.com/gorilla/mux) | [_integrations/nrgorilla/v1](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrgorilla/v1) | Instrument inbound requests through the Gorilla framework |
-| [julienschmidt/httprouter](https://github.com/julienschmidt/httprouter) | [_integrations/nrhttprouter](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrhttprouter) | Instrument inbound requests through the HttpRouter framework |
-| [aws/aws-lambda-go](https://github.com/aws/aws-lambda-go) | [_integrations/nrlambda](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlambda) | Instrument AWS Lambda applications |
-| [sirupsen/logrus](https://github.com/sirupsen/logrus) | [_integrations/nrlogrus](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlogrus) | Send agent log messages to Logrus |
-| [mgutz/logxi](https://github.com/mgutz/logxi) | [_integrations/nrlogxi/v1](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlogxi/v1) | Send agent log messages to Logxi |
-| [uber-go/zap](https://github.com/uber-go/zap) | [_integrations/nrzap](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrzap) | Send agent log messages to Zap |
-| [pkg/errors](https://github.com/pkg/errors) | [_integrations/nrpkgerrors](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrpkgerrors) | Wrap pkg/errors errors to improve stack traces and error class information |
-| [go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) | [_integrations/nrmysql](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrmysql) | Instrument MySQL driver |
-| [lib/pq](https://github.com/lib/pq) | [_integrations/nrpq](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrpq) | Instrument PostgreSQL driver |
-| [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) | [_integrations/nrsqlite3](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrsqlite3) | Instrument SQLite driver |
-| [google.golang.org/grpc](https://github.com/grpc/grpc-go) | [_integrations/nrgrpc](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrgrpc) | Instrument gRPC servers and clients |
-| [micro/go-micro](https://github.com/micro/go-micro) | [_integrations/nrmicro](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrmicro) | Instrument servers, clients, publishers, and subscribers through the Micro framework |
-| [nats-io/nats.go](https://github.com/nats-io/nats.go) | [_integrations/nrnats](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrnats) | Instrument publishers and subscribers using the NATS client |
-| [nats-io/stan.go](https://github.com/nats-io/stan.go) | [_integrations/nrstan](https://godoc.org/github.com/newrelic/go-agent/_integrations/nrstan) | Instrument publishers and subscribers using the NATS streaming client |
-
-
-These integration packages must be imported along
-with the [newrelic](https://godoc.org/github.com/newrelic/go-agent) package, as shown in this
-[nrgin example](https://github.com/newrelic/go-agent/blob/master/_integrations/nrgin/v1/example/main.go).
-
-## Getting Started
-
-Follow the steps in [GETTING_STARTED.md](GETTING_STARTED.md) to instrument your
-application.
-
-## Runnable Example
-
-[examples/server/main.go](./examples/server/main.go) is an example that will
-appear as "Example App" in your New Relic applications list. To run it:
-
-```
-env NEW_RELIC_LICENSE_KEY=__YOUR_NEW_RELIC_LICENSE_KEY__LICENSE__ \
- go run examples/server/main.go
-```
-
-Some endpoints exposed are [http://localhost:8000/](http://localhost:8000/)
-and [http://localhost:8000/notice_error](http://localhost:8000/notice_error)
-
-## Support
-
-You can find more detailed documentation [in the guide](GUIDE.md) and on
-[the New Relic Documentation site](https://docs.newrelic.com/docs/agents/go-agent).
-
-If you can't find what you're looking for there, reach out to us on our [support
-site](http://support.newrelic.com/) or our [community
-forum](https://discuss.newrelic.com) and we'll be happy to help you.
-
-Find a bug? Contact us via [support.newrelic.com](http://support.newrelic.com/),
-or email support@newrelic.com.
diff --git a/vendor/github.com/newrelic/go-agent/THIRD_PARTY_NOTICES.md b/vendor/github.com/newrelic/go-agent/THIRD_PARTY_NOTICES.md
deleted file mode 100644
index 3161d9b742b..00000000000
--- a/vendor/github.com/newrelic/go-agent/THIRD_PARTY_NOTICES.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Third Party Notices
-
-The New Relic Go Agent uses source code from third party libraries which carry
-their own copyright notices and license terms. These notices are provided
-below.
-
-In the event that a required notice is missing or incorrect, please notify us
-either by [opening an issue](https://github.com/newrelic/go-agent/issues/new),
-or by e-mailing [open-source@newrelic.com](mailto:open-source@newrelic.com).
-
-For any licenses that require the disclosure of source code, the source code
-can be found at https://github.com/newrelic/go-agent/.
-
-## Contents
-
-* [Go](#go)
-
-## Go
-
-This product includes source derived from the
-[Go programming language](https://golang.org/), distributed under the
-[Go license](https://golang.org/LICENSE):
-
-```
-Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-```
diff --git a/vendor/github.com/newrelic/go-agent/_integrations/nrgorilla/v1/nrgorilla.go b/vendor/github.com/newrelic/go-agent/_integrations/nrgorilla/v1/nrgorilla.go
deleted file mode 100644
index e63aa306a13..00000000000
--- a/vendor/github.com/newrelic/go-agent/_integrations/nrgorilla/v1/nrgorilla.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Package nrgorilla instruments https://github.com/gorilla/mux applications.
-//
-// Use this package to instrument inbound requests handled by a gorilla
-// mux.Router. Call nrgorilla.InstrumentRoutes on your gorilla mux.Router
-// after your routes have been added to it.
-//
-// Example: https://github.com/newrelic/go-agent/tree/master/_integrations/nrgorilla/v1/example/main.go
-package nrgorilla
-
-import (
- "net/http"
-
- "github.com/gorilla/mux"
- newrelic "github.com/newrelic/go-agent"
- "github.com/newrelic/go-agent/internal"
-)
-
-func init() { internal.TrackUsage("integration", "framework", "gorilla", "v1") }
-
-type instrumentedHandler struct {
- name string
- app newrelic.Application
- orig http.Handler
-}
-
-func (h instrumentedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- txn := h.app.StartTransaction(h.name, w, r)
- defer txn.End()
-
- r = newrelic.RequestWithTransactionContext(r, txn)
-
- h.orig.ServeHTTP(txn, r)
-}
-
-func instrumentRoute(h http.Handler, app newrelic.Application, name string) http.Handler {
- if _, ok := h.(instrumentedHandler); ok {
- return h
- }
- return instrumentedHandler{
- name: name,
- orig: h,
- app: app,
- }
-}
-
-func routeName(route *mux.Route) string {
- if nil == route {
- return ""
- }
- if n := route.GetName(); n != "" {
- return n
- }
- if n, _ := route.GetPathTemplate(); n != "" {
- return n
- }
- n, _ := route.GetHostTemplate()
- return n
-}
-
-// InstrumentRoutes instruments requests through the provided mux.Router. Use
-// this after the routes have been added to the router.
-func InstrumentRoutes(r *mux.Router, app newrelic.Application) *mux.Router {
- if app != nil {
- r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
- h := instrumentRoute(route.GetHandler(), app, routeName(route))
- route.Handler(h)
- return nil
- })
- if nil != r.NotFoundHandler {
- r.NotFoundHandler = instrumentRoute(r.NotFoundHandler, app, "NotFoundHandler")
- }
- }
- return r
-}
diff --git a/vendor/github.com/newrelic/go-agent/app_run.go b/vendor/github.com/newrelic/go-agent/app_run.go
deleted file mode 100644
index 977fa7b6324..00000000000
--- a/vendor/github.com/newrelic/go-agent/app_run.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package newrelic
-
-import (
- "encoding/json"
- "strings"
- "time"
-
- "github.com/newrelic/go-agent/internal"
-)
-
-// appRun contains information regarding a single connection session with the
-// collector. It is immutable after creation at application connect.
-type appRun struct {
- Reply *internal.ConnectReply
-
- // AttributeConfig is calculated on every connect since it depends on
- // the security policies.
- AttributeConfig *internal.AttributeConfig
- Config Config
-
- // firstAppName is the value of Config.AppName up to the first semicolon.
- firstAppName string
-}
-
-func newAppRun(config Config, reply *internal.ConnectReply) *appRun {
- convertConfig := func(c AttributeDestinationConfig) internal.AttributeDestinationConfig {
- return internal.AttributeDestinationConfig{
- Enabled: c.Enabled,
- Include: c.Include,
- Exclude: c.Exclude,
- }
- }
- run := &appRun{
- Reply: reply,
- AttributeConfig: internal.CreateAttributeConfig(internal.AttributeConfigInput{
- Attributes: convertConfig(config.Attributes),
- ErrorCollector: convertConfig(config.ErrorCollector.Attributes),
- TransactionEvents: convertConfig(config.TransactionEvents.Attributes),
- TransactionTracer: convertConfig(config.TransactionTracer.Attributes),
- BrowserMonitoring: convertConfig(config.BrowserMonitoring.Attributes),
- SpanEvents: convertConfig(config.SpanEvents.Attributes),
- TraceSegments: convertConfig(config.TransactionTracer.Segments.Attributes),
- }, reply.SecurityPolicies.AttributesInclude.Enabled()),
- Config: config,
- }
-
- // Overwrite local settings with any server-side-config settings
- // present. NOTE! This requires that the Config provided to this
- // function is a value and not a pointer: We do not want to change the
- // input Config with values particular to this connection.
-
- if v := run.Reply.ServerSideConfig.TransactionTracerEnabled; nil != v {
- run.Config.TransactionTracer.Enabled = *v
- }
- if v := run.Reply.ServerSideConfig.ErrorCollectorEnabled; nil != v {
- run.Config.ErrorCollector.Enabled = *v
- }
- if v := run.Reply.ServerSideConfig.CrossApplicationTracerEnabled; nil != v {
- run.Config.CrossApplicationTracer.Enabled = *v
- }
- if v := run.Reply.ServerSideConfig.TransactionTracerThreshold; nil != v {
- switch val := v.(type) {
- case float64:
- run.Config.TransactionTracer.Threshold.IsApdexFailing = false
- run.Config.TransactionTracer.Threshold.Duration = internal.FloatSecondsToDuration(val)
- case string:
- if val == "apdex_f" {
- run.Config.TransactionTracer.Threshold.IsApdexFailing = true
- }
- }
- }
- if v := run.Reply.ServerSideConfig.TransactionTracerStackTraceThreshold; nil != v {
- run.Config.TransactionTracer.StackTraceThreshold = internal.FloatSecondsToDuration(*v)
- }
- if v := run.Reply.ServerSideConfig.ErrorCollectorIgnoreStatusCodes; nil != v {
- run.Config.ErrorCollector.IgnoreStatusCodes = v
- }
-
- if !run.Reply.CollectErrorEvents {
- run.Config.ErrorCollector.CaptureEvents = false
- }
- if !run.Reply.CollectAnalyticsEvents {
- run.Config.TransactionEvents.Enabled = false
- }
- if !run.Reply.CollectTraces {
- run.Config.TransactionTracer.Enabled = false
- run.Config.DatastoreTracer.SlowQuery.Enabled = false
- }
- if !run.Reply.CollectSpanEvents {
- run.Config.SpanEvents.Enabled = false
- }
-
- // Distributed tracing takes priority over cross-app-tracing per:
- // https://source.datanerd.us/agents/agent-specs/blob/master/Distributed-Tracing.md#distributed-trace-payload
- if run.Config.DistributedTracer.Enabled {
- run.Config.CrossApplicationTracer.Enabled = false
- }
-
- // Cache the first application name set on the config
- run.firstAppName = strings.SplitN(config.AppName, ";", 2)[0]
-
- if "" != run.Reply.RunID {
- js, _ := json.Marshal(settings(run.Config))
- run.Config.Logger.Debug("final configuration", map[string]interface{}{
- "config": internal.JSONString(js),
- })
- }
-
- return run
-}
-
-const (
- // https://source.datanerd.us/agents/agent-specs/blob/master/Lambda.md#distributed-tracing
- serverlessDefaultPrimaryAppID = "Unknown"
-)
-
-const (
- // https://source.datanerd.us/agents/agent-specs/blob/master/Lambda.md#adaptive-sampling
- serverlessSamplerPeriod = 60 * time.Second
- serverlessSamplerTarget = 10
-)
-
-func newServerlessConnectReply(config Config) *internal.ConnectReply {
- reply := internal.ConnectReplyDefaults()
-
- reply.ApdexThresholdSeconds = config.ServerlessMode.ApdexThreshold.Seconds()
-
- reply.AccountID = config.ServerlessMode.AccountID
- reply.TrustedAccountKey = config.ServerlessMode.TrustedAccountKey
- reply.PrimaryAppID = config.ServerlessMode.PrimaryAppID
-
- if "" == reply.TrustedAccountKey {
- // The trust key does not need to be provided by customers whose
- // account ID is the same as the trust key.
- reply.TrustedAccountKey = reply.AccountID
- }
-
- if "" == reply.PrimaryAppID {
- reply.PrimaryAppID = serverlessDefaultPrimaryAppID
- }
-
- reply.AdaptiveSampler = internal.NewAdaptiveSampler(serverlessSamplerPeriod,
- serverlessSamplerTarget, time.Now())
-
- return reply
-}
-
-func (run *appRun) responseCodeIsError(code int) bool {
- // Response codes below 100 are allowed to be errors to support gRPC.
- if code < 400 && code >= 100 {
- return false
- }
- for _, ignoreCode := range run.Config.ErrorCollector.IgnoreStatusCodes {
- if code == ignoreCode {
- return false
- }
- }
- return true
-}
-
-func (run *appRun) txnTraceThreshold(apdexThreshold time.Duration) time.Duration {
- if run.Config.TransactionTracer.Threshold.IsApdexFailing {
- return internal.ApdexFailingThreshold(apdexThreshold)
- }
- return run.Config.TransactionTracer.Threshold.Duration
-}
diff --git a/vendor/github.com/newrelic/go-agent/application.go b/vendor/github.com/newrelic/go-agent/application.go
deleted file mode 100644
index 61702adf004..00000000000
--- a/vendor/github.com/newrelic/go-agent/application.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package newrelic
-
-import (
- "net/http"
- "time"
-)
-
-// Application represents your application.
-type Application interface {
- // StartTransaction begins a Transaction.
- // * Transaction.NewGoroutine() must be used to pass the Transaction
- // between goroutines.
- // * This method never returns nil.
- // * The Transaction is considered a web transaction if an http.Request
- // is provided.
- // * The transaction returned implements the http.ResponseWriter
- // interface. Provide your ResponseWriter as a parameter and
- // then use the Transaction in its place to instrument the response
- // code and response headers.
- StartTransaction(name string, w http.ResponseWriter, r *http.Request) Transaction
-
- // RecordCustomEvent adds a custom event.
- //
- // eventType must consist of alphanumeric characters, underscores, and
- // colons, and must contain fewer than 255 bytes.
- //
- // Each value in the params map must be a number, string, or boolean.
- // Keys must be less than 255 bytes. The params map may not contain
- // more than 64 attributes. For more information, and a set of
- // restricted keywords, see:
- //
- // https://docs.newrelic.com/docs/insights/new-relic-insights/adding-querying-data/inserting-custom-events-new-relic-apm-agents
- //
- // An error is returned if event type or params is invalid.
- RecordCustomEvent(eventType string, params map[string]interface{}) error
-
- // RecordCustomMetric records a custom metric. The metric name you
- // provide will be prefixed by "Custom/". Custom metrics are not
- // currently supported in serverless mode.
- //
- // https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-data/collect-custom-metrics
- RecordCustomMetric(name string, value float64) error
-
- // WaitForConnection blocks until the application is connected, is
- // incapable of being connected, or the timeout has been reached. This
- // method is useful for short-lived processes since the application will
- // not gather data until it is connected. nil is returned if the
- // application is connected successfully.
- WaitForConnection(timeout time.Duration) error
-
- // Shutdown flushes data to New Relic's servers and stops all
- // agent-related goroutines managing this application. After Shutdown
- // is called, The application is disabled and will never collect data
- // again. This method blocks until all final data is sent to New Relic
- // or the timeout has elapsed. Increase the timeout and check debug
- // logs if you aren't seeing data.
- Shutdown(timeout time.Duration)
-}
-
-// NewApplication creates an Application and spawns goroutines to manage the
-// aggregation and harvesting of data. On success, a non-nil Application and a
-// nil error are returned. On failure, a nil Application and a non-nil error
-// are returned. Applications do not share global state, therefore it is safe
-// to create multiple applications.
-func NewApplication(c Config) (Application, error) {
- return newApp(c)
-}
diff --git a/vendor/github.com/newrelic/go-agent/attributes.go b/vendor/github.com/newrelic/go-agent/attributes.go
deleted file mode 100644
index a5fab6d73b6..00000000000
--- a/vendor/github.com/newrelic/go-agent/attributes.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package newrelic
-
-// This file contains the names of the automatically captured attributes.
-// Attributes are key value pairs attached to transaction events, error events,
-// and traced errors. You may add your own attributes using the
-// Transaction.AddAttribute method (see transaction.go).
-//
-// These attribute names are exposed here to facilitate configuration.
-//
-// For more information, see:
-// https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-metrics/agent-attributes
-
-// Attributes destined for Transaction Events, Errors, and Transaction Traces:
-const (
- // AttributeResponseCode is the response status code for a web request.
- AttributeResponseCode = "httpResponseCode"
- // AttributeRequestMethod is the request's method.
- AttributeRequestMethod = "request.method"
- // AttributeRequestAccept is the request's "Accept" header.
- AttributeRequestAccept = "request.headers.accept"
- // AttributeRequestContentType is the request's "Content-Type" header.
- AttributeRequestContentType = "request.headers.contentType"
- // AttributeRequestContentLength is the request's "Content-Length" header.
- AttributeRequestContentLength = "request.headers.contentLength"
- // AttributeRequestHost is the request's "Host" header.
- AttributeRequestHost = "request.headers.host"
- // AttributeRequestURI is the request's URL without query parameters,
- // fragment, user, or password.
- AttributeRequestURI = "request.uri"
- // AttributeResponseContentType is the response "Content-Type" header.
- AttributeResponseContentType = "response.headers.contentType"
- // AttributeResponseContentLength is the response "Content-Length" header.
- AttributeResponseContentLength = "response.headers.contentLength"
- // AttributeHostDisplayName contains the value of Config.HostDisplayName.
- AttributeHostDisplayName = "host.displayName"
-)
-
-// Attributes destined for Errors and Transaction Traces:
-const (
- // AttributeRequestUserAgent is the request's "User-Agent" header.
- AttributeRequestUserAgent = "request.headers.User-Agent"
- // AttributeRequestReferer is the request's "Referer" header. Query
- // string parameters are removed.
- AttributeRequestReferer = "request.headers.referer"
-)
-
-// AWS Lambda specific attributes:
-const (
- AttributeAWSRequestID = "aws.requestId"
- AttributeAWSLambdaARN = "aws.lambda.arn"
- AttributeAWSLambdaColdStart = "aws.lambda.coldStart"
- AttributeAWSLambdaEventSourceARN = "aws.lambda.eventSource.arn"
-)
-
-// Attributes destined for Span Events:
-//
-// To disable the capture of one of these span event attributes, db.statement
-// for example, modify your Config like this:
-//
-// cfg.SpanEvents.Attributes.Exclude = append(cfg.SpanEvents.Attributes.Exclude,
-// newrelic.SpanAttributeDBStatement)
-const (
- SpanAttributeDBStatement = "db.statement"
- SpanAttributeDBInstance = "db.instance"
- SpanAttributeDBCollection = "db.collection"
- SpanAttributePeerAddress = "peer.address"
- SpanAttributePeerHostname = "peer.hostname"
- SpanAttributeHTTPURL = "http.url"
- SpanAttributeHTTPMethod = "http.method"
- SpanAttributeAWSOperation = "aws.operation"
- SpanAttributeAWSRequestID = "aws.requestId"
- SpanAttributeAWSRegion = "aws.region"
-)
diff --git a/vendor/github.com/newrelic/go-agent/browser_header.go b/vendor/github.com/newrelic/go-agent/browser_header.go
deleted file mode 100644
index 0df1d6f22f1..00000000000
--- a/vendor/github.com/newrelic/go-agent/browser_header.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package newrelic
-
-import (
- "encoding/json"
-)
-
-var (
- browserStartTag = []byte(``)
- browserInfoPrefix = []byte(`window.NREUM||(NREUM={});NREUM.info=`)
-)
-
-// browserInfo contains the fields that are marshalled into the Browser agent's
-// info hash.
-//
-// https://newrelic.atlassian.net/wiki/spaces/eng/pages/50299103/BAM+Agent+Auto-Instrumentation
-type browserInfo struct {
- Beacon string `json:"beacon"`
- LicenseKey string `json:"licenseKey"`
- ApplicationID string `json:"applicationID"`
- TransactionName string `json:"transactionName"`
- QueueTimeMillis int64 `json:"queueTime"`
- ApplicationTimeMillis int64 `json:"applicationTime"`
- ObfuscatedAttributes string `json:"atts"`
- ErrorBeacon string `json:"errorBeacon"`
- Agent string `json:"agent"`
-}
-
-// BrowserTimingHeader encapsulates the JavaScript required to enable New
-// Relic's Browser product.
-type BrowserTimingHeader struct {
- agentLoader string
- info browserInfo
-}
-
-func appendSlices(slices ...[]byte) []byte {
- length := 0
- for _, s := range slices {
- length += len(s)
- }
- combined := make([]byte, 0, length)
- for _, s := range slices {
- combined = append(combined, s...)
- }
- return combined
-}
-
-// WithTags returns the browser timing JavaScript which includes the enclosing
-// tags. This method returns nil if the receiver is
-// nil, the feature is disabled, the application is not yet connected, or an
-// error occurs. The byte slice returned is in UTF-8 format.
-func (h *BrowserTimingHeader) WithTags() []byte {
- withoutTags := h.WithoutTags()
- if nil == withoutTags {
- return nil
- }
- return appendSlices(browserStartTag, withoutTags, browserEndTag)
-}
-
-// WithoutTags returns the browser timing JavaScript without any enclosing tags,
-// which may then be embedded within any JavaScript code. This method returns
-// nil if the receiver is nil, the feature is disabled, the application is not
-// yet connected, or an error occurs. The byte slice returned is in UTF-8
-// format.
-func (h *BrowserTimingHeader) WithoutTags() []byte {
- if nil == h {
- return nil
- }
-
- // We could memoise this, but it seems unnecessary, since most users are
- // going to call this zero or one times.
- info, err := json.Marshal(h.info)
- if err != nil {
- // There's no way to log from here, but this also should be unreachable in
- // practice.
- return nil
- }
-
- return appendSlices([]byte(h.agentLoader), browserInfoPrefix, info)
-}
diff --git a/vendor/github.com/newrelic/go-agent/build-script.sh b/vendor/github.com/newrelic/go-agent/build-script.sh
deleted file mode 100644
index 71fd37826d1..00000000000
--- a/vendor/github.com/newrelic/go-agent/build-script.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-set -x
-set -e
-
-LATEST_VERSION="go1.13"
-
-if [ -n "$INTEGRATION" ]; then
- cd $INTEGRATION
- go get -t ./...
-fi
-
-go test -race -benchtime=1ms -bench=. ./...
-go vet ./...
-
-if [[ -n "$(go version | grep $LATEST_VERSION)" ]]; then
- # golint requires a supported version of Go, which in practice is currently 1.9+.
- # See: https://github.com/golang/lint#installation
- # For simplicity, run it on a single Go version.
- go get -u golang.org/x/lint/golint
- golint -set_exit_status ./...
-
- # only run gofmt on a single version as the format changed from 1.10 to
- # 1.11.
- if [ -n "$(gofmt -s -l .)" ]; then
- exit 1
- fi
-fi
diff --git a/vendor/github.com/newrelic/go-agent/config.go b/vendor/github.com/newrelic/go-agent/config.go
deleted file mode 100644
index 170d75daf45..00000000000
--- a/vendor/github.com/newrelic/go-agent/config.go
+++ /dev/null
@@ -1,397 +0,0 @@
-package newrelic
-
-import (
- "errors"
- "fmt"
- "net/http"
- "strings"
- "time"
-)
-
-// Config contains Application and Transaction behavior settings.
-// Use NewConfig to create a Config with proper defaults.
-type Config struct {
- // AppName is used by New Relic to link data across servers.
- //
- // https://docs.newrelic.com/docs/apm/new-relic-apm/installation-configuration/naming-your-application
- AppName string
-
- // License is your New Relic license key.
- //
- // https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/license-key
- License string
-
- // Logger controls go-agent logging. For info level logging to stdout:
- //
- // cfg.Logger = newrelic.NewLogger(os.Stdout)
- //
- // For debug level logging to stdout:
- //
- // cfg.Logger = newrelic.NewDebugLogger(os.Stdout)
- //
- // See https://github.com/newrelic/go-agent/blob/master/GUIDE.md#logging
- // for more examples and logging integrations.
- Logger Logger
-
- // Enabled controls whether the agent will communicate with the New Relic
- // servers and spawn goroutines. Setting this to be false is useful in
- // testing and staging situations.
- Enabled bool
-
- // Labels are key value pairs used to roll up applications into specific
- // categories.
- //
- // https://docs.newrelic.com/docs/using-new-relic/user-interface-functions/organize-your-data/labels-categories-organize-apps-monitors
- Labels map[string]string
-
- // HighSecurity guarantees that certain agent settings can not be made
- // more permissive. This setting must match the corresponding account
- // setting in the New Relic UI.
- //
- // https://docs.newrelic.com/docs/agents/manage-apm-agents/configuration/high-security-mode
- HighSecurity bool
-
- // SecurityPoliciesToken enables security policies if set to a non-empty
- // string. Only set this if security policies have been enabled on your
- // account. This cannot be used in conjunction with HighSecurity.
- //
- // https://docs.newrelic.com/docs/agents/manage-apm-agents/configuration/enable-configurable-security-policies
- SecurityPoliciesToken string
-
- // CustomInsightsEvents controls the behavior of
- // Application.RecordCustomEvent.
- //
- // https://docs.newrelic.com/docs/insights/new-relic-insights/adding-querying-data/inserting-custom-events-new-relic-apm-agents
- CustomInsightsEvents struct {
- // Enabled controls whether RecordCustomEvent will collect
- // custom analytics events. High security mode overrides this
- // setting.
- Enabled bool
- }
-
- // TransactionEvents controls the behavior of transaction analytics
- // events.
- TransactionEvents struct {
- // Enabled controls whether transaction events are captured.
- Enabled bool
- // Attributes controls the attributes included with transaction
- // events.
- Attributes AttributeDestinationConfig
- }
-
- // ErrorCollector controls the capture of errors.
- ErrorCollector struct {
- // Enabled controls whether errors are captured. This setting
- // affects both traced errors and error analytics events.
- Enabled bool
- // CaptureEvents controls whether error analytics events are
- // captured.
- CaptureEvents bool
- // IgnoreStatusCodes controls which http response codes are
- // automatically turned into errors. By default, response codes
- // greater than or equal to 400, with the exception of 404, are
- // turned into errors.
- IgnoreStatusCodes []int
- // Attributes controls the attributes included with errors.
- Attributes AttributeDestinationConfig
- }
-
- // TransactionTracer controls the capture of transaction traces.
- TransactionTracer struct {
- // Enabled controls whether transaction traces are captured.
- Enabled bool
- // Threshold controls whether a transaction trace will be
- // considered for capture. Of the traces exceeding the
- // threshold, the slowest trace every minute is captured.
- Threshold struct {
- // If IsApdexFailing is true then the trace threshold is
- // four times the apdex threshold.
- IsApdexFailing bool
- // If IsApdexFailing is false then this field is the
- // threshold, otherwise it is ignored.
- Duration time.Duration
- }
- // SegmentThreshold is the threshold at which segments will be
- // added to the trace. Lowering this setting may increase
- // overhead. Decrease this duration if your Transaction Traces are
- // missing segments.
- SegmentThreshold time.Duration
- // StackTraceThreshold is the threshold at which segments will
- // be given a stack trace in the transaction trace. Lowering
- // this setting will increase overhead.
- StackTraceThreshold time.Duration
- // Attributes controls the attributes included with transaction
- // traces.
- Attributes AttributeDestinationConfig
- // Segments.Attributes controls the attributes included with
- // each trace segment.
- Segments struct {
- Attributes AttributeDestinationConfig
- }
- }
-
- // BrowserMonitoring contains settings which control the behavior of
- // Transaction.BrowserTimingHeader.
- BrowserMonitoring struct {
- // Enabled controls whether or not the Browser monitoring feature is
- // enabled.
- Enabled bool
- // Attributes controls the attributes included with Browser monitoring.
- // BrowserMonitoring.Attributes.Enabled is false by default, to include
- // attributes in the Browser timing Javascript:
- //
- // cfg.BrowserMonitoring.Attributes.Enabled = true
- Attributes AttributeDestinationConfig
- }
-
- // HostDisplayName gives this server a recognizable name in the New
- // Relic UI. This is an optional setting.
- HostDisplayName string
-
- // Transport customizes communication with the New Relic servers. This may
- // be used to configure a proxy.
- Transport http.RoundTripper
-
- // Utilization controls the detection and gathering of system
- // information.
- Utilization struct {
- // DetectAWS controls whether the Application attempts to detect
- // AWS.
- DetectAWS bool
- // DetectAzure controls whether the Application attempts to detect
- // Azure.
- DetectAzure bool
- // DetectPCF controls whether the Application attempts to detect
- // PCF.
- DetectPCF bool
- // DetectGCP controls whether the Application attempts to detect
- // GCP.
- DetectGCP bool
- // DetectDocker controls whether the Application attempts to
- // detect Docker.
- DetectDocker bool
- // DetectKubernetes controls whether the Application attempts to
- // detect Kubernetes.
- DetectKubernetes bool
-
- // These settings provide system information when custom values
- // are required.
- LogicalProcessors int
- TotalRAMMIB int
- BillingHostname string
- }
-
- // CrossApplicationTracer controls behaviour relating to cross application
- // tracing (CAT), available since Go Agent v0.11. The
- // CrossApplicationTracer and the DistributedTracer cannot be
- // simultaneously enabled.
- //
- // https://docs.newrelic.com/docs/apm/transactions/cross-application-traces/introduction-cross-application-traces
- CrossApplicationTracer struct {
- Enabled bool
- }
-
- // DistributedTracer controls behaviour relating to Distributed Tracing,
- // available since Go Agent v2.1. The DistributedTracer and the
- // CrossApplicationTracer cannot be simultaneously enabled.
- //
- // https://docs.newrelic.com/docs/apm/distributed-tracing/getting-started/introduction-distributed-tracing
- DistributedTracer struct {
- Enabled bool
- }
-
- // SpanEvents controls behavior relating to Span Events. Span Events
- // require that DistributedTracer is enabled.
- SpanEvents struct {
- Enabled bool
- Attributes AttributeDestinationConfig
- }
-
- // DatastoreTracer controls behavior relating to datastore segments.
- DatastoreTracer struct {
- // InstanceReporting controls whether the host and port are collected
- // for datastore segments.
- InstanceReporting struct {
- Enabled bool
- }
- // DatabaseNameReporting controls whether the database name is
- // collected for datastore segments.
- DatabaseNameReporting struct {
- Enabled bool
- }
- QueryParameters struct {
- Enabled bool
- }
- // SlowQuery controls the capture of slow query traces. Slow
- // query traces show you instances of your slowest datastore
- // segments.
- SlowQuery struct {
- Enabled bool
- Threshold time.Duration
- }
- }
-
- // Attributes controls which attributes are enabled and disabled globally.
- // This setting affects all attribute destinations: Transaction Events,
- // Error Events, Transaction Traces and segments, Traced Errors, Span
- // Events, and Browser timing header.
- Attributes AttributeDestinationConfig
-
- // RuntimeSampler controls the collection of runtime statistics like
- // CPU/Memory usage, goroutine count, and GC pauses.
- RuntimeSampler struct {
- // Enabled controls whether runtime statistics are captured.
- Enabled bool
- }
-
- // ServerlessMode contains fields which control behavior when running in
- // AWS Lambda.
- //
- // https://docs.newrelic.com/docs/serverless-function-monitoring/aws-lambda-monitoring/get-started/introduction-new-relic-monitoring-aws-lambda
- ServerlessMode struct {
- // Enabling ServerlessMode will print each transaction's data to
- // stdout. No agent goroutines will be spawned in serverless mode, and
- // no data will be sent directly to the New Relic backend.
- // nrlambda.NewConfig sets Enabled to true.
- Enabled bool
- // ApdexThreshold sets the Apdex threshold when in ServerlessMode. The
- // default is 500 milliseconds. nrlambda.NewConfig populates this
- // field using the NEW_RELIC_APDEX_T environment variable.
- //
- // https://docs.newrelic.com/docs/apm/new-relic-apm/apdex/apdex-measure-user-satisfaction
- ApdexThreshold time.Duration
- // AccountID, TrustedAccountKey, and PrimaryAppID are used for
- // distributed tracing in ServerlessMode. AccountID and
- // TrustedAccountKey must be populated for distributed tracing to be
- // enabled. nrlambda.NewConfig populates these fields using the
- // NEW_RELIC_ACCOUNT_ID, NEW_RELIC_TRUSTED_ACCOUNT_KEY, and
- // NEW_RELIC_PRIMARY_APPLICATION_ID environment variables.
- AccountID string
- TrustedAccountKey string
- PrimaryAppID string
- }
-}
-
-// AttributeDestinationConfig controls the attributes sent to each destination.
-// For more information, see:
-// https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-data/agent-attributes
-type AttributeDestinationConfig struct {
- // Enabled controls whether or not this destination will get any
- // attributes at all. For example, to prevent any attributes from being
- // added to errors, set:
- //
- // cfg.ErrorCollector.Attributes.Enabled = false
- //
- Enabled bool
- Include []string
- // Exclude allows you to prevent the capture of certain attributes. For
- // example, to prevent the capture of the request URL attribute
- // "request.uri", set:
- //
- // cfg.Attributes.Exclude = append(cfg.Attributes.Exclude, newrelic.AttributeRequestURI)
- //
- // The '*' character acts as a wildcard. For example, to prevent the
- // capture of all request related attributes, set:
- //
- // cfg.Attributes.Exclude = append(cfg.Attributes.Exclude, "request.*")
- //
- Exclude []string
-}
-
-// NewConfig creates a Config populated with default settings and the given
-// appname and license.
-func NewConfig(appname, license string) Config {
- c := Config{}
-
- c.AppName = appname
- c.License = license
- c.Enabled = true
- c.Labels = make(map[string]string)
- c.CustomInsightsEvents.Enabled = true
- c.TransactionEvents.Enabled = true
- c.TransactionEvents.Attributes.Enabled = true
- c.HighSecurity = false
- c.ErrorCollector.Enabled = true
- c.ErrorCollector.CaptureEvents = true
- c.ErrorCollector.IgnoreStatusCodes = []int{
- // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
- 0, // gRPC OK
- 5, // gRPC NOT_FOUND
- http.StatusNotFound, // 404
- }
- c.ErrorCollector.Attributes.Enabled = true
- c.Utilization.DetectAWS = true
- c.Utilization.DetectAzure = true
- c.Utilization.DetectPCF = true
- c.Utilization.DetectGCP = true
- c.Utilization.DetectDocker = true
- c.Utilization.DetectKubernetes = true
- c.Attributes.Enabled = true
- c.RuntimeSampler.Enabled = true
-
- c.TransactionTracer.Enabled = true
- c.TransactionTracer.Threshold.IsApdexFailing = true
- c.TransactionTracer.Threshold.Duration = 500 * time.Millisecond
- c.TransactionTracer.SegmentThreshold = 2 * time.Millisecond
- c.TransactionTracer.StackTraceThreshold = 500 * time.Millisecond
- c.TransactionTracer.Attributes.Enabled = true
- c.TransactionTracer.Segments.Attributes.Enabled = true
-
- c.BrowserMonitoring.Enabled = true
- // browser monitoring attributes are disabled by default
- c.BrowserMonitoring.Attributes.Enabled = false
-
- c.CrossApplicationTracer.Enabled = true
- c.DistributedTracer.Enabled = false
- c.SpanEvents.Enabled = true
- c.SpanEvents.Attributes.Enabled = true
-
- c.DatastoreTracer.InstanceReporting.Enabled = true
- c.DatastoreTracer.DatabaseNameReporting.Enabled = true
- c.DatastoreTracer.QueryParameters.Enabled = true
- c.DatastoreTracer.SlowQuery.Enabled = true
- c.DatastoreTracer.SlowQuery.Threshold = 10 * time.Millisecond
-
- c.ServerlessMode.ApdexThreshold = 500 * time.Millisecond
- c.ServerlessMode.Enabled = false
-
- return c
-}
-
-const (
- licenseLength = 40
- appNameLimit = 3
-)
-
-// The following errors will be returned if your Config fails to validate.
-var (
- errLicenseLen = fmt.Errorf("license length is not %d", licenseLength)
- errAppNameMissing = errors.New("string AppName required")
- errAppNameLimit = fmt.Errorf("max of %d rollup application names", appNameLimit)
- errHighSecurityWithSecurityPolicies = errors.New("SecurityPoliciesToken and HighSecurity are incompatible; please ensure HighSecurity is set to false if SecurityPoliciesToken is a non-empty string and a security policy has been set for your account")
-)
-
-// Validate checks the config for improper fields. If the config is invalid,
-// newrelic.NewApplication returns an error.
-func (c Config) Validate() error {
- if c.Enabled && !c.ServerlessMode.Enabled {
- if len(c.License) != licenseLength {
- return errLicenseLen
- }
- } else {
- // The License may be empty when the agent is not enabled.
- if len(c.License) != licenseLength && len(c.License) != 0 {
- return errLicenseLen
- }
- }
- if "" == c.AppName && c.Enabled && !c.ServerlessMode.Enabled {
- return errAppNameMissing
- }
- if c.HighSecurity && "" != c.SecurityPoliciesToken {
- return errHighSecurityWithSecurityPolicies
- }
- if strings.Count(c.AppName, ";") >= appNameLimit {
- return errAppNameLimit
- }
- return nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/context.go b/vendor/github.com/newrelic/go-agent/context.go
deleted file mode 100644
index d0063135e4a..00000000000
--- a/vendor/github.com/newrelic/go-agent/context.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// +build go1.7
-
-package newrelic
-
-import (
- "context"
- "net/http"
-
- "github.com/newrelic/go-agent/internal"
-)
-
-// NewContext returns a new Context that carries the provided transaction.
-func NewContext(ctx context.Context, txn Transaction) context.Context {
- return context.WithValue(ctx, internal.TransactionContextKey, txn)
-}
-
-// FromContext returns the Transaction from the context if present, and nil
-// otherwise.
-func FromContext(ctx context.Context) Transaction {
- h, _ := ctx.Value(internal.TransactionContextKey).(Transaction)
- if nil != h {
- return h
- }
- // If we couldn't find a transaction using
- // internal.TransactionContextKey, try with
- // internal.GinTransactionContextKey. Unfortunately, gin.Context.Set
- // requires a string key, so we cannot use
- // internal.TransactionContextKey in nrgin.Middleware. We check for two
- // keys (rather than turning internal.TransactionContextKey into a
- // string key) because context.WithValue will cause golint to complain
- // if used with a string key.
- h, _ = ctx.Value(internal.GinTransactionContextKey).(Transaction)
- return h
-}
-
-// RequestWithTransactionContext adds the transaction to the request's context.
-func RequestWithTransactionContext(req *http.Request, txn Transaction) *http.Request {
- ctx := req.Context()
- ctx = NewContext(ctx, txn)
- return req.WithContext(ctx)
-}
-
-func transactionFromRequestContext(req *http.Request) Transaction {
- var txn Transaction
- if nil != req {
- txn = FromContext(req.Context())
- }
- return txn
-}
diff --git a/vendor/github.com/newrelic/go-agent/context_stub.go b/vendor/github.com/newrelic/go-agent/context_stub.go
deleted file mode 100644
index 03ea58da35d..00000000000
--- a/vendor/github.com/newrelic/go-agent/context_stub.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// +build !go1.7
-
-package newrelic
-
-import "net/http"
-
-// RequestWithTransactionContext adds the transaction to the request's context.
-func RequestWithTransactionContext(req *http.Request, txn Transaction) *http.Request {
- return req
-}
-
-func transactionFromRequestContext(req *http.Request) Transaction {
- return nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/datastore.go b/vendor/github.com/newrelic/go-agent/datastore.go
deleted file mode 100644
index 9dff98f35d5..00000000000
--- a/vendor/github.com/newrelic/go-agent/datastore.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package newrelic
-
-// DatastoreProduct is used to identify your datastore type in New Relic. It
-// is used in the DatastoreSegment Product field. See
-// https://github.com/newrelic/go-agent/blob/master/datastore.go for the full
-// list of available DatastoreProducts.
-type DatastoreProduct string
-
-// Datastore names used across New Relic agents:
-const (
- DatastoreCassandra DatastoreProduct = "Cassandra"
- DatastoreDerby = "Derby"
- DatastoreElasticsearch = "Elasticsearch"
- DatastoreFirebird = "Firebird"
- DatastoreIBMDB2 = "IBMDB2"
- DatastoreInformix = "Informix"
- DatastoreMemcached = "Memcached"
- DatastoreMongoDB = "MongoDB"
- DatastoreMySQL = "MySQL"
- DatastoreMSSQL = "MSSQL"
- DatastoreNeptune = "Neptune"
- DatastoreOracle = "Oracle"
- DatastorePostgres = "Postgres"
- DatastoreRedis = "Redis"
- DatastoreSolr = "Solr"
- DatastoreSQLite = "SQLite"
- DatastoreCouchDB = "CouchDB"
- DatastoreRiak = "Riak"
- DatastoreVoltDB = "VoltDB"
- DatastoreDynamoDB = "DynamoDB"
-)
diff --git a/vendor/github.com/newrelic/go-agent/errors.go b/vendor/github.com/newrelic/go-agent/errors.go
deleted file mode 100644
index c2020716612..00000000000
--- a/vendor/github.com/newrelic/go-agent/errors.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package newrelic
-
-// StackTracer can be implemented by errors to provide a stack trace when using
-// Transaction.NoticeError.
-type StackTracer interface {
- StackTrace() []uintptr
-}
-
-// ErrorClasser can be implemented by errors to provide a custom class when
-// using Transaction.NoticeError.
-type ErrorClasser interface {
- ErrorClass() string
-}
-
-// ErrorAttributer can be implemented by errors to provide extra context when
-// using Transaction.NoticeError.
-type ErrorAttributer interface {
- ErrorAttributes() map[string]interface{}
-}
-
-// Error is an error that implements ErrorClasser and ErrorAttributer. Use it
-// with Transaction.NoticeError to directly control error message, class, and
-// attributes.
-type Error struct {
- // Message is the error message which will be returned by the Error()
- // method.
- Message string
- // Class indicates how the error may be aggregated.
- Class string
- // Attributes are attached to traced errors and error events for
- // additional context. These attributes are validated just like those
- // added to `Transaction.AddAttribute`.
- Attributes map[string]interface{}
-}
-
-func (e Error) Error() string { return e.Message }
-
-// ErrorClass implements the ErrorClasser interface.
-func (e Error) ErrorClass() string { return e.Class }
-
-// ErrorAttributes implements the ErrorAttributes interface.
-func (e Error) ErrorAttributes() map[string]interface{} { return e.Attributes }
diff --git a/vendor/github.com/newrelic/go-agent/instrumentation.go b/vendor/github.com/newrelic/go-agent/instrumentation.go
deleted file mode 100644
index a5c50c2d3ca..00000000000
--- a/vendor/github.com/newrelic/go-agent/instrumentation.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package newrelic
-
-import (
- "net/http"
-)
-
-// instrumentation.go contains helpers built on the lower level api.
-
-// WrapHandle instruments http.Handler handlers with transactions. To
-// instrument this code:
-//
-// http.Handle("/foo", myHandler)
-//
-// Perform this replacement:
-//
-// http.Handle(newrelic.WrapHandle(app, "/foo", myHandler))
-//
-// WrapHandle adds the Transaction to the request's context. Access it using
-// FromContext to add attributes, create segments, or notice errors:
-//
-// func myHandler(rw ResponseWriter, req *Request) {
-// if txn := newrelic.FromContext(req.Context()); nil != txn {
-// txn.AddAttribute("customerLevel", "gold")
-// }
-// }
-//
-// This function is safe to call if app is nil.
-func WrapHandle(app Application, pattern string, handler http.Handler) (string, http.Handler) {
- if app == nil {
- return pattern, handler
- }
- return pattern, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- txn := app.StartTransaction(pattern, w, r)
- defer txn.End()
-
- r = RequestWithTransactionContext(r, txn)
-
- handler.ServeHTTP(txn, r)
- })
-}
-
-// WrapHandleFunc instruments handler functions using transactions. To
-// instrument this code:
-//
-// http.HandleFunc("/users", func(w http.ResponseWriter, req *http.Request) {
-// io.WriteString(w, "users page")
-// })
-//
-// Perform this replacement:
-//
-// http.HandleFunc(WrapHandleFunc(app, "/users", func(w http.ResponseWriter, req *http.Request) {
-// io.WriteString(w, "users page")
-// }))
-//
-// WrapHandleFunc adds the Transaction to the request's context. Access it using
-// FromContext to add attributes, create segments, or notice errors:
-//
-// http.HandleFunc(WrapHandleFunc(app, "/users", func(w http.ResponseWriter, req *http.Request) {
-// if txn := newrelic.FromContext(req.Context()); nil != txn {
-// txn.AddAttribute("customerLevel", "gold")
-// }
-// io.WriteString(w, "users page")
-// }))
-//
-// This function is safe to call if app is nil.
-func WrapHandleFunc(app Application, pattern string, handler func(http.ResponseWriter, *http.Request)) (string, func(http.ResponseWriter, *http.Request)) {
- p, h := WrapHandle(app, pattern, http.HandlerFunc(handler))
- return p, func(w http.ResponseWriter, r *http.Request) { h.ServeHTTP(w, r) }
-}
-
-// NewRoundTripper creates an http.RoundTripper to instrument external requests
-// and add distributed tracing headers. The RoundTripper returned creates an
-// external segment before delegating to the original RoundTripper provided (or
-// http.DefaultTransport if none is provided). If the Transaction parameter is
-// nil then the RoundTripper will look for a Transaction in the request's
-// context (using FromContext). Using a nil Transaction is STRONGLY recommended
-// because it allows the same RoundTripper (and client) to be reused for
-// multiple transactions.
-func NewRoundTripper(txn Transaction, original http.RoundTripper) http.RoundTripper {
- return roundTripperFunc(func(request *http.Request) (*http.Response, error) {
- // The specification of http.RoundTripper requires that the request is never modified.
- request = cloneRequest(request)
- segment := StartExternalSegment(txn, request)
-
- if nil == original {
- original = http.DefaultTransport
- }
- response, err := original.RoundTrip(request)
-
- segment.Response = response
- segment.End()
-
- return response, err
- })
-}
-
-// cloneRequest mimics implementation of
-// https://godoc.org/github.com/google/go-github/github#BasicAuthTransport.RoundTrip
-func cloneRequest(r *http.Request) *http.Request {
- // shallow copy of the struct
- r2 := new(http.Request)
- *r2 = *r
- // deep copy of the Header
- r2.Header = make(http.Header, len(r.Header))
- for k, s := range r.Header {
- r2.Header[k] = append([]string(nil), s...)
- }
- return r2
-}
-
-type roundTripperFunc func(*http.Request) (*http.Response, error)
-
-func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) }
diff --git a/vendor/github.com/newrelic/go-agent/internal/adaptive_sampler.go b/vendor/github.com/newrelic/go-agent/internal/adaptive_sampler.go
deleted file mode 100644
index f965d85343a..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/adaptive_sampler.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package internal
-
-import (
- "math"
- "sync"
- "time"
-)
-
-// AdaptiveSampler calculates which transactions should be sampled. An interface
-// is used in the connect reply to facilitate testing.
-type AdaptiveSampler interface {
- ComputeSampled(priority float32, now time.Time) bool
-}
-
-// SampleEverything is used for testing.
-type SampleEverything struct{}
-
-// SampleNothing is used when the application is not yet connected.
-type SampleNothing struct{}
-
-// ComputeSampled implements AdaptiveSampler.
-func (s SampleEverything) ComputeSampled(priority float32, now time.Time) bool { return true }
-
-// ComputeSampled implements AdaptiveSampler.
-func (s SampleNothing) ComputeSampled(priority float32, now time.Time) bool { return false }
-
-type adaptiveSampler struct {
- sync.Mutex
- period time.Duration
- target uint64
-
- // Transactions with priority higher than this are sampled.
- // This is 1 - sampleRatio.
- priorityMin float32
-
- currentPeriod struct {
- numSampled uint64
- numSeen uint64
- end time.Time
- }
-}
-
-// NewAdaptiveSampler creates an AdaptiveSampler.
-func NewAdaptiveSampler(period time.Duration, target uint64, now time.Time) AdaptiveSampler {
- as := &adaptiveSampler{}
- as.period = period
- as.target = target
- as.currentPeriod.end = now.Add(period)
-
- // Sample the first transactions in the first period.
- as.priorityMin = 0.0
- return as
-}
-
-// ComputeSampled calculates if the transaction should be sampled.
-func (as *adaptiveSampler) ComputeSampled(priority float32, now time.Time) bool {
- as.Lock()
- defer as.Unlock()
-
- // If the current time is after the end of the "currentPeriod". This is in
- // a `for`/`while` loop in case there's a harvest where no sampling happened.
- // i.e. for situations where a single call to
- // as.currentPeriod.end = as.currentPeriod.end.Add(as.period)
- // might not catch us up to the current period
- for now.After(as.currentPeriod.end) {
- as.priorityMin = 0.0
- if as.currentPeriod.numSeen > 0 {
- sampledRatio := float32(as.target) / float32(as.currentPeriod.numSeen)
- as.priorityMin = 1.0 - sampledRatio
- }
- as.currentPeriod.numSampled = 0
- as.currentPeriod.numSeen = 0
- as.currentPeriod.end = as.currentPeriod.end.Add(as.period)
- }
-
- as.currentPeriod.numSeen++
-
- // exponential backoff -- if the number of sampled items is greater than our
- // target, we need to apply the exponential backoff
- if as.currentPeriod.numSampled > as.target {
- if as.computeSampledBackoff(as.target, as.currentPeriod.numSeen, as.currentPeriod.numSampled) {
- as.currentPeriod.numSampled++
- return true
- }
- return false
- }
-
- if priority >= as.priorityMin {
- as.currentPeriod.numSampled++
- return true
- }
-
- return false
-}
-
-func (as *adaptiveSampler) computeSampledBackoff(target uint64, decidedCount uint64, sampledTrueCount uint64) bool {
- return float64(RandUint64N(decidedCount)) <
- math.Pow(float64(target), (float64(target)/float64(sampledTrueCount)))-math.Pow(float64(target), 0.5)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/analytics_events.go b/vendor/github.com/newrelic/go-agent/internal/analytics_events.go
deleted file mode 100644
index cb1b94f722b..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/analytics_events.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package internal
-
-import (
- "bytes"
- "container/heap"
-
- "github.com/newrelic/go-agent/internal/jsonx"
-)
-
-type analyticsEvent struct {
- priority Priority
- jsonWriter
-}
-
-type analyticsEventHeap []analyticsEvent
-
-type analyticsEvents struct {
- numSeen int
- events analyticsEventHeap
- failedHarvests int
-}
-
-func (events *analyticsEvents) NumSeen() float64 { return float64(events.numSeen) }
-func (events *analyticsEvents) NumSaved() float64 { return float64(len(events.events)) }
-
-func (h analyticsEventHeap) Len() int { return len(h) }
-func (h analyticsEventHeap) Less(i, j int) bool { return h[i].priority.isLowerPriority(h[j].priority) }
-func (h analyticsEventHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
-
-// Push and Pop are unused: only heap.Init and heap.Fix are used.
-func (h analyticsEventHeap) Push(x interface{}) {}
-func (h analyticsEventHeap) Pop() interface{} { return nil }
-
-func newAnalyticsEvents(max int) *analyticsEvents {
- return &analyticsEvents{
- numSeen: 0,
- events: make(analyticsEventHeap, 0, max),
- failedHarvests: 0,
- }
-}
-
-func (events *analyticsEvents) capacity() int {
- return cap(events.events)
-}
-
-func (events *analyticsEvents) addEvent(e analyticsEvent) {
- events.numSeen++
-
- if events.capacity() == 0 {
- // Configurable event harvest limits may be zero.
- return
- }
-
- if len(events.events) < cap(events.events) {
- events.events = append(events.events, e)
- if len(events.events) == cap(events.events) {
- // Delay heap initialization so that we can have
- // deterministic ordering for integration tests (the max
- // is not being reached).
- heap.Init(events.events)
- }
- return
- }
-
- if e.priority.isLowerPriority((events.events)[0].priority) {
- return
- }
-
- events.events[0] = e
- heap.Fix(events.events, 0)
-}
-
-func (events *analyticsEvents) mergeFailed(other *analyticsEvents) {
- fails := other.failedHarvests + 1
- if fails >= failedEventsAttemptsLimit {
- return
- }
- events.failedHarvests = fails
- events.Merge(other)
-}
-
-func (events *analyticsEvents) Merge(other *analyticsEvents) {
- allSeen := events.numSeen + other.numSeen
-
- for _, e := range other.events {
- events.addEvent(e)
- }
- events.numSeen = allSeen
-}
-
-func (events *analyticsEvents) CollectorJSON(agentRunID string) ([]byte, error) {
- if 0 == len(events.events) {
- return nil, nil
- }
-
- estimate := 256 * len(events.events)
- buf := bytes.NewBuffer(make([]byte, 0, estimate))
-
- buf.WriteByte('[')
- jsonx.AppendString(buf, agentRunID)
- buf.WriteByte(',')
- buf.WriteByte('{')
- buf.WriteString(`"reservoir_size":`)
- jsonx.AppendUint(buf, uint64(cap(events.events)))
- buf.WriteByte(',')
- buf.WriteString(`"events_seen":`)
- jsonx.AppendUint(buf, uint64(events.numSeen))
- buf.WriteByte('}')
- buf.WriteByte(',')
- buf.WriteByte('[')
- for i, e := range events.events {
- if i > 0 {
- buf.WriteByte(',')
- }
- e.WriteJSON(buf)
- }
- buf.WriteByte(']')
- buf.WriteByte(']')
-
- return buf.Bytes(), nil
-
-}
-
-// split splits the events into two. NOTE! The two event pools are not valid
-// priority queues, and should only be used to create JSON, not for adding any
-// events.
-func (events *analyticsEvents) split() (*analyticsEvents, *analyticsEvents) {
- // numSeen is conserved: e1.numSeen + e2.numSeen == events.numSeen.
- e1 := &analyticsEvents{
- numSeen: len(events.events) / 2,
- events: make([]analyticsEvent, len(events.events)/2),
- failedHarvests: events.failedHarvests,
- }
- e2 := &analyticsEvents{
- numSeen: events.numSeen - e1.numSeen,
- events: make([]analyticsEvent, len(events.events)-len(e1.events)),
- failedHarvests: events.failedHarvests,
- }
- // Note that slicing is not used to ensure that length == capacity for
- // e1.events and e2.events.
- copy(e1.events, events.events)
- copy(e2.events, events.events[len(events.events)/2:])
-
- return e1, e2
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/apdex.go b/vendor/github.com/newrelic/go-agent/internal/apdex.go
deleted file mode 100644
index 28225f7d017..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/apdex.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package internal
-
-import "time"
-
-// ApdexZone is a transaction classification.
-type ApdexZone int
-
-// https://en.wikipedia.org/wiki/Apdex
-const (
- ApdexNone ApdexZone = iota
- ApdexSatisfying
- ApdexTolerating
- ApdexFailing
-)
-
-// ApdexFailingThreshold calculates the threshold at which the transaction is
-// considered a failure.
-func ApdexFailingThreshold(threshold time.Duration) time.Duration {
- return 4 * threshold
-}
-
-// CalculateApdexZone calculates the apdex based on the transaction duration and
-// threshold.
-//
-// Note that this does not take into account whether or not the transaction
-// had an error. That is expected to be done by the caller.
-func CalculateApdexZone(threshold, duration time.Duration) ApdexZone {
- if duration <= threshold {
- return ApdexSatisfying
- }
- if duration <= ApdexFailingThreshold(threshold) {
- return ApdexTolerating
- }
- return ApdexFailing
-}
-
-func (zone ApdexZone) label() string {
- switch zone {
- case ApdexSatisfying:
- return "S"
- case ApdexTolerating:
- return "T"
- case ApdexFailing:
- return "F"
- default:
- return ""
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/attributes.go b/vendor/github.com/newrelic/go-agent/internal/attributes.go
deleted file mode 100644
index 96cb3ecbe8a..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/attributes.go
+++ /dev/null
@@ -1,601 +0,0 @@
-package internal
-
-import (
- "bytes"
- "fmt"
- "net/http"
- "net/url"
- "sort"
- "strconv"
- "strings"
-)
-
-// AgentAttributeID uniquely identifies each agent attribute.
-type AgentAttributeID int
-
-// New agent attributes must be added in the following places:
-// * Constants here.
-// * Top level attributes.go file.
-// * agentAttributeInfo
-const (
- AttributeHostDisplayName AgentAttributeID = iota
- attributeRequestMethod
- attributeRequestAcceptHeader
- attributeRequestContentType
- attributeRequestContentLength
- attributeRequestHeadersHost
- attributeRequestHeadersUserAgent
- attributeRequestHeadersReferer
- attributeRequestURI
- attributeResponseHeadersContentType
- attributeResponseHeadersContentLength
- attributeResponseCode
- AttributeAWSRequestID
- AttributeAWSLambdaARN
- AttributeAWSLambdaColdStart
- AttributeAWSLambdaEventSourceARN
-)
-
-// SpanAttribute is an attribute put in span events.
-type SpanAttribute string
-
-// AddAgentSpanAttributer should be implemented by the Transaction.
-type AddAgentSpanAttributer interface {
- AddAgentSpanAttribute(key SpanAttribute, val string)
-}
-
-// AddAgentSpanAttribute allows instrumentation packages to add span attributes.
-func AddAgentSpanAttribute(txn interface{}, key SpanAttribute, val string) {
- if aa, ok := txn.(AddAgentSpanAttributer); ok {
- aa.AddAgentSpanAttribute(key, val)
- }
-}
-
-// These span event string constants must match the contents of the top level
-// attributes.go file.
-const (
- spanAttributeDBStatement SpanAttribute = "db.statement"
- spanAttributeDBInstance SpanAttribute = "db.instance"
- spanAttributeDBCollection SpanAttribute = "db.collection"
- spanAttributePeerAddress SpanAttribute = "peer.address"
- spanAttributePeerHostname SpanAttribute = "peer.hostname"
- spanAttributeHTTPURL SpanAttribute = "http.url"
- spanAttributeHTTPMethod SpanAttribute = "http.method"
- // query parameters only appear in segments, not span events, but is
- // listed as span attributes to simplify code.
- spanAttributeQueryParameters SpanAttribute = "query_parameters"
- // These span attributes are added by aws sdk instrumentation.
- // https://source.datanerd.us/agents/agent-specs/blob/master/implementation_guides/aws-sdk.md#span-and-segment-attributes
- SpanAttributeAWSOperation SpanAttribute = "aws.operation"
- SpanAttributeAWSRequestID SpanAttribute = "aws.requestId"
- SpanAttributeAWSRegion SpanAttribute = "aws.region"
-)
-
-func (sa SpanAttribute) String() string { return string(sa) }
-
-var (
- usualDests = DestAll &^ destBrowser
- tracesDests = destTxnTrace | destError
- agentAttributeInfo = map[AgentAttributeID]struct {
- name string
- defaultDests destinationSet
- }{
- AttributeHostDisplayName: {name: "host.displayName", defaultDests: usualDests},
- attributeRequestMethod: {name: "request.method", defaultDests: usualDests},
- attributeRequestAcceptHeader: {name: "request.headers.accept", defaultDests: usualDests},
- attributeRequestContentType: {name: "request.headers.contentType", defaultDests: usualDests},
- attributeRequestContentLength: {name: "request.headers.contentLength", defaultDests: usualDests},
- attributeRequestHeadersHost: {name: "request.headers.host", defaultDests: usualDests},
- attributeRequestHeadersUserAgent: {name: "request.headers.User-Agent", defaultDests: tracesDests},
- attributeRequestHeadersReferer: {name: "request.headers.referer", defaultDests: tracesDests},
- attributeRequestURI: {name: "request.uri", defaultDests: usualDests},
- attributeResponseHeadersContentType: {name: "response.headers.contentType", defaultDests: usualDests},
- attributeResponseHeadersContentLength: {name: "response.headers.contentLength", defaultDests: usualDests},
- attributeResponseCode: {name: "httpResponseCode", defaultDests: usualDests},
- AttributeAWSRequestID: {name: "aws.requestId", defaultDests: usualDests},
- AttributeAWSLambdaARN: {name: "aws.lambda.arn", defaultDests: usualDests},
- AttributeAWSLambdaColdStart: {name: "aws.lambda.coldStart", defaultDests: usualDests},
- AttributeAWSLambdaEventSourceARN: {name: "aws.lambda.eventSource.arn", defaultDests: usualDests},
- }
- spanAttributes = []SpanAttribute{
- spanAttributeDBStatement,
- spanAttributeDBInstance,
- spanAttributeDBCollection,
- spanAttributePeerAddress,
- spanAttributePeerHostname,
- spanAttributeHTTPURL,
- spanAttributeHTTPMethod,
- spanAttributeQueryParameters,
- SpanAttributeAWSOperation,
- SpanAttributeAWSRequestID,
- SpanAttributeAWSRegion,
- }
-)
-
-func (id AgentAttributeID) name() string { return agentAttributeInfo[id].name }
-
-// https://source.datanerd.us/agents/agent-specs/blob/master/Agent-Attributes-PORTED.md
-
-// AttributeDestinationConfig matches newrelic.AttributeDestinationConfig to
-// avoid circular dependency issues.
-type AttributeDestinationConfig struct {
- Enabled bool
- Include []string
- Exclude []string
-}
-
-type destinationSet int
-
-const (
- destTxnEvent destinationSet = 1 << iota
- destError
- destTxnTrace
- destBrowser
- destSpan
- destSegment
-)
-
-const (
- destNone destinationSet = 0
- // DestAll contains all destinations.
- DestAll destinationSet = destTxnEvent | destTxnTrace | destError | destBrowser | destSpan | destSegment
-)
-
-const (
- attributeWildcardSuffix = '*'
-)
-
-type attributeModifier struct {
- match string // This will not contain a trailing '*'.
- includeExclude
-}
-
-type byMatch []*attributeModifier
-
-func (m byMatch) Len() int { return len(m) }
-func (m byMatch) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
-func (m byMatch) Less(i, j int) bool { return m[i].match < m[j].match }
-
-// AttributeConfig is created at connect and shared between all transactions.
-type AttributeConfig struct {
- disabledDestinations destinationSet
- exactMatchModifiers map[string]*attributeModifier
- // Once attributeConfig is constructed, wildcardModifiers is sorted in
- // lexicographical order. Modifiers appearing later have precedence
- // over modifiers appearing earlier.
- wildcardModifiers []*attributeModifier
- agentDests map[AgentAttributeID]destinationSet
- spanDests map[SpanAttribute]destinationSet
-}
-
-type includeExclude struct {
- include destinationSet
- exclude destinationSet
-}
-
-func modifierApply(m *attributeModifier, d destinationSet) destinationSet {
- // Include before exclude, since exclude has priority.
- d |= m.include
- d &^= m.exclude
- return d
-}
-
-func applyAttributeConfig(c *AttributeConfig, key string, d destinationSet) destinationSet {
- // Important: The wildcard modifiers must be applied before the exact
- // match modifiers, and the slice must be iterated in a forward
- // direction.
- for _, m := range c.wildcardModifiers {
- if strings.HasPrefix(key, m.match) {
- d = modifierApply(m, d)
- }
- }
-
- if m, ok := c.exactMatchModifiers[key]; ok {
- d = modifierApply(m, d)
- }
-
- d &^= c.disabledDestinations
-
- return d
-}
-
-func addModifier(c *AttributeConfig, match string, d includeExclude) {
- if "" == match {
- return
- }
- exactMatch := true
- if attributeWildcardSuffix == match[len(match)-1] {
- exactMatch = false
- match = match[0 : len(match)-1]
- }
- mod := &attributeModifier{
- match: match,
- includeExclude: d,
- }
-
- if exactMatch {
- if m, ok := c.exactMatchModifiers[mod.match]; ok {
- m.include |= mod.include
- m.exclude |= mod.exclude
- } else {
- c.exactMatchModifiers[mod.match] = mod
- }
- } else {
- for _, m := range c.wildcardModifiers {
- // Important: Duplicate entries for the same match
- // string would not work because exclude needs
- // precedence over include.
- if m.match == mod.match {
- m.include |= mod.include
- m.exclude |= mod.exclude
- return
- }
- }
- c.wildcardModifiers = append(c.wildcardModifiers, mod)
- }
-}
-
-func processDest(c *AttributeConfig, includeEnabled bool, dc *AttributeDestinationConfig, d destinationSet) {
- if !dc.Enabled {
- c.disabledDestinations |= d
- }
- if includeEnabled {
- for _, match := range dc.Include {
- addModifier(c, match, includeExclude{include: d})
- }
- }
- for _, match := range dc.Exclude {
- addModifier(c, match, includeExclude{exclude: d})
- }
-}
-
-// AttributeConfigInput is used as the input to CreateAttributeConfig: it
-// transforms newrelic.Config settings into an AttributeConfig.
-type AttributeConfigInput struct {
- Attributes AttributeDestinationConfig
- ErrorCollector AttributeDestinationConfig
- TransactionEvents AttributeDestinationConfig
- BrowserMonitoring AttributeDestinationConfig
- TransactionTracer AttributeDestinationConfig
- SpanEvents AttributeDestinationConfig
- TraceSegments AttributeDestinationConfig
-}
-
-var (
- sampleAttributeConfigInput = AttributeConfigInput{
- Attributes: AttributeDestinationConfig{Enabled: true},
- ErrorCollector: AttributeDestinationConfig{Enabled: true},
- TransactionEvents: AttributeDestinationConfig{Enabled: true},
- TransactionTracer: AttributeDestinationConfig{Enabled: true},
- BrowserMonitoring: AttributeDestinationConfig{Enabled: true},
- SpanEvents: AttributeDestinationConfig{Enabled: true},
- TraceSegments: AttributeDestinationConfig{Enabled: true},
- }
-)
-
-// CreateAttributeConfig creates a new AttributeConfig.
-func CreateAttributeConfig(input AttributeConfigInput, includeEnabled bool) *AttributeConfig {
- c := &AttributeConfig{
- exactMatchModifiers: make(map[string]*attributeModifier),
- wildcardModifiers: make([]*attributeModifier, 0, 64),
- }
-
- processDest(c, includeEnabled, &input.Attributes, DestAll)
- processDest(c, includeEnabled, &input.ErrorCollector, destError)
- processDest(c, includeEnabled, &input.TransactionEvents, destTxnEvent)
- processDest(c, includeEnabled, &input.TransactionTracer, destTxnTrace)
- processDest(c, includeEnabled, &input.BrowserMonitoring, destBrowser)
- processDest(c, includeEnabled, &input.SpanEvents, destSpan)
- processDest(c, includeEnabled, &input.TraceSegments, destSegment)
-
- sort.Sort(byMatch(c.wildcardModifiers))
-
- c.agentDests = make(map[AgentAttributeID]destinationSet)
- for id, info := range agentAttributeInfo {
- c.agentDests[id] = applyAttributeConfig(c, info.name, info.defaultDests)
- }
- c.spanDests = make(map[SpanAttribute]destinationSet, len(spanAttributes))
- for _, id := range spanAttributes {
- c.spanDests[id] = applyAttributeConfig(c, id.String(), destSpan|destSegment)
- }
-
- return c
-}
-
-type userAttribute struct {
- value interface{}
- dests destinationSet
-}
-
-type agentAttributeValue struct {
- stringVal string
- otherVal interface{}
-}
-
-type agentAttributes map[AgentAttributeID]agentAttributeValue
-
-func (a *Attributes) filterSpanAttributes(s map[SpanAttribute]jsonWriter, d destinationSet) map[SpanAttribute]jsonWriter {
- if nil != a {
- for key := range s {
- if a.config.spanDests[key]&d == 0 {
- delete(s, key)
- }
- }
- }
- return s
-}
-
-// GetAgentValue is used to access agent attributes. This function returns ("",
-// nil) if the attribute doesn't exist or it doesn't match the destinations
-// provided.
-func (a *Attributes) GetAgentValue(id AgentAttributeID, d destinationSet) (string, interface{}) {
- if nil == a || 0 == a.config.agentDests[id]&d {
- return "", nil
- }
- v, _ := a.Agent[id]
- return v.stringVal, v.otherVal
-}
-
-// AddAgentAttributer allows instrumentation to add agent attributes without
-// exposing a Transaction method.
-type AddAgentAttributer interface {
- AddAgentAttribute(id AgentAttributeID, stringVal string, otherVal interface{})
-}
-
-// Add is used to add agent attributes. Only one of stringVal and
-// otherVal should be populated. Since most agent attribute values are strings,
-// stringVal exists to avoid allocations.
-func (attr agentAttributes) Add(id AgentAttributeID, stringVal string, otherVal interface{}) {
- if "" != stringVal || otherVal != nil {
- attr[id] = agentAttributeValue{
- stringVal: truncateStringValueIfLong(stringVal),
- otherVal: otherVal,
- }
- }
-}
-
-// Attributes are key value pairs attached to the various collected data types.
-type Attributes struct {
- config *AttributeConfig
- user map[string]userAttribute
- Agent agentAttributes
-}
-
-// NewAttributes creates a new Attributes.
-func NewAttributes(config *AttributeConfig) *Attributes {
- return &Attributes{
- config: config,
- Agent: make(agentAttributes),
- }
-}
-
-// ErrInvalidAttributeType is returned when the value is not valid.
-type ErrInvalidAttributeType struct {
- key string
- val interface{}
-}
-
-func (e ErrInvalidAttributeType) Error() string {
- return fmt.Sprintf("attribute '%s' value of type %T is invalid", e.key, e.val)
-}
-
-type invalidAttributeKeyErr struct{ key string }
-
-func (e invalidAttributeKeyErr) Error() string {
- return fmt.Sprintf("attribute key '%.32s...' exceeds length limit %d",
- e.key, attributeKeyLengthLimit)
-}
-
-type userAttributeLimitErr struct{ key string }
-
-func (e userAttributeLimitErr) Error() string {
- return fmt.Sprintf("attribute '%s' discarded: limit of %d reached", e.key,
- attributeUserLimit)
-}
-
-func truncateStringValueIfLong(val string) string {
- if len(val) > attributeValueLengthLimit {
- return StringLengthByteLimit(val, attributeValueLengthLimit)
- }
- return val
-}
-
-// ValidateUserAttribute validates a user attribute.
-func ValidateUserAttribute(key string, val interface{}) (interface{}, error) {
- if str, ok := val.(string); ok {
- val = interface{}(truncateStringValueIfLong(str))
- }
-
- switch val.(type) {
- case string, bool,
- uint8, uint16, uint32, uint64, int8, int16, int32, int64,
- float32, float64, uint, int, uintptr:
- default:
- return nil, ErrInvalidAttributeType{
- key: key,
- val: val,
- }
- }
-
- // Attributes whose keys are excessively long are dropped rather than
- // truncated to avoid worrying about the application of configuration to
- // truncated values or performing the truncation after configuration.
- if len(key) > attributeKeyLengthLimit {
- return nil, invalidAttributeKeyErr{key: key}
- }
- return val, nil
-}
-
-// AddUserAttribute adds a user attribute.
-func AddUserAttribute(a *Attributes, key string, val interface{}, d destinationSet) error {
- val, err := ValidateUserAttribute(key, val)
- if nil != err {
- return err
- }
- dests := applyAttributeConfig(a.config, key, d)
- if destNone == dests {
- return nil
- }
- if nil == a.user {
- a.user = make(map[string]userAttribute)
- }
-
- if _, exists := a.user[key]; !exists && len(a.user) >= attributeUserLimit {
- return userAttributeLimitErr{key}
- }
-
- // Note: Duplicates are overridden: last attribute in wins.
- a.user[key] = userAttribute{
- value: val,
- dests: dests,
- }
- return nil
-}
-
-func writeAttributeValueJSON(w *jsonFieldsWriter, key string, val interface{}) {
- switch v := val.(type) {
- case string:
- w.stringField(key, v)
- case bool:
- if v {
- w.rawField(key, `true`)
- } else {
- w.rawField(key, `false`)
- }
- case uint8:
- w.intField(key, int64(v))
- case uint16:
- w.intField(key, int64(v))
- case uint32:
- w.intField(key, int64(v))
- case uint64:
- w.intField(key, int64(v))
- case uint:
- w.intField(key, int64(v))
- case uintptr:
- w.intField(key, int64(v))
- case int8:
- w.intField(key, int64(v))
- case int16:
- w.intField(key, int64(v))
- case int32:
- w.intField(key, int64(v))
- case int64:
- w.intField(key, v)
- case int:
- w.intField(key, int64(v))
- case float32:
- w.floatField(key, float64(v))
- case float64:
- w.floatField(key, v)
- default:
- w.stringField(key, fmt.Sprintf("%T", v))
- }
-}
-
-func agentAttributesJSON(a *Attributes, buf *bytes.Buffer, d destinationSet) {
- if nil == a {
- buf.WriteString("{}")
- return
- }
- w := jsonFieldsWriter{buf: buf}
- buf.WriteByte('{')
- for id, val := range a.Agent {
- if 0 != a.config.agentDests[id]&d {
- if val.stringVal != "" {
- w.stringField(id.name(), val.stringVal)
- } else {
- writeAttributeValueJSON(&w, id.name(), val.otherVal)
- }
- }
- }
- buf.WriteByte('}')
-
-}
-
-func userAttributesJSON(a *Attributes, buf *bytes.Buffer, d destinationSet, extraAttributes map[string]interface{}) {
- buf.WriteByte('{')
- if nil != a {
- w := jsonFieldsWriter{buf: buf}
- for key, val := range extraAttributes {
- outputDest := applyAttributeConfig(a.config, key, d)
- if 0 != outputDest&d {
- writeAttributeValueJSON(&w, key, val)
- }
- }
- for name, atr := range a.user {
- if 0 != atr.dests&d {
- if _, found := extraAttributes[name]; found {
- continue
- }
- writeAttributeValueJSON(&w, name, atr.value)
- }
- }
- }
- buf.WriteByte('}')
-}
-
-// userAttributesStringJSON is only used for testing.
-func userAttributesStringJSON(a *Attributes, d destinationSet, extraAttributes map[string]interface{}) string {
- estimate := len(a.user) * 128
- buf := bytes.NewBuffer(make([]byte, 0, estimate))
- userAttributesJSON(a, buf, d, extraAttributes)
- return buf.String()
-}
-
-// RequestAgentAttributes gathers agent attributes out of the request.
-func RequestAgentAttributes(a *Attributes, method string, h http.Header, u *url.URL) {
- a.Agent.Add(attributeRequestMethod, method, nil)
-
- if nil != u {
- a.Agent.Add(attributeRequestURI, SafeURL(u), nil)
- }
-
- if nil == h {
- return
- }
- a.Agent.Add(attributeRequestAcceptHeader, h.Get("Accept"), nil)
- a.Agent.Add(attributeRequestContentType, h.Get("Content-Type"), nil)
- a.Agent.Add(attributeRequestHeadersHost, h.Get("Host"), nil)
- a.Agent.Add(attributeRequestHeadersUserAgent, h.Get("User-Agent"), nil)
- a.Agent.Add(attributeRequestHeadersReferer, SafeURLFromString(h.Get("Referer")), nil)
-
- if l := GetContentLengthFromHeader(h); l >= 0 {
- a.Agent.Add(attributeRequestContentLength, "", l)
- }
-}
-
-// ResponseHeaderAttributes gather agent attributes from the response headers.
-func ResponseHeaderAttributes(a *Attributes, h http.Header) {
- if nil == h {
- return
- }
- a.Agent.Add(attributeResponseHeadersContentType, h.Get("Content-Type"), nil)
-
- if l := GetContentLengthFromHeader(h); l >= 0 {
- a.Agent.Add(attributeResponseHeadersContentLength, "", l)
- }
-}
-
-var (
- // statusCodeLookup avoids a strconv.Itoa call.
- statusCodeLookup = map[int]string{
- 100: "100", 101: "101",
- 200: "200", 201: "201", 202: "202", 203: "203", 204: "204", 205: "205", 206: "206",
- 300: "300", 301: "301", 302: "302", 303: "303", 304: "304", 305: "305", 307: "307",
- 400: "400", 401: "401", 402: "402", 403: "403", 404: "404", 405: "405", 406: "406",
- 407: "407", 408: "408", 409: "409", 410: "410", 411: "411", 412: "412", 413: "413",
- 414: "414", 415: "415", 416: "416", 417: "417", 418: "418", 428: "428", 429: "429",
- 431: "431", 451: "451",
- 500: "500", 501: "501", 502: "502", 503: "503", 504: "504", 505: "505", 511: "511",
- }
-)
-
-// ResponseCodeAttribute sets the response code agent attribute.
-func ResponseCodeAttribute(a *Attributes, code int) {
- rc := statusCodeLookup[code]
- if rc == "" {
- rc = strconv.Itoa(code)
- }
- a.Agent.Add(attributeResponseCode, rc, nil)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/browser.go b/vendor/github.com/newrelic/go-agent/internal/browser.go
deleted file mode 100644
index a55456ad321..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/browser.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package internal
-
-import "bytes"
-
-// BrowserAttributes returns a string with the attributes that are attached to
-// the browser destination encoded in the JSON format expected by the Browser
-// agent.
-func BrowserAttributes(a *Attributes) []byte {
- buf := &bytes.Buffer{}
-
- buf.WriteString(`{"u":`)
- userAttributesJSON(a, buf, destBrowser, nil)
- buf.WriteString(`,"a":`)
- agentAttributesJSON(a, buf, destBrowser)
- buf.WriteByte('}')
-
- return buf.Bytes()
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/cat/appdata.go b/vendor/github.com/newrelic/go-agent/internal/cat/appdata.go
deleted file mode 100644
index d62b71f2b47..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/cat/appdata.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package cat
-
-import (
- "bytes"
- "encoding/json"
- "errors"
-
- "github.com/newrelic/go-agent/internal/jsonx"
-)
-
-// AppDataHeader represents a decoded AppData header.
-type AppDataHeader struct {
- CrossProcessID string
- TransactionName string
- QueueTimeInSeconds float64
- ResponseTimeInSeconds float64
- ContentLength int64
- TransactionGUID string
-}
-
-var (
- errInvalidAppDataJSON = errors.New("invalid transaction data JSON")
- errInvalidAppDataCrossProcessID = errors.New("cross process ID is not a string")
- errInvalidAppDataTransactionName = errors.New("transaction name is not a string")
- errInvalidAppDataQueueTimeInSeconds = errors.New("queue time is not a float64")
- errInvalidAppDataResponseTimeInSeconds = errors.New("response time is not a float64")
- errInvalidAppDataContentLength = errors.New("content length is not a float64")
- errInvalidAppDataTransactionGUID = errors.New("transaction GUID is not a string")
-)
-
-// MarshalJSON marshalls an AppDataHeader as raw JSON.
-func (appData *AppDataHeader) MarshalJSON() ([]byte, error) {
- buf := bytes.NewBufferString("[")
-
- jsonx.AppendString(buf, appData.CrossProcessID)
-
- buf.WriteString(",")
- jsonx.AppendString(buf, appData.TransactionName)
-
- buf.WriteString(",")
- jsonx.AppendFloat(buf, appData.QueueTimeInSeconds)
-
- buf.WriteString(",")
- jsonx.AppendFloat(buf, appData.ResponseTimeInSeconds)
-
- buf.WriteString(",")
- jsonx.AppendInt(buf, appData.ContentLength)
-
- buf.WriteString(",")
- jsonx.AppendString(buf, appData.TransactionGUID)
-
- // The mysterious unused field. We don't need to round trip this, so we'll
- // just hardcode it to false.
- buf.WriteString(",false]")
- return buf.Bytes(), nil
-}
-
-// UnmarshalJSON unmarshalls an AppDataHeader from raw JSON.
-func (appData *AppDataHeader) UnmarshalJSON(data []byte) error {
- var ok bool
- var v interface{}
-
- if err := json.Unmarshal(data, &v); err != nil {
- return err
- }
-
- arr, ok := v.([]interface{})
- if !ok {
- return errInvalidAppDataJSON
- }
- if len(arr) < 7 {
- return errUnexpectedArraySize{
- label: "unexpected number of application data elements",
- expected: 7,
- actual: len(arr),
- }
- }
-
- if appData.CrossProcessID, ok = arr[0].(string); !ok {
- return errInvalidAppDataCrossProcessID
- }
-
- if appData.TransactionName, ok = arr[1].(string); !ok {
- return errInvalidAppDataTransactionName
- }
-
- if appData.QueueTimeInSeconds, ok = arr[2].(float64); !ok {
- return errInvalidAppDataQueueTimeInSeconds
- }
-
- if appData.ResponseTimeInSeconds, ok = arr[3].(float64); !ok {
- return errInvalidAppDataResponseTimeInSeconds
- }
-
- cl, ok := arr[4].(float64)
- if !ok {
- return errInvalidAppDataContentLength
- }
- // Content length is specced as int32, but not all agents are consistent on
- // this in practice. Let's handle it as int64 to maximise compatibility.
- appData.ContentLength = int64(cl)
-
- if appData.TransactionGUID, ok = arr[5].(string); !ok {
- return errInvalidAppDataTransactionGUID
- }
-
- // As above, we don't bother decoding the unused field here. It just has to
- // be present (which was checked earlier with the length check).
-
- return nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/cat/errors.go b/vendor/github.com/newrelic/go-agent/internal/cat/errors.go
deleted file mode 100644
index d19ce5183fb..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/cat/errors.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package cat
-
-import (
- "fmt"
-)
-
-type errUnexpectedArraySize struct {
- label string
- expected int
- actual int
-}
-
-func (e errUnexpectedArraySize) Error() string {
- return fmt.Sprintf("%s: expected %d; got %d", e.label, e.expected, e.actual)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/cat/headers.go b/vendor/github.com/newrelic/go-agent/internal/cat/headers.go
deleted file mode 100644
index 52586ed9337..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/cat/headers.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// Package cat provides functionality related to the wire format of CAT
-// headers.
-package cat
-
-// These header names don't match the spec in terms of their casing, but does
-// match what Go will give us from http.CanonicalHeaderKey(). Besides, HTTP
-// headers are case insensitive anyway. Rejoice!
-const (
- NewRelicIDName = "X-Newrelic-Id"
- NewRelicTxnName = "X-Newrelic-Transaction"
- NewRelicAppDataName = "X-Newrelic-App-Data"
- NewRelicSyntheticsName = "X-Newrelic-Synthetics"
-)
diff --git a/vendor/github.com/newrelic/go-agent/internal/cat/id.go b/vendor/github.com/newrelic/go-agent/internal/cat/id.go
deleted file mode 100644
index f8d3928ac19..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/cat/id.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package cat
-
-import (
- "errors"
- "strconv"
- "strings"
-)
-
-// IDHeader represents a decoded cross process ID header (generally encoded as
-// a string in the form ACCOUNT#BLOB).
-type IDHeader struct {
- AccountID int
- Blob string
-}
-
-var (
- errInvalidAccountID = errors.New("invalid account ID")
-)
-
-// NewIDHeader parses the given decoded ID header and creates an IDHeader
-// representing it.
-func NewIDHeader(in []byte) (*IDHeader, error) {
- parts := strings.Split(string(in), "#")
- if len(parts) != 2 {
- return nil, errUnexpectedArraySize{
- label: "unexpected number of ID elements",
- expected: 2,
- actual: len(parts),
- }
- }
-
- account, err := strconv.Atoi(parts[0])
- if err != nil {
- return nil, errInvalidAccountID
- }
-
- return &IDHeader{
- AccountID: account,
- Blob: parts[1],
- }, nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/cat/path_hash.go b/vendor/github.com/newrelic/go-agent/internal/cat/path_hash.go
deleted file mode 100644
index 34014464f11..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/cat/path_hash.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package cat
-
-import (
- "crypto/md5"
- "encoding/binary"
- "fmt"
- "regexp"
-)
-
-var pathHashValidator = regexp.MustCompile("^[0-9a-f]{8}$")
-
-// GeneratePathHash generates a path hash given a referring path hash,
-// transaction name, and application name. referringPathHash can be an empty
-// string if there was no referring path hash.
-func GeneratePathHash(referringPathHash, txnName, appName string) (string, error) {
- var rph uint32
- if referringPathHash != "" {
- if !pathHashValidator.MatchString(referringPathHash) {
- // Per the spec, invalid referring path hashes should be treated as "0".
- referringPathHash = "0"
- }
-
- if _, err := fmt.Sscanf(referringPathHash, "%x", &rph); err != nil {
- fmt.Println(rph)
- return "", err
- }
- rph = (rph << 1) | (rph >> 31)
- }
-
- hashInput := fmt.Sprintf("%s;%s", appName, txnName)
- hash := md5.Sum([]byte(hashInput))
- low32 := binary.BigEndian.Uint32(hash[12:])
-
- return fmt.Sprintf("%08x", rph^low32), nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/cat/synthetics.go b/vendor/github.com/newrelic/go-agent/internal/cat/synthetics.go
deleted file mode 100644
index 3836f625b01..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/cat/synthetics.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package cat
-
-import (
- "encoding/json"
- "errors"
- "fmt"
-)
-
-// SyntheticsHeader represents a decoded Synthetics header.
-type SyntheticsHeader struct {
- Version int
- AccountID int
- ResourceID string
- JobID string
- MonitorID string
-}
-
-var (
- errInvalidSyntheticsJSON = errors.New("invalid synthetics JSON")
- errInvalidSyntheticsVersion = errors.New("version is not a float64")
- errInvalidSyntheticsAccountID = errors.New("account ID is not a float64")
- errInvalidSyntheticsResourceID = errors.New("synthetics resource ID is not a string")
- errInvalidSyntheticsJobID = errors.New("synthetics job ID is not a string")
- errInvalidSyntheticsMonitorID = errors.New("synthetics monitor ID is not a string")
-)
-
-type errUnexpectedSyntheticsVersion int
-
-func (e errUnexpectedSyntheticsVersion) Error() string {
- return fmt.Sprintf("unexpected synthetics header version: %d", e)
-}
-
-// UnmarshalJSON unmarshalls a SyntheticsHeader from raw JSON.
-func (s *SyntheticsHeader) UnmarshalJSON(data []byte) error {
- var ok bool
- var v interface{}
-
- if err := json.Unmarshal(data, &v); err != nil {
- return err
- }
-
- arr, ok := v.([]interface{})
- if !ok {
- return errInvalidSyntheticsJSON
- }
- if len(arr) != 5 {
- return errUnexpectedArraySize{
- label: "unexpected number of application data elements",
- expected: 5,
- actual: len(arr),
- }
- }
-
- version, ok := arr[0].(float64)
- if !ok {
- return errInvalidSyntheticsVersion
- }
- s.Version = int(version)
- if s.Version != 1 {
- return errUnexpectedSyntheticsVersion(s.Version)
- }
-
- accountID, ok := arr[1].(float64)
- if !ok {
- return errInvalidSyntheticsAccountID
- }
- s.AccountID = int(accountID)
-
- if s.ResourceID, ok = arr[2].(string); !ok {
- return errInvalidSyntheticsResourceID
- }
-
- if s.JobID, ok = arr[3].(string); !ok {
- return errInvalidSyntheticsJobID
- }
-
- if s.MonitorID, ok = arr[4].(string); !ok {
- return errInvalidSyntheticsMonitorID
- }
-
- return nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/cat/txndata.go b/vendor/github.com/newrelic/go-agent/internal/cat/txndata.go
deleted file mode 100644
index a766926a820..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/cat/txndata.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package cat
-
-import (
- "bytes"
- "encoding/json"
- "errors"
-
- "github.com/newrelic/go-agent/internal/jsonx"
-)
-
-// TxnDataHeader represents a decoded TxnData header.
-type TxnDataHeader struct {
- GUID string
- TripID string
- PathHash string
-}
-
-var (
- errInvalidTxnDataJSON = errors.New("invalid transaction data JSON")
- errInvalidTxnDataGUID = errors.New("GUID is not a string")
- errInvalidTxnDataTripID = errors.New("trip ID is not a string or null")
- errInvalidTxnDataPathHash = errors.New("path hash is not a string or null")
-)
-
-// MarshalJSON marshalls a TxnDataHeader as raw JSON.
-func (txnData *TxnDataHeader) MarshalJSON() ([]byte, error) {
- // Note that, although there are two and four element versions of this header
- // in the wild, we will only ever generate the four element version.
-
- buf := bytes.NewBufferString("[")
-
- jsonx.AppendString(buf, txnData.GUID)
-
- // Write the unused second field.
- buf.WriteString(",false,")
- jsonx.AppendString(buf, txnData.TripID)
-
- buf.WriteString(",")
- jsonx.AppendString(buf, txnData.PathHash)
-
- buf.WriteString("]")
-
- return buf.Bytes(), nil
-}
-
-// UnmarshalJSON unmarshalls a TxnDataHeader from raw JSON.
-func (txnData *TxnDataHeader) UnmarshalJSON(data []byte) error {
- var ok bool
- var v interface{}
-
- if err := json.Unmarshal(data, &v); err != nil {
- return err
- }
-
- arr, ok := v.([]interface{})
- if !ok {
- return errInvalidTxnDataJSON
- }
- if len(arr) < 2 {
- return errUnexpectedArraySize{
- label: "unexpected number of transaction data elements",
- expected: 2,
- actual: len(arr),
- }
- }
-
- if txnData.GUID, ok = arr[0].(string); !ok {
- return errInvalidTxnDataGUID
- }
-
- // Ignore the unused second field.
-
- // Set up defaults for the optional values.
- txnData.TripID = ""
- txnData.PathHash = ""
-
- if len(arr) >= 3 {
- // Per the cross agent tests, an explicit null is valid here.
- if nil != arr[2] {
- if txnData.TripID, ok = arr[2].(string); !ok {
- return errInvalidTxnDataTripID
- }
- }
-
- if len(arr) >= 4 {
- // Per the cross agent tests, an explicit null is also valid here.
- if nil != arr[3] {
- if txnData.PathHash, ok = arr[3].(string); !ok {
- return errInvalidTxnDataPathHash
- }
- }
- }
- }
-
- return nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/collector.go b/vendor/github.com/newrelic/go-agent/internal/collector.go
deleted file mode 100644
index e2460a683eb..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/collector.go
+++ /dev/null
@@ -1,333 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "os"
- "regexp"
- "strconv"
- "time"
-
- "github.com/newrelic/go-agent/internal/logger"
-)
-
-const (
- // ProcotolVersion is the protocol version used to communicate with NR
- // backend.
- ProcotolVersion = 17
- userAgentPrefix = "NewRelic-Go-Agent/"
-
- // Methods used in collector communication.
- cmdPreconnect = "preconnect"
- cmdConnect = "connect"
- cmdMetrics = "metric_data"
- cmdCustomEvents = "custom_event_data"
- cmdTxnEvents = "analytic_event_data"
- cmdErrorEvents = "error_event_data"
- cmdErrorData = "error_data"
- cmdTxnTraces = "transaction_sample_data"
- cmdSlowSQLs = "sql_trace_data"
- cmdSpanEvents = "span_event_data"
-)
-
-// RpmCmd contains fields specific to an individual call made to RPM.
-type RpmCmd struct {
- Name string
- Collector string
- RunID string
- Data []byte
- RequestHeadersMap map[string]string
- MaxPayloadSize int
-}
-
-// RpmControls contains fields which will be the same for all calls made
-// by the same application.
-type RpmControls struct {
- License string
- Client *http.Client
- Logger logger.Logger
- AgentVersion string
-}
-
-// RPMResponse contains a NR endpoint response.
-//
-// Agent Behavior Summary:
-//
-// on connect/preconnect:
-// 410 means shutdown
-// 200, 202 mean success (start run)
-// all other response codes and errors mean try after backoff
-//
-// on harvest:
-// 410 means shutdown
-// 401, 409 mean restart run
-// 408, 429, 500, 503 mean save data for next harvest
-// all other response codes and errors discard the data and continue the current harvest
-type RPMResponse struct {
- statusCode int
- body []byte
- // Err indicates whether or not the call was successful: newRPMResponse
- // should be used to avoid mismatch between statusCode and Err.
- Err error
- disconnectSecurityPolicy bool
-}
-
-func newRPMResponse(statusCode int) RPMResponse {
- var err error
- if statusCode != 200 && statusCode != 202 {
- err = fmt.Errorf("response code: %d", statusCode)
- }
- return RPMResponse{statusCode: statusCode, Err: err}
-}
-
-// IsDisconnect indicates that the agent should disconnect.
-func (resp RPMResponse) IsDisconnect() bool {
- return resp.statusCode == 410 || resp.disconnectSecurityPolicy
-}
-
-// IsRestartException indicates that the agent should restart.
-func (resp RPMResponse) IsRestartException() bool {
- return resp.statusCode == 401 ||
- resp.statusCode == 409
-}
-
-// ShouldSaveHarvestData indicates that the agent should save the data and try
-// to send it in the next harvest.
-func (resp RPMResponse) ShouldSaveHarvestData() bool {
- switch resp.statusCode {
- case 408, 429, 500, 503:
- return true
- default:
- return false
- }
-}
-
-func rpmURL(cmd RpmCmd, cs RpmControls) string {
- var u url.URL
-
- u.Host = cmd.Collector
- u.Path = "agent_listener/invoke_raw_method"
- u.Scheme = "https"
-
- query := url.Values{}
- query.Set("marshal_format", "json")
- query.Set("protocol_version", strconv.Itoa(ProcotolVersion))
- query.Set("method", cmd.Name)
- query.Set("license_key", cs.License)
-
- if len(cmd.RunID) > 0 {
- query.Set("run_id", cmd.RunID)
- }
-
- u.RawQuery = query.Encode()
- return u.String()
-}
-
-func collectorRequestInternal(url string, cmd RpmCmd, cs RpmControls) RPMResponse {
- compressed, err := compress(cmd.Data)
- if nil != err {
- return RPMResponse{Err: err}
- }
-
- if l := compressed.Len(); l > cmd.MaxPayloadSize {
- return RPMResponse{Err: fmt.Errorf("Payload size for %s too large: %d greater than %d", cmd.Name, l, cmd.MaxPayloadSize)}
- }
-
- req, err := http.NewRequest("POST", url, compressed)
- if nil != err {
- return RPMResponse{Err: err}
- }
-
- req.Header.Add("Accept-Encoding", "identity, deflate")
- req.Header.Add("Content-Type", "application/octet-stream")
- req.Header.Add("User-Agent", userAgentPrefix+cs.AgentVersion)
- req.Header.Add("Content-Encoding", "gzip")
- for k, v := range cmd.RequestHeadersMap {
- req.Header.Add(k, v)
- }
-
- resp, err := cs.Client.Do(req)
- if err != nil {
- return RPMResponse{Err: err}
- }
-
- defer resp.Body.Close()
-
- r := newRPMResponse(resp.StatusCode)
-
- // Read the entire response, rather than using resp.Body as input to json.NewDecoder to
- // avoid the issue described here:
- // https://github.com/google/go-github/pull/317
- // https://ahmetalpbalkan.com/blog/golang-json-decoder-pitfalls/
- // Also, collector JSON responses are expected to be quite small.
- body, err := ioutil.ReadAll(resp.Body)
- if nil == r.Err {
- r.Err = err
- }
- r.body = body
-
- return r
-}
-
-// CollectorRequest makes a request to New Relic.
-func CollectorRequest(cmd RpmCmd, cs RpmControls) RPMResponse {
- url := rpmURL(cmd, cs)
-
- if cs.Logger.DebugEnabled() {
- cs.Logger.Debug("rpm request", map[string]interface{}{
- "command": cmd.Name,
- "url": url,
- "payload": JSONString(cmd.Data),
- })
- }
-
- resp := collectorRequestInternal(url, cmd, cs)
-
- if cs.Logger.DebugEnabled() {
- if err := resp.Err; err != nil {
- cs.Logger.Debug("rpm failure", map[string]interface{}{
- "command": cmd.Name,
- "url": url,
- "response": string(resp.body), // Body might not be JSON on failure.
- "error": err.Error(),
- })
- } else {
- cs.Logger.Debug("rpm response", map[string]interface{}{
- "command": cmd.Name,
- "url": url,
- "response": JSONString(resp.body),
- })
- }
- }
-
- return resp
-}
-
-const (
- // NEW_RELIC_HOST can be used to override the New Relic endpoint. This
- // is useful for testing.
- envHost = "NEW_RELIC_HOST"
-)
-
-var (
- preconnectHostOverride = os.Getenv(envHost)
- preconnectHostDefault = "collector.newrelic.com"
- preconnectRegionLicenseRegex = regexp.MustCompile(`(^.+?)x`)
-)
-
-func calculatePreconnectHost(license, overrideHost string) string {
- if "" != overrideHost {
- return overrideHost
- }
- m := preconnectRegionLicenseRegex.FindStringSubmatch(license)
- if len(m) > 1 {
- return "collector." + m[1] + ".nr-data.net"
- }
- return preconnectHostDefault
-}
-
-// ConnectJSONCreator allows the creation of the connect payload JSON to be
-// deferred until the SecurityPolicies are acquired and vetted.
-type ConnectJSONCreator interface {
- CreateConnectJSON(*SecurityPolicies) ([]byte, error)
-}
-
-type preconnectRequest struct {
- SecurityPoliciesToken string `json:"security_policies_token,omitempty"`
- HighSecurity bool `json:"high_security"`
-}
-
-var (
- errMissingAgentRunID = errors.New("connect reply missing agent run id")
-)
-
-// ConnectAttempt tries to connect an application.
-func ConnectAttempt(config ConnectJSONCreator, securityPoliciesToken string, highSecurity bool, cs RpmControls) (*ConnectReply, RPMResponse) {
- preconnectData, err := json.Marshal([]preconnectRequest{{
- SecurityPoliciesToken: securityPoliciesToken,
- HighSecurity: highSecurity,
- }})
- if nil != err {
- return nil, RPMResponse{Err: fmt.Errorf("unable to marshal preconnect data: %v", err)}
- }
-
- call := RpmCmd{
- Name: cmdPreconnect,
- Collector: calculatePreconnectHost(cs.License, preconnectHostOverride),
- Data: preconnectData,
- MaxPayloadSize: maxPayloadSizeInBytes,
- }
-
- resp := CollectorRequest(call, cs)
- if nil != resp.Err {
- return nil, resp
- }
-
- var preconnect struct {
- Preconnect PreconnectReply `json:"return_value"`
- }
- err = json.Unmarshal(resp.body, &preconnect)
- if nil != err {
- // Certain security policy errors must be treated as a disconnect.
- return nil, RPMResponse{
- Err: fmt.Errorf("unable to process preconnect reply: %v", err),
- disconnectSecurityPolicy: isDisconnectSecurityPolicyError(err),
- }
- }
-
- js, err := config.CreateConnectJSON(preconnect.Preconnect.SecurityPolicies.PointerIfPopulated())
- if nil != err {
- return nil, RPMResponse{Err: fmt.Errorf("unable to create connect data: %v", err)}
- }
-
- call.Collector = preconnect.Preconnect.Collector
- call.Data = js
- call.Name = cmdConnect
-
- resp = CollectorRequest(call, cs)
- if nil != resp.Err {
- return nil, resp
- }
-
- reply, err := constructConnectReply(resp.body, preconnect.Preconnect)
- if nil != err {
- return nil, RPMResponse{Err: err}
- }
-
- // Note: This should never happen. It would mean the collector
- // response is malformed. This exists merely as extra defensiveness.
- if "" == reply.RunID {
- return nil, RPMResponse{Err: errMissingAgentRunID}
- }
-
- return reply, resp
-}
-
-func constructConnectReply(body []byte, preconnect PreconnectReply) (*ConnectReply, error) {
- var reply struct {
- Reply *ConnectReply `json:"return_value"`
- }
- reply.Reply = ConnectReplyDefaults()
- err := json.Unmarshal(body, &reply)
- if nil != err {
- return nil, fmt.Errorf("unable to parse connect reply: %v", err)
- }
-
- reply.Reply.PreconnectReply = preconnect
-
- reply.Reply.AdaptiveSampler = NewAdaptiveSampler(
- time.Duration(reply.Reply.SamplingTargetPeriodInSeconds)*time.Second,
- reply.Reply.SamplingTarget,
- time.Now())
- reply.Reply.rulesCache = newRulesCache(txnNameCacheLimit)
-
- if reply.Reply.EventData.EventReportPeriodMs <= 0 {
- reply.Reply.EventData.EventReportPeriodMs = defaultConfigurableEventHarvestMs
- }
-
- return reply.Reply, nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/compress.go b/vendor/github.com/newrelic/go-agent/internal/compress.go
deleted file mode 100644
index b20b9600f5e..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/compress.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package internal
-
-import (
- "bytes"
- "compress/gzip"
-)
-
-func compress(b []byte) (*bytes.Buffer, error) {
- var buf bytes.Buffer
- w := gzip.NewWriter(&buf)
- _, err := w.Write(b)
- w.Close()
-
- if nil != err {
- return nil, err
- }
-
- return &buf, nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/connect_reply.go b/vendor/github.com/newrelic/go-agent/internal/connect_reply.go
deleted file mode 100644
index 315f5e0f2e5..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/connect_reply.go
+++ /dev/null
@@ -1,237 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "strings"
- "time"
-)
-
-// AgentRunID identifies the current connection with the collector.
-type AgentRunID string
-
-func (id AgentRunID) String() string {
- return string(id)
-}
-
-// PreconnectReply contains settings from the preconnect endpoint.
-type PreconnectReply struct {
- Collector string `json:"redirect_host"`
- SecurityPolicies SecurityPolicies `json:"security_policies"`
-}
-
-// ConnectReply contains all of the settings and state send down from the
-// collector. It should not be modified after creation.
-type ConnectReply struct {
- RunID AgentRunID `json:"agent_run_id"`
- RequestHeadersMap map[string]string `json:"request_headers_map"`
- MaxPayloadSizeInBytes int `json:"max_payload_size_in_bytes"`
- EntityGUID string `json:"entity_guid"`
-
- // Transaction Name Modifiers
- SegmentTerms segmentRules `json:"transaction_segment_terms"`
- TxnNameRules metricRules `json:"transaction_name_rules"`
- URLRules metricRules `json:"url_rules"`
- MetricRules metricRules `json:"metric_name_rules"`
-
- // Cross Process
- EncodingKey string `json:"encoding_key"`
- CrossProcessID string `json:"cross_process_id"`
- TrustedAccounts trustedAccountSet `json:"trusted_account_ids"`
-
- // Settings
- KeyTxnApdex map[string]float64 `json:"web_transactions_apdex"`
- ApdexThresholdSeconds float64 `json:"apdex_t"`
- CollectAnalyticsEvents bool `json:"collect_analytics_events"`
- CollectCustomEvents bool `json:"collect_custom_events"`
- CollectTraces bool `json:"collect_traces"`
- CollectErrors bool `json:"collect_errors"`
- CollectErrorEvents bool `json:"collect_error_events"`
- CollectSpanEvents bool `json:"collect_span_events"`
-
- // RUM
- AgentLoader string `json:"js_agent_loader"`
- Beacon string `json:"beacon"`
- BrowserKey string `json:"browser_key"`
- AppID string `json:"application_id"`
- ErrorBeacon string `json:"error_beacon"`
- JSAgentFile string `json:"js_agent_file"`
-
- // PreconnectReply fields are not in the connect reply, this embedding
- // is done to simplify code.
- PreconnectReply `json:"-"`
-
- Messages []struct {
- Message string `json:"message"`
- Level string `json:"level"`
- } `json:"messages"`
-
- AdaptiveSampler AdaptiveSampler
- // TraceIDGenerator creates random IDs for distributed tracing. It
- // exists here in the connect reply so it can be modified to create
- // deterministic identifiers in tests.
- TraceIDGenerator *TraceIDGenerator `json:"-"`
-
- // BetterCAT/Distributed Tracing
- AccountID string `json:"account_id"`
- TrustedAccountKey string `json:"trusted_account_key"`
- PrimaryAppID string `json:"primary_application_id"`
- SamplingTarget uint64 `json:"sampling_target"`
- SamplingTargetPeriodInSeconds int `json:"sampling_target_period_in_seconds"`
-
- // rulesCache caches the results of calling CreateFullTxnName. It
- // exists here in ConnectReply since it is specific to a set of rules
- // and is shared between transactions.
- rulesCache *rulesCache
-
- ServerSideConfig struct {
- TransactionTracerEnabled *bool `json:"transaction_tracer.enabled"`
- // TransactionTracerThreshold should contain either a number or
- // "apdex_f" if it is non-nil.
- TransactionTracerThreshold interface{} `json:"transaction_tracer.transaction_threshold"`
- TransactionTracerStackTraceThreshold *float64 `json:"transaction_tracer.stack_trace_threshold"`
- ErrorCollectorEnabled *bool `json:"error_collector.enabled"`
- ErrorCollectorIgnoreStatusCodes []int `json:"error_collector.ignore_status_codes"`
- CrossApplicationTracerEnabled *bool `json:"cross_application_tracer.enabled"`
- } `json:"agent_config"`
-
- // Faster Event Harvest
- EventData EventHarvestConfig `json:"event_harvest_config"`
-}
-
-// EventHarvestConfig contains fields relating to faster event harvest.
-// This structure is used in the connect request (to send up defaults)
-// and in the connect response (to get the server values).
-//
-// https://source.datanerd.us/agents/agent-specs/blob/master/Connect-LEGACY.md#event_harvest_config-hash
-// https://source.datanerd.us/agents/agent-specs/blob/master/Connect-LEGACY.md#event-harvest-config
-type EventHarvestConfig struct {
- EventReportPeriodMs int `json:"report_period_ms"`
- HarvestLimits struct {
- TxnEvents uint `json:"analytic_event_data"`
- CustomEvents uint `json:"custom_event_data"`
- ErrorEvents uint `json:"error_event_data"`
- } `json:"harvest_limits"`
-}
-
-func (r *ConnectReply) getHarvestData() EventHarvestConfig {
- if nil != r {
- return r.EventData
- }
- return DefaultEventHarvestConfig()
-}
-
-// DefaultEventHarvestConfig provides faster event harvest defaults.
-func DefaultEventHarvestConfig() EventHarvestConfig {
- cfg := EventHarvestConfig{}
- cfg.EventReportPeriodMs = defaultConfigurableEventHarvestMs
- cfg.HarvestLimits.TxnEvents = maxTxnEvents
- cfg.HarvestLimits.CustomEvents = maxCustomEvents
- cfg.HarvestLimits.ErrorEvents = maxErrorEvents
- return cfg
-}
-
-func (h EventHarvestConfig) eventReportPeriod() time.Duration {
- return time.Duration(h.EventReportPeriodMs) * time.Millisecond
-}
-
-type trustedAccountSet map[int]struct{}
-
-func (t *trustedAccountSet) IsTrusted(account int) bool {
- _, exists := (*t)[account]
- return exists
-}
-
-func (t *trustedAccountSet) UnmarshalJSON(data []byte) error {
- accounts := make([]int, 0)
- if err := json.Unmarshal(data, &accounts); err != nil {
- return err
- }
-
- *t = make(trustedAccountSet)
- for _, account := range accounts {
- (*t)[account] = struct{}{}
- }
-
- return nil
-}
-
-// ConnectReplyDefaults returns a newly allocated ConnectReply with the proper
-// default settings. A pointer to a global is not used to prevent consumers
-// from changing the default settings.
-func ConnectReplyDefaults() *ConnectReply {
- return &ConnectReply{
- ApdexThresholdSeconds: 0.5,
- CollectAnalyticsEvents: true,
- CollectCustomEvents: true,
- CollectTraces: true,
- CollectErrors: true,
- CollectErrorEvents: true,
- CollectSpanEvents: true,
- MaxPayloadSizeInBytes: maxPayloadSizeInBytes,
- // No transactions should be sampled before the application is
- // connected.
- AdaptiveSampler: SampleNothing{},
-
- SamplingTarget: 10,
- SamplingTargetPeriodInSeconds: 60,
-
- EventData: DefaultEventHarvestConfig(),
-
- TraceIDGenerator: NewTraceIDGenerator(int64(time.Now().UnixNano())),
- }
-}
-
-// CalculateApdexThreshold calculates the apdex threshold.
-func CalculateApdexThreshold(c *ConnectReply, txnName string) time.Duration {
- if t, ok := c.KeyTxnApdex[txnName]; ok {
- return FloatSecondsToDuration(t)
- }
- return FloatSecondsToDuration(c.ApdexThresholdSeconds)
-}
-
-// CreateFullTxnName uses collector rules and the appropriate metric prefix to
-// construct the full transaction metric name from the name given by the
-// consumer.
-func CreateFullTxnName(input string, reply *ConnectReply, isWeb bool) string {
- if name := reply.rulesCache.find(input, isWeb); "" != name {
- return name
- }
- name := constructFullTxnName(input, reply, isWeb)
- if "" != name {
- // Note that we don't cache situations where the rules say
- // ignore. It would increase complication (we would need to
- // disambiguate not-found vs ignore). Also, the ignore code
- // path is probably extremely uncommon.
- reply.rulesCache.set(input, isWeb, name)
- }
- return name
-}
-
-func constructFullTxnName(input string, reply *ConnectReply, isWeb bool) string {
- var afterURLRules string
- if "" != input {
- afterURLRules = reply.URLRules.Apply(input)
- if "" == afterURLRules {
- return ""
- }
- }
-
- prefix := backgroundMetricPrefix
- if isWeb {
- prefix = webMetricPrefix
- }
-
- var beforeNameRules string
- if strings.HasPrefix(afterURLRules, "/") {
- beforeNameRules = prefix + afterURLRules
- } else {
- beforeNameRules = prefix + "/" + afterURLRules
- }
-
- afterNameRules := reply.TxnNameRules.Apply(beforeNameRules)
- if "" == afterNameRules {
- return ""
- }
-
- return reply.SegmentTerms.apply(afterNameRules)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/context.go b/vendor/github.com/newrelic/go-agent/internal/context.go
deleted file mode 100644
index 2b3cab688c6..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/context.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package internal
-
-type contextKeyType struct{}
-
-var (
- // TransactionContextKey is the key used for newrelic.FromContext and
- // newrelic.NewContext.
- TransactionContextKey = contextKeyType(struct{}{})
-
- // GinTransactionContextKey is used as the context key in
- // nrgin.Middleware and nrgin.Transaction. Unfortunately, Gin requires
- // a string context key. We use two different context keys (and check
- // both in nrgin.Transaction and newrelic.FromContext) rather than use a
- // single string key because context.WithValue will fail golint if used
- // with a string key.
- GinTransactionContextKey = "newRelicTransaction"
-)
diff --git a/vendor/github.com/newrelic/go-agent/internal/cross_process_http.go b/vendor/github.com/newrelic/go-agent/internal/cross_process_http.go
deleted file mode 100644
index 73145c62c03..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/cross_process_http.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package internal
-
-import (
- "net/http"
-
- "github.com/newrelic/go-agent/internal/cat"
-)
-
-// InboundHTTPRequest adds the inbound request metadata to the TxnCrossProcess.
-func (txp *TxnCrossProcess) InboundHTTPRequest(hdr http.Header) error {
- return txp.handleInboundRequestHeaders(HTTPHeaderToMetadata(hdr))
-}
-
-// AppDataToHTTPHeader encapsulates the given appData value in the correct HTTP
-// header.
-func AppDataToHTTPHeader(appData string) http.Header {
- header := http.Header{}
-
- if appData != "" {
- header.Add(cat.NewRelicAppDataName, appData)
- }
-
- return header
-}
-
-// HTTPHeaderToAppData gets the appData value from the correct HTTP header.
-func HTTPHeaderToAppData(header http.Header) string {
- if header == nil {
- return ""
- }
-
- return header.Get(cat.NewRelicAppDataName)
-}
-
-// HTTPHeaderToMetadata gets the cross process metadata from the relevant HTTP
-// headers.
-func HTTPHeaderToMetadata(header http.Header) CrossProcessMetadata {
- if header == nil {
- return CrossProcessMetadata{}
- }
-
- return CrossProcessMetadata{
- ID: header.Get(cat.NewRelicIDName),
- TxnData: header.Get(cat.NewRelicTxnName),
- Synthetics: header.Get(cat.NewRelicSyntheticsName),
- }
-}
-
-// MetadataToHTTPHeader creates a set of HTTP headers to represent the given
-// cross process metadata.
-func MetadataToHTTPHeader(metadata CrossProcessMetadata) http.Header {
- header := http.Header{}
-
- if metadata.ID != "" {
- header.Add(cat.NewRelicIDName, metadata.ID)
- }
-
- if metadata.TxnData != "" {
- header.Add(cat.NewRelicTxnName, metadata.TxnData)
- }
-
- if metadata.Synthetics != "" {
- header.Add(cat.NewRelicSyntheticsName, metadata.Synthetics)
- }
-
- return header
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/custom_event.go b/vendor/github.com/newrelic/go-agent/internal/custom_event.go
deleted file mode 100644
index 20cf5918ae6..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/custom_event.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package internal
-
-import (
- "bytes"
- "fmt"
- "regexp"
- "time"
-)
-
-// https://newrelic.atlassian.net/wiki/display/eng/Custom+Events+in+New+Relic+Agents
-
-var (
- eventTypeRegexRaw = `^[a-zA-Z0-9:_ ]+$`
- eventTypeRegex = regexp.MustCompile(eventTypeRegexRaw)
-
- errEventTypeLength = fmt.Errorf("event type exceeds length limit of %d",
- attributeKeyLengthLimit)
- // ErrEventTypeRegex will be returned to caller of app.RecordCustomEvent
- // if the event type is not valid.
- ErrEventTypeRegex = fmt.Errorf("event type must match %s", eventTypeRegexRaw)
- errNumAttributes = fmt.Errorf("maximum of %d attributes exceeded",
- customEventAttributeLimit)
-)
-
-// CustomEvent is a custom event.
-type CustomEvent struct {
- eventType string
- timestamp time.Time
- truncatedParams map[string]interface{}
-}
-
-// WriteJSON prepares JSON in the format expected by the collector.
-func (e *CustomEvent) WriteJSON(buf *bytes.Buffer) {
- w := jsonFieldsWriter{buf: buf}
- buf.WriteByte('[')
- buf.WriteByte('{')
- w.stringField("type", e.eventType)
- w.floatField("timestamp", timeToFloatSeconds(e.timestamp))
- buf.WriteByte('}')
-
- buf.WriteByte(',')
- buf.WriteByte('{')
- w = jsonFieldsWriter{buf: buf}
- for key, val := range e.truncatedParams {
- writeAttributeValueJSON(&w, key, val)
- }
- buf.WriteByte('}')
-
- buf.WriteByte(',')
- buf.WriteByte('{')
- buf.WriteByte('}')
- buf.WriteByte(']')
-}
-
-// MarshalJSON is used for testing.
-func (e *CustomEvent) MarshalJSON() ([]byte, error) {
- buf := bytes.NewBuffer(make([]byte, 0, 256))
-
- e.WriteJSON(buf)
-
- return buf.Bytes(), nil
-}
-
-func eventTypeValidate(eventType string) error {
- if len(eventType) > attributeKeyLengthLimit {
- return errEventTypeLength
- }
- if !eventTypeRegex.MatchString(eventType) {
- return ErrEventTypeRegex
- }
- return nil
-}
-
-// CreateCustomEvent creates a custom event.
-func CreateCustomEvent(eventType string, params map[string]interface{}, now time.Time) (*CustomEvent, error) {
- if err := eventTypeValidate(eventType); nil != err {
- return nil, err
- }
-
- if len(params) > customEventAttributeLimit {
- return nil, errNumAttributes
- }
-
- truncatedParams := make(map[string]interface{})
- for key, val := range params {
- val, err := ValidateUserAttribute(key, val)
- if nil != err {
- return nil, err
- }
- truncatedParams[key] = val
- }
-
- return &CustomEvent{
- eventType: eventType,
- timestamp: now,
- truncatedParams: truncatedParams,
- }, nil
-}
-
-// MergeIntoHarvest implements Harvestable.
-func (e *CustomEvent) MergeIntoHarvest(h *Harvest) {
- h.CustomEvents.Add(e)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/custom_events.go b/vendor/github.com/newrelic/go-agent/internal/custom_events.go
deleted file mode 100644
index d58121aeb6f..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/custom_events.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package internal
-
-import (
- "time"
-)
-
-type customEvents struct {
- *analyticsEvents
-}
-
-func newCustomEvents(max int) *customEvents {
- return &customEvents{
- analyticsEvents: newAnalyticsEvents(max),
- }
-}
-
-func (cs *customEvents) Add(e *CustomEvent) {
- // For the Go Agent, customEvents are added to the application, not the transaction.
- // As a result, customEvents do not inherit their priority from the transaction, though
- // they are still sampled according to priority sampling.
- priority := NewPriority()
- cs.addEvent(analyticsEvent{priority, e})
-}
-
-func (cs *customEvents) MergeIntoHarvest(h *Harvest) {
- h.CustomEvents.mergeFailed(cs.analyticsEvents)
-}
-
-func (cs *customEvents) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
- return cs.CollectorJSON(agentRunID)
-}
-
-func (cs *customEvents) EndpointMethod() string {
- return cmdCustomEvents
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/custom_metric.go b/vendor/github.com/newrelic/go-agent/internal/custom_metric.go
deleted file mode 100644
index 61600aea2b5..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/custom_metric.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package internal
-
-// CustomMetric is a custom metric.
-type CustomMetric struct {
- RawInputName string
- Value float64
-}
-
-// MergeIntoHarvest implements Harvestable.
-func (m CustomMetric) MergeIntoHarvest(h *Harvest) {
- h.Metrics.addValue(customMetric(m.RawInputName), "", m.Value, unforced)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/distributed_tracing.go b/vendor/github.com/newrelic/go-agent/internal/distributed_tracing.go
deleted file mode 100644
index 82af9b6674d..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/distributed_tracing.go
+++ /dev/null
@@ -1,203 +0,0 @@
-package internal
-
-import (
- "encoding/base64"
- "encoding/json"
- "fmt"
- "time"
-)
-
-type distTraceVersion [2]int
-
-func (v distTraceVersion) major() int { return v[0] }
-func (v distTraceVersion) minor() int { return v[1] }
-
-const (
- // CallerType is the Type field's value for outbound payloads.
- CallerType = "App"
-)
-
-var (
- currentDistTraceVersion = distTraceVersion([2]int{0 /* Major */, 1 /* Minor */})
- callerUnknown = payloadCaller{Type: "Unknown", App: "Unknown", Account: "Unknown", TransportType: "Unknown"}
-)
-
-// timestampMillis allows raw payloads to use exact times, and marshalled
-// payloads to use times in millis.
-type timestampMillis time.Time
-
-func (tm *timestampMillis) UnmarshalJSON(data []byte) error {
- var millis uint64
- if err := json.Unmarshal(data, &millis); nil != err {
- return err
- }
- *tm = timestampMillis(timeFromUnixMilliseconds(millis))
- return nil
-}
-
-func (tm timestampMillis) MarshalJSON() ([]byte, error) {
- return json.Marshal(TimeToUnixMilliseconds(tm.Time()))
-}
-
-func (tm timestampMillis) Time() time.Time { return time.Time(tm) }
-func (tm *timestampMillis) Set(t time.Time) { *tm = timestampMillis(t) }
-
-// Payload is the distributed tracing payload.
-type Payload struct {
- payloadCaller
- TransactionID string `json:"tx,omitempty"`
- ID string `json:"id,omitempty"`
- TracedID string `json:"tr"`
- Priority Priority `json:"pr"`
- Sampled *bool `json:"sa"`
- Timestamp timestampMillis `json:"ti"`
- TransportDuration time.Duration `json:"-"`
-}
-
-type payloadCaller struct {
- TransportType string `json:"-"`
- Type string `json:"ty"`
- App string `json:"ap"`
- Account string `json:"ac"`
- TrustedAccountKey string `json:"tk,omitempty"`
-}
-
-// IsValid validates the payload data by looking for missing fields.
-// Returns an error if there's a problem, nil if everything's fine
-func (p Payload) IsValid() error {
-
- // If a payload is missing both `guid` and `transactionId` is received,
- // a ParseException supportability metric should be generated.
- if "" == p.TransactionID && "" == p.ID {
- return ErrPayloadMissingField{message: "missing both guid/id and TransactionId/tx"}
- }
-
- if "" == p.Type {
- return ErrPayloadMissingField{message: "missing Type/ty"}
- }
-
- if "" == p.Account {
- return ErrPayloadMissingField{message: "missing Account/ac"}
- }
-
- if "" == p.App {
- return ErrPayloadMissingField{message: "missing App/ap"}
- }
-
- if "" == p.TracedID {
- return ErrPayloadMissingField{message: "missing TracedID/tr"}
- }
-
- if p.Timestamp.Time().IsZero() || 0 == p.Timestamp.Time().Unix() {
- return ErrPayloadMissingField{message: "missing Timestamp/ti"}
- }
-
- return nil
-}
-
-func (p Payload) text(v distTraceVersion) []byte {
- js, _ := json.Marshal(struct {
- Version distTraceVersion `json:"v"`
- Data Payload `json:"d"`
- }{
- Version: v,
- Data: p,
- })
- return js
-}
-
-// Text implements newrelic.DistributedTracePayload.
-func (p Payload) Text() string {
- t := p.text(currentDistTraceVersion)
- return string(t)
-}
-
-// HTTPSafe implements newrelic.DistributedTracePayload.
-func (p Payload) HTTPSafe() string {
- t := p.text(currentDistTraceVersion)
- return base64.StdEncoding.EncodeToString(t)
-}
-
-// SetSampled lets us set a value for our *bool,
-// which we can't do directly since a pointer
-// needs something to point at.
-func (p *Payload) SetSampled(sampled bool) {
- p.Sampled = &sampled
-}
-
-// ErrPayloadParse indicates that the payload was malformed.
-type ErrPayloadParse struct{ err error }
-
-func (e ErrPayloadParse) Error() string {
- return fmt.Sprintf("unable to parse inbound payload: %s", e.err.Error())
-}
-
-// ErrPayloadMissingField indicates there's a required field that's missing
-type ErrPayloadMissingField struct{ message string }
-
-func (e ErrPayloadMissingField) Error() string {
- return fmt.Sprintf("payload is missing required fields: %s", e.message)
-}
-
-// ErrUnsupportedPayloadVersion indicates that the major version number is
-// unknown.
-type ErrUnsupportedPayloadVersion struct{ version int }
-
-func (e ErrUnsupportedPayloadVersion) Error() string {
- return fmt.Sprintf("unsupported major version number %d", e.version)
-}
-
-// AcceptPayload parses the inbound distributed tracing payload.
-func AcceptPayload(p interface{}) (*Payload, error) {
- var payload Payload
- if byteSlice, ok := p.([]byte); ok {
- p = string(byteSlice)
- }
- switch v := p.(type) {
- case string:
- if "" == v {
- return nil, nil
- }
- var decoded []byte
- if '{' == v[0] {
- decoded = []byte(v)
- } else {
- var err error
- decoded, err = base64.StdEncoding.DecodeString(v)
- if nil != err {
- return nil, ErrPayloadParse{err: err}
- }
- }
- envelope := struct {
- Version distTraceVersion `json:"v"`
- Data json.RawMessage `json:"d"`
- }{}
- if err := json.Unmarshal(decoded, &envelope); nil != err {
- return nil, ErrPayloadParse{err: err}
- }
-
- if 0 == envelope.Version.major() && 0 == envelope.Version.minor() {
- return nil, ErrPayloadMissingField{message: "missing v"}
- }
-
- if envelope.Version.major() > currentDistTraceVersion.major() {
- return nil, ErrUnsupportedPayloadVersion{
- version: envelope.Version.major(),
- }
- }
- if err := json.Unmarshal(envelope.Data, &payload); nil != err {
- return nil, ErrPayloadParse{err: err}
- }
- case Payload:
- payload = v
- default:
- // Could be a shim payload (if the app is not yet connected).
- return nil, nil
- }
- // Ensure that we don't have a reference to the input payload: we don't
- // want to change it, it could be used multiple times.
- alloc := new(Payload)
- *alloc = payload
-
- return alloc, nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/environment.go b/vendor/github.com/newrelic/go-agent/internal/environment.go
deleted file mode 100644
index f7f27801226..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/environment.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "reflect"
- "runtime"
-)
-
-// Environment describes the application's environment.
-type Environment struct {
- Compiler string `env:"runtime.Compiler"`
- GOARCH string `env:"runtime.GOARCH"`
- GOOS string `env:"runtime.GOOS"`
- Version string `env:"runtime.Version"`
- NumCPU int `env:"runtime.NumCPU"`
-}
-
-var (
- // SampleEnvironment is useful for testing.
- SampleEnvironment = Environment{
- Compiler: "comp",
- GOARCH: "arch",
- GOOS: "goos",
- Version: "vers",
- NumCPU: 8,
- }
-)
-
-// NewEnvironment returns a new Environment.
-func NewEnvironment() Environment {
- return Environment{
- Compiler: runtime.Compiler,
- GOARCH: runtime.GOARCH,
- GOOS: runtime.GOOS,
- Version: runtime.Version(),
- NumCPU: runtime.NumCPU(),
- }
-}
-
-// MarshalJSON prepares Environment JSON in the format expected by the collector
-// during the connect command.
-func (e Environment) MarshalJSON() ([]byte, error) {
- var arr [][]interface{}
-
- val := reflect.ValueOf(e)
- numFields := val.NumField()
-
- arr = make([][]interface{}, numFields)
-
- for i := 0; i < numFields; i++ {
- v := val.Field(i)
- t := val.Type().Field(i).Tag.Get("env")
-
- arr[i] = []interface{}{
- t,
- v.Interface(),
- }
- }
-
- return json.Marshal(arr)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/error_events.go b/vendor/github.com/newrelic/go-agent/internal/error_events.go
deleted file mode 100644
index 08f607dbef9..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/error_events.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package internal
-
-import (
- "bytes"
- "time"
-)
-
-// MarshalJSON is used for testing.
-func (e *ErrorEvent) MarshalJSON() ([]byte, error) {
- buf := bytes.NewBuffer(make([]byte, 0, 256))
-
- e.WriteJSON(buf)
-
- return buf.Bytes(), nil
-}
-
-// WriteJSON prepares JSON in the format expected by the collector.
-// https://source.datanerd.us/agents/agent-specs/blob/master/Error-Events.md
-func (e *ErrorEvent) WriteJSON(buf *bytes.Buffer) {
- w := jsonFieldsWriter{buf: buf}
- buf.WriteByte('[')
- buf.WriteByte('{')
- w.stringField("type", "TransactionError")
- w.stringField("error.class", e.Klass)
- w.stringField("error.message", e.Msg)
- w.floatField("timestamp", timeToFloatSeconds(e.When))
- w.stringField("transactionName", e.FinalName)
-
- sharedTransactionIntrinsics(&e.TxnEvent, &w)
- sharedBetterCATIntrinsics(&e.TxnEvent, &w)
-
- buf.WriteByte('}')
- buf.WriteByte(',')
- userAttributesJSON(e.Attrs, buf, destError, e.ErrorData.ExtraAttributes)
- buf.WriteByte(',')
- agentAttributesJSON(e.Attrs, buf, destError)
- buf.WriteByte(']')
-}
-
-type errorEvents struct {
- *analyticsEvents
-}
-
-func newErrorEvents(max int) *errorEvents {
- return &errorEvents{
- analyticsEvents: newAnalyticsEvents(max),
- }
-}
-
-func (events *errorEvents) Add(e *ErrorEvent, priority Priority) {
- events.addEvent(analyticsEvent{priority, e})
-}
-
-func (events *errorEvents) MergeIntoHarvest(h *Harvest) {
- h.ErrorEvents.mergeFailed(events.analyticsEvents)
-}
-
-func (events *errorEvents) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
- return events.CollectorJSON(agentRunID)
-}
-
-func (events *errorEvents) EndpointMethod() string {
- return cmdErrorEvents
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/errors.go b/vendor/github.com/newrelic/go-agent/internal/errors.go
deleted file mode 100644
index 23dec702991..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/errors.go
+++ /dev/null
@@ -1,175 +0,0 @@
-package internal
-
-import (
- "bytes"
- "fmt"
- "net/http"
- "strconv"
- "time"
-
- "github.com/newrelic/go-agent/internal/jsonx"
-)
-
-const (
- // PanicErrorKlass is the error klass used for errors generated by
- // recovering panics in txn.End.
- PanicErrorKlass = "panic"
-)
-
-func panicValueMsg(v interface{}) string {
- switch val := v.(type) {
- case error:
- return val.Error()
- default:
- return fmt.Sprintf("%v", v)
- }
-}
-
-// TxnErrorFromPanic creates a new TxnError from a panic.
-func TxnErrorFromPanic(now time.Time, v interface{}) ErrorData {
- return ErrorData{
- When: now,
- Msg: panicValueMsg(v),
- Klass: PanicErrorKlass,
- }
-}
-
-// TxnErrorFromResponseCode creates a new TxnError from an http response code.
-func TxnErrorFromResponseCode(now time.Time, code int) ErrorData {
- codeStr := strconv.Itoa(code)
- msg := http.StatusText(code)
- if msg == "" {
- // Use a generic message if the code was not an http code
- // to support gRPC.
- msg = "response code " + codeStr
- }
- return ErrorData{
- When: now,
- Msg: msg,
- Klass: codeStr,
- }
-}
-
-// ErrorData contains the information about a recorded error.
-type ErrorData struct {
- When time.Time
- Stack StackTrace
- ExtraAttributes map[string]interface{}
- Msg string
- Klass string
-}
-
-// TxnError combines error data with information about a transaction. TxnError is used for
-// both error events and traced errors.
-type TxnError struct {
- ErrorData
- TxnEvent
-}
-
-// ErrorEvent and tracedError are separate types so that error events and traced errors can have
-// different WriteJSON methods.
-type ErrorEvent TxnError
-
-type tracedError TxnError
-
-// TxnErrors is a set of errors captured in a Transaction.
-type TxnErrors []*ErrorData
-
-// NewTxnErrors returns a new empty TxnErrors.
-func NewTxnErrors(max int) TxnErrors {
- return make([]*ErrorData, 0, max)
-}
-
-// Add adds a TxnError.
-func (errors *TxnErrors) Add(e ErrorData) {
- if len(*errors) < cap(*errors) {
- *errors = append(*errors, &e)
- }
-}
-
-func (h *tracedError) WriteJSON(buf *bytes.Buffer) {
- buf.WriteByte('[')
- jsonx.AppendFloat(buf, timeToFloatMilliseconds(h.When))
- buf.WriteByte(',')
- jsonx.AppendString(buf, h.FinalName)
- buf.WriteByte(',')
- jsonx.AppendString(buf, h.Msg)
- buf.WriteByte(',')
- jsonx.AppendString(buf, h.Klass)
- buf.WriteByte(',')
-
- buf.WriteByte('{')
- buf.WriteString(`"agentAttributes"`)
- buf.WriteByte(':')
- agentAttributesJSON(h.Attrs, buf, destError)
- buf.WriteByte(',')
- buf.WriteString(`"userAttributes"`)
- buf.WriteByte(':')
- userAttributesJSON(h.Attrs, buf, destError, h.ErrorData.ExtraAttributes)
- buf.WriteByte(',')
- buf.WriteString(`"intrinsics"`)
- buf.WriteByte(':')
- intrinsicsJSON(&h.TxnEvent, buf)
- if nil != h.Stack {
- buf.WriteByte(',')
- buf.WriteString(`"stack_trace"`)
- buf.WriteByte(':')
- h.Stack.WriteJSON(buf)
- }
- buf.WriteByte('}')
-
- buf.WriteByte(']')
-}
-
-// MarshalJSON is used for testing.
-func (h *tracedError) MarshalJSON() ([]byte, error) {
- buf := &bytes.Buffer{}
- h.WriteJSON(buf)
- return buf.Bytes(), nil
-}
-
-type harvestErrors []*tracedError
-
-func newHarvestErrors(max int) harvestErrors {
- return make([]*tracedError, 0, max)
-}
-
-// MergeTxnErrors merges a transaction's errors into the harvest's errors.
-func MergeTxnErrors(errors *harvestErrors, errs TxnErrors, txnEvent TxnEvent) {
- for _, e := range errs {
- if len(*errors) == cap(*errors) {
- return
- }
- *errors = append(*errors, &tracedError{
- TxnEvent: txnEvent,
- ErrorData: *e,
- })
- }
-}
-
-func (errors harvestErrors) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
- if 0 == len(errors) {
- return nil, nil
- }
- estimate := 1024 * len(errors)
- buf := bytes.NewBuffer(make([]byte, 0, estimate))
- buf.WriteByte('[')
- jsonx.AppendString(buf, agentRunID)
- buf.WriteByte(',')
- buf.WriteByte('[')
- for i, e := range errors {
- if i > 0 {
- buf.WriteByte(',')
- }
- e.WriteJSON(buf)
- }
- buf.WriteByte(']')
- buf.WriteByte(']')
- return buf.Bytes(), nil
-}
-
-func (errors harvestErrors) MergeIntoHarvest(h *Harvest) {}
-
-func (errors harvestErrors) EndpointMethod() string {
- return cmdErrorData
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/expect.go b/vendor/github.com/newrelic/go-agent/internal/expect.go
deleted file mode 100644
index deff8f23833..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/expect.go
+++ /dev/null
@@ -1,591 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "fmt"
- "runtime"
-
- "time"
-)
-
-var (
- // Unfortunately, the resolution of time.Now() on Windows is coarse: Two
- // sequential calls to time.Now() may return the same value, and tests
- // which expect non-zero durations may fail. To avoid adding sleep
- // statements or mocking time.Now(), those tests are skipped on Windows.
- doDurationTests = runtime.GOOS != `windows`
-)
-
-// Validator is used for testing.
-type Validator interface {
- Error(...interface{})
-}
-
-func validateStringField(v Validator, fieldName, v1, v2 string) {
- if v1 != v2 {
- v.Error(fieldName, v1, v2)
- }
-}
-
-type addValidatorField struct {
- field interface{}
- original Validator
-}
-
-func (a addValidatorField) Error(fields ...interface{}) {
- fields = append([]interface{}{a.field}, fields...)
- a.original.Error(fields...)
-}
-
-// ExtendValidator is used to add more context to a validator.
-func ExtendValidator(v Validator, field interface{}) Validator {
- return addValidatorField{
- field: field,
- original: v,
- }
-}
-
-// WantMetric is a metric expectation. If Data is nil, then any data values are
-// acceptable. If Data has len 1, then only the metric count is validated.
-type WantMetric struct {
- Name string
- Scope string
- Forced interface{} // true, false, or nil
- Data []float64
-}
-
-// WantError is a traced error expectation.
-type WantError struct {
- TxnName string
- Msg string
- Klass string
- UserAttributes map[string]interface{}
- AgentAttributes map[string]interface{}
-}
-
-func uniquePointer() *struct{} {
- s := struct{}{}
- return &s
-}
-
-var (
- // MatchAnything is for use when matching attributes.
- MatchAnything = uniquePointer()
-)
-
-// WantEvent is a transaction or error event expectation.
-type WantEvent struct {
- Intrinsics map[string]interface{}
- UserAttributes map[string]interface{}
- AgentAttributes map[string]interface{}
-}
-
-// WantTxnTrace is a transaction trace expectation.
-type WantTxnTrace struct {
- MetricName string
- NumSegments int
- UserAttributes map[string]interface{}
- AgentAttributes map[string]interface{}
- Intrinsics map[string]interface{}
- // If the Root's SegmentName is populated then the segments will be
- // tested, otherwise NumSegments will be tested.
- Root WantTraceSegment
-}
-
-// WantTraceSegment is a transaction trace segment expectation.
-type WantTraceSegment struct {
- SegmentName string
- // RelativeStartMillis and RelativeStopMillis will be tested if they are
- // provided: This makes it easy for top level tests which cannot
- // control duration.
- RelativeStartMillis interface{}
- RelativeStopMillis interface{}
- Attributes map[string]interface{}
- Children []WantTraceSegment
-}
-
-// WantSlowQuery is a slowQuery expectation.
-type WantSlowQuery struct {
- Count int32
- MetricName string
- Query string
- TxnName string
- TxnURL string
- DatabaseName string
- Host string
- PortPathOrID string
- Params map[string]interface{}
-}
-
-// HarvestTestinger is implemented by the app. It sets an empty test harvest
-// and modifies the connect reply if a callback is provided.
-type HarvestTestinger interface {
- HarvestTesting(replyfn func(*ConnectReply))
-}
-
-// HarvestTesting allows integration packages to test instrumentation.
-func HarvestTesting(app interface{}, replyfn func(*ConnectReply)) {
- ta, ok := app.(HarvestTestinger)
- if !ok {
- panic("HarvestTesting type assertion failure")
- }
- ta.HarvestTesting(replyfn)
-}
-
-// WantTxn provides the expectation parameters to ExpectTxnMetrics.
-type WantTxn struct {
- Name string
- IsWeb bool
- NumErrors int
-}
-
-// ExpectTxnMetrics tests that the app contains metrics for a transaction.
-func ExpectTxnMetrics(t Validator, mt *metricTable, want WantTxn) {
- var metrics []WantMetric
- var scope string
- var allWebOther string
- if want.IsWeb {
- scope = "WebTransaction/Go/" + want.Name
- allWebOther = "allWeb"
- metrics = []WantMetric{
- {Name: "WebTransaction/Go/" + want.Name, Scope: "", Forced: true, Data: nil},
- {Name: "WebTransaction", Scope: "", Forced: true, Data: nil},
- {Name: "WebTransactionTotalTime/Go/" + want.Name, Scope: "", Forced: false, Data: nil},
- {Name: "WebTransactionTotalTime", Scope: "", Forced: true, Data: nil},
- {Name: "HttpDispatcher", Scope: "", Forced: true, Data: nil},
- {Name: "Apdex", Scope: "", Forced: true, Data: nil},
- {Name: "Apdex/Go/" + want.Name, Scope: "", Forced: false, Data: nil},
- }
- } else {
- scope = "OtherTransaction/Go/" + want.Name
- allWebOther = "allOther"
- metrics = []WantMetric{
- {Name: "OtherTransaction/Go/" + want.Name, Scope: "", Forced: true, Data: nil},
- {Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
- {Name: "OtherTransactionTotalTime/Go/" + want.Name, Scope: "", Forced: false, Data: nil},
- {Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
- }
- }
- if want.NumErrors > 0 {
- data := []float64{float64(want.NumErrors), 0, 0, 0, 0, 0}
- metrics = append(metrics, []WantMetric{
- {Name: "Errors/all", Scope: "", Forced: true, Data: data},
- {Name: "Errors/" + allWebOther, Scope: "", Forced: true, Data: data},
- {Name: "Errors/" + scope, Scope: "", Forced: true, Data: data},
- }...)
- }
- ExpectMetrics(t, mt, metrics)
-}
-
-// Expect exposes methods that allow for testing whether the correct data was
-// captured.
-type Expect interface {
- ExpectCustomEvents(t Validator, want []WantEvent)
- ExpectErrors(t Validator, want []WantError)
- ExpectErrorEvents(t Validator, want []WantEvent)
-
- ExpectTxnEvents(t Validator, want []WantEvent)
-
- ExpectMetrics(t Validator, want []WantMetric)
- ExpectMetricsPresent(t Validator, want []WantMetric)
- ExpectTxnMetrics(t Validator, want WantTxn)
-
- ExpectTxnTraces(t Validator, want []WantTxnTrace)
- ExpectSlowQueries(t Validator, want []WantSlowQuery)
-
- ExpectSpanEvents(t Validator, want []WantEvent)
-}
-
-func expectMetricField(t Validator, id metricID, v1, v2 float64, fieldName string) {
- if v1 != v2 {
- t.Error("metric fields do not match", id, v1, v2, fieldName)
- }
-}
-
-// ExpectMetricsPresent allows testing of metrics without requiring an exact match
-func ExpectMetricsPresent(t Validator, mt *metricTable, expect []WantMetric) {
- expectMetrics(t, mt, expect, false)
-}
-
-// ExpectMetrics allows testing of metrics. It passes if mt exactly matches expect.
-func ExpectMetrics(t Validator, mt *metricTable, expect []WantMetric) {
- expectMetrics(t, mt, expect, true)
-}
-
-func expectMetrics(t Validator, mt *metricTable, expect []WantMetric, exactMatch bool) {
- if exactMatch {
- if len(mt.metrics) != len(expect) {
- t.Error("metric counts do not match expectations", len(mt.metrics), len(expect))
- }
- }
- expectedIds := make(map[metricID]struct{})
- for _, e := range expect {
- id := metricID{Name: e.Name, Scope: e.Scope}
- expectedIds[id] = struct{}{}
- m := mt.metrics[id]
- if nil == m {
- t.Error("unable to find metric", id)
- continue
- }
-
- if b, ok := e.Forced.(bool); ok {
- if b != (forced == m.forced) {
- t.Error("metric forced incorrect", b, m.forced, id)
- }
- }
-
- if nil != e.Data {
- expectMetricField(t, id, e.Data[0], m.data.countSatisfied, "countSatisfied")
-
- if len(e.Data) > 1 {
- expectMetricField(t, id, e.Data[1], m.data.totalTolerated, "totalTolerated")
- expectMetricField(t, id, e.Data[2], m.data.exclusiveFailed, "exclusiveFailed")
- expectMetricField(t, id, e.Data[3], m.data.min, "min")
- expectMetricField(t, id, e.Data[4], m.data.max, "max")
- expectMetricField(t, id, e.Data[5], m.data.sumSquares, "sumSquares")
- }
- }
- }
- if exactMatch {
- for id := range mt.metrics {
- if _, ok := expectedIds[id]; !ok {
- t.Error("expected metrics does not contain", id.Name, id.Scope)
- }
- }
- }
-}
-
-func expectAttributes(v Validator, exists map[string]interface{}, expect map[string]interface{}) {
- // TODO: This params comparison can be made smarter: Alert differences
- // based on sub/super set behavior.
- if len(exists) != len(expect) {
- v.Error("attributes length difference", len(exists), len(expect))
- }
- for key, val := range expect {
- found, ok := exists[key]
- if !ok {
- v.Error("expected attribute not found: ", key)
- continue
- }
- if val == MatchAnything {
- continue
- }
- v1 := fmt.Sprint(found)
- v2 := fmt.Sprint(val)
- if v1 != v2 {
- v.Error("value difference", fmt.Sprintf("key=%s", key), v1, v2)
- }
- }
- for key, val := range exists {
- _, ok := expect[key]
- if !ok {
- v.Error("unexpected attribute present: ", key, val)
- continue
- }
- }
-}
-
-// ExpectCustomEvents allows testing of custom events. It passes if cs exactly matches expect.
-func ExpectCustomEvents(v Validator, cs *customEvents, expect []WantEvent) {
- expectEvents(v, cs.analyticsEvents, expect, nil)
-}
-
-func expectEvent(v Validator, e json.Marshaler, expect WantEvent) {
- js, err := e.MarshalJSON()
- if nil != err {
- v.Error("unable to marshal event", err)
- return
- }
- var event []map[string]interface{}
- err = json.Unmarshal(js, &event)
- if nil != err {
- v.Error("unable to parse event json", err)
- return
- }
- intrinsics := event[0]
- userAttributes := event[1]
- agentAttributes := event[2]
-
- if nil != expect.Intrinsics {
- expectAttributes(v, intrinsics, expect.Intrinsics)
- }
- if nil != expect.UserAttributes {
- expectAttributes(v, userAttributes, expect.UserAttributes)
- }
- if nil != expect.AgentAttributes {
- expectAttributes(v, agentAttributes, expect.AgentAttributes)
- }
-}
-
-func expectEvents(v Validator, events *analyticsEvents, expect []WantEvent, extraAttributes map[string]interface{}) {
- if len(events.events) != len(expect) {
- v.Error("number of events does not match", len(events.events), len(expect))
- return
- }
- for i, e := range expect {
- event, ok := events.events[i].jsonWriter.(json.Marshaler)
- if !ok {
- v.Error("event does not implement json.Marshaler")
- continue
- }
- if nil != e.Intrinsics {
- e.Intrinsics = mergeAttributes(extraAttributes, e.Intrinsics)
- }
- expectEvent(v, event, e)
- }
-}
-
-// Second attributes have priority.
-func mergeAttributes(a1, a2 map[string]interface{}) map[string]interface{} {
- a := make(map[string]interface{})
- for k, v := range a1 {
- a[k] = v
- }
- for k, v := range a2 {
- a[k] = v
- }
- return a
-}
-
-// ExpectErrorEvents allows testing of error events. It passes if events exactly matches expect.
-func ExpectErrorEvents(v Validator, events *errorEvents, expect []WantEvent) {
- expectEvents(v, events.analyticsEvents, expect, map[string]interface{}{
- // The following intrinsics should always be present in
- // error events:
- "type": "TransactionError",
- "timestamp": MatchAnything,
- "duration": MatchAnything,
- })
-}
-
-// ExpectSpanEvents allows testing of span events. It passes if events exactly matches expect.
-func ExpectSpanEvents(v Validator, events *spanEvents, expect []WantEvent) {
- expectEvents(v, events.analyticsEvents, expect, map[string]interface{}{
- // The following intrinsics should always be present in
- // span events:
- "type": "Span",
- "timestamp": MatchAnything,
- "duration": MatchAnything,
- "traceId": MatchAnything,
- "guid": MatchAnything,
- "transactionId": MatchAnything,
- // All span events are currently sampled.
- "sampled": true,
- "priority": MatchAnything,
- })
-}
-
-// ExpectTxnEvents allows testing of txn events.
-func ExpectTxnEvents(v Validator, events *txnEvents, expect []WantEvent) {
- expectEvents(v, events.analyticsEvents, expect, map[string]interface{}{
- // The following intrinsics should always be present in
- // txn events:
- "type": "Transaction",
- "timestamp": MatchAnything,
- "duration": MatchAnything,
- "totalTime": MatchAnything,
- "error": MatchAnything,
- })
-}
-
-func expectError(v Validator, err *tracedError, expect WantError) {
- validateStringField(v, "txnName", expect.TxnName, err.FinalName)
- validateStringField(v, "klass", expect.Klass, err.Klass)
- validateStringField(v, "msg", expect.Msg, err.Msg)
- js, errr := err.MarshalJSON()
- if nil != errr {
- v.Error("unable to marshal error json", errr)
- return
- }
- var unmarshalled []interface{}
- errr = json.Unmarshal(js, &unmarshalled)
- if nil != errr {
- v.Error("unable to unmarshal error json", errr)
- return
- }
- attributes := unmarshalled[4].(map[string]interface{})
- agentAttributes := attributes["agentAttributes"].(map[string]interface{})
- userAttributes := attributes["userAttributes"].(map[string]interface{})
-
- if nil != expect.UserAttributes {
- expectAttributes(v, userAttributes, expect.UserAttributes)
- }
- if nil != expect.AgentAttributes {
- expectAttributes(v, agentAttributes, expect.AgentAttributes)
- }
- if stack := attributes["stack_trace"]; nil == stack {
- v.Error("missing error stack trace")
- }
-}
-
-// ExpectErrors allows testing of errors.
-func ExpectErrors(v Validator, errors harvestErrors, expect []WantError) {
- if len(errors) != len(expect) {
- v.Error("number of errors mismatch", len(errors), len(expect))
- return
- }
- for i, e := range expect {
- expectError(v, errors[i], e)
- }
-}
-
-func countSegments(node []interface{}) int {
- count := 1
- children := node[4].([]interface{})
- for _, c := range children {
- node := c.([]interface{})
- count += countSegments(node)
- }
- return count
-}
-
-func expectTraceSegment(v Validator, nodeObj interface{}, expect WantTraceSegment) {
- node := nodeObj.([]interface{})
- start := int(node[0].(float64))
- stop := int(node[1].(float64))
- name := node[2].(string)
- attributes := node[3].(map[string]interface{})
- children := node[4].([]interface{})
-
- validateStringField(v, "segmentName", expect.SegmentName, name)
- if nil != expect.RelativeStartMillis {
- expectStart, ok := expect.RelativeStartMillis.(int)
- if !ok {
- v.Error("invalid expect.RelativeStartMillis", expect.RelativeStartMillis)
- } else if expectStart != start {
- v.Error("segmentStartTime", expect.SegmentName, start, expectStart)
- }
- }
- if nil != expect.RelativeStopMillis {
- expectStop, ok := expect.RelativeStopMillis.(int)
- if !ok {
- v.Error("invalid expect.RelativeStopMillis", expect.RelativeStopMillis)
- } else if expectStop != stop {
- v.Error("segmentStopTime", expect.SegmentName, stop, expectStop)
- }
- }
- if nil != expect.Attributes {
- expectAttributes(v, attributes, expect.Attributes)
- }
- if len(children) != len(expect.Children) {
- v.Error("segmentChildrenCount", expect.SegmentName, len(children), len(expect.Children))
- } else {
- for idx, child := range children {
- expectTraceSegment(v, child, expect.Children[idx])
- }
- }
-}
-
-func expectTxnTrace(v Validator, got interface{}, expect WantTxnTrace) {
- unmarshalled := got.([]interface{})
- duration := unmarshalled[1].(float64)
- name := unmarshalled[2].(string)
- var arrayURL string
- if nil != unmarshalled[3] {
- arrayURL = unmarshalled[3].(string)
- }
- traceData := unmarshalled[4].([]interface{})
-
- rootNode := traceData[3].([]interface{})
- attributes := traceData[4].(map[string]interface{})
- userAttributes := attributes["userAttributes"].(map[string]interface{})
- agentAttributes := attributes["agentAttributes"].(map[string]interface{})
- intrinsics := attributes["intrinsics"].(map[string]interface{})
-
- validateStringField(v, "metric name", expect.MetricName, name)
-
- if doDurationTests && 0 == duration {
- v.Error("zero trace duration")
- }
-
- if nil != expect.UserAttributes {
- expectAttributes(v, userAttributes, expect.UserAttributes)
- }
- if nil != expect.AgentAttributes {
- expectAttributes(v, agentAttributes, expect.AgentAttributes)
- expectURL, _ := expect.AgentAttributes["request.uri"].(string)
- if "" != expectURL {
- validateStringField(v, "request url in array", expectURL, arrayURL)
- }
- }
- if nil != expect.Intrinsics {
- expectAttributes(v, intrinsics, expect.Intrinsics)
- }
- if expect.Root.SegmentName != "" {
- expectTraceSegment(v, rootNode, expect.Root)
- } else {
- numSegments := countSegments(rootNode)
- // The expectation segment count does not include the two root nodes.
- numSegments -= 2
- if expect.NumSegments != numSegments {
- v.Error("wrong number of segments", expect.NumSegments, numSegments)
- }
- }
-}
-
-// ExpectTxnTraces allows testing of transaction traces.
-func ExpectTxnTraces(v Validator, traces *harvestTraces, want []WantTxnTrace) {
- if len(want) != traces.Len() {
- v.Error("number of traces do not match", len(want), traces.Len())
- return
- }
- if len(want) == 0 {
- return
- }
- js, err := traces.Data("agentRunID", time.Now())
- if nil != err {
- v.Error("error creasing harvest traces data", err)
- return
- }
-
- var unmarshalled []interface{}
- err = json.Unmarshal(js, &unmarshalled)
- if nil != err {
- v.Error("unable to unmarshal error json", err)
- return
- }
- if "agentRunID" != unmarshalled[0].(string) {
- v.Error("traces agent run id wrong", unmarshalled[0])
- return
- }
- gotTraces := unmarshalled[1].([]interface{})
- if len(gotTraces) != len(want) {
- v.Error("number of traces in json does not match", len(gotTraces), len(want))
- return
- }
- for i, expected := range want {
- expectTxnTrace(v, gotTraces[i], expected)
- }
-}
-
-func expectSlowQuery(t Validator, slowQuery *slowQuery, want WantSlowQuery) {
- if slowQuery.Count != want.Count {
- t.Error("wrong Count field", slowQuery.Count, want.Count)
- }
- uri, _ := slowQuery.TxnEvent.Attrs.GetAgentValue(attributeRequestURI, destTxnTrace)
- validateStringField(t, "MetricName", slowQuery.DatastoreMetric, want.MetricName)
- validateStringField(t, "Query", slowQuery.ParameterizedQuery, want.Query)
- validateStringField(t, "TxnEvent.FinalName", slowQuery.TxnEvent.FinalName, want.TxnName)
- validateStringField(t, "request.uri", uri, want.TxnURL)
- validateStringField(t, "DatabaseName", slowQuery.DatabaseName, want.DatabaseName)
- validateStringField(t, "Host", slowQuery.Host, want.Host)
- validateStringField(t, "PortPathOrID", slowQuery.PortPathOrID, want.PortPathOrID)
- expectAttributes(t, map[string]interface{}(slowQuery.QueryParameters), want.Params)
-}
-
-// ExpectSlowQueries allows testing of slow queries.
-func ExpectSlowQueries(t Validator, slowQueries *slowQueries, want []WantSlowQuery) {
- if len(want) != len(slowQueries.priorityQueue) {
- t.Error("wrong number of slow queries",
- "expected", len(want), "got", len(slowQueries.priorityQueue))
- return
- }
- for _, s := range want {
- idx, ok := slowQueries.lookup[s.Query]
- if !ok {
- t.Error("unable to find slow query", s.Query)
- continue
- }
- expectSlowQuery(t, slowQueries.priorityQueue[idx], s)
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/harvest.go b/vendor/github.com/newrelic/go-agent/internal/harvest.go
deleted file mode 100644
index 35f9849fd5b..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/harvest.go
+++ /dev/null
@@ -1,317 +0,0 @@
-package internal
-
-import (
- "strings"
- "sync"
- "time"
-)
-
-// Harvestable is something that can be merged into a Harvest.
-type Harvestable interface {
- MergeIntoHarvest(h *Harvest)
-}
-
-type harvestTimer struct {
- lastHarvest time.Time
- period time.Duration
-}
-
-func newHarvestTimer(now time.Time, period time.Duration) harvestTimer {
- return harvestTimer{
- lastHarvest: now,
- period: period,
- }
-}
-
-func (timer *harvestTimer) ready(now time.Time) bool {
- deadline := timer.lastHarvest.Add(timer.period)
- if now.After(deadline) {
- timer.lastHarvest = deadline
- return true
- }
- return false
-}
-
-// Harvest contains collected data.
-type Harvest struct {
- configurableHarvestTimer harvestTimer
- fixedHarvestTimer harvestTimer
-
- // fixedHarvest and configurableHarvest are non-nil in the main Harvest
- // used in app.process(), but may be nil in the Harvest returned by
- // Harvest.Ready().
- *fixedHarvest
- *configurableHarvest
-}
-
-type fixedHarvest struct {
- Metrics *metricTable
- ErrorTraces harvestErrors
- TxnTraces *harvestTraces
- SlowSQLs *slowQueries
- SpanEvents *spanEvents
-}
-
-type configurableHarvest struct {
- CustomEvents *customEvents
- TxnEvents *txnEvents
- ErrorEvents *errorEvents
-}
-
-const (
- // txnEventPayloadlimit is the maximum number of events that should be
- // sent up in one post.
- txnEventPayloadlimit = 5000
-)
-
-// Ready returns a new Harvest which contains the data types ready for harvest,
-// or nil if no data is ready for harvest.
-func (h *Harvest) Ready(now time.Time, reply *ConnectReply) *Harvest {
- ready := &Harvest{}
-
- if h.configurableHarvestTimer.ready(now) {
- h.Metrics.addCount(customEventsSeen, h.CustomEvents.NumSeen(), forced)
- h.Metrics.addCount(customEventsSent, h.CustomEvents.NumSaved(), forced)
-
- h.Metrics.addCount(txnEventsSeen, h.TxnEvents.NumSeen(), forced)
- h.Metrics.addCount(txnEventsSent, h.TxnEvents.NumSaved(), forced)
-
- h.Metrics.addCount(errorEventsSeen, h.ErrorEvents.NumSeen(), forced)
- h.Metrics.addCount(errorEventsSent, h.ErrorEvents.NumSaved(), forced)
-
- ready.configurableHarvest = h.configurableHarvest
- h.configurableHarvest = newConfigurableHarvest(now, reply)
- }
-
- // NOTE! This must happen after the configurable harvest conditional to
- // ensure that the metrics contain the event supportability metrics.
- if h.fixedHarvestTimer.ready(now) {
- h.Metrics.addCount(spanEventsSeen, h.SpanEvents.NumSeen(), forced)
- h.Metrics.addCount(spanEventsSent, h.SpanEvents.NumSaved(), forced)
-
- ready.fixedHarvest = h.fixedHarvest
- h.fixedHarvest = newFixedHarvest(now)
- }
-
- if nil == ready.fixedHarvest && nil == ready.configurableHarvest {
- return nil
- }
- return ready
-}
-
-func (h *configurableHarvest) payloads(splitLargeTxnEvents bool) []PayloadCreator {
- if nil == h {
- return nil
- }
- ps := []PayloadCreator{
- h.CustomEvents,
- h.ErrorEvents,
- }
- if splitLargeTxnEvents {
- ps = append(ps, h.TxnEvents.payloads(txnEventPayloadlimit)...)
- } else {
- ps = append(ps, h.TxnEvents)
- }
- return ps
-}
-
-func (h *fixedHarvest) payloads() []PayloadCreator {
- if nil == h {
- return nil
- }
- return []PayloadCreator{
- h.Metrics,
- h.ErrorTraces,
- h.TxnTraces,
- h.SlowSQLs,
- h.SpanEvents,
- }
-}
-
-// Payloads returns a map from expected collector method name to data type.
-func (h *Harvest) Payloads(splitLargeTxnEvents bool) []PayloadCreator {
- if nil == h {
- return nil
- }
- var ps []PayloadCreator
- ps = append(ps, h.configurableHarvest.payloads(splitLargeTxnEvents)...)
- ps = append(ps, h.fixedHarvest.payloads()...)
- return ps
-}
-
-func newFixedHarvest(now time.Time) *fixedHarvest {
- return &fixedHarvest{
- Metrics: newMetricTable(maxMetrics, now),
- ErrorTraces: newHarvestErrors(maxHarvestErrors),
- TxnTraces: newHarvestTraces(),
- SlowSQLs: newSlowQueries(maxHarvestSlowSQLs),
- SpanEvents: newSpanEvents(maxSpanEvents),
- }
-}
-
-func newConfigurableHarvest(now time.Time, reply *ConnectReply) *configurableHarvest {
- harvestData := reply.getHarvestData()
- return &configurableHarvest{
- CustomEvents: newCustomEvents(int(harvestData.HarvestLimits.CustomEvents)),
- TxnEvents: newTxnEvents(int(harvestData.HarvestLimits.TxnEvents)),
- ErrorEvents: newErrorEvents(int(harvestData.HarvestLimits.ErrorEvents)),
- }
-}
-
-// NewHarvest returns a new Harvest.
-func NewHarvest(now time.Time, reply *ConnectReply) *Harvest {
- harvestData := reply.getHarvestData()
- return &Harvest{
- configurableHarvestTimer: newHarvestTimer(now, harvestData.eventReportPeriod()),
- fixedHarvestTimer: newHarvestTimer(now, fixedHarvestPeriod),
-
- configurableHarvest: newConfigurableHarvest(now, reply),
- fixedHarvest: newFixedHarvest(now),
- }
-}
-
-var (
- trackMutex sync.Mutex
- trackMetrics []string
-)
-
-// TrackUsage helps track which integration packages are used.
-func TrackUsage(s ...string) {
- trackMutex.Lock()
- defer trackMutex.Unlock()
-
- m := "Supportability/" + strings.Join(s, "/")
- trackMetrics = append(trackMetrics, m)
-}
-
-func createTrackUsageMetrics(metrics *metricTable) {
- trackMutex.Lock()
- defer trackMutex.Unlock()
-
- for _, m := range trackMetrics {
- metrics.addSingleCount(m, forced)
- }
-}
-
-// CreateFinalMetrics creates extra metrics at harvest time.
-func (h *fixedHarvest) CreateFinalMetrics(reply *ConnectReply) {
- if nil == h {
- return
- }
-
- h.Metrics.addSingleCount(instanceReporting, forced)
-
- // Configurable event harvest supportability metrics:
- // https://source.datanerd.us/agents/agent-specs/blob/master/Connect-LEGACY.md#event-harvest-config
- hd := reply.getHarvestData()
- period := hd.eventReportPeriod()
- h.Metrics.addDuration(supportReportPeriod, "", period, period, forced)
- h.Metrics.addValue(supportTxnEventLimit, "", float64(hd.HarvestLimits.TxnEvents), forced)
- h.Metrics.addValue(supportCustomEventLimit, "", float64(hd.HarvestLimits.CustomEvents), forced)
- h.Metrics.addValue(supportErrorEventLimit, "", float64(hd.HarvestLimits.ErrorEvents), forced)
-
- createTrackUsageMetrics(h.Metrics)
-
- h.Metrics = h.Metrics.ApplyRules(reply.MetricRules)
-}
-
-// PayloadCreator is a data type in the harvest.
-type PayloadCreator interface {
- // In the event of a rpm request failure (hopefully simply an
- // intermittent collector issue) the payload may be merged into the next
- // time period's harvest.
- Harvestable
- // Data prepares JSON in the format expected by the collector endpoint.
- // This method should return (nil, nil) if the payload is empty and no
- // rpm request is necessary.
- Data(agentRunID string, harvestStart time.Time) ([]byte, error)
- // EndpointMethod is used for the "method" query parameter when posting
- // the data.
- EndpointMethod() string
-}
-
-func supportMetric(metrics *metricTable, b bool, metricName string) {
- if b {
- metrics.addSingleCount(metricName, forced)
- }
-}
-
-// CreateTxnMetrics creates metrics for a transaction.
-func CreateTxnMetrics(args *TxnData, metrics *metricTable) {
- withoutFirstSegment := removeFirstSegment(args.FinalName)
-
- // Duration Metrics
- var durationRollup string
- var totalTimeRollup string
- if args.IsWeb {
- durationRollup = webRollup
- totalTimeRollup = totalTimeWeb
- metrics.addDuration(dispatcherMetric, "", args.Duration, 0, forced)
- } else {
- durationRollup = backgroundRollup
- totalTimeRollup = totalTimeBackground
- }
-
- metrics.addDuration(args.FinalName, "", args.Duration, 0, forced)
- metrics.addDuration(durationRollup, "", args.Duration, 0, forced)
-
- metrics.addDuration(totalTimeRollup, "", args.TotalTime, args.TotalTime, forced)
- metrics.addDuration(totalTimeRollup+"/"+withoutFirstSegment, "", args.TotalTime, args.TotalTime, unforced)
-
- // Better CAT Metrics
- if cat := args.BetterCAT; cat.Enabled {
- caller := callerUnknown
- if nil != cat.Inbound {
- caller = cat.Inbound.payloadCaller
- }
- m := durationByCallerMetric(caller)
- metrics.addDuration(m.all, "", args.Duration, args.Duration, unforced)
- metrics.addDuration(m.webOrOther(args.IsWeb), "", args.Duration, args.Duration, unforced)
-
- // Transport Duration Metric
- if nil != cat.Inbound {
- d := cat.Inbound.TransportDuration
- m = transportDurationMetric(caller)
- metrics.addDuration(m.all, "", d, d, unforced)
- metrics.addDuration(m.webOrOther(args.IsWeb), "", d, d, unforced)
- }
-
- // CAT Error Metrics
- if args.HasErrors() {
- m = errorsByCallerMetric(caller)
- metrics.addSingleCount(m.all, unforced)
- metrics.addSingleCount(m.webOrOther(args.IsWeb), unforced)
- }
-
- supportMetric(metrics, args.AcceptPayloadSuccess, supportTracingAcceptSuccess)
- supportMetric(metrics, args.AcceptPayloadException, supportTracingAcceptException)
- supportMetric(metrics, args.AcceptPayloadParseException, supportTracingAcceptParseException)
- supportMetric(metrics, args.AcceptPayloadCreateBeforeAccept, supportTracingCreateBeforeAccept)
- supportMetric(metrics, args.AcceptPayloadIgnoredMultiple, supportTracingIgnoredMultiple)
- supportMetric(metrics, args.AcceptPayloadIgnoredVersion, supportTracingIgnoredVersion)
- supportMetric(metrics, args.AcceptPayloadUntrustedAccount, supportTracingAcceptUntrustedAccount)
- supportMetric(metrics, args.AcceptPayloadNullPayload, supportTracingAcceptNull)
- supportMetric(metrics, args.CreatePayloadSuccess, supportTracingCreatePayloadSuccess)
- supportMetric(metrics, args.CreatePayloadException, supportTracingCreatePayloadException)
- }
-
- // Apdex Metrics
- if args.Zone != ApdexNone {
- metrics.addApdex(apdexRollup, "", args.ApdexThreshold, args.Zone, forced)
-
- mname := apdexPrefix + withoutFirstSegment
- metrics.addApdex(mname, "", args.ApdexThreshold, args.Zone, unforced)
- }
-
- // Error Metrics
- if args.HasErrors() {
- metrics.addSingleCount(errorsRollupMetric.all, forced)
- metrics.addSingleCount(errorsRollupMetric.webOrOther(args.IsWeb), forced)
- metrics.addSingleCount(errorsPrefix+args.FinalName, forced)
- }
-
- // Queueing Metrics
- if args.Queuing > 0 {
- metrics.addDuration(queueMetric, "", args.Queuing, args.Queuing, forced)
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/intrinsics.go b/vendor/github.com/newrelic/go-agent/internal/intrinsics.go
deleted file mode 100644
index 6925e49ff70..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/intrinsics.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package internal
-
-import (
- "bytes"
-)
-
-func addOptionalStringField(w *jsonFieldsWriter, key, value string) {
- if value != "" {
- w.stringField(key, value)
- }
-}
-
-func intrinsicsJSON(e *TxnEvent, buf *bytes.Buffer) {
- w := jsonFieldsWriter{buf: buf}
-
- buf.WriteByte('{')
-
- w.floatField("totalTime", e.TotalTime.Seconds())
-
- if e.BetterCAT.Enabled {
- w.stringField("guid", e.BetterCAT.ID)
- w.stringField("traceId", e.BetterCAT.TraceID())
- w.writerField("priority", e.BetterCAT.Priority)
- w.boolField("sampled", e.BetterCAT.Sampled)
- }
-
- if e.CrossProcess.Used() {
- addOptionalStringField(&w, "client_cross_process_id", e.CrossProcess.ClientID)
- addOptionalStringField(&w, "trip_id", e.CrossProcess.TripID)
- addOptionalStringField(&w, "path_hash", e.CrossProcess.PathHash)
- addOptionalStringField(&w, "referring_transaction_guid", e.CrossProcess.ReferringTxnGUID)
- }
-
- if e.CrossProcess.IsSynthetics() {
- addOptionalStringField(&w, "synthetics_resource_id", e.CrossProcess.Synthetics.ResourceID)
- addOptionalStringField(&w, "synthetics_job_id", e.CrossProcess.Synthetics.JobID)
- addOptionalStringField(&w, "synthetics_monitor_id", e.CrossProcess.Synthetics.MonitorID)
- }
-
- buf.WriteByte('}')
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/json_object_writer.go b/vendor/github.com/newrelic/go-agent/internal/json_object_writer.go
deleted file mode 100644
index e9533f14126..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/json_object_writer.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package internal
-
-import (
- "bytes"
-
- "github.com/newrelic/go-agent/internal/jsonx"
-)
-
-type jsonWriter interface {
- WriteJSON(buf *bytes.Buffer)
-}
-
-type jsonFieldsWriter struct {
- buf *bytes.Buffer
- needsComma bool
-}
-
-func (w *jsonFieldsWriter) addKey(key string) {
- if w.needsComma {
- w.buf.WriteByte(',')
- } else {
- w.needsComma = true
- }
- // defensively assume that the key needs escaping:
- jsonx.AppendString(w.buf, key)
- w.buf.WriteByte(':')
-}
-
-func (w *jsonFieldsWriter) stringField(key string, val string) {
- w.addKey(key)
- jsonx.AppendString(w.buf, val)
-}
-
-func (w *jsonFieldsWriter) intField(key string, val int64) {
- w.addKey(key)
- jsonx.AppendInt(w.buf, val)
-}
-
-func (w *jsonFieldsWriter) floatField(key string, val float64) {
- w.addKey(key)
- jsonx.AppendFloat(w.buf, val)
-}
-
-func (w *jsonFieldsWriter) boolField(key string, val bool) {
- w.addKey(key)
- if val {
- w.buf.WriteString("true")
- } else {
- w.buf.WriteString("false")
- }
-}
-
-func (w *jsonFieldsWriter) rawField(key string, val JSONString) {
- w.addKey(key)
- w.buf.WriteString(string(val))
-}
-
-func (w *jsonFieldsWriter) writerField(key string, val jsonWriter) {
- w.addKey(key)
- val.WriteJSON(w.buf)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/jsonx/encode.go b/vendor/github.com/newrelic/go-agent/internal/jsonx/encode.go
deleted file mode 100644
index 6495829f784..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/jsonx/encode.go
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package jsonx extends the encoding/json package to encode JSON
-// incrementally and without requiring reflection.
-package jsonx
-
-import (
- "bytes"
- "encoding/json"
- "math"
- "reflect"
- "strconv"
- "unicode/utf8"
-)
-
-var hex = "0123456789abcdef"
-
-// AppendString escapes s appends it to buf.
-func AppendString(buf *bytes.Buffer, s string) {
- buf.WriteByte('"')
- start := 0
- for i := 0; i < len(s); {
- if b := s[i]; b < utf8.RuneSelf {
- if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
- i++
- continue
- }
- if start < i {
- buf.WriteString(s[start:i])
- }
- switch b {
- case '\\', '"':
- buf.WriteByte('\\')
- buf.WriteByte(b)
- case '\n':
- buf.WriteByte('\\')
- buf.WriteByte('n')
- case '\r':
- buf.WriteByte('\\')
- buf.WriteByte('r')
- case '\t':
- buf.WriteByte('\\')
- buf.WriteByte('t')
- default:
- // This encodes bytes < 0x20 except for \n and \r,
- // as well as <, > and &. The latter are escaped because they
- // can lead to security holes when user-controlled strings
- // are rendered into JSON and served to some browsers.
- buf.WriteString(`\u00`)
- buf.WriteByte(hex[b>>4])
- buf.WriteByte(hex[b&0xF])
- }
- i++
- start = i
- continue
- }
- c, size := utf8.DecodeRuneInString(s[i:])
- if c == utf8.RuneError && size == 1 {
- if start < i {
- buf.WriteString(s[start:i])
- }
- buf.WriteString(`\ufffd`)
- i += size
- start = i
- continue
- }
- // U+2028 is LINE SEPARATOR.
- // U+2029 is PARAGRAPH SEPARATOR.
- // They are both technically valid characters in JSON strings,
- // but don't work in JSONP, which has to be evaluated as JavaScript,
- // and can lead to security holes there. It is valid JSON to
- // escape them, so we do so unconditionally.
- // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
- if c == '\u2028' || c == '\u2029' {
- if start < i {
- buf.WriteString(s[start:i])
- }
- buf.WriteString(`\u202`)
- buf.WriteByte(hex[c&0xF])
- i += size
- start = i
- continue
- }
- i += size
- }
- if start < len(s) {
- buf.WriteString(s[start:])
- }
- buf.WriteByte('"')
-}
-
-// AppendStringArray appends an array of string literals to buf.
-func AppendStringArray(buf *bytes.Buffer, a ...string) {
- buf.WriteByte('[')
- for i, s := range a {
- if i > 0 {
- buf.WriteByte(',')
- }
- AppendString(buf, s)
- }
- buf.WriteByte(']')
-}
-
-// AppendFloat appends a numeric literal representing the value to buf.
-func AppendFloat(buf *bytes.Buffer, x float64) error {
- var scratch [64]byte
-
- if math.IsInf(x, 0) || math.IsNaN(x) {
- return &json.UnsupportedValueError{
- Value: reflect.ValueOf(x),
- Str: strconv.FormatFloat(x, 'g', -1, 64),
- }
- }
-
- buf.Write(strconv.AppendFloat(scratch[:0], x, 'g', -1, 64))
- return nil
-}
-
-// AppendFloatArray appends an array of numeric literals to buf.
-func AppendFloatArray(buf *bytes.Buffer, a ...float64) error {
- buf.WriteByte('[')
- for i, x := range a {
- if i > 0 {
- buf.WriteByte(',')
- }
- if err := AppendFloat(buf, x); err != nil {
- return err
- }
- }
- buf.WriteByte(']')
- return nil
-}
-
-// AppendInt appends a numeric literal representing the value to buf.
-func AppendInt(buf *bytes.Buffer, x int64) {
- var scratch [64]byte
- buf.Write(strconv.AppendInt(scratch[:0], x, 10))
-}
-
-// AppendIntArray appends an array of numeric literals to buf.
-func AppendIntArray(buf *bytes.Buffer, a ...int64) {
- var scratch [64]byte
-
- buf.WriteByte('[')
- for i, x := range a {
- if i > 0 {
- buf.WriteByte(',')
- }
- buf.Write(strconv.AppendInt(scratch[:0], x, 10))
- }
- buf.WriteByte(']')
-}
-
-// AppendUint appends a numeric literal representing the value to buf.
-func AppendUint(buf *bytes.Buffer, x uint64) {
- var scratch [64]byte
- buf.Write(strconv.AppendUint(scratch[:0], x, 10))
-}
-
-// AppendUintArray appends an array of numeric literals to buf.
-func AppendUintArray(buf *bytes.Buffer, a ...uint64) {
- var scratch [64]byte
-
- buf.WriteByte('[')
- for i, x := range a {
- if i > 0 {
- buf.WriteByte(',')
- }
- buf.Write(strconv.AppendUint(scratch[:0], x, 10))
- }
- buf.WriteByte(']')
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/labels.go b/vendor/github.com/newrelic/go-agent/internal/labels.go
deleted file mode 100644
index b3671c65c90..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/labels.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package internal
-
-import "encoding/json"
-
-// Labels is used for connect JSON formatting.
-type Labels map[string]string
-
-// MarshalJSON requires a comment for golint?
-func (l Labels) MarshalJSON() ([]byte, error) {
- ls := make([]struct {
- Key string `json:"label_type"`
- Value string `json:"label_value"`
- }, len(l))
-
- i := 0
- for key, val := range l {
- ls[i].Key = key
- ls[i].Value = val
- i++
- }
-
- return json.Marshal(ls)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/limits.go b/vendor/github.com/newrelic/go-agent/internal/limits.go
deleted file mode 100644
index 04cf98fdeff..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/limits.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package internal
-
-import "time"
-
-const (
- // app behavior
-
- // fixedHarvestPeriod is the period that fixed period data (metrics,
- // traces, and span events) is sent to New Relic.
- fixedHarvestPeriod = 60 * time.Second
- // defaultConfigurableEventHarvestMs is the period for custom, error,
- // and transaction events if the connect response's
- // "event_harvest_config.report_period_ms" is missing or invalid.
- defaultConfigurableEventHarvestMs = 60 * 1000
- // CollectorTimeout is the timeout used in the client for communication
- // with New Relic's servers.
- CollectorTimeout = 20 * time.Second
- // AppDataChanSize is the size of the channel that contains data sent
- // the app processor.
- AppDataChanSize = 200
- failedMetricAttemptsLimit = 5
- failedEventsAttemptsLimit = 10
- // maxPayloadSizeInBytes specifies the maximum payload size in bytes that
- // should be sent to any endpoint
- maxPayloadSizeInBytes = 1000 * 1000
-
- // transaction behavior
- maxStackTraceFrames = 100
- // MaxTxnErrors is the maximum number of errors captured per
- // transaction.
- MaxTxnErrors = 5
- maxTxnSlowQueries = 10
-
- startingTxnTraceNodes = 16
- maxTxnTraceNodes = 256
-
- // harvest data
- maxMetrics = 2 * 1000
- maxCustomEvents = 10 * 1000
- maxTxnEvents = 10 * 1000
- maxRegularTraces = 1
- maxSyntheticsTraces = 20
- maxErrorEvents = 100
- maxHarvestErrors = 20
- maxHarvestSlowSQLs = 10
- maxSpanEvents = 1000
-
- // attributes
- attributeKeyLengthLimit = 255
- attributeValueLengthLimit = 255
- attributeUserLimit = 64
- // AttributeErrorLimit limits the number of extra attributes that can be
- // provided when noticing an error.
- AttributeErrorLimit = 32
- attributeAgentLimit = 255 - (attributeUserLimit + AttributeErrorLimit)
- customEventAttributeLimit = 64
-
- // Limits affecting Config validation are found in the config package.
-
- // RuntimeSamplerPeriod is the period of the runtime sampler. Runtime
- // metrics should not depend on the sampler period, but the period must
- // be the same across instances. For that reason, this value should not
- // be changed without notifying customers that they must update all
- // instance simultaneously for valid runtime metrics.
- RuntimeSamplerPeriod = 60 * time.Second
-
- txnNameCacheLimit = 40
-)
diff --git a/vendor/github.com/newrelic/go-agent/internal/logger/logger.go b/vendor/github.com/newrelic/go-agent/internal/logger/logger.go
deleted file mode 100644
index 9fda99da54c..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/logger/logger.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package logger
-
-import (
- "encoding/json"
- "fmt"
- "io"
- "log"
- "os"
-)
-
-// Logger matches newrelic.Logger to allow implementations to be passed to
-// internal packages.
-type Logger interface {
- Error(msg string, context map[string]interface{})
- Warn(msg string, context map[string]interface{})
- Info(msg string, context map[string]interface{})
- Debug(msg string, context map[string]interface{})
- DebugEnabled() bool
-}
-
-// ShimLogger implements Logger and does nothing.
-type ShimLogger struct {
- // IsDebugEnabled is useful as it allows DebugEnabled code paths to be
- // tested.
- IsDebugEnabled bool
-}
-
-// Error allows ShimLogger to implement Logger.
-func (s ShimLogger) Error(string, map[string]interface{}) {}
-
-// Warn allows ShimLogger to implement Logger.
-func (s ShimLogger) Warn(string, map[string]interface{}) {}
-
-// Info allows ShimLogger to implement Logger.
-func (s ShimLogger) Info(string, map[string]interface{}) {}
-
-// Debug allows ShimLogger to implement Logger.
-func (s ShimLogger) Debug(string, map[string]interface{}) {}
-
-// DebugEnabled allows ShimLogger to implement Logger.
-func (s ShimLogger) DebugEnabled() bool { return s.IsDebugEnabled }
-
-type logFile struct {
- l *log.Logger
- doDebug bool
-}
-
-// New creates a basic Logger.
-func New(w io.Writer, doDebug bool) Logger {
- return &logFile{
- l: log.New(w, logPid, logFlags),
- doDebug: doDebug,
- }
-}
-
-const logFlags = log.Ldate | log.Ltime | log.Lmicroseconds
-
-var (
- logPid = fmt.Sprintf("(%d) ", os.Getpid())
-)
-
-func (f *logFile) fire(level, msg string, ctx map[string]interface{}) {
- js, err := json.Marshal(struct {
- Level string `json:"level"`
- Event string `json:"msg"`
- Context map[string]interface{} `json:"context"`
- }{
- level,
- msg,
- ctx,
- })
- if nil == err {
- f.l.Print(string(js))
- } else {
- f.l.Printf("unable to marshal log entry: %v", err)
- }
-}
-
-func (f *logFile) Error(msg string, ctx map[string]interface{}) {
- f.fire("error", msg, ctx)
-}
-func (f *logFile) Warn(msg string, ctx map[string]interface{}) {
- f.fire("warn", msg, ctx)
-}
-func (f *logFile) Info(msg string, ctx map[string]interface{}) {
- f.fire("info", msg, ctx)
-}
-func (f *logFile) Debug(msg string, ctx map[string]interface{}) {
- if f.doDebug {
- f.fire("debug", msg, ctx)
- }
-}
-func (f *logFile) DebugEnabled() bool { return f.doDebug }
diff --git a/vendor/github.com/newrelic/go-agent/internal/metric_names.go b/vendor/github.com/newrelic/go-agent/internal/metric_names.go
deleted file mode 100644
index cd9321e07b4..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/metric_names.go
+++ /dev/null
@@ -1,262 +0,0 @@
-package internal
-
-const (
- apdexRollup = "Apdex"
- apdexPrefix = "Apdex/"
-
- webRollup = "WebTransaction"
- backgroundRollup = "OtherTransaction/all"
-
- // https://source.datanerd.us/agents/agent-specs/blob/master/Total-Time-Async.md
- totalTimeWeb = "WebTransactionTotalTime"
- totalTimeBackground = "OtherTransactionTotalTime"
-
- errorsPrefix = "Errors/"
-
- // "HttpDispatcher" metric is used for the overview graph, and
- // therefore should only be made for web transactions.
- dispatcherMetric = "HttpDispatcher"
-
- queueMetric = "WebFrontend/QueueTime"
-
- webMetricPrefix = "WebTransaction/Go"
- backgroundMetricPrefix = "OtherTransaction/Go"
-
- instanceReporting = "Instance/Reporting"
-
- // https://newrelic.atlassian.net/wiki/display/eng/Custom+Events+in+New+Relic+Agents
- customEventsSeen = "Supportability/Events/Customer/Seen"
- customEventsSent = "Supportability/Events/Customer/Sent"
-
- // https://source.datanerd.us/agents/agent-specs/blob/master/Transaction-Events-PORTED.md
- txnEventsSeen = "Supportability/AnalyticsEvents/TotalEventsSeen"
- txnEventsSent = "Supportability/AnalyticsEvents/TotalEventsSent"
-
- // https://source.datanerd.us/agents/agent-specs/blob/master/Error-Events.md
- errorEventsSeen = "Supportability/Events/TransactionError/Seen"
- errorEventsSent = "Supportability/Events/TransactionError/Sent"
-
- // https://source.datanerd.us/agents/agent-specs/blob/master/Span-Events.md
- spanEventsSeen = "Supportability/SpanEvent/TotalEventsSeen"
- spanEventsSent = "Supportability/SpanEvent/TotalEventsSent"
-
- supportabilityDropped = "Supportability/MetricsDropped"
-
- // Runtime/System Metrics
- memoryPhysical = "Memory/Physical"
- heapObjectsAllocated = "Memory/Heap/AllocatedObjects"
- cpuUserUtilization = "CPU/User/Utilization"
- cpuSystemUtilization = "CPU/System/Utilization"
- cpuUserTime = "CPU/User Time"
- cpuSystemTime = "CPU/System Time"
- runGoroutine = "Go/Runtime/Goroutines"
- gcPauseFraction = "GC/System/Pause Fraction"
- gcPauses = "GC/System/Pauses"
-
- // Distributed Tracing Supportability Metrics
- supportTracingAcceptSuccess = "Supportability/DistributedTrace/AcceptPayload/Success"
- supportTracingAcceptException = "Supportability/DistributedTrace/AcceptPayload/Exception"
- supportTracingAcceptParseException = "Supportability/DistributedTrace/AcceptPayload/ParseException"
- supportTracingCreateBeforeAccept = "Supportability/DistributedTrace/AcceptPayload/Ignored/CreateBeforeAccept"
- supportTracingIgnoredMultiple = "Supportability/DistributedTrace/AcceptPayload/Ignored/Multiple"
- supportTracingIgnoredVersion = "Supportability/DistributedTrace/AcceptPayload/Ignored/MajorVersion"
- supportTracingAcceptUntrustedAccount = "Supportability/DistributedTrace/AcceptPayload/Ignored/UntrustedAccount"
- supportTracingAcceptNull = "Supportability/DistributedTrace/AcceptPayload/Ignored/Null"
- supportTracingCreatePayloadSuccess = "Supportability/DistributedTrace/CreatePayload/Success"
- supportTracingCreatePayloadException = "Supportability/DistributedTrace/CreatePayload/Exception"
-
- // Configurable event harvest supportability metrics
- supportReportPeriod = "Supportability/EventHarvest/ReportPeriod"
- supportTxnEventLimit = "Supportability/EventHarvest/AnalyticEventData/HarvestLimit"
- supportCustomEventLimit = "Supportability/EventHarvest/CustomEventData/HarvestLimit"
- supportErrorEventLimit = "Supportability/EventHarvest/ErrorEventData/HarvestLimit"
-)
-
-// DistributedTracingSupport is used to track distributed tracing activity for
-// supportability.
-type DistributedTracingSupport struct {
- AcceptPayloadSuccess bool // AcceptPayload was called successfully
- AcceptPayloadException bool // AcceptPayload had a generic exception
- AcceptPayloadParseException bool // AcceptPayload had a parsing exception
- AcceptPayloadCreateBeforeAccept bool // AcceptPayload was ignored because CreatePayload had already been called
- AcceptPayloadIgnoredMultiple bool // AcceptPayload was ignored because AcceptPayload had already been called
- AcceptPayloadIgnoredVersion bool // AcceptPayload was ignored because the payload's major version was greater than the agent's
- AcceptPayloadUntrustedAccount bool // AcceptPayload was ignored because the payload was untrusted
- AcceptPayloadNullPayload bool // AcceptPayload was ignored because the payload was nil
- CreatePayloadSuccess bool // CreatePayload was called successfully
- CreatePayloadException bool // CreatePayload had a generic exception
-}
-
-type rollupMetric struct {
- all string
- allWeb string
- allOther string
-}
-
-func newRollupMetric(s string) rollupMetric {
- return rollupMetric{
- all: s + "all",
- allWeb: s + "allWeb",
- allOther: s + "allOther",
- }
-}
-
-func (r rollupMetric) webOrOther(isWeb bool) string {
- if isWeb {
- return r.allWeb
- }
- return r.allOther
-}
-
-var (
- errorsRollupMetric = newRollupMetric("Errors/")
-
- // source.datanerd.us/agents/agent-specs/blob/master/APIs/external_segment.md
- // source.datanerd.us/agents/agent-specs/blob/master/APIs/external_cat.md
- // source.datanerd.us/agents/agent-specs/blob/master/Cross-Application-Tracing-PORTED.md
- externalRollupMetric = newRollupMetric("External/")
-
- // source.datanerd.us/agents/agent-specs/blob/master/Datastore-Metrics-PORTED.md
- datastoreRollupMetric = newRollupMetric("Datastore/")
-
- datastoreProductMetricsCache = map[string]rollupMetric{
- "Cassandra": newRollupMetric("Datastore/Cassandra/"),
- "Derby": newRollupMetric("Datastore/Derby/"),
- "Elasticsearch": newRollupMetric("Datastore/Elasticsearch/"),
- "Firebird": newRollupMetric("Datastore/Firebird/"),
- "IBMDB2": newRollupMetric("Datastore/IBMDB2/"),
- "Informix": newRollupMetric("Datastore/Informix/"),
- "Memcached": newRollupMetric("Datastore/Memcached/"),
- "MongoDB": newRollupMetric("Datastore/MongoDB/"),
- "MySQL": newRollupMetric("Datastore/MySQL/"),
- "MSSQL": newRollupMetric("Datastore/MSSQL/"),
- "Oracle": newRollupMetric("Datastore/Oracle/"),
- "Postgres": newRollupMetric("Datastore/Postgres/"),
- "Redis": newRollupMetric("Datastore/Redis/"),
- "Solr": newRollupMetric("Datastore/Solr/"),
- "SQLite": newRollupMetric("Datastore/SQLite/"),
- "CouchDB": newRollupMetric("Datastore/CouchDB/"),
- "Riak": newRollupMetric("Datastore/Riak/"),
- "VoltDB": newRollupMetric("Datastore/VoltDB/"),
- }
-)
-
-func customSegmentMetric(s string) string {
- return "Custom/" + s
-}
-
-// customMetric is used to construct custom metrics from the input given to
-// Application.RecordCustomMetric. Note that the "Custom/" prefix helps prevent
-// collision with other agent metrics, but does not eliminate the possibility
-// since "Custom/" is also used for segments.
-func customMetric(customerInput string) string {
- return "Custom/" + customerInput
-}
-
-// DatastoreMetricKey contains the fields by which datastore metrics are
-// aggregated.
-type DatastoreMetricKey struct {
- Product string
- Collection string
- Operation string
- Host string
- PortPathOrID string
-}
-
-type externalMetricKey struct {
- Host string
- Library string
- Method string
- ExternalCrossProcessID string
- ExternalTransactionName string
-}
-
-func datastoreScopedMetric(key DatastoreMetricKey) string {
- if "" != key.Collection {
- return datastoreStatementMetric(key)
- }
- return datastoreOperationMetric(key)
-}
-
-// Datastore/{datastore}/*
-func datastoreProductMetric(key DatastoreMetricKey) rollupMetric {
- d, ok := datastoreProductMetricsCache[key.Product]
- if ok {
- return d
- }
- return newRollupMetric("Datastore/" + key.Product + "/")
-}
-
-// Datastore/operation/{datastore}/{operation}
-func datastoreOperationMetric(key DatastoreMetricKey) string {
- return "Datastore/operation/" + key.Product +
- "/" + key.Operation
-}
-
-// Datastore/statement/{datastore}/{table}/{operation}
-func datastoreStatementMetric(key DatastoreMetricKey) string {
- return "Datastore/statement/" + key.Product +
- "/" + key.Collection +
- "/" + key.Operation
-}
-
-// Datastore/instance/{datastore}/{host}/{port_path_or_id}
-func datastoreInstanceMetric(key DatastoreMetricKey) string {
- return "Datastore/instance/" + key.Product +
- "/" + key.Host +
- "/" + key.PortPathOrID
-}
-
-func (key externalMetricKey) scopedMetric() string {
- if "" != key.ExternalCrossProcessID && "" != key.ExternalTransactionName {
- return externalTransactionMetric(key)
- }
-
- if key.Method == "" {
- // External/{host}/{library}
- return "External/" + key.Host + "/" + key.Library
- }
- // External/{host}/{library}/{method}
- return "External/" + key.Host + "/" + key.Library + "/" + key.Method
-}
-
-// External/{host}/all
-func externalHostMetric(key externalMetricKey) string {
- return "External/" + key.Host + "/all"
-}
-
-// ExternalApp/{host}/{external_id}/all
-func externalAppMetric(key externalMetricKey) string {
- return "ExternalApp/" + key.Host +
- "/" + key.ExternalCrossProcessID + "/all"
-}
-
-// ExternalTransaction/{host}/{external_id}/{external_txnname}
-func externalTransactionMetric(key externalMetricKey) string {
- return "ExternalTransaction/" + key.Host +
- "/" + key.ExternalCrossProcessID +
- "/" + key.ExternalTransactionName
-}
-
-func callerFields(c payloadCaller) string {
- return "/" + c.Type +
- "/" + c.Account +
- "/" + c.App +
- "/" + c.TransportType +
- "/"
-}
-
-// DurationByCaller/{type}/{account}/{app}/{transport}/*
-func durationByCallerMetric(c payloadCaller) rollupMetric {
- return newRollupMetric("DurationByCaller" + callerFields(c))
-}
-
-// ErrorsByCaller/{type}/{account}/{app}/{transport}/*
-func errorsByCallerMetric(c payloadCaller) rollupMetric {
- return newRollupMetric("ErrorsByCaller" + callerFields(c))
-}
-
-// TransportDuration/{type}/{account}/{app}/{transport}/*
-func transportDurationMetric(c payloadCaller) rollupMetric {
- return newRollupMetric("TransportDuration" + callerFields(c))
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/metric_rules.go b/vendor/github.com/newrelic/go-agent/internal/metric_rules.go
deleted file mode 100644
index b634a8b5b33..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/metric_rules.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "regexp"
- "sort"
- "strings"
-)
-
-type ruleResult int
-
-const (
- ruleMatched ruleResult = iota
- ruleUnmatched
- ruleIgnore
-)
-
-type metricRule struct {
- // 'Ignore' indicates if the entire transaction should be discarded if
- // there is a match. This field is only used by "url_rules" and
- // "transaction_name_rules", not "metric_name_rules".
- Ignore bool `json:"ignore"`
- EachSegment bool `json:"each_segment"`
- ReplaceAll bool `json:"replace_all"`
- Terminate bool `json:"terminate_chain"`
- Order int `json:"eval_order"`
- OriginalReplacement string `json:"replacement"`
- RawExpr string `json:"match_expression"`
-
- // Go's regexp backreferences use '${1}' instead of the Perlish '\1', so
- // we transform the replacement string into the Go syntax and store it
- // here.
- TransformedReplacement string
- re *regexp.Regexp
-}
-
-type metricRules []*metricRule
-
-// Go's regexp backreferences use `${1}` instead of the Perlish `\1`, so we must
-// transform the replacement string. This is non-trivial: `\1` is a
-// backreference but `\\1` is not. Rather than count the number of back slashes
-// preceding the digit, we simply skip rules with tricky replacements.
-var (
- transformReplacementAmbiguous = regexp.MustCompile(`\\\\([0-9]+)`)
- transformReplacementRegex = regexp.MustCompile(`\\([0-9]+)`)
- transformReplacementReplacement = "$${${1}}"
-)
-
-func (rules *metricRules) UnmarshalJSON(data []byte) (err error) {
- var raw []*metricRule
-
- if err := json.Unmarshal(data, &raw); nil != err {
- return err
- }
-
- valid := make(metricRules, 0, len(raw))
-
- for _, r := range raw {
- re, err := regexp.Compile("(?i)" + r.RawExpr)
- if err != nil {
- // TODO
- // Warn("unable to compile rule", {
- // "match_expression": r.RawExpr,
- // "error": err.Error(),
- // })
- continue
- }
-
- if transformReplacementAmbiguous.MatchString(r.OriginalReplacement) {
- // TODO
- // Warn("unable to transform replacement", {
- // "match_expression": r.RawExpr,
- // "replacement": r.OriginalReplacement,
- // })
- continue
- }
-
- r.re = re
- r.TransformedReplacement = transformReplacementRegex.ReplaceAllString(r.OriginalReplacement,
- transformReplacementReplacement)
- valid = append(valid, r)
- }
-
- sort.Sort(valid)
-
- *rules = valid
- return nil
-}
-
-func (rules metricRules) Len() int {
- return len(rules)
-}
-
-// Rules should be applied in increasing order
-func (rules metricRules) Less(i, j int) bool {
- return rules[i].Order < rules[j].Order
-}
-func (rules metricRules) Swap(i, j int) {
- rules[i], rules[j] = rules[j], rules[i]
-}
-
-func replaceFirst(re *regexp.Regexp, s string, replacement string) (ruleResult, string) {
- // Note that ReplaceAllStringFunc cannot be used here since it does
- // not replace $1 placeholders.
- loc := re.FindStringIndex(s)
- if nil == loc {
- return ruleUnmatched, s
- }
- firstMatch := s[loc[0]:loc[1]]
- firstMatchReplaced := re.ReplaceAllString(firstMatch, replacement)
- return ruleMatched, s[0:loc[0]] + firstMatchReplaced + s[loc[1]:]
-}
-
-func (r *metricRule) apply(s string) (ruleResult, string) {
- // Rules are strange, and there is no spec.
- // This code attempts to duplicate the logic of the PHP agent.
- // Ambiguity abounds.
-
- if r.Ignore {
- if r.re.MatchString(s) {
- return ruleIgnore, ""
- }
- return ruleUnmatched, s
- }
-
- if r.ReplaceAll {
- if r.re.MatchString(s) {
- return ruleMatched, r.re.ReplaceAllString(s, r.TransformedReplacement)
- }
- return ruleUnmatched, s
- } else if r.EachSegment {
- segments := strings.Split(s, "/")
- applied := make([]string, len(segments))
- result := ruleUnmatched
- for i, segment := range segments {
- var segmentMatched ruleResult
- segmentMatched, applied[i] = replaceFirst(r.re, segment, r.TransformedReplacement)
- if segmentMatched == ruleMatched {
- result = ruleMatched
- }
- }
- return result, strings.Join(applied, "/")
- } else {
- return replaceFirst(r.re, s, r.TransformedReplacement)
- }
-}
-
-func (rules metricRules) Apply(input string) string {
- var res ruleResult
- s := input
-
- for _, rule := range rules {
- res, s = rule.apply(s)
-
- if ruleIgnore == res {
- return ""
- }
- if (ruleMatched == res) && rule.Terminate {
- break
- }
- }
-
- return s
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/metrics.go b/vendor/github.com/newrelic/go-agent/internal/metrics.go
deleted file mode 100644
index 1cbc5fcf45d..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/metrics.go
+++ /dev/null
@@ -1,261 +0,0 @@
-package internal
-
-import (
- "bytes"
- "time"
-
- "github.com/newrelic/go-agent/internal/jsonx"
-)
-
-type metricForce int
-
-const (
- forced metricForce = iota
- unforced
-)
-
-type metricID struct {
- Name string `json:"name"`
- Scope string `json:"scope,omitempty"`
-}
-
-type metricData struct {
- // These values are in the units expected by the collector.
- countSatisfied float64 // Seconds, or count for Apdex
- totalTolerated float64 // Seconds, or count for Apdex
- exclusiveFailed float64 // Seconds, or count for Apdex
- min float64 // Seconds
- max float64 // Seconds
- sumSquares float64 // Seconds**2, or 0 for Apdex
-}
-
-func metricDataFromDuration(duration, exclusive time.Duration) metricData {
- ds := duration.Seconds()
- return metricData{
- countSatisfied: 1,
- totalTolerated: ds,
- exclusiveFailed: exclusive.Seconds(),
- min: ds,
- max: ds,
- sumSquares: ds * ds,
- }
-}
-
-type metric struct {
- forced metricForce
- data metricData
-}
-
-type metricTable struct {
- metricPeriodStart time.Time
- failedHarvests int
- maxTableSize int // After this max is reached, only forced metrics are added
- metrics map[metricID]*metric
-}
-
-func newMetricTable(maxTableSize int, now time.Time) *metricTable {
- return &metricTable{
- metricPeriodStart: now,
- metrics: make(map[metricID]*metric),
- maxTableSize: maxTableSize,
- failedHarvests: 0,
- }
-}
-
-func (mt *metricTable) full() bool {
- return len(mt.metrics) >= mt.maxTableSize
-}
-
-func (data *metricData) aggregate(src metricData) {
- data.countSatisfied += src.countSatisfied
- data.totalTolerated += src.totalTolerated
- data.exclusiveFailed += src.exclusiveFailed
-
- if src.min < data.min {
- data.min = src.min
- }
- if src.max > data.max {
- data.max = src.max
- }
-
- data.sumSquares += src.sumSquares
-}
-
-func (mt *metricTable) mergeMetric(id metricID, m metric) {
- if to := mt.metrics[id]; nil != to {
- to.data.aggregate(m.data)
- return
- }
-
- if mt.full() && (unforced == m.forced) {
- mt.addSingleCount(supportabilityDropped, forced)
- return
- }
- // NOTE: `new` is used in place of `&m` since the latter will make `m`
- // get heap allocated regardless of whether or not this line gets
- // reached (running go version go1.5 darwin/amd64). See
- // BenchmarkAddingSameMetrics.
- alloc := new(metric)
- *alloc = m
- mt.metrics[id] = alloc
-}
-
-func (mt *metricTable) mergeFailed(from *metricTable) {
- fails := from.failedHarvests + 1
- if fails >= failedMetricAttemptsLimit {
- return
- }
- if from.metricPeriodStart.Before(mt.metricPeriodStart) {
- mt.metricPeriodStart = from.metricPeriodStart
- }
- mt.failedHarvests = fails
- mt.merge(from, "")
-}
-
-func (mt *metricTable) merge(from *metricTable, newScope string) {
- if "" == newScope {
- for id, m := range from.metrics {
- mt.mergeMetric(id, *m)
- }
- } else {
- for id, m := range from.metrics {
- mt.mergeMetric(metricID{Name: id.Name, Scope: newScope}, *m)
- }
- }
-}
-
-func (mt *metricTable) add(name, scope string, data metricData, force metricForce) {
- mt.mergeMetric(metricID{Name: name, Scope: scope}, metric{data: data, forced: force})
-}
-
-func (mt *metricTable) addCount(name string, count float64, force metricForce) {
- mt.add(name, "", metricData{countSatisfied: count}, force)
-}
-
-func (mt *metricTable) addSingleCount(name string, force metricForce) {
- mt.addCount(name, float64(1), force)
-}
-
-func (mt *metricTable) addDuration(name, scope string, duration, exclusive time.Duration, force metricForce) {
- mt.add(name, scope, metricDataFromDuration(duration, exclusive), force)
-}
-
-func (mt *metricTable) addValueExclusive(name, scope string, total, exclusive float64, force metricForce) {
- data := metricData{
- countSatisfied: 1,
- totalTolerated: total,
- exclusiveFailed: exclusive,
- min: total,
- max: total,
- sumSquares: total * total,
- }
- mt.add(name, scope, data, force)
-}
-
-func (mt *metricTable) addValue(name, scope string, total float64, force metricForce) {
- mt.addValueExclusive(name, scope, total, total, force)
-}
-
-func (mt *metricTable) addApdex(name, scope string, apdexThreshold time.Duration, zone ApdexZone, force metricForce) {
- apdexSeconds := apdexThreshold.Seconds()
- data := metricData{min: apdexSeconds, max: apdexSeconds}
-
- switch zone {
- case ApdexSatisfying:
- data.countSatisfied = 1
- case ApdexTolerating:
- data.totalTolerated = 1
- case ApdexFailing:
- data.exclusiveFailed = 1
- }
-
- mt.add(name, scope, data, force)
-}
-
-func (mt *metricTable) CollectorJSON(agentRunID string, now time.Time) ([]byte, error) {
- if 0 == len(mt.metrics) {
- return nil, nil
- }
- estimatedBytesPerMetric := 128
- estimatedLen := len(mt.metrics) * estimatedBytesPerMetric
- buf := bytes.NewBuffer(make([]byte, 0, estimatedLen))
- buf.WriteByte('[')
-
- jsonx.AppendString(buf, agentRunID)
- buf.WriteByte(',')
- jsonx.AppendInt(buf, mt.metricPeriodStart.Unix())
- buf.WriteByte(',')
- jsonx.AppendInt(buf, now.Unix())
- buf.WriteByte(',')
-
- buf.WriteByte('[')
- first := true
- for id, metric := range mt.metrics {
- if first {
- first = false
- } else {
- buf.WriteByte(',')
- }
- buf.WriteByte('[')
- buf.WriteByte('{')
- buf.WriteString(`"name":`)
- jsonx.AppendString(buf, id.Name)
- if id.Scope != "" {
- buf.WriteString(`,"scope":`)
- jsonx.AppendString(buf, id.Scope)
- }
- buf.WriteByte('}')
- buf.WriteByte(',')
-
- jsonx.AppendFloatArray(buf,
- metric.data.countSatisfied,
- metric.data.totalTolerated,
- metric.data.exclusiveFailed,
- metric.data.min,
- metric.data.max,
- metric.data.sumSquares)
-
- buf.WriteByte(']')
- }
- buf.WriteByte(']')
-
- buf.WriteByte(']')
- return buf.Bytes(), nil
-}
-
-func (mt *metricTable) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
- return mt.CollectorJSON(agentRunID, harvestStart)
-}
-func (mt *metricTable) MergeIntoHarvest(h *Harvest) {
- h.Metrics.mergeFailed(mt)
-}
-
-func (mt *metricTable) ApplyRules(rules metricRules) *metricTable {
- if nil == rules {
- return mt
- }
- if len(rules) == 0 {
- return mt
- }
-
- applied := newMetricTable(mt.maxTableSize, mt.metricPeriodStart)
- cache := make(map[string]string)
-
- for id, m := range mt.metrics {
- out, ok := cache[id.Name]
- if !ok {
- out = rules.Apply(id.Name)
- cache[id.Name] = out
- }
-
- if "" != out {
- applied.mergeMetric(metricID{Name: out, Scope: id.Scope}, *m)
- }
- }
-
- return applied
-}
-
-func (mt *metricTable) EndpointMethod() string {
- return cmdMetrics
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/obfuscate.go b/vendor/github.com/newrelic/go-agent/internal/obfuscate.go
deleted file mode 100644
index 0fcf859667e..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/obfuscate.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package internal
-
-import (
- "encoding/base64"
- "errors"
-)
-
-// Deobfuscate deobfuscates a byte array.
-func Deobfuscate(in string, key []byte) ([]byte, error) {
- if len(key) == 0 {
- return nil, errors.New("key cannot be zero length")
- }
-
- decoded, err := base64.StdEncoding.DecodeString(in)
- if err != nil {
- return nil, err
- }
-
- out := make([]byte, len(decoded))
- for i, c := range decoded {
- out[i] = c ^ key[i%len(key)]
- }
-
- return out, nil
-}
-
-// Obfuscate obfuscates a byte array for transmission in CAT and RUM.
-func Obfuscate(in, key []byte) (string, error) {
- if len(key) == 0 {
- return "", errors.New("key cannot be zero length")
- }
-
- out := make([]byte, len(in))
- for i, c := range in {
- out[i] = c ^ key[i%len(key)]
- }
-
- return base64.StdEncoding.EncodeToString(out), nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/priority.go b/vendor/github.com/newrelic/go-agent/internal/priority.go
deleted file mode 100644
index e7aae796e8a..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/priority.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package internal
-
-// Priority allows for a priority sampling of events. When an event
-// is created it is given a Priority. Whenever an event pool is
-// full and events need to be dropped, the events with the lowest priority
-// are dropped.
-type Priority float32
-
-// According to spec, Agents SHOULD truncate the value to at most 6
-// digits past the decimal point.
-const (
- priorityFormat = "%.6f"
-)
-
-// NewPriority returns a new priority.
-func NewPriority() Priority {
- return Priority(RandFloat32())
-}
-
-// Float32 returns the priority as a float32.
-func (p Priority) Float32() float32 {
- return float32(p)
-}
-
-func (p Priority) isLowerPriority(y Priority) bool {
- return p < y
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/queuing.go b/vendor/github.com/newrelic/go-agent/internal/queuing.go
deleted file mode 100644
index cc361f82088..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/queuing.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package internal
-
-import (
- "net/http"
- "strconv"
- "strings"
- "time"
-)
-
-const (
- xRequestStart = "X-Request-Start"
- xQueueStart = "X-Queue-Start"
-)
-
-var (
- earliestAcceptableSeconds = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()
- latestAcceptableSeconds = time.Date(2050, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()
-)
-
-func checkQueueTimeSeconds(secondsFloat float64) time.Time {
- seconds := int64(secondsFloat)
- nanos := int64((secondsFloat - float64(seconds)) * (1000.0 * 1000.0 * 1000.0))
- if seconds > earliestAcceptableSeconds && seconds < latestAcceptableSeconds {
- return time.Unix(seconds, nanos)
- }
- return time.Time{}
-}
-
-func parseQueueTime(s string) time.Time {
- f, err := strconv.ParseFloat(s, 64)
- if nil != err {
- return time.Time{}
- }
- if f <= 0 {
- return time.Time{}
- }
-
- // try microseconds
- if t := checkQueueTimeSeconds(f / (1000.0 * 1000.0)); !t.IsZero() {
- return t
- }
- // try milliseconds
- if t := checkQueueTimeSeconds(f / (1000.0)); !t.IsZero() {
- return t
- }
- // try seconds
- if t := checkQueueTimeSeconds(f); !t.IsZero() {
- return t
- }
- return time.Time{}
-}
-
-// QueueDuration TODO
-func QueueDuration(hdr http.Header, txnStart time.Time) time.Duration {
- s := hdr.Get(xQueueStart)
- if "" == s {
- s = hdr.Get(xRequestStart)
- }
- if "" == s {
- return 0
- }
-
- s = strings.TrimPrefix(s, "t=")
- qt := parseQueueTime(s)
- if qt.IsZero() {
- return 0
- }
- if qt.After(txnStart) {
- return 0
- }
- return txnStart.Sub(qt)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/rand.go b/vendor/github.com/newrelic/go-agent/internal/rand.go
deleted file mode 100644
index 7e76d7d585c..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/rand.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package internal
-
-import (
- "math/rand"
- "sync"
- "time"
-)
-
-var (
- seededRand = struct {
- sync.Mutex
- *rand.Rand
- }{
- Rand: rand.New(rand.NewSource(int64(time.Now().UnixNano()))),
- }
-)
-
-// RandUint64 returns a random uint64.
-//
-// IMPORTANT! The default rand package functions are not used, since we want to
-// minimize the chance that different Go processes duplicate the same
-// transaction id. (Note that the rand top level functions "use a default
-// shared Source that produces a deterministic sequence of values each time a
-// program is run" (and we don't seed the shared Source to avoid changing
-// customer apps' behavior)).
-func RandUint64() uint64 {
- seededRand.Lock()
- defer seededRand.Unlock()
-
- u1 := seededRand.Uint32()
- u2 := seededRand.Uint32()
- return (uint64(u1) << 32) | uint64(u2)
-}
-
-// RandUint32 returns a random uint32.
-func RandUint32() uint32 {
- seededRand.Lock()
- defer seededRand.Unlock()
-
- return seededRand.Uint32()
-}
-
-// RandFloat32 returns a random float32 between 0.0 and 1.0.
-func RandFloat32() float32 {
- seededRand.Lock()
- defer seededRand.Unlock()
-
- for {
- if r := seededRand.Float32(); 0.0 != r {
- return r
- }
- }
-}
-
-// RandUint64N returns a random int64 that's
-// between 0 and the passed in max, non-inclusive
-func RandUint64N(max uint64) uint64 {
- return RandUint64() % max
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/rules_cache.go b/vendor/github.com/newrelic/go-agent/internal/rules_cache.go
deleted file mode 100644
index d8357075322..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/rules_cache.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package internal
-
-import "sync"
-
-// rulesCache is designed to avoid applying url-rules, txn-name-rules, and
-// segment-rules since regexes are expensive!
-type rulesCache struct {
- sync.RWMutex
- cache map[rulesCacheKey]string
- maxCacheSize int
-}
-
-type rulesCacheKey struct {
- isWeb bool
- inputName string
-}
-
-func newRulesCache(maxCacheSize int) *rulesCache {
- return &rulesCache{
- cache: make(map[rulesCacheKey]string, maxCacheSize),
- maxCacheSize: maxCacheSize,
- }
-}
-
-func (cache *rulesCache) find(inputName string, isWeb bool) string {
- if nil == cache {
- return ""
- }
- cache.RLock()
- defer cache.RUnlock()
-
- return cache.cache[rulesCacheKey{
- inputName: inputName,
- isWeb: isWeb,
- }]
-}
-
-func (cache *rulesCache) set(inputName string, isWeb bool, finalName string) {
- if nil == cache {
- return
- }
- cache.Lock()
- defer cache.Unlock()
-
- if len(cache.cache) >= cache.maxCacheSize {
- return
- }
- cache.cache[rulesCacheKey{
- inputName: inputName,
- isWeb: isWeb,
- }] = finalName
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sampler.go b/vendor/github.com/newrelic/go-agent/internal/sampler.go
deleted file mode 100644
index d78cdc64051..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sampler.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package internal
-
-import (
- "runtime"
- "time"
-
- "github.com/newrelic/go-agent/internal/logger"
- "github.com/newrelic/go-agent/internal/sysinfo"
-)
-
-// Sample is a system/runtime snapshot.
-type Sample struct {
- when time.Time
- memStats runtime.MemStats
- usage sysinfo.Usage
- numGoroutine int
- numCPU int
-}
-
-func bytesToMebibytesFloat(bts uint64) float64 {
- return float64(bts) / (1024 * 1024)
-}
-
-// GetSample gathers a new Sample.
-func GetSample(now time.Time, lg logger.Logger) *Sample {
- s := Sample{
- when: now,
- numGoroutine: runtime.NumGoroutine(),
- numCPU: runtime.NumCPU(),
- }
-
- if usage, err := sysinfo.GetUsage(); err == nil {
- s.usage = usage
- } else {
- lg.Warn("unable to usage", map[string]interface{}{
- "error": err.Error(),
- })
- }
-
- runtime.ReadMemStats(&s.memStats)
-
- return &s
-}
-
-type cpuStats struct {
- used time.Duration
- fraction float64 // used / (elapsed * numCPU)
-}
-
-// Stats contains system information for a period of time.
-type Stats struct {
- numGoroutine int
- allocBytes uint64
- heapObjects uint64
- user cpuStats
- system cpuStats
- gcPauseFraction float64
- deltaNumGC uint32
- deltaPauseTotal time.Duration
- minPause time.Duration
- maxPause time.Duration
-}
-
-// Samples is used as the parameter to GetStats to avoid mixing up the previous
-// and current sample.
-type Samples struct {
- Previous *Sample
- Current *Sample
-}
-
-// GetStats combines two Samples into a Stats.
-func GetStats(ss Samples) Stats {
- cur := ss.Current
- prev := ss.Previous
- elapsed := cur.when.Sub(prev.when)
-
- s := Stats{
- numGoroutine: cur.numGoroutine,
- allocBytes: cur.memStats.Alloc,
- heapObjects: cur.memStats.HeapObjects,
- }
-
- // CPU Utilization
- totalCPUSeconds := elapsed.Seconds() * float64(cur.numCPU)
- if prev.usage.User != 0 && cur.usage.User > prev.usage.User {
- s.user.used = cur.usage.User - prev.usage.User
- s.user.fraction = s.user.used.Seconds() / totalCPUSeconds
- }
- if prev.usage.System != 0 && cur.usage.System > prev.usage.System {
- s.system.used = cur.usage.System - prev.usage.System
- s.system.fraction = s.system.used.Seconds() / totalCPUSeconds
- }
-
- // GC Pause Fraction
- deltaPauseTotalNs := cur.memStats.PauseTotalNs - prev.memStats.PauseTotalNs
- frac := float64(deltaPauseTotalNs) / float64(elapsed.Nanoseconds())
- s.gcPauseFraction = frac
-
- // GC Pauses
- if deltaNumGC := cur.memStats.NumGC - prev.memStats.NumGC; deltaNumGC > 0 {
- // In case more than 256 pauses have happened between samples
- // and we are examining a subset of the pauses, we ensure that
- // the min and max are not on the same side of the average by
- // using the average as the starting min and max.
- maxPauseNs := deltaPauseTotalNs / uint64(deltaNumGC)
- minPauseNs := deltaPauseTotalNs / uint64(deltaNumGC)
- for i := prev.memStats.NumGC + 1; i <= cur.memStats.NumGC; i++ {
- pause := cur.memStats.PauseNs[(i+255)%256]
- if pause > maxPauseNs {
- maxPauseNs = pause
- }
- if pause < minPauseNs {
- minPauseNs = pause
- }
- }
- s.deltaPauseTotal = time.Duration(deltaPauseTotalNs) * time.Nanosecond
- s.deltaNumGC = deltaNumGC
- s.minPause = time.Duration(minPauseNs) * time.Nanosecond
- s.maxPause = time.Duration(maxPauseNs) * time.Nanosecond
- }
-
- return s
-}
-
-// MergeIntoHarvest implements Harvestable.
-func (s Stats) MergeIntoHarvest(h *Harvest) {
- h.Metrics.addValue(heapObjectsAllocated, "", float64(s.heapObjects), forced)
- h.Metrics.addValue(runGoroutine, "", float64(s.numGoroutine), forced)
- h.Metrics.addValueExclusive(memoryPhysical, "", bytesToMebibytesFloat(s.allocBytes), 0, forced)
- h.Metrics.addValueExclusive(cpuUserUtilization, "", s.user.fraction, 0, forced)
- h.Metrics.addValueExclusive(cpuSystemUtilization, "", s.system.fraction, 0, forced)
- h.Metrics.addValue(cpuUserTime, "", s.user.used.Seconds(), forced)
- h.Metrics.addValue(cpuSystemTime, "", s.system.used.Seconds(), forced)
- h.Metrics.addValueExclusive(gcPauseFraction, "", s.gcPauseFraction, 0, forced)
- if s.deltaNumGC > 0 {
- h.Metrics.add(gcPauses, "", metricData{
- countSatisfied: float64(s.deltaNumGC),
- totalTolerated: s.deltaPauseTotal.Seconds(),
- exclusiveFailed: 0,
- min: s.minPause.Seconds(),
- max: s.maxPause.Seconds(),
- sumSquares: s.deltaPauseTotal.Seconds() * s.deltaPauseTotal.Seconds(),
- }, forced)
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/security_policies.go b/vendor/github.com/newrelic/go-agent/internal/security_policies.go
deleted file mode 100644
index d8d119b7798..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/security_policies.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "fmt"
- "reflect"
-)
-
-// Security policies documentation:
-// https://source.datanerd.us/agents/agent-specs/blob/master/Language-Agent-Security-Policies.md
-
-// SecurityPolicies contains the security policies.
-type SecurityPolicies struct {
- RecordSQL securityPolicy `json:"record_sql"`
- AttributesInclude securityPolicy `json:"attributes_include"`
- AllowRawExceptionMessages securityPolicy `json:"allow_raw_exception_messages"`
- CustomEvents securityPolicy `json:"custom_events"`
- CustomParameters securityPolicy `json:"custom_parameters"`
-}
-
-// PointerIfPopulated returns a reference to the security policies if they have
-// been populated from JSON.
-func (sp *SecurityPolicies) PointerIfPopulated() *SecurityPolicies {
- emptyPolicies := SecurityPolicies{}
- if nil != sp && *sp != emptyPolicies {
- return sp
- }
- return nil
-}
-
-type securityPolicy struct {
- EnabledVal *bool `json:"enabled"`
-}
-
-func (p *securityPolicy) Enabled() bool { return nil == p.EnabledVal || *p.EnabledVal }
-func (p *securityPolicy) SetEnabled(enabled bool) { p.EnabledVal = &enabled }
-func (p *securityPolicy) IsSet() bool { return nil != p.EnabledVal }
-
-type policyer interface {
- SetEnabled(bool)
- IsSet() bool
-}
-
-// UnmarshalJSON decodes security policies sent from the preconnect endpoint.
-func (sp *SecurityPolicies) UnmarshalJSON(data []byte) (er error) {
- defer func() {
- // Zero out all fields if there is an error to ensure that the
- // populated check works.
- if er != nil {
- *sp = SecurityPolicies{}
- }
- }()
-
- var raw map[string]struct {
- Enabled bool `json:"enabled"`
- Required bool `json:"required"`
- }
- err := json.Unmarshal(data, &raw)
- if err != nil {
- return fmt.Errorf("unable to unmarshal security policies: %v", err)
- }
-
- knownPolicies := make(map[string]policyer)
-
- spv := reflect.ValueOf(sp).Elem()
- for i := 0; i < spv.NumField(); i++ {
- fieldAddress := spv.Field(i).Addr()
- field := fieldAddress.Interface().(policyer)
- name := spv.Type().Field(i).Tag.Get("json")
- knownPolicies[name] = field
- }
-
- for name, policy := range raw {
- p, ok := knownPolicies[name]
- if !ok {
- if policy.Required {
- return errUnknownRequiredPolicy{name: name}
- }
- } else {
- p.SetEnabled(policy.Enabled)
- }
- }
- for name, policy := range knownPolicies {
- if !policy.IsSet() {
- return errUnsetPolicy{name: name}
- }
- }
- return nil
-}
-
-type errUnknownRequiredPolicy struct{ name string }
-
-func (err errUnknownRequiredPolicy) Error() string {
- return fmt.Sprintf("policy '%s' is unrecognized, please check for a newer agent version or contact support", err.name)
-}
-
-type errUnsetPolicy struct{ name string }
-
-func (err errUnsetPolicy) Error() string {
- return fmt.Sprintf("policy '%s' not received, please contact support", err.name)
-}
-
-func isDisconnectSecurityPolicyError(e error) bool {
- if _, ok := e.(errUnknownRequiredPolicy); ok {
- return true
- }
- if _, ok := e.(errUnsetPolicy); ok {
- return true
- }
- return false
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/segment_terms.go b/vendor/github.com/newrelic/go-agent/internal/segment_terms.go
deleted file mode 100644
index a0fd1f2e667..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/segment_terms.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package internal
-
-// https://newrelic.atlassian.net/wiki/display/eng/Language+agent+transaction+segment+terms+rules
-
-import (
- "encoding/json"
- "strings"
-)
-
-const (
- placeholder = "*"
- separator = "/"
-)
-
-type segmentRule struct {
- Prefix string `json:"prefix"`
- Terms []string `json:"terms"`
- TermsMap map[string]struct{}
-}
-
-// segmentRules is keyed by each segmentRule's Prefix field with any trailing
-// slash removed.
-type segmentRules map[string]*segmentRule
-
-func buildTermsMap(terms []string) map[string]struct{} {
- m := make(map[string]struct{}, len(terms))
- for _, t := range terms {
- m[t] = struct{}{}
- }
- return m
-}
-
-func (rules *segmentRules) UnmarshalJSON(b []byte) error {
- var raw []*segmentRule
-
- if err := json.Unmarshal(b, &raw); nil != err {
- return err
- }
-
- rs := make(map[string]*segmentRule)
-
- for _, rule := range raw {
- prefix := strings.TrimSuffix(rule.Prefix, "/")
- if len(strings.Split(prefix, "/")) != 2 {
- // TODO
- // Warn("invalid segment term rule prefix",
- // {"prefix": rule.Prefix})
- continue
- }
-
- if nil == rule.Terms {
- // TODO
- // Warn("segment term rule has missing terms",
- // {"prefix": rule.Prefix})
- continue
- }
-
- rule.TermsMap = buildTermsMap(rule.Terms)
-
- rs[prefix] = rule
- }
-
- *rules = rs
- return nil
-}
-
-func (rule *segmentRule) apply(name string) string {
- if !strings.HasPrefix(name, rule.Prefix) {
- return name
- }
-
- s := strings.TrimPrefix(name, rule.Prefix)
-
- leadingSlash := ""
- if strings.HasPrefix(s, separator) {
- leadingSlash = separator
- s = strings.TrimPrefix(s, separator)
- }
-
- if "" != s {
- segments := strings.Split(s, separator)
-
- for i, segment := range segments {
- _, whitelisted := rule.TermsMap[segment]
- if whitelisted {
- segments[i] = segment
- } else {
- segments[i] = placeholder
- }
- }
-
- segments = collapsePlaceholders(segments)
- s = strings.Join(segments, separator)
- }
-
- return rule.Prefix + leadingSlash + s
-}
-
-func (rules segmentRules) apply(name string) string {
- if nil == rules {
- return name
- }
-
- rule, ok := rules[firstTwoSegments(name)]
- if !ok {
- return name
- }
-
- return rule.apply(name)
-}
-
-func firstTwoSegments(name string) string {
- firstSlashIdx := strings.Index(name, separator)
- if firstSlashIdx == -1 {
- return name
- }
-
- secondSlashIdx := strings.Index(name[firstSlashIdx+1:], separator)
- if secondSlashIdx == -1 {
- return name
- }
-
- return name[0 : firstSlashIdx+secondSlashIdx+1]
-}
-
-func collapsePlaceholders(segments []string) []string {
- j := 0
- prevStar := false
- for i := 0; i < len(segments); i++ {
- segment := segments[i]
- if placeholder == segment {
- if prevStar {
- continue
- }
- segments[j] = placeholder
- j++
- prevStar = true
- } else {
- segments[j] = segment
- j++
- prevStar = false
- }
- }
- return segments[0:j]
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/serverless.go b/vendor/github.com/newrelic/go-agent/internal/serverless.go
deleted file mode 100644
index 414d0ebd05a..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/serverless.go
+++ /dev/null
@@ -1,217 +0,0 @@
-package internal
-
-import (
- "bytes"
- "compress/gzip"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io"
- "strings"
- "sync"
- "time"
-
- "github.com/newrelic/go-agent/internal/logger"
-)
-
-const (
- lambdaMetadataVersion = 2
-
- // AgentLanguage is used in the connect JSON and the Lambda JSON.
- AgentLanguage = "go"
-)
-
-// ServerlessHarvest is used to store and log data when the agent is running in
-// serverless mode.
-type ServerlessHarvest struct {
- logger logger.Logger
- version string
- awsExecutionEnv string
-
- // The Lambda handler could be using multiple goroutines so we use a
- // mutex to prevent race conditions.
- sync.Mutex
- harvest *Harvest
-}
-
-// NewServerlessHarvest creates a new ServerlessHarvest.
-func NewServerlessHarvest(logger logger.Logger, version string, getEnv func(string) string) *ServerlessHarvest {
- return &ServerlessHarvest{
- logger: logger,
- version: version,
- awsExecutionEnv: getEnv("AWS_EXECUTION_ENV"),
-
- // A ConnectReply parameter to NewHarvest isn't needed because
- // serverless mode doesn't have a connect, and therefore won't
- // have custom event limits from the server.
- harvest: NewHarvest(time.Now(), nil),
- }
-}
-
-// Consume adds data to the harvest.
-func (sh *ServerlessHarvest) Consume(data Harvestable) {
- if nil == sh {
- return
- }
- sh.Lock()
- defer sh.Unlock()
-
- data.MergeIntoHarvest(sh.harvest)
-}
-
-func (sh *ServerlessHarvest) swapHarvest() *Harvest {
- sh.Lock()
- defer sh.Unlock()
-
- h := sh.harvest
- sh.harvest = NewHarvest(time.Now(), nil)
- return h
-}
-
-// Write logs the data in the format described by:
-// https://source.datanerd.us/agents/agent-specs/blob/master/Lambda.md
-func (sh *ServerlessHarvest) Write(arn string, writer io.Writer) {
- if nil == sh {
- return
- }
- harvest := sh.swapHarvest()
- payloads := harvest.Payloads(false)
- // Note that *json.RawMessage (instead of json.RawMessage) is used to
- // support older Go versions: https://go-review.googlesource.com/c/go/+/21811/
- harvestPayloads := make(map[string]*json.RawMessage, len(payloads))
- for _, p := range payloads {
- agentRunID := ""
- cmd := p.EndpointMethod()
- data, err := p.Data(agentRunID, time.Now())
- if err != nil {
- sh.logger.Error("error creating payload json", map[string]interface{}{
- "command": cmd,
- "error": err.Error(),
- })
- continue
- }
- if nil == data {
- continue
- }
- // NOTE! This code relies on the fact that each payload is
- // using a different endpoint method. Sometimes the transaction
- // events payload might be split, but since there is only one
- // transaction event per serverless transaction, that's not an
- // issue. Likewise, if we ever split normal transaction events
- // apart from synthetics events, the transaction will either be
- // normal or synthetic, so that won't be an issue. Log an error
- // if this happens for future defensiveness.
- if _, ok := harvestPayloads[cmd]; ok {
- sh.logger.Error("data with duplicate command name lost", map[string]interface{}{
- "command": cmd,
- })
- }
- d := json.RawMessage(data)
- harvestPayloads[cmd] = &d
- }
-
- if len(harvestPayloads) == 0 {
- // The harvest may not contain any data if the serverless
- // transaction was ignored.
- return
- }
-
- data, err := json.Marshal(harvestPayloads)
- if nil != err {
- sh.logger.Error("error creating serverless data json", map[string]interface{}{
- "error": err.Error(),
- })
- return
- }
-
- var dataBuf bytes.Buffer
- gz := gzip.NewWriter(&dataBuf)
- gz.Write(data)
- gz.Flush()
- gz.Close()
-
- js, err := json.Marshal([]interface{}{
- lambdaMetadataVersion,
- "NR_LAMBDA_MONITORING",
- struct {
- MetadataVersion int `json:"metadata_version"`
- ARN string `json:"arn,omitempty"`
- ProtocolVersion int `json:"protocol_version"`
- ExecutionEnvironment string `json:"execution_environment,omitempty"`
- AgentVersion string `json:"agent_version"`
- AgentLanguage string `json:"agent_language"`
- }{
- MetadataVersion: lambdaMetadataVersion,
- ProtocolVersion: ProcotolVersion,
- AgentVersion: sh.version,
- ExecutionEnvironment: sh.awsExecutionEnv,
- ARN: arn,
- AgentLanguage: AgentLanguage,
- },
- base64.StdEncoding.EncodeToString(dataBuf.Bytes()),
- })
-
- if err != nil {
- sh.logger.Error("error creating serverless json", map[string]interface{}{
- "error": err.Error(),
- })
- return
- }
-
- fmt.Fprintln(writer, string(js))
-}
-
-// ParseServerlessPayload exists for testing.
-func ParseServerlessPayload(data []byte) (metadata, uncompressedData map[string]json.RawMessage, err error) {
- var arr [4]json.RawMessage
- if err = json.Unmarshal(data, &arr); nil != err {
- err = fmt.Errorf("unable to unmarshal serverless data array: %v", err)
- return
- }
- var dataJSON []byte
- compressed := strings.Trim(string(arr[3]), `"`)
- if dataJSON, err = decodeUncompress(compressed); nil != err {
- err = fmt.Errorf("unable to uncompress serverless data: %v", err)
- return
- }
- if err = json.Unmarshal(dataJSON, &uncompressedData); nil != err {
- err = fmt.Errorf("unable to unmarshal uncompressed serverless data: %v", err)
- return
- }
- if err = json.Unmarshal(arr[2], &metadata); nil != err {
- err = fmt.Errorf("unable to unmarshal serverless metadata: %v", err)
- return
- }
- return
-}
-
-func decodeUncompress(input string) ([]byte, error) {
- decoded, err := base64.StdEncoding.DecodeString(input)
- if nil != err {
- return nil, err
- }
-
- buf := bytes.NewBuffer(decoded)
- gz, err := gzip.NewReader(buf)
- if nil != err {
- return nil, err
- }
- var out bytes.Buffer
- io.Copy(&out, gz)
- gz.Close()
-
- return out.Bytes(), nil
-}
-
-// ServerlessWriter is implemented by newrelic.Application.
-type ServerlessWriter interface {
- ServerlessWrite(arn string, writer io.Writer)
-}
-
-// ServerlessWrite exists to avoid type assertion in the nrlambda integration
-// package.
-func ServerlessWrite(app interface{}, arn string, writer io.Writer) {
- if s, ok := app.(ServerlessWriter); ok {
- s.ServerlessWrite(arn, writer)
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/slow_queries.go b/vendor/github.com/newrelic/go-agent/internal/slow_queries.go
deleted file mode 100644
index 36f435fcd56..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/slow_queries.go
+++ /dev/null
@@ -1,261 +0,0 @@
-package internal
-
-import (
- "bytes"
- "container/heap"
- "hash/fnv"
- "time"
-
- "github.com/newrelic/go-agent/internal/jsonx"
-)
-
-type queryParameters map[string]interface{}
-
-func vetQueryParameters(params map[string]interface{}) (queryParameters, error) {
- if nil == params {
- return nil, nil
- }
- // Copying the parameters into a new map is safer than modifying the map
- // from the customer.
- vetted := make(map[string]interface{})
- var retErr error
- for key, val := range params {
- val, err := ValidateUserAttribute(key, val)
- if nil != err {
- retErr = err
- continue
- }
- vetted[key] = val
- }
- return queryParameters(vetted), retErr
-}
-
-func (q queryParameters) WriteJSON(buf *bytes.Buffer) {
- buf.WriteByte('{')
- w := jsonFieldsWriter{buf: buf}
- for key, val := range q {
- writeAttributeValueJSON(&w, key, val)
- }
- buf.WriteByte('}')
-}
-
-// https://source.datanerd.us/agents/agent-specs/blob/master/Slow-SQLs-LEGACY.md
-
-// slowQueryInstance represents a single datastore call.
-type slowQueryInstance struct {
- // Fields populated right after the datastore segment finishes:
-
- Duration time.Duration
- DatastoreMetric string
- ParameterizedQuery string
- QueryParameters queryParameters
- Host string
- PortPathOrID string
- DatabaseName string
- StackTrace StackTrace
-
- TxnEvent
-}
-
-// Aggregation is performed to avoid reporting multiple slow queries with same
-// query string. Since some datastore segments may be below the slow query
-// threshold, the aggregation fields Count, Total, and Min should be taken with
-// a grain of salt.
-type slowQuery struct {
- Count int32 // number of times the query has been observed
- Total time.Duration // cummulative duration
- Min time.Duration // minimum observed duration
-
- // When Count > 1, slowQueryInstance contains values from the slowest
- // observation.
- slowQueryInstance
-}
-
-type slowQueries struct {
- priorityQueue []*slowQuery
- // lookup maps query strings to indices in the priorityQueue
- lookup map[string]int
-}
-
-func (slows *slowQueries) Len() int {
- return len(slows.priorityQueue)
-}
-func (slows *slowQueries) Less(i, j int) bool {
- pq := slows.priorityQueue
- return pq[i].Duration < pq[j].Duration
-}
-func (slows *slowQueries) Swap(i, j int) {
- pq := slows.priorityQueue
- si := pq[i]
- sj := pq[j]
- pq[i], pq[j] = pq[j], pq[i]
- slows.lookup[si.ParameterizedQuery] = j
- slows.lookup[sj.ParameterizedQuery] = i
-}
-
-// Push and Pop are unused: only heap.Init and heap.Fix are used.
-func (slows *slowQueries) Push(x interface{}) {}
-func (slows *slowQueries) Pop() interface{} { return nil }
-
-func newSlowQueries(max int) *slowQueries {
- return &slowQueries{
- lookup: make(map[string]int, max),
- priorityQueue: make([]*slowQuery, 0, max),
- }
-}
-
-// Merge is used to merge slow queries from the transaction into the harvest.
-func (slows *slowQueries) Merge(other *slowQueries, txnEvent TxnEvent) {
- for _, s := range other.priorityQueue {
- cp := *s
- cp.TxnEvent = txnEvent
- slows.observe(cp)
- }
-}
-
-// merge aggregates the observations from two slow queries with the same Query.
-func (slow *slowQuery) merge(other slowQuery) {
- slow.Count += other.Count
- slow.Total += other.Total
-
- if other.Min < slow.Min {
- slow.Min = other.Min
- }
- if other.Duration > slow.Duration {
- slow.slowQueryInstance = other.slowQueryInstance
- }
-}
-
-func (slows *slowQueries) observeInstance(slow slowQueryInstance) {
- slows.observe(slowQuery{
- Count: 1,
- Total: slow.Duration,
- Min: slow.Duration,
- slowQueryInstance: slow,
- })
-}
-
-func (slows *slowQueries) insertAtIndex(slow slowQuery, idx int) {
- cpy := new(slowQuery)
- *cpy = slow
- slows.priorityQueue[idx] = cpy
- slows.lookup[slow.ParameterizedQuery] = idx
- heap.Fix(slows, idx)
-}
-
-func (slows *slowQueries) observe(slow slowQuery) {
- // Has the query has previously been observed?
- if idx, ok := slows.lookup[slow.ParameterizedQuery]; ok {
- slows.priorityQueue[idx].merge(slow)
- heap.Fix(slows, idx)
- return
- }
- // Has the collection reached max capacity?
- if len(slows.priorityQueue) < cap(slows.priorityQueue) {
- idx := len(slows.priorityQueue)
- slows.priorityQueue = slows.priorityQueue[0 : idx+1]
- slows.insertAtIndex(slow, idx)
- return
- }
- // Is this query slower than the existing fastest?
- fastest := slows.priorityQueue[0]
- if slow.Duration > fastest.Duration {
- delete(slows.lookup, fastest.ParameterizedQuery)
- slows.insertAtIndex(slow, 0)
- return
- }
-}
-
-// The third element of the slow query JSON should be a hash of the query
-// string. This hash may be used by backend services to aggregate queries which
-// have the have the same query string. It is unknown if this actually used.
-func makeSlowQueryID(query string) uint32 {
- h := fnv.New32a()
- h.Write([]byte(query))
- return h.Sum32()
-}
-
-func (slow *slowQuery) WriteJSON(buf *bytes.Buffer) {
- buf.WriteByte('[')
- jsonx.AppendString(buf, slow.TxnEvent.FinalName)
- buf.WriteByte(',')
- // Include request.uri if it is included in any destination.
- // TODO: Change this to the transaction trace segment destination
- // once transaction trace segment attribute configuration has been
- // added.
- uri, _ := slow.TxnEvent.Attrs.GetAgentValue(attributeRequestURI, DestAll)
- jsonx.AppendString(buf, uri)
- buf.WriteByte(',')
- jsonx.AppendInt(buf, int64(makeSlowQueryID(slow.ParameterizedQuery)))
- buf.WriteByte(',')
- jsonx.AppendString(buf, slow.ParameterizedQuery)
- buf.WriteByte(',')
- jsonx.AppendString(buf, slow.DatastoreMetric)
- buf.WriteByte(',')
- jsonx.AppendInt(buf, int64(slow.Count))
- buf.WriteByte(',')
- jsonx.AppendFloat(buf, slow.Total.Seconds()*1000.0)
- buf.WriteByte(',')
- jsonx.AppendFloat(buf, slow.Min.Seconds()*1000.0)
- buf.WriteByte(',')
- jsonx.AppendFloat(buf, slow.Duration.Seconds()*1000.0)
- buf.WriteByte(',')
- w := jsonFieldsWriter{buf: buf}
- buf.WriteByte('{')
- if "" != slow.Host {
- w.stringField("host", slow.Host)
- }
- if "" != slow.PortPathOrID {
- w.stringField("port_path_or_id", slow.PortPathOrID)
- }
- if "" != slow.DatabaseName {
- w.stringField("database_name", slow.DatabaseName)
- }
- if nil != slow.StackTrace {
- w.writerField("backtrace", slow.StackTrace)
- }
- if nil != slow.QueryParameters {
- w.writerField("query_parameters", slow.QueryParameters)
- }
-
- sharedBetterCATIntrinsics(&slow.TxnEvent, &w)
-
- buf.WriteByte('}')
- buf.WriteByte(']')
-}
-
-// WriteJSON marshals the collection of slow queries into JSON according to the
-// schema expected by the collector.
-//
-// Note: This JSON does not contain the agentRunID. This is for unknown
-// historical reasons. Since the agentRunID is included in the url,
-// its use in the other commands' JSON is redundant (although required).
-func (slows *slowQueries) WriteJSON(buf *bytes.Buffer) {
- buf.WriteByte('[')
- buf.WriteByte('[')
- for idx, s := range slows.priorityQueue {
- if idx > 0 {
- buf.WriteByte(',')
- }
- s.WriteJSON(buf)
- }
- buf.WriteByte(']')
- buf.WriteByte(']')
-}
-
-func (slows *slowQueries) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
- if 0 == len(slows.priorityQueue) {
- return nil, nil
- }
- estimate := 1024 * len(slows.priorityQueue)
- buf := bytes.NewBuffer(make([]byte, 0, estimate))
- slows.WriteJSON(buf)
- return buf.Bytes(), nil
-}
-
-func (slows *slowQueries) MergeIntoHarvest(newHarvest *Harvest) {
-}
-
-func (slows *slowQueries) EndpointMethod() string {
- return cmdSlowSQLs
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/span_events.go b/vendor/github.com/newrelic/go-agent/internal/span_events.go
deleted file mode 100644
index 6a670008b85..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/span_events.go
+++ /dev/null
@@ -1,143 +0,0 @@
-package internal
-
-import (
- "bytes"
- "time"
-)
-
-// https://source.datanerd.us/agents/agent-specs/blob/master/Span-Events.md
-
-type spanCategory string
-
-const (
- spanCategoryHTTP spanCategory = "http"
- spanCategoryDatastore = "datastore"
- spanCategoryGeneric = "generic"
-)
-
-// SpanEvent represents a span event, necessary to support Distributed Tracing.
-type SpanEvent struct {
- TraceID string
- GUID string
- ParentID string
- TransactionID string
- Sampled bool
- Priority Priority
- Timestamp time.Time
- Duration time.Duration
- Name string
- Category spanCategory
- Component string
- Kind string
- IsEntrypoint bool
- Attributes spanAttributeMap
-}
-
-// WriteJSON prepares JSON in the format expected by the collector.
-func (e *SpanEvent) WriteJSON(buf *bytes.Buffer) {
- w := jsonFieldsWriter{buf: buf}
- buf.WriteByte('[')
- buf.WriteByte('{')
- w.stringField("type", "Span")
- w.stringField("traceId", e.TraceID)
- w.stringField("guid", e.GUID)
- if "" != e.ParentID {
- w.stringField("parentId", e.ParentID)
- }
- w.stringField("transactionId", e.TransactionID)
- w.boolField("sampled", e.Sampled)
- w.writerField("priority", e.Priority)
- w.intField("timestamp", e.Timestamp.UnixNano()/(1000*1000)) // in milliseconds
- w.floatField("duration", e.Duration.Seconds())
- w.stringField("name", e.Name)
- w.stringField("category", string(e.Category))
- if e.IsEntrypoint {
- w.boolField("nr.entryPoint", true)
- }
- if e.Component != "" {
- w.stringField("component", e.Component)
- }
- if e.Kind != "" {
- w.stringField("span.kind", e.Kind)
- }
- buf.WriteByte('}')
- buf.WriteByte(',')
- buf.WriteByte('{')
- // user attributes section is unused
- buf.WriteByte('}')
- buf.WriteByte(',')
- buf.WriteByte('{')
-
- w = jsonFieldsWriter{buf: buf}
- for key, val := range e.Attributes {
- w.writerField(key.String(), val)
- }
-
- buf.WriteByte('}')
- buf.WriteByte(']')
-}
-
-// MarshalJSON is used for testing.
-func (e *SpanEvent) MarshalJSON() ([]byte, error) {
- buf := bytes.NewBuffer(make([]byte, 0, 256))
-
- e.WriteJSON(buf)
-
- return buf.Bytes(), nil
-}
-
-type spanEvents struct {
- *analyticsEvents
-}
-
-func newSpanEvents(max int) *spanEvents {
- return &spanEvents{
- analyticsEvents: newAnalyticsEvents(max),
- }
-}
-
-func (events *spanEvents) addEvent(e *SpanEvent, cat *BetterCAT) {
- e.TraceID = cat.TraceID()
- e.TransactionID = cat.ID
- e.Sampled = cat.Sampled
- e.Priority = cat.Priority
- events.addEventPopulated(e)
-}
-
-func (events *spanEvents) addEventPopulated(e *SpanEvent) {
- events.analyticsEvents.addEvent(analyticsEvent{priority: e.Priority, jsonWriter: e})
-}
-
-// MergeFromTransaction merges the span events from a transaction into the
-// harvest's span events. This should only be called if the transaction was
-// sampled and span events are enabled.
-func (events *spanEvents) MergeFromTransaction(txndata *TxnData) {
- root := &SpanEvent{
- GUID: txndata.getRootSpanID(),
- Timestamp: txndata.Start,
- Duration: txndata.Duration,
- Name: txndata.FinalName,
- Category: spanCategoryGeneric,
- IsEntrypoint: true,
- }
- if nil != txndata.BetterCAT.Inbound {
- root.ParentID = txndata.BetterCAT.Inbound.ID
- }
- events.addEvent(root, &txndata.BetterCAT)
-
- for _, evt := range txndata.spanEvents {
- events.addEvent(evt, &txndata.BetterCAT)
- }
-}
-
-func (events *spanEvents) MergeIntoHarvest(h *Harvest) {
- h.SpanEvents.mergeFailed(events.analyticsEvents)
-}
-
-func (events *spanEvents) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
- return events.CollectorJSON(agentRunID)
-}
-
-func (events *spanEvents) EndpointMethod() string {
- return cmdSpanEvents
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/stack_frame.go b/vendor/github.com/newrelic/go-agent/internal/stack_frame.go
deleted file mode 100644
index 837bcb7077e..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/stack_frame.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// +build go1.7
-
-package internal
-
-import "runtime"
-
-func (st StackTrace) frames() []stacktraceFrame {
- if len(st) == 0 {
- return nil
- }
- frames := runtime.CallersFrames(st) // CallersFrames is only available in Go 1.7+
- fs := make([]stacktraceFrame, 0, maxStackTraceFrames)
- var frame runtime.Frame
- more := true
- for more {
- frame, more = frames.Next()
- fs = append(fs, stacktraceFrame{
- Name: frame.Function,
- File: frame.File,
- Line: int64(frame.Line),
- })
- }
- return fs
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/stack_frame_pre_1_7.go b/vendor/github.com/newrelic/go-agent/internal/stack_frame_pre_1_7.go
deleted file mode 100644
index b9d824788c3..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/stack_frame_pre_1_7.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// +build !go1.7
-
-package internal
-
-import "runtime"
-
-func (st StackTrace) frames() []stacktraceFrame {
- fs := make([]stacktraceFrame, len(st))
- for idx, pc := range st {
- fs[idx] = lookupFrame(pc)
- }
- return fs
-}
-
-func lookupFrame(pc uintptr) stacktraceFrame {
- // The Golang runtime package documentation says "To look up the file
- // and line number of the call itself, use pc[i]-1. As an exception to
- // this rule, if pc[i-1] corresponds to the function runtime.sigpanic,
- // then pc[i] is the program counter of a faulting instruction and
- // should be used without any subtraction."
- //
- // TODO: Fully understand when this subtraction is necessary.
- place := pc - 1
- f := runtime.FuncForPC(place)
- if nil == f {
- return stacktraceFrame{}
- }
- file, line := f.FileLine(place)
- return stacktraceFrame{
- Name: f.Name(),
- File: file,
- Line: int64(line),
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/stacktrace.go b/vendor/github.com/newrelic/go-agent/internal/stacktrace.go
deleted file mode 100644
index 0a66d2795e6..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/stacktrace.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package internal
-
-import (
- "bytes"
- "path"
- "runtime"
- "strings"
-)
-
-// StackTrace is a stack trace.
-type StackTrace []uintptr
-
-// GetStackTrace returns a new StackTrace.
-func GetStackTrace() StackTrace {
- skip := 1 // skip runtime.Callers
- callers := make([]uintptr, maxStackTraceFrames)
- written := runtime.Callers(skip, callers)
- return callers[:written]
-}
-
-type stacktraceFrame struct {
- Name string
- File string
- Line int64
-}
-
-func (f stacktraceFrame) formattedName() string {
- if strings.HasPrefix(f.Name, "go.") {
- // This indicates an anonymous struct. eg.
- // "go.(*struct { github.com/newrelic/go-agent.threadWithExtras }).NoticeError"
- return f.Name
- }
- return path.Base(f.Name)
-}
-
-func (f stacktraceFrame) isAgent() bool {
- // Note this is not a contains conditional rather than a prefix
- // conditional to handle anonymous functions like:
- // "go.(*struct { github.com/newrelic/go-agent.threadWithExtras }).NoticeError"
- return strings.Contains(f.Name, "github.com/newrelic/go-agent/internal.") ||
- strings.Contains(f.Name, "github.com/newrelic/go-agent.")
-}
-
-func (f stacktraceFrame) WriteJSON(buf *bytes.Buffer) {
- buf.WriteByte('{')
- w := jsonFieldsWriter{buf: buf}
- if f.Name != "" {
- w.stringField("name", f.formattedName())
- }
- if f.File != "" {
- w.stringField("filepath", f.File)
- }
- if f.Line != 0 {
- w.intField("line", f.Line)
- }
- buf.WriteByte('}')
-}
-
-func writeFrames(buf *bytes.Buffer, frames []stacktraceFrame) {
- // Remove top agent frames.
- for len(frames) > 0 && frames[0].isAgent() {
- frames = frames[1:]
- }
- // Truncate excessively long stack traces (they may be provided by the
- // customer).
- if len(frames) > maxStackTraceFrames {
- frames = frames[0:maxStackTraceFrames]
- }
-
- buf.WriteByte('[')
- for idx, frame := range frames {
- if idx > 0 {
- buf.WriteByte(',')
- }
- frame.WriteJSON(buf)
- }
- buf.WriteByte(']')
-}
-
-// WriteJSON adds the stack trace to the buffer in the JSON form expected by the
-// collector.
-func (st StackTrace) WriteJSON(buf *bytes.Buffer) {
- frames := st.frames()
- writeFrames(buf, frames)
-}
-
-// MarshalJSON prepares JSON in the format expected by the collector.
-func (st StackTrace) MarshalJSON() ([]byte, error) {
- estimate := 256 * len(st)
- buf := bytes.NewBuffer(make([]byte, 0, estimate))
-
- st.WriteJSON(buf)
-
- return buf.Bytes(), nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/bootid.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/bootid.go
deleted file mode 100644
index 780058d5ee8..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/bootid.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package sysinfo
-
-import (
- "bytes"
- "fmt"
- "io/ioutil"
- "runtime"
-)
-
-// BootID returns the boot ID of the executing kernel.
-func BootID() (string, error) {
- if "linux" != runtime.GOOS {
- return "", ErrFeatureUnsupported
- }
- data, err := ioutil.ReadFile("/proc/sys/kernel/random/boot_id")
- if err != nil {
- return "", err
- }
-
- return validateBootID(data)
-}
-
-type invalidBootID string
-
-func (e invalidBootID) Error() string {
- return fmt.Sprintf("Boot id has unrecognized format, id=%q", string(e))
-}
-
-func isASCIIByte(b byte) bool {
- return (b >= 0x20 && b <= 0x7f)
-}
-
-func validateBootID(data []byte) (string, error) {
- // We're going to go for the permissive reading of
- // https://source.datanerd.us/agents/agent-specs/blob/master/Utilization.md:
- // any ASCII (excluding control characters, because I'm pretty sure that's not
- // in the spirit of the spec) string will be sent up to and including 128
- // bytes in length.
- trunc := bytes.TrimSpace(data)
- if len(trunc) > 128 {
- trunc = trunc[:128]
- }
- for _, b := range trunc {
- if !isASCIIByte(b) {
- return "", invalidBootID(data)
- }
- }
-
- return string(trunc), nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/docker.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/docker.go
deleted file mode 100644
index a4f7c004bc5..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/docker.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package sysinfo
-
-import (
- "bufio"
- "bytes"
- "errors"
- "fmt"
- "io"
- "os"
- "regexp"
- "runtime"
-)
-
-var (
- // ErrDockerNotFound is returned if a Docker ID is not found in
- // /proc/self/cgroup
- ErrDockerNotFound = errors.New("Docker ID not found")
-)
-
-// DockerID attempts to detect Docker.
-func DockerID() (string, error) {
- if "linux" != runtime.GOOS {
- return "", ErrFeatureUnsupported
- }
-
- f, err := os.Open("/proc/self/cgroup")
- if err != nil {
- return "", err
- }
- defer f.Close()
-
- return parseDockerID(f)
-}
-
-var (
- // The DockerID must be a 64-character lowercase hex string
- // be greedy and match anything 64-characters or longer to spot invalid IDs
- dockerIDLength = 64
- dockerIDRegexRaw = fmt.Sprintf("[0-9a-f]{%d,}", dockerIDLength)
- dockerIDRegex = regexp.MustCompile(dockerIDRegexRaw)
-)
-
-func parseDockerID(r io.Reader) (string, error) {
- // Each line in the cgroup file consists of three colon delimited fields.
- // 1. hierarchy ID - we don't care about this
- // 2. subsystems - comma separated list of cgroup subsystem names
- // 3. control group - control group to which the process belongs
- //
- // Example
- // 5:cpuacct,cpu,cpuset:/daemons
-
- var id string
-
- for scanner := bufio.NewScanner(r); scanner.Scan(); {
- line := scanner.Bytes()
- cols := bytes.SplitN(line, []byte(":"), 3)
-
- if len(cols) < 3 {
- continue
- }
-
- // We're only interested in the cpu subsystem.
- if !isCPUCol(cols[1]) {
- continue
- }
-
- id = dockerIDRegex.FindString(string(cols[2]))
-
- if err := validateDockerID(id); err != nil {
- // We can stop searching at this point, the CPU
- // subsystem should only occur once, and its cgroup is
- // not docker or not a format we accept.
- return "", err
- }
- return id, nil
- }
-
- return "", ErrDockerNotFound
-}
-
-func isCPUCol(col []byte) bool {
- // Sometimes we have multiple subsystems in one line, as in this example
- // from:
- // https://source.datanerd.us/newrelic/cross_agent_tests/blob/master/docker_container_id/docker-1.1.2-native-driver-systemd.txt
- //
- // 3:cpuacct,cpu:/system.slice/docker-67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f.scope
- splitCSV := func(r rune) bool { return r == ',' }
- subsysCPU := []byte("cpu")
-
- for _, subsys := range bytes.FieldsFunc(col, splitCSV) {
- if bytes.Equal(subsysCPU, subsys) {
- return true
- }
- }
- return false
-}
-
-func isHex(r rune) bool {
- return ('0' <= r && r <= '9') || ('a' <= r && r <= 'f')
-}
-
-func validateDockerID(id string) error {
- if len(id) != 64 {
- return fmt.Errorf("%s is not %d characters long", id, dockerIDLength)
- }
-
- for _, c := range id {
- if !isHex(c) {
- return fmt.Errorf("Character: %c is not hex in string %s", c, id)
- }
- }
-
- return nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/errors.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/errors.go
deleted file mode 100644
index d4b684b5faa..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/errors.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package sysinfo
-
-import (
- "errors"
-)
-
-var (
- // ErrFeatureUnsupported indicates unsupported platform.
- ErrFeatureUnsupported = errors.New("That feature is not supported on this platform")
-)
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/hostname_generic.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/hostname_generic.go
deleted file mode 100644
index ccef4fcab57..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/hostname_generic.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// +build !linux
-
-package sysinfo
-
-import "os"
-
-// Hostname returns the host name.
-func Hostname() (string, error) {
- return os.Hostname()
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/hostname_linux.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/hostname_linux.go
deleted file mode 100644
index e2300854d07..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/hostname_linux.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package sysinfo
-
-import (
- "os"
- "syscall"
-)
-
-// Hostname returns the host name.
-func Hostname() (string, error) {
- // Try the builtin API first, which is designed to match the output of
- // /bin/hostname, and fallback to uname(2) if that fails to match the
- // behavior of gethostname(2) as implemented by glibc. On Linux, all
- // these method should result in the same value because sethostname(2)
- // limits the hostname to 64 bytes, the same size of the nodename field
- // returned by uname(2). Note that is correspondence is not true on
- // other platforms.
- //
- // os.Hostname failures should be exceedingly rare, however some systems
- // configure SELinux to deny read access to /proc/sys/kernel/hostname.
- // Redhat's OpenShift platform for example. os.Hostname can also fail if
- // some or all of /proc has been hidden via chroot(2) or manipulation of
- // the current processes' filesystem namespace via the cgroups APIs.
- // Docker is an example of a tool that can configure such an
- // environment.
- name, err := os.Hostname()
- if err == nil {
- return name, nil
- }
-
- var uts syscall.Utsname
- if err2 := syscall.Uname(&uts); err2 != nil {
- // The man page documents only one possible error for uname(2),
- // suggesting that as long as the buffer given is valid, the
- // call will never fail. Return the original error in the hope
- // it provides more relevant information about why the hostname
- // can't be retrieved.
- return "", err
- }
-
- // Convert Nodename to a Go string.
- buf := make([]byte, 0, len(uts.Nodename))
- for _, c := range uts.Nodename {
- if c == 0 {
- break
- }
- buf = append(buf, byte(c))
- }
-
- return string(buf), nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal.go
deleted file mode 100644
index 0763ee301a2..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package sysinfo
-
-import (
- "bufio"
- "errors"
- "io"
- "regexp"
- "strconv"
-)
-
-// BytesToMebibytes converts bytes into mebibytes.
-func BytesToMebibytes(bts uint64) uint64 {
- return bts / ((uint64)(1024 * 1024))
-}
-
-var (
- meminfoRe = regexp.MustCompile(`^MemTotal:\s+([0-9]+)\s+[kK]B$`)
- errMemTotalNotFound = errors.New("supported MemTotal not found in /proc/meminfo")
-)
-
-// parseProcMeminfo is used to parse Linux's "/proc/meminfo". It is located
-// here so that the relevant cross agent tests will be run on all platforms.
-func parseProcMeminfo(f io.Reader) (uint64, error) {
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- if m := meminfoRe.FindSubmatch(scanner.Bytes()); m != nil {
- kb, err := strconv.ParseUint(string(m[1]), 10, 64)
- if err != nil {
- return 0, err
- }
- return kb * 1024, nil
- }
- }
-
- err := scanner.Err()
- if err == nil {
- err = errMemTotalNotFound
- }
- return 0, err
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_darwin.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_darwin.go
deleted file mode 100644
index 3c40f42d5df..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_darwin.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package sysinfo
-
-import (
- "syscall"
- "unsafe"
-)
-
-// PhysicalMemoryBytes returns the total amount of host memory.
-func PhysicalMemoryBytes() (uint64, error) {
- mib := []int32{6 /* CTL_HW */, 24 /* HW_MEMSIZE */}
-
- buf := make([]byte, 8)
- bufLen := uintptr(8)
-
- _, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL,
- uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)),
- uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&bufLen)),
- uintptr(0), uintptr(0))
-
- if e1 != 0 {
- return 0, e1
- }
-
- if bufLen != 8 {
- return 0, syscall.EIO
- }
-
- return *(*uint64)(unsafe.Pointer(&buf[0])), nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_freebsd.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_freebsd.go
deleted file mode 100644
index 2e82320ac72..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_freebsd.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package sysinfo
-
-import (
- "syscall"
- "unsafe"
-)
-
-// PhysicalMemoryBytes returns the total amount of host memory.
-func PhysicalMemoryBytes() (uint64, error) {
- mib := []int32{6 /* CTL_HW */, 5 /* HW_PHYSMEM */}
-
- buf := make([]byte, 8)
- bufLen := uintptr(8)
-
- _, _, e1 := syscall.Syscall6(syscall.SYS___SYSCTL,
- uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)),
- uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&bufLen)),
- uintptr(0), uintptr(0))
-
- if e1 != 0 {
- return 0, e1
- }
-
- switch bufLen {
- case 4:
- return uint64(*(*uint32)(unsafe.Pointer(&buf[0]))), nil
- case 8:
- return *(*uint64)(unsafe.Pointer(&buf[0])), nil
- default:
- return 0, syscall.EIO
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_linux.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_linux.go
deleted file mode 100644
index 958e569937c..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_linux.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package sysinfo
-
-import "os"
-
-// PhysicalMemoryBytes returns the total amount of host memory.
-func PhysicalMemoryBytes() (uint64, error) {
- f, err := os.Open("/proc/meminfo")
- if err != nil {
- return 0, err
- }
- defer f.Close()
-
- return parseProcMeminfo(f)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_solaris.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_solaris.go
deleted file mode 100644
index 4f1c818e552..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_solaris.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package sysinfo
-
-/*
-#include
-*/
-import "C"
-
-// PhysicalMemoryBytes returns the total amount of host memory.
-func PhysicalMemoryBytes() (uint64, error) {
- // The function we're calling on Solaris is
- // long sysconf(int name);
- var pages C.long
- var pagesizeBytes C.long
- var err error
-
- pagesizeBytes, err = C.sysconf(C._SC_PAGE_SIZE)
- if pagesizeBytes < 1 {
- return 0, err
- }
- pages, err = C.sysconf(C._SC_PHYS_PAGES)
- if pages < 1 {
- return 0, err
- }
-
- return uint64(pages) * uint64(pagesizeBytes), nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_windows.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_windows.go
deleted file mode 100644
index b211317e1f4..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/memtotal_windows.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package sysinfo
-
-import (
- "syscall"
- "unsafe"
-)
-
-// PhysicalMemoryBytes returns the total amount of host memory.
-func PhysicalMemoryBytes() (uint64, error) {
- // https://msdn.microsoft.com/en-us/library/windows/desktop/cc300158(v=vs.85).aspx
- // http://stackoverflow.com/questions/30743070/query-total-physical-memory-in-windows-with-golang
- mod := syscall.NewLazyDLL("kernel32.dll")
- proc := mod.NewProc("GetPhysicallyInstalledSystemMemory")
- var memkb uint64
-
- ret, _, err := proc.Call(uintptr(unsafe.Pointer(&memkb)))
- // return value TRUE(1) succeeds, FAILED(0) fails
- if ret != 1 {
- return 0, err
- }
-
- return memkb * 1024, nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/usage.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/usage.go
deleted file mode 100644
index 071049edabf..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/usage.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package sysinfo
-
-import (
- "time"
-)
-
-// Usage contains process process times.
-type Usage struct {
- System time.Duration
- User time.Duration
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/usage_posix.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/usage_posix.go
deleted file mode 100644
index 3f7ab31f735..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/usage_posix.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// +build !windows
-
-package sysinfo
-
-import (
- "syscall"
- "time"
-)
-
-func timevalToDuration(tv syscall.Timeval) time.Duration {
- return time.Duration(tv.Nano()) * time.Nanosecond
-}
-
-// GetUsage gathers process times.
-func GetUsage() (Usage, error) {
- ru := syscall.Rusage{}
- err := syscall.Getrusage(syscall.RUSAGE_SELF, &ru)
- if err != nil {
- return Usage{}, err
- }
-
- return Usage{
- System: timevalToDuration(ru.Stime),
- User: timevalToDuration(ru.Utime),
- }, nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/sysinfo/usage_windows.go b/vendor/github.com/newrelic/go-agent/internal/sysinfo/usage_windows.go
deleted file mode 100644
index 8a8677a35b4..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/sysinfo/usage_windows.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package sysinfo
-
-import (
- "syscall"
- "time"
-)
-
-func filetimeToDuration(ft *syscall.Filetime) time.Duration {
- ns := ft.Nanoseconds()
- return time.Duration(ns)
-}
-
-// GetUsage gathers process times.
-func GetUsage() (Usage, error) {
- var creationTime syscall.Filetime
- var exitTime syscall.Filetime
- var kernelTime syscall.Filetime
- var userTime syscall.Filetime
-
- handle, err := syscall.GetCurrentProcess()
- if err != nil {
- return Usage{}, err
- }
-
- err = syscall.GetProcessTimes(handle, &creationTime, &exitTime, &kernelTime, &userTime)
- if err != nil {
- return Usage{}, err
- }
-
- return Usage{
- System: filetimeToDuration(&kernelTime),
- User: filetimeToDuration(&userTime),
- }, nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/trace_id_generator.go b/vendor/github.com/newrelic/go-agent/internal/trace_id_generator.go
deleted file mode 100644
index 3e6afd55758..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/trace_id_generator.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package internal
-
-import (
- "fmt"
- "math/rand"
- "sync"
-)
-
-// TraceIDGenerator creates identifiers for distributed tracing.
-type TraceIDGenerator struct {
- sync.Mutex
- rnd *rand.Rand
-}
-
-// NewTraceIDGenerator creates a new trace identifier generator.
-func NewTraceIDGenerator(seed int64) *TraceIDGenerator {
- return &TraceIDGenerator{
- rnd: rand.New(rand.NewSource(seed)),
- }
-}
-
-// GenerateTraceID creates a new trace identifier.
-func (tg *TraceIDGenerator) GenerateTraceID() string {
- tg.Lock()
- defer tg.Unlock()
-
- u1 := tg.rnd.Uint32()
- u2 := tg.rnd.Uint32()
- bits := (uint64(u1) << 32) | uint64(u2)
- return fmt.Sprintf("%016x", bits)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/tracing.go b/vendor/github.com/newrelic/go-agent/internal/tracing.go
deleted file mode 100644
index 8cc236086a2..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/tracing.go
+++ /dev/null
@@ -1,705 +0,0 @@
-package internal
-
-import (
- "bytes"
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "time"
-
- "github.com/newrelic/go-agent/internal/cat"
- "github.com/newrelic/go-agent/internal/jsonx"
- "github.com/newrelic/go-agent/internal/logger"
- "github.com/newrelic/go-agent/internal/sysinfo"
-)
-
-// MarshalJSON limits the number of decimals.
-func (p *Priority) MarshalJSON() ([]byte, error) {
- return []byte(fmt.Sprintf(priorityFormat, *p)), nil
-}
-
-// WriteJSON limits the number of decimals.
-func (p Priority) WriteJSON(buf *bytes.Buffer) {
- fmt.Fprintf(buf, priorityFormat, p)
-}
-
-// TxnEvent represents a transaction.
-// https://source.datanerd.us/agents/agent-specs/blob/master/Transaction-Events-PORTED.md
-// https://newrelic.atlassian.net/wiki/display/eng/Agent+Support+for+Synthetics%3A+Forced+Transaction+Traces+and+Analytic+Events
-type TxnEvent struct {
- FinalName string
- Start time.Time
- Duration time.Duration
- TotalTime time.Duration
- Queuing time.Duration
- Zone ApdexZone
- Attrs *Attributes
- DatastoreExternalTotals
- CrossProcess TxnCrossProcess
- BetterCAT BetterCAT
- HasError bool
-}
-
-// BetterCAT stores the transaction's priority and all fields related
-// to a DistributedTracer's Cross-Application Trace.
-type BetterCAT struct {
- Enabled bool
- Priority Priority
- Sampled bool
- Inbound *Payload
- ID string
-}
-
-// TraceID returns the trace id.
-func (e BetterCAT) TraceID() string {
- if nil != e.Inbound {
- return e.Inbound.TracedID
- }
- return e.ID
-}
-
-// TxnData contains the recorded data of a transaction.
-type TxnData struct {
- TxnEvent
- IsWeb bool
- Name string // Work in progress name.
- Errors TxnErrors // Lazily initialized.
- Stop time.Time
- ApdexThreshold time.Duration
-
- stamp segmentStamp
- threadIDCounter uint64
-
- TraceIDGenerator *TraceIDGenerator
- LazilyCalculateSampled func() bool
- SpanEventsEnabled bool
- rootSpanID string
- spanEvents []*SpanEvent
-
- customSegments map[string]*metricData
- datastoreSegments map[DatastoreMetricKey]*metricData
- externalSegments map[externalMetricKey]*metricData
-
- TxnTrace
-
- SlowQueriesEnabled bool
- SlowQueryThreshold time.Duration
- SlowQueries *slowQueries
-
- // These better CAT supportability fields are left outside of
- // TxnEvent.BetterCAT to minimize the size of transaction event memory.
- DistributedTracingSupport
-}
-
-func (t *TxnData) saveTraceSegment(end segmentEnd, name string, attrs spanAttributeMap, externalGUID string) {
- attrs = t.Attrs.filterSpanAttributes(attrs, destSegment)
- t.TxnTrace.witnessNode(end, name, attrs, externalGUID)
-}
-
-// Thread contains a segment stack that is used to track segment parenting time
-// within a single goroutine.
-type Thread struct {
- threadID uint64
- stack []segmentFrame
- // start and end are used to track the TotalTime this Thread was active.
- start time.Time
- end time.Time
-}
-
-// RecordActivity indicates that activity happened at this time on this
-// goroutine which helps track total time.
-func (thread *Thread) RecordActivity(now time.Time) {
- if thread.start.IsZero() || now.Before(thread.start) {
- thread.start = now
- }
- if now.After(thread.end) {
- thread.end = now
- }
-}
-
-// TotalTime returns the amount to time that this thread contributes to the
-// total time.
-func (thread *Thread) TotalTime() time.Duration {
- if thread.start.Before(thread.end) {
- return thread.end.Sub(thread.start)
- }
- return 0
-}
-
-// NewThread returns a new Thread to track segments in a new goroutine.
-func NewThread(txndata *TxnData) *Thread {
- // Each thread needs a unique ID.
- txndata.threadIDCounter++
- return &Thread{
- threadID: txndata.threadIDCounter,
- }
-}
-
-type segmentStamp uint64
-
-type segmentTime struct {
- Stamp segmentStamp
- Time time.Time
-}
-
-// SegmentStartTime is embedded into the top level segments (rather than
-// segmentTime) to minimize the structure sizes to minimize allocations.
-type SegmentStartTime struct {
- Stamp segmentStamp
- Depth int
-}
-
-type stringJSONWriter string
-
-func (s stringJSONWriter) WriteJSON(buf *bytes.Buffer) {
- jsonx.AppendString(buf, string(s))
-}
-
-// spanAttributeMap is used for span attributes and segment attributes. The
-// value is a jsonWriter to allow for segment query parameters.
-type spanAttributeMap map[SpanAttribute]jsonWriter
-
-func (m *spanAttributeMap) addString(key SpanAttribute, val string) {
- if "" != val {
- m.add(key, stringJSONWriter(val))
- }
-}
-
-func (m *spanAttributeMap) add(key SpanAttribute, val jsonWriter) {
- if *m == nil {
- *m = make(spanAttributeMap)
- }
- (*m)[key] = val
-}
-
-func (m spanAttributeMap) copy() spanAttributeMap {
- if len(m) == 0 {
- return nil
- }
- cpy := make(spanAttributeMap, len(m))
- for k, v := range m {
- cpy[k] = v
- }
- return cpy
-}
-
-type segmentFrame struct {
- segmentTime
- children time.Duration
- spanID string
- attributes spanAttributeMap
-}
-
-type segmentEnd struct {
- start segmentTime
- stop segmentTime
- duration time.Duration
- exclusive time.Duration
- SpanID string
- ParentID string
- threadID uint64
- attributes spanAttributeMap
-}
-
-func (end segmentEnd) spanEvent() *SpanEvent {
- if "" == end.SpanID {
- return nil
- }
- return &SpanEvent{
- GUID: end.SpanID,
- ParentID: end.ParentID,
- Timestamp: end.start.Time,
- Duration: end.duration,
- Attributes: end.attributes,
- IsEntrypoint: false,
- }
-}
-
-const (
- datastoreProductUnknown = "Unknown"
- datastoreOperationUnknown = "other"
-)
-
-// HasErrors indicates whether the transaction had errors.
-func (t *TxnData) HasErrors() bool {
- return len(t.Errors) > 0
-}
-
-func (t *TxnData) time(now time.Time) segmentTime {
- // Update the stamp before using it so that a 0 stamp can be special.
- t.stamp++
- return segmentTime{
- Time: now,
- Stamp: t.stamp,
- }
-}
-
-// AddAgentSpanAttribute allows attributes to be added to spans.
-func (thread *Thread) AddAgentSpanAttribute(key SpanAttribute, val string) {
- if len(thread.stack) > 0 {
- thread.stack[len(thread.stack)-1].attributes.addString(key, val)
- }
-}
-
-// StartSegment begins a segment.
-func StartSegment(t *TxnData, thread *Thread, now time.Time) SegmentStartTime {
- tm := t.time(now)
- thread.stack = append(thread.stack, segmentFrame{
- segmentTime: tm,
- children: 0,
- })
-
- return SegmentStartTime{
- Stamp: tm.Stamp,
- Depth: len(thread.stack) - 1,
- }
-}
-
-func (t *TxnData) getRootSpanID() string {
- if "" == t.rootSpanID {
- t.rootSpanID = t.TraceIDGenerator.GenerateTraceID()
- }
- return t.rootSpanID
-}
-
-// CurrentSpanIdentifier returns the identifier of the span at the top of the
-// segment stack.
-func (t *TxnData) CurrentSpanIdentifier(thread *Thread) string {
- if 0 == len(thread.stack) {
- return t.getRootSpanID()
- }
- if "" == thread.stack[len(thread.stack)-1].spanID {
- thread.stack[len(thread.stack)-1].spanID = t.TraceIDGenerator.GenerateTraceID()
- }
- return thread.stack[len(thread.stack)-1].spanID
-}
-
-func (t *TxnData) saveSpanEvent(e *SpanEvent) {
- e.Attributes = t.Attrs.filterSpanAttributes(e.Attributes, destSpan)
- if len(t.spanEvents) < maxSpanEvents {
- t.spanEvents = append(t.spanEvents, e)
- }
-}
-
-var (
- errMalformedSegment = errors.New("segment identifier malformed: perhaps unsafe code has modified it?")
- errSegmentOrder = errors.New(`improper segment use: the Transaction must be used ` +
- `in a single goroutine and segments must be ended in "last started first ended" order: ` +
- `see https://github.com/newrelic/go-agent/blob/master/GUIDE.md#segments`)
-)
-
-func endSegment(t *TxnData, thread *Thread, start SegmentStartTime, now time.Time) (segmentEnd, error) {
- if 0 == start.Stamp {
- return segmentEnd{}, errMalformedSegment
- }
- if start.Depth >= len(thread.stack) {
- return segmentEnd{}, errSegmentOrder
- }
- if start.Depth < 0 {
- return segmentEnd{}, errMalformedSegment
- }
- frame := thread.stack[start.Depth]
- if start.Stamp != frame.Stamp {
- return segmentEnd{}, errSegmentOrder
- }
-
- var children time.Duration
- for i := start.Depth; i < len(thread.stack); i++ {
- children += thread.stack[i].children
- }
- s := segmentEnd{
- stop: t.time(now),
- start: frame.segmentTime,
- attributes: frame.attributes,
- }
- if s.stop.Time.After(s.start.Time) {
- s.duration = s.stop.Time.Sub(s.start.Time)
- }
- if s.duration > children {
- s.exclusive = s.duration - children
- }
-
- // Note that we expect (depth == (len(t.stack) - 1)). However, if
- // (depth < (len(t.stack) - 1)), that's ok: could be a panic popped
- // some stack frames (and the consumer was not using defer).
-
- if start.Depth > 0 {
- thread.stack[start.Depth-1].children += s.duration
- }
-
- thread.stack = thread.stack[0:start.Depth]
-
- if t.SpanEventsEnabled && t.LazilyCalculateSampled() {
- s.SpanID = frame.spanID
- if "" == s.SpanID {
- s.SpanID = t.TraceIDGenerator.GenerateTraceID()
- }
- // Note that the current span identifier is the parent's
- // identifier because we've already popped the segment that's
- // ending off of the stack.
- s.ParentID = t.CurrentSpanIdentifier(thread)
- }
-
- s.threadID = thread.threadID
-
- thread.RecordActivity(s.start.Time)
- thread.RecordActivity(s.stop.Time)
-
- return s, nil
-}
-
-// EndBasicSegment ends a basic segment.
-func EndBasicSegment(t *TxnData, thread *Thread, start SegmentStartTime, now time.Time, name string) error {
- end, err := endSegment(t, thread, start, now)
- if nil != err {
- return err
- }
- if nil == t.customSegments {
- t.customSegments = make(map[string]*metricData)
- }
- m := metricDataFromDuration(end.duration, end.exclusive)
- if data, ok := t.customSegments[name]; ok {
- data.aggregate(m)
- } else {
- // Use `new` in place of &m so that m is not
- // automatically moved to the heap.
- cpy := new(metricData)
- *cpy = m
- t.customSegments[name] = cpy
- }
-
- if t.TxnTrace.considerNode(end) {
- attributes := end.attributes.copy()
- t.saveTraceSegment(end, customSegmentMetric(name), attributes, "")
- }
-
- if evt := end.spanEvent(); evt != nil {
- evt.Name = customSegmentMetric(name)
- evt.Category = spanCategoryGeneric
- t.saveSpanEvent(evt)
- }
-
- return nil
-}
-
-// EndExternalParams contains the parameters for EndExternalSegment.
-type EndExternalParams struct {
- TxnData *TxnData
- Thread *Thread
- Start SegmentStartTime
- Now time.Time
- Logger logger.Logger
- Response *http.Response
- URL *url.URL
- Host string
- Library string
- Method string
-}
-
-// EndExternalSegment ends an external segment.
-func EndExternalSegment(p EndExternalParams) error {
- t := p.TxnData
- end, err := endSegment(t, p.Thread, p.Start, p.Now)
- if nil != err {
- return err
- }
-
- // Use the Host field if present, otherwise use host in the URL.
- if p.Host == "" && p.URL != nil {
- p.Host = p.URL.Host
- }
- if p.Host == "" {
- p.Host = "unknown"
- }
- if p.Library == "" {
- p.Library = "http"
- }
-
- var appData *cat.AppDataHeader
- if p.Response != nil {
- hdr := HTTPHeaderToAppData(p.Response.Header)
- appData, err = t.CrossProcess.ParseAppData(hdr)
- if err != nil {
- if p.Logger.DebugEnabled() {
- p.Logger.Debug("failure to parse cross application response header", map[string]interface{}{
- "err": err.Error(),
- "header": hdr,
- })
- }
- }
- }
-
- var crossProcessID string
- var transactionName string
- var transactionGUID string
- if appData != nil {
- crossProcessID = appData.CrossProcessID
- transactionName = appData.TransactionName
- transactionGUID = appData.TransactionGUID
- }
-
- key := externalMetricKey{
- Host: p.Host,
- Library: p.Library,
- Method: p.Method,
- ExternalCrossProcessID: crossProcessID,
- ExternalTransactionName: transactionName,
- }
- if nil == t.externalSegments {
- t.externalSegments = make(map[externalMetricKey]*metricData)
- }
- t.externalCallCount++
- t.externalDuration += end.duration
- m := metricDataFromDuration(end.duration, end.exclusive)
- if data, ok := t.externalSegments[key]; ok {
- data.aggregate(m)
- } else {
- // Use `new` in place of &m so that m is not
- // automatically moved to the heap.
- cpy := new(metricData)
- *cpy = m
- t.externalSegments[key] = cpy
- }
-
- if t.TxnTrace.considerNode(end) {
- attributes := end.attributes.copy()
- if p.Library == "http" {
- attributes.addString(spanAttributeHTTPURL, SafeURL(p.URL))
- }
- t.saveTraceSegment(end, key.scopedMetric(), attributes, transactionGUID)
- }
-
- if evt := end.spanEvent(); evt != nil {
- evt.Name = key.scopedMetric()
- evt.Category = spanCategoryHTTP
- evt.Kind = "client"
- evt.Component = p.Library
- if p.Library == "http" {
- evt.Attributes.addString(spanAttributeHTTPURL, SafeURL(p.URL))
- evt.Attributes.addString(spanAttributeHTTPMethod, p.Method)
- }
- t.saveSpanEvent(evt)
- }
-
- return nil
-}
-
-// EndDatastoreParams contains the parameters for EndDatastoreSegment.
-type EndDatastoreParams struct {
- TxnData *TxnData
- Thread *Thread
- Start SegmentStartTime
- Now time.Time
- Product string
- Collection string
- Operation string
- ParameterizedQuery string
- QueryParameters map[string]interface{}
- Host string
- PortPathOrID string
- Database string
-}
-
-const (
- unknownDatastoreHost = "unknown"
- unknownDatastorePortPathOrID = "unknown"
-)
-
-var (
- // ThisHost is the system hostname.
- ThisHost = func() string {
- if h, err := sysinfo.Hostname(); nil == err {
- return h
- }
- return unknownDatastoreHost
- }()
- hostsToReplace = map[string]struct{}{
- "localhost": {},
- "127.0.0.1": {},
- "0.0.0.0": {},
- "0:0:0:0:0:0:0:1": {},
- "::1": {},
- "0:0:0:0:0:0:0:0": {},
- "::": {},
- }
-)
-
-func (t TxnData) slowQueryWorthy(d time.Duration) bool {
- return t.SlowQueriesEnabled && (d >= t.SlowQueryThreshold)
-}
-
-func datastoreSpanAddress(host, portPathOrID string) string {
- if "" != host && "" != portPathOrID {
- return host + ":" + portPathOrID
- }
- if "" != host {
- return host
- }
- return portPathOrID
-}
-
-// EndDatastoreSegment ends a datastore segment.
-func EndDatastoreSegment(p EndDatastoreParams) error {
- end, err := endSegment(p.TxnData, p.Thread, p.Start, p.Now)
- if nil != err {
- return err
- }
- if p.Operation == "" {
- p.Operation = datastoreOperationUnknown
- }
- if p.Product == "" {
- p.Product = datastoreProductUnknown
- }
- if p.Host == "" && p.PortPathOrID != "" {
- p.Host = unknownDatastoreHost
- }
- if p.PortPathOrID == "" && p.Host != "" {
- p.PortPathOrID = unknownDatastorePortPathOrID
- }
- if _, ok := hostsToReplace[p.Host]; ok {
- p.Host = ThisHost
- }
-
- // We still want to create a slowQuery if the consumer has not provided
- // a Query string (or it has been removed by LASP) since the stack trace
- // has value.
- if p.ParameterizedQuery == "" {
- collection := p.Collection
- if "" == collection {
- collection = "unknown"
- }
- p.ParameterizedQuery = fmt.Sprintf(`'%s' on '%s' using '%s'`,
- p.Operation, collection, p.Product)
- }
-
- key := DatastoreMetricKey{
- Product: p.Product,
- Collection: p.Collection,
- Operation: p.Operation,
- Host: p.Host,
- PortPathOrID: p.PortPathOrID,
- }
- if nil == p.TxnData.datastoreSegments {
- p.TxnData.datastoreSegments = make(map[DatastoreMetricKey]*metricData)
- }
- p.TxnData.datastoreCallCount++
- p.TxnData.datastoreDuration += end.duration
- m := metricDataFromDuration(end.duration, end.exclusive)
- if data, ok := p.TxnData.datastoreSegments[key]; ok {
- data.aggregate(m)
- } else {
- // Use `new` in place of &m so that m is not
- // automatically moved to the heap.
- cpy := new(metricData)
- *cpy = m
- p.TxnData.datastoreSegments[key] = cpy
- }
-
- scopedMetric := datastoreScopedMetric(key)
- // errors in QueryParameters must not stop the recording of the segment
- queryParams, err := vetQueryParameters(p.QueryParameters)
-
- if p.TxnData.TxnTrace.considerNode(end) {
- attributes := end.attributes.copy()
- attributes.addString(spanAttributeDBStatement, p.ParameterizedQuery)
- attributes.addString(spanAttributeDBInstance, p.Database)
- attributes.addString(spanAttributePeerAddress, datastoreSpanAddress(p.Host, p.PortPathOrID))
- attributes.addString(spanAttributePeerHostname, p.Host)
- if len(queryParams) > 0 {
- attributes.add(spanAttributeQueryParameters, queryParams)
- }
- p.TxnData.saveTraceSegment(end, scopedMetric, attributes, "")
- }
-
- if p.TxnData.slowQueryWorthy(end.duration) {
- if nil == p.TxnData.SlowQueries {
- p.TxnData.SlowQueries = newSlowQueries(maxTxnSlowQueries)
- }
- p.TxnData.SlowQueries.observeInstance(slowQueryInstance{
- Duration: end.duration,
- DatastoreMetric: scopedMetric,
- ParameterizedQuery: p.ParameterizedQuery,
- QueryParameters: queryParams,
- Host: p.Host,
- PortPathOrID: p.PortPathOrID,
- DatabaseName: p.Database,
- StackTrace: GetStackTrace(),
- })
- }
-
- if evt := end.spanEvent(); evt != nil {
- evt.Name = scopedMetric
- evt.Category = spanCategoryDatastore
- evt.Kind = "client"
- evt.Component = p.Product
- evt.Attributes.addString(spanAttributeDBStatement, p.ParameterizedQuery)
- evt.Attributes.addString(spanAttributeDBInstance, p.Database)
- evt.Attributes.addString(spanAttributePeerAddress, datastoreSpanAddress(p.Host, p.PortPathOrID))
- evt.Attributes.addString(spanAttributePeerHostname, p.Host)
- evt.Attributes.addString(spanAttributeDBCollection, p.Collection)
- p.TxnData.saveSpanEvent(evt)
- }
-
- return err
-}
-
-// MergeBreakdownMetrics creates segment metrics.
-func MergeBreakdownMetrics(t *TxnData, metrics *metricTable) {
- scope := t.FinalName
- isWeb := t.IsWeb
- // Custom Segment Metrics
- for key, data := range t.customSegments {
- name := customSegmentMetric(key)
- // Unscoped
- metrics.add(name, "", *data, unforced)
- // Scoped
- metrics.add(name, scope, *data, unforced)
- }
-
- // External Segment Metrics
- for key, data := range t.externalSegments {
- metrics.add(externalRollupMetric.all, "", *data, forced)
- metrics.add(externalRollupMetric.webOrOther(isWeb), "", *data, forced)
-
- hostMetric := externalHostMetric(key)
- metrics.add(hostMetric, "", *data, unforced)
- if "" != key.ExternalCrossProcessID && "" != key.ExternalTransactionName {
- txnMetric := externalTransactionMetric(key)
-
- // Unscoped CAT metrics
- metrics.add(externalAppMetric(key), "", *data, unforced)
- metrics.add(txnMetric, "", *data, unforced)
- }
-
- // Scoped External Metric
- metrics.add(key.scopedMetric(), scope, *data, unforced)
- }
-
- // Datastore Segment Metrics
- for key, data := range t.datastoreSegments {
- metrics.add(datastoreRollupMetric.all, "", *data, forced)
- metrics.add(datastoreRollupMetric.webOrOther(isWeb), "", *data, forced)
-
- product := datastoreProductMetric(key)
- metrics.add(product.all, "", *data, forced)
- metrics.add(product.webOrOther(isWeb), "", *data, forced)
-
- if key.Host != "" && key.PortPathOrID != "" {
- instance := datastoreInstanceMetric(key)
- metrics.add(instance, "", *data, unforced)
- }
-
- operation := datastoreOperationMetric(key)
- metrics.add(operation, "", *data, unforced)
-
- if "" != key.Collection {
- statement := datastoreStatementMetric(key)
-
- metrics.add(statement, "", *data, unforced)
- metrics.add(statement, scope, *data, unforced)
- } else {
- metrics.add(operation, scope, *data, unforced)
- }
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/txn_cross_process.go b/vendor/github.com/newrelic/go-agent/internal/txn_cross_process.go
deleted file mode 100644
index 5b251a1b3da..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/txn_cross_process.go
+++ /dev/null
@@ -1,417 +0,0 @@
-package internal
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "time"
-
- "github.com/newrelic/go-agent/internal/cat"
-)
-
-// Bitfield values for the TxnCrossProcess.Type field.
-const (
- txnCrossProcessSynthetics = (1 << 0)
- txnCrossProcessInbound = (1 << 1)
- txnCrossProcessOutbound = (1 << 2)
-)
-
-var (
- // ErrAccountNotTrusted indicates that, while the inbound headers were valid,
- // the account ID within them is not trusted by the user's application.
- ErrAccountNotTrusted = errors.New("account not trusted")
-)
-
-// TxnCrossProcess contains the metadata required for CAT and Synthetics
-// headers, transaction events, and traces.
-type TxnCrossProcess struct {
- // The user side switch controlling whether CAT is enabled or not.
- Enabled bool
-
- // The user side switch controlling whether Distributed Tracing is enabled or not
- // This is required by synthetics support. If Distributed Tracing is enabled,
- // any synthetics functionality that is triggered should not set nr.guid.
- DistributedTracingEnabled bool
-
- // Rather than copying in the entire ConnectReply, here are the fields that
- // we need to support CAT.
- CrossProcessID []byte
- EncodingKey []byte
- TrustedAccounts trustedAccountSet
-
- // CAT state for a given transaction.
- Type uint8
- ClientID string
- GUID string
- TripID string
- PathHash string
- AlternatePathHashes map[string]bool
- ReferringPathHash string
- ReferringTxnGUID string
- Synthetics *cat.SyntheticsHeader
-
- // The encoded synthetics header received as part of the request headers, if
- // any. By storing this here, we avoid needing to marshal the invariant
- // Synthetics struct above each time an external segment is created.
- SyntheticsHeader string
-}
-
-// CrossProcessMetadata represents the metadata that must be transmitted with
-// an external request for CAT to work.
-type CrossProcessMetadata struct {
- ID string
- TxnData string
- Synthetics string
-}
-
-// Init initialises a TxnCrossProcess based on the given application connect
-// reply.
-func (txp *TxnCrossProcess) Init(enabled bool, dt bool, reply *ConnectReply) {
- txp.CrossProcessID = []byte(reply.CrossProcessID)
- txp.EncodingKey = []byte(reply.EncodingKey)
- txp.DistributedTracingEnabled = dt
- txp.Enabled = enabled
- txp.TrustedAccounts = reply.TrustedAccounts
-}
-
-// CreateCrossProcessMetadata generates request metadata that enable CAT and
-// Synthetics support for an external segment.
-func (txp *TxnCrossProcess) CreateCrossProcessMetadata(txnName, appName string) (CrossProcessMetadata, error) {
- metadata := CrossProcessMetadata{}
-
- // Regardless of the user's CAT settings, if there was a synthetics header in
- // the inbound request, a synthetics header should always be included in the
- // outbound request headers.
- if txp.IsSynthetics() {
- metadata.Synthetics = txp.SyntheticsHeader
- }
-
- if txp.Enabled {
- txp.SetOutbound(true)
- txp.requireTripID()
-
- id, err := txp.outboundID()
- if err != nil {
- return metadata, err
- }
-
- txnData, err := txp.outboundTxnData(txnName, appName)
- if err != nil {
- return metadata, err
- }
-
- metadata.ID = id
- metadata.TxnData = txnData
- }
-
- return metadata, nil
-}
-
-// Finalise handles any end-of-transaction tasks. In practice, this simply
-// means ensuring the path hash is set if it hasn't already been.
-func (txp *TxnCrossProcess) Finalise(txnName, appName string) error {
- if txp.Enabled && txp.Used() {
- _, err := txp.setPathHash(txnName, appName)
- return err
- }
-
- // If there was no CAT activity, then do nothing, successfully.
- return nil
-}
-
-// IsInbound returns true if the transaction had inbound CAT headers.
-func (txp *TxnCrossProcess) IsInbound() bool {
- return 0 != (txp.Type & txnCrossProcessInbound)
-}
-
-// IsOutbound returns true if the transaction has generated outbound CAT
-// headers.
-func (txp *TxnCrossProcess) IsOutbound() bool {
- // We don't actually use this anywhere today, but it feels weird not having
- // it.
- return 0 != (txp.Type & txnCrossProcessOutbound)
-}
-
-// IsSynthetics returns true if the transaction had inbound Synthetics headers.
-func (txp *TxnCrossProcess) IsSynthetics() bool {
- // Technically, this is redundant: the presence of a non-nil Synthetics
- // pointer should be sufficient to determine if this is a synthetics
- // transaction. Nevertheless, it's convenient to have the Type field be
- // non-zero if any CAT behaviour has occurred.
- return 0 != (txp.Type&txnCrossProcessSynthetics) && nil != txp.Synthetics
-}
-
-// ParseAppData decodes the given appData value.
-func (txp *TxnCrossProcess) ParseAppData(encodedAppData string) (*cat.AppDataHeader, error) {
- if !txp.Enabled {
- return nil, nil
- }
- if encodedAppData != "" {
- rawAppData, err := Deobfuscate(encodedAppData, txp.EncodingKey)
- if err != nil {
- return nil, err
- }
-
- appData := &cat.AppDataHeader{}
- if err := json.Unmarshal(rawAppData, appData); err != nil {
- return nil, err
- }
-
- return appData, nil
- }
-
- return nil, nil
-}
-
-// CreateAppData creates the appData value that should be sent with a response
-// to ensure CAT operates as expected.
-func (txp *TxnCrossProcess) CreateAppData(name string, queueTime, responseTime time.Duration, contentLength int64) (string, error) {
- // If CAT is disabled, do nothing, successfully.
- if !txp.Enabled {
- return "", nil
- }
-
- data, err := json.Marshal(&cat.AppDataHeader{
- CrossProcessID: string(txp.CrossProcessID),
- TransactionName: name,
- QueueTimeInSeconds: queueTime.Seconds(),
- ResponseTimeInSeconds: responseTime.Seconds(),
- ContentLength: contentLength,
- TransactionGUID: txp.GUID,
- })
- if err != nil {
- return "", err
- }
-
- obfuscated, err := Obfuscate(data, txp.EncodingKey)
- if err != nil {
- return "", err
- }
-
- return obfuscated, nil
-}
-
-// Used returns true if any CAT or Synthetics related functionality has been
-// triggered on the transaction.
-func (txp *TxnCrossProcess) Used() bool {
- return 0 != txp.Type
-}
-
-// SetInbound sets the inbound CAT flag. This function is provided only for
-// internal and unit testing purposes, and should not be used outside of this
-// package normally.
-func (txp *TxnCrossProcess) SetInbound(inbound bool) {
- if inbound {
- txp.Type |= txnCrossProcessInbound
- } else {
- txp.Type &^= txnCrossProcessInbound
- }
-}
-
-// SetOutbound sets the outbound CAT flag. This function is provided only for
-// internal and unit testing purposes, and should not be used outside of this
-// package normally.
-func (txp *TxnCrossProcess) SetOutbound(outbound bool) {
- if outbound {
- txp.Type |= txnCrossProcessOutbound
- } else {
- txp.Type &^= txnCrossProcessOutbound
- }
-}
-
-// SetSynthetics sets the Synthetics CAT flag. This function is provided only
-// for internal and unit testing purposes, and should not be used outside of
-// this package normally.
-func (txp *TxnCrossProcess) SetSynthetics(synthetics bool) {
- if synthetics {
- txp.Type |= txnCrossProcessSynthetics
- } else {
- txp.Type &^= txnCrossProcessSynthetics
- }
-}
-
-// handleInboundRequestHeaders parses the CAT headers from the given metadata
-// and updates the relevant fields on the provided TxnData.
-func (txp *TxnCrossProcess) handleInboundRequestHeaders(metadata CrossProcessMetadata) error {
- if txp.Enabled && metadata.ID != "" && metadata.TxnData != "" {
- if err := txp.handleInboundRequestEncodedCAT(metadata.ID, metadata.TxnData); err != nil {
- return err
- }
- }
-
- if metadata.Synthetics != "" {
- if err := txp.handleInboundRequestEncodedSynthetics(metadata.Synthetics); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func (txp *TxnCrossProcess) handleInboundRequestEncodedCAT(encodedID, encodedTxnData string) error {
- rawID, err := Deobfuscate(encodedID, txp.EncodingKey)
- if err != nil {
- return err
- }
-
- rawTxnData, err := Deobfuscate(encodedTxnData, txp.EncodingKey)
- if err != nil {
- return err
- }
-
- if err := txp.handleInboundRequestID(rawID); err != nil {
- return err
- }
-
- return txp.handleInboundRequestTxnData(rawTxnData)
-}
-
-func (txp *TxnCrossProcess) handleInboundRequestID(raw []byte) error {
- id, err := cat.NewIDHeader(raw)
- if err != nil {
- return err
- }
-
- if !txp.TrustedAccounts.IsTrusted(id.AccountID) {
- return ErrAccountNotTrusted
- }
-
- txp.SetInbound(true)
- txp.ClientID = string(raw)
- txp.setRequireGUID()
-
- return nil
-}
-
-func (txp *TxnCrossProcess) handleInboundRequestTxnData(raw []byte) error {
- txnData := &cat.TxnDataHeader{}
- if err := json.Unmarshal(raw, txnData); err != nil {
- return err
- }
-
- txp.SetInbound(true)
- if txnData.TripID != "" {
- txp.TripID = txnData.TripID
- } else {
- txp.setRequireGUID()
- txp.TripID = txp.GUID
- }
- txp.ReferringTxnGUID = txnData.GUID
- txp.ReferringPathHash = txnData.PathHash
-
- return nil
-}
-
-func (txp *TxnCrossProcess) handleInboundRequestEncodedSynthetics(encoded string) error {
- raw, err := Deobfuscate(encoded, txp.EncodingKey)
- if err != nil {
- return err
- }
-
- if err := txp.handleInboundRequestSynthetics(raw); err != nil {
- return err
- }
-
- txp.SyntheticsHeader = encoded
- return nil
-}
-
-func (txp *TxnCrossProcess) handleInboundRequestSynthetics(raw []byte) error {
- synthetics := &cat.SyntheticsHeader{}
- if err := json.Unmarshal(raw, synthetics); err != nil {
- return err
- }
-
- // The specced behaviour here if the account isn't trusted is to disable the
- // synthetics handling, but not CAT in general, so we won't return an error
- // here.
- if txp.TrustedAccounts.IsTrusted(synthetics.AccountID) {
- txp.SetSynthetics(true)
- txp.setRequireGUID()
- txp.Synthetics = synthetics
- }
-
- return nil
-}
-
-func (txp *TxnCrossProcess) outboundID() (string, error) {
- return Obfuscate(txp.CrossProcessID, txp.EncodingKey)
-}
-
-func (txp *TxnCrossProcess) outboundTxnData(txnName, appName string) (string, error) {
- pathHash, err := txp.setPathHash(txnName, appName)
- if err != nil {
- return "", err
- }
-
- data, err := json.Marshal(&cat.TxnDataHeader{
- GUID: txp.GUID,
- TripID: txp.TripID,
- PathHash: pathHash,
- })
- if err != nil {
- return "", err
- }
-
- return Obfuscate(data, txp.EncodingKey)
-}
-
-// setRequireGUID ensures that the transaction has a valid GUID, and sets the
-// nr.guid and trip ID if they are not already set. If the customer has enabled
-// DistributedTracing, then the new style of guid will be set elsewhere.
-func (txp *TxnCrossProcess) setRequireGUID() {
- if txp.DistributedTracingEnabled {
- return
- }
-
- if txp.GUID != "" {
- return
- }
-
- txp.GUID = fmt.Sprintf("%x", RandUint64())
-
- if txp.TripID == "" {
- txp.requireTripID()
- }
-}
-
-// requireTripID ensures that the transaction has a valid trip ID.
-func (txp *TxnCrossProcess) requireTripID() {
- if !txp.Enabled {
- return
- }
- if txp.TripID != "" {
- return
- }
-
- txp.setRequireGUID()
- txp.TripID = txp.GUID
-}
-
-// setPathHash generates a path hash, sets the transaction's path hash to
-// match, and returns it. This function will also ensure that the alternate
-// path hashes are correctly updated.
-func (txp *TxnCrossProcess) setPathHash(txnName, appName string) (string, error) {
- pathHash, err := cat.GeneratePathHash(txp.ReferringPathHash, txnName, appName)
- if err != nil {
- return "", err
- }
-
- if pathHash != txp.PathHash {
- if txp.PathHash != "" {
- // Lazily initialise the alternate path hashes if they haven't been
- // already.
- if txp.AlternatePathHashes == nil {
- txp.AlternatePathHashes = make(map[string]bool)
- }
-
- // The spec limits us to a maximum of 10 alternate path hashes.
- if len(txp.AlternatePathHashes) < 10 {
- txp.AlternatePathHashes[txp.PathHash] = true
- }
- }
- txp.PathHash = pathHash
- }
-
- return pathHash, nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/txn_events.go b/vendor/github.com/newrelic/go-agent/internal/txn_events.go
deleted file mode 100644
index 02477f669ad..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/txn_events.go
+++ /dev/null
@@ -1,194 +0,0 @@
-package internal
-
-import (
- "bytes"
- "sort"
- "strings"
- "time"
-)
-
-// DatastoreExternalTotals contains overview of external and datastore calls
-// made during a transaction.
-type DatastoreExternalTotals struct {
- externalCallCount uint64
- externalDuration time.Duration
- datastoreCallCount uint64
- datastoreDuration time.Duration
-}
-
-// WriteJSON prepares JSON in the format expected by the collector.
-func (e *TxnEvent) WriteJSON(buf *bytes.Buffer) {
- w := jsonFieldsWriter{buf: buf}
- buf.WriteByte('[')
- buf.WriteByte('{')
- w.stringField("type", "Transaction")
- w.stringField("name", e.FinalName)
- w.floatField("timestamp", timeToFloatSeconds(e.Start))
- if ApdexNone != e.Zone {
- w.stringField("nr.apdexPerfZone", e.Zone.label())
- }
-
- w.boolField("error", e.HasError)
-
- sharedTransactionIntrinsics(e, &w)
-
- // totalTime gets put into transaction events but not error events:
- // https://source.datanerd.us/agents/agent-specs/blob/master/Total-Time-Async.md#attributes
- w.floatField("totalTime", e.TotalTime.Seconds())
-
- // Write better CAT intrinsics if enabled
- sharedBetterCATIntrinsics(e, &w)
-
- if e.BetterCAT.Enabled {
- if p := e.BetterCAT.Inbound; nil != p {
- if "" != p.TransactionID {
- w.stringField("parentId", p.TransactionID)
- }
-
- if "" != p.ID {
- w.stringField("parentSpanId", p.ID)
- }
- }
- }
-
- // Write old CAT intrinsics if enabled
- oldCATIntrinsics(e, &w)
-
- buf.WriteByte('}')
- buf.WriteByte(',')
- userAttributesJSON(e.Attrs, buf, destTxnEvent, nil)
- buf.WriteByte(',')
- agentAttributesJSON(e.Attrs, buf, destTxnEvent)
- buf.WriteByte(']')
-}
-
-// oldCATIntrinsics reports old CAT intrinsics for Transaction
-// if CrossProcess.Used() is true
-func oldCATIntrinsics(e *TxnEvent, w *jsonFieldsWriter) {
- if !e.CrossProcess.Used() {
- return
- }
-
- if e.CrossProcess.ClientID != "" {
- w.stringField("client_cross_process_id", e.CrossProcess.ClientID)
- }
- if e.CrossProcess.TripID != "" {
- w.stringField("nr.tripId", e.CrossProcess.TripID)
- }
- if e.CrossProcess.PathHash != "" {
- w.stringField("nr.pathHash", e.CrossProcess.PathHash)
- }
- if e.CrossProcess.ReferringPathHash != "" {
- w.stringField("nr.referringPathHash", e.CrossProcess.ReferringPathHash)
- }
- if e.CrossProcess.GUID != "" {
- w.stringField("nr.guid", e.CrossProcess.GUID)
- }
- if e.CrossProcess.ReferringTxnGUID != "" {
- w.stringField("nr.referringTransactionGuid", e.CrossProcess.ReferringTxnGUID)
- }
- if len(e.CrossProcess.AlternatePathHashes) > 0 {
- hashes := make([]string, 0, len(e.CrossProcess.AlternatePathHashes))
- for hash := range e.CrossProcess.AlternatePathHashes {
- hashes = append(hashes, hash)
- }
- sort.Strings(hashes)
- w.stringField("nr.alternatePathHashes", strings.Join(hashes, ","))
- }
-}
-
-// sharedTransactionIntrinsics reports intrinsics that are shared
-// by Transaction and TransactionError
-func sharedTransactionIntrinsics(e *TxnEvent, w *jsonFieldsWriter) {
- w.floatField("duration", e.Duration.Seconds())
- if e.Queuing > 0 {
- w.floatField("queueDuration", e.Queuing.Seconds())
- }
- if e.externalCallCount > 0 {
- w.intField("externalCallCount", int64(e.externalCallCount))
- w.floatField("externalDuration", e.externalDuration.Seconds())
- }
- if e.datastoreCallCount > 0 {
- // Note that "database" is used for the keys here instead of
- // "datastore" for historical reasons.
- w.intField("databaseCallCount", int64(e.datastoreCallCount))
- w.floatField("databaseDuration", e.datastoreDuration.Seconds())
- }
-
- if e.CrossProcess.IsSynthetics() {
- w.stringField("nr.syntheticsResourceId", e.CrossProcess.Synthetics.ResourceID)
- w.stringField("nr.syntheticsJobId", e.CrossProcess.Synthetics.JobID)
- w.stringField("nr.syntheticsMonitorId", e.CrossProcess.Synthetics.MonitorID)
- }
-}
-
-// sharedBetterCATIntrinsics reports intrinsics that are shared
-// by Transaction, TransactionError, and Slow SQL
-func sharedBetterCATIntrinsics(e *TxnEvent, w *jsonFieldsWriter) {
- if e.BetterCAT.Enabled {
- if p := e.BetterCAT.Inbound; nil != p {
- w.stringField("parent.type", p.Type)
- w.stringField("parent.app", p.App)
- w.stringField("parent.account", p.Account)
- w.stringField("parent.transportType", p.TransportType)
- w.floatField("parent.transportDuration", p.TransportDuration.Seconds())
- }
-
- w.stringField("guid", e.BetterCAT.ID)
- w.stringField("traceId", e.BetterCAT.TraceID())
- w.writerField("priority", e.BetterCAT.Priority)
- w.boolField("sampled", e.BetterCAT.Sampled)
- }
-}
-
-// MarshalJSON is used for testing.
-func (e *TxnEvent) MarshalJSON() ([]byte, error) {
- buf := bytes.NewBuffer(make([]byte, 0, 256))
-
- e.WriteJSON(buf)
-
- return buf.Bytes(), nil
-}
-
-type txnEvents struct {
- *analyticsEvents
-}
-
-func newTxnEvents(max int) *txnEvents {
- return &txnEvents{
- analyticsEvents: newAnalyticsEvents(max),
- }
-}
-
-func (events *txnEvents) AddTxnEvent(e *TxnEvent, priority Priority) {
- // Synthetics events always get priority: normal event priorities are in the
- // range [0.0,1.99999], so adding 2 means that a Synthetics event will always
- // win.
- if e.CrossProcess.IsSynthetics() {
- priority += 2.0
- }
- events.addEvent(analyticsEvent{priority: priority, jsonWriter: e})
-}
-
-func (events *txnEvents) MergeIntoHarvest(h *Harvest) {
- h.TxnEvents.mergeFailed(events.analyticsEvents)
-}
-
-func (events *txnEvents) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
- return events.CollectorJSON(agentRunID)
-}
-
-func (events *txnEvents) EndpointMethod() string {
- return cmdTxnEvents
-}
-
-func (events *txnEvents) payloads(limit int) []PayloadCreator {
- if events.NumSaved() < float64(limit) {
- return []PayloadCreator{events}
- }
- e1, e2 := events.split()
- return []PayloadCreator{
- &txnEvents{analyticsEvents: e1},
- &txnEvents{analyticsEvents: e2},
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/txn_trace.go b/vendor/github.com/newrelic/go-agent/internal/txn_trace.go
deleted file mode 100644
index 04b2f6e6d98..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/txn_trace.go
+++ /dev/null
@@ -1,447 +0,0 @@
-package internal
-
-import (
- "bytes"
- "container/heap"
- "sort"
- "time"
-
- "github.com/newrelic/go-agent/internal/jsonx"
-)
-
-// See https://source.datanerd.us/agents/agent-specs/blob/master/Transaction-Trace-LEGACY.md
-
-type traceNodeHeap []traceNode
-
-type traceNodeParams struct {
- attributes map[SpanAttribute]jsonWriter
- StackTrace StackTrace
- TransactionGUID string
- exclusiveDurationMillis *float64
-}
-
-type traceNode struct {
- start segmentTime
- stop segmentTime
- threadID uint64
- duration time.Duration
- traceNodeParams
- name string
-}
-
-func (h traceNodeHeap) Len() int { return len(h) }
-func (h traceNodeHeap) Less(i, j int) bool { return h[i].duration < h[j].duration }
-func (h traceNodeHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
-
-// Push and Pop are unused: only heap.Init and heap.Fix are used.
-func (h traceNodeHeap) Push(x interface{}) {}
-func (h traceNodeHeap) Pop() interface{} { return nil }
-
-// TxnTrace contains the work in progress transaction trace.
-type TxnTrace struct {
- Enabled bool
- SegmentThreshold time.Duration
- StackTraceThreshold time.Duration
- nodes traceNodeHeap
- maxNodes int
-}
-
-// getMaxNodes allows the maximum number of nodes to be overwritten for unit
-// tests.
-func (trace *TxnTrace) getMaxNodes() int {
- if 0 != trace.maxNodes {
- return trace.maxNodes
- }
- return maxTxnTraceNodes
-}
-
-// considerNode exists to prevent unnecessary calls to witnessNode: constructing
-// the metric name and params map requires allocations.
-func (trace *TxnTrace) considerNode(end segmentEnd) bool {
- return trace.Enabled && (end.duration >= trace.SegmentThreshold)
-}
-
-func (trace *TxnTrace) witnessNode(end segmentEnd, name string, attrs spanAttributeMap, externalGUID string) {
- node := traceNode{
- start: end.start,
- stop: end.stop,
- duration: end.duration,
- threadID: end.threadID,
- name: name,
- }
- node.attributes = attrs
- node.TransactionGUID = externalGUID
- if !trace.considerNode(end) {
- return
- }
- if trace.nodes == nil {
- trace.nodes = make(traceNodeHeap, 0, startingTxnTraceNodes)
- }
- if end.exclusive >= trace.StackTraceThreshold {
- node.StackTrace = GetStackTrace()
- }
- if max := trace.getMaxNodes(); len(trace.nodes) < max {
- trace.nodes = append(trace.nodes, node)
- if len(trace.nodes) == max {
- heap.Init(trace.nodes)
- }
- return
- }
-
- if node.duration <= trace.nodes[0].duration {
- return
- }
- trace.nodes[0] = node
- heap.Fix(trace.nodes, 0)
-}
-
-// HarvestTrace contains a finished transaction trace ready for serialization to
-// the collector.
-type HarvestTrace struct {
- TxnEvent
- Trace TxnTrace
-}
-
-type nodeDetails struct {
- name string
- relativeStart time.Duration
- relativeStop time.Duration
- traceNodeParams
-}
-
-func printNodeStart(buf *bytes.Buffer, n nodeDetails) {
- // time.Seconds() is intentionally not used here. Millisecond
- // precision is enough.
- relativeStartMillis := n.relativeStart.Nanoseconds() / (1000 * 1000)
- relativeStopMillis := n.relativeStop.Nanoseconds() / (1000 * 1000)
-
- buf.WriteByte('[')
- jsonx.AppendInt(buf, relativeStartMillis)
- buf.WriteByte(',')
- jsonx.AppendInt(buf, relativeStopMillis)
- buf.WriteByte(',')
- jsonx.AppendString(buf, n.name)
- buf.WriteByte(',')
-
- w := jsonFieldsWriter{buf: buf}
- buf.WriteByte('{')
- if nil != n.StackTrace {
- w.writerField("backtrace", n.StackTrace)
- }
- if nil != n.exclusiveDurationMillis {
- w.floatField("exclusive_duration_millis", *n.exclusiveDurationMillis)
- }
- if "" != n.TransactionGUID {
- w.stringField("transaction_guid", n.TransactionGUID)
- }
- for k, v := range n.attributes {
- w.writerField(k.String(), v)
- }
- buf.WriteByte('}')
-
- buf.WriteByte(',')
- buf.WriteByte('[')
-}
-
-func printChildren(buf *bytes.Buffer, traceStart time.Time, nodes sortedTraceNodes, next int, stop *segmentStamp, threadID uint64) int {
- firstChild := true
- for {
- if next >= len(nodes) {
- // No more children to print.
- break
- }
- if nodes[next].threadID != threadID {
- // The next node is not of the same thread. Due to the
- // node sorting, all nodes of the same thread should be
- // together.
- break
- }
- if stop != nil && nodes[next].start.Stamp >= *stop {
- // Make sure this node is a child of the parent that is
- // being printed.
- break
- }
- if firstChild {
- firstChild = false
- } else {
- buf.WriteByte(',')
- }
- printNodeStart(buf, nodeDetails{
- name: nodes[next].name,
- relativeStart: nodes[next].start.Time.Sub(traceStart),
- relativeStop: nodes[next].stop.Time.Sub(traceStart),
- traceNodeParams: nodes[next].traceNodeParams,
- })
- next = printChildren(buf, traceStart, nodes, next+1, &nodes[next].stop.Stamp, threadID)
- buf.WriteString("]]")
-
- }
- return next
-}
-
-type sortedTraceNodes []*traceNode
-
-func (s sortedTraceNodes) Len() int { return len(s) }
-func (s sortedTraceNodes) Less(i, j int) bool {
- // threadID is the first sort key and start.Stamp is the second key.
- if s[i].threadID == s[j].threadID {
- return s[i].start.Stamp < s[j].start.Stamp
- }
- return s[i].threadID < s[j].threadID
-}
-func (s sortedTraceNodes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
-// MarshalJSON is used for testing.
-//
-// TODO: Eliminate this entirely by using harvestTraces.Data().
-func (trace *HarvestTrace) MarshalJSON() ([]byte, error) {
- buf := bytes.NewBuffer(make([]byte, 0, 100+100*trace.Trace.nodes.Len()))
-
- trace.writeJSON(buf)
-
- return buf.Bytes(), nil
-}
-
-func (trace *HarvestTrace) writeJSON(buf *bytes.Buffer) {
- nodes := make(sortedTraceNodes, len(trace.Trace.nodes))
- for i := 0; i < len(nodes); i++ {
- nodes[i] = &trace.Trace.nodes[i]
- }
- sort.Sort(nodes)
-
- buf.WriteByte('[') // begin trace
-
- jsonx.AppendInt(buf, trace.Start.UnixNano()/1000)
- buf.WriteByte(',')
- jsonx.AppendFloat(buf, trace.Duration.Seconds()*1000.0)
- buf.WriteByte(',')
- jsonx.AppendString(buf, trace.FinalName)
- buf.WriteByte(',')
- if uri, _ := trace.Attrs.GetAgentValue(attributeRequestURI, destTxnTrace); "" != uri {
- jsonx.AppendString(buf, uri)
- } else {
- buf.WriteString("null")
- }
- buf.WriteByte(',')
-
- buf.WriteByte('[') // begin trace data
-
- // If the trace string pool is used, insert another array here.
-
- jsonx.AppendFloat(buf, 0.0) // unused timestamp
- buf.WriteByte(',') //
- buf.WriteString("{}") // unused: formerly request parameters
- buf.WriteByte(',') //
- buf.WriteString("{}") // unused: formerly custom parameters
- buf.WriteByte(',') //
-
- printNodeStart(buf, nodeDetails{ // begin outer root
- name: "ROOT",
- relativeStart: 0,
- relativeStop: trace.Duration,
- })
-
- // exclusive_duration_millis field is added to fix the transaction trace
- // summary tab. If exclusive_duration_millis is not provided, the UIs
- // will calculate exclusive time, which doesn't work for this root node
- // since all async goroutines are children of this root.
- exclusiveDurationMillis := trace.Duration.Seconds() * 1000.0
- details := nodeDetails{ // begin inner root
- name: trace.FinalName,
- relativeStart: 0,
- relativeStop: trace.Duration,
- }
- details.exclusiveDurationMillis = &exclusiveDurationMillis
- printNodeStart(buf, details)
-
- for next := 0; next < len(nodes); {
- if next > 0 {
- buf.WriteByte(',')
- }
- // We put each thread's nodes into the root node instead of the
- // node that spawned the thread. This approach is simple and
- // works when the segment which spawned a thread has been pruned
- // from the trace. Each call to printChildren prints one
- // thread.
- next = printChildren(buf, trace.Start, nodes, next, nil, nodes[next].threadID)
- }
-
- buf.WriteString("]]") // end outer root
- buf.WriteString("]]") // end inner root
-
- buf.WriteByte(',')
- buf.WriteByte('{')
- buf.WriteString(`"agentAttributes":`)
- agentAttributesJSON(trace.Attrs, buf, destTxnTrace)
- buf.WriteByte(',')
- buf.WriteString(`"userAttributes":`)
- userAttributesJSON(trace.Attrs, buf, destTxnTrace, nil)
- buf.WriteByte(',')
- buf.WriteString(`"intrinsics":`)
- intrinsicsJSON(&trace.TxnEvent, buf)
- buf.WriteByte('}')
-
- // If the trace string pool is used, end another array here.
-
- buf.WriteByte(']') // end trace data
-
- buf.WriteByte(',')
- if trace.CrossProcess.Used() && trace.CrossProcess.GUID != "" {
- jsonx.AppendString(buf, trace.CrossProcess.GUID)
- } else {
- buf.WriteString(`""`)
- }
- buf.WriteByte(',') //
- buf.WriteString(`null`) // reserved for future use
- buf.WriteByte(',') //
- buf.WriteString(`false`) // ForcePersist is not yet supported
- buf.WriteByte(',') //
- buf.WriteString(`null`) // X-Ray sessions not supported
- buf.WriteByte(',') //
-
- // Synthetics are supported:
- if trace.CrossProcess.IsSynthetics() {
- jsonx.AppendString(buf, trace.CrossProcess.Synthetics.ResourceID)
- } else {
- buf.WriteString(`""`)
- }
-
- buf.WriteByte(']') // end trace
-}
-
-type txnTraceHeap []*HarvestTrace
-
-func (h *txnTraceHeap) isEmpty() bool {
- return 0 == len(*h)
-}
-
-func newTxnTraceHeap(max int) *txnTraceHeap {
- h := make(txnTraceHeap, 0, max)
- heap.Init(&h)
- return &h
-}
-
-// Implement sort.Interface.
-func (h txnTraceHeap) Len() int { return len(h) }
-func (h txnTraceHeap) Less(i, j int) bool { return h[i].Duration < h[j].Duration }
-func (h txnTraceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
-
-// Implement heap.Interface.
-func (h *txnTraceHeap) Push(x interface{}) { *h = append(*h, x.(*HarvestTrace)) }
-
-func (h *txnTraceHeap) Pop() interface{} {
- old := *h
- n := len(old)
- x := old[n-1]
- *h = old[0 : n-1]
- return x
-}
-
-func (h *txnTraceHeap) isKeeper(t *HarvestTrace) bool {
- if len(*h) < cap(*h) {
- return true
- }
- return t.Duration >= (*h)[0].Duration
-}
-
-func (h *txnTraceHeap) addTxnTrace(t *HarvestTrace) {
- if len(*h) < cap(*h) {
- heap.Push(h, t)
- return
- }
-
- if t.Duration <= (*h)[0].Duration {
- return
- }
- heap.Pop(h)
- heap.Push(h, t)
-}
-
-type harvestTraces struct {
- regular *txnTraceHeap
- synthetics *txnTraceHeap
-}
-
-func newHarvestTraces() *harvestTraces {
- return &harvestTraces{
- regular: newTxnTraceHeap(maxRegularTraces),
- synthetics: newTxnTraceHeap(maxSyntheticsTraces),
- }
-}
-
-func (traces *harvestTraces) Len() int {
- return traces.regular.Len() + traces.synthetics.Len()
-}
-
-func (traces *harvestTraces) Witness(trace HarvestTrace) {
- traceHeap := traces.regular
- if trace.CrossProcess.IsSynthetics() {
- traceHeap = traces.synthetics
- }
-
- if traceHeap.isKeeper(&trace) {
- cpy := new(HarvestTrace)
- *cpy = trace
- traceHeap.addTxnTrace(cpy)
- }
-}
-
-func (traces *harvestTraces) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
- if traces.Len() == 0 {
- return nil, nil
- }
-
- // This estimate is used to guess the size of the buffer. No worries if
- // the estimate is small since the buffer will be lengthened as
- // necessary. This is just about minimizing reallocations.
- estimate := 512
- for _, t := range *traces.regular {
- estimate += 100 * t.Trace.nodes.Len()
- }
- for _, t := range *traces.synthetics {
- estimate += 100 * t.Trace.nodes.Len()
- }
-
- buf := bytes.NewBuffer(make([]byte, 0, estimate))
- buf.WriteByte('[')
- jsonx.AppendString(buf, agentRunID)
- buf.WriteByte(',')
- buf.WriteByte('[')
-
- // use a function to add traces to the buffer to avoid duplicating comma
- // logic in both loops
- firstTrace := true
- addTrace := func(trace *HarvestTrace) {
- if firstTrace {
- firstTrace = false
- } else {
- buf.WriteByte(',')
- }
- trace.writeJSON(buf)
- }
-
- for _, trace := range *traces.regular {
- addTrace(trace)
- }
- for _, trace := range *traces.synthetics {
- addTrace(trace)
- }
- buf.WriteByte(']')
- buf.WriteByte(']')
-
- return buf.Bytes(), nil
-}
-
-func (traces *harvestTraces) slice() []*HarvestTrace {
- out := make([]*HarvestTrace, 0, traces.Len())
- out = append(out, (*traces.regular)...)
- out = append(out, (*traces.synthetics)...)
-
- return out
-}
-
-func (traces *harvestTraces) MergeIntoHarvest(h *Harvest) {}
-
-func (traces *harvestTraces) EndpointMethod() string {
- return cmdTxnTraces
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/url.go b/vendor/github.com/newrelic/go-agent/internal/url.go
deleted file mode 100644
index 21976ee4fc9..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/url.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package internal
-
-import "net/url"
-
-// SafeURL removes sensitive information from a URL.
-func SafeURL(u *url.URL) string {
- if nil == u {
- return ""
- }
- if "" != u.Opaque {
- // If the URL is opaque, we cannot be sure if it contains
- // sensitive information.
- return ""
- }
-
- // Omit user, query, and fragment information for security.
- ur := url.URL{
- Scheme: u.Scheme,
- Host: u.Host,
- Path: u.Path,
- }
- return ur.String()
-}
-
-// SafeURLFromString removes sensitive information from a URL.
-func SafeURLFromString(rawurl string) string {
- u, err := url.Parse(rawurl)
- if nil != err {
- return ""
- }
- return SafeURL(u)
-}
-
-// HostFromURL returns the URL's host.
-func HostFromURL(u *url.URL) string {
- if nil == u {
- return ""
- }
- if "" != u.Opaque {
- return "opaque"
- }
- return u.Host
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilities.go b/vendor/github.com/newrelic/go-agent/internal/utilities.go
deleted file mode 100644
index 75566f0ea9c..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilities.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package internal
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "net/http"
- "strconv"
- "strings"
- "time"
-)
-
-// JSONString assists in logging JSON: Based on the formatter used to log
-// Context contents, the contents could be marshalled as JSON or just printed
-// directly.
-type JSONString string
-
-// MarshalJSON returns the JSONString unmodified without any escaping.
-func (js JSONString) MarshalJSON() ([]byte, error) {
- if "" == js {
- return []byte("null"), nil
- }
- return []byte(js), nil
-}
-
-func removeFirstSegment(name string) string {
- idx := strings.Index(name, "/")
- if -1 == idx {
- return name
- }
- return name[idx+1:]
-}
-
-func timeToFloatSeconds(t time.Time) float64 {
- return float64(t.UnixNano()) / float64(1000*1000*1000)
-}
-
-func timeToFloatMilliseconds(t time.Time) float64 {
- return float64(t.UnixNano()) / float64(1000*1000)
-}
-
-// FloatSecondsToDuration turns a float64 in seconds into a time.Duration.
-func FloatSecondsToDuration(seconds float64) time.Duration {
- nanos := seconds * 1000 * 1000 * 1000
- return time.Duration(nanos) * time.Nanosecond
-}
-
-func absTimeDiff(t1, t2 time.Time) time.Duration {
- if t1.After(t2) {
- return t1.Sub(t2)
- }
- return t2.Sub(t1)
-}
-
-// CompactJSONString removes the whitespace from a JSON string. This function
-// will panic if the string provided is not valid JSON. Thus is must only be
-// used in testing code!
-func CompactJSONString(js string) string {
- buf := new(bytes.Buffer)
- if err := json.Compact(buf, []byte(js)); err != nil {
- panic(fmt.Errorf("unable to compact JSON: %v", err))
- }
- return buf.String()
-}
-
-// GetContentLengthFromHeader gets the content length from a HTTP header, or -1
-// if no content length is available.
-func GetContentLengthFromHeader(h http.Header) int64 {
- if cl := h.Get("Content-Length"); cl != "" {
- if contentLength, err := strconv.ParseInt(cl, 10, 64); err == nil {
- return contentLength
- }
- }
-
- return -1
-}
-
-// StringLengthByteLimit truncates strings using a byte-limit boundary and
-// avoids terminating in the middle of a multibyte character.
-func StringLengthByteLimit(str string, byteLimit int) string {
- if len(str) <= byteLimit {
- return str
- }
-
- limitIndex := 0
- for pos := range str {
- if pos > byteLimit {
- break
- }
- limitIndex = pos
- }
- return str[0:limitIndex]
-}
-
-func timeFromUnixMilliseconds(millis uint64) time.Time {
- secs := int64(millis) / 1000
- msecsRemaining := int64(millis) % 1000
- nsecsRemaining := msecsRemaining * (1000 * 1000)
- return time.Unix(secs, nsecsRemaining)
-}
-
-// TimeToUnixMilliseconds converts a time into a Unix timestamp in millisecond
-// units.
-func TimeToUnixMilliseconds(tm time.Time) uint64 {
- return uint64(tm.UnixNano()) / uint64(1000*1000)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilization/addresses.go b/vendor/github.com/newrelic/go-agent/internal/utilization/addresses.go
deleted file mode 100644
index a6f64a1a2ef..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilization/addresses.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package utilization
-
-import (
- "fmt"
- "net"
-)
-
-func nonlocalIPAddressesByInterface() (map[string][]string, error) {
- ifaces, err := net.Interfaces()
- if err != nil {
- return nil, err
- }
- ips := make(map[string][]string, len(ifaces))
- for _, ifc := range ifaces {
- addrs, err := ifc.Addrs()
- if err != nil {
- continue
- }
- for _, addr := range addrs {
- var ip net.IP
- switch iptype := addr.(type) {
- case *net.IPAddr:
- ip = iptype.IP
- case *net.IPNet:
- ip = iptype.IP
- case *net.TCPAddr:
- ip = iptype.IP
- case *net.UDPAddr:
- ip = iptype.IP
- }
- if nil != ip && !ip.IsLoopback() && !ip.IsUnspecified() {
- ips[ifc.Name] = append(ips[ifc.Name], ip.String())
- }
- }
- }
- return ips, nil
-}
-
-// utilizationIPs gathers IP address which may help identify this entity. This
-// code chooses all IPs from the interface which contains the IP of a UDP
-// connection with NR. This approach has the following advantages:
-// * Matches the behavior of the Java agent.
-// * Reports fewer IPs to lower linking burden on infrastructure backend.
-// * The UDP connection interface is more likely to contain unique external IPs.
-func utilizationIPs() ([]string, error) {
- // Port choice designed to match
- // https://source.datanerd.us/java-agent/java_agent/blob/master/newrelic-agent/src/main/java/com/newrelic/agent/config/Hostname.java#L110
- conn, err := net.Dial("udp", "newrelic.com:10002")
- if err != nil {
- return nil, err
- }
- defer conn.Close()
-
- addr, ok := conn.LocalAddr().(*net.UDPAddr)
-
- if !ok || nil == addr || addr.IP.IsLoopback() || addr.IP.IsUnspecified() {
- return nil, fmt.Errorf("unexpected connection address: %v", conn.LocalAddr())
- }
- outboundIP := addr.IP.String()
-
- ipsByInterface, err := nonlocalIPAddressesByInterface()
- if err != nil {
- return nil, err
- }
- for _, ips := range ipsByInterface {
- for _, ip := range ips {
- if ip == outboundIP {
- return ips, nil
- }
- }
- }
- return nil, nil
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilization/aws.go b/vendor/github.com/newrelic/go-agent/internal/utilization/aws.go
deleted file mode 100644
index 0651d259ad3..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilization/aws.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package utilization
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
-)
-
-const (
- awsHostname = "169.254.169.254"
- awsEndpointPath = "/2016-09-02/dynamic/instance-identity/document"
- awsEndpoint = "http://" + awsHostname + awsEndpointPath
-)
-
-type aws struct {
- InstanceID string `json:"instanceId,omitempty"`
- InstanceType string `json:"instanceType,omitempty"`
- AvailabilityZone string `json:"availabilityZone,omitempty"`
-}
-
-func gatherAWS(util *Data, client *http.Client) error {
- aws, err := getAWS(client)
- if err != nil {
- // Only return the error here if it is unexpected to prevent
- // warning customers who aren't running AWS about a timeout.
- if _, ok := err.(unexpectedAWSErr); ok {
- return err
- }
- return nil
- }
- util.Vendors.AWS = aws
-
- return nil
-}
-
-type unexpectedAWSErr struct{ e error }
-
-func (e unexpectedAWSErr) Error() string {
- return fmt.Sprintf("unexpected AWS error: %v", e.e)
-}
-
-func getAWS(client *http.Client) (*aws, error) {
- response, err := client.Get(awsEndpoint)
- if err != nil {
- // No unexpectedAWSErr here: A timeout is usually going to
- // happen.
- return nil, err
- }
- defer response.Body.Close()
-
- if response.StatusCode != 200 {
- return nil, unexpectedAWSErr{e: fmt.Errorf("response code %d", response.StatusCode)}
- }
-
- data, err := ioutil.ReadAll(response.Body)
- if err != nil {
- return nil, unexpectedAWSErr{e: err}
- }
- a := &aws{}
- if err := json.Unmarshal(data, a); err != nil {
- return nil, unexpectedAWSErr{e: err}
- }
-
- if err := a.validate(); err != nil {
- return nil, unexpectedAWSErr{e: err}
- }
-
- return a, nil
-}
-
-func (a *aws) validate() (err error) {
- a.InstanceID, err = normalizeValue(a.InstanceID)
- if err != nil {
- return fmt.Errorf("invalid instance ID: %v", err)
- }
-
- a.InstanceType, err = normalizeValue(a.InstanceType)
- if err != nil {
- return fmt.Errorf("invalid instance type: %v", err)
- }
-
- a.AvailabilityZone, err = normalizeValue(a.AvailabilityZone)
- if err != nil {
- return fmt.Errorf("invalid availability zone: %v", err)
- }
-
- return
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilization/azure.go b/vendor/github.com/newrelic/go-agent/internal/utilization/azure.go
deleted file mode 100644
index aea6a1b027a..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilization/azure.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package utilization
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
-)
-
-const (
- azureHostname = "169.254.169.254"
- azureEndpointPath = "/metadata/instance/compute?api-version=2017-03-01"
- azureEndpoint = "http://" + azureHostname + azureEndpointPath
-)
-
-type azure struct {
- Location string `json:"location,omitempty"`
- Name string `json:"name,omitempty"`
- VMID string `json:"vmId,omitempty"`
- VMSize string `json:"vmSize,omitempty"`
-}
-
-func gatherAzure(util *Data, client *http.Client) error {
- az, err := getAzure(client)
- if err != nil {
- // Only return the error here if it is unexpected to prevent
- // warning customers who aren't running Azure about a timeout.
- if _, ok := err.(unexpectedAzureErr); ok {
- return err
- }
- return nil
- }
- util.Vendors.Azure = az
-
- return nil
-}
-
-type unexpectedAzureErr struct{ e error }
-
-func (e unexpectedAzureErr) Error() string {
- return fmt.Sprintf("unexpected Azure error: %v", e.e)
-}
-
-func getAzure(client *http.Client) (*azure, error) {
- req, err := http.NewRequest("GET", azureEndpoint, nil)
- if err != nil {
- return nil, err
- }
- req.Header.Add("Metadata", "true")
-
- response, err := client.Do(req)
- if err != nil {
- // No unexpectedAzureErr here: a timeout isusually going to
- // happen.
- return nil, err
- }
- defer response.Body.Close()
-
- if response.StatusCode != 200 {
- return nil, unexpectedAzureErr{e: fmt.Errorf("response code %d", response.StatusCode)}
- }
-
- data, err := ioutil.ReadAll(response.Body)
- if err != nil {
- return nil, unexpectedAzureErr{e: err}
- }
-
- az := &azure{}
- if err := json.Unmarshal(data, az); err != nil {
- return nil, unexpectedAzureErr{e: err}
- }
-
- if err := az.validate(); err != nil {
- return nil, unexpectedAzureErr{e: err}
- }
-
- return az, nil
-}
-
-func (az *azure) validate() (err error) {
- az.Location, err = normalizeValue(az.Location)
- if err != nil {
- return fmt.Errorf("Invalid location: %v", err)
- }
-
- az.Name, err = normalizeValue(az.Name)
- if err != nil {
- return fmt.Errorf("Invalid name: %v", err)
- }
-
- az.VMID, err = normalizeValue(az.VMID)
- if err != nil {
- return fmt.Errorf("Invalid VM ID: %v", err)
- }
-
- az.VMSize, err = normalizeValue(az.VMSize)
- if err != nil {
- return fmt.Errorf("Invalid VM size: %v", err)
- }
-
- return
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilization/fqdn.go b/vendor/github.com/newrelic/go-agent/internal/utilization/fqdn.go
deleted file mode 100644
index d44b1a202ff..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilization/fqdn.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// +build go1.8
-
-package utilization
-
-import (
- "context"
- "net"
- "strings"
-)
-
-func lookupAddr(addr string) ([]string, error) {
- ctx, cancel := context.WithTimeout(context.Background(), lookupAddrTimeout)
- defer cancel()
-
- r := &net.Resolver{}
-
- return r.LookupAddr(ctx, addr)
-}
-
-func getFQDN(candidateIPs []string) string {
- for _, ip := range candidateIPs {
- names, _ := lookupAddr(ip)
- if len(names) > 0 {
- return strings.TrimSuffix(names[0], ".")
- }
- }
- return ""
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilization/fqdn_pre18.go b/vendor/github.com/newrelic/go-agent/internal/utilization/fqdn_pre18.go
deleted file mode 100644
index 0f549ed21c1..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilization/fqdn_pre18.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build !go1.8
-
-package utilization
-
-// net.Resolver.LookupAddr was added in Go 1.8, and net.LookupAddr does not have
-// a controllable timeout, so we skip the optional full_hostname on pre 1.8
-// versions.
-
-func getFQDN(candidateIPs []string) string {
- return ""
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilization/gcp.go b/vendor/github.com/newrelic/go-agent/internal/utilization/gcp.go
deleted file mode 100644
index e79c8e35190..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilization/gcp.go
+++ /dev/null
@@ -1,152 +0,0 @@
-package utilization
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "strings"
-)
-
-const (
- gcpHostname = "metadata.google.internal"
- gcpEndpointPath = "/computeMetadata/v1/instance/?recursive=true"
- gcpEndpoint = "http://" + gcpHostname + gcpEndpointPath
-)
-
-func gatherGCP(util *Data, client *http.Client) error {
- gcp, err := getGCP(client)
- if err != nil {
- // Only return the error here if it is unexpected to prevent
- // warning customers who aren't running GCP about a timeout.
- if _, ok := err.(unexpectedGCPErr); ok {
- return err
- }
- return nil
- }
- util.Vendors.GCP = gcp
-
- return nil
-}
-
-// numericString is used rather than json.Number because we want the output when
-// marshalled to be a string, rather than a number.
-type numericString string
-
-func (ns *numericString) MarshalJSON() ([]byte, error) {
- return json.Marshal(ns.String())
-}
-
-func (ns *numericString) String() string {
- return string(*ns)
-}
-
-func (ns *numericString) UnmarshalJSON(data []byte) error {
- var n int64
-
- // Try to unmarshal as an integer first.
- if err := json.Unmarshal(data, &n); err == nil {
- *ns = numericString(fmt.Sprintf("%d", n))
- return nil
- }
-
- // Otherwise, unmarshal as a string, and verify that it's numeric (for our
- // definition of numeric, which is actually integral).
- var s string
- if err := json.Unmarshal(data, &s); err != nil {
- return err
- }
-
- for _, r := range s {
- if r < '0' || r > '9' {
- return fmt.Errorf("invalid numeric character: %c", r)
- }
- }
-
- *ns = numericString(s)
- return nil
-}
-
-type gcp struct {
- ID numericString `json:"id"`
- MachineType string `json:"machineType,omitempty"`
- Name string `json:"name,omitempty"`
- Zone string `json:"zone,omitempty"`
-}
-
-type unexpectedGCPErr struct{ e error }
-
-func (e unexpectedGCPErr) Error() string {
- return fmt.Sprintf("unexpected GCP error: %v", e.e)
-}
-
-func getGCP(client *http.Client) (*gcp, error) {
- // GCP's metadata service requires a Metadata-Flavor header because... hell, I
- // don't know, maybe they really like Guy Fieri?
- req, err := http.NewRequest("GET", gcpEndpoint, nil)
- if err != nil {
- return nil, err
- }
- req.Header.Add("Metadata-Flavor", "Google")
-
- response, err := client.Do(req)
- if err != nil {
- return nil, err
- }
- defer response.Body.Close()
-
- if response.StatusCode != 200 {
- return nil, unexpectedGCPErr{e: fmt.Errorf("response code %d", response.StatusCode)}
- }
-
- data, err := ioutil.ReadAll(response.Body)
- if err != nil {
- return nil, unexpectedGCPErr{e: err}
- }
-
- g := &gcp{}
- if err := json.Unmarshal(data, g); err != nil {
- return nil, unexpectedGCPErr{e: err}
- }
-
- if err := g.validate(); err != nil {
- return nil, unexpectedGCPErr{e: err}
- }
-
- return g, nil
-}
-
-func (g *gcp) validate() (err error) {
- id, err := normalizeValue(g.ID.String())
- if err != nil {
- return fmt.Errorf("Invalid ID: %v", err)
- }
- g.ID = numericString(id)
-
- mt, err := normalizeValue(g.MachineType)
- if err != nil {
- return fmt.Errorf("Invalid machine type: %v", err)
- }
- g.MachineType = stripGCPPrefix(mt)
-
- g.Name, err = normalizeValue(g.Name)
- if err != nil {
- return fmt.Errorf("Invalid name: %v", err)
- }
-
- zone, err := normalizeValue(g.Zone)
- if err != nil {
- return fmt.Errorf("Invalid zone: %v", err)
- }
- g.Zone = stripGCPPrefix(zone)
-
- return
-}
-
-// We're only interested in the last element of slash separated paths for the
-// machine type and zone values, so this function handles stripping the parts
-// we don't need.
-func stripGCPPrefix(s string) string {
- parts := strings.Split(s, "/")
- return parts[len(parts)-1]
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilization/pcf.go b/vendor/github.com/newrelic/go-agent/internal/utilization/pcf.go
deleted file mode 100644
index de0250a1899..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilization/pcf.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package utilization
-
-import (
- "errors"
- "fmt"
- "net/http"
- "os"
-)
-
-type pcf struct {
- InstanceGUID string `json:"cf_instance_guid,omitempty"`
- InstanceIP string `json:"cf_instance_ip,omitempty"`
- MemoryLimit string `json:"memory_limit,omitempty"`
-}
-
-func gatherPCF(util *Data, _ *http.Client) error {
- pcf, err := getPCF(os.Getenv)
- if err != nil {
- // Only return the error here if it is unexpected to prevent
- // warning customers who aren't running PCF about a timeout.
- if _, ok := err.(unexpectedPCFErr); ok {
- return err
- }
- return nil
- }
- util.Vendors.PCF = pcf
-
- return nil
-}
-
-type unexpectedPCFErr struct{ e error }
-
-func (e unexpectedPCFErr) Error() string {
- return fmt.Sprintf("unexpected PCF error: %v", e.e)
-}
-
-var (
- errNoPCFVariables = errors.New("no PCF environment variables present")
-)
-
-func getPCF(initializer func(key string) string) (*pcf, error) {
- p := &pcf{}
-
- p.InstanceGUID = initializer("CF_INSTANCE_GUID")
- p.InstanceIP = initializer("CF_INSTANCE_IP")
- p.MemoryLimit = initializer("MEMORY_LIMIT")
-
- if "" == p.InstanceGUID && "" == p.InstanceIP && "" == p.MemoryLimit {
- return nil, errNoPCFVariables
- }
-
- if err := p.validate(); err != nil {
- return nil, unexpectedPCFErr{e: err}
- }
-
- return p, nil
-}
-
-func (pcf *pcf) validate() (err error) {
- pcf.InstanceGUID, err = normalizeValue(pcf.InstanceGUID)
- if err != nil {
- return fmt.Errorf("Invalid instance GUID: %v", err)
- }
-
- pcf.InstanceIP, err = normalizeValue(pcf.InstanceIP)
- if err != nil {
- return fmt.Errorf("Invalid instance IP: %v", err)
- }
-
- pcf.MemoryLimit, err = normalizeValue(pcf.MemoryLimit)
- if err != nil {
- return fmt.Errorf("Invalid memory limit: %v", err)
- }
-
- if pcf.InstanceGUID == "" || pcf.InstanceIP == "" || pcf.MemoryLimit == "" {
- err = errors.New("One or more environment variables are unavailable")
- }
-
- return
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilization/provider.go b/vendor/github.com/newrelic/go-agent/internal/utilization/provider.go
deleted file mode 100644
index 5d589368ada..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilization/provider.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package utilization
-
-import (
- "fmt"
- "strings"
- "time"
-)
-
-// Helper constants, functions, and types common to multiple providers are
-// contained in this file.
-
-// Constants from the spec.
-const (
- maxFieldValueSize = 255 // The maximum value size, in bytes.
- providerTimeout = 1 * time.Second // The maximum time a HTTP provider may block.
- lookupAddrTimeout = 500 * time.Millisecond
-)
-
-type validationError struct{ e error }
-
-func (a validationError) Error() string {
- return a.e.Error()
-}
-
-func isValidationError(e error) bool {
- _, is := e.(validationError)
- return is
-}
-
-// This function normalises string values per the utilization spec.
-func normalizeValue(s string) (string, error) {
- out := strings.TrimSpace(s)
-
- bytes := []byte(out)
- if len(bytes) > maxFieldValueSize {
- return "", validationError{fmt.Errorf("response is too long: got %d; expected <=%d", len(bytes), maxFieldValueSize)}
- }
-
- for i, r := range out {
- if !isAcceptableRune(r) {
- return "", validationError{fmt.Errorf("bad character %x at position %d in response", r, i)}
- }
- }
-
- return out, nil
-}
-
-func isAcceptableRune(r rune) bool {
- switch r {
- case 0xFFFD:
- return false // invalid UTF-8
- case '_', ' ', '/', '.', '-':
- return true
- default:
- return r > 0x7f || // still allows some invalid UTF-8, but that's the spec.
- ('0' <= r && r <= '9') ||
- ('a' <= r && r <= 'z') ||
- ('A' <= r && r <= 'Z')
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal/utilization/utilization.go b/vendor/github.com/newrelic/go-agent/internal/utilization/utilization.go
deleted file mode 100644
index 5b338d2821d..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal/utilization/utilization.go
+++ /dev/null
@@ -1,239 +0,0 @@
-// Package utilization implements the Utilization spec, available at
-// https://source.datanerd.us/agents/agent-specs/blob/master/Utilization.md
-//
-package utilization
-
-import (
- "net/http"
- "os"
- "runtime"
- "sync"
-
- "github.com/newrelic/go-agent/internal/logger"
- "github.com/newrelic/go-agent/internal/sysinfo"
-)
-
-const (
- metadataVersion = 5
-)
-
-// Config controls the behavior of utilization information capture.
-type Config struct {
- DetectAWS bool
- DetectAzure bool
- DetectGCP bool
- DetectPCF bool
- DetectDocker bool
- DetectKubernetes bool
- LogicalProcessors int
- TotalRAMMIB int
- BillingHostname string
-}
-
-type override struct {
- LogicalProcessors *int `json:"logical_processors,omitempty"`
- TotalRAMMIB *int `json:"total_ram_mib,omitempty"`
- BillingHostname string `json:"hostname,omitempty"`
-}
-
-// Data contains utilization system information.
-type Data struct {
- MetadataVersion int `json:"metadata_version"`
- // Although `runtime.NumCPU()` will never fail, this field is a pointer
- // to facilitate the cross agent tests.
- LogicalProcessors *int `json:"logical_processors"`
- RAMMiB *uint64 `json:"total_ram_mib"`
- Hostname string `json:"hostname"`
- FullHostname string `json:"full_hostname,omitempty"`
- Addresses []string `json:"ip_address,omitempty"`
- BootID string `json:"boot_id,omitempty"`
- Config *override `json:"config,omitempty"`
- Vendors *vendors `json:"vendors,omitempty"`
-}
-
-var (
- sampleRAMMib = uint64(1024)
- sampleLogicProc = int(16)
- // SampleData contains sample utilization data useful for testing.
- SampleData = Data{
- MetadataVersion: metadataVersion,
- LogicalProcessors: &sampleLogicProc,
- RAMMiB: &sampleRAMMib,
- Hostname: "my-hostname",
- }
-)
-
-type docker struct {
- ID string `json:"id,omitempty"`
-}
-
-type kubernetes struct {
- Host string `json:"kubernetes_service_host"`
-}
-
-type vendors struct {
- AWS *aws `json:"aws,omitempty"`
- Azure *azure `json:"azure,omitempty"`
- GCP *gcp `json:"gcp,omitempty"`
- PCF *pcf `json:"pcf,omitempty"`
- Docker *docker `json:"docker,omitempty"`
- Kubernetes *kubernetes `json:"kubernetes,omitempty"`
-}
-
-func (v *vendors) isEmpty() bool {
- return nil == v || *v == vendors{}
-}
-
-func overrideFromConfig(config Config) *override {
- ov := &override{}
-
- if 0 != config.LogicalProcessors {
- x := config.LogicalProcessors
- ov.LogicalProcessors = &x
- }
- if 0 != config.TotalRAMMIB {
- x := config.TotalRAMMIB
- ov.TotalRAMMIB = &x
- }
- ov.BillingHostname = config.BillingHostname
-
- if "" == ov.BillingHostname &&
- nil == ov.LogicalProcessors &&
- nil == ov.TotalRAMMIB {
- ov = nil
- }
- return ov
-}
-
-// Gather gathers system utilization data.
-func Gather(config Config, lg logger.Logger) *Data {
- client := &http.Client{
- Timeout: providerTimeout,
- }
- return gatherWithClient(config, lg, client)
-}
-
-func gatherWithClient(config Config, lg logger.Logger, client *http.Client) *Data {
- var wg sync.WaitGroup
-
- cpu := runtime.NumCPU()
- uDat := &Data{
- MetadataVersion: metadataVersion,
- LogicalProcessors: &cpu,
- Vendors: &vendors{},
- }
-
- warnGatherError := func(datatype string, err error) {
- lg.Debug("error gathering utilization data", map[string]interface{}{
- "error": err.Error(),
- "datatype": datatype,
- })
- }
-
- // Gather IPs before spawning goroutines since the IPs are used in
- // gathering full hostname.
- if ips, err := utilizationIPs(); nil == err {
- uDat.Addresses = ips
- } else {
- warnGatherError("addresses", err)
- }
-
- // This closure allows us to run each gather function in a separate goroutine
- // and wait for them at the end by closing over the wg WaitGroup we
- // instantiated at the start of the function.
- goGather := func(datatype string, gather func(*Data, *http.Client) error) {
- wg.Add(1)
- go func() {
- // Note that locking around util is not necessary since
- // WaitGroup provides acts as a memory barrier:
- // https://groups.google.com/d/msg/golang-nuts/5oHzhzXCcmM/utEwIAApCQAJ
- // Thus this code is fine as long as each routine is
- // modifying a different field of util.
- defer wg.Done()
- if err := gather(uDat, client); err != nil {
- warnGatherError(datatype, err)
- }
- }()
- }
-
- // Kick off gathering which requires network calls in goroutines.
-
- if config.DetectAWS {
- goGather("aws", gatherAWS)
- }
-
- if config.DetectAzure {
- goGather("azure", gatherAzure)
- }
-
- if config.DetectPCF {
- goGather("pcf", gatherPCF)
- }
-
- if config.DetectGCP {
- goGather("gcp", gatherGCP)
- }
-
- wg.Add(1)
- go func() {
- defer wg.Done()
- uDat.FullHostname = getFQDN(uDat.Addresses)
- }()
-
- // Do non-network gathering sequentially since it is fast.
-
- if id, err := sysinfo.BootID(); err != nil {
- if err != sysinfo.ErrFeatureUnsupported {
- warnGatherError("bootid", err)
- }
- } else {
- uDat.BootID = id
- }
-
- if config.DetectKubernetes {
- gatherKubernetes(uDat.Vendors, os.Getenv)
- }
-
- if config.DetectDocker {
- if id, err := sysinfo.DockerID(); err != nil {
- if err != sysinfo.ErrFeatureUnsupported &&
- err != sysinfo.ErrDockerNotFound {
- warnGatherError("docker", err)
- }
- } else {
- uDat.Vendors.Docker = &docker{ID: id}
- }
- }
-
- if hostname, err := sysinfo.Hostname(); nil == err {
- uDat.Hostname = hostname
- } else {
- warnGatherError("hostname", err)
- }
-
- if bts, err := sysinfo.PhysicalMemoryBytes(); nil == err {
- mib := sysinfo.BytesToMebibytes(bts)
- uDat.RAMMiB = &mib
- } else {
- warnGatherError("memory", err)
- }
-
- // Now we wait for everything!
- wg.Wait()
-
- // Override whatever needs to be overridden.
- uDat.Config = overrideFromConfig(config)
-
- if uDat.Vendors.isEmpty() {
- // Per spec, we MUST NOT send any vendors hash if it's empty.
- uDat.Vendors = nil
- }
-
- return uDat
-}
-
-func gatherKubernetes(v *vendors, getenv func(string) string) {
- if host := getenv("KUBERNETES_SERVICE_HOST"); host != "" {
- v.Kubernetes = &kubernetes{Host: host}
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal_app.go b/vendor/github.com/newrelic/go-agent/internal_app.go
deleted file mode 100644
index 50ca494147b..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal_app.go
+++ /dev/null
@@ -1,607 +0,0 @@
-package newrelic
-
-import (
- "errors"
- "fmt"
- "io"
- "math"
- "net/http"
- "os"
- "strings"
- "sync"
- "time"
-
- "github.com/newrelic/go-agent/internal"
- "github.com/newrelic/go-agent/internal/logger"
-)
-
-var (
- // NEW_RELIC_DEBUG_LOGGING can be set to anything to enable additional
- // debug logging: the agent will log every transaction's data at info
- // level.
- envDebugLogging = "NEW_RELIC_DEBUG_LOGGING"
- debugLogging = os.Getenv(envDebugLogging)
-)
-
-type dataConsumer interface {
- Consume(internal.AgentRunID, internal.Harvestable)
-}
-
-type appData struct {
- id internal.AgentRunID
- data internal.Harvestable
-}
-
-type app struct {
- Logger
- config Config
- rpmControls internal.RpmControls
- testHarvest *internal.Harvest
-
- // placeholderRun is used when the application is not connected.
- placeholderRun *appRun
-
- // initiateShutdown is used to tell the processor to shutdown.
- initiateShutdown chan struct{}
-
- // shutdownStarted and shutdownComplete are closed by the processor
- // goroutine to indicate the shutdown status. Two channels are used so
- // that the call of app.Shutdown() can block until shutdown has
- // completed but other goroutines can exit when shutdown has started.
- // This is not just an optimization: This prevents a deadlock if
- // harvesting data during the shutdown fails and an attempt is made to
- // merge the data into the next harvest.
- shutdownStarted chan struct{}
- shutdownComplete chan struct{}
-
- // Sends to these channels should not occur without a <-shutdownStarted
- // select option to prevent deadlock.
- dataChan chan appData
- collectorErrorChan chan internal.RPMResponse
- connectChan chan *appRun
-
- // This mutex protects both `run` and `err`, both of which should only
- // be accessed using getState and setState.
- sync.RWMutex
- // run is non-nil when the app is successfully connected. It is
- // immutable.
- run *appRun
- // err is non-nil if the application will never be connected again
- // (disconnect, license exception, shutdown).
- err error
-
- serverless *internal.ServerlessHarvest
-}
-
-func (app *app) doHarvest(h *internal.Harvest, harvestStart time.Time, run *appRun) {
- h.CreateFinalMetrics(run.Reply)
-
- payloads := h.Payloads(app.config.DistributedTracer.Enabled)
- for _, p := range payloads {
- cmd := p.EndpointMethod()
- data, err := p.Data(run.Reply.RunID.String(), harvestStart)
-
- if nil != err {
- app.Warn("unable to create harvest data", map[string]interface{}{
- "cmd": cmd,
- "error": err.Error(),
- })
- continue
- }
- if nil == data {
- continue
- }
-
- call := internal.RpmCmd{
- Collector: run.Reply.Collector,
- RunID: run.Reply.RunID.String(),
- Name: cmd,
- Data: data,
- RequestHeadersMap: run.Reply.RequestHeadersMap,
- MaxPayloadSize: run.Reply.MaxPayloadSizeInBytes,
- }
-
- resp := internal.CollectorRequest(call, app.rpmControls)
-
- if resp.IsDisconnect() || resp.IsRestartException() {
- select {
- case app.collectorErrorChan <- resp:
- case <-app.shutdownStarted:
- }
- return
- }
-
- if nil != resp.Err {
- app.Warn("harvest failure", map[string]interface{}{
- "cmd": cmd,
- "error": resp.Err.Error(),
- "retain_data": resp.ShouldSaveHarvestData(),
- })
- }
-
- if resp.ShouldSaveHarvestData() {
- app.Consume(run.Reply.RunID, p)
- }
- }
-}
-
-func (app *app) connectRoutine() {
- connectAttempt := 0
- for {
- reply, resp := internal.ConnectAttempt(config{app.config},
- app.config.SecurityPoliciesToken, app.config.HighSecurity, app.rpmControls)
-
- if reply != nil {
- select {
- case app.connectChan <- newAppRun(app.config, reply):
- case <-app.shutdownStarted:
- }
- return
- }
-
- if resp.IsDisconnect() {
- select {
- case app.collectorErrorChan <- resp:
- case <-app.shutdownStarted:
- }
- return
- }
-
- if nil != resp.Err {
- app.Warn("application connect failure", map[string]interface{}{
- "error": resp.Err.Error(),
- })
- }
-
- backoff := getConnectBackoffTime(connectAttempt)
- time.Sleep(time.Duration(backoff) * time.Second)
- connectAttempt++
- }
-}
-
-// Connect backoff time follows the sequence defined at
-// https://source.datanerd.us/agents/agent-specs/blob/master/Collector-Response-Handling.md#retries-and-backoffs
-func getConnectBackoffTime(attempt int) int {
- connectBackoffTimes := [...]int{15, 15, 30, 60, 120, 300}
- l := len(connectBackoffTimes)
- if (attempt < 0) || (attempt >= l) {
- return connectBackoffTimes[l-1]
- }
- return connectBackoffTimes[attempt]
-}
-
-func debug(data internal.Harvestable, lg Logger) {
- now := time.Now()
- h := internal.NewHarvest(now, nil)
- data.MergeIntoHarvest(h)
- ps := h.Payloads(false)
- for _, p := range ps {
- cmd := p.EndpointMethod()
- d, err := p.Data("agent run id", now)
- if nil == d && nil == err {
- continue
- }
- if nil != err {
- lg.Info("integration", map[string]interface{}{
- "cmd": cmd,
- "error": err.Error(),
- })
- continue
- }
- lg.Info("integration", map[string]interface{}{
- "cmd": cmd,
- "data": internal.JSONString(d),
- })
- }
-}
-
-func processConnectMessages(run *appRun, lg Logger) {
- for _, msg := range run.Reply.Messages {
- event := "collector message"
- cn := map[string]interface{}{"msg": msg.Message}
-
- switch strings.ToLower(msg.Level) {
- case "error":
- lg.Error(event, cn)
- case "warn":
- lg.Warn(event, cn)
- case "info":
- lg.Info(event, cn)
- case "debug", "verbose":
- lg.Debug(event, cn)
- }
- }
-}
-
-func (app *app) process() {
- // Both the harvest and the run are non-nil when the app is connected,
- // and nil otherwise.
- var h *internal.Harvest
- var run *appRun
-
- harvestTicker := time.NewTicker(time.Second)
- defer harvestTicker.Stop()
-
- for {
- select {
- case <-harvestTicker.C:
- if nil != run {
- now := time.Now()
- if ready := h.Ready(now, run.Reply); nil != ready {
- go app.doHarvest(ready, now, run)
- }
- }
- case d := <-app.dataChan:
- if nil != run && run.Reply.RunID == d.id {
- d.data.MergeIntoHarvest(h)
- }
- case <-app.initiateShutdown:
- close(app.shutdownStarted)
-
- // Remove the run before merging any final data to
- // ensure a bounded number of receives from dataChan.
- app.setState(nil, errors.New("application shut down"))
-
- if nil != run {
- for done := false; !done; {
- select {
- case d := <-app.dataChan:
- if run.Reply.RunID == d.id {
- d.data.MergeIntoHarvest(h)
- }
- default:
- done = true
- }
- }
- app.doHarvest(h, time.Now(), run)
- }
-
- close(app.shutdownComplete)
- return
- case resp := <-app.collectorErrorChan:
- run = nil
- h = nil
- app.setState(nil, nil)
-
- if resp.IsDisconnect() {
- app.setState(nil, resp.Err)
- app.Error("application disconnected", map[string]interface{}{
- "app": app.config.AppName,
- })
- } else if resp.IsRestartException() {
- app.Info("application restarted", map[string]interface{}{
- "app": app.config.AppName,
- })
- go app.connectRoutine()
- }
- case run = <-app.connectChan:
- h = internal.NewHarvest(time.Now(), run.Reply)
- app.setState(run, nil)
-
- app.Info("application connected", map[string]interface{}{
- "app": app.config.AppName,
- "run": run.Reply.RunID.String(),
- })
- processConnectMessages(run, app)
- }
- }
-}
-
-func (app *app) Shutdown(timeout time.Duration) {
- if !app.config.Enabled {
- return
- }
- if app.config.ServerlessMode.Enabled {
- return
- }
-
- select {
- case app.initiateShutdown <- struct{}{}:
- default:
- }
-
- // Block until shutdown is done or timeout occurs.
- t := time.NewTimer(timeout)
- select {
- case <-app.shutdownComplete:
- case <-t.C:
- }
- t.Stop()
-
- app.Info("application shutdown", map[string]interface{}{
- "app": app.config.AppName,
- })
-}
-
-func runSampler(app *app, period time.Duration) {
- previous := internal.GetSample(time.Now(), app)
- t := time.NewTicker(period)
- for {
- select {
- case now := <-t.C:
- current := internal.GetSample(now, app)
- run, _ := app.getState()
- app.Consume(run.Reply.RunID, internal.GetStats(internal.Samples{
- Previous: previous,
- Current: current,
- }))
- previous = current
- case <-app.shutdownStarted:
- t.Stop()
- return
- }
- }
-}
-
-func (app *app) WaitForConnection(timeout time.Duration) error {
- if !app.config.Enabled {
- return nil
- }
- if app.config.ServerlessMode.Enabled {
- return nil
- }
- deadline := time.Now().Add(timeout)
- pollPeriod := 50 * time.Millisecond
-
- for {
- run, err := app.getState()
- if nil != err {
- return err
- }
- if run.Reply.RunID != "" {
- return nil
- }
- if time.Now().After(deadline) {
- return fmt.Errorf("timeout out after %s", timeout.String())
- }
- time.Sleep(pollPeriod)
- }
-}
-
-func newApp(c Config) (Application, error) {
- c = copyConfigReferenceFields(c)
- if err := c.Validate(); nil != err {
- return nil, err
- }
- if nil == c.Logger {
- c.Logger = logger.ShimLogger{}
- }
- app := &app{
- Logger: c.Logger,
- config: c,
- placeholderRun: newAppRun(c, internal.ConnectReplyDefaults()),
-
- // This channel must be buffered since Shutdown makes a
- // non-blocking send attempt.
- initiateShutdown: make(chan struct{}, 1),
-
- shutdownStarted: make(chan struct{}),
- shutdownComplete: make(chan struct{}),
- connectChan: make(chan *appRun, 1),
- collectorErrorChan: make(chan internal.RPMResponse, 1),
- dataChan: make(chan appData, internal.AppDataChanSize),
- rpmControls: internal.RpmControls{
- License: c.License,
- Client: &http.Client{
- Transport: c.Transport,
- Timeout: internal.CollectorTimeout,
- },
- Logger: c.Logger,
- AgentVersion: Version,
- },
- }
-
- app.Info("application created", map[string]interface{}{
- "app": app.config.AppName,
- "version": Version,
- "enabled": app.config.Enabled,
- })
-
- if app.config.Enabled {
- if app.config.ServerlessMode.Enabled {
- reply := newServerlessConnectReply(c)
- app.run = newAppRun(c, reply)
- app.serverless = internal.NewServerlessHarvest(c.Logger, Version, os.Getenv)
- } else {
- go app.process()
- go app.connectRoutine()
- if app.config.RuntimeSampler.Enabled {
- go runSampler(app, internal.RuntimeSamplerPeriod)
- }
- }
- }
-
- return app, nil
-}
-
-var (
- _ internal.HarvestTestinger = &app{}
- _ internal.Expect = &app{}
-)
-
-func (app *app) HarvestTesting(replyfn func(*internal.ConnectReply)) {
- if nil != replyfn {
- reply := internal.ConnectReplyDefaults()
- replyfn(reply)
- app.placeholderRun = newAppRun(app.config, reply)
- }
- app.testHarvest = internal.NewHarvest(time.Now(), nil)
-}
-
-func (app *app) getState() (*appRun, error) {
- app.RLock()
- defer app.RUnlock()
-
- run := app.run
- if nil == run {
- run = app.placeholderRun
- }
- return run, app.err
-}
-
-func (app *app) setState(run *appRun, err error) {
- app.Lock()
- defer app.Unlock()
-
- app.run = run
- app.err = err
-}
-
-// StartTransaction implements newrelic.Application's StartTransaction.
-func (app *app) StartTransaction(name string, w http.ResponseWriter, r *http.Request) Transaction {
- run, _ := app.getState()
- txn := upgradeTxn(newTxn(txnInput{
- app: app,
- appRun: run,
- writer: w,
- Consumer: app,
- }, name))
-
- if nil != r {
- txn.SetWebRequest(NewWebRequest(r))
- }
- return txn
-}
-
-var (
- errHighSecurityEnabled = errors.New("high security enabled")
- errCustomEventsDisabled = errors.New("custom events disabled")
- errCustomEventsRemoteDisabled = errors.New("custom events disabled by server")
-)
-
-// RecordCustomEvent implements newrelic.Application's RecordCustomEvent.
-func (app *app) RecordCustomEvent(eventType string, params map[string]interface{}) error {
- if app.config.HighSecurity {
- return errHighSecurityEnabled
- }
-
- if !app.config.CustomInsightsEvents.Enabled {
- return errCustomEventsDisabled
- }
-
- event, e := internal.CreateCustomEvent(eventType, params, time.Now())
- if nil != e {
- return e
- }
-
- run, _ := app.getState()
- if !run.Reply.CollectCustomEvents {
- return errCustomEventsRemoteDisabled
- }
-
- if !run.Reply.SecurityPolicies.CustomEvents.Enabled() {
- return errSecurityPolicy
- }
-
- app.Consume(run.Reply.RunID, event)
-
- return nil
-}
-
-var (
- errMetricInf = errors.New("invalid metric value: inf")
- errMetricNaN = errors.New("invalid metric value: NaN")
- errMetricNameEmpty = errors.New("missing metric name")
- errMetricServerless = errors.New("custom metrics are not currently supported in serverless mode")
-)
-
-// RecordCustomMetric implements newrelic.Application's RecordCustomMetric.
-func (app *app) RecordCustomMetric(name string, value float64) error {
- if app.config.ServerlessMode.Enabled {
- return errMetricServerless
- }
- if math.IsNaN(value) {
- return errMetricNaN
- }
- if math.IsInf(value, 0) {
- return errMetricInf
- }
- if "" == name {
- return errMetricNameEmpty
- }
- run, _ := app.getState()
- app.Consume(run.Reply.RunID, internal.CustomMetric{
- RawInputName: name,
- Value: value,
- })
- return nil
-}
-
-var (
- _ internal.ServerlessWriter = &app{}
-)
-
-func (app *app) ServerlessWrite(arn string, writer io.Writer) {
- app.serverless.Write(arn, writer)
-}
-
-func (app *app) Consume(id internal.AgentRunID, data internal.Harvestable) {
- if "" != debugLogging {
- debug(data, app)
- }
-
- app.serverless.Consume(data)
-
- if nil != app.testHarvest {
- data.MergeIntoHarvest(app.testHarvest)
- return
- }
-
- if "" == id {
- return
- }
-
- select {
- case app.dataChan <- appData{id, data}:
- case <-app.shutdownStarted:
- }
-}
-
-func (app *app) ExpectCustomEvents(t internal.Validator, want []internal.WantEvent) {
- internal.ExpectCustomEvents(internal.ExtendValidator(t, "custom events"), app.testHarvest.CustomEvents, want)
-}
-
-func (app *app) ExpectErrors(t internal.Validator, want []internal.WantError) {
- t = internal.ExtendValidator(t, "traced errors")
- internal.ExpectErrors(t, app.testHarvest.ErrorTraces, want)
-}
-
-func (app *app) ExpectErrorEvents(t internal.Validator, want []internal.WantEvent) {
- t = internal.ExtendValidator(t, "error events")
- internal.ExpectErrorEvents(t, app.testHarvest.ErrorEvents, want)
-}
-
-func (app *app) ExpectSpanEvents(t internal.Validator, want []internal.WantEvent) {
- t = internal.ExtendValidator(t, "spans events")
- internal.ExpectSpanEvents(t, app.testHarvest.SpanEvents, want)
-}
-
-func (app *app) ExpectTxnEvents(t internal.Validator, want []internal.WantEvent) {
- t = internal.ExtendValidator(t, "txn events")
- internal.ExpectTxnEvents(t, app.testHarvest.TxnEvents, want)
-}
-
-func (app *app) ExpectMetrics(t internal.Validator, want []internal.WantMetric) {
- t = internal.ExtendValidator(t, "metrics")
- internal.ExpectMetrics(t, app.testHarvest.Metrics, want)
-}
-
-func (app *app) ExpectMetricsPresent(t internal.Validator, want []internal.WantMetric) {
- t = internal.ExtendValidator(t, "metrics")
- internal.ExpectMetricsPresent(t, app.testHarvest.Metrics, want)
-}
-
-func (app *app) ExpectTxnMetrics(t internal.Validator, want internal.WantTxn) {
- t = internal.ExtendValidator(t, "metrics")
- internal.ExpectTxnMetrics(t, app.testHarvest.Metrics, want)
-}
-
-func (app *app) ExpectTxnTraces(t internal.Validator, want []internal.WantTxnTrace) {
- t = internal.ExtendValidator(t, "txn traces")
- internal.ExpectTxnTraces(t, app.testHarvest.TxnTraces, want)
-}
-
-func (app *app) ExpectSlowQueries(t internal.Validator, want []internal.WantSlowQuery) {
- t = internal.ExtendValidator(t, "slow queries")
- internal.ExpectSlowQueries(t, app.testHarvest.SlowSQLs, want)
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal_config.go b/vendor/github.com/newrelic/go-agent/internal_config.go
deleted file mode 100644
index d8e6180957f..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal_config.go
+++ /dev/null
@@ -1,190 +0,0 @@
-package newrelic
-
-import (
- "encoding/json"
- "fmt"
- "net/http"
- "os"
- "strings"
-
- "github.com/newrelic/go-agent/internal"
- "github.com/newrelic/go-agent/internal/logger"
- "github.com/newrelic/go-agent/internal/utilization"
-)
-
-func copyDestConfig(c AttributeDestinationConfig) AttributeDestinationConfig {
- cp := c
- if nil != c.Include {
- cp.Include = make([]string, len(c.Include))
- copy(cp.Include, c.Include)
- }
- if nil != c.Exclude {
- cp.Exclude = make([]string, len(c.Exclude))
- copy(cp.Exclude, c.Exclude)
- }
- return cp
-}
-
-func copyConfigReferenceFields(cfg Config) Config {
- cp := cfg
- if nil != cfg.Labels {
- cp.Labels = make(map[string]string, len(cfg.Labels))
- for key, val := range cfg.Labels {
- cp.Labels[key] = val
- }
- }
- if nil != cfg.ErrorCollector.IgnoreStatusCodes {
- ignored := make([]int, len(cfg.ErrorCollector.IgnoreStatusCodes))
- copy(ignored, cfg.ErrorCollector.IgnoreStatusCodes)
- cp.ErrorCollector.IgnoreStatusCodes = ignored
- }
-
- cp.Attributes = copyDestConfig(cfg.Attributes)
- cp.ErrorCollector.Attributes = copyDestConfig(cfg.ErrorCollector.Attributes)
- cp.TransactionEvents.Attributes = copyDestConfig(cfg.TransactionEvents.Attributes)
- cp.TransactionTracer.Attributes = copyDestConfig(cfg.TransactionTracer.Attributes)
- cp.BrowserMonitoring.Attributes = copyDestConfig(cfg.BrowserMonitoring.Attributes)
- cp.SpanEvents.Attributes = copyDestConfig(cfg.SpanEvents.Attributes)
- cp.TransactionTracer.Segments.Attributes = copyDestConfig(cfg.TransactionTracer.Segments.Attributes)
-
- return cp
-}
-
-func transportSetting(t http.RoundTripper) interface{} {
- if nil == t {
- return nil
- }
- return fmt.Sprintf("%T", t)
-}
-
-func loggerSetting(lg Logger) interface{} {
- if nil == lg {
- return nil
- }
- if _, ok := lg.(logger.ShimLogger); ok {
- return nil
- }
- return fmt.Sprintf("%T", lg)
-}
-
-const (
- // https://source.datanerd.us/agents/agent-specs/blob/master/Custom-Host-Names.md
- hostByteLimit = 255
-)
-
-type settings Config
-
-func (s settings) MarshalJSON() ([]byte, error) {
- c := Config(s)
- transport := c.Transport
- c.Transport = nil
- logger := c.Logger
- c.Logger = nil
-
- js, err := json.Marshal(c)
- if nil != err {
- return nil, err
- }
- fields := make(map[string]interface{})
- err = json.Unmarshal(js, &fields)
- if nil != err {
- return nil, err
- }
- // The License field is not simply ignored by adding the `json:"-"` tag
- // to it since we want to allow consumers to populate Config from JSON.
- delete(fields, `License`)
- fields[`Transport`] = transportSetting(transport)
- fields[`Logger`] = loggerSetting(logger)
-
- // Browser monitoring support.
- if c.BrowserMonitoring.Enabled {
- fields[`browser_monitoring.loader`] = "rum"
- }
-
- return json.Marshal(fields)
-}
-
-func configConnectJSONInternal(c Config, pid int, util *utilization.Data, e internal.Environment, version string, securityPolicies *internal.SecurityPolicies, metadata map[string]string) ([]byte, error) {
- return json.Marshal([]interface{}{struct {
- Pid int `json:"pid"`
- Language string `json:"language"`
- Version string `json:"agent_version"`
- Host string `json:"host"`
- HostDisplayName string `json:"display_host,omitempty"`
- Settings interface{} `json:"settings"`
- AppName []string `json:"app_name"`
- HighSecurity bool `json:"high_security"`
- Labels internal.Labels `json:"labels,omitempty"`
- Environment internal.Environment `json:"environment"`
- Identifier string `json:"identifier"`
- Util *utilization.Data `json:"utilization"`
- SecurityPolicies *internal.SecurityPolicies `json:"security_policies,omitempty"`
- Metadata map[string]string `json:"metadata"`
- EventData internal.EventHarvestConfig `json:"event_harvest_config"`
- }{
- Pid: pid,
- Language: internal.AgentLanguage,
- Version: version,
- Host: internal.StringLengthByteLimit(util.Hostname, hostByteLimit),
- HostDisplayName: internal.StringLengthByteLimit(c.HostDisplayName, hostByteLimit),
- Settings: (settings)(c),
- AppName: strings.Split(c.AppName, ";"),
- HighSecurity: c.HighSecurity,
- Labels: internal.Labels(c.Labels),
- Environment: e,
- // This identifier field is provided to avoid:
- // https://newrelic.atlassian.net/browse/DSCORE-778
- //
- // This identifier is used by the collector to look up the real
- // agent. If an identifier isn't provided, the collector will
- // create its own based on the first appname, which prevents a
- // single daemon from connecting "a;b" and "a;c" at the same
- // time.
- //
- // Providing the identifier below works around this issue and
- // allows users more flexibility in using application rollups.
- Identifier: c.AppName,
- Util: util,
- SecurityPolicies: securityPolicies,
- Metadata: metadata,
- EventData: internal.DefaultEventHarvestConfig(),
- }})
-}
-
-const (
- // https://source.datanerd.us/agents/agent-specs/blob/master/Connect-LEGACY.md#metadata-hash
- metadataPrefix = "NEW_RELIC_METADATA_"
-)
-
-func gatherMetadata(environ func() []string) map[string]string {
- metadata := make(map[string]string)
- env := environ()
- for _, pair := range env {
- if strings.HasPrefix(pair, metadataPrefix) {
- idx := strings.Index(pair, "=")
- if idx >= 0 {
- metadata[pair[0:idx]] = pair[idx+1:]
- }
- }
- }
- return metadata
-}
-
-// config allows CreateConnectJSON to be a method on a non-public type.
-type config struct{ Config }
-
-func (c config) CreateConnectJSON(securityPolicies *internal.SecurityPolicies) ([]byte, error) {
- env := internal.NewEnvironment()
- util := utilization.Gather(utilization.Config{
- DetectAWS: c.Utilization.DetectAWS,
- DetectAzure: c.Utilization.DetectAzure,
- DetectPCF: c.Utilization.DetectPCF,
- DetectGCP: c.Utilization.DetectGCP,
- DetectDocker: c.Utilization.DetectDocker,
- DetectKubernetes: c.Utilization.DetectKubernetes,
- LogicalProcessors: c.Utilization.LogicalProcessors,
- TotalRAMMIB: c.Utilization.TotalRAMMIB,
- BillingHostname: c.Utilization.BillingHostname,
- }, c.Logger)
- return configConnectJSONInternal(c.Config, os.Getpid(), util, env, Version, securityPolicies, gatherMetadata(os.Environ))
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal_response_writer.go b/vendor/github.com/newrelic/go-agent/internal_response_writer.go
deleted file mode 100644
index 89cd8a86374..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal_response_writer.go
+++ /dev/null
@@ -1,154 +0,0 @@
-package newrelic
-
-import (
- "bufio"
- "io"
- "net"
- "net/http"
-
- "github.com/newrelic/go-agent/internal"
-)
-
-func (thd *thread) CloseNotify() <-chan bool {
- return thd.txn.getWriter().(http.CloseNotifier).CloseNotify()
-}
-func (thd *thread) Flush() {
- thd.txn.getWriter().(http.Flusher).Flush()
-}
-func (thd *thread) Hijack() (net.Conn, *bufio.ReadWriter, error) {
- return thd.txn.getWriter().(http.Hijacker).Hijack()
-}
-func (thd *thread) ReadFrom(r io.Reader) (int64, error) {
- return thd.txn.getWriter().(io.ReaderFrom).ReadFrom(r)
-}
-
-type threadWithExtras interface {
- Transaction
- internal.AddAgentAttributer
- internal.AddAgentSpanAttributer
-}
-
-func upgradeTxn(thd *thread) Transaction {
- // Note that thd.txn.getWriter() is not used here. The transaction is
- // locked (or under construction) when this function is used.
-
- // GENERATED CODE DO NOT MODIFY
- // This code generated by internal/tools/interface-wrapping
- var (
- i0 int32 = 1 << 0
- i1 int32 = 1 << 1
- i2 int32 = 1 << 2
- i3 int32 = 1 << 3
- )
- var interfaceSet int32
- if _, ok := thd.txn.writer.(http.CloseNotifier); ok {
- interfaceSet |= i0
- }
- if _, ok := thd.txn.writer.(http.Flusher); ok {
- interfaceSet |= i1
- }
- if _, ok := thd.txn.writer.(http.Hijacker); ok {
- interfaceSet |= i2
- }
- if _, ok := thd.txn.writer.(io.ReaderFrom); ok {
- interfaceSet |= i3
- }
- switch interfaceSet {
- default: // No optional interfaces implemented
- return struct {
- threadWithExtras
- }{thd}
- case i0:
- return struct {
- threadWithExtras
- http.CloseNotifier
- }{thd, thd}
- case i1:
- return struct {
- threadWithExtras
- http.Flusher
- }{thd, thd}
- case i0 | i1:
- return struct {
- threadWithExtras
- http.CloseNotifier
- http.Flusher
- }{thd, thd, thd}
- case i2:
- return struct {
- threadWithExtras
- http.Hijacker
- }{thd, thd}
- case i0 | i2:
- return struct {
- threadWithExtras
- http.CloseNotifier
- http.Hijacker
- }{thd, thd, thd}
- case i1 | i2:
- return struct {
- threadWithExtras
- http.Flusher
- http.Hijacker
- }{thd, thd, thd}
- case i0 | i1 | i2:
- return struct {
- threadWithExtras
- http.CloseNotifier
- http.Flusher
- http.Hijacker
- }{thd, thd, thd, thd}
- case i3:
- return struct {
- threadWithExtras
- io.ReaderFrom
- }{thd, thd}
- case i0 | i3:
- return struct {
- threadWithExtras
- http.CloseNotifier
- io.ReaderFrom
- }{thd, thd, thd}
- case i1 | i3:
- return struct {
- threadWithExtras
- http.Flusher
- io.ReaderFrom
- }{thd, thd, thd}
- case i0 | i1 | i3:
- return struct {
- threadWithExtras
- http.CloseNotifier
- http.Flusher
- io.ReaderFrom
- }{thd, thd, thd, thd}
- case i2 | i3:
- return struct {
- threadWithExtras
- http.Hijacker
- io.ReaderFrom
- }{thd, thd, thd}
- case i0 | i2 | i3:
- return struct {
- threadWithExtras
- http.CloseNotifier
- http.Hijacker
- io.ReaderFrom
- }{thd, thd, thd, thd}
- case i1 | i2 | i3:
- return struct {
- threadWithExtras
- http.Flusher
- http.Hijacker
- io.ReaderFrom
- }{thd, thd, thd, thd}
- case i0 | i1 | i2 | i3:
- return struct {
- threadWithExtras
- http.CloseNotifier
- http.Flusher
- http.Hijacker
- io.ReaderFrom
- }{thd, thd, thd, thd, thd}
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/internal_txn.go b/vendor/github.com/newrelic/go-agent/internal_txn.go
deleted file mode 100644
index e6e9e46cbf9..00000000000
--- a/vendor/github.com/newrelic/go-agent/internal_txn.go
+++ /dev/null
@@ -1,1134 +0,0 @@
-package newrelic
-
-import (
- "errors"
- "fmt"
- "net/http"
- "net/url"
- "reflect"
- "strings"
- "sync"
- "time"
-
- "github.com/newrelic/go-agent/internal"
-)
-
-type txnInput struct {
- // This ResponseWriter should only be accessed using txn.getWriter()
- writer http.ResponseWriter
- app Application
- Consumer dataConsumer
- *appRun
-}
-
-type txn struct {
- txnInput
- // This mutex is required since the consumer may call the public API
- // interface functions from different routines.
- sync.Mutex
- // finished indicates whether or not End() has been called. After
- // finished has been set to true, no recording should occur.
- finished bool
- numPayloadsCreated uint32
- sampledCalculated bool
-
- ignore bool
-
- // wroteHeader prevents capturing multiple response code errors if the
- // user erroneously calls WriteHeader multiple times.
- wroteHeader bool
-
- internal.TxnData
-
- mainThread internal.Thread
- asyncThreads []*internal.Thread
-}
-
-type thread struct {
- *txn
- // thread does not have locking because it should only be accessed while
- // the txn is locked.
- thread *internal.Thread
-}
-
-func (txn *txn) markStart(now time.Time) {
- txn.Start = now
- // The mainThread is considered active now.
- txn.mainThread.RecordActivity(now)
-
-}
-
-func (txn *txn) markEnd(now time.Time, thread *internal.Thread) {
- txn.Stop = now
- // The thread on which End() was called is considered active now.
- thread.RecordActivity(now)
- txn.Duration = txn.Stop.Sub(txn.Start)
-
- // TotalTime is the sum of "active time" across all threads. A thread
- // was active when it started the transaction, stopped the transaction,
- // started a segment, or stopped a segment.
- txn.TotalTime = txn.mainThread.TotalTime()
- for _, thd := range txn.asyncThreads {
- txn.TotalTime += thd.TotalTime()
- }
- // Ensure that TotalTime is at least as large as Duration so that the
- // graphs look sensible. This can happen under the following situation:
- // goroutine1: txn.start----|segment1|
- // goroutine2: |segment2|----txn.end
- if txn.Duration > txn.TotalTime {
- txn.TotalTime = txn.Duration
- }
-}
-
-func newTxn(input txnInput, name string) *thread {
- txn := &txn{
- txnInput: input,
- }
- txn.markStart(time.Now())
-
- txn.Name = name
- txn.Attrs = internal.NewAttributes(input.AttributeConfig)
-
- if input.Config.DistributedTracer.Enabled {
- txn.BetterCAT.Enabled = true
- txn.BetterCAT.Priority = internal.NewPriority()
- txn.TraceIDGenerator = input.Reply.TraceIDGenerator
- txn.BetterCAT.ID = txn.TraceIDGenerator.GenerateTraceID()
- txn.SpanEventsEnabled = txn.Config.SpanEvents.Enabled
- txn.LazilyCalculateSampled = txn.lazilyCalculateSampled
- }
-
- txn.Attrs.Agent.Add(internal.AttributeHostDisplayName, txn.Config.HostDisplayName, nil)
- txn.TxnTrace.Enabled = txn.Config.TransactionTracer.Enabled
- txn.TxnTrace.SegmentThreshold = txn.Config.TransactionTracer.SegmentThreshold
- txn.StackTraceThreshold = txn.Config.TransactionTracer.StackTraceThreshold
- txn.SlowQueriesEnabled = txn.Config.DatastoreTracer.SlowQuery.Enabled
- txn.SlowQueryThreshold = txn.Config.DatastoreTracer.SlowQuery.Threshold
-
- // Synthetics support is tied up with a transaction's Old CAT field,
- // CrossProcess. To support Synthetics with either BetterCAT or Old CAT,
- // Initialize the CrossProcess field of the transaction, passing in
- // the top-level configuration.
- doOldCAT := txn.Config.CrossApplicationTracer.Enabled
- noGUID := txn.Config.DistributedTracer.Enabled
- txn.CrossProcess.Init(doOldCAT, noGUID, input.Reply)
-
- return &thread{
- txn: txn,
- thread: &txn.mainThread,
- }
-}
-
-// lazilyCalculateSampled calculates and returns whether or not the transaction
-// should be sampled. Sampled is not computed at the beginning of the
-// transaction because we want to calculate Sampled only for transactions that
-// do not accept an inbound payload.
-func (txn *txn) lazilyCalculateSampled() bool {
- if !txn.BetterCAT.Enabled {
- return false
- }
- if txn.sampledCalculated {
- return txn.BetterCAT.Sampled
- }
- txn.BetterCAT.Sampled = txn.Reply.AdaptiveSampler.ComputeSampled(txn.BetterCAT.Priority.Float32(), time.Now())
- if txn.BetterCAT.Sampled {
- txn.BetterCAT.Priority += 1.0
- }
- txn.sampledCalculated = true
- return txn.BetterCAT.Sampled
-}
-
-type requestWrap struct{ request *http.Request }
-
-func (r requestWrap) Header() http.Header { return r.request.Header }
-func (r requestWrap) URL() *url.URL { return r.request.URL }
-func (r requestWrap) Method() string { return r.request.Method }
-
-func (r requestWrap) Transport() TransportType {
- if strings.HasPrefix(r.request.Proto, "HTTP") {
- if r.request.TLS != nil {
- return TransportHTTPS
- }
- return TransportHTTP
- }
- return TransportUnknown
-
-}
-
-type staticWebRequest struct {
- header http.Header
- url *url.URL
- method string
- transport TransportType
-}
-
-func (r staticWebRequest) Header() http.Header { return r.header }
-func (r staticWebRequest) URL() *url.URL { return r.url }
-func (r staticWebRequest) Method() string { return r.method }
-func (r staticWebRequest) Transport() TransportType { return TransportHTTP }
-
-func (txn *txn) SetWebRequest(r WebRequest) error {
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return errAlreadyEnded
- }
-
- // Any call to SetWebRequest should indicate a web transaction.
- txn.IsWeb = true
-
- if nil == r {
- return nil
- }
- h := r.Header()
- if nil != h {
- txn.Queuing = internal.QueueDuration(h, txn.Start)
-
- if p := h.Get(DistributedTracePayloadHeader); p != "" {
- txn.acceptDistributedTracePayloadLocked(r.Transport(), p)
- }
-
- txn.CrossProcess.InboundHTTPRequest(h)
- }
-
- internal.RequestAgentAttributes(txn.Attrs, r.Method(), h, r.URL())
-
- return nil
-}
-
-func (thd *thread) SetWebResponse(w http.ResponseWriter) Transaction {
- txn := thd.txn
- txn.Lock()
- defer txn.Unlock()
-
- // Replace the ResponseWriter even if the transaction has ended so that
- // consumers calling ResponseWriter methods on the transactions see that
- // data flowing through as expected.
- txn.writer = w
-
- return upgradeTxn(&thread{
- thread: thd.thread,
- txn: txn,
- })
-}
-
-func (txn *txn) freezeName() {
- if txn.ignore || ("" != txn.FinalName) {
- return
- }
-
- txn.FinalName = internal.CreateFullTxnName(txn.Name, txn.Reply, txn.IsWeb)
- if "" == txn.FinalName {
- txn.ignore = true
- }
-}
-
-func (txn *txn) getsApdex() bool {
- return txn.IsWeb
-}
-
-func (txn *txn) shouldSaveTrace() bool {
- if !txn.Config.TransactionTracer.Enabled {
- return false
- }
- if txn.CrossProcess.IsSynthetics() {
- return true
- }
- return txn.Duration >= txn.txnTraceThreshold(txn.ApdexThreshold)
-}
-
-func (txn *txn) MergeIntoHarvest(h *internal.Harvest) {
-
- var priority internal.Priority
- if txn.BetterCAT.Enabled {
- priority = txn.BetterCAT.Priority
- } else {
- priority = internal.NewPriority()
- }
-
- internal.CreateTxnMetrics(&txn.TxnData, h.Metrics)
- internal.MergeBreakdownMetrics(&txn.TxnData, h.Metrics)
-
- if txn.Config.TransactionEvents.Enabled {
- // Allocate a new TxnEvent to prevent a reference to the large transaction.
- alloc := new(internal.TxnEvent)
- *alloc = txn.TxnData.TxnEvent
- h.TxnEvents.AddTxnEvent(alloc, priority)
- }
-
- if txn.Reply.CollectErrors {
- internal.MergeTxnErrors(&h.ErrorTraces, txn.Errors, txn.TxnEvent)
- }
-
- if txn.Config.ErrorCollector.CaptureEvents {
- for _, e := range txn.Errors {
- errEvent := &internal.ErrorEvent{
- ErrorData: *e,
- TxnEvent: txn.TxnEvent,
- }
- // Since the stack trace is not used in error events, remove the reference
- // to minimize memory.
- errEvent.Stack = nil
- h.ErrorEvents.Add(errEvent, priority)
- }
- }
-
- if txn.shouldSaveTrace() {
- h.TxnTraces.Witness(internal.HarvestTrace{
- TxnEvent: txn.TxnEvent,
- Trace: txn.TxnTrace,
- })
- }
-
- if nil != txn.SlowQueries {
- h.SlowSQLs.Merge(txn.SlowQueries, txn.TxnEvent)
- }
-
- if txn.BetterCAT.Sampled && txn.SpanEventsEnabled {
- h.SpanEvents.MergeFromTransaction(&txn.TxnData)
- }
-}
-
-func headersJustWritten(txn *txn, code int, hdr http.Header) {
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return
- }
- if txn.wroteHeader {
- return
- }
- txn.wroteHeader = true
-
- internal.ResponseHeaderAttributes(txn.Attrs, hdr)
- internal.ResponseCodeAttribute(txn.Attrs, code)
-
- if txn.appRun.responseCodeIsError(code) {
- e := internal.TxnErrorFromResponseCode(time.Now(), code)
- e.Stack = internal.GetStackTrace()
- txn.noticeErrorInternal(e)
- }
-}
-
-func (txn *txn) responseHeader(hdr http.Header) http.Header {
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return nil
- }
- if txn.wroteHeader {
- return nil
- }
- if !txn.CrossProcess.Enabled {
- return nil
- }
- if !txn.CrossProcess.IsInbound() {
- return nil
- }
- txn.freezeName()
- contentLength := internal.GetContentLengthFromHeader(hdr)
-
- appData, err := txn.CrossProcess.CreateAppData(txn.FinalName, txn.Queuing, time.Since(txn.Start), contentLength)
- if err != nil {
- txn.Config.Logger.Debug("error generating outbound response header", map[string]interface{}{
- "error": err,
- })
- return nil
- }
- return internal.AppDataToHTTPHeader(appData)
-}
-
-func addCrossProcessHeaders(txn *txn, hdr http.Header) {
- // responseHeader() checks the wroteHeader field and returns a nil map if the
- // header has been written, so we don't need a check here.
- if nil != hdr {
- for key, values := range txn.responseHeader(hdr) {
- for _, value := range values {
- hdr.Add(key, value)
- }
- }
- }
-}
-
-// getWriter is used to access the transaction's ResponseWriter. The
-// ResponseWriter is mutex protected since it may be changed with
-// txn.SetWebResponse, and we want changes to be visible across goroutines. The
-// ResponseWriter is accessed using this getWriter() function rather than directly
-// in mutex protected methods since we do NOT want the transaction to be locked
-// while calling the ResponseWriter's methods.
-func (txn *txn) getWriter() http.ResponseWriter {
- txn.Lock()
- rw := txn.writer
- txn.Unlock()
- return rw
-}
-
-func nilSafeHeader(rw http.ResponseWriter) http.Header {
- if nil == rw {
- return nil
- }
- return rw.Header()
-}
-
-func (txn *txn) Header() http.Header {
- return nilSafeHeader(txn.getWriter())
-}
-
-func (txn *txn) Write(b []byte) (n int, err error) {
- rw := txn.getWriter()
- hdr := nilSafeHeader(rw)
-
- // This is safe to call unconditionally, even if Write() is called multiple
- // times; see also the commentary in addCrossProcessHeaders().
- addCrossProcessHeaders(txn, hdr)
-
- if rw != nil {
- n, err = rw.Write(b)
- }
-
- headersJustWritten(txn, http.StatusOK, hdr)
-
- return
-}
-
-func (txn *txn) WriteHeader(code int) {
- rw := txn.getWriter()
- hdr := nilSafeHeader(rw)
-
- addCrossProcessHeaders(txn, hdr)
-
- if nil != rw {
- rw.WriteHeader(code)
- }
-
- headersJustWritten(txn, code, hdr)
-}
-
-func (thd *thread) End() error {
- txn := thd.txn
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return errAlreadyEnded
- }
-
- txn.finished = true
-
- r := recover()
- if nil != r {
- e := internal.TxnErrorFromPanic(time.Now(), r)
- e.Stack = internal.GetStackTrace()
- txn.noticeErrorInternal(e)
- }
-
- txn.markEnd(time.Now(), thd.thread)
- txn.freezeName()
- // Make a sampling decision if there have been no segments or outbound
- // payloads.
- txn.lazilyCalculateSampled()
-
- // Finalise the CAT state.
- if err := txn.CrossProcess.Finalise(txn.Name, txn.Config.AppName); err != nil {
- txn.Config.Logger.Debug("error finalising the cross process state", map[string]interface{}{
- "error": err,
- })
- }
-
- // Assign apdexThreshold regardless of whether or not the transaction
- // gets apdex since it may be used to calculate the trace threshold.
- txn.ApdexThreshold = internal.CalculateApdexThreshold(txn.Reply, txn.FinalName)
-
- if txn.getsApdex() {
- if txn.HasErrors() {
- txn.Zone = internal.ApdexFailing
- } else {
- txn.Zone = internal.CalculateApdexZone(txn.ApdexThreshold, txn.Duration)
- }
- } else {
- txn.Zone = internal.ApdexNone
- }
-
- if txn.Config.Logger.DebugEnabled() {
- txn.Config.Logger.Debug("transaction ended", map[string]interface{}{
- "name": txn.FinalName,
- "duration_ms": txn.Duration.Seconds() * 1000.0,
- "ignored": txn.ignore,
- "app_connected": "" != txn.Reply.RunID,
- })
- }
-
- if !txn.ignore {
- txn.Consumer.Consume(txn.Reply.RunID, txn)
- }
-
- // Note that if a consumer uses `panic(nil)`, the panic will not
- // propagate.
- if nil != r {
- panic(r)
- }
-
- return nil
-}
-
-func (txn *txn) AddAttribute(name string, value interface{}) error {
- txn.Lock()
- defer txn.Unlock()
-
- if txn.Config.HighSecurity {
- return errHighSecurityEnabled
- }
-
- if !txn.Reply.SecurityPolicies.CustomParameters.Enabled() {
- return errSecurityPolicy
- }
-
- if txn.finished {
- return errAlreadyEnded
- }
-
- return internal.AddUserAttribute(txn.Attrs, name, value, internal.DestAll)
-}
-
-var (
- errorsDisabled = errors.New("errors disabled")
- errNilError = errors.New("nil error")
- errAlreadyEnded = errors.New("transaction has already ended")
- errSecurityPolicy = errors.New("disabled by security policy")
- errTransactionIgnored = errors.New("transaction has been ignored")
- errBrowserDisabled = errors.New("browser disabled by local configuration")
-)
-
-const (
- highSecurityErrorMsg = "message removed by high security setting"
- securityPolicyErrorMsg = "message removed by security policy"
-)
-
-func (txn *txn) noticeErrorInternal(err internal.ErrorData) error {
- if !txn.Config.ErrorCollector.Enabled {
- return errorsDisabled
- }
-
- if nil == txn.Errors {
- txn.Errors = internal.NewTxnErrors(internal.MaxTxnErrors)
- }
-
- if txn.Config.HighSecurity {
- err.Msg = highSecurityErrorMsg
- }
-
- if !txn.Reply.SecurityPolicies.AllowRawExceptionMessages.Enabled() {
- err.Msg = securityPolicyErrorMsg
- }
-
- txn.Errors.Add(err)
- txn.TxnData.TxnEvent.HasError = true //mark transaction as having an error
- return nil
-}
-
-var (
- errTooManyErrorAttributes = fmt.Errorf("too many extra attributes: limit is %d",
- internal.AttributeErrorLimit)
-)
-
-func (txn *txn) NoticeError(err error) error {
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return errAlreadyEnded
- }
-
- if nil == err {
- return errNilError
- }
-
- e := internal.ErrorData{
- When: time.Now(),
- Msg: err.Error(),
- }
- if ec, ok := err.(ErrorClasser); ok {
- e.Klass = ec.ErrorClass()
- }
- if "" == e.Klass {
- e.Klass = reflect.TypeOf(err).String()
- }
- if st, ok := err.(StackTracer); ok {
- e.Stack = st.StackTrace()
- // Note that if the provided stack trace is excessive in length,
- // it will be truncated during JSON creation.
- }
- if nil == e.Stack {
- e.Stack = internal.GetStackTrace()
- }
-
- if ea, ok := err.(ErrorAttributer); ok && !txn.Config.HighSecurity && txn.Reply.SecurityPolicies.CustomParameters.Enabled() {
- unvetted := ea.ErrorAttributes()
- if len(unvetted) > internal.AttributeErrorLimit {
- return errTooManyErrorAttributes
- }
-
- e.ExtraAttributes = make(map[string]interface{})
- for key, val := range unvetted {
- val, errr := internal.ValidateUserAttribute(key, val)
- if nil != errr {
- return errr
- }
- e.ExtraAttributes[key] = val
- }
- }
-
- return txn.noticeErrorInternal(e)
-}
-
-func (txn *txn) SetName(name string) error {
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return errAlreadyEnded
- }
-
- txn.Name = name
- return nil
-}
-
-func (txn *txn) Ignore() error {
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return errAlreadyEnded
- }
- txn.ignore = true
- return nil
-}
-
-func (thd *thread) StartSegmentNow() SegmentStartTime {
- var s internal.SegmentStartTime
- txn := thd.txn
- txn.Lock()
- if !txn.finished {
- s = internal.StartSegment(&txn.TxnData, thd.thread, time.Now())
- }
- txn.Unlock()
- return SegmentStartTime{
- segment: segment{
- start: s,
- thread: thd,
- },
- }
-}
-
-const (
- // Browser fields are encoded using the first digits of the license
- // key.
- browserEncodingKeyLimit = 13
-)
-
-func browserEncodingKey(licenseKey string) []byte {
- key := []byte(licenseKey)
- if len(key) > browserEncodingKeyLimit {
- key = key[0:browserEncodingKeyLimit]
- }
- return key
-}
-
-func (txn *txn) BrowserTimingHeader() (*BrowserTimingHeader, error) {
- txn.Lock()
- defer txn.Unlock()
-
- if !txn.Config.BrowserMonitoring.Enabled {
- return nil, errBrowserDisabled
- }
-
- if txn.Reply.AgentLoader == "" {
- // If the loader is empty, either browser has been disabled
- // by the server or the application is not yet connected.
- return nil, nil
- }
-
- if txn.finished {
- return nil, errAlreadyEnded
- }
-
- txn.freezeName()
-
- // Freezing the name might cause the transaction to be ignored, so check
- // this after txn.freezeName().
- if txn.ignore {
- return nil, errTransactionIgnored
- }
-
- encodingKey := browserEncodingKey(txn.Config.License)
-
- attrs, err := internal.Obfuscate(internal.BrowserAttributes(txn.Attrs), encodingKey)
- if err != nil {
- return nil, fmt.Errorf("error getting browser attributes: %v", err)
- }
-
- name, err := internal.Obfuscate([]byte(txn.FinalName), encodingKey)
- if err != nil {
- return nil, fmt.Errorf("error obfuscating name: %v", err)
- }
-
- return &BrowserTimingHeader{
- agentLoader: txn.Reply.AgentLoader,
- info: browserInfo{
- Beacon: txn.Reply.Beacon,
- LicenseKey: txn.Reply.BrowserKey,
- ApplicationID: txn.Reply.AppID,
- TransactionName: name,
- QueueTimeMillis: txn.Queuing.Nanoseconds() / (1000 * 1000),
- ApplicationTimeMillis: time.Now().Sub(txn.Start).Nanoseconds() / (1000 * 1000),
- ObfuscatedAttributes: attrs,
- ErrorBeacon: txn.Reply.ErrorBeacon,
- Agent: txn.Reply.JSAgentFile,
- },
- }, nil
-}
-
-func createThread(txn *txn) *internal.Thread {
- newThread := internal.NewThread(&txn.TxnData)
- txn.asyncThreads = append(txn.asyncThreads, newThread)
- return newThread
-}
-
-func (thd *thread) NewGoroutine() Transaction {
- txn := thd.txn
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- // If the transaction has finished, return the same thread.
- return upgradeTxn(thd)
- }
- return upgradeTxn(&thread{
- thread: createThread(txn),
- txn: txn,
- })
-}
-
-type segment struct {
- start internal.SegmentStartTime
- thread *thread
-}
-
-func endSegment(s *Segment) error {
- if nil == s {
- return nil
- }
- thd := s.StartTime.thread
- if nil == thd {
- return nil
- }
- txn := thd.txn
- var err error
- txn.Lock()
- if txn.finished {
- err = errAlreadyEnded
- } else {
- err = internal.EndBasicSegment(&txn.TxnData, thd.thread, s.StartTime.start, time.Now(), s.Name)
- }
- txn.Unlock()
- return err
-}
-
-func endDatastore(s *DatastoreSegment) error {
- if nil == s {
- return nil
- }
- thd := s.StartTime.thread
- if nil == thd {
- return nil
- }
- txn := thd.txn
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return errAlreadyEnded
- }
- if txn.Config.HighSecurity {
- s.QueryParameters = nil
- }
- if !txn.Config.DatastoreTracer.QueryParameters.Enabled {
- s.QueryParameters = nil
- }
- if txn.Reply.SecurityPolicies.RecordSQL.IsSet() {
- s.QueryParameters = nil
- if !txn.Reply.SecurityPolicies.RecordSQL.Enabled() {
- s.ParameterizedQuery = ""
- }
- }
- if !txn.Config.DatastoreTracer.DatabaseNameReporting.Enabled {
- s.DatabaseName = ""
- }
- if !txn.Config.DatastoreTracer.InstanceReporting.Enabled {
- s.Host = ""
- s.PortPathOrID = ""
- }
- return internal.EndDatastoreSegment(internal.EndDatastoreParams{
- TxnData: &txn.TxnData,
- Thread: thd.thread,
- Start: s.StartTime.start,
- Now: time.Now(),
- Product: string(s.Product),
- Collection: s.Collection,
- Operation: s.Operation,
- ParameterizedQuery: s.ParameterizedQuery,
- QueryParameters: s.QueryParameters,
- Host: s.Host,
- PortPathOrID: s.PortPathOrID,
- Database: s.DatabaseName,
- })
-}
-
-func externalSegmentMethod(s *ExternalSegment) string {
- if "" != s.Procedure {
- return s.Procedure
- }
- r := s.Request
- if nil != s.Response && nil != s.Response.Request {
- r = s.Response.Request
- }
-
- if nil != r {
- if "" != r.Method {
- return r.Method
- }
- // Golang's http package states that when a client's Request has
- // an empty string for Method, the method is GET.
- return "GET"
- }
-
- return ""
-}
-
-func externalSegmentURL(s *ExternalSegment) (*url.URL, error) {
- if "" != s.URL {
- return url.Parse(s.URL)
- }
- r := s.Request
- if nil != s.Response && nil != s.Response.Request {
- r = s.Response.Request
- }
- if r != nil {
- return r.URL, nil
- }
- return nil, nil
-}
-
-func endExternal(s *ExternalSegment) error {
- if nil == s {
- return nil
- }
- thd := s.StartTime.thread
- if nil == thd {
- return nil
- }
- txn := thd.txn
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return errAlreadyEnded
- }
- u, err := externalSegmentURL(s)
- if nil != err {
- return err
- }
- return internal.EndExternalSegment(internal.EndExternalParams{
- TxnData: &txn.TxnData,
- Thread: thd.thread,
- Start: s.StartTime.start,
- Now: time.Now(),
- Logger: txn.Config.Logger,
- Response: s.Response,
- URL: u,
- Host: s.Host,
- Library: s.Library,
- Method: externalSegmentMethod(s),
- })
-}
-
-// oldCATOutboundHeaders generates the Old CAT and Synthetics headers, depending
-// on whether Old CAT is enabled or any Synthetics functionality has been
-// triggered in the agent.
-func oldCATOutboundHeaders(txn *txn) http.Header {
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return http.Header{}
- }
-
- metadata, err := txn.CrossProcess.CreateCrossProcessMetadata(txn.Name, txn.Config.AppName)
- if err != nil {
- txn.Config.Logger.Debug("error generating outbound headers", map[string]interface{}{
- "error": err,
- })
-
- // It's possible for CreateCrossProcessMetadata() to error and still have a
- // Synthetics header, so we'll still fall through to returning headers
- // based on whatever metadata was returned.
- }
-
- return internal.MetadataToHTTPHeader(metadata)
-}
-
-func outboundHeaders(s *ExternalSegment) http.Header {
- thd := s.StartTime.thread
-
- if nil == thd {
- return http.Header{}
- }
- txn := thd.txn
- hdr := oldCATOutboundHeaders(txn)
-
- // hdr may be empty, or it may contain headers. If DistributedTracer
- // is enabled, add more to the existing hdr
- if p := thd.CreateDistributedTracePayload().HTTPSafe(); "" != p {
- hdr.Add(DistributedTracePayloadHeader, p)
- return hdr
- }
-
- return hdr
-}
-
-const (
- maxSampledDistributedPayloads = 35
-)
-
-type shimPayload struct{}
-
-func (s shimPayload) Text() string { return "" }
-func (s shimPayload) HTTPSafe() string { return "" }
-
-func (thd *thread) CreateDistributedTracePayload() (payload DistributedTracePayload) {
- payload = shimPayload{}
-
- txn := thd.txn
- txn.Lock()
- defer txn.Unlock()
-
- if !txn.BetterCAT.Enabled {
- return
- }
-
- if txn.finished {
- txn.CreatePayloadException = true
- return
- }
-
- if "" == txn.Reply.AccountID || "" == txn.Reply.TrustedAccountKey {
- // We can't create a payload: The application is not yet
- // connected or serverless distributed tracing configuration was
- // not provided.
- return
- }
-
- txn.numPayloadsCreated++
-
- var p internal.Payload
- p.Type = internal.CallerType
- p.Account = txn.Reply.AccountID
-
- p.App = txn.Reply.PrimaryAppID
- p.TracedID = txn.BetterCAT.TraceID()
- p.Priority = txn.BetterCAT.Priority
- p.Timestamp.Set(time.Now())
- p.TransactionID = txn.BetterCAT.ID // Set the transaction ID to the transaction guid.
-
- if txn.Reply.AccountID != txn.Reply.TrustedAccountKey {
- p.TrustedAccountKey = txn.Reply.TrustedAccountKey
- }
-
- sampled := txn.lazilyCalculateSampled()
- if sampled && txn.SpanEventsEnabled {
- p.ID = txn.CurrentSpanIdentifier(thd.thread)
- }
-
- // limit the number of outbound sampled=true payloads to prevent too
- // many downstream sampled events.
- p.SetSampled(false)
- if txn.numPayloadsCreated < maxSampledDistributedPayloads {
- p.SetSampled(sampled)
- }
-
- txn.CreatePayloadSuccess = true
-
- payload = p
- return
-}
-
-var (
- errOutboundPayloadCreated = errors.New("outbound payload already created")
- errAlreadyAccepted = errors.New("AcceptDistributedTracePayload has already been called")
- errInboundPayloadDTDisabled = errors.New("DistributedTracer must be enabled to accept an inbound payload")
- errTrustedAccountKey = errors.New("trusted account key missing or does not match")
-)
-
-func (txn *txn) AcceptDistributedTracePayload(t TransportType, p interface{}) error {
- txn.Lock()
- defer txn.Unlock()
-
- return txn.acceptDistributedTracePayloadLocked(t, p)
-}
-
-func (txn *txn) acceptDistributedTracePayloadLocked(t TransportType, p interface{}) error {
-
- if !txn.BetterCAT.Enabled {
- return errInboundPayloadDTDisabled
- }
-
- if txn.finished {
- txn.AcceptPayloadException = true
- return errAlreadyEnded
- }
-
- if txn.numPayloadsCreated > 0 {
- txn.AcceptPayloadCreateBeforeAccept = true
- return errOutboundPayloadCreated
- }
-
- if txn.BetterCAT.Inbound != nil {
- txn.AcceptPayloadIgnoredMultiple = true
- return errAlreadyAccepted
- }
-
- if nil == p {
- txn.AcceptPayloadNullPayload = true
- return nil
- }
-
- if "" == txn.Reply.AccountID || "" == txn.Reply.TrustedAccountKey {
- // We can't accept a payload: The application is not yet
- // connected or serverless distributed tracing configuration was
- // not provided.
- return nil
- }
-
- payload, err := internal.AcceptPayload(p)
- if nil != err {
- if _, ok := err.(internal.ErrPayloadParse); ok {
- txn.AcceptPayloadParseException = true
- } else if _, ok := err.(internal.ErrUnsupportedPayloadVersion); ok {
- txn.AcceptPayloadIgnoredVersion = true
- } else if _, ok := err.(internal.ErrPayloadMissingField); ok {
- txn.AcceptPayloadParseException = true
- } else {
- txn.AcceptPayloadException = true
- }
- return err
- }
-
- if nil == payload {
- return nil
- }
-
- // now that we have a parsed and alloc'd payload,
- // let's make sure it has the correct fields
- if err := payload.IsValid(); nil != err {
- txn.AcceptPayloadParseException = true
- return err
- }
-
- // and let's also do our trustedKey check
- receivedTrustKey := payload.TrustedAccountKey
- if "" == receivedTrustKey {
- receivedTrustKey = payload.Account
- }
- if receivedTrustKey != txn.Reply.TrustedAccountKey {
- txn.AcceptPayloadUntrustedAccount = true
- return errTrustedAccountKey
- }
-
- if 0 != payload.Priority {
- txn.BetterCAT.Priority = payload.Priority
- }
-
- // a nul payload.Sampled means the a field wasn't provided
- if nil != payload.Sampled {
- txn.BetterCAT.Sampled = *payload.Sampled
- txn.sampledCalculated = true
- }
-
- txn.BetterCAT.Inbound = payload
-
- // TransportType's name field is not mutable outside of its package
- // so the only check needed is if the caller is using an empty TransportType
- txn.BetterCAT.Inbound.TransportType = t.name
- if t.name == "" {
- txn.BetterCAT.Inbound.TransportType = TransportUnknown.name
- txn.Config.Logger.Debug("Invalid transport type, defaulting to Unknown", map[string]interface{}{})
- }
-
- if tm := payload.Timestamp.Time(); txn.Start.After(tm) {
- txn.BetterCAT.Inbound.TransportDuration = txn.Start.Sub(tm)
- }
-
- txn.AcceptPayloadSuccess = true
-
- return nil
-}
-
-func (txn *txn) Application() Application {
- return txn.app
-}
-
-func (thd *thread) AddAgentSpanAttribute(key internal.SpanAttribute, val string) {
- thd.thread.AddAgentSpanAttribute(key, val)
-}
-
-var (
- // Ensure that txn implements AddAgentAttributer to avoid breaking
- // integration package type assertions.
- _ internal.AddAgentAttributer = &txn{}
-)
-
-func (txn *txn) AddAgentAttribute(id internal.AgentAttributeID, stringVal string, otherVal interface{}) {
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return
- }
- txn.Attrs.Agent.Add(id, stringVal, otherVal)
-}
-
-func (thd *thread) GetTraceMetadata() (metadata TraceMetadata) {
- txn := thd.txn
- txn.Lock()
- defer txn.Unlock()
-
- if txn.finished {
- return
- }
-
- if txn.BetterCAT.Enabled {
- metadata.TraceID = txn.BetterCAT.TraceID()
- if txn.SpanEventsEnabled && txn.lazilyCalculateSampled() {
- metadata.SpanID = txn.CurrentSpanIdentifier(thd.thread)
- }
- }
-
- return
-}
-
-func (thd *thread) GetLinkingMetadata() (metadata LinkingMetadata) {
- txn := thd.txn
- metadata.EntityName = txn.appRun.firstAppName
- metadata.EntityType = "SERVICE"
- metadata.EntityGUID = txn.appRun.Reply.EntityGUID
- metadata.Hostname = internal.ThisHost
-
- md := thd.GetTraceMetadata()
- metadata.TraceID = md.TraceID
- metadata.SpanID = md.SpanID
-
- return
-}
diff --git a/vendor/github.com/newrelic/go-agent/log.go b/vendor/github.com/newrelic/go-agent/log.go
deleted file mode 100644
index aa2daf62c0c..00000000000
--- a/vendor/github.com/newrelic/go-agent/log.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package newrelic
-
-import (
- "io"
-
- "github.com/newrelic/go-agent/internal/logger"
-)
-
-// Logger is the interface that is used for logging in the go-agent. Assign the
-// Config.Logger field to the Logger you wish to use. Loggers must be safe for
-// use in multiple goroutines. Two Logger implementations are included:
-// NewLogger, which logs at info level, and NewDebugLogger which logs at debug
-// level. logrus and logxi are supported by the integration packages
-// https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlogrus and
-// https://godoc.org/github.com/newrelic/go-agent/_integrations/nrlogxi/v1.
-type Logger interface {
- Error(msg string, context map[string]interface{})
- Warn(msg string, context map[string]interface{})
- Info(msg string, context map[string]interface{})
- Debug(msg string, context map[string]interface{})
- DebugEnabled() bool
-}
-
-// NewLogger creates a basic Logger at info level.
-func NewLogger(w io.Writer) Logger {
- return logger.New(w, false)
-}
-
-// NewDebugLogger creates a basic Logger at debug level.
-func NewDebugLogger(w io.Writer) Logger {
- return logger.New(w, true)
-}
diff --git a/vendor/github.com/newrelic/go-agent/segments.go b/vendor/github.com/newrelic/go-agent/segments.go
deleted file mode 100644
index d1a1d2a3c99..00000000000
--- a/vendor/github.com/newrelic/go-agent/segments.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package newrelic
-
-import (
- "net/http"
-)
-
-// SegmentStartTime is created by Transaction.StartSegmentNow and marks the
-// beginning of a segment. A segment with a zero-valued SegmentStartTime may
-// safely be ended.
-type SegmentStartTime struct{ segment }
-
-// Segment is used to instrument functions, methods, and blocks of code. The
-// easiest way use Segment is the StartSegment function.
-type Segment struct {
- StartTime SegmentStartTime
- Name string
-}
-
-// DatastoreSegment is used to instrument calls to databases and object stores.
-type DatastoreSegment struct {
- // StartTime should be assigned using StartSegmentNow before each datastore
- // call is made.
- StartTime SegmentStartTime
-
- // Product, Collection, and Operation are highly recommended as they are
- // used for aggregate metrics:
- //
- // Product is the datastore type. See the constants in
- // https://github.com/newrelic/go-agent/blob/master/datastore.go. Product
- // is one of the fields primarily responsible for the grouping of Datastore
- // metrics.
- Product DatastoreProduct
- // Collection is the table or group being operated upon in the datastore,
- // e.g. "users_table". This becomes the db.collection attribute on Span
- // events and Transaction Trace segments. Collection is one of the fields
- // primarily responsible for the grouping of Datastore metrics.
- Collection string
- // Operation is the relevant action, e.g. "SELECT" or "GET". Operation is
- // one of the fields primarily responsible for the grouping of Datastore
- // metrics.
- Operation string
-
- // The following fields are used for extra metrics and added to instance
- // data:
- //
- // ParameterizedQuery may be set to the query being performed. It must
- // not contain any raw parameters, only placeholders.
- ParameterizedQuery string
- // QueryParameters may be used to provide query parameters. Care should
- // be taken to only provide parameters which are not sensitive.
- // QueryParameters are ignored in high security mode. The keys must contain
- // fewer than than 255 bytes. The values must be numbers, strings, or
- // booleans.
- QueryParameters map[string]interface{}
- // Host is the name of the server hosting the datastore.
- Host string
- // PortPathOrID can represent either the port, path, or id of the
- // datastore being connected to.
- PortPathOrID string
- // DatabaseName is name of database instance where the current query is
- // being executed. This becomes the db.instance attribute on Span events
- // and Transaction Trace segments.
- DatabaseName string
-}
-
-// ExternalSegment instruments external calls. StartExternalSegment is the
-// recommended way to create ExternalSegments.
-type ExternalSegment struct {
- StartTime SegmentStartTime
- Request *http.Request
- Response *http.Response
-
- // URL is an optional field which can be populated in lieu of Request if
- // you don't have an http.Request. Either URL or Request must be
- // populated. If both are populated then Request information takes
- // priority. URL is parsed using url.Parse so it must include the
- // protocol scheme (eg. "http://").
- URL string
- // Host is an optional field that is automatically populated from the
- // Request or URL. It is used for external metrics, transaction trace
- // segment names, and span event names. Use this field to override the
- // host in the URL or Request. This field does not override the host in
- // the "http.url" attribute.
- Host string
- // Procedure is an optional field that can be set to the remote
- // procedure being called. If set, this value will be used in metrics,
- // transaction trace segment names, and span event names. If unset, the
- // request's http method is used.
- Procedure string
- // Library is an optional field that defaults to "http". It is used for
- // external metrics and the "component" span attribute. It should be
- // the framework making the external call.
- Library string
-}
-
-// End finishes the segment.
-func (s *Segment) End() error { return endSegment(s) }
-
-// End finishes the datastore segment.
-func (s *DatastoreSegment) End() error { return endDatastore(s) }
-
-// End finishes the external segment.
-func (s *ExternalSegment) End() error { return endExternal(s) }
-
-// OutboundHeaders returns the headers that should be attached to the external
-// request.
-func (s *ExternalSegment) OutboundHeaders() http.Header {
- return outboundHeaders(s)
-}
-
-// StartSegmentNow starts timing a segment. This function is recommended over
-// Transaction.StartSegmentNow() because it is nil safe.
-func StartSegmentNow(txn Transaction) SegmentStartTime {
- if nil != txn {
- return txn.StartSegmentNow()
- }
- return SegmentStartTime{}
-}
-
-// StartSegment makes it easy to instrument segments. To time a function, do
-// the following:
-//
-// func timeMe(txn newrelic.Transaction) {
-// defer newrelic.StartSegment(txn, "timeMe").End()
-// // ... function code here ...
-// }
-//
-// To time a block of code, do the following:
-//
-// segment := StartSegment(txn, "myBlock")
-// // ... code you want to time here ...
-// segment.End()
-//
-func StartSegment(txn Transaction, name string) *Segment {
- return &Segment{
- StartTime: StartSegmentNow(txn),
- Name: name,
- }
-}
-
-// StartExternalSegment starts the instrumentation of an external call and adds
-// distributed tracing headers to the request. If the Transaction parameter is
-// nil then StartExternalSegment will look for a Transaction in the request's
-// context using FromContext.
-//
-// Using the same http.Client for all of your external requests? Check out
-// NewRoundTripper: You may not need to use StartExternalSegment at all!
-//
-func StartExternalSegment(txn Transaction, request *http.Request) *ExternalSegment {
- if nil == txn {
- txn = transactionFromRequestContext(request)
- }
- s := &ExternalSegment{
- StartTime: StartSegmentNow(txn),
- Request: request,
- }
-
- if request != nil && request.Header != nil {
- for key, values := range s.OutboundHeaders() {
- for _, value := range values {
- request.Header.Add(key, value)
- }
- }
- }
-
- return s
-}
diff --git a/vendor/github.com/newrelic/go-agent/sql_driver.go b/vendor/github.com/newrelic/go-agent/sql_driver.go
deleted file mode 100644
index 6a0312bb829..00000000000
--- a/vendor/github.com/newrelic/go-agent/sql_driver.go
+++ /dev/null
@@ -1,268 +0,0 @@
-// +build go1.10
-
-package newrelic
-
-import (
- "context"
- "database/sql/driver"
-)
-
-// SQLDriverSegmentBuilder populates DatastoreSegments for sql.Driver
-// instrumentation. Use this to instrument a database that is not supported by
-// an existing integration package (nrmysql, nrpq, and nrsqlite3). See
-// https://github.com/newrelic/go-agent/blob/master/_integrations/nrmysql/nrmysql.go
-// for example use.
-type SQLDriverSegmentBuilder struct {
- BaseSegment DatastoreSegment
- ParseQuery func(segment *DatastoreSegment, query string)
- ParseDSN func(segment *DatastoreSegment, dataSourceName string)
-}
-
-// InstrumentSQLDriver wraps a driver.Driver, adding instrumentation for exec
-// and query calls made with a transaction-containing context. Use this to
-// instrument a database driver that is not supported by an existing integration
-// package (nrmysql, nrpq, and nrsqlite3). See
-// https://github.com/newrelic/go-agent/blob/master/_integrations/nrmysql/nrmysql.go
-// for example use.
-func InstrumentSQLDriver(d driver.Driver, bld SQLDriverSegmentBuilder) driver.Driver {
- return optionalMethodsDriver(&wrapDriver{bld: bld, original: d})
-}
-
-// InstrumentSQLConnector wraps a driver.Connector, adding instrumentation for
-// exec and query calls made with a transaction-containing context. Use this to
-// instrument a database connector that is not supported by an existing
-// integration package (nrmysql, nrpq, and nrsqlite3). See
-// https://github.com/newrelic/go-agent/blob/master/_integrations/nrmysql/nrmysql.go
-// for example use.
-func InstrumentSQLConnector(connector driver.Connector, bld SQLDriverSegmentBuilder) driver.Connector {
- return &wrapConnector{original: connector, bld: bld}
-}
-
-func (bld SQLDriverSegmentBuilder) useDSN(dsn string) SQLDriverSegmentBuilder {
- if f := bld.ParseDSN; nil != f {
- f(&bld.BaseSegment, dsn)
- }
- return bld
-}
-
-func (bld SQLDriverSegmentBuilder) useQuery(query string) SQLDriverSegmentBuilder {
- if f := bld.ParseQuery; nil != f {
- f(&bld.BaseSegment, query)
- }
- return bld
-}
-
-func (bld SQLDriverSegmentBuilder) startSegment(ctx context.Context) DatastoreSegment {
- segment := bld.BaseSegment
- segment.StartTime = StartSegmentNow(FromContext(ctx))
- return segment
-}
-
-type wrapDriver struct {
- bld SQLDriverSegmentBuilder
- original driver.Driver
-}
-
-type wrapConnector struct {
- bld SQLDriverSegmentBuilder
- original driver.Connector
-}
-
-type wrapConn struct {
- bld SQLDriverSegmentBuilder
- original driver.Conn
-}
-
-type wrapStmt struct {
- bld SQLDriverSegmentBuilder
- original driver.Stmt
-}
-
-func (w *wrapDriver) Open(name string) (driver.Conn, error) {
- original, err := w.original.Open(name)
- if err != nil {
- return nil, err
- }
- return optionalMethodsConn(&wrapConn{
- original: original,
- bld: w.bld.useDSN(name),
- }), nil
-}
-
-// OpenConnector implements DriverContext.
-func (w *wrapDriver) OpenConnector(name string) (driver.Connector, error) {
- original, err := w.original.(driver.DriverContext).OpenConnector(name)
- if err != nil {
- return nil, err
- }
- return &wrapConnector{
- original: original,
- bld: w.bld.useDSN(name),
- }, nil
-}
-
-func (w *wrapConnector) Connect(ctx context.Context) (driver.Conn, error) {
- original, err := w.original.Connect(ctx)
- if nil != err {
- return nil, err
- }
- return optionalMethodsConn(&wrapConn{
- bld: w.bld,
- original: original,
- }), nil
-}
-
-func (w *wrapConnector) Driver() driver.Driver {
- return optionalMethodsDriver(&wrapDriver{
- bld: w.bld,
- original: w.original.Driver(),
- })
-}
-
-func prepare(original driver.Stmt, err error, bld SQLDriverSegmentBuilder, query string) (driver.Stmt, error) {
- if nil != err {
- return nil, err
- }
- return optionalMethodsStmt(&wrapStmt{
- bld: bld.useQuery(query),
- original: original,
- }), nil
-}
-
-func (w *wrapConn) Prepare(query string) (driver.Stmt, error) {
- original, err := w.original.Prepare(query)
- return prepare(original, err, w.bld, query)
-}
-
-// PrepareContext implements ConnPrepareContext.
-func (w *wrapConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
- original, err := w.original.(driver.ConnPrepareContext).PrepareContext(ctx, query)
- return prepare(original, err, w.bld, query)
-}
-
-func (w *wrapConn) Close() error {
- return w.original.Close()
-}
-
-func (w *wrapConn) Begin() (driver.Tx, error) {
- return w.original.Begin()
-}
-
-// BeginTx implements ConnBeginTx.
-func (w *wrapConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
- return w.original.(driver.ConnBeginTx).BeginTx(ctx, opts)
-}
-
-// Exec implements Execer.
-func (w *wrapConn) Exec(query string, args []driver.Value) (driver.Result, error) {
- return w.original.(driver.Execer).Exec(query, args)
-}
-
-// ExecContext implements ExecerContext.
-func (w *wrapConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
- segment := w.bld.useQuery(query).startSegment(ctx)
- result, err := w.original.(driver.ExecerContext).ExecContext(ctx, query, args)
- if err != driver.ErrSkip {
- segment.End()
- }
- return result, err
-}
-
-// CheckNamedValue implements NamedValueChecker.
-func (w *wrapConn) CheckNamedValue(v *driver.NamedValue) error {
- return w.original.(driver.NamedValueChecker).CheckNamedValue(v)
-}
-
-// Ping implements Pinger.
-func (w *wrapConn) Ping(ctx context.Context) error {
- return w.original.(driver.Pinger).Ping(ctx)
-}
-
-func (w *wrapConn) Query(query string, args []driver.Value) (driver.Rows, error) {
- return w.original.(driver.Queryer).Query(query, args)
-}
-
-// QueryContext implements QueryerContext.
-func (w *wrapConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
- segment := w.bld.useQuery(query).startSegment(ctx)
- rows, err := w.original.(driver.QueryerContext).QueryContext(ctx, query, args)
- if err != driver.ErrSkip {
- segment.End()
- }
- return rows, err
-}
-
-// ResetSession implements SessionResetter.
-func (w *wrapConn) ResetSession(ctx context.Context) error {
- return w.original.(driver.SessionResetter).ResetSession(ctx)
-}
-
-func (w *wrapStmt) Close() error {
- return w.original.Close()
-}
-
-func (w *wrapStmt) NumInput() int {
- return w.original.NumInput()
-}
-
-func (w *wrapStmt) Exec(args []driver.Value) (driver.Result, error) {
- return w.original.Exec(args)
-}
-
-func (w *wrapStmt) Query(args []driver.Value) (driver.Rows, error) {
- return w.original.Query(args)
-}
-
-// ColumnConverter implements ColumnConverter.
-func (w *wrapStmt) ColumnConverter(idx int) driver.ValueConverter {
- return w.original.(driver.ColumnConverter).ColumnConverter(idx)
-}
-
-// CheckNamedValue implements NamedValueChecker.
-func (w *wrapStmt) CheckNamedValue(v *driver.NamedValue) error {
- return w.original.(driver.NamedValueChecker).CheckNamedValue(v)
-}
-
-// ExecContext implements StmtExecContext.
-func (w *wrapStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
- segment := w.bld.startSegment(ctx)
- result, err := w.original.(driver.StmtExecContext).ExecContext(ctx, args)
- segment.End()
- return result, err
-}
-
-// QueryContext implements StmtQueryContext.
-func (w *wrapStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
- segment := w.bld.startSegment(ctx)
- rows, err := w.original.(driver.StmtQueryContext).QueryContext(ctx, args)
- segment.End()
- return rows, err
-}
-
-var (
- _ interface {
- driver.Driver
- driver.DriverContext
- } = &wrapDriver{}
- _ interface {
- driver.Connector
- } = &wrapConnector{}
- _ interface {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- } = &wrapConn{}
- _ interface {
- driver.Stmt
- driver.ColumnConverter
- driver.NamedValueChecker
- driver.StmtExecContext
- driver.StmtQueryContext
- } = &wrapStmt{}
-)
diff --git a/vendor/github.com/newrelic/go-agent/sql_driver_optional_methods.go b/vendor/github.com/newrelic/go-agent/sql_driver_optional_methods.go
deleted file mode 100644
index 6663835a96f..00000000000
--- a/vendor/github.com/newrelic/go-agent/sql_driver_optional_methods.go
+++ /dev/null
@@ -1,2240 +0,0 @@
-// +build go1.10
-
-package newrelic
-
-import "database/sql/driver"
-
-func optionalMethodsDriver(dv *wrapDriver) driver.Driver {
- // GENERATED CODE DO NOT MODIFY
- // This code generated by internal/tools/interface-wrapping
- var (
- i0 int32 = 1 << 0
- )
- var interfaceSet int32
- if _, ok := dv.original.(driver.DriverContext); ok {
- interfaceSet |= i0
- }
- switch interfaceSet {
- default: // No optional interfaces implemented
- return struct {
- driver.Driver
- }{dv}
- case i0:
- return struct {
- driver.Driver
- driver.DriverContext
- }{dv, dv}
- }
-}
-
-func optionalMethodsStmt(stmt *wrapStmt) driver.Stmt {
- // GENERATED CODE DO NOT MODIFY
- // This code generated by internal/tools/interface-wrapping
- var (
- i0 int32 = 1 << 0
- i1 int32 = 1 << 1
- i2 int32 = 1 << 2
- i3 int32 = 1 << 3
- )
- var interfaceSet int32
- if _, ok := stmt.original.(driver.ColumnConverter); ok {
- interfaceSet |= i0
- }
- if _, ok := stmt.original.(driver.NamedValueChecker); ok {
- interfaceSet |= i1
- }
- if _, ok := stmt.original.(driver.StmtExecContext); ok {
- interfaceSet |= i2
- }
- if _, ok := stmt.original.(driver.StmtQueryContext); ok {
- interfaceSet |= i3
- }
- switch interfaceSet {
- default: // No optional interfaces implemented
- return struct {
- driver.Stmt
- }{stmt}
- case i0:
- return struct {
- driver.Stmt
- driver.ColumnConverter
- }{stmt, stmt}
- case i1:
- return struct {
- driver.Stmt
- driver.NamedValueChecker
- }{stmt, stmt}
- case i0 | i1:
- return struct {
- driver.Stmt
- driver.ColumnConverter
- driver.NamedValueChecker
- }{stmt, stmt, stmt}
- case i2:
- return struct {
- driver.Stmt
- driver.StmtExecContext
- }{stmt, stmt}
- case i0 | i2:
- return struct {
- driver.Stmt
- driver.ColumnConverter
- driver.StmtExecContext
- }{stmt, stmt, stmt}
- case i1 | i2:
- return struct {
- driver.Stmt
- driver.NamedValueChecker
- driver.StmtExecContext
- }{stmt, stmt, stmt}
- case i0 | i1 | i2:
- return struct {
- driver.Stmt
- driver.ColumnConverter
- driver.NamedValueChecker
- driver.StmtExecContext
- }{stmt, stmt, stmt, stmt}
- case i3:
- return struct {
- driver.Stmt
- driver.StmtQueryContext
- }{stmt, stmt}
- case i0 | i3:
- return struct {
- driver.Stmt
- driver.ColumnConverter
- driver.StmtQueryContext
- }{stmt, stmt, stmt}
- case i1 | i3:
- return struct {
- driver.Stmt
- driver.NamedValueChecker
- driver.StmtQueryContext
- }{stmt, stmt, stmt}
- case i0 | i1 | i3:
- return struct {
- driver.Stmt
- driver.ColumnConverter
- driver.NamedValueChecker
- driver.StmtQueryContext
- }{stmt, stmt, stmt, stmt}
- case i2 | i3:
- return struct {
- driver.Stmt
- driver.StmtExecContext
- driver.StmtQueryContext
- }{stmt, stmt, stmt}
- case i0 | i2 | i3:
- return struct {
- driver.Stmt
- driver.ColumnConverter
- driver.StmtExecContext
- driver.StmtQueryContext
- }{stmt, stmt, stmt, stmt}
- case i1 | i2 | i3:
- return struct {
- driver.Stmt
- driver.NamedValueChecker
- driver.StmtExecContext
- driver.StmtQueryContext
- }{stmt, stmt, stmt, stmt}
- case i0 | i1 | i2 | i3:
- return struct {
- driver.Stmt
- driver.ColumnConverter
- driver.NamedValueChecker
- driver.StmtExecContext
- driver.StmtQueryContext
- }{stmt, stmt, stmt, stmt, stmt}
- }
-}
-
-func optionalMethodsConn(conn *wrapConn) driver.Conn {
- // GENERATED CODE DO NOT MODIFY
- // This code generated by internal/tools/interface-wrapping
- var (
- i0 int32 = 1 << 0
- i1 int32 = 1 << 1
- i2 int32 = 1 << 2
- i3 int32 = 1 << 3
- i4 int32 = 1 << 4
- i5 int32 = 1 << 5
- i6 int32 = 1 << 6
- i7 int32 = 1 << 7
- )
- var interfaceSet int32
- if _, ok := conn.original.(driver.ConnBeginTx); ok {
- interfaceSet |= i0
- }
- if _, ok := conn.original.(driver.ConnPrepareContext); ok {
- interfaceSet |= i1
- }
- if _, ok := conn.original.(driver.Execer); ok {
- interfaceSet |= i2
- }
- if _, ok := conn.original.(driver.ExecerContext); ok {
- interfaceSet |= i3
- }
- if _, ok := conn.original.(driver.NamedValueChecker); ok {
- interfaceSet |= i4
- }
- if _, ok := conn.original.(driver.Pinger); ok {
- interfaceSet |= i5
- }
- if _, ok := conn.original.(driver.Queryer); ok {
- interfaceSet |= i6
- }
- if _, ok := conn.original.(driver.QueryerContext); ok {
- interfaceSet |= i7
- }
- switch interfaceSet {
- default: // No optional interfaces implemented
- return struct {
- driver.Conn
- }{conn}
- case i0:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- }{conn, conn}
- case i1:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- }{conn, conn}
- case i0 | i1:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- }{conn, conn, conn}
- case i2:
- return struct {
- driver.Conn
- driver.Execer
- }{conn, conn}
- case i0 | i2:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- }{conn, conn, conn}
- case i1 | i2:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- }{conn, conn, conn}
- case i0 | i1 | i2:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- }{conn, conn, conn, conn}
- case i3:
- return struct {
- driver.Conn
- driver.ExecerContext
- }{conn, conn}
- case i0 | i3:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- }{conn, conn, conn}
- case i1 | i3:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- }{conn, conn, conn}
- case i0 | i1 | i3:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- }{conn, conn, conn, conn}
- case i2 | i3:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- }{conn, conn, conn}
- case i0 | i2 | i3:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- }{conn, conn, conn, conn}
- case i1 | i2 | i3:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- }{conn, conn, conn, conn}
- case i0 | i1 | i2 | i3:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- }{conn, conn, conn, conn, conn}
- case i4:
- return struct {
- driver.Conn
- driver.NamedValueChecker
- }{conn, conn}
- case i0 | i4:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.NamedValueChecker
- }{conn, conn, conn}
- case i1 | i4:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.NamedValueChecker
- }{conn, conn, conn}
- case i0 | i1 | i4:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.NamedValueChecker
- }{conn, conn, conn, conn}
- case i2 | i4:
- return struct {
- driver.Conn
- driver.Execer
- driver.NamedValueChecker
- }{conn, conn, conn}
- case i0 | i2 | i4:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.NamedValueChecker
- }{conn, conn, conn, conn}
- case i1 | i2 | i4:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- }{conn, conn, conn, conn}
- case i0 | i1 | i2 | i4:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- }{conn, conn, conn, conn, conn}
- case i3 | i4:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.NamedValueChecker
- }{conn, conn, conn}
- case i0 | i3 | i4:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.NamedValueChecker
- }{conn, conn, conn, conn}
- case i1 | i3 | i4:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- }{conn, conn, conn, conn}
- case i0 | i1 | i3 | i4:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- }{conn, conn, conn, conn, conn}
- case i2 | i3 | i4:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- }{conn, conn, conn, conn}
- case i0 | i2 | i3 | i4:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i4:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i4:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- }{conn, conn, conn, conn, conn, conn}
- case i5:
- return struct {
- driver.Conn
- driver.Pinger
- }{conn, conn}
- case i0 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Pinger
- }{conn, conn, conn}
- case i1 | i5:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Pinger
- }{conn, conn, conn}
- case i0 | i1 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Pinger
- }{conn, conn, conn, conn}
- case i2 | i5:
- return struct {
- driver.Conn
- driver.Execer
- driver.Pinger
- }{conn, conn, conn}
- case i0 | i2 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.Pinger
- }{conn, conn, conn, conn}
- case i1 | i2 | i5:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.Pinger
- }{conn, conn, conn, conn}
- case i0 | i1 | i2 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i3 | i5:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.Pinger
- }{conn, conn, conn}
- case i0 | i3 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.Pinger
- }{conn, conn, conn, conn}
- case i1 | i3 | i5:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Pinger
- }{conn, conn, conn, conn}
- case i0 | i1 | i3 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i2 | i3 | i5:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- }{conn, conn, conn, conn}
- case i0 | i2 | i3 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i5:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- }{conn, conn, conn, conn, conn, conn}
- case i4 | i5:
- return struct {
- driver.Conn
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn}
- case i0 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn}
- case i1 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn}
- case i0 | i1 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i2 | i4 | i5:
- return struct {
- driver.Conn
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn}
- case i0 | i2 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn, conn}
- case i3 | i4 | i5:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn}
- case i0 | i3 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i1 | i3 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i4 | i5:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i4 | i5:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- }{conn, conn, conn, conn, conn, conn, conn}
- case i6:
- return struct {
- driver.Conn
- driver.Queryer
- }{conn, conn}
- case i0 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Queryer
- }{conn, conn, conn}
- case i1 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Queryer
- }{conn, conn, conn}
- case i0 | i1 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Queryer
- }{conn, conn, conn, conn}
- case i2 | i6:
- return struct {
- driver.Conn
- driver.Execer
- driver.Queryer
- }{conn, conn, conn}
- case i0 | i2 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.Queryer
- }{conn, conn, conn, conn}
- case i1 | i2 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i1 | i2 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i3 | i6:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.Queryer
- }{conn, conn, conn}
- case i0 | i3 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.Queryer
- }{conn, conn, conn, conn}
- case i1 | i3 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i1 | i3 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i2 | i3 | i6:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i2 | i3 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i4 | i6:
- return struct {
- driver.Conn
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn}
- case i0 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn}
- case i1 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i1 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i2 | i4 | i6:
- return struct {
- driver.Conn
- driver.Execer
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i2 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i3 | i4 | i6:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i3 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i1 | i3 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i4 | i6:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i4 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn, conn}
- case i5 | i6:
- return struct {
- driver.Conn
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn}
- case i0 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn}
- case i1 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i1 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i2 | i5 | i6:
- return struct {
- driver.Conn
- driver.Execer
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i2 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i3 | i5 | i6:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i3 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i1 | i3 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i5 | i6:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn, conn}
- case i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn}
- case i0 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i1 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn, conn}
- case i3 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn}
- case i0 | i3 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i3 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i4 | i5 | i6:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- }{conn, conn, conn, conn, conn, conn, conn, conn}
- case i7:
- return struct {
- driver.Conn
- driver.QueryerContext
- }{conn, conn}
- case i0 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.QueryerContext
- }{conn, conn, conn}
- case i1 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.QueryerContext
- }{conn, conn, conn}
- case i0 | i1 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i2 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.QueryerContext
- }{conn, conn, conn}
- case i0 | i2 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i1 | i2 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i1 | i2 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i3 | i7:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.QueryerContext
- }{conn, conn, conn}
- case i0 | i3 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i1 | i3 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i1 | i3 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i2 | i3 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i2 | i3 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i4 | i7:
- return struct {
- driver.Conn
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn}
- case i0 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i1 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i1 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i2 | i4 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i2 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i3 | i4 | i7:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i3 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i3 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i4 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i4 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i5 | i7:
- return struct {
- driver.Conn
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn}
- case i0 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i1 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i1 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i2 | i5 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i2 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i3 | i5 | i7:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i3 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i3 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i5 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i3 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i3 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i3 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i4 | i5 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn, conn}
- case i6 | i7:
- return struct {
- driver.Conn
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn}
- case i0 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i1 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i1 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i2 | i6 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i2 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i2 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i3 | i6 | i7:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i3 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i3 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i6 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i3 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i3 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i3 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i4 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn, conn}
- case i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn}
- case i0 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i1 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i1 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i2 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i2 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i3 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i3 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i3 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn, conn}
- case i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn}
- case i0 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i1 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i2 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i2 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn, conn}
- case i3 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn}
- case i0 | i3 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i1 | i3 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i3 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn, conn}
- case i2 | i3 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn}
- case i0 | i2 | i3 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn, conn}
- case i1 | i2 | i3 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn, conn}
- case i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7:
- return struct {
- driver.Conn
- driver.ConnBeginTx
- driver.ConnPrepareContext
- driver.Execer
- driver.ExecerContext
- driver.NamedValueChecker
- driver.Pinger
- driver.Queryer
- driver.QueryerContext
- }{conn, conn, conn, conn, conn, conn, conn, conn, conn}
- }
-}
diff --git a/vendor/github.com/newrelic/go-agent/transaction.go b/vendor/github.com/newrelic/go-agent/transaction.go
deleted file mode 100644
index 5f344cc84e0..00000000000
--- a/vendor/github.com/newrelic/go-agent/transaction.go
+++ /dev/null
@@ -1,262 +0,0 @@
-package newrelic
-
-import (
- "net/http"
- "net/url"
-)
-
-// Transaction instruments one logical unit of work: either an inbound web
-// request or background task. Start a new Transaction with the
-// Application.StartTransaction() method.
-type Transaction interface {
- // The transaction's http.ResponseWriter methods delegate to the
- // http.ResponseWriter provided as a parameter to
- // Application.StartTransaction or Transaction.SetWebResponse. This
- // allows instrumentation of the response code and response headers.
- // These methods may be called safely if the transaction does not have a
- // http.ResponseWriter.
- http.ResponseWriter
-
- // End finishes the Transaction. After that, subsequent calls to End or
- // other Transaction methods have no effect. All segments and
- // instrumentation must be completed before End is called.
- End() error
-
- // Ignore prevents this transaction's data from being recorded.
- Ignore() error
-
- // SetName names the transaction. Use a limited set of unique names to
- // ensure that Transactions are grouped usefully.
- SetName(name string) error
-
- // NoticeError records an error. The Transaction saves the first five
- // errors. For more control over the recorded error fields, see the
- // newrelic.Error type. In certain situations, using this method may
- // result in an error being recorded twice: Errors are automatically
- // recorded when Transaction.WriteHeader receives a status code above
- // 400 or below 100 that is not in the IgnoreStatusCodes configuration
- // list. This method is unaffected by the IgnoreStatusCodes
- // configuration list.
- NoticeError(err error) error
-
- // AddAttribute adds a key value pair to the transaction event, errors,
- // and traces.
- //
- // The key must contain fewer than than 255 bytes. The value must be a
- // number, string, or boolean.
- //
- // For more information, see:
- // https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-metrics/collect-custom-attributes
- AddAttribute(key string, value interface{}) error
-
- // SetWebRequest marks the transaction as a web transaction. If
- // WebRequest is non-nil, SetWebRequest will additionally collect
- // details on request attributes, url, and method. If headers are
- // present, the agent will look for a distributed tracing header. Use
- // NewWebRequest to transform a *http.Request into a WebRequest.
- SetWebRequest(WebRequest) error
-
- // SetWebResponse sets transaction's http.ResponseWriter. After calling
- // this method, the transaction may be used in place of the
- // ResponseWriter to intercept the response code. This method is useful
- // when the ResponseWriter is not available at the beginning of the
- // transaction (if so, it can be given as a parameter to
- // Application.StartTransaction). This method will return a reference
- // to the transaction which implements the combination of
- // http.CloseNotifier, http.Flusher, http.Hijacker, and io.ReaderFrom
- // implemented by the ResponseWriter.
- SetWebResponse(http.ResponseWriter) Transaction
-
- // StartSegmentNow starts timing a segment. The SegmentStartTime
- // returned can be used as the StartTime field in Segment,
- // DatastoreSegment, or ExternalSegment. We recommend using the
- // StartSegmentNow function instead of this method since it checks if
- // the Transaction is nil.
- StartSegmentNow() SegmentStartTime
-
- // CreateDistributedTracePayload creates a payload used to link
- // transactions. CreateDistributedTracePayload should be called every
- // time an outbound call is made since the payload contains a timestamp.
- //
- // StartExternalSegment calls CreateDistributedTracePayload, so you
- // don't need to use it for outbound HTTP calls: Just use
- // StartExternalSegment!
- //
- // This method never returns nil. If the application is disabled or not
- // yet connected then this method returns a shim implementation whose
- // methods return empty strings.
- CreateDistributedTracePayload() DistributedTracePayload
-
- // AcceptDistributedTracePayload links transactions by accepting a
- // distributed trace payload from another transaction.
- //
- // Application.StartTransaction calls this method automatically if a
- // payload is present in the request headers. Therefore, this method
- // does not need to be used for typical HTTP transactions.
- //
- // AcceptDistributedTracePayload should be used as early in the
- // transaction as possible. It may not be called after a call to
- // CreateDistributedTracePayload.
- //
- // The payload parameter may be a DistributedTracePayload, a string, or
- // a []byte.
- AcceptDistributedTracePayload(t TransportType, payload interface{}) error
-
- // Application returns the Application which started the transaction.
- Application() Application
-
- // BrowserTimingHeader generates the JavaScript required to enable New
- // Relic's Browser product. This code should be placed into your pages
- // as close to the top of the element as possible, but after any
- // position-sensitive tags (for example, X-UA-Compatible or
- // charset information).
- //
- // This function freezes the transaction name: any calls to SetName()
- // after BrowserTimingHeader() will be ignored.
- //
- // The *BrowserTimingHeader return value will be nil if browser
- // monitoring is disabled, the application is not connected, or an error
- // occurred. It is safe to call the pointer's methods if it is nil.
- BrowserTimingHeader() (*BrowserTimingHeader, error)
-
- // NewGoroutine allows you to use the Transaction in multiple
- // goroutines.
- //
- // Each goroutine must have its own Transaction reference returned by
- // NewGoroutine. You must call NewGoroutine to get a new Transaction
- // reference every time you wish to pass the Transaction to another
- // goroutine. It does not matter if you call this before or after the
- // other goroutine has started.
- //
- // All Transaction methods can be used in any Transaction reference.
- // The Transaction will end when End() is called in any goroutine.
- //
- // Example passing a new Transaction reference directly to another
- // goroutine:
- //
- // go func(txn newrelic.Transaction) {
- // defer newrelic.StartSegment(txn, "async").End()
- // time.Sleep(100 * time.Millisecond)
- // }(txn.NewGoroutine())
- //
- // Example passing a new Transaction reference on a channel to another
- // goroutine:
- //
- // ch := make(chan newrelic.Transaction)
- // go func() {
- // txn := <-ch
- // defer newrelic.StartSegment(txn, "async").End()
- // time.Sleep(100 * time.Millisecond)
- // }()
- // ch <- txn.NewGoroutine()
- //
- NewGoroutine() Transaction
-
- // GetTraceMetadata returns distributed tracing identifiers. Empty
- // string identifiers are returned if the transaction has finished.
- GetTraceMetadata() TraceMetadata
-
- // GetLinkingMetadata returns the fields needed to link data to a trace or
- // entity.
- GetLinkingMetadata() LinkingMetadata
-}
-
-// DistributedTracePayload traces requests between applications or processes.
-// DistributedTracePayloads are automatically added to HTTP requests by
-// StartExternalSegment, so you only need to use this if you are tracing through
-// a message queue or another non-HTTP communication library. The
-// DistributedTracePayload may be marshalled in one of two formats: HTTPSafe or
-// Text. All New Relic agents can accept payloads in either format.
-type DistributedTracePayload interface {
- // HTTPSafe serializes the payload into a string containing http safe
- // characters.
- HTTPSafe() string
- // Text serializes the payload into a string. The format is slightly
- // more compact than HTTPSafe.
- Text() string
-}
-
-const (
- // DistributedTracePayloadHeader is the header used by New Relic agents
- // for automatic trace payload instrumentation.
- DistributedTracePayloadHeader = "Newrelic"
-)
-
-// TransportType is used in Transaction.AcceptDistributedTracePayload() to
-// represent the type of connection that the trace payload was transported over.
-type TransportType struct{ name string }
-
-// TransportType names used across New Relic agents:
-var (
- TransportUnknown = TransportType{name: "Unknown"}
- TransportHTTP = TransportType{name: "HTTP"}
- TransportHTTPS = TransportType{name: "HTTPS"}
- TransportKafka = TransportType{name: "Kafka"}
- TransportJMS = TransportType{name: "JMS"}
- TransportIronMQ = TransportType{name: "IronMQ"}
- TransportAMQP = TransportType{name: "AMQP"}
- TransportQueue = TransportType{name: "Queue"}
- TransportOther = TransportType{name: "Other"}
-)
-
-// WebRequest may be implemented to provide request information to
-// Transaction.SetWebRequest.
-type WebRequest interface {
- // Header may return nil if you don't have any headers or don't want to
- // transform them to http.Header format.
- Header() http.Header
- // URL may return nil if you don't have a URL or don't want to transform
- // it to *url.URL.
- URL() *url.URL
- Method() string
- // If a distributed tracing header is found in the headers returned by
- // Header(), this TransportType will be used in the distributed tracing
- // metrics.
- Transport() TransportType
-}
-
-// NewWebRequest turns a *http.Request into a WebRequest for input into
-// Transaction.SetWebRequest.
-func NewWebRequest(request *http.Request) WebRequest {
- if nil == request {
- return nil
- }
- return requestWrap{request: request}
-}
-
-// NewStaticWebRequest takes the minimum necessary information and creates a static WebRequest out of it
-func NewStaticWebRequest(hdrs http.Header, url *url.URL, method string, transport TransportType) WebRequest {
- return staticWebRequest{hdrs, url, method, transport}
-}
-
-// LinkingMetadata is returned by Transaction.GetLinkingMetadata. It contains
-// identifiers needed link data to a trace or entity.
-type LinkingMetadata struct {
- // TraceID identifies the entire distributed trace. This field is empty
- // if distributed tracing is disabled.
- TraceID string
- // SpanID identifies the currently active segment. This field is empty
- // if distributed tracing is disabled or the transaction is not sampled.
- SpanID string
- // EntityName is the Application name as set on the newrelic.Config. If
- // multiple application names are specified, only the first is returned.
- EntityName string
- // EntityType is the type of this entity and is always the string
- // "SERVICE".
- EntityType string
- // EntityGUID is the unique identifier for this entity.
- EntityGUID string
- // Hostname is the hostname this entity is running on.
- Hostname string
-}
-
-// TraceMetadata is returned by Transaction.GetTraceMetadata. It contains
-// distributed tracing identifiers.
-type TraceMetadata struct {
- // TraceID identifies the entire distributed trace. This field is empty
- // if distributed tracing is disabled.
- TraceID string
- // SpanID identifies the currently active segment. This field is empty
- // if distributed tracing is disabled or the transaction is not sampled.
- SpanID string
-}
diff --git a/vendor/github.com/newrelic/go-agent/version.go b/vendor/github.com/newrelic/go-agent/version.go
deleted file mode 100644
index ab5d20dd68d..00000000000
--- a/vendor/github.com/newrelic/go-agent/version.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package newrelic
-
-import "github.com/newrelic/go-agent/internal"
-
-const (
- major = "2"
- minor = "13"
- patch = "0"
-
- // Version is the full string version of this Go Agent.
- Version = major + "." + minor + "." + patch
-)
-
-func init() { internal.TrackUsage("Go", "Version", Version) }
diff --git a/vendor/github.com/opentracing/opentracing-go/.gitignore b/vendor/github.com/opentracing/opentracing-go/.gitignore
deleted file mode 100644
index c57100a595c..00000000000
--- a/vendor/github.com/opentracing/opentracing-go/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-coverage.txt
diff --git a/vendor/github.com/opentracing/opentracing-go/.travis.yml b/vendor/github.com/opentracing/opentracing-go/.travis.yml
deleted file mode 100644
index 8d5b75e41e7..00000000000
--- a/vendor/github.com/opentracing/opentracing-go/.travis.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-language: go
-
-matrix:
- include:
- - go: "1.11.x"
- - go: "1.12.x"
- - go: "tip"
- env:
- - LINT=true
- - COVERAGE=true
-
-install:
- - if [ "$LINT" == true ]; then go get -u golang.org/x/lint/golint/... ; else echo 'skipping lint'; fi
- - go get -u github.com/stretchr/testify/...
-
-script:
- - make test
- - go build ./...
- - if [ "$LINT" == true ]; then make lint ; else echo 'skipping lint'; fi
- - if [ "$COVERAGE" == true ]; then make cover && bash <(curl -s https://codecov.io/bash) ; else echo 'skipping coverage'; fi
diff --git a/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md b/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md
deleted file mode 100644
index 7c14febe109..00000000000
--- a/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md
+++ /dev/null
@@ -1,46 +0,0 @@
-Changes by Version
-==================
-
-1.1.0 (2019-03-23)
--------------------
-
-Notable changes:
-- The library is now released under Apache 2.0 license
-- Use Set() instead of Add() in HTTPHeadersCarrier is functionally a breaking change (fixes issue [#159](https://github.com/opentracing/opentracing-go/issues/159))
-- 'golang.org/x/net/context' is replaced with 'context' from the standard library
-
-List of all changes:
-
-- Export StartSpanFromContextWithTracer (#214)
-- Add IsGlobalTracerRegistered() to indicate if a tracer has been registered (#201)
-- Use Set() instead of Add() in HTTPHeadersCarrier (#191)
-- Update license to Apache 2.0 (#181)
-- Replace 'golang.org/x/net/context' with 'context' (#176)
-- Port of Python opentracing/harness/api_check.py to Go (#146)
-- Fix race condition in MockSpan.Context() (#170)
-- Add PeerHostIPv4.SetString() (#155)
-- Add a Noop log field type to log to allow for optional fields (#150)
-
-
-1.0.2 (2017-04-26)
--------------------
-
-- Add more semantic tags (#139)
-
-
-1.0.1 (2017-02-06)
--------------------
-
-- Correct spelling in comments
-- Address race in nextMockID() (#123)
-- log: avoid panic marshaling nil error (#131)
-- Deprecate InitGlobalTracer in favor of SetGlobalTracer (#128)
-- Drop Go 1.5 that fails in Travis (#129)