diff --git a/Package.swift b/Package.swift index e8c8886c..91243440 100644 --- a/Package.swift +++ b/Package.swift @@ -23,7 +23,6 @@ let package = Package( url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.3.0") ), - .package(url: "https://github.com/apple/swift-nio.git", from: "2.34.0"), .package( url: "https://github.com/swiftwasm/WasmTransformer", .upToNextMinor(from: "0.5.0") @@ -44,12 +43,6 @@ let package = Package( ), .executableTarget( name: "carton-frontend", - dependencies: [ - "CartonFrontend" - ] - ), - .executableTarget( - name: "carton-frontend-slim", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "CartonHelpers", @@ -64,7 +57,7 @@ let package = Package( description: "Produces an optimized app bundle for distribution." ) ), - dependencies: ["carton-frontend-slim"], + dependencies: ["carton-frontend"], exclude: [ "CartonCore/README.md", "CartonPluginShared/README.md", @@ -78,7 +71,7 @@ let package = Package( description: "Run the tests in a WASI environment." ) ), - dependencies: ["carton-frontend-slim"], + dependencies: ["carton-frontend"], exclude: [ "CartonCore/README.md", "CartonPluginShared/README.md", @@ -99,27 +92,6 @@ let package = Package( ] ), .executableTarget(name: "carton-plugin-helper"), - .target( - name: "CartonFrontend", - dependencies: [ - "CartonKit" - ] - ), - .target( - name: "CartonKit", - dependencies: [ - .product(name: "NIOWebSocket", package: "swift-nio"), - .product(name: "NIOHTTP1", package: "swift-nio"), - .product(name: "NIO", package: "swift-nio"), - .product(name: "ArgumentParser", package: "swift-argument-parser"), - "CartonHelpers", - "WasmTransformer", - ], - exclude: ["Utilities/README.md"], - swiftSettings: [ - .enableUpcomingFeature("BareSlashRegexLiterals") - ] - ), .target( name: "SwiftToolchain", dependencies: [ @@ -151,13 +123,6 @@ let package = Package( name: "CartonCore", exclude: ["README.md"] ), - .target( - name: "WebDriver", - dependencies: [ - .product(name: "NIO", package: "swift-nio"), - "CartonHelpers", - ] - ), // This target is used only for release automation tasks and // should not be installed by `carton` users. .executableTarget( @@ -171,7 +136,7 @@ let package = Package( .testTarget( name: "CartonTests", dependencies: [ - "CartonFrontend", + "carton", "CartonHelpers", .product(name: "ArgumentParser", package: "swift-argument-parser"), ] @@ -179,12 +144,10 @@ let package = Package( .testTarget( name: "CartonCommandTests", dependencies: [ - "CartonFrontend", "SwiftToolchain", - "WebDriver", + "CartonHelpers", .product(name: "ArgumentParser", package: "swift-argument-parser"), ] ), - .testTarget(name: "WebDriverTests", dependencies: ["WebDriver"]), ] ) diff --git a/Plugins/CartonBundlePlugin/CartonBundlePluginCommand.swift b/Plugins/CartonBundlePlugin/CartonBundlePluginCommand.swift index 44fe2ecb..2984cd1b 100644 --- a/Plugins/CartonBundlePlugin/CartonBundlePluginCommand.swift +++ b/Plugins/CartonBundlePlugin/CartonBundlePluginCommand.swift @@ -33,7 +33,7 @@ struct CartonBundlePluginCommand: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) async throws { try checkSwiftVersion() - try checkHelpFlag(arguments, frontend: "carton-frontend-slim", subcommand: "bundle", context: context) + try checkHelpFlag(arguments, subcommand: "bundle", context: context) var extractor = ArgumentExtractor(arguments) let options = Options.parse(from: &extractor) @@ -86,7 +86,6 @@ struct CartonBundlePluginCommand: CommandPlugin { } + extractor.remainingArguments let frontend = try makeCartonFrontendProcess( context: context, - frontend: "carton-frontend-slim", arguments: frontendArguments ) try frontend.checkRun(printsLoadingMessage: false, forwardExit: true) diff --git a/Plugins/CartonDevPlugin/CartonDevPluginCommand.swift b/Plugins/CartonDevPlugin/CartonDevPluginCommand.swift index b21bca6b..23a16898 100644 --- a/Plugins/CartonDevPlugin/CartonDevPluginCommand.swift +++ b/Plugins/CartonDevPlugin/CartonDevPluginCommand.swift @@ -90,6 +90,7 @@ struct CartonDevPluginCommand: CommandPlugin { var args: [String] = [ "dev", "--main-wasm-path", productArtifact.path.string, + "--plugin-work-directory", context.pluginWorkDirectory.string, "--build-request", buildRequestPipe, "--build-response", buildResponsePipe ] @@ -100,7 +101,11 @@ struct CartonDevPluginCommand: CommandPlugin { args += extractor.remainingArguments let frontend = try makeCartonFrontendProcess(context: context, arguments: args) - frontend.forwardTerminationSignals() + let signalSources = frontend.forwardTerminationSignals() + defer { signalSources.forEach { $0.cancel() } } + frontend.terminationHandler = { _ in + frontend.forwardExit() + } try frontend.run() diff --git a/Plugins/CartonTestPlugin/CartonTestPluginCommand.swift b/Plugins/CartonTestPlugin/CartonTestPluginCommand.swift index 1d35c75f..5df8d4e1 100644 --- a/Plugins/CartonTestPlugin/CartonTestPluginCommand.swift +++ b/Plugins/CartonTestPlugin/CartonTestPluginCommand.swift @@ -38,7 +38,7 @@ struct CartonTestPluginCommand: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) async throws { try checkSwiftVersion() try checkHelpFlag( - arguments, frontend: "carton-frontend-slim", subcommand: "test", context: context) + arguments, subcommand: "test", context: context) let productName = "\(context.package.displayName)PackageTests" @@ -116,7 +116,7 @@ struct CartonTestPluginCommand: CommandPlugin { } args += extractor.remainingArguments let frontend = try makeCartonFrontendProcess( - context: context, frontend: "carton-frontend-slim", arguments: args) + context: context, arguments: args) try frontend.checkRun(printsLoadingMessage: false, forwardExit: true) } diff --git a/Sources/CartonCore/FoundationProcessEx.swift b/Sources/CartonCore/FoundationProcessEx.swift index c93147b1..b76fcf49 100644 --- a/Sources/CartonCore/FoundationProcessEx.swift +++ b/Sources/CartonCore/FoundationProcessEx.swift @@ -2,7 +2,7 @@ import Foundation extension Foundation.Process { // Monitor termination/interrruption signals to forward them to child process - public func setSignalForwarding(_ signalNo: Int32) { + public func setSignalForwarding(_ signalNo: Int32) -> DispatchSourceSignal { signal(signalNo, SIG_IGN) let signalSource = DispatchSource.makeSignalSource(signal: signalNo) signalSource.setEventHandler { [self] in @@ -10,11 +10,14 @@ extension Foundation.Process { kill(processIdentifier, signalNo) } signalSource.resume() + return signalSource } - public func forwardTerminationSignals() { - setSignalForwarding(SIGINT) - setSignalForwarding(SIGTERM) + public func forwardTerminationSignals() -> [DispatchSourceSignal] { + return [ + setSignalForwarding(SIGINT), + setSignalForwarding(SIGTERM), + ] } public var commandLine: String { @@ -44,8 +47,14 @@ extension Foundation.Process { print("Running \(try commandLine)") } + let signalSources = forwardTerminationSignals() + defer { + for signalSource in signalSources { + signalSource.cancel() + } + } + try run() - forwardTerminationSignals() waitUntilExit() if forwardExit { diff --git a/Sources/CartonFrontend/CartonFrontendCommand.swift b/Sources/CartonFrontend/CartonFrontendCommand.swift deleted file mode 100644 index 43a81b9d..00000000 --- a/Sources/CartonFrontend/CartonFrontendCommand.swift +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 Carton contributors -// -// 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. - -import ArgumentParser -import CartonCore - -public struct CartonFrontendCommand: AsyncParsableCommand { - public static let configuration = CommandConfiguration( - commandName: "carton-frontend", - abstract: "📦 Watcher, bundler, and test runner for your SwiftWasm apps.", - version: cartonVersion, - subcommands: [ - CartonFrontendDevCommand.self - ] - ) - - public init() {} -} diff --git a/Sources/CartonKit/Utilities/FSWatch.swift b/Sources/CartonHelpers/Basics/FSWatch.swift similarity index 99% rename from Sources/CartonKit/Utilities/FSWatch.swift rename to Sources/CartonHelpers/Basics/FSWatch.swift index 44c2e3f0..f8c1254e 100644 --- a/Sources/CartonKit/Utilities/FSWatch.swift +++ b/Sources/CartonHelpers/Basics/FSWatch.swift @@ -8,7 +8,6 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -import CartonHelpers import Dispatch import Foundation diff --git a/Sources/CartonHelpers/StaticArchive.swift b/Sources/CartonHelpers/StaticArchive.swift index dd89a42e..63e77cea 100644 --- a/Sources/CartonHelpers/StaticArchive.swift +++ b/Sources/CartonHelpers/StaticArchive.swift @@ -1,8 +1,8 @@ import Foundation public enum StaticResource { - public static let dev: Data = Data(base64Encoded: "Ly8gbm9kZV9tb2R1bGVzL3JlY29ubmVjdGluZy13ZWJzb2NrZXQvZGlzdC9yZWNvbm5lY3Rpbmctd2Vic29ja2V0LW1qcy5qcwp2YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHsKICBleHRlbmRTdGF0aWNzID0gT2JqZWN0LnNldFByb3RvdHlwZU9mIHx8IHsgX19wcm90b19fOiBbXSB9IGluc3RhbmNlb2YgQXJyYXkgJiYgZnVuY3Rpb24oZDIsIGIyKSB7CiAgICBkMi5fX3Byb3RvX18gPSBiMjsKICB9IHx8IGZ1bmN0aW9uKGQyLCBiMikgewogICAgZm9yICh2YXIgcCBpbiBiMikKICAgICAgaWYgKGIyLmhhc093blByb3BlcnR5KHApKQogICAgICAgIGQyW3BdID0gYjJbcF07CiAgfTsKICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTsKfTsKZnVuY3Rpb24gX19leHRlbmRzKGQsIGIpIHsKICBleHRlbmRTdGF0aWNzKGQsIGIpOwogIGZ1bmN0aW9uIF9fKCkgewogICAgdGhpcy5jb25zdHJ1Y3RvciA9IGQ7CiAgfQogIGQucHJvdG90eXBlID0gYiA9PT0gbnVsbCA/IE9iamVjdC5jcmVhdGUoYikgOiAoX18ucHJvdG90eXBlID0gYi5wcm90b3R5cGUsIG5ldyBfXygpKTsKfQpmdW5jdGlvbiBfX3ZhbHVlcyhvKSB7CiAgdmFyIG0gPSB0eXBlb2YgU3ltYm9sID09PSAiZnVuY3Rpb24iICYmIG9bU3ltYm9sLml0ZXJhdG9yXSwgaSA9IDA7CiAgaWYgKG0pCiAgICByZXR1cm4gbS5jYWxsKG8pOwogIHJldHVybiB7CiAgICBuZXh0OiBmdW5jdGlvbigpIHsKICAgICAgaWYgKG8gJiYgaSA+PSBvLmxlbmd0aCkKICAgICAgICBvID0gdm9pZCAwOwogICAgICByZXR1cm4geyB2YWx1ZTogbyAmJiBvW2krK10sIGRvbmU6ICFvIH07CiAgICB9CiAgfTsKfQpmdW5jdGlvbiBfX3JlYWQobywgbikgewogIHZhciBtID0gdHlwZW9mIFN5bWJvbCA9PT0gImZ1bmN0aW9uIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl07CiAgaWYgKCFtKQogICAgcmV0dXJuIG87CiAgdmFyIGkgPSBtLmNhbGwobyksIHIsIGFyID0gW10sIGU7CiAgdHJ5IHsKICAgIHdoaWxlICgobiA9PT0gdm9pZCAwIHx8IG4tLSA+IDApICYmICEociA9IGkubmV4dCgpKS5kb25lKQogICAgICBhci5wdXNoKHIudmFsdWUpOwogIH0gY2F0Y2ggKGVycm9yKSB7CiAgICBlID0geyBlcnJvciB9OwogIH0gZmluYWxseSB7CiAgICB0cnkgewogICAgICBpZiAociAmJiAhci5kb25lICYmIChtID0gaVsicmV0dXJuIl0pKQogICAgICAgIG0uY2FsbChpKTsKICAgIH0gZmluYWxseSB7CiAgICAgIGlmIChlKQogICAgICAgIHRocm93IGUuZXJyb3I7CiAgICB9CiAgfQogIHJldHVybiBhcjsKfQpmdW5jdGlvbiBfX3NwcmVhZCgpIHsKICBmb3IgKHZhciBhciA9IFtdLCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykKICAgIGFyID0gYXIuY29uY2F0KF9fcmVhZChhcmd1bWVudHNbaV0pKTsKICByZXR1cm4gYXI7Cn0KdmFyIEV2ZW50ID0gZnVuY3Rpb24oKSB7CiAgZnVuY3Rpb24gRXZlbnQyKHR5cGUsIHRhcmdldCkgewogICAgdGhpcy50YXJnZXQgPSB0YXJnZXQ7CiAgICB0aGlzLnR5cGUgPSB0eXBlOwogIH0KICByZXR1cm4gRXZlbnQyOwp9KCk7CnZhciBFcnJvckV2ZW50ID0gZnVuY3Rpb24oX3N1cGVyKSB7CiAgX19leHRlbmRzKEVycm9yRXZlbnQyLCBfc3VwZXIpOwogIGZ1bmN0aW9uIEVycm9yRXZlbnQyKGVycm9yLCB0YXJnZXQpIHsKICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMsICJlcnJvciIsIHRhcmdldCkgfHwgdGhpczsKICAgIF90aGlzLm1lc3NhZ2UgPSBlcnJvci5tZXNzYWdlOwogICAgX3RoaXMuZXJyb3IgPSBlcnJvcjsKICAgIHJldHVybiBfdGhpczsKICB9CiAgcmV0dXJuIEVycm9yRXZlbnQyOwp9KEV2ZW50KTsKdmFyIENsb3NlRXZlbnQgPSBmdW5jdGlvbihfc3VwZXIpIHsKICBfX2V4dGVuZHMoQ2xvc2VFdmVudDIsIF9zdXBlcik7CiAgZnVuY3Rpb24gQ2xvc2VFdmVudDIoY29kZSwgcmVhc29uLCB0YXJnZXQpIHsKICAgIGlmIChjb2RlID09PSB2b2lkIDApIHsKICAgICAgY29kZSA9IDFlMzsKICAgIH0KICAgIGlmIChyZWFzb24gPT09IHZvaWQgMCkgewogICAgICByZWFzb24gPSAiIjsKICAgIH0KICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMsICJjbG9zZSIsIHRhcmdldCkgfHwgdGhpczsKICAgIF90aGlzLndhc0NsZWFuID0gdHJ1ZTsKICAgIF90aGlzLmNvZGUgPSBjb2RlOwogICAgX3RoaXMucmVhc29uID0gcmVhc29uOwogICAgcmV0dXJuIF90aGlzOwogIH0KICByZXR1cm4gQ2xvc2VFdmVudDI7Cn0oRXZlbnQpOwp2YXIgZ2V0R2xvYmFsV2ViU29ja2V0ID0gZnVuY3Rpb24oKSB7CiAgaWYgKHR5cGVvZiBXZWJTb2NrZXQgIT09ICJ1bmRlZmluZWQiKSB7CiAgICByZXR1cm4gV2ViU29ja2V0OwogIH0KfTsKdmFyIGlzV2ViU29ja2V0ID0gZnVuY3Rpb24odykgewogIHJldHVybiB0eXBlb2YgdyAhPT0gInVuZGVmaW5lZCIgJiYgISF3ICYmIHcuQ0xPU0lORyA9PT0gMjsKfTsKdmFyIERFRkFVTFQgPSB7CiAgbWF4UmVjb25uZWN0aW9uRGVsYXk6IDFlNCwKICBtaW5SZWNvbm5lY3Rpb25EZWxheTogMWUzICsgTWF0aC5yYW5kb20oKSAqIDRlMywKICBtaW5VcHRpbWU6IDVlMywKICByZWNvbm5lY3Rpb25EZWxheUdyb3dGYWN0b3I6IDEuMywKICBjb25uZWN0aW9uVGltZW91dDogNGUzLAogIG1heFJldHJpZXM6IEluZmluaXR5LAogIG1heEVucXVldWVkTWVzc2FnZXM6IEluZmluaXR5LAogIHN0YXJ0Q2xvc2VkOiBmYWxzZSwKICBkZWJ1ZzogZmFsc2UKfTsKdmFyIFJlY29ubmVjdGluZ1dlYlNvY2tldCA9IGZ1bmN0aW9uKCkgewogIGZ1bmN0aW9uIFJlY29ubmVjdGluZ1dlYlNvY2tldDIodXJsLCBwcm90b2NvbHMsIG9wdGlvbnMpIHsKICAgIHZhciBfdGhpcyA9IHRoaXM7CiAgICBpZiAob3B0aW9ucyA9PT0gdm9pZCAwKSB7CiAgICAgIG9wdGlvbnMgPSB7fTsKICAgIH0KICAgIHRoaXMuX2xpc3RlbmVycyA9IHsKICAgICAgZXJyb3I6IFtdLAogICAgICBtZXNzYWdlOiBbXSwKICAgICAgb3BlbjogW10sCiAgICAgIGNsb3NlOiBbXQogICAgfTsKICAgIHRoaXMuX3JldHJ5Q291bnQgPSAtMTsKICAgIHRoaXMuX3Nob3VsZFJlY29ubmVjdCA9IHRydWU7CiAgICB0aGlzLl9jb25uZWN0TG9jayA9IGZhbHNlOwogICAgdGhpcy5fYmluYXJ5VHlwZSA9ICJibG9iIjsKICAgIHRoaXMuX2Nsb3NlQ2FsbGVkID0gZmFsc2U7CiAgICB0aGlzLl9tZXNzYWdlUXVldWUgPSBbXTsKICAgIHRoaXMub25jbG9zZSA9IG51bGw7CiAgICB0aGlzLm9uZXJyb3IgPSBudWxsOwogICAgdGhpcy5vbm1lc3NhZ2UgPSBudWxsOwogICAgdGhpcy5vbm9wZW4gPSBudWxsOwogICAgdGhpcy5faGFuZGxlT3BlbiA9IGZ1bmN0aW9uKGV2ZW50KSB7CiAgICAgIF90aGlzLl9kZWJ1Zygib3BlbiBldmVudCIpOwogICAgICB2YXIgX2EgPSBfdGhpcy5fb3B0aW9ucy5taW5VcHRpbWUsIG1pblVwdGltZSA9IF9hID09PSB2b2lkIDAgPyBERUZBVUxULm1pblVwdGltZSA6IF9hOwogICAgICBjbGVhclRpbWVvdXQoX3RoaXMuX2Nvbm5lY3RUaW1lb3V0KTsKICAgICAgX3RoaXMuX3VwdGltZVRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiBfdGhpcy5fYWNjZXB0T3BlbigpOwogICAgICB9LCBtaW5VcHRpbWUpOwogICAgICBfdGhpcy5fd3MuYmluYXJ5VHlwZSA9IF90aGlzLl9iaW5hcnlUeXBlOwogICAgICBfdGhpcy5fbWVzc2FnZVF1ZXVlLmZvckVhY2goZnVuY3Rpb24obWVzc2FnZSkgewogICAgICAgIHJldHVybiBfdGhpcy5fd3Muc2VuZChtZXNzYWdlKTsKICAgICAgfSk7CiAgICAgIF90aGlzLl9tZXNzYWdlUXVldWUgPSBbXTsKICAgICAgaWYgKF90aGlzLm9ub3BlbikgewogICAgICAgIF90aGlzLm9ub3BlbihldmVudCk7CiAgICAgIH0KICAgICAgX3RoaXMuX2xpc3RlbmVycy5vcGVuLmZvckVhY2goZnVuY3Rpb24obGlzdGVuZXIpIHsKICAgICAgICByZXR1cm4gX3RoaXMuX2NhbGxFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcik7CiAgICAgIH0pOwogICAgfTsKICAgIHRoaXMuX2hhbmRsZU1lc3NhZ2UgPSBmdW5jdGlvbihldmVudCkgewogICAgICBfdGhpcy5fZGVidWcoIm1lc3NhZ2UgZXZlbnQiKTsKICAgICAgaWYgKF90aGlzLm9ubWVzc2FnZSkgewogICAgICAgIF90aGlzLm9ubWVzc2FnZShldmVudCk7CiAgICAgIH0KICAgICAgX3RoaXMuX2xpc3RlbmVycy5tZXNzYWdlLmZvckVhY2goZnVuY3Rpb24obGlzdGVuZXIpIHsKICAgICAgICByZXR1cm4gX3RoaXMuX2NhbGxFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcik7CiAgICAgIH0pOwogICAgfTsKICAgIHRoaXMuX2hhbmRsZUVycm9yID0gZnVuY3Rpb24oZXZlbnQpIHsKICAgICAgX3RoaXMuX2RlYnVnKCJlcnJvciBldmVudCIsIGV2ZW50Lm1lc3NhZ2UpOwogICAgICBfdGhpcy5fZGlzY29ubmVjdCh2b2lkIDAsIGV2ZW50Lm1lc3NhZ2UgPT09ICJUSU1FT1VUIiA/ICJ0aW1lb3V0IiA6IHZvaWQgMCk7CiAgICAgIGlmIChfdGhpcy5vbmVycm9yKSB7CiAgICAgICAgX3RoaXMub25lcnJvcihldmVudCk7CiAgICAgIH0KICAgICAgX3RoaXMuX2RlYnVnKCJleGVjIGVycm9yIGxpc3RlbmVycyIpOwogICAgICBfdGhpcy5fbGlzdGVuZXJzLmVycm9yLmZvckVhY2goZnVuY3Rpb24obGlzdGVuZXIpIHsKICAgICAgICByZXR1cm4gX3RoaXMuX2NhbGxFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcik7CiAgICAgIH0pOwogICAgICBfdGhpcy5fY29ubmVjdCgpOwogICAgfTsKICAgIHRoaXMuX2hhbmRsZUNsb3NlID0gZnVuY3Rpb24oZXZlbnQpIHsKICAgICAgX3RoaXMuX2RlYnVnKCJjbG9zZSBldmVudCIpOwogICAgICBfdGhpcy5fY2xlYXJUaW1lb3V0cygpOwogICAgICBpZiAoX3RoaXMuX3Nob3VsZFJlY29ubmVjdCkgewogICAgICAgIF90aGlzLl9jb25uZWN0KCk7CiAgICAgIH0KICAgICAgaWYgKF90aGlzLm9uY2xvc2UpIHsKICAgICAgICBfdGhpcy5vbmNsb3NlKGV2ZW50KTsKICAgICAgfQogICAgICBfdGhpcy5fbGlzdGVuZXJzLmNsb3NlLmZvckVhY2goZnVuY3Rpb24obGlzdGVuZXIpIHsKICAgICAgICByZXR1cm4gX3RoaXMuX2NhbGxFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcik7CiAgICAgIH0pOwogICAgfTsKICAgIHRoaXMuX3VybCA9IHVybDsKICAgIHRoaXMuX3Byb3RvY29scyA9IHByb3RvY29sczsKICAgIHRoaXMuX29wdGlvbnMgPSBvcHRpb25zOwogICAgaWYgKHRoaXMuX29wdGlvbnMuc3RhcnRDbG9zZWQpIHsKICAgICAgdGhpcy5fc2hvdWxkUmVjb25uZWN0ID0gZmFsc2U7CiAgICB9CiAgICB0aGlzLl9jb25uZWN0KCk7CiAgfQogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLCAiQ09OTkVDVElORyIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiAwOwogICAgfSwKICAgIGVudW1lcmFibGU6IHRydWUsCiAgICBjb25maWd1cmFibGU6IHRydWUKICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoUmVjb25uZWN0aW5nV2ViU29ja2V0MiwgIk9QRU4iLCB7CiAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICByZXR1cm4gMTsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIsICJDTE9TSU5HIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgcmV0dXJuIDI7CiAgICB9LAogICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogIH0pOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLCAiQ0xPU0VEIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgcmV0dXJuIDM7CiAgICB9LAogICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogIH0pOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZSwgIkNPTk5FQ1RJTkciLCB7CiAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICByZXR1cm4gUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5DT05ORUNUSU5HOwogICAgfSwKICAgIGVudW1lcmFibGU6IHRydWUsCiAgICBjb25maWd1cmFibGU6IHRydWUKICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUsICJPUEVOIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgcmV0dXJuIFJlY29ubmVjdGluZ1dlYlNvY2tldDIuT1BFTjsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAiQ0xPU0lORyIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLkNMT1NJTkc7CiAgICB9LAogICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogIH0pOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZSwgIkNMT1NFRCIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLkNMT1NFRDsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAiYmluYXJ5VHlwZSIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiB0aGlzLl93cyA/IHRoaXMuX3dzLmJpbmFyeVR5cGUgOiB0aGlzLl9iaW5hcnlUeXBlOwogICAgfSwKICAgIHNldDogZnVuY3Rpb24odmFsdWUpIHsKICAgICAgdGhpcy5fYmluYXJ5VHlwZSA9IHZhbHVlOwogICAgICBpZiAodGhpcy5fd3MpIHsKICAgICAgICB0aGlzLl93cy5iaW5hcnlUeXBlID0gdmFsdWU7CiAgICAgIH0KICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAicmV0cnlDb3VudCIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiBNYXRoLm1heCh0aGlzLl9yZXRyeUNvdW50LCAwKTsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAiYnVmZmVyZWRBbW91bnQiLCB7CiAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICB2YXIgYnl0ZXMgPSB0aGlzLl9tZXNzYWdlUXVldWUucmVkdWNlKGZ1bmN0aW9uKGFjYywgbWVzc2FnZSkgewogICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZSA9PT0gInN0cmluZyIpIHsKICAgICAgICAgIGFjYyArPSBtZXNzYWdlLmxlbmd0aDsKICAgICAgICB9IGVsc2UgaWYgKG1lc3NhZ2UgaW5zdGFuY2VvZiBCbG9iKSB7CiAgICAgICAgICBhY2MgKz0gbWVzc2FnZS5zaXplOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBhY2MgKz0gbWVzc2FnZS5ieXRlTGVuZ3RoOwogICAgICAgIH0KICAgICAgICByZXR1cm4gYWNjOwogICAgICB9LCAwKTsKICAgICAgcmV0dXJuIGJ5dGVzICsgKHRoaXMuX3dzID8gdGhpcy5fd3MuYnVmZmVyZWRBbW91bnQgOiAwKTsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAiZXh0ZW5zaW9ucyIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiB0aGlzLl93cyA/IHRoaXMuX3dzLmV4dGVuc2lvbnMgOiAiIjsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAicHJvdG9jb2wiLCB7CiAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICByZXR1cm4gdGhpcy5fd3MgPyB0aGlzLl93cy5wcm90b2NvbCA6ICIiOwogICAgfSwKICAgIGVudW1lcmFibGU6IHRydWUsCiAgICBjb25maWd1cmFibGU6IHRydWUKICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUsICJyZWFkeVN0YXRlIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgaWYgKHRoaXMuX3dzKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuX3dzLnJlYWR5U3RhdGU7CiAgICAgIH0KICAgICAgcmV0dXJuIHRoaXMuX29wdGlvbnMuc3RhcnRDbG9zZWQgPyBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLkNMT1NFRCA6IFJlY29ubmVjdGluZ1dlYlNvY2tldDIuQ09OTkVDVElORzsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAidXJsIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgcmV0dXJuIHRoaXMuX3dzID8gdGhpcy5fd3MudXJsIDogIiI7CiAgICB9LAogICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogIH0pOwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oY29kZSwgcmVhc29uKSB7CiAgICBpZiAoY29kZSA9PT0gdm9pZCAwKSB7CiAgICAgIGNvZGUgPSAxZTM7CiAgICB9CiAgICB0aGlzLl9jbG9zZUNhbGxlZCA9IHRydWU7CiAgICB0aGlzLl9zaG91bGRSZWNvbm5lY3QgPSBmYWxzZTsKICAgIHRoaXMuX2NsZWFyVGltZW91dHMoKTsKICAgIGlmICghdGhpcy5fd3MpIHsKICAgICAgdGhpcy5fZGVidWcoImNsb3NlIGVucXVldWVkOiBubyB3cyBpbnN0YW5jZSIpOwogICAgICByZXR1cm47CiAgICB9CiAgICBpZiAodGhpcy5fd3MucmVhZHlTdGF0ZSA9PT0gdGhpcy5DTE9TRUQpIHsKICAgICAgdGhpcy5fZGVidWcoImNsb3NlOiBhbHJlYWR5IGNsb3NlZCIpOwogICAgICByZXR1cm47CiAgICB9CiAgICB0aGlzLl93cy5jbG9zZShjb2RlLCByZWFzb24pOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUucmVjb25uZWN0ID0gZnVuY3Rpb24oY29kZSwgcmVhc29uKSB7CiAgICB0aGlzLl9zaG91bGRSZWNvbm5lY3QgPSB0cnVlOwogICAgdGhpcy5fY2xvc2VDYWxsZWQgPSBmYWxzZTsKICAgIHRoaXMuX3JldHJ5Q291bnQgPSAtMTsKICAgIGlmICghdGhpcy5fd3MgfHwgdGhpcy5fd3MucmVhZHlTdGF0ZSA9PT0gdGhpcy5DTE9TRUQpIHsKICAgICAgdGhpcy5fY29ubmVjdCgpOwogICAgfSBlbHNlIHsKICAgICAgdGhpcy5fZGlzY29ubmVjdChjb2RlLCByZWFzb24pOwogICAgICB0aGlzLl9jb25uZWN0KCk7CiAgICB9CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24oZGF0YSkgewogICAgaWYgKHRoaXMuX3dzICYmIHRoaXMuX3dzLnJlYWR5U3RhdGUgPT09IHRoaXMuT1BFTikgewogICAgICB0aGlzLl9kZWJ1Zygic2VuZCIsIGRhdGEpOwogICAgICB0aGlzLl93cy5zZW5kKGRhdGEpOwogICAgfSBlbHNlIHsKICAgICAgdmFyIF9hID0gdGhpcy5fb3B0aW9ucy5tYXhFbnF1ZXVlZE1lc3NhZ2VzLCBtYXhFbnF1ZXVlZE1lc3NhZ2VzID0gX2EgPT09IHZvaWQgMCA/IERFRkFVTFQubWF4RW5xdWV1ZWRNZXNzYWdlcyA6IF9hOwogICAgICBpZiAodGhpcy5fbWVzc2FnZVF1ZXVlLmxlbmd0aCA8IG1heEVucXVldWVkTWVzc2FnZXMpIHsKICAgICAgICB0aGlzLl9kZWJ1ZygiZW5xdWV1ZSIsIGRhdGEpOwogICAgICAgIHRoaXMuX21lc3NhZ2VRdWV1ZS5wdXNoKGRhdGEpOwogICAgICB9CiAgICB9CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5hZGRFdmVudExpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHsKICAgIGlmICh0aGlzLl9saXN0ZW5lcnNbdHlwZV0pIHsKICAgICAgdGhpcy5fbGlzdGVuZXJzW3R5cGVdLnB1c2gobGlzdGVuZXIpOwogICAgfQogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuZGlzcGF0Y2hFdmVudCA9IGZ1bmN0aW9uKGV2ZW50KSB7CiAgICB2YXIgZV8xLCBfYTsKICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnNbZXZlbnQudHlwZV07CiAgICBpZiAobGlzdGVuZXJzKSB7CiAgICAgIHRyeSB7CiAgICAgICAgZm9yICh2YXIgbGlzdGVuZXJzXzEgPSBfX3ZhbHVlcyhsaXN0ZW5lcnMpLCBsaXN0ZW5lcnNfMV8xID0gbGlzdGVuZXJzXzEubmV4dCgpOyAhbGlzdGVuZXJzXzFfMS5kb25lOyBsaXN0ZW5lcnNfMV8xID0gbGlzdGVuZXJzXzEubmV4dCgpKSB7CiAgICAgICAgICB2YXIgbGlzdGVuZXIgPSBsaXN0ZW5lcnNfMV8xLnZhbHVlOwogICAgICAgICAgdGhpcy5fY2FsbEV2ZW50TGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVyKTsKICAgICAgICB9CiAgICAgIH0gY2F0Y2ggKGVfMV8xKSB7CiAgICAgICAgZV8xID0geyBlcnJvcjogZV8xXzEgfTsKICAgICAgfSBmaW5hbGx5IHsKICAgICAgICB0cnkgewogICAgICAgICAgaWYgKGxpc3RlbmVyc18xXzEgJiYgIWxpc3RlbmVyc18xXzEuZG9uZSAmJiAoX2EgPSBsaXN0ZW5lcnNfMS5yZXR1cm4pKQogICAgICAgICAgICBfYS5jYWxsKGxpc3RlbmVyc18xKTsKICAgICAgICB9IGZpbmFsbHkgewogICAgICAgICAgaWYgKGVfMSkKICAgICAgICAgICAgdGhyb3cgZV8xLmVycm9yOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5yZW1vdmVFdmVudExpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHsKICAgIGlmICh0aGlzLl9saXN0ZW5lcnNbdHlwZV0pIHsKICAgICAgdGhpcy5fbGlzdGVuZXJzW3R5cGVdID0gdGhpcy5fbGlzdGVuZXJzW3R5cGVdLmZpbHRlcihmdW5jdGlvbihsKSB7CiAgICAgICAgcmV0dXJuIGwgIT09IGxpc3RlbmVyOwogICAgICB9KTsKICAgIH0KICB9OwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLl9kZWJ1ZyA9IGZ1bmN0aW9uKCkgewogICAgdmFyIGFyZ3MgPSBbXTsKICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBhcmd1bWVudHMubGVuZ3RoOyBfaSsrKSB7CiAgICAgIGFyZ3NbX2ldID0gYXJndW1lbnRzW19pXTsKICAgIH0KICAgIGlmICh0aGlzLl9vcHRpb25zLmRlYnVnKSB7CiAgICAgIGNvbnNvbGUubG9nLmFwcGx5KGNvbnNvbGUsIF9fc3ByZWFkKFsiUldTPiJdLCBhcmdzKSk7CiAgICB9CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5fZ2V0TmV4dERlbGF5ID0gZnVuY3Rpb24oKSB7CiAgICB2YXIgX2EgPSB0aGlzLl9vcHRpb25zLCBfYiA9IF9hLnJlY29ubmVjdGlvbkRlbGF5R3Jvd0ZhY3RvciwgcmVjb25uZWN0aW9uRGVsYXlHcm93RmFjdG9yID0gX2IgPT09IHZvaWQgMCA/IERFRkFVTFQucmVjb25uZWN0aW9uRGVsYXlHcm93RmFjdG9yIDogX2IsIF9jID0gX2EubWluUmVjb25uZWN0aW9uRGVsYXksIG1pblJlY29ubmVjdGlvbkRlbGF5ID0gX2MgPT09IHZvaWQgMCA/IERFRkFVTFQubWluUmVjb25uZWN0aW9uRGVsYXkgOiBfYywgX2QgPSBfYS5tYXhSZWNvbm5lY3Rpb25EZWxheSwgbWF4UmVjb25uZWN0aW9uRGVsYXkgPSBfZCA9PT0gdm9pZCAwID8gREVGQVVMVC5tYXhSZWNvbm5lY3Rpb25EZWxheSA6IF9kOwogICAgdmFyIGRlbGF5ID0gMDsKICAgIGlmICh0aGlzLl9yZXRyeUNvdW50ID4gMCkgewogICAgICBkZWxheSA9IG1pblJlY29ubmVjdGlvbkRlbGF5ICogTWF0aC5wb3cocmVjb25uZWN0aW9uRGVsYXlHcm93RmFjdG9yLCB0aGlzLl9yZXRyeUNvdW50IC0gMSk7CiAgICAgIGlmIChkZWxheSA+IG1heFJlY29ubmVjdGlvbkRlbGF5KSB7CiAgICAgICAgZGVsYXkgPSBtYXhSZWNvbm5lY3Rpb25EZWxheTsKICAgICAgfQogICAgfQogICAgdGhpcy5fZGVidWcoIm5leHQgZGVsYXkiLCBkZWxheSk7CiAgICByZXR1cm4gZGVsYXk7CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5fd2FpdCA9IGZ1bmN0aW9uKCkgewogICAgdmFyIF90aGlzID0gdGhpczsKICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlKSB7CiAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgX3RoaXMuX2dldE5leHREZWxheSgpKTsKICAgIH0pOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX2dldE5leHRVcmwgPSBmdW5jdGlvbih1cmxQcm92aWRlcikgewogICAgaWYgKHR5cGVvZiB1cmxQcm92aWRlciA9PT0gInN0cmluZyIpIHsKICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh1cmxQcm92aWRlcik7CiAgICB9CiAgICBpZiAodHlwZW9mIHVybFByb3ZpZGVyID09PSAiZnVuY3Rpb24iKSB7CiAgICAgIHZhciB1cmwgPSB1cmxQcm92aWRlcigpOwogICAgICBpZiAodHlwZW9mIHVybCA9PT0gInN0cmluZyIpIHsKICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHVybCk7CiAgICAgIH0KICAgICAgaWYgKCEhdXJsLnRoZW4pIHsKICAgICAgICByZXR1cm4gdXJsOwogICAgICB9CiAgICB9CiAgICB0aHJvdyBFcnJvcigiSW52YWxpZCBVUkwiKTsKICB9OwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLl9jb25uZWN0ID0gZnVuY3Rpb24oKSB7CiAgICB2YXIgX3RoaXMgPSB0aGlzOwogICAgaWYgKHRoaXMuX2Nvbm5lY3RMb2NrIHx8ICF0aGlzLl9zaG91bGRSZWNvbm5lY3QpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgdGhpcy5fY29ubmVjdExvY2sgPSB0cnVlOwogICAgdmFyIF9hID0gdGhpcy5fb3B0aW9ucywgX2IgPSBfYS5tYXhSZXRyaWVzLCBtYXhSZXRyaWVzID0gX2IgPT09IHZvaWQgMCA/IERFRkFVTFQubWF4UmV0cmllcyA6IF9iLCBfYyA9IF9hLmNvbm5lY3Rpb25UaW1lb3V0LCBjb25uZWN0aW9uVGltZW91dCA9IF9jID09PSB2b2lkIDAgPyBERUZBVUxULmNvbm5lY3Rpb25UaW1lb3V0IDogX2MsIF9kID0gX2EuV2ViU29ja2V0LCBXZWJTb2NrZXQyID0gX2QgPT09IHZvaWQgMCA/IGdldEdsb2JhbFdlYlNvY2tldCgpIDogX2Q7CiAgICBpZiAodGhpcy5fcmV0cnlDb3VudCA+PSBtYXhSZXRyaWVzKSB7CiAgICAgIHRoaXMuX2RlYnVnKCJtYXggcmV0cmllcyByZWFjaGVkIiwgdGhpcy5fcmV0cnlDb3VudCwgIj49IiwgbWF4UmV0cmllcyk7CiAgICAgIHJldHVybjsKICAgIH0KICAgIHRoaXMuX3JldHJ5Q291bnQrKzsKICAgIHRoaXMuX2RlYnVnKCJjb25uZWN0IiwgdGhpcy5fcmV0cnlDb3VudCk7CiAgICB0aGlzLl9yZW1vdmVMaXN0ZW5lcnMoKTsKICAgIGlmICghaXNXZWJTb2NrZXQoV2ViU29ja2V0MikpIHsKICAgICAgdGhyb3cgRXJyb3IoIk5vIHZhbGlkIFdlYlNvY2tldCBjbGFzcyBwcm92aWRlZCIpOwogICAgfQogICAgdGhpcy5fd2FpdCgpLnRoZW4oZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiBfdGhpcy5fZ2V0TmV4dFVybChfdGhpcy5fdXJsKTsKICAgIH0pLnRoZW4oZnVuY3Rpb24odXJsKSB7CiAgICAgIGlmIChfdGhpcy5fY2xvc2VDYWxsZWQpIHsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgX3RoaXMuX2RlYnVnKCJjb25uZWN0IiwgeyB1cmwsIHByb3RvY29sczogX3RoaXMuX3Byb3RvY29scyB9KTsKICAgICAgX3RoaXMuX3dzID0gX3RoaXMuX3Byb3RvY29scyA/IG5ldyBXZWJTb2NrZXQyKHVybCwgX3RoaXMuX3Byb3RvY29scykgOiBuZXcgV2ViU29ja2V0Mih1cmwpOwogICAgICBfdGhpcy5fd3MuYmluYXJ5VHlwZSA9IF90aGlzLl9iaW5hcnlUeXBlOwogICAgICBfdGhpcy5fY29ubmVjdExvY2sgPSBmYWxzZTsKICAgICAgX3RoaXMuX2FkZExpc3RlbmVycygpOwogICAgICBfdGhpcy5fY29ubmVjdFRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiBfdGhpcy5faGFuZGxlVGltZW91dCgpOwogICAgICB9LCBjb25uZWN0aW9uVGltZW91dCk7CiAgICB9KTsKICB9OwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLl9oYW5kbGVUaW1lb3V0ID0gZnVuY3Rpb24oKSB7CiAgICB0aGlzLl9kZWJ1ZygidGltZW91dCBldmVudCIpOwogICAgdGhpcy5faGFuZGxlRXJyb3IobmV3IEVycm9yRXZlbnQoRXJyb3IoIlRJTUVPVVQiKSwgdGhpcykpOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX2Rpc2Nvbm5lY3QgPSBmdW5jdGlvbihjb2RlLCByZWFzb24pIHsKICAgIGlmIChjb2RlID09PSB2b2lkIDApIHsKICAgICAgY29kZSA9IDFlMzsKICAgIH0KICAgIHRoaXMuX2NsZWFyVGltZW91dHMoKTsKICAgIGlmICghdGhpcy5fd3MpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgdGhpcy5fcmVtb3ZlTGlzdGVuZXJzKCk7CiAgICB0cnkgewogICAgICB0aGlzLl93cy5jbG9zZShjb2RlLCByZWFzb24pOwogICAgICB0aGlzLl9oYW5kbGVDbG9zZShuZXcgQ2xvc2VFdmVudChjb2RlLCByZWFzb24sIHRoaXMpKTsKICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICB9CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5fYWNjZXB0T3BlbiA9IGZ1bmN0aW9uKCkgewogICAgdGhpcy5fZGVidWcoImFjY2VwdCBvcGVuIik7CiAgICB0aGlzLl9yZXRyeUNvdW50ID0gMDsKICB9OwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLl9jYWxsRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKGV2ZW50LCBsaXN0ZW5lcikgewogICAgaWYgKCJoYW5kbGVFdmVudCIgaW4gbGlzdGVuZXIpIHsKICAgICAgbGlzdGVuZXIuaGFuZGxlRXZlbnQoZXZlbnQpOwogICAgfSBlbHNlIHsKICAgICAgbGlzdGVuZXIoZXZlbnQpOwogICAgfQogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX3JlbW92ZUxpc3RlbmVycyA9IGZ1bmN0aW9uKCkgewogICAgaWYgKCF0aGlzLl93cykgewogICAgICByZXR1cm47CiAgICB9CiAgICB0aGlzLl9kZWJ1ZygicmVtb3ZlTGlzdGVuZXJzIik7CiAgICB0aGlzLl93cy5yZW1vdmVFdmVudExpc3RlbmVyKCJvcGVuIiwgdGhpcy5faGFuZGxlT3Blbik7CiAgICB0aGlzLl93cy5yZW1vdmVFdmVudExpc3RlbmVyKCJjbG9zZSIsIHRoaXMuX2hhbmRsZUNsb3NlKTsKICAgIHRoaXMuX3dzLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLCB0aGlzLl9oYW5kbGVNZXNzYWdlKTsKICAgIHRoaXMuX3dzLnJlbW92ZUV2ZW50TGlzdGVuZXIoImVycm9yIiwgdGhpcy5faGFuZGxlRXJyb3IpOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX2FkZExpc3RlbmVycyA9IGZ1bmN0aW9uKCkgewogICAgaWYgKCF0aGlzLl93cykgewogICAgICByZXR1cm47CiAgICB9CiAgICB0aGlzLl9kZWJ1ZygiYWRkTGlzdGVuZXJzIik7CiAgICB0aGlzLl93cy5hZGRFdmVudExpc3RlbmVyKCJvcGVuIiwgdGhpcy5faGFuZGxlT3Blbik7CiAgICB0aGlzLl93cy5hZGRFdmVudExpc3RlbmVyKCJjbG9zZSIsIHRoaXMuX2hhbmRsZUNsb3NlKTsKICAgIHRoaXMuX3dzLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLCB0aGlzLl9oYW5kbGVNZXNzYWdlKTsKICAgIHRoaXMuX3dzLmFkZEV2ZW50TGlzdGVuZXIoImVycm9yIiwgdGhpcy5faGFuZGxlRXJyb3IpOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX2NsZWFyVGltZW91dHMgPSBmdW5jdGlvbigpIHsKICAgIGNsZWFyVGltZW91dCh0aGlzLl9jb25uZWN0VGltZW91dCk7CiAgICBjbGVhclRpbWVvdXQodGhpcy5fdXB0aW1lVGltZW91dCk7CiAgfTsKICByZXR1cm4gUmVjb25uZWN0aW5nV2ViU29ja2V0MjsKfSgpOwp2YXIgcmVjb25uZWN0aW5nX3dlYnNvY2tldF9tanNfZGVmYXVsdCA9IFJlY29ubmVjdGluZ1dlYlNvY2tldDsKCi8vIG5vZGVfbW9kdWxlcy9AYmpvcm4zL2Jyb3dzZXJfd2FzaV9zaGltL2Rpc3Qvd2FzaV9kZWZzLmpzCnZhciBDTE9DS0lEX1JFQUxUSU1FID0gMDsKdmFyIENMT0NLSURfTU9OT1RPTklDID0gMTsKdmFyIEVSUk5PX1NVQ0NFU1MgPSAwOwp2YXIgRVJSTk9fQkFERiA9IDg7CnZhciBFUlJOT19FWElTVCA9IDIwOwp2YXIgRVJSTk9fSU5WQUwgPSAyODsKdmFyIEVSUk5PX0lTRElSID0gMzE7CnZhciBFUlJOT19OQU1FVE9PTE9ORyA9IDM3Owp2YXIgRVJSTk9fTk9FTlQgPSA0NDsKdmFyIEVSUk5PX05PU1lTID0gNTI7CnZhciBFUlJOT19OT1RESVIgPSA1NDsKdmFyIEVSUk5PX05PVEVNUFRZID0gNTU7CnZhciBFUlJOT19OT1RTVVAgPSA1ODsKdmFyIEVSUk5PX1BFUk0gPSA2MzsKdmFyIEVSUk5PX05PVENBUEFCTEUgPSA3NjsKdmFyIFJJR0hUU19GRF9EQVRBU1lOQyA9IDEgPDwgMDsKdmFyIFJJR0hUU19GRF9SRUFEID0gMSA8PCAxOwp2YXIgUklHSFRTX0ZEX1NFRUsgPSAxIDw8IDI7CnZhciBSSUdIVFNfRkRfRkRTVEFUX1NFVF9GTEFHUyA9IDEgPDwgMzsKdmFyIFJJR0hUU19GRF9TWU5DID0gMSA8PCA0Owp2YXIgUklHSFRTX0ZEX1RFTEwgPSAxIDw8IDU7CnZhciBSSUdIVFNfRkRfV1JJVEUgPSAxIDw8IDY7CnZhciBSSUdIVFNfRkRfQURWSVNFID0gMSA8PCA3Owp2YXIgUklHSFRTX0ZEX0FMTE9DQVRFID0gMSA8PCA4Owp2YXIgUklHSFRTX1BBVEhfQ1JFQVRFX0RJUkVDVE9SWSA9IDEgPDwgOTsKdmFyIFJJR0hUU19QQVRIX0NSRUFURV9GSUxFID0gMSA8PCAxMDsKdmFyIFJJR0hUU19QQVRIX0xJTktfU09VUkNFID0gMSA8PCAxMTsKdmFyIFJJR0hUU19QQVRIX0xJTktfVEFSR0VUID0gMSA8PCAxMjsKdmFyIFJJR0hUU19QQVRIX09QRU4gPSAxIDw8IDEzOwp2YXIgUklHSFRTX0ZEX1JFQURESVIgPSAxIDw8IDE0Owp2YXIgUklHSFRTX1BBVEhfUkVBRExJTksgPSAxIDw8IDE1Owp2YXIgUklHSFRTX1BBVEhfUkVOQU1FX1NPVVJDRSA9IDEgPDwgMTY7CnZhciBSSUdIVFNfUEFUSF9SRU5BTUVfVEFSR0VUID0gMSA8PCAxNzsKdmFyIFJJR0hUU19QQVRIX0ZJTEVTVEFUX0dFVCA9IDEgPDwgMTg7CnZhciBSSUdIVFNfUEFUSF9GSUxFU1RBVF9TRVRfU0laRSA9IDEgPDwgMTk7CnZhciBSSUdIVFNfUEFUSF9GSUxFU1RBVF9TRVRfVElNRVMgPSAxIDw8IDIwOwp2YXIgUklHSFRTX0ZEX0ZJTEVTVEFUX0dFVCA9IDEgPDwgMjE7CnZhciBSSUdIVFNfRkRfRklMRVNUQVRfU0VUX1NJWkUgPSAxIDw8IDIyOwp2YXIgUklHSFRTX0ZEX0ZJTEVTVEFUX1NFVF9USU1FUyA9IDEgPDwgMjM7CnZhciBSSUdIVFNfUEFUSF9TWU1MSU5LID0gMSA8PCAyNDsKdmFyIFJJR0hUU19QQVRIX1JFTU9WRV9ESVJFQ1RPUlkgPSAxIDw8IDI1Owp2YXIgUklHSFRTX1BBVEhfVU5MSU5LX0ZJTEUgPSAxIDw8IDI2Owp2YXIgUklHSFRTX1BPTExfRkRfUkVBRFdSSVRFID0gMSA8PCAyNzsKdmFyIFJJR0hUU19TT0NLX1NIVVRET1dOID0gMSA8PCAyODsKdmFyIElvdmVjID0gY2xhc3MgewogIHN0YXRpYyByZWFkX2J5dGVzKHZpZXcsIHB0cikgewogICAgY29uc3QgaW92ZWMgPSBuZXcgSW92ZWMoKTsKICAgIGlvdmVjLmJ1ZiA9IHZpZXcuZ2V0VWludDMyKHB0ciwgdHJ1ZSk7CiAgICBpb3ZlYy5idWZfbGVuID0gdmlldy5nZXRVaW50MzIocHRyICsgNCwgdHJ1ZSk7CiAgICByZXR1cm4gaW92ZWM7CiAgfQogIHN0YXRpYyByZWFkX2J5dGVzX2FycmF5KHZpZXcsIHB0ciwgbGVuKSB7CiAgICBjb25zdCBpb3ZlY3MgPSBbXTsKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspIHsKICAgICAgaW92ZWNzLnB1c2goSW92ZWMucmVhZF9ieXRlcyh2aWV3LCBwdHIgKyA4ICogaSkpOwogICAgfQogICAgcmV0dXJuIGlvdmVjczsKICB9Cn07CnZhciBDaW92ZWMgPSBjbGFzcyB7CiAgc3RhdGljIHJlYWRfYnl0ZXModmlldywgcHRyKSB7CiAgICBjb25zdCBpb3ZlYyA9IG5ldyBDaW92ZWMoKTsKICAgIGlvdmVjLmJ1ZiA9IHZpZXcuZ2V0VWludDMyKHB0ciwgdHJ1ZSk7CiAgICBpb3ZlYy5idWZfbGVuID0gdmlldy5nZXRVaW50MzIocHRyICsgNCwgdHJ1ZSk7CiAgICByZXR1cm4gaW92ZWM7CiAgfQogIHN0YXRpYyByZWFkX2J5dGVzX2FycmF5KHZpZXcsIHB0ciwgbGVuKSB7CiAgICBjb25zdCBpb3ZlY3MgPSBbXTsKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspIHsKICAgICAgaW92ZWNzLnB1c2goQ2lvdmVjLnJlYWRfYnl0ZXModmlldywgcHRyICsgOCAqIGkpKTsKICAgIH0KICAgIHJldHVybiBpb3ZlY3M7CiAgfQp9Owp2YXIgV0hFTkNFX1NFVCA9IDA7CnZhciBXSEVOQ0VfQ1VSID0gMTsKdmFyIFdIRU5DRV9FTkQgPSAyOwp2YXIgRklMRVRZUEVfQ0hBUkFDVEVSX0RFVklDRSA9IDI7CnZhciBGSUxFVFlQRV9ESVJFQ1RPUlkgPSAzOwp2YXIgRklMRVRZUEVfUkVHVUxBUl9GSUxFID0gNDsKdmFyIERpcmVudCA9IGNsYXNzIHsKICBoZWFkX2xlbmd0aCgpIHsKICAgIHJldHVybiAyNDsKICB9CiAgbmFtZV9sZW5ndGgoKSB7CiAgICByZXR1cm4gdGhpcy5kaXJfbmFtZS5ieXRlTGVuZ3RoOwogIH0KICB3cml0ZV9oZWFkX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRCaWdVaW50NjQocHRyLCB0aGlzLmRfbmV4dCwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA4LCB0aGlzLmRfaW5vLCB0cnVlKTsKICAgIHZpZXcuc2V0VWludDMyKHB0ciArIDE2LCB0aGlzLmRpcl9uYW1lLmxlbmd0aCwgdHJ1ZSk7CiAgICB2aWV3LnNldFVpbnQ4KHB0ciArIDIwLCB0aGlzLmRfdHlwZSk7CiAgfQogIHdyaXRlX25hbWVfYnl0ZXModmlldzgsIHB0ciwgYnVmX2xlbikgewogICAgdmlldzguc2V0KHRoaXMuZGlyX25hbWUuc2xpY2UoMCwgTWF0aC5taW4odGhpcy5kaXJfbmFtZS5ieXRlTGVuZ3RoLCBidWZfbGVuKSksIHB0cik7CiAgfQogIGNvbnN0cnVjdG9yKG5leHRfY29va2llLCBuYW1lLCB0eXBlKSB7CiAgICB0aGlzLmRfaW5vID0gMG47CiAgICBjb25zdCBlbmNvZGVkX25hbWUgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUobmFtZSk7CiAgICB0aGlzLmRfbmV4dCA9IG5leHRfY29va2llOwogICAgdGhpcy5kX25hbWxlbiA9IGVuY29kZWRfbmFtZS5ieXRlTGVuZ3RoOwogICAgdGhpcy5kX3R5cGUgPSB0eXBlOwogICAgdGhpcy5kaXJfbmFtZSA9IGVuY29kZWRfbmFtZTsKICB9Cn07CnZhciBGREZMQUdTX0FQUEVORCA9IDEgPDwgMDsKdmFyIEZERkxBR1NfRFNZTkMgPSAxIDw8IDE7CnZhciBGREZMQUdTX05PTkJMT0NLID0gMSA8PCAyOwp2YXIgRkRGTEFHU19SU1lOQyA9IDEgPDwgMzsKdmFyIEZERkxBR1NfU1lOQyA9IDEgPDwgNDsKdmFyIEZkc3RhdCA9IGNsYXNzIHsKICB3cml0ZV9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIHZpZXcuc2V0VWludDgocHRyLCB0aGlzLmZzX2ZpbGV0eXBlKTsKICAgIHZpZXcuc2V0VWludDE2KHB0ciArIDIsIHRoaXMuZnNfZmxhZ3MsIHRydWUpOwogICAgdmlldy5zZXRCaWdVaW50NjQocHRyICsgOCwgdGhpcy5mc19yaWdodHNfYmFzZSwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyAxNiwgdGhpcy5mc19yaWdodHNfaW5oZXJpdGVkLCB0cnVlKTsKICB9CiAgY29uc3RydWN0b3IoZmlsZXR5cGUsIGZsYWdzKSB7CiAgICB0aGlzLmZzX3JpZ2h0c19iYXNlID0gMG47CiAgICB0aGlzLmZzX3JpZ2h0c19pbmhlcml0ZWQgPSAwbjsKICAgIHRoaXMuZnNfZmlsZXR5cGUgPSBmaWxldHlwZTsKICAgIHRoaXMuZnNfZmxhZ3MgPSBmbGFnczsKICB9Cn07CnZhciBGU1RGTEFHU19BVElNID0gMSA8PCAwOwp2YXIgRlNURkxBR1NfQVRJTV9OT1cgPSAxIDw8IDE7CnZhciBGU1RGTEFHU19NVElNID0gMSA8PCAyOwp2YXIgRlNURkxBR1NfTVRJTV9OT1cgPSAxIDw8IDM7CnZhciBPRkxBR1NfQ1JFQVQgPSAxIDw8IDA7CnZhciBPRkxBR1NfRElSRUNUT1JZID0gMSA8PCAxOwp2YXIgT0ZMQUdTX0VYQ0wgPSAxIDw8IDI7CnZhciBPRkxBR1NfVFJVTkMgPSAxIDw8IDM7CnZhciBGaWxlc3RhdCA9IGNsYXNzIHsKICB3cml0ZV9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciwgdGhpcy5kZXYsIHRydWUpOwogICAgdmlldy5zZXRCaWdVaW50NjQocHRyICsgOCwgdGhpcy5pbm8sIHRydWUpOwogICAgdmlldy5zZXRVaW50OChwdHIgKyAxNiwgdGhpcy5maWxldHlwZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyAyNCwgdGhpcy5ubGluaywgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyAzMiwgdGhpcy5zaXplLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDM4LCB0aGlzLmF0aW0sIHRydWUpOwogICAgdmlldy5zZXRCaWdVaW50NjQocHRyICsgNDYsIHRoaXMubXRpbSwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA1MiwgdGhpcy5jdGltLCB0cnVlKTsKICB9CiAgY29uc3RydWN0b3IoZmlsZXR5cGUsIHNpemUpIHsKICAgIHRoaXMuZGV2ID0gMG47CiAgICB0aGlzLmlubyA9IDBuOwogICAgdGhpcy5ubGluayA9IDBuOwogICAgdGhpcy5hdGltID0gMG47CiAgICB0aGlzLm10aW0gPSAwbjsKICAgIHRoaXMuY3RpbSA9IDBuOwogICAgdGhpcy5maWxldHlwZSA9IGZpbGV0eXBlOwogICAgdGhpcy5zaXplID0gc2l6ZTsKICB9Cn07CnZhciBFVkVOVFJXRkxBR1NfRkRfUkVBRFdSSVRFX0hBTkdVUCA9IDEgPDwgMDsKdmFyIFNVQkNMT0NLRkxBR1NfU1VCU0NSSVBUSU9OX0NMT0NLX0FCU1RJTUUgPSAxIDw8IDA7CnZhciBSSUZMQUdTX1JFQ1ZfUEVFSyA9IDEgPDwgMDsKdmFyIFJJRkxBR1NfUkVDVl9XQUlUQUxMID0gMSA8PCAxOwp2YXIgUk9GTEFHU19SRUNWX0RBVEFfVFJVTkNBVEVEID0gMSA8PCAwOwp2YXIgU0RGTEFHU19SRCA9IDEgPDwgMDsKdmFyIFNERkxBR1NfV1IgPSAxIDw8IDE7CnZhciBQUkVPUEVOVFlQRV9ESVIgPSAwOwp2YXIgUHJlc3RhdERpciA9IGNsYXNzIHsKICB3cml0ZV9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIHZpZXcuc2V0VWludDMyKHB0ciwgdGhpcy5wcl9uYW1lLmJ5dGVMZW5ndGgsIHRydWUpOwogIH0KICBjb25zdHJ1Y3RvcihuYW1lKSB7CiAgICB0aGlzLnByX25hbWUgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUobmFtZSk7CiAgfQp9Owp2YXIgUHJlc3RhdCA9IGNsYXNzIHsKICBzdGF0aWMgZGlyKG5hbWUpIHsKICAgIGNvbnN0IHByZXN0YXQgPSBuZXcgUHJlc3RhdCgpOwogICAgcHJlc3RhdC50YWcgPSBQUkVPUEVOVFlQRV9ESVI7CiAgICBwcmVzdGF0LmlubmVyID0gbmV3IFByZXN0YXREaXIobmFtZSk7CiAgICByZXR1cm4gcHJlc3RhdDsKICB9CiAgd3JpdGVfYnl0ZXModmlldywgcHRyKSB7CiAgICB2aWV3LnNldFVpbnQzMihwdHIsIHRoaXMudGFnLCB0cnVlKTsKICAgIHRoaXMuaW5uZXIud3JpdGVfYnl0ZXModmlldywgcHRyICsgNCk7CiAgfQp9OwoKLy8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC9kZWJ1Zy5qcwp2YXIgRGVidWcgPSBjbGFzcyBEZWJ1ZzIgewogIGVuYWJsZShlbmFibGVkKSB7CiAgICB0aGlzLmxvZyA9IGNyZWF0ZUxvZ2dlcihlbmFibGVkID09PSB2b2lkIDAgPyB0cnVlIDogZW5hYmxlZCwgdGhpcy5wcmVmaXgpOwogIH0KICBnZXQgZW5hYmxlZCgpIHsKICAgIHJldHVybiB0aGlzLmlzRW5hYmxlZDsKICB9CiAgY29uc3RydWN0b3IoaXNFbmFibGVkKSB7CiAgICB0aGlzLmlzRW5hYmxlZCA9IGlzRW5hYmxlZDsKICAgIHRoaXMucHJlZml4ID0gIndhc2k6IjsKICAgIHRoaXMuZW5hYmxlKGlzRW5hYmxlZCk7CiAgfQp9OwpmdW5jdGlvbiBjcmVhdGVMb2dnZXIoZW5hYmxlZCwgcHJlZml4KSB7CiAgaWYgKGVuYWJsZWQpIHsKICAgIGNvbnN0IGEgPSBjb25zb2xlLmxvZy5iaW5kKGNvbnNvbGUsICIlYyVzIiwgImNvbG9yOiAjMjY1QkEwIiwgcHJlZml4KTsKICAgIHJldHVybiBhOwogIH0gZWxzZSB7CiAgICByZXR1cm4gKCkgPT4gewogICAgfTsKICB9Cn0KdmFyIGRlYnVnID0gbmV3IERlYnVnKGZhbHNlKTsKCi8vIG5vZGVfbW9kdWxlcy9AYmpvcm4zL2Jyb3dzZXJfd2FzaV9zaGltL2Rpc3Qvd2FzaS5qcwp2YXIgV0FTSVByb2NFeGl0ID0gY2xhc3MgZXh0ZW5kcyBFcnJvciB7CiAgY29uc3RydWN0b3IoY29kZSkgewogICAgc3VwZXIoImV4aXQgd2l0aCBleGl0IGNvZGUgIiArIGNvZGUpOwogICAgdGhpcy5jb2RlID0gY29kZTsKICB9Cn07CnZhciBXQVNJID0gY2xhc3MgV0FTSTIgewogIHN0YXJ0KGluc3RhbmNlKSB7CiAgICB0aGlzLmluc3QgPSBpbnN0YW5jZTsKICAgIHRyeSB7CiAgICAgIGluc3RhbmNlLmV4cG9ydHMuX3N0YXJ0KCk7CiAgICAgIHJldHVybiAwOwogICAgfSBjYXRjaCAoZSkgewogICAgICBpZiAoZSBpbnN0YW5jZW9mIFdBU0lQcm9jRXhpdCkgewogICAgICAgIHJldHVybiBlLmNvZGU7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdGhyb3cgZTsKICAgICAgfQogICAgfQogIH0KICBpbml0aWFsaXplKGluc3RhbmNlKSB7CiAgICB0aGlzLmluc3QgPSBpbnN0YW5jZTsKICAgIGlmIChpbnN0YW5jZS5leHBvcnRzLl9pbml0aWFsaXplKSB7CiAgICAgIGluc3RhbmNlLmV4cG9ydHMuX2luaXRpYWxpemUoKTsKICAgIH0KICB9CiAgY29uc3RydWN0b3IoYXJncywgZW52LCBmZHMsIG9wdGlvbnMgPSB7fSkgewogICAgdGhpcy5hcmdzID0gW107CiAgICB0aGlzLmVudiA9IFtdOwogICAgdGhpcy5mZHMgPSBbXTsKICAgIGRlYnVnLmVuYWJsZShvcHRpb25zLmRlYnVnKTsKICAgIHRoaXMuYXJncyA9IGFyZ3M7CiAgICB0aGlzLmVudiA9IGVudjsKICAgIHRoaXMuZmRzID0gZmRzOwogICAgY29uc3Qgc2VsZiA9IHRoaXM7CiAgICB0aGlzLndhc2lJbXBvcnQgPSB7IGFyZ3Nfc2l6ZXNfZ2V0KGFyZ2MsIGFyZ3ZfYnVmX3NpemUpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBidWZmZXIuc2V0VWludDMyKGFyZ2MsIHNlbGYuYXJncy5sZW5ndGgsIHRydWUpOwogICAgICBsZXQgYnVmX3NpemUgPSAwOwogICAgICBmb3IgKGNvbnN0IGFyZyBvZiBzZWxmLmFyZ3MpIHsKICAgICAgICBidWZfc2l6ZSArPSBhcmcubGVuZ3RoICsgMTsKICAgICAgfQogICAgICBidWZmZXIuc2V0VWludDMyKGFyZ3ZfYnVmX3NpemUsIGJ1Zl9zaXplLCB0cnVlKTsKICAgICAgZGVidWcubG9nKGJ1ZmZlci5nZXRVaW50MzIoYXJnYywgdHJ1ZSksIGJ1ZmZlci5nZXRVaW50MzIoYXJndl9idWZfc2l6ZSwgdHJ1ZSkpOwogICAgICByZXR1cm4gMDsKICAgIH0sIGFyZ3NfZ2V0KGFyZ3YsIGFyZ3ZfYnVmKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBvcmlnX2FyZ3ZfYnVmID0gYXJndl9idWY7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2VsZi5hcmdzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgYnVmZmVyLnNldFVpbnQzMihhcmd2LCBhcmd2X2J1ZiwgdHJ1ZSk7CiAgICAgICAgYXJndiArPSA0OwogICAgICAgIGNvbnN0IGFyZyA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShzZWxmLmFyZ3NbaV0pOwogICAgICAgIGJ1ZmZlcjguc2V0KGFyZywgYXJndl9idWYpOwogICAgICAgIGJ1ZmZlci5zZXRVaW50OChhcmd2X2J1ZiArIGFyZy5sZW5ndGgsIDApOwogICAgICAgIGFyZ3ZfYnVmICs9IGFyZy5sZW5ndGggKyAxOwogICAgICB9CiAgICAgIGlmIChkZWJ1Zy5lbmFibGVkKSB7CiAgICAgICAgZGVidWcubG9nKG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShvcmlnX2FyZ3ZfYnVmLCBhcmd2X2J1ZikpKTsKICAgICAgfQogICAgICByZXR1cm4gMDsKICAgIH0sIGVudmlyb25fc2l6ZXNfZ2V0KGVudmlyb25fY291bnQsIGVudmlyb25fc2l6ZSkgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoZW52aXJvbl9jb3VudCwgc2VsZi5lbnYubGVuZ3RoLCB0cnVlKTsKICAgICAgbGV0IGJ1Zl9zaXplID0gMDsKICAgICAgZm9yIChjb25zdCBlbnZpcm9uIG9mIHNlbGYuZW52KSB7CiAgICAgICAgYnVmX3NpemUgKz0gZW52aXJvbi5sZW5ndGggKyAxOwogICAgICB9CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoZW52aXJvbl9zaXplLCBidWZfc2l6ZSwgdHJ1ZSk7CiAgICAgIGRlYnVnLmxvZyhidWZmZXIuZ2V0VWludDMyKGVudmlyb25fY291bnQsIHRydWUpLCBidWZmZXIuZ2V0VWludDMyKGVudmlyb25fc2l6ZSwgdHJ1ZSkpOwogICAgICByZXR1cm4gMDsKICAgIH0sIGVudmlyb25fZ2V0KGVudmlyb24sIGVudmlyb25fYnVmKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBvcmlnX2Vudmlyb25fYnVmID0gZW52aXJvbl9idWY7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2VsZi5lbnYubGVuZ3RoOyBpKyspIHsKICAgICAgICBidWZmZXIuc2V0VWludDMyKGVudmlyb24sIGVudmlyb25fYnVmLCB0cnVlKTsKICAgICAgICBlbnZpcm9uICs9IDQ7CiAgICAgICAgY29uc3QgZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShzZWxmLmVudltpXSk7CiAgICAgICAgYnVmZmVyOC5zZXQoZSwgZW52aXJvbl9idWYpOwogICAgICAgIGJ1ZmZlci5zZXRVaW50OChlbnZpcm9uX2J1ZiArIGUubGVuZ3RoLCAwKTsKICAgICAgICBlbnZpcm9uX2J1ZiArPSBlLmxlbmd0aCArIDE7CiAgICAgIH0KICAgICAgaWYgKGRlYnVnLmVuYWJsZWQpIHsKICAgICAgICBkZWJ1Zy5sb2cobmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG9yaWdfZW52aXJvbl9idWYsIGVudmlyb25fYnVmKSkpOwogICAgICB9CiAgICAgIHJldHVybiAwOwogICAgfSwgY2xvY2tfcmVzX2dldChpZCwgcmVzX3B0cikgewogICAgICBsZXQgcmVzb2x1dGlvblZhbHVlOwogICAgICBzd2l0Y2ggKGlkKSB7CiAgICAgICAgY2FzZSBDTE9DS0lEX01PTk9UT05JQzogewogICAgICAgICAgcmVzb2x1dGlvblZhbHVlID0gNTAwMG47CiAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICAgICAgY2FzZSBDTE9DS0lEX1JFQUxUSU1FOiB7CiAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSAxMDAwMDAwbjsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICBkZWZhdWx0OgogICAgICAgICAgcmV0dXJuIEVSUk5PX05PU1lTOwogICAgICB9CiAgICAgIGNvbnN0IHZpZXcgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIHZpZXcuc2V0QmlnVWludDY0KHJlc19wdHIsIHJlc29sdXRpb25WYWx1ZSwgdHJ1ZSk7CiAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgfSwgY2xvY2tfdGltZV9nZXQoaWQsIHByZWNpc2lvbiwgdGltZSkgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChpZCA9PT0gQ0xPQ0tJRF9SRUFMVElNRSkgewogICAgICAgIGJ1ZmZlci5zZXRCaWdVaW50NjQodGltZSwgQmlnSW50KG5ldyBEYXRlKCkuZ2V0VGltZSgpKSAqIDEwMDAwMDBuLCB0cnVlKTsKICAgICAgfSBlbHNlIGlmIChpZCA9PSBDTE9DS0lEX01PTk9UT05JQykgewogICAgICAgIGxldCBtb25vdG9uaWNfdGltZTsKICAgICAgICB0cnkgewogICAgICAgICAgbW9ub3RvbmljX3RpbWUgPSBCaWdJbnQoTWF0aC5yb3VuZChwZXJmb3JtYW5jZS5ub3coKSAqIDFlNikpOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIG1vbm90b25pY190aW1lID0gMG47CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRCaWdVaW50NjQodGltZSwgbW9ub3RvbmljX3RpbWUsIHRydWUpOwogICAgICB9IGVsc2UgewogICAgICAgIGJ1ZmZlci5zZXRCaWdVaW50NjQodGltZSwgMG4sIHRydWUpOwogICAgICB9CiAgICAgIHJldHVybiAwOwogICAgfSwgZmRfYWR2aXNlKGZkLCBvZmZzZXQsIGxlbiwgYWR2aWNlKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2FsbG9jYXRlKGZkLCBvZmZzZXQsIGxlbikgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfYWxsb2NhdGUob2Zmc2V0LCBsZW4pOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9jbG9zZShmZCkgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHJldCA9IHNlbGYuZmRzW2ZkXS5mZF9jbG9zZSgpOwogICAgICAgIHNlbGYuZmRzW2ZkXSA9IHZvaWQgMDsKICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9kYXRhc3luYyhmZCkgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfc3luYygpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9mZHN0YXRfZ2V0KGZkLCBmZHN0YXRfcHRyKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIGZkc3RhdCB9ID0gc2VsZi5mZHNbZmRdLmZkX2Zkc3RhdF9nZXQoKTsKICAgICAgICBpZiAoZmRzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIGZkc3RhdC53cml0ZV9ieXRlcyhuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlciksIGZkc3RhdF9wdHIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9mZHN0YXRfc2V0X2ZsYWdzKGZkLCBmbGFncykgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmRzdGF0X3NldF9mbGFncyhmbGFncyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Zkc3RhdF9zZXRfcmlnaHRzKGZkLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICByZXR1cm4gc2VsZi5mZHNbZmRdLmZkX2Zkc3RhdF9zZXRfcmlnaHRzKGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2ZpbGVzdGF0X2dldChmZCwgZmlsZXN0YXRfcHRyKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIGZpbGVzdGF0IH0gPSBzZWxmLmZkc1tmZF0uZmRfZmlsZXN0YXRfZ2V0KCk7CiAgICAgICAgaWYgKGZpbGVzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIGZpbGVzdGF0LndyaXRlX2J5dGVzKG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKSwgZmlsZXN0YXRfcHRyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfZmlsZXN0YXRfc2V0X3NpemUoZmQsIHNpemUpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICByZXR1cm4gc2VsZi5mZHNbZmRdLmZkX2ZpbGVzdGF0X3NldF9zaXplKHNpemUpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9maWxlc3RhdF9zZXRfdGltZXMoZmQsIGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmlsZXN0YXRfc2V0X3RpbWVzKGF0aW0sIG10aW0sIGZzdF9mbGFncyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3ByZWFkKGZkLCBpb3ZzX3B0ciwgaW92c19sZW4sIG9mZnNldCwgbnJlYWRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IGlvdmVjcyA9IElvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBucmVhZCA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBkYXRhIH0gPSBzZWxmLmZkc1tmZF0uZmRfcHJlYWQoaW92ZWMuYnVmX2xlbiwgb2Zmc2V0KTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgYnVmZmVyOC5zZXQoZGF0YSwgaW92ZWMuYnVmKTsKICAgICAgICAgIG5yZWFkICs9IGRhdGEubGVuZ3RoOwogICAgICAgICAgb2Zmc2V0ICs9IEJpZ0ludChkYXRhLmxlbmd0aCk7CiAgICAgICAgICBpZiAoZGF0YS5sZW5ndGggIT0gaW92ZWMuYnVmX2xlbikgewogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgYnVmZmVyLnNldFVpbnQzMihucmVhZF9wdHIsIG5yZWFkLCB0cnVlKTsKICAgICAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHJlc3RhdF9nZXQoZmQsIGJ1Zl9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHsgcmV0LCBwcmVzdGF0IH0gPSBzZWxmLmZkc1tmZF0uZmRfcHJlc3RhdF9nZXQoKTsKICAgICAgICBpZiAocHJlc3RhdCAhPSBudWxsKSB7CiAgICAgICAgICBwcmVzdGF0LndyaXRlX2J5dGVzKGJ1ZmZlciwgYnVmX3B0cik7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3ByZXN0YXRfZGlyX25hbWUoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbikgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHsgcmV0LCBwcmVzdGF0IH0gPSBzZWxmLmZkc1tmZF0uZmRfcHJlc3RhdF9nZXQoKTsKICAgICAgICBpZiAocHJlc3RhdCA9PSBudWxsKSB7CiAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0KICAgICAgICBjb25zdCBwcmVzdGF0X2Rpcl9uYW1lID0gcHJlc3RhdC5pbm5lci5wcl9uYW1lOwogICAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICBidWZmZXI4LnNldChwcmVzdGF0X2Rpcl9uYW1lLnNsaWNlKDAsIHBhdGhfbGVuKSwgcGF0aF9wdHIpOwogICAgICAgIHJldHVybiBwcmVzdGF0X2Rpcl9uYW1lLmJ5dGVMZW5ndGggPiBwYXRoX2xlbiA/IEVSUk5PX05BTUVUT09MT05HIDogRVJSTk9fU1VDQ0VTUzsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHdyaXRlKGZkLCBpb3ZzX3B0ciwgaW92c19sZW4sIG9mZnNldCwgbndyaXR0ZW5fcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IGlvdmVjcyA9IENpb3ZlYy5yZWFkX2J5dGVzX2FycmF5KGJ1ZmZlciwgaW92c19wdHIsIGlvdnNfbGVuKTsKICAgICAgICBsZXQgbndyaXR0ZW4gPSAwOwogICAgICAgIGZvciAoY29uc3QgaW92ZWMgb2YgaW92ZWNzKSB7CiAgICAgICAgICBjb25zdCBkYXRhID0gYnVmZmVyOC5zbGljZShpb3ZlYy5idWYsIGlvdmVjLmJ1ZiArIGlvdmVjLmJ1Zl9sZW4pOwogICAgICAgICAgY29uc3QgeyByZXQsIG53cml0dGVuOiBud3JpdHRlbl9wYXJ0IH0gPSBzZWxmLmZkc1tmZF0uZmRfcHdyaXRlKGRhdGEsIG9mZnNldCk7CiAgICAgICAgICBpZiAocmV0ICE9IEVSUk5PX1NVQ0NFU1MpIHsKICAgICAgICAgICAgYnVmZmVyLnNldFVpbnQzMihud3JpdHRlbl9wdHIsIG53cml0dGVuLCB0cnVlKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICAgIH0KICAgICAgICAgIG53cml0dGVuICs9IG53cml0dGVuX3BhcnQ7CiAgICAgICAgICBvZmZzZXQgKz0gQmlnSW50KG53cml0dGVuX3BhcnQpOwogICAgICAgICAgaWYgKG53cml0dGVuX3BhcnQgIT0gZGF0YS5ieXRlTGVuZ3RoKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9yZWFkKGZkLCBpb3ZzX3B0ciwgaW92c19sZW4sIG5yZWFkX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBpb3ZlY3MgPSBJb3ZlYy5yZWFkX2J5dGVzX2FycmF5KGJ1ZmZlciwgaW92c19wdHIsIGlvdnNfbGVuKTsKICAgICAgICBsZXQgbnJlYWQgPSAwOwogICAgICAgIGZvciAoY29uc3QgaW92ZWMgb2YgaW92ZWNzKSB7CiAgICAgICAgICBjb25zdCB7IHJldCwgZGF0YSB9ID0gc2VsZi5mZHNbZmRdLmZkX3JlYWQoaW92ZWMuYnVmX2xlbik7CiAgICAgICAgICBpZiAocmV0ICE9IEVSUk5PX1NVQ0NFU1MpIHsKICAgICAgICAgICAgYnVmZmVyLnNldFVpbnQzMihucmVhZF9wdHIsIG5yZWFkLCB0cnVlKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICAgIH0KICAgICAgICAgIGJ1ZmZlcjguc2V0KGRhdGEsIGlvdmVjLmJ1Zik7CiAgICAgICAgICBucmVhZCArPSBkYXRhLmxlbmd0aDsKICAgICAgICAgIGlmIChkYXRhLmxlbmd0aCAhPSBpb3ZlYy5idWZfbGVuKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9yZWFkZGlyKGZkLCBidWYsIGJ1Zl9sZW4sIGNvb2tpZSwgYnVmdXNlZF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgbGV0IGJ1ZnVzZWQgPSAwOwogICAgICAgIHdoaWxlICh0cnVlKSB7CiAgICAgICAgICBjb25zdCB7IHJldCwgZGlyZW50IH0gPSBzZWxmLmZkc1tmZF0uZmRfcmVhZGRpcl9zaW5nbGUoY29va2llKTsKICAgICAgICAgIGlmIChyZXQgIT0gMCkgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKGJ1ZnVzZWRfcHRyLCBidWZ1c2VkLCB0cnVlKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChkaXJlbnQgPT0gbnVsbCkgewogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChidWZfbGVuIC0gYnVmdXNlZCA8IGRpcmVudC5oZWFkX2xlbmd0aCgpKSB7CiAgICAgICAgICAgIGJ1ZnVzZWQgPSBidWZfbGVuOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGhlYWRfYnl0ZXMgPSBuZXcgQXJyYXlCdWZmZXIoZGlyZW50LmhlYWRfbGVuZ3RoKCkpOwogICAgICAgICAgZGlyZW50LndyaXRlX2hlYWRfYnl0ZXMobmV3IERhdGFWaWV3KGhlYWRfYnl0ZXMpLCAwKTsKICAgICAgICAgIGJ1ZmZlcjguc2V0KG5ldyBVaW50OEFycmF5KGhlYWRfYnl0ZXMpLnNsaWNlKDAsIE1hdGgubWluKGhlYWRfYnl0ZXMuYnl0ZUxlbmd0aCwgYnVmX2xlbiAtIGJ1ZnVzZWQpKSwgYnVmKTsKICAgICAgICAgIGJ1ZiArPSBkaXJlbnQuaGVhZF9sZW5ndGgoKTsKICAgICAgICAgIGJ1ZnVzZWQgKz0gZGlyZW50LmhlYWRfbGVuZ3RoKCk7CiAgICAgICAgICBpZiAoYnVmX2xlbiAtIGJ1ZnVzZWQgPCBkaXJlbnQubmFtZV9sZW5ndGgoKSkgewogICAgICAgICAgICBidWZ1c2VkID0gYnVmX2xlbjsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgICBkaXJlbnQud3JpdGVfbmFtZV9ieXRlcyhidWZmZXI4LCBidWYsIGJ1Zl9sZW4gLSBidWZ1c2VkKTsKICAgICAgICAgIGJ1ZiArPSBkaXJlbnQubmFtZV9sZW5ndGgoKTsKICAgICAgICAgIGJ1ZnVzZWQgKz0gZGlyZW50Lm5hbWVfbGVuZ3RoKCk7CiAgICAgICAgICBjb29raWUgPSBkaXJlbnQuZF9uZXh0OwogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKGJ1ZnVzZWRfcHRyLCBidWZ1c2VkLCB0cnVlKTsKICAgICAgICByZXR1cm4gMDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcmVudW1iZXIoZmQsIHRvKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwICYmIHNlbGYuZmRzW3RvXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCByZXQgPSBzZWxmLmZkc1t0b10uZmRfY2xvc2UoKTsKICAgICAgICBpZiAocmV0ICE9IDApIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHNlbGYuZmRzW3RvXSA9IHNlbGYuZmRzW2ZkXTsKICAgICAgICBzZWxmLmZkc1tmZF0gPSB2b2lkIDA7CiAgICAgICAgcmV0dXJuIDA7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3NlZWsoZmQsIG9mZnNldCwgd2hlbmNlLCBvZmZzZXRfb3V0X3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIG9mZnNldDogb2Zmc2V0X291dCB9ID0gc2VsZi5mZHNbZmRdLmZkX3NlZWsob2Zmc2V0LCB3aGVuY2UpOwogICAgICAgIGJ1ZmZlci5zZXRCaWdJbnQ2NChvZmZzZXRfb3V0X3B0ciwgb2Zmc2V0X291dCwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfc3luYyhmZCkgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfc3luYygpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF90ZWxsKGZkLCBvZmZzZXRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgb2Zmc2V0IH0gPSBzZWxmLmZkc1tmZF0uZmRfdGVsbCgpOwogICAgICAgIGJ1ZmZlci5zZXRCaWdVaW50NjQob2Zmc2V0X3B0ciwgb2Zmc2V0LCB0cnVlKTsKICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF93cml0ZShmZCwgaW92c19wdHIsIGlvdnNfbGVuLCBud3JpdHRlbl9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgaW92ZWNzID0gQ2lvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBud3JpdHRlbiA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IGRhdGEgPSBidWZmZXI4LnNsaWNlKGlvdmVjLmJ1ZiwgaW92ZWMuYnVmICsgaW92ZWMuYnVmX2xlbik7CiAgICAgICAgICBjb25zdCB7IHJldCwgbndyaXR0ZW46IG53cml0dGVuX3BhcnQgfSA9IHNlbGYuZmRzW2ZkXS5mZF93cml0ZShkYXRhKTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgbndyaXR0ZW4gKz0gbndyaXR0ZW5fcGFydDsKICAgICAgICAgIGlmIChud3JpdHRlbl9wYXJ0ICE9IGRhdGEuYnl0ZUxlbmd0aCkgewogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgYnVmZmVyLnNldFVpbnQzMihud3JpdHRlbl9wdHIsIG53cml0dGVuLCB0cnVlKTsKICAgICAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9jcmVhdGVfZGlyZWN0b3J5KGZkLCBwYXRoX3B0ciwgcGF0aF9sZW4pIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICByZXR1cm4gc2VsZi5mZHNbZmRdLnBhdGhfY3JlYXRlX2RpcmVjdG9yeShwYXRoKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9maWxlc3RhdF9nZXQoZmQsIGZsYWdzLCBwYXRoX3B0ciwgcGF0aF9sZW4sIGZpbGVzdGF0X3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgY29uc3QgeyByZXQsIGZpbGVzdGF0IH0gPSBzZWxmLmZkc1tmZF0ucGF0aF9maWxlc3RhdF9nZXQoZmxhZ3MsIHBhdGgpOwogICAgICAgIGlmIChmaWxlc3RhdCAhPSBudWxsKSB7CiAgICAgICAgICBmaWxlc3RhdC53cml0ZV9ieXRlcyhidWZmZXIsIGZpbGVzdGF0X3B0cik7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfZmlsZXN0YXRfc2V0X3RpbWVzKGZkLCBmbGFncywgcGF0aF9wdHIsIHBhdGhfbGVuLCBhdGltLCBtdGltLCBmc3RfZmxhZ3MpIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICByZXR1cm4gc2VsZi5mZHNbZmRdLnBhdGhfZmlsZXN0YXRfc2V0X3RpbWVzKGZsYWdzLCBwYXRoLCBhdGltLCBtdGltLCBmc3RfZmxhZ3MpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX2xpbmsob2xkX2ZkLCBvbGRfZmxhZ3MsIG9sZF9wYXRoX3B0ciwgb2xkX3BhdGhfbGVuLCBuZXdfZmQsIG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW29sZF9mZF0gIT0gdm9pZCAwICYmIHNlbGYuZmRzW25ld19mZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3Qgb2xkX3BhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9wdHIgKyBvbGRfcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCBuZXdfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShuZXdfcGF0aF9wdHIsIG5ld19wYXRoX3B0ciArIG5ld19wYXRoX2xlbikpOwogICAgICAgIGNvbnN0IHsgcmV0LCBpbm9kZV9vYmogfSA9IHNlbGYuZmRzW29sZF9mZF0ucGF0aF9sb29rdXAob2xkX3BhdGgsIG9sZF9mbGFncyk7CiAgICAgICAgaWYgKGlub2RlX29iaiA9PSBudWxsKSB7CiAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0KICAgICAgICByZXR1cm4gc2VsZi5mZHNbbmV3X2ZkXS5wYXRoX2xpbmsobmV3X3BhdGgsIGlub2RlX29iaiwgZmFsc2UpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX29wZW4oZmQsIGRpcmZsYWdzLCBwYXRoX3B0ciwgcGF0aF9sZW4sIG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nLCBmZF9mbGFncywgb3BlbmVkX2ZkX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgZGVidWcubG9nKHBhdGgpOwogICAgICAgIGNvbnN0IHsgcmV0LCBmZF9vYmogfSA9IHNlbGYuZmRzW2ZkXS5wYXRoX29wZW4oZGlyZmxhZ3MsIHBhdGgsIG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nLCBmZF9mbGFncyk7CiAgICAgICAgaWYgKHJldCAhPSAwKSB7CiAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0KICAgICAgICBzZWxmLmZkcy5wdXNoKGZkX29iaik7CiAgICAgICAgY29uc3Qgb3BlbmVkX2ZkID0gc2VsZi5mZHMubGVuZ3RoIC0gMTsKICAgICAgICBidWZmZXIuc2V0VWludDMyKG9wZW5lZF9mZF9wdHIsIG9wZW5lZF9mZCwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIDA7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfcmVhZGxpbmsoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbiwgYnVmX3B0ciwgYnVmX2xlbiwgbnJlYWRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICBkZWJ1Zy5sb2cocGF0aCk7CiAgICAgICAgY29uc3QgeyByZXQsIGRhdGEgfSA9IHNlbGYuZmRzW2ZkXS5wYXRoX3JlYWRsaW5rKHBhdGgpOwogICAgICAgIGlmIChkYXRhICE9IG51bGwpIHsKICAgICAgICAgIGNvbnN0IGRhdGFfYnVmID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKGRhdGEpOwogICAgICAgICAgaWYgKGRhdGFfYnVmLmxlbmd0aCA+IGJ1Zl9sZW4pIHsKICAgICAgICAgICAgYnVmZmVyLnNldFVpbnQzMihucmVhZF9wdHIsIDAsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgICAgIH0KICAgICAgICAgIGJ1ZmZlcjguc2V0KGRhdGFfYnVmLCBidWZfcHRyKTsKICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobnJlYWRfcHRyLCBkYXRhX2J1Zi5sZW5ndGgsIHRydWUpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX3JlbW92ZV9kaXJlY3RvcnkoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF9yZW1vdmVfZGlyZWN0b3J5KHBhdGgpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX3JlbmFtZShmZCwgb2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9sZW4sIG5ld19mZCwgbmV3X3BhdGhfcHRyLCBuZXdfcGF0aF9sZW4pIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCAmJiBzZWxmLmZkc1tuZXdfZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IG9sZF9wYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG9sZF9wYXRoX3B0ciwgb2xkX3BhdGhfcHRyICsgb2xkX3BhdGhfbGVuKSk7CiAgICAgICAgY29uc3QgbmV3X3BhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UobmV3X3BhdGhfcHRyLCBuZXdfcGF0aF9wdHIgKyBuZXdfcGF0aF9sZW4pKTsKICAgICAgICBsZXQgeyByZXQsIGlub2RlX29iaiB9ID0gc2VsZi5mZHNbZmRdLnBhdGhfdW5saW5rKG9sZF9wYXRoKTsKICAgICAgICBpZiAoaW5vZGVfb2JqID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHJldCA9IHNlbGYuZmRzW25ld19mZF0ucGF0aF9saW5rKG5ld19wYXRoLCBpbm9kZV9vYmosIHRydWUpOwogICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgaWYgKHNlbGYuZmRzW2ZkXS5wYXRoX2xpbmsob2xkX3BhdGgsIGlub2RlX29iaiwgdHJ1ZSkgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICB0aHJvdyAicGF0aF9saW5rIHNob3VsZCBhbHdheXMgcmV0dXJuIHN1Y2Nlc3Mgd2hlbiByZWxpbmtpbmcgYW4gaW5vZGUgYmFjayB0byB0aGUgb3JpZ2luYWwgcGxhY2UiOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX3N5bWxpbmsob2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9sZW4sIGZkLCBuZXdfcGF0aF9wdHIsIG5ld19wYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3Qgb2xkX3BhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9wdHIgKyBvbGRfcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCBuZXdfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShuZXdfcGF0aF9wdHIsIG5ld19wYXRoX3B0ciArIG5ld19wYXRoX2xlbikpOwogICAgICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfdW5saW5rX2ZpbGUoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF91bmxpbmtfZmlsZShwYXRoKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcG9sbF9vbmVvZmYoaW5fLCBvdXQsIG5zdWJzY3JpcHRpb25zKSB7CiAgICAgIHRocm93ICJhc3luYyBpbyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHByb2NfZXhpdChleGl0X2NvZGUpIHsKICAgICAgdGhyb3cgbmV3IFdBU0lQcm9jRXhpdChleGl0X2NvZGUpOwogICAgfSwgcHJvY19yYWlzZShzaWcpIHsKICAgICAgdGhyb3cgInJhaXNlZCBzaWduYWwgIiArIHNpZzsKICAgIH0sIHNjaGVkX3lpZWxkKCkgewogICAgfSwgcmFuZG9tX2dldChidWYsIGJ1Zl9sZW4pIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGJ1Zl9sZW47IGkrKykgewogICAgICAgIGJ1ZmZlcjhbYnVmICsgaV0gPSBNYXRoLnJhbmRvbSgpICogMjU2IHwgMDsKICAgICAgfQogICAgfSwgc29ja19yZWN2KGZkLCByaV9kYXRhLCByaV9mbGFncykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHNvY2tfc2VuZChmZCwgc2lfZGF0YSwgc2lfZmxhZ3MpIHsKICAgICAgdGhyb3cgInNvY2tldHMgbm90IHN1cHBvcnRlZCI7CiAgICB9LCBzb2NrX3NodXRkb3duKGZkLCBob3cpIHsKICAgICAgdGhyb3cgInNvY2tldHMgbm90IHN1cHBvcnRlZCI7CiAgICB9LCBzb2NrX2FjY2VwdChmZCwgZmxhZ3MpIHsKICAgICAgdGhyb3cgInNvY2tldHMgbm90IHN1cHBvcnRlZCI7CiAgICB9IH07CiAgfQp9OwoKLy8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC9mZC5qcwp2YXIgRmQgPSBjbGFzcyB7CiAgZmRfYWxsb2NhdGUob2Zmc2V0LCBsZW4pIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIGZkX2Nsb3NlKCkgewogICAgcmV0dXJuIDA7CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZmRzdGF0OiBudWxsIH07CiAgfQogIGZkX2Zkc3RhdF9zZXRfZmxhZ3MoZmxhZ3MpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIGZkX2Zkc3RhdF9zZXRfcmlnaHRzKGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfZmlsZXN0YXRfZ2V0KCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGZpbGVzdGF0OiBudWxsIH07CiAgfQogIGZkX2ZpbGVzdGF0X3NldF9zaXplKHNpemUpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIGZkX2ZpbGVzdGF0X3NldF90aW1lcyhhdGltLCBtdGltLCBmc3RfZmxhZ3MpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIGZkX3ByZWFkKHNpemUsIG9mZnNldCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGRhdGE6IG5ldyBVaW50OEFycmF5KCkgfTsKICB9CiAgZmRfcHJlc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgcHJlc3RhdDogbnVsbCB9OwogIH0KICBmZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgbndyaXR0ZW46IDAgfTsKICB9CiAgZmRfcmVhZChzaXplKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZGF0YTogbmV3IFVpbnQ4QXJyYXkoKSB9OwogIH0KICBmZF9yZWFkZGlyX3NpbmdsZShjb29raWUpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBkaXJlbnQ6IG51bGwgfTsKICB9CiAgZmRfc2VlayhvZmZzZXQsIHdoZW5jZSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIG9mZnNldDogMG4gfTsKICB9CiAgZmRfc3luYygpIHsKICAgIHJldHVybiAwOwogIH0KICBmZF90ZWxsKCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIG9mZnNldDogMG4gfTsKICB9CiAgZmRfd3JpdGUoZGF0YSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIG53cml0dGVuOiAwIH07CiAgfQogIHBhdGhfY3JlYXRlX2RpcmVjdG9yeShwYXRoKSB7CiAgICByZXR1cm4gRVJSTk9fTk9UU1VQOwogIH0KICBwYXRoX2ZpbGVzdGF0X2dldChmbGFncywgcGF0aCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGZpbGVzdGF0OiBudWxsIH07CiAgfQogIHBhdGhfZmlsZXN0YXRfc2V0X3RpbWVzKGZsYWdzLCBwYXRoLCBhdGltLCBtdGltLCBmc3RfZmxhZ3MpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfbGluayhwYXRoLCBpbm9kZSwgYWxsb3dfZGlyKSB7CiAgICByZXR1cm4gRVJSTk9fTk9UU1VQOwogIH0KICBwYXRoX3VubGluayhwYXRoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgaW5vZGVfb2JqOiBudWxsIH07CiAgfQogIHBhdGhfbG9va3VwKHBhdGgsIGRpcmZsYWdzKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgaW5vZGVfb2JqOiBudWxsIH07CiAgfQogIHBhdGhfb3BlbihkaXJmbGFncywgcGF0aCwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgZmRfb2JqOiBudWxsIH07CiAgfQogIHBhdGhfcmVhZGxpbmsocGF0aCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGRhdGE6IG51bGwgfTsKICB9CiAgcGF0aF9yZW1vdmVfZGlyZWN0b3J5KHBhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfcmVuYW1lKG9sZF9wYXRoLCBuZXdfZmQsIG5ld19wYXRoKSB7CiAgICByZXR1cm4gRVJSTk9fTk9UU1VQOwogIH0KICBwYXRoX3VubGlua19maWxlKHBhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQp9Owp2YXIgSW5vZGUgPSBjbGFzcyB7Cn07CgovLyBub2RlX21vZHVsZXMvQGJqb3JuMy9icm93c2VyX3dhc2lfc2hpbS9kaXN0L2ZzX21lbS5qcwp2YXIgT3BlbkZpbGUgPSBjbGFzcyBleHRlbmRzIEZkIHsKICBmZF9hbGxvY2F0ZShvZmZzZXQsIGxlbikgewogICAgaWYgKHRoaXMuZmlsZS5zaXplID4gb2Zmc2V0ICsgbGVuKSB7CiAgICB9IGVsc2UgewogICAgICBjb25zdCBuZXdfZGF0YSA9IG5ldyBVaW50OEFycmF5KE51bWJlcihvZmZzZXQgKyBsZW4pKTsKICAgICAgbmV3X2RhdGEuc2V0KHRoaXMuZmlsZS5kYXRhLCAwKTsKICAgICAgdGhpcy5maWxlLmRhdGEgPSBuZXdfZGF0YTsKICAgIH0KICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogIH0KICBmZF9mZHN0YXRfZ2V0KCkgewogICAgcmV0dXJuIHsgcmV0OiAwLCBmZHN0YXQ6IG5ldyBGZHN0YXQoRklMRVRZUEVfUkVHVUxBUl9GSUxFLCAwKSB9OwogIH0KICBmZF9maWxlc3RhdF9zZXRfc2l6ZShzaXplKSB7CiAgICBpZiAodGhpcy5maWxlLnNpemUgPiBzaXplKSB7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5maWxlLmRhdGEuYnVmZmVyLnNsaWNlKDAsIE51bWJlcihzaXplKSkpOwogICAgfSBlbHNlIHsKICAgICAgY29uc3QgbmV3X2RhdGEgPSBuZXcgVWludDhBcnJheShOdW1iZXIoc2l6ZSkpOwogICAgICBuZXdfZGF0YS5zZXQodGhpcy5maWxlLmRhdGEsIDApOwogICAgICB0aGlzLmZpbGUuZGF0YSA9IG5ld19kYXRhOwogICAgfQogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIGZkX3JlYWQoc2l6ZSkgewogICAgY29uc3Qgc2xpY2UgPSB0aGlzLmZpbGUuZGF0YS5zbGljZShOdW1iZXIodGhpcy5maWxlX3BvcyksIE51bWJlcih0aGlzLmZpbGVfcG9zICsgQmlnSW50KHNpemUpKSk7CiAgICB0aGlzLmZpbGVfcG9zICs9IEJpZ0ludChzbGljZS5sZW5ndGgpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBkYXRhOiBzbGljZSB9OwogIH0KICBmZF9wcmVhZChzaXplLCBvZmZzZXQpIHsKICAgIGNvbnN0IHNsaWNlID0gdGhpcy5maWxlLmRhdGEuc2xpY2UoTnVtYmVyKG9mZnNldCksIE51bWJlcihvZmZzZXQgKyBCaWdJbnQoc2l6ZSkpKTsKICAgIHJldHVybiB7IHJldDogMCwgZGF0YTogc2xpY2UgfTsKICB9CiAgZmRfc2VlayhvZmZzZXQsIHdoZW5jZSkgewogICAgbGV0IGNhbGN1bGF0ZWRfb2Zmc2V0OwogICAgc3dpdGNoICh3aGVuY2UpIHsKICAgICAgY2FzZSBXSEVOQ0VfU0VUOgogICAgICAgIGNhbGN1bGF0ZWRfb2Zmc2V0ID0gb2Zmc2V0OwogICAgICAgIGJyZWFrOwogICAgICBjYXNlIFdIRU5DRV9DVVI6CiAgICAgICAgY2FsY3VsYXRlZF9vZmZzZXQgPSB0aGlzLmZpbGVfcG9zICsgb2Zmc2V0OwogICAgICAgIGJyZWFrOwogICAgICBjYXNlIFdIRU5DRV9FTkQ6CiAgICAgICAgY2FsY3VsYXRlZF9vZmZzZXQgPSBCaWdJbnQodGhpcy5maWxlLmRhdGEuYnl0ZUxlbmd0aCkgKyBvZmZzZXQ7CiAgICAgICAgYnJlYWs7CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19JTlZBTCwgb2Zmc2V0OiAwbiB9OwogICAgfQogICAgaWYgKGNhbGN1bGF0ZWRfb2Zmc2V0IDwgMCkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0lOVkFMLCBvZmZzZXQ6IDBuIH07CiAgICB9CiAgICB0aGlzLmZpbGVfcG9zID0gY2FsY3VsYXRlZF9vZmZzZXQ7CiAgICByZXR1cm4geyByZXQ6IDAsIG9mZnNldDogdGhpcy5maWxlX3BvcyB9OwogIH0KICBmZF90ZWxsKCkgewogICAgcmV0dXJuIHsgcmV0OiAwLCBvZmZzZXQ6IHRoaXMuZmlsZV9wb3MgfTsKICB9CiAgZmRfd3JpdGUoZGF0YSkgewogICAgaWYgKHRoaXMuZmlsZS5yZWFkb25seSkKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBud3JpdHRlbjogMCB9OwogICAgaWYgKHRoaXMuZmlsZV9wb3MgKyBCaWdJbnQoZGF0YS5ieXRlTGVuZ3RoKSA+IHRoaXMuZmlsZS5zaXplKSB7CiAgICAgIGNvbnN0IG9sZCA9IHRoaXMuZmlsZS5kYXRhOwogICAgICB0aGlzLmZpbGUuZGF0YSA9IG5ldyBVaW50OEFycmF5KE51bWJlcih0aGlzLmZpbGVfcG9zICsgQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCkpKTsKICAgICAgdGhpcy5maWxlLmRhdGEuc2V0KG9sZCk7CiAgICB9CiAgICB0aGlzLmZpbGUuZGF0YS5zZXQoZGF0YSwgTnVtYmVyKHRoaXMuZmlsZV9wb3MpKTsKICAgIHRoaXMuZmlsZV9wb3MgKz0gQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCk7CiAgICByZXR1cm4geyByZXQ6IDAsIG53cml0dGVuOiBkYXRhLmJ5dGVMZW5ndGggfTsKICB9CiAgZmRfcHdyaXRlKGRhdGEsIG9mZnNldCkgewogICAgaWYgKHRoaXMuZmlsZS5yZWFkb25seSkKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBud3JpdHRlbjogMCB9OwogICAgaWYgKG9mZnNldCArIEJpZ0ludChkYXRhLmJ5dGVMZW5ndGgpID4gdGhpcy5maWxlLnNpemUpIHsKICAgICAgY29uc3Qgb2xkID0gdGhpcy5maWxlLmRhdGE7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoTnVtYmVyKG9mZnNldCArIEJpZ0ludChkYXRhLmJ5dGVMZW5ndGgpKSk7CiAgICAgIHRoaXMuZmlsZS5kYXRhLnNldChvbGQpOwogICAgfQogICAgdGhpcy5maWxlLmRhdGEuc2V0KGRhdGEsIE51bWJlcihvZmZzZXQpKTsKICAgIHJldHVybiB7IHJldDogMCwgbndyaXR0ZW46IGRhdGEuYnl0ZUxlbmd0aCB9OwogIH0KICBmZF9maWxlc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIGZpbGVzdGF0OiB0aGlzLmZpbGUuc3RhdCgpIH07CiAgfQogIGNvbnN0cnVjdG9yKGZpbGUpIHsKICAgIHN1cGVyKCk7CiAgICB0aGlzLmZpbGVfcG9zID0gMG47CiAgICB0aGlzLmZpbGUgPSBmaWxlOwogIH0KfTsKdmFyIE9wZW5EaXJlY3RvcnkgPSBjbGFzcyBleHRlbmRzIEZkIHsKICBmZF9zZWVrKG9mZnNldCwgd2hlbmNlKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG9mZnNldDogMG4gfTsKICB9CiAgZmRfdGVsbCgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fQkFERiwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF9hbGxvY2F0ZShvZmZzZXQsIGxlbikgewogICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIGZkc3RhdDogbmV3IEZkc3RhdChGSUxFVFlQRV9ESVJFQ1RPUlksIDApIH07CiAgfQogIGZkX3JlYWRkaXJfc2luZ2xlKGNvb2tpZSkgewogICAgaWYgKGRlYnVnLmVuYWJsZWQpIHsKICAgICAgZGVidWcubG9nKCJyZWFkZGlyX3NpbmdsZSIsIGNvb2tpZSk7CiAgICAgIGRlYnVnLmxvZyhjb29raWUsIHRoaXMuZGlyLmNvbnRlbnRzLmtleXMoKSk7CiAgICB9CiAgICBpZiAoY29va2llID09IDBuKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZGlyZW50OiBuZXcgRGlyZW50KDFuLCAiLiIsIEZJTEVUWVBFX0RJUkVDVE9SWSkgfTsKICAgIH0gZWxzZSBpZiAoY29va2llID09IDFuKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZGlyZW50OiBuZXcgRGlyZW50KDJuLCAiLi4iLCBGSUxFVFlQRV9ESVJFQ1RPUlkpIH07CiAgICB9CiAgICBpZiAoY29va2llID49IEJpZ0ludCh0aGlzLmRpci5jb250ZW50cy5zaXplKSArIDJuKSB7CiAgICAgIHJldHVybiB7IHJldDogMCwgZGlyZW50OiBudWxsIH07CiAgICB9CiAgICBjb25zdCBbbmFtZSwgZW50cnldID0gQXJyYXkuZnJvbSh0aGlzLmRpci5jb250ZW50cy5lbnRyaWVzKCkpW051bWJlcihjb29raWUgLSAybildOwogICAgcmV0dXJuIHsgcmV0OiAwLCBkaXJlbnQ6IG5ldyBEaXJlbnQoY29va2llICsgMW4sIG5hbWUsIGVudHJ5LnN0YXQoKS5maWxldHlwZSkgfTsKICB9CiAgcGF0aF9maWxlc3RhdF9nZXQoZmxhZ3MsIHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9lcnIsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogcGF0aF9lcnIsIGZpbGVzdGF0OiBudWxsIH07CiAgICB9CiAgICBjb25zdCB7IHJldCwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9lbnRyeV9mb3JfcGF0aChwYXRoKTsKICAgIGlmIChlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldCwgZmlsZXN0YXQ6IG51bGwgfTsKICAgIH0KICAgIHJldHVybiB7IHJldDogMCwgZmlsZXN0YXQ6IGVudHJ5LnN0YXQoKSB9OwogIH0KICBwYXRoX2xvb2t1cChwYXRoX3N0ciwgZGlyZmxhZ3MpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX3JldCwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX3JldCwgaW5vZGVfb2JqOiBudWxsIH07CiAgICB9CiAgICBjb25zdCB7IHJldCwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9lbnRyeV9mb3JfcGF0aChwYXRoKTsKICAgIGlmIChlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldCwgaW5vZGVfb2JqOiBudWxsIH07CiAgICB9CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGlub2RlX29iajogZW50cnkgfTsKICB9CiAgcGF0aF9vcGVuKGRpcmZsYWdzLCBwYXRoX3N0ciwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogcGF0aF9yZXQsIGZkX29iajogbnVsbCB9OwogICAgfQogICAgbGV0IHsgcmV0LCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgaWYgKHJldCAhPSBFUlJOT19OT0VOVCkgewogICAgICAgIHJldHVybiB7IHJldCwgZmRfb2JqOiBudWxsIH07CiAgICAgIH0KICAgICAgaWYgKChvZmxhZ3MgJiBPRkxBR1NfQ1JFQVQpID09IE9GTEFHU19DUkVBVCkgewogICAgICAgIGNvbnN0IHsgcmV0OiByZXQyLCBlbnRyeTogbmV3X2VudHJ5IH0gPSB0aGlzLmRpci5jcmVhdGVfZW50cnlfZm9yX3BhdGgocGF0aF9zdHIsIChvZmxhZ3MgJiBPRkxBR1NfRElSRUNUT1JZKSA9PSBPRkxBR1NfRElSRUNUT1JZKTsKICAgICAgICBpZiAobmV3X2VudHJ5ID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiB7IHJldDogcmV0MiwgZmRfb2JqOiBudWxsIH07CiAgICAgICAgfQogICAgICAgIGVudHJ5ID0gbmV3X2VudHJ5OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9FTlQsIGZkX29iajogbnVsbCB9OwogICAgICB9CiAgICB9IGVsc2UgaWYgKChvZmxhZ3MgJiBPRkxBR1NfRVhDTCkgPT0gT0ZMQUdTX0VYQ0wpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19FWElTVCwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICBpZiAoKG9mbGFncyAmIE9GTEFHU19ESVJFQ1RPUlkpID09IE9GTEFHU19ESVJFQ1RPUlkgJiYgZW50cnkuc3RhdCgpLmZpbGV0eXBlICE9PSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIGZkX29iajogbnVsbCB9OwogICAgfQogICAgcmV0dXJuIGVudHJ5LnBhdGhfb3BlbihvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmZF9mbGFncyk7CiAgfQogIHBhdGhfY3JlYXRlX2RpcmVjdG9yeShwYXRoKSB7CiAgICByZXR1cm4gdGhpcy5wYXRoX29wZW4oMCwgcGF0aCwgT0ZMQUdTX0NSRUFUIHwgT0ZMQUdTX0RJUkVDVE9SWSwgMG4sIDBuLCAwKS5yZXQ7CiAgfQogIHBhdGhfbGluayhwYXRoX3N0ciwgaW5vZGUsIGFsbG93X2RpcikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4gcGF0aF9yZXQ7CiAgICB9CiAgICBpZiAocGF0aC5pc19kaXIpIHsKICAgICAgcmV0dXJuIEVSUk5PX05PRU5UOwogICAgfQogICAgY29uc3QgeyByZXQ6IHBhcmVudF9yZXQsIHBhcmVudF9lbnRyeSwgZmlsZW5hbWUsIGVudHJ5IH0gPSB0aGlzLmRpci5nZXRfcGFyZW50X2Rpcl9hbmRfZW50cnlfZm9yX3BhdGgocGF0aCwgdHJ1ZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm4gcGFyZW50X3JldDsKICAgIH0KICAgIGlmIChlbnRyeSAhPSBudWxsKSB7CiAgICAgIGNvbnN0IHNvdXJjZV9pc19kaXIgPSBpbm9kZS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfRElSRUNUT1JZOwogICAgICBjb25zdCB0YXJnZXRfaXNfZGlyID0gZW50cnkuc3RhdCgpLmZpbGV0eXBlID09IEZJTEVUWVBFX0RJUkVDVE9SWTsKICAgICAgaWYgKHNvdXJjZV9pc19kaXIgJiYgdGFyZ2V0X2lzX2RpcikgewogICAgICAgIGlmIChhbGxvd19kaXIgJiYgZW50cnkgaW5zdGFuY2VvZiBEaXJlY3RvcnkpIHsKICAgICAgICAgIGlmIChlbnRyeS5jb250ZW50cy5zaXplID09IDApIHsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJldHVybiBFUlJOT19OT1RFTVBUWTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmV0dXJuIEVSUk5PX0VYSVNUOwogICAgICAgIH0KICAgICAgfSBlbHNlIGlmIChzb3VyY2VfaXNfZGlyICYmICF0YXJnZXRfaXNfZGlyKSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX05PVERJUjsKICAgICAgfSBlbHNlIGlmICghc291cmNlX2lzX2RpciAmJiB0YXJnZXRfaXNfZGlyKSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0lTRElSOwogICAgICB9IGVsc2UgaWYgKGlub2RlLnN0YXQoKS5maWxldHlwZSA9PSBGSUxFVFlQRV9SRUdVTEFSX0ZJTEUgJiYgZW50cnkuc3RhdCgpLmZpbGV0eXBlID09IEZJTEVUWVBFX1JFR1VMQVJfRklMRSkgewogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19FWElTVDsKICAgICAgfQogICAgfQogICAgaWYgKCFhbGxvd19kaXIgJiYgaW5vZGUuc3RhdCgpLmZpbGV0eXBlID09IEZJTEVUWVBFX0RJUkVDVE9SWSkgewogICAgICByZXR1cm4gRVJSTk9fUEVSTTsKICAgIH0KICAgIHBhcmVudF9lbnRyeS5jb250ZW50cy5zZXQoZmlsZW5hbWUsIGlub2RlKTsKICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogIH0KICBwYXRoX3VubGluayhwYXRoX3N0cikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhdGhfcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIHRydWUpOwogICAgaWYgKHBhcmVudF9lbnRyeSA9PSBudWxsIHx8IGZpbGVuYW1lID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXJlbnRfcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIGlmIChlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9FTlQsIGlub2RlX29iajogbnVsbCB9OwogICAgfQogICAgcGFyZW50X2VudHJ5LmNvbnRlbnRzLmRlbGV0ZShmaWxlbmFtZSk7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGlub2RlX29iajogZW50cnkgfTsKICB9CiAgcGF0aF91bmxpbmtfZmlsZShwYXRoX3N0cikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4gcGF0aF9yZXQ7CiAgICB9CiAgICBjb25zdCB7IHJldDogcGFyZW50X3JldCwgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9wYXJlbnRfZGlyX2FuZF9lbnRyeV9mb3JfcGF0aChwYXRoLCBmYWxzZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCB8fCBlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXJlbnRfcmV0OwogICAgfQogICAgaWYgKGVudHJ5LnN0YXQoKS5maWxldHlwZSA9PT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgIHJldHVybiBFUlJOT19JU0RJUjsKICAgIH0KICAgIHBhcmVudF9lbnRyeS5jb250ZW50cy5kZWxldGUoZmlsZW5hbWUpOwogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIHBhdGhfcmVtb3ZlX2RpcmVjdG9yeShwYXRoX3N0cikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4gcGF0aF9yZXQ7CiAgICB9CiAgICBjb25zdCB7IHJldDogcGFyZW50X3JldCwgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9wYXJlbnRfZGlyX2FuZF9lbnRyeV9mb3JfcGF0aChwYXRoLCBmYWxzZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCB8fCBlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXJlbnRfcmV0OwogICAgfQogICAgaWYgKCEoZW50cnkgaW5zdGFuY2VvZiBEaXJlY3RvcnkpIHx8IGVudHJ5LnN0YXQoKS5maWxldHlwZSAhPT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgIHJldHVybiBFUlJOT19OT1RESVI7CiAgICB9CiAgICBpZiAoZW50cnkuY29udGVudHMuc2l6ZSAhPT0gMCkgewogICAgICByZXR1cm4gRVJSTk9fTk9URU1QVFk7CiAgICB9CiAgICBpZiAoIXBhcmVudF9lbnRyeS5jb250ZW50cy5kZWxldGUoZmlsZW5hbWUpKSB7CiAgICAgIHJldHVybiBFUlJOT19OT0VOVDsKICAgIH0KICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogIH0KICBmZF9maWxlc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIGZpbGVzdGF0OiB0aGlzLmRpci5zdGF0KCkgfTsKICB9CiAgZmRfZmlsZXN0YXRfc2V0X3NpemUoc2l6ZSkgewogICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgfQogIGZkX3JlYWQoc2l6ZSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBkYXRhOiBuZXcgVWludDhBcnJheSgpIH07CiAgfQogIGZkX3ByZWFkKHNpemUsIG9mZnNldCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBkYXRhOiBuZXcgVWludDhBcnJheSgpIH07CiAgfQogIGZkX3dyaXRlKGRhdGEpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fQkFERiwgbndyaXR0ZW46IDAgfTsKICB9CiAgZmRfcHdyaXRlKGRhdGEsIG9mZnNldCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBud3JpdHRlbjogMCB9OwogIH0KICBjb25zdHJ1Y3RvcihkaXIpIHsKICAgIHN1cGVyKCk7CiAgICB0aGlzLmRpciA9IGRpcjsKICB9Cn07CnZhciBQcmVvcGVuRGlyZWN0b3J5ID0gY2xhc3MgZXh0ZW5kcyBPcGVuRGlyZWN0b3J5IHsKICBmZF9wcmVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgcHJlc3RhdDogUHJlc3RhdC5kaXIodGhpcy5wcmVzdGF0X25hbWUpIH07CiAgfQogIGNvbnN0cnVjdG9yKG5hbWUsIGNvbnRlbnRzKSB7CiAgICBzdXBlcihuZXcgRGlyZWN0b3J5KGNvbnRlbnRzKSk7CiAgICB0aGlzLnByZXN0YXRfbmFtZSA9IG5hbWU7CiAgfQp9Owp2YXIgRmlsZSA9IGNsYXNzIGV4dGVuZHMgSW5vZGUgewogIHBhdGhfb3BlbihvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmZF9mbGFncykgewogICAgaWYgKHRoaXMucmVhZG9ubHkgJiYgKGZzX3JpZ2h0c19iYXNlICYgQmlnSW50KFJJR0hUU19GRF9XUklURSkpID09IEJpZ0ludChSSUdIVFNfRkRfV1JJVEUpKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fUEVSTSwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICBpZiAoKG9mbGFncyAmIE9GTEFHU19UUlVOQykgPT0gT0ZMQUdTX1RSVU5DKSB7CiAgICAgIGlmICh0aGlzLnJlYWRvbmx5KQogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fUEVSTSwgZmRfb2JqOiBudWxsIH07CiAgICAgIHRoaXMuZGF0YSA9IG5ldyBVaW50OEFycmF5KFtdKTsKICAgIH0KICAgIGNvbnN0IGZpbGUgPSBuZXcgT3BlbkZpbGUodGhpcyk7CiAgICBpZiAoZmRfZmxhZ3MgJiBGREZMQUdTX0FQUEVORCkKICAgICAgZmlsZS5mZF9zZWVrKDBuLCBXSEVOQ0VfRU5EKTsKICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZmRfb2JqOiBmaWxlIH07CiAgfQogIGdldCBzaXplKCkgewogICAgcmV0dXJuIEJpZ0ludCh0aGlzLmRhdGEuYnl0ZUxlbmd0aCk7CiAgfQogIHN0YXQoKSB7CiAgICByZXR1cm4gbmV3IEZpbGVzdGF0KEZJTEVUWVBFX1JFR1VMQVJfRklMRSwgdGhpcy5zaXplKTsKICB9CiAgY29uc3RydWN0b3IoZGF0YSwgb3B0aW9ucykgewogICAgc3VwZXIoKTsKICAgIHRoaXMuZGF0YSA9IG5ldyBVaW50OEFycmF5KGRhdGEpOwogICAgdGhpcy5yZWFkb25seSA9ICEhb3B0aW9ucz8ucmVhZG9ubHk7CiAgfQp9Owp2YXIgUGF0aCA9IGNsYXNzIFBhdGgyIHsKICBzdGF0aWMgZnJvbShwYXRoKSB7CiAgICBjb25zdCBzZWxmID0gbmV3IFBhdGgyKCk7CiAgICBzZWxmLmlzX2RpciA9IHBhdGguZW5kc1dpdGgoIi8iKTsKICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoIi8iKSkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVENBUEFCTEUsIHBhdGg6IG51bGwgfTsKICAgIH0KICAgIGlmIChwYXRoLmluY2x1ZGVzKCJcMCIpKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fSU5WQUwsIHBhdGg6IG51bGwgfTsKICAgIH0KICAgIGZvciAoY29uc3QgY29tcG9uZW50IG9mIHBhdGguc3BsaXQoIi8iKSkgewogICAgICBpZiAoY29tcG9uZW50ID09PSAiIiB8fCBjb21wb25lbnQgPT09ICIuIikgewogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGlmIChjb21wb25lbnQgPT09ICIuLiIpIHsKICAgICAgICBpZiAoc2VsZi5wYXJ0cy5wb3AoKSA9PSB2b2lkIDApIHsKICAgICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UQ0FQQUJMRSwgcGF0aDogbnVsbCB9OwogICAgICAgIH0KICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICBzZWxmLnBhcnRzLnB1c2goY29tcG9uZW50KTsKICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgcGF0aDogc2VsZiB9OwogIH0KICB0b19wYXRoX3N0cmluZygpIHsKICAgIGxldCBzID0gdGhpcy5wYXJ0cy5qb2luKCIvIik7CiAgICBpZiAodGhpcy5pc19kaXIpIHsKICAgICAgcyArPSAiLyI7CiAgICB9CiAgICByZXR1cm4gczsKICB9CiAgY29uc3RydWN0b3IoKSB7CiAgICB0aGlzLnBhcnRzID0gW107CiAgICB0aGlzLmlzX2RpciA9IGZhbHNlOwogIH0KfTsKdmFyIERpcmVjdG9yeSA9IGNsYXNzIGV4dGVuZHMgSW5vZGUgewogIHBhdGhfb3BlbihvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmZF9mbGFncykgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBmZF9vYmo6IG5ldyBPcGVuRGlyZWN0b3J5KHRoaXMpIH07CiAgfQogIHN0YXQoKSB7CiAgICByZXR1cm4gbmV3IEZpbGVzdGF0KEZJTEVUWVBFX0RJUkVDVE9SWSwgMG4pOwogIH0KICBnZXRfZW50cnlfZm9yX3BhdGgocGF0aCkgewogICAgbGV0IGVudHJ5ID0gdGhpczsKICAgIGZvciAoY29uc3QgY29tcG9uZW50IG9mIHBhdGgucGFydHMpIHsKICAgICAgaWYgKCEoZW50cnkgaW5zdGFuY2VvZiBEaXJlY3RvcnkpKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIGVudHJ5OiBudWxsIH07CiAgICAgIH0KICAgICAgY29uc3QgY2hpbGQgPSBlbnRyeS5jb250ZW50cy5nZXQoY29tcG9uZW50KTsKICAgICAgaWYgKGNoaWxkICE9PSB2b2lkIDApIHsKICAgICAgICBlbnRyeSA9IGNoaWxkOwogICAgICB9IGVsc2UgewogICAgICAgIGRlYnVnLmxvZyhjb21wb25lbnQpOwogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9FTlQsIGVudHJ5OiBudWxsIH07CiAgICAgIH0KICAgIH0KICAgIGlmIChwYXRoLmlzX2RpcikgewogICAgICBpZiAoZW50cnkuc3RhdCgpLmZpbGV0eXBlICE9IEZJTEVUWVBFX0RJUkVDVE9SWSkgewogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9URElSLCBlbnRyeTogbnVsbCB9OwogICAgICB9CiAgICB9CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGVudHJ5IH07CiAgfQogIGdldF9wYXJlbnRfZGlyX2FuZF9lbnRyeV9mb3JfcGF0aChwYXRoLCBhbGxvd191bmRlZmluZWQpIHsKICAgIGNvbnN0IGZpbGVuYW1lID0gcGF0aC5wYXJ0cy5wb3AoKTsKICAgIGlmIChmaWxlbmFtZSA9PT0gdm9pZCAwKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fSU5WQUwsIHBhcmVudF9lbnRyeTogbnVsbCwgZmlsZW5hbWU6IG51bGwsIGVudHJ5OiBudWxsIH07CiAgICB9CiAgICBjb25zdCB7IHJldDogZW50cnlfcmV0LCBlbnRyeTogcGFyZW50X2VudHJ5IH0gPSB0aGlzLmdldF9lbnRyeV9mb3JfcGF0aChwYXRoKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IGVudHJ5X3JldCwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGlmICghKHBhcmVudF9lbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIHBhcmVudF9lbnRyeTogbnVsbCwgZmlsZW5hbWU6IG51bGwsIGVudHJ5OiBudWxsIH07CiAgICB9CiAgICBjb25zdCBlbnRyeSA9IHBhcmVudF9lbnRyeS5jb250ZW50cy5nZXQoZmlsZW5hbWUpOwogICAgaWYgKGVudHJ5ID09PSB2b2lkIDApIHsKICAgICAgaWYgKCFhbGxvd191bmRlZmluZWQpIHsKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PRU5ULCBwYXJlbnRfZW50cnk6IG51bGwsIGZpbGVuYW1lOiBudWxsLCBlbnRyeTogbnVsbCB9OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgfQogICAgaWYgKHBhdGguaXNfZGlyKSB7CiAgICAgIGlmIChlbnRyeS5zdGF0KCkuZmlsZXR5cGUgIT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIHBhcmVudF9lbnRyeTogbnVsbCwgZmlsZW5hbWU6IG51bGwsIGVudHJ5OiBudWxsIH07CiAgICAgIH0KICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfTsKICB9CiAgY3JlYXRlX2VudHJ5X2Zvcl9wYXRoKHBhdGhfc3RyLCBpc19kaXIpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX3JldCwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX3JldCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGxldCB7IHJldDogcGFyZW50X3JldCwgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfSA9IHRoaXMuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIHRydWUpOwogICAgaWYgKHBhcmVudF9lbnRyeSA9PSBudWxsIHx8IGZpbGVuYW1lID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXJlbnRfcmV0LCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgaWYgKGVudHJ5ICE9IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19FWElTVCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGRlYnVnLmxvZygiY3JlYXRlIiwgcGF0aCk7CiAgICBsZXQgbmV3X2NoaWxkOwogICAgaWYgKCFpc19kaXIpIHsKICAgICAgbmV3X2NoaWxkID0gbmV3IEZpbGUobmV3IEFycmF5QnVmZmVyKDApKTsKICAgIH0gZWxzZSB7CiAgICAgIG5ld19jaGlsZCA9IG5ldyBEaXJlY3RvcnkoLyogQF9fUFVSRV9fICovIG5ldyBNYXAoKSk7CiAgICB9CiAgICBwYXJlbnRfZW50cnkuY29udGVudHMuc2V0KGZpbGVuYW1lLCBuZXdfY2hpbGQpOwogICAgZW50cnkgPSBuZXdfY2hpbGQ7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGVudHJ5IH07CiAgfQogIGNvbnN0cnVjdG9yKGNvbnRlbnRzKSB7CiAgICBzdXBlcigpOwogICAgaWYgKGNvbnRlbnRzIGluc3RhbmNlb2YgQXJyYXkpIHsKICAgICAgdGhpcy5jb250ZW50cyA9IG5ldyBNYXAoY29udGVudHMpOwogICAgfSBlbHNlIHsKICAgICAgdGhpcy5jb250ZW50cyA9IGNvbnRlbnRzOwogICAgfQogIH0KfTsKdmFyIENvbnNvbGVTdGRvdXQgPSBjbGFzcyBleHRlbmRzIEZkIHsKICBmZF9maWxlc3RhdF9nZXQoKSB7CiAgICBjb25zdCBmaWxlc3RhdCA9IG5ldyBGaWxlc3RhdChGSUxFVFlQRV9DSEFSQUNURVJfREVWSUNFLCBCaWdJbnQoMCkpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBmaWxlc3RhdCB9OwogIH0KICBmZF9mZHN0YXRfZ2V0KCkgewogICAgY29uc3QgZmRzdGF0ID0gbmV3IEZkc3RhdChGSUxFVFlQRV9DSEFSQUNURVJfREVWSUNFLCAwKTsKICAgIGZkc3RhdC5mc19yaWdodHNfYmFzZSA9IEJpZ0ludChSSUdIVFNfRkRfV1JJVEUpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBmZHN0YXQgfTsKICB9CiAgZmRfd3JpdGUoZGF0YSkgewogICAgdGhpcy53cml0ZShkYXRhKTsKICAgIHJldHVybiB7IHJldDogMCwgbndyaXR0ZW46IGRhdGEuYnl0ZUxlbmd0aCB9OwogIH0KICBzdGF0aWMgbGluZUJ1ZmZlcmVkKHdyaXRlKSB7CiAgICBjb25zdCBkZWMgPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IiwgeyBmYXRhbDogZmFsc2UgfSk7CiAgICBsZXQgbGluZV9idWYgPSAiIjsKICAgIHJldHVybiBuZXcgQ29uc29sZVN0ZG91dCgoYnVmZmVyKSA9PiB7CiAgICAgIGxpbmVfYnVmICs9IGRlYy5kZWNvZGUoYnVmZmVyLCB7IHN0cmVhbTogdHJ1ZSB9KTsKICAgICAgY29uc3QgbGluZXMgPSBsaW5lX2J1Zi5zcGxpdCgiXG4iKTsKICAgICAgZm9yIChjb25zdCBbaSwgbGluZV0gb2YgbGluZXMuZW50cmllcygpKSB7CiAgICAgICAgaWYgKGkgPCBsaW5lcy5sZW5ndGggLSAxKSB7CiAgICAgICAgICB3cml0ZShsaW5lKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgbGluZV9idWYgPSBsaW5lOwogICAgICAgIH0KICAgICAgfQogICAgfSk7CiAgfQogIGNvbnN0cnVjdG9yKHdyaXRlKSB7CiAgICBzdXBlcigpOwogICAgdGhpcy53cml0ZSA9IHdyaXRlOwogIH0KfTsKCi8vIG5vZGVfbW9kdWxlcy93YXNtLWltcG9ydHMtcGFyc2VyL2luZGV4LmpzCmZ1bmN0aW9uIHBhcnNlSW1wb3J0cyhtb2R1bGVCeXRlcykgewogIGlmIChtb2R1bGVCeXRlcyBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHsKICB9IGVsc2UgaWYgKG1vZHVsZUJ5dGVzIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHsKICAgIG1vZHVsZUJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkobW9kdWxlQnl0ZXMpOwogIH0gZWxzZSBpZiAobW9kdWxlQnl0ZXMuYnVmZmVyIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHsKICAgIG1vZHVsZUJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkobW9kdWxlQnl0ZXMuYnVmZmVyKTsKICB9IGVsc2UgewogICAgdGhyb3cgbmV3IEVycm9yKCJBcmd1bWVudCBtdXN0IGJlIGEgYnVmZmVyIHNvdXJjZSwgbGlrZSBVaW50OEFycmF5IG9yIEFycmF5QnVmZmVyIik7CiAgfQogIGNvbnN0IHBhcnNlU3RhdGUgPSBuZXcgUGFyc2VTdGF0ZShtb2R1bGVCeXRlcyk7CiAgcGFyc2VNYWdpY051bWJlcihwYXJzZVN0YXRlKTsKICBwYXJzZVZlcnNpb24ocGFyc2VTdGF0ZSk7CiAgY29uc3QgdHlwZXMgPSBbXTsKICBjb25zdCBpbXBvcnRzID0gW107CiAgd2hpbGUgKHBhcnNlU3RhdGUuaGFzTW9yZUJ5dGVzKCkpIHsKICAgIGNvbnN0IHNlY3Rpb25JZCA9IHBhcnNlU3RhdGUucmVhZEJ5dGUoKTsKICAgIGNvbnN0IHNlY3Rpb25TaXplID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgIHN3aXRjaCAoc2VjdGlvbklkKSB7CiAgICAgIGNhc2UgMTogewogICAgICAgIGNvbnN0IHR5cGVDb3VudCA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0eXBlQ291bnQ7IGkrKykgewogICAgICAgICAgdHlwZXMucHVzaChwYXJzZUZ1bmN0aW9uVHlwZShwYXJzZVN0YXRlKSk7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgICB9CiAgICAgIGNhc2UgMjogewogICAgICAgIGNvbnN0IGltcG9ydENvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGltcG9ydENvdW50OyBpKyspIHsKICAgICAgICAgIGNvbnN0IG1vZHVsZSA9IHBhcnNlU3RhdGUucmVhZE5hbWUoKTsKICAgICAgICAgIGNvbnN0IG5hbWUgPSBwYXJzZVN0YXRlLnJlYWROYW1lKCk7CiAgICAgICAgICBjb25zdCB0eXBlID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogICAgICAgICAgc3dpdGNoICh0eXBlKSB7CiAgICAgICAgICAgIGNhc2UgMDoKICAgICAgICAgICAgICBjb25zdCBpbmRleCA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICAgICAgICAgICAgaW1wb3J0cy5wdXNoKHsgbW9kdWxlLCBuYW1lLCBraW5kOiAiZnVuY3Rpb24iLCB0eXBlOiB0eXBlc1tpbmRleF0gfSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgMToKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJ0YWJsZSIsIHR5cGU6IHBhcnNlVGFibGVUeXBlKHBhcnNlU3RhdGUpIH0pOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgaW1wb3J0cy5wdXNoKHsgbW9kdWxlLCBuYW1lLCBraW5kOiAibWVtb3J5IiwgdHlwZTogcGFyc2VMaW1pdHMocGFyc2VTdGF0ZSkgfSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgMzoKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJnbG9iYWwiLCB0eXBlOiBwYXJzZUdsb2JhbFR5cGUocGFyc2VTdGF0ZSkgfSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIGltcG9ydCBkZXNjcmlwdG9yIHR5cGUgJHt0eXBlfWApOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gaW1wb3J0czsKICAgICAgfQogICAgICBkZWZhdWx0OiB7CiAgICAgICAgcGFyc2VTdGF0ZS5za2lwQnl0ZXMoc2VjdGlvblNpemUpOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgfQogIHJldHVybiBbXTsKfQp2YXIgUGFyc2VTdGF0ZSA9IGNsYXNzIHsKICBjb25zdHJ1Y3Rvcihtb2R1bGVCeXRlcykgewogICAgdGhpcy5tb2R1bGVCeXRlcyA9IG1vZHVsZUJ5dGVzOwogICAgdGhpcy5vZmZzZXQgPSAwOwogICAgdGhpcy50ZXh0RGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKTsKICB9CiAgaGFzTW9yZUJ5dGVzKCkgewogICAgcmV0dXJuIHRoaXMub2Zmc2V0IDwgdGhpcy5tb2R1bGVCeXRlcy5sZW5ndGg7CiAgfQogIHJlYWRCeXRlKCkgewogICAgcmV0dXJuIHRoaXMubW9kdWxlQnl0ZXNbdGhpcy5vZmZzZXQrK107CiAgfQogIHNraXBCeXRlcyhjb3VudCkgewogICAgdGhpcy5vZmZzZXQgKz0gY291bnQ7CiAgfQogIHJlYWRVbnNpZ25lZExFQjEyOCgpIHsKICAgIGxldCByZXN1bHQgPSAwOwogICAgbGV0IHNoaWZ0ID0gMDsKICAgIGxldCBieXRlOwogICAgZG8gewogICAgICBieXRlID0gdGhpcy5yZWFkQnl0ZSgpOwogICAgICByZXN1bHQgfD0gKGJ5dGUgJiAxMjcpIDw8IHNoaWZ0OwogICAgICBzaGlmdCArPSA3OwogICAgfSB3aGlsZSAoYnl0ZSAmIDEyOCk7CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICByZWFkTmFtZSgpIHsKICAgIGNvbnN0IG5hbWVMZW5ndGggPSB0aGlzLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgY29uc3QgbmFtZUJ5dGVzID0gdGhpcy5tb2R1bGVCeXRlcy5zbGljZSh0aGlzLm9mZnNldCwgdGhpcy5vZmZzZXQgKyBuYW1lTGVuZ3RoKTsKICAgIGNvbnN0IG5hbWUgPSB0aGlzLnRleHREZWNvZGVyLmRlY29kZShuYW1lQnl0ZXMpOwogICAgdGhpcy5vZmZzZXQgKz0gbmFtZUxlbmd0aDsKICAgIHJldHVybiBuYW1lOwogIH0KICBhc3NlcnRCeXRlcyhleHBlY3RlZCkgewogICAgY29uc3QgYmFzZU9mZnNldCA9IHRoaXMub2Zmc2V0OwogICAgY29uc3QgZXhwZWN0ZWRMZW5ndGggPSBleHBlY3RlZC5sZW5ndGg7CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGV4cGVjdGVkTGVuZ3RoOyBpKyspIHsKICAgICAgaWYgKHRoaXMubW9kdWxlQnl0ZXNbYmFzZU9mZnNldCArIGldICE9PSBleHBlY3RlZFtpXSkgewogICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgJHtleHBlY3RlZH0gYXQgb2Zmc2V0ICR7YmFzZU9mZnNldH1gKTsKICAgICAgfQogICAgfQogICAgdGhpcy5vZmZzZXQgKz0gZXhwZWN0ZWRMZW5ndGg7CiAgfQp9OwpmdW5jdGlvbiBwYXJzZU1hZ2ljTnVtYmVyKHBhcnNlU3RhdGUpIHsKICBjb25zdCBleHBlY3RlZCA9IFswLCA5NywgMTE1LCAxMDldOwogIHBhcnNlU3RhdGUuYXNzZXJ0Qnl0ZXMoZXhwZWN0ZWQpOwp9CmZ1bmN0aW9uIHBhcnNlVmVyc2lvbihwYXJzZVN0YXRlKSB7CiAgY29uc3QgZXhwZWN0ZWQgPSBbMSwgMCwgMCwgMF07CiAgcGFyc2VTdGF0ZS5hc3NlcnRCeXRlcyhleHBlY3RlZCk7Cn0KZnVuY3Rpb24gcGFyc2VUYWJsZVR5cGUocGFyc2VTdGF0ZSkgewogIGNvbnN0IGVsZW1lbnRUeXBlID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogIGxldCBlbGVtZW50OwogIHN3aXRjaCAoZWxlbWVudFR5cGUpIHsKICAgIGNhc2UgMTEyOgogICAgICBlbGVtZW50ID0gImZ1bmNyZWYiOwogICAgICBicmVhazsKICAgIGNhc2UgMTExOgogICAgICBlbGVtZW50ID0gImV4dGVybnJlZiI7CiAgICAgIGJyZWFrOwogICAgZGVmYXVsdDoKICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIHRhYmxlIGVsZW1lbnQgdHlwZSAke2VsZW1lbnRUeXBlfWApOwogIH0KICBjb25zdCB7IG1pbmltdW0sIG1heGltdW0gfSA9IHBhcnNlTGltaXRzKHBhcnNlU3RhdGUpOwogIGlmIChtYXhpbXVtKSB7CiAgICByZXR1cm4geyBlbGVtZW50LCBtaW5pbXVtLCBtYXhpbXVtIH07CiAgfSBlbHNlIHsKICAgIHJldHVybiB7IGVsZW1lbnQsIG1pbmltdW0gfTsKICB9Cn0KZnVuY3Rpb24gcGFyc2VMaW1pdHMocGFyc2VTdGF0ZSkgewogIGNvbnN0IGZsYWdzID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogIGNvbnN0IG1pbmltdW0gPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogIGNvbnN0IGhhc01heGltdW0gPSBmbGFncyAmIDE7CiAgY29uc3Qgc2hhcmVkID0gKGZsYWdzICYgMikgIT09IDA7CiAgY29uc3QgaXNNZW1vcnk2NCA9IChmbGFncyAmIDQpICE9PSAwOwogIGNvbnN0IGluZGV4ID0gaXNNZW1vcnk2NCA/ICJpNjQiIDogImkzMiI7CiAgaWYgKGhhc01heGltdW0pIHsKICAgIGNvbnN0IG1heGltdW0gPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgcmV0dXJuIHsgbWluaW11bSwgc2hhcmVkLCBpbmRleCwgbWF4aW11bSB9OwogIH0gZWxzZSB7CiAgICByZXR1cm4geyBtaW5pbXVtLCBzaGFyZWQsIGluZGV4IH07CiAgfQp9CmZ1bmN0aW9uIHBhcnNlR2xvYmFsVHlwZShwYXJzZVN0YXRlKSB7CiAgY29uc3QgdmFsdWUgPSBwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKTsKICBjb25zdCBtdXRhYmxlID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpID09PSAxOwogIHJldHVybiB7IHZhbHVlLCBtdXRhYmxlIH07Cn0KZnVuY3Rpb24gcGFyc2VWYWx1ZVR5cGUocGFyc2VTdGF0ZSkgewogIGNvbnN0IHR5cGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgc3dpdGNoICh0eXBlKSB7CiAgICBjYXNlIDEyNzoKICAgICAgcmV0dXJuICJpMzIiOwogICAgY2FzZSAxMjY6CiAgICAgIHJldHVybiAiaTY0IjsKICAgIGNhc2UgMTI1OgogICAgICByZXR1cm4gImYzMiI7CiAgICBjYXNlIDEyNDoKICAgICAgcmV0dXJuICJmNjQiOwogICAgY2FzZSAxMTI6CiAgICAgIHJldHVybiAiZnVuY3JlZiI7CiAgICBjYXNlIDExMToKICAgICAgcmV0dXJuICJleHRlcm5yZWYiOwogICAgY2FzZSAxMjM6CiAgICAgIHJldHVybiAidjEyOCI7CiAgICBkZWZhdWx0OgogICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gdmFsdWUgdHlwZSAke3R5cGV9YCk7CiAgfQp9CmZ1bmN0aW9uIHBhcnNlRnVuY3Rpb25UeXBlKHBhcnNlU3RhdGUpIHsKICBjb25zdCBmb3JtID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogIGlmIChmb3JtICE9PSA5NikgewogICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBmdW5jdGlvbiB0eXBlIGZvcm0gMHg2MCwgZ290ICR7Zm9ybX1gKTsKICB9CiAgY29uc3QgcGFyYW1ldGVycyA9IFtdOwogIGNvbnN0IHBhcmFtZXRlckNvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcmFtZXRlckNvdW50OyBpKyspIHsKICAgIHBhcmFtZXRlcnMucHVzaChwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKSk7CiAgfQogIGNvbnN0IHJlc3VsdHMgPSBbXTsKICBjb25zdCByZXN1bHRDb3VudCA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXN1bHRDb3VudDsgaSsrKSB7CiAgICByZXN1bHRzLnB1c2gocGFyc2VWYWx1ZVR5cGUocGFyc2VTdGF0ZSkpOwogIH0KICByZXR1cm4geyBwYXJhbWV0ZXJzLCByZXN1bHRzIH07Cn0KCi8vIG5vZGVfbW9kdWxlcy93YXNtLWltcG9ydHMtcGFyc2VyL3BvbHlmaWxsLmpzCnZhciBoYXNXYXNtVHlwZVJlZmxlY3Rpb25TdXBwb3J0ID0gKCgpID0+IHsKICBjb25zdCBtb2R1bGVCeXRlcyA9IG5ldyBVaW50OEFycmF5KFsKICAgIDAsCiAgICA5NywKICAgIDExNSwKICAgIDEwOSwKICAgIDEsCiAgICAwLAogICAgMCwKICAgIDAsCiAgICAyLAogICAgNiwKICAgIDEsCiAgICAwLAogICAgMCwKICAgIDIsCiAgICAwLAogICAgMQogIF0pOwogIGNvbnN0IG1vZHVsZSA9IG5ldyBXZWJBc3NlbWJseS5Nb2R1bGUobW9kdWxlQnl0ZXMpOwogIGNvbnN0IGltcG9ydHMgPSBXZWJBc3NlbWJseS5Nb2R1bGUuaW1wb3J0cyhtb2R1bGUpOwogIGNvbnN0IG1lbW9yeUltcG9ydCA9IGltcG9ydHNbMF07CiAgcmV0dXJuIHR5cGVvZiBtZW1vcnlJbXBvcnQudHlwZSA9PT0gIm9iamVjdCI7Cn0pKCk7CmZ1bmN0aW9uIHBvbHlmaWxsKFdlYkFzc2VtYmx5MykgewogIGlmIChoYXNXYXNtVHlwZVJlZmxlY3Rpb25TdXBwb3J0KSB7CiAgICByZXR1cm4gV2ViQXNzZW1ibHkzOwogIH0KICBjb25zdCBuZXdXZWJBc3NlbWJseSA9IHt9OwogIGZvciAoY29uc3Qga2V5IGluIE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKFdlYkFzc2VtYmx5MykpIHsKICAgIG5ld1dlYkFzc2VtYmx5W2tleV0gPSBXZWJBc3NlbWJseTNba2V5XTsKICB9CiAgY29uc3QgcG9seWZpbGxlZEltcG9ydHNTeW1ib2wgPSBTeW1ib2woInBvbHlmaWxsZWRJbXBvcnRzU3ltYm9sIik7CiAgY29uc3QgYXNzaWduSW1wb3J0cyA9IChtb2R1bGUsIHNvdXJjZUJ5dGVzKSA9PiB7CiAgICBtb2R1bGVbcG9seWZpbGxlZEltcG9ydHNTeW1ib2xdID0gcGFyc2VJbXBvcnRzKHNvdXJjZUJ5dGVzKTsKICB9OwogIGNvbnN0IG5ld01vZHVsZSA9IG5ld1dlYkFzc2VtYmx5Lk1vZHVsZSA9IGZ1bmN0aW9uKGJ5dGVzKSB7CiAgICBjb25zdCBtb2R1bGUgPSBuZXcgV2ViQXNzZW1ibHkzLk1vZHVsZShieXRlcyk7CiAgICBhc3NpZ25JbXBvcnRzKG1vZHVsZSwgYnl0ZXMpOwogICAgT2JqZWN0LnNldFByb3RvdHlwZU9mKG1vZHVsZSwgbmV3TW9kdWxlLnByb3RvdHlwZSk7CiAgICByZXR1cm4gbW9kdWxlOwogIH07CiAgT2JqZWN0LnNldFByb3RvdHlwZU9mKG5ld01vZHVsZS5wcm90b3R5cGUsIFdlYkFzc2VtYmx5My5Nb2R1bGUucHJvdG90eXBlKTsKICBuZXdXZWJBc3NlbWJseS5jb21waWxlID0gYXN5bmMgKHNvdXJjZSkgPT4gewogICAgY29uc3QgbW9kdWxlID0gYXdhaXQgV2ViQXNzZW1ibHkzLmNvbXBpbGUoc291cmNlKTsKICAgIGFzc2lnbkltcG9ydHMobW9kdWxlLCBzb3VyY2UpOwogICAgcmV0dXJuIG1vZHVsZTsKICB9OwogIGlmIChXZWJBc3NlbWJseTMuY29tcGlsZVN0cmVhbWluZykgewogICAgbmV3V2ViQXNzZW1ibHkuY29tcGlsZVN0cmVhbWluZyA9IGFzeW5jIChzb3VyY2UpID0+IHsKICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBzb3VyY2U7CiAgICAgIGNvbnN0IGNsb25lID0gcmVzcG9uc2UuY2xvbmUoKTsKICAgICAgY29uc3QgbW9kdWxlID0gYXdhaXQgV2ViQXNzZW1ibHkzLmNvbXBpbGVTdHJlYW1pbmcocmVzcG9uc2UpOwogICAgICBhc3NpZ25JbXBvcnRzKG1vZHVsZSwgbmV3IFVpbnQ4QXJyYXkoYXdhaXQgY2xvbmUuYXJyYXlCdWZmZXIoKSkpOwogICAgICByZXR1cm4gbW9kdWxlOwogICAgfTsKICB9CiAgbmV3TW9kdWxlLmltcG9ydHMgPSAobW9kdWxlKSA9PiB7CiAgICBjb25zdCBwYXJzZWRJbXBvcnRzID0gbW9kdWxlW3BvbHlmaWxsZWRJbXBvcnRzU3ltYm9sXTsKICAgIGlmICghcGFyc2VkSW1wb3J0cykgewogICAgICByZXR1cm4gV2ViQXNzZW1ibHkzLk1vZHVsZS5pbXBvcnRzKG1vZHVsZSk7CiAgICB9CiAgICByZXR1cm4gcGFyc2VkSW1wb3J0czsKICB9OwogIHJldHVybiBuZXdXZWJBc3NlbWJseTsKfQoKLy8gZW50cnlwb2ludC9pbnRyaW5zaWNzLnRzCnZhciBXZWJBc3NlbWJseTIgPSBwb2x5ZmlsbChnbG9iYWxUaGlzLldlYkFzc2VtYmx5KTsKdmFyIExpbmVEZWNvZGVyID0gY2xhc3MgewogIGNvbnN0cnVjdG9yKG9uTGluZSkgewogICAgdGhpcy5kZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIsIHsgZmF0YWw6IGZhbHNlIH0pOwogICAgdGhpcy5idWZmZXIgPSAiIjsKICAgIHRoaXMub25MaW5lID0gb25MaW5lOwogIH0KICBkZWNvZGVyOwogIGJ1ZmZlcjsKICBvbkxpbmU7CiAgc2VuZChjaHVuaykgewogICAgdGhpcy5idWZmZXIgKz0gdGhpcy5kZWNvZGVyLmRlY29kZShjaHVuaywgeyBzdHJlYW06IHRydWUgfSk7CiAgICBjb25zdCBsaW5lcyA9IHRoaXMuYnVmZmVyLnNwbGl0KCJcbiIpOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGggLSAxOyBpKyspIHsKICAgICAgdGhpcy5vbkxpbmUobGluZXNbaV0pOwogICAgfQogICAgdGhpcy5idWZmZXIgPSBsaW5lc1tsaW5lcy5sZW5ndGggLSAxXTsKICB9Cn07CmFzeW5jIGZ1bmN0aW9uIGluc3RhbnRpYXRlKHJhd09wdGlvbnMsIGV4dHJhV2FzbUltcG9ydHMpIHsKICBjb25zdCBvcHRpb25zID0gZGVmYXVsdEluc3RhbnRpYXRpb25PcHRpb25zKHJhd09wdGlvbnMpOwogIGxldCBzd2lmdCA9IG9wdGlvbnMuc3dpZnQ7CiAgaWYgKCFzd2lmdCAmJiBvcHRpb25zLlN3aWZ0UnVudGltZSkgewogICAgbGV0IHNoYXJlZE1lbW9yeSA9IGZhbHNlOwogICAgZm9yIChjb25zdCBpbXBvcnRFbnRyeSBvZiBXZWJBc3NlbWJseTIuTW9kdWxlLmltcG9ydHMob3B0aW9ucy5tb2R1bGUpKSB7CiAgICAgIGlmIChpbXBvcnRFbnRyeS5tb2R1bGUgPT09ICJlbnYiICYmIGltcG9ydEVudHJ5Lm5hbWUgPT09ICJtZW1vcnkiICYmIGltcG9ydEVudHJ5LmtpbmQgPT09ICJtZW1vcnkiKSB7CiAgICAgICAgc2hhcmVkTWVtb3J5ID0gdHJ1ZTsKICAgICAgICBicmVhazsKICAgICAgfQogICAgfQogICAgc3dpZnQgPSBuZXcgb3B0aW9ucy5Td2lmdFJ1bnRpbWUoeyBzaGFyZWRNZW1vcnkgfSk7CiAgfQogIGxldCBzdGRvdXRMaW5lID0gdm9pZCAwOwogIGlmIChvcHRpb25zLm9uU3Rkb3V0TGluZSAhPSBudWxsKSB7CiAgICBzdGRvdXRMaW5lID0gbmV3IExpbmVEZWNvZGVyKG9wdGlvbnMub25TdGRvdXRMaW5lKTsKICB9CiAgY29uc3Qgc3Rkb3V0ID0gbmV3IENvbnNvbGVTdGRvdXQoKGNodW5rKSA9PiB7CiAgICBvcHRpb25zLm9uU3Rkb3V0Py5jYWxsKHZvaWQgMCwgY2h1bmspOwogICAgc3Rkb3V0TGluZT8uc2VuZChjaHVuayk7CiAgfSk7CiAgbGV0IHN0ZGVyckxpbmUgPSB2b2lkIDA7CiAgaWYgKG9wdGlvbnMub25TdGRlcnJMaW5lICE9IG51bGwpIHsKICAgIHN0ZGVyckxpbmUgPSBuZXcgTGluZURlY29kZXIob3B0aW9ucy5vblN0ZGVyckxpbmUpOwogIH0KICBjb25zdCBzdGRlcnIgPSBuZXcgQ29uc29sZVN0ZG91dCgoY2h1bmspID0+IHsKICAgIG9wdGlvbnMub25TdGRlcnI/LmNhbGwodm9pZCAwLCBjaHVuayk7CiAgICBzdGRlcnJMaW5lPy5zZW5kKGNodW5rKTsKICB9KTsKICBjb25zdCBhcmdzID0gb3B0aW9ucy5hcmdzIHx8IFtdOwogIGNvbnN0IHJvb3RGcyA9IG9wdGlvbnMucm9vdEZzIHx8IC8qIEBfX1BVUkVfXyAqLyBuZXcgTWFwKCk7CiAgY29uc3QgZmRzID0gWwogICAgbmV3IE9wZW5GaWxlKG5ldyBGaWxlKFtdKSksCiAgICBzdGRvdXQsCiAgICBzdGRlcnIsCiAgICBuZXcgUHJlb3BlbkRpcmVjdG9yeSgiLyIsIHJvb3RGcykKICBdOwogIGNvbnN0IGVudnMgPSBvcHRpb25zLmVudiA/IE9iamVjdC5lbnRyaWVzKG9wdGlvbnMuZW52KS5tYXAoKFtrZXksIHZhbHVlXSkgPT4gYCR7a2V5fT0ke3ZhbHVlfWApIDogW107CiAgY29uc3Qgd2FzaSA9IG5ldyBXQVNJKGFyZ3MsIGVudnMsIGZkcywgewogICAgZGVidWc6IGZhbHNlCiAgfSk7CiAgY29uc3QgY3JlYXRlV2FzbUltcG9ydE9iamVjdCA9IChleHRyYVdhc21JbXBvcnRzMiwgbW9kdWxlKSA9PiB7CiAgICBjb25zdCBpbXBvcnRPYmplY3QyID0gewogICAgICB3YXNpX3NuYXBzaG90X3ByZXZpZXcxOiB3YXNpLndhc2lJbXBvcnQKICAgIH07CiAgICBpZiAoc3dpZnQpIHsKICAgICAgaW1wb3J0T2JqZWN0Mi5qYXZhc2NyaXB0X2tpdCA9IHN3aWZ0Lndhc21JbXBvcnRzOwogICAgfQogICAgaWYgKGV4dHJhV2FzbUltcG9ydHMyKSB7CiAgICAgIGZvciAoY29uc3QgbW9kdWxlTmFtZSBpbiBleHRyYVdhc21JbXBvcnRzMikgewogICAgICAgIGlmICghaW1wb3J0T2JqZWN0Mlttb2R1bGVOYW1lXSkgewogICAgICAgICAgaW1wb3J0T2JqZWN0Mlttb2R1bGVOYW1lXSA9IHt9OwogICAgICAgIH0KICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IGluIGV4dHJhV2FzbUltcG9ydHMyW21vZHVsZU5hbWVdKSB7CiAgICAgICAgICBpbXBvcnRPYmplY3QyW21vZHVsZU5hbWVdW2VudHJ5XSA9IGV4dHJhV2FzbUltcG9ydHMyW21vZHVsZU5hbWVdW2VudHJ5XTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGZvciAoY29uc3QgX2ltcG9ydEVudHJ5IG9mIFdlYkFzc2VtYmx5Mi5Nb2R1bGUuaW1wb3J0cyhtb2R1bGUpKSB7CiAgICAgIGNvbnN0IGltcG9ydEVudHJ5ID0gX2ltcG9ydEVudHJ5OwogICAgICBpZiAoIWltcG9ydE9iamVjdDJbaW1wb3J0RW50cnkubW9kdWxlXSkgewogICAgICAgIGltcG9ydE9iamVjdDJbaW1wb3J0RW50cnkubW9kdWxlXSA9IHt9OwogICAgICB9CiAgICAgIGlmIChpbXBvcnRPYmplY3QyW2ltcG9ydEVudHJ5Lm1vZHVsZV1baW1wb3J0RW50cnkubmFtZV0pIHsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICBpZiAoaW1wb3J0RW50cnkua2luZCA9PSAiZnVuY3Rpb24iKSB7CiAgICAgICAgaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdW2ltcG9ydEVudHJ5Lm5hbWVdID0gKCkgPT4gewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbXBvcnRlZCBmdW5jdGlvbiAke2ltcG9ydEVudHJ5Lm1vZHVsZX0uJHtpbXBvcnRFbnRyeS5uYW1lfSBub3QgaW1wbGVtZW50ZWRgKTsKICAgICAgICB9OwogICAgICB9IGVsc2UgaWYgKGltcG9ydEVudHJ5LmtpbmQgPT0gIm1lbW9yeSIgJiYgaW1wb3J0RW50cnkubW9kdWxlID09ICJlbnYiICYmIGltcG9ydEVudHJ5Lm5hbWUgPT0gIm1lbW9yeSIpIHsKICAgICAgICBjb25zdCB0eXBlID0gaW1wb3J0RW50cnkudHlwZTsKICAgICAgICBjb25zdCBkZXNjcmlwdG9yID0gewogICAgICAgICAgaW5pdGlhbDogdHlwZS5taW5pbXVtLAogICAgICAgICAgbWF4aW11bTogdHlwZS5tYXhpbXVtLAogICAgICAgICAgc2hhcmVkOiB0eXBlLnNoYXJlZAogICAgICAgIH07CiAgICAgICAgaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdW2ltcG9ydEVudHJ5Lm5hbWVdID0gbmV3IFdlYkFzc2VtYmx5Mi5NZW1vcnkoZGVzY3JpcHRvcik7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBpbXBvcnRPYmplY3QyOwogIH07CiAgY29uc3QgaW1wb3J0T2JqZWN0ID0gY3JlYXRlV2FzbUltcG9ydE9iamVjdChleHRyYVdhc21JbXBvcnRzLCBvcHRpb25zLm1vZHVsZSk7CiAgY29uc3QgaW5zdGFuY2UgPSBhd2FpdCBXZWJBc3NlbWJseTIuaW5zdGFudGlhdGUob3B0aW9ucy5tb2R1bGUsIGltcG9ydE9iamVjdCk7CiAgaWYgKHN3aWZ0ICYmIGluc3RhbmNlLmV4cG9ydHMuc3dqc19saWJyYXJ5X3ZlcnNpb24pIHsKICAgIHN3aWZ0LnNldEluc3RhbmNlKGluc3RhbmNlKTsKICB9CiAgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLl9zdGFydCA9PT0gImZ1bmN0aW9uIikgewogICAgd2FzaS5zdGFydChpbnN0YW5jZSk7CiAgfSBlbHNlIGlmICh0eXBlb2YgaW5zdGFuY2UuZXhwb3J0cy5faW5pdGlhbGl6ZSA9PSAiZnVuY3Rpb24iKSB7CiAgICB3YXNpLmluaXRpYWxpemUoaW5zdGFuY2UpOwogICAgaWYgKHN3aWZ0ICYmIHN3aWZ0Lm1haW4pIHsKICAgICAgc3dpZnQubWFpbigpOwogICAgfSBlbHNlIHsKICAgICAgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLm1haW4gPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICBpbnN0YW5jZS5leHBvcnRzLm1haW4oKTsKICAgICAgfSBlbHNlIGlmICh0eXBlb2YgaW5zdGFuY2UuZXhwb3J0cy5fX21haW5fYXJnY19hcmd2ID09PSAiZnVuY3Rpb24iKSB7CiAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5fX21haW5fYXJnY19hcmd2KDAsIDApOwogICAgICB9CiAgICB9CiAgfQogIHJldHVybiB7IGluc3RhbmNlLCByb290RnMgfTsKfQpmdW5jdGlvbiBkZWZhdWx0SW5zdGFudGlhdGlvbk9wdGlvbnMob3B0aW9ucykgewogIGlmIChvcHRpb25zLmFyZ3MgPT0gbnVsbCkgewogICAgb3B0aW9ucy5hcmdzID0gWyJtYWluLndhc20iXTsKICB9CiAgY29uc3QgaXNOb2RlSnMgPSB0eXBlb2YgcHJvY2VzcyAhPT0gInVuZGVmaW5lZCIgJiYgcHJvY2Vzcy5yZWxlYXNlLm5hbWUgPT09ICJub2RlIjsKICBjb25zdCBpc1dlYkJyb3dzZXIgPSB0eXBlb2Ygd2luZG93ICE9PSAidW5kZWZpbmVkIjsKICBpZiAoaXNOb2RlSnMpIHsKICAgIGlmICghb3B0aW9ucy5vblN0ZG91dCkgewogICAgICBvcHRpb25zLm9uU3Rkb3V0ID0gKGNodW5rKSA9PiBwcm9jZXNzLnN0ZG91dC53cml0ZShjaHVuayk7CiAgICB9CiAgICBpZiAoIW9wdGlvbnMub25TdGRlcnIpIHsKICAgICAgb3B0aW9ucy5vblN0ZGVyciA9IChjaHVuaykgPT4gcHJvY2Vzcy5zdGRlcnIud3JpdGUoY2h1bmspOwogICAgfQogIH0gZWxzZSBpZiAoaXNXZWJCcm93c2VyKSB7CiAgICBpZiAoIW9wdGlvbnMub25TdGRvdXRMaW5lKSB7CiAgICAgIG9wdGlvbnMub25TdGRvdXRMaW5lID0gKGxpbmUpID0+IGNvbnNvbGUubG9nKGxpbmUpOwogICAgfQogICAgaWYgKCFvcHRpb25zLm9uU3RkZXJyTGluZSkgewogICAgICBvcHRpb25zLm9uU3RkZXJyTGluZSA9IChsaW5lKSA9PiBjb25zb2xlLndhcm4obGluZSk7CiAgICB9CiAgfQogIHJldHVybiBvcHRpb25zOwp9CgovLyBlbnRyeXBvaW50L2Rldi50cwp2YXIgc29ja2V0ID0gbmV3IHJlY29ubmVjdGluZ193ZWJzb2NrZXRfbWpzX2RlZmF1bHQoYHdzOi8vJHtsb2NhdGlvbi5ob3N0fS93YXRjaGVyYCk7CnNvY2tldC5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwgKG1lc3NhZ2UpID0+IHsKICBpZiAobWVzc2FnZS5kYXRhID09PSAicmVsb2FkIikgewogICAgbG9jYXRpb24ucmVsb2FkKCk7CiAgfQp9KTsKdmFyIHN0YXJ0V2FzaVRhc2sgPSBhc3luYyAoKSA9PiB7CiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCgiL21haW4ud2FzbSIpOwogIGxldCBydW50aW1lQ29uc3RydWN0b3IgPSB2b2lkIDA7CiAgdHJ5IHsKICAgIGNvbnN0IHsgU3dpZnRSdW50aW1lIH0gPSBhd2FpdCBpbXBvcnQoCiAgICAgIC8vIEB0cy1pZ25vcmUKICAgICAgIi4vSmF2YVNjcmlwdEtpdF9KYXZhU2NyaXB0S2l0LnJlc291cmNlcy9SdW50aW1lL2luZGV4Lm1qcyIKICAgICk7CiAgICBydW50aW1lQ29uc3RydWN0b3IgPSBTd2lmdFJ1bnRpbWU7CiAgfSBjYXRjaCB7CiAgICBjb25zb2xlLmxvZygiSmF2YVNjcmlwdEtpdCBtb2R1bGUgbm90IGF2YWlsYWJsZSwgcnVubmluZyB3aXRob3V0IEphdmFTY3JpcHRLaXQgcnVudGltZS4iKTsKICB9CiAgYXdhaXQgaW5zdGFudGlhdGUoewogICAgbW9kdWxlOiBhd2FpdCBXZWJBc3NlbWJseTIuY29tcGlsZVN0cmVhbWluZyhyZXNwb25zZSksCiAgICBvblN0ZG91dChjaHVuaykgewogICAgICBjb25zdCBraW5kQnVmZmVyID0gbmV3IEFycmF5QnVmZmVyKDIpOwogICAgICBuZXcgRGF0YVZpZXcoa2luZEJ1ZmZlcikuc2V0VWludDE2KDAsIDEwMDEsIHRydWUpOwogICAgICBjb25zdCBidWZmZXIgPSBuZXcgVWludDhBcnJheSgyICsgY2h1bmsubGVuZ3RoKTsKICAgICAgYnVmZmVyLnNldChuZXcgVWludDhBcnJheShraW5kQnVmZmVyKSwgMCk7CiAgICAgIGJ1ZmZlci5zZXQoY2h1bmssIDIpOwogICAgICBzb2NrZXQuc2VuZChidWZmZXIpOwogICAgfSwKICAgIG9uU3Rkb3V0TGluZShsaW5lKSB7CiAgICAgIGNvbnNvbGUubG9nKGxpbmUpOwogICAgfSwKICAgIG9uU3RkZXJyKGNodW5rKSB7CiAgICAgIGNvbnN0IGtpbmRCdWZmZXIgPSBuZXcgQXJyYXlCdWZmZXIoMik7CiAgICAgIG5ldyBEYXRhVmlldyhraW5kQnVmZmVyKS5zZXRVaW50MTYoMCwgMTAwMiwgdHJ1ZSk7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBVaW50OEFycmF5KDIgKyBjaHVuay5sZW5ndGgpOwogICAgICBidWZmZXIuc2V0KG5ldyBVaW50OEFycmF5KGtpbmRCdWZmZXIpLCAwKTsKICAgICAgYnVmZmVyLnNldChjaHVuaywgMik7CiAgICAgIHNvY2tldC5zZW5kKGJ1ZmZlcik7CiAgICB9LAogICAgb25TdGRlcnJMaW5lKGxpbmUpIHsKICAgICAgY29uc29sZS5lcnJvcihsaW5lKTsKICAgIH0sCiAgICBTd2lmdFJ1bnRpbWU6IHJ1bnRpbWVDb25zdHJ1Y3RvcgogIH0pOwp9OwpmdW5jdGlvbiBoYW5kbGVFcnJvcihlKSB7CiAgaWYgKGUgaW5zdGFuY2VvZiBFcnJvcikgewogICAgY29uc3Qgc3RhY2sgPSBlLnN0YWNrOwogICAgaWYgKHN0YWNrICE9IG51bGwpIHsKICAgICAgc29ja2V0LnNlbmQoSlNPTi5zdHJpbmdpZnkoewogICAgICAgIGtpbmQ6ICJzdGFja1RyYWNlIiwKICAgICAgICBzdGFja1RyYWNlOiBzdGFjawogICAgICB9KSk7CiAgICB9CiAgfQp9CmFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7CiAgdHJ5IHsKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCJlcnJvciIsIChldmVudCkgPT4gewogICAgICBoYW5kbGVFcnJvcihldmVudC5lcnJvcik7CiAgICB9KTsKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCJ1bmhhbmRsZWRyZWplY3Rpb24iLCAoZXZlbnQpID0+IHsKICAgICAgaGFuZGxlRXJyb3IoZXZlbnQucmVhc29uKTsKICAgIH0pOwogICAgYXdhaXQgc3RhcnRXYXNpVGFzaygpOwogIH0gY2F0Y2ggKGUpIHsKICAgIGhhbmRsZUVycm9yKGUpOwogICAgdGhyb3cgZTsKICB9Cn0KbWFpbigpOwovKiEKICogUmVjb25uZWN0aW5nIFdlYlNvY2tldAogKiBieSBQZWRybyBMYWRhcmlhIDxwZWRyby5sYWRhcmlhQGdtYWlsLmNvbT4KICogaHR0cHM6Ly9naXRodWIuY29tL3BsYWRhcmlhL3JlY29ubmVjdGluZy13ZWJzb2NrZXQKICogTGljZW5zZSBNSVQKICovCi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgpDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7IHlvdSBtYXkgbm90IHVzZQp0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4gWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZQpMaWNlbnNlIGF0IGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKVEhJUyBDT0RFIElTIFBST1ZJREVEIE9OIEFOICpBUyBJUyogQkFTSVMsIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWQpLSU5ELCBFSVRIRVIgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgV0lUSE9VVCBMSU1JVEFUSU9OIEFOWSBJTVBMSUVECldBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBUSVRMRSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UsCk1FUkNIQU5UQUJMSVRZIE9SIE5PTi1JTkZSSU5HRU1FTlQuCgpTZWUgdGhlIEFwYWNoZSBWZXJzaW9uIDIuMCBMaWNlbnNlIGZvciBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMKYW5kIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAqLwo=")! - public static let bundle: Data = Data(base64Encoded: "Ly8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC93YXNpX2RlZnMuanMKdmFyIENMT0NLSURfUkVBTFRJTUUgPSAwOwp2YXIgQ0xPQ0tJRF9NT05PVE9OSUMgPSAxOwp2YXIgRVJSTk9fU1VDQ0VTUyA9IDA7CnZhciBFUlJOT19CQURGID0gODsKdmFyIEVSUk5PX0VYSVNUID0gMjA7CnZhciBFUlJOT19JTlZBTCA9IDI4Owp2YXIgRVJSTk9fSVNESVIgPSAzMTsKdmFyIEVSUk5PX05BTUVUT09MT05HID0gMzc7CnZhciBFUlJOT19OT0VOVCA9IDQ0Owp2YXIgRVJSTk9fTk9TWVMgPSA1MjsKdmFyIEVSUk5PX05PVERJUiA9IDU0Owp2YXIgRVJSTk9fTk9URU1QVFkgPSA1NTsKdmFyIEVSUk5PX05PVFNVUCA9IDU4Owp2YXIgRVJSTk9fUEVSTSA9IDYzOwp2YXIgRVJSTk9fTk9UQ0FQQUJMRSA9IDc2Owp2YXIgUklHSFRTX0ZEX0RBVEFTWU5DID0gMSA8PCAwOwp2YXIgUklHSFRTX0ZEX1JFQUQgPSAxIDw8IDE7CnZhciBSSUdIVFNfRkRfU0VFSyA9IDEgPDwgMjsKdmFyIFJJR0hUU19GRF9GRFNUQVRfU0VUX0ZMQUdTID0gMSA8PCAzOwp2YXIgUklHSFRTX0ZEX1NZTkMgPSAxIDw8IDQ7CnZhciBSSUdIVFNfRkRfVEVMTCA9IDEgPDwgNTsKdmFyIFJJR0hUU19GRF9XUklURSA9IDEgPDwgNjsKdmFyIFJJR0hUU19GRF9BRFZJU0UgPSAxIDw8IDc7CnZhciBSSUdIVFNfRkRfQUxMT0NBVEUgPSAxIDw8IDg7CnZhciBSSUdIVFNfUEFUSF9DUkVBVEVfRElSRUNUT1JZID0gMSA8PCA5Owp2YXIgUklHSFRTX1BBVEhfQ1JFQVRFX0ZJTEUgPSAxIDw8IDEwOwp2YXIgUklHSFRTX1BBVEhfTElOS19TT1VSQ0UgPSAxIDw8IDExOwp2YXIgUklHSFRTX1BBVEhfTElOS19UQVJHRVQgPSAxIDw8IDEyOwp2YXIgUklHSFRTX1BBVEhfT1BFTiA9IDEgPDwgMTM7CnZhciBSSUdIVFNfRkRfUkVBRERJUiA9IDEgPDwgMTQ7CnZhciBSSUdIVFNfUEFUSF9SRUFETElOSyA9IDEgPDwgMTU7CnZhciBSSUdIVFNfUEFUSF9SRU5BTUVfU09VUkNFID0gMSA8PCAxNjsKdmFyIFJJR0hUU19QQVRIX1JFTkFNRV9UQVJHRVQgPSAxIDw8IDE3Owp2YXIgUklHSFRTX1BBVEhfRklMRVNUQVRfR0VUID0gMSA8PCAxODsKdmFyIFJJR0hUU19QQVRIX0ZJTEVTVEFUX1NFVF9TSVpFID0gMSA8PCAxOTsKdmFyIFJJR0hUU19QQVRIX0ZJTEVTVEFUX1NFVF9USU1FUyA9IDEgPDwgMjA7CnZhciBSSUdIVFNfRkRfRklMRVNUQVRfR0VUID0gMSA8PCAyMTsKdmFyIFJJR0hUU19GRF9GSUxFU1RBVF9TRVRfU0laRSA9IDEgPDwgMjI7CnZhciBSSUdIVFNfRkRfRklMRVNUQVRfU0VUX1RJTUVTID0gMSA8PCAyMzsKdmFyIFJJR0hUU19QQVRIX1NZTUxJTksgPSAxIDw8IDI0Owp2YXIgUklHSFRTX1BBVEhfUkVNT1ZFX0RJUkVDVE9SWSA9IDEgPDwgMjU7CnZhciBSSUdIVFNfUEFUSF9VTkxJTktfRklMRSA9IDEgPDwgMjY7CnZhciBSSUdIVFNfUE9MTF9GRF9SRUFEV1JJVEUgPSAxIDw8IDI3Owp2YXIgUklHSFRTX1NPQ0tfU0hVVERPV04gPSAxIDw8IDI4Owp2YXIgSW92ZWMgPSBjbGFzcyB7CiAgc3RhdGljIHJlYWRfYnl0ZXModmlldywgcHRyKSB7CiAgICBjb25zdCBpb3ZlYyA9IG5ldyBJb3ZlYygpOwogICAgaW92ZWMuYnVmID0gdmlldy5nZXRVaW50MzIocHRyLCB0cnVlKTsKICAgIGlvdmVjLmJ1Zl9sZW4gPSB2aWV3LmdldFVpbnQzMihwdHIgKyA0LCB0cnVlKTsKICAgIHJldHVybiBpb3ZlYzsKICB9CiAgc3RhdGljIHJlYWRfYnl0ZXNfYXJyYXkodmlldywgcHRyLCBsZW4pIHsKICAgIGNvbnN0IGlvdmVjcyA9IFtdOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykgewogICAgICBpb3ZlY3MucHVzaChJb3ZlYy5yZWFkX2J5dGVzKHZpZXcsIHB0ciArIDggKiBpKSk7CiAgICB9CiAgICByZXR1cm4gaW92ZWNzOwogIH0KfTsKdmFyIENpb3ZlYyA9IGNsYXNzIHsKICBzdGF0aWMgcmVhZF9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIGNvbnN0IGlvdmVjID0gbmV3IENpb3ZlYygpOwogICAgaW92ZWMuYnVmID0gdmlldy5nZXRVaW50MzIocHRyLCB0cnVlKTsKICAgIGlvdmVjLmJ1Zl9sZW4gPSB2aWV3LmdldFVpbnQzMihwdHIgKyA0LCB0cnVlKTsKICAgIHJldHVybiBpb3ZlYzsKICB9CiAgc3RhdGljIHJlYWRfYnl0ZXNfYXJyYXkodmlldywgcHRyLCBsZW4pIHsKICAgIGNvbnN0IGlvdmVjcyA9IFtdOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykgewogICAgICBpb3ZlY3MucHVzaChDaW92ZWMucmVhZF9ieXRlcyh2aWV3LCBwdHIgKyA4ICogaSkpOwogICAgfQogICAgcmV0dXJuIGlvdmVjczsKICB9Cn07CnZhciBXSEVOQ0VfU0VUID0gMDsKdmFyIFdIRU5DRV9DVVIgPSAxOwp2YXIgV0hFTkNFX0VORCA9IDI7CnZhciBGSUxFVFlQRV9DSEFSQUNURVJfREVWSUNFID0gMjsKdmFyIEZJTEVUWVBFX0RJUkVDVE9SWSA9IDM7CnZhciBGSUxFVFlQRV9SRUdVTEFSX0ZJTEUgPSA0Owp2YXIgRGlyZW50ID0gY2xhc3MgewogIGhlYWRfbGVuZ3RoKCkgewogICAgcmV0dXJuIDI0OwogIH0KICBuYW1lX2xlbmd0aCgpIHsKICAgIHJldHVybiB0aGlzLmRpcl9uYW1lLmJ5dGVMZW5ndGg7CiAgfQogIHdyaXRlX2hlYWRfYnl0ZXModmlldywgcHRyKSB7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIsIHRoaXMuZF9uZXh0LCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDgsIHRoaXMuZF9pbm8sIHRydWUpOwogICAgdmlldy5zZXRVaW50MzIocHRyICsgMTYsIHRoaXMuZGlyX25hbWUubGVuZ3RoLCB0cnVlKTsKICAgIHZpZXcuc2V0VWludDgocHRyICsgMjAsIHRoaXMuZF90eXBlKTsKICB9CiAgd3JpdGVfbmFtZV9ieXRlcyh2aWV3OCwgcHRyLCBidWZfbGVuKSB7CiAgICB2aWV3OC5zZXQodGhpcy5kaXJfbmFtZS5zbGljZSgwLCBNYXRoLm1pbih0aGlzLmRpcl9uYW1lLmJ5dGVMZW5ndGgsIGJ1Zl9sZW4pKSwgcHRyKTsKICB9CiAgY29uc3RydWN0b3IobmV4dF9jb29raWUsIG5hbWUsIHR5cGUpIHsKICAgIHRoaXMuZF9pbm8gPSAwbjsKICAgIGNvbnN0IGVuY29kZWRfbmFtZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShuYW1lKTsKICAgIHRoaXMuZF9uZXh0ID0gbmV4dF9jb29raWU7CiAgICB0aGlzLmRfbmFtbGVuID0gZW5jb2RlZF9uYW1lLmJ5dGVMZW5ndGg7CiAgICB0aGlzLmRfdHlwZSA9IHR5cGU7CiAgICB0aGlzLmRpcl9uYW1lID0gZW5jb2RlZF9uYW1lOwogIH0KfTsKdmFyIEZERkxBR1NfQVBQRU5EID0gMSA8PCAwOwp2YXIgRkRGTEFHU19EU1lOQyA9IDEgPDwgMTsKdmFyIEZERkxBR1NfTk9OQkxPQ0sgPSAxIDw8IDI7CnZhciBGREZMQUdTX1JTWU5DID0gMSA8PCAzOwp2YXIgRkRGTEFHU19TWU5DID0gMSA8PCA0Owp2YXIgRmRzdGF0ID0gY2xhc3MgewogIHdyaXRlX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRVaW50OChwdHIsIHRoaXMuZnNfZmlsZXR5cGUpOwogICAgdmlldy5zZXRVaW50MTYocHRyICsgMiwgdGhpcy5mc19mbGFncywgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA4LCB0aGlzLmZzX3JpZ2h0c19iYXNlLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDE2LCB0aGlzLmZzX3JpZ2h0c19pbmhlcml0ZWQsIHRydWUpOwogIH0KICBjb25zdHJ1Y3RvcihmaWxldHlwZSwgZmxhZ3MpIHsKICAgIHRoaXMuZnNfcmlnaHRzX2Jhc2UgPSAwbjsKICAgIHRoaXMuZnNfcmlnaHRzX2luaGVyaXRlZCA9IDBuOwogICAgdGhpcy5mc19maWxldHlwZSA9IGZpbGV0eXBlOwogICAgdGhpcy5mc19mbGFncyA9IGZsYWdzOwogIH0KfTsKdmFyIEZTVEZMQUdTX0FUSU0gPSAxIDw8IDA7CnZhciBGU1RGTEFHU19BVElNX05PVyA9IDEgPDwgMTsKdmFyIEZTVEZMQUdTX01USU0gPSAxIDw8IDI7CnZhciBGU1RGTEFHU19NVElNX05PVyA9IDEgPDwgMzsKdmFyIE9GTEFHU19DUkVBVCA9IDEgPDwgMDsKdmFyIE9GTEFHU19ESVJFQ1RPUlkgPSAxIDw8IDE7CnZhciBPRkxBR1NfRVhDTCA9IDEgPDwgMjsKdmFyIE9GTEFHU19UUlVOQyA9IDEgPDwgMzsKdmFyIEZpbGVzdGF0ID0gY2xhc3MgewogIHdyaXRlX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRCaWdVaW50NjQocHRyLCB0aGlzLmRldiwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA4LCB0aGlzLmlubywgdHJ1ZSk7CiAgICB2aWV3LnNldFVpbnQ4KHB0ciArIDE2LCB0aGlzLmZpbGV0eXBlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDI0LCB0aGlzLm5saW5rLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDMyLCB0aGlzLnNpemUsIHRydWUpOwogICAgdmlldy5zZXRCaWdVaW50NjQocHRyICsgMzgsIHRoaXMuYXRpbSwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA0NiwgdGhpcy5tdGltLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDUyLCB0aGlzLmN0aW0sIHRydWUpOwogIH0KICBjb25zdHJ1Y3RvcihmaWxldHlwZSwgc2l6ZSkgewogICAgdGhpcy5kZXYgPSAwbjsKICAgIHRoaXMuaW5vID0gMG47CiAgICB0aGlzLm5saW5rID0gMG47CiAgICB0aGlzLmF0aW0gPSAwbjsKICAgIHRoaXMubXRpbSA9IDBuOwogICAgdGhpcy5jdGltID0gMG47CiAgICB0aGlzLmZpbGV0eXBlID0gZmlsZXR5cGU7CiAgICB0aGlzLnNpemUgPSBzaXplOwogIH0KfTsKdmFyIEVWRU5UUldGTEFHU19GRF9SRUFEV1JJVEVfSEFOR1VQID0gMSA8PCAwOwp2YXIgU1VCQ0xPQ0tGTEFHU19TVUJTQ1JJUFRJT05fQ0xPQ0tfQUJTVElNRSA9IDEgPDwgMDsKdmFyIFJJRkxBR1NfUkVDVl9QRUVLID0gMSA8PCAwOwp2YXIgUklGTEFHU19SRUNWX1dBSVRBTEwgPSAxIDw8IDE7CnZhciBST0ZMQUdTX1JFQ1ZfREFUQV9UUlVOQ0FURUQgPSAxIDw8IDA7CnZhciBTREZMQUdTX1JEID0gMSA8PCAwOwp2YXIgU0RGTEFHU19XUiA9IDEgPDwgMTsKdmFyIFBSRU9QRU5UWVBFX0RJUiA9IDA7CnZhciBQcmVzdGF0RGlyID0gY2xhc3MgewogIHdyaXRlX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRVaW50MzIocHRyLCB0aGlzLnByX25hbWUuYnl0ZUxlbmd0aCwgdHJ1ZSk7CiAgfQogIGNvbnN0cnVjdG9yKG5hbWUpIHsKICAgIHRoaXMucHJfbmFtZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShuYW1lKTsKICB9Cn07CnZhciBQcmVzdGF0ID0gY2xhc3MgewogIHN0YXRpYyBkaXIobmFtZSkgewogICAgY29uc3QgcHJlc3RhdCA9IG5ldyBQcmVzdGF0KCk7CiAgICBwcmVzdGF0LnRhZyA9IFBSRU9QRU5UWVBFX0RJUjsKICAgIHByZXN0YXQuaW5uZXIgPSBuZXcgUHJlc3RhdERpcihuYW1lKTsKICAgIHJldHVybiBwcmVzdGF0OwogIH0KICB3cml0ZV9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIHZpZXcuc2V0VWludDMyKHB0ciwgdGhpcy50YWcsIHRydWUpOwogICAgdGhpcy5pbm5lci53cml0ZV9ieXRlcyh2aWV3LCBwdHIgKyA0KTsKICB9Cn07CgovLyBub2RlX21vZHVsZXMvQGJqb3JuMy9icm93c2VyX3dhc2lfc2hpbS9kaXN0L2RlYnVnLmpzCnZhciBEZWJ1ZyA9IGNsYXNzIERlYnVnMiB7CiAgZW5hYmxlKGVuYWJsZWQpIHsKICAgIHRoaXMubG9nID0gY3JlYXRlTG9nZ2VyKGVuYWJsZWQgPT09IHZvaWQgMCA/IHRydWUgOiBlbmFibGVkLCB0aGlzLnByZWZpeCk7CiAgfQogIGdldCBlbmFibGVkKCkgewogICAgcmV0dXJuIHRoaXMuaXNFbmFibGVkOwogIH0KICBjb25zdHJ1Y3Rvcihpc0VuYWJsZWQpIHsKICAgIHRoaXMuaXNFbmFibGVkID0gaXNFbmFibGVkOwogICAgdGhpcy5wcmVmaXggPSAid2FzaToiOwogICAgdGhpcy5lbmFibGUoaXNFbmFibGVkKTsKICB9Cn07CmZ1bmN0aW9uIGNyZWF0ZUxvZ2dlcihlbmFibGVkLCBwcmVmaXgpIHsKICBpZiAoZW5hYmxlZCkgewogICAgY29uc3QgYSA9IGNvbnNvbGUubG9nLmJpbmQoY29uc29sZSwgIiVjJXMiLCAiY29sb3I6ICMyNjVCQTAiLCBwcmVmaXgpOwogICAgcmV0dXJuIGE7CiAgfSBlbHNlIHsKICAgIHJldHVybiAoKSA9PiB7CiAgICB9OwogIH0KfQp2YXIgZGVidWcgPSBuZXcgRGVidWcoZmFsc2UpOwoKLy8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC93YXNpLmpzCnZhciBXQVNJUHJvY0V4aXQgPSBjbGFzcyBleHRlbmRzIEVycm9yIHsKICBjb25zdHJ1Y3Rvcihjb2RlKSB7CiAgICBzdXBlcigiZXhpdCB3aXRoIGV4aXQgY29kZSAiICsgY29kZSk7CiAgICB0aGlzLmNvZGUgPSBjb2RlOwogIH0KfTsKdmFyIFdBU0kgPSBjbGFzcyBXQVNJMiB7CiAgc3RhcnQoaW5zdGFuY2UpIHsKICAgIHRoaXMuaW5zdCA9IGluc3RhbmNlOwogICAgdHJ5IHsKICAgICAgaW5zdGFuY2UuZXhwb3J0cy5fc3RhcnQoKTsKICAgICAgcmV0dXJuIDA7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIGlmIChlIGluc3RhbmNlb2YgV0FTSVByb2NFeGl0KSB7CiAgICAgICAgcmV0dXJuIGUuY29kZTsKICAgICAgfSBlbHNlIHsKICAgICAgICB0aHJvdyBlOwogICAgICB9CiAgICB9CiAgfQogIGluaXRpYWxpemUoaW5zdGFuY2UpIHsKICAgIHRoaXMuaW5zdCA9IGluc3RhbmNlOwogICAgaWYgKGluc3RhbmNlLmV4cG9ydHMuX2luaXRpYWxpemUpIHsKICAgICAgaW5zdGFuY2UuZXhwb3J0cy5faW5pdGlhbGl6ZSgpOwogICAgfQogIH0KICBjb25zdHJ1Y3RvcihhcmdzLCBlbnYsIGZkcywgb3B0aW9ucyA9IHt9KSB7CiAgICB0aGlzLmFyZ3MgPSBbXTsKICAgIHRoaXMuZW52ID0gW107CiAgICB0aGlzLmZkcyA9IFtdOwogICAgZGVidWcuZW5hYmxlKG9wdGlvbnMuZGVidWcpOwogICAgdGhpcy5hcmdzID0gYXJnczsKICAgIHRoaXMuZW52ID0gZW52OwogICAgdGhpcy5mZHMgPSBmZHM7CiAgICBjb25zdCBzZWxmID0gdGhpczsKICAgIHRoaXMud2FzaUltcG9ydCA9IHsgYXJnc19zaXplc19nZXQoYXJnYywgYXJndl9idWZfc2l6ZSkgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYXJnYywgc2VsZi5hcmdzLmxlbmd0aCwgdHJ1ZSk7CiAgICAgIGxldCBidWZfc2l6ZSA9IDA7CiAgICAgIGZvciAoY29uc3QgYXJnIG9mIHNlbGYuYXJncykgewogICAgICAgIGJ1Zl9zaXplICs9IGFyZy5sZW5ndGggKyAxOwogICAgICB9CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYXJndl9idWZfc2l6ZSwgYnVmX3NpemUsIHRydWUpOwogICAgICBkZWJ1Zy5sb2coYnVmZmVyLmdldFVpbnQzMihhcmdjLCB0cnVlKSwgYnVmZmVyLmdldFVpbnQzMihhcmd2X2J1Zl9zaXplLCB0cnVlKSk7CiAgICAgIHJldHVybiAwOwogICAgfSwgYXJnc19nZXQoYXJndiwgYXJndl9idWYpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IG9yaWdfYXJndl9idWYgPSBhcmd2X2J1ZjsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmLmFyZ3MubGVuZ3RoOyBpKyspIHsKICAgICAgICBidWZmZXIuc2V0VWludDMyKGFyZ3YsIGFyZ3ZfYnVmLCB0cnVlKTsKICAgICAgICBhcmd2ICs9IDQ7CiAgICAgICAgY29uc3QgYXJnID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHNlbGYuYXJnc1tpXSk7CiAgICAgICAgYnVmZmVyOC5zZXQoYXJnLCBhcmd2X2J1Zik7CiAgICAgICAgYnVmZmVyLnNldFVpbnQ4KGFyZ3ZfYnVmICsgYXJnLmxlbmd0aCwgMCk7CiAgICAgICAgYXJndl9idWYgKz0gYXJnLmxlbmd0aCArIDE7CiAgICAgIH0KICAgICAgaWYgKGRlYnVnLmVuYWJsZWQpIHsKICAgICAgICBkZWJ1Zy5sb2cobmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG9yaWdfYXJndl9idWYsIGFyZ3ZfYnVmKSkpOwogICAgICB9CiAgICAgIHJldHVybiAwOwogICAgfSwgZW52aXJvbl9zaXplc19nZXQoZW52aXJvbl9jb3VudCwgZW52aXJvbl9zaXplKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgYnVmZmVyLnNldFVpbnQzMihlbnZpcm9uX2NvdW50LCBzZWxmLmVudi5sZW5ndGgsIHRydWUpOwogICAgICBsZXQgYnVmX3NpemUgPSAwOwogICAgICBmb3IgKGNvbnN0IGVudmlyb24gb2Ygc2VsZi5lbnYpIHsKICAgICAgICBidWZfc2l6ZSArPSBlbnZpcm9uLmxlbmd0aCArIDE7CiAgICAgIH0KICAgICAgYnVmZmVyLnNldFVpbnQzMihlbnZpcm9uX3NpemUsIGJ1Zl9zaXplLCB0cnVlKTsKICAgICAgZGVidWcubG9nKGJ1ZmZlci5nZXRVaW50MzIoZW52aXJvbl9jb3VudCwgdHJ1ZSksIGJ1ZmZlci5nZXRVaW50MzIoZW52aXJvbl9zaXplLCB0cnVlKSk7CiAgICAgIHJldHVybiAwOwogICAgfSwgZW52aXJvbl9nZXQoZW52aXJvbiwgZW52aXJvbl9idWYpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IG9yaWdfZW52aXJvbl9idWYgPSBlbnZpcm9uX2J1ZjsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmLmVudi5sZW5ndGg7IGkrKykgewogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIoZW52aXJvbiwgZW52aXJvbl9idWYsIHRydWUpOwogICAgICAgIGVudmlyb24gKz0gNDsKICAgICAgICBjb25zdCBlID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHNlbGYuZW52W2ldKTsKICAgICAgICBidWZmZXI4LnNldChlLCBlbnZpcm9uX2J1Zik7CiAgICAgICAgYnVmZmVyLnNldFVpbnQ4KGVudmlyb25fYnVmICsgZS5sZW5ndGgsIDApOwogICAgICAgIGVudmlyb25fYnVmICs9IGUubGVuZ3RoICsgMTsKICAgICAgfQogICAgICBpZiAoZGVidWcuZW5hYmxlZCkgewogICAgICAgIGRlYnVnLmxvZyhuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob3JpZ19lbnZpcm9uX2J1ZiwgZW52aXJvbl9idWYpKSk7CiAgICAgIH0KICAgICAgcmV0dXJuIDA7CiAgICB9LCBjbG9ja19yZXNfZ2V0KGlkLCByZXNfcHRyKSB7CiAgICAgIGxldCByZXNvbHV0aW9uVmFsdWU7CiAgICAgIHN3aXRjaCAoaWQpIHsKICAgICAgICBjYXNlIENMT0NLSURfTU9OT1RPTklDOiB7CiAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSA1MDAwbjsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICBjYXNlIENMT0NLSURfUkVBTFRJTUU6IHsKICAgICAgICAgIHJlc29sdXRpb25WYWx1ZSA9IDEwMDAwMDBuOwogICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICByZXR1cm4gRVJSTk9fTk9TWVM7CiAgICAgIH0KICAgICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgdmlldy5zZXRCaWdVaW50NjQocmVzX3B0ciwgcmVzb2x1dGlvblZhbHVlLCB0cnVlKTsKICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICB9LCBjbG9ja190aW1lX2dldChpZCwgcHJlY2lzaW9uLCB0aW1lKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKGlkID09PSBDTE9DS0lEX1JFQUxUSU1FKSB7CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NCh0aW1lLCBCaWdJbnQobmV3IERhdGUoKS5nZXRUaW1lKCkpICogMTAwMDAwMG4sIHRydWUpOwogICAgICB9IGVsc2UgaWYgKGlkID09IENMT0NLSURfTU9OT1RPTklDKSB7CiAgICAgICAgbGV0IG1vbm90b25pY190aW1lOwogICAgICAgIHRyeSB7CiAgICAgICAgICBtb25vdG9uaWNfdGltZSA9IEJpZ0ludChNYXRoLnJvdW5kKHBlcmZvcm1hbmNlLm5vdygpICogMWU2KSk7CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgbW9ub3RvbmljX3RpbWUgPSAwbjsKICAgICAgICB9CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NCh0aW1lLCBtb25vdG9uaWNfdGltZSwgdHJ1ZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NCh0aW1lLCAwbiwgdHJ1ZSk7CiAgICAgIH0KICAgICAgcmV0dXJuIDA7CiAgICB9LCBmZF9hZHZpc2UoZmQsIG9mZnNldCwgbGVuLCBhZHZpY2UpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfYWxsb2NhdGUoZmQsIG9mZnNldCwgbGVuKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9hbGxvY2F0ZShvZmZzZXQsIGxlbik7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Nsb3NlKGZkKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcmV0ID0gc2VsZi5mZHNbZmRdLmZkX2Nsb3NlKCk7CiAgICAgICAgc2VsZi5mZHNbZmRdID0gdm9pZCAwOwogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2RhdGFzeW5jKGZkKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9zeW5jKCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Zkc3RhdF9nZXQoZmQsIGZkc3RhdF9wdHIpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgZmRzdGF0IH0gPSBzZWxmLmZkc1tmZF0uZmRfZmRzdGF0X2dldCgpOwogICAgICAgIGlmIChmZHN0YXQgIT0gbnVsbCkgewogICAgICAgICAgZmRzdGF0LndyaXRlX2J5dGVzKG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKSwgZmRzdGF0X3B0cik7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Zkc3RhdF9zZXRfZmxhZ3MoZmQsIGZsYWdzKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9mZHN0YXRfc2V0X2ZsYWdzKGZsYWdzKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfZmRzdGF0X3NldF9yaWdodHMoZmQsIGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZykgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmRzdGF0X3NldF9yaWdodHMoZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfZmlsZXN0YXRfZ2V0KGZkLCBmaWxlc3RhdF9wdHIpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgZmlsZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9maWxlc3RhdF9nZXQoKTsKICAgICAgICBpZiAoZmlsZXN0YXQgIT0gbnVsbCkgewogICAgICAgICAgZmlsZXN0YXQud3JpdGVfYnl0ZXMobmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpLCBmaWxlc3RhdF9wdHIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9maWxlc3RhdF9zZXRfc2l6ZShmZCwgc2l6ZSkgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmlsZXN0YXRfc2V0X3NpemUoc2l6ZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2ZpbGVzdGF0X3NldF90aW1lcyhmZCwgYXRpbSwgbXRpbSwgZnN0X2ZsYWdzKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9maWxlc3RhdF9zZXRfdGltZXMoYXRpbSwgbXRpbSwgZnN0X2ZsYWdzKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHJlYWQoZmQsIGlvdnNfcHRyLCBpb3ZzX2xlbiwgb2Zmc2V0LCBucmVhZF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgaW92ZWNzID0gSW92ZWMucmVhZF9ieXRlc19hcnJheShidWZmZXIsIGlvdnNfcHRyLCBpb3ZzX2xlbik7CiAgICAgICAgbGV0IG5yZWFkID0gMDsKICAgICAgICBmb3IgKGNvbnN0IGlvdmVjIG9mIGlvdmVjcykgewogICAgICAgICAgY29uc3QgeyByZXQsIGRhdGEgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wcmVhZChpb3ZlYy5idWZfbGVuLCBvZmZzZXQpOwogICAgICAgICAgaWYgKHJldCAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobnJlYWRfcHRyLCBucmVhZCwgdHJ1ZSk7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgICB9CiAgICAgICAgICBidWZmZXI4LnNldChkYXRhLCBpb3ZlYy5idWYpOwogICAgICAgICAgbnJlYWQgKz0gZGF0YS5sZW5ndGg7CiAgICAgICAgICBvZmZzZXQgKz0gQmlnSW50KGRhdGEubGVuZ3RoKTsKICAgICAgICAgIGlmIChkYXRhLmxlbmd0aCAhPSBpb3ZlYy5idWZfbGVuKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9wcmVzdGF0X2dldChmZCwgYnVmX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIHByZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wcmVzdGF0X2dldCgpOwogICAgICAgIGlmIChwcmVzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIHByZXN0YXQud3JpdGVfYnl0ZXMoYnVmZmVyLCBidWZfcHRyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHJlc3RhdF9kaXJfbmFtZShmZCwgcGF0aF9wdHIsIHBhdGhfbGVuKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIHByZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wcmVzdGF0X2dldCgpOwogICAgICAgIGlmIChwcmVzdGF0ID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHByZXN0YXRfZGlyX25hbWUgPSBwcmVzdGF0LmlubmVyLnByX25hbWU7CiAgICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgIGJ1ZmZlcjguc2V0KHByZXN0YXRfZGlyX25hbWUuc2xpY2UoMCwgcGF0aF9sZW4pLCBwYXRoX3B0cik7CiAgICAgICAgcmV0dXJuIHByZXN0YXRfZGlyX25hbWUuYnl0ZUxlbmd0aCA+IHBhdGhfbGVuID8gRVJSTk9fTkFNRVRPT0xPTkcgOiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9wd3JpdGUoZmQsIGlvdnNfcHRyLCBpb3ZzX2xlbiwgb2Zmc2V0LCBud3JpdHRlbl9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgaW92ZWNzID0gQ2lvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBud3JpdHRlbiA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IGRhdGEgPSBidWZmZXI4LnNsaWNlKGlvdmVjLmJ1ZiwgaW92ZWMuYnVmICsgaW92ZWMuYnVmX2xlbik7CiAgICAgICAgICBjb25zdCB7IHJldCwgbndyaXR0ZW46IG53cml0dGVuX3BhcnQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgbndyaXR0ZW4gKz0gbndyaXR0ZW5fcGFydDsKICAgICAgICAgIG9mZnNldCArPSBCaWdJbnQobndyaXR0ZW5fcGFydCk7CiAgICAgICAgICBpZiAobndyaXR0ZW5fcGFydCAhPSBkYXRhLmJ5dGVMZW5ndGgpIHsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobndyaXR0ZW5fcHRyLCBud3JpdHRlbiwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3JlYWQoZmQsIGlvdnNfcHRyLCBpb3ZzX2xlbiwgbnJlYWRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IGlvdmVjcyA9IElvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBucmVhZCA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBkYXRhIH0gPSBzZWxmLmZkc1tmZF0uZmRfcmVhZChpb3ZlYy5idWZfbGVuKTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgYnVmZmVyOC5zZXQoZGF0YSwgaW92ZWMuYnVmKTsKICAgICAgICAgIG5yZWFkICs9IGRhdGEubGVuZ3RoOwogICAgICAgICAgaWYgKGRhdGEubGVuZ3RoICE9IGlvdmVjLmJ1Zl9sZW4pIHsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobnJlYWRfcHRyLCBucmVhZCwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3JlYWRkaXIoZmQsIGJ1ZiwgYnVmX2xlbiwgY29va2llLCBidWZ1c2VkX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBsZXQgYnVmdXNlZCA9IDA7CiAgICAgICAgd2hpbGUgKHRydWUpIHsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBkaXJlbnQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9yZWFkZGlyX3NpbmdsZShjb29raWUpOwogICAgICAgICAgaWYgKHJldCAhPSAwKSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYnVmdXNlZF9wdHIsIGJ1ZnVzZWQsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgaWYgKGRpcmVudCA9PSBudWxsKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGJ1Zl9sZW4gLSBidWZ1c2VkIDwgZGlyZW50LmhlYWRfbGVuZ3RoKCkpIHsKICAgICAgICAgICAgYnVmdXNlZCA9IGJ1Zl9sZW47CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgaGVhZF9ieXRlcyA9IG5ldyBBcnJheUJ1ZmZlcihkaXJlbnQuaGVhZF9sZW5ndGgoKSk7CiAgICAgICAgICBkaXJlbnQud3JpdGVfaGVhZF9ieXRlcyhuZXcgRGF0YVZpZXcoaGVhZF9ieXRlcyksIDApOwogICAgICAgICAgYnVmZmVyOC5zZXQobmV3IFVpbnQ4QXJyYXkoaGVhZF9ieXRlcykuc2xpY2UoMCwgTWF0aC5taW4oaGVhZF9ieXRlcy5ieXRlTGVuZ3RoLCBidWZfbGVuIC0gYnVmdXNlZCkpLCBidWYpOwogICAgICAgICAgYnVmICs9IGRpcmVudC5oZWFkX2xlbmd0aCgpOwogICAgICAgICAgYnVmdXNlZCArPSBkaXJlbnQuaGVhZF9sZW5ndGgoKTsKICAgICAgICAgIGlmIChidWZfbGVuIC0gYnVmdXNlZCA8IGRpcmVudC5uYW1lX2xlbmd0aCgpKSB7CiAgICAgICAgICAgIGJ1ZnVzZWQgPSBidWZfbGVuOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICAgIGRpcmVudC53cml0ZV9uYW1lX2J5dGVzKGJ1ZmZlcjgsIGJ1ZiwgYnVmX2xlbiAtIGJ1ZnVzZWQpOwogICAgICAgICAgYnVmICs9IGRpcmVudC5uYW1lX2xlbmd0aCgpOwogICAgICAgICAgYnVmdXNlZCArPSBkaXJlbnQubmFtZV9sZW5ndGgoKTsKICAgICAgICAgIGNvb2tpZSA9IGRpcmVudC5kX25leHQ7CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYnVmdXNlZF9wdHIsIGJ1ZnVzZWQsIHRydWUpOwogICAgICAgIHJldHVybiAwOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9yZW51bWJlcihmZCwgdG8pIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDAgJiYgc2VsZi5mZHNbdG9dICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHJldCA9IHNlbGYuZmRzW3RvXS5mZF9jbG9zZSgpOwogICAgICAgIGlmIChyZXQgIT0gMCkgewogICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9CiAgICAgICAgc2VsZi5mZHNbdG9dID0gc2VsZi5mZHNbZmRdOwogICAgICAgIHNlbGYuZmRzW2ZkXSA9IHZvaWQgMDsKICAgICAgICByZXR1cm4gMDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfc2VlayhmZCwgb2Zmc2V0LCB3aGVuY2UsIG9mZnNldF9vdXRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgb2Zmc2V0OiBvZmZzZXRfb3V0IH0gPSBzZWxmLmZkc1tmZF0uZmRfc2VlayhvZmZzZXQsIHdoZW5jZSk7CiAgICAgICAgYnVmZmVyLnNldEJpZ0ludDY0KG9mZnNldF9vdXRfcHRyLCBvZmZzZXRfb3V0LCB0cnVlKTsKICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9zeW5jKGZkKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9zeW5jKCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3RlbGwoZmQsIG9mZnNldF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHsgcmV0LCBvZmZzZXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF90ZWxsKCk7CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NChvZmZzZXRfcHRyLCBvZmZzZXQsIHRydWUpOwogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3dyaXRlKGZkLCBpb3ZzX3B0ciwgaW92c19sZW4sIG53cml0dGVuX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBpb3ZlY3MgPSBDaW92ZWMucmVhZF9ieXRlc19hcnJheShidWZmZXIsIGlvdnNfcHRyLCBpb3ZzX2xlbik7CiAgICAgICAgbGV0IG53cml0dGVuID0gMDsKICAgICAgICBmb3IgKGNvbnN0IGlvdmVjIG9mIGlvdmVjcykgewogICAgICAgICAgY29uc3QgZGF0YSA9IGJ1ZmZlcjguc2xpY2UoaW92ZWMuYnVmLCBpb3ZlYy5idWYgKyBpb3ZlYy5idWZfbGVuKTsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBud3JpdHRlbjogbndyaXR0ZW5fcGFydCB9ID0gc2VsZi5mZHNbZmRdLmZkX3dyaXRlKGRhdGEpOwogICAgICAgICAgaWYgKHJldCAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobndyaXR0ZW5fcHRyLCBud3JpdHRlbiwgdHJ1ZSk7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgICB9CiAgICAgICAgICBud3JpdHRlbiArPSBud3JpdHRlbl9wYXJ0OwogICAgICAgICAgaWYgKG53cml0dGVuX3BhcnQgIT0gZGF0YS5ieXRlTGVuZ3RoKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX2NyZWF0ZV9kaXJlY3RvcnkoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF9jcmVhdGVfZGlyZWN0b3J5KHBhdGgpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX2ZpbGVzdGF0X2dldChmZCwgZmxhZ3MsIHBhdGhfcHRyLCBwYXRoX2xlbiwgZmlsZXN0YXRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCB7IHJldCwgZmlsZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5wYXRoX2ZpbGVzdGF0X2dldChmbGFncywgcGF0aCk7CiAgICAgICAgaWYgKGZpbGVzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIGZpbGVzdGF0LndyaXRlX2J5dGVzKGJ1ZmZlciwgZmlsZXN0YXRfcHRyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9maWxlc3RhdF9zZXRfdGltZXMoZmQsIGZsYWdzLCBwYXRoX3B0ciwgcGF0aF9sZW4sIGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF9maWxlc3RhdF9zZXRfdGltZXMoZmxhZ3MsIHBhdGgsIGF0aW0sIG10aW0sIGZzdF9mbGFncyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfbGluayhvbGRfZmQsIG9sZF9mbGFncywgb2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9sZW4sIG5ld19mZCwgbmV3X3BhdGhfcHRyLCBuZXdfcGF0aF9sZW4pIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbb2xkX2ZkXSAhPSB2b2lkIDAgJiYgc2VsZi5mZHNbbmV3X2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBvbGRfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX3B0ciArIG9sZF9wYXRoX2xlbikpOwogICAgICAgIGNvbnN0IG5ld19wYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfcHRyICsgbmV3X3BhdGhfbGVuKSk7CiAgICAgICAgY29uc3QgeyByZXQsIGlub2RlX29iaiB9ID0gc2VsZi5mZHNbb2xkX2ZkXS5wYXRoX2xvb2t1cChvbGRfcGF0aCwgb2xkX2ZsYWdzKTsKICAgICAgICBpZiAoaW5vZGVfb2JqID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHJldHVybiBzZWxmLmZkc1tuZXdfZmRdLnBhdGhfbGluayhuZXdfcGF0aCwgaW5vZGVfb2JqLCBmYWxzZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfb3BlbihmZCwgZGlyZmxhZ3MsIHBhdGhfcHRyLCBwYXRoX2xlbiwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzLCBvcGVuZWRfZmRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICBkZWJ1Zy5sb2cocGF0aCk7CiAgICAgICAgY29uc3QgeyByZXQsIGZkX29iaiB9ID0gc2VsZi5mZHNbZmRdLnBhdGhfb3BlbihkaXJmbGFncywgcGF0aCwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzKTsKICAgICAgICBpZiAocmV0ICE9IDApIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHNlbGYuZmRzLnB1c2goZmRfb2JqKTsKICAgICAgICBjb25zdCBvcGVuZWRfZmQgPSBzZWxmLmZkcy5sZW5ndGggLSAxOwogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIob3BlbmVkX2ZkX3B0ciwgb3BlbmVkX2ZkLCB0cnVlKTsKICAgICAgICByZXR1cm4gMDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9yZWFkbGluayhmZCwgcGF0aF9wdHIsIHBhdGhfbGVuLCBidWZfcHRyLCBidWZfbGVuLCBucmVhZF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIGRlYnVnLmxvZyhwYXRoKTsKICAgICAgICBjb25zdCB7IHJldCwgZGF0YSB9ID0gc2VsZi5mZHNbZmRdLnBhdGhfcmVhZGxpbmsocGF0aCk7CiAgICAgICAgaWYgKGRhdGEgIT0gbnVsbCkgewogICAgICAgICAgY29uc3QgZGF0YV9idWYgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoZGF0YSk7CiAgICAgICAgICBpZiAoZGF0YV9idWYubGVuZ3RoID4gYnVmX2xlbikgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgMCwgdHJ1ZSk7CiAgICAgICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICAgICAgfQogICAgICAgICAgYnVmZmVyOC5zZXQoZGF0YV9idWYsIGJ1Zl9wdHIpOwogICAgICAgICAgYnVmZmVyLnNldFVpbnQzMihucmVhZF9wdHIsIGRhdGFfYnVmLmxlbmd0aCwgdHJ1ZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfcmVtb3ZlX2RpcmVjdG9yeShmZCwgcGF0aF9wdHIsIHBhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5wYXRoX3JlbW92ZV9kaXJlY3RvcnkocGF0aCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfcmVuYW1lKGZkLCBvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX2xlbiwgbmV3X2ZkLCBuZXdfcGF0aF9wdHIsIG5ld19wYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwICYmIHNlbGYuZmRzW25ld19mZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3Qgb2xkX3BhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9wdHIgKyBvbGRfcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCBuZXdfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShuZXdfcGF0aF9wdHIsIG5ld19wYXRoX3B0ciArIG5ld19wYXRoX2xlbikpOwogICAgICAgIGxldCB7IHJldCwgaW5vZGVfb2JqIH0gPSBzZWxmLmZkc1tmZF0ucGF0aF91bmxpbmsob2xkX3BhdGgpOwogICAgICAgIGlmIChpbm9kZV9vYmogPT0gbnVsbCkgewogICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9CiAgICAgICAgcmV0ID0gc2VsZi5mZHNbbmV3X2ZkXS5wYXRoX2xpbmsobmV3X3BhdGgsIGlub2RlX29iaiwgdHJ1ZSk7CiAgICAgICAgaWYgKHJldCAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICBpZiAoc2VsZi5mZHNbZmRdLnBhdGhfbGluayhvbGRfcGF0aCwgaW5vZGVfb2JqLCB0cnVlKSAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICAgIHRocm93ICJwYXRoX2xpbmsgc2hvdWxkIGFsd2F5cyByZXR1cm4gc3VjY2VzcyB3aGVuIHJlbGlua2luZyBhbiBpbm9kZSBiYWNrIHRvIHRoZSBvcmlnaW5hbCBwbGFjZSI7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfc3ltbGluayhvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX2xlbiwgZmQsIG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBvbGRfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX3B0ciArIG9sZF9wYXRoX2xlbikpOwogICAgICAgIGNvbnN0IG5ld19wYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfcHRyICsgbmV3X3BhdGhfbGVuKSk7CiAgICAgICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF91bmxpbmtfZmlsZShmZCwgcGF0aF9wdHIsIHBhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5wYXRoX3VubGlua19maWxlKHBhdGgpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwb2xsX29uZW9mZihpbl8sIG91dCwgbnN1YnNjcmlwdGlvbnMpIHsKICAgICAgdGhyb3cgImFzeW5jIGlvIG5vdCBzdXBwb3J0ZWQiOwogICAgfSwgcHJvY19leGl0KGV4aXRfY29kZSkgewogICAgICB0aHJvdyBuZXcgV0FTSVByb2NFeGl0KGV4aXRfY29kZSk7CiAgICB9LCBwcm9jX3JhaXNlKHNpZykgewogICAgICB0aHJvdyAicmFpc2VkIHNpZ25hbCAiICsgc2lnOwogICAgfSwgc2NoZWRfeWllbGQoKSB7CiAgICB9LCByYW5kb21fZ2V0KGJ1ZiwgYnVmX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYnVmX2xlbjsgaSsrKSB7CiAgICAgICAgYnVmZmVyOFtidWYgKyBpXSA9IE1hdGgucmFuZG9tKCkgKiAyNTYgfCAwOwogICAgICB9CiAgICB9LCBzb2NrX3JlY3YoZmQsIHJpX2RhdGEsIHJpX2ZsYWdzKSB7CiAgICAgIHRocm93ICJzb2NrZXRzIG5vdCBzdXBwb3J0ZWQiOwogICAgfSwgc29ja19zZW5kKGZkLCBzaV9kYXRhLCBzaV9mbGFncykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHNvY2tfc2h1dGRvd24oZmQsIGhvdykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHNvY2tfYWNjZXB0KGZkLCBmbGFncykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0gfTsKICB9Cn07CgovLyBub2RlX21vZHVsZXMvQGJqb3JuMy9icm93c2VyX3dhc2lfc2hpbS9kaXN0L2ZkLmpzCnZhciBGZCA9IGNsYXNzIHsKICBmZF9hbGxvY2F0ZShvZmZzZXQsIGxlbikgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfY2xvc2UoKSB7CiAgICByZXR1cm4gMDsKICB9CiAgZmRfZmRzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBmZHN0YXQ6IG51bGwgfTsKICB9CiAgZmRfZmRzdGF0X3NldF9mbGFncyhmbGFncykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfZmRzdGF0X3NldF9yaWdodHMoZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nKSB7CiAgICByZXR1cm4gRVJSTk9fTk9UU1VQOwogIH0KICBmZF9maWxlc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZmlsZXN0YXQ6IG51bGwgfTsKICB9CiAgZmRfZmlsZXN0YXRfc2V0X3NpemUoc2l6ZSkgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfZmlsZXN0YXRfc2V0X3RpbWVzKGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfcHJlYWQoc2l6ZSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZGF0YTogbmV3IFVpbnQ4QXJyYXkoKSB9OwogIH0KICBmZF9wcmVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBwcmVzdGF0OiBudWxsIH07CiAgfQogIGZkX3B3cml0ZShkYXRhLCBvZmZzZXQpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBud3JpdHRlbjogMCB9OwogIH0KICBmZF9yZWFkKHNpemUpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBkYXRhOiBuZXcgVWludDhBcnJheSgpIH07CiAgfQogIGZkX3JlYWRkaXJfc2luZ2xlKGNvb2tpZSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGRpcmVudDogbnVsbCB9OwogIH0KICBmZF9zZWVrKG9mZnNldCwgd2hlbmNlKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF9zeW5jKCkgewogICAgcmV0dXJuIDA7CiAgfQogIGZkX3RlbGwoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF93cml0ZShkYXRhKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgbndyaXR0ZW46IDAgfTsKICB9CiAgcGF0aF9jcmVhdGVfZGlyZWN0b3J5KHBhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfZmlsZXN0YXRfZ2V0KGZsYWdzLCBwYXRoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZmlsZXN0YXQ6IG51bGwgfTsKICB9CiAgcGF0aF9maWxlc3RhdF9zZXRfdGltZXMoZmxhZ3MsIHBhdGgsIGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgcGF0aF9saW5rKHBhdGgsIGlub2RlLCBhbGxvd19kaXIpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfdW5saW5rKHBhdGgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBpbm9kZV9vYmo6IG51bGwgfTsKICB9CiAgcGF0aF9sb29rdXAocGF0aCwgZGlyZmxhZ3MpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBpbm9kZV9vYmo6IG51bGwgfTsKICB9CiAgcGF0aF9vcGVuKGRpcmZsYWdzLCBwYXRoLCBvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZywgZmRfZmxhZ3MpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9URElSLCBmZF9vYmo6IG51bGwgfTsKICB9CiAgcGF0aF9yZWFkbGluayhwYXRoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZGF0YTogbnVsbCB9OwogIH0KICBwYXRoX3JlbW92ZV9kaXJlY3RvcnkocGF0aCkgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgcGF0aF9yZW5hbWUob2xkX3BhdGgsIG5ld19mZCwgbmV3X3BhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfdW5saW5rX2ZpbGUocGF0aCkgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9Cn07CnZhciBJbm9kZSA9IGNsYXNzIHsKfTsKCi8vIG5vZGVfbW9kdWxlcy9AYmpvcm4zL2Jyb3dzZXJfd2FzaV9zaGltL2Rpc3QvZnNfbWVtLmpzCnZhciBPcGVuRmlsZSA9IGNsYXNzIGV4dGVuZHMgRmQgewogIGZkX2FsbG9jYXRlKG9mZnNldCwgbGVuKSB7CiAgICBpZiAodGhpcy5maWxlLnNpemUgPiBvZmZzZXQgKyBsZW4pIHsKICAgIH0gZWxzZSB7CiAgICAgIGNvbnN0IG5ld19kYXRhID0gbmV3IFVpbnQ4QXJyYXkoTnVtYmVyKG9mZnNldCArIGxlbikpOwogICAgICBuZXdfZGF0YS5zZXQodGhpcy5maWxlLmRhdGEsIDApOwogICAgICB0aGlzLmZpbGUuZGF0YSA9IG5ld19kYXRhOwogICAgfQogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIGZkc3RhdDogbmV3IEZkc3RhdChGSUxFVFlQRV9SRUdVTEFSX0ZJTEUsIDApIH07CiAgfQogIGZkX2ZpbGVzdGF0X3NldF9zaXplKHNpemUpIHsKICAgIGlmICh0aGlzLmZpbGUuc2l6ZSA+IHNpemUpIHsKICAgICAgdGhpcy5maWxlLmRhdGEgPSBuZXcgVWludDhBcnJheSh0aGlzLmZpbGUuZGF0YS5idWZmZXIuc2xpY2UoMCwgTnVtYmVyKHNpemUpKSk7CiAgICB9IGVsc2UgewogICAgICBjb25zdCBuZXdfZGF0YSA9IG5ldyBVaW50OEFycmF5KE51bWJlcihzaXplKSk7CiAgICAgIG5ld19kYXRhLnNldCh0aGlzLmZpbGUuZGF0YSwgMCk7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3X2RhdGE7CiAgICB9CiAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICB9CiAgZmRfcmVhZChzaXplKSB7CiAgICBjb25zdCBzbGljZSA9IHRoaXMuZmlsZS5kYXRhLnNsaWNlKE51bWJlcih0aGlzLmZpbGVfcG9zKSwgTnVtYmVyKHRoaXMuZmlsZV9wb3MgKyBCaWdJbnQoc2l6ZSkpKTsKICAgIHRoaXMuZmlsZV9wb3MgKz0gQmlnSW50KHNsaWNlLmxlbmd0aCk7CiAgICByZXR1cm4geyByZXQ6IDAsIGRhdGE6IHNsaWNlIH07CiAgfQogIGZkX3ByZWFkKHNpemUsIG9mZnNldCkgewogICAgY29uc3Qgc2xpY2UgPSB0aGlzLmZpbGUuZGF0YS5zbGljZShOdW1iZXIob2Zmc2V0KSwgTnVtYmVyKG9mZnNldCArIEJpZ0ludChzaXplKSkpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBkYXRhOiBzbGljZSB9OwogIH0KICBmZF9zZWVrKG9mZnNldCwgd2hlbmNlKSB7CiAgICBsZXQgY2FsY3VsYXRlZF9vZmZzZXQ7CiAgICBzd2l0Y2ggKHdoZW5jZSkgewogICAgICBjYXNlIFdIRU5DRV9TRVQ6CiAgICAgICAgY2FsY3VsYXRlZF9vZmZzZXQgPSBvZmZzZXQ7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgV0hFTkNFX0NVUjoKICAgICAgICBjYWxjdWxhdGVkX29mZnNldCA9IHRoaXMuZmlsZV9wb3MgKyBvZmZzZXQ7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgV0hFTkNFX0VORDoKICAgICAgICBjYWxjdWxhdGVkX29mZnNldCA9IEJpZ0ludCh0aGlzLmZpbGUuZGF0YS5ieXRlTGVuZ3RoKSArIG9mZnNldDsKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0lOVkFMLCBvZmZzZXQ6IDBuIH07CiAgICB9CiAgICBpZiAoY2FsY3VsYXRlZF9vZmZzZXQgPCAwKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fSU5WQUwsIG9mZnNldDogMG4gfTsKICAgIH0KICAgIHRoaXMuZmlsZV9wb3MgPSBjYWxjdWxhdGVkX29mZnNldDsKICAgIHJldHVybiB7IHJldDogMCwgb2Zmc2V0OiB0aGlzLmZpbGVfcG9zIH07CiAgfQogIGZkX3RlbGwoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIG9mZnNldDogdGhpcy5maWxlX3BvcyB9OwogIH0KICBmZF93cml0ZShkYXRhKSB7CiAgICBpZiAodGhpcy5maWxlLnJlYWRvbmx5KQogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG53cml0dGVuOiAwIH07CiAgICBpZiAodGhpcy5maWxlX3BvcyArIEJpZ0ludChkYXRhLmJ5dGVMZW5ndGgpID4gdGhpcy5maWxlLnNpemUpIHsKICAgICAgY29uc3Qgb2xkID0gdGhpcy5maWxlLmRhdGE7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoTnVtYmVyKHRoaXMuZmlsZV9wb3MgKyBCaWdJbnQoZGF0YS5ieXRlTGVuZ3RoKSkpOwogICAgICB0aGlzLmZpbGUuZGF0YS5zZXQob2xkKTsKICAgIH0KICAgIHRoaXMuZmlsZS5kYXRhLnNldChkYXRhLCBOdW1iZXIodGhpcy5maWxlX3BvcykpOwogICAgdGhpcy5maWxlX3BvcyArPSBCaWdJbnQoZGF0YS5ieXRlTGVuZ3RoKTsKICAgIHJldHVybiB7IHJldDogMCwgbndyaXR0ZW46IGRhdGEuYnl0ZUxlbmd0aCB9OwogIH0KICBmZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KSB7CiAgICBpZiAodGhpcy5maWxlLnJlYWRvbmx5KQogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG53cml0dGVuOiAwIH07CiAgICBpZiAob2Zmc2V0ICsgQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCkgPiB0aGlzLmZpbGUuc2l6ZSkgewogICAgICBjb25zdCBvbGQgPSB0aGlzLmZpbGUuZGF0YTsKICAgICAgdGhpcy5maWxlLmRhdGEgPSBuZXcgVWludDhBcnJheShOdW1iZXIob2Zmc2V0ICsgQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCkpKTsKICAgICAgdGhpcy5maWxlLmRhdGEuc2V0KG9sZCk7CiAgICB9CiAgICB0aGlzLmZpbGUuZGF0YS5zZXQoZGF0YSwgTnVtYmVyKG9mZnNldCkpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBud3JpdHRlbjogZGF0YS5ieXRlTGVuZ3RoIH07CiAgfQogIGZkX2ZpbGVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgZmlsZXN0YXQ6IHRoaXMuZmlsZS5zdGF0KCkgfTsKICB9CiAgY29uc3RydWN0b3IoZmlsZSkgewogICAgc3VwZXIoKTsKICAgIHRoaXMuZmlsZV9wb3MgPSAwbjsKICAgIHRoaXMuZmlsZSA9IGZpbGU7CiAgfQp9Owp2YXIgT3BlbkRpcmVjdG9yeSA9IGNsYXNzIGV4dGVuZHMgRmQgewogIGZkX3NlZWsob2Zmc2V0LCB3aGVuY2UpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fQkFERiwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF90ZWxsKCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBvZmZzZXQ6IDBuIH07CiAgfQogIGZkX2FsbG9jYXRlKG9mZnNldCwgbGVuKSB7CiAgICByZXR1cm4gRVJSTk9fQkFERjsKICB9CiAgZmRfZmRzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgZmRzdGF0OiBuZXcgRmRzdGF0KEZJTEVUWVBFX0RJUkVDVE9SWSwgMCkgfTsKICB9CiAgZmRfcmVhZGRpcl9zaW5nbGUoY29va2llKSB7CiAgICBpZiAoZGVidWcuZW5hYmxlZCkgewogICAgICBkZWJ1Zy5sb2coInJlYWRkaXJfc2luZ2xlIiwgY29va2llKTsKICAgICAgZGVidWcubG9nKGNvb2tpZSwgdGhpcy5kaXIuY29udGVudHMua2V5cygpKTsKICAgIH0KICAgIGlmIChjb29raWUgPT0gMG4pIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBkaXJlbnQ6IG5ldyBEaXJlbnQoMW4sICIuIiwgRklMRVRZUEVfRElSRUNUT1JZKSB9OwogICAgfSBlbHNlIGlmIChjb29raWUgPT0gMW4pIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBkaXJlbnQ6IG5ldyBEaXJlbnQoMm4sICIuLiIsIEZJTEVUWVBFX0RJUkVDVE9SWSkgfTsKICAgIH0KICAgIGlmIChjb29raWUgPj0gQmlnSW50KHRoaXMuZGlyLmNvbnRlbnRzLnNpemUpICsgMm4pIHsKICAgICAgcmV0dXJuIHsgcmV0OiAwLCBkaXJlbnQ6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IFtuYW1lLCBlbnRyeV0gPSBBcnJheS5mcm9tKHRoaXMuZGlyLmNvbnRlbnRzLmVudHJpZXMoKSlbTnVtYmVyKGNvb2tpZSAtIDJuKV07CiAgICByZXR1cm4geyByZXQ6IDAsIGRpcmVudDogbmV3IERpcmVudChjb29raWUgKyAxbiwgbmFtZSwgZW50cnkuc3RhdCgpLmZpbGV0eXBlKSB9OwogIH0KICBwYXRoX2ZpbGVzdGF0X2dldChmbGFncywgcGF0aF9zdHIpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX2VyciwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX2VyciwgZmlsZXN0YXQ6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0LCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0LCBmaWxlc3RhdDogbnVsbCB9OwogICAgfQogICAgcmV0dXJuIHsgcmV0OiAwLCBmaWxlc3RhdDogZW50cnkuc3RhdCgpIH07CiAgfQogIHBhdGhfbG9va3VwKHBhdGhfc3RyLCBkaXJmbGFncykgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhdGhfcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0LCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgaW5vZGVfb2JqOiBlbnRyeSB9OwogIH0KICBwYXRoX29wZW4oZGlyZmxhZ3MsIHBhdGhfc3RyLCBvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZywgZmRfZmxhZ3MpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX3JldCwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX3JldCwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICBsZXQgeyByZXQsIGVudHJ5IH0gPSB0aGlzLmRpci5nZXRfZW50cnlfZm9yX3BhdGgocGF0aCk7CiAgICBpZiAoZW50cnkgPT0gbnVsbCkgewogICAgICBpZiAocmV0ICE9IEVSUk5PX05PRU5UKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0LCBmZF9vYmo6IG51bGwgfTsKICAgICAgfQogICAgICBpZiAoKG9mbGFncyAmIE9GTEFHU19DUkVBVCkgPT0gT0ZMQUdTX0NSRUFUKSB7CiAgICAgICAgY29uc3QgeyByZXQ6IHJldDIsIGVudHJ5OiBuZXdfZW50cnkgfSA9IHRoaXMuZGlyLmNyZWF0ZV9lbnRyeV9mb3JfcGF0aChwYXRoX3N0ciwgKG9mbGFncyAmIE9GTEFHU19ESVJFQ1RPUlkpID09IE9GTEFHU19ESVJFQ1RPUlkpOwogICAgICAgIGlmIChuZXdfZW50cnkgPT0gbnVsbCkgewogICAgICAgICAgcmV0dXJuIHsgcmV0OiByZXQyLCBmZF9vYmo6IG51bGwgfTsKICAgICAgICB9CiAgICAgICAgZW50cnkgPSBuZXdfZW50cnk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT0VOVCwgZmRfb2JqOiBudWxsIH07CiAgICAgIH0KICAgIH0gZWxzZSBpZiAoKG9mbGFncyAmIE9GTEFHU19FWENMKSA9PSBPRkxBR1NfRVhDTCkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0VYSVNULCBmZF9vYmo6IG51bGwgfTsKICAgIH0KICAgIGlmICgob2ZsYWdzICYgT0ZMQUdTX0RJUkVDVE9SWSkgPT0gT0ZMQUdTX0RJUkVDVE9SWSAmJiBlbnRyeS5zdGF0KCkuZmlsZXR5cGUgIT09IEZJTEVUWVBFX0RJUkVDVE9SWSkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICByZXR1cm4gZW50cnkucGF0aF9vcGVuKG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZkX2ZsYWdzKTsKICB9CiAgcGF0aF9jcmVhdGVfZGlyZWN0b3J5KHBhdGgpIHsKICAgIHJldHVybiB0aGlzLnBhdGhfb3BlbigwLCBwYXRoLCBPRkxBR1NfQ1JFQVQgfCBPRkxBR1NfRElSRUNUT1JZLCAwbiwgMG4sIDApLnJldDsKICB9CiAgcGF0aF9saW5rKHBhdGhfc3RyLCBpbm9kZSwgYWxsb3dfZGlyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXRoX3JldDsKICAgIH0KICAgIGlmIChwYXRoLmlzX2RpcikgewogICAgICByZXR1cm4gRVJSTk9fTk9FTlQ7CiAgICB9CiAgICBjb25zdCB7IHJldDogcGFyZW50X3JldCwgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9wYXJlbnRfZGlyX2FuZF9lbnRyeV9mb3JfcGF0aChwYXRoLCB0cnVlKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCB8fCBmaWxlbmFtZSA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXJlbnRfcmV0OwogICAgfQogICAgaWYgKGVudHJ5ICE9IG51bGwpIHsKICAgICAgY29uc3Qgc291cmNlX2lzX2RpciA9IGlub2RlLnN0YXQoKS5maWxldHlwZSA9PSBGSUxFVFlQRV9ESVJFQ1RPUlk7CiAgICAgIGNvbnN0IHRhcmdldF9pc19kaXIgPSBlbnRyeS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfRElSRUNUT1JZOwogICAgICBpZiAoc291cmNlX2lzX2RpciAmJiB0YXJnZXRfaXNfZGlyKSB7CiAgICAgICAgaWYgKGFsbG93X2RpciAmJiBlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkgewogICAgICAgICAgaWYgKGVudHJ5LmNvbnRlbnRzLnNpemUgPT0gMCkgewogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcmV0dXJuIEVSUk5PX05PVEVNUFRZOwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXR1cm4gRVJSTk9fRVhJU1Q7CiAgICAgICAgfQogICAgICB9IGVsc2UgaWYgKHNvdXJjZV9pc19kaXIgJiYgIXRhcmdldF9pc19kaXIpIHsKICAgICAgICByZXR1cm4gRVJSTk9fTk9URElSOwogICAgICB9IGVsc2UgaWYgKCFzb3VyY2VfaXNfZGlyICYmIHRhcmdldF9pc19kaXIpIHsKICAgICAgICByZXR1cm4gRVJSTk9fSVNESVI7CiAgICAgIH0gZWxzZSBpZiAoaW5vZGUuc3RhdCgpLmZpbGV0eXBlID09IEZJTEVUWVBFX1JFR1VMQVJfRklMRSAmJiBlbnRyeS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfUkVHVUxBUl9GSUxFKSB7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0VYSVNUOwogICAgICB9CiAgICB9CiAgICBpZiAoIWFsbG93X2RpciAmJiBpbm9kZS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgIHJldHVybiBFUlJOT19QRVJNOwogICAgfQogICAgcGFyZW50X2VudHJ5LmNvbnRlbnRzLnNldChmaWxlbmFtZSwgaW5vZGUpOwogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIHBhdGhfdW5saW5rKHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogcGF0aF9yZXQsIGlub2RlX29iajogbnVsbCB9OwogICAgfQogICAgY29uc3QgeyByZXQ6IHBhcmVudF9yZXQsIHBhcmVudF9lbnRyeSwgZmlsZW5hbWUsIGVudHJ5IH0gPSB0aGlzLmRpci5nZXRfcGFyZW50X2Rpcl9hbmRfZW50cnlfZm9yX3BhdGgocGF0aCwgdHJ1ZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhcmVudF9yZXQsIGlub2RlX29iajogbnVsbCB9OwogICAgfQogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT0VOVCwgaW5vZGVfb2JqOiBudWxsIH07CiAgICB9CiAgICBwYXJlbnRfZW50cnkuY29udGVudHMuZGVsZXRlKGZpbGVuYW1lKTsKICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgaW5vZGVfb2JqOiBlbnRyeSB9OwogIH0KICBwYXRoX3VubGlua19maWxlKHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXRoX3JldDsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIGZhbHNlKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCB8fCBmaWxlbmFtZSA9PSBudWxsIHx8IGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHBhcmVudF9yZXQ7CiAgICB9CiAgICBpZiAoZW50cnkuc3RhdCgpLmZpbGV0eXBlID09PSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgcmV0dXJuIEVSUk5PX0lTRElSOwogICAgfQogICAgcGFyZW50X2VudHJ5LmNvbnRlbnRzLmRlbGV0ZShmaWxlbmFtZSk7CiAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICB9CiAgcGF0aF9yZW1vdmVfZGlyZWN0b3J5KHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXRoX3JldDsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIGZhbHNlKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCB8fCBmaWxlbmFtZSA9PSBudWxsIHx8IGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHBhcmVudF9yZXQ7CiAgICB9CiAgICBpZiAoIShlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkgfHwgZW50cnkuc3RhdCgpLmZpbGV0eXBlICE9PSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgcmV0dXJuIEVSUk5PX05PVERJUjsKICAgIH0KICAgIGlmIChlbnRyeS5jb250ZW50cy5zaXplICE9PSAwKSB7CiAgICAgIHJldHVybiBFUlJOT19OT1RFTVBUWTsKICAgIH0KICAgIGlmICghcGFyZW50X2VudHJ5LmNvbnRlbnRzLmRlbGV0ZShmaWxlbmFtZSkpIHsKICAgICAgcmV0dXJuIEVSUk5PX05PRU5UOwogICAgfQogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIGZkX2ZpbGVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgZmlsZXN0YXQ6IHRoaXMuZGlyLnN0YXQoKSB9OwogIH0KICBmZF9maWxlc3RhdF9zZXRfc2l6ZShzaXplKSB7CiAgICByZXR1cm4gRVJSTk9fQkFERjsKICB9CiAgZmRfcmVhZChzaXplKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIGRhdGE6IG5ldyBVaW50OEFycmF5KCkgfTsKICB9CiAgZmRfcHJlYWQoc2l6ZSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIGRhdGE6IG5ldyBVaW50OEFycmF5KCkgfTsKICB9CiAgZmRfd3JpdGUoZGF0YSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBud3JpdHRlbjogMCB9OwogIH0KICBmZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG53cml0dGVuOiAwIH07CiAgfQogIGNvbnN0cnVjdG9yKGRpcikgewogICAgc3VwZXIoKTsKICAgIHRoaXMuZGlyID0gZGlyOwogIH0KfTsKdmFyIFByZW9wZW5EaXJlY3RvcnkgPSBjbGFzcyBleHRlbmRzIE9wZW5EaXJlY3RvcnkgewogIGZkX3ByZXN0YXRfZ2V0KCkgewogICAgcmV0dXJuIHsgcmV0OiAwLCBwcmVzdGF0OiBQcmVzdGF0LmRpcih0aGlzLnByZXN0YXRfbmFtZSkgfTsKICB9CiAgY29uc3RydWN0b3IobmFtZSwgY29udGVudHMpIHsKICAgIHN1cGVyKG5ldyBEaXJlY3RvcnkoY29udGVudHMpKTsKICAgIHRoaXMucHJlc3RhdF9uYW1lID0gbmFtZTsKICB9Cn07CnZhciBGaWxlID0gY2xhc3MgZXh0ZW5kcyBJbm9kZSB7CiAgcGF0aF9vcGVuKG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZkX2ZsYWdzKSB7CiAgICBpZiAodGhpcy5yZWFkb25seSAmJiAoZnNfcmlnaHRzX2Jhc2UgJiBCaWdJbnQoUklHSFRTX0ZEX1dSSVRFKSkgPT0gQmlnSW50KFJJR0hUU19GRF9XUklURSkpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19QRVJNLCBmZF9vYmo6IG51bGwgfTsKICAgIH0KICAgIGlmICgob2ZsYWdzICYgT0ZMQUdTX1RSVU5DKSA9PSBPRkxBR1NfVFJVTkMpIHsKICAgICAgaWYgKHRoaXMucmVhZG9ubHkpCiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19QRVJNLCBmZF9vYmo6IG51bGwgfTsKICAgICAgdGhpcy5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoW10pOwogICAgfQogICAgY29uc3QgZmlsZSA9IG5ldyBPcGVuRmlsZSh0aGlzKTsKICAgIGlmIChmZF9mbGFncyAmIEZERkxBR1NfQVBQRU5EKQogICAgICBmaWxlLmZkX3NlZWsoMG4sIFdIRU5DRV9FTkQpOwogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBmZF9vYmo6IGZpbGUgfTsKICB9CiAgZ2V0IHNpemUoKSB7CiAgICByZXR1cm4gQmlnSW50KHRoaXMuZGF0YS5ieXRlTGVuZ3RoKTsKICB9CiAgc3RhdCgpIHsKICAgIHJldHVybiBuZXcgRmlsZXN0YXQoRklMRVRZUEVfUkVHVUxBUl9GSUxFLCB0aGlzLnNpemUpOwogIH0KICBjb25zdHJ1Y3RvcihkYXRhLCBvcHRpb25zKSB7CiAgICBzdXBlcigpOwogICAgdGhpcy5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoZGF0YSk7CiAgICB0aGlzLnJlYWRvbmx5ID0gISFvcHRpb25zPy5yZWFkb25seTsKICB9Cn07CnZhciBQYXRoID0gY2xhc3MgUGF0aDIgewogIHN0YXRpYyBmcm9tKHBhdGgpIHsKICAgIGNvbnN0IHNlbGYgPSBuZXcgUGF0aDIoKTsKICAgIHNlbGYuaXNfZGlyID0gcGF0aC5lbmRzV2l0aCgiLyIpOwogICAgaWYgKHBhdGguc3RhcnRzV2l0aCgiLyIpKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UQ0FQQUJMRSwgcGF0aDogbnVsbCB9OwogICAgfQogICAgaWYgKHBhdGguaW5jbHVkZXMoIlwwIikpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19JTlZBTCwgcGF0aDogbnVsbCB9OwogICAgfQogICAgZm9yIChjb25zdCBjb21wb25lbnQgb2YgcGF0aC5zcGxpdCgiLyIpKSB7CiAgICAgIGlmIChjb21wb25lbnQgPT09ICIiIHx8IGNvbXBvbmVudCA9PT0gIi4iKSB7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgaWYgKGNvbXBvbmVudCA9PT0gIi4uIikgewogICAgICAgIGlmIChzZWxmLnBhcnRzLnBvcCgpID09IHZvaWQgMCkgewogICAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RDQVBBQkxFLCBwYXRoOiBudWxsIH07CiAgICAgICAgfQogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIHNlbGYucGFydHMucHVzaChjb21wb25lbnQpOwogICAgfQogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBwYXRoOiBzZWxmIH07CiAgfQogIHRvX3BhdGhfc3RyaW5nKCkgewogICAgbGV0IHMgPSB0aGlzLnBhcnRzLmpvaW4oIi8iKTsKICAgIGlmICh0aGlzLmlzX2RpcikgewogICAgICBzICs9ICIvIjsKICAgIH0KICAgIHJldHVybiBzOwogIH0KICBjb25zdHJ1Y3RvcigpIHsKICAgIHRoaXMucGFydHMgPSBbXTsKICAgIHRoaXMuaXNfZGlyID0gZmFsc2U7CiAgfQp9Owp2YXIgRGlyZWN0b3J5ID0gY2xhc3MgZXh0ZW5kcyBJbm9kZSB7CiAgcGF0aF9vcGVuKG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZkX2ZsYWdzKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGZkX29iajogbmV3IE9wZW5EaXJlY3RvcnkodGhpcykgfTsKICB9CiAgc3RhdCgpIHsKICAgIHJldHVybiBuZXcgRmlsZXN0YXQoRklMRVRZUEVfRElSRUNUT1JZLCAwbik7CiAgfQogIGdldF9lbnRyeV9mb3JfcGF0aChwYXRoKSB7CiAgICBsZXQgZW50cnkgPSB0aGlzOwogICAgZm9yIChjb25zdCBjb21wb25lbnQgb2YgcGF0aC5wYXJ0cykgewogICAgICBpZiAoIShlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkpIHsKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgICBjb25zdCBjaGlsZCA9IGVudHJ5LmNvbnRlbnRzLmdldChjb21wb25lbnQpOwogICAgICBpZiAoY2hpbGQgIT09IHZvaWQgMCkgewogICAgICAgIGVudHJ5ID0gY2hpbGQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgZGVidWcubG9nKGNvbXBvbmVudCk7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT0VOVCwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgfQogICAgaWYgKHBhdGguaXNfZGlyKSB7CiAgICAgIGlmIChlbnRyeS5zdGF0KCkuZmlsZXR5cGUgIT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIGVudHJ5OiBudWxsIH07CiAgICAgIH0KICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZW50cnkgfTsKICB9CiAgZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIGFsbG93X3VuZGVmaW5lZCkgewogICAgY29uc3QgZmlsZW5hbWUgPSBwYXRoLnBhcnRzLnBvcCgpOwogICAgaWYgKGZpbGVuYW1lID09PSB2b2lkIDApIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19JTlZBTCwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBlbnRyeV9yZXQsIGVudHJ5OiBwYXJlbnRfZW50cnkgfSA9IHRoaXMuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKHBhcmVudF9lbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogZW50cnlfcmV0LCBwYXJlbnRfZW50cnk6IG51bGwsIGZpbGVuYW1lOiBudWxsLCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgaWYgKCEocGFyZW50X2VudHJ5IGluc3RhbmNlb2YgRGlyZWN0b3J5KSkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IGVudHJ5ID0gcGFyZW50X2VudHJ5LmNvbnRlbnRzLmdldChmaWxlbmFtZSk7CiAgICBpZiAoZW50cnkgPT09IHZvaWQgMCkgewogICAgICBpZiAoIWFsbG93X3VuZGVmaW5lZCkgewogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9FTlQsIHBhcmVudF9lbnRyeTogbnVsbCwgZmlsZW5hbWU6IG51bGwsIGVudHJ5OiBudWxsIH07CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeTogbnVsbCB9OwogICAgICB9CiAgICB9CiAgICBpZiAocGF0aC5pc19kaXIpIHsKICAgICAgaWYgKGVudHJ5LnN0YXQoKS5maWxldHlwZSAhPSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9OwogIH0KICBjcmVhdGVfZW50cnlfZm9yX3BhdGgocGF0aF9zdHIsIGlzX2RpcikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhdGhfcmV0LCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgbGV0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5nZXRfcGFyZW50X2Rpcl9hbmRfZW50cnlfZm9yX3BhdGgocGF0aCwgdHJ1ZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhcmVudF9yZXQsIGVudHJ5OiBudWxsIH07CiAgICB9CiAgICBpZiAoZW50cnkgIT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0VYSVNULCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgZGVidWcubG9nKCJjcmVhdGUiLCBwYXRoKTsKICAgIGxldCBuZXdfY2hpbGQ7CiAgICBpZiAoIWlzX2RpcikgewogICAgICBuZXdfY2hpbGQgPSBuZXcgRmlsZShuZXcgQXJyYXlCdWZmZXIoMCkpOwogICAgfSBlbHNlIHsKICAgICAgbmV3X2NoaWxkID0gbmV3IERpcmVjdG9yeSgvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpKTsKICAgIH0KICAgIHBhcmVudF9lbnRyeS5jb250ZW50cy5zZXQoZmlsZW5hbWUsIG5ld19jaGlsZCk7CiAgICBlbnRyeSA9IG5ld19jaGlsZDsKICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZW50cnkgfTsKICB9CiAgY29uc3RydWN0b3IoY29udGVudHMpIHsKICAgIHN1cGVyKCk7CiAgICBpZiAoY29udGVudHMgaW5zdGFuY2VvZiBBcnJheSkgewogICAgICB0aGlzLmNvbnRlbnRzID0gbmV3IE1hcChjb250ZW50cyk7CiAgICB9IGVsc2UgewogICAgICB0aGlzLmNvbnRlbnRzID0gY29udGVudHM7CiAgICB9CiAgfQp9Owp2YXIgQ29uc29sZVN0ZG91dCA9IGNsYXNzIGV4dGVuZHMgRmQgewogIGZkX2ZpbGVzdGF0X2dldCgpIHsKICAgIGNvbnN0IGZpbGVzdGF0ID0gbmV3IEZpbGVzdGF0KEZJTEVUWVBFX0NIQVJBQ1RFUl9ERVZJQ0UsIEJpZ0ludCgwKSk7CiAgICByZXR1cm4geyByZXQ6IDAsIGZpbGVzdGF0IH07CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICBjb25zdCBmZHN0YXQgPSBuZXcgRmRzdGF0KEZJTEVUWVBFX0NIQVJBQ1RFUl9ERVZJQ0UsIDApOwogICAgZmRzdGF0LmZzX3JpZ2h0c19iYXNlID0gQmlnSW50KFJJR0hUU19GRF9XUklURSk7CiAgICByZXR1cm4geyByZXQ6IDAsIGZkc3RhdCB9OwogIH0KICBmZF93cml0ZShkYXRhKSB7CiAgICB0aGlzLndyaXRlKGRhdGEpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBud3JpdHRlbjogZGF0YS5ieXRlTGVuZ3RoIH07CiAgfQogIHN0YXRpYyBsaW5lQnVmZmVyZWQod3JpdGUpIHsKICAgIGNvbnN0IGRlYyA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiLCB7IGZhdGFsOiBmYWxzZSB9KTsKICAgIGxldCBsaW5lX2J1ZiA9ICIiOwogICAgcmV0dXJuIG5ldyBDb25zb2xlU3Rkb3V0KChidWZmZXIpID0+IHsKICAgICAgbGluZV9idWYgKz0gZGVjLmRlY29kZShidWZmZXIsIHsgc3RyZWFtOiB0cnVlIH0pOwogICAgICBjb25zdCBsaW5lcyA9IGxpbmVfYnVmLnNwbGl0KCJcbiIpOwogICAgICBmb3IgKGNvbnN0IFtpLCBsaW5lXSBvZiBsaW5lcy5lbnRyaWVzKCkpIHsKICAgICAgICBpZiAoaSA8IGxpbmVzLmxlbmd0aCAtIDEpIHsKICAgICAgICAgIHdyaXRlKGxpbmUpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBsaW5lX2J1ZiA9IGxpbmU7CiAgICAgICAgfQogICAgICB9CiAgICB9KTsKICB9CiAgY29uc3RydWN0b3Iod3JpdGUpIHsKICAgIHN1cGVyKCk7CiAgICB0aGlzLndyaXRlID0gd3JpdGU7CiAgfQp9OwoKLy8gbm9kZV9tb2R1bGVzL3dhc20taW1wb3J0cy1wYXJzZXIvaW5kZXguanMKZnVuY3Rpb24gcGFyc2VJbXBvcnRzKG1vZHVsZUJ5dGVzKSB7CiAgaWYgKG1vZHVsZUJ5dGVzIGluc3RhbmNlb2YgVWludDhBcnJheSkgewogIH0gZWxzZSBpZiAobW9kdWxlQnl0ZXMgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgewogICAgbW9kdWxlQnl0ZXMgPSBuZXcgVWludDhBcnJheShtb2R1bGVCeXRlcyk7CiAgfSBlbHNlIGlmIChtb2R1bGVCeXRlcy5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgewogICAgbW9kdWxlQnl0ZXMgPSBuZXcgVWludDhBcnJheShtb2R1bGVCeXRlcy5idWZmZXIpOwogIH0gZWxzZSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkFyZ3VtZW50IG11c3QgYmUgYSBidWZmZXIgc291cmNlLCBsaWtlIFVpbnQ4QXJyYXkgb3IgQXJyYXlCdWZmZXIiKTsKICB9CiAgY29uc3QgcGFyc2VTdGF0ZSA9IG5ldyBQYXJzZVN0YXRlKG1vZHVsZUJ5dGVzKTsKICBwYXJzZU1hZ2ljTnVtYmVyKHBhcnNlU3RhdGUpOwogIHBhcnNlVmVyc2lvbihwYXJzZVN0YXRlKTsKICBjb25zdCB0eXBlcyA9IFtdOwogIGNvbnN0IGltcG9ydHMgPSBbXTsKICB3aGlsZSAocGFyc2VTdGF0ZS5oYXNNb3JlQnl0ZXMoKSkgewogICAgY29uc3Qgc2VjdGlvbklkID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogICAgY29uc3Qgc2VjdGlvblNpemUgPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgc3dpdGNoIChzZWN0aW9uSWQpIHsKICAgICAgY2FzZSAxOiB7CiAgICAgICAgY29uc3QgdHlwZUNvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHR5cGVDb3VudDsgaSsrKSB7CiAgICAgICAgICB0eXBlcy5wdXNoKHBhcnNlRnVuY3Rpb25UeXBlKHBhcnNlU3RhdGUpKTsKICAgICAgICB9CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgY2FzZSAyOiB7CiAgICAgICAgY29uc3QgaW1wb3J0Q291bnQgPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW1wb3J0Q291bnQ7IGkrKykgewogICAgICAgICAgY29uc3QgbW9kdWxlID0gcGFyc2VTdGF0ZS5yZWFkTmFtZSgpOwogICAgICAgICAgY29uc3QgbmFtZSA9IHBhcnNlU3RhdGUucmVhZE5hbWUoKTsKICAgICAgICAgIGNvbnN0IHR5cGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgICAgICAgICBzd2l0Y2ggKHR5cGUpIHsKICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJmdW5jdGlvbiIsIHR5cGU6IHR5cGVzW2luZGV4XSB9KTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICAgIGltcG9ydHMucHVzaCh7IG1vZHVsZSwgbmFtZSwga2luZDogInRhYmxlIiwgdHlwZTogcGFyc2VUYWJsZVR5cGUocGFyc2VTdGF0ZSkgfSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJtZW1vcnkiLCB0eXBlOiBwYXJzZUxpbWl0cyhwYXJzZVN0YXRlKSB9KTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgIGltcG9ydHMucHVzaCh7IG1vZHVsZSwgbmFtZSwga2luZDogImdsb2JhbCIsIHR5cGU6IHBhcnNlR2xvYmFsVHlwZShwYXJzZVN0YXRlKSB9KTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gaW1wb3J0IGRlc2NyaXB0b3IgdHlwZSAke3R5cGV9YCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBpbXBvcnRzOwogICAgICB9CiAgICAgIGRlZmF1bHQ6IHsKICAgICAgICBwYXJzZVN0YXRlLnNraXBCeXRlcyhzZWN0aW9uU2l6ZSk7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgIH0KICB9CiAgcmV0dXJuIFtdOwp9CnZhciBQYXJzZVN0YXRlID0gY2xhc3MgewogIGNvbnN0cnVjdG9yKG1vZHVsZUJ5dGVzKSB7CiAgICB0aGlzLm1vZHVsZUJ5dGVzID0gbW9kdWxlQnl0ZXM7CiAgICB0aGlzLm9mZnNldCA9IDA7CiAgICB0aGlzLnRleHREZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpOwogIH0KICBoYXNNb3JlQnl0ZXMoKSB7CiAgICByZXR1cm4gdGhpcy5vZmZzZXQgPCB0aGlzLm1vZHVsZUJ5dGVzLmxlbmd0aDsKICB9CiAgcmVhZEJ5dGUoKSB7CiAgICByZXR1cm4gdGhpcy5tb2R1bGVCeXRlc1t0aGlzLm9mZnNldCsrXTsKICB9CiAgc2tpcEJ5dGVzKGNvdW50KSB7CiAgICB0aGlzLm9mZnNldCArPSBjb3VudDsKICB9CiAgcmVhZFVuc2lnbmVkTEVCMTI4KCkgewogICAgbGV0IHJlc3VsdCA9IDA7CiAgICBsZXQgc2hpZnQgPSAwOwogICAgbGV0IGJ5dGU7CiAgICBkbyB7CiAgICAgIGJ5dGUgPSB0aGlzLnJlYWRCeXRlKCk7CiAgICAgIHJlc3VsdCB8PSAoYnl0ZSAmIDEyNykgPDwgc2hpZnQ7CiAgICAgIHNoaWZ0ICs9IDc7CiAgICB9IHdoaWxlIChieXRlICYgMTI4KTsKICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHJlYWROYW1lKCkgewogICAgY29uc3QgbmFtZUxlbmd0aCA9IHRoaXMucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICBjb25zdCBuYW1lQnl0ZXMgPSB0aGlzLm1vZHVsZUJ5dGVzLnNsaWNlKHRoaXMub2Zmc2V0LCB0aGlzLm9mZnNldCArIG5hbWVMZW5ndGgpOwogICAgY29uc3QgbmFtZSA9IHRoaXMudGV4dERlY29kZXIuZGVjb2RlKG5hbWVCeXRlcyk7CiAgICB0aGlzLm9mZnNldCArPSBuYW1lTGVuZ3RoOwogICAgcmV0dXJuIG5hbWU7CiAgfQogIGFzc2VydEJ5dGVzKGV4cGVjdGVkKSB7CiAgICBjb25zdCBiYXNlT2Zmc2V0ID0gdGhpcy5vZmZzZXQ7CiAgICBjb25zdCBleHBlY3RlZExlbmd0aCA9IGV4cGVjdGVkLmxlbmd0aDsKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZXhwZWN0ZWRMZW5ndGg7IGkrKykgewogICAgICBpZiAodGhpcy5tb2R1bGVCeXRlc1tiYXNlT2Zmc2V0ICsgaV0gIT09IGV4cGVjdGVkW2ldKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCAke2V4cGVjdGVkfSBhdCBvZmZzZXQgJHtiYXNlT2Zmc2V0fWApOwogICAgICB9CiAgICB9CiAgICB0aGlzLm9mZnNldCArPSBleHBlY3RlZExlbmd0aDsKICB9Cn07CmZ1bmN0aW9uIHBhcnNlTWFnaWNOdW1iZXIocGFyc2VTdGF0ZSkgewogIGNvbnN0IGV4cGVjdGVkID0gWzAsIDk3LCAxMTUsIDEwOV07CiAgcGFyc2VTdGF0ZS5hc3NlcnRCeXRlcyhleHBlY3RlZCk7Cn0KZnVuY3Rpb24gcGFyc2VWZXJzaW9uKHBhcnNlU3RhdGUpIHsKICBjb25zdCBleHBlY3RlZCA9IFsxLCAwLCAwLCAwXTsKICBwYXJzZVN0YXRlLmFzc2VydEJ5dGVzKGV4cGVjdGVkKTsKfQpmdW5jdGlvbiBwYXJzZVRhYmxlVHlwZShwYXJzZVN0YXRlKSB7CiAgY29uc3QgZWxlbWVudFR5cGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgbGV0IGVsZW1lbnQ7CiAgc3dpdGNoIChlbGVtZW50VHlwZSkgewogICAgY2FzZSAxMTI6CiAgICAgIGVsZW1lbnQgPSAiZnVuY3JlZiI7CiAgICAgIGJyZWFrOwogICAgY2FzZSAxMTE6CiAgICAgIGVsZW1lbnQgPSAiZXh0ZXJucmVmIjsKICAgICAgYnJlYWs7CiAgICBkZWZhdWx0OgogICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gdGFibGUgZWxlbWVudCB0eXBlICR7ZWxlbWVudFR5cGV9YCk7CiAgfQogIGNvbnN0IHsgbWluaW11bSwgbWF4aW11bSB9ID0gcGFyc2VMaW1pdHMocGFyc2VTdGF0ZSk7CiAgaWYgKG1heGltdW0pIHsKICAgIHJldHVybiB7IGVsZW1lbnQsIG1pbmltdW0sIG1heGltdW0gfTsKICB9IGVsc2UgewogICAgcmV0dXJuIHsgZWxlbWVudCwgbWluaW11bSB9OwogIH0KfQpmdW5jdGlvbiBwYXJzZUxpbWl0cyhwYXJzZVN0YXRlKSB7CiAgY29uc3QgZmxhZ3MgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgY29uc3QgbWluaW11bSA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgY29uc3QgaGFzTWF4aW11bSA9IGZsYWdzICYgMTsKICBjb25zdCBzaGFyZWQgPSAoZmxhZ3MgJiAyKSAhPT0gMDsKICBjb25zdCBpc01lbW9yeTY0ID0gKGZsYWdzICYgNCkgIT09IDA7CiAgY29uc3QgaW5kZXggPSBpc01lbW9yeTY0ID8gImk2NCIgOiAiaTMyIjsKICBpZiAoaGFzTWF4aW11bSkgewogICAgY29uc3QgbWF4aW11bSA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICByZXR1cm4geyBtaW5pbXVtLCBzaGFyZWQsIGluZGV4LCBtYXhpbXVtIH07CiAgfSBlbHNlIHsKICAgIHJldHVybiB7IG1pbmltdW0sIHNoYXJlZCwgaW5kZXggfTsKICB9Cn0KZnVuY3Rpb24gcGFyc2VHbG9iYWxUeXBlKHBhcnNlU3RhdGUpIHsKICBjb25zdCB2YWx1ZSA9IHBhcnNlVmFsdWVUeXBlKHBhcnNlU3RhdGUpOwogIGNvbnN0IG11dGFibGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCkgPT09IDE7CiAgcmV0dXJuIHsgdmFsdWUsIG11dGFibGUgfTsKfQpmdW5jdGlvbiBwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKSB7CiAgY29uc3QgdHlwZSA9IHBhcnNlU3RhdGUucmVhZEJ5dGUoKTsKICBzd2l0Y2ggKHR5cGUpIHsKICAgIGNhc2UgMTI3OgogICAgICByZXR1cm4gImkzMiI7CiAgICBjYXNlIDEyNjoKICAgICAgcmV0dXJuICJpNjQiOwogICAgY2FzZSAxMjU6CiAgICAgIHJldHVybiAiZjMyIjsKICAgIGNhc2UgMTI0OgogICAgICByZXR1cm4gImY2NCI7CiAgICBjYXNlIDExMjoKICAgICAgcmV0dXJuICJmdW5jcmVmIjsKICAgIGNhc2UgMTExOgogICAgICByZXR1cm4gImV4dGVybnJlZiI7CiAgICBjYXNlIDEyMzoKICAgICAgcmV0dXJuICJ2MTI4IjsKICAgIGRlZmF1bHQ6CiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biB2YWx1ZSB0eXBlICR7dHlwZX1gKTsKICB9Cn0KZnVuY3Rpb24gcGFyc2VGdW5jdGlvblR5cGUocGFyc2VTdGF0ZSkgewogIGNvbnN0IGZvcm0gPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgaWYgKGZvcm0gIT09IDk2KSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGZ1bmN0aW9uIHR5cGUgZm9ybSAweDYwLCBnb3QgJHtmb3JtfWApOwogIH0KICBjb25zdCBwYXJhbWV0ZXJzID0gW107CiAgY29uc3QgcGFyYW1ldGVyQ291bnQgPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogIGZvciAobGV0IGkgPSAwOyBpIDwgcGFyYW1ldGVyQ291bnQ7IGkrKykgewogICAgcGFyYW1ldGVycy5wdXNoKHBhcnNlVmFsdWVUeXBlKHBhcnNlU3RhdGUpKTsKICB9CiAgY29uc3QgcmVzdWx0cyA9IFtdOwogIGNvbnN0IHJlc3VsdENvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICBmb3IgKGxldCBpID0gMDsgaSA8IHJlc3VsdENvdW50OyBpKyspIHsKICAgIHJlc3VsdHMucHVzaChwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKSk7CiAgfQogIHJldHVybiB7IHBhcmFtZXRlcnMsIHJlc3VsdHMgfTsKfQoKLy8gbm9kZV9tb2R1bGVzL3dhc20taW1wb3J0cy1wYXJzZXIvcG9seWZpbGwuanMKdmFyIGhhc1dhc21UeXBlUmVmbGVjdGlvblN1cHBvcnQgPSAoKCkgPT4gewogIGNvbnN0IG1vZHVsZUJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoWwogICAgMCwKICAgIDk3LAogICAgMTE1LAogICAgMTA5LAogICAgMSwKICAgIDAsCiAgICAwLAogICAgMCwKICAgIDIsCiAgICA2LAogICAgMSwKICAgIDAsCiAgICAwLAogICAgMiwKICAgIDAsCiAgICAxCiAgXSk7CiAgY29uc3QgbW9kdWxlID0gbmV3IFdlYkFzc2VtYmx5Lk1vZHVsZShtb2R1bGVCeXRlcyk7CiAgY29uc3QgaW1wb3J0cyA9IFdlYkFzc2VtYmx5Lk1vZHVsZS5pbXBvcnRzKG1vZHVsZSk7CiAgY29uc3QgbWVtb3J5SW1wb3J0ID0gaW1wb3J0c1swXTsKICByZXR1cm4gdHlwZW9mIG1lbW9yeUltcG9ydC50eXBlID09PSAib2JqZWN0IjsKfSkoKTsKZnVuY3Rpb24gcG9seWZpbGwoV2ViQXNzZW1ibHkzKSB7CiAgaWYgKGhhc1dhc21UeXBlUmVmbGVjdGlvblN1cHBvcnQpIHsKICAgIHJldHVybiBXZWJBc3NlbWJseTM7CiAgfQogIGNvbnN0IG5ld1dlYkFzc2VtYmx5ID0ge307CiAgZm9yIChjb25zdCBrZXkgaW4gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoV2ViQXNzZW1ibHkzKSkgewogICAgbmV3V2ViQXNzZW1ibHlba2V5XSA9IFdlYkFzc2VtYmx5M1trZXldOwogIH0KICBjb25zdCBwb2x5ZmlsbGVkSW1wb3J0c1N5bWJvbCA9IFN5bWJvbCgicG9seWZpbGxlZEltcG9ydHNTeW1ib2wiKTsKICBjb25zdCBhc3NpZ25JbXBvcnRzID0gKG1vZHVsZSwgc291cmNlQnl0ZXMpID0+IHsKICAgIG1vZHVsZVtwb2x5ZmlsbGVkSW1wb3J0c1N5bWJvbF0gPSBwYXJzZUltcG9ydHMoc291cmNlQnl0ZXMpOwogIH07CiAgY29uc3QgbmV3TW9kdWxlID0gbmV3V2ViQXNzZW1ibHkuTW9kdWxlID0gZnVuY3Rpb24oYnl0ZXMpIHsKICAgIGNvbnN0IG1vZHVsZSA9IG5ldyBXZWJBc3NlbWJseTMuTW9kdWxlKGJ5dGVzKTsKICAgIGFzc2lnbkltcG9ydHMobW9kdWxlLCBieXRlcyk7CiAgICBPYmplY3Quc2V0UHJvdG90eXBlT2YobW9kdWxlLCBuZXdNb2R1bGUucHJvdG90eXBlKTsKICAgIHJldHVybiBtb2R1bGU7CiAgfTsKICBPYmplY3Quc2V0UHJvdG90eXBlT2YobmV3TW9kdWxlLnByb3RvdHlwZSwgV2ViQXNzZW1ibHkzLk1vZHVsZS5wcm90b3R5cGUpOwogIG5ld1dlYkFzc2VtYmx5LmNvbXBpbGUgPSBhc3luYyAoc291cmNlKSA9PiB7CiAgICBjb25zdCBtb2R1bGUgPSBhd2FpdCBXZWJBc3NlbWJseTMuY29tcGlsZShzb3VyY2UpOwogICAgYXNzaWduSW1wb3J0cyhtb2R1bGUsIHNvdXJjZSk7CiAgICByZXR1cm4gbW9kdWxlOwogIH07CiAgaWYgKFdlYkFzc2VtYmx5My5jb21waWxlU3RyZWFtaW5nKSB7CiAgICBuZXdXZWJBc3NlbWJseS5jb21waWxlU3RyZWFtaW5nID0gYXN5bmMgKHNvdXJjZSkgPT4gewogICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHNvdXJjZTsKICAgICAgY29uc3QgY2xvbmUgPSByZXNwb25zZS5jbG9uZSgpOwogICAgICBjb25zdCBtb2R1bGUgPSBhd2FpdCBXZWJBc3NlbWJseTMuY29tcGlsZVN0cmVhbWluZyhyZXNwb25zZSk7CiAgICAgIGFzc2lnbkltcG9ydHMobW9kdWxlLCBuZXcgVWludDhBcnJheShhd2FpdCBjbG9uZS5hcnJheUJ1ZmZlcigpKSk7CiAgICAgIHJldHVybiBtb2R1bGU7CiAgICB9OwogIH0KICBuZXdNb2R1bGUuaW1wb3J0cyA9IChtb2R1bGUpID0+IHsKICAgIGNvbnN0IHBhcnNlZEltcG9ydHMgPSBtb2R1bGVbcG9seWZpbGxlZEltcG9ydHNTeW1ib2xdOwogICAgaWYgKCFwYXJzZWRJbXBvcnRzKSB7CiAgICAgIHJldHVybiBXZWJBc3NlbWJseTMuTW9kdWxlLmltcG9ydHMobW9kdWxlKTsKICAgIH0KICAgIHJldHVybiBwYXJzZWRJbXBvcnRzOwogIH07CiAgcmV0dXJuIG5ld1dlYkFzc2VtYmx5Owp9CgovLyBlbnRyeXBvaW50L2ludHJpbnNpY3MudHMKdmFyIFdlYkFzc2VtYmx5MiA9IHBvbHlmaWxsKGdsb2JhbFRoaXMuV2ViQXNzZW1ibHkpOwp2YXIgTGluZURlY29kZXIgPSBjbGFzcyB7CiAgY29uc3RydWN0b3Iob25MaW5lKSB7CiAgICB0aGlzLmRlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IiwgeyBmYXRhbDogZmFsc2UgfSk7CiAgICB0aGlzLmJ1ZmZlciA9ICIiOwogICAgdGhpcy5vbkxpbmUgPSBvbkxpbmU7CiAgfQogIGRlY29kZXI7CiAgYnVmZmVyOwogIG9uTGluZTsKICBzZW5kKGNodW5rKSB7CiAgICB0aGlzLmJ1ZmZlciArPSB0aGlzLmRlY29kZXIuZGVjb2RlKGNodW5rLCB7IHN0cmVhbTogdHJ1ZSB9KTsKICAgIGNvbnN0IGxpbmVzID0gdGhpcy5idWZmZXIuc3BsaXQoIlxuIik7CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aCAtIDE7IGkrKykgewogICAgICB0aGlzLm9uTGluZShsaW5lc1tpXSk7CiAgICB9CiAgICB0aGlzLmJ1ZmZlciA9IGxpbmVzW2xpbmVzLmxlbmd0aCAtIDFdOwogIH0KfTsKYXN5bmMgZnVuY3Rpb24gaW5zdGFudGlhdGUocmF3T3B0aW9ucywgZXh0cmFXYXNtSW1wb3J0cykgewogIGNvbnN0IG9wdGlvbnMgPSBkZWZhdWx0SW5zdGFudGlhdGlvbk9wdGlvbnMocmF3T3B0aW9ucyk7CiAgbGV0IHN3aWZ0ID0gb3B0aW9ucy5zd2lmdDsKICBpZiAoIXN3aWZ0ICYmIG9wdGlvbnMuU3dpZnRSdW50aW1lKSB7CiAgICBsZXQgc2hhcmVkTWVtb3J5ID0gZmFsc2U7CiAgICBmb3IgKGNvbnN0IGltcG9ydEVudHJ5IG9mIFdlYkFzc2VtYmx5Mi5Nb2R1bGUuaW1wb3J0cyhvcHRpb25zLm1vZHVsZSkpIHsKICAgICAgaWYgKGltcG9ydEVudHJ5Lm1vZHVsZSA9PT0gImVudiIgJiYgaW1wb3J0RW50cnkubmFtZSA9PT0gIm1lbW9yeSIgJiYgaW1wb3J0RW50cnkua2luZCA9PT0gIm1lbW9yeSIpIHsKICAgICAgICBzaGFyZWRNZW1vcnkgPSB0cnVlOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgICBzd2lmdCA9IG5ldyBvcHRpb25zLlN3aWZ0UnVudGltZSh7IHNoYXJlZE1lbW9yeSB9KTsKICB9CiAgbGV0IHN0ZG91dExpbmUgPSB2b2lkIDA7CiAgaWYgKG9wdGlvbnMub25TdGRvdXRMaW5lICE9IG51bGwpIHsKICAgIHN0ZG91dExpbmUgPSBuZXcgTGluZURlY29kZXIob3B0aW9ucy5vblN0ZG91dExpbmUpOwogIH0KICBjb25zdCBzdGRvdXQgPSBuZXcgQ29uc29sZVN0ZG91dCgoY2h1bmspID0+IHsKICAgIG9wdGlvbnMub25TdGRvdXQ/LmNhbGwodm9pZCAwLCBjaHVuayk7CiAgICBzdGRvdXRMaW5lPy5zZW5kKGNodW5rKTsKICB9KTsKICBsZXQgc3RkZXJyTGluZSA9IHZvaWQgMDsKICBpZiAob3B0aW9ucy5vblN0ZGVyckxpbmUgIT0gbnVsbCkgewogICAgc3RkZXJyTGluZSA9IG5ldyBMaW5lRGVjb2RlcihvcHRpb25zLm9uU3RkZXJyTGluZSk7CiAgfQogIGNvbnN0IHN0ZGVyciA9IG5ldyBDb25zb2xlU3Rkb3V0KChjaHVuaykgPT4gewogICAgb3B0aW9ucy5vblN0ZGVycj8uY2FsbCh2b2lkIDAsIGNodW5rKTsKICAgIHN0ZGVyckxpbmU/LnNlbmQoY2h1bmspOwogIH0pOwogIGNvbnN0IGFyZ3MgPSBvcHRpb25zLmFyZ3MgfHwgW107CiAgY29uc3Qgcm9vdEZzID0gb3B0aW9ucy5yb290RnMgfHwgLyogQF9fUFVSRV9fICovIG5ldyBNYXAoKTsKICBjb25zdCBmZHMgPSBbCiAgICBuZXcgT3BlbkZpbGUobmV3IEZpbGUoW10pKSwKICAgIHN0ZG91dCwKICAgIHN0ZGVyciwKICAgIG5ldyBQcmVvcGVuRGlyZWN0b3J5KCIvIiwgcm9vdEZzKQogIF07CiAgY29uc3QgZW52cyA9IG9wdGlvbnMuZW52ID8gT2JqZWN0LmVudHJpZXMob3B0aW9ucy5lbnYpLm1hcCgoW2tleSwgdmFsdWVdKSA9PiBgJHtrZXl9PSR7dmFsdWV9YCkgOiBbXTsKICBjb25zdCB3YXNpID0gbmV3IFdBU0koYXJncywgZW52cywgZmRzLCB7CiAgICBkZWJ1ZzogZmFsc2UKICB9KTsKICBjb25zdCBjcmVhdGVXYXNtSW1wb3J0T2JqZWN0ID0gKGV4dHJhV2FzbUltcG9ydHMyLCBtb2R1bGUpID0+IHsKICAgIGNvbnN0IGltcG9ydE9iamVjdDIgPSB7CiAgICAgIHdhc2lfc25hcHNob3RfcHJldmlldzE6IHdhc2kud2FzaUltcG9ydAogICAgfTsKICAgIGlmIChzd2lmdCkgewogICAgICBpbXBvcnRPYmplY3QyLmphdmFzY3JpcHRfa2l0ID0gc3dpZnQud2FzbUltcG9ydHM7CiAgICB9CiAgICBpZiAoZXh0cmFXYXNtSW1wb3J0czIpIHsKICAgICAgZm9yIChjb25zdCBtb2R1bGVOYW1lIGluIGV4dHJhV2FzbUltcG9ydHMyKSB7CiAgICAgICAgaWYgKCFpbXBvcnRPYmplY3QyW21vZHVsZU5hbWVdKSB7CiAgICAgICAgICBpbXBvcnRPYmplY3QyW21vZHVsZU5hbWVdID0ge307CiAgICAgICAgfQogICAgICAgIGZvciAoY29uc3QgZW50cnkgaW4gZXh0cmFXYXNtSW1wb3J0czJbbW9kdWxlTmFtZV0pIHsKICAgICAgICAgIGltcG9ydE9iamVjdDJbbW9kdWxlTmFtZV1bZW50cnldID0gZXh0cmFXYXNtSW1wb3J0czJbbW9kdWxlTmFtZV1bZW50cnldOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgZm9yIChjb25zdCBfaW1wb3J0RW50cnkgb2YgV2ViQXNzZW1ibHkyLk1vZHVsZS5pbXBvcnRzKG1vZHVsZSkpIHsKICAgICAgY29uc3QgaW1wb3J0RW50cnkgPSBfaW1wb3J0RW50cnk7CiAgICAgIGlmICghaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdKSB7CiAgICAgICAgaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdID0ge307CiAgICAgIH0KICAgICAgaWYgKGltcG9ydE9iamVjdDJbaW1wb3J0RW50cnkubW9kdWxlXVtpbXBvcnRFbnRyeS5uYW1lXSkgewogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGlmIChpbXBvcnRFbnRyeS5raW5kID09ICJmdW5jdGlvbiIpIHsKICAgICAgICBpbXBvcnRPYmplY3QyW2ltcG9ydEVudHJ5Lm1vZHVsZV1baW1wb3J0RW50cnkubmFtZV0gPSAoKSA9PiB7CiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEltcG9ydGVkIGZ1bmN0aW9uICR7aW1wb3J0RW50cnkubW9kdWxlfS4ke2ltcG9ydEVudHJ5Lm5hbWV9IG5vdCBpbXBsZW1lbnRlZGApOwogICAgICAgIH07CiAgICAgIH0gZWxzZSBpZiAoaW1wb3J0RW50cnkua2luZCA9PSAibWVtb3J5IiAmJiBpbXBvcnRFbnRyeS5tb2R1bGUgPT0gImVudiIgJiYgaW1wb3J0RW50cnkubmFtZSA9PSAibWVtb3J5IikgewogICAgICAgIGNvbnN0IHR5cGUgPSBpbXBvcnRFbnRyeS50eXBlOwogICAgICAgIGNvbnN0IGRlc2NyaXB0b3IgPSB7CiAgICAgICAgICBpbml0aWFsOiB0eXBlLm1pbmltdW0sCiAgICAgICAgICBtYXhpbXVtOiB0eXBlLm1heGltdW0sCiAgICAgICAgICBzaGFyZWQ6IHR5cGUuc2hhcmVkCiAgICAgICAgfTsKICAgICAgICBpbXBvcnRPYmplY3QyW2ltcG9ydEVudHJ5Lm1vZHVsZV1baW1wb3J0RW50cnkubmFtZV0gPSBuZXcgV2ViQXNzZW1ibHkyLk1lbW9yeShkZXNjcmlwdG9yKTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIGltcG9ydE9iamVjdDI7CiAgfTsKICBjb25zdCBpbXBvcnRPYmplY3QgPSBjcmVhdGVXYXNtSW1wb3J0T2JqZWN0KGV4dHJhV2FzbUltcG9ydHMsIG9wdGlvbnMubW9kdWxlKTsKICBjb25zdCBpbnN0YW5jZSA9IGF3YWl0IFdlYkFzc2VtYmx5Mi5pbnN0YW50aWF0ZShvcHRpb25zLm1vZHVsZSwgaW1wb3J0T2JqZWN0KTsKICBpZiAoc3dpZnQgJiYgaW5zdGFuY2UuZXhwb3J0cy5zd2pzX2xpYnJhcnlfdmVyc2lvbikgewogICAgc3dpZnQuc2V0SW5zdGFuY2UoaW5zdGFuY2UpOwogIH0KICBpZiAodHlwZW9mIGluc3RhbmNlLmV4cG9ydHMuX3N0YXJ0ID09PSAiZnVuY3Rpb24iKSB7CiAgICB3YXNpLnN0YXJ0KGluc3RhbmNlKTsKICB9IGVsc2UgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLl9pbml0aWFsaXplID09ICJmdW5jdGlvbiIpIHsKICAgIHdhc2kuaW5pdGlhbGl6ZShpbnN0YW5jZSk7CiAgICBpZiAoc3dpZnQgJiYgc3dpZnQubWFpbikgewogICAgICBzd2lmdC5tYWluKCk7CiAgICB9IGVsc2UgewogICAgICBpZiAodHlwZW9mIGluc3RhbmNlLmV4cG9ydHMubWFpbiA9PT0gImZ1bmN0aW9uIikgewogICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWFpbigpOwogICAgICB9IGVsc2UgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLl9fbWFpbl9hcmdjX2FyZ3YgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICBpbnN0YW5jZS5leHBvcnRzLl9fbWFpbl9hcmdjX2FyZ3YoMCwgMCk7CiAgICAgIH0KICAgIH0KICB9CiAgcmV0dXJuIHsgaW5zdGFuY2UsIHJvb3RGcyB9Owp9CmZ1bmN0aW9uIGRlZmF1bHRJbnN0YW50aWF0aW9uT3B0aW9ucyhvcHRpb25zKSB7CiAgaWYgKG9wdGlvbnMuYXJncyA9PSBudWxsKSB7CiAgICBvcHRpb25zLmFyZ3MgPSBbIm1haW4ud2FzbSJdOwogIH0KICBjb25zdCBpc05vZGVKcyA9IHR5cGVvZiBwcm9jZXNzICE9PSAidW5kZWZpbmVkIiAmJiBwcm9jZXNzLnJlbGVhc2UubmFtZSA9PT0gIm5vZGUiOwogIGNvbnN0IGlzV2ViQnJvd3NlciA9IHR5cGVvZiB3aW5kb3cgIT09ICJ1bmRlZmluZWQiOwogIGlmIChpc05vZGVKcykgewogICAgaWYgKCFvcHRpb25zLm9uU3Rkb3V0KSB7CiAgICAgIG9wdGlvbnMub25TdGRvdXQgPSAoY2h1bmspID0+IHByb2Nlc3Muc3Rkb3V0LndyaXRlKGNodW5rKTsKICAgIH0KICAgIGlmICghb3B0aW9ucy5vblN0ZGVycikgewogICAgICBvcHRpb25zLm9uU3RkZXJyID0gKGNodW5rKSA9PiBwcm9jZXNzLnN0ZGVyci53cml0ZShjaHVuayk7CiAgICB9CiAgfSBlbHNlIGlmIChpc1dlYkJyb3dzZXIpIHsKICAgIGlmICghb3B0aW9ucy5vblN0ZG91dExpbmUpIHsKICAgICAgb3B0aW9ucy5vblN0ZG91dExpbmUgPSAobGluZSkgPT4gY29uc29sZS5sb2cobGluZSk7CiAgICB9CiAgICBpZiAoIW9wdGlvbnMub25TdGRlcnJMaW5lKSB7CiAgICAgIG9wdGlvbnMub25TdGRlcnJMaW5lID0gKGxpbmUpID0+IGNvbnNvbGUud2FybihsaW5lKTsKICAgIH0KICB9CiAgcmV0dXJuIG9wdGlvbnM7Cn0KCi8vIGVudHJ5cG9pbnQvYnVuZGxlLnRzCnZhciBzdGFydFdhc2lUYXNrID0gYXN5bmMgKCkgPT4gewogIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goIlJFUExBQ0VfVEhJU19XSVRIX1RIRV9NQUlOX1dFQkFTU0VNQkxZX01PRFVMRSIpOwogIGxldCBydW50aW1lQ29uc3RydWN0b3IgPSB2b2lkIDA7CiAgdHJ5IHsKICAgIGNvbnN0IHsgU3dpZnRSdW50aW1lIH0gPSBhd2FpdCBpbXBvcnQoCiAgICAgIC8vIEB0cy1pZ25vcmUKICAgICAgIi4vSmF2YVNjcmlwdEtpdF9KYXZhU2NyaXB0S2l0LnJlc291cmNlcy9SdW50aW1lL2luZGV4Lm1qcyIKICAgICk7CiAgICBydW50aW1lQ29uc3RydWN0b3IgPSBTd2lmdFJ1bnRpbWU7CiAgfSBjYXRjaCB7CiAgfQogIGF3YWl0IGluc3RhbnRpYXRlKHsKICAgIG1vZHVsZTogYXdhaXQgV2ViQXNzZW1ibHkyLmNvbXBpbGVTdHJlYW1pbmcocmVzcG9uc2UpLAogICAgb25TdGRvdXRMaW5lKGxpbmUpIHsKICAgICAgY29uc29sZS5sb2cobGluZSk7CiAgICB9LAogICAgb25TdGRlcnJMaW5lKGxpbmUpIHsKICAgICAgY29uc29sZS5lcnJvcihsaW5lKTsKICAgIH0sCiAgICBTd2lmdFJ1bnRpbWU6IHJ1bnRpbWVDb25zdHJ1Y3RvcgogIH0pOwp9Owphc3luYyBmdW5jdGlvbiBtYWluKCkgewogIGF3YWl0IHN0YXJ0V2FzaVRhc2soKTsKfQptYWluKCk7Cg==")! + public static let dev: Data = Data(base64Encoded: "Ly8gbm9kZV9tb2R1bGVzL3JlY29ubmVjdGluZy13ZWJzb2NrZXQvZGlzdC9yZWNvbm5lY3Rpbmctd2Vic29ja2V0LW1qcy5qcwp2YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHsKICBleHRlbmRTdGF0aWNzID0gT2JqZWN0LnNldFByb3RvdHlwZU9mIHx8IHsgX19wcm90b19fOiBbXSB9IGluc3RhbmNlb2YgQXJyYXkgJiYgZnVuY3Rpb24oZDIsIGIyKSB7CiAgICBkMi5fX3Byb3RvX18gPSBiMjsKICB9IHx8IGZ1bmN0aW9uKGQyLCBiMikgewogICAgZm9yICh2YXIgcCBpbiBiMikKICAgICAgaWYgKGIyLmhhc093blByb3BlcnR5KHApKQogICAgICAgIGQyW3BdID0gYjJbcF07CiAgfTsKICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTsKfTsKZnVuY3Rpb24gX19leHRlbmRzKGQsIGIpIHsKICBleHRlbmRTdGF0aWNzKGQsIGIpOwogIGZ1bmN0aW9uIF9fKCkgewogICAgdGhpcy5jb25zdHJ1Y3RvciA9IGQ7CiAgfQogIGQucHJvdG90eXBlID0gYiA9PT0gbnVsbCA/IE9iamVjdC5jcmVhdGUoYikgOiAoX18ucHJvdG90eXBlID0gYi5wcm90b3R5cGUsIG5ldyBfXygpKTsKfQpmdW5jdGlvbiBfX3ZhbHVlcyhvKSB7CiAgdmFyIG0gPSB0eXBlb2YgU3ltYm9sID09PSAiZnVuY3Rpb24iICYmIG9bU3ltYm9sLml0ZXJhdG9yXSwgaSA9IDA7CiAgaWYgKG0pCiAgICByZXR1cm4gbS5jYWxsKG8pOwogIHJldHVybiB7CiAgICBuZXh0OiBmdW5jdGlvbigpIHsKICAgICAgaWYgKG8gJiYgaSA+PSBvLmxlbmd0aCkKICAgICAgICBvID0gdm9pZCAwOwogICAgICByZXR1cm4geyB2YWx1ZTogbyAmJiBvW2krK10sIGRvbmU6ICFvIH07CiAgICB9CiAgfTsKfQpmdW5jdGlvbiBfX3JlYWQobywgbikgewogIHZhciBtID0gdHlwZW9mIFN5bWJvbCA9PT0gImZ1bmN0aW9uIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl07CiAgaWYgKCFtKQogICAgcmV0dXJuIG87CiAgdmFyIGkgPSBtLmNhbGwobyksIHIsIGFyID0gW10sIGU7CiAgdHJ5IHsKICAgIHdoaWxlICgobiA9PT0gdm9pZCAwIHx8IG4tLSA+IDApICYmICEociA9IGkubmV4dCgpKS5kb25lKQogICAgICBhci5wdXNoKHIudmFsdWUpOwogIH0gY2F0Y2ggKGVycm9yKSB7CiAgICBlID0geyBlcnJvciB9OwogIH0gZmluYWxseSB7CiAgICB0cnkgewogICAgICBpZiAociAmJiAhci5kb25lICYmIChtID0gaVsicmV0dXJuIl0pKQogICAgICAgIG0uY2FsbChpKTsKICAgIH0gZmluYWxseSB7CiAgICAgIGlmIChlKQogICAgICAgIHRocm93IGUuZXJyb3I7CiAgICB9CiAgfQogIHJldHVybiBhcjsKfQpmdW5jdGlvbiBfX3NwcmVhZCgpIHsKICBmb3IgKHZhciBhciA9IFtdLCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykKICAgIGFyID0gYXIuY29uY2F0KF9fcmVhZChhcmd1bWVudHNbaV0pKTsKICByZXR1cm4gYXI7Cn0KdmFyIEV2ZW50ID0gZnVuY3Rpb24oKSB7CiAgZnVuY3Rpb24gRXZlbnQyKHR5cGUsIHRhcmdldCkgewogICAgdGhpcy50YXJnZXQgPSB0YXJnZXQ7CiAgICB0aGlzLnR5cGUgPSB0eXBlOwogIH0KICByZXR1cm4gRXZlbnQyOwp9KCk7CnZhciBFcnJvckV2ZW50ID0gZnVuY3Rpb24oX3N1cGVyKSB7CiAgX19leHRlbmRzKEVycm9yRXZlbnQyLCBfc3VwZXIpOwogIGZ1bmN0aW9uIEVycm9yRXZlbnQyKGVycm9yLCB0YXJnZXQpIHsKICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMsICJlcnJvciIsIHRhcmdldCkgfHwgdGhpczsKICAgIF90aGlzLm1lc3NhZ2UgPSBlcnJvci5tZXNzYWdlOwogICAgX3RoaXMuZXJyb3IgPSBlcnJvcjsKICAgIHJldHVybiBfdGhpczsKICB9CiAgcmV0dXJuIEVycm9yRXZlbnQyOwp9KEV2ZW50KTsKdmFyIENsb3NlRXZlbnQgPSBmdW5jdGlvbihfc3VwZXIpIHsKICBfX2V4dGVuZHMoQ2xvc2VFdmVudDIsIF9zdXBlcik7CiAgZnVuY3Rpb24gQ2xvc2VFdmVudDIoY29kZSwgcmVhc29uLCB0YXJnZXQpIHsKICAgIGlmIChjb2RlID09PSB2b2lkIDApIHsKICAgICAgY29kZSA9IDFlMzsKICAgIH0KICAgIGlmIChyZWFzb24gPT09IHZvaWQgMCkgewogICAgICByZWFzb24gPSAiIjsKICAgIH0KICAgIHZhciBfdGhpcyA9IF9zdXBlci5jYWxsKHRoaXMsICJjbG9zZSIsIHRhcmdldCkgfHwgdGhpczsKICAgIF90aGlzLndhc0NsZWFuID0gdHJ1ZTsKICAgIF90aGlzLmNvZGUgPSBjb2RlOwogICAgX3RoaXMucmVhc29uID0gcmVhc29uOwogICAgcmV0dXJuIF90aGlzOwogIH0KICByZXR1cm4gQ2xvc2VFdmVudDI7Cn0oRXZlbnQpOwp2YXIgZ2V0R2xvYmFsV2ViU29ja2V0ID0gZnVuY3Rpb24oKSB7CiAgaWYgKHR5cGVvZiBXZWJTb2NrZXQgIT09ICJ1bmRlZmluZWQiKSB7CiAgICByZXR1cm4gV2ViU29ja2V0OwogIH0KfTsKdmFyIGlzV2ViU29ja2V0ID0gZnVuY3Rpb24odykgewogIHJldHVybiB0eXBlb2YgdyAhPT0gInVuZGVmaW5lZCIgJiYgISF3ICYmIHcuQ0xPU0lORyA9PT0gMjsKfTsKdmFyIERFRkFVTFQgPSB7CiAgbWF4UmVjb25uZWN0aW9uRGVsYXk6IDFlNCwKICBtaW5SZWNvbm5lY3Rpb25EZWxheTogMWUzICsgTWF0aC5yYW5kb20oKSAqIDRlMywKICBtaW5VcHRpbWU6IDVlMywKICByZWNvbm5lY3Rpb25EZWxheUdyb3dGYWN0b3I6IDEuMywKICBjb25uZWN0aW9uVGltZW91dDogNGUzLAogIG1heFJldHJpZXM6IEluZmluaXR5LAogIG1heEVucXVldWVkTWVzc2FnZXM6IEluZmluaXR5LAogIHN0YXJ0Q2xvc2VkOiBmYWxzZSwKICBkZWJ1ZzogZmFsc2UKfTsKdmFyIFJlY29ubmVjdGluZ1dlYlNvY2tldCA9IGZ1bmN0aW9uKCkgewogIGZ1bmN0aW9uIFJlY29ubmVjdGluZ1dlYlNvY2tldDIodXJsLCBwcm90b2NvbHMsIG9wdGlvbnMpIHsKICAgIHZhciBfdGhpcyA9IHRoaXM7CiAgICBpZiAob3B0aW9ucyA9PT0gdm9pZCAwKSB7CiAgICAgIG9wdGlvbnMgPSB7fTsKICAgIH0KICAgIHRoaXMuX2xpc3RlbmVycyA9IHsKICAgICAgZXJyb3I6IFtdLAogICAgICBtZXNzYWdlOiBbXSwKICAgICAgb3BlbjogW10sCiAgICAgIGNsb3NlOiBbXQogICAgfTsKICAgIHRoaXMuX3JldHJ5Q291bnQgPSAtMTsKICAgIHRoaXMuX3Nob3VsZFJlY29ubmVjdCA9IHRydWU7CiAgICB0aGlzLl9jb25uZWN0TG9jayA9IGZhbHNlOwogICAgdGhpcy5fYmluYXJ5VHlwZSA9ICJibG9iIjsKICAgIHRoaXMuX2Nsb3NlQ2FsbGVkID0gZmFsc2U7CiAgICB0aGlzLl9tZXNzYWdlUXVldWUgPSBbXTsKICAgIHRoaXMub25jbG9zZSA9IG51bGw7CiAgICB0aGlzLm9uZXJyb3IgPSBudWxsOwogICAgdGhpcy5vbm1lc3NhZ2UgPSBudWxsOwogICAgdGhpcy5vbm9wZW4gPSBudWxsOwogICAgdGhpcy5faGFuZGxlT3BlbiA9IGZ1bmN0aW9uKGV2ZW50KSB7CiAgICAgIF90aGlzLl9kZWJ1Zygib3BlbiBldmVudCIpOwogICAgICB2YXIgX2EgPSBfdGhpcy5fb3B0aW9ucy5taW5VcHRpbWUsIG1pblVwdGltZSA9IF9hID09PSB2b2lkIDAgPyBERUZBVUxULm1pblVwdGltZSA6IF9hOwogICAgICBjbGVhclRpbWVvdXQoX3RoaXMuX2Nvbm5lY3RUaW1lb3V0KTsKICAgICAgX3RoaXMuX3VwdGltZVRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiBfdGhpcy5fYWNjZXB0T3BlbigpOwogICAgICB9LCBtaW5VcHRpbWUpOwogICAgICBfdGhpcy5fd3MuYmluYXJ5VHlwZSA9IF90aGlzLl9iaW5hcnlUeXBlOwogICAgICBfdGhpcy5fbWVzc2FnZVF1ZXVlLmZvckVhY2goZnVuY3Rpb24obWVzc2FnZSkgewogICAgICAgIHJldHVybiBfdGhpcy5fd3Muc2VuZChtZXNzYWdlKTsKICAgICAgfSk7CiAgICAgIF90aGlzLl9tZXNzYWdlUXVldWUgPSBbXTsKICAgICAgaWYgKF90aGlzLm9ub3BlbikgewogICAgICAgIF90aGlzLm9ub3BlbihldmVudCk7CiAgICAgIH0KICAgICAgX3RoaXMuX2xpc3RlbmVycy5vcGVuLmZvckVhY2goZnVuY3Rpb24obGlzdGVuZXIpIHsKICAgICAgICByZXR1cm4gX3RoaXMuX2NhbGxFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcik7CiAgICAgIH0pOwogICAgfTsKICAgIHRoaXMuX2hhbmRsZU1lc3NhZ2UgPSBmdW5jdGlvbihldmVudCkgewogICAgICBfdGhpcy5fZGVidWcoIm1lc3NhZ2UgZXZlbnQiKTsKICAgICAgaWYgKF90aGlzLm9ubWVzc2FnZSkgewogICAgICAgIF90aGlzLm9ubWVzc2FnZShldmVudCk7CiAgICAgIH0KICAgICAgX3RoaXMuX2xpc3RlbmVycy5tZXNzYWdlLmZvckVhY2goZnVuY3Rpb24obGlzdGVuZXIpIHsKICAgICAgICByZXR1cm4gX3RoaXMuX2NhbGxFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcik7CiAgICAgIH0pOwogICAgfTsKICAgIHRoaXMuX2hhbmRsZUVycm9yID0gZnVuY3Rpb24oZXZlbnQpIHsKICAgICAgX3RoaXMuX2RlYnVnKCJlcnJvciBldmVudCIsIGV2ZW50Lm1lc3NhZ2UpOwogICAgICBfdGhpcy5fZGlzY29ubmVjdCh2b2lkIDAsIGV2ZW50Lm1lc3NhZ2UgPT09ICJUSU1FT1VUIiA/ICJ0aW1lb3V0IiA6IHZvaWQgMCk7CiAgICAgIGlmIChfdGhpcy5vbmVycm9yKSB7CiAgICAgICAgX3RoaXMub25lcnJvcihldmVudCk7CiAgICAgIH0KICAgICAgX3RoaXMuX2RlYnVnKCJleGVjIGVycm9yIGxpc3RlbmVycyIpOwogICAgICBfdGhpcy5fbGlzdGVuZXJzLmVycm9yLmZvckVhY2goZnVuY3Rpb24obGlzdGVuZXIpIHsKICAgICAgICByZXR1cm4gX3RoaXMuX2NhbGxFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcik7CiAgICAgIH0pOwogICAgICBfdGhpcy5fY29ubmVjdCgpOwogICAgfTsKICAgIHRoaXMuX2hhbmRsZUNsb3NlID0gZnVuY3Rpb24oZXZlbnQpIHsKICAgICAgX3RoaXMuX2RlYnVnKCJjbG9zZSBldmVudCIpOwogICAgICBfdGhpcy5fY2xlYXJUaW1lb3V0cygpOwogICAgICBpZiAoX3RoaXMuX3Nob3VsZFJlY29ubmVjdCkgewogICAgICAgIF90aGlzLl9jb25uZWN0KCk7CiAgICAgIH0KICAgICAgaWYgKF90aGlzLm9uY2xvc2UpIHsKICAgICAgICBfdGhpcy5vbmNsb3NlKGV2ZW50KTsKICAgICAgfQogICAgICBfdGhpcy5fbGlzdGVuZXJzLmNsb3NlLmZvckVhY2goZnVuY3Rpb24obGlzdGVuZXIpIHsKICAgICAgICByZXR1cm4gX3RoaXMuX2NhbGxFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcik7CiAgICAgIH0pOwogICAgfTsKICAgIHRoaXMuX3VybCA9IHVybDsKICAgIHRoaXMuX3Byb3RvY29scyA9IHByb3RvY29sczsKICAgIHRoaXMuX29wdGlvbnMgPSBvcHRpb25zOwogICAgaWYgKHRoaXMuX29wdGlvbnMuc3RhcnRDbG9zZWQpIHsKICAgICAgdGhpcy5fc2hvdWxkUmVjb25uZWN0ID0gZmFsc2U7CiAgICB9CiAgICB0aGlzLl9jb25uZWN0KCk7CiAgfQogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLCAiQ09OTkVDVElORyIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiAwOwogICAgfSwKICAgIGVudW1lcmFibGU6IHRydWUsCiAgICBjb25maWd1cmFibGU6IHRydWUKICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoUmVjb25uZWN0aW5nV2ViU29ja2V0MiwgIk9QRU4iLCB7CiAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICByZXR1cm4gMTsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIsICJDTE9TSU5HIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgcmV0dXJuIDI7CiAgICB9LAogICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogIH0pOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLCAiQ0xPU0VEIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgcmV0dXJuIDM7CiAgICB9LAogICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogIH0pOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZSwgIkNPTk5FQ1RJTkciLCB7CiAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICByZXR1cm4gUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5DT05ORUNUSU5HOwogICAgfSwKICAgIGVudW1lcmFibGU6IHRydWUsCiAgICBjb25maWd1cmFibGU6IHRydWUKICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUsICJPUEVOIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgcmV0dXJuIFJlY29ubmVjdGluZ1dlYlNvY2tldDIuT1BFTjsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAiQ0xPU0lORyIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLkNMT1NJTkc7CiAgICB9LAogICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogIH0pOwogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZSwgIkNMT1NFRCIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLkNMT1NFRDsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAiYmluYXJ5VHlwZSIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiB0aGlzLl93cyA/IHRoaXMuX3dzLmJpbmFyeVR5cGUgOiB0aGlzLl9iaW5hcnlUeXBlOwogICAgfSwKICAgIHNldDogZnVuY3Rpb24odmFsdWUpIHsKICAgICAgdGhpcy5fYmluYXJ5VHlwZSA9IHZhbHVlOwogICAgICBpZiAodGhpcy5fd3MpIHsKICAgICAgICB0aGlzLl93cy5iaW5hcnlUeXBlID0gdmFsdWU7CiAgICAgIH0KICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAicmV0cnlDb3VudCIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiBNYXRoLm1heCh0aGlzLl9yZXRyeUNvdW50LCAwKTsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAiYnVmZmVyZWRBbW91bnQiLCB7CiAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICB2YXIgYnl0ZXMgPSB0aGlzLl9tZXNzYWdlUXVldWUucmVkdWNlKGZ1bmN0aW9uKGFjYywgbWVzc2FnZSkgewogICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZSA9PT0gInN0cmluZyIpIHsKICAgICAgICAgIGFjYyArPSBtZXNzYWdlLmxlbmd0aDsKICAgICAgICB9IGVsc2UgaWYgKG1lc3NhZ2UgaW5zdGFuY2VvZiBCbG9iKSB7CiAgICAgICAgICBhY2MgKz0gbWVzc2FnZS5zaXplOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBhY2MgKz0gbWVzc2FnZS5ieXRlTGVuZ3RoOwogICAgICAgIH0KICAgICAgICByZXR1cm4gYWNjOwogICAgICB9LCAwKTsKICAgICAgcmV0dXJuIGJ5dGVzICsgKHRoaXMuX3dzID8gdGhpcy5fd3MuYnVmZmVyZWRBbW91bnQgOiAwKTsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAiZXh0ZW5zaW9ucyIsIHsKICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiB0aGlzLl93cyA/IHRoaXMuX3dzLmV4dGVuc2lvbnMgOiAiIjsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAicHJvdG9jb2wiLCB7CiAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICByZXR1cm4gdGhpcy5fd3MgPyB0aGlzLl93cy5wcm90b2NvbCA6ICIiOwogICAgfSwKICAgIGVudW1lcmFibGU6IHRydWUsCiAgICBjb25maWd1cmFibGU6IHRydWUKICB9KTsKICBPYmplY3QuZGVmaW5lUHJvcGVydHkoUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUsICJyZWFkeVN0YXRlIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgaWYgKHRoaXMuX3dzKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuX3dzLnJlYWR5U3RhdGU7CiAgICAgIH0KICAgICAgcmV0dXJuIHRoaXMuX29wdGlvbnMuc3RhcnRDbG9zZWQgPyBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLkNMT1NFRCA6IFJlY29ubmVjdGluZ1dlYlNvY2tldDIuQ09OTkVDVElORzsKICAgIH0sCiAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgY29uZmlndXJhYmxlOiB0cnVlCiAgfSk7CiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLCAidXJsIiwgewogICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgcmV0dXJuIHRoaXMuX3dzID8gdGhpcy5fd3MudXJsIDogIiI7CiAgICB9LAogICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZQogIH0pOwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oY29kZSwgcmVhc29uKSB7CiAgICBpZiAoY29kZSA9PT0gdm9pZCAwKSB7CiAgICAgIGNvZGUgPSAxZTM7CiAgICB9CiAgICB0aGlzLl9jbG9zZUNhbGxlZCA9IHRydWU7CiAgICB0aGlzLl9zaG91bGRSZWNvbm5lY3QgPSBmYWxzZTsKICAgIHRoaXMuX2NsZWFyVGltZW91dHMoKTsKICAgIGlmICghdGhpcy5fd3MpIHsKICAgICAgdGhpcy5fZGVidWcoImNsb3NlIGVucXVldWVkOiBubyB3cyBpbnN0YW5jZSIpOwogICAgICByZXR1cm47CiAgICB9CiAgICBpZiAodGhpcy5fd3MucmVhZHlTdGF0ZSA9PT0gdGhpcy5DTE9TRUQpIHsKICAgICAgdGhpcy5fZGVidWcoImNsb3NlOiBhbHJlYWR5IGNsb3NlZCIpOwogICAgICByZXR1cm47CiAgICB9CiAgICB0aGlzLl93cy5jbG9zZShjb2RlLCByZWFzb24pOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUucmVjb25uZWN0ID0gZnVuY3Rpb24oY29kZSwgcmVhc29uKSB7CiAgICB0aGlzLl9zaG91bGRSZWNvbm5lY3QgPSB0cnVlOwogICAgdGhpcy5fY2xvc2VDYWxsZWQgPSBmYWxzZTsKICAgIHRoaXMuX3JldHJ5Q291bnQgPSAtMTsKICAgIGlmICghdGhpcy5fd3MgfHwgdGhpcy5fd3MucmVhZHlTdGF0ZSA9PT0gdGhpcy5DTE9TRUQpIHsKICAgICAgdGhpcy5fY29ubmVjdCgpOwogICAgfSBlbHNlIHsKICAgICAgdGhpcy5fZGlzY29ubmVjdChjb2RlLCByZWFzb24pOwogICAgICB0aGlzLl9jb25uZWN0KCk7CiAgICB9CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24oZGF0YSkgewogICAgaWYgKHRoaXMuX3dzICYmIHRoaXMuX3dzLnJlYWR5U3RhdGUgPT09IHRoaXMuT1BFTikgewogICAgICB0aGlzLl9kZWJ1Zygic2VuZCIsIGRhdGEpOwogICAgICB0aGlzLl93cy5zZW5kKGRhdGEpOwogICAgfSBlbHNlIHsKICAgICAgdmFyIF9hID0gdGhpcy5fb3B0aW9ucy5tYXhFbnF1ZXVlZE1lc3NhZ2VzLCBtYXhFbnF1ZXVlZE1lc3NhZ2VzID0gX2EgPT09IHZvaWQgMCA/IERFRkFVTFQubWF4RW5xdWV1ZWRNZXNzYWdlcyA6IF9hOwogICAgICBpZiAodGhpcy5fbWVzc2FnZVF1ZXVlLmxlbmd0aCA8IG1heEVucXVldWVkTWVzc2FnZXMpIHsKICAgICAgICB0aGlzLl9kZWJ1ZygiZW5xdWV1ZSIsIGRhdGEpOwogICAgICAgIHRoaXMuX21lc3NhZ2VRdWV1ZS5wdXNoKGRhdGEpOwogICAgICB9CiAgICB9CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5hZGRFdmVudExpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHsKICAgIGlmICh0aGlzLl9saXN0ZW5lcnNbdHlwZV0pIHsKICAgICAgdGhpcy5fbGlzdGVuZXJzW3R5cGVdLnB1c2gobGlzdGVuZXIpOwogICAgfQogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuZGlzcGF0Y2hFdmVudCA9IGZ1bmN0aW9uKGV2ZW50KSB7CiAgICB2YXIgZV8xLCBfYTsKICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnNbZXZlbnQudHlwZV07CiAgICBpZiAobGlzdGVuZXJzKSB7CiAgICAgIHRyeSB7CiAgICAgICAgZm9yICh2YXIgbGlzdGVuZXJzXzEgPSBfX3ZhbHVlcyhsaXN0ZW5lcnMpLCBsaXN0ZW5lcnNfMV8xID0gbGlzdGVuZXJzXzEubmV4dCgpOyAhbGlzdGVuZXJzXzFfMS5kb25lOyBsaXN0ZW5lcnNfMV8xID0gbGlzdGVuZXJzXzEubmV4dCgpKSB7CiAgICAgICAgICB2YXIgbGlzdGVuZXIgPSBsaXN0ZW5lcnNfMV8xLnZhbHVlOwogICAgICAgICAgdGhpcy5fY2FsbEV2ZW50TGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVyKTsKICAgICAgICB9CiAgICAgIH0gY2F0Y2ggKGVfMV8xKSB7CiAgICAgICAgZV8xID0geyBlcnJvcjogZV8xXzEgfTsKICAgICAgfSBmaW5hbGx5IHsKICAgICAgICB0cnkgewogICAgICAgICAgaWYgKGxpc3RlbmVyc18xXzEgJiYgIWxpc3RlbmVyc18xXzEuZG9uZSAmJiAoX2EgPSBsaXN0ZW5lcnNfMS5yZXR1cm4pKQogICAgICAgICAgICBfYS5jYWxsKGxpc3RlbmVyc18xKTsKICAgICAgICB9IGZpbmFsbHkgewogICAgICAgICAgaWYgKGVfMSkKICAgICAgICAgICAgdGhyb3cgZV8xLmVycm9yOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5yZW1vdmVFdmVudExpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHsKICAgIGlmICh0aGlzLl9saXN0ZW5lcnNbdHlwZV0pIHsKICAgICAgdGhpcy5fbGlzdGVuZXJzW3R5cGVdID0gdGhpcy5fbGlzdGVuZXJzW3R5cGVdLmZpbHRlcihmdW5jdGlvbihsKSB7CiAgICAgICAgcmV0dXJuIGwgIT09IGxpc3RlbmVyOwogICAgICB9KTsKICAgIH0KICB9OwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLl9kZWJ1ZyA9IGZ1bmN0aW9uKCkgewogICAgdmFyIGFyZ3MgPSBbXTsKICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBhcmd1bWVudHMubGVuZ3RoOyBfaSsrKSB7CiAgICAgIGFyZ3NbX2ldID0gYXJndW1lbnRzW19pXTsKICAgIH0KICAgIGlmICh0aGlzLl9vcHRpb25zLmRlYnVnKSB7CiAgICAgIGNvbnNvbGUubG9nLmFwcGx5KGNvbnNvbGUsIF9fc3ByZWFkKFsiUldTPiJdLCBhcmdzKSk7CiAgICB9CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5fZ2V0TmV4dERlbGF5ID0gZnVuY3Rpb24oKSB7CiAgICB2YXIgX2EgPSB0aGlzLl9vcHRpb25zLCBfYiA9IF9hLnJlY29ubmVjdGlvbkRlbGF5R3Jvd0ZhY3RvciwgcmVjb25uZWN0aW9uRGVsYXlHcm93RmFjdG9yID0gX2IgPT09IHZvaWQgMCA/IERFRkFVTFQucmVjb25uZWN0aW9uRGVsYXlHcm93RmFjdG9yIDogX2IsIF9jID0gX2EubWluUmVjb25uZWN0aW9uRGVsYXksIG1pblJlY29ubmVjdGlvbkRlbGF5ID0gX2MgPT09IHZvaWQgMCA/IERFRkFVTFQubWluUmVjb25uZWN0aW9uRGVsYXkgOiBfYywgX2QgPSBfYS5tYXhSZWNvbm5lY3Rpb25EZWxheSwgbWF4UmVjb25uZWN0aW9uRGVsYXkgPSBfZCA9PT0gdm9pZCAwID8gREVGQVVMVC5tYXhSZWNvbm5lY3Rpb25EZWxheSA6IF9kOwogICAgdmFyIGRlbGF5ID0gMDsKICAgIGlmICh0aGlzLl9yZXRyeUNvdW50ID4gMCkgewogICAgICBkZWxheSA9IG1pblJlY29ubmVjdGlvbkRlbGF5ICogTWF0aC5wb3cocmVjb25uZWN0aW9uRGVsYXlHcm93RmFjdG9yLCB0aGlzLl9yZXRyeUNvdW50IC0gMSk7CiAgICAgIGlmIChkZWxheSA+IG1heFJlY29ubmVjdGlvbkRlbGF5KSB7CiAgICAgICAgZGVsYXkgPSBtYXhSZWNvbm5lY3Rpb25EZWxheTsKICAgICAgfQogICAgfQogICAgdGhpcy5fZGVidWcoIm5leHQgZGVsYXkiLCBkZWxheSk7CiAgICByZXR1cm4gZGVsYXk7CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5fd2FpdCA9IGZ1bmN0aW9uKCkgewogICAgdmFyIF90aGlzID0gdGhpczsKICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlKSB7CiAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgX3RoaXMuX2dldE5leHREZWxheSgpKTsKICAgIH0pOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX2dldE5leHRVcmwgPSBmdW5jdGlvbih1cmxQcm92aWRlcikgewogICAgaWYgKHR5cGVvZiB1cmxQcm92aWRlciA9PT0gInN0cmluZyIpIHsKICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh1cmxQcm92aWRlcik7CiAgICB9CiAgICBpZiAodHlwZW9mIHVybFByb3ZpZGVyID09PSAiZnVuY3Rpb24iKSB7CiAgICAgIHZhciB1cmwgPSB1cmxQcm92aWRlcigpOwogICAgICBpZiAodHlwZW9mIHVybCA9PT0gInN0cmluZyIpIHsKICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHVybCk7CiAgICAgIH0KICAgICAgaWYgKCEhdXJsLnRoZW4pIHsKICAgICAgICByZXR1cm4gdXJsOwogICAgICB9CiAgICB9CiAgICB0aHJvdyBFcnJvcigiSW52YWxpZCBVUkwiKTsKICB9OwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLl9jb25uZWN0ID0gZnVuY3Rpb24oKSB7CiAgICB2YXIgX3RoaXMgPSB0aGlzOwogICAgaWYgKHRoaXMuX2Nvbm5lY3RMb2NrIHx8ICF0aGlzLl9zaG91bGRSZWNvbm5lY3QpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgdGhpcy5fY29ubmVjdExvY2sgPSB0cnVlOwogICAgdmFyIF9hID0gdGhpcy5fb3B0aW9ucywgX2IgPSBfYS5tYXhSZXRyaWVzLCBtYXhSZXRyaWVzID0gX2IgPT09IHZvaWQgMCA/IERFRkFVTFQubWF4UmV0cmllcyA6IF9iLCBfYyA9IF9hLmNvbm5lY3Rpb25UaW1lb3V0LCBjb25uZWN0aW9uVGltZW91dCA9IF9jID09PSB2b2lkIDAgPyBERUZBVUxULmNvbm5lY3Rpb25UaW1lb3V0IDogX2MsIF9kID0gX2EuV2ViU29ja2V0LCBXZWJTb2NrZXQyID0gX2QgPT09IHZvaWQgMCA/IGdldEdsb2JhbFdlYlNvY2tldCgpIDogX2Q7CiAgICBpZiAodGhpcy5fcmV0cnlDb3VudCA+PSBtYXhSZXRyaWVzKSB7CiAgICAgIHRoaXMuX2RlYnVnKCJtYXggcmV0cmllcyByZWFjaGVkIiwgdGhpcy5fcmV0cnlDb3VudCwgIj49IiwgbWF4UmV0cmllcyk7CiAgICAgIHJldHVybjsKICAgIH0KICAgIHRoaXMuX3JldHJ5Q291bnQrKzsKICAgIHRoaXMuX2RlYnVnKCJjb25uZWN0IiwgdGhpcy5fcmV0cnlDb3VudCk7CiAgICB0aGlzLl9yZW1vdmVMaXN0ZW5lcnMoKTsKICAgIGlmICghaXNXZWJTb2NrZXQoV2ViU29ja2V0MikpIHsKICAgICAgdGhyb3cgRXJyb3IoIk5vIHZhbGlkIFdlYlNvY2tldCBjbGFzcyBwcm92aWRlZCIpOwogICAgfQogICAgdGhpcy5fd2FpdCgpLnRoZW4oZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiBfdGhpcy5fZ2V0TmV4dFVybChfdGhpcy5fdXJsKTsKICAgIH0pLnRoZW4oZnVuY3Rpb24odXJsKSB7CiAgICAgIGlmIChfdGhpcy5fY2xvc2VDYWxsZWQpIHsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgX3RoaXMuX2RlYnVnKCJjb25uZWN0IiwgeyB1cmwsIHByb3RvY29sczogX3RoaXMuX3Byb3RvY29scyB9KTsKICAgICAgX3RoaXMuX3dzID0gX3RoaXMuX3Byb3RvY29scyA/IG5ldyBXZWJTb2NrZXQyKHVybCwgX3RoaXMuX3Byb3RvY29scykgOiBuZXcgV2ViU29ja2V0Mih1cmwpOwogICAgICBfdGhpcy5fd3MuYmluYXJ5VHlwZSA9IF90aGlzLl9iaW5hcnlUeXBlOwogICAgICBfdGhpcy5fY29ubmVjdExvY2sgPSBmYWxzZTsKICAgICAgX3RoaXMuX2FkZExpc3RlbmVycygpOwogICAgICBfdGhpcy5fY29ubmVjdFRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiBfdGhpcy5faGFuZGxlVGltZW91dCgpOwogICAgICB9LCBjb25uZWN0aW9uVGltZW91dCk7CiAgICB9KTsKICB9OwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLl9oYW5kbGVUaW1lb3V0ID0gZnVuY3Rpb24oKSB7CiAgICB0aGlzLl9kZWJ1ZygidGltZW91dCBldmVudCIpOwogICAgdGhpcy5faGFuZGxlRXJyb3IobmV3IEVycm9yRXZlbnQoRXJyb3IoIlRJTUVPVVQiKSwgdGhpcykpOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX2Rpc2Nvbm5lY3QgPSBmdW5jdGlvbihjb2RlLCByZWFzb24pIHsKICAgIGlmIChjb2RlID09PSB2b2lkIDApIHsKICAgICAgY29kZSA9IDFlMzsKICAgIH0KICAgIHRoaXMuX2NsZWFyVGltZW91dHMoKTsKICAgIGlmICghdGhpcy5fd3MpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgdGhpcy5fcmVtb3ZlTGlzdGVuZXJzKCk7CiAgICB0cnkgewogICAgICB0aGlzLl93cy5jbG9zZShjb2RlLCByZWFzb24pOwogICAgICB0aGlzLl9oYW5kbGVDbG9zZShuZXcgQ2xvc2VFdmVudChjb2RlLCByZWFzb24sIHRoaXMpKTsKICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICB9CiAgfTsKICBSZWNvbm5lY3RpbmdXZWJTb2NrZXQyLnByb3RvdHlwZS5fYWNjZXB0T3BlbiA9IGZ1bmN0aW9uKCkgewogICAgdGhpcy5fZGVidWcoImFjY2VwdCBvcGVuIik7CiAgICB0aGlzLl9yZXRyeUNvdW50ID0gMDsKICB9OwogIFJlY29ubmVjdGluZ1dlYlNvY2tldDIucHJvdG90eXBlLl9jYWxsRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKGV2ZW50LCBsaXN0ZW5lcikgewogICAgaWYgKCJoYW5kbGVFdmVudCIgaW4gbGlzdGVuZXIpIHsKICAgICAgbGlzdGVuZXIuaGFuZGxlRXZlbnQoZXZlbnQpOwogICAgfSBlbHNlIHsKICAgICAgbGlzdGVuZXIoZXZlbnQpOwogICAgfQogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX3JlbW92ZUxpc3RlbmVycyA9IGZ1bmN0aW9uKCkgewogICAgaWYgKCF0aGlzLl93cykgewogICAgICByZXR1cm47CiAgICB9CiAgICB0aGlzLl9kZWJ1ZygicmVtb3ZlTGlzdGVuZXJzIik7CiAgICB0aGlzLl93cy5yZW1vdmVFdmVudExpc3RlbmVyKCJvcGVuIiwgdGhpcy5faGFuZGxlT3Blbik7CiAgICB0aGlzLl93cy5yZW1vdmVFdmVudExpc3RlbmVyKCJjbG9zZSIsIHRoaXMuX2hhbmRsZUNsb3NlKTsKICAgIHRoaXMuX3dzLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLCB0aGlzLl9oYW5kbGVNZXNzYWdlKTsKICAgIHRoaXMuX3dzLnJlbW92ZUV2ZW50TGlzdGVuZXIoImVycm9yIiwgdGhpcy5faGFuZGxlRXJyb3IpOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX2FkZExpc3RlbmVycyA9IGZ1bmN0aW9uKCkgewogICAgaWYgKCF0aGlzLl93cykgewogICAgICByZXR1cm47CiAgICB9CiAgICB0aGlzLl9kZWJ1ZygiYWRkTGlzdGVuZXJzIik7CiAgICB0aGlzLl93cy5hZGRFdmVudExpc3RlbmVyKCJvcGVuIiwgdGhpcy5faGFuZGxlT3Blbik7CiAgICB0aGlzLl93cy5hZGRFdmVudExpc3RlbmVyKCJjbG9zZSIsIHRoaXMuX2hhbmRsZUNsb3NlKTsKICAgIHRoaXMuX3dzLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLCB0aGlzLl9oYW5kbGVNZXNzYWdlKTsKICAgIHRoaXMuX3dzLmFkZEV2ZW50TGlzdGVuZXIoImVycm9yIiwgdGhpcy5faGFuZGxlRXJyb3IpOwogIH07CiAgUmVjb25uZWN0aW5nV2ViU29ja2V0Mi5wcm90b3R5cGUuX2NsZWFyVGltZW91dHMgPSBmdW5jdGlvbigpIHsKICAgIGNsZWFyVGltZW91dCh0aGlzLl9jb25uZWN0VGltZW91dCk7CiAgICBjbGVhclRpbWVvdXQodGhpcy5fdXB0aW1lVGltZW91dCk7CiAgfTsKICByZXR1cm4gUmVjb25uZWN0aW5nV2ViU29ja2V0MjsKfSgpOwp2YXIgcmVjb25uZWN0aW5nX3dlYnNvY2tldF9tanNfZGVmYXVsdCA9IFJlY29ubmVjdGluZ1dlYlNvY2tldDsKCi8vIG5vZGVfbW9kdWxlcy9AYmpvcm4zL2Jyb3dzZXJfd2FzaV9zaGltL2Rpc3Qvd2FzaV9kZWZzLmpzCnZhciBDTE9DS0lEX1JFQUxUSU1FID0gMDsKdmFyIENMT0NLSURfTU9OT1RPTklDID0gMTsKdmFyIEVSUk5PX1NVQ0NFU1MgPSAwOwp2YXIgRVJSTk9fQkFERiA9IDg7CnZhciBFUlJOT19FWElTVCA9IDIwOwp2YXIgRVJSTk9fSU5WQUwgPSAyODsKdmFyIEVSUk5PX0lTRElSID0gMzE7CnZhciBFUlJOT19OQU1FVE9PTE9ORyA9IDM3Owp2YXIgRVJSTk9fTk9FTlQgPSA0NDsKdmFyIEVSUk5PX05PU1lTID0gNTI7CnZhciBFUlJOT19OT1RESVIgPSA1NDsKdmFyIEVSUk5PX05PVEVNUFRZID0gNTU7CnZhciBFUlJOT19OT1RTVVAgPSA1ODsKdmFyIEVSUk5PX1BFUk0gPSA2MzsKdmFyIEVSUk5PX05PVENBUEFCTEUgPSA3NjsKdmFyIFJJR0hUU19GRF9EQVRBU1lOQyA9IDEgPDwgMDsKdmFyIFJJR0hUU19GRF9SRUFEID0gMSA8PCAxOwp2YXIgUklHSFRTX0ZEX1NFRUsgPSAxIDw8IDI7CnZhciBSSUdIVFNfRkRfRkRTVEFUX1NFVF9GTEFHUyA9IDEgPDwgMzsKdmFyIFJJR0hUU19GRF9TWU5DID0gMSA8PCA0Owp2YXIgUklHSFRTX0ZEX1RFTEwgPSAxIDw8IDU7CnZhciBSSUdIVFNfRkRfV1JJVEUgPSAxIDw8IDY7CnZhciBSSUdIVFNfRkRfQURWSVNFID0gMSA8PCA3Owp2YXIgUklHSFRTX0ZEX0FMTE9DQVRFID0gMSA8PCA4Owp2YXIgUklHSFRTX1BBVEhfQ1JFQVRFX0RJUkVDVE9SWSA9IDEgPDwgOTsKdmFyIFJJR0hUU19QQVRIX0NSRUFURV9GSUxFID0gMSA8PCAxMDsKdmFyIFJJR0hUU19QQVRIX0xJTktfU09VUkNFID0gMSA8PCAxMTsKdmFyIFJJR0hUU19QQVRIX0xJTktfVEFSR0VUID0gMSA8PCAxMjsKdmFyIFJJR0hUU19QQVRIX09QRU4gPSAxIDw8IDEzOwp2YXIgUklHSFRTX0ZEX1JFQURESVIgPSAxIDw8IDE0Owp2YXIgUklHSFRTX1BBVEhfUkVBRExJTksgPSAxIDw8IDE1Owp2YXIgUklHSFRTX1BBVEhfUkVOQU1FX1NPVVJDRSA9IDEgPDwgMTY7CnZhciBSSUdIVFNfUEFUSF9SRU5BTUVfVEFSR0VUID0gMSA8PCAxNzsKdmFyIFJJR0hUU19QQVRIX0ZJTEVTVEFUX0dFVCA9IDEgPDwgMTg7CnZhciBSSUdIVFNfUEFUSF9GSUxFU1RBVF9TRVRfU0laRSA9IDEgPDwgMTk7CnZhciBSSUdIVFNfUEFUSF9GSUxFU1RBVF9TRVRfVElNRVMgPSAxIDw8IDIwOwp2YXIgUklHSFRTX0ZEX0ZJTEVTVEFUX0dFVCA9IDEgPDwgMjE7CnZhciBSSUdIVFNfRkRfRklMRVNUQVRfU0VUX1NJWkUgPSAxIDw8IDIyOwp2YXIgUklHSFRTX0ZEX0ZJTEVTVEFUX1NFVF9USU1FUyA9IDEgPDwgMjM7CnZhciBSSUdIVFNfUEFUSF9TWU1MSU5LID0gMSA8PCAyNDsKdmFyIFJJR0hUU19QQVRIX1JFTU9WRV9ESVJFQ1RPUlkgPSAxIDw8IDI1Owp2YXIgUklHSFRTX1BBVEhfVU5MSU5LX0ZJTEUgPSAxIDw8IDI2Owp2YXIgUklHSFRTX1BPTExfRkRfUkVBRFdSSVRFID0gMSA8PCAyNzsKdmFyIFJJR0hUU19TT0NLX1NIVVRET1dOID0gMSA8PCAyODsKdmFyIElvdmVjID0gY2xhc3MgewogIHN0YXRpYyByZWFkX2J5dGVzKHZpZXcsIHB0cikgewogICAgY29uc3QgaW92ZWMgPSBuZXcgSW92ZWMoKTsKICAgIGlvdmVjLmJ1ZiA9IHZpZXcuZ2V0VWludDMyKHB0ciwgdHJ1ZSk7CiAgICBpb3ZlYy5idWZfbGVuID0gdmlldy5nZXRVaW50MzIocHRyICsgNCwgdHJ1ZSk7CiAgICByZXR1cm4gaW92ZWM7CiAgfQogIHN0YXRpYyByZWFkX2J5dGVzX2FycmF5KHZpZXcsIHB0ciwgbGVuKSB7CiAgICBjb25zdCBpb3ZlY3MgPSBbXTsKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspIHsKICAgICAgaW92ZWNzLnB1c2goSW92ZWMucmVhZF9ieXRlcyh2aWV3LCBwdHIgKyA4ICogaSkpOwogICAgfQogICAgcmV0dXJuIGlvdmVjczsKICB9Cn07CnZhciBDaW92ZWMgPSBjbGFzcyB7CiAgc3RhdGljIHJlYWRfYnl0ZXModmlldywgcHRyKSB7CiAgICBjb25zdCBpb3ZlYyA9IG5ldyBDaW92ZWMoKTsKICAgIGlvdmVjLmJ1ZiA9IHZpZXcuZ2V0VWludDMyKHB0ciwgdHJ1ZSk7CiAgICBpb3ZlYy5idWZfbGVuID0gdmlldy5nZXRVaW50MzIocHRyICsgNCwgdHJ1ZSk7CiAgICByZXR1cm4gaW92ZWM7CiAgfQogIHN0YXRpYyByZWFkX2J5dGVzX2FycmF5KHZpZXcsIHB0ciwgbGVuKSB7CiAgICBjb25zdCBpb3ZlY3MgPSBbXTsKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGVuOyBpKyspIHsKICAgICAgaW92ZWNzLnB1c2goQ2lvdmVjLnJlYWRfYnl0ZXModmlldywgcHRyICsgOCAqIGkpKTsKICAgIH0KICAgIHJldHVybiBpb3ZlY3M7CiAgfQp9Owp2YXIgV0hFTkNFX1NFVCA9IDA7CnZhciBXSEVOQ0VfQ1VSID0gMTsKdmFyIFdIRU5DRV9FTkQgPSAyOwp2YXIgRklMRVRZUEVfQ0hBUkFDVEVSX0RFVklDRSA9IDI7CnZhciBGSUxFVFlQRV9ESVJFQ1RPUlkgPSAzOwp2YXIgRklMRVRZUEVfUkVHVUxBUl9GSUxFID0gNDsKdmFyIERpcmVudCA9IGNsYXNzIHsKICBoZWFkX2xlbmd0aCgpIHsKICAgIHJldHVybiAyNDsKICB9CiAgbmFtZV9sZW5ndGgoKSB7CiAgICByZXR1cm4gdGhpcy5kaXJfbmFtZS5ieXRlTGVuZ3RoOwogIH0KICB3cml0ZV9oZWFkX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRCaWdVaW50NjQocHRyLCB0aGlzLmRfbmV4dCwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA4LCB0aGlzLmRfaW5vLCB0cnVlKTsKICAgIHZpZXcuc2V0VWludDMyKHB0ciArIDE2LCB0aGlzLmRpcl9uYW1lLmxlbmd0aCwgdHJ1ZSk7CiAgICB2aWV3LnNldFVpbnQ4KHB0ciArIDIwLCB0aGlzLmRfdHlwZSk7CiAgfQogIHdyaXRlX25hbWVfYnl0ZXModmlldzgsIHB0ciwgYnVmX2xlbikgewogICAgdmlldzguc2V0KHRoaXMuZGlyX25hbWUuc2xpY2UoMCwgTWF0aC5taW4odGhpcy5kaXJfbmFtZS5ieXRlTGVuZ3RoLCBidWZfbGVuKSksIHB0cik7CiAgfQogIGNvbnN0cnVjdG9yKG5leHRfY29va2llLCBuYW1lLCB0eXBlKSB7CiAgICB0aGlzLmRfaW5vID0gMG47CiAgICBjb25zdCBlbmNvZGVkX25hbWUgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUobmFtZSk7CiAgICB0aGlzLmRfbmV4dCA9IG5leHRfY29va2llOwogICAgdGhpcy5kX25hbWxlbiA9IGVuY29kZWRfbmFtZS5ieXRlTGVuZ3RoOwogICAgdGhpcy5kX3R5cGUgPSB0eXBlOwogICAgdGhpcy5kaXJfbmFtZSA9IGVuY29kZWRfbmFtZTsKICB9Cn07CnZhciBGREZMQUdTX0FQUEVORCA9IDEgPDwgMDsKdmFyIEZERkxBR1NfRFNZTkMgPSAxIDw8IDE7CnZhciBGREZMQUdTX05PTkJMT0NLID0gMSA8PCAyOwp2YXIgRkRGTEFHU19SU1lOQyA9IDEgPDwgMzsKdmFyIEZERkxBR1NfU1lOQyA9IDEgPDwgNDsKdmFyIEZkc3RhdCA9IGNsYXNzIHsKICB3cml0ZV9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIHZpZXcuc2V0VWludDgocHRyLCB0aGlzLmZzX2ZpbGV0eXBlKTsKICAgIHZpZXcuc2V0VWludDE2KHB0ciArIDIsIHRoaXMuZnNfZmxhZ3MsIHRydWUpOwogICAgdmlldy5zZXRCaWdVaW50NjQocHRyICsgOCwgdGhpcy5mc19yaWdodHNfYmFzZSwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyAxNiwgdGhpcy5mc19yaWdodHNfaW5oZXJpdGVkLCB0cnVlKTsKICB9CiAgY29uc3RydWN0b3IoZmlsZXR5cGUsIGZsYWdzKSB7CiAgICB0aGlzLmZzX3JpZ2h0c19iYXNlID0gMG47CiAgICB0aGlzLmZzX3JpZ2h0c19pbmhlcml0ZWQgPSAwbjsKICAgIHRoaXMuZnNfZmlsZXR5cGUgPSBmaWxldHlwZTsKICAgIHRoaXMuZnNfZmxhZ3MgPSBmbGFnczsKICB9Cn07CnZhciBGU1RGTEFHU19BVElNID0gMSA8PCAwOwp2YXIgRlNURkxBR1NfQVRJTV9OT1cgPSAxIDw8IDE7CnZhciBGU1RGTEFHU19NVElNID0gMSA8PCAyOwp2YXIgRlNURkxBR1NfTVRJTV9OT1cgPSAxIDw8IDM7CnZhciBPRkxBR1NfQ1JFQVQgPSAxIDw8IDA7CnZhciBPRkxBR1NfRElSRUNUT1JZID0gMSA8PCAxOwp2YXIgT0ZMQUdTX0VYQ0wgPSAxIDw8IDI7CnZhciBPRkxBR1NfVFJVTkMgPSAxIDw8IDM7CnZhciBGaWxlc3RhdCA9IGNsYXNzIHsKICB3cml0ZV9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciwgdGhpcy5kZXYsIHRydWUpOwogICAgdmlldy5zZXRCaWdVaW50NjQocHRyICsgOCwgdGhpcy5pbm8sIHRydWUpOwogICAgdmlldy5zZXRVaW50OChwdHIgKyAxNiwgdGhpcy5maWxldHlwZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyAyNCwgdGhpcy5ubGluaywgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyAzMiwgdGhpcy5zaXplLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDM4LCB0aGlzLmF0aW0sIHRydWUpOwogICAgdmlldy5zZXRCaWdVaW50NjQocHRyICsgNDYsIHRoaXMubXRpbSwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA1MiwgdGhpcy5jdGltLCB0cnVlKTsKICB9CiAgY29uc3RydWN0b3IoZmlsZXR5cGUsIHNpemUpIHsKICAgIHRoaXMuZGV2ID0gMG47CiAgICB0aGlzLmlubyA9IDBuOwogICAgdGhpcy5ubGluayA9IDBuOwogICAgdGhpcy5hdGltID0gMG47CiAgICB0aGlzLm10aW0gPSAwbjsKICAgIHRoaXMuY3RpbSA9IDBuOwogICAgdGhpcy5maWxldHlwZSA9IGZpbGV0eXBlOwogICAgdGhpcy5zaXplID0gc2l6ZTsKICB9Cn07CnZhciBFVkVOVFJXRkxBR1NfRkRfUkVBRFdSSVRFX0hBTkdVUCA9IDEgPDwgMDsKdmFyIFNVQkNMT0NLRkxBR1NfU1VCU0NSSVBUSU9OX0NMT0NLX0FCU1RJTUUgPSAxIDw8IDA7CnZhciBSSUZMQUdTX1JFQ1ZfUEVFSyA9IDEgPDwgMDsKdmFyIFJJRkxBR1NfUkVDVl9XQUlUQUxMID0gMSA8PCAxOwp2YXIgUk9GTEFHU19SRUNWX0RBVEFfVFJVTkNBVEVEID0gMSA8PCAwOwp2YXIgU0RGTEFHU19SRCA9IDEgPDwgMDsKdmFyIFNERkxBR1NfV1IgPSAxIDw8IDE7CnZhciBQUkVPUEVOVFlQRV9ESVIgPSAwOwp2YXIgUHJlc3RhdERpciA9IGNsYXNzIHsKICB3cml0ZV9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIHZpZXcuc2V0VWludDMyKHB0ciwgdGhpcy5wcl9uYW1lLmJ5dGVMZW5ndGgsIHRydWUpOwogIH0KICBjb25zdHJ1Y3RvcihuYW1lKSB7CiAgICB0aGlzLnByX25hbWUgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUobmFtZSk7CiAgfQp9Owp2YXIgUHJlc3RhdCA9IGNsYXNzIHsKICBzdGF0aWMgZGlyKG5hbWUpIHsKICAgIGNvbnN0IHByZXN0YXQgPSBuZXcgUHJlc3RhdCgpOwogICAgcHJlc3RhdC50YWcgPSBQUkVPUEVOVFlQRV9ESVI7CiAgICBwcmVzdGF0LmlubmVyID0gbmV3IFByZXN0YXREaXIobmFtZSk7CiAgICByZXR1cm4gcHJlc3RhdDsKICB9CiAgd3JpdGVfYnl0ZXModmlldywgcHRyKSB7CiAgICB2aWV3LnNldFVpbnQzMihwdHIsIHRoaXMudGFnLCB0cnVlKTsKICAgIHRoaXMuaW5uZXIud3JpdGVfYnl0ZXModmlldywgcHRyICsgNCk7CiAgfQp9OwoKLy8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC9kZWJ1Zy5qcwp2YXIgRGVidWcgPSBjbGFzcyBEZWJ1ZzIgewogIGVuYWJsZShlbmFibGVkKSB7CiAgICB0aGlzLmxvZyA9IGNyZWF0ZUxvZ2dlcihlbmFibGVkID09PSB2b2lkIDAgPyB0cnVlIDogZW5hYmxlZCwgdGhpcy5wcmVmaXgpOwogIH0KICBnZXQgZW5hYmxlZCgpIHsKICAgIHJldHVybiB0aGlzLmlzRW5hYmxlZDsKICB9CiAgY29uc3RydWN0b3IoaXNFbmFibGVkKSB7CiAgICB0aGlzLmlzRW5hYmxlZCA9IGlzRW5hYmxlZDsKICAgIHRoaXMucHJlZml4ID0gIndhc2k6IjsKICAgIHRoaXMuZW5hYmxlKGlzRW5hYmxlZCk7CiAgfQp9OwpmdW5jdGlvbiBjcmVhdGVMb2dnZXIoZW5hYmxlZCwgcHJlZml4KSB7CiAgaWYgKGVuYWJsZWQpIHsKICAgIGNvbnN0IGEgPSBjb25zb2xlLmxvZy5iaW5kKGNvbnNvbGUsICIlYyVzIiwgImNvbG9yOiAjMjY1QkEwIiwgcHJlZml4KTsKICAgIHJldHVybiBhOwogIH0gZWxzZSB7CiAgICByZXR1cm4gKCkgPT4gewogICAgfTsKICB9Cn0KdmFyIGRlYnVnID0gbmV3IERlYnVnKGZhbHNlKTsKCi8vIG5vZGVfbW9kdWxlcy9AYmpvcm4zL2Jyb3dzZXJfd2FzaV9zaGltL2Rpc3Qvd2FzaS5qcwp2YXIgV0FTSVByb2NFeGl0ID0gY2xhc3MgZXh0ZW5kcyBFcnJvciB7CiAgY29uc3RydWN0b3IoY29kZSkgewogICAgc3VwZXIoImV4aXQgd2l0aCBleGl0IGNvZGUgIiArIGNvZGUpOwogICAgdGhpcy5jb2RlID0gY29kZTsKICB9Cn07CnZhciBXQVNJID0gY2xhc3MgV0FTSTIgewogIHN0YXJ0KGluc3RhbmNlKSB7CiAgICB0aGlzLmluc3QgPSBpbnN0YW5jZTsKICAgIHRyeSB7CiAgICAgIGluc3RhbmNlLmV4cG9ydHMuX3N0YXJ0KCk7CiAgICAgIHJldHVybiAwOwogICAgfSBjYXRjaCAoZSkgewogICAgICBpZiAoZSBpbnN0YW5jZW9mIFdBU0lQcm9jRXhpdCkgewogICAgICAgIHJldHVybiBlLmNvZGU7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdGhyb3cgZTsKICAgICAgfQogICAgfQogIH0KICBpbml0aWFsaXplKGluc3RhbmNlKSB7CiAgICB0aGlzLmluc3QgPSBpbnN0YW5jZTsKICAgIGlmIChpbnN0YW5jZS5leHBvcnRzLl9pbml0aWFsaXplKSB7CiAgICAgIGluc3RhbmNlLmV4cG9ydHMuX2luaXRpYWxpemUoKTsKICAgIH0KICB9CiAgY29uc3RydWN0b3IoYXJncywgZW52LCBmZHMsIG9wdGlvbnMgPSB7fSkgewogICAgdGhpcy5hcmdzID0gW107CiAgICB0aGlzLmVudiA9IFtdOwogICAgdGhpcy5mZHMgPSBbXTsKICAgIGRlYnVnLmVuYWJsZShvcHRpb25zLmRlYnVnKTsKICAgIHRoaXMuYXJncyA9IGFyZ3M7CiAgICB0aGlzLmVudiA9IGVudjsKICAgIHRoaXMuZmRzID0gZmRzOwogICAgY29uc3Qgc2VsZiA9IHRoaXM7CiAgICB0aGlzLndhc2lJbXBvcnQgPSB7IGFyZ3Nfc2l6ZXNfZ2V0KGFyZ2MsIGFyZ3ZfYnVmX3NpemUpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBidWZmZXIuc2V0VWludDMyKGFyZ2MsIHNlbGYuYXJncy5sZW5ndGgsIHRydWUpOwogICAgICBsZXQgYnVmX3NpemUgPSAwOwogICAgICBmb3IgKGNvbnN0IGFyZyBvZiBzZWxmLmFyZ3MpIHsKICAgICAgICBidWZfc2l6ZSArPSBhcmcubGVuZ3RoICsgMTsKICAgICAgfQogICAgICBidWZmZXIuc2V0VWludDMyKGFyZ3ZfYnVmX3NpemUsIGJ1Zl9zaXplLCB0cnVlKTsKICAgICAgZGVidWcubG9nKGJ1ZmZlci5nZXRVaW50MzIoYXJnYywgdHJ1ZSksIGJ1ZmZlci5nZXRVaW50MzIoYXJndl9idWZfc2l6ZSwgdHJ1ZSkpOwogICAgICByZXR1cm4gMDsKICAgIH0sIGFyZ3NfZ2V0KGFyZ3YsIGFyZ3ZfYnVmKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBvcmlnX2FyZ3ZfYnVmID0gYXJndl9idWY7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2VsZi5hcmdzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgYnVmZmVyLnNldFVpbnQzMihhcmd2LCBhcmd2X2J1ZiwgdHJ1ZSk7CiAgICAgICAgYXJndiArPSA0OwogICAgICAgIGNvbnN0IGFyZyA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShzZWxmLmFyZ3NbaV0pOwogICAgICAgIGJ1ZmZlcjguc2V0KGFyZywgYXJndl9idWYpOwogICAgICAgIGJ1ZmZlci5zZXRVaW50OChhcmd2X2J1ZiArIGFyZy5sZW5ndGgsIDApOwogICAgICAgIGFyZ3ZfYnVmICs9IGFyZy5sZW5ndGggKyAxOwogICAgICB9CiAgICAgIGlmIChkZWJ1Zy5lbmFibGVkKSB7CiAgICAgICAgZGVidWcubG9nKG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShvcmlnX2FyZ3ZfYnVmLCBhcmd2X2J1ZikpKTsKICAgICAgfQogICAgICByZXR1cm4gMDsKICAgIH0sIGVudmlyb25fc2l6ZXNfZ2V0KGVudmlyb25fY291bnQsIGVudmlyb25fc2l6ZSkgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoZW52aXJvbl9jb3VudCwgc2VsZi5lbnYubGVuZ3RoLCB0cnVlKTsKICAgICAgbGV0IGJ1Zl9zaXplID0gMDsKICAgICAgZm9yIChjb25zdCBlbnZpcm9uIG9mIHNlbGYuZW52KSB7CiAgICAgICAgYnVmX3NpemUgKz0gZW52aXJvbi5sZW5ndGggKyAxOwogICAgICB9CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoZW52aXJvbl9zaXplLCBidWZfc2l6ZSwgdHJ1ZSk7CiAgICAgIGRlYnVnLmxvZyhidWZmZXIuZ2V0VWludDMyKGVudmlyb25fY291bnQsIHRydWUpLCBidWZmZXIuZ2V0VWludDMyKGVudmlyb25fc2l6ZSwgdHJ1ZSkpOwogICAgICByZXR1cm4gMDsKICAgIH0sIGVudmlyb25fZ2V0KGVudmlyb24sIGVudmlyb25fYnVmKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBvcmlnX2Vudmlyb25fYnVmID0gZW52aXJvbl9idWY7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2VsZi5lbnYubGVuZ3RoOyBpKyspIHsKICAgICAgICBidWZmZXIuc2V0VWludDMyKGVudmlyb24sIGVudmlyb25fYnVmLCB0cnVlKTsKICAgICAgICBlbnZpcm9uICs9IDQ7CiAgICAgICAgY29uc3QgZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShzZWxmLmVudltpXSk7CiAgICAgICAgYnVmZmVyOC5zZXQoZSwgZW52aXJvbl9idWYpOwogICAgICAgIGJ1ZmZlci5zZXRVaW50OChlbnZpcm9uX2J1ZiArIGUubGVuZ3RoLCAwKTsKICAgICAgICBlbnZpcm9uX2J1ZiArPSBlLmxlbmd0aCArIDE7CiAgICAgIH0KICAgICAgaWYgKGRlYnVnLmVuYWJsZWQpIHsKICAgICAgICBkZWJ1Zy5sb2cobmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG9yaWdfZW52aXJvbl9idWYsIGVudmlyb25fYnVmKSkpOwogICAgICB9CiAgICAgIHJldHVybiAwOwogICAgfSwgY2xvY2tfcmVzX2dldChpZCwgcmVzX3B0cikgewogICAgICBsZXQgcmVzb2x1dGlvblZhbHVlOwogICAgICBzd2l0Y2ggKGlkKSB7CiAgICAgICAgY2FzZSBDTE9DS0lEX01PTk9UT05JQzogewogICAgICAgICAgcmVzb2x1dGlvblZhbHVlID0gNTAwMG47CiAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICAgICAgY2FzZSBDTE9DS0lEX1JFQUxUSU1FOiB7CiAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSAxMDAwMDAwbjsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICBkZWZhdWx0OgogICAgICAgICAgcmV0dXJuIEVSUk5PX05PU1lTOwogICAgICB9CiAgICAgIGNvbnN0IHZpZXcgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIHZpZXcuc2V0QmlnVWludDY0KHJlc19wdHIsIHJlc29sdXRpb25WYWx1ZSwgdHJ1ZSk7CiAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgfSwgY2xvY2tfdGltZV9nZXQoaWQsIHByZWNpc2lvbiwgdGltZSkgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChpZCA9PT0gQ0xPQ0tJRF9SRUFMVElNRSkgewogICAgICAgIGJ1ZmZlci5zZXRCaWdVaW50NjQodGltZSwgQmlnSW50KG5ldyBEYXRlKCkuZ2V0VGltZSgpKSAqIDEwMDAwMDBuLCB0cnVlKTsKICAgICAgfSBlbHNlIGlmIChpZCA9PSBDTE9DS0lEX01PTk9UT05JQykgewogICAgICAgIGxldCBtb25vdG9uaWNfdGltZTsKICAgICAgICB0cnkgewogICAgICAgICAgbW9ub3RvbmljX3RpbWUgPSBCaWdJbnQoTWF0aC5yb3VuZChwZXJmb3JtYW5jZS5ub3coKSAqIDFlNikpOwogICAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICAgIG1vbm90b25pY190aW1lID0gMG47CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRCaWdVaW50NjQodGltZSwgbW9ub3RvbmljX3RpbWUsIHRydWUpOwogICAgICB9IGVsc2UgewogICAgICAgIGJ1ZmZlci5zZXRCaWdVaW50NjQodGltZSwgMG4sIHRydWUpOwogICAgICB9CiAgICAgIHJldHVybiAwOwogICAgfSwgZmRfYWR2aXNlKGZkLCBvZmZzZXQsIGxlbiwgYWR2aWNlKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2FsbG9jYXRlKGZkLCBvZmZzZXQsIGxlbikgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfYWxsb2NhdGUob2Zmc2V0LCBsZW4pOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9jbG9zZShmZCkgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHJldCA9IHNlbGYuZmRzW2ZkXS5mZF9jbG9zZSgpOwogICAgICAgIHNlbGYuZmRzW2ZkXSA9IHZvaWQgMDsKICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9kYXRhc3luYyhmZCkgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfc3luYygpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9mZHN0YXRfZ2V0KGZkLCBmZHN0YXRfcHRyKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIGZkc3RhdCB9ID0gc2VsZi5mZHNbZmRdLmZkX2Zkc3RhdF9nZXQoKTsKICAgICAgICBpZiAoZmRzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIGZkc3RhdC53cml0ZV9ieXRlcyhuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlciksIGZkc3RhdF9wdHIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9mZHN0YXRfc2V0X2ZsYWdzKGZkLCBmbGFncykgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmRzdGF0X3NldF9mbGFncyhmbGFncyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Zkc3RhdF9zZXRfcmlnaHRzKGZkLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICByZXR1cm4gc2VsZi5mZHNbZmRdLmZkX2Zkc3RhdF9zZXRfcmlnaHRzKGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2ZpbGVzdGF0X2dldChmZCwgZmlsZXN0YXRfcHRyKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIGZpbGVzdGF0IH0gPSBzZWxmLmZkc1tmZF0uZmRfZmlsZXN0YXRfZ2V0KCk7CiAgICAgICAgaWYgKGZpbGVzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIGZpbGVzdGF0LndyaXRlX2J5dGVzKG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKSwgZmlsZXN0YXRfcHRyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfZmlsZXN0YXRfc2V0X3NpemUoZmQsIHNpemUpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICByZXR1cm4gc2VsZi5mZHNbZmRdLmZkX2ZpbGVzdGF0X3NldF9zaXplKHNpemUpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9maWxlc3RhdF9zZXRfdGltZXMoZmQsIGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmlsZXN0YXRfc2V0X3RpbWVzKGF0aW0sIG10aW0sIGZzdF9mbGFncyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3ByZWFkKGZkLCBpb3ZzX3B0ciwgaW92c19sZW4sIG9mZnNldCwgbnJlYWRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IGlvdmVjcyA9IElvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBucmVhZCA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBkYXRhIH0gPSBzZWxmLmZkc1tmZF0uZmRfcHJlYWQoaW92ZWMuYnVmX2xlbiwgb2Zmc2V0KTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgYnVmZmVyOC5zZXQoZGF0YSwgaW92ZWMuYnVmKTsKICAgICAgICAgIG5yZWFkICs9IGRhdGEubGVuZ3RoOwogICAgICAgICAgb2Zmc2V0ICs9IEJpZ0ludChkYXRhLmxlbmd0aCk7CiAgICAgICAgICBpZiAoZGF0YS5sZW5ndGggIT0gaW92ZWMuYnVmX2xlbikgewogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgYnVmZmVyLnNldFVpbnQzMihucmVhZF9wdHIsIG5yZWFkLCB0cnVlKTsKICAgICAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHJlc3RhdF9nZXQoZmQsIGJ1Zl9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHsgcmV0LCBwcmVzdGF0IH0gPSBzZWxmLmZkc1tmZF0uZmRfcHJlc3RhdF9nZXQoKTsKICAgICAgICBpZiAocHJlc3RhdCAhPSBudWxsKSB7CiAgICAgICAgICBwcmVzdGF0LndyaXRlX2J5dGVzKGJ1ZmZlciwgYnVmX3B0cik7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3ByZXN0YXRfZGlyX25hbWUoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbikgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHsgcmV0LCBwcmVzdGF0IH0gPSBzZWxmLmZkc1tmZF0uZmRfcHJlc3RhdF9nZXQoKTsKICAgICAgICBpZiAocHJlc3RhdCA9PSBudWxsKSB7CiAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0KICAgICAgICBjb25zdCBwcmVzdGF0X2Rpcl9uYW1lID0gcHJlc3RhdC5pbm5lci5wcl9uYW1lOwogICAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICBidWZmZXI4LnNldChwcmVzdGF0X2Rpcl9uYW1lLnNsaWNlKDAsIHBhdGhfbGVuKSwgcGF0aF9wdHIpOwogICAgICAgIHJldHVybiBwcmVzdGF0X2Rpcl9uYW1lLmJ5dGVMZW5ndGggPiBwYXRoX2xlbiA/IEVSUk5PX05BTUVUT09MT05HIDogRVJSTk9fU1VDQ0VTUzsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHdyaXRlKGZkLCBpb3ZzX3B0ciwgaW92c19sZW4sIG9mZnNldCwgbndyaXR0ZW5fcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IGlvdmVjcyA9IENpb3ZlYy5yZWFkX2J5dGVzX2FycmF5KGJ1ZmZlciwgaW92c19wdHIsIGlvdnNfbGVuKTsKICAgICAgICBsZXQgbndyaXR0ZW4gPSAwOwogICAgICAgIGZvciAoY29uc3QgaW92ZWMgb2YgaW92ZWNzKSB7CiAgICAgICAgICBjb25zdCBkYXRhID0gYnVmZmVyOC5zbGljZShpb3ZlYy5idWYsIGlvdmVjLmJ1ZiArIGlvdmVjLmJ1Zl9sZW4pOwogICAgICAgICAgY29uc3QgeyByZXQsIG53cml0dGVuOiBud3JpdHRlbl9wYXJ0IH0gPSBzZWxmLmZkc1tmZF0uZmRfcHdyaXRlKGRhdGEsIG9mZnNldCk7CiAgICAgICAgICBpZiAocmV0ICE9IEVSUk5PX1NVQ0NFU1MpIHsKICAgICAgICAgICAgYnVmZmVyLnNldFVpbnQzMihud3JpdHRlbl9wdHIsIG53cml0dGVuLCB0cnVlKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICAgIH0KICAgICAgICAgIG53cml0dGVuICs9IG53cml0dGVuX3BhcnQ7CiAgICAgICAgICBvZmZzZXQgKz0gQmlnSW50KG53cml0dGVuX3BhcnQpOwogICAgICAgICAgaWYgKG53cml0dGVuX3BhcnQgIT0gZGF0YS5ieXRlTGVuZ3RoKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9yZWFkKGZkLCBpb3ZzX3B0ciwgaW92c19sZW4sIG5yZWFkX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBpb3ZlY3MgPSBJb3ZlYy5yZWFkX2J5dGVzX2FycmF5KGJ1ZmZlciwgaW92c19wdHIsIGlvdnNfbGVuKTsKICAgICAgICBsZXQgbnJlYWQgPSAwOwogICAgICAgIGZvciAoY29uc3QgaW92ZWMgb2YgaW92ZWNzKSB7CiAgICAgICAgICBjb25zdCB7IHJldCwgZGF0YSB9ID0gc2VsZi5mZHNbZmRdLmZkX3JlYWQoaW92ZWMuYnVmX2xlbik7CiAgICAgICAgICBpZiAocmV0ICE9IEVSUk5PX1NVQ0NFU1MpIHsKICAgICAgICAgICAgYnVmZmVyLnNldFVpbnQzMihucmVhZF9wdHIsIG5yZWFkLCB0cnVlKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICAgIH0KICAgICAgICAgIGJ1ZmZlcjguc2V0KGRhdGEsIGlvdmVjLmJ1Zik7CiAgICAgICAgICBucmVhZCArPSBkYXRhLmxlbmd0aDsKICAgICAgICAgIGlmIChkYXRhLmxlbmd0aCAhPSBpb3ZlYy5idWZfbGVuKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9yZWFkZGlyKGZkLCBidWYsIGJ1Zl9sZW4sIGNvb2tpZSwgYnVmdXNlZF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgbGV0IGJ1ZnVzZWQgPSAwOwogICAgICAgIHdoaWxlICh0cnVlKSB7CiAgICAgICAgICBjb25zdCB7IHJldCwgZGlyZW50IH0gPSBzZWxmLmZkc1tmZF0uZmRfcmVhZGRpcl9zaW5nbGUoY29va2llKTsKICAgICAgICAgIGlmIChyZXQgIT0gMCkgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKGJ1ZnVzZWRfcHRyLCBidWZ1c2VkLCB0cnVlKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChkaXJlbnQgPT0gbnVsbCkgewogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChidWZfbGVuIC0gYnVmdXNlZCA8IGRpcmVudC5oZWFkX2xlbmd0aCgpKSB7CiAgICAgICAgICAgIGJ1ZnVzZWQgPSBidWZfbGVuOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGhlYWRfYnl0ZXMgPSBuZXcgQXJyYXlCdWZmZXIoZGlyZW50LmhlYWRfbGVuZ3RoKCkpOwogICAgICAgICAgZGlyZW50LndyaXRlX2hlYWRfYnl0ZXMobmV3IERhdGFWaWV3KGhlYWRfYnl0ZXMpLCAwKTsKICAgICAgICAgIGJ1ZmZlcjguc2V0KG5ldyBVaW50OEFycmF5KGhlYWRfYnl0ZXMpLnNsaWNlKDAsIE1hdGgubWluKGhlYWRfYnl0ZXMuYnl0ZUxlbmd0aCwgYnVmX2xlbiAtIGJ1ZnVzZWQpKSwgYnVmKTsKICAgICAgICAgIGJ1ZiArPSBkaXJlbnQuaGVhZF9sZW5ndGgoKTsKICAgICAgICAgIGJ1ZnVzZWQgKz0gZGlyZW50LmhlYWRfbGVuZ3RoKCk7CiAgICAgICAgICBpZiAoYnVmX2xlbiAtIGJ1ZnVzZWQgPCBkaXJlbnQubmFtZV9sZW5ndGgoKSkgewogICAgICAgICAgICBidWZ1c2VkID0gYnVmX2xlbjsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgICBkaXJlbnQud3JpdGVfbmFtZV9ieXRlcyhidWZmZXI4LCBidWYsIGJ1Zl9sZW4gLSBidWZ1c2VkKTsKICAgICAgICAgIGJ1ZiArPSBkaXJlbnQubmFtZV9sZW5ndGgoKTsKICAgICAgICAgIGJ1ZnVzZWQgKz0gZGlyZW50Lm5hbWVfbGVuZ3RoKCk7CiAgICAgICAgICBjb29raWUgPSBkaXJlbnQuZF9uZXh0OwogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKGJ1ZnVzZWRfcHRyLCBidWZ1c2VkLCB0cnVlKTsKICAgICAgICByZXR1cm4gMDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcmVudW1iZXIoZmQsIHRvKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwICYmIHNlbGYuZmRzW3RvXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCByZXQgPSBzZWxmLmZkc1t0b10uZmRfY2xvc2UoKTsKICAgICAgICBpZiAocmV0ICE9IDApIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHNlbGYuZmRzW3RvXSA9IHNlbGYuZmRzW2ZkXTsKICAgICAgICBzZWxmLmZkc1tmZF0gPSB2b2lkIDA7CiAgICAgICAgcmV0dXJuIDA7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3NlZWsoZmQsIG9mZnNldCwgd2hlbmNlLCBvZmZzZXRfb3V0X3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIG9mZnNldDogb2Zmc2V0X291dCB9ID0gc2VsZi5mZHNbZmRdLmZkX3NlZWsob2Zmc2V0LCB3aGVuY2UpOwogICAgICAgIGJ1ZmZlci5zZXRCaWdJbnQ2NChvZmZzZXRfb3V0X3B0ciwgb2Zmc2V0X291dCwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfc3luYyhmZCkgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfc3luYygpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF90ZWxsKGZkLCBvZmZzZXRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgb2Zmc2V0IH0gPSBzZWxmLmZkc1tmZF0uZmRfdGVsbCgpOwogICAgICAgIGJ1ZmZlci5zZXRCaWdVaW50NjQob2Zmc2V0X3B0ciwgb2Zmc2V0LCB0cnVlKTsKICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF93cml0ZShmZCwgaW92c19wdHIsIGlvdnNfbGVuLCBud3JpdHRlbl9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgaW92ZWNzID0gQ2lvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBud3JpdHRlbiA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IGRhdGEgPSBidWZmZXI4LnNsaWNlKGlvdmVjLmJ1ZiwgaW92ZWMuYnVmICsgaW92ZWMuYnVmX2xlbik7CiAgICAgICAgICBjb25zdCB7IHJldCwgbndyaXR0ZW46IG53cml0dGVuX3BhcnQgfSA9IHNlbGYuZmRzW2ZkXS5mZF93cml0ZShkYXRhKTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgbndyaXR0ZW4gKz0gbndyaXR0ZW5fcGFydDsKICAgICAgICAgIGlmIChud3JpdHRlbl9wYXJ0ICE9IGRhdGEuYnl0ZUxlbmd0aCkgewogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgYnVmZmVyLnNldFVpbnQzMihud3JpdHRlbl9wdHIsIG53cml0dGVuLCB0cnVlKTsKICAgICAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9jcmVhdGVfZGlyZWN0b3J5KGZkLCBwYXRoX3B0ciwgcGF0aF9sZW4pIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICByZXR1cm4gc2VsZi5mZHNbZmRdLnBhdGhfY3JlYXRlX2RpcmVjdG9yeShwYXRoKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9maWxlc3RhdF9nZXQoZmQsIGZsYWdzLCBwYXRoX3B0ciwgcGF0aF9sZW4sIGZpbGVzdGF0X3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgY29uc3QgeyByZXQsIGZpbGVzdGF0IH0gPSBzZWxmLmZkc1tmZF0ucGF0aF9maWxlc3RhdF9nZXQoZmxhZ3MsIHBhdGgpOwogICAgICAgIGlmIChmaWxlc3RhdCAhPSBudWxsKSB7CiAgICAgICAgICBmaWxlc3RhdC53cml0ZV9ieXRlcyhidWZmZXIsIGZpbGVzdGF0X3B0cik7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfZmlsZXN0YXRfc2V0X3RpbWVzKGZkLCBmbGFncywgcGF0aF9wdHIsIHBhdGhfbGVuLCBhdGltLCBtdGltLCBmc3RfZmxhZ3MpIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICByZXR1cm4gc2VsZi5mZHNbZmRdLnBhdGhfZmlsZXN0YXRfc2V0X3RpbWVzKGZsYWdzLCBwYXRoLCBhdGltLCBtdGltLCBmc3RfZmxhZ3MpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX2xpbmsob2xkX2ZkLCBvbGRfZmxhZ3MsIG9sZF9wYXRoX3B0ciwgb2xkX3BhdGhfbGVuLCBuZXdfZmQsIG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW29sZF9mZF0gIT0gdm9pZCAwICYmIHNlbGYuZmRzW25ld19mZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3Qgb2xkX3BhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9wdHIgKyBvbGRfcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCBuZXdfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShuZXdfcGF0aF9wdHIsIG5ld19wYXRoX3B0ciArIG5ld19wYXRoX2xlbikpOwogICAgICAgIGNvbnN0IHsgcmV0LCBpbm9kZV9vYmogfSA9IHNlbGYuZmRzW29sZF9mZF0ucGF0aF9sb29rdXAob2xkX3BhdGgsIG9sZF9mbGFncyk7CiAgICAgICAgaWYgKGlub2RlX29iaiA9PSBudWxsKSB7CiAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0KICAgICAgICByZXR1cm4gc2VsZi5mZHNbbmV3X2ZkXS5wYXRoX2xpbmsobmV3X3BhdGgsIGlub2RlX29iaiwgZmFsc2UpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX29wZW4oZmQsIGRpcmZsYWdzLCBwYXRoX3B0ciwgcGF0aF9sZW4sIG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nLCBmZF9mbGFncywgb3BlbmVkX2ZkX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgZGVidWcubG9nKHBhdGgpOwogICAgICAgIGNvbnN0IHsgcmV0LCBmZF9vYmogfSA9IHNlbGYuZmRzW2ZkXS5wYXRoX29wZW4oZGlyZmxhZ3MsIHBhdGgsIG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nLCBmZF9mbGFncyk7CiAgICAgICAgaWYgKHJldCAhPSAwKSB7CiAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0KICAgICAgICBzZWxmLmZkcy5wdXNoKGZkX29iaik7CiAgICAgICAgY29uc3Qgb3BlbmVkX2ZkID0gc2VsZi5mZHMubGVuZ3RoIC0gMTsKICAgICAgICBidWZmZXIuc2V0VWludDMyKG9wZW5lZF9mZF9wdHIsIG9wZW5lZF9mZCwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIDA7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfcmVhZGxpbmsoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbiwgYnVmX3B0ciwgYnVmX2xlbiwgbnJlYWRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICBkZWJ1Zy5sb2cocGF0aCk7CiAgICAgICAgY29uc3QgeyByZXQsIGRhdGEgfSA9IHNlbGYuZmRzW2ZkXS5wYXRoX3JlYWRsaW5rKHBhdGgpOwogICAgICAgIGlmIChkYXRhICE9IG51bGwpIHsKICAgICAgICAgIGNvbnN0IGRhdGFfYnVmID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKGRhdGEpOwogICAgICAgICAgaWYgKGRhdGFfYnVmLmxlbmd0aCA+IGJ1Zl9sZW4pIHsKICAgICAgICAgICAgYnVmZmVyLnNldFVpbnQzMihucmVhZF9wdHIsIDAsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgICAgIH0KICAgICAgICAgIGJ1ZmZlcjguc2V0KGRhdGFfYnVmLCBidWZfcHRyKTsKICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobnJlYWRfcHRyLCBkYXRhX2J1Zi5sZW5ndGgsIHRydWUpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX3JlbW92ZV9kaXJlY3RvcnkoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF9yZW1vdmVfZGlyZWN0b3J5KHBhdGgpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX3JlbmFtZShmZCwgb2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9sZW4sIG5ld19mZCwgbmV3X3BhdGhfcHRyLCBuZXdfcGF0aF9sZW4pIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCAmJiBzZWxmLmZkc1tuZXdfZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IG9sZF9wYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG9sZF9wYXRoX3B0ciwgb2xkX3BhdGhfcHRyICsgb2xkX3BhdGhfbGVuKSk7CiAgICAgICAgY29uc3QgbmV3X3BhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UobmV3X3BhdGhfcHRyLCBuZXdfcGF0aF9wdHIgKyBuZXdfcGF0aF9sZW4pKTsKICAgICAgICBsZXQgeyByZXQsIGlub2RlX29iaiB9ID0gc2VsZi5mZHNbZmRdLnBhdGhfdW5saW5rKG9sZF9wYXRoKTsKICAgICAgICBpZiAoaW5vZGVfb2JqID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHJldCA9IHNlbGYuZmRzW25ld19mZF0ucGF0aF9saW5rKG5ld19wYXRoLCBpbm9kZV9vYmosIHRydWUpOwogICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgaWYgKHNlbGYuZmRzW2ZkXS5wYXRoX2xpbmsob2xkX3BhdGgsIGlub2RlX29iaiwgdHJ1ZSkgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICB0aHJvdyAicGF0aF9saW5rIHNob3VsZCBhbHdheXMgcmV0dXJuIHN1Y2Nlc3Mgd2hlbiByZWxpbmtpbmcgYW4gaW5vZGUgYmFjayB0byB0aGUgb3JpZ2luYWwgcGxhY2UiOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX3N5bWxpbmsob2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9sZW4sIGZkLCBuZXdfcGF0aF9wdHIsIG5ld19wYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3Qgb2xkX3BhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9wdHIgKyBvbGRfcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCBuZXdfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShuZXdfcGF0aF9wdHIsIG5ld19wYXRoX3B0ciArIG5ld19wYXRoX2xlbikpOwogICAgICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfdW5saW5rX2ZpbGUoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF91bmxpbmtfZmlsZShwYXRoKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcG9sbF9vbmVvZmYoaW5fLCBvdXQsIG5zdWJzY3JpcHRpb25zKSB7CiAgICAgIHRocm93ICJhc3luYyBpbyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHByb2NfZXhpdChleGl0X2NvZGUpIHsKICAgICAgdGhyb3cgbmV3IFdBU0lQcm9jRXhpdChleGl0X2NvZGUpOwogICAgfSwgcHJvY19yYWlzZShzaWcpIHsKICAgICAgdGhyb3cgInJhaXNlZCBzaWduYWwgIiArIHNpZzsKICAgIH0sIHNjaGVkX3lpZWxkKCkgewogICAgfSwgcmFuZG9tX2dldChidWYsIGJ1Zl9sZW4pIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGJ1Zl9sZW47IGkrKykgewogICAgICAgIGJ1ZmZlcjhbYnVmICsgaV0gPSBNYXRoLnJhbmRvbSgpICogMjU2IHwgMDsKICAgICAgfQogICAgfSwgc29ja19yZWN2KGZkLCByaV9kYXRhLCByaV9mbGFncykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHNvY2tfc2VuZChmZCwgc2lfZGF0YSwgc2lfZmxhZ3MpIHsKICAgICAgdGhyb3cgInNvY2tldHMgbm90IHN1cHBvcnRlZCI7CiAgICB9LCBzb2NrX3NodXRkb3duKGZkLCBob3cpIHsKICAgICAgdGhyb3cgInNvY2tldHMgbm90IHN1cHBvcnRlZCI7CiAgICB9LCBzb2NrX2FjY2VwdChmZCwgZmxhZ3MpIHsKICAgICAgdGhyb3cgInNvY2tldHMgbm90IHN1cHBvcnRlZCI7CiAgICB9IH07CiAgfQp9OwoKLy8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC9mZC5qcwp2YXIgRmQgPSBjbGFzcyB7CiAgZmRfYWxsb2NhdGUob2Zmc2V0LCBsZW4pIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIGZkX2Nsb3NlKCkgewogICAgcmV0dXJuIDA7CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZmRzdGF0OiBudWxsIH07CiAgfQogIGZkX2Zkc3RhdF9zZXRfZmxhZ3MoZmxhZ3MpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIGZkX2Zkc3RhdF9zZXRfcmlnaHRzKGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfZmlsZXN0YXRfZ2V0KCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGZpbGVzdGF0OiBudWxsIH07CiAgfQogIGZkX2ZpbGVzdGF0X3NldF9zaXplKHNpemUpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIGZkX2ZpbGVzdGF0X3NldF90aW1lcyhhdGltLCBtdGltLCBmc3RfZmxhZ3MpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIGZkX3ByZWFkKHNpemUsIG9mZnNldCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGRhdGE6IG5ldyBVaW50OEFycmF5KCkgfTsKICB9CiAgZmRfcHJlc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgcHJlc3RhdDogbnVsbCB9OwogIH0KICBmZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgbndyaXR0ZW46IDAgfTsKICB9CiAgZmRfcmVhZChzaXplKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZGF0YTogbmV3IFVpbnQ4QXJyYXkoKSB9OwogIH0KICBmZF9yZWFkZGlyX3NpbmdsZShjb29raWUpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBkaXJlbnQ6IG51bGwgfTsKICB9CiAgZmRfc2VlayhvZmZzZXQsIHdoZW5jZSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIG9mZnNldDogMG4gfTsKICB9CiAgZmRfc3luYygpIHsKICAgIHJldHVybiAwOwogIH0KICBmZF90ZWxsKCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIG9mZnNldDogMG4gfTsKICB9CiAgZmRfd3JpdGUoZGF0YSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIG53cml0dGVuOiAwIH07CiAgfQogIHBhdGhfY3JlYXRlX2RpcmVjdG9yeShwYXRoKSB7CiAgICByZXR1cm4gRVJSTk9fTk9UU1VQOwogIH0KICBwYXRoX2ZpbGVzdGF0X2dldChmbGFncywgcGF0aCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGZpbGVzdGF0OiBudWxsIH07CiAgfQogIHBhdGhfZmlsZXN0YXRfc2V0X3RpbWVzKGZsYWdzLCBwYXRoLCBhdGltLCBtdGltLCBmc3RfZmxhZ3MpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfbGluayhwYXRoLCBpbm9kZSwgYWxsb3dfZGlyKSB7CiAgICByZXR1cm4gRVJSTk9fTk9UU1VQOwogIH0KICBwYXRoX3VubGluayhwYXRoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgaW5vZGVfb2JqOiBudWxsIH07CiAgfQogIHBhdGhfbG9va3VwKHBhdGgsIGRpcmZsYWdzKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgaW5vZGVfb2JqOiBudWxsIH07CiAgfQogIHBhdGhfb3BlbihkaXJmbGFncywgcGF0aCwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgZmRfb2JqOiBudWxsIH07CiAgfQogIHBhdGhfcmVhZGxpbmsocGF0aCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGRhdGE6IG51bGwgfTsKICB9CiAgcGF0aF9yZW1vdmVfZGlyZWN0b3J5KHBhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfcmVuYW1lKG9sZF9wYXRoLCBuZXdfZmQsIG5ld19wYXRoKSB7CiAgICByZXR1cm4gRVJSTk9fTk9UU1VQOwogIH0KICBwYXRoX3VubGlua19maWxlKHBhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQp9Owp2YXIgSW5vZGUgPSBjbGFzcyB7Cn07CgovLyBub2RlX21vZHVsZXMvQGJqb3JuMy9icm93c2VyX3dhc2lfc2hpbS9kaXN0L2ZzX21lbS5qcwp2YXIgT3BlbkZpbGUgPSBjbGFzcyBleHRlbmRzIEZkIHsKICBmZF9hbGxvY2F0ZShvZmZzZXQsIGxlbikgewogICAgaWYgKHRoaXMuZmlsZS5zaXplID4gb2Zmc2V0ICsgbGVuKSB7CiAgICB9IGVsc2UgewogICAgICBjb25zdCBuZXdfZGF0YSA9IG5ldyBVaW50OEFycmF5KE51bWJlcihvZmZzZXQgKyBsZW4pKTsKICAgICAgbmV3X2RhdGEuc2V0KHRoaXMuZmlsZS5kYXRhLCAwKTsKICAgICAgdGhpcy5maWxlLmRhdGEgPSBuZXdfZGF0YTsKICAgIH0KICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogIH0KICBmZF9mZHN0YXRfZ2V0KCkgewogICAgcmV0dXJuIHsgcmV0OiAwLCBmZHN0YXQ6IG5ldyBGZHN0YXQoRklMRVRZUEVfUkVHVUxBUl9GSUxFLCAwKSB9OwogIH0KICBmZF9maWxlc3RhdF9zZXRfc2l6ZShzaXplKSB7CiAgICBpZiAodGhpcy5maWxlLnNpemUgPiBzaXplKSB7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5maWxlLmRhdGEuYnVmZmVyLnNsaWNlKDAsIE51bWJlcihzaXplKSkpOwogICAgfSBlbHNlIHsKICAgICAgY29uc3QgbmV3X2RhdGEgPSBuZXcgVWludDhBcnJheShOdW1iZXIoc2l6ZSkpOwogICAgICBuZXdfZGF0YS5zZXQodGhpcy5maWxlLmRhdGEsIDApOwogICAgICB0aGlzLmZpbGUuZGF0YSA9IG5ld19kYXRhOwogICAgfQogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIGZkX3JlYWQoc2l6ZSkgewogICAgY29uc3Qgc2xpY2UgPSB0aGlzLmZpbGUuZGF0YS5zbGljZShOdW1iZXIodGhpcy5maWxlX3BvcyksIE51bWJlcih0aGlzLmZpbGVfcG9zICsgQmlnSW50KHNpemUpKSk7CiAgICB0aGlzLmZpbGVfcG9zICs9IEJpZ0ludChzbGljZS5sZW5ndGgpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBkYXRhOiBzbGljZSB9OwogIH0KICBmZF9wcmVhZChzaXplLCBvZmZzZXQpIHsKICAgIGNvbnN0IHNsaWNlID0gdGhpcy5maWxlLmRhdGEuc2xpY2UoTnVtYmVyKG9mZnNldCksIE51bWJlcihvZmZzZXQgKyBCaWdJbnQoc2l6ZSkpKTsKICAgIHJldHVybiB7IHJldDogMCwgZGF0YTogc2xpY2UgfTsKICB9CiAgZmRfc2VlayhvZmZzZXQsIHdoZW5jZSkgewogICAgbGV0IGNhbGN1bGF0ZWRfb2Zmc2V0OwogICAgc3dpdGNoICh3aGVuY2UpIHsKICAgICAgY2FzZSBXSEVOQ0VfU0VUOgogICAgICAgIGNhbGN1bGF0ZWRfb2Zmc2V0ID0gb2Zmc2V0OwogICAgICAgIGJyZWFrOwogICAgICBjYXNlIFdIRU5DRV9DVVI6CiAgICAgICAgY2FsY3VsYXRlZF9vZmZzZXQgPSB0aGlzLmZpbGVfcG9zICsgb2Zmc2V0OwogICAgICAgIGJyZWFrOwogICAgICBjYXNlIFdIRU5DRV9FTkQ6CiAgICAgICAgY2FsY3VsYXRlZF9vZmZzZXQgPSBCaWdJbnQodGhpcy5maWxlLmRhdGEuYnl0ZUxlbmd0aCkgKyBvZmZzZXQ7CiAgICAgICAgYnJlYWs7CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19JTlZBTCwgb2Zmc2V0OiAwbiB9OwogICAgfQogICAgaWYgKGNhbGN1bGF0ZWRfb2Zmc2V0IDwgMCkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0lOVkFMLCBvZmZzZXQ6IDBuIH07CiAgICB9CiAgICB0aGlzLmZpbGVfcG9zID0gY2FsY3VsYXRlZF9vZmZzZXQ7CiAgICByZXR1cm4geyByZXQ6IDAsIG9mZnNldDogdGhpcy5maWxlX3BvcyB9OwogIH0KICBmZF90ZWxsKCkgewogICAgcmV0dXJuIHsgcmV0OiAwLCBvZmZzZXQ6IHRoaXMuZmlsZV9wb3MgfTsKICB9CiAgZmRfd3JpdGUoZGF0YSkgewogICAgaWYgKHRoaXMuZmlsZS5yZWFkb25seSkKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBud3JpdHRlbjogMCB9OwogICAgaWYgKHRoaXMuZmlsZV9wb3MgKyBCaWdJbnQoZGF0YS5ieXRlTGVuZ3RoKSA+IHRoaXMuZmlsZS5zaXplKSB7CiAgICAgIGNvbnN0IG9sZCA9IHRoaXMuZmlsZS5kYXRhOwogICAgICB0aGlzLmZpbGUuZGF0YSA9IG5ldyBVaW50OEFycmF5KE51bWJlcih0aGlzLmZpbGVfcG9zICsgQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCkpKTsKICAgICAgdGhpcy5maWxlLmRhdGEuc2V0KG9sZCk7CiAgICB9CiAgICB0aGlzLmZpbGUuZGF0YS5zZXQoZGF0YSwgTnVtYmVyKHRoaXMuZmlsZV9wb3MpKTsKICAgIHRoaXMuZmlsZV9wb3MgKz0gQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCk7CiAgICByZXR1cm4geyByZXQ6IDAsIG53cml0dGVuOiBkYXRhLmJ5dGVMZW5ndGggfTsKICB9CiAgZmRfcHdyaXRlKGRhdGEsIG9mZnNldCkgewogICAgaWYgKHRoaXMuZmlsZS5yZWFkb25seSkKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBud3JpdHRlbjogMCB9OwogICAgaWYgKG9mZnNldCArIEJpZ0ludChkYXRhLmJ5dGVMZW5ndGgpID4gdGhpcy5maWxlLnNpemUpIHsKICAgICAgY29uc3Qgb2xkID0gdGhpcy5maWxlLmRhdGE7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoTnVtYmVyKG9mZnNldCArIEJpZ0ludChkYXRhLmJ5dGVMZW5ndGgpKSk7CiAgICAgIHRoaXMuZmlsZS5kYXRhLnNldChvbGQpOwogICAgfQogICAgdGhpcy5maWxlLmRhdGEuc2V0KGRhdGEsIE51bWJlcihvZmZzZXQpKTsKICAgIHJldHVybiB7IHJldDogMCwgbndyaXR0ZW46IGRhdGEuYnl0ZUxlbmd0aCB9OwogIH0KICBmZF9maWxlc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIGZpbGVzdGF0OiB0aGlzLmZpbGUuc3RhdCgpIH07CiAgfQogIGNvbnN0cnVjdG9yKGZpbGUpIHsKICAgIHN1cGVyKCk7CiAgICB0aGlzLmZpbGVfcG9zID0gMG47CiAgICB0aGlzLmZpbGUgPSBmaWxlOwogIH0KfTsKdmFyIE9wZW5EaXJlY3RvcnkgPSBjbGFzcyBleHRlbmRzIEZkIHsKICBmZF9zZWVrKG9mZnNldCwgd2hlbmNlKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG9mZnNldDogMG4gfTsKICB9CiAgZmRfdGVsbCgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fQkFERiwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF9hbGxvY2F0ZShvZmZzZXQsIGxlbikgewogICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIGZkc3RhdDogbmV3IEZkc3RhdChGSUxFVFlQRV9ESVJFQ1RPUlksIDApIH07CiAgfQogIGZkX3JlYWRkaXJfc2luZ2xlKGNvb2tpZSkgewogICAgaWYgKGRlYnVnLmVuYWJsZWQpIHsKICAgICAgZGVidWcubG9nKCJyZWFkZGlyX3NpbmdsZSIsIGNvb2tpZSk7CiAgICAgIGRlYnVnLmxvZyhjb29raWUsIHRoaXMuZGlyLmNvbnRlbnRzLmtleXMoKSk7CiAgICB9CiAgICBpZiAoY29va2llID09IDBuKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZGlyZW50OiBuZXcgRGlyZW50KDFuLCAiLiIsIEZJTEVUWVBFX0RJUkVDVE9SWSkgfTsKICAgIH0gZWxzZSBpZiAoY29va2llID09IDFuKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZGlyZW50OiBuZXcgRGlyZW50KDJuLCAiLi4iLCBGSUxFVFlQRV9ESVJFQ1RPUlkpIH07CiAgICB9CiAgICBpZiAoY29va2llID49IEJpZ0ludCh0aGlzLmRpci5jb250ZW50cy5zaXplKSArIDJuKSB7CiAgICAgIHJldHVybiB7IHJldDogMCwgZGlyZW50OiBudWxsIH07CiAgICB9CiAgICBjb25zdCBbbmFtZSwgZW50cnldID0gQXJyYXkuZnJvbSh0aGlzLmRpci5jb250ZW50cy5lbnRyaWVzKCkpW051bWJlcihjb29raWUgLSAybildOwogICAgcmV0dXJuIHsgcmV0OiAwLCBkaXJlbnQ6IG5ldyBEaXJlbnQoY29va2llICsgMW4sIG5hbWUsIGVudHJ5LnN0YXQoKS5maWxldHlwZSkgfTsKICB9CiAgcGF0aF9maWxlc3RhdF9nZXQoZmxhZ3MsIHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9lcnIsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogcGF0aF9lcnIsIGZpbGVzdGF0OiBudWxsIH07CiAgICB9CiAgICBjb25zdCB7IHJldCwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9lbnRyeV9mb3JfcGF0aChwYXRoKTsKICAgIGlmIChlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldCwgZmlsZXN0YXQ6IG51bGwgfTsKICAgIH0KICAgIHJldHVybiB7IHJldDogMCwgZmlsZXN0YXQ6IGVudHJ5LnN0YXQoKSB9OwogIH0KICBwYXRoX2xvb2t1cChwYXRoX3N0ciwgZGlyZmxhZ3MpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX3JldCwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX3JldCwgaW5vZGVfb2JqOiBudWxsIH07CiAgICB9CiAgICBjb25zdCB7IHJldCwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9lbnRyeV9mb3JfcGF0aChwYXRoKTsKICAgIGlmIChlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldCwgaW5vZGVfb2JqOiBudWxsIH07CiAgICB9CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGlub2RlX29iajogZW50cnkgfTsKICB9CiAgcGF0aF9vcGVuKGRpcmZsYWdzLCBwYXRoX3N0ciwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogcGF0aF9yZXQsIGZkX29iajogbnVsbCB9OwogICAgfQogICAgbGV0IHsgcmV0LCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgaWYgKHJldCAhPSBFUlJOT19OT0VOVCkgewogICAgICAgIHJldHVybiB7IHJldCwgZmRfb2JqOiBudWxsIH07CiAgICAgIH0KICAgICAgaWYgKChvZmxhZ3MgJiBPRkxBR1NfQ1JFQVQpID09IE9GTEFHU19DUkVBVCkgewogICAgICAgIGNvbnN0IHsgcmV0OiByZXQyLCBlbnRyeTogbmV3X2VudHJ5IH0gPSB0aGlzLmRpci5jcmVhdGVfZW50cnlfZm9yX3BhdGgocGF0aF9zdHIsIChvZmxhZ3MgJiBPRkxBR1NfRElSRUNUT1JZKSA9PSBPRkxBR1NfRElSRUNUT1JZKTsKICAgICAgICBpZiAobmV3X2VudHJ5ID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiB7IHJldDogcmV0MiwgZmRfb2JqOiBudWxsIH07CiAgICAgICAgfQogICAgICAgIGVudHJ5ID0gbmV3X2VudHJ5OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9FTlQsIGZkX29iajogbnVsbCB9OwogICAgICB9CiAgICB9IGVsc2UgaWYgKChvZmxhZ3MgJiBPRkxBR1NfRVhDTCkgPT0gT0ZMQUdTX0VYQ0wpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19FWElTVCwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICBpZiAoKG9mbGFncyAmIE9GTEFHU19ESVJFQ1RPUlkpID09IE9GTEFHU19ESVJFQ1RPUlkgJiYgZW50cnkuc3RhdCgpLmZpbGV0eXBlICE9PSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIGZkX29iajogbnVsbCB9OwogICAgfQogICAgcmV0dXJuIGVudHJ5LnBhdGhfb3BlbihvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmZF9mbGFncyk7CiAgfQogIHBhdGhfY3JlYXRlX2RpcmVjdG9yeShwYXRoKSB7CiAgICByZXR1cm4gdGhpcy5wYXRoX29wZW4oMCwgcGF0aCwgT0ZMQUdTX0NSRUFUIHwgT0ZMQUdTX0RJUkVDVE9SWSwgMG4sIDBuLCAwKS5yZXQ7CiAgfQogIHBhdGhfbGluayhwYXRoX3N0ciwgaW5vZGUsIGFsbG93X2RpcikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4gcGF0aF9yZXQ7CiAgICB9CiAgICBpZiAocGF0aC5pc19kaXIpIHsKICAgICAgcmV0dXJuIEVSUk5PX05PRU5UOwogICAgfQogICAgY29uc3QgeyByZXQ6IHBhcmVudF9yZXQsIHBhcmVudF9lbnRyeSwgZmlsZW5hbWUsIGVudHJ5IH0gPSB0aGlzLmRpci5nZXRfcGFyZW50X2Rpcl9hbmRfZW50cnlfZm9yX3BhdGgocGF0aCwgdHJ1ZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm4gcGFyZW50X3JldDsKICAgIH0KICAgIGlmIChlbnRyeSAhPSBudWxsKSB7CiAgICAgIGNvbnN0IHNvdXJjZV9pc19kaXIgPSBpbm9kZS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfRElSRUNUT1JZOwogICAgICBjb25zdCB0YXJnZXRfaXNfZGlyID0gZW50cnkuc3RhdCgpLmZpbGV0eXBlID09IEZJTEVUWVBFX0RJUkVDVE9SWTsKICAgICAgaWYgKHNvdXJjZV9pc19kaXIgJiYgdGFyZ2V0X2lzX2RpcikgewogICAgICAgIGlmIChhbGxvd19kaXIgJiYgZW50cnkgaW5zdGFuY2VvZiBEaXJlY3RvcnkpIHsKICAgICAgICAgIGlmIChlbnRyeS5jb250ZW50cy5zaXplID09IDApIHsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJldHVybiBFUlJOT19OT1RFTVBUWTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmV0dXJuIEVSUk5PX0VYSVNUOwogICAgICAgIH0KICAgICAgfSBlbHNlIGlmIChzb3VyY2VfaXNfZGlyICYmICF0YXJnZXRfaXNfZGlyKSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX05PVERJUjsKICAgICAgfSBlbHNlIGlmICghc291cmNlX2lzX2RpciAmJiB0YXJnZXRfaXNfZGlyKSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0lTRElSOwogICAgICB9IGVsc2UgaWYgKGlub2RlLnN0YXQoKS5maWxldHlwZSA9PSBGSUxFVFlQRV9SRUdVTEFSX0ZJTEUgJiYgZW50cnkuc3RhdCgpLmZpbGV0eXBlID09IEZJTEVUWVBFX1JFR1VMQVJfRklMRSkgewogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19FWElTVDsKICAgICAgfQogICAgfQogICAgaWYgKCFhbGxvd19kaXIgJiYgaW5vZGUuc3RhdCgpLmZpbGV0eXBlID09IEZJTEVUWVBFX0RJUkVDVE9SWSkgewogICAgICByZXR1cm4gRVJSTk9fUEVSTTsKICAgIH0KICAgIHBhcmVudF9lbnRyeS5jb250ZW50cy5zZXQoZmlsZW5hbWUsIGlub2RlKTsKICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogIH0KICBwYXRoX3VubGluayhwYXRoX3N0cikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhdGhfcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIHRydWUpOwogICAgaWYgKHBhcmVudF9lbnRyeSA9PSBudWxsIHx8IGZpbGVuYW1lID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXJlbnRfcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIGlmIChlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9FTlQsIGlub2RlX29iajogbnVsbCB9OwogICAgfQogICAgcGFyZW50X2VudHJ5LmNvbnRlbnRzLmRlbGV0ZShmaWxlbmFtZSk7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGlub2RlX29iajogZW50cnkgfTsKICB9CiAgcGF0aF91bmxpbmtfZmlsZShwYXRoX3N0cikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4gcGF0aF9yZXQ7CiAgICB9CiAgICBjb25zdCB7IHJldDogcGFyZW50X3JldCwgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9wYXJlbnRfZGlyX2FuZF9lbnRyeV9mb3JfcGF0aChwYXRoLCBmYWxzZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCB8fCBlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXJlbnRfcmV0OwogICAgfQogICAgaWYgKGVudHJ5LnN0YXQoKS5maWxldHlwZSA9PT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgIHJldHVybiBFUlJOT19JU0RJUjsKICAgIH0KICAgIHBhcmVudF9lbnRyeS5jb250ZW50cy5kZWxldGUoZmlsZW5hbWUpOwogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIHBhdGhfcmVtb3ZlX2RpcmVjdG9yeShwYXRoX3N0cikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4gcGF0aF9yZXQ7CiAgICB9CiAgICBjb25zdCB7IHJldDogcGFyZW50X3JldCwgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9wYXJlbnRfZGlyX2FuZF9lbnRyeV9mb3JfcGF0aChwYXRoLCBmYWxzZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCB8fCBlbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXJlbnRfcmV0OwogICAgfQogICAgaWYgKCEoZW50cnkgaW5zdGFuY2VvZiBEaXJlY3RvcnkpIHx8IGVudHJ5LnN0YXQoKS5maWxldHlwZSAhPT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgIHJldHVybiBFUlJOT19OT1RESVI7CiAgICB9CiAgICBpZiAoZW50cnkuY29udGVudHMuc2l6ZSAhPT0gMCkgewogICAgICByZXR1cm4gRVJSTk9fTk9URU1QVFk7CiAgICB9CiAgICBpZiAoIXBhcmVudF9lbnRyeS5jb250ZW50cy5kZWxldGUoZmlsZW5hbWUpKSB7CiAgICAgIHJldHVybiBFUlJOT19OT0VOVDsKICAgIH0KICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogIH0KICBmZF9maWxlc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIGZpbGVzdGF0OiB0aGlzLmRpci5zdGF0KCkgfTsKICB9CiAgZmRfZmlsZXN0YXRfc2V0X3NpemUoc2l6ZSkgewogICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgfQogIGZkX3JlYWQoc2l6ZSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBkYXRhOiBuZXcgVWludDhBcnJheSgpIH07CiAgfQogIGZkX3ByZWFkKHNpemUsIG9mZnNldCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBkYXRhOiBuZXcgVWludDhBcnJheSgpIH07CiAgfQogIGZkX3dyaXRlKGRhdGEpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fQkFERiwgbndyaXR0ZW46IDAgfTsKICB9CiAgZmRfcHdyaXRlKGRhdGEsIG9mZnNldCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBud3JpdHRlbjogMCB9OwogIH0KICBjb25zdHJ1Y3RvcihkaXIpIHsKICAgIHN1cGVyKCk7CiAgICB0aGlzLmRpciA9IGRpcjsKICB9Cn07CnZhciBQcmVvcGVuRGlyZWN0b3J5ID0gY2xhc3MgZXh0ZW5kcyBPcGVuRGlyZWN0b3J5IHsKICBmZF9wcmVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgcHJlc3RhdDogUHJlc3RhdC5kaXIodGhpcy5wcmVzdGF0X25hbWUpIH07CiAgfQogIGNvbnN0cnVjdG9yKG5hbWUsIGNvbnRlbnRzKSB7CiAgICBzdXBlcihuZXcgRGlyZWN0b3J5KGNvbnRlbnRzKSk7CiAgICB0aGlzLnByZXN0YXRfbmFtZSA9IG5hbWU7CiAgfQp9Owp2YXIgRmlsZSA9IGNsYXNzIGV4dGVuZHMgSW5vZGUgewogIHBhdGhfb3BlbihvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmZF9mbGFncykgewogICAgaWYgKHRoaXMucmVhZG9ubHkgJiYgKGZzX3JpZ2h0c19iYXNlICYgQmlnSW50KFJJR0hUU19GRF9XUklURSkpID09IEJpZ0ludChSSUdIVFNfRkRfV1JJVEUpKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fUEVSTSwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICBpZiAoKG9mbGFncyAmIE9GTEFHU19UUlVOQykgPT0gT0ZMQUdTX1RSVU5DKSB7CiAgICAgIGlmICh0aGlzLnJlYWRvbmx5KQogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fUEVSTSwgZmRfb2JqOiBudWxsIH07CiAgICAgIHRoaXMuZGF0YSA9IG5ldyBVaW50OEFycmF5KFtdKTsKICAgIH0KICAgIGNvbnN0IGZpbGUgPSBuZXcgT3BlbkZpbGUodGhpcyk7CiAgICBpZiAoZmRfZmxhZ3MgJiBGREZMQUdTX0FQUEVORCkKICAgICAgZmlsZS5mZF9zZWVrKDBuLCBXSEVOQ0VfRU5EKTsKICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZmRfb2JqOiBmaWxlIH07CiAgfQogIGdldCBzaXplKCkgewogICAgcmV0dXJuIEJpZ0ludCh0aGlzLmRhdGEuYnl0ZUxlbmd0aCk7CiAgfQogIHN0YXQoKSB7CiAgICByZXR1cm4gbmV3IEZpbGVzdGF0KEZJTEVUWVBFX1JFR1VMQVJfRklMRSwgdGhpcy5zaXplKTsKICB9CiAgY29uc3RydWN0b3IoZGF0YSwgb3B0aW9ucykgewogICAgc3VwZXIoKTsKICAgIHRoaXMuZGF0YSA9IG5ldyBVaW50OEFycmF5KGRhdGEpOwogICAgdGhpcy5yZWFkb25seSA9ICEhb3B0aW9ucz8ucmVhZG9ubHk7CiAgfQp9Owp2YXIgUGF0aCA9IGNsYXNzIFBhdGgyIHsKICBzdGF0aWMgZnJvbShwYXRoKSB7CiAgICBjb25zdCBzZWxmID0gbmV3IFBhdGgyKCk7CiAgICBzZWxmLmlzX2RpciA9IHBhdGguZW5kc1dpdGgoIi8iKTsKICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoIi8iKSkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVENBUEFCTEUsIHBhdGg6IG51bGwgfTsKICAgIH0KICAgIGlmIChwYXRoLmluY2x1ZGVzKCJcMCIpKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fSU5WQUwsIHBhdGg6IG51bGwgfTsKICAgIH0KICAgIGZvciAoY29uc3QgY29tcG9uZW50IG9mIHBhdGguc3BsaXQoIi8iKSkgewogICAgICBpZiAoY29tcG9uZW50ID09PSAiIiB8fCBjb21wb25lbnQgPT09ICIuIikgewogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGlmIChjb21wb25lbnQgPT09ICIuLiIpIHsKICAgICAgICBpZiAoc2VsZi5wYXJ0cy5wb3AoKSA9PSB2b2lkIDApIHsKICAgICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UQ0FQQUJMRSwgcGF0aDogbnVsbCB9OwogICAgICAgIH0KICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICBzZWxmLnBhcnRzLnB1c2goY29tcG9uZW50KTsKICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgcGF0aDogc2VsZiB9OwogIH0KICB0b19wYXRoX3N0cmluZygpIHsKICAgIGxldCBzID0gdGhpcy5wYXJ0cy5qb2luKCIvIik7CiAgICBpZiAodGhpcy5pc19kaXIpIHsKICAgICAgcyArPSAiLyI7CiAgICB9CiAgICByZXR1cm4gczsKICB9CiAgY29uc3RydWN0b3IoKSB7CiAgICB0aGlzLnBhcnRzID0gW107CiAgICB0aGlzLmlzX2RpciA9IGZhbHNlOwogIH0KfTsKdmFyIERpcmVjdG9yeSA9IGNsYXNzIGV4dGVuZHMgSW5vZGUgewogIHBhdGhfb3BlbihvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmZF9mbGFncykgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBmZF9vYmo6IG5ldyBPcGVuRGlyZWN0b3J5KHRoaXMpIH07CiAgfQogIHN0YXQoKSB7CiAgICByZXR1cm4gbmV3IEZpbGVzdGF0KEZJTEVUWVBFX0RJUkVDVE9SWSwgMG4pOwogIH0KICBnZXRfZW50cnlfZm9yX3BhdGgocGF0aCkgewogICAgbGV0IGVudHJ5ID0gdGhpczsKICAgIGZvciAoY29uc3QgY29tcG9uZW50IG9mIHBhdGgucGFydHMpIHsKICAgICAgaWYgKCEoZW50cnkgaW5zdGFuY2VvZiBEaXJlY3RvcnkpKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIGVudHJ5OiBudWxsIH07CiAgICAgIH0KICAgICAgY29uc3QgY2hpbGQgPSBlbnRyeS5jb250ZW50cy5nZXQoY29tcG9uZW50KTsKICAgICAgaWYgKGNoaWxkICE9PSB2b2lkIDApIHsKICAgICAgICBlbnRyeSA9IGNoaWxkOwogICAgICB9IGVsc2UgewogICAgICAgIGRlYnVnLmxvZyhjb21wb25lbnQpOwogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9FTlQsIGVudHJ5OiBudWxsIH07CiAgICAgIH0KICAgIH0KICAgIGlmIChwYXRoLmlzX2RpcikgewogICAgICBpZiAoZW50cnkuc3RhdCgpLmZpbGV0eXBlICE9IEZJTEVUWVBFX0RJUkVDVE9SWSkgewogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9URElSLCBlbnRyeTogbnVsbCB9OwogICAgICB9CiAgICB9CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGVudHJ5IH07CiAgfQogIGdldF9wYXJlbnRfZGlyX2FuZF9lbnRyeV9mb3JfcGF0aChwYXRoLCBhbGxvd191bmRlZmluZWQpIHsKICAgIGNvbnN0IGZpbGVuYW1lID0gcGF0aC5wYXJ0cy5wb3AoKTsKICAgIGlmIChmaWxlbmFtZSA9PT0gdm9pZCAwKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fSU5WQUwsIHBhcmVudF9lbnRyeTogbnVsbCwgZmlsZW5hbWU6IG51bGwsIGVudHJ5OiBudWxsIH07CiAgICB9CiAgICBjb25zdCB7IHJldDogZW50cnlfcmV0LCBlbnRyeTogcGFyZW50X2VudHJ5IH0gPSB0aGlzLmdldF9lbnRyeV9mb3JfcGF0aChwYXRoKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IGVudHJ5X3JldCwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGlmICghKHBhcmVudF9lbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIHBhcmVudF9lbnRyeTogbnVsbCwgZmlsZW5hbWU6IG51bGwsIGVudHJ5OiBudWxsIH07CiAgICB9CiAgICBjb25zdCBlbnRyeSA9IHBhcmVudF9lbnRyeS5jb250ZW50cy5nZXQoZmlsZW5hbWUpOwogICAgaWYgKGVudHJ5ID09PSB2b2lkIDApIHsKICAgICAgaWYgKCFhbGxvd191bmRlZmluZWQpIHsKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PRU5ULCBwYXJlbnRfZW50cnk6IG51bGwsIGZpbGVuYW1lOiBudWxsLCBlbnRyeTogbnVsbCB9OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgfQogICAgaWYgKHBhdGguaXNfZGlyKSB7CiAgICAgIGlmIChlbnRyeS5zdGF0KCkuZmlsZXR5cGUgIT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIHBhcmVudF9lbnRyeTogbnVsbCwgZmlsZW5hbWU6IG51bGwsIGVudHJ5OiBudWxsIH07CiAgICAgIH0KICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfTsKICB9CiAgY3JlYXRlX2VudHJ5X2Zvcl9wYXRoKHBhdGhfc3RyLCBpc19kaXIpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX3JldCwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX3JldCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGxldCB7IHJldDogcGFyZW50X3JldCwgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfSA9IHRoaXMuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIHRydWUpOwogICAgaWYgKHBhcmVudF9lbnRyeSA9PSBudWxsIHx8IGZpbGVuYW1lID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXJlbnRfcmV0LCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgaWYgKGVudHJ5ICE9IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19FWElTVCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGRlYnVnLmxvZygiY3JlYXRlIiwgcGF0aCk7CiAgICBsZXQgbmV3X2NoaWxkOwogICAgaWYgKCFpc19kaXIpIHsKICAgICAgbmV3X2NoaWxkID0gbmV3IEZpbGUobmV3IEFycmF5QnVmZmVyKDApKTsKICAgIH0gZWxzZSB7CiAgICAgIG5ld19jaGlsZCA9IG5ldyBEaXJlY3RvcnkoLyogQF9fUFVSRV9fICovIG5ldyBNYXAoKSk7CiAgICB9CiAgICBwYXJlbnRfZW50cnkuY29udGVudHMuc2V0KGZpbGVuYW1lLCBuZXdfY2hpbGQpOwogICAgZW50cnkgPSBuZXdfY2hpbGQ7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGVudHJ5IH07CiAgfQogIGNvbnN0cnVjdG9yKGNvbnRlbnRzKSB7CiAgICBzdXBlcigpOwogICAgaWYgKGNvbnRlbnRzIGluc3RhbmNlb2YgQXJyYXkpIHsKICAgICAgdGhpcy5jb250ZW50cyA9IG5ldyBNYXAoY29udGVudHMpOwogICAgfSBlbHNlIHsKICAgICAgdGhpcy5jb250ZW50cyA9IGNvbnRlbnRzOwogICAgfQogIH0KfTsKdmFyIENvbnNvbGVTdGRvdXQgPSBjbGFzcyBleHRlbmRzIEZkIHsKICBmZF9maWxlc3RhdF9nZXQoKSB7CiAgICBjb25zdCBmaWxlc3RhdCA9IG5ldyBGaWxlc3RhdChGSUxFVFlQRV9DSEFSQUNURVJfREVWSUNFLCBCaWdJbnQoMCkpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBmaWxlc3RhdCB9OwogIH0KICBmZF9mZHN0YXRfZ2V0KCkgewogICAgY29uc3QgZmRzdGF0ID0gbmV3IEZkc3RhdChGSUxFVFlQRV9DSEFSQUNURVJfREVWSUNFLCAwKTsKICAgIGZkc3RhdC5mc19yaWdodHNfYmFzZSA9IEJpZ0ludChSSUdIVFNfRkRfV1JJVEUpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBmZHN0YXQgfTsKICB9CiAgZmRfd3JpdGUoZGF0YSkgewogICAgdGhpcy53cml0ZShkYXRhKTsKICAgIHJldHVybiB7IHJldDogMCwgbndyaXR0ZW46IGRhdGEuYnl0ZUxlbmd0aCB9OwogIH0KICBzdGF0aWMgbGluZUJ1ZmZlcmVkKHdyaXRlKSB7CiAgICBjb25zdCBkZWMgPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IiwgeyBmYXRhbDogZmFsc2UgfSk7CiAgICBsZXQgbGluZV9idWYgPSAiIjsKICAgIHJldHVybiBuZXcgQ29uc29sZVN0ZG91dCgoYnVmZmVyKSA9PiB7CiAgICAgIGxpbmVfYnVmICs9IGRlYy5kZWNvZGUoYnVmZmVyLCB7IHN0cmVhbTogdHJ1ZSB9KTsKICAgICAgY29uc3QgbGluZXMgPSBsaW5lX2J1Zi5zcGxpdCgiXG4iKTsKICAgICAgZm9yIChjb25zdCBbaSwgbGluZV0gb2YgbGluZXMuZW50cmllcygpKSB7CiAgICAgICAgaWYgKGkgPCBsaW5lcy5sZW5ndGggLSAxKSB7CiAgICAgICAgICB3cml0ZShsaW5lKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgbGluZV9idWYgPSBsaW5lOwogICAgICAgIH0KICAgICAgfQogICAgfSk7CiAgfQogIGNvbnN0cnVjdG9yKHdyaXRlKSB7CiAgICBzdXBlcigpOwogICAgdGhpcy53cml0ZSA9IHdyaXRlOwogIH0KfTsKCi8vIG5vZGVfbW9kdWxlcy93YXNtLWltcG9ydHMtcGFyc2VyL2luZGV4LmpzCmZ1bmN0aW9uIHBhcnNlSW1wb3J0cyhtb2R1bGVCeXRlcykgewogIGlmIChtb2R1bGVCeXRlcyBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHsKICB9IGVsc2UgaWYgKG1vZHVsZUJ5dGVzIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHsKICAgIG1vZHVsZUJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkobW9kdWxlQnl0ZXMpOwogIH0gZWxzZSBpZiAobW9kdWxlQnl0ZXMuYnVmZmVyIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHsKICAgIG1vZHVsZUJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkobW9kdWxlQnl0ZXMuYnVmZmVyKTsKICB9IGVsc2UgewogICAgdGhyb3cgbmV3IEVycm9yKCJBcmd1bWVudCBtdXN0IGJlIGEgYnVmZmVyIHNvdXJjZSwgbGlrZSBVaW50OEFycmF5IG9yIEFycmF5QnVmZmVyIik7CiAgfQogIGNvbnN0IHBhcnNlU3RhdGUgPSBuZXcgUGFyc2VTdGF0ZShtb2R1bGVCeXRlcyk7CiAgcGFyc2VNYWdpY051bWJlcihwYXJzZVN0YXRlKTsKICBwYXJzZVZlcnNpb24ocGFyc2VTdGF0ZSk7CiAgY29uc3QgdHlwZXMgPSBbXTsKICBjb25zdCBpbXBvcnRzID0gW107CiAgd2hpbGUgKHBhcnNlU3RhdGUuaGFzTW9yZUJ5dGVzKCkpIHsKICAgIGNvbnN0IHNlY3Rpb25JZCA9IHBhcnNlU3RhdGUucmVhZEJ5dGUoKTsKICAgIGNvbnN0IHNlY3Rpb25TaXplID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgIHN3aXRjaCAoc2VjdGlvbklkKSB7CiAgICAgIGNhc2UgMTogewogICAgICAgIGNvbnN0IHR5cGVDb3VudCA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0eXBlQ291bnQ7IGkrKykgewogICAgICAgICAgdHlwZXMucHVzaChwYXJzZUZ1bmN0aW9uVHlwZShwYXJzZVN0YXRlKSk7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgICB9CiAgICAgIGNhc2UgMjogewogICAgICAgIGNvbnN0IGltcG9ydENvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGltcG9ydENvdW50OyBpKyspIHsKICAgICAgICAgIGNvbnN0IG1vZHVsZSA9IHBhcnNlU3RhdGUucmVhZE5hbWUoKTsKICAgICAgICAgIGNvbnN0IG5hbWUgPSBwYXJzZVN0YXRlLnJlYWROYW1lKCk7CiAgICAgICAgICBjb25zdCB0eXBlID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogICAgICAgICAgc3dpdGNoICh0eXBlKSB7CiAgICAgICAgICAgIGNhc2UgMDoKICAgICAgICAgICAgICBjb25zdCBpbmRleCA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICAgICAgICAgICAgaW1wb3J0cy5wdXNoKHsgbW9kdWxlLCBuYW1lLCBraW5kOiAiZnVuY3Rpb24iLCB0eXBlOiB0eXBlc1tpbmRleF0gfSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgMToKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJ0YWJsZSIsIHR5cGU6IHBhcnNlVGFibGVUeXBlKHBhcnNlU3RhdGUpIH0pOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgaW1wb3J0cy5wdXNoKHsgbW9kdWxlLCBuYW1lLCBraW5kOiAibWVtb3J5IiwgdHlwZTogcGFyc2VMaW1pdHMocGFyc2VTdGF0ZSkgfSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgMzoKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJnbG9iYWwiLCB0eXBlOiBwYXJzZUdsb2JhbFR5cGUocGFyc2VTdGF0ZSkgfSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIGltcG9ydCBkZXNjcmlwdG9yIHR5cGUgJHt0eXBlfWApOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gaW1wb3J0czsKICAgICAgfQogICAgICBkZWZhdWx0OiB7CiAgICAgICAgcGFyc2VTdGF0ZS5za2lwQnl0ZXMoc2VjdGlvblNpemUpOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgfQogIHJldHVybiBbXTsKfQp2YXIgUGFyc2VTdGF0ZSA9IGNsYXNzIHsKICBjb25zdHJ1Y3Rvcihtb2R1bGVCeXRlcykgewogICAgdGhpcy5tb2R1bGVCeXRlcyA9IG1vZHVsZUJ5dGVzOwogICAgdGhpcy5vZmZzZXQgPSAwOwogICAgdGhpcy50ZXh0RGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKTsKICB9CiAgaGFzTW9yZUJ5dGVzKCkgewogICAgcmV0dXJuIHRoaXMub2Zmc2V0IDwgdGhpcy5tb2R1bGVCeXRlcy5sZW5ndGg7CiAgfQogIHJlYWRCeXRlKCkgewogICAgcmV0dXJuIHRoaXMubW9kdWxlQnl0ZXNbdGhpcy5vZmZzZXQrK107CiAgfQogIHNraXBCeXRlcyhjb3VudCkgewogICAgdGhpcy5vZmZzZXQgKz0gY291bnQ7CiAgfQogIHJlYWRVbnNpZ25lZExFQjEyOCgpIHsKICAgIGxldCByZXN1bHQgPSAwOwogICAgbGV0IHNoaWZ0ID0gMDsKICAgIGxldCBieXRlOwogICAgZG8gewogICAgICBieXRlID0gdGhpcy5yZWFkQnl0ZSgpOwogICAgICByZXN1bHQgfD0gKGJ5dGUgJiAxMjcpIDw8IHNoaWZ0OwogICAgICBzaGlmdCArPSA3OwogICAgfSB3aGlsZSAoYnl0ZSAmIDEyOCk7CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICByZWFkTmFtZSgpIHsKICAgIGNvbnN0IG5hbWVMZW5ndGggPSB0aGlzLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgY29uc3QgbmFtZUJ5dGVzID0gdGhpcy5tb2R1bGVCeXRlcy5zbGljZSh0aGlzLm9mZnNldCwgdGhpcy5vZmZzZXQgKyBuYW1lTGVuZ3RoKTsKICAgIGNvbnN0IG5hbWUgPSB0aGlzLnRleHREZWNvZGVyLmRlY29kZShuYW1lQnl0ZXMpOwogICAgdGhpcy5vZmZzZXQgKz0gbmFtZUxlbmd0aDsKICAgIHJldHVybiBuYW1lOwogIH0KICBhc3NlcnRCeXRlcyhleHBlY3RlZCkgewogICAgY29uc3QgYmFzZU9mZnNldCA9IHRoaXMub2Zmc2V0OwogICAgY29uc3QgZXhwZWN0ZWRMZW5ndGggPSBleHBlY3RlZC5sZW5ndGg7CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGV4cGVjdGVkTGVuZ3RoOyBpKyspIHsKICAgICAgaWYgKHRoaXMubW9kdWxlQnl0ZXNbYmFzZU9mZnNldCArIGldICE9PSBleHBlY3RlZFtpXSkgewogICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgJHtleHBlY3RlZH0gYXQgb2Zmc2V0ICR7YmFzZU9mZnNldH1gKTsKICAgICAgfQogICAgfQogICAgdGhpcy5vZmZzZXQgKz0gZXhwZWN0ZWRMZW5ndGg7CiAgfQp9OwpmdW5jdGlvbiBwYXJzZU1hZ2ljTnVtYmVyKHBhcnNlU3RhdGUpIHsKICBjb25zdCBleHBlY3RlZCA9IFswLCA5NywgMTE1LCAxMDldOwogIHBhcnNlU3RhdGUuYXNzZXJ0Qnl0ZXMoZXhwZWN0ZWQpOwp9CmZ1bmN0aW9uIHBhcnNlVmVyc2lvbihwYXJzZVN0YXRlKSB7CiAgY29uc3QgZXhwZWN0ZWQgPSBbMSwgMCwgMCwgMF07CiAgcGFyc2VTdGF0ZS5hc3NlcnRCeXRlcyhleHBlY3RlZCk7Cn0KZnVuY3Rpb24gcGFyc2VUYWJsZVR5cGUocGFyc2VTdGF0ZSkgewogIGNvbnN0IGVsZW1lbnRUeXBlID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogIGxldCBlbGVtZW50OwogIHN3aXRjaCAoZWxlbWVudFR5cGUpIHsKICAgIGNhc2UgMTEyOgogICAgICBlbGVtZW50ID0gImZ1bmNyZWYiOwogICAgICBicmVhazsKICAgIGNhc2UgMTExOgogICAgICBlbGVtZW50ID0gImV4dGVybnJlZiI7CiAgICAgIGJyZWFrOwogICAgZGVmYXVsdDoKICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIHRhYmxlIGVsZW1lbnQgdHlwZSAke2VsZW1lbnRUeXBlfWApOwogIH0KICBjb25zdCB7IG1pbmltdW0sIG1heGltdW0gfSA9IHBhcnNlTGltaXRzKHBhcnNlU3RhdGUpOwogIGlmIChtYXhpbXVtKSB7CiAgICByZXR1cm4geyBlbGVtZW50LCBtaW5pbXVtLCBtYXhpbXVtIH07CiAgfSBlbHNlIHsKICAgIHJldHVybiB7IGVsZW1lbnQsIG1pbmltdW0gfTsKICB9Cn0KZnVuY3Rpb24gcGFyc2VMaW1pdHMocGFyc2VTdGF0ZSkgewogIGNvbnN0IGZsYWdzID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogIGNvbnN0IG1pbmltdW0gPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogIGNvbnN0IGhhc01heGltdW0gPSBmbGFncyAmIDE7CiAgY29uc3Qgc2hhcmVkID0gKGZsYWdzICYgMikgIT09IDA7CiAgY29uc3QgaXNNZW1vcnk2NCA9IChmbGFncyAmIDQpICE9PSAwOwogIGNvbnN0IGluZGV4ID0gaXNNZW1vcnk2NCA/ICJpNjQiIDogImkzMiI7CiAgaWYgKGhhc01heGltdW0pIHsKICAgIGNvbnN0IG1heGltdW0gPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgcmV0dXJuIHsgbWluaW11bSwgc2hhcmVkLCBpbmRleCwgbWF4aW11bSB9OwogIH0gZWxzZSB7CiAgICByZXR1cm4geyBtaW5pbXVtLCBzaGFyZWQsIGluZGV4IH07CiAgfQp9CmZ1bmN0aW9uIHBhcnNlR2xvYmFsVHlwZShwYXJzZVN0YXRlKSB7CiAgY29uc3QgdmFsdWUgPSBwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKTsKICBjb25zdCBtdXRhYmxlID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpID09PSAxOwogIHJldHVybiB7IHZhbHVlLCBtdXRhYmxlIH07Cn0KZnVuY3Rpb24gcGFyc2VWYWx1ZVR5cGUocGFyc2VTdGF0ZSkgewogIGNvbnN0IHR5cGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgc3dpdGNoICh0eXBlKSB7CiAgICBjYXNlIDEyNzoKICAgICAgcmV0dXJuICJpMzIiOwogICAgY2FzZSAxMjY6CiAgICAgIHJldHVybiAiaTY0IjsKICAgIGNhc2UgMTI1OgogICAgICByZXR1cm4gImYzMiI7CiAgICBjYXNlIDEyNDoKICAgICAgcmV0dXJuICJmNjQiOwogICAgY2FzZSAxMTI6CiAgICAgIHJldHVybiAiZnVuY3JlZiI7CiAgICBjYXNlIDExMToKICAgICAgcmV0dXJuICJleHRlcm5yZWYiOwogICAgY2FzZSAxMjM6CiAgICAgIHJldHVybiAidjEyOCI7CiAgICBkZWZhdWx0OgogICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gdmFsdWUgdHlwZSAke3R5cGV9YCk7CiAgfQp9CmZ1bmN0aW9uIHBhcnNlRnVuY3Rpb25UeXBlKHBhcnNlU3RhdGUpIHsKICBjb25zdCBmb3JtID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogIGlmIChmb3JtICE9PSA5NikgewogICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBmdW5jdGlvbiB0eXBlIGZvcm0gMHg2MCwgZ290ICR7Zm9ybX1gKTsKICB9CiAgY29uc3QgcGFyYW1ldGVycyA9IFtdOwogIGNvbnN0IHBhcmFtZXRlckNvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcmFtZXRlckNvdW50OyBpKyspIHsKICAgIHBhcmFtZXRlcnMucHVzaChwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKSk7CiAgfQogIGNvbnN0IHJlc3VsdHMgPSBbXTsKICBjb25zdCByZXN1bHRDb3VudCA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXN1bHRDb3VudDsgaSsrKSB7CiAgICByZXN1bHRzLnB1c2gocGFyc2VWYWx1ZVR5cGUocGFyc2VTdGF0ZSkpOwogIH0KICByZXR1cm4geyBwYXJhbWV0ZXJzLCByZXN1bHRzIH07Cn0KCi8vIG5vZGVfbW9kdWxlcy93YXNtLWltcG9ydHMtcGFyc2VyL3BvbHlmaWxsLmpzCnZhciBoYXNXYXNtVHlwZVJlZmxlY3Rpb25TdXBwb3J0ID0gKCgpID0+IHsKICBjb25zdCBtb2R1bGVCeXRlcyA9IG5ldyBVaW50OEFycmF5KFsKICAgIDAsCiAgICA5NywKICAgIDExNSwKICAgIDEwOSwKICAgIDEsCiAgICAwLAogICAgMCwKICAgIDAsCiAgICAyLAogICAgNiwKICAgIDEsCiAgICAwLAogICAgMCwKICAgIDIsCiAgICAwLAogICAgMQogIF0pOwogIGNvbnN0IG1vZHVsZSA9IG5ldyBXZWJBc3NlbWJseS5Nb2R1bGUobW9kdWxlQnl0ZXMpOwogIGNvbnN0IGltcG9ydHMgPSBXZWJBc3NlbWJseS5Nb2R1bGUuaW1wb3J0cyhtb2R1bGUpOwogIGNvbnN0IG1lbW9yeUltcG9ydCA9IGltcG9ydHNbMF07CiAgcmV0dXJuIHR5cGVvZiBtZW1vcnlJbXBvcnQudHlwZSA9PT0gIm9iamVjdCI7Cn0pKCk7CmZ1bmN0aW9uIHBvbHlmaWxsKFdlYkFzc2VtYmx5MykgewogIGlmIChoYXNXYXNtVHlwZVJlZmxlY3Rpb25TdXBwb3J0KSB7CiAgICByZXR1cm4gV2ViQXNzZW1ibHkzOwogIH0KICBjb25zdCBuZXdXZWJBc3NlbWJseSA9IHt9OwogIGZvciAoY29uc3Qga2V5IGluIE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKFdlYkFzc2VtYmx5MykpIHsKICAgIG5ld1dlYkFzc2VtYmx5W2tleV0gPSBXZWJBc3NlbWJseTNba2V5XTsKICB9CiAgY29uc3QgcG9seWZpbGxlZEltcG9ydHNTeW1ib2wgPSBTeW1ib2woInBvbHlmaWxsZWRJbXBvcnRzU3ltYm9sIik7CiAgY29uc3QgYXNzaWduSW1wb3J0cyA9IChtb2R1bGUsIHNvdXJjZUJ5dGVzKSA9PiB7CiAgICBtb2R1bGVbcG9seWZpbGxlZEltcG9ydHNTeW1ib2xdID0gcGFyc2VJbXBvcnRzKHNvdXJjZUJ5dGVzKTsKICB9OwogIGNvbnN0IG5ld01vZHVsZSA9IG5ld1dlYkFzc2VtYmx5Lk1vZHVsZSA9IGZ1bmN0aW9uKGJ5dGVzKSB7CiAgICBjb25zdCBtb2R1bGUgPSBuZXcgV2ViQXNzZW1ibHkzLk1vZHVsZShieXRlcyk7CiAgICBhc3NpZ25JbXBvcnRzKG1vZHVsZSwgYnl0ZXMpOwogICAgT2JqZWN0LnNldFByb3RvdHlwZU9mKG1vZHVsZSwgbmV3TW9kdWxlLnByb3RvdHlwZSk7CiAgICByZXR1cm4gbW9kdWxlOwogIH07CiAgT2JqZWN0LnNldFByb3RvdHlwZU9mKG5ld01vZHVsZS5wcm90b3R5cGUsIFdlYkFzc2VtYmx5My5Nb2R1bGUucHJvdG90eXBlKTsKICBuZXdXZWJBc3NlbWJseS5jb21waWxlID0gYXN5bmMgKHNvdXJjZSkgPT4gewogICAgY29uc3QgbW9kdWxlID0gYXdhaXQgV2ViQXNzZW1ibHkzLmNvbXBpbGUoc291cmNlKTsKICAgIGFzc2lnbkltcG9ydHMobW9kdWxlLCBzb3VyY2UpOwogICAgcmV0dXJuIG1vZHVsZTsKICB9OwogIGlmIChXZWJBc3NlbWJseTMuY29tcGlsZVN0cmVhbWluZykgewogICAgbmV3V2ViQXNzZW1ibHkuY29tcGlsZVN0cmVhbWluZyA9IGFzeW5jIChzb3VyY2UpID0+IHsKICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBzb3VyY2U7CiAgICAgIGNvbnN0IGNsb25lID0gcmVzcG9uc2UuY2xvbmUoKTsKICAgICAgY29uc3QgbW9kdWxlID0gYXdhaXQgV2ViQXNzZW1ibHkzLmNvbXBpbGVTdHJlYW1pbmcocmVzcG9uc2UpOwogICAgICBhc3NpZ25JbXBvcnRzKG1vZHVsZSwgbmV3IFVpbnQ4QXJyYXkoYXdhaXQgY2xvbmUuYXJyYXlCdWZmZXIoKSkpOwogICAgICByZXR1cm4gbW9kdWxlOwogICAgfTsKICB9CiAgbmV3TW9kdWxlLmltcG9ydHMgPSAobW9kdWxlKSA9PiB7CiAgICBjb25zdCBwYXJzZWRJbXBvcnRzID0gbW9kdWxlW3BvbHlmaWxsZWRJbXBvcnRzU3ltYm9sXTsKICAgIGlmICghcGFyc2VkSW1wb3J0cykgewogICAgICByZXR1cm4gV2ViQXNzZW1ibHkzLk1vZHVsZS5pbXBvcnRzKG1vZHVsZSk7CiAgICB9CiAgICByZXR1cm4gcGFyc2VkSW1wb3J0czsKICB9OwogIHJldHVybiBuZXdXZWJBc3NlbWJseTsKfQoKLy8gZW50cnlwb2ludC9pbnRyaW5zaWNzLnRzCnZhciBXZWJBc3NlbWJseTIgPSBwb2x5ZmlsbChnbG9iYWxUaGlzLldlYkFzc2VtYmx5KTsKdmFyIExpbmVEZWNvZGVyID0gY2xhc3MgewogIGNvbnN0cnVjdG9yKG9uTGluZSkgewogICAgdGhpcy5kZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIsIHsgZmF0YWw6IGZhbHNlIH0pOwogICAgdGhpcy5idWZmZXIgPSAiIjsKICAgIHRoaXMub25MaW5lID0gb25MaW5lOwogIH0KICBkZWNvZGVyOwogIGJ1ZmZlcjsKICBvbkxpbmU7CiAgc2VuZChjaHVuaykgewogICAgdGhpcy5idWZmZXIgKz0gdGhpcy5kZWNvZGVyLmRlY29kZShjaHVuaywgeyBzdHJlYW06IHRydWUgfSk7CiAgICBjb25zdCBsaW5lcyA9IHRoaXMuYnVmZmVyLnNwbGl0KCJcbiIpOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGggLSAxOyBpKyspIHsKICAgICAgdGhpcy5vbkxpbmUobGluZXNbaV0pOwogICAgfQogICAgdGhpcy5idWZmZXIgPSBsaW5lc1tsaW5lcy5sZW5ndGggLSAxXTsKICB9Cn07CmFzeW5jIGZ1bmN0aW9uIGluc3RhbnRpYXRlKHJhd09wdGlvbnMsIGV4dHJhV2FzbUltcG9ydHMpIHsKICBjb25zdCBvcHRpb25zID0gZGVmYXVsdEluc3RhbnRpYXRpb25PcHRpb25zKHJhd09wdGlvbnMpOwogIGxldCBzd2lmdCA9IG9wdGlvbnMuc3dpZnQ7CiAgaWYgKCFzd2lmdCAmJiBvcHRpb25zLlN3aWZ0UnVudGltZSkgewogICAgbGV0IHNoYXJlZE1lbW9yeSA9IGZhbHNlOwogICAgZm9yIChjb25zdCBpbXBvcnRFbnRyeSBvZiBXZWJBc3NlbWJseTIuTW9kdWxlLmltcG9ydHMob3B0aW9ucy5tb2R1bGUpKSB7CiAgICAgIGlmIChpbXBvcnRFbnRyeS5tb2R1bGUgPT09ICJlbnYiICYmIGltcG9ydEVudHJ5Lm5hbWUgPT09ICJtZW1vcnkiICYmIGltcG9ydEVudHJ5LmtpbmQgPT09ICJtZW1vcnkiKSB7CiAgICAgICAgc2hhcmVkTWVtb3J5ID0gdHJ1ZTsKICAgICAgICBicmVhazsKICAgICAgfQogICAgfQogICAgc3dpZnQgPSBuZXcgb3B0aW9ucy5Td2lmdFJ1bnRpbWUoeyBzaGFyZWRNZW1vcnkgfSk7CiAgfQogIGxldCBzdGRvdXRMaW5lID0gdm9pZCAwOwogIGlmIChvcHRpb25zLm9uU3Rkb3V0TGluZSAhPSBudWxsKSB7CiAgICBzdGRvdXRMaW5lID0gbmV3IExpbmVEZWNvZGVyKG9wdGlvbnMub25TdGRvdXRMaW5lKTsKICB9CiAgY29uc3Qgc3Rkb3V0ID0gbmV3IENvbnNvbGVTdGRvdXQoKGNodW5rKSA9PiB7CiAgICBvcHRpb25zLm9uU3Rkb3V0Py5jYWxsKHZvaWQgMCwgY2h1bmspOwogICAgc3Rkb3V0TGluZT8uc2VuZChjaHVuayk7CiAgfSk7CiAgbGV0IHN0ZGVyckxpbmUgPSB2b2lkIDA7CiAgaWYgKG9wdGlvbnMub25TdGRlcnJMaW5lICE9IG51bGwpIHsKICAgIHN0ZGVyckxpbmUgPSBuZXcgTGluZURlY29kZXIob3B0aW9ucy5vblN0ZGVyckxpbmUpOwogIH0KICBjb25zdCBzdGRlcnIgPSBuZXcgQ29uc29sZVN0ZG91dCgoY2h1bmspID0+IHsKICAgIG9wdGlvbnMub25TdGRlcnI/LmNhbGwodm9pZCAwLCBjaHVuayk7CiAgICBzdGRlcnJMaW5lPy5zZW5kKGNodW5rKTsKICB9KTsKICBjb25zdCBhcmdzID0gb3B0aW9ucy5hcmdzIHx8IFtdOwogIGNvbnN0IHJvb3RGcyA9IG9wdGlvbnMucm9vdEZzIHx8IC8qIEBfX1BVUkVfXyAqLyBuZXcgTWFwKCk7CiAgY29uc3QgZmRzID0gWwogICAgbmV3IE9wZW5GaWxlKG5ldyBGaWxlKFtdKSksCiAgICBzdGRvdXQsCiAgICBzdGRlcnIsCiAgICBuZXcgUHJlb3BlbkRpcmVjdG9yeSgiLyIsIHJvb3RGcykKICBdOwogIGNvbnN0IGVudnMgPSBvcHRpb25zLmVudiA/IE9iamVjdC5lbnRyaWVzKG9wdGlvbnMuZW52KS5tYXAoKFtrZXksIHZhbHVlXSkgPT4gYCR7a2V5fT0ke3ZhbHVlfWApIDogW107CiAgY29uc3Qgd2FzaSA9IG5ldyBXQVNJKGFyZ3MsIGVudnMsIGZkcywgewogICAgZGVidWc6IGZhbHNlCiAgfSk7CiAgY29uc3QgY3JlYXRlV2FzbUltcG9ydE9iamVjdCA9IChleHRyYVdhc21JbXBvcnRzMiwgbW9kdWxlKSA9PiB7CiAgICBjb25zdCBpbXBvcnRPYmplY3QyID0gewogICAgICB3YXNpX3NuYXBzaG90X3ByZXZpZXcxOiB3YXNpLndhc2lJbXBvcnQKICAgIH07CiAgICBpZiAoc3dpZnQpIHsKICAgICAgaW1wb3J0T2JqZWN0Mi5qYXZhc2NyaXB0X2tpdCA9IHN3aWZ0Lndhc21JbXBvcnRzOwogICAgfQogICAgaWYgKGV4dHJhV2FzbUltcG9ydHMyKSB7CiAgICAgIGZvciAoY29uc3QgbW9kdWxlTmFtZSBpbiBleHRyYVdhc21JbXBvcnRzMikgewogICAgICAgIGlmICghaW1wb3J0T2JqZWN0Mlttb2R1bGVOYW1lXSkgewogICAgICAgICAgaW1wb3J0T2JqZWN0Mlttb2R1bGVOYW1lXSA9IHt9OwogICAgICAgIH0KICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IGluIGV4dHJhV2FzbUltcG9ydHMyW21vZHVsZU5hbWVdKSB7CiAgICAgICAgICBpbXBvcnRPYmplY3QyW21vZHVsZU5hbWVdW2VudHJ5XSA9IGV4dHJhV2FzbUltcG9ydHMyW21vZHVsZU5hbWVdW2VudHJ5XTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGZvciAoY29uc3QgX2ltcG9ydEVudHJ5IG9mIFdlYkFzc2VtYmx5Mi5Nb2R1bGUuaW1wb3J0cyhtb2R1bGUpKSB7CiAgICAgIGNvbnN0IGltcG9ydEVudHJ5ID0gX2ltcG9ydEVudHJ5OwogICAgICBpZiAoIWltcG9ydE9iamVjdDJbaW1wb3J0RW50cnkubW9kdWxlXSkgewogICAgICAgIGltcG9ydE9iamVjdDJbaW1wb3J0RW50cnkubW9kdWxlXSA9IHt9OwogICAgICB9CiAgICAgIGlmIChpbXBvcnRPYmplY3QyW2ltcG9ydEVudHJ5Lm1vZHVsZV1baW1wb3J0RW50cnkubmFtZV0pIHsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICBpZiAoaW1wb3J0RW50cnkua2luZCA9PSAiZnVuY3Rpb24iKSB7CiAgICAgICAgaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdW2ltcG9ydEVudHJ5Lm5hbWVdID0gKCkgPT4gewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbXBvcnRlZCBmdW5jdGlvbiAke2ltcG9ydEVudHJ5Lm1vZHVsZX0uJHtpbXBvcnRFbnRyeS5uYW1lfSBub3QgaW1wbGVtZW50ZWRgKTsKICAgICAgICB9OwogICAgICB9IGVsc2UgaWYgKGltcG9ydEVudHJ5LmtpbmQgPT0gIm1lbW9yeSIgJiYgaW1wb3J0RW50cnkubW9kdWxlID09ICJlbnYiICYmIGltcG9ydEVudHJ5Lm5hbWUgPT0gIm1lbW9yeSIpIHsKICAgICAgICBjb25zdCB0eXBlID0gaW1wb3J0RW50cnkudHlwZTsKICAgICAgICBjb25zdCBkZXNjcmlwdG9yID0gewogICAgICAgICAgaW5pdGlhbDogdHlwZS5taW5pbXVtLAogICAgICAgICAgbWF4aW11bTogdHlwZS5tYXhpbXVtLAogICAgICAgICAgc2hhcmVkOiB0eXBlLnNoYXJlZAogICAgICAgIH07CiAgICAgICAgaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdW2ltcG9ydEVudHJ5Lm5hbWVdID0gbmV3IFdlYkFzc2VtYmx5Mi5NZW1vcnkoZGVzY3JpcHRvcik7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBpbXBvcnRPYmplY3QyOwogIH07CiAgY29uc3QgaW1wb3J0T2JqZWN0ID0gY3JlYXRlV2FzbUltcG9ydE9iamVjdChleHRyYVdhc21JbXBvcnRzLCBvcHRpb25zLm1vZHVsZSk7CiAgY29uc3QgaW5zdGFuY2UgPSBhd2FpdCBXZWJBc3NlbWJseTIuaW5zdGFudGlhdGUob3B0aW9ucy5tb2R1bGUsIGltcG9ydE9iamVjdCk7CiAgaWYgKHN3aWZ0ICYmIGluc3RhbmNlLmV4cG9ydHMuc3dqc19saWJyYXJ5X3ZlcnNpb24pIHsKICAgIHN3aWZ0LnNldEluc3RhbmNlKGluc3RhbmNlKTsKICB9CiAgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLl9zdGFydCA9PT0gImZ1bmN0aW9uIikgewogICAgd2FzaS5zdGFydChpbnN0YW5jZSk7CiAgfSBlbHNlIGlmICh0eXBlb2YgaW5zdGFuY2UuZXhwb3J0cy5faW5pdGlhbGl6ZSA9PSAiZnVuY3Rpb24iKSB7CiAgICB3YXNpLmluaXRpYWxpemUoaW5zdGFuY2UpOwogICAgaWYgKHN3aWZ0ICYmIHN3aWZ0Lm1haW4pIHsKICAgICAgc3dpZnQubWFpbigpOwogICAgfSBlbHNlIHsKICAgICAgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLm1haW4gPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICBpbnN0YW5jZS5leHBvcnRzLm1haW4oKTsKICAgICAgfSBlbHNlIGlmICh0eXBlb2YgaW5zdGFuY2UuZXhwb3J0cy5fX21haW5fYXJnY19hcmd2ID09PSAiZnVuY3Rpb24iKSB7CiAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5fX21haW5fYXJnY19hcmd2KDAsIDApOwogICAgICB9CiAgICB9CiAgfQogIHJldHVybiB7IGluc3RhbmNlLCByb290RnMgfTsKfQpmdW5jdGlvbiBkZWZhdWx0SW5zdGFudGlhdGlvbk9wdGlvbnMob3B0aW9ucykgewogIGlmIChvcHRpb25zLmFyZ3MgPT0gbnVsbCkgewogICAgb3B0aW9ucy5hcmdzID0gWyJtYWluLndhc20iXTsKICB9CiAgY29uc3QgaXNOb2RlSnMgPSB0eXBlb2YgcHJvY2VzcyAhPT0gInVuZGVmaW5lZCIgJiYgcHJvY2Vzcy5yZWxlYXNlLm5hbWUgPT09ICJub2RlIjsKICBjb25zdCBpc1dlYkJyb3dzZXIgPSB0eXBlb2Ygd2luZG93ICE9PSAidW5kZWZpbmVkIjsKICBpZiAoaXNOb2RlSnMpIHsKICAgIGlmICghb3B0aW9ucy5vblN0ZG91dCkgewogICAgICBvcHRpb25zLm9uU3Rkb3V0ID0gKGNodW5rKSA9PiBwcm9jZXNzLnN0ZG91dC53cml0ZShjaHVuayk7CiAgICB9CiAgICBpZiAoIW9wdGlvbnMub25TdGRlcnIpIHsKICAgICAgb3B0aW9ucy5vblN0ZGVyciA9IChjaHVuaykgPT4gcHJvY2Vzcy5zdGRlcnIud3JpdGUoY2h1bmspOwogICAgfQogIH0gZWxzZSBpZiAoaXNXZWJCcm93c2VyKSB7CiAgICBpZiAoIW9wdGlvbnMub25TdGRvdXRMaW5lKSB7CiAgICAgIG9wdGlvbnMub25TdGRvdXRMaW5lID0gKGxpbmUpID0+IGNvbnNvbGUubG9nKGxpbmUpOwogICAgfQogICAgaWYgKCFvcHRpb25zLm9uU3RkZXJyTGluZSkgewogICAgICBvcHRpb25zLm9uU3RkZXJyTGluZSA9IChsaW5lKSA9PiBjb25zb2xlLndhcm4obGluZSk7CiAgICB9CiAgfQogIHJldHVybiBvcHRpb25zOwp9CgovLyBlbnRyeXBvaW50L2Rldi50cwp2YXIgc29ja2V0ID0gbmV3IHJlY29ubmVjdGluZ193ZWJzb2NrZXRfbWpzX2RlZmF1bHQoYHdzOi8vJHtsb2NhdGlvbi5ob3N0fS93YXRjaGVyYCk7CnNvY2tldC5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIiwgKG1lc3NhZ2UpID0+IHsKICBpZiAobWVzc2FnZS5kYXRhID09PSAicmVsb2FkIikgewogICAgbG9jYXRpb24ucmVsb2FkKCk7CiAgfQp9KTsKdmFyIHN0YXJ0V2FzaVRhc2sgPSBhc3luYyAoKSA9PiB7CiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCgiL21haW4ud2FzbSIpOwogIGxldCBydW50aW1lQ29uc3RydWN0b3IgPSB2b2lkIDA7CiAgdHJ5IHsKICAgIGNvbnN0IG1vZHVsZVBhdGggPSAiLi9KYXZhU2NyaXB0S2l0X0phdmFTY3JpcHRLaXQucmVzb3VyY2VzL1J1bnRpbWUvaW5kZXgubWpzIjsKICAgIGNvbnN0IHsgU3dpZnRSdW50aW1lIH0gPSBhd2FpdCBpbXBvcnQoCiAgICAgIC8vIEB0cy1pZ25vcmUKICAgICAgLyogQHZpdGUtaWdub3JlICovCiAgICAgIG1vZHVsZVBhdGgKICAgICk7CiAgICBydW50aW1lQ29uc3RydWN0b3IgPSBTd2lmdFJ1bnRpbWU7CiAgfSBjYXRjaCB7CiAgICBjb25zb2xlLmxvZygiSmF2YVNjcmlwdEtpdCBtb2R1bGUgbm90IGF2YWlsYWJsZSwgcnVubmluZyB3aXRob3V0IEphdmFTY3JpcHRLaXQgcnVudGltZS4iKTsKICB9CiAgYXdhaXQgaW5zdGFudGlhdGUoewogICAgbW9kdWxlOiBhd2FpdCBXZWJBc3NlbWJseTIuY29tcGlsZVN0cmVhbWluZyhyZXNwb25zZSksCiAgICBvblN0ZG91dChjaHVuaykgewogICAgICBjb25zdCBraW5kQnVmZmVyID0gbmV3IEFycmF5QnVmZmVyKDIpOwogICAgICBuZXcgRGF0YVZpZXcoa2luZEJ1ZmZlcikuc2V0VWludDE2KDAsIDEwMDEsIHRydWUpOwogICAgICBjb25zdCBidWZmZXIgPSBuZXcgVWludDhBcnJheSgyICsgY2h1bmsubGVuZ3RoKTsKICAgICAgYnVmZmVyLnNldChuZXcgVWludDhBcnJheShraW5kQnVmZmVyKSwgMCk7CiAgICAgIGJ1ZmZlci5zZXQoY2h1bmssIDIpOwogICAgICBzb2NrZXQuc2VuZChidWZmZXIpOwogICAgfSwKICAgIG9uU3Rkb3V0TGluZShsaW5lKSB7CiAgICAgIGNvbnNvbGUubG9nKGxpbmUpOwogICAgfSwKICAgIG9uU3RkZXJyKGNodW5rKSB7CiAgICAgIGNvbnN0IGtpbmRCdWZmZXIgPSBuZXcgQXJyYXlCdWZmZXIoMik7CiAgICAgIG5ldyBEYXRhVmlldyhraW5kQnVmZmVyKS5zZXRVaW50MTYoMCwgMTAwMiwgdHJ1ZSk7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBVaW50OEFycmF5KDIgKyBjaHVuay5sZW5ndGgpOwogICAgICBidWZmZXIuc2V0KG5ldyBVaW50OEFycmF5KGtpbmRCdWZmZXIpLCAwKTsKICAgICAgYnVmZmVyLnNldChjaHVuaywgMik7CiAgICAgIHNvY2tldC5zZW5kKGJ1ZmZlcik7CiAgICB9LAogICAgb25TdGRlcnJMaW5lKGxpbmUpIHsKICAgICAgY29uc29sZS5lcnJvcihsaW5lKTsKICAgIH0sCiAgICBTd2lmdFJ1bnRpbWU6IHJ1bnRpbWVDb25zdHJ1Y3RvcgogIH0pOwp9OwpmdW5jdGlvbiBoYW5kbGVFcnJvcihlKSB7CiAgaWYgKGUgaW5zdGFuY2VvZiBFcnJvcikgewogICAgY29uc3Qgc3RhY2sgPSBlLnN0YWNrOwogICAgaWYgKHN0YWNrICE9IG51bGwpIHsKICAgICAgc29ja2V0LnNlbmQoSlNPTi5zdHJpbmdpZnkoewogICAgICAgIGtpbmQ6ICJzdGFja1RyYWNlIiwKICAgICAgICBzdGFja1RyYWNlOiBzdGFjawogICAgICB9KSk7CiAgICB9CiAgfQp9CmFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7CiAgdHJ5IHsKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCJlcnJvciIsIChldmVudCkgPT4gewogICAgICBoYW5kbGVFcnJvcihldmVudC5lcnJvcik7CiAgICB9KTsKICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCJ1bmhhbmRsZWRyZWplY3Rpb24iLCAoZXZlbnQpID0+IHsKICAgICAgaGFuZGxlRXJyb3IoZXZlbnQucmVhc29uKTsKICAgIH0pOwogICAgYXdhaXQgc3RhcnRXYXNpVGFzaygpOwogIH0gY2F0Y2ggKGUpIHsKICAgIGhhbmRsZUVycm9yKGUpOwogICAgdGhyb3cgZTsKICB9Cn0KbWFpbigpOwovKiEKICogUmVjb25uZWN0aW5nIFdlYlNvY2tldAogKiBieSBQZWRybyBMYWRhcmlhIDxwZWRyby5sYWRhcmlhQGdtYWlsLmNvbT4KICogaHR0cHM6Ly9naXRodWIuY29tL3BsYWRhcmlhL3JlY29ubmVjdGluZy13ZWJzb2NrZXQKICogTGljZW5zZSBNSVQKICovCi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgpDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7IHlvdSBtYXkgbm90IHVzZQp0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4gWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZQpMaWNlbnNlIGF0IGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKVEhJUyBDT0RFIElTIFBST1ZJREVEIE9OIEFOICpBUyBJUyogQkFTSVMsIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWQpLSU5ELCBFSVRIRVIgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgV0lUSE9VVCBMSU1JVEFUSU9OIEFOWSBJTVBMSUVECldBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBUSVRMRSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UsCk1FUkNIQU5UQUJMSVRZIE9SIE5PTi1JTkZSSU5HRU1FTlQuCgpTZWUgdGhlIEFwYWNoZSBWZXJzaW9uIDIuMCBMaWNlbnNlIGZvciBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMKYW5kIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAqLwo=")! + public static let bundle: Data = Data(base64Encoded: "Ly8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC93YXNpX2RlZnMuanMKdmFyIENMT0NLSURfUkVBTFRJTUUgPSAwOwp2YXIgQ0xPQ0tJRF9NT05PVE9OSUMgPSAxOwp2YXIgRVJSTk9fU1VDQ0VTUyA9IDA7CnZhciBFUlJOT19CQURGID0gODsKdmFyIEVSUk5PX0VYSVNUID0gMjA7CnZhciBFUlJOT19JTlZBTCA9IDI4Owp2YXIgRVJSTk9fSVNESVIgPSAzMTsKdmFyIEVSUk5PX05BTUVUT09MT05HID0gMzc7CnZhciBFUlJOT19OT0VOVCA9IDQ0Owp2YXIgRVJSTk9fTk9TWVMgPSA1MjsKdmFyIEVSUk5PX05PVERJUiA9IDU0Owp2YXIgRVJSTk9fTk9URU1QVFkgPSA1NTsKdmFyIEVSUk5PX05PVFNVUCA9IDU4Owp2YXIgRVJSTk9fUEVSTSA9IDYzOwp2YXIgRVJSTk9fTk9UQ0FQQUJMRSA9IDc2Owp2YXIgUklHSFRTX0ZEX0RBVEFTWU5DID0gMSA8PCAwOwp2YXIgUklHSFRTX0ZEX1JFQUQgPSAxIDw8IDE7CnZhciBSSUdIVFNfRkRfU0VFSyA9IDEgPDwgMjsKdmFyIFJJR0hUU19GRF9GRFNUQVRfU0VUX0ZMQUdTID0gMSA8PCAzOwp2YXIgUklHSFRTX0ZEX1NZTkMgPSAxIDw8IDQ7CnZhciBSSUdIVFNfRkRfVEVMTCA9IDEgPDwgNTsKdmFyIFJJR0hUU19GRF9XUklURSA9IDEgPDwgNjsKdmFyIFJJR0hUU19GRF9BRFZJU0UgPSAxIDw8IDc7CnZhciBSSUdIVFNfRkRfQUxMT0NBVEUgPSAxIDw8IDg7CnZhciBSSUdIVFNfUEFUSF9DUkVBVEVfRElSRUNUT1JZID0gMSA8PCA5Owp2YXIgUklHSFRTX1BBVEhfQ1JFQVRFX0ZJTEUgPSAxIDw8IDEwOwp2YXIgUklHSFRTX1BBVEhfTElOS19TT1VSQ0UgPSAxIDw8IDExOwp2YXIgUklHSFRTX1BBVEhfTElOS19UQVJHRVQgPSAxIDw8IDEyOwp2YXIgUklHSFRTX1BBVEhfT1BFTiA9IDEgPDwgMTM7CnZhciBSSUdIVFNfRkRfUkVBRERJUiA9IDEgPDwgMTQ7CnZhciBSSUdIVFNfUEFUSF9SRUFETElOSyA9IDEgPDwgMTU7CnZhciBSSUdIVFNfUEFUSF9SRU5BTUVfU09VUkNFID0gMSA8PCAxNjsKdmFyIFJJR0hUU19QQVRIX1JFTkFNRV9UQVJHRVQgPSAxIDw8IDE3Owp2YXIgUklHSFRTX1BBVEhfRklMRVNUQVRfR0VUID0gMSA8PCAxODsKdmFyIFJJR0hUU19QQVRIX0ZJTEVTVEFUX1NFVF9TSVpFID0gMSA8PCAxOTsKdmFyIFJJR0hUU19QQVRIX0ZJTEVTVEFUX1NFVF9USU1FUyA9IDEgPDwgMjA7CnZhciBSSUdIVFNfRkRfRklMRVNUQVRfR0VUID0gMSA8PCAyMTsKdmFyIFJJR0hUU19GRF9GSUxFU1RBVF9TRVRfU0laRSA9IDEgPDwgMjI7CnZhciBSSUdIVFNfRkRfRklMRVNUQVRfU0VUX1RJTUVTID0gMSA8PCAyMzsKdmFyIFJJR0hUU19QQVRIX1NZTUxJTksgPSAxIDw8IDI0Owp2YXIgUklHSFRTX1BBVEhfUkVNT1ZFX0RJUkVDVE9SWSA9IDEgPDwgMjU7CnZhciBSSUdIVFNfUEFUSF9VTkxJTktfRklMRSA9IDEgPDwgMjY7CnZhciBSSUdIVFNfUE9MTF9GRF9SRUFEV1JJVEUgPSAxIDw8IDI3Owp2YXIgUklHSFRTX1NPQ0tfU0hVVERPV04gPSAxIDw8IDI4Owp2YXIgSW92ZWMgPSBjbGFzcyB7CiAgc3RhdGljIHJlYWRfYnl0ZXModmlldywgcHRyKSB7CiAgICBjb25zdCBpb3ZlYyA9IG5ldyBJb3ZlYygpOwogICAgaW92ZWMuYnVmID0gdmlldy5nZXRVaW50MzIocHRyLCB0cnVlKTsKICAgIGlvdmVjLmJ1Zl9sZW4gPSB2aWV3LmdldFVpbnQzMihwdHIgKyA0LCB0cnVlKTsKICAgIHJldHVybiBpb3ZlYzsKICB9CiAgc3RhdGljIHJlYWRfYnl0ZXNfYXJyYXkodmlldywgcHRyLCBsZW4pIHsKICAgIGNvbnN0IGlvdmVjcyA9IFtdOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykgewogICAgICBpb3ZlY3MucHVzaChJb3ZlYy5yZWFkX2J5dGVzKHZpZXcsIHB0ciArIDggKiBpKSk7CiAgICB9CiAgICByZXR1cm4gaW92ZWNzOwogIH0KfTsKdmFyIENpb3ZlYyA9IGNsYXNzIHsKICBzdGF0aWMgcmVhZF9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIGNvbnN0IGlvdmVjID0gbmV3IENpb3ZlYygpOwogICAgaW92ZWMuYnVmID0gdmlldy5nZXRVaW50MzIocHRyLCB0cnVlKTsKICAgIGlvdmVjLmJ1Zl9sZW4gPSB2aWV3LmdldFVpbnQzMihwdHIgKyA0LCB0cnVlKTsKICAgIHJldHVybiBpb3ZlYzsKICB9CiAgc3RhdGljIHJlYWRfYnl0ZXNfYXJyYXkodmlldywgcHRyLCBsZW4pIHsKICAgIGNvbnN0IGlvdmVjcyA9IFtdOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykgewogICAgICBpb3ZlY3MucHVzaChDaW92ZWMucmVhZF9ieXRlcyh2aWV3LCBwdHIgKyA4ICogaSkpOwogICAgfQogICAgcmV0dXJuIGlvdmVjczsKICB9Cn07CnZhciBXSEVOQ0VfU0VUID0gMDsKdmFyIFdIRU5DRV9DVVIgPSAxOwp2YXIgV0hFTkNFX0VORCA9IDI7CnZhciBGSUxFVFlQRV9DSEFSQUNURVJfREVWSUNFID0gMjsKdmFyIEZJTEVUWVBFX0RJUkVDVE9SWSA9IDM7CnZhciBGSUxFVFlQRV9SRUdVTEFSX0ZJTEUgPSA0Owp2YXIgRGlyZW50ID0gY2xhc3MgewogIGhlYWRfbGVuZ3RoKCkgewogICAgcmV0dXJuIDI0OwogIH0KICBuYW1lX2xlbmd0aCgpIHsKICAgIHJldHVybiB0aGlzLmRpcl9uYW1lLmJ5dGVMZW5ndGg7CiAgfQogIHdyaXRlX2hlYWRfYnl0ZXModmlldywgcHRyKSB7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIsIHRoaXMuZF9uZXh0LCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDgsIHRoaXMuZF9pbm8sIHRydWUpOwogICAgdmlldy5zZXRVaW50MzIocHRyICsgMTYsIHRoaXMuZGlyX25hbWUubGVuZ3RoLCB0cnVlKTsKICAgIHZpZXcuc2V0VWludDgocHRyICsgMjAsIHRoaXMuZF90eXBlKTsKICB9CiAgd3JpdGVfbmFtZV9ieXRlcyh2aWV3OCwgcHRyLCBidWZfbGVuKSB7CiAgICB2aWV3OC5zZXQodGhpcy5kaXJfbmFtZS5zbGljZSgwLCBNYXRoLm1pbih0aGlzLmRpcl9uYW1lLmJ5dGVMZW5ndGgsIGJ1Zl9sZW4pKSwgcHRyKTsKICB9CiAgY29uc3RydWN0b3IobmV4dF9jb29raWUsIG5hbWUsIHR5cGUpIHsKICAgIHRoaXMuZF9pbm8gPSAwbjsKICAgIGNvbnN0IGVuY29kZWRfbmFtZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShuYW1lKTsKICAgIHRoaXMuZF9uZXh0ID0gbmV4dF9jb29raWU7CiAgICB0aGlzLmRfbmFtbGVuID0gZW5jb2RlZF9uYW1lLmJ5dGVMZW5ndGg7CiAgICB0aGlzLmRfdHlwZSA9IHR5cGU7CiAgICB0aGlzLmRpcl9uYW1lID0gZW5jb2RlZF9uYW1lOwogIH0KfTsKdmFyIEZERkxBR1NfQVBQRU5EID0gMSA8PCAwOwp2YXIgRkRGTEFHU19EU1lOQyA9IDEgPDwgMTsKdmFyIEZERkxBR1NfTk9OQkxPQ0sgPSAxIDw8IDI7CnZhciBGREZMQUdTX1JTWU5DID0gMSA8PCAzOwp2YXIgRkRGTEFHU19TWU5DID0gMSA8PCA0Owp2YXIgRmRzdGF0ID0gY2xhc3MgewogIHdyaXRlX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRVaW50OChwdHIsIHRoaXMuZnNfZmlsZXR5cGUpOwogICAgdmlldy5zZXRVaW50MTYocHRyICsgMiwgdGhpcy5mc19mbGFncywgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA4LCB0aGlzLmZzX3JpZ2h0c19iYXNlLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDE2LCB0aGlzLmZzX3JpZ2h0c19pbmhlcml0ZWQsIHRydWUpOwogIH0KICBjb25zdHJ1Y3RvcihmaWxldHlwZSwgZmxhZ3MpIHsKICAgIHRoaXMuZnNfcmlnaHRzX2Jhc2UgPSAwbjsKICAgIHRoaXMuZnNfcmlnaHRzX2luaGVyaXRlZCA9IDBuOwogICAgdGhpcy5mc19maWxldHlwZSA9IGZpbGV0eXBlOwogICAgdGhpcy5mc19mbGFncyA9IGZsYWdzOwogIH0KfTsKdmFyIEZTVEZMQUdTX0FUSU0gPSAxIDw8IDA7CnZhciBGU1RGTEFHU19BVElNX05PVyA9IDEgPDwgMTsKdmFyIEZTVEZMQUdTX01USU0gPSAxIDw8IDI7CnZhciBGU1RGTEFHU19NVElNX05PVyA9IDEgPDwgMzsKdmFyIE9GTEFHU19DUkVBVCA9IDEgPDwgMDsKdmFyIE9GTEFHU19ESVJFQ1RPUlkgPSAxIDw8IDE7CnZhciBPRkxBR1NfRVhDTCA9IDEgPDwgMjsKdmFyIE9GTEFHU19UUlVOQyA9IDEgPDwgMzsKdmFyIEZpbGVzdGF0ID0gY2xhc3MgewogIHdyaXRlX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRCaWdVaW50NjQocHRyLCB0aGlzLmRldiwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA4LCB0aGlzLmlubywgdHJ1ZSk7CiAgICB2aWV3LnNldFVpbnQ4KHB0ciArIDE2LCB0aGlzLmZpbGV0eXBlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDI0LCB0aGlzLm5saW5rLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDMyLCB0aGlzLnNpemUsIHRydWUpOwogICAgdmlldy5zZXRCaWdVaW50NjQocHRyICsgMzgsIHRoaXMuYXRpbSwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA0NiwgdGhpcy5tdGltLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDUyLCB0aGlzLmN0aW0sIHRydWUpOwogIH0KICBjb25zdHJ1Y3RvcihmaWxldHlwZSwgc2l6ZSkgewogICAgdGhpcy5kZXYgPSAwbjsKICAgIHRoaXMuaW5vID0gMG47CiAgICB0aGlzLm5saW5rID0gMG47CiAgICB0aGlzLmF0aW0gPSAwbjsKICAgIHRoaXMubXRpbSA9IDBuOwogICAgdGhpcy5jdGltID0gMG47CiAgICB0aGlzLmZpbGV0eXBlID0gZmlsZXR5cGU7CiAgICB0aGlzLnNpemUgPSBzaXplOwogIH0KfTsKdmFyIEVWRU5UUldGTEFHU19GRF9SRUFEV1JJVEVfSEFOR1VQID0gMSA8PCAwOwp2YXIgU1VCQ0xPQ0tGTEFHU19TVUJTQ1JJUFRJT05fQ0xPQ0tfQUJTVElNRSA9IDEgPDwgMDsKdmFyIFJJRkxBR1NfUkVDVl9QRUVLID0gMSA8PCAwOwp2YXIgUklGTEFHU19SRUNWX1dBSVRBTEwgPSAxIDw8IDE7CnZhciBST0ZMQUdTX1JFQ1ZfREFUQV9UUlVOQ0FURUQgPSAxIDw8IDA7CnZhciBTREZMQUdTX1JEID0gMSA8PCAwOwp2YXIgU0RGTEFHU19XUiA9IDEgPDwgMTsKdmFyIFBSRU9QRU5UWVBFX0RJUiA9IDA7CnZhciBQcmVzdGF0RGlyID0gY2xhc3MgewogIHdyaXRlX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRVaW50MzIocHRyLCB0aGlzLnByX25hbWUuYnl0ZUxlbmd0aCwgdHJ1ZSk7CiAgfQogIGNvbnN0cnVjdG9yKG5hbWUpIHsKICAgIHRoaXMucHJfbmFtZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShuYW1lKTsKICB9Cn07CnZhciBQcmVzdGF0ID0gY2xhc3MgewogIHN0YXRpYyBkaXIobmFtZSkgewogICAgY29uc3QgcHJlc3RhdCA9IG5ldyBQcmVzdGF0KCk7CiAgICBwcmVzdGF0LnRhZyA9IFBSRU9QRU5UWVBFX0RJUjsKICAgIHByZXN0YXQuaW5uZXIgPSBuZXcgUHJlc3RhdERpcihuYW1lKTsKICAgIHJldHVybiBwcmVzdGF0OwogIH0KICB3cml0ZV9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIHZpZXcuc2V0VWludDMyKHB0ciwgdGhpcy50YWcsIHRydWUpOwogICAgdGhpcy5pbm5lci53cml0ZV9ieXRlcyh2aWV3LCBwdHIgKyA0KTsKICB9Cn07CgovLyBub2RlX21vZHVsZXMvQGJqb3JuMy9icm93c2VyX3dhc2lfc2hpbS9kaXN0L2RlYnVnLmpzCnZhciBEZWJ1ZyA9IGNsYXNzIERlYnVnMiB7CiAgZW5hYmxlKGVuYWJsZWQpIHsKICAgIHRoaXMubG9nID0gY3JlYXRlTG9nZ2VyKGVuYWJsZWQgPT09IHZvaWQgMCA/IHRydWUgOiBlbmFibGVkLCB0aGlzLnByZWZpeCk7CiAgfQogIGdldCBlbmFibGVkKCkgewogICAgcmV0dXJuIHRoaXMuaXNFbmFibGVkOwogIH0KICBjb25zdHJ1Y3Rvcihpc0VuYWJsZWQpIHsKICAgIHRoaXMuaXNFbmFibGVkID0gaXNFbmFibGVkOwogICAgdGhpcy5wcmVmaXggPSAid2FzaToiOwogICAgdGhpcy5lbmFibGUoaXNFbmFibGVkKTsKICB9Cn07CmZ1bmN0aW9uIGNyZWF0ZUxvZ2dlcihlbmFibGVkLCBwcmVmaXgpIHsKICBpZiAoZW5hYmxlZCkgewogICAgY29uc3QgYSA9IGNvbnNvbGUubG9nLmJpbmQoY29uc29sZSwgIiVjJXMiLCAiY29sb3I6ICMyNjVCQTAiLCBwcmVmaXgpOwogICAgcmV0dXJuIGE7CiAgfSBlbHNlIHsKICAgIHJldHVybiAoKSA9PiB7CiAgICB9OwogIH0KfQp2YXIgZGVidWcgPSBuZXcgRGVidWcoZmFsc2UpOwoKLy8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC93YXNpLmpzCnZhciBXQVNJUHJvY0V4aXQgPSBjbGFzcyBleHRlbmRzIEVycm9yIHsKICBjb25zdHJ1Y3Rvcihjb2RlKSB7CiAgICBzdXBlcigiZXhpdCB3aXRoIGV4aXQgY29kZSAiICsgY29kZSk7CiAgICB0aGlzLmNvZGUgPSBjb2RlOwogIH0KfTsKdmFyIFdBU0kgPSBjbGFzcyBXQVNJMiB7CiAgc3RhcnQoaW5zdGFuY2UpIHsKICAgIHRoaXMuaW5zdCA9IGluc3RhbmNlOwogICAgdHJ5IHsKICAgICAgaW5zdGFuY2UuZXhwb3J0cy5fc3RhcnQoKTsKICAgICAgcmV0dXJuIDA7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIGlmIChlIGluc3RhbmNlb2YgV0FTSVByb2NFeGl0KSB7CiAgICAgICAgcmV0dXJuIGUuY29kZTsKICAgICAgfSBlbHNlIHsKICAgICAgICB0aHJvdyBlOwogICAgICB9CiAgICB9CiAgfQogIGluaXRpYWxpemUoaW5zdGFuY2UpIHsKICAgIHRoaXMuaW5zdCA9IGluc3RhbmNlOwogICAgaWYgKGluc3RhbmNlLmV4cG9ydHMuX2luaXRpYWxpemUpIHsKICAgICAgaW5zdGFuY2UuZXhwb3J0cy5faW5pdGlhbGl6ZSgpOwogICAgfQogIH0KICBjb25zdHJ1Y3RvcihhcmdzLCBlbnYsIGZkcywgb3B0aW9ucyA9IHt9KSB7CiAgICB0aGlzLmFyZ3MgPSBbXTsKICAgIHRoaXMuZW52ID0gW107CiAgICB0aGlzLmZkcyA9IFtdOwogICAgZGVidWcuZW5hYmxlKG9wdGlvbnMuZGVidWcpOwogICAgdGhpcy5hcmdzID0gYXJnczsKICAgIHRoaXMuZW52ID0gZW52OwogICAgdGhpcy5mZHMgPSBmZHM7CiAgICBjb25zdCBzZWxmID0gdGhpczsKICAgIHRoaXMud2FzaUltcG9ydCA9IHsgYXJnc19zaXplc19nZXQoYXJnYywgYXJndl9idWZfc2l6ZSkgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYXJnYywgc2VsZi5hcmdzLmxlbmd0aCwgdHJ1ZSk7CiAgICAgIGxldCBidWZfc2l6ZSA9IDA7CiAgICAgIGZvciAoY29uc3QgYXJnIG9mIHNlbGYuYXJncykgewogICAgICAgIGJ1Zl9zaXplICs9IGFyZy5sZW5ndGggKyAxOwogICAgICB9CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYXJndl9idWZfc2l6ZSwgYnVmX3NpemUsIHRydWUpOwogICAgICBkZWJ1Zy5sb2coYnVmZmVyLmdldFVpbnQzMihhcmdjLCB0cnVlKSwgYnVmZmVyLmdldFVpbnQzMihhcmd2X2J1Zl9zaXplLCB0cnVlKSk7CiAgICAgIHJldHVybiAwOwogICAgfSwgYXJnc19nZXQoYXJndiwgYXJndl9idWYpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IG9yaWdfYXJndl9idWYgPSBhcmd2X2J1ZjsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmLmFyZ3MubGVuZ3RoOyBpKyspIHsKICAgICAgICBidWZmZXIuc2V0VWludDMyKGFyZ3YsIGFyZ3ZfYnVmLCB0cnVlKTsKICAgICAgICBhcmd2ICs9IDQ7CiAgICAgICAgY29uc3QgYXJnID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHNlbGYuYXJnc1tpXSk7CiAgICAgICAgYnVmZmVyOC5zZXQoYXJnLCBhcmd2X2J1Zik7CiAgICAgICAgYnVmZmVyLnNldFVpbnQ4KGFyZ3ZfYnVmICsgYXJnLmxlbmd0aCwgMCk7CiAgICAgICAgYXJndl9idWYgKz0gYXJnLmxlbmd0aCArIDE7CiAgICAgIH0KICAgICAgaWYgKGRlYnVnLmVuYWJsZWQpIHsKICAgICAgICBkZWJ1Zy5sb2cobmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG9yaWdfYXJndl9idWYsIGFyZ3ZfYnVmKSkpOwogICAgICB9CiAgICAgIHJldHVybiAwOwogICAgfSwgZW52aXJvbl9zaXplc19nZXQoZW52aXJvbl9jb3VudCwgZW52aXJvbl9zaXplKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgYnVmZmVyLnNldFVpbnQzMihlbnZpcm9uX2NvdW50LCBzZWxmLmVudi5sZW5ndGgsIHRydWUpOwogICAgICBsZXQgYnVmX3NpemUgPSAwOwogICAgICBmb3IgKGNvbnN0IGVudmlyb24gb2Ygc2VsZi5lbnYpIHsKICAgICAgICBidWZfc2l6ZSArPSBlbnZpcm9uLmxlbmd0aCArIDE7CiAgICAgIH0KICAgICAgYnVmZmVyLnNldFVpbnQzMihlbnZpcm9uX3NpemUsIGJ1Zl9zaXplLCB0cnVlKTsKICAgICAgZGVidWcubG9nKGJ1ZmZlci5nZXRVaW50MzIoZW52aXJvbl9jb3VudCwgdHJ1ZSksIGJ1ZmZlci5nZXRVaW50MzIoZW52aXJvbl9zaXplLCB0cnVlKSk7CiAgICAgIHJldHVybiAwOwogICAgfSwgZW52aXJvbl9nZXQoZW52aXJvbiwgZW52aXJvbl9idWYpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IG9yaWdfZW52aXJvbl9idWYgPSBlbnZpcm9uX2J1ZjsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmLmVudi5sZW5ndGg7IGkrKykgewogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIoZW52aXJvbiwgZW52aXJvbl9idWYsIHRydWUpOwogICAgICAgIGVudmlyb24gKz0gNDsKICAgICAgICBjb25zdCBlID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHNlbGYuZW52W2ldKTsKICAgICAgICBidWZmZXI4LnNldChlLCBlbnZpcm9uX2J1Zik7CiAgICAgICAgYnVmZmVyLnNldFVpbnQ4KGVudmlyb25fYnVmICsgZS5sZW5ndGgsIDApOwogICAgICAgIGVudmlyb25fYnVmICs9IGUubGVuZ3RoICsgMTsKICAgICAgfQogICAgICBpZiAoZGVidWcuZW5hYmxlZCkgewogICAgICAgIGRlYnVnLmxvZyhuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob3JpZ19lbnZpcm9uX2J1ZiwgZW52aXJvbl9idWYpKSk7CiAgICAgIH0KICAgICAgcmV0dXJuIDA7CiAgICB9LCBjbG9ja19yZXNfZ2V0KGlkLCByZXNfcHRyKSB7CiAgICAgIGxldCByZXNvbHV0aW9uVmFsdWU7CiAgICAgIHN3aXRjaCAoaWQpIHsKICAgICAgICBjYXNlIENMT0NLSURfTU9OT1RPTklDOiB7CiAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSA1MDAwbjsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICBjYXNlIENMT0NLSURfUkVBTFRJTUU6IHsKICAgICAgICAgIHJlc29sdXRpb25WYWx1ZSA9IDEwMDAwMDBuOwogICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICByZXR1cm4gRVJSTk9fTk9TWVM7CiAgICAgIH0KICAgICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgdmlldy5zZXRCaWdVaW50NjQocmVzX3B0ciwgcmVzb2x1dGlvblZhbHVlLCB0cnVlKTsKICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICB9LCBjbG9ja190aW1lX2dldChpZCwgcHJlY2lzaW9uLCB0aW1lKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKGlkID09PSBDTE9DS0lEX1JFQUxUSU1FKSB7CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NCh0aW1lLCBCaWdJbnQobmV3IERhdGUoKS5nZXRUaW1lKCkpICogMTAwMDAwMG4sIHRydWUpOwogICAgICB9IGVsc2UgaWYgKGlkID09IENMT0NLSURfTU9OT1RPTklDKSB7CiAgICAgICAgbGV0IG1vbm90b25pY190aW1lOwogICAgICAgIHRyeSB7CiAgICAgICAgICBtb25vdG9uaWNfdGltZSA9IEJpZ0ludChNYXRoLnJvdW5kKHBlcmZvcm1hbmNlLm5vdygpICogMWU2KSk7CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgbW9ub3RvbmljX3RpbWUgPSAwbjsKICAgICAgICB9CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NCh0aW1lLCBtb25vdG9uaWNfdGltZSwgdHJ1ZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NCh0aW1lLCAwbiwgdHJ1ZSk7CiAgICAgIH0KICAgICAgcmV0dXJuIDA7CiAgICB9LCBmZF9hZHZpc2UoZmQsIG9mZnNldCwgbGVuLCBhZHZpY2UpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfYWxsb2NhdGUoZmQsIG9mZnNldCwgbGVuKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9hbGxvY2F0ZShvZmZzZXQsIGxlbik7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Nsb3NlKGZkKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcmV0ID0gc2VsZi5mZHNbZmRdLmZkX2Nsb3NlKCk7CiAgICAgICAgc2VsZi5mZHNbZmRdID0gdm9pZCAwOwogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2RhdGFzeW5jKGZkKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9zeW5jKCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Zkc3RhdF9nZXQoZmQsIGZkc3RhdF9wdHIpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgZmRzdGF0IH0gPSBzZWxmLmZkc1tmZF0uZmRfZmRzdGF0X2dldCgpOwogICAgICAgIGlmIChmZHN0YXQgIT0gbnVsbCkgewogICAgICAgICAgZmRzdGF0LndyaXRlX2J5dGVzKG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKSwgZmRzdGF0X3B0cik7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Zkc3RhdF9zZXRfZmxhZ3MoZmQsIGZsYWdzKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9mZHN0YXRfc2V0X2ZsYWdzKGZsYWdzKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfZmRzdGF0X3NldF9yaWdodHMoZmQsIGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZykgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmRzdGF0X3NldF9yaWdodHMoZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfZmlsZXN0YXRfZ2V0KGZkLCBmaWxlc3RhdF9wdHIpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgZmlsZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9maWxlc3RhdF9nZXQoKTsKICAgICAgICBpZiAoZmlsZXN0YXQgIT0gbnVsbCkgewogICAgICAgICAgZmlsZXN0YXQud3JpdGVfYnl0ZXMobmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpLCBmaWxlc3RhdF9wdHIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9maWxlc3RhdF9zZXRfc2l6ZShmZCwgc2l6ZSkgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmlsZXN0YXRfc2V0X3NpemUoc2l6ZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2ZpbGVzdGF0X3NldF90aW1lcyhmZCwgYXRpbSwgbXRpbSwgZnN0X2ZsYWdzKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9maWxlc3RhdF9zZXRfdGltZXMoYXRpbSwgbXRpbSwgZnN0X2ZsYWdzKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHJlYWQoZmQsIGlvdnNfcHRyLCBpb3ZzX2xlbiwgb2Zmc2V0LCBucmVhZF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgaW92ZWNzID0gSW92ZWMucmVhZF9ieXRlc19hcnJheShidWZmZXIsIGlvdnNfcHRyLCBpb3ZzX2xlbik7CiAgICAgICAgbGV0IG5yZWFkID0gMDsKICAgICAgICBmb3IgKGNvbnN0IGlvdmVjIG9mIGlvdmVjcykgewogICAgICAgICAgY29uc3QgeyByZXQsIGRhdGEgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wcmVhZChpb3ZlYy5idWZfbGVuLCBvZmZzZXQpOwogICAgICAgICAgaWYgKHJldCAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobnJlYWRfcHRyLCBucmVhZCwgdHJ1ZSk7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgICB9CiAgICAgICAgICBidWZmZXI4LnNldChkYXRhLCBpb3ZlYy5idWYpOwogICAgICAgICAgbnJlYWQgKz0gZGF0YS5sZW5ndGg7CiAgICAgICAgICBvZmZzZXQgKz0gQmlnSW50KGRhdGEubGVuZ3RoKTsKICAgICAgICAgIGlmIChkYXRhLmxlbmd0aCAhPSBpb3ZlYy5idWZfbGVuKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9wcmVzdGF0X2dldChmZCwgYnVmX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIHByZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wcmVzdGF0X2dldCgpOwogICAgICAgIGlmIChwcmVzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIHByZXN0YXQud3JpdGVfYnl0ZXMoYnVmZmVyLCBidWZfcHRyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHJlc3RhdF9kaXJfbmFtZShmZCwgcGF0aF9wdHIsIHBhdGhfbGVuKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIHByZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wcmVzdGF0X2dldCgpOwogICAgICAgIGlmIChwcmVzdGF0ID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHByZXN0YXRfZGlyX25hbWUgPSBwcmVzdGF0LmlubmVyLnByX25hbWU7CiAgICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgIGJ1ZmZlcjguc2V0KHByZXN0YXRfZGlyX25hbWUuc2xpY2UoMCwgcGF0aF9sZW4pLCBwYXRoX3B0cik7CiAgICAgICAgcmV0dXJuIHByZXN0YXRfZGlyX25hbWUuYnl0ZUxlbmd0aCA+IHBhdGhfbGVuID8gRVJSTk9fTkFNRVRPT0xPTkcgOiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9wd3JpdGUoZmQsIGlvdnNfcHRyLCBpb3ZzX2xlbiwgb2Zmc2V0LCBud3JpdHRlbl9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgaW92ZWNzID0gQ2lvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBud3JpdHRlbiA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IGRhdGEgPSBidWZmZXI4LnNsaWNlKGlvdmVjLmJ1ZiwgaW92ZWMuYnVmICsgaW92ZWMuYnVmX2xlbik7CiAgICAgICAgICBjb25zdCB7IHJldCwgbndyaXR0ZW46IG53cml0dGVuX3BhcnQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgbndyaXR0ZW4gKz0gbndyaXR0ZW5fcGFydDsKICAgICAgICAgIG9mZnNldCArPSBCaWdJbnQobndyaXR0ZW5fcGFydCk7CiAgICAgICAgICBpZiAobndyaXR0ZW5fcGFydCAhPSBkYXRhLmJ5dGVMZW5ndGgpIHsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobndyaXR0ZW5fcHRyLCBud3JpdHRlbiwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3JlYWQoZmQsIGlvdnNfcHRyLCBpb3ZzX2xlbiwgbnJlYWRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IGlvdmVjcyA9IElvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBucmVhZCA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBkYXRhIH0gPSBzZWxmLmZkc1tmZF0uZmRfcmVhZChpb3ZlYy5idWZfbGVuKTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgYnVmZmVyOC5zZXQoZGF0YSwgaW92ZWMuYnVmKTsKICAgICAgICAgIG5yZWFkICs9IGRhdGEubGVuZ3RoOwogICAgICAgICAgaWYgKGRhdGEubGVuZ3RoICE9IGlvdmVjLmJ1Zl9sZW4pIHsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobnJlYWRfcHRyLCBucmVhZCwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3JlYWRkaXIoZmQsIGJ1ZiwgYnVmX2xlbiwgY29va2llLCBidWZ1c2VkX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBsZXQgYnVmdXNlZCA9IDA7CiAgICAgICAgd2hpbGUgKHRydWUpIHsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBkaXJlbnQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9yZWFkZGlyX3NpbmdsZShjb29raWUpOwogICAgICAgICAgaWYgKHJldCAhPSAwKSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYnVmdXNlZF9wdHIsIGJ1ZnVzZWQsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgaWYgKGRpcmVudCA9PSBudWxsKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGJ1Zl9sZW4gLSBidWZ1c2VkIDwgZGlyZW50LmhlYWRfbGVuZ3RoKCkpIHsKICAgICAgICAgICAgYnVmdXNlZCA9IGJ1Zl9sZW47CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgaGVhZF9ieXRlcyA9IG5ldyBBcnJheUJ1ZmZlcihkaXJlbnQuaGVhZF9sZW5ndGgoKSk7CiAgICAgICAgICBkaXJlbnQud3JpdGVfaGVhZF9ieXRlcyhuZXcgRGF0YVZpZXcoaGVhZF9ieXRlcyksIDApOwogICAgICAgICAgYnVmZmVyOC5zZXQobmV3IFVpbnQ4QXJyYXkoaGVhZF9ieXRlcykuc2xpY2UoMCwgTWF0aC5taW4oaGVhZF9ieXRlcy5ieXRlTGVuZ3RoLCBidWZfbGVuIC0gYnVmdXNlZCkpLCBidWYpOwogICAgICAgICAgYnVmICs9IGRpcmVudC5oZWFkX2xlbmd0aCgpOwogICAgICAgICAgYnVmdXNlZCArPSBkaXJlbnQuaGVhZF9sZW5ndGgoKTsKICAgICAgICAgIGlmIChidWZfbGVuIC0gYnVmdXNlZCA8IGRpcmVudC5uYW1lX2xlbmd0aCgpKSB7CiAgICAgICAgICAgIGJ1ZnVzZWQgPSBidWZfbGVuOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICAgIGRpcmVudC53cml0ZV9uYW1lX2J5dGVzKGJ1ZmZlcjgsIGJ1ZiwgYnVmX2xlbiAtIGJ1ZnVzZWQpOwogICAgICAgICAgYnVmICs9IGRpcmVudC5uYW1lX2xlbmd0aCgpOwogICAgICAgICAgYnVmdXNlZCArPSBkaXJlbnQubmFtZV9sZW5ndGgoKTsKICAgICAgICAgIGNvb2tpZSA9IGRpcmVudC5kX25leHQ7CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYnVmdXNlZF9wdHIsIGJ1ZnVzZWQsIHRydWUpOwogICAgICAgIHJldHVybiAwOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9yZW51bWJlcihmZCwgdG8pIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDAgJiYgc2VsZi5mZHNbdG9dICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHJldCA9IHNlbGYuZmRzW3RvXS5mZF9jbG9zZSgpOwogICAgICAgIGlmIChyZXQgIT0gMCkgewogICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9CiAgICAgICAgc2VsZi5mZHNbdG9dID0gc2VsZi5mZHNbZmRdOwogICAgICAgIHNlbGYuZmRzW2ZkXSA9IHZvaWQgMDsKICAgICAgICByZXR1cm4gMDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfc2VlayhmZCwgb2Zmc2V0LCB3aGVuY2UsIG9mZnNldF9vdXRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgb2Zmc2V0OiBvZmZzZXRfb3V0IH0gPSBzZWxmLmZkc1tmZF0uZmRfc2VlayhvZmZzZXQsIHdoZW5jZSk7CiAgICAgICAgYnVmZmVyLnNldEJpZ0ludDY0KG9mZnNldF9vdXRfcHRyLCBvZmZzZXRfb3V0LCB0cnVlKTsKICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9zeW5jKGZkKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9zeW5jKCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3RlbGwoZmQsIG9mZnNldF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHsgcmV0LCBvZmZzZXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF90ZWxsKCk7CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NChvZmZzZXRfcHRyLCBvZmZzZXQsIHRydWUpOwogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3dyaXRlKGZkLCBpb3ZzX3B0ciwgaW92c19sZW4sIG53cml0dGVuX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBpb3ZlY3MgPSBDaW92ZWMucmVhZF9ieXRlc19hcnJheShidWZmZXIsIGlvdnNfcHRyLCBpb3ZzX2xlbik7CiAgICAgICAgbGV0IG53cml0dGVuID0gMDsKICAgICAgICBmb3IgKGNvbnN0IGlvdmVjIG9mIGlvdmVjcykgewogICAgICAgICAgY29uc3QgZGF0YSA9IGJ1ZmZlcjguc2xpY2UoaW92ZWMuYnVmLCBpb3ZlYy5idWYgKyBpb3ZlYy5idWZfbGVuKTsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBud3JpdHRlbjogbndyaXR0ZW5fcGFydCB9ID0gc2VsZi5mZHNbZmRdLmZkX3dyaXRlKGRhdGEpOwogICAgICAgICAgaWYgKHJldCAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobndyaXR0ZW5fcHRyLCBud3JpdHRlbiwgdHJ1ZSk7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgICB9CiAgICAgICAgICBud3JpdHRlbiArPSBud3JpdHRlbl9wYXJ0OwogICAgICAgICAgaWYgKG53cml0dGVuX3BhcnQgIT0gZGF0YS5ieXRlTGVuZ3RoKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX2NyZWF0ZV9kaXJlY3RvcnkoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF9jcmVhdGVfZGlyZWN0b3J5KHBhdGgpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX2ZpbGVzdGF0X2dldChmZCwgZmxhZ3MsIHBhdGhfcHRyLCBwYXRoX2xlbiwgZmlsZXN0YXRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCB7IHJldCwgZmlsZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5wYXRoX2ZpbGVzdGF0X2dldChmbGFncywgcGF0aCk7CiAgICAgICAgaWYgKGZpbGVzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIGZpbGVzdGF0LndyaXRlX2J5dGVzKGJ1ZmZlciwgZmlsZXN0YXRfcHRyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9maWxlc3RhdF9zZXRfdGltZXMoZmQsIGZsYWdzLCBwYXRoX3B0ciwgcGF0aF9sZW4sIGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF9maWxlc3RhdF9zZXRfdGltZXMoZmxhZ3MsIHBhdGgsIGF0aW0sIG10aW0sIGZzdF9mbGFncyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfbGluayhvbGRfZmQsIG9sZF9mbGFncywgb2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9sZW4sIG5ld19mZCwgbmV3X3BhdGhfcHRyLCBuZXdfcGF0aF9sZW4pIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbb2xkX2ZkXSAhPSB2b2lkIDAgJiYgc2VsZi5mZHNbbmV3X2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBvbGRfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX3B0ciArIG9sZF9wYXRoX2xlbikpOwogICAgICAgIGNvbnN0IG5ld19wYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfcHRyICsgbmV3X3BhdGhfbGVuKSk7CiAgICAgICAgY29uc3QgeyByZXQsIGlub2RlX29iaiB9ID0gc2VsZi5mZHNbb2xkX2ZkXS5wYXRoX2xvb2t1cChvbGRfcGF0aCwgb2xkX2ZsYWdzKTsKICAgICAgICBpZiAoaW5vZGVfb2JqID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHJldHVybiBzZWxmLmZkc1tuZXdfZmRdLnBhdGhfbGluayhuZXdfcGF0aCwgaW5vZGVfb2JqLCBmYWxzZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfb3BlbihmZCwgZGlyZmxhZ3MsIHBhdGhfcHRyLCBwYXRoX2xlbiwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzLCBvcGVuZWRfZmRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICBkZWJ1Zy5sb2cocGF0aCk7CiAgICAgICAgY29uc3QgeyByZXQsIGZkX29iaiB9ID0gc2VsZi5mZHNbZmRdLnBhdGhfb3BlbihkaXJmbGFncywgcGF0aCwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzKTsKICAgICAgICBpZiAocmV0ICE9IDApIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHNlbGYuZmRzLnB1c2goZmRfb2JqKTsKICAgICAgICBjb25zdCBvcGVuZWRfZmQgPSBzZWxmLmZkcy5sZW5ndGggLSAxOwogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIob3BlbmVkX2ZkX3B0ciwgb3BlbmVkX2ZkLCB0cnVlKTsKICAgICAgICByZXR1cm4gMDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9yZWFkbGluayhmZCwgcGF0aF9wdHIsIHBhdGhfbGVuLCBidWZfcHRyLCBidWZfbGVuLCBucmVhZF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIGRlYnVnLmxvZyhwYXRoKTsKICAgICAgICBjb25zdCB7IHJldCwgZGF0YSB9ID0gc2VsZi5mZHNbZmRdLnBhdGhfcmVhZGxpbmsocGF0aCk7CiAgICAgICAgaWYgKGRhdGEgIT0gbnVsbCkgewogICAgICAgICAgY29uc3QgZGF0YV9idWYgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoZGF0YSk7CiAgICAgICAgICBpZiAoZGF0YV9idWYubGVuZ3RoID4gYnVmX2xlbikgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgMCwgdHJ1ZSk7CiAgICAgICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICAgICAgfQogICAgICAgICAgYnVmZmVyOC5zZXQoZGF0YV9idWYsIGJ1Zl9wdHIpOwogICAgICAgICAgYnVmZmVyLnNldFVpbnQzMihucmVhZF9wdHIsIGRhdGFfYnVmLmxlbmd0aCwgdHJ1ZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfcmVtb3ZlX2RpcmVjdG9yeShmZCwgcGF0aF9wdHIsIHBhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5wYXRoX3JlbW92ZV9kaXJlY3RvcnkocGF0aCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfcmVuYW1lKGZkLCBvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX2xlbiwgbmV3X2ZkLCBuZXdfcGF0aF9wdHIsIG5ld19wYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwICYmIHNlbGYuZmRzW25ld19mZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3Qgb2xkX3BhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9wdHIgKyBvbGRfcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCBuZXdfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShuZXdfcGF0aF9wdHIsIG5ld19wYXRoX3B0ciArIG5ld19wYXRoX2xlbikpOwogICAgICAgIGxldCB7IHJldCwgaW5vZGVfb2JqIH0gPSBzZWxmLmZkc1tmZF0ucGF0aF91bmxpbmsob2xkX3BhdGgpOwogICAgICAgIGlmIChpbm9kZV9vYmogPT0gbnVsbCkgewogICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9CiAgICAgICAgcmV0ID0gc2VsZi5mZHNbbmV3X2ZkXS5wYXRoX2xpbmsobmV3X3BhdGgsIGlub2RlX29iaiwgdHJ1ZSk7CiAgICAgICAgaWYgKHJldCAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICBpZiAoc2VsZi5mZHNbZmRdLnBhdGhfbGluayhvbGRfcGF0aCwgaW5vZGVfb2JqLCB0cnVlKSAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICAgIHRocm93ICJwYXRoX2xpbmsgc2hvdWxkIGFsd2F5cyByZXR1cm4gc3VjY2VzcyB3aGVuIHJlbGlua2luZyBhbiBpbm9kZSBiYWNrIHRvIHRoZSBvcmlnaW5hbCBwbGFjZSI7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfc3ltbGluayhvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX2xlbiwgZmQsIG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBvbGRfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX3B0ciArIG9sZF9wYXRoX2xlbikpOwogICAgICAgIGNvbnN0IG5ld19wYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfcHRyICsgbmV3X3BhdGhfbGVuKSk7CiAgICAgICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF91bmxpbmtfZmlsZShmZCwgcGF0aF9wdHIsIHBhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5wYXRoX3VubGlua19maWxlKHBhdGgpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwb2xsX29uZW9mZihpbl8sIG91dCwgbnN1YnNjcmlwdGlvbnMpIHsKICAgICAgdGhyb3cgImFzeW5jIGlvIG5vdCBzdXBwb3J0ZWQiOwogICAgfSwgcHJvY19leGl0KGV4aXRfY29kZSkgewogICAgICB0aHJvdyBuZXcgV0FTSVByb2NFeGl0KGV4aXRfY29kZSk7CiAgICB9LCBwcm9jX3JhaXNlKHNpZykgewogICAgICB0aHJvdyAicmFpc2VkIHNpZ25hbCAiICsgc2lnOwogICAgfSwgc2NoZWRfeWllbGQoKSB7CiAgICB9LCByYW5kb21fZ2V0KGJ1ZiwgYnVmX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYnVmX2xlbjsgaSsrKSB7CiAgICAgICAgYnVmZmVyOFtidWYgKyBpXSA9IE1hdGgucmFuZG9tKCkgKiAyNTYgfCAwOwogICAgICB9CiAgICB9LCBzb2NrX3JlY3YoZmQsIHJpX2RhdGEsIHJpX2ZsYWdzKSB7CiAgICAgIHRocm93ICJzb2NrZXRzIG5vdCBzdXBwb3J0ZWQiOwogICAgfSwgc29ja19zZW5kKGZkLCBzaV9kYXRhLCBzaV9mbGFncykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHNvY2tfc2h1dGRvd24oZmQsIGhvdykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHNvY2tfYWNjZXB0KGZkLCBmbGFncykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0gfTsKICB9Cn07CgovLyBub2RlX21vZHVsZXMvQGJqb3JuMy9icm93c2VyX3dhc2lfc2hpbS9kaXN0L2ZkLmpzCnZhciBGZCA9IGNsYXNzIHsKICBmZF9hbGxvY2F0ZShvZmZzZXQsIGxlbikgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfY2xvc2UoKSB7CiAgICByZXR1cm4gMDsKICB9CiAgZmRfZmRzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBmZHN0YXQ6IG51bGwgfTsKICB9CiAgZmRfZmRzdGF0X3NldF9mbGFncyhmbGFncykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfZmRzdGF0X3NldF9yaWdodHMoZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nKSB7CiAgICByZXR1cm4gRVJSTk9fTk9UU1VQOwogIH0KICBmZF9maWxlc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZmlsZXN0YXQ6IG51bGwgfTsKICB9CiAgZmRfZmlsZXN0YXRfc2V0X3NpemUoc2l6ZSkgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfZmlsZXN0YXRfc2V0X3RpbWVzKGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfcHJlYWQoc2l6ZSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZGF0YTogbmV3IFVpbnQ4QXJyYXkoKSB9OwogIH0KICBmZF9wcmVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBwcmVzdGF0OiBudWxsIH07CiAgfQogIGZkX3B3cml0ZShkYXRhLCBvZmZzZXQpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBud3JpdHRlbjogMCB9OwogIH0KICBmZF9yZWFkKHNpemUpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBkYXRhOiBuZXcgVWludDhBcnJheSgpIH07CiAgfQogIGZkX3JlYWRkaXJfc2luZ2xlKGNvb2tpZSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGRpcmVudDogbnVsbCB9OwogIH0KICBmZF9zZWVrKG9mZnNldCwgd2hlbmNlKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF9zeW5jKCkgewogICAgcmV0dXJuIDA7CiAgfQogIGZkX3RlbGwoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF93cml0ZShkYXRhKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgbndyaXR0ZW46IDAgfTsKICB9CiAgcGF0aF9jcmVhdGVfZGlyZWN0b3J5KHBhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfZmlsZXN0YXRfZ2V0KGZsYWdzLCBwYXRoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZmlsZXN0YXQ6IG51bGwgfTsKICB9CiAgcGF0aF9maWxlc3RhdF9zZXRfdGltZXMoZmxhZ3MsIHBhdGgsIGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgcGF0aF9saW5rKHBhdGgsIGlub2RlLCBhbGxvd19kaXIpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfdW5saW5rKHBhdGgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBpbm9kZV9vYmo6IG51bGwgfTsKICB9CiAgcGF0aF9sb29rdXAocGF0aCwgZGlyZmxhZ3MpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBpbm9kZV9vYmo6IG51bGwgfTsKICB9CiAgcGF0aF9vcGVuKGRpcmZsYWdzLCBwYXRoLCBvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZywgZmRfZmxhZ3MpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9URElSLCBmZF9vYmo6IG51bGwgfTsKICB9CiAgcGF0aF9yZWFkbGluayhwYXRoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZGF0YTogbnVsbCB9OwogIH0KICBwYXRoX3JlbW92ZV9kaXJlY3RvcnkocGF0aCkgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgcGF0aF9yZW5hbWUob2xkX3BhdGgsIG5ld19mZCwgbmV3X3BhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfdW5saW5rX2ZpbGUocGF0aCkgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9Cn07CnZhciBJbm9kZSA9IGNsYXNzIHsKfTsKCi8vIG5vZGVfbW9kdWxlcy9AYmpvcm4zL2Jyb3dzZXJfd2FzaV9zaGltL2Rpc3QvZnNfbWVtLmpzCnZhciBPcGVuRmlsZSA9IGNsYXNzIGV4dGVuZHMgRmQgewogIGZkX2FsbG9jYXRlKG9mZnNldCwgbGVuKSB7CiAgICBpZiAodGhpcy5maWxlLnNpemUgPiBvZmZzZXQgKyBsZW4pIHsKICAgIH0gZWxzZSB7CiAgICAgIGNvbnN0IG5ld19kYXRhID0gbmV3IFVpbnQ4QXJyYXkoTnVtYmVyKG9mZnNldCArIGxlbikpOwogICAgICBuZXdfZGF0YS5zZXQodGhpcy5maWxlLmRhdGEsIDApOwogICAgICB0aGlzLmZpbGUuZGF0YSA9IG5ld19kYXRhOwogICAgfQogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIGZkc3RhdDogbmV3IEZkc3RhdChGSUxFVFlQRV9SRUdVTEFSX0ZJTEUsIDApIH07CiAgfQogIGZkX2ZpbGVzdGF0X3NldF9zaXplKHNpemUpIHsKICAgIGlmICh0aGlzLmZpbGUuc2l6ZSA+IHNpemUpIHsKICAgICAgdGhpcy5maWxlLmRhdGEgPSBuZXcgVWludDhBcnJheSh0aGlzLmZpbGUuZGF0YS5idWZmZXIuc2xpY2UoMCwgTnVtYmVyKHNpemUpKSk7CiAgICB9IGVsc2UgewogICAgICBjb25zdCBuZXdfZGF0YSA9IG5ldyBVaW50OEFycmF5KE51bWJlcihzaXplKSk7CiAgICAgIG5ld19kYXRhLnNldCh0aGlzLmZpbGUuZGF0YSwgMCk7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3X2RhdGE7CiAgICB9CiAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICB9CiAgZmRfcmVhZChzaXplKSB7CiAgICBjb25zdCBzbGljZSA9IHRoaXMuZmlsZS5kYXRhLnNsaWNlKE51bWJlcih0aGlzLmZpbGVfcG9zKSwgTnVtYmVyKHRoaXMuZmlsZV9wb3MgKyBCaWdJbnQoc2l6ZSkpKTsKICAgIHRoaXMuZmlsZV9wb3MgKz0gQmlnSW50KHNsaWNlLmxlbmd0aCk7CiAgICByZXR1cm4geyByZXQ6IDAsIGRhdGE6IHNsaWNlIH07CiAgfQogIGZkX3ByZWFkKHNpemUsIG9mZnNldCkgewogICAgY29uc3Qgc2xpY2UgPSB0aGlzLmZpbGUuZGF0YS5zbGljZShOdW1iZXIob2Zmc2V0KSwgTnVtYmVyKG9mZnNldCArIEJpZ0ludChzaXplKSkpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBkYXRhOiBzbGljZSB9OwogIH0KICBmZF9zZWVrKG9mZnNldCwgd2hlbmNlKSB7CiAgICBsZXQgY2FsY3VsYXRlZF9vZmZzZXQ7CiAgICBzd2l0Y2ggKHdoZW5jZSkgewogICAgICBjYXNlIFdIRU5DRV9TRVQ6CiAgICAgICAgY2FsY3VsYXRlZF9vZmZzZXQgPSBvZmZzZXQ7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgV0hFTkNFX0NVUjoKICAgICAgICBjYWxjdWxhdGVkX29mZnNldCA9IHRoaXMuZmlsZV9wb3MgKyBvZmZzZXQ7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgV0hFTkNFX0VORDoKICAgICAgICBjYWxjdWxhdGVkX29mZnNldCA9IEJpZ0ludCh0aGlzLmZpbGUuZGF0YS5ieXRlTGVuZ3RoKSArIG9mZnNldDsKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0lOVkFMLCBvZmZzZXQ6IDBuIH07CiAgICB9CiAgICBpZiAoY2FsY3VsYXRlZF9vZmZzZXQgPCAwKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fSU5WQUwsIG9mZnNldDogMG4gfTsKICAgIH0KICAgIHRoaXMuZmlsZV9wb3MgPSBjYWxjdWxhdGVkX29mZnNldDsKICAgIHJldHVybiB7IHJldDogMCwgb2Zmc2V0OiB0aGlzLmZpbGVfcG9zIH07CiAgfQogIGZkX3RlbGwoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIG9mZnNldDogdGhpcy5maWxlX3BvcyB9OwogIH0KICBmZF93cml0ZShkYXRhKSB7CiAgICBpZiAodGhpcy5maWxlLnJlYWRvbmx5KQogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG53cml0dGVuOiAwIH07CiAgICBpZiAodGhpcy5maWxlX3BvcyArIEJpZ0ludChkYXRhLmJ5dGVMZW5ndGgpID4gdGhpcy5maWxlLnNpemUpIHsKICAgICAgY29uc3Qgb2xkID0gdGhpcy5maWxlLmRhdGE7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoTnVtYmVyKHRoaXMuZmlsZV9wb3MgKyBCaWdJbnQoZGF0YS5ieXRlTGVuZ3RoKSkpOwogICAgICB0aGlzLmZpbGUuZGF0YS5zZXQob2xkKTsKICAgIH0KICAgIHRoaXMuZmlsZS5kYXRhLnNldChkYXRhLCBOdW1iZXIodGhpcy5maWxlX3BvcykpOwogICAgdGhpcy5maWxlX3BvcyArPSBCaWdJbnQoZGF0YS5ieXRlTGVuZ3RoKTsKICAgIHJldHVybiB7IHJldDogMCwgbndyaXR0ZW46IGRhdGEuYnl0ZUxlbmd0aCB9OwogIH0KICBmZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KSB7CiAgICBpZiAodGhpcy5maWxlLnJlYWRvbmx5KQogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG53cml0dGVuOiAwIH07CiAgICBpZiAob2Zmc2V0ICsgQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCkgPiB0aGlzLmZpbGUuc2l6ZSkgewogICAgICBjb25zdCBvbGQgPSB0aGlzLmZpbGUuZGF0YTsKICAgICAgdGhpcy5maWxlLmRhdGEgPSBuZXcgVWludDhBcnJheShOdW1iZXIob2Zmc2V0ICsgQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCkpKTsKICAgICAgdGhpcy5maWxlLmRhdGEuc2V0KG9sZCk7CiAgICB9CiAgICB0aGlzLmZpbGUuZGF0YS5zZXQoZGF0YSwgTnVtYmVyKG9mZnNldCkpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBud3JpdHRlbjogZGF0YS5ieXRlTGVuZ3RoIH07CiAgfQogIGZkX2ZpbGVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgZmlsZXN0YXQ6IHRoaXMuZmlsZS5zdGF0KCkgfTsKICB9CiAgY29uc3RydWN0b3IoZmlsZSkgewogICAgc3VwZXIoKTsKICAgIHRoaXMuZmlsZV9wb3MgPSAwbjsKICAgIHRoaXMuZmlsZSA9IGZpbGU7CiAgfQp9Owp2YXIgT3BlbkRpcmVjdG9yeSA9IGNsYXNzIGV4dGVuZHMgRmQgewogIGZkX3NlZWsob2Zmc2V0LCB3aGVuY2UpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fQkFERiwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF90ZWxsKCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBvZmZzZXQ6IDBuIH07CiAgfQogIGZkX2FsbG9jYXRlKG9mZnNldCwgbGVuKSB7CiAgICByZXR1cm4gRVJSTk9fQkFERjsKICB9CiAgZmRfZmRzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgZmRzdGF0OiBuZXcgRmRzdGF0KEZJTEVUWVBFX0RJUkVDVE9SWSwgMCkgfTsKICB9CiAgZmRfcmVhZGRpcl9zaW5nbGUoY29va2llKSB7CiAgICBpZiAoZGVidWcuZW5hYmxlZCkgewogICAgICBkZWJ1Zy5sb2coInJlYWRkaXJfc2luZ2xlIiwgY29va2llKTsKICAgICAgZGVidWcubG9nKGNvb2tpZSwgdGhpcy5kaXIuY29udGVudHMua2V5cygpKTsKICAgIH0KICAgIGlmIChjb29raWUgPT0gMG4pIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBkaXJlbnQ6IG5ldyBEaXJlbnQoMW4sICIuIiwgRklMRVRZUEVfRElSRUNUT1JZKSB9OwogICAgfSBlbHNlIGlmIChjb29raWUgPT0gMW4pIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBkaXJlbnQ6IG5ldyBEaXJlbnQoMm4sICIuLiIsIEZJTEVUWVBFX0RJUkVDVE9SWSkgfTsKICAgIH0KICAgIGlmIChjb29raWUgPj0gQmlnSW50KHRoaXMuZGlyLmNvbnRlbnRzLnNpemUpICsgMm4pIHsKICAgICAgcmV0dXJuIHsgcmV0OiAwLCBkaXJlbnQ6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IFtuYW1lLCBlbnRyeV0gPSBBcnJheS5mcm9tKHRoaXMuZGlyLmNvbnRlbnRzLmVudHJpZXMoKSlbTnVtYmVyKGNvb2tpZSAtIDJuKV07CiAgICByZXR1cm4geyByZXQ6IDAsIGRpcmVudDogbmV3IERpcmVudChjb29raWUgKyAxbiwgbmFtZSwgZW50cnkuc3RhdCgpLmZpbGV0eXBlKSB9OwogIH0KICBwYXRoX2ZpbGVzdGF0X2dldChmbGFncywgcGF0aF9zdHIpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX2VyciwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX2VyciwgZmlsZXN0YXQ6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0LCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0LCBmaWxlc3RhdDogbnVsbCB9OwogICAgfQogICAgcmV0dXJuIHsgcmV0OiAwLCBmaWxlc3RhdDogZW50cnkuc3RhdCgpIH07CiAgfQogIHBhdGhfbG9va3VwKHBhdGhfc3RyLCBkaXJmbGFncykgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhdGhfcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0LCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgaW5vZGVfb2JqOiBlbnRyeSB9OwogIH0KICBwYXRoX29wZW4oZGlyZmxhZ3MsIHBhdGhfc3RyLCBvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZywgZmRfZmxhZ3MpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX3JldCwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX3JldCwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICBsZXQgeyByZXQsIGVudHJ5IH0gPSB0aGlzLmRpci5nZXRfZW50cnlfZm9yX3BhdGgocGF0aCk7CiAgICBpZiAoZW50cnkgPT0gbnVsbCkgewogICAgICBpZiAocmV0ICE9IEVSUk5PX05PRU5UKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0LCBmZF9vYmo6IG51bGwgfTsKICAgICAgfQogICAgICBpZiAoKG9mbGFncyAmIE9GTEFHU19DUkVBVCkgPT0gT0ZMQUdTX0NSRUFUKSB7CiAgICAgICAgY29uc3QgeyByZXQ6IHJldDIsIGVudHJ5OiBuZXdfZW50cnkgfSA9IHRoaXMuZGlyLmNyZWF0ZV9lbnRyeV9mb3JfcGF0aChwYXRoX3N0ciwgKG9mbGFncyAmIE9GTEFHU19ESVJFQ1RPUlkpID09IE9GTEFHU19ESVJFQ1RPUlkpOwogICAgICAgIGlmIChuZXdfZW50cnkgPT0gbnVsbCkgewogICAgICAgICAgcmV0dXJuIHsgcmV0OiByZXQyLCBmZF9vYmo6IG51bGwgfTsKICAgICAgICB9CiAgICAgICAgZW50cnkgPSBuZXdfZW50cnk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT0VOVCwgZmRfb2JqOiBudWxsIH07CiAgICAgIH0KICAgIH0gZWxzZSBpZiAoKG9mbGFncyAmIE9GTEFHU19FWENMKSA9PSBPRkxBR1NfRVhDTCkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0VYSVNULCBmZF9vYmo6IG51bGwgfTsKICAgIH0KICAgIGlmICgob2ZsYWdzICYgT0ZMQUdTX0RJUkVDVE9SWSkgPT0gT0ZMQUdTX0RJUkVDVE9SWSAmJiBlbnRyeS5zdGF0KCkuZmlsZXR5cGUgIT09IEZJTEVUWVBFX0RJUkVDVE9SWSkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICByZXR1cm4gZW50cnkucGF0aF9vcGVuKG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZkX2ZsYWdzKTsKICB9CiAgcGF0aF9jcmVhdGVfZGlyZWN0b3J5KHBhdGgpIHsKICAgIHJldHVybiB0aGlzLnBhdGhfb3BlbigwLCBwYXRoLCBPRkxBR1NfQ1JFQVQgfCBPRkxBR1NfRElSRUNUT1JZLCAwbiwgMG4sIDApLnJldDsKICB9CiAgcGF0aF9saW5rKHBhdGhfc3RyLCBpbm9kZSwgYWxsb3dfZGlyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXRoX3JldDsKICAgIH0KICAgIGlmIChwYXRoLmlzX2RpcikgewogICAgICByZXR1cm4gRVJSTk9fTk9FTlQ7CiAgICB9CiAgICBjb25zdCB7IHJldDogcGFyZW50X3JldCwgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9wYXJlbnRfZGlyX2FuZF9lbnRyeV9mb3JfcGF0aChwYXRoLCB0cnVlKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCB8fCBmaWxlbmFtZSA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXJlbnRfcmV0OwogICAgfQogICAgaWYgKGVudHJ5ICE9IG51bGwpIHsKICAgICAgY29uc3Qgc291cmNlX2lzX2RpciA9IGlub2RlLnN0YXQoKS5maWxldHlwZSA9PSBGSUxFVFlQRV9ESVJFQ1RPUlk7CiAgICAgIGNvbnN0IHRhcmdldF9pc19kaXIgPSBlbnRyeS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfRElSRUNUT1JZOwogICAgICBpZiAoc291cmNlX2lzX2RpciAmJiB0YXJnZXRfaXNfZGlyKSB7CiAgICAgICAgaWYgKGFsbG93X2RpciAmJiBlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkgewogICAgICAgICAgaWYgKGVudHJ5LmNvbnRlbnRzLnNpemUgPT0gMCkgewogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcmV0dXJuIEVSUk5PX05PVEVNUFRZOwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXR1cm4gRVJSTk9fRVhJU1Q7CiAgICAgICAgfQogICAgICB9IGVsc2UgaWYgKHNvdXJjZV9pc19kaXIgJiYgIXRhcmdldF9pc19kaXIpIHsKICAgICAgICByZXR1cm4gRVJSTk9fTk9URElSOwogICAgICB9IGVsc2UgaWYgKCFzb3VyY2VfaXNfZGlyICYmIHRhcmdldF9pc19kaXIpIHsKICAgICAgICByZXR1cm4gRVJSTk9fSVNESVI7CiAgICAgIH0gZWxzZSBpZiAoaW5vZGUuc3RhdCgpLmZpbGV0eXBlID09IEZJTEVUWVBFX1JFR1VMQVJfRklMRSAmJiBlbnRyeS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfUkVHVUxBUl9GSUxFKSB7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0VYSVNUOwogICAgICB9CiAgICB9CiAgICBpZiAoIWFsbG93X2RpciAmJiBpbm9kZS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgIHJldHVybiBFUlJOT19QRVJNOwogICAgfQogICAgcGFyZW50X2VudHJ5LmNvbnRlbnRzLnNldChmaWxlbmFtZSwgaW5vZGUpOwogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIHBhdGhfdW5saW5rKHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogcGF0aF9yZXQsIGlub2RlX29iajogbnVsbCB9OwogICAgfQogICAgY29uc3QgeyByZXQ6IHBhcmVudF9yZXQsIHBhcmVudF9lbnRyeSwgZmlsZW5hbWUsIGVudHJ5IH0gPSB0aGlzLmRpci5nZXRfcGFyZW50X2Rpcl9hbmRfZW50cnlfZm9yX3BhdGgocGF0aCwgdHJ1ZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhcmVudF9yZXQsIGlub2RlX29iajogbnVsbCB9OwogICAgfQogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT0VOVCwgaW5vZGVfb2JqOiBudWxsIH07CiAgICB9CiAgICBwYXJlbnRfZW50cnkuY29udGVudHMuZGVsZXRlKGZpbGVuYW1lKTsKICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgaW5vZGVfb2JqOiBlbnRyeSB9OwogIH0KICBwYXRoX3VubGlua19maWxlKHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXRoX3JldDsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIGZhbHNlKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCB8fCBmaWxlbmFtZSA9PSBudWxsIHx8IGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHBhcmVudF9yZXQ7CiAgICB9CiAgICBpZiAoZW50cnkuc3RhdCgpLmZpbGV0eXBlID09PSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgcmV0dXJuIEVSUk5PX0lTRElSOwogICAgfQogICAgcGFyZW50X2VudHJ5LmNvbnRlbnRzLmRlbGV0ZShmaWxlbmFtZSk7CiAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICB9CiAgcGF0aF9yZW1vdmVfZGlyZWN0b3J5KHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXRoX3JldDsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIGZhbHNlKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCB8fCBmaWxlbmFtZSA9PSBudWxsIHx8IGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHBhcmVudF9yZXQ7CiAgICB9CiAgICBpZiAoIShlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkgfHwgZW50cnkuc3RhdCgpLmZpbGV0eXBlICE9PSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgcmV0dXJuIEVSUk5PX05PVERJUjsKICAgIH0KICAgIGlmIChlbnRyeS5jb250ZW50cy5zaXplICE9PSAwKSB7CiAgICAgIHJldHVybiBFUlJOT19OT1RFTVBUWTsKICAgIH0KICAgIGlmICghcGFyZW50X2VudHJ5LmNvbnRlbnRzLmRlbGV0ZShmaWxlbmFtZSkpIHsKICAgICAgcmV0dXJuIEVSUk5PX05PRU5UOwogICAgfQogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIGZkX2ZpbGVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgZmlsZXN0YXQ6IHRoaXMuZGlyLnN0YXQoKSB9OwogIH0KICBmZF9maWxlc3RhdF9zZXRfc2l6ZShzaXplKSB7CiAgICByZXR1cm4gRVJSTk9fQkFERjsKICB9CiAgZmRfcmVhZChzaXplKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIGRhdGE6IG5ldyBVaW50OEFycmF5KCkgfTsKICB9CiAgZmRfcHJlYWQoc2l6ZSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIGRhdGE6IG5ldyBVaW50OEFycmF5KCkgfTsKICB9CiAgZmRfd3JpdGUoZGF0YSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBud3JpdHRlbjogMCB9OwogIH0KICBmZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG53cml0dGVuOiAwIH07CiAgfQogIGNvbnN0cnVjdG9yKGRpcikgewogICAgc3VwZXIoKTsKICAgIHRoaXMuZGlyID0gZGlyOwogIH0KfTsKdmFyIFByZW9wZW5EaXJlY3RvcnkgPSBjbGFzcyBleHRlbmRzIE9wZW5EaXJlY3RvcnkgewogIGZkX3ByZXN0YXRfZ2V0KCkgewogICAgcmV0dXJuIHsgcmV0OiAwLCBwcmVzdGF0OiBQcmVzdGF0LmRpcih0aGlzLnByZXN0YXRfbmFtZSkgfTsKICB9CiAgY29uc3RydWN0b3IobmFtZSwgY29udGVudHMpIHsKICAgIHN1cGVyKG5ldyBEaXJlY3RvcnkoY29udGVudHMpKTsKICAgIHRoaXMucHJlc3RhdF9uYW1lID0gbmFtZTsKICB9Cn07CnZhciBGaWxlID0gY2xhc3MgZXh0ZW5kcyBJbm9kZSB7CiAgcGF0aF9vcGVuKG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZkX2ZsYWdzKSB7CiAgICBpZiAodGhpcy5yZWFkb25seSAmJiAoZnNfcmlnaHRzX2Jhc2UgJiBCaWdJbnQoUklHSFRTX0ZEX1dSSVRFKSkgPT0gQmlnSW50KFJJR0hUU19GRF9XUklURSkpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19QRVJNLCBmZF9vYmo6IG51bGwgfTsKICAgIH0KICAgIGlmICgob2ZsYWdzICYgT0ZMQUdTX1RSVU5DKSA9PSBPRkxBR1NfVFJVTkMpIHsKICAgICAgaWYgKHRoaXMucmVhZG9ubHkpCiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19QRVJNLCBmZF9vYmo6IG51bGwgfTsKICAgICAgdGhpcy5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoW10pOwogICAgfQogICAgY29uc3QgZmlsZSA9IG5ldyBPcGVuRmlsZSh0aGlzKTsKICAgIGlmIChmZF9mbGFncyAmIEZERkxBR1NfQVBQRU5EKQogICAgICBmaWxlLmZkX3NlZWsoMG4sIFdIRU5DRV9FTkQpOwogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBmZF9vYmo6IGZpbGUgfTsKICB9CiAgZ2V0IHNpemUoKSB7CiAgICByZXR1cm4gQmlnSW50KHRoaXMuZGF0YS5ieXRlTGVuZ3RoKTsKICB9CiAgc3RhdCgpIHsKICAgIHJldHVybiBuZXcgRmlsZXN0YXQoRklMRVRZUEVfUkVHVUxBUl9GSUxFLCB0aGlzLnNpemUpOwogIH0KICBjb25zdHJ1Y3RvcihkYXRhLCBvcHRpb25zKSB7CiAgICBzdXBlcigpOwogICAgdGhpcy5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoZGF0YSk7CiAgICB0aGlzLnJlYWRvbmx5ID0gISFvcHRpb25zPy5yZWFkb25seTsKICB9Cn07CnZhciBQYXRoID0gY2xhc3MgUGF0aDIgewogIHN0YXRpYyBmcm9tKHBhdGgpIHsKICAgIGNvbnN0IHNlbGYgPSBuZXcgUGF0aDIoKTsKICAgIHNlbGYuaXNfZGlyID0gcGF0aC5lbmRzV2l0aCgiLyIpOwogICAgaWYgKHBhdGguc3RhcnRzV2l0aCgiLyIpKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UQ0FQQUJMRSwgcGF0aDogbnVsbCB9OwogICAgfQogICAgaWYgKHBhdGguaW5jbHVkZXMoIlwwIikpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19JTlZBTCwgcGF0aDogbnVsbCB9OwogICAgfQogICAgZm9yIChjb25zdCBjb21wb25lbnQgb2YgcGF0aC5zcGxpdCgiLyIpKSB7CiAgICAgIGlmIChjb21wb25lbnQgPT09ICIiIHx8IGNvbXBvbmVudCA9PT0gIi4iKSB7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgaWYgKGNvbXBvbmVudCA9PT0gIi4uIikgewogICAgICAgIGlmIChzZWxmLnBhcnRzLnBvcCgpID09IHZvaWQgMCkgewogICAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RDQVBBQkxFLCBwYXRoOiBudWxsIH07CiAgICAgICAgfQogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIHNlbGYucGFydHMucHVzaChjb21wb25lbnQpOwogICAgfQogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBwYXRoOiBzZWxmIH07CiAgfQogIHRvX3BhdGhfc3RyaW5nKCkgewogICAgbGV0IHMgPSB0aGlzLnBhcnRzLmpvaW4oIi8iKTsKICAgIGlmICh0aGlzLmlzX2RpcikgewogICAgICBzICs9ICIvIjsKICAgIH0KICAgIHJldHVybiBzOwogIH0KICBjb25zdHJ1Y3RvcigpIHsKICAgIHRoaXMucGFydHMgPSBbXTsKICAgIHRoaXMuaXNfZGlyID0gZmFsc2U7CiAgfQp9Owp2YXIgRGlyZWN0b3J5ID0gY2xhc3MgZXh0ZW5kcyBJbm9kZSB7CiAgcGF0aF9vcGVuKG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZkX2ZsYWdzKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGZkX29iajogbmV3IE9wZW5EaXJlY3RvcnkodGhpcykgfTsKICB9CiAgc3RhdCgpIHsKICAgIHJldHVybiBuZXcgRmlsZXN0YXQoRklMRVRZUEVfRElSRUNUT1JZLCAwbik7CiAgfQogIGdldF9lbnRyeV9mb3JfcGF0aChwYXRoKSB7CiAgICBsZXQgZW50cnkgPSB0aGlzOwogICAgZm9yIChjb25zdCBjb21wb25lbnQgb2YgcGF0aC5wYXJ0cykgewogICAgICBpZiAoIShlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkpIHsKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgICBjb25zdCBjaGlsZCA9IGVudHJ5LmNvbnRlbnRzLmdldChjb21wb25lbnQpOwogICAgICBpZiAoY2hpbGQgIT09IHZvaWQgMCkgewogICAgICAgIGVudHJ5ID0gY2hpbGQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgZGVidWcubG9nKGNvbXBvbmVudCk7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT0VOVCwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgfQogICAgaWYgKHBhdGguaXNfZGlyKSB7CiAgICAgIGlmIChlbnRyeS5zdGF0KCkuZmlsZXR5cGUgIT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIGVudHJ5OiBudWxsIH07CiAgICAgIH0KICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZW50cnkgfTsKICB9CiAgZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIGFsbG93X3VuZGVmaW5lZCkgewogICAgY29uc3QgZmlsZW5hbWUgPSBwYXRoLnBhcnRzLnBvcCgpOwogICAgaWYgKGZpbGVuYW1lID09PSB2b2lkIDApIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19JTlZBTCwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBlbnRyeV9yZXQsIGVudHJ5OiBwYXJlbnRfZW50cnkgfSA9IHRoaXMuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKHBhcmVudF9lbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogZW50cnlfcmV0LCBwYXJlbnRfZW50cnk6IG51bGwsIGZpbGVuYW1lOiBudWxsLCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgaWYgKCEocGFyZW50X2VudHJ5IGluc3RhbmNlb2YgRGlyZWN0b3J5KSkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IGVudHJ5ID0gcGFyZW50X2VudHJ5LmNvbnRlbnRzLmdldChmaWxlbmFtZSk7CiAgICBpZiAoZW50cnkgPT09IHZvaWQgMCkgewogICAgICBpZiAoIWFsbG93X3VuZGVmaW5lZCkgewogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9FTlQsIHBhcmVudF9lbnRyeTogbnVsbCwgZmlsZW5hbWU6IG51bGwsIGVudHJ5OiBudWxsIH07CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeTogbnVsbCB9OwogICAgICB9CiAgICB9CiAgICBpZiAocGF0aC5pc19kaXIpIHsKICAgICAgaWYgKGVudHJ5LnN0YXQoKS5maWxldHlwZSAhPSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9OwogIH0KICBjcmVhdGVfZW50cnlfZm9yX3BhdGgocGF0aF9zdHIsIGlzX2RpcikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhdGhfcmV0LCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgbGV0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5nZXRfcGFyZW50X2Rpcl9hbmRfZW50cnlfZm9yX3BhdGgocGF0aCwgdHJ1ZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhcmVudF9yZXQsIGVudHJ5OiBudWxsIH07CiAgICB9CiAgICBpZiAoZW50cnkgIT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0VYSVNULCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgZGVidWcubG9nKCJjcmVhdGUiLCBwYXRoKTsKICAgIGxldCBuZXdfY2hpbGQ7CiAgICBpZiAoIWlzX2RpcikgewogICAgICBuZXdfY2hpbGQgPSBuZXcgRmlsZShuZXcgQXJyYXlCdWZmZXIoMCkpOwogICAgfSBlbHNlIHsKICAgICAgbmV3X2NoaWxkID0gbmV3IERpcmVjdG9yeSgvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpKTsKICAgIH0KICAgIHBhcmVudF9lbnRyeS5jb250ZW50cy5zZXQoZmlsZW5hbWUsIG5ld19jaGlsZCk7CiAgICBlbnRyeSA9IG5ld19jaGlsZDsKICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZW50cnkgfTsKICB9CiAgY29uc3RydWN0b3IoY29udGVudHMpIHsKICAgIHN1cGVyKCk7CiAgICBpZiAoY29udGVudHMgaW5zdGFuY2VvZiBBcnJheSkgewogICAgICB0aGlzLmNvbnRlbnRzID0gbmV3IE1hcChjb250ZW50cyk7CiAgICB9IGVsc2UgewogICAgICB0aGlzLmNvbnRlbnRzID0gY29udGVudHM7CiAgICB9CiAgfQp9Owp2YXIgQ29uc29sZVN0ZG91dCA9IGNsYXNzIGV4dGVuZHMgRmQgewogIGZkX2ZpbGVzdGF0X2dldCgpIHsKICAgIGNvbnN0IGZpbGVzdGF0ID0gbmV3IEZpbGVzdGF0KEZJTEVUWVBFX0NIQVJBQ1RFUl9ERVZJQ0UsIEJpZ0ludCgwKSk7CiAgICByZXR1cm4geyByZXQ6IDAsIGZpbGVzdGF0IH07CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICBjb25zdCBmZHN0YXQgPSBuZXcgRmRzdGF0KEZJTEVUWVBFX0NIQVJBQ1RFUl9ERVZJQ0UsIDApOwogICAgZmRzdGF0LmZzX3JpZ2h0c19iYXNlID0gQmlnSW50KFJJR0hUU19GRF9XUklURSk7CiAgICByZXR1cm4geyByZXQ6IDAsIGZkc3RhdCB9OwogIH0KICBmZF93cml0ZShkYXRhKSB7CiAgICB0aGlzLndyaXRlKGRhdGEpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBud3JpdHRlbjogZGF0YS5ieXRlTGVuZ3RoIH07CiAgfQogIHN0YXRpYyBsaW5lQnVmZmVyZWQod3JpdGUpIHsKICAgIGNvbnN0IGRlYyA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiLCB7IGZhdGFsOiBmYWxzZSB9KTsKICAgIGxldCBsaW5lX2J1ZiA9ICIiOwogICAgcmV0dXJuIG5ldyBDb25zb2xlU3Rkb3V0KChidWZmZXIpID0+IHsKICAgICAgbGluZV9idWYgKz0gZGVjLmRlY29kZShidWZmZXIsIHsgc3RyZWFtOiB0cnVlIH0pOwogICAgICBjb25zdCBsaW5lcyA9IGxpbmVfYnVmLnNwbGl0KCJcbiIpOwogICAgICBmb3IgKGNvbnN0IFtpLCBsaW5lXSBvZiBsaW5lcy5lbnRyaWVzKCkpIHsKICAgICAgICBpZiAoaSA8IGxpbmVzLmxlbmd0aCAtIDEpIHsKICAgICAgICAgIHdyaXRlKGxpbmUpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBsaW5lX2J1ZiA9IGxpbmU7CiAgICAgICAgfQogICAgICB9CiAgICB9KTsKICB9CiAgY29uc3RydWN0b3Iod3JpdGUpIHsKICAgIHN1cGVyKCk7CiAgICB0aGlzLndyaXRlID0gd3JpdGU7CiAgfQp9OwoKLy8gbm9kZV9tb2R1bGVzL3dhc20taW1wb3J0cy1wYXJzZXIvaW5kZXguanMKZnVuY3Rpb24gcGFyc2VJbXBvcnRzKG1vZHVsZUJ5dGVzKSB7CiAgaWYgKG1vZHVsZUJ5dGVzIGluc3RhbmNlb2YgVWludDhBcnJheSkgewogIH0gZWxzZSBpZiAobW9kdWxlQnl0ZXMgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgewogICAgbW9kdWxlQnl0ZXMgPSBuZXcgVWludDhBcnJheShtb2R1bGVCeXRlcyk7CiAgfSBlbHNlIGlmIChtb2R1bGVCeXRlcy5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgewogICAgbW9kdWxlQnl0ZXMgPSBuZXcgVWludDhBcnJheShtb2R1bGVCeXRlcy5idWZmZXIpOwogIH0gZWxzZSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkFyZ3VtZW50IG11c3QgYmUgYSBidWZmZXIgc291cmNlLCBsaWtlIFVpbnQ4QXJyYXkgb3IgQXJyYXlCdWZmZXIiKTsKICB9CiAgY29uc3QgcGFyc2VTdGF0ZSA9IG5ldyBQYXJzZVN0YXRlKG1vZHVsZUJ5dGVzKTsKICBwYXJzZU1hZ2ljTnVtYmVyKHBhcnNlU3RhdGUpOwogIHBhcnNlVmVyc2lvbihwYXJzZVN0YXRlKTsKICBjb25zdCB0eXBlcyA9IFtdOwogIGNvbnN0IGltcG9ydHMgPSBbXTsKICB3aGlsZSAocGFyc2VTdGF0ZS5oYXNNb3JlQnl0ZXMoKSkgewogICAgY29uc3Qgc2VjdGlvbklkID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogICAgY29uc3Qgc2VjdGlvblNpemUgPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgc3dpdGNoIChzZWN0aW9uSWQpIHsKICAgICAgY2FzZSAxOiB7CiAgICAgICAgY29uc3QgdHlwZUNvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHR5cGVDb3VudDsgaSsrKSB7CiAgICAgICAgICB0eXBlcy5wdXNoKHBhcnNlRnVuY3Rpb25UeXBlKHBhcnNlU3RhdGUpKTsKICAgICAgICB9CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgY2FzZSAyOiB7CiAgICAgICAgY29uc3QgaW1wb3J0Q291bnQgPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW1wb3J0Q291bnQ7IGkrKykgewogICAgICAgICAgY29uc3QgbW9kdWxlID0gcGFyc2VTdGF0ZS5yZWFkTmFtZSgpOwogICAgICAgICAgY29uc3QgbmFtZSA9IHBhcnNlU3RhdGUucmVhZE5hbWUoKTsKICAgICAgICAgIGNvbnN0IHR5cGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgICAgICAgICBzd2l0Y2ggKHR5cGUpIHsKICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJmdW5jdGlvbiIsIHR5cGU6IHR5cGVzW2luZGV4XSB9KTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICAgIGltcG9ydHMucHVzaCh7IG1vZHVsZSwgbmFtZSwga2luZDogInRhYmxlIiwgdHlwZTogcGFyc2VUYWJsZVR5cGUocGFyc2VTdGF0ZSkgfSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJtZW1vcnkiLCB0eXBlOiBwYXJzZUxpbWl0cyhwYXJzZVN0YXRlKSB9KTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgIGltcG9ydHMucHVzaCh7IG1vZHVsZSwgbmFtZSwga2luZDogImdsb2JhbCIsIHR5cGU6IHBhcnNlR2xvYmFsVHlwZShwYXJzZVN0YXRlKSB9KTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gaW1wb3J0IGRlc2NyaXB0b3IgdHlwZSAke3R5cGV9YCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBpbXBvcnRzOwogICAgICB9CiAgICAgIGRlZmF1bHQ6IHsKICAgICAgICBwYXJzZVN0YXRlLnNraXBCeXRlcyhzZWN0aW9uU2l6ZSk7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgIH0KICB9CiAgcmV0dXJuIFtdOwp9CnZhciBQYXJzZVN0YXRlID0gY2xhc3MgewogIGNvbnN0cnVjdG9yKG1vZHVsZUJ5dGVzKSB7CiAgICB0aGlzLm1vZHVsZUJ5dGVzID0gbW9kdWxlQnl0ZXM7CiAgICB0aGlzLm9mZnNldCA9IDA7CiAgICB0aGlzLnRleHREZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpOwogIH0KICBoYXNNb3JlQnl0ZXMoKSB7CiAgICByZXR1cm4gdGhpcy5vZmZzZXQgPCB0aGlzLm1vZHVsZUJ5dGVzLmxlbmd0aDsKICB9CiAgcmVhZEJ5dGUoKSB7CiAgICByZXR1cm4gdGhpcy5tb2R1bGVCeXRlc1t0aGlzLm9mZnNldCsrXTsKICB9CiAgc2tpcEJ5dGVzKGNvdW50KSB7CiAgICB0aGlzLm9mZnNldCArPSBjb3VudDsKICB9CiAgcmVhZFVuc2lnbmVkTEVCMTI4KCkgewogICAgbGV0IHJlc3VsdCA9IDA7CiAgICBsZXQgc2hpZnQgPSAwOwogICAgbGV0IGJ5dGU7CiAgICBkbyB7CiAgICAgIGJ5dGUgPSB0aGlzLnJlYWRCeXRlKCk7CiAgICAgIHJlc3VsdCB8PSAoYnl0ZSAmIDEyNykgPDwgc2hpZnQ7CiAgICAgIHNoaWZ0ICs9IDc7CiAgICB9IHdoaWxlIChieXRlICYgMTI4KTsKICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHJlYWROYW1lKCkgewogICAgY29uc3QgbmFtZUxlbmd0aCA9IHRoaXMucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICBjb25zdCBuYW1lQnl0ZXMgPSB0aGlzLm1vZHVsZUJ5dGVzLnNsaWNlKHRoaXMub2Zmc2V0LCB0aGlzLm9mZnNldCArIG5hbWVMZW5ndGgpOwogICAgY29uc3QgbmFtZSA9IHRoaXMudGV4dERlY29kZXIuZGVjb2RlKG5hbWVCeXRlcyk7CiAgICB0aGlzLm9mZnNldCArPSBuYW1lTGVuZ3RoOwogICAgcmV0dXJuIG5hbWU7CiAgfQogIGFzc2VydEJ5dGVzKGV4cGVjdGVkKSB7CiAgICBjb25zdCBiYXNlT2Zmc2V0ID0gdGhpcy5vZmZzZXQ7CiAgICBjb25zdCBleHBlY3RlZExlbmd0aCA9IGV4cGVjdGVkLmxlbmd0aDsKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZXhwZWN0ZWRMZW5ndGg7IGkrKykgewogICAgICBpZiAodGhpcy5tb2R1bGVCeXRlc1tiYXNlT2Zmc2V0ICsgaV0gIT09IGV4cGVjdGVkW2ldKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCAke2V4cGVjdGVkfSBhdCBvZmZzZXQgJHtiYXNlT2Zmc2V0fWApOwogICAgICB9CiAgICB9CiAgICB0aGlzLm9mZnNldCArPSBleHBlY3RlZExlbmd0aDsKICB9Cn07CmZ1bmN0aW9uIHBhcnNlTWFnaWNOdW1iZXIocGFyc2VTdGF0ZSkgewogIGNvbnN0IGV4cGVjdGVkID0gWzAsIDk3LCAxMTUsIDEwOV07CiAgcGFyc2VTdGF0ZS5hc3NlcnRCeXRlcyhleHBlY3RlZCk7Cn0KZnVuY3Rpb24gcGFyc2VWZXJzaW9uKHBhcnNlU3RhdGUpIHsKICBjb25zdCBleHBlY3RlZCA9IFsxLCAwLCAwLCAwXTsKICBwYXJzZVN0YXRlLmFzc2VydEJ5dGVzKGV4cGVjdGVkKTsKfQpmdW5jdGlvbiBwYXJzZVRhYmxlVHlwZShwYXJzZVN0YXRlKSB7CiAgY29uc3QgZWxlbWVudFR5cGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgbGV0IGVsZW1lbnQ7CiAgc3dpdGNoIChlbGVtZW50VHlwZSkgewogICAgY2FzZSAxMTI6CiAgICAgIGVsZW1lbnQgPSAiZnVuY3JlZiI7CiAgICAgIGJyZWFrOwogICAgY2FzZSAxMTE6CiAgICAgIGVsZW1lbnQgPSAiZXh0ZXJucmVmIjsKICAgICAgYnJlYWs7CiAgICBkZWZhdWx0OgogICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gdGFibGUgZWxlbWVudCB0eXBlICR7ZWxlbWVudFR5cGV9YCk7CiAgfQogIGNvbnN0IHsgbWluaW11bSwgbWF4aW11bSB9ID0gcGFyc2VMaW1pdHMocGFyc2VTdGF0ZSk7CiAgaWYgKG1heGltdW0pIHsKICAgIHJldHVybiB7IGVsZW1lbnQsIG1pbmltdW0sIG1heGltdW0gfTsKICB9IGVsc2UgewogICAgcmV0dXJuIHsgZWxlbWVudCwgbWluaW11bSB9OwogIH0KfQpmdW5jdGlvbiBwYXJzZUxpbWl0cyhwYXJzZVN0YXRlKSB7CiAgY29uc3QgZmxhZ3MgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgY29uc3QgbWluaW11bSA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgY29uc3QgaGFzTWF4aW11bSA9IGZsYWdzICYgMTsKICBjb25zdCBzaGFyZWQgPSAoZmxhZ3MgJiAyKSAhPT0gMDsKICBjb25zdCBpc01lbW9yeTY0ID0gKGZsYWdzICYgNCkgIT09IDA7CiAgY29uc3QgaW5kZXggPSBpc01lbW9yeTY0ID8gImk2NCIgOiAiaTMyIjsKICBpZiAoaGFzTWF4aW11bSkgewogICAgY29uc3QgbWF4aW11bSA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICByZXR1cm4geyBtaW5pbXVtLCBzaGFyZWQsIGluZGV4LCBtYXhpbXVtIH07CiAgfSBlbHNlIHsKICAgIHJldHVybiB7IG1pbmltdW0sIHNoYXJlZCwgaW5kZXggfTsKICB9Cn0KZnVuY3Rpb24gcGFyc2VHbG9iYWxUeXBlKHBhcnNlU3RhdGUpIHsKICBjb25zdCB2YWx1ZSA9IHBhcnNlVmFsdWVUeXBlKHBhcnNlU3RhdGUpOwogIGNvbnN0IG11dGFibGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCkgPT09IDE7CiAgcmV0dXJuIHsgdmFsdWUsIG11dGFibGUgfTsKfQpmdW5jdGlvbiBwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKSB7CiAgY29uc3QgdHlwZSA9IHBhcnNlU3RhdGUucmVhZEJ5dGUoKTsKICBzd2l0Y2ggKHR5cGUpIHsKICAgIGNhc2UgMTI3OgogICAgICByZXR1cm4gImkzMiI7CiAgICBjYXNlIDEyNjoKICAgICAgcmV0dXJuICJpNjQiOwogICAgY2FzZSAxMjU6CiAgICAgIHJldHVybiAiZjMyIjsKICAgIGNhc2UgMTI0OgogICAgICByZXR1cm4gImY2NCI7CiAgICBjYXNlIDExMjoKICAgICAgcmV0dXJuICJmdW5jcmVmIjsKICAgIGNhc2UgMTExOgogICAgICByZXR1cm4gImV4dGVybnJlZiI7CiAgICBjYXNlIDEyMzoKICAgICAgcmV0dXJuICJ2MTI4IjsKICAgIGRlZmF1bHQ6CiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biB2YWx1ZSB0eXBlICR7dHlwZX1gKTsKICB9Cn0KZnVuY3Rpb24gcGFyc2VGdW5jdGlvblR5cGUocGFyc2VTdGF0ZSkgewogIGNvbnN0IGZvcm0gPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgaWYgKGZvcm0gIT09IDk2KSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGZ1bmN0aW9uIHR5cGUgZm9ybSAweDYwLCBnb3QgJHtmb3JtfWApOwogIH0KICBjb25zdCBwYXJhbWV0ZXJzID0gW107CiAgY29uc3QgcGFyYW1ldGVyQ291bnQgPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogIGZvciAobGV0IGkgPSAwOyBpIDwgcGFyYW1ldGVyQ291bnQ7IGkrKykgewogICAgcGFyYW1ldGVycy5wdXNoKHBhcnNlVmFsdWVUeXBlKHBhcnNlU3RhdGUpKTsKICB9CiAgY29uc3QgcmVzdWx0cyA9IFtdOwogIGNvbnN0IHJlc3VsdENvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICBmb3IgKGxldCBpID0gMDsgaSA8IHJlc3VsdENvdW50OyBpKyspIHsKICAgIHJlc3VsdHMucHVzaChwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKSk7CiAgfQogIHJldHVybiB7IHBhcmFtZXRlcnMsIHJlc3VsdHMgfTsKfQoKLy8gbm9kZV9tb2R1bGVzL3dhc20taW1wb3J0cy1wYXJzZXIvcG9seWZpbGwuanMKdmFyIGhhc1dhc21UeXBlUmVmbGVjdGlvblN1cHBvcnQgPSAoKCkgPT4gewogIGNvbnN0IG1vZHVsZUJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoWwogICAgMCwKICAgIDk3LAogICAgMTE1LAogICAgMTA5LAogICAgMSwKICAgIDAsCiAgICAwLAogICAgMCwKICAgIDIsCiAgICA2LAogICAgMSwKICAgIDAsCiAgICAwLAogICAgMiwKICAgIDAsCiAgICAxCiAgXSk7CiAgY29uc3QgbW9kdWxlID0gbmV3IFdlYkFzc2VtYmx5Lk1vZHVsZShtb2R1bGVCeXRlcyk7CiAgY29uc3QgaW1wb3J0cyA9IFdlYkFzc2VtYmx5Lk1vZHVsZS5pbXBvcnRzKG1vZHVsZSk7CiAgY29uc3QgbWVtb3J5SW1wb3J0ID0gaW1wb3J0c1swXTsKICByZXR1cm4gdHlwZW9mIG1lbW9yeUltcG9ydC50eXBlID09PSAib2JqZWN0IjsKfSkoKTsKZnVuY3Rpb24gcG9seWZpbGwoV2ViQXNzZW1ibHkzKSB7CiAgaWYgKGhhc1dhc21UeXBlUmVmbGVjdGlvblN1cHBvcnQpIHsKICAgIHJldHVybiBXZWJBc3NlbWJseTM7CiAgfQogIGNvbnN0IG5ld1dlYkFzc2VtYmx5ID0ge307CiAgZm9yIChjb25zdCBrZXkgaW4gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoV2ViQXNzZW1ibHkzKSkgewogICAgbmV3V2ViQXNzZW1ibHlba2V5XSA9IFdlYkFzc2VtYmx5M1trZXldOwogIH0KICBjb25zdCBwb2x5ZmlsbGVkSW1wb3J0c1N5bWJvbCA9IFN5bWJvbCgicG9seWZpbGxlZEltcG9ydHNTeW1ib2wiKTsKICBjb25zdCBhc3NpZ25JbXBvcnRzID0gKG1vZHVsZSwgc291cmNlQnl0ZXMpID0+IHsKICAgIG1vZHVsZVtwb2x5ZmlsbGVkSW1wb3J0c1N5bWJvbF0gPSBwYXJzZUltcG9ydHMoc291cmNlQnl0ZXMpOwogIH07CiAgY29uc3QgbmV3TW9kdWxlID0gbmV3V2ViQXNzZW1ibHkuTW9kdWxlID0gZnVuY3Rpb24oYnl0ZXMpIHsKICAgIGNvbnN0IG1vZHVsZSA9IG5ldyBXZWJBc3NlbWJseTMuTW9kdWxlKGJ5dGVzKTsKICAgIGFzc2lnbkltcG9ydHMobW9kdWxlLCBieXRlcyk7CiAgICBPYmplY3Quc2V0UHJvdG90eXBlT2YobW9kdWxlLCBuZXdNb2R1bGUucHJvdG90eXBlKTsKICAgIHJldHVybiBtb2R1bGU7CiAgfTsKICBPYmplY3Quc2V0UHJvdG90eXBlT2YobmV3TW9kdWxlLnByb3RvdHlwZSwgV2ViQXNzZW1ibHkzLk1vZHVsZS5wcm90b3R5cGUpOwogIG5ld1dlYkFzc2VtYmx5LmNvbXBpbGUgPSBhc3luYyAoc291cmNlKSA9PiB7CiAgICBjb25zdCBtb2R1bGUgPSBhd2FpdCBXZWJBc3NlbWJseTMuY29tcGlsZShzb3VyY2UpOwogICAgYXNzaWduSW1wb3J0cyhtb2R1bGUsIHNvdXJjZSk7CiAgICByZXR1cm4gbW9kdWxlOwogIH07CiAgaWYgKFdlYkFzc2VtYmx5My5jb21waWxlU3RyZWFtaW5nKSB7CiAgICBuZXdXZWJBc3NlbWJseS5jb21waWxlU3RyZWFtaW5nID0gYXN5bmMgKHNvdXJjZSkgPT4gewogICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHNvdXJjZTsKICAgICAgY29uc3QgY2xvbmUgPSByZXNwb25zZS5jbG9uZSgpOwogICAgICBjb25zdCBtb2R1bGUgPSBhd2FpdCBXZWJBc3NlbWJseTMuY29tcGlsZVN0cmVhbWluZyhyZXNwb25zZSk7CiAgICAgIGFzc2lnbkltcG9ydHMobW9kdWxlLCBuZXcgVWludDhBcnJheShhd2FpdCBjbG9uZS5hcnJheUJ1ZmZlcigpKSk7CiAgICAgIHJldHVybiBtb2R1bGU7CiAgICB9OwogIH0KICBuZXdNb2R1bGUuaW1wb3J0cyA9IChtb2R1bGUpID0+IHsKICAgIGNvbnN0IHBhcnNlZEltcG9ydHMgPSBtb2R1bGVbcG9seWZpbGxlZEltcG9ydHNTeW1ib2xdOwogICAgaWYgKCFwYXJzZWRJbXBvcnRzKSB7CiAgICAgIHJldHVybiBXZWJBc3NlbWJseTMuTW9kdWxlLmltcG9ydHMobW9kdWxlKTsKICAgIH0KICAgIHJldHVybiBwYXJzZWRJbXBvcnRzOwogIH07CiAgcmV0dXJuIG5ld1dlYkFzc2VtYmx5Owp9CgovLyBlbnRyeXBvaW50L2ludHJpbnNpY3MudHMKdmFyIFdlYkFzc2VtYmx5MiA9IHBvbHlmaWxsKGdsb2JhbFRoaXMuV2ViQXNzZW1ibHkpOwp2YXIgTGluZURlY29kZXIgPSBjbGFzcyB7CiAgY29uc3RydWN0b3Iob25MaW5lKSB7CiAgICB0aGlzLmRlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IiwgeyBmYXRhbDogZmFsc2UgfSk7CiAgICB0aGlzLmJ1ZmZlciA9ICIiOwogICAgdGhpcy5vbkxpbmUgPSBvbkxpbmU7CiAgfQogIGRlY29kZXI7CiAgYnVmZmVyOwogIG9uTGluZTsKICBzZW5kKGNodW5rKSB7CiAgICB0aGlzLmJ1ZmZlciArPSB0aGlzLmRlY29kZXIuZGVjb2RlKGNodW5rLCB7IHN0cmVhbTogdHJ1ZSB9KTsKICAgIGNvbnN0IGxpbmVzID0gdGhpcy5idWZmZXIuc3BsaXQoIlxuIik7CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aCAtIDE7IGkrKykgewogICAgICB0aGlzLm9uTGluZShsaW5lc1tpXSk7CiAgICB9CiAgICB0aGlzLmJ1ZmZlciA9IGxpbmVzW2xpbmVzLmxlbmd0aCAtIDFdOwogIH0KfTsKYXN5bmMgZnVuY3Rpb24gaW5zdGFudGlhdGUocmF3T3B0aW9ucywgZXh0cmFXYXNtSW1wb3J0cykgewogIGNvbnN0IG9wdGlvbnMgPSBkZWZhdWx0SW5zdGFudGlhdGlvbk9wdGlvbnMocmF3T3B0aW9ucyk7CiAgbGV0IHN3aWZ0ID0gb3B0aW9ucy5zd2lmdDsKICBpZiAoIXN3aWZ0ICYmIG9wdGlvbnMuU3dpZnRSdW50aW1lKSB7CiAgICBsZXQgc2hhcmVkTWVtb3J5ID0gZmFsc2U7CiAgICBmb3IgKGNvbnN0IGltcG9ydEVudHJ5IG9mIFdlYkFzc2VtYmx5Mi5Nb2R1bGUuaW1wb3J0cyhvcHRpb25zLm1vZHVsZSkpIHsKICAgICAgaWYgKGltcG9ydEVudHJ5Lm1vZHVsZSA9PT0gImVudiIgJiYgaW1wb3J0RW50cnkubmFtZSA9PT0gIm1lbW9yeSIgJiYgaW1wb3J0RW50cnkua2luZCA9PT0gIm1lbW9yeSIpIHsKICAgICAgICBzaGFyZWRNZW1vcnkgPSB0cnVlOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgICBzd2lmdCA9IG5ldyBvcHRpb25zLlN3aWZ0UnVudGltZSh7IHNoYXJlZE1lbW9yeSB9KTsKICB9CiAgbGV0IHN0ZG91dExpbmUgPSB2b2lkIDA7CiAgaWYgKG9wdGlvbnMub25TdGRvdXRMaW5lICE9IG51bGwpIHsKICAgIHN0ZG91dExpbmUgPSBuZXcgTGluZURlY29kZXIob3B0aW9ucy5vblN0ZG91dExpbmUpOwogIH0KICBjb25zdCBzdGRvdXQgPSBuZXcgQ29uc29sZVN0ZG91dCgoY2h1bmspID0+IHsKICAgIG9wdGlvbnMub25TdGRvdXQ/LmNhbGwodm9pZCAwLCBjaHVuayk7CiAgICBzdGRvdXRMaW5lPy5zZW5kKGNodW5rKTsKICB9KTsKICBsZXQgc3RkZXJyTGluZSA9IHZvaWQgMDsKICBpZiAob3B0aW9ucy5vblN0ZGVyckxpbmUgIT0gbnVsbCkgewogICAgc3RkZXJyTGluZSA9IG5ldyBMaW5lRGVjb2RlcihvcHRpb25zLm9uU3RkZXJyTGluZSk7CiAgfQogIGNvbnN0IHN0ZGVyciA9IG5ldyBDb25zb2xlU3Rkb3V0KChjaHVuaykgPT4gewogICAgb3B0aW9ucy5vblN0ZGVycj8uY2FsbCh2b2lkIDAsIGNodW5rKTsKICAgIHN0ZGVyckxpbmU/LnNlbmQoY2h1bmspOwogIH0pOwogIGNvbnN0IGFyZ3MgPSBvcHRpb25zLmFyZ3MgfHwgW107CiAgY29uc3Qgcm9vdEZzID0gb3B0aW9ucy5yb290RnMgfHwgLyogQF9fUFVSRV9fICovIG5ldyBNYXAoKTsKICBjb25zdCBmZHMgPSBbCiAgICBuZXcgT3BlbkZpbGUobmV3IEZpbGUoW10pKSwKICAgIHN0ZG91dCwKICAgIHN0ZGVyciwKICAgIG5ldyBQcmVvcGVuRGlyZWN0b3J5KCIvIiwgcm9vdEZzKQogIF07CiAgY29uc3QgZW52cyA9IG9wdGlvbnMuZW52ID8gT2JqZWN0LmVudHJpZXMob3B0aW9ucy5lbnYpLm1hcCgoW2tleSwgdmFsdWVdKSA9PiBgJHtrZXl9PSR7dmFsdWV9YCkgOiBbXTsKICBjb25zdCB3YXNpID0gbmV3IFdBU0koYXJncywgZW52cywgZmRzLCB7CiAgICBkZWJ1ZzogZmFsc2UKICB9KTsKICBjb25zdCBjcmVhdGVXYXNtSW1wb3J0T2JqZWN0ID0gKGV4dHJhV2FzbUltcG9ydHMyLCBtb2R1bGUpID0+IHsKICAgIGNvbnN0IGltcG9ydE9iamVjdDIgPSB7CiAgICAgIHdhc2lfc25hcHNob3RfcHJldmlldzE6IHdhc2kud2FzaUltcG9ydAogICAgfTsKICAgIGlmIChzd2lmdCkgewogICAgICBpbXBvcnRPYmplY3QyLmphdmFzY3JpcHRfa2l0ID0gc3dpZnQud2FzbUltcG9ydHM7CiAgICB9CiAgICBpZiAoZXh0cmFXYXNtSW1wb3J0czIpIHsKICAgICAgZm9yIChjb25zdCBtb2R1bGVOYW1lIGluIGV4dHJhV2FzbUltcG9ydHMyKSB7CiAgICAgICAgaWYgKCFpbXBvcnRPYmplY3QyW21vZHVsZU5hbWVdKSB7CiAgICAgICAgICBpbXBvcnRPYmplY3QyW21vZHVsZU5hbWVdID0ge307CiAgICAgICAgfQogICAgICAgIGZvciAoY29uc3QgZW50cnkgaW4gZXh0cmFXYXNtSW1wb3J0czJbbW9kdWxlTmFtZV0pIHsKICAgICAgICAgIGltcG9ydE9iamVjdDJbbW9kdWxlTmFtZV1bZW50cnldID0gZXh0cmFXYXNtSW1wb3J0czJbbW9kdWxlTmFtZV1bZW50cnldOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgZm9yIChjb25zdCBfaW1wb3J0RW50cnkgb2YgV2ViQXNzZW1ibHkyLk1vZHVsZS5pbXBvcnRzKG1vZHVsZSkpIHsKICAgICAgY29uc3QgaW1wb3J0RW50cnkgPSBfaW1wb3J0RW50cnk7CiAgICAgIGlmICghaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdKSB7CiAgICAgICAgaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdID0ge307CiAgICAgIH0KICAgICAgaWYgKGltcG9ydE9iamVjdDJbaW1wb3J0RW50cnkubW9kdWxlXVtpbXBvcnRFbnRyeS5uYW1lXSkgewogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGlmIChpbXBvcnRFbnRyeS5raW5kID09ICJmdW5jdGlvbiIpIHsKICAgICAgICBpbXBvcnRPYmplY3QyW2ltcG9ydEVudHJ5Lm1vZHVsZV1baW1wb3J0RW50cnkubmFtZV0gPSAoKSA9PiB7CiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEltcG9ydGVkIGZ1bmN0aW9uICR7aW1wb3J0RW50cnkubW9kdWxlfS4ke2ltcG9ydEVudHJ5Lm5hbWV9IG5vdCBpbXBsZW1lbnRlZGApOwogICAgICAgIH07CiAgICAgIH0gZWxzZSBpZiAoaW1wb3J0RW50cnkua2luZCA9PSAibWVtb3J5IiAmJiBpbXBvcnRFbnRyeS5tb2R1bGUgPT0gImVudiIgJiYgaW1wb3J0RW50cnkubmFtZSA9PSAibWVtb3J5IikgewogICAgICAgIGNvbnN0IHR5cGUgPSBpbXBvcnRFbnRyeS50eXBlOwogICAgICAgIGNvbnN0IGRlc2NyaXB0b3IgPSB7CiAgICAgICAgICBpbml0aWFsOiB0eXBlLm1pbmltdW0sCiAgICAgICAgICBtYXhpbXVtOiB0eXBlLm1heGltdW0sCiAgICAgICAgICBzaGFyZWQ6IHR5cGUuc2hhcmVkCiAgICAgICAgfTsKICAgICAgICBpbXBvcnRPYmplY3QyW2ltcG9ydEVudHJ5Lm1vZHVsZV1baW1wb3J0RW50cnkubmFtZV0gPSBuZXcgV2ViQXNzZW1ibHkyLk1lbW9yeShkZXNjcmlwdG9yKTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIGltcG9ydE9iamVjdDI7CiAgfTsKICBjb25zdCBpbXBvcnRPYmplY3QgPSBjcmVhdGVXYXNtSW1wb3J0T2JqZWN0KGV4dHJhV2FzbUltcG9ydHMsIG9wdGlvbnMubW9kdWxlKTsKICBjb25zdCBpbnN0YW5jZSA9IGF3YWl0IFdlYkFzc2VtYmx5Mi5pbnN0YW50aWF0ZShvcHRpb25zLm1vZHVsZSwgaW1wb3J0T2JqZWN0KTsKICBpZiAoc3dpZnQgJiYgaW5zdGFuY2UuZXhwb3J0cy5zd2pzX2xpYnJhcnlfdmVyc2lvbikgewogICAgc3dpZnQuc2V0SW5zdGFuY2UoaW5zdGFuY2UpOwogIH0KICBpZiAodHlwZW9mIGluc3RhbmNlLmV4cG9ydHMuX3N0YXJ0ID09PSAiZnVuY3Rpb24iKSB7CiAgICB3YXNpLnN0YXJ0KGluc3RhbmNlKTsKICB9IGVsc2UgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLl9pbml0aWFsaXplID09ICJmdW5jdGlvbiIpIHsKICAgIHdhc2kuaW5pdGlhbGl6ZShpbnN0YW5jZSk7CiAgICBpZiAoc3dpZnQgJiYgc3dpZnQubWFpbikgewogICAgICBzd2lmdC5tYWluKCk7CiAgICB9IGVsc2UgewogICAgICBpZiAodHlwZW9mIGluc3RhbmNlLmV4cG9ydHMubWFpbiA9PT0gImZ1bmN0aW9uIikgewogICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWFpbigpOwogICAgICB9IGVsc2UgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLl9fbWFpbl9hcmdjX2FyZ3YgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICBpbnN0YW5jZS5leHBvcnRzLl9fbWFpbl9hcmdjX2FyZ3YoMCwgMCk7CiAgICAgIH0KICAgIH0KICB9CiAgcmV0dXJuIHsgaW5zdGFuY2UsIHJvb3RGcyB9Owp9CmZ1bmN0aW9uIGRlZmF1bHRJbnN0YW50aWF0aW9uT3B0aW9ucyhvcHRpb25zKSB7CiAgaWYgKG9wdGlvbnMuYXJncyA9PSBudWxsKSB7CiAgICBvcHRpb25zLmFyZ3MgPSBbIm1haW4ud2FzbSJdOwogIH0KICBjb25zdCBpc05vZGVKcyA9IHR5cGVvZiBwcm9jZXNzICE9PSAidW5kZWZpbmVkIiAmJiBwcm9jZXNzLnJlbGVhc2UubmFtZSA9PT0gIm5vZGUiOwogIGNvbnN0IGlzV2ViQnJvd3NlciA9IHR5cGVvZiB3aW5kb3cgIT09ICJ1bmRlZmluZWQiOwogIGlmIChpc05vZGVKcykgewogICAgaWYgKCFvcHRpb25zLm9uU3Rkb3V0KSB7CiAgICAgIG9wdGlvbnMub25TdGRvdXQgPSAoY2h1bmspID0+IHByb2Nlc3Muc3Rkb3V0LndyaXRlKGNodW5rKTsKICAgIH0KICAgIGlmICghb3B0aW9ucy5vblN0ZGVycikgewogICAgICBvcHRpb25zLm9uU3RkZXJyID0gKGNodW5rKSA9PiBwcm9jZXNzLnN0ZGVyci53cml0ZShjaHVuayk7CiAgICB9CiAgfSBlbHNlIGlmIChpc1dlYkJyb3dzZXIpIHsKICAgIGlmICghb3B0aW9ucy5vblN0ZG91dExpbmUpIHsKICAgICAgb3B0aW9ucy5vblN0ZG91dExpbmUgPSAobGluZSkgPT4gY29uc29sZS5sb2cobGluZSk7CiAgICB9CiAgICBpZiAoIW9wdGlvbnMub25TdGRlcnJMaW5lKSB7CiAgICAgIG9wdGlvbnMub25TdGRlcnJMaW5lID0gKGxpbmUpID0+IGNvbnNvbGUud2FybihsaW5lKTsKICAgIH0KICB9CiAgcmV0dXJuIG9wdGlvbnM7Cn0KCi8vIGVudHJ5cG9pbnQvYnVuZGxlLnRzCnZhciBzdGFydFdhc2lUYXNrID0gYXN5bmMgKCkgPT4gewogIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goIlJFUExBQ0VfVEhJU19XSVRIX1RIRV9NQUlOX1dFQkFTU0VNQkxZX01PRFVMRSIpOwogIGxldCBydW50aW1lQ29uc3RydWN0b3IgPSB2b2lkIDA7CiAgdHJ5IHsKICAgIGNvbnN0IG1vZHVsZVBhdGggPSAiLi9KYXZhU2NyaXB0S2l0X0phdmFTY3JpcHRLaXQucmVzb3VyY2VzL1J1bnRpbWUvaW5kZXgubWpzIjsKICAgIGNvbnN0IHsgU3dpZnRSdW50aW1lIH0gPSBhd2FpdCBpbXBvcnQoCiAgICAgIC8vIEB0cy1pZ25vcmUKICAgICAgLyogQHZpdGUtaWdub3JlICovCiAgICAgIG1vZHVsZVBhdGgKICAgICk7CiAgICBydW50aW1lQ29uc3RydWN0b3IgPSBTd2lmdFJ1bnRpbWU7CiAgfSBjYXRjaCB7CiAgfQogIGF3YWl0IGluc3RhbnRpYXRlKHsKICAgIG1vZHVsZTogYXdhaXQgV2ViQXNzZW1ibHkyLmNvbXBpbGVTdHJlYW1pbmcocmVzcG9uc2UpLAogICAgb25TdGRvdXRMaW5lKGxpbmUpIHsKICAgICAgY29uc29sZS5sb2cobGluZSk7CiAgICB9LAogICAgb25TdGRlcnJMaW5lKGxpbmUpIHsKICAgICAgY29uc29sZS5lcnJvcihsaW5lKTsKICAgIH0sCiAgICBTd2lmdFJ1bnRpbWU6IHJ1bnRpbWVDb25zdHJ1Y3RvcgogIH0pOwp9Owphc3luYyBmdW5jdGlvbiBtYWluKCkgewogIGF3YWl0IHN0YXJ0V2FzaVRhc2soKTsKfQptYWluKCk7Cg==")! public static let intrinsics: Data = Data(base64Encoded: "Ly8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC93YXNpX2RlZnMuanMKdmFyIENMT0NLSURfUkVBTFRJTUUgPSAwOwp2YXIgQ0xPQ0tJRF9NT05PVE9OSUMgPSAxOwp2YXIgRVJSTk9fU1VDQ0VTUyA9IDA7CnZhciBFUlJOT19CQURGID0gODsKdmFyIEVSUk5PX0VYSVNUID0gMjA7CnZhciBFUlJOT19JTlZBTCA9IDI4Owp2YXIgRVJSTk9fSVNESVIgPSAzMTsKdmFyIEVSUk5PX05BTUVUT09MT05HID0gMzc7CnZhciBFUlJOT19OT0VOVCA9IDQ0Owp2YXIgRVJSTk9fTk9TWVMgPSA1MjsKdmFyIEVSUk5PX05PVERJUiA9IDU0Owp2YXIgRVJSTk9fTk9URU1QVFkgPSA1NTsKdmFyIEVSUk5PX05PVFNVUCA9IDU4Owp2YXIgRVJSTk9fUEVSTSA9IDYzOwp2YXIgRVJSTk9fTk9UQ0FQQUJMRSA9IDc2Owp2YXIgUklHSFRTX0ZEX0RBVEFTWU5DID0gMSA8PCAwOwp2YXIgUklHSFRTX0ZEX1JFQUQgPSAxIDw8IDE7CnZhciBSSUdIVFNfRkRfU0VFSyA9IDEgPDwgMjsKdmFyIFJJR0hUU19GRF9GRFNUQVRfU0VUX0ZMQUdTID0gMSA8PCAzOwp2YXIgUklHSFRTX0ZEX1NZTkMgPSAxIDw8IDQ7CnZhciBSSUdIVFNfRkRfVEVMTCA9IDEgPDwgNTsKdmFyIFJJR0hUU19GRF9XUklURSA9IDEgPDwgNjsKdmFyIFJJR0hUU19GRF9BRFZJU0UgPSAxIDw8IDc7CnZhciBSSUdIVFNfRkRfQUxMT0NBVEUgPSAxIDw8IDg7CnZhciBSSUdIVFNfUEFUSF9DUkVBVEVfRElSRUNUT1JZID0gMSA8PCA5Owp2YXIgUklHSFRTX1BBVEhfQ1JFQVRFX0ZJTEUgPSAxIDw8IDEwOwp2YXIgUklHSFRTX1BBVEhfTElOS19TT1VSQ0UgPSAxIDw8IDExOwp2YXIgUklHSFRTX1BBVEhfTElOS19UQVJHRVQgPSAxIDw8IDEyOwp2YXIgUklHSFRTX1BBVEhfT1BFTiA9IDEgPDwgMTM7CnZhciBSSUdIVFNfRkRfUkVBRERJUiA9IDEgPDwgMTQ7CnZhciBSSUdIVFNfUEFUSF9SRUFETElOSyA9IDEgPDwgMTU7CnZhciBSSUdIVFNfUEFUSF9SRU5BTUVfU09VUkNFID0gMSA8PCAxNjsKdmFyIFJJR0hUU19QQVRIX1JFTkFNRV9UQVJHRVQgPSAxIDw8IDE3Owp2YXIgUklHSFRTX1BBVEhfRklMRVNUQVRfR0VUID0gMSA8PCAxODsKdmFyIFJJR0hUU19QQVRIX0ZJTEVTVEFUX1NFVF9TSVpFID0gMSA8PCAxOTsKdmFyIFJJR0hUU19QQVRIX0ZJTEVTVEFUX1NFVF9USU1FUyA9IDEgPDwgMjA7CnZhciBSSUdIVFNfRkRfRklMRVNUQVRfR0VUID0gMSA8PCAyMTsKdmFyIFJJR0hUU19GRF9GSUxFU1RBVF9TRVRfU0laRSA9IDEgPDwgMjI7CnZhciBSSUdIVFNfRkRfRklMRVNUQVRfU0VUX1RJTUVTID0gMSA8PCAyMzsKdmFyIFJJR0hUU19QQVRIX1NZTUxJTksgPSAxIDw8IDI0Owp2YXIgUklHSFRTX1BBVEhfUkVNT1ZFX0RJUkVDVE9SWSA9IDEgPDwgMjU7CnZhciBSSUdIVFNfUEFUSF9VTkxJTktfRklMRSA9IDEgPDwgMjY7CnZhciBSSUdIVFNfUE9MTF9GRF9SRUFEV1JJVEUgPSAxIDw8IDI3Owp2YXIgUklHSFRTX1NPQ0tfU0hVVERPV04gPSAxIDw8IDI4Owp2YXIgSW92ZWMgPSBjbGFzcyB7CiAgc3RhdGljIHJlYWRfYnl0ZXModmlldywgcHRyKSB7CiAgICBjb25zdCBpb3ZlYyA9IG5ldyBJb3ZlYygpOwogICAgaW92ZWMuYnVmID0gdmlldy5nZXRVaW50MzIocHRyLCB0cnVlKTsKICAgIGlvdmVjLmJ1Zl9sZW4gPSB2aWV3LmdldFVpbnQzMihwdHIgKyA0LCB0cnVlKTsKICAgIHJldHVybiBpb3ZlYzsKICB9CiAgc3RhdGljIHJlYWRfYnl0ZXNfYXJyYXkodmlldywgcHRyLCBsZW4pIHsKICAgIGNvbnN0IGlvdmVjcyA9IFtdOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykgewogICAgICBpb3ZlY3MucHVzaChJb3ZlYy5yZWFkX2J5dGVzKHZpZXcsIHB0ciArIDggKiBpKSk7CiAgICB9CiAgICByZXR1cm4gaW92ZWNzOwogIH0KfTsKdmFyIENpb3ZlYyA9IGNsYXNzIHsKICBzdGF0aWMgcmVhZF9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIGNvbnN0IGlvdmVjID0gbmV3IENpb3ZlYygpOwogICAgaW92ZWMuYnVmID0gdmlldy5nZXRVaW50MzIocHRyLCB0cnVlKTsKICAgIGlvdmVjLmJ1Zl9sZW4gPSB2aWV3LmdldFVpbnQzMihwdHIgKyA0LCB0cnVlKTsKICAgIHJldHVybiBpb3ZlYzsKICB9CiAgc3RhdGljIHJlYWRfYnl0ZXNfYXJyYXkodmlldywgcHRyLCBsZW4pIHsKICAgIGNvbnN0IGlvdmVjcyA9IFtdOwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykgewogICAgICBpb3ZlY3MucHVzaChDaW92ZWMucmVhZF9ieXRlcyh2aWV3LCBwdHIgKyA4ICogaSkpOwogICAgfQogICAgcmV0dXJuIGlvdmVjczsKICB9Cn07CnZhciBXSEVOQ0VfU0VUID0gMDsKdmFyIFdIRU5DRV9DVVIgPSAxOwp2YXIgV0hFTkNFX0VORCA9IDI7CnZhciBGSUxFVFlQRV9DSEFSQUNURVJfREVWSUNFID0gMjsKdmFyIEZJTEVUWVBFX0RJUkVDVE9SWSA9IDM7CnZhciBGSUxFVFlQRV9SRUdVTEFSX0ZJTEUgPSA0Owp2YXIgRGlyZW50ID0gY2xhc3MgewogIGhlYWRfbGVuZ3RoKCkgewogICAgcmV0dXJuIDI0OwogIH0KICBuYW1lX2xlbmd0aCgpIHsKICAgIHJldHVybiB0aGlzLmRpcl9uYW1lLmJ5dGVMZW5ndGg7CiAgfQogIHdyaXRlX2hlYWRfYnl0ZXModmlldywgcHRyKSB7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIsIHRoaXMuZF9uZXh0LCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDgsIHRoaXMuZF9pbm8sIHRydWUpOwogICAgdmlldy5zZXRVaW50MzIocHRyICsgMTYsIHRoaXMuZGlyX25hbWUubGVuZ3RoLCB0cnVlKTsKICAgIHZpZXcuc2V0VWludDgocHRyICsgMjAsIHRoaXMuZF90eXBlKTsKICB9CiAgd3JpdGVfbmFtZV9ieXRlcyh2aWV3OCwgcHRyLCBidWZfbGVuKSB7CiAgICB2aWV3OC5zZXQodGhpcy5kaXJfbmFtZS5zbGljZSgwLCBNYXRoLm1pbih0aGlzLmRpcl9uYW1lLmJ5dGVMZW5ndGgsIGJ1Zl9sZW4pKSwgcHRyKTsKICB9CiAgY29uc3RydWN0b3IobmV4dF9jb29raWUsIG5hbWUsIHR5cGUpIHsKICAgIHRoaXMuZF9pbm8gPSAwbjsKICAgIGNvbnN0IGVuY29kZWRfbmFtZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShuYW1lKTsKICAgIHRoaXMuZF9uZXh0ID0gbmV4dF9jb29raWU7CiAgICB0aGlzLmRfbmFtbGVuID0gZW5jb2RlZF9uYW1lLmJ5dGVMZW5ndGg7CiAgICB0aGlzLmRfdHlwZSA9IHR5cGU7CiAgICB0aGlzLmRpcl9uYW1lID0gZW5jb2RlZF9uYW1lOwogIH0KfTsKdmFyIEZERkxBR1NfQVBQRU5EID0gMSA8PCAwOwp2YXIgRkRGTEFHU19EU1lOQyA9IDEgPDwgMTsKdmFyIEZERkxBR1NfTk9OQkxPQ0sgPSAxIDw8IDI7CnZhciBGREZMQUdTX1JTWU5DID0gMSA8PCAzOwp2YXIgRkRGTEFHU19TWU5DID0gMSA8PCA0Owp2YXIgRmRzdGF0ID0gY2xhc3MgewogIHdyaXRlX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRVaW50OChwdHIsIHRoaXMuZnNfZmlsZXR5cGUpOwogICAgdmlldy5zZXRVaW50MTYocHRyICsgMiwgdGhpcy5mc19mbGFncywgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA4LCB0aGlzLmZzX3JpZ2h0c19iYXNlLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDE2LCB0aGlzLmZzX3JpZ2h0c19pbmhlcml0ZWQsIHRydWUpOwogIH0KICBjb25zdHJ1Y3RvcihmaWxldHlwZSwgZmxhZ3MpIHsKICAgIHRoaXMuZnNfcmlnaHRzX2Jhc2UgPSAwbjsKICAgIHRoaXMuZnNfcmlnaHRzX2luaGVyaXRlZCA9IDBuOwogICAgdGhpcy5mc19maWxldHlwZSA9IGZpbGV0eXBlOwogICAgdGhpcy5mc19mbGFncyA9IGZsYWdzOwogIH0KfTsKdmFyIEZTVEZMQUdTX0FUSU0gPSAxIDw8IDA7CnZhciBGU1RGTEFHU19BVElNX05PVyA9IDEgPDwgMTsKdmFyIEZTVEZMQUdTX01USU0gPSAxIDw8IDI7CnZhciBGU1RGTEFHU19NVElNX05PVyA9IDEgPDwgMzsKdmFyIE9GTEFHU19DUkVBVCA9IDEgPDwgMDsKdmFyIE9GTEFHU19ESVJFQ1RPUlkgPSAxIDw8IDE7CnZhciBPRkxBR1NfRVhDTCA9IDEgPDwgMjsKdmFyIE9GTEFHU19UUlVOQyA9IDEgPDwgMzsKdmFyIEZpbGVzdGF0ID0gY2xhc3MgewogIHdyaXRlX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRCaWdVaW50NjQocHRyLCB0aGlzLmRldiwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA4LCB0aGlzLmlubywgdHJ1ZSk7CiAgICB2aWV3LnNldFVpbnQ4KHB0ciArIDE2LCB0aGlzLmZpbGV0eXBlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDI0LCB0aGlzLm5saW5rLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDMyLCB0aGlzLnNpemUsIHRydWUpOwogICAgdmlldy5zZXRCaWdVaW50NjQocHRyICsgMzgsIHRoaXMuYXRpbSwgdHJ1ZSk7CiAgICB2aWV3LnNldEJpZ1VpbnQ2NChwdHIgKyA0NiwgdGhpcy5tdGltLCB0cnVlKTsKICAgIHZpZXcuc2V0QmlnVWludDY0KHB0ciArIDUyLCB0aGlzLmN0aW0sIHRydWUpOwogIH0KICBjb25zdHJ1Y3RvcihmaWxldHlwZSwgc2l6ZSkgewogICAgdGhpcy5kZXYgPSAwbjsKICAgIHRoaXMuaW5vID0gMG47CiAgICB0aGlzLm5saW5rID0gMG47CiAgICB0aGlzLmF0aW0gPSAwbjsKICAgIHRoaXMubXRpbSA9IDBuOwogICAgdGhpcy5jdGltID0gMG47CiAgICB0aGlzLmZpbGV0eXBlID0gZmlsZXR5cGU7CiAgICB0aGlzLnNpemUgPSBzaXplOwogIH0KfTsKdmFyIEVWRU5UUldGTEFHU19GRF9SRUFEV1JJVEVfSEFOR1VQID0gMSA8PCAwOwp2YXIgU1VCQ0xPQ0tGTEFHU19TVUJTQ1JJUFRJT05fQ0xPQ0tfQUJTVElNRSA9IDEgPDwgMDsKdmFyIFJJRkxBR1NfUkVDVl9QRUVLID0gMSA8PCAwOwp2YXIgUklGTEFHU19SRUNWX1dBSVRBTEwgPSAxIDw8IDE7CnZhciBST0ZMQUdTX1JFQ1ZfREFUQV9UUlVOQ0FURUQgPSAxIDw8IDA7CnZhciBTREZMQUdTX1JEID0gMSA8PCAwOwp2YXIgU0RGTEFHU19XUiA9IDEgPDwgMTsKdmFyIFBSRU9QRU5UWVBFX0RJUiA9IDA7CnZhciBQcmVzdGF0RGlyID0gY2xhc3MgewogIHdyaXRlX2J5dGVzKHZpZXcsIHB0cikgewogICAgdmlldy5zZXRVaW50MzIocHRyLCB0aGlzLnByX25hbWUuYnl0ZUxlbmd0aCwgdHJ1ZSk7CiAgfQogIGNvbnN0cnVjdG9yKG5hbWUpIHsKICAgIHRoaXMucHJfbmFtZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShuYW1lKTsKICB9Cn07CnZhciBQcmVzdGF0ID0gY2xhc3MgewogIHN0YXRpYyBkaXIobmFtZSkgewogICAgY29uc3QgcHJlc3RhdCA9IG5ldyBQcmVzdGF0KCk7CiAgICBwcmVzdGF0LnRhZyA9IFBSRU9QRU5UWVBFX0RJUjsKICAgIHByZXN0YXQuaW5uZXIgPSBuZXcgUHJlc3RhdERpcihuYW1lKTsKICAgIHJldHVybiBwcmVzdGF0OwogIH0KICB3cml0ZV9ieXRlcyh2aWV3LCBwdHIpIHsKICAgIHZpZXcuc2V0VWludDMyKHB0ciwgdGhpcy50YWcsIHRydWUpOwogICAgdGhpcy5pbm5lci53cml0ZV9ieXRlcyh2aWV3LCBwdHIgKyA0KTsKICB9Cn07CgovLyBub2RlX21vZHVsZXMvQGJqb3JuMy9icm93c2VyX3dhc2lfc2hpbS9kaXN0L2RlYnVnLmpzCnZhciBEZWJ1ZyA9IGNsYXNzIERlYnVnMiB7CiAgZW5hYmxlKGVuYWJsZWQpIHsKICAgIHRoaXMubG9nID0gY3JlYXRlTG9nZ2VyKGVuYWJsZWQgPT09IHZvaWQgMCA/IHRydWUgOiBlbmFibGVkLCB0aGlzLnByZWZpeCk7CiAgfQogIGdldCBlbmFibGVkKCkgewogICAgcmV0dXJuIHRoaXMuaXNFbmFibGVkOwogIH0KICBjb25zdHJ1Y3Rvcihpc0VuYWJsZWQpIHsKICAgIHRoaXMuaXNFbmFibGVkID0gaXNFbmFibGVkOwogICAgdGhpcy5wcmVmaXggPSAid2FzaToiOwogICAgdGhpcy5lbmFibGUoaXNFbmFibGVkKTsKICB9Cn07CmZ1bmN0aW9uIGNyZWF0ZUxvZ2dlcihlbmFibGVkLCBwcmVmaXgpIHsKICBpZiAoZW5hYmxlZCkgewogICAgY29uc3QgYSA9IGNvbnNvbGUubG9nLmJpbmQoY29uc29sZSwgIiVjJXMiLCAiY29sb3I6ICMyNjVCQTAiLCBwcmVmaXgpOwogICAgcmV0dXJuIGE7CiAgfSBlbHNlIHsKICAgIHJldHVybiAoKSA9PiB7CiAgICB9OwogIH0KfQp2YXIgZGVidWcgPSBuZXcgRGVidWcoZmFsc2UpOwoKLy8gbm9kZV9tb2R1bGVzL0Biam9ybjMvYnJvd3Nlcl93YXNpX3NoaW0vZGlzdC93YXNpLmpzCnZhciBXQVNJUHJvY0V4aXQgPSBjbGFzcyBleHRlbmRzIEVycm9yIHsKICBjb25zdHJ1Y3Rvcihjb2RlKSB7CiAgICBzdXBlcigiZXhpdCB3aXRoIGV4aXQgY29kZSAiICsgY29kZSk7CiAgICB0aGlzLmNvZGUgPSBjb2RlOwogIH0KfTsKdmFyIFdBU0kgPSBjbGFzcyBXQVNJMiB7CiAgc3RhcnQoaW5zdGFuY2UpIHsKICAgIHRoaXMuaW5zdCA9IGluc3RhbmNlOwogICAgdHJ5IHsKICAgICAgaW5zdGFuY2UuZXhwb3J0cy5fc3RhcnQoKTsKICAgICAgcmV0dXJuIDA7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIGlmIChlIGluc3RhbmNlb2YgV0FTSVByb2NFeGl0KSB7CiAgICAgICAgcmV0dXJuIGUuY29kZTsKICAgICAgfSBlbHNlIHsKICAgICAgICB0aHJvdyBlOwogICAgICB9CiAgICB9CiAgfQogIGluaXRpYWxpemUoaW5zdGFuY2UpIHsKICAgIHRoaXMuaW5zdCA9IGluc3RhbmNlOwogICAgaWYgKGluc3RhbmNlLmV4cG9ydHMuX2luaXRpYWxpemUpIHsKICAgICAgaW5zdGFuY2UuZXhwb3J0cy5faW5pdGlhbGl6ZSgpOwogICAgfQogIH0KICBjb25zdHJ1Y3RvcihhcmdzLCBlbnYsIGZkcywgb3B0aW9ucyA9IHt9KSB7CiAgICB0aGlzLmFyZ3MgPSBbXTsKICAgIHRoaXMuZW52ID0gW107CiAgICB0aGlzLmZkcyA9IFtdOwogICAgZGVidWcuZW5hYmxlKG9wdGlvbnMuZGVidWcpOwogICAgdGhpcy5hcmdzID0gYXJnczsKICAgIHRoaXMuZW52ID0gZW52OwogICAgdGhpcy5mZHMgPSBmZHM7CiAgICBjb25zdCBzZWxmID0gdGhpczsKICAgIHRoaXMud2FzaUltcG9ydCA9IHsgYXJnc19zaXplc19nZXQoYXJnYywgYXJndl9idWZfc2l6ZSkgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYXJnYywgc2VsZi5hcmdzLmxlbmd0aCwgdHJ1ZSk7CiAgICAgIGxldCBidWZfc2l6ZSA9IDA7CiAgICAgIGZvciAoY29uc3QgYXJnIG9mIHNlbGYuYXJncykgewogICAgICAgIGJ1Zl9zaXplICs9IGFyZy5sZW5ndGggKyAxOwogICAgICB9CiAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYXJndl9idWZfc2l6ZSwgYnVmX3NpemUsIHRydWUpOwogICAgICBkZWJ1Zy5sb2coYnVmZmVyLmdldFVpbnQzMihhcmdjLCB0cnVlKSwgYnVmZmVyLmdldFVpbnQzMihhcmd2X2J1Zl9zaXplLCB0cnVlKSk7CiAgICAgIHJldHVybiAwOwogICAgfSwgYXJnc19nZXQoYXJndiwgYXJndl9idWYpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IG9yaWdfYXJndl9idWYgPSBhcmd2X2J1ZjsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmLmFyZ3MubGVuZ3RoOyBpKyspIHsKICAgICAgICBidWZmZXIuc2V0VWludDMyKGFyZ3YsIGFyZ3ZfYnVmLCB0cnVlKTsKICAgICAgICBhcmd2ICs9IDQ7CiAgICAgICAgY29uc3QgYXJnID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHNlbGYuYXJnc1tpXSk7CiAgICAgICAgYnVmZmVyOC5zZXQoYXJnLCBhcmd2X2J1Zik7CiAgICAgICAgYnVmZmVyLnNldFVpbnQ4KGFyZ3ZfYnVmICsgYXJnLmxlbmd0aCwgMCk7CiAgICAgICAgYXJndl9idWYgKz0gYXJnLmxlbmd0aCArIDE7CiAgICAgIH0KICAgICAgaWYgKGRlYnVnLmVuYWJsZWQpIHsKICAgICAgICBkZWJ1Zy5sb2cobmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG9yaWdfYXJndl9idWYsIGFyZ3ZfYnVmKSkpOwogICAgICB9CiAgICAgIHJldHVybiAwOwogICAgfSwgZW52aXJvbl9zaXplc19nZXQoZW52aXJvbl9jb3VudCwgZW52aXJvbl9zaXplKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgYnVmZmVyLnNldFVpbnQzMihlbnZpcm9uX2NvdW50LCBzZWxmLmVudi5sZW5ndGgsIHRydWUpOwogICAgICBsZXQgYnVmX3NpemUgPSAwOwogICAgICBmb3IgKGNvbnN0IGVudmlyb24gb2Ygc2VsZi5lbnYpIHsKICAgICAgICBidWZfc2l6ZSArPSBlbnZpcm9uLmxlbmd0aCArIDE7CiAgICAgIH0KICAgICAgYnVmZmVyLnNldFVpbnQzMihlbnZpcm9uX3NpemUsIGJ1Zl9zaXplLCB0cnVlKTsKICAgICAgZGVidWcubG9nKGJ1ZmZlci5nZXRVaW50MzIoZW52aXJvbl9jb3VudCwgdHJ1ZSksIGJ1ZmZlci5nZXRVaW50MzIoZW52aXJvbl9zaXplLCB0cnVlKSk7CiAgICAgIHJldHVybiAwOwogICAgfSwgZW52aXJvbl9nZXQoZW52aXJvbiwgZW52aXJvbl9idWYpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IG9yaWdfZW52aXJvbl9idWYgPSBlbnZpcm9uX2J1ZjsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmLmVudi5sZW5ndGg7IGkrKykgewogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIoZW52aXJvbiwgZW52aXJvbl9idWYsIHRydWUpOwogICAgICAgIGVudmlyb24gKz0gNDsKICAgICAgICBjb25zdCBlID0gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHNlbGYuZW52W2ldKTsKICAgICAgICBidWZmZXI4LnNldChlLCBlbnZpcm9uX2J1Zik7CiAgICAgICAgYnVmZmVyLnNldFVpbnQ4KGVudmlyb25fYnVmICsgZS5sZW5ndGgsIDApOwogICAgICAgIGVudmlyb25fYnVmICs9IGUubGVuZ3RoICsgMTsKICAgICAgfQogICAgICBpZiAoZGVidWcuZW5hYmxlZCkgewogICAgICAgIGRlYnVnLmxvZyhuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob3JpZ19lbnZpcm9uX2J1ZiwgZW52aXJvbl9idWYpKSk7CiAgICAgIH0KICAgICAgcmV0dXJuIDA7CiAgICB9LCBjbG9ja19yZXNfZ2V0KGlkLCByZXNfcHRyKSB7CiAgICAgIGxldCByZXNvbHV0aW9uVmFsdWU7CiAgICAgIHN3aXRjaCAoaWQpIHsKICAgICAgICBjYXNlIENMT0NLSURfTU9OT1RPTklDOiB7CiAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSA1MDAwbjsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICBjYXNlIENMT0NLSURfUkVBTFRJTUU6IHsKICAgICAgICAgIHJlc29sdXRpb25WYWx1ZSA9IDEwMDAwMDBuOwogICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICByZXR1cm4gRVJSTk9fTk9TWVM7CiAgICAgIH0KICAgICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgdmlldy5zZXRCaWdVaW50NjQocmVzX3B0ciwgcmVzb2x1dGlvblZhbHVlLCB0cnVlKTsKICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICB9LCBjbG9ja190aW1lX2dldChpZCwgcHJlY2lzaW9uLCB0aW1lKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKGlkID09PSBDTE9DS0lEX1JFQUxUSU1FKSB7CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NCh0aW1lLCBCaWdJbnQobmV3IERhdGUoKS5nZXRUaW1lKCkpICogMTAwMDAwMG4sIHRydWUpOwogICAgICB9IGVsc2UgaWYgKGlkID09IENMT0NLSURfTU9OT1RPTklDKSB7CiAgICAgICAgbGV0IG1vbm90b25pY190aW1lOwogICAgICAgIHRyeSB7CiAgICAgICAgICBtb25vdG9uaWNfdGltZSA9IEJpZ0ludChNYXRoLnJvdW5kKHBlcmZvcm1hbmNlLm5vdygpICogMWU2KSk7CiAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgbW9ub3RvbmljX3RpbWUgPSAwbjsKICAgICAgICB9CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NCh0aW1lLCBtb25vdG9uaWNfdGltZSwgdHJ1ZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NCh0aW1lLCAwbiwgdHJ1ZSk7CiAgICAgIH0KICAgICAgcmV0dXJuIDA7CiAgICB9LCBmZF9hZHZpc2UoZmQsIG9mZnNldCwgbGVuLCBhZHZpY2UpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfYWxsb2NhdGUoZmQsIG9mZnNldCwgbGVuKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9hbGxvY2F0ZShvZmZzZXQsIGxlbik7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Nsb3NlKGZkKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcmV0ID0gc2VsZi5mZHNbZmRdLmZkX2Nsb3NlKCk7CiAgICAgICAgc2VsZi5mZHNbZmRdID0gdm9pZCAwOwogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2RhdGFzeW5jKGZkKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9zeW5jKCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Zkc3RhdF9nZXQoZmQsIGZkc3RhdF9wdHIpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgZmRzdGF0IH0gPSBzZWxmLmZkc1tmZF0uZmRfZmRzdGF0X2dldCgpOwogICAgICAgIGlmIChmZHN0YXQgIT0gbnVsbCkgewogICAgICAgICAgZmRzdGF0LndyaXRlX2J5dGVzKG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKSwgZmRzdGF0X3B0cik7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2Zkc3RhdF9zZXRfZmxhZ3MoZmQsIGZsYWdzKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9mZHN0YXRfc2V0X2ZsYWdzKGZsYWdzKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfZmRzdGF0X3NldF9yaWdodHMoZmQsIGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZykgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmRzdGF0X3NldF9yaWdodHMoZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfZmlsZXN0YXRfZ2V0KGZkLCBmaWxlc3RhdF9wdHIpIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgZmlsZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9maWxlc3RhdF9nZXQoKTsKICAgICAgICBpZiAoZmlsZXN0YXQgIT0gbnVsbCkgewogICAgICAgICAgZmlsZXN0YXQud3JpdGVfYnl0ZXMobmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpLCBmaWxlc3RhdF9wdHIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9maWxlc3RhdF9zZXRfc2l6ZShmZCwgc2l6ZSkgewogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0uZmRfZmlsZXN0YXRfc2V0X3NpemUoc2l6ZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX2ZpbGVzdGF0X3NldF90aW1lcyhmZCwgYXRpbSwgbXRpbSwgZnN0X2ZsYWdzKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9maWxlc3RhdF9zZXRfdGltZXMoYXRpbSwgbXRpbSwgZnN0X2ZsYWdzKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHJlYWQoZmQsIGlvdnNfcHRyLCBpb3ZzX2xlbiwgb2Zmc2V0LCBucmVhZF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgaW92ZWNzID0gSW92ZWMucmVhZF9ieXRlc19hcnJheShidWZmZXIsIGlvdnNfcHRyLCBpb3ZzX2xlbik7CiAgICAgICAgbGV0IG5yZWFkID0gMDsKICAgICAgICBmb3IgKGNvbnN0IGlvdmVjIG9mIGlvdmVjcykgewogICAgICAgICAgY29uc3QgeyByZXQsIGRhdGEgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wcmVhZChpb3ZlYy5idWZfbGVuLCBvZmZzZXQpOwogICAgICAgICAgaWYgKHJldCAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobnJlYWRfcHRyLCBucmVhZCwgdHJ1ZSk7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgICB9CiAgICAgICAgICBidWZmZXI4LnNldChkYXRhLCBpb3ZlYy5idWYpOwogICAgICAgICAgbnJlYWQgKz0gZGF0YS5sZW5ndGg7CiAgICAgICAgICBvZmZzZXQgKz0gQmlnSW50KGRhdGEubGVuZ3RoKTsKICAgICAgICAgIGlmIChkYXRhLmxlbmd0aCAhPSBpb3ZlYy5idWZfbGVuKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9wcmVzdGF0X2dldChmZCwgYnVmX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIHByZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wcmVzdGF0X2dldCgpOwogICAgICAgIGlmIChwcmVzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIHByZXN0YXQud3JpdGVfYnl0ZXMoYnVmZmVyLCBidWZfcHRyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfcHJlc3RhdF9kaXJfbmFtZShmZCwgcGF0aF9wdHIsIHBhdGhfbGVuKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgeyByZXQsIHByZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wcmVzdGF0X2dldCgpOwogICAgICAgIGlmIChwcmVzdGF0ID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHByZXN0YXRfZGlyX25hbWUgPSBwcmVzdGF0LmlubmVyLnByX25hbWU7CiAgICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgIGJ1ZmZlcjguc2V0KHByZXN0YXRfZGlyX25hbWUuc2xpY2UoMCwgcGF0aF9sZW4pLCBwYXRoX3B0cik7CiAgICAgICAgcmV0dXJuIHByZXN0YXRfZGlyX25hbWUuYnl0ZUxlbmd0aCA+IHBhdGhfbGVuID8gRVJSTk9fTkFNRVRPT0xPTkcgOiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9wd3JpdGUoZmQsIGlvdnNfcHRyLCBpb3ZzX2xlbiwgb2Zmc2V0LCBud3JpdHRlbl9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgaW92ZWNzID0gQ2lvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBud3JpdHRlbiA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IGRhdGEgPSBidWZmZXI4LnNsaWNlKGlvdmVjLmJ1ZiwgaW92ZWMuYnVmICsgaW92ZWMuYnVmX2xlbik7CiAgICAgICAgICBjb25zdCB7IHJldCwgbndyaXR0ZW46IG53cml0dGVuX3BhcnQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgbndyaXR0ZW4gKz0gbndyaXR0ZW5fcGFydDsKICAgICAgICAgIG9mZnNldCArPSBCaWdJbnQobndyaXR0ZW5fcGFydCk7CiAgICAgICAgICBpZiAobndyaXR0ZW5fcGFydCAhPSBkYXRhLmJ5dGVMZW5ndGgpIHsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobndyaXR0ZW5fcHRyLCBud3JpdHRlbiwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3JlYWQoZmQsIGlvdnNfcHRyLCBpb3ZzX2xlbiwgbnJlYWRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IGlvdmVjcyA9IElvdmVjLnJlYWRfYnl0ZXNfYXJyYXkoYnVmZmVyLCBpb3ZzX3B0ciwgaW92c19sZW4pOwogICAgICAgIGxldCBucmVhZCA9IDA7CiAgICAgICAgZm9yIChjb25zdCBpb3ZlYyBvZiBpb3ZlY3MpIHsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBkYXRhIH0gPSBzZWxmLmZkc1tmZF0uZmRfcmVhZChpb3ZlYy5idWZfbGVuKTsKICAgICAgICAgIGlmIChyZXQgIT0gRVJSTk9fU1VDQ0VTUykgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgbnJlYWQsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgYnVmZmVyOC5zZXQoZGF0YSwgaW92ZWMuYnVmKTsKICAgICAgICAgIG5yZWFkICs9IGRhdGEubGVuZ3RoOwogICAgICAgICAgaWYgKGRhdGEubGVuZ3RoICE9IGlvdmVjLmJ1Zl9sZW4pIHsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobnJlYWRfcHRyLCBucmVhZCwgdHJ1ZSk7CiAgICAgICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3JlYWRkaXIoZmQsIGJ1ZiwgYnVmX2xlbiwgY29va2llLCBidWZ1c2VkX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBsZXQgYnVmdXNlZCA9IDA7CiAgICAgICAgd2hpbGUgKHRydWUpIHsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBkaXJlbnQgfSA9IHNlbGYuZmRzW2ZkXS5mZF9yZWFkZGlyX3NpbmdsZShjb29raWUpOwogICAgICAgICAgaWYgKHJldCAhPSAwKSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYnVmdXNlZF9wdHIsIGJ1ZnVzZWQsIHRydWUpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfQogICAgICAgICAgaWYgKGRpcmVudCA9PSBudWxsKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGJ1Zl9sZW4gLSBidWZ1c2VkIDwgZGlyZW50LmhlYWRfbGVuZ3RoKCkpIHsKICAgICAgICAgICAgYnVmdXNlZCA9IGJ1Zl9sZW47CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgaGVhZF9ieXRlcyA9IG5ldyBBcnJheUJ1ZmZlcihkaXJlbnQuaGVhZF9sZW5ndGgoKSk7CiAgICAgICAgICBkaXJlbnQud3JpdGVfaGVhZF9ieXRlcyhuZXcgRGF0YVZpZXcoaGVhZF9ieXRlcyksIDApOwogICAgICAgICAgYnVmZmVyOC5zZXQobmV3IFVpbnQ4QXJyYXkoaGVhZF9ieXRlcykuc2xpY2UoMCwgTWF0aC5taW4oaGVhZF9ieXRlcy5ieXRlTGVuZ3RoLCBidWZfbGVuIC0gYnVmdXNlZCkpLCBidWYpOwogICAgICAgICAgYnVmICs9IGRpcmVudC5oZWFkX2xlbmd0aCgpOwogICAgICAgICAgYnVmdXNlZCArPSBkaXJlbnQuaGVhZF9sZW5ndGgoKTsKICAgICAgICAgIGlmIChidWZfbGVuIC0gYnVmdXNlZCA8IGRpcmVudC5uYW1lX2xlbmd0aCgpKSB7CiAgICAgICAgICAgIGJ1ZnVzZWQgPSBidWZfbGVuOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICAgIGRpcmVudC53cml0ZV9uYW1lX2J5dGVzKGJ1ZmZlcjgsIGJ1ZiwgYnVmX2xlbiAtIGJ1ZnVzZWQpOwogICAgICAgICAgYnVmICs9IGRpcmVudC5uYW1lX2xlbmd0aCgpOwogICAgICAgICAgYnVmdXNlZCArPSBkaXJlbnQubmFtZV9sZW5ndGgoKTsKICAgICAgICAgIGNvb2tpZSA9IGRpcmVudC5kX25leHQ7CiAgICAgICAgfQogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIoYnVmdXNlZF9wdHIsIGJ1ZnVzZWQsIHRydWUpOwogICAgICAgIHJldHVybiAwOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9yZW51bWJlcihmZCwgdG8pIHsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDAgJiYgc2VsZi5mZHNbdG9dICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHJldCA9IHNlbGYuZmRzW3RvXS5mZF9jbG9zZSgpOwogICAgICAgIGlmIChyZXQgIT0gMCkgewogICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9CiAgICAgICAgc2VsZi5mZHNbdG9dID0gc2VsZi5mZHNbZmRdOwogICAgICAgIHNlbGYuZmRzW2ZkXSA9IHZvaWQgMDsKICAgICAgICByZXR1cm4gMDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgZmRfc2VlayhmZCwgb2Zmc2V0LCB3aGVuY2UsIG9mZnNldF9vdXRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCB7IHJldCwgb2Zmc2V0OiBvZmZzZXRfb3V0IH0gPSBzZWxmLmZkc1tmZF0uZmRfc2VlayhvZmZzZXQsIHdoZW5jZSk7CiAgICAgICAgYnVmZmVyLnNldEJpZ0ludDY0KG9mZnNldF9vdXRfcHRyLCBvZmZzZXRfb3V0LCB0cnVlKTsKICAgICAgICByZXR1cm4gcmV0OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBmZF9zeW5jKGZkKSB7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5mZF9zeW5jKCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3RlbGwoZmQsIG9mZnNldF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHsgcmV0LCBvZmZzZXQgfSA9IHNlbGYuZmRzW2ZkXS5mZF90ZWxsKCk7CiAgICAgICAgYnVmZmVyLnNldEJpZ1VpbnQ2NChvZmZzZXRfcHRyLCBvZmZzZXQsIHRydWUpOwogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIGZkX3dyaXRlKGZkLCBpb3ZzX3B0ciwgaW92c19sZW4sIG53cml0dGVuX3B0cikgewogICAgICBjb25zdCBidWZmZXIgPSBuZXcgRGF0YVZpZXcoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBpb3ZlY3MgPSBDaW92ZWMucmVhZF9ieXRlc19hcnJheShidWZmZXIsIGlvdnNfcHRyLCBpb3ZzX2xlbik7CiAgICAgICAgbGV0IG53cml0dGVuID0gMDsKICAgICAgICBmb3IgKGNvbnN0IGlvdmVjIG9mIGlvdmVjcykgewogICAgICAgICAgY29uc3QgZGF0YSA9IGJ1ZmZlcjguc2xpY2UoaW92ZWMuYnVmLCBpb3ZlYy5idWYgKyBpb3ZlYy5idWZfbGVuKTsKICAgICAgICAgIGNvbnN0IHsgcmV0LCBud3JpdHRlbjogbndyaXR0ZW5fcGFydCB9ID0gc2VsZi5mZHNbZmRdLmZkX3dyaXRlKGRhdGEpOwogICAgICAgICAgaWYgKHJldCAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICAgIGJ1ZmZlci5zZXRVaW50MzIobndyaXR0ZW5fcHRyLCBud3JpdHRlbiwgdHJ1ZSk7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgICB9CiAgICAgICAgICBud3JpdHRlbiArPSBud3JpdHRlbl9wYXJ0OwogICAgICAgICAgaWYgKG53cml0dGVuX3BhcnQgIT0gZGF0YS5ieXRlTGVuZ3RoKSB7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBidWZmZXIuc2V0VWludDMyKG53cml0dGVuX3B0ciwgbndyaXR0ZW4sIHRydWUpOwogICAgICAgIHJldHVybiBFUlJOT19TVUNDRVNTOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX2NyZWF0ZV9kaXJlY3RvcnkoZmQsIHBhdGhfcHRyLCBwYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF9jcmVhdGVfZGlyZWN0b3J5KHBhdGgpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwYXRoX2ZpbGVzdGF0X2dldChmZCwgZmxhZ3MsIHBhdGhfcHRyLCBwYXRoX2xlbiwgZmlsZXN0YXRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCB7IHJldCwgZmlsZXN0YXQgfSA9IHNlbGYuZmRzW2ZkXS5wYXRoX2ZpbGVzdGF0X2dldChmbGFncywgcGF0aCk7CiAgICAgICAgaWYgKGZpbGVzdGF0ICE9IG51bGwpIHsKICAgICAgICAgIGZpbGVzdGF0LndyaXRlX2J5dGVzKGJ1ZmZlciwgZmlsZXN0YXRfcHRyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9maWxlc3RhdF9zZXRfdGltZXMoZmQsIGZsYWdzLCBwYXRoX3B0ciwgcGF0aF9sZW4sIGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIHJldHVybiBzZWxmLmZkc1tmZF0ucGF0aF9maWxlc3RhdF9zZXRfdGltZXMoZmxhZ3MsIHBhdGgsIGF0aW0sIG10aW0sIGZzdF9mbGFncyk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfbGluayhvbGRfZmQsIG9sZF9mbGFncywgb2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9sZW4sIG5ld19mZCwgbmV3X3BhdGhfcHRyLCBuZXdfcGF0aF9sZW4pIHsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbb2xkX2ZkXSAhPSB2b2lkIDAgJiYgc2VsZi5mZHNbbmV3X2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBvbGRfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX3B0ciArIG9sZF9wYXRoX2xlbikpOwogICAgICAgIGNvbnN0IG5ld19wYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfcHRyICsgbmV3X3BhdGhfbGVuKSk7CiAgICAgICAgY29uc3QgeyByZXQsIGlub2RlX29iaiB9ID0gc2VsZi5mZHNbb2xkX2ZkXS5wYXRoX2xvb2t1cChvbGRfcGF0aCwgb2xkX2ZsYWdzKTsKICAgICAgICBpZiAoaW5vZGVfb2JqID09IG51bGwpIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHJldHVybiBzZWxmLmZkc1tuZXdfZmRdLnBhdGhfbGluayhuZXdfcGF0aCwgaW5vZGVfb2JqLCBmYWxzZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfb3BlbihmZCwgZGlyZmxhZ3MsIHBhdGhfcHRyLCBwYXRoX2xlbiwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzLCBvcGVuZWRfZmRfcHRyKSB7CiAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBEYXRhVmlldyhzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgY29uc3QgYnVmZmVyOCA9IG5ldyBVaW50OEFycmF5KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBpZiAoc2VsZi5mZHNbZmRdICE9IHZvaWQgMCkgewogICAgICAgIGNvbnN0IHBhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2UocGF0aF9wdHIsIHBhdGhfcHRyICsgcGF0aF9sZW4pKTsKICAgICAgICBkZWJ1Zy5sb2cocGF0aCk7CiAgICAgICAgY29uc3QgeyByZXQsIGZkX29iaiB9ID0gc2VsZi5mZHNbZmRdLnBhdGhfb3BlbihkaXJmbGFncywgcGF0aCwgb2ZsYWdzLCBmc19yaWdodHNfYmFzZSwgZnNfcmlnaHRzX2luaGVyaXRpbmcsIGZkX2ZsYWdzKTsKICAgICAgICBpZiAocmV0ICE9IDApIHsKICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfQogICAgICAgIHNlbGYuZmRzLnB1c2goZmRfb2JqKTsKICAgICAgICBjb25zdCBvcGVuZWRfZmQgPSBzZWxmLmZkcy5sZW5ndGggLSAxOwogICAgICAgIGJ1ZmZlci5zZXRVaW50MzIob3BlbmVkX2ZkX3B0ciwgb3BlbmVkX2ZkLCB0cnVlKTsKICAgICAgICByZXR1cm4gMDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF9yZWFkbGluayhmZCwgcGF0aF9wdHIsIHBhdGhfbGVuLCBidWZfcHRyLCBidWZfbGVuLCBucmVhZF9wdHIpIHsKICAgICAgY29uc3QgYnVmZmVyID0gbmV3IERhdGFWaWV3KHNlbGYuaW5zdC5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3QgcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShwYXRoX3B0ciwgcGF0aF9wdHIgKyBwYXRoX2xlbikpOwogICAgICAgIGRlYnVnLmxvZyhwYXRoKTsKICAgICAgICBjb25zdCB7IHJldCwgZGF0YSB9ID0gc2VsZi5mZHNbZmRdLnBhdGhfcmVhZGxpbmsocGF0aCk7CiAgICAgICAgaWYgKGRhdGEgIT0gbnVsbCkgewogICAgICAgICAgY29uc3QgZGF0YV9idWYgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoZGF0YSk7CiAgICAgICAgICBpZiAoZGF0YV9idWYubGVuZ3RoID4gYnVmX2xlbikgewogICAgICAgICAgICBidWZmZXIuc2V0VWludDMyKG5yZWFkX3B0ciwgMCwgdHJ1ZSk7CiAgICAgICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICAgICAgfQogICAgICAgICAgYnVmZmVyOC5zZXQoZGF0YV9idWYsIGJ1Zl9wdHIpOwogICAgICAgICAgYnVmZmVyLnNldFVpbnQzMihucmVhZF9wdHIsIGRhdGFfYnVmLmxlbmd0aCwgdHJ1ZSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfcmVtb3ZlX2RpcmVjdG9yeShmZCwgcGF0aF9wdHIsIHBhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5wYXRoX3JlbW92ZV9kaXJlY3RvcnkocGF0aCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfcmVuYW1lKGZkLCBvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX2xlbiwgbmV3X2ZkLCBuZXdfcGF0aF9wdHIsIG5ld19wYXRoX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGlmIChzZWxmLmZkc1tmZF0gIT0gdm9pZCAwICYmIHNlbGYuZmRzW25ld19mZF0gIT0gdm9pZCAwKSB7CiAgICAgICAgY29uc3Qgb2xkX3BhdGggPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IikuZGVjb2RlKGJ1ZmZlcjguc2xpY2Uob2xkX3BhdGhfcHRyLCBvbGRfcGF0aF9wdHIgKyBvbGRfcGF0aF9sZW4pKTsKICAgICAgICBjb25zdCBuZXdfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShuZXdfcGF0aF9wdHIsIG5ld19wYXRoX3B0ciArIG5ld19wYXRoX2xlbikpOwogICAgICAgIGxldCB7IHJldCwgaW5vZGVfb2JqIH0gPSBzZWxmLmZkc1tmZF0ucGF0aF91bmxpbmsob2xkX3BhdGgpOwogICAgICAgIGlmIChpbm9kZV9vYmogPT0gbnVsbCkgewogICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9CiAgICAgICAgcmV0ID0gc2VsZi5mZHNbbmV3X2ZkXS5wYXRoX2xpbmsobmV3X3BhdGgsIGlub2RlX29iaiwgdHJ1ZSk7CiAgICAgICAgaWYgKHJldCAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICBpZiAoc2VsZi5mZHNbZmRdLnBhdGhfbGluayhvbGRfcGF0aCwgaW5vZGVfb2JqLCB0cnVlKSAhPSBFUlJOT19TVUNDRVNTKSB7CiAgICAgICAgICAgIHRocm93ICJwYXRoX2xpbmsgc2hvdWxkIGFsd2F5cyByZXR1cm4gc3VjY2VzcyB3aGVuIHJlbGlua2luZyBhbiBpbm9kZSBiYWNrIHRvIHRoZSBvcmlnaW5hbCBwbGFjZSI7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0JBREY7CiAgICAgIH0KICAgIH0sIHBhdGhfc3ltbGluayhvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX2xlbiwgZmQsIG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBvbGRfcGF0aCA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiKS5kZWNvZGUoYnVmZmVyOC5zbGljZShvbGRfcGF0aF9wdHIsIG9sZF9wYXRoX3B0ciArIG9sZF9wYXRoX2xlbikpOwogICAgICAgIGNvbnN0IG5ld19wYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKG5ld19wYXRoX3B0ciwgbmV3X3BhdGhfcHRyICsgbmV3X3BhdGhfbGVuKSk7CiAgICAgICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXR1cm4gRVJSTk9fQkFERjsKICAgICAgfQogICAgfSwgcGF0aF91bmxpbmtfZmlsZShmZCwgcGF0aF9wdHIsIHBhdGhfbGVuKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjggPSBuZXcgVWludDhBcnJheShzZWxmLmluc3QuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgaWYgKHNlbGYuZmRzW2ZkXSAhPSB2b2lkIDApIHsKICAgICAgICBjb25zdCBwYXRoID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpLmRlY29kZShidWZmZXI4LnNsaWNlKHBhdGhfcHRyLCBwYXRoX3B0ciArIHBhdGhfbGVuKSk7CiAgICAgICAgcmV0dXJuIHNlbGYuZmRzW2ZkXS5wYXRoX3VubGlua19maWxlKHBhdGgpOwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBFUlJOT19CQURGOwogICAgICB9CiAgICB9LCBwb2xsX29uZW9mZihpbl8sIG91dCwgbnN1YnNjcmlwdGlvbnMpIHsKICAgICAgdGhyb3cgImFzeW5jIGlvIG5vdCBzdXBwb3J0ZWQiOwogICAgfSwgcHJvY19leGl0KGV4aXRfY29kZSkgewogICAgICB0aHJvdyBuZXcgV0FTSVByb2NFeGl0KGV4aXRfY29kZSk7CiAgICB9LCBwcm9jX3JhaXNlKHNpZykgewogICAgICB0aHJvdyAicmFpc2VkIHNpZ25hbCAiICsgc2lnOwogICAgfSwgc2NoZWRfeWllbGQoKSB7CiAgICB9LCByYW5kb21fZ2V0KGJ1ZiwgYnVmX2xlbikgewogICAgICBjb25zdCBidWZmZXI4ID0gbmV3IFVpbnQ4QXJyYXkoc2VsZi5pbnN0LmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYnVmX2xlbjsgaSsrKSB7CiAgICAgICAgYnVmZmVyOFtidWYgKyBpXSA9IE1hdGgucmFuZG9tKCkgKiAyNTYgfCAwOwogICAgICB9CiAgICB9LCBzb2NrX3JlY3YoZmQsIHJpX2RhdGEsIHJpX2ZsYWdzKSB7CiAgICAgIHRocm93ICJzb2NrZXRzIG5vdCBzdXBwb3J0ZWQiOwogICAgfSwgc29ja19zZW5kKGZkLCBzaV9kYXRhLCBzaV9mbGFncykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHNvY2tfc2h1dGRvd24oZmQsIGhvdykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0sIHNvY2tfYWNjZXB0KGZkLCBmbGFncykgewogICAgICB0aHJvdyAic29ja2V0cyBub3Qgc3VwcG9ydGVkIjsKICAgIH0gfTsKICB9Cn07CgovLyBub2RlX21vZHVsZXMvQGJqb3JuMy9icm93c2VyX3dhc2lfc2hpbS9kaXN0L2ZkLmpzCnZhciBGZCA9IGNsYXNzIHsKICBmZF9hbGxvY2F0ZShvZmZzZXQsIGxlbikgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfY2xvc2UoKSB7CiAgICByZXR1cm4gMDsKICB9CiAgZmRfZmRzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBmZHN0YXQ6IG51bGwgfTsKICB9CiAgZmRfZmRzdGF0X3NldF9mbGFncyhmbGFncykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfZmRzdGF0X3NldF9yaWdodHMoZnNfcmlnaHRzX2Jhc2UsIGZzX3JpZ2h0c19pbmhlcml0aW5nKSB7CiAgICByZXR1cm4gRVJSTk9fTk9UU1VQOwogIH0KICBmZF9maWxlc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZmlsZXN0YXQ6IG51bGwgfTsKICB9CiAgZmRfZmlsZXN0YXRfc2V0X3NpemUoc2l6ZSkgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfZmlsZXN0YXRfc2V0X3RpbWVzKGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgZmRfcHJlYWQoc2l6ZSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZGF0YTogbmV3IFVpbnQ4QXJyYXkoKSB9OwogIH0KICBmZF9wcmVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBwcmVzdGF0OiBudWxsIH07CiAgfQogIGZkX3B3cml0ZShkYXRhLCBvZmZzZXQpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBud3JpdHRlbjogMCB9OwogIH0KICBmZF9yZWFkKHNpemUpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBkYXRhOiBuZXcgVWludDhBcnJheSgpIH07CiAgfQogIGZkX3JlYWRkaXJfc2luZ2xlKGNvb2tpZSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RTVVAsIGRpcmVudDogbnVsbCB9OwogIH0KICBmZF9zZWVrKG9mZnNldCwgd2hlbmNlKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF9zeW5jKCkgewogICAgcmV0dXJuIDA7CiAgfQogIGZkX3RlbGwoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF93cml0ZShkYXRhKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgbndyaXR0ZW46IDAgfTsKICB9CiAgcGF0aF9jcmVhdGVfZGlyZWN0b3J5KHBhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfZmlsZXN0YXRfZ2V0KGZsYWdzLCBwYXRoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZmlsZXN0YXQ6IG51bGwgfTsKICB9CiAgcGF0aF9maWxlc3RhdF9zZXRfdGltZXMoZmxhZ3MsIHBhdGgsIGF0aW0sIG10aW0sIGZzdF9mbGFncykgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgcGF0aF9saW5rKHBhdGgsIGlub2RlLCBhbGxvd19kaXIpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfdW5saW5rKHBhdGgpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBpbm9kZV9vYmo6IG51bGwgfTsKICB9CiAgcGF0aF9sb29rdXAocGF0aCwgZGlyZmxhZ3MpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UU1VQLCBpbm9kZV9vYmo6IG51bGwgfTsKICB9CiAgcGF0aF9vcGVuKGRpcmZsYWdzLCBwYXRoLCBvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZywgZmRfZmxhZ3MpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9URElSLCBmZF9vYmo6IG51bGwgfTsKICB9CiAgcGF0aF9yZWFkbGluayhwYXRoKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVFNVUCwgZGF0YTogbnVsbCB9OwogIH0KICBwYXRoX3JlbW92ZV9kaXJlY3RvcnkocGF0aCkgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9CiAgcGF0aF9yZW5hbWUob2xkX3BhdGgsIG5ld19mZCwgbmV3X3BhdGgpIHsKICAgIHJldHVybiBFUlJOT19OT1RTVVA7CiAgfQogIHBhdGhfdW5saW5rX2ZpbGUocGF0aCkgewogICAgcmV0dXJuIEVSUk5PX05PVFNVUDsKICB9Cn07CnZhciBJbm9kZSA9IGNsYXNzIHsKfTsKCi8vIG5vZGVfbW9kdWxlcy9AYmpvcm4zL2Jyb3dzZXJfd2FzaV9zaGltL2Rpc3QvZnNfbWVtLmpzCnZhciBPcGVuRmlsZSA9IGNsYXNzIGV4dGVuZHMgRmQgewogIGZkX2FsbG9jYXRlKG9mZnNldCwgbGVuKSB7CiAgICBpZiAodGhpcy5maWxlLnNpemUgPiBvZmZzZXQgKyBsZW4pIHsKICAgIH0gZWxzZSB7CiAgICAgIGNvbnN0IG5ld19kYXRhID0gbmV3IFVpbnQ4QXJyYXkoTnVtYmVyKG9mZnNldCArIGxlbikpOwogICAgICBuZXdfZGF0YS5zZXQodGhpcy5maWxlLmRhdGEsIDApOwogICAgICB0aGlzLmZpbGUuZGF0YSA9IG5ld19kYXRhOwogICAgfQogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIGZkc3RhdDogbmV3IEZkc3RhdChGSUxFVFlQRV9SRUdVTEFSX0ZJTEUsIDApIH07CiAgfQogIGZkX2ZpbGVzdGF0X3NldF9zaXplKHNpemUpIHsKICAgIGlmICh0aGlzLmZpbGUuc2l6ZSA+IHNpemUpIHsKICAgICAgdGhpcy5maWxlLmRhdGEgPSBuZXcgVWludDhBcnJheSh0aGlzLmZpbGUuZGF0YS5idWZmZXIuc2xpY2UoMCwgTnVtYmVyKHNpemUpKSk7CiAgICB9IGVsc2UgewogICAgICBjb25zdCBuZXdfZGF0YSA9IG5ldyBVaW50OEFycmF5KE51bWJlcihzaXplKSk7CiAgICAgIG5ld19kYXRhLnNldCh0aGlzLmZpbGUuZGF0YSwgMCk7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3X2RhdGE7CiAgICB9CiAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICB9CiAgZmRfcmVhZChzaXplKSB7CiAgICBjb25zdCBzbGljZSA9IHRoaXMuZmlsZS5kYXRhLnNsaWNlKE51bWJlcih0aGlzLmZpbGVfcG9zKSwgTnVtYmVyKHRoaXMuZmlsZV9wb3MgKyBCaWdJbnQoc2l6ZSkpKTsKICAgIHRoaXMuZmlsZV9wb3MgKz0gQmlnSW50KHNsaWNlLmxlbmd0aCk7CiAgICByZXR1cm4geyByZXQ6IDAsIGRhdGE6IHNsaWNlIH07CiAgfQogIGZkX3ByZWFkKHNpemUsIG9mZnNldCkgewogICAgY29uc3Qgc2xpY2UgPSB0aGlzLmZpbGUuZGF0YS5zbGljZShOdW1iZXIob2Zmc2V0KSwgTnVtYmVyKG9mZnNldCArIEJpZ0ludChzaXplKSkpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBkYXRhOiBzbGljZSB9OwogIH0KICBmZF9zZWVrKG9mZnNldCwgd2hlbmNlKSB7CiAgICBsZXQgY2FsY3VsYXRlZF9vZmZzZXQ7CiAgICBzd2l0Y2ggKHdoZW5jZSkgewogICAgICBjYXNlIFdIRU5DRV9TRVQ6CiAgICAgICAgY2FsY3VsYXRlZF9vZmZzZXQgPSBvZmZzZXQ7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgV0hFTkNFX0NVUjoKICAgICAgICBjYWxjdWxhdGVkX29mZnNldCA9IHRoaXMuZmlsZV9wb3MgKyBvZmZzZXQ7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgV0hFTkNFX0VORDoKICAgICAgICBjYWxjdWxhdGVkX29mZnNldCA9IEJpZ0ludCh0aGlzLmZpbGUuZGF0YS5ieXRlTGVuZ3RoKSArIG9mZnNldDsKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0lOVkFMLCBvZmZzZXQ6IDBuIH07CiAgICB9CiAgICBpZiAoY2FsY3VsYXRlZF9vZmZzZXQgPCAwKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fSU5WQUwsIG9mZnNldDogMG4gfTsKICAgIH0KICAgIHRoaXMuZmlsZV9wb3MgPSBjYWxjdWxhdGVkX29mZnNldDsKICAgIHJldHVybiB7IHJldDogMCwgb2Zmc2V0OiB0aGlzLmZpbGVfcG9zIH07CiAgfQogIGZkX3RlbGwoKSB7CiAgICByZXR1cm4geyByZXQ6IDAsIG9mZnNldDogdGhpcy5maWxlX3BvcyB9OwogIH0KICBmZF93cml0ZShkYXRhKSB7CiAgICBpZiAodGhpcy5maWxlLnJlYWRvbmx5KQogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG53cml0dGVuOiAwIH07CiAgICBpZiAodGhpcy5maWxlX3BvcyArIEJpZ0ludChkYXRhLmJ5dGVMZW5ndGgpID4gdGhpcy5maWxlLnNpemUpIHsKICAgICAgY29uc3Qgb2xkID0gdGhpcy5maWxlLmRhdGE7CiAgICAgIHRoaXMuZmlsZS5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoTnVtYmVyKHRoaXMuZmlsZV9wb3MgKyBCaWdJbnQoZGF0YS5ieXRlTGVuZ3RoKSkpOwogICAgICB0aGlzLmZpbGUuZGF0YS5zZXQob2xkKTsKICAgIH0KICAgIHRoaXMuZmlsZS5kYXRhLnNldChkYXRhLCBOdW1iZXIodGhpcy5maWxlX3BvcykpOwogICAgdGhpcy5maWxlX3BvcyArPSBCaWdJbnQoZGF0YS5ieXRlTGVuZ3RoKTsKICAgIHJldHVybiB7IHJldDogMCwgbndyaXR0ZW46IGRhdGEuYnl0ZUxlbmd0aCB9OwogIH0KICBmZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KSB7CiAgICBpZiAodGhpcy5maWxlLnJlYWRvbmx5KQogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG53cml0dGVuOiAwIH07CiAgICBpZiAob2Zmc2V0ICsgQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCkgPiB0aGlzLmZpbGUuc2l6ZSkgewogICAgICBjb25zdCBvbGQgPSB0aGlzLmZpbGUuZGF0YTsKICAgICAgdGhpcy5maWxlLmRhdGEgPSBuZXcgVWludDhBcnJheShOdW1iZXIob2Zmc2V0ICsgQmlnSW50KGRhdGEuYnl0ZUxlbmd0aCkpKTsKICAgICAgdGhpcy5maWxlLmRhdGEuc2V0KG9sZCk7CiAgICB9CiAgICB0aGlzLmZpbGUuZGF0YS5zZXQoZGF0YSwgTnVtYmVyKG9mZnNldCkpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBud3JpdHRlbjogZGF0YS5ieXRlTGVuZ3RoIH07CiAgfQogIGZkX2ZpbGVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgZmlsZXN0YXQ6IHRoaXMuZmlsZS5zdGF0KCkgfTsKICB9CiAgY29uc3RydWN0b3IoZmlsZSkgewogICAgc3VwZXIoKTsKICAgIHRoaXMuZmlsZV9wb3MgPSAwbjsKICAgIHRoaXMuZmlsZSA9IGZpbGU7CiAgfQp9Owp2YXIgT3BlbkRpcmVjdG9yeSA9IGNsYXNzIGV4dGVuZHMgRmQgewogIGZkX3NlZWsob2Zmc2V0LCB3aGVuY2UpIHsKICAgIHJldHVybiB7IHJldDogRVJSTk9fQkFERiwgb2Zmc2V0OiAwbiB9OwogIH0KICBmZF90ZWxsKCkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBvZmZzZXQ6IDBuIH07CiAgfQogIGZkX2FsbG9jYXRlKG9mZnNldCwgbGVuKSB7CiAgICByZXR1cm4gRVJSTk9fQkFERjsKICB9CiAgZmRfZmRzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgZmRzdGF0OiBuZXcgRmRzdGF0KEZJTEVUWVBFX0RJUkVDVE9SWSwgMCkgfTsKICB9CiAgZmRfcmVhZGRpcl9zaW5nbGUoY29va2llKSB7CiAgICBpZiAoZGVidWcuZW5hYmxlZCkgewogICAgICBkZWJ1Zy5sb2coInJlYWRkaXJfc2luZ2xlIiwgY29va2llKTsKICAgICAgZGVidWcubG9nKGNvb2tpZSwgdGhpcy5kaXIuY29udGVudHMua2V5cygpKTsKICAgIH0KICAgIGlmIChjb29raWUgPT0gMG4pIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBkaXJlbnQ6IG5ldyBEaXJlbnQoMW4sICIuIiwgRklMRVRZUEVfRElSRUNUT1JZKSB9OwogICAgfSBlbHNlIGlmIChjb29raWUgPT0gMW4pIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBkaXJlbnQ6IG5ldyBEaXJlbnQoMm4sICIuLiIsIEZJTEVUWVBFX0RJUkVDVE9SWSkgfTsKICAgIH0KICAgIGlmIChjb29raWUgPj0gQmlnSW50KHRoaXMuZGlyLmNvbnRlbnRzLnNpemUpICsgMm4pIHsKICAgICAgcmV0dXJuIHsgcmV0OiAwLCBkaXJlbnQ6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IFtuYW1lLCBlbnRyeV0gPSBBcnJheS5mcm9tKHRoaXMuZGlyLmNvbnRlbnRzLmVudHJpZXMoKSlbTnVtYmVyKGNvb2tpZSAtIDJuKV07CiAgICByZXR1cm4geyByZXQ6IDAsIGRpcmVudDogbmV3IERpcmVudChjb29raWUgKyAxbiwgbmFtZSwgZW50cnkuc3RhdCgpLmZpbGV0eXBlKSB9OwogIH0KICBwYXRoX2ZpbGVzdGF0X2dldChmbGFncywgcGF0aF9zdHIpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX2VyciwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX2VyciwgZmlsZXN0YXQ6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0LCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0LCBmaWxlc3RhdDogbnVsbCB9OwogICAgfQogICAgcmV0dXJuIHsgcmV0OiAwLCBmaWxlc3RhdDogZW50cnkuc3RhdCgpIH07CiAgfQogIHBhdGhfbG9va3VwKHBhdGhfc3RyLCBkaXJmbGFncykgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhdGhfcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0LCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0LCBpbm9kZV9vYmo6IG51bGwgfTsKICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgaW5vZGVfb2JqOiBlbnRyeSB9OwogIH0KICBwYXRoX29wZW4oZGlyZmxhZ3MsIHBhdGhfc3RyLCBvZmxhZ3MsIGZzX3JpZ2h0c19iYXNlLCBmc19yaWdodHNfaW5oZXJpdGluZywgZmRfZmxhZ3MpIHsKICAgIGNvbnN0IHsgcmV0OiBwYXRoX3JldCwgcGF0aCB9ID0gUGF0aC5mcm9tKHBhdGhfc3RyKTsKICAgIGlmIChwYXRoID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBwYXRoX3JldCwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICBsZXQgeyByZXQsIGVudHJ5IH0gPSB0aGlzLmRpci5nZXRfZW50cnlfZm9yX3BhdGgocGF0aCk7CiAgICBpZiAoZW50cnkgPT0gbnVsbCkgewogICAgICBpZiAocmV0ICE9IEVSUk5PX05PRU5UKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0LCBmZF9vYmo6IG51bGwgfTsKICAgICAgfQogICAgICBpZiAoKG9mbGFncyAmIE9GTEFHU19DUkVBVCkgPT0gT0ZMQUdTX0NSRUFUKSB7CiAgICAgICAgY29uc3QgeyByZXQ6IHJldDIsIGVudHJ5OiBuZXdfZW50cnkgfSA9IHRoaXMuZGlyLmNyZWF0ZV9lbnRyeV9mb3JfcGF0aChwYXRoX3N0ciwgKG9mbGFncyAmIE9GTEFHU19ESVJFQ1RPUlkpID09IE9GTEFHU19ESVJFQ1RPUlkpOwogICAgICAgIGlmIChuZXdfZW50cnkgPT0gbnVsbCkgewogICAgICAgICAgcmV0dXJuIHsgcmV0OiByZXQyLCBmZF9vYmo6IG51bGwgfTsKICAgICAgICB9CiAgICAgICAgZW50cnkgPSBuZXdfZW50cnk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT0VOVCwgZmRfb2JqOiBudWxsIH07CiAgICAgIH0KICAgIH0gZWxzZSBpZiAoKG9mbGFncyAmIE9GTEFHU19FWENMKSA9PSBPRkxBR1NfRVhDTCkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0VYSVNULCBmZF9vYmo6IG51bGwgfTsKICAgIH0KICAgIGlmICgob2ZsYWdzICYgT0ZMQUdTX0RJUkVDVE9SWSkgPT0gT0ZMQUdTX0RJUkVDVE9SWSAmJiBlbnRyeS5zdGF0KCkuZmlsZXR5cGUgIT09IEZJTEVUWVBFX0RJUkVDVE9SWSkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgZmRfb2JqOiBudWxsIH07CiAgICB9CiAgICByZXR1cm4gZW50cnkucGF0aF9vcGVuKG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZkX2ZsYWdzKTsKICB9CiAgcGF0aF9jcmVhdGVfZGlyZWN0b3J5KHBhdGgpIHsKICAgIHJldHVybiB0aGlzLnBhdGhfb3BlbigwLCBwYXRoLCBPRkxBR1NfQ1JFQVQgfCBPRkxBR1NfRElSRUNUT1JZLCAwbiwgMG4sIDApLnJldDsKICB9CiAgcGF0aF9saW5rKHBhdGhfc3RyLCBpbm9kZSwgYWxsb3dfZGlyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXRoX3JldDsKICAgIH0KICAgIGlmIChwYXRoLmlzX2RpcikgewogICAgICByZXR1cm4gRVJSTk9fTk9FTlQ7CiAgICB9CiAgICBjb25zdCB7IHJldDogcGFyZW50X3JldCwgcGFyZW50X2VudHJ5LCBmaWxlbmFtZSwgZW50cnkgfSA9IHRoaXMuZGlyLmdldF9wYXJlbnRfZGlyX2FuZF9lbnRyeV9mb3JfcGF0aChwYXRoLCB0cnVlKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCB8fCBmaWxlbmFtZSA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXJlbnRfcmV0OwogICAgfQogICAgaWYgKGVudHJ5ICE9IG51bGwpIHsKICAgICAgY29uc3Qgc291cmNlX2lzX2RpciA9IGlub2RlLnN0YXQoKS5maWxldHlwZSA9PSBGSUxFVFlQRV9ESVJFQ1RPUlk7CiAgICAgIGNvbnN0IHRhcmdldF9pc19kaXIgPSBlbnRyeS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfRElSRUNUT1JZOwogICAgICBpZiAoc291cmNlX2lzX2RpciAmJiB0YXJnZXRfaXNfZGlyKSB7CiAgICAgICAgaWYgKGFsbG93X2RpciAmJiBlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkgewogICAgICAgICAgaWYgKGVudHJ5LmNvbnRlbnRzLnNpemUgPT0gMCkgewogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcmV0dXJuIEVSUk5PX05PVEVNUFRZOwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXR1cm4gRVJSTk9fRVhJU1Q7CiAgICAgICAgfQogICAgICB9IGVsc2UgaWYgKHNvdXJjZV9pc19kaXIgJiYgIXRhcmdldF9pc19kaXIpIHsKICAgICAgICByZXR1cm4gRVJSTk9fTk9URElSOwogICAgICB9IGVsc2UgaWYgKCFzb3VyY2VfaXNfZGlyICYmIHRhcmdldF9pc19kaXIpIHsKICAgICAgICByZXR1cm4gRVJSTk9fSVNESVI7CiAgICAgIH0gZWxzZSBpZiAoaW5vZGUuc3RhdCgpLmZpbGV0eXBlID09IEZJTEVUWVBFX1JFR1VMQVJfRklMRSAmJiBlbnRyeS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfUkVHVUxBUl9GSUxFKSB7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIEVSUk5PX0VYSVNUOwogICAgICB9CiAgICB9CiAgICBpZiAoIWFsbG93X2RpciAmJiBpbm9kZS5zdGF0KCkuZmlsZXR5cGUgPT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgIHJldHVybiBFUlJOT19QRVJNOwogICAgfQogICAgcGFyZW50X2VudHJ5LmNvbnRlbnRzLnNldChmaWxlbmFtZSwgaW5vZGUpOwogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIHBhdGhfdW5saW5rKHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogcGF0aF9yZXQsIGlub2RlX29iajogbnVsbCB9OwogICAgfQogICAgY29uc3QgeyByZXQ6IHBhcmVudF9yZXQsIHBhcmVudF9lbnRyeSwgZmlsZW5hbWUsIGVudHJ5IH0gPSB0aGlzLmRpci5nZXRfcGFyZW50X2Rpcl9hbmRfZW50cnlfZm9yX3BhdGgocGF0aCwgdHJ1ZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhcmVudF9yZXQsIGlub2RlX29iajogbnVsbCB9OwogICAgfQogICAgaWYgKGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT0VOVCwgaW5vZGVfb2JqOiBudWxsIH07CiAgICB9CiAgICBwYXJlbnRfZW50cnkuY29udGVudHMuZGVsZXRlKGZpbGVuYW1lKTsKICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgaW5vZGVfb2JqOiBlbnRyeSB9OwogIH0KICBwYXRoX3VubGlua19maWxlKHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXRoX3JldDsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIGZhbHNlKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCB8fCBmaWxlbmFtZSA9PSBudWxsIHx8IGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHBhcmVudF9yZXQ7CiAgICB9CiAgICBpZiAoZW50cnkuc3RhdCgpLmZpbGV0eXBlID09PSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgcmV0dXJuIEVSUk5PX0lTRElSOwogICAgfQogICAgcGFyZW50X2VudHJ5LmNvbnRlbnRzLmRlbGV0ZShmaWxlbmFtZSk7CiAgICByZXR1cm4gRVJSTk9fU1VDQ0VTUzsKICB9CiAgcGF0aF9yZW1vdmVfZGlyZWN0b3J5KHBhdGhfc3RyKSB7CiAgICBjb25zdCB7IHJldDogcGF0aF9yZXQsIHBhdGggfSA9IFBhdGguZnJvbShwYXRoX3N0cik7CiAgICBpZiAocGF0aCA9PSBudWxsKSB7CiAgICAgIHJldHVybiBwYXRoX3JldDsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5kaXIuZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIGZhbHNlKTsKICAgIGlmIChwYXJlbnRfZW50cnkgPT0gbnVsbCB8fCBmaWxlbmFtZSA9PSBudWxsIHx8IGVudHJ5ID09IG51bGwpIHsKICAgICAgcmV0dXJuIHBhcmVudF9yZXQ7CiAgICB9CiAgICBpZiAoIShlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkgfHwgZW50cnkuc3RhdCgpLmZpbGV0eXBlICE9PSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgcmV0dXJuIEVSUk5PX05PVERJUjsKICAgIH0KICAgIGlmIChlbnRyeS5jb250ZW50cy5zaXplICE9PSAwKSB7CiAgICAgIHJldHVybiBFUlJOT19OT1RFTVBUWTsKICAgIH0KICAgIGlmICghcGFyZW50X2VudHJ5LmNvbnRlbnRzLmRlbGV0ZShmaWxlbmFtZSkpIHsKICAgICAgcmV0dXJuIEVSUk5PX05PRU5UOwogICAgfQogICAgcmV0dXJuIEVSUk5PX1NVQ0NFU1M7CiAgfQogIGZkX2ZpbGVzdGF0X2dldCgpIHsKICAgIHJldHVybiB7IHJldDogMCwgZmlsZXN0YXQ6IHRoaXMuZGlyLnN0YXQoKSB9OwogIH0KICBmZF9maWxlc3RhdF9zZXRfc2l6ZShzaXplKSB7CiAgICByZXR1cm4gRVJSTk9fQkFERjsKICB9CiAgZmRfcmVhZChzaXplKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIGRhdGE6IG5ldyBVaW50OEFycmF5KCkgfTsKICB9CiAgZmRfcHJlYWQoc2l6ZSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIGRhdGE6IG5ldyBVaW50OEFycmF5KCkgfTsKICB9CiAgZmRfd3JpdGUoZGF0YSkgewogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19CQURGLCBud3JpdHRlbjogMCB9OwogIH0KICBmZF9wd3JpdGUoZGF0YSwgb2Zmc2V0KSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX0JBREYsIG53cml0dGVuOiAwIH07CiAgfQogIGNvbnN0cnVjdG9yKGRpcikgewogICAgc3VwZXIoKTsKICAgIHRoaXMuZGlyID0gZGlyOwogIH0KfTsKdmFyIFByZW9wZW5EaXJlY3RvcnkgPSBjbGFzcyBleHRlbmRzIE9wZW5EaXJlY3RvcnkgewogIGZkX3ByZXN0YXRfZ2V0KCkgewogICAgcmV0dXJuIHsgcmV0OiAwLCBwcmVzdGF0OiBQcmVzdGF0LmRpcih0aGlzLnByZXN0YXRfbmFtZSkgfTsKICB9CiAgY29uc3RydWN0b3IobmFtZSwgY29udGVudHMpIHsKICAgIHN1cGVyKG5ldyBEaXJlY3RvcnkoY29udGVudHMpKTsKICAgIHRoaXMucHJlc3RhdF9uYW1lID0gbmFtZTsKICB9Cn07CnZhciBGaWxlID0gY2xhc3MgZXh0ZW5kcyBJbm9kZSB7CiAgcGF0aF9vcGVuKG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZkX2ZsYWdzKSB7CiAgICBpZiAodGhpcy5yZWFkb25seSAmJiAoZnNfcmlnaHRzX2Jhc2UgJiBCaWdJbnQoUklHSFRTX0ZEX1dSSVRFKSkgPT0gQmlnSW50KFJJR0hUU19GRF9XUklURSkpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19QRVJNLCBmZF9vYmo6IG51bGwgfTsKICAgIH0KICAgIGlmICgob2ZsYWdzICYgT0ZMQUdTX1RSVU5DKSA9PSBPRkxBR1NfVFJVTkMpIHsKICAgICAgaWYgKHRoaXMucmVhZG9ubHkpCiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19QRVJNLCBmZF9vYmo6IG51bGwgfTsKICAgICAgdGhpcy5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoW10pOwogICAgfQogICAgY29uc3QgZmlsZSA9IG5ldyBPcGVuRmlsZSh0aGlzKTsKICAgIGlmIChmZF9mbGFncyAmIEZERkxBR1NfQVBQRU5EKQogICAgICBmaWxlLmZkX3NlZWsoMG4sIFdIRU5DRV9FTkQpOwogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBmZF9vYmo6IGZpbGUgfTsKICB9CiAgZ2V0IHNpemUoKSB7CiAgICByZXR1cm4gQmlnSW50KHRoaXMuZGF0YS5ieXRlTGVuZ3RoKTsKICB9CiAgc3RhdCgpIHsKICAgIHJldHVybiBuZXcgRmlsZXN0YXQoRklMRVRZUEVfUkVHVUxBUl9GSUxFLCB0aGlzLnNpemUpOwogIH0KICBjb25zdHJ1Y3RvcihkYXRhLCBvcHRpb25zKSB7CiAgICBzdXBlcigpOwogICAgdGhpcy5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoZGF0YSk7CiAgICB0aGlzLnJlYWRvbmx5ID0gISFvcHRpb25zPy5yZWFkb25seTsKICB9Cn07CnZhciBQYXRoID0gY2xhc3MgUGF0aDIgewogIHN0YXRpYyBmcm9tKHBhdGgpIHsKICAgIGNvbnN0IHNlbGYgPSBuZXcgUGF0aDIoKTsKICAgIHNlbGYuaXNfZGlyID0gcGF0aC5lbmRzV2l0aCgiLyIpOwogICAgaWYgKHBhdGguc3RhcnRzV2l0aCgiLyIpKSB7CiAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9UQ0FQQUJMRSwgcGF0aDogbnVsbCB9OwogICAgfQogICAgaWYgKHBhdGguaW5jbHVkZXMoIlwwIikpIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19JTlZBTCwgcGF0aDogbnVsbCB9OwogICAgfQogICAgZm9yIChjb25zdCBjb21wb25lbnQgb2YgcGF0aC5zcGxpdCgiLyIpKSB7CiAgICAgIGlmIChjb21wb25lbnQgPT09ICIiIHx8IGNvbXBvbmVudCA9PT0gIi4iKSB7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgaWYgKGNvbXBvbmVudCA9PT0gIi4uIikgewogICAgICAgIGlmIChzZWxmLnBhcnRzLnBvcCgpID09IHZvaWQgMCkgewogICAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RDQVBBQkxFLCBwYXRoOiBudWxsIH07CiAgICAgICAgfQogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIHNlbGYucGFydHMucHVzaChjb21wb25lbnQpOwogICAgfQogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBwYXRoOiBzZWxmIH07CiAgfQogIHRvX3BhdGhfc3RyaW5nKCkgewogICAgbGV0IHMgPSB0aGlzLnBhcnRzLmpvaW4oIi8iKTsKICAgIGlmICh0aGlzLmlzX2RpcikgewogICAgICBzICs9ICIvIjsKICAgIH0KICAgIHJldHVybiBzOwogIH0KICBjb25zdHJ1Y3RvcigpIHsKICAgIHRoaXMucGFydHMgPSBbXTsKICAgIHRoaXMuaXNfZGlyID0gZmFsc2U7CiAgfQp9Owp2YXIgRGlyZWN0b3J5ID0gY2xhc3MgZXh0ZW5kcyBJbm9kZSB7CiAgcGF0aF9vcGVuKG9mbGFncywgZnNfcmlnaHRzX2Jhc2UsIGZkX2ZsYWdzKSB7CiAgICByZXR1cm4geyByZXQ6IEVSUk5PX1NVQ0NFU1MsIGZkX29iajogbmV3IE9wZW5EaXJlY3RvcnkodGhpcykgfTsKICB9CiAgc3RhdCgpIHsKICAgIHJldHVybiBuZXcgRmlsZXN0YXQoRklMRVRZUEVfRElSRUNUT1JZLCAwbik7CiAgfQogIGdldF9lbnRyeV9mb3JfcGF0aChwYXRoKSB7CiAgICBsZXQgZW50cnkgPSB0aGlzOwogICAgZm9yIChjb25zdCBjb21wb25lbnQgb2YgcGF0aC5wYXJ0cykgewogICAgICBpZiAoIShlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkpIHsKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgICBjb25zdCBjaGlsZCA9IGVudHJ5LmNvbnRlbnRzLmdldChjb21wb25lbnQpOwogICAgICBpZiAoY2hpbGQgIT09IHZvaWQgMCkgewogICAgICAgIGVudHJ5ID0gY2hpbGQ7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgZGVidWcubG9nKGNvbXBvbmVudCk7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT0VOVCwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgfQogICAgaWYgKHBhdGguaXNfZGlyKSB7CiAgICAgIGlmIChlbnRyeS5zdGF0KCkuZmlsZXR5cGUgIT0gRklMRVRZUEVfRElSRUNUT1JZKSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19OT1RESVIsIGVudHJ5OiBudWxsIH07CiAgICAgIH0KICAgIH0KICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZW50cnkgfTsKICB9CiAgZ2V0X3BhcmVudF9kaXJfYW5kX2VudHJ5X2Zvcl9wYXRoKHBhdGgsIGFsbG93X3VuZGVmaW5lZCkgewogICAgY29uc3QgZmlsZW5hbWUgPSBwYXRoLnBhcnRzLnBvcCgpOwogICAgaWYgKGZpbGVuYW1lID09PSB2b2lkIDApIHsKICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19JTlZBTCwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IHsgcmV0OiBlbnRyeV9yZXQsIGVudHJ5OiBwYXJlbnRfZW50cnkgfSA9IHRoaXMuZ2V0X2VudHJ5X2Zvcl9wYXRoKHBhdGgpOwogICAgaWYgKHBhcmVudF9lbnRyeSA9PSBudWxsKSB7CiAgICAgIHJldHVybiB7IHJldDogZW50cnlfcmV0LCBwYXJlbnRfZW50cnk6IG51bGwsIGZpbGVuYW1lOiBudWxsLCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgaWYgKCEocGFyZW50X2VudHJ5IGluc3RhbmNlb2YgRGlyZWN0b3J5KSkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgIH0KICAgIGNvbnN0IGVudHJ5ID0gcGFyZW50X2VudHJ5LmNvbnRlbnRzLmdldChmaWxlbmFtZSk7CiAgICBpZiAoZW50cnkgPT09IHZvaWQgMCkgewogICAgICBpZiAoIWFsbG93X3VuZGVmaW5lZCkgewogICAgICAgIHJldHVybiB7IHJldDogRVJSTk9fTk9FTlQsIHBhcmVudF9lbnRyeTogbnVsbCwgZmlsZW5hbWU6IG51bGwsIGVudHJ5OiBudWxsIH07CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeTogbnVsbCB9OwogICAgICB9CiAgICB9CiAgICBpZiAocGF0aC5pc19kaXIpIHsKICAgICAgaWYgKGVudHJ5LnN0YXQoKS5maWxldHlwZSAhPSBGSUxFVFlQRV9ESVJFQ1RPUlkpIHsKICAgICAgICByZXR1cm4geyByZXQ6IEVSUk5PX05PVERJUiwgcGFyZW50X2VudHJ5OiBudWxsLCBmaWxlbmFtZTogbnVsbCwgZW50cnk6IG51bGwgfTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHsgcmV0OiBFUlJOT19TVUNDRVNTLCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9OwogIH0KICBjcmVhdGVfZW50cnlfZm9yX3BhdGgocGF0aF9zdHIsIGlzX2RpcikgewogICAgY29uc3QgeyByZXQ6IHBhdGhfcmV0LCBwYXRoIH0gPSBQYXRoLmZyb20ocGF0aF9zdHIpOwogICAgaWYgKHBhdGggPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhdGhfcmV0LCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgbGV0IHsgcmV0OiBwYXJlbnRfcmV0LCBwYXJlbnRfZW50cnksIGZpbGVuYW1lLCBlbnRyeSB9ID0gdGhpcy5nZXRfcGFyZW50X2Rpcl9hbmRfZW50cnlfZm9yX3BhdGgocGF0aCwgdHJ1ZSk7CiAgICBpZiAocGFyZW50X2VudHJ5ID09IG51bGwgfHwgZmlsZW5hbWUgPT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IHBhcmVudF9yZXQsIGVudHJ5OiBudWxsIH07CiAgICB9CiAgICBpZiAoZW50cnkgIT0gbnVsbCkgewogICAgICByZXR1cm4geyByZXQ6IEVSUk5PX0VYSVNULCBlbnRyeTogbnVsbCB9OwogICAgfQogICAgZGVidWcubG9nKCJjcmVhdGUiLCBwYXRoKTsKICAgIGxldCBuZXdfY2hpbGQ7CiAgICBpZiAoIWlzX2RpcikgewogICAgICBuZXdfY2hpbGQgPSBuZXcgRmlsZShuZXcgQXJyYXlCdWZmZXIoMCkpOwogICAgfSBlbHNlIHsKICAgICAgbmV3X2NoaWxkID0gbmV3IERpcmVjdG9yeSgvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpKTsKICAgIH0KICAgIHBhcmVudF9lbnRyeS5jb250ZW50cy5zZXQoZmlsZW5hbWUsIG5ld19jaGlsZCk7CiAgICBlbnRyeSA9IG5ld19jaGlsZDsKICAgIHJldHVybiB7IHJldDogRVJSTk9fU1VDQ0VTUywgZW50cnkgfTsKICB9CiAgY29uc3RydWN0b3IoY29udGVudHMpIHsKICAgIHN1cGVyKCk7CiAgICBpZiAoY29udGVudHMgaW5zdGFuY2VvZiBBcnJheSkgewogICAgICB0aGlzLmNvbnRlbnRzID0gbmV3IE1hcChjb250ZW50cyk7CiAgICB9IGVsc2UgewogICAgICB0aGlzLmNvbnRlbnRzID0gY29udGVudHM7CiAgICB9CiAgfQp9Owp2YXIgQ29uc29sZVN0ZG91dCA9IGNsYXNzIGV4dGVuZHMgRmQgewogIGZkX2ZpbGVzdGF0X2dldCgpIHsKICAgIGNvbnN0IGZpbGVzdGF0ID0gbmV3IEZpbGVzdGF0KEZJTEVUWVBFX0NIQVJBQ1RFUl9ERVZJQ0UsIEJpZ0ludCgwKSk7CiAgICByZXR1cm4geyByZXQ6IDAsIGZpbGVzdGF0IH07CiAgfQogIGZkX2Zkc3RhdF9nZXQoKSB7CiAgICBjb25zdCBmZHN0YXQgPSBuZXcgRmRzdGF0KEZJTEVUWVBFX0NIQVJBQ1RFUl9ERVZJQ0UsIDApOwogICAgZmRzdGF0LmZzX3JpZ2h0c19iYXNlID0gQmlnSW50KFJJR0hUU19GRF9XUklURSk7CiAgICByZXR1cm4geyByZXQ6IDAsIGZkc3RhdCB9OwogIH0KICBmZF93cml0ZShkYXRhKSB7CiAgICB0aGlzLndyaXRlKGRhdGEpOwogICAgcmV0dXJuIHsgcmV0OiAwLCBud3JpdHRlbjogZGF0YS5ieXRlTGVuZ3RoIH07CiAgfQogIHN0YXRpYyBsaW5lQnVmZmVyZWQod3JpdGUpIHsKICAgIGNvbnN0IGRlYyA9IG5ldyBUZXh0RGVjb2RlcigidXRmLTgiLCB7IGZhdGFsOiBmYWxzZSB9KTsKICAgIGxldCBsaW5lX2J1ZiA9ICIiOwogICAgcmV0dXJuIG5ldyBDb25zb2xlU3Rkb3V0KChidWZmZXIpID0+IHsKICAgICAgbGluZV9idWYgKz0gZGVjLmRlY29kZShidWZmZXIsIHsgc3RyZWFtOiB0cnVlIH0pOwogICAgICBjb25zdCBsaW5lcyA9IGxpbmVfYnVmLnNwbGl0KCJcbiIpOwogICAgICBmb3IgKGNvbnN0IFtpLCBsaW5lXSBvZiBsaW5lcy5lbnRyaWVzKCkpIHsKICAgICAgICBpZiAoaSA8IGxpbmVzLmxlbmd0aCAtIDEpIHsKICAgICAgICAgIHdyaXRlKGxpbmUpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBsaW5lX2J1ZiA9IGxpbmU7CiAgICAgICAgfQogICAgICB9CiAgICB9KTsKICB9CiAgY29uc3RydWN0b3Iod3JpdGUpIHsKICAgIHN1cGVyKCk7CiAgICB0aGlzLndyaXRlID0gd3JpdGU7CiAgfQp9OwoKLy8gbm9kZV9tb2R1bGVzL3dhc20taW1wb3J0cy1wYXJzZXIvaW5kZXguanMKZnVuY3Rpb24gcGFyc2VJbXBvcnRzKG1vZHVsZUJ5dGVzKSB7CiAgaWYgKG1vZHVsZUJ5dGVzIGluc3RhbmNlb2YgVWludDhBcnJheSkgewogIH0gZWxzZSBpZiAobW9kdWxlQnl0ZXMgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgewogICAgbW9kdWxlQnl0ZXMgPSBuZXcgVWludDhBcnJheShtb2R1bGVCeXRlcyk7CiAgfSBlbHNlIGlmIChtb2R1bGVCeXRlcy5idWZmZXIgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgewogICAgbW9kdWxlQnl0ZXMgPSBuZXcgVWludDhBcnJheShtb2R1bGVCeXRlcy5idWZmZXIpOwogIH0gZWxzZSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoIkFyZ3VtZW50IG11c3QgYmUgYSBidWZmZXIgc291cmNlLCBsaWtlIFVpbnQ4QXJyYXkgb3IgQXJyYXlCdWZmZXIiKTsKICB9CiAgY29uc3QgcGFyc2VTdGF0ZSA9IG5ldyBQYXJzZVN0YXRlKG1vZHVsZUJ5dGVzKTsKICBwYXJzZU1hZ2ljTnVtYmVyKHBhcnNlU3RhdGUpOwogIHBhcnNlVmVyc2lvbihwYXJzZVN0YXRlKTsKICBjb25zdCB0eXBlcyA9IFtdOwogIGNvbnN0IGltcG9ydHMgPSBbXTsKICB3aGlsZSAocGFyc2VTdGF0ZS5oYXNNb3JlQnl0ZXMoKSkgewogICAgY29uc3Qgc2VjdGlvbklkID0gcGFyc2VTdGF0ZS5yZWFkQnl0ZSgpOwogICAgY29uc3Qgc2VjdGlvblNpemUgPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgc3dpdGNoIChzZWN0aW9uSWQpIHsKICAgICAgY2FzZSAxOiB7CiAgICAgICAgY29uc3QgdHlwZUNvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHR5cGVDb3VudDsgaSsrKSB7CiAgICAgICAgICB0eXBlcy5wdXNoKHBhcnNlRnVuY3Rpb25UeXBlKHBhcnNlU3RhdGUpKTsKICAgICAgICB9CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgY2FzZSAyOiB7CiAgICAgICAgY29uc3QgaW1wb3J0Q291bnQgPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW1wb3J0Q291bnQ7IGkrKykgewogICAgICAgICAgY29uc3QgbW9kdWxlID0gcGFyc2VTdGF0ZS5yZWFkTmFtZSgpOwogICAgICAgICAgY29uc3QgbmFtZSA9IHBhcnNlU3RhdGUucmVhZE5hbWUoKTsKICAgICAgICAgIGNvbnN0IHR5cGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgICAgICAgICBzd2l0Y2ggKHR5cGUpIHsKICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJmdW5jdGlvbiIsIHR5cGU6IHR5cGVzW2luZGV4XSB9KTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICAgIGltcG9ydHMucHVzaCh7IG1vZHVsZSwgbmFtZSwga2luZDogInRhYmxlIiwgdHlwZTogcGFyc2VUYWJsZVR5cGUocGFyc2VTdGF0ZSkgfSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICBpbXBvcnRzLnB1c2goeyBtb2R1bGUsIG5hbWUsIGtpbmQ6ICJtZW1vcnkiLCB0eXBlOiBwYXJzZUxpbWl0cyhwYXJzZVN0YXRlKSB9KTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgIGltcG9ydHMucHVzaCh7IG1vZHVsZSwgbmFtZSwga2luZDogImdsb2JhbCIsIHR5cGU6IHBhcnNlR2xvYmFsVHlwZShwYXJzZVN0YXRlKSB9KTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gaW1wb3J0IGRlc2NyaXB0b3IgdHlwZSAke3R5cGV9YCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBpbXBvcnRzOwogICAgICB9CiAgICAgIGRlZmF1bHQ6IHsKICAgICAgICBwYXJzZVN0YXRlLnNraXBCeXRlcyhzZWN0aW9uU2l6ZSk7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgIH0KICB9CiAgcmV0dXJuIFtdOwp9CnZhciBQYXJzZVN0YXRlID0gY2xhc3MgewogIGNvbnN0cnVjdG9yKG1vZHVsZUJ5dGVzKSB7CiAgICB0aGlzLm1vZHVsZUJ5dGVzID0gbW9kdWxlQnl0ZXM7CiAgICB0aGlzLm9mZnNldCA9IDA7CiAgICB0aGlzLnRleHREZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpOwogIH0KICBoYXNNb3JlQnl0ZXMoKSB7CiAgICByZXR1cm4gdGhpcy5vZmZzZXQgPCB0aGlzLm1vZHVsZUJ5dGVzLmxlbmd0aDsKICB9CiAgcmVhZEJ5dGUoKSB7CiAgICByZXR1cm4gdGhpcy5tb2R1bGVCeXRlc1t0aGlzLm9mZnNldCsrXTsKICB9CiAgc2tpcEJ5dGVzKGNvdW50KSB7CiAgICB0aGlzLm9mZnNldCArPSBjb3VudDsKICB9CiAgcmVhZFVuc2lnbmVkTEVCMTI4KCkgewogICAgbGV0IHJlc3VsdCA9IDA7CiAgICBsZXQgc2hpZnQgPSAwOwogICAgbGV0IGJ5dGU7CiAgICBkbyB7CiAgICAgIGJ5dGUgPSB0aGlzLnJlYWRCeXRlKCk7CiAgICAgIHJlc3VsdCB8PSAoYnl0ZSAmIDEyNykgPDwgc2hpZnQ7CiAgICAgIHNoaWZ0ICs9IDc7CiAgICB9IHdoaWxlIChieXRlICYgMTI4KTsKICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHJlYWROYW1lKCkgewogICAgY29uc3QgbmFtZUxlbmd0aCA9IHRoaXMucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICBjb25zdCBuYW1lQnl0ZXMgPSB0aGlzLm1vZHVsZUJ5dGVzLnNsaWNlKHRoaXMub2Zmc2V0LCB0aGlzLm9mZnNldCArIG5hbWVMZW5ndGgpOwogICAgY29uc3QgbmFtZSA9IHRoaXMudGV4dERlY29kZXIuZGVjb2RlKG5hbWVCeXRlcyk7CiAgICB0aGlzLm9mZnNldCArPSBuYW1lTGVuZ3RoOwogICAgcmV0dXJuIG5hbWU7CiAgfQogIGFzc2VydEJ5dGVzKGV4cGVjdGVkKSB7CiAgICBjb25zdCBiYXNlT2Zmc2V0ID0gdGhpcy5vZmZzZXQ7CiAgICBjb25zdCBleHBlY3RlZExlbmd0aCA9IGV4cGVjdGVkLmxlbmd0aDsKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZXhwZWN0ZWRMZW5ndGg7IGkrKykgewogICAgICBpZiAodGhpcy5tb2R1bGVCeXRlc1tiYXNlT2Zmc2V0ICsgaV0gIT09IGV4cGVjdGVkW2ldKSB7CiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCAke2V4cGVjdGVkfSBhdCBvZmZzZXQgJHtiYXNlT2Zmc2V0fWApOwogICAgICB9CiAgICB9CiAgICB0aGlzLm9mZnNldCArPSBleHBlY3RlZExlbmd0aDsKICB9Cn07CmZ1bmN0aW9uIHBhcnNlTWFnaWNOdW1iZXIocGFyc2VTdGF0ZSkgewogIGNvbnN0IGV4cGVjdGVkID0gWzAsIDk3LCAxMTUsIDEwOV07CiAgcGFyc2VTdGF0ZS5hc3NlcnRCeXRlcyhleHBlY3RlZCk7Cn0KZnVuY3Rpb24gcGFyc2VWZXJzaW9uKHBhcnNlU3RhdGUpIHsKICBjb25zdCBleHBlY3RlZCA9IFsxLCAwLCAwLCAwXTsKICBwYXJzZVN0YXRlLmFzc2VydEJ5dGVzKGV4cGVjdGVkKTsKfQpmdW5jdGlvbiBwYXJzZVRhYmxlVHlwZShwYXJzZVN0YXRlKSB7CiAgY29uc3QgZWxlbWVudFR5cGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgbGV0IGVsZW1lbnQ7CiAgc3dpdGNoIChlbGVtZW50VHlwZSkgewogICAgY2FzZSAxMTI6CiAgICAgIGVsZW1lbnQgPSAiZnVuY3JlZiI7CiAgICAgIGJyZWFrOwogICAgY2FzZSAxMTE6CiAgICAgIGVsZW1lbnQgPSAiZXh0ZXJucmVmIjsKICAgICAgYnJlYWs7CiAgICBkZWZhdWx0OgogICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gdGFibGUgZWxlbWVudCB0eXBlICR7ZWxlbWVudFR5cGV9YCk7CiAgfQogIGNvbnN0IHsgbWluaW11bSwgbWF4aW11bSB9ID0gcGFyc2VMaW1pdHMocGFyc2VTdGF0ZSk7CiAgaWYgKG1heGltdW0pIHsKICAgIHJldHVybiB7IGVsZW1lbnQsIG1pbmltdW0sIG1heGltdW0gfTsKICB9IGVsc2UgewogICAgcmV0dXJuIHsgZWxlbWVudCwgbWluaW11bSB9OwogIH0KfQpmdW5jdGlvbiBwYXJzZUxpbWl0cyhwYXJzZVN0YXRlKSB7CiAgY29uc3QgZmxhZ3MgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgY29uc3QgbWluaW11bSA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgY29uc3QgaGFzTWF4aW11bSA9IGZsYWdzICYgMTsKICBjb25zdCBzaGFyZWQgPSAoZmxhZ3MgJiAyKSAhPT0gMDsKICBjb25zdCBpc01lbW9yeTY0ID0gKGZsYWdzICYgNCkgIT09IDA7CiAgY29uc3QgaW5kZXggPSBpc01lbW9yeTY0ID8gImk2NCIgOiAiaTMyIjsKICBpZiAoaGFzTWF4aW11bSkgewogICAgY29uc3QgbWF4aW11bSA9IHBhcnNlU3RhdGUucmVhZFVuc2lnbmVkTEVCMTI4KCk7CiAgICByZXR1cm4geyBtaW5pbXVtLCBzaGFyZWQsIGluZGV4LCBtYXhpbXVtIH07CiAgfSBlbHNlIHsKICAgIHJldHVybiB7IG1pbmltdW0sIHNoYXJlZCwgaW5kZXggfTsKICB9Cn0KZnVuY3Rpb24gcGFyc2VHbG9iYWxUeXBlKHBhcnNlU3RhdGUpIHsKICBjb25zdCB2YWx1ZSA9IHBhcnNlVmFsdWVUeXBlKHBhcnNlU3RhdGUpOwogIGNvbnN0IG11dGFibGUgPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCkgPT09IDE7CiAgcmV0dXJuIHsgdmFsdWUsIG11dGFibGUgfTsKfQpmdW5jdGlvbiBwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKSB7CiAgY29uc3QgdHlwZSA9IHBhcnNlU3RhdGUucmVhZEJ5dGUoKTsKICBzd2l0Y2ggKHR5cGUpIHsKICAgIGNhc2UgMTI3OgogICAgICByZXR1cm4gImkzMiI7CiAgICBjYXNlIDEyNjoKICAgICAgcmV0dXJuICJpNjQiOwogICAgY2FzZSAxMjU6CiAgICAgIHJldHVybiAiZjMyIjsKICAgIGNhc2UgMTI0OgogICAgICByZXR1cm4gImY2NCI7CiAgICBjYXNlIDExMjoKICAgICAgcmV0dXJuICJmdW5jcmVmIjsKICAgIGNhc2UgMTExOgogICAgICByZXR1cm4gImV4dGVybnJlZiI7CiAgICBjYXNlIDEyMzoKICAgICAgcmV0dXJuICJ2MTI4IjsKICAgIGRlZmF1bHQ6CiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biB2YWx1ZSB0eXBlICR7dHlwZX1gKTsKICB9Cn0KZnVuY3Rpb24gcGFyc2VGdW5jdGlvblR5cGUocGFyc2VTdGF0ZSkgewogIGNvbnN0IGZvcm0gPSBwYXJzZVN0YXRlLnJlYWRCeXRlKCk7CiAgaWYgKGZvcm0gIT09IDk2KSB7CiAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGZ1bmN0aW9uIHR5cGUgZm9ybSAweDYwLCBnb3QgJHtmb3JtfWApOwogIH0KICBjb25zdCBwYXJhbWV0ZXJzID0gW107CiAgY29uc3QgcGFyYW1ldGVyQ291bnQgPSBwYXJzZVN0YXRlLnJlYWRVbnNpZ25lZExFQjEyOCgpOwogIGZvciAobGV0IGkgPSAwOyBpIDwgcGFyYW1ldGVyQ291bnQ7IGkrKykgewogICAgcGFyYW1ldGVycy5wdXNoKHBhcnNlVmFsdWVUeXBlKHBhcnNlU3RhdGUpKTsKICB9CiAgY29uc3QgcmVzdWx0cyA9IFtdOwogIGNvbnN0IHJlc3VsdENvdW50ID0gcGFyc2VTdGF0ZS5yZWFkVW5zaWduZWRMRUIxMjgoKTsKICBmb3IgKGxldCBpID0gMDsgaSA8IHJlc3VsdENvdW50OyBpKyspIHsKICAgIHJlc3VsdHMucHVzaChwYXJzZVZhbHVlVHlwZShwYXJzZVN0YXRlKSk7CiAgfQogIHJldHVybiB7IHBhcmFtZXRlcnMsIHJlc3VsdHMgfTsKfQoKLy8gbm9kZV9tb2R1bGVzL3dhc20taW1wb3J0cy1wYXJzZXIvcG9seWZpbGwuanMKdmFyIGhhc1dhc21UeXBlUmVmbGVjdGlvblN1cHBvcnQgPSAoKCkgPT4gewogIGNvbnN0IG1vZHVsZUJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoWwogICAgMCwKICAgIDk3LAogICAgMTE1LAogICAgMTA5LAogICAgMSwKICAgIDAsCiAgICAwLAogICAgMCwKICAgIDIsCiAgICA2LAogICAgMSwKICAgIDAsCiAgICAwLAogICAgMiwKICAgIDAsCiAgICAxCiAgXSk7CiAgY29uc3QgbW9kdWxlID0gbmV3IFdlYkFzc2VtYmx5Lk1vZHVsZShtb2R1bGVCeXRlcyk7CiAgY29uc3QgaW1wb3J0cyA9IFdlYkFzc2VtYmx5Lk1vZHVsZS5pbXBvcnRzKG1vZHVsZSk7CiAgY29uc3QgbWVtb3J5SW1wb3J0ID0gaW1wb3J0c1swXTsKICByZXR1cm4gdHlwZW9mIG1lbW9yeUltcG9ydC50eXBlID09PSAib2JqZWN0IjsKfSkoKTsKZnVuY3Rpb24gcG9seWZpbGwoV2ViQXNzZW1ibHkzKSB7CiAgaWYgKGhhc1dhc21UeXBlUmVmbGVjdGlvblN1cHBvcnQpIHsKICAgIHJldHVybiBXZWJBc3NlbWJseTM7CiAgfQogIGNvbnN0IG5ld1dlYkFzc2VtYmx5ID0ge307CiAgZm9yIChjb25zdCBrZXkgaW4gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoV2ViQXNzZW1ibHkzKSkgewogICAgbmV3V2ViQXNzZW1ibHlba2V5XSA9IFdlYkFzc2VtYmx5M1trZXldOwogIH0KICBjb25zdCBwb2x5ZmlsbGVkSW1wb3J0c1N5bWJvbCA9IFN5bWJvbCgicG9seWZpbGxlZEltcG9ydHNTeW1ib2wiKTsKICBjb25zdCBhc3NpZ25JbXBvcnRzID0gKG1vZHVsZSwgc291cmNlQnl0ZXMpID0+IHsKICAgIG1vZHVsZVtwb2x5ZmlsbGVkSW1wb3J0c1N5bWJvbF0gPSBwYXJzZUltcG9ydHMoc291cmNlQnl0ZXMpOwogIH07CiAgY29uc3QgbmV3TW9kdWxlID0gbmV3V2ViQXNzZW1ibHkuTW9kdWxlID0gZnVuY3Rpb24oYnl0ZXMpIHsKICAgIGNvbnN0IG1vZHVsZSA9IG5ldyBXZWJBc3NlbWJseTMuTW9kdWxlKGJ5dGVzKTsKICAgIGFzc2lnbkltcG9ydHMobW9kdWxlLCBieXRlcyk7CiAgICBPYmplY3Quc2V0UHJvdG90eXBlT2YobW9kdWxlLCBuZXdNb2R1bGUucHJvdG90eXBlKTsKICAgIHJldHVybiBtb2R1bGU7CiAgfTsKICBPYmplY3Quc2V0UHJvdG90eXBlT2YobmV3TW9kdWxlLnByb3RvdHlwZSwgV2ViQXNzZW1ibHkzLk1vZHVsZS5wcm90b3R5cGUpOwogIG5ld1dlYkFzc2VtYmx5LmNvbXBpbGUgPSBhc3luYyAoc291cmNlKSA9PiB7CiAgICBjb25zdCBtb2R1bGUgPSBhd2FpdCBXZWJBc3NlbWJseTMuY29tcGlsZShzb3VyY2UpOwogICAgYXNzaWduSW1wb3J0cyhtb2R1bGUsIHNvdXJjZSk7CiAgICByZXR1cm4gbW9kdWxlOwogIH07CiAgaWYgKFdlYkFzc2VtYmx5My5jb21waWxlU3RyZWFtaW5nKSB7CiAgICBuZXdXZWJBc3NlbWJseS5jb21waWxlU3RyZWFtaW5nID0gYXN5bmMgKHNvdXJjZSkgPT4gewogICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHNvdXJjZTsKICAgICAgY29uc3QgY2xvbmUgPSByZXNwb25zZS5jbG9uZSgpOwogICAgICBjb25zdCBtb2R1bGUgPSBhd2FpdCBXZWJBc3NlbWJseTMuY29tcGlsZVN0cmVhbWluZyhyZXNwb25zZSk7CiAgICAgIGFzc2lnbkltcG9ydHMobW9kdWxlLCBuZXcgVWludDhBcnJheShhd2FpdCBjbG9uZS5hcnJheUJ1ZmZlcigpKSk7CiAgICAgIHJldHVybiBtb2R1bGU7CiAgICB9OwogIH0KICBuZXdNb2R1bGUuaW1wb3J0cyA9IChtb2R1bGUpID0+IHsKICAgIGNvbnN0IHBhcnNlZEltcG9ydHMgPSBtb2R1bGVbcG9seWZpbGxlZEltcG9ydHNTeW1ib2xdOwogICAgaWYgKCFwYXJzZWRJbXBvcnRzKSB7CiAgICAgIHJldHVybiBXZWJBc3NlbWJseTMuTW9kdWxlLmltcG9ydHMobW9kdWxlKTsKICAgIH0KICAgIHJldHVybiBwYXJzZWRJbXBvcnRzOwogIH07CiAgcmV0dXJuIG5ld1dlYkFzc2VtYmx5Owp9CgovLyBlbnRyeXBvaW50L2ludHJpbnNpY3MudHMKdmFyIFdlYkFzc2VtYmx5MiA9IHBvbHlmaWxsKGdsb2JhbFRoaXMuV2ViQXNzZW1ibHkpOwp2YXIgTGluZURlY29kZXIgPSBjbGFzcyB7CiAgY29uc3RydWN0b3Iob25MaW5lKSB7CiAgICB0aGlzLmRlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoInV0Zi04IiwgeyBmYXRhbDogZmFsc2UgfSk7CiAgICB0aGlzLmJ1ZmZlciA9ICIiOwogICAgdGhpcy5vbkxpbmUgPSBvbkxpbmU7CiAgfQogIGRlY29kZXI7CiAgYnVmZmVyOwogIG9uTGluZTsKICBzZW5kKGNodW5rKSB7CiAgICB0aGlzLmJ1ZmZlciArPSB0aGlzLmRlY29kZXIuZGVjb2RlKGNodW5rLCB7IHN0cmVhbTogdHJ1ZSB9KTsKICAgIGNvbnN0IGxpbmVzID0gdGhpcy5idWZmZXIuc3BsaXQoIlxuIik7CiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aCAtIDE7IGkrKykgewogICAgICB0aGlzLm9uTGluZShsaW5lc1tpXSk7CiAgICB9CiAgICB0aGlzLmJ1ZmZlciA9IGxpbmVzW2xpbmVzLmxlbmd0aCAtIDFdOwogIH0KfTsKYXN5bmMgZnVuY3Rpb24gaW5zdGFudGlhdGUocmF3T3B0aW9ucywgZXh0cmFXYXNtSW1wb3J0cykgewogIGNvbnN0IG9wdGlvbnMgPSBkZWZhdWx0SW5zdGFudGlhdGlvbk9wdGlvbnMocmF3T3B0aW9ucyk7CiAgbGV0IHN3aWZ0ID0gb3B0aW9ucy5zd2lmdDsKICBpZiAoIXN3aWZ0ICYmIG9wdGlvbnMuU3dpZnRSdW50aW1lKSB7CiAgICBsZXQgc2hhcmVkTWVtb3J5ID0gZmFsc2U7CiAgICBmb3IgKGNvbnN0IGltcG9ydEVudHJ5IG9mIFdlYkFzc2VtYmx5Mi5Nb2R1bGUuaW1wb3J0cyhvcHRpb25zLm1vZHVsZSkpIHsKICAgICAgaWYgKGltcG9ydEVudHJ5Lm1vZHVsZSA9PT0gImVudiIgJiYgaW1wb3J0RW50cnkubmFtZSA9PT0gIm1lbW9yeSIgJiYgaW1wb3J0RW50cnkua2luZCA9PT0gIm1lbW9yeSIpIHsKICAgICAgICBzaGFyZWRNZW1vcnkgPSB0cnVlOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgICBzd2lmdCA9IG5ldyBvcHRpb25zLlN3aWZ0UnVudGltZSh7IHNoYXJlZE1lbW9yeSB9KTsKICB9CiAgbGV0IHN0ZG91dExpbmUgPSB2b2lkIDA7CiAgaWYgKG9wdGlvbnMub25TdGRvdXRMaW5lICE9IG51bGwpIHsKICAgIHN0ZG91dExpbmUgPSBuZXcgTGluZURlY29kZXIob3B0aW9ucy5vblN0ZG91dExpbmUpOwogIH0KICBjb25zdCBzdGRvdXQgPSBuZXcgQ29uc29sZVN0ZG91dCgoY2h1bmspID0+IHsKICAgIG9wdGlvbnMub25TdGRvdXQ/LmNhbGwodm9pZCAwLCBjaHVuayk7CiAgICBzdGRvdXRMaW5lPy5zZW5kKGNodW5rKTsKICB9KTsKICBsZXQgc3RkZXJyTGluZSA9IHZvaWQgMDsKICBpZiAob3B0aW9ucy5vblN0ZGVyckxpbmUgIT0gbnVsbCkgewogICAgc3RkZXJyTGluZSA9IG5ldyBMaW5lRGVjb2RlcihvcHRpb25zLm9uU3RkZXJyTGluZSk7CiAgfQogIGNvbnN0IHN0ZGVyciA9IG5ldyBDb25zb2xlU3Rkb3V0KChjaHVuaykgPT4gewogICAgb3B0aW9ucy5vblN0ZGVycj8uY2FsbCh2b2lkIDAsIGNodW5rKTsKICAgIHN0ZGVyckxpbmU/LnNlbmQoY2h1bmspOwogIH0pOwogIGNvbnN0IGFyZ3MgPSBvcHRpb25zLmFyZ3MgfHwgW107CiAgY29uc3Qgcm9vdEZzID0gb3B0aW9ucy5yb290RnMgfHwgLyogQF9fUFVSRV9fICovIG5ldyBNYXAoKTsKICBjb25zdCBmZHMgPSBbCiAgICBuZXcgT3BlbkZpbGUobmV3IEZpbGUoW10pKSwKICAgIHN0ZG91dCwKICAgIHN0ZGVyciwKICAgIG5ldyBQcmVvcGVuRGlyZWN0b3J5KCIvIiwgcm9vdEZzKQogIF07CiAgY29uc3QgZW52cyA9IG9wdGlvbnMuZW52ID8gT2JqZWN0LmVudHJpZXMob3B0aW9ucy5lbnYpLm1hcCgoW2tleSwgdmFsdWVdKSA9PiBgJHtrZXl9PSR7dmFsdWV9YCkgOiBbXTsKICBjb25zdCB3YXNpID0gbmV3IFdBU0koYXJncywgZW52cywgZmRzLCB7CiAgICBkZWJ1ZzogZmFsc2UKICB9KTsKICBjb25zdCBjcmVhdGVXYXNtSW1wb3J0T2JqZWN0ID0gKGV4dHJhV2FzbUltcG9ydHMyLCBtb2R1bGUpID0+IHsKICAgIGNvbnN0IGltcG9ydE9iamVjdDIgPSB7CiAgICAgIHdhc2lfc25hcHNob3RfcHJldmlldzE6IHdhc2kud2FzaUltcG9ydAogICAgfTsKICAgIGlmIChzd2lmdCkgewogICAgICBpbXBvcnRPYmplY3QyLmphdmFzY3JpcHRfa2l0ID0gc3dpZnQud2FzbUltcG9ydHM7CiAgICB9CiAgICBpZiAoZXh0cmFXYXNtSW1wb3J0czIpIHsKICAgICAgZm9yIChjb25zdCBtb2R1bGVOYW1lIGluIGV4dHJhV2FzbUltcG9ydHMyKSB7CiAgICAgICAgaWYgKCFpbXBvcnRPYmplY3QyW21vZHVsZU5hbWVdKSB7CiAgICAgICAgICBpbXBvcnRPYmplY3QyW21vZHVsZU5hbWVdID0ge307CiAgICAgICAgfQogICAgICAgIGZvciAoY29uc3QgZW50cnkgaW4gZXh0cmFXYXNtSW1wb3J0czJbbW9kdWxlTmFtZV0pIHsKICAgICAgICAgIGltcG9ydE9iamVjdDJbbW9kdWxlTmFtZV1bZW50cnldID0gZXh0cmFXYXNtSW1wb3J0czJbbW9kdWxlTmFtZV1bZW50cnldOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgZm9yIChjb25zdCBfaW1wb3J0RW50cnkgb2YgV2ViQXNzZW1ibHkyLk1vZHVsZS5pbXBvcnRzKG1vZHVsZSkpIHsKICAgICAgY29uc3QgaW1wb3J0RW50cnkgPSBfaW1wb3J0RW50cnk7CiAgICAgIGlmICghaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdKSB7CiAgICAgICAgaW1wb3J0T2JqZWN0MltpbXBvcnRFbnRyeS5tb2R1bGVdID0ge307CiAgICAgIH0KICAgICAgaWYgKGltcG9ydE9iamVjdDJbaW1wb3J0RW50cnkubW9kdWxlXVtpbXBvcnRFbnRyeS5uYW1lXSkgewogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGlmIChpbXBvcnRFbnRyeS5raW5kID09ICJmdW5jdGlvbiIpIHsKICAgICAgICBpbXBvcnRPYmplY3QyW2ltcG9ydEVudHJ5Lm1vZHVsZV1baW1wb3J0RW50cnkubmFtZV0gPSAoKSA9PiB7CiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEltcG9ydGVkIGZ1bmN0aW9uICR7aW1wb3J0RW50cnkubW9kdWxlfS4ke2ltcG9ydEVudHJ5Lm5hbWV9IG5vdCBpbXBsZW1lbnRlZGApOwogICAgICAgIH07CiAgICAgIH0gZWxzZSBpZiAoaW1wb3J0RW50cnkua2luZCA9PSAibWVtb3J5IiAmJiBpbXBvcnRFbnRyeS5tb2R1bGUgPT0gImVudiIgJiYgaW1wb3J0RW50cnkubmFtZSA9PSAibWVtb3J5IikgewogICAgICAgIGNvbnN0IHR5cGUgPSBpbXBvcnRFbnRyeS50eXBlOwogICAgICAgIGNvbnN0IGRlc2NyaXB0b3IgPSB7CiAgICAgICAgICBpbml0aWFsOiB0eXBlLm1pbmltdW0sCiAgICAgICAgICBtYXhpbXVtOiB0eXBlLm1heGltdW0sCiAgICAgICAgICBzaGFyZWQ6IHR5cGUuc2hhcmVkCiAgICAgICAgfTsKICAgICAgICBpbXBvcnRPYmplY3QyW2ltcG9ydEVudHJ5Lm1vZHVsZV1baW1wb3J0RW50cnkubmFtZV0gPSBuZXcgV2ViQXNzZW1ibHkyLk1lbW9yeShkZXNjcmlwdG9yKTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIGltcG9ydE9iamVjdDI7CiAgfTsKICBjb25zdCBpbXBvcnRPYmplY3QgPSBjcmVhdGVXYXNtSW1wb3J0T2JqZWN0KGV4dHJhV2FzbUltcG9ydHMsIG9wdGlvbnMubW9kdWxlKTsKICBjb25zdCBpbnN0YW5jZSA9IGF3YWl0IFdlYkFzc2VtYmx5Mi5pbnN0YW50aWF0ZShvcHRpb25zLm1vZHVsZSwgaW1wb3J0T2JqZWN0KTsKICBpZiAoc3dpZnQgJiYgaW5zdGFuY2UuZXhwb3J0cy5zd2pzX2xpYnJhcnlfdmVyc2lvbikgewogICAgc3dpZnQuc2V0SW5zdGFuY2UoaW5zdGFuY2UpOwogIH0KICBpZiAodHlwZW9mIGluc3RhbmNlLmV4cG9ydHMuX3N0YXJ0ID09PSAiZnVuY3Rpb24iKSB7CiAgICB3YXNpLnN0YXJ0KGluc3RhbmNlKTsKICB9IGVsc2UgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLl9pbml0aWFsaXplID09ICJmdW5jdGlvbiIpIHsKICAgIHdhc2kuaW5pdGlhbGl6ZShpbnN0YW5jZSk7CiAgICBpZiAoc3dpZnQgJiYgc3dpZnQubWFpbikgewogICAgICBzd2lmdC5tYWluKCk7CiAgICB9IGVsc2UgewogICAgICBpZiAodHlwZW9mIGluc3RhbmNlLmV4cG9ydHMubWFpbiA9PT0gImZ1bmN0aW9uIikgewogICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWFpbigpOwogICAgICB9IGVsc2UgaWYgKHR5cGVvZiBpbnN0YW5jZS5leHBvcnRzLl9fbWFpbl9hcmdjX2FyZ3YgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICBpbnN0YW5jZS5leHBvcnRzLl9fbWFpbl9hcmdjX2FyZ3YoMCwgMCk7CiAgICAgIH0KICAgIH0KICB9CiAgcmV0dXJuIHsgaW5zdGFuY2UsIHJvb3RGcyB9Owp9CmZ1bmN0aW9uIGRlZmF1bHRJbnN0YW50aWF0aW9uT3B0aW9ucyhvcHRpb25zKSB7CiAgaWYgKG9wdGlvbnMuYXJncyA9PSBudWxsKSB7CiAgICBvcHRpb25zLmFyZ3MgPSBbIm1haW4ud2FzbSJdOwogIH0KICBjb25zdCBpc05vZGVKcyA9IHR5cGVvZiBwcm9jZXNzICE9PSAidW5kZWZpbmVkIiAmJiBwcm9jZXNzLnJlbGVhc2UubmFtZSA9PT0gIm5vZGUiOwogIGNvbnN0IGlzV2ViQnJvd3NlciA9IHR5cGVvZiB3aW5kb3cgIT09ICJ1bmRlZmluZWQiOwogIGlmIChpc05vZGVKcykgewogICAgaWYgKCFvcHRpb25zLm9uU3Rkb3V0KSB7CiAgICAgIG9wdGlvbnMub25TdGRvdXQgPSAoY2h1bmspID0+IHByb2Nlc3Muc3Rkb3V0LndyaXRlKGNodW5rKTsKICAgIH0KICAgIGlmICghb3B0aW9ucy5vblN0ZGVycikgewogICAgICBvcHRpb25zLm9uU3RkZXJyID0gKGNodW5rKSA9PiBwcm9jZXNzLnN0ZGVyci53cml0ZShjaHVuayk7CiAgICB9CiAgfSBlbHNlIGlmIChpc1dlYkJyb3dzZXIpIHsKICAgIGlmICghb3B0aW9ucy5vblN0ZG91dExpbmUpIHsKICAgICAgb3B0aW9ucy5vblN0ZG91dExpbmUgPSAobGluZSkgPT4gY29uc29sZS5sb2cobGluZSk7CiAgICB9CiAgICBpZiAoIW9wdGlvbnMub25TdGRlcnJMaW5lKSB7CiAgICAgIG9wdGlvbnMub25TdGRlcnJMaW5lID0gKGxpbmUpID0+IGNvbnNvbGUud2FybihsaW5lKTsKICAgIH0KICB9CiAgcmV0dXJuIG9wdGlvbnM7Cn0KYXN5bmMgZnVuY3Rpb24gZXh0cmFjdEFuZFNhdmVGaWxlKHJvb3RGcywgcGF0aCkgewogIGNvbnN0IGdldEZpbGUgPSAocGFyZW50LCBjb21wb25lbnRzMiwgaW5kZXgpID0+IHsKICAgIGNvbnN0IG5hbWUgPSBjb21wb25lbnRzMltpbmRleF07CiAgICBjb25zdCBlbnRyeSA9IHBhcmVudC5nZXQobmFtZSk7CiAgICBpZiAoZW50cnkgPT09IHZvaWQgMCkgewogICAgICByZXR1cm4gdm9pZCAwOwogICAgfQogICAgaWYgKGluZGV4ID09PSBjb21wb25lbnRzMi5sZW5ndGggLSAxKSB7CiAgICAgIHJldHVybiBlbnRyeTsKICAgIH0KICAgIGlmIChlbnRyeSBpbnN0YW5jZW9mIERpcmVjdG9yeSkgewogICAgICByZXR1cm4gZ2V0RmlsZShlbnRyeS5jb250ZW50cywgY29tcG9uZW50czIsIGluZGV4ICsgMSk7CiAgICB9CiAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGRpcmVjdG9yeSBhdCAke2NvbXBvbmVudHMyLnNsaWNlKDAsIGluZGV4KS5qb2luKCIvIil9YCk7CiAgfTsKICBjb25zdCBjb21wb25lbnRzID0gcGF0aC5zcGxpdCgiLyIpOwogIGNvbnN0IGZpbGUgPSBnZXRGaWxlKHJvb3RGcywgY29tcG9uZW50cywgMCk7CiAgaWYgKGZpbGUgPT09IHZvaWQgMCkgewogICAgcmV0dXJuIGZhbHNlOwogIH0KICBpZiAoZmlsZSBpbnN0YW5jZW9mIEZpbGUpIHsKICAgIGNvbnN0IGZzID0gYXdhaXQgaW1wb3J0KCJub2RlOmZzL3Byb21pc2VzIik7CiAgICBjb25zb2xlLmxvZyhgU2F2ZWQgJHtwYXRofSB0byAke3Byb2Nlc3MuY3dkKCl9YCk7CiAgICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aCwgZmlsZS5kYXRhKTsKICAgIHJldHVybiB0cnVlOwogIH0KICByZXR1cm4gZmFsc2U7Cn0KYXN5bmMgZnVuY3Rpb24gdGVzdEJyb3dzZXIoaW5zdGFudGlhdGUyLCB3YXNtRmlsZU5hbWUsIGFyZ3MsIGluZGV4SnNVcmwsIG9wdGlvbnMgPSB7fSwgaW5QYWdlID0gZmFsc2UpIHsKICBpZiAoaW5QYWdlKSB7CiAgICByZXR1cm4gYXdhaXQgdGVzdEJyb3dzZXJJblBhZ2UoaW5zdGFudGlhdGUyLCB3YXNtRmlsZU5hbWUsIGFyZ3MpOwogIH0KICBjb25zdCB7IGZpbGVVUkxUb1BhdGggfSA9IGF3YWl0IGltcG9ydCgibm9kZTp1cmwiKTsKICBjb25zdCBwYXRoID0gYXdhaXQgaW1wb3J0KCJub2RlOnBhdGgiKTsKICBjb25zdCBmcyA9IGF3YWl0IGltcG9ydCgibm9kZTpmcy9wcm9taXNlcyIpOwogIGNvbnN0IHsgZXhpc3RzU3luYyB9ID0gYXdhaXQgaW1wb3J0KCJub2RlOmZzIik7CiAgY29uc3QgaW5kZXhKc1BhdGggPSBmaWxlVVJMVG9QYXRoKGluZGV4SnNVcmwpOwogIGNvbnN0IHdlYlJvb3QgPSBwYXRoLmRpcm5hbWUoaW5kZXhKc1BhdGgpOwogIGNvbnN0IGh0dHAgPSBhd2FpdCBpbXBvcnQoIm5vZGU6aHR0cCIpOwogIGNvbnN0IGRlZmF1bHRDb250ZW50VHlwZXMgPSB7CiAgICAiLmh0bWwiOiAidGV4dC9odG1sIiwKICAgICIuanMiOiAidGV4dC9qYXZhc2NyaXB0IiwKICAgICIubWpzIjogInRleHQvamF2YXNjcmlwdCIsCiAgICAiLndhc20iOiAiYXBwbGljYXRpb24vd2FzbSIKICB9OwogIGNvbnN0IHNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFzeW5jIChyZXEsIHJlcykgPT4gewogICAgY29uc3QgdXJsID0gbmV3IFVSTChyZXEudXJsLCBgaHR0cDovLyR7cmVxLmhlYWRlcnMuaG9zdH1gKTsKICAgIGNvbnN0IHBhdGhuYW1lID0gdXJsLnBhdGhuYW1lOwogICAgY29uc3QgZmlsZVBhdGggPSBwYXRoLmpvaW4od2ViUm9vdCwgcGF0aG5hbWUpOwogICAgaWYgKGV4aXN0c1N5bmMoZmlsZVBhdGgpICYmIChhd2FpdCBmcy5zdGF0KGZpbGVQYXRoKSkuaXNGaWxlKCkpIHsKICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGZzLnJlYWRGaWxlKGZpbGVQYXRoKTsKICAgICAgY29uc3QgZXh0ID0gcGF0aG5hbWUuc2xpY2UocGF0aG5hbWUubGFzdEluZGV4T2YoIi4iKSk7CiAgICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gb3B0aW9ucy5jb250ZW50VHlwZXM/LihwYXRobmFtZSkgfHwgZGVmYXVsdENvbnRlbnRUeXBlc1tleHRdIHx8ICJ0ZXh0L3BsYWluIjsKICAgICAgcmVzLndyaXRlSGVhZCgyMDAsIHsgIkNvbnRlbnQtVHlwZSI6IGNvbnRlbnRUeXBlIH0pOwogICAgICByZXMuZW5kKGRhdGEpOwogICAgfSBlbHNlIGlmIChwYXRobmFtZSA9PT0gIi9wcm9jZXNzLWluZm8uanNvbiIpIHsKICAgICAgcmVzLndyaXRlSGVhZCgyMDAsIHsgIkNvbnRlbnQtVHlwZSI6ICJhcHBsaWNhdGlvbi9qc29uIiB9KTsKICAgICAgcmVzLmVuZChKU09OLnN0cmluZ2lmeSh7IGVudjogcHJvY2Vzcy5lbnYgfSkpOwogICAgfSBlbHNlIHsKICAgICAgcmVzLndyaXRlSGVhZCg0MDQpOwogICAgICByZXMuZW5kKCk7CiAgICB9CiAgfSk7CiAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNlcnZlci5saXN0ZW4oeyBob3N0OiAibG9jYWxob3N0IiwgcG9ydDogMCB9LCAoKSA9PiByZXNvbHZlKCkpKTsKICBjb25zdCBhZGRyZXNzID0gc2VydmVyLmFkZHJlc3MoKTsKICBjb25zdCBwbGF5d3JpZ2h0ID0gYXdhaXQgKGFzeW5jICgpID0+IHsKICAgIHRyeSB7CiAgICAgIHJldHVybiBhd2FpdCBpbXBvcnQoInBsYXl3cmlnaHQiKTsKICAgIH0gY2F0Y2ggewogICAgICBjb25zb2xlLmVycm9yKGBQbGF5d3JpZ2h0IGlzIG5vdCBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgZW52aXJvbm1lbnQuClBsZWFzZSBydW4gdGhlIGZvbGxvd2luZyBjb21tYW5kIHRvIGluc3RhbGwgaXQ6CgogICAgICAkIG5wbSBpbnN0YWxsIHBsYXl3cmlnaHQgJiYgbnB4IHBsYXl3cmlnaHQgaW5zdGFsbCBjaHJvbWl1bQogICAgICBgKTsKICAgICAgcHJvY2Vzcy5leGl0KDEpOwogICAgfQogIH0pKCk7CiAgY29uc3QgYnJvd3NlciA9IGF3YWl0IHBsYXl3cmlnaHQuY2hyb21pdW0ubGF1bmNoKCk7CiAgY29uc3QgY29udGV4dCA9IGF3YWl0IGJyb3dzZXIubmV3Q29udGV4dCgpOwogIGNvbnN0IHBhZ2UgPSBhd2FpdCBjb250ZXh0Lm5ld1BhZ2UoKTsKICBwYWdlLm9uKCJjb25zb2xlIiwgKG1lc3NhZ2UpID0+IHsKICAgIGNvbnNvbGUubG9nKG1lc3NhZ2UudGV4dCgpKTsKICB9KTsKICBjb25zdCBvbkV4aXQgPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewogICAgcGFnZS5leHBvc2VGdW5jdGlvbigiZXhpdFRlc3QiLCByZXNvbHZlKTsKICB9KTsKICBhd2FpdCBwYWdlLmdvdG8oYGh0dHA6Ly9sb2NhbGhvc3Q6JHthZGRyZXNzLnBvcnR9L3Rlc3QuYnJvd3Nlci5odG1sYCk7CiAgY29uc3QgZXhpdENvZGUgPSBhd2FpdCBvbkV4aXQ7CiAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpOwogIHByb2Nlc3MuZXhpdChleGl0Q29kZSk7Cn0KYXN5bmMgZnVuY3Rpb24gdGVzdEJyb3dzZXJJblBhZ2UoaW5zdGFudGlhdGUyLCB3YXNtRmlsZU5hbWUsIGFyZ3MpIHsKICBjb25zdCBsb2dFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgicHJlIik7CiAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChsb2dFbGVtZW50KTsKICBjb25zdCBleGl0VGVzdCA9IChjb2RlKSA9PiB7CiAgICBjb25zdCBmbiA9IHdpbmRvdy5leGl0VGVzdDsKICAgIGlmIChmbikgewogICAgICBmbihjb2RlKTsKICAgIH0KICB9OwogIGNvbnN0IGNvbmZpZyA9IGF3YWl0IGZldGNoKCIvcHJvY2Vzcy1pbmZvLmpzb24iKS50aGVuKChyZXNwb25zZSkgPT4gcmVzcG9uc2UuanNvbigpKTsKICBjb25zdCBoYW5kbGVFcnJvciA9IChlcnJvcikgPT4gewogICAgY29uc29sZS5lcnJvcihlcnJvcik7CiAgICBleGl0VGVzdCgxKTsKICB9OwogIGNvbnN0IGhhbmRsZUV4aXRPckVycm9yID0gKGVycm9yKSA9PiB7CiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBXQVNJUHJvY0V4aXQpIHsKICAgICAgaWYgKGVycm9yLmNvZGUgPT09IDApIHsKICAgICAgICBleGl0VGVzdCgwKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBoYW5kbGVFcnJvcihlcnJvcik7CiAgICAgIH0KICAgIH0gZWxzZSB7CiAgICAgIGhhbmRsZUVycm9yKGVycm9yKTsKICAgIH0KICB9OwogIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCJ1bmhhbmRsZWRyZWplY3Rpb24iLCAoZXZlbnQpID0+IHsKICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7CiAgICBjb25zdCBlcnJvciA9IGV2ZW50LnJlYXNvbjsKICAgIGhhbmRsZUV4aXRPckVycm9yKGVycm9yKTsKICB9KTsKICB0cnkgewogICAgYXdhaXQgaW5zdGFudGlhdGUyKHsKICAgICAgZW52OiBjb25maWcuZW52LAogICAgICBhcmdzOiBbd2FzbUZpbGVOYW1lXS5jb25jYXQoYXJncyksCiAgICAgIG9uU3Rkb3V0TGluZShsaW5lKSB7CiAgICAgICAgY29uc29sZS5sb2cobGluZSk7CiAgICAgICAgbG9nRWxlbWVudC50ZXh0Q29udGVudCArPSBsaW5lICsgIlxuIjsKICAgICAgfSwKICAgICAgb25TdGRlcnJMaW5lKGxpbmUpIHsKICAgICAgICBjb25zb2xlLndhcm4obGluZSk7CiAgICAgICAgbG9nRWxlbWVudC50ZXh0Q29udGVudCArPSBsaW5lICsgIlxuIjsKICAgICAgfQogICAgfSwgewogICAgICAid2FzaV9zbmFwc2hvdF9wcmV2aWV3MSI6IHsKICAgICAgICBwcm9jX2V4aXQ6IChjb2RlKSA9PiB7CiAgICAgICAgICBleGl0VGVzdChjb2RlKTsKICAgICAgICAgIHRocm93IG5ldyBXQVNJUHJvY0V4aXQoY29kZSk7CiAgICAgICAgfQogICAgICB9CiAgICB9KTsKICB9IGNhdGNoIChlcnJvcikgewogICAgaGFuZGxlRXhpdE9yRXJyb3IoZXJyb3IpOwogIH0KfQphc3luYyBmdW5jdGlvbiB0ZXN0Tm9kZShpbnN0YW50aWF0ZTIsIHdhc21GaWxlTmFtZSwgYXJncykgewogIGNvbnN0IGVudiA9IHt9OwogIGZvciAoY29uc3Qga2V5IGluIHByb2Nlc3MuZW52KSB7CiAgICBjb25zdCB2YWx1ZSA9IHByb2Nlc3MuZW52W2tleV07CiAgICBpZiAodmFsdWUpIHsKICAgICAgZW52W2tleV0gPSB2YWx1ZTsKICAgIH0KICB9CiAgbGV0IHByb2NFeGl0Q2FsbGVkID0gZmFsc2U7CiAgY29uc3QgeyBjcmVhdGVSZXF1aXJlIH0gPSBhd2FpdCBpbXBvcnQoIm5vZGU6bW9kdWxlIik7CiAgY29uc3QgcmVxdWlyZTIgPSBjcmVhdGVSZXF1aXJlKGltcG9ydC5tZXRhLnVybCk7CiAgZ2xvYmFsVGhpcy5yZXF1aXJlID0gcmVxdWlyZTI7CiAgcHJvY2Vzcy5vbigiYmVmb3JlRXhpdCIsICgpID0+IHsKICAgIGlmICghcHJvY0V4aXRDYWxsZWQpIHsKICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZXN0IGhhcm5lc3MgcHJvY2VzcyBleGl0ZWQgYmVmb3JlIHRlc3QgcHJvY2Vzcy4KVGhpcyB1c3VhbGx5IG1lYW5zIHRoZXJlIGFyZSBzb21lIGRhbmdsaW5nIGNvbnRpbnVhdGlvbnMsIHdoaWNoIGFyZSBhd2FpdGVkIGJ1dCBuZXZlciByZXN1bWVkLmApOwogICAgfQogIH0pOwogIHByb2Nlc3Mub24oInVuaGFuZGxlZFJlamVjdGlvbiIsIChlcnJvcikgPT4gewogICAgaWYgKGVycm9yIGluc3RhbmNlb2YgV0FTSVByb2NFeGl0ICYmIGVycm9yLmNvZGUgPT0gMCkgewogICAgICByZXR1cm47CiAgICB9CiAgICB0aHJvdyBlcnJvcjsKICB9KTsKICBjb25zdCByb290RnMgPSAvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpOwogIGNvbnN0IG9uRXhpdCA9IG5ldyBQcm9taXNlKGFzeW5jIChyZXNvbHZlKSA9PiB7CiAgICB0cnkgewogICAgICBhd2FpdCBpbnN0YW50aWF0ZTIoeyBlbnYsIGFyZ3M6IFt3YXNtRmlsZU5hbWVdLmNvbmNhdChhcmdzKSwgcm9vdEZzIH0sIHsKICAgICAgICAid2FzaV9zbmFwc2hvdF9wcmV2aWV3MSI6IHsKICAgICAgICAgIHByb2NfZXhpdDogKGNvZGUyKSA9PiB7CiAgICAgICAgICAgIHByb2NFeGl0Q2FsbGVkID0gdHJ1ZTsKICAgICAgICAgICAgcmVzb2x2ZShjb2RlMik7CiAgICAgICAgICAgIHRocm93IG5ldyBXQVNJUHJvY0V4aXQoY29kZTIpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICB9IGNhdGNoIChlcnJvcikgewogICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBXQVNJUHJvY0V4aXQpIHsKICAgICAgICByZXNvbHZlKGVycm9yLmNvZGUpOwogICAgICB9IGVsc2UgewogICAgICAgIHRocm93IGVycm9yOwogICAgICB9CiAgICB9CiAgfSk7CiAgbGV0IGNvZGUgPSAxOwogIHRyeSB7CiAgICBjb2RlID0gYXdhaXQgb25FeGl0OwogIH0gZmluYWxseSB7CiAgICBmb3IgKGNvbnN0IHBhdGggb2YgWyJkZWZhdWx0LnByb2ZyYXciXSkgewogICAgICBhd2FpdCBleHRyYWN0QW5kU2F2ZUZpbGUocm9vdEZzLCBwYXRoKTsKICAgIH0KICAgIHByb2Nlc3MuZXhpdChjb2RlKTsKICB9Cn0KZXhwb3J0IHsKICBXZWJBc3NlbWJseTIgYXMgV2ViQXNzZW1ibHksCiAgaW5zdGFudGlhdGUsCiAgdGVzdEJyb3dzZXIsCiAgdGVzdE5vZGUKfTsK")! } \ No newline at end of file diff --git a/Sources/WebDriver/CommandWebDriverService.swift b/Sources/WebDriver/CommandWebDriverService.swift deleted file mode 100644 index b7069675..00000000 --- a/Sources/WebDriver/CommandWebDriverService.swift +++ /dev/null @@ -1,91 +0,0 @@ -import CartonHelpers -import CartonCore -import Foundation -import NIOCore -import NIOPosix - -public struct CommandWebDriverService: WebDriverService { - private static func findAvailablePort() async throws -> SocketAddress { - let bootstrap = ServerBootstrap(group: .singletonMultiThreadedEventLoopGroup) - let address = try SocketAddress.makeAddressResolvingHost("127.0.0.1", port: 0) - let channel = try await bootstrap.bind(to: address).get() - let localAddr = channel.localAddress! - try await channel.close() - return localAddr - } - - private static func launchDriver( - terminal: InteractiveWriter, - executablePath: String - ) async throws -> (URL, CartonHelpers.Process) { - let address = try await findAvailablePort() - let process = CartonHelpers.Process(arguments: [ - executablePath, "--port=\(address.port!)", - ]) - terminal.logLookup("Launch WebDriver executable: ", executablePath) - try process.launch() - let url = URL(string: "http://\(address.ipAddress!):\(address.port!)")! - return (url, process) - } - - public static func findFromEnvironment( - terminal: InteractiveWriter - ) async throws -> CommandWebDriverService? { - terminal.logLookup("- checking WebDriver executable: ", "WEBDRIVER_PATH") - guard let executable = ProcessInfo.processInfo.environment["WEBDRIVER_PATH"] else { - return nil - } - let (endpoint, process) = try await launchDriver( - terminal: terminal, executablePath: executable - ) - return CommandWebDriverService(endpoint: endpoint, process: process) - } - - public static func findFromPath( - terminal: InteractiveWriter - ) async throws -> CommandWebDriverService? { - let driverCandidates = [ - "chromedriver", "geckodriver", "safaridriver", "msedgedriver", - ] - terminal.logLookup( - "- checking WebDriver executable in PATH: ", driverCandidates.joined(separator: ", ")) - guard let found = driverCandidates.lazy - .compactMap({ try? Foundation.Process.which($0) }).first else - { - return nil - } - let (endpoint, process) = try await launchDriver( - terminal: terminal, executablePath: found.path - ) - return CommandWebDriverService(endpoint: endpoint, process: process) - } - - public static func find( - terminal: InteractiveWriter - ) async throws -> CommandWebDriverService? { - if let driver = try await findFromEnvironment(terminal: terminal) { - return driver - } - - if let driver = try await findFromPath(terminal: terminal) { - return driver - } - - return nil - } - - public init( - endpoint: URL, - process: CartonHelpers.Process - ) { - self.endpoint = endpoint - self.process = process - } - - public var endpoint: URL - public var process: CartonHelpers.Process - - public func dispose() { - process.signal(SIGKILL) - } -} diff --git a/Sources/WebDriver/CurlWebDriverHTTPClient.swift b/Sources/WebDriver/CurlWebDriverHTTPClient.swift deleted file mode 100644 index 33da368d..00000000 --- a/Sources/WebDriver/CurlWebDriverHTTPClient.swift +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2022 Carton contributors -// -// 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. - -import Foundation - -#if canImport(FoundationNetworking) -import FoundationNetworking -#endif - -public struct CurlWebDriverHTTPClient: WebDriverHTTPClient { - public init(cliPath: URL) { - self.cliPath = cliPath - } - - public var cliPath: URL - - public static func find() -> CurlWebDriverHTTPClient? { - guard let path = ProcessInfo.processInfo.environment["PATH"] else { return nil } - #if os(Windows) - let pathSeparator: Character = ";" - #else - let pathSeparator: Character = ":" - #endif - for pathEntry in path.split(separator: pathSeparator) { - let candidate = URL(fileURLWithPath: String(pathEntry)).appendingPathComponent("curl") - if FileManager.default.fileExists(atPath: candidate.path) { - return CurlWebDriverHTTPClient(cliPath: candidate) - } - } - return nil - } - - public func data(for request: URLRequest) async throws -> Data { - guard let url = request.url?.absoluteString else { - preconditionFailure() - } - let process = Process() - process.executableURL = cliPath - process.arguments = [ - url, "-X", request.httpMethod ?? "GET", "--silent", "--fail-with-body", "--data-binary", "@-" - ] - let stdout = Pipe() - let stdin = Pipe() - process.standardOutput = stdout - process.standardInput = stdin - if let httpBody = request.httpBody { - try stdin.fileHandleForWriting.write(contentsOf: httpBody) - } - try stdin.fileHandleForWriting.close() - try process.run() - process.waitUntilExit() - let responseBody = try stdout.fileHandleForReading.readToEnd() - guard process.terminationStatus == 0 else { - let body: String? = responseBody.map { String(decoding: $0, as: UTF8.self) } - - throw WebDriverError.curlError( - path: cliPath, - status: process.terminationStatus, - body: body - ) - } - return responseBody ?? Data() - } -} diff --git a/Sources/WebDriver/RemoteWebDriverService.swift b/Sources/WebDriver/RemoteWebDriverService.swift deleted file mode 100644 index c89f24b1..00000000 --- a/Sources/WebDriver/RemoteWebDriverService.swift +++ /dev/null @@ -1,25 +0,0 @@ -import CartonCore -import Foundation - -public struct RemoteWebDriverService: WebDriverService { - public static func find( - terminal: InteractiveWriter - ) async throws -> RemoteWebDriverService? { - terminal.logLookup("- checking WebDriver endpoint: ", "WEBDRIVER_REMOTE_URL") - guard let value = ProcessInfo.processInfo.environment["WEBDRIVER_REMOTE_URL"] else { - return nil - } - guard let endporint = URL(string: value) else { - throw WebDriverError.invalidRemoteURL(value) - } - return RemoteWebDriverService(endpoint: endporint) - } - - public init(endpoint: URL) { - self.endpoint = endpoint - } - - public var endpoint: URL - - public func dispose() {} -} diff --git a/Sources/WebDriver/URLSessionAsync.swift b/Sources/WebDriver/URLSessionAsync.swift deleted file mode 100644 index faa548b2..00000000 --- a/Sources/WebDriver/URLSessionAsync.swift +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2022 Carton contributors -// -// 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. - -import Foundation - -#if canImport(FoundationNetworking) - -import FoundationNetworking - -/// Until we get "async" implementations of URLSession in corelibs-foundation, we use our own polyfill. -extension URLSession { - public func data(for request: URLRequest) async throws -> (Data, URLResponse) { - return try await withCheckedThrowingContinuation { continuation in - let task = self.dataTask(with: request) { (data, response, error) in - guard let data = data, let response = response else { - let error = error ?? URLError(.badServerResponse) - return continuation.resume(throwing: error) - } - continuation.resume(returning: (data, response)) - } - task.resume() - } - } -} - -#endif diff --git a/Sources/WebDriver/URLSessionWebDriverHTTPClient.swift b/Sources/WebDriver/URLSessionWebDriverHTTPClient.swift deleted file mode 100644 index 5d33da8b..00000000 --- a/Sources/WebDriver/URLSessionWebDriverHTTPClient.swift +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 Carton contributors -// -// 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. - -import Foundation - -#if canImport(FoundationNetworking) -#else - -// Due to a broken URLSession in swift-corelibs-foundation, this class cannot be used on Linux. -public struct URLSessionWebDriverHTTPClient: WebDriverHTTPClient { - public init(session: URLSession) { - self.session = session - } - - public var session: URLSession - - public func data(for request: URLRequest) async throws -> Data { - let (data, httpResponse) = try await session.data(for: request) - guard let httpResponse = httpResponse as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode - else { - throw WebDriverError.httpError( - "\(request.httpMethod ?? "GET") \(request.url.debugDescription) failed" - ) - } - return data - } -} - -#endif diff --git a/Sources/WebDriver/WebDriverClient.swift b/Sources/WebDriver/WebDriverClient.swift deleted file mode 100644 index dd20ef27..00000000 --- a/Sources/WebDriver/WebDriverClient.swift +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2022 Carton contributors -// -// 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. - -import Foundation - -#if canImport(FoundationNetworking) -import FoundationNetworking -#endif - -public struct WebDriverClient { - private let client: any WebDriverHTTPClient - let driverEndpoint: URL - let sessionId: String - - @dynamicMemberLookup - struct ValueResponse: Decodable { - let value: Value - subscript(dynamicMember keyPath: KeyPath) -> T { - self.value[keyPath: keyPath] - } - } - - public static let defaultSessionRequestBody = #""" - { - "capabilities": { - "alwaysMatch": { - "goog:chromeOptions": { - "w3c": true, - "args": ["--headless", "--no-sandbox"] - }, - "moz:firefoxOptions": { - "args": ["-headless"] - }, - "ms:edgeOptions": { - "args": ["--headless", "--no-sandbox"] - } - } - } - } - """# - - public static func newSession( - endpoint: URL, - body: String = defaultSessionRequestBody, - httpClient: any WebDriverHTTPClient - ) async throws -> WebDriverClient { - struct Response: Decodable { - let sessionId: String - } - struct Request: Encodable { - let capabilities: [String: String] = [:] - let desiredCapabilities: [String: String] = [:] - } - - var request = URLRequest(url: endpoint.appendingPathComponent("session")) - request.httpMethod = "POST" - request.httpBody = body.data(using: .utf8) - let body = try await httpClient.data(for: request) - let decoder = JSONDecoder() - let response = try decoder.decode(ValueResponse.self, from: body) - return WebDriverClient( - client: httpClient, - driverEndpoint: endpoint, - sessionId: response.sessionId) - } - - private func makeSessionURL(_ components: String...) -> String { - var url = - driverEndpoint - .appendingPathComponent("session") - .appendingPathComponent(sessionId) - for component in components { - url.appendPathComponent(component) - } - return url.absoluteString - } - - private static func makeRequestBody(_ body: R) throws -> Data { - let encoder = JSONEncoder() - return try encoder.encode(body) - } - - public func goto(url: URL) async throws { - struct Request: Encodable { - let url: String - } - var request = URLRequest(url: URL(string: makeSessionURL("url"))!) - request.httpMethod = "POST" - request.httpBody = try Self.makeRequestBody(Request(url: url.absoluteString)) - request.addValue("carton", forHTTPHeaderField: "User-Agent") - _ = try await client.data(for: request) - } - - public func closeSession() async throws { - var request = URLRequest(url: URL(string: makeSessionURL())!) - request.httpMethod = "DELETE" - _ = try await client.data(for: request) - } -} diff --git a/Sources/WebDriver/WebDriverError.swift b/Sources/WebDriver/WebDriverError.swift deleted file mode 100644 index 1dd199cf..00000000 --- a/Sources/WebDriver/WebDriverError.swift +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2022 Carton contributors -// -// 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. - -import Foundation - -public enum WebDriverError: Error & CustomStringConvertible { - case invalidRemoteURL(String) - case failedToFindWebDriver - case failedToFindHTTPClient - case curlError(path: URL, status: Int32, body: String?) - case httpError(String) - - public var description: String { - switch self { - case .invalidRemoteURL(let url): return "invalid remote webdriver URL: \(url)" - case .curlError(path: let path, status: let status, body: let body): - var lines: [String] = [ - "\(path.path) failed with status \(status)." - ] - - if let body { - lines += [ - "body:", body - ] - } - - return lines.joined(separator: "\n") - case .failedToFindWebDriver: - return """ - Failed to find WebDriver executable or remote URL to a running driver process. - Please make sure that you are satisfied with one of the followings (in order of priority) - 1. Set `WEBDRIVER_REMOTE_URL` with the address of remote WebDriver like `WEBDRIVER_REMOTE_URL=http://localhost:9515`. - 2. Set `WEBDRIVER_PATH` with the path to your WebDriver executable. - 3. `chromedriver`, `geckodriver`, `safaridriver`, or `msedgedriver` has been installed in `PATH` - """ - case .failedToFindHTTPClient: - return """ - The HTTPClient for use with WebDriver could not be found. - On Linux, please ensure that curl is installed. - On Mac, URLSession can be used, so this error should not appear. - If this error is displayed, an unknown bug may have occurred. - """ - case .httpError(let string): return "http error: \(string)" - } - } -} diff --git a/Sources/WebDriver/WebDriverHTTPClient.swift b/Sources/WebDriver/WebDriverHTTPClient.swift deleted file mode 100644 index c1d03e67..00000000 --- a/Sources/WebDriver/WebDriverHTTPClient.swift +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2022 Carton contributors -// -// 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. - -import Foundation - -#if canImport(FoundationNetworking) -import FoundationNetworking -#endif - -public protocol WebDriverHTTPClient { - func data(for request: URLRequest) async throws -> Data -} - -public enum WebDriverHTTPClients { - public static func find() throws -> any WebDriverHTTPClient { - if let curl = CurlWebDriverHTTPClient.find() { - return curl - } - - #if canImport(FoundationNetworking) - throw WebDriverError.failedToFindHTTPClient - #else - return URLSessionWebDriverHTTPClient(session: .shared) - #endif - } -} diff --git a/Sources/WebDriver/WebDriverService.swift b/Sources/WebDriver/WebDriverService.swift deleted file mode 100644 index 7f5731fc..00000000 --- a/Sources/WebDriver/WebDriverService.swift +++ /dev/null @@ -1,48 +0,0 @@ -import CartonHelpers -import CartonCore -import Foundation - -public protocol WebDriverService { - static func find( - terminal: InteractiveWriter - ) async throws -> Self? - - func dispose() - - var endpoint: URL { get } -} - -extension WebDriverService { - public func client( - httpClient: (any WebDriverHTTPClient)? = nil - ) async throws -> WebDriverClient { - let httpClient = try httpClient ?? WebDriverHTTPClients.find() - - return try await withRetry( - maxAttempts: 5, - initialDelay: .seconds(3), - retryInterval: .seconds(10) - ) { - try await WebDriverClient.newSession( - endpoint: endpoint, - httpClient: httpClient - ) - } - } -} - -public enum WebDriverServices { - public static func find( - terminal: InteractiveWriter - ) async throws -> any WebDriverService { - if let service = try await RemoteWebDriverService.find(terminal: terminal) { - return service - } - - if let service = try await CommandWebDriverService.find(terminal: terminal) { - return service - } - - throw WebDriverError.failedToFindWebDriver - } -} diff --git a/Sources/carton-frontend-slim/BundleLayout.swift b/Sources/carton-frontend/BundleLayout.swift similarity index 82% rename from Sources/carton-frontend-slim/BundleLayout.swift rename to Sources/carton-frontend/BundleLayout.swift index 991958a0..8a1c448f 100644 --- a/Sources/carton-frontend-slim/BundleLayout.swift +++ b/Sources/carton-frontend/BundleLayout.swift @@ -29,7 +29,8 @@ struct BundleLayout { { let wasmDestinationPath = try computeWasmDestinationPath(contentHash: contentHash) if wasmSourcePath != wasmDestinationPath { - try localFileSystem.move(from: wasmSourcePath, to: wasmDestinationPath) + try localFileSystem.removeFileTree(wasmDestinationPath) + try localFileSystem.copy(from: wasmSourcePath, to: wasmDestinationPath) } try copyResources(wasmDestinationPath: wasmDestinationPath, terminal: terminal) // Copy the bundle entrypoint, point to the binary, and give it a cachebuster name. @@ -46,13 +47,12 @@ struct BundleLayout { bytes: entrypoint ) - try localFileSystem.writeFileContents( + try writeFileIfChanged( AbsolutePath(validating: "index.html", relativeTo: bundleDirectory), - bytes: ByteString( - encodingAsUTF8: HTML.indexPage( - customContent: HTML.readCustomIndexPage(at: customIndexPage, on: localFileSystem), - entrypointName: entrypointName - )) + contents: HTML.indexPage( + customContent: HTML.readCustomIndexPage(at: customIndexPage, on: localFileSystem), + entrypointName: entrypointName + ).utf8 ) } @@ -97,14 +97,44 @@ struct BundleLayout { } } - func computeWasmDestinationPath(contentHash: Bool) throws -> AbsolutePath { + @discardableResult + private func copyFileIfChanged( + from sourcePath: AbsolutePath, + to destinationPath: AbsolutePath + ) throws -> Bool { + if localFileSystem.exists(destinationPath) { + let sourceContent = try localFileSystem.readFileContents(sourcePath) + let destinationContent = try localFileSystem.readFileContents(destinationPath) + if sourceContent == destinationContent { + return false + } + try localFileSystem.removeFileTree(destinationPath) + } + try localFileSystem.copy(from: sourcePath, to: destinationPath) + return true + } + + private func writeFileIfChanged( + _ path: AbsolutePath, contents: S + ) throws where S.Element == UInt8 { + let bytes = ByteString(contents) + if localFileSystem.exists(path) { + let existingContents = try localFileSystem.readFileContents(path) + if existingContents == bytes { + return + } + } + try localFileSystem.writeFileContents(path, bytes: bytes) + } + + private func computeWasmDestinationPath(contentHash: Bool) throws -> AbsolutePath { let wasmFileHash = try localFileSystem.readFileContents(wasmSourcePath).hexChecksum // Rename the final binary to use a part of its hash to bust browsers and CDN caches. let mainModuleName = contentHash ? "\(mainModuleBaseName).\(wasmFileHash).wasm" : "\(mainModuleBaseName).wasm" return try AbsolutePath(validating: mainModuleName, relativeTo: bundleDirectory) } - func copyResources(wasmDestinationPath: AbsolutePath, terminal: InteractiveWriter) throws { + private func copyResources(wasmDestinationPath: AbsolutePath, terminal: InteractiveWriter) throws { try localFileSystem.writeFileContents( AbsolutePath(validating: "intrinsics.js", relativeTo: bundleDirectory), bytes: ByteString(StaticResource.intrinsics) @@ -129,7 +159,10 @@ struct BundleLayout { encodingAsUTF8: """ { "type": "module", - "main": "./index.js" + "main": "./index.js", + "devDependencies": { + "vite": "^6.0.3" + } } """ ) @@ -141,6 +174,7 @@ struct BundleLayout { guard localFileSystem.exists(resourcesPath, followSymlink: true) else { continue } terminal.logLookup("Copying resources to ", targetDirectory) + try localFileSystem.removeFileTree(targetDirectory) try localFileSystem.copy(from: resourcesPath, to: targetDirectory) } diff --git a/Sources/carton-frontend-slim/CartonFrontendBundleCommand.swift b/Sources/carton-frontend/CartonFrontendBundleCommand.swift similarity index 100% rename from Sources/carton-frontend-slim/CartonFrontendBundleCommand.swift rename to Sources/carton-frontend/CartonFrontendBundleCommand.swift diff --git a/Sources/CartonFrontend/Commands/CartonFrontendDevCommand.swift b/Sources/carton-frontend/CartonFrontendDevCommand.swift similarity index 65% rename from Sources/CartonFrontend/Commands/CartonFrontendDevCommand.swift rename to Sources/carton-frontend/CartonFrontendDevCommand.swift index b1a19810..23fb5382 100644 --- a/Sources/CartonFrontend/Commands/CartonFrontendDevCommand.swift +++ b/Sources/carton-frontend/CartonFrontendDevCommand.swift @@ -15,7 +15,6 @@ import ArgumentParser import CartonCore import CartonHelpers -import CartonKit import Foundation enum DevCommandError: Error & CustomStringConvertible { @@ -41,7 +40,6 @@ enum DevCommandError: Error & CustomStringConvertible { } struct CartonFrontendDevCommand: AsyncParsableCommand { - static let entrypoint = Entrypoint(fileName: "dev.js", content: StaticResource.dev) @Option(help: "Specify name of an executable product in development.") var product: String? @@ -75,9 +73,6 @@ struct CartonFrontendDevCommand: AsyncParsableCommand { ) var host: String? - @Flag(name: .long, help: "Skip automatically opening app in system browser.") - var skipAutoOpen = false - @Option( name: .customLong("watch-path"), help: "Specify a path to a directory to watch for changes." @@ -119,27 +114,103 @@ struct CartonFrontendDevCommand: AsyncParsableCommand { @Option(name: .long, help: .hidden) var pid: Int32? + @Option( + name: .long, + help: ArgumentHelp( + "Internal: Path to writable directory", visibility: .private + )) + var pluginWorkDirectory: String = "./" + static let configuration = CommandConfiguration( commandName: "dev", abstract: "Watch the current directory, host the app, rebuild on change." ) - private func makeBuilderIfNeed() throws -> SwiftPMPluginBuilder? { + func run() async throws { + let terminal = InteractiveWriter.stdout + + if !verbose { + terminal.revertCursorAndClear() + } + + let cwd = localFileSystem.currentWorkingDirectory! + let mainWasmPath = try AbsolutePath(validating: mainWasmPath, relativeTo: cwd) + let bundleDirectory = try AbsolutePath( + validating: pluginWorkDirectory, + relativeTo: cwd + ).appending(component: "Bundle") + + let layout = BundleLayout( + mainModuleBaseName: mainWasmPath.basenameWithoutExt, + wasmSourcePath: mainWasmPath, + buildDirectory: mainWasmPath.parentDirectory, + bundleDirectory: bundleDirectory, + topLevelResourcePaths: resources + ) + try build(layout: layout, terminal: terminal) + + try Foundation.Process.checkRun(Foundation.Process.which("npm"), arguments: [ + "--prefix", bundleDirectory.pathString, "install", + ]) + + try watch(cwd: cwd, layout: layout, terminal: terminal) + + var viteArguments = [bundleDirectory.pathString, "--clearScreen", "false"] + if let host = host { + viteArguments += ["--host", host] + } + viteArguments += ["--port", "\(port)"] + let viteProcess = Foundation.Process() + viteProcess.executableURL = bundleDirectory.asURL + .appendingPathComponent("node_modules") + .appendingPathComponent(".bin") + .appendingPathComponent("vite") + viteProcess.arguments = viteArguments + let signalSources = viteProcess.forwardTerminationSignals() + defer { + for signalSource in signalSources { + signalSource.cancel() + } + } + try viteProcess.run() + + let _: () = try await withCheckedThrowingContinuation { continuation in + viteProcess.terminationHandler = { process in + if process.terminationStatus != 0 { + continuation.resume( + throwing: CartonCoreError("Vite process exited with status \(process.terminationStatus)") + ) + } else { + continuation.resume() + } + } + } + } + + private func build(layout: BundleLayout, terminal: InteractiveWriter) throws { + try localFileSystem.createDirectory(layout.bundleDirectory, recursive: false) + + try layout.copyAppEntrypoint( + customIndexPage: customIndexPage, + contentHash: false, + terminal: terminal + ) + } + + private func watch(cwd: AbsolutePath, layout: BundleLayout, terminal: InteractiveWriter) throws { guard !watchPaths.isEmpty else { - return nil + return } + let pathsToWatch = try watchPaths.map { + try AbsolutePath(validating: $0, relativeTo: cwd) + } guard let buildRequest else { throw DevCommandError.noBuildRequestOption } guard let buildResponse else { throw DevCommandError.noBuildResponseOption } - - let pathsToWatch = try watchPaths.map { - try AbsolutePath(validating: $0, relativeTo: localFileSystem.currentWorkingDirectory!) - } - guard let buildRequest = FileHandle(forWritingAtPath: buildRequest) else { throw DevCommandError.failedToOpenBuildRequestPipe } @@ -147,52 +218,31 @@ struct CartonFrontendDevCommand: AsyncParsableCommand { throw DevCommandError.failedToOpenBuildResponsePipe } - return SwiftPMPluginBuilder( + let builder = SwiftPMPluginBuilder( pathsToWatch: pathsToWatch, buildRequest: buildRequest, buildResponse: buildResponse ) - } - - func run() async throws { - let terminal = InteractiveWriter.stdout - if !verbose { - terminal.revertCursorAndClear() - } - - let server = try await Server( - .init( - builder: try makeBuilderIfNeed(), - mainWasmPath: AbsolutePath( - validating: mainWasmPath, relativeTo: localFileSystem.currentWorkingDirectory!), - verbose: verbose, - bindingAddress: bind, - port: port, - host: Server.Configuration.host(bindOption: bind, hostOption: host), - customIndexPath: customIndexPage.map { - try AbsolutePath(validating: $0, relativeTo: localFileSystem.currentWorkingDirectory!) - }, - resourcesPaths: resources, - entrypoint: Self.entrypoint, - pid: pid, - terminal: terminal - ) - ) - let localURL = try await server.start() - if !skipAutoOpen { + let watcher = FSWatch( + paths: pathsToWatch, + latency: 0.1 + ) { changes in + guard !changes.isEmpty else { return } do { - try openInSystemBrowser(url: localURL) + try builder.run() + try build(layout: layout, terminal: terminal) } catch { - terminal.write("open browser failed: \(error)", inColor: .red) + terminal.write("\(error)", inColor: .red) } } - try await server.waitUntilStop() + try watcher.start() } } /// Builder for communicating with the SwiftPM Plugin process by IPC. -struct SwiftPMPluginBuilder: BuilderProtocol { +struct SwiftPMPluginBuilder { + struct BuilderProtocolSimpleBuildFailedError: Error {} let pathsToWatch: [AbsolutePath] let buildRequest: FileHandle let buildResponse: FileHandle @@ -203,7 +253,7 @@ struct SwiftPMPluginBuilder: BuilderProtocol { self.buildResponse = buildResponse } - func run() async throws { + func run() throws { // We expect single response per request try buildRequest.write(contentsOf: Data([1])) guard let responseMessage = try buildResponse.read(upToCount: 1) else { diff --git a/Sources/carton-frontend-slim/CartonFrontendSlimCommand.swift b/Sources/carton-frontend/CartonFrontendSlimCommand.swift similarity index 94% rename from Sources/carton-frontend-slim/CartonFrontendSlimCommand.swift rename to Sources/carton-frontend/CartonFrontendSlimCommand.swift index d516058d..915a28e3 100644 --- a/Sources/carton-frontend-slim/CartonFrontendSlimCommand.swift +++ b/Sources/carton-frontend/CartonFrontendSlimCommand.swift @@ -21,12 +21,13 @@ import CartonCore @main public struct CartonFrontendSlimCommand: AsyncParsableCommand { public static let configuration = CommandConfiguration( - commandName: "carton-frontend-slim", + commandName: "carton-frontend", abstract: "📦 Watcher, bundler, and test runner for your SwiftWasm apps.", version: cartonVersion, subcommands: [ CartonFrontendBundleCommand.self, CartonFrontendTestCommand.self, + CartonFrontendDevCommand.self, ] ) diff --git a/Sources/carton-frontend-slim/CartonFrontendTestCommand.swift b/Sources/carton-frontend/CartonFrontendTestCommand.swift similarity index 100% rename from Sources/carton-frontend-slim/CartonFrontendTestCommand.swift rename to Sources/carton-frontend/CartonFrontendTestCommand.swift diff --git a/Sources/carton-frontend-slim/TestRunners/CommandTestRunner.swift b/Sources/carton-frontend/TestRunners/CommandTestRunner.swift similarity index 100% rename from Sources/carton-frontend-slim/TestRunners/CommandTestRunner.swift rename to Sources/carton-frontend/TestRunners/CommandTestRunner.swift diff --git a/Sources/carton-frontend-slim/TestRunners/JavaScriptTestRunner.swift b/Sources/carton-frontend/TestRunners/JavaScriptTestRunner.swift similarity index 100% rename from Sources/carton-frontend-slim/TestRunners/JavaScriptTestRunner.swift rename to Sources/carton-frontend/TestRunners/JavaScriptTestRunner.swift diff --git a/Sources/carton-frontend-slim/TestRunners/String+Regex.swift b/Sources/carton-frontend/TestRunners/String+Regex.swift similarity index 100% rename from Sources/carton-frontend-slim/TestRunners/String+Regex.swift rename to Sources/carton-frontend/TestRunners/String+Regex.swift diff --git a/Sources/carton-frontend-slim/TestRunners/String+color.swift b/Sources/carton-frontend/TestRunners/String+color.swift similarity index 100% rename from Sources/carton-frontend-slim/TestRunners/String+color.swift rename to Sources/carton-frontend/TestRunners/String+color.swift diff --git a/Sources/carton-frontend-slim/TestRunners/TestRunner.swift b/Sources/carton-frontend/TestRunners/TestRunner.swift similarity index 100% rename from Sources/carton-frontend-slim/TestRunners/TestRunner.swift rename to Sources/carton-frontend/TestRunners/TestRunner.swift diff --git a/Sources/carton-frontend-slim/TestRunners/TestsParser.swift b/Sources/carton-frontend/TestRunners/TestsParser.swift similarity index 100% rename from Sources/carton-frontend-slim/TestRunners/TestsParser.swift rename to Sources/carton-frontend/TestRunners/TestsParser.swift diff --git a/Sources/carton-frontend/main.swift b/Sources/carton-frontend/main.swift deleted file mode 100644 index 98a505b7..00000000 --- a/Sources/carton-frontend/main.swift +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2020 Carton contributors -// -// 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. - -import CartonFrontend - -func main() async { - await CartonFrontendCommand.main() -} -await main() diff --git a/Tests/CartonCommandTests/BundleCommandTests.swift b/Tests/CartonCommandTests/BundleCommandTests.swift index e0ace910..13f905a6 100644 --- a/Tests/CartonCommandTests/BundleCommandTests.swift +++ b/Tests/CartonCommandTests/BundleCommandTests.swift @@ -19,8 +19,6 @@ import CartonHelpers import CartonCore import XCTest -@testable import CartonFrontend - final class BundleCommandTests: XCTestCase { func testWithNoArguments() async throws { let fs = localFileSystem diff --git a/Tests/CartonCommandTests/CommandTestHelper.swift b/Tests/CartonCommandTests/CommandTestHelper.swift index eeb4a725..99536497 100644 --- a/Tests/CartonCommandTests/CommandTestHelper.swift +++ b/Tests/CartonCommandTests/CommandTestHelper.swift @@ -15,7 +15,7 @@ import ArgumentParser import XCTest import CartonHelpers -import CartonKit +import SwiftToolchain #if canImport(FoundationNetworking) import FoundationNetworking @@ -155,18 +155,3 @@ func fetchHead(at url: URL, timeout: Duration) async throws -> HTTPURLResponse { return httpResponse } - -func checkServerNameField(response: HTTPURLResponse, expectedPID: Int32) throws { - guard let string = response.value(forHTTPHeaderField: "Server") else { - throw CommandTestError("no Server header") - } - let field = try Server.ServerNameField.parse(string) - - guard field.name == Server.serverName else { - throw CommandTestError("invalid server name: \(field)") - } - - guard field.pid == expectedPID else { - throw CommandTestError("Expected PID \(expectedPID) but got PID \(field.pid).") - } -} diff --git a/Tests/CartonCommandTests/DevCommandTests.swift b/Tests/CartonCommandTests/DevCommandTests.swift index 9d36a99b..fd27b9dc 100644 --- a/Tests/CartonCommandTests/DevCommandTests.swift +++ b/Tests/CartonCommandTests/DevCommandTests.swift @@ -19,8 +19,6 @@ import Foundation import XCTest import CartonHelpers -@testable import CartonFrontend - #if canImport(FoundationNetworking) import FoundationNetworking #endif @@ -31,11 +29,11 @@ final class DevCommandTests: XCTestCase { // FIXME: Don't assume a specific port is available since it can be used by others or tests try await withFixture("EchoExecutable") { packageDirectory in let process = try swiftRunProcess( - ["carton", "dev", "--verbose", "--skip-auto-open"], + ["carton", "dev", "--verbose"], packageDirectory: packageDirectory.asURL ) - try await checkForExpectedContent(process: process, at: "http://127.0.0.1:8080") + try await checkForExpectedContent(process: process, at: "http://localhost:8080") } } @@ -43,11 +41,11 @@ final class DevCommandTests: XCTestCase { // FIXME: Don't assume a specific port is available since it can be used by others or tests try await withFixture("EchoExecutable") { packageDirectory in let process = try swiftRunProcess( - ["carton", "dev", "--verbose", "--port", "8080", "--skip-auto-open"], + ["carton", "dev", "--verbose", "--port", "8080"], packageDirectory: packageDirectory.asURL ) - try await checkForExpectedContent(process: process, at: "http://127.0.0.1:8080") + try await checkForExpectedContent(process: process, at: "http://localhost:8080") } } #endif @@ -82,15 +80,16 @@ final class DevCommandTests: XCTestCase { let (response, data) = try await fetchDevServerWithRetry(at: try URL(string: url).unwrap("url")) XCTAssertEqual(response.statusCode, 200, "Response was not ok") - try checkServerNameField(response: response, expectedPID: process.process.processID) let expectedHtml = """ + + - + diff --git a/Tests/CartonCommandTests/FrontendDevServerTests.swift b/Tests/CartonCommandTests/FrontendDevServerTests.swift deleted file mode 100644 index 8519f0dc..00000000 --- a/Tests/CartonCommandTests/FrontendDevServerTests.swift +++ /dev/null @@ -1,191 +0,0 @@ -import XCTest -import CartonCore -import CartonHelpers -import CartonKit -import SwiftToolchain -import WebDriver - -struct DevServerClient { - var process: CartonHelpers.Process - - init( - wasmFile: AbsolutePath, - resourcesDir: AbsolutePath, - terminal: InteractiveWriter, - onStdout: ((String) -> Void)? - ) throws { - process = Process( - arguments: [ - "swift", "run", "carton-frontend", "dev", - "--skip-auto-open", "--verbose", - "--main-wasm-path", wasmFile.pathString, - "--resources", resourcesDir.pathString - ], - outputRedirection: .stream( - stdout: { (chunk) in - let string = String(decoding: chunk, as: UTF8.self) - - onStdout?(string) - - terminal.write(string) - }, stderr: { (_) in }, - redirectStderr: true - ) - ) - try process.launch() - } - - func dispose() { - process.signal(SIGINT) - } - - func fetchBinary( - at url: URL, - file: StaticString = #file, line: UInt = #line - ) async throws -> Data { - let (response, body) = try await withRetry( - maxAttempts: 5, initialDelay: .seconds(3), retryInterval: .seconds(10) - ) { - try await fetchWebContent(at: url, timeout: .seconds(10)) - } - XCTAssertEqual(response.statusCode, 200, file: file, line: line) - - try checkServerNameField(response: response, expectedPID: process.processID) - - return body - } - - func fetchString( - at url: URL, - file: StaticString = #file, line: UInt = #line - ) async throws -> String { - let data = try await fetchBinary(at: url, file: file, line: line) - - guard let string = String(data: data, encoding: .utf8) else { - throw CommandTestError("not UTF-8 string content") - } - - return string - } - - func fetchContentSize( - at url: URL, file: StaticString = #file, line: UInt = #line - ) async throws -> Int { - let httpResponse = try await fetchHead(at: url, timeout: .seconds(10)) - let contentLength = try XCTUnwrap(httpResponse.allHeaderFields["Content-Length"] as? String) - return Int(contentLength)! - } -} - -final class FrontendDevServerTests: XCTestCase { - func testDevServerPublish() async throws { - let fs = localFileSystem - let terminal = InteractiveWriter.stdout - let projectDir = try testFixturesDirectory.appending(component: "DevServerTestApp") - let buildDir = projectDir.appending(components: [".build", "wasm32-unknown-wasi", "debug"]) - let wasmFile = buildDir.appending(component: "app.wasm") - let resourcesDir = buildDir.appending(component: "DevServerTestApp_app.resources") - - try fs.changeCurrentWorkingDirectory(to: projectDir) - - if !fs.exists(wasmFile) { - let tools = try ToolchainSystem(fileSystem: .default) - let builderSwift = try await tools.inferSwiftPath(terminal) - - var args: [String] = [ - builderSwift.swift.path, "build", "--triple", "wasm32-unknown-wasi" - ] - args += Environment.browser.buildParameters().asBuildArguments() - - try await Process.run(args, terminal) - } - - try await Process.run(["swift", "build", "--target", "carton-frontend"], terminal) - - var gotHelloStdout = false - var gotHelloStderr = false - - let cl = try DevServerClient( - wasmFile: wasmFile, - resourcesDir: resourcesDir, - terminal: terminal, - onStdout: { (string) in - if string.contains("stdout: hello stdout") { - gotHelloStdout = true - } - if string.contains("stderr: hello stderr") { - gotHelloStderr = true - } - } - ) - defer { - cl.dispose() - } - - let host = try URL(string: "http://127.0.0.1:8080").unwrap("url") - - do { - let indexHtml = try await cl.fetchString(at: host) - - XCTAssertEqual(indexHtml, """ - - - - - - - - - - - """ - ) - let contentSize = try await cl.fetchContentSize(at: host) - XCTAssertEqual(contentSize, indexHtml.utf8.count) - } - - do { - let url = host.appendingPathComponent("dev.js") - let devJs = try await cl.fetchString(at: url) - let expected = try XCTUnwrap(String(data: StaticResource.dev, encoding: .utf8)) - XCTAssertEqual(devJs, expected) - let contentSize = try await cl.fetchContentSize(at: url) - XCTAssertEqual(contentSize, expected.utf8.count) - } - - do { - let url = host.appendingPathComponent("main.wasm") - let mainWasm = try await cl.fetchBinary(at: url) - let expected = try Data(contentsOf: wasmFile.asURL) - XCTAssertEqual(mainWasm, expected) - let contentSize = try await cl.fetchContentSize(at: url) - XCTAssertEqual(contentSize, expected.count) - } - - for name in ["style.css", "space separated.txt"] { - let styleCss = try await cl.fetchString(at: host.appendingPathComponent(name)) - let expected = try String(contentsOf: resourcesDir.appending(component: name).asURL) - XCTAssertEqual(styleCss, expected) - let contentSize = try await cl.fetchContentSize(at: host.appendingPathComponent(name)) - XCTAssertEqual(contentSize, expected.utf8.count) - } - - let webDriver = try await WebDriverServices.find(terminal: terminal) - defer { - webDriver.dispose() - } - - let webDriverClient = try await webDriver.client() - - try await webDriverClient.goto(url: host) - - try await withRetry(maxAttempts: 10, initialDelay: .seconds(3), retryInterval: .seconds(3)) { - if gotHelloStdout, gotHelloStderr { - return - } - throw CommandTestError("no output") - } - - try await webDriverClient.closeSession() - } -} diff --git a/Tests/CartonCommandTests/TestCommandTests.swift b/Tests/CartonCommandTests/TestCommandTests.swift index d9007985..49f400be 100644 --- a/Tests/CartonCommandTests/TestCommandTests.swift +++ b/Tests/CartonCommandTests/TestCommandTests.swift @@ -18,8 +18,6 @@ import CartonHelpers import XCTest -@testable import CartonFrontend - private enum Constants { static let testAppPackageName = "TestApp" static let nodeJSKitPackageName = "NodeJSKitTest" diff --git a/Tests/CartonTests/CartonTests.swift b/Tests/CartonTests/CartonTests.swift index 4dc2bb4c..c08cd05e 100644 --- a/Tests/CartonTests/CartonTests.swift +++ b/Tests/CartonTests/CartonTests.swift @@ -18,7 +18,6 @@ import XCTest import class Foundation.Bundle -@testable import CartonKit @testable import SwiftToolchain final class CartonTests: XCTestCase { @@ -61,60 +60,4 @@ final class CartonTests: XCTestCase { XCTAssertEqual(output?.trimmingCharacters(in: .whitespacesAndNewlines), cartonVersion) } - - final class TestOutputStream: OutputByteStream { - var bytes: [UInt8] = [] - var currentOutput: String { - String(bytes: bytes, encoding: .utf8)! - } - - var position: Int = 0 - - init() {} - - func flush() {} - - func write(_ byte: UInt8) { - bytes.append(byte) - } - - func write(_ bytes: C) where C: Collection, C.Element == UInt8 { - self.bytes.append(contentsOf: bytes) - } - } - - func testDestinationEnvironment() { - XCTAssertEqual( - DestinationEnvironment( - userAgent: - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:93.0) Gecko/20100101 Firefox/93.0" - ), - .firefox - ) - XCTAssertEqual( - DestinationEnvironment( - userAgent: - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38" - ), - .edge - ) - XCTAssertEqual( - DestinationEnvironment( - userAgent: - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36" - ), - .chrome - ) - XCTAssertEqual( - DestinationEnvironment( - userAgent: - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15" - ), - .safari - ) - XCTAssertEqual( - DestinationEnvironment(userAgent: "Opera/9.30 (Nintendo Wii; U; ; 3642; en)"), - nil - ) - } } diff --git a/Tests/CartonTests/StackTraceTests.swift b/Tests/CartonTests/StackTraceTests.swift deleted file mode 100644 index d3918174..00000000 --- a/Tests/CartonTests/StackTraceTests.swift +++ /dev/null @@ -1,520 +0,0 @@ -// Copyright 2020 Carton contributors -// -// 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. -// -// Created by Max Desiatov on 08/11/2020. -// - -import XCTest - -@testable import CartonHelpers -@testable import CartonKit - -final class StackTraceTests: XCTestCase {} -extension StackTraceTests { - func testFirefoxStackTrace() { - // swiftlint:disable line_length - let stackTrace = """ - wasmFs.fs.writeSync@webpack:///./entrypoint/dev.js?:35:21 - a/this.wasiImport.fd_write eval line 58 > WebAssembly.instantiate:wasm-function[62062]:0x12af331 - swift_reportError@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[21654]:0x37c242 - _swift_stdlib_reportFatalErrorInFile@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[22950]:0x3e2996 - $ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtFySRys5UInt8VGXEfU_yAMXEfU_@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[3635]:0xd717d - $ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtFySRys5UInt8VGXEfU_Tm@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[3636]:0xd7374 - $ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[2752]:0xa7917 - $sSayxSicig@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[2982]:0xb34da - $s7TestApp5crashyyF@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[1372]:0x8012c - $s7TestAppySay13JavaScriptKit7JSValueOGcfU_@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[1367]:0x7f4e7 - $s13JavaScriptKit9JSClosureCyACySayAA7JSValueOGccfcAeFcfU_@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[787]:0x5003b - $s13JavaScriptKit9JSClosureCyACySayAA7JSValueOGccfcAeFcfU_TA@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[786]:0x4ff96 - $sSay13JavaScriptKit7JSValueOGACIeggo_AdCIegnr_TR@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[783]:0x4fe00 - $sSay13JavaScriptKit7JSValueOGACIeggo_AdCIegnr_TRTA@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[782]:0x4fdc8 - $sSay13JavaScriptKit7JSValueOGACIegnr_AdCIeggo_TR@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[812]:0x52ddd - $sSay13JavaScriptKit7JSValueOGACIegnr_AdCIeggo_TRTA@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[802]:0x529bc - $s13JavaScriptKit24_call_host_function_implyys6UInt32V_SPySo10RawJSValueaGs5Int32VADtF@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[801]:0x525e8 - _call_host_function_impl@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[800]:0x52158 - _call_host_function@http://127.0.0.1:8080/dev.js line 97 > eval line 58 > WebAssembly.instantiate:wasm-function[1388]:0x814d3 - callHostFunction@webpack:///./node_modules/javascript-kit-swift/Runtime/lib/index.js?:110:21 - swjs_create_function/func_ref<@webpack:///./node_modules/javascript-kit-swift/Runtime/lib/index.js?:280:28 - """.firefoxStackTrace - - let expected: [StackTraceItem] = [ - .init( - symbol: "wasmFs.fs.writeSync", - location: "./entrypoint/dev.js?:35:21", - kind: .javaScript - ), - .init( - symbol: "a/this.wasiImport.fd_write) -> () in closure #1 (UnsafeBufferPointer) -> () in _assertionFailure(_: StaticString, _: StaticString, file: StaticString, line: UInt, flags: UInt32) -> Never", - location: "wasm-function[3635]:0xd717d", - kind: .webAssembly - ), - .init( - symbol: - "merged closure #1 (UnsafeBufferPointer) -> () in _assertionFailure(_: StaticString, _: StaticString, file: StaticString, line: UInt, flags: UInt32) -> Never", - location: "wasm-function[3636]:0xd7374", - kind: .webAssembly - ), - .init( - symbol: - "Swift._assertionFailure(_: StaticString, _: StaticString, file: StaticString, line: UInt, flags: UInt32) -> Never", - location: "wasm-function[2752]:0xa7917", - kind: .webAssembly - ), - .init( - symbol: "Swift.Array.subscript.getter : (Int) -> A", - location: "wasm-function[2982]:0xb34da", - kind: .webAssembly - ), - .init( - symbol: "TestApp.crash() -> ()", - location: "wasm-function[1372]:0x8012c", - kind: .webAssembly - ), - .init( - symbol: "closure #1 (Array) -> () in TestApp", - location: "wasm-function[1367]:0x7f4e7", - kind: .webAssembly - ), - .init( - symbol: - "closure #1 (Array) -> JavaScriptKit.JSValue in JavaScriptKit.JSClosure.init((Array) -> ()) -> JavaScriptKit.JSClosure", - location: "wasm-function[787]:0x5003b", - kind: .webAssembly - ), - .init( - symbol: - "partial apply forwarder for closure #1 (Array) -> JavaScriptKit.JSValue in JavaScriptKit.JSClosure.init((Array) -> ()) -> JavaScriptKit.JSClosure", - location: "wasm-function[786]:0x4ff96", - kind: .webAssembly - ), - .init( - symbol: - "reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue)", - location: "wasm-function[783]:0x4fe00", - kind: .webAssembly - ), - .init( - symbol: - "partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue)", - location: "wasm-function[782]:0x4fdc8", - kind: .webAssembly - ), - .init( - symbol: - "reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue)", - location: "wasm-function[812]:0x52ddd", - kind: .webAssembly - ), - .init( - symbol: - "partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue)", - location: "wasm-function[802]:0x529bc", - kind: .webAssembly - ), - .init( - symbol: - "JavaScriptKit._call_host_function_impl(UInt32, UnsafePointer<__C.RawJSValue>, Int32, UInt32) -> ()", - location: "wasm-function[801]:0x525e8", - kind: .webAssembly - ), - .init( - symbol: "_call_host_function_impl", - location: "wasm-function[800]:0x52158", - kind: .webAssembly - ), - .init( - symbol: "_call_host_function", - location: "wasm-function[1388]:0x814d3", - kind: .webAssembly - ), - .init( - symbol: "callHostFunction", - location: "./node_modules/javascript-kit-swift/Runtime/lib/index.js?:110:21", - kind: .javaScript - ), - .init( - symbol: "swjs_create_function/func_ref<", - location: "./node_modules/javascript-kit-swift/Runtime/lib/index.js?:280:28", - kind: .javaScript - ), - ] - XCTAssertEqual(stackTrace, expected) - } -} - -extension StackTraceTests { - func testSafariStackTrace() { - // swiftlint:disable line_length - let stackTrace = """ - forEach@[native code] - - - wasm-stub@[wasm code] - .wasm-function[write]@[wasm code] - .wasm-function[swift_reportError]@[wasm code] - .wasm-function[_swift_stdlib_reportFatalErrorInFile]@[wasm code] - .wasm-function[$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtFySRys5UInt8VGXEfU_yAMXEfU_]@[wasm code] - .wasm-function[$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtFySRys5UInt8VGXEfU_Tm]@[wasm code] - .wasm-function[$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF]@[wasm code] - .wasm-function[$sSayxSicig]@[wasm code] - .wasm-function[$s7TestApp5crashyyF]@[wasm code] - .wasm-function[$s7TestAppySay13JavaScriptKit7JSValueOGcfU_]@[wasm code] - .wasm-function[$s13JavaScriptKit9JSClosureCyACySayAA7JSValueOGccfcAeFcfU_]@[wasm code] - .wasm-function[$s13JavaScriptKit9JSClosureCyACySayAA7JSValueOGccfcAeFcfU_TA]@[wasm code] - .wasm-function[$sSay13JavaScriptKit7JSValueOGACIeggo_AdCIegnr_TR]@[wasm code] - .wasm-function[$sSay13JavaScriptKit7JSValueOGACIeggo_AdCIegnr_TRTA]@[wasm code] - .wasm-function[$sSay13JavaScriptKit7JSValueOGACIegnr_AdCIeggo_TR]@[wasm code] - .wasm-function[$sSay13JavaScriptKit7JSValueOGACIegnr_AdCIeggo_TRTA]@[wasm code] - .wasm-function[$s13JavaScriptKit24_call_host_function_implyys6UInt32V_SPySo10RawJSValueaGs5Int32VADtF]@[wasm code] - .wasm-function[_call_host_function_impl]@[wasm code] - .wasm-function[_call_host_function]@[wasm code] - wasm-stub@[wasm code] - swjs_call_host_function@[native code] - callHostFunction - """.safariStackTrace - - let expected: [StackTraceItem] = - [ - .init( - symbol: "forEach", - location: nil, - kind: .javaScript - ), - .init( - symbol: "wasm-stub", - location: nil, - kind: .javaScript - ), - .init( - symbol: "write", - location: nil, - kind: .webAssembly - ), - .init( - symbol: "swift_reportError", - location: nil, - kind: .webAssembly - ), - .init( - symbol: "_swift_stdlib_reportFatalErrorInFile", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "closure #1 (UnsafeBufferPointer) -> () in closure #1 (UnsafeBufferPointer) -> () in _assertionFailure(_: StaticString, _: StaticString, file: StaticString, line: UInt, flags: UInt32) -> Never", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "merged closure #1 (UnsafeBufferPointer) -> () in _assertionFailure(_: StaticString, _: StaticString, file: StaticString, line: UInt, flags: UInt32) -> Never", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "Swift._assertionFailure(_: StaticString, _: StaticString, file: StaticString, line: UInt, flags: UInt32) -> Never", - location: nil, - kind: .webAssembly - ), - .init( - symbol: "Swift.Array.subscript.getter : (Int) -> A", - location: nil, - kind: .webAssembly - ), - .init( - symbol: "TestApp.crash() -> ()", - location: nil, - kind: .webAssembly - ), - .init( - symbol: "closure #1 (Array) -> () in TestApp", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "closure #1 (Array) -> JavaScriptKit.JSValue in JavaScriptKit.JSClosure.init((Array) -> ()) -> JavaScriptKit.JSClosure", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "partial apply forwarder for closure #1 (Array) -> JavaScriptKit.JSValue in JavaScriptKit.JSClosure.init((Array) -> ()) -> JavaScriptKit.JSClosure", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue)", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue)", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue)", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue)", - location: nil, - kind: .webAssembly - ), - .init( - symbol: - "JavaScriptKit._call_host_function_impl(UInt32, UnsafePointer<__C.RawJSValue>, Int32, UInt32) -> ()", - location: nil, - kind: .webAssembly - ), - .init( - symbol: "_call_host_function_impl", - location: nil, - kind: .webAssembly - ), - .init( - symbol: "_call_host_function", - location: nil, - kind: .webAssembly - ), - .init( - symbol: "wasm-stub", - location: nil, - kind: .javaScript - ), - .init( - symbol: "swjs_call_host_function", - location: nil, - kind: .javaScript - ), - .init( - symbol: "callHostFunction", - location: nil, - kind: .javaScript - ), - ] - XCTAssertEqual(stackTrace, expected) - } -} - -extension StackTraceTests { - func testChromeStackTrace() { - // swiftlint:disable line_length - let stackTrace = """ - Error - at Object.wasmFs.fs.writeSync (webpack:///./entrypoint/dev.js?:54:25) - at eval (webpack:///./node_modules/@wasmer/wasi/lib/index.esm.js?:115:429) - at Array.forEach () - at eval (webpack:///./node_modules/@wasmer/wasi/lib/index.esm.js?:115:372) - at eval (webpack:///./node_modules/@wasmer/wasi/lib/index.esm.js?:102:271) - at write (:wasm-function[62105]:0x12b19bc) - at swift_reportError (:wasm-function[21697]:0x37e8aa) - at _swift_stdlib_reportFatalErrorInFile (:wasm-function[22993]:0x3e4ffe) - at $ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtFySRys5UInt8VGXEfU_yAMXEfU_ (:wasm-function[3676]:0xd96fc) - at $ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtFySRys5UInt8VGXEfU_Tm (:wasm-function[3677]:0xd98f3) - at $ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF (:wasm-function[2793]:0xa9f38) - at $sSayxSicig (:wasm-function[3023]:0xb5afb) - at $s7TestApp5crashyyF (:wasm-function[1413]:0x8274d) - at $s7TestAppySay13JavaScriptKit7JSValueOGcfU_ (:wasm-function[1408]:0x81b08) - at $s13JavaScriptKit9JSClosureCyACySayAA7JSValueOGccfcAeFcfU_ (:wasm-function[816]:0x51881) - at $s13JavaScriptKit9JSClosureCyACySayAA7JSValueOGccfcAeFcfU_TA (:wasm-function[815]:0x517dc) - at $sSay13JavaScriptKit7JSValueOGACIeggo_AdCIegnr_TR (:wasm-function[812]:0x51646) - at $sSay13JavaScriptKit7JSValueOGACIeggo_AdCIegnr_TRTA (:wasm-function[811]:0x5160e) - at $sSay13JavaScriptKit7JSValueOGACIegnr_AdCIeggo_TR (:wasm-function[839]:0x54566) - at $sSay13JavaScriptKit7JSValueOGACIegnr_AdCIeggo_TRTA (:wasm-function[831]:0x54202) - at $s13JavaScriptKit24_call_host_function_implyys6UInt32V_SPySo10RawJSValueaGs5Int32VADtF (:wasm-function[830]:0x53e2e) - at _call_host_function_impl (:wasm-function[829]:0x5399e) - at _call_host_function (:wasm-function[1429]:0x83af4) - at callHostFunction (webpack:///./node_modules/javascript-kit-swift/Runtime/lib/index.js?:110:21) - at HTMLButtonElement.eval (webpack:///./node_modules/javascript-kit-swift/Runtime/lib/index.js?:295:28) - """.chromeStackTrace - - let expected: [StackTraceItem] = - [ - .init( - symbol: "Object.wasmFs.fs.writeSync", - location: "./entrypoint/dev.js?:54:25", - kind: .javaScript - ), - .init( - symbol: "eval", - location: "./node_modules/@wasmer/wasi/lib/index.esm.js?:115:429", - kind: .javaScript - ), - .init( - symbol: "eval", - location: "./node_modules/@wasmer/wasi/lib/index.esm.js?:115:372", - kind: .javaScript - ), - .init( - symbol: "eval", - location: "./node_modules/@wasmer/wasi/lib/index.esm.js?:102:271", - kind: .javaScript - ), - .init( - symbol: "write", - location: "wasm-function[62105]:0x12b19bc", - kind: .webAssembly - ), - .init( - symbol: "swift_reportError", - location: "wasm-function[21697]:0x37e8aa", - kind: .webAssembly - ), - .init( - symbol: "_swift_stdlib_reportFatalErrorInFile", - location: "wasm-function[22993]:0x3e4ffe", - kind: .webAssembly - ), - .init( - symbol: - "closure #1 (UnsafeBufferPointer) -> () in closure #1 (UnsafeBufferPointer) -> () in _assertionFailure(_: StaticString, _: StaticString, file: StaticString, line: UInt, flags: UInt32) -> Never", - location: "wasm-function[3676]:0xd96fc", - kind: .webAssembly - ), - .init( - symbol: - "merged closure #1 (UnsafeBufferPointer) -> () in _assertionFailure(_: StaticString, _: StaticString, file: StaticString, line: UInt, flags: UInt32) -> Never", - location: "wasm-function[3677]:0xd98f3", - kind: .webAssembly - ), - .init( - symbol: - "Swift._assertionFailure(_: StaticString, _: StaticString, file: StaticString, line: UInt, flags: UInt32) -> Never", - location: "wasm-function[2793]:0xa9f38", - kind: .webAssembly - ), - .init( - symbol: "Swift.Array.subscript.getter : (Int) -> A", - location: "wasm-function[3023]:0xb5afb", - kind: .webAssembly - ), - .init( - symbol: "TestApp.crash() -> ()", - location: "wasm-function[1413]:0x8274d", - kind: .webAssembly - ), - .init( - symbol: "closure #1 (Array) -> () in TestApp", - location: "wasm-function[1408]:0x81b08", - kind: .webAssembly - ), - .init( - symbol: - "closure #1 (Array) -> JavaScriptKit.JSValue in JavaScriptKit.JSClosure.init((Array) -> ()) -> JavaScriptKit.JSClosure", - location: "wasm-function[816]:0x51881", - kind: .webAssembly - ), - .init( - symbol: - "partial apply forwarder for closure #1 (Array) -> JavaScriptKit.JSValue in JavaScriptKit.JSClosure.init((Array) -> ()) -> JavaScriptKit.JSClosure", - location: "wasm-function[815]:0x517dc", - kind: .webAssembly - ), - .init( - symbol: - "reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue)", - location: "wasm-function[812]:0x51646", - kind: .webAssembly - ), - .init( - symbol: - "partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue)", - location: "wasm-function[811]:0x5160e", - kind: .webAssembly - ), - .init( - symbol: - "reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue)", - location: "wasm-function[839]:0x54566", - kind: .webAssembly - ), - .init( - symbol: - "partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed (@in_guaranteed Array) -> (@out JavaScriptKit.JSValue) to @escaping @callee_guaranteed (@guaranteed Array) -> (@owned JavaScriptKit.JSValue)", - location: "wasm-function[831]:0x54202", - kind: .webAssembly - ), - .init( - symbol: - "JavaScriptKit._call_host_function_impl(UInt32, UnsafePointer<__C.RawJSValue>, Int32, UInt32) -> ()", - location: "wasm-function[830]:0x53e2e", - kind: .webAssembly - ), - .init( - symbol: "_call_host_function_impl", - location: "wasm-function[829]:0x5399e", - kind: .webAssembly - ), - .init( - symbol: "_call_host_function", - location: "wasm-function[1429]:0x83af4", - kind: .webAssembly - ), - .init( - symbol: "callHostFunction", - location: "./node_modules/javascript-kit-swift/Runtime/lib/index.js?:110:21", - kind: .javaScript - ), - .init( - symbol: "HTMLButtonElement.eval", - location: "./node_modules/javascript-kit-swift/Runtime/lib/index.js?:295:28", - kind: .javaScript - ), - ] - XCTAssertEqual(stackTrace, expected) - } -} diff --git a/Tests/Fixtures/NodeJSKitTest/Package.resolved b/Tests/Fixtures/NodeJSKitTest/Package.resolved index fa0da1c9..d1a0b7d7 100644 --- a/Tests/Fixtures/NodeJSKitTest/Package.resolved +++ b/Tests/Fixtures/NodeJSKitTest/Package.resolved @@ -18,42 +18,6 @@ "version" : "1.3.1" } }, - { - "identity" : "swift-atomics", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-atomics.git", - "state" : { - "revision" : "cd142fd2f64be2100422d658e7411e39489da985", - "version" : "1.2.0" - } - }, - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", - "version" : "1.1.4" - } - }, - { - "identity" : "swift-nio", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio.git", - "state" : { - "revision" : "914081701062b11e3bb9e21accc379822621995e", - "version" : "2.76.1" - } - }, - { - "identity" : "swift-system", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-system.git", - "state" : { - "revision" : "c8a44d836fe7913603e246acab7c528c2e780168", - "version" : "1.4.0" - } - }, { "identity" : "wasmtransformer", "kind" : "remoteSourceControl", diff --git a/Tests/Fixtures/TestApp/Package.resolved b/Tests/Fixtures/TestApp/Package.resolved index b762fc0a..3faf21a1 100644 --- a/Tests/Fixtures/TestApp/Package.resolved +++ b/Tests/Fixtures/TestApp/Package.resolved @@ -19,42 +19,6 @@ "version": "1.3.0" } }, - { - "package": "swift-atomics", - "repositoryURL": "https://github.com/apple/swift-atomics.git", - "state": { - "branch": null, - "revision": "cd142fd2f64be2100422d658e7411e39489da985", - "version": "1.2.0" - } - }, - { - "package": "swift-collections", - "repositoryURL": "https://github.com/apple/swift-collections.git", - "state": { - "branch": null, - "revision": "94cf62b3ba8d4bed62680a282d4c25f9c63c2efb", - "version": "1.1.0" - } - }, - { - "package": "swift-nio", - "repositoryURL": "https://github.com/apple/swift-nio.git", - "state": { - "branch": null, - "revision": "635b2589494c97e48c62514bc8b37ced762e0a62", - "version": "2.63.0" - } - }, - { - "package": "swift-system", - "repositoryURL": "https://github.com/apple/swift-system.git", - "state": { - "branch": null, - "revision": "025bcb1165deab2e20d4eaba79967ce73013f496", - "version": "1.2.1" - } - }, { "package": "WasmTransformer", "repositoryURL": "https://github.com/swiftwasm/WasmTransformer", diff --git a/Tests/WebDriverTests/WebDriverClientTests.swift b/Tests/WebDriverTests/WebDriverClientTests.swift deleted file mode 100644 index 5029704b..00000000 --- a/Tests/WebDriverTests/WebDriverClientTests.swift +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2022 Carton contributors -// -// 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. - -import CartonCore -import WebDriver -import XCTest - -final class WebDriverClientTests: XCTestCase { - #if canImport(FoundationNetworking) - #else - func testGotoURLSession() async throws { - let terminal = InteractiveWriter.stdout - let service = try await WebDriverServices.find(terminal: terminal) - defer { - service.dispose() - } - - let client = try await service.client( - httpClient: URLSessionWebDriverHTTPClient(session: .shared) - ) - try await client.goto(url: URL(string: "https://example.com")!) - try await client.closeSession() - } - #endif - - func testGotoCurl() async throws { - let terminal = InteractiveWriter.stdout - let service = try await WebDriverServices.find(terminal: terminal) - defer { - service.dispose() - } - - let client = try await service.client( - httpClient: try XCTUnwrap(CurlWebDriverHTTPClient.find()) - ) - try await client.goto(url: URL(string: "https://example.com")!) - try await client.closeSession() - } -} diff --git a/entrypoint/bundle.ts b/entrypoint/bundle.ts index d6023099..90c4fe8c 100644 --- a/entrypoint/bundle.ts +++ b/entrypoint/bundle.ts @@ -21,9 +21,12 @@ const startWasiTask = async () => { let runtimeConstructor: SwiftRuntimeConstructor | undefined = undefined; try { + // NOTE: We need to provide the path via a variable to make Vite happy as it + // doesn't understand @vite-ignore comments with dynamic imports with string literals. + const modulePath = "./JavaScriptKit_JavaScriptKit.resources/Runtime/index.mjs"; const { SwiftRuntime } = await import( // @ts-ignore - "./JavaScriptKit_JavaScriptKit.resources/Runtime/index.mjs" + /* @vite-ignore */ modulePath ); runtimeConstructor = SwiftRuntime; } catch { diff --git a/entrypoint/dev.ts b/entrypoint/dev.ts index a21d13d1..e9db7fca 100644 --- a/entrypoint/dev.ts +++ b/entrypoint/dev.ts @@ -30,9 +30,12 @@ const startWasiTask = async () => { let runtimeConstructor: SwiftRuntimeConstructor | undefined = undefined; try { + // NOTE: We need to provide the path via a variable to make Vite happy as it + // doesn't understand @vite-ignore comments with dynamic imports with string literals. + const modulePath = "./JavaScriptKit_JavaScriptKit.resources/Runtime/index.mjs"; const { SwiftRuntime } = await import( // @ts-ignore - "./JavaScriptKit_JavaScriptKit.resources/Runtime/index.mjs" + /* @vite-ignore */ modulePath ); runtimeConstructor = SwiftRuntime; } catch {